summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile268
-rw-r--r--bchecker.ini3
-rwxr-xr-xbuildnum.pl49
-rw-r--r--component_versions.mk198
-rw-r--r--components.mk978
-rw-r--r--config/.cvsignore5
-rw-r--r--config/Linux2.4.mk58
-rw-r--r--config/Linux2.6.mk58
-rw-r--r--config/Makefile38
-rw-r--r--config/SunOS5.8.mk14
-rw-r--r--config/SunOS5.8_i86pc.mk14
-rw-r--r--config/SunOS5.9.mk14
-rw-r--r--config/UNIX.mk14
-rw-r--r--config/WINNT5.0.mk56
-rw-r--r--config/common.mn120
-rw-r--r--config/config.mk520
-rw-r--r--config/nfspwd.pl21
-rw-r--r--config/nsinstall.c305
-rw-r--r--config/pathsub.c206
-rw-r--r--config/pathsub.h46
-rw-r--r--config/revdepth-nt.pl19
-rw-r--r--config/revdepth.pl22
-rw-r--r--config/rules.mk707
-rw-r--r--config/webint.mk24
-rwxr-xr-xdirver.pl125
-rwxr-xr-xhttpd/autobuild500
-rw-r--r--httpd/src/Makefile229
-rw-r--r--httpd/src/ntnsapi.c383
-rw-r--r--httpd/src/unixso.exp38
-rw-r--r--httpd/src/unixso.mk246
-rw-r--r--include/Makefile85
-rw-r--r--include/base/Makefile40
-rw-r--r--include/base/crit.h209
-rw-r--r--include/base/dbtbase.h217
-rw-r--r--include/base/ereport.h76
-rw-r--r--include/base/eventhandler.h73
-rw-r--r--include/base/eventlog.h34
-rw-r--r--include/base/file.h121
-rw-r--r--include/base/fsmutex.h94
-rw-r--r--include/base/lexer.h89
-rw-r--r--include/base/nterr.h21
-rw-r--r--include/base/nterrors.h67
-rw-r--r--include/base/plist.h61
-rw-r--r--include/base/pool.h103
-rw-r--r--include/base/rwlock.h54
-rw-r--r--include/base/shexp.h114
-rw-r--r--include/base/systems.h565
-rw-r--r--include/base/systhr.h91
-rw-r--r--include/base/util.h210
-rw-r--r--include/copyrght.h6
-rw-r--r--include/i18n.h245
-rw-r--r--include/ldaputil/cert.h27
-rw-r--r--include/ldaputil/certmap.h124
-rw-r--r--include/ldaputil/dbconf.h91
-rw-r--r--include/ldaputil/encode.h29
-rw-r--r--include/ldaputil/errors.h108
-rw-r--r--include/ldaputil/extcmap.h634
-rw-r--r--include/ldaputil/init.h23
-rw-r--r--include/ldaputil/ldapauth.h94
-rw-r--r--include/ldaputil/ldapdb.h100
-rw-r--r--include/ldaputil/ldaputil.h132
-rw-r--r--include/libaccess/acl.h41
-rw-r--r--include/libaccess/acladmin.h79
-rw-r--r--include/libaccess/aclbuild.h56
-rw-r--r--include/libaccess/aclerror.h307
-rw-r--r--include/libaccess/acleval.h37
-rw-r--r--include/libaccess/aclglobal.h52
-rw-r--r--include/libaccess/aclparse.h112
-rw-r--r--include/libaccess/aclproto.h156
-rw-r--r--include/libaccess/aclstruct.h264
-rw-r--r--include/libaccess/attrec.h157
-rw-r--r--include/libaccess/authdb.h24
-rw-r--r--include/libaccess/ava.h40
-rw-r--r--include/libaccess/avadb.h15
-rw-r--r--include/libaccess/avapfile.h59
-rw-r--r--include/libaccess/dbtlibaccess.h161
-rw-r--r--include/libaccess/dnfstruct.h51
-rw-r--r--include/libaccess/ipfstruct.h81
-rw-r--r--include/libaccess/las.h184
-rw-r--r--include/libaccess/ldapacl.h62
-rw-r--r--include/libaccess/nsadb.h87
-rw-r--r--include/libaccess/nsamgmt.h122
-rw-r--r--include/libaccess/nsauth.h288
-rw-r--r--include/libaccess/nsautherr.h97
-rw-r--r--include/libaccess/nscert.h102
-rw-r--r--include/libaccess/nsdb.h182
-rw-r--r--include/libaccess/nsdberr.h92
-rw-r--r--include/libaccess/nsdbmgmt.h52
-rw-r--r--include/libaccess/nserror.h47
-rw-r--r--include/libaccess/nsgmgmt.h35
-rw-r--r--include/libaccess/nsgroup.h73
-rw-r--r--include/libaccess/nslock.h74
-rw-r--r--include/libaccess/nsumgmt.h36
-rw-r--r--include/libaccess/nsuser.h70
-rw-r--r--include/libaccess/register.h215
-rw-r--r--include/libaccess/stubs.h6
-rw-r--r--include/libaccess/symbols.h99
-rw-r--r--include/libaccess/userauth.h13
-rw-r--r--include/libaccess/usi.h81
-rw-r--r--include/libaccess/usrcache.h104
-rw-r--r--include/libadmin/dbtlibadmin.h20
-rw-r--r--include/libadmin/libadmin.h1403
-rw-r--r--include/netsite.h312
-rw-r--r--include/nt/messages.h410
-rw-r--r--include/nt/nsapi.h346
-rw-r--r--include/nt/ntos.h155
-rw-r--r--include/nt/regparms.h586
-rw-r--r--include/nt/resource.h36
-rw-r--r--include/public/Makefile59
-rw-r--r--include/public/base/Makefile40
-rw-r--r--include/public/base/crit.h21
-rw-r--r--include/public/base/ereport.h21
-rw-r--r--include/public/base/file.h21
-rw-r--r--include/public/base/pool.h22
-rw-r--r--include/public/base/shexp.h22
-rw-r--r--include/public/base/systems.h242
-rw-r--r--include/public/base/systhr.h21
-rw-r--r--include/public/base/util.h21
-rw-r--r--include/public/netsite.h21
-rw-r--r--include/public/nsacl/Makefile38
-rw-r--r--include/public/nsacl/aclapi.h396
-rw-r--r--include/public/nsacl/acldef.h465
-rw-r--r--include/public/nsacl/copyrght.h6
-rw-r--r--include/public/nsacl/nserrdef.h100
-rw-r--r--include/public/nsacl/plistdef.h62
-rw-r--r--include/public/nsapi.h3481
-rw-r--r--include/version.h53
-rw-r--r--l10n/dirserv/de/ns-slapd.txt899
-rw-r--r--l10n/dirserv/de/ns-slapd.txt.iso8859879
-rw-r--r--l10n/dirserv/en/ns-slapd.txt986
-rw-r--r--l10n/dirserv/es/ns-slapd.txt889
-rw-r--r--l10n/dirserv/es/ns-slapd.txt.iso8859874
-rw-r--r--l10n/dirserv/fr/ns-slapd.txt898
-rw-r--r--l10n/dirserv/fr/ns-slapd.txt.iso8859883
-rw-r--r--l10n/dirserv/ja/ns-slapd.txt1018
-rw-r--r--l10n/dirserv/ja/ns-slapd.txt.eucjp981
-rw-r--r--ldap/Makefile95
-rw-r--r--ldap/Makefile.client39
-rw-r--r--ldap/admin/Makefile33
-rw-r--r--ldap/admin/include/Makefile39
-rw-r--r--ldap/admin/include/dsalib.h450
-rw-r--r--ldap/admin/include/dsalib_pw.h17
-rw-r--r--ldap/admin/include/dsalib_schema.h255
-rw-r--r--ldap/admin/include/nterrors.h728
-rw-r--r--ldap/admin/lib/Makefile108
-rw-r--r--ldap/admin/lib/dsalib_conf.c213
-rw-r--r--ldap/admin/lib/dsalib_confs.c130
-rw-r--r--ldap/admin/lib/dsalib_db.c374
-rw-r--r--ldap/admin/lib/dsalib_debug.c73
-rw-r--r--ldap/admin/lib/dsalib_dn.c465
-rw-r--r--ldap/admin/lib/dsalib_filename.c95
-rw-r--r--ldap/admin/lib/dsalib_html.c201
-rw-r--r--ldap/admin/lib/dsalib_ldif.c374
-rw-r--r--ldap/admin/lib/dsalib_location.c142
-rw-r--r--ldap/admin/lib/dsalib_pw.c29
-rw-r--r--ldap/admin/lib/dsalib_tailf.c206
-rw-r--r--ldap/admin/lib/dsalib_updown.c702
-rw-r--r--ldap/admin/lib/dsalib_util.c1123
-rw-r--r--ldap/admin/src/AddPerlHeader.pl60
-rw-r--r--ldap/admin/src/Base.def13
-rw-r--r--ldap/admin/src/Base.pm63
-rw-r--r--ldap/admin/src/CGI_ENV36
-rw-r--r--ldap/admin/src/Cgi.pm70
-rw-r--r--ldap/admin/src/CreateInstall.pl34
-rw-r--r--ldap/admin/src/DSAdmin.def11
-rw-r--r--ldap/admin/src/DSAdmin.mk134
-rw-r--r--ldap/admin/src/DSAdmin.pm225
-rw-r--r--ldap/admin/src/DSAdmin.xs76
-rw-r--r--ldap/admin/src/Inf.pm243
-rw-r--r--ldap/admin/src/Makefile304
-rw-r--r--ldap/admin/src/addindex.c80
-rw-r--r--ldap/admin/src/cfg_sspt.c1621
-rw-r--r--ldap/admin/src/cfg_sspt.h110
-rw-r--r--ldap/admin/src/configure_instance.cpp1969
-rw-r--r--ldap/admin/src/configure_instance.h53
-rw-r--r--ldap/admin/src/create_instance.c4640
-rw-r--r--ldap/admin/src/create_instance.h112
-rw-r--r--ldap/admin/src/ds_bak2db.c71
-rw-r--r--ldap/admin/src/ds_db2bak.c77
-rw-r--r--ldap/admin/src/ds_db2ldif.c78
-rw-r--r--ldap/admin/src/ds_ldif2db.c103
-rw-r--r--ldap/admin/src/ds_listdb.c37
-rw-r--r--ldap/admin/src/ds_remove.c234
-rw-r--r--ldap/admin/src/ds_remove_uninst.cpp317
-rw-r--r--ldap/admin/src/ds_remove_uninst.h23
-rw-r--r--ldap/admin/src/ds_rmdb.c73
-rw-r--r--ldap/admin/src/ds_snmpctrl.c308
-rw-r--r--ldap/admin/src/ds_viewlog.pl129
-rw-r--r--ldap/admin/src/getConfigInfo134
-rwxr-xr-xldap/admin/src/import2info58
-rw-r--r--ldap/admin/src/init_ds_env.c57
-rw-r--r--ldap/admin/src/init_ds_env.h11
-rw-r--r--ldap/admin/src/install_keywords.h111
-rw-r--r--ldap/admin/src/instindex.cpp423
-rw-r--r--ldap/admin/src/java/com/netscape/xmltools/DSML2LDIF.java234
-rw-r--r--ldap/admin/src/java/com/netscape/xmltools/DSMLReader.java47
-rw-r--r--ldap/admin/src/java/com/netscape/xmltools/DSMLSAXBuilder.java86
-rw-r--r--ldap/admin/src/java/com/netscape/xmltools/DSMLSAXHandler.java299
-rw-r--r--ldap/admin/src/java/com/netscape/xmltools/DSMLWriter.java315
-rw-r--r--ldap/admin/src/java/com/netscape/xmltools/GetOpt.java222
-rw-r--r--ldap/admin/src/java/com/netscape/xmltools/LDIF2DSML.java214
-rw-r--r--ldap/admin/src/java/com/netscape/xmltools/Makefile67
-rwxr-xr-xldap/admin/src/java/install17
-rwxr-xr-xldap/admin/src/java/mcc38
-rw-r--r--ldap/admin/src/java/mcc.bat45
-rw-r--r--ldap/admin/src/key.rc150
-rw-r--r--ldap/admin/src/latest_file.c95
-rw-r--r--ldap/admin/src/makemccvlvindexes211
-rw-r--r--ldap/admin/src/makevlvindex109
-rw-r--r--ldap/admin/src/makevlvsearch138
-rw-r--r--ldap/admin/src/migrateInstance549
-rw-r--r--ldap/admin/src/migrateLocalDB265
-rw-r--r--ldap/admin/src/migratePwdFile90
-rw-r--r--ldap/admin/src/migrateTo41581
-rwxr-xr-xldap/admin/src/migratedsgw445
-rw-r--r--ldap/admin/src/namegen.c107
-rw-r--r--ldap/admin/src/ns-newpwpolicy.pl198
-rw-r--r--ldap/admin/src/restart.c46
-rw-r--r--ldap/admin/src/script-gen.c107
-rw-r--r--ldap/admin/src/scripts/template-bak2db.pl89
-rwxr-xr-xldap/admin/src/scripts/template-cl-dump.pl307
-rw-r--r--ldap/admin/src/scripts/template-db2bak.pl89
-rw-r--r--ldap/admin/src/scripts/template-db2index.pl195
-rw-r--r--ldap/admin/src/scripts/template-db2ldif.pl215
-rw-r--r--ldap/admin/src/scripts/template-dsml-activate.pl198
-rw-r--r--ldap/admin/src/scripts/template-ldif2db.pl193
-rw-r--r--ldap/admin/src/scripts/template-migrate50to512778
-rw-r--r--ldap/admin/src/scripts/template-migrate5to63043
-rw-r--r--ldap/admin/src/scripts/template-migrate5to73043
-rw-r--r--ldap/admin/src/scripts/template-migrate6to73049
-rw-r--r--ldap/admin/src/scripts/template-migrateInstance5518
-rw-r--r--ldap/admin/src/scripts/template-migrateInstance6550
-rw-r--r--ldap/admin/src/scripts/template-migrateInstance7559
-rwxr-xr-xldap/admin/src/scripts/template-migrateTo53094
-rw-r--r--ldap/admin/src/scripts/template-migrateTo63268
-rw-r--r--ldap/admin/src/scripts/template-migrateTo73268
-rw-r--r--ldap/admin/src/scripts/template-ns-accountstatus.pl813
-rw-r--r--ldap/admin/src/scripts/template-ns-activate.pl813
-rw-r--r--ldap/admin/src/scripts/template-ns-inactivate.pl813
-rwxr-xr-xldap/admin/src/scripts/template-ns-newpwpolicy.pl241
-rwxr-xr-xldap/admin/src/scripts/template-repl-monitor-cgi.pl40
-rwxr-xr-xldap/admin/src/scripts/template-repl-monitor.pl956
-rw-r--r--ldap/admin/src/scripts/template-verify-db.pl196
-rw-r--r--ldap/admin/src/shutdown.c39
-rw-r--r--ldap/admin/src/start.c42
-rw-r--r--ldap/admin/src/uname.lib169
-rwxr-xr-xldap/admin/src/updatedsgw331
-rwxr-xr-xldap/admin/src/upgradeServer442
-rw-r--r--ldap/admin/src/vlvindex.c92
-rw-r--r--ldap/clients/Makefile31
-rw-r--r--ldap/clients/dsgw/Makefile305
-rw-r--r--ldap/clients/dsgw/Versiongw.c25
-rw-r--r--ldap/clients/dsgw/admhtml/Makefile52
-rw-r--r--ldap/clients/dsgw/admhtml/display-country.html52
-rw-r--r--ldap/clients/dsgw/admhtml/display-dnedit.html74
-rw-r--r--ldap/clients/dsgw/admhtml/display-dnedittop.html19
-rw-r--r--ldap/clients/dsgw/admhtml/display-group.html122
-rw-r--r--ldap/clients/dsgw/admhtml/display-groupun.html122
-rw-r--r--ldap/clients/dsgw/admhtml/display-licensed-user.html71
-rw-r--r--ldap/clients/dsgw/admhtml/display-mailgroup.html121
-rw-r--r--ldap/clients/dsgw/admhtml/display-org.html129
-rw-r--r--ldap/clients/dsgw/admhtml/display-orgperson.html142
-rw-r--r--ldap/clients/dsgw/admhtml/display-orgunit.html95
-rw-r--r--ldap/clients/dsgw/admhtml/display-person.html133
-rw-r--r--ldap/clients/dsgw/admhtml/display-umperson.html177
-rw-r--r--ldap/clients/dsgw/admhtml/dsconfig.html191
-rw-r--r--ldap/clients/dsgw/admhtml/dscrgroup.html114
-rw-r--r--ldap/clients/dsgw/admhtml/dscrou.html103
-rw-r--r--ldap/clients/dsgw/admhtml/dscruser.html172
-rw-r--r--ldap/clients/dsgw/admhtml/dsexpldif.html76
-rw-r--r--ldap/clients/dsgw/admhtml/dsimpldif.html85
-rw-r--r--ldap/clients/dsgw/admhtml/dslsgroups.html164
-rw-r--r--ldap/clients/dsgw/admhtml/dslsous.html172
-rw-r--r--ldap/clients/dsgw/admhtml/dslsusers.html166
-rw-r--r--ldap/clients/dsgw/admhtml/edit-passwd.html103
-rw-r--r--ldap/clients/dsgw/admhtml/index.lst87
-rw-r--r--ldap/clients/dsgw/admhtml/list-Anything.html42
-rw-r--r--ldap/clients/dsgw/admhtml/list-Auth.html72
-rw-r--r--ldap/clients/dsgw/admhtml/list-Groups-report.html56
-rw-r--r--ldap/clients/dsgw/admhtml/list-Groups-rm.html80
-rw-r--r--ldap/clients/dsgw/admhtml/list-Groups.html62
-rw-r--r--ldap/clients/dsgw/admhtml/list-Org-Units.html62
-rw-r--r--ldap/clients/dsgw/admhtml/list-OrgUnits-report.html56
-rw-r--r--ldap/clients/dsgw/admhtml/list-OrgUnits.html62
-rw-r--r--ldap/clients/dsgw/admhtml/list-Organizations.html38
-rw-r--r--ldap/clients/dsgw/admhtml/list-Ous-rm.html80
-rw-r--r--ldap/clients/dsgw/admhtml/list-People-report.html60
-rw-r--r--ldap/clients/dsgw/admhtml/list-People-rm.html81
-rw-r--r--ldap/clients/dsgw/admhtml/list-People.html61
-rw-r--r--ldap/clients/dsgw/admhtml/list-fa-Groups.html24
-rw-r--r--ldap/clients/dsgw/admhtml/list-fa-People.html24
-rw-r--r--ldap/clients/dsgw/admhtml/list-fa_people.html24
-rw-r--r--ldap/clients/dsgw/admhtml/list-urlsearch.html39
-rw-r--r--ldap/clients/dsgw/auth.c120
-rw-r--r--ldap/clients/dsgw/cgiutil.c512
-rw-r--r--ldap/clients/dsgw/ckdel.c30
-rw-r--r--ldap/clients/dsgw/ckdump.c38
-rw-r--r--ldap/clients/dsgw/ckget.c46
-rw-r--r--ldap/clients/dsgw/ckpurge.c33
-rw-r--r--ldap/clients/dsgw/ckput.c63
-rw-r--r--ldap/clients/dsgw/collate.c400
-rw-r--r--ldap/clients/dsgw/config.c2080
-rw-r--r--ldap/clients/dsgw/config/Makefile77
-rw-r--r--ldap/clients/dsgw/config/authPassword.html30
-rw-r--r--ldap/clients/dsgw/config/authSearch.html35
-rw-r--r--ldap/clients/dsgw/config/csearch.html28
-rw-r--r--ldap/clients/dsgw/config/csearchAttr.html23
-rw-r--r--ldap/clients/dsgw/config/csearchBase.html22
-rw-r--r--ldap/clients/dsgw/config/csearchMatch.html21
-rw-r--r--ldap/clients/dsgw/config/csearchString.html26
-rw-r--r--ldap/clients/dsgw/config/csearchType.html24
-rw-r--r--ldap/clients/dsgw/config/de/authPassword.html29
-rw-r--r--ldap/clients/dsgw/config/de/authSearch.html33
-rw-r--r--ldap/clients/dsgw/config/de/csearchAttr.html17
-rw-r--r--ldap/clients/dsgw/config/de/csearchBase.html17
-rw-r--r--ldap/clients/dsgw/config/de/csearchString.html28
-rw-r--r--ldap/clients/dsgw/config/de/csearchType.html18
-rw-r--r--ldap/clients/dsgw/config/de/display-country.html54
-rw-r--r--ldap/clients/dsgw/config/de/display-dnedit.html76
-rw-r--r--ldap/clients/dsgw/config/de/display-dneditpeople.html75
-rw-r--r--ldap/clients/dsgw/config/de/display-group.html150
-rw-r--r--ldap/clients/dsgw/config/de/display-groupun.html150
-rw-r--r--ldap/clients/dsgw/config/de/display-mailgroup.html124
-rw-r--r--ldap/clients/dsgw/config/de/display-ntgroup.html216
-rw-r--r--ldap/clients/dsgw/config/de/display-ntperson.html505
-rw-r--r--ldap/clients/dsgw/config/de/display-org.html136
-rw-r--r--ldap/clients/dsgw/config/de/display-orgperson.html345
-rw-r--r--ldap/clients/dsgw/config/de/display-orgunit.html136
-rw-r--r--ldap/clients/dsgw/config/de/display-person.html231
-rw-r--r--ldap/clients/dsgw/config/de/display-umperson.html200
-rw-r--r--ldap/clients/dsgw/config/de/dsgw-l10n.conf18
-rw-r--r--ldap/clients/dsgw/config/de/dsgw.conf133
-rw-r--r--ldap/clients/dsgw/config/de/dsgw.tmpl116
-rw-r--r--ldap/clients/dsgw/config/de/dsgw_adm.conf46
-rw-r--r--ldap/clients/dsgw/config/de/dsgwfilter.conf139
-rw-r--r--ldap/clients/dsgw/config/de/dsgwfilter_adm.conf73
-rw-r--r--ldap/clients/dsgw/config/de/dsgwsearchprefs.conf213
-rw-r--r--ldap/clients/dsgw/config/de/edit-passwd.html78
-rw-r--r--ldap/clients/dsgw/config/de/list-Anything.html42
-rw-r--r--ldap/clients/dsgw/config/de/list-Auth.html73
-rw-r--r--ldap/clients/dsgw/config/de/list-Groups.html38
-rw-r--r--ldap/clients/dsgw/config/de/list-NT-Groups.html44
-rw-r--r--ldap/clients/dsgw/config/de/list-NT-People.html48
-rw-r--r--ldap/clients/dsgw/config/de/list-Org-Units.html38
-rw-r--r--ldap/clients/dsgw/config/de/list-Organizations.html38
-rw-r--r--ldap/clients/dsgw/config/de/list-People.html48
-rw-r--r--ldap/clients/dsgw/config/de/list-fa-Groups.html22
-rw-r--r--ldap/clients/dsgw/config/de/list-fa-People.html22
-rw-r--r--ldap/clients/dsgw/config/de/list-urlsearch.html38
-rw-r--r--ldap/clients/dsgw/config/de/newentry.html25
-rw-r--r--ldap/clients/dsgw/config/de/newentryName.html48
-rw-r--r--ldap/clients/dsgw/config/de/newentryType.html14
-rw-r--r--ldap/clients/dsgw/config/de/search.html18
-rw-r--r--ldap/clients/dsgw/config/de/searchString.html30
-rw-r--r--ldap/clients/dsgw/config/display-country.html61
-rw-r--r--ldap/clients/dsgw/config/display-dc.html188
-rw-r--r--ldap/clients/dsgw/config/display-dnedit.html85
-rw-r--r--ldap/clients/dsgw/config/display-dneditpeople.html83
-rw-r--r--ldap/clients/dsgw/config/display-group.html186
-rw-r--r--ldap/clients/dsgw/config/display-groupun.html186
-rw-r--r--ldap/clients/dsgw/config/display-ntgroup.html277
-rw-r--r--ldap/clients/dsgw/config/display-ntperson.html670
-rw-r--r--ldap/clients/dsgw/config/display-org.html189
-rw-r--r--ldap/clients/dsgw/config/display-orgperson.html501
-rw-r--r--ldap/clients/dsgw/config/display-orgunit.html191
-rw-r--r--ldap/clients/dsgw/config/display-person.html366
-rw-r--r--ldap/clients/dsgw/config/dsgw-l10n.conf18
-rw-r--r--ldap/clients/dsgw/config/dsgw.tmpl148
-rw-r--r--ldap/clients/dsgw/config/dsgw_adm.conf46
-rw-r--r--ldap/clients/dsgw/config/dsgwfilter.conf154
-rw-r--r--ldap/clients/dsgw/config/dsgwfilter_adm.conf73
-rw-r--r--ldap/clients/dsgw/config/dsgwsearchprefs.conf234
-rw-r--r--ldap/clients/dsgw/config/edit-passwd.html78
-rw-r--r--ldap/clients/dsgw/config/en-us/dsgw-l10n.conf18
-rw-r--r--ldap/clients/dsgw/config/en-us/dsgwcollate.conf8
-rw-r--r--ldap/clients/dsgw/config/en/dsgw-l10n.conf18
-rw-r--r--ldap/clients/dsgw/config/en/dsgwcollate.conf41
-rw-r--r--ldap/clients/dsgw/config/es/authPassword.html29
-rw-r--r--ldap/clients/dsgw/config/es/authSearch.html33
-rw-r--r--ldap/clients/dsgw/config/es/csearch.html23
-rw-r--r--ldap/clients/dsgw/config/es/csearchAttr.html18
-rw-r--r--ldap/clients/dsgw/config/es/csearchBase.html17
-rw-r--r--ldap/clients/dsgw/config/es/csearchString.html28
-rw-r--r--ldap/clients/dsgw/config/es/csearchType.html19
-rw-r--r--ldap/clients/dsgw/config/es/display-country.html54
-rw-r--r--ldap/clients/dsgw/config/es/display-dnedit.html76
-rw-r--r--ldap/clients/dsgw/config/es/display-dneditpeople.html75
-rw-r--r--ldap/clients/dsgw/config/es/display-group.html149
-rw-r--r--ldap/clients/dsgw/config/es/display-groupun.html149
-rw-r--r--ldap/clients/dsgw/config/es/display-ntgroup.html215
-rw-r--r--ldap/clients/dsgw/config/es/display-ntperson.html493
-rw-r--r--ldap/clients/dsgw/config/es/display-org.html135
-rw-r--r--ldap/clients/dsgw/config/es/display-orgperson.html342
-rw-r--r--ldap/clients/dsgw/config/es/display-orgunit.html135
-rw-r--r--ldap/clients/dsgw/config/es/display-person.html229
-rw-r--r--ldap/clients/dsgw/config/es/dsgw-l10n.conf18
-rw-r--r--ldap/clients/dsgw/config/es/dsgw.tmpl116
-rw-r--r--ldap/clients/dsgw/config/es/dsgw_adm.conf46
-rw-r--r--ldap/clients/dsgw/config/es/dsgwfilter.conf139
-rw-r--r--ldap/clients/dsgw/config/es/dsgwfilter_adm.conf73
-rw-r--r--ldap/clients/dsgw/config/es/dsgwsearchprefs.conf213
-rw-r--r--ldap/clients/dsgw/config/es/edit-passwd.html78
-rw-r--r--ldap/clients/dsgw/config/es/list-Anything.html42
-rw-r--r--ldap/clients/dsgw/config/es/list-Auth.html73
-rw-r--r--ldap/clients/dsgw/config/es/list-Groups.html38
-rw-r--r--ldap/clients/dsgw/config/es/list-NT-Groups.html44
-rw-r--r--ldap/clients/dsgw/config/es/list-NT-People.html48
-rw-r--r--ldap/clients/dsgw/config/es/list-Org-Units.html38
-rw-r--r--ldap/clients/dsgw/config/es/list-Organizations.html38
-rw-r--r--ldap/clients/dsgw/config/es/list-People.html48
-rw-r--r--ldap/clients/dsgw/config/es/list-fa-Groups.html22
-rw-r--r--ldap/clients/dsgw/config/es/list-fa-People.html22
-rw-r--r--ldap/clients/dsgw/config/es/list-urlsearch.html38
-rw-r--r--ldap/clients/dsgw/config/es/newentry.html26
-rw-r--r--ldap/clients/dsgw/config/es/newentryName.html48
-rw-r--r--ldap/clients/dsgw/config/es/newentryType.html14
-rw-r--r--ldap/clients/dsgw/config/es/ns-license-schema.conf17
-rw-r--r--ldap/clients/dsgw/config/es/search.html18
-rw-r--r--ldap/clients/dsgw/config/es/searchString.html30
-rw-r--r--ldap/clients/dsgw/config/fr/authPassword.html29
-rw-r--r--ldap/clients/dsgw/config/fr/authSearch.html34
-rw-r--r--ldap/clients/dsgw/config/fr/csearch.html23
-rw-r--r--ldap/clients/dsgw/config/fr/csearchAttr.html17
-rw-r--r--ldap/clients/dsgw/config/fr/csearchBase.html17
-rw-r--r--ldap/clients/dsgw/config/fr/csearchString.html28
-rw-r--r--ldap/clients/dsgw/config/fr/csearchType.html18
-rw-r--r--ldap/clients/dsgw/config/fr/display-country.html54
-rw-r--r--ldap/clients/dsgw/config/fr/display-dnedit.html76
-rw-r--r--ldap/clients/dsgw/config/fr/display-dneditpeople.html77
-rw-r--r--ldap/clients/dsgw/config/fr/display-group.html150
-rw-r--r--ldap/clients/dsgw/config/fr/display-groupun.html150
-rw-r--r--ldap/clients/dsgw/config/fr/display-mailgroup.html125
-rw-r--r--ldap/clients/dsgw/config/fr/display-ntgroup.html218
-rw-r--r--ldap/clients/dsgw/config/fr/display-ntperson.html508
-rw-r--r--ldap/clients/dsgw/config/fr/display-org.html137
-rw-r--r--ldap/clients/dsgw/config/fr/display-orgperson.html346
-rw-r--r--ldap/clients/dsgw/config/fr/display-orgunit.html136
-rw-r--r--ldap/clients/dsgw/config/fr/display-person.html233
-rw-r--r--ldap/clients/dsgw/config/fr/display-umperson.html200
-rw-r--r--ldap/clients/dsgw/config/fr/dsgw-l10n.conf18
-rw-r--r--ldap/clients/dsgw/config/fr/dsgw.conf133
-rw-r--r--ldap/clients/dsgw/config/fr/dsgw.tmpl113
-rw-r--r--ldap/clients/dsgw/config/fr/dsgw_adm.conf48
-rw-r--r--ldap/clients/dsgw/config/fr/dsgwfilter.conf141
-rw-r--r--ldap/clients/dsgw/config/fr/dsgwfilter_adm.conf75
-rw-r--r--ldap/clients/dsgw/config/fr/dsgwsearchprefs.conf214
-rw-r--r--ldap/clients/dsgw/config/fr/edit-passwd.html78
-rw-r--r--ldap/clients/dsgw/config/fr/list-Anything.html42
-rw-r--r--ldap/clients/dsgw/config/fr/list-Auth.html75
-rw-r--r--ldap/clients/dsgw/config/fr/list-Groups.html38
-rw-r--r--ldap/clients/dsgw/config/fr/list-NT-Groups.html46
-rw-r--r--ldap/clients/dsgw/config/fr/list-NT-People.html50
-rw-r--r--ldap/clients/dsgw/config/fr/list-Org-Units.html38
-rw-r--r--ldap/clients/dsgw/config/fr/list-Organizations.html38
-rw-r--r--ldap/clients/dsgw/config/fr/list-People.html50
-rw-r--r--ldap/clients/dsgw/config/fr/list-fa-Groups.html22
-rw-r--r--ldap/clients/dsgw/config/fr/list-fa-People.html22
-rw-r--r--ldap/clients/dsgw/config/fr/list-urlsearch.html38
-rw-r--r--ldap/clients/dsgw/config/fr/newentry.html27
-rw-r--r--ldap/clients/dsgw/config/fr/newentryName.html48
-rw-r--r--ldap/clients/dsgw/config/fr/newentryType.html14
-rw-r--r--ldap/clients/dsgw/config/fr/search.html18
-rw-r--r--ldap/clients/dsgw/config/fr/searchString.html30
-rw-r--r--ldap/clients/dsgw/config/ja/authPassword.html29
-rw-r--r--ldap/clients/dsgw/config/ja/authSearch.html33
-rw-r--r--ldap/clients/dsgw/config/ja/csearch.html23
-rw-r--r--ldap/clients/dsgw/config/ja/csearchAttr.html17
-rw-r--r--ldap/clients/dsgw/config/ja/csearchBase.html17
-rw-r--r--ldap/clients/dsgw/config/ja/csearchString.html28
-rw-r--r--ldap/clients/dsgw/config/ja/csearchType.html18
-rw-r--r--ldap/clients/dsgw/config/ja/display-country.html54
-rw-r--r--ldap/clients/dsgw/config/ja/display-dnedit.html76
-rw-r--r--ldap/clients/dsgw/config/ja/display-dneditpeople.html75
-rw-r--r--ldap/clients/dsgw/config/ja/display-group.html150
-rw-r--r--ldap/clients/dsgw/config/ja/display-groupun.html150
-rw-r--r--ldap/clients/dsgw/config/ja/display-mailgroup.html124
-rw-r--r--ldap/clients/dsgw/config/ja/display-ntgroup.html218
-rw-r--r--ldap/clients/dsgw/config/ja/display-ntperson.html506
-rw-r--r--ldap/clients/dsgw/config/ja/display-org.html136
-rw-r--r--ldap/clients/dsgw/config/ja/display-orgperson.html345
-rw-r--r--ldap/clients/dsgw/config/ja/display-orgunit.html136
-rw-r--r--ldap/clients/dsgw/config/ja/display-person.html230
-rw-r--r--ldap/clients/dsgw/config/ja/display-umperson.html199
-rw-r--r--ldap/clients/dsgw/config/ja/dsgw-l10n.conf18
-rw-r--r--ldap/clients/dsgw/config/ja/dsgw.conf133
-rw-r--r--ldap/clients/dsgw/config/ja/dsgw.tmpl111
-rw-r--r--ldap/clients/dsgw/config/ja/dsgw_adm.conf46
-rw-r--r--ldap/clients/dsgw/config/ja/dsgwcharset.conf7
-rw-r--r--ldap/clients/dsgw/config/ja/dsgwcollate.conf31
-rw-r--r--ldap/clients/dsgw/config/ja/dsgwfilter.conf139
-rw-r--r--ldap/clients/dsgw/config/ja/dsgwfilter_adm.conf73
-rw-r--r--ldap/clients/dsgw/config/ja/dsgwsearchprefs.conf213
-rw-r--r--ldap/clients/dsgw/config/ja/edit-passwd.html78
-rw-r--r--ldap/clients/dsgw/config/ja/list-Anything.html42
-rw-r--r--ldap/clients/dsgw/config/ja/list-Auth.html73
-rw-r--r--ldap/clients/dsgw/config/ja/list-Groups.html38
-rw-r--r--ldap/clients/dsgw/config/ja/list-NT-Groups.html44
-rw-r--r--ldap/clients/dsgw/config/ja/list-NT-People.html48
-rw-r--r--ldap/clients/dsgw/config/ja/list-Org-Units.html38
-rw-r--r--ldap/clients/dsgw/config/ja/list-Organizations.html38
-rw-r--r--ldap/clients/dsgw/config/ja/list-People.html48
-rw-r--r--ldap/clients/dsgw/config/ja/list-fa-Groups.html22
-rw-r--r--ldap/clients/dsgw/config/ja/list-fa-People.html22
-rw-r--r--ldap/clients/dsgw/config/ja/list-urlsearch.html38
-rw-r--r--ldap/clients/dsgw/config/ja/newentry.html26
-rw-r--r--ldap/clients/dsgw/config/ja/newentryName.html48
-rw-r--r--ldap/clients/dsgw/config/ja/newentryType.html14
-rw-r--r--ldap/clients/dsgw/config/ja/search.html18
-rw-r--r--ldap/clients/dsgw/config/ja/searchString.html30
-rw-r--r--ldap/clients/dsgw/config/ko/dsgw-l10n.conf18
-rw-r--r--ldap/clients/dsgw/config/ko/dsgwcharset.conf7
-rw-r--r--ldap/clients/dsgw/config/list-Anything.html120
-rw-r--r--ldap/clients/dsgw/config/list-Auth.html78
-rw-r--r--ldap/clients/dsgw/config/list-Domaincomponent.html115
-rw-r--r--ldap/clients/dsgw/config/list-Groups.html110
-rw-r--r--ldap/clients/dsgw/config/list-NT-Groups.html119
-rw-r--r--ldap/clients/dsgw/config/list-NT-People.html152
-rw-r--r--ldap/clients/dsgw/config/list-Org-Units.html118
-rw-r--r--ldap/clients/dsgw/config/list-Organizations.html127
-rw-r--r--ldap/clients/dsgw/config/list-People.html176
-rw-r--r--ldap/clients/dsgw/config/list-fa-Groups.html26
-rw-r--r--ldap/clients/dsgw/config/list-fa-People.html26
-rw-r--r--ldap/clients/dsgw/config/list-urlsearch.html129
-rw-r--r--ldap/clients/dsgw/config/newentry.html26
-rw-r--r--ldap/clients/dsgw/config/newentryName.html62
-rw-r--r--ldap/clients/dsgw/config/newentryType.html25
-rw-r--r--ldap/clients/dsgw/config/ns-license-schema.conf17
-rw-r--r--ldap/clients/dsgw/config/search.html18
-rw-r--r--ldap/clients/dsgw/config/searchString.html41
-rw-r--r--ldap/clients/dsgw/config/zh/dsgw-l10n.conf18
-rw-r--r--ldap/clients/dsgw/config/zh/dsgwcharset.conf7
-rw-r--r--ldap/clients/dsgw/cookie.c990
-rw-r--r--ldap/clients/dsgw/csearch.c336
-rw-r--r--ldap/clients/dsgw/dbtdsgw.h447
-rw-r--r--ldap/clients/dsgw/dnedit.c415
-rw-r--r--ldap/clients/dsgw/doauth.c386
-rw-r--r--ldap/clients/dsgw/domodify.c1254
-rw-r--r--ldap/clients/dsgw/dosearch.c352
-rw-r--r--ldap/clients/dsgw/dsconfig.c255
-rw-r--r--ldap/clients/dsgw/dsexpldif.c133
-rw-r--r--ldap/clients/dsgw/dsgw.h1053
-rw-r--r--ldap/clients/dsgw/dsgw_include.mk23
-rw-r--r--ldap/clients/dsgw/dsgwutil.c1318
-rw-r--r--ldap/clients/dsgw/dsimpldif.c150
-rw-r--r--ldap/clients/dsgw/edit.c256
-rw-r--r--ldap/clients/dsgw/emitauth.c317
-rw-r--r--ldap/clients/dsgw/emitf.c860
-rw-r--r--ldap/clients/dsgw/entrydisplay.c3228
-rw-r--r--ldap/clients/dsgw/error.c542
-rw-r--r--ldap/clients/dsgw/genscreen.c117
-rw-r--r--ldap/clients/dsgw/getopt.c115
-rw-r--r--ldap/clients/dsgw/html/Makefile81
-rw-r--r--ldap/clients/dsgw/html/aim-online.gifbin0 -> 897 bytes
-rw-r--r--ldap/clients/dsgw/html/alert.gifbin0 -> 368 bytes
-rw-r--r--ldap/clients/dsgw/html/alert.html24
-rw-r--r--ldap/clients/dsgw/html/auth.html26
-rw-r--r--ldap/clients/dsgw/html/authroot.html26
-rw-r--r--ldap/clients/dsgw/html/authtitle.html156
-rw-r--r--ldap/clients/dsgw/html/back1.gifbin0 -> 1068 bytes
-rw-r--r--ldap/clients/dsgw/html/clear.gifbin0 -> 43 bytes
-rw-r--r--ldap/clients/dsgw/html/confirm.gifbin0 -> 372 bytes
-rw-r--r--ldap/clients/dsgw/html/confirm.html30
-rw-r--r--ldap/clients/dsgw/html/content1.gifbin0 -> 1131 bytes
-rw-r--r--ldap/clients/dsgw/html/country.gifbin0 -> 298 bytes
-rw-r--r--ldap/clients/dsgw/html/csearchtitle.html156
-rw-r--r--ldap/clients/dsgw/html/dc.gifbin0 -> 268 bytes
-rw-r--r--ldap/clients/dsgw/html/de/adsearch_off.gifbin0 -> 1348 bytes
-rw-r--r--ldap/clients/dsgw/html/de/adsearch_on.gifbin0 -> 1348 bytes
-rw-r--r--ldap/clients/dsgw/html/de/auth.html24
-rw-r--r--ldap/clients/dsgw/html/de/authen_off.gifbin0 -> 1335 bytes
-rw-r--r--ldap/clients/dsgw/html/de/authen_on.gifbin0 -> 1330 bytes
-rw-r--r--ldap/clients/dsgw/html/de/authroot.html22
-rw-r--r--ldap/clients/dsgw/html/de/authtitle.html37
-rw-r--r--ldap/clients/dsgw/html/de/back.gifbin0 -> 384 bytes
-rw-r--r--ldap/clients/dsgw/html/de/back1.gifbin0 -> 276 bytes
-rw-r--r--ldap/clients/dsgw/html/de/content.gifbin0 -> 681 bytes
-rw-r--r--ldap/clients/dsgw/html/de/content1.gifbin0 -> 317 bytes
-rw-r--r--ldap/clients/dsgw/html/de/csearchtitle.html37
-rw-r--r--ldap/clients/dsgw/html/de/eduser.html30
-rw-r--r--ldap/clients/dsgw/html/de/exit1.gifbin0 -> 352 bytes
-rw-r--r--ldap/clients/dsgw/html/de/forward1.gifbin0 -> 281 bytes
-rw-r--r--ldap/clients/dsgw/html/de/greeting.html64
-rw-r--r--ldap/clients/dsgw/html/de/index.html21
-rw-r--r--ldap/clients/dsgw/html/de/index1.gifbin0 -> 316 bytes
-rw-r--r--ldap/clients/dsgw/html/de/maintitle.html37
-rw-r--r--ldap/clients/dsgw/html/de/newentry_off.gifbin0 -> 1324 bytes
-rw-r--r--ldap/clients/dsgw/html/de/newentry_on.gifbin0 -> 1325 bytes
-rw-r--r--ldap/clients/dsgw/html/de/newentrytitle.html37
-rw-r--r--ldap/clients/dsgw/html/de/searchtitle.html37
-rw-r--r--ldap/clients/dsgw/html/de/stsearch_off.gifbin0 -> 1328 bytes
-rw-r--r--ldap/clients/dsgw/html/de/stsearch_on.gifbin0 -> 1334 bytes
-rw-r--r--ldap/clients/dsgw/html/de/title.gifbin0 -> 4534 bytes
-rw-r--r--ldap/clients/dsgw/html/eduser.html31
-rw-r--r--ldap/clients/dsgw/html/emptyFrame.html7
-rw-r--r--ldap/clients/dsgw/html/es/adsearch_off.gifbin0 -> 587 bytes
-rw-r--r--ldap/clients/dsgw/html/es/adsearch_on.gifbin0 -> 630 bytes
-rw-r--r--ldap/clients/dsgw/html/es/auth.html23
-rw-r--r--ldap/clients/dsgw/html/es/authen_off.gifbin0 -> 544 bytes
-rw-r--r--ldap/clients/dsgw/html/es/authen_on.gifbin0 -> 598 bytes
-rw-r--r--ldap/clients/dsgw/html/es/authroot.html22
-rw-r--r--ldap/clients/dsgw/html/es/authtitle.html37
-rw-r--r--ldap/clients/dsgw/html/es/back1.gifbin0 -> 1086 bytes
-rw-r--r--ldap/clients/dsgw/html/es/blank.gifbin0 -> 278 bytes
-rw-r--r--ldap/clients/dsgw/html/es/content1.gifbin0 -> 1146 bytes
-rw-r--r--ldap/clients/dsgw/html/es/country.gifbin0 -> 1044 bytes
-rw-r--r--ldap/clients/dsgw/html/es/csearchtitle.html37
-rw-r--r--ldap/clients/dsgw/html/es/eduser.html30
-rw-r--r--ldap/clients/dsgw/html/es/exit1.gifbin0 -> 1144 bytes
-rw-r--r--ldap/clients/dsgw/html/es/forward1.gifbin0 -> 1095 bytes
-rw-r--r--ldap/clients/dsgw/html/es/greeting.html64
-rw-r--r--ldap/clients/dsgw/html/es/group.gifbin0 -> 1032 bytes
-rw-r--r--ldap/clients/dsgw/html/es/index.html20
-rw-r--r--ldap/clients/dsgw/html/es/index1.gifbin0 -> 1134 bytes
-rw-r--r--ldap/clients/dsgw/html/es/maintitle.html37
-rw-r--r--ldap/clients/dsgw/html/es/newentry_off.gifbin0 -> 542 bytes
-rw-r--r--ldap/clients/dsgw/html/es/newentry_on.gifbin0 -> 591 bytes
-rw-r--r--ldap/clients/dsgw/html/es/newentrytitle.html37
-rw-r--r--ldap/clients/dsgw/html/es/organization.gifbin0 -> 1023 bytes
-rw-r--r--ldap/clients/dsgw/html/es/orgunit.gifbin0 -> 1060 bytes
-rw-r--r--ldap/clients/dsgw/html/es/person.gifbin0 -> 1042 bytes
-rw-r--r--ldap/clients/dsgw/html/es/searchtitle.html37
-rw-r--r--ldap/clients/dsgw/html/es/stsearch_off.gifbin0 -> 558 bytes
-rw-r--r--ldap/clients/dsgw/html/es/stsearch_on.gifbin0 -> 612 bytes
-rw-r--r--ldap/clients/dsgw/html/es/title.gifbin0 -> 3888 bytes
-rw-r--r--ldap/clients/dsgw/html/exit1.gifbin0 -> 1128 bytes
-rw-r--r--ldap/clients/dsgw/html/forward1.gifbin0 -> 1080 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/adsearch_off.gifbin0 -> 1367 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/adsearch_on.gifbin0 -> 1358 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/auth.html24
-rw-r--r--ldap/clients/dsgw/html/fr/authen_off.gifbin0 -> 1338 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/authen_on.gifbin0 -> 1339 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/authroot.html22
-rw-r--r--ldap/clients/dsgw/html/fr/authtitle.html37
-rw-r--r--ldap/clients/dsgw/html/fr/back.gifbin0 -> 373 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/back1.gifbin0 -> 278 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/content.gifbin0 -> 676 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/content1.gifbin0 -> 319 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/csearchtitle.html37
-rw-r--r--ldap/clients/dsgw/html/fr/eduser.html32
-rw-r--r--ldap/clients/dsgw/html/fr/exit1.gifbin0 -> 374 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/forward1.gifbin0 -> 313 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/greeting.html65
-rw-r--r--ldap/clients/dsgw/html/fr/index.html20
-rw-r--r--ldap/clients/dsgw/html/fr/index1.gifbin0 -> 316 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/maintitle.html38
-rw-r--r--ldap/clients/dsgw/html/fr/newentry_off.gifbin0 -> 1330 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/newentry_on.gifbin0 -> 1338 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/newentrytitle.html38
-rw-r--r--ldap/clients/dsgw/html/fr/searchtitle.html38
-rw-r--r--ldap/clients/dsgw/html/fr/stsearch_off.gifbin0 -> 1374 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/stsearch_on.gifbin0 -> 1370 bytes
-rw-r--r--ldap/clients/dsgw/html/fr/title.gifbin0 -> 4545 bytes
-rw-r--r--ldap/clients/dsgw/html/greeting.html89
-rw-r--r--ldap/clients/dsgw/html/group.gifbin0 -> 297 bytes
-rw-r--r--ldap/clients/dsgw/html/index.html24
-rw-r--r--ldap/clients/dsgw/html/index1.gifbin0 -> 1121 bytes
-rw-r--r--ldap/clients/dsgw/html/info/Makefile40
-rw-r--r--ldap/clients/dsgw/html/info/infonav.html31
-rw-r--r--ldap/clients/dsgw/html/ja/adsearch_off.gifbin0 -> 541 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/adsearch_on.gifbin0 -> 600 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/auth.html23
-rw-r--r--ldap/clients/dsgw/html/ja/authen_off.gifbin0 -> 478 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/authen_on.gifbin0 -> 1267 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/authroot.html23
-rw-r--r--ldap/clients/dsgw/html/ja/authtitle.html37
-rw-r--r--ldap/clients/dsgw/html/ja/back.gifbin0 -> 463 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/back1.gifbin0 -> 270 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/content.gifbin0 -> 628 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/content1.gifbin0 -> 325 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/csearchtitle.html37
-rw-r--r--ldap/clients/dsgw/html/ja/eduser.html30
-rw-r--r--ldap/clients/dsgw/html/ja/exit1.gifbin0 -> 369 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/forward1.gifbin0 -> 270 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/greeting.html65
-rw-r--r--ldap/clients/dsgw/html/ja/index.html20
-rw-r--r--ldap/clients/dsgw/html/ja/index1.gifbin0 -> 324 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/maintitle.html37
-rw-r--r--ldap/clients/dsgw/html/ja/newentry_off.gifbin0 -> 542 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/newentry_on.gifbin0 -> 1340 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/newentrytitle.html37
-rw-r--r--ldap/clients/dsgw/html/ja/searchtitle.html37
-rw-r--r--ldap/clients/dsgw/html/ja/stsearch_off.gifbin0 -> 534 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/stsearch_on.gifbin0 -> 1337 bytes
-rw-r--r--ldap/clients/dsgw/html/ja/title.gifbin0 -> 4976 bytes
-rw-r--r--ldap/clients/dsgw/html/left_bottom.gifbin0 -> 44 bytes
-rw-r--r--ldap/clients/dsgw/html/left_off.gifbin0 -> 73 bytes
-rw-r--r--ldap/clients/dsgw/html/left_on.gifbin0 -> 87 bytes
-rw-r--r--ldap/clients/dsgw/html/maintitle.html152
-rw-r--r--ldap/clients/dsgw/html/manual/Makefile56
-rw-r--r--ldap/clients/dsgw/html/manual/a.gifbin0 -> 181 bytes
-rw-r--r--ldap/clients/dsgw/html/manual/add.htm681
-rw-r--r--ldap/clients/dsgw/html/manual/attribua.gif103
-rw-r--r--ldap/clients/dsgw/html/manual/attribut.htm6712
-rw-r--r--ldap/clients/dsgw/html/manual/auth.htm286
-rw-r--r--ldap/clients/dsgw/html/manual/contents.html185
-rw-r--r--ldap/clients/dsgw/html/manual/dn.htm262
-rw-r--r--ldap/clients/dsgw/html/manual/dna.gifbin0 -> 185 bytes
-rw-r--r--ldap/clients/dsgw/html/manual/filters.htm622
-rw-r--r--ldap/clients/dsgw/html/manual/index.html150
-rw-r--r--ldap/clients/dsgw/html/manual/index.map49
-rw-r--r--ldap/clients/dsgw/html/manual/intro.htm70
-rw-r--r--ldap/clients/dsgw/html/manual/ja/add.htm517
-rw-r--r--ldap/clients/dsgw/html/manual/ja/attribut.htm7139
-rw-r--r--ldap/clients/dsgw/html/manual/ja/auth.htm151
-rw-r--r--ldap/clients/dsgw/html/manual/ja/contents.html172
-rw-r--r--ldap/clients/dsgw/html/manual/ja/filters.htm1062
-rw-r--r--ldap/clients/dsgw/html/manual/ja/intro.htm39
-rw-r--r--ldap/clients/dsgw/html/manual/ja/mod.htm670
-rw-r--r--ldap/clients/dsgw/html/manual/ja/objclass.htm7249
-rw-r--r--ldap/clients/dsgw/html/manual/ja/search.htm380
-rw-r--r--ldap/clients/dsgw/html/manual/mod.htm828
-rw-r--r--ldap/clients/dsgw/html/manual/n.gifbin0 -> 181 bytes
-rw-r--r--ldap/clients/dsgw/html/manual/objclass.htm7246
-rw-r--r--ldap/clients/dsgw/html/manual/search.htm651
-rw-r--r--ldap/clients/dsgw/html/manual/t.gifbin0 -> 147 bytes
-rw-r--r--ldap/clients/dsgw/html/manual/y.gifbin0 -> 176 bytes
-rw-r--r--ldap/clients/dsgw/html/message.gifbin0 -> 693 bytes
-rw-r--r--ldap/clients/dsgw/html/netscape.gifbin0 -> 207 bytes
-rw-r--r--ldap/clients/dsgw/html/newentrytitle.html156
-rw-r--r--ldap/clients/dsgw/html/organization.gifbin0 -> 268 bytes
-rw-r--r--ldap/clients/dsgw/html/orgicon.gifbin0 -> 884 bytes
-rw-r--r--ldap/clients/dsgw/html/orgunit.gifbin0 -> 296 bytes
-rw-r--r--ldap/clients/dsgw/html/person.gifbin0 -> 287 bytes
-rw-r--r--ldap/clients/dsgw/html/right_bottom.gifbin0 -> 44 bytes
-rw-r--r--ldap/clients/dsgw/html/right_off.gifbin0 -> 80 bytes
-rw-r--r--ldap/clients/dsgw/html/right_on.gifbin0 -> 130 bytes
-rw-r--r--ldap/clients/dsgw/html/searchtitle.html157
-rw-r--r--ldap/clients/dsgw/html/style.css142
-rw-r--r--ldap/clients/dsgw/html/transparent.gifbin0 -> 278 bytes
-rw-r--r--ldap/clients/dsgw/htmlout.c431
-rw-r--r--ldap/clients/dsgw/htmlparse.c805
-rw-r--r--ldap/clients/dsgw/lang.c246
-rw-r--r--ldap/clients/dsgw/ldaputil.c1564
-rw-r--r--ldap/clients/dsgw/newentry.c447
-rw-r--r--ldap/clients/dsgw/pbconfig/Makefile50
-rw-r--r--ldap/clients/dsgw/pbconfig/authPassword.html43
-rw-r--r--ldap/clients/dsgw/pbconfig/authSearch.html44
-rw-r--r--ldap/clients/dsgw/pbconfig/display-orgperson.html388
-rw-r--r--ldap/clients/dsgw/pbconfig/display-orgunit.html198
-rw-r--r--ldap/clients/dsgw/pbconfig/display-room.html124
-rw-r--r--ldap/clients/dsgw/pbconfig/dsgwfilter.conf89
-rw-r--r--ldap/clients/dsgw/pbconfig/dsgwsearchprefs.conf126
-rw-r--r--ldap/clients/dsgw/pbconfig/edit-passwd.html111
-rw-r--r--ldap/clients/dsgw/pbconfig/list-Auth.html116
-rw-r--r--ldap/clients/dsgw/pbconfig/list-People.html125
-rw-r--r--ldap/clients/dsgw/pbconfig/pb.tmpl126
-rw-r--r--ldap/clients/dsgw/pbhtml/16-conference.gifbin0 -> 191 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/16-person.gifbin0 -> 74 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/32-alert.gifbin0 -> 372 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/32-conference.gifbin0 -> 362 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/32-message.gifbin0 -> 693 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/32-office.gifbin0 -> 376 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/32-person.gifbin0 -> 145 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/Makefile53
-rw-r--r--ldap/clients/dsgw/pbhtml/aim-online.gifbin0 -> 897 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/alert.html24
-rw-r--r--ldap/clients/dsgw/pbhtml/brandblock.gifbin0 -> 1111 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/carded.html44
-rw-r--r--ldap/clients/dsgw/pbhtml/clear.gifbin0 -> 43 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/conference.gifbin0 -> 545 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/confirm.html30
-rw-r--r--ldap/clients/dsgw/pbhtml/department.gifbin0 -> 1023 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/emptyFrame.html7
-rw-r--r--ldap/clients/dsgw/pbhtml/get_cert.gifbin0 -> 545 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/get_cert_sm.gifbin0 -> 319 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/index.html41
-rw-r--r--ldap/clients/dsgw/pbhtml/intro.html207
-rw-r--r--ldap/clients/dsgw/pbhtml/modify.html292
-rw-r--r--ldap/clients/dsgw/pbhtml/nonemp.html69
-rw-r--r--ldap/clients/dsgw/pbhtml/nullStringError.html64
-rw-r--r--ldap/clients/dsgw/pbhtml/office.gifbin0 -> 1072 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/orgicon.gifbin0 -> 884 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/pbrd.jpgbin0 -> 17206 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/person.gifbin0 -> 2674 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/phone.html87
-rwxr-xr-xldap/clients/dsgw/pbhtml/phone.js43
-rw-r--r--ldap/clients/dsgw/pbhtml/pixel.gifbin0 -> 43 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/report.html155
-rw-r--r--ldap/clients/dsgw/pbhtml/style.css88
-rw-r--r--ldap/clients/dsgw/pbhtml/tiny_cert.gifbin0 -> 164 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/tiny_vcard.gifbin0 -> 153 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/vendor.gifbin0 -> 701 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/view_vcard.gifbin0 -> 454 bytes
-rw-r--r--ldap/clients/dsgw/pbhtml/view_vcard_sm.gifbin0 -> 286 bytes
-rw-r--r--ldap/clients/dsgw/search.c217
-rw-r--r--ldap/clients/dsgw/secglue.c174
-rw-r--r--ldap/clients/dsgw/sort.c138
-rw-r--r--ldap/clients/dsgw/templateindex.c184
-rw-r--r--ldap/clients/dsgw/tutor.c276
-rw-r--r--ldap/clients/dsgw/unauth.c165
-rw-r--r--ldap/clients/dsgw/userhtml/Makefile60
-rw-r--r--ldap/clients/dsgw/userhtml/edit-userpasswd.html85
-rw-r--r--ldap/clients/dsgw/userhtml/edit-userpinfo.html92
-rw-r--r--ldap/clients/dsgw/userhtml/index.html29
-rw-r--r--ldap/clients/dsgw/userhtml/index.lst29
-rw-r--r--ldap/clients/dsgw/utf8compare.c2236
-rw-r--r--ldap/clients/dsgw/vcard.c258
-rw-r--r--ldap/clients/dsmlgw/Makefile16
-rw-r--r--ldap/clients/dsmlgw/build.xml67
-rw-r--r--ldap/clients/dsmlgw/misc/dsmlgw.cfg13
-rw-r--r--ldap/clients/dsmlgw/misc/server-config.wsdd79
-rw-r--r--ldap/clients/dsmlgw/misc/web-app_2_3.dtd1063
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/BatchProcessor.java229
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/Configuration.java97
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/Constants.java142
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/GenericOperation.java47
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/IConnMgrFactoryFunctor.java22
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/IConnectionManager.java30
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/LDAPAuthenticator.java67
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationAdd.java96
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationAuth.java36
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationCompare.java82
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationDelete.java58
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationExtended.java93
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationModify.java134
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationModifyDN.java96
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationSearch.java322
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ParseControl.java131
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ParseFilter.java153
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ProxyConnMgrFactory.java38
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ProxyConnectionManager.java260
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayContext.java84
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayException.java36
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayHandler.java208
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayService.java44
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/test/SOAPClient.java74
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/test/dsmlClient.java90
-rw-r--r--ldap/clients/dsmlgw/src/com/netscape/dsml/test/dsmlSearch.java55
-rw-r--r--ldap/clients/orgchart/aim-online.gifbin0 -> 897 bytes
-rw-r--r--ldap/clients/orgchart/arrow.gifbin0 -> 180 bytes
-rw-r--r--ldap/clients/orgchart/botframe.html26
-rw-r--r--ldap/clients/orgchart/branch-cc1.gifbin0 -> 841 bytes
-rw-r--r--ldap/clients/orgchart/config.tmpl185
-rw-r--r--ldap/clients/orgchart/index.html33
-rw-r--r--ldap/clients/orgchart/ldap-person.gifbin0 -> 121 bytes
-rw-r--r--ldap/clients/orgchart/mag.gifbin0 -> 895 bytes
-rw-r--r--ldap/clients/orgchart/mail.gifbin0 -> 884 bytes
-rw-r--r--ldap/clients/orgchart/myorg.bat2
-rwxr-xr-xldap/clients/orgchart/myorg.pl632
-rw-r--r--ldap/clients/orgchart/new-branch-blank.gifbin0 -> 832 bytes
-rw-r--r--ldap/clients/orgchart/new-branch-first.gifbin0 -> 848 bytes
-rw-r--r--ldap/clients/orgchart/new-branch-straight.gifbin0 -> 852 bytes
-rw-r--r--ldap/clients/orgchart/nslogo.gifbin0 -> 1950 bytes
-rw-r--r--ldap/clients/orgchart/org.bat2
-rwxr-xr-xldap/clients/orgchart/org.pl2004
-rw-r--r--ldap/clients/orgchart/orgicon.gifbin0 -> 884 bytes
-rw-r--r--ldap/clients/orgchart/starthelp.gifbin0 -> 11440 bytes
-rw-r--r--ldap/clients/orgchart/styles.css146
-rw-r--r--ldap/clients/orgchart/topframe.html88
-rw-r--r--ldap/clients/orgchart/wrapper.c89
-rw-r--r--ldap/cm/Makefile938
-rw-r--r--ldap/cm/filterfiles.sh30
-rw-r--r--ldap/cm/fixBaseInf.pl39
-rw-r--r--ldap/cm/fixNSPerlInf.pl55
-rw-r--r--ldap/cm/fixPerlDAPInf.pl33
-rw-r--r--ldap/cm/fixSetupInf.pl82
-rw-r--r--ldap/cm/ldapjava.mpw8
-rw-r--r--ldap/cm/nbsp2utf8.sh15
-rw-r--r--ldap/cm/newinst/Makefile159
-rw-r--r--ldap/cm/newinst/fixINF.pl50
-rwxr-xr-xldap/cm/newinst/ns-keygen168
-rwxr-xr-xldap/cm/newinst/ns-update135
-rw-r--r--ldap/cm/newinst/replaceToken.pl34
-rwxr-xr-xldap/cm/newinst/setup.pl141
-rwxr-xr-xldap/cm/newinst/setup.sh10
-rw-r--r--ldap/cm/newinst/slapd.inf48
-rwxr-xr-xldap/cm/newinst/uninstall75
-rw-r--r--ldap/cm/newinst/ux-config.cc1151
-rw-r--r--ldap/cm/newinst/ux-config.h172
-rw-r--r--ldap/cm/newinst/ux-dialog.cc4332
-rw-r--r--ldap/cm/newinst/ux-dialog.h69
-rw-r--r--ldap/cm/newinst/ux-dsalib_dn.c13
-rw-r--r--ldap/cm/newinst/ux-guesses.cc125
-rw-r--r--ldap/cm/newinstnt/Makefile91
-rw-r--r--ldap/cm/newinstnt/consolinst.c320
-rw-r--r--ldap/cm/newinstnt/consolinst.h39
-rw-r--r--ldap/cm/newinstnt/dsinst.apsbin0 -> 121483 bytes
-rw-r--r--ldap/cm/newinstnt/dsinst.c8316
-rw-r--r--ldap/cm/newinstnt/dsinst.h248
-rw-r--r--ldap/cm/newinstnt/dsinst.rc710
-rw-r--r--ldap/cm/newinstnt/dsinst_dsalib_dn.c7
-rw-r--r--ldap/cm/newinstnt/libinst.c136
-rw-r--r--ldap/cm/newinstnt/libinst.h26
-rw-r--r--ldap/cm/newinstnt/resource.h334
-rw-r--r--ldap/cm/newinstnt/setup.bat3
-rw-r--r--ldap/cm/newinstnt/setup.inf42
-rw-r--r--ldap/cm/newinstnt/slapd.inf62
-rw-r--r--ldap/cm/newinstnt/wizard.bmpbin0 -> 31760 bytes
-rw-r--r--ldap/cm/ntpack.sh76
-rwxr-xr-xldap/cm/unixstrip31
-rw-r--r--ldap/cm/unixstrip.pl57
-rw-r--r--ldap/cm/v1confs/ns-calendar-globopt.conf10
-rw-r--r--ldap/cm/v1confs/ns-calendar-schema.conf131
-rw-r--r--ldap/cm/v1confs/ns-certificate-globopt.conf9
-rw-r--r--ldap/cm/v1confs/ns-certificate-schema.conf12
-rw-r--r--ldap/cm/v1confs/ns-compass-globopt.conf11
-rw-r--r--ldap/cm/v1confs/ns-compass-schema.conf169
-rw-r--r--ldap/cm/v1confs/ns-directory-globopt.conf9
-rw-r--r--ldap/cm/v1confs/ns-directory-schema.conf12
-rw-r--r--ldap/cm/v1confs/ns-mail-globopt.conf10
-rw-r--r--ldap/cm/v1confs/ns-mail-schema.conf93
-rw-r--r--ldap/cm/v1confs/ns-media-globopt.conf9
-rw-r--r--ldap/cm/v1confs/ns-media-schema.conf12
-rw-r--r--ldap/cm/v1confs/ns-news-globopt.conf10
-rw-r--r--ldap/cm/v1confs/ns-news-schema.conf33
-rw-r--r--ldap/cm/v1confs/ns-proxy-globopt.conf9
-rw-r--r--ldap/cm/v1confs/ns-proxy-schema.conf12
-rw-r--r--ldap/cm/v1confs/ns-web-globopt.conf10
-rw-r--r--ldap/cm/v1confs/ns-web-schema.conf12
-rw-r--r--ldap/cm/v1confs/slapd.at.conf276
-rw-r--r--ldap/cm/v1confs/slapd.oc.conf1077
-rw-r--r--ldap/cm/v3confs/ns-calendar-globopt.conf10
-rw-r--r--ldap/cm/v3confs/ns-calendar-schema.conf135
-rw-r--r--ldap/cm/v3confs/ns-certificate-globopt.conf9
-rw-r--r--ldap/cm/v3confs/ns-certificate-schema.conf13
-rw-r--r--ldap/cm/v3confs/ns-compass-globopt.conf11
-rw-r--r--ldap/cm/v3confs/ns-compass-schema.conf173
-rw-r--r--ldap/cm/v3confs/ns-directory-globopt.conf9
-rw-r--r--ldap/cm/v3confs/ns-directory-schema.conf13
-rw-r--r--ldap/cm/v3confs/ns-mail-globopt.conf10
-rw-r--r--ldap/cm/v3confs/ns-mail-schema.conf97
-rw-r--r--ldap/cm/v3confs/ns-media-globopt.conf9
-rw-r--r--ldap/cm/v3confs/ns-media-schema.conf13
-rw-r--r--ldap/cm/v3confs/ns-news-globopt.conf10
-rw-r--r--ldap/cm/v3confs/ns-news-schema.conf35
-rw-r--r--ldap/cm/v3confs/ns-proxy-globopt.conf9
-rw-r--r--ldap/cm/v3confs/ns-proxy-schema.conf13
-rw-r--r--ldap/cm/v3confs/ns-web-globopt.conf10
-rw-r--r--ldap/cm/v3confs/ns-web-schema.conf13
-rw-r--r--ldap/cm/v3confs/slapd.at.conf319
-rw-r--r--ldap/cm/v3confs/slapd.oc.conf779
-rw-r--r--ldap/cm/v4confs/40/java-object-schema.conf58
-rw-r--r--ldap/cm/v4confs/40/ns-admin-schema.confbin0 -> 3032 bytes
-rw-r--r--ldap/cm/v4confs/40/ns-calendar-globopt.conf10
-rw-r--r--ldap/cm/v4confs/40/ns-calendar-schema.conf148
-rw-r--r--ldap/cm/v4confs/40/ns-certificate-globopt.conf9
-rw-r--r--ldap/cm/v4confs/40/ns-certificate-schema.conf24
-rw-r--r--ldap/cm/v4confs/40/ns-common-schema.conf245
-rw-r--r--ldap/cm/v4confs/40/ns-compass-globopt.conf11
-rw-r--r--ldap/cm/v4confs/40/ns-compass-schema.conf173
-rw-r--r--ldap/cm/v4confs/40/ns-cos-schema.conf29
-rw-r--r--ldap/cm/v4confs/40/ns-delegated-admin-schema.conf62
-rw-r--r--ldap/cm/v4confs/40/ns-directory-globopt.conf9
-rw-r--r--ldap/cm/v4confs/40/ns-directory-schema.conf27
-rw-r--r--ldap/cm/v4confs/40/ns-legacy-schema.conf33
-rw-r--r--ldap/cm/v4confs/40/ns-mail-globopt.conf12
-rw-r--r--ldap/cm/v4confs/40/ns-mail-schema.conf132
-rw-r--r--ldap/cm/v4confs/40/ns-mcd-browser-schema.conf179
-rw-r--r--ldap/cm/v4confs/40/ns-mcd-config-schema.conf55
-rw-r--r--ldap/cm/v4confs/40/ns-mcd-li-globopt.conf9
-rw-r--r--ldap/cm/v4confs/40/ns-mcd-li-schema.conf60
-rw-r--r--ldap/cm/v4confs/40/ns-mcd-mail-schema.conf219
-rw-r--r--ldap/cm/v4confs/40/ns-media-globopt.conf9
-rw-r--r--ldap/cm/v4confs/40/ns-media-schema.conf13
-rw-r--r--ldap/cm/v4confs/40/ns-mlm-schema.conf95
-rw-r--r--ldap/cm/v4confs/40/ns-msg-schema.conf690
-rw-r--r--ldap/cm/v4confs/40/ns-netshare-schema.conf47
-rw-r--r--ldap/cm/v4confs/40/ns-news-globopt.conf10
-rw-r--r--ldap/cm/v4confs/40/ns-news-schema.conf35
-rw-r--r--ldap/cm/v4confs/40/ns-proxy-globopt.conf9
-rw-r--r--ldap/cm/v4confs/40/ns-proxy-schema.conf13
-rw-r--r--ldap/cm/v4confs/40/ns-value-schema.conf42
-rw-r--r--ldap/cm/v4confs/40/ns-wcal-globopt.conf10
-rw-r--r--ldap/cm/v4confs/40/ns-wcal-schema.conf71
-rw-r--r--ldap/cm/v4confs/40/ns-web-globopt.conf10
-rw-r--r--ldap/cm/v4confs/40/ns-web-schema.conf18
-rw-r--r--ldap/cm/v4confs/40/slapd.at.conf391
-rw-r--r--ldap/cm/v4confs/40/slapd.oc.conf1068
-rw-r--r--ldap/cm/v4confs/41/java-object-schema.conf53
-rw-r--r--ldap/cm/v4confs/41/ns-admin-schema.conf155
-rw-r--r--ldap/cm/v4confs/41/ns-calendar-globopt.conf10
-rw-r--r--ldap/cm/v4confs/41/ns-calendar-schema.conf148
-rw-r--r--ldap/cm/v4confs/41/ns-certificate-globopt.conf9
-rw-r--r--ldap/cm/v4confs/41/ns-certificate-schema.conf24
-rw-r--r--ldap/cm/v4confs/41/ns-common-schema.conf246
-rw-r--r--ldap/cm/v4confs/41/ns-compass-globopt.conf11
-rw-r--r--ldap/cm/v4confs/41/ns-compass-schema.conf173
-rw-r--r--ldap/cm/v4confs/41/ns-cos-schema.conf29
-rw-r--r--ldap/cm/v4confs/41/ns-delegated-admin-schema.conf62
-rw-r--r--ldap/cm/v4confs/41/ns-directory-globopt.conf9
-rw-r--r--ldap/cm/v4confs/41/ns-directory-schema.conf27
-rw-r--r--ldap/cm/v4confs/41/ns-legacy-schema.conf33
-rw-r--r--ldap/cm/v4confs/41/ns-mail-globopt.conf12
-rw-r--r--ldap/cm/v4confs/41/ns-mail-schema.conf144
-rw-r--r--ldap/cm/v4confs/41/ns-mcd-browser-schema.conf179
-rw-r--r--ldap/cm/v4confs/41/ns-mcd-config-schema.conf55
-rw-r--r--ldap/cm/v4confs/41/ns-mcd-li-globopt.conf9
-rw-r--r--ldap/cm/v4confs/41/ns-mcd-li-schema.conf60
-rw-r--r--ldap/cm/v4confs/41/ns-mcd-mail-schema.conf219
-rw-r--r--ldap/cm/v4confs/41/ns-media-globopt.conf9
-rw-r--r--ldap/cm/v4confs/41/ns-media-schema.conf13
-rw-r--r--ldap/cm/v4confs/41/ns-mlm-schema.conf102
-rw-r--r--ldap/cm/v4confs/41/ns-msg-schema.conf711
-rw-r--r--ldap/cm/v4confs/41/ns-netshare-schema.conf47
-rw-r--r--ldap/cm/v4confs/41/ns-news-globopt.conf10
-rw-r--r--ldap/cm/v4confs/41/ns-news-schema.conf35
-rw-r--r--ldap/cm/v4confs/41/ns-proxy-globopt.conf9
-rw-r--r--ldap/cm/v4confs/41/ns-proxy-schema.conf13
-rw-r--r--ldap/cm/v4confs/41/ns-value-schema.conf42
-rw-r--r--ldap/cm/v4confs/41/ns-wcal-globopt.conf10
-rw-r--r--ldap/cm/v4confs/41/ns-wcal-schema.conf71
-rw-r--r--ldap/cm/v4confs/41/ns-web-globopt.conf10
-rw-r--r--ldap/cm/v4confs/41/ns-web-schema.conf18
-rw-r--r--ldap/cm/v4confs/41/slapd.at.conf391
-rw-r--r--ldap/cm/v4confs/41/slapd.oc.conf1069
-rw-r--r--ldap/cm/v4confs/411/java-object-schema.conf58
-rw-r--r--ldap/cm/v4confs/411/ns-admin-schema.conf155
-rw-r--r--ldap/cm/v4confs/411/ns-calendar-globopt.conf10
-rw-r--r--ldap/cm/v4confs/411/ns-calendar-schema.conf148
-rw-r--r--ldap/cm/v4confs/411/ns-certificate-globopt.conf9
-rw-r--r--ldap/cm/v4confs/411/ns-certificate-schema.conf24
-rw-r--r--ldap/cm/v4confs/411/ns-common-schema.conf246
-rw-r--r--ldap/cm/v4confs/411/ns-compass-globopt.conf11
-rw-r--r--ldap/cm/v4confs/411/ns-compass-schema.conf173
-rw-r--r--ldap/cm/v4confs/411/ns-cos-schema.conf29
-rw-r--r--ldap/cm/v4confs/411/ns-delegated-admin-schema.conf97
-rw-r--r--ldap/cm/v4confs/411/ns-directory-globopt.conf9
-rw-r--r--ldap/cm/v4confs/411/ns-directory-schema.conf27
-rw-r--r--ldap/cm/v4confs/411/ns-legacy-schema.conf33
-rw-r--r--ldap/cm/v4confs/411/ns-mail-globopt.conf12
-rw-r--r--ldap/cm/v4confs/411/ns-mail-schema.conf144
-rw-r--r--ldap/cm/v4confs/411/ns-mcd-browser-schema.conf179
-rw-r--r--ldap/cm/v4confs/411/ns-mcd-config-schema.conf55
-rw-r--r--ldap/cm/v4confs/411/ns-mcd-li-globopt.conf9
-rw-r--r--ldap/cm/v4confs/411/ns-mcd-li-schema.conf60
-rw-r--r--ldap/cm/v4confs/411/ns-mcd-mail-schema.conf219
-rw-r--r--ldap/cm/v4confs/411/ns-media-globopt.conf9
-rw-r--r--ldap/cm/v4confs/411/ns-media-schema.conf13
-rw-r--r--ldap/cm/v4confs/411/ns-mlm-schema.conf102
-rw-r--r--ldap/cm/v4confs/411/ns-msg-schema.conf711
-rw-r--r--ldap/cm/v4confs/411/ns-netshare-schema.conf47
-rw-r--r--ldap/cm/v4confs/411/ns-news-globopt.conf10
-rw-r--r--ldap/cm/v4confs/411/ns-news-schema.conf35
-rw-r--r--ldap/cm/v4confs/411/ns-proxy-globopt.conf9
-rw-r--r--ldap/cm/v4confs/411/ns-proxy-schema.conf13
-rw-r--r--ldap/cm/v4confs/411/ns-value-schema.conf42
-rw-r--r--ldap/cm/v4confs/411/ns-wcal-globopt.conf10
-rw-r--r--ldap/cm/v4confs/411/ns-wcal-schema.conf71
-rw-r--r--ldap/cm/v4confs/411/ns-web-globopt.conf10
-rw-r--r--ldap/cm/v4confs/411/ns-web-schema.conf18
-rw-r--r--ldap/cm/v4confs/411/slapd.at.conf391
-rw-r--r--ldap/cm/v4confs/411/slapd.oc.conf1069
-rw-r--r--ldap/cm/v4confs/412/java-object-schema.conf58
-rw-r--r--ldap/cm/v4confs/412/ns-admin-schema.conf155
-rw-r--r--ldap/cm/v4confs/412/ns-calendar-globopt.conf10
-rw-r--r--ldap/cm/v4confs/412/ns-calendar-schema.conf148
-rw-r--r--ldap/cm/v4confs/412/ns-certificate-globopt.conf9
-rw-r--r--ldap/cm/v4confs/412/ns-certificate-schema.conf24
-rw-r--r--ldap/cm/v4confs/412/ns-common-schema.conf246
-rw-r--r--ldap/cm/v4confs/412/ns-compass-globopt.conf11
-rw-r--r--ldap/cm/v4confs/412/ns-compass-schema.conf173
-rw-r--r--ldap/cm/v4confs/412/ns-cos-schema.conf29
-rw-r--r--ldap/cm/v4confs/412/ns-delegated-admin-schema.conf114
-rw-r--r--ldap/cm/v4confs/412/ns-directory-globopt.conf9
-rw-r--r--ldap/cm/v4confs/412/ns-directory-schema.conf27
-rw-r--r--ldap/cm/v4confs/412/ns-legacy-schema.conf33
-rw-r--r--ldap/cm/v4confs/412/ns-mail-globopt.conf12
-rw-r--r--ldap/cm/v4confs/412/ns-mail-schema.conf144
-rw-r--r--ldap/cm/v4confs/412/ns-mcd-browser-schema.conf179
-rw-r--r--ldap/cm/v4confs/412/ns-mcd-config-schema.conf55
-rw-r--r--ldap/cm/v4confs/412/ns-mcd-li-globopt.conf9
-rw-r--r--ldap/cm/v4confs/412/ns-mcd-li-schema.conf60
-rw-r--r--ldap/cm/v4confs/412/ns-mcd-mail-schema.conf219
-rw-r--r--ldap/cm/v4confs/412/ns-media-globopt.conf9
-rw-r--r--ldap/cm/v4confs/412/ns-media-schema.conf13
-rw-r--r--ldap/cm/v4confs/412/ns-mlm-schema.conf102
-rw-r--r--ldap/cm/v4confs/412/ns-msg-schema.conf711
-rw-r--r--ldap/cm/v4confs/412/ns-netshare-schema.conf47
-rw-r--r--ldap/cm/v4confs/412/ns-news-globopt.conf10
-rw-r--r--ldap/cm/v4confs/412/ns-news-schema.conf35
-rw-r--r--ldap/cm/v4confs/412/ns-proxy-globopt.conf9
-rw-r--r--ldap/cm/v4confs/412/ns-proxy-schema.conf13
-rw-r--r--ldap/cm/v4confs/412/ns-value-schema.conf42
-rw-r--r--ldap/cm/v4confs/412/ns-wcal-globopt.conf10
-rw-r--r--ldap/cm/v4confs/412/ns-wcal-schema.conf71
-rw-r--r--ldap/cm/v4confs/412/ns-web-globopt.conf10
-rw-r--r--ldap/cm/v4confs/412/ns-web-schema.conf18
-rw-r--r--ldap/cm/v4confs/412/slapd.at.conf391
-rw-r--r--ldap/cm/v4confs/412/slapd.oc.conf1069
-rw-r--r--ldap/docs/LICENSE.txt6
-rw-r--r--ldap/docs/README.txt19
-rw-r--r--ldap/docs/dirhlp/Makefile196
-rw-r--r--ldap/docs/dirhlp/dssynchhelp.zbin0 -> 256000 bytes
-rw-r--r--ldap/docs/dirhlp/help/account_mgmt.htm183
-rw-r--r--ldap/docs/dirhlp/help/adv_search.htm142
-rw-r--r--ldap/docs/dirhlp/help/configtab_chaindb.htm189
-rw-r--r--ldap/docs/dirhlp/help/configtab_chaindb2.htm191
-rw-r--r--ldap/docs/dirhlp/help/configtab_chaindb3.htm325
-rw-r--r--ldap/docs/dirhlp/help/configtab_chaindb4.htm277
-rw-r--r--ldap/docs/dirhlp/help/configtab_chaindb5.htm242
-rw-r--r--ldap/docs/dirhlp/help/configtab_chaindb6.htm249
-rw-r--r--ldap/docs/dirhlp/help/configtab_chaindb7.htm193
-rw-r--r--ldap/docs/dirhlp/help/configtab_db.htm207
-rw-r--r--ldap/docs/dirhlp/help/configtab_db10.htm161
-rw-r--r--ldap/docs/dirhlp/help/configtab_db11.htm154
-rw-r--r--ldap/docs/dirhlp/help/configtab_db12.htm170
-rw-r--r--ldap/docs/dirhlp/help/configtab_db13.htm112
-rw-r--r--ldap/docs/dirhlp/help/configtab_db14.htm87
-rw-r--r--ldap/docs/dirhlp/help/configtab_db15.htm94
-rw-r--r--ldap/docs/dirhlp/help/configtab_db2.htm239
-rw-r--r--ldap/docs/dirhlp/help/configtab_db3.htm169
-rw-r--r--ldap/docs/dirhlp/help/configtab_db4.htm142
-rw-r--r--ldap/docs/dirhlp/help/configtab_db5.htm158
-rw-r--r--ldap/docs/dirhlp/help/configtab_db6.htm168
-rw-r--r--ldap/docs/dirhlp/help/configtab_db7.htm165
-rw-r--r--ldap/docs/dirhlp/help/configtab_db8.htm175
-rw-r--r--ldap/docs/dirhlp/help/configtab_db9.htm177
-rw-r--r--ldap/docs/dirhlp/help/configtab_ldbmdb.htm154
-rw-r--r--ldap/docs/dirhlp/help/configtab_logs.htm217
-rw-r--r--ldap/docs/dirhlp/help/configtab_logs2.htm221
-rw-r--r--ldap/docs/dirhlp/help/configtab_logs3.htm217
-rw-r--r--ldap/docs/dirhlp/help/configtab_maptree.htm177
-rw-r--r--ldap/docs/dirhlp/help/configtab_maptree2.htm138
-rw-r--r--ldap/docs/dirhlp/help/configtab_maptree3.htm175
-rw-r--r--ldap/docs/dirhlp/help/configtab_maptree4.htm161
-rw-r--r--ldap/docs/dirhlp/help/configtab_maptree5.htm161
-rw-r--r--ldap/docs/dirhlp/help/configtab_maptree6.htm169
-rw-r--r--ldap/docs/dirhlp/help/configtab_maptree7.htm157
-rw-r--r--ldap/docs/dirhlp/help/configtab_plugins.htm174
-rw-r--r--ldap/docs/dirhlp/help/configtab_replication.htm165
-rw-r--r--ldap/docs/dirhlp/help/configtab_replication2.htm177
-rw-r--r--ldap/docs/dirhlp/help/configtab_replication3.htm193
-rw-r--r--ldap/docs/dirhlp/help/configtab_replication4.htm170
-rw-r--r--ldap/docs/dirhlp/help/configtab_replication5.htm150
-rw-r--r--ldap/docs/dirhlp/help/configtab_replication6.htm176
-rw-r--r--ldap/docs/dirhlp/help/configtab_replication7.htm146
-rw-r--r--ldap/docs/dirhlp/help/configtab_replication8.htm146
-rw-r--r--ldap/docs/dirhlp/help/configtab_rootnode.htm162
-rw-r--r--ldap/docs/dirhlp/help/configtab_rootnode2.htm154
-rw-r--r--ldap/docs/dirhlp/help/configtab_rootnode3.htm341
-rw-r--r--ldap/docs/dirhlp/help/configtab_rootnode4.htm153
-rw-r--r--ldap/docs/dirhlp/help/configtab_rootnode5.htm181
-rw-r--r--ldap/docs/dirhlp/help/configtab_rootnode6.htm180
-rw-r--r--ldap/docs/dirhlp/help/configtab_rootnode7.htm118
-rw-r--r--ldap/docs/dirhlp/help/configtab_rootnode8.htm96
-rw-r--r--ldap/docs/dirhlp/help/configtab_rootnode9.htm96
-rw-r--r--ldap/docs/dirhlp/help/configtab_schema.htm181
-rw-r--r--ldap/docs/dirhlp/help/configtab_schema2.htm177
-rw-r--r--ldap/docs/dirhlp/help/configtab_schema3.htm195
-rw-r--r--ldap/docs/dirhlp/help/configtab_schema4.htm173
-rw-r--r--ldap/docs/dirhlp/help/configtab_schema5.htm211
-rw-r--r--ldap/docs/dirhlp/help/dir_browser.htm138
-rw-r--r--ldap/docs/dirhlp/help/dir_browser2.htm239
-rw-r--r--ldap/docs/dirhlp/help/dir_browser3.htm169
-rw-r--r--ldap/docs/dirhlp/help/dir_browser4.htm189
-rw-r--r--ldap/docs/dirhlp/help/dirtab_cos.htm169
-rw-r--r--ldap/docs/dirhlp/help/dirtab_cos2.htm161
-rw-r--r--ldap/docs/dirhlp/help/dirtab_cos3.htm181
-rw-r--r--ldap/docs/dirhlp/help/dirtab_role.htm213
-rw-r--r--ldap/docs/dirhlp/help/dirtab_role2.htm161
-rw-r--r--ldap/docs/dirhlp/help/dirtab_role3.htm161
-rw-r--r--ldap/docs/dirhlp/help/dirtab_role4.htm157
-rw-r--r--ldap/docs/dirhlp/help/dirtab_role5.htm161
-rw-r--r--ldap/docs/dirhlp/help/dirtab_role6.htm157
-rw-r--r--ldap/docs/dirhlp/help/dirtab_role7.htm161
-rw-r--r--ldap/docs/dirhlp/help/helpmenu.htm204
-rw-r--r--ldap/docs/dirhlp/help/ix.htm228
-rw-r--r--ldap/docs/dirhlp/help/ldapurl.htm154
-rw-r--r--ldap/docs/dirhlp/help/netscape32.gifbin0 -> 1529 bytes
-rw-r--r--ldap/docs/dirhlp/help/new_instance.htm166
-rw-r--r--ldap/docs/dirhlp/help/pixel.gifbin0 -> 45 bytes
-rw-r--r--ldap/docs/dirhlp/help/property_editor.htm185
-rw-r--r--ldap/docs/dirhlp/help/property_editor2.htm142
-rw-r--r--ldap/docs/dirhlp/help/property_editor3.htm188
-rw-r--r--ldap/docs/dirhlp/help/property_editor4.htm186
-rw-r--r--ldap/docs/dirhlp/help/redir_agtoc.htm136
-rw-r--r--ldap/docs/dirhlp/help/redir_dochome.htm113
-rw-r--r--ldap/docs/dirhlp/help/replication_wizard.htm196
-rw-r--r--ldap/docs/dirhlp/help/replication_wizard2.htm150
-rw-r--r--ldap/docs/dirhlp/help/replication_wizard3.htm169
-rw-r--r--ldap/docs/dirhlp/help/replication_wizard4.htm142
-rw-r--r--ldap/docs/dirhlp/help/replication_wizard5.htm146
-rwxr-xr-xldap/docs/dirhlp/help/sniffer.js104
-rw-r--r--ldap/docs/dirhlp/help/statustab_general.htm182
-rw-r--r--ldap/docs/dirhlp/help/statustab_logs.htm189
-rw-r--r--ldap/docs/dirhlp/help/statustab_logs2.htm181
-rw-r--r--ldap/docs/dirhlp/help/statustab_logs3.htm169
-rw-r--r--ldap/docs/dirhlp/help/statustab_performance.htm363
-rw-r--r--ldap/docs/dirhlp/help/statustab_performance2.htm237
-rw-r--r--ldap/docs/dirhlp/help/statustab_replication.htm213
-rw-r--r--ldap/docs/dirhlp/help/taskstab_bkup_restore.htm165
-rw-r--r--ldap/docs/dirhlp/help/taskstab_bkup_restore2.htm157
-rw-r--r--ldap/docs/dirhlp/help/topics.htm531
-rw-r--r--ldap/docs/dirhlp/index.htm297
-rw-r--r--ldap/docs/dirhlp/index.map149
-rw-r--r--ldap/docs/dirhlp/pixel.gifbin0 -> 45 bytes
-rw-r--r--ldap/docs/dirhlp/tokens.map166
-rw-r--r--ldap/docs/dirhlp/topicindex.htm662
-rw-r--r--ldap/dsml/European.dsml17598
-rw-r--r--ldap/dsml/Example-roles.dsml6514
-rw-r--r--ldap/dsml/Example.dsml6501
-rw-r--r--ldap/include/Makefile53
-rw-r--r--ldap/include/Makefile.client54
-rw-r--r--ldap/include/avl.h67
-rw-r--r--ldap/include/dblayer.h7
-rw-r--r--ldap/include/dirlite_strings.h62
-rw-r--r--ldap/include/disptmpl.h348
-rw-r--r--ldap/include/ldaplog.h84
-rw-r--r--ldap/include/ldaprot.h167
-rw-r--r--ldap/include/ldbm.h380
-rw-r--r--ldap/include/ldif.h76
-rw-r--r--ldap/include/litekey.h30
-rw-r--r--ldap/include/lthread.h423
-rw-r--r--ldap/include/ntslapdregparms.h41
-rw-r--r--ldap/include/ntwatchdog.h68
-rw-r--r--ldap/include/portable.h380
-rw-r--r--ldap/include/proto-ntutil.h79
-rw-r--r--ldap/include/regex.h63
-rw-r--r--ldap/include/srchpref.h123
-rw-r--r--ldap/include/sysexits-compat.h107
-rw-r--r--ldap/javarules.mk118
-rw-r--r--ldap/ldif/Ace.ldif2604
-rw-r--r--ldap/ldif/European.ldif7589
-rw-r--r--ldap/ldif/Eurosuffix.ldif12
-rw-r--r--ldap/ldif/Example-roles.ldif2995
-rw-r--r--ldap/ldif/Example-views.ldif3167
-rw-r--r--ldap/ldif/Example.ldif2981
-rw-r--r--ldap/ldif/commonTasks.ldif45
-rw-r--r--ldap/ldif/roledit.ldif50
-rw-r--r--ldap/ldif/tasks.ldif134
-rw-r--r--ldap/ldif/template.ldif83
-rw-r--r--ldap/libraries/Makefile370
-rw-r--r--ldap/libraries/Makefile.client37
-rw-r--r--ldap/libraries/libavl/Makefile52
-rw-r--r--ldap/libraries/libavl/avl.c773
-rw-r--r--ldap/libraries/libavl/testavl.c125
-rw-r--r--ldap/libraries/libldif/Makefile52
-rw-r--r--ldap/libraries/libldif/fileurl.c289
-rw-r--r--ldap/libraries/libldif/fileurl.h40
-rw-r--r--ldap/libraries/libldif/line64.c743
-rw-r--r--ldap/libraries/liblitekey/Makefile50
-rw-r--r--ldap/libraries/liblitekey/keycheck.c137
-rw-r--r--ldap/libraries/libutil/Makefile70
-rw-r--r--ldap/libraries/libutil/getopt.c109
-rw-r--r--ldap/libraries/libutil/ntdebug.c51
-rw-r--r--ldap/libraries/libutil/ntevent.c183
-rw-r--r--ldap/libraries/libutil/ntreg.c105
-rw-r--r--ldap/libraries/libutil/ntresource.h31
-rw-r--r--ldap/libraries/libutil/ntstubs.c40
-rw-r--r--ldap/nsdeps.mk59
-rw-r--r--ldap/nsldap.mk1752
-rw-r--r--ldap/schema/00core.ldif339
-rw-r--r--ldap/schema/05rfc2247.ldif19
-rw-r--r--ldap/schema/05rfc2927.ldif19
-rw-r--r--ldap/schema/10presence.ldif25
-rw-r--r--ldap/schema/10rfc2307.ldif54
-rw-r--r--ldap/schema/20subscriber.ldif32
-rw-r--r--ldap/schema/25java-object.ldif24
-rw-r--r--ldap/schema/28pilot.ldif62
-rw-r--r--ldap/schema/30ns-common.ldif77
-rw-r--r--ldap/schema/50ns-admin.ldif42
-rw-r--r--ldap/schema/50ns-calendar.ldif40
-rw-r--r--ldap/schema/50ns-certificate.ldif14
-rw-r--r--ldap/schema/50ns-compass.ldif69
-rw-r--r--ldap/schema/50ns-delegated-admin.ldif37
-rw-r--r--ldap/schema/50ns-directory.ldif87
-rw-r--r--ldap/schema/50ns-legacy.ldif16
-rw-r--r--ldap/schema/50ns-mail.ldif48
-rw-r--r--ldap/schema/50ns-mcd-browser.ldif86
-rw-r--r--ldap/schema/50ns-mcd-config.ldif29
-rw-r--r--ldap/schema/50ns-mcd-li.ldif22
-rw-r--r--ldap/schema/50ns-mcd-mail.ldif103
-rw-r--r--ldap/schema/50ns-media.ldif12
-rw-r--r--ldap/schema/50ns-mlm.ldif43
-rw-r--r--ldap/schema/50ns-msg.ldif297
-rw-r--r--ldap/schema/50ns-netshare.ldif23
-rw-r--r--ldap/schema/50ns-news.ldif19
-rw-r--r--ldap/schema/50ns-proxy.ldif12
-rw-r--r--ldap/schema/50ns-value.ldif24
-rw-r--r--ldap/schema/50ns-wcal.ldif26
-rw-r--r--ldap/schema/50ns-web.ldif14
-rw-r--r--ldap/schema/51ns-calendar.ldif69
-rw-r--r--ldap/schema/99user.ldif11
-rw-r--r--ldap/schema/ns-calendar-globopt.conf10
-rw-r--r--ldap/schema/ns-certificate-globopt.conf9
-rw-r--r--ldap/schema/ns-compass-globopt.conf11
-rw-r--r--ldap/schema/ns-directory-globopt.conf9
-rw-r--r--ldap/schema/ns-mail-globopt.conf12
-rw-r--r--ldap/schema/ns-mcd-li-globopt.conf9
-rw-r--r--ldap/schema/ns-media-globopt.conf9
-rw-r--r--ldap/schema/ns-news-globopt.conf10
-rw-r--r--ldap/schema/ns-proxy-globopt.conf9
-rw-r--r--ldap/schema/ns-wcal-globopt.conf10
-rw-r--r--ldap/schema/ns-web-globopt.conf10
-rw-r--r--ldap/schema/slapd-collations.conf67
-rw-r--r--ldap/servers/Makefile90
-rw-r--r--ldap/servers/plugins/Makefile101
-rw-r--r--ldap/servers/plugins/acl/ACL-Notes215
-rw-r--r--ldap/servers/plugins/acl/Makefile96
-rw-r--r--ldap/servers/plugins/acl/acl.c4118
-rw-r--r--ldap/servers/plugins/acl/acl.h867
-rw-r--r--ldap/servers/plugins/acl/acl_ext.c968
-rw-r--r--ldap/servers/plugins/acl/aclanom.c536
-rw-r--r--ldap/servers/plugins/acl/acldllmain.c128
-rw-r--r--ldap/servers/plugins/acl/acleffectiverights.c674
-rw-r--r--ldap/servers/plugins/acl/aclgroup.c442
-rw-r--r--ldap/servers/plugins/acl/aclinit.c537
-rw-r--r--ldap/servers/plugins/acl/acllas.c3848
-rw-r--r--ldap/servers/plugins/acl/acllist.c940
-rw-r--r--ldap/servers/plugins/acl/aclparse.c1928
-rw-r--r--ldap/servers/plugins/acl/aclplugin.c355
-rw-r--r--ldap/servers/plugins/acl/aclproxy.c195
-rw-r--r--ldap/servers/plugins/acl/aclutil.c1475
-rw-r--r--ldap/servers/plugins/acl/libacl.def16
-rw-r--r--ldap/servers/plugins/chainingdb/Makefile93
-rw-r--r--ldap/servers/plugins/chainingdb/cb.h461
-rw-r--r--ldap/servers/plugins/chainingdb/cb_abandon.c50
-rw-r--r--ldap/servers/plugins/chainingdb/cb_acl.c60
-rw-r--r--ldap/servers/plugins/chainingdb/cb_add.c227
-rw-r--r--ldap/servers/plugins/chainingdb/cb_bind.c290
-rw-r--r--ldap/servers/plugins/chainingdb/cb_cleanup.c22
-rw-r--r--ldap/servers/plugins/chainingdb/cb_close.c67
-rw-r--r--ldap/servers/plugins/chainingdb/cb_compare.c217
-rw-r--r--ldap/servers/plugins/chainingdb/cb_config.c600
-rw-r--r--ldap/servers/plugins/chainingdb/cb_conn_stateless.c1132
-rw-r--r--ldap/servers/plugins/chainingdb/cb_controls.c289
-rw-r--r--ldap/servers/plugins/chainingdb/cb_debug.c23
-rw-r--r--ldap/servers/plugins/chainingdb/cb_delete.c203
-rw-r--r--ldap/servers/plugins/chainingdb/cb_init.c120
-rw-r--r--ldap/servers/plugins/chainingdb/cb_instance.c1871
-rw-r--r--ldap/servers/plugins/chainingdb/cb_modify.c244
-rw-r--r--ldap/servers/plugins/chainingdb/cb_modrdn.c239
-rw-r--r--ldap/servers/plugins/chainingdb/cb_monitor.c228
-rw-r--r--ldap/servers/plugins/chainingdb/cb_schema.c45
-rw-r--r--ldap/servers/plugins/chainingdb/cb_search.c698
-rw-r--r--ldap/servers/plugins/chainingdb/cb_size.c22
-rw-r--r--ldap/servers/plugins/chainingdb/cb_start.c43
-rw-r--r--ldap/servers/plugins/chainingdb/cb_temp.c15
-rw-r--r--ldap/servers/plugins/chainingdb/cb_test.c76
-rw-r--r--ldap/servers/plugins/chainingdb/cb_unbind.c23
-rw-r--r--ldap/servers/plugins/chainingdb/cb_utils.c375
-rw-r--r--ldap/servers/plugins/chainingdb/cbdllmain.c128
-rw-r--r--ldap/servers/plugins/chainingdb/libcb.def15
-rw-r--r--ldap/servers/plugins/collation/Makefile99
-rw-r--r--ldap/servers/plugins/collation/collate.c454
-rw-r--r--ldap/servers/plugins/collation/collate.h36
-rw-r--r--ldap/servers/plugins/collation/collation.def10
-rw-r--r--ldap/servers/plugins/collation/config.c178
-rw-r--r--ldap/servers/plugins/collation/config.h12
-rw-r--r--ldap/servers/plugins/collation/debug.c14
-rw-r--r--ldap/servers/plugins/collation/dllmain.c129
-rw-r--r--ldap/servers/plugins/collation/orfilter.c984
-rw-r--r--ldap/servers/plugins/collation/orfilter.h10
-rw-r--r--ldap/servers/plugins/cos/Makefile79
-rw-r--r--ldap/servers/plugins/cos/cos.c266
-rw-r--r--ldap/servers/plugins/cos/cos.def11
-rw-r--r--ldap/servers/plugins/cos/cos_cache.c3566
-rw-r--r--ldap/servers/plugins/cos/cos_cache.h19
-rw-r--r--ldap/servers/plugins/cos/dllmain.c96
-rw-r--r--ldap/servers/plugins/distrib/Makefile109
-rw-r--r--ldap/servers/plugins/distrib/Makefile.AIX44
-rw-r--r--ldap/servers/plugins/distrib/Makefile.BSDI30
-rw-r--r--ldap/servers/plugins/distrib/Makefile.HPUX27
-rw-r--r--ldap/servers/plugins/distrib/Makefile.HPUX6427
-rw-r--r--ldap/servers/plugins/distrib/Makefile.IRIX30
-rw-r--r--ldap/servers/plugins/distrib/Makefile.Linux30
-rw-r--r--ldap/servers/plugins/distrib/Makefile.OSF129
-rw-r--r--ldap/servers/plugins/distrib/Makefile.ReliantUNIX30
-rw-r--r--ldap/servers/plugins/distrib/Makefile.SOLARIS30
-rw-r--r--ldap/servers/plugins/distrib/Makefile.SOLARIS6430
-rw-r--r--ldap/servers/plugins/distrib/Makefile.SOLARISx8630
-rw-r--r--ldap/servers/plugins/distrib/Makefile.UnixWare30
-rw-r--r--ldap/servers/plugins/distrib/Makefile.UnixWareUDK30
-rw-r--r--ldap/servers/plugins/distrib/Makefile.WINNT38
-rw-r--r--ldap/servers/plugins/distrib/README23
-rw-r--r--ldap/servers/plugins/distrib/distrib.c222
-rw-r--r--ldap/servers/plugins/distrib/distrib.dsp116
-rw-r--r--ldap/servers/plugins/distrib/dllmain.c101
-rw-r--r--ldap/servers/plugins/distrib/libdistrib.def10
-rw-r--r--ldap/servers/plugins/http/Makefile80
-rw-r--r--ldap/servers/plugins/http/dllmain.c98
-rw-r--r--ldap/servers/plugins/http/http.def13
-rw-r--r--ldap/servers/plugins/http/http_client.c290
-rw-r--r--ldap/servers/plugins/http/http_client.h64
-rw-r--r--ldap/servers/plugins/http/http_impl.c1479
-rw-r--r--ldap/servers/plugins/http/http_impl.h25
-rw-r--r--ldap/servers/plugins/passthru/Makefile90
-rw-r--r--ldap/servers/plugins/passthru/PT-Notes30
-rw-r--r--ldap/servers/plugins/passthru/libpassthru.def14
-rw-r--r--ldap/servers/plugins/passthru/passthru.h131
-rw-r--r--ldap/servers/plugins/passthru/ptbind.c144
-rw-r--r--ldap/servers/plugins/passthru/ptconfig.c301
-rw-r--r--ldap/servers/plugins/passthru/ptconn.c420
-rw-r--r--ldap/servers/plugins/passthru/ptdebug.c23
-rw-r--r--ldap/servers/plugins/passthru/ptdllmain.c131
-rw-r--r--ldap/servers/plugins/passthru/ptpreop.c252
-rw-r--r--ldap/servers/plugins/passthru/ptutil.c111
-rw-r--r--ldap/servers/plugins/presence/Makefile85
-rw-r--r--ldap/servers/plugins/presence/dllmain.c96
-rw-r--r--ldap/servers/plugins/presence/images/aim-offline.gifbin0 -> 113 bytes
-rw-r--r--ldap/servers/plugins/presence/images/aim-online.gifbin0 -> 895 bytes
-rw-r--r--ldap/servers/plugins/presence/images/icq-disabled.gifbin0 -> 138 bytes
-rw-r--r--ldap/servers/plugins/presence/images/icq-offline.gifbin0 -> 198 bytes
-rw-r--r--ldap/servers/plugins/presence/images/icq-online.gifbin0 -> 198 bytes
-rw-r--r--ldap/servers/plugins/presence/images/yahoo-offline.gifbin0 -> 84 bytes
-rw-r--r--ldap/servers/plugins/presence/images/yahoo-online.gifbin0 -> 140 bytes
-rw-r--r--ldap/servers/plugins/presence/presence.c1204
-rw-r--r--ldap/servers/plugins/presence/presence.def11
-rw-r--r--ldap/servers/plugins/presence/presence.ldif44
-rw-r--r--ldap/servers/plugins/pwdstorage/Makefile115
-rw-r--r--ldap/servers/plugins/pwdstorage/clear_pwd.c27
-rw-r--r--ldap/servers/plugins/pwdstorage/crypt_pwd.c91
-rw-r--r--ldap/servers/plugins/pwdstorage/dllmain.c91
-rw-r--r--ldap/servers/plugins/pwdstorage/libpwdstorage.def24
-rw-r--r--ldap/servers/plugins/pwdstorage/md5.h63
-rw-r--r--ldap/servers/plugins/pwdstorage/md5c.c337
-rw-r--r--ldap/servers/plugins/pwdstorage/ns-mta-md5_pwd.bu405
-rw-r--r--ldap/servers/plugins/pwdstorage/ns-mta-md5_pwd.c81
-rw-r--r--ldap/servers/plugins/pwdstorage/pwd_init.c146
-rw-r--r--ldap/servers/plugins/pwdstorage/pwdstorage.h99
-rw-r--r--ldap/servers/plugins/pwdstorage/sha_pwd.c111
-rw-r--r--ldap/servers/plugins/pwdstorage/ssha_pwd.c112
-rw-r--r--ldap/servers/plugins/referint/Makefile72
-rw-r--r--ldap/servers/plugins/referint/dllmain.c95
-rw-r--r--ldap/servers/plugins/referint/referint.c808
-rw-r--r--ldap/servers/plugins/referint/referint.def12
-rw-r--r--ldap/servers/plugins/replication/Makefile152
-rw-r--r--ldap/servers/plugins/replication/cl4.h65
-rw-r--r--ldap/servers/plugins/replication/cl4_api.c797
-rw-r--r--ldap/servers/plugins/replication/cl4_api.h67
-rw-r--r--ldap/servers/plugins/replication/cl4_init.c349
-rw-r--r--ldap/servers/plugins/replication/cl5.h38
-rw-r--r--ldap/servers/plugins/replication/cl5_api.c6512
-rw-r--r--ldap/servers/plugins/replication/cl5_api.h478
-rw-r--r--ldap/servers/plugins/replication/cl5_clcache.c910
-rw-r--r--ldap/servers/plugins/replication/cl5_clcache.h22
-rw-r--r--ldap/servers/plugins/replication/cl5_config.c868
-rw-r--r--ldap/servers/plugins/replication/cl5_init.c77
-rw-r--r--ldap/servers/plugins/replication/cl5_test.c830
-rw-r--r--ldap/servers/plugins/replication/cl5_test.h21
-rw-r--r--ldap/servers/plugins/replication/csnpl.c328
-rw-r--r--ldap/servers/plugins/replication/csnpl.h23
-rw-r--r--ldap/servers/plugins/replication/dllmain.c91
-rw-r--r--ldap/servers/plugins/replication/legacy_consumer.c707
-rw-r--r--ldap/servers/plugins/replication/llist.c336
-rw-r--r--ldap/servers/plugins/replication/llist.h26
-rw-r--r--ldap/servers/plugins/replication/profile.c42
-rw-r--r--ldap/servers/plugins/replication/repl.h366
-rw-r--r--ldap/servers/plugins/replication/repl5.h480
-rw-r--r--ldap/servers/plugins/replication/repl5_agmt.c1766
-rw-r--r--ldap/servers/plugins/replication/repl5_agmtlist.c618
-rw-r--r--ldap/servers/plugins/replication/repl5_backoff.c232
-rw-r--r--ldap/servers/plugins/replication/repl5_connection.c1493
-rw-r--r--ldap/servers/plugins/replication/repl5_inc_protocol.c1759
-rw-r--r--ldap/servers/plugins/replication/repl5_init.c572
-rw-r--r--ldap/servers/plugins/replication/repl5_mtnode_ext.c194
-rw-r--r--ldap/servers/plugins/replication/repl5_plugins.c1416
-rw-r--r--ldap/servers/plugins/replication/repl5_prot_private.h66
-rw-r--r--ldap/servers/plugins/replication/repl5_protocol.c502
-rw-r--r--ldap/servers/plugins/replication/repl5_protocol_util.c468
-rw-r--r--ldap/servers/plugins/replication/repl5_replica.c3387
-rw-r--r--ldap/servers/plugins/replication/repl5_replica_config.c750
-rw-r--r--ldap/servers/plugins/replication/repl5_replica_dnhash.c189
-rw-r--r--ldap/servers/plugins/replication/repl5_replica_hash.c243
-rw-r--r--ldap/servers/plugins/replication/repl5_replsupplier.c166
-rw-r--r--ldap/servers/plugins/replication/repl5_ruv.c2022
-rw-r--r--ldap/servers/plugins/replication/repl5_ruv.h88
-rw-r--r--ldap/servers/plugins/replication/repl5_schedule.c742
-rw-r--r--ldap/servers/plugins/replication/repl5_tot_protocol.c372
-rw-r--r--ldap/servers/plugins/replication/repl5_total.c869
-rw-r--r--ldap/servers/plugins/replication/repl5_updatedn_list.c243
-rw-r--r--ldap/servers/plugins/replication/repl_add.c30
-rw-r--r--ldap/servers/plugins/replication/repl_bind.c48
-rw-r--r--ldap/servers/plugins/replication/repl_compare.c34
-rw-r--r--ldap/servers/plugins/replication/repl_connext.c91
-rw-r--r--ldap/servers/plugins/replication/repl_controls.c337
-rw-r--r--ldap/servers/plugins/replication/repl_delete.c26
-rw-r--r--ldap/servers/plugins/replication/repl_entry.c38
-rw-r--r--ldap/servers/plugins/replication/repl_ext.c113
-rw-r--r--ldap/servers/plugins/replication/repl_extop.c1134
-rw-r--r--ldap/servers/plugins/replication/repl_globals.c108
-rw-r--r--ldap/servers/plugins/replication/repl_helper.c85
-rw-r--r--ldap/servers/plugins/replication/repl_helper.h69
-rw-r--r--ldap/servers/plugins/replication/repl_init.c312
-rw-r--r--ldap/servers/plugins/replication/repl_modify.c29
-rw-r--r--ldap/servers/plugins/replication/repl_modrdn.c28
-rw-r--r--ldap/servers/plugins/replication/repl_monitor.c58
-rw-r--r--ldap/servers/plugins/replication/repl_objset.c524
-rw-r--r--ldap/servers/plugins/replication/repl_objset.h37
-rw-r--r--ldap/servers/plugins/replication/repl_opext.c97
-rw-r--r--ldap/servers/plugins/replication/repl_ops.c180
-rw-r--r--ldap/servers/plugins/replication/repl_rootdse.c79
-rw-r--r--ldap/servers/plugins/replication/repl_search.c25
-rw-r--r--ldap/servers/plugins/replication/repl_shared.h132
-rw-r--r--ldap/servers/plugins/replication/replication.def16
-rw-r--r--ldap/servers/plugins/replication/replutil.c1073
-rw-r--r--ldap/servers/plugins/replication/tests/dnp_sim.c1033
-rw-r--r--ldap/servers/plugins/replication/tests/dnp_sim2.c972
-rw-r--r--ldap/servers/plugins/replication/tests/dnp_sim3.c1489
-rwxr-xr-xldap/servers/plugins/replication/tests/makesim58
-rw-r--r--ldap/servers/plugins/replication/urp.c1282
-rw-r--r--ldap/servers/plugins/replication/urp.h45
-rw-r--r--ldap/servers/plugins/replication/urp_glue.c235
-rw-r--r--ldap/servers/plugins/replication/urp_tombstone.c210
-rw-r--r--ldap/servers/plugins/retrocl/Makefile135
-rw-r--r--ldap/servers/plugins/retrocl/dllmain.c90
-rw-r--r--ldap/servers/plugins/retrocl/linktest.c16
-rw-r--r--ldap/servers/plugins/retrocl/retrocl.c341
-rw-r--r--ldap/servers/plugins/retrocl/retrocl.def15
-rw-r--r--ldap/servers/plugins/retrocl/retrocl.h123
-rw-r--r--ldap/servers/plugins/retrocl/retrocl.txt107
-rw-r--r--ldap/servers/plugins/retrocl/retrocl_cn.c391
-rw-r--r--ldap/servers/plugins/retrocl/retrocl_create.c317
-rw-r--r--ldap/servers/plugins/retrocl/retrocl_po.c529
-rw-r--r--ldap/servers/plugins/retrocl/retrocl_rootdse.c64
-rw-r--r--ldap/servers/plugins/retrocl/retrocl_trim.c505
-rw-r--r--ldap/servers/plugins/rever/Makefile111
-rw-r--r--ldap/servers/plugins/rever/des.c465
-rw-r--r--ldap/servers/plugins/rever/dllmain.c91
-rw-r--r--ldap/servers/plugins/rever/libdes.def13
-rw-r--r--ldap/servers/plugins/rever/rever.c77
-rw-r--r--ldap/servers/plugins/rever/rever.h34
-rw-r--r--ldap/servers/plugins/roles/Makefile95
-rw-r--r--ldap/servers/plugins/roles/dllmain.c96
-rw-r--r--ldap/servers/plugins/roles/roles.def10
-rw-r--r--ldap/servers/plugins/roles/roles_cache.c2061
-rw-r--r--ldap/servers/plugins/roles/roles_cache.h52
-rw-r--r--ldap/servers/plugins/roles/roles_plugin.c254
-rw-r--r--ldap/servers/plugins/shared/Makefile56
-rw-r--r--ldap/servers/plugins/shared/plugin-utils.h77
-rw-r--r--ldap/servers/plugins/shared/utils.c467
-rw-r--r--ldap/servers/plugins/statechange/Makefile78
-rw-r--r--ldap/servers/plugins/statechange/dllmain.c96
-rw-r--r--ldap/servers/plugins/statechange/statechange.c450
-rw-r--r--ldap/servers/plugins/statechange/statechange.def10
-rw-r--r--ldap/servers/plugins/syntaxes/Makefile87
-rw-r--r--ldap/servers/plugins/syntaxes/bin.c201
-rw-r--r--ldap/servers/plugins/syntaxes/ces.c168
-rw-r--r--ldap/servers/plugins/syntaxes/cis.c298
-rw-r--r--ldap/servers/plugins/syntaxes/debug.c20
-rw-r--r--ldap/servers/plugins/syntaxes/dllmain.c133
-rw-r--r--ldap/servers/plugins/syntaxes/dn.c98
-rw-r--r--ldap/servers/plugins/syntaxes/int.c188
-rw-r--r--ldap/servers/plugins/syntaxes/libsyntax.def24
-rw-r--r--ldap/servers/plugins/syntaxes/phonetic.c461
-rw-r--r--ldap/servers/plugins/syntaxes/sicis.c139
-rw-r--r--ldap/servers/plugins/syntaxes/string.c612
-rw-r--r--ldap/servers/plugins/syntaxes/syntax.h42
-rw-r--r--ldap/servers/plugins/syntaxes/tel.c135
-rw-r--r--ldap/servers/plugins/syntaxes/value.c209
-rw-r--r--ldap/servers/plugins/uiduniq/7bit.c722
-rw-r--r--ldap/servers/plugins/uiduniq/Makefile99
-rw-r--r--ldap/servers/plugins/uiduniq/UID-Notes93
-rw-r--r--ldap/servers/plugins/uiduniq/libuiduniq.def15
-rw-r--r--ldap/servers/plugins/uiduniq/uid.c1073
-rw-r--r--ldap/servers/plugins/vattrsp_template/Makefile79
-rw-r--r--ldap/servers/plugins/vattrsp_template/dllmain.c96
-rw-r--r--ldap/servers/plugins/vattrsp_template/vattrsp.c397
-rw-r--r--ldap/servers/plugins/vattrsp_template/vattrsp.def10
-rw-r--r--ldap/servers/plugins/views/Makefile79
-rw-r--r--ldap/servers/plugins/views/dllmain.c96
-rw-r--r--ldap/servers/plugins/views/views.c1779
-rw-r--r--ldap/servers/plugins/views/views.def10
-rw-r--r--ldap/servers/slapd/Makefile278
-rw-r--r--ldap/servers/slapd/abandon.c141
-rw-r--r--ldap/servers/slapd/add.c781
-rw-r--r--ldap/servers/slapd/agtmmap.c330
-rw-r--r--ldap/servers/slapd/agtmmap.h191
-rw-r--r--ldap/servers/slapd/apibroker.c245
-rw-r--r--ldap/servers/slapd/attr.c849
-rw-r--r--ldap/servers/slapd/attrlist.c253
-rw-r--r--ldap/servers/slapd/attrsyntax.c906
-rw-r--r--ldap/servers/slapd/auditlog.c217
-rw-r--r--ldap/servers/slapd/auth.c506
-rw-r--r--ldap/servers/slapd/auth.h15
-rw-r--r--ldap/servers/slapd/ava.c129
-rw-r--r--ldap/servers/slapd/back-ldbm/Makefile190
-rw-r--r--ldap/servers/slapd/back-ldbm/ancestorid.c747
-rw-r--r--ldap/servers/slapd/back-ldbm/archive.c332
-rw-r--r--ldap/servers/slapd/back-ldbm/attrcrypt.h33
-rw-r--r--ldap/servers/slapd/back-ldbm/back-ldbm.h629
-rw-r--r--ldap/servers/slapd/back-ldbm/backentry.c89
-rw-r--r--ldap/servers/slapd/back-ldbm/cache.c1195
-rw-r--r--ldap/servers/slapd/back-ldbm/cleanup.c51
-rw-r--r--ldap/servers/slapd/back-ldbm/close.c52
-rw-r--r--ldap/servers/slapd/back-ldbm/dblayer.c5395
-rw-r--r--ldap/servers/slapd/back-ldbm/dblayer.h140
-rw-r--r--ldap/servers/slapd/back-ldbm/dbsize.c25
-rw-r--r--ldap/servers/slapd/back-ldbm/dbtest.c312
-rw-r--r--ldap/servers/slapd/back-ldbm/dbversion.c181
-rw-r--r--ldap/servers/slapd/back-ldbm/dllmain.c128
-rw-r--r--ldap/servers/slapd/back-ldbm/dn2entry.c230
-rw-r--r--ldap/servers/slapd/back-ldbm/entrystore.c12
-rw-r--r--ldap/servers/slapd/back-ldbm/filterindex.c830
-rw-r--r--ldap/servers/slapd/back-ldbm/findentry.c284
-rw-r--r--ldap/servers/slapd/back-ldbm/haschildren.c8
-rw-r--r--ldap/servers/slapd/back-ldbm/id2entry.c250
-rw-r--r--ldap/servers/slapd/back-ldbm/idl.c1599
-rw-r--r--ldap/servers/slapd/back-ldbm/idl_common.c402
-rw-r--r--ldap/servers/slapd/back-ldbm/idl_new.c671
-rw-r--r--ldap/servers/slapd/back-ldbm/idl_shim.c124
-rw-r--r--ldap/servers/slapd/back-ldbm/idlapi.h30
-rw-r--r--ldap/servers/slapd/back-ldbm/import-merge.c680
-rw-r--r--ldap/servers/slapd/back-ldbm/import-threads.c1992
-rw-r--r--ldap/servers/slapd/back-ldbm/import.c1465
-rw-r--r--ldap/servers/slapd/back-ldbm/import.h199
-rw-r--r--ldap/servers/slapd/back-ldbm/index.c1852
-rw-r--r--ldap/servers/slapd/back-ldbm/init.c255
-rw-r--r--ldap/servers/slapd/back-ldbm/instance.c353
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_abandon.c14
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_add.c880
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_attr.c635
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c870
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_attrcrypt_config.c298
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_bind.c245
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_compare.c77
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_config.c1730
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_config.h133
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_delete.c633
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_index_config.c698
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_instance_config.c997
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_modify.c567
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_modrdn.c1403
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_search.c1345
-rw-r--r--ldap/servers/slapd/back-ldbm/ldbm_unbind.c14
-rw-r--r--ldap/servers/slapd/back-ldbm/ldif2ldbm.c2440
-rw-r--r--ldap/servers/slapd/back-ldbm/libback-ldbm.def13
-rw-r--r--ldap/servers/slapd/back-ldbm/matchrule.c126
-rw-r--r--ldap/servers/slapd/back-ldbm/misc.c356
-rw-r--r--ldap/servers/slapd/back-ldbm/monitor.c274
-rw-r--r--ldap/servers/slapd/back-ldbm/nextid.c204
-rw-r--r--ldap/servers/slapd/back-ldbm/parents.c105
-rw-r--r--ldap/servers/slapd/back-ldbm/perfctrs.c444
-rw-r--r--ldap/servers/slapd/back-ldbm/perfctrs.h51
-rw-r--r--ldap/servers/slapd/back-ldbm/proto-back-ldbm.h582
-rw-r--r--ldap/servers/slapd/back-ldbm/rmdb.c54
-rw-r--r--ldap/servers/slapd/back-ldbm/seq.c262
-rw-r--r--ldap/servers/slapd/back-ldbm/sort.c1031
-rw-r--r--ldap/servers/slapd/back-ldbm/start.c177
-rw-r--r--ldap/servers/slapd/back-ldbm/tools/index_dump/Makefile40
-rw-r--r--ldap/servers/slapd/back-ldbm/tools/index_dump/index_dump.c206
-rw-r--r--ldap/servers/slapd/back-ldbm/uniqueid2entry.c74
-rw-r--r--ldap/servers/slapd/back-ldbm/upgrade.c352
-rw-r--r--ldap/servers/slapd/back-ldbm/vlv.c1947
-rw-r--r--ldap/servers/slapd/back-ldbm/vlv_key.c69
-rw-r--r--ldap/servers/slapd/back-ldbm/vlv_key.h22
-rw-r--r--ldap/servers/slapd/back-ldbm/vlv_srch.c901
-rw-r--r--ldap/servers/slapd/back-ldbm/vlv_srch.h134
-rw-r--r--ldap/servers/slapd/back-ldif/Makefile81
-rw-r--r--ldap/servers/slapd/back-ldif/add.c189
-rw-r--r--ldap/servers/slapd/back-ldif/back-ldif.h94
-rw-r--r--ldap/servers/slapd/back-ldif/bind.c108
-rw-r--r--ldap/servers/slapd/back-ldif/close.c79
-rw-r--r--ldap/servers/slapd/back-ldif/compare.c82
-rw-r--r--ldap/servers/slapd/back-ldif/config.c203
-rw-r--r--ldap/servers/slapd/back-ldif/delete.c136
-rw-r--r--ldap/servers/slapd/back-ldif/dllmain.c132
-rw-r--r--ldap/servers/slapd/back-ldif/init.c114
-rw-r--r--ldap/servers/slapd/back-ldif/libback-ldif.def12
-rw-r--r--ldap/servers/slapd/back-ldif/modify.c557
-rw-r--r--ldap/servers/slapd/back-ldif/modrdn.c282
-rw-r--r--ldap/servers/slapd/back-ldif/monitor.c124
-rw-r--r--ldap/servers/slapd/back-ldif/search.c197
-rw-r--r--ldap/servers/slapd/back-ldif/start.c31
-rw-r--r--ldap/servers/slapd/back-ldif/unbind.c27
-rw-r--r--ldap/servers/slapd/backend.c505
-rw-r--r--ldap/servers/slapd/backend_manager.c770
-rw-r--r--ldap/servers/slapd/bind.c710
-rw-r--r--ldap/servers/slapd/bitset.c47
-rw-r--r--ldap/servers/slapd/bulk_import.c149
-rw-r--r--ldap/servers/slapd/ch_malloc.c657
-rw-r--r--ldap/servers/slapd/charray.c354
-rw-r--r--ldap/servers/slapd/compare.c153
-rw-r--r--ldap/servers/slapd/computed.c208
-rw-r--r--ldap/servers/slapd/config.c459
-rw-r--r--ldap/servers/slapd/configdse.c515
-rw-r--r--ldap/servers/slapd/connection.c2485
-rw-r--r--ldap/servers/slapd/conntable.c515
-rw-r--r--ldap/servers/slapd/control.c592
-rw-r--r--ldap/servers/slapd/counters.c151
-rw-r--r--ldap/servers/slapd/csn.c383
-rw-r--r--ldap/servers/slapd/csngen.c762
-rw-r--r--ldap/servers/slapd/csngen.h27
-rw-r--r--ldap/servers/slapd/csnset.c360
-rw-r--r--ldap/servers/slapd/daemon.c2694
-rw-r--r--ldap/servers/slapd/defbackend.c200
-rw-r--r--ldap/servers/slapd/delete.c324
-rw-r--r--ldap/servers/slapd/detach.c244
-rw-r--r--ldap/servers/slapd/disconnect_error_strings.h30
-rw-r--r--ldap/servers/slapd/disconnect_errors.h32
-rw-r--r--ldap/servers/slapd/dl.c219
-rw-r--r--ldap/servers/slapd/dn.c1469
-rw-r--r--ldap/servers/slapd/dse.c2304
-rw-r--r--ldap/servers/slapd/dynalib.c86
-rw-r--r--ldap/servers/slapd/entry.c3124
-rw-r--r--ldap/servers/slapd/entrywsi.c1151
-rw-r--r--ldap/servers/slapd/errormap.c186
-rw-r--r--ldap/servers/slapd/eventq.c482
-rw-r--r--ldap/servers/slapd/extendop.c297
-rw-r--r--ldap/servers/slapd/factory.c458
-rw-r--r--ldap/servers/slapd/fe.h159
-rw-r--r--ldap/servers/slapd/fedse.c1886
-rw-r--r--ldap/servers/slapd/fileio.c336
-rw-r--r--ldap/servers/slapd/filter.c1505
-rw-r--r--ldap/servers/slapd/filter.h33
-rw-r--r--ldap/servers/slapd/filtercmp.c402
-rw-r--r--ldap/servers/slapd/filterentry.c1000
-rw-r--r--ldap/servers/slapd/generation.c140
-rw-r--r--ldap/servers/slapd/getfilelist.c233
-rw-r--r--ldap/servers/slapd/getopt_ext.c236
-rw-r--r--ldap/servers/slapd/getopt_ext.h111
-rw-r--r--ldap/servers/slapd/globals.c142
-rw-r--r--ldap/servers/slapd/house.c91
-rw-r--r--ldap/servers/slapd/http.h43
-rw-r--r--ldap/servers/slapd/index_subsys.h47
-rw-r--r--ldap/servers/slapd/index_subsystem.c1286
-rw-r--r--ldap/servers/slapd/init.c63
-rw-r--r--ldap/servers/slapd/intrinsics.h112
-rw-r--r--ldap/servers/slapd/ldbmlinktest.c38
-rw-r--r--ldap/servers/slapd/lenstr.c80
-rw-r--r--ldap/servers/slapd/libglobs.c4051
-rw-r--r--ldap/servers/slapd/libmakefile174
-rw-r--r--ldap/servers/slapd/libsh_stub/Makefile63
-rw-r--r--ldap/servers/slapd/libsh_stub/libsh_stub.c7
-rw-r--r--ldap/servers/slapd/libslapd.def1147
-rw-r--r--ldap/servers/slapd/listConfigAttrs.pl106
-rw-r--r--ldap/servers/slapd/lite_entries.c106
-rw-r--r--ldap/servers/slapd/localhost.c228
-rw-r--r--ldap/servers/slapd/lock.c82
-rw-r--r--ldap/servers/slapd/log.c3664
-rw-r--r--ldap/servers/slapd/log.h186
-rw-r--r--ldap/servers/slapd/main.c2753
-rw-r--r--ldap/servers/slapd/mapping_tree.c3436
-rw-r--r--ldap/servers/slapd/match.c237
-rwxr-xr-xldap/servers/slapd/mkDBErrStrs.pl83
-rw-r--r--ldap/servers/slapd/modify.c966
-rw-r--r--ldap/servers/slapd/modrdn.c501
-rw-r--r--ldap/servers/slapd/modutil.c774
-rw-r--r--ldap/servers/slapd/monitor.c176
-rw-r--r--ldap/servers/slapd/ntmsgdll/Makefile62
-rw-r--r--ldap/servers/slapd/ntmsgdll/ntslapdmessages.c16
-rw-r--r--ldap/servers/slapd/ntmsgdll/ntslapdmessages.mc283
-rw-r--r--ldap/servers/slapd/ntperfdll/Makefile52
-rw-r--r--ldap/servers/slapd/ntperfdll/exports.def9
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapctr.cpp985
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapctrdef.h33
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapctrmc.h122
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapctrmc.mc74
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapctrmsg.h60
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapctrs.h67
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapctrs.ini57
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapctrutil.cpp364
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapctrutil.h120
-rw-r--r--ldap/servers/slapd/ntperfdll/nsldapreg.ini18
-rw-r--r--ldap/servers/slapd/ntuserpin.c178
-rw-r--r--ldap/servers/slapd/ntwdog/Makefile60
-rw-r--r--ldap/servers/slapd/ntwdog/cron_conf.c654
-rw-r--r--ldap/servers/slapd/ntwdog/cron_conf.h86
-rw-r--r--ldap/servers/slapd/ntwdog/ntcron.c156
-rw-r--r--ldap/servers/slapd/ntwdog/ntwatchdog.c1163
-rw-r--r--ldap/servers/slapd/object.c95
-rw-r--r--ldap/servers/slapd/objset.c380
-rw-r--r--ldap/servers/slapd/operation.c410
-rw-r--r--ldap/servers/slapd/opshared.c1163
-rw-r--r--ldap/servers/slapd/pblock.c2930
-rw-r--r--ldap/servers/slapd/plugin.c2833
-rw-r--r--ldap/servers/slapd/plugin_acl.c192
-rw-r--r--ldap/servers/slapd/plugin_internal_op.c864
-rw-r--r--ldap/servers/slapd/plugin_mr.c181
-rw-r--r--ldap/servers/slapd/plugin_role.c30
-rw-r--r--ldap/servers/slapd/plugin_syntax.c360
-rw-r--r--ldap/servers/slapd/poll_using_select.c122
-rw-r--r--ldap/servers/slapd/poll_using_select.h43
-rw-r--r--ldap/servers/slapd/prerrstrs.h121
-rw-r--r--ldap/servers/slapd/protect_db.c758
-rw-r--r--ldap/servers/slapd/protect_db.h75
-rw-r--r--ldap/servers/slapd/proto-slap.h1163
-rw-r--r--ldap/servers/slapd/psearch.c723
-rw-r--r--ldap/servers/slapd/pw.c1540
-rw-r--r--ldap/servers/slapd/pw.h70
-rw-r--r--ldap/servers/slapd/pw_mgmt.c398
-rw-r--r--ldap/servers/slapd/pw_retry.c253
-rw-r--r--ldap/servers/slapd/rdn.c410
-rw-r--r--ldap/servers/slapd/referral.c1205
-rw-r--r--ldap/servers/slapd/regex.c1045
-rw-r--r--ldap/servers/slapd/resourcelimit.c653
-rw-r--r--ldap/servers/slapd/result.c1794
-rw-r--r--ldap/servers/slapd/rootdse.c331
-rw-r--r--ldap/servers/slapd/rwlock.c222
-rw-r--r--ldap/servers/slapd/rwlock.h28
-rw-r--r--ldap/servers/slapd/sasl_io.c334
-rw-r--r--ldap/servers/slapd/sasl_map.c472
-rw-r--r--ldap/servers/slapd/saslbind.c908
-rw-r--r--ldap/servers/slapd/schema.c4664
-rw-r--r--ldap/servers/slapd/schemaparse.c262
-rw-r--r--ldap/servers/slapd/search.c283
-rw-r--r--ldap/servers/slapd/secerrstrs.h431
-rw-r--r--ldap/servers/slapd/security_wrappers.c339
-rw-r--r--ldap/servers/slapd/slap.h1944
-rw-r--r--ldap/servers/slapd/slapd.lite.key8
-rw-r--r--ldap/servers/slapd/slapd.normal.key9
-rw-r--r--ldap/servers/slapd/slapd_plhash.c59
-rw-r--r--ldap/servers/slapd/slapi-plugin-compat4.h132
-rw-r--r--ldap/servers/slapd/slapi-plugin.h1652
-rw-r--r--ldap/servers/slapd/slapi-private.h1212
-rw-r--r--ldap/servers/slapd/slapi2nspr.c274
-rw-r--r--ldap/servers/slapd/snmp_collator.c617
-rw-r--r--ldap/servers/slapd/snmp_collator.h15
-rw-r--r--ldap/servers/slapd/snoop.c39
-rw-r--r--ldap/servers/slapd/ssl.c1499
-rw-r--r--ldap/servers/slapd/sslerrstrs.h355
-rw-r--r--ldap/servers/slapd/start_tls_extop.c479
-rw-r--r--ldap/servers/slapd/statechange.h47
-rw-r--r--ldap/servers/slapd/str2filter.c380
-rw-r--r--ldap/servers/slapd/strdup.c25
-rw-r--r--ldap/servers/slapd/stubrepl.c42
-rw-r--r--ldap/servers/slapd/stubs.c36
-rw-r--r--ldap/servers/slapd/subentry.c56
-rw-r--r--ldap/servers/slapd/task.c1703
-rw-r--r--ldap/servers/slapd/tempnam.c44
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile51
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.AIX36
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.BSDI31
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.HPUX25
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.HPUX6424
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.IRIX31
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.Linux31
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.OSF130
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.ReliantUNIX31
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.SOLARIS28
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.SOLARIS6428
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.SOLARISx8631
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.UnixWare31
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.UnixWareUDK31
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.WINNT45
-rw-r--r--ldap/servers/slapd/test-plugins/Makefile.server107
-rw-r--r--ldap/servers/slapd/test-plugins/README149
-rw-r--r--ldap/servers/slapd/test-plugins/clients/README45
-rw-r--r--ldap/servers/slapd/test-plugins/clients/ReqExtOp.java77
-rw-r--r--ldap/servers/slapd/test-plugins/clients/reqextop.c85
-rw-r--r--ldap/servers/slapd/test-plugins/dllmain.c109
-rwxr-xr-xldap/servers/slapd/test-plugins/installDse.pl129
-rw-r--r--ldap/servers/slapd/test-plugins/nicknames10
-rw-r--r--ldap/servers/slapd/test-plugins/testbind.c252
-rw-r--r--ldap/servers/slapd/test-plugins/testdatainterop.c312
-rw-r--r--ldap/servers/slapd/test-plugins/testdbinterop.c102
-rw-r--r--ldap/servers/slapd/test-plugins/testdbinterop.h22
-rw-r--r--ldap/servers/slapd/test-plugins/testentry.c133
-rw-r--r--ldap/servers/slapd/test-plugins/testextendedop.c188
-rw-r--r--ldap/servers/slapd/test-plugins/testgetip.c141
-rw-r--r--ldap/servers/slapd/test-plugins/testplugin.def16
-rw-r--r--ldap/servers/slapd/test-plugins/testplugin.dsp143
-rw-r--r--ldap/servers/slapd/test-plugins/testplugin.mak431
-rw-r--r--ldap/servers/slapd/test-plugins/testpostop.c386
-rw-r--r--ldap/servers/slapd/test-plugins/testpreop.c215
-rw-r--r--ldap/servers/slapd/test-plugins/testsaslbind.c145
-rw-r--r--ldap/servers/slapd/time.c367
-rw-r--r--ldap/servers/slapd/tools/Makefile168
-rw-r--r--ldap/servers/slapd/tools/eggencode.c57
-rw-r--r--ldap/servers/slapd/tools/keyupg.c85
-rw-r--r--ldap/servers/slapd/tools/ldif.c128
-rw-r--r--ldap/servers/slapd/tools/migratecred.c154
-rw-r--r--ldap/servers/slapd/tools/mkdep.c335
-rw-r--r--ldap/servers/slapd/tools/mmldif.c1742
-rw-r--r--ldap/servers/slapd/tools/pwenc.c400
-rw-r--r--ldap/servers/slapd/unbind.c83
-rw-r--r--ldap/servers/slapd/uniqueid.c295
-rw-r--r--ldap/servers/slapd/uniqueidgen.c219
-rw-r--r--ldap/servers/slapd/utf8compare.c2287
-rw-r--r--ldap/servers/slapd/util.c601
-rw-r--r--ldap/servers/slapd/uuid.c893
-rw-r--r--ldap/servers/slapd/uuid.h116
-rw-r--r--ldap/servers/slapd/value.c460
-rw-r--r--ldap/servers/slapd/valueset.c1303
-rw-r--r--ldap/servers/slapd/vattr.c2387
-rw-r--r--ldap/servers/slapd/vattr_spi.h54
-rw-r--r--ldap/servers/slapd/views.h29
-rw-r--r--ldap/servers/snmp/Makefile91
-rw-r--r--ldap/servers/snmp/NETWORK-SERVICES-MIB.txt650
-rw-r--r--ldap/servers/snmp/RFC-1215.txt38
-rw-r--r--ldap/servers/snmp/RFC1155-SMI.txt119
-rw-r--r--ldap/servers/snmp/SNMPv2-CONF.txt322
-rw-r--r--ldap/servers/snmp/SNMPv2-SMI.txt344
-rw-r--r--ldap/servers/snmp/SNMPv2-TC.txt772
-rw-r--r--ldap/servers/snmp/netscape-ldap.mib727
-rw-r--r--ldap/servers/snmp/ntagt/Makefile103
-rw-r--r--ldap/servers/snmp/ntagt/msrvdefs.mak492
-rw-r--r--ldap/servers/snmp/ntagt/nslagtcom_nt.h32
-rw-r--r--ldap/servers/snmp/ntagt/nsldapagt_nt.c1738
-rw-r--r--ldap/servers/snmp/ntagt/nsldapagt_nt.def24
-rw-r--r--ldap/servers/snmp/ntagt/nsldapagt_nt.h228
-rw-r--r--ldap/servers/snmp/ntagt/nsldapmib_nt.c1041
-rw-r--r--ldap/servers/snmp/ntagt/nsldapmib_nt.h130
-rw-r--r--ldap/systools/Makefile96
-rw-r--r--ldap/systools/README31
-rwxr-xr-xldap/systools/getHPPatches.pl83
-rwxr-xr-xldap/systools/getSolPatches.pl64
-rw-r--r--ldap/systools/hp_patches.c5
-rw-r--r--ldap/systools/idsktune.c3279
-rwxr-xr-xldap/systools/mergeSolPatches.pl57
-rw-r--r--ldap/systools/pio.c94
-rw-r--r--ldap/systools/pio.h32
-rw-r--r--ldap/systools/sol_patches.c271
-rw-r--r--ldap/systools/viewcore.c464
-rw-r--r--lib/base/Makefile111
-rw-r--r--lib/base/crit.cpp399
-rw-r--r--lib/base/dns.cpp176
-rw-r--r--lib/base/dnsdmain.cpp159
-rw-r--r--lib/base/ereport.cpp249
-rw-r--r--lib/base/eventlog.cpp70
-rw-r--r--lib/base/file.cpp702
-rw-r--r--lib/base/fsmutex.cpp187
-rw-r--r--lib/base/lexer.cpp978
-rw-r--r--lib/base/lexer_pvt.h30
-rw-r--r--lib/base/net.cpp578
-rw-r--r--lib/base/nscperror.c162
-rw-r--r--lib/base/nterrors.cpp83
-rw-r--r--lib/base/plist.cpp1154
-rw-r--r--lib/base/plist_pvt.h122
-rw-r--r--lib/base/pool.cpp654
-rw-r--r--lib/base/rwlock.cpp131
-rw-r--r--lib/base/shexp.cpp290
-rw-r--r--lib/base/shmem.cpp127
-rw-r--r--lib/base/system.cpp264
-rw-r--r--lib/base/systhr.cpp256
-rw-r--r--lib/base/util.cpp1449
-rw-r--r--lib/ldaputil/Makefile65
-rw-r--r--lib/ldaputil/cert.c452
-rw-r--r--lib/ldaputil/certmap.c1950
-rw-r--r--lib/ldaputil/certmap.conf48
-rw-r--r--lib/ldaputil/dbconf.c704
-rw-r--r--lib/ldaputil/encode.c142
-rw-r--r--lib/ldaputil/errors.c202
-rw-r--r--lib/ldaputil/examples/Certmap.mak254
-rw-r--r--lib/ldaputil/examples/Makefile91
-rw-r--r--lib/ldaputil/examples/README97
-rw-r--r--lib/ldaputil/examples/init.c40
-rw-r--r--lib/ldaputil/examples/plugin.c239
-rw-r--r--lib/ldaputil/examples/plugin.h33
-rw-r--r--lib/ldaputil/init.c185
-rw-r--r--lib/ldaputil/ldapauth.c1099
-rw-r--r--lib/ldaputil/ldapdb.c583
-rw-r--r--lib/ldaputil/ldapu-changes.html403
-rw-r--r--lib/ldaputil/ldaputili.h62
-rw-r--r--lib/ldaputil/utest/Makefile117
-rw-r--r--lib/ldaputil/utest/auth.cpp574
-rwxr-xr-xlib/ldaputil/utest/authtest106
-rw-r--r--lib/ldaputil/utest/certmap.conf36
-rw-r--r--lib/ldaputil/utest/dblist.conf15
-rw-r--r--lib/ldaputil/utest/example.c116
-rw-r--r--lib/ldaputil/utest/plugin.c115
-rw-r--r--lib/ldaputil/utest/plugin.h20
-rw-r--r--lib/ldaputil/utest/stubs.c107
-rw-r--r--lib/ldaputil/utest/stubs.cpp102
-rw-r--r--lib/ldaputil/utest/test.ref448
-rw-r--r--lib/ldaputil/vtable.c427
-rw-r--r--lib/libaccess/Makefile176
-rw-r--r--lib/libaccess/access_plhash.cpp65
-rw-r--r--lib/libaccess/access_plhash.h17
-rw-r--r--lib/libaccess/acl.tab.cpp1718
-rw-r--r--lib/libaccess/acl.tab.h44
-rw-r--r--lib/libaccess/acl.yy.cpp1995
-rw-r--r--lib/libaccess/aclbuild.cpp1360
-rw-r--r--lib/libaccess/aclcache.cpp579
-rw-r--r--lib/libaccess/aclcache.h27
-rw-r--r--lib/libaccess/aclerror.cpp246
-rw-r--r--lib/libaccess/acleval.cpp556
-rw-r--r--lib/libaccess/aclflush.cpp178
-rw-r--r--lib/libaccess/aclparse.cpp2241
-rw-r--r--lib/libaccess/aclpriv.h171
-rw-r--r--lib/libaccess/aclscan.h25
-rw-r--r--lib/libaccess/aclscan.l379
-rw-r--r--lib/libaccess/aclspace.cpp37
-rw-r--r--lib/libaccess/acltext.y957
-rw-r--r--lib/libaccess/acltools.cpp3457
-rw-r--r--lib/libaccess/aclutil.cpp223
-rw-r--r--lib/libaccess/aclutil.h25
-rw-r--r--lib/libaccess/attrec.cpp309
-rw-r--r--lib/libaccess/authdb.cpp339
-rw-r--r--lib/libaccess/avadb.c300
-rw-r--r--lib/libaccess/avaparse.y140
-rw-r--r--lib/libaccess/avapfile.c428
-rw-r--r--lib/libaccess/avascan.l106
-rw-r--r--lib/libaccess/las.h53
-rw-r--r--lib/libaccess/lasdns.cpp373
-rw-r--r--lib/libaccess/lasdns.h10
-rw-r--r--lib/libaccess/lasgroup.cpp164
-rw-r--r--lib/libaccess/lasip.cpp487
-rw-r--r--lib/libaccess/lasip.h13
-rw-r--r--lib/libaccess/lastod.cpp170
-rw-r--r--lib/libaccess/lasuser.cpp154
-rw-r--r--lib/libaccess/lcache.h23
-rw-r--r--lib/libaccess/ldapacl.cpp822
-rw-r--r--lib/libaccess/ldapauth.h42
-rw-r--r--lib/libaccess/leval.h18
-rw-r--r--lib/libaccess/lparse.h27
-rw-r--r--lib/libaccess/method.cpp163
-rw-r--r--lib/libaccess/nsadb.cpp582
-rw-r--r--lib/libaccess/nsamgmt.cpp1567
-rw-r--r--lib/libaccess/nsautherr.cpp126
-rw-r--r--lib/libaccess/nscert.cpp963
-rw-r--r--lib/libaccess/nsdb.cpp836
-rw-r--r--lib/libaccess/nsdbmgmt.cpp685
-rw-r--r--lib/libaccess/nseframe.cpp207
-rw-r--r--lib/libaccess/nsgmgmt.cpp434
-rw-r--r--lib/libaccess/nsgroup.cpp336
-rw-r--r--lib/libaccess/nslock.cpp268
-rw-r--r--lib/libaccess/nsumgmt.cpp456
-rw-r--r--lib/libaccess/nsuser.cpp309
-rw-r--r--lib/libaccess/oneeval.cpp1054
-rw-r--r--lib/libaccess/oneeval.h17
-rw-r--r--lib/libaccess/parse.h21
-rw-r--r--lib/libaccess/permhash.h79
-rw-r--r--lib/libaccess/register.cpp821
-rw-r--r--lib/libaccess/register.h98
-rw-r--r--lib/libaccess/symbols.cpp350
-rw-r--r--lib/libaccess/userauth.cpp12
-rw-r--r--lib/libaccess/usi.cpp371
-rw-r--r--lib/libaccess/usrcache.cpp657
-rw-r--r--lib/libaccess/utest.mk61
-rw-r--r--lib/libaccess/utest/.purify19
-rw-r--r--lib/libaccess/utest/Makefile119
-rw-r--r--lib/libaccess/utest/acl.dat12
-rw-r--r--lib/libaccess/utest/aclfile055
-rw-r--r--lib/libaccess/utest/aclfile111
-rw-r--r--lib/libaccess/utest/aclfile1013
-rw-r--r--lib/libaccess/utest/aclfile1111
-rw-r--r--lib/libaccess/utest/aclfile1211
-rw-r--r--lib/libaccess/utest/aclfile1311
-rw-r--r--lib/libaccess/utest/aclfile1411
-rw-r--r--lib/libaccess/utest/aclfile1511
-rw-r--r--lib/libaccess/utest/aclfile1611
-rw-r--r--lib/libaccess/utest/aclfile1711
-rw-r--r--lib/libaccess/utest/aclfile1819
-rw-r--r--lib/libaccess/utest/aclfile1914
-rw-r--r--lib/libaccess/utest/aclfile211
-rw-r--r--lib/libaccess/utest/aclfile311
-rw-r--r--lib/libaccess/utest/aclfile411
-rw-r--r--lib/libaccess/utest/aclfile511
-rw-r--r--lib/libaccess/utest/aclfile623
-rw-r--r--lib/libaccess/utest/aclfile711
-rw-r--r--lib/libaccess/utest/aclfile811
-rw-r--r--lib/libaccess/utest/aclfile911
-rw-r--r--lib/libaccess/utest/aclgrp010
-rw-r--r--lib/libaccess/utest/aclgrp110
-rw-r--r--lib/libaccess/utest/aclgrp210
-rw-r--r--lib/libaccess/utest/aclgrp310
-rw-r--r--lib/libaccess/utest/aclgrp410
-rw-r--r--lib/libaccess/utest/acltest.cpp796
-rw-r--r--lib/libaccess/utest/lasemail.cpp180
-rw-r--r--lib/libaccess/utest/onetest.cpp47
-rw-r--r--lib/libaccess/utest/shexp.cpp294
-rw-r--r--lib/libaccess/utest/shexp.h131
-rw-r--r--lib/libaccess/utest/test.ref234
-rw-r--r--lib/libaccess/utest/testmain.cpp52
-rw-r--r--lib/libaccess/utest/twotest.cpp57
-rw-r--r--lib/libaccess/utest/ustubs.cpp283
-rw-r--r--lib/libaccess/winnt.l762
-rw-r--r--lib/libaccess/winnt.v156
-rw-r--r--lib/libaccess/winnt.y793
-rw-r--r--lib/libaccess/wintab.h26
-rw-r--r--lib/libaccess/yy-sed21
-rw-r--r--lib/libadmin/Makefile61
-rw-r--r--lib/libadmin/authdb.c2467
-rw-r--r--lib/libadmin/error.c109
-rw-r--r--lib/libadmin/strlist.c46
-rw-r--r--lib/libadmin/template.c820
-rw-r--r--lib/libadmin/util.c1340
-rw-r--r--lib/libnt/Makefile27
-rw-r--r--lib/libnt/info.c81
-rw-r--r--lib/libnt/path.c266
-rw-r--r--lib/libnt/pmddeml.c375
-rw-r--r--lib/libnt/registry.c242
-rw-r--r--lib/libnt/service.c375
-rw-r--r--lib/libnt/tcpip.c145
-rw-r--r--lib/libsi18n/Makefile155
-rw-r--r--lib/libsi18n/acclanglist.c187
-rw-r--r--lib/libsi18n/coreres.c113
-rw-r--r--lib/libsi18n/coreres.h15
-rw-r--r--lib/libsi18n/getlang.c294
-rw-r--r--lib/libsi18n/getstrmem.c123
-rw-r--r--lib/libsi18n/getstrmem.h1156
-rw-r--r--lib/libsi18n/getstrprop.c137
-rw-r--r--lib/libsi18n/gsslapd.h37
-rw-r--r--lib/libsi18n/makstrdb.c221
-rw-r--r--lib/libsi18n/propset.c404
-rw-r--r--lib/libsi18n/propset.h43
-rw-r--r--lib/libsi18n/reshash.c264
-rw-r--r--lib/libsi18n/reshash.h54
-rw-r--r--lib/libsi18n/txtfile.c130
-rw-r--r--lib/libsi18n/txtfile.h45
-rw-r--r--modules.awk451
-rw-r--r--modules.sh79
-rw-r--r--ns_usedb.mk153
-rw-r--r--ns_usepurify.mk20
-rw-r--r--ns_usequantify.mk18
-rw-r--r--ns_usesh.mk138
-rwxr-xr-xnsarch812
-rw-r--r--nsarch.bat8
-rw-r--r--nsconfig.mk1448
-rw-r--r--nscore.mk78
-rw-r--r--nsdefs.mk245
-rwxr-xr-xnsperl.mk88
-rw-r--r--ntversion.pl34
-rw-r--r--pumpkin.pl15
2095 files changed, 626140 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 00000000..1fa353eb
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,268 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Top-level gmake Makefile for Directory Server builds.
+#
+# Execute the command:
+#
+# gmake help
+#
+# to see a list of available targets.
+
+# Relative path to the top of the build tree (i.e., where the DS source tree is checked out)
+MCOM_ROOT=..
+
+# define COMPONENT_DEPS here so that components are pulled in this makefile
+COMPONENT_DEPS := 1
+
+include nsdefs.mk
+include nsconfig.mk
+include ns_usedb.mk
+
+# first (default) rule: build and create a DS package
+all: buildAndPkgDirectory
+
+help:
+ @echo
+ @echo The following are build targets that you can choose from:
+ @echo
+ @echo " gmake buildAndPkgDirectory"
+ @echo " gmake buildDirectory"
+ @echo " gmake pkgDirectory"
+ @echo " gmake pkgDirectoryl10n"
+ @echo " gmake pkgDirectoryPseudoL10n"
+
+###### Implementation notes:
+#
+# We use ../../reltools/ftp_puller_new.pl to pull and maintain dependencies
+# for the components (binary and header files) we use for the build. The
+# dependencies are maintained in the file ../components.OS, where OS is
+# the operating system. These files do not exist in CVS; they are created
+# as needed. We could probably make the system smarter to know the
+# difference between debug/optimized and export/domestic, but for now it
+# does not.
+#
+# The file ./component_versions.mk contains the component version
+# information. If you want to change the version of a component used
+# to build or package, this is the place to look.
+#
+#
+# The file ./components.mk contains the information about what files and
+# directories are used by the component. It also contains the
+# information about how to pull the component. Each component defines a
+# XXX_DEP macro which is the name of a file to be used for dependency
+# checking.
+#
+#
+# By default, NT uses FTP and Unix uses SYMLINK as their pull methods.
+# This is controlled by the COMPONENT_PULL_METHOD macro. For example,
+# on Unix, you can use
+#
+# gmake COMPONENT_PULL_METHOD=FTP buildDirectory
+#
+# To force use of ftp to pull all components. In addition, each component
+# can have a XXX_PULL_METHOD macro. If this macro is defined, it overrides
+# the default. For example, on Unix, you can use
+#
+# gmake NSPR_PULL_METHOD=FTP buildDirectory
+#
+# if you want to get NSPR via ftp and the other components via symlink.
+#
+#
+# By default, the components are only pulled from the top level if you do
+# a gmake buildDirectory. There is a macro called COMPONENT_DEPS. If
+# this is defined on the command line of the gmake command e.g.
+#
+# gmake COMPONENT_DEPS=1 ...
+#
+# this will force component checking and pulling. This will have the
+# effect of slowing down the build.
+#
+###### End of implementation notes.
+
+components: $(ADMINUTIL_DEP) $(NSPR_DEP) $(ARLIB_DEP) $(DBM_DEP) $(SECURITY_DEP) $(SVRCORE_DEP) \
+ $(ICU_DEP) $(SETUPSDK_DEP) $(LDAPSDK_DEP) $(DB_LIB_DEP) $(SASL_DEP) $(PEER_DEP) \
+ $(DSRK_DEP) $(AXIS_DEP) $(DSMLJAR_DEP)
+ -@echo "The components are up to date"
+
+ifeq ($(BUILD_JAVA_CODE),1)
+DS_CONSOLE_COMPONENT_DEP = $(LDAPJDK_DEP) $(SWING_DEP) $(MCC_DEP)
+DS_CONSOLE_COMPONENT_DEP += $(JAVASSL_DEP) $(JSS_DEP) $(CRIMSONJAR_DEP)
+java_platform_check:
+
+else
+
+DS_CONSOLE_COMPONENT_DEP =
+java_platform_check:
+ -@echo "Note: Java code is not built on this platform ($(ARCH))."
+ -@echo " Use 'gmake BUILD_JAVA_CODE=1 ...' to override."
+endif
+
+consoleComponents: $(DS_CONSOLE_COMPONENT_DEP)
+
+pumpkin:
+ @echo NSOS_RELEASE is: $(NSOS_RELEASE)
+ $(PERL) pumpkin.pl $(PUMPKIN_AGE) pumpkin.dat
+
+buildnum:
+ if test ! -d $(BUILD_ARCH); then mkdir $(BUILD_ARCH); fi;
+ $(PERL) buildnum.pl -p $(BUILD_ARCH)
+
+nsCommon:
+ cd config; $(MAKE) export $(NSDEFS)
+# XXXsspitzer: for UNIXWARE and UnixWare
+ifeq ($(subst nix,NIX,$(subst are,ARE,$(ARCH))), UNIXWARE)
+ - mkdir built/$(NS_BUILD_FLAVOR)/obj
+ cd built/$(NS_BUILD_FLAVOR)/obj && ar xv ../../../$(LIBNSPR) uxwrap.o
+endif
+ifeq ($(ARCH), WINNT)
+ cd lib/libnt; $(MAKE) $(MFLAGS) export $(NSDEFS)
+ cd lib/libnt; $(MAKE) $(MFLAGS) libs $(NSDEFS)
+endif
+
+#
+# Notice that BUILD_MODULE is not supplied directly on this target.
+# It either inherits from the calling target or from the default in
+# nsdefs.mk. Therefore if you need to perform 'gmake httpdlib', be sure
+# that BUILD_MODULE is set to whatever target release that you need.
+#
+httpdLib:
+ @echo
+ @echo
+ @echo
+ @echo ==== Starting Server LIBS for: $(BUILD_MODULE) ==========
+ @echo
+ cd lib/base; $(MAKE) $(MFLAGS)
+ cd lib/ldaputil; $(MAKE) $(MFLAGS)
+ cd lib/frame; $(MAKE) $(MFLAGS)
+ cd lib/libaccess; $(MAKE) $(MFLAGS)
+ cd lib/libadmin; $(MAKE) $(MFLAGS)
+ cd lib/safs; $(MAKE) $(MFLAGS)
+ cd lib/libcrypt; $(MAKE) $(MFLAGS)
+ cd lib/libmsgdisp; $(MAKE) $(MFLAGS)
+ cd lib/libsi18n; $(MAKE) $(MFLAGS)
+ifeq ($(ARCH), WINNT)
+ cd lib/httpdaemon; $(MAKE) $(MFLAGS)
+endif
+ @echo ==== Finished Server LIBS for: $(BUILD_MODULE) ==========
+ @echo
+
+buildAndPkgDirectory: buildDirectory pkgDirectory
+
+buildDirectory: buildnum pumpkin $(OBJDIR) $(DIRVER_H) $(SDKVER_H) components
+ @echo
+ @echo
+ @echo
+ @echo ==== Starting Netscape Directory Server ==========
+ @echo
+ $(MAKE) $(MFLAGS) nsCommon
+ cd config; $(MAKE) $(MFLAGS) install $(NSDEFS)
+ $(MAKE) $(MFLAGS) BUILD_MODULE=DIRECTORY LDAP_NO_LIBLCACHE=1 httpdLib
+ifeq ($(ARCH), WINNT)
+ $(PERL) ntversion.pl $(MCOM_ROOT) $(MAJOR_VERSION) $(MINOR_VERSION)
+endif
+ cd httpd; $(MAKE) $(MFLAGS) LDAP_NO_LIBLCACHE=1 BUILD_MODULE=DIRECTORY httpd-bin
+ cd ldap; $(MAKE) $(MFLAGS) LDAP_NO_LIBLCACHE=1 BUILD_MODULE=DIRECTORY all
+ @echo ==== Finished Netscape Directory Server ==========
+ @echo
+ @echo ==== Starting Netscape Directory Server Console ==========
+ @echo
+ $(MAKE) $(MFLAGS) buildDirectoryConsole
+ @echo
+ @echo ==== Finished Netscape Directory Server Console ==========
+ @echo
+ @echo ==== Starting Netscape Directory Clients ==========
+ @echo
+ $(MAKE) $(MFLAGS) buildDirectoryClients
+ @echo
+ @echo ==== Finished Netscape Directory Clients ==========
+ @echo
+
+cleanDirectory:
+ @echo
+ @echo
+ @echo ==== Cleaning Netscape Directory Server on $(ARCH) ====
+ @echo
+ rm -rf $(ARCH)
+ rm -rf built/$(NS_BUILD_FLAVOR)
+ rm -rf built/release/slapd/$(NS_BUILD_FLAVOR)
+ rm -rf ../dist/$(NSOBJDIR_NAME)
+ rm -rf ../dist/full
+ rm -rf $(CLASS_DEST) # ../dist/classes
+ @echo
+ @echo ==== All done ===
+ @echo
+
+buildDirectoryConsole: consoleComponents java_platform_check
+ifeq ($(BUILD_JAVA_CODE),1)
+ cd ldap/admin/src/java/com/netscape/admin/dirserv; $(MAKE) $(MFLAGS) package
+ cd ldap/admin/src/java/com/netscape/xmltools; $(MAKE) $(MFLAGS) package
+endif
+
+buildDirectoryClients: $(ANT_DEP) java_platform_check
+ifeq ($(BUILD_JAVA_CODE),1)
+ cd ldap/clients; $(MAKE) $(MFLAGS)
+endif
+ cd ldap/clients/dsgw; $(MAKE) $(MFLAGS)
+
+$(OBJDIR):
+ if test ! -d $(OBJDIR); then mkdir $(OBJDIR); fi;
+
+$(SDKVER_H):
+ if test ! -d $(DIRVERDIR); then mkdir $(DIRVERDIR); fi;
+ $(PERL) dirver.pl -v "$(DIRSDK_VERSION)" -o $@
+
+$(DIRVER_H):
+ if test ! -d $(DIRVERDIR); then mkdir $(DIRVERDIR); fi;
+ $(PERL) dirver.pl -v "$(DIR_VERSION)" -o $@
+
+pkgLdapSDK: setupLdapSDK
+ @echo
+ @echo =========== Finished - LDAP SDK Package Build ============
+
+setupLdapSDK:
+ @echo =========== Starting - LDAP SDK Package Build ============
+ @echo
+ cd ldap/cm; $(MAKE) $(MAKEFLAGS) releaseLdapSDK
+ cd ldap/cm; $(MAKE) $(MAKEFLAGS) packageLdapSDK
+
+
+pkgDirectory: setupDirectory
+ @echo
+ @echo =========== Finished - Directory Server Package Build ============
+
+Acceptance:
+ cd ldap/cm; $(MAKE) Acceptance $(MFLAGS)
+
+Longduration:
+ cd ldap/cm; $(MAKE) Longduration $(MFLAGS)
+
+setupDirectory:
+ cd ldap/cm; $(MAKE) $(MFLAGS) releaseDirectory;
+ cd ldap/cm; $(MAKE) $(MFLAGS) packageDirectory;
+
+pkgDirectoryJars:
+ cd ldap/cm; $(MAKE) $(MFLAGS) packageJars
+
+pkgDirectoryl10n:
+ @echo =========== Starting - Directory Server International Package Build ============
+ cd ldap/cm; $(MAKE) $(MFLAGS) l10nRePackage
+ @echo =========== Finished - Directory Server International Package Build ============
+
+pkgDirectoryPseudoL10n:
+ @echo =========== Starting - Directory Server L10N Package Build ============
+ifeq ($(BUILD_SECURITY),export)
+ifeq ($(BUILD_DEBUG),optimize)
+ cd i18npkg/apollo; $(MAKE) $(MFLAGS)
+else
+ @echo skipping pkgDirectoryPseudoL10n
+endif
+else
+ @echo skipping pkgDirectoryPseudoL10n
+endif
+ @echo =========== Finished - Directory Server L10N Package Build ============
+
diff --git a/bchecker.ini b/bchecker.ini
new file mode 100644
index 00000000..4ff9a1c6
--- /dev/null
+++ b/bchecker.ini
@@ -0,0 +1,3 @@
+checking_level full
+checking_uninit_compile on
+compiler_fault_recovery on
diff --git a/buildnum.pl b/buildnum.pl
new file mode 100755
index 00000000..6b184f21
--- /dev/null
+++ b/buildnum.pl
@@ -0,0 +1,49 @@
+#!/usr/bin/perl
+#--------------------------------------------
+# buildnum.pl
+#
+# Generates a dated build number and writes
+# out a buildnum.dat file in a user specified
+# subdirectory.
+#
+# Usage: buildnum.pl -p <platform dir>
+#--------------------------------------------
+
+use Getopt::Std;
+use FileHandle;
+
+autoflush STDERR 1;
+
+getopts('p:H');
+
+if ($opt_H) {exitHelp();}
+
+# Load arguments
+$platdir = $opt_p || exitHelp();
+$buildnum_file = "./$platdir/buildnum.dat";
+
+# Get current time
+@now = gmtime;
+
+# Format buildnum as YYYY.DDD.HHMM
+$year = $now[5] + 1900;
+$doy = $now[7] + 1;
+if ($doy < 100) { $doy = 0 . $doy; }
+$tod = $now[2] . $now[1];
+$buildnum = "$year.$doy.$tod";
+
+# Write buildnum.dat
+open(BUILDNUM,">$buildnum_file") || die "Error: Can't create $buildnum_file: $!\n";
+print BUILDNUM "\\\"$buildnum\\\"";
+close(BUILDNUM);
+
+#---------- exitHelp subroutine ----------
+sub exitHelp {
+ print(STDERR "$0: Generates a dated build number.
+
+ \tUsage: $0 -p <platform>
+
+ \t-p <platform> Platform subdirectory.
+ \t-H Print this help message\n");
+ exit(0);
+}
diff --git a/component_versions.mk b/component_versions.mk
new file mode 100644
index 00000000..bcdd4a1d
--- /dev/null
+++ b/component_versions.mk
@@ -0,0 +1,198 @@
+#
+# 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 version definitions for all components used in the build. It
+# should be COMPLETELY AND TOTALLY SELF CONTAINED e.g. no references to macros defined
+# outside of this file.
+
+# The XXX_DIR OR XXX_VERSDIR or XXX_COMP or XXX_COMP_DIR macros are the name of the
+# base directory for the component under the main components directory
+# for example, the LDAP SDK component directory is
+# $(COMPONENTS_DIR)/$(LDAPCOMP_DIR) == /share/builds/components/ldapsdk31
+
+# the XXX_RELDATE or XXX_VERSION macros are the name of the subdirectory under
+# the component directory where the specific version can be found. This is
+# usually in the form of YYYYMMDD, although NSPR et. al use a different
+# naming scheme.
+# NSPR
+ifndef NSPR_RELDATE
+ NSPR_RELDATE = DS7.0
+endif
+
+# SECURITY (NSS) LIBRARY
+ifndef SECURITY_RELDATE
+ SECURITY_RELDATE = DS7.0
+endif
+
+# LIBDB
+DBDEFS:=
+ifndef DB_MAJOR_MINOR
+DB_MAJOR_MINOR:=db42
+endif
+ifndef DB_VERSION
+ DB_VERSION:=DS7.0
+endif
+
+# DBM Library
+ifndef DBM_RELDATE
+ DBM_RELDATE = DS7.0
+endif
+
+# SMARTHEAP
+ifndef SH_VERSION
+ SH_VERSION:=v6.01
+endif
+
+# LDAP SDK
+ifndef LDAP_RELDATE
+ LDAP_RELDATE = DS7.0
+endif
+ifndef LDAPCOMP_DIR
+ LDAPCOMP_DIR=ldapsdk50
+endif
+
+# DSRK
+ifndef DSRK_RELDATE
+ DSRK_RELDATE = 20041029
+endif
+ifndef DSRKCOMP_DIR
+ DSRKCOMP_DIR=dsrk70
+endif
+
+# CRIMSONJAR
+ifndef CRIMSONJAR_VERSION
+ CRIMSONJAR_VERSION = 1.1.3
+endif
+ifndef CRIMSONJAR_COMP
+ CRIMSONJAR_COMP = crimson
+endif
+
+# ANT
+ifndef ANT_VERSION
+ ANT_VERSION = 1.4.1
+endif
+ifndef ANT_COMP
+ ANT_COMP = ant
+endif
+
+# Servlet SDK
+ifndef SERVLET_VERSION
+ SERVLET_VERSION = 2.3
+endif
+ifndef SERVLET_COMP
+ SERVLET_COMP = javax/servlet
+endif
+
+# LDAP JDK
+ifndef LDAPJDK_RELDATE
+ LDAPJDK_RELDATE = v4.17
+endif
+ifndef LDAPJDK_COMP
+ LDAPJDK_COMP = ldapjdk41
+endif
+
+# admin server
+
+ifndef ADM_RELDATE
+ ADM_RELDATE = 20041117
+endif
+ifndef ADM_VERSDIR
+ ADM_VERSDIR = admserv62
+endif
+
+# peer
+ifndef PEER_RELDATE
+ PEER_RELDATE = DS7.0
+endif
+
+# setup sdk
+ifndef SETUP_SDK_RELDATE
+ SETUP_SDK_RELDATE = DS7.0
+endif
+ifndef SETUPSDK_VERSDIR
+ SETUPSDK_VERSDIR = v6.2
+endif
+
+# infozip utilities
+ifndef INFOZIP_RELDATE
+ INFOZIP_RELDATE = CMSTOOLS_7_x
+endif
+
+# server core
+ifndef SVRCORE_RELDATE
+ SVRCORE_RELDATE = DS7.0
+endif
+
+# admin utility library
+ifndef ADMINUTIL_VER
+ ADMINUTIL_VER=62
+endif
+ifndef ADMINUTIL_RELDATE
+ ADMINUTIL_RELDATE=20041117
+endif
+
+ifndef ADMINUTIL_VERSDIR
+ ADMINUTIL_VERSDIR=adminsdk$(ADMINUTIL_VER)
+endif
+
+# MCC (Console JDK)
+ifndef MCC_REL
+ MCC_REL=62
+endif
+ifndef MCC_COMP
+ MCC_COMP = consolesdk$(MCC_REL)
+endif
+ifndef MCC_RELDATE
+ MCC_RELDATE=20041117
+endif
+
+ifndef PERLDAP_VERSION
+ PERLDAP_VERSION=20041116
+endif
+
+ifndef JSS_COMP
+ JSS_COMP=jss
+endif
+
+ifndef JSS_VERSION
+ JSS_VERSION=DS7.0
+endif
+
+ifndef JSS_JAR_VERSION
+ JSS_JAR_VERSION=3
+endif
+
+ifndef SASL_VERSDIR
+ SASL_VERSDIR=sasl_1_0
+endif
+ifndef SASL_RELDATE
+ SASL_RELDATE=20041130
+endif
+
+# jakarta/axis for DSMLGW
+ifndef TOMCAT_VERSION
+ TOMCAT_VERSION=5.0.27
+endif
+ifndef AXIS_VERSION
+ AXIS_VERSION=1_2beta
+endif
+
+# JSP compiler jasper
+ifndef JSPC_VERSION
+ JSPC_VERSION = 4.0.3
+endif
+ifndef JSPC_COMP
+ JSPC_COMP = javax/jasper
+endif
+
+# ICU
+ifndef ICU_VERSDIR
+ ICU_VERSDIR=libicu_2_4
+endif
+ifndef ICU_RELDATE
+ ICU_RELDATE=DS7.0
+endif
diff --git a/components.mk b/components.mk
new file mode 100644
index 00000000..f661a26f
--- /dev/null
+++ b/components.mk
@@ -0,0 +1,978 @@
+#
+# 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 definitions for component macros used during the build
+# process. Things like the component location in the build tree, etc.
+# this file should be included by nsconfig.mk after it figures out all
+# of the OS, architecture, security, and other platform and build related
+# macros. This file also contains the instructions for making the component
+# up to date e.g. copying the files from their repository to an area where
+# the build process has access to it. For some components and OS's, this may
+# be as simple as creating a symbolic link to the repository
+
+# Each component should define a COMPONENT_DEP macro which can be used in
+# other makefiles for dependency checking e.g.
+# target: $(COMPONENT1_DEP) $(COMPONENT2_DEP) ...
+# This macro should evaluate to the name of a single file which must be
+# present for the package to be complete e.g. some library or include
+# file name
+# Each component then should define a target for that dependency which will
+# bring the component up to date if that target does not exist e.g.
+# $(COMPONENT1_DEP):
+# use ftp or symlinks or ??? to get the necessary files to the build
+# area
+
+# Each component should define a COMPONENT_LINK macro which can be used to
+# link the component's libraries with the target. For NT, this will typically
+# be something like
+# /LIBPATH:path_to_library lib1 lib2 lib3 /LIBPATH:more_libs lib4 lib5 ...
+# On Unix, this will be something like
+# -Lpath_to_library -l1 -l2 -l3 -Lmore_libs -l4 -l5 ...
+
+# Each component should define a COMPONENT_INCLUDE macro which can be used
+# to compile using the component's header files e.g.
+# -Ipath_to_include_files -Ipath_to_more_include_files
+
+# Once this file is working, I will DELETE compvers.sh and ns_ftp.sh
+# from the tree, so help me god.
+
+# this macro contains a list of source files and directories to copy to
+# the directory where DLLs/SOs go at runtime; each component will add the files/dirs to
+# this macro that it needs to package; not all components will have
+# files which need packaging
+# if you need some other behavior, see PACKAGE_SRC_DEST below
+LIBS_TO_PKG =
+
+# this macro contains a list of source files and directories to copy to
+# the directory where DLLs/SOs go at runtime; each component will add the files/dirs to
+# this macro that it needs to package; this is for DLLs/SOs for the shared/bin
+# directory where the ldap c sdk command line tools, some security tools, and
+# the i18n conversion tools live
+LIBS_TO_PKG_SHARED =
+
+# this macro contains a list of source files and directories to copy to
+# the shared tools directory - things like the ldap c sdk command line
+# tools, shared security tools, etc.
+BINS_TO_PKG_SHARED =
+
+# this macro contains a list of shared libraries/dlls needed during
+# setup to run the setup pre-install program on unix (ns-config) or
+# the slapd plugin on NT (DSINST_PreInstall)
+PACKAGE_SETUP_LIBS =
+
+# this macro contains a list of libraries/dlls to copy to the clients
+# library directory
+LIBS_TO_PKG_CLIENTS =
+
+# this macro contains a list of source files and directories to copy to
+# the release/java directory; usually a list of jar files
+PACKAGE_UNDER_JAVA =
+
+# this macro contains a list of pairs of source and dest files and directories
+# the source is where to find the item in the build tree, and the dest is
+# the place in the release to put the item, relative to the server root e.g.
+# nls locale files are in libnls31/locale, but for packaging they need to
+# go into lib/nls, not just lib; the destination should be a directory name;
+# separate the src from the dest with a single space
+COMMA := ,
+NULLSTRING :=
+SPACE := $(NULLSTRING) # the space is between the ) and the #
+PACKAGE_SRC_DEST =
+
+ifeq ($(ARCH), WINNT)
+EXE_SUFFIX = .exe
+else # unix - windows has no lib name prefix, except for nspr
+LIB_PREFIX = lib
+endif
+
+# ADMINUTIL library #######################################
+ADMINUTIL_VERSION=$(ADMINUTIL_RELDATE)$(SEC_SUFFIX)
+ADMINUTIL_BASE=$(ADMINUTIL_VERSDIR)/${ADMINUTIL_VERSION}
+ADMSDKOBJDIR = $(FULL_RTL_OBJDIR)
+ADMINUTIL_IMPORT=$(COMPONENTS_DIR)/${ADMINUTIL_BASE}/$(NSOBJDIR_NAME)
+# this is the base directory under which the component's files will be found
+# during the build process
+ADMINUTIL_BUILD_DIR=$(NSCP_DISTDIR_FULL_RTL)/adminutil
+ADMINUTIL_LIBPATH=$(ADMINUTIL_BUILD_DIR)/lib
+ADMINUTIL_INCPATH=$(ADMINUTIL_BUILD_DIR)/include
+
+PACKAGE_SRC_DEST += $(ADMINUTIL_LIBPATH)/property bin/slapd/lib
+LIBS_TO_PKG += $(wildcard $(ADMINUTIL_LIBPATH)/*.$(DLL_SUFFIX))
+LIBS_TO_PKG_CLIENTS += $(wildcard $(ADMINUTIL_LIBPATH)/*.$(DLL_SUFFIX))
+
+#
+# Libadminutil
+#
+ADMINUTIL_DEP = $(ADMINUTIL_LIBPATH)/libadminutil$(ADMINUTIL_VER).$(LIB_SUFFIX)
+ifeq ($(ARCH), WINNT)
+ADMINUTIL_LINK = /LIBPATH:$(ADMINUTIL_LIBPATH) libadminutil$(ADMINUTIL_VER).$(LIB_SUFFIX)
+ADMINUTIL_S_LINK = /LIBPATH:$(ADMINUTIL_LIBPATH) libadminutil_s$(ADMINUTIL_VER).$(LIB_SUFFIX)
+LIBADMINUTILDLL_NAMES = $(ADMINUTIL_LIBPATH)/libadminutil$(ADMINUTIL_VER).$(DLL_SUFFIX)
+else
+ADMINUTIL_LINK=-L$(ADMINUTIL_LIBPATH) -ladminutil$(ADMINUTIL_VER)
+endif
+ADMINUTIL_INCLUDE=-I$(ADMINUTIL_INCPATH) \
+ -I$(ADMINUTIL_INCPATH)/libadminutil \
+ -I$(ADMINUTIL_INCPATH)/libadmsslutil
+
+ifndef ADMINUTIL_PULL_METHOD
+ADMINUTIL_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(ADMINUTIL_DEP): ${NSCP_DISTDIR_FULL_RTL}
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(ADMINUTIL_PULL_METHOD) \
+ -objdir $(ADMINUTIL_BUILD_DIR) \
+ -componentdir $(ADMINUTIL_IMPORT) \
+ -files include,lib
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component adminutil file $@" ; \
+ fi
+###########################################################
+# Peer
+
+PEER_BUILD_DIR = $(NSCP_DISTDIR)/peer
+ifeq ($(ARCH), WINNT)
+# PEER_RELEASE = $(COMPONENTS_DIR)/peer/$(PEER_RELDATE)
+# PEER_FILES = include
+else
+PEER_RELEASE = $(COMPONENTS_DIR)/peer/$(PEER_RELDATE)/$(NSOBJDIR_NAME)
+PEER_FILES = obj
+PEER_DEP = $(PEER_OBJPATH)/ns-ldapagt
+endif
+# PEER_MGMTPATH = $(PEER_BUILD_DIR)/dev
+# PEER_INCDIR = $(PEER_BUILD_DIR)/include
+# PEER_BINPATH = $(PEER_BUILD_DIR)/dev
+PEER_OBJPATH = $(PEER_BUILD_DIR)/obj
+# PEER_INCLUDE = -I$(PEER_INCDIR)
+
+ifndef PEER_PULL_METHOD
+PEER_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(PEER_DEP): $(NSCP_DISTDIR)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(PEER_PULL_METHOD) \
+ -objdir $(PEER_BUILD_DIR) -componentdir $(PEER_RELEASE) \
+ -files $(PEER_FILES)
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component PEER file $@" ; \
+ fi
+endif
+
+###########################################################
+
+# NSPR20 Library
+NSPR_LIBNAMES = plc4 plds4
+ifeq ($(ARCH), SOLARIS)
+ ifeq ($(NSPR_RELDATE), v4.2.2)
+# no need after v4.4.1
+NSPR_LIBNAMES += ultrasparc4
+# just need ultrasparc for now
+LIBS_TO_PKG += $(addsuffix .$(DLL_SUFFIX),$(addprefix $(NSPR_LIBPATH)/lib,ultrasparc4))
+ endif
+endif
+NSPR_LIBNAMES += nspr4
+NSPR_BUILD_DIR = $(NSCP_DISTDIR_FULL_RTL)/nspr
+NSPR_ABS_BUILD_DIR = $(NSCP_ABS_DISTDIR_FULL_RTL)/nspr
+NSPR_LIBPATH = $(NSPR_BUILD_DIR)/lib
+NSPR_INCLUDE = -I$(NSPR_BUILD_DIR)/include
+NSPR_IMPORT = $(COMPONENTS_DIR)/nspr20/$(NSPR_RELDATE)/$(FULL_RTL_OBJDIR)
+NSPR_LIBS_TO_PKG = $(addsuffix .$(DLL_SUFFIX),$(addprefix $(NSPR_LIBPATH)/lib,$(NSPR_LIBNAMES)))
+
+LIBS_TO_PKG += $(NSPR_LIBS_TO_PKG)
+LIBS_TO_PKG_SHARED += $(NSPR_LIBS_TO_PKG) # needed for cmd line tools
+PACKAGE_SETUP_LIBS += $(NSPR_LIBS_TO_PKG)
+LIBS_TO_PKG_CLIENTS += $(NSPR_LIBS_TO_PKG) # for dsgw
+
+NSPR_DEP = $(NSPR_LIBPATH)/libnspr4.$(LIB_SUFFIX)
+ifeq ($(ARCH), WINNT)
+ NSPRDLL_NAME = $(addprefix lib, $(NSPR_LIBNAMES))
+ NSPROBJNAME = $(addsuffix .lib, $(NSPRDLL_NAME))
+ NSPRLINK = /LIBPATH:$(NSPR_LIBPATH) $(NSPROBJNAME)
+ LIBNSPRDLL_NAMES = $(addsuffix .dll, $(addprefix $(NSPR_LIBPATH)/, \
+ $(addprefix lib, $(NSPR_LIBNAMES))))
+else
+ NSPR_SOLIBS = $(addsuffix .$(DLL_SUFFIX), $(addprefix $(LIB_PREFIX), $(NSPR_LIBNAMES)))
+ NSPROBJNAME = $(addsuffix .a, $(addprefix $(LIB_PREFIX), $(NSPR_LIBNAMES))
+ LIBNSPR = $(addprefix $(NSPR_LIBPATH)/, $(NSPR_SOLIBS))
+ NSPRLINK = -L$(NSPR_LIBPATH) $(addprefix -l, $(NSPR_LIBNAMES))
+endif
+
+ifndef NSPR_PULL_METHOD
+NSPR_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(NSPR_DEP): $(NSCP_DISTDIR_FULL_RTL)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(NSPR_PULL_METHOD) \
+ -objdir $(NSPR_BUILD_DIR) -componentdir $(NSPR_IMPORT) \
+ -files lib,include
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component NSPR file $@" ; \
+ fi
+
+### DBM #############################
+
+DBM_BUILD_DIR = $(NSCP_DISTDIR_FULL_RTL)/dbm
+DBM_LIBPATH = $(DBM_BUILD_DIR)/lib
+DBM_INCDIR = $(DBM_BUILD_DIR)/include
+DBM_DEP = $(DBM_LIBPATH)/libdbm.$(LIB_SUFFIX)
+DBM_IMPORT = $(COMPONENTS_DIR)/dbm/$(DBM_RELDATE)/$(NSOBJDIR_NAME)
+DBM_INCLUDE = -I$(DBM_INCDIR)
+DBM_LIBNAMES = dbm
+
+ifeq ($(ARCH), WINNT)
+ DBMOBJNAME = $(addsuffix .lib, $(DBM_LIBNAMES))
+ LIBDBM = $(addprefix $(DBM_LIBPATH)/, $(DBMOBJNAME))
+ DBMLINK = /LIBPATH:$(DBM_LIBPATH) $(DBMOBJNAME)
+ DBM_DEP = $(DBM_LIBPATH)/dbm.$(LIB_SUFFIX)
+else
+ DBM_SOLIBS = $(addsuffix .$(DLL_SUFFIX), $(addprefix $(LIB_PREFIX), $(DBM_LIBNAMES)))
+ DBMROBJNAME = $(addsuffix .a, $(addprefix $(LIB_PREFIX), $(DBM_LIBNAMES)))
+ LIBDBM = $(addprefix $(DBM_LIBPATH)/, $(DBMROBJNAME))
+ DBMLINK = -L$(DBM_LIBPATH) $(addprefix -l, $(DBM_LIBNAMES))
+ DBM_DEP = $(DBM_LIBPATH)/libdbm.$(LIB_SUFFIX)
+endif
+
+ifndef DBM_PULL_METHOD
+DBM_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(DBM_DEP): $(NSCP_DISTDIR_FULL_RTL)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(DBM_PULL_METHOD) \
+ -objdir $(DBM_BUILD_DIR) -componentdir $(DBM_IMPORT)/.. \
+ -files xpheader.jar -unzip $(DBM_INCDIR)
+ $(FTP_PULL) -method $(DBM_PULL_METHOD) \
+ -objdir $(DBM_BUILD_DIR) -componentdir $(DBM_IMPORT) \
+ -files mdbinary.jar -unzip $(DBM_BUILD_DIR)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component DBM file $@" ; \
+ fi
+
+### DBM END #############################
+
+### SECURITY #############################
+SECURITY_BUILD_DIR = $(NSCP_DISTDIR_FULL_RTL)/nss
+SECURITY_LIBPATH = $(SECURITY_BUILD_DIR)/lib
+SECURITY_BINPATH = $(SECURITY_BUILD_DIR)/bin
+SECURITY_INCDIR = $(SECURITY_BUILD_DIR)/include
+SECURITY_INCLUDE = -I$(SECURITY_INCDIR)
+# add crlutil and ocspclnt when we support CRL and OCSP cert checking in DS
+ifeq ($(SECURITY_RELDATE), NSS_3_7_9_RTM)
+SECURITY_BINNAMES = certutil derdump pp pk12util ssltap modutil
+else
+SECURITY_BINNAMES = certutil derdump pp pk12util ssltap modutil shlibsign
+endif
+SECURITY_LIBNAMES = ssl3 nss3 softokn3
+SECURITY_IMPORT = $(COMPONENTS_DIR)/nss/$(SECURITY_RELDATE)/$(FULL_RTL_OBJDIR)
+
+SECURITY_LIBNAMES.pkg = $(SECURITY_LIBNAMES)
+SECURITY_LIBNAMES.pkg += smime3
+ifeq ($(ARCH), SOLARIS)
+SECURITY_LIBNAMES.pkg += freebl_hybrid_3 freebl_pure32_3 fort swft
+endif
+ifeq ($(ARCH), HPUX)
+SECURITY_LIBNAMES.pkg += freebl_hybrid_3 freebl_pure32_3 fort swft
+endif
+ifeq ($(ARCH), AIX)
+SECURITY_LIBNAMES.pkg += fort swft
+endif
+ifeq ($(ARCH), OSF1)
+SECURITY_LIBNAMES.pkg += fort swft
+endif
+ifeq ($(ARCH), WINNT)
+SECURITY_LIBNAMES.pkg += fort32 swft32
+endif
+
+SECURITY_TOOLS = $(addsuffix $(EXE_SUFFIX),$(SECURITY_BINNAMES))
+SECURITY_TOOLS_FULLPATH = $(addprefix $(SECURITY_BINPATH)/, $(SECURITY_TOOLS))
+
+SECURITY_LIBS_TO_PKG = $(addsuffix .$(DLL_SUFFIX),$(addprefix $(SECURITY_LIBPATH)/$(LIB_PREFIX),$(SECURITY_LIBNAMES.pkg)))
+ifneq ($(SECURITY_RELDATE), NSS_3_7_9_RTM)
+SECURITY_LIBS_TO_PKG += $(addsuffix .chk,$(addprefix $(SECURITY_LIBPATH)/$(LIB_PREFIX),$(SECURITY_LIBNAMES.pkg)))
+endif
+LIBS_TO_PKG += $(SECURITY_LIBS_TO_PKG)
+LIBS_TO_PKG_SHARED += $(SECURITY_LIBS_TO_PKG) # for cmd line tools
+PACKAGE_SETUP_LIBS += $(SECURITY_LIBS_TO_PKG)
+LIBS_TO_PKG_CLIENTS += $(SECURITY_LIBS_TO_PKG) # for dsgw
+
+ifeq ($(ARCH), WINNT)
+ SECURITYOBJNAME = $(addsuffix .$(LIB_SUFFIX), $(SECURITY_LIBNAMES))
+ LIBSECURITY = $(addprefix $(SECURITY_LIBPATH)/, $(SECURITYOBJNAME))
+ SECURITYLINK = /LIBPATH:$(SECURITY_LIBPATH) $(SECURITYOBJNAME)
+ SECURITY_DEP = $(SECURITY_LIBPATH)/ssl3.$(DLL_SUFFIX)
+else
+ SECURITYOBJNAME = $(addsuffix .$(DLL_SUFFIX), $(addprefix $(LIB_PREFIX), $(SECURITY_LIBNAMES)))
+ LIBSECURITY = $(addprefix $(SECURITY_LIBPATH)/, $(SECURITYOBJNAME))
+ SECURITYLINK = -L$(SECURITY_LIBPATH) $(addprefix -l, $(SECURITY_LIBNAMES))
+ SECURITY_DEP = $(SECURITY_LIBPATH)/libssl3.$(DLL_SUFFIX)
+endif
+
+# we need to package the root cert file in the alias directory
+PACKAGE_SRC_DEST += $(SECURITY_LIBPATH)/$(LIB_PREFIX)nssckbi.$(DLL_SUFFIX) alias
+
+# need to package the sec tools in shared/bin
+BINS_TO_PKG_SHARED += $(SECURITY_TOOLS_FULLPATH)
+
+#ifeq ($(ARCH), OSF1)
+#OSF1SECURITYHACKOBJ = $(OBJDIR)/osf1securityhack.o
+
+#$(OSF1SECURITYHACKOBJ): $(MCOM_ROOT)/ldapserver/osf1securityhack.c
+# $(CC) -c $(CFLAGS) $(MCC_INCLUDE) $< -o $@
+
+# SECURITYLINK += $(OSF1SECURITYHACKOBJ)
+#endif
+
+SECURITY_FILES=lib,include,bin/$(subst $(SPACE),$(COMMA)bin/,$(SECURITY_TOOLS))
+
+ifndef SECURITY_PULL_METHOD
+SECURITY_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(SECURITY_DEP): $(NSCP_DISTDIR_FULL_RTL) $(OSF1SECURITYHACKOBJ)
+ifdef COMPONENT_DEPS
+ mkdir -p $(SECURITY_BINPATH)
+ $(FTP_PULL) -method $(SECURITY_PULL_METHOD) \
+ -objdir $(SECURITY_BUILD_DIR) -componentdir $(SECURITY_IMPORT) \
+ -files $(SECURITY_FILES)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component NSS file $@" ; \
+ fi
+
+### SECURITY END #############################
+
+### SVRCORE #############################
+SVRCORE_BUILD_DIR = $(NSCP_DISTDIR)/svrcore
+SVRCORE_LIBPATH = $(SVRCORE_BUILD_DIR)/lib
+SVRCORE_INCDIR = $(SVRCORE_BUILD_DIR)/include
+SVRCORE_INCLUDE = -I$(SVRCORE_INCDIR)
+#SVRCORE_LIBNAMES = svrplcy svrcore
+SVRCORE_LIBNAMES = svrcore
+SVRCORE_IMPORT = $(COMPONENTS_DIR)/svrcore/$(SVRCORE_RELDATE)/$(NSOBJDIR_NAME)
+
+ifeq ($(ARCH), WINNT)
+ SVRCOREOBJNAME = $(addsuffix .lib, $(SVRCORE_LIBNAMES))
+ LIBSVRCORE = $(addprefix $(SVRCORE_LIBPATH)/, $(SVRCOREOBJNAME))
+ SVRCORELINK = /LIBPATH:$(SVRCORE_LIBPATH) $(SVRCOREOBJNAME)
+ SVRCORE_DEP = $(SVRCORE_LIBPATH)/svrcore.$(LIB_SUFFIX)
+else
+ SVRCOREOBJNAME = $(addsuffix .a, $(addprefix $(LIB_PREFIX), $(SVRCORE_LIBNAMES)))
+ LIBSVRCORE = $(addprefix $(SVRCORE_LIBPATH)/, $(SVRCOREOBJNAME))
+ifeq ($(ARCH), OSF1)
+# the -all flag is used by default. This flag causes _all_ objects in lib.a files to
+# be processed and linked. This causes problems with svrcore because there are
+# several undefined symbols (notably, the JSS_xxx functions)
+ SVRCORELINK = -L$(SVRCORE_LIBPATH) -none $(addprefix -l, $(SVRCORE_LIBNAMES)) -all
+else
+ SVRCORELINK = -L$(SVRCORE_LIBPATH) $(addprefix -l, $(SVRCORE_LIBNAMES))
+endif
+ SVRCORE_DEP = $(SVRCORE_LIBPATH)/libsvrcore.$(LIB_SUFFIX)
+endif
+
+ifndef SVRCORE_PULL_METHOD
+SVRCORE_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(SVRCORE_DEP): $(NSCP_DISTDIR)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(SVRCORE_PULL_METHOD) \
+ -objdir $(SVRCORE_BUILD_DIR) -componentdir $(SVRCORE_IMPORT)/.. \
+ -files xpheader.jar -unzip $(SVRCORE_INCDIR)
+ $(FTP_PULL) -method $(SVRCORE_PULL_METHOD) \
+ -objdir $(SVRCORE_BUILD_DIR) -componentdir $(SVRCORE_IMPORT) \
+ -files mdbinary.jar -unzip $(SVRCORE_BUILD_DIR)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component SVRCORE file $@" ; \
+ fi
+
+### SVRCORE END #############################
+
+### SETUPSDK #############################
+# this is where the build looks for setupsdk components
+SETUP_SDK_BUILD_DIR = $(NSCP_DISTDIR)/setupsdk
+SETUPSDK_VERSION = $(SETUP_SDK_RELDATE)$(SEC_SUFFIX)
+SETUPSDK_RELEASE = $(COMPONENTS_DIR)/setupsdk/$(SETUPSDK_VERSDIR)/$(SETUPSDK_VERSION)/$(NSOBJDIR_NAME)
+SETUPSDK_LIBPATH = $(SETUP_SDK_BUILD_DIR)/lib
+SETUPSDK_INCDIR = $(SETUP_SDK_BUILD_DIR)/include
+SETUPSDK_BINPATH = $(SETUP_SDK_BUILD_DIR)/bin
+SETUPSDK_INCLUDE = -I$(SETUPSDK_INCDIR)
+
+ifeq ($(ARCH), WINNT)
+SETUP_SDK_FILES = setupsdk.tar.gz -unzip $(NSCP_DISTDIR)/setupsdk
+SETUPSDK_DEP = $(SETUPSDK_LIBPATH)/nssetup32.$(LIB_SUFFIX)
+SETUPSDKLINK = /LIBPATH:$(SETUPSDK_LIBPATH) nssetup32.$(LIB_SUFFIX)
+SETUPSDK_S_LINK = /LIBPATH:$(SETUPSDK_LIBPATH) nssetup32_s.$(LIB_SUFFIX)
+else
+SETUP_SDK_FILES = bin,lib,include
+SETUPSDK_DEP = $(SETUPSDK_LIBPATH)/libinstall.$(LIB_SUFFIX)
+SETUPSDKLINK = -L$(SETUPSDK_LIBPATH) -linstall
+SETUPSDK_S_LINK = $(SETUPSDKLINK)
+endif
+
+ifndef SETUPSDK_PULL_METHOD
+SETUPSDK_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(SETUPSDK_DEP): $(NSCP_DISTDIR)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(SETUPSDK_PULL_METHOD) \
+ -objdir $(SETUP_SDK_BUILD_DIR) -componentdir $(SETUPSDK_RELEASE) \
+ -files $(SETUP_SDK_FILES)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component SETUPSDK file $@" ; \
+ fi
+
+####################################################
+# LDAP SDK
+###################################################
+ifndef LDAP_VERSION
+ LDAP_VERSION = $(LDAP_RELDATE)$(SEC_SUFFIX)
+endif
+
+LDAP_ROOT = $(NSCP_DISTDIR_FULL_RTL)/ldapsdk
+LDAPSDK_LIBPATH = $(LDAP_ROOT)/lib
+LDAPSDK_INCDIR = $(LDAP_ROOT)/include
+LDAPSDK_INCLUDE = -I$(LDAPSDK_INCDIR)
+ifndef LDAP_SBC
+# LDAP_SBC = $(COMPONENTS_DIR_DEV)
+LDAP_SBC = $(COMPONENTS_DIR)
+endif
+
+# package the command line programs
+LDAPSDK_TOOLS = $(wildcard $(LDAP_ROOT)/tools/*$(EXE_SUFFIX))
+BINS_TO_PKG_SHARED += $(LDAPSDK_TOOLS)
+# package the include files - needed for the plugin API
+LDAPSDK_INCLUDE_FILES = $(wildcard $(LDAPSDK_INCDIR)/*.h)
+PACKAGE_SRC_DEST += $(subst $(SPACE),$(SPACE)plugins/slapd/slapi/include$(SPACE),$(LDAPSDK_INCLUDE_FILES))
+PACKAGE_SRC_DEST += plugins/slapd/slapi/include
+
+LDAPOBJDIR = $(FULL_RTL_OBJDIR)
+ifeq ($(ARCH), WINNT)
+ ifeq ($(PROCESSOR), ALPHA)
+ ifeq ($(DEBUG), full)
+ LDAPOBJDIR = WINNTALPHA3.51_DBG.OBJ
+ else
+ LDAPOBJDIR = WINNTALPHA3.51_OPT.OBJ
+ endif
+ endif
+
+ LDAP_RELEASE = $(LDAP_SBC)/$(LDAPCOMP_DIR)/$(LDAP_VERSION)/$(LDAPOBJDIR)
+ LDAP_LIBNAMES = ldapssl32v$(LDAP_SUF) ldap32v$(LDAP_SUF) ldappr32v$(LDAP_SUF)
+ LDAPDLL_NAME = $(addprefix ns, $(LDAP_LIBNAMES))
+ LDAPOBJNAME = $(addsuffix .$(LIB_SUFFIX), $(LDAPDLL_NAME))
+ LDAPLINK = /LIBPATH:$(LDAPSDK_LIBPATH) $(LDAPOBJNAME)
+ LIBLDAPDLL_NAMES = $(addsuffix .dll, $(addprefix $(LDAP_LIBPATH)/, $(LDAPDLL_NAME)))
+ LDAPSDK_DEP = $(LDAPSDK_LIBPATH)/nsldap32v$(LDAP_SUF).$(DLL_SUFFIX)
+ LDAPSDK_PULL_LIBS = lib/nsldapssl32v$(LDAP_SUF).$(LIB_SUFFIX),lib/nsldapssl32v$(LDAP_SUF).$(LDAP_DLL_SUFFIX),lib/nsldap32v$(LDAP_SUF).$(LIB_SUFFIX),lib/nsldap32v$(LDAP_SUF).$(LDAP_DLL_SUFFIX),lib/nsldappr32v$(LDAP_SUF).$(LIB_SUFFIX),lib/nsldappr32v$(LDAP_SUF).$(LDAP_DLL_SUFFIX)
+
+ LIBS_TO_PKG += $(addsuffix .$(DLL_SUFFIX),$(addprefix $(LDAPSDK_LIBPATH)/,$(LDAPDLL_NAME)))
+ PACKAGE_SETUP_LIBS += $(addsuffix .$(DLL_SUFFIX),$(addprefix $(LDAPSDK_LIBPATH)/,$(LDAPDLL_NAME)))
+ LIBS_TO_PKG_SHARED += $(addsuffix .$(DLL_SUFFIX),$(addprefix $(LDAPSDK_LIBPATH)/,$(LDAPDLL_NAME)))
+ LIBS_TO_PKG_CLIENTS += $(addsuffix .$(DLL_SUFFIX),$(addprefix $(LDAPSDK_LIBPATH)/,$(LDAPDLL_NAME)))
+endif
+
+# override LDAP version in OS specific section
+ifneq ($(ARCH), WINNT)
+# LDAP Does not has PTH version, so here is the hack which treat non PTH
+# version as PTH version
+ ifeq ($(USE_PTHREADS), 1)
+ LDAP_RELEASE = $(LDAP_SBC)/$(LDAPCOMP_DIR)/$(LDAP_VERSION)/$(NSOBJDIR_NAME1)
+ else
+ LDAP_RELEASE = $(LDAP_SBC)/$(LDAPCOMP_DIR)/$(LDAP_VERSION)/$(LDAPOBJDIR)
+ endif
+ LDAP_SOLIB_NAMES = ssldap$(LDAP_SUF)$(LDAP_DLL_PRESUF) ldap$(LDAP_SUF)$(LDAP_DLL_PRESUF) prldap$(LDAP_SUF)$(LDAP_DLL_PRESUF)
+ ifndef LDAP_NO_LIBLCACHE
+ LDAP_SOLIB_NAMES += lcache30$(LDAP_DLL_PRESUF)
+ endif
+ LDAP_DOTALIB_NAMES =
+ LDAP_LIBNAMES = $(LDAP_DOTALIB_NAMES) $(LDAP_SOLIB_NAMES)
+ LDAP_SOLIBS = $(addsuffix .$(LDAP_DLL_SUFFIX), $(addprefix $(LIB_PREFIX), $(LDAP_SOLIB_NAMES)))
+ LDAPOBJNAME = $(addsuffix .$(LIB_SUFFIX), $(addprefix $(LIB_PREFIX), $(LDAP_DOTALIB_NAMES))) \
+ $(LDAP_SOLIBS)
+ LDAPSDK_DEP = $(LDAPSDK_LIBPATH)/libldap$(LDAP_SUF).$(DLL_SUFFIX)
+ LDAPLINK = -L$(LDAPSDK_LIBPATH) $(addprefix -l,$(LDAP_SOLIB_NAMES))
+ LDAP_NOSSL_LINK = -L$(LDAPSDK_LIBPATH) -lldap$(LDAP_SUF)$(LDAP_DLL_PRESUF)
+ LDAPSDK_PULL_LIBS = lib/libssldap$(LDAP_SUF)$(LDAP_DLL_PRESUF).$(LDAP_DLL_SUFFIX),lib/libldap$(LDAP_SUF)$(LDAP_DLL_PRESUF).$(LDAP_DLL_SUFFIX),lib/libprldap$(LDAP_SUF)$(LDAP_DLL_PRESUF).$(LDAP_DLL_SUFFIX)
+
+ LIBS_TO_PKG += $(addprefix $(LDAPSDK_LIBPATH)/,$(LDAP_SOLIBS))
+ PACKAGE_SETUP_LIBS += $(addprefix $(LDAPSDK_LIBPATH)/,$(LDAP_SOLIBS))
+ LIBS_TO_PKG_SHARED += $(addprefix $(LDAPSDK_LIBPATH)/,$(LDAP_SOLIBS))
+ LIBS_TO_PKG_CLIENTS += $(addprefix $(LDAPSDK_LIBPATH)/,$(LDAP_SOLIBS))
+endif
+
+LDAP_LIBPATH = $(LDAP_ROOT)/lib
+LDAP_INCLUDE = $(LDAP_ROOT)/include
+LDAP_TOOLDIR = $(LDAP_ROOT)/tools
+LIBLDAP = $(addprefix $(LDAP_LIBPATH)/, $(LDAPOBJNAME))
+LDAPSDK_FILES = include,$(LDAPSDK_PULL_LIBS),tools
+
+ifndef LDAPSDK_PULL_METHOD
+LDAPSDK_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(LDAPSDK_DEP): $(NSCP_DISTDIR_FULL_RTL)
+ifdef COMPONENT_DEPS
+ mkdir -p $(LDAP_LIBPATH)
+ $(FTP_PULL) -method $(LDAPSDK_PULL_METHOD) \
+ -objdir $(LDAP_ROOT) -componentdir $(LDAP_RELEASE) \
+ -files $(LDAPSDK_FILES)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component LDAPSDK file $@" ; \
+ fi
+
+####################################################
+# DSRK
+####################################################
+ifndef DSRK_VERSION
+ DSRK_VERSION = $(DSRK_RELDATE)$(SEC_SUFFIX)
+endif
+ifndef DSRK_SBC
+# DSRK_SBC = $(COMPONENTS_DIR_DEV)
+DSRK_SBC = $(COMPONENTS_DIR)
+endif
+
+DSRK_RELEASE = $(DSRK_SBC)/dsrk/$(DSRKCOMP_DIR)/$(DSRK_VERSION)/$(NSOBJDIR_NAME)
+DSRK_FILES = bin,perl
+DSRK_BUILD_DIR = $(NSCP_DISTDIR)/dsrk
+DSRK_DEP = $(DSRK_BUILD_DIR)/bin/n$(DSRKCOMP_DIR)
+
+ifndef DSRK_PULL_METHOD
+DSRK_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(DSRK_DEP): $(NSCP_DISTDIR_FULL_RTL)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(DSRK_PULL_METHOD) \
+ -objdir $(DSRK_BUILD_DIR) -componentdir $(DSRK_RELEASE) \
+ -files $(DSRK_FILES)
+endif
+ -@if [ ! -d $@ ] ; \
+ then echo "Error: could not get component DSRK file $@" ; \
+ fi
+
+# apache-axis java classes #######################################
+AXIS = axis-bin-$(AXIS_VERSION).zip
+AXIS_FILES = $(AXIS)
+#AXIS_RELEASE = $(COMPONENTS_DIR)
+AXIS_RELEASE = $(COMPONENTS_DIR_DEV)/ds/ds70-bozeman
+#AXISJAR_DIR = $(AXISJAR_RELEASE)/$(AXISJAR_COMP)/$(AXISJAR_VERSION)
+AXIS_DIR = $(AXIS_RELEASE)/axis
+AXIS_FILE = $(CLASS_DEST)/$(AXIS)
+AXIS_DEP = $(AXIS_FILE)
+AXIS_REL_DIR=$(subst -bin,,$(subst .zip,,$(AXIS)))
+
+
+# This is java, so there is only one real platform subdirectory
+
+#PACKAGE_UNDER_JAVA += $(AXIS_FILE)
+
+ifndef AXIS_PULL_METHOD
+AXIS_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(AXIS_DEP): $(CLASS_DEST)
+ifdef COMPONENT_DEPS
+ echo "Inside ftppull"
+ $(FTP_PULL) -method $(COMPONENT_PULL_METHOD) \
+ -objdir $(CLASS_DEST) -componentdir $(AXIS_DIR) \
+ -files $(AXIS_FILES) -unzip $(CLASS_DEST)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component AXIS files $@" ; \
+ fi
+
+###########################################################
+
+
+# other dsml java classes #######################################
+DSMLJAR = activation.jar,jaxrpc-api.jar,jaxrpc.jar,saaj.jar,xercesImpl.jar,xml-apis.jar
+DSMLJAR_FILES = $(DSMLJAR)
+DSMLJAR_RELEASE = $(COMPONENTS_DIR_DEV)/ds/ds70-bozeman
+#DSMLJARJAR_DIR = $(DSMLJARJAR_RELEASE)/$(DSMLJARJAR_COMP)/$(DSMLJARJAR_VERSION)
+DSMLJAR_DIR = $(DSMLJAR_RELEASE)/dsmljars
+DSMLJAR_FILE = $(CLASS_DEST)
+DSMLJAR_DEP = $(CLASS_DEST)/activation.jar $(CLASS_DEST)/jaxrpc-api.jar $(CLASS_DEST)/jaxrpc.jar $(CLASS_DEST)/saaj.jar $(CLASS_DEST)/xercesImpl.jar $(CLASS_DEST)/xml-apis.jar
+
+ifndef DSMLJAR_PULL_METHOD
+DSMLJAR_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(DSMLJAR_DEP): $(CLASS_DEST)
+ifdef COMPONENT_DEPS
+ echo "Inside ftppull"
+ $(FTP_PULL) -method $(COMPONENT_PULL_METHOD) \
+ -objdir $(CLASS_DEST) -componentdir $(DSMLJAR_DIR) \
+ -files $(DSMLJAR_FILES)
+
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component DSMLJAR files $@" ; \
+ fi
+
+###########################################################
+
+# XMLTOOLS java classes #######################################
+CRIMSONJAR = crimson.jar
+CRIMSON_LICENSE = LICENSE.crimson
+CRIMSONJAR_FILES = $(CRIMSONJAR),$(CRIMSON_LICENSE)
+CRIMSONJAR_RELEASE = $(COMPONENTS_DIR)
+CRIMSONJAR_DIR = $(CRIMSONJAR_RELEASE)/$(CRIMSONJAR_COMP)/$(CRIMSONJAR_VERSION)
+CRIMSONJAR_FILE = $(CLASS_DEST)/$(CRIMSONJAR)
+CRIMSONJAR_DEP = $(CRIMSONJAR_FILE) $(CLASS_DEST)/$(CRIMSON_LICENSE)
+
+
+# This is java, so there is only one real platform subdirectory
+
+PACKAGE_UNDER_JAVA += $(CRIMSONJAR_FILE)
+
+ifndef CRIMSONJAR_PULL_METHOD
+CRIMSONJAR_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(CRIMSONJAR_DEP): $(CLASS_DEST)
+ifdef COMPONENT_DEPS
+ echo "Inside ftppull"
+ $(FTP_PULL) -method $(COMPONENT_PULL_METHOD) \
+ -objdir $(CLASS_DEST) -componentdir $(CRIMSONJAR_DIR) \
+ -files $(CRIMSONJAR_FILES)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component CRIMSONJAR files $@" ; \
+ fi
+
+###########################################################
+
+# ANT java classes #######################################
+ifeq ($(BUILD_JAVA_CODE),1)
+# (we use ant for building some Java code)
+ANTJAR = ant.jar
+JAXPJAR = jaxp.jar
+ANT_FILES = $(ANTJAR) $(JAXPJAR)
+ANT_RELEASE = $(COMPONENTS_DIR)
+ANT_HOME = $(ANT_RELEASE)/$(ANT_COMP)/$(ANT_VERSION)
+ANT_DIR = $(ANT_HOME)/lib
+ANT_DEP = $(addprefix $(CLASS_DEST)/, $(ANT_FILES))
+ANT_CP = $(subst $(SPACE),$(PATH_SEP),$(ANT_DEP))
+ANT_PULL = $(subst $(SPACE),$(COMMA),$(ANT_FILES))
+
+ifndef ANT_PULL_METHOD
+ANT_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(ANT_DEP): $(CLASS_DEST) $(CRIMSONJAR_DEP)
+ifdef COMPONENT_DEPS
+ echo "Inside ftppull"
+ $(FTP_PULL) -method $(COMPONENT_PULL_METHOD) \
+ -objdir $(CLASS_DEST) -componentdir $(ANT_DIR) \
+ -files $(ANT_PULL)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component ant files $@" ; \
+ fi
+endif
+###########################################################
+
+# Servlet SDK classes #######################################
+SERVLETJAR = servlet.jar
+SERVLET_FILES = $(SERVLETJAR)
+SERVLET_RELEASE = $(COMPONENTS_DIR)
+SERVLET_DIR = $(SERVLET_RELEASE)/$(SERVLET_COMP)/$(SERVLET_VERSION)
+SERVLET_DEP = $(addprefix $(CLASS_DEST)/, $(SERVLET_FILES))
+SERVLET_CP = $(subst $(SPACE),$(PATH_SEP),$(SERVLET_DEP))
+SERVLET_PULL = $(subst $(SPACE),$(COMMA),$(SERVLET_FILES))
+
+ifndef SERVLET_PULL_METHOD
+SERVLET_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(SERVLET_DEP): $(CLASS_DEST)
+ifdef COMPONENT_DEPS
+ echo "Inside ftppull"
+ $(FTP_PULL) -method $(COMPONENT_PULL_METHOD) \
+ -objdir $(CLASS_DEST) -componentdir $(SERVLET_DIR) \
+ -files $(SERVLET_PULL)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component servlet SDK files $@" ; \
+ fi
+
+###########################################################
+
+# LDAP java classes #######################################
+LDAPJDK = ldapjdk.jar
+LDAPJDK_VERSION = $(LDAPJDK_RELDATE)
+LDAPJDK_RELEASE = $(COMPONENTS_DIR)
+LDAPJDK_DIR = $(LDAPJDK_RELEASE)
+LDAPJDK_IMPORT = $(LDAPJDK_RELEASE)/$(LDAPJDK_COMP)/$(LDAPJDK_VERSION)/$(NSOBJDIR_NAME)
+# This is java, so there is only one real platform subdirectory
+LDAPJARFILE=$(CLASS_DEST)/ldapjdk.jar
+LDAPJDK_DEP=$(LDAPJARFILE)
+
+#PACKAGE_UNDER_JAVA += $(LDAPJARFILE)
+
+ifndef LDAPJDK_PULL_METHOD
+LDAPJDK_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(LDAPJDK_DEP): $(CLASS_DEST)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(LDAPJDK_PULL_METHOD) \
+ -objdir $(CLASS_DEST) -componentdir $(LDAPJDK_IMPORT) \
+ -files $(LDAPJDK)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component LDAPJDK file $@" ; \
+ fi
+
+###########################################################
+
+# MCC java classes - the Mission Control Console #########
+MCC_VERSION=$(MCC_RELDATE)$(SEC_SUFFIX)
+#
+MCCJAR = mcc$(MCC_REL).jar
+MCCJAR_EN = mcc$(MCC_REL)_en.jar
+NMCLFJAR = nmclf$(MCC_REL).jar
+NMCLFJAR_EN = nmclf$(MCC_REL)_en.jar
+BASEJAR = base.jar
+#MCC_RELEASE=$(COMPONENTS_DIR_DEV)
+MCC_RELEASE=$(COMPONENTS_DIR)
+MCC_JARDIR = $(MCC_RELEASE)/$(MCC_COMP)/$(MCC_VERSION)/jars
+MCCJARFILE=$(CLASS_DEST)/$(MCCJAR)
+NMCLFJARFILE=$(CLASS_DEST)/$(NMCLFJAR)
+BASEJARFILE=$(CLASS_DEST)/$(BASEJAR)
+
+MCC_DEP = $(BASEJARFILE)
+MCC_FILES=$(MCCJAR),$(MCCJAR_EN),$(NMCLFJAR),$(NMCLFJAR_EN),$(BASEJAR)
+
+#PACKAGE_UNDER_JAVA += $(addprefix $(CLASS_DEST)/,$(subst $(COMMA),$(SPACE),$(MCC_FILES)))
+
+ifndef MCC_PULL_METHOD
+MCC_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(MCC_DEP): $(CLASS_DEST)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(MCC_PULL_METHOD) \
+ -objdir $(CLASS_DEST) -componentdir $(MCC_JARDIR) \
+ -files $(MCC_FILES)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component MCC file $@" ; \
+ fi
+
+###########################################################
+
+###########################################################
+### Perldap package #######################################
+
+PERLDAP_COMPONENT_DIR = $(COMPONENTS_DIR)/perldap/$(PERLDAP_VERSION)/$(NSOBJDIR_NAME_32)
+PERLDAP_ZIP_FILE = perldap14.zip
+
+###########################################################
+
+# JSS classes - for the Mission Control Console ######
+JSSJAR = jss$(JSS_JAR_VERSION).jar
+JSSJARFILE = $(CLASS_DEST)/$(JSSJAR)
+JSS_RELEASE = $(COMPONENTS_DIR)/$(JSS_COMP)/$(JSS_VERSION)
+JSS_DEP = $(JSSJARFILE)
+
+#PACKAGE_UNDER_JAVA += $(JSSJARFILE)
+
+ifndef JSS_PULL_METHOD
+JSS_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(JSS_DEP): $(CLASS_DEST)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(JSS_PULL_METHOD) \
+ -objdir $(CLASS_DEST) -componentdir $(JSS_RELEASE) \
+ -files $(JSSJAR)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component JSS file $@" ; \
+ fi
+
+###########################################################
+
+###########################################################
+### Admin Server package ##################################
+
+ADMIN_REL = $(ADM_VERSDIR)
+ADMIN_REL_DATE = $(ADM_VERSION)
+ADMIN_FILE = admserv.tar.gz
+ADMIN_FILE_TAR = admserv.tar
+ADMSDKOBJDIR = $(NSCONFIG)$(NSOBJDIR_TAG).OBJ
+IMPORTADMINSRV_BASE=$(COMPONENTS_DIR)/$(ADMIN_REL)/$(ADMIN_REL_DATE)
+IMPORTADMINSRV = $(IMPORTADMINSRV_BASE)/$(NSOBJDIR_NAME_32)
+ADMSERV_DIR=$(ABS_ROOT)/dist/$(NSOBJDIR_NAME)/admserv
+ADMSERV_DEP = $(ADMSERV_DIR)/setup$(EXE_SUFFIX)
+
+ifdef FORTEZZA
+ ADM_VERSION = $(ADM_RELDATE)F
+else
+ ifeq ($(SECURITY), domestic)
+ ADM_VERSION = $(ADM_RELDATE)D
+ else
+ ifneq ($(ARCH), IRIX)
+ ADM_VERSION = $(ADM_RELDATE)E
+ else
+ ADM_VERSION = $(ADM_RELDATE)D
+ endif
+ endif
+endif
+
+ADM_VERSION = $(ADM_RELDATE)$(SEC_SUFFIX)
+ADM_RELEASE = $(COMPONENTS_DIR)/$(ADM_VERSDIR)/$(ADM_VERSION)/$(NSOBJDIR_NAME)
+
+ifndef ADMSERV_PULL_METHOD
+ADMSERV_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+ifndef ADMSERV_DEPS
+ADMSERV_DEPS = $(COMPONENT_DEPS)
+endif
+#IMPORTADMINSRV = /share/builds/sbsrel1/admsvr/admsvr62/ships/20030702.2/spd04_Solaris8/SunOS5.8-domestic-optimize-normal
+#ADM_RELEASE = /share/builds/sbsrel1/admsvr/admsvr62/ships/20030702.2/spd04_Solaris8/SunOS5.8-domestic-optimize-normal
+$(ADMSERV_DEP): $(ABS_ROOT)/dist/$(NSOBJDIR_NAME)
+ifdef ADMSERV_DEPS
+ $(FTP_PULL) -method $(ADMSERV_PULL_METHOD) \
+ -objdir $(ADMSERV_DIR) -componentdir $(IMPORTADMINSRV) \
+ -files $(ADMIN_FILE) -unzip $(ADMSERV_DIR)
+endif
+ @if [ ! -f $@ ] ; \
+ then echo "Error: could not get component ADMINSERV file $@" ; \
+ exit 1 ; \
+ fi
+### Admin Server END ######################################
+
+
+
+### SASL package ##########################################
+
+SASL_BUILD_DIR = $(NSCP_DISTDIR_FULL_RTL)/sasl
+SASL_RELEASE = $(COMPONENTS_DIR)/sasl/$(SASL_VERSDIR)/$(SASL_RELDATE)/$(NSOBJDIR_NAME)
+SASL_LIBPATH = $(SASL_BUILD_DIR)/lib
+SASL_BINPATH = $(SASL_BUILD_DIR)/bin
+SASL_INCLUDE = $(SASL_BUILD_DIR)/include
+SASL_DEP = $(SASL_INCLUDE)/sasl.h
+ifeq ($(ARCH), WINNT)
+SASL_LINK = /LIBPATH:$(SASL_LIBPATH) sasl.lib
+else
+ifeq ($(ARCH), SOLARIS)
+GSSAPI_LIBS=-lgss
+endif
+#ifeq ($(ARCH), HPUX)
+GSSAPI_LIBS=-lgss
+#endif
+ifeq ($(ARCH), Linux)
+GSSAPI_LIBS=-L/usr/kerberos/lib -lgssapi_krb5
+endif
+SASL_LINK = -L$(SASL_LIBPATH) -lsasl $(GSSAPI_LIBS)
+#SASL_LINK = -L$(SASL_LIBPATH) -lsasl
+endif
+
+ifndef SASL_PULL_METHOD
+SASL_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(SASL_DEP): $(NSCP_DISTDIR_FULL_RTL)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(SASL_PULL_METHOD) \
+ -objdir $(SASL_BUILD_DIR) -componentdir $(SASL_RELEASE) \
+ -files lib,include
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component SASL file $@" ; \
+ fi
+
+###########################################################
+
+### JSP compiler package ##################################
+
+JSPC_REL = $(JSPC_VERSDIR)
+JSPC_REL_DATE = $(JSPC_VERSION)
+JSPC_FILES = jasper-compiler.jar jasper-runtime.jar
+JSPC_RELEASE = $(COMPONENTS_DIR)
+JSPC_DIR = $(JSPC_RELEASE)/$(JSPC_COMP)/$(JSPC_VERSION)
+JSPC_DEP = $(addprefix $(CLASS_DEST)/, $(JSPC_FILES))
+JSPC_CP = $(subst $(SPACE),$(PATH_SEP),$(JSPC_DEP))
+JSPC_PULL = $(subst $(SPACE),$(COMMA),$(JSPC_FILES))
+
+ifndef JSPC_PULL_METHOD
+JSPC_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(JSPC_DEP): $(CLASS_DEST)
+ifdef COMPONENT_DEPS
+ echo "Inside ftppull"
+ $(FTP_PULL) -method $(COMPONENT_PULL_METHOD) \
+ -objdir $(CLASS_DEST) -componentdir $(JSPC_DIR) \
+ -files $(JSPC_PULL)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component jspc files $@" ; \
+ fi
+
+###########################################################
+
+### ICU package ##########################################
+
+ICU_LIB_VERSION = 24
+ICU_BUILD_DIR = $(NSCP_DISTDIR_FULL_RTL)/libicu
+ICU_RELEASE = $(COMPONENTS_DIR)/libicu/$(ICU_VERSDIR)/$(ICU_RELDATE)/$(NSOBJDIR_NAME)
+ICU_LIBPATH = $(ICU_BUILD_DIR)/lib
+ICU_BINPATH = $(ICU_BUILD_DIR)/bin
+ICU_INCPATH = $(ICU_BUILD_DIR)/include
+ICU_DEP = $(ICU_INCPATH)/unicode/unicode.h
+ICU_INCLUDE = -I$(ICU_INCPATH)
+ifeq ($(ARCH), WINNT)
+ifeq ($(BUILD_DEBUG), optimize)
+ICU_LIB_SUF=
+else
+ICU_LIB_SUF=d
+endif
+ICU_LIBNAMES = icuin$(ICU_LIB_SUF) icuuc$(ICU_LIB_SUF) icudata
+ICU_DLLNAMES = icuin$(ICU_LIB_VERSION)$(ICU_LIB_SUF) icuuc$(ICU_LIB_VERSION)$(ICU_LIB_SUF) icudt$(ICU_LIB_VERSION)l
+ICULINK = /LIBPATH:$(ICU_LIBPATH) $(addsuffix .$(LIB_SUFFIX),$(ICU_LIBNAMES))
+LIBS_TO_PKG += $(addsuffix .$(DLL_SUFFIX),$(addprefix $(ICU_BINPATH)/,$(ICU_DLLNAMES)))
+LIBS_TO_PKG_SHARED += $(addsuffix .$(DLL_SUFFIX),$(addprefix $(ICU_BINPATH)/,$(ICU_DLLNAMES)))
+LIBS_TO_PKG_CLIENTS += $(addsuffix .$(DLL_SUFFIX),$(addprefix $(ICU_BINPATH)/,$(ICU_DLLNAMES)))
+else
+ICU_LIBNAMES = icui18n icuuc icudata
+ICULINK = -L$(ICU_LIBPATH) $(addprefix -l, $(ICU_LIBNAMES))
+LIBS_TO_PKG += $(addsuffix .$(ICU_LIB_VERSION),$(addsuffix .$(DLL_SUFFIX),$(addprefix $(ICU_LIBPATH)/,$(addprefix lib,$(ICU_LIBNAMES)))))
+LIBS_TO_PKG_SHARED += $(addsuffix .$(ICU_LIB_VERSION),$(addsuffix .$(DLL_SUFFIX),$(addprefix $(ICU_LIBPATH)/,$(addprefix lib,$(ICU_LIBNAMES)))))
+LIBS_TO_PKG_CLIENTS += $(addsuffix .$(ICU_LIB_VERSION),$(addsuffix .$(DLL_SUFFIX),$(addprefix $(ICU_LIBPATH)/,$(addprefix lib,$(ICU_LIBNAMES)))))
+#LIBS_TO_PKG = $(addsuffix $(addprefix lib,$(ICU_LIBNAMES))
+endif
+
+BINS_TO_PKG_SHARED += $(ICU_BINPATH)/uconv$(EXE_SUFFIX)
+
+ifndef ICU_PULL_METHOD
+ICU_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(ICU_DEP): $(NSCP_DISTDIR_FULL_RTL)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(ICU_PULL_METHOD) \
+ -objdir $(ICU_BUILD_DIR) -componentdir $(ICU_RELEASE) \
+ -files lib,include,bin
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component ICU file $@" ; \
+ fi
+
+###########################################################
diff --git a/config/.cvsignore b/config/.cvsignore
new file mode 100644
index 00000000..9a1527d0
--- /dev/null
+++ b/config/.cvsignore
@@ -0,0 +1,5 @@
+nfspwd
+nsinstall
+revdepth
+myconfig.mk
+myrules.mk
diff --git a/config/Linux2.4.mk b/config/Linux2.4.mk
new file mode 100644
index 00000000..fc0447b8
--- /dev/null
+++ b/config/Linux2.4.mk
@@ -0,0 +1,58 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Config stuff for Linux2.4
+#
+
+#include $(NSPRDEPTH)/config/UNIX.mk
+
+CC = gcc
+CCC = g++
+
+CPU_ARCH = x86
+GFX_ARCH = x
+
+RANLIB = ranlib
+
+ifdef SERVER_BUILD
+# see sun-java/config/config.mk
+STATIC_JAVA = yes
+endif
+
+NEED_XMOS = 1
+
+# fixme OS_CFLAGS = -m486 -ansi -Wall -pipe -MDupdate $(DEPENDENCIES)
+OS_CFLAGS = -m486 -ansi -Wall -pipe
+
+OS_CFLAGS += -DLINUX -DLINUX2_4 -D_POSIX_SOURCE -D_BSD_SOURCE -DHAVE_STRERROR -D_REENTRANT
+OS_LIBS = -L /lib -lc -ldl -lpthread
+
+ARCH = linux
+
+EN_LOCALE = C
+DE_LOCALE = de_DE.ISO8859-1
+FR_LOCALE = fr_FR.ISO8859-1
+JP_LOCALE = ja
+SJIS_LOCALE = ja_JP.SJIS
+KR_LOCALE = ko_KR.EUC
+CN_LOCALE = zh
+TW_LOCALE = zh
+I2_LOCALE = i2
+
+BUILD_UNIX_PLUGINS = 1
+
+ifeq ($(OS_RELEASE),2.4)
+OS_REL_CFLAGS += -DLINUX2_4
+MKSHLIB = $(LD) -shared
+endif
+
+XINC = /usr/X11R6/include
+INCLUDES += -I$(XINC)
+
+BSDECHO = echo
+
diff --git a/config/Linux2.6.mk b/config/Linux2.6.mk
new file mode 100644
index 00000000..fc0447b8
--- /dev/null
+++ b/config/Linux2.6.mk
@@ -0,0 +1,58 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Config stuff for Linux2.4
+#
+
+#include $(NSPRDEPTH)/config/UNIX.mk
+
+CC = gcc
+CCC = g++
+
+CPU_ARCH = x86
+GFX_ARCH = x
+
+RANLIB = ranlib
+
+ifdef SERVER_BUILD
+# see sun-java/config/config.mk
+STATIC_JAVA = yes
+endif
+
+NEED_XMOS = 1
+
+# fixme OS_CFLAGS = -m486 -ansi -Wall -pipe -MDupdate $(DEPENDENCIES)
+OS_CFLAGS = -m486 -ansi -Wall -pipe
+
+OS_CFLAGS += -DLINUX -DLINUX2_4 -D_POSIX_SOURCE -D_BSD_SOURCE -DHAVE_STRERROR -D_REENTRANT
+OS_LIBS = -L /lib -lc -ldl -lpthread
+
+ARCH = linux
+
+EN_LOCALE = C
+DE_LOCALE = de_DE.ISO8859-1
+FR_LOCALE = fr_FR.ISO8859-1
+JP_LOCALE = ja
+SJIS_LOCALE = ja_JP.SJIS
+KR_LOCALE = ko_KR.EUC
+CN_LOCALE = zh
+TW_LOCALE = zh
+I2_LOCALE = i2
+
+BUILD_UNIX_PLUGINS = 1
+
+ifeq ($(OS_RELEASE),2.4)
+OS_REL_CFLAGS += -DLINUX2_4
+MKSHLIB = $(LD) -shared
+endif
+
+XINC = /usr/X11R6/include
+INCLUDES += -I$(XINC)
+
+BSDECHO = echo
+
diff --git a/config/Makefile b/config/Makefile
new file mode 100644
index 00000000..a3326e44
--- /dev/null
+++ b/config/Makefile
@@ -0,0 +1,38 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#! gmake
+
+DEPTH = ..
+
+HSRCS = pathsub.h
+CSRCS = nsinstall.c pathsub.c
+
+PLSRCS = nfspwd.pl revdepth.pl
+
+ifneq ($(subst /,_,$(shell uname -s)),WINNT)
+PROGRAM = nsinstall
+OBJS = $(CSRCS:.c=.o)
+endif
+
+TARGETS = $(PROGRAM) $(PLSRCS:.pl=)
+
+# IMPORTANT: Disable NSBUILDROOT for this directory only, otherwise we have
+# a recursive rule for finding nsinstall and the perl scripts
+ifdef NSBUILDROOT
+override NSBUILDROOT :=
+endif
+
+include $(DEPTH)/config/rules.mk
+
+# Redefine MAKE_OBJDIR for just this directory
+define MAKE_OBJDIR
+if test ! -d $(@D); then rm -rf $(@D); mkdir $(@D); fi
+endef
+
+export:: $(TARGETS)
+install:: $(TARGETS)
diff --git a/config/SunOS5.8.mk b/config/SunOS5.8.mk
new file mode 100644
index 00000000..5019c182
--- /dev/null
+++ b/config/SunOS5.8.mk
@@ -0,0 +1,14 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Config stuff for SunOS5.8
+#
+
+SOL_CFLAGS = -D_SVID_GETTOD -DSOLARIS_55_OR_GREATER
+
+include $(DEPTH)/config/SunOS5.mk
diff --git a/config/SunOS5.8_i86pc.mk b/config/SunOS5.8_i86pc.mk
new file mode 100644
index 00000000..5019c182
--- /dev/null
+++ b/config/SunOS5.8_i86pc.mk
@@ -0,0 +1,14 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Config stuff for SunOS5.8
+#
+
+SOL_CFLAGS = -D_SVID_GETTOD -DSOLARIS_55_OR_GREATER
+
+include $(DEPTH)/config/SunOS5.mk
diff --git a/config/SunOS5.9.mk b/config/SunOS5.9.mk
new file mode 100644
index 00000000..bff14749
--- /dev/null
+++ b/config/SunOS5.9.mk
@@ -0,0 +1,14 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Config stuff for SunOS5.9
+#
+
+SOL_CFLAGS = -D_SVID_GETTOD -DSOLARIS_55_OR_GREATER
+
+include $(DEPTH)/config/SunOS5.mk
diff --git a/config/UNIX.mk b/config/UNIX.mk
new file mode 100644
index 00000000..35d0c36e
--- /dev/null
+++ b/config/UNIX.mk
@@ -0,0 +1,14 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# A small start on what nspr20/config did
+XP_DEFINE = -DXP_UNIX
+LIB_SUFFIX = a
+#
+DLL_SUFFIX = so
+AR = ar cr $@
+
diff --git a/config/WINNT5.0.mk b/config/WINNT5.0.mk
new file mode 100644
index 00000000..41c2cac6
--- /dev/null
+++ b/config/WINNT5.0.mk
@@ -0,0 +1,56 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Config stuff for WINNT 5.0
+#
+
+CC=cl
+CCC=cl
+LINK = link
+RANLIB = echo
+BSDECHO = echo
+
+OTHER_DIRT =
+GARBAGE = vc20.pdb
+
+ifdef DEBUG_RUNTIME
+RTLIBFLAGS:=-MDd
+else
+RTLIBFLAGS:=-MD
+endif
+
+PROCESSOR := $(shell uname -p)
+USE_KERNEL_THREADS=1
+_PR_USECPU=1
+ifeq ($(PROCESSOR), I386)
+CPU_ARCH = x386
+OS_CFLAGS = $(OPTIMIZER) -GT $(RTLIBFLAGS) -W3 -nologo -D_X86_ -Dx386 -D_WINDOWS -DWIN32 -DHW_THREADS
+else
+ifeq ($(PROCESSOR), MIPS)
+CPU_ARCH = MIPS
+#OS_CFLAGS = $(OPTIMIZER) $(RTLIBFLAGS) -W3 -nologo -D_MIPS_ -D_WINDOWS -DWIN32 -DHW_THREADS
+OS_CFLAGS = $(OPTIMIZER) $(RTLIBFLAGS) -W3 -nologo -D_WINDOWS -DWIN32 -DHW_THREADS
+else
+ifeq ($(PROCESSOR), ALPHA)
+CPU_ARCH = ALPHA
+OS_CFLAGS = $(OPTIMIZER) $(RTLIBFLAGS) -W3 -nologo -D_ALPHA_=1 -D_WINDOWS -DWIN32 -DHW_THREADS
+else
+CPU_ARCH = processor_is_undefined
+endif
+endif
+endif
+
+ifeq ($(SERVER_BUILD), 1)
+OS_CFLAGS += -DSERVER_BUILD
+endif
+
+OS_DLLFLAGS = -nologo -DLL -SUBSYSTEM:WINDOWS -MAP -PDB:NONE
+OS_LFLAGS = -nologo -PDB:NONE -INCREMENT:NO -SUBSYSTEM:console
+OS_LIBS = kernel32.lib user32.lib gdi32.lib winmm.lib wsock32.lib advapi32.lib
+
+OS_DEFS= SERVER_BUILD=$(SERVER_BUILD) NSPR_VERSION=$(VERSION) NS_PRODUCT=$(NS_PRODUCT)
diff --git a/config/common.mn b/config/common.mn
new file mode 100644
index 00000000..daae3872
--- /dev/null
+++ b/config/common.mn
@@ -0,0 +1,120 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+######################################################################
+### Comon Manifest File
+### Cross-platform defines used on all platforms (in theory)
+######################################################################
+
+# The VERSION_NUMBER is suffixed onto the end of the DLLs we ship.
+# Since the longest of these is 5 characters without the suffix,
+# be sure to not set VERSION_NUMBER to anything longer than 3
+# characters for Win16's sake.
+#
+# Also... If you change this value, there are several other places
+# you'll need to change (because they're not reached by this
+# variable):
+# sun-java/nsjava/nsjava32.def
+# sun-java/nsjava/nsjava16.def
+# sun-java/classsrc/sun/audio/AudioDevice.java
+# sun-java/classsrc/sun/awt/windows/WToolkit.java
+
+VERSION_NUMBER = 40
+
+ZIP_NAME = java_$(VERSION_NUMBER)
+JAR_NAME = java_$(VERSION_NUMBER).jar
+
+######################################################################
+### Cross-Platform Java Stuff
+######################################################################
+## java interpreter
+
+# get class files from the directory they are compiled to
+JAVA_CLASSPATH = $(JAVA_DESTPATH)
+
+JAVA_FLAGS = -classpath $(JAVA_CLASSPATH) -ms8m
+JAVA = $(JAVA_PROG) $(JAVA_FLAGS)
+
+JAVA_DEFINES = \
+ -DZIP_NAME=\"$(ZIP_NAME)\" \
+ -DJAR_NAME=\"$(JAR_NAME)\" \
+ -DJRTDLL=\"$(JRTDLL)\" \
+ -DMMDLL=\"$(MMDLL)\" \
+ -DAWTDLL=\"$(AWTDLL)\" \
+ -DJITDLL=\"$(JITDLL)\"
+
+######################################################################
+## javac
+
+# to run the compiler in the interpreter
+JAVAC_PROG = -ms8m -classpath $(JAVAC_ZIP) sun.tools.javac.Main
+JAVAC = $(JAVA_PROG) $(JAVAC_PROG) $(JAVAC_FLAGS)
+
+# std set of options passed to the compiler
+JAVAC_FLAGS = -classpath $(JAVAC_CLASSPATH) $(JAVA_OPTIMIZER) -d $(JAVA_DESTPATH)
+
+##
+## The canonical Java classpath is:
+## JAVA_DESTPATH, JAVA_SOURCEPATH, JAVA_LIBS
+##
+## appropriately delimited, in that order
+##
+JAVAC_CLASSPATH = $(JAVA_DESTPATH)$(PATH_SEPARATOR)$(JAVA_SOURCEPATH)
+
+######################################################################
+## javadoc
+
+# Rules to build java .html files from java source files
+
+JAVADOC_PROG = $(JAVA) sun.tools.javadoc.Main
+JAVADOC_FLAGS = -classpath $(JAVAC_CLASSPATH)
+JAVADOC = $(JAVADOC_PROG) $(JAVADOC_FLAGS)
+
+######################################################################
+## javah
+
+JAVAH_FLAGS = -classpath $(JAVA_CLASSPATH)
+JAVAH = $(JAVAH_PROG) $(JAVAH_FLAGS)
+
+######################################################################
+## jmc
+
+JMCSRCDIR = $(XPDIST)/_jmc
+JMC_PROG = $(JAVA) netscape.tools.jmc.Main
+JMC_CLASSPATH = $(JMCSRCDIR)$(PATH_SEPARATOR)$(JAVAC_CLASSPATH)
+JMC_FLAGS = -classpath $(JMC_CLASSPATH) -verbose
+JMC = $(JMC_PROG) $(JMC_FLAGS)
+
+######################################################################
+## zip
+
+ZIP = $(ZIP_PROG) $(ZIP_FLAGS)
+
+######################################################################
+## idl2java
+
+ORBTOOLS = $(DEPTH)/modules/iiop/tools/orbtools.zip
+ORB_CLASSPATH = $(ORBTOOLS)$(PATH_SEPARATOR)$(JAVA_CLASSPATH)
+
+IDL2JAVA_PROG = $(JAVA_PROG)
+IDL2JAVA_FLAGS = -classpath $(ORB_CLASSPATH) pomoco.tools.idl2java
+IDL2JAVA = $(IDL2JAVA_PROG) $(IDL2JAVA_FLAGS)
+
+######################################################################
+## lex and yacc
+
+JAVALEX_PROG = $(JAVA_PROG) -classpath $(ORB_CLASSPATH) sbktech.tools.jax.driver
+JAVALEX_FLAGS =
+JAVALEX = $(JAVALEX_PROG) $(JAVALEX_FLAGS)
+
+JAVACUP_PROG = $(JAVA_PROG) -classpath $(ORB_CLASSPATH) java_cup.Main
+JAVACUP_FLAGS =
+JAVACUP = $(JAVACUP_PROG) $(JAVACUP_FLAGS)
+
+######################################################################
+
+
diff --git a/config/config.mk b/config/config.mk
new file mode 100644
index 00000000..b962fae0
--- /dev/null
+++ b/config/config.mk
@@ -0,0 +1,520 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#! gmake
+
+include $(DEPTH)/config/common.mn
+
+#
+# Important internal static macros
+#
+OS_ARCH := $(subst /,_,$(shell uname -s))
+OS_TEST := $(shell uname -m)
+
+# Force the IRIX64 machines to use IRIX.
+ifeq ($(OS_ARCH),IRIX64)
+OS_ARCH := IRIX
+endif
+
+# Attempt to differentiate between SunOS 5.4 and x86 5.4
+ifeq ($(OS_TEST),i86pc)
+OS_RELEASE := $(shell uname -r)_$(OS_TEST)
+else
+OS_RELEASE := $(shell uname -r)
+endif
+
+ifeq ($(OS_ARCH),AIX)
+OS_RELEASE := $(shell uname -v).$(shell uname -r)
+endif
+
+# SINIX changes name to ReliantUNIX with 5.43
+ifeq ($(OS_ARCH),ReliantUNIX-N)
+OS_ARCH := ReliantUNIX
+OS_RELEASE := 5.4
+endif
+ifeq ($(OS_ARCH),SINIX-N)
+OS_ARCH := ReliantUNIX
+OS_RELEASE := 5.4
+endif
+
+# SVR5 (UnixWare[7])
+ifeq ($(OS_ARCH),UnixWare)
+# For now get the OS release for backward compatibility (UnixWare5)
+OS_RELEASE := $(shell uname -r)
+endif
+
+# Catch NCR butchering of SVR4
+ifeq ($(OS_ARCH),UNIX_SV)
+ifneq ($(findstring NCR, $(shell grep NCR /etc/bcheckrc | head -1 )),)
+OS_ARCH := NCR
+OS_RELEASE := $(shell uname -v)
+else # !NCR
+# Make UnixWare something human readable
+OS_ARCH := UNIXWARE
+# Check for UW2 using UDK, which looks like a Gemini (UnixWare[3,5,7]) build
+OS_RELEASE := $(shell $(DEPTH)/netsite/nsarch -f | sed 's/UnixWare //')
+ifeq ($(OS_RELEASE),5)
+OS_ARCH := UnixWare
+else # OS_RELEASE = 5
+# Get the OS release number, not 4.2
+OS_RELEASE := $(shell uname -v)
+ifeq ($(OS_RELEASE),2.1.2)
+OS_RELEASE := 2.1
+endif # OS_RELEASE = 2.1.2
+endif # OS_RELEASE = 5
+endif # !NCR
+endif # UNIX_SV
+
+
+ifeq ($(OS_ARCH),Linux)
+#
+# Handle FreeBSD 2.2-STABLE and Linux 2.0.30-osfmach3 and 2.2.14-5.0smp
+#
+ifeq (,$(filter-out Linux FreeBSD,$(NSOS_ARCH)))
+ OS_RELEASE := $(shell echo $(OS_RELEASE) | sed 's/-.*//')
+endif
+OS_RELEASE := $(basename $(OS_RELEASE))
+ ifeq (86,$(findstring 86,$(OS_TEST)))
+ CPU_TAG = _x86
+ else
+ CPU_TAG = _$(OS_TEST)
+ endif
+ ifeq ($(USE_LIBC),1)
+ LIBC_TAG = _libc
+ else
+ LIBC_TAG = _glibc
+ endif
+# always use pthreads
+ USE_PTHREADS = 1
+ ifeq ($(USE_PTHREADS),1)
+ IMPL_STRATEGY = _PTH
+ endif
+ ifeq ($(USE_EGCS),1)
+ COMPILER_TAG = _egcs
+ endif
+endif
+
+# Clean up SCO
+ifeq ($(OS_ARCH),SCO_SV)
+OS_ARCH := SCOOS
+ifeq (5.0,$(findstring 5.0,$(shell ls /var/opt/K/SCO/Unix)))
+OS_RELEASE := 5.0
+else
+OS_RELEASE := UNKNOWN
+endif
+endif
+
+# Furnish the extra libraries for using ld on OSF1
+ifeq ($(OS_ARCH),OSF1)
+LDEXTRA := -lcxx -lexc -lc
+#
+# Distinguish between OSF1 V4.0B and V4.0D
+#
+ifeq ($(OS_RELEASE),V4.0)
+ OS_VERSION := $(shell uname -v)
+ ifeq ($(OS_VERSION),564)
+ OS_RELEASE := V4.0B
+ endif
+ ifeq ($(OS_VERSION),878)
+ OS_RELEASE := V4.0D
+ endif
+endif
+else
+LDEXTRA :=
+endif
+
+# Relative pathname from top-of-tree to current source directory
+ifneq ($(OS_ARCH),WINNT)
+REVDEPTH := $(DEPTH)/config/revdepth
+SRCDIR := $(shell perl $(REVDEPTH).pl $(DEPTH))
+endif
+
+# define an include-at-most-once flag
+NS_CONFIG_MK = 1
+
+#
+# Default command macros; can be overridden in <arch>.mk.
+#
+AS = $(CC)
+ASFLAGS = $(CFLAGS)
+CCF = $(CC) $(CFLAGS)
+PURIFY = purify $(PURIFYOPTIONS)
+LINK_EXE = $(LINK) $(OS_LFLAGS) $(LFLAGS)
+LINK_DLL = $(LINK) $(OS_DLLFLAGS) $(DLLFLAGS)
+NFSPWD = $(DEPTH)/config/nfspwd
+
+ifeq ($(OS_ARCH),WINNT)
+RC = rc.exe
+XP_DEFINE = -DXP_PC
+LIB_SUFFIX = lib
+DLL_SUFFIX = dll
+AR = lib -NOLOGO -OUT:"$@"
+DLLFLAGS = $(XLFLAGS) -OUT:"$@"
+LFLAGS = $(OBJS) $(DEPLIBS) $(EXTRA_LIBS) -OUT:"$@"
+NSINSTALL = nsinstall
+INSTALL = $(NSINSTALL)
+else
+include $(DEPTH)/config/UNIX.mk
+endif
+
+ifdef BUILD_OPT
+ifeq ($(OS_ARCH),WINNT)
+OPTIMIZER = -O2
+XCFLAGS = $(LCFLAGS)
+XLFLAGS = $(LLFLAGS)
+else
+OPTIMIZER = -O
+JAVA_OPTIMIZER = -O
+DEFINES = -UDEBUG -DNDEBUG -DTRIMMED
+endif
+OBJDIR_TAG = _OPT
+else
+ifeq ($(OS_ARCH),WINNT)
+OPTIMIZER = -Od -Z7
+LDFLAGS = -DEBUG
+
+XCFLAGS = $(LCFLAGS)
+XLFLAGS = -DEBUG $(LLFLAGS)
+XBCFLAGS = -FR$*
+JAVA_OPTIMIZER = -Od -Z7
+else
+ifeq ($(ARCH), ReliantUNIX)
+OPTIMIZER = -gdwarf
+JAVA_OPTIMIZER = -gdwarf
+else
+OPTIMIZER = -g
+JAVA_OPTIMIZER = -g
+endif
+ifeq ($(OS_ARCH),OSF1)
+DEFINES = -DDEBUG_$(shell whoami) -DTRACING
+else
+DEFINES = -DDEBUG -UNDEBUG -DDEBUG_$(shell whoami) -DTRACING
+endif
+endif
+OBJDIR_TAG = _DBG
+endif
+
+LIBNT = $(DIST)/lib/libnt.$(LIB_SUFFIX)
+LIBAWT = $(DIST)/lib/libawt.$(LIB_SUFFIX)
+LIBMMEDIA = $(DIST)/lib/libmmedia.$(LIB_SUFFIX)
+LIBNSPR = $(DIST)/lib/libnspr.$(LIB_SUFFIX)
+PURELIBNSPR = $(DIST)/lib/libpurenspr.$(LIB_SUFFIX)
+
+ifeq ($(OS_ARCH),WINNT)
+LIBNSJAVA = $(DIST)/lib/jrt3221.$(LIB_SUFFIX)
+else
+LIBNSJAVA = $(DIST)/lib/nsjava32.$(LIB_SUFFIX)
+endif
+
+
+# XXX For now, we're including $(DEPTH)/include directly instead of
+# getting this stuff from dist. This stuff is old and will eventually
+# be put in the library directories where it belongs so that it can
+# get exported to dist properly.
+INCLUDES = $(LOCAL_PREINCLUDES) -I$(DEPTH)/include $(LOCAL_INCLUDES)
+
+CFLAGS = $(XP_DEFINE) $(OPTIMIZER) $(OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS)
+# For purify
+NOMD_CFLAGS = $(XP_DEFINE) $(OPTIMIZER) $(NOMD_OS_CFLAGS) $(DEFINES) $(INCLUDES) $(XCFLAGS)
+
+#
+# To build on SunOS5.8 when some SunOS5.8 components or config
+# files are missing, just pretend you're on SunOS5.6 by setting
+# NSOS_RELEASE_OVERRIDE=5.6
+#
+ifdef NSOS_RELEASE_OVERRIDE
+OS_RELEASE := $(NSOS_RELEASE_OVERRIDE)
+endif
+
+include $(DEPTH)/config/$(OS_ARCH)$(OS_RELEASE).mk
+
+OS_CONFIG := $(OS_ARCH)$(OS_RELEASE)
+
+include $(DEPTH)/config/$(OS_CONFIG).mk
+
+# now take care of default GCC (rus@5/5/97)
+
+ifdef NS_USE_GCC
+# if gcc-settings are redefined already - don't touch it
+#
+ifeq (,$(findstring gcc, $(CC)))
+CC = gcc
+CCC = g++
+CXX = g++
+# always use -fpic - some makefiles are still broken and don't distinguish
+# situation when they build shared and static libraries
+CFLAGS += -fpic -Wall -DNS_USE_GCC $(GCC_FLAGS_EXTRA)
+OS_LIBS += -L/usr/local/lib -lstdc++ -lg++ -lgcc
+endif
+endif
+###
+
+# Name of the binary code directories
+ifeq ($(OS_ARCH),WINNT)
+ifneq ($(PROCESSOR_ARCHITECTURE),x86)
+OBJDIR_NAME = $(OS_CONFIG)$(PROCESSOR_ARCHITECTURE)$(OBJDIR_TAG).OBJ
+else
+OBJDIR_NAME = $(OS_CONFIG)$(OBJDIR_TAG).OBJ
+endif
+else # WINNT
+ifeq ($(OS_ARCH),Linux)
+OBJDIR_NAME = $(OS_CONFIG)$(CPU_TAG)$(COMPILER_TAG)$(LIBC_TAG)$(IMPL_STRATEGY)$(OBJDIR_TAG).OBJ
+else
+ifeq ($(OS_ARCH), IRIX)
+ ifeq ($(USE_PTHREADS), 1)
+ ifeq ($(USE_N32), 1)
+ OBJDIR_NAME = $(OS_CONFIG)_n32_PTH$(OBJDIR_TAG).OBJ
+ else
+ OBJDIR_NAME = $(OS_CONFIG)_PTH$(OBJDIR_TAG).OBJ
+ endif
+ else
+ OBJDIR_NAME = $(OS_CONFIG)$(OBJDIR_TAG).OBJ
+ endif
+else
+ OBJDIR_NAME = $(OS_CONFIG)$(OBJDIR_TAG).OBJ
+endif # IRIX
+endif # Linux
+endif # WINNT
+
+# Figure out where the binary code lives. It either lives in the src
+# tree (NSBUILDROOT is undefined) or somewhere else.
+ifdef NSBUILDROOT
+BUILD = $(NSBUILDROOT)/$(OBJDIR_NAME)/build
+OBJDIR = $(BUILD)/$(SRCDIR)
+XPDIST = $(NSBUILDROOT)
+DIST = $(NSBUILDROOT)/$(OBJDIR_NAME)/dist
+else
+BUILD = $(OBJDIR_NAME)
+OBJDIR = $(OBJDIR_NAME)
+XPDIST = $(DEPTH)/dist
+DIST = $(DEPTH)/dist/$(OBJDIR_NAME)
+endif
+
+# all public include files go in subdirectories of PUBLIC:
+PUBLIC = $(XPDIST)/public
+
+VPATH = $(OBJDIR)
+DEPENDENCIES = $(OBJDIR)/.md
+
+# Personal makefile customizations go in these optional make include files.
+MY_CONFIG = $(DEPTH)/config/myconfig.mk
+MY_RULES = $(DEPTH)/config/myrules.mk
+
+-include $(MY_CONFIG)
+
+######################################################################
+
+# Specify that we are building a client.
+# This will instruct the cross platform libraries to
+# include all the client specific cruft.
+ifndef SERVER_BUILD
+ifndef LIVEWIRE
+DEFINES += -DMOZILLA_CLIENT -DNETSCAPE
+endif
+else
+DEFINES += -DSERVER_BUILD
+endif
+DEFINES += -DNETSCAPE
+
+# Now test variables that might have been set or overridden by $(MY_CONFIG).
+
+# if ((BUILD_EDITOR || BUILD_EDT) && !NO_EDITOR) -> -DEDITOR is defined
+ifndef NO_EDITOR
+ifdef BUILD_EDITOR
+OBJDIR_TAG := $(OBJDIR_TAG)_EDT
+DEFINES += -DEDITOR -DGOLD
+# This is the product classification not the feature classification.
+# It effects things like where are the release notes, etc..
+BUILD_GOLD = yea
+else
+# We ought to get rid of this now that BUILD_EDITOR has replaced it.
+ifdef BUILD_EDT
+OBJDIR_TAG := $(OBJDIR_TAG)_EDT
+DEFINES += -DEDITOR -DGOLD
+BUILD_EDITOR = yea
+endif
+endif
+endif
+
+# Build layers by default
+ifndef NO_LAYERS
+DEFINES += -DLAYERS
+endif
+
+# if (BUILD_EDITOR_UI && !NO_EDITOR_UI) -> -DEDITOR_UI is defined
+ifdef BUILD_EDITOR_UI
+ifndef NO_EDITOR_UI
+DEFINES += -DEDITOR_UI
+endif
+endif
+
+ifdef BUILD_DEBUG_GC
+DEFINES += -DDEBUG_GC
+endif
+
+ifdef BUILD_UNIX_PLUGINS
+# UNIX_EMBED Should not be needed. For now these two defines go
+# together until I talk with jg. --dp
+DEFINES += -DUNIX_EMBED -DX_PLUGINS
+endif
+
+ifndef NO_UNIX_LDAP
+DEFINES += -DUNIX_LDAP
+endif
+
+#
+# Platform dependent switching off of NSPR, JAVA and MOCHA
+#
+ifndef NO_NSPR
+DEFINES += -DNSPR -DNSPR20
+endif
+
+ifndef NO_JAVA
+DEFINES += -DJAVA
+endif
+
+ifeq ($(LW_JAVA), 1)
+DEFINES += -DJAVA
+endif
+
+ifndef NO_MOCHA
+DEFINES += -DMOCHA
+endif
+
+ifdef FORTEZZA
+DEFINES += -DFORTEZZA
+endif
+
+######################################################################
+
+GARBAGE = $(DEPENDENCIES) core
+
+ifneq ($(OS_ARCH),WINNT)
+NSINSTALL = $(DEPTH)/config/$(OBJDIR_NAME)/nsinstall
+
+ifeq ($(NSDISTMODE),copy)
+# copy files, but preserve source mtime
+INSTALL = $(NSINSTALL) -t
+else
+ifeq ($(NSDISTMODE),absolute_symlink)
+# install using absolute symbolic links
+INSTALL = $(NSINSTALL) -L `$(NFSPWD)`
+else
+# install using relative symbolic links
+INSTALL = $(NSINSTALL) -R
+endif
+endif
+endif
+
+ifndef PLATFORM_HOSTS
+PLATFORM_HOSTS = \
+ atm \
+ bsdi \
+ diva \
+ gunwale \
+ openwound \
+ server2 \
+ server3 \
+ server9 \
+ zot \
+ $(NULL)
+endif
+
+######################################################################
+
+# always copy files for the sdk
+SDKINSTALL = $(NSINSTALL) -t
+
+ifndef SDK
+SDK = $(DEPTH)/dist/sdk
+endif
+
+######################################################################
+### Java Stuff
+######################################################################
+## java interpreter
+
+JAVA_PROG = java # from the ether
+
+# Let user over-ride CLASSPATH from environment
+#ifdef xCLASSPATH # bad idea
+#JAVA_CLASSPATH = $(CLASSPATH)
+#else
+# keep sun-java/classsrc until bootstrapped
+#JAVA_CLASSPATH = $(XPDIST)/classes:$(DEPTH)/sun-java/classsrc
+#endif
+
+#JAVA_FLAGS = -classpath $(JAVA_CLASSPATH) -ms8m
+#JAVA = $(JAVA_PROG) $(JAVA_FLAGS)
+
+######################################################################
+## java compiler
+# XXX - ram included from common.mn
+#JAVAC_PROG = javac # from the ether
+#JAVAC_CLASSPATH = $(JAVA_CLASSPATH):/usr/local/netscape/java/lib/javac.zip
+#JAVAC_FLAGS = -classpath $(JAVAC_CLASSPATH) $(JAVA_OPTIMIZER)
+#JAVAC = $(JAVAC_PROG) $(JAVAC_FLAGS)
+
+PATH_SEPARATOR = :
+JAVAC_ZIP = /usr/local/netscape/java/lib/javac.zip
+
+#
+# The canonical classpath for building java libraries
+# includes these two entries first, then any additional zips
+# or directories
+#
+# see "JAVAC_CLASSPATH" in common.mn
+#
+
+# where the bytecode will go
+JAVA_DESTPATH = $(XPDIST)/classes
+# where the sources for the module you are compiling are
+# default is sun-java/classsrc, override for other modules
+JAVA_SOURCEPATH = $(DEPTH)/sun-java/classsrc
+
+######################################################################
+## javadoc
+
+# Rules to build java .html files from java source files
+
+JAVADOC_PROG = $(JAVA) sun.tools.javadoc.Main
+JAVADOC_FLAGS = -classpath $(JAVAC_CLASSPATH)
+JAVADOC = $(JAVADOC_PROG) $(JAVADOC_FLAGS)
+
+######################################################################
+## javah
+
+ifndef JAVAH_IN_JAVA
+JAVAH_PROG = $(DIST)/bin/javah
+else
+JAVAH_PROG = $(JAVA) netscape.tools.jric.Main
+endif
+JAVAH_FLAGS = -classpath $(JAVA_CLASSPATH)
+JAVAH = $(JAVAH_PROG) $(JAVAH_FLAGS)
+
+######################################################################
+## jmc
+
+JMCSRCDIR = $(XPDIST)/_jmc
+JMC_PROG = $(JAVA) netscape.tools.jmc.Main
+JMC_CLASSPATH = $(JMCSRCDIR):$(JAVAC_CLASSPATH)
+JMC_FLAGS = -classpath $(JMC_CLASSPATH) -verbose
+JMC = $(JMC_PROG) $(JMC_FLAGS)
+
+######################################################################
+## zip
+
+ZIP_PROG = zip
+ZIP_FLAGS = -0rq
+ZIP = $(ZIP_PROG) $(ZIP_FLAGS)
+
+######################################################################
+JRTDLL = libjrt.$(DLL_SUFFIX)
+MMDLL = libmm32$(VERSION_NUMBER).$(DLL_SUFFIX)
+AWTDLL = libawt.$(DLL_SUFFIX)
+JITDLL = libjit
+
diff --git a/config/nfspwd.pl b/config/nfspwd.pl
new file mode 100644
index 00000000..a4d1645d
--- /dev/null
+++ b/config/nfspwd.pl
@@ -0,0 +1,21 @@
+#! /usr/local/bin/perl
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+require "fastcwd.pl";
+
+$_ = &fastcwd;
+if (m@^/[uh]/@o || s@^/tmp_mnt/@/@o) {
+ print("$_\n");
+} elsif ((($user, $rest) = m@^/usr/people/(\w+)/(.*)@o)
+ && readlink("/u/$user") eq "/usr/people/$user") {
+ print("/u/$user/$rest\n");
+} else {
+ chop($host = `hostname`);
+ print("/h/$host$_\n");
+}
diff --git a/config/nsinstall.c b/config/nsinstall.c
new file mode 100644
index 00000000..0d8a537a
--- /dev/null
+++ b/config/nsinstall.c
@@ -0,0 +1,305 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+** Netscape portable install command.
+**
+** Brendan Eich, 7/20/95
+*/
+#include <stdio.h> /* OSF/1 requires this before grp.h, so put it first */
+#include <assert.h>
+#include <fcntl.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <utime.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "pathsub.h"
+
+#define HAVE_LCHOWN
+
+#if defined(AIXV3) || defined(BSDI) || defined(HPUX) || defined(LINUX) || defined(SUNOS4) || defined(SCO) || defined(SNI)
+#undef HAVE_LCHOWN
+#endif
+
+#ifdef LINUX
+# include <getopt.h>
+#endif
+
+#if defined(SCO) || defined(UNIXWARE) || defined(SNI) || defined (NCR) || defined(UnixWare)
+#if !defined(S_ISLNK) && defined(S_IFLNK)
+#define S_ISLNK(a) (((a) & S_IFMT) == S_IFLNK)
+#endif
+#endif
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-C cwd] [-L linkprefix] [-m mode] [-o owner] [-g group]\n"
+ " %*s [-DdltR] file [file ...] directory\n",
+ program, strlen(program), "");
+ exit(2);
+}
+
+static int
+mkdirs(char *path, mode_t mode)
+{
+ char *cp;
+ struct stat sb;
+
+ while (*path == '/' && path[1] == '/')
+ path++;
+ while ((cp = strrchr(path, '/')) && cp[1] == '\0')
+ *cp = '\0';
+ if (cp && cp != path) {
+ *cp = '\0';
+ if ((lstat(path, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
+ mkdirs(path, mode) < 0) {
+ return -1;
+ }
+ *cp = '/';
+ }
+ return mkdir(path, mode);
+}
+
+static uid_t
+touid(char *owner)
+{
+ struct passwd *pw;
+ uid_t uid;
+ char *cp;
+
+ pw = getpwnam(owner);
+ if (pw)
+ return pw->pw_uid;
+ uid = strtol(owner, &cp, 0);
+ if (uid == 0 && cp == owner)
+ fail("cannot find uid for %s", owner);
+ return uid;
+}
+
+static gid_t
+togid(char *group)
+{
+ struct group *gr;
+ gid_t gid;
+ char *cp;
+
+ gr = getgrnam(group);
+ if (gr)
+ return gr->gr_gid;
+ gid = strtol(group, &cp, 0);
+ if (gid == 0 && cp == group)
+ fail("cannot find gid for %s", group);
+ return gid;
+}
+
+int
+main(int argc, char **argv)
+{
+ int onlydir, dodir, dolink, dorelsymlink, dotimes;
+ mode_t mode;
+ char *linkprefix, *owner, *group;
+ int opt, len, lplen, tdlen, bnlen, exists, fromfd, tofd, cc, wc;
+ char *cp, *cwd, *todir, *toname, *name, *base, *linkname;
+ uid_t uid;
+ gid_t gid;
+ char *bp, buf[BUFSIZ];
+ struct stat sb, tosb;
+ struct utimbuf utb;
+
+ program = argv[0];
+ cwd = 0;
+ onlydir = dodir = dolink = dorelsymlink = dotimes = 0;
+ mode = 0755;
+ linkprefix = owner = group = 0;
+
+ while ((opt = getopt(argc, argv, "C:DdlL:Rm:o:g:t")) != EOF) {
+ switch (opt) {
+ case 'C':
+ cwd = optarg;
+ break;
+ case 'D':
+ onlydir = 1;
+ break;
+ case 'd':
+ dodir = 1;
+ break;
+ case 'l':
+ dolink = 1;
+ break;
+ case 'L':
+ linkprefix = optarg;
+ lplen = strlen(linkprefix);
+ dolink = 1;
+ break;
+ case 'R':
+ dolink = dorelsymlink = 1;
+ break;
+ case 'm':
+ mode = strtoul(optarg, &cp, 8);
+ if (mode == 0 && cp == optarg)
+ usage();
+ break;
+ case 'o':
+ owner = optarg;
+ break;
+ case 'g':
+ group = optarg;
+ break;
+ case 't':
+ dotimes = 1;
+ break;
+ default:
+ usage();
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+ if (argc < 2 - onlydir)
+ usage();
+
+ todir = argv[argc-1];
+ if ((stat(todir, &sb) < 0 || !S_ISDIR(sb.st_mode)) &&
+ mkdirs(todir, 0777) < 0) {
+ fail("cannot make directory %s", todir);
+ }
+ if (onlydir)
+ return 0;
+
+ if (!cwd)
+ cwd = getcwd(0, PATH_MAX);
+ xchdir(todir);
+ todir = getcwd(0, PATH_MAX);
+ tdlen = strlen(todir);
+ xchdir(cwd);
+ tdlen = strlen(todir);
+
+ uid = owner ? touid(owner) : -1;
+ gid = group ? togid(group) : -1;
+
+ while (--argc > 0) {
+ name = *argv++;
+ len = strlen(name);
+ base = xbasename(name);
+ bnlen = strlen(base);
+ toname = xmalloc(tdlen + 1 + bnlen + 1);
+ sprintf(toname, "%s/%s", todir, base);
+ exists = (lstat(toname, &tosb) == 0);
+
+ if (dodir) {
+ /* -d means create a directory, always */
+ if (exists && !S_ISDIR(tosb.st_mode)) {
+ (void) unlink(toname);
+ exists = 0;
+ }
+ if (!exists && mkdir(toname, mode) < 0)
+ fail("cannot make directory %s", toname);
+ if ((owner || group) && chown(toname, uid, gid) < 0)
+ fail("cannot change owner of %s", toname);
+ } else if (dolink) {
+ if (*name == '/') {
+ /* source is absolute pathname, link to it directly */
+ linkname = 0;
+ } else {
+ if (linkprefix) {
+ /* -L implies -l and prefixes names with a $cwd arg. */
+ len += lplen + 1;
+ linkname = xmalloc(len + 1);
+ sprintf(linkname, "%s/%s", linkprefix, name);
+ } else if (dorelsymlink) {
+ /* Symlink the relative path from todir to source name. */
+ linkname = xmalloc(PATH_MAX);
+
+ if (*todir == '/') {
+ /* todir is absolute: skip over common prefix. */
+ lplen = relatepaths(todir, cwd, linkname);
+ strcpy(linkname + lplen, name);
+ } else {
+ /* todir is named by a relative path: reverse it. */
+ reversepath(todir, name, len, linkname);
+ xchdir(cwd);
+ }
+
+ len = strlen(linkname);
+ }
+ name = linkname;
+ }
+
+ /* Check for a pre-existing symlink with identical content. */
+ if (exists &&
+ (!S_ISLNK(tosb.st_mode) ||
+ readlink(toname, buf, sizeof buf) != len ||
+ strncmp(buf, name, len) != 0)) {
+ (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
+ exists = 0;
+ }
+ if (!exists && symlink(name, toname) < 0)
+ fail("cannot make symbolic link %s", toname);
+#ifdef HAVE_LCHOWN
+ if ((owner || group) && lchown(toname, uid, gid) < 0)
+ fail("cannot change owner of %s", toname);
+#endif
+
+ if (linkname) {
+ free(linkname);
+ linkname = 0;
+ }
+ } else {
+ /* Copy from name to toname, which might be the same file. */
+ fromfd = open(name, O_RDONLY);
+ if (fromfd < 0 || fstat(fromfd, &sb) < 0)
+ fail("cannot access %s", name);
+ if (exists && (!S_ISREG(tosb.st_mode) || access(toname, W_OK) < 0))
+ (void) (S_ISDIR(tosb.st_mode) ? rmdir : unlink)(toname);
+ tofd = open(toname, O_CREAT | O_WRONLY, 0666);
+ if (tofd < 0)
+ fail("cannot create %s", toname);
+
+ bp = buf;
+ while ((cc = read(fromfd, bp, sizeof buf)) > 0) {
+ while ((wc = write(tofd, bp, cc)) > 0) {
+ if ((cc -= wc) == 0)
+ break;
+ bp += wc;
+ }
+ if (wc < 0)
+ fail("cannot write to %s", toname);
+ }
+ if (cc < 0)
+ fail("cannot read from %s", name);
+
+ if (ftruncate(tofd, sb.st_size) < 0)
+ fail("cannot truncate %s", toname);
+ if (dotimes) {
+ utb.actime = sb.st_atime;
+ utb.modtime = sb.st_mtime;
+ if (utime(toname, &utb) < 0)
+ fail("cannot set times of %s", toname);
+ }
+ if (fchmod(tofd, mode) < 0)
+ fail("cannot change mode of %s", toname);
+ if ((owner || group) && fchown(tofd, uid, gid) < 0)
+ fail("cannot change owner of %s", toname);
+
+ /* Must check for delayed (NFS) write errors on close. */
+ if (close(tofd) < 0)
+ fail("cannot write to %s", toname);
+ close(fromfd);
+ }
+
+ free(toname);
+ }
+
+ free(cwd);
+ free(todir);
+ return 0;
+}
diff --git a/config/pathsub.c b/config/pathsub.c
new file mode 100644
index 00000000..6e5cfd20
--- /dev/null
+++ b/config/pathsub.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 **/
+/*
+** Pathname subroutines.
+**
+** Brendan Eich, 8/29/95
+*/
+#include <assert.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "pathsub.h"
+#ifdef USE_REENTRANT_LIBC
+#include <libc_r.h>
+#endif /* USE_REENTRANT_LIBC */
+
+char *program;
+
+void
+fail(char *format, ...)
+{
+ int error;
+ va_list ap;
+
+#ifdef USE_REENTRANT_LIBC
+ R_STRERROR_INIT_R();
+#endif
+
+ error = errno;
+ fprintf(stderr, "%s: ", program);
+ va_start(ap, format);
+ vfprintf(stderr, format, ap);
+ va_end(ap);
+ if (error)
+
+#ifdef USE_REENTRANT_LIBC
+ R_STRERROR_R(errno);
+ fprintf(stderr, ": %s", r_strerror_r);
+#else
+ fprintf(stderr, ": %s", strerror(errno));
+#endif
+
+ putc('\n', stderr);
+ exit(1);
+}
+
+char *
+getcomponent(char *path, char *name)
+{
+ if (*path == '\0')
+ return 0;
+ if (*path == '/') {
+ *name++ = '/';
+ } else {
+ do {
+ *name++ = *path++;
+ } while (*path != '/' && *path != '\0');
+ }
+ *name = '\0';
+ while (*path == '/')
+ path++;
+ return path;
+}
+
+#ifdef UNIXWARE
+/* Sigh. The static buffer in Unixware's readdir is too small. */
+struct dirent * readdir(DIR *d)
+{
+ static struct dirent *buf = NULL;
+#define MAX_PATH_LEN 1024
+
+
+ if(buf == NULL)
+ buf = (struct dirent *) malloc(sizeof(struct dirent) + MAX_PATH_LEN)
+;
+ return(readdir_r(d, buf));
+}
+#endif
+
+char *
+ino2name(ino_t ino, char *dir)
+{
+ DIR *dp;
+ struct dirent *ep;
+ char *name;
+
+ dp = opendir("..");
+ if (!dp)
+ fail("cannot read parent directory");
+ for (;;) {
+ if (!(ep = readdir(dp)))
+ fail("cannot find current directory");
+ if (ep->d_ino == ino)
+ break;
+ }
+ name = xstrdup(ep->d_name);
+ closedir(dp);
+ return name;
+}
+
+void *
+xmalloc(size_t size)
+{
+ void *p = malloc(size);
+ if (!p)
+ fail("cannot allocate %u bytes", size);
+ return p;
+}
+
+char *
+xstrdup(char *s)
+{
+ return strcpy(xmalloc(strlen(s) + 1), s);
+}
+
+char *
+xbasename(char *path)
+{
+ char *cp;
+
+ while ((cp = strrchr(path, '/')) && cp[1] == '\0')
+ *cp = '\0';
+ if (!cp) return path;
+ return cp + 1;
+}
+
+void
+xchdir(char *dir)
+{
+ if (chdir(dir) < 0)
+ fail("cannot change directory to %s", dir);
+}
+
+int
+relatepaths(char *from, char *to, char *outpath)
+{
+ char *cp, *cp2;
+ int len;
+ char buf[NAME_MAX];
+
+ assert(*from == '/' && *to == '/');
+ for (cp = to, cp2 = from; *cp == *cp2; cp++, cp2++)
+ if (*cp == '\0')
+ break;
+ while (cp[-1] != '/')
+ cp--, cp2--;
+ if (cp - 1 == to) {
+ /* closest common ancestor is /, so use full pathname */
+ len = strlen(strcpy(outpath, to));
+ if (outpath[len] != '/') {
+ outpath[len++] = '/';
+ outpath[len] = '\0';
+ }
+ } else {
+ len = 0;
+ while ((cp2 = getcomponent(cp2, buf)) != 0) {
+ strcpy(outpath + len, "../");
+ len += 3;
+ }
+ while ((cp = getcomponent(cp, buf)) != 0) {
+ sprintf(outpath + len, "%s/", buf);
+ len += strlen(outpath + len);
+ }
+ }
+ return len;
+}
+
+void
+reversepath(char *inpath, char *name, int len, char *outpath)
+{
+ char *cp, *cp2;
+ char buf[NAME_MAX];
+ struct stat sb;
+
+ cp = strcpy(outpath + PATH_MAX - (len + 1), name);
+ cp2 = inpath;
+ while ((cp2 = getcomponent(cp2, buf)) != 0) {
+ if (strcmp(buf, ".") == 0)
+ continue;
+ if (strcmp(buf, "..") == 0) {
+ if (stat(".", &sb) < 0)
+ fail("cannot stat current directory");
+ name = ino2name(sb.st_ino, "..");
+ len = strlen(name);
+ cp -= len + 1;
+ strcpy(cp, name);
+ cp[len] = '/';
+ free(name);
+ xchdir("..");
+ } else {
+ cp -= 3;
+ strncpy(cp, "../", 3);
+ xchdir(buf);
+ }
+ }
+ strcpy(outpath, cp);
+}
diff --git a/config/pathsub.h b/config/pathsub.h
new file mode 100644
index 00000000..2e7a0554
--- /dev/null
+++ b/config/pathsub.h
@@ -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 **/
+#ifndef pathsub_h___
+#define pathsub_h___
+/*
+** Pathname subroutines.
+**
+** Brendan Eich, 8/29/95
+*/
+#include <limits.h>
+#include <sys/types.h>
+
+#if SUNOS4
+#include "../nspr/include/sunos4.h"
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
+
+/*
+ * Just prevent stupidity
+ */
+#undef NAME_MAX
+#define NAME_MAX 256
+
+extern char *program;
+
+extern void fail(char *format, ...);
+extern char *getcomponent(char *path, char *name);
+extern char *ino2name(ino_t ino, char *dir);
+extern void *xmalloc(size_t size);
+extern char *xstrdup(char *s);
+extern char *xbasename(char *path);
+extern void xchdir(char *dir);
+
+/* Relate absolute pathnames from and to returning the result in outpath. */
+extern int relatepaths(char *from, char *to, char *outpath);
+
+/* XXX changes current working directory -- caveat emptor */
+extern void reversepath(char *inpath, char *name, int len, char *outpath);
+
+#endif /* pathsub_h___ */
diff --git a/config/revdepth-nt.pl b/config/revdepth-nt.pl
new file mode 100644
index 00000000..8b8a85f5
--- /dev/null
+++ b/config/revdepth-nt.pl
@@ -0,0 +1,19 @@
+#! /usr/local/bin/perl
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+require "/ns/config/fastcwd.pl";
+
+$cur = &fastcwd;
+chdir($ARGV[0]);
+$newcur = &fastcwd;
+$newcurlen = length($newcur);
+
+# Skip common separating / unless $newcur is "/"
+$cur = substr($cur, $newcurlen + ($newcurlen > 1));
+print $cur;
diff --git a/config/revdepth.pl b/config/revdepth.pl
new file mode 100644
index 00000000..b38f6f3d
--- /dev/null
+++ b/config/revdepth.pl
@@ -0,0 +1,22 @@
+#! /usr/local/bin/perl
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+unshift(@INC, '/usr/lib/perl');
+unshift(@INC, '/usr/local/lib/perl');
+
+require "fastcwd.pl";
+
+$cur = &fastcwd;
+chdir($ARGV[0]);
+$newcur = &fastcwd;
+$newcurlen = length($newcur);
+
+# Skip common separating / unless $newcur is "/"
+$cur = substr($cur, $newcurlen + ($newcurlen > 1));
+print $cur;
diff --git a/config/rules.mk b/config/rules.mk
new file mode 100644
index 00000000..c65f49f2
--- /dev/null
+++ b/config/rules.mk
@@ -0,0 +1,707 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+################################################################################
+# Wow this is complicated! The story is that we now have a 4 pass build process:
+#
+# Pass 1. export - Create generated headers and stubs. Publish public headers to
+# dist/<arch>/include.
+#
+# Pass 2. libs - Create libraries. Publish libraries to dist/<arch>/lib.
+#
+# Pass 3. all - Create programs.
+#
+# Pass 4. install - Publish programs to dist/<arch>/bin.
+#
+# Parameters to this makefile (set these before including):
+#
+# a)
+# TARGETS -- the target to create
+# (defaults to $LIBRARY $PROGRAM)
+# b)
+# DIRS -- subdirectories for make to recurse on
+# (the 'all' rule builds $TARGETS $DIRS)
+# c)
+# CSRCS, CPPSRCS -- .c and .cpp files to compile
+# (used to define $OBJS)
+# d)
+# PROGRAM -- the target program name to create from $OBJS
+# ($OBJDIR automatically prepended to it)
+# e)
+# LIBRARY -- the target library name to create from $OBJS
+# ($OBJDIR automatically prepended to it)
+# f)
+# JSRCS -- java source files to compile into class files
+# (if you don't specify this it will default to *.java)
+# PACKAGE -- the package to put the .class files into
+# (e.g. netscape/applet)
+# JMC_EXPORT -- java files to be exported for use by JMC_GEN
+# (this is a list of Class names)
+# g)
+# JRI_GEN -- files to run through javah to generate headers and stubs
+# (output goes into the _jri sub-dir)
+# h)
+# JMC_GEN -- files to run through jmc to generate headers and stubs
+# (output goes into the _jmc sub-dir)
+#
+################################################################################
+
+#
+# Common rules used by lots of makefiles...
+#
+ifndef NS_CONFIG_MK
+include $(DEPTH)/config/config.mk
+endif
+
+ifdef PROGRAM
+PROGRAM := $(addprefix $(OBJDIR)/, $(PROGRAM))
+endif
+
+ifndef LIBRARY
+ifdef LIBRARY_NAME
+LIBRARY := lib$(LIBRARY_NAME).$(LIB_SUFFIX)
+endif
+endif
+
+ifdef LIBRARY
+LIBRARY := $(addprefix $(OBJDIR)/, $(LIBRARY))
+ifdef MKSHLIB
+SHARED_LIBRARY := $(LIBRARY:.$(LIB_SUFFIX)=$(DLL_PRESUF).$(DLL_SUFFIX))
+endif
+endif
+
+ifndef TARGETS
+TARGETS = $(LIBRARY) $(SHARED_LIBRARY) $(PROGRAM)
+endif
+
+ifndef OBJS
+OBJS = $(JRI_STUB_CFILES) $(addsuffix .o, $(JMC_GEN)) $(CSRCS:.c=.o) $(CPPSRCS:.cpp=.o) $(ASFILES:.s=.o)
+endif
+
+ifdef OBJS
+OBJS := $(addprefix $(OBJDIR)/, $(OBJS))
+endif
+
+ifdef REQUIRES
+MODULE_PREINCLUDES = $(addprefix -I$(XPDIST)/public/, $(REQUIRES))
+endif
+
+ifeq ($(OS_ARCH),WINNT)
+ifdef DLL
+DLL := $(addprefix $(OBJDIR)/, $(DLL))
+LIB := $(addprefix $(OBJDIR)/, $(LIB))
+endif
+endif
+define MAKE_OBJDIR
+if test ! -d $(@D); then rm -rf $(@D); $(NSINSTALL) -D $(@D); fi
+endef
+
+ALL_TRASH = $(TARGETS) $(OBJS) $(OBJDIR) LOGS TAGS $(GARBAGE) \
+ $(NOSUCHFILE) $(JDK_HEADER_CFILES) $(JDK_STUB_CFILES) \
+ $(JRI_HEADER_CFILES) $(JRI_STUB_CFILES) $(JMC_STUBS) \
+ $(JMC_HEADERS) $(JMC_EXPORT_FILES) so_locations \
+ _gen _jmc _jri _stubs \
+ $(wildcard $(JAVA_DESTPATH)/$(PACKAGE)/*.class)
+
+ifdef JDIRS
+ALL_TRASH += $(addprefix $(JAVA_DESTPATH)/,$(JDIRS))
+endif
+
+ifdef NSBUILDROOT
+JDK_GEN_DIR = $(XPDIST)/_gen
+JMC_GEN_DIR = $(XPDIST)/_jmc
+JRI_GEN_DIR = $(XPDIST)/_jri
+JDK_STUB_DIR = $(XPDIST)/_stubs
+else
+JDK_GEN_DIR = _gen
+JMC_GEN_DIR = _jmc
+JRI_GEN_DIR = _jri
+JDK_STUB_DIR = _stubs
+endif
+
+#
+# If this is an "official" build, try to build everything.
+# I.e., don't exit on errors.
+#
+ifdef BUILD_OFFICIAL
+EXIT_ON_ERROR = +e
+CLICK_STOPWATCH = date
+else
+EXIT_ON_ERROR = -e
+CLICK_STOPWATCH = true
+endif
+
+
+################################################################################
+
+ifdef ALL_PLATFORMS
+all_platforms:: $(NFSPWD)
+ @d=`$(NFSPWD)`; \
+ if test ! -d LOGS; then rm -rf LOGS; mkdir LOGS; fi; \
+ for h in $(PLATFORM_HOSTS); do \
+ echo "On $$h: $(MAKE) $(ALL_PLATFORMS) >& LOGS/$$h.log"; \
+ rsh $$h -n "(chdir $$d; \
+ $(MAKE) $(ALL_PLATFORMS) >& LOGS/$$h.log; \
+ echo DONE) &" 2>&1 > LOGS/$$h.pid & \
+ sleep 1; \
+ done
+
+$(NFSPWD):
+ cd $(@D); $(MAKE) $(@F)
+endif
+
+ifdef REQUIRES
+ifndef NO_NSPR
+INCLUDES += -I$(XPDIST)/$(OBJDIR)/include/nspr20/pr $(addprefix -I$(XPDIST)/public/, $(REQUIRES))
+else
+INCLUDES += $(addprefix -I$(XPDIST)/public/, $(REQUIRES))
+endif
+endif
+
+all:: $(TARGETS)
+ +$(LOOP_OVER_DIRS)
+
+libs:: $(LIBRARY) $(SHARED_LIBRARY)
+
+$(PROGRAM): $(OBJS)
+ @$(MAKE_OBJDIR)
+ifeq ($(OS_ARCH),WINNT)
+ $(CC) $(OBJS) -Fe$@ -link $(LDFLAGS) $(OS_LIBS) $(EXTRA_LIBS)
+else
+ $(CC) -o $@ $(CFLAGS) $(OBJS) $(LDFLAGS)
+endif
+
+$(LIBRARY): $(OBJS)
+ @$(MAKE_OBJDIR)
+ rm -f $@
+ $(AR) $(OBJS)
+ $(RANLIB) $@
+
+$(SHARED_LIBRARY): $(OBJS)
+ @$(MAKE_OBJDIR)
+ rm -f $@
+ $(MKSHLIB) -o $@ $(OBJS) $(EXTRA_SHLIBS)
+ chmod +x $@
+
+ifeq ($(OS_ARCH),WINNT)
+$(DLL): $(OBJS) $(EXTRA_LIBS)
+ @$(MAKE_OBJDIR)
+ rm -f $@
+ $(LINK_DLL) $(OBJS) $(OS_LIBS) $(EXTRA_LIBS)
+endif
+
+.SUFFIXES: .i .pl .class .java .html
+
+.PRECIOUS: .java
+
+$(OBJDIR)/%: %.c
+ @$(MAKE_OBJDIR)
+ifeq ($(OS_ARCH),WINNT)
+ $(CC) -Fo$@ -c $(CFLAGS) $*.c
+else
+ $(CC) -o $@ $(CFLAGS) $*.c $(LDFLAGS)
+endif
+
+$(OBJDIR)/%.o: %.c
+ @$(MAKE_OBJDIR)
+ifeq ($(OS_ARCH),WINNT)
+ $(CC) -Fo$@ -c $(CFLAGS) $*.c
+else
+ $(CC) -o $@ -c $(CFLAGS) $*.c
+endif
+
+$(OBJDIR)/%.o: %.s
+ @$(MAKE_OBJDIR)
+ $(AS) -o $@ $(ASFLAGS) -c $*.s
+
+$(OBJDIR)/%.o: %.S
+ @$(MAKE_OBJDIR)
+ $(AS) -o $@ $(ASFLAGS) -c $*.S
+
+$(OBJDIR)/%: %.cpp
+ @$(MAKE_OBJDIR)
+ $(CCC) -o $@ $(CFLAGS) $*.c $(LDFLAGS)
+
+#
+# Please keep the next two rules in sync.
+#
+$(OBJDIR)/%.o: %.cc
+ @$(MAKE_OBJDIR)
+ $(CCC) -o $@ -c $(CFLAGS) $*.cc
+
+$(OBJDIR)/%.o: %.cpp
+ @$(MAKE_OBJDIR)
+ifdef STRICT_CPLUSPLUS_SUFFIX
+ echo "#line 1 \"$*.cpp\"" | cat - $*.cpp > $(OBJDIR)/t_$*.cc
+ $(CCC) -o $@ -c $(CFLAGS) $(OBJDIR)/t_$*.cc
+ rm -f $(OBJDIR)/t_$*.cc
+else
+ifeq ($(OS_ARCH),WINNT)
+ $(CCC) -Fo$@ -c $(CFLAGS) $*.cpp
+else
+ $(CCC) -o $@ -c $(CFLAGS) $*.cpp
+endif
+endif #STRICT_CPLUSPLUS_SUFFIX
+
+%.i: %.cpp
+ $(CCC) -C -E $(CFLAGS) $< > $*.i
+
+%.i: %.c
+ $(CC) -C -E $(CFLAGS) $< > $*.i
+
+%: %.pl
+ rm -f $@; cp $*.pl $@; chmod +x $@
+
+%: %.sh
+ rm -f $@; cp $*.sh $@; chmod +x $@
+
+#
+# If this is an "official" build, try to build everything.
+# I.e., don't exit on errors.
+#
+ifdef BUILD_OFFICIAL
+EXIT_ON_ERROR = +e
+else
+EXIT_ON_ERROR = -e
+endif
+
+ifdef DIRS
+ifneq ($(OS_ARCH),WINNT)
+override MAKEFLAGS :=
+endif
+LOOP_OVER_DIRS = \
+ @for d in $(DIRS); do \
+ if test -d $$d; then \
+ set $(EXIT_ON_ERROR); \
+ echo "cd $$d; $(MAKE) $(MAKEFLAGS) $@"; \
+ cd $$d; $(MAKE) $(MAKEFLAGS) $@; cd ..; \
+ set +e; \
+ else \
+ echo "Skipping non-directory $$d..."; \
+ fi; \
+ $(CLICK_STOPWATCH); \
+done
+
+$(DIRS)::
+ @if test -d $@; then \
+ set $(EXIT_ON_ERROR); \
+ echo "cd $@; $(MAKE) $(MAKEFLAGS)"; \
+ cd $@; $(MAKE) $(MAKEFLAGS); \
+ set +e; \
+ else \
+ echo "Skipping non-directory $@..."; \
+ fi \
+ $(CLICK_STOPWATCH);
+endif # DIRS
+
+clean::
+ rm -f $(OBJS) $(NOSUCHFILE)
+ +$(LOOP_OVER_DIRS)
+
+clobber::
+ rm -f $(OBJS) $(TARGETS) $(GARBAGE) $(NOSUCHFILE)
+ +$(LOOP_OVER_DIRS)
+
+realclean clobber_all::
+ rm -rf LOGS TAGS $(wildcard *.OBJ) $(OBJS) $(TARGETS) $(GARBAGE) $(NOSUCHFILE)
+ +$(LOOP_OVER_DIRS)
+
+alltags:
+ rm -f TAGS
+ find . -name dist -prune -o \( -name '*.[hc]' -o -name '*.cp' -o -name '*.cpp' \) -print | xargs etags -a
+
+export::
+ +$(LOOP_OVER_DIRS)
+
+libs::
+ +$(LOOP_OVER_DIRS)
+
+install::
+ +$(LOOP_OVER_DIRS)
+
+mac::
+ +$(LOOP_OVER_DIRS)
+
+################################################################################
+### Bunch of things that extend the 'export' rule (in order):
+################################################################################
+### JSRCS -- for compiling java files
+
+ifndef PACKAGE
+PACKAGE = .
+endif
+$(JAVA_DESTPATH) $(JAVA_DESTPATH)/$(PACKAGE) $(JMCSRCDIR)::
+ @if test ! -d $@; then \
+ echo Creating $@; \
+ rm -rf $@; \
+ $(NSINSTALL) -D $@; \
+ fi
+
+ifneq ($(JSRCS),)
+export:: $(JAVA_DESTPATH) $(JAVA_DESTPATH)/$(PACKAGE)
+ @list=`perl $(DEPTH)/config/outofdate.pl $(PERLARG) \
+ -d $(JAVA_DESTPATH)/$(PACKAGE) $(JSRCS)`; \
+ if test "$$list"x != "x"; then \
+ echo $(JAVAC) $$list; \
+ $(JAVAC) $$list; \
+ fi
+
+all:: export
+
+clobber::
+ rm -f $(XPDIST)/classes/$(PACKAGE)/*.class
+
+endif
+
+################################################################################
+## JDIRS -- like JSRCS, except you can give a list of directories and it will
+## compile all the out-of-date java files recursively below those directories.
+
+ifdef JDIRS
+
+export:: $(JAVA_DESTPATH) $(JAVA_DESTPATH)/$(PACKAGE)
+ @for d in $(JDIRS); do \
+ if test -d $$d; then \
+ set $(EXIT_ON_ERROR); \
+ files=`echo $$d/*.java`; \
+ list=`perl $(DEPTH)/config/outofdate.pl $(PERLARG) \
+ -d $(JAVA_DESTPATH)/$(PACKAGE) $$files`; \
+ if test "$${list}x" != "x"; then \
+ echo Building all java files in $$d; \
+ echo $(JAVAC) $$list; \
+ $(JAVAC) $$list; \
+ fi; \
+ set +e; \
+ else \
+ echo "Skipping non-directory $$d..."; \
+ fi; \
+ $(CLICK_STOPWATCH); \
+ done
+
+all:: export
+
+clobber::
+ @for d in $(JDIRS); do \
+ echo rm -rf $(XPDIST)/classes/$$d; \
+ rm -rf $(XPDIST)/classes/$$d; \
+ done
+
+endif
+
+################################################################################
+### JDK_GEN -- for generating "old style" native methods
+
+# Generate JDK Headers and Stubs into the '_gen' and '_stubs' directory
+
+ifneq ($(JDK_GEN),)
+
+ifdef NSBUILDROOT
+JDK_GEN_DIR = $(XPDIST)/_gen
+JDK_STUB_DIR = $(XPDIST)/_stubs
+else
+JDK_GEN_DIR = _gen
+JDK_STUB_DIR = _stubs
+endif
+
+INCLUDES += -I$(JDK_GEN_DIR)
+
+JDK_PACKAGE_CLASSES = $(JDK_GEN)
+JDK_PATH_CLASSES = $(subst .,/,$(JDK_PACKAGE_CLASSES))
+JDK_PATH_CLASSES = $(subst .,/,$(JDK_PACKAGE_CLASSES))
+JDK_HEADER_CLASSFILES = $(patsubst %,$(JAVA_DESTPATH)/%.class,$(JDK_PATH_CLASSES))
+JDK_STUB_CLASSFILES = $(patsubst %,$(JAVA_DESTPATH)/%.class,$(JDK_PATH_CLASSES))
+JDK_HEADER_CFILES = $(patsubst %,$(JDK_GEN_DIR)/%.h,$(JDK_GEN))
+JDK_STUB_CFILES = $(patsubst %,$(JDK_STUB_DIR)/%.c,$(JDK_GEN))
+
+$(JDK_HEADER_CFILES): $(JDK_HEADER_CLASSFILES)
+$(JDK_STUB_CFILES): $(JDK_STUB_CLASSFILES)
+
+export::
+ @echo Generating/Updating JDK headers
+ $(JAVAH) -d $(JDK_GEN_DIR) $(JDK_PACKAGE_CLASSES)
+ @echo Generating/Updating JDK stubs
+ $(JAVAH) -stubs -d $(JDK_STUB_DIR) $(JDK_PACKAGE_CLASSES)
+
+mac::
+ @echo Generating/Updating JDK headers for the Mac
+ $(JAVAH) -mac -d $(DEPTH)/lib/mac/Java/_gen $(JDK_PACKAGE_CLASSES)
+ @echo Generating/Updating JDK stubs for the Mac
+ $(JAVAH) -mac -stubs -d $(DEPTH)/lib/mac/Java/_stubs $(JDK_PACKAGE_CLASSES)
+
+# Don't delete them if the don't compile (makes it hard to debug):
+.PRECIOUS: $(JDK_HEADERS) $(JDK_STUBS)
+
+clobber::
+ rm -rf $(JDK_HEADER_CFILES) $(JDK_STUB_CFILES)
+
+endif
+
+################################################################################
+### JRI_GEN -- for generating JRI native methods
+
+# Generate JRI Headers and Stubs into the 'jri' directory
+
+ifneq ($(JRI_GEN),)
+
+ifdef NSBUILDROOT
+JRI_GEN_DIR = $(XPDIST)/_jri
+else
+JRI_GEN_DIR = _jri
+endif
+
+INCLUDES += -I$(JRI_GEN_DIR)
+
+JRI_PACKAGE_CLASSES = $(JRI_GEN)
+JRI_PATH_CLASSES = $(subst .,/,$(JRI_PACKAGE_CLASSES))
+
+## dependency fu
+JRI_HEADER_CLASSFILES = $(patsubst %,$(XPDIST)/classes/%.class,$(JRI_PATH_CLASSES))
+JRI_HEADER_CFILES = $(patsubst %,$(JRI_GEN_DIR)/%.h,$(JRI_GEN))
+$(JRI_HEADER_CFILES): $(JRI_HEADER_CLASSFILES)
+
+## dependency fu
+JRI_STUB_CLASSFILES = $(patsubst %,$(XPDIST)/classes/%.class,$(JRI_PATH_CLASSES))
+JRI_STUB_CFILES = $(patsubst %,$(JRI_GEN_DIR)/%.c,$(JRI_GEN))
+$(JRI_STUB_CFILES): $(JRI_STUB_CLASSFILES)
+
+export::
+ @echo Generating/Updating JRI headers
+ $(JAVAH) -jri -d $(JRI_GEN_DIR) $(JRI_PACKAGE_CLASSES)
+ @echo Generating/Updating JRI stubs
+ $(JAVAH) -jri -stubs -d $(JRI_GEN_DIR) $(JRI_PACKAGE_CLASSES)
+ @if test ! -d $(DEPTH)/lib/mac/Java/; then \
+ echo "!!! You need to have a ns/lib/mac/Java directory checked out."; \
+ echo "!!! This allows us to automatically update generated files for the mac."; \
+ echo "!!! If you see any modified files there, please check them in."; \
+ fi
+ @echo Generating/Updating JRI headers for the Mac
+ $(JAVAH) -jri -mac -d $(DEPTH)/lib/mac/Java/_jri $(JRI_PACKAGE_CLASSES)
+ @echo Generating/Updating JRI stubs for the Mac
+ $(JAVAH) -jri -mac -stubs -d $(DEPTH)/lib/mac/Java/_jri $(JRI_PACKAGE_CLASSES)
+
+# Don't delete them if the don't compile (makes it hard to debug):
+.PRECIOUS: $(JRI_HEADERS) $(JRI_STUBS)
+
+clobber::
+ rm -rf $(JRI_HEADER_CFILES) $(JRI_STUB_CFILES)
+
+endif
+
+################################################################################
+## JMC_EXPORT -- for declaring which java classes are to be exported for jmc
+
+ifneq ($(JMC_EXPORT),)
+
+JMC_EXPORT_PATHS = $(subst .,/,$(JMC_EXPORT))
+JMC_EXPORT_FILES = $(patsubst %,$(XPDIST)/classes/$(PACKAGE)/%.class,$(JMC_EXPORT_PATHS))
+
+# We're doing NSINSTALL -t here (copy mode) because calling INSTALL will pick up
+# your NSDISTMODE and make links relative to the current directory. This is a
+# problem because the source isn't in the current directory:
+
+export:: $(JMC_EXPORT_FILES) $(JMCSRCDIR)
+ $(NSINSTALL) -t -m 444 $(JMC_EXPORT_FILES) $(JMCSRCDIR)
+
+clobber::
+ rm -rf $(JMC_EXPORT_FILES)
+
+endif
+
+
+################################################################################
+## EXPORTS
+#
+# Copy each element of EXPORTS to $(XPDIST)/public/$(MODULE)/
+#
+
+ifneq ($(EXPORTS),)
+
+$(XPDIST)/public/$(MODULE)::
+ @if test ! -d $@; then \
+ echo Creating $@; \
+ rm -rf $@; \
+ mkdir -p $@; \
+ fi
+
+export:: $(EXPORTS) $(XPDIST)/public/$(MODULE)
+ $(NSINSTALL) -t -m 444 $(EXPORTS) $(XPDIST)/public/$(MODULE)
+
+endif
+
+################################################################################
+## JMC_GEN -- for generating java modules
+
+# Provide default export & install rules when using JMC_GEN
+ifneq ($(JMC_GEN),)
+
+ifdef NSBUILDROOT
+JMC_GEN_DIR = $(XPDIST)/_jmc
+else
+JMC_GEN_DIR = _jmc
+endif
+
+INCLUDES += -I$(JMC_GEN_DIR)
+
+JMC_HEADERS = $(patsubst %,$(JMC_GEN_DIR)/%.h,$(JMC_GEN))
+JMC_STUBS = $(patsubst %,$(JMC_GEN_DIR)/%.c,$(JMC_GEN))
+JMC_OBJS = $(patsubst %,$(OBJDIR)/%.o,$(JMC_GEN))
+
+$(JMC_GEN_DIR)/M%.h: $(JMCSRCDIR)/%.class
+ $(JMC) -d $(JMC_GEN_DIR) -interface $(JMC_GEN_FLAGS) $(?F:.class=)
+
+$(JMC_GEN_DIR)/M%.c: $(JMCSRCDIR)/%.class
+ $(JMC) -d $(JMC_GEN_DIR) -module $(JMC_GEN_FLAGS) $(?F:.class=)
+
+$(OBJDIR)/M%.o: $(JMC_GEN_DIR)/M%.h $(JMC_GEN_DIR)/M%.c
+ @$(MAKE_OBJDIR)
+ $(CC) -o $@ -c $(CFLAGS) $(JMC_GEN_DIR)/M$*.c
+
+export:: $(JMC_HEADERS) $(JMC_STUBS)
+
+# Don't delete them if the don't compile (makes it hard to debug):
+.PRECIOUS: $(JMC_HEADERS) $(JMC_STUBS)
+
+clobber::
+ rm -rf $(JMC_HEADERS) $(JMC_STUBS)
+
+endif
+
+################################################################################
+## LIBRARY -- default rules for for building libraries
+
+ifdef LIBRARY
+libs:: $(LIBRARY)
+ $(INSTALL) -m 444 $(LIBRARY) $(DIST)/lib
+
+install:: $(LIBRARY)
+ $(INSTALL) -m 444 $(LIBRARY) $(DIST)/lib
+endif
+
+ifdef SHARED_LIBRARY
+libs:: $(SHARED_LIBRARY)
+ $(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin
+
+install:: $(SHARED_LIBRARY)
+ $(INSTALL) -m 555 $(SHARED_LIBRARY) $(DIST)/bin
+endif
+
+################################################################################
+## PROGRAM -- this is now needed because final programs are distributed
+## through dist and link with dynamic libraries
+
+ifdef PROGRAM
+libs:: $(PROGRAM)
+ $(INSTALL) -m 444 $(PROGRAM) $(DIST)/bin
+
+install:: $(PROGRAM)
+ $(INSTALL) -m 444 $(PROGRAM) $(DIST)/bin
+endif
+
+################################################################################
+
+-include $(DEPENDENCIES)
+
+ifneq ($(OS_ARCH),WINNT)
+# Can't use sed because of its 4000-char line length limit, so resort to perl
+.DEFAULT:
+ @perl -e ' \
+ open(MD, "< $(DEPENDENCIES)"); \
+ while (<MD>) { \
+ if (m@ \.*/*$< @) { \
+ $$found = 1; \
+ last; \
+ } \
+ } \
+ if ($$found) { \
+ print "Removing stale dependency $< from $(DEPENDENCIES)\n"; \
+ seek(MD, 0, 0); \
+ $$tmpname = "$(OBJDIR)/fix.md" . $$$$; \
+ open(TMD, "> " . $$tmpname); \
+ while (<MD>) { \
+ s@ \.*/*$< @ @; \
+ if (!print TMD "$$_") { \
+ unlink(($$tmpname)); \
+ exit(1); \
+ } \
+ } \
+ close(TMD); \
+ if (!rename($$tmpname, "$(DEPENDENCIES)")) { \
+ unlink(($$tmpname)); \
+ } \
+ } elsif ("$<" ne "$(DEPENDENCIES)") { \
+ print "$(MAKE): *** No rule to make target $<. Stop.\n"; \
+ exit(1); \
+ }'
+endif
+
+#############################################################################
+# X dependency system
+#############################################################################
+
+ifneq ($(OS_ARCH),WINNT)
+
+$(MKDEPENDENCIES)::
+ @$(MAKE_OBJDIR)
+ touch $(MKDEPENDENCIES)
+ $(MKDEPEND) -p$(OBJDIR_NAME)/ -o'.o' -f$(MKDEPENDENCIES) $(INCLUDES) $(CSRCS) $(CPPSRCS)
+
+$(MKDEPEND)::
+ cd $(MKDEPEND_DIR); $(MAKE)
+
+ifdef OBJS
+depend:: $(MKDEPEND) $(MKDEPENDENCIES)
+else
+depend::
+endif
+ +$(LOOP_OVER_DIRS)
+
+dependclean::
+ rm -f $(MKDEPENDENCIES)
+ +$(LOOP_OVER_DIRS)
+
+#-include $(OBJDIR)/depend.mk
+
+endif
+
+#############################################################################
+
+-include $(MY_RULES)
+
+$(MY_CONFIG):
+$(MY_RULES):
+
+# Generate Emacs tags in a file named TAGS if ETAGS was set in $(MY_CONFIG)
+# or in $(MY_RULES)
+ifdef ETAGS
+ifneq ($(CSRCS)$(HEADERS),)
+all:: TAGS
+TAGS:: $(CSRCS) $(HEADERS)
+ $(ETAGS) $(CSRCS) $(HEADERS)
+endif
+endif
+
+################################################################################
+# Special gmake rules.
+################################################################################
+
+#
+# Re-define the list of default suffixes, so gmake won't have to churn through
+# hundreds of built-in suffix rules for stuff we don't need.
+#
+.SUFFIXES:
+.SUFFIXES: .out .a .ln .o .c .cc .C .cpp .y .l .s .S .h .sh .i .pl .class .java .html
+
+#
+# Don't delete these files if we get killed.
+#
+.PRECIOUS: .java $(JDK_HEADERS) $(JDK_STUBS) $(JRI_HEADERS) $(JRI_STUBS) $(JMC_HEADERS) $(JMC_STUBS)
+
+#
+# Fake targets. Always run these rules, even if a file/directory with that
+# name already exists.
+#
+.PHONY: all all_platforms alltags boot clean clobber clobber_all export install libs realclean $(OBJDIR) $(DIRS)
diff --git a/config/webint.mk b/config/webint.mk
new file mode 100644
index 00000000..5269b321
--- /dev/null
+++ b/config/webint.mk
@@ -0,0 +1,24 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+ifdef WEBSERVER_LANGS
+LANG_LOOP= \
+ @for d in $(WEBSERVER_LANGS); do \
+ if test ! -d $$d; then \
+ echo Directory $$d does not exist. Creating...; \
+ mkdir -p $$d; \
+ fi; \
+ echo cd $$d; \
+ cd $$d; \
+ echo $(MAKE) -f ../Makefile $(MAKEFLAGS) INT_SUBDIR=1; \
+ $(MAKE) -f ../Makefile $(MAKEFLAGS) INT_SUBDIR=1; \
+ cd ..; \
+ done
+else
+LANG_LOOP= @echo "No foreign languages in this build"
+endif
+
diff --git a/dirver.pl b/dirver.pl
new file mode 100755
index 00000000..f360c18a
--- /dev/null
+++ b/dirver.pl
@@ -0,0 +1,125 @@
+#!/usr/bin/perl
+#-----------------------------------------------------------------
+# dirver.pl: Generates ascii format #define for FILEVERSION
+# resource identifier used by Windows executable binaries.
+#
+# Usage: dirver.pl -v <major.minor.patch> [-d mm/dd/yy] [-o outfile]
+# Example: dirver.pl -v 6.5.2 -d 1/19/2005 -o fileversion.h
+#
+# -v <major.minor.patch> Version number.
+# -d <mm/dd/yy> Date. (optional)
+# -o <outfile> Output header file. (optional)
+# -H Print this help message
+#-----------------------------------------------------------------
+
+use Getopt::Std;
+use FileHandle;
+
+autoflush STDERR 1;
+
+getopts('v:d:o:H');
+
+if ($opt_H) {exitHelp();}
+
+# Load arguments
+$version = $opt_v || exitHelp();
+$date = $opt_d;
+$outfile = $opt_o;
+
+# Separate version into components
+my @verComponents = split(/\./, $version);
+
+# Set version components to 0 if not defined
+if ($verComponents[1] == undef) { $verComponents[1] = "0"; }
+if ($verComponents[2] == undef) { $verComponents[2] = "0"; }
+
+# Calculate build version and build date
+my $buildVersion = calcVersion(@verComponents);
+my $buildDate = calcBuildDate($date);
+
+# Write #defines out to stdout or a file is requested
+if ($outfile) {
+ open(OUTFILE,">$outfile") || die "Error: Can't create $outfile: $!";
+ $outhdl = OUTFILE;
+} else {
+ $outhdl = STDOUT;
+}
+
+print $outhdl "#define VI_PRODUCTVERSION $verComponents[0].$verComponents[1]\n";
+print $outhdl "#define PRODUCTTEXT \"$version\"\n";
+print $outhdl "#define VI_FILEVERSION $buildVersion, 0, 0, $buildDate\n";
+print $outhdl "#define VI_FileVersion \"$version Build $buildDate\\0\"\n";
+
+# Close file if not using STDOUT
+if ($outfile) {
+ close(OUTFILE);
+}
+
+#---------- calcVersion subroutine ----------
+sub calcVersion {
+ my @ver = shift;
+ my $nVersion = 0;
+
+ $nVersion = $ver[0];
+ $nVersion <<= 5;
+ $nVersion += $ver[1];
+ $nVersion <<= 7;
+ $nVersion += $ver[2];
+ $nVersion &= 0xFFFF;
+
+ return $nVersion;
+}
+
+#---------- calcBuildDate subroutine ----------
+sub calcBuildDate {
+ my $date = shift;
+ my @dateComponents = ();
+ my $month, $date, $year;
+ my $buildDate = "";
+
+ # Use date if passed in, otherwise use system date
+ if ($date) {
+ # Separate date into month, day, and year
+ @dateComponents = split(/\//, $date);
+
+ # Use struct tm range for month
+ $dateComponents[0]--;
+
+ # Handle 2 digit years like (20)00
+ if ($dateComponents[2] < 70) {
+ $dateComponents[2] += 20;
+ }
+
+ $month = $dateComponents[0];
+ $day = $dateComponents[1];
+ $year = $dateComponents[2];
+ } else {
+ $month = (localtime)[4];
+ $day = (localtime)[3];
+ $year = (localtime)[5] - 80;
+ }
+
+ $buildDate = $year;
+ $buildDate <<= 4;
+ $buildDate += $month;
+ $buildDate <<= 5;
+ $buildDate += $day;
+ $buildDate &= 0xFFFF;
+
+ return $buildDate;
+}
+
+#---------- exitHelp subroutine ----------
+sub exitHelp {
+ print(STDERR "$0: Generates ascii format #define for FILEVERSION
+ \tresource identifier used by Windows executable binaries.
+
+ \tUsage: $0 -v <major.minor.patch> [-d mm/dd/yy] [-o outfile]
+ \tExample: $0 -v 6.5.2 -d 1/19/2005 -o fileversion.h
+
+ \t-v <major.minor.patch> Version number.
+ \t-d <mm/dd/yy> Date. \(optional\)
+ \t-o <outfile> Output header file. \(optional\)
+ \t-H Print this help message\n");
+ exit(0);
+}
diff --git a/httpd/autobuild b/httpd/autobuild
new file mode 100755
index 00000000..a8b4a2fa
--- /dev/null
+++ b/httpd/autobuild
@@ -0,0 +1,500 @@
+#!/bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+UNAME=`../nsarch`
+NSUNAME=`uname -s | sed -e 's%/%_%g'``uname -r`
+DATE="`date +%d-%h`"
+
+# OS tweaks
+
+if [ "$UNAME" = "SUNOS4" ]; then
+ PATH=/usr/local/sun4/bin:/usr/bin/X11:$PATH; export PATH
+ GTAR=/share/builds/f/gtar/bin/sunos-gtar
+ HTTPDLIB=ns-httpd.so
+
+elif [ "$UNAME" = "SOLARIS" ]; then
+ PATH=/usr/ccs/bin:/usr/openwin/bin:$PATH; export PATH
+ OPENWINHOME=/usr/openwin; export OPENWINHOME
+ GTAR=/share/builds/f/gtar/bin/solaris-gtar
+ HTTPDLIB=ns-httpd.so
+
+elif [ "$UNAME" = "SOLARISx86" ]; then
+ PATH=/usr/ccs/bin:/usr/openwin/bin:$PATH; export PATH
+ OPENWINHOME=/usr/openwin; export OPENWINHOME
+ HTTPDLIB=ns-httpd.so
+
+elif [ "$UNAME" = "HPUX" ]; then
+ PATH=/usr/local/hpux/bin:/usr/bin/X11:$PATH; export PATH
+ GTAR=/share/builds/f/gtar/bin/hpux-gtar
+ HTTPDLIB=libnshttpd.sl
+
+elif [ "$UNAME" = "BSDI" ]; then
+ PATH=/usr/local/bin:/usr/X11/bin:$PATH; export PATH
+ GTAR=/share/builds/f/gtar/bin/bsdi-gtar
+
+elif [ "$UNAME" = "OSF1" ]; then
+# NOJAVA=true
+ PATH=/usr/local/dec/bin:/usr/bin/X11:$PATH; export PATH
+ GTAR=/share/builds/f/gtar/bin/osf1-gtar
+ HTTPDLIB=ns-httpd.so
+
+elif [ "$UNAME" = "AIX" ]; then
+ PATH=/usr/local/aix32/bin:/usr/bin/X11:$PATH; export PATH
+ GTAR=/share/builds/f/gtar/bin/aix-gtar
+ HTTPDLIB=ns-httpd.a
+
+elif [ "$UNAME" = "IRIX" ]; then
+ GTAR=/share/builds/f/gtar/bin/irix-gtar
+ HTTPDLIB=ns-httpd.so
+
+elif [ "$UNAME" = "SONY" ]; then
+ PATH=/usr/bin/X11:$PATH; export PATH
+ HTTPDLIB=ns-httpd.so
+
+elif [ "$UNAME" = "NECSVR4" ]; then
+ PATH=/u/malmer/nec/usr/local/bin:/usr/bin/X11:$PATH; export PATH
+ HTTPDLIB=ns-httpd.so
+
+elif [ "$UNAME" = "ReliantUNIX" ]; then
+ PATH=/usr/local/bin:$PATH; export PATH
+ GTAR=tar
+ HTTPDLIB=ns-httpd.so
+
+elif [ "$UNAME" = "SCO" ]; then
+ PATH=/usr/local/bin:/usr/bin/X11:$PATH; export PATH
+ GTAR=/usr/local/bin/gtar
+ HTTPDLIB=ns-httpd.so
+
+elif [ "$UNAME" = "UNIXWARE" ]; then
+ PATH=/usr/local/bin:/usr/bin/X11:$PATH; export PATH
+ GTAR=/usr/local/bin/gtar
+ HTTPDLIB=ns-httpd.so
+
+fi
+
+set -- `getopt p: $*` || {
+ echo "### `basename $0`: ERROR: unknown option" 1>&2
+ exit 1
+}
+
+BuildInPhases=0
+
+while [ "$1" != "--" ] ; do
+ case "$1" in
+ -p) BuildInPhases=1; shift; Phase=$1
+ ;;
+ esac
+ shift
+done
+shift
+
+
+buildit() {
+
+# Initialize some variables
+
+ADMINDIR=../built/$UNAME-$SECTYPE-admserv
+if [ "$PRODUCT" = "personal" ]; then
+ BINDIR=httpd
+ TARNAME=nshttpd.tar
+elif [ "$PRODUCT" = "catalog" ]; then
+ BINDIR=catalog
+ TARNAME=ns-catalog.tar
+elif [ "$PRODUCT" = "rds" ]; then
+ BINDIR=rds
+ TARNAME=ns-rds.tar
+elif [ "$PRODUCT" = "cms" ]; then
+ BINDIR=https
+ TARNAME=ns-cms.tar
+else
+ BINDIR=https
+ TARNAME=nshttps.tar
+fi
+SOURCEDIR=../built/$UNAME-$SECTYPE-$BINDIR
+TARGETDIR=$TYPE/$UNAME-$SECTYPE-$BINDIR
+TARGETUNTAR=$TYPE/$UNAME-$SECTYPE-$BINDIR/untarred
+
+TARGETHTBIN=$TYPE/$UNAME-$SECTYPE-$BINDIR/untarred/bin/$BINDIR
+mkdir -p $TARGETUNTAR 2> /dev/null
+
+if [ $BuildInPhases = 1 ]
+then
+ if [ "$Phase" = "server" ]
+ then
+ buildserver
+ elif [ "$Phase" = "admin" ]
+ then
+ buildadmin
+ elif [ "$Phase" = "batman" ]
+ then
+ buildbatman
+ elif [ "$Phase" = "tar" ]
+ then
+ (cd $TARGETUNTAR; tar cvf ../$TARNAME *)
+ else
+ echo "`basename $0`: ERROR: unknown build phase"
+ exit 1
+ fi
+else
+ buildserver
+ buildadmin
+ buildbatman
+ (cd $TARGETUNTAR; tar cvf ../$TARNAME *)
+fi
+}
+
+buildserver() {
+
+(cd ..; ./config $BOMB $PRODUCT $SECCONFIG $OPTIMIZE)
+gmake
+
+if [ $? -ne 0 ]; then
+ exit 2
+fi
+
+(cd ../mc-icons; gmake)
+if [ $? -ne 0 ]; then
+ exit 2
+fi
+
+(cd ../include; gmake)
+if [ $? -ne 0 ]; then
+ exit 2
+fi
+
+(cd nsapi; gmake)
+if [ $? -ne 0 ]; then
+ exit 2
+fi
+
+(cd extras; gmake)
+if [ $? -ne 0 ]; then
+ exit 2
+fi
+
+if [ "$NOJAVA" != "true" ]; then
+ (cd ../lib/sjava; gmake)
+ if [ $? -ne 0 ]; then
+ exit 2
+ fi
+fi
+
+# generate DBMs in admin/bin directory
+(cd $SOURCEDIR/admin/bin; ./mkdbm)
+
+# Each product has different manuals
+if [ "$BINDIR" = "catalog" -o "$BINDIR" = "rds" ]; then
+ # Batman
+ ADMINMANUALS="html/manual/ag html/manual/design html/manual/beta2"
+else
+ # Enterprise and FastTrack
+ ADMINMANUALS="html/manual/ag html/manual/pg html/manual/javascript"
+fi
+for i in icons html html/info html/manual $ADMINMANUALS bin; do
+ mkdir -p $TARGETUNTAR/bin/$BINDIR/admin/$i
+ cp $SOURCEDIR/admin/$i/* $TARGETHTBIN/admin/$i
+done
+
+/bin/rm -f $TARGETHTBIN/admin/bin/*.o
+$STRIP $TARGETHTBIN/admin/bin/*
+
+for i in misc icons html bin; do
+ mkdir -p $TARGETHTBIN/install/$i
+ cp $SOURCEDIR/install/$i/* $TARGETHTBIN/install/$i
+done
+$STRIP $TARGETHTBIN/install/bin/*
+mv $TARGETHTBIN/install/bin/ns-setup $TARGETDIR
+mv $TARGETHTBIN/install/bin/ns-config $TARGETHTBIN/ns-config
+
+
+mkdir -p $TARGETUNTAR/ns-icons
+cp $SOURCEDIR/mc-icons/* $TARGETUNTAR/ns-icons
+
+if [ -d $SOURCEDIR/nsapi -a "$UNAME" != "BSDI" ]; then
+ mkdir -p $TARGETUNTAR/nsapi
+ cp -r $SOURCEDIR/nsapi/* $TARGETUNTAR/nsapi
+fi
+
+mkdir -p $TARGETUNTAR/extras
+cp -r $SOURCEDIR/extras/* $TARGETUNTAR/extras
+$STRIP $TARGETUNTAR/extras/*/*
+
+cp $SOURCEDIR/ns-httpd $TARGETHTBIN/ns-httpd
+if [ "$HTTPDLIB" != "" ]; then
+ cp $SOURCEDIR/$HTTPDLIB $TARGETHTBIN/$HTTPDLIB
+fi
+$STRIP $TARGETHTBIN/ns-httpd
+if [ "$UNAME" != "IRIX" -a "$UNAME" != "SUNOS4" ]; then
+ $STRIP $TARGETHTBIN/$HTTPDLIB
+fi
+
+if [ "$UNAME" = "AIX" ]; then
+ cp /usr/lib/libsvld.a $TARGETHTBIN/libsvld.a
+fi
+
+
+cp README $TARGETDIR
+cp newinst/misc/license.txt $TARGETDIR
+
+mkdir -p $TARGETUNTAR/userdb
+mkdir -p $TARGETUNTAR/httpacl
+mkdir -p $TARGETUNTAR/authdb
+mkdir -p $TARGETUNTAR/authdb/default
+
+if [ "$PRODUCT" = "enterprise" ]; then
+mkdir -p $TARGETUNTAR/plugins/search/admin
+mkdir -p $TARGETUNTAR/plugins/search/tmp
+chmod a+w $TARGETUNTAR/plugins/search/tmp
+mkdir -p $TARGETUNTAR/plugins/search/collections
+chmod a+w $TARGETUNTAR/plugins/search/collections
+cp -r plugins/search $TARGETUNTAR/plugins
+(cd $TARGETUNTAR/plugins/search; rm -r `find . -name CVS -print`)
+cp $SOURCEDIR/lib/vsearch $TARGETUNTAR/plugins/search/vsearch
+cp $SOURCEDIR/admin/bin/ia* $TARGETUNTAR/plugins/search/vsearch
+$STRIP $TARGETUNTAR/plugins/search/vsearch/ia*
+cp ../lib/libsearch/searching/query.err $TARGETUNTAR/plugins/search/vsearch
+mkdir -p $TARGETUNTAR/plugins/search/ui/icons
+mkdir -p $TARGETUNTAR/plugins/search/ui/usa
+cp ../lib/libsearch/searching/ui/icons/* $TARGETUNTAR/plugins/search/ui/icons
+cp ../lib/libsearch/searching/ui/usa/* $TARGETUNTAR/plugins/search/ui/usa
+
+mkdir -p $TARGETUNTAR/plugins/snmp
+mkdir -p $TARGETUNTAR/plugins/snmp/magt
+mkdir -p $TARGETUNTAR/plugins/snmp/sagt
+if [ -d $SOURCEDIR/plugin/snmp -a -f $SOURCEDIR/plugin/snmp/httpagt ]; then
+ cp $SOURCEDIR/plugin/snmp/httpagt $TARGETUNTAR/plugins/snmp/httpagt
+fi
+cp plugins/snmp/netscape.pub $TARGETUNTAR/plugins/snmp/netscape.mib
+
+mkdir -p $TARGETUNTAR/plugins/mks/bin
+ cp $SOURCEDIR/plugins/mks/bin/*.so $TARGETUNTAR/plugins/mks/bin
+
+if [ "$UNAME" = "SUNOS4" ]; then
+ cp ../../../peer/sunos/magt/* $TARGETUNTAR/plugins/snmp/magt
+ cp ../../../peer/sunos/sagt/* $TARGETUNTAR/plugins/snmp/sagt
+elif [ "$UNAME" = "SOLARIS" ]; then
+ cp ../../../peer/solaris/magt/* $TARGETUNTAR/plugins/snmp/magt
+ cp ../../../peer/solaris/sagt/* $TARGETUNTAR/plugins/snmp/sagt
+elif [ "$UNAME" = "HPUX" ]; then
+ cp ../../../peer/hp/magt/* $TARGETUNTAR/plugins/snmp/magt
+ cp ../../../peer/hp/sagt/* $TARGETUNTAR/plugins/snmp/sagt
+elif [ "$UNAME" = "OSF1" ]; then
+ cp ../../../peer/osf/magt/* $TARGETUNTAR/plugins/snmp/magt
+ cp ../../../peer/osf/sagt/* $TARGETUNTAR/plugins/snmp/sagt
+elif [ "$UNAME" = "AIX" ]; then
+ cp ../../../peer/aix/magt/* $TARGETUNTAR/plugins/snmp/magt
+ cp ../../../peer/aix/sagt/* $TARGETUNTAR/plugins/snmp/sgat
+elif [ "$UNAME" = "IRIX" ]; then
+ cp ../../../peer/irix/magt/* $TARGETUNTAR/plugins/snmp/magt
+ cp ../../../peer/irix/sagt/* $TARGETUNTAR/plugins/snmp/sagt
+fi
+fi # PRODUCT = enterprise
+
+
+if [ "$NOJAVA" != "true" ]; then
+ mkdir -p $TARGETUNTAR/plugins/java/bin
+ cp $SOURCEDIR/lib/libsjava.so $TARGETUNTAR/plugins/java/bin
+
+ mkdir -p $TARGETUNTAR/plugins/java/classes
+ cp ../../sun-java/classsrc/serv2_0.zip $TARGETUNTAR/plugins/java/classes
+
+ cp plugins/java/javac $TARGETUNTAR/plugins/java
+ cp plugins/java/README $TARGETUNTAR/plugins/java
+
+ mkdir -p $TARGETUNTAR/plugins/java/applets
+ cp plugins/java/applets/* $TARGETUNTAR/plugins/java/applets
+
+# mkdir -p $TARGETUNTAR/plugins/java/local-classes
+# cp plugins/java/local-classes/* $TARGETUNTAR/plugins/java/local-classes
+
+# XXXrobm these docs assume that we have Sun's HTML and images
+# mkdir -p $TARGETUNTAR/plugins/java/docs/images
+# cp plugins/java/docs/*.html $TARGETUNTAR/plugins/java/docs
+# cp ../../sun-java/javadoc/*.gif $TARGETUNTAR/plugins/java/docs/images
+fi
+
+mkdir $TARGETUNTAR/install
+cp ./newinst/src/upgrade $TARGETUNTAR/install
+cp ./newinst/src/ObjConf.pm $TARGETUNTAR/install
+cp ./newinst/src/Magnus.pm $TARGETUNTAR/install
+cp ./newinst/src/start $TARGETUNTAR/install
+cp ./newinst/src/stop $TARGETUNTAR/install
+cp ./newinst/src/restart $TARGETUNTAR/install
+cp ./newinst/src/rotate $TARGETUNTAR/install
+cp ./newinst/perl5/$UNAME-perl5/perl $TARGETUNTAR/install
+cp ./newinst/perl5/artistic $TARGETUNTAR/install
+if [ "$UNAME" = "IRIX" ] || [ "$UNAME" = "SOLARIS" ] || [ "$UNAME" = "OSF1" ] ; then
+ cp ./newinst/src/kernelThreads.pl $TARGETUNTAR/install/threads.pl
+fi
+cp $SOURCEDIR/extras/database/mkuser $TARGETUNTAR/install
+cp $SOURCEDIR/extras/database/ndbmdump $TARGETUNTAR/install
+cp $SOURCEDIR/extras/database/rcert11 $TARGETUNTAR/install
+cp $SOURCEDIR/extras/database/rkey11 $TARGETUNTAR/install
+$STRIP $TARGETUNTAR/install/*
+
+if [ "$DO_LIVEWIRE" = "yes" ]; then
+ if [ "$UNAME" = "IRIX" ] ; then
+ PLATSFX=sgi
+ elif [ "$UNAME" = "SOLARIS" ] ; then
+ PLATSFX=sol
+ elif [ "$UNAME" = "HPUX" ] ; then
+ PLATSFX=hpx
+ fi
+ LIVEWIRETAR=livewire_$PLATSFX.tar
+ if [ -d $TARGETUNTAR/LiveWire ]; then
+ rm -rf $TARGETUNTAR/LiveWire
+ fi
+ mkdir $TARGETUNTAR/LiveWire
+ cp ./newinst/src/$LIVEWIRETAR.gz $TARGETUNTAR/LiveWire
+ gunzip $TARGETUNTAR/LiveWire/$LIVEWIRETAR
+ (cd $TARGETUNTAR/LiveWire; tar xf livewire*.tar)
+ cp $TARGETUNTAR/LiveWire/server/* $TARGETUNTAR/bin/$BINDIR
+ cp $TARGETUNTAR/LiveWire/bin/* $TARGETUNTAR/bin/$BINDIR
+ rm -rf $TARGETUNTAR/LiveWire/server $TARGETUNTAR/LiveWire/bin
+ rm $TARGETUNTAR/LiveWire/livewire*.tar
+fi
+
+
+(cd $TARGETUNTAR; find . -name \*.o -print | xargs rm -f)
+
+}
+
+buildadmin() {
+
+# BONEHEAD
+(cd ..; ./config $BOMB admin $SECCONFIG $OPTIMIZE)
+(cd ../admserv; gmake)
+if [ $? -ne 0 ]; then
+ exit 2
+fi
+
+mkdir -p $TARGETUNTAR/admserv
+cp $ADMINDIR/ns-admin $TARGETUNTAR/admserv
+$STRIP $TARGETUNTAR/admserv/ns-admin
+
+for i in icons html html/info bin cfgstuff; do
+ mkdir -p $TARGETUNTAR/bin/admserv/$i
+ cp $ADMINDIR/cgi/$i/* $TARGETUNTAR/bin/admserv/$i
+done
+$STRIP $TARGETUNTAR/bin/admserv/bin/*
+
+}
+
+buildbatman() {
+
+# For AutoCatalog from Batman -Darren
+if [ "$DO_AUTOCATALOG" = "yes" ]; then
+ # We need to re-run config to get our own library versions, etc.
+ (cd ..; ./config $BOMB batman $SECCONFIG $OPTIMIZE)
+
+ # This ugly hack is needed because nspr.a must be rebuilt on
+ # SOLARIS for batman. There are symbols required by the gcc
+ # generated code that SparcWorks doesn't provide - nothing links.
+
+ if [ "$UNAME" = "SOLARIS" ]; then
+ NSPRDIR=../../nspr/src/${NSUNAME}_${NSTAG}.OBJ
+ mv $NSPRDIR/nspr.a $NSPRDIR/GCCnspr.a
+ if [ -f $NSPRDIR/SPARCWKnspr.a ] ; then
+ mv $NSPRDIR/SPARCWKnspr.a $NSPRDIR/nspr.a
+ else
+ rm -f $NSPRDIR/*.o
+ fi
+ fi
+ (NS_USE_NATIVE=1; export NS_USE_NATIVE; cd ../batman; gmake MINIRDS_INSTALLDIR="../../httpd/$TARGETUNTAR/plugins" NSAPIDIR="$TARGETUNTAR/nsapi" minirds)
+ if [ $? -ne 0 ]; then
+ exit 2
+ fi
+ $STRIP $TARGETUNTAR/plugins/autocatalog/bin/*
+ $STRIP $TARGETUNTAR/plugins/autocatalog/*
+ if [ "$UNAME" = "SOLARIS" ] ; then
+ mv $NSPRDIR/nspr.a $NSPRDIR/SPARCWKnspr.a
+ mv $NSPRDIR/GCCnspr.a $NSPRDIR/nspr.a
+ fi
+fi
+
+}
+
+if [ "`echo $* | grep final`" != "" ]; then
+ TYPE=final
+ BOMB=nobomb
+
+elif [ "`echo $* | grep beta`" != "" ]; then
+ TYPE=beta
+ BOMB=bomb
+
+else
+ echo "You must choose to build either a beta or final version."
+ exit 2
+fi
+
+
+if [ "$NOJAVA" = "" -a "`echo $* | grep java`" != "" ]; then
+ NOJAVA=false
+else
+ NOJAVA=true
+fi
+
+if [ "$DO_AUTOCATALOG" = "" -a "`echo $* | grep autocatalog`" != "" ]; then
+ DO_AUTOCATALOG=yes
+else
+ DO_AUTOCATALOG=no
+fi
+# need to export DO_AUTOCATALOG so that it's passed down through all gmakes
+export DO_AUTOCATALOG
+
+if [ "$DO_LIVEWIRE" = "" ]; then
+ if [ "`echo $* | grep livewire`" != "" ]; then
+ DO_LIVEWIRE=yes
+ else
+ DO_LIVEWIRE=no
+ fi
+fi
+export DO_LIVEWIRE
+
+OPTIMIZE=optimize
+NSTAG=OPT
+STRIP=strip
+if [ "`echo $* | grep debug`" != "" ]; then
+ OPTIMIZE=debug
+ NSTAG=DBG
+ STRIP=echo
+fi
+
+NSDISTDIR=../../dist/${NSUNAME}_${NSTAG}.OBJ
+
+if [ "`echo $* | grep personal`" != "" ]; then
+ PRODUCT=personal
+elif [ "`echo $* | grep ns_catalog`" != "" ]; then
+ PRODUCT=catalog
+elif [ "`echo $* | grep ns_rds`" != "" ]; then
+ PRODUCT=rds
+elif [ "`echo $* | grep cms`" != "" ]; then
+ PRODUCT=cms
+else
+ PRODUCT=enterprise
+fi
+
+
+if [ "`echo $* | grep unsecure`" != "" -o "`echo $* | grep all`" != "" ]; then
+ SECTYPE=none
+ SECCONFIG=unsecure
+ buildit
+fi
+
+if [ "`echo $* | grep export`" != "" -o "`echo $* | grep all`" != "" ]; then
+ SECTYPE=export
+ SECCONFIG=export
+ buildit
+fi
+
+if [ "`echo $* | grep domestic`" != "" -o "`echo $* | grep all`" != "" ]; then
+ SECTYPE=domestic
+ SECCONFIG=domestic
+ buildit
+fi
diff --git a/httpd/src/Makefile b/httpd/src/Makefile
new file mode 100644
index 00000000..26ac574c
--- /dev/null
+++ b/httpd/src/Makefile
@@ -0,0 +1,229 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Makefile.cpp for the Netsite Commerce and Communications servers.
+
+MCOM_ROOT = ../../..
+
+MODULE=httpdBinary
+
+ifneq ($(ARCH), WINNT)
+OLD_MCOM_ROOT := $(MCOM_ROOT)
+MCOM_ROOT := $(shell cd $(OLD_MCOM_ROOT); pwd)
+BUILDSO=mocha admin
+endif
+
+HTTPD_DIR=$(OBJDIR)
+OBJDEST=$(HTTPD_DIR)/obj
+
+include ../../nsconfig.mk
+
+MCC_INCLUDE += $(ADMINUTIL_INCLUDE)
+
+ifeq ($(ARCH), WINNT)
+BINS=$(HTTPD_DIR)/httpd.exe
+DLLS=$(HTTPD_DIR)/$(HTTPDLL_NAME).dll
+HTTPD_LIB=$(HTTPD_DIR)/$(HTTPDLL_NAME).lib
+NSAPI20=$(HTTPD_DIR)/ns-httpd20.dll
+LOCAL_LINK_EXE = link -OUT:"$@" /STACK:0x20000,0x2000 /MAP $(ARCH_LINK_DEBUG) $(LCFLAGS) /NOLOGO /PDB:NONE /INCREMENTAL:NO \
+ /SUBSYSTEM:windows $(EXTRA_LIBS)
+EXTRA_LIBS+=$(NSPRLINK)
+
+ifeq ($(BSCINFO), yes)
+BSCS=$(HTTPD_DIR)/httpd.bsc
+endif
+
+else
+BINS=$(HTTPD_DIR)/ns-httpd
+endif
+
+ifeq ($(ARCH), SCO)
+EXTRA_OPTS := -Wl,-Bexport
+endif
+
+ifeq ($(ARCH), UNIXWARE)
+EXTRA_OPTS := -W l,-Bexport
+endif
+
+ifeq ($(ARCH), NCR)
+EXTRA_OPTS := -Wl,-Bexport
+endif
+
+ifeq ($(ARCH), SUNOS4)
+EXTRA_LIBS=-nostdlib /usr/lib/libc.a
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_OPTS = -blibpath:../../bin/https:$(DEF_LIBPATH)
+endif
+
+ifeq ($(ARCH), SOLARIS)
+EXTRA_LIBS=$(GCCLIBS)
+endif
+
+ifeq ($(ARCH), WINNT)
+OS_TARGETS= admin libhttpdaemon $(DLLS)
+endif
+
+all: $(OBJDEST) $(OS_TARGETS) $(BINS) $(BSCS)
+
+include unixso.mk
+
+ifeq ($(ARCH), HPUX)
+comma:=,
+#EXTRA_LIBS +=/opt/CC/lib/cxxshl.o
+EXTRA_LIBS += $(NSCP_DISTDIR)/lib/libprstrms.$(LIB_SUFFIX)
+EXTRA_LIBS := $(subst -E,-E$(comma)+s,$(EXTRA_LIBS))
+EXTRA_OPTS := -Wl,+s,-E
+#The extra library below is required to debug shared libraries.
+ifeq ($(BUILD_DEBUG), full)
+EXTRA_LIBS += /opt/langtools/lib/end.o
+endif
+# THIS IS A TEMPORARY SOLUTION TO THE HPUX COMPILER LIMITATION. WE
+# NEED TO INCLUDE ALL OF THE eh/LIBC object files into our main executable
+# to avoid having undefined symbols with plugins.
+LIBCARCHIVE = /opt/CC/lib/eh/libC.a
+endif
+
+$(OBJDEST):
+ mkdir -p $(OBJDEST)
+
+HTTPD_LIBS=$(FRAME) $(HTTPDAEMON)
+
+ifeq ($(ARCH), WINNT)
+ifeq ($(NO_MOCHA), 1)
+MOCHA =
+MCC_SERVER += -DNO_MOCHA
+else
+MOCHA=$(NSCP_DISTDIR)/lib/mocha.lib
+endif
+OSOBJS = ntmagnus.o ntnsapi.o
+HTTPD_LIBS += $(SAFS) $(LIBCRYPT)
+FVERSION_FLAGS+=-s$(BUILD_SECURITY)
+else
+OSOBJS = main.o
+endif
+
+ifneq ($(ARCH), WINNT)
+OBJS=$(addprefix $(OBJDEST)/, $(OSOBJS) index.o shtml.o upload.o \
+ cookie.o nsconfig.o)
+else
+EXEOBJS=$(addprefix $(OBJDEST)/, password.res ntmain.o)
+OBJS=$(addprefix $(OBJDEST)/, $(OSOBJS) index.o shtml.o upload.o \
+ cookie.o nsconfig.o)
+endif
+
+MODULE_CFLAGS=
+
+# Unixware linker braindamage. The libnspr.so won't override select
+# at link time
+ifeq ($(ARCH), UNIXWARE)
+OBJS+=$(HTTPD_DIR)/obj/uxwrap.o
+endif
+
+ifeq ($(ARCH), NCR)
+#OBJS+=$(HTTPD_DIR)/httpd-lib/nspr20/uxwrap.o
+endif
+
+ifdef PRODUCT_IS_DIRECTORY_SERVER
+# Primitive NT link process for nshttpd.dll requires httpdaemon
+ ifeq ($(ARCH), WINNT)
+ DAEMONLIB=$(OBJDIR)/lib/libhttpdaemon
+ else
+ DAEMONLIB=
+ endif
+else
+ DAEMONLIB=$(OBJDIR)/lib/libhttpdaemon
+endif
+
+ifeq ($(ARCH), WINNT)
+# Don't define DEPLIBS for NT because standard macros like LINK_EXE
+# and LINK_DLL automatically pick up DEPLIBS which we don't always wan't.
+# $(LIBDIRMON) (temporily removed)
+DEPLIBS = $(addsuffix .$(LIB_SUFFIX), $(addprefix $(OBJDIR)/lib/lib, $(LIBADMIN) $(LIBLDAPU) $(LIBACCESS) $(HTTPD_LIBS))) \
+ $(addsuffix .$(LIB_SUFFIX), $(OBJDIR)/lib/libmsgdisp)
+DEPLIBS += $(LIBSECURITY) \
+ $(LIBNSPR) \
+ $(LIBLDAP) \
+ $(LIBDBM) \
+ $(ADMINUTIL_DEP)
+
+DEPLINK = /LIBPATH:$(OBJDIR)/lib $(addsuffix .$(LIB_SUFFIX), $(addprefix lib, $(LIBADMIN) $(LIBLDAPU) $(LIBACCESS) $(HTTPD_LIBS))) \
+ libmsgdisp.$(LIB_SUFFIX) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) \
+ $(NSPRLINK) $(DBMLINK)
+else
+# unixso.mk may define DEPLIBS
+ifndef DEPLIBS
+DEPLIBS = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(OBJDIR)/lib/lib,$(HTTPD_LIBS)) \
+ $(DAEMONLIB) \
+ $(OBJDIR)/lib/libaccess \
+ $(OBJDIR)/lib/libbase \
+ $(OBJDIR)/lib/libsi18n \
+ $(OBJDIR)/lib/libmsgdisp) \
+ $(LIBSSLIO)
+DEPLIBS += $(SECURITY_DEP) \
+ $(NSPR_DEP) \
+ $(ADMINUTIL_DEP)
+
+DEPLINK = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(OBJDIR)/lib/lib,$(HTTPD_LIBS)) \
+ $(DAEMONLIB) \
+ $(OBJDIR)/lib/libaccess \
+ $(OBJDIR)/lib/libbase \
+ $(OBJDIR)/lib/libsi18n \
+ $(OBJDIR)/lib/libmsgdisp) \
+ $(SECURITYLINK) \
+ $(NSPRLINK) \
+ $(LIBSSLIO) \
+ $(ADMINUTILLINK)
+endif
+
+endif
+
+ifndef PRODUCT_IS_DIRECTORY_SERVER
+ifeq ($(ARCH), AIX)
+ifdef OLD_AIX_LINKING
+# why is this redefined here?
+CCC = svxlC_r
+endif
+endif
+endif
+ifneq ($(ARCH), WINNT)
+$(BINS): $(DEPLIBS) $(OBJS)
+ifndef PRODUCT_IS_DIRECTORY_SERVER
+ echo "why are we doing this for directory server?"
+ cd $(HTTPD_DIR); $(PURIFY) $(CCC) -o ns-httpd $(OBJS) \
+ $(EXTRA_OPTS) $(DEPLINK) $(EXTRA_LIBS)
+endif # Netscape Directory Server
+else # WINNT
+
+$(MOCHA):
+ cd $(MCOM_ROOT)/mocha; $(MAKE) export $(NSDEFS)
+
+$(DLLS): $(OBJS) $(DEPLIBS) $(OBJDEST)/ns-httpd.res
+ -@echo EXTRA_LIBS = $(EXTRA_LIBS)
+ $(PURIFY) $(LINK_DLL) $(DEPLINK) $(OBJDEST)/ns-httpd.res $(OBJS) $(EXTRA_LIBS)
+ cp $(HTTPD_LIB) $(NSCP_DISTDIR)/lib
+ echo $(DLLS) finished
+
+$(BINS): $(OBJS) $(EXEOBJS) $(HTTPD_LIB)
+ rm -f $@
+ $(PURIFY) $(LOCAL_LINK_EXE) $(EXEOBJS) $(HTTPD_LIB)
+ echo $(BINS) finished
+
+$(NSAPI20): $(HTTPD_LIB) $(OBJDIR)/lib/frame/nsapi20.o
+ $(PURIFY) $(LINK_DLL) $(LIBNSPR) $(HTTPD_LIB) $(OBJDIR)/lib/frame/nsapi20.o $(EXTRA_LIBS)
+
+ifeq ($(BSCINFO), yes)
+$(BSCS): $(OBJS)
+ $(BSCMAKE) $(OBJDEST)/*.sbr
+endif
+endif
+
+
+include $(INCLUDE_DEPENDS)
diff --git a/httpd/src/ntnsapi.c b/httpd/src/ntnsapi.c
new file mode 100644
index 00000000..33fa7955
--- /dev/null
+++ b/httpd/src/ntnsapi.c
@@ -0,0 +1,383 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Aruna Victor
+ * NT NSAPI works differently from UNIX. The DLL doesn't know the addresses
+ * of the functions in the server process and needs to be told them.
+ */
+
+#include <nt/nsapi.h>
+extern int upload_file(pblock *pb, Session *sn, Request *rq);
+
+#ifdef BUILD_DLL
+
+#include <libadmin/libadmin.h>
+#include <libadmin/dstats.h>
+#include <libaccess/nsadb.h>
+#include <libadminutil/admutil.h>
+#include <libadminutil/distadm.h>
+#if 0
+#ifndef NO_MOCHA
+#include <mocha/mo_atom.h>
+#include <mocha/mo_scope.h>
+#include <mocha/mochaapi.h>
+#endif /* NO_MOCHA */
+#endif
+#include <base/fsmutex.h>
+
+extern char *system_winerr(void);
+extern char *system_winsockerr(void);
+
+VOID NsapiDummy()
+{
+ int i = 0;
+ SafTable = (SafFunction **)MALLOC(400 * sizeof(VOID*));
+
+ /* Force references to libadmin */
+
+ /* Functions from libadmin:keyconf.c */
+ SafTable[i++] = (SafFunction *)get_alias_dir;
+ /* Functions from libadmin:objconf.c */
+ SafTable[i++] = (SafFunction *)get_mag_init;
+ /* Functions from libadmin:form_post.c */
+ SafTable[i++] = (SafFunction *)post_begin;
+ /* Functions from libadmin:form_get.c */
+ SafTable[i++] = (SafFunction *)open_html_file;
+ /* Functions from libadmin:userdb.c */
+#if 0
+ SafTable[i++] = (SafFunction *)detect_db_type;
+#endif
+ /* Functions from libadmin:authdb.c */
+ SafTable[i++] = (SafFunction *)list_auth_dbs;
+ /* Functions from libadmin:error.c */
+ SafTable[i++] = (SafFunction *)report_error;
+ /* Functions from libadmin:template.c */
+ SafTable[i++] = (SafFunction *)directive_is;
+ /* Functions from libaccess:pcontrol.c */
+ SafTable[i++] = (SafFunction *)restart_http;
+ /* Functions from libadmin:admserv.c */
+ SafTable[i++] = (SafFunction *)read_server_lst;
+ /* Functions from libadmin:multconf.c */
+ SafTable[i++] = (SafFunction *)make_conflist;
+ /* Functions from libadmin:password */
+ SafTable[i++] = (SafFunction *)pw_enc;
+ /* Functions from libadmin:cron_conf.c */
+#if 0
+ SafTable[i++] = (SafFunction *)cron_conf_create_obj;
+#endif
+ /* Functions from libadmin:dstats.c */
+ SafTable[i++] = (SafFunction *)dstats_open;
+ /* Functions from libadmin:distadm.c */
+ SafTable[i++] = (SafFunction *)ADM_InitializePermissions;
+
+#ifndef NO_MOCHA
+ /* Force references to mocha */
+ /* Functions from mocha:mo_atom.c */
+ SafTable[i++] = (SafFunction *)mocha_Atomize;
+ /* Functions from mocha:mo_fun.c */
+ /* SafTable[i++] = (SafFunction *)mocha_NewFunctionObject; */
+ /* Functions from mocha:mo_scope.c */
+ SafTable[i++] = (SafFunction *)mocha_DefineSymbol;
+ /* Functions from mocha:mochaapi.c */
+ SafTable[i++] = (SafFunction *)MOCHA_CanConvertDatum;
+#endif /* NO_MOCHA */
+
+ /* Force references to base */
+ SafTable[i++] = (SafFunction *)fsmutex_init;
+
+ /* Force references to libmsgdisp */
+ SafTable[i++] = (SafFunction *)NSORB_Init;
+ SafTable[i++] = (SafFunction *)ConsumerCreatePush;
+ SafTable[i++] = (SafFunction *)CMNewBTree;
+ SafTable[i++] = (SafFunction *)NSObjArrayNew;
+}
+#endif /* BUILD_DLL */
+
+VOID InitializeSafFunctions()
+{
+
+ SafTable = (SafFunction **)MALLOC(400 * sizeof(VOID *));
+
+/* Functions from buffer.c */
+
+ SafTable[FILEBUF_OPEN] = (SafFunction *)filebuf_open;
+ SafTable[NETBUF_OPEN] = (SafFunction *)netbuf_open;
+ SafTable[FILEBUF_OPEN_NOSTAT] = (SafFunction *)filebuf_open_nostat;
+ SafTable[PIPEBUF_OPEN] = (SafFunction *)pipebuf_open;
+ SafTable[PIPEBUF_CLOSE] = (SafFunction *)pipebuf_close;
+ SafTable[FILEBUF_OPEN_NOSTAT] = (SafFunction *)filebuf_open_nostat;
+ SafTable[NETBUF_NEXT] = (SafFunction *)netbuf_next;
+ SafTable[PIPEBUF_NEXT] = (SafFunction *)pipebuf_next;
+ SafTable[FILEBUF_CLOSE] = (SafFunction *)filebuf_close;
+ SafTable[NETBUF_CLOSE] = (SafFunction *)netbuf_close;
+ SafTable[FILEBUF_GRAB] = (SafFunction *)filebuf_grab;
+ SafTable[NETBUF_GRAB] = (SafFunction *)netbuf_grab;
+ SafTable[PIPEBUF_GRAB] = (SafFunction *)pipebuf_grab;
+ SafTable[NETBUF_BUF2SD] = (SafFunction *)netbuf_buf2sd;
+ SafTable[FILEBUF_BUF2SD] = (SafFunction *)filebuf_buf2sd;
+ SafTable[PIPEBUF_BUF2SD] = (SafFunction *)pipebuf_buf2sd;
+ SafTable[PIPEBUF_NETBUF2SD] = (SafFunction *)pipebuf_netbuf2sd;
+
+/* Functions from daemon.h */
+ SafTable[NTDAEMON_RUN] = (SafFunction *)daemon_run;
+ SafTable[CHILD_STATUS] = (SafFunction *)child_status;
+
+/* Functions from file.h */
+ SafTable[SYSTEM_STAT] = (SafFunction *)system_stat;
+ SafTable[SYSTEM_FOPENRO] = (SafFunction *)system_fopenRO;
+ SafTable[SYSTEM_FOPENWA] = (SafFunction *)system_fopenWA;
+ SafTable[SYSTEM_FOPENRW] = (SafFunction *)system_fopenRW;
+ SafTable[SYSTEM_NOCOREDUMPS] = (SafFunction *)system_nocoredumps;
+ SafTable[SYSTEM_FWRITE] = (SafFunction *)system_fwrite;
+ SafTable[SYSTEM_FWRITE_ATOMIC] = (SafFunction *)system_fwrite_atomic;
+ SafTable[SYSTEM_WINERR] = (SafFunction *)system_winerr;
+ SafTable[SYSTEM_WINSOCKERR] = (SafFunction *)system_winsockerr;
+
+ SafTable[FILE_NOTFOUND] = (SafFunction *)file_notfound;
+ /* Removed from main code- 9-2-96
+ *
+ SafTable[SYSTEM_INITLOCK] = (SafFunction *)system_initlock;*/
+ SafTable[FILE_UNIX2LOCAL] = (SafFunction *)file_unix2local;
+ SafTable[DIR_OPEN] = (SafFunction *)dir_open;
+ SafTable[DIR_READ] = (SafFunction *)dir_read;
+ SafTable[DIR_CLOSE] = (SafFunction *)dir_close;
+
+/* Functions from cinfo.h */
+ SafTable[CINFO_INIT] = (SafFunction *)cinfo_init;
+ SafTable[CINFO_TERMINATE] = (SafFunction *)cinfo_terminate;
+ SafTable[CINFO_MERGE] = (SafFunction *)cinfo_merge;
+ SafTable[CINFO_FIND] = (SafFunction *)cinfo_find;
+ SafTable[CINFO_LOOKUP] = (SafFunction *)cinfo_lookup;
+ SafTable[CINFO_DUMP_DATABASE] = (SafFunction *)cinfo_dump_database;
+
+/* Functions from ereport.h */
+ SafTable[EREPORT] = (SafFunction *)ereport ;
+ SafTable[EREPORT_INIT] = (SafFunction *)ereport_init;
+ SafTable[EREPORT_TERMINATE] = (SafFunction *)ereport_terminate;
+ SafTable[EREPORT_GETFD] = (SafFunction *)ereport_getfd;
+
+#ifdef NET_SSL
+/* Functions from minissl.h */
+ SafTable[SSL_CLOSE] = (SafFunction *)PR_Close;
+ SafTable[SSL_SOCKET] = (SafFunction *)PR_NewTCPSocket;
+ SafTable[SSL_GET_SOCKOPT] = (SafFunction *)PR_GetSocketOption;
+ SafTable[SSL_SET_SOCKOPT] = (SafFunction *)PR_SetSocketOption;
+ SafTable[SSL_BIND] = (SafFunction *)PR_Bind;
+ SafTable[SSL_LISTEN] = (SafFunction *)PR_Listen;
+ SafTable[SSL_ACCEPT] = (SafFunction *)PR_Accept;
+ SafTable[SSL_READ] = (SafFunction *)PR_Read;
+ SafTable[SSL_WRITE] = (SafFunction *)PR_Write;
+ SafTable[SSL_GETPEERNAME] = (SafFunction *)PR_GetPeerName;
+#endif /* NET_SSL */
+
+
+/* Functions from net.h */
+
+ SafTable[NET_BIND] = (SafFunction *)net_bind;
+ SafTable[NET_READ] = (SafFunction *)net_read;
+ SafTable[NET_WRITE] = (SafFunction *)net_write;
+ /* SafTable[NET_FIND_FQDN] = (SafFunction *)net_find_fqdn; */
+ SafTable[NET_IP2HOST] = (SafFunction *)net_ip2host;
+
+/* Functions from pblock.h */
+ SafTable[PARAM_CREATE] = (SafFunction *)param_create;
+ SafTable[PARAM_FREE] = (SafFunction *)param_free;
+ SafTable[PBLOCK_CREATE] = (SafFunction *)pblock_create;
+ SafTable[PBLOCK_FREE] = (SafFunction *)pblock_free;
+ SafTable[PBLOCK_FINDVAL] = (SafFunction *)pblock_findval;
+ SafTable[PBLOCK_NVINSERT] = (SafFunction *)pblock_nvinsert;
+ SafTable[PBLOCK_NNINSERT] = (SafFunction *)pblock_nninsert;
+ SafTable[PBLOCK_PINSERT] = (SafFunction *)pblock_pinsert;
+ SafTable[PBLOCK_STR2PBLOCK] = (SafFunction *)pblock_str2pblock;
+ SafTable[PBLOCK_PBLOCK2STR] = (SafFunction *)pblock_pblock2str;
+ SafTable[PBLOCK_COPY] = (SafFunction *)pblock_copy;
+ SafTable[PBLOCK_PB2ENV] = (SafFunction *)pblock_pb2env;
+ SafTable[PBLOCK_FR] = (SafFunction *)pblock_fr;
+
+/* Functions from sem.h */
+ SafTable[SEM_INIT] = (SafFunction *)sem_init;
+ SafTable[SEM_TERMINATE] = (SafFunction *)sem_terminate;
+ SafTable[SEM_GRAB] = (SafFunction *)sem_grab;
+ SafTable[SEM_TGRAB] = (SafFunction *)sem_grab;
+ SafTable[SEM_RELEASE] = (SafFunction *)sem_release;
+
+/* Functions from session.h */
+ SafTable[SESSION_CREATE] = (SafFunction *)session_create;
+ SafTable[SESSION_FREE] = (SafFunction *)session_free;
+ SafTable[SESSION_DNS_LOOKUP] = (SafFunction *)session_dns_lookup;
+
+/* Functions from shexp.h */
+ SafTable[SHEXP_VALID] = (SafFunction *)shexp_valid;
+ SafTable[SHEXP_MATCH] = (SafFunction *)shexp_match;
+ SafTable[SHEXP_CMP] = (SafFunction *)shexp_cmp;
+ SafTable[SHEXP_CASECMP] = (SafFunction *)shexp_casecmp;
+
+/* Functions from systhr.h */
+ SafTable[SYSTHREAD_START] = (SafFunction *)systhread_start;
+ SafTable[SYSTHREAD_ATTACH] = (SafFunction *)systhread_attach;
+ SafTable[SYSTHREAD_TERMINATE] = (SafFunction *)systhread_terminate;
+ SafTable[SYSTHREAD_SLEEP] = (SafFunction *)systhread_sleep;
+ SafTable[SYSTHREAD_INIT] = (SafFunction *)systhread_init;
+ SafTable[SYSTHREAD_NEWKEY] = (SafFunction *)systhread_newkey;
+ SafTable[SYSTHREAD_GETDATA] = (SafFunction *)systhread_getdata;
+ SafTable[SYSTHREAD_SETDATA] = (SafFunction *)systhread_setdata;
+
+/* Functions from shmem.h */
+ SafTable[SHMEM_ALLOC] = (SafFunction *)shmem_alloc;
+ SafTable[SHMEM_FREE] = (SafFunction *)shmem_free;
+
+/* Functions from systems.h */
+ SafTable[UTIL_STRCASECMP] = (SafFunction *)util_strcasecmp;
+ SafTable[UTIL_STRNCASECMP] = (SafFunction *)util_strncasecmp;
+
+/* Functions from util.h */
+ SafTable[UTIL_GETLINE] = (SafFunction *)util_getline;
+ SafTable[UTIL_ENV_CREATE] = (SafFunction *)util_env_create;
+ SafTable[UTIL_ENV_STR] = (SafFunction *)util_env_str;
+#if 0
+ /* Removed from ntcgi.c --- obsolete; MB 1-26-96 */
+ SafTable[NTUTIL_ENV_STR] = (SafFunction *)ntutil_env_str;
+#endif
+ SafTable[UTIL_ENV_REPLACE] = (SafFunction *)util_env_replace;
+ SafTable[UTIL_ENV_FREE] = (SafFunction *)util_env_free;
+ SafTable[UTIL_ENV_FIND] = (SafFunction *)util_env_find;
+ SafTable[UTIL_HOSTNAME] = (SafFunction *)util_hostname;
+ SafTable[UTIL_CHDIR2PATH] = (SafFunction *)util_chdir2path;
+ SafTable[UTIL_IS_MOZILLA] = (SafFunction *)util_is_mozilla;
+ SafTable[UTIL_IS_URL] = (SafFunction *)util_is_url;
+ SafTable[UTIL_LATER_THAN] = (SafFunction *)util_later_than;
+ SafTable[UTIL_URI_IS_EVIL] = (SafFunction *)util_uri_is_evil;
+ SafTable[UTIL_URI_PARSE] = (SafFunction *)util_uri_parse;
+ SafTable[UTIL_URI_UNESCAPE] = (SafFunction *)util_uri_unescape;
+ SafTable[UTIL_URI_ESCAPE] = (SafFunction *)util_uri_escape;
+ SafTable[UTIL_URL_ESCAPE] = (SafFunction *)util_url_escape;
+ SafTable[UTIL_SH_ESCAPE] = (SafFunction *)util_sh_escape;
+ SafTable[UTIL_ITOA] = (SafFunction *)util_itoa;
+ SafTable[UTIL_VSPRINTF] = (SafFunction *)util_vsprintf;
+ SafTable[UTIL_SPRINTF] = (SafFunction *)util_sprintf;
+ SafTable[UTIL_VSNPRINTF] = (SafFunction *)util_vsnprintf;
+ SafTable[UTIL_SNPRINTF] = (SafFunction *)util_snprintf;
+
+// SafTable[INITIALIZE_ADMIN_LOGGING] = (SafFunction *)InitializeAdminLogging;
+// SafTable[INITIALIZE_HTTPD_LOGGING] = (SafFunction *)InitializeHttpdLogging;
+// SafTable[TERMINATE_ADMIN_LOGGING] = (SafFunction *)TerminateAdminLogging;
+// SafTable[TERMINATE_HTTPD_LOGGING] = (SafFunction *)TerminateHttpdLogging;
+
+ SafTable[LOG_ERROR_EVENT] = (SafFunction *)LogErrorEvent;
+
+/* Functions from conf.h */
+ SafTable[CONF_INIT] = (SafFunction *)conf_init;
+ SafTable[CONF_TERMINATE] = (SafFunction *)conf_terminate;
+ SafTable[CONF_GETGLOBALS] = (SafFunction *)conf_getglobals;
+ SafTable[CONF_VARS2DAEMON] = (SafFunction *)conf_vars2daemon;
+
+ SafTable[FUNC_INIT] = (SafFunction *)func_init;
+ SafTable[FUNC_FIND] = (SafFunction *)func_find;
+ SafTable[FUNC_EXEC] = (SafFunction *)func_exec;
+ SafTable[FUNC_INSERT] = (SafFunction *)func_insert;
+ SafTable[HTTP_SCAN_HEADERS] = (SafFunction *)http_scan_headers;
+ SafTable[HTTP_START_RESPONSE] = (SafFunction *)http_start_response;
+ SafTable[HTTP_HDRS2_ENV] = (SafFunction *)http_hdrs2env;
+ SafTable[HTTP_STATUS] = (SafFunction *)http_status;
+ SafTable[HTTP_SET_FINFO] = (SafFunction *)http_set_finfo;
+ SafTable[HTTP_DUMP822] = (SafFunction *)http_dump822;
+ SafTable[HTTP_FINISH_REQUEST] = (SafFunction *)http_finish_request;
+ SafTable[HTTP_HANDLE_SESSION] = (SafFunction *)http_handle_session;
+ SafTable[HTTP_URI2URL] = (SafFunction *)http_uri2url;
+
+/* Functions from log.h */
+ SafTable[LOG_ERROR] = (SafFunction *)log_error;
+ SafTable[DIRECTIVE_NAME2NUM] = (SafFunction *)directive_name2num;
+ SafTable[DIRECTIVE_NUM2NAME] = (SafFunction *)directive_num2name;
+ SafTable[OBJECT_CREATE] = (SafFunction *)object_create;
+ SafTable[OBJECT_FREE] = (SafFunction *)object_free;
+ SafTable[OBJECT_ADD_DIRECTIVE] = (SafFunction *)object_add_directive;
+ SafTable[OBJECT_EXECUTE] = (SafFunction *)object_execute;
+ SafTable[OBJSET_SCAN_BUFFER] = (SafFunction *)objset_scan_buffer;
+ SafTable[OBJSET_FREE] = (SafFunction *)objset_free;
+ SafTable[OBJSET_FREE_SETONLY] = (SafFunction *)objset_free_setonly;
+ SafTable[OBJSET_NEW_OBJECT] = (SafFunction *)objset_new_object;
+ SafTable[OBJSET_ADD_OBJECT] = (SafFunction *)objset_add_object;
+ SafTable[OBJSET_FINDBYNAME] = (SafFunction *)objset_findbyname;
+ SafTable[OBJSET_FINDBYPPATH] = (SafFunction *)objset_findbyppath;
+
+ SafTable[REQUEST_CREATE] = (SafFunction *)request_create;
+ SafTable[REQUEST_FREE] = (SafFunction *)request_free;
+ SafTable[REQUEST_RESTART_INTERNAL] = (SafFunction *)request_restart_internal;
+ SafTable[REQUEST_TRANSLATE_URI] = (SafFunction *)request_translate_uri;
+ SafTable[REQUEST_HEADER] = (SafFunction *)request_header;
+ SafTable[REQUEST_STAT_PATH] = (SafFunction *)request_stat_path;
+
+ /* temporarily remove definitions till they are added into the header file. */
+ SafTable[REQUEST_HANDLE_PROCESSED] = (SafFunction *)request_handle_processed;
+
+ SafTable[MAGNUS_ATRESTART] = (SafFunction *)magnus_atrestart;
+
+ SafTable[SYSTEM_FOPENWT] = (SafFunction *)system_fopenWT;
+ SafTable[SYSTEM_MALLOC] = (SafFunction *)system_malloc;
+ SafTable[SYSTEM_FREE] = (SafFunction *)system_free;
+ SafTable[SYSTEM_REALLOC] = (SafFunction *)system_realloc;
+ SafTable[SYSTEM_STRDUP] = (SafFunction *)system_strdup;
+
+ SafTable[UPLOAD_FILE] = (SafFunction *)upload_file;
+
+ SafTable[CRIT_INIT] = (SafFunction *)crit_init;
+ SafTable[CRIT_ENTER] = (SafFunction *)crit_enter;
+ SafTable[CRIT_EXIT] = (SafFunction *)crit_exit;
+ SafTable[CRIT_TERMINATE] = (SafFunction *)crit_terminate;
+ SafTable[SYSTHREAD_CURRENT] = (SafFunction *)systhread_current;
+
+ SafTable[NET_ACCEPT] = (SafFunction *)net_accept;
+ SafTable[NET_CLOSE] = (SafFunction *)net_close;
+ SafTable[NET_CONNECT] = (SafFunction *)net_connect;
+ SafTable[NET_IOCTL] = (SafFunction *)net_ioctl;
+ SafTable[NET_LISTEN] = (SafFunction *)net_listen;
+ SafTable[NET_SETSOCKOPT] = (SafFunction *)net_setsockopt;
+ SafTable[NET_SOCKET] = (SafFunction *)net_socket;
+
+
+ /* msgdisp functions */
+ SafTable[NSORB_INIT] = (SafFunction *)NSORB_Init;
+ SafTable[NSORB_INST_ID] = (SafFunction *)NSORB_InstanceID;
+ SafTable[NSORB_GET_INST] = (SafFunction *)NSORB_GetInstance;
+ SafTable[NSORB_REG_INT] = (SafFunction *)NSORB_RegisterInterface;
+ SafTable[NSORB_FIND_OBJ] = (SafFunction *)NSORB_FindObject;
+ SafTable[NSORB_GET_INTERFACE] = (SafFunction *)NSORB_GetInterface;
+
+ SafTable[ARR_NEW] = (SafFunction *)NSObjArrayNew;
+ SafTable[ARR_FREE] = (SafFunction *)NSObjArrayFree;
+ SafTable[ARR_GET_OBJ] = (SafFunction *)NSObjArrayGetObj;
+ SafTable[ARR_GET_LAST_OBJ] = (SafFunction *)NSObjArrayGetLastObj;
+ SafTable[ARR_NEW_OBJ] = (SafFunction *)NSObjArrayNewObj;
+ SafTable[ARR_GET_NUM_OBJ] = (SafFunction *)NSObjArrayGetNumObj;
+ SafTable[ARR_RESET] = (SafFunction *)NSObjArrayReset;
+ SafTable[ARR_REMOVEOBJ] = (SafFunction *)NSObjArrayRemoveObj;
+ SafTable[ARR_GET_OBJ_NUM] = (SafFunction *)NSObjArrayGetObjNum;
+
+ SafTable[CM_BT_NEW] = (SafFunction *)CMNewBTree;
+ SafTable[CM_BT_ADD_NODE] = (SafFunction *)CMBTreeAddNode;
+ SafTable[CM_BT_FIND_NODE] = (SafFunction *)CMBTreeFindNode;
+ SafTable[CM_BT_DEL_NODE] = (SafFunction *)CMBTreeDeleteNode;
+ SafTable[CM_BT_DESTROY] = (SafFunction *)CMBTreeDestroy;
+ SafTable[CM_BT_GET_NUM] = (SafFunction *)CMBTreeGetNumNode;
+ SafTable[CM_BT_TRAVEL] = (SafFunction *)CMBTreeInorderTravel;
+
+ SafTable[CM_STR_NEW] = (SafFunction *)NewCMStrObj;
+ SafTable[CM_STR_ADD] = (SafFunction *)CMStrObjAdd;
+ SafTable[CM_STR_REL] = (SafFunction *)CMStrObjRelease;
+ SafTable[CM_STR_FREE] = (SafFunction *)CMStrObjFree;
+ SafTable[CM_STR_GET] = (SafFunction *)CMStrObjGetString;
+ SafTable[CM_STR_SIZE] = (SafFunction *)CMStrObjGetSize;
+ SafTable[CM_COPY_STR] = (SafFunction *)CMCopyString;
+ SafTable[CM_MAKE_UID] = (SafFunction *)MakeUID;
+
+ SafTable[MS_NEW] = (SafFunction *)ConsumerNewPush;
+ SafTable[MS_CREATE] = (SafFunction *)ConsumerCreatePush;
+
+
+
+}
+
diff --git a/httpd/src/unixso.exp b/httpd/src/unixso.exp
new file mode 100644
index 00000000..55aae332
--- /dev/null
+++ b/httpd/src/unixso.exp
@@ -0,0 +1,38 @@
+acl_write_rights
+acl_read_rights
+SEC_ERROR_INVALID_AVA
+SEC_ERROR_INPUT_LEN
+SEC_ERROR_BAD_KEY
+SEC_ERROR_EXPIRED_CERTIFICATE
+SSL_ERROR_BAD_CERT_DOMAIN
+SEC_ERROR_UNTRUSTED_CERT
+SEC_ERROR_UNKNOWN_ISSUER
+SEC_ERROR_BAD_SIGNATURE
+SEC_ERROR_IO
+SEC_ERROR_INVALID_TIME
+XP_ERRNO_EWOULDBLOCK
+XP_ERRNO_EAGAIN
+pr_fdTable
+XP_ERRNO_EIO
+XP_ERRNO_EISCONN
+XP_ERRNO_EINVAL
+XP_ERRNO_EBADF
+XP_ERRNO_ECONNREFUSED
+SSL_ERROR_US_ONLY_SERVER
+SSL_ERROR_EXPORT_ONLY_SERVER
+SSL_ERROR_BAD_CERTIFICATE
+SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE
+SSL_ERROR_NO_CERTIFICATE
+SSL_ERROR_UNSUPPORTED_VERSION
+SSL_ERROR_NO_CYPHER_OVERLAP
+SSL_ERROR_BAD_SERVER
+SSL_ERROR_BAD_CLIENT
+SEC_ERROR_OUTPUT_LEN
+SEC_ERROR_INVALID_ARGS
+SEC_ERROR_BAD_DATA
+SEC_ERROR_NO_MEMORY
+SEC_ERROR_BAD_DATABASE
+SEC_ERROR_BAD_DER
+SEC_ERROR_INVALID_ALGORITHM
+SEC_ERROR_LIBRARY_FAILURE
+SEC_ERROR_BAD_PASSWORD
diff --git a/httpd/src/unixso.mk b/httpd/src/unixso.mk
new file mode 100644
index 00000000..e60e0226
--- /dev/null
+++ b/httpd/src/unixso.mk
@@ -0,0 +1,246 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+LIBSECDIR=$(MCOM_ROOT)/lib/libsec/$(NSOBJDIR_NAME)
+
+ifneq ($(ARCH), WINNT)
+
+SRCDIR=$(MCOM_ROOT)/ldapserver/httpd/src
+
+AR = ar
+
+ifeq ($(ARCH), OSF1)
+DLL_LDFLAGS += -soname $(SONAME)
+EXTRA_LIBS += -Wl,-rpath,.:../../lib:../../bin/https:../../plugins/java/bin:../../wai/lib
+ADM_EXTRA = -lcxx -lpthread -lmach -lexc -lc
+AR = rm -f ________64ELEL_ ; ar
+endif
+
+ifeq ($(ARCH), IRIX)
+DLL_LDFLAGS += -soname $(SONAME)
+ifeq ($(USE_N32), 1)
+ DLL_LDFLAGS += -n32 -mips3
+endif
+EXTRA_LIBS += -rpath .:../../lib:../../bin/https:../../plugins/java/bin:../wai/lib
+# IRIX likes it twice!
+SOLINK2=$(SOLINK)
+endif
+
+ifeq ($(ARCH), SOLARIS)
+DLL_LDFLAGS += -h $(SONAME)
+EXTRA_LIBS += -R .:../../lib:../../bin/https:../../plugins/java/bin:../wai/lib
+ADM_EXTRA = $(GCCLIB)
+endif
+
+ifdef USE_LD_RUN_PATH
+EXTRA_LIBS += -L.
+export LD_RUN_PATH=./.:../../lib:../../bin/https:../../plugins/java/bin:../wai/lib
+endif
+
+ifeq ($(ARCH), SONY)
+DLL_LDFLAGS += -soname $(SONAME)
+EXTRA_LIBS += -rpath .
+endif
+
+ifeq ($(ARCH), NEC)
+DLL_LDFLAGS += -h $(SONAME)
+endif
+
+ifeq ($(ARCH), HPUX)
+DLL_LDFLAGS += -L.
+SOLINK=-L. -l$(HTTPDSO_NAME)$(DLL_PRESUF)
+EXTRA_LIBS += -Wl,+b.:../../lib:../../bin/https:../../plugins/java/bin:../wai/lib
+# The line below is required for LiveWire DB2 to work.
+EXTRA_LIBS += -Wl,-uallow_unaligned_data_access -lhppa
+LD=$(CCC)
+# Well HPUX's not happy about including libnspr.sl(-lnspr) into our executable,
+# it's that ___ +eh again.
+NSPRLINK=$(NOTHING)
+#LDAPLINK=-L. $(addsuffix .a, $(addprefix lib, $(LDAP_DOTALIB_NAMES))) \
+# $(addprefix -l, $(LDAP_SOLIB_NAMES))
+endif
+
+ifeq ($(ARCH), AIX)
+MKSHLIB_FLAGS += -berok -brtl
+SOLINK=-L. -L../../lib -lns-dshttpd$(DLL_PRESUF)
+LIBSECDIR=$(MCOM_ROOT)/lib/libsec/$(NSOBJDIR_NAME)
+#LDAPLINK=-L. $(addsuffix .a, $(addprefix lib, $(LDAP_DOTALIB_NAMES))) \
+# $(addprefix -l, $(LDAP_SOLIB_NAMES))
+#NSPRLINK = -L. -lnspr$(DLL_PRESUF)
+#NSPRLINK = -L. -ldsnspr$(DLL_PRESUF)
+ADM_EXTRA := -L. -L../../lib $(LDAPLINK) $(NSPRLINK) $(EXTRA_LIBS)
+#ADM_EXTRA := -L. -L../../lib $(LDAPLINK) $(NSPRLINK) $(EXTRA_LIBS) -L$(LIBSECDIR) -lsec-$(WHICHA)
+ifdef FORTEZZA
+ADM_EXTRA += $(NSCP_DISTDIR)/lib/libci.$(LIB_SUFFIX)
+endif
+DEF_LIBPATH := .:../../lib:$(DEF_LIBPATH)
+endif
+
+ifeq ($(ARCH), SUNOS4)
+EXTRA_LIBS += -L.
+ADM_EXTRA = $(EXTRA_LIBS)
+endif
+
+ifeq ($(ARCH), UnixWare)
+DLL_LDFLAGS += -h $(SONAME)
+NSPRLINK = -L. -ldsnspr$(DLL_PRESUF)
+endif
+
+EXTRA_LIBS += $(MATHLIB)
+
+ifndef SONAME
+SONAME=$(HTTPDSO_NAME)$(DLL_PRESUF).$(DLL_SUFFIX)
+endif
+
+ifndef SOLINK
+SOLINK=./$(HTTPDSO_NAME)$(DLL_PRESUF).$(DLL_SUFFIX)
+endif
+
+#ifndef LDAPLINK
+#LDAPLINK=$(LDAPOBJNAME)
+#endif
+
+ifndef NSPRLINK
+NSPRLINK=libnspr$(DLL_PRESUF).$(DLL_SUFFIX)
+endif
+
+# Temporary directory for the libraries and their object files
+$(OBJDIR)/httpd-lib:
+ifeq ($(ARCH), HPUX)
+ mkdir -p $(OBJDIR)/httpd-lib/nspr20
+endif
+ mkdir -p $(OBJDIR)/httpd-lib/sslio
+ mkdir -p $(OBJDIR)/httpd-lib/arlib
+ mkdir -p $(OBJDIR)/httpd-lib/mocha
+ mkdir -p $(OBJDIR)/httpd-lib/libsec
+ mkdir -p $(OBJDIR)/httpd-lib/libdbm
+ mkdir -p $(OBJDIR)/httpd-lib/xp
+
+# Define a LIBSEC which doesn't include libdbm and xp.
+LIBSECNAME=$(MCOM_LIBDIR)/libsec/$(NSOBJDIR_NAME)/libsec-$(WHICHA).$(LIB_SUFFIX)
+ifndef LIBSECOBJS
+LIBSEC1=$(LIBSECNAME)
+else
+LIBSEC1=$(LIBSECOBJS)
+endif
+
+ifdef PRODUCT_IS_DIRECTORY_SERVER
+ DAEMONLIB=
+else
+ DAEMONLIB=$(OBJDIR)/lib/libhttpdaemon.a
+endif
+
+DEPLIBS = ${DAEMONLIB} $(OBJDIR)/lib/libsi18n.a $(ADMLIB) $(LDAPSDK_DEP)
+
+ifdef FORTEZZA
+LIBSEC1 += $(NSCP_DISTDIR)/lib/libci.$(LIB_SUFFIX)
+endif
+
+DEPLINK = ${DAEMONLIB} $(OBJDIR)/lib/libsi18n.a
+ifneq ($(BUILD_MODULE), HTTP_PERSONAL)
+DEPLINK += $(OBJDIR)/lib/libmsgdisp.a
+endif
+DEPLINK += $(SOLINK) $(LDAPLINK) $(NSPRLINK) $(SOLINK2)
+
+# Relative to the directory that contains the .so
+BUILTDIR = .
+
+ifndef NO_VERITY
+
+ifeq ($(DO_SEARCH), yes)
+ifdef VERITY_TASKSTUB
+TASKSTUB = ./taskstub.o
+else
+TASKSTUB =
+endif
+
+ifndef VERITY_SOLINK
+VERITY_SOLINK=$(TASKSTUB) -L. $(addprefix -l, $(VERITY_LIBNAMES))
+endif
+
+VERITYDEP=$(addprefix $(OBJDIR)/, $(VERITYOBJNAMES) $(TASKSTUB))
+
+$(VERITYDEP) : $(LIBVERITY)
+ cp $(LIBVERITY) $(VERITY_TASKSTUB) $(OBJDIR)
+
+DEPLINK += $(VERITY_SOLINK)
+DEPLIBS += $(VERITYDEP)
+endif
+
+endif
+
+SERVLIBS = $(addprefix $(OBJDIR)/lib/, libadmin.a libframe.a libaccess.a \
+ libldapu.a libbase.a libsi18n.a)
+SERVLIB_DIRS = $(addprefix $(OBJDIR)/lib/, libadmin frame libaccess base \
+ ldaputil libmsgdisp libsi18n)
+SERVLIB_OBJS = $(subst $(OBJDIR)/,$(BUILTDIR)/, \
+ $(filter-out $(OBJDIR)/lib/libadmin/nsnews.o, \
+ $(wildcard $(addsuffix /*.o, $(SERVLIB_DIRS)))))
+
+MOCHA=$(NSCP_DISTDIR)/lib/mocha.a
+
+# Removed for ns-security integration
+#NSLIBS = $(SECLIB) $(LIBSSLIO)
+
+ADMLIB_LIBS = $(SERVLIBS) $(NSLIBS)
+
+mocha:
+ cd $(MCOM_ROOT)/mocha; $(MAKE) export $(NSDEFS)
+
+
+admobjs:
+ifeq ($(ARCH), HPUX)
+ cd $(OBJDIR)/httpd-lib/nspr20; $(AR) x $(LIBNSPR)
+endif
+ cd $(OBJDIR)/httpd-lib/sslio; $(AR) x $(LIBSSLIO)
+ifndef NSPR20
+ cd $(OBJDIR)/httpd-lib/mocha; $(AR) x $(MOCHA)
+endif
+ cd $(OBJDIR)/httpd-lib/libdbm; $(AR) x $(LIBDBM)
+ cd $(OBJDIR)/httpd-lib/xp; $(AR) x $(LIBXP)
+ cd $(OBJDIR)/httpd-lib/libdbm; $(AR) x $(LIBDBM)
+ cd $(OBJDIR)/httpd-lib/xp; $(AR) x $(LIBXP)
+ rm -f $(addprefix $(OBJDIR)/httpd-lib/xp/, xp_time.o xplocale.o \
+ xp_cntxt.o)
+
+#$(LDAPOBJNAME): ldapobjs
+
+#ldapobjs:
+# (cd $(OBJDIR); rm -f $(LDAPOBJNAME))
+# cp $(LIBLDAP) $(OBJDIR)
+
+# Removed for ns-security integration.
+#OBJRULES += ldapobjs
+
+# Removed the httpd-lib from link for ns-security integration.
+#ADMOBJS=$(SERVLIB_OBJS) $(BUILTDIR)/httpd-lib/*/*.o
+#OBJRULES += admobjs
+ADMLIB=$(OBJDIR)/$(SONAME)
+
+$(ADMLIB): $(ADMLIB_LIBS)
+ifeq ($(ARCH), IRIX)
+ ifeq ($(USE_N32), 1) # no -objectlist any more
+ cd $(OBJDIR) ; \
+ $(LINK_DLL) \
+ $(SERVLIB_OBJS) $(ADM_EXTRA)
+ else
+ echo "$(SERVLIB_OBJS)" > /tmp/objectlist
+ tr ' ' '\012' < /tmp/objectlist > /tmp/objectlist.NEW
+ mv /tmp/objectlist.NEW /tmp/objectlist
+ cd $(OBJDIR) ; \
+ $(LINK_DLL) \
+ -objectlist /tmp/objectlist $(ADM_EXTRA)
+ rm /tmp/objectlist
+ endif
+else
+ cd $(OBJDIR) ; \
+ $(LINK_DLL) \
+ $(SERVLIB_OBJS) $(ADM_EXTRA)
+endif
+
+
+endif
diff --git a/include/Makefile b/include/Makefile
new file mode 100644
index 00000000..40e9f063
--- /dev/null
+++ b/include/Makefile
@@ -0,0 +1,85 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Makefile for netsite.h
+
+MCOM_ROOT = ../..
+MODULE=netsiteInclude
+
+include ../nsdefs.mk
+
+HDRDEST=$(OBJDIR)/include
+
+NSPRDEST=$(HDRDEST)
+NSPRHDRS= \
+ prio.h \
+ prlong.h \
+ prtypes.h \
+ prtime.h \
+ prthread.h \
+ prinrval.h \
+ md/prcpucfg.h \
+ obsolete/protypes.h
+
+NSPRBINS=$(addprefix $(NSPRDEST)/, $(NSPRHDRS))
+
+PREFIX=copyrght.h
+
+
+NOSTDSTRIP=true
+NOSTDDEPEND=true
+
+HDRS=netsite.h version.h
+
+BINS=$(addprefix $(HDRDEST)/,$(HDRS))
+
+all: stuff nspr
+
+strip:
+depend:
+
+include ../nsconfig.mk
+
+ifeq ($(NSAPI_CAPABLE), true)
+
+stuff: $(HDRDEST) $(BINS) sub-hdrs
+
+$(HDRDEST):
+ mkdir -p $(HDRDEST)
+
+ifeq ($(PRODUCT), "Netscape Proxy Server")
+sub-hdrs:
+ cd base; gmake
+ cd frame; gmake
+ cd libproxy; gmake
+else
+sub-hdrs:
+ cd base; gmake
+ cd frame; gmake
+endif
+
+$(HDRDEST)/%.h: %.h
+ cat $(PREFIX) $< > $(HDRDEST)/$*.h
+
+else
+stuff:
+
+endif
+
+$(NSPRDEST):
+ mkdir -p $(NSPRDEST)
+
+$(NSPRDEST)/md: $(NSPRDEST)
+ mkdir -p $(NSPRDEST)/md
+
+$(NSPRDEST)/obsolete: $(NSPRDEST)
+ mkdir -p $(NSPRDEST)/obsolete
+
+$(NSPRDEST)/%.h:
+ cp $(NSCP_DISTDIR)/include/nspr20/pr/$*.h $(NSPRDEST)/$*.h
+
+nspr: $(NSPRDEST)/md $(NSPRDEST)/obsolete $(NSPRBINS)
diff --git a/include/base/Makefile b/include/base/Makefile
new file mode 100644
index 00000000..9f2f6a35
--- /dev/null
+++ b/include/base/Makefile
@@ -0,0 +1,40 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Makefile for netsite.h
+
+MCOM_ROOT = ../../..
+MODULE=netsiteIncludeBase
+
+include ../../nsdefs.mk
+
+HDRDEST=$(OBJDIR)/include/base
+
+PREFIX=../copyrght.h
+
+
+NOSTDSTRIP=true
+NOSTDDEPEND=true
+
+#HDRS=$(wildcard *.h)
+HDRS=daemon.h cinfo.h crit.h ereport.h buffer.h net.h pblock.h sem.h session.h shexp.h shmem.h systhr.h util.h file.h pool.h regexp.h systems.h
+
+
+BINS=$(addprefix $(HDRDEST)/,$(HDRS))
+
+all: $(HDRDEST) $(BINS)
+
+$(HDRDEST):
+ mkdir -p $(HDRDEST)
+
+strip:
+depend:
+
+include ../../nsconfig.mk
+
+$(HDRDEST)/%.h: %.h
+ cat $(PREFIX) $< > $(HDRDEST)/$*.h
diff --git a/include/base/crit.h b/include/base/crit.h
new file mode 100644
index 00000000..1ff7e957
--- /dev/null
+++ b/include/base/crit.h
@@ -0,0 +1,209 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef BASE_CRIT_H
+#define BASE_CRIT_H
+
+#ifndef NOINTNSAPI
+#define INTNSAPI
+#endif /* !NOINTNSAPI */
+
+/*
+ * crit.h: Critical section abstraction. Used in threaded servers to protect
+ * areas where two threads can interfere with each other.
+ *
+ * Condvars are condition variables that are used for thread-thread
+ * synchronization.
+ *
+ * Rob McCool
+ */
+
+#ifndef NETSITE_H
+#include "netsite.h"
+#endif /* !NETSITE_H */
+
+/* Define C interface */
+#ifndef PUBLIC_BASE_CRIT_H
+#include "public/base/crit.h"
+#endif /* !PUBLIC_BASE_CRIT_H */
+
+/* Define C++ interface */
+#ifdef __cplusplus
+
+#ifndef BASE_NSASSERT_H
+#include "nsassert.h"
+#endif /* !BASE_NSASSERT_H */
+
+#ifndef prmon_h___
+#include "prmon.h"
+#endif /* !prmon_h___ */
+
+class NSAPI_PUBLIC CriticalSection
+{
+public:
+ CriticalSection();
+ ~CriticalSection();
+ void Acquire(){PR_EnterMonitor(_crtsec);}
+ void Release(){PR_ExitMonitor(_crtsec);}
+
+private:
+ PRMonitor *_crtsec;
+};
+
+inline CriticalSection::CriticalSection():_crtsec(0)
+{
+ _crtsec = PR_NewMonitor();
+ NS_ASSERT(_crtsec);
+}
+
+inline CriticalSection::~CriticalSection()
+{
+ if (_crtsec)
+ PR_DestroyMonitor(_crtsec);
+}
+
+class SafeLock {
+ public:
+ SafeLock (CriticalSection&); // acquire lock
+ ~SafeLock (); // release lock
+ private:
+ CriticalSection& lock;
+};
+
+inline SafeLock::SafeLock (CriticalSection& _lock) : lock(_lock)
+{
+ lock.Acquire();
+}
+
+inline SafeLock::~SafeLock ()
+{
+ lock.Release();
+}
+#endif /* __cplusplus */
+
+/* --- Begin function prototypes --- */
+
+#ifdef INTNSAPI
+
+NSPR_BEGIN_EXTERN_C
+
+/* ASSERT function only */
+NSAPI_PUBLIC int crit_owner_is_me(CRITICAL id);
+
+/*
+ * INTcrit_init creates and returns a new critical section variable. At the
+ * time of creation no one has entered it.
+ */
+NSAPI_PUBLIC CRITICAL INTcrit_init(void);
+
+/*
+ * INTcrit_enter enters a critical section. If someone is already in the
+ * section, the calling thread is blocked until that thread exits.
+ */
+NSAPI_PUBLIC void INTcrit_enter(CRITICAL id);
+
+
+/*
+ * INTcrit_exit exits a critical section. If another thread is blocked waiting
+ * to enter, it will be unblocked and given ownership of the section.
+ */
+NSAPI_PUBLIC void INTcrit_exit(CRITICAL id);
+
+
+/*
+ * INTcrit_terminate removes a previously allocated critical section variable.
+ */
+NSAPI_PUBLIC void INTcrit_terminate(CRITICAL id);
+
+
+/*
+ * INTcondvar_init initializes and returns a new condition variable. You
+ * must provide a critical section to be associated with this condition
+ * variable.
+ */
+NSAPI_PUBLIC CONDVAR INTcondvar_init(CRITICAL id);
+
+
+/*
+ * INTcondvar_wait blocks on the given condition variable. The calling thread
+ * will be blocked until another thread calls INTcondvar_notify on this variable.
+ * The caller must have entered the critical section associated with this
+ * condition variable prior to waiting for it.
+ */
+NSAPI_PUBLIC void INTcondvar_wait(CONDVAR cv);
+NSAPI_PUBLIC void condvar_timed_wait(CONDVAR _cv, long secs);
+
+
+/*
+ * INTcondvar_notify awakens any threads blocked on the given condition
+ * variable. The caller must have entered the critical section associated
+ * with this variable first.
+ */
+NSAPI_PUBLIC void INTcondvar_notify(CONDVAR cv);
+
+/*
+ * INTcondvar_notifyAll awakens all threads blocked on the given condition
+ * variable. The caller must have entered the critical section associated
+ * with this variable first.
+ */
+NSAPI_PUBLIC void INTcondvar_notifyAll(CONDVAR cv);
+
+/*
+ * INTcondvar_terminate frees the given previously allocated condition variable
+ */
+NSAPI_PUBLIC void INTcondvar_terminate(CONDVAR cv);
+
+
+/*
+ * Create a counting semaphore.
+ * Return non-zero on success, 0 on failure.
+ */
+NSAPI_PUBLIC COUNTING_SEMAPHORE INTcs_init(int initial_count);
+
+/*
+ * Destroy a counting semaphore
+ */
+NSAPI_PUBLIC void INTcs_terminate(COUNTING_SEMAPHORE csp);
+
+/*
+ * Wait to "enter" the semaphore.
+ * Return 0 on success, -1 on failure.
+ */
+NSAPI_PUBLIC int INTcs_wait(COUNTING_SEMAPHORE csp);
+
+/*
+ * Enter the semaphore if the count is > 0. Otherwise return -1.
+ *
+ */
+NSAPI_PUBLIC int INTcs_trywait(COUNTING_SEMAPHORE csp);
+
+/*
+ * Release the semaphore- allowing a thread to enter.
+ * Return 0 on success, -1 on failure.
+ */
+NSAPI_PUBLIC int INTcs_release(COUNTING_SEMAPHORE csp);
+
+NSPR_END_EXTERN_C
+
+/* --- End function prototypes --- */
+
+#define crit_init INTcrit_init
+#define crit_enter INTcrit_enter
+#define crit_exit INTcrit_exit
+#define crit_terminate INTcrit_terminate
+#define condvar_init INTcondvar_init
+#define condvar_wait INTcondvar_wait
+#define condvar_notify INTcondvar_notify
+#define condvar_notifyAll INTcondvar_notifyAll
+#define condvar_terminate INTcondvar_terminate
+#define cs_init INTcs_init
+#define cs_terminate INTcs_terminate
+#define cs_wait INTcs_wait
+#define cs_trywait INTcs_trywait
+#define cs_release INTcs_release
+
+#endif /* INTNSAPI */
+
+#endif /* !BASE_CRIT_H */
diff --git a/include/base/dbtbase.h b/include/base/dbtbase.h
new file mode 100644
index 00000000..5f30d374
--- /dev/null
+++ b/include/base/dbtbase.h
@@ -0,0 +1,217 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#define LIBRARY_NAME "base"
+
+static char dbtbaseid[] = "$DBT: base referenced v1 $";
+
+#include "i18n.h"
+
+BEGIN_STR(base)
+ ResDef( DBT_LibraryID_, -1, dbtbaseid )/* extracted from dbtbase.h*/
+ ResDef( DBT_insufficientMemoryToCreateHashTa_, 1, "insufficient memory to create hash table" )/*extracted from cache.cpp*/
+ ResDef( DBT_insufficientMemoryToCreateHashTa_1, 2, "insufficient memory to create hash table" )/*extracted from cache.cpp*/
+ ResDef( DBT_cacheDestroyCacheTablesAppearCor_, 3, "cache_destroy: cache tables appear corrupt." )/*extracted from cache.cpp*/
+ ResDef( DBT_unableToAllocateHashEntry_, 4, "unable to allocate hash entry" )/*extracted from cache.cpp*/
+ ResDef( DBT_cacheInsertUnableToCreateCacheEn_, 5, "cache_insert: unable to create cache entry" )/*extracted from cache.cpp*/
+ ResDef( DBT_http10200OkNcontentTypeTextHtmlN_, 6, "HTTP/1.0 200 OK\nContent-type: text/html\n\n" )/*extracted from cache.cpp*/
+ ResDef( DBT_H2NetscapeCacheStatusReportH2N_, 7, "<H2>Netscape cache status report</H2>\n" )/*extracted from cache.cpp*/
+ ResDef( DBT_noCachesOnSystemP_, 8, "No caches on system<P>" )/*extracted from cache.cpp*/
+ ResDef( DBT_H2SCacheH2N_, 9, "<H2>%s cache</H2>\n" )/*extracted from cache.cpp*/
+ ResDef( DBT_cacheHitRatioDDFPNPN_, 10, "Cache hit ratio: %d/%d (%f)</P>\n</P>\n" )/*extracted from cache.cpp*/
+ ResDef( DBT_cacheSizeDDPNPN_, 11, "Cache size: %d/%d</P>\n</P>\n" )/*extracted from cache.cpp*/
+ ResDef( DBT_hashTableSizeDPNPN_, 12, "Hash table size: %d</P>\n</P>\n" )/*extracted from cache.cpp*/
+ ResDef( DBT_mruDPNlruDPN_, 13, "mru : %d</P>\nlru : %d</P>\n" )/*extracted from cache.cpp*/
+ ResDef( DBT_UlTableBorder4ThBucketThThAddres_, 14, "<UL><TABLE BORDER=4> <TH>Bucket</TH> <TH>Address</TH> <TH>Key</TH> <TH>Access Count</TH> <TH>Delete</TH> <TH>Next</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>Data</TH>\n" )/*extracted from cache.cpp*/
+ ResDef( DBT_munmapFailedS_, 15, "munmap failed (%s)" )/*extracted from buffer.cpp*/
+ ResDef( DBT_munmapFailedS_1, 16, "munmap failed (%s)" )/*extracted from buffer.cpp*/
+ ResDef( DBT_closeFailedS_, 17, "close failed (%s)" )/*extracted from buffer.cpp*/
+ ResDef( DBT_daemonUnableToForkNewProcessSN_, 18, "daemon: unable to fork new process (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_daemonSetsidFailedSN_, 19, "daemon: setsid failed (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_daemonCanTLogPidToSSN_, 20, "daemon: can't log pid to %s (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_warningCouldNotSetGroupIdToDSN_, 21, "warning: could not set group id to %d (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_warningCouldNotSetUserIdToDSN_, 22, "warning: could not set user id to %d (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_warningDaemonIsRunningAsSuperUse_, 23, "warning: daemon is running as super-user\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_couldNotDetermineCurrentUserName_, 24, "could not determine current user name\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_errorChrootToSFailedSN_, 25, "error: chroot to %s failed (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_AddressS_, 27, ", address %s" )/*extracted from daemon.cpp*/
+ ResDef( DBT_warningStatisticsDisabledSN_, 28, "warning: statistics disabled (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_securityHandshakeTimedOutForPidD_, 29, "security handshake timed out for pid %d" )/*extracted from daemon.cpp*/
+ ResDef( DBT_warningStatisticsDisabledSN_1, 30, "warning: statistics disabled (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_secureHandshakeFailedCodeDN_, 31, "secure handshake failed (code %d)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_acceptFailedS_, 32, "accept failed (%s)" )/*extracted from daemon.cpp*/
+ ResDef( DBT_warningStatisticsDisabledSN_2, 33, "warning: statistics disabled (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_selectThreadMiss_, 34, "select thread miss" )/*extracted from daemon.cpp*/
+ ResDef( DBT_keepaliveWorkerAwokenWithNoWorkT_, 35, "keepalive worker awoken with no work to do" )/*extracted from daemon.cpp*/
+ ResDef( DBT_couldNotCreateNewThreadDS_, 36, "could not create new thread: %d (%s)" )/*extracted from daemon.cpp*/
+ ResDef( DBT_waitForSemaSucceededButNothingTo_, 37, "wait for sema succeeded, but nothing to dequeue" )/*extracted from daemon.cpp*/
+ ResDef( DBT_queueSemaCreationFailure_, 38, "queue-sema creation failure" )/*extracted from daemon.cpp*/
+ ResDef( DBT_errorGettingProcessorInfoForProc_, 39, "error getting processor info for processor %d" )/*extracted from daemon.cpp*/
+ ResDef( DBT_errorBindingToProcessorD_, 40, "Error binding to processor %d" )/*extracted from daemon.cpp*/
+ ResDef( DBT_boundProcessDToProcessorD_, 41, "bound process %d to processor %d" )/*extracted from daemon.cpp*/
+ ResDef( DBT_netscapeServerIsNotExplicitlyBin_, 42, "Netscape server is not explicitly binding to any processors." )/*extracted from daemon.cpp*/
+ ResDef( DBT_cacheMonitorExited_, 43, "cache monitor exited" )/*extracted from daemon.cpp*/
+ ResDef( DBT_cacheBatchUpdateDaemonExited_, 44, "cache batch update daemon exited" )/*extracted from daemon.cpp*/
+ ResDef( DBT_usingSingleThreadedAccepts_, 45, "Using single threaded accepts." )/*extracted from daemon.cpp*/
+ ResDef( DBT_usingMultiThreadedAccepts_, 46, "Using multi threaded accepts." )/*extracted from daemon.cpp*/
+ ResDef( DBT_usingPartialSingleThreadedAccept_, 47, "Using partial single threaded accepts." )/*extracted from daemon.cpp*/
+ ResDef( DBT_thisMachineHasDProcessors_, 48, "This machine has %d processors." )/*extracted from daemon.cpp*/
+ ResDef( DBT_errorCallingThrSeconcurrencyDS_, 49, "Error calling thr_seconcurrency(%d)- (%s)" )/*extracted from daemon.cpp*/
+ ResDef( DBT_setConncurrencyToD_, 50, "Set conncurrency to %d." )/*extracted from daemon.cpp*/
+ ResDef( DBT_warningNetscapeExecutableAndLibr_, 51, "WARNING! netscape executable and library have different versions.\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_seminitFailedSN_, 54, "seminit failed (%s)\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_thisBetaSoftwareHasExpiredN_, 55, "This beta software has expired.\n" )/*extracted from daemon.cpp*/
+ ResDef( DBT_cacheMonitorRespawned_, 56, "Cache monitor respawned" )/*extracted from daemon.cpp*/
+ ResDef( DBT_cacheBatchUpdateDaemonRespawned_, 57, "Cache batch update daemon respawned" )/*extracted from daemon.cpp*/
+ ResDef( DBT_canTFindEmptyStatisticsSlot_, 58, "can't find empty statistics slot" )/*extracted from daemon.cpp*/
+ ResDef( DBT_canTForkNewProcessS_, 59, "can't fork new process (%s)" )/*extracted from daemon.cpp*/
+ ResDef( DBT_assertFailedSN_, 60, "assert failed! %s\n" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrTableInit_, 61, "mr_table_init()" )/*extracted from multiplex.c*/
+ ResDef( DBT_mallocFailed_, 62, "malloc failed" )/*extracted from multiplex.c*/
+ ResDef( DBT_mallocFailed_1, 63, "malloc failed!" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrAddIoDTypeDFileD_, 64, "mr_add_io(%d, type %d, file %d)" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrAddIoStage1_, 65, "mr_add_io - stage 1" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrAddIoStage2_, 66, "mr_add_io - stage 2" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrAddIoFoundInvalidIoTypeD_, 67, "mr_add_io found invalid IO type %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrAddIoAddingTimeout_, 68, "mr_add_io - adding timeout" )/*extracted from multiplex.c*/
+ ResDef( DBT_outOfMemoryN_, 69, "Out of memory!\n" )/*extracted from multiplex.c*/
+ ResDef( DBT_doneWithMrAddIo_, 70, "done with mr_add_io" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrDelIoDTypeDFileD_, 71, "mr_del_io(%d, type %d, file %d)" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrDelIoFoundInvalidIoTypeD_, 72, "mr_del_io found invalid IO type %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrLookupIoD_, 73, "mr_lookup_io(%d)" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrAsyncIoDDBytesFileD_, 74, "mr_async_io(%d, %d bytes, file %d)" )/*extracted from multiplex.c*/
+ ResDef( DBT_mallocFailureAddingAsyncIo_, 75, "malloc failure adding async IO" )/*extracted from multiplex.c*/
+ ResDef( DBT_errorAddingAsyncIo_, 76, "Error adding async io!" )/*extracted from multiplex.c*/
+ ResDef( DBT_cannotSeekForRead_, 77, "Cannot seek for read!" )/*extracted from multiplex.c*/
+ ResDef( DBT_readFailureDS_, 78, "read failure! (%d, %s)" )/*extracted from multiplex.c*/
+ ResDef( DBT_doReadReadDBytesForFileD_, 79, "do_read read %d bytes for file %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_cannotSeekForWrite_, 80, "Cannot seek for write!" )/*extracted from multiplex.c*/
+ ResDef( DBT_writevFailureDS_, 81, "writev failure! (%d, %s)" )/*extracted from multiplex.c*/
+ ResDef( DBT_writeFailureDS_, 82, "write failure! (%d, %s)" )/*extracted from multiplex.c*/
+ ResDef( DBT_doWriteWroteDBytesForFileD_, 83, "do_write wrote %d bytes for file %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_doTimeoutMrpD_, 84, "do_timeout(mrp %d)" )/*extracted from multiplex.c*/
+ ResDef( DBT_doTimeoutFoundIoTimerDTimeD_, 85, "do_timeout: found IO (timer=%d, time=%d)" )/*extracted from multiplex.c*/
+ ResDef( DBT_errorDeletingIo_, 86, "error deleting io" )/*extracted from multiplex.c*/
+ ResDef( DBT_timeoutCallbackFailureForDN_, 87, "timeout callback failure for %d\n" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrGetEventDOutstandingIoD_, 88, "mr_get_event(%d) - outstanding io %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrGetEventWaitingForReadsOnFd_, 89, "mr_get_event: Waiting for reads on FD:" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrGetEventWaitingForWritesOnFd_, 90, "mr_get_event: Waiting for writes on FD:" )/*extracted from multiplex.c*/
+ ResDef( DBT_TD_, 91, "\t%d" )/*extracted from multiplex.c*/
+ ResDef( DBT_TD_1, 92, "\t%d" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrGetEventSetNoTimeout_, 93, "mr_get_event set no timeout" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrGetEventSetTimeoutToDDSec_, 94, "mr_get_event set timeout to: %d.%d sec" )/*extracted from multiplex.c*/
+ ResDef( DBT_errorInSelectDS_, 95, "error in select (%d, %s)" )/*extracted from multiplex.c*/
+ ResDef( DBT_mrGetEventSelectFoundD_, 96, "mr_get_event() - select found %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_errorLookingUpIoFdD_, 97, "error looking up IO fd %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_readFailedForFdD_, 98, "read failed for fd %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_errorDeletingIo_1, 99, "error deleting io" )/*extracted from multiplex.c*/
+ ResDef( DBT_callbackFailureForDN_, 100, "callback failure for %d\n" )/*extracted from multiplex.c*/
+ ResDef( DBT_errorLookingUpIoFdD_1, 101, "error looking up IO fd %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_writingHeaderLenDWritelenDTotalD_, 102, "writing: header len %d, writelen %d, total %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_writeFailedForFdD_, 103, "write failed for fd %d" )/*extracted from multiplex.c*/
+ ResDef( DBT_errorDeletingIo_2, 104, "error deleting io" )/*extracted from multiplex.c*/
+ ResDef( DBT_callbackFailureForDN_1, 105, "callback failure for %d\n" )/*extracted from multiplex.c*/
+ ResDef( DBT_errorCreatingDnsCache_, 106, "Error creating dns cache" )/*extracted from dns_cache.cpp*/
+ ResDef( DBT_dnsCacheInitHashSize0UsingD_, 107, "dns_cache_init: hash_size <= 0, using %d" )/*extracted from dns_cache.cpp*/
+ ResDef( DBT_dnsCacheInitCacheSizeDUsingD_, 108, "dns_cache_init: cache-size <= %d, using %d" )/*extracted from dns_cache.cpp*/
+ ResDef( DBT_dnsCacheInitCacheSizeIsDIsTooLar_, 109, "dns_cache_init: cache-size is %d is too large, using %d." )/*extracted from dns_cache.cpp*/
+ ResDef( DBT_dnsCacheInitExpireTime0UsingD_, 110, "dns_cache_init: expire_time <= 0, using %d" )/*extracted from dns_cache.cpp*/
+ ResDef( DBT_dnsCacheInitExpireIsDIsTooLargeU_, 111, "dns_cache_init: expire is %d is too large, using %d seconds." )/*extracted from dns_cache.cpp*/
+ ResDef( DBT_errorCreatingDnsCache_1, 112, "Error creating dns cache" )/*extracted from dns_cache.cpp*/
+ ResDef( DBT_dnsCacheInsertErrorAllocatingEnt_, 113, "dns-cache-insert: Error allocating entry" )/*extracted from dns_cache.cpp*/
+ ResDef( DBT_dnsCacheInsertMallocFailure_, 114, "dns-cache-insert: malloc failure" )/*extracted from dns_cache.cpp*/
+ ResDef( DBT_successfulServerStartup_, 115, "successful server startup" )/*extracted from ereport.cpp*/
+ ResDef( DBT_SBS_, 116, "%s B%s" )/*extracted from ereport.cpp*/
+ ResDef( DBT_netscapeExecutableAndSharedLibra_, 117, "Netscape executable and shared library have different versions" )/*extracted from ereport.cpp*/
+ ResDef( DBT_executableVersionIsS_, 118, " executable version is %s" )/*extracted from ereport.cpp*/
+ ResDef( DBT_sharedLibraryVersionIsS_, 119, " shared library version is %s" )/*extracted from ereport.cpp*/
+ ResDef( DBT_errorReportingShuttingDown_, 120, "error reporting shutting down" )/*extracted from ereport.cpp*/
+ ResDef( DBT_warning_, 121, "warning" )/*extracted from ereport.cpp*/
+ ResDef( DBT_config_, 122, "config" )/*extracted from ereport.cpp*/
+ ResDef( DBT_security_, 123, "security" )/*extracted from ereport.cpp*/
+ ResDef( DBT_failure_, 124, "failure" )/*extracted from ereport.cpp*/
+ ResDef( DBT_catastrophe_, 125, "catastrophe" )/*extracted from ereport.cpp*/
+ ResDef( DBT_info_, 126, "info" )/*extracted from ereport.cpp*/
+ ResDef( DBT_verbose_, 127, "verbose" )/*extracted from ereport.cpp*/
+ ResDef( DBT_eventHandlerFailedToWaitOnEvents_, 128, "event_handler:Failed to wait on events %s" )/*extracted from eventhandler.cpp*/
+ ResDef( DBT_couldNotWaitOnResumeEventEventS_, 129, "could not wait on resume event event (%s)" )/*extracted from eventhandler.cpp*/
+ ResDef( DBT_dlopenOfSFailedS_, 130, "dlopen of %s failed (%s)" )/*extracted from LibMgr.cpp*/
+ ResDef( DBT_dlopenOfSFailedS_1, 131, "dlopen of %s failed (%s)" )/*extracted from LibMgr.cpp*/
+ ResDef( DBT_theServerIsTerminatingDueToAnErr_, 132, "The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_terminatingTheServerS_, 133, "Terminating the server %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_killServerCannotOpenServerEventS_, 134, "kill_server:cannot open server event %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_killServerCannotSetServerEventS_, 135, "kill_server:cannot set server event %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_errorCouldNotGetSocketSN_, 136, "error: could not get socket (%s)\n" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_errorCouldNotSetSocketOptionSN_, 137, "error: could not set socket option (%s)\n" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_terminatingServiceErrorCouldNotB_, 138, "Terminating Service:error: could not bind to address %s port %d (%s)\n" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_terminatingServiceErrorCouldNotB_1, 139, "Terminating Service:error: could not bind to port %d (%s)\n" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_sethandlenoninheritableCouldNotD_, 140, "SetHandleNonInheritable: could not duplicate socket (%s)" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_sethandlenoninheritableClosingTh_, 141, "SetHandleNonInheritable: closing the original socket failed (%s)" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_couldNotSethandleinformationS_, 142, "Could not SetHandleInformation (%s)" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_terminatingServiceFailureCouldNo_, 143, "Terminating Service:Failure: Could not open statistics file (%s)\n" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_couldNotSetThreadLocalStorageVal_, 144, "Could not set Thread Local Storage Value for thread at slot %d" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_secureHandshakeFailedCodeDN_1, 145, "secure handshake failed (code %d)\n" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_acceptFailedDS_, 146, "accept failed %d (%s)" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_failedToPulseEventDS_, 147, "Failed to pulse Event %d %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_failedToSendMobgrowthEventToPare_, 148, "Failed to send MobGrowth Event to parent %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_pulsingMobrespawnEventD_, 149, "Pulsing MobRespawn Event %d" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_respawnThreadPoolToDD_, 150, "respawn thread pool to %d (%d)" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_couldNotOpenEventToSignalRotateA_, 151, "Could not open event to signal rotate application. Could not create the MoveLog event:%s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_failedToSendMovelogEventToRotate_, 152, "Failed to send MoveLog Event to rotate app %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_growingThreadPoolFromDToD_, 153, "growing thread pool from %d to %d" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_couldNotOpenTheServicecontrolman_, 154, "Could not open the ServiceControlManager, Error %d" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_startnetsiteserviceCouldNotOpenT_, 155, "StartNetsiteService:Could not open the service %s: Error %d" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_startnetsiteserviceCouldNotStart_, 156, "StartNetsiteService:Could not start the service %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_serviceStartupCouldNotAllocateSe_, 157, "Service Startup: Could not allocate security descriptor" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_serviceStartupCouldNotInitSecuri_, 158, "Service Startup: Could not init security descriptor" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_serviceStartupCouldNotSetTheSecu_, 159, "Service Startup: Could not set the security Dacl" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_terminatingServiceWinsockInitFai_, 160, "Terminating Service:WinSock init failed: %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_httpdServerStartupFailedS_, 161, "Httpd Server Startup failed: %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_canTFindEmptyStatisticsSlot_1, 162, "can't find empty statistics slot" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_ntDaemonCouldNotCreateNewThreadD_, 163, "NT daemon: could not create new thread %d" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_serviceStartupFailureTerminating_, 164, "Service Startup Failure. Terminating Service:Could not create event %d:%s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_serviceStartupErrorCouldNotCreat_, 165, "Service Startup Error. Could not create the MoveLog event:%s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_failedToWaitOnEventObjectsS_, 166, "Failed to wait on Event objects %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_failedToWaitOnEventObjectsS_1, 167, "Failed to wait on Event objects %s" )/*extracted from ntdaemon.cpp*/
+ ResDef( DBT_pipebufBuf2sdPipebufGrabIoErrorD_, 168, "pipebuf_buf2sd: pipebuf_grab IO_ERROR %d" )/*extracted from ntpipe.cpp*/
+ ResDef( DBT_poolInitMemoryPoolsDisabled_, 169, "pool-init: memory pools disabled" )/*extracted from pool.cpp*/
+ ResDef( DBT_poolInitFreeSize0UsingD_, 170, "pool-init: free_size <= 0, using %d" )/*extracted from pool.cpp*/
+ ResDef( DBT_poolCreateBlockOutOfMemory_, 171, "pool-create-block: out of memory" )/*extracted from pool.cpp*/
+ ResDef( DBT_poolCreateOutOfMemory_, 172, "pool-create: out of memory" )/*extracted from pool.cpp*/
+ ResDef( DBT_poolCreateOutOfMemory_1, 173, "pool-create: out of memory" )/*extracted from pool.cpp*/
+ ResDef( DBT_poolMallocOutOfMemory_, 174, "pool-malloc: out of memory" )/*extracted from pool.cpp*/
+ ResDef( DBT_freeUsedWherePermFreeShouldHaveB_, 175, "FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings." )/*extracted from pool.cpp*/
+ ResDef( DBT_regexErrorSRegexS_, 176, "regex error: %s (regex: '%s')" )/*extracted from regexp.cpp*/
+ ResDef( DBT_canTCreateIpcPipeS_, 177, "can't create IPC pipe (%s)" )/*extracted from thrconn.cpp*/
+ ResDef( DBT_writeToWakeupPipeFailedS_, 178, "write to wakeup pipe failed (%s)" )/*extracted from thrconn.cpp*/
+ ResDef( DBT_flushingDConnectionsCurrentDTotD_, 179, "flushing %d connections; current %d; tot %d" )/*extracted from thrconn.cpp*/
+ ResDef( DBT_acceptFailedS_1, 180, "accept failed (%s)" )/*extracted from thrconn.cpp*/
+ ResDef( DBT_errorCreatingTimeCache_, 181, "Error creating time cache" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_timeCacheCacheDisabled_, 182, "time-cache: cache disabled" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_timeCacheInitHashSizeDUsingDefau_, 183, "time_cache_init: hash_size < %d, using default, %d" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_timeCacheInitHashSizeDUsingDefau_1, 184, "time_cache_init: hash_size > %d, using default, %d" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_timeCacheInitCacheSizeDUsingDefa_, 185, "time_cache_init: cache_size < %d, using default, %d" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_timeCacheInitCacheSizeDUsingDefa_1, 186, "time_cache_init: cache_size > %d, using default, %d" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_errorAllocatingMemoryForTimeCach_, 187, "Error allocating memory for time_cache" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_errorAllocatingMemoryForTimeCach_1, 188, "Error allocating memory for time_cache entry" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_errorAllocatingMemoryForTimeCach_2, 189, "Error allocating memory for time_cache entry" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_errorInsertingNewTimeCacheEntry_, 190, "Error inserting new time_cache entry" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_errorAllocatingMemoryForTimeCach_3, 191, "Error allocating memory for time_cache" )/*extracted from time_cache.cpp*/
+ ResDef( DBT_csTerminateFailureS_, 192, "cs-terminate failure (%s)" )/*extracted from crit.cpp*/
+ ResDef( DBT_csInitFailureS_, 193, "cs-init failure (%s)" )/*extracted from crit.cpp*/
+ ResDef( DBT_csWaitFailureS_, 194, "cs-wait failure (%s)" )/*extracted from crit.cpp*/
+ ResDef( DBT_csPostFailureS_, 195, "cs-post failure (%s)" )/*extracted from crit.cpp*/
+ ResDef( DBT_unableToCreateNonblockingSocketS_, 196, "Unable to create nonblocking socket (%s)" )/*extracted from net.cpp*/
+ ResDef( DBT_errorCouldNotSetKeepaliveSN_, 197, "error: could not set keepalive (%s)\n" )/*extracted from net.cpp*/
+ ResDef( DBT_errorCouldNotSetRecvTimeoutSN_, 198, "error: could not set recv timeout (%s)\n" )/*extracted from net.cpp*/
+ ResDef( DBT_errorCouldNotSetSendTimeoutSN_, 199, "error: could not set send timeout (%s)\n" )/*extracted from net.cpp*/
+ ResDef( DBT_unableToCreateNonblockingSocketS_1, 200, "Unable to create nonblocking socket (%s)" )/*extracted from net.cpp*/
+ ResDef( DBT_semGrabFailedS_, 201, "sem_grab failed (%s)" )/*extracted from net.cpp*/
+ ResDef( DBT_semReleaseFailedS_, 202, "sem_release failed (%s)" )/*extracted from net.cpp*/
+ ResDef( DBT_semReleaseFailedS_1, 203, "sem_release failed (%s)" )/*extracted from net.cpp*/
+ ResDef( DBT_couldNotRemoveTemporaryDirectory_, 204, "Could not remove temporary directory %s, Error %d" )/*extracted from util.cpp*/
+ ResDef( DBT_couldNotRemoveTemporaryDirectory_1, 205, "Could not remove temporary directory %s, Error %d" )/*extracted from util.cpp*/
+END_STR(base)
diff --git a/include/base/ereport.h b/include/base/ereport.h
new file mode 100644
index 00000000..0c74e957
--- /dev/null
+++ b/include/base/ereport.h
@@ -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 **/
+#ifndef BASE_EREPORT_H
+#define BASE_EREPORT_H
+
+#ifndef NOINTNSAPI
+#define INTNSAPI
+#endif /* !NOINTNSAPI */
+
+/*
+ * ereport.h: Records transactions, reports errors to administrators, etc.
+ *
+ * Rob McCool
+ */
+
+#ifndef BASE_SESSION_H
+#include "session.h"
+#endif /* !BASE_SESSION_H */
+
+#ifndef PUBLIC_BASE_EREPORT_H
+#include "public/base/ereport.h"
+#endif /* !PUBLIC_BASE_EREPORT_H */
+
+/* --- Begin function prototypes --- */
+
+#ifdef INTNSAPI
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * INTereport logs an error of the given degree and formats the arguments with
+ * the printf() style fmt. Returns whether the log was successful. Records
+ * the current date.
+ */
+
+NSAPI_PUBLIC int INTereport(int degree, char *fmt, ...);
+NSAPI_PUBLIC int INTereport_v(int degree, char *fmt, va_list args);
+
+/*
+ * INTereport_init initializes the error logging subsystem and opens the static
+ * file descriptors. It returns NULL upon success and an error string upon
+ * error. If a userpw is given, the logs will be chowned to that user.
+ *
+ * email is the address of a person to mail upon catastrophic error. It
+ * can be NULL if no e-mail is desired. INTereport_init will not duplicate
+ * its own copy of this string; you must make sure it stays around and free
+ * it when you shut down the server.
+ */
+
+NSAPI_PUBLIC
+char *INTereport_init(char *err_fn, char *email, PASSWD pwuser, char *version);
+
+/*
+ * log_terminate closes the error and common log file descriptors.
+ */
+NSAPI_PUBLIC void INTereport_terminate(void);
+
+/* For restarts */
+NSAPI_PUBLIC SYS_FILE INTereport_getfd(void);
+
+NSPR_END_EXTERN_C
+
+/* --- End function prototypes --- */
+
+#define ereport INTereport
+#define ereport_v INTereport_v
+#define ereport_init INTereport_init
+#define ereport_terminate INTereport_terminate
+#define ereport_getfd INTereport_getfd
+
+#endif /* INTNSAPI */
+
+#endif /* !BASE_EREPORT_H */
diff --git a/include/base/eventhandler.h b/include/base/eventhandler.h
new file mode 100644
index 00000000..a68a231e
--- /dev/null
+++ b/include/base/eventhandler.h
@@ -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 **/
+/*
+ * eventhandler.h: Handle registration of event handlers
+ *
+ * This is a facility in the NT server to provide a way to register event
+ * handling functions. Often there is a need to send a control signal of some
+ * kind to the server. This could be a signal for the server to rotate its
+ * logs, or a signal to collect and return statistical information of some kind
+ * such as perfmon stats.
+ *
+ * This file specifies the structures and functions necessary to set up this
+ * kind of asynchronous special event handling.
+ *
+ * Aruna Victor 2/21/96
+ */
+
+#ifndef EVENTHANDLER_H
+#define EVENTHANDLER_H
+
+#include "netsite.h"
+
+/* ------------------------------ Structures ------------------------------ */
+
+/* EVENT_HANDLER specifies
+ 1. The name of the event. This is the event that the event handler will
+ create and wait on for a signal.
+ 2. The name of the function should be called to handle the event.
+ 3. The argument that should be passed to this function.
+ 4. The next EVENT_HANDLER on the list this structure is on. */
+
+typedef struct event_handler {
+ int event_number;
+ char *event_name;
+ void (*_event_handler)(void *);
+ void *argument;
+ struct event_handler *next;
+} EVENT_HANDLER;
+
+/* ------------------------------ Prototypes ------------------------------ */
+
+NSPR_BEGIN_EXTERN_C
+
+char *initialize_event_handler(char *serverid);
+
+char *terminate_event_handler();
+
+char *add_handler(char *event, void (*fn)(void *), void *arg);
+
+char *delete_handler(char *event);
+
+char *add_rotation_handler(char *event, void (*fn)(void *), void *arg);
+
+NSPR_END_EXTERN_C
+
+#endif /* !EVENTHANDLER */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/include/base/eventlog.h b/include/base/eventlog.h
new file mode 100644
index 00000000..a8dd6d27
--- /dev/null
+++ b/include/base/eventlog.h
@@ -0,0 +1,34 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+// EVENTLOG.H
+//
+// This file contains the defines that make NT an installable service.
+//
+// 1/12/95 aruna
+//
+
+// Functions in eventlog.c
+
+#ifndef _EVENTLOG_H_
+#define _EVENTLOG_H_
+
+#include "netsite.h"
+
+
+#if defined(XP_WIN32)
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC HANDLE InitializeLogging(char *szEventLogName);
+NSAPI_PUBLIC BOOL TerminateLogging(HANDLE hEventSource);
+NSAPI_PUBLIC BOOL LogErrorEvent(HANDLE hEventSource, WORD fwEventType, WORD fwCategory, DWORD IDEvent, LPTSTR chMsg, LPTSTR lpszMsg);
+
+NSPR_END_EXTERN_C
+
+#endif /* XP_WIN32 */
+
+
+#endif
diff --git a/include/base/file.h b/include/base/file.h
new file mode 100644
index 00000000..6447bb83
--- /dev/null
+++ b/include/base/file.h
@@ -0,0 +1,121 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef BASE_FILE_H
+#define BASE_FILE_H
+
+#ifndef NOINTNSAPI
+#define INTNSAPI
+#endif /* !NOINTNSAPI */
+
+/* GLOBAL FUNCTIONS:
+ * DESCRIPTION:
+ * system-specific functions for reading/writing files
+ */
+
+#ifndef NETSITE_H
+#include "../netsite.h"
+#endif /* !NETSITE_H */
+
+#ifndef PUBLIC_BASE_FILE_H
+#include "public/base/file.h"
+#endif /* !PUBLIC_BASE_FILE_H */
+
+/* --- Begin function prototypes --- */
+
+#ifdef INTNSAPI
+
+NSPR_BEGIN_EXTERN_C
+
+void INTsystem_errmsg_init(void);
+
+NSAPI_PUBLIC SYS_FILE INTsystem_fopenRO(char *path);
+NSAPI_PUBLIC SYS_FILE INTsystem_fopenWA(char *path);
+NSAPI_PUBLIC SYS_FILE INTsystem_fopenRW(char *path);
+NSAPI_PUBLIC SYS_FILE INTsystem_fopenWT(char *path);
+NSAPI_PUBLIC int INTsystem_fread(SYS_FILE fd, char *buf, int sz);
+NSAPI_PUBLIC int INTsystem_fwrite(SYS_FILE fd,char *buf,int sz);
+NSAPI_PUBLIC int INTsystem_fwrite_atomic(SYS_FILE fd, char *buf, int sz);
+NSAPI_PUBLIC int INTsystem_lseek(SYS_FILE fd, int off, int wh);
+NSAPI_PUBLIC int INTsystem_fclose(SYS_FILE fd);
+NSAPI_PUBLIC int INTsystem_stat(char *name, struct stat *finfo);
+NSAPI_PUBLIC int INTsystem_rename(char *oldpath, char *newpath);
+NSAPI_PUBLIC int INTsystem_unlink(char *path);
+NSAPI_PUBLIC int INTsystem_tlock(SYS_FILE fd);
+NSAPI_PUBLIC int INTsystem_flock(SYS_FILE fd);
+NSAPI_PUBLIC int INTsystem_ulock(SYS_FILE fd);
+
+#ifdef XP_WIN32
+NSAPI_PUBLIC SYS_DIR INTdir_open(char *path);
+NSAPI_PUBLIC SYS_DIRENT *INTdir_read(SYS_DIR ds);
+NSAPI_PUBLIC void INTdir_close(SYS_DIR ds);
+#endif /* XP_WIN32 */
+
+NSAPI_PUBLIC int INTdir_create_all(char *dir);
+
+/* --- OBSOLETE ----------------------------------------------------------
+ * The following macros/functions are obsolete and are only maintained for
+ * compatibility. Do not use them. 11-19-96
+ * -----------------------------------------------------------------------
+ */
+
+#ifdef XP_WIN32
+NSAPI_PUBLIC char *INTsystem_winsockerr(void);
+NSAPI_PUBLIC char *INTsystem_winerr(void);
+NSAPI_PUBLIC int INTsystem_pread(SYS_FILE fd, char *buf, int sz);
+NSAPI_PUBLIC int INTsystem_pwrite(SYS_FILE fd, char *buf, int sz);
+NSAPI_PUBLIC void INTfile_unix2local(char *path, char *p2);
+#endif /* XP_WIN32 */
+
+NSAPI_PUBLIC int INTsystem_nocoredumps(void);
+NSAPI_PUBLIC int INTfile_setinherit(SYS_FILE fd, int value);
+NSAPI_PUBLIC int INTfile_notfound(void);
+NSAPI_PUBLIC char *INTsystem_errmsg(void);
+NSAPI_PUBLIC int INTsystem_errmsg_fn(char **buff, size_t maxlen);
+
+NSPR_END_EXTERN_C
+
+#define system_errmsg_init INTsystem_errmsg_init
+#define system_fopenRO INTsystem_fopenRO
+#define system_fopenWA INTsystem_fopenWA
+#define system_fopenRW INTsystem_fopenRW
+#define system_fopenWT INTsystem_fopenWT
+#define system_fread INTsystem_fread
+#define system_fwrite INTsystem_fwrite
+#define system_fwrite_atomic INTsystem_fwrite_atomic
+#define system_lseek INTsystem_lseek
+#define system_fclose INTsystem_fclose
+#define system_stat INTsystem_stat
+#define system_rename INTsystem_rename
+#define system_unlink INTsystem_unlink
+#define system_tlock INTsystem_tlock
+#define system_flock INTsystem_flock
+#define system_ulock INTsystem_ulock
+#ifdef XP_WIN32
+#define dir_open INTdir_open
+#define dir_read INTdir_read
+#define dir_close INTdir_close
+#endif /* XP_WIN32 */
+#define dir_create_all INTdir_create_all
+
+/* Obsolete */
+#ifdef XP_WIN32
+#define system_winsockerr INTsystem_winsockerr
+#define system_winerr INTsystem_winerr
+#define system_pread INTsystem_pread
+#define system_pwrite INTsystem_pwrite
+#define file_unix2local INTfile_unix2local
+#endif /* XP_WIN32 */
+
+#define system_nocoredumps INTsystem_nocoredumps
+#define file_setinherit INTfile_setinherit
+#define file_notfound INTfile_notfound
+#define rtfile_notfound INTfile_notfound
+#define system_errmsg INTsystem_errmsg
+#define system_errmsg_fn INTsystem_errmsg_fn
+
+#endif /* INTNSAPI */
+
+#endif /* BASE_FILE_H */
diff --git a/include/base/fsmutex.h b/include/base/fsmutex.h
new file mode 100644
index 00000000..486f0f4c
--- /dev/null
+++ b/include/base/fsmutex.h
@@ -0,0 +1,94 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * fsmutex: Mutexes that are filesystem-based so they're available from more
+ * than one process and address space
+ *
+ * Rob McCool
+ */
+
+
+#ifndef FSMUTEX_H
+#define FSMUTEX_H
+
+#include "netsite.h"
+
+typedef void * FSMUTEX;
+
+
+/* ------------------------------ Prototypes ------------------------------ */
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ Flags to fsmutex_init.
+
+ FSMUTEX_VISIBLE makes a filesystem mutex which can be opened by other
+ programs or processes.
+
+ FSMUTEX_NEEDCRIT specifies that the fsmutex_lock and fsmutex_unlock
+ functions should also use a critical section to ensure that more than
+ one thread does not acquire the mutex at a time. If this flag is not
+ specified, it is up to the caller to ensure that only thread within a
+ process tries to acquire the lock at any given time.
+ */
+#define FSMUTEX_VISIBLE 0x01
+#define FSMUTEX_NEEDCRIT 0x02
+
+
+/*
+ fsmutex_init creates a new filesystem-based mutex. The resulting mutex
+ is part of the filesystem. The name and number parameters are used to
+ create a name for the mutex. If the FSMUTEX_VISIBLE flag is specified,
+ the mutex will be left in the filesystem for other programs and processes
+ to access. If a mutex with the given name/number combination already
+ exists, the calling process is allowed access to it. If the mutex does
+ not already exist, the mutex is created.
+
+ Returns NULL on failure, a void pointer to a fsmutex structure otherwise.
+ This fsmutex structure is local to the current process.
+ */
+NSAPI_PUBLIC FSMUTEX fsmutex_init(char *name, int number, int flags);
+
+/*
+ Sets the ownership of the underlying filesystem object to the given
+ uid and gid. Only effective if the server is running as root.
+ */
+#ifdef XP_UNIX
+#include <unistd.h>
+#ifdef __sony
+#include <sys/types.h>
+#endif
+NSAPI_PUBLIC void fsmutex_setowner(FSMUTEX fsm, uid_t uid, gid_t gid);
+#endif
+
+
+
+/*
+ fsmutex_terminate deletes a filesystem-based mutex. A mutex will only
+ be deleted when every process which has an open pointer to the mutex
+ calls this function.
+ */
+NSAPI_PUBLIC void fsmutex_terminate(FSMUTEX id);
+
+/*
+ fsmutex_lock attempts to acquire the given filesystem-based mutex. If
+ another process is holding the mutex, or if the FSMUTEX_NEEDCRIT flag
+ was passed to fsmutex_init and another thread in the current process is
+ holding the mutex, then the calling thread will block until the mutex
+ is available.
+ */
+NSAPI_PUBLIC void fsmutex_lock(FSMUTEX id);
+
+/*
+ fsmutex_unlock releases a filesystem-based mutex previously acquired
+ by fsmutex_lock.
+ */
+NSAPI_PUBLIC void fsmutex_unlock(FSMUTEX id);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/include/base/lexer.h b/include/base/lexer.h
new file mode 100644
index 00000000..129aa449
--- /dev/null
+++ b/include/base/lexer.h
@@ -0,0 +1,89 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __lexer_h
+#define __lexer_h
+
+#ifndef _POOL_H_
+#include "base/pool.h"
+#endif /* _POOL_H_ */
+
+/* Define error codes */
+#define LEXERR_MALLOC -1 /* insufficient dynamic memory */
+
+
+typedef struct LEXStream_s LEXStream_t;
+typedef int (*LEXStreamGet_t)(LEXStream_t *);
+struct LEXStream_s {
+ LEXStream_t * lst_next; /* link for "include" parent stream */
+ void * lst_strmid; /* client stream identifier */
+ LEXStreamGet_t lst_get; /* pointer to stream "get" function */
+ char * lst_buf; /* stream buffer pointer */
+ char * lst_cp; /* current position in buffer */
+ int lst_len; /* remaining bytes in buffer */
+ int lst_buflen; /* buffer length */
+ int lst_flags; /* bit flags */
+#define LST_FREEBUF 0x1 /* free lst_buf in stream destroy */
+};
+NSPR_BEGIN_EXTERN_C
+
+/* Functions in lexer.c */
+NSAPI_PUBLIC
+int lex_class_check(void * chtab, char code, unsigned long cbits);
+
+NSAPI_PUBLIC
+int lex_class_create(int classc, char * classv[], void **pchtab);
+
+NSAPI_PUBLIC void lex_class_destroy(void * chtab);
+
+NSAPI_PUBLIC
+LEXStream_t * lex_stream_create(LEXStreamGet_t strmget, void * strmid,
+ char * buf, int buflen);
+
+NSAPI_PUBLIC void lex_stream_destroy(LEXStream_t * lst);
+
+NSAPI_PUBLIC int
+lex_token_new(pool_handle_t * pool, int initlen, int growlen, void **token);
+
+NSAPI_PUBLIC int lex_token_start(void * token);
+
+NSAPI_PUBLIC
+char * lex_token_info(void * token, int * tdatalen, int * tbufflen);
+
+NSAPI_PUBLIC char * lex_token(void * token);
+
+NSAPI_PUBLIC void lex_token_destroy(void * token);
+
+NSAPI_PUBLIC
+char * lex_token_get(void * token, int * tdatalen, int * tbufflen);
+
+NSAPI_PUBLIC char * lex_token_take(void * token);
+
+NSAPI_PUBLIC
+int lex_token_append(void * token, int nbytes, char * src);
+
+NSAPI_PUBLIC
+int lex_next_char(LEXStream_t * lst, void * chtab, unsigned long cbits);
+
+NSAPI_PUBLIC
+int lex_scan_over(LEXStream_t * lst, void * chtab, unsigned long cbits,
+ void * token);
+
+NSAPI_PUBLIC
+int lex_scan_string(LEXStream_t * lst, void * token, int flags);
+
+NSAPI_PUBLIC
+int lex_scan_to(LEXStream_t * lst, void * chtab, unsigned long cbits,
+ void * token);
+
+NSAPI_PUBLIC
+int lex_skip_over(LEXStream_t * lst, void * chtab, unsigned long cbits);
+
+NSAPI_PUBLIC
+int lex_skip_to(LEXStream_t * lst, void * chtab, unsigned long cbits);
+
+NSPR_END_EXTERN_C
+
+#endif /* __lexer_h */
diff --git a/include/base/nterr.h b/include/base/nterr.h
new file mode 100644
index 00000000..55d1be22
--- /dev/null
+++ b/include/base/nterr.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Added function prototypes for nterror stuff.
+ *
+ * Robin Maxwell
+ */
+
+#ifndef _NTERR_H
+#define _NTERR_H
+NSPR_BEGIN_EXTERN_C
+
+char * FindError(int error);
+NSAPI_PUBLIC void HashNtErrors();
+
+NSPR_END_EXTERN_C
+
+#endif /* _NTERR_H */
diff --git a/include/base/nterrors.h b/include/base/nterrors.h
new file mode 100644
index 00000000..f9e4aa1f
--- /dev/null
+++ b/include/base/nterrors.h
@@ -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 **/
+/* DO NOT EDIT THIS FILE - it is automatically generated */
+
+typedef struct _NtError {
+ int ErrorNumber;
+ char *ErrorString;
+ struct _NtError *next;
+} NtError;
+
+NtError NtErrorStrings[] = {
+{ 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/include/base/plist.h b/include/base/plist.h
new file mode 100644
index 00000000..d9ab744f
--- /dev/null
+++ b/include/base/plist.h
@@ -0,0 +1,61 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _PLIST_H
+#define _PLIST_H
+
+#ifndef NOINTNSACL
+#define INTNSACL
+#endif /* !NOINTNSACL */
+
+/*
+ * TYPE: PList_t
+ *
+ * DESCRIPTION:
+ *
+ * This type defines a handle for a property list.
+ */
+
+#include "base/pool.h"
+
+#ifndef PUBLIC_NSACL_PLISTDEF_H
+#include "../public/nsacl/plistdef.h"
+#endif /* !PUBLIC_NSACL_PLISTDEF_H */
+
+#ifdef INTNSACL
+
+/* Functions in plist.c */
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC extern int PListAssignValue(PList_t plist, const char *pname,
+ const void *pvalue, PList_t ptype);
+NSAPI_PUBLIC extern PList_t PListCreate(pool_handle_t *mempool,
+ int resvprop, int maxprop, int flags);
+NSAPI_PUBLIC extern int PListDefProp(PList_t plist, int pindex,
+ const char *pname, const int flags);
+NSAPI_PUBLIC extern const void * PListDeleteProp(PList_t plist, int pindex, const char *pname);
+NSAPI_PUBLIC extern int PListFindValue(PList_t plist,
+ const char *pname, void **pvalue, PList_t *type);
+NSAPI_PUBLIC extern int PListInitProp(PList_t plist, int pindex, const char *pname,
+ const void *pvalue, PList_t ptype);
+NSAPI_PUBLIC extern PList_t PListNew(pool_handle_t *mempool);
+NSAPI_PUBLIC extern void PListDestroy(PList_t plist);
+NSAPI_PUBLIC extern int PListGetValue(PList_t plist,
+ int pindex, void **pvalue, PList_t *type);
+NSAPI_PUBLIC extern int PListNameProp(PList_t plist, int pindex, const char *pname);
+NSAPI_PUBLIC extern int PListSetType(PList_t plist, int pindex, PList_t type);
+NSAPI_PUBLIC extern int PListSetValue(PList_t plist,
+ int pindex, const void *pvalue, PList_t type);
+NSAPI_PUBLIC extern void PListEnumerate(PList_t plist, PListFunc_t *user_func,
+ void *user_data);
+NSAPI_PUBLIC extern PList_t
+PListDuplicate(PList_t plist, pool_handle_t *new_mempool, int flags);
+NSAPI_PUBLIC extern pool_handle_t *PListGetPool(PList_t plist);
+
+NSPR_END_EXTERN_C
+
+#endif /* INTNSACL */
+
+#endif /* _PLIST_H */
diff --git a/include/base/pool.h b/include/base/pool.h
new file mode 100644
index 00000000..bca055c7
--- /dev/null
+++ b/include/base/pool.h
@@ -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 **/
+#ifndef BASE_POOL_H
+#define BASE_POOL_H
+
+#ifndef NOINTNSAPI
+#define INTNSAPI
+#endif /* !NOINTNSAPI */
+
+/*
+ * pool.h
+ *
+ * Module for handling memory allocations.
+ *
+ * Notes:
+ * This module is used instead of the NSPR prarena module because the prarenas
+ * did not fit as cleanly into the existing server.
+ *
+ * Mike Belshe
+ * 10-02-95
+ *
+ */
+
+#ifdef MALLOC_POOLS
+
+#ifndef NETSITE_H
+#include "netsite.h"
+#endif /* !NETSITE_H */
+
+#ifndef BASE_PBLOCK_H
+#include "pblock.h"
+#endif /* !BASE_PBLOCK_H */
+
+#ifndef BASE_SESSION_H
+#include "session.h"
+#endif /* !BASE_SESSION_H */
+
+#ifndef FRAME_REQ_H
+#include "frame/req.h"
+#endif /* !FRAME_REQ_H */
+
+#ifndef PUBLIC_BASE_POOL_H
+#include "public/base/pool.h"
+#endif /* !PUBLIC_BASE_POOL_H */
+
+/* --- Begin function prototypes --- */
+
+#ifdef INTNSAPI
+
+NSPR_BEGIN_EXTERN_C
+
+int pool_internal_init(void);
+
+NSAPI_PUBLIC int INTpool_init(pblock *pb, Session *sn, Request *rq);
+
+#ifdef DEBUG_CACHES
+NSAPI_PUBLIC int INTpool_service_debug(pblock *pb, Session *sn, Request *rq);
+#endif
+
+NSAPI_PUBLIC pool_handle_t *INTpool_create(void);
+
+NSAPI_PUBLIC void INTpool_destroy(pool_handle_t *pool_handle);
+
+NSAPI_PUBLIC int INTpool_enabled(void);
+
+NSAPI_PUBLIC void *INTpool_malloc(pool_handle_t *pool_handle, size_t size );
+
+NSAPI_PUBLIC void INTpool_free(pool_handle_t *pool_handle, void *ptr );
+
+NSAPI_PUBLIC
+void *INTpool_calloc(pool_handle_t *pool_handle, size_t nelem, size_t elsize);
+
+NSAPI_PUBLIC
+void *INTpool_realloc(pool_handle_t *pool_handle, void *ptr, size_t size );
+
+NSAPI_PUBLIC
+char *INTpool_strdup(pool_handle_t *pool_handle, const char *orig_str );
+
+NSPR_END_EXTERN_C
+
+#define pool_init INTpool_init
+
+#ifdef DEBUG_CACHES
+#define pool_service_debug INTpool_service_debug
+#endif /* DEBUG_CACHES */
+
+#define pool_create INTpool_create
+#define pool_destroy INTpool_destroy
+#define pool_enabled INTpool_enabled
+#define pool_malloc INTpool_malloc
+#define pool_free INTpool_free
+#define pool_calloc INTpool_calloc
+#define pool_realloc INTpool_realloc
+#define pool_strdup INTpool_strdup
+
+#endif /* INTNSAPI */
+
+#endif /* MALLOC_POOLS */
+
+#endif /* !BASE_POOL_H_ */
diff --git a/include/base/rwlock.h b/include/base/rwlock.h
new file mode 100644
index 00000000..2111e97b
--- /dev/null
+++ b/include/base/rwlock.h
@@ -0,0 +1,54 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * rwlock.h: Shared/Exclusive lock abstraction.
+ *
+ * Sanjay Krishnamurthi
+ */
+#ifndef _BASE_RWLOCK_H_
+#define _BASE_RWLOCK_H_
+
+#include "netsite.h"
+#include "crit.h"
+
+NSPR_BEGIN_EXTERN_C
+
+typedef void* RWLOCK;
+
+/*
+ * rwlock_Init()
+ * creates and returns a new readwrite lock variable.
+ */
+NSAPI_PUBLIC RWLOCK rwlock_Init(void);
+
+/*
+ * rwlock_ReadLock()
+ */
+NSAPI_PUBLIC void rwlock_ReadLock(RWLOCK lock);
+
+/*
+ * rwlock_WriteLock()
+ */
+NSAPI_PUBLIC void rwlock_WriteLock(RWLOCK lock);
+
+/*
+ * rwlock_Unlock()
+ */
+NSAPI_PUBLIC void rwlock_Unlock(RWLOCK lock);
+
+/*
+ * rwlock_DemoteLock()
+ */
+NSAPI_PUBLIC void rwlock_DemoteLock(RWLOCK lock);
+
+/*
+ * rwlock_terminate removes a previously allocated RWLOCK variable.
+ */
+NSAPI_PUBLIC void rwlock_Terminate(RWLOCK lock);
+
+NSPR_END_EXTERN_C
+
+#endif /* _BASE_RWLOCK_H_ */
diff --git a/include/base/shexp.h b/include/base/shexp.h
new file mode 100644
index 00000000..f1a5aab6
--- /dev/null
+++ b/include/base/shexp.h
@@ -0,0 +1,114 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef BASE_SHEXP_H
+#define BASE_SHEXP_H
+
+#ifndef NOINTNSAPI
+#define INTNSAPI
+#endif /* !NOINTNSAPI */
+
+/*
+ * shexp.h: Defines and prototypes for shell exp. match routines
+ *
+ *
+ * This routine will match a string with a shell expression. The expressions
+ * accepted are based loosely on the expressions accepted by zsh.
+ *
+ * o * matches anything
+ * o ? matches one character
+ * o \ will escape a special character
+ * o $ matches the end of the string
+ * o [abc] matches one occurence of a, b, or c. The only character that needs
+ * to be escaped in this is ], all others are not special.
+ * o [a-z] matches any character between a and z
+ * o [^az] matches any character except a or z
+ * o ~ followed by another shell expression will remove any pattern
+ * matching the shell expression from the match list
+ * o (foo|bar) will match either the substring foo, or the substring bar.
+ * These can be shell expressions as well.
+ *
+ * The public interface to these routines is documented in
+ * public/base/shexp.h.
+ *
+ * Rob McCool
+ *
+ */
+
+/*
+ * Requires that the macro MALLOC be set to a "safe" malloc that will
+ * exit if no memory is available. If not under MCC httpd, define MALLOC
+ * to be the real malloc and play with fire, or make your own function.
+ */
+
+#ifndef NETSITE_H
+#include "../netsite.h"
+#endif /* !NETSITE_H */
+
+#ifndef OS_CTYPE_H
+#include <ctype.h> /* isalnum */
+#define OS_CTYPE_H
+#endif /* !OS_CTYPE_H */
+
+#ifndef OS_STRING_H
+#include <string.h> /* strlen */
+#define OS_STRING_H
+#endif /* !OS_STRING_H */
+
+/* See public/base/shexp.h or public/base/regexp.h concerning USE_REGEX */
+
+/*
+ * This little bit of nonsense is because USE_REGEX is currently
+ * supposed to be recognized only by the proxy. If that's the
+ * case, only the proxy should define USE_REGEX, but I'm playing
+ * it safe. XXXHEP 12/96
+ */
+#ifndef MCC_PROXY
+#ifdef USE_REGEX
+#define SAVED_USE_REGEX USE_REGEX
+#undef USE_REGEX
+#endif /* USE_REGEX */
+#endif /* !MCC_PROXY */
+
+#ifndef PUBLIC_BASE_SHEXP_H
+#include "public/base/shexp.h"
+#endif /* !PUBLIC_BASE_SHEXP_H */
+
+/* --- Begin function prototypes --- */
+
+#ifdef INTNSAPI
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC int INTshexp_valid(char *exp);
+
+NSAPI_PUBLIC int INTshexp_match(char *str, char *exp);
+
+NSAPI_PUBLIC int INTshexp_cmp(char *str, char *exp);
+
+NSAPI_PUBLIC int INTshexp_casecmp(char *str, char *exp);
+
+NSPR_END_EXTERN_C
+
+/* --- End function prototypes --- */
+
+#define shexp_valid INTshexp_valid
+#define shexp_match INTshexp_match
+#define shexp_cmp INTshexp_cmp
+#define shexp_casecmp INTshexp_casecmp
+
+#endif /* INTNSAPI */
+
+/* Restore USE_REGEX definition for non-proxy. See above. */
+#ifdef SAVED_USE_REGEX
+#define USE_REGEX SAVED_USE_REGEX
+#undef SAVED_USE_REGEX
+#endif /* SAVED_USE_REGEX */
+
+#ifdef USE_REGEX
+#include "base/regexp.h"
+#endif /* USE_REGEX */
+
+#endif /* !BASE_SHEXP_H */
diff --git a/include/base/systems.h b/include/base/systems.h
new file mode 100644
index 00000000..ca28c453
--- /dev/null
+++ b/include/base/systems.h
@@ -0,0 +1,565 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef BASE_SYSTEMS_H
+#define BASE_SYSTEMS_H
+
+#ifndef NOINTNSAPI
+#define INTNSAPI
+#endif /* !NOINTNSAPI */
+
+/*
+ * systems.h: Lists of defines for systems
+ *
+ * This sets what general flavor the system is (UNIX, etc.),
+ * and defines what extra functions your particular system needs.
+ */
+
+
+/* --- Begin common definitions for all supported platforms --- */
+
+#define DAEMON_ANY
+#define DAEMON_STATS
+
+/* --- End common definitions for all supported platforms --- */
+
+/* --- Begin platform-specific definitions --- */
+
+#if defined(AIX)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#define BSD_RLIMIT
+#undef BSD_SIGNALS
+/* AIX can handle really big shoes */
+#define DAEMON_LISTEN_SIZE 4096
+#define DAEMON_NEEDS_SEMAPHORE
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW|RTLD_GLOBAL
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAS_STATFS
+#define HAVE_ATEXIT
+#define HAVE_PW_R /* reent passwd routines */
+#define HAVE_STRERROR_R
+#define HAVE_STRTOK_R
+#define HAVE_TIME_R 2 /* arg count */
+#define HAVE_STRFTIME /* no cftime */
+#define JAVA_STATIC_LINK
+#undef NEED_CRYPT_H
+#define NEED_SETEID_PROTO /* setegid, seteuid */
+#define NEED_STRINGS_H /* for strcasecmp */
+#define NET_SOCKETS
+#define SA_HANDLER_T(x) (void (*)(int))x
+#if OSVERSION < 4210
+#define SA_NOCLDWAIT 0 /* AIX < 4.2 don't got this */
+#endif /* OSVERSION < 4210 */
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+#ifdef HW_THREADS
+#define THREAD_ANY
+#endif
+
+#elif defined(BSDI)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#define BSD_MAIL
+#define BSD_RLIMIT
+#define BSD_SIGNALS
+#define BSD_TIME
+#define DAEMON_UNIX_MOBRULE
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS (MAP_FILE | MAP_SHARED)
+#define HAS_STATFS
+#define HAVE_ATEXIT
+#undef NEED_CRYPT_PROTO
+#define NET_SOCKETS
+#ifndef NO_DOMAINNAME
+#define NO_DOMAINNAME
+#endif
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+#define JAVA_STATIC_LINK
+
+#elif defined(HPUX)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#undef BSD_RLIMIT
+#undef BSD_SIGNALS
+#ifdef MCC_PROXY
+#define DAEMON_NEEDS_SEMAPHORE
+#else
+#undef DAEMON_NEEDS_SEMAPHORE
+#endif
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_HPSHL
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_PRIVATE
+#define HAS_STATFS
+#define HAVE_ATEXIT
+#define HAVE_STRFTIME
+#define JAVA_STATIC_LINK
+#undef NEED_CRYPT_H
+#define NET_SOCKETS
+#define SA_HANDLER_T(x) (void (*)(int))x
+/* warning: mmap doesn't work under 9.04 */
+#define SHMEM_MMAP_FLAGS MAP_FILE | MAP_VARIABLE | MAP_SHARED
+
+#elif defined (IRIX)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#define BSD_RLIMIT
+#undef BSD_SIGNALS
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAS_STATVFS
+#define HAVE_ATEXIT
+#define HAVE_STRTOK_R
+#ifdef IRIX
+#define HAVE_TIME_R 2 /* arg count */
+#else
+#define HAVE_TIME_R 3 /* arg count */
+#define NEED_SETEID_PROTO /* setegid, seteuid */
+#endif
+#define JAVA_STATIC_LINK
+#define NEED_CRYPT_H
+#define NET_SOCKETS
+#define SA_HANDLER_T(x) (void (*)(int))x
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+#define THROW_HACK throw()
+
+#elif defined(NCR)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#undef BSD_RLIMIT
+/* #define DAEMON_NEEDS_SEMAPHORE */
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAS_STATVFS
+#define HAVE_ATEXIT
+#define HAVE_STRTOK_R
+#define JAVA_STATIC_LINK
+#define NEED_CRYPT_H
+#define NEED_FILIO
+#define NEED_GHN_PROTO
+#define NET_SOCKETS
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+
+#elif defined(NEC)
+
+#define ACCELERATOR_CACHE
+#define DNS_CACHE
+#define AUTH_DBM
+#undef BSD_RLIMIT
+#define DAEMON_NEEDS_SEMAPHORE
+#define DAEMON_UNIX_MOBRULE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW
+#define DLL_CAPABLE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAS_STATVFS
+#define HAVE_ATEXIT
+#define HAVE_STRTOK_R
+#define HAVE_TIME_R 2 /* arg count */
+#define JAVA_STATIC_LINK
+#define NEED_CRYPT_H
+#define NEED_FILIO
+#define NET_SOCKETS
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+
+#elif defined(OSF1)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#define BSD_RLIMIT
+#undef BSD_SIGNALS
+#define BSD_TIME
+#define DAEMON_NEEDS_SEMAPHORE
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAVE_ATEXIT
+#define HAVE_STRFTIME /* no cftime */
+#define HAVE_TIME_R 2 /* ctime_r arg count */
+#define NET_SOCKETS
+#define SA_HANDLER_T(x) (void (*)(int))x
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+
+#elif defined(SCO)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#undef BSD_RLIMIT
+#undef BSD_SIGNALS
+#define DAEMON_NEEDS_SEMAPHORE
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAS_STATVFS
+#define HAVE_ATEXIT
+#undef NEED_CRYPT_H
+#undef NEED_FILIO
+#undef NEED_GHN_PROTO
+#undef NEED_SETEID_PROTO /* setegid, seteuid */
+#define NET_SOCKETS
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+#define SA_HANDLER_T(x) (void (*)(int))x
+
+
+#elif defined(SNI)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#undef BSD_RLIMIT
+#define DAEMON_NEEDS_SEMAPHORE
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAS_STATVFS
+#define HAVE_ATEXIT
+#define JAVA_STATIC_LINK
+#define NEED_CRYPT_H
+#define NEED_FILIO
+#define NEED_SETEID_PROTO /* setegid, seteuid */
+#define NET_SOCKETS
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+#define TCPLEN_T size_t
+#define USE_PIPE
+/*
+ * define this if your C++ platform has separate inline functions for
+ * e.g. const char *strchr(const char *, char)
+ * and
+ * char *strchr(char *, char)
+ * and your compiler complains about this:
+ * func(const char *bla)
+ * {
+ * char *fasel = strchr(bla, '.');
+ * ....
+ * because it says that you cannot initialize a char * with a const char *
+ */
+#define HAS_CONSTVALUED_STRFUNCS
+
+/* hack for C++ platforms where bool is a keyword */
+#ifndef boolean
+#define boolean boolean
+#endif
+
+#elif defined(Linux)
+
+#define ACCELERATOR_CACHE
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define DAEMON_UNIX_MOBRULE
+#define BSD_RLIMIT
+#undef BSD_SIGNALS
+#define FILE_UNIX_MMAP
+#define FILE_MMAP_FLAGS (MAP_FILE | MAP_SHARED)
+#define SHMEM_UNIX_MMAP
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+#define AUTH_DBM
+#define SEM_FLOCK
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW
+#define HAVE_ATEXIT
+#define HAS_STATFS
+#define JAVA_STATIC_LINK
+#define SA_HANDLER_T(x) (void (*)(int))(x)
+#define SA_NOCLDWAIT 0 /* Linux doesn't have this */
+#define TCPLEN_T size_t
+
+#undef NEED_CRYPT_PROTO
+#define NET_SOCKETS
+#ifndef NO_DOMAINNAME
+#define NO_DOMAINNAME
+#endif
+#elif defined(SOLARIS) || defined(SOLARISx86)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#define BSD_RLIMIT
+#undef BSD_SIGNALS
+#define DAEMON_NEEDS_SEMAPHORE
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAS_STATVFS
+#define HAVE_ATEXIT
+#define HAVE_PW_R
+#define HAVE_STRTOK_R
+#define HAVE_TIME_R 3 /* arg count */
+#define NEED_CRYPT_H
+#define NEED_FILIO
+#if OSVERSION < 506 || OSVERSION == 50501
+#define NEED_GHN_PROTO
+#endif
+#define NET_SOCKETS
+#if OSVERSION > 504
+#define SA_HANDLER_T(x) x
+#endif
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+
+#elif defined (SONY)
+
+#define AUTH_DBM
+#undef BSD_RLIMIT
+#define DAEMON_NEEDS_SEMAPHORE
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAVE_ATEXIT
+#define NEED_CRYPT_H
+#define NEED_FILIO
+#define NET_SOCKETS
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+
+#elif defined(SUNOS4)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#define BSD_MAIL
+#define BSD_RLIMIT
+#define BSD_SIGNALS
+#define BSD_TIME
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS 1
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAS_STATFS
+#undef HAVE_ATEXIT
+#undef NEED_CRYPT_H
+#define NEED_CRYPT_PROTO
+#define NEED_FILIO
+#define NET_SOCKETS
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+
+#elif defined(UNIXWARE) || defined(UnixWare)
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+#undef BSD_RLIMIT
+#define DAEMON_UNIX_MOBRULE
+#define DLL_CAPABLE
+#define DLL_DLOPEN
+#define DLL_DLOPEN_FLAGS RTLD_NOW
+#define DNS_CACHE
+#define FILE_INHERIT_FCNTL
+#define FILE_MMAP_FLAGS MAP_SHARED
+#define HAS_STATVFS
+#define HAVE_ATEXIT
+#define NEED_CRYPT_H
+#define NEED_FILIO
+#define NEED_GHN_PROTO
+#define NEED_SETEID_PROTO /* setegid, seteuid */
+#define NET_SOCKETS
+#define SHMEM_MMAP_FLAGS MAP_SHARED
+
+#ifndef boolean
+#define boolean boolean
+#endif
+
+#if defined (UnixWare)
+/* UnixWare but not UNIXWARE... */
+#define NEED_STRINGS_H /* for strcasecmp */
+#define SA_HANDLER_T(x) (void (*)(int))x
+#endif
+
+#elif defined (XP_WIN32) /* Windows NT */
+
+#include <wtypes.h>
+#include <winbase.h>
+
+typedef void* PASSWD;
+
+#define ACCELERATOR_CACHE
+#define AUTH_DBM
+/* size has been raised to 200 with NT 4.0 server; NT 4.0 workstation is still
+ * limited
+ */
+#define DAEMON_LISTEN_SIZE 200
+#define DAEMON_WIN32
+#define DLL_CAPABLE
+#define DLL_WIN32
+#define DNS_CACHE
+#define LOG_BUFFERING
+#define HAVE_STRFTIME /* no cftime */
+#define NEED_CRYPT_PROTO
+#define NEEDS_WRITEV
+#define NET_SOCKETS
+#ifndef NO_DOMAINNAME
+#define NO_DOMAINNAME
+#endif
+#ifdef BUILD_DLL
+#define NSAPI_PUBLIC __declspec(dllexport)
+#else
+#define NSAPI_PUBLIC
+#endif /* BUILD_DLL */
+#define THREAD_ANY
+#define THREAD_NSPR_KERNEL
+#define USE_NSPR
+#define USE_STRFTIME /* no cftime */
+
+#else
+
+#error "Missing defines in ns/netsite/include/base/systems.h"
+
+#endif /* Windows NT */
+
+/* Pick up the configuration symbols in the public interface */
+#ifndef PUBLIC_BASE_SYSTEMS_H
+#include "public/base/systems.h"
+#endif /* PUBLIC_BASE_SYSTEMS_H */
+
+/* --- Begin defaults for values not defined above --- */
+
+#ifndef DAEMON_LISTEN_SIZE
+#define DAEMON_LISTEN_SIZE 128
+#endif /* !DAEMON_LISTEN_SIZE */
+
+#ifndef SA_HANDLER_T
+#define SA_HANDLER_T(x) (void (*)())x
+#endif
+
+#ifdef HAS_CONSTVALUED_STRFUNCS
+#define CONSTVALSTRCAST (char *)
+#else
+#define CONSTVALSTRCAST
+#endif
+
+#ifndef TCPLEN_T
+#define TCPLEN_T int
+#endif
+
+#ifndef THROW_HACK
+#define THROW_HACK /* as nothing */
+#endif
+
+
+/* --- End defaults for values not defined above --- */
+
+/* --- Begin the great debate --- */
+
+/* NS_MAIL builds sec-key.c which calls systhread_init, which requires */
+/* that USE_NSPR is defined when systhr.c is compiled. --lachman */
+/* MCC_PROXY does the same thing now --nbreslow -- LIKE HELL --ari */
+#if (defined(MCC_HTTPD) || defined(MCC_ADMSERV) || defined(MCC_PROXY) || defined(NS_MAIL)) && defined(XP_UNIX)
+#define USE_NSPR
+/* XXXrobm This is UNIX-only for the moment */
+#define LOG_BUFFERING
+#ifdef SW_THREADS
+#define THREAD_NSPR_USER
+#else
+#define THREAD_NSPR_KERNEL
+#ifdef IRIX
+#undef SEM_FLOCK
+#define SEM_IRIX
+#endif
+#endif
+#define THREAD_ANY
+#endif
+
+/* --- End the great debate --- */
+
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#ifndef NSPR_PRIO_H
+#include <prio.h>
+#define NSPR_PRIO_H
+#endif /* !NSPR_PRIO_H */
+
+/*
+ * These types have to be defined early, because they are defined
+ * as (void *) in the public API.
+ */
+
+#ifndef SYS_FILE_T
+typedef PRFileDesc *SYS_FILE;
+#define SYS_FILE_T PRFileDesc *
+#endif /* !SYS_FILE_T */
+
+#ifndef SYS_NETFD_T
+typedef PRFileDesc *SYS_NETFD;
+#define SYS_NETFD_T PRFileDesc *
+#endif /* !SYS_NETFD_T */
+
+#ifdef SEM_WIN32
+
+typedef HANDLE SEMAPHORE;
+#define SEMAPHORE_T HANDLE
+#define SEM_ERROR NULL
+/* That oughta hold them (I hope) */
+#define SEM_MAXVALUE 32767
+
+#elif defined(SEM_IRIX)
+
+#ifndef OS_ULOCKS_H
+#include <ulocks.h>
+#define OS_ULOCKS_H
+#endif /* !OS_ULOCKS_H */
+
+typedef struct {
+ usptr_t *arena;
+ usema_t *sem;
+} semirix_s;
+typedef semirix_s* SEMAPHORE;
+#define SEMAPHORE_T semirix_s *
+#define SEM_ERROR NULL
+
+#elif defined(SEM_FLOCK)
+
+#define SEMAPHORE_T SYS_FILE
+typedef SYS_FILE SEMAPHORE;
+#define SEM_ERROR NULL
+
+#else /* ! SEM_WIN32, !SEM_IRIX */
+
+typedef int SEMAPHORE;
+#define SEMAPHORE_T int
+#define SEM_ERROR -1
+
+#endif /* SEM_WIN32 */
+
+#endif /* !APSTUDIO_READONLY_SYMBOLS */
+
+#endif /* BASE_SYSTEMS_H */
diff --git a/include/base/systhr.h b/include/base/systhr.h
new file mode 100644
index 00000000..714246df
--- /dev/null
+++ b/include/base/systhr.h
@@ -0,0 +1,91 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef BASE_SYSTHR_H
+#define BASE_SYSTHR_H
+
+#ifndef NOINTNSAPI
+#define INTNSAPI
+#endif /* !NOINTNSAPI */
+
+/*
+ * systhr.h: Abstracted threading mechanisms
+ *
+ * Rob McCool
+ */
+
+#ifndef NETSITE_H
+#include "netsite.h"
+#endif /* !NETSITE_H */
+
+#ifdef THREAD_ANY
+
+#ifndef PUBLIC_BASE_SYSTHR_H
+#include "public/base/systhr.h"
+#endif /* !PUBLIC_BASE_SYSTHR_H */
+
+/* --- Begin function prototypes --- */
+
+#ifdef INTNSAPI
+
+NSPR_BEGIN_EXTERN_C
+
+#ifdef UnixWare
+typedef void(*ArgFn_systhread_start)(void *);
+NSAPI_PUBLIC
+SYS_THREAD INTsysthread_start( int prio, int stksz, \
+ ArgFn_systhread_start, void *arg);
+#else
+NSAPI_PUBLIC
+SYS_THREAD INTsysthread_start(int prio, int stksz, void (*fn)(void *), void *arg);
+#endif
+
+NSAPI_PUBLIC SYS_THREAD INTsysthread_current(void);
+
+NSAPI_PUBLIC void INTsysthread_yield(void);
+
+NSAPI_PUBLIC SYS_THREAD INTsysthread_attach(void);
+
+NSAPI_PUBLIC void INTsysthread_detach(SYS_THREAD thr);
+
+NSAPI_PUBLIC void INTsysthread_terminate(SYS_THREAD thr);
+
+NSAPI_PUBLIC void INTsysthread_sleep(int milliseconds);
+
+NSAPI_PUBLIC void INTsysthread_init(char *name);
+
+NSAPI_PUBLIC void INTsysthread_timerset(int usec);
+
+NSAPI_PUBLIC int INTsysthread_newkey(void);
+
+NSAPI_PUBLIC void *INTsysthread_getdata(int key);
+
+NSAPI_PUBLIC void INTsysthread_setdata(int key, void *data);
+
+NSAPI_PUBLIC
+void INTsysthread_set_default_stacksize(unsigned long size);
+
+NSPR_END_EXTERN_C
+
+/* --- End function prototypes --- */
+#define systhread_start INTsysthread_start
+#define systhread_current INTsysthread_current
+#define systhread_yield INTsysthread_yield
+#define systhread_attach INTsysthread_attach
+#define systhread_detach INTsysthread_detach
+#define systhread_terminate INTsysthread_terminate
+#define systhread_sleep INTsysthread_sleep
+#define systhread_init INTsysthread_init
+#define systhread_timerset INTsysthread_timerset
+#define systhread_newkey INTsysthread_newkey
+#define systhread_getdata INTsysthread_getdata
+#define systhread_setdata INTsysthread_setdata
+#define systhread_set_default_stacksize INTsysthread_set_default_stacksize
+
+#endif /* INTNSAPI */
+
+#endif /* THREAD_ANY */
+
+#endif /* !BASE_SYSTHR_H */
diff --git a/include/base/util.h b/include/base/util.h
new file mode 100644
index 00000000..7778b924
--- /dev/null
+++ b/include/base/util.h
@@ -0,0 +1,210 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef BASE_UTIL_H
+#define BASE_UTIL_H
+
+#ifndef NOINTNSAPI
+#define INTNSAPI
+#endif /* !NOINTNSAPI */
+
+/*
+ * util.h: A hodge podge of utility functions and standard functions which
+ * are unavailable on certain systems
+ *
+ * Rob McCool
+ */
+
+/* Needed for various reentrant functions */
+#define DEF_CTIMEBUF 26
+#define DEF_ERRBUF 256
+#define DEF_PWBUF 256
+
+#ifndef BASE_BUFFER_H
+#include "buffer.h" /* filebuf for getline */
+#endif /* !BASE_BUFFER_H */
+
+#ifndef PUBLIC_BASE_UTIL_H
+#include "public/base/util.h"
+#endif /* !PUBLIC_BASE_UTIL_H */
+
+/* --- Begin common function prototypes --- */
+
+#ifdef INTNSAPI
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC
+int INTutil_getline(filebuffer *buf, int lineno, int maxlen, char *l);
+
+NSAPI_PUBLIC char **INTutil_env_create(char **env, int n, int *pos);
+
+NSAPI_PUBLIC char *INTutil_env_str(char *name, char *value);
+
+NSAPI_PUBLIC void INTutil_env_replace(char **env, char *name, char *value);
+
+NSAPI_PUBLIC void INTutil_env_free(char **env);
+
+NSAPI_PUBLIC char **INTutil_env_copy(char **src, char **dst);
+
+NSAPI_PUBLIC char *INTutil_env_find(char **env, char *name);
+
+NSAPI_PUBLIC char *INTutil_hostname(void);
+
+NSAPI_PUBLIC int INTutil_chdir2path(char *path);
+
+NSAPI_PUBLIC int INTutil_is_mozilla(char *ua, char *major, char *minor);
+
+NSAPI_PUBLIC int INTutil_is_url(char *url);
+
+NSAPI_PUBLIC int INTutil_later_than(struct tm *lms, char *ims);
+
+NSAPI_PUBLIC int INTutil_time_equal(struct tm *lms, char *ims);
+
+NSAPI_PUBLIC int INTutil_str_time_equal(char *t1, char *t2);
+
+NSAPI_PUBLIC int INTutil_uri_is_evil(char *t);
+
+NSAPI_PUBLIC void INTutil_uri_parse(char *uri);
+
+NSAPI_PUBLIC void INTutil_uri_unescape(char *s);
+
+NSAPI_PUBLIC char *INTutil_uri_escape(char *d, char *s);
+
+NSAPI_PUBLIC char *INTutil_url_escape(char *d, char *s);
+
+NSAPI_PUBLIC char *INTutil_sh_escape(char *s);
+
+NSAPI_PUBLIC int INTutil_mime_separator(char *sep);
+
+NSAPI_PUBLIC int INTutil_itoa(int i, char *a);
+
+NSAPI_PUBLIC
+int INTutil_vsprintf(char *s, register const char *fmt, va_list args);
+
+NSAPI_PUBLIC int INTutil_sprintf(char *s, const char *fmt, ...);
+
+NSAPI_PUBLIC int INTutil_vsnprintf(char *s, int n, register const char *fmt,
+ va_list args);
+
+NSAPI_PUBLIC int INTutil_snprintf(char *s, int n, const char *fmt, ...);
+
+NSAPI_PUBLIC int INTutil_strftime(char *s, const char *format, const struct tm *t);
+
+NSAPI_PUBLIC char *INTutil_strtok(char *s1, const char *s2, char **lasts);
+
+NSAPI_PUBLIC struct tm *INTutil_localtime(const time_t *clock, struct tm *res);
+
+NSAPI_PUBLIC char *INTutil_ctime(const time_t *clock, char *buf, int buflen);
+
+NSAPI_PUBLIC char *INTutil_strerror(int errnum, char *msg, int buflen);
+
+NSAPI_PUBLIC struct tm *INTutil_gmtime(const time_t *clock, struct tm *res);
+
+NSAPI_PUBLIC char *INTutil_asctime(const struct tm *tm,char *buf, int buflen);
+
+#ifdef NEED_STRCASECMP
+NSAPI_PUBLIC int INTutil_strcasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two);
+#endif /* NEED_STRCASECMP */
+
+#ifdef NEED_STRNCASECMP
+NSAPI_PUBLIC int INTutil_strncasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two, int n);
+#endif /* NEED_STRNCASECMP */
+
+/* --- End common function prototypes --- */
+
+/* --- Begin Unix-only function prototypes --- */
+
+#ifdef XP_UNIX
+
+NSAPI_PUBLIC int INTutil_can_exec(struct stat *finfo, uid_t uid, gid_t gid);
+
+NSAPI_PUBLIC
+struct passwd *INTutil_getpwnam(const char *name, struct passwd *result,
+ char *buffer, int buflen);
+
+NSAPI_PUBLIC pid_t INTutil_waitpid(pid_t pid, int *statptr, int options);
+
+#endif /* XP_UNIX */
+
+/* --- End Unix-only function prototypes --- */
+
+/* --- Begin Windows-only function prototypes --- */
+
+#ifdef XP_WIN32
+
+NSAPI_PUBLIC
+VOID INTutil_delete_directory(char *FileName, BOOL delete_directory);
+
+#endif /* XP_WIN32 */
+
+/* --- End Windows-only function prototypes --- */
+
+NSPR_END_EXTERN_C
+
+#define util_getline INTutil_getline
+#define util_env_create INTutil_env_create
+#define util_env_str INTutil_env_str
+#define util_env_replace INTutil_env_replace
+#define util_env_free INTutil_env_free
+#define util_env_copy INTutil_env_copy
+#define util_env_find INTutil_env_find
+#define util_hostname INTutil_hostname
+#define util_chdir2path INTutil_chdir2path
+#define util_is_mozilla INTutil_is_mozilla
+#define util_is_url INTutil_is_url
+#define util_later_than INTutil_later_than
+#define util_time_equal INTutil_time_equal
+#define util_str_time_equal INTutil_str_time_equal
+#define util_uri_is_evil INTutil_uri_is_evil
+#define util_uri_parse INTutil_uri_parse
+#define util_uri_unescape INTutil_uri_unescape
+#define util_uri_escape INTutil_uri_escape
+#define util_url_escape INTutil_url_escape
+#define util_sh_escape INTutil_sh_escape
+#define util_mime_separator INTutil_mime_separator
+#define util_itoa INTutil_itoa
+#define util_vsprintf INTutil_vsprintf
+#define util_sprintf INTutil_sprintf
+#define util_vsnprintf INTutil_vsnprintf
+#define util_snprintf INTutil_snprintf
+#define util_strftime INTutil_strftime
+#define util_strcasecmp INTutil_strcasecmp
+#define util_strncasecmp INTutil_strncasecmp
+#define util_strtok INTutil_strtok
+#define util_localtime INTutil_localtime
+#define util_ctime INTutil_ctime
+#define util_strerror INTutil_strerror
+#define util_gmtime INTutil_gmtime
+#define util_asctime INTutil_asctime
+
+#ifdef XP_UNIX
+#define util_can_exec INTutil_can_exec
+#define util_getpwnam INTutil_getpwnam
+#define util_waitpid INTutil_waitpid
+#endif /* XP_UNIX */
+
+#ifdef XP_WIN32
+#define util_delete_directory INTutil_delete_directory
+#endif /* XP_WIN32 */
+
+#ifdef NEED_STRCASECMP
+#define util_strcasecmp INTutil_strcasecmp
+#define strcasecmp INTutil_strcasecmp
+#endif /* NEED_STRCASECMP */
+
+#ifdef NEED_STRINGS_H /* usually for strcasecmp */
+#include <strings.h>
+#endif
+
+#ifdef NEED_STRNCASECMP
+#define util_strncasecmp INTutil_strncasecmp
+#define strncasecmp INTutil_strncasecmp
+#endif /* NEED_STRNCASECMP */
+
+#endif /* INTNSAPI */
+
+#endif /* !BASE_UTIL_H */
+
diff --git a/include/copyrght.h b/include/copyrght.h
new file mode 100644
index 00000000..4f8ec167
--- /dev/null
+++ b/include/copyrght.h
@@ -0,0 +1,6 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
diff --git a/include/i18n.h b/include/i18n.h
new file mode 100644
index 00000000..1a6e67c4
--- /dev/null
+++ b/include/i18n.h
@@ -0,0 +1,245 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef I18N_H
+#define I18N_H
+
+/* Make NSAPI_PUBLIC available */
+#include "base/systems.h"
+#include "libadminutil/resource.h"
+
+typedef res_RESOURCE_TABLE RESOURCE_TABLE;
+typedef res_RESOURCE_GLOBAL RESOURCE_GLOBAL;
+
+/*******************************************************************************/
+
+/*
+ * In accordance with the recommendations in the
+ * "Netscape Coding Standard for Server Internationalization",
+ * the following aliases are defined for fprintf, et al., and
+ * these aliases should be used to clearly indicate the intended
+ * destination for output.
+ */
+
+#define AdminFprintf fprintf
+#define DebugFprintf fprintf
+
+#define ClientSprintf sprintf
+#define AdminSprintf sprintf
+#define DebugSprintf sprintf
+
+#define ClientFputs fputs
+#define AdminFputs fputs
+#define DebugFputs fputs
+
+/* more #define, as needed */
+
+/*******************************************************************************/
+
+/*
+ * Function prototypes for application and libraries
+ */
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/***************************/
+/* XP_InitStringDatabase() */
+/***************************/
+
+NSAPI_PUBLIC
+void
+XP_InitStringDatabase(char* pathCWD, char* databaseName);
+
+/* Initialize the resource string database */
+
+/******************************/
+/* XP_GetStringFromDatabase() */
+/******************************/
+
+NSAPI_PUBLIC
+extern char*
+XP_GetStringFromDatabase(char* strLibraryName,
+ char* strLanguage,
+ int iToken);
+
+/* Given the LibraryName, Language and Token, extracts the string corresponding
+ to that library and token from the database in the language requested and
+ returns a pointer to the string. Note: Use the macros XP_GetClientStr() and
+ XP_GetAdminStr() defined below to simplify source code. */
+
+/*****************/
+/* SetLanguage() */
+/*****************/
+enum
+{
+ CLIENT_LANGUAGE,
+ ADMIN_LANGUAGE,
+ DEFAULT_LANGUAGE
+};
+
+NSAPI_PUBLIC
+extern void
+SetLanguage(int type, char *language);
+
+/* Set language for Client, Admin and Default, XP_GetStringFromDatabase will
+ base on the setting to retrieve correct string for specific language */
+
+/***********************/
+/* GetClientLanguage() */
+/***********************/
+
+NSAPI_PUBLIC
+extern char*
+GetClientLanguage(void);
+
+/* Returns a pointer to a string with the name of the language requested by
+ the current client; intended to be passed to XP_GetStringFromDatabase()
+ and used by the front end macro XP_GetClientStr(). */
+
+/**********************/
+/* GetAdminLanguage() */
+/**********************/
+
+NSAPI_PUBLIC
+extern char*
+GetAdminLanguage(void);
+
+/* Returns a pointer to a string with the name of the language requested by
+ the administrator; intended to be passed to XP_GetStringFromDatabase()
+ and used by the front end macro XP_GetAdminStr(). */
+
+/************************/
+/* GetDefaultLanguage() */
+/************************/
+
+NSAPI_PUBLIC
+extern char*
+GetDefaultLanguage(void);
+
+/* Returns a pointer to a string with the name of the default language
+ for the installation from the configuration file. */
+
+/************************/
+/* GetFileForLanguage() */
+/************************/
+
+NSAPI_PUBLIC
+int
+GetFileForLanguage(char* filepath,char* language,char* existingFilepath);
+
+/* Looks for a file in the appropriate language.
+
+ Input: filePath,language
+ filePath is of the form "/xxx/xxx/$$LANGDIR/xxx/xxx/filename"
+ or of the form "/xxx/xxx/xxx/xxx/filename".
+ filename may or may not have an extension.
+ language is an Accept-Language list; each language-range will be
+ tried as a subdirectory name and possibly as a filename modifier.
+ "*" is ignored - default always provided if needed.
+ "-" is replaced by "_".
+ $$LANGDIR is a special string replaced by language. It is optional.
+ For the default case, $$LANGDIR/ is replaced by nothing
+ (so // is not created).
+
+ Returned: existingPath
+ existingFilePath is the path of a satisfactory, existing file.
+ if no file is found, an empty string "" is returned.
+
+ int returned: -1 if no file found (existingFilePath = "")
+ 0 if default file is returned
+ 1 if language file is returned (any in list) */
+
+/********************/
+/* XP_AccLangList() */
+/********************/
+
+#define MAX_ACCEPT_LANGUAGE 16
+#define MAX_ACCEPT_LENGTH 18
+
+typedef char ACCEPT_LANGUAGE_LIST[MAX_ACCEPT_LANGUAGE][MAX_ACCEPT_LENGTH];
+
+NSAPI_PUBLIC
+int
+XP_AccLangList(char* AcceptLanguage,
+ ACCEPT_LANGUAGE_LIST AcceptLanguageList);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+/*******************************************************************************/
+
+/*
+ * Function prototypes for building string database
+ */
+
+extern int XP_MakeStringDatabase(void);
+
+/* Used to create the string database at build time; not used by the application
+ itself. Returns 0 is successful. */
+
+extern void XP_PrintStringDatabase(void);
+
+/* DEBUG: Prints out entire string database to standard output. */
+
+/*******************************************************************************/
+
+/*
+ * Macros to simplify calls to XP_GetStringFromDatabase
+ * (need one argument instead of three)
+ */
+
+#define XP_GetClientStr(DBTTokenName) \
+ XP_GetStringFromDatabase(LIBRARY_NAME, \
+ GetClientLanguage(), \
+ DBTTokenName)
+
+#define XP_GetAdminStr(DBTTokenName) \
+ XP_GetStringFromDatabase(LIBRARY_NAME, \
+ "en", \
+ DBTTokenName)
+
+/*******************************************************************************/
+
+
+/*******************************************************************************/
+
+/*
+ * Define the ResDef macro to simplify the maintenance of strings which are to
+ * be added to the library or application header file (dbtxxx.h). This enables
+ * source code to refer to the strings by theit TokenNames, and allows the
+ * strings to be stored in the database.
+ *
+ * Usage: ResDef(TokenName,TokenValue,String)
+ *
+ * Example: ResDef(DBT_HelloWorld_, \
+ * 1,"Hello, World!")
+ * ResDef(DBT_TheCowJumpedOverTheMoon_, \
+ * 2,"The cow jumped over the moon.")
+ * ResDef(DBT_TheValueOfPiIsAbout31415926536_, \
+ * 3,"The value of PI is about 3.1415926536."
+ *
+ * RESOURCE_STR is used by makstrdb.c only. It is not used by getstrdb.c or
+ * in library or application source code.
+ */
+
+#if 0
+#define BEGIN_STR(argLibraryName) \
+ enum {
+#define ResDef(argToken,argID,argString) \
+ argToken = argID,
+#define END_STR(argLibraryName) \
+ argLibraryName ## top };
+
+#endif
+/*******************************************************************************/
+
+#endif
diff --git a/include/ldaputil/cert.h b/include/ldaputil/cert.h
new file mode 100644
index 00000000..4dac8f05
--- /dev/null
+++ b/include/ldaputil/cert.h
@@ -0,0 +1,27 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _LDAPU_CERT_H
+#define _LDAPU_CERT_H
+
+#ifndef NSAPI_PUBLIC
+#ifdef XP_WIN32
+#define NSAPI_PUBLIC __declspec(dllexport)
+#else
+#define NSAPI_PUBLIC
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NSAPI_PUBLIC int ldapu_get_cert (void *SSLendpoint, void **cert);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAPU_CERT_H */
diff --git a/include/ldaputil/certmap.h b/include/ldaputil/certmap.h
new file mode 100644
index 00000000..921cbd06
--- /dev/null
+++ b/include/ldaputil/certmap.h
@@ -0,0 +1,124 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _LDAPU_CERTMAP_H
+#define _LDAPU_CERTMAP_H
+
+#ifndef INTLDAPU
+#define INTLDAPU
+#endif /* INTLDAPU */
+
+#include "extcmap.h"
+
+enum {
+ LDAPU_STR_FILTER_DEFAULT,
+ LDAPU_STR_FILTER_USER,
+ LDAPU_STR_FILTER_GROUP,
+ LDAPU_STR_FILTER_MEMBER,
+ LDAPU_STR_FILTER_MEMBER_RECURSE,
+ LDAPU_STR_ATTR_USER,
+ LDAPU_STR_ATTR_CERT,
+ LDAPU_STR_ATTR_CERT_NOSUBTYPE,
+ LDAPU_STR_MAX_INDEX
+};
+
+static char *ldapu_strings[] = {
+ "objectclass=*", /* LDAPU_STR_DEFAULT */
+ "uid=%s", /* LDAPU_STR_FILTER_USER */
+ "(& (cn=%s) (| (objectclass=groupofuniquenames) (objectclass=groupofnames)))", /* LDAPU_STR_FILTER_GROUP */
+ "(| (uniquemember=%s) (member=%s))", /* LDAPU_STR_FILTER_MEMBER */
+ "(& %s (| (objectclass=groupofuniquenames) (objectclass=groupofnames))", /* LDAPU_STR_FILTER_MEMBER_RECURSE */
+ "uid", /* LDAPU_STR_ATTR_USER */
+ "userCertificate;binary", /* LDAPU_STR_ATTR_CERT */
+ "userCertificate" /* LDAPU_STR_ATTR_CERT_NOSUBTYPE */
+};
+
+typedef struct {
+ char *str;
+ int size;
+ int len;
+} LDAPUStr_t;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NSAPI_PUBLIC int ldapu_cert_to_ldap_entry (void *cert, LDAP *ld,
+ const char *basedn,
+ LDAPMessage **res);
+
+NSAPI_PUBLIC int ldapu_set_cert_mapfn (const char *issuerDN,
+ CertMapFn_t mapfn);
+
+
+NSAPI_PUBLIC CertMapFn_t ldapu_get_cert_mapfn (const char *issuerDN);
+
+NSAPI_PUBLIC int ldapu_set_cert_searchfn (const char *issuerDN,
+ CertSearchFn_t searchfn);
+
+
+NSAPI_PUBLIC CertSearchFn_t ldapu_get_cert_searchfn (const char *issuerDN);
+
+NSAPI_PUBLIC int ldapu_set_cert_verifyfn (const char *issuerDN,
+ CertVerifyFn_t verifyFn);
+
+NSAPI_PUBLIC CertVerifyFn_t ldapu_get_cert_verifyfn (const char *issuerDN);
+
+
+NSAPI_PUBLIC int ldapu_get_cert_subject_dn (void *cert, char **subjectDN);
+
+
+NSAPI_PUBLIC int ldapu_get_cert_issuer_dn (void *cert, char **issuerDN);
+
+
+NSAPI_PUBLIC int ldapu_get_cert_ava_val (void *cert, int which_dn,
+ const char *attr, char ***val);
+
+
+NSAPI_PUBLIC int ldapu_free_cert_ava_val (char **val);
+
+
+NSAPI_PUBLIC int ldapu_get_cert_der (void *cert, unsigned char **derCert,
+ unsigned int *len);
+
+
+NSAPI_PUBLIC int ldapu_issuer_certinfo (const char *issuerDN,
+ void **certmap_info);
+
+
+NSAPI_PUBLIC int ldapu_certmap_info_attrval (void *certmap_info,
+ const char *attr, char **val);
+
+
+NSAPI_PUBLIC char *ldapu_err2string (int err);
+
+/* Keep the old fn for backward compatibility */
+NSAPI_PUBLIC void ldapu_free_old (char *ptr);
+
+
+NSAPI_PUBLIC void *ldapu_malloc (int size);
+
+
+NSAPI_PUBLIC char *ldapu_strdup (const char *ptr);
+
+
+NSAPI_PUBLIC void *ldapu_realloc (void *ptr, int size);
+
+
+NSAPI_PUBLIC void ldapu_free (void *ptr);
+
+
+NSAPI_PUBLIC int ldapu_string_set (const int type, const char *filter);
+
+
+NSAPI_PUBLIC const char *ldapu_string_get (const int type);
+
+NSAPI_PUBLIC int ldaputil_exit ();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAPU_CERTMAP_H */
diff --git a/include/ldaputil/dbconf.h b/include/ldaputil/dbconf.h
new file mode 100644
index 00000000..3556c36e
--- /dev/null
+++ b/include/ldaputil/dbconf.h
@@ -0,0 +1,91 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _LDAPU_DBCONF_H
+#define _LDAPU_DBCONF_H
+
+#include <stdio.h>
+
+#ifndef NSAPI_PUBLIC
+#ifdef XP_WIN32
+#define NSAPI_PUBLIC __declspec(dllexport)
+#else
+#define NSAPI_PUBLIC
+#endif
+#endif
+
+typedef struct dbconf_propval {
+ char *prop; /* Property name */
+ char *val; /* Property value */
+ struct dbconf_propval *next; /* Pointer to the next prop-val pair */
+} DBPropVal_t;
+
+typedef struct dbconf_dbinfo {
+ char *dbname; /* Database name */
+ char *url; /* Database URL */
+ DBPropVal_t *firstprop; /* pointer to first property-value pair */
+ DBPropVal_t *lastprop; /* pointer to last property-value pair */
+ struct dbconf_dbinfo *next; /* pointer to next db info */
+} DBConfDBInfo_t;
+
+typedef struct {
+ DBConfDBInfo_t *firstdb; /* pointer to first db info */
+ DBConfDBInfo_t *lastdb; /* pointer to last db info */
+} DBConfInfo_t;
+
+#define DBCONF_DEFAULT_DBNAME "default"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NSAPI_PUBLIC extern int dbconf_read_default_dbinfo (const char *file,
+ DBConfDBInfo_t **db_info);
+NSAPI_PUBLIC extern int dbconf_read_config_file (const char *file,
+ DBConfInfo_t **conf_info);
+
+NSAPI_PUBLIC extern int ldapu_dbinfo_attrval (DBConfDBInfo_t *db_info,
+ const char *attr, char **val);
+
+NSAPI_PUBLIC extern void dbconf_free_confinfo (DBConfInfo_t *conf_info);
+NSAPI_PUBLIC extern void dbconf_free_dbinfo (DBConfDBInfo_t *db_info);
+
+extern void dbconf_free_propval (DBPropVal_t *propval);
+
+extern void dbconf_print_confinfo (DBConfInfo_t *conf_info);
+extern void dbconf_print_dbinfo (DBConfDBInfo_t *db_info);
+extern void dbconf_print_propval (DBPropVal_t *propval);
+
+
+NSAPI_PUBLIC int dbconf_output_db_directive (FILE *fp, const char *dbname,
+ const char *url);
+
+NSAPI_PUBLIC int dbconf_output_propval (FILE *fp, const char *dbname,
+ const char *prop, const char *val,
+ const int encoded);
+
+/* Following functions are required by certmap.c file */
+extern int dbconf_read_config_file_sub (const char *file,
+ const char *directive,
+ const int directive_len,
+ DBConfInfo_t **conf_info_out);
+
+extern int dbconf_read_default_dbinfo_sub (const char *file,
+ const char *directive,
+ const int directive_len,
+ DBConfDBInfo_t **db_info_out);
+
+NSAPI_PUBLIC int dbconf_get_dbnames (const char *dbmap, char ***dbnames, int *cnt);
+
+NSAPI_PUBLIC int dbconf_free_dbnames (char **dbnames);
+
+
+extern int ldapu_strcasecmp (const char *s1, const char *s2);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAPU_DBCONF_H */
diff --git a/include/ldaputil/encode.h b/include/ldaputil/encode.h
new file mode 100644
index 00000000..6cc7729e
--- /dev/null
+++ b/include/ldaputil/encode.h
@@ -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 **/
+#ifndef _LDAPU_ENCODE_H
+#define _LDAPU_ENCODE_H
+
+#ifndef NSAPI_PUBLIC
+#ifdef XP_WIN32
+#define NSAPI_PUBLIC __declspec(dllexport)
+#else
+#define NSAPI_PUBLIC
+#endif
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NSAPI_PUBLIC extern char *dbconf_encodeval(const char *val);
+
+NSAPI_PUBLIC extern char *dbconf_decodeval (const char *val);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAPU_ENCODE_H */
diff --git a/include/ldaputil/errors.h b/include/ldaputil/errors.h
new file mode 100644
index 00000000..de6f893d
--- /dev/null
+++ b/include/ldaputil/errors.h
@@ -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 **/
+#ifndef _LDAPU_ERRORS_H
+#define _LDAPU_ERRORS_H
+
+#ifndef NSAPI_PUBLIC
+#ifdef XP_WIN32
+#define NSAPI_PUBLIC __declspec(dllexport)
+#else
+#define NSAPI_PUBLIC
+#endif
+#endif
+
+#ifdef DBG_PRINT
+#include <stdio.h>
+#define DBG_PRINT1(x) fprintf(stderr, x)
+#define DBG_PRINT2(x,y) fprintf(stderr, x, y)
+#define DBG_PRINT3(x,y,z) fprintf(stderr, x, y, z)
+#define DBG_PRINT4(x,y,z,a) fprintf(stderr, x, y, z, a)
+#else
+#define DBG_PRINT1(x)
+#define DBG_PRINT2(x,y)
+#define DBG_PRINT3(x,y,z)
+#define DBG_PRINT4(x,y,z,a)
+#endif
+
+/* Common error codes */
+#define LDAPU_ERR_NOT_IMPLEMENTED -1000
+#define LDAPU_ERR_INTERNAL -1001
+/* #define LDAPU_SUCCESS 0 */ /* defined in extcmap.h */
+/* #define LDAPU_FAILED -1 */ /* defined in extcmap.h */
+/* #define LDAPU_CERT_MAP_FUNCTION_FAILED -2 *//* defined in extcmap.h */
+/* #define LDAPU_CERT_VERIFY_FUNCTION_FAILED -3 *//* defined in extcmap.h */
+/* #define LDAPU_CERT_VERIFY_FUNCTION_FAILED -4 *//* defined in extcmap.h */
+/* #define LDAPU_CERT_MAP_INITFN_FAILED -5 *//* defined in extcmap.h */
+
+/* Error codes returned by ldapdb.c */
+#define LDAPU_ERR_OUT_OF_MEMORY -110
+#define LDAPU_ERR_URL_INVALID_PREFIX -112
+#define LDAPU_ERR_URL_NO_BASEDN -113
+#define LDAPU_ERR_URL_PARSE_FAILED -114
+
+#define LDAPU_ERR_LDAP_INIT_FAILED -120
+#define LDAPU_ERR_LCACHE_INIT_FAILED -121
+#define LDAPU_ERR_LDAP_SET_OPTION_FAILED -122
+#define LDAPU_ERR_NO_DEFAULT_CERTDB -123
+
+/* Errors returned by dbconf.c */
+#define LDAPU_ERR_CANNOT_OPEN_FILE -141
+#define LDAPU_ERR_DBNAME_IS_MISSING -142
+#define LDAPU_ERR_PROP_IS_MISSING -143
+#define LDAPU_ERR_DIRECTIVE_IS_MISSING -145
+#define LDAPU_ERR_NOT_PROPVAL -146
+#define LDAPU_ATTR_NOT_FOUND -147
+
+/* Error codes returned by certmap.c */
+#define LDAPU_ERR_NO_ISSUERDN_IN_CERT -181
+#define LDAPU_ERR_NO_ISSUERDN_IN_CONFIG_FILE -182
+#define LDAPU_ERR_CERTMAP_INFO_MISSING -183
+#define LDAPU_ERR_MALFORMED_SUBJECT_DN -184
+#define LDAPU_ERR_MAPPED_ENTRY_NOT_FOUND -185
+#define LDAPU_ERR_UNABLE_TO_LOAD_PLUGIN -186
+#define LDAPU_ERR_MISSING_INIT_FN_IN_LIB -187
+#define LDAPU_ERR_MISSING_INIT_FN_IN_CONFIG -188
+#define LDAPU_ERR_CERT_VERIFY_FAILED -189
+#define LDAPU_ERR_CERT_VERIFY_NO_CERTS -190
+#define LDAPU_ERR_MISSING_LIBNAME -191
+#define LDAPU_ERR_MISSING_INIT_FN_NAME -192
+
+#define LDAPU_ERR_EMPTY_LDAP_RESULT -193
+#define LDAPU_ERR_MULTIPLE_MATCHES -194
+#define LDAPU_ERR_MISSING_RES_ENTRY -195
+#define LDAPU_ERR_MISSING_UID_ATTR -196
+#define LDAPU_ERR_WRONG_ARGS -197
+#define LDAPU_ERR_RENAME_FILE_FAILED -198
+
+#define LDAPU_ERR_MISSING_VERIFYCERT_VAL -199
+#define LDAPU_ERR_CANAME_IS_MISSING -200
+#define LDAPU_ERR_CAPROP_IS_MISSING -201
+#define LDAPU_ERR_UNKNOWN_CERT_ATTR -202
+#define LDAPU_ERR_INVALID_ARGUMENT -203
+#define LDAPU_ERR_INVALID_SUFFIX -204
+
+/* Error codes returned by cert.c */
+#define LDAPU_ERR_EXTRACT_SUBJECTDN_FAILED -300
+#define LDAPU_ERR_EXTRACT_ISSUERDN_FAILED -301
+#define LDAPU_ERR_EXTRACT_DERCERT_FAILED -302
+
+/* Error codes returned by ldapauth.c */
+#define LDAPU_ERR_CIRCULAR_GROUPS -400
+#define LDAPU_ERR_INVALID_STRING -401
+#define LDAPU_ERR_INVALID_STRING_INDEX -402
+#define LDAPU_ERR_MISSING_ATTR_VAL -403
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+ /* NSAPI_PUBLIC extern char *ldapu_err2string(int err); */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDAPUTIL_LDAPU_H */
diff --git a/include/ldaputil/extcmap.h b/include/ldaputil/extcmap.h
new file mode 100644
index 00000000..fde6a4b3
--- /dev/null
+++ b/include/ldaputil/extcmap.h
@@ -0,0 +1,634 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _PUBLIC_CERTMAP_H
+#define _PUBLIC_CERTMAP_H
+
+#include <ldap.h>
+
+#ifndef NSAPI_PUBLIC
+#if defined( _WINDOWS ) || defined( _WIN32 ) || defined( XP_WIN32 )
+#define NSAPI_PUBLIC __declspec(dllexport)
+#else
+#define NSAPI_PUBLIC
+#endif
+#endif
+
+
+#define LDAPU_ATTR_INITFN "InitFn"
+#define LDAPU_ATTR_LIBRARY "library"
+#define LDAPU_ATTR_DNCOMPS "DNComps"
+#define LDAPU_ATTR_FILTERCOMPS "FilterComps"
+#define LDAPU_ATTR_VERIFYCERT "VerifyCert"
+#define LDAPU_ATTR_CERTMAP_LDAP_ATTR "CmapLdapAttr"
+
+/* Error/Success codes */
+#define LDAPU_SUCCESS 0
+#define LDAPU_FAILED -1
+#define LDAPU_CERT_MAP_FUNCTION_FAILED -2
+#define LDAPU_CERT_SEARCH_FUNCTION_FAILED -3
+#define LDAPU_CERT_VERIFY_FUNCTION_FAILED -4
+#define LDAPU_CERT_MAP_INITFN_FAILED -5
+
+
+/*
+ * CertMapFn_t -
+ * This is a typedef for cert mapping function. The mapping function is
+ * called by the function ldapu_cert_to_ldap_entry.
+ * Parameters:
+ * cert - cert to be mapped. You can pass this to
+ * functions ldapu_get_cert_XYZ.
+ * ld - Handle to the connection to the directory server.
+ * certmap_info - This structure contains information about the
+ * configuration parameters for the cert's issuer (CA).
+ * This structure can be passed to the function
+ * ldapu_certmap_info_attrval to get value for a particular
+ * configuration attribute (or a property).
+ * ldapdn - The mapping function should allocate memory for ldapdn
+ * using malloc and set this variable using the 'cert' and
+ * 'certmap_info'. This DN will be used for ldap lookup.
+ * filter - The mapping function should allocate memory for filter
+ * using malloc and set this variable using the 'cert' and
+ * 'certmap_info'. This will be used as ldap filter for ldap
+ * lookup of the ldapdn.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion (cert is mapped)
+ * return LDAPU_FAILED there is no unexpected error but cert could not
+ * mapped (probably because ldap entry doesn't exist).
+ * otherwise return LDAPU_CERT_MAP_FUNCTION_FAILED.
+ */
+typedef int (*CertMapFn_t)(void *cert, LDAP *ld, void *certmap_info,
+ char **ldapdn, char **filter);
+
+
+/*
+ * CertSearchFn_t -
+ * This is a typedef for cert search function. The search function is
+ * called by the function ldapu_cert_to_ldap_entry after calling the mapping
+ * function. The candidate 'dn' and 'filter' returned by the mapping
+ * function is passed to this function.
+ * The default search function works as follows:
+ * 1. If the 'filter' is NULL, default it to 'objectclass=*'.
+ * 2. If the 'dn' is non-NULL, do a base level search with the 'dn' and
+ * 'filter'. If it succeeds, we are done. If there is no serious
+ * error (LDAP_NO_SUCH_OBJECT is not serious error yet), continue.
+ * 3. If the 'dn' is NULL, default it to 'basedn'.
+ * 4. Perform a 'subtree' search in LDAP for the 'dn' and the 'filter'.
+ * 5. Return the results of the last search.
+ * Parameters:
+ * cert - cert to be mapped. You can pass this to
+ * functions ldapu_get_cert_XYZ.
+ * ld - Handle to the connection to the directory server.
+ * certmap_info - This structure contains information about the
+ * configuration parameters for the cert's issuer (CA).
+ * This structure can be passed to the function
+ * ldapu_certmap_info_attrval to get value for a particular
+ * configuration attribute (or a property).
+ * suffix - If the ldapdn is empty then use this DN to begin the
+ * search. This is the DN of the root object in LDAP
+ * Directory.
+ * ldapdn - candidate 'dn' returned by the mapping function.
+ * filter - returned by the mapping function.
+ * attrs - list of attributes to return from the search. If this is
+ * NULL, all attributes are returned.
+ * res - result of the search which is passed to the verify
+ * function.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * return LDAPU_FAILED there is no unexpected error but entries matching the
+ * 'dn' and 'filter' doesn't exist.
+ * otherwise return LDAPU_CERT_SEARCH_FUNCTION_FAILED.
+ */
+typedef int (*CertSearchFn_t)(void *cert, LDAP *ld, void *certmap_info,
+ const char *suffix, const char *ldapdn,
+ const char *filter, const char **attrs,
+ LDAPMessage ***res);
+
+
+/*
+ * CertVerifyFn_t -
+ * This is a typedef for cert verify function. The verify function is
+ * called by the function ldapu_cert_to_ldap_entry after the cert is
+ * successfully mapped to ldapdn and filter, and an entry matching that
+ * exists in the directory server. The verify fn may get called for
+ * multiple matched entries. This function must go through all the entries
+ * and check which one is appropriate. The pointer to that entry must be
+ * passed back in the 'LDAPMessage **entry' parameter.
+ * Parameters:
+ * cert - Original cert to be mapped. You can pass this to
+ * functions ldapu_get_cert_XYZ.
+ * ld - Handle to the connection to the directory server.
+ * certmap_info - This structure contains information about the
+ * configuration parameters for the cert's issuer (CA).
+ * This structure can be passed to the function
+ * ldapu_certmap_info_attrval to get value for a particular
+ * configuration attribute (or a property).
+ * res - cert is first mapped to ldapdn and filter. 'res' is the
+ * result of ldap search using the ldapdn and filter.
+ * 'ld' and 'res' can be used in the calls to ldapsdk API.
+ * entry - pointer to the entry from 'res' which is the correct match
+ * according to the verify function.
+ *
+ * Return Values:
+ * return LDAPU_SUCCESS upon successful completion (cert is verified)
+ * return LDAPU_FAILED there is no unexpected error but cert could not
+ * verified (probably because it was revoked).
+ * otherwise return LDAPU_CERT_VERIFY_FUNCTION_FAILED.
+ */
+typedef int (*CertVerifyFn_t)(void *cert, LDAP *ld, void *certmap_info,
+ LDAPMessage *res, LDAPMessage **entry);
+
+
+
+/*
+ * CertmapInitFn_t -
+ * This is a typedef for user defined init function. An init function can be
+ * specified in the config file (<ServerRoot>/userdb/certmap.conf) per issuer
+ * of a certificate. This init function must from the user's library, also
+ * loaded from the config file using the 'library' property. The init
+ * function is specified in the config file using the 'InitFn' property.
+ * When the config file is loaded, any user defined init functions will be
+ * called with the certmap_info pertaining to the issuer (CA).
+ * Parameters:
+ * certmap_info - This structure contains information about the
+ * configuration parameters for the cert's issuer (CA).
+ * This structure can be passed to the function
+ * ldapu_certmap_info_attrval to get value for a particular
+ * configuration attribute (or a property).
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise return LDAPU_CERT_MAP_INITFN_FAILED. The server startup will be
+ * aborted if the return value is not LDAPU_SUCCESS.
+ */
+typedef int (*CertMapInitFn_t)(void *certmap_info, const char *issuerName,
+ const char *issuerDN, const char *libname);
+
+/*
+ * Refer to the description of the function ldapu_get_cert_ava_val
+ */
+enum {
+ LDAPU_SUBJECT_DN,
+ LDAPU_ISSUER_DN
+};
+
+/* ldapu_cert_to_ldap_entry */
+typedef int (*t_ldapu_cert_to_ldap_entry)(void *cert, LDAP *ld,
+ const char *suffix,
+ LDAPMessage **res);
+
+/* ldapu_set_cert_mapfn */
+typedef int (*t_ldapu_set_cert_mapfn)(const char *issuerDN,
+ CertMapFn_t mapfn);
+
+/* ldapu_get_cert_mapfn */
+typedef CertMapFn_t (*t_ldapu_get_cert_mapfn) (const char *issuerDN);
+
+/* ldapu_set_cert_searchfn */
+typedef int (*t_ldapu_set_cert_searchfn) (const char *issuerDN,
+ CertSearchFn_t searchfn);
+
+/* ldapu_get_cert_searchfn */
+typedef CertSearchFn_t (*t_ldapu_get_cert_searchfn) (const char *issuerDN);
+
+/* ldapu_set_cert_verifyfn */
+typedef int (*t_ldapu_set_cert_verifyfn) (const char *issuerDN,
+ CertVerifyFn_t verifyFn);
+
+/* ldapu_get_cert_verifyfn */
+typedef CertVerifyFn_t (*t_ldapu_get_cert_verifyfn) (const char *issuerDN);
+
+/* ldapu_get_cert_subject_dn */
+typedef int (*t_ldapu_get_cert_subject_dn) (void *cert, char **subjectDN);
+
+/* ldapu_get_cert_issuer_dn */
+typedef int (*t_ldapu_get_cert_issuer_dn) (void *cert, char **issuerDN);
+
+/* ldapu_get_cert_ava_val */
+typedef int (*t_ldapu_get_cert_ava_val) (void *cert, int which_dn,
+ const char *attr, char ***val);
+
+/* ldapu_free_cert_ava_val */
+typedef int (*t_ldapu_free_cert_ava_val) (char **val);
+
+/* ldapu_get_cert_der */
+typedef int (*t_ldapu_get_cert_der) (void *cert, unsigned char **derCert,
+ unsigned int *len);
+
+/* ldapu_issuer_certinfo */
+typedef int (*t_ldapu_issuer_certinfo) (const char *issuerDN,
+ void **certmap_info);
+
+/* ldapu_certmap_info_attrval */
+typedef int (*t_ldapu_certmap_info_attrval) (void *certmap_info,
+ const char *attr, char **val);
+
+/* ldapu_err2string */
+typedef char * (*t_ldapu_err2string) (int err);
+
+/* ldapu_free */
+typedef void (*t_ldapu_free_old) (char *ptr);
+typedef void (*t_ldapu_free) (void *ptr);
+
+/* ldapu_malloc */
+typedef void *(*t_ldapu_malloc) (int size);
+
+/* ldapu_strdup */
+typedef char *(*t_ldapu_strdup) (const char *ptr);
+
+
+typedef struct LDAPUDispatchVector LDAPUDispatchVector_t;
+struct LDAPUDispatchVector {
+ t_ldapu_cert_to_ldap_entry f_ldapu_cert_to_ldap_entry;
+ t_ldapu_set_cert_mapfn f_ldapu_set_cert_mapfn;
+ t_ldapu_get_cert_mapfn f_ldapu_get_cert_mapfn;
+ t_ldapu_set_cert_searchfn f_ldapu_set_cert_searchfn;
+ t_ldapu_get_cert_searchfn f_ldapu_get_cert_searchfn;
+ t_ldapu_set_cert_verifyfn f_ldapu_set_cert_verifyfn;
+ t_ldapu_get_cert_verifyfn f_ldapu_get_cert_verifyfn;
+ t_ldapu_get_cert_subject_dn f_ldapu_get_cert_subject_dn;
+ t_ldapu_get_cert_issuer_dn f_ldapu_get_cert_issuer_dn;
+ t_ldapu_get_cert_ava_val f_ldapu_get_cert_ava_val;
+ t_ldapu_free_cert_ava_val f_ldapu_free_cert_ava_val;
+ t_ldapu_get_cert_der f_ldapu_get_cert_der;
+ t_ldapu_issuer_certinfo f_ldapu_issuer_certinfo;
+ t_ldapu_certmap_info_attrval f_ldapu_certmap_info_attrval;
+ t_ldapu_err2string f_ldapu_err2string;
+ t_ldapu_free_old f_ldapu_free_old;
+ t_ldapu_malloc f_ldapu_malloc;
+ t_ldapu_strdup f_ldapu_strdup;
+ t_ldapu_free f_ldapu_free;
+};
+
+
+#ifdef INTLDAPU
+NSAPI_PUBLIC extern LDAPUDispatchVector_t *__ldapu_table;
+#else
+typedef int (*CertMapDLLInitFn_t)(LDAPUDispatchVector_t **table);
+
+NSAPI_PUBLIC extern int CertMapDLLInitFn(LDAPUDispatchVector_t **table);
+
+extern LDAPUDispatchVector_t *__ldapu_table;
+
+#if defined( _WINDOWS ) || defined( _WIN32 ) || defined( XP_WIN32 )
+#define CertmapDLLInitFnTbl LDAPUDispatchVector_t *__ldapu_table;
+#define CertmapDLLInit(rv, libname) \
+{\
+ HANDLE h = LoadLibrary((libname)); \
+ CertMapDLLInitFn_t init_fn; \
+ if (!h) return LDAPU_CERT_MAP_INITFN_FAILED; \
+ init_fn = (CertMapDLLInitFn_t)GetProcAddress(h, "CertMapDLLInitFn"); \
+ rv = init_fn(&__ldapu_table); \
+}
+#else
+#define CertmapDLLInit(rv, libname)
+#define CertmapDLLInitFnTbl
+#endif
+
+#endif /* INTLDAPU */
+
+#ifndef INTLDAPU
+
+/*
+ * ldapu_cert_to_ldap_entry -
+ * This function is called to map a cert to an ldap entry. It extracts the
+ * cert issuer information from the given cert. The mapping function set for
+ * the issuer (if any) or the default mapping function is called to map the
+ * subject DN from the cert to a candidate ldap DN and filter for ldap
+ * search. If the mapped ldap DN is NULL, the 'basedn' passed into this
+ * function is used as a starting place for the search. If the mapped filter
+ * is NULL, "objectclass=*" is used as a filter. A base level search is
+ * performed to see if the candidate DN exists in the LDAP database matching
+ * the filter. If there is no match, a scoped search (sub-tree search) is
+ * performed. If at least one entry matched the mapped DN and filter, the
+ * result is passed to the appropriate verify function. The verify function
+ * is called only if 'VerifyCert' parameter has been set for the cert issuer
+ * in the certmap.conf file.
+ * If the verify function succeeds, it must return the pointer to the matched
+ * 'entry'. If at the end, there is only one matching entry, the mapping is
+ * successful.
+ * Parameters:
+ * cert - cert to be mapped. You can pass this to
+ * functions ldapu_get_cert_XYZ.
+ * ld - Handle to the connection to the directory server.
+ * suffix - If the subject dn is mapped to empty LDAP DN then use this
+ * DN to begin the search. This is the DN of the root object
+ * in LDAP Directory.
+ * res - cert is first mapped to ldapdn and filter. 'res' is the
+ * result of ldap search using the ldapdn and filter.
+ * 'ld' and 'res' can be used in the calls to ldapsdk API.
+ * When done with 'res', free it using ldap_msgfree(res)
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_cert_to_ldap_entry (*__ldapu_table->f_ldapu_cert_to_ldap_entry)
+
+/*
+ * ldapu_set_cert_mapfn -
+ * This function can be used to set the cert mapping function for the given
+ * issuer (CA). If the mapping information doesn't exist for the given
+ * issuer then a new one will be created and the mapping function will be
+ * set. When creating the new mapping information, the default mapping
+ * information is copied.
+ * Parameters:
+ * issuerDN - DN of the cert issuer. This mapping function will be used
+ * for all certs issued by this issuer. If the issuerDN is
+ * NULL, the given 'mapfn' becomes the default mapping
+ * function (which is used when no mapping function has been
+ * set for the cert's issuer).
+ * mapfn - the mapping function. Look at the desciption of
+ * CertMapFn_t to find out more about the mapping functions.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_set_cert_mapfn (*__ldapu_table->f_ldapu_set_cert_mapfn)
+
+
+/*
+ * ldapu_get_cert_mapfn -
+ * This function can be used to get the cert mapping function for the given
+ * issuer (CA). This will always return a non-NULL function.
+ * Parameters:
+ * issuerDN - DN of the cert issuer for which the mapping function is to
+ * be retrieved. If this is NULL, default mapping function
+ * is returned.
+ *
+ * Return Value:
+ * The mapping function set for the issuer is returned. If the issuerDN is
+ * NULL or if no specific mapping function has been set for the issuer, the
+ * default mapping function is returned.
+ */
+#define ldapu_get_cert_mapfn (*__ldapu_table->f_ldapu_get_cert_mapfn)
+
+/*
+ * ldapu_set_cert_searchfn -
+ * This function can be used to set the cert search function for the given
+ * issuer (CA).
+ * Parameters:
+ * issuerDN - DN of the cert issuer. This search function will be used
+ * for all certs issued by this issuer. If the issuerDN is
+ * NULL, the given 'searchfn' becomes the default search
+ * function (which is used when no search function has been
+ * set for the cert's issuer).
+ * searchfn - the search function. Look at the desciption of
+ * CertSearchFn_t to find out more about the search functions.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_set_cert_searchfn (*__ldapu_table->f_ldapu_set_cert_searchfn)
+
+
+/*
+ * ldapu_get_cert_searchfn -
+ * This function can be used to get the cert search function for the given
+ * issuer (CA). This will always return a non-NULL function.
+ * Parameters:
+ * issuerDN - DN of the cert issuer for which the search function is to
+ * be retrieved. If this is NULL, the default search
+ * function is returned.
+ *
+ * Return Value:
+ * The search function set for the issuer is returned. If the issuerDN is
+ * NULL or if no specific search function has been set for the issuer, the
+ * default search function is returned.
+ */
+#define ldapu_get_cert_searchfn (*__ldapu_table->f_ldapu_get_cert_searchfn)
+
+/*
+ * ldapu_set_cert_verifyfn -
+ * This function can be used to set the cert verify function for the given
+ * issuer (CA). If the mapping information doesn't exist for the given
+ * issuer then a new one will be created and the verify function will be
+ * set. When creating the new mapping information, the default mapping
+ * information is copied.
+ * Parameters:
+ * issuerDN - DN of the cert issuer. This verify function will be used
+ * for all certs issued by this issuer. If the issuerDN is
+ * NULL, the given 'verifyFn' becomes the default verify
+ * function (which is used when no verify function has been
+ * set for the cert's issuer).
+ * verifyFn - the verify function. Look at the desciption of
+ * CertMapFn_t to find out more about the verify functions.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_set_cert_verifyfn (*__ldapu_table->f_ldapu_set_cert_verifyfn)
+
+/*
+ * ldapu_get_cert_verifyfn -
+ * This function can be used to get the cert verify function for the given
+ * issuer (CA). This function can return NULL when there is no applicable
+ * verify function.
+ * Parameters:
+ * issuerDN - DN of the cert issuer for which the verify function is to
+ * be retrieved. If this is NULL, default verify function
+ * is returned.
+ *
+ * Return Value:
+ * The verify function set for the issuer is returned. If the issuerDN is
+ * NULL or if no specific verify function has been set for the issuer, the
+ * default verify function is returned. This function can return NULL when
+ * there is no applicable verify function.
+ */
+#define ldapu_get_cert_verifyfn (*__ldapu_table->f_ldapu_get_cert_verifyfn)
+
+
+/*
+ * ldapu_get_cert_subject_dn -
+ * This function can be used to get the subject DN from the cert. Free the
+ * subjectDN using 'free' after you are done using it.
+ * Parameters:
+ * cert - cert from which the DN is to be extracted.
+ * subjectDN - subjectDN extracted from the cert. Free it using 'free'
+ * after it is no longer required.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_get_cert_subject_dn (*__ldapu_table->f_ldapu_get_cert_subject_dn)
+
+
+/*
+ * ldapu_get_cert_issuer_dn -
+ * This function can be used to get the issuer DN from the cert. Free the
+ * issuerDN using 'free' after you are done using it.
+ * Parameters:
+ * cert - cert from which the DN is to be extracted.
+ * issuerDN - issuerDN extracted from the cert. Free it using 'free'
+ * after it is no longer required.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_get_cert_issuer_dn (*__ldapu_table->f_ldapu_get_cert_issuer_dn)
+
+
+/*
+ * ldapu_get_cert_ava_val -
+ * This function can be used to get value of the given attribute from either
+ * the subject DN or the issuer DN from the cert.
+ * Parameters:
+ * cert - cert from which the values are to be extracted.
+ * which_dn - Should be either LDAPU_ISSUER_DN or LDAPU_SUBJECT_DN.
+ * attr - Should be one of "CN", "OU", "O", "C", "UID", "MAIL",
+ * "E", "L", and "ST".
+ * val - An array of attribute values extracted from the cert.
+ * There could be multiple values. The last entry in the
+ * array is NULL. You must free this array of strings after
+ * you are done with it (using the function
+ * ldapu_free_cert_ava_val). 'val' is initialized to NULL if
+ * there is an error.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_get_cert_ava_val (*__ldapu_table->f_ldapu_get_cert_ava_val)
+
+
+/*
+ * ldapu_free_cert_ava_val -
+ * This function can be used to free the array returned by the
+ * ldapu_get_cert_ava_val function.
+ * Parameters:
+ * val - An array of attribute values returned by
+ * ldapu_get_cert_ava_val.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_free_cert_ava_val (*__ldapu_table->f_ldapu_free_cert_ava_val)
+
+
+/*
+ * ldapu_get_cert_der -
+ * This function can be used to get the original DER encoded cert for the
+ * given cert.
+ * Parameters:
+ * cert - cert from which the original DER is to be extracted.
+ * derCert - the original DER encoded cert
+ * len - length of derCert
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_get_cert_der (*__ldapu_table->f_ldapu_get_cert_der)
+
+
+/*
+ * ldapu_issuer_certinfo -
+ * This function can be used to get the handle on the internal structure for
+ * the given issuer. This handle can be passed to ldapu_certmap_info_attrval
+ * to get configuration attribute values for the issuer.
+ * Parameters:
+ * issuerDN - DN of the issuer for whom the handle on internal structure
+ * is requested. If issuerDN is NULL, the handle to the
+ * default configuration information is returned.
+ * certmap_info - This structure contains information about the
+ * configuration parameters for the cert's issuer (CA).
+ * This structure can be passed to the function
+ * ldapu_certmap_info_attrval to get value for a particular
+ * configuration attribute (or a property).
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ * CAUTION: DON'T FREE THE 'certmap_info' STRUCTURE.
+ */
+#define ldapu_issuer_certinfo (*__ldapu_table->f_ldapu_issuer_certinfo)
+
+
+/*
+ * ldapu_certmap_info_attrval -
+ * This function can be used to get values for the given attribute/property
+ * from the given certmap_info. You can get handle on the certmap_info by
+ * calling the ldapu_issuer_certinfo function. Free the 'val' using 'free'
+ * after it is no longer required.
+ * Parameters:
+ * certmap_info - This structure contains information about the
+ * configuration parameters for the cert's issuer (CA).
+ * attr - name of the attribute/property for which the value is to
+ * be returned. The attribute can be one of the attributes
+ * listed above (LDAPU_ATTR_XYZ). User defined attributes
+ * can also be used.
+ * val - Value of the 'attr' from the 'certmap_info'.
+ *
+ * Return Value:
+ * return LDAPU_SUCCESS upon successful completion
+ * otherwise returns an error code that can be passed to ldapu_err2string.
+ */
+#define ldapu_certmap_info_attrval (*__ldapu_table->f_ldapu_certmap_info_attrval)
+
+
+/*
+ * ldapu_err2string -
+ * This function can be used to print any of the ldaputil or LDAP error
+ * code.
+ * Parameters:
+ * err - error code to be converted to printable string.
+ *
+ * Return Value:
+ * Printable representation of the given error code.
+ */
+#define ldapu_err2string (*__ldapu_table->f_ldapu_err2string)
+
+/*
+ * ldapu_free -
+ * This function should be used to free the memory allocated by
+ * ldapu_* functions if the ldapu_* function doesn't have a corresponding
+ * 'free' function. Use this function for free'ing the memory allocated by
+ * the following functions:
+ * ldapu_get_cert_subject_dn
+ * ldapu_get_cert_issuer_dn
+ * ldapu_get_cert_der
+ * ldapu_certmap_info_attrval
+ * To free memory allocated by ldapu_get_cert_ava_val, use
+ * ldapu_free_cert_ava_val. Do not free the certmap_info pointer returned by
+ * ldapu_issuer_certinfo.
+ * Parameters:
+ * ptr - pointer returned by ldapu_get_cert_* functions.
+ */
+#define ldapu_free (*__ldapu_table->f_ldapu_free)
+
+/*
+ * ldapu_malloc -
+ * This function is a cover function for the 'malloc' system call. On NT, it
+ * is best to alloc & free the memory in the same DLL.
+ * Parameters:
+ * size - size of the memory to be allocated
+ * Return Value:
+ * same as 'malloc' -- pointer to the allocated memory or NULL on failure.
+ */
+#define ldapu_malloc (*__ldapu_table->f_ldapu_malloc)
+
+/*
+ * ldapu_strdup -
+ * This function is a cover function for the 'strdup' system call. On NT, it
+ * is best to alloc & free the memory in the same DLL.
+ * Parameters:
+ * ptr - Pointer to the string to be copied
+ * Return Value:
+ * same as 'strdup' -- pointer to the copied string or NULL on failure.
+ */
+#define ldapu_strdup (*__ldapu_table->f_ldapu_strdup)
+
+
+#endif /* !INTLDAPU */
+
+#endif /* _PUBLIC_CERTMAP_H */
diff --git a/include/ldaputil/init.h b/include/ldaputil/init.h
new file mode 100644
index 00000000..e983787b
--- /dev/null
+++ b/include/ldaputil/init.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 **/
+#ifndef _LDAPU_INIT_H
+#define _LDAPU_INIT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NSAPI_PUBLIC extern int ldaputil_init (const char *config_file,
+ const char *dllname,
+ const char *serv_root,
+ const char *serv_type,
+ const char *serv_id);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAPU_INIT_H */
diff --git a/include/ldaputil/ldapauth.h b/include/ldaputil/ldapauth.h
new file mode 100644
index 00000000..d4d96bfc
--- /dev/null
+++ b/include/ldaputil/ldapauth.h
@@ -0,0 +1,94 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef LDAPU_AUTH_H
+#define LDAPU_AUTH_H
+
+#include <ldap.h>
+
+#ifndef NSAPI_PUBLIC
+#ifdef XP_WIN32
+#define NSAPI_PUBLIC __declspec(dllexport)
+#else
+#define NSAPI_PUBLIC
+#endif
+#endif
+
+typedef int (*LDAPU_GroupCmpFn_t)(const void *groupids, const char *group,
+ const int len);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int ldapu_find (LDAP *ld, const char *base, int scope,
+ const char *filter, const char **attrs,
+ int attrsonly, LDAPMessage **res);
+
+int ldapu_find_entire_tree (LDAP *ld, int scope,
+ const char *filter, const char **attrs,
+ int attrsonly, LDAPMessage ***res);
+
+extern int ldapu_auth_userdn_groupdn (LDAP *ld, const char *userdn,
+ const char *groupdn,
+ const char *base);
+
+extern int ldapu_auth_uid_groupdn (LDAP *ld, const char *uid,
+ const char *groupdn, const char *base);
+
+extern int ldapu_auth_uid_groupid (LDAP *ld, const char *uid,
+ const char *groupid, const char *base);
+
+extern int ldapu_auth_userdn_groupid (LDAP *ld,
+ const char *userdn, const char *groupid,
+ const char *base);
+
+extern int ldapu_auth_userdn_groupids (LDAP *ld, const char *userdn,
+ void *groupids,
+ LDAPU_GroupCmpFn_t grpcmpfn,
+ const char *base,
+ char **group_out);
+
+extern int ldapu_auth_userdn_attrfilter (LDAP *ld,
+ const char *userdn,
+ const char *attrfilter);
+
+extern int ldapu_auth_uid_attrfilter (LDAP *ld, const char *uid,
+ const char *attrfilter,
+ const char *base);
+
+extern int ldapu_auth_userdn_password (LDAP *ld,
+ const char *userdn,
+ const char *password);
+
+extern int ldapu_find_uid_attrs (LDAP *ld, const char *uid,
+ const char *base, const char **attrs,
+ int attrsonly, LDAPMessage **res);
+
+extern int ldapu_find_uid (LDAP *ld, const char *uid,
+ const char *base, LDAPMessage **res);
+
+NSAPI_PUBLIC extern int ldapu_find_userdn (LDAP *ld, const char *uid,
+ const char *base, char **dn);
+
+extern int ldapu_find_group_attrs (LDAP *ld, const char *groupid,
+ const char *base, const char **attrs,
+ int attrsonly, LDAPMessage **res);
+
+extern int ldapu_find_group (LDAP *ld, const char *groupid,
+ const char *base, LDAPMessage **res);
+
+extern int ldapu_find_groupdn (LDAP *ld, const char *groupid,
+ const char *base, char **dn);
+
+extern int ldapu_auth_uid_password (LDAP *ld, const char *uid,
+ const char *password, const char *base);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDAPU_AUTH_H */
diff --git a/include/ldaputil/ldapdb.h b/include/ldaputil/ldapdb.h
new file mode 100644
index 00000000..13254a93
--- /dev/null
+++ b/include/ldaputil/ldapdb.h
@@ -0,0 +1,100 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _LDAPU_LDAPDB_H
+#define _LDAPU_LDAPDB_H
+
+#include <ldap.h>
+/* removed for LDAPSDK31 integration
+#include <lcache.h>
+*/
+#ifdef LDAPDB_THREAD_SAFE
+/* In the past, we used CRITICAL objects from lib/base/crit.cpp.
+ * Now we use PRMonitor to avoid ldapu to depend on lib/base.
+ */
+#include <prmon.h>
+#else
+#define PRMonitor void
+#endif /* LDAPDB_THREAD_SAFE */
+
+#ifndef NSAPI_PUBLIC
+#ifdef XP_WIN32
+#define NSAPI_PUBLIC __declspec(dllexport)
+#else
+#define NSAPI_PUBLIC
+#endif
+#endif
+
+#define LDAPDB_URL_PREFIX "ldapdb:"
+#define LDAPDB_URL_PREFIX_LEN 7
+
+typedef struct {
+ int use_ssl; /* Set to 0 in case of local LDAP cache */
+ char *host; /* Set to 0 in case of local LDAP cache */
+ int port; /* Set to 0 in case of local LDAP cache */
+ char *basedn;
+ char *scope;
+ char *filter;
+ LDAP *ld;
+ char *binddn; /* Set to 0 in case of local LDAP cache */
+ char *bindpw; /* Set to 0 in case of local LDAP cache */
+ int bound; /* If 0 then not bound with binddn & bindpw */
+ PRMonitor* crit;/* to control critical sections */
+} LDAPDatabase_t;
+
+#define LDAPU_ATTR_BINDDN "binddn"
+#define LDAPU_ATTR_BINDPW "bindpw"
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+NSAPI_PUBLIC extern int ldapu_url_parse (const char *url, const char *binddn,
+ const char *bindpw,
+ LDAPDatabase_t **ldb);
+
+NSAPI_PUBLIC extern int ldapu_ldapdb_url_parse (const char *url,
+ LDAPDatabase_t **ldb);
+
+NSAPI_PUBLIC extern int ldapu_is_local_db (const LDAPDatabase_t *ldb);
+
+NSAPI_PUBLIC extern void ldapu_free_LDAPDatabase_t (LDAPDatabase_t *ldb);
+
+NSAPI_PUBLIC extern LDAPDatabase_t *ldapu_copy_LDAPDatabase_t (const LDAPDatabase_t *ldb);
+
+NSAPI_PUBLIC extern int ldapu_ldap_init (LDAPDatabase_t *ldb);
+
+NSAPI_PUBLIC extern int ldapu_ldap_init_and_bind (LDAPDatabase_t *ldb);
+
+NSAPI_PUBLIC extern int ldapu_ldap_rebind (LDAPDatabase_t *ldb);
+
+NSAPI_PUBLIC extern int ldapu_ldap_reinit_and_rebind (LDAPDatabase_t *ldb);
+
+#ifdef __cplusplus
+}
+#endif
+
+/*
+ * LDAPU_REQ --
+ * 'ld' is cached in the 'ldb' structure. If the LDAP server goes down since
+ * it was cached, the ldap lookup commands fail with LDAP_SERVER_DOWN. This
+ * macro can be used to rebind to the server and retry the command once if
+ * this happens.
+ */
+#define LDAPU_REQ(rv, ldb, cmd) \
+{ \
+ int numtry = 0; \
+ while(1) { \
+ rv = cmd; \
+ if (rv != LDAP_SERVER_DOWN || numtry++ != 0) break; \
+ /* Server went down since our last ldap lookup ... reconnect */ \
+ rv = ldapu_ldap_reinit_and_rebind(ldb); \
+ if (rv != LDAPU_SUCCESS) break; \
+ } \
+}
+
+
+#endif /* LDAPUTIL_LDAPDB_H */
diff --git a/include/ldaputil/ldaputil.h b/include/ldaputil/ldaputil.h
new file mode 100644
index 00000000..f0d87c22
--- /dev/null
+++ b/include/ldaputil/ldaputil.h
@@ -0,0 +1,132 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _LDAPU_LDAPUTIL_H
+#define _LDAPU_LDAPUTIL_H
+
+#include <ldaputil/dbconf.h>
+#include <ldaputil/certmap.h>
+
+typedef struct ldapu_list_node {
+ void *info; /* pointer to the corresponding info */
+ struct ldapu_list_node *next; /* pointer to the next node */
+ struct ldapu_list_node *prev; /* pointer to the prev node */
+} LDAPUListNode_t;
+
+typedef struct ldapu_list {
+ LDAPUListNode_t *head;
+ LDAPUListNode_t *tail;
+} LDAPUList_t;
+
+typedef struct {
+ char *prop; /* property name */
+ char *val; /* value -- only char* supported for now */
+} LDAPUPropVal_t;
+
+typedef LDAPUList_t LDAPUPropValList_t;
+
+enum {
+ COMPS_COMMENTED_OUT,
+ COMPS_EMPTY,
+ COMPS_HAS_ATTRS
+};
+
+typedef struct {
+ char *issuerName; /* issuer (symbolic/short) name */
+ char *issuerDN; /* cert issuer's DN */
+ LDAPUPropValList_t *propval; /* pointer to the prop-val pairs list */
+ CertMapFn_t mapfn; /* cert to ldapdn & filter mapping func */
+ CertVerifyFn_t verifyfn; /* verify cert function */
+ CertSearchFn_t searchfn; /* search ldap entry function */
+ long dncomps; /* bitmask: components to form ldap dn */
+ long filtercomps; /* components used to form ldap filter */
+ int verifyCert; /* Verify the cert? */
+ char *searchAttr; /* LDAP attr used by the search fn */
+ int dncompsState; /* Empty, commented out, or attr names */
+ int filtercompsState; /* Empty, commented out, or attr names */
+} LDAPUCertMapInfo_t;
+
+typedef LDAPUList_t LDAPUCertMapListInfo_t;
+
+typedef void * (*LDAPUListNodeFn_t)(void *info, void *arg);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int certmap_read_default_certinfo (const char *file);
+
+extern int certmap_read_certconfig_file (const char *file);
+
+extern void ldapu_certinfo_free (void *certmap_info);
+
+extern void ldapu_certmap_listinfo_free (void *certmap_listinfo);
+
+extern void ldapu_propval_list_free (void *propval_list);
+
+NSAPI_PUBLIC extern int ldaputil_exit ();
+
+NSAPI_PUBLIC extern int ldapu_cert_to_user (void *cert, LDAP *ld,
+ const char *basedn,
+ LDAPMessage **res,
+ char **user);
+
+NSAPI_PUBLIC extern int ldapu_certmap_init (const char *config_file,
+ const char *libname,
+ LDAPUCertMapListInfo_t **certmap_list,
+ LDAPUCertMapInfo_t
+ **certmap_default);
+
+NSAPI_PUBLIC extern int ldapu_certinfo_modify (const char *issuerName,
+ const char *issuerDN,
+ const LDAPUPropValList_t *propval);
+
+NSAPI_PUBLIC extern int ldapu_certinfo_delete (const char *issuerDN);
+
+NSAPI_PUBLIC extern int ldapu_certinfo_save (const char *fname,
+ const char *old_fname,
+ const char *tmp_fname);
+
+NSAPI_PUBLIC extern int ldapu_list_alloc (LDAPUList_t **list);
+NSAPI_PUBLIC extern int ldapu_propval_alloc (const char *prop, const char *val,
+ LDAPUPropVal_t **propval);
+NSAPI_PUBLIC extern int ldapu_list_add_info (LDAPUList_t *list, void *info);
+
+#ifndef DONT_USE_LDAP_SSL
+#define USE_LDAP_SSL
+#endif
+
+typedef struct {
+#ifdef USE_LDAP_SSL
+ LDAP* (LDAP_CALL LDAP_CALLBACK *ldapuV_ssl_init) ( const char*, int, int );
+#else
+ LDAP* (LDAP_CALL LDAP_CALLBACK *ldapuV_init) ( const char*, int );
+#endif
+ int (LDAP_CALL LDAP_CALLBACK *ldapuV_set_option) ( LDAP*, int, void* );
+ int (LDAP_CALL LDAP_CALLBACK *ldapuV_simple_bind_s) ( LDAP*, const char*, const char* );
+ int (LDAP_CALL LDAP_CALLBACK *ldapuV_unbind) ( LDAP* );
+ int (LDAP_CALL LDAP_CALLBACK *ldapuV_search_s) ( LDAP*, const char*, int, const char*, char**, int, LDAPMessage** );
+ int (LDAP_CALL LDAP_CALLBACK *ldapuV_count_entries) ( LDAP*, LDAPMessage* );
+ LDAPMessage*(LDAP_CALL LDAP_CALLBACK *ldapuV_first_entry) ( LDAP*, LDAPMessage* );
+ LDAPMessage*(LDAP_CALL LDAP_CALLBACK *ldapuV_next_entry) ( LDAP*, LDAPMessage* );
+ int (LDAP_CALL LDAP_CALLBACK *ldapuV_msgfree) ( LDAP*, LDAPMessage* );
+ char* (LDAP_CALL LDAP_CALLBACK *ldapuV_get_dn) ( LDAP*, LDAPMessage* );
+ void (LDAP_CALL LDAP_CALLBACK *ldapuV_memfree) ( LDAP*, void* );
+ char* (LDAP_CALL LDAP_CALLBACK *ldapuV_first_attribute) ( LDAP*, LDAPMessage*, BerElement** );
+ char* (LDAP_CALL LDAP_CALLBACK *ldapuV_next_attribute) ( LDAP*, LDAPMessage*, BerElement* );
+ void (LDAP_CALL LDAP_CALLBACK *ldapuV_ber_free) ( LDAP*, BerElement*, int );
+ char** (LDAP_CALL LDAP_CALLBACK *ldapuV_get_values) ( LDAP*, LDAPMessage*, const char* );
+ void (LDAP_CALL LDAP_CALLBACK *ldapuV_value_free) ( LDAP*, char** );
+ struct berval**(LDAP_CALL LDAP_CALLBACK *ldapuV_get_values_len)( LDAP*, LDAPMessage*, const char* );
+ void (LDAP_CALL LDAP_CALLBACK *ldapuV_value_free_len)( LDAP*, struct berval** );
+} LDAPUVTable_t;
+
+NSAPI_PUBLIC extern void ldapu_VTable_set (LDAPUVTable_t*);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAPU_LDAPUTIL_H */
diff --git a/include/libaccess/acl.h b/include/libaccess/acl.h
new file mode 100644
index 00000000..88ac07f4
--- /dev/null
+++ b/include/libaccess/acl.h
@@ -0,0 +1,41 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef ACL_HEADER
+#define ACL_HEADER
+
+#ifndef NOINTNSACL
+#define INTNSACL
+#endif /* NOINTNSACL */
+
+#include <netsite.h>
+#include <base/pool.h>
+#include <base/pblock.h>
+#include <base/plist.h>
+#include <libaccess/nserror.h>
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef PUBLIC_NSACL_ACLAPI_H
+#include "public/nsacl/aclapi.h"
+#endif /* !PUBLIC_NSACL_ACLAPI_H */
+
+#ifdef INTNSACL
+
+NSPR_BEGIN_EXTERN_C
+
+extern char *generic_rights[];
+extern char *http_generic[];
+
+NSPR_END_EXTERN_C
+
+#endif /* INTNSACL */
+
+#endif
diff --git a/include/libaccess/acladmin.h b/include/libaccess/acladmin.h
new file mode 100644
index 00000000..9bd75623
--- /dev/null
+++ b/include/libaccess/acladmin.h
@@ -0,0 +1,79 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __acladmin_h
+#define __acladmin_h
+
+
+/*
+ * Description (acladmin.h)
+ *
+ * This file describes the interface to access control list (ACL)
+ * administration functions. This interface provides mechanisms
+ * for inspecting, modifying, and writing out in text form ACL
+ * structures.
+ */
+
+#include "aclstruct.h"
+
+NSPR_BEGIN_EXTERN_C
+
+/* Flags used for various functions */
+#define ACLF_NPREFIX 0x1 /* ACL name string is a name prefix */
+#define ACLF_REXACT 0x2 /* rights must match exactly */
+#define ACLF_RALL 0x4 /* must have all specified rights */
+
+/* Functions in acladmin.c */
+extern NSAPI_PUBLIC int aclDNSAddHost(char * newhost,
+ char ***alist, int * asize);
+extern NSAPI_PUBLIC int aclDNSAddAliases(char * host,
+ char ***alist, int * asize);
+extern NSAPI_PUBLIC int aclDNSPutHost(char * hname, int fqdn, int aliases,
+ char ***alist, int * asize);
+extern NSAPI_PUBLIC int aclFindByName(ACContext_t * acc, char * aclname,
+ char **rights, int flags, ACL_t **pacl);
+extern NSAPI_PUBLIC char * aclGetAuthMethod(ACL_t * acl, int dirno);
+extern NSAPI_PUBLIC char * aclGetDatabase(ACL_t * acl, int dirno);
+extern NSAPI_PUBLIC char **aclGetHosts(ACL_t * acl, int dirno, int clsno);
+extern NSAPI_PUBLIC char * aclGetPrompt(ACL_t * acl, int dirno);
+extern NSAPI_PUBLIC char **aclGetRights(ACL_t * acl);
+extern NSAPI_PUBLIC unsigned long aclGetRightsMask(ACContext_t * acc, char **rlist);
+extern NSAPI_PUBLIC char * aclGetSignature(ACL_t * acl);
+extern NSAPI_PUBLIC char **aclGetUsers(ACL_t * acl, int dirno, int clsno);
+extern NSAPI_PUBLIC int aclDNSFilterStrings(char **list, DNSFilter_t * dnf);
+extern NSAPI_PUBLIC int aclIPFilterStrings(char **list, IPFilter_t * ipf);
+extern NSAPI_PUBLIC int aclIdsToNames(char **list,
+ USIList_t * uilptr, int uflag, Realm_t * rlm);
+extern NSAPI_PUBLIC int aclMakeNew(ACContext_t * acc, char * aclsig, char * aclname,
+ char **rights, int flags, ACL_t **pacl);
+extern NSAPI_PUBLIC int aclPutAllowDeny(NSErr_t * errp, ACL_t * acl,
+ int always, int allow, char **users, char **hosts);
+extern NSAPI_PUBLIC int aclPutAuth(NSErr_t * errp, ACL_t * acl,
+ int always, int amethod, char * dbname, char * prompt);
+extern NSAPI_PUBLIC char * aclSafeIdent(char * str);
+extern NSAPI_PUBLIC int aclSetRights(ACL_t * acl, char **rights, int replace);
+extern NSAPI_PUBLIC int accWriteFile(ACContext_t * acc, char * filename, int flags);
+extern NSAPI_PUBLIC int aclStringGet(LEXStream_t * lst);
+extern NSAPI_PUBLIC int aclStringOpen(NSErr_t * errp,
+ int slen, char * sptr, int flags, ACLFile_t **pacf);
+extern NSAPI_PUBLIC int aclCheckUsers(NSErr_t * errp, char * dbpath, char * usernames,
+ char * groupnames, char ***uglist, char ***badulist,
+ char ***badglist);
+extern NSAPI_PUBLIC int aclCheckHosts(NSErr_t * errp,
+ int hexpand, char * dnsspecs, char * ipspecs,
+ char ***hlist, char ***baddns, char ***badip);
+
+#ifdef NOTDEF
+extern int aclSetAuthMethod(ACL_t * acl, int dirno, char * amethod);
+extern int aclSetDatabase(ACL_t * acl, int dirno, char * dbname);
+extern int aclSetExecOptions(ACL_t * acl, char **options);
+extern int aclSetHosts(ACL_t * acl, int dirno, char **hostlist);
+extern int aclSetPrompt(ACL_t * acl, int dirno, char * prompt);
+extern int aclSetUsers(ACL_t * acl, int dirno, char **userlist);
+#endif /* NOTDEF */
+
+NSPR_END_EXTERN_C
+
+#endif /* __acladmin_h */
diff --git a/include/libaccess/aclbuild.h b/include/libaccess/aclbuild.h
new file mode 100644
index 00000000..319f5342
--- /dev/null
+++ b/include/libaccess/aclbuild.h
@@ -0,0 +1,56 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __aclbuild_h
+#define __aclbuild_h
+
+/*
+ * Description (aclbuild.h)
+ *
+ * This file describes the interface to a module which provides
+ * functions for building Access Control List (ACL) structures
+ * in memory.
+ */
+
+#include "usi.h"
+#include "nserror.h"
+#include "aclstruct.h"
+
+/* Define flags for aclAuthNameAdd() return value */
+#define ANA_GROUP 0x1 /* name matches group name */
+#define ANA_USER 0x2 /* name matches user name */
+#define ANA_DUP 0x4 /* name already in AuthNode_t */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Functions in aclbuild.c */
+extern int accCreate(NSErr_t * errp, void * stp, ACContext_t **pacc);
+extern void accDestroy(ACContext_t * acc, int flags);
+extern int accDestroySym(Symbol_t * sym, void * argp);
+extern int accReadFile(NSErr_t * errp, char * aclfile, ACContext_t **pacc);
+extern int aclAuthDNSAdd(HostSpec_t **hspp, char * dnsspec, int fqdn);
+extern int aclAuthIPAdd(HostSpec_t **hspp, IPAddr_t ipaddr, IPAddr_t netmask);
+extern int aclAuthNameAdd(NSErr_t * errp, UserSpec_t * usp,
+ Realm_t * rlm, char * name);
+extern ACClients_t * aclClientsDirCreate();
+extern int aclCreate(NSErr_t * errp,
+ ACContext_t * acc, char * aclname, ACL_t **pacl);
+extern void aclDestroy(ACL_t * acl);
+extern void aclDelete(ACL_t * acl);
+extern int aclDirectiveAdd(ACL_t * acl, ACDirective_t * acd);
+extern ACDirective_t * aclDirectiveCreate();
+extern void aclDirectiveDestroy(ACDirective_t * acd);
+extern int aclDNSSpecDestroy(Symbol_t * sym, void * parg);
+extern void aclHostSpecDestroy(HostSpec_t * hsp);
+extern void aclRealmSpecDestroy(RealmSpec_t * rsp);
+extern int aclRightDef(NSErr_t * errp,
+ ACContext_t * acc, char * rname, RightDef_t **prd);
+extern void aclRightSpecDestroy(RightSpec_t * rsp);
+extern UserSpec_t * aclUserSpecCreate();
+extern void aclUserSpecDestroy(UserSpec_t * usp);
+
+NSPR_END_EXTERN_C
+
+#endif /* __aclbuild_h */
diff --git a/include/libaccess/aclerror.h b/include/libaccess/aclerror.h
new file mode 100644
index 00000000..ffd5510b
--- /dev/null
+++ b/include/libaccess/aclerror.h
@@ -0,0 +1,307 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __aclerror_h
+#define __aclerror_h
+
+/* ACL facility name string (in aclbuild.c) */
+NSPR_BEGIN_EXTERN_C
+extern char * ACL_Program;
+NSPR_END_EXTERN_C
+
+/* Define error identifiers */
+
+/* Errors generated in aclparse.c */
+
+/* aclAuthListParse() */
+#define ACLERR1000 1000 /* dynamic memory shortage */
+
+/* aclAuthHostsParse() */
+#define ACLERR1100 1100 /* unsupported list of host lists */
+#define ACLERR1120 1120 /* host list name not found where expected */
+#define ACLERR1140 1140 /* undefined host list name */
+#define ACLERR1160 1160 /* *unused* */
+#define ACLERR1180 1180 /* error adding IP filter entry */
+#define ACLERR1200 1200 /* error adding DNS filter entry */
+#define ACLERR1220 1220 /* ")" missing */
+
+/* aclAuthUsersParse() */
+#define ACLERR1300 1300 /* *unused* */
+#define ACLERR1320 1320 /* *unused* */
+#define ACLERR1340 1340 /* *unused* */
+#define ACLERR1360 1360 /* undefined user or group name */
+#define ACLERR1380 1380 /* duplicate user or group name */
+#define ACLERR1400 1400 /* ")" missing */
+#define ACLERR1420 1420 /* empty auth-user-elem */
+#define ACLERR1440 1440 /* duplicate or conflicting use of "all" */
+#define ACLERR1460 1460 /* duplicate or conflicting use of "any" */
+#define ACLERR1480 1480 /* conflicting use of "all" or "any" */
+#define ACLERR1500 1500 /* insufficient dynamic memory */
+#define ACLERR1520 1520 /* insufficient dynamic memory */
+
+/* aclDirectivesParse() */
+#define ACLERR1600 1600 /* dir-access missing */
+#define ACLERR1620 1620 /* invalid dir-access specification */
+#define ACLERR1640 1640 /* error adding ACD_AUTH directive to ACL */
+#define ACLERR1650 1650 /* error adding directive to ACL */
+#define ACLERR1660 1660 /* insufficient dynamic memory */
+#define ACLERR1680 1680 /* insufficient dynamic memory */
+#define ACLERR1685 1685 /* insufficient dynamic memory */
+#define ACLERR1690 1690 /* error adding directive to ACL */
+#define ACLERR1695 1695 /* error in "execute" directive */
+
+/* aclACLParse() */
+#define ACLERR1700 1700 /* ACL statement missing */
+#define ACLERR1720 1720 /* ACL name missing */
+#define ACLERR1740 1740 /* opening "{" missing */
+#define ACLERR1760 1760 /* closing "}" missing */
+#define ACLERR1780 1780 /* unrecognized ACL statement */
+
+/* aclFileOpen() */
+#define ACLERR1900 1900 /* file open error */
+#define ACLERR1920 1920 /* memory shortage for ACLFile_t */
+#define ACLERR1940 1940 /* memory shortage for token */
+#define ACLERR1960 1960 /* memory shortage for LEX stream */
+
+/* aclGetDNSString() */
+#define ACLERR2100 2100 /* */
+#define ACLERR2120 2120 /* */
+#define ACLERR2140 2140 /* */
+
+/* aclGetIPAddr() */
+#define ACLERR2200 2200 /* */
+#define ACLERR2220 2220 /* */
+#define ACLERR2240 2240 /* */
+#define ACLERR2260 2260 /* */
+#define ACLERR2280 2280 /* */
+#define ACLERR2300 2300 /* */
+#define ACLERR2320 2320 /* */
+
+/* aclGetToken() */
+#define ACLERR2400 2400 /* aclGetToken() parse error */
+
+/* aclParseInit() */
+
+/* aclRealmSpecParse() */
+#define ACLERR2500 2500 /* missing realm name */
+#define ACLERR2520 2520 /* undefined realm name */
+#define ACLERR2540 2540 /* insufficient dynamic memory */
+#define ACLERR2560 2560 /* missing realm directive */
+#define ACLERR2570 2570 /* missing database filespec */
+#define ACLERR2580 2580 /* missing authentication method name */
+#define ACLERR2600 2600 /* unknown authentication method name */
+#define ACLERR2605 2605 /* realm prompt string missing */
+#define ACLERR2610 2610 /* unknown realm directive */
+#define ACLERR2620 2620 /* missing "}" */
+
+/* aclRightsParse() */
+#define ACLERR2700 2700 /* missing rights list element */
+#define ACLERR2720 2720 /* missing rights list name */
+#define ACLERR2740 2740 /* undefined rights list name */
+#define ACLERR2760 2760 /* insufficient dynamic memory */
+#define ACLERR2780 2780 /* insufficient dynamic memory */
+#define ACLERR2800 2800 /* error creating access right definition */
+#define ACLERR2820 2820 /* insufficient dynamic memory */
+#define ACLERR2840 2840 /* missing ")" */
+
+/* aclGetFileSpec() */
+#define ACLERR2900 2900 /* skip over whitespace failed */
+#define ACLERR2920 2920 /* scan over filename failed */
+#define ACLERR2940 2940 /* missing filename */
+
+/* aclStringOpen() */
+#define ACLERR5000 5000 /* memory shortage for ACLFile_t */
+#define ACLERR5020 5020 /* memory shortage for token */
+#define ACLERR5040 5040 /* memory shortage for LEX stream */
+
+/* Errors generated in aclbuild.c */
+
+/* accCreate() */
+#define ACLERR3000 3000 /* insufficient dynamic memory */
+#define ACLERR3020 3020 /* insufficient dynamic memory */
+
+/* accFileRead() */
+#define ACLERR3100 3100 /* error initializing ACL parser */
+#define ACLERR3120 3120 /* error creating ACL symbol table */
+
+/* aclCreate() */
+#define ACLERR3200 3200 /* insufficient dynamic memory */
+#define ACLERR3220 3220 /* duplicate ACL name */
+
+/* aclAuthNameAdd() */
+#define ACLERR3400 3400 /* realm missing for user/group name */
+#define ACLERR3420 3420 /* error opening authentication DB */
+#define ACLERR3440 3440 /* error finding name in DB */
+#define ACLERR3460 3460 /* insufficient dynamic memory */
+
+/* aclRightDef() */
+#define ACLERR3600 3600 /* insufficient dynamic memory */
+#define ACLERR3620 3620 /* add right to symbol table failed */
+
+/* ACL_ListPostParseForAuth() */
+#define ACLERR3800 3800 /* Undefined method/database */
+#define ACLERR3810 3810 /* insufficient dynamic memory */
+
+/* Register.cpp */
+#define ACLERR3900 3900 /* Duplicate LAS registered */
+
+/* ACL_EvalBuildContext */
+#define ACLERR4000 4000 /* Unable to create context hash */
+#define ACLERR4010 4010 /* Unable to alloc cache structure */
+#define ACLERR4020 4020 /* Unable to alloc ACE entry */
+#define ACLERR4030 4030 /* Unable to alloc ACE entry */
+#define ACLERR4040 4040 /* Unable to alloc Auth Ptr Array */
+#define ACLERR4050 4050 /* Unable to alloc Auth Ptr Array */
+
+/* ACL_EvalTestRights */
+#define ACLERR4100 4100 /* Interim absolute, non-allow value */
+#define ACLERR4110 4110 /* BuildContext call failed */
+
+/* ACL_ModuleRegister */
+#define ACLERR4200 4200 /* module name missing */
+#define ACLERR4210 4210 /* module registration call failed */
+
+/* ACL_GetAttribute */
+#define ACLERR4300 4300 /* Couldn't determine method */
+#define ACLERR4310 4310 /* Couldn't locate Getter */
+#define ACLERR4320 4320 /* Couldn't Set Attr */
+#define ACLERR4330 4330 /* Couldn't Get Attr */
+#define ACLERR4340 4340 /* All getters declined */
+#define ACLERR4350 4350 /* All getters declined */
+#define ACLERR4360 4360 /* All getters declined */
+#define ACLERR4370 4370 /* All getters declined */
+#define ACLERR4380 4380 /* Couldn't determine dbtype */
+
+/* reg_dbname_internal */
+#define ACLERR4400 4400 /* dbtype not defined yet */
+#define ACLERR4410 4410 /* dbtype not defined yet */
+#define ACLERR4420 4420 /* out of memory */
+
+/* ACL_DatabaseRegister */
+#define ACLERR4500 4500 /* database name is missing */
+
+/* ACL_ReadDbMapFile */
+#define ACLERR4600 4600 /* Error reading the Map file */
+#define ACLERR4610 4610 /* Couldn't determine dbtype */
+#define ACLERR4620 4620 /* Missing URL for database */
+#define ACLERR4630 4630 /* Invalid proprty pair */
+#define ACLERR4640 4640 /* Register database failed */
+#define ACLERR4650 4650 /* Default database not LDAP */
+#define ACLERR4660 4660 /* Multiple default databases */
+#define ACLERR4670 4670 /* No default database */
+
+/* LASDnsBuild */
+#define ACLERR4700 4700 /* Cannot allocatae hash */
+#define ACLERR4710 4710 /* Cannot add token to hash */
+#define ACLERR4720 4720 /* Cannot add token to hash */
+#define ACLERR4730 4730 /* Cannot add token to hash */
+#define ACLERR4740 4740 /* Cannot add token to hash */
+#define ACLERR4750 4750 /* Cannot add token to hash */
+#define ACLERR4760 4760 /* Cannot add token to hash */
+
+/* LASDnsEval */
+#define ACLERR4800 4800 /* Wrong attribute name */
+#define ACLERR4810 4810 /* Illegal comparator */
+#define ACLERR4820 4820 /* Cannot allocate context struct */
+#define ACLERR4830 4830 /* Cannot get DNS attribute */
+
+/* LASGroupEval */
+#define ACLERR4900 4900 /* wrong attribute */
+#define ACLERR4910 4910 /* bad comparator */
+#define ACLERR4920 4920 /* unable to get database name */
+
+/* LASIpTreeAllocNode */
+#define ACLERR5000 5000 /* Cannot allocate IP tree */
+
+/* LASIpAddPattern */
+#define ACLERR5100 5100 /* Cannot allocate IP tree node */
+#define ACLERR5110 5110 /* Cannot allocate IP tree node */
+
+/* LASIpEval */
+#define ACLERR5200 5200 /* Wrong attribute */
+#define ACLERR5210 5210 /* Bad comparator */
+#define ACLERR5220 5220 /* Cannot get session pointer */
+#define ACLERR5230 5230 /* Cannot allocate context */
+#define ACLERR5240 5240 /* Tested 32 bits without conclusion */
+
+/* LASProgramEval */
+#define ACLERR5300 5300 /* Wrong attribute */
+#define ACLERR5310 5310 /* Bad comparator */
+#define ACLERR5320 5320 /* Can't get request pointer */
+#define ACLERR5330 5330 /* Invalid program expression */
+#define ACLERR5340 5340 /* Rejecting Request */
+
+/* LASDayOfWeekEval */
+#define ACLERR5400 5400 /* wrong attribute */
+#define ACLERR5410 5410 /* bad comparator */
+
+/* LASTimeOfDayEval */
+#define ACLERR5600 5600 /* wrong attribute */
+#define ACLERR5610 5610 /* bad comparator */
+
+/* LASUserEval */
+#define ACLERR5700 5700 /* wrong attribute */
+#define ACLERR5710 5710 /* bad comparator */
+#define ACLERR5720 5720 /* Out of memory */
+
+/* ldapacl.cpp */
+#define ACLERR5800 5800 /* missing the database url */
+#define ACLERR5810 5810 /* missing the database name */
+#define ACLERR5820 5820 /* error parsing the db url */
+#define ACLERR5830 5830 /* unable to get db name */
+#define ACLERR5840 5840 /* can't get parsed db name */
+#define ACLERR5850 5850 /* can't init ldap connection */
+#define ACLERR5860 5860 /* passwd check ldap error */
+#define ACLERR5870 5870 /* Out of memory */
+#define ACLERR5880 5880 /* User doesn't exist anymore */
+#define ACLERR5890 5890 /* PList error */
+
+/* get_user_ismember_ldap */
+#define ACLERR5900 5900 /* Can't get db name */
+#define ACLERR5910 5910 /* Can't get parsed db name */
+#define ACLERR5920 5920 /* Out of memory */
+#define ACLERR5930 5930 /* Can't init ldap connection */
+#define ACLERR5940 5940 /* Group doesn't exist */
+#define ACLERR5950 5950 /* LDAP error */
+
+/* ACL_LDAPDatabaseHandle */
+#define ACLERR6000 6000 /* Not a registered db */
+#define ACLERR6010 6010 /* Not an LDAP db */
+#define ACLERR6020 6020 /* Out of memory */
+#define ACLERR6030 6030 /* Can't init ldap connection */
+#define ACLERR6040 6040 /* Can't bind to ldap server */
+
+
+
+/* Define error return codes */
+#define ACLERRNOMEM -1 /* insufficient dynamic memory */
+#define ACLERROPEN -2 /* file open error */
+#define ACLERRDUPSYM -3 /* duplicate symbol */
+#define ACLERRSYNTAX -4 /* syntax error */
+#define ACLERRUNDEF -5 /* undefined symbol */
+#define ACLERRADB -6 /* authentication DB access error */
+#define ACLERRPARSE -7 /* ACL parsing error */
+#define ACLERRNORLM -8 /* missing authentication realm */
+#define ACLERRIO -9 /* IO error */
+#define ACLERRINTERNAL -10 /* internal processing error */
+/* #define ACLERRFAIL -11 */ /* defined in include/public/nsacl/acldef.h */
+#define ACLERRINVAL -12 /* invalid argument */
+#define ACLERRCONFIG -13 /* auth realms don't math acl */
+
+#include "nserror.h"
+
+#ifndef PUBLIC_NSACL_ACLDEF_H
+#include "public/nsacl/acldef.h"
+#endif /* !PUBLIC_NSACL_ACLDEF_H */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Functions in aclerror.c */
+extern void aclErrorFmt(NSErr_t * errp,
+ char * msgbuf, int maxlen, int maxdepth);
+
+NSPR_END_EXTERN_C
+
+#endif /* __aclerror_h */
diff --git a/include/libaccess/acleval.h b/include/libaccess/acleval.h
new file mode 100644
index 00000000..7fbd077a
--- /dev/null
+++ b/include/libaccess/acleval.h
@@ -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 **/
+#ifndef __acleval_h
+#define __acleval_h
+
+/*
+ * Description (acleval.h)
+ *
+ * This file defines the interface to the ACL evaluation module.
+ */
+
+#include "nserror.h"
+#include "nsauth.h"
+#include "aclstruct.h"
+
+/* Define values returned by lookup routines */
+#define ACL_NOMATCH 0 /* no match */
+#define ACL_IPMATCH 0x1 /* IP address match */
+#define ACL_DNMATCH 0x2 /* DNS name match */
+#define ACL_USMATCH 0x4 /* user name match */
+#define ACL_GRMATCH 0x8 /* user is member of group */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Functions in acleval.c */
+extern int aclDNSLookup(DNSFilter_t * dnf,
+ char * dnsspec, int fqdn, char **match);
+extern int aclIPLookup(IPFilter_t * ipf, IPAddr_t ipaddr, void **match);
+extern int aclUserLookup(UidUser_t * uup, UserObj_t * uoptr);
+extern int aclEvaluate(ACL_t * acl, USI_t arid, ClAuth_t * clauth, int * padn);
+
+NSPR_END_EXTERN_C
+
+#endif /* __acleval_h */
diff --git a/include/libaccess/aclglobal.h b/include/libaccess/aclglobal.h
new file mode 100644
index 00000000..165a69ef
--- /dev/null
+++ b/include/libaccess/aclglobal.h
@@ -0,0 +1,52 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+** Header file containing global data elements. These are duplicated
+** when a cache flush is done.
+*/
+
+#include <libaccess/acl.h>
+
+struct ACLGlobal_s {
+ ACLListHandle_t *masterlist;
+ pool_handle_t *pool; /* Deallocate at the start of cache flush */
+ pool_handle_t *databasepool;
+ pool_handle_t *methodpool;
+ PRHashTable *urihash;
+ PRHashTable *urigethash;
+ PRHashTable *listhash;
+ PRHashTable *evalhash;
+ PRHashTable *flushhash;
+ PRHashTable *methodhash;
+ PRHashTable *dbtypehash;
+ PRHashTable *dbnamehash;
+ PRHashTable *attrgetterhash;
+ PRHashTable *userLdbHash; /* user's LDAP handle hash */
+};
+
+typedef struct ACLGlobal_s ACLGlobal_t;
+typedef struct ACLGlobal_s *ACLGlobal_p;
+
+#define acl_uri_hash_pool ACLGlobal->pool
+#define acl_uri_hash ACLGlobal->urihash
+#define acl_uri_get_hash ACLGlobal->urigethash
+#define ACLListHash ACLGlobal->listhash
+#define ACLLasEvalHash ACLGlobal->evalhash
+#define ACLLasFlushHash ACLGlobal->flushhash
+#define ACLMethodHash ACLGlobal->methodhash
+#define ACLDbTypeHash ACLGlobal->dbtypehash
+#define ACLDbNameHash ACLGlobal->dbnamehash
+#define ACLAttrGetterHash ACLGlobal->attrgetterhash
+#define ACLUserLdbHash ACLGlobal->userLdbHash
+#define ACL_DATABASE_POOL ACLGlobal->databasepool
+#define ACL_METHOD_POOL ACLGlobal->methodpool
+
+NSPR_BEGIN_EXTERN_C
+
+extern ACLGlobal_p ACLGlobal;
+extern ACLGlobal_p oldACLGlobal;
+
+NSPR_END_EXTERN_C
diff --git a/include/libaccess/aclparse.h b/include/libaccess/aclparse.h
new file mode 100644
index 00000000..503657e1
--- /dev/null
+++ b/include/libaccess/aclparse.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 **/
+#ifndef __aclparse_h
+#define __aclparse_h
+
+/*
+ * Description (aclparse.h)
+ *
+ * This file describes the interface to a parser for files
+ * containing Access Control List (ACL) definitions. The parser
+ * uses the services of the aclbuild module to construct an
+ * in-memory representation of the ACLs it parses.
+ */
+
+#include "nserror.h"
+#include "aclbuild.h"
+
+/* Define keywords */
+#define KEYWORD_ACL "acl"
+#define KEYWORD_ALL "all"
+#define KEYWORD_ALLOW "allow"
+#define KEYWORD_ANY "anyone"
+#define KEYWORD_AT "at"
+#define KEYWORD_AUTH "authenticate"
+#define KEYWORD_BASIC "basic"
+#define KEYWORD_DATABASE "database"
+#define KEYWORD_DEFAULT "default"
+#define KEYWORD_DENY "deny"
+#define KEYWORD_EXECUTE "execute"
+#define KEYWORD_HOSTS "hosts"
+#define KEYWORD_IF "if"
+#define KEYWORD_IN "in"
+#define KEYWORD_INCLUDE "include"
+#define KEYWORD_METHOD "method"
+#define KEYWORD_PROMPT "prompt"
+#define KEYWORD_REALM "realm"
+#define KEYWORD_RIGHTS "rights"
+#define KEYWORD_SSL "ssl"
+
+/* Define character classes */
+#define CCM_WS 0x1 /* whitespace */
+#define CCM_NL 0x2 /* newline */
+#define CCM_SPECIAL 0x4 /* special characters */
+#define CCM_DIGIT 0x8 /* digits */
+#define CCM_LETTER 0x10 /* letters */
+#define CCM_HYPHEN 0x20 /* hyphen */
+#define CCM_USCORE 0x40 /* underscore */
+#define CCM_FILESPEC 0x80 /* filename special characters */
+
+#define CCM_HYPUND (CCM_HYPHEN|CCM_USCORE)
+#define CCM_IDENT (CCM_LETTER|CCM_DIGIT|CCM_HYPUND)
+#define CCM_FILENAME (CCM_LETTER|CCM_DIGIT|CCM_FILESPEC)
+
+/* Define token numbers */
+#define TOKEN_ERROR -1 /* error in reading data stream */
+#define TOKEN_EOF 0 /* end-of-file */
+#define TOKEN_EOS 1 /* end-of-statement */
+#define TOKEN_IDENT 2 /* identifier */
+#define TOKEN_NUMBER 3 /* number */
+#define TOKEN_COMMA 4 /* comma */
+#define TOKEN_SEMI 5 /* semicolon */
+#define TOKEN_PERIOD 6 /* period */
+#define TOKEN_LPAREN 7 /* left parenthesis */
+#define TOKEN_RPAREN 8 /* right parenthesis */
+#define TOKEN_LBRACE 9 /* left brace */
+#define TOKEN_RBRACE 10 /* right brace */
+#define TOKEN_AT 11 /* at sign */
+#define TOKEN_PLUS 12 /* plus sign */
+#define TOKEN_STAR 13 /* asterisk */
+#define TOKEN_STRING 14 /* quoted string */
+#define TOKEN_HUH 15 /* unrecognized input */
+
+/* Define flags bits for aclGetToken() */
+#define AGT_NOSKIP 0x1 /* don't skip leading whitespace */
+#define AGT_APPEND 0x2 /* append next to token buffer */
+
+NSPR_BEGIN_EXTERN_C
+
+extern void * aclChTab; /* character table for ACL parsing */
+
+/* Functions in aclparse.c */
+extern int aclAuthListParse(NSErr_t * errp, ACLFile_t * acf,
+ ACContext_t * acc, Realm_t * rlm,
+ ACClients_t **clsp);
+extern int aclAuthHostsParse(NSErr_t * errp, ACLFile_t * acf,
+ ACContext_t * acc, HostSpec_t **hspp);
+extern int aclAuthUsersParse(NSErr_t * errp, ACLFile_t * acf,
+ Realm_t * rlm, UserSpec_t **uspp, char ***elist);
+extern int aclDirectivesParse(NSErr_t * errp, ACLFile_t * acf, ACL_t * acl);
+extern int aclACLParse(NSErr_t * errp,
+ ACLFile_t * acf, ACContext_t * acc, int flags);
+extern void aclFileClose(ACLFile_t * acf, int flags);
+extern int aclFileOpen(NSErr_t * errp,
+ char * filename, int flags, ACLFile_t **pacf);
+extern int aclGetDNSString(NSErr_t * errp, ACLFile_t * acf);
+extern int aclGetFileSpec(NSErr_t * errp, ACLFile_t * acf, int flags);
+extern int aclGetIPAddr(NSErr_t * errp,
+ ACLFile_t * acf, IPAddr_t * pip, IPAddr_t * pmask);
+extern int aclGetToken(NSErr_t * errp, ACLFile_t * acf, int flags);
+extern int aclParseInit();
+extern int aclRealmSpecParse(NSErr_t * errp, ACLFile_t * acf,
+ ACContext_t * acc, RealmSpec_t **rspp);
+extern int aclRightsParse(NSErr_t * errp, ACLFile_t * acf, ACContext_t * acc,
+ RightSpec_t **rights);
+extern int aclStreamGet(LEXStream_t * lst);
+
+NSPR_END_EXTERN_C
+
+#endif /* __aclparse_h */
diff --git a/include/libaccess/aclproto.h b/include/libaccess/aclproto.h
new file mode 100644
index 00000000..6dbc07d5
--- /dev/null
+++ b/include/libaccess/aclproto.h
@@ -0,0 +1,156 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef ACL_PROTO_HEADER
+#define ACL_PROTO_HEADER
+
+#ifndef NOINTNSACL
+#define INTNSACL
+#endif /* !NOINTNSACL */
+
+#ifndef PUBLIC_NSACL_ACLDEF_H
+#include "public/nsacl/acldef.h"
+#endif /* !PUBLIC_NSACL_ACLDEF_H */
+
+#ifdef INTNSACL
+
+NSPR_BEGIN_EXTERN_C
+
+/*********************************************************************
+ * ACL language and file interfaces
+ *********************************************************************/
+
+NSAPI_PUBLIC ACLListHandle_t * ACL_ParseFile(NSErr_t *errp, char *filename);
+NSAPI_PUBLIC ACLListHandle_t * ACL_ParseString(NSErr_t *errp, char *buffer);
+NSAPI_PUBLIC int ACL_Decompose(NSErr_t *errp, char **acl, ACLListHandle_t *acl_list);
+NSAPI_PUBLIC int ACL_WriteString(NSErr_t *errp, char **acl, ACLListHandle_t *acllist);
+NSAPI_PUBLIC int ACL_WriteFile(NSErr_t *errp, char *filename, ACLListHandle_t *acllist);
+NSAPI_PUBLIC int ACL_FileRenameAcl(NSErr_t *errp, char *filename, char *acl_name, char *new_acl_name, int flags);
+NSAPI_PUBLIC int ACL_FileDeleteAcl(NSErr_t *errp, char *filename, char *acl_name, int flags);
+NSAPI_PUBLIC int ACL_FileGetAcl(NSErr_t *errp, char *filename, char *acl_name, char **acl_text, int flags);
+NSAPI_PUBLIC int ACL_FileSetAcl(NSErr_t *errp, char *filename, char *acl_text, int flags);
+NSAPI_PUBLIC int ACL_FileMergeAcl(NSErr_t *errp, char *filename, char **acl_name_list, char *new_acl_name, int flags);
+NSAPI_PUBLIC int ACL_FileMergeFile(NSErr_t *errp, char *filename, char **file_list, int flags);
+
+
+/*********************************************************************
+ * ACL Expression construction interfaces
+ *********************************************************************/
+NSAPI_PUBLIC ACLExprHandle_t *ACL_ExprNew(const ACLExprType_t expr_type);
+NSAPI_PUBLIC void ACL_ExprDestroy(ACLExprHandle_t *expr);
+NSAPI_PUBLIC int ACL_ExprSetPFlags(NSErr_t *errp, ACLExprHandle_t *expr, PFlags_t flags);
+NSAPI_PUBLIC int ACL_ExprClearPFlags(NSErr_t *errp, ACLExprHandle_t *expr);
+NSAPI_PUBLIC int ACL_ExprTerm(NSErr_t *errp, ACLExprHandle_t *acl_expr, char *attr_name, CmpOp_t cmp, char *attr_pattern);
+NSAPI_PUBLIC int ACL_ExprNot(NSErr_t *errp, ACLExprHandle_t *acl_expr);
+NSAPI_PUBLIC int ACL_ExprAnd(NSErr_t *errp, ACLExprHandle_t *acl_expr);
+NSAPI_PUBLIC int ACL_ExprOr(NSErr_t *errp, ACLExprHandle_t *acl_expr);
+NSAPI_PUBLIC int ACL_ExprAddAuthInfo(ACLExprHandle_t *expr, PList_t auth_info);
+NSAPI_PUBLIC int ACL_ExprAddArg(NSErr_t *errp, ACLExprHandle_t *expr, char *arg);
+NSAPI_PUBLIC int ACL_ExprSetDenyWith(NSErr_t *errp, ACLExprHandle_t *expr, char *deny_type, char *deny_response);
+NSAPI_PUBLIC int ACL_ExprGetDenyWith(NSErr_t *errp, ACLExprHandle_t *expr, char **deny_type, char **deny_response);
+
+/*********************************************************************
+ * ACL manipulation
+ *********************************************************************/
+
+NSAPI_PUBLIC ACLHandle_t * ACL_AclNew(NSErr_t *errp, char *tag);
+NSAPI_PUBLIC void ACL_AclDestroy(NSErr_t *errp, ACLHandle_t *acl);
+NSAPI_PUBLIC int ACL_ExprAppend(NSErr_t *errp, ACLHandle_t *acl, ACLExprHandle_t *expr);
+NSAPI_PUBLIC const char *ACL_AclGetTag(ACLHandle_t *acl);
+
+/*********************************************************************
+ * ACL list manipulation
+ *********************************************************************/
+
+NSAPI_PUBLIC ACLListHandle_t * ACL_ListNew(NSErr_t *errp);
+NSAPI_PUBLIC int ACL_ListConcat(NSErr_t *errp, ACLListHandle_t *acl_list1, ACLListHandle_t *acl_list2, int flags);
+NSAPI_PUBLIC int ACL_ListAppend(NSErr_t *errp, ACLListHandle_t *acllist, ACLHandle_t *acl, int flags);
+NSAPI_PUBLIC void ACL_ListDestroy(NSErr_t *errp, ACLListHandle_t *acllist);
+NSAPI_PUBLIC ACLHandle_t * ACL_ListFind(NSErr_t *errp, ACLListHandle_t *acllist, char *aclname, int flags);
+NSAPI_PUBLIC int ACL_ListAclDelete(NSErr_t *errp, ACLListHandle_t *acl_list, char *acl_name, int flags);
+NSAPI_PUBLIC int ACL_ListGetNameList(NSErr_t *errp, ACLListHandle_t *acl_list, char ***name_list);
+NSAPI_PUBLIC int ACL_FileGetNameList(NSErr_t *errp, char * filename, char ***name_list);
+NSAPI_PUBLIC int ACL_NameListDestroy(NSErr_t *errp, char **name_list);
+NSAPI_PUBLIC ACLHandle_t *ACL_ListGetFirst(ACLListHandle_t *acl_list,
+ ACLListEnum_t *acl_enum);
+NSAPI_PUBLIC ACLHandle_t *ACL_ListGetNext(ACLListHandle_t *acl_list,
+ ACLListEnum_t *acl_enum);
+
+/* Only used for asserts. Probably shouldn't be publicly advertized */
+extern int ACL_AssertAcllist( ACLListHandle_t *acllist );
+
+/* Need to be ACL_LIB_INTERNAL */
+NSAPI_PUBLIC int ACL_ListPostParseForAuth(NSErr_t *errp, ACLListHandle_t *acl_list);
+
+/*********************************************************************
+ * ACL evaluation
+ *********************************************************************/
+
+NSAPI_PUBLIC int ACL_EvalTestRights(NSErr_t *errp, ACLEvalHandle_t *acleval, char **rights, char **map_generic, char **deny_type, char **deny_response, char **acl_tag, int *expr_num);
+NSAPI_PUBLIC int ACL_CachableAclList(ACLListHandle_t *acllist);
+NSAPI_PUBLIC ACLEvalHandle_t * ACL_EvalNew(NSErr_t *errp, pool_handle_t *pool);
+NSAPI_PUBLIC void ACL_EvalDestroy(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval);
+NSAPI_PUBLIC void ACL_EvalDestroyNoDecrement(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval);
+NSAPI_PUBLIC int ACL_ListDecrement(NSErr_t *errp, ACLListHandle_t *acllist);
+NSAPI_PUBLIC int ACL_EvalSetACL(NSErr_t *errp, ACLEvalHandle_t *acleval, ACLListHandle_t *acllist);
+NSAPI_PUBLIC PList_t ACL_EvalGetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval);
+NSAPI_PUBLIC int ACL_EvalSetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t subject);
+NSAPI_PUBLIC PList_t ACL_EvalGetResource(NSErr_t *errp, ACLEvalHandle_t *acleval);
+NSAPI_PUBLIC int ACL_EvalSetResource(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t resource);
+
+/*
+ * The following entities are only meant to be called by whole server
+ * products that include libaccess. E.g. the HTTP server, the Directory
+ * server etc. They should not be called by ACL callers, LASs etc.
+ */
+
+/*********************************************************************
+ * ACL misc routines
+ *********************************************************************/
+
+NSAPI_PUBLIC int ACL_Init(void);
+NSAPI_PUBLIC int ACL_InitPostMagnus(void);
+NSAPI_PUBLIC int ACL_LateInitPostMagnus(void);
+NSAPI_PUBLIC void ACL_ListHashUpdate(ACLListHandle_t **acllistp);
+NSAPI_PUBLIC void ACL_GetPathAcls(char *path, ACLListHandle_t **acllist_p, char *prefix, ACLListHandle_t *masterlist);
+NSAPI_PUBLIC int ACL_ReadDbMapFile(NSErr_t *errp, const char *map_file, int default_only);
+
+NSAPI_PUBLIC int ACL_MethodNamesGet(NSErr_t *errp, char ***names, int *count);
+NSAPI_PUBLIC int ACL_MethodNamesFree(NSErr_t *errp, char **names, int count);
+
+NSAPI_PUBLIC int ACL_DatabaseNamesGet(NSErr_t *errp, char ***names, int *count);
+NSAPI_PUBLIC int ACL_DatabaseNamesFree(NSErr_t *errp, char **names, int count);
+
+NSAPI_PUBLIC int ACL_InitAttr2Index(void);
+NSAPI_PUBLIC int ACL_Attr2Index(const char *attrname);
+
+/*********************************************************************
+ * ACL cache and flush utility
+ *********************************************************************/
+
+NSAPI_PUBLIC int ACL_CacheCheck(char *uri, ACLListHandle_t **acllist_p);
+NSAPI_PUBLIC int ACL_CacheCheckGet(char *uri, ACLListHandle_t **acllist_p);
+NSAPI_PUBLIC void ACL_CacheEnter(char *uri, ACLListHandle_t **acllist_p);
+NSAPI_PUBLIC void ACL_CacheEnterGet(char *uri, ACLListHandle_t **acllist_p);
+NSAPI_PUBLIC int ACL_ListHashCheck(ACLListHandle_t **acllist_p);
+NSAPI_PUBLIC void ACL_ListHashEnter(ACLListHandle_t **acllist_p);
+NSAPI_PUBLIC int ACL_CacheFlush(void);
+NSAPI_PUBLIC void ACL_Restart(void *clntData);
+NSAPI_PUBLIC void ACL_CritEnter(void);
+NSAPI_PUBLIC void ACL_CritExit(void);
+
+/*********************************************************************
+ * ACL CGI routines
+ *********************************************************************/
+
+NSAPI_PUBLIC void ACL_OutputSelector(char *name, char **item);
+
+
+NSPR_END_EXTERN_C
+
+#endif /* INTNSACL */
+
+#endif
+
diff --git a/include/libaccess/aclstruct.h b/include/libaccess/aclstruct.h
new file mode 100644
index 00000000..71320b0f
--- /dev/null
+++ b/include/libaccess/aclstruct.h
@@ -0,0 +1,264 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __aclstruct_h
+#define __aclstruct_h
+
+/*
+ * Description (aclstruct.h)
+ *
+ * This file defines types and data structures used to construct
+ * representations of Access Control Lists (ACLs) in memory.
+ */
+
+#include "base/systems.h"
+#include "base/file.h"
+#include "base/lexer.h"
+#include "nsauth.h" /* authentication types */
+#include "symbols.h" /* typed symbol support */
+#include "ipfstruct.h" /* IP address filter structures */
+#include "dnfstruct.h" /* DNS name filter structures */
+
+
+NSPR_BEGIN_EXTERN_C
+
+/* Forward type definitions */
+typedef struct ACL_s ACL_t;
+
+/*
+ * Description (InetHost_t)
+ *
+ * This type defines a structure which represents a list of Internet
+ * hosts by IP address and netmask, or by fully or partially
+ * qualified DNS name.
+ */
+
+typedef struct InetHost_s InetHost_t;
+struct InetHost_s {
+ IPFilter_t inh_ipf; /* reference to IP filter */
+ DNSFilter_t inh_dnf; /* reference to DNS filter */
+};
+
+/*
+ * Description (HostSpec_t)
+ *
+ * This type describes a named list of hosts.
+ */
+
+typedef struct HostSpec_s HostSpec_t;
+struct HostSpec_s {
+ Symbol_t hs_sym; /* symbol name, type ACLSYMHOST */
+ InetHost_t hs_host; /* host information */
+};
+
+/*
+ * Description (UidUser_t)
+ *
+ * This type represents a list of users and groups using unique
+ * integer identifiers.
+ */
+
+typedef struct UidUser_s UidUser_t;
+struct UidUser_s {
+ USIList_t uu_user; /* list of user ids */
+ USIList_t uu_group; /* list of group ids */
+};
+
+/*
+ * Description (UserSpec_t)
+ *
+ * This type describes a named list of users and groups.
+ */
+
+typedef struct UserSpec_s UserSpec_t;
+struct UserSpec_s {
+ Symbol_t us_sym; /* list name, type ACLSYMUSER */
+ int us_flags; /* bit flags */
+#define ACL_USALL 0x1 /* any authenticated user */
+
+ UidUser_t us_user; /* user list structure */
+};
+
+/*
+ * Description (ACClients_t)
+ *
+ * This type defines the structure of action-specific information
+ * for access control directives with action codes ACD_ALLOW and
+ * ACD_DENY. These directives specify access control constraints
+ * on users/groups and hosts.
+ */
+
+typedef struct ACClients_s ACClients_t;
+struct ACClients_s {
+ ACClients_t * cl_next; /* list link */
+ HostSpec_t * cl_host; /* host specification pointer */
+ UserSpec_t * cl_user; /* user list pointer */
+};
+
+/*
+ * Description (RealmSpec_t)
+ *
+ * This type describes a named realm.
+ */
+
+typedef struct RealmSpec_s RealmSpec_t;
+struct RealmSpec_s {
+ Symbol_t rs_sym; /* realm name, type ACLSYMREALM */
+ Realm_t rs_realm; /* realm information */
+};
+
+/*
+ * Description (ACAuth_t)
+ *
+ * This type defines the structure of action-specific information
+ * for an access control directive with action code ACD_AUTH,
+ * which specifies information about authentication requirements.
+ */
+
+typedef struct ACAuth_s ACAuth_t;
+struct ACAuth_s {
+ RealmSpec_t * au_realm; /* pointer to realm information */
+};
+
+/*
+ * Description (ACDirective_t)
+ *
+ * This type defines a structure which represents an access control
+ * directive. Each directive specifies an access control action
+ * to be taken during ACL evaluation. The ACDirective_t structure
+ * begins an action-specific structure which contains the
+ * parameters for an action.
+ */
+
+typedef struct ACDirective_s ACDirective_t;
+struct ACDirective_s {
+ ACDirective_t * acd_next; /* next directive in ACL */
+ short acd_action; /* directive action code */
+ short acd_flags; /* action modifier flags */
+
+ /* Begin action-specific information */
+ union {
+ ACClients_t * acu_cl; /* ACD_ALLOW, ACD_DENY */
+ ACAuth_t acu_auth; /* ACD_AUTH */
+ } acd_u;
+};
+
+#define acd_cl acd_u.acu_cl
+#define acd_auth acd_u.acu_auth
+
+/* Define acd_action codes */
+#define ACD_ALLOW 1 /* allow access */
+#define ACD_DENY 2 /* deny access */
+#define ACD_AUTH 3 /* specify authentication realm */
+#define ACD_EXEC 4 /* execute (conditionally) */
+
+/* Define acd_flags values */
+#define ACD_ACTION 0xf /* bits reserved for acd_action */
+#define ACD_FORCE 0x10 /* force of action */
+#define ACD_DEFAULT 0 /* default action */
+#define ACD_ALWAYS ACD_FORCE /* immediate action */
+#define ACD_EXALLOW 0x20 /* execute if allow */
+#define ACD_EXDENY 0x40 /* execute if deny */
+#define ACD_EXAUTH 0x80 /* execute if authenticate */
+
+/*
+ * Description (RightDef_t)
+ *
+ * This type describes a named access right. Each access right has
+ * an associated unique integer id. A list of all access rights
+ * known in an ACL context is maintained, with its head in the
+ * ACContext_t structure.
+ */
+
+typedef struct RightDef_s RightDef_t;
+struct RightDef_s {
+ Symbol_t rd_sym; /* right name, type ACLSYMRIGHT */
+ RightDef_t * rd_next; /* next on ACContext_t list */
+ USI_t rd_id; /* unique id */
+};
+
+/*
+ * Description (RightSpec_t)
+ *
+ * This type describes a named list of access rights.
+ */
+
+typedef struct RightSpec_s RightSpec_t;
+struct RightSpec_s {
+ Symbol_t rs_sym; /* list name, type ACLSYMRDEF */
+ USIList_t rs_list; /* list of right ids */
+};
+
+/*
+ * Description (ACContext_t)
+ *
+ * This type defines a structure that defines a context for a set
+ * of Access Control Lists. This includes references to an
+ * authentication database, if any, and a symbol table containing
+ * access right definitions. It also serves as a list head for the
+ * ACLs which are defined in the specified context.
+ */
+
+typedef struct ACContext_s ACContext_t;
+struct ACContext_s {
+ void * acc_stp; /* symbol table handle */
+ ACL_t * acc_acls; /* list of ACLs */
+ RightDef_t * acc_rights; /* list of access right definitions */
+ int acc_refcnt; /* reference count */
+};
+
+/*
+ * Description (ACL_t)
+ *
+ * This type defines the structure that represents an Access Control
+ * List (ACL). An ACL has a user-assigned name and an internally
+ * assigned identifier (which is an index in an object directory).
+ * It references a list of access rights which are to be allowed or
+ * denied, according to the ACL specifications. It references an
+ * ordered list of ACL directives, which specify who has and who does
+ * not have the associated access rights.
+ */
+
+struct ACL_s {
+ Symbol_t acl_sym; /* ACL name, type ACLSYMACL */
+ ACL_t * acl_next; /* next ACL on a list */
+ ACContext_t * acl_acc; /* context for this ACL */
+ USI_t acl_id; /* id of this ACL */
+ int acl_refcnt; /* reference count */
+ RightSpec_t * acl_rights; /* access rights list */
+ ACDirective_t * acl_dirf; /* first directive pointer */
+ ACDirective_t * acl_dirl; /* last directive pointer */
+};
+
+/* Define symbol type codes */
+#define ACLSYMACL 0 /* ACL */
+#define ACLSYMRIGHT 1 /* access right */
+#define ACLSYMRDEF 2 /* access rights list */
+#define ACLSYMREALM 3 /* realm name */
+#define ACLSYMHOST 4 /* host specifications */
+#define ACLSYMUSER 5 /* user/group list */
+
+/*
+ * Description (ACLFile_t)
+ *
+ * This type describes a structure containing information about
+ * an open ACL description file.
+ */
+
+typedef struct ACLFile_s ACLFile_t;
+struct ACLFile_s {
+ ACLFile_t * acf_next; /* list link */
+ char * acf_filename; /* pointer to filename string */
+ LEXStream_t * acf_lst; /* LEX stream handle */
+ SYS_FILE acf_fd; /* file descriptor */
+ int acf_flags; /* bit flags (unused) */
+ int acf_lineno; /* current line number */
+ void * acf_token; /* LEX token handle */
+ int acf_ttype; /* current token type */
+};
+
+NSPR_END_EXTERN_C
+
+#endif /* __aclstruct_h */
diff --git a/include/libaccess/attrec.h b/include/libaccess/attrec.h
new file mode 100644
index 00000000..267c32ff
--- /dev/null
+++ b/include/libaccess/attrec.h
@@ -0,0 +1,157 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __attrec_h
+#define __attrec_h
+
+/*
+ * Description (attrec.h)
+ *
+ * This file describes the encoding and decoding of attribute
+ * records. Attribute records consist of a sequence of items
+ * of the form:
+ *
+ * <tag><length><contents>
+ *
+ * The <tag> is an integer code which identifies a particular
+ * attribute. The <length> is the integer length in bytes of
+ * the <contents>. The encoding of the contents is determined
+ * by the <tag>, and is application-specific.
+ *
+ * Primitive data types currently supported are unsigned
+ * integers (USI) and null-terminated strings (NTS). The
+ * encoding of USI values less than 128 is simply an octet
+ * containing the value. For values 128 or greater, the first
+ * octet is 0x80 plus the length of the value, in octets.
+ * This octet is followed by the indicated number of octets,
+ * containing the USI value, with the most significant bits in
+ * the first octet, and the least significant bits in the last
+ * octet.
+ *
+ * Examples of USI encoding:
+ *
+ * Value Encoding (each value is an octet)
+ * 4 0x04
+ * 127 0x7f
+ * -1 (this is not a USI)
+ * 128 0x81 0x80
+ * 1023 0x82 0x03 0xff
+ *
+ * The encoding of a null-terminated string (NTS) is simply the
+ * sequence of octets which comprise the string, including the
+ * terminating null (0x00) octet. The terminating null octet is
+ * the only null value in the string. The character set used to
+ * encode the other string octets is ASCII.
+ */
+
+#include "usi.h"
+
+NSPR_BEGIN_EXTERN_C
+
+/* Define a type to reference an attribute record */
+typedef unsigned char * ATR_t;
+
+/*
+ * Description (USILENGTH)
+ *
+ * This macro returns the length of the USI encoding for a specified
+ * unsigned integer value. The length is the number of octets
+ * required. It will be greater than zero, and less than or equal
+ * to USIALLOC(). This is a partial inline optimization of
+ * USI_Length().
+ */
+
+#define USILENGTH(val) (((USI_t)(val) <= 0x7f) ? 1 : USI_Length((USI_t)(val)))
+
+/*
+ * Description (USIALLOC)
+ *
+ * This macro returns the maximum length of an unsigned integer
+ * encoding.
+ */
+
+#define USIALLOC() (5)
+
+/*
+ * Description (USIENCODE)
+ *
+ * This macro encodes a USI value into a specified buffer. It
+ * returns a pointer to the first octet after the encoding.
+ * This is a partial inline optimization for USI_Encode().
+ */
+
+#define USIENCODE(cp, val) (((USI_t)(val) <= 0x7f) ? (*(cp) = (val), (cp)+1) \
+ : USI_Encode((cp), (val)))
+
+/*
+ * Description (USIINSERT)
+ *
+ * This macro performs a variation of USIENCODE which always
+ * generates the maximum-sized USI encoding, i.e. the number of
+ * octets indicated by USIALLOC().
+ */
+
+#define USIINSERT(cp, val) USI_Insert((ATR_t)(cp), (USI_t)(val))
+
+/*
+ * Description (USIDECODE)
+ *
+ * This macro decodes a USI value from a specified buffer. It
+ * returns a pointer to the first octet after the encoding.
+ * This is a partial inline optimization for USI_Decode().
+ */
+
+#define USIDECODE(cp, pval) \
+ ((*(cp) & 0x80) ? USI_Decode((cp), (pval)) \
+ : (((pval) ? (*(pval) = *(cp)) : 0), (cp)+1))
+
+/* Define a type to reference a null-terminated string */
+typedef unsigned char * NTS_t;
+
+/*
+ * Decription (NTSLENGTH)
+ *
+ * Return the length, in octets, of a null-terminated string.
+ * It includes the terminating null octet.
+ */
+
+#define NTSLENGTH(nts) ((nts) ? strlen((char *)(nts)) + 1 : 1)
+
+/*
+ * Description (NTSENCODE)
+ *
+ * This macro copies a null-terminated string to a specified
+ * attribute record buffer. It returns a pointer to the octet
+ * following the NTS in the buffer.
+ */
+
+#define NTSENCODE(cp, nts) \
+ ((ATR_t)memccpy((void *)(cp), \
+ (void *)((nts) ? (NTS_t)(nts) : (NTS_t)""), \
+ 0, NTSLENGTH(nts)))
+
+/*
+ * Description (NTSDECODE)
+ *
+ * This macro decodes a null-terminated string in a specified
+ * attribute record buffer into a dynamically allocated buffer.
+ * It returns a pointer to the first octet after the NTS in the
+ * attribute record buffer.
+ */
+
+#define NTSDECODE(cp, pnts) NTS_Decode((cp), (pnts))
+
+/* Functions in attrec.c */
+extern int NTS_Length(NTS_t ntsp);
+extern ATR_t NTS_Decode(ATR_t cp, NTS_t * pnts);
+extern ATR_t NTS_Encode(ATR_t cp, NTS_t nts);
+extern ATR_t USI_Decode(ATR_t cp, USI_t * pval);
+extern ATR_t USI_Encode(ATR_t cp, USI_t val);
+extern ATR_t USI_Insert(ATR_t cp, USI_t val);
+extern int USI_Length(USI_t val);
+
+NSPR_END_EXTERN_C
+
+#endif /* __attrec_h */
diff --git a/include/libaccess/authdb.h b/include/libaccess/authdb.h
new file mode 100644
index 00000000..952f0d07
--- /dev/null
+++ b/include/libaccess/authdb.h
@@ -0,0 +1,24 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef AUTHDB_H
+#define AUTHDB_H
+
+#include <base/plist.h>
+#include <libaccess/nserror.h>
+#include <libaccess/las.h>
+
+#define URL_PREFIX_LDAP "ldap"
+#define URL_PREFIX_LDAP_LEN 4
+
+typedef struct {
+ char *dbname;
+ ACLDbType_t dbtype;
+ void *dbinfo;
+} AuthdbInfo_t;
+
+extern int acl_num_databases();
+
+#endif /* AUTHDB_H */
diff --git a/include/libaccess/ava.h b/include/libaccess/ava.h
new file mode 100644
index 00000000..c8570b90
--- /dev/null
+++ b/include/libaccess/ava.h
@@ -0,0 +1,40 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _ava_h
+#define _ava_h
+
+#define ENTRIES_ALLOCSIZE 100
+#define ORGS_ALLOCSIZE 15
+
+
+#ifdef XP_WIN32
+#define NSAPI_PUBLIC __declspec(dllexport)
+#else /* !XP_WIN32 */
+#define NSAPI_PUBLIC
+#endif
+
+
+typedef struct {
+ char *email;
+ char *locality;
+ char *userid;
+ char *state;
+ char *country;
+ char *company;
+ int numOrgs;
+ char **organizations;
+ char *CNEntry;
+} AVAEntry;
+
+typedef struct {
+ char *userdb;
+ int numEntries;
+ AVAEntry **enteredTable;
+} AVATable;
+
+
+#endif
+
diff --git a/include/libaccess/avadb.h b/include/libaccess/avadb.h
new file mode 100644
index 00000000..bbb6c904
--- /dev/null
+++ b/include/libaccess/avadb.h
@@ -0,0 +1,15 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _avadb_h_
+#define _avadb_h_
+
+#define USE_NSAPI
+
+USE_NSAPI int AddEntry (char *key, char *value);
+USE_NSAPI int DeleteEntry (char *key);
+USE_NSAPI char *GetValue (char *key);
+
+#endif /*_avadb_h_*/
diff --git a/include/libaccess/avapfile.h b/include/libaccess/avapfile.h
new file mode 100644
index 00000000..4b60117c
--- /dev/null
+++ b/include/libaccess/avapfile.h
@@ -0,0 +1,59 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _avaparsedfiles_h_
+#define _avaparsedfiles_h_
+
+#include "libaccess/ava.h"
+#include "frame/req.h"
+#include "base/session.h"
+
+#define AUTH_DB_FILE "AvaCertmap"
+#define AVADB_TAG "avadb"
+#define AVA_DB_SEL "ava_db_sel" /*Variable name used in
+ *outputAVAdbs
+ */
+
+
+extern void outputAVAdbs (char *chosen); /*Outputs the selector of auth databases
+ *and makes it so that the form submits
+ *when onChange event occurs.
+ */
+
+
+/*For the following 3 functions, enter the full path of
+ *ava database file includint tag and filename
+ */
+/*Before calling _getTable, initializa yy_sn and yy_rq. Set to NULL if no
+ *Session* or Request* variables exist and an error will be reported with
+ *function report_error(libamin.h). Otherwise error will be logged into
+ *the server's error log
+ */
+extern AVATable *_getTable (char *avadbfile);
+extern AVATable *_wasParsed (char *avadbfile);/*Assumes a call to yyparse was just
+ *completed
+ */
+extern int _hasBeenParsed (char *avadbfile);/*Check if _getTable returns NULL or not*/
+
+extern AVAEntry* _getAVAEntry (char *groupid, AVATable *table);
+extern AVAEntry* _deleteAVAEntry (char *groupid, AVATable *table);
+extern void _addAVAtoTable (AVAEntry *entry, AVATable *table);
+extern void AVAEntry_Free (AVAEntry *entry);
+
+/*Functions for writing out files*/
+extern void PrintHeader (FILE *outfile);
+extern void writeOutFile (char *avadbfilename, AVATable *table);
+
+
+extern int yyparse();
+extern FILE *yyin;
+
+extern char *currFile;
+
+extern Session *yy_sn;
+extern Request *yy_rq;
+
+
+#endif /*_avaparsedfiles_h_*/
diff --git a/include/libaccess/dbtlibaccess.h b/include/libaccess/dbtlibaccess.h
new file mode 100644
index 00000000..f1eb420f
--- /dev/null
+++ b/include/libaccess/dbtlibaccess.h
@@ -0,0 +1,161 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#define LIBRARY_NAME "libaccess"
+
+static char dbtlibaccessid[] = "$DBT: libaccess referenced v1 $";
+
+#include "i18n.h"
+
+BEGIN_STR(libaccess)
+ ResDef( DBT_LibraryID_, -1, dbtlibaccessid )/* extracted from dbtlibaccess.h*/
+ ResDef( DBT_basicNcsa_, 1, "basic-ncsa" )/*extracted from userauth.cpp*/
+ ResDef( DBT_cannotOpenDatabaseS_, 2, "cannot open database %s" )/*extracted from userauth.cpp*/
+ ResDef( DBT_basicNcsa_1, 3, "basic-ncsa" )/*extracted from userauth.cpp*/
+ ResDef( DBT_userSPasswordDidNotMatchDatabase_, 4, "user %s password did not match database %s" )/*extracted from userauth.cpp*/
+ ResDef( DBT_basicNcsa_2, 5, "basic-ncsa" )/*extracted from userauth.cpp*/
+ ResDef( DBT_cannotOpenConnectionToLdapServer_, 6, "cannot open connection to LDAP server on %s:%d" )/*NOT USED - extracted from userauth.cpp*/
+ ResDef( DBT_basicNcsa_3, 7, "basic-ncsa" )/*extracted from userauth.cpp*/
+ ResDef( DBT_userSPasswordDidNotMatchLdapOnSD_, 8, "user %s password did not match LDAP on %s:%d" )/*NOT USED - extracted from userauth.cpp*/
+ ResDef( DBT_aclState_, 9, "acl-state" )/*extracted from userauth.cpp*/
+ ResDef( DBT_missingRealm_, 10, "missing realm" )/*extracted from userauth.cpp*/
+ ResDef( DBT_unableToAllocateAclListHashN_, 11, "Unable to allocate ACL List Hash\n" )/*extracted from cache.cpp*/
+ ResDef( DBT_aclevalbuildcontextUnableToPermM_, 12, "ACLEvalBuildContext unable to PERM_MALLOC cache structure\n" )/*extracted from eval.cpp*/
+ ResDef( DBT_aclevalbuildcontextUnableToCreat_, 13, "ACLEvalBuildContext unable to create hash table\n" )/*extracted from eval.cpp*/
+ ResDef( DBT_aclevalbuildcontextUnableToAlloc_, 14, "ACLEvalBuildContext unable to allocate ACE Entry\n" )/*extracted from eval.cpp*/
+ ResDef( DBT_aclevalbuildcontextUnableToAlloc_1, 15, "ACLEvalBuildContext unable to allocate ACE entry\n" )/*extracted from eval.cpp*/
+ ResDef( DBT_aclevalbuildcontextUnableToAlloc_2, 16, "ACLEvalBuildContext unable to allocate Boundary Entry\n" )/*extracted from eval.cpp*/
+ ResDef( DBT_aclevalbuildcontextFailedN_, 17, "ACLEvalBuildContext failed.\n" )/*extracted from eval.cpp*/
+ ResDef( DBT_aclEvaltestrightsAnInterimAbsolu_, 18, "ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n" )/*NOT USED - extracted from eval.cpp*/
+ ResDef( DBT_lasdnsbuildUnableToAllocateHashT_, 19, "LASDnsBuild unable to allocate hash table header\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasdnsbuildUnableToAddKeySN_, 20, "LASDnsBuild unable to add key %s\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasdnsbuildUnableToAddKeySN_1, 21, "LASDnsBuild unable to add key %s\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasdnsbuildUnableToAddKeySN_2, 22, "LASDnsBuild unable to add key %s\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasdnsbuildUnableToAddKeySN_3, 23, "LASDnsBuild unable to add key %s\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasdnsbuildUnableToAddKeySN_4, 24, "LASDnsBuild unable to add key %s\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasDnsBuildReceivedRequestForAtt_, 25, "LAS DNS build received request for attribute %s\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasdnsevalIllegalComparatorDN_, 26, "LASDnsEval - illegal comparator %s\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasdnsevalUnableToAllocateContex_, 27, "LASDnsEval unable to allocate Context struct\n\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasdnsevalUnableToGetSessionAddr_, 28, "LASDnsEval unable to get session address %d\n" )/*NOT USED - extracted from lasdns.cpp*/
+ ResDef( DBT_lasdnsevalUnableToGetDnsErrorDN_, 29, "LASDnsEval unable to get DNS - error=%s\n" )/*extracted from lasdns.cpp*/
+ ResDef( DBT_lasGroupEvalReceivedRequestForAt_, 30, "LAS Group Eval received request for attribute %s\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_lasgroupevalIllegalComparatorDN_, 31, "LASGroupEval - illegal comparator %s\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_lasgroupevalRanOutOfMemoryN_, 32, "LASGroupEval - ran out of memory\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_lasgroupevalUnableToGetSessionAd_, 33, "LASGroupEval unable to get session address %d\n" )/*NOT USED - extracted from lasgroup.cpp*/
+ ResDef( DBT_lasgroupevalUnableToGetSessionAd_1, 34, "LASGroupEval unable to get session address %d\n" )/*NOT USED - extracted from lasgroup.cpp*/
+ ResDef( DBT_lasgroupevalCouldnTLocateGetterF_, 35, "LASGroupEval - couldn't locate getter for auth-user\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_lasgroupevalAttributeGetterForAu_, 36, "LASGroupEval - Attribute getter for auth-user failed\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_lasgroupevalAttributeGetterDidnT_, 37, "LASGroupEval - Attribute getter didn't set auth-user\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_checkGroupMembershipOfUserSForGr_, 38, "Check group membership of user \"%s\" for group \"%s\"\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_ldapuSuccessForGroupSN_, 39, "LDAPU_SUCCESS for group \"%s\"\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_ldapuFailedForGroupSN_, 40, "LDAPU_FAILED for group \"%s\"\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_lasEvalFalseN_, 41, "LAS_EVAL_FALSE\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_lasEvalTrueN_, 42, "LAS_EVAL_TRUE\n" )/*extracted from lasgroup.cpp*/
+ ResDef( DBT_lasiptreeallocNoMemoryN_, 43, "LASIpTreeAlloc - no memory\n" )/*extracted from lasip.cpp*/
+ ResDef( DBT_ipLasUnableToAllocateTreeNodeN_, 44, "IP LAS unable to allocate tree node\n" )/*extracted from lasip.cpp*/
+ ResDef( DBT_ipLasUnableToAllocateTreeNodeN_1, 45, "IP LAS unable to allocate tree node\n" )/*extracted from lasip.cpp*/
+ ResDef( DBT_lasIpBuildReceivedRequestForAttr_, 46, "LAS IP build received request for attribute %s\n" )/*extracted from lasip.cpp*/
+ ResDef( DBT_lasipevalIllegalComparatorDN_, 47, "LASIpEval - illegal comparator %s\n" )/*extracted from lasip.cpp*/
+ ResDef( DBT_lasipevalUnableToGetSessionAddre_, 48, "LASIpEval unable to get session address - error=%s\n" )/*extracted from lasip.cpp*/
+ ResDef( DBT_lasipevalUnableToAllocateContext_, 49, "LASIpEval unable to allocate Context struct\n\n" )/*extracted from lasip.cpp*/
+ ResDef( DBT_lasipevalReach32BitsWithoutConcl_, 50, "LASIpEval - reach 32 bits without conclusion value=%s" )/*extracted from lasip.cpp*/
+ ResDef( DBT_lasProgramEvalReceivedRequestFor_, 51, "LAS Program Eval received request for attribute %s\n" )/*extracted from lasprogram.cpp*/
+ ResDef( DBT_lasprogramevalIllegalComparatorD_, 52, "LASProgramEval - illegal comparator %s\n" )/*extracted from lasprogram.cpp*/
+ ResDef( DBT_lasprogramUnableToGetSessionAddr_, 53, "LASProgram unable to get session address %d\n" )/*NOT USED - extracted from lasprogram.cpp*/
+ ResDef( DBT_bin_, 54, "bin" )/*extracted from lasprogram.cpp*/
+ ResDef( DBT_lasprogramevalRequestNotOfTypeAd_, 55, "LASProgramEval: request not of type admin or bin, passing.\n" )/*extracted from lasprogram.cpp*/
+ ResDef( DBT_lasprogramevalCheckIfProgramSMat_, 56, "LASProgramEval: check if program %s matches pattern %s.\n" )/*extracted from lasprogram.cpp*/
+ ResDef( DBT_lasprogramevalInvalidWildcardExp_, 57, "LASProgramEval: Invalid wildcard expression %s.\n" )/*extracted from lasprogram.cpp*/
+ ResDef( DBT_lasEvalFalseN_1, 58, "LAS_EVAL_FALSE\n" )/*extracted from lasprogram.cpp*/
+ ResDef( DBT_lasEvalTrueN_1, 59, "LAS_EVAL_TRUE\n" )/*extracted from lasprogram.cpp*/
+ ResDef( DBT_unexpectedAttributeInDayofweekSN_, 60, "Unexpected attribute in dayOfWeek - %s\n" )/*extracted from lastod.cpp*/
+ ResDef( DBT_illegalComparatorForDayofweekDN_, 61, "Illegal comparator for dayOfWeek - %s\n" )/*extracted from lastod.cpp*/
+ ResDef( DBT_unexpectedAttributeInTimeofdaySN_, 62, "Unexpected attribute in timeOfDay - %s\n" )/*extracted from lastod.cpp*/
+ ResDef( DBT_lasUserEvalReceivedRequestForAtt_, 63, "LAS User Eval received request for attribute %s\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_lasuserevalIllegalComparatorDN_, 64, "LASUserEval - illegal comparator %s\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_lasuserevalRanOutOfMemoryN_, 65, "LASUserEval - ran out of memory\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_lasuserevalUnableToGetSessionAdd_, 66, "LASUserEval unable to get session address %d\n" )/*NOT USED - extracted from lasuser.cpp*/
+ ResDef( DBT_lasuserevalUnableToGetSessionAdd_1, 67, "LASUserEval unable to get session address %d\n" )/*NOT USED - extracted from lasuser.cpp*/
+ ResDef( DBT_lasgroupevalCouldnTLocateGetterF_1, 68, "LASGroupEval - couldn't locate getter for auth-user\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_lasgroupevalAttributeGetterForAu_1, 69, "LASGroupEval - Attribute getter for auth-user failed\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_lasgroupevalAttributeGetterDidnT_1, 70, "LASGroupEval - Attribute getter didn't set auth-user\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_checkIfUidUserIECheckSSN_, 71, "Check if uid == user (i.e. check \"%s\" == \"%s)\"\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_successForUserSN_, 72, "SUCCESS for user \"%s\"\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_failedForUserSN_, 73, "FAILED for user \"%s\"\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_lasEvalFalseN_2, 74, "LAS_EVAL_FALSE\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_lasEvalTrueN_2, 75, "LAS_EVAL_TRUE\n" )/*extracted from lasuser.cpp*/
+ ResDef( DBT_Unused76, 76, "")
+ ResDef( DBT_lasProgramUnableToGetRequest_, 77, "LASProgram unable to get request address - error=%s" ) /*extracted from lasprogram.cpp*/
+ ResDef( DBT_lasProgramRejectingRequestForProgram_, 78, "LASProgram rejecting request for program %s from pattern %s" ) /*extracted from lasprogram.cpp*/
+ ResDef( DBT_aclcacheflushCannotParseFile, 79, "ACL_CacheFlush: unable to parse file \"%s\"\n" )
+ ResDef( DBT_aclcacheflushCannotConcatList, 80, "ACL_CacheFlush: unable to concatenate ACL list \"%s\"\n" )
+ ResDef( DBT_aclcacheflushCannotOpenMagnus, 81, "ACL_CacheFlush: unable to open and process the magnus file \"%s\"\n" )
+ ResDef( DBT_illegalComparatorForTimeOfDayDN_, 82, "Illegal comparator for timeOfDay - %s\n" )/*extracted from lastod.cpp*/
+ ResDef( DBT_EvalBuildContextUnableToCreateHash, 83, "ACL_EvalBuildContext unable to create hash table\n")
+ ResDef( DBT_EvalBuildContextUnableToAllocCache, 84, "ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n")
+ ResDef( DBT_EvalBuildContextUnableToAllocAceEntry, 85, "ACL_EvalBuildContext unable to allocate ACE entry\n")
+ ResDef( DBT_EvalBuildContextUnableToAllocAuthPointerArray, 86, "ACL_EvalBuildContext unable to allocate auth pointer array\n")
+ ResDef( DBT_EvalBuildContextUnableToAllocAuthPlist, 87, "ACL_EvalBuildContext unable to allocate auth plist\n")
+ ResDef( DBT_EvalTestRightsInterimAbsoluteNonAllowValue, 88, "ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n")
+ ResDef( DBT_EvalTestRightsEvalBuildContextFailed, 89, "ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n")
+ ResDef( DBT_ModuleRegisterModuleNameMissing, 90, "ACL_ModuleRegister: module name is missing\n")
+ ResDef( DBT_ModuleRegisterFailed, 91, "ACL_ModuleRegister: call to module init function returned a failed status\n")
+ ResDef( DBT_GetAttributeCouldntDetermineMethod, 92, "ACL_GetAttribute: couldn't determine method for %s\n")
+ ResDef( DBT_GetAttributeCouldntLocateGetter, 93, "ACL_GetAttribute: couldn't locate getter for %s")
+ ResDef( DBT_GetAttributeDidntGetAttr, 94, "ACL_GetAttribute: attr getter failed to get %s")
+ ResDef( DBT_GetAttributeDidntSetAttr, 95, "ACL_GetAttribute: attr getter failed to get %s")
+ ResDef( DBT_GetAttributeAllGettersDeclined, 96, "ACL_GetAttribute: All attribute getters declined for attr %s")
+ ResDef( DBT_DbtypeNoteDefinedYet, 97, "ACL_DatabaseRegister: dbtype for database \"%s\" is not defined yet!")
+ ResDef( DBT_DatabaseRegisterDatabaseNameMissing, 98, "ACL_DatabaseRegister: database name is missing")
+ ResDef( DBT_ReadDbMapFileErrorReadingFile, 99, "Error reading the DB Map File: %s. Reason: %s")
+ ResDef( DBT_ReadDbMapFileMissingUrl, 100, "URL is missing for database %s")
+ ResDef( DBT_ReadDbMapFileInvalidPropertyPair, 101, "Invalid property value pair for database %s")
+ ResDef( DBT_ReadDbMapFileDefaultDatabaseNotLdap, 102, "\"default\" database must be an LDAP database")
+ ResDef( DBT_ReadDbMapFileMultipleDefaultDatabases, 103, "Multiple \"default\" databases are being registered")
+ ResDef( DBT_ReadDbMapFileMissingDefaultDatabase, 104, "\"default\" LDAP database must be registered")
+ ResDef( DBT_lasGroupEvalUnableToGetDatabaseName, 105, "LASGroupEval unable to get database name - error= %s")
+ ResDef( DBT_lasProgramReceivedInvalidProgramExpression, 106, "received invalid program expression %s")
+ ResDef( DBT_ldapaclDatabaseUrlIsMissing, 107, "parse_ldap_url: database url is missing")
+ ResDef( DBT_ldapaclDatabaseNameIsMissing, 108, "parse_ldap_url: database name is missing")
+ ResDef( DBT_ldapaclErrorParsingLdapUrl, 109, "parse_ldap_url: error in parsing ldap url. Reason: %s")
+ ResDef( DBT_ldapaclUnableToGetDatabaseName, 110, "ldap password check: unable to get database name - error=%s")
+ ResDef( DBT_ldapaclUnableToGetParsedDatabaseName, 111, "ldap password check: unable to get parsed database %s")
+ ResDef( DBT_ldapaclCoudlntInitializeConnectionToLdap, 112, "ldap password check: couldn't initialize connection to LDAP. Reason: %s")
+ ResDef( DBT_ldapaclPassworkCheckLdapError, 113, "ldap password check: LDAP error: \"%s\"")
+ ResDef( DBT_GetUserIsMemberLdapUnabelToGetDatabaseName, 114, "get_user_ismember_ldap unable to get database name - error=%s")
+ ResDef( DBT_GetUserIsMemberLdapUnableToGetParsedDatabaseName, 115, "get_user_ismember_ldap unable to get parsed database %s")
+ ResDef( DBT_GetUserIsMemberLdapCouldntInitializeConnectionToLdap, 116, "ldap password check: couldn't initialize connection to LDAP. Reason: %s")
+ ResDef( DBT_GetUserIsMemberLdapGroupDoesntExist, 117, "get_user_ismember_ldap: group %s does not exist")
+ ResDef( DBT_GetUserIsMemberLdapError, 118, "get_user_ismember_ldap: LDAP error: \"%s\"")
+ ResDef( DBT_LdapDatabaseHandleNotARegisteredDatabase, 119, "ACL_LDAPDatabaseHandle: %s is not a registered database")
+ ResDef( DBT_LdapDatabaseHandleNotAnLdapDatabase, 120, "ACL_LDAPDatabaseHandle: %s is not an LDAP database")
+ ResDef( DBT_LdapDatabaseHandleOutOfMemory, 121, "ACL_LDAPDatabaseHandle: out of memory")
+ ResDef( DBT_LdapDatabaseHandleCouldntInitializeConnectionToLdap, 122, "ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s")
+ ResDef( DBT_LdapDatabaseHandleCouldntBindToLdapServer, 123, "ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s")
+ ResDef( DBT_AclerrfmtAclerrnomem, 124, "insufficient dynamic memory")
+ ResDef( DBT_AclerrfmtAclerropen, 125, "error opening file, %s: %s")
+ ResDef( DBT_AclerrfmtAclerrdupsym1, 126, "duplicate definition of %s")
+ ResDef( DBT_AclerrfmtAclerrdupsym3, 127, "file %s, line %s: duplicate definition of %s")
+ ResDef( DBT_AclerrfmtAclerrsyntax, 128, "file %s, line %s: syntax error")
+ ResDef( DBT_AclerrfmtAclerrundef, 129, "file %s, line %s: %s is undefined")
+ ResDef( DBT_AclerrfmtAclaclundef, 130, "in acl %s, %s %s is undefined")
+ ResDef( DBT_AclerrfmtAclerradb, 131, "database %s: error accessing %s")
+ ResDef( DBT_AclerrfmtAclerrparse1, 132, "%s")
+ ResDef( DBT_AclerrfmtAclerrparse2, 133, "file %s, line %s: invalid syntax")
+ ResDef( DBT_AclerrfmtAclerrparse3, 134, "file %s, line %s: syntax error at \"%s\"")
+ ResDef( DBT_AclerrfmtAclerrnorlm, 135, "realm %s is not defined")
+ ResDef( DBT_AclerrfmtUnknownerr, 136, "error code = %d")
+ ResDef( DBT_AclerrfmtAclerrinternal, 137, "internal ACL error")
+ ResDef( DBT_AclerrfmtAclerrinval, 138, "invalid argument")
+ ResDef( DBT_DbtypeNotDefinedYet, 139, "ACL_DatabaseRegister: dbtype for database \"%s\" is not defined yet!")
+ ResDef( DBT_ReadDbMapFileCouldntDetermineDbtype, 140, "couldn't determine dbtype from: %s")
+ ResDef( DBT_ReadDbMapFileRegisterDatabaseFailed, 141, "Failed to register database %s")
+ ResDef( DBT_AclerrfmtAclerrfail, 142, "ACL call returned failed status")
+ ResDef( DBT_AclerrfmtAclerrio, 143, "file %s: ACL IO error - %s")
+ ResDef( DBT_AclUserExistsOutOfMemory, 144, "acl_user_exists: out of memory")
+ ResDef( DBT_AclUserExistsNot, 145, "acl_user_exists: user doesn't exist anymore")
+ ResDef( DBT_AclUserPlistError, 146, "acl_user_exists: plist error")
+END_STR(libaccess)
diff --git a/include/libaccess/dnfstruct.h b/include/libaccess/dnfstruct.h
new file mode 100644
index 00000000..d1ab28a3
--- /dev/null
+++ b/include/libaccess/dnfstruct.h
@@ -0,0 +1,51 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __dnfstruct_h
+#define __dnfstruct_h
+
+/*
+ * Description (dnfstruct_h)
+ *
+ * This file defines types and structures used to represent a DNS
+ * name filter in memory. A DNS name filter contains specifications
+ * of fully or partially qualified DNS names. Each of these
+ * specifications can be associated with whatever information is
+ * appropriate for a particular use of a DNS name filter.
+ */
+
+#include "nspr.h"
+#include "plhash.h"
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * Description (DNSLeaf_t)
+ *
+ * This type describes the structure of information associated with
+ * an entry in a DNS filter. The filter itself is implemented as a
+ * hash table, keyed by the DNS name specification string. The
+ * value associated with a key is a pointer to a DNSLeaf_t structure.
+ */
+
+typedef struct DNSLeaf_s DNSLeaf_t;
+struct DNSLeaf_s {
+ PLHashEntry dnl_he; /* NSPR hash table entry */
+};
+
+#define dnl_next dnl_he.next /* hash table collision link */
+#define dnl_keyhash dnl_he.keyHash /* symbol hash value */
+#define dnl_key dnl_he.key /* pointer to Symbol_t structure */
+#define dnl_ref dnl_he.value /* pointer to named structure */
+
+typedef struct DNSFilter_s DNSFilter_t;
+struct DNSFilter_s {
+ DNSFilter_t * dnf_next; /* link to next filter */
+ void * dnf_hash; /* pointer to constructed hash table */
+};
+
+NSPR_END_EXTERN_C
+
+#endif /* __dnfstruct_h */
diff --git a/include/libaccess/ipfstruct.h b/include/libaccess/ipfstruct.h
new file mode 100644
index 00000000..acb0349e
--- /dev/null
+++ b/include/libaccess/ipfstruct.h
@@ -0,0 +1,81 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __ipfstruct_h
+#define __ipfstruct_h
+
+/*
+ * Description (ipfstruct.h)
+ *
+ * This file defines types and structures used to represent an
+ * IP address filter in memory. An IP address filter contains
+ * specifications of IP host and network addresses. Each of
+ * these specifications can be associated with whatever information
+ * is appropriate for a particular use of an IP address filter.
+ */
+
+/* Define a scalar IP address value */
+#ifndef __IPADDR_T_
+#define __IPADDR_T_
+typedef unsigned long IPAddr_t;
+#endif /* __IPADDR_T_ */
+
+/*
+ * Description (IPNode_t)
+ *
+ * This type describes an internal node in the radix tree. An internal
+ * node has a link up the tree to its parent, and up to three links
+ * down the tree to its descendants. Each internal node is used to
+ * test a particular bit in a given IP address, and traverse down the
+ * tree in a direction which depends on whether the bit is set, clear,
+ * or masked out. The descendants of an internal node may be internal
+ * nodes or leaf nodes (IPLeaf_t).
+ */
+
+/* Define indices of links in an IPNode_t */
+#define IPN_CLEAR 0 /* link to node with ipn_bit clear */
+#define IPN_SET 1 /* link to node with ipn_bit set */
+#define IPN_MASKED 2 /* link to node with ipn_bit masked out */
+#define IPN_NLINKS 3 /* number of links */
+
+typedef struct IPNode_s IPNode_t;
+struct IPNode_s {
+ char ipn_type; /* node type */
+#define IPN_LEAF 0 /* leaf node */
+#define IPN_NODE 1 /* internal node */
+
+ char ipn_bit; /* bit number (31-0) to test */
+ IPNode_t * ipn_parent; /* link to parent node */
+ IPNode_t * ipn_links[IPN_NLINKS];
+};
+
+/* Helper definitions */
+#define ipn_clear ipn_links[IPN_CLEAR]
+#define ipn_set ipn_links[IPN_SET]
+#define ipn_masked ipn_links[IPN_MASKED]
+
+/*
+ * Description (IPLeaf_t)
+ *
+ * This type describes a leaf node in the radix tree. A leaf node
+ * contains an IP host or network address, and a network mask. A
+ * given IP address matches a leaf node if the IP address, when masked
+ * by ipl_netmask, equals ipl_ipaddr.
+ */
+
+typedef struct IPLeaf_s IPLeaf_t;
+struct IPLeaf_s {
+ char ipl_type; /* see ipn_type in IPNode_t */
+ IPAddr_t ipl_netmask; /* IP network mask */
+ IPAddr_t ipl_ipaddr; /* IP address of host or network */
+};
+
+typedef struct IPFilter_s IPFilter_t;
+struct IPFilter_s {
+ IPFilter_t * ipf_next; /* link to next filter */
+ IPNode_t * ipf_tree; /* pointer to radix tree structure */
+};
+
+#endif /* __ipfstruct_h */
diff --git a/include/libaccess/las.h b/include/libaccess/las.h
new file mode 100644
index 00000000..252e3619
--- /dev/null
+++ b/include/libaccess/las.h
@@ -0,0 +1,184 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef ACL_LAS_HEADER
+#define ACL_LAS_HEADER
+
+#ifndef NOINTNSACL
+#define INTNSACL
+#endif /* !NOINTNSACL */
+
+/* #include <prhash.h> */
+#include <plhash.h>
+#include <prclist.h>
+
+#include <base/pblock.h>
+#include <base/plist.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+
+#ifndef PUBLIC_NSACL_ACLDEF_H
+#include "public/nsacl/acldef.h"
+#endif /* !PUBLIC_NSACL_ACLDEF_H */
+
+#define ACL_MAX_METHOD 32
+#define ACL_MAX_DBTYPE 32
+
+struct ACLAttrGetter {
+ PRCList list; /* must be first */
+ ACLMethod_t method;
+ ACLDbType_t dbtype;
+ ACLAttrGetterFn_t fn;
+ void *arg;
+};
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC extern int
+ ACL_LasRegister(NSErr_t *errp, char *attr_name, LASEvalFunc_t
+ eval_func, LASFlushFunc_t flush_func);
+NSAPI_PUBLIC extern int
+ ACL_LasFindEval(NSErr_t *errp, char *attr_name, LASEvalFunc_t
+ *eval_funcp);
+NSAPI_PUBLIC extern int
+ ACL_LasFindFlush(NSErr_t *errp, char *attr_name, LASFlushFunc_t
+ *flush_funcp);
+extern void
+ ACL_LasHashInit(void);
+extern void
+ ACL_LasHashDestroy(void);
+
+/*
+ * Revised, normalized method/dbtype registration routines
+ */
+NSAPI_PUBLIC extern int
+ ACL_MethodRegister(NSErr_t *errp, const char *name, ACLMethod_t *t);
+NSAPI_PUBLIC extern int
+ ACL_MethodIsEqual(NSErr_t *errp, const ACLMethod_t t1, const ACLMethod_t t2);
+NSAPI_PUBLIC extern int
+ ACL_MethodNameIsEqual(NSErr_t *errp, const ACLMethod_t t, const char *name);
+NSAPI_PUBLIC extern int
+ ACL_MethodFind(NSErr_t *errp, const char *name, ACLMethod_t *t);
+NSAPI_PUBLIC extern ACLMethod_t
+ ACL_MethodGetDefault(NSErr_t *errp);
+NSAPI_PUBLIC extern int
+ ACL_MethodSetDefault(NSErr_t *errp, const ACLMethod_t t);
+NSAPI_PUBLIC extern int
+ ACL_AuthInfoGetMethod(NSErr_t *errp, PList_t auth_info, ACLMethod_t *t);
+NSAPI_PUBLIC extern int
+ ACL_AuthInfoSetMethod(NSErr_t *errp, PList_t auth_info, ACLMethod_t t);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeRegister(NSErr_t *errp, const char *name, DbParseFn_t func, ACLDbType_t *t);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeIsEqual(NSErr_t *errp, const ACLDbType_t t1, const ACLDbType_t t2);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeNameIsEqual(NSErr_t *errp, const ACLDbType_t t, const char *name);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeFind(NSErr_t *errp, const char *name, ACLDbType_t *t);
+NSAPI_PUBLIC extern ACLDbType_t
+ ACL_DbTypeGetDefault(NSErr_t *errp);
+NSAPI_PUBLIC extern const char *
+ ACL_DatabaseGetDefault(NSErr_t *errp);
+NSAPI_PUBLIC extern int
+ ACL_DatabaseSetDefault(NSErr_t *errp, const char *dbname);
+NSAPI_PUBLIC extern int
+ ACL_AuthInfoGetDbType(NSErr_t *errp, PList_t auth_info, ACLDbType_t *t);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeIsRegistered(NSErr_t *errp, const ACLDbType_t dbtype);
+NSAPI_PUBLIC extern int
+ ACL_AttrGetterRegister(NSErr_t *errp, const char *attr,
+ ACLAttrGetterFn_t fn, ACLMethod_t m,
+ ACLDbType_t d, int position, void *arg);
+
+extern ACLDbType_t ACL_DbTypeLdap;
+
+NSAPI_PUBLIC extern int
+ ACL_DbTypeSetDefault(NSErr_t *errp, ACLDbType_t t);
+NSAPI_PUBLIC extern DbParseFn_t
+ ACL_DbTypeParseFn(NSErr_t *errp, const ACLDbType_t dbtype);
+NSAPI_PUBLIC extern int
+ ACL_AttrGetterFind(NSErr_t *errp, const char *attr,
+ ACLAttrGetterList_t *getters);
+NSAPI_PUBLIC extern ACLAttrGetter_t *
+ ACL_AttrGetterFirst(ACLAttrGetterList_t *getters);
+NSAPI_PUBLIC extern ACLAttrGetter_t *
+ ACL_AttrGetterNext(ACLAttrGetterList_t *getters,
+ ACLAttrGetter_t *last);
+
+/* typedef PRHashTable AttrGetterTable_t; */
+typedef PLHashTable AttrGetterTable_t;
+
+typedef struct {
+ char *method;
+ char *authtype;
+ char *dbtype;
+ AttrGetterTable_t *attrGetters;
+} MethodInfo_t;
+
+NSAPI_PUBLIC int ACL_ModuleRegister (NSErr_t *errp, const char *moduleName, AclModuleInitFunc func);
+
+NSAPI_PUBLIC int ACL_GetAttribute(NSErr_t *errp, const char *attr, void **val, PList_t subject, PList_t resource, PList_t auth_info, PList_t global_auth);
+
+NSAPI_PUBLIC int ACL_DatabaseRegister(NSErr_t *errp, ACLDbType_t dbtype, const char *dbname, const char *url, PList_t plist);
+
+NSAPI_PUBLIC int ACL_RegisterDbFromACL(NSErr_t *errp, const char *url, ACLDbType_t *dbtype);
+NSAPI_PUBLIC int ACL_DatabaseFind(NSErr_t *errp, const char *dbname,
+ ACLDbType_t *dbtype, void **db);
+NSAPI_PUBLIC int ACL_LDAPDatabaseHandle (NSErr_t *errp,
+ const char *dbname, LDAP **ld,
+ char **basedn);
+NSAPI_PUBLIC int ACL_AuthInfoGetDbname (PList_t auth_info, char **dbname);
+NSAPI_PUBLIC int ACL_AuthInfoSetDbname (NSErr_t *errp, PList_t auth_info,
+ const char *dbname);
+NSAPI_PUBLIC int ACL_CacheFlushRegister(AclCacheFlushFunc_t func);
+NSAPI_PUBLIC int ACL_SetDefaultResult (NSErr_t *errp,
+ ACLEvalHandle_t *acleval,
+ int result);
+NSAPI_PUBLIC int ACL_GetDefaultResult (ACLEvalHandle_t *acleval);
+
+struct program_groups {
+ char *type;
+ char **groups;
+ char **programs;
+};
+
+extern int LASTimeOfDayEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, ACLCachable_t *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASDayOfWeekEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, ACLCachable_t *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASIpEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, ACLCachable_t *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASDnsEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, ACLCachable_t *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASGroupEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, ACLCachable_t *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASUserEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, ACLCachable_t *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASProgramEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, ACLCachable_t *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern void LASTimeOfDayFlush(void **cookie);
+extern void LASDayOfWeekFlush(void **cookie);
+extern void LASIpFlush(void **cookie);
+extern void LASDnsFlush(void **cookie);
+
+NSPR_END_EXTERN_C
+
+#endif /* ACL_LAS_HEADER */
diff --git a/include/libaccess/ldapacl.h b/include/libaccess/ldapacl.h
new file mode 100644
index 00000000..94a00333
--- /dev/null
+++ b/include/libaccess/ldapacl.h
@@ -0,0 +1,62 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef ACL_AUTH_H
+#define ACL_AUTH_H
+
+#include <ldap.h>
+#include <base/plist.h>
+#include <ldaputil/ldapdb.h>
+#include <libaccess/nserror.h>
+
+NSPR_BEGIN_EXTERN_C
+
+extern void init_ldb_rwlock ();
+
+NSAPI_PUBLIC extern int parse_ldap_url (NSErr_t *errp, ACLDbType_t dbtype,
+ const char *name, const char *url,
+ PList_t plist, void **db);
+
+extern int get_is_valid_password_basic_ldap (NSErr_t *errp,
+ PList_t subject,
+ PList_t resource,
+ PList_t auth_info,
+ PList_t global_auth,
+ void *arg);
+
+extern int get_user_ismember_ldap (NSErr_t *errp,
+ PList_t subject,
+ PList_t resource,
+ PList_t auth_info,
+ PList_t global_auth,
+ void *arg);
+
+extern int get_userdn_ldap (NSErr_t *errp,
+ PList_t subject,
+ PList_t resource,
+ PList_t auth_info,
+ PList_t global_auth,
+ void *arg);
+
+extern int ACL_NeedLDAPOverSSL();
+
+extern int acl_map_cert_to_user (NSErr_t *errp, const char *dbname,
+ LDAPDatabase_t *ldb, void *cert,
+ PList_t resource, pool_handle_t *pool,
+ char **user, char **userdn);
+
+extern int get_user_exists_ldap (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused);
+
+NSAPI_PUBLIC extern int acl_user_exists (const char *user,
+ const char *userdn,
+ const char *dbname,
+ const int logerr);
+
+NSPR_END_EXTERN_C
+
+#endif /* ACL_AUTH_H */
diff --git a/include/libaccess/nsadb.h b/include/libaccess/nsadb.h
new file mode 100644
index 00000000..07fb2ca2
--- /dev/null
+++ b/include/libaccess/nsadb.h
@@ -0,0 +1,87 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __nsadb_h
+#define __nsadb_h
+
+/*
+ * Description (nsadb.h)
+ *
+ * This file describes the interface for retrieving information
+ * from a Netscape authentication database. This facility is
+ * built on top of the Netscape (server) database interface as
+ * defined in nsdb.h. It represents a subclass of a more general
+ * authentication database interface defined in nsauth.h.
+ */
+
+#include "nserror.h" /* error frame list support */
+#include "nsautherr.h" /* authentication error codes */
+#include "nsauth.h"
+
+/* Begin private definitions */
+#ifdef __PRIVATE_NSADB
+
+#include "nsdb.h"
+
+#if defined(CLIENT_AUTH)
+#define ADBDBNAMES 3 /* number of named files */
+#else
+#define ADBDBNAMES 2 /* number of named files */
+#endif
+#define ADBUSERDBNAME "Users" /* name of user database */
+#define ADBGROUPDBNAME "Groups" /* name of group database */
+#if defined(CLIENT_AUTH)
+#define ADBCERTDBNAME "Certs" /* name of certificate mapping DB */
+#define ADBUMAPDBNAME "Certs.nm" /* name of mapped user names DB */
+#endif
+
+typedef struct AuthDB_s AuthDB_t;
+struct AuthDB_s {
+ char * adb_dbname; /* database name */
+ void * adb_userdb; /* handle for user database */
+ void * adb_groupdb; /* handle for group database */
+#if defined(CLIENT_AUTH)
+ void * adb_certdb; /* handle for cert mapping database */
+ void * adb_certlock; /* lock for cert mapping database */
+ void * adb_certnm; /* handle for username-to-certid DB */
+#endif
+ int adb_flags; /* flags */
+};
+
+/* Definitions for adb_flags (also used on nsadbOpenXxxx() calls) */
+#define ADBF_NEW 0x1 /* newly created database */
+#define ADBF_UREAD 0x10 /* user database open for read */
+#define ADBF_UWRITE 0x20 /* user database open for write */
+#define ADBF_GREAD 0x100 /* group database open for read */
+#define ADBF_GWRITE 0x200 /* group database open for write */
+#define ADBF_CREAD 0x1000 /* cert database open for read */
+#define ADBF_CWRITE 0x2000 /* cert database open for write */
+#endif /* __PRIVATE_NSADB */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Functions in nsadb.c */
+extern NSAPI_PUBLIC int nsadbOpen(NSErr_t * errp,
+ char * adbname, int flags, void **rptr);
+extern NSAPI_PUBLIC void nsadbClose(void * authdb, int flags);
+extern NSAPI_PUBLIC int nsadbOpenUsers(NSErr_t * errp,
+ void * authdb, int flags);
+extern NSAPI_PUBLIC int nsadbOpenGroups(NSErr_t * errp,
+ void * authdb, int flags);
+extern NSAPI_PUBLIC int nsadbIdToName(NSErr_t * errp, void * authdb,
+ USI_t id, int flags, char **rptr);
+extern NSAPI_PUBLIC int nsadbFindByName(NSErr_t * errp, void * authdb,
+ char * name, int flags, void **rptr);
+
+#if defined(CLIENT_AUTH)
+#include "nscert.h"
+#endif
+
+/* Authentication database interface structure in nsadb.c */
+extern AuthIF_t NSADB_AuthIF;
+
+NSPR_END_EXTERN_C
+
+#endif /* __nsadb_h */
diff --git a/include/libaccess/nsamgmt.h b/include/libaccess/nsamgmt.h
new file mode 100644
index 00000000..c6b82ca4
--- /dev/null
+++ b/include/libaccess/nsamgmt.h
@@ -0,0 +1,122 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __nsamgmt_h
+#define __nsamgmt_h
+
+/*
+ * Description (nsamgmt.h)
+ *
+ * This file defines the interface for managing information in a
+ * Netscape authentication database. An authentication database
+ * consists of a user database and a group database. This
+ * implementation of an authentication database based on Netscape
+ * user and group databases defined in nsuser.h and nsgroup.h,
+ * which in turn are based on the Netscape (server) database
+ * implementation defined in nsdb.h. The interface for retrieving
+ * information from an authentication database is described
+ * separately in nsadb.h.
+ */
+
+#include "nsadb.h"
+
+/* Flags used in enumeration call-back function return value */
+#define ADBF_KEEPOBJ 0x1 /* do not free user or group object */
+#define ADBF_STOPENUM 0x2 /* stop the enumeration */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Functions in nsamgmt.c */
+NSAPI_PUBLIC extern int nsadbAddGroupToGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * pgoptr,
+ GroupObj_t * cgoptr);
+
+NSAPI_PUBLIC extern int nsadbAddUserToGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * goptr,
+ UserObj_t * uoptr);
+
+NSAPI_PUBLIC extern int nsadbCreateGroup(NSErr_t * errp,
+ void * authdb, GroupObj_t * goptr);
+
+NSAPI_PUBLIC extern int nsadbCreateUser(NSErr_t * errp,
+ void * authdb, UserObj_t * uoptr);
+
+/*
+for ANSI C++ standard on SCO UDK must typedef fn in arg list, otherwise fn
+name is managled
+*/
+
+#ifdef UnixWare
+typedef int(*ArgFn_EnumUsers)(NSErr_t * ferrp, void * authdb, void * parg,
+ UserObj_t * uoptr);
+
+NSAPI_PUBLIC extern int nsadbEnumerateUsers(NSErr_t * errp, void * authdb,
+ void * argp, ArgFn_EnumUsers);
+#else /* UnixWare */
+NSAPI_PUBLIC extern int nsadbEnumerateUsers(NSErr_t * errp, void * authdb,
+ void * argp,
+ int (*func)(NSErr_t * ferrp,
+ void * authdb,
+ void * parg,
+ UserObj_t * uoptr));
+#endif /* UnixWare */
+
+#ifdef UnixWare
+typedef int(*ArgFn_EnumGroups)(NSErr_t * ferrp, void * authdb, void * parg,
+ GroupObj_t * goptr);
+NSAPI_PUBLIC extern int nsadbEnumerateGroups(NSErr_t * errp,
+ void * authdb, void * argp,
+ ArgFn_EnumGroups);
+#else /* UnixWare */
+NSAPI_PUBLIC extern int nsadbEnumerateGroups(NSErr_t * errp,
+ void * authdb, void * argp,
+ int (*func)(NSErr_t * ferrp,
+ void * authdb,
+ void * parg,
+ GroupObj_t * goptr));
+#endif /* UnixWare */
+
+NSAPI_PUBLIC extern int nsadbIsUserInGroup(NSErr_t * errp, void * authdb,
+ USI_t uid, USI_t gid,
+ int ngroups, USI_t * grplist);
+
+NSAPI_PUBLIC extern int nsadbModifyGroup(NSErr_t * errp,
+ void * authdb, GroupObj_t * goptr);
+
+NSAPI_PUBLIC extern int nsadbModifyUser(NSErr_t * errp,
+ void * authdb, UserObj_t * uoptr);
+
+NSAPI_PUBLIC extern int nsadbRemoveGroup(NSErr_t * errp,
+ void * authdb, char * name);
+
+NSAPI_PUBLIC extern int nsadbRemoveUser(NSErr_t * errp,
+ void * authdb, char * name);
+
+NSAPI_PUBLIC extern int nsadbRemGroupFromGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * pgoptr,
+ GroupObj_t * cgoptr);
+
+NSAPI_PUBLIC extern int nsadbRemUserFromGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * goptr,
+ UserObj_t * uoptr);
+
+NSAPI_PUBLIC extern int nsadbSuperGroups(NSErr_t * errp, void * authdb,
+ GroupObj_t * goptr,
+ USIList_t * gsuper);
+
+
+NSPR_END_EXTERN_C
+
+#if defined(CLIENT_AUTH)
+
+/* Removed for new ns security integration
+#include <sec.h>
+*/
+#include <key.h>
+#include <cert.h>
+
+#endif /* defined(CLIENT_AUTH) */
+
+#endif /* __nsamgmt_h */
diff --git a/include/libaccess/nsauth.h b/include/libaccess/nsauth.h
new file mode 100644
index 00000000..8f5ce877
--- /dev/null
+++ b/include/libaccess/nsauth.h
@@ -0,0 +1,288 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __nsauth_h
+#define __nsauth_h
+
+/*
+ * Description (nsauth.h)
+ *
+ * This file defines types and interfaces which pertain to client
+ * authentication. The key types are Realm_t, which describes a
+ * context for authentication, and ClAuth_t, which is used to
+ * pass authentication information about a particular client
+ * into and out of authentication interface functions.
+ */
+
+#ifdef CLIENT_AUTH
+
+#include "ssl.h"
+
+#if 0
+/* Removed for new ns security */
+#include "sec.h" /* SECCertificate */
+#endif
+#include "cert.h" /* CERTCertificate for new ns security bin */
+#endif /* CLIENT_AUTH */
+
+#include "usi.h" /* identifier list support */
+#include "attrec.h" /* attribute record types */
+#include "nserror.h" /* error frame list support */
+#include "nsautherr.h" /* authentication error codes */
+
+/* Define a scalar IP address value */
+#ifndef __IPADDR_T_
+#define __IPADDR_T_
+typedef unsigned long IPAddr_t;
+#endif /* __IPADDR_T_ */
+
+/*
+ * Description (UserObj_t)
+ *
+ * This type defines the structure of a user object. A user object
+ * contains information about a user which might be contained in
+ * an authentication database, including user name, password, user id,
+ * and group membership.
+ */
+
+typedef struct UserObj_s UserObj_t;
+struct UserObj_s {
+ NTS_t uo_name; /* user account name */
+ NTS_t uo_pwd; /* encrypted password */
+ USI_t uo_uid; /* user id */
+ USI_t uo_flags; /* bit flags */
+#define UOF_DBFLAGS 0x1f /* mask for flags stored in DB file */
+#define UOF_ERROR 0x20 /* error on last operation */
+#define UOF_NEW 0x40 /* new user object */
+#define UOF_MODIFIED 0x80 /* internal object modified */
+#define UOF_DELPEND 0x100 /* delete pending */
+
+ NTS_t uo_rname; /* real user name (gecos string) */
+ USIList_t uo_groups; /* list of group ids containing user */
+};
+
+/*
+ * Description (GroupObj_t)
+ *
+ * This type defines the structure of a group object. A group object
+ * contains information about a group which might be contained in
+ * an authentication database, including group name, group id, and
+ * relationships to other groups.
+ */
+
+typedef struct GroupObj_s GroupObj_t;
+struct GroupObj_s {
+ NTS_t go_name; /* group name */
+ USI_t go_gid; /* group id */
+ USI_t go_flags; /* bit flags */
+#define GOF_DBFLAGS 0x3f /* mask for flags stored in DB file */
+#define GOF_NEW 0x40 /* new group object */
+#define GOF_MODIFIED 0x80 /* internal object modified */
+#define GOF_DELPEND 0x100 /* delete pending */
+
+ NTS_t go_desc; /* group description */
+ USIList_t go_users; /* list of user members (uids) */
+ USIList_t go_groups; /* list of group members (gids) */
+ USIList_t go_pgroups; /* list of parent groups (gids) */
+};
+
+/*
+ * Description (AuthIF_t)
+ *
+ * This type describes a structure containing pointers to functions
+ * which provide a standard interface to an authentication database.
+ * The functions are described below.
+ *
+ * Description (aif_close)
+ *
+ * The referenced function closes an authentication database which
+ * was previously opened via the aif_open function.
+ *
+ * Arguments:
+ *
+ * authdb - handle for database returned by aif_open
+ * flags - close flags (unused - must be zero)
+ *
+ *
+ * Description (aif_findid)
+ *
+ * The referenced function looks up a specified user or group id
+ * in a given authentication database. Flags can be specified to
+ * search for only matching user ids, only matching group ids,
+ * or both. The result value for a successful search indicates
+ * whether a matching user or group id was found, and a pointer to
+ * a user or group object is returned accordingly.
+ *
+ * Arguments:
+ *
+ * authdb - handle for database returned by aif_open
+ * id - user/group id value
+ * flags - bit flags to control search
+ * rptr - pointer to returned user or group object
+ * pointer (may be null)
+ *
+ * Returns:
+ *
+ * If successful, the result value is greater than zero, and contains
+ * a subset of the search flags, indicating what was found, and a user
+ * or group object pointer is returned through 'rptr' if it is non-null.
+ * An unsuccessful search is indicated by a return value of zero. An
+ * error is indicated by a negative return value (defined in
+ * nsautherr.h).
+ *
+ *
+ * Description (aif_findname)
+ *
+ * The referenced function looks up a specified user or group name
+ * in a given authentication database. Flags can be specified to
+ * search for only matching user names, only matching group names,
+ * or both. The result value for a successful search indicates
+ * whether a matching user or group was found, and a pointer to a
+ * user or group object is returned accordingly.
+ *
+ * Arguments:
+ *
+ * authdb - handle for database returned by aif_open
+ * name - user/group name string pointer
+ * flags - bit flags to control search
+ * rptr - pointer to returned user or group object
+ * pointer (may be null)
+ *
+ * Returns:
+ *
+ * If successful, the result value is greater than zero, and contains
+ * a subset of the search flags, indicating what was found, and a user
+ * or group object pointer is returned through 'rptr' if it is non-null.
+ * An unsuccessful search is indicated by a return value of zero. An
+ * error is indicated by a negative return value (defined in
+ * nsautherr.h).
+ *
+ *
+ * Description (aif_idtoname)
+ *
+ * The referenced function looks up a specified user or group id
+ * in a given authentication database, and returns the associated
+ * user or group name. Flags can be specified to search for only
+ * matching user ids, only matching group ids, or both. The result
+ * value for a successful search indicates whether a matching user
+ * or group id was found, and a pointer to the user or group name
+ * is returned accordingly.
+ *
+ * Arguments:
+ *
+ * authdb - handle for database returned by aif_open
+ * id - user/group id value
+ * flags - bit flags to control search
+ * rptr - pointer to returned user or group name
+ * pointer (may be null)
+ *
+ * Returns:
+ *
+ * If successful, the result value is greater than zero, and contains
+ * a subset of the search flags, indicating what was found, and a user
+ * or group name pointer is returned through 'rptr' if it is non-null.
+ * An unsuccessful search is indicated by a return value of zero. An
+ * error is indicated by a negative return value (defined in
+ * nsautherr.h).
+ *
+ *
+ * Description (aif_open)
+ *
+ * The referenced function opens a named authentication database of
+ * the type supported by this interface. The actual effect of the
+ * open function depends on the particular type of database, but a
+ * call to the aif_open function should generally be followed by a
+ * call to the aif_close function at some point.
+ *
+ * Arguments:
+ *
+ * adbname - authentication database name string pointer
+ * flags - open flags (definitions below)
+ * rptr - pointer to returned handle for the database
+ *
+ * Returns:
+ *
+ * The return value is zero if the operation is successful, and a
+ * handle for the authentication database is returned through 'rptr'.
+ * An error is indicated by a negative return value (defined in
+ * nsautherr.h).
+ */
+
+typedef struct AuthIF_s AuthIF_t;
+struct AuthIF_s {
+ int (*aif_findid)(NSErr_t * errp,
+ void * authdb, USI_t id, int flags, void **rptr);
+ int (*aif_findname)(NSErr_t * errp,
+ void * authdb, char * name, int flags, void **rptr);
+ int (*aif_idtoname)(NSErr_t * errp,
+ void * authdb, USI_t id, int flags, char **rptr);
+ int (*aif_open)(NSErr_t * errp, char * adbname, int flags, void **rptr);
+ void (*aif_close)(void * authdb, int flags);
+ int (*aif_addmember)(void **pmlist, char * name, int flags);
+ int (*aif_ismember)(void * mlist, char * name, int flags);
+};
+
+/* Define flags for the aif_open function */
+#define AIF_CREATE 0x1 /* new database (create it) */
+
+/*
+ * Define bits for flags and return value of aif_findid, aif_findid,
+ * and aif_idtoname functions.
+ */
+#define AIF_NONE 0 /* no matching group or user name */
+#define AIF_GROUP 0x1 /* matching group name/id found */
+#define AIF_USER 0x2 /* matching user name/id found */
+
+/*
+ * Description (Realm_t)
+ *
+ * This type defines a structure which represents an authentication
+ * realm. Each realm has a unique name, which is accessed through
+ * a Symbol_t structure, which in turn references a Realm_t as the
+ * symbol value. This structure specifies an authentication
+ * method and an authentication database.
+ */
+
+typedef struct Realm_s Realm_t;
+struct Realm_s {
+ int rlm_ameth; /* authentication method type */
+ char * rlm_dbname; /* authentication database name */
+ AuthIF_t * rlm_aif; /* authentication interface pointer */
+ void * rlm_authdb; /* authentication database handle */
+ char * rlm_prompt; /* realm prompt string */
+};
+
+/* Define supported authentication method codes for rlm_ameth */
+#define AUTH_METHOD_BASIC 1 /* basic authentication */
+#define AUTH_METHOD_SSL 2 /* SSL client authentication */
+
+/*
+ * Description (ClAuth_t)
+ *
+ * This type describes a structure containing information about a
+ * particular client. It is used to pass information into and out
+ * of authentication support functions, as well as to other functions
+ * needing access to client authentication information.
+ * FUTURE:
+ * - add client certificate pointer
+ */
+
+typedef struct ClAuth_s ClAuth_t;
+struct ClAuth_s {
+ Realm_t * cla_realm; /* authentication realm pointer */
+ IPAddr_t cla_ipaddr; /* IP address */
+ char * cla_dns; /* DNS name string pointer */
+ UserObj_t * cla_uoptr; /* authenticated user object pointer */
+ GroupObj_t * cla_goptr; /* pointer to list of group objects */
+#ifdef CLIENT_AUTH
+#if 0
+ /* Removed for new ns security */
+ SECCertificate * cla_cert; /* certificate from SSL client auth */
+#endif
+ CERTCertificate * cla_cert; /* certificate from SSL client auth */
+#endif /* CLIENT_AUTH */
+};
+
+#endif /* __nsauth_h */
diff --git a/include/libaccess/nsautherr.h b/include/libaccess/nsautherr.h
new file mode 100644
index 00000000..02951b9f
--- /dev/null
+++ b/include/libaccess/nsautherr.h
@@ -0,0 +1,97 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __nsautherr_h
+#define __nsautherr_h
+
+/* Define error id codes */
+
+/* Define error ids generated by nsumgmt.c */
+
+/* userRename() */
+#define NSAUERR1000 1000 /* insufficient dynamic memory */
+
+/* userStore() */
+#define NSAUERR1100 1100 /* insufficient dynamic memory */
+
+/* Define error ids generated by nsgmgmt.c */
+
+/* groupStore() */
+#define NSAUERR2000 2000 /* insufficient dynamic memory */
+
+/* Define error ids generated by nsadb.c */
+
+/* nsadbOpen() */
+#define NSAUERR3000 3000 /* invalid function argument */
+#define NSAUERR3020 3020 /* insufficient dynamic memory */
+#define NSAUERR3040 3040 /* create directory operation failed */
+#define NSAUERR3060 3060 /* open directory operation failed */
+
+/* nsadbOpenUsers() */
+#define NSAUERR3200 3200 /* invalid function argument */
+#define NSAUERR3220 3220 /* insufficient dynamic memory */
+#define NSAUERR3240 3240 /* error opening user database */
+
+/* nsadbOpenGroups() */
+#define NSAUERR3300 3300 /* invalid function argument */
+#define NSAUERR3320 3320 /* insufficient dynamic memory */
+#define NSAUERR3340 3340 /* error opening group database */
+
+#if defined(CLIENT_AUTH)
+/* nsadbOpenClients() */
+#define NSAUERR3400 3400 /* invalid function argument */
+#define NSAUERR3420 3420 /* insufficient dynamic memory */
+#define NSAUERR3430 3430 /* error initializing DB lock */
+#define NSAUERR3440 3440 /* error opening group database */
+
+/* nsadbPutUserByCert() */
+#define NSAUERR3500 3500 /* invalid username length */
+#define NSAUERR3520 3520 /* user-to-cert map already exists */
+
+/* nsadbOpenCertUsers() */
+#define NSAUERR3600 3600 /* error opening user-to-cert id DB */
+
+/* nsadbFindCertUser() */
+#define NSAUERR3700 3700 /* specified user name not found */
+
+/* nsadbAddCertUser() */
+#define NSAUERR3800 3800 /* error adding entry to database */
+
+/* nsadbRemoveCertUser() */
+#define NSAUERR3900 3900 /* error deleting entry in database */
+
+#endif /* defined(CLIENT_AUTH) */
+
+/* Define error ids generated by nsamgmt.c */
+
+/* nsadbRemoveUser() */
+#define NSAUERR4000 4000 /* user name not found */
+
+/* nsadbRemoveGroup() */
+#define NSAUERR4100 4100 /* group name not found */
+
+/* Define error codes */
+#define NSAERRNOMEM -1 /* insufficient dynamic memory */
+#define NSAERRINVAL -2 /* invalid function argument */
+#define NSAERROPEN -3 /* error opening database */
+#define NSAERRMKDIR -4 /* error creating database directory */
+#define NSAERRNAME -5 /* user or group name not found */
+#define NSAERRPUT -6 /* error writing record to database */
+#define NSAERRCMAP -7 /* certificate map already exists */
+#define NSAERRDEL -8 /* error deleting database entry */
+#define NSAERRLOCK -9 /* error initializing DB lock */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Authentication facility name in nsuser.c */
+extern char * NSAuth_Program;
+
+ /* Functions in nsautherr.c */
+extern NSAPI_PUBLIC void nsadbErrorFmt(NSErr_t * errp,
+ char * msgbuf, int maxlen, int maxdepth);
+
+NSPR_END_EXTERN_C
+
+#endif /* __nsautherr_h */
diff --git a/include/libaccess/nscert.h b/include/libaccess/nscert.h
new file mode 100644
index 00000000..b704bbdf
--- /dev/null
+++ b/include/libaccess/nscert.h
@@ -0,0 +1,102 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __nscert_h
+#define __nscert_h
+
+/*
+ * Description (nscert.h)
+ *
+ * This file describes the interface for accessing and storing
+ * information in a Netscape client certificate to username
+ * database. This facility is built on top of the Netscape
+ * (server) database interface as defined in nsdb.h.
+ */
+
+#include <libaccess/nserror.h> /* error frame list support */
+#include <libaccess/nsautherr.h> /* authentication error codes */
+#include <libaccess/nsauth.h>
+
+#include <prtypes.h>
+/* Removed for new ns security integration
+#include <sec.h>
+*/
+#include <cert.h>
+
+#if defined(CLIENT_AUTH)
+
+/* Certificate to user record attribute tags */
+#define CAT_USERNAME 0x61 /* username associated with cert */
+#define CAT_CERTID 0x62 /* id assigned to cert */
+
+/* Attribute tags used in certificate key encoding */
+#define KAT_ISSUER 0x01 /* issuer DER */
+#define KAT_SUBJECT 0x02 /* subject DER */
+
+typedef struct CertObj_s CertObj_t;
+struct CertObj_s {
+ SECItem co_issuer; /* issuing authority */
+ SECItem co_subject; /* certicate's subject */
+ char * co_username; /* the local name it mapps to */
+ USI_t co_certid; /* internal id for this client certificate */
+};
+
+typedef int (*CertEnumCallback)(NSErr_t * ferrp, void * authdb,
+ void * argp, CertObj_t * coptr);
+
+NSPR_BEGIN_EXTERN_C
+
+extern NSAPI_PUBLIC int nsadbCertInitialize(void);
+
+extern NSAPI_PUBLIC int nsadbDecodeCertKey(int keylen, char * keyptr,
+ SECItem * issuer,
+ SECItem * subject);
+
+extern NSAPI_PUBLIC int nsadbDecodeCertRec(int reclen, char * recptr,
+ CertObj_t * coptr);
+
+extern NSAPI_PUBLIC int nsadbEncodeCertKey(SECItem * issuer, SECItem * subject,
+ int * keylen, char **keyptr);
+
+extern NSAPI_PUBLIC int nsadbEnumerateCerts(NSErr_t * errp, void * authdb,
+ void * argp,
+ CertEnumCallback func);
+
+extern NSAPI_PUBLIC void nsadbFreeCertObj(CertObj_t * coptr);
+
+extern NSAPI_PUBLIC int nsadbGetCertById(NSErr_t * errp, void * authdb,
+ USI_t certid, CertObj_t **coptr);
+
+extern NSAPI_PUBLIC int nsadbGetUserByCert(NSErr_t * errp, void * authdb,
+ CERTCertificate * cert,
+ char **username);
+
+extern NSAPI_PUBLIC int nsadbOpenCerts(NSErr_t * errp,
+ void * authdb, int flags);
+
+extern NSAPI_PUBLIC int nsadbPutUserByCert(NSErr_t * errp, void * authdb,
+ CERTCertificate * cert,
+ const char * username);
+
+extern NSAPI_PUBLIC int nsadbRemoveCert(NSErr_t * errp, void * authdb,
+ void * username, CertObj_t * coptr);
+
+extern NSAPI_PUBLIC int nsadbRemoveUserCert(NSErr_t * errp, void * authdb,
+ char * username);
+
+extern NSAPI_PUBLIC void nsadbCloseCerts(void * authdb, int flags);
+
+extern NSAPI_PUBLIC void nsadbCloseCertUsers(void * authdb, int flags);
+
+extern NSAPI_PUBLIC int nsadbFindCertUser(NSErr_t * errp, void * authdb,
+ const char * username, USI_t * id);
+
+
+NSPR_END_EXTERN_C
+
+#endif /* CLIENT_AUTH */
+
+
+#endif /* __nscert_h */
diff --git a/include/libaccess/nsdb.h b/include/libaccess/nsdb.h
new file mode 100644
index 00000000..c5b39e1c
--- /dev/null
+++ b/include/libaccess/nsdb.h
@@ -0,0 +1,182 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __nsdb_h
+#define __nsdb_h
+
+/*
+ * Description (nsdb.h)
+ *
+ * This file describes the interface for retrieving information
+ * from a Netscape (server) database. A database is composed of
+ * two (libdbm) DB files. One of these (<dbname>.db) contains
+ * records indexed by a string key. These records contain the
+ * primary information in the database. A second DB file
+ * (<dbname>.id) is used to map an integer id value to a string
+ * key, which can then be used to locate a record in the first file.
+ * The interface for managing information in a database is described
+ * in nsdbmgmt.h.
+ */
+
+/* Begin private definitions */
+#ifdef __PRIVATE_NSDB
+
+#include "mcom_db.h"
+
+/*
+ * Description (NSDB_t)
+ *
+ * This type describes the structure that used to represent a
+ * Netscape server database. It includes fields to reference
+ * both the primary and id-to-name DB files, and information
+ * about the current state of the database.
+ */
+
+typedef struct NSDB_s NSDB_t;
+struct NSDB_s {
+ char * ndb_pname; /* primary DB file name pointer */
+ DB * ndb_pdb; /* primary DB file handle */
+ char * ndb_iname; /* id-to-name DB file name pointer */
+ DB * ndb_idb; /* id-to-name DB file handle */
+ int ndb_flags; /* bit flags */
+#define NDBF_RDNAME 0x1 /* primary DB open for read */
+#define NDBF_WRNAME 0x2 /* primary DB open for write */
+#define NDBF_NONAME 0x4 /* primary DB does not exist */
+#define NDBF_RDID 0x10 /* id-to-name DB open for read */
+#define NDBF_WRID 0x20 /* id-to-name DB open for write */
+#define NDBF_NOID 0x40 /* id-to-name DB does not exist */
+
+ int ndb_dbtype; /* database type */
+ int ndb_version; /* type-specific version number */
+};
+
+/* Define metadata record keys (must start with NDB_MDPREFIX) */
+#define NDB_DBTYPE "?dbtype" /* database type and version info */
+#define NDB_IDMAP "?idmap" /* id allocation bitmap */
+
+#endif /* __PRIVATE_NSDB */
+
+/* Begin public definitions */
+
+#include "nserror.h" /* error frame list support */
+#include "nsdberr.h" /* error codes for NSDB facility */
+
+/* Define the NSDB version number */
+#define NDB_VERSION 0x10 /* NSDB version 1.0 */
+
+/* Define reserved database type codes for ndb_dbtype */
+#define NDB_TYPE_USERDB 1 /* user database */
+#define NDB_TYPE_GROUPDB 2 /* group database */
+#define NDB_TYPE_CLIENTDB 3 /* client database */
+#define NDB_TYPE_ACLDB 4 /* access control list database */
+
+/*
+ * Define the metadata record key prefix character. Normal data record
+ * keys (names) cannot begin with this character.
+ */
+#define NDB_MDPREFIX '?'
+
+/* Define flags for ndbEnumerate() */
+#define NDBF_ENUMNORM 0x1 /* enumerate normal data records */
+#define NDBF_ENUMMETA 0x2 /* enumerate metadata records */
+
+/* Define return values for a user function called by ndbEnumerate */
+#define NDB_ENUMSTOP -1 /* terminate enumeration */
+#define NDB_ENUMCONT 0 /* continue enumeration */
+#define NDB_ENUMRESET 1 /* restart enumeration at beginning */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Functions for database information retrieval in nsdb.c */
+extern void ndbClose(void * ndb, int flags);
+
+/* for ANSI C++ standard on SCO UDK, otherwise fn name is mangled */
+#ifdef UnixWare
+typedef int (*ArgFn_ndbEnum)(NSErr_t * ferrp, void * parg, int namelen,
+ char * name, int reclen, char * recptr);
+extern int ndbEnumerate(NSErr_t * errp, void * ndb, int flags, void * argp,
+ ArgFn_ndbEnum);
+#else /* UnixWare */
+extern int ndbEnumerate(NSErr_t * errp, void * ndb, int flags, void * argp,
+ int (*func)(NSErr_t * ferrp, void * parg,
+ int namelen, char * name,
+ int reclen, char * recptr));
+#endif /* UnixWare */
+extern int ndbFindName(NSErr_t * errp, void * ndb, int namelen, char * name,
+ int * reclen, char **recptr);
+extern int ndbIdToName(NSErr_t * errp,
+ void * ndb, unsigned int id, int * plen, char **pname);
+extern int ndbInitPrimary(NSErr_t * errp, void * ndb);
+extern void * ndbOpen(NSErr_t * errp,
+ char * dbname, int flags, int dbtype, int * version);
+extern int ndbReOpen(NSErr_t * errp, void * ndb, int flags);
+
+NSPR_END_EXTERN_C
+
+/* richm - 20020218 - these macros were added as part of the port to DBM 1.6
+ * apparently, these were exported for outside use from mcom_db.h in
+ * DBM 1.5x and earlier, but were made private in 1.6 - so I copied them
+ * here
+ */
+/*
+ * Little endian <==> big endian 32-bit swap macros.
+ * M_32_SWAP swap a memory location
+ * P_32_SWAP swap a referenced memory location
+ * P_32_COPY swap from one location to another
+ */
+#ifndef M_32_SWAP
+#define M_32_SWAP(a) { \
+ uint32 _tmp = a; \
+ ((char *)&a)[0] = ((char *)&_tmp)[3]; \
+ ((char *)&a)[1] = ((char *)&_tmp)[2]; \
+ ((char *)&a)[2] = ((char *)&_tmp)[1]; \
+ ((char *)&a)[3] = ((char *)&_tmp)[0]; \
+}
+#endif
+#ifndef P_32_SWAP
+#define P_32_SWAP(a) { \
+ uint32 _tmp = *(uint32 *)a; \
+ ((char *)a)[0] = ((char *)&_tmp)[3]; \
+ ((char *)a)[1] = ((char *)&_tmp)[2]; \
+ ((char *)a)[2] = ((char *)&_tmp)[1]; \
+ ((char *)a)[3] = ((char *)&_tmp)[0]; \
+}
+#endif
+#ifndef P_32_COPY
+#define P_32_COPY(a, b) { \
+ ((char *)&(b))[0] = ((char *)&(a))[3]; \
+ ((char *)&(b))[1] = ((char *)&(a))[2]; \
+ ((char *)&(b))[2] = ((char *)&(a))[1]; \
+ ((char *)&(b))[3] = ((char *)&(a))[0]; \
+}
+#endif
+/*
+ * Little endian <==> big endian 16-bit swap macros.
+ * M_16_SWAP swap a memory location
+ * P_16_SWAP swap a referenced memory location
+ * P_16_COPY swap from one location to another
+ */
+#ifndef M_16_SWAP
+#define M_16_SWAP(a) { \
+ uint16 _tmp = a; \
+ ((char *)&a)[0] = ((char *)&_tmp)[1]; \
+ ((char *)&a)[1] = ((char *)&_tmp)[0]; \
+}
+#endif
+#ifndef P_16_SWAP
+#define P_16_SWAP(a) { \
+ uint16 _tmp = *(uint16 *)a; \
+ ((char *)a)[0] = ((char *)&_tmp)[1]; \
+ ((char *)a)[1] = ((char *)&_tmp)[0]; \
+}
+#endif
+#ifndef P_16_COPY
+#define P_16_COPY(a, b) { \
+ ((char *)&(b))[0] = ((char *)&(a))[1]; \
+ ((char *)&(b))[1] = ((char *)&(a))[0]; \
+}
+#endif
+
+#endif /* __nsdb_h */
diff --git a/include/libaccess/nsdberr.h b/include/libaccess/nsdberr.h
new file mode 100644
index 00000000..224bd483
--- /dev/null
+++ b/include/libaccess/nsdberr.h
@@ -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 **/
+#ifndef __nsdberr_h
+#define __nsdberr_h
+
+/* NSDB facility name (defined in nsdb,c) */
+extern char * NSDB_Program;
+
+/* Define error identifiers for NSDB facility */
+
+/* Errors generated in nsdb.c */
+
+/* ndbFindName() */
+#define NSDBERR1000 1000 /* primary DB get operation failed */
+
+/* ndbIdToName() */
+#define NSDBERR1100 1100 /* id-to-name DB get operation failed */
+
+/* ndbInitPrimary() */
+#define NSDBERR1200 1200 /* primary database already exists */
+#define NSDBERR1220 1220 /* primary database open failed */
+#define NSDBERR1240 1240 /* primary DB put operation failed */
+#define NSDBERR1260 1260 /* primary DB put operation failed */
+
+/* ndbOpen() */
+#define NSDBERR1400 1400 /* insufficient dynamic memory */
+#define NSDBERR1420 1420 /* insufficient dynamic memory */
+#define NSDBERR1440 1440 /* insufficient dynamic memory */
+#define NSDBERR1460 1460 /* primary DB get metadata operation failed */
+#define NSDBERR1480 1480 /* metadata format error */
+#define NSDBERR1500 1500 /* unsupported database version number */
+#define NSDBERR1520 1520 /* wrong database type */
+
+/* ndbReOpen() */
+#define NSDBERR1600 1600 /* create primary DB failed */
+#define NSDBERR1620 1620 /* open primary/write failed */
+#define NSDBERR1640 1640 /* open primary/read failed */
+#define NSDBERR1660 1660 /* create id-to-name DB failed */
+#define NSDBERR1680 1680 /* open id-to-name DB for write failed */
+#define NSDBERR1700 1700 /* open id-to-name DB for read failed */
+
+/* Define error ids generated in nsdbmgmt.c */
+
+/* ndbAllocId() */
+#define NSDBERR2000 2000 /* bad DB name key */
+#define NSDBERR2020 2020 /* metadata get operation failed */
+#define NSDBERR2040 2040 /* no space to grow DB id bitmap */
+#define NSDBERR2060 2060 /* no space to copy DB id bitmap */
+#define NSDBERR2080 2080 /* put bitmap to DB operation failed */
+#define NSDBERR2100 2100 /* put id-to-name operation failed */
+
+/* ndbDeleteName() */
+#define NSDBERR2200 2200 /* error deleting record */
+
+/* ndbFreeId() */
+#define NSDBERR2300 2300 /* invalid id value */
+#define NSDBERR2320 2320 /* error deleting id-to-name record */
+#define NSDBERR2340 2340 /* error reading id bitmap from primary DB */
+#define NSDBERR2360 2360 /* invalid id value */
+#define NSDBERR2380 2380 /* insufficient dynamic memory */
+#define NSDBERR2400 2400 /* error writing id bitmap back to DB */
+
+/* ndbRenameId() */
+#define NSDBERR2500 2500 /* invalid new key name string */
+#define NSDBERR2520 2520 /* get id record operation failed */
+#define NSDBERR2540 2540 /* put id record operation failed */
+
+/* ndbStoreName() */
+#define NSDBERR2700 2700 /* database put operation failed */
+
+/* Define error return codes */
+#define NDBERRNOMEM -1 /* insufficient dynamic memory */
+#define NDBERRNAME -2 /* invalid key name string */
+#define NDBERROPEN -3 /* database open error */
+#define NDBERRMDGET -4 /* database metadata get failed */
+#define NDBERRMDPUT -5 /* database metadata put failed */
+#define NDBERRIDPUT -6 /* id-to-name record put failed */
+#define NDBERRNMDEL -7 /* delete named record failed */
+#define NDBERRPINIT -8 /* error creating primary DB file */
+#define NDBERRGET -9 /* database get failed */
+#define NDBERREXIST -10 /* DB already exists */
+#define NDBERRMDFMT -11 /* invalid metadata format */
+#define NDBERRDBTYPE -12 /* wrong DB type */
+#define NDBERRBADID -13 /* invalid id value for name */
+#define NDBERRPUT -14 /* database put operation failed */
+#define NDBERRVERS -15 /* unsupported database version */
+#define NDBERRIDDEL -16 /* delete id-to-name record failed */
+
+#endif /* __nsdberr_h */
diff --git a/include/libaccess/nsdbmgmt.h b/include/libaccess/nsdbmgmt.h
new file mode 100644
index 00000000..2977e6a2
--- /dev/null
+++ b/include/libaccess/nsdbmgmt.h
@@ -0,0 +1,52 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __nsdbmgmt_h
+#define __nsdbmgmt_h
+
+/*
+ * Description (nsdbmgmt.h)
+ *
+ * The file describes the interface for managing information in
+ * a Netscape (server) database. A database is composed of
+ * two (libdbm) DB files. One of these (<dbname>.db) contains
+ * records indexed by a string key. These records contain the
+ * primary information in the database. A second DB file
+ * (<dbname>.id) is used to map an integer id value to a string
+ * key, which can then be used to locate a record in the first file.
+ * The interface for retrieving information from a database is
+ * described in nsdb.h.
+ *
+ * FUTURE:
+ * Normally the records in the primary DB file will contain the
+ * id values which are used to key the id-to-name DB. When this
+ * is the case, it is possible to construct the id-to-name DB from
+ * the primary DB file, and an interface is provided to facilitate
+ * this.
+ */
+
+#include "nsdb.h" /* database access */
+
+/* Define flags for ndbStoreName() */
+#define NDBF_NEWNAME 0x1 /* this is (should be) a new name */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Functions for database management in nsdbmgmt.c */
+extern int ndbAllocId(NSErr_t * errp, void * ndb,
+ int namelen, char * name, unsigned int * id);
+extern int ndbDeleteName(NSErr_t * errp,
+ void * ndb, int flags, int namelen, char * name);
+extern int ndbFreeId(NSErr_t * errp,
+ void * ndb, int namelen, char * name, unsigned int id);
+extern int ndbRenameId(NSErr_t * errp, void * ndb,
+ int namelen, char * newname, unsigned int id);
+extern int ndbStoreName(NSErr_t * errp, void * ndb, int flags,
+ int namelen, char * name, int reclen, char * recptr);
+extern int ndbSync(NSErr_t * errp, void * ndb, int flags);
+
+NSPR_END_EXTERN_C
+
+#endif /* __nsdbmgmt_h */
diff --git a/include/libaccess/nserror.h b/include/libaccess/nserror.h
new file mode 100644
index 00000000..2a28c4f9
--- /dev/null
+++ b/include/libaccess/nserror.h
@@ -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 **/
+#ifndef __nserror_h
+#define __nserror_h
+
+#ifndef NOINTNSACL
+#define INTNSACL
+#endif /* !NOINTNSACL */
+
+/*
+ * Description (nserror.h)
+ *
+ * This file describes the interface to an error handling mechanism
+ * that is intended for general use. This mechanism uses a data
+ * structure known as an "error frame" to capture information about
+ * an error. Multiple error frames are used in nested function calls
+ * to capture the interpretation of an error at the different levels
+ * of a nested call.
+ */
+
+#include <stdarg.h>
+#include <prtypes.h>
+#include "public/nsacl/nserrdef.h"
+
+#ifdef INTNSACL
+
+NSPR_BEGIN_EXTERN_C
+
+/* Functions in nseframe.c */
+extern void nserrDispose(NSErr_t * errp);
+extern NSEFrame_t * nserrFAlloc(NSErr_t * errp);
+extern void nserrFFree(NSErr_t * errp, NSEFrame_t * efp);
+extern NSEFrame_t * nserrGenerate(NSErr_t * errp, long retcode, long errorid,
+ char * program, int errc, ...);
+
+/* Functions in nserrmsg.c */
+extern char * nserrMessage(NSEFrame_t * efp, int flags);
+extern char * nserrRetrieve(NSEFrame_t * efp, int flags);
+
+NSPR_END_EXTERN_C
+
+#endif /* INTNSACL */
+
+#endif /* __nserror_h */
diff --git a/include/libaccess/nsgmgmt.h b/include/libaccess/nsgmgmt.h
new file mode 100644
index 00000000..8fc59e12
--- /dev/null
+++ b/include/libaccess/nsgmgmt.h
@@ -0,0 +1,35 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __nsgmgmt_h
+#define __nsgmgmt_h
+
+/*
+ * Description (nsgmgmt.h)
+ *
+ * This file defines the interface to group management facilities
+ * implemented using a Netscape group database. This interface
+ * provides functions for adding, modifying, and removing group
+ * entries in the database, using the group object (GroupObj_t)
+ * structure to convey information across the interface.
+ */
+
+#define __PRIVATE_NSGROUP
+#include "nsgroup.h" /* group object access */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Group information management operations in nsgmgmt.c */
+extern NSAPI_PUBLIC int groupAddMember(GroupObj_t * goptr, int isgid, USI_t id);
+extern NSAPI_PUBLIC GroupObj_t * groupCreate(NTS_t name, NTS_t desc);
+extern NSAPI_PUBLIC int groupDeleteMember(GroupObj_t * goptr, int isgid, USI_t id);
+extern NSAPI_PUBLIC int groupEncode(GroupObj_t * goptr, int * ureclen, ATR_t * urecptr);
+extern NSAPI_PUBLIC int groupRemove(NSErr_t * errp, void * groupdb, int flags, NTS_t name);
+extern NSAPI_PUBLIC int groupStore(NSErr_t * errp,
+ void * groupdb, int flags, GroupObj_t * goptr);
+
+NSPR_END_EXTERN_C
+
+#endif /* __nsgmgmt_h */
diff --git a/include/libaccess/nsgroup.h b/include/libaccess/nsgroup.h
new file mode 100644
index 00000000..8f4bf56a
--- /dev/null
+++ b/include/libaccess/nsgroup.h
@@ -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 **/
+#ifndef __nsgroup_h
+#define __nsgroup_h
+
+/*
+ * Description (nsgroup.h)
+ *
+ * This file describes the interface to group information stored in
+ * a Netscape group database. Information about a group is provided
+ * to the caller in the form of a group object (GroupObj_t), defined
+ * in nsauth.h. This interface provides only read access to group
+ * information. The interface for managing the group database is
+ * described in nsgmgmt.h.
+ */
+
+#include "nserror.h" /* error frame list support */
+#include "nsautherr.h" /* authentication error codes */
+#include "nsauth.h" /* authentication types */
+
+/* Begin private definitions */
+#ifdef __PRIVATE_NSGROUP
+
+#include "nsdb.h"
+
+/*
+ * Define structure used to communicate between groupEnumerate() and
+ * groupEnumHelp().
+ */
+
+typedef struct GroupEnumArgs_s GroupEnumArgs_t;
+struct GroupEnumArgs_s {
+ void * groupdb; /* group database handle */
+ int flags; /* groupEnumerate() flags */
+ int (*func)(NSErr_t * ferrp, void * parg,
+ GroupObj_t * goptr); /* user function pointer */
+ void * user; /* user's argp pointer */
+};
+
+/* Define attribute tags for group DB records */
+#define GAT_GID 0x50 /* group id (USI) */
+#define GAT_FLAGS 0x51 /* flags (USI) */
+#define GAT_DESCRIPT 0x52 /* group description (NTS) */
+#define GAT_USERS 0x53 /* list of users (USI...) */
+#define GAT_GROUPS 0x54 /* list of groups (USI...) */
+#define GAT_PGROUPS 0x55 /* list of paret groups (USI...) */
+
+#endif /* __PRIVATE_NSGROUP */
+
+/* Begin public definitions */
+
+/* Define flags for groupEnumerate() */
+#define GOF_ENUMKEEP 0x1 /* don't free group objects */
+
+NSPR_BEGIN_EXTERN_C
+
+ /* Operations on a group object (see nsgroup.c) */
+extern NSAPI_PUBLIC GroupObj_t * groupDecode(NTS_t name, int ureclen, ATR_t urecptr);
+extern NSAPI_PUBLIC int groupEnumerate(NSErr_t * errp,
+ void * groupdb, int flags, void * argp,
+ int (*func)(NSErr_t * ferrp,
+ void * parg, GroupObj_t * goptr));
+extern NSAPI_PUBLIC GroupObj_t * groupFindByName(NSErr_t * errp,
+ void * groupdb, NTS_t name);
+extern NSAPI_PUBLIC GroupObj_t * groupFindByGid(NSErr_t * errp, void * groupdb, USI_t gid);
+extern NSAPI_PUBLIC void groupFree(GroupObj_t * goptr);
+
+NSPR_END_EXTERN_C
+
+#endif /* __nsgroup_h */
diff --git a/include/libaccess/nslock.h b/include/libaccess/nslock.h
new file mode 100644
index 00000000..af205863
--- /dev/null
+++ b/include/libaccess/nslock.h
@@ -0,0 +1,74 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __nslock_h
+#define __nslock_h
+
+/*
+ * Description (nslock.h)
+ *
+ * This file defines to interface for a locking facility that
+ * provides exclusive access to a resource across multiple
+ * server processes.
+ */
+
+#include "nserror.h"
+#include "base/crit.h"
+
+#ifdef __PRIVATE_NSLOCK
+
+/*
+ * Description (NSLock_t)
+ *
+ * This type represents a lock. It includes a name which
+ * uniquely identifies the lock, and a handle for referencing
+ * the lock once it has been initialized.
+ */
+
+typedef struct NSLock_s NSLock_t;
+struct NSLock_s {
+ NSLock_t * nl_next; /* next lock on NSLock_List */
+ char * nl_name; /* name associate with lock */
+#if defined(FILE_UNIX)
+ CRITICAL nl_crit; /* critical section for threads */
+ SYS_FILE nl_fd; /* file descriptor */
+ int nl_cnt; /* nsLockAcquire() count */
+#elif defined(XP_WIN32)
+#else
+#error "nslock.h needs work for this platform"
+#endif
+};
+
+#endif /* __PRIVATE_NSLOCK */
+
+/* Define error identifiers */
+
+/* nsLockOpen() */
+#define NSLERR1000 1000 /* insufficient dynamic memory */
+#define NSLERR1020 1020 /* error creating lock */
+#define NSLERR1040 1040 /* error accessing lock */
+
+/* nsLockAcquire() */
+#define NSLERR1100 1100 /* error acquiring lock */
+
+/* Define error return codes */
+
+#define NSLERRNOMEM -1 /* insufficient dynamic memory */
+#define NSLERRCREATE -2 /* error creating lock */
+#define NSLERROPEN -3 /* error accessing lock */
+#define NSLERRLOCK -4 /* error acquiring lock */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Functions in nslock.c */
+extern NSAPI_PUBLIC int nsLockOpen(NSErr_t * errp,
+ char * lockname, void **plock);
+extern NSAPI_PUBLIC int nsLockAcquire(NSErr_t * errp, void * lock);
+extern NSAPI_PUBLIC void nsLockRelease(void * lock);
+extern NSAPI_PUBLIC void nsLockClose(void * lock);
+
+NSPR_END_EXTERN_C
+
+#endif __nslock_h
diff --git a/include/libaccess/nsumgmt.h b/include/libaccess/nsumgmt.h
new file mode 100644
index 00000000..6d295a85
--- /dev/null
+++ b/include/libaccess/nsumgmt.h
@@ -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 **/
+#ifndef __nsumgmt_h
+#define __nsumgmt_h
+
+/*
+ * Description (nsumgmt.h)
+ *
+ * This file defines the interface to user management facilities
+ * implemented using a Netscape user database. This interface
+ * provides functions for adding, modifying, and removing user
+ * entries in the database, using the user object (UserObj_t)
+ * structure to convey information across the interface.
+ */
+
+#include "nsuser.h" /* user object access */
+
+NSPR_BEGIN_EXTERN_C
+
+/* User information management operations in nsumgmt.c */
+extern int userAddGroup(UserObj_t * uoptr, USI_t gid);
+extern NSAPI_PUBLIC UserObj_t * userCreate(NTS_t name, NTS_t pwd, NTS_t rname);
+extern int userDeleteGroup(UserObj_t * uoptr, USI_t gid);
+extern int userEncode(UserObj_t * uoptr, int * ureclen, ATR_t * urecptr);
+extern NSAPI_PUBLIC int userRemove(NSErr_t * errp, void * userdb, int flags, NTS_t name);
+extern NSAPI_PUBLIC int userRename(NSErr_t * errp,
+ void * userdb, UserObj_t * uoptr, NTS_t newname);
+extern NSAPI_PUBLIC int userStore(NSErr_t * errp,
+ void * userdb, int flags, UserObj_t * uoptr);
+
+NSPR_END_EXTERN_C
+
+#endif /* __nsumgmt_h */
diff --git a/include/libaccess/nsuser.h b/include/libaccess/nsuser.h
new file mode 100644
index 00000000..fbc51ba3
--- /dev/null
+++ b/include/libaccess/nsuser.h
@@ -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 **/
+#ifndef __nsuser_h
+#define __nsuser_h
+
+/*
+ * Description (nsuser.h)
+ *
+ * This file describes the interface to user information stored in
+ * a Netscape user database. Information about a user is provided
+ * to the caller in the form of a user object (UserObj_t), defined
+ * in nsauth.h. This interface provides only read access to user
+ * information. The interface for managing the user database is
+ * described in nsumgmt.h.
+ */
+
+#include "nserror.h" /* error frame list support */
+#include "nsautherr.h" /* authentication error codes */
+#include "nsauth.h" /* authentication types */
+
+/* Begin private definitions */
+#ifdef __PRIVATE_NSUSER
+
+#include "nsdb.h"
+
+/*
+ * Define structure used to communicate between userEnumerate() and
+ * userEnumHelp().
+ */
+
+typedef struct UserEnumArgs_s UserEnumArgs_t;
+struct UserEnumArgs_s {
+ void * userdb; /* user database handle */
+ int flags; /* userEnumerate() flags */
+ int (*func)(NSErr_t * ferrp, void * parg,
+ UserObj_t * uoptr); /* user function pointer */
+ void * user; /* user's argp pointer */
+};
+
+/* Define attribute tags for user DB records */
+#define UAT_PASSWORD 0x40 /* password (NTS) */
+#define UAT_UID 0x41 /* user id (USI) */
+#define UAT_ACCFLAGS 0x42 /* account flags (USI) */
+#define UAT_REALNAME 0x43 /* real name (NTS) */
+#define UAT_GROUPS 0x44 /* list of groups (USI...) */
+
+#endif /* __PRIVATE_NSUSER */
+
+/* Begin public definitions */
+
+/* Define flags for userEnumerate() */
+#define UOF_ENUMKEEP 0x1 /* don't free user objects */
+
+NSPR_BEGIN_EXTERN_C
+
+/* User information retrieval operations in nsuser.c */
+extern UserObj_t * userDecode(NTS_t name, int ureclen, ATR_t urecptr);
+extern int userEnumerate(NSErr_t * errp, void * userdb, int flags, void * argp,
+ int (*func)(NSErr_t * ferrp,
+ void * parg, UserObj_t * uoptr));
+extern UserObj_t * userFindByName(NSErr_t * errp, void * userdb, NTS_t name);
+extern UserObj_t * userFindByUid(NSErr_t * errp, void * userdb, USI_t uid);
+NSAPI_PUBLIC extern void userFree(UserObj_t * uoptr);
+
+NSPR_END_EXTERN_C
+
+#endif /* __nsuser_h */
diff --git a/include/libaccess/register.h b/include/libaccess/register.h
new file mode 100644
index 00000000..9b5837e4
--- /dev/null
+++ b/include/libaccess/register.h
@@ -0,0 +1,215 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef ACL_REGISTER_HEADER
+#define ACL_REGISTER_HEADER
+
+#include <prhash.h>
+
+#include <ldap.h>
+#include <base/pblock.h>
+#include <base/plist.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+
+typedef void * ACLMethod_t;
+#define ACL_METHOD_ANY (ACLMethod_t)-1
+#define ACL_METHOD_INVALID (ACLMethod_t)-2
+extern ACLMethod_t ACL_METHOD_BASIC;
+
+typedef void * ACLDbType_t;
+#define ACL_DBTYPE_ANY (ACLDbType_t)-1
+#define ACL_DBTYPE_INVALID (ACLDbType_t)-2
+extern ACLDbType_t ACL_ACL_DBTYPE_LDAP;
+
+typedef int (*AttrGetterFn)(NSErr_t *errp, PList_t subject, PList_t resource, PList_t auth_info, PList_t global_auth, void *arg);
+typedef int (*AclModuleInitFunc)(pblock *pb, Session *sn, Request *rq);
+typedef int (*DbParseFn_t)(NSErr_t *errp, ACLDbType_t dbtype,
+ const char *name, const char *url,
+ PList_t plist, void **db);
+typedef int (*AclCacheFlushFunc_t)(void);
+
+#ifdef __cplusplus
+typedef int (*LASEvalFunc_t)(NSErr_t*, char*, CmpOp_t, char*, int*, void**, PList_t, PList_t, PList_t, PList_t);
+typedef void (*LASFlushFunc_t)(void **);
+#else
+typedef int (*LASEvalFunc_t)();
+typedef void (*LASFlushFunc_t)();
+#endif
+
+/* We need to hide ACLGetter_t */
+typedef struct ACLGetter_s {
+ ACLMethod_t method;
+ ACLDbType_t db;
+ AttrGetterFn fn;
+ void *arg;
+} ACLGetter_t;
+typedef ACLGetter_t *ACLGetter_p;
+
+/*
+ * Command values for the "position" argument to ACL_RegisterGetter
+ * Any positive >0 value is the specific position in the list to insert
+ * the new function.
+ */
+#define ACL_AT_FRONT 0
+#define ACL_AT_END -1
+#define ACL_REPLACE_ALL -2
+#define ACL_REPLACE_MATCHING -3
+
+#ifdef ACL_LIB_INTERNAL
+#define ACL_MAX_METHOD 32
+#define ACL_MAX_DBTYPE 32
+#endif
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC extern int
+ ACL_LasRegister( NSErr_t *errp, char *attr_name, LASEvalFunc_t
+ eval_func, LASFlushFunc_t flush_func );
+NSAPI_PUBLIC extern int
+ ACL_LasFindEval( NSErr_t *errp, char *attr_name, LASEvalFunc_t
+ *eval_funcp );
+NSAPI_PUBLIC extern int
+ ACL_LasFindFlush( NSErr_t *errp, char *attr_name, LASFlushFunc_t
+ *flush_funcp );
+extern void
+ ACL_LasHashInit( void );
+extern void
+ ACL_LasHashDestroy( void );
+
+/*
+ * Revised, normalized method/dbtype registration routines
+ */
+NSAPI_PUBLIC extern int
+ ACL_MethodRegister(const char *name, ACLMethod_t *t);
+NSAPI_PUBLIC extern int
+ ACL_MethodIsEqual(const ACLMethod_t t1, const ACLMethod_t t2);
+NSAPI_PUBLIC extern int
+ ACL_MethodNameIsEqual(const ACLMethod_t t, const char *name);
+NSAPI_PUBLIC extern int
+ ACL_MethodFind(const char *name, ACLMethod_t *t);
+NSAPI_PUBLIC extern ACLMethod_t
+ ACL_MethodGetDefault();
+NSAPI_PUBLIC extern void
+ ACL_MethodSetDefault(const ACLMethod_t t);
+NSAPI_PUBLIC extern int
+ ACL_AuthInfoGetMethod(PList_t auth_info, ACLMethod_t *t);
+
+NSAPI_PUBLIC extern int
+ ACL_DbTypeRegister(const char *name, DbParseFn_t func, ACLDbType_t *t);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeIsEqual(const ACLDbType_t t1, const ACLDbType_t t2);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeNameIsEqual(const ACLDbType_t t, const char *name);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeFind(const char *name, ACLDbType_t *t);
+NSAPI_PUBLIC extern const ACLDbType_t
+ ACL_DbTypeGetDefault();
+NSAPI_PUBLIC extern void
+ ACL_DbTypeSetDefault(ACLDbType_t t);
+NSAPI_PUBLIC extern int
+ ACL_AuthInfoGetDbType(PList_t auth_info, ACLDbType_t *t);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeIsRegistered(const ACLDbType_t dbtype);
+NSAPI_PUBLIC extern DbParseFn_t
+ ACL_DbTypeParseFn(const ACLDbType_t dbtype);
+
+NSAPI_PUBLIC extern int
+ ACL_AttrGetterRegister(const char *attr, AttrGetterFn fn, ACLMethod_t m,
+ ACLDbType_t d, int position, void *arg);
+typedef ACLGetter_t *AttrGetterList; /* TEMPORARY */
+NSAPI_PUBLIC extern int
+ ACL_AttrGetterFind(PList_t auth_info, const char *attr,
+ AttrGetterList *getters);
+
+NSPR_END_EXTERN_C
+
+
+/* LAS return codes - Must all be negative numbers */
+#define LAS_EVAL_TRUE -1
+#define LAS_EVAL_FALSE -2
+#define LAS_EVAL_DECLINE -3
+#define LAS_EVAL_FAIL -4
+#define LAS_EVAL_INVALID -5
+#define LAS_EVAL_NEED_MORE_INFO -6
+
+#define ACL_ATTR_GROUP "group"
+#define ACL_ATTR_RAW_USER_LOGIN "user-login"
+#define ACL_ATTR_AUTH_USER "auth-user"
+#define ACL_ATTR_AUTH_TYPE "auth-type"
+#define ACL_ATTR_AUTH_DB "auth-db"
+#define ACL_ATTR_AUTH_PASSWORD "auth-password"
+#define ACL_ATTR_USER "user"
+#define ACL_ATTR_PASSWORD "pw"
+#define ACL_ATTR_USERDN "userdn"
+#define ACL_ATTR_RAW_USER "raw-user"
+#define ACL_ATTR_RAW_PASSWORD "raw-pw"
+#define ACL_ATTR_USER_ISMEMBER "user-ismember"
+#define ACL_ATTR_DATABASE "database"
+#define ACL_ATTR_DBTYPE "dbtype"
+#define ACL_ATTR_DBNAME "dbname"
+#define ACL_ATTR_DATABASE_URL "url"
+#define ACL_ATTR_METHOD "method"
+#define ACL_ATTR_AUTHTYPE "authtype"
+#define ACL_ATTR_AUTHORIZATION "authorization"
+#define ACL_ATTR_PARSEFN "parsefn"
+#define ACL_ATTR_ATTRIBUTE "attr"
+#define ACL_ATTR_GETTERFN "getterfunc"
+#define ACL_ATTR_IP "ip"
+#define ACL_ATTR_DNS "dns"
+#define ACL_ATTR_MODULE "module"
+#define ACL_ATTR_MODULEFUNC "func"
+#define ACL_ATTR_GROUPS "groups"
+#define ACL_ATTR_IS_VALID_PASSWORD "isvalid-password"
+#define ACL_ATTR_CERT2USER "cert2user"
+#define ACL_ATTR_USER_CERT "cert"
+#define ACL_ATTR_PROMPT "prompt"
+#define ACL_ATTR_TIME "time"
+#define ACL_ATTR_USERS_GROUP "users-group"
+
+#define ACL_DBTYPE_LDAP "ldap"
+
+#define METHOD_DEFAULT "default"
+
+typedef PRHashTable AttrGetterTable_t;
+
+typedef struct {
+ char *method;
+ char *authtype;
+ char *dbtype;
+ AttrGetterTable_t *attrGetters;
+} MethodInfo_t;
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC int ACL_FindMethod (NSErr_t *errp, const char *method, MethodInfo_t **method_info_handle);
+NSAPI_PUBLIC int ACL_RegisterModule (NSErr_t *errp, const char *moduleName, AclModuleInitFunc func);
+NSAPI_PUBLIC int ACL_RegisterMethod (NSErr_t *errp, const char *method, const char *authtype, const char *dbtype, MethodInfo_t **method_info_handle);
+NSAPI_PUBLIC int ACL_RegisterAttrGetter (NSErr_t *errp, MethodInfo_t *method_info_handle, const char *attr, AttrGetterFn func);
+NSAPI_PUBLIC int ACL_UseAttrGettersFromMethod (NSErr_t *errp, const char *method, const char *usefrom);
+NSAPI_PUBLIC int ACL_GetAttribute(NSErr_t *errp, const char *attr, void **val, PList_t subject, PList_t resource, PList_t auth_info, PList_t global_auth);
+NSAPI_PUBLIC int ACL_FindAttrGetter (NSErr_t *errp, const char *method, const char *attr, AttrGetterFn *func);
+NSAPI_PUBLIC int ACL_CallAttrGetter (NSErr_t *errp, const char *method, const char *attr, PList_t subject, PList_t resource, PList_t auth_info, PList_t global_auth);
+NSAPI_PUBLIC int ACL_RegisterDbType(NSErr_t *errp, const char *dbtype, DbParseFn_t func);
+NSAPI_PUBLIC int ACL_RegisterDbName(NSErr_t *errp, ACLDbType_t dbtype, const char *dbname, const char *url, PList_t plist);
+NSAPI_PUBLIC int ACL_RegisterDbFromACL(NSErr_t *errp, const char *url, ACLDbType_t *dbtype);
+NSAPI_PUBLIC int ACL_DatabaseFind(NSErr_t *errp, const char *dbname,
+ ACLDbType_t *dbtype, void **db);
+NSAPI_PUBLIC int ACL_SetDefaultDatabase (NSErr_t *errp, const char *dbname);
+NSAPI_PUBLIC int ACL_SetDefaultMethod (NSErr_t *errp, const char *method);
+NSAPI_PUBLIC const char *ACL_DbnameGetDefault (NSErr_t *errp);
+NSAPI_PUBLIC int ACL_LDAPDatabaseHandle (NSErr_t *errp, const char *dbname, LDAP **ld);
+NSAPI_PUBLIC int ACL_AuthInfoGetDbname (NSErr_t *errp, PList_t auth_info, char **dbname);
+NSAPI_PUBLIC int ACL_CacheFlushRegister(AclCacheFlushFunc_t func);
+
+NSPR_END_EXTERN_C
+
+struct program_groups {
+ char **groups;
+ char **programs;
+};
+
+#endif
diff --git a/include/libaccess/stubs.h b/include/libaccess/stubs.h
new file mode 100644
index 00000000..8efa0923
--- /dev/null
+++ b/include/libaccess/stubs.h
@@ -0,0 +1,6 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+typedef void PropList_t;
diff --git a/include/libaccess/symbols.h b/include/libaccess/symbols.h
new file mode 100644
index 00000000..c711f351
--- /dev/null
+++ b/include/libaccess/symbols.h
@@ -0,0 +1,99 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __symbols_h
+#define __symbols_h
+
+/*
+ * Description (symbols.h)
+ *
+ * This file describes the interface to an ACL symbol table
+ * implementation. The symbol table provides for storing symbols
+ * keyed by name and type, creating a separate name space for
+ * each symbol type.
+ */
+
+#ifdef __PRIVATE_SYMBOLS
+
+#include "plhash.h"
+#include "base/crit.h"
+
+/*
+ * Description (SymTable_t)
+ *
+ * This type describes a symbols table. It contains a pointer to
+ * an NSPR hash table and a pointer to a monitor. The monitor is
+ * needed even for read access to the symbol table because NSPR
+ * modifies the list for a hash bucket when a name is looked up.
+ */
+
+typedef struct SymTable_s SymTable_t;
+struct SymTable_s {
+ CRITICAL stb_crit; /* monitor pointer */
+ PLHashTable * stb_ht; /* hash table pointer */
+};
+
+
+/* Private functions defined in symbols.c */
+/*
+static PLHashEntry * symAllocEntry(void * pool, const void *unused);
+static void * symAllocTable(void * pool, PRSize size);
+static int symCmpName(const void * name1, const void * name2);
+static int symCmpValue(const void * value1, const void * value2);
+static PLHashNumber symHash(const void * symkey);
+static void symFreeEntry(void * pool, PLHashEntry * he, PRUintn flag);
+static void symFreeTable(void * pool, void * item);
+*/
+#endif /* __PRIVATE_SYMBOLS */
+
+/*
+ * Description (Symbol_t)
+ *
+ * This type describes a symbol table entry. A symbol is
+ * identified by the combination of its name and type. This
+ * structure is normally embedded in a structure for a particular
+ * symbol type, which will contain the symbol "value" information
+ * as well.
+ */
+
+typedef struct Symbol_s Symbol_t;
+struct Symbol_s {
+ char * sym_name; /* pointer to symbol name string */
+ int sym_type; /* symbol type */
+ void *sym_data; /* symbol data storage */
+};
+
+/* Define error return codes */
+#define SYMERRNOMEM -1 /* insufficient dynamic memory */
+#define SYMERRDUPSYM -2 /* duplicate symbol name and type */
+#define SYMERRNOSYM -3 /* symbol name and type not found */
+
+/* Define return flags for symTableEnumerate() func() */
+#define SYMENUMSTOP 0x1 /* terminate enumeration */
+#define SYMENUMREMOVE 0x2 /* remove entry from symbol table */
+
+NSPR_BEGIN_EXTERN_C
+
+/* Public functions defined in symbols.c */
+extern int symTableAddSym(void * table, Symbol_t * newsym, void * symref);
+extern void symTableRemoveSym(void * table, Symbol_t * sym);
+extern void symTableDestroy(void * table, int flags);
+
+/* for ANSI C++ on SCO UDK, otherwise fn name is managled */
+#ifdef UnixWare
+typedef int (*ArgFn_symTableEnum)(Symbol_t * sym, void * parg);
+extern void symTableEnumerate(void * table, void * argp, ArgFn_symTableEnum);
+#else /* UnixWare */
+extern void symTableEnumerate(void * table, void * argp,
+ int (*func)(Symbol_t * sym, void * parg));
+#endif /* UnixWare */
+
+extern int symTableFindSym(void * table, char * symname,
+ int symtype, void **psymref);
+extern int symTableNew(void **ptable);
+
+NSPR_END_EXTERN_C
+
+#endif /* __symbols_h */
diff --git a/include/libaccess/userauth.h b/include/libaccess/userauth.h
new file mode 100644
index 00000000..84bf4d8a
--- /dev/null
+++ b/include/libaccess/userauth.h
@@ -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 **/
+#ifndef USERAUTH_H
+#define USERAUTH_H
+
+NSPR_BEGIN_EXTERN_C
+
+
+NSPR_END_EXTERN_C
+#endif
diff --git a/include/libaccess/usi.h b/include/libaccess/usi.h
new file mode 100644
index 00000000..7cbe7371
--- /dev/null
+++ b/include/libaccess/usi.h
@@ -0,0 +1,81 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __usi_h
+#define __usi_h
+
+/*
+ * Description (usi.h)
+ *
+ * This file defines the interface to an unsigned integer datatype.
+ * Unsigned integers are used to represent object identifiers of
+ * various sorts, including user ids and group ids. Functions
+ * for manipulating lists of USIs are also provided in this
+ * interface.
+ */
+
+/* Define a type to contain an unsigned integer value */
+typedef unsigned int USI_t;
+
+/* Define a type to describe a list of USI_t values */
+typedef struct USIList_s USIList_t;
+struct USIList_s {
+ int uil_count; /* number of active values in list */
+ int uil_size; /* current size of list area in USI_t */
+ USI_t * uil_list; /* pointer to array of values */
+};
+
+/* Define macro to initialize a USIList_t structure */
+#define UILINIT(uilptr) \
+ { \
+ (uilptr)->uil_count = 0; \
+ (uilptr)->uil_size = 0; \
+ (uilptr)->uil_list = 0; \
+ }
+
+/* Define a macro to replace the contents of one USIList_t with another's */
+#define UILREPLACE(dst, src) \
+ { \
+ if ((dst)->uil_size > 0) { \
+ FREE((dst)->uil_list); \
+ } \
+ (dst)->uil_count = (src)->uil_count; \
+ (dst)->uil_size = (src)->uil_size; \
+ (dst)->uil_list = (src)->uil_list; \
+ (src)->uil_count = 0; \
+ (src)->uil_size = 0; \
+ (src)->uil_list = 0; \
+ }
+
+/* Define a variation of UILINIT() that frees any allocated space */
+#define UILFREE(uilptr) \
+ { \
+ if ((uilptr)->uil_size > 0) { \
+ FREE((uilptr)->uil_list); \
+ } \
+ (uilptr)->uil_count = 0; \
+ (uilptr)->uil_size = 0; \
+ (uilptr)->uil_list = 0; \
+ }
+
+/* Define a macro to extract the current number of items in a USIList_t */
+#define UILCOUNT(uilptr) ((uilptr)->uil_count)
+
+/* Define a macro to return a pointer to the array of values */
+#define UILLIST(uilptr) ((uilptr)->uil_list)
+
+NSPR_BEGIN_EXTERN_C
+
+/* Define functions in usi.c */
+extern USI_t * usiAlloc(USIList_t * uilptr, int count);
+extern int usiInsert(USIList_t * uilptr, USI_t usi);
+extern int usiPresent(USIList_t * uilptr, USI_t usi);
+extern int usiRemove(USIList_t * uilptr, USI_t usi);
+extern int uilDuplicate(USIList_t * dstptr, USIList_t * srcptr);
+extern int uilMerge(USIList_t * dstptr, USIList_t * srcptr);
+
+NSPR_END_EXTERN_C
+
+#endif /* __usi_h */
diff --git a/include/libaccess/usrcache.h b/include/libaccess/usrcache.h
new file mode 100644
index 00000000..646d1fd9
--- /dev/null
+++ b/include/libaccess/usrcache.h
@@ -0,0 +1,104 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef ACL_USER_CACHE_H
+#define ACL_USER_CACHE_H
+
+#ifdef NSPR20
+#include <plhash.h>
+#else
+#include <nspr/prhash.h>
+#endif
+
+#include <sys/types.h>
+#include <time.h>
+/* Removed for new ns security integration
+#include <sec.h>
+*/
+#include <key.h>
+#include <cert.h>
+#include <prclist.h>
+
+typedef struct {
+ PRCList list; /* pointer to next & prev obj */
+ char *uid; /* unique within a database */
+ char *userdn; /* LDAP DN if using LDAP db */
+ char *passwd; /* password */
+ SECItem *derCert; /* raw certificate data */
+ char *group; /* group recently checked for membership */
+ time_t time; /* last time when the cache was validated */
+ PRHashTable *hashtable; /* hash table where this obj is being used */
+} UserCacheObj;
+
+NSPR_BEGIN_EXTERN_C
+
+/* Set the number of seconds the cache is valid */
+extern int acl_usr_cache_set_timeout (const int nsec);
+
+/* Is the cache enabled? */
+extern int acl_usr_cache_enabled();
+
+/* initialize user cache */
+extern int acl_usr_cache_init ();
+
+/* Creates a new user obj entry */
+extern int acl_usr_cache_insert (const char *uid, const char *dbname,
+ const char *dn, const char *passwd,
+ const char *group, const SECItem *derCert,
+ const time_t time);
+
+/* Add group to the user's cache obj. */
+extern int acl_usr_cache_set_group (const char *uid, const char *dbname,
+ const char *group, const time_t time);
+
+/* Add userdn to the user's cache obj. */
+extern int acl_usr_cache_set_userdn (const char *uid, const char *dbname,
+ const char *userdn, const time_t time);
+
+/* Returns LAS_EVAL_TRUE if the user's password matches -- also returns the dn */
+extern int acl_usr_cache_passwd_check (const char *uid, const char *dbname,
+ const char *passwd,
+ const time_t time, char **dn,
+ pool_handle_t *pool);
+
+/* Returns LAS_EVAL_TRUE if the user is a member of the group */
+extern int acl_usr_cache_group_check (const char *uid, const char *dbname,
+ const char *group, const time_t time);
+
+/* Returns LAS_EVAL_TRUE if the user is a member of the group */
+extern int acl_usr_cache_group_len_check (const char *uid, const char *dbname,
+ const char *group,
+ const int len,
+ const time_t time);
+
+/* Returns LAS_EVAL_TRUE if the user's cache is valid and has a group */
+extern int acl_usr_cache_get_group (const char *uid, const char *dbname,
+ const time_t time, char **group,
+ pool_handle_t *pool);
+
+/* Returns LAS_EVAL_TRUE if the user is a member of the group */
+extern int acl_usr_cache_userdn_check (const char *uid, const char *dbname,
+ const char *userdn, const time_t time);
+
+/* Returns LAS_EVAL_TRUE if the user's cache is valid and has userdn */
+extern int acl_usr_cache_get_userdn (const char *uid, const char *dbname,
+ const time_t time, char **userdn,
+ pool_handle_t *pool);
+
+/* Creates a new user obj entry for cert to user mapping */
+extern int acl_cert_cache_insert (void *cert, const char *dbname,
+ const char *uid, const char *dn,
+ const time_t time);
+
+/* Returns LAS_EVAL_TRUE if the user's cache is valid and returns uid */
+extern int acl_cert_cache_get_uid (void *cert, const char *dbname,
+ const time_t time, char **uid,
+ char **dn, pool_handle_t *pool);
+
+NSPR_END_EXTERN_C
+
+
+#endif /* ACL_USER_CACHE_H */
diff --git a/include/libadmin/dbtlibadmin.h b/include/libadmin/dbtlibadmin.h
new file mode 100644
index 00000000..aa828d71
--- /dev/null
+++ b/include/libadmin/dbtlibadmin.h
@@ -0,0 +1,20 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#define LIBRARY_NAME "libadmin"
+
+static char dbtlibadminid[] = "$DBT: libadmin referenced v1 $";
+
+#include "i18n.h"
+
+BEGIN_STR(libadmin)
+ ResDef( DBT_LibraryID_, -1, dbtlibadminid )/* extracted from dbtlibadmin.h*/
+ ResDef( DBT_help_, 1, " Help " )/*extracted from template.c*/
+ ResDef( DBT_ok_, 2, " OK " )/*extracted from template.c*/
+ ResDef( DBT_reset_, 3, " Reset " )/*extracted from template.c*/
+ ResDef( DBT_done_, 4, " Done " )/*extracted from template.c*/
+ ResDef( DBT_cancel_, 5, " Cancel " )/*extracted from template.c*/
+END_STR(libadmin)
diff --git a/include/libadmin/libadmin.h b/include/libadmin/libadmin.h
new file mode 100644
index 00000000..8fdd4fa2
--- /dev/null
+++ b/include/libadmin/libadmin.h
@@ -0,0 +1,1403 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * libadmin.h - All functions contained in libadmin.a
+ *
+ * All blame goes to Mike McCool
+ */
+
+#ifndef libadmin_h
+#define libadmin_h
+
+#include <stdio.h>
+#include <limits.h>
+
+#include "base/systems.h"
+#include "base/systhr.h"
+#include "base/util.h"
+
+#include "frame/objset.h"
+#include "frame/req.h"
+
+#ifdef XP_UNIX
+#include <unistd.h>
+#else /* XP_WIN32 */
+#include <winsock.h>
+#endif /* XP_WIN32 */
+
+#include "prinit.h"
+#include "prthread.h"
+#include "prlong.h"
+
+#define NSPR_INIT(Program) (PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 8))
+
+#undef howmany
+
+#define ADM_CONF "admin.conf"
+#define MAGNUS_CONF "magnus.conf"
+#define OBJ_DATABASE "obj.conf"
+#define MIME_TYPES "mime.types"
+#define NSADMIN_CONF "ns-admin.conf"
+#define CERT_LOG "cert.log"
+
+#define SERVER_KEY_NAME "Server-Key"
+#define SERVER_CERT_NAME "Server-Cert"
+
+#define DBPW_USER "admin"
+#define DB_BAD_INPUT_CHARS "<>\""
+#define AUTHDB_ACL_FAIL -1
+#define AUTHDB_ACL_ODD_ACL -2
+#define AUTHDB_ACL_NOT_FOUND -3
+
+#define ACLNAME_READ_COOKIE "formgen-READ-ACL"
+#define ACLNAME_WRITE_COOKIE "formgen-WRITE-ACL"
+
+#define USERNAME_KEYWORD "USERNAME"
+
+typedef struct authInfo_s authInfo_t;
+struct authInfo_s {
+ char *type;
+ char *db_path;
+ char *prompt;
+};
+
+/* Not defined in any nspr header file, why? */
+PRNetAddr *PR_CreateNetAddr(int PR_IpAddrNull, PRUint16 port);
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC char *get_ip_and_mask(char *candidate);
+NSAPI_PUBLIC int groupOrUser(char *dbname, char *name,
+ int *is_user, int *is_group);
+NSAPI_PUBLIC int is_readacl(char *name);
+NSAPI_PUBLIC int is_writeacl(char *name);
+NSAPI_PUBLIC char *get_acl_file(void); /* Full path to file used by server. */
+NSAPI_PUBLIC char *get_workacl_file(void); /* Full path to file updated by ACL forms. */
+NSAPI_PUBLIC int get_acl_names(char **readaclname,
+ char **writeaclname, char *dir);
+NSAPI_PUBLIC int get_acl_info(char *acl_file, char *acl_name,
+ void **acl_context, char ***hosts,
+ authInfo_t **authinfo,
+ char ***users, char ***userhosts,
+ int *fdefaultallow);
+NSAPI_PUBLIC int set_acl_info(char *acl_file, char *acl_name, int prefix,
+ void **pacl, char **rights,
+ char **hosts, authInfo_t *authinfo,
+ char **users, char **userhosts,
+ int fdefaultallow);
+NSAPI_PUBLIC int delete_acl_by_name(char *acl_file, char *acl_name);
+
+NSAPI_PUBLIC int str_flag_to_int(char *str_flag);
+NSAPI_PUBLIC int admin_is_ipaddr(char *p);
+NSAPI_PUBLIC void get_hostnames_and_ipaddrs(char **hosts,
+ char **hostnames, char **ipaddrs);
+NSAPI_PUBLIC void load_host_array(char ***hosts,
+ char *hostnames, char *ipaddrs);
+NSAPI_PUBLIC void load_users_array(char ***users,
+ char *usernames, char *groups);
+NSAPI_PUBLIC void get_users_and_groups(char **users, char **usernames,
+ char **groups, char *dbname);
+NSAPI_PUBLIC char * str_unquote(char * str);
+
+extern NSAPI_PUBLIC char *acl_read_rights[];
+extern NSAPI_PUBLIC char *acl_write_rights[];
+
+#ifdef USE_ADMSERV
+#define CONFDIR(x) get_conf_dir(x)
+#define ACLDIR(x) get_acl_dir(x)
+#define COMMDEST(x) get_commit_dest(x)
+#define SERVER_NAMES getenv("SERVER_NAMES")
+#define ADMCONFDIR getenv("ADMSERV_ROOT")
+#else
+#define ACLDIR(x) "../../httpacl/"
+#define CONFDIR(x) "../config/"
+#define ADMCONFDIR "../config/"
+#endif
+
+#ifdef XP_UNIX
+#define FILE_PATHSEP '/'
+#define OPEN_MODE "r"
+#define QUOTE ""
+#define CONVERT_TO_NATIVE_FS(Filename)
+#define CONVERT_TO_HTTP_FORMAT(Filename)
+#define WSACleanup()
+
+#undef GET_QUERY_STRING
+#define GET_QUERY_STRING() (getenv("QUERY_STRING"))
+#define NOT_ABSOLUTE_PATH(str) (str[0] != '/')
+#define CREATE_DIRECTORY(Directory)
+#define FILE_LOCK_PATH (get_flock_path())
+
+#else /* XP_WIN32 */
+#define verify_adm_dbm
+#define add_user_dbm
+#define find_user_dbm
+#define list_users_dbm
+#define modify_user_dbm
+#define remove_user_dbm
+#define dbm_open
+#define dbm_close
+#define dbm_store
+#define lstat stat
+#define popen _popen
+#define pclose _pclose
+
+#define CONVERT_TO_NATIVE_FS(Filename) \
+{ \
+ register char *s; \
+ if (Filename) \
+ for (s = Filename; *s; s++) \
+ if ( *s == '/') \
+ *s = '\\'; \
+}
+#define CONVERT_TO_HTTP_FORMAT(Filename) \
+{ \
+ register char *s; \
+ if (Filename) \
+ for (s = Filename; *s; s++) \
+ if ( *s == '\\') \
+ *s = '/'; \
+}
+#define FILE_PATHSEP '/'
+#define OPEN_MODE "r+b"
+#define QUOTE "\""
+
+
+#undef GET_QUERY_STRING
+#define GET_QUERY_STRING() (GetQueryNT())
+/* Defined in util.c */
+NSAPI_PUBLIC char *GetQueryNT(void);
+#define NOT_ABSOLUTE_PATH(str) \
+ ((str[0] != '/') && (str[0] != '\\') && (str[2] != '/') && (str[2] != '\\'))
+
+#define CREATE_DIRECTORY(Directory) CreateDirectory(Directory, NULL)
+#define FILE_LOCK_PATH (get_flock_path())
+
+#endif /* XP_WIN32 */
+
+
+/* error types */
+#define FILE_ERROR 0
+#define MEMORY_ERROR 1
+#define SYSTEM_ERROR 2
+#define INCORRECT_USAGE 3
+#define ELEM_MISSING 4
+#define REGISTRY_DATABASE_ERROR 5
+#define NETWORK_ERROR 6
+#define GENERAL_FAILURE 7
+#define WARNING 8
+
+/* The upper bound on error types */
+#define MAX_ERROR 9
+
+/* The default error type (in case something goes wrong */
+#define DEFAULT_ERROR 3
+
+/* The change types for admin logging */
+#define TO_MAGNUS "magnus.conf"
+#define TO_OBJCONF "obj.conf"
+#define TO_ACLFILE "generated.acl"
+#define TO_STATUS "status"
+#define TO_ADMIN "admserv"
+#define TO_USERDB "userdb"
+#define TO_SEC "security"
+#define TO_BACKUP "backup"
+#define TO_CACHE "cache"
+#define TO_BUCONF "bu.conf"
+#define TO_LDAP "ldap"
+
+/* The indexes for conf file backup purposes */
+#define BK_MAGNUS 0
+#define BK_OBJ 1
+#define BK_MIMETYPES 2
+#define BK_BU 3
+#define BK_ACLFILE 4
+
+/* The extension for backup files to use. Emacs weenies like "%s.~%d~" */
+/* But real vi men like this one */
+#define BACKUP_EXT "%s.v%d"
+/* Need also a way to identify the backup files when we're doing an ls */
+#define BACKUP_SHORT ".v"
+
+/* User database defines */
+#define IS_A_DBM 1
+#define IS_A_NCSA 2
+
+#define REMOVE_FROM_DB "-REMOVE_THIS_USER"
+#define DB_INC "inc"
+#define NCSA_EXT "pwf"
+
+/* We now use the client DB libs, so they're all '.db' with no second file. */
+#define DBM_EXT_1 "db"
+#define DBM_EXT_2 NULL
+
+/* Define the functions in a central place so that obj.conf viewer can get
+ * to them */
+#ifdef MCC_PROXY
+#define BASIC_NCSA_FN "proxy-auth"
+#define REQUIRE_AUTH_FN "require-proxy-auth"
+#define CHECK_ACL_FN "check-acl"
+#else
+#define BASIC_NCSA_FN "basic-ncsa"
+#define REQUIRE_AUTH_FN "require-auth"
+#define CHECK_ACL_FN "check-acl"
+#endif
+
+
+/* Frame window names. */
+#define INDEX_NAME "index"
+#define MESSAGE_NAME "msgs"
+#define TOP_NAME "tabs"
+#define BOTTOM_NAME "category"
+#define OPTIONS_NAME "options"
+#define CONTENT_NAME "content"
+#define COPY_NAME "copy"
+
+#define INFO_IDX_NAME "infowin"
+#define INFO_TOPIC_NAME "infotopic"
+#define HELP_WIN_OPTIONS "'resizable=1,width=500,height=500'"
+
+
+/* pblock types, either it's a ppath, or it's a name. */
+#define PB_NAME 1
+#define PB_PATH 2
+
+/* Resource types */
+#define NAME "name"
+#define FILE_OR_DIR "path"
+#define TEMPLATE "tmpl"
+#define WILDCARD "wild"
+
+/* A really big form line */
+#define BIG_LINE 1024
+
+/* Max size for a pathname */
+#ifndef PATH_MAX
+#define PATH_MAX 256
+#endif
+
+
+/* Boundary string for uploading / downloading config files. */
+#define CF_BOUNDARY "--Config_File_Boundary--"
+#define CF_NEWCONFIG "--NewConfigFile:"
+#define CF_MTIME "--LastMod:"
+#define CF_ERRSTR "--Error: "
+#define CFTRANS_BIN "bin/cftrans"
+#define CF_REMOTE_URL "#RemoteUrl "
+
+#define HTML_ERRCOLOR "#AA0000"
+
+#define MOCHA_NAME "JavaScript"
+
+/* Internationalization stuffs. If we define MSG_RETURN, then create a
+ * function which will return a string of the given identifier. If we
+ * define MSG_DBM, it creates a function you can call to create the DBM
+ * properly. Finally, if nothing else, it will create a mapping from
+ * the string's name to its proper ID number. */
+/* store_msg is in mkdbm.c, in the admin stuff */
+/* get_msg.c */
+NSAPI_PUBLIC char *get_msg(int msgid);
+NSAPI_PUBLIC void store_msg(int msgid, char *msg);
+
+#if defined(MSG_RETURN)
+#define BGN_MSG(arg) static char *(arg)(int i) { switch(i) {
+#define STR(name, id, msg) case (id): return(msg);
+#define END_MSG(arg) } return 0; }
+
+#elif defined(MSG_DBM)
+#define BGN_MSG(arg) void (arg)() {
+#define STR(name, id, msg) store_msg(id, msg);
+#define END_MSG(arg) }
+
+#else
+#define BGN_MSG(arg) enum {
+#define STR(name, id, msg) name=id,
+#define END_MSG(arg) arg=0 };
+#endif
+
+/* The files where the messages are kept. */
+#define LA_BASE 1000
+#define LA_BASE_END 1999
+#define LA_DBM_LOC "./la_msgs"
+
+#define HADM_BASE 2000
+#define HADM_BASE_END 5999
+#define HADM_DBM_LOC "./hadm_msgs"
+
+#include "la_msgs.i"
+#include "hadm_msgs.i"
+
+/* Initialize libadmin. Should be called by EVERY CGI. */
+/* util.c */
+NSAPI_PUBLIC int ADM_Init(void);
+
+/* Open a .html file to parse it. Returns a file ptr (simple fn, really) */
+/* error one doesn't call report_error so we lose the infinite loop prob */
+/* form_get.c */
+NSAPI_PUBLIC FILE *open_html_file(char *filename);
+NSAPI_PUBLIC FILE *open_error_file(char *filename);
+
+/* Same as open_html_file, but opens the html file from the specified */
+/* language subdirectory, if available, else from the default language */
+/* subdirectory. */
+/* form_get.c */
+NSAPI_PUBLIC FILE* open_html_file_lang(char* filename,char* language);
+
+/* Parse an HTML file and return it to the client. */
+/* form_get.c */
+NSAPI_PUBLIC void return_html_file(char *filename);
+
+/* Parse an HTML file, return it to the client, but don't set the referer */
+/* form_get.c */
+NSAPI_PUBLIC void return_html_noref(char *filename);
+
+/* Output an input of an arbitrary type. Not really that flexible. */
+/* form_get.c */
+NSAPI_PUBLIC void output_input(char *type, char *name, char *value, char *other);
+
+/* Get the next line from the file. Returns 0 when EOF is encountered. */
+/* form_get.c */
+NSAPI_PUBLIC int next_html_line(FILE *f, char *line);
+
+
+
+/* Get the referer from the config file */
+/* referer.c */
+NSAPI_PUBLIC char *get_referer(char **config);
+
+/* Set the referer and write out the config file */
+/* referer.c */
+NSAPI_PUBLIC void set_referer(char **config);
+
+/* Sets the referer to a script that's not you. If new_ref is an absolute ref,
+ * it will cat that with SERVER_URL; if it's not, it will replace the
+ * current script name with new_ref. */
+/* referer.c */
+NSAPI_PUBLIC void set_fake_referer(char *new_ref);
+
+/* Redirect the person to the Referer, or give a short error message */
+/* referer.c */
+NSAPI_PUBLIC void redirect_to_referer(char *addition);
+
+/* Opens the referer in the content window using JavaScript */
+/* referer.c */
+NSAPI_PUBLIC void js_open_referer(void);
+
+/* Redirect to the given script. Assumes that SCRIPT_NAME is set to a script */
+/* referer.c */
+NSAPI_PUBLIC void redirect_to_script(char *script);
+
+
+/* Filter a line using templates, and spit the results to stdout */
+/* template.c */
+NSAPI_PUBLIC int parse_line(char *line, char **input);
+
+/* Since everyone seems to be doing this independently, at least centralize
+ the code. Useful for onClicks and automatic help */
+NSAPI_PUBLIC char *helpJavaScript();
+NSAPI_PUBLIC char *helpJavaScriptForTopic( char *topic );
+
+/* Check to see if a directive the parser didn't know about is a given
+ * directive */
+/* template.c */
+NSAPI_PUBLIC int directive_is(char *target, char *directive);
+
+/* Export the pageheader because sec-icrt uses it --MLM */
+/* template.c */
+NSAPI_PUBLIC void pageheader(char **vars, char **config);
+
+
+/* Report an error. Takes 3 args: 1. Category of error
+ * 2. Some more specific category info (opt)
+ * 3. A short explanation of the error.
+ *
+ * report_warning: same thing except doesn't exit when done whining
+ */
+/* error.c */
+NSAPI_PUBLIC void output_alert(int type, char *info, char *details, int wait);
+NSAPI_PUBLIC void report_error(int type, char *info, char *details);
+NSAPI_PUBLIC void report_warning(int type, char *info, char *details);
+
+/* Read the administrative config from the server admin root */
+/* Mult adm gets a particular adm config (for multiple server config) */
+/* admconf.c */
+NSAPI_PUBLIC char **get_adm_config(void);
+NSAPI_PUBLIC char **get_mult_adm_config(int whichone);
+
+/* Write the administrative config back to the file */
+/* Mult adm saves a particular adm config (for multiple server config) */
+/* admconf.c */
+NSAPI_PUBLIC int write_adm_config(char **config);
+NSAPI_PUBLIC int write_mult_adm_config(int whichone, char **config);
+
+/* An additional level of abstraction for resource grabbing. Gets the current
+ * resource from the config set. */
+/* admconf.c */
+NSAPI_PUBLIC char *get_current_resource(char **config);
+
+/* Gets the string of the current resource type */
+/* admconf.c */
+NSAPI_PUBLIC char *get_current_typestr(char **config);
+
+/* Gets the pblock type of the current resource from the config set. */
+/* admconf.c */
+NSAPI_PUBLIC int get_current_restype(char **config);
+
+/* Sets the current resource given its type and its data. */
+/* admconf.c */
+NSAPI_PUBLIC void set_current_resource(char **config, char *nrestype, char *nres);
+
+
+/* Get the value of a particular variable in magnus.conf */
+/* get_num_mag_var: get only a particular server's value for it */
+/* magconf.c */
+NSAPI_PUBLIC char *get_mag_var(char *var);
+NSAPI_PUBLIC char *get_num_mag_var(int whichsrv, char *var);
+
+/* Set the value of a particular variable in magnus.conf */
+/* magconf.c */
+NSAPI_PUBLIC void set_mag_var(char *name, char *value);
+
+/* Get the value of a particular variable in cert.log */
+NSAPI_PUBLIC char *get_cert_var(char *var);
+NSAPI_PUBLIC char *get_num_cert_var(int whichsrv, char *var);
+
+/* Set the value of a particular variable in cert.log */
+NSAPI_PUBLIC void set_cert_var(char *name, char *value);
+
+/* Get the value of a particular variable in ns-admin.conf */
+/* admserv.c */
+NSAPI_PUBLIC char *get_nsadm_var(char *var);
+NSAPI_PUBLIC char **scan_server_instance(char *, char **);
+
+
+/* Set the value of a particular variable in ns-admin.conf */
+/* admserv.c */
+NSAPI_PUBLIC void set_nsadm_var(char *name, char *value);
+
+/* List all of the installed servers on the admin server. */
+/* Takes 1 arg (string list of identifiers for servers, such as */
+/* httpd, https, proxy, news) */
+/* admserv.c */
+NSAPI_PUBLIC char **list_installed_servers(char **namelist);
+
+/* Reads in the list of servers installed on this machine. Fills in
+ * two string lists (one of names, one of descriptions.) *servlist and
+ * *desclist will be allocated for you. */
+NSAPI_PUBLIC void read_server_lst(char ***namelist, char ***desclist);
+NSAPI_PUBLIC void read_keyalias_lst(char ***namelist);
+NSAPI_PUBLIC void read_certalias_lst(char ***namelist);
+NSAPI_PUBLIC void get_key_cert_files(char *alias, char **keyfile, char **certfile);
+NSAPI_PUBLIC void display_aliases(char *keyfile, char **aliaslist);
+
+/* Create a new object (i.e. empty "<Object name=foo></Object>" in the
+ * config files. */
+/* objconf.c */
+NSAPI_PUBLIC void add_object(int objtype, char *id);
+
+/* Destroy a given object and all its contents. */
+/* objconf.c */
+NSAPI_PUBLIC void delete_object(int objtype, char *id);
+
+/* Grab a given object */
+/* objconf.c */
+NSAPI_PUBLIC httpd_object *grab_object(int objtype, char *id);
+
+/* List all objects of the given type. */
+/* objconf.c */
+NSAPI_PUBLIC char **list_objects(int objtype);
+
+/* Count how many objects there are of the given type. */
+/* objconf.c */
+NSAPI_PUBLIC int count_objects(int objtype);
+
+/* Return the total number of objects in the configuration. */
+/* objconf.c */
+NSAPI_PUBLIC int total_object_count(void);
+
+/* Find a particular instance of a parameter in a particular object and a
+ * particular directive. id_type and id_value are optional parameter
+ * specifiers if you want not just the first instance of a function.
+ */
+/* objconf.c */
+NSAPI_PUBLIC pblock *grab_pblock(int objtype, char *object, char *directive,
+ char *function, char *id_type, char *id_value);
+
+/* Grab a pblock, but don't use the "fn" parameter. Instead of "fn",
+ * use the string "fname" to identify the block. */
+/* objconf.c */
+NSAPI_PUBLIC pblock *grab_pblock_byid(int objtype, char *object, char *directive,
+ char *fname, char *function, char *id_type,
+ char *id_value);
+
+/* Add a new parameter block into the given object, of the given directive
+ * type, using the given function, and with the list of parameters given
+ * (should be called like this:)
+ *
+ * add_pblock(PB_NAME, "default", "NameTrans", "pfx2dir",
+ * 4, "from", "/foo", "dir", "/bar");
+ * Returns the new pblock for posterity
+ */
+/* objconf.c */
+NSAPI_PUBLIC pblock *add_pblock(int objtype, char *object, char *directive, char *function,
+ int nargs, ...);
+
+/* Create a new pblock, but don't save it or anything. */
+/* objconf.c */
+NSAPI_PUBLIC pblock *new_pblock(char *function, int nargs, ...);
+
+/* Destroy a paramter block. Same call patterns as grab_pblock. */
+/* objconf.c */
+NSAPI_PUBLIC void delete_pblock(int objtype, char *object, char *directive, char *function,
+ char *id_type, char *id_value);
+
+/* Set the values of a given pblock to these new values. Arg passing is same
+ * as for add_pblock()
+ */
+/* objconf.c */
+NSAPI_PUBLIC void set_pblock_vals(pblock *pb, int nargs, ...);
+
+/* List all the pblocks you can find with the given object, directive, and
+ * function. Returns a pointer to a list of pblock *'s just like a strlist.
+ */
+/* objconf.c */
+NSAPI_PUBLIC pblock **list_pblocks(int objtype, char *object, char *direct, char *function);
+
+/* Get the client pblock from a given directive, specified as above in
+ * grab_pblock.
+ */
+/* objconf.c */
+NSAPI_PUBLIC pblock *grab_client(int objtype, char *object, char *directive,
+ char *function, char *id_type, char *id_value);
+
+/* Add a client pblock to a given object. If you have a pblock, send it
+ * in oldpb, if not, send NULL and it will create one with a
+ * "PathCheck fn=deny-existence" directive for you.
+ *
+ * Send the nargs just like above; assumedly there's only two: client and ip.
+ */
+/* objconf.c */
+NSAPI_PUBLIC void add_client(int objtype, char *object, char *direct,
+ pblock *oldpb, int nargs, ...);
+
+/* List all the clients you can find with the given object, directive, and
+ * function. Returns a pointer to a list of directive *'s (struct with
+ * two pblock ptrs: param and client)
+ */
+/* objconf.c */
+NSAPI_PUBLIC directive **list_clients(int objtype, char *object, char *direct,
+ char *function);
+
+/* Delete a client, as identified by directive, path=blah in param part,
+ * dns=blah in client part, and ip=blah in client part. */
+/* objconf.c */
+NSAPI_PUBLIC void delete_client(int objtype, char *object, char *direct, char *path,
+ char *dns, char *ip);
+
+/* Gets the directive associated with a given pblock. */
+/* objconf.c */
+NSAPI_PUBLIC directive *get_pb_directive(int objtype, char *object,
+ char *directive, pblock *pb);
+NSAPI_PUBLIC directive *get_cl_directive(int objtype, char *object,
+ char *directive, pblock *cl);
+
+/* Delete a pblock by its pointer. (Note: I should have done this function
+ * long ago. Grr. */
+/* objconf.c */
+NSAPI_PUBLIC void delete_pblock_byptr(int objtype, char *object,
+ char *directive, pblock *pb);
+
+/* Init directives are now in obj.conf, deal with them there. */
+/* ---------------------------------------------------------- */
+
+/* Get the value of an init variable in pblock form. */
+/* objconf.c */
+NSAPI_PUBLIC pblock *get_mag_init(char *fn);
+
+/* Get only a particular mag init */
+/* objconf.c */
+NSAPI_PUBLIC pblock *get_specific_mag_init(char *fn, char *name, char *value);
+
+/* Get all instances of the same Init function as an array of pblock ptrs */
+/* objconf.c */
+NSAPI_PUBLIC pblock **get_all_mag_inits(char *fn);
+
+/* Set the value of an init variable. If it exists, modify existing, if not,
+ * create it.
+ * If the key_nam and key_val are set, also the parameter named key_val
+ * will be used when matching against the specific directive. This will
+ * allow multiple calls to the same Init function, with a specific parameter
+ * value together with the function name uniquely identifying the specific
+ * Init function call.
+ */
+/* objconf.c */
+NSAPI_PUBLIC void set_mag_init(char *fn, char *key_nam, char *key_val, int nargs, ...);
+
+/* Delete an instance of an Init variable. */
+/* objconf.c */
+NSAPI_PUBLIC void delete_mag_init(char *fn);
+NSAPI_PUBLIC void delete_specific_mag_init(char *fn, char *key_nam, char *key_val);
+
+
+/* Commit all outstanding config stuff from admin directory to the actual
+ * server. Does not restart the server. */
+/* Argument authlist is a string list of authorization strings
+ * (username:password) to send to remote servers (or NULL if it is a
+ * local machine.) */
+/* commit.c */
+NSAPI_PUBLIC int do_commit(char **authlist);
+
+/* Back out from outstanding changes. Authlist same as above. */
+/* commit.c */
+NSAPI_PUBLIC int do_undo(char **authlist);
+
+/* Prints outstanding changes to server to stdout. */
+/* commit.c */
+NSAPI_PUBLIC void output_uncommitted(void);
+
+/* Returns a flag saying whether there are outstanding changes that need to
+ * be committed. If you've already read in admin.conf, send a pointer to
+ * it here. Or else send NULL, and it'll read it in. */
+/* commit.c */
+NSAPI_PUBLIC int needs_commit(char **config);
+
+/* Sets the flag to say whether we need to commit or not. 1 means "yes,
+ * we need to commit." 0 means "No, I just committed the changes."
+ * whichsrv is which server to set the bit in (if you're configuring
+ * multiple servers.) */
+/* commit.c */
+NSAPI_PUBLIC void set_commit(int whichsrv, int needscommit);
+
+/* Returns an int for which backup number to use. 0=magnus, 1=obj*/
+/* index is which server among the list you want to use (mult config) */
+/* commit.c */
+NSAPI_PUBLIC int get_bknum(int which, int index);
+
+/* Sets the current backup number. */
+/* index is which server among the list you want to use. */
+/* commit.c */
+NSAPI_PUBLIC void set_bknum(int num, int which, int index);
+
+/* Backs up given file, using number in admconf. */
+/* commit.c */
+NSAPI_PUBLIC void conf_backup(char *whichfile, int index, int whichsrv);
+
+/* Gets the last known modification time for a config file.
+ * When you do a commit, this is set to the mod time after you do
+ * the commit. Later, when you want to see if the file you're about
+ * to upload has changed, you check this value. */
+/* commit.c */
+NSAPI_PUBLIC time_t get_org_mtime(int whichsrv, int whichfile);
+
+/* Gets and sets the three modification times as they were stored in
+ * admin.conf. */
+/* Useful in remote transactions. */
+/* commit.c */
+NSAPI_PUBLIC char *get_mtime_str(int whichsrv);
+NSAPI_PUBLIC void set_mtime_str(int whichsrv, char *str);
+
+/* Sets that same value (see above) */
+/* commit.c */
+NSAPI_PUBLIC void set_org_mtime(int whichsrv, int whichfile, time_t mtime);
+
+/* Set the modification times for *all* of the files needing this check,
+ * assuming admin.conf got lost or hasn't been created yet. */
+/* When it doubt, set to zero. */
+NSAPI_PUBLIC void set_all_org_mtimes(void);
+
+
+/* Create an internal list of the servers which are being changed. */
+/* Returns the total number of servers in the list. */
+/* multconf.c */
+NSAPI_PUBLIC int make_conflist(void);
+
+/* Don't use this function. It's a grotesque hack. It's used by the admin
+ * page to fake the on/off buttons for the servers. */
+/* multconf.c */
+NSAPI_PUBLIC int fake_conflist(char *fakename);
+
+/* Get the current admin config directory. Takes an int to say which one
+ * (of the list of servers to configure) you're interested in, so you can
+ * for loop through them. Always use 0 if you want the first one. */
+/* multconf.c */
+NSAPI_PUBLIC char *get_conf_dir(int whichone);
+NSAPI_PUBLIC char *get_alias_dir(void);
+NSAPI_PUBLIC void read_alias_files(char ***aliasfiles);
+NSAPI_PUBLIC void read_aliases(char ***aliaslist);
+
+/* Return 1 if this server number whichone is a not on the local machine. */
+/* multconf.c */
+NSAPI_PUBLIC int is_remote_server(int whichone);
+
+/* Return 1 if we are configuring the admin server. */
+/* multconf.c */
+NSAPI_PUBLIC int is_admserv(void);
+
+/* Return 1 if there is a remote server in the list of servers to config. */
+/* Return 0 if not. */
+/* multconf.c */
+NSAPI_PUBLIC int remote_server_inlist(void);
+
+/* Get the ultimate destination for a particular config file set. Same
+ * arg as above function. */
+/* multconf.c */
+NSAPI_PUBLIC char *get_commit_dest(int whichone);
+
+/* Get the name of the indicated server (for logging purposes etc.) */
+/* Send -1 for a string with all of them. */
+/* multconf.c */
+NSAPI_PUBLIC char *get_srvname(int whichsrv);
+
+
+/* Some simple buffering tools */
+/* Keeps a buffer for network info, and a buffer for returning lines */
+/* httpcon.c */
+typedef struct bufstruct {
+ char *buf;
+ int bufsize;
+ int curpos;
+ int inbuf;
+ char *hbuf;
+ int hbufsize;
+ int hbufpos;
+} bufstruct;
+
+/* Make a new buffer. Flush the rest of a buffer (leaving the contents
+ * unread. Delete a buffer structure. */
+/* httpcon.c */
+NSAPI_PUBLIC bufstruct *new_buffer(int bufsize);
+NSAPI_PUBLIC void flush_buffer(bufstruct *buf);
+NSAPI_PUBLIC void delete_buffer(bufstruct *buf);
+
+/* stdio replacement for a network connection (so shoot me) */
+/* httpcon.c */
+NSAPI_PUBLIC char *get_line_from_fd(PRFileDesc *fd, bufstruct *buf);
+
+/* send a line to a remote server (equivalent to write()) */
+/* httpcon.c */
+NSAPI_PUBLIC int send_line_to_fd(PRFileDesc *fd, char *line, int linesize);
+
+/* Decompose a URL into protocol, server, port, and URI. You needn't allocate
+ * the strings you're passing, will be done for you. */
+/* httpcon.c */
+NSAPI_PUBLIC int decompose_url(char *url, char **protocol, char **server, unsigned int *port, char **uri);
+
+/* Take a status line "HTTP/1.0 200 OK" or some such and produce a protocol
+ * status number. */
+/* httpcon.c */
+NSAPI_PUBLIC int parse_status_line(char *statusline);
+
+/* Returns whether the headers have now ended (with the line you give it) */
+/* httpcon.c */
+NSAPI_PUBLIC int is_end_of_headers(char *hline);
+
+/* Make an HTTP request to a given server, running on a given port,
+ * with the given initial request. Returns a FD that can be used
+ * to read / write to the connection. */
+/* Note: Reports status to stdout in HTML form. Bad? Perhaps... */
+/* httpcon.c */
+NSAPI_PUBLIC PRFileDesc *make_http_request(char *protocol, char *server, unsigned int port, char *request, int *errcode);
+
+/* Terminate an HTTP request session (see above) */
+/* httpcon.c */
+NSAPI_PUBLIC void end_http_request(PRFileDesc *req_socket);
+
+/* Verify that given server is an admin server. */
+NSAPI_PUBLIC int verify_is_admin(char *protocol, char *server, int port);
+
+
+/* Log a change in the verbose admin log. kind is a string representing
+ * what kind of change it was (see #defines at top of file, such as MAGNUS_LOG)
+ * Change is the text of the change, in printf format (so you can give args). */
+/* admlog.c */
+NSAPI_PUBLIC void log_change(char *kind, char *change, ...);
+
+/* Get a pretty string for the current resource for logging. */
+/* admlog.c */
+NSAPI_PUBLIC char *log_curres(char **config);
+
+
+/* List all the user databases (actually, all files) in a given path into a
+ * strlist. */
+/* userdb.c */
+NSAPI_PUBLIC char **list_user_dbs(char *fullpath);
+
+NSAPI_PUBLIC char **list_auth_dbs(char *fullpath);
+
+/* Output the 1.x database selector. Path is the path to the DB's, element is
+ * the desired SELECT name, current is the one that should currently be
+ * selected. */
+/* userdb.c */
+NSAPI_PUBLIC void output_db_selector(char *path, char *element, char *current);
+
+/* Output the 2.x database selector. Path is the path to the DB's, element is
+ * the desired SELECT name, current is the one that should currently be
+ * selected. */
+NSAPI_PUBLIC void output_authdb_selector(char *path, char *element, char *current);
+
+/* Sets which DB is considered current. */
+/* userdb.c */
+NSAPI_PUBLIC void set_current_db(char *current); /* obsolete 1.x */
+
+/* Sets which DB is considered current (2.x version). */
+NSAPI_PUBLIC void set_current_authdb(char *current);
+NSAPI_PUBLIC char *get_current_authdb(void);
+
+/* Detect the type of the given database. */
+/* WARNING: REMOVES THE EXTENSION!!! */
+/* userdb.c */
+NSAPI_PUBLIC int detect_db_type(char *db_name);
+
+/* Find a user within an NCSA database, and return */
+/* userdb.c */
+NSAPI_PUBLIC char *find_user_ncsa(char *db, char *user);
+
+/* Add a user to an NCSA style database */
+/* userdb.c */
+NSAPI_PUBLIC void add_user_ncsa(char *db, char *user, char *password, int enc);
+
+/* List all the users in an NCSA style database */
+/* userdb.c */
+NSAPI_PUBLIC char **list_users_ncsa(char *db);
+
+/* Modify a user in an NCSA style database */
+/* userdb.c */
+NSAPI_PUBLIC int modify_user_ncsa(char *db, char *user, char *pw);
+
+/* Verify the admin password, or die. Returns 1 if there is one, 0 if not */
+/* userdb.c */
+NSAPI_PUBLIC int verify_adm_ncsa(char *db, char *pw);
+
+/* Remove a user from an NCSA style database */
+/* userdb.c */
+NSAPI_PUBLIC int remove_user_ncsa(char *db, char *user);
+
+#ifdef XP_UNIX /* WIN32 has no DBM */
+/* Find a user within a DBM database, and return */
+/* userdb.c */
+char *find_user_dbm(char *db, char *user);
+
+/* Add a user to a DBM database */
+/* userdb.c */
+void add_user_dbm(char *db, char *user, char *password, int enc);
+
+/* List all the users in a DBM */
+/* userdb.c */
+char **list_users_dbm(char *db);
+
+/* Modify a user in a DBM database */
+/* userdb.c */
+int modify_user_dbm(char *db, char *user, char *pw);
+
+/* Verify the admin password, or die. Returns 1 if there is one, 0 if not */
+/* userdb.c */
+int verify_adm_dbm(char *db, char *pw);
+
+/* Remove a user from a DBM */
+/* userdb.c */
+int remove_user_dbm(char *db, char *user);
+
+#endif /* WIN32 */
+
+
+/* Checks to see if server is running. Doesn't work over network. Returns 0
+ * if it's down, 1 if it's up, -1 if an error occurred. */
+/* pcontrol.c */
+NSAPI_PUBLIC int is_server_running(int whichsrv);
+
+/* Starts up the HTTP server. Puts the errors into /tmp/startup.[pid] */
+/* Returns 0 on success, 1 on failure */
+/* Restart restarts it, shutdown shuts it down */
+/* pcontrol.c */
+NSAPI_PUBLIC int startup_http(int, char*, char *);
+NSAPI_PUBLIC int restart_http(int, char*, char *);
+NSAPI_PUBLIC int shutdown_http(int, char*);
+
+/* As above, but for SNMP HTTP subagent */
+/* pcontrol.c */
+NSAPI_PUBLIC int startup_snmp();
+NSAPI_PUBLIC int restart_snmp();
+NSAPI_PUBLIC int shutdown_snmp();
+
+/* Performs the request rq, for server (in list) whichsrv, using auth as
+ * auth info.
+ *
+ * successmsg is the prefix on lines that are returned from the remote
+ * server that indicate success. */
+/* pcontrol.c */
+NSAPI_PUBLIC int perform_request(char *req, int whichsrv, char *auth, char *successmsg);
+
+/* Escapes a shell command for system() calls. NOTE: This string should
+ * be large enough to handle expansion!!!! */
+/* util.c */
+NSAPI_PUBLIC void escape_for_shell(char *cmd);
+
+/* Lists all files in a directory. If dashA list .files except . and .. */
+/* util.c */
+NSAPI_PUBLIC char **list_directory(char *path, int dashA);
+
+/* Does a given file exist? */
+/* util.c */
+NSAPI_PUBLIC int file_exists(char *filename);
+
+/* What's the size of a given file? */
+/* util.c */
+NSAPI_PUBLIC int get_file_size(char *path);
+
+/* Create a directory path if it does not exist (mkdir -p) */
+/* util.c */
+NSAPI_PUBLIC int ADM_mkdir_p(char *dir, int mode);
+
+/* Copy a directory recursively. */
+/* util.c */
+NSAPI_PUBLIC int ADM_copy_directory(char *src_dir, char *dest_dir);
+
+/* Remove a directory recursively. Same as remove_directory except that
+ filenames arent printed on stdout */
+/* util.c */
+NSAPI_PUBLIC void ADM_remove_directory(char *path);
+
+#ifdef XP_UNIX
+/* Obtain Unix SuiteSpot user/group information */
+/* util.c */
+NSAPI_PUBLIC int ADM_GetUXSSid(char *, char **, char **);
+#endif
+
+/* Return: LastModificationTime(f1) < LastModificationTime(f2) ? */
+/* util.c */
+NSAPI_PUBLIC int mtime_is_earlier(char *file1, char *file2);
+
+/* Return: the last mod time of fn */
+/* util.c */
+NSAPI_PUBLIC time_t get_mtime(char *fn);
+
+/* Does this string have all numbers? */
+/* util.c */
+NSAPI_PUBLIC int all_numbers(char *target);
+/* Valid floating point number? */
+NSAPI_PUBLIC int all_numbers_float(char *target);
+
+/* Get the [ServerRoot]/config directory. */
+/* whichone is which server you're interested in. */
+/* 0 if you want the first one.*/
+/* util.c */
+NSAPI_PUBLIC char *get_admcf_dir(int whichone);
+
+/* Get the admin server's [ServerRoot]/config directory */
+NSAPI_PUBLIC char *get_admservcf_dir(void);
+
+/* Get the admin/userdb directory. */
+/* util.c */
+NSAPI_PUBLIC char *get_userdb_dir(void);
+/* Get the V2.x admin/userdb directory. */
+/* util.c */
+NSAPI_PUBLIC char *get_authdb_dir(void);
+NSAPI_PUBLIC char *get_httpacl_dir(void);
+
+
+/* V2.x User admin functions. They take a full path of
+ the directory where the databases live, and perform
+ various operations on the databases. They open and
+ close the DBM, so they can not be called when the
+ database is already open. The output_xxx ones spit
+ out various HTMLized admin data.
+*/
+NSAPI_PUBLIC int getfullname(char *dbname, char *user, char **fullname);
+NSAPI_PUBLIC int setfullname(char *dbname, char *user, char *fullname);
+NSAPI_PUBLIC int setpw(char *dbname, char *user, char *pwd);
+NSAPI_PUBLIC int setdbpw(char *dbname, char *pwd);
+NSAPI_PUBLIC int checkdbpw(char *dbname, char *pwd);
+NSAPI_PUBLIC int addusertogroup(char *dbname, char *user, char *group);
+NSAPI_PUBLIC int remuserfromgroup(char *dbname, char *user, char *group);
+NSAPI_PUBLIC int addgrouptogroup(char *dbname, char *memgroup, char *group);
+NSAPI_PUBLIC int remgroupfromgroup(char *dbname, char *memgroup, char *group);
+NSAPI_PUBLIC int output_users_list(char *line, char *userfilter);
+NSAPI_PUBLIC int output_groups_list(char *dbname, char *groupfilter);
+NSAPI_PUBLIC void output_group_membership(char *dbname, char *user);
+NSAPI_PUBLIC void output_nonmembership(char *dbname, char *user);
+NSAPI_PUBLIC void output_grpgroup_membership(char *dbname, char *group, char *filter);
+NSAPI_PUBLIC void output_user_membership(char *dbname, char *group, char *filter);
+NSAPI_PUBLIC void output_nongrpgroup_membership(char *dbname, char *group, char *filter);
+NSAPI_PUBLIC void output_nonuser_membership(char *dbname, char *group, char *filter);
+
+/* Set a user's login name */
+NSAPI_PUBLIC int setusername(char *db_path, char *user, char *newname);
+
+/* Output a selector box with name "name", an option "NONE" if none=1,
+ * and make it a multiple selector box if multiple=1. If multiple != 1,
+ * then make it a pulldown list if the number of groups is less than
+ * SELECT_OVERFLOW. */
+/* If highlight is non-null, specifically highlight that entry. */
+/* If user is non-null, and it's a multiple box, correctly set the group
+ * membership in the multiple list (Groups they're in are on, groups they're
+ * not in are off. */
+/* If group_user is one, then the variable "user" refers to *group* members,
+ * not *user* members. */
+/* If except is non-null, output all entries except the "except" item. */
+/* (note: this methodology is known as the "Garbage pail method", just
+ * keep adding parameters till it does everything you want) MLM */
+#define SELECT_OVERFLOW 25
+NSAPI_PUBLIC void output_group_selector(char *db_path,
+ int group_user, char *user,
+ char *highlight, char *except,
+ char *name, int none, int multiple);
+
+/* Same as above, except output a list of users, highlighting those in a
+ * particular group. MLM */
+NSAPI_PUBLIC void output_user_selector(char *db_path, char *group,
+ char *highlight, char *except,
+ char *name, int none, int multiple);
+
+/* Take a char ** null terminated list of group names, and change a user's
+ * memberships so those are the only groups he's in. MLM */
+NSAPI_PUBLIC void change_user_membership(char *db_path, char *user,
+ char **new_groups);
+
+/* Take a char ** null terminated list of group names, and change a user's
+ * memberships so those are the only groups he's in. MLM */
+/* If group_users is 1, then new_users are assumed to be groups. */
+NSAPI_PUBLIC void change_group_membership(char *db_path, char *group,
+ int group_users, char **new_users);
+
+
+/* Get the server's URL. */
+/* util.c */
+NSAPI_PUBLIC char *get_serv_url(void);
+
+/* Run a command and check the output */
+struct runcmd_s {
+ char *title;
+ char *msg;
+ char *arg;
+ int sysmsg;
+};
+/* util.c */
+NSAPI_PUBLIC int run_cmd(char *cmd, FILE *closeme, struct runcmd_s *rm);
+
+/* This is basically copy_file from the install section, with the error
+ * reporting changed to match the admin stuff. Since some stuff depends
+ * on copy_file being the install version, I'll cheat and call this one
+ * cp_file. */
+/* util.c */
+NSAPI_PUBLIC void cp_file(char *sfile, char *dfile, int mode);
+
+/* Delete the file with the given path. Returns positive value on failure.*/
+/* util.c */
+NSAPI_PUBLIC int delete_file(char *path);
+
+/* Delete the directory with the given path. Returns positive value on failure.*/
+/* BEWARE! Be sure to verify you're not deleting things you */
+/* shouldn't. Testing the directory with "util_uri_is_evil" */
+/* is often a good idea. */
+/* util.c */
+NSAPI_PUBLIC void remove_directory(char *path);
+
+/* Simply creates a directory that you give it. Checks for errors and
+ * all that. (Not to be confused with create_subdirs in install, since
+ * it relies on some installation stuff.) */
+/* util.c */
+NSAPI_PUBLIC void create_dir(char *dir, int mode);
+
+/* Open a file, with file locking. Close a file, releasing the lock. */
+/* util.c */
+NSAPI_PUBLIC FILE *fopen_l(char *pathname, char *mode);
+NSAPI_PUBLIC void fclose_l(FILE *f);
+
+/* helper function to figure out where to put the lock */
+/* util.c */
+NSAPI_PUBLIC char *get_flock_path(void);
+
+/* uuencode a given buffer. both src and dst need to be allocated. dst
+ * should be 1 1/4 as big as src (i saved some math and just made it twice
+ * as big when I called it) */
+/* util.c */
+NSAPI_PUBLIC int do_uuencode(unsigned char *src, unsigned char *dst, int srclen);
+
+/* Word wrap a string to fit into a JavaScript alert box. */
+/* str is the string, width is the width to wrap to, linefeed is the string
+ * to use as a linefeed. */
+/* util.c */
+#define WORD_WRAP_WIDTH 80
+NSAPI_PUBLIC char *alert_word_wrap(char *str, int width, char *linefeed);
+
+
+/* Writes the given object set as the current database */
+/* Takes an argument for which server in the list to dump to */
+/* ns-util.c */
+NSAPI_PUBLIC void dump_database(int whichsrv, httpd_objset *os);
+NSAPI_PUBLIC void dump_database_tofile(int whichsrv, char *fn, httpd_objset *os);
+
+/* Scans the given database and returns its object set. */
+/* ns-util.c */
+NSAPI_PUBLIC httpd_objset *read_config_from_file(char *objconf);
+
+/* Scans the current database and returns its object set. */
+/* Takes a number for which server in multiple list to read */
+/* ns-util.c */
+NSAPI_PUBLIC httpd_objset *read_config(int x);
+
+/* Inserts a new pfx2dir name translation into the object, making sure there
+ * are no name conflicts. Name conflict resolution is simple: Keep the longest
+ * from fields first in the file. */
+/* ns-util.c */
+NSAPI_PUBLIC void insert_ntrans(pblock *p, pblock *c, httpd_object *obj);
+
+/* Inserts a new assign-name and mkssi-version into the object, making sure
+ * that they come first and are sorted. */
+NSAPI_PUBLIC void insert_ntrans_an(pblock *p, pblock *c, httpd_object *obj);
+
+/* Inserts a new mkssi-pcheck into the object, making sure that they come
+ * first and are sorted. */
+NSAPI_PUBLIC void insert_pcheck_mp(pblock *p, pblock *c, httpd_object *obj);
+
+/* Inserts a new alias in the database (before all other entries) */
+/* ns-util.c */
+NSAPI_PUBLIC void insert_alias(pblock *p, pblock *c, httpd_object *obj);
+
+/* Scans a file and puts all of its lines into a char * array. Strips
+ * trailing whitespace */
+/* ns-util.c */
+NSAPI_PUBLIC char **scan_tech(char *fn);
+
+/* Writes the lines to the given file */
+/* ns-util.c */
+NSAPI_PUBLIC int write_tech(char *fn, char **lines);
+
+/* Finds an object by its ppath */
+/* ns-util.c */
+NSAPI_PUBLIC httpd_object *findliteralppath(char *qs, httpd_objset *os);
+
+
+/* Compares two passwords, one plaintext and one encrypted. Returns strcmp()
+ * like integer (0 good, anything else bad) */
+/* password.c */
+NSAPI_PUBLIC int pw_cmp(char *pw, char *enc);
+
+/* Encrypts a plaintext password. */
+/* password.c */
+NSAPI_PUBLIC char *pw_enc(char *pw);
+
+
+/* Maintain what amounts to a handle to a list of strings */
+/* strlist.c */
+/* Moved to libadminutil, use libadminutil/admutil.h instead
+NSAPI_PUBLIC char **new_strlist(int size);
+NSAPI_PUBLIC char **grow_strlist(char **strlist, int newsize);
+NSAPI_PUBLIC void free_strlist(char **strlist);
+*/
+
+/* Handle INN config.data which are now called nsnews.conf files */
+/* nsnews.c */
+char *find_nsnews_var(char *var, char **lines);
+void set_nsnews_var(char *name, char *val, char **lines);
+int find_nsnews_line(char *var, char **lines);
+void remove_nsnews_var(char *name, char **lines);
+void replace_nsnews_prefix(char *opfx, char *npfx, char **lines);
+
+char **scan_nsnews_admin(char *filename);
+char **scan_nsnews_install(char *filename);
+void nsnews_file2path_admin(char *filename, char *path);
+void nsnews_file2path_install(char *filename, char *path);
+void write_nsnews_admin(char *filename, char **lines);
+void write_nsnews_install(char *filename, char **lines);
+
+void run_ctlinnd(char *cmd);
+char **nsnews_status(void);
+void set_moderator(char *group, char *email);
+char *find_moderator(char *group, char **lines);
+char **scan_active(char **nscnf);
+int find_active_group(char *grp, char **active);
+char *active_flags(char *line);
+int active_groupmatch(char *grppat, char *line);
+char **scan_expirectl(char *fn);
+void write_expirectl(char *fn, char **lines);
+void set_expire_remember(char *days, char **lines);
+void set_expire_default(char *def, char *keep, char *purge, char **lines);
+
+#define EXPREM_STRING "/remember/:"
+#define EXPREM_LEN 11
+#define EXPDEF_STRING "*:A:"
+#define EXPDEF_LEN 4
+
+#define find_expire_remember(lines) (find_expire_string(EXPREM_STRING, lines))
+#define find_expire_default(lines) (find_expire_string(EXPDEF_STRING, lines))
+char *find_expire_string(char *find, char **lines);
+
+typedef struct {
+ char *patterns;
+ char flag;
+ char *keep;
+ char *def;
+ char *purge;
+} expire_s;
+int expire_entry(char *line, expire_s *ret);
+expire_s *expire_entry_default(char **lines);
+expire_s *find_expire_entry(char *find, char **lines);
+void new_expire_entry(expire_s *ex, char **lines);
+void change_expire_entry(char *find, expire_s *ex, char **lines);
+void remove_expire_entry(char *find, char **lines);
+
+typedef struct {
+ char *grp;
+ char *hostpats;
+ char *flags;
+ char *userpat;
+} permission_s;
+char **scan_nsaccess(char *fn);
+void write_nsaccess(char *fn, char **lines);
+permission_s *find_nsaccess_default(char **lines);
+permission_s *find_nsaccess_entry(char *find, char **lines);
+void new_nsaccess_entry(permission_s *ps, char **lines);
+void change_nsaccess_entry(char *find, permission_s *ps, char **lines);
+void remove_nsaccess_entry(char *find, char **lines);
+
+/* Handle newsfeeds files */
+void feed_read_file();
+void feed_write_file();
+char *feed_get_ind_var(int *x);
+char *feed_get_host_var(char *host);
+char *feed_get_newsgroups(char *feedline);
+char *feed_get_param(char *feedline);
+void feed_split_newsgroups(char *ngroups, char **allow, char **deny);
+char *add_bangs(char *string);
+void compress_whitespace(char *source);
+char *feed_merge_newsgroups(char *allow_in, char *deny_in);
+void feed_set_groups(char *host, char *groups);
+void feed_set_entry(char *id, char *ngroups, char *feedtype, char *params);
+void feed_delete_host(char *host);
+void feed_dump_vars(char *feedtype, char *dest);
+
+void nnhost_add(char *hostname);
+void nnhost_delete(char *hostname);
+
+void nnctl_add(char *hostname);
+void nnctl_delete(char *hostname);
+
+int nsnews_running(char **nscnf);
+
+
+#ifdef MCC_PROXY
+
+extern long inst_cache_size_tbl[];
+extern long inst_cache_capacity_tbl[];
+extern long cache_size_tbl[];
+extern long cache_capacity_tbl[];
+extern float lm_factor_tbl[];
+extern long time_interval_tbl[];
+extern long timeout_tbl[];
+extern int percent_tbl[];
+
+char *mb_str(long mb);
+char *lm_str(float f);
+
+void output_interval_select(char *name, char *other, long selected, long *tbl);
+void output_mb_select(char *name, char *other, long selected, long *tbl);
+void output_lm_select(char *name, char *other, float selected, float *tbl);
+void output_percentage_select(char *name, char *other, int selected, int *tbl);
+
+#endif /* MCC_PROXY */
+
+#ifdef MCC_NEWS
+
+char * get_active_news_authdb(char **nscnf);
+void set_active_news_authdb(char *name, char **nscnf);
+void output_active_news_authdb(char **nscnf);
+
+#endif /* MCC_NEWS */
+
+#if 0 /* move cron_conf to libadminutil */
+
+/* read and write to cron.conf, cron_conf.c */
+/* Alex Feygin, 3/22/96 */
+typedef struct cron_conf_obj
+{
+ char *name;
+ char *command;
+ char *dir;
+ char *user;
+ char *start_time;
+ char *days;
+}
+cron_conf_obj;
+
+typedef struct cron_conf_list
+{
+ char *name;
+ cron_conf_obj *obj;
+ struct cron_conf_list *next;
+}
+cron_conf_list;
+
+/* Reads cron.conf to a null terminated list of cron_conf_objects; returns
+ 0 if unable to do a read; 1 otherwise */
+NSAPI_PUBLIC int cron_conf_read();
+
+/* gets a cron object, NULL if it doesnt exist */
+NSAPI_PUBLIC cron_conf_obj *cron_conf_get(char *name);
+
+/* returns a NULL-terminated cron_conf_list of all the cron conf objects */
+NSAPI_PUBLIC cron_conf_list *cron_conf_get_list();
+
+/* Creates a cron conf object; all these args get STRDUP'd in the function
+ so make sure to free up the space later if need be */
+NSAPI_PUBLIC cron_conf_obj *cron_conf_create_obj(char *name, char *command,
+ char *dir, char *user,
+ char *start_time, char *days);
+
+/* Puts a cron conf object into list or updates it if it already in there.
+ Returns either the object passed or the object in there already;
+ cco may be FREE'd during this operation so if you need the object
+ back, call it like so:
+
+ cco = cron_conf_set(cco->name, cco);
+
+ calling cron_conf_set with a NULL cco will cause the 'name' object
+ to be deleted.
+*/
+NSAPI_PUBLIC cron_conf_obj *cron_conf_set(char *name, cron_conf_obj *cco);
+
+/* write out current list of cron_conf_objects to cron.conf file */
+NSAPI_PUBLIC void cron_conf_write();
+
+/* free all cron conf data structures */
+NSAPI_PUBLIC void cron_conf_free();
+
+
+#endif /* move cron_conf to libadminutil */
+
+
+/**************************************************************************
+ * This is should really be in base/file.h, but we don't want to tread on
+ * toes.
+ * Implement fgets without the error complaints the util_getline has. The
+ * calling function is smart enough to deal with partial lines.
+ * Also include a sleep that has the same functionality as Unix for NT.
+ *************************************************************************/
+
+NSAPI_PUBLIC char *system_gets( char *, int, filebuffer * );
+
+#ifdef XP_UNIX
+NSAPI_PUBLIC int system_zero( SYS_FILE );
+#else /* XP_WIN32 */
+#define system_zero( f ) \
+ SetFilePointer( PR_FileDesc2NativeHandle( f ), 0, NULL, FILE_BEGIN );\
+ SetEndOfFile( PR_FileDesc2NativeHandle( f ) )
+#define sleep( t ) Sleep( (t) * 1000 )
+#endif /* XP_WIN32 */
+
+NSAPI_PUBLIC char *cookieValue( char *, char * );
+
+NSAPI_PUBLIC void jsPWDialogSrc( int inScript, char *otherJS );
+
+NSAPI_PUBLIC int IsCurrentTemplateNSPlugin(char* templateName);
+
+/************************** Miscellaneous *************************/
+NSAPI_PUBLIC char * jsEscape(char *src);
+NSAPI_PUBLIC int read_AbbrDescType_file(char *path, char ***namelist, char ***desclist);
+
+NSPR_END_EXTERN_C
+
+#endif /* libadmin_h */
diff --git a/include/netsite.h b/include/netsite.h
new file mode 100644
index 00000000..278b1d14
--- /dev/null
+++ b/include/netsite.h
@@ -0,0 +1,312 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef NETSITE_H
+#define NETSITE_H
+
+#ifndef NOINTNSAPI
+#define INTNSAPI
+#endif /* !NOINTNSAPI */
+
+/*
+ * Standard defs for NetSite servers.
+ */
+
+/*
+** Macro shorthands for conditional C++ extern block delimiters.
+** Don't redefine for compatability with NSPR.
+*/
+#ifndef NSPR_BEGIN_EXTERN_C
+#ifdef __cplusplus
+#define NSPR_BEGIN_EXTERN_C extern "C" {
+#define NSPR_END_EXTERN_C }
+#else
+#define NSPR_BEGIN_EXTERN_C
+#define NSPR_END_EXTERN_C
+#endif
+#endif /* NSPR_BEGIN_EXTERN_C */
+#ifdef __cplusplus
+#define EXTERNC extern "C"
+#else
+#define EXTERNC
+#endif
+
+#ifndef VERSION_H
+#include "version.h"
+#endif /* !VERSION_H */
+
+#ifndef BASE_SYSTEMS_H
+#include "base/systems.h"
+#endif /* !BASE_SYSTEMS_H */
+
+#undef MAGNUS_VERSION_STRING
+
+#ifdef MCC_PROXY
+#define MAGNUS_VERSION PROXY_VERSION_DEF
+#define MAGNUS_VERSION_STRING PROXY_VERSION_STRING
+
+#elif defined(NS_CMS)
+#define MAGNUS_VERSION CMS_VERSION_DEF
+#define MAGNUS_VERSION_STRING CMS_VERSION_STRING
+
+#elif defined(NS_DS)
+#define MAGNUS_VERSION DS_VERSION_DEF
+#define MAGNUS_VERSION_STRING DS_VERSION_STRING
+
+#elif defined(MCC_ADMSERV)
+#define MAGNUS_VERSION ADMSERV_VERSION_DEF
+#define MAGNUS_VERSION_STRING ADMSERV_VERSION_STRING
+
+#elif defined(NS_CATALOG)
+#define MAGNUS_VERSION CATALOG_VERSION_DEF
+#define MAGNUS_VERSION_STRING CATALOG_VERSION_STRING
+
+#elif defined(NS_RDS)
+#define MAGNUS_VERSION RDS_VERSION_DEF
+#define MAGNUS_VERSION_STRING RDS_VERSION_STRING
+
+#elif defined(MCC_HTTPD)
+
+#ifdef NS_PERSONAL
+#define MAGNUS_VERSION PERSONAL_VERSION_DEF
+#else
+#define MAGNUS_VERSION ENTERPRISE_VERSION_DEF
+#endif
+
+#if defined(XP_UNIX) || defined(USE_ADMSERV)
+#if defined(NS_DS)
+#define MAGNUS_VERSION_STRING DS_VERSION_STRING
+#elif defined(NS_PERSONAL)
+#define MAGNUS_VERSION_STRING PERSONAL_VERSION_STRING
+#elif defined(NS_CATALOG)
+#define MAGNUS_VERSION_STRING CATALOG_VERSION_STRING
+#elif defined(NS_RDS)
+#define MAGNUS_VERSION_STRING RDS_VERSION_STRING
+#elif defined(NS_CMS)
+#define MAGNUS_VERSION_STRING CMS_VERSION_STRING
+#else
+#define MAGNUS_VERSION_STRING ENTERPRISE_VERSION_STRING
+#endif
+#endif /* XP_UNIX */
+
+#elif defined(MCC_NEWS)
+#define MAGNUS_VERSION_STRING NEWS_VERSION_STRING
+
+#elif defined(NS_MAIL)
+#define MAGNUS_VERSION MAIL_VERSION_DEF
+#define MAGNUS_VERSION_STRING MAIL_VERSION_STRING
+
+#elif defined(MCC_BATMAN)
+#define MAGNUS_VERSION BATMAN_VERSION_DEF
+#define MAGNUS_VERSION_STRING BATMAN_VERSION_STRING
+
+#endif
+
+#ifndef VOID
+#define VOID void
+#endif
+
+#ifdef XP_UNIX
+/*
+ * Provide some typedefs that are commonly used on windows
+ *
+ * DO NOT USE THESE! They will be deleted later!
+ *
+ */
+#define CONST const
+typedef unsigned long DWORD;
+typedef int BOOL;
+typedef unsigned char BYTE;
+typedef unsigned short WORD;
+typedef float FLOAT;
+typedef FLOAT *PFLOAT;
+typedef BOOL *PBOOL;
+typedef BOOL *LPBOOL;
+typedef BYTE *PBYTE;
+typedef BYTE *LPBYTE;
+typedef int *PINT;
+typedef int *LPINT;
+typedef WORD *PWORD;
+typedef WORD *LPWORD;
+typedef long *LPLONG;
+typedef DWORD *PDWORD;
+typedef DWORD *LPDWORD;
+typedef void *LPVOID;
+
+#ifndef SNI
+#if !defined (boolean) && !defined (__GNUC__)
+typedef int boolean;
+#endif
+#endif
+
+#endif
+#define NS_TRUE 1
+#define NS_FALSE 0
+
+NSPR_BEGIN_EXTERN_C
+
+/* -------------------------- System version on NT------------------------- */
+
+/* Encode the server version as a number to be able to provide inexpensive
+ * dynamic checks on server version - this isn't added in yet. */
+
+#define ENTERPRISE_VERSION 1
+#define PERSONAL_VERSION 2
+#define CATALOG_VERSION 3
+#define RDS_VERSION 4
+#define CMS_VERSION 5
+#undef DS_VERSION
+#define DS_VERSION 6
+
+#define server_fasttrack (!strcmp(MAGNUS_VERSION_STRING, PERSONAL_VERSION_STRING))
+#define server_enterprise (!strcmp(MAGNUS_VERSION_STRING, ENTERPRISE_VERSION_STRING))
+
+/* This definition of MAGNUS_VERSION_STRING on NT should be used
+ * only when building the ns-http DLL */
+
+#if defined(MCC_HTTPD) && defined(XP_WIN32) && !defined(USE_ADMSERV) && !defined(MCC_ADMSERV)
+#undef MAGNUS_VERSION_STRING
+#define MAGNUS_VERSION_STRING INTsystem_version()
+#endif /* XP_WIN32 */
+
+/* Set server's version dynamically */
+NSAPI_PUBLIC void INTsystem_version_set(char *ptr);
+
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+/* Include the public netsite.h definitions */
+#ifndef PUBLIC_NETSITE_H
+#ifdef MALLOC_DEBUG
+#define NS_MALLOC_DEBUG
+#endif /* MALLOC_DEBUG */
+#include "public/netsite.h"
+#endif /* PUBLIC_NETSITE_H */
+
+#endif /* !APSTUDIO_READONLY_SYMBOLS */
+
+/*
+ * If NS_MALLOC_DEBUG is defined, declare the debug version of the memory
+ * allocation API.
+ */
+#ifdef NS_MALLOC_DEBUG
+#define PERM_MALLOC(size) INTsystem_malloc_perm(size, __LINE__, __FILE__)
+NSAPI_PUBLIC void *INTsystem_malloc_perm(int size, int line, char *file);
+
+#define PERM_CALLOC(size) INTsystem_calloc_perm(size, __LINE__, __FILE__)
+NSAPI_PUBLIC void *INTsystem_calloc_perm(int size, int line, char *file);
+
+#define PERM_REALLOC(ptr, size) INTsystem_realloc_perm(ptr, size, __LINE__, __FILE__)
+NSAPI_PUBLIC void *INTsystem_realloc_perm(void *ptr, int size, int line, char *file);
+
+#define PERM_FREE(ptr) INTsystem_free_perm((void *) ptr, __LINE__, __FILE__)
+NSAPI_PUBLIC void INTsystem_free_perm(void *ptr, int line, char *file);
+
+#define PERM_STRDUP(ptr) INTsystem_strdup_perm(ptr, __LINE__, __FILE__)
+NSAPI_PUBLIC char *INTsystem_strdup_perm(const char *ptr, int line, char *file);
+#endif /* NS_MALLOC_DEBUG */
+
+/*
+ * Only the mainline needs to set the malloc key.
+ */
+
+void setThreadMallocKey(int key);
+
+/* This probably belongs somewhere else, perhaps with a different name */
+NSAPI_PUBLIC char *INTdns_guess_domain(char * hname);
+
+/* --- Begin public functions --- */
+
+#ifdef INTNSAPI
+
+NSAPI_PUBLIC char *INTsystem_version();
+
+/*
+ Depending on the system, memory allocated via these macros may come from
+ an arena. If these functions are called from within an Init function, they
+ will be allocated from permanent storage. Otherwise, they will be freed
+ when the current request is finished.
+ */
+
+#define MALLOC(size) INTsystem_malloc(size)
+NSAPI_PUBLIC void *INTsystem_malloc(int size);
+
+#define CALLOC(size) INTsystem_calloc(size)
+NSAPI_PUBLIC void *INTsystem_calloc(int size);
+
+#define REALLOC(ptr, size) INTsystem_realloc(ptr, size)
+NSAPI_PUBLIC void *INTsystem_realloc(void *ptr, int size);
+
+#define FREE(ptr) INTsystem_free((void *) ptr)
+NSAPI_PUBLIC void INTsystem_free(void *ptr);
+
+#define STRDUP(ptr) INTsystem_strdup(ptr)
+NSAPI_PUBLIC char *INTsystem_strdup(const char *ptr);
+
+/*
+ These macros always provide permanent storage, for use in global variables
+ and such. They are checked at runtime to prevent them from returning NULL.
+ */
+
+#ifndef NS_MALLOC_DEBUG
+
+#define PERM_MALLOC(size) INTsystem_malloc_perm(size)
+NSAPI_PUBLIC void *INTsystem_malloc_perm(int size);
+
+#define PERM_CALLOC(size) INTsystem_calloc_perm(size)
+NSAPI_PUBLIC void *INTsystem_calloc_perm(int size);
+
+#define PERM_REALLOC(ptr, size) INTsystem_realloc_perm(ptr, size)
+NSAPI_PUBLIC void *INTsystem_realloc_perm(void *ptr, int size);
+
+#define PERM_FREE(ptr) INTsystem_free_perm((void *) ptr)
+NSAPI_PUBLIC void INTsystem_free_perm(void *ptr);
+
+#define PERM_STRDUP(ptr) INTsystem_strdup_perm(ptr)
+NSAPI_PUBLIC char *INTsystem_strdup_perm(const char *ptr);
+
+#endif /* !NS_MALLOC_DEBUG */
+
+/* Thread-Private data key index for accessing the thread-private memory pool.
+ * Each thread creates its own pool for allocating data. The MALLOC/FREE/etc
+ * macros have been defined to check the thread private data area with the
+ * thread_malloc_key index to find the address for the pool currently in use.
+ *
+ * If a thread wants to use a different pool, it must change the thread-local-
+ * storage[thread_malloc_key].
+ */
+
+NSAPI_PUBLIC int INTgetThreadMallocKey(void);
+
+/* Not sure where to put this. */
+NSAPI_PUBLIC void INTmagnus_atrestart(void (*fn)(void *), void *data);
+
+#endif /* INTNSAPI */
+
+/* --- End public functions --- */
+
+NSPR_END_EXTERN_C
+
+#define system_version_set INTsystem_version_set
+#define dns_guess_domain INTdns_guess_domain
+
+#ifdef INTNSAPI
+
+#define system_version INTsystem_version
+#define system_malloc INTsystem_malloc
+#define system_calloc INTsystem_calloc
+#define system_realloc INTsystem_realloc
+#define system_free INTsystem_free
+#define system_strdup INTsystem_strdup
+#define system_malloc_perm INTsystem_malloc_perm
+#define system_calloc_perm INTsystem_calloc_perm
+#define system_realloc_perm INTsystem_realloc_perm
+#define system_free_perm INTsystem_free_perm
+#define system_strdup_perm INTsystem_strdup_perm
+#define getThreadMallocKey INTgetThreadMallocKey
+#define magnus_atrestart INTmagnus_atrestart
+
+#endif /* INTNSAPI */
+
+#endif /* NETSITE_H */
diff --git a/include/nt/messages.h b/include/nt/messages.h
new file mode 100644
index 00000000..d47a9fa5
--- /dev/null
+++ b/include/nt/messages.h
@@ -0,0 +1,410 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+ /*
+ Microsoft Developer Support
+ Copyright (c) 1992 Microsoft Corporation
+
+ This file contains the message definitions for the Win32
+ messages.exe sample program.
+-------------------------------------------------------------------------
+ HEADER SECTION
+
+ The header section defines names and language identifiers for use
+ by the message definitions later in this file. The MessageIdTypedef,
+ SeverityNames, FacilityNames, and LanguageNames keywords are
+ optional and not required.
+
+
+
+ The MessageIdTypedef keyword gives a typedef name that is used in a
+ type cast for each message code in the generated include file. Each
+ message code appears in the include file with the format: #define
+ name ((type) 0xnnnnnnnn) The default value for type is empty, and no
+ type cast is generated. It is the programmer's responsibility to
+ specify a typedef statement in the application source code to define
+ the type. The type used in the typedef must be large enough to
+ accomodate the entire 32-bit message code.
+
+
+
+ The SeverityNames keyword defines the set of names that are allowed
+ as the value of the Severity keyword in the message definition. The
+ set is delimited by left and right parentheses. Associated with each
+ severity name is a number that, when shifted left by 30, gives the
+ bit pattern to logical-OR with the Facility value and MessageId
+ value to form the full 32-bit message code. The default value of
+ this keyword is:
+
+ SeverityNames=(
+ Success=0x0
+ Informational=0x1
+ Warning=0x2
+ Error=0x3
+ )
+
+ Severity values occupy the high two bits of a 32-bit message code.
+ Any severity value that does not fit in two bits is an error. The
+ severity codes can be given symbolic names by following each value
+ with :name
+
+
+
+ The FacilityNames keyword defines the set of names that are allowed
+ as the value of the Facility keyword in the message definition. The
+ set is delimited by left and right parentheses. Associated with each
+ facility name is a number that, when shift it left by 16 bits, gives
+ the bit pattern to logical-OR with the Severity value and MessageId
+ value to form the full 32-bit message code. The default value of
+ this keyword is:
+
+ FacilityNames=(
+ System=0x0FF
+ Application=0xFFF
+ )
+
+ Facility codes occupy the low order 12 bits of the high order
+ 16-bits of a 32-bit message code. Any facility code that does not
+ fit in 12 bits is an error. This allows for 4,096 facility codes.
+ The first 256 codes are reserved for use by the system software. The
+ facility codes can be given symbolic names by following each value
+ with :name
+
+
+ The LanguageNames keyword defines the set of names that are allowed
+ as the value of the Language keyword in the message definition. The
+ set is delimited by left and right parentheses. Associated with each
+ language name is a number and a file name that are used to name the
+ generated resource file that contains the messages for that
+ language. The number corresponds to the language identifier to use
+ in the resource table. The number is separated from the file name
+ with a colon. The initial value of LanguageNames is:
+
+ LanguageNames=(English=1:MSG00001)
+
+ Any new names in the source file which don't override the built-in
+ names are added to the list of valid languages. This allows an
+ application to support private languages with descriptive names.
+
+
+-------------------------------------------------------------------------
+ MESSAGE DEFINITION SECTION
+
+ Following the header section is the body of the Message Compiler
+ source file. The body consists of zero or more message definitions.
+ Each message definition begins with one or more of the following
+ statements:
+
+ MessageId = [number|+number]
+ Severity = severity_name
+ Facility = facility_name
+ SymbolicName = name
+
+ The MessageId statement marks the beginning of the message
+ definition. A MessageID statement is required for each message,
+ although the value is optional. If no value is specified, the value
+ used is the previous value for the facility plus one. If the value
+ is specified as +number then the value used is the previous value
+ for the facility, plus the number after the plus sign. Otherwise, if
+ a numeric value is given, that value is used. Any MessageId value
+ that does not fit in 16 bits is an error.
+
+ The Severity and Facility statements are optional. These statements
+ specify additional bits to OR into the final 32-bit message code. If
+ not specified they default to the value last specified for a message
+ definition. The initial values prior to processing the first message
+ definition are:
+
+ Severity=Success
+ Facility=Application
+
+ The value associated with Severity and Facility must match one of
+ the names given in the FacilityNames and SeverityNames statements in
+ the header section. The SymbolicName statement allows you to
+ associate a C/C++ symbolic constant with the final 32-bit message
+ code.
+ */
+//
+// Values are 32 bit values layed out as follows:
+//
+// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+// +---+-+-+-----------------------+-------------------------------+
+// |Sev|C|R| Facility | Code |
+// +---+-+-+-----------------------+-------------------------------+
+//
+// where
+//
+// Sev - is the severity code
+//
+// 00 - Success
+// 01 - Informational
+// 10 - Warning
+// 11 - Error
+//
+// C - is the Customer code flag
+//
+// R - is a reserved bit
+//
+// Facility - is the facility code
+//
+// Code - is the facility's status code
+//
+//
+// Define the facility codes
+//
+#define FACILITY_SYSTEM 0x0
+#define FACILITY_STARTUP 0x5
+#define FACILITY_RUNTIME 0x1
+#define FACILITY_REGISTRY 0x7
+#define FACILITY_NETWORK 0x4
+#define FACILITY_SERVICE 0x3
+#define FACILITY_FILESYSTEM 0x6
+#define FACILITY_CGI 0x2
+
+
+//
+// Define the severity codes
+//
+#define STATUS_SEVERITY_WARNING 0x2
+#define STATUS_SEVERITY_SUCCESS 0x0
+#define STATUS_SEVERITY_INFORMATIONAL 0x1
+#define STATUS_SEVERITY_ERROR 0x3
+
+
+//
+// MessageId: MSG_BAD_CONF_INIT
+//
+// MessageText:
+//
+// Netsite:%1 %2
+//
+#define MSG_BAD_CONF_INIT ((DWORD)0xC0050001L)
+
+//
+// MessageId: MSG_BAD_EREPORT_INIT
+//
+// MessageText:
+//
+// Netsite:%1 %2
+//
+#define MSG_BAD_EREPORT_INIT ((DWORD)0xC0050002L)
+
+//
+// MessageId: MSG_BAD_STARTUP
+//
+// MessageText:
+//
+// Netsite:%1 %2
+//
+#define MSG_BAD_STARTUP ((DWORD)0xC0050003L)
+
+//
+// MessageId: MSG_BAD_WINSOCK_INIT
+//
+// MessageText:
+//
+// Netsite Initialization:%1 %2
+//
+#define MSG_BAD_WINSOCK_INIT ((DWORD)0xC0050004L)
+
+//
+// MessageId: MSG_BAD_CGISEM_CREATE
+//
+// MessageText:
+//
+// Netsite Initialization:%1 %2
+//
+#define MSG_BAD_CGISEM_CREATE ((DWORD)0xC0050005L)
+
+//
+// MessageId: MSG_BAD_PROCESSSEM_CREATE
+//
+// MessageText:
+//
+// Netsite:Initialization:%1 %2
+//
+#define MSG_BAD_PROCESSSEM_CREATE ((DWORD)0xC0050006L)
+
+//
+// MessageId: MSG_STARTUP_SUCCESSFUL
+//
+// MessageText:
+//
+// Netsite:%1 %2
+//
+#define MSG_STARTUP_SUCCESSFUL ((DWORD)0x00050007L)
+
+//
+// MessageId: MSG_BAD_REGISTRY_PARAMETER
+//
+// MessageText:
+//
+// Netsite:%1 %2
+//
+#define MSG_BAD_REGISTRY_PARAMETER ((DWORD)0x80050008L)
+
+//
+// MessageId: MSG_BAD_GENERAL_FUNCTION
+//
+// MessageText:
+//
+// Netsite:Execution of Initialization Function failed %1 %2
+//
+#define MSG_BAD_GENERAL_FUNCTION ((DWORD)0xC0050009L)
+
+//
+// MessageId: MSG_BAD_SETCIPHERS
+//
+// MessageText:
+//
+// Netsite: %1 %2
+//
+#define MSG_BAD_SETCIPHERS ((DWORD)0xC0050010L)
+
+//
+// MessageId: MSG_BAD_REGISTRY_KEY_OPEN
+//
+// MessageText:
+//
+// Netsite Initialization:Open of %1 %2
+//
+#define MSG_BAD_REGISTRY_KEY_OPEN ((DWORD)0xC0050011L)
+
+//
+// MessageId: MSG_BAD_REGISTRY_KEY_ENUM
+//
+// MessageText:
+//
+// Netsite Initialization:Enumeration of %1 %2
+//
+#define MSG_BAD_REGISTRY_KEY_ENUM ((DWORD)0xC0050012L)
+
+//
+// MessageId: MSG_BAD_REGISTRY_VALUE_ENUM
+//
+// MessageText:
+//
+// Netsite Initialization:Enumeration of Values of %1 %2
+//
+#define MSG_BAD_REGISTRY_VALUE_ENUM ((DWORD)0xC0050013L)
+
+//
+// MessageId: MSG_BAD_OBJECT_VALUE
+//
+// MessageText:
+//
+// Netsite startup:Use Values "name" or "ppath" for object key.Incorrect Parameter %1 %2
+//
+#define MSG_BAD_OBJECT_VALUE ((DWORD)0xC0050014L)
+
+//
+// MessageId: MSG_BAD_PBLOCK
+//
+// MessageText:
+//
+// Netsite startup:Could not enter Parameter %1 %2
+//
+#define MSG_BAD_PBLOCK ((DWORD)0xC0050015L)
+
+//
+// MessageId: MSG_BAD_CLIENT_VALUE
+//
+// MessageText:
+//
+// Netsite startup:Use Values "dns" or "ip" for client key.Incorrect Parameter %1 %2
+//
+#define MSG_BAD_CLIENT_VALUE ((DWORD)0xC0050016L)
+
+//
+// MessageId: MSG_BAD_DIRECTIVE
+//
+// MessageText:
+//
+// Netsite startup:Incorrect Directive Value %1 %2
+//
+#define MSG_BAD_DIRECTIVE ((DWORD)0xC0050017L)
+
+//
+// MessageId: MSG_BAD_PARAMETER
+//
+// MessageText:
+//
+// Netsite startup:Incorrect Parameter %1 %2
+//
+#define MSG_BAD_PARAMETER ((DWORD)0xC0050018L)
+
+//
+// MessageId: MSG_WD_RESTART
+//
+// MessageText:
+//
+// Web Server: %1
+// The server terminated abnormally with error code %2.
+// An attempt will be made to restart it.
+//
+#define MSG_WD_RESTART ((DWORD)0xC0050019L)
+
+//
+// MessageId: MSG_WD_STARTFAILED
+//
+// MessageText:
+//
+// Web Server: %1
+// The server could not be started.
+// Command line used: %2
+//
+#define MSG_WD_STARTFAILED ((DWORD)0xC005001AL)
+
+//
+// MessageId: MSG_WD_BADPASSWORD
+//
+// MessageText:
+//
+// Web Server: %1
+// Incorrect SSL password entered.
+//
+#define MSG_WD_BADPASSWORD ((DWORD)0xC005001BL)
+
+//
+// MessageId: MSG_WD_BADCMDLINE
+//
+// MessageText:
+//
+// Web Server: %1
+// Invalid command line specified: %2
+//
+#define MSG_WD_BADCMDLINE ((DWORD)0xC005001CL)
+
+//
+// MessageId: MSG_WD_STRING
+//
+// MessageText:
+//
+// Web Server: %1
+// %2
+//
+#define MSG_WD_STRING ((DWORD)0xC005001DL)
+
+//
+// MessageId: MSG_WD_REGISTRY
+//
+// MessageText:
+//
+// Web Server: %1
+// Could not open registry key: %2
+//
+#define MSG_WD_REGISTRY ((DWORD)0xC005001EL)
+
+//
+// MessageId: MSG_CRON_STARTFAILED
+//
+// MessageText:
+//
+// Web Server: %1
+// The scheduled job (%2) could not be started.
+//
+#define MSG_CRON_STARTFAILED ((DWORD)0xC005001FL)
+
diff --git a/include/nt/nsapi.h b/include/nt/nsapi.h
new file mode 100644
index 00000000..f286dc1f
--- /dev/null
+++ b/include/nt/nsapi.h
@@ -0,0 +1,346 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Aruna Victor
+ */
+
+#include <windows.h>
+#include <stdio.h>
+
+#include <base/buffer.h>
+#include <base/file.h>
+#include <base/daemon.h>
+#include <base/eventlog.h>
+#include <base/util.h>
+#include <base/shexp.h>
+#include <base/session.h>
+#include <base/sem.h>
+#include <base/pblock.h>
+#include <base/net.h>
+#include <base/ereport.h>
+#include <base/cinfo.h>
+#include <base/systhr.h>
+#include <base/shmem.h>
+#include <base/crit.h>
+#include <base/systhr.h>
+
+#include <frame/objset.h>
+#include <frame/conf.h>
+#include <frame/func.h>
+#include <frame/http.h>
+#include <frame/log.h>
+#include <frame/object.h>
+#include <frame/protocol.h>
+#include <frame/req.h>
+#include <frame/httpact.h>
+#include <frame/servact.h>
+
+#include <libmsgdisp/orb.h>
+#include <libmsgdisp/nsarray.h>
+#include <libmsgdisp/msgchnel.h>
+#include <libmsgdisp/mdbtree.h>
+#include <libmsgdisp/mdutil.h>
+
+#include <ssl.h>
+#include <nt/magnus.h>
+
+typedef void * (SafFunction)();
+SafFunction **SafTable;
+__declspec(dllexport) int InitSafTable(SafFunction *Table);
+
+/* Functions from ntbuffer.c */
+
+#define FILEBUF_OPEN 1
+#define NETBUF_OPEN 2
+#define FILEBUF_OPEN_NOSTAT 3
+
+#define PIPEBUF_OPEN 4
+#define PIPEBUF_CLOSE 5
+#define FILEBUF_NEXT 6
+#define NETBUF_NEXT 7
+
+#define PIPEBUF_NEXT 8
+#define FILEBUF_CLOSE 9
+#define NETBUF_CLOSE 10
+#define FILEBUF_GRAB 11
+#define NETBUF_GRAB 12
+#define PIPEBUF_GRAB 13
+#define NETBUF_BUF2SD 14
+#define FILEBUF_BUF2SD 15
+
+#define PIPEBUF_BUF2SD 16
+#define PIPEBUF_NETBUF2SD 17
+
+/* Functions from daemon.h */
+
+#define NTDAEMON_RUN 18
+#define CHILD_STATUS 19
+
+/* Functions from file.h */
+#define SYSTEM_FREAD 20
+#define SYSTEM_PREAD 21
+#define SYSTEM_FOPENRO 22
+#define SYSTEM_FOPENWA 23
+#define SYSTEM_FOPENRW 24
+#define SYSTEM_FCLOSE 25
+#define SYSTEM_NOCOREDUMPS 26
+#define SYSTEM_FWRITE 27
+#define SYSTEM_FWRITE_ATOMIC 28
+#define SYSTEM_WINERR 29
+#define SYSTEM_WINSOCKERR 30
+#define FILE_NOTFOUND 31
+#define SYSTEM_STAT 32
+#define SYSTEM_INITLOCK 33
+
+#define FILE_UNIX2LOCAL 34
+#define DIR_OPEN 35
+#define DIR_READ 36
+#define DIR_CLOSE 37
+
+/* Functions from sem.h */
+#define SEM_INIT 40
+#define SEM_TERMINATE 41
+#define SEM_GRAB 42
+#define SEM_TGRAB 43
+#define SEM_RELEASE 44
+
+/* Functions from session.h */
+#define SESSION_CREATE 45
+#define SESSION_FREE 46
+#define SESSION_DNS_LOOKUP 47
+
+/* Functions from cinfo.h */
+#define CINFO_INIT 70
+#define CINFO_TERMINATE 71
+#define CINFO_MERGE 72
+#define CINFO_FIND 73
+#define CINFO_LOOKUP 74
+#define CINFO_DUMP_DATABASE 75
+
+/* Functions from ereport.h */
+#define EREPORT 80
+#define EREPORT_INIT 81
+#define EREPORT_TERMINATE 82
+#define EREPORT_GETFD 83
+
+/* Functions from minissl.h */
+#define SSL_CLOSE 90
+#define SSL_SOCKET 91
+#define SSL_GET_SOCKOPT 92
+#define SSL_SET_SOCKOPT 93
+#define SSL_BIND 94
+#define SSL_LISTEN 95
+#define SSL_ACCEPT 96
+#define SSL_READ 97
+#define SSL_WRITE 98
+#define SSL_GETPEERNAME 99
+
+/* Functions from net.h */
+#define NET_BIND 110
+#define NET_READ 111
+#define NET_WRITE 112
+
+#define NET_FIND_FQDN 113
+#define NET_IP2HOST 114
+#define NET_SENDMAIL 115
+
+/* Functions from pblock.h */
+#define PARAM_CREATE 120
+#define PARAM_FREE 121
+#define PBLOCK_CREATE 122
+#define PBLOCK_FREE 123
+#define PBLOCK_FINDVAL 124
+#define PBLOCK_NVINSERT 125
+#define PBLOCK_NNINSERT 126
+#define PBLOCK_PINSERT 127
+#define PBLOCK_STR2PBLOCK 128
+#define PBLOCK_PBLOCK2STR 129
+#define PBLOCK_COPY 130
+#define PBLOCK_PB2ENV 131
+#define PBLOCK_FR 132
+
+/* Functions from systhr.h */
+#define SYSTHREAD_START 133
+#define SYSTHREAD_ATTACH 134
+#define SYSTHREAD_TERMINATE 135
+#define SYSTHREAD_SLEEP 136
+#define SYSTHREAD_INIT 137
+#define SYSTHREAD_NEWKEY 138
+#define SYSTHREAD_GETDATA 139
+#define SYSTHREAD_SETDATA 140
+
+/* Functions from shmem.h */
+#define SHMEM_ALLOC 141
+#define SHMEM_FREE 142
+
+/* Functions from eventlog.h */
+#define INITIALIZE_ADMIN_LOGGING 143
+#define INITIALIZE_HTTPD_LOGGING 144
+#define INITIALIZE_HTTPS_LOGGING 145
+
+#define TERMINATE_ADMIN_LOGGING 146
+#define TERMINATE_HTTPD_LOGGING 147
+#define TERMINATE_HTTPS_LOGGING 148
+
+#define LOG_ERROR_EVENT 149
+
+/* Functions from shexp.h */
+#define SHEXP_VALID 160
+#define SHEXP_MATCH 161
+#define SHEXP_CMP 162
+#define SHEXP_CASECMP 163
+
+/* Functions from systems.h */
+#define UTIL_STRCASECMP 170
+#define UTIL_STRNCASECMP 171
+
+/* Functions from util.h */
+#define UTIL_GETLINE 180
+#define UTIL_ENV_CREATE 181
+#define UTIL_ENV_STR 182
+#define NTUTIL_ENV_STR 183
+#define UTIL_ENV_REPLACE 184
+#define UTIL_ENV_FREE 185
+#define UTIL_ENV_FIND 186
+#define UTIL_HOSTNAME 187
+#define UTIL_CHDIR2PATH 188
+#define UTIL_IS_MOZILLA 189
+#define UTIL_IS_URL 190
+#define UTIL_LATER_THAN 191
+#define UTIL_URI_IS_EVIL 192
+#define UTIL_URI_PARSE 193
+#define UTIL_URI_UNESCAPE 194
+#define UTIL_URI_ESCAPE 195
+#define UTIL_URL_ESCAPE 196
+#define UTIL_SH_ESCAPE 197
+#define UTIL_ITOA 198
+#define UTIL_VSPRINTF 199
+#define UTIL_SPRINTF 200
+#define UTIL_VSNPRINTF 201
+#define UTIL_SNPRINTF 202
+
+/* Functions from magnus.h */
+#define MAGNUS_ATRESTART 203
+
+/* Functions from conf.h */
+#define CONF_INIT 207
+#define CONF_TERMINATE 208
+#define CONF_GETGLOBALS 209
+#define CONF_VARS2DAEMON 210
+
+/* Functions from req.h */
+#define REQUEST_CREATE 211
+#define REQUEST_FREE 212
+#define REQUEST_RESTART_INTERNAL 213
+#define REQUEST_TRANSLATE_URI 214
+#define REQUEST_HEADER 215
+#define REQUEST_STAT_PATH 216
+#define REQUEST_URI2PATH 217
+#define REQUEST_PATHCHECKS 218
+#define REQUEST_FILEINFO 219
+#define REQUEST_HANDLE_PROCESSED 220
+#define REQUEST_SERVICE 221
+#define REQUEST_HANDLE 222
+
+/* Functions from object.h */
+#define DIRECTIVE_NAME2NUM 223
+#define DIRECTIVE_NUM2NAME 224
+#define OBJECT_CREATE 225
+#define OBJECT_FREE 226
+#define OBJECT_ADD_DIRECTIVE 227
+#define OBJECT_EXECUTE 228
+
+/* Functions from objset.h */
+#define OBJSET_SCAN_BUFFER 230
+#define OBJSET_CREATE 231
+#define OBJSET_FREE 232
+#define OBJSET_FREE_SETONLY 233
+#define OBJSET_NEW_OBJECT 234
+#define OBJSET_ADD_OBJECT 235
+#define OBJSET_FINDBYNAME 236
+#define OBJSET_FINDBYPPATH 237
+
+/* Functions from http.h */
+#define HTTP_PARSE_REQUEST 240
+#define HTTP_SCAN_HEADERS 241
+#define HTTP_START_RESPONSE 242
+#define HTTP_HDRS2_ENV 243
+#define HTTP_STATUS 244
+#define HTTP_SET_FINFO 245
+#define HTTP_DUMP822 246
+#define HTTP_FINISH_REQUEST 247
+#define HTTP_HANDLE_SESSION 248
+#define HTTP_URI2URL 249
+
+/* Functions from func.h */
+#define FUNC_INIT 251
+#define FUNC_FIND 252
+#define FUNC_EXEC 253
+#define FUNC_INSERT 254
+
+/* Functions from log.h */
+#define LOG_ERROR 260
+
+/* robm Functions added in 2.0 */
+#define SYSTEM_FOPENWT 261
+#define SYSTEM_MALLOC 262
+#define SYSTEM_FREE 263
+#define SYSTEM_REALLOC 264
+#define SYSTEM_STRDUP 265
+
+#define UPLOAD_FILE 266
+
+#define CRIT_INIT 267
+#define CRIT_ENTER 268
+#define CRIT_EXIT 269
+#define CRIT_TERMINATE 270
+#define SYSTHREAD_CURRENT 271
+
+#define NET_ACCEPT 272
+#define NET_CLOSE 273
+#define NET_CONNECT 274
+#define NET_IOCTL 275
+#define NET_LISTEN 276
+#define NET_SETSOCKOPT 277
+#define NET_SOCKET 278
+
+/* Daryoush Functions added in 3.0 */
+#define NSORB_INIT 279
+#define NSORB_INST_ID 280
+#define NSORB_GET_INST 281
+#define NSORB_REG_INT 282
+#define NSORB_FIND_OBJ 283
+#define NSORB_GET_INTERFACE 284
+
+#define ARR_NEW 285
+#define ARR_FREE 286
+#define ARR_GET_OBJ 288
+#define ARR_GET_LAST_OBJ 289
+#define ARR_NEW_OBJ 290
+#define ARR_GET_NUM_OBJ 291
+#define ARR_RESET 292
+#define ARR_REMOVEOBJ 293
+#define ARR_GET_OBJ_NUM 294
+
+#define CM_BT_NEW 295
+#define CM_BT_ADD_NODE 296
+#define CM_BT_FIND_NODE 297
+#define CM_BT_DEL_NODE 298
+#define CM_BT_DESTROY 299
+#define CM_BT_GET_NUM 300
+#define CM_BT_TRAVEL 301
+
+#define CM_STR_NEW 302
+#define CM_STR_ADD 303
+#define CM_STR_REL 304
+#define CM_STR_FREE 305
+#define CM_STR_GET 306
+#define CM_STR_SIZE 307
+#define CM_COPY_STR 308
+#define CM_MAKE_UID 309
+
+#define MS_NEW 310
+#define MS_CREATE 311
diff --git a/include/nt/ntos.h b/include/nt/ntos.h
new file mode 100644
index 00000000..dce0efa0
--- /dev/null
+++ b/include/nt/ntos.h
@@ -0,0 +1,155 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/**********************************************************************
+ * ntOS.h - functionality used bt NT Operating System
+ *
+ **********************************************************************/
+
+#ifndef _ntos_h
+#define _ntos_h
+
+
+#ifdef __cplusplus
+extern "C" { /* Assume C declarations for C++ */
+#endif /* __cplusplus */
+
+#ifdef ISHIELD_DLL
+#define NS_WINAPI WINAPI
+#else
+#define NS_WINAPI
+#endif
+
+/* prototypes for info.c */
+typedef enum {
+ OS_WIN95,
+ OS_WINNT,
+ OS_WIN32S,
+ OS_UNKNOWN
+} OS_TYPE;
+
+typedef enum {
+ PROCESSOR_I386,
+ PROCESSOR_ALPHA,
+ PROCESSOR_MIPS,
+ PROCESSOR_PPC,
+ PROCESSOR_UNKNOWN
+} PROCESSOR_TYPE;
+
+OS_TYPE NS_WINAPI INFO_GetOperatingSystem ();
+DWORD NS_WINAPI INFO_GetOSMajorVersion ();
+DWORD NS_WINAPI INFO_GetOSMinorVersion ();
+void NS_WINAPI OS_GetComputerName (LPTSTR computerName, int nComputerNameLength );
+PROCESSOR_TYPE NS_WINAPI OS_GetProcessor ();
+DWORD NS_WINAPI INFO_GetOSServicePack ();
+
+
+/* prototypes for path.c */
+DWORD NS_WINAPI PATH_RemoveRelative ( char * path );
+DWORD NS_WINAPI PATH_ConvertNtSlashesToUnix( LPCTSTR lpszNtPath, LPSTR lpszUnixPath );
+DWORD NS_WINAPI PATH_GetNextFileInDirectory ( long hFile, char * path, char * lpFileName );
+DWORD NS_WINAPI PATH_GetNextSubDirectory( long hFile, char * path, char * lpSubDirectoryName, char * lpSubDirectoryPrefix );
+DWORD NS_WINAPI PATH_DeleteRecursively ( char * path );
+
+
+/* prototypes for registry.c */
+BOOL NS_WINAPI REG_CheckIfKeyExists( HKEY hKey, LPCTSTR registryKey );
+BOOL NS_WINAPI REG_CreateKey( HKEY hKey, LPCTSTR registryKey );
+BOOL NS_WINAPI REG_DeleteKey( HKEY hKey, LPCTSTR registryKey );
+BOOL NS_WINAPI REG_DeleteValue( HKEY hKey, LPCTSTR registryKey, LPCSTR valueName );
+
+BOOL NS_WINAPI
+REG_GetRegistryParameter(
+ HKEY hKey,
+ LPCTSTR registryKey,
+ LPTSTR QueryValueName,
+ LPDWORD ValueType,
+ LPBYTE ValueBuffer,
+ LPDWORD ValueBufferSize
+ );
+
+BOOL NS_WINAPI
+REG_SetRegistryParameter(
+ HKEY hKey,
+ LPCTSTR registryKey,
+ LPTSTR valueName,
+ DWORD valueType,
+ LPCTSTR ValueString,
+ DWORD valueStringLength
+ );
+
+BOOL NS_WINAPI
+REG_GetSubKeysInfo(
+ HKEY hKey,
+ LPCTSTR registryKey,
+ LPDWORD lpdwNumberOfSubKeys,
+ LPDWORD lpdwMaxSubKeyLength
+ );
+
+BOOL NS_WINAPI
+REG_GetSubKey( HKEY hKey,
+ LPCTSTR registryKey,
+ DWORD nSubKeyIndex,
+ LPTSTR registrySubKeyBuffer,
+ DWORD subKeyBufferSize
+ );
+
+/* prototypes for service.c */
+#define SERVRET_ERROR 0
+#define SERVRET_INSTALLED 1
+#define SERVRET_STARTING 2
+#define SERVRET_STARTED 3
+#define SERVRET_STOPPING 4
+#define SERVRET_REMOVED 5
+
+DWORD NS_WINAPI SERVICE_GetNTServiceStatus(LPCTSTR szServiceName, LPDWORD lpLastError );
+DWORD NS_WINAPI SERVICE_InstallNTService(LPCTSTR szServiceName, LPCTSTR szServiceDisplayName, LPCTSTR szServiceExe );
+DWORD NS_WINAPI SERVICE_ReinstallNTService(LPCTSTR szServiceName, LPCTSTR szServiceDisplayName, LPCTSTR szServiceExe );
+DWORD NS_WINAPI SERVICE_RemoveNTService(LPCTSTR szServiceName);
+DWORD NS_WINAPI SERVICE_StartNTService(LPCTSTR szServiceName);
+DWORD NS_WINAPI SERVICE_StartNTServiceAndWait(LPCTSTR szServiceName, LPDWORD lpdwLastError);
+DWORD NS_WINAPI SERVICE_StopNTService(LPCTSTR szServiceName);
+DWORD NS_WINAPI SERVICE_StopNTServiceAndWait(LPCTSTR szServiceName, LPDWORD lpdwLastError);
+
+
+/* prototypes for pmddeml.c */
+DWORD PMDDEML_Open ( void );
+BOOL PMDDEML_Close ( DWORD idInst );
+BOOL PMDDEML_CreateProgramManagerGroup ( DWORD idInst, LPCTSTR lpszGroupName );
+BOOL PMDDEML_DeleteProgramManagerGroup ( DWORD idInst, LPCTSTR lpszGroupName );
+BOOL PMDDEML_ShowProgramManagerGroup ( DWORD idInst, LPCTSTR lpszGroupName );
+BOOL PMDDEML_AddIconToProgramManagerGroup ( DWORD idInst, LPCTSTR lpszCmdLine,
+ LPCTSTR lpszTitle, LPCTSTR lpszIconPath, LPCTSTR lpszWorkingDir,
+ BOOL bReplace );
+BOOL PMDDEML_CreateProgramManagerCommonGroup ( DWORD idInst,
+ LPCTSTR lpszGroupName );
+BOOL PMDDEML_DeleteProgramManagerCommonGroup ( DWORD idInst,
+ LPCTSTR lpszGroupName );
+BOOL PMDDEML_ShowProgramManagerCommonGroup ( DWORD idInst,
+ LPCTSTR lpszGroupName );
+BOOL PMDDEML_DeleteIconInProgramManagerGroup ( DWORD idInst, LPCTSTR lpszTitle );
+BOOL PMDDEML_GetProgramGroupInfo(DWORD idInst, LPSTR lpProgramGroup, char *szBuffer, DWORD cbBuffer);
+
+/* prototypes for tcpip.c */
+#define TCPIP_NO_ERROR 0
+#define TCPIP_UNSUPPORTED_OS 1
+#define TCPIP_NO_WINSOCK_DLL 2
+#define TCPIP_NO_TCPIP 3
+#define TCPIP_NETWORK_DOWN 4 /* The Windows Sockets implementation has detected that the network subsystem has failed. */
+#define TCPIP_NETWORK_ERROR 5
+#define TCPIP_HOST_NOT_FOUND 6 /* Authoritative Answer Host not found. */
+#define TCPIP_HOST_SERVER_DOWN 7 /* Non-Authoritative Host not found, or SERVERFAIL */
+#define TCPIP_HOST_VALID_NAME 8 /* Valid name, no data record of requested type. */
+
+DWORD NS_WINAPI
+TCPIP_GetDefaultHostName( LPTSTR lpszFullHostName, LPTSTR lpszHostName, LPTSTR lpszDomainName );
+DWORD NS_WINAPI TCPIP_VerifyHostName( LPCTSTR lpszHostName );
+
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif
diff --git a/include/nt/regparms.h b/include/nt/regparms.h
new file mode 100644
index 00000000..418e60b0
--- /dev/null
+++ b/include/nt/regparms.h
@@ -0,0 +1,586 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+// //
+// Name: regparms.h //
+// Platforms: WIN32 //
+// ...................................................................... //
+// This module contains registry key definations used throughout the //
+// server. //
+// ...................................................................... //
+// Revision History: //
+// 01-12-95 Initial Version, Aruna Victor (aruna@netscape.com) //
+// 12-19-96 3.0 registry changes, Andy Hakim (ahakim@netscape.com) //
+// 07-24-97 3.5 registry changes, Ted Byrd (tbyrd@netscape.com) //
+// 09-28-97 4.0 registry changes, Glen Beasley (gbeasley@netscape.com) //
+//--------------------------------------------------------------------------//
+#define KEY_COMPANY "Netscape"
+#define KEY_APP_PATH "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths"
+#define KEY_RUN_ONCE "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\RunOnce"
+#define KEY_SERVICES "SYSTEM\\CurrentControlSet\\Services"
+#define KEY_SNMP_SERVICE "SNMP\\Parameters\\ExtensionAgents"
+#define KEY_SNMP_CURRENTVERSION "SNMP\\CurrentVersion"
+#define KEY_EVENTLOG_MESSAGES "EventLogMessages"
+#define KEY_EVENTLOG_APP "EventLog\\Application"
+#define KEY_SOFTWARE_NETSCAPE "SOFTWARE\\Netscape"
+#define VALUE_IMAGE_PATH "ImagePath"
+#define VALUE_CONFIG_PATH "ConfigurationPath"
+#define VALUE_ROOT_PATH "RootPath"
+#define VALUE_APP_PATH "Pathname"
+#define PROGRAM_GROUP_NAME "Netscape SuiteSpot"
+#define STR_PRODUCT_TYPE "Server"
+#define STR_EXE ".exe"
+#define STR_COMPANY_PREFIX "ns-"
+
+/* SuiteSpot IDs */
+#define NSS_NAME_SHORT "SuiteSpot"
+#define NSS_VERSION "6.0"
+#define NSS_NAME_VERSION "SuiteSpot 6.0"
+#define NSS_NAME_FULL "Netscape SuiteSpot"
+#define NSS_NAME_FULL_VERSION "Netscape SuiteSpot 6.0"
+#define NSS_NAME_UNINSTALL "Uninstall SuiteSpot 6.0"
+
+/* Admin IDs */
+#define ADM_ID_PRODUCT "admin"
+#define ADM_NAME_SHORT "Administration"
+#define ADM_VERSION "6.0"
+#define ADM_NAME_VERSION "Administration 6.0"
+#define ADM_NAME_SERVER "Administration Server"
+#define ADM_NAME_FULL "Netscape Administration Server"
+#define ADM_NAME_FULL_VERSION "Netscape Administration Server 6.0"
+#define ADM_NAME_SERVICE "Netscape Administration 6.0"
+#define ADM_EXE "ns-admin.exe"
+#define ADM_EXE_START "admin.exe"
+#define ADM_ID_SERVICE "admin60"
+#define ADM_KEY_ROOT "Administration\\6.0"
+#define ADM_SERVER_LST_NAME "adm:Netscape Enterprise Server"
+#define ADM_DIR_ROOT "admin"
+#define ADM_NAME_UNINSTALL "Uninstall Administration Server 6.0"
+
+#if defined( NS_DS )
+#define ADMIN_SERVICE_NAME "Admin Server"
+#define ADMIN_ICON_NAME "Administer Netscape Servers"
+#endif
+
+/* Enterprise IDs */
+#define ENT_ID_PRODUCT "https"
+#define ENT_NAME_SHORT "Enterprise"
+#define ENT_VERSION "3.01"
+#define ENT_NAME_VERSION "Enterprise 3.01"
+#define ENT_NAME_SERVER "Enterprise Server"
+#define ENT_NAME_FULL "Netscape Enterprise Server"
+#define ENT_NAME_FULL_VERSION "Netscape Enterprise Server 3.01"
+#define ENT_NAME_SERVICE "Netscape Enterprise 3.01"
+#define ENT_EXE "ns-httpd.exe"
+#define ENT_EXE_START "httpd.exe"
+#define ENT_ID_SERVICE "https"
+#define ENT_KEY_ROOT "Enterprise\\3.01"
+#define ENT_SERVER_LST_NAME "https:Netscape Enterprise Server"
+#define ENT_DIR_ROOT "https"
+#define ENT_NAME_UNINSTALL "Uninstall Enterprise Server 3.01"
+
+/* Personal IDs */
+#define PERSONAL_APP_PATH_KEY "ns-httpd.exe"
+#define PERSONAL_README_ICON_NAME "FastTrack README"
+#define PERSONAL_REGISTRY_ROOT_KEY "Httpd Server"
+#define PERSONAL_SERVER_LST_NAME "httpd:Netscape FastTrack Server"
+#define PERSONAL_UNINSTALL_ICON_NAME "Uninstall FastTrack"
+#define PERSONAL_UNINSTALL_KEY "FastTrackV2.0"
+#define PERSONAL_SERVER_NAME "Netscape FastTrack Server"
+
+
+
+
+#define PER_ID_PRODUCT "httpd"
+#define PER_NAME_SHORT "FastTrack"
+#define PER_VERSION "3.01"
+#define PER_NAME_VERSION "FastTrack 3.01"
+#define PER_NAME_SERVER "FastTrack Server"
+#define PER_NAME_FULL "Netscape FastTrack Server"
+#define PER_NAME_FULL_VERSION "Netscape FastTrack Server 3.01"
+#define PER_NAME_SERVICE "Netscape FastTrack 3.01"
+#define PER_EXE "ns-httpd.exe"
+#define PER_EXE_START "httpd.exe"
+#define PER_ID_SERVICE "httpd"
+#define PER_KEY_ROOT "FastTrack\\3.01"
+#define PER_SERVER_LST_NAME "httpd:Netscape FastTrack Server"
+#define PER_DIR_ROOT "httpd"
+#define PER_NAME_UNINSTALL "Uninstall FastTrack Server 3.01"
+
+/* Proxy IDs */
+#define PRX_ID_PRODUCT "proxy"
+#define PRX_NAME_SHORT "Proxy"
+#define PRX_VERSION "3.0"
+#define PRX_NAME_VERSION "Proxy 3.0"
+#define PRX_NAME_SERVER "Proxy Server"
+#define PRX_NAME_FULL "Netscape Proxy Server"
+#define PRX_NAME_FULL_VERSION "Netscape Proxy Server 3.0"
+#define PRX_NAME_SERVICE "Netscape Proxy 3.0"
+#define PRX_EXE "ns-proxy.exe"
+#define PRX_EXE_START "proxy.exe"
+#define PRX_ID_SERVICE "proxy30"
+#define PRX_KEY_ROOT "Proxy\\3.0"
+#define PRX_SERVER_LST_NAME "proxy:Netscape Proxy Server"
+#define PRX_DIR_ROOT "proxy"
+#define PRX_NAME_UNINSTALL "Uninstall Proxy Server 3.0"
+
+/* Catalog IDs */
+#define CATALOG_SHORT_NAME "Catalog"
+#define CATALOG_SERVER_NAME "Netscape Catalog Server"
+#define CATALOG_SERVER_VERSION "1.0"
+#define CATALOG_SETUP_SHORT_NAME "Catalog Server"
+#define CATALOG_SETUP_NAME "Netscape Catalog Server 1.0"
+#define CATALOG_REGISTRY_ROOT_KEY "Catalog Server"
+#define CATALOG_EXE "ns-httpd.exe"
+#define CATALOG_DIR_ROOT "catalog"
+#define CATALOG_APP_PATH_KEY "ns-catalog"
+#define CATALOG_UNINSTALL_KEY "CatalogV1.0"
+#define CATALOG_SERVER_LST_NAME "catalog:Netscape Catalog Server"
+#define CATALOG_SERVICE_PREFIX "Netscape Catalog Server "
+#define CATALOG_README_ICON_NAME "Catalog README"
+#define CATALOG_UNINSTALL_ICON_NAME "Uninstall Catalog"
+#define CATALOG_PRODUCT_NAME "catalog"
+
+/* RDS IDs */
+#define RDS_SHORT_NAME "RDS"
+#define RDS_SERVER_NAME "Netscape RDS Server"
+#define RDS_SERVER_VERSION "1.0"
+#define RDS_SETUP_SHORT_NAME "RDS Server"
+#define RDS_SETUP_NAME "Netscape RDS Server 1.0"
+#define RDS_REGISTRY_ROOT_KEY "RDS Server"
+#define RDS_EXE "ns-httpd.exe"
+#define RDS_DIR_ROOT "rds"
+#define RDS_APP_PATH_KEY "ns-rds"
+#define RDS_UNINSTALL_KEY "RdsV1.0"
+#define RDS_SERVER_LST_NAME "rds:Netscape RDS Server"
+#define RDS_SERVICE_PREFIX "Netscape RDS Server "
+#define RDS_README_ICON_NAME "Rds README"
+#define RDS_UNINSTALL_ICON_NAME "Uninstall RDS"
+#define RDS_PRODUCT_NAME "rds"
+
+/* News IDs */
+#define NEWS_SHORT_NAME "News"
+/* Alpha #define NEWS_SERVER_NAME "Netscape News Server (tm) " */
+/* Alpha #define NEWS_SETUP_NAME "Netscape News Server (tm) " */
+/* Alpha #define NEWS_UNINSTALL_KEY "NewsV1.2" */
+#define NEWS_SERVER_NAME "Netscape News Server"
+#define NEWS_SERVER_VERSION "2.0"
+#define NEWS_UNINSTALL_KEY "NetscapeNewsV2.0"
+#define NEWS_SETUP_SHORT_NAME "News Server"
+#define NEWS_SETUP_NAME "Netscape News Server"
+#define NEWS_REGISTRY_ROOT_KEY "News Server" // key under SW/Netscape
+#define NEWS_EXE "nnrpd.exe" // value for <No name>
+#define NEWS_DIR_ROOT "news" // mess.dll in Reg, and in .lst
+#define NEWS_APP_PATH_KEY "innd.exe" // key under app paths
+#define NEWS_SERVER_LST_NAME "news:Netscape News Server"
+#define NEWS_SERVICE_PREFIX "Netscape News Server "
+#define NEWS_README_ICON_NAME "News Readme"
+#define NEWS_UNINSTALL_ICON_NAME "Uninstall News"
+
+/* Mail IDs */
+/* When we integrate the core & admin servers installation processes */
+/* we will use the code below instead of the section following it. */
+
+/*
+#define MAIL_SHORT_NAME "Mail"
+#define MAIL_SERVER_NAME "Netscape Mail Server (tm)"
+#define MAIL_SERVER_VERSION "2.0"
+#define MAIL_SETUP_SHORT_NAME "Mail Server"
+#define MAIL_SETUP_NAME "Netscape Mail Server (tm)"
+#define MAIL_REGISTRY_ROOT_KEY "Mail Server" // key under SW/Netscape
+#define MAIL_EXE "NetscapeMTA.exe" // value for <No name>
+#define MAIL_DIR_ROOT "mail" // mess.dll in Reg, and in .lst
+#define MAIL_APP_PATH_KEY "NetscapeMTA.exe" // key under app paths
+#define MAIL_UNINSTALL_KEY "MailV2.0"
+#define MAIL_SERVER_LST_NAME "mail:Netscape Mail Server"
+#define MAIL_SERVICE_PREFIX "Netscape Mail Server "
+#define MAIL_README_ICON_NAME "Mail Readme"
+#define MAIL_UNINSTALL_ICON_NAME "Uninstall Mail"
+*/
+
+#define MAIL_SHORT_NAME "Admin"
+#define MAIL_SERVER_NAME "Netscape Administration Server (tm)"
+#define MAIL_SERVER_VERSION "2.0"
+#define MAIL_SETUP_SHORT_NAME "Admin Server"
+#define MAIL_SETUP_NAME "Netscape Administration Server (tm)"
+#define MAIL_REGISTRY_ROOT_KEY "Mail Server" // key under SW/Netscape
+#define MAIL_EXE "NetscapeMTA.exe" // value for <No name>
+#define MAIL_DIR_ROOT "mail" // mess.dll in Reg, and in .lst
+#define MAIL_APP_PATH_KEY "NetscapeMTA.exe" // key under app paths
+#define MAIL_UNINSTALL_KEY "MailV2.0"
+#define MAIL_SERVER_LST_NAME "mail:Netscape Mail Server"
+#define MAIL_SERVICE_PREFIX "Netscape Admin Server "
+#define MAIL_README_ICON_NAME "Mail Readme"
+#define MAIL_UNINSTALL_ICON_NAME "Uninstall Mail"
+
+/* Synchronization Service IDs */
+#define DSS_SHORT_NAME "Directory Synchronization Service"
+#define DSS_SERVER_NAME "Netscape Directory Synchronization Service"
+#define DSS_SERVER_VERSION "7"
+#define DSS_SETUP_SHORT_NAME "Netscape Synchronization Service"
+#define DSS_SETUP_NAME "Netscape Directory Synchronization Service 7"
+#define DSS_REGISTRY_ROOT_KEY "Directory Synchronization Service"
+#define DSS_EXE "dssynch.exe"
+#define DSS_DIR_ROOT "dssynch"
+#define DSS_APP_PATH_KEY "dssynch.exe"
+#define DSS_CONFIG_TOOL "synchcfg.exe"
+#define DSS_UNINSTALL_KEY "SynchronizationV7"
+#define DSS_SERVER_LST_NAME "dssynch:Netscape Directory Synchronization Service"
+#define DSS_SERVICE_PREFIX "Netscape Directory Synchronization Service "
+#define DSS_README_ICON_NAME "Directory Synchronization Service README"
+#define DSS_CONFIG_ICON_NAME "Directory Synchronization Service Config"
+#define DSS_UNINSTALL_ICON_NAME "Uninstall Directory Synch Service"
+#define DSS_PRODUCT_NAME "dssynch"
+#define DSS_ID_PRODUCT DSS_PRODUCT_NAME
+#define DS_COMPONENT 1
+
+/* IDs needed for Directory 102/30 synchservice */
+#define ADMIN_APP_PATH_KEY "ns-admin.exe"
+#define ADMIN_EXE "ns-admin.exe"
+#define ADMIN_REGISTRY_ROOT_KEY "admin.exe"
+#define ADMSERV_COMPRESSED_FILE "admserv.z"
+#define APPBASE_DIR95 "Program Files"
+#define APPBASE_PATH "Netscape"
+#define APP_PATH_KEY "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths"
+#define BASE_REGISTRY95 "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\"
+#define BASE_REGISTRYNT "Software\\Microsoft\\Windows NT\\CurrentVersion\\App Paths\\"
+#define CMS_COMPRESSED_FILE "certsvr.z"
+#define CMS_DIR_ROOT "cms"
+#define CMS_SHORT_NAME "Certificate Server"
+#define CMS_APP_PATH_KEY "libcms.dll"
+#define CMS_UNINSTALL_KEY "CertificateV1.0"
+#define CMS_UNINSTALL_ICON_NAME "Uninstall CertServer"
+#define UPGRADE_VER_1_ICON_NAME "Upgrade 1.1x Servers"
+#define CMS_README_ICON_NAME "CertServer README"
+#define CMS_REGISTRY_ROOT_KEY "Certificate Server"
+#define CMS_SERVER_NAME "Netscape Certificate Server"
+#define CMS_SERVER_LST_NAME "cms:Netscape Certificate Server"
+#define COMPANY_NAME "Netscape"
+#define DIR_HTTPD_SERVER DSS_DIR_ROOT
+#define DSS_COMPRESSED_FILE "dssynch.z"
+#define DSS_COMPRESSED_HELP_FILE "hdssynch.z"
+#define DS_COMPRESSED_FILE "slapd.z"
+#define ENTERPRISE_APP_PATH_KEY "ns-https.exe"
+#define ENTERPRISE_README_ICON_NAME "Enterprise README"
+#define ENTERPRISE_REGISTRY_ROOT_KEY "Https Server"
+#define ENTERPRISE_SERVER_LST_NAME "https:Netscape Enterprise Server"
+#define ENTERPRISE_SERVER_NAME "Netscape Enterprise Server"
+#define ENTERPRISE_UNINSTALL_KEY "EnterpriseV2.0"
+#define ENTERPRISE_UNINSTALL_ICON_NAME "Uninstall Enterprise"
+#define ENTERPRISE_DIR_ROOT "https"
+#define ENTERPRISE_SHORT_NAME "Enterprise"
+#define EXTRAS_COMPRESSED_FILE "extras.z"
+#define HTTP_SERVER_NAME DSS_DIR_ROOT
+#define INSTALL_COMPRESSED_FILE "install.z"
+#define LIVEWIRE_COMPRESSED_FILE "wire.z"
+#define NSAPI_COMPRESSED_FILE "nsapi.z"
+#define PERSONAL_DIR_ROOT "httpd"
+#define PERSONAL_SHORT_NAME "FastTrack"
+#define PLUGINS_COMPRESSED_FILE "plugins.z"
+#define REGISTRY_ROOT_PATH_KEY "Path"
+#define SERVDLLS_COMPRESSED_FILE "servdlls.z"
+#define SERVER_APP_PATH_KEY DSS_APP_PATH_KEY
+#define SERVER_COMPRESSED_FILE "server.z"
+#define SERVER_EXE DSS_EXE
+#define SERVER_LIST_NAME DSS_SERVER_LST_NAME
+#define SERVER_PRODUCT_NAME DSS_REGISTRY_ROOT_KEY
+#define SERVER_PRODUCT_VERSION DSS_VERSION_DEF
+#define SERVER_README_ICON_NAME DSS_README_ICON_NAME
+#define SERVER_UNINSTALL_ICON_NAME DSS_UNINSTALL_ICON_NAME
+#define SETUP_NAME DSS_SETUP_NAME
+#define SETUP_SHORT_NAME DSS_SHORT_NAME
+#define SETUP_TITLE_WIN95_BMP "titleNTb.bmp"
+#define SETUP_TITLE_WINNT_BMP "titledss.bmp"
+#define SOFTWARE_NETSCAPE_KEY "SOFTWARE\\Netscape"
+#define NETSCAPE_WEB_KEY "Netscape Web Servers"
+#define NETSCAPE_SERVICE_KEY "SYSTEM\\CurrentControlSet\\Services"
+
+#define SYSDLLS_COMPRESSED_FILE "ssdlls.z"
+#define UNINSTALL_KEY DSS_UNINSTALL_KEY
+#define UNINSTALL_REGISTRY95 "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
+// NT SNMP Extension Agent registry entries
+#define SNMP_SERVICE_KEY "SYSTEM\\CurrentControlSet\\Services\\SNMP\\Parameters\\ExtensionAgents\\"
+#define SNMP_AGENT_KEY "HTTP SNMP Agent"
+#define SNMP_CURRENT_VERSION "CurrentVersion"
+#define SNMP_PATHNAME "Pathname"
+#define SNMP_DLL_PATH "bin\\https\\httpsnmp.dll"
+#define SNMP_SERVICE_NAME "SNMP"
+// end synch service
+
+#define LICENSE_TXT "license.txt"
+
+#define UNINST_EXE "unslapd.exe"
+#define DSS_UNINST_EXE "unsynch.exe"
+
+#define DIR_ADMSERV_SERVER "admserv"
+
+#define COPY_READMEFILES "Copying readme files..."
+#define COPY_SYSDLLFILES "Copying Shared System files..."
+#define COPY_SERVDLLFILES "Copying Shared Server files..."
+#define COPY_SERVERFILES "Copying web server files..."
+#define COPY_ADMINFILES "Copying administration server files..."
+#define COPY_EXTRASFILES "Copying CGI Example and Log Analyzer Files..."
+#define COPY_INSTALLFILES "Copying Version 1.1x upgrade files..."
+#define COPY_NSAPIFILES "Copying NSAPI Library and Examples Files..."
+#define COPY_PLUGINSFILES "Copying Plug-in Files..."
+#define COPY_LIVEWIREFILES "Copying LiveWire Files..."
+#define INSTALL_LIVEWIREFILES "Installing LiveWire Server Extension files..."
+#define INSTALL_CMSFILES "Installing Certificate Server files..."
+#define INSTALL_DSFILES "Installing Directory Server files..."
+#define INSTALL_DSSFILES "Installing Directory Synchronization Service files..."
+#define INSTALL_DSSHELPFILES "Installing Directory Synchronization Service Help files..."
+
+#define STR_DEFTAB " "
+/* end temp ds102 IDs */
+
+
+/* Directory IDs */
+/* NOTES:
+ dboreham: I have no idea what is going on below:
+ we seem to be using two completely different sets of defines.
+ This needs sorted out
+ ryamaura: The first group is there only to ensure that
+ nothing breaks. The second group conforms to the rest of
+ the SuiteSpot servers and should be the final form.
+*/
+#define DS_SHORT_NAME "Directory Server"
+#define DS_SERVER_NAME "Netscape Directory Server"
+#define DS_SERVER_VERSION "7"
+#define DS_SETUP_SHORT_NAME "Directory Server"
+#define DS_SETUP_NAME "Netscape Directory Server 7"
+#define DS_REGISTRY_ROOT_KEY "Directory Server"
+#define DS_APP_PATH_KEY "ns-slapd.exe"
+#define DS_UNINSTALL_KEY "DirectoryV7"
+#define DS_SERVICE_PREFIX "Netscape Directory Server "
+#define DS_README_ICON_NAME "Directory Server 7 README"
+#define DS_UNINSTALL_ICON_NAME "Uninstall Directory Server 7"
+#define DS_PRODUCT_NAME "slapd"
+
+#define DS_ID_PRODUCT "slapd"
+#define DS_NAME_SHORT "Directory"
+#define DS_VERSION_OLD "3.0"
+#undef DS_VERSION
+#define DS_VERSION "7"
+#define DS_NAME_VERSION "Directory 7"
+#define DS_NAME_SERVER "Directory Server"
+#define DS_NAME_FULL "Netscape Directory Server"
+#define DS_NAME_FULL_VERSION "Netscape Directory Server 7"
+#define DS_NAME_SERVICE "Netscape Directory 7"
+#define DS_EXE "ns-slapd.exe"
+#define DS_EXE_START "slapd.exe"
+#define DS_ID_SERVICE "slapd"
+#define DS_KEY_ROOT "Directory\\7"
+#define DS_KEY_ROOT_OLD "Directory\\3.0"
+#define DS_SERVER_LST_NAME "slapd:Netscape Directory Server"
+#define DS_DIR_ROOT "slapd"
+#define DS_NAME_UNINSTALL "Uninstall Directory Server 7"
+#define DS_SNMP_PATH "bin\\slapd\\server\\ns-ldapagt.dll"
+#define DS_OPTIONS "Select the installation option from below"
+#define DS_OPTIONS_TITLE "Directory Server Installions Options"
+#define DS_GENERAL_OPTIONS DS_NAME_SERVER
+
+
+#ifndef DS_COMPONENT
+#define DS_COMPONENT 1
+#endif
+
+/* original definitions */
+// Upper-level registry parameters
+/* Note: the followin MCC_ are not defined when this file is included
+ for the NT setup.rul file. Beware of using the following definitions in NT
+ - nirmal
+*/
+#if defined(MCC_ADMSERV)
+
+#define SERVICE_NAME ADM_ID_SERVICE
+#define EVENTLOG_APPNAME ADM_NAME_VERSION
+#define SERVICE_EXE ADM_EXE
+#define SERVICE_PREFIX ADM_NAME_VERSION
+#define SVR_ID_PRODUCT ADM_ID_PRODUCT
+#define SVR_NAME_SHORT ADM_NAME_SHORT
+#define SVR_VERSION ADM_VERSION
+#define SVR_NAME_VERSION ADM_NAME_VERSION
+#define SVR_NAME_SERVER ADM_NAME_SERVER
+#define SVR_NAME_FULL ADM_NAME_FULL
+#define SVR_NAME_FULL_VERSION ADM_NAME_FULL_VERSION
+#define SVR_NAME_SERVICE ADM_NAME_SERVICE
+#define SVR_EXE ADM_EXE
+#define SVR_EXE_START ADM_EXE_START
+#define SVR_ID_SERVICE ADM_ID_SERVICE
+#define SVR_KEY_ROOT ADM_KEY_ROOT
+#define SVR_SERVER_LST_NAME ADM_SERVER_LST_NAME
+#define SVR_DIR_ROOT ADM_DIR_ROOT
+#define SVR_NAME_UNINSTALL ADM_NAME_UNINSTALL
+
+#elif defined(NS_ENTERPRISE)
+
+#define PRODUCT_KEY ENT_KEY_ROOT
+#define PRODUCT_NAME ENT_ID_PRODUCT
+#define EVENTLOG_APPNAME ENT_NAME_VERSION
+#define SERVICE_PREFIX ENT_NAME_VERSION
+#define SVR_ID_PRODUCT ENT_ID_PRODUCT
+#define SVR_NAME_SHORT ENT_NAME_SHORT
+#define SVR_VERSION ENT_VERSION
+#define SVR_NAME_VERSION ENT_NAME_VERSION
+#define SVR_NAME_SERVER ENT_NAME_SERVER
+#define SVR_NAME_FULL ENT_NAME_FULL
+#define SVR_NAME_FULL_VERSION ENT_NAME_FULL_VERSION
+#define SVR_NAME_SERVICE ENT_NAME_SERVICE
+#define SVR_EXE ENT_EXE
+#define SVR_EXE_START ENT_EXE_START
+#define SVR_ID_SERVICE ENT_ID_SERVICE
+#define SVR_KEY_ROOT ENT_KEY_ROOT
+#define SVR_SERVER_LST_NAME ENT_SERVER_LST_NAME
+#define SVR_DIR_ROOT ENT_DIR_ROOT
+#define SVR_NAME_UNINSTALL ENT_NAME_UNINSTALL
+
+#elif defined(NS_PROXY)
+
+#define PRODUCT_KEY PRX_KEY_ROOT
+#define PRODUCT_NAME PRX_ID_PRODUCT
+#define EVENTLOG_APPNAME PRX_NAME_VERSION
+#define SERVICE_PREFIX PRX_NAME_VERSION
+#define SVR_ID_PRODUCT PRX_ID_PRODUCT
+#define SVR_NAME_SHORT PRX_NAME_SHORT
+#define SVR_VERSION PRX_VERSION
+#define SVR_NAME_VERSION PRX_NAME_VERSION
+#define SVR_NAME_SERVER PRX_NAME_SERVER
+#define SVR_NAME_FULL PRX_NAME_FULL
+#define SVR_NAME_FULL_VERSION PRX_NAME_FULL_VERSION
+#define SVR_NAME_SERVICE PRX_NAME_SERVICE
+#define SVR_EXE PRX_EXE
+#define SVR_EXE_START PRX_EXE_START
+#define SVR_ID_SERVICE PRX_ID_SERVICE
+#define SVR_KEY_ROOT PRX_KEY_ROOT
+#define SVR_SERVER_LST_NAME PRX_SERVER_LST_NAME
+#define SVR_DIR_ROOT PRX_DIR_ROOT
+#define SVR_NAME_UNINSTALL PRX_NAME_UNINSTALL
+
+#elif defined(NS_CATALOG)
+
+#define PRODUCT_KEY CATALOG_REGISTRY_ROOT_KEY // CKA (should use key above)
+#define PRODUCT_NAME "catalog"
+#define EVENTLOG_APPNAME "NetscapeCatalog"
+#define SERVICE_PREFIX CATALOG_SERVICE_PREFIX
+
+#elif defined(NS_RDS)
+
+#define PRODUCT_KEY RDS_REGISTRY_ROOT_KEY // CKA (should use key above)
+#define PRODUCT_NAME "rds"
+#define EVENTLOG_APPNAME "NetscapeRds"
+#define SERVICE_PREFIX RDS_SERVICE_PREFIX
+
+#elif defined(NS_PERSONAL)
+
+#define PRODUCT_KEY PER_KEY_ROOT
+#define PRODUCT_NAME PER_ID_PRODUCT
+#define EVENTLOG_APPNAME PER_NAME_VERSION
+#define SERVICE_PREFIX PER_NAME_VERSION
+#define SVR_ID_PRODUCT PER_ID_PRODUCT
+#define SVR_NAME_SHORT PER_NAME_SHORT
+#define SVR_VERSION PER_VERSION
+#define SVR_NAME_VERSION PER_NAME_VERSION
+#define SVR_NAME_SERVER PER_NAME_SERVER
+#define SVR_NAME_FULL PER_NAME_FULL
+#define SVR_NAME_FULL_VERSION PER_NAME_FULL_VERSION
+#define SVR_NAME_SERVICE PER_NAME_SERVICE
+#define SVR_EXE PER_EXE
+#define SVR_EXE_START PER_EXE_START
+#define SVR_ID_SERVICE PER_ID_SERVICE
+#define SVR_KEY_ROOT PER_KEY_ROOT
+#define SVR_SERVER_LST_NAME PER_SERVER_LST_NAME
+#define SVR_DIR_ROOT PER_DIR_ROOT
+#define SVR_NAME_UNINSTALL PER_NAME_UNINSTALL
+
+#elif defined(NS_DSS)
+
+#define PRODUCT_KEY DSS_REGISTRY_ROOT_KEY // CKA (should use key above)
+#define PRODUCT_NAME "dssynch"
+#define EVENTLOG_APPNAME "NetscapeDirSynchService"
+#define SERVICE_PREFIX DSS_SERVICE_PREFIX
+
+#elif defined(NS_DS)
+
+#define PRODUCT_BIN "ns-slapd"
+#define SLAPD_EXE "slapd.exe"
+#define SERVICE_EXE SLAPD_EXE
+#define SLAPD_CONF "slapd.conf"
+#define SLAPD_DONGLE_FILE "password.dng"
+#define DONGLE_FILE_NAME SLAPD_DONGLE_FILE
+
+#define PRODUCT_KEY DS_REGISTRY_ROOT_KEY
+#define PRODUCT_NAME DS_ID_PRODUCT
+#define EVENTLOG_APPNAME DS_NAME_VERSION
+#define SERVICE_PREFIX DS_NAME_VERSION
+#define SVR_ID_PRODUCT DS_ID_PRODUCT
+#define SVR_NAME_SHORT DS_NAME_SHORT
+#define SVR_VERSION DS_VERSION
+#define SVR_VERSION_OLD DS_VERSION_OLD
+#define SVR_NAME_VERSION DS_NAME_VERSION
+#define SVR_NAME_SERVER DS_NAME_SERVER
+#define SVR_NAME_FULL DS_NAME_FULL
+#define SVR_NAME_FULL_VERSION DS_NAME_FULL_VERSION
+#define SVR_NAME_SERVICE DS_NAME_SERVICE
+#define SVR_EXE DS_EXE
+#define SVR_EXE_START DS_EXE_START
+#define SVR_ID_SERVICE DS_ID_SERVICE
+#define SVR_KEY_ROOT DS_KEY_ROOT
+#define SVR_SERVER_LST_NAME DS_SERVER_LST_NAME
+#define SVR_DIR_ROOT DS_DIR_ROOT
+#define SVR_NAME_UNINSTALL DS_NAME_UNINSTALL
+#define SNMP_PATH DS_SNMP_PATH
+
+#elif defined(NS_SETUP)
+#else
+
+#error SERVER TYPE NOT DEFINED
+
+#endif /* MCC_ADMSERV */
+
+// Do not move this section. This has to come immediately after the
+// ifdef section above - Nirmal
+//
+#if defined(MCC_NEWS) // Nirmal : added for news 2/21/95.
+#define PRODUCT_BIN "innd" // Redefine the generic ns-httpd.exe
+#define PRODUCT_KEY NEWS_REGISTRY_ROOT_KEY // CKA (should use key above)
+#define PRODUCT_NAME "news"
+#define EVENTLOG_APPNAME "NetscapeNews"
+#define SERVICE_PREFIX NEWS_SERVICE_PREFIX
+
+#endif
+
+
+#define VERSION_KEY "CurrentVersion"
+
+// Configuration Parameters
+
+#define SOFTWARE_KEY "Software"
+
+// NT Perfmon DLL entries
+#define KEY_PERFORMANCE "Performance"
+#define PERF_MICROSOFT_KEY "SOFTWARE\\Microsoft\\Windows NT\\Perflib\\009"
+#define PERF_COUNTER_KEY "Counter"
+#define PERF_HELP_KEY "Help"
+#define PERF_OPEN_FUNCTION "OpenNSPerformanceData"
+#define PERF_COLLECT_FUNCTION "CollectNSPerformanceData"
+#define PERF_CLOSE_FUNCTION "CloseNSPerformanceData"
+#define PERF_CTR_INI "nsctrs.ini"
+
+// this section used to be in confhttp.h. TODO: convert to SVR_ format -ahakim
+#if defined(NS_CATALOG)
+#define SERVER_REGISTRY_ROOT_KEY CATALOG_REGISTRY_ROOT_KEY
+#define SERVER_APP_PATH_KEY CATALOG_APP_PATH_KEY
+#define SERVER_DIR_ROOT CATALOG_DIR_ROOT
+#define SERVER_SETUP_NAME CATALOG_SETUP_NAME
+#define SERVER_SHORT_NAME CATALOG_SHORT_NAME
+
+#elif defined(NS_RDS)
+#define SERVER_REGISTRY_ROOT_KEY RDS_REGISTRY_ROOT_KEY
+#define SERVER_APP_PATH_KEY RDS_APP_PATH_KEY
+#define SERVER_DIR_ROOT RDS_DIR_ROOT
+#define SERVER_SETUP_NAME RDS_SETUP_NAME
+#define SERVER_SHORT_NAME RDS_SHORT_NAME
+
+#endif
diff --git a/include/nt/resource.h b/include/nt/resource.h
new file mode 100644
index 00000000..905cbeb6
--- /dev/null
+++ b/include/nt/resource.h
@@ -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 **/
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by netsite.rc
+//
+#define IDB_BITMAP1 101
+#define DLG_STARTUP_ERROR 101
+#define IDI_NETSITE 102
+#define IDI_ICON1 104
+#define DLG_GETPASSWORD 106
+#define IDI_ICON2 107
+#define IDD_PASSWORD 108
+#define IDI_KEY 109
+#define IDD_PIN 110
+#define IDEDIT 1000
+#define IDC_ERRORLOG 1001
+#define ID_EXIT 1001
+#define IDC_ERRORMSG 1002
+#define IDC_STARTUP_ERROR 1003
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 110
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1002
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
+
diff --git a/include/public/Makefile b/include/public/Makefile
new file mode 100644
index 00000000..9d291cae
--- /dev/null
+++ b/include/public/Makefile
@@ -0,0 +1,59 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Makefile for netsite.h
+
+MCOM_ROOT = ../../..
+MODULE=netsiteInclude
+
+include ../../nsdefs.mk
+
+HDRDEST=$(OBJDIR)/include
+
+PREFIX=../copyrght.h
+
+
+NOSTDSTRIP=true
+NOSTDDEPEND=true
+
+HDRS=netsite.h nsapi.h
+
+BINS=$(addprefix $(HDRDEST)/,$(HDRS))
+
+all: stuff
+
+strip:
+depend:
+
+include ../../nsconfig.mk
+
+ifeq ($(NSAPI_CAPABLE), true)
+
+stuff: $(HDRDEST) $(BINS) sub-hdrs
+
+$(HDRDEST):
+ mkdir -p $(HDRDEST)
+
+ifeq ($(PRODUCT), "Netscape Proxy Server")
+sub-hdrs:
+ cd base; $(MAKE) $(MAKEFLAGS)
+ cd frame; $(MAKE) $(MAKEFLAGS)
+ cd libproxy; $(MAKE) $(MAKEFLAGS)
+else
+sub-hdrs:
+ cd base; $(MAKE) $(MAKEFLAGS)
+ cd frame; $(MAKE) $(MAKEFLAGS)
+ cd nsacl; $(MAKE) $(MAKEFLAGS)
+endif
+
+$(HDRDEST)/%.h: %.h
+ cat $(PREFIX) $< > $(HDRDEST)/$*.h
+
+else
+stuff:
+
+endif
diff --git a/include/public/base/Makefile b/include/public/base/Makefile
new file mode 100644
index 00000000..15fa95e3
--- /dev/null
+++ b/include/public/base/Makefile
@@ -0,0 +1,40 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Makefile for netsite.h
+
+MCOM_ROOT = ../../../..
+MODULE=netsiteIncludeBase
+
+include ../../../nsdefs.mk
+
+HDRDEST=$(OBJDIR)/include/base
+
+PREFIX=../../copyrght.h
+
+
+NOSTDSTRIP=true
+NOSTDDEPEND=true
+
+#HDRS=$(wildcard *.h)
+HDRS=daemon.h cinfo.h crit.h ereport.h buffer.h net.h pblock.h sem.h session.h shexp.h shmem.h systhr.h util.h file.h pool.h regexp.h systems.h
+
+
+BINS=$(addprefix $(HDRDEST)/,$(HDRS))
+
+all: $(HDRDEST) $(BINS)
+
+$(HDRDEST):
+ mkdir -p $(HDRDEST)
+
+strip:
+depend:
+
+include ../../../nsconfig.mk
+
+$(HDRDEST)/%.h: %.h
+ cat $(PREFIX) $< > $(HDRDEST)/$*.h
diff --git a/include/public/base/crit.h b/include/public/base/crit.h
new file mode 100644
index 00000000..bca8c839
--- /dev/null
+++ b/include/public/base/crit.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_BASE_CRIT_H
+#define PUBLIC_BASE_CRIT_H
+
+/*
+ * File: crit.h
+ *
+ * Description:
+ *
+ * Deprecated include file.
+ */
+
+#ifndef PUBLIC_NSAPI_H
+#include "../nsapi.h"
+#endif /* !PUBLIC_NSAPI_H */
+
+#endif /* !PUBLIC_BASE_CRIT_H */
diff --git a/include/public/base/ereport.h b/include/public/base/ereport.h
new file mode 100644
index 00000000..742d77ea
--- /dev/null
+++ b/include/public/base/ereport.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_BASE_EREPORT_H
+#define PUBLIC_BASE_EREPORT_H
+
+/*
+ * File: ereport.h
+ *
+ * Description:
+ *
+ * Deprecated include file.
+ */
+
+#ifndef PUBLIC_NSAPI_H
+#include "../nsapi.h"
+#endif /* !PUBLIC_NSAPI_H */
+
+#endif /* !PUBLIC_BASE_EREPORT_H */
diff --git a/include/public/base/file.h b/include/public/base/file.h
new file mode 100644
index 00000000..73312bd2
--- /dev/null
+++ b/include/public/base/file.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_BASE_FILE_H
+#define PUBLIC_BASE_FILE_H
+
+/*
+ * File: file.h
+ *
+ * Description:
+ *
+ * Deprecated include file.
+ */
+
+#ifndef PUBLIC_NSAPI_H
+#include "../nsapi.h"
+#endif /* !PUBLIC_NSAPI_H */
+
+#endif /* !PUBLIC_BASE_FILE_H */
diff --git a/include/public/base/pool.h b/include/public/base/pool.h
new file mode 100644
index 00000000..9480d7c6
--- /dev/null
+++ b/include/public/base/pool.h
@@ -0,0 +1,22 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_BASE_POOL_H
+#define PUBLIC_BASE_POOL_H
+
+/*
+ * File: pool.h
+ *
+ * Description:
+ *
+ * Deprecated include file.
+ */
+
+#ifndef PUBLIC_NSAPI_H
+#include "../nsapi.h"
+#endif /* !PUBLIC_NSAPI_H */
+
+#endif /* !PUBLIC_BASE_POOL_H */
+
diff --git a/include/public/base/shexp.h b/include/public/base/shexp.h
new file mode 100644
index 00000000..dd7acf9b
--- /dev/null
+++ b/include/public/base/shexp.h
@@ -0,0 +1,22 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_BASE_SHEXP_H
+#define PUBLIC_BASE_SHEXP_H
+
+/*
+ * File: shexp.h
+ *
+ * Description:
+ *
+ * Deprecated include file.
+ */
+
+#ifndef PUBLIC_NSAPI_H
+#include "../nsapi.h"
+#endif /* !PUBLIC_NSAPI_H */
+
+#endif /* !PUBLIC_BASE_SHEXP_H */
+
diff --git a/include/public/base/systems.h b/include/public/base/systems.h
new file mode 100644
index 00000000..51be7bcd
--- /dev/null
+++ b/include/public/base/systems.h
@@ -0,0 +1,242 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_BASE_SYSTEMS_H
+#define PUBLIC_BASE_SYSTEMS_H
+
+/*
+ * File: systems.h
+ *
+ * Description:
+ *
+ * This file defines various platform-dependent symbols, which are
+ * used to configure platform-dependent aspects of the API.
+ */
+
+/* --- Begin native platform configuration definitions --- */
+
+#if defined(AIX)
+
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#if OSVERSION > 4200
+#define TCPLEN_T size_t
+#endif /* OSVERSION > 4200 */
+
+#elif defined(BSDI)
+
+#define BSD_FLOCK
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined(HPUX)
+
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define SEM_FLOCK
+/* warning: mmap doesn't work under 9.04 */
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined (IRIX)
+
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined(NCR)
+
+#define CASECMPARG_T unsigned
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined(NEC)
+
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined(OSF1)
+
+#undef BSD_FLOCK
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined(SCO)
+
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined(SNI)
+
+#define CASECMPARG_T const
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#if 0
+#define socketpair(a,b,c,d) pipe(d)
+#endif
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined(SOLARIS) || defined (SOLARISx86)
+
+#undef FILE_UNIX /* avoid redefinition message */
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+/* The Solaris routines return ENOSPC when too many semaphores are SEM_UNDO. */
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined (SONY)
+
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined(SUNOS4)
+
+#define BSD_FLOCK
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined(UNIXWARE) || defined(UnixWare)
+
+#define CASECMPARG_T const
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#ifndef S_ISLNK
+#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK)
+#endif
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+#define TCPLEN_T size_t
+
+#elif defined(Linux)
+
+#define FILE_UNIX
+#define FILE_UNIX_MMAP
+#define MALLOC_POOLS
+#define SEM_FLOCK
+#define SHMEM_UNIX_MMAP
+#define ZERO(ptr,len) memset(ptr,0,len)
+
+#elif defined (XP_WIN32) /* Windows NT */
+
+#include <wtypes.h>
+#include <winbase.h>
+
+typedef void* PASSWD;
+
+#define caddr_t PCHAR
+#define CASECMPARG_T const
+#define FILE_WIN32
+#define FILE_WIN32_MMAP
+#define MALLOC_POOLS
+#define NEED_STRCASECMP
+#define NEED_STRNCASECMP
+#define NET_WINSOCK
+#define NSAPI_PUBLIC __declspec(dllexport)
+/* The stat call under NT doesn't define these macros */
+#ifndef S_ISDIR
+#define S_ISDIR(mode) ((mode&S_IFMT) == S_IFDIR)
+#endif
+#ifndef S_ISREG
+#define S_ISREG(mode) ((mode&S_IFMT) == S_IFREG)
+#endif
+#ifndef S_ISLNK
+#define S_ISLNK(x) (0)
+#endif
+#define SEM_WIN32
+#define SHMEM_WIN32_MMAP
+#define ZERO(ptr, len) ZeroMemory(ptr, len)
+
+#else
+
+#error "Missing defines in ns/netsite/include/public/base/systems.h"
+
+#endif /* Windows NT */
+
+#ifndef NSPR_BEGIN_EXTERN_C
+#ifdef __cplusplus
+#define NSPR_BEGIN_EXTERN_C extern "C" {
+#define NSPR_END_EXTERN_C }
+#else
+#define NSPR_BEGIN_EXTERN_C
+#define NSPR_END_EXTERN_C
+#endif /* __cplusplus */
+#endif /* !NSPR_BEGIN_EXTERN_C */
+
+#ifndef TCPLEN_T
+#define TCPLEN_T int
+#endif
+
+#ifndef NSAPI_PUBLIC
+#define NSAPI_PUBLIC
+#endif /* !NSAPI_PUBLIC */
+
+#if defined(NEED_STRCASECMP) || defined(NEED_STRNCASECMP)
+#ifndef CASECMPARG_T
+#define CASECMPARG_T const
+#endif /* !CASECMPARG_T */
+#endif /* NEED_STRCASECMP || NEED_STRNCASECMP */
+
+#endif /* PUBLIC_BASE_SYSTEMS_H */
diff --git a/include/public/base/systhr.h b/include/public/base/systhr.h
new file mode 100644
index 00000000..d312c3b2
--- /dev/null
+++ b/include/public/base/systhr.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_BASE_SYSTHR_H
+#define PUBLIC_BASE_SYSTHR_H
+
+/*
+ * File: systhr.h
+ *
+ * Description:
+ *
+ * Deprecated include file.
+ */
+
+#ifndef PUBLIC_NSAPI_H
+#include "../nsapi.h"
+#endif /* !PUBLIC_NSAPI_H */
+
+#endif /* !PUBLIC_BASE_SYSTHR_H */
diff --git a/include/public/base/util.h b/include/public/base/util.h
new file mode 100644
index 00000000..88897e5d
--- /dev/null
+++ b/include/public/base/util.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_BASE_UTIL_H
+#define PUBLIC_BASE_UTIL_H
+
+/*
+ * File: util.h
+ *
+ * Description:
+ *
+ * Deprecated include file.
+ */
+
+#ifndef PUBLIC_NSAPI_H
+#include "../nsapi.h"
+#endif /* !PUBLIC_NSAPI_H */
+
+#endif /* PUBLIC_BASE_UTIL_H */
diff --git a/include/public/netsite.h b/include/public/netsite.h
new file mode 100644
index 00000000..4f745cc7
--- /dev/null
+++ b/include/public/netsite.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_NETSITE_H
+#define PUBLIC_NETSITE_H
+
+/*
+ * File: netsite.h
+ *
+ * Description:
+ *
+ * Deprecated include file.
+ */
+
+#ifndef PUBLIC_NSAPI_H
+#include "nsapi.h"
+#endif /* !PUBLIC_NSAPI_H */
+
+#endif /* !PUBLIC_NETSITE_H */
diff --git a/include/public/nsacl/Makefile b/include/public/nsacl/Makefile
new file mode 100644
index 00000000..e55a0d9d
--- /dev/null
+++ b/include/public/nsacl/Makefile
@@ -0,0 +1,38 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Makefile for include/public/nsacl public header files
+
+MCOM_ROOT = ../../../..
+MODULE=netsiteIncludeNsacl
+
+include ../../../nsdefs.mk
+
+HDRDEST=$(OBJDIR)/include/nsacl
+
+PREFIX=copyrght.h
+
+
+NOSTDSTRIP=true
+NOSTDDEPEND=true
+
+HDRS=$(wildcard *.h)
+
+BINS=$(addprefix $(HDRDEST)/,$(HDRS))
+
+all: $(HDRDEST) $(BINS)
+
+$(HDRDEST):
+ mkdir -p $(HDRDEST)
+
+strip:
+depend:
+
+include ../../../nsconfig.mk
+
+$(HDRDEST)/%.h: %.h
+ cat $(PREFIX) $< > $(HDRDEST)/$*.h
diff --git a/include/public/nsacl/aclapi.h b/include/public/nsacl/aclapi.h
new file mode 100644
index 00000000..09068f8a
--- /dev/null
+++ b/include/public/nsacl/aclapi.h
@@ -0,0 +1,396 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_NSACL_ACLAPI_H
+#define PUBLIC_NSACL_ACLAPI_H
+
+/*
+ * File: aclapi.h
+ *
+ * Description:
+ *
+ * This file defines the functions available in the ACL API.
+ */
+
+#ifndef PUBLIC_NSACL_NSERRDEF_H
+#include "nserrdef.h"
+#endif /* !PUBLIC_NSACL_NSERRDEF_H */
+
+#ifndef PUBLIC_BASE_POOL_H
+#include "../base/pool.h"
+#endif /* !PUBLIC_BASE_POOL_H */
+
+#ifndef PUBLIC_NSACL_PLISTDEF_H
+#include "plistdef.h"
+#endif /* !PUBLIC_NSACL_PLISTDEF_H */
+
+#ifndef PUBLIC_NSACL_ACLDEF_H
+#include "acldef.h"
+#endif /* !PUBLIC_NSACL_ACLDEF_H */
+
+NSPR_BEGIN_EXTERN_C
+
+typedef struct ACLDispatchVector ACLDispatchVector_t;
+struct ACLDispatchVector {
+
+ /* Error frame stack support */
+
+ void (*f_nserrDispose)(NSErr_t * errp);
+ NSEFrame_t *(*f_nserrFAlloc)(NSErr_t * errp);
+ void (*f_nserrFFree)(NSErr_t * errp, NSEFrame_t * efp);
+ NSEFrame_t *(*f_nserrGenerate)(NSErr_t * errp, long retcode,
+ long errorid, char * program,
+ int errc, ...);
+
+ /* Property list support
+ * The Property List facility makes extensive use of pointers to
+ * opaque structures. As such, PLists cannot be marshalled. WAI-style
+ * ACL APIs in future releases will therefore not be using PLists.
+ * However the C API documented here may continue to be supported
+ * in future releases.
+ */
+
+ int (*f_PListAssignValue)(PList_t plist, const char *pname,
+ const void *pvalue, PList_t ptype);
+ PList_t (*f_PListCreate)(pool_handle_t *mempool,
+ int resvprop, int maxprop, int flags);
+ int (*f_PListDefProp)(PList_t plist, int pindex,
+ const char *pname, const int flags);
+ const void * (*f_PListDeleteProp)(PList_t plist, int pindex,
+ const char *pname);
+ int (*f_PListFindValue)(PList_t plist,
+ const char *pname, void **pvalue, PList_t *type);
+ int (*f_PListInitProp)(PList_t plist, int pindex, const char *pname,
+ const void *pvalue, PList_t ptype);
+ PList_t (*f_PListNew)(pool_handle_t *mempool);
+ void (*f_PListDestroy)(PList_t plist);
+ int (*f_PListGetValue)(PList_t plist,
+ int pindex, void **pvalue, PList_t *type);
+ int (*f_PListNameProp)(PList_t plist, int pindex, const char *pname);
+ int (*f_PListSetType)(PList_t plist, int pindex, PList_t type);
+ int (*f_PListSetValue)(PList_t plist,
+ int pindex, const void *pvalue, PList_t type);
+ void (*f_PListEnumerate)(PList_t plist, PListFunc_t *user_func,
+ void *user_data);
+ PList_t (*f_PListDuplicate)(PList_t plist,
+ pool_handle_t *new_mempool, int flags);
+ pool_handle_t *(*f_PListGetPool)(PList_t plist);
+
+ /* ACL attribute handling */
+
+ int (*f_ACL_LasRegister)(NSErr_t *errp, char *attr_name,
+ LASEvalFunc_t eval_func,
+ LASFlushFunc_t flush_func);
+
+ /* method/dbtype registration routines */
+
+ int (*f_ACL_MethodRegister)(NSErr_t *errp, const char *name,
+ ACLMethod_t *t);
+ int (*f_ACL_MethodIsEqual)(NSErr_t *errp,
+ const ACLMethod_t t1, const ACLMethod_t t2);
+ int (*f_ACL_MethodNameIsEqual)(NSErr_t *errp,
+ const ACLMethod_t t, const char *name);
+ int (*f_ACL_MethodFind)(NSErr_t *errp, const char *name, ACLMethod_t *t);
+ ACLMethod_t (*f_ACL_MethodGetDefault)(NSErr_t *errp);
+ int (*f_ACL_MethodSetDefault)(NSErr_t *errp, const ACLMethod_t t);
+ int (*f_ACL_AuthInfoGetMethod)(NSErr_t *errp,
+ PList_t auth_info, ACLMethod_t *t);
+
+ int (*f_ACL_DbTypeRegister)(NSErr_t *errp, const char *name,
+ DbParseFn_t func, ACLDbType_t *t);
+ int (*f_ACL_DbTypeIsEqual)(NSErr_t *errp,
+ const ACLDbType_t t1, const ACLDbType_t t2);
+ int (*f_ACL_DbTypeNameIsEqual)(NSErr_t * errp,
+ const ACLDbType_t t, const char *name);
+ int (*f_ACL_DbTypeFind)(NSErr_t *errp, const char *name, ACLDbType_t *t);
+ ACLDbType_t (*f_ACL_DbTypeGetDefault)(NSErr_t *errp);
+ int (*f_ACL_AuthInfoGetDbType)(NSErr_t *errp,
+ PList_t auth_info, ACLDbType_t *t);
+ int (*f_ACL_DbTypeIsRegistered)(NSErr_t *errp, const ACLDbType_t dbtype);
+ DbParseFn_t (*f_ACL_DbTypeParseFn)(NSErr_t *errp,
+ const ACLDbType_t dbtype);
+
+ int (*f_ACL_AttrGetterRegister)(NSErr_t *errp,
+ const char *attr, ACLAttrGetterFn_t fn,
+ ACLMethod_t m, ACLDbType_t d,
+ int position, void *arg);
+
+ int (*f_ACL_ModuleRegister)(NSErr_t *errp, const char *moduleName,
+ AclModuleInitFunc func);
+ int (*f_ACL_GetAttribute)(NSErr_t *errp, const char *attr, void **val,
+ PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth);
+ int (*f_ACL_DatabaseRegister)(NSErr_t *errp, ACLDbType_t dbtype,
+ const char *dbname, const char *url,
+ PList_t plist);
+ int (*f_ACL_DatabaseFind)(NSErr_t *errp, const char *dbname,
+ ACLDbType_t *dbtype, void **db);
+ int (*f_ACL_DatabaseSetDefault)(NSErr_t *errp, const char *dbname);
+ int (*f_ACL_LDAPDatabaseHandle )(NSErr_t *errp, const char *dbname,
+ LDAP **ld, char **basedn);
+ int (*f_ACL_AuthInfoGetDbname)(PList_t auth_info, char **dbname);
+ int (*f_ACL_CacheFlushRegister)(AclCacheFlushFunc_t func);
+ int (*f_ACL_CacheFlush)(void);
+
+ /* ACL language and file interfaces */
+
+ ACLListHandle_t * (*f_ACL_ParseFile)(NSErr_t *errp, char *filename);
+ ACLListHandle_t * (*f_ACL_ParseString)(NSErr_t *errp, char *buffer);
+ int (*f_ACL_WriteString)(NSErr_t *errp, char **acl,
+ ACLListHandle_t *acllist);
+ int (*f_ACL_WriteFile)(NSErr_t *errp, char *filename,
+ ACLListHandle_t *acllist);
+ int (*f_ACL_FileRenameAcl)(NSErr_t *errp, char *filename,
+ char *acl_name, char *new_acl_name, int flags);
+ int (*f_ACL_FileDeleteAcl)(NSErr_t *errp, char *filename,
+ char *acl_name, int flags);
+ int (*f_ACL_FileGetAcl)(NSErr_t *errp, char *filename,
+ char *acl_name, char **acl_text, int flags);
+ int (*f_ACL_FileSetAcl)(NSErr_t *errp, char *filename,
+ char *acl_text, int flags);
+
+ /* ACL Expression construction interfaces
+ * These are low-level interfaces that may be useful to those who are not
+ * using the ONE ACL syntax, but want to use the ONE ACL evaluation
+ * routines. By their low-level nature, future support of these APIs
+ * cannot be guaranteed. Use ACL_ParseFile and ACL_ParseString wherever
+ * possible.
+ */
+
+ ACLExprHandle_t *(*f_ACL_ExprNew)(const ACLExprType_t expr_type);
+ void (*f_ACL_ExprDestroy)(ACLExprHandle_t *expr);
+ int (*f_ACL_ExprSetPFlags)(NSErr_t *errp,
+ ACLExprHandle_t *expr, PFlags_t flags);
+ int (*f_ACL_ExprClearPFlags)(NSErr_t *errp, ACLExprHandle_t *expr);
+ int (*f_ACL_ExprTerm)(NSErr_t *errp, ACLExprHandle_t *acl_expr,
+ char *attr_name, CmpOp_t cmp, char *attr_pattern);
+ int (*f_ACL_ExprNot)(NSErr_t *errp, ACLExprHandle_t *acl_expr);
+ int (*f_ACL_ExprAnd)(NSErr_t *errp, ACLExprHandle_t *acl_expr);
+ int (*f_ACL_ExprOr)(NSErr_t *errp, ACLExprHandle_t *acl_expr);
+ int (*f_ACL_ExprAddAuthInfo)(ACLExprHandle_t *expr, PList_t auth_info);
+ int (*f_ACL_ExprAddArg)(NSErr_t *errp, ACLExprHandle_t *expr, char *arg);
+ int (*f_ACL_ExprSetDenyWith)(NSErr_t *errp, ACLExprHandle_t *expr,
+ char *deny_type, char *deny_response);
+ int (*f_ACL_ExprGetDenyWith)(NSErr_t *errp, ACLExprHandle_t *expr,
+ char **deny_type, char **deny_response);
+ int (*f_ACL_ExprAppend)(NSErr_t *errp,
+ ACLHandle_t *acl, ACLExprHandle_t *expr);
+
+ /* ACL manipulation */
+
+ ACLHandle_t * (*f_ACL_AclNew)(NSErr_t *errp, char *tag);
+ void (*f_ACL_AclDestroy)(NSErr_t *errp, ACLHandle_t *acl);
+
+ /* ACL list manipulation */
+
+ ACLListHandle_t * (*f_ACL_ListNew)(NSErr_t *errp);
+ int (*f_ACL_ListConcat)(NSErr_t *errp, ACLListHandle_t *acl_list1,
+ ACLListHandle_t *acl_list2, int flags);
+ int (*f_ACL_ListAppend)(NSErr_t *errp, ACLListHandle_t *acllist,
+ ACLHandle_t *acl, int flags);
+ void (*f_ACL_ListDestroy)(NSErr_t *errp, ACLListHandle_t *acllist);
+ ACLHandle_t * (*f_ACL_ListFind)(NSErr_t *errp, ACLListHandle_t *acllist,
+ char *aclname, int flags);
+ int (*f_ACL_ListAclDelete)(NSErr_t *errp, ACLListHandle_t *acl_list,
+ char *acl_name, int flags);
+ int (*f_ACL_ListGetNameList)(NSErr_t *errp, ACLListHandle_t *acl_list,
+ char ***name_list);
+ int (*f_ACL_NameListDestroy)(NSErr_t *errp, char **name_list);
+
+ /* ACL evaluation */
+
+ int (*f_ACL_EvalTestRights)(NSErr_t *errp, ACLEvalHandle_t *acleval,
+ char **rights, char **map_generic,
+ char **deny_type, char **deny_response,
+ char **acl_tag, int *expr_num);
+ ACLEvalHandle_t * (*f_ACL_EvalNew)(NSErr_t *errp, pool_handle_t *pool);
+ void (*f_ACL_EvalDestroy)(NSErr_t *errp,
+ pool_handle_t *pool, ACLEvalHandle_t *acleval);
+ int (*f_ACL_EvalSetACL)(NSErr_t *errp, ACLEvalHandle_t *acleval,
+ ACLListHandle_t *acllist);
+ PList_t (*f_ACL_EvalGetSubject)(NSErr_t *errp, ACLEvalHandle_t *acleval);
+ int (*f_ACL_EvalSetSubject)(NSErr_t *errp,
+ ACLEvalHandle_t *acleval, PList_t subject);
+ PList_t (*f_ACL_EvalGetResource)(NSErr_t *errp, ACLEvalHandle_t *acleval);
+ int (*f_ACL_EvalSetResource)(NSErr_t *errp,
+ ACLEvalHandle_t *acleval, PList_t resource);
+
+ /* Access to critical section for ACL cache */
+
+ void (*f_ACL_CritEnter)(void);
+ void (*f_ACL_CritExit)(void);
+
+ /* Miscellaneous functions */
+ const char * (*f_ACL_AclGetTag)(ACLHandle_t *acl);
+ ACLHandle_t * (*f_ACL_ListGetFirst)(ACLListHandle_t *acl_list,
+ ACLListEnum_t *acl_enum);
+ ACLHandle_t * (*f_ACL_ListGetNext)(ACLListHandle_t *acl_list,
+ ACLListEnum_t *acl_enum);
+
+ /* Functions added after ES 3.0 release */
+ const char * (*f_ACL_DatabaseGetDefault)(NSErr_t *errp);
+ int (*f_ACL_SetDefaultResult)(NSErr_t *errp, ACLEvalHandle_t *acleval,
+ int result);
+ int (*f_ACL_GetDefaultResult)(ACLEvalHandle_t *acleval);
+};
+
+#ifdef XP_WIN32
+
+#ifdef INTNSACL
+NSAPI_PUBLIC extern ACLDispatchVector_t *__nsacl_table;
+#else
+__declspec(dllimport) ACLDispatchVector_t *__nsacl_table;
+#endif /* INTNSACL */
+
+#else /* !XP_WIN32 */
+
+NSAPI_PUBLIC extern ACLDispatchVector_t *__nsacl_table;
+
+#endif /* XP_WIN32 */
+
+#ifndef INTNSACL
+
+#define nserrDispose (*__nsacl_table->f_nserrDispose)
+#define nserrFAlloc (*__nsacl_table->f_nserrFAlloc)
+#define nserrFFree (*__nsacl_table->f_nserrFFree)
+#define nserrGenerate (*__nsacl_table->f_nserrGenerate)
+
+ /* Property list support
+ * The Property List facility makes extensive use of pointers to
+ * opaque structures. As such, PLists cannot be marshalled. WAI-style
+ * ACL APIs in future releases will therefore not be using PLists.
+ * However the C API documented here may continue to be supported
+ * in future releases.
+ */
+
+#define PListAssignValue (*__nsacl_table->f_PListAssignValue)
+#define PListCreate (*__nsacl_table->f_PListCreate)
+#define PListDefProp (*__nsacl_table->f_PListDefProp)
+#define PListDeleteProp (*__nsacl_table->f_PListDeleteProp)
+#define PListFindValue (*__nsacl_table->f_PListFindValue)
+#define PListInitProp (*__nsacl_table->f_PListInitProp)
+#define PListNew (*__nsacl_table->f_PListNew)
+#define PListDestroy (*__nsacl_table->f_PListDestroy)
+#define PListGetValue (*__nsacl_table->f_PListGetValue)
+#define PListNameProp (*__nsacl_table->f_PListNameProp)
+#define PListSetType (*__nsacl_table->f_PListSetType)
+#define PListSetValue (*__nsacl_table->f_PListSetValue)
+#define PListEnumerate (*__nsacl_table->f_PListEnumerate)
+#define PListDuplicate (*__nsacl_table->f_PListDuplicate)
+#define PListGetPool (*__nsacl_table->f_PListGetPool)
+
+ /* ACL attribute handling */
+
+#define ACL_LasRegister (*__nsacl_table->f_ACL_LasRegister)
+
+ /* method/dbtype registration routines */
+
+#define ACL_MethodRegister (*__nsacl_table->f_ACL_MethodRegister)
+#define ACL_MethodIsEqual (*__nsacl_table->f_ACL_MethodIsEqual)
+#define ACL_MethodNameIsEqual (*__nsacl_table->f_ACL_MethodNameIsEqual)
+#define ACL_MethodFind (*__nsacl_table->f_ACL_MethodFind)
+#define ACL_MethodGetDefault (*__nsacl_table->f_ACL_MethodGetDefault)
+#define ACL_MethodSetDefault (*__nsacl_table->f_ACL_MethodSetDefault)
+#define ACL_AuthInfoGetMethod (*__nsacl_table->f_ACL_AuthInfoGetMethod)
+#define ACL_DbTypeRegister (*__nsacl_table->f_ACL_DbTypeRegister)
+#define ACL_DbTypeIsEqual (*__nsacl_table->f_ACL_DbTypeIsEqual)
+#define ACL_DbTypeNameIsEqual (*__nsacl_table->f_ACL_DbTypeNameIsEqual)
+#define ACL_DbTypeFind (*__nsacl_table->f_ACL_DbTypeFind)
+#define ACL_DbTypeGetDefault (*__nsacl_table->f_ACL_DbTypeGetDefault)
+#define ACL_AuthInfoGetDbType (*__nsacl_table->f_ACL_AuthInfoGetDbType)
+#define ACL_DbTypeIsRegistered (*__nsacl_table->f_ACL_DbTypeIsRegistered)
+#define ACL_DbTypeParseFn (*__nsacl_table->f_ACL_DbTypeParseFn)
+#define ACL_AttrGetterRegister (*__nsacl_table->f_ACL_AttrGetterRegister)
+#define ACL_ModuleRegister (*__nsacl_table->f_ACL_ModuleRegister)
+#define ACL_GetAttribute (*__nsacl_table->f_ACL_GetAttribute)
+#define ACL_DatabaseRegister (*__nsacl_table->f_ACL_DatabaseRegister)
+#define ACL_DatabaseFind (*__nsacl_table->f_ACL_DatabaseFind)
+#define ACL_DatabaseSetDefault (*__nsacl_table->f_ACL_DatabaseSetDefault)
+#define ACL_LDAPDatabaseHandle (*__nsacl_table->f_ACL_LDAPDatabaseHandle)
+#define ACL_AuthInfoGetDbname (*__nsacl_table->f_ACL_AuthInfoGetDbname)
+#define ACL_CacheFlushRegister (*__nsacl_table->f_ACL_CacheFlushRegister)
+#define ACL_CacheFlush (*__nsacl_table->f_ACL_CacheFlush)
+
+ /* ACL language and file interfaces */
+
+#define ACL_ParseFile (*__nsacl_table->f_ACL_ParseFile)
+#define ACL_ParseString (*__nsacl_table->f_ACL_ParseString)
+#define ACL_WriteString (*__nsacl_table->f_ACL_WriteString)
+#define ACL_WriteFile (*__nsacl_table->f_ACL_WriteFile)
+#define ACL_FileRenameAcl (*__nsacl_table->f_ACL_FileRenameAcl)
+#define ACL_FileDeleteAcl (*__nsacl_table->f_ACL_FileDeleteAcl)
+#define ACL_FileGetAcl (*__nsacl_table->f_ACL_FileGetAcl)
+#define ACL_FileSetAcl (*__nsacl_table->f_ACL_FileSetAcl)
+
+ /* ACL Expression construction interfaces
+ * These are low-level interfaces that may be useful to those who are not
+ * using the ONE ACL syntax, but want to use the ONE ACL evaluation
+ * routines. By their low-level nature, future support of these APIs
+ * cannot be guaranteed. Use ACL_ParseFile and ACL_ParseString wherever
+ * possible.
+ */
+
+#define ACL_ExprNew (*__nsacl_table->f_ACL_ExprNew)
+#define ACL_ExprDestroy (*__nsacl_table->f_ACL_ExprDestroy)
+#define ACL_ExprSetPFlags (*__nsacl_table->f_ACL_ExprSetPFlags)
+#define ACL_ExprClearPFlags (*__nsacl_table->f_ACL_ExprClearPFlags)
+#define ACL_ExprTerm (*__nsacl_table->f_ACL_ExprTerm)
+#define ACL_ExprNot (*__nsacl_table->f_ACL_ExprNot)
+#define ACL_ExprAnd (*__nsacl_table->f_ACL_ExprAnd)
+#define ACL_ExprOr (*__nsacl_table->f_ACL_ExprOr)
+#define ACL_ExprAddAuthInfo (*__nsacl_table->f_ACL_ExprAddAuthInfo)
+#define ACL_ExprAddArg (*__nsacl_table->f_ACL_ExprAddArg)
+#define ACL_ExprSetDenyWith (*__nsacl_table->f_ACL_ExprSetDenyWith)
+#define ACL_ExprGetDenyWith (*__nsacl_table->f_ACL_ExprGetDenyWith)
+#define ACL_ExprAppend (*__nsacl_table->f_ACL_ExprAppend)
+
+ /* ACL manipulation */
+
+#define ACL_AclNew (*__nsacl_table->f_ACL_AclNew)
+#define ACL_AclDestroy (*__nsacl_table->f_ACL_AclDestroy)
+
+ /* ACL list manipulation */
+
+#define ACL_ListNew (*__nsacl_table->f_ACL_ListNew)
+#define ACL_ListConcat (*__nsacl_table->f_ACL_ListConcat)
+#define ACL_ListAppend (*__nsacl_table->f_ACL_ListAppend)
+#define ACL_ListDestroy (*__nsacl_table->f_ACL_ListDestroy)
+#define ACL_ListFind (*__nsacl_table->f_ACL_ListFind)
+#define ACL_ListAclDelete (*__nsacl_table->f_ACL_ListAclDelete)
+#define ACL_ListGetNameList (*__nsacl_table->f_ACL_ListGetNameList)
+#define ACL_NameListDestroy (*__nsacl_table->f_ACL_NameListDestroy)
+
+ /* ACL evaluation */
+
+#define ACL_EvalTestRights (*__nsacl_table->f_ACL_EvalTestRights)
+#define ACL_EvalNew (*__nsacl_table->f_ACL_EvalNew)
+#define ACL_EvalDestroy (*__nsacl_table->f_ACL_EvalDestroy)
+#define ACL_EvalSetACL (*__nsacl_table->f_ACL_EvalSetACL)
+#define ACL_EvalGetSubject (*__nsacl_table->f_ACL_EvalGetSubject)
+#define ACL_EvalSetSubject (*__nsacl_table->f_ACL_EvalSetSubject)
+#define ACL_EvalGetResource (*__nsacl_table->f_ACL_EvalGetResource)
+#define ACL_EvalSetResource (*__nsacl_table->f_ACL_EvalSetResource)
+
+ /* Access to critical section for ACL cache */
+
+#define ACL_CritEnter (*__nsacl_table->f_ACL_CritEnter)
+#define ACL_CritExit (*__nsacl_table->f_ACL_CritExit)
+
+ /* Miscellaneous functions */
+
+#define ACL_AclGetTag (*__nsacl_table->f_ACL_AclGetTag)
+#define ACL_ListGetFirst (*__nsacl_table->f_ACL_ListGetFirst)
+#define ACL_ListGetNext (*__nsacl_table->f_ACL_ListGetNext)
+
+ /* Functions added after ES 3.0 release */
+#define ACL_DatabaseGetDefault (*__nsacl_table->f_ACL_DatabaseGetDefault)
+#define ACL_SetDefaultResult (*__nsacl_table->f_ACL_SetDefaultResult)
+#define ACL_GetDefaultResult (*__nsacl_table->f_ACL_GetDefaultResult)
+
+#endif /* !INTNSACL */
+
+NSPR_END_EXTERN_C
+
+#endif /* !PUBLIC_NSACL_ACLAPI_H */
diff --git a/include/public/nsacl/acldef.h b/include/public/nsacl/acldef.h
new file mode 100644
index 00000000..c5eb1d09
--- /dev/null
+++ b/include/public/nsacl/acldef.h
@@ -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 **/
+#ifndef PUBLIC_NSACL_ACLDEF_H
+#define PUBLIC_NSACL_ACLDEF_H
+
+/*
+ * File: acldef.h
+ *
+ * Description:
+ *
+ * This file contains constant and type definitions for the ACL API.
+ */
+
+#ifndef PUBLIC_NSACL_NSERRDEF_H
+#include "nserrdef.h"
+#endif /* !PUBLIC_NSACL_NSERRDEF_H */
+
+#ifndef PUBLIC_NSACL_PLISTDEF_H
+#include "plistdef.h"
+#endif /* !PUBLIC_NSACL_PLISTDEF_H */
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * Type: ACLCachable_t
+ *
+ * Description:
+ *
+ * This type is used to specify whether and how long something
+ * may be safely cached. A value of zero (ACL_NOT_CACHABLE)
+ * indicates that the item is not cachable. Any other value is
+ * a time, in seconds since 00:00:00 UTC, January 1, 1970, after
+ * which the cached information should be discarded.
+ */
+
+typedef unsigned long ACLCachable_t;
+
+#define ACL_NOT_CACHABLE 0
+#define ACL_INDEF_CACHABLE ((unsigned long)(-1))
+
+/*
+ * Type: ACLListHandle_t
+ *
+ * Description:
+ *
+ * This type represents a list of ACLs in their in-memory form.
+ */
+
+typedef struct ACLListHandle ACLListHandle_t;
+
+/* The object has been checked for ACLs and has none attached */
+#define ACL_LIST_NO_ACLS ((ACLListHandle_t *)-1)
+
+/*
+ * Type: ACLHandle_t
+ *
+ * Description:
+ *
+ * This type represents the in-memory form of an ACL.
+ */
+
+typedef struct ACLHandle ACLHandle_t;
+
+/*
+ * Type: ACLListEnum_t
+ *
+ * Description:
+ *
+ * This type contains the state of an ACL list enumeration.
+ */
+
+typedef void *ACLListEnum_t;
+
+/*
+ * Type: ACLExprHandle_t
+ *
+ * Description:
+ *
+ * This type represents a single ACL entry, e.g. allow, deny, etc.
+ */
+
+typedef struct ACLExprHandle ACLExprHandle_t;
+
+/*
+ * Type: ACLEvalHandle_t
+ *
+ * Description:
+ *
+ * This type represents an ACL evaluation context, which includes
+ * an ACL list and property lists for the subject and resource.
+ */
+
+typedef struct ACLEvalHandle ACLEvalHandle_t;
+
+/*
+ * Type: PFlags_t
+ *
+ * Description:
+ *
+ * This type represents a set of processing flags for an ACL entry.
+ */
+typedef int PFlags_t;
+
+#define ACL_PFLAG_ABSOLUTE 0x1
+#define ACL_PFLAG_TERMINAL 0x2
+#define ACL_PFLAG_CONTENT 0x4
+
+#define IS_ABSOLUTE(x) ((x) & ACL_PFLAG_ABSOLUTE)
+#define IS_STATIC(x) ((x) & ACL_PFLAG_STATIC)
+#define IS_CONTENT(x) ((x) & ACL_PFLAG_CONTENT)
+
+/*
+ * Type: CmpOp_t
+ *
+ * Description:
+ *
+ * This type represents a comparison operator in an ACL attribute
+ * expression.
+ */
+typedef enum {
+ CMP_OP_EQ,
+ CMP_OP_NE,
+ CMP_OP_GT,
+ CMP_OP_LT,
+ CMP_OP_GE,
+ CMP_OP_LE
+ } CmpOp_t;
+
+/*
+ * Type: ACLExprType_t
+ *
+ * Description:
+ *
+ * This type represents the type of an ACL entry.
+ */
+typedef enum {
+ ACL_EXPR_TYPE_ALLOW,
+ ACL_EXPR_TYPE_DENY,
+ ACL_EXPR_TYPE_AUTH,
+ ACL_EXPR_TYPE_RESPONSE
+ } ACLExprType_t;
+
+/*
+ * Type: ACLEvalRes_t
+ *
+ * Description:
+ *
+ * This type represents the result of ACL evaluation.
+ */
+typedef enum {
+ ACL_RES_ALLOW,
+ ACL_RES_DENY,
+ ACL_RES_FAIL,
+ ACL_RES_INVALID,
+ ACL_RES_NONE
+ } ACLEvalRes_t;
+
+/*
+ * Type: ACLMethod_t
+ *
+ * Description:
+ *
+ * This type represents a reference to an authentication method.
+ */
+typedef void * ACLMethod_t;
+
+#define ACL_METHOD_ANY ((ACLMethod_t)-1)
+#define ACL_METHOD_INVALID ((ACLMethod_t)-2)
+
+/*
+ * Type: ACLDbType_t
+ *
+ * Description:
+ *
+ * This type represents a reference to a type of authentication
+ * database.
+ */
+typedef void * ACLDbType_t;
+
+#define ACL_DBTYPE_ANY ((ACLDbType_t)-1)
+#define ACL_DBTYPE_INVALID ((ACLDbType_t)-2)
+
+/*
+ * Type: ACLAttrGetterFn_t
+ *
+ * Description:
+ *
+ * This type describes a kind of callback function that obtains
+ * a value for an ACL attribute and enters the attribute and value
+ * into the subject property list.
+ */
+typedef int (*ACLAttrGetterFn_t)(NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *arg);
+
+typedef struct ACLAttrGetter ACLAttrGetter_t;
+typedef void *ACLAttrGetterList_t;
+
+/*
+ * Type: AclModuleInitFunc
+ *
+ * Description:
+ *
+ * This type describes a kind of callback function that is
+ * specified to ACL_ModuleRegister() and called from there.
+ * The function should return 0 on success and non-zero on
+ * failure.
+ */
+typedef int (*AclModuleInitFunc)(NSErr_t *errp);
+
+/*
+ * Type: DbParseFn_t
+ *
+ * Description:
+ *
+ * This type describes a kind of callback function that parses
+ * a reference to an authentication database of a particular
+ * database type. It is called when ACL_DatabaseRegister() is
+ * called for a database which is that database type.
+ * The function should return 0 on success and non-zero on
+ * failure.
+ */
+typedef int (*DbParseFn_t)(NSErr_t *errp, ACLDbType_t dbtype,
+ const char *name, const char *url,
+ PList_t plist, void **db);
+
+/*
+ * Type: AclCacheFlushFunc_t
+ *
+ * Description:
+ *
+ * This type describes a kind of callback function that is called
+ * when ACL_CacheFlush() is called.
+ */
+typedef int (*AclCacheFlushFunc_t)(void);
+
+/*
+ * Type: LASEvalFunc_t
+ *
+ * Description:
+ *
+ * This type describes a kind of callback function that is called
+ * to evaluate an attribute value expression in an ACL statement.
+ */
+typedef int (*LASEvalFunc_t)(NSErr_t *errp, char *attr_name,
+ CmpOp_t comparator, char *attr_pattern,
+ ACLCachable_t *cachable, void **cookie,
+ PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth);
+
+/*
+ * Type: LASFlushFunc_t
+ *
+ * Description:
+ *
+ * This type describes a kind of callback function that is called
+ * when a previously cached LAS cookie is being flushed from
+ * the ACL cache.
+ */
+typedef void (*LASFlushFunc_t)(void **cookie);
+
+/*
+ * Type: LDAP
+ *
+ * Description:
+ *
+ * This is an opaque type that represents an open LDAP connection.
+ * It is used mostly via the LDAP SDK API.
+ * Include the <ldap.h> file before including this file if you wish to
+ * use the function ACL_LDAPDatabaseHandle.
+ */
+#ifndef _LDAP_H
+typedef struct ldap LDAP;
+#endif /* _LDAP_H */
+
+
+/* Flags to ACL_ListFind */
+#define ACL_CASE_INSENSITIVE 0x1
+#define ACL_CASE_SENSITIVE 0x2
+
+#define ACL_MAX_TEST_RIGHTS 32
+#define ACL_MAX_GENERIC 32
+
+/*
+ * ACLERRFAIL -- Use this as an 'retcode' argument to nserrGenerate.
+ */
+#define ACLERRFAIL -11
+
+
+/*
+ * Command values for the "position" argument to ACL_RegisterGetter
+ * Any positive >0 value is the specific position in the list to insert
+ * the new function.
+ */
+#define ACL_AT_FRONT 0
+#define ACL_AT_END -1
+#define ACL_REPLACE_ALL -2
+#define ACL_REPLACE_MATCHING -3
+
+#define ACL_ATTR_GROUP "group"
+#define ACL_ATTR_GROUP_INDEX 1
+#define ACL_ATTR_RAW_USER_LOGIN "user-login"
+#define ACL_ATTR_RAW_USER_LOGIN_INDEX 2
+#define ACL_ATTR_AUTH_USER "auth-user"
+#define ACL_ATTR_AUTH_USER_INDEX 3
+#define ACL_ATTR_AUTH_TYPE "auth-type"
+#define ACL_ATTR_AUTH_TYPE_INDEX 4
+#define ACL_ATTR_AUTH_DB "auth-db"
+#define ACL_ATTR_AUTH_DB_INDEX 5
+#define ACL_ATTR_AUTH_PASSWORD "auth-password"
+#define ACL_ATTR_AUTH_PASSWORD_INDEX 6
+#define ACL_ATTR_USER "user"
+#define ACL_ATTR_USER_INDEX 7
+#define ACL_ATTR_PASSWORD "pw"
+#define ACL_ATTR_PASSWORD_INDEX 8
+#define ACL_ATTR_USERDN "userdn"
+#define ACL_ATTR_USERDN_INDEX 9
+#define ACL_ATTR_RAW_USER "raw-user"
+#define ACL_ATTR_RAW_USER_INDEX 10
+#define ACL_ATTR_RAW_PASSWORD "raw-pw"
+#define ACL_ATTR_RAW_PASSWORD_INDEX 11
+#define ACL_ATTR_USER_ISMEMBER "user-ismember"
+#define ACL_ATTR_USER_ISMEMBER_INDEX 12
+#define ACL_ATTR_DATABASE "database"
+#define ACL_ATTR_DATABASE_INDEX 13
+#define ACL_ATTR_DBTYPE "dbtype"
+#define ACL_ATTR_DBTYPE_INDEX 14
+#define ACL_ATTR_DBNAME "dbname"
+#define ACL_ATTR_DBNAME_INDEX 15
+#define ACL_ATTR_DATABASE_URL "url"
+#define ACL_ATTR_DATABASE_URL_INDEX 16
+#define ACL_ATTR_METHOD "method"
+#define ACL_ATTR_METHOD_INDEX 17
+#define ACL_ATTR_AUTHTYPE "authtype"
+#define ACL_ATTR_AUTHTYPE_INDEX 18
+#define ACL_ATTR_AUTHORIZATION "authorization"
+#define ACL_ATTR_AUTHORIZATION_INDEX 19
+#define ACL_ATTR_PARSEFN "parsefn"
+#define ACL_ATTR_PARSEFN_INDEX 20
+#define ACL_ATTR_ATTRIBUTE "attr"
+#define ACL_ATTR_ATTRIBUTE_INDEX 21
+#define ACL_ATTR_GETTERFN "getterfunc"
+#define ACL_ATTR_GETTERFN_INDEX 22
+#define ACL_ATTR_IP "ip"
+#define ACL_ATTR_IP_INDEX 23
+#define ACL_ATTR_DNS "dns"
+#define ACL_ATTR_DNS_INDEX 24
+#define ACL_ATTR_MODULE "module"
+#define ACL_ATTR_MODULE_INDEX 25
+#define ACL_ATTR_MODULEFUNC "func"
+#define ACL_ATTR_MODULEFUNC_INDEX 26
+#define ACL_ATTR_GROUPS "groups"
+#define ACL_ATTR_GROUPS_INDEX 27
+#define ACL_ATTR_IS_VALID_PASSWORD "isvalid-password"
+#define ACL_ATTR_IS_VALID_PASSWORD_INDEX 28
+#define ACL_ATTR_CERT2USER "cert2user"
+#define ACL_ATTR_CERT2USER_INDEX 29
+#define ACL_ATTR_USER_CERT "cert"
+#define ACL_ATTR_USER_CERT_INDEX 30
+#define ACL_ATTR_PROMPT "prompt"
+#define ACL_ATTR_PROMPT_INDEX 31
+#define ACL_ATTR_TIME "time"
+#define ACL_ATTR_TIME_INDEX 32
+#define ACL_ATTR_USERS_GROUP "users-group"
+#define ACL_ATTR_USERS_GROUP_INDEX 33
+#define ACL_ATTR_SESSION "session" /* subject property */
+#define ACL_ATTR_SESSION_INDEX 34
+#define ACL_ATTR_REQUEST "request" /* resource property */
+#define ACL_ATTR_REQUEST_INDEX 35
+#define ACL_ATTR_ERROR "error"
+#define ACL_ATTR_ERROR_INDEX 36
+#define ACL_ATTR_PROGRAMS "programs" /* resource property */
+#define ACL_ATTR_PROGRAMS_INDEX 37
+#define ACL_ATTR_ACCEL_AUTH "accel-authorization"
+#define ACL_ATTR_ACCEL_AUTH_INDEX 38
+#define ACL_ATTR_WWW_AUTH_PROMPT "www-auth-prompt"
+#define ACL_ATTR_WWW_AUTH_PROMPT_INDEX 39
+#define ACL_ATTR_OWNER "owner"
+#define ACL_ATTR_OWNER_INDEX 40
+#define ACL_ATTR_IS_OWNER "is-owner"
+#define ACL_ATTR_IS_OWNER_INDEX 41
+#define ACL_ATTR_CACHED_USER "cached-user"
+#define ACL_ATTR_CACHED_USER_INDEX 42
+#define ACL_ATTR_USER_EXISTS "user-exists"
+#define ACL_ATTR_USER_EXISTS_INDEX 43
+
+/* Must be 1 larger than the highest index used */
+#define ACL_ATTR_INDEX_MAX 44
+
+#ifdef ALLOCATE_ATTR_TABLE
+/* Must be in the same order as the index numbers */
+char *ACLAttrTable[] = {
+ NULL, /* 0 */
+/* Don't have one numbered 0 */
+ ACL_ATTR_GROUP, /* 1 */
+ ACL_ATTR_RAW_USER_LOGIN, /* 2 */
+ ACL_ATTR_AUTH_USER, /* 3 */
+ ACL_ATTR_AUTH_TYPE, /* 4 */
+ ACL_ATTR_AUTH_DB, /* 5 */
+ ACL_ATTR_AUTH_PASSWORD, /* 6 */
+ ACL_ATTR_USER, /* 7 */
+ ACL_ATTR_PASSWORD, /* 8 */
+ ACL_ATTR_USERDN, /* 9 */
+ ACL_ATTR_RAW_USER, /* 10 */
+ ACL_ATTR_RAW_PASSWORD, /* 11 */
+ ACL_ATTR_USER_ISMEMBER, /* 12 */
+ ACL_ATTR_DATABASE, /* 13 */
+ ACL_ATTR_DBTYPE, /* 14 */
+ ACL_ATTR_DBNAME, /* 15 */
+ ACL_ATTR_DATABASE_URL, /* 16 */
+ ACL_ATTR_METHOD, /* 17 */
+ ACL_ATTR_AUTHTYPE, /* 18 */
+ ACL_ATTR_AUTHORIZATION, /* 19 */
+ ACL_ATTR_PARSEFN, /* 20 */
+ ACL_ATTR_ATTRIBUTE, /* 21 */
+ ACL_ATTR_GETTERFN, /* 22 */
+ ACL_ATTR_IP, /* 23 */
+ ACL_ATTR_DNS, /* 24 */
+ ACL_ATTR_MODULE, /* 25 */
+ ACL_ATTR_MODULEFUNC, /* 26 */
+ ACL_ATTR_GROUPS, /* 27 */
+ ACL_ATTR_IS_VALID_PASSWORD, /* 28 */
+ ACL_ATTR_CERT2USER, /* 29 */
+ ACL_ATTR_USER_CERT, /* 30 */
+ ACL_ATTR_PROMPT, /* 31 */
+ ACL_ATTR_TIME, /* 32 */
+ ACL_ATTR_USERS_GROUP, /* 33 */
+ ACL_ATTR_SESSION, /* 34 */
+ ACL_ATTR_REQUEST, /* 35 */
+ ACL_ATTR_ERROR, /* 36 */
+ ACL_ATTR_PROGRAMS, /* 37 */
+ ACL_ATTR_ACCEL_AUTH, /* 38 */
+ ACL_ATTR_WWW_AUTH_PROMPT, /* 39 */
+ ACL_ATTR_OWNER, /* 40 */
+ ACL_ATTR_IS_OWNER, /* 41 */
+ ACL_ATTR_CACHED_USER, /* 42 */
+ ACL_ATTR_USER_EXISTS /* 43 */
+};
+#endif
+
+
+#define ACL_DBTYPE_LDAP "ldap"
+
+#define METHOD_DEFAULT "default"
+
+/* Errors must be < 0 */
+#define ACL_RES_ERROR -1
+
+/* LAS return codes - Must all be negative numbers */
+#define LAS_EVAL_TRUE -1
+#define LAS_EVAL_FALSE -2
+#define LAS_EVAL_DECLINE -3
+#define LAS_EVAL_FAIL -4
+#define LAS_EVAL_INVALID -5
+#define LAS_EVAL_NEED_MORE_INFO -6
+
+/* Max pathlength. Intended to match REQ_MAX_LEN */
+#define ACL_PATH_MAX 4096
+
+NSPR_END_EXTERN_C
+
+#endif /* !PUBLIC_NSACL_ACLDEF_H */
diff --git a/include/public/nsacl/copyrght.h b/include/public/nsacl/copyrght.h
new file mode 100644
index 00000000..4f8ec167
--- /dev/null
+++ b/include/public/nsacl/copyrght.h
@@ -0,0 +1,6 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
diff --git a/include/public/nsacl/nserrdef.h b/include/public/nsacl/nserrdef.h
new file mode 100644
index 00000000..81748227
--- /dev/null
+++ b/include/public/nsacl/nserrdef.h
@@ -0,0 +1,100 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_NSACL_NSERRDEF_H
+#define PUBLIC_NSACL_NSERRDEF_H
+
+/*
+ * Type: NSEFrame_t
+ *
+ * Description:
+ *
+ * This type describes the structure of an error frame. An error
+ * frame contains the following items:
+ *
+ * ef_retcode - This is a copy of the traditional error code,
+ * as might be returned as a function value to
+ * indicate an error. The purpose of the error
+ * code is to provide the caller of a function
+ * with sufficient information to determine how
+ * to process the error. That is, it does not
+ * need to identify a specific error, but only
+ * has to distinguish between classes of errors
+ * as needed by the caller to respond differently.
+ * Usually this should be a small number of values.
+ *
+ * ef_errorid - This is an integer identifier which uniquely
+ * identifies errors in a module or library.
+ * That is, there should be only one place in
+ * the source code of the module or library which
+ * generates a particular error id. The error id
+ * is used to select an error message in an error
+ * message file.
+ *
+ * ef_program - This is a pointer to a string which identifies
+ * the module or library context of ef_errorid.
+ * The string is used to construct the name of
+ * the message file in which an error message for
+ * ef_errorid can be found.
+ *
+ * ef_errc - This is the number of values stored in ef_errc[]
+ * for the current error id.
+ *
+ * ef_errv - This is an array of strings which are relevant
+ * to a particular error id. These strings can
+ * be included in an error message retrieved from
+ * a message file. The strings in a message file
+ * can contain "%s" sprintf() format codes. The
+ * ef_errv[] strings are passed to sprintf() along
+ * with the error message string.
+ */
+
+#define NSERRMAXARG 8 /* size of ef_errv[] */
+
+typedef struct NSEFrame_s NSEFrame_t;
+struct NSEFrame_s {
+ NSEFrame_t * ef_next; /* next error frame on NSErr_t list */
+ long ef_retcode; /* error return code */
+ long ef_errorid; /* error unique identifier */
+ char * ef_program; /* context for ef_errorid */
+ int ef_errc; /* number of strings in ef_errv[] */
+ char * ef_errv[NSERRMAXARG];/* arguments for formatting error message */
+};
+
+/*
+ * Description (NSErr_t)
+ *
+ * This type describes the structure of a header for a list of
+ * error frames. The header contains a pointer to the first
+ * and last error frames on the list. The first error frame
+ * is normally the one most recently generated, which usually
+ * represents the highest-level interpretation available for an
+ * error that is propogating upward in a call chain. These
+ * structures are generally allocated as automatic or static
+ * variables.
+ */
+
+typedef struct NSErr_s NSErr_t;
+struct NSErr_s {
+ NSEFrame_t * err_first; /* first error frame */
+ NSEFrame_t * err_last; /* last error frame */
+ NSEFrame_t *(*err_falloc)(NSErr_t * errp); /* error frame allocator */
+ void (*err_ffree)(NSErr_t * errp,
+ NSEFrame_t * efp); /* error frame deallocator */
+};
+
+/* Define an initializer for an NSErr_t */
+#define NSERRINIT { 0, 0, 0, 0 }
+
+#ifndef INTNSACL
+
+#define nserrDispose (*__nsacl_table->f_nserrDispose)
+#define nserrFAlloc (*__nsacl_table->f_nserrFAlloc)
+#define nserrFFree (*__nsacl_table->f_nserrFFree)
+#define nserrGenerate (*__nsacl_table->f_nserrGenerate)
+
+#endif /* !INTNSACL */
+
+#endif /* !PUBLIC_NSACL_NSERRDEF_H */
diff --git a/include/public/nsacl/plistdef.h b/include/public/nsacl/plistdef.h
new file mode 100644
index 00000000..f3e804ee
--- /dev/null
+++ b/include/public/nsacl/plistdef.h
@@ -0,0 +1,62 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_NSACL_PLISTDEF_H
+#define PUBLIC_NSACL_PLISTDEF_H
+
+/*
+ * File: plistdef.h
+ *
+ * Description:
+ *
+ * This file defines the interface to property lists. Property
+ * lists are a generalization of parameter blocks (pblocks).
+ */
+
+#ifndef PUBLIC_BASE_POOL_H
+#include "../base/pool.h"
+#endif /* !PUBLIC_BASE_POOL_H */
+
+typedef struct PListStruct_s *PList_t;
+
+/* Define error codes returned from property list routines */
+
+#define ERRPLINVPI -1 /* invalid property index */
+#define ERRPLEXIST -2 /* property already exists */
+#define ERRPLFULL -3 /* property list is full */
+#define ERRPLNOMEM -4 /* insufficient dynamic memory */
+#define ERRPLUNDEF -5 /* undefined property name */
+
+#define PLFLG_OLD_MPOOL 0 /* use the plist memory pool */
+#define PLFLG_NEW_MPOOL 1 /* use the input memory pool */
+#define PLFLG_IGN_RES 2 /* ignore the reserved properties */
+#define PLFLG_USE_RES 3 /* use the reserved properties */
+
+#ifdef __cplusplus
+typedef void (PListFunc_t)(char*, const void*, void*);
+#else
+typedef void (PListFunc_t)();
+#endif
+
+#ifndef INTNSACL
+#define PListAssignValue (*__nsacl_table->f_PListAssignValue)
+#define PListCreate (*__nsacl_table->f_PListCreate)
+#define PListDefProp (*__nsacl_table->f_PListDefProp)
+#define PListDeleteProp (*__nsacl_table->f_PListDeleteProp)
+#define PListFindValue (*__nsacl_table->f_PListFindValue)
+#define PListInitProp (*__nsacl_table->f_PListInitProp)
+#define PListNew (*__nsacl_table->f_PListNew)
+#define PListDestroy (*__nsacl_table->f_PListDestroy)
+#define PListGetValue (*__nsacl_table->f_PListGetValue)
+#define PListNameProp (*__nsacl_table->f_PListNameProp)
+#define PListSetType (*__nsacl_table->f_PListSetType)
+#define PListSetValue (*__nsacl_table->f_PListSetValue)
+#define PListEnumerate (*__nsacl_table->f_PListEnumerate)
+#define PListDuplicate (*__nsacl_table->f_PListDuplicate)
+#define PListGetPool (*__nsacl_table->f_PListGetPool)
+
+#endif /* !INTNSACL */
+
+#endif /* !PUBLIC_NSACL_PLISTDEF_H */
diff --git a/include/public/nsapi.h b/include/public/nsapi.h
new file mode 100644
index 00000000..3544fd20
--- /dev/null
+++ b/include/public/nsapi.h
@@ -0,0 +1,3481 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PUBLIC_NSAPI_H
+#define PUBLIC_NSAPI_H
+
+/*
+ * File: nsapi.h
+ *
+ * Description:
+ *
+ * This file defines an interface for extending the server with
+ * in-process plug-ins.
+ */
+
+#include "base/systems.h"
+
+#if defined(FILE_UNIX_MMAP) || defined(FILE_WIN32_MMAP)
+#define FILE_MMAP
+#endif
+
+/* --- Begin miscellaneous definitions --- */
+
+/* Used in some places as a length limit on error messages */
+#define MAGNUS_ERROR_LEN 1024
+
+/* Carriage return and line feed */
+#define CR 13
+#define LF 10
+#ifdef XP_WIN32
+#define ENDLINE "\r\n"
+#else
+#define ENDLINE "\n"
+#endif
+
+/* mime.types file identification line */
+#define NCC_MT_MAGIC "#--Netscape Communications Corporation MIME Information"
+#define NCC_MT_MAGIC_LEN 55
+
+/* Deprecated */
+#define MCC_MT_MAGIC "#--Mosaic Communications Corporation MIME Information"
+#define MCC_MT_MAGIC_LEN 53
+
+/* The character which separates extensions with cinfo_find */
+#define CINFO_SEPARATOR '.'
+
+/* The maximum length of a line in a mime.types file */
+#define CINFO_MAX_LEN 1024
+
+/*
+ * The maximum length of an error message. NOT RUN-TIME CHECKED
+ */
+
+#define MAX_ERROR_LEN 1024
+
+/* A warning is a minor mishap, such as a 404 being issued. */
+#define LOG_WARN 0
+
+/*
+ * A misconfig is when there is a syntax error or permission violation in
+ * a config. file.
+ */
+#define LOG_MISCONFIG 1
+
+/*
+ * Security warnings are issued when authentication fails, or a host is
+ * given a 403 return code.
+ */
+#define LOG_SECURITY 2
+
+/*
+ * A failure is when a request could not be fulfilled due to an internal
+ * problem, such as a CGI script exiting prematurely, or a filesystem
+ * permissions problem.
+ */
+#define LOG_FAILURE 3
+
+/*
+ * A catastrophe is a fatal server error such as running out of
+ * memory or processes, or a system call failing, or even a server crash.
+ * The server child cannot recover from a catastrophe.
+ */
+#define LOG_CATASTROPHE 4
+
+/*
+ * Informational message, of no concern.
+ */
+#define LOG_INFORM 5
+
+/*
+ * Internal log messages to be logged. Internal use only.
+ * Enable with "LogVerbose on" in magnus.conf
+ */
+#define LOG_VERBOSE 6
+
+/*
+ * The time format to use in the error log
+ */
+
+#define ERR_TIMEFMT "[%d/%b/%Y:%H:%M:%S]"
+
+
+/* The fd you will get if you are reporting errors to SYSLOG */
+
+#define ERRORS_TO_SYSLOG -1
+
+/* Return codes from file I/O routines */
+#define IO_OKAY 1
+#define IO_ERROR -1
+#define IO_EOF 0
+#define NETBUF_EOF -1
+#define NETBUF_ERROR -2
+
+/* The disk page size on this machine. */
+#define FILE_BUFFERSIZE 4096
+
+#ifdef XP_UNIX
+
+#define FILE_PATHSEP '/'
+#define FILE_PARENT "../"
+
+#elif defined(XP_WIN32)
+
+#define FILE_PATHSEP '/'
+#define FILE_PARENT "..\\"
+
+#endif /* XP_WIN32 */
+
+#define NET_INFINITE_TIMEOUT 0
+#define NET_ZERO_TIMEOUT -1
+
+
+/*
+ * The following macros allow code to be written to use either the
+ * shell expression API defined here, or the regular expression
+ * pattern matching API defined in regexp.h. Regular expressions
+ * have a more complicated syntax, but also are more powerful.
+ * Define the symbol, USE_REGEX to use regular expressions. You
+ * can include either or both of shexp.h and regexp.h, regardless
+ * of whether USE_REGEX is defined or not, and the WILDPAT macros
+ * will be defined appropriately.
+ */
+
+#ifdef USE_REGEX
+
+#define WILDPAT_VALID(exp) regexp_valid(exp)
+#define WILDPAT_MATCH(str, exp) regexp_match(str, exp)
+#define WILDPAT_CMP(str, exp) regexp_cmp(str, exp)
+#define WILDPAT_CASECMP(str, exp) regexp_casecmp(str, exp)
+#define WILDPAT_USES_REGEXP 1
+
+/* Define return codes from WILDPAT_VALID */
+#define NON_WILDPAT -1 /* exp is ordinary string */
+#define INVALID_WILDPAT -2 /* exp is an invalid pattern */
+#define VALID_WILDPAT 1 /* exp is a valid pattern */
+
+#else
+
+/* WILDPAT uses shell expressions */
+#define WILDPAT_VALID(exp) shexp_valid(exp)
+#define WILDPAT_MATCH(str, exp) shexp_match(str, exp)
+#define WILDPAT_CMP(str, exp) shexp_cmp(str, exp)
+#define WILDPAT_CASECMP(str, exp) shexp_casecmp(str, exp)
+#define WILDPAT_USES_SHEXP 1
+
+/* Define return codes from WILDPAT_VALID */
+#define NON_WILDPAT -1 /* exp is ordinary string */
+#define INVALID_WILDPAT -2 /* exp is an invalid pattern */
+#define VALID_WILDPAT 1 /* exp is a valid pattern */
+
+#endif /* USE_REGEX */
+
+/* Define return codes from regexp_valid and shexp_valid */
+#define NON_SXP NON_WILDPAT /* exp is an ordinary string */
+#define INVALID_SXP INVALID_WILDPAT /* exp is an invalid shell exp */
+#define VALID_SXP VALID_WILDPAT /* exp is a valid shell exp */
+
+#ifdef USE_REGEX
+/* and regexp versions */
+#define NON_REGEXP NON_SXP
+#define INVALID_REGEXP INVALID_SXP
+#define VALID_REGEXP VALID_SXP
+#endif
+
+#define SYSTHREAD_DEFAULT_PRIORITY 16
+
+/* The longest line in the configuration file */
+#define CONF_MAXLEN 16384
+
+#define HTTP_DATE_LEN 128
+#ifdef XP_UNIX
+#define HTTP_DATE_FMT "%A, %d-%b-%y %T GMT"
+#else /* XP_WIN32 */
+#define HTTP_DATE_FMT "%A, %d-%b-%y %H:%M:%S GMT"
+#endif /* XP_WIN32 */
+
+/* HTTP status codes */
+#define PROTOCOL_CONTINUE 100 /* HTTP/1.1 */
+#define PROTOCOL_SWITCHING 101 /* HTTP/1.1 */
+#define PROTOCOL_OK 200
+#define PROTOCOL_CREATED 201
+#define PROTOCOL_NO_RESPONSE 204
+#define PROTOCOL_PARTIAL_CONTENT 206
+#define PROTOCOL_REDIRECT 302
+#define PROTOCOL_NOT_MODIFIED 304
+#define PROTOCOL_BAD_REQUEST 400
+#define PROTOCOL_UNAUTHORIZED 401
+#define PROTOCOL_FORBIDDEN 403
+#define PROTOCOL_NOT_FOUND 404
+#define PROTOCOL_METHOD_NOT_ALLOWED 405 /*HTTP/1.1 */
+#define PROTOCOL_PROXY_UNAUTHORIZED 407
+#define PROTOCOL_CONFLICT 409 /* HTTP/1.1 */
+#define PROTOCOL_LENGTH_REQUIRED 411 /*HTTP/1.1 */
+#define PROTOCOL_PRECONDITION_FAIL 412 /*HTTP/1.1 */
+#define PROTOCOL_ENTITY_TOO_LARGE 413 /*HTTP/1.1 */
+#define PROTOCOL_URI_TOO_LARGE 414 /*HTTP/1.1 */
+#define PROTOCOL_SERVER_ERROR 500
+#define PROTOCOL_NOT_IMPLEMENTED 501
+#define PROTOCOL_VERSION_NOT_SUPPORTED 505 /*HTTP/1.1 */
+
+#define CURRENT_PROTOCOL_VERSION 101
+
+/* Definitions for HTTP over SSL */
+#define HTTPS_PORT 443
+#define HTTPS_URL "https"
+
+/* Definitions for HTTP over TCP */
+#define HTTP_PORT 80
+#define HTTP_URL "http"
+
+
+#define REQ_MAX_LINE 4096
+
+/*
+ * The REQ_ return codes. These codes are used to determine what the server
+ * should do after a particular module completes its task.
+ *
+ * Func type functions return these as do many internal functions.
+ */
+
+/* The function performed its task, proceed with the request */
+#define REQ_PROCEED 0
+/* The entire request should be aborted: An error occurred */
+#define REQ_ABORTED -1
+/* The function performed no task, but proceed anyway. */
+#define REQ_NOACTION -2
+/* Tear down the session and exit */
+#define REQ_EXIT -3
+/* Restart the entire request-response process */
+#define REQ_RESTART -4
+
+/* --- End miscellaneous definitions --- */
+
+/* --- Begin native platform includes --- */
+
+#if defined(FILE_UNIX) || defined(FILE_UNIX_MMAP)
+#include <sys/types.h> /* caddr_t */
+#include <sys/file.h>
+#include <fcntl.h>
+#include <unistd.h>
+#endif
+
+#ifdef FILE_WIN32
+#include <direct.h>
+#endif /* FILE_WIN32 */
+
+#ifdef NET_WINSOCK
+#include <winsock.h>
+struct iovec {
+ char *iov_base;
+ unsigned iov_len;
+};
+#else
+#if !defined(SUNOS4) && !defined(HPUX) && !defined(LINUX)
+#include <sys/select.h>
+#endif
+#include <sys/time.h> /* struct timeval */
+#include <sys/socket.h>
+#include <netinet/in.h> /* sockaddr and in_addr */
+#include <sys/uio.h>
+#endif /* NET_WINSOCK */
+
+#include <sys/stat.h>
+
+#include <ctype.h> /* isspace */
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+
+#ifdef XP_UNIX
+#include <dirent.h>
+#include <pwd.h> /* struct passwd */
+#endif /* XP_UNIX */
+#include "libadminutil/psetc.h"
+
+/* --- End native platform includes --- */
+
+/* --- Begin type definitions --- */
+
+#ifndef SYS_FILE_T
+typedef void *SYS_FILE;
+#define SYS_FILE_T void *
+#endif /* !SYS_FILE_T */
+
+#define SYS_ERROR_FD ((SYS_FILE)-1)
+
+#ifndef SYS_NETFD_T
+typedef void *SYS_NETFD;
+#define SYS_NETFD_T void *
+#endif /* !SYS_NETFD_T */
+
+/* Error value for a SYS_NETFD */
+#ifndef SYS_NET_ERRORFD
+#define SYS_NET_ERRORFD ((SYS_NETFD)-1)
+#endif /* !SYS_NET_ERRORFD */
+
+/*
+ * Type: filebuffer, filebuf_t
+ *
+ * Description:
+ *
+ * This structure is used to represent a buffered file. On some
+ * systems the file may be memory-mapped. A filebuffer is created
+ * by filebuf_open(), and destroyed by filebuf_close().
+ *
+ * Notes:
+ *
+ * Direct access to the members of this structure, not using
+ * macros defined here, is discouraged.
+ *
+ * The filebuf alias that used to be defined for this type was
+ * found to conflict with a C++ class of the same name, so it
+ * has been renamed to filebuf_t.
+ *
+ * The inbuf field used to be (char *), but is now (unsigned char *)
+ * to simplify handling of 8-bit data. The value returned by the
+ * filebuf_getc() macro is the (unsigned char) casted to (int), or
+ * an error code. Unfortunately, IO_EOF cannot be distinguished
+ * from a zero byte, but a new function, filebuf_iseof(), is
+ * provided that will indicate definitively whether EOF has been
+ * reached.
+ */
+
+#ifdef FILE_MMAP
+
+/* Version of filebuffer when memory-mapped files are supported */
+typedef struct {
+ SYS_FILE fd;
+#ifdef FILE_UNIX_MMAP
+ caddr_t fp;
+#else /* FILE_WIN32_MMAP */
+ HANDLE fdmap;
+ char *fp;
+#endif /* FILE_UNIX_MMAP */
+ int len;
+
+ unsigned char *inbuf; /* for buffer_grab */
+ int cursize;
+
+ int pos;
+ char *errmsg;
+} filebuffer;
+
+/* Return next character or IO_EOF */
+#define filebuf_getc(b) ((b)->pos == (b)->len ? IO_EOF : (int)((unsigned char *)(b)->fp)[(b)->pos++])
+
+#define filebuf_iseof(b) ((b)->pos == (b)->len)
+
+#else
+
+/* Version of filebuffer with no memory-mapped file support */
+typedef struct {
+ SYS_FILE fd;
+
+ int pos, cursize, maxsize;
+ unsigned char *inbuf;
+ char *errmsg;
+} filebuffer;
+
+/* Return next character, IO_EOF, or IO_ERROR */
+#define filebuf_getc(b) \
+ ((b)->pos != (b)->cursize ? (int)((b)->inbuf[(b)->pos++]) : filebuf_next(b,1))
+
+#endif /* FILE_MMAP */
+
+/* C++ streamio defines a filebuf class. */
+typedef filebuffer filebuf_t;
+
+#ifdef XP_WIN32
+/* Use a filebuffer to read data from a pipe */
+#define pipebuf_getc(b) \
+ ((b)->pos != (b)->cursize ? (int)((b)->inbuf[(b)->pos++]) : pipebuf_next(b,1))
+#endif /* XP_WIN32 */
+
+/*
+ * Type: netbuf
+ *
+ * Description:
+ *
+ * This structure is used to represent a buffered network socket.
+ * It is created by netbuf_open(), and destroyed by netbuf_close().
+ *
+ * Notes:
+ *
+ * Direct access to the members of this structure, not using
+ * macros defined here, is discouraged.
+ *
+ * The inbuf field used to be (unsigned char *), but is now
+ * simply (char *). The value returned by the netbuf_getc()
+ * macro is (int).
+ */
+
+typedef struct {
+ SYS_NETFD sd;
+
+ int pos, cursize, maxsize, rdtimeout;
+#ifdef XP_WIN32
+ CHAR address[64];
+#endif /* XP_WIN32 */
+ unsigned char *inbuf;
+ char *errmsg;
+#ifndef XP_WIN32
+ char address[64];
+#endif /* !XP_WIN32 */
+} netbuf;
+
+/*
+ * netbuf_getc gets a character from the given network buffer and returns
+ * it. (as an integer).
+ *
+ * It will return (int) IO_ERROR for an error and (int) IO_EOF for
+ * an error condition or EOF respectively.
+ */
+
+#define netbuf_getc(b) \
+ ((b)->pos != (b)->cursize ? (int)((b)->inbuf[(b)->pos++]) : netbuf_next(b,1))
+
+/*
+ * buffer_error returns the last error that occurred with buffer. Don't use
+ * this unless you know an error occurred. Independent of network/file type.
+ */
+
+#define buffer_error(b) ((b)->errmsg)
+
+/*
+ * Type: cinfo
+ *
+ * Description:
+ *
+ * This is a structure that captures the information in the name/value
+ * pairs on one line of a mime.types file. A cinfo structure is
+ * stored in the memory-resident database, indexed by each of the
+ * file extensions specified in the "exts" name/value pair. It
+ * defines various attributes of resources with names containing
+ * the specified file extensions.
+ *
+ * Notes:
+ *
+ * Pointers to cinfo structures returned by this API may or may not
+ * need to freed by the caller. See the individual function
+ * descriptions.
+ *
+ * The strings referenced by the fields of cinfo structures returned
+ * by this API should be considered read-only, and do not need to be
+ * freed by the caller, even when the cinfo structure does.
+ */
+
+typedef struct {
+ char *type;
+ char *encoding;
+ char *language;
+} cinfo;
+
+
+typedef void* CONDVAR;
+typedef void *COUNTING_SEMAPHORE;
+typedef void* CRITICAL;
+
+#ifdef XP_UNIX
+typedef struct passwd *PASSWD;
+typedef DIR* SYS_DIR;
+typedef struct dirent SYS_DIRENT;
+#endif /* XP_UNIX */
+
+#ifdef XP_WIN32
+
+typedef struct {
+ char *d_name;
+} dirent_s;
+
+typedef struct {
+ HANDLE dp;
+ WIN32_FIND_DATA fdata;
+ dirent_s de;
+} dir_s;
+
+typedef dir_s* SYS_DIR;
+typedef dirent_s SYS_DIRENT;
+
+#endif /* XP_WIN32 */
+
+typedef struct {
+ char *name,*value;
+} pb_param;
+
+struct pb_entry {
+ pb_param *param;
+ struct pb_entry *next;
+};
+
+typedef struct {
+ int hsize;
+ struct pb_entry **ht;
+} pblock;
+
+#ifndef POOL_HANDLE_T
+#define POOL_HANDLE_T
+typedef void *pool_handle_t;
+#endif
+
+#ifndef SEMAPHORE_T
+typedef void *SEMAPHORE;
+#define SEMAPHORE_T void *
+#endif /* !SEMAPHORE_T */
+
+#define SESSION_HASHSIZE 5
+
+typedef struct PListStruct_s PListStruct_s;
+typedef struct ACLListHandle ACLListHandle;
+
+typedef struct Session {
+ /* Client-specific information */
+ pblock *client;
+
+ SYS_NETFD csd;
+ netbuf *inbuf;
+ int csd_open;
+
+ struct in_addr iaddr;
+
+#ifdef MCC_PROXY
+ int req_cnt;
+#endif
+
+#ifdef MALLOC_POOLS
+ pool_handle_t *pool;
+#endif /* MALLOC_POOLS */
+
+ void *clauth; /* ACL client authentication information */
+ struct Session *next;
+ int fill;
+ struct sockaddr_in local_addr; /* local addr for this session*/
+
+ PListStruct_s *subject;
+} Session;
+
+#if defined (SHMEM_UNIX_MMAP) || defined (SHMEM_WIN32_MMAP)
+typedef struct {
+ void *data; /* the data */
+#ifdef SHMEM_WIN32_MMAP
+ HANDLE fdmap;
+#endif /* SHMEM_WIN32_MMAP */
+ int size; /* the maximum length of the data */
+
+ char *name; /* internal use: filename to unlink if exposed */
+ SYS_FILE fd; /* internal use: file descriptor for region */
+} shmem_s;
+#endif /* SHMEM_UNIX_MMAP || SHMEM_WIN32_MMAP */
+
+
+/* Define a handle for a thread */
+typedef void* SYS_THREAD;
+
+/* Define an error value for the thread handle */
+#define SYS_THREAD_ERROR NULL
+
+/*
+ * Hierarchy of httpd_object
+ *
+ * An object contains dtables.
+ *
+ * Each dtable is a table of directives that were entered of a certain type.
+ * There is one dtable for each unique type of directive.
+ *
+ * Each dtable contains an array of directives, each of which is equivalent
+ * to one directive that occurred in a config. file.
+ *
+ * It is up to the caller to determine how many dtables will be allocated
+ * and to keep track of which of their directive types maps to which dtable
+ * number.
+ */
+
+
+/*
+ * directive is a structure containing the protection and parameters to an
+ * instance of a directive within an httpd_object.
+ *
+ * param is the parameters, client is the protection.
+ */
+
+typedef struct {
+ pblock *param;
+ pblock *client;
+} directive;
+
+/*
+ * dtable is a structure for creating tables of directives
+ */
+
+typedef struct {
+ int ni;
+ directive *inst;
+} dtable;
+
+/*
+ * The httpd_object structure.
+ *
+ * The name pblock array contains the names for this object, such as its
+ * virtual location, its physical location, or its identifier.
+ *
+ * tmpl contains any templates allocated to this object.
+ */
+
+typedef struct {
+ pblock *name;
+
+ int nd;
+ dtable *dt;
+} httpd_object;
+
+/*
+ * httpd_objset is a container for a bunch of objects. obj is a
+ * NULL-terminated array of objects. pos points to the entry after the last
+ * one in the array. You should not mess with pos, but can read it to find
+ * the last entry.
+ *
+ * The initfns array is a NULL-terminated array of the Init functions
+ * associated with this object set. If there are no Init functions associated
+ * with this object set, initfns can be NULL. Each pblock specifies the
+ * parameters which are passed to the function when it's executed.
+ */
+
+typedef struct {
+ int pos;
+ httpd_object **obj;
+
+ pblock **initfns;
+} httpd_objset;
+
+
+typedef struct {
+
+ /* What port we listen to */
+ int Vport;
+#define server_portnum conf_getglobals()->Vport
+
+ /* What address to bind to */
+ char *Vaddr;
+
+ /* User to run as */
+#define user_pw conf_getglobals()->Vuserpw
+ struct passwd *Vuserpw;
+
+ /* Directory to chroot to */
+ char *Vchr;
+
+ /* Where to log our pid to */
+ char *Vpidfn;
+
+#define pool_max conf_getglobals()->Vpool_max
+ int Vpool_max; /* OBSOLETE */
+#define pool_min conf_getglobals()->Vpool_min
+ int Vpool_min; /* OBSOLETE */
+#define pool_life conf_getglobals()->Vpool_life
+ int Vpool_life; /* OBSOLETE */
+
+ /* For multiprocess UNIX servers, the maximum threads per process */
+#define pool_maxthreads conf_getglobals()->Vpool_maxthreads
+ int Vpool_maxthreads;
+
+#define pool_minthreads conf_getglobals()->Vpool_minthreads
+ int Vpool_minthreads; /* OBSOLETE */
+
+ char *Vsecure_keyfn;
+ char *Vsecure_certfn;
+
+#define security_active conf_getglobals()->Vsecurity_active
+ int Vsecurity_active;
+#define ssl3_active conf_getglobals()->Vssl3_active
+ int Vssl3_active;
+#define ssl2_active conf_getglobals()->Vssl2_active
+ int Vssl2_active;
+ int Vsecure_auth;
+#define security_session_timeout conf_getglobals()->Vsecurity_session_timeout
+ int Vsecurity_session_timeout;
+#define ssl3_session_timeout conf_getglobals()->Vssl3_session_timeout
+ long Vssl3_session_timeout;
+
+ /* The server's hostname as should be reported in self-ref URLs */
+#define server_hostname conf_getglobals()->Vserver_hostname
+ char *Vserver_hostname;
+
+ /* The main object from which all are derived */
+#define root_object conf_getglobals()->Vroot_object
+ char *Vroot_object;
+
+ /* The object set the administrator has asked us to load */
+#define std_os conf_getglobals()->Vstd_os
+ httpd_objset *Vstd_os;
+
+ /* The root of ACL data structures */
+ void *Vacl_root;
+#define acl_root conf_getglobals()->Vacl_root
+
+ /* The main error log, where all errors are logged */
+#define master_error_log conf_getglobals()->Vmaster_error_log
+ char *Vmaster_error_log;
+
+ /* The server root ( in which the server sits while executing ) */
+#define server_root conf_getglobals()->Vserver_root
+ char *Vserver_root;
+
+ /* This server's id */
+#define server_id conf_getglobals()->Vserver_id
+ char *Vserver_id;
+
+ int single_accept; /* daemon mode Internal use only */
+ int num_keep_alives; /* number of KA threads Internal use only */
+ int log_verbose; /* Flag to log LOG_VERBOSE messages */
+ int mmap_flags; /* mmap flags for file cache mmaping - internal use only */
+ int mmap_prots; /* mmap prots for file cache mmaping - internal use only */
+ int unused1;
+ int unused2;
+
+ /* Begin Enterprise 3.0 fields */
+ int accept_language; /* turn accept-language on/off */
+
+ char *mtahost; /* Hostname of the Mail Transport Agent :
+ * typically "localhost" for the Unix boxes,
+ * or the hostname of a POP server otherwise.
+ * Needed by the Agents subsystem.
+ */
+ char *nntphost; /* NNTP server -> for Agents */
+
+ /* The root of ACL data structures */
+ void *Vacl_root_30;
+#define acl_root_30 conf_getglobals()->Vacl_root_30
+
+ /* This is for the agent subsystem */
+ /* The name of tha configuration parameter is: "AgentsFilePath" */
+ char* agentFilePath; /* path to agent.conf */
+#define AgentFilePath (conf_getglobals()->agentFilePath)
+
+ /* Default allowed methods - */
+ int Allowed;
+#define AllowedMethods (conf_getglobals()->Allowed)
+
+ pblock *genericGlobals; /* See conf_api.h for details on accessing
+ * these
+ */
+
+ /*Agents ACL file */
+ char* agentsACLFile;
+ int wait_for_cgi;
+ int cgiwatch_timeout;
+
+#ifdef FORTEZZA
+ uint32 fortezza_card_mask;
+ char *fortezza_personality;
+ char *krlname;
+#endif
+} conf_global_vars_s;
+
+typedef struct {
+ /* Server working variables */
+ pblock *vars;
+
+ /* The method, URI, and protocol revision of this request */
+ pblock *reqpb;
+ /* Protocol specific headers */
+ int loadhdrs;
+ pblock *headers;
+
+ /* Server's response headers */
+ int senthdrs;
+ pblock *srvhdrs;
+
+ /* The object set constructed to fulfill this request */
+ httpd_objset *os;
+ /* Array of objects that were created from .nsconfig files */
+ httpd_objset *tmpos;
+
+ /* The stat last returned by request_stat_path */
+ char *statpath;
+ char *staterr;
+ struct stat *finfo;
+
+ /* access control state */
+ int aclstate; /* ACL decision state */
+ int acldirno; /* deciding ACL directive number */
+ char * aclname; /* name of deciding ACL */
+ pblock * aclpb; /* parameter block for ACL PathCheck */
+ /* 3.0 ACL list pointer */
+ ACLListHandle *acllist;
+
+#ifdef MCC_PROXY
+ struct hostent *hp; /* proxy NSAPI: DNS resolution result */
+ char * host; /* proxy NSAPI: host to resolve/connect to */
+ int port; /* proxy NSAPI: port to connect to */
+
+ void * socks_rq; /* SOCKS request data */
+#endif
+
+ int request_is_cacheable; /* default TRUE */
+ int directive_is_cacheable; /* default FALSE */
+
+ char *cached_headers;
+ int cached_headers_len; /* length of the valid headers */
+ char *unused;
+
+ /* HTTP/1.1 features */
+ time_t req_start; /* Time request arrived - used for determining weak or*/
+ /* strong cache validation */
+#define REQ_TIME(x) (x)->req_start
+ short protv_num; /* Protocol Version number */
+ short method_num; /* Method number */
+ struct rq_attr {
+#ifdef AIX
+ unsigned abs_uri:1; /* 1=Absolute URI was used */
+ unsigned chunked:1; /* chunked transfer-coding */
+ unsigned keep_alive:1; /* connection keek-alive */
+ unsigned pipelined:1; /* request packet is pipelined */
+ unsigned reserved:28; /* If you add a bit flag, make */
+ /* sure to subtract one from this */
+#else
+ unsigned long abs_uri:1; /* 1=Absolute URI was used */
+ unsigned long chunked:1; /* chunked transfer-coding */
+ unsigned long keep_alive:1; /* connection keek-alive */
+ unsigned pipelined:1; /* request packet is pipelined */
+ unsigned long reserved:28; /* If you add a bit flag, make */
+ /* sure to subtract one from this */
+#endif
+ }rq_attr;
+ char * hostname; /* Not NULL if abs_uri */
+ int allowed; /* Allowed METHODs for this server */
+ int byterange; /* number of byte ranges */
+ short status_num; /* Status code */
+
+ int staterrno; /* used for rqstat */
+} Request;
+
+/* Request attribute macros */
+#define ABS_URI(x) (x)->rq_attr.abs_uri
+#define CHUNKED(x) (x)->rq_attr.chunked
+#define KEEP_ALIVE(x) (x)->rq_attr.keep_alive
+#define PIPELINED(x) (x)->rq_attr.pipelined
+
+/* Define METHODS for HTTP/1.1 */
+#define METHOD_HEAD 0
+#define METHOD_GET 1
+#define METHOD_PUT 2
+#define METHOD_POST 3
+#define METHOD_DELETE 4
+#define METHOD_TRACE 5
+#define METHOD_OPTIONS 6
+/* The following methods are Netscape method extensions */
+#define METHOD_MOVE 7
+#define METHOD_INDEX 8
+#define METHOD_MKDIR 9
+#define METHOD_RMDIR 10
+#define METHOD_COPY 11
+#define METHOD_MAX 12 /* Number of methods available on this server */
+
+#define ISMGET(r) ((r)->method_num == METHOD_GET)
+#define ISMHEAD(r) ((r)->method_num == METHOD_HEAD)
+#define ISMPUT(r) ((r)->method_num == METHOD_PUT)
+#define ISMPOST(r) ((r)->method_num == METHOD_POST)
+#define ISMDELETE(r) ((r)->method_num == METHOD_DELETE)
+#define ISMMOVE(r) ((r)->method_num == METHOD_MOVE)
+#define ISMINDEX(r) ((r)->method_num == METHOD_INDEX)
+#define ISMMKDIR(r) ((r)->method_num == METHOD_MKDIR)
+#define ISMRMDIR(r) ((r)->method_num == METHOD_RMDIR)
+#define ISMCOPY(r) ((r)->method_num == METHOD_COPY)
+#define ISMTRACE(r) ((r)->method_num == METHOD_TRACE)
+#define ISMOPTIONS(r) ((r)->method_num == METHOD_OPTIONS)
+
+/*
+ * FuncPtr is a pointer to our kind of functions
+ */
+
+#ifdef XP_UNIX
+typedef int Func(pblock *, Session *, Request *);
+#else /* XP_WIN32 */
+typedef int _cdecl Func(pblock *, Session *, Request *);
+#endif /* XP_WIN32 */
+
+typedef Func *FuncPtr;
+
+/*
+ * FuncStruct is a structure used in the static declaration of the
+ * functions. This static declaration is parsed into a hash table at
+ * startup. You should initialize the next entry to NULL.
+ */
+
+struct FuncStruct {
+ char *name;
+ FuncPtr func;
+ struct FuncStruct *next;
+ int flags;
+};
+
+/* --- End type definitions --- */
+
+/* --- Begin dispatch vector table definition --- */
+
+typedef struct nsapi_dispatch_s nsapi_dispatch_t;
+struct nsapi_dispatch_s {
+ char *(*f_system_version)();
+ void *(*f_system_malloc)(int size);
+ void *(*f_system_calloc)(int size);
+ void *(*f_system_realloc)(void *ptr, int size);
+ void (*f_system_free)(void *ptr);
+ char *(*f_system_strdup)(const char *ptr);
+ void *(*f_system_malloc_perm)(int size);
+ void *(*f_system_calloc_perm)(int size);
+ void *(*f_system_realloc_perm)(void *ptr, int size);
+ void (*f_system_free_perm)(void *ptr);
+ char *(*f_system_strdup_perm)(const char *ptr);
+ int (*f_getThreadMallocKey)(void);
+ void (*f_magnus_atrestart)(void (*fn)(void *), void *data);
+ filebuf_t *(*f_filebuf_open)(SYS_FILE fd, int sz);
+ netbuf *(*f_netbuf_open)(SYS_NETFD sd, int sz);
+ filebuf_t *(*f_filebuf_create)(SYS_FILE fd, caddr_t mmap_ptr,
+ int mmap_len, int bufsz);
+ void (*f_filebuf_close_buffer)(filebuf_t *buf, int clean_mmap);
+#ifdef FILE_MMAP
+ filebuf_t *(*f_filebuf_open_nostat)(SYS_FILE fd, int sz,
+ struct stat *finfo);
+#else
+ void *(*f_filebuf_open_nostat)(void);
+#endif
+#ifdef XP_WIN32
+ filebuf_t *(*f_pipebuf_open)(SYS_FILE fd, int sz, struct stat *finfo);
+#else
+ void *(*f_pipebuf_open)(void);
+#endif /* XP_WIN32 */
+#ifndef FILE_MMAP
+ int (*f_filebuf_next)(filebuf_t *buf, int advance);
+#else
+ int (*f_filebuf_next)(void);
+#endif /* !FILE_MMAP */
+ int (*f_netbuf_next)(netbuf *buf, int advance);
+#ifdef XP_WIN32
+ int (*f_pipebuf_next)(filebuf_t *buf, int advance);
+#else
+ int (*f_pipebuf_next)(void);
+#endif /* XP_WIN32 */
+ void (*f_filebuf_close)(filebuf_t *buf);
+ void (*f_netbuf_close)(netbuf *buf);
+#ifdef XP_WIN32
+ void (*f_pipebuf_close)(filebuf_t *buf);
+#else
+ void (*f_pipebuf_close)(void);
+#endif /* XP_WIN32 */
+ int (*f_filebuf_grab)(filebuf_t *buf, int sz);
+ int (*f_netbuf_grab)(netbuf *buf, int sz);
+#ifdef XP_WIN32
+ int (*f_pipebuf_grab)(filebuf_t *buf, int sz);
+#else
+ int (*f_pipebuf_grab)(void);
+#endif /* XP_WIN32 */
+ int (*f_netbuf_buf2sd)(netbuf *buf, SYS_NETFD sd, int len);
+ int (*f_filebuf_buf2sd)(filebuf_t *buf, SYS_NETFD sd);
+#ifdef XP_WIN32
+ int (*f_pipebuf_buf2sd)(filebuf_t *buf, SYS_NETFD sd, int len);
+ int (*f_pipebuf_netbuf2sd)(netbuf *buf, SYS_FILE sd, int len);
+ int (*f_pipebuf_netbuf2pipe)(netbuf *buf, SYS_NETFD sd, int len);
+#else
+ int (*f_pipebuf_buf2sd)(void);
+ int (*f_pipebuf_netbuf2sd)(void);
+ int (*f_pipebuf_netbuf2pipe)(void);
+#endif /* XP_WIN32 */
+ void (*f_cinfo_init)(void);
+ void (*f_cinfo_terminate)(void);
+ char *(*f_cinfo_merge)(char *fn);
+ cinfo *(*f_cinfo_find)(char *uri);
+ cinfo *(*f_cinfo_lookup)(char *type);
+ void (*f_cinfo_dump_database)(FILE *dump);
+ CRITICAL (*f_crit_init)(void);
+ void (*f_crit_enter)(CRITICAL id);
+ void (*f_crit_exit)(CRITICAL id);
+ void (*f_crit_terminate)(CRITICAL id);
+ CONDVAR (*f_condvar_init)(CRITICAL id);
+ void (*f_condvar_wait)(CONDVAR cv);
+ void (*f_condvar_notify)(CONDVAR cv);
+ void (*f_condvar_notifyAll)(CONDVAR cv);
+ void (*f_condvar_terminate)(CONDVAR cv);
+ COUNTING_SEMAPHORE (*f_cs_init)(int initial_count);
+ void (*f_cs_terminate)(COUNTING_SEMAPHORE csp);
+ int (*f_cs_wait)(COUNTING_SEMAPHORE csp);
+ int (*f_cs_trywait)(COUNTING_SEMAPHORE csp);
+ int (*f_cs_release)(COUNTING_SEMAPHORE csp);
+ void (*f_daemon_atrestart)(void (*fn)(void *), void *data);
+#ifdef FORTEZZA
+ /* THIS IS BOGUS... WHO Decided to export servssl_init!!! It should not
+ * be a public function.
+ */
+ void (*f_servssl_init)(void);
+#else
+ void (*f_servssl_init)(PsetHndl pset, PRFileDesc *fd, char *admRoot);
+#endif
+ int (*f_ereport)(int degree, char *fmt, ...);
+ int (*f_ereport_v)(int degree, char *fmt, va_list args);
+ char *(*f_ereport_init)(char *err_fn, char *email,
+ PASSWD pwuser, char *version);
+ void (*f_ereport_terminate)(void);
+ SYS_FILE (*f_ereport_getfd)(void);
+ SYS_FILE (*f_system_fopenRO)(char *path);
+ SYS_FILE (*f_system_fopenWA)(char *path);
+ SYS_FILE (*f_system_fopenRW)(char *path);
+ SYS_FILE (*f_system_fopenWT)(char *path);
+ int (*f_system_fread)(SYS_FILE fd, char *buf, int sz);
+ int (*f_system_fwrite)(SYS_FILE fd,char *buf,int sz);
+ int (*f_system_fwrite_atomic)(SYS_FILE fd, char *buf, int sz);
+ int (*f_system_lseek)(SYS_FILE fd, int off, int wh);
+ int (*f_system_fclose)(SYS_FILE fd);
+ int (*f_system_stat)(char *name, struct stat *finfo);
+ int (*f_system_rename)(char *oldpath, char *newpath);
+ int (*f_system_unlink)(char *path);
+ int (*f_system_tlock)(SYS_FILE fd);
+ int (*f_system_flock)(SYS_FILE fd);
+ int (*f_system_ulock)(SYS_FILE fd);
+#ifdef XP_WIN32
+ SYS_DIR (*f_dir_open)(char *path);
+ SYS_DIRENT *(*f_dir_read)(SYS_DIR ds);
+ void (*f_dir_close)(SYS_DIR ds);
+#else
+ void *(*f_dir_open)(void);
+ void *(*f_dir_read)(void);
+ void (*f_dir_close)(void);
+#endif /* XP_WIN32 */
+ int (*f_dir_create_all)(char *dir);
+#ifdef XP_WIN32
+ char *(*f_system_winsockerr)(void);
+ char *(*f_system_winerr)(void);
+ int (*f_system_pread)(SYS_FILE fd, char *buf, int sz);
+ int (*f_system_pwrite)(SYS_FILE fd, char *buf, int sz);
+ void (*f_file_unix2local)(char *path, char *p2);
+#else
+ void *(*f_system_winsockerr)(void);
+ void *(*f_system_winerr)(void);
+ int (*f_system_pread)(void);
+ int (*f_system_pwrite)(void);
+ void (*f_file_unix2local)(void);
+#endif /* XP_WIN32 */
+ int (*f_system_nocoredumps)(void);
+ int (*f_file_setinherit)(SYS_FILE fd, int value);
+ int (*f_file_notfound)(void);
+ char *(*f_system_errmsg)(void);
+ int (*f_system_errmsg_fn)(char **buff, size_t maxlen);
+ SYS_NETFD (*f_net_socket)(int domain, int type, int protocol);
+ int (*f_net_listen)(SYS_NETFD s, int backlog);
+ SYS_NETFD (*f_net_create_listener)(char *ipaddr, int port);
+ int (*f_net_connect)(SYS_NETFD s, const void *sockaddr, int namelen);
+ int (*f_net_getpeername)(SYS_NETFD s, struct sockaddr *name, int *namelen);
+ int (*f_net_close)(SYS_NETFD s);
+ int (*f_net_bind)(SYS_NETFD s, const struct sockaddr *name, int namelen);
+ SYS_NETFD (*f_net_accept)(SYS_NETFD s, struct sockaddr *addr, int *addrlen);
+ int (*f_net_read)(SYS_NETFD sd, char *buf, int sz, int timeout);
+ int (*f_net_write)(SYS_NETFD sd, char *buf, int sz);
+ int (*f_net_writev)(SYS_NETFD sd, struct iovec *iov, int iovlen);
+ int (*f_net_isalive)(SYS_NETFD sd);
+ char *(*f_net_ip2host)(char *ip, int verify);
+ int (*f_net_getsockopt)(SYS_NETFD s, int level, int optname,
+ void *optval, int *optlen);
+ int (*f_net_setsockopt)(SYS_NETFD s, int level, int optname,
+ const void *optval, int optlen);
+ int (*f_net_select)(int nfds, fd_set *r, fd_set *w, fd_set *e,
+ struct timeval *timeout);
+ int (*f_net_ioctl)(SYS_NETFD s, int tag, void *result);
+ pb_param *(*f_param_create)(char *name, char *value);
+ int (*f_param_free)(pb_param *pp);
+ pblock *(*f_pblock_create)(int n);
+ void (*f_pblock_free)(pblock *pb);
+ char *(*f_pblock_findval)(const char *name, pblock *pb);
+ pb_param *(*f_pblock_nvinsert)(const char *name, const char *value, pblock *pb);
+ pb_param *(*f_pblock_nninsert)(const char *name, int value, pblock *pb);
+ void (*f_pblock_pinsert)(pb_param *pp, pblock *pb);
+ int (*f_pblock_str2pblock)(const char *str, pblock *pb);
+ char *(*f_pblock_pblock2str)(pblock *pb, char *str);
+ void (*f_pblock_copy)(pblock *src, pblock *dst);
+ pblock *(*f_pblock_dup)(pblock *src);
+ char **(*f_pblock_pb2env)(pblock *pb, char **env);
+ pb_param *(*f_pblock_fr)(const char *name, pblock *pb, int remove);
+ char * (*f_pblock_replace)(const char *name,char * new_value,pblock *pb);
+ pool_handle_t *(*f_pool_create)(void);
+ void (*f_pool_destroy)(pool_handle_t *pool_handle);
+ int (*f_pool_enabled)(void);
+ void *(*f_pool_malloc)(pool_handle_t *pool_handle, size_t size );
+ void (*f_pool_free)(pool_handle_t *pool_handle, void *ptr );
+ void *(*f_pool_calloc)(pool_handle_t *pool_handle, size_t nelem, size_t elsize);
+ void *(*f_pool_realloc)(pool_handle_t *pool_handle, void *ptr, size_t size );
+ char *(*f_pool_strdup)(pool_handle_t *pool_handle, const char *orig_str );
+#if defined(MCC_PROXY) && defined(USE_REGEX)
+ int (*f_regexp_valid)(char *exp);
+ int (*f_regexp_match)(char *str, char *exp);
+ int (*f_regexp_cmp)(char *str, char *exp);
+ int (*f_regexp_casecmp)(char *str, char *exp);
+#else
+ int (*f_regexp_valid)(void);
+ int (*f_regexp_match)(void);
+ int (*f_regexp_cmp)(void);
+ int (*f_regexp_casecmp)(void);
+#endif
+ SEMAPHORE (*f_sem_init)(char *name, int number);
+ void (*f_sem_terminate)(SEMAPHORE id);
+ int (*f_sem_grab)(SEMAPHORE id);
+ int (*f_sem_tgrab)(SEMAPHORE id);
+ int (*f_sem_release)(SEMAPHORE id);
+ Session *(*f_session_alloc)(SYS_NETFD csd, struct sockaddr_in *sac); /* internal */
+ Session *(*f_session_fill)(Session *sn); /* internal */
+ Session *(*f_session_create)(SYS_NETFD csd, struct sockaddr_in *sac);
+ void (*f_session_free)(Session *sn);
+ char *(*f_session_dns_lookup)(Session *sn, int verify);
+ int (*f_shexp_valid)(char *exp);
+ int (*f_shexp_match)(char *str, char *exp);
+ int (*f_shexp_cmp)(char *str, char *exp);
+ int (*f_shexp_casecmp)(char *str, char *exp);
+#if defined (SHMEM_UNIX_MMAP) || defined (SHMEM_WIN32_MMAP)
+ shmem_s *(*f_shmem_alloc)(char *name, int size, int expose);
+ void (*f_shmem_free)(shmem_s *region);
+#else
+ void *(*f_shmem_alloc)(void);
+ void (*f_shmem_free)(void);
+#endif /* SHMEM_UNIX_MMAP || SHMEM_WIN32_MMAP */
+ SYS_THREAD (*f_systhread_start)(int prio, int stksz, void (*fn)(void *), void *arg);
+ SYS_THREAD (*f_systhread_current)(void);
+ void (*f_systhread_yield)(void);
+ SYS_THREAD (*f_systhread_attach)(void);
+ void (*f_systhread_detach)(SYS_THREAD thr);
+ void (*f_systhread_terminate)(SYS_THREAD thr);
+ void (*f_systhread_sleep)(int milliseconds);
+ void (*f_systhread_init)(char *name);
+ void (*f_systhread_timerset)(int usec);
+ int (*f_systhread_newkey)(void);
+ void *(*f_systhread_getdata)(int key);
+ void (*f_systhread_setdata)(int key, void *data);
+ void (*f_systhread_set_default_stacksize)(unsigned long size);
+ int (*f_util_getline)(filebuffer *buf, int lineno, int maxlen, char *l);
+ char **(*f_util_env_create)(char **env, int n, int *pos);
+ char *(*f_util_env_str)(char *name, char *value);
+ void (*f_util_env_replace)(char **env, char *name, char *value);
+ void (*f_util_env_free)(char **env);
+ char **(*f_util_env_copy)(char **src, char **dst);
+ char *(*f_util_env_find)(char **env, char *name);
+ char *(*f_util_hostname)(void);
+ int (*f_util_chdir2path)(char *path);
+ int (*f_util_is_mozilla)(char *ua, char *major, char *minor);
+ int (*f_util_is_url)(char *url);
+ int (*f_util_later_than)(struct tm *lms, char *ims);
+ int (*f_util_time_equal)(struct tm *lms, char *ims);
+ int (*f_util_str_time_equal)(char *t1, char *t2);
+ int (*f_util_uri_is_evil)(char *t);
+ void (*f_util_uri_parse)(char *uri);
+ void (*f_util_uri_unescape)(char *s);
+ char *(*f_util_uri_escape)(char *d, char *s);
+ char *(*f_util_url_escape)(char *d, char *s);
+ char *(*f_util_sh_escape)(char *s);
+ int (*f_util_mime_separator)(char *sep);
+ int (*f_util_itoa)(int i, char *a);
+ int (*f_util_vsprintf)(char *s, register const char *fmt, va_list args);
+ int (*f_util_sprintf)(char *s, const char *fmt, ...);
+ int (*f_util_vsnprintf)(char *s, int n, register const char *fmt,
+ va_list args);
+ int (*f_util_snprintf)(char *s, int n, const char *fmt, ...);
+ int (*f_util_strftime)(char *s, const char *format, const struct tm *t);
+ char *(*f_util_strtok)(char *s1, const char *s2, char **lasts);
+ struct tm *(*f_util_localtime)(const time_t *clock, struct tm *res);
+ char *(*f_util_ctime)(const time_t *clock, char *buf, int buflen);
+ char *(*f_util_strerror)(int errnum, char *msg, int buflen);
+ struct tm *(*f_util_gmtime)(const time_t *clock, struct tm *res);
+ char *(*f_util_asctime)(const struct tm *tm,char *buf, int buflen);
+#ifdef NEED_STRCASECMP
+ int (*f_util_strcasecmp)(CASECMPARG_T char *one, CASECMPARG_T char *two);
+#else
+ int (*f_util_strcasecmp)(void);
+#endif /* NEED_STRCASECMP */
+#ifdef NEED_STRNCASECMP
+ int (*f_util_strncasecmp)(CASECMPARG_T char *one, CASECMPARG_T char *two, int n);
+#else
+ int (*f_util_strncasecmp)(void);
+#endif /* NEED_STRNCASECMP */
+#ifdef XP_UNIX
+ int (*f_util_can_exec)(struct stat *finfo, uid_t uid, gid_t gid);
+ struct passwd *(*f_util_getpwnam)(const char *name, struct passwd
+ *result, char *buffer, int buflen);
+ pid_t (*f_util_waitpid)(pid_t pid, int *statptr, int options);
+#else
+ int (*f_util_can_exec)(void);
+ void *(*f_util_getpwnam)(void);
+ int (*f_util_waitpid)(void);
+#endif /* XP_UNIX */
+#ifdef XP_WIN32
+ VOID (*f_util_delete_directory)(char *FileName, BOOL delete_directory);
+#else
+ void (*f_util_delete_directory)(void);
+#endif /* XP_WIN32 */
+ char *(*f_conf_init)(char *cfn);
+ char *(*f_conf_run_init_functions)(void);
+ void (*f_conf_terminate)(void);
+ conf_global_vars_s *(*f_conf_getglobals)(void);
+ void (*f_func_init)(struct FuncStruct *func_standard);
+ FuncPtr (*f_func_find)(char *name);
+ int (*f_func_exec)(pblock *pb, Session *sn, Request *rq);
+ struct FuncStruct *(*f_func_insert)(char *name, FuncPtr fn);
+ int (*f_object_execute)(directive *inst, Session *sn, void *rq);
+ Request *(*f_http_find_request)(netbuf *buf, Session *sn, int *reply);
+ int (*f_http_parse_request)(char *t, Request *rq, Session *sn);
+ int (*f_http_scan_headers)(Session *sn, netbuf *buf, char *t,
+ pblock *headers);
+ int (*f_http_start_response)(Session *sn, Request *rq);
+ char **(*f_http_hdrs2env)(pblock *pb);
+ void (*f_http_status)(Session *sn, Request *rq, int n, char *r);
+ int (*f_http_set_finfo)(Session *sn, Request *rq, struct stat *finfo);
+ char *(*f_http_dump822)(pblock *pb, char *t, int *pos, int tsz);
+ void (*f_http_finish_request)(Session *sn, Request *rq);
+ void (*f_http_handle_session)(Session *sn);
+ char *(*f_http_uri2url)(const char *prefix, const char *suffix);
+ char *(*f_http_uri2url_dynamic)(const char *prefix, const char *suffix,
+ Session *sn, Request *rq);
+ void (*f_http_set_keepalive_timeout)(int secs);
+ int (*f_log_error_v)(int degree, char *func, Session *sn, Request *rq,
+ char *fmt, va_list args);
+ int (*f_log_error)(int degree, char *func, Session *sn, Request *rq,
+ char *fmt, ...);
+ int (*f_log_ereport_v)(int degree, char *fmt, va_list args);
+ int (*f_log_ereport)(int degree, char *fmt, ...);
+ httpd_object *(*f_object_create)(int nd, pblock *name);
+ void (*f_object_free)(httpd_object *obj);
+ void (*f_object_add_directive)(int dc, pblock *p, pblock *c,
+ httpd_object *obj);
+ httpd_objset *(*f_objset_scan_buffer)(filebuffer *buf, char *errstr,
+ httpd_objset *os);
+ httpd_objset *(*f_objset_create)(void);
+ void (*f_objset_free)(httpd_objset *os);
+ void (*f_objset_free_setonly)(httpd_objset *os);
+ httpd_object *(*f_objset_new_object)(pblock *name, httpd_objset *os);
+ void (*f_objset_add_object)(httpd_object *obj, httpd_objset *os);
+ void (*f_objset_add_init)(pblock *initfn, httpd_objset *os);
+ httpd_object *(*f_objset_findbyname)(char *name, httpd_objset *ign,
+ httpd_objset *os);
+ httpd_object *(*f_objset_findbyppath)(char *ppath, httpd_objset *ign,
+ httpd_objset *os);
+ Request *(*f_request_create)(void);
+ void (*f_request_free)(Request *req);
+ Request *(*f_request_restart_internal)(char *uri, Request *rq);
+ int (*f_request_header)(char *name, char **value, Session *sn,
+ Request *rq);
+ struct stat *(*f_request_stat_path)(char *path, Request *rq);
+ char *(*f_conf_getServerString)(void);
+ FuncPtr (*f_func_replace)(char *funcname, FuncPtr fn);
+ int (*f_net_socketpair)(SYS_NETFD *pair);
+#ifdef XP_UNIX
+ SYS_NETFD (*f_net_dup2)(SYS_NETFD prfd, int osfd);
+ int (*f_net_is_STDOUT)(SYS_NETFD prfd);
+ int (*f_net_is_STDIN)(SYS_NETFD prfd);
+#else
+ void *(*f_net_dup2)(void);
+ int (*f_net_is_STDOUT)(void);
+ int (*f_net_is_STDIN)(void);
+#endif /* XP_UNIX */
+ int (*f_func_set_native_thread_flag)(char *name, int flags);
+ void *(*f_random_create)(void);
+ void (*f_random_update)(void *rctx, unsigned char *inbuf, int length);
+ void (*f_random_generate)(void *rctx, unsigned char *outbuf, int length);
+ void (*f_random_destroy)(void *rctx);
+ void *(*f_md5hash_create)(void);
+ void *(*f_md5hash_copy)(void *hctx);
+ void (*f_md5hash_begin)(void *hctx);
+ void (*f_md5hash_update)(void *hctx, unsigned char *inbuf, int length);
+ void (*f_md5hash_end)(void *hctx, unsigned char *outbuf);
+ void (*f_md5hash_destroy)(void *hctx);
+ void (*f_md5hash_data)(unsigned char *outbuf, unsigned char *src, int length);
+ int (*f_ACL_SetupEval)(struct ACLListHandle *acllist, Session *sn, Request *rq, char **rights, char **map_generic, const char *user);
+ int (*f_netbuf_getbytes)(netbuf *buf, char *buffer, int size);
+ char *(*f_servact_translate_uri)(char *uri, Session *sn);
+
+};
+
+/* --- End dispatch vector table definition --- */
+
+/* --- Begin API macro definitions --- */
+
+#ifndef INTNSAPI
+
+#define system_version (*__nsapi30_table->f_system_version)
+
+/*
+ Depending on the system, memory allocated via these macros may come from
+ an arena. If these functions are called from within an Init function, they
+ will be allocated from permanent storage. Otherwise, they will be freed
+ when the current request is finished.
+ */
+
+#define MALLOC (*__nsapi30_table->f_system_malloc)
+#define system_malloc (*__nsapi30_table->f_system_malloc)
+
+#define CALLOC (*__nsapi30_table->f_system_calloc)
+#define system_calloc (*__nsapi30_table->f_system_calloc)
+
+#define REALLOC (*__nsapi30_table->f_system_realloc)
+#define system_realloc (*__nsapi30_table->f_system_realloc)
+
+#define FREE (*__nsapi30_table->f_system_free)
+#define system_free (*__nsapi30_table->f_system_free)
+
+#define STRDUP (*__nsapi30_table->f_system_strdup)
+#define system_strdup (*__nsapi30_table->f_system_strdup)
+
+#ifndef NS_MALLOC_DEBUG
+
+/*
+ These macros always provide permanent storage, for use in global variables
+ and such. They are checked at runtime to prevent them from returning NULL.
+ */
+
+#define PERM_MALLOC (*__nsapi30_table->f_system_malloc_perm)
+#define system_malloc_perm (*__nsapi30_table->f_system_malloc_perm)
+
+#define PERM_CALLOC (*__nsapi30_table->f_system_calloc_perm)
+#define system_calloc_perm (*__nsapi30_table->f_system_calloc_perm)
+
+#define PERM_REALLOC (*__nsapi30_table->f_system_realloc_perm)
+#define system_realloc_perm (*__nsapi30_table->f_system_realloc_perm)
+
+#define PERM_FREE (*__nsapi30_table->f_system_free_perm)
+#define system_free_perm (*__nsapi30_table->f_system_free_perm)
+
+#define PERM_STRDUP (*__nsapi30_table->f_system_strdup_perm)
+#define system_strdup_perm (*__nsapi30_table->f_system_strdup_perm)
+
+#endif /* !NS_MALLOC_DEBUG */
+
+/* Thread-Private data key index for accessing the thread-private memory pool.
+ * Each thread creates its own pool for allocating data. The MALLOC/FREE/etc
+ * macros have been defined to check the thread private data area with the
+ * thread_malloc_key index to find the address for the pool currently in use.
+ *
+ * If a thread wants to use a different pool, it must change the thread-local-
+ * storage[thread_malloc_key].
+ */
+
+#define getThreadMallocKey (*__nsapi30_table->f_getThreadMallocKey)
+
+#define magnus_atrestart (*__nsapi30_table->f_magnus_atrestart)
+
+/*
+ * buffer_open opens a new buffer reading the specified file, with an I/O
+ * buffer of size sz, and returns a new buffer structure which will hold
+ * the data.
+ *
+ * If FILE_UNIX_MMAP is defined, this may return NULL. If it does, check
+ * system_errmsg to get a message about the error.
+ */
+
+#define filebuf_open (*__nsapi30_table->f_filebuf_open)
+#define netbuf_open (*__nsapi30_table->f_netbuf_open)
+
+/*
+ * filebuf_open_nostat is a convenience function for mmap() buffer opens,
+ * if you happen to have the stat structure already.
+ */
+
+#ifdef FILE_MMAP
+#define filebuf_open_nostat (*__nsapi30_table->f_filebuf_open_nostat)
+#endif /* FILE_MMAP */
+
+/*
+ * filebuf_create is a convenience function if the file is already open
+ * or mmap'd. It creates a new filebuf for use with the mmap'd file.
+ * If mmap_ptr is NULL, or MMAP is not supported on this system, it
+ * creates a buffer with buffer size bufsz.
+ */
+
+#define filebuf_create (*__nsapi30_table->f_filebuf_create)
+
+/*
+ * filebuf_close_buffer is provided to cleanup a filebuf without closing
+ * the underlying file. If clean_mmap is 1, and the file is memory mapped,
+ * the file will be unmapped. If clean_mmap is 0, the file will not
+ * be unmapped.
+ */
+#define filebuf_close_buffer (*__nsapi30_table->f_filebuf_close_buffer)
+
+#ifdef FILE_MMAP
+#define filebuf_open_nostat (*__nsapi30_table->f_filebuf_open_nostat)
+#endif
+
+#ifdef XP_WIN32
+#define pipebuf_open (*__nsapi30_table->f_pipebuf_open)
+#endif /* XP_WIN32 */
+
+/*
+ * buffer_next loads size more bytes into the given buffer and returns the
+ * first one, or BUFFER_EOF on EOF and BUFFER_ERROR on error.
+ */
+
+#ifndef FILE_MMAP
+#define filebuf_next (*__nsapi30_table->f_filebuf_next)
+#endif /* !FILE_MMAP */
+#define netbuf_next (*__nsapi30_table->f_netbuf_next)
+#ifdef XP_WIN32
+#define pipebuf_next (*__nsapi30_table->f_pipebuf_next)
+#endif /* XP_WIN32 */
+
+/*
+ * buffer_close deallocates a buffer and closes its associated files
+ * (does not close a network socket).
+ */
+
+#define filebuf_close (*__nsapi30_table->f_filebuf_close)
+#define netbuf_close (*__nsapi30_table->f_netbuf_close)
+#ifdef XP_WIN32
+#define pipebuf_close (*__nsapi30_table->f_pipebuf_close)
+#endif /* XP_WIN32 */
+
+/*
+ * buffer_grab will set the buffer's inbuf array to an array of sz bytes
+ * from the buffer's associated object. It returns the number of bytes
+ * actually read (between 1 and sz). It returns IO_EOF upon EOF or IO_ERROR
+ * upon error. The cursize entry of the structure will reflect the size
+ * of the iobuf array.
+ *
+ * The buffer will take care of allocation and deallocation of this array.
+ */
+
+#define filebuf_grab (*__nsapi30_table->f_filebuf_grab)
+#define netbuf_grab (*__nsapi30_table->f_netbuf_grab)
+#ifdef XP_WIN32
+#define pipebuf_grab (*__nsapi30_table->f_pipebuf_grab)
+#endif /* XP_WIN32 */
+
+/*
+ * netbuf_getbytes will read bytes from the netbuf into the user
+ * supplied buffer. Up to size bytes will be read.
+ * If the call is successful, the number of bytes read is returned.
+ * NETBUF_EOF is returned when no more data will arrive on the socket,
+ * and NETBUF_ERROR is returned in the event of an error.
+ *
+ */
+#define netbuf_getbytes (*__nsapi30_table->f_netbuf_getbytes)
+
+
+/*
+ * netbuf_buf2sd will send n bytes from the (probably previously read)
+ * buffer and send them to sd. If sd is -1, they are discarded. If n is
+ * -1, it will continue until EOF is recieved. Returns IO_ERROR on error
+ * and the number of bytes sent any other time.
+ */
+
+#define netbuf_buf2sd (*__nsapi30_table->f_netbuf_buf2sd)
+
+/*
+ * filebuf_buf2sd assumes that nothing has been read from the filebuf,
+ * and just sends the file out to the given socket. Returns IO_ERROR on error
+ * and the number of bytes sent otherwise.
+ *
+ * Does not currently support you having read from the buffer previously. This
+ * can be changed transparently.
+ */
+
+#define filebuf_buf2sd (*__nsapi30_table->f_filebuf_buf2sd)
+
+#ifdef XP_WIN32
+
+/*
+ * NT pipe version of filebuf_buf2sd.
+ */
+#define pipebuf_buf2sd (*__nsapi30_table->f_pipebuf_buf2sd)
+
+/*
+ * NT pipe version of netbuf_buf2sd.
+ */
+
+#define pipebuf_netbuf2sd (*__nsapi30_table->f_pipebuf_netbuf2sd)
+#define pipebuf_netbuf2pipe (*__nsapi30_table->f_pipebuf_netbuf2pipe)
+#endif /* XP_WIN32 */
+
+/*
+ * Notes:
+ *
+ * Format of a mime.types file
+ *
+ * A mime.types file passed to cinfo_merge() should begin with
+ * a line containing NCC_MT_MAGIC as defined below (MCC_MT_MAGIC
+ * is also still supported). Lines containing only whitespace
+ * and lines beginning with "#" are ignored. Other lines contain
+ * one or more name/value pairs, separated by whitespace. The
+ * format of each of these is NAME=VALUE, where NAME is one of:
+ *
+ * type - VALUE is a mime type, e.g. text/html
+ * exts - VALUE is a list of file extensions, e.g. htm,html
+ * enc - VALUE specifies a content encoding, e.g. x-gzip
+ * lang - VALUE specifies a content language, e.g. en-US
+ * (see RFC1766)
+ *
+ * The VALUE may be enclosed in quotes (" "), and should be if it
+ * contains whitespace.
+ *
+ * Each line in the file that contains at least one name/value
+ * pair causes a cinfo structure to be created, containing the
+ * specified information. These structures are kept in memory
+ * and can be queried using cinfo_find().
+ *
+ * Related information
+ *
+ * See the NSAPI "load-types" function.
+ */
+
+/*
+ * Function: cinfo_init
+ *
+ * Description:
+ *
+ * This function initializes the memory resident content information
+ * database to be empty.
+ *
+ * Notes:
+ *
+ * This function is called by the NSAPI "load-types" function,
+ * which also sets up a call to cinfo_terminate() on server restart.
+ * If "load-types" is used, it should be unnecessary to call this
+ * function.
+ */
+
+#define cinfo_init (*__nsapi30_table->f_cinfo_init)
+
+/*
+ * Function: cinfo_terminate
+ *
+ * Description:
+ *
+ * This function frees all dynamic memory associated with the
+ * memory resident content information database, and leaves the
+ * database empty. cinfo_init() should be called before using
+ * the database again.
+ */
+
+#define cinfo_terminate (*__nsapi30_table->f_cinfo_terminate)
+
+/*
+ * Function: cinfo_merge
+ *
+ * Description:
+ *
+ * This function reads a mime.types formatted file of the specified
+ * name. Content information in the file is merged into the
+ * memory resident content information database.
+ *
+ * Arguments:
+ *
+ * fn - name of mime.types formatted file
+ *
+ * Returns:
+ *
+ * If successful, NULL is returned. If an error occurs, the return
+ * value is a pointer to a descriptive error string, which should
+ * be freed by the caller (using FREE()). Information processed
+ * prior to the error will still be added to the database.
+ */
+
+#define cinfo_merge (*__nsapi30_table->f_cinfo_merge)
+
+
+/*
+ * Function: cinfo_find
+ *
+ * Description:
+ *
+ * This function is used to retrieve content information based on
+ * a file extension contained in the argument string, which might
+ * be either a URI or a file name. It ignores any text up to and
+ * including the last FILE_PATHSEP character in the argument
+ * string. It looks for one or more file extensions in the
+ * remaining string, each one starting with a CINFO_SEPARATOR
+ * character. Each file extension is looked up in the database
+ * and any information found there is used to build a composite
+ * cinfo structure, containing information derived from each of
+ * the file extensions. If more than one file extensions present
+ * have a particular piece of information associated with them
+ * in the database (e.g. type or language), the value returned in
+ * the composite cinfo structure is taken from the data for the
+ * last file extension to provide that attribute.
+ *
+ * Arguments:
+ *
+ * uri - pointer to the argument string
+ *
+ * Returns:
+ *
+ * If successful, a pointer to the composite cinfo structure is
+ * returned. The fields of this structure reference values of
+ * those fields in one or more cinfo structures in the database,
+ * so these values should be copied if they are going to be
+ * modified. The cinfo structure itself should be freed by the
+ * caller using FREE(). If an error occurs, a null pointer is
+ * returned. If no information is found for any of the extensions,
+ * a null pointer is returned, although this is not necessarily
+ * an error.
+ *
+ * Notes:
+ *
+ * The matching of extensions in the argument string to extensions
+ * in the database is case-insensitive.
+ *
+ * The argument string is modified during parsing, but only
+ * temporarily. It should be intact on return.
+ */
+
+#define cinfo_find (*__nsapi30_table->f_cinfo_find)
+
+/*
+ * Function: cinfo_lookup
+ *
+ * Description:
+ *
+ * This function returns a pointer to the last cinfo structure
+ * added to the database for a specified mime type. Unlike
+ * cinfo_find(), the returned pointer references a cinfo structure
+ * that is part of the database, and corresponds to a single line
+ * in a mime.types file. This structure should be considered
+ * read-only, and should not be freed by the caller.
+ *
+ * Arguments:
+ *
+ * type - a pointer to a mime type string
+ *
+ * Returns:
+ *
+ * If the specified type is found, a pointer to the cinfo structure
+ * returned. Otherwise a null pointer is returned.
+ *
+ * Notes:
+ *
+ * The search for the type is case-insensitive.
+ */
+
+#define cinfo_lookup (*__nsapi30_table->f_cinfo_lookup)
+
+/*
+ * Function: cinfo_dump_database
+ *
+ * Description:
+ *
+ * This function outputs, to a specified file, formatted text
+ * describing the contents of the content information database.
+ * This is intended for debugging purposes. It is not in mime.types
+ * format.
+ *
+ * Arguments:
+ *
+ * dump - handle for already open output file
+ */
+
+#define cinfo_dump_database (*__nsapi30_table->f_cinfo_dump_database)
+
+/*
+ * Critical section abstraction. Used in threaded servers to protect
+ * areas where two threads can interfere with each other.
+ *
+ * Condvars are condition variables that are used for thread-thread
+ * synchronization.
+ */
+
+/*
+ * crit_init creates and returns a new critical section variable. At the
+ * time of creation no one has entered it.
+ */
+#define crit_init (*__nsapi30_table->f_crit_init)
+
+/*
+ * crit_enter enters a critical section. If someone is already in the
+ * section, the calling thread is blocked until that thread exits.
+ */
+#define crit_enter (*__nsapi30_table->f_crit_enter)
+
+/*
+ * crit_exit exits a critical section. If another thread is blocked waiting
+ * to enter, it will be unblocked and given ownership of the section.
+ */
+#define crit_exit (*__nsapi30_table->f_crit_exit)
+
+/*
+ * crit_terminate removes a previously allocated critical section variable.
+ */
+#define crit_terminate (*__nsapi30_table->f_crit_terminate)
+
+/*
+ * condvar_init initializes and returns a new condition variable. You
+ * must provide a critical section to be associated with this condition
+ * variable.
+ */
+#define condvar_init (*__nsapi30_table->f_condvar_init)
+
+/*
+ * condvar_wait blocks on the given condition variable. The calling thread
+ * will be blocked until another thread calls condvar_notify on this variable.
+ * The caller must have entered the critical section associated with this
+ * condition variable prior to waiting for it.
+ */
+#define condvar_wait (*__nsapi30_table->f_condvar_wait)
+
+/*
+ * condvar_notify awakens any threads blocked on the given condition
+ * variable. The caller must have entered the critical section associated
+ * with this variable first.
+ */
+#define condvar_notify (*__nsapi30_table->f_condvar_notify)
+
+/*
+ * condvar_notify awakens all threads blocked on the given condition
+ * variable. The caller must have entered the critical section associated
+ * with this variable first.
+ */
+#define condvar_notifyAll (*__nsapi30_table->f_condvar_notifyAll)
+
+/*
+ * condvar_terminate frees the given previously allocated condition variable
+ */
+#define condvar_terminate (*__nsapi30_table->f_condvar_terminate)
+
+/*
+ * Create a counting semaphore.
+ * Return non-zero on success, 0 on failure.
+ */
+#define cs_init (*__nsapi30_table->f_cs_init)
+
+/*
+ * Destroy a counting semaphore
+ */
+#define cs_terminate (*__nsapi30_table->f_cs_terminate)
+
+/*
+ * Wait to "enter" the semaphore.
+ * Return 0 on success, -1 on failure.
+ */
+#define cs_wait (*__nsapi30_table->f_cs_wait)
+
+/*
+ * Enter the semaphore if the count is > 0. Otherwise return -1.
+ *
+ */
+#define cs_trywait (*__nsapi30_table->f_cs_trywait)
+
+/*
+ * Release the semaphore- allowing a thread to enter.
+ * Return 0 on success, -1 on failure.
+ */
+#define cs_release (*__nsapi30_table->f_cs_release)
+
+/*
+ * daemon_atrestart registers a function to be called fn, with the given
+ * void pointer as an argument, when the server is restarted.
+ */
+#define daemon_atrestart (*__nsapi30_table->f_daemon_atrestart)
+
+#define servssl_init (*__nsapi30_table->f_servssl_init)
+
+/*
+ * ereport logs an error of the given degree and formats the arguments with
+ * the printf() style fmt. Returns whether the log was successful. Records
+ * the current date.
+ */
+
+#define ereport (*__nsapi30_table->f_ereport)
+#define ereport_v (*__nsapi30_table->f_ereport_v)
+
+/*
+ * ereport_init initializes the error logging subsystem and opens the static
+ * file descriptors. It returns NULL upon success and an error string upon
+ * error. If a userpw is given, the logs will be chowned to that user.
+ *
+ * email is the address of a person to mail upon catastrophic error. It
+ * can be NULL if no e-mail is desired. ereport_init will not duplicate
+ * its own copy of this string; you must make sure it stays around and free
+ * it when you shut down the server.
+ */
+
+#define ereport_init (*__nsapi30_table->f_ereport_init)
+
+/*
+ * log_terminate closes the error and common log file descriptors.
+ */
+#define ereport_terminate (*__nsapi30_table->f_ereport_terminate)
+
+/* For restarts */
+#define ereport_getfd (*__nsapi30_table->f_ereport_getfd)
+
+/* FUNCTION: system_fopenXX
+ * DESCRIPTION:
+ * system_fopenRO - Open a disk file for read-only access.
+ * system_fopenWA - Open a disk file for write and append access.
+ * system_fopenRW - Open a disk file for read-write access.
+ * system_fopenWT - Open a disk file for write and truncate access.
+ * INPUTS:
+ * path- the name of the file
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * SYS_ERRORFD on failure
+ * A opaque file handle on success
+ * RESTRICTIONS:
+ * The return from this function should not be interpreted as a native
+ * file handle. It may only be used in other calls to system_xxx().
+ *
+ * Note for unix programmers: Although this routine is called
+ * "system_fopen" do not consider it to be equivalent to the unix
+ * "fopen" call, which opens a buffered-IO file.
+ */
+#define system_fopenRO (*__nsapi30_table->f_system_fopenRO)
+#define system_fopenWA (*__nsapi30_table->f_system_fopenWA)
+#define system_fopenRW (*__nsapi30_table->f_system_fopenRW)
+#define system_fopenWT (*__nsapi30_table->f_system_fopenWT)
+
+/* FUNCTION: system_fread
+ * DESCRIPTION:
+ * Read from a file
+ * INPUTS:
+ * fd- an open file handle to read from
+ * buf- a buffer to receive data
+ * sz- the number of bytes to read from the file
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * less-than-zero on failure
+ * 0 for end-of-file
+ * positive for number of bytes read
+ * RESTRICTIONS:
+ */
+#define system_fread (*__nsapi30_table->f_system_fread)
+
+/* FUNCTION: system_write
+ * DESCRIPTION:
+ * Writes sz bytes from buf to file fd.
+ * INPUTS:
+ * fd- the file to write to
+ * buf- the buffer containing data to be written
+ * sz- the size of data to write.
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * IO_OKAY on success
+ * IO_ERROR on failure
+ * RESTRICTIONS:
+ * There is no way to determine if bytes were written when this call fails.
+ * For more specific information, use PR_WRITE().
+ */
+#define system_fwrite (*__nsapi30_table->f_system_fwrite)
+
+/* FUNCTION: system_fwrite_atomic
+ * DESCRIPTION:
+ * system_fwrite_atomic locks the given fd before writing to it. This
+ * avoids interference between simultaneous writes.
+ * INPUTS:
+ * fd- the file to write to
+ * buf- the buffer containing data to be written
+ * sz- the size of data to write.
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * IO_OKAY on success
+ * IO_ERROR on failure
+ * RESTRICTIONS:
+ */
+#define system_fwrite_atomic (*__nsapi30_table->f_system_fwrite_atomic)
+
+/* FUNCTION: system_lseek
+ * DESCRIPTION:
+ * Seek to a position in a file
+ * INPUTS:
+ * fd- an open file handle
+ * off
+ * wh
+ * OUTPUTS:
+ * RETURNS:
+ * RESTRICTIONS:
+ */
+#define system_lseek (*__nsapi30_table->f_system_lseek)
+
+/* FUNCTION: system_fclose
+ * DESCRIPTION:
+ * Close a file.
+ * INPUTS:
+ * fd- an open file handle from a previous system_fopenXX call.
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * IO_OKAY on success
+ * IO_ERROR on failure
+ * RESTRICTIONS:
+ */
+#define system_fclose (*__nsapi30_table->f_system_fclose)
+
+/* FUNCTION: system_stat
+ * DESCRIPTION:
+ * Get information about a file on disk
+ * INPUTS:
+ * name- the name of the file to be queried
+ * OUTPUTS:
+ * finfo- a buffer to receive the file information.
+ * RETURN:
+ * less-than-zero on failure.
+ * 0 on success.
+ * RESTRICTIONS:
+ * Within the stat structure, this routine is only guaranteed to return
+ * st_mode, st_size, st_ctime, and st_mtime. Other stat fields are
+ * undefined.
+ */
+#define system_stat (*__nsapi30_table->f_system_stat)
+
+/* --- File manipulation --------------------------------------------- */
+
+/* FUNCTION: system_rename
+ * DESCRIPTION:
+ * Rename a file on disk.
+ * INPUTS:
+ * oldpath- old file name
+ * newpath- new file name
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * less-than-zero on failure
+ * 0 on success
+ * RESTRICTIONS:
+ * Not guaranteed to work portably on files which are in use.
+ */
+#define system_rename (*__nsapi30_table->f_system_rename)
+
+/* FUNCTION: system_unlink
+ * DESCRIPTION:
+ * Remove a file from disk.
+ * INPUTS:
+ * path- the file to delete
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * less-than-zero on failure
+ * 0 on success
+ * RESTRICTIONS:
+ * Not guaranteed to work portably on files which are in use.
+ */
+#define system_unlink (*__nsapi30_table->f_system_unlink)
+
+/* --- File locking -------------------------------------------------- */
+
+#define system_initlock(fd) (0)
+
+/* FUNCTION: system_tlock
+ * DESCRIPTION:
+ * Test for a file lock and grab it if it is available
+ * INPUTS:
+ * fd- the file to lock
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * 0 - if we now hold the lock
+ * less-than-zero if the lock is held by someone else
+ * RESTRICTIONS:
+ * 1. file locking is process based. Two threads in the same process
+ * requesting exclusive access will both be allowed to access the file
+ * at the same time.
+ */
+#define system_tlock (*__nsapi30_table->f_system_tlock)
+
+/* FUNCTION: system_flock
+ * DESCRIPTION:
+ * Wait for exclusive access to a file
+ * INPUTS:
+ * fd- the file to lock
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * 0 - if we now hold the lock
+ * less-than-zero if an error occurred
+ * RESTRICTIONS:
+ * 1. file locking is process based. Two threads in the same process
+ * requesting exclusive access will both be allowed to access the file
+ * at the same time.
+ */
+#define system_flock (*__nsapi30_table->f_system_flock)
+
+/* FUNCTION: system_ulock
+ * DESCRIPTION:
+ * Release exclusive access to a file
+ * INPUTS:
+ * fd- the file to lock
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * 0 - if we released the lock
+ * less-than-zero if an error occurred
+ * RESTRICTIONS:
+ * 1. file locking is process based. Two threads in the same process
+ * requesting exclusive access will both be allowed to access the file
+ * at the same time.
+ */
+#define system_ulock (*__nsapi30_table->f_system_ulock)
+
+/* --- Directory manipulation routines ---------------------------------- */
+
+#ifdef XP_WIN32
+#define dir_open (*__nsapi30_table->f_dir_open)
+#define dir_read (*__nsapi30_table->f_dir_read)
+#define dir_close (*__nsapi30_table->f_dir_close)
+#endif /* XP_WIN32 */
+
+/*
+ * create a directory and any of its parents
+ */
+#define dir_create_all (*__nsapi30_table->f_dir_create_all)
+
+#ifdef XP_WIN32
+#define system_winsockerr (*__nsapi30_table->f_system_winsockerr)
+#define system_winerr (*__nsapi30_table->f_system_winerr)
+#define system_pread (*__nsapi30_table->f_system_pread)
+#define system_pwrite (*__nsapi30_table->f_system_pwrite)
+#define file_unix2local (*__nsapi30_table->f_file_unix2local)
+#endif /* XP_WIN32 */
+
+#define system_nocoredumps (*__nsapi30_table->f_system_nocoredumps)
+#define file_setinherit (*__nsapi30_table->f_file_setinherit)
+#define file_notfound (*__nsapi30_table->f_file_notfound)
+#define system_errmsg (*__nsapi30_table->f_system_errmsg)
+#define system_errmsg_fn (*__nsapi30_table->f_system_errmsg_fn)
+
+/* FUNCTION: net_socket
+ * DESCRIPTION:
+ * Create a new socket.
+ * INPUTS:
+ * domain- only supported type is AF_INET
+ * type- only supported type is SOCK_STREAM
+ * protocol- only supported value is 0
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * SYS_NET_ERRORFD on errro
+ * a valid SYS_NETFD on success
+ * RESTRICTIONS:
+ */
+#define net_socket (*__nsapi30_table->f_net_socket)
+
+/* FUNCTION: net_listen
+ * DESCRIPTION:
+ * Set listen backlog for a socket.
+ * INPUTS:
+ * s- the socket
+ * backlog- value of backlog to set
+ * OUTPUTS:
+ * RETURNS:
+ * 0 on success
+ * less-than-zero on failure
+ * RESTRICTIONS:
+ * Some systems do not return errors even when the requested backlog
+ * cannot be set (it is too high). Consult your system manual for
+ * details on the maximum value of the backlog.
+ */
+#define net_listen (*__nsapi30_table->f_net_listen)
+
+/* FUNCTION: net_create_listener
+ * DESCRIPTION:
+ * Creates a socket for accepting new connection.
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * SYS_NET_ERRORFD on error.
+ * RESTRICTIONS:
+ * This is a convenience routine which creates a socket, binds to
+ * an IP address and port, and sets the listen backlog to
+ * net_listenqsize.
+ */
+#define net_create_listener (*__nsapi30_table->f_net_create_listener)
+
+/* FUNCTION: net_connect
+ * DESCRIPTION:
+ * Connect a socket to a remote listener
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * 0 on success
+ * less-than-zero on error
+ * RESTRICTIONS:
+ */
+#define net_connect (*__nsapi30_table->f_net_connect)
+
+/* FUNCTION: net_getpeername
+ * DESCRIPTION:
+ * Get the socket address (IP address/port) of the remote host.
+ * INPUTS:
+ * s- the socket
+ * name - the socket address of the remote
+ * OUTPUTS:
+ * RETURNS:
+ * RESTRICTIONS:
+ */
+#define net_getpeername (*__nsapi30_table->f_net_getpeername)
+
+/* FUNCTION: net_close
+ * DESCRIPTION:
+ * Close an open socket
+ * INPUTS:
+ * s- the socket to close
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * 0 on success
+ * less-than-zero on failure
+ * RESTRICTIONS:
+ */
+#define net_close (*__nsapi30_table->f_net_close)
+
+/* FUNCTION: net_bind
+ * DESCRIPTION:
+ * Bind to a socket address
+ * INPUTS:
+ * s-
+ * name-
+ * namelen-
+ * OUTPUTS:
+ * RETURNS:
+ * RESTRICTIONS:
+ */
+#define net_bind (*__nsapi30_table->f_net_bind)
+
+/* FUNCTION: net_accept
+ * DESCRIPTION:
+ * Accept a connection on a listener socket.
+ * INPUTS:
+ * s
+ * addr
+ * OUTPUTS:
+ * addrlen
+ * RETURNS:
+ * RESTRICTIONS:
+ */
+#define net_accept (*__nsapi30_table->f_net_accept)
+
+/* FUNCTION: net_read
+ * DESCRIPTION:
+ * sd
+ * buf
+ * sz
+ * timeout
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * IO_ERROR on error
+ * 0 if the remote closes the socket
+ * positive representing the number of bytes successfully read
+ * RESTRICTIONS:
+ * timeout must be NET_ZERO_TIMEOUT, NET_INFINITE_TIMEOUT, or a positive
+ * value in seconds
+ */
+#define net_read (*__nsapi30_table->f_net_read)
+
+/* FUNCTION: net_write
+ * DESCRIPTION:
+ * Write data to a socket.
+ * INPUTS:
+ * sd
+ * buf
+ * sz
+ * OUTPUTS:
+ * RETURNS:
+ * RESTRICTIONS:
+ * net_write() is unbuffered. Specifying many calls to net_write() for
+ * small amounts of data is inefficient.
+ */
+#define net_write (*__nsapi30_table->f_net_write)
+
+/* FUNCTION: net_writev
+ * DESCRIPTION:
+ * Write vectored data to the socket.
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * RESTRICTIONS:
+ * net_writev() is unbuffered. Specifying many calls to net_writev() for
+ * small amounts of data is inefficient.
+ */
+#define net_writev (*__nsapi30_table->f_net_writev)
+
+/* FUNCTION: net_isalive
+ * DESCRIPTION:
+ * Checks to see if the given socket is still connected to a remote
+ * host. The remote host does not see any side effects from this call.
+ * INPUTS:
+ * sd - the socket
+ * OUTPUTS:
+ * none
+ * RETURNS:
+ * 0 if the socket is no longer connected
+ * 1 if the socket is still connected.
+ * RESTRICTIONS:
+ */
+#define net_isalive (*__nsapi30_table->f_net_isalive)
+
+/* FUNCTION: net_ip2host
+ * DESCRIPTION:
+ * Transforms the given textual IP number into a fully qualified domain
+ * name (FQDN). This is similar to calling gethostbyaddr().
+ * INPUTS:
+ * verify- If 1, specifies that the function should verify the hostname
+ * returned from the lookup. This is similar to calling
+ * gethostbyname() on the result of the call to gethostbyaddr().
+ * OUTPUTS:
+ * RETURNS:
+ * The fully qualified domain name, or whatever it can find.
+ * If it cannot resolve the name at all, returns NULL.
+ * RESTRICTIONS:
+ * This function is governed by the use of the Server DNS cache. If caching
+ * is enabled it can take as long as 20 minutes before this function
+ * does the lookup again.
+ */
+#define net_ip2host (*__nsapi30_table->f_net_ip2host)
+
+
+/* --- OBSOLETE ----------------------------------------------------------
+ * The following macros/functions are obsolete and are only maintained for
+ * compatibility. Do not use them.
+ * -----------------------------------------------------------------------
+ */
+
+/* FUNCTION: net_getsockopt
+ * DESCRIPTION:
+ * Get socket options
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * RESTRICTIONS:
+ * Because this function is not portable (not all systems support the
+ * same options), it should be used with caution.
+ */
+#define net_getsockopt (*__nsapi30_table->f_net_getsockopt)
+
+/* FUNCTION: net_setsockopt
+ * DESCRIPTION:
+ * Set socket options
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * RESTRICTIONS:
+ * Because this function is not portable (not all systems support the
+ * same options), it should be used with caution.
+ */
+#define net_setsockopt (*__nsapi30_table->f_net_setsockopt)
+
+/* FUNCTION: net_select
+ * DESCRIPTION:
+ * Wait for IO on a set of sockets.
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * -1 on error
+ * 0 on timeout
+ * positive value representing the number of IOs ready
+ * RESTRICTIONS:
+ * Because this function is not portable (not all systems support the
+ * same options), it should be used with caution.
+ */
+#define net_select (*__nsapi30_table->f_net_select)
+
+/* FUNCTION: net_ioctl
+ * DESCRIPTION:
+ * Set socket options.
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * RESTRICTIONS:
+ * Because this function is not portable (not all systems support the
+ * same options), it should be used with caution.
+ */
+#define net_ioctl (*__nsapi30_table->f_net_ioctl)
+
+/* FUNCTION: net_socketpair
+ * DESCRIPTION:
+ * Creates a TCP socketpair.
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * 0 on success
+ * -1 on failure
+ * RESTRICTIONS:
+ * Because this function is not portable (not all systems support the
+ * same options), it should be used with caution.
+ */
+#define net_socketpair (*__nsapi30_table->f_net_socketpair)
+
+#ifdef XP_UNIX
+/* FUNCTION: net_dup2
+ * DESCRIPTION:
+ * Duplicates a socket to a specific file descriptor
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * RESTRICTIONS:
+ * Because this function is not portable (not all systems support the
+ * same options), it should be used with caution.
+ */
+#define net_dup2 (*__nsapi30_table->f_net_dup2)
+
+/* FUNCTION: net_is_STDOUT
+ * DESCRIPTION:
+ * Checks if the underlying OS file descriptor for the given
+ * SYS_NETFD is the STDOUT filedescriptor
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * 1 if it is STDOUT (1)
+ * 0 otherwise
+ * RESTRICTIONS:
+ * Because this function is not portable (not all systems support the
+ * same options), it should be used with caution.
+ */
+#define net_is_STDOUT (*__nsapi30_table->f_net_is_STDOUT)
+
+/* FUNCTION: net_is_STDIN
+ * DESCRIPTION:
+ * Checks if the underlying OS file descriptor for the given
+ * SYS_NETFD is the STDIN filedescriptor
+ * INPUTS:
+ * OUTPUTS:
+ * RETURNS:
+ * 1 if it is STDIN (0)
+ * 0 otherwise
+ * RESTRICTIONS:
+ * Because this function is not portable (not all systems support the
+ * same options), it should be used with caution.
+ */
+#define net_is_STDIN (*__nsapi30_table->f_net_is_STDIN)
+#endif /* XP_UNIX */
+
+/*
+ * A parameter block is a set of name=value pairs which are generally used
+ * as parameters, but can be anything. They are kept in a hash table for
+ * reasonable speed, but if you are doing any intensive modification or
+ * access of them you should probably make a local copy of each parameter
+ * while working.
+ *
+ * When creating a pblock, you specify the hash table size for that pblock.
+ * You should set this size larger if you know that many items will be in
+ * that pblock, and smaller if only a few will be used or if speed is not
+ * a concern.
+ */
+
+/*
+ * param_create creates a parameter with the given name and value. If name
+ * and value are non-NULL, they are copied and placed into the new pb_param
+ * struct.
+ */
+
+#define param_create (*__nsapi30_table->f_param_create)
+
+/*
+ * param_free frees a given parameter if it's non-NULL, and returns 1 if
+ * p was non-NULL, and 0 if p was NULL.
+ *
+ * Useful for error checking pblock_remove.
+ */
+
+#define param_free (*__nsapi30_table->f_param_free)
+
+/*
+ * pblock_create creates a new pblock with hash table size n.
+ *
+ * It returns the newly allocated pblock.
+ */
+
+#define pblock_create (*__nsapi30_table->f_pblock_create)
+
+/*
+ * pblock_free frees the given pblock and any entries inside it.
+ *
+ * If you want to save anything in a pblock, remove its entities with
+ * pblock_remove first and save the pointers you get.
+ */
+
+#define pblock_free (*__nsapi30_table->f_pblock_free)
+
+/*
+ * pblock_findval finds the entry with the given name in pblock pb, and
+ * returns its value, otherwise returns NULL.
+ */
+
+#define pblock_findval (*__nsapi30_table->f_pblock_findval)
+
+/*
+ * pblock_nvinsert creates a new parameter with the given name and value
+ * and inserts it into pblock pb. The name and value in the parameter are
+ * also newly allocated. Returns the pb_param it allocated (in case you
+ * need it).
+ *
+ * pblock_nninsert inserts a numerical value.
+ */
+
+#define pblock_nvinsert (*__nsapi30_table->f_pblock_nvinsert)
+#define pblock_nninsert (*__nsapi30_table->f_pblock_nninsert)
+
+/*
+ * pblock_pinsert inserts a pb_param into a pblock.
+ */
+
+#define pblock_pinsert (*__nsapi30_table->f_pblock_pinsert)
+
+/*
+ * pblock_str2pblock scans the given string str for parameter pairs
+ * name=value, or name="value". Any \ must be followed by a literal
+ * character. If a string value is found, with no unescaped = signs, it
+ * will be added with the name 1, 2, 3, etc. depending on whether it was
+ * first, second, third, etc. in the stream (zero doesn't count).
+ *
+ * Returns the number of parameters added to the table, or -1 upon error.
+ */
+
+#define pblock_str2pblock (*__nsapi30_table->f_pblock_str2pblock)
+
+/*
+ * pblock_pblock2str places all of the parameters in the given pblock
+ * into the given string (NULL if it needs creation). It will re-allocate
+ * more space for the string. Each parameter is separated by a space and of
+ * the form name="value"
+ */
+
+#define pblock_pblock2str (*__nsapi30_table->f_pblock_pblock2str)
+
+/*
+ * pblock_copy copies the entries in the given source pblock to the
+ * destination one. The entries are newly allocated so that the original
+ * pblock may be freed or the new one changed without affecting the other.
+ */
+
+#define pblock_copy (*__nsapi30_table->f_pblock_copy)
+
+/*
+ * pblock_dup creates a new pblock and copies the given source pblock
+ * into it. The entries are newly allocated so that the original pblock
+ * may be freed or the new one changed without affecting the other.
+ */
+
+#define pblock_dup (*__nsapi30_table->f_pblock_dup)
+
+/*
+ * pblock_pb2env copies the given pblock into the given environment, with
+ * one new env entry for each name/value pair in the pblock.
+ */
+
+#define pblock_pb2env (*__nsapi30_table->f_pblock_pb2env)
+
+/* --------------------------- Internal things ---------------------------- */
+#define pblock_fr (*__nsapi30_table->f_pblock_fr)
+#define pblock_replace (*__nsapi30_table->f_pblock_replace)
+
+/* pool_create()
+ * Function to create a new pool.
+ * Returns non-NULL on success, NULL on failure.
+ */
+#define pool_create (*__nsapi30_table->f_pool_create)
+
+/* pool_destroy()
+ * Frees all memory associated with a pool and destroys the pool.
+ */
+#define pool_destroy (*__nsapi30_table->f_pool_destroy)
+
+/* pool_enabled()
+ * Check if the pools are enabled and a pool is currently set
+ * for this thread. Return 1 if enabled, 0 if not enabled.
+ */
+#define pool_enabled (*__nsapi30_table->f_pool_enabled)
+
+#define pool_malloc (*__nsapi30_table->f_pool_malloc)
+#define pool_free (*__nsapi30_table->f_pool_free)
+#define pool_calloc (*__nsapi30_table->f_pool_calloc)
+#define pool_realloc (*__nsapi30_table->f_pool_realloc)
+#define pool_strdup (*__nsapi30_table->f_pool_strdup)
+
+/*
+ * regexp_valid takes a regular expression exp as input. It returns:
+ *
+ * NON_REGEXP if exp is a standard string
+ * (above not used -- always returns VALID_REGEXP!!)
+ * INVALID_REGEXP if exp is a regular expression, but invalid
+ * VALID_REGEXP if exp is a valid regular expression
+ */
+
+#define regexp_valid (*__nsapi30_table->f_regexp_valid)
+
+/*
+ * regexp_match
+ *
+ * Takes a prevalidated shell expression exp, and a string str.
+ *
+ * Returns 0 on match and 1 on non-match.
+ */
+
+#define regexp_match (*__nsapi30_table->f_regexp_match)
+
+/*
+ * regexp_cmp
+ *
+ * Same as above, but validates the exp first. 0 on match, 1 on non-match,
+ * -1 on invalid exp. regexp_casecmp does the same thing but is case
+ * insensitive.
+ */
+
+#define regexp_cmp (*__nsapi30_table->f_regexp_cmp)
+#define regexp_casecmp (*__nsapi30_table->f_regexp_casecmp)
+
+/*
+ * sem_init creates a semaphore using the given name and unique
+ * identification number. filename should be a file accessible to the
+ * process. Returns SEM_ERROR on error.
+ */
+
+#define sem_init (*__nsapi30_table->f_sem_init)
+
+/*
+ * sem_terminate de-allocates the given semaphore.
+ */
+
+#define sem_terminate (*__nsapi30_table->f_sem_terminate)
+
+/*
+ * sem_grab attempts to gain exclusive access to the given semaphore. If
+ * it can't get it, the caller will block. Returns -1 on error.
+ */
+
+#define sem_grab (*__nsapi30_table->f_sem_grab)
+#define sem_tgrab (*__nsapi30_table->f_sem_tgrab)
+
+/*
+ * sem_release releases this process's exclusive control over the given
+ * semaphore. Returns -1 on error.
+ */
+
+#define sem_release (*__nsapi30_table->f_sem_release)
+
+/*
+ * session_create creates a new request structure for the client with the
+ * given socket descriptor and sockaddr.
+ */
+
+#define session_alloc (*__nsapi30_table->f_session_alloc)
+#define session_fill (*__nsapi30_table->f_session_fill)
+#define session_create (*__nsapi30_table->f_session_create)
+
+/*
+ * session_free frees the given session
+ */
+
+#define session_free (*__nsapi30_table->f_session_free)
+
+#define session_dns_lookup (*__nsapi30_table->f_session_dns_lookup)
+
+/*
+ * This describes the API for matching a string with a "shell expression".
+ * The expressions accepted are based loosely on the expressions accepted
+ * by zsh. A shell expression is a string pattern made up of ordinary
+ * characters and any of the types of pattern sequences listed below.
+ *
+ * Pattern Matches
+ * * zero or more characters
+ * ? exactly one character
+ * $ matches the end of string
+ * [abc] matches one instance of any of the characters
+ * enclosed in []
+ * [a-z] matches one instance of any character in the
+ * specified range of characters
+ * [^abc] matches one instance of any character not
+ * in the enclosed set
+ *
+ * Backslash (\) is used to quote a character that would otherwise be
+ * considered part of a pattern sequence, e.g. "2\*2=4".
+ *
+ * The following composite shell expression structures are also
+ * recognized:
+ *
+ * shexp1~shexp2 matches any string that matches shexp1,
+ * unless the string also matches shexp2
+ *
+ * Example: "*~*.netscape.com" matches any string that does
+ * not end with ".netscape.com"
+ *
+ * (shexp1|...|shexpN) matches any string that matches any one of
+ * the ()-enclosed, |-separated shell
+ * expressions.
+ */
+
+/* Determine whether exp is a valid shell expression */
+#define shexp_valid (*__nsapi30_table->f_shexp_valid)
+
+/*
+ * shexp_match
+ *
+ * Takes a prevalidated shell expression exp, and a string str.
+ *
+ * Returns 0 on match and 1 on non-match.
+ */
+
+#define shexp_match (*__nsapi30_table->f_shexp_match)
+
+
+/*
+ * shexp_cmp
+ *
+ * Same as above, but validates the exp first. 0 on match, 1 on non-match,
+ * -1 on invalid exp. shexp_casecmp does the same thing but is case
+ * insensitive.
+ */
+
+#define shexp_cmp (*__nsapi30_table->f_shexp_cmp)
+#define shexp_casecmp (*__nsapi30_table->f_shexp_casecmp)
+
+/*
+ * Regular expression API - Analogous to shell expression API
+ */
+
+#define regexp_valid (*__nsapi30_table->f_regexp_valid)
+#define regexp_match (*__nsapi30_table->f_regexp_match)
+#define regexp_cmp (*__nsapi30_table->f_regexp_cmp)
+#define regexp_casecmp (*__nsapi30_table->f_regexp_casecmp)
+
+
+#if defined (SHMEM_UNIX_MMAP) || defined (SHMEM_WIN32_MMAP)
+
+/*
+ * shmem_alloc allocates a region of shared memory of the given size, using
+ * the given name to avoid conflicts between multiple regions within the
+ * program. The region will not be automatically grown if its boundaries
+ * are over-run, use shmem_realloc for that.
+ *
+ * If expose is non-zero and the underlying system supports it, the
+ * file used to create the shared region will be visible to other processes
+ * running on the system.
+ *
+ * name should be unique to the program which calls this routine, otherwise
+ * conflicts will arise.
+ *
+ * Returns a new shared memory region, with the data element being a
+ * pointer to the shared memory. This function must be called before any
+ * daemon workers are spawned, in order for the handle to the shared region
+ * to be inherited by the children.
+ *
+ * Because of the requirement that the region must be inherited by the
+ * children, the region cannot be re-allocated with a larger size when
+ * necessary.
+ */
+#define shmem_alloc (*__nsapi30_table->f_shmem_alloc)
+
+/*
+ * shmem_free de-allocates the specified region of shared memory.
+ */
+#define shmem_free (*__nsapi30_table->f_shmem_free)
+
+#endif /* SHMEM_UNIX_MMAP || SHMEM_WIN32_MMAP */
+
+/*
+ * systhread_start creates a thread with the given priority, will allocate
+ * a stack of stksz bytes, and calls fn with arg as its argument. stksz
+ * of zero will allocate a default stack size.
+ *
+ * Returns a new SYS_THREAD pointer on success, SYS_THREAD_ERROR on failure.
+ * XXX Priorities are system dependent
+ */
+
+#define systhread_start (*__nsapi30_table->f_systhread_start)
+
+/*
+ * systhread_current returns a handle for the current thread.
+ */
+
+#define systhread_current (*__nsapi30_table->f_systhread_current)
+
+/*
+ * systhread_yield yields the processor to another thread
+ */
+
+#define systhread_yield (*__nsapi30_table->f_systhread_yield)
+
+/*
+ * systhread_attach makes an existing thread an NSPR thread.
+ */
+#define systhread_attach (*__nsapi30_table->f_systhread_attach)
+
+/*
+ * Detaches a thread that was attached.
+ */
+
+#define systhread_detach (*__nsapi30_table->f_systhread_detach)
+
+/*
+ * systhread_terminate terminates the thread that is passed in.
+ */
+#define systhread_terminate (*__nsapi30_table->f_systhread_terminate)
+
+/*
+ * systhread_sleep puts the calling thread to sleep for the given number
+ * of milliseconds.
+ */
+#define systhread_sleep (*__nsapi30_table->f_systhread_sleep)
+
+/*
+ * systhread_init initializes the threading system. name is a name for the
+ * program for debugging.
+ */
+
+#define systhread_init (*__nsapi30_table->f_systhread_init)
+
+/*
+ * systhread_timerset starts or re-sets the interrupt timer for a thread
+ * system. This should be considered a suggestion as most systems don't allow
+ * the timer interval to be changed.
+ */
+
+#define systhread_timerset (*__nsapi30_table->f_systhread_timerset)
+
+/*
+ * newkey allocates a new integer id for thread-private data. Use this
+ * key to identify a variable which you want to appear differently
+ * between threads, and then use setdata to associate a value with this
+ * key for each thread.
+ */
+#define systhread_newkey (*__nsapi30_table->f_systhread_newkey)
+
+/*
+ * Get data that has been previously associated with key in this thread.
+ * Returns NULL if setkey has not been called with this key by this
+ * thread previously, or the data that was previously used with setkey
+ * by this thread with this key.
+ */
+#define systhread_getdata (*__nsapi30_table->f_systhread_getdata)
+
+/*
+ * Associate data with the given key number in this thread.
+ */
+#define systhread_setdata (*__nsapi30_table->f_systhread_setdata)
+
+/*
+ * Set the default stack size for threads created via systhr_start
+ */
+#define systhread_set_default_stacksize (*__nsapi30_table->f_systhread_set_default_stacksize)
+
+/*
+ * A hodge podge of utility functions and standard functions which
+ * are unavailable on certain systems
+ */
+
+/*
+ * getline scans in buf until it finds a LF or CRLF, storing the string in
+ * l. It will terminate the string and return:
+ *
+ * 0 when done, with the scanned line (minus CR or LF) in l
+ * 1 upon EOF, with the scanned line (minus CR or LF) in l
+ * -1 on error with the error description in l (uses lineno for information)
+ */
+
+#define util_getline (*__nsapi30_table->f_util_getline)
+
+/*
+ * env_create creates a new environment with the given env, with n new
+ * entries, and places the current position that you should add your
+ * entries with at pos.
+ *
+ * If env is NULL, it will allocate a new one. If not, it will reallocate
+ * that one.
+ */
+
+#define util_env_create (*__nsapi30_table->f_util_env_create)
+
+/*
+ * util_env_str allocates a string from the given name and value and
+ * returns it. It does not check for things like = signs in name.
+ */
+
+#define util_env_str (*__nsapi30_table->f_util_env_str)
+
+/*
+ * env_replace replaces the occurrence of the given variable with the
+ * value you give.
+ */
+
+#define util_env_replace (*__nsapi30_table->f_util_env_replace)
+
+/*
+ * util_env_free frees an environment.
+ */
+
+#define util_env_free (*__nsapi30_table->f_util_env_free)
+
+/*
+ * util_env_copy copies an env
+ */
+#define util_env_copy (*__nsapi30_table->f_util_env_copy)
+
+/*
+ * util_env_find looks through env for the named string. Returns the
+ * corresponding value if the named string is found, or NULL if not.
+ */
+#define util_env_find (*__nsapi30_table->f_util_env_find)
+
+/*
+ * hostname gets the local hostname. Returns NULL if it can't find a FQDN.
+ * You are free to realloc or free this string.
+ */
+
+#define util_hostname (*__nsapi30_table->f_util_hostname)
+
+/*
+ * chdir2path changes the current directory to the one that the file
+ * path is in. path should point to a file. Caveat: path must be a writable
+ * string. It won't get modified permanently.
+ */
+
+#define util_chdir2path (*__nsapi30_table->f_util_chdir2path)
+
+/*
+ * is_mozilla checks if the given user-agent is mozilla, of at least
+ * the given major and minor revisions. These are strings to avoid
+ * ambiguities like 1.56 > 1.5
+ */
+
+#define util_is_mozilla (*__nsapi30_table->f_util_is_mozilla)
+
+/*
+ * is_url will return 1 if the given string seems to be a URL, or will
+ * return 0 otherwise.
+ *
+ * Because of stupid news URLs, this will return 1 if the string has
+ * all alphabetic characters up to the first colon and will not check for
+ * the double slash.
+ */
+
+#define util_is_url (*__nsapi30_table->f_util_is_url)
+
+/*
+ * util_later_than checks the date in the string ims, and if that date is
+ * later than or equal to the one in the tm struct lms, then it returns 1.
+ *
+ * util_time_equal is above, but checks for exact equality.
+ *
+ * Handles RFC 822, 850, and ctime formats.
+ */
+
+#define util_later_than (*__nsapi30_table->f_util_later_than)
+#define util_time_equal (*__nsapi30_table->f_util_time_equal)
+
+/*
+ * util_str_time_equal checks the character-string dates are equal.
+ * Supports rfc1123 and rfc850 formats. t1 must be rfc1123
+ * Returns 0 if equal, -1 otherwise
+ */
+#define util_str_time_equal (*__nsapi30_table->f_util_str_time_equal)
+
+/*
+ * util_uri_is_evil returns 1 if a URL has ../ or // in it.
+ */
+#define util_uri_is_evil (*__nsapi30_table->f_util_uri_is_evil)
+
+/*
+ * util_uri_parse gets rid of /../, /./, and //.
+ *
+ * Assumes that either the string starts with a /, or the string will
+ * not .. right off of its beginning. As such, ../foo.gif will
+ * not be changed, although /../foo.gif will become /foo.gif.
+ */
+
+#define util_uri_parse (*__nsapi30_table->f_util_uri_parse)
+
+/*
+ * util_uri_unescape unescapes the given URI in place (% conversions only).
+ */
+
+#define util_uri_unescape (*__nsapi30_table->f_util_uri_unescape)
+
+/*
+ * util_uri_escape escapes any nasty chars in s and copies the string into d.
+ * If d is NULL, it will allocate and return a properly sized string.
+ * Warning: does not check bounds on a given d.
+ *
+ * util_url_escape does the same thing but does it for a url, i.e. ?:+ is
+ * not escaped.
+ */
+
+#define util_uri_escape (*__nsapi30_table->f_util_uri_escape)
+#define util_url_escape (*__nsapi30_table->f_util_url_escape)
+
+/*
+ * util_sh_escape places a \ in front of any shell-special characters.
+ * Returns a newly-allocated copy of the string.
+ */
+
+#define util_sh_escape (*__nsapi30_table->f_util_sh_escape)
+
+/*
+ * util_mime_separator generates a new MIME separator into the given buffer.
+ * The buffer should be more than 4 + 3*10 + 1 bytes long. A CRLF is prepended
+ * to the beginning of the string, along with two dashes. The string is null
+ * terminated, with no CRLF. The intent is that you create your content-type
+ * header by accessing &sep[4], and afterwards print sep followed by CRLF
+ * for message boundaries.
+ *
+ * Returns the length of the string.
+ */
+#define util_mime_separator (*__nsapi30_table->f_util_mime_separator)
+
+/*
+ * util_itoa converts the given integer to a string into a.
+ */
+
+#define util_itoa (*__nsapi30_table->f_util_itoa)
+
+/*
+ * util_vsprintf and util_sprintf are simplified clones of the System V
+ * vsprintf and sprintf routines.
+ *
+ * Returns the number of characters printed. Only handles %d and %s,
+ * does not handle any width or precision.
+ */
+
+#define util_vsprintf (*__nsapi30_table->f_util_vsprintf)
+#define util_sprintf (*__nsapi30_table->f_util_sprintf)
+
+/* These routines perform bounds checks. */
+#define util_vsnprintf (*__nsapi30_table->f_util_vsnprintf)
+#define util_snprintf (*__nsapi30_table->f_util_snprintf)
+
+/* util_strftime()
+ * Thread safe version of strftime.
+ * No bounds checking is done s. t must be a valid tm structure.
+ */
+#define util_strftime (*__nsapi30_table->f_util_strftime)
+
+/* Various thread safe routines. */
+
+#define util_strtok (*__nsapi30_table->f_util_strtok)
+#define util_localtime (*__nsapi30_table->f_util_localtime)
+#define util_ctime (*__nsapi30_table->f_util_ctime)
+#define util_strerror (*__nsapi30_table->f_util_strerror)
+#define util_gmtime (*__nsapi30_table->f_util_gmtime)
+#define util_asctime (*__nsapi30_table->f_util_asctime)
+
+#ifdef NEED_STRCASECMP
+#define util_strcasecmp (*__nsapi30_table->f_util_strcasecmp)
+#define strcasecmp(s1, s2) util_strcasecmp(s1, s2)
+#endif /* NEED_STRCASECMP */
+
+#ifdef NEED_STRNCASECMP
+#define util_strncasecmp (*__nsapi30_table->f_util_strncasecmp)
+#define strncasecmp(s1, s2, n) util_strncasecmp(s1, s2, n)
+#endif /* NEED_STRNCASECMP */
+
+#ifdef XP_UNIX
+
+/*
+ * can_exec returns 1 if you can execute the file described by finfo, and
+ * 0 if you can't.
+ */
+
+#define util_can_exec (*__nsapi30_table->f_util_can_exec)
+
+/*
+ * Thread safe getpwnam
+ */
+#define util_getpwnam (*__nsapi30_table->f_util_getpwnam)
+
+#define util_waitpid (*__nsapi30_table->f_util_waitpid)
+
+#endif /* XP_UNIX */
+
+#ifdef XP_WIN32
+
+/* util_delete_directory()
+ * This routine deletes all the files in a directory. If delete_directory is
+ * TRUE it will also delete the directory itself.
+ */
+#define util_delete_directory (*__nsapi30_table->f_util_delete_directory)
+
+#endif /* XP_WIN32 */
+
+/*
+ * conf_init reads the given configuration file and sets any non-default
+ * parameters to their given setting.
+ */
+#define conf_init (*__nsapi30_table->f_conf_init)
+#define conf_run_init_functions (*__nsapi30_table->f_conf_run_init_functions)
+
+/*
+ * conf_terminate frees any data the conf routines may be holding.
+ */
+#define conf_terminate (*__nsapi30_table->f_conf_terminate)
+
+/*
+ * conf_getServerString returns the Server ID string
+ */
+#define conf_getServerString (*__nsapi30_table->f_conf_getServerString)
+
+/*
+ * Get a structure with the global variables for this server.
+ */
+#define conf_getglobals (*__nsapi30_table->f_conf_getglobals)
+
+/*
+ * func_init reads the static FuncStruct arrays and creates the global
+ * function table from them.
+ *
+ * func_init will only read from the static arrays defined in func.c.
+ */
+#define func_init (*__nsapi30_table->f_func_init)
+
+/*
+ * func_find returns a pointer to the function named name, or NULL if none
+ * exists.
+ */
+#define func_find (*__nsapi30_table->f_func_find)
+
+/* DO NOT USE this function.
+ */
+#define func_set_native_thread_flag (*__nsapi30_table->f_func_set_native_thread_flag)
+
+/*
+ * func_exec will try to execute the function whose name is the "fn" entry
+ * in the given pblock. If name is not found, it will log a misconfig of
+ * missing fn parameter. If it can't find it, it will log that. In these
+ * cases it will return REQ_ABORTED. Otherwise, it will return what the
+ * function being executed returns.
+ */
+#define func_exec (*__nsapi30_table->f_func_exec)
+
+/*
+ * func_replace will replace a function in the server's function table with
+ * another. Returns the FuncPtr to the old function if it replaces the
+ * function, otherwise it returns 0.
+ */
+#define func_replace (*__nsapi30_table->f_func_replace)
+
+/*
+ * func_insert dynamically inserts a named function into the server's
+ * table of functions. Returns the FuncStruct it keeps in internal
+ * databases, because on server restart you are responsible for freeing
+ * (or not) its contents.
+ */
+#define func_insert (*__nsapi30_table->f_func_insert)
+#define object_execute (*__nsapi30_table->f_object_execute)
+
+/*
+ * gets the first line of an HTTP request
+ */
+#define http_find_request (*__nsapi30_table->f_http_find_request)
+
+/*
+ * parses the first line of an HTTP request
+ */
+#define http_parse_request (*__nsapi30_table->f_http_parse_request)
+
+/*
+ * Scans HTTP headers from the given netbuf, and places them in headers.
+ * If netbuf is NULL, the session's inbuf is used.
+ *
+ * Folded lines are joined and the linefeed removed (but not the whitespace).
+ * If there are any repeat headers they are joined and the two field bodies
+ * separated by a comma and space.
+ *
+ * t should be a string of length REQ_MAX_LINE. This is a convenience to
+ * req.c so that we don't use too much runtime stack.
+ *
+ * Session is an optional parameter. Use NULL if you wish. It's used for
+ * error logs.
+ */
+#define http_scan_headers (*__nsapi30_table->f_http_scan_headers)
+
+/*
+ * Starts the HTTP response. If HTTP/0.9, does nothing. If 1.0, sends header.
+ * If this returns REQ_NOACTION, the method was head and no body should be
+ * sent. Otherwise, it will return REQ_PROCEED.
+ */
+#define http_start_response (*__nsapi30_table->f_http_start_response)
+
+/*
+ * http_hdrs2env takes the entries from the given pblock and converts them
+ * to an environment.
+ *
+ * Each name entry will be made uppercase, prefixed with HTTP_ and any
+ * occurrence of - will be converted to _.
+ */
+#define http_hdrs2env (*__nsapi30_table->f_http_hdrs2env)
+
+/*
+ * http_status sets status to the code n, with reason string r. If r is
+ * NULL, the server will attempt to find one for the given status code.
+ * If it finds none, it will give "Because I felt like it."
+ */
+#define http_status (*__nsapi30_table->f_http_status)
+
+/*
+ * http_set_finfo sets content-length and last-modified
+ */
+
+#define http_set_finfo (*__nsapi30_table->f_http_set_finfo)
+
+/*
+ * Takes the given pblock and prints headers into the given buffer at
+ * position pos. Returns the buffer, reallocated if needed. Modifies pos.
+ */
+#define http_dump822 (*__nsapi30_table->f_http_dump822)
+
+/*
+ * Finishes a request. For HTTP, this just closes the socket.
+ */
+#define http_finish_request (*__nsapi30_table->f_http_finish_request)
+
+/*
+ * http_handle_session processes each request generated by Session
+ */
+#define http_handle_session (*__nsapi30_table->f_http_handle_session)
+
+/*
+ * http_uri2url takes the give URI prefix and URI suffix and creates a
+ * newly-allocated full URL from them of the form
+ * http://(server):(port)(prefix)(suffix)
+ *
+ * If you want either prefix or suffix to be skipped, use "" instead of NULL.
+ *
+ * Normally, the server hostname is taken from the ServerName parameter in
+ * magnus.conf. The newer function http_uri2url_dynamic should be used when
+ * a Session and Request structure are available, to ensure that the browser
+ * gets redirected to the exact host they were originally referencing.
+ */
+
+#define http_uri2url (*__nsapi30_table->f_http_uri2url)
+#define http_uri2url_dynamic (*__nsapi30_table->f_http_uri2url_dynamic)
+
+/*
+ * http_set_keepalive_timeout sets the number of seconds to wait for a new
+ * request to come from a persistent connection. Returns nothing. Intended
+ * to be called at server startup only.
+ *
+ * Specifying a timeout of zero will disable persistent connections and allow
+ * browsers to request only one file per connection.
+ */
+#define http_set_keepalive_timeout (*__nsapi30_table->f_http_set_keepalive_timeout)
+
+/*
+ * log_error logs an error of the given degree from the function func
+ * and formats the arguments with the printf() style fmt. Returns whether the
+ * log was successful. Records the current date.
+ *
+ * sn and rq are optional parameters. If given, information about the client
+ * will be reported.
+ */
+#define log_error_v (*__nsapi30_table->f_log_error_v)
+#define log_error (*__nsapi30_table->f_log_error)
+
+/*
+ * Internal use only
+ */
+#define log_ereport_v (*__nsapi30_table->f_log_ereport_v)
+#define log_ereport (*__nsapi30_table->f_log_ereport)
+
+/*
+ * object_create will create a new object and return a pointer to it.
+ * It will allocate space for nd directive types and set name accordingly.
+ */
+#define object_create (*__nsapi30_table->f_object_create)
+
+/*
+ * object_free will free an object and any data associated with it.
+ */
+#define object_free (*__nsapi30_table->f_object_free)
+
+/*
+ * object_add_directive will add a new directive to the dtable for
+ * the directive class at position dc.
+ */
+#define object_add_directive (*__nsapi30_table->f_object_add_directive)
+
+/*
+ * Executes the directive specified by inst within the context of the
+ * given session and request structures. Returns what the executed function
+ * returned (one of the REQ_* codes defined in req.h).
+ *
+ * This prototype uses void * for Request * in order to avoid including
+ * all of req.h.
+ *
+ */
+
+/*
+ * objset_scan_buffer will scan through buffer, looking for object
+ * configuration information, and adding them to the object set os if it
+ * finds any. If os is NULL it will allocate a new object set.
+ *
+ * If any error occurs (syntax error, premature EOF) this function will
+ * free os, print an error message into errstr, and return NULL.
+ * This is because a config. file error is viewed as a catastrophic error
+ * from which httpd should not try to recover. If httpd were to continue
+ * after an error, it would not behave as the admin. expected and he/she
+ * may not notice until it's too late.
+ *
+ * Upon EOF the file will not be closed.
+ */
+#define objset_scan_buffer (*__nsapi30_table->f_objset_scan_buffer)
+
+/*
+ * objset_create creates a new object set and returns a pointer to it.
+ */
+#define objset_create (*__nsapi30_table->f_objset_create)
+
+/*
+ * objset_free will free an object set, any associated objects, and any
+ * associated Init functions.
+ */
+#define objset_free (*__nsapi30_table->f_objset_free)
+
+/*
+ * objset_free_setonly frees only the object set, and not the associated
+ * objects or init functions.
+ */
+#define objset_free_setonly (*__nsapi30_table->f_objset_free_setonly)
+
+/*
+ * objset_new_object will add a new object to objset with the specified
+ * name. It returns a pointer to the new object (which may be anywhere in
+ * the objset).
+ */
+#define objset_new_object (*__nsapi30_table->f_objset_new_object)
+
+/*
+ * objset_add_object will add the existing object to os.
+ */
+#define objset_add_object (*__nsapi30_table->f_objset_add_object)
+
+/*
+ * objset_add_init will add the initialization function specified by
+ * initfn to the given object set. Modifies os->initfns.
+ */
+#define objset_add_init (*__nsapi30_table->f_objset_add_init)
+
+/*
+ * objset_findbyname will find the object in objset having the given name,
+ * and return the object if found, and NULL otherwise.
+ * ign is a set of objects to ignore.
+ */
+#define objset_findbyname (*__nsapi30_table->f_objset_findbyname)
+
+/*
+ * objset_findbyppath will find the object in objset having the given
+ * partial path entry. Returns object if found, NULL otherwise.
+ * ign is a set of objects to ignore.
+ */
+#define objset_findbyppath (*__nsapi30_table->f_objset_findbyppath)
+
+/*
+ * request_create creates a new request structure.
+ */
+#define request_create (*__nsapi30_table->f_request_create)
+
+/*
+ * request_free destroys a request structure.
+ */
+#define request_free (*__nsapi30_table->f_request_free)
+
+/*
+ * Restarts a request for a given URI internally. If rq is non-NULL, the
+ * function will keep the old request's headers and protocol, but with a new
+ * URI and method of GET. If the previous method was HEAD, this is preserved.
+ * Any other method becomes GET. You may assume that if you give it a request
+ * structure that it will use the same structure.
+ *
+ * Once you have this new Request, you must then do what you want with
+ * it (e.g. send the object back, perform uri2path translation, etc.)
+ */
+#define request_restart_internal (*__nsapi30_table->f_request_restart_internal)
+
+/*
+ * request_header finds the named header depending on the requesting
+ * protocol. If possible, it will not load headers until the first is
+ * requested. You have to watch out because this can return REQ_ABORTED.
+ */
+#define request_header (*__nsapi30_table->f_request_header)
+
+/*
+ * request_loadheaders just makes sure the headers have been loaded.
+ */
+#define request_loadheaders (*__nsapi30_table->f_request_loadheaders)
+
+/*
+ * request_stat_path tries to stat path. If path is NULL, it will look in
+ * the vars pblock for "path". If the stat is successful, it returns the stat
+ * structure. If not, returns NULL and leaves a message in rq->staterr. If a
+ * previous call to this function was successful, and path is the same, the
+ * function will simply return the previously found value.
+ *
+ * User functions should not free this structure.
+ */
+
+#define request_stat_path (*__nsapi30_table->f_request_stat_path)
+
+/*
+ * Random number generation
+ *
+ * random_create - create a new random number context
+ * random_update - update a context with random data
+ * random_generate - generate random bytes
+ * random_destroy - destroy a random number context
+ */
+
+#define random_create (*__nsapi30_table->f_random_create)
+#define random_update (*__nsapi30_table->f_random_update)
+#define random_generate (*__nsapi30_table->f_random_generate)
+#define random_destroy (*__nsapi30_table->f_random_destroy)
+
+/*
+ * MD5 hash routines
+ *
+ * md5hash_create - create an MD5 hash context
+ * md5hash_copy - make a copy of an MD5 hash context
+ * md5hash_begin - initialize an MD5 hash context
+ * md5hash_update - update MD5 hash with more input data
+ * md5hash_end - finalize MD5 hash and get result
+ * md5hash_destroy - destroy an MD5 hash context
+ * md5hash_data - compute MD5 hash of data in one step
+ */
+
+#define md5hash_create (*__nsapi30_table->f_md5hash_create)
+#define md5hash_copy (*__nsapi30_table->f_md5hash_copy)
+#define md5hash_begin (*__nsapi30_table->f_md5hash_begin)
+#define md5hash_update (*__nsapi30_table->f_md5hash_update)
+#define md5hash_end (*__nsapi30_table->f_md5hash_end)
+#define md5hash_destroy (*__nsapi30_table->f_md5hash_destroy)
+#define md5hash_data (*__nsapi30_table->f_md5hash_data)
+
+/*
+ * ACL_SetupEval -
+ * Setup environment and call ACL_EvalTestRights.
+ */
+#define ACL_SetupEval (*__nsapi30_table->f_ACL_SetupEval)
+
+/*
+ * servact_translate_uri
+ * Returns the translated path (filename) for the given uri, NULL otherwise.
+ * If authentication is required for the given uri, nothing is returned even
+ * if the current user has authenticated to that area.
+ */
+#define servact_translate_uri (*__nsapi30_table->f_servact_translate_uri)
+
+#endif /* !INTNSAPI */
+
+#ifndef FILE_MMAP
+#define filebuf_open_nostat(fd,sz,finfo) filebuf_open(fd,sz)
+#endif
+
+#ifdef XP_UNIX
+#define dir_open opendir
+#define dir_read readdir
+#define dir_close closedir
+#define dir_create(path) mkdir(path, 0755)
+#define dir_remove rmdir
+#define system_chdir chdir
+#define file_unix2local(path,p2) strcpy(p2,path)
+#endif /* XP_UNIX */
+
+#ifdef XP_WIN32
+#define dir_create _mkdir
+#define dir_remove _rmdir
+#define system_chdir SetCurrentDirectory
+#endif /* XP_WIN32 */
+
+/*
+ * Thread-safe variants of localtime and gmtime
+ */
+#define system_localtime(curtime, ret) util_localtime(curtime, ret)
+#define system_gmtime(curtime, ret) util_gmtime(curtime, ret)
+
+/*
+ * pblock_find finds the entry with the given name in pblock pb.
+ *
+ * If it is successful, it returns the param block. If not, it returns NULL.
+ */
+
+#define pblock_find(name, pb) (pblock_fr(name,pb,0))
+
+/*
+ * pblock_remove behaves exactly like pblock_find, but removes the given
+ * entry from pb.
+ */
+
+#define pblock_remove(name, pb) (pblock_fr(name,pb,1))
+
+/*
+ * session_dns returns the DNS hostname of the client of this session,
+ * and inserts it into the client pblock. Returns NULL if unavailable.
+ */
+
+#define session_dns(sn) session_dns_lookup(sn, 0)
+
+/*
+ * session_maxdns looks up a hostname from an IP address, and then verifies
+ * that the host is really who they claim to be.
+ */
+
+#define session_maxdns(sn) session_dns_lookup(sn, 1)
+
+#define protocol_find_request http_find_request
+#define protocol_parse_request http_parse_request
+#define protocol_scan_headers http_scan_headers
+#define protocol_start_response http_start_response
+#define protocol_status http_status
+#define protocol_set_finfo http_set_finfo
+#define protocol_finish_request http_finish_request
+#define protocol_handle_session http_handle_session
+#define protocol_uri2url http_uri2url
+#define protocol_uri2url_dynamic http_uri2url_dynamic
+#define protocol_set_keepalive_timeout http_set_keepalive_timeout
+
+/* XXXrobm temporary compatibility */
+#define request_uri2path servact_uri2path
+#define request_pathchecks servact_pathchecks
+#define request_fileinfo servact_fileinfo
+#define request_service servact_service
+
+#define request_handle_processed servact_handle_processed
+#define request_translate_uri servact_translate_uri
+#define request_finderror servact_finderror
+
+/* --- OBSOLETE ----------------------------------------------------------
+ * The following macros/functions are obsolete and are only maintained for
+ * compatibility. Do not use them. 11-19-96
+ * -----------------------------------------------------------------------
+ */
+
+#define SYS_STDERR STDERR_FILENO
+
+#ifdef XP_WIN32
+
+typedef HANDLE pid_t;
+
+#define ERROR_PIPE \
+ (ERROR_BROKEN_PIPE | ERROR_BAD_PIPE |\
+ ERROR_PIPE_BUSY | ERROR_PIPE_LISTENING | ERROR_PIPE_NOT_CONNECTED)
+#define CONVERT_TO_PRINTABLE_FORMAT(Filename) \
+{ \
+ register char *s; \
+ if (Filename) \
+ for (s = Filename; *s; s++) \
+ if ( *s == '\\') \
+ *s = '/'; \
+}
+#define CONVERT_TO_NATIVE_FS(Filename) \
+{ \
+ register char *s; \
+ if (Filename) \
+ for (s = Filename; *s; s++) \
+ if ( *s == '/') \
+ *s = '\\'; \
+}
+
+#ifdef INTNSAPI
+NSAPI_PUBLIC extern nsapi_dispatch_t *__nsapi30_table;
+#else
+__declspec(dllimport) nsapi_dispatch_t *__nsapi30_table;
+#endif /* INTNSAPI */
+
+#else /* !XP_WIN32 */
+
+NSAPI_PUBLIC extern nsapi_dispatch_t *__nsapi30_table;
+
+#endif /* XP_WIN32 */
+
+#endif /* !PUBLIC_NSAPI_H */
diff --git a/include/version.h b/include/version.h
new file mode 100644
index 00000000..a1116466
--- /dev/null
+++ b/include/version.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 **/
+/*
+ This file is included from both C source and the NT installation compiler.
+ Because of that, no ifdefs are allowed, and strings must be simple strings
+ (not concatenated).
+
+ Because macros called PERSONAL_VERSION and ENTERPRISE_VERSION already
+ exist, the PRODUCT_VERSION define has _DEF appended.
+ */
+
+#define DIRECTORY_VERSION_DEF "7.0"
+#define DIRECTORY_COMPATIBLE "3.0"
+#define DIRECTORY_VERSION_STRING "Netscape-DirServer/7.0"
+
+#define DS_VERSION_DEF DIRECTORY_VERSION_DEF
+#define DS_VERSION_STRING DIRECTORY_VERSION_STRING
+
+#define DSS_VERSION_DEF DIRECTORY_VERSION_DEF
+#define DSS_VERSION_STRING "Netscape-DirSynchService/7.0"
+
+#define PROXY_VERSION_DEF "2.0"
+#define PROXY_VERSION_STRING "Netscape-Proxy/2.0"
+
+#define ADMSERV_VERSION_DEF "4.0b1"
+#define ADMSERV_VERSION_STRING "Netscape-Administrator/4.0b1"
+/* supposedly the trunk is currently the home of 3.x development */
+
+#define PERSONAL_VERSION_DEF "3.01b1"
+#define PERSONAL_VERSION_STRING "Netscape-FastTrack/3.01b1"
+
+#define CATALOG_VERSION_DEF "1.0b2"
+#define CATALOG_VERSION_STRING "Netscape-Catalog/1.0b2"
+
+#define RDS_VERSION_DEF "1.0b2"
+#define RDS_VERSION_STRING "Netscape-RDS/1.0b2"
+
+#define ENTERPRISE_VERSION_DEF "3.01"
+#define ENTERPRISE_VERSION_STRING "Netscape-Enterprise/3.01"
+
+#define MAIL_VERSION_DEF "3.0a0"
+#define MAIL_VERSION_STRING "Netscape-Mail/3.0a0"
+
+#define NEWS_VERSION_STRING "Netscape 1.1"
+
+#define BATMAN_VERSION_DEF "1.0a1"
+#define BATMAN_VERSION_STRING "Batman/1.0a1"
+
+#define VI_COMPANYNAME "Netscape Communications Corporation\0"
+#define VI_COPYRIGHT "Copyright 2001 Sun Microsystems, Inc. Portions copyright 1999, 2001-2003 Netscape Communications Corporation. All rights reserved.\0"
diff --git a/l10n/dirserv/de/ns-slapd.txt b/l10n/dirserv/de/ns-slapd.txt
new file mode 100644
index 00000000..7e183ed7
--- /dev/null
+++ b/l10n/dirserv/de/ns-slapd.txt
@@ -0,0 +1,899 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* This text file was generated by program dblink */
+
+$Revision: 1.1 $
+$Log: ns-slapd.txt,v $
+Revision 1.1 2005/01/21 00:40:48 cvsadm
+Initial revision
+
+Revision 1.2.10.6 2003/09/22 19:36:39 ulfw
+Update copyright years from 2001 to 2001-2003
+
+Revision 1.2.10.5 2001/11/03 01:05:12 richm
+XXX use new copyright XXX
+
+Revision 1.2.10.4 2001/10/06 20:00:37 richm
+ns/netsite/l10n/dirserv/de/ns-slapd.txt
+1.2.10.3
+20010918
+
+Remove copyright caracter from copyright
+
+
+====================================================
+
+Revision 1.2.10.3 2001/09/18 11:48:15 rmarco
+Remove copyright caracter from copyright
+
+Revision 1.2.10.2 2001/02/13 09:59:50 rmarco
+Copyrights
+
+Revision 1.2.10.1 1998/10/10 02:13:58 ggood
+Copy from Directory40RtmBranchpoint to DirectoryBranch
+
+Revision 1.2.2.3.6.1 1998/04/04 23:16:45 mcs
+merge changes made on directory31_rtm_branch into server4_directory_branch
+
+Revision 1.2.2.3.2.1 1998/02/24 05:51:51 noriko
+Synched with server3_i18npkg_branch
+
+Revision 1.1.2.6 1997/12/31 00:28:38 werudge
+UTF8 Encoded from de/ns-slapd.txt.iso8859 : 1.1.2.6
+Based on en/ns-slapd.txt : 1.1.2.3
+
+Revision 1.1.2.6 1997/12/31 00:23:36 werudge
+Remove \n from dsgw,198 to fix JavaScript problem
+
+Revision 1.1.2.5 1997/12/19 02:03:43 werudge
+Based on en/ns-slapd.txt : 1.1.2.3
+daily 971113.1 SOLARIS-export-optimize-normal-slapd
+$EndLog$
+
+$StartStringData$
+
+de,base,-1,[$DBT: base in DB file v1 $]
+de,base,1,[nicht genügend Arbeitsspeicher zum Erstellen der Hash-Tabelle]
+de,base,2,[nicht genügend Arbeitsspeicher zum Erstellen der Hash-Tabelle]
+de,base,3,[cache_destroy: Cache-Tabellen scheinen beschädigt zu sein.]
+de,base,4,[Hash-Eintrag kann nicht zugewiesen werden]
+de,base,5,[cache_insert: Cache-Eintrag kann nicht erstellt werden]
+de,base,6,[HTTP/1.0 200 OK\nContent-type: text/html\n\n]
+de,base,7,[<H2>Netscape-Cache Statusbericht</H2>\n(<H2>Netscape cache status report</H2>)\n]
+de,base,8,[Keine Caches im System (No caches on system)<P>]
+de,base,9,[<H2>%s Cache (cache)</H2>\n]
+de,base,10,[Cacheverbindungsverhältnis (Cache hit ratio): %d/%d (%f)</P>\n</P>\n]
+de,base,11,[Cachegröße (Cache size): %d/%d</P>\n</P>\n]
+de,base,12,[Hash-Tabellengröße (Hash table size): %d</P>\n</P>\n]
+de,base,13,[mru : %d</P>\nlru : %d</P>\n]
+de,base,14,[<UL><TABLE BORDER=4> <TH>Originalspeicherbereich (Bucket)</TH> <TH>Adresse (Address)</TH> <TH>Schlüssel (Key)</TH> <TH>Zugriffsanzahl (Access Count)</TH> <TH>Löschen (Delete)</TH> <TH>Nächste (Next)</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>Daten (Data)</TH>\n]
+de,base,15,[munmap failed (%s)]
+de,base,16,[munmap failed (%s)]
+de,base,17,[close failed (%s)]
+de,base,18,[daemon: unable to fork new process (%s)\n]
+de,base,19,[daemon: setsid failed (%s)\n]
+de,base,20,[daemon: can't log pid to %s (%s)\n]
+de,base,21,[warning: could not set group id to %d (%s)\n]
+de,base,22,[warning: could not set user id to %d (%s)\n]
+de,base,23,[warning: daemon is running as super-user\n]
+de,base,24,[could not determine current user name\n]
+de,base,25,[error: chroot to %s failed (%s)\n]
+de,base,27,[, address %s]
+de,base,28,[warning: statistics disabled (%s)\n]
+de,base,29,[security handshake timed out for pid %d]
+de,base,30,[warning: statistics disabled (%s)\n]
+de,base,31,[secure handshake failed (code %d)\n]
+de,base,32,[accept failed (%s)]
+de,base,33,[warning: statistics disabled (%s)\n]
+de,base,34,[select thread miss]
+de,base,35,[keepalive worker awoken with no work to do]
+de,base,36,[could not create new thread: %d (%s)]
+de,base,37,[wait for sema succeeded, but nothing to dequeue]
+de,base,38,[queue-sema creation failure]
+de,base,39,[error getting processor info for processor %d]
+de,base,40,[Error binding to processor %d]
+de,base,41,[bound process %d to processor %d]
+de,base,42,[Netscape server is not explicitly binding to any processors.]
+de,base,43,[cache monitor exited]
+de,base,44,[cache batch update daemon exited]
+de,base,45,[Using single threaded accepts.]
+de,base,46,[Using multi threaded accepts.]
+de,base,47,[Using partial single threaded accepts.]
+de,base,48,[This machine has %d processors.]
+de,base,49,[Error calling thr_seconcurrency(%d)- (%s)]
+de,base,50,[Set conncurrency to %d.]
+de,base,51,[WARNING! netscape executable and library have different versions.\n]
+de,base,54,[seminit failed (%s)\n]
+de,base,55,[This beta software has expired.\n]
+de,base,56,[Cache monitor respawned]
+de,base,57,[Cache batch update daemon respawned]
+de,base,58,[can't find empty statistics slot]
+de,base,59,[can't fork new process (%s)]
+de,base,60,[assert failed! %s\n]
+de,base,61,[mr_table_init()]
+de,base,62,[malloc failed]
+de,base,63,[malloc failed!]
+de,base,64,[mr_add_io(%d, type %d, file %d)]
+de,base,65,[mr_add_io - stage 1]
+de,base,66,[mr_add_io - stage 2]
+de,base,67,[mr_add_io found invalid IO type %d]
+de,base,68,[mr_add_io - adding timeout]
+de,base,69,[Out of memory!\n]
+de,base,70,[done with mr_add_io]
+de,base,71,[mr_del_io(%d, type %d, file %d)]
+de,base,72,[mr_del_io found invalid IO type %d]
+de,base,73,[mr_lookup_io(%d)]
+de,base,74,[mr_async_io(%d, %d bytes, file %d)]
+de,base,75,[malloc failure adding async IO]
+de,base,76,[Error adding async io!]
+de,base,77,[Cannot seek for read!]
+de,base,78,[read failure! (%d, %s)]
+de,base,79,[do_read read %d bytes for file %d]
+de,base,80,[Cannot seek for write!]
+de,base,81,[writev failure! (%d, %s)]
+de,base,82,[write failure! (%d, %s)]
+de,base,83,[do_write wrote %d bytes for file %d]
+de,base,84,[do_timeout(mrp %d)]
+de,base,85,[do_timeout: found IO (timer=%d, time=%d)]
+de,base,86,[error deleting io]
+de,base,87,[timeout callback failure for %d\n]
+de,base,88,[mr_get_event(%d) - outstanding io %d]
+de,base,89,[mr_get_event: Waiting for reads on FD:]
+de,base,90,[mr_get_event: Waiting for writes on FD:]
+de,base,91,[ %d]
+de,base,92,[ %d]
+de,base,93,[mr_get_event set no timeout]
+de,base,94,[mr_get_event set timeout to: %d.%d sec]
+de,base,95,[error in select (%d, %s)]
+de,base,96,[mr_get_event() - select found %d]
+de,base,97,[error looking up IO fd %d]
+de,base,98,[read failed for fd %d]
+de,base,99,[error deleting io]
+de,base,100,[callback failure for %d\n]
+de,base,101,[error looking up IO fd %d]
+de,base,102,[writing: header len %d, writelen %d, total %d]
+de,base,103,[write failed for fd %d]
+de,base,104,[error deleting io]
+de,base,105,[callback failure for %d\n]
+de,base,106,[Error creating dns cache]
+de,base,107,[dns_cache_init: hash_size <= 0, using %d]
+de,base,108,[dns_cache_init: cache-size <= %d, using %d]
+de,base,109,[dns_cache_init: cache-size is %d is too large, using %d.]
+de,base,110,[dns_cache_init: expire_time <= 0, using %d]
+de,base,111,[dns_cache_init: expire is %d is too large, using %d seconds.]
+de,base,112,[Error creating dns cache]
+de,base,113,[dns-cache-insert: Error allocating entry]
+de,base,114,[dns-cache-insert: malloc failure]
+de,base,115,[successful server startup]
+de,base,116,[%s B%s]
+de,base,117,[Netscape executable and shared library have different versions]
+de,base,118,[ executable version is %s]
+de,base,119,[ shared library version is %s]
+de,base,120,[error reporting shutting down]
+de,base,121,[warning]
+de,base,122,[config]
+de,base,123,[security]
+de,base,124,[failure]
+de,base,125,[catastrophe]
+de,base,126,[info]
+de,base,127,[verbose]
+de,base,128,[event_handler:Failed to wait on events %s]
+de,base,129,[could not wait on resume event event (%s)]
+de,base,130,[dlopen of %s failed (%s)]
+de,base,131,[dlopen of %s failed (%s)]
+de,base,132,[The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!]
+de,base,133,[Terminating the server %s]
+de,base,134,[kill_server:cannot open server event %s]
+de,base,135,[kill_server:cannot set server event %s]
+de,base,136,[error: could not get socket (%s)\n]
+de,base,137,[error: could not set socket option (%s)\n]
+de,base,138,[Terminating Service:error: could not bind to address %s port %d (%s)\n]
+de,base,139,[Terminating Service:error: could not bind to port %d (%s)\n]
+de,base,140,[SetHandleNonInheritable: could not duplicate socket (%s)]
+de,base,141,[SetHandleNonInheritable: closing the original socket failed (%s)]
+de,base,142,[Could not SetHandleInformation (%s)]
+de,base,143,[Terminating Service:Failure: Could not open statistics file (%s)\n]
+de,base,144,[Could not set Thread Local Storage Value for thread at slot %d]
+de,base,145,[secure handshake failed (code %d)\n]
+de,base,146,[accept failed %d (%s)]
+de,base,147,[Failed to pulse Event %d %s]
+de,base,148,[Failed to send MobGrowth Event to parent %s]
+de,base,149,[Pulsing MobRespawn Event %d]
+de,base,150,[respawn thread pool to %d (%d)]
+de,base,151,[Could not open event to signal rotate application. Could not create the MoveLog event:%s]
+de,base,152,[Failed to send MoveLog Event to rotate app %s]
+de,base,153,[growing thread pool from %d to %d]
+de,base,154,[Could not open the ServiceControlManager, Error %d]
+de,base,155,[StartNetsiteService:Could not open the service %s: Error %d]
+de,base,156,[StartNetsiteService:Could not start the service %s]
+de,base,157,[Service Startup: Could not allocate security descriptor]
+de,base,158,[Service Startup: Could not init security descriptor]
+de,base,159,[Service Startup: Could not set the security Dacl]
+de,base,160,[Terminating Service:WinSock init failed: %s]
+de,base,161,[Httpd Server Startup failed: %s]
+de,base,162,[can't find empty statistics slot]
+de,base,163,[NT daemon: could not create new thread %d]
+de,base,164,[Service Startup Failure. Terminating Service:Could not create event %d:%s]
+de,base,165,[Service Startup Error. Could not create the MoveLog event:%s]
+de,base,166,[Failed to wait on Event objects %s]
+de,base,167,[Failed to wait on Event objects %s]
+de,base,168,[pipebuf_buf2sd: pipebuf_grab IO_ERROR %d]
+de,base,169,[pool-init: memory pools disabled]
+de,base,170,[pool-init: free_size <= 0, using %d]
+de,base,171,[pool-create-block: out of memory]
+de,base,172,[pool-create: out of memory]
+de,base,173,[pool-create: out of memory]
+de,base,174,[pool-malloc: out of memory]
+de,base,175,[FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.]
+de,base,176,[regex error: %s (regex: '%s')]
+de,base,177,[can't create IPC pipe (%s)]
+de,base,178,[write to wakeup pipe failed (%s)]
+de,base,179,[flushing %d connections; current %d; tot %d]
+de,base,180,[accept failed (%s)]
+de,base,181,[Error creating time cache]
+de,base,182,[time-cache: cache disabled]
+de,base,183,[time_cache_init: hash_size < %d, using default, %d]
+de,base,184,[time_cache_init: hash_size > %d, using default, %d]
+de,base,185,[time_cache_init: cache_size < %d, using default, %d]
+de,base,186,[time_cache_init: cache_size > %d, using default, %d]
+de,base,187,[Error allocating memory for time_cache]
+de,base,188,[Error allocating memory for time_cache entry]
+de,base,189,[Error allocating memory for time_cache entry]
+de,base,190,[Error inserting new time_cache entry]
+de,base,191,[Error allocating memory for time_cache]
+de,base,192,[cs-terminate failure (%s)]
+de,base,193,[cs-init failure (%s)]
+de,base,194,[cs-wait failure (%s)]
+de,base,195,[cs-post failure (%s)]
+de,base,196,[Unable to create nonblocking socket (%s)]
+de,base,197,[error: could not set keepalive (%s)\n]
+de,base,198,[error: could not set recv timeout (%s)\n]
+de,base,199,[error: could not set send timeout (%s)\n]
+de,base,200,[Unable to create nonblocking socket (%s)]
+de,base,201,[sem_grab failed (%s)]
+de,base,202,[sem_release failed (%s)]
+de,base,203,[sem_release failed (%s)]
+de,base,204,[Could not remove temporary directory %s, Error %d]
+de,base,205,[Could not remove temporary directory %s, Error %d]
+de,dsgw,-1,[$DBT: dsgw in DB file v1 $]
+de,dsgw,1,[Unbekannte HTTP-Anforderungsmethode (Unknown HTTP request method)]
+de,dsgw,2,[Ungültige oder unvollständige HTML-Formulardaten (Invalid or incomplete HTML form data)]
+de,dsgw,3,[Nicht genügend Speicherplatz (Out of memory)]
+de,dsgw,4,[Erforderliche Anfrage-/Formulareingabe fehlt (Required query/form input is missing)]
+de,dsgw,5,[Ungültiges Zeichen im Dateipfad (Illegal character in file path)]
+de,dsgw,6,[Falsche oder fehlende Konfigurationsdatei (Bad or missing configuration file)]
+de,dsgw,7,[LDAP kann nicht initialisiert werden (Unable to initialize LDAP)]
+de,dsgw,8,[Fehler beim Aufrufen des LDAP-Server (An error occurred while contacting the LDAP server)]
+de,dsgw,9,[Unbekannter Suchobjekttyp (Unknown search object type)]
+de,dsgw,10,[Unbekanntes Attributetikett (Unknown attribute label)]
+de,dsgw,11,[Unbekannte Match-Aufforderung (Unknown match prompt)]
+de,dsgw,12,[Keine Suchfilter für Objekttyp (No search filters for object type)]
+de,dsgw,13,[HTML-Vorlagedatei kann nicht gefunden werden (Unable to open HTML template file)]
+de,dsgw,14,[Unbekannter Suchmodus - benutzen Sie "smart", "complex", "pattern" oder "auth" (Unknown search mode - use "smart", "complex", "pattern", or "auth")]
+de,dsgw,15,[Unverwechselbarer Name fehlt in der URL (Distinguished Name missing in URL)]
+de,dsgw,16,[Unbekannter Bereich in der URL (sollte "base", "sub" oder "one" sein) (Unknown scope in URL (should be base, sub, or one))]
+de,dsgw,17,[Unbekannte URL oder unbekannter Fehler (Unrecognized URL or unknown error)]
+de,dsgw,18,[Ungültiges URL-Format (Bad URL format)]
+de,dsgw,19,[Interner Fehler (Internal error)]
+de,dsgw,20,[Vorlageindexdatei kann nicht geschrieben werden (Unable to write template index file)]
+de,dsgw,21,[Vorlageindexdatei kann nicht geöffnet werden (Unable to open template index file)]
+de,dsgw,22,[Verzeichnis kann nicht gelesen werden (Unable to read directory)]
+de,dsgw,23,[Fehler bei der Initialisierung von LDAP SSL (Sicherheitspfad überprüfen) (LDAP SSL initialization failed (check the security path)]
+de,dsgw,24,[Damit die Benutzer- und Gruppenformulare mit dem Verwalter-Server via SSL ausgeführt werden können, müssen Sie oder der Systemverwalter über das Formular <B>Server-Eigenschaften|Verschlüsselung EIN/AUS</B> SSL für diesen Verwaltungsserver aktivieren aktivieren.\n(For the Users and Groups forms to work over SSL, you or your server administrator needs to activate SSL for this Administration Server. The Encryption|On/Off page can be used to do so.)]
+de,dsgw,25,[Beglaubigungsberechtigung wurde nicht in der Beglaubigungsdatenbank gefunden (Authentication credentials not found in authentication database)]
+de,dsgw,26,[Fehler beim Abrufen der Daten von der Beglaubigungsdatenbank (Error retrieving data from the authentication database)]
+de,dsgw,27,[Ihre Beglaubigungsberechtigung ist abgelaufen (Your authentication credentials have expired)]
+de,dsgw,28,[Zufalls-Zeichenfolge kann nicht erstellt werden\n(Unable to create a random string)]
+de,dsgw,29,[Beim Abrufen des Berechtigungsnachweises wurde kein unverwechselbarer Name angegeben (No distinguished name was provided when retrieving credentials)]
+de,dsgw,30,[Beglaubigungsdatenbank kann nicht geöffnet werden (Cannot open authentication database)]
+de,dsgw,31,[Daten konnten nicht an die Beglaubigungsdatenbank angehängt werden (Could not append data to the authentication database)]
+de,dsgw,32,[Es wurde kein Verzeichnisverwalter definiert (No Directory Manager is defined)]
+de,dsgw,33,[Es wurde keine Suchzeichenfolge angegeben. Bitte noch einmal versuchen (No search string was provided. Please try again)]
+de,dsgw,34,[Zu viele Argumente auf einer Zeile in der Konfigurationsdatei (Too many arguments on one line in the config. file)]
+de,dsgw,35,[Windows Sockets konnte nicht initialisiert werden (Failed to initialize Windows Sockets)]
+de,dsgw,36,[Beglaubigungsberechtigung konnte nicht vom Verwaltungs-Server abgerufen werden (Authentication credentials could not be obtained from the Administration Server)]
+de,dsgw,37,[Unverwechselbarer Name fehlt in der ldapdb:// URL (Distinguished Name missing in ldapdb:// URL)]
+de,dsgw,38,[Unbekannte URL oder unbekannter Fehler (Unrecognized URL or unknown error)]
+de,dsgw,39,[Ungültiges URL-Format (Bad URL format)]
+de,dsgw,40,[Fehler beim Initialisieren der lokalen LDAP-Datenbank\n(An error occurred while initializing the local LDAP database)]
+de,dsgw,41,[Unbekannter Verzeichnis-Servicetyp - benutzen Sie "local" oder "remote" (Unknown directory service type - use "local" or "remote")]
+de,dsgw,42,[Fehler beim Lesen der db-Konfigurationdatei (An error occurred while reading the db configuration file)]
+de,dsgw,43,[NSHOME/userdb-Pfad war NULL (NSHOME/userdb path was NULL)]
+de,dsgw,44,[Die Servicekonfiguration des Verzeichnisses konnte nicht aktualisiert werden. (The directory service configuration could not be updated.)]
+de,dsgw,45,[Der Eintrag konnte nicht im Verzeichnis gelesen werden. (The entry could not be read from the directory.)]
+de,dsgw,46,[Die LDAP-Databank konnte nicht gelöscht werden. (The LDAP database could not be erased.)]
+de,dsgw,47,[Sie dürfen keine Einträge außer Ihren eigenen ändern. (You may not change entries besides your own.)]
+de,dsgw,48,[Problem]
+de,dsgw,49,[Beglaubigungsproblem (Authentication Problem)]
+de,dsgw,50,[.\n<P>Sie müssen neu beglaubigen, ehe Sie fortfahren. (You must re-authenticate before continuing.)\n]
+de,dsgw,51,[.\n<P>Sie müssen neu beglaubigen, ehe Sie fortfahren. (You must re-authenticate before continuing.)\n]
+de,dsgw,52,[unbekannter Fehler (unknown error)]
+de,dsgw,53,[Der Vorgang war erfolgreich. (The operation was successful.)]
+de,dsgw,54,[Im Server ist ein interner Fehler aufgetreten. Das deutet gewöhnlich auf einen ernsthaften Fehler im Server hin und sollte Ihrem Serververwalter mitgeteilt werden. (An internal error occurred in the server. This usually indicates a serious malfunction in the server and should be brought to the attention of your server administrator.)]
+de,dsgw,55,[Der Server konnte die durch das Gateway an ihn gesandte Anforderung nicht verstehen. (The server could not understand the request which was sent to it by the gateway.)]
+de,dsgw,56,[Das Zeitlimit wurde bei der Ausführung Ihrer Anforderung überschritten. Die Suche nach Einträgen erzielt bessere Ergebnisse, wenn Sie Ihre Suche präziser definieren. (A time limit was exceeded in responding to your request. If you are searching for entries, you may achieve better results if you are more specific in your search.)]
+de,dsgw,57,[Das Größenlimit wurde bei der Ausführung Ihrer Anforderung überschritten. Ihre Suche nach Einträgen erzielt bessere Ergebnisse, wenn Sie Ihre Suche präziser definieren, da zu viele Einträge zu Ihren Suchkriterien paßten. (A size limit was exceeded in responding to your request. If you are searching for entries, you may achieve better results if you are more specific in your search, because too many entries matched your search criteria.)]
+de,dsgw,58,[Das Gateway versuchte, mit einer Methode auf dem Server\nzu beglaubigen, die der Server nicht versteht.\n(The gateway attempted to authenticate to the server using\na method the server doesn't understand.)]
+de,dsgw,59,[Das Gateway versuchte mit einer Beglaubigungsmethode auf dem Server zu beglaubigen, die der Server nicht unterstützt. (The gateway attempted to authenticate to the server using an authentication method which the server does not support. )]
+de,dsgw,60,[Ihre Anforderung konnte nicht ausgeführt werden, weil der aufgerufene Server wahrscheinlich nicht die von Ihnen gewünschten Daten enthält. Möglicherweise wurde die Anforderung auf einen anderen Server umgeleitet und wieder zurückgesandt, konnte jedoch nicht zurückverfolgt werden. Sollten Sie versucht haben, Änderungen im Verzeichnis vorzunehmen, dann ist der Server mit der Stammkopie möglicherweise nicht verfügbar. (Your request could not be fulfilled, probably because the server that was contacted does not contain the data you are looking for. It is possible that a referral to another server was returned but could not be followed. If you were trying to make changes to the directory, it may be that the server that holds the master copy of the data is not available.)]
+de,dsgw,61,[Ihre Anforderung hat ein Verwalterlimit auf dem Server überschritten. (Your request exceeded an administrative limit in the server.)]
+de,dsgw,62,[Eine vom Gateway angeforderte kritische Erweiterung ist auf diesem Server nicht verfügbar. (A critical extension that the gateway requested is not available in this server.)]
+de,dsgw,63,[Der Server konnte die Anforderung nicht ausführen, da sie\nsich auf ein Attribut bezieht, das nicht im\nEintrag existiert.\n(The server was unable to process the request, because the\nrequest referred to an attribute which does not exist in the\nentry.)]
+de,dsgw,64,[Der Server konnte Ihre Anforderung nicht ausführen, da\nsie gegen eine Beschränkung verstößt.\n(The server was unable to fulfill your request, because the\nrequest violates a constraint.)]
+de,dsgw,65,[Der Server konnte dem Eintrag keinen Wert hinzufügen, da dieser Wert bereits im Eintrag enthalten ist. (The server could not add a value to the entry, because that value is already contained in the entry.)]
+de,dsgw,66,[Der Server konnte diesen Eintrag nicht finden. Wird ein neuer\nWert hinzugefügt, vergewissern Sie sich, daß das übergeordnete Verzeichnis,\nfür den Eintrag, den Sie hinzufügen möchten, existiert. Erscheint diese\nFehlermeldung bei einem Suchvorgang, bedeutet das,\ndaß der von Ihnen gesuchte Eintrag nicht existiert. Wenn Sie versucht\nhaben, als Verzeichnisverwalter zu beglaubigen und diese Fehlermeldung erscheint,\ndann überprüfen Sie die Gateway-Konfigurationsdatei.\n(The server could not locate the entry. If adding a new entry,\nbe sure that the parent of the entry you are trying to add exists.\nIf you received this error while searching, it indicates that the\nentry which was being searched for does not exist.\nIf you were attempting to authenticate as the directory manager and\nreceived this error, check the gateway configuration file.)]
+de,dsgw,67,[Ein unverwechselbarer Name hatte nicht das richtige Format. (A distinguished name was not in the proper format. )]
+de,dsgw,68,[Dem Eintrag, den Sie beglaubigen wollten, fehlt entweder der Kennwortsatz oder andere erforderliche Beglaubigungsberechtigungen. Mit dieser Eingabe können Sie erst beglaubigen, wenn der Verzeichnisverwalter die passenden Attribute hinzugefügt hat. (The entry you attempted to authenticate as does not have a password set, or is missing other required authentication credentials. You cannot authenticate as that entry until the appropriate attributes have been added by the directory manager.)]
+de,dsgw,69,[Das eingegebene Kennwort (oder andere Beglaubigungsberechtigungen)\nist falsch.\n(The password (or other authentication credentials) you supplied\nis incorrect.)]
+de,dsgw,70,[Sie sind nicht ausreichend berechtigt, um den Vorgang auszuführen. (You do not have sufficient privileges to perform the operation. )]
+de,dsgw,71,[Der Server ist belegt und kann Ihre Anforderung nicht ausführen. Versuchen Sie es in ein paar Miuten noch einmal. (The server is too busy to service your request. Try again in a few minutes.)]
+de,dsgw,72,[Der LDAP-Server konnte nicht aufgerufen werden. (The LDAP server could not be contacted.)]
+de,dsgw,73,[Der Server lehnt die Ausführung Ihrer Anforderung ab. Das bedeutet gewöhnlich, daß die Ausführung Ihrer Anforderung den Server zu sehr belastet. Es könnte möglicherweise auch bedeuten, daß der Server nicht konfiguriert ist, Ihre Anforderung auszuführen. Versuchen Sie, bei der Suche den Suchbereich einzuschränken. (The server was unwilling to process your request. Usually, this indicates that serving your request would put a heavy load on the server. It may also indicate that the server is not configured to process your request. If searching, you may wish to limit the scope of your search.)]
+de,dsgw,74,[Der Verzeichnis-Server konnte Ihrer Anforderung nicht nachkommen, da sie gegen die Schemabedingungen verstößt. Das bedeutet gewöhnlich, daß Sie keinen Wert für ein erforderliches Feld eingegeben haben. Es könnte auch bedeuten, daß das Schema im Verzeichnis-Server aktualisiert werden muß. (The directory server could not honor your request because it violates the schema requirements. Typically, this means that you have not provided a value for a required field. It could also mean that the schema in the directory server needs to be updated.)]
+de,dsgw,75,[Der Verzeichnis-Server läßt nicht zu, daß Sie einen Eintrag, der untergeordnet ist, löschen oder umbenennen. Um das zu tun, müssen Sie erst alle untergeordneten Einträge löschen. (The directory server will not allow you to delete or rename an entry if that entry has children. If you wish to do this, you must first delete all the child entries.)]
+de,dsgw,76,[Der Server konnte weder einen neuen Eintrag hinzufügen noch einen bestehenden umbenennen, da ein Eintrag unter diesem Namen bereits existiert. (The server was unable to add a new entry, or rename an existing entry, because an entry by that name already exists.)]
+de,dsgw,77,[Ihre Anforderung würde mehrere Verzeichnis-Server betreffen. (Your request would affect several directory servers.)]
+de,dsgw,78,[Der Verzeichnis-Server konnte nicht aufgerufen werden. Wenden\nSie sich an den Serververwalter.\n(The directory server could not be contacted. Contact your\n server administrator for assistance.)]
+de,dsgw,79,[Fehler beim Senden der Daten zum Server. (An error occured while sending data to the server.)]
+de,dsgw,80,[Fehler beim Lesen der Daten vom Server. (An error occured while reading data from the server.)]
+de,dsgw,81,[Der Server hat nicht auf Ihre Anforderung reagiert. Die Anforderung wurde unterbrochen. (The server did not respond to the request. The request timed out.)]
+de,dsgw,82,[Der Server unterstützt nicht die vom Gateway benutzte Beglaubigungsmethode. (The server does not support the authentication method used by the gateway.)]
+de,dsgw,83,[Der vom Gateway erstellte Suchfilter war falsch. (The search filter constructed by the gateway was in error.)]
+de,dsgw,84,[Der Vorgang wurde auf Ihren Wunsch abgebrochen. (The operation was cancelled at your request.)]
+de,dsgw,85,[Interner Fehler in der Bibliothek - ein Parameter war falsch. (An internal error occurred in the library - a parameter was incorrect.)]
+de,dsgw,86,[Verbindung zum Verzeichnis-Server konnte nicht hergestellt werden. Wenden\nSie sich an Ihren Server-Verwalter.\n(A connection to the directory server could not be opened. Contact your\nserver administrator for assistance.)]
+de,dsgw,87,[Unbekannter Fehler aufgetreten. (An unknown error was encountered.)]
+de,dsgw,88,[Eintrag existiert bereits (Entry Already Exists)]
+de,dsgw,89,[Dieser Namenseintrag (An entry named )]
+de,dsgw,90,[onMouseOver="window.status='Klicken Sie hier, um den Eintrag einzusehen'; return true"\n(onMouseOver="window.status='Click here to view this entry'; return true")]
+de,dsgw,91,[ existiert bereits (already exists).<P>Bitte anderen Namen und/oder Adresse wählen.\n(Please choose another name and/or location.\n<P>)\n]
+de,dsgw,92,[Ãœbergeordneter Eintrag existiert nicht\n(Parent entry does not exist)]
+de,dsgw,93,[Sie können einen Eintrag unter diesem Namen:\n(You cannot add an entry by the name:)<P><B>%s</B>,<P> nicht hinzufügen,\nda der übergeordnete Eintrags nicht existiert.\n(because the parent of that entry does not exist.)<P>\nEhe Sie diesen Eintrag hinzufügen, müssen Sie zunächst den dazugehörige\n(Before you can add this entry, you must first add)\n]
+de,dsgw,94,[übergeordneten Eintrag hinzufügen. (its parent.)\n]
+de,dsgw,95,[ein Eintrag unter diesem Namen (an entry named):<P><B>%s</B>.\n]
+de,dsgw,96,[Warnung: Keine Beglaubigung (wird fortgesetzt)...\n(Warning: no authentication (continuing)...)\n]
+de,dsgw,97,[%s Verzeichniseintrag (Directory Entry)]
+de,dsgw,98,[<PRE>Eingabe-DN (Entry DN): %s</PRE><P>\n]
+de,dsgw,99,[Änderungen zu <B>%s</B> wurden gespeichert.]
+de,dsgw,100,[<B>%s</B> has been added.]
+de,dsgw,101,[<B>%s</B> has been deleted.]
+de,dsgw,102,[Renamed <B>%s</B> to <B>%s</B>.]
+de,dsgw,103,[<P><B>Hinweis:</B> Da Sie den Eintrag, unter dem Sie beglaubigt\nsind, %s haben, mußte Ihre Beglaubigungsberechtigung\ngelöscht werden. Sie müssen neu beglaubig werden, um\nweitere Änderungen vornehmen zu können.\n(<B>Note:</B> because of your action on the entry you were \nauthenticated as, it was necessary to discard your \nauthentication credentials. You will need to authenticate \nagain to make additional changes.)\n]
+de,dsgw,104,[gelöscht (deleted)]
+de,dsgw,105,[umbenannt (renamed)]
+de,dsgw,106,[Kennwort umbenannt für (changed the password of)]
+de,dsgw,107,[Attribut (Attribute) %s wurde geändert (was changed)<BR>\n]
+de,dsgw,108,[ NICHT (NOT) ASCII (%ld Bytes)\n]
+de,dsgw,109,[Es wurden keine Werte eingegeben. Bitte erneut versuchen.\n(No values were entered. Please try again.)\n]
+de,dsgw,110,[Es wurden keine Änderungen vorgenommen.\n]
+de,dsgw,111,[<P>%s wird an Verzeichnis-Server gesendet...\n]
+de,dsgw,112,[Information]
+de,dsgw,113,[Änderungen (changes)]
+de,dsgw,114,[<P>Eintrag erfolgreich hinzugefügt.\n(Successfully added entry.)\n]
+de,dsgw,115,[<P>Eintrag erfolgreich bearbeitet. Änderungen wurden gespeichert.\n(Successfully edited entry. Your changes have been saved.)\n]
+de,dsgw,116,[<P>Eintrag erfolgreich gelöscht.\n(Successfully deleted entry.)\n]
+de,dsgw,117,[<PRE>Der neue Eintrag heißt (The new name for the entry is): %s\n</PRE><HR>\n]
+de,dsgw,118,[<P>Eintrag erfolgreich umbenannt.\n(Successfully renamed entry.)\n]
+de,dsgw,119,[Sie müssen das alte Kennwort angeben.]
+de,dsgw,120,[Sie müssen ein neues Kennwort angeben. Bitte erneut versuchen]
+de,dsgw,121,[Neues und bestätigendes Kennwort stimmen nicht überein. Bitte erneut versuchen]
+de,dsgw,122,[<BR>%s <B>%s</B> ist bereits in Benutzung. Bitte ein anderes wählen.\n(The item shown is already in use. Please choose a different one.)<BR>\n]
+de,dsgw,123,[fehlendes Formulardatenelement (missing form data element) "%.100s"]
+de,dsgw,124,[Konfigurationsinformation wird initialisiert\n(Initializing config info)]
+de,dsgw,125,[Datei kann nicht geöffnet werden.\n(Cannot open file.)]
+de,dsgw,126,[ Konfigurationsdate der Datenbanki ist verstümmelt.\n(Malformed dbconf file.)]
+de,dsgw,127,[Eigenschaftsname in der Konfigurationsdatei der Datenbank fehlt.\n(Missing property name in dbconf file.)]
+de,dsgw,128,[Nicht genügend Arbeitspeicher. (Out of memory.)]
+de,dsgw,129,[Betriebsanweisung in der Konfigurationsdatei der Datenbank fehlt.\n(Missing directive in dbconf file.)]
+de,dsgw,130,[Konfigurationsdatei "%s" kann nicht geöffnet werden\n(Cannot open config file with name shown)\n]
+de,dsgw,131,[Argument für die Betriebsanweisung "authlifetime" fehlt\n(Missing argument for "authlifetime" directive)\n]
+de,dsgw,132,[Argument für Betriebsanweisung "dirmgr" fehlt\n(Missing argument for "dirmgr" directive)\n]
+de,dsgw,133,[Argument für Betriebsanweisung "baseurl" fehlt\n(Missing argument for "baseurl" directive)\n]
+de,dsgw,134,[Falsche URL für Betriebsanweisung "baseurl" angegeben - Basis-DN fehlt\n(Bad URL provided for "baseurl" directive - the base DN is missing)\n]
+de,dsgw,135,[Betriebsanweisung "baseurl" wird analysiert\n(parsing baseurl directive)]
+de,dsgw,136,[Falsche URL für Betriebsanweisung "baseurl" angegeben - keine "ldap://" URL\n(Bad URL provided for "baseurl" directive - not an "ldap://" URL)\n]
+de,dsgw,137,["ldaps://" URLs werden noch nicht unterstützt\n("ldaps://" URLs are not yet supported)\n]
+de,dsgw,138,[Argumente für Betriebsanweisung "template" fehlen\n(Missing arguments for "template" directive)\n]
+de,dsgw,139,[Argument für Betriebsanweisung "sslrequired" fehlt\n(Missing argument for "sslrequired" directive)\n]
+de,dsgw,140,[Unbekanntes Argument für Betriebsanweisung "sslrequired" (muß "never", "whenauthenticated"oder "always" sein)\n(Unknown argument to "sslrequired" directive (should be "never", "whenauthenticated", "always"))\n]
+de,dsgw,141,[Argument für Betriebsanweisung "securitypath" fehlt\n(Missing argument for "securitypath" directive)\n]
+de,dsgw,142,[Argument für Betriebsanweisung "location-suffix" fehlt\n(Missing argument for "location-suffix" directive)\n]
+de,dsgw,143,[Die Betriebsanweisung "location" erfordert drei Argumente\n(Three arguments are required for the "location" directive)\n]
+de,dsgw,144,[Die Betriebsanweisung "newtype" erfordert mindestens zwei Argumente\n(At least two arguments are required for the "newtype" directive)\n]
+de,dsgw,145,[Unbekannte Adresse in der Betriebsanweisung "newtype"\n(Unknown location in "newtype" directive)\n]
+de,dsgw,146,[Die Betriebsanweisung "tmplset" erfordert drei oder vier Argumente\n(Three or four arguments are required for the "tmplset" directive)\n]
+de,dsgw,147,[Die Betriebsanweisung "attrvset" erfordert vier Argumente\n(Four arguments are required for the "attrvset" directive)\n]
+de,dsgw,148,[Argument für Betriebsanweisung "charset" fehlt\n(Missing argument for "charset" directive)\n]
+de,dsgw,149,[Argument für Betriebsanweisung "ClientLanguage" fehlt\n(Missing argument for "ClientLanguage" directive)\n]
+de,dsgw,150,[Argument für Betriebsanweisung "AdminLanguage" fehlt\n(Missing argument for "AdminLanguage" directive)\n]
+de,dsgw,151,[Argument für Betriebsanweisung "DefaultLanguage" fehlt\n(Missing argument for "DefaultLanguage" directive)\n]
+de,dsgw,152,[Dateiname für Betriebsanweisung "include" fehlt\n(Missing filename for "include" directive)\n]
+de,dsgw,153,[Unbekannte Betriebsanweisung in der Konfigurationsdatei\n(Unknown directive in config file)\n]
+de,dsgw,154,[<= erase_db konnte lcache.conf-Datei "%s" nicht öffnen\n(<= erase_db could not open lcache.conf file with name shown)\n]
+de,dsgw,155,[<FONT SIZE="+1">\n<P>Die Datenbank wurde gelöscht. Neue Datenbank wird erstellt...\n(The database has been deleted. Creating new database...)\n</FONT>\n ]
+de,dsgw,156,[<FONT SIZE="+1">\n<P>Die Datenbank konnte nicht gelöscht werden\n(The database could not be deleted)\n</FONT>\n ]
+de,dsgw,157,[<= app_suffix konnte ldif-Datei "%s" nicht öffnen\n(<= app_suffix could not open ldif file with name shown)\n]
+de,dsgw,158,[<= app_suffix konnte tmp-Datei "%s" nicht öffnen\n(<= app_suffix could not open tmp file with name shown)\n]
+de,dsgw,159,[%s konnte nicht in %s umbenannt werden\n(Unable to rename with names as shown)]
+de,dsgw,160,[Leerzeiger wurde von dbconf_read_default_dbinfo() zurückgegeben.\n(null pointer returned by dbconf_read_default_dbinfo().)]
+de,dsgw,161,[Falsche "ldapdb"-URL - Basis-DN fehlt\n(Bad "ldapdb" URL - the base DN is missing)\n]
+de,dsgw,162,[Falsche "ldapdb"-URL (Bad "ldapdb" URL)\n]
+de,dsgw,163,[Falsche URL für Betriebsanweisung "baseurl" angegeben - Basis-DN fehlt \n(Bad URL provided for "baseurl" directive - the base DN is missing)\n]
+de,dsgw,164,[Betriebsanweisung "baseurl" wird analysiert\n(parsing baseurl directive)]
+de,dsgw,165,[Falsche URL für Betriebsanweisung "baseurl" angegeben - keine "ldap:// bzw. ldapdb://" URL\n(Bad URL provided for "baseurl" directive - not an "ldap:// or ldapdb://" URL)\n]
+de,dsgw,166,["ldaps://" URLs werden noch nicht unterstützt\n("ldaps://" URLs are not yet supported)\n]
+de,dsgw,167,[Kein Wert für binddn angegeben\n(No value given for binddn)]
+de,dsgw,168,[Kein Wert für bindpw angegeben\n(No value given for bindpw)]
+de,dsgw,169,[In der dbswitch.conf-Datei ist kein Standard-Verzeichnisservice angegeben\n(There is no default directory service defined in the dbswitch.conf file)]
+de,dsgw,170,[Konfigurationsdatei "%s" kann nicht zum Schreiben geöffnet werden\n(Cannot open config file with name shown for writing)\n]
+de,dsgw,171,[Kann %s nicht in %s umbenennen\n(Unable to rename with names as shown)]
+de,dsgw,172,[Konfigurationsdatei (config file) %s: ]
+de,dsgw,173,[Konfigurationsdatei (config file) %s: Zeile (line) %d: ]
+de,dsgw,174,[Max. (max) %d]
+de,dsgw,175,[ OK ]
+de,dsgw,176,[Fenster schließen (Close Window)]
+de,dsgw,177,[Zurück]
+de,dsgw,178,[{crypt}GESPERRT (LOCKED) [%s GMT]]
+de,dsgw,179,[Zurück zum Hauptbildschirm (Return to Main)]
+de,dsgw,181,[ Help ]
+de,dsgw,182,[Hilfe (Help)]
+de,dsgw,184,[Hilfe ist noch nicht verfügbar.\n(Help is not yet available.)]
+de,dsgw,186,[Fenster schließen (Close Window)]
+de,dsgw,187,[Fenster schließen (Close Window)]
+de,dsgw,188,[?template fehlt (missing ?template)]
+de,dsgw,189,[Beglaubigen...(Authenticate...)]
+de,dsgw,190,[Beglaubigungsberechtigung löschen (abmelden)?\n(Discard authentication credentials (log out)?)]
+de,dsgw,191,[Geben Sie eine Suchenzeichenfolge an\n(Please type a search string)]
+de,dsgw,192,[Um Ihren Zugriff zu dem Verzeichnis zu beglaubigen, müssen Sie sich zunächst zu\nerkennen geben.<br>Geben Sie Ihren Namen ein:\n(The first step in authenticating to the directory is identifying\nyourself.<br>Please type your name:)]
+de,dsgw,193,[Weiter (Continue)]
+de,dsgw,194,[Weiter (Continue)]
+de,dsgw,195,[Abbrechen (Cancel)]
+de,dsgw,196,[Als Verzeichnisverwalter beglaubigen"> &nbsp;(nur für Verzeichnis-Administratoren verfügbar)\n(Authenticate as directory manager"> &nbsp;(only available to Directory Administrators))\n]
+de,dsgw,197,[Beglaubigen...(Authenticate...)]
+de,dsgw,198,[Beglaubigungsberechtigung löschen? (Discard authentication credentials?)]
+de,dsgw,200,[Weiter (Continue)]
+de,dsgw,201,[Weiter (Continue)]
+de,dsgw,202,[Abbrechen (Cancel)]
+de,dsgw,203,[Zugriff zu dem Verzeichnis beglaubigen (anmelden)\n(Authenticate (log in) to the directory)]
+de,dsgw,204,[Ihr Zugriff zu dem Verzeichnis wird gleich beglaubigt werden unter \n(You are about to authenticate to the directory as) <B>%s</B>. Geben Sie zum Vervollständigen des Beglaubigungsvorgangs Ihr Kennwort ein. (To complete the authentication process, type your password.\n]
+de,dsgw,206,[Ehe Sie Einträge bearbeiten bzw. hinzufügen können, muß\nIhr Zugriff zu dem Verzeichnis beglaubigt (angemeldet) sein\n. Folgen Sie den Anweisungen für den Beglaubigungsprozeß\nauf diesem Fenster.\n(Before you can edit or add entries, you must authenticate\n(log in) to the directory. This window will guide\nyou through the steps of the authentication\nprocess.)\n]
+de,dsgw,207,[Ihr Zugriff zu dem Verzeichnis kann von diesem Bildschirm aus\nbeglaubigt bzw. angemeldet werden.\nSie müssen beglaubigt sein, ehe Sie Verzeichniseinträge\nändern können. Wenn Sie einen Eintrag, ohne beglaubigt zu sein, ändern möchten, dann werden Sie aufgefordert, sich anzumelden.\n(From this screen you may authenticate, or log in, \nto the directory. You will need to authenticate\nbefore you can modify directory entries. If you\nattempt to modify an entry without authenticating,\nyou will be asked to log in.)\n]
+de,dsgw,208,[Beglaubigungsstatus(Authentication Status)]
+de,dsgw,209,[<form>\nIhr Zugriff zu dem Verzeichnis ist derzeitig beglaubigt unter \n(<form>\nYou are currently authenticated to the directory as )]
+de,dsgw,210,[.\nWenn Sie Ihre Beglaubigungsberechtigung löschen und sich vom Verzeichnis abmelden möchten, klicken Sie unten auf die Schaltfläche.\n(.\nIf you wish to discard your authentication credentials and log out of the directory, click on the button below.)]
+de,dsgw,211,[Beglaubigungsberechtigung löschen (abmelden)\n(Discard Authentication Credentials (log out))]
+de,dsgw,212,[Ihre Beglaubigungsberechtigung für \n(Your authentication credentials for )]
+de,dsgw,213,[ist abgelaufen (have expired).\n<HR>)\n]
+de,dsgw,214,[Ihr Zugriff zu dem Verzeichnis ist derzeitig nicht beglaubigt.\n(Currently, you are not authenticated to the directory.<HR>)\n]
+de,dsgw,215,["%s=" fehlt (missing)]
+de,dsgw,216,["%s=%s" unbekannt (unknown)]
+de,dsgw,217,[unbekannte Option (unknown option) %s ]
+de,dsgw,218,[unbekannte Syntax=%s (syntax shown unknown)\n]
+de,dsgw,219,[** HTML-Typ "%s" nicht unterstützt **<BR>\n(** HTML type shown is not supported **<BR>)\n]
+de,dsgw,224,[Bearbeiten (Edit)]
+de,dsgw,225,[Save Changes]
+de,dsgw,226,[modify]
+de,dsgw,227,[add]
+de,dsgw,228,[Löschen (Delete)]
+de,dsgw,229,[Diesen Eintrag löschen? (Delete this entry?)]
+de,dsgw,230,[Umbenennen (Rename)]
+de,dsgw,231,[Neuen Namen für diesen Eintrag eingeben:\n(Enter a new name for this entry:)]
+de,dsgw,232,[Bearbeiten unter (Edit As)]
+de,dsgw,233,[%s= fehlt (missing)]
+de,dsgw,234,[Fenster schließen (Close Window)]
+de,dsgw,235,[Bearbeiten... (Edit...)]
+de,dsgw,236,["%s=" fehlt (missing)\n]
+de,dsgw,237,[Unbekannter Satz "%s" (set shown is unknown)\n]
+de,dsgw,238,[unbekannte Syntax "%s" (unknown syntax "%s")\n]
+de,dsgw,239,[Neu beglaubigen (Re-Authenticate)]
+de,dsgw,240,[Fenster schließen (Close Window)]
+de,dsgw,241,[Möchten Sie wirklich (Do you really want to )]
+de,dsgw,242,[?]
+de,dsgw,243,[ OK ]
+de,dsgw,244,[ OK ]
+de,dsgw,245,[Zurücksetzen (Reset)]
+de,dsgw,246,[Beendet (Done)]
+de,dsgw,247,[Abbrechen (Cancel)]
+de,dsgw,248,[anderes IF gefunden (geschachtelte IFs sind nicht unterstützt)\n(found another IF (nested IFs are not supported))]
+de,dsgw,249,[ELSE wurde gefunden, aber kein IF\n(found ELSE but didn't see an IF)]
+de,dsgw,250,[ELSE nach ELSE gefunden (ENDIF erwartet)\n(found ELSE after ELSE (expecting ENDIF))]
+de,dsgw,251,[ELSE wurde gefunden, aber kein IF\n(found ELIF but didn't see an IF)]
+de,dsgw,252,[ELIF nach ELSE gefunden (ENDIF erwartet)\n(found ELIF after ELSE (expecting ENDIF))]
+de,dsgw,253,[ELDIF wurde gefunden, aber kein IF\n(found ENDIF but didn't see an IF)]
+de,dsgw,254,[<BR><B>Vorlagefehler (template error):</B> %s<BR>\n]
+de,dsgw,255,[ldap_init/lcache_init aufgerufen, ehe Konfigurationsdatei gelesen wurde\n(ldap_init/lcache_init attempted before config file read)]
+de,dsgw,256,[führt nicht unter dem Verwaltungs-Server aus\n(not running under the administration server)]
+de,dsgw,257,[Konnte Genehmigungen nicht initialisieren\n(Could not initialize permissions)]
+de,dsgw,258,[Konnte Benutzername nicht auf einem DN abbilden (Fehler vom Verwaltungs-Server)\n(Could not map username to a DN (error from admin server))]
+de,dsgw,259,[Konnte aktuellen Benutzernamen nicht aufrufen\n(Could not get current username)]
+de,dsgw,260,[Konnte aktuelles Benutzerkennwort nicht abrufen\n(Could not get current user password)]
+de,dsgw,261,[Fehler (Error): %s]
+de,dsgw,262,[Hinweis: Für diese Art von Eintrag gibt es keine Anzeigevorlage; die Eintragsart \nwird unten\nim Standarmodus angezeigt.\n(Note: there is no display template for this type of entry available, so it is\ndisplayed below using a default method.)]
+de,dsgw,263,[Ungültige Benutzer-ID bzw. NULL LDAP-Erkennung\n(Invalid user id or NULL LDAP handle)]
+de,dsgw,264,[keine Ãœbereinstimmung mit Benutzer-ID\n(no match for user id)]
+de,dsgw,265,[mehr als eine Ãœbereinstimmung mit Benutzer-ID\n(more than one match for user id)]
+de,dsgw,266,[the entire directory]
+de,dsgw,267,[Die Betriebsanweisung "includeset" erfordert zwei Argumente\n(Two arguments are required for the "includeset" directive)\n]
+de,dsgw,268,[Der angeforderte Attributwert wurde im Eintrag nicht gefunden (The attribute value requested was not found in the entry)]
+de,dsgw,269,[Argument fehlt in der "NLS"-Betriebsanweisung\n]
+de,dsgw,270,[Es muß ein NT-Benutzername angegeben werden]
+de,dsgw,271,[Die Kombination aus NT-Benutzernamen und NT-Domäne ist in diesem Verzeichnis nicht eindeutig\n]
+de,dsgw,272,[Es muß sowohl ein NT-Benutzername als auch eine NT-Domäne angegeben werden\n]
+de,dsgw,273,[Der NT-Benutzername darf nicht länger sein als 20 Zeichen.]
+de,dsgw,274,[Namen für den neuen Eintrag angeben.]
+de,dsgw,275,[Standort für den neuen Eintrag auswählen.]
+de,dsgw,276,[Neuer Eintrag]
+de,dsgw,277,[Für diese Funktion muß ein Verzeichnisverwalter in der Datei "dsgw.conf" definiert sein]
+de,dsgw,278,[Die Betriebsanweisung "vcard-property" erfordert drei oder vier Argumente.\n]
+de,dsgw,279,[DieVCard-Eigenschaft kann nur entweder "cis" oder "mls" lauten.\n]
+de,dsgw,280,[Kein Eintrag gefunden.\n%2$s]
+de,dsgw,281,[Kein Eintrag gefunden, in dem %2$s '%4$s' %3$s.\n]
+de,dsgw,282,[Kein Eintrag gefunden.\n%2$s]
+de,dsgw,283,[Kein Eintrag gefunden, in dem %2$s '%4$s' %3$s.\n]
+de,dsgw,284,[1 Eintrag gefunden.\n%2$s]
+de,dsgw,285,[1 Eintrag gefunden, in dem %2$s '%4$s' %3$s.\n]
+de,dsgw,286,[1 Eintrag gefunden.\n%2$s]
+de,dsgw,287,[1 Eintrag gefunden, in dem %2$s '%4$s' %3$s.\n]
+de,dsgw,288,[%1$li Einträge gefunden.\n%2$s]
+de,dsgw,289,[%1$li Einträge gefunden, in denen %2$s '%4$s' %3$s.\n]
+de,dsgw,290,[%1$li Einträge gefunden.\n%2$s]
+de,dsgw,291,[%1$li Einträge gefunden, in denen %2$s '%4$s' %3$s.\n]
+de,dsgw,292,[der LDAP-Filter ist]
+de,dsgw,293,[Der Server konnte den Eintrag, den Sie bei der Beglaubigung verwendet haben, nicht finden. Möglicherweise wurde der Eintrag umbenannt oder gelöscht. Bitte wiederholen Sie die Beglaubigung.]
+de,dsgw,294,[Die neue Kennwortsyntax ist ungültig.\n]
+de,dsgw,295,[Das neue Kennwort ist in der Kennwortchronik enthalten.\n]
+de,dsgw,296,[Sie haben den Grenzwert für die Wiederholung des Kennworts überschritten. Bitte wenden Sie sich an den Systemverwalter.\n]
+de,dsgw,297,[Sie haben den Grenzwert für die Wiederholung des Kennworts überschritten. Versuchen Sie es später erneut.\n]
+de,dsgw,298,[Das Kennwort ist abgelaufen. Wenden Sie sich an den Systemverwalter, um das Kennwort zurückzusetzen.\n]
+de,frame,-1,[$DBT: frame in DB file v1 $]
+de,frame,1,[<TITLE>Nicht gefunden (Not Found)</TITLE><H1>Nicht gefunden (Not Found)</H1> Das angeforderte Objekt existiert nicht auf diesem Server. Die von Ihnen verfolgte Verknüpfung ist entweder veraltet, ungenau oder der Server darf sie Ihnen nicht anbieten.\n(The requested object does not exist on this server. The link you followed is either outdated, inaccurate, or the server has been instructed not to let you have it.)]
+de,frame,2,[Informieren Sie bitte den Standortverwalter über die <A HREF="%s">, Bezugsseite </A>.\n(Please inform the site administrator of the referring page.)]
+de,frame,3,[Ihr Browser sandte eine Anforderung, die dieser Proxy-Server nicht verstehen kann.\n(Your browser sent a request that this proxy could not understand.)]
+de,frame,4,[Ordnungsgemäße Genehmigung ist für den Administrator dieses Proxy-Servers erforderlich.\nEntweder führt Ihr Browser keine Genehmigung aus oder Ihre Genehmigung ist falsch.\n(Proper authorization is required for the administration of this proxy.\nEither your browser does not perform authorization, or your authorization\nhas failed.)]
+de,frame,5,[Beglaubigung des Benutzernamens ist erforderlich, um diesen Proxy-Server zu benutzen.\n Entweder führt Ihr Browser keine Proxy-Genehmigung aus oder Ihre Genehmigung ist falsch.\n(Username authentication is required for using this proxy.\nEither your browser does not perform proxy authorization, or your\nauthorization has failed.)]
+de,frame,6,[Die Zugriffssteuerungskonfiguration des Proxy-Servers verweigert\nZugriff auf das durch diesen Proxy-Server angeforderte Objekt.\n(The proxy's access control configuration denies access to\nthe requested object through this proxy.)]
+de,frame,7,[Im Proxy-Server ist ein interner Fehler aufgetreten, so daß Ihre\nAnforderung nicht ausgeführt werden kann. Wahrscheinlich ist die Konfiguration falsch.\nBitten Sie den Administrator, nach entsprechenden Hinweisen im Fehlerprotokoll des Proxy-Servers zu suchen.\n(The proxy has encountered an internal error which prevents it from\nfulfilling your request. The most likely cause is a misconfiguration.\nPlease ask the administrator to look for messages in the proxy's error log.)]
+de,frame,8,[Dieser Proxy-Server setzt nicht die angeforderte Methode ein.\n(This proxy server does not implement the requested method.)]
+de,frame,9,[Ein Fehler ist auf dem Proxy-Server aufgetreten.\n(An error has occurred on the proxy server.)]
+de,frame,10,[Dieser Server konnte die gesendete Anfrage Ihres Browsers nicht verstehen.\n(Your browser sent a query this server could not understand.)]
+de,frame,11,[Ordnungsgemäße Genehmigung ist für diesen Bereich erforderlich. Entweder führt Ihr Browser keine Genehmigung aus oder Ihre Genehmigung ist falsch.\n(Proper authorization is required for this area. Either your browser does not perform authorization, or your authorization has failed.)]
+de,frame,12,[Ihr Client darf das angeforderte Objekt nicht abrufen.\n(Your client is not allowed to access the requested object.)]
+de,frame,13,[In diesem Server ist ein interner Fehler aufgetreten, so daß Ihre Anforderung nicht ausgeführt werden kann. Wahrscheinlich ist die Konfiguration falsch. Bitten Sie den Administrator, nach entsprechenden Hinweisen im Fehlerprotokoll des Proxy-Servers zu suchen.\n(This server has encountered an internal error which prevents it from fulfilling your request. The most likely cause is a misconfiguration. Please ask the administrator to look for messages in the server's error log.)]
+de,frame,14,[Dieser Server setzt nicht die angeforderte Methode ein.\n(This server does not implement the requested method.)]
+de,frame,15,[Ein Fehler ist aufgetreten.\n(An error has occurred.)]
+de,frame,16,[Dieser Server konnte die gesendete Meldung Ihres Browsers nicht verstehen.\n(Your browser sent a message this server could not understand.)]
+de,frame,17,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="de"><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>\nDieses Dokument wurde an einen neuen <a href="%s">Standort verschoben</a>. Aktualisieren Sie bitte Ihre Dokumente und Hotlisten entsprechend.(This document has moved to a new location. Please update your documents and hotlists accordingly.)</BODY></HTML>\n]
+de,frame,18,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="de"><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>]
+de,frame,19,[process-uri-objects]
+de,frame,20,[cannot find template %s]
+de,frame,21,[process-uri-objects]
+de,frame,22,[no partial path after object processing]
+de,frame,23,[find-service]
+de,frame,24,[invalid shexp %s]
+de,frame,25,[find-service]
+de,frame,26,[invalid shexp %s]
+de,frame,27,[handle-processed]
+de,frame,28,[no way to service request for %s]
+de,frame,29,[finish-socks-request]
+de,frame,30,[close failed (%s), csd=%d]
+de,frame,31,[This beta software has expired.\n]
+de,frame,32,[mr_accept(%d)]
+de,frame,33,[Error issuing read on accept socket]
+de,frame,34,[acb_accept_connection(%d)]
+de,frame,35,[Error getting accept socket (%d)]
+de,frame,36,[Error in accept! (%d, %s)]
+de,frame,37,[Error creating new accept request]
+de,frame,38,[accepted connection: %d (NSPR %d)]
+de,frame,39,[Error creating new session structure]
+de,frame,40,[accel_read_request()]
+de,frame,41,[Error allocating request read buffer]
+de,frame,42,[Error issuing async read request]
+de,frame,43,[acb_read_request(%d, bytes %d)]
+de,frame,44,[acb_read_req(1 session = %d)]
+de,frame,45,[Error reading request (%d, %s)]
+de,frame,46,[Client aborted connection]
+de,frame,47,[Error reading request]
+de,frame,48,[Error creating new request]
+de,frame,49,[error occurred, closing %d, io was for %d]
+de,frame,50,[accel_async_scan_headers()]
+de,frame,51,[out of memory: accel_async_scan_headers]
+de,frame,52,[out of memory: accel_async_scan_headers]
+de,frame,53,[Error during async read (%d, %s)]
+de,frame,54,[scan-headers reports: line too long]
+de,frame,55,[scan-headers reports: too many headers]
+de,frame,56,[Error reading headers]
+de,frame,57,[scan-headers reports: header missing terminator (an empty line)]
+de,frame,58,[scan-headers reports: header was empty]
+de,frame,59,[Name ohne Wert: Zeile "%s" erhalten\n(name without value: got line as shown)]
+de,frame,60,[accel_send_plain_file()]
+de,frame,61,[accel_send_plain_file() - found request %d]
+de,frame,62,[Parse headers lost the URI!]
+de,frame,63,[accel_send_plain_file() - found uri %s]
+de,frame,64,[accel_send_plain_file() - found in cache?]
+de,frame,65,[malloc died!]
+de,frame,66,[Error writing back file\n]
+de,frame,67,[acb_send_plain_file(%d)]
+de,frame,68,[Error writing in acb_send_plain_file (%d, %s)]
+de,frame,69,[acb_close_connection(%d)]
+de,frame,70,[Errored IO in acb_close_connection (%d, %s)]
+de,frame,71,[Unable to close socket %d]
+de,frame,72,[accel-cache-insert: Error allocating entry]
+de,frame,73,[cache-init: server cache disabled]
+de,frame,74,[accel_file_cache: Error initializing file cache]
+de,frame,75,[accel_file_cache: Error creating cache]
+de,frame,76,[accel_file_cache_init: CacheHashSize < %d, using %d]
+de,frame,77,[accel_file_cache_init: CacheHashSize > %d, using %d]
+de,frame,78,[accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d]
+de,frame,79,[accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d]
+de,frame,80,[accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d]
+de,frame,81,[accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d]
+de,frame,82,[accel_file_cache: Error initializing file cache]
+de,frame,83,[file-cache: enabled = %s ]
+de,frame,84,[on]
+de,frame,85,[off]
+de,frame,86,[file-cache: MaxNumberOfCachedFiles %d (0x%x)]
+de,frame,87,[file-cache: CacheHashSize %d (0x%x)]
+de,frame,88,[file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)]
+de,frame,89,[accel-cache-insert: Error allocating entry]
+de,frame,90,[file-cache-cleanup: munmap failed (%s)]
+de,frame,91,[file-cache-cleanup: found mmapped file \non system without mmap]
+de,frame,92,[file_cache_init: MaxTotalCachedFileSize < %d, using %d]
+de,frame,93,[file_cache_init: MaxTotalCachedFileSize > %d, using %d]
+de,frame,94,[file cache using mmap flags 0x%x]
+de,frame,95,[file cache using mmap prots 0x%x]
+de,frame,96,[file-cache-init: could not create lock]
+de,frame,97,[file-cache: unable to create temporary directory %s.\n]
+de,frame,98,[file-cache: unable to create temporary directory %s.\n]
+de,frame,99,[file-cache: GetTempPath() Cannot find temp directory to store file!]
+de,frame,100,[file-cache-init: set max cached file size to %d]
+de,frame,101,[file-cache-init: could not create lock]
+de,frame,102,[file_cache_destroy()]
+de,frame,103,[file-cache: Unable to get temp file name. Error %s]
+de,frame,104,[file-cache: Unable to get temp file name. Error %s]
+de,frame,105,[file-cache-insert: Error allocating entry]
+de,frame,106,[file-cache-create: Error opening file %s (%s)]
+de,frame,107,[file-cache-create: Error stat()ing file %s (%s)]
+de,frame,108,[file-cache-create: Error mmap()ing file %s (%s)]
+de,frame,109,[file-cache-create: malloc failure]
+de,frame,110,[file-cache-create: error case failed to munmap(%d, %d) (%s)]
+de,frame,111,[file-cache-valid: cannot stat %s]
+de,frame,112,[dir change: invalidating %s (%d)]
+de,frame,113,[file-cache: asynchronous file change notification failed.]
+de,frame,114,[dir change: offset %d, action %d, len %d, name %s]
+de,frame,115,[unable to check async file status]
+de,frame,116,[ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s]
+de,frame,117,[file-cache-add-watch failure- unable to open directory %s. Error %s]
+de,frame,118,[ReadDirectoryChangesW failure- unable to start watching %s. Error %s]
+de,frame,119,[func_exec]
+de,frame,120,[no handler function given for directive]
+de,frame,121,[func_exec]
+de,frame,122,[cannot find function named %s]
+de,frame,123,[handle-request]
+de,frame,124,[method without URI]
+de,frame,125,[http-parse-request]
+de,frame,126,[while scanning HTTP headers, %s]
+de,frame,127,[handle-request]
+de,frame,128,[read from %s failed, error is %s]
+de,frame,129,[handle-request]
+de,frame,130,[request too long]
+de,frame,131,[start-http-response]
+de,frame,132,[write failed (%s)]
+de,frame,133,[start-http-response]
+de,frame,134,[write failed (%s)]
+de,frame,135,[http-status]
+de,frame,136,[%d is not a valid HTTP status code]
+de,frame,137,[finish-request]
+de,frame,138,[close failed (%s)]
+de,frame,139,[Unable to close socket for writing]
+de,frame,140,[os has %d objects]
+de,frame,141,[obj %d has no hash table at %d]
+de,frame,142,[obj %d has no param]
+de,frame,143,[obj %d name %s value %s]
+de,frame,144,[.....directives %d.......]
+de,frame,145,[.....directive %d]
+de,frame,146,[.......instance %d]
+de,frame,147,[...........param name %s value %s]
+de,frame,148,[ClearConfigurationParameters:RegCreateKey %s]
+de,frame,149,[ClearConfigurationParameters:RegEnumKey %s failed]
+de,frame,150,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+de,frame,151,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+de,frame,152,[Unable to allocate Subject property list.\n]
+de,frame,153,[Unable to set session ptr in Subject property list - error=%d\n]
+de,frame,154,[Unable to set request ptr in Subject property list - error=%d\n]
+de,frame,155,[file-cache-valid: cannot stat %s]
+de,frame,156,[file-cache-create: Error stat()ing file %s (%s)]
+de,httpdaemon,-1,[$DBT: httpdaemon in DB file v1 $]
+de,httpdaemon,1,[Error in ConvertThreadToFiber]
+de,httpdaemon,2,[Error in ConvertThreadToFiber]
+de,httpdaemon,3,[Error in md_start_system]
+de,httpdaemon,4,[Error in CreateFiber - idlefiber]
+de,httpdaemon,5,[Error in GetQueuedCompletionStatus]
+de,httpdaemon,6,[Error creating completion port]
+de,httpdaemon,7,[Could not SetHandleNonInheritable (%s)]
+de,httpdaemon,8,[Error accept/read new conn]
+de,httpdaemon,9,[Error in Respond()]
+de,httpdaemon,10,[Error in RespondCompleted()]
+de,httpdaemon,11,[daemon: unable to fork new process (%s)\n]
+de,httpdaemon,12,[daemon: setsid failed (%s)\n]
+de,httpdaemon,13,[daemon: can't log pid to %s (%s)\n]
+de,httpdaemon,14,[warning: could not set group id to %d (%s)\n]
+de,httpdaemon,15,[warning: could not set user id to %d (%s)\n]
+de,httpdaemon,16,[warning: daemon is running as super-user\n]
+de,httpdaemon,17,[could not determine current user name\n]
+de,httpdaemon,18,[error: chroot to %s failed (%s)\n]
+de,httpdaemon,19,[WARNING! netscape executable and library have different versions.\n]
+de,httpdaemon,20,[startup: listening to %s://%s, port %d as %s\n]
+de,httpdaemon,21,[startup: listening to %s://%s, port %d as %s\n]
+de,httpdaemon,22,[seminit failed (%s)\n]
+de,httpdaemon,23,[Using single threaded accepts.]
+de,httpdaemon,24,[Using multi threaded accepts.]
+de,httpdaemon,25,[Using partial single threaded accepts.]
+de,httpdaemon,26,[This machine has %d processors.]
+de,httpdaemon,27,[Error calling thr_seconcurrency(%d)- (%s)]
+de,httpdaemon,28,[Set conncurrency to %d.]
+de,httpdaemon,29,[can't fork new process (%s)]
+de,httpdaemon,30,[This beta software has expired.\n]
+de,httpdaemon,31,[can't create IPC pipe (%s)]
+de,httpdaemon,32,[write to wakeup pipe failed (%s)]
+de,httpdaemon,33,[select thread miss]
+de,httpdaemon,34,[startup failure: could not bind to port %d (%s)\n]
+de,httpdaemon,35,[startup failure: could not bind to port %d, IP address %s (%s)\n]
+de,libaccess,-1,[$DBT: libaccess in DB file v1 $]
+de,libaccess,1,[basic-ncsa]
+de,libaccess,2,[cannot open database %s]
+de,libaccess,3,[basic-ncsa]
+de,libaccess,4,[user %s password did not match database %s]
+de,libaccess,5,[basic-ncsa]
+de,libaccess,6,[cannot open connection to LDAP server on %s:%d]
+de,libaccess,7,[basic-ncsa]
+de,libaccess,8,[user %s password did not match LDAP on %s:%d]
+de,libaccess,9,[acl-state]
+de,libaccess,10,[missing realm]
+de,libaccess,11,[Unable to allocate ACL List Hash\n]
+de,libaccess,12,[ACLEvalBuildContext unable to PERM_MALLOC cache structure\n]
+de,libaccess,13,[ACLEvalBuildContext unable to create hash table\n]
+de,libaccess,14,[ACLEvalBuildContext unable to allocate ACE Entry\n]
+de,libaccess,15,[ACLEvalBuildContext unable to allocate ACE entry\n]
+de,libaccess,16,[ACLEvalBuildContext unable to allocate Boundary Entry\n]
+de,libaccess,17,[ACLEvalBuildContext failed.\n]
+de,libaccess,18,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n]
+de,libaccess,19,[LASDnsBuild unable to allocate hash table header\n]
+de,libaccess,20,[LASDnsBuild unable to add key %s\n]
+de,libaccess,21,[LASDnsBuild unable to add key %s\n]
+de,libaccess,22,[LASDnsBuild unable to add key %s\n]
+de,libaccess,23,[LASDnsBuild unable to add key %s\n]
+de,libaccess,24,[LASDnsBuild unable to add key %s\n]
+de,libaccess,25,[LAS DNS build received request for attribute %s\n]
+de,libaccess,26,[LASDnsEval - illegal comparator %s\n]
+de,libaccess,27,[LASDnsEval unable to allocate Context struct\n\n]
+de,libaccess,28,[LASDnsEval unable to get session address %d\n]
+de,libaccess,29,[LASDnsEval unable to get DNS - error=%s\n]
+de,libaccess,30,[LAS Group Eval received request for attribute %s\n]
+de,libaccess,31,[LASGroupEval - illegal comparator %s\n]
+de,libaccess,32,[LASGroupEval - ran out of memory\n]
+de,libaccess,33,[LASGroupEval unable to get session address %d\n]
+de,libaccess,34,[LASGroupEval unable to get session address %d\n]
+de,libaccess,35,[LASGroupEval - couldn't locate getter for auth-user\n]
+de,libaccess,36,[LASGroupEval - Attribute getter for auth-user failed\n]
+de,libaccess,37,[LASGroupEval - Attribute getter didn't set auth-user\n]
+de,libaccess,38,[Check group membership of user "%s" for group "%s"\n]
+de,libaccess,39,[LDAPU_SUCCESS for group "%s"\n]
+de,libaccess,40,[LDAPU_FAILED for group "%s"\n]
+de,libaccess,41,[LAS_EVAL_FALSE\n]
+de,libaccess,42,[LAS_EVAL_TRUE\n]
+de,libaccess,43,[LASIpTreeAlloc - no memory\n]
+de,libaccess,44,[IP LAS unable to allocate tree node\n]
+de,libaccess,45,[IP LAS unable to allocate tree node\n]
+de,libaccess,46,[LAS IP build received request for attribute %s\n]
+de,libaccess,47,[LASIpEval - illegal comparator %s\n]
+de,libaccess,48,[LASIpEval unable to get session address - error=%s\n]
+de,libaccess,49,[LASIpEval unable to allocate Context struct\n\n]
+de,libaccess,50,[LASIpEval - reach 32 bits without conclusion value=%s]
+de,libaccess,51,[LAS Program Eval received request for attribute %s\n]
+de,libaccess,52,[LASProgramEval - illegal comparator %s\n]
+de,libaccess,53,[LASProgram unable to get session address %d\n]
+de,libaccess,54,[bin]
+de,libaccess,55,[LASProgramEval: request not of type admin or bin, passing.\n]
+de,libaccess,56,[LASProgramEval: check if program %s matches pattern %s.\n]
+de,libaccess,57,[LASProgramEval: Invalid wildcard expression %s.\n]
+de,libaccess,58,[LAS_EVAL_FALSE\n]
+de,libaccess,59,[LAS_EVAL_TRUE\n]
+de,libaccess,60,[Unexpected attribute in dayOfWeek - %s\n]
+de,libaccess,61,[Illegal comparator for dayOfWeek - %s\n]
+de,libaccess,62,[Unexpected attribute in timeOfDay - %s\n]
+de,libaccess,63,[LAS User Eval received request for attribute %s\n]
+de,libaccess,64,[LASUserEval - illegal comparator %s\n]
+de,libaccess,65,[LASUserEval - ran out of memory\n]
+de,libaccess,66,[LASUserEval unable to get session address %d\n]
+de,libaccess,67,[LASUserEval unable to get session address %d\n]
+de,libaccess,68,[LASGroupEval - couldn't locate getter for auth-user\n]
+de,libaccess,69,[LASGroupEval - Attribute getter for auth-user failed\n]
+de,libaccess,70,[LASGroupEval - Attribute getter didn't set auth-user\n]
+de,libaccess,71,[Check if uid == user (i.e. check "%s" == "%s)"\n]
+de,libaccess,72,[SUCCESS for user "%s"\n]
+de,libaccess,73,[FAILED for user "%s"\n]
+de,libaccess,74,[LAS_EVAL_FALSE\n]
+de,libaccess,75,[LAS_EVAL_TRUE\n]
+de,libaccess,76,[]
+de,libaccess,77,[LASProgram unable to get request address - error=%s]
+de,libaccess,78,[LASProgram rejecting request for program %s from pattern %s]
+de,libaccess,79,[ACL_CacheFlush: unable to parse file "%s"\n]
+de,libaccess,80,[ACL_CacheFlush: unable to concatenate ACL list "%s"\n]
+de,libaccess,81,[ACL_CacheFlush: unable to open and process the magnus file "%s"\n]
+de,libaccess,82,[Illegal comparator for timeOfDay - %s\n]
+de,libaccess,83,[ACL_EvalBuildContext unable to create hash table\n]
+de,libaccess,84,[ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n]
+de,libaccess,85,[ACL_EvalBuildContext unable to allocate ACE entry\n]
+de,libaccess,86,[ACL_EvalBuildContext unable to allocate auth pointer array\n]
+de,libaccess,87,[ACL_EvalBuildContext unable to allocate auth plist\n]
+de,libaccess,88,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n]
+de,libaccess,89,[ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n]
+de,libaccess,90,[ACL_ModuleRegister: module name is missing\n]
+de,libaccess,91,[ACL_ModuleRegister: call to module init function returned a failed status\n]
+de,libaccess,92,[ACL_GetAttribute: couldn't determine method for %s\n]
+de,libaccess,93,[ACL_GetAttribute: couldn't locate getter for %s]
+de,libaccess,94,[ACL_GetAttribute: attr getter failed to get %s]
+de,libaccess,95,[ACL_GetAttribute: attr getter failed to get %s]
+de,libaccess,96,[ACL_GetAttribute: All attribute getters declined for attr %s]
+de,libaccess,97,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+de,libaccess,98,[ACL_DatabaseRegister: database name is missing]
+de,libaccess,99,[Error reading the DB Map File: %s. Reason: %s]
+de,libaccess,100,[URL is missing for database %s]
+de,libaccess,101,[Invalid property value pair for database %s]
+de,libaccess,102,["default" database must be an LDAP database]
+de,libaccess,103,[Multiple "default" databases are being registered]
+de,libaccess,104,["default" LDAP database must be registered]
+de,libaccess,105,[LASGroupEval unable to get database name - error= %s]
+de,libaccess,106,[received invalid program expression %s]
+de,libaccess,107,[parse_ldap_url: database url is missing]
+de,libaccess,108,[parse_ldap_url: database name is missing]
+de,libaccess,109,[parse_ldap_url: error in parsing ldap url. Reason: %s]
+de,libaccess,110,[ldap password check: unable to get database name - error=%s]
+de,libaccess,111,[ldap password check: unable to get parsed database %s]
+de,libaccess,112,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+de,libaccess,113,[ldap password check: LDAP error: "%s"]
+de,libaccess,114,[get_user_ismember_ldap unable to get database name - error=%s]
+de,libaccess,115,[get_user_ismember_ldap unable to get parsed database %s]
+de,libaccess,116,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+de,libaccess,117,[get_user_ismember_ldap: group %s does not exist]
+de,libaccess,118,[get_user_ismember_ldap: LDAP error: "%s"]
+de,libaccess,119,[ACL_LDAPDatabaseHandle: %s is not a registered database]
+de,libaccess,120,[ACL_LDAPDatabaseHandle: %s is not an LDAP database]
+de,libaccess,121,[ACL_LDAPDatabaseHandle: out of memory]
+de,libaccess,122,[ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s]
+de,libaccess,123,[ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s]
+de,libaccess,124,[insufficient dynamic memory]
+de,libaccess,125,[error opening file, %s: %s]
+de,libaccess,126,[duplicate definition of %s]
+de,libaccess,127,[file %s, line %s: duplicate definition of %s]
+de,libaccess,128,[file %s, line %s: syntax error]
+de,libaccess,129,[file %s, line %s: %s is undefined]
+de,libaccess,130,[in acl %s, %s %s is undefined]
+de,libaccess,131,[database %s: error accessing %s]
+de,libaccess,132,[%s]
+de,libaccess,133,[file %s, line %s: invalid syntax]
+de,libaccess,134,[file %s, line %s: syntax error at "%s"]
+de,libaccess,135,[realm %s is not defined]
+de,libaccess,136,[error code = %d]
+de,libaccess,137,[internal ACL error]
+de,libaccess,138,[invalid argument]
+de,libaccess,139,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+de,libaccess,140,[couldn't determine dbtype from: %s]
+de,libaccess,141,[Failed to register database %s]
+de,libaccess,142,[ACL call returned failed status]
+de,libaccess,143,[file %s: ACL IO error - %s]
+de,libaccess,144,[acl_user_exists: Nicht genug Speicher]
+de,libaccess,145,[acl_user_exists: Benutzer existiert nicht mehr]
+de,libaccess,146,[acl_user_exists: plist-Fehler]
+de,libadmin,-1,[$DBT: libadmin in DB file v1 $]
+de,libadmin,1,[ Help ]
+de,libadmin,2,[ OK ]
+de,libadmin,3,[ Reset ]
+de,libadmin,4,[ Done ]
+de,libadmin,5,[ Cancel ]
+de,libir,-1,[$DBT: libadmin in DB file v1 $]
+de,libir,1,[An I/O error occurred before all form data could be read.]
diff --git a/l10n/dirserv/de/ns-slapd.txt.iso8859 b/l10n/dirserv/de/ns-slapd.txt.iso8859
new file mode 100644
index 00000000..a61ef25f
--- /dev/null
+++ b/l10n/dirserv/de/ns-slapd.txt.iso8859
@@ -0,0 +1,879 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* This text file was generated by program dblink */
+
+$Revision: 1.1 $
+$Log: ns-slapd.txt.iso8859,v $
+Revision 1.1 2005/01/21 00:40:48 cvsadm
+Initial revision
+
+Revision 1.3.2.3 2003/09/22 19:36:40 ulfw
+Update copyright years from 2001 to 2001-2003
+
+Revision 1.3.2.2 2001/11/03 01:05:35 richm
+XXX use new copyright XXX
+
+Revision 1.3.2.1 1998/10/10 02:13:59 ggood
+Copy from Directory40RtmBranchpoint to DirectoryBranch
+
+Revision 1.1.2.4.2.2.6.1 1998/04/04 23:16:47 mcs
+merge changes made on directory31_rtm_branch into server4_directory_branch
+
+Revision 1.1.2.4.2.2.2.1 1998/02/24 05:51:52 noriko
+Synched with server3_i18npkg_branch
+
+Revision 1.1.2.6 1997/12/31 00:23:36 werudge
+Remove \n from dsgw,198 to fix JavaScript problem
+
+Revision 1.1.2.5 1997/12/19 02:03:43 werudge
+Based on en/ns-slapd.txt : 1.1.2.3
+daily 971113.1 SOLARIS-export-optimize-normal-slapd
+$EndLog$
+
+$StartStringData$
+
+de,base,-1,[$DBT: base in DB file v1 $]
+de,base,1,[nicht genügend Arbeitsspeicher zum Erstellen der Hash-Tabelle]
+de,base,2,[nicht genügend Arbeitsspeicher zum Erstellen der Hash-Tabelle]
+de,base,3,[cache_destroy: Cache-Tabellen scheinen beschädigt zu sein.]
+de,base,4,[Hash-Eintrag kann nicht zugewiesen werden]
+de,base,5,[cache_insert: Cache-Eintrag kann nicht erstellt werden]
+de,base,6,[HTTP/1.0 200 OK\nContent-type: text/html\n\n]
+de,base,7,[<H2>Netscape-Cache Statusbericht</H2>\n(<H2>Netscape cache status report</H2>)\n]
+de,base,8,[Keine Caches im System (No caches on system)<P>]
+de,base,9,[<H2>%s Cache (cache)</H2>\n]
+de,base,10,[Cacheverbindungsverhältnis (Cache hit ratio): %d/%d (%f)</P>\n</P>\n]
+de,base,11,[Cachegröße (Cache size): %d/%d</P>\n</P>\n]
+de,base,12,[Hash-Tabellengröße (Hash table size): %d</P>\n</P>\n]
+de,base,13,[mru : %d</P>\nlru : %d</P>\n]
+de,base,14,[<UL><TABLE BORDER=4> <TH>Originalspeicherbereich (Bucket)</TH> <TH>Adresse (Address)</TH> <TH>Schlüssel (Key)</TH> <TH>Zugriffsanzahl (Access Count)</TH> <TH>Löschen (Delete)</TH> <TH>Nächste (Next)</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>Daten (Data)</TH>\n]
+de,base,15,[munmap failed (%s)]
+de,base,16,[munmap failed (%s)]
+de,base,17,[close failed (%s)]
+de,base,18,[daemon: unable to fork new process (%s)\n]
+de,base,19,[daemon: setsid failed (%s)\n]
+de,base,20,[daemon: can't log pid to %s (%s)\n]
+de,base,21,[warning: could not set group id to %d (%s)\n]
+de,base,22,[warning: could not set user id to %d (%s)\n]
+de,base,23,[warning: daemon is running as super-user\n]
+de,base,24,[could not determine current user name\n]
+de,base,25,[error: chroot to %s failed (%s)\n]
+de,base,27,[, address %s]
+de,base,28,[warning: statistics disabled (%s)\n]
+de,base,29,[security handshake timed out for pid %d]
+de,base,30,[warning: statistics disabled (%s)\n]
+de,base,31,[secure handshake failed (code %d)\n]
+de,base,32,[accept failed (%s)]
+de,base,33,[warning: statistics disabled (%s)\n]
+de,base,34,[select thread miss]
+de,base,35,[keepalive worker awoken with no work to do]
+de,base,36,[could not create new thread: %d (%s)]
+de,base,37,[wait for sema succeeded, but nothing to dequeue]
+de,base,38,[queue-sema creation failure]
+de,base,39,[error getting processor info for processor %d]
+de,base,40,[Error binding to processor %d]
+de,base,41,[bound process %d to processor %d]
+de,base,42,[Netscape server is not explicitly binding to any processors.]
+de,base,43,[cache monitor exited]
+de,base,44,[cache batch update daemon exited]
+de,base,45,[Using single threaded accepts.]
+de,base,46,[Using multi threaded accepts.]
+de,base,47,[Using partial single threaded accepts.]
+de,base,48,[This machine has %d processors.]
+de,base,49,[Error calling thr_seconcurrency(%d)- (%s)]
+de,base,50,[Set conncurrency to %d.]
+de,base,51,[WARNING! netscape executable and library have different versions.\n]
+de,base,54,[seminit failed (%s)\n]
+de,base,55,[This beta software has expired.\n]
+de,base,56,[Cache monitor respawned]
+de,base,57,[Cache batch update daemon respawned]
+de,base,58,[can't find empty statistics slot]
+de,base,59,[can't fork new process (%s)]
+de,base,60,[assert failed! %s\n]
+de,base,61,[mr_table_init()]
+de,base,62,[malloc failed]
+de,base,63,[malloc failed!]
+de,base,64,[mr_add_io(%d, type %d, file %d)]
+de,base,65,[mr_add_io - stage 1]
+de,base,66,[mr_add_io - stage 2]
+de,base,67,[mr_add_io found invalid IO type %d]
+de,base,68,[mr_add_io - adding timeout]
+de,base,69,[Out of memory!\n]
+de,base,70,[done with mr_add_io]
+de,base,71,[mr_del_io(%d, type %d, file %d)]
+de,base,72,[mr_del_io found invalid IO type %d]
+de,base,73,[mr_lookup_io(%d)]
+de,base,74,[mr_async_io(%d, %d bytes, file %d)]
+de,base,75,[malloc failure adding async IO]
+de,base,76,[Error adding async io!]
+de,base,77,[Cannot seek for read!]
+de,base,78,[read failure! (%d, %s)]
+de,base,79,[do_read read %d bytes for file %d]
+de,base,80,[Cannot seek for write!]
+de,base,81,[writev failure! (%d, %s)]
+de,base,82,[write failure! (%d, %s)]
+de,base,83,[do_write wrote %d bytes for file %d]
+de,base,84,[do_timeout(mrp %d)]
+de,base,85,[do_timeout: found IO (timer=%d, time=%d)]
+de,base,86,[error deleting io]
+de,base,87,[timeout callback failure for %d\n]
+de,base,88,[mr_get_event(%d) - outstanding io %d]
+de,base,89,[mr_get_event: Waiting for reads on FD:]
+de,base,90,[mr_get_event: Waiting for writes on FD:]
+de,base,91,[ %d]
+de,base,92,[ %d]
+de,base,93,[mr_get_event set no timeout]
+de,base,94,[mr_get_event set timeout to: %d.%d sec]
+de,base,95,[error in select (%d, %s)]
+de,base,96,[mr_get_event() - select found %d]
+de,base,97,[error looking up IO fd %d]
+de,base,98,[read failed for fd %d]
+de,base,99,[error deleting io]
+de,base,100,[callback failure for %d\n]
+de,base,101,[error looking up IO fd %d]
+de,base,102,[writing: header len %d, writelen %d, total %d]
+de,base,103,[write failed for fd %d]
+de,base,104,[error deleting io]
+de,base,105,[callback failure for %d\n]
+de,base,106,[Error creating dns cache]
+de,base,107,[dns_cache_init: hash_size <= 0, using %d]
+de,base,108,[dns_cache_init: cache-size <= %d, using %d]
+de,base,109,[dns_cache_init: cache-size is %d is too large, using %d.]
+de,base,110,[dns_cache_init: expire_time <= 0, using %d]
+de,base,111,[dns_cache_init: expire is %d is too large, using %d seconds.]
+de,base,112,[Error creating dns cache]
+de,base,113,[dns-cache-insert: Error allocating entry]
+de,base,114,[dns-cache-insert: malloc failure]
+de,base,115,[successful server startup]
+de,base,116,[%s B%s]
+de,base,117,[Netscape executable and shared library have different versions]
+de,base,118,[ executable version is %s]
+de,base,119,[ shared library version is %s]
+de,base,120,[error reporting shutting down]
+de,base,121,[warning]
+de,base,122,[config]
+de,base,123,[security]
+de,base,124,[failure]
+de,base,125,[catastrophe]
+de,base,126,[info]
+de,base,127,[verbose]
+de,base,128,[event_handler:Failed to wait on events %s]
+de,base,129,[could not wait on resume event event (%s)]
+de,base,130,[dlopen of %s failed (%s)]
+de,base,131,[dlopen of %s failed (%s)]
+de,base,132,[The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!]
+de,base,133,[Terminating the server %s]
+de,base,134,[kill_server:cannot open server event %s]
+de,base,135,[kill_server:cannot set server event %s]
+de,base,136,[error: could not get socket (%s)\n]
+de,base,137,[error: could not set socket option (%s)\n]
+de,base,138,[Terminating Service:error: could not bind to address %s port %d (%s)\n]
+de,base,139,[Terminating Service:error: could not bind to port %d (%s)\n]
+de,base,140,[SetHandleNonInheritable: could not duplicate socket (%s)]
+de,base,141,[SetHandleNonInheritable: closing the original socket failed (%s)]
+de,base,142,[Could not SetHandleInformation (%s)]
+de,base,143,[Terminating Service:Failure: Could not open statistics file (%s)\n]
+de,base,144,[Could not set Thread Local Storage Value for thread at slot %d]
+de,base,145,[secure handshake failed (code %d)\n]
+de,base,146,[accept failed %d (%s)]
+de,base,147,[Failed to pulse Event %d %s]
+de,base,148,[Failed to send MobGrowth Event to parent %s]
+de,base,149,[Pulsing MobRespawn Event %d]
+de,base,150,[respawn thread pool to %d (%d)]
+de,base,151,[Could not open event to signal rotate application. Could not create the MoveLog event:%s]
+de,base,152,[Failed to send MoveLog Event to rotate app %s]
+de,base,153,[growing thread pool from %d to %d]
+de,base,154,[Could not open the ServiceControlManager, Error %d]
+de,base,155,[StartNetsiteService:Could not open the service %s: Error %d]
+de,base,156,[StartNetsiteService:Could not start the service %s]
+de,base,157,[Service Startup: Could not allocate security descriptor]
+de,base,158,[Service Startup: Could not init security descriptor]
+de,base,159,[Service Startup: Could not set the security Dacl]
+de,base,160,[Terminating Service:WinSock init failed: %s]
+de,base,161,[Httpd Server Startup failed: %s]
+de,base,162,[can't find empty statistics slot]
+de,base,163,[NT daemon: could not create new thread %d]
+de,base,164,[Service Startup Failure. Terminating Service:Could not create event %d:%s]
+de,base,165,[Service Startup Error. Could not create the MoveLog event:%s]
+de,base,166,[Failed to wait on Event objects %s]
+de,base,167,[Failed to wait on Event objects %s]
+de,base,168,[pipebuf_buf2sd: pipebuf_grab IO_ERROR %d]
+de,base,169,[pool-init: memory pools disabled]
+de,base,170,[pool-init: free_size <= 0, using %d]
+de,base,171,[pool-create-block: out of memory]
+de,base,172,[pool-create: out of memory]
+de,base,173,[pool-create: out of memory]
+de,base,174,[pool-malloc: out of memory]
+de,base,175,[FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.]
+de,base,176,[regex error: %s (regex: '%s')]
+de,base,177,[can't create IPC pipe (%s)]
+de,base,178,[write to wakeup pipe failed (%s)]
+de,base,179,[flushing %d connections; current %d; tot %d]
+de,base,180,[accept failed (%s)]
+de,base,181,[Error creating time cache]
+de,base,182,[time-cache: cache disabled]
+de,base,183,[time_cache_init: hash_size < %d, using default, %d]
+de,base,184,[time_cache_init: hash_size > %d, using default, %d]
+de,base,185,[time_cache_init: cache_size < %d, using default, %d]
+de,base,186,[time_cache_init: cache_size > %d, using default, %d]
+de,base,187,[Error allocating memory for time_cache]
+de,base,188,[Error allocating memory for time_cache entry]
+de,base,189,[Error allocating memory for time_cache entry]
+de,base,190,[Error inserting new time_cache entry]
+de,base,191,[Error allocating memory for time_cache]
+de,base,192,[cs-terminate failure (%s)]
+de,base,193,[cs-init failure (%s)]
+de,base,194,[cs-wait failure (%s)]
+de,base,195,[cs-post failure (%s)]
+de,base,196,[Unable to create nonblocking socket (%s)]
+de,base,197,[error: could not set keepalive (%s)\n]
+de,base,198,[error: could not set recv timeout (%s)\n]
+de,base,199,[error: could not set send timeout (%s)\n]
+de,base,200,[Unable to create nonblocking socket (%s)]
+de,base,201,[sem_grab failed (%s)]
+de,base,202,[sem_release failed (%s)]
+de,base,203,[sem_release failed (%s)]
+de,base,204,[Could not remove temporary directory %s, Error %d]
+de,base,205,[Could not remove temporary directory %s, Error %d]
+de,dsgw,-1,[$DBT: dsgw in DB file v1 $]
+de,dsgw,1,[Unbekannte HTTP-Anforderungsmethode (Unknown HTTP request method)]
+de,dsgw,2,[Ungültige oder unvollständige HTML-Formulardaten (Invalid or incomplete HTML form data)]
+de,dsgw,3,[Nicht genügend Speicherplatz (Out of memory)]
+de,dsgw,4,[Erforderliche Anfrage-/Formulareingabe fehlt (Required query/form input is missing)]
+de,dsgw,5,[Ungültiges Zeichen im Dateipfad (Illegal character in file path)]
+de,dsgw,6,[Falsche oder fehlende Konfigurationsdatei (Bad or missing configuration file)]
+de,dsgw,7,[LDAP kann nicht initialisiert werden (Unable to initialize LDAP)]
+de,dsgw,8,[Fehler beim Aufrufen des LDAP-Server (An error occurred while contacting the LDAP server)]
+de,dsgw,9,[Unbekannter Suchobjekttyp (Unknown search object type)]
+de,dsgw,10,[Unbekanntes Attributetikett (Unknown attribute label)]
+de,dsgw,11,[Unbekannte Match-Aufforderung (Unknown match prompt)]
+de,dsgw,12,[Keine Suchfilter für Objekttyp (No search filters for object type)]
+de,dsgw,13,[HTML-Vorlagedatei kann nicht gefunden werden (Unable to open HTML template file)]
+de,dsgw,14,[Unbekannter Suchmodus - benutzen Sie "smart", "complex", "pattern" oder "auth" (Unknown search mode - use "smart", "complex", "pattern", or "auth")]
+de,dsgw,15,[Unverwechselbarer Name fehlt in der URL (Distinguished Name missing in URL)]
+de,dsgw,16,[Unbekannter Bereich in der URL (sollte "base", "sub" oder "one" sein) (Unknown scope in URL (should be base, sub, or one))]
+de,dsgw,17,[Unbekannte URL oder unbekannter Fehler (Unrecognized URL or unknown error)]
+de,dsgw,18,[Ungültiges URL-Format (Bad URL format)]
+de,dsgw,19,[Interner Fehler (Internal error)]
+de,dsgw,20,[Vorlageindexdatei kann nicht geschrieben werden (Unable to write template index file)]
+de,dsgw,21,[Vorlageindexdatei kann nicht geöffnet werden (Unable to open template index file)]
+de,dsgw,22,[Verzeichnis kann nicht gelesen werden (Unable to read directory)]
+de,dsgw,23,[Fehler bei der Initialisierung von LDAP SSL (Sicherheitspfad überprüfen) (LDAP SSL initialization failed (check the security path)]
+de,dsgw,24,[Damit die Benutzer- und Gruppenformulare mit dem Verwalter-Server via SSL ausgeführt werden können, müssen Sie oder der Systemverwalter über das Formular <B>Server-Eigenschaften|Verschlüsselung EIN/AUS</B> SSL für diesen Verwaltungsserver aktivieren aktivieren.\n(For the Users and Groups forms to work over SSL, you or your server administrator needs to activate SSL for this Administration Server. The Encryption|On/Off page can be used to do so.)]
+de,dsgw,25,[Beglaubigungsberechtigung wurde nicht in der Beglaubigungsdatenbank gefunden (Authentication credentials not found in authentication database)]
+de,dsgw,26,[Fehler beim Abrufen der Daten von der Beglaubigungsdatenbank (Error retrieving data from the authentication database)]
+de,dsgw,27,[Ihre Beglaubigungsberechtigung ist abgelaufen (Your authentication credentials have expired)]
+de,dsgw,28,[Zufalls-Zeichenfolge kann nicht erstellt werden\n(Unable to create a random string)]
+de,dsgw,29,[Beim Abrufen des Berechtigungsnachweises wurde kein unverwechselbarer Name angegeben (No distinguished name was provided when retrieving credentials)]
+de,dsgw,30,[Beglaubigungsdatenbank kann nicht geöffnet werden (Cannot open authentication database)]
+de,dsgw,31,[Daten konnten nicht an die Beglaubigungsdatenbank angehängt werden (Could not append data to the authentication database)]
+de,dsgw,32,[Es wurde kein Verzeichnisverwalter definiert (No Directory Manager is defined)]
+de,dsgw,33,[Es wurde keine Suchzeichenfolge angegeben. Bitte noch einmal versuchen (No search string was provided. Please try again)]
+de,dsgw,34,[Zu viele Argumente auf einer Zeile in der Konfigurationsdatei (Too many arguments on one line in the config. file)]
+de,dsgw,35,[Windows Sockets konnte nicht initialisiert werden (Failed to initialize Windows Sockets)]
+de,dsgw,36,[Beglaubigungsberechtigung konnte nicht vom Verwaltungs-Server abgerufen werden (Authentication credentials could not be obtained from the Administration Server)]
+de,dsgw,37,[Unverwechselbarer Name fehlt in der ldapdb:// URL (Distinguished Name missing in ldapdb:// URL)]
+de,dsgw,38,[Unbekannte URL oder unbekannter Fehler (Unrecognized URL or unknown error)]
+de,dsgw,39,[Ungültiges URL-Format (Bad URL format)]
+de,dsgw,40,[Fehler beim Initialisieren der lokalen LDAP-Datenbank\n(An error occurred while initializing the local LDAP database)]
+de,dsgw,41,[Unbekannter Verzeichnis-Servicetyp - benutzen Sie "local" oder "remote" (Unknown directory service type - use "local" or "remote")]
+de,dsgw,42,[Fehler beim Lesen der db-Konfigurationdatei (An error occurred while reading the db configuration file)]
+de,dsgw,43,[NSHOME/userdb-Pfad war NULL (NSHOME/userdb path was NULL)]
+de,dsgw,44,[Die Servicekonfiguration des Verzeichnisses konnte nicht aktualisiert werden. (The directory service configuration could not be updated.)]
+de,dsgw,45,[Der Eintrag konnte nicht im Verzeichnis gelesen werden. (The entry could not be read from the directory.)]
+de,dsgw,46,[Die LDAP-Databank konnte nicht gelöscht werden. (The LDAP database could not be erased.)]
+de,dsgw,47,[Sie dürfen keine Einträge außer Ihren eigenen ändern. (You may not change entries besides your own.)]
+de,dsgw,48,[Problem]
+de,dsgw,49,[Beglaubigungsproblem (Authentication Problem)]
+de,dsgw,50,[.\n<P>Sie müssen neu beglaubigen, ehe Sie fortfahren. (You must re-authenticate before continuing.)\n]
+de,dsgw,51,[.\n<P>Sie müssen neu beglaubigen, ehe Sie fortfahren. (You must re-authenticate before continuing.)\n]
+de,dsgw,52,[unbekannter Fehler (unknown error)]
+de,dsgw,53,[Der Vorgang war erfolgreich. (The operation was successful.)]
+de,dsgw,54,[Im Server ist ein interner Fehler aufgetreten. Das deutet gewöhnlich auf einen ernsthaften Fehler im Server hin und sollte Ihrem Serververwalter mitgeteilt werden. (An internal error occurred in the server. This usually indicates a serious malfunction in the server and should be brought to the attention of your server administrator.)]
+de,dsgw,55,[Der Server konnte die durch das Gateway an ihn gesandte Anforderung nicht verstehen. (The server could not understand the request which was sent to it by the gateway.)]
+de,dsgw,56,[Das Zeitlimit wurde bei der Ausführung Ihrer Anforderung überschritten. Die Suche nach Einträgen erzielt bessere Ergebnisse, wenn Sie Ihre Suche präziser definieren. (A time limit was exceeded in responding to your request. If you are searching for entries, you may achieve better results if you are more specific in your search.)]
+de,dsgw,57,[Das Größenlimit wurde bei der Ausführung Ihrer Anforderung überschritten. Ihre Suche nach Einträgen erzielt bessere Ergebnisse, wenn Sie Ihre Suche präziser definieren, da zu viele Einträge zu Ihren Suchkriterien paßten. (A size limit was exceeded in responding to your request. If you are searching for entries, you may achieve better results if you are more specific in your search, because too many entries matched your search criteria.)]
+de,dsgw,58,[Das Gateway versuchte, mit einer Methode auf dem Server\nzu beglaubigen, die der Server nicht versteht.\n(The gateway attempted to authenticate to the server using\na method the server doesn't understand.)]
+de,dsgw,59,[Das Gateway versuchte mit einer Beglaubigungsmethode auf dem Server zu beglaubigen, die der Server nicht unterstützt. (The gateway attempted to authenticate to the server using an authentication method which the server does not support. )]
+de,dsgw,60,[Ihre Anforderung konnte nicht ausgeführt werden, weil der aufgerufene Server wahrscheinlich nicht die von Ihnen gewünschten Daten enthält. Möglicherweise wurde die Anforderung auf einen anderen Server umgeleitet und wieder zurückgesandt, konnte jedoch nicht zurückverfolgt werden. Sollten Sie versucht haben, Änderungen im Verzeichnis vorzunehmen, dann ist der Server mit der Stammkopie möglicherweise nicht verfügbar. (Your request could not be fulfilled, probably because the server that was contacted does not contain the data you are looking for. It is possible that a referral to another server was returned but could not be followed. If you were trying to make changes to the directory, it may be that the server that holds the master copy of the data is not available.)]
+de,dsgw,61,[Ihre Anforderung hat ein Verwalterlimit auf dem Server überschritten. (Your request exceeded an administrative limit in the server.)]
+de,dsgw,62,[Eine vom Gateway angeforderte kritische Erweiterung ist auf diesem Server nicht verfügbar. (A critical extension that the gateway requested is not available in this server.)]
+de,dsgw,63,[Der Server konnte die Anforderung nicht ausführen, da sie\nsich auf ein Attribut bezieht, das nicht im\nEintrag existiert.\n(The server was unable to process the request, because the\nrequest referred to an attribute which does not exist in the\nentry.)]
+de,dsgw,64,[Der Server konnte Ihre Anforderung nicht ausführen, da\nsie gegen eine Beschränkung verstößt.\n(The server was unable to fulfill your request, because the\nrequest violates a constraint.)]
+de,dsgw,65,[Der Server konnte dem Eintrag keinen Wert hinzufügen, da dieser Wert bereits im Eintrag enthalten ist. (The server could not add a value to the entry, because that value is already contained in the entry.)]
+de,dsgw,66,[Der Server konnte diesen Eintrag nicht finden. Wird ein neuer\nWert hinzugefügt, vergewissern Sie sich, daß das übergeordnete Verzeichnis,\nfür den Eintrag, den Sie hinzufügen möchten, existiert. Erscheint diese\nFehlermeldung bei einem Suchvorgang, bedeutet das,\ndaß der von Ihnen gesuchte Eintrag nicht existiert. Wenn Sie versucht\nhaben, als Verzeichnisverwalter zu beglaubigen und diese Fehlermeldung erscheint,\ndann überprüfen Sie die Gateway-Konfigurationsdatei.\n(The server could not locate the entry. If adding a new entry,\nbe sure that the parent of the entry you are trying to add exists.\nIf you received this error while searching, it indicates that the\nentry which was being searched for does not exist.\nIf you were attempting to authenticate as the directory manager and\nreceived this error, check the gateway configuration file.)]
+de,dsgw,67,[Ein unverwechselbarer Name hatte nicht das richtige Format. (A distinguished name was not in the proper format. )]
+de,dsgw,68,[Dem Eintrag, den Sie beglaubigen wollten, fehlt entweder der Kennwortsatz oder andere erforderliche Beglaubigungsberechtigungen. Mit dieser Eingabe können Sie erst beglaubigen, wenn der Verzeichnisverwalter die passenden Attribute hinzugefügt hat. (The entry you attempted to authenticate as does not have a password set, or is missing other required authentication credentials. You cannot authenticate as that entry until the appropriate attributes have been added by the directory manager.)]
+de,dsgw,69,[Das eingegebene Kennwort (oder andere Beglaubigungsberechtigungen)\nist falsch.\n(The password (or other authentication credentials) you supplied\nis incorrect.)]
+de,dsgw,70,[Sie sind nicht ausreichend berechtigt, um den Vorgang auszuführen. (You do not have sufficient privileges to perform the operation. )]
+de,dsgw,71,[Der Server ist belegt und kann Ihre Anforderung nicht ausführen. Versuchen Sie es in ein paar Miuten noch einmal. (The server is too busy to service your request. Try again in a few minutes.)]
+de,dsgw,72,[Der LDAP-Server konnte nicht aufgerufen werden. (The LDAP server could not be contacted.)]
+de,dsgw,73,[Der Server lehnt die Ausführung Ihrer Anforderung ab. Das bedeutet gewöhnlich, daß die Ausführung Ihrer Anforderung den Server zu sehr belastet. Es könnte möglicherweise auch bedeuten, daß der Server nicht konfiguriert ist, Ihre Anforderung auszuführen. Versuchen Sie, bei der Suche den Suchbereich einzuschränken. (The server was unwilling to process your request. Usually, this indicates that serving your request would put a heavy load on the server. It may also indicate that the server is not configured to process your request. If searching, you may wish to limit the scope of your search.)]
+de,dsgw,74,[Der Verzeichnis-Server konnte Ihrer Anforderung nicht nachkommen, da sie gegen die Schemabedingungen verstößt. Das bedeutet gewöhnlich, daß Sie keinen Wert für ein erforderliches Feld eingegeben haben. Es könnte auch bedeuten, daß das Schema im Verzeichnis-Server aktualisiert werden muß. (The directory server could not honor your request because it violates the schema requirements. Typically, this means that you have not provided a value for a required field. It could also mean that the schema in the directory server needs to be updated.)]
+de,dsgw,75,[Der Verzeichnis-Server läßt nicht zu, daß Sie einen Eintrag, der untergeordnet ist, löschen oder umbenennen. Um das zu tun, müssen Sie erst alle untergeordneten Einträge löschen. (The directory server will not allow you to delete or rename an entry if that entry has children. If you wish to do this, you must first delete all the child entries.)]
+de,dsgw,76,[Der Server konnte weder einen neuen Eintrag hinzufügen noch einen bestehenden umbenennen, da ein Eintrag unter diesem Namen bereits existiert. (The server was unable to add a new entry, or rename an existing entry, because an entry by that name already exists.)]
+de,dsgw,77,[Ihre Anforderung würde mehrere Verzeichnis-Server betreffen. (Your request would affect several directory servers.)]
+de,dsgw,78,[Der Verzeichnis-Server konnte nicht aufgerufen werden. Wenden\nSie sich an den Serververwalter.\n(The directory server could not be contacted. Contact your\n server administrator for assistance.)]
+de,dsgw,79,[Fehler beim Senden der Daten zum Server. (An error occured while sending data to the server.)]
+de,dsgw,80,[Fehler beim Lesen der Daten vom Server. (An error occured while reading data from the server.)]
+de,dsgw,81,[Der Server hat nicht auf Ihre Anforderung reagiert. Die Anforderung wurde unterbrochen. (The server did not respond to the request. The request timed out.)]
+de,dsgw,82,[Der Server unterstützt nicht die vom Gateway benutzte Beglaubigungsmethode. (The server does not support the authentication method used by the gateway.)]
+de,dsgw,83,[Der vom Gateway erstellte Suchfilter war falsch. (The search filter constructed by the gateway was in error.)]
+de,dsgw,84,[Der Vorgang wurde auf Ihren Wunsch abgebrochen. (The operation was cancelled at your request.)]
+de,dsgw,85,[Interner Fehler in der Bibliothek - ein Parameter war falsch. (An internal error occurred in the library - a parameter was incorrect.)]
+de,dsgw,86,[Verbindung zum Verzeichnis-Server konnte nicht hergestellt werden. Wenden\nSie sich an Ihren Server-Verwalter.\n(A connection to the directory server could not be opened. Contact your\nserver administrator for assistance.)]
+de,dsgw,87,[Unbekannter Fehler aufgetreten. (An unknown error was encountered.)]
+de,dsgw,88,[Eintrag existiert bereits (Entry Already Exists)]
+de,dsgw,89,[Dieser Namenseintrag (An entry named )]
+de,dsgw,90,[onMouseOver="window.status='Klicken Sie hier, um den Eintrag einzusehen'; return true"\n(onMouseOver="window.status='Click here to view this entry'; return true")]
+de,dsgw,91,[ existiert bereits (already exists).<P>Bitte anderen Namen und/oder Adresse wählen.\n(Please choose another name and/or location.\n<P>)\n]
+de,dsgw,92,[Übergeordneter Eintrag existiert nicht\n(Parent entry does not exist)]
+de,dsgw,93,[Sie können einen Eintrag unter diesem Namen:\n(You cannot add an entry by the name:)<P><B>%s</B>,<P> nicht hinzufügen,\nda der übergeordnete Eintrags nicht existiert.\n(because the parent of that entry does not exist.)<P>\nEhe Sie diesen Eintrag hinzufügen, müssen Sie zunächst den dazugehörige\n(Before you can add this entry, you must first add)\n]
+de,dsgw,94,[übergeordneten Eintrag hinzufügen. (its parent.)\n]
+de,dsgw,95,[ein Eintrag unter diesem Namen (an entry named):<P><B>%s</B>.\n]
+de,dsgw,96,[Warnung: Keine Beglaubigung (wird fortgesetzt)...\n(Warning: no authentication (continuing)...)\n]
+de,dsgw,97,[%s Verzeichniseintrag (Directory Entry)]
+de,dsgw,98,[<PRE>Eingabe-DN (Entry DN): %s</PRE><P>\n]
+de,dsgw,99,[Änderungen zu <B>%s</B> wurden gespeichert.]
+de,dsgw,100,[<B>%s</B> has been added.]
+de,dsgw,101,[<B>%s</B> has been deleted.]
+de,dsgw,102,[Renamed <B>%s</B> to <B>%s</B>.]
+de,dsgw,103,[<P><B>Hinweis:</B> Da Sie den Eintrag, unter dem Sie beglaubigt\nsind, %s haben, mußte Ihre Beglaubigungsberechtigung\ngelöscht werden. Sie müssen neu beglaubig werden, um\nweitere Änderungen vornehmen zu können.\n(<B>Note:</B> because of your action on the entry you were \nauthenticated as, it was necessary to discard your \nauthentication credentials. You will need to authenticate \nagain to make additional changes.)\n]
+de,dsgw,104,[gelöscht (deleted)]
+de,dsgw,105,[umbenannt (renamed)]
+de,dsgw,106,[Kennwort umbenannt für (changed the password of)]
+de,dsgw,107,[Attribut (Attribute) %s wurde geändert (was changed)<BR>\n]
+de,dsgw,108,[ NICHT (NOT) ASCII (%ld Bytes)\n]
+de,dsgw,109,[Es wurden keine Werte eingegeben. Bitte erneut versuchen.\n(No values were entered. Please try again.)\n]
+de,dsgw,110,[Es wurden keine Änderungen vorgenommen.\n]
+de,dsgw,111,[<P>%s wird an Verzeichnis-Server gesendet...\n]
+de,dsgw,112,[Information]
+de,dsgw,113,[Änderungen (changes)]
+de,dsgw,114,[<P>Eintrag erfolgreich hinzugefügt.\n(Successfully added entry.)\n]
+de,dsgw,115,[<P>Eintrag erfolgreich bearbeitet. Änderungen wurden gespeichert.\n(Successfully edited entry. Your changes have been saved.)\n]
+de,dsgw,116,[<P>Eintrag erfolgreich gelöscht.\n(Successfully deleted entry.)\n]
+de,dsgw,117,[<PRE>Der neue Eintrag heißt (The new name for the entry is): %s\n</PRE><HR>\n]
+de,dsgw,118,[<P>Eintrag erfolgreich umbenannt.\n(Successfully renamed entry.)\n]
+de,dsgw,119,[Sie müssen das alte Kennwort angeben.]
+de,dsgw,120,[Sie müssen ein neues Kennwort angeben. Bitte erneut versuchen]
+de,dsgw,121,[Neues und bestätigendes Kennwort stimmen nicht überein. Bitte erneut versuchen]
+de,dsgw,122,[<BR>%s <B>%s</B> ist bereits in Benutzung. Bitte ein anderes wählen.\n(The item shown is already in use. Please choose a different one.)<BR>\n]
+de,dsgw,123,[fehlendes Formulardatenelement (missing form data element) "%.100s"]
+de,dsgw,124,[Konfigurationsinformation wird initialisiert\n(Initializing config info)]
+de,dsgw,125,[Datei kann nicht geöffnet werden.\n(Cannot open file.)]
+de,dsgw,126,[ Konfigurationsdate der Datenbanki ist verstümmelt.\n(Malformed dbconf file.)]
+de,dsgw,127,[Eigenschaftsname in der Konfigurationsdatei der Datenbank fehlt.\n(Missing property name in dbconf file.)]
+de,dsgw,128,[Nicht genügend Arbeitspeicher. (Out of memory.)]
+de,dsgw,129,[Betriebsanweisung in der Konfigurationsdatei der Datenbank fehlt.\n(Missing directive in dbconf file.)]
+de,dsgw,130,[Konfigurationsdatei "%s" kann nicht geöffnet werden\n(Cannot open config file with name shown)\n]
+de,dsgw,131,[Argument für die Betriebsanweisung "authlifetime" fehlt\n(Missing argument for "authlifetime" directive)\n]
+de,dsgw,132,[Argument für Betriebsanweisung "dirmgr" fehlt\n(Missing argument for "dirmgr" directive)\n]
+de,dsgw,133,[Argument für Betriebsanweisung "baseurl" fehlt\n(Missing argument for "baseurl" directive)\n]
+de,dsgw,134,[Falsche URL für Betriebsanweisung "baseurl" angegeben - Basis-DN fehlt\n(Bad URL provided for "baseurl" directive - the base DN is missing)\n]
+de,dsgw,135,[Betriebsanweisung "baseurl" wird analysiert\n(parsing baseurl directive)]
+de,dsgw,136,[Falsche URL für Betriebsanweisung "baseurl" angegeben - keine "ldap://" URL\n(Bad URL provided for "baseurl" directive - not an "ldap://" URL)\n]
+de,dsgw,137,["ldaps://" URLs werden noch nicht unterstützt\n("ldaps://" URLs are not yet supported)\n]
+de,dsgw,138,[Argumente für Betriebsanweisung "template" fehlen\n(Missing arguments for "template" directive)\n]
+de,dsgw,139,[Argument für Betriebsanweisung "sslrequired" fehlt\n(Missing argument for "sslrequired" directive)\n]
+de,dsgw,140,[Unbekanntes Argument für Betriebsanweisung "sslrequired" (muß "never", "whenauthenticated"oder "always" sein)\n(Unknown argument to "sslrequired" directive (should be "never", "whenauthenticated", "always"))\n]
+de,dsgw,141,[Argument für Betriebsanweisung "securitypath" fehlt\n(Missing argument for "securitypath" directive)\n]
+de,dsgw,142,[Argument für Betriebsanweisung "location-suffix" fehlt\n(Missing argument for "location-suffix" directive)\n]
+de,dsgw,143,[Die Betriebsanweisung "location" erfordert drei Argumente\n(Three arguments are required for the "location" directive)\n]
+de,dsgw,144,[Die Betriebsanweisung "newtype" erfordert mindestens zwei Argumente\n(At least two arguments are required for the "newtype" directive)\n]
+de,dsgw,145,[Unbekannte Adresse in der Betriebsanweisung "newtype"\n(Unknown location in "newtype" directive)\n]
+de,dsgw,146,[Die Betriebsanweisung "tmplset" erfordert drei oder vier Argumente\n(Three or four arguments are required for the "tmplset" directive)\n]
+de,dsgw,147,[Die Betriebsanweisung "attrvset" erfordert vier Argumente\n(Four arguments are required for the "attrvset" directive)\n]
+de,dsgw,148,[Argument für Betriebsanweisung "charset" fehlt\n(Missing argument for "charset" directive)\n]
+de,dsgw,149,[Argument für Betriebsanweisung "ClientLanguage" fehlt\n(Missing argument for "ClientLanguage" directive)\n]
+de,dsgw,150,[Argument für Betriebsanweisung "AdminLanguage" fehlt\n(Missing argument for "AdminLanguage" directive)\n]
+de,dsgw,151,[Argument für Betriebsanweisung "DefaultLanguage" fehlt\n(Missing argument for "DefaultLanguage" directive)\n]
+de,dsgw,152,[Dateiname für Betriebsanweisung "include" fehlt\n(Missing filename for "include" directive)\n]
+de,dsgw,153,[Unbekannte Betriebsanweisung in der Konfigurationsdatei\n(Unknown directive in config file)\n]
+de,dsgw,154,[<= erase_db konnte lcache.conf-Datei "%s" nicht öffnen\n(<= erase_db could not open lcache.conf file with name shown)\n]
+de,dsgw,155,[<FONT SIZE="+1">\n<P>Die Datenbank wurde gelöscht. Neue Datenbank wird erstellt...\n(The database has been deleted. Creating new database...)\n</FONT>\n ]
+de,dsgw,156,[<FONT SIZE="+1">\n<P>Die Datenbank konnte nicht gelöscht werden\n(The database could not be deleted)\n</FONT>\n ]
+de,dsgw,157,[<= app_suffix konnte ldif-Datei "%s" nicht öffnen\n(<= app_suffix could not open ldif file with name shown)\n]
+de,dsgw,158,[<= app_suffix konnte tmp-Datei "%s" nicht öffnen\n(<= app_suffix could not open tmp file with name shown)\n]
+de,dsgw,159,[%s konnte nicht in %s umbenannt werden\n(Unable to rename with names as shown)]
+de,dsgw,160,[Leerzeiger wurde von dbconf_read_default_dbinfo() zurückgegeben.\n(null pointer returned by dbconf_read_default_dbinfo().)]
+de,dsgw,161,[Falsche "ldapdb"-URL - Basis-DN fehlt\n(Bad "ldapdb" URL - the base DN is missing)\n]
+de,dsgw,162,[Falsche "ldapdb"-URL (Bad "ldapdb" URL)\n]
+de,dsgw,163,[Falsche URL für Betriebsanweisung "baseurl" angegeben - Basis-DN fehlt \n(Bad URL provided for "baseurl" directive - the base DN is missing)\n]
+de,dsgw,164,[Betriebsanweisung "baseurl" wird analysiert\n(parsing baseurl directive)]
+de,dsgw,165,[Falsche URL für Betriebsanweisung "baseurl" angegeben - keine "ldap:// bzw. ldapdb://" URL\n(Bad URL provided for "baseurl" directive - not an "ldap:// or ldapdb://" URL)\n]
+de,dsgw,166,["ldaps://" URLs werden noch nicht unterstützt\n("ldaps://" URLs are not yet supported)\n]
+de,dsgw,167,[Kein Wert für binddn angegeben\n(No value given for binddn)]
+de,dsgw,168,[Kein Wert für bindpw angegeben\n(No value given for bindpw)]
+de,dsgw,169,[In der dbswitch.conf-Datei ist kein Standard-Verzeichnisservice angegeben\n(There is no default directory service defined in the dbswitch.conf file)]
+de,dsgw,170,[Konfigurationsdatei "%s" kann nicht zum Schreiben geöffnet werden\n(Cannot open config file with name shown for writing)\n]
+de,dsgw,171,[Kann %s nicht in %s umbenennen\n(Unable to rename with names as shown)]
+de,dsgw,172,[Konfigurationsdatei (config file) %s: ]
+de,dsgw,173,[Konfigurationsdatei (config file) %s: Zeile (line) %d: ]
+de,dsgw,174,[Max. (max) %d]
+de,dsgw,175,[ OK ]
+de,dsgw,176,[Fenster schließen (Close Window)]
+de,dsgw,177,[Zurück]
+de,dsgw,178,[{crypt}GESPERRT (LOCKED) [%s GMT]]
+de,dsgw,179,[Zurück zum Hauptbildschirm (Return to Main)]
+de,dsgw,181,[ Help ]
+de,dsgw,182,[Hilfe (Help)]
+de,dsgw,184,[Hilfe ist noch nicht verfügbar.\n(Help is not yet available.)]
+de,dsgw,186,[Fenster schließen (Close Window)]
+de,dsgw,187,[Fenster schließen (Close Window)]
+de,dsgw,188,[?template fehlt (missing ?template)]
+de,dsgw,189,[Beglaubigen...(Authenticate...)]
+de,dsgw,190,[Beglaubigungsberechtigung löschen (abmelden)?\n(Discard authentication credentials (log out)?)]
+de,dsgw,191,[Geben Sie eine Suchenzeichenfolge an\n(Please type a search string)]
+de,dsgw,192,[Um Ihren Zugriff zu dem Verzeichnis zu beglaubigen, müssen Sie sich zunächst zu\nerkennen geben.<br>Geben Sie Ihren Namen ein:\n(The first step in authenticating to the directory is identifying\nyourself.<br>Please type your name:)]
+de,dsgw,193,[Weiter (Continue)]
+de,dsgw,194,[Weiter (Continue)]
+de,dsgw,195,[Abbrechen (Cancel)]
+de,dsgw,196,[Als Verzeichnisverwalter beglaubigen"> &nbsp;(nur für Verzeichnis-Administratoren verfügbar)\n(Authenticate as directory manager"> &nbsp;(only available to Directory Administrators))\n]
+de,dsgw,197,[Beglaubigen...(Authenticate...)]
+de,dsgw,198,[Beglaubigungsberechtigung löschen? (Discard authentication credentials?)]
+de,dsgw,200,[Weiter (Continue)]
+de,dsgw,201,[Weiter (Continue)]
+de,dsgw,202,[Abbrechen (Cancel)]
+de,dsgw,203,[Zugriff zu dem Verzeichnis beglaubigen (anmelden)\n(Authenticate (log in) to the directory)]
+de,dsgw,204,[Ihr Zugriff zu dem Verzeichnis wird gleich beglaubigt werden unter \n(You are about to authenticate to the directory as) <B>%s</B>. Geben Sie zum Vervollständigen des Beglaubigungsvorgangs Ihr Kennwort ein. (To complete the authentication process, type your password.\n]
+de,dsgw,206,[Ehe Sie Einträge bearbeiten bzw. hinzufügen können, muß\nIhr Zugriff zu dem Verzeichnis beglaubigt (angemeldet) sein\n. Folgen Sie den Anweisungen für den Beglaubigungsprozeß\nauf diesem Fenster.\n(Before you can edit or add entries, you must authenticate\n(log in) to the directory. This window will guide\nyou through the steps of the authentication\nprocess.)\n]
+de,dsgw,207,[Ihr Zugriff zu dem Verzeichnis kann von diesem Bildschirm aus\nbeglaubigt bzw. angemeldet werden.\nSie müssen beglaubigt sein, ehe Sie Verzeichniseinträge\nändern können. Wenn Sie einen Eintrag, ohne beglaubigt zu sein, ändern möchten, dann werden Sie aufgefordert, sich anzumelden.\n(From this screen you may authenticate, or log in, \nto the directory. You will need to authenticate\nbefore you can modify directory entries. If you\nattempt to modify an entry without authenticating,\nyou will be asked to log in.)\n]
+de,dsgw,208,[Beglaubigungsstatus(Authentication Status)]
+de,dsgw,209,[<form>\nIhr Zugriff zu dem Verzeichnis ist derzeitig beglaubigt unter \n(<form>\nYou are currently authenticated to the directory as )]
+de,dsgw,210,[.\nWenn Sie Ihre Beglaubigungsberechtigung löschen und sich vom Verzeichnis abmelden möchten, klicken Sie unten auf die Schaltfläche.\n(.\nIf you wish to discard your authentication credentials and log out of the directory, click on the button below.)]
+de,dsgw,211,[Beglaubigungsberechtigung löschen (abmelden)\n(Discard Authentication Credentials (log out))]
+de,dsgw,212,[Ihre Beglaubigungsberechtigung für \n(Your authentication credentials for )]
+de,dsgw,213,[ist abgelaufen (have expired).\n<HR>)\n]
+de,dsgw,214,[Ihr Zugriff zu dem Verzeichnis ist derzeitig nicht beglaubigt.\n(Currently, you are not authenticated to the directory.<HR>)\n]
+de,dsgw,215,["%s=" fehlt (missing)]
+de,dsgw,216,["%s=%s" unbekannt (unknown)]
+de,dsgw,217,[unbekannte Option (unknown option) %s ]
+de,dsgw,218,[unbekannte Syntax=%s (syntax shown unknown)\n]
+de,dsgw,219,[** HTML-Typ "%s" nicht unterstützt **<BR>\n(** HTML type shown is not supported **<BR>)\n]
+de,dsgw,224,[Bearbeiten (Edit)]
+de,dsgw,225,[Save Changes]
+de,dsgw,226,[modify]
+de,dsgw,227,[add]
+de,dsgw,228,[Löschen (Delete)]
+de,dsgw,229,[Diesen Eintrag löschen? (Delete this entry?)]
+de,dsgw,230,[Umbenennen (Rename)]
+de,dsgw,231,[Neuen Namen für diesen Eintrag eingeben:\n(Enter a new name for this entry:)]
+de,dsgw,232,[Bearbeiten unter (Edit As)]
+de,dsgw,233,[%s= fehlt (missing)]
+de,dsgw,234,[Fenster schließen (Close Window)]
+de,dsgw,235,[Bearbeiten... (Edit...)]
+de,dsgw,236,["%s=" fehlt (missing)\n]
+de,dsgw,237,[Unbekannter Satz "%s" (set shown is unknown)\n]
+de,dsgw,238,[unbekannte Syntax "%s" (unknown syntax "%s")\n]
+de,dsgw,239,[Neu beglaubigen (Re-Authenticate)]
+de,dsgw,240,[Fenster schließen (Close Window)]
+de,dsgw,241,[Möchten Sie wirklich (Do you really want to )]
+de,dsgw,242,[?]
+de,dsgw,243,[ OK ]
+de,dsgw,244,[ OK ]
+de,dsgw,245,[Zurücksetzen (Reset)]
+de,dsgw,246,[Beendet (Done)]
+de,dsgw,247,[Abbrechen (Cancel)]
+de,dsgw,248,[anderes IF gefunden (geschachtelte IFs sind nicht unterstützt)\n(found another IF (nested IFs are not supported))]
+de,dsgw,249,[ELSE wurde gefunden, aber kein IF\n(found ELSE but didn't see an IF)]
+de,dsgw,250,[ELSE nach ELSE gefunden (ENDIF erwartet)\n(found ELSE after ELSE (expecting ENDIF))]
+de,dsgw,251,[ELSE wurde gefunden, aber kein IF\n(found ELIF but didn't see an IF)]
+de,dsgw,252,[ELIF nach ELSE gefunden (ENDIF erwartet)\n(found ELIF after ELSE (expecting ENDIF))]
+de,dsgw,253,[ELDIF wurde gefunden, aber kein IF\n(found ENDIF but didn't see an IF)]
+de,dsgw,254,[<BR><B>Vorlagefehler (template error):</B> %s<BR>\n]
+de,dsgw,255,[ldap_init/lcache_init aufgerufen, ehe Konfigurationsdatei gelesen wurde\n(ldap_init/lcache_init attempted before config file read)]
+de,dsgw,256,[führt nicht unter dem Verwaltungs-Server aus\n(not running under the administration server)]
+de,dsgw,257,[Konnte Genehmigungen nicht initialisieren\n(Could not initialize permissions)]
+de,dsgw,258,[Konnte Benutzername nicht auf einem DN abbilden (Fehler vom Verwaltungs-Server)\n(Could not map username to a DN (error from admin server))]
+de,dsgw,259,[Konnte aktuellen Benutzernamen nicht aufrufen\n(Could not get current username)]
+de,dsgw,260,[Konnte aktuelles Benutzerkennwort nicht abrufen\n(Could not get current user password)]
+de,dsgw,261,[Fehler (Error): %s]
+de,dsgw,262,[Hinweis: Für diese Art von Eintrag gibt es keine Anzeigevorlage; die Eintragsart \nwird unten\nim Standarmodus angezeigt.\n(Note: there is no display template for this type of entry available, so it is\ndisplayed below using a default method.)]
+de,dsgw,263,[Ungültige Benutzer-ID bzw. NULL LDAP-Erkennung\n(Invalid user id or NULL LDAP handle)]
+de,dsgw,264,[keine Übereinstimmung mit Benutzer-ID\n(no match for user id)]
+de,dsgw,265,[mehr als eine Übereinstimmung mit Benutzer-ID\n(more than one match for user id)]
+de,dsgw,266,[the entire directory]
+de,dsgw,267,[Die Betriebsanweisung "includeset" erfordert zwei Argumente\n(Two arguments are required for the "includeset" directive)\n]
+de,dsgw,268,[Der angeforderte Attributwert wurde im Eintrag nicht gefunden (The attribute value requested was not found in the entry)]
+de,dsgw,269,[Argument fehlt in der "NLS"-Betriebsanweisung\n]
+de,dsgw,270,[Es muß ein NT-Benutzername angegeben werden]
+de,dsgw,271,[Die Kombination aus NT-Benutzernamen und NT-Domäne ist in diesem Verzeichnis nicht eindeutig\n]
+de,dsgw,272,[Es muß sowohl ein NT-Benutzername als auch eine NT-Domäne angegeben werden\n]
+de,dsgw,273,[Der NT-Benutzername darf nicht länger sein als 20 Zeichen.]
+de,dsgw,274,[Namen für den neuen Eintrag angeben.]
+de,dsgw,275,[Standort für den neuen Eintrag auswählen.]
+de,dsgw,276,[Neuer Eintrag]
+de,dsgw,277,[Für diese Funktion muß ein Verzeichnisverwalter in der Datei "dsgw.conf" definiert sein]
+de,dsgw,278,[Die Betriebsanweisung "vcard-property" erfordert drei oder vier Argumente.\n]
+de,dsgw,279,[DieVCard-Eigenschaft kann nur entweder "cis" oder "mls" lauten.\n]
+de,dsgw,280,[Kein Eintrag gefunden.\n%2$s]
+de,dsgw,281,[Kein Eintrag gefunden, in dem %2$s '%4$s' %3$s.\n]
+de,dsgw,282,[Kein Eintrag gefunden.\n%2$s]
+de,dsgw,283,[Kein Eintrag gefunden, in dem %2$s '%4$s' %3$s.\n]
+de,dsgw,284,[1 Eintrag gefunden.\n%2$s]
+de,dsgw,285,[1 Eintrag gefunden, in dem %2$s '%4$s' %3$s.\n]
+de,dsgw,286,[1 Eintrag gefunden.\n%2$s]
+de,dsgw,287,[1 Eintrag gefunden, in dem %2$s '%4$s' %3$s.\n]
+de,dsgw,288,[%1$li Einträge gefunden.\n%2$s]
+de,dsgw,289,[%1$li Einträge gefunden, in denen %2$s '%4$s' %3$s.\n]
+de,dsgw,290,[%1$li Einträge gefunden.\n%2$s]
+de,dsgw,291,[%1$li Einträge gefunden, in denen %2$s '%4$s' %3$s.\n]
+de,dsgw,292,[der LDAP-Filter ist]
+de,dsgw,293,[Der Server konnte den Eintrag, den Sie bei der Beglaubigung verwendet haben, nicht finden. Möglicherweise wurde der Eintrag umbenannt oder gelöscht. Bitte wiederholen Sie die Beglaubigung.]
+de,dsgw,294,[Die neue Kennwortsyntax ist ungültig.\n]
+de,dsgw,295,[Das neue Kennwort ist in der Kennwortchronik enthalten.\n]
+de,dsgw,296,[Sie haben den Grenzwert für die Wiederholung des Kennworts überschritten. Bitte wenden Sie sich an den Systemverwalter.\n]
+de,dsgw,297,[Sie haben den Grenzwert für die Wiederholung des Kennworts überschritten. Versuchen Sie es später erneut.\n]
+de,dsgw,298,[Das Kennwort ist abgelaufen. Wenden Sie sich an den Systemverwalter, um das Kennwort zurückzusetzen.\n]
+de,frame,-1,[$DBT: frame in DB file v1 $]
+de,frame,1,[<TITLE>Nicht gefunden (Not Found)</TITLE><H1>Nicht gefunden (Not Found)</H1> Das angeforderte Objekt existiert nicht auf diesem Server. Die von Ihnen verfolgte Verknüpfung ist entweder veraltet, ungenau oder der Server darf sie Ihnen nicht anbieten.\n(The requested object does not exist on this server. The link you followed is either outdated, inaccurate, or the server has been instructed not to let you have it.)]
+de,frame,2,[Informieren Sie bitte den Standortverwalter über die <A HREF="%s">, Bezugsseite </A>.\n(Please inform the site administrator of the referring page.)]
+de,frame,3,[Ihr Browser sandte eine Anforderung, die dieser Proxy-Server nicht verstehen kann.\n(Your browser sent a request that this proxy could not understand.)]
+de,frame,4,[Ordnungsgemäße Genehmigung ist für den Administrator dieses Proxy-Servers erforderlich.\nEntweder führt Ihr Browser keine Genehmigung aus oder Ihre Genehmigung ist falsch.\n(Proper authorization is required for the administration of this proxy.\nEither your browser does not perform authorization, or your authorization\nhas failed.)]
+de,frame,5,[Beglaubigung des Benutzernamens ist erforderlich, um diesen Proxy-Server zu benutzen.\n Entweder führt Ihr Browser keine Proxy-Genehmigung aus oder Ihre Genehmigung ist falsch.\n(Username authentication is required for using this proxy.\nEither your browser does not perform proxy authorization, or your\nauthorization has failed.)]
+de,frame,6,[Die Zugriffssteuerungskonfiguration des Proxy-Servers verweigert\nZugriff auf das durch diesen Proxy-Server angeforderte Objekt.\n(The proxy's access control configuration denies access to\nthe requested object through this proxy.)]
+de,frame,7,[Im Proxy-Server ist ein interner Fehler aufgetreten, so daß Ihre\nAnforderung nicht ausgeführt werden kann. Wahrscheinlich ist die Konfiguration falsch.\nBitten Sie den Administrator, nach entsprechenden Hinweisen im Fehlerprotokoll des Proxy-Servers zu suchen.\n(The proxy has encountered an internal error which prevents it from\nfulfilling your request. The most likely cause is a misconfiguration.\nPlease ask the administrator to look for messages in the proxy's error log.)]
+de,frame,8,[Dieser Proxy-Server setzt nicht die angeforderte Methode ein.\n(This proxy server does not implement the requested method.)]
+de,frame,9,[Ein Fehler ist auf dem Proxy-Server aufgetreten.\n(An error has occurred on the proxy server.)]
+de,frame,10,[Dieser Server konnte die gesendete Anfrage Ihres Browsers nicht verstehen.\n(Your browser sent a query this server could not understand.)]
+de,frame,11,[Ordnungsgemäße Genehmigung ist für diesen Bereich erforderlich. Entweder führt Ihr Browser keine Genehmigung aus oder Ihre Genehmigung ist falsch.\n(Proper authorization is required for this area. Either your browser does not perform authorization, or your authorization has failed.)]
+de,frame,12,[Ihr Client darf das angeforderte Objekt nicht abrufen.\n(Your client is not allowed to access the requested object.)]
+de,frame,13,[In diesem Server ist ein interner Fehler aufgetreten, so daß Ihre Anforderung nicht ausgeführt werden kann. Wahrscheinlich ist die Konfiguration falsch. Bitten Sie den Administrator, nach entsprechenden Hinweisen im Fehlerprotokoll des Proxy-Servers zu suchen.\n(This server has encountered an internal error which prevents it from fulfilling your request. The most likely cause is a misconfiguration. Please ask the administrator to look for messages in the server's error log.)]
+de,frame,14,[Dieser Server setzt nicht die angeforderte Methode ein.\n(This server does not implement the requested method.)]
+de,frame,15,[Ein Fehler ist aufgetreten.\n(An error has occurred.)]
+de,frame,16,[Dieser Server konnte die gesendete Meldung Ihres Browsers nicht verstehen.\n(Your browser sent a message this server could not understand.)]
+de,frame,17,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="de"><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>\nDieses Dokument wurde an einen neuen <a href="%s">Standort verschoben</a>. Aktualisieren Sie bitte Ihre Dokumente und Hotlisten entsprechend.(This document has moved to a new location. Please update your documents and hotlists accordingly.)</BODY></HTML>\n]
+de,frame,18,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="de"><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>]
+de,frame,19,[process-uri-objects]
+de,frame,20,[cannot find template %s]
+de,frame,21,[process-uri-objects]
+de,frame,22,[no partial path after object processing]
+de,frame,23,[find-service]
+de,frame,24,[invalid shexp %s]
+de,frame,25,[find-service]
+de,frame,26,[invalid shexp %s]
+de,frame,27,[handle-processed]
+de,frame,28,[no way to service request for %s]
+de,frame,29,[finish-socks-request]
+de,frame,30,[close failed (%s), csd=%d]
+de,frame,31,[This beta software has expired.\n]
+de,frame,32,[mr_accept(%d)]
+de,frame,33,[Error issuing read on accept socket]
+de,frame,34,[acb_accept_connection(%d)]
+de,frame,35,[Error getting accept socket (%d)]
+de,frame,36,[Error in accept! (%d, %s)]
+de,frame,37,[Error creating new accept request]
+de,frame,38,[accepted connection: %d (NSPR %d)]
+de,frame,39,[Error creating new session structure]
+de,frame,40,[accel_read_request()]
+de,frame,41,[Error allocating request read buffer]
+de,frame,42,[Error issuing async read request]
+de,frame,43,[acb_read_request(%d, bytes %d)]
+de,frame,44,[acb_read_req(1 session = %d)]
+de,frame,45,[Error reading request (%d, %s)]
+de,frame,46,[Client aborted connection]
+de,frame,47,[Error reading request]
+de,frame,48,[Error creating new request]
+de,frame,49,[error occurred, closing %d, io was for %d]
+de,frame,50,[accel_async_scan_headers()]
+de,frame,51,[out of memory: accel_async_scan_headers]
+de,frame,52,[out of memory: accel_async_scan_headers]
+de,frame,53,[Error during async read (%d, %s)]
+de,frame,54,[scan-headers reports: line too long]
+de,frame,55,[scan-headers reports: too many headers]
+de,frame,56,[Error reading headers]
+de,frame,57,[scan-headers reports: header missing terminator (an empty line)]
+de,frame,58,[scan-headers reports: header was empty]
+de,frame,59,[Name ohne Wert: Zeile "%s" erhalten\n(name without value: got line as shown)]
+de,frame,60,[accel_send_plain_file()]
+de,frame,61,[accel_send_plain_file() - found request %d]
+de,frame,62,[Parse headers lost the URI!]
+de,frame,63,[accel_send_plain_file() - found uri %s]
+de,frame,64,[accel_send_plain_file() - found in cache?]
+de,frame,65,[malloc died!]
+de,frame,66,[Error writing back file\n]
+de,frame,67,[acb_send_plain_file(%d)]
+de,frame,68,[Error writing in acb_send_plain_file (%d, %s)]
+de,frame,69,[acb_close_connection(%d)]
+de,frame,70,[Errored IO in acb_close_connection (%d, %s)]
+de,frame,71,[Unable to close socket %d]
+de,frame,72,[accel-cache-insert: Error allocating entry]
+de,frame,73,[cache-init: server cache disabled]
+de,frame,74,[accel_file_cache: Error initializing file cache]
+de,frame,75,[accel_file_cache: Error creating cache]
+de,frame,76,[accel_file_cache_init: CacheHashSize < %d, using %d]
+de,frame,77,[accel_file_cache_init: CacheHashSize > %d, using %d]
+de,frame,78,[accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d]
+de,frame,79,[accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d]
+de,frame,80,[accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d]
+de,frame,81,[accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d]
+de,frame,82,[accel_file_cache: Error initializing file cache]
+de,frame,83,[file-cache: enabled = %s ]
+de,frame,84,[on]
+de,frame,85,[off]
+de,frame,86,[file-cache: MaxNumberOfCachedFiles %d (0x%x)]
+de,frame,87,[file-cache: CacheHashSize %d (0x%x)]
+de,frame,88,[file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)]
+de,frame,89,[accel-cache-insert: Error allocating entry]
+de,frame,90,[file-cache-cleanup: munmap failed (%s)]
+de,frame,91,[file-cache-cleanup: found mmapped file \non system without mmap]
+de,frame,92,[file_cache_init: MaxTotalCachedFileSize < %d, using %d]
+de,frame,93,[file_cache_init: MaxTotalCachedFileSize > %d, using %d]
+de,frame,94,[file cache using mmap flags 0x%x]
+de,frame,95,[file cache using mmap prots 0x%x]
+de,frame,96,[file-cache-init: could not create lock]
+de,frame,97,[file-cache: unable to create temporary directory %s.\n]
+de,frame,98,[file-cache: unable to create temporary directory %s.\n]
+de,frame,99,[file-cache: GetTempPath() Cannot find temp directory to store file!]
+de,frame,100,[file-cache-init: set max cached file size to %d]
+de,frame,101,[file-cache-init: could not create lock]
+de,frame,102,[file_cache_destroy()]
+de,frame,103,[file-cache: Unable to get temp file name. Error %s]
+de,frame,104,[file-cache: Unable to get temp file name. Error %s]
+de,frame,105,[file-cache-insert: Error allocating entry]
+de,frame,106,[file-cache-create: Error opening file %s (%s)]
+de,frame,107,[file-cache-create: Error stat()ing file %s (%s)]
+de,frame,108,[file-cache-create: Error mmap()ing file %s (%s)]
+de,frame,109,[file-cache-create: malloc failure]
+de,frame,110,[file-cache-create: error case failed to munmap(%d, %d) (%s)]
+de,frame,111,[file-cache-valid: cannot stat %s]
+de,frame,112,[dir change: invalidating %s (%d)]
+de,frame,113,[file-cache: asynchronous file change notification failed.]
+de,frame,114,[dir change: offset %d, action %d, len %d, name %s]
+de,frame,115,[unable to check async file status]
+de,frame,116,[ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s]
+de,frame,117,[file-cache-add-watch failure- unable to open directory %s. Error %s]
+de,frame,118,[ReadDirectoryChangesW failure- unable to start watching %s. Error %s]
+de,frame,119,[func_exec]
+de,frame,120,[no handler function given for directive]
+de,frame,121,[func_exec]
+de,frame,122,[cannot find function named %s]
+de,frame,123,[handle-request]
+de,frame,124,[method without URI]
+de,frame,125,[http-parse-request]
+de,frame,126,[while scanning HTTP headers, %s]
+de,frame,127,[handle-request]
+de,frame,128,[read from %s failed, error is %s]
+de,frame,129,[handle-request]
+de,frame,130,[request too long]
+de,frame,131,[start-http-response]
+de,frame,132,[write failed (%s)]
+de,frame,133,[start-http-response]
+de,frame,134,[write failed (%s)]
+de,frame,135,[http-status]
+de,frame,136,[%d is not a valid HTTP status code]
+de,frame,137,[finish-request]
+de,frame,138,[close failed (%s)]
+de,frame,139,[Unable to close socket for writing]
+de,frame,140,[os has %d objects]
+de,frame,141,[obj %d has no hash table at %d]
+de,frame,142,[obj %d has no param]
+de,frame,143,[obj %d name %s value %s]
+de,frame,144,[.....directives %d.......]
+de,frame,145,[.....directive %d]
+de,frame,146,[.......instance %d]
+de,frame,147,[...........param name %s value %s]
+de,frame,148,[ClearConfigurationParameters:RegCreateKey %s]
+de,frame,149,[ClearConfigurationParameters:RegEnumKey %s failed]
+de,frame,150,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+de,frame,151,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+de,frame,152,[Unable to allocate Subject property list.\n]
+de,frame,153,[Unable to set session ptr in Subject property list - error=%d\n]
+de,frame,154,[Unable to set request ptr in Subject property list - error=%d\n]
+de,frame,155,[file-cache-valid: cannot stat %s]
+de,frame,156,[file-cache-create: Error stat()ing file %s (%s)]
+de,httpdaemon,-1,[$DBT: httpdaemon in DB file v1 $]
+de,httpdaemon,1,[Error in ConvertThreadToFiber]
+de,httpdaemon,2,[Error in ConvertThreadToFiber]
+de,httpdaemon,3,[Error in md_start_system]
+de,httpdaemon,4,[Error in CreateFiber - idlefiber]
+de,httpdaemon,5,[Error in GetQueuedCompletionStatus]
+de,httpdaemon,6,[Error creating completion port]
+de,httpdaemon,7,[Could not SetHandleNonInheritable (%s)]
+de,httpdaemon,8,[Error accept/read new conn]
+de,httpdaemon,9,[Error in Respond()]
+de,httpdaemon,10,[Error in RespondCompleted()]
+de,httpdaemon,11,[daemon: unable to fork new process (%s)\n]
+de,httpdaemon,12,[daemon: setsid failed (%s)\n]
+de,httpdaemon,13,[daemon: can't log pid to %s (%s)\n]
+de,httpdaemon,14,[warning: could not set group id to %d (%s)\n]
+de,httpdaemon,15,[warning: could not set user id to %d (%s)\n]
+de,httpdaemon,16,[warning: daemon is running as super-user\n]
+de,httpdaemon,17,[could not determine current user name\n]
+de,httpdaemon,18,[error: chroot to %s failed (%s)\n]
+de,httpdaemon,19,[WARNING! netscape executable and library have different versions.\n]
+de,httpdaemon,20,[startup: listening to %s://%s, port %d as %s\n]
+de,httpdaemon,21,[startup: listening to %s://%s, port %d as %s\n]
+de,httpdaemon,22,[seminit failed (%s)\n]
+de,httpdaemon,23,[Using single threaded accepts.]
+de,httpdaemon,24,[Using multi threaded accepts.]
+de,httpdaemon,25,[Using partial single threaded accepts.]
+de,httpdaemon,26,[This machine has %d processors.]
+de,httpdaemon,27,[Error calling thr_seconcurrency(%d)- (%s)]
+de,httpdaemon,28,[Set conncurrency to %d.]
+de,httpdaemon,29,[can't fork new process (%s)]
+de,httpdaemon,30,[This beta software has expired.\n]
+de,httpdaemon,31,[can't create IPC pipe (%s)]
+de,httpdaemon,32,[write to wakeup pipe failed (%s)]
+de,httpdaemon,33,[select thread miss]
+de,httpdaemon,34,[startup failure: could not bind to port %d (%s)\n]
+de,httpdaemon,35,[startup failure: could not bind to port %d, IP address %s (%s)\n]
+de,libaccess,-1,[$DBT: libaccess in DB file v1 $]
+de,libaccess,1,[basic-ncsa]
+de,libaccess,2,[cannot open database %s]
+de,libaccess,3,[basic-ncsa]
+de,libaccess,4,[user %s password did not match database %s]
+de,libaccess,5,[basic-ncsa]
+de,libaccess,6,[cannot open connection to LDAP server on %s:%d]
+de,libaccess,7,[basic-ncsa]
+de,libaccess,8,[user %s password did not match LDAP on %s:%d]
+de,libaccess,9,[acl-state]
+de,libaccess,10,[missing realm]
+de,libaccess,11,[Unable to allocate ACL List Hash\n]
+de,libaccess,12,[ACLEvalBuildContext unable to PERM_MALLOC cache structure\n]
+de,libaccess,13,[ACLEvalBuildContext unable to create hash table\n]
+de,libaccess,14,[ACLEvalBuildContext unable to allocate ACE Entry\n]
+de,libaccess,15,[ACLEvalBuildContext unable to allocate ACE entry\n]
+de,libaccess,16,[ACLEvalBuildContext unable to allocate Boundary Entry\n]
+de,libaccess,17,[ACLEvalBuildContext failed.\n]
+de,libaccess,18,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n]
+de,libaccess,19,[LASDnsBuild unable to allocate hash table header\n]
+de,libaccess,20,[LASDnsBuild unable to add key %s\n]
+de,libaccess,21,[LASDnsBuild unable to add key %s\n]
+de,libaccess,22,[LASDnsBuild unable to add key %s\n]
+de,libaccess,23,[LASDnsBuild unable to add key %s\n]
+de,libaccess,24,[LASDnsBuild unable to add key %s\n]
+de,libaccess,25,[LAS DNS build received request for attribute %s\n]
+de,libaccess,26,[LASDnsEval - illegal comparator %s\n]
+de,libaccess,27,[LASDnsEval unable to allocate Context struct\n\n]
+de,libaccess,28,[LASDnsEval unable to get session address %d\n]
+de,libaccess,29,[LASDnsEval unable to get DNS - error=%s\n]
+de,libaccess,30,[LAS Group Eval received request for attribute %s\n]
+de,libaccess,31,[LASGroupEval - illegal comparator %s\n]
+de,libaccess,32,[LASGroupEval - ran out of memory\n]
+de,libaccess,33,[LASGroupEval unable to get session address %d\n]
+de,libaccess,34,[LASGroupEval unable to get session address %d\n]
+de,libaccess,35,[LASGroupEval - couldn't locate getter for auth-user\n]
+de,libaccess,36,[LASGroupEval - Attribute getter for auth-user failed\n]
+de,libaccess,37,[LASGroupEval - Attribute getter didn't set auth-user\n]
+de,libaccess,38,[Check group membership of user "%s" for group "%s"\n]
+de,libaccess,39,[LDAPU_SUCCESS for group "%s"\n]
+de,libaccess,40,[LDAPU_FAILED for group "%s"\n]
+de,libaccess,41,[LAS_EVAL_FALSE\n]
+de,libaccess,42,[LAS_EVAL_TRUE\n]
+de,libaccess,43,[LASIpTreeAlloc - no memory\n]
+de,libaccess,44,[IP LAS unable to allocate tree node\n]
+de,libaccess,45,[IP LAS unable to allocate tree node\n]
+de,libaccess,46,[LAS IP build received request for attribute %s\n]
+de,libaccess,47,[LASIpEval - illegal comparator %s\n]
+de,libaccess,48,[LASIpEval unable to get session address - error=%s\n]
+de,libaccess,49,[LASIpEval unable to allocate Context struct\n\n]
+de,libaccess,50,[LASIpEval - reach 32 bits without conclusion value=%s]
+de,libaccess,51,[LAS Program Eval received request for attribute %s\n]
+de,libaccess,52,[LASProgramEval - illegal comparator %s\n]
+de,libaccess,53,[LASProgram unable to get session address %d\n]
+de,libaccess,54,[bin]
+de,libaccess,55,[LASProgramEval: request not of type admin or bin, passing.\n]
+de,libaccess,56,[LASProgramEval: check if program %s matches pattern %s.\n]
+de,libaccess,57,[LASProgramEval: Invalid wildcard expression %s.\n]
+de,libaccess,58,[LAS_EVAL_FALSE\n]
+de,libaccess,59,[LAS_EVAL_TRUE\n]
+de,libaccess,60,[Unexpected attribute in dayOfWeek - %s\n]
+de,libaccess,61,[Illegal comparator for dayOfWeek - %s\n]
+de,libaccess,62,[Unexpected attribute in timeOfDay - %s\n]
+de,libaccess,63,[LAS User Eval received request for attribute %s\n]
+de,libaccess,64,[LASUserEval - illegal comparator %s\n]
+de,libaccess,65,[LASUserEval - ran out of memory\n]
+de,libaccess,66,[LASUserEval unable to get session address %d\n]
+de,libaccess,67,[LASUserEval unable to get session address %d\n]
+de,libaccess,68,[LASGroupEval - couldn't locate getter for auth-user\n]
+de,libaccess,69,[LASGroupEval - Attribute getter for auth-user failed\n]
+de,libaccess,70,[LASGroupEval - Attribute getter didn't set auth-user\n]
+de,libaccess,71,[Check if uid == user (i.e. check "%s" == "%s)"\n]
+de,libaccess,72,[SUCCESS for user "%s"\n]
+de,libaccess,73,[FAILED for user "%s"\n]
+de,libaccess,74,[LAS_EVAL_FALSE\n]
+de,libaccess,75,[LAS_EVAL_TRUE\n]
+de,libaccess,76,[]
+de,libaccess,77,[LASProgram unable to get request address - error=%s]
+de,libaccess,78,[LASProgram rejecting request for program %s from pattern %s]
+de,libaccess,79,[ACL_CacheFlush: unable to parse file "%s"\n]
+de,libaccess,80,[ACL_CacheFlush: unable to concatenate ACL list "%s"\n]
+de,libaccess,81,[ACL_CacheFlush: unable to open and process the magnus file "%s"\n]
+de,libaccess,82,[Illegal comparator for timeOfDay - %s\n]
+de,libaccess,83,[ACL_EvalBuildContext unable to create hash table\n]
+de,libaccess,84,[ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n]
+de,libaccess,85,[ACL_EvalBuildContext unable to allocate ACE entry\n]
+de,libaccess,86,[ACL_EvalBuildContext unable to allocate auth pointer array\n]
+de,libaccess,87,[ACL_EvalBuildContext unable to allocate auth plist\n]
+de,libaccess,88,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n]
+de,libaccess,89,[ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n]
+de,libaccess,90,[ACL_ModuleRegister: module name is missing\n]
+de,libaccess,91,[ACL_ModuleRegister: call to module init function returned a failed status\n]
+de,libaccess,92,[ACL_GetAttribute: couldn't determine method for %s\n]
+de,libaccess,93,[ACL_GetAttribute: couldn't locate getter for %s]
+de,libaccess,94,[ACL_GetAttribute: attr getter failed to get %s]
+de,libaccess,95,[ACL_GetAttribute: attr getter failed to get %s]
+de,libaccess,96,[ACL_GetAttribute: All attribute getters declined for attr %s]
+de,libaccess,97,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+de,libaccess,98,[ACL_DatabaseRegister: database name is missing]
+de,libaccess,99,[Error reading the DB Map File: %s. Reason: %s]
+de,libaccess,100,[URL is missing for database %s]
+de,libaccess,101,[Invalid property value pair for database %s]
+de,libaccess,102,["default" database must be an LDAP database]
+de,libaccess,103,[Multiple "default" databases are being registered]
+de,libaccess,104,["default" LDAP database must be registered]
+de,libaccess,105,[LASGroupEval unable to get database name - error= %s]
+de,libaccess,106,[received invalid program expression %s]
+de,libaccess,107,[parse_ldap_url: database url is missing]
+de,libaccess,108,[parse_ldap_url: database name is missing]
+de,libaccess,109,[parse_ldap_url: error in parsing ldap url. Reason: %s]
+de,libaccess,110,[ldap password check: unable to get database name - error=%s]
+de,libaccess,111,[ldap password check: unable to get parsed database %s]
+de,libaccess,112,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+de,libaccess,113,[ldap password check: LDAP error: "%s"]
+de,libaccess,114,[get_user_ismember_ldap unable to get database name - error=%s]
+de,libaccess,115,[get_user_ismember_ldap unable to get parsed database %s]
+de,libaccess,116,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+de,libaccess,117,[get_user_ismember_ldap: group %s does not exist]
+de,libaccess,118,[get_user_ismember_ldap: LDAP error: "%s"]
+de,libaccess,119,[ACL_LDAPDatabaseHandle: %s is not a registered database]
+de,libaccess,120,[ACL_LDAPDatabaseHandle: %s is not an LDAP database]
+de,libaccess,121,[ACL_LDAPDatabaseHandle: out of memory]
+de,libaccess,122,[ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s]
+de,libaccess,123,[ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s]
+de,libaccess,124,[insufficient dynamic memory]
+de,libaccess,125,[error opening file, %s: %s]
+de,libaccess,126,[duplicate definition of %s]
+de,libaccess,127,[file %s, line %s: duplicate definition of %s]
+de,libaccess,128,[file %s, line %s: syntax error]
+de,libaccess,129,[file %s, line %s: %s is undefined]
+de,libaccess,130,[in acl %s, %s %s is undefined]
+de,libaccess,131,[database %s: error accessing %s]
+de,libaccess,132,[%s]
+de,libaccess,133,[file %s, line %s: invalid syntax]
+de,libaccess,134,[file %s, line %s: syntax error at "%s"]
+de,libaccess,135,[realm %s is not defined]
+de,libaccess,136,[error code = %d]
+de,libaccess,137,[internal ACL error]
+de,libaccess,138,[invalid argument]
+de,libaccess,139,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+de,libaccess,140,[couldn't determine dbtype from: %s]
+de,libaccess,141,[Failed to register database %s]
+de,libaccess,142,[ACL call returned failed status]
+de,libaccess,143,[file %s: ACL IO error - %s]
+de,libaccess,144,[acl_user_exists: Nicht genug Speicher]
+de,libaccess,145,[acl_user_exists: Benutzer existiert nicht mehr]
+de,libaccess,146,[acl_user_exists: plist-Fehler]
+de,libadmin,-1,[$DBT: libadmin in DB file v1 $]
+de,libadmin,1,[ Help ]
+de,libadmin,2,[ OK ]
+de,libadmin,3,[ Reset ]
+de,libadmin,4,[ Done ]
+de,libadmin,5,[ Cancel ]
+de,libir,-1,[$DBT: libadmin in DB file v1 $]
+de,libir,1,[An I/O error occurred before all form data could be read.]
diff --git a/l10n/dirserv/en/ns-slapd.txt b/l10n/dirserv/en/ns-slapd.txt
new file mode 100644
index 00000000..b1f8348f
--- /dev/null
+++ b/l10n/dirserv/en/ns-slapd.txt
@@ -0,0 +1,986 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+/**************************************************************************/
+/* The copyright notice(s) in this Source Code does not indicate actual */
+/* or intended publication of this Source Code. */
+/**************************************************************************/
+
+/* This text file was generated by program dblink */
+
+$Revision: 1.1 $
+$Log: ns-slapd.txt,v $
+Revision 1.1 2005/01/21 00:40:48 cvsadm
+Initial revision
+
+Revision 1.1.2.3.10.1.8.4 2003/09/22 19:36:41 ulfw
+Update copyright years from 2001 to 2001-2003
+
+Revision 1.1.2.3.10.1.8.3 2001/11/03 01:05:57 richm
+XXX use new copyright XXX
+
+Revision 1.1.2.3.10.1.8.2 2001/09/20 16:39:13 richm
+removed 8 bit copyright character
+
+Revision 1.1.2.3.10.1.8.2 2001/09/18 11:48:15 rmarco
+Remove copyright caracter from copyright
+
+Revision 1.1.2.3.10.1.8.1 2001/02/13 09:59:52 rmarco
+Copyrights
+
+Revision 1.1.2.3.10.1 1998/04/04 23:16:50 mcs
+merge changes made on directory31_rtm_branch into server4_directory_branch
+
+Revision 1.1.2.3.6.1 1998/02/24 05:51:54 noriko
+Synched with server3_i18npkg_branch
+
+Revision 1.1.2.5 1998/02/12 01:15:09 scronin
+still the same i18n changes
+
+$EndLog$
+
+$StartStringData$
+
+en,base,-1,[$DBT: base in DB file v1 $]
+en,base,1,[insufficient memory to create hash table]
+en,base,2,[insufficient memory to create hash table]
+en,base,3,[cache_destroy: cache tables appear corrupt.]
+en,base,4,[unable to allocate hash entry]
+en,base,5,[cache_insert: unable to create cache entry]
+en,base,6,[HTTP/1.0 200 OK\nContent-type: text/html\n\n]
+en,base,7,[<H2>Netscape cache status report</H2>\n]
+en,base,8,[No caches on system<P>]
+en,base,9,[<H2>%s cache</H2>\n]
+en,base,10,[Cache hit ratio: %d/%d (%f)</P>\n</P>\n]
+en,base,11,[Cache size: %d/%d</P>\n</P>\n]
+en,base,12,[Hash table size: %d</P>\n</P>\n]
+en,base,13,[mru : %d</P>\nlru : %d</P>\n]
+en,base,14,[<UL><TABLE BORDER=4> <TH>Bucket</TH> <TH>Address</TH> <TH>Key</TH> <TH>Access Count</TH> <TH>Delete</TH> <TH>Next</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>Data</TH>\n]
+en,base,15,[munmap failed (%s)]
+en,base,16,[munmap failed (%s)]
+en,base,17,[close failed (%s)]
+en,base,18,[daemon: unable to fork new process (%s)\n]
+en,base,19,[daemon: setsid failed (%s)\n]
+en,base,20,[daemon: can't log pid to %s (%s)\n]
+en,base,21,[warning: could not set group id to %d (%s)\n]
+en,base,22,[warning: could not set user id to %d (%s)\n]
+en,base,23,[warning: daemon is running as super-user\n]
+en,base,24,[could not determine current user name\n]
+en,base,25,[error: chroot to %s failed (%s)\n]
+en,base,27,[, address %s]
+en,base,28,[warning: statistics disabled (%s)\n]
+en,base,29,[security handshake timed out for pid %d]
+en,base,30,[warning: statistics disabled (%s)\n]
+en,base,31,[secure handshake failed (code %d)\n]
+en,base,32,[accept failed (%s)]
+en,base,33,[warning: statistics disabled (%s)\n]
+en,base,34,[select thread miss]
+en,base,35,[keepalive worker awoken with no work to do]
+en,base,36,[could not create new thread: %d (%s)]
+en,base,37,[wait for sema succeeded, but nothing to dequeue]
+en,base,38,[queue-sema creation failure]
+en,base,39,[error getting processor info for processor %d]
+en,base,40,[Error binding to processor %d]
+en,base,41,[bound process %d to processor %d]
+en,base,42,[Netscape server is not explicitly binding to any processors.]
+en,base,43,[cache monitor exited]
+en,base,44,[cache batch update daemon exited]
+en,base,45,[Using single threaded accepts.]
+en,base,46,[Using multi threaded accepts.]
+en,base,47,[Using partial single threaded accepts.]
+en,base,48,[This machine has %d processors.]
+en,base,49,[Error calling thr_seconcurrency(%d)- (%s)]
+en,base,50,[Set conncurrency to %d.]
+en,base,51,[WARNING! netscape executable and library have different versions.\n]
+en,base,54,[seminit failed (%s)\n]
+en,base,55,[This beta software has expired.\n]
+en,base,56,[Cache monitor respawned]
+en,base,57,[Cache batch update daemon respawned]
+en,base,58,[can't find empty statistics slot]
+en,base,59,[can't fork new process (%s)]
+en,base,60,[assert failed! %s\n]
+en,base,61,[mr_table_init()]
+en,base,62,[malloc failed]
+en,base,63,[malloc failed!]
+en,base,64,[mr_add_io(%d, type %d, file %d)]
+en,base,65,[mr_add_io - stage 1]
+en,base,66,[mr_add_io - stage 2]
+en,base,67,[mr_add_io found invalid IO type %d]
+en,base,68,[mr_add_io - adding timeout]
+en,base,69,[Out of memory!\n]
+en,base,70,[done with mr_add_io]
+en,base,71,[mr_del_io(%d, type %d, file %d)]
+en,base,72,[mr_del_io found invalid IO type %d]
+en,base,73,[mr_lookup_io(%d)]
+en,base,74,[mr_async_io(%d, %d bytes, file %d)]
+en,base,75,[malloc failure adding async IO]
+en,base,76,[Error adding async io!]
+en,base,77,[Cannot seek for read!]
+en,base,78,[read failure! (%d, %s)]
+en,base,79,[do_read read %d bytes for file %d]
+en,base,80,[Cannot seek for write!]
+en,base,81,[writev failure! (%d, %s)]
+en,base,82,[write failure! (%d, %s)]
+en,base,83,[do_write wrote %d bytes for file %d]
+en,base,84,[do_timeout(mrp %d)]
+en,base,85,[do_timeout: found IO (timer=%d, time=%d)]
+en,base,86,[error deleting io]
+en,base,87,[timeout callback failure for %d\n]
+en,base,88,[mr_get_event(%d) - outstanding io %d]
+en,base,89,[mr_get_event: Waiting for reads on FD:]
+en,base,90,[mr_get_event: Waiting for writes on FD:]
+en,base,91,[ %d]
+en,base,92,[ %d]
+en,base,93,[mr_get_event set no timeout]
+en,base,94,[mr_get_event set timeout to: %d.%d sec]
+en,base,95,[error in select (%d, %s)]
+en,base,96,[mr_get_event() - select found %d]
+en,base,97,[error looking up IO fd %d]
+en,base,98,[read failed for fd %d]
+en,base,99,[error deleting io]
+en,base,100,[callback failure for %d\n]
+en,base,101,[error looking up IO fd %d]
+en,base,102,[writing: header len %d, writelen %d, total %d]
+en,base,103,[write failed for fd %d]
+en,base,104,[error deleting io]
+en,base,105,[callback failure for %d\n]
+en,base,106,[Error creating dns cache]
+en,base,107,[dns_cache_init: hash_size <= 0, using %d]
+en,base,108,[dns_cache_init: cache-size <= %d, using %d]
+en,base,109,[dns_cache_init: cache-size is %d is too large, using %d.]
+en,base,110,[dns_cache_init: expire_time <= 0, using %d]
+en,base,111,[dns_cache_init: expire is %d is too large, using %d seconds.]
+en,base,112,[Error creating dns cache]
+en,base,113,[dns-cache-insert: Error allocating entry]
+en,base,114,[dns-cache-insert: malloc failure]
+en,base,115,[successful server startup]
+en,base,116,[%s B%s]
+en,base,117,[Netscape executable and shared library have different versions]
+en,base,118,[ executable version is %s]
+en,base,119,[ shared library version is %s]
+en,base,120,[error reporting shutting down]
+en,base,121,[warning]
+en,base,122,[config]
+en,base,123,[security]
+en,base,124,[failure]
+en,base,125,[catastrophe]
+en,base,126,[info]
+en,base,127,[verbose]
+en,base,128,[event_handler:Failed to wait on events %s]
+en,base,129,[could not wait on resume event event (%s)]
+en,base,130,[dlopen of %s failed (%s)]
+en,base,131,[dlopen of %s failed (%s)]
+en,base,132,[The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!]
+en,base,133,[Terminating the server %s]
+en,base,134,[kill_server:cannot open server event %s]
+en,base,135,[kill_server:cannot set server event %s]
+en,base,136,[error: could not get socket (%s)\n]
+en,base,137,[error: could not set socket option (%s)\n]
+en,base,138,[Terminating Service:error: could not bind to address %s port %d (%s)\n]
+en,base,139,[Terminating Service:error: could not bind to port %d (%s)\n]
+en,base,140,[SetHandleNonInheritable: could not duplicate socket (%s)]
+en,base,141,[SetHandleNonInheritable: closing the original socket failed (%s)]
+en,base,142,[Could not SetHandleInformation (%s)]
+en,base,143,[Terminating Service:Failure: Could not open statistics file (%s)\n]
+en,base,144,[Could not set Thread Local Storage Value for thread at slot %d]
+en,base,145,[secure handshake failed (code %d)\n]
+en,base,146,[accept failed %d (%s)]
+en,base,147,[Failed to pulse Event %d %s]
+en,base,148,[Failed to send MobGrowth Event to parent %s]
+en,base,149,[Pulsing MobRespawn Event %d]
+en,base,150,[respawn thread pool to %d (%d)]
+en,base,151,[Could not open event to signal rotate application. Could not create the MoveLog event:%s]
+en,base,152,[Failed to send MoveLog Event to rotate app %s]
+en,base,153,[growing thread pool from %d to %d]
+en,base,154,[Could not open the ServiceControlManager, Error %d]
+en,base,155,[StartNetsiteService:Could not open the service %s: Error %d]
+en,base,156,[StartNetsiteService:Could not start the service %s]
+en,base,157,[Service Startup: Could not allocate security descriptor]
+en,base,158,[Service Startup: Could not init security descriptor]
+en,base,159,[Service Startup: Could not set the security Dacl]
+en,base,160,[Terminating Service:WinSock init failed: %s]
+en,base,161,[Httpd Server Startup failed: %s]
+en,base,162,[can't find empty statistics slot]
+en,base,163,[NT daemon: could not create new thread %d]
+en,base,164,[Service Startup Failure. Terminating Service:Could not create event %d:%s]
+en,base,165,[Service Startup Error. Could not create the MoveLog event:%s]
+en,base,166,[Failed to wait on Event objects %s]
+en,base,167,[Failed to wait on Event objects %s]
+en,base,168,[pipebuf_buf2sd: pipebuf_grab IO_ERROR %d]
+en,base,169,[pool-init: memory pools disabled]
+en,base,170,[pool-init: free_size <= 0, using %d]
+en,base,171,[pool-create-block: out of memory]
+en,base,172,[pool-create: out of memory]
+en,base,173,[pool-create: out of memory]
+en,base,174,[pool-malloc: out of memory]
+en,base,175,[FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.]
+en,base,176,[regex error: %s (regex: '%s')]
+en,base,177,[can't create IPC pipe (%s)]
+en,base,178,[write to wakeup pipe failed (%s)]
+en,base,179,[flushing %d connections; current %d; tot %d]
+en,base,180,[accept failed (%s)]
+en,base,181,[Error creating time cache]
+en,base,182,[time-cache: cache disabled]
+en,base,183,[time_cache_init: hash_size < %d, using default, %d]
+en,base,184,[time_cache_init: hash_size > %d, using default, %d]
+en,base,185,[time_cache_init: cache_size < %d, using default, %d]
+en,base,186,[time_cache_init: cache_size > %d, using default, %d]
+en,base,187,[Error allocating memory for time_cache]
+en,base,188,[Error allocating memory for time_cache entry]
+en,base,189,[Error allocating memory for time_cache entry]
+en,base,190,[Error inserting new time_cache entry]
+en,base,191,[Error allocating memory for time_cache]
+en,base,192,[cs-terminate failure (%s)]
+en,base,193,[cs-init failure (%s)]
+en,base,194,[cs-wait failure (%s)]
+en,base,195,[cs-post failure (%s)]
+en,base,196,[Unable to create nonblocking socket (%s)]
+en,base,197,[error: could not set keepalive (%s)\n]
+en,base,198,[error: could not set recv timeout (%s)\n]
+en,base,199,[error: could not set send timeout (%s)\n]
+en,base,200,[Unable to create nonblocking socket (%s)]
+en,base,201,[sem_grab failed (%s)]
+en,base,202,[sem_release failed (%s)]
+en,base,203,[sem_release failed (%s)]
+en,base,204,[Could not remove temporary directory %s, Error %d]
+en,base,205,[Could not remove temporary directory %s, Error %d]
+en,dsgw,-1,[$DBT: dsgw in DB file v1 $]
+en,dsgw,1,[Unknown HTTP request method]
+en,dsgw,2,[Invalid or incomplete HTML form data]
+en,dsgw,3,[Out of memory]
+en,dsgw,4,[Required query/form input is missing]
+en,dsgw,5,[Illegal character in file path]
+en,dsgw,6,[Bad or missing configuration file]
+en,dsgw,7,[Unable to initialize LDAP]
+en,dsgw,8,[An error occurred while contacting the LDAP server]
+en,dsgw,9,[Unknown search object type]
+en,dsgw,10,[Unknown attribute label]
+en,dsgw,11,[Unknown match prompt]
+en,dsgw,12,[No search filters for object type]
+en,dsgw,13,[Unable to open HTML template file]
+en,dsgw,14,[Unknown search mode - use "smart", "complex", "pattern", or "auth"]
+en,dsgw,15,[Distinguished Name missing in URL]
+en,dsgw,16,[Unknown scope in URL (should be base, sub, or one)]
+en,dsgw,17,[Unrecognized URL or unknown error]
+en,dsgw,18,[Bad URL format]
+en,dsgw,19,[Internal error]
+en,dsgw,20,[Unable to write template index file]
+en,dsgw,21,[Unable to open template index file]
+en,dsgw,22,[Unable to read directory]
+en,dsgw,23,[LDAP SSL initialization failed (check the security path)]
+en,dsgw,24,[For the Users and Groups forms to work over SSL, you or your server administrator needs to activate SSL for this Administration Server. The Encryption|On/Off page can be used to do so ]
+en,dsgw,25,[Authentication credentials not found in authentication database]
+en,dsgw,26,[Error retrieving data from the authentication database]
+en,dsgw,27,[Your authentication credentials have expired]
+en,dsgw,28,[Unable to create a random string]
+en,dsgw,29,[No distinguished name was provided when retrieving credentials]
+en,dsgw,30,[Cannot open authentication database]
+en,dsgw,31,[Could not append data to the authentication database]
+en,dsgw,32,[No Directory Manager is defined]
+en,dsgw,33,[No search string was provided. Please try again]
+en,dsgw,34,[Too many arguments on one line in the config. file]
+en,dsgw,35,[Failed to initialize Windows Sockets]
+en,dsgw,36,[Authentication credentials could not be obtained from the Administration Server]
+en,dsgw,37,[Distinguished Name missing in ldapdb:// URL]
+en,dsgw,38,[Unrecognized URL or unknown error]
+en,dsgw,39,[Bad URL format]
+en,dsgw,40,[An error occurred while initializing the local ldap database]
+en,dsgw,41,[Unknown directory service type - use "local" or "remote"]
+en,dsgw,42,[An error occurred while reading the db configuration file]
+en,dsgw,43,[NSHOME/userdb path was NULL]
+en,dsgw,44,[The directory service configuration could not be updated.]
+en,dsgw,45,[The entry could not be read from the directory.]
+en,dsgw,46,[The LDAP database could not be erased.]
+en,dsgw,47,[You may not change entries besides your own.]
+en,dsgw,48,[Problem]
+en,dsgw,49,[Authentication Problem]
+en,dsgw,50,[.\n<P>You must re-authenticate before continuing.\n]
+en,dsgw,51,[.\n<P>You must re-authenticate before continuing.\n]
+en,dsgw,52,[unknown error]
+en,dsgw,53,[The operation was successful.]
+en,dsgw,54,[An internal error occurred in the server. This usually\nindicates a serious malfunction in the server and should be\nbrought to the attention of your server administrator.]
+en,dsgw,55,[The server could not understand the request which was sent to\nit by the gateway.]
+en,dsgw,56,[A time limit was exceeded in responding to your request. If\nyou are searching for entries, you may achieve better results\nif you are more specific in your search.]
+en,dsgw,57,[A size limit was exceeded in responding to your request. If\nyou are searching for entries, you may achieve better results\nif you are more specific in your search, because too many entries\nmatched your search criteria.]
+en,dsgw,58,[The gateway attempted to authenticate to the server using\na method the server doesn't understand.]
+en,dsgw,59,[The gateway attempted to authenticate to the server using an\nauthentication method which the server does not support. ]
+en,dsgw,60,[Your request could not be fulfilled, probably because the server\nthat was contacted does not contain the data you are looking\nfor. It is possible that a referral to another server was\nreturned but could not be followed. If you were trying to make\nchanges to the directory, it may be that the server that holds\nthe master copy of the data is not available.]
+en,dsgw,61,[Your request exceeded an administrative limit in the server.]
+en,dsgw,62,[A critical extension that the gateway requested is not available in this server.]
+en,dsgw,63,[The server was unable to process the request, becase the\nrequest referred to an attribute which does not exist in the\nentry.]
+en,dsgw,64,[The server was unable to fulfill your request, because the\nrequest violates a constraint.]
+en,dsgw,65,[The server could not add a value to the entry, because that\nvalue is already contained in the entry.]
+en,dsgw,66,[The server could not locate the entry. If adding a new entry,\nbe sure that the parent of the entry you are trying to add exists.\nIf you received this error while searching, it indicates that the\nentry which was being searched for does not exist.\nIf you were attempting to authenticate as the directory manager and\nreceived this error, check the gateway configuration file.]
+en,dsgw,67,[A distinguished name was not in the proper format. ]
+en,dsgw,68,[The entry you attempted to authenticate as does not have a\npassword set, or is missing other required authentication\ncredentials. You cannot authenticate as that entry until the\nappropriate attributes have been added by the directory manager. ]
+en,dsgw,69,[The password (or other authentication credentials) you supplied\nis incorrect.]
+en,dsgw,70,[You do not have sufficient privileges to perform the operation. ]
+en,dsgw,71,[The server is too busy to service your request. Try again\nin a few minutes.]
+en,dsgw,72,[The LDAP server could not be contacted.]
+en,dsgw,73,[The server was unwilliing to process your request. Usually,\nthis indicates that serving your request would put a heavy load\non the server. It may also indicate that the server is not\nconfigured to process your request. If searching, you may wish\nto limit the scope of your search.]
+en,dsgw,74,[The directory server could not honor your request because it\nviolates the schema requirements. Typically, this means that you\nhave not provided a value for a required field. It could also mean\nthat the schema in the directory server needs to be updated.]
+en,dsgw,75,[The directory server will not allow you to delete or rename\nan entry if that entry has children. If you wish to do this, you\nmust first delete all the child entries.]
+en,dsgw,76,[The server was unable to add a new entry, or rename an existing\nentry, because an entry by that name already exists.]
+en,dsgw,77,[Your request would affect several directory servers.]
+en,dsgw,78,[The directory server could not be contacted. Contact your\nserver administrator for assistance.]
+en,dsgw,79,[An error occured while sending data to the server.]
+en,dsgw,80,[An error occured while reading data from the server.]
+en,dsgw,81,[The server did not respond to the request. \nThe request timed out.]
+en,dsgw,82,[The server does not support the authentication method used\nby the gateway.]
+en,dsgw,83,[The search filter constructed by the gateway was in error.]
+en,dsgw,84,[The operation was cancelled at your request.]
+en,dsgw,85,[An internal error occurred in the library - a parameter was\nincorrect.]
+en,dsgw,86,[A connection to the server could not be opened. Contact your\nserver administrator for assistance.]
+en,dsgw,87,[An unknown error was encountered.]
+en,dsgw,88,[Entry Already Exists]
+en,dsgw,89,[An entry named ]
+en,dsgw,90,[onMouseOver="window.status='Click here to view this entry'; return true"]
+en,dsgw,91,[ already exists.<P>Please choose another name and/or location.\n<P>\n]
+en,dsgw,92,[Parent entry does not exist]
+en,dsgw,93,[You cannot add an entry by the name:<P><B>%s</B>,<P>\nbecause the parent of that entry does not exist.<P>\nBefore you can add this entry, you must first add\n]
+en,dsgw,94,[its parent.\n]
+en,dsgw,95,[an entry named:<P><B>%s</B>.\n]
+en,dsgw,96,[Warning: no authentication (continuing)...\n]
+en,dsgw,97,[%s Directory Entry]
+en,dsgw,98,[<PRE>Entry DN: %s</PRE><P>\n]
+en,dsgw,99,[Changes to <B>%s</B> have been saved.]
+en,dsgw,100,[<B>%s</B> has been added.]
+en,dsgw,101,[<B>%s</B> has been deleted.]
+en,dsgw,102,[Renamed <B>%s</B> to <B>%s</B>.]
+en,dsgw,103,[<P><B>Note:</B> because you %s the entry you were \nauthenticated as, it was necessary to discard your \nauthentication credentials. You will need to authenticate \nagain to make additional changes.\n]
+en,dsgw,104,[deleted]
+en,dsgw,105,[renamed]
+en,dsgw,106,[changed the password of]
+en,dsgw,107,[Attribute %s was changed<BR>\n]
+en,dsgw,108,[ NOT ASCII (%ld bytes)\n]
+en,dsgw,109,[No values were entered. Please try again.\n]
+en,dsgw,110,[No changes were made.\n]
+en,dsgw,111,[<P>Sending %s to the directory server...\n]
+en,dsgw,112,[information]
+en,dsgw,113,[changes]
+en,dsgw,114,[<P>Successfully added entry.\n]
+en,dsgw,115,[<P>Successfully edited entry. Your changes have been saved.\n]
+en,dsgw,116,[<P>Successfully deleted entry.\n]
+en,dsgw,117,[<PRE>The new name for the entry is: %s\n</PRE><HR>\n]
+en,dsgw,118,[<P>Successfully renamed entry.\n]
+en,dsgw,119,[You must provide the old password.]
+en,dsgw,120,[You must provide a new password. Please try again]
+en,dsgw,121,[The new and confirming passwords do not match. Please try again]
+en,dsgw,122,[<BR>The %s <B>%s</B> is already in use. Please choose a different one.<BR>\n]
+en,dsgw,123,[missing form data element "%.100s"]
+en,dsgw,124,[Initializing config info]
+en,dsgw,125,[Cannot open file.]
+en,dsgw,126,[Malformed dbconf file.]
+en,dsgw,127,[Missing property name in dbconf file.]
+en,dsgw,128,[Out of memory.]
+en,dsgw,129,[Missing directive in dbconf file.]
+en,dsgw,130,[Cannot open config file "%s"\n]
+en,dsgw,131,[Missing argument for "authlifetime" directive\n]
+en,dsgw,132,[Missing argument for "dirmgr" directive\n]
+en,dsgw,133,[Missing argument for "baseurl" directive\n]
+en,dsgw,134,[Bad URL provided for "baseurl" directive - the base DN is missing\n]
+en,dsgw,135,[parsing baseurl directive]
+en,dsgw,136,[Bad URL provided for "baseurl" directive - not an "ldap://" URL\n]
+en,dsgw,137,["ldaps://" URLs are not yet supported\n]
+en,dsgw,138,[Missing arguments for "template" directive\n]
+en,dsgw,139,[Missing argument for "sslrequired" directive\n]
+en,dsgw,140,[Unknown argument to "sslrequired" directive (should be "never", "whenauthenticated", "always")\n]
+en,dsgw,141,[Missing argument for "securitypath" directive\n]
+en,dsgw,142,[Missing argument for "location-suffix" directive\n]
+en,dsgw,143,[Three arguments are required for the "location" directive\n]
+en,dsgw,144,[At least two arguments are required for the "newtype" directive\n]
+en,dsgw,145,[Unknown location in "newtype" directive\n]
+en,dsgw,146,[Three or four arguments are required for the "tmplset" directive\n]
+en,dsgw,147,[Four arguments are required for the "attrvset" directive\n]
+en,dsgw,148,[Missing argument for "charset" directive\n]
+en,dsgw,149,[Missing argument for "ClientLanguage" directive\n]
+en,dsgw,150,[Missing argument for "AdminLanguage" directive\n]
+en,dsgw,151,[Missing argument for "DefaultLanguage" directive\n]
+en,dsgw,152,[Missing filename for "include" directive\n]
+en,dsgw,153,[Unknown directive in config file\n]
+en,dsgw,154,[<= erase_db could not open lcache.conf file "%s"\n]
+en,dsgw,155,[<FONT SIZE="+1">\n<P>The database has been deleted. Creating new database... \n</FONT>\n ]
+en,dsgw,156,[<FONT SIZE="+1">\n<P>The database could not be deleted \n</FONT>\n ]
+en,dsgw,157,[<= app_suffix could not open ldif file "%s"\n]
+en,dsgw,158,[<= app_suffix could not open tmp file "%s"\n]
+en,dsgw,159,[Unable to rename %s to %s]
+en,dsgw,160,[null pointer returned by dbconf_read_default_dbinfo().]
+en,dsgw,161,[Bad "ldapdb" URL - the base DN is missing\n]
+en,dsgw,162,[Bad "ldapdb" URL\n]
+en,dsgw,163,[Bad URL provided for "baseurl" directive - the base DN is missing\n]
+en,dsgw,164,[parsing baseurl directive]
+en,dsgw,165,[Bad URL provided for "baseurl" directive - not an "ldap:// or ldapdb://" URL\n]
+en,dsgw,166,["ldaps://" URLs are not yet supported\n]
+en,dsgw,167,[No value given for binddn]
+en,dsgw,168,[No value given for bindpw]
+en,dsgw,169,[There is no default directory service defined in the dbswitch.conf file]
+en,dsgw,170,[Cannot open config file "%s" for writing\n]
+en,dsgw,171,[Unable to rename %s to %s]
+en,dsgw,172,[config file %s: ]
+en,dsgw,173,[config file %s: line %d: ]
+en,dsgw,174,[max %d]
+en,dsgw,175,[ OK ]
+en,dsgw,176,[Close Window]
+en,dsgw,177,[Go Back]
+en,dsgw,178,[{crypt}LOCKED [%s GMT]]
+en,dsgw,179,[Return to Main]
+en,dsgw,181,[ Help ]
+en,dsgw,182,[Help]
+en,dsgw,184,[Help is not yet available.]
+en,dsgw,186,[Close Window]
+en,dsgw,187,[Close Window]
+en,dsgw,188,[The URL did not include a template name (immediately following the '?').]
+en,dsgw,189,[Authenticate...]
+en,dsgw,190,[Discard authentication credentials (log out)?]
+en,dsgw,191,[Please type a search string]
+en,dsgw,192,[The first step in authenticating to the directory is identifying\nyourself.<br>Please type your name:]
+en,dsgw,193,[Continue]
+en,dsgw,194,[Continue]
+en,dsgw,195,[Cancel]
+en,dsgw,196,[Authenticate as directory manager">  (only available to Directory Administrators)\n]
+en,dsgw,197,[Authenticate...]
+en,dsgw,198,[Discard authentication credentials?]
+en,dsgw,200,[Continue]
+en,dsgw,201,[Continue]
+en,dsgw,202,[Cancel]
+en,dsgw,203,[Authenticate (log in) to the directory]
+en,dsgw,204,[You are about to authenticate to the directory as <B>%s</B>. To complete the authentication process, type your password.\n]
+en,dsgw,206,[Before you can edit or add entries, you must authenticate\n(log in) to the directory. This window will guide\nyou through the steps of the authentication\nprocess.\n]
+en,dsgw,207,[From this screen you may authenticate, or log in, \nto the directory. You will need to authenticate\nbefore you can modify directory entries. If you\nattempt to modify an entry without authenticating,\nyou will be asked to log in.\n]
+en,dsgw,208,[Authentication Status]
+en,dsgw,209,[<form>\nYou are currently authenticated to the directory as ]
+en,dsgw,210,[.\nIf you wish to discard your authentication credentials and log out of the directory, click on the button below.]
+en,dsgw,211,[Discard Authentication Credentials (log out)]
+en,dsgw,212,[Your authentication credentials for ]
+en,dsgw,213,[have expired.\n<HR>\n]
+en,dsgw,214,[Currently, you are not authenticated to the directory.<HR>\n]
+en,dsgw,215,[missing "%s="]
+en,dsgw,216,[unknown "%s=%s"]
+en,dsgw,217,[unknown option %s]
+en,dsgw,218,[unknown syntax=%s\n]
+en,dsgw,219,[** HTML type "%s" not supported **<BR>\n]
+en,dsgw,224,[Edit]
+en,dsgw,225,[Save Changes]
+en,dsgw,226,[modify]
+en,dsgw,227,[add]
+en,dsgw,228,[Delete]
+en,dsgw,229,[Delete this entry?]
+en,dsgw,230,[Rename]
+en,dsgw,231,[Enter a new name for this entry:]
+en,dsgw,232,[Edit As]
+en,dsgw,233,[missing %s=]
+en,dsgw,234,[Close Window]
+en,dsgw,235,[Edit...]
+en,dsgw,236,[missing "%s="\n]
+en,dsgw,237,[unknown set "%s"\n]
+en,dsgw,238,[unknown syntax "%s"\n]
+en,dsgw,239,[Re-Authenticate]
+en,dsgw,240,[Close Window]
+en,dsgw,241,[Do you really want to %s?]
+en,dsgw,242,[width=400,height=130,resizable]
+en,dsgw,243,[ OK ]
+en,dsgw,244,[ OK ]
+en,dsgw,245,[ Reset ]
+en,dsgw,246,[ Done ]
+en,dsgw,247,[ Cancel ]
+en,dsgw,248,[found another IF (nested IFs are not supported)]
+en,dsgw,249,[found ELSE but didn't see an IF]
+en,dsgw,250,[found ELSE after ELSE (expecting ENDIF)]
+en,dsgw,251,[found ELIF but didn't see an IF]
+en,dsgw,252,[found ELIF after ELSE (expecting ENDIF)]
+en,dsgw,253,[found ENDIF but didn't see an IF]
+en,dsgw,254,[<BR><B>template error:</B> %s<BR>\n]
+en,dsgw,255,[ldap_init/lcache_init attempted before config file read]
+en,dsgw,256,[not running under the administration server]
+en,dsgw,257,[Could not initialize permissions]
+en,dsgw,258,[Could not map username to a DN (error from admin server)]
+en,dsgw,259,[Could not get current username]
+en,dsgw,260,[Could not get current user password]
+en,dsgw,261,[Error: %s (%i)]
+en,dsgw,262,[Note: there is no display template for this type of entry available, so it is\ndisplayed below using a default method.]
+en,dsgw,263,[Invalid user id or NULL LDAP handle]
+en,dsgw,264,[no match for user id]
+en,dsgw,265,[more than one match for user id]
+en,dsgw,266,[the entire directory]
+en,dsgw,267,[Two arguments are required for the "includeset" directive\n]
+en,dsgw,268,[The attribute value requested was not found in the entry]
+en,dsgw,269,[Missing argument for "NLS" directive\n]
+en,dsgw,270,[A value must be specified for NT User Id\n]
+en,dsgw,271,[The combination of NT User Id, NT Domain Id is not unique in the directory\n]
+en,dsgw,272,[Values must be specified for both NT User Id and NT Domain Id\n]
+en,dsgw,273,[The NT User Id value must not exceed 20 characters in length.\n]
+en,dsgw,274,[Please provide a name for the new entry.]
+en,dsgw,275,[Please select a location for the new entry.]
+en,dsgw,276,[New Entry]
+en,dsgw,277,[In order to use this feature, there must be a dirmgr defined in dsgw.conf]
+en,dsgw,278,[Three or four arguments are required for the "vcard-property" directive\n]
+en,dsgw,279,[VCard property syntax must be "cis" or "mls"\n]
+en,dsgw,280,[Found no entries.\n%2$s]
+en,dsgw,281,[Found no entries where the %2$s %3$s '%4$s'.\n]
+en,dsgw,282,[Searched and found no entries.\n%2$s]
+en,dsgw,283,[Searched and found no entries where the %2$s %3$s %4$s'.\n]
+en,dsgw,284,[Found 1 entry.\n%2$s]
+en,dsgw,285,[Found 1 entry where the %2$s %3$s '%4$s'.\n]
+en,dsgw,286,[Searched and found 1 entry.\n%2$s]
+en,dsgw,287,[Searched and found 1 entry where the %2$s %3$s '%4$s'.\n]
+en,dsgw,288,[Found %1$li entries.\n%2$s]
+en,dsgw,289,[Found %1$li entries where the %2$s %3$s '%4$s'.\n]
+en,dsgw,290,[Searched and found %1$li entries.\n%2$s]
+en,dsgw,291,[Searched and found %1$li entries where the %2$s %3$s '%4$s'.\n]
+en,dsgw,292,[the LDAP filter is]
+en,dsgw,293,[The server could not locate the entry you used when you authenticated. It is possible that someone renamed the entry or that is was deleted. Please try to authenticate again.]
+en,dsgw,294,[The new password syntax is invalid.\n]
+en,dsgw,295,[The new password occurs in the password history.\n]
+en,dsgw,296,[You've exceeded the password retry limit. Please contact your System Administrator.\n]
+en,dsgw,297,[You've exceeded the password retry limit. Please try again later.\n]
+en,dsgw,298,[The password has expired. Contact your System Administrator to reset the password.\n]
+en,dsgw,299,[Editing]
+en,dsgw,300,[Adding]
+en,dsgw,301,[Deleting]
+en,dsgw,302,[Renaming]
+en,dsgw,303,[There are <B>no</B> names in the list.]
+en,dsgw,304,[There is <B>1</B> name in the list.]
+en,dsgw,305,[There are <B>%s</B> names in the list.]
+en,dsgw,306,[Remove\\nfrom\\nlist? Name]
+en,dsgw,307,[Discard Changes?]
+en,dsgw,308,[width=300,height=130,resizable]
+en,dsgw,309,[Continue without saving changes?<br>Unsaved changes will be lost.]
+en,dsgw,310,[width=400,height=150,resizable]
+en,dsgw,311,[Alert]
+en,dsgw,312,[Confirm]
+en,dsgw,313,[Authentication Failed\n]
+en,dsgw,314,[Authentication Successful]
+en,dsgw,315,[You are now authenticated to the directory as <B>%s</B>.]
+en,dsgw,316,[Your authentication credentials will expire in %d minutes.\n]
+en,dsgw,317,[After your credentials expire, you will need to \nre-authenticate to the directory.\n]
+en,dsgw,318,[<P>The password for this entry will expire <B>%s</B>.\n]
+en,dsgw,319,[Authentication failed because]
+en,dsgw,320,[Authentication failed because the entry you attempted to authenticate as does\nnot exist in the directory.\nYou may only authenticate as an existing directory\nentry.\n]
+en,dsgw,321,[Authentication failed because the entry you attempted to authenticate as does\nnot have a password. Before you can authenticate\nas this entry, a password must be set by a\ndirectory administrator\n]
+en,dsgw,322,[Authentication failed because the password you supplied is incorrect. Please\nclick the Retry button and try again. If you have\nforgotten the password for this entry, a directory\nadministrator must reset the password for you.\n]
+en,dsgw,323,[Authentication failed because of an unexpected error: %s\n]
+en,dsgw,324,[Retry]
+en,dsgw,325,[To continue, select a task from the list above.\n]
+en,dsgw,326,[Edit Password]
+en,dsgw,327,[<H3>Password Expired for %s</H3>\n]
+en,dsgw,328,[Your Directory Server password has expired.]
+en,dsgw,329,[ You must change your password immediately.\n]
+en,dsgw,330,[you did not provide a password. Whenever you authenticate, you must provide a password so that the server can verify your identity.]
+en,dsgw,331,[the server was unable to generate authentication credentials. The authentication database could not be opened.]
+en,dsgw,332,[the server was unable to generate authentication credentials. Data could not be appended to the authentication database.]
+en,dsgw,333,[Continue]
+en,dsgw,334,[Close Window]
+en,dsgw,335,[Success]
+en,dsgw,336,[Your authentication credentials have been destroyed. You are no longer authenticated to the \ndirectory.\n]
+en,dsgw,337,[Go Back]
+en,dsgw,338,[Success]
+en,dsgw,339,[Operations error]
+en,dsgw,340,[Protocol error]
+en,dsgw,341,[Warning: a time limit was exceeded. Not all matching entries are shown.]
+en,dsgw,342,[Warning: a size limit was exceeded. Not all matching entries are shown.]
+en,dsgw,343,[Compare false]
+en,dsgw,344,[Compare true]
+en,dsgw,345,[Strong authentication not supported]
+en,dsgw,346,[Strong authentication required]
+en,dsgw,347,[Warning: some directory servers could not be contacted. Not all matching entries are shown.]
+en,dsgw,348,[Referral received]
+en,dsgw,349,[Administrative limit exceeded]
+en,dsgw,350,[Unavailable critical extension]
+en,dsgw,351,[Confidentiality required]
+en,dsgw,352,[SASL bind in progress]
+en,dsgw,353,[No such attribute]
+en,dsgw,354,[Undefined attribute type]
+en,dsgw,355,[Inappropriate matching]
+en,dsgw,356,[Constraint violation]
+en,dsgw,357,[Type or value exists]
+en,dsgw,358,[Invalid syntax]
+en,dsgw,359,[No such object]
+en,dsgw,360,[Alias problem]
+en,dsgw,361,[Invalid DN syntax]
+en,dsgw,362,[Object is a leaf]
+en,dsgw,363,[Alias dereferencing problem]
+en,dsgw,364,[Inappropriate authentication]
+en,dsgw,365,[Invalid credentials]
+en,dsgw,366,[Insufficient access]
+en,dsgw,367,[DSA is busy]
+en,dsgw,368,[DSA is unavailable]
+en,dsgw,369,[DSA is unwilling to perform]
+en,dsgw,370,[Loop detected]
+en,dsgw,371,[Naming violation]
+en,dsgw,372,[Object class violation]
+en,dsgw,373,[Operation not allowed on nonleaf]
+en,dsgw,374,[Operation not allowed on RDN]
+en,dsgw,375,[Already exists]
+en,dsgw,376,[Cannot modify object class]
+en,dsgw,377,[Results too large]
+en,dsgw,378,[Affects multiple servers]
+en,dsgw,379,[Unknown error]
+en,dsgw,380,[Can't contact LDAP server]
+en,dsgw,381,[Local error]
+en,dsgw,382,[Encoding error]
+en,dsgw,383,[Decoding error]
+en,dsgw,384,[Timed out]
+en,dsgw,385,[Unknown authentication method]
+en,dsgw,386,[Bad search filter]
+en,dsgw,387,[User cancelled operation]
+en,dsgw,388,[Bad parameter to an ldap routine]
+en,dsgw,389,[Out of memory]
+en,dsgw,390,[Can't connect to the LDAP server]
+en,dsgw,391,[Not supported by this version of the LDAP protocol]
+en,dsgw,392,[Requested LDAP control not found]
+en,dsgw,393,[No results returned]
+en,dsgw,394,[More results to return]
+en,dsgw,395,[Client detected loop]
+en,dsgw,396,[Referral hop limit exceeded]
+en,frame,-1,[$DBT: frame in DB file v1 $]
+en,frame,1,[<TITLE>Not Found</TITLE><H1>Not Found</H1> The requested object does not exist on this server. The link you followed is either outdated, inaccurate, or the server has been instructed not to let you have it. ]
+en,frame,2,[Please inform the site administrator of the <A HREF="%s">referring page</A>.]
+en,frame,3,[Your browser sent a request that this proxy could not understand.]
+en,frame,4,[Proper authorization is required for the administration of this proxy.\nEither your browser does not perform authorization, or your authorization\nhas failed.]
+en,frame,5,[Username authentication is required for using this proxy.\nEither your browser does not perform proxy authorization, or your\nauthorization has failed.]
+en,frame,6,[The proxy's access control configuration denies access to\nthe requested object through this proxy.]
+en,frame,7,[The proxy has encountered an internal error which prevents it from\nfulfilling your request. The most likely cause is a misconfiguration.\nPlease ask the administrator to look for messages in the proxy's error log.]
+en,frame,8,[This proxy server does not implement the requested method.]
+en,frame,9,[An error has occurred on the proxy server.]
+en,frame,10,[Your browser sent a query this server could not understand.]
+en,frame,11,[Proper authorization is required for this area. Either your browser does not perform authorization, or your authorization has failed.]
+en,frame,12,[Your client is not allowed to access the requested object.]
+en,frame,13,[This server has encountered an internal error which prevents it from fulfilling your request. The most likely cause is a misconfiguration. Please ask the administrator to look for messages in the server's error log.]
+en,frame,14,[This server does not implement the requested method.]
+en,frame,15,[An error has occurred.]
+en,frame,16,[Your browser sent a message this server could not understand.]
+en,frame,17,[<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>\nThis document has moved to a new <a href="%s">location</a>. Please update your documents and hotlists accordingly.</BODY></HTML>]
+en,frame,18,[<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>]
+en,frame,19,[process-uri-objects]
+en,frame,20,[cannot find template %s]
+en,frame,21,[process-uri-objects]
+en,frame,22,[no partial path after object processing]
+en,frame,23,[find-service]
+en,frame,24,[invalid shexp %s]
+en,frame,25,[find-service]
+en,frame,26,[invalid shexp %s]
+en,frame,27,[handle-processed]
+en,frame,28,[no way to service request for %s]
+en,frame,29,[finish-socks-request]
+en,frame,30,[close failed (%s), csd=%d]
+en,frame,31,[This beta software has expired.\n]
+en,frame,32,[mr_accept(%d)]
+en,frame,33,[Error issuing read on accept socket]
+en,frame,34,[acb_accept_connection(%d)]
+en,frame,35,[Error getting accept socket (%d)]
+en,frame,36,[Error in accept! (%d, %s)]
+en,frame,37,[Error creating new accept request]
+en,frame,38,[accepted connection: %d (NSPR %d)]
+en,frame,39,[Error creating new session structure]
+en,frame,40,[accel_read_request()]
+en,frame,41,[Error allocating request read buffer]
+en,frame,42,[Error issuing async read request]
+en,frame,43,[acb_read_request(%d, bytes %d)]
+en,frame,44,[acb_read_req(1 session = %d)]
+en,frame,45,[Error reading request (%d, %s)]
+en,frame,46,[Client aborted connection]
+en,frame,47,[Error reading request]
+en,frame,48,[Error creating new request]
+en,frame,49,[error occurred, closing %d, io was for %d]
+en,frame,50,[accel_async_scan_headers()]
+en,frame,51,[out of memory: accel_async_scan_headers]
+en,frame,52,[out of memory: accel_async_scan_headers]
+en,frame,53,[Error during async read (%d, %s)]
+en,frame,54,[scan-headers reports: line too long]
+en,frame,55,[scan-headers reports: too many headers]
+en,frame,56,[Error reading headers]
+en,frame,57,[scan-headers reports: header missing terminator (an empty line)]
+en,frame,58,[scan-headers reports: header was empty]
+en,frame,59,[name without value: got line "%s"]
+en,frame,60,[accel_send_plain_file()]
+en,frame,61,[accel_send_plain_file() - found request %d]
+en,frame,62,[Parse headers lost the URI!]
+en,frame,63,[accel_send_plain_file() - found uri %s]
+en,frame,64,[accel_send_plain_file() - found in cache?]
+en,frame,65,[malloc died!]
+en,frame,66,[Error writing back file\n]
+en,frame,67,[acb_send_plain_file(%d)]
+en,frame,68,[Error writing in acb_send_plain_file (%d, %s)]
+en,frame,69,[acb_close_connection(%d)]
+en,frame,70,[Errored IO in acb_close_connection (%d, %s)]
+en,frame,71,[Unable to close socket %d]
+en,frame,72,[accel-cache-insert: Error allocating entry]
+en,frame,73,[cache-init: server cache disabled]
+en,frame,74,[accel_file_cache: Error initializing file cache]
+en,frame,75,[accel_file_cache: Error creating cache]
+en,frame,76,[accel_file_cache_init: CacheHashSize < %d, using %d]
+en,frame,77,[accel_file_cache_init: CacheHashSize > %d, using %d]
+en,frame,78,[accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d]
+en,frame,79,[accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d]
+en,frame,80,[accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d]
+en,frame,81,[accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d]
+en,frame,82,[accel_file_cache: Error initializing file cache]
+en,frame,83,[file-cache: enabled = %s ]
+en,frame,84,[on]
+en,frame,85,[off]
+en,frame,86,[file-cache: MaxNumberOfCachedFiles %d (0x%x)]
+en,frame,87,[file-cache: CacheHashSize %d (0x%x)]
+en,frame,88,[file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)]
+en,frame,89,[accel-cache-insert: Error allocating entry]
+en,frame,90,[file-cache-cleanup: munmap failed (%s)]
+en,frame,91,[file-cache-cleanup: found mmapped file \non system without mmap]
+en,frame,92,[file_cache_init: MaxTotalCachedFileSize < %d, using %d]
+en,frame,93,[file_cache_init: MaxTotalCachedFileSize > %d, using %d]
+en,frame,94,[file cache using mmap flags 0x%x]
+en,frame,95,[file cache using mmap prots 0x%x]
+en,frame,96,[file-cache-init: could not create lock]
+en,frame,97,[file-cache: unable to create temporary directory %s.\n]
+en,frame,98,[file-cache: unable to create temporary directory %s.\n]
+en,frame,99,[file-cache: GetTempPath() Cannot find temp directory to store file!]
+en,frame,100,[file-cache-init: set max cached file size to %d]
+en,frame,101,[file-cache-init: could not create lock]
+en,frame,102,[file_cache_destroy()]
+en,frame,103,[file-cache: Unable to get temp file name. Error %s]
+en,frame,104,[file-cache: Unable to get temp file name. Error %s]
+en,frame,105,[file-cache-insert: Error allocating entry]
+en,frame,106,[file-cache-create: Error opening file %s (%s)]
+en,frame,107,[file-cache-create: Error stat()ing file %s (%s)]
+en,frame,108,[file-cache-create: Error mmap()ing file %s (%s)]
+en,frame,109,[file-cache-create: malloc failure]
+en,frame,110,[file-cache-create: error case failed to munmap(%d, %d) (%s)]
+en,frame,111,[file-cache-valid: cannot stat %s]
+en,frame,112,[dir change: invalidating %s (%d)]
+en,frame,113,[file-cache: asynchronous file change notification failed.]
+en,frame,114,[dir change: offset %d, action %d, len %d, name %s]
+en,frame,115,[unable to check async file status]
+en,frame,116,[ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s]
+en,frame,117,[file-cache-add-watch failure- unable to open directory %s. Error %s]
+en,frame,118,[ReadDirectoryChangesW failure- unable to start watching %s. Error %s]
+en,frame,119,[func_exec]
+en,frame,120,[no handler function given for directive]
+en,frame,121,[func_exec]
+en,frame,122,[cannot find function named %s]
+en,frame,123,[handle-request]
+en,frame,124,[method without URI]
+en,frame,125,[http-parse-request]
+en,frame,126,[while scanning HTTP headers, %s]
+en,frame,127,[handle-request]
+en,frame,128,[read from %s failed, error is %s]
+en,frame,129,[handle-request]
+en,frame,130,[request too long]
+en,frame,131,[start-http-response]
+en,frame,132,[write failed (%s)]
+en,frame,133,[start-http-response]
+en,frame,134,[write failed (%s)]
+en,frame,135,[http-status]
+en,frame,136,[%d is not a valid HTTP status code]
+en,frame,137,[finish-request]
+en,frame,138,[close failed (%s)]
+en,frame,139,[Unable to close socket for writing]
+en,frame,140,[os has %d objects]
+en,frame,141,[obj %d has no hash table at %d]
+en,frame,142,[obj %d has no param]
+en,frame,143,[obj %d name %s value %s]
+en,frame,144,[.....directives %d.......]
+en,frame,145,[.....directive %d]
+en,frame,146,[.......instance %d]
+en,frame,147,[...........param name %s value %s]
+en,frame,148,[ClearConfigurationParameters:RegCreateKey %s]
+en,frame,149,[ClearConfigurationParameters:RegEnumKey %s failed]
+en,frame,150,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+en,frame,151,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+en,frame,152,[Unable to allocate Subject property list.\n]
+en,frame,153,[Unable to set session ptr in Subject property list - error=%d\n]
+en,frame,154,[Unable to set request ptr in Subject property list - error=%d\n]
+en,frame,155,[file-cache-valid: cannot stat %s]
+en,frame,156,[file-cache-create: Error stat()ing file %s (%s)]
+en,httpdaemon,-1,[$DBT: httpdaemon in DB file v1 $]
+en,httpdaemon,1,[Error in ConvertThreadToFiber]
+en,httpdaemon,2,[Error in ConvertThreadToFiber]
+en,httpdaemon,3,[Error in md_start_system]
+en,httpdaemon,4,[Error in CreateFiber - idlefiber]
+en,httpdaemon,5,[Error in GetQueuedCompletionStatus]
+en,httpdaemon,6,[Error creating completion port]
+en,httpdaemon,7,[Could not SetHandleNonInheritable (%s)]
+en,httpdaemon,8,[Error accept/read new conn]
+en,httpdaemon,9,[Error in Respond()]
+en,httpdaemon,10,[Error in RespondCompleted()]
+en,httpdaemon,11,[daemon: unable to fork new process (%s)\n]
+en,httpdaemon,12,[daemon: setsid failed (%s)\n]
+en,httpdaemon,13,[daemon: can't log pid to %s (%s)\n]
+en,httpdaemon,14,[warning: could not set group id to %d (%s)\n]
+en,httpdaemon,15,[warning: could not set user id to %d (%s)\n]
+en,httpdaemon,16,[warning: daemon is running as super-user\n]
+en,httpdaemon,17,[could not determine current user name\n]
+en,httpdaemon,18,[error: chroot to %s failed (%s)\n]
+en,httpdaemon,19,[WARNING! netscape executable and library have different versions.\n]
+en,httpdaemon,20,[startup: listening to %s://%s, port %d as %s\n]
+en,httpdaemon,21,[startup: listening to %s://%s, port %d as %s\n]
+en,httpdaemon,22,[seminit failed (%s)\n]
+en,httpdaemon,23,[Using single threaded accepts.]
+en,httpdaemon,24,[Using multi threaded accepts.]
+en,httpdaemon,25,[Using partial single threaded accepts.]
+en,httpdaemon,26,[This machine has %d processors.]
+en,httpdaemon,27,[Error calling thr_seconcurrency(%d)- (%s)]
+en,httpdaemon,28,[Set conncurrency to %d.]
+en,httpdaemon,29,[can't fork new process (%s)]
+en,httpdaemon,30,[This beta software has expired.\n]
+en,httpdaemon,31,[can't create IPC pipe (%s)]
+en,httpdaemon,32,[write to wakeup pipe failed (%s)]
+en,httpdaemon,33,[select thread miss]
+en,httpdaemon,34,[startup failure: could not bind to port %d (%s)\n]
+en,httpdaemon,35,[startup failure: could not bind to port %d, IP address %s (%s)\n]
+en,libaccess,-1,[$DBT: libaccess in DB file v1 $]
+en,libaccess,1,[basic-ncsa]
+en,libaccess,2,[cannot open database %s]
+en,libaccess,3,[basic-ncsa]
+en,libaccess,4,[user %s password did not match database %s]
+en,libaccess,5,[basic-ncsa]
+en,libaccess,6,[cannot open connection to LDAP server on %s:%d]
+en,libaccess,7,[basic-ncsa]
+en,libaccess,8,[user %s password did not match LDAP on %s:%d]
+en,libaccess,9,[acl-state]
+en,libaccess,10,[missing realm]
+en,libaccess,11,[Unable to allocate ACL List Hash\n]
+en,libaccess,12,[ACLEvalBuildContext unable to PERM_MALLOC cache structure\n]
+en,libaccess,13,[ACLEvalBuildContext unable to create hash table\n]
+en,libaccess,14,[ACLEvalBuildContext unable to allocate ACE Entry\n]
+en,libaccess,15,[ACLEvalBuildContext unable to allocate ACE entry\n]
+en,libaccess,16,[ACLEvalBuildContext unable to allocate Boundary Entry\n]
+en,libaccess,17,[ACLEvalBuildContext failed.\n]
+en,libaccess,18,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n]
+en,libaccess,19,[LASDnsBuild unable to allocate hash table header\n]
+en,libaccess,20,[LASDnsBuild unable to add key %s\n]
+en,libaccess,21,[LASDnsBuild unable to add key %s\n]
+en,libaccess,22,[LASDnsBuild unable to add key %s\n]
+en,libaccess,23,[LASDnsBuild unable to add key %s\n]
+en,libaccess,24,[LASDnsBuild unable to add key %s\n]
+en,libaccess,25,[LAS DNS build received request for attribute %s\n]
+en,libaccess,26,[LASDnsEval - illegal comparator %s\n]
+en,libaccess,27,[LASDnsEval unable to allocate Context struct\n\n]
+en,libaccess,28,[LASDnsEval unable to get session address %d\n]
+en,libaccess,29,[LASDnsEval unable to get DNS - error=%s\n]
+en,libaccess,30,[LAS Group Eval received request for attribute %s\n]
+en,libaccess,31,[LASGroupEval - illegal comparator %s\n]
+en,libaccess,32,[LASGroupEval - ran out of memory\n]
+en,libaccess,33,[LASGroupEval unable to get session address %d\n]
+en,libaccess,34,[LASGroupEval unable to get session address %d\n]
+en,libaccess,35,[LASGroupEval - couldn't locate getter for auth-user\n]
+en,libaccess,36,[LASGroupEval - Attribute getter for auth-user failed\n]
+en,libaccess,37,[LASGroupEval - Attribute getter didn't set auth-user\n]
+en,libaccess,38,[Check group membership of user "%s" for group "%s"\n]
+en,libaccess,39,[LDAPU_SUCCESS for group "%s"\n]
+en,libaccess,40,[LDAPU_FAILED for group "%s"\n]
+en,libaccess,41,[LAS_EVAL_FALSE\n]
+en,libaccess,42,[LAS_EVAL_TRUE\n]
+en,libaccess,43,[LASIpTreeAlloc - no memory\n]
+en,libaccess,44,[IP LAS unable to allocate tree node\n]
+en,libaccess,45,[IP LAS unable to allocate tree node\n]
+en,libaccess,46,[LAS IP build received request for attribute %s\n]
+en,libaccess,47,[LASIpEval - illegal comparator %s\n]
+en,libaccess,48,[LASIpEval unable to get session address - error=%s\n]
+en,libaccess,49,[LASIpEval unable to allocate Context struct\n\n]
+en,libaccess,50,[LASIpEval - reach 32 bits without conclusion value=%s]
+en,libaccess,51,[LAS Program Eval received request for attribute %s\n]
+en,libaccess,52,[LASProgramEval - illegal comparator %s\n]
+en,libaccess,53,[LASProgram unable to get session address %d\n]
+en,libaccess,54,[bin]
+en,libaccess,55,[LASProgramEval: request not of type admin or bin, passing.\n]
+en,libaccess,56,[LASProgramEval: check if program %s matches pattern %s.\n]
+en,libaccess,57,[LASProgramEval: Invalid wildcard expression %s.\n]
+en,libaccess,58,[LAS_EVAL_FALSE\n]
+en,libaccess,59,[LAS_EVAL_TRUE\n]
+en,libaccess,60,[Unexpected attribute in dayOfWeek - %s\n]
+en,libaccess,61,[Illegal comparator for dayOfWeek - %s\n]
+en,libaccess,62,[Unexpected attribute in timeOfDay - %s\n]
+en,libaccess,63,[LAS User Eval received request for attribute %s\n]
+en,libaccess,64,[LASUserEval - illegal comparator %s\n]
+en,libaccess,65,[LASUserEval - ran out of memory\n]
+en,libaccess,66,[LASUserEval unable to get session address %d\n]
+en,libaccess,67,[LASUserEval unable to get session address %d\n]
+en,libaccess,68,[LASGroupEval - couldn't locate getter for auth-user\n]
+en,libaccess,69,[LASGroupEval - Attribute getter for auth-user failed\n]
+en,libaccess,70,[LASGroupEval - Attribute getter didn't set auth-user\n]
+en,libaccess,71,[Check if uid == user (i.e. check "%s" == "%s)"\n]
+en,libaccess,72,[SUCCESS for user "%s"\n]
+en,libaccess,73,[FAILED for user "%s"\n]
+en,libaccess,74,[LAS_EVAL_FALSE\n]
+en,libaccess,75,[LAS_EVAL_TRUE\n]
+en,libaccess,76,[]
+en,libaccess,77,[LASProgram unable to get request address - error=%s]
+en,libaccess,78,[LASProgram rejecting request for program %s from pattern %s]
+en,libaccess,79,[ACL_CacheFlush: unable to parse file "%s"\n]
+en,libaccess,80,[ACL_CacheFlush: unable to concatenate ACL list "%s"\n]
+en,libaccess,81,[ACL_CacheFlush: unable to open and process the magnus file "%s"\n]
+en,libaccess,82,[Illegal comparator for timeOfDay - %s\n]
+en,libaccess,83,[ACL_EvalBuildContext unable to create hash table\n]
+en,libaccess,84,[ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n]
+en,libaccess,85,[ACL_EvalBuildContext unable to allocate ACE entry\n]
+en,libaccess,86,[ACL_EvalBuildContext unable to allocate auth pointer array\n]
+en,libaccess,87,[ACL_EvalBuildContext unable to allocate auth plist\n]
+en,libaccess,88,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n]
+en,libaccess,89,[ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n]
+en,libaccess,90,[ACL_ModuleRegister: module name is missing\n]
+en,libaccess,91,[ACL_ModuleRegister: call to module init function returned a failed status\n]
+en,libaccess,92,[ACL_GetAttribute: couldn't determine method for %s\n]
+en,libaccess,93,[ACL_GetAttribute: couldn't locate getter for %s]
+en,libaccess,94,[ACL_GetAttribute: attr getter failed to get %s]
+en,libaccess,95,[ACL_GetAttribute: attr getter failed to get %s]
+en,libaccess,96,[ACL_GetAttribute: All attribute getters declined for attr %s]
+en,libaccess,97,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+en,libaccess,98,[ACL_DatabaseRegister: database name is missing]
+en,libaccess,99,[Error reading the DB Map File: %s. Reason: %s]
+en,libaccess,100,[URL is missing for database %s]
+en,libaccess,101,[Invalid property value pair for database %s]
+en,libaccess,102,["default" database must be an LDAP database]
+en,libaccess,103,[Multiple "default" databases are being registered]
+en,libaccess,104,["default" LDAP database must be registered]
+en,libaccess,105,[LASGroupEval unable to get database name - error= %s]
+en,libaccess,106,[received invalid program expression %s]
+en,libaccess,107,[parse_ldap_url: database url is missing]
+en,libaccess,108,[parse_ldap_url: database name is missing]
+en,libaccess,109,[parse_ldap_url: error in parsing ldap url. Reason: %s]
+en,libaccess,110,[ldap password check: unable to get database name - error=%s]
+en,libaccess,111,[ldap password check: unable to get parsed database %s]
+en,libaccess,112,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+en,libaccess,113,[ldap password check: LDAP error: "%s"]
+en,libaccess,114,[get_user_ismember_ldap unable to get database name - error=%s]
+en,libaccess,115,[get_user_ismember_ldap unable to get parsed database %s]
+en,libaccess,116,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+en,libaccess,117,[get_user_ismember_ldap: group %s does not exist]
+en,libaccess,118,[get_user_ismember_ldap: LDAP error: "%s"]
+en,libaccess,119,[ACL_LDAPDatabaseHandle: %s is not a registered database]
+en,libaccess,120,[ACL_LDAPDatabaseHandle: %s is not an LDAP database]
+en,libaccess,121,[ACL_LDAPDatabaseHandle: out of memory]
+en,libaccess,122,[ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s]
+en,libaccess,123,[ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s]
+en,libaccess,124,[insufficient dynamic memory]
+en,libaccess,125,[error opening file, %s: %s]
+en,libaccess,126,[duplicate definition of %s]
+en,libaccess,127,[file %s, line %s: duplicate definition of %s]
+en,libaccess,128,[file %s, line %s: syntax error]
+en,libaccess,129,[file %s, line %s: %s is undefined]
+en,libaccess,130,[in acl %s, %s %s is undefined]
+en,libaccess,131,[database %s: error accessing %s]
+en,libaccess,132,[%s]
+en,libaccess,133,[file %s, line %s: invalid syntax]
+en,libaccess,134,[file %s, line %s: syntax error at "%s"]
+en,libaccess,135,[realm %s is not defined]
+en,libaccess,136,[error code = %d]
+en,libaccess,137,[internal ACL error]
+en,libaccess,138,[invalid argument]
+en,libaccess,139,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+en,libaccess,140,[couldn't determine dbtype from: %s]
+en,libaccess,141,[Failed to register database %s]
+en,libaccess,142,[ACL call returned failed status]
+en,libaccess,143,[file %s: ACL IO error - %s]
+en,libaccess,144,[acl_user_exists: out of memory]
+en,libaccess,145,[acl_user_exists: user doesn't exist anymore]
+en,libaccess,146,[acl_user_exists: plist error]
+en,libadmin,-1,[$DBT: libadmin in DB file v1 $]
+en,libadmin,1,[ Help ]
+en,libadmin,2,[ OK ]
+en,libadmin,3,[ Reset ]
+en,libadmin,4,[ Done ]
+en,libadmin,5,[ Cancel ]
+en,libir,-1,[$DBT: libadmin in DB file v1 $]
+en,libir,1,[An I/O error occurred before all form data could be read.]
diff --git a/l10n/dirserv/es/ns-slapd.txt b/l10n/dirserv/es/ns-slapd.txt
new file mode 100644
index 00000000..c7b2bb87
--- /dev/null
+++ b/l10n/dirserv/es/ns-slapd.txt
@@ -0,0 +1,889 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+/**************************************************************************/
+/* The copyright notice(s) in this Source Code does not indicate actual */
+/* or intended publication of this Source Code. */
+/**************************************************************************/
+
+/* This text file was generated by program dblink */
+
+$Revision: 1.1 $
+$Log: ns-slapd.txt,v $
+Revision 1.1 2005/01/21 00:40:48 cvsadm
+Initial revision
+
+Revision 1.2.4.5 2003/09/22 19:36:41 ulfw
+Update copyright years from 2001 to 2001-2003
+
+Revision 1.2.4.4 2001/11/03 01:06:19 richm
+XXX use new copyright XXX
+
+Revision 1.2.4.3 2001/09/20 16:39:14 richm
+removed 8 bit copyright character
+
+Revision 1.2.4.3 2001/09/18 11:48:16 rmarco
+Remove copyright caracter from copyright
+
+Revision 1.2.4.2 2001/02/13 09:59:53 rmarco
+Copyrights
+
+Revision 1.2.4.1 1998/10/10 02:14:04 ggood
+Copy from Directory40RtmBranchpoint to DirectoryBranch
+
+Revision 1.1.2.1 1997/12/24 01:18:23 werudge
+UTF8 Encoded from es/ns-slapd.txt.iso8859 : 1.1.2.1
+Based on en/ns-slapd.txt : 1.1.2.3
+
+Revision 1.1.2.1 1997/12/24 01:14:39 werudge
+Based on en/ns-slapd.txt : 1.1.2.3
+daily 971113.1 SOLARIS-export-optimize-normal-slapd
+$EndLog$
+
+$StartStringData$
+
+es,base,-1,[$DBT: base in DB file v1 $]
+es,base,1,[no hay memoria suficiente para crear la tabla de totales de control]
+es,base,2,[no hay memoria suficiente para crear la tabla de totales de control]
+es,base,3,[cache_destroy: las tablas caché parecen dañadas.]
+es,base,4,[no ha sido posible asignar la entrada de total de control]
+es,base,5,[cache_insert: no ha sido posible crear la entrada caché]
+es,base,6,[HTTP/1.0 200 OK\nContent-type: text/html\n\n]
+es,base,7,[<H2>Informe de estado de caché de Netscape</H2>\n]
+es,base,8,[El sistema no tiene cachés<P>]
+es,base,9,[<H2>Caché %s</H2>\n]
+es,base,10,[Índice de aciertos de caché: %d/%d (%f)</P>\n</P>\n]
+es,base,11,[Tamaño de caché: %d/%d</P>\n</P>\n]
+es,base,12,[Tamaño de la tabla de totales de control: %d</P>\n</P>\n]
+es,base,13,[mru : %d</P>\nlru : %d</P>\n]
+es,base,14,[<UL><TABLE BORDER=4> <TH>Sector de almacenamiento</TH> <TH>Dirección</TH> <TH>Clave</TH> <TH>Recuento de accesos</TH> <TH>Eliminar</TH> <TH>Siguiente</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>Datos</TH>\n]
+es,base,15,[munmap failed (%s)]
+es,base,16,[munmap failed (%s)]
+es,base,17,[close failed (%s)]
+es,base,18,[daemon: unable to fork new process (%s)\n]
+es,base,19,[daemon: setsid failed (%s)\n]
+es,base,20,[daemon: can't log pid to %s (%s)\n]
+es,base,21,[warning: could not set group id to %d (%s)\n]
+es,base,22,[warning: could not set user id to %d (%s)\n]
+es,base,23,[warning: daemon is running as super-user\n]
+es,base,24,[could not determine current user name\n]
+es,base,25,[error: chroot to %s failed (%s)\n]
+es,base,27,[, address %s]
+es,base,28,[warning: statistics disabled (%s)\n]
+es,base,29,[security handshake timed out for pid %d]
+es,base,30,[warning: statistics disabled (%s)\n]
+es,base,31,[secure handshake failed (code %d)\n]
+es,base,32,[accept failed (%s)]
+es,base,33,[warning: statistics disabled (%s)\n]
+es,base,34,[select thread miss]
+es,base,35,[keepalive worker awoken with no work to do]
+es,base,36,[could not create new thread: %d (%s)]
+es,base,37,[wait for sema succeeded, but nothing to dequeue]
+es,base,38,[queue-sema creation failure]
+es,base,39,[error getting processor info for processor %d]
+es,base,40,[Error binding to processor %d]
+es,base,41,[bound process %d to processor %d]
+es,base,42,[Netscape server is not explicitly binding to any processors.]
+es,base,43,[cache monitor exited]
+es,base,44,[cache batch update daemon exited]
+es,base,45,[Using single threaded accepts.]
+es,base,46,[Using multi threaded accepts.]
+es,base,47,[Using partial single threaded accepts.]
+es,base,48,[This machine has %d processors.]
+es,base,49,[Error calling thr_seconcurrency(%d)- (%s)]
+es,base,50,[Set conncurrency to %d.]
+es,base,51,[WARNING! netscape executable and library have different versions.\n]
+es,base,54,[seminit failed (%s)\n]
+es,base,55,[This beta software has expired.\n]
+es,base,56,[Cache monitor respawned]
+es,base,57,[Cache batch update daemon respawned]
+es,base,58,[can't find empty statistics slot]
+es,base,59,[can't fork new process (%s)]
+es,base,60,[assert failed! %s\n]
+es,base,61,[mr_table_init()]
+es,base,62,[malloc failed]
+es,base,63,[malloc failed!]
+es,base,64,[mr_add_io(%d, type %d, file %d)]
+es,base,65,[mr_add_io - stage 1]
+es,base,66,[mr_add_io - stage 2]
+es,base,67,[mr_add_io found invalid IO type %d]
+es,base,68,[mr_add_io - adding timeout]
+es,base,69,[Out of memory!\n]
+es,base,70,[done with mr_add_io]
+es,base,71,[mr_del_io(%d, type %d, file %d)]
+es,base,72,[mr_del_io found invalid IO type %d]
+es,base,73,[mr_lookup_io(%d)]
+es,base,74,[mr_async_io(%d, %d bytes, file %d)]
+es,base,75,[malloc failure adding async IO]
+es,base,76,[Error adding async io!]
+es,base,77,[Cannot seek for read!]
+es,base,78,[read failure! (%d, %s)]
+es,base,79,[do_read read %d bytes for file %d]
+es,base,80,[Cannot seek for write!]
+es,base,81,[writev failure! (%d, %s)]
+es,base,82,[write failure! (%d, %s)]
+es,base,83,[do_write wrote %d bytes for file %d]
+es,base,84,[do_timeout(mrp %d)]
+es,base,85,[do_timeout: found IO (timer=%d, time=%d)]
+es,base,86,[error deleting io]
+es,base,87,[timeout callback failure for %d\n]
+es,base,88,[mr_get_event(%d) - outstanding io %d]
+es,base,89,[mr_get_event: Waiting for reads on FD:]
+es,base,90,[mr_get_event: Waiting for writes on FD:]
+es,base,91,[ %d]
+es,base,92,[ %d]
+es,base,93,[mr_get_event set no timeout]
+es,base,94,[mr_get_event set timeout to: %d.%d sec]
+es,base,95,[error in select (%d, %s)]
+es,base,96,[mr_get_event() - select found %d]
+es,base,97,[error looking up IO fd %d]
+es,base,98,[read failed for fd %d]
+es,base,99,[error deleting io]
+es,base,100,[callback failure for %d\n]
+es,base,101,[error looking up IO fd %d]
+es,base,102,[writing: header len %d, writelen %d, total %d]
+es,base,103,[write failed for fd %d]
+es,base,104,[error deleting io]
+es,base,105,[callback failure for %d\n]
+es,base,106,[Error creating dns cache]
+es,base,107,[dns_cache_init: hash_size <= 0, using %d]
+es,base,108,[dns_cache_init: cache-size <= %d, using %d]
+es,base,109,[dns_cache_init: cache-size is %d is too large, using %d.]
+es,base,110,[dns_cache_init: expire_time <= 0, using %d]
+es,base,111,[dns_cache_init: expire is %d is too large, using %d seconds.]
+es,base,112,[Error creating dns cache]
+es,base,113,[dns-cache-insert: Error allocating entry]
+es,base,114,[dns-cache-insert: malloc failure]
+es,base,115,[successful server startup]
+es,base,116,[%s B%s]
+es,base,117,[Netscape executable and shared library have different versions]
+es,base,118,[ executable version is %s]
+es,base,119,[ shared library version is %s]
+es,base,120,[error reporting shutting down]
+es,base,121,[warning]
+es,base,122,[config]
+es,base,123,[security]
+es,base,124,[failure]
+es,base,125,[catastrophe]
+es,base,126,[info]
+es,base,127,[verbose]
+es,base,128,[event_handler:Failed to wait on events %s]
+es,base,129,[could not wait on resume event event (%s)]
+es,base,130,[dlopen of %s failed (%s)]
+es,base,131,[dlopen of %s failed (%s)]
+es,base,132,[The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!]
+es,base,133,[Terminating the server %s]
+es,base,134,[kill_server:cannot open server event %s]
+es,base,135,[kill_server:cannot set server event %s]
+es,base,136,[error: could not get socket (%s)\n]
+es,base,137,[error: could not set socket option (%s)\n]
+es,base,138,[Terminating Service:error: could not bind to address %s port %d (%s)\n]
+es,base,139,[Terminating Service:error: could not bind to port %d (%s)\n]
+es,base,140,[SetHandleNonInheritable: could not duplicate socket (%s)]
+es,base,141,[SetHandleNonInheritable: closing the original socket failed (%s)]
+es,base,142,[Could not SetHandleInformation (%s)]
+es,base,143,[Terminating Service:Failure: Could not open statistics file (%s)\n]
+es,base,144,[Could not set Thread Local Storage Value for thread at slot %d]
+es,base,145,[secure handshake failed (code %d)\n]
+es,base,146,[accept failed %d (%s)]
+es,base,147,[Failed to pulse Event %d %s]
+es,base,148,[Failed to send MobGrowth Event to parent %s]
+es,base,149,[Pulsing MobRespawn Event %d]
+es,base,150,[respawn thread pool to %d (%d)]
+es,base,151,[Could not open event to signal rotate application. Could not create the MoveLog event:%s]
+es,base,152,[Failed to send MoveLog Event to rotate app %s]
+es,base,153,[growing thread pool from %d to %d]
+es,base,154,[Could not open the ServiceControlManager, Error %d]
+es,base,155,[StartNetsiteService:Could not open the service %s: Error %d]
+es,base,156,[StartNetsiteService:Could not start the service %s]
+es,base,157,[Service Startup: Could not allocate security descriptor]
+es,base,158,[Service Startup: Could not init security descriptor]
+es,base,159,[Service Startup: Could not set the security Dacl]
+es,base,160,[Terminating Service:WinSock init failed: %s]
+es,base,161,[Httpd Server Startup failed: %s]
+es,base,162,[can't find empty statistics slot]
+es,base,163,[NT daemon: could not create new thread %d]
+es,base,164,[Service Startup Failure. Terminating Service:Could not create event %d:%s]
+es,base,165,[Service Startup Error. Could not create the MoveLog event:%s]
+es,base,166,[Failed to wait on Event objects %s]
+es,base,167,[Failed to wait on Event objects %s]
+es,base,168,[pipebuf_buf2sd: pipebuf_grab IO_ERROR %d]
+es,base,169,[pool-init: memory pools disabled]
+es,base,170,[pool-init: free_size <= 0, using %d]
+es,base,171,[pool-create-block: out of memory]
+es,base,172,[pool-create: out of memory]
+es,base,173,[pool-create: out of memory]
+es,base,174,[pool-malloc: out of memory]
+es,base,175,[FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.]
+es,base,176,[regex error: %s (regex: '%s')]
+es,base,177,[can't create IPC pipe (%s)]
+es,base,178,[write to wakeup pipe failed (%s)]
+es,base,179,[flushing %d connections; current %d; tot %d]
+es,base,180,[accept failed (%s)]
+es,base,181,[Error creating time cache]
+es,base,182,[time-cache: cache disabled]
+es,base,183,[time_cache_init: hash_size < %d, using default, %d]
+es,base,184,[time_cache_init: hash_size > %d, using default, %d]
+es,base,185,[time_cache_init: cache_size < %d, using default, %d]
+es,base,186,[time_cache_init: cache_size > %d, using default, %d]
+es,base,187,[Error allocating memory for time_cache]
+es,base,188,[Error allocating memory for time_cache entry]
+es,base,189,[Error allocating memory for time_cache entry]
+es,base,190,[Error inserting new time_cache entry]
+es,base,191,[Error allocating memory for time_cache]
+es,base,192,[cs-terminate failure (%s)]
+es,base,193,[cs-init failure (%s)]
+es,base,194,[cs-wait failure (%s)]
+es,base,195,[cs-post failure (%s)]
+es,base,196,[Unable to create nonblocking socket (%s)]
+es,base,197,[error: could not set keepalive (%s)\n]
+es,base,198,[error: could not set recv timeout (%s)\n]
+es,base,199,[error: could not set send timeout (%s)\n]
+es,base,200,[Unable to create nonblocking socket (%s)]
+es,base,201,[sem_grab failed (%s)]
+es,base,202,[sem_release failed (%s)]
+es,base,203,[sem_release failed (%s)]
+es,base,204,[Could not remove temporary directory %s, Error %d]
+es,base,205,[Could not remove temporary directory %s, Error %d]
+es,dsgw,-1,[$DBT: dsgw in DB file v1 $]
+es,dsgw,1,[Se desconoce el método de solicitud HTTP]
+es,dsgw,2,[Los datos del formulario HTML no son válidos o son incompletos]
+es,dsgw,3,[Memoria agotada]
+es,dsgw,4,[Falta una entrada necesaria de solicitud/formulario]
+es,dsgw,5,[La vía de acceso contiene caracteres no válidos]
+es,dsgw,6,[Falta el archivo de configuración o está dañado]
+es,dsgw,7,[Imposible inicializar el protocolo LDAP]
+es,dsgw,8,[Se ha producido un error al establecer contacto con el servidor LDAP]
+es,dsgw,9,[Se desconoce el tipo de objeto de búsqueda]
+es,dsgw,10,[Se desconoce la etiqueta de atributo]
+es,dsgw,11,[Se desconoce el indicador de correspondencia]
+es,dsgw,12,[El tipo de objeto no tiene filtros de búsqueda]
+es,dsgw,13,[Imposible abrir el archivo de la plantilla HTML]
+es,dsgw,14,[Se desconoce el modo de búsqueda: utilice "smart", "complex", "pattern" o "auth"]
+es,dsgw,15,[Falta un nombre distinguido en el URL]
+es,dsgw,16,[Se desconoce un ámbito del URL (debe ser base, sub o one)]
+es,dsgw,17,[No se reconoce el URL o hay un error desconocido]
+es,dsgw,18,[El formato del URL no es correcto]
+es,dsgw,19,[Error interno]
+es,dsgw,20,[Imposible escribir en el archivo de índices de la plantilla]
+es,dsgw,21,[Imposible abrir el archivo de índice de plantillas]
+es,dsgw,22,[Imposible leer el directorio]
+es,dsgw,23,[Ha fallado la inicialización SSL LDAP (compruebe la vía de acceso de seguridad)]
+es,dsgw,24,[Para que los formularios Usuarios y Grupos funcionen mediante SSL, usted o el administrador del servidor tiene que activar SSL en este Administration Server. Para ello, puede utilizar la página Cifrado|activado/desactivado]
+es,dsgw,25,[No se han encontrado las credenciales de autentificación en la base de datos de autentificación]
+es,dsgw,26,[Error al recuperar datos de la base de datos de autentificación]
+es,dsgw,27,[Sus credenciales de autentificación han caducado]
+es,dsgw,28,[Imposible crear una cadena aleatoria]
+es,dsgw,29,[No se ha especificado un nombre distinguido al recuperar credenciales]
+es,dsgw,30,[No se puede abrir la base de datos de autentificación]
+es,dsgw,31,[No ha sido posible añadir los datos a la base de datos de autentificación]
+es,dsgw,32,[No se ha definido un Gestor de directorios]
+es,dsgw,33,[No se ha especificado una cadena de búsqueda. Vuelva a intentarlo]
+es,dsgw,34,[Una de las líneas del archivo config. contiene demasiados argumentos]
+es,dsgw,35,[No ha sido posible inicializar Windows Sockets]
+es,dsgw,36,[No se han recibido las credenciales de autentificación del Administration Server]
+es,dsgw,37,[Falta un nombre distinguido en el URL ldapdb://]
+es,dsgw,38,[No se reconoce el URL o hay un error desconocido]
+es,dsgw,39,[El formato del URL no es correcto]
+es,dsgw,40,[Se ha producido un error al inicializar la base de datos ldap local]
+es,dsgw,41,[Se desconoce el tipo de servicio de directorios: utilice "local" o "remote"]
+es,dsgw,42,[Se ha producido un error al leer el archivo de configuración de base de datos]
+es,dsgw,43,[La vía de acceso a NSHOME/userdb tenía el valor NULL]
+es,dsgw,44,[No ha sido posible actualizar la configuración del servicio de directorios.]
+es,dsgw,45,[No ha sido posible leer la entrada desde el directorio.]
+es,dsgw,46,[No ha sido posible borrar la base de datos LDAP.]
+es,dsgw,47,[No está autorizado a cambiar otras entradas que no sean las suyas propias.]
+es,dsgw,48,[Problema]
+es,dsgw,49,[Problema de autentificación]
+es,dsgw,50,[.\n<P>Debe repetir la autentificación para poder continuar.\n]
+es,dsgw,51,[.\n<P>Debe repetir la autentificación para poder continuar.\n]
+es,dsgw,52,[error desconocido]
+es,dsgw,53,[La operación se ha realizado con éxito.]
+es,dsgw,54,[Se ha producido un error interno en el servidor. Por lo general,\nesto indica un fallo grave del servidor.\nComuníqueselo al administrador del servidor.]
+es,dsgw,55,[El servidor no ha entendido la solicitud que le ha llegado desde\nla pasarela.]
+es,dsgw,56,[Se ha sobrepasado el límite de tiempo para responder a su solicitud.\nSi lo que busca son entradas, es posible que obtenga mejores\nresultados si realiza una búsqueda más específica.]
+es,dsgw,57,[Se ha sobrepasado el límite de tamaño para responder a su solicitud.\nSi lo que busca son entradas, es posible que obtenga mejores\nresultados si realiza una búsqueda más específica, ya que existen\ndemasiadas entradas que cumplen los criterios de búsqueda.]
+es,dsgw,58,[La pasarela ha intentado autentificarse en el servidor\nmediante un método que el servidor no entiende.]
+es,dsgw,59,[La pasarela ha intentado autentificarse ante el servidor mediante un\nmétodo de autentificación incompatible con el servidor. ]
+es,dsgw,60,[No ha sido posible atender su solicitud, probablemente porque\nel servidor con el que se ha establecido contacto no contiene los datos que\nusted busca. Es posible que se haya recibido\nuna referencia a otro servidor\nal que no es posible acceder. Si tenía la intención\n de realizar cambios en el directorio, puede que no esté disponible el servidor\nque contiene la copia maestra de los datos.]
+es,dsgw,61,[Su solicitud ha sobrepasado un límite administrativo en el servidor.]
+es,dsgw,62,[La pasarela ha solicitado una extensión crítica que no está disponible en el servidor.]
+es,dsgw,63,[El servidor no ha podido procesar la solicitud debido a que\nésta contiene una referencia a un atributo que no\nexiste en la entrada.]
+es,dsgw,64,[El servidor no ha podido atender la solicitud debido a que\nésta no cumple con una restricción de la base de datos.]
+es,dsgw,65,[El servidor no ha podido añadir un valor a la entrada debido a que\ndicho valor ya está incluido en la entrada.]
+es,dsgw,66,[El servidor no ha encontrado la entrada. Si desea añadir\nuna entrada, compruebe que exista su entrada primaria. Si este error\nse ha producido durante una búsqueda, indica que no existe\nla entrada que se está buscando.\nSi ha intentado autentificarse como gestor de directorios y se ha producido\neste error, compruebe el archivo de configuración de la pasarela.]
+es,dsgw,67,[Un nombre distinguido no tenía el formato correcto. ]
+es,dsgw,68,[Ha intentado autentificarse mediante una entrada que no tiene un\nconjunto de contraseñas o que carece de otras credenciales\nnecesarias para la autentificación. No podrá utilizar esa entrada para la autentificación\nhasta que el gestor de directorios haya añadido\nlos atributos correspondientes.]
+es,dsgw,69,[La contraseña u otras credenciales de autentificación especificadas\nno son correctas.]
+es,dsgw,70,[No dispone de suficientes derechos de acceso para realizar la operación. ]
+es,dsgw,71,[El servidor está demasiado ocupado para atender su\nsolicitud. Vuelva a intentarlo dentro de unos minutos.]
+es,dsgw,72,[No ha sido posible establecer contacto con el servidor LDAP.]
+es,dsgw,73,[El servidor se ha negado a procesar su solicitud,\nprobablemente porque se saturaría durante la operación. También puede indicar que el servidor no está\nconfigurado para procesar su solicitud. Si está realizando una búsqueda,\nquizás convenga limitar el ámbito de la misma.]
+es,dsgw,74,[El servidor de directorios no ha podido atender su solicitud porque\nno cumple con los requisitos del esquema. Normalmente, esto suele indicar\nque no se ha especificado el valor de un campo necesario, aunque también\npodría indicar que es necesario actualizar el esquema del servidor de directorios.]
+es,dsgw,75,[El servidor de directorios no permite eliminar una entrada\nni cambiarle el nombre si tiene entradas secundarias. Si desea realizar esta operación,\ndeberá eliminar en primer lugar todas las entradas secundarias.]
+es,dsgw,76,[El servidor no ha podido añadir una entrada nueva o cambiar el nombre de\nuna entrada ya existente porque ese nombre ya se utiliza.]
+es,dsgw,77,[Su solicitud afectaría a varios servidores de directorios.]
+es,dsgw,78,[No ha sido posible establecer contacto con el servidor de directorios.\nConsulte con el administrador del servidor.]
+es,dsgw,79,[Se ha producido un error al enviar datos al servidor.]
+es,dsgw,80,[Se ha producido un error al leer datos desde el servidor.]
+es,dsgw,81,[El servidor no ha respondido a la solicitud.\nHa vencido el tiempo de espera de la solicitud.]
+es,dsgw,82,[El servidor no admite el método de autentificación que\nutiliza la pasarela.]
+es,dsgw,83,[El filtro de búsqueda que ha formado la pasarela tiene un error.]
+es,dsgw,84,[La operación se ha cancelado a solicitud del usuario.]
+es,dsgw,85,[Se ha producido un error interno en la biblioteca: un parámetro\nera incorrecto.]
+es,dsgw,86,[No ha sido posible abrir una conexión con el servidor.\nConsulte con el administrador del servidor.]
+es,dsgw,87,[Se ha producido un error desconocido.]
+es,dsgw,88,[La entrada ya existe]
+es,dsgw,89,[Ya existe una entrada con el nombre ]
+es,dsgw,90,[onMouseOver="window.status='Haga clic aquí para ver esta entrada'; return true"]
+es,dsgw,91,[ .<P>Elija otro nombre u otra ubicación.\n<P>\n]
+es,dsgw,92,[No existe la entrada primaria]
+es,dsgw,93,[No puede añadir una entrada mediante este nombre:<P><B>%s</B>,<P>\nya que no existe su entrada primaria.<P>\nPara poder añadir esta entrada, deberá añadir en primer lugar\n]
+es,dsgw,94,[su entrada primaria.\n]
+es,dsgw,95,[una entrada con este nombre:<P><B>%s</B>.\n]
+es,dsgw,96,[Advertencia: sin autentificar (continuación)...\n]
+es,dsgw,97,[%s la entrada de directorio]
+es,dsgw,98,[<PRE>DN de la entrada: %s</PRE><P>\n]
+es,dsgw,99,[Han quedado guardados los cambios realizados en <B>%s</B>]
+es,dsgw,100,[<B>%s</B> has been added.]
+es,dsgw,101,[<B>%s</B> has been deleted.]
+es,dsgw,102,[Renamed <B>%s</B> to <B>%s</B>.]
+es,dsgw,103,[<P><B>Nota:</B> debido a que ha %s la entrada que utilizó como\nautentificación, ha sido necesario descartar sus credenciales de \nautentificación. Si desea realizar más cambios,\ndeberá volver a autentificarse.\n]
+es,dsgw,104,[eliminado]
+es,dsgw,105,[cambiado el nombre de]
+es,dsgw,106,[cambiado la contraseña de]
+es,dsgw,107,[Se ha cambiado el atributo %s<BR>\n]
+es,dsgw,108,[ NO ASCII (%ld bytes)\n]
+es,dsgw,109,[No se han introducido valores. Vuelva a intentarlo.\n]
+es,dsgw,110,[No se han realizado cambios.\n]
+es,dsgw,111,[<P>Enviando %s al servidor de directorios...\n]
+es,dsgw,112,[información]
+es,dsgw,113,[cambios]
+es,dsgw,114,[<P>Se ha añadido la entrada sin problemas.\n]
+es,dsgw,115,[<P>Se ha modificado la entrada sin problemas. Los cambios han quedado guardados.\n]
+es,dsgw,116,[<P>Se ha eliminado la entrada sin problemas.\n]
+es,dsgw,117,[<PRE>El nombre nuevo de la entrada es: %s\n</PRE><HR>\n]
+es,dsgw,118,[<P>Se ha cambiado el nombre de la entrada sin problemas.\n]
+es,dsgw,119,[Es necesario especificar la contraseña antigua.]
+es,dsgw,120,[Es necesario especificar una contraseña nueva. Vuelva a intentarlo]
+es,dsgw,121,[La contraseña de confirmación no coincide con la contraseña nueva. Vuelva a intentarlo]
+es,dsgw,122,[<BR>El %s <B>%s</B> ya está en uso. Elija otro.<BR>\n]
+es,dsgw,123,[falta el elemento "%.100s" de los datos del formulario]
+es,dsgw,124,[Inicializando la información de configuración]
+es,dsgw,125,[Imposible abrir el archivo.]
+es,dsgw,126,[Archivo dbconf mal construido.]
+es,dsgw,127,[Falta un nombre de propiedad en el archivo dbconf.]
+es,dsgw,128,[Memoria agotada.]
+es,dsgw,129,[Falta una directiva en el archivo dbconf.]
+es,dsgw,130,[Imposible abrir el archivo de configuración "%s"\n]
+es,dsgw,131,[Falta un argumento en la directiva "authlifetime"\n]
+es,dsgw,132,[Falta un argumento en la directiva "dirmgr"\n]
+es,dsgw,133,[Falta un argumento en la directiva "baseurl"\n]
+es,dsgw,134,[Se ha especificado un URL erróneo para la directiva "baseurl": falta el DN de base\n]
+es,dsgw,135,[analizando la directiva baseurl]
+es,dsgw,136,[Se ha especificado un URL erróneo para la directiva "baseurl": no es un URL "ldap://"\n]
+es,dsgw,137,[Todavía no son compatibles las direcciones URL "ldap://"\n]
+es,dsgw,138,[Faltan argumentos en la directiva "template"\n]
+es,dsgw,139,[Faltan un argumento en la directiva "sslrequired"\n]
+es,dsgw,140,[Se desconoce un argumento de la directiva "sslrequired" (debería ser "never", "whenauthenticated", "always")\n]
+es,dsgw,141,[Falta un argumento en la directiva "securitypath"\n]
+es,dsgw,142,[Falta un argumento en la directiva "location-suffix"\n]
+es,dsgw,143,[La directiva "location" necesita tres argumentos\n]
+es,dsgw,144,[La directiva "newtype" necesita dos argumentos como mínimo\n]
+es,dsgw,145,[Se desconoce una ubicación en la directiva "newtype"\n]
+es,dsgw,146,[La directiva "tmplset" necesita tres o cuatro argumentos\n]
+es,dsgw,147,[La directiva "attrvset" necesita cuatro argumentos\n]
+es,dsgw,148,[Falta un argumento en la directiva "charset"\n]
+es,dsgw,149,[Falta un argumento en la directiva "ClientLanguage"\n]
+es,dsgw,150,[Falta un argumento en la directiva "AdminLanguage"\n]
+es,dsgw,151,[Falta un argumento en la directiva "DefaultLanguage"\n]
+es,dsgw,152,[Falta un nombre de archivo en la directiva "include"\n]
+es,dsgw,153,[Se desconoce una directiva del archivo config\n]
+es,dsgw,154,[<= erase_db no ha podido abrir el archivo lcache.conf "%s"\n]
+es,dsgw,155,[<FONT SIZE="+1">\n<P>Se ha eliminado la base de datos. Creando una base de datos nueva... \n</FONT>\n ]
+es,dsgw,156,[<FONT SIZE="+1">\n<P>No ha sido posible eliminar la base de datos \n</FONT>\n ]
+es,dsgw,157,[<= app_suffix no ha podido abrir el archivo ldif "%s"\n]
+es,dsgw,158,[<= app_suffix no ha podido abrir el archivo temporal "%s"\n]
+es,dsgw,159,[Imposible cambiar el nombre de %s a %s]
+es,dsgw,160,[dbconf_read_default_dbinfo() ha devuelto un puntero NULL.]
+es,dsgw,161,[El URL "ldapdb" es erróneo: falta el DN de base\n]
+es,dsgw,162,[El URL "ldapdb" es erróneo\n]
+es,dsgw,163,[Se ha especificado un URL erróneo en la directiva "baseurl": falta el DN de base\n]
+es,dsgw,164,[analizando la directiva baseurl]
+es,dsgw,165,[Se ha especificado un URL erróneo en la directiva "baseurl": no es un URL "ldap:// o ldapdb://"\n]
+es,dsgw,166,[Todavía no son compatibles las direcciones URL "ldap://"\n]
+es,dsgw,167,[No se ha dado ningún valor para binddn]
+es,dsgw,168,[No se ha dado ningún valor para bindpw]
+es,dsgw,169,[No se ha definido un servicio predeterminado de directorios en el archivo dbswitch.conf]
+es,dsgw,170,[Imposible abrir el archivo de configuración "%s" para escribir en él]
+es,dsgw,171,[Imposible cambiar el nombre de %s a %s]
+es,dsgw,172,[archivo de configuración %s: ]
+es,dsgw,173,[archivo de configuración %s: línea %d: ]
+es,dsgw,174,[máx %d]
+es,dsgw,175,[ OK ]
+es,dsgw,176,[Cerrar la ventana]
+es,dsgw,177,[Retroceder]
+es,dsgw,178,[{crypt}BLOQUEADO [%s GMT]]
+es,dsgw,179,[Volver a la pantalla principal]
+es,dsgw,181,[ Help ]
+es,dsgw,182,[Ayuda]
+es,dsgw,184,[Todavía no hay ayuda disponible.]
+es,dsgw,186,[Cerrar la ventana]
+es,dsgw,187,[Cerrar la ventana]
+es,dsgw,188,[El URL no incluía un nombre de plantilla justo después de "?"]
+es,dsgw,189,[Autentificar...]
+es,dsgw,190,[¿Desea descartar las credenciales de autentificación (finalizar la sesión?]
+es,dsgw,191,[Escriba una cadena de búsqueda]
+es,dsgw,192,[Como primer paso para autentificarse ante el directorio,\n identifíquese.<br>Introduzca su nombre:]
+es,dsgw,193,[Continuar]
+es,dsgw,194,[Continuar]
+es,dsgw,195,[Cancelar]
+es,dsgw,196,[Autentificarse como gestor de directorios"> Â (solamente para los administradores de directorios)\n]
+es,dsgw,197,[Autentificar...]
+es,dsgw,198,[¿Desea descartar las credenciales de autentificación?]
+es,dsgw,200,[Continuar]
+es,dsgw,201,[Continuar]
+es,dsgw,202,[Cancelar]
+es,dsgw,203,[Autentifíquese (inicie la sesión) en el directorio]
+es,dsgw,204,[Está a punto de autentificarse en el directorio como <B>%s</B>. Para concluir el proceso de autentificación, escriba su contraseña.\n]
+es,dsgw,206,[Para poder modificar o añadir entradas, es necesario autentificarse\n(iniciar sesión) en el directorio. Esta ventana le servirá de\nguía para realizar el proceso\nde autentificación.\n]
+es,dsgw,207,[Desde esta pantalla, es posible autentificarse (iniciar sesión)\nen el directorio. Para poder modificar entradas del directorio, es necesario\realizar la autentificación en primer lugar.\nSi intenta modificar una entrada si haberse autentificado,\nel sistema le pedirá que inicie sesión.\n]
+es,dsgw,208,[Estado de la autentificación]
+es,dsgw,209,[<form>\nActualmente, se encuentra autentificado en el directorio como ]
+es,dsgw,210,[.\nSi desea descartar las credenciales de autentificación y finalizar la sesión en el directorio, haga clic en el botón que aparece a continuación.]
+es,dsgw,211,[Descartar credenciales de autentificación (finalizar sesión)]
+es,dsgw,212,[Sus credenciales de autentificación en ]
+es,dsgw,213,[han caducado.\n<HR>\n]
+es,dsgw,214,[Actualmente, no se encuentra autentificado en el directorio.<HR>\n]
+es,dsgw,215,[falta "%s=" ]
+es,dsgw,216,[se desconoce "%s=%s"]
+es,dsgw,217,[se desconoce la opción %s]
+es,dsgw,218,[se desconoce la sintaxis=%s\n]
+es,dsgw,219,[** El tipo de HTML "%s" no es compatible **<BR>\n]
+es,dsgw,224,[Modificar]
+es,dsgw,225,[Save Changes]
+es,dsgw,226,[modify]
+es,dsgw,227,[add]
+es,dsgw,228,[Eliminar]
+es,dsgw,229,[¿Desea eliminar esta entrada?]
+es,dsgw,230,[Cambiar el nombre]
+es,dsgw,231,[Escriba un nombre nuevo para esta entrada:]
+es,dsgw,232,[Modificar como]
+es,dsgw,233,[falta %s=]
+es,dsgw,234,[Cerrar la ventana]
+es,dsgw,235,[Modificar...]
+es,dsgw,236,[falta"%s="\n]
+es,dsgw,237,[se desconoce el conjunto "%s"\n]
+es,dsgw,238,[se desconoce la sintaxis "%s"\n]
+es,dsgw,239,[Repetir la autentificación]
+es,dsgw,240,[Cerrar la ventana]
+es,dsgw,241,[Confirme que desea ]
+es,dsgw,242,[?]
+es,dsgw,243,[ Aceptar ]
+es,dsgw,244,[ Aceptar ]
+es,dsgw,245,[ Restablecer ]
+es,dsgw,246,[ Terminado ]
+es,dsgw,247,[ Cancelar ]
+es,dsgw,248,[se ha encontrado otra sentencia IF (no se admiten las sentencias IF anidadas)]
+es,dsgw,249,[se ha encontrado una sentencia ELSE, pero no aparece la IF]
+es,dsgw,250,[se ha encontrado una sentencia ELSE después de ELSE (se esperaba encontrar ENDIF)]
+es,dsgw,251,[se ha encontrado una sentencia ELIF, pero no aparece la IF]
+es,dsgw,252,[se ha encontrado una sentencia ELIF después de ELSE (se esperaba encontrar ENDIF)]
+es,dsgw,253,[se ha encontrado una sentencia ENDIF, pero no aparece la IF]
+es,dsgw,254,[<BR><B>error de plantilla:</B> %s<BR>\n]
+es,dsgw,255,[se ha intentado el proceso ldap_init/lcache_init antes de leer el archivo de configuración]
+es,dsgw,256,[no se ejecuta bajo el Administration Server]
+es,dsgw,257,[No se han podido inicializar los permisos]
+es,dsgw,258,[No ha sido posible asignar el nombre de usuario a un DN (el Administration Server ha comunicado un error)]
+es,dsgw,259,[No se ha recibido el nombre de usuario actual]
+es,dsgw,260,[No se ha recibido la contraseña del usuario actual]
+es,dsgw,261,[Error: %s]
+es,dsgw,262,[Nota: no se encuentra disponible ninguna plantilla de presentación para este tipo de\nentrada; la entrada se muestra a continuación con un método predeterminado.]
+es,dsgw,263,[La identifación de usuario no es válida o el identifador LDAP tiene el valor NULL]
+es,dsgw,264,[no coincide ninguna identificación de usuario]
+es,dsgw,265,[coinciden varias identificaciones de usuario]
+es,dsgw,266,[the entire directory]
+es,dsgw,267,[La directiva "includeset" necesita dos argumentos\n]
+es,dsgw,268,[No se ha encontrado en esta entrada el valor de atributo solicitado]
+es,dsgw,269,[Falta un argumento en la directiva "NLS"\n]
+es,dsgw,270,[Es necesario especificar un valor de identificación de usuario NT\n ]
+es,dsgw,271,[La combinación de identificaciones de usuario NT y dominio NT ya se utiliza en el directorio\n]
+es,dsgw,272,[Es necesario especificar valores de identificación de usuario NT y de dominio NT\n]
+es,dsgw,273,[La identifiación de usuario NT no puede contener más de 20 caracteres.\n]
+es,dsgw,274,[Especifique el nombre de la entrada nueva.]
+es,dsgw,275,[Seleccione la ubicación de la entrada nueva.]
+es,dsgw,276,[Entrada nueva]
+es,dsgw,277,[Para poder utilizar esta función, el archivo dsgw.conf debe contener una definición de dirmgr]
+es,dsgw,278,[La directiva "vcard-property" necesita tres o cuatro argumentos\n]
+es,dsgw,279,[La sintaxis de la propiedad VCard debe ser "cis" o "mls"\n]
+es,dsgw,280,[No se han encontrado entradas.\n%2$s]
+es,dsgw,281,[No se han encontrado entradas en las que %2$s %3$s '%4$s'.\n]
+es,dsgw,282,[Se ha realizado la búsqueda, pero no se ha encontrado ninguna entrada.\n%2$s]
+es,dsgw,283,[Se ha realizado la búsqueda, pero no se ha encontrado ninguna entrada en la que %2$s %3$s %4$s'.\n]
+es,dsgw,284,[Se ha encontrado 1 entrada.\n%2$s]
+es,dsgw,285,[Se ha encontrado 1 entrada en la que %2$s %3$s '%4$s'.\n]
+es,dsgw,286,[Se ha realizado la búsqueda y se ha encontrado 1 entrada.\n%2$s]
+es,dsgw,287,[Se ha realizado la búsqueda y se ha encontrado 1 entrada en la que %2$s %3$s '%4$s'.\n]
+es,dsgw,288,[Se han encontrado %1$li entradas.\n%2$s]
+es,dsgw,289,[Se han encontrado %1$li entradas en las que %2$s %3$s '%4$s'.\n]
+es,dsgw,290,[Se ha realizado la búsqueda y se han encontrado %1$li entradas.\n%2$s]
+es,dsgw,291,[Se ha realizado la búsqueda y se han encontrado %1$li entradas en las que %2$s %3$s '%4$s'.\n]
+es,dsgw,292,[el filtro LDAP es]
+es,dsgw,293,[El servidor no ha encontrado la entrada que usted ha utilizado el autentificarse. Es posible que se haya eliminado la entrada o que alguien le haya cambiado el nombre. Intente volver a realizar la autentificación.]
+es,dsgw,294,[La sintaxis de la contraseña nueva no es válida.\n]
+es,dsgw,295,[La contraseña nueva ya existe en el historial de contraseñas.\n]
+es,dsgw,296,[Ha sobrepasado el límite de reintentos de contraseña. Consulte con el administrador del sistema.\n]
+es,dsgw,297,[Ha sobrepasado el límite de reintentos de contraseña. Vuelva a intentarlo más adelante.\n]
+es,dsgw,298,[La contraseña ha caducado. Consulte con el administrador del sistema para restablecer la contraseña.\n]
+es,frame,-1,[$DBT: frame in DB file v1 $]
+es,frame,1,[<TITLE>No se ha encontrado</TITLE><H1>No se ha encontrado</H1> El objeto solicitado no existe en este servidor. El vínculo que ha seguido no está actualizado o no es exacto, o bien el servidor ha recibido instrucciones para no permitirle el acceso.]
+es,frame,2,[Informe al administrador de la oficina acerca de la <A HREF="%s">página que contiene la referencia</A>.]
+es,frame,3,[El navegador ha enviado una solicitud que este servidor proxy no ha entendido.]
+es,frame,4,[Es necesario disponer de la autorización adecuada para la administración de\neste servidor proxy. El navegador no puede conceder la autorización,\no la autorización no se ha podido realizar.]
+es,frame,5,[Es necesaria la autentificación de nombre de usuario para utilizar\neste servidor proxy. El navegador no puede conceder la autorización,\no la autorización no se ha podido realizar.]
+es,frame,6,[La configuración de control de acceso al servidor proxy deniega\nel acceso al objeto solicitado mediante este servidor proxy.]
+es,frame,7,[El servidor proxy ha encontrado un error interno que le impide\natender su solicitud. Lo más probable es que se deba a una configuración\nerrónea. Solicite al administrador que examine el registro de errores del servidor proxy.]
+es,frame,8,[Este servidor proxy no utiliza el método solicitado.]
+es,frame,9,[Se ha producido un error en el servidor proxy.]
+es,frame,10,[El navegador ha enviado una consulta que este servidor no ha entendido.]
+es,frame,11,[Es necesario disponer de la autorización adecuada para acceder a esta zona. El navegador no puede conceder la autorización o la autorización no se ha podido realizar]
+es,frame,12,[Su cliente no está autorizado a acceder al objeto que ha solicitado.]
+es,frame,13,[El servidor ha encontrado un error interno que le impide atender su solicitud. Lo más probable es que se deba a una configuración errónea. Solicite al administrador que examine el registro de errores del servidor.]
+es,frame,14,[Este servidor no utiliza el método solicitado.]
+es,frame,15,[Se ha producido un error.]
+es,frame,16,[El navegador ha enviado un mensaje que este servidor no ha entendido.]
+es,frame,17,[<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>\nEste documento ha sido trasladado a otra <a href="%s">ubicación</a>. Actualice los documentos y listas de acceso con los nuevos datos.</BODY></HTML>]
+es,frame,18,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="es"><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>]
+es,frame,19,[process-uri-objects]
+es,frame,20,[cannot find template %s]
+es,frame,21,[process-uri-objects]
+es,frame,22,[no partial path after object processing]
+es,frame,23,[find-service]
+es,frame,24,[invalid shexp %s]
+es,frame,25,[find-service]
+es,frame,26,[invalid shexp %s]
+es,frame,27,[handle-processed]
+es,frame,28,[no way to service request for %s]
+es,frame,29,[finish-socks-request]
+es,frame,30,[close failed (%s), csd=%d]
+es,frame,31,[This beta software has expired.\n]
+es,frame,32,[mr_accept(%d)]
+es,frame,33,[Error issuing read on accept socket]
+es,frame,34,[acb_accept_connection(%d)]
+es,frame,35,[Error getting accept socket (%d)]
+es,frame,36,[Error in accept! (%d, %s)]
+es,frame,37,[Error creating new accept request]
+es,frame,38,[accepted connection: %d (NSPR %d)]
+es,frame,39,[Error creating new session structure]
+es,frame,40,[accel_read_request()]
+es,frame,41,[Error allocating request read buffer]
+es,frame,42,[Error issuing async read request]
+es,frame,43,[acb_read_request(%d, bytes %d)]
+es,frame,44,[acb_read_req(1 session = %d)]
+es,frame,45,[Error reading request (%d, %s)]
+es,frame,46,[Client aborted connection]
+es,frame,47,[Error reading request]
+es,frame,48,[Error creating new request]
+es,frame,49,[error occurred, closing %d, io was for %d]
+es,frame,50,[accel_async_scan_headers()]
+es,frame,51,[out of memory: accel_async_scan_headers]
+es,frame,52,[out of memory: accel_async_scan_headers]
+es,frame,53,[Error during async read (%d, %s)]
+es,frame,54,[scan-headers reports: line too long]
+es,frame,55,[scan-headers reports: too many headers]
+es,frame,56,[Error reading headers]
+es,frame,57,[scan-headers reports: header missing terminator (an empty line)]
+es,frame,58,[scan-headers reports: header was empty]
+es,frame,59,[nombre sin valor: se ha recibido la línea "%s"]
+es,frame,60,[accel_send_plain_file()]
+es,frame,61,[accel_send_plain_file() - found request %d]
+es,frame,62,[Parse headers lost the URI!]
+es,frame,63,[accel_send_plain_file() - found uri %s]
+es,frame,64,[accel_send_plain_file() - found in cache?]
+es,frame,65,[malloc died!]
+es,frame,66,[Error writing back file\n]
+es,frame,67,[acb_send_plain_file(%d)]
+es,frame,68,[Error writing in acb_send_plain_file (%d, %s)]
+es,frame,69,[acb_close_connection(%d)]
+es,frame,70,[Errored IO in acb_close_connection (%d, %s)]
+es,frame,71,[Unable to close socket %d]
+es,frame,72,[accel-cache-insert: Error allocating entry]
+es,frame,73,[cache-init: server cache disabled]
+es,frame,74,[accel_file_cache: Error initializing file cache]
+es,frame,75,[accel_file_cache: Error creating cache]
+es,frame,76,[accel_file_cache_init: CacheHashSize < %d, using %d]
+es,frame,77,[accel_file_cache_init: CacheHashSize > %d, using %d]
+es,frame,78,[accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d]
+es,frame,79,[accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d]
+es,frame,80,[accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d]
+es,frame,81,[accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d]
+es,frame,82,[accel_file_cache: Error initializing file cache]
+es,frame,83,[file-cache: enabled = %s ]
+es,frame,84,[on]
+es,frame,85,[off]
+es,frame,86,[file-cache: MaxNumberOfCachedFiles %d (0x%x)]
+es,frame,87,[file-cache: CacheHashSize %d (0x%x)]
+es,frame,88,[file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)]
+es,frame,89,[accel-cache-insert: Error allocating entry]
+es,frame,90,[file-cache-cleanup: munmap failed (%s)]
+es,frame,91,[file-cache-cleanup: found mmapped file \non system without mmap]
+es,frame,92,[file_cache_init: MaxTotalCachedFileSize < %d, using %d]
+es,frame,93,[file_cache_init: MaxTotalCachedFileSize > %d, using %d]
+es,frame,94,[file cache using mmap flags 0x%x]
+es,frame,95,[file cache using mmap prots 0x%x]
+es,frame,96,[file-cache-init: could not create lock]
+es,frame,97,[file-cache: unable to create temporary directory %s.\n]
+es,frame,98,[file-cache: unable to create temporary directory %s.\n]
+es,frame,99,[file-cache: GetTempPath() Cannot find temp directory to store file!]
+es,frame,100,[file-cache-init: set max cached file size to %d]
+es,frame,101,[file-cache-init: could not create lock]
+es,frame,102,[file_cache_destroy()]
+es,frame,103,[file-cache: Unable to get temp file name. Error %s]
+es,frame,104,[file-cache: Unable to get temp file name. Error %s]
+es,frame,105,[file-cache-insert: Error allocating entry]
+es,frame,106,[file-cache-create: Error opening file %s (%s)]
+es,frame,107,[file-cache-create: Error stat()ing file %s (%s)]
+es,frame,108,[file-cache-create: Error mmap()ing file %s (%s)]
+es,frame,109,[file-cache-create: malloc failure]
+es,frame,110,[file-cache-create: error case failed to munmap(%d, %d) (%s)]
+es,frame,111,[file-cache-valid: cannot stat %s]
+es,frame,112,[dir change: invalidating %s (%d)]
+es,frame,113,[file-cache: asynchronous file change notification failed.]
+es,frame,114,[dir change: offset %d, action %d, len %d, name %s]
+es,frame,115,[unable to check async file status]
+es,frame,116,[ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s]
+es,frame,117,[file-cache-add-watch failure- unable to open directory %s. Error %s]
+es,frame,118,[ReadDirectoryChangesW failure- unable to start watching %s. Error %s]
+es,frame,119,[func_exec]
+es,frame,120,[no handler function given for directive]
+es,frame,121,[func_exec]
+es,frame,122,[cannot find function named %s]
+es,frame,123,[handle-request]
+es,frame,124,[method without URI]
+es,frame,125,[http-parse-request]
+es,frame,126,[while scanning HTTP headers, %s]
+es,frame,127,[handle-request]
+es,frame,128,[read from %s failed, error is %s]
+es,frame,129,[handle-request]
+es,frame,130,[request too long]
+es,frame,131,[start-http-response]
+es,frame,132,[write failed (%s)]
+es,frame,133,[start-http-response]
+es,frame,134,[write failed (%s)]
+es,frame,135,[http-status]
+es,frame,136,[%d is not a valid HTTP status code]
+es,frame,137,[finish-request]
+es,frame,138,[close failed (%s)]
+es,frame,139,[Unable to close socket for writing]
+es,frame,140,[os has %d objects]
+es,frame,141,[obj %d has no hash table at %d]
+es,frame,142,[obj %d has no param]
+es,frame,143,[obj %d name %s value %s]
+es,frame,144,[.....directives %d.......]
+es,frame,145,[.....directive %d]
+es,frame,146,[.......instance %d]
+es,frame,147,[...........param name %s value %s]
+es,frame,148,[ClearConfigurationParameters:RegCreateKey %s]
+es,frame,149,[ClearConfigurationParameters:RegEnumKey %s failed]
+es,frame,150,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+es,frame,151,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+es,frame,152,[Unable to allocate Subject property list.\n]
+es,frame,153,[Unable to set session ptr in Subject property list - error=%d\n]
+es,frame,154,[Unable to set request ptr in Subject property list - error=%d\n]
+es,frame,155,[file-cache-valid: cannot stat %s]
+es,frame,156,[file-cache-create: Error stat()ing file %s (%s)]
+es,httpdaemon,-1,[$DBT: httpdaemon in DB file v1 $]
+es,httpdaemon,1,[Error in ConvertThreadToFiber]
+es,httpdaemon,2,[Error in ConvertThreadToFiber]
+es,httpdaemon,3,[Error in md_start_system]
+es,httpdaemon,4,[Error in CreateFiber - idlefiber]
+es,httpdaemon,5,[Error in GetQueuedCompletionStatus]
+es,httpdaemon,6,[Error creating completion port]
+es,httpdaemon,7,[Could not SetHandleNonInheritable (%s)]
+es,httpdaemon,8,[Error accept/read new conn]
+es,httpdaemon,9,[Error in Respond()]
+es,httpdaemon,10,[Error in RespondCompleted()]
+es,httpdaemon,11,[daemon: unable to fork new process (%s)\n]
+es,httpdaemon,12,[daemon: setsid failed (%s)\n]
+es,httpdaemon,13,[daemon: can't log pid to %s (%s)\n]
+es,httpdaemon,14,[warning: could not set group id to %d (%s)\n]
+es,httpdaemon,15,[warning: could not set user id to %d (%s)\n]
+es,httpdaemon,16,[warning: daemon is running as super-user\n]
+es,httpdaemon,17,[could not determine current user name\n]
+es,httpdaemon,18,[error: chroot to %s failed (%s)\n]
+es,httpdaemon,19,[WARNING! netscape executable and library have different versions.\n]
+es,httpdaemon,20,[startup: listening to %s://%s, port %d as %s\n]
+es,httpdaemon,21,[startup: listening to %s://%s, port %d as %s\n]
+es,httpdaemon,22,[seminit failed (%s)\n]
+es,httpdaemon,23,[Using single threaded accepts.]
+es,httpdaemon,24,[Using multi threaded accepts.]
+es,httpdaemon,25,[Using partial single threaded accepts.]
+es,httpdaemon,26,[This machine has %d processors.]
+es,httpdaemon,27,[Error calling thr_seconcurrency(%d)- (%s)]
+es,httpdaemon,28,[Set conncurrency to %d.]
+es,httpdaemon,29,[can't fork new process (%s)]
+es,httpdaemon,30,[This beta software has expired.\n]
+es,httpdaemon,31,[can't create IPC pipe (%s)]
+es,httpdaemon,32,[write to wakeup pipe failed (%s)]
+es,httpdaemon,33,[select thread miss]
+es,httpdaemon,34,[startup failure: could not bind to port %d (%s)\n]
+es,httpdaemon,35,[startup failure: could not bind to port %d, IP address %s (%s)\n]
+es,libaccess,-1,[$DBT: libaccess in DB file v1 $]
+es,libaccess,1,[basic-ncsa]
+es,libaccess,2,[cannot open database %s]
+es,libaccess,3,[basic-ncsa]
+es,libaccess,4,[user %s password did not match database %s]
+es,libaccess,5,[basic-ncsa]
+es,libaccess,6,[cannot open connection to LDAP server on %s:%d]
+es,libaccess,7,[basic-ncsa]
+es,libaccess,8,[user %s password did not match LDAP on %s:%d]
+es,libaccess,9,[acl-state]
+es,libaccess,10,[missing realm]
+es,libaccess,11,[Unable to allocate ACL List Hash\n]
+es,libaccess,12,[ACLEvalBuildContext unable to PERM_MALLOC cache structure\n]
+es,libaccess,13,[ACLEvalBuildContext unable to create hash table\n]
+es,libaccess,14,[ACLEvalBuildContext unable to allocate ACE Entry\n]
+es,libaccess,15,[ACLEvalBuildContext unable to allocate ACE entry\n]
+es,libaccess,16,[ACLEvalBuildContext unable to allocate Boundary Entry\n]
+es,libaccess,17,[ACLEvalBuildContext failed.\n]
+es,libaccess,18,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n]
+es,libaccess,19,[LASDnsBuild unable to allocate hash table header\n]
+es,libaccess,20,[LASDnsBuild unable to add key %s\n]
+es,libaccess,21,[LASDnsBuild unable to add key %s\n]
+es,libaccess,22,[LASDnsBuild unable to add key %s\n]
+es,libaccess,23,[LASDnsBuild unable to add key %s\n]
+es,libaccess,24,[LASDnsBuild unable to add key %s\n]
+es,libaccess,25,[LAS DNS build received request for attribute %s\n]
+es,libaccess,26,[LASDnsEval - illegal comparator %s\n]
+es,libaccess,27,[LASDnsEval unable to allocate Context struct\n\n]
+es,libaccess,28,[LASDnsEval unable to get session address %d\n]
+es,libaccess,29,[LASDnsEval unable to get DNS - error=%s\n]
+es,libaccess,30,[LAS Group Eval received request for attribute %s\n]
+es,libaccess,31,[LASGroupEval - illegal comparator %s\n]
+es,libaccess,32,[LASGroupEval - ran out of memory\n]
+es,libaccess,33,[LASGroupEval unable to get session address %d\n]
+es,libaccess,34,[LASGroupEval unable to get session address %d\n]
+es,libaccess,35,[LASGroupEval - couldn't locate getter for auth-user\n]
+es,libaccess,36,[LASGroupEval - Attribute getter for auth-user failed\n]
+es,libaccess,37,[LASGroupEval - Attribute getter didn't set auth-user\n]
+es,libaccess,38,[Check group membership of user "%s" for group "%s"\n]
+es,libaccess,39,[LDAPU_SUCCESS for group "%s"\n]
+es,libaccess,40,[LDAPU_FAILED for group "%s"\n]
+es,libaccess,41,[LAS_EVAL_FALSE\n]
+es,libaccess,42,[LAS_EVAL_TRUE\n]
+es,libaccess,43,[LASIpTreeAlloc - no memory\n]
+es,libaccess,44,[IP LAS unable to allocate tree node\n]
+es,libaccess,45,[IP LAS unable to allocate tree node\n]
+es,libaccess,46,[LAS IP build received request for attribute %s\n]
+es,libaccess,47,[LASIpEval - illegal comparator %s\n]
+es,libaccess,48,[LASIpEval unable to get session address - error=%s\n]
+es,libaccess,49,[LASIpEval unable to allocate Context struct\n\n]
+es,libaccess,50,[LASIpEval - reach 32 bits without conclusion value=%s]
+es,libaccess,51,[LAS Program Eval received request for attribute %s\n]
+es,libaccess,52,[LASProgramEval - illegal comparator %s\n]
+es,libaccess,53,[LASProgram unable to get session address %d\n]
+es,libaccess,54,[bin]
+es,libaccess,55,[LASProgramEval: request not of type admin or bin, passing.\n]
+es,libaccess,56,[LASProgramEval: check if program %s matches pattern %s.\n]
+es,libaccess,57,[LASProgramEval: Invalid wildcard expression %s.\n]
+es,libaccess,58,[LAS_EVAL_FALSE\n]
+es,libaccess,59,[LAS_EVAL_TRUE\n]
+es,libaccess,60,[Unexpected attribute in dayOfWeek - %s\n]
+es,libaccess,61,[Illegal comparator for dayOfWeek - %s\n]
+es,libaccess,62,[Unexpected attribute in timeOfDay - %s\n]
+es,libaccess,63,[LAS User Eval received request for attribute %s\n]
+es,libaccess,64,[LASUserEval - illegal comparator %s\n]
+es,libaccess,65,[LASUserEval - ran out of memory\n]
+es,libaccess,66,[LASUserEval unable to get session address %d\n]
+es,libaccess,67,[LASUserEval unable to get session address %d\n]
+es,libaccess,68,[LASGroupEval - couldn't locate getter for auth-user\n]
+es,libaccess,69,[LASGroupEval - Attribute getter for auth-user failed\n]
+es,libaccess,70,[LASGroupEval - Attribute getter didn't set auth-user\n]
+es,libaccess,71,[Check if uid == user (i.e. check "%s" == "%s)"\n]
+es,libaccess,72,[SUCCESS for user "%s"\n]
+es,libaccess,73,[FAILED for user "%s"\n]
+es,libaccess,74,[LAS_EVAL_FALSE\n]
+es,libaccess,75,[LAS_EVAL_TRUE\n]
+es,libaccess,76,[]
+es,libaccess,77,[LASProgram unable to get request address - error=%s]
+es,libaccess,78,[LASProgram rejecting request for program %s from pattern %s]
+es,libaccess,79,[ACL_CacheFlush: unable to parse file "%s"\n]
+es,libaccess,80,[ACL_CacheFlush: unable to concatenate ACL list "%s"\n]
+es,libaccess,81,[ACL_CacheFlush: unable to open and process the magnus file "%s"\n]
+es,libaccess,82,[Illegal comparator for timeOfDay - %s\n]
+es,libaccess,83,[ACL_EvalBuildContext unable to create hash table\n]
+es,libaccess,84,[ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n]
+es,libaccess,85,[ACL_EvalBuildContext unable to allocate ACE entry\n]
+es,libaccess,86,[ACL_EvalBuildContext unable to allocate auth pointer array\n]
+es,libaccess,87,[ACL_EvalBuildContext unable to allocate auth plist\n]
+es,libaccess,88,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n]
+es,libaccess,89,[ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n]
+es,libaccess,90,[ACL_ModuleRegister: module name is missing\n]
+es,libaccess,91,[ACL_ModuleRegister: call to module init function returned a failed status\n]
+es,libaccess,92,[ACL_GetAttribute: couldn't determine method for %s\n]
+es,libaccess,93,[ACL_GetAttribute: couldn't locate getter for %s]
+es,libaccess,94,[ACL_GetAttribute: attr getter failed to get %s]
+es,libaccess,95,[ACL_GetAttribute: attr getter failed to get %s]
+es,libaccess,96,[ACL_GetAttribute: All attribute getters declined for attr %s]
+es,libaccess,97,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+es,libaccess,98,[ACL_DatabaseRegister: database name is missing]
+es,libaccess,99,[Error reading the DB Map File: %s. Reason: %s]
+es,libaccess,100,[URL is missing for database %s]
+es,libaccess,101,[Invalid property value pair for database %s]
+es,libaccess,102,["default" database must be an LDAP database]
+es,libaccess,103,[Multiple "default" databases are being registered]
+es,libaccess,104,["default" LDAP database must be registered]
+es,libaccess,105,[LASGroupEval unable to get database name - error= %s]
+es,libaccess,106,[received invalid program expression %s]
+es,libaccess,107,[parse_ldap_url: database url is missing]
+es,libaccess,108,[parse_ldap_url: database name is missing]
+es,libaccess,109,[parse_ldap_url: error in parsing ldap url. Reason: %s]
+es,libaccess,110,[ldap password check: unable to get database name - error=%s]
+es,libaccess,111,[ldap password check: unable to get parsed database %s]
+es,libaccess,112,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+es,libaccess,113,[ldap password check: LDAP error: "%s"]
+es,libaccess,114,[get_user_ismember_ldap unable to get database name - error=%s]
+es,libaccess,115,[get_user_ismember_ldap unable to get parsed database %s]
+es,libaccess,116,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+es,libaccess,117,[get_user_ismember_ldap: group %s does not exist]
+es,libaccess,118,[get_user_ismember_ldap: LDAP error: "%s"]
+es,libaccess,119,[ACL_LDAPDatabaseHandle: %s is not a registered database]
+es,libaccess,120,[ACL_LDAPDatabaseHandle: %s is not an LDAP database]
+es,libaccess,121,[ACL_LDAPDatabaseHandle: out of memory]
+es,libaccess,122,[ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s]
+es,libaccess,123,[ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s]
+es,libaccess,124,[insufficient dynamic memory]
+es,libaccess,125,[error opening file, %s: %s]
+es,libaccess,126,[duplicate definition of %s]
+es,libaccess,127,[file %s, line %s: duplicate definition of %s]
+es,libaccess,128,[file %s, line %s: syntax error]
+es,libaccess,129,[file %s, line %s: %s is undefined]
+es,libaccess,130,[in acl %s, %s %s is undefined]
+es,libaccess,131,[database %s: error accessing %s]
+es,libaccess,132,[%s]
+es,libaccess,133,[file %s, line %s: invalid syntax]
+es,libaccess,134,[file %s, line %s: syntax error at "%s"]
+es,libaccess,135,[realm %s is not defined]
+es,libaccess,136,[error code = %d]
+es,libaccess,137,[internal ACL error]
+es,libaccess,138,[invalid argument]
+es,libaccess,139,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+es,libaccess,140,[couldn't determine dbtype from: %s]
+es,libaccess,141,[Failed to register database %s]
+es,libaccess,142,[ACL call returned failed status]
+es,libaccess,143,[file %s: ACL IO error - %s]
+es,libaccess,144,[acl_user_exists: memoria agotada]
+es,libaccess,145,[acl_user_exists: ya no existe el usuario]
+es,libaccess,146,[acl_user_exists: error de plist]
+es,libadmin,-1,[$DBT: libadmin in DB file v1 $]
+es,libadmin,1,[ Help ]
+es,libadmin,2,[ OK ]
+es,libadmin,3,[ Reset ]
+es,libadmin,4,[ Done ]
+es,libadmin,5,[ Cancel ]
+es,libir,-1,[$DBT: libadmin in DB file v1 $]
+es,libir,1,[An I/O error occurred before all form data could be read.]
diff --git a/l10n/dirserv/es/ns-slapd.txt.iso8859 b/l10n/dirserv/es/ns-slapd.txt.iso8859
new file mode 100644
index 00000000..3298ce5a
--- /dev/null
+++ b/l10n/dirserv/es/ns-slapd.txt.iso8859
@@ -0,0 +1,874 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/**************************************************************************/
+/* The copyright notice(s) in this Source Code does not indicate actual */
+/* or intended publication of this Source Code. */
+/**************************************************************************/
+
+/* This text file was generated by program dblink */
+
+$Revision: 1.1 $
+$Log: ns-slapd.txt.iso8859,v $
+Revision 1.1 2005/01/21 00:40:48 cvsadm
+Initial revision
+
+Revision 1.1.8.3 2003/09/22 19:36:42 ulfw
+Update copyright years from 2001 to 2001-2003
+
+Revision 1.1.8.2 2001/11/03 01:06:41 richm
+XXX use new copyright XXX
+
+Revision 1.1.8.1 1998/10/10 02:14:04 ggood
+Copy from Directory40RtmBranchpoint to DirectoryBranch
+
+Revision 1.1.2.1 1997/12/24 01:14:39 werudge
+Based on en/ns-slapd.txt : 1.1.2.3
+daily 971113.1 SOLARIS-export-optimize-normal-slapd
+$EndLog$
+
+$StartStringData$
+
+es,base,-1,[$DBT: base in DB file v1 $]
+es,base,1,[no hay memoria suficiente para crear la tabla de totales de control]
+es,base,2,[no hay memoria suficiente para crear la tabla de totales de control]
+es,base,3,[cache_destroy: las tablas caché parecen dañadas.]
+es,base,4,[no ha sido posible asignar la entrada de total de control]
+es,base,5,[cache_insert: no ha sido posible crear la entrada caché]
+es,base,6,[HTTP/1.0 200 OK\nContent-type: text/html\n\n]
+es,base,7,[<H2>Informe de estado de caché de Netscape</H2>\n]
+es,base,8,[El sistema no tiene cachés<P>]
+es,base,9,[<H2>Caché %s</H2>\n]
+es,base,10,[Índice de aciertos de caché: %d/%d (%f)</P>\n</P>\n]
+es,base,11,[Tamaño de caché: %d/%d</P>\n</P>\n]
+es,base,12,[Tamaño de la tabla de totales de control: %d</P>\n</P>\n]
+es,base,13,[mru : %d</P>\nlru : %d</P>\n]
+es,base,14,[<UL><TABLE BORDER=4> <TH>Sector de almacenamiento</TH> <TH>Dirección</TH> <TH>Clave</TH> <TH>Recuento de accesos</TH> <TH>Eliminar</TH> <TH>Siguiente</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>Datos</TH>\n]
+es,base,15,[munmap failed (%s)]
+es,base,16,[munmap failed (%s)]
+es,base,17,[close failed (%s)]
+es,base,18,[daemon: unable to fork new process (%s)\n]
+es,base,19,[daemon: setsid failed (%s)\n]
+es,base,20,[daemon: can't log pid to %s (%s)\n]
+es,base,21,[warning: could not set group id to %d (%s)\n]
+es,base,22,[warning: could not set user id to %d (%s)\n]
+es,base,23,[warning: daemon is running as super-user\n]
+es,base,24,[could not determine current user name\n]
+es,base,25,[error: chroot to %s failed (%s)\n]
+es,base,27,[, address %s]
+es,base,28,[warning: statistics disabled (%s)\n]
+es,base,29,[security handshake timed out for pid %d]
+es,base,30,[warning: statistics disabled (%s)\n]
+es,base,31,[secure handshake failed (code %d)\n]
+es,base,32,[accept failed (%s)]
+es,base,33,[warning: statistics disabled (%s)\n]
+es,base,34,[select thread miss]
+es,base,35,[keepalive worker awoken with no work to do]
+es,base,36,[could not create new thread: %d (%s)]
+es,base,37,[wait for sema succeeded, but nothing to dequeue]
+es,base,38,[queue-sema creation failure]
+es,base,39,[error getting processor info for processor %d]
+es,base,40,[Error binding to processor %d]
+es,base,41,[bound process %d to processor %d]
+es,base,42,[Netscape server is not explicitly binding to any processors.]
+es,base,43,[cache monitor exited]
+es,base,44,[cache batch update daemon exited]
+es,base,45,[Using single threaded accepts.]
+es,base,46,[Using multi threaded accepts.]
+es,base,47,[Using partial single threaded accepts.]
+es,base,48,[This machine has %d processors.]
+es,base,49,[Error calling thr_seconcurrency(%d)- (%s)]
+es,base,50,[Set conncurrency to %d.]
+es,base,51,[WARNING! netscape executable and library have different versions.\n]
+es,base,54,[seminit failed (%s)\n]
+es,base,55,[This beta software has expired.\n]
+es,base,56,[Cache monitor respawned]
+es,base,57,[Cache batch update daemon respawned]
+es,base,58,[can't find empty statistics slot]
+es,base,59,[can't fork new process (%s)]
+es,base,60,[assert failed! %s\n]
+es,base,61,[mr_table_init()]
+es,base,62,[malloc failed]
+es,base,63,[malloc failed!]
+es,base,64,[mr_add_io(%d, type %d, file %d)]
+es,base,65,[mr_add_io - stage 1]
+es,base,66,[mr_add_io - stage 2]
+es,base,67,[mr_add_io found invalid IO type %d]
+es,base,68,[mr_add_io - adding timeout]
+es,base,69,[Out of memory!\n]
+es,base,70,[done with mr_add_io]
+es,base,71,[mr_del_io(%d, type %d, file %d)]
+es,base,72,[mr_del_io found invalid IO type %d]
+es,base,73,[mr_lookup_io(%d)]
+es,base,74,[mr_async_io(%d, %d bytes, file %d)]
+es,base,75,[malloc failure adding async IO]
+es,base,76,[Error adding async io!]
+es,base,77,[Cannot seek for read!]
+es,base,78,[read failure! (%d, %s)]
+es,base,79,[do_read read %d bytes for file %d]
+es,base,80,[Cannot seek for write!]
+es,base,81,[writev failure! (%d, %s)]
+es,base,82,[write failure! (%d, %s)]
+es,base,83,[do_write wrote %d bytes for file %d]
+es,base,84,[do_timeout(mrp %d)]
+es,base,85,[do_timeout: found IO (timer=%d, time=%d)]
+es,base,86,[error deleting io]
+es,base,87,[timeout callback failure for %d\n]
+es,base,88,[mr_get_event(%d) - outstanding io %d]
+es,base,89,[mr_get_event: Waiting for reads on FD:]
+es,base,90,[mr_get_event: Waiting for writes on FD:]
+es,base,91,[ %d]
+es,base,92,[ %d]
+es,base,93,[mr_get_event set no timeout]
+es,base,94,[mr_get_event set timeout to: %d.%d sec]
+es,base,95,[error in select (%d, %s)]
+es,base,96,[mr_get_event() - select found %d]
+es,base,97,[error looking up IO fd %d]
+es,base,98,[read failed for fd %d]
+es,base,99,[error deleting io]
+es,base,100,[callback failure for %d\n]
+es,base,101,[error looking up IO fd %d]
+es,base,102,[writing: header len %d, writelen %d, total %d]
+es,base,103,[write failed for fd %d]
+es,base,104,[error deleting io]
+es,base,105,[callback failure for %d\n]
+es,base,106,[Error creating dns cache]
+es,base,107,[dns_cache_init: hash_size <= 0, using %d]
+es,base,108,[dns_cache_init: cache-size <= %d, using %d]
+es,base,109,[dns_cache_init: cache-size is %d is too large, using %d.]
+es,base,110,[dns_cache_init: expire_time <= 0, using %d]
+es,base,111,[dns_cache_init: expire is %d is too large, using %d seconds.]
+es,base,112,[Error creating dns cache]
+es,base,113,[dns-cache-insert: Error allocating entry]
+es,base,114,[dns-cache-insert: malloc failure]
+es,base,115,[successful server startup]
+es,base,116,[%s B%s]
+es,base,117,[Netscape executable and shared library have different versions]
+es,base,118,[ executable version is %s]
+es,base,119,[ shared library version is %s]
+es,base,120,[error reporting shutting down]
+es,base,121,[warning]
+es,base,122,[config]
+es,base,123,[security]
+es,base,124,[failure]
+es,base,125,[catastrophe]
+es,base,126,[info]
+es,base,127,[verbose]
+es,base,128,[event_handler:Failed to wait on events %s]
+es,base,129,[could not wait on resume event event (%s)]
+es,base,130,[dlopen of %s failed (%s)]
+es,base,131,[dlopen of %s failed (%s)]
+es,base,132,[The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!]
+es,base,133,[Terminating the server %s]
+es,base,134,[kill_server:cannot open server event %s]
+es,base,135,[kill_server:cannot set server event %s]
+es,base,136,[error: could not get socket (%s)\n]
+es,base,137,[error: could not set socket option (%s)\n]
+es,base,138,[Terminating Service:error: could not bind to address %s port %d (%s)\n]
+es,base,139,[Terminating Service:error: could not bind to port %d (%s)\n]
+es,base,140,[SetHandleNonInheritable: could not duplicate socket (%s)]
+es,base,141,[SetHandleNonInheritable: closing the original socket failed (%s)]
+es,base,142,[Could not SetHandleInformation (%s)]
+es,base,143,[Terminating Service:Failure: Could not open statistics file (%s)\n]
+es,base,144,[Could not set Thread Local Storage Value for thread at slot %d]
+es,base,145,[secure handshake failed (code %d)\n]
+es,base,146,[accept failed %d (%s)]
+es,base,147,[Failed to pulse Event %d %s]
+es,base,148,[Failed to send MobGrowth Event to parent %s]
+es,base,149,[Pulsing MobRespawn Event %d]
+es,base,150,[respawn thread pool to %d (%d)]
+es,base,151,[Could not open event to signal rotate application. Could not create the MoveLog event:%s]
+es,base,152,[Failed to send MoveLog Event to rotate app %s]
+es,base,153,[growing thread pool from %d to %d]
+es,base,154,[Could not open the ServiceControlManager, Error %d]
+es,base,155,[StartNetsiteService:Could not open the service %s: Error %d]
+es,base,156,[StartNetsiteService:Could not start the service %s]
+es,base,157,[Service Startup: Could not allocate security descriptor]
+es,base,158,[Service Startup: Could not init security descriptor]
+es,base,159,[Service Startup: Could not set the security Dacl]
+es,base,160,[Terminating Service:WinSock init failed: %s]
+es,base,161,[Httpd Server Startup failed: %s]
+es,base,162,[can't find empty statistics slot]
+es,base,163,[NT daemon: could not create new thread %d]
+es,base,164,[Service Startup Failure. Terminating Service:Could not create event %d:%s]
+es,base,165,[Service Startup Error. Could not create the MoveLog event:%s]
+es,base,166,[Failed to wait on Event objects %s]
+es,base,167,[Failed to wait on Event objects %s]
+es,base,168,[pipebuf_buf2sd: pipebuf_grab IO_ERROR %d]
+es,base,169,[pool-init: memory pools disabled]
+es,base,170,[pool-init: free_size <= 0, using %d]
+es,base,171,[pool-create-block: out of memory]
+es,base,172,[pool-create: out of memory]
+es,base,173,[pool-create: out of memory]
+es,base,174,[pool-malloc: out of memory]
+es,base,175,[FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.]
+es,base,176,[regex error: %s (regex: '%s')]
+es,base,177,[can't create IPC pipe (%s)]
+es,base,178,[write to wakeup pipe failed (%s)]
+es,base,179,[flushing %d connections; current %d; tot %d]
+es,base,180,[accept failed (%s)]
+es,base,181,[Error creating time cache]
+es,base,182,[time-cache: cache disabled]
+es,base,183,[time_cache_init: hash_size < %d, using default, %d]
+es,base,184,[time_cache_init: hash_size > %d, using default, %d]
+es,base,185,[time_cache_init: cache_size < %d, using default, %d]
+es,base,186,[time_cache_init: cache_size > %d, using default, %d]
+es,base,187,[Error allocating memory for time_cache]
+es,base,188,[Error allocating memory for time_cache entry]
+es,base,189,[Error allocating memory for time_cache entry]
+es,base,190,[Error inserting new time_cache entry]
+es,base,191,[Error allocating memory for time_cache]
+es,base,192,[cs-terminate failure (%s)]
+es,base,193,[cs-init failure (%s)]
+es,base,194,[cs-wait failure (%s)]
+es,base,195,[cs-post failure (%s)]
+es,base,196,[Unable to create nonblocking socket (%s)]
+es,base,197,[error: could not set keepalive (%s)\n]
+es,base,198,[error: could not set recv timeout (%s)\n]
+es,base,199,[error: could not set send timeout (%s)\n]
+es,base,200,[Unable to create nonblocking socket (%s)]
+es,base,201,[sem_grab failed (%s)]
+es,base,202,[sem_release failed (%s)]
+es,base,203,[sem_release failed (%s)]
+es,base,204,[Could not remove temporary directory %s, Error %d]
+es,base,205,[Could not remove temporary directory %s, Error %d]
+es,dsgw,-1,[$DBT: dsgw in DB file v1 $]
+es,dsgw,1,[Se desconoce el método de solicitud HTTP]
+es,dsgw,2,[Los datos del formulario HTML no son válidos o son incompletos]
+es,dsgw,3,[Memoria agotada]
+es,dsgw,4,[Falta una entrada necesaria de solicitud/formulario]
+es,dsgw,5,[La vía de acceso contiene caracteres no válidos]
+es,dsgw,6,[Falta el archivo de configuración o está dañado]
+es,dsgw,7,[Imposible inicializar el protocolo LDAP]
+es,dsgw,8,[Se ha producido un error al establecer contacto con el servidor LDAP]
+es,dsgw,9,[Se desconoce el tipo de objeto de búsqueda]
+es,dsgw,10,[Se desconoce la etiqueta de atributo]
+es,dsgw,11,[Se desconoce el indicador de correspondencia]
+es,dsgw,12,[El tipo de objeto no tiene filtros de búsqueda]
+es,dsgw,13,[Imposible abrir el archivo de la plantilla HTML]
+es,dsgw,14,[Se desconoce el modo de búsqueda: utilice "smart", "complex", "pattern" o "auth"]
+es,dsgw,15,[Falta un nombre distinguido en el URL]
+es,dsgw,16,[Se desconoce un ámbito del URL (debe ser base, sub o one)]
+es,dsgw,17,[No se reconoce el URL o hay un error desconocido]
+es,dsgw,18,[El formato del URL no es correcto]
+es,dsgw,19,[Error interno]
+es,dsgw,20,[Imposible escribir en el archivo de índices de la plantilla]
+es,dsgw,21,[Imposible abrir el archivo de índice de plantillas]
+es,dsgw,22,[Imposible leer el directorio]
+es,dsgw,23,[Ha fallado la inicialización SSL LDAP (compruebe la vía de acceso de seguridad)]
+es,dsgw,24,[Para que los formularios Usuarios y Grupos funcionen mediante SSL, usted o el administrador del servidor tiene que activar SSL en este Administration Server. Para ello, puede utilizar la página Cifrado|activado/desactivado]
+es,dsgw,25,[No se han encontrado las credenciales de autentificación en la base de datos de autentificación]
+es,dsgw,26,[Error al recuperar datos de la base de datos de autentificación]
+es,dsgw,27,[Sus credenciales de autentificación han caducado]
+es,dsgw,28,[Imposible crear una cadena aleatoria]
+es,dsgw,29,[No se ha especificado un nombre distinguido al recuperar credenciales]
+es,dsgw,30,[No se puede abrir la base de datos de autentificación]
+es,dsgw,31,[No ha sido posible añadir los datos a la base de datos de autentificación]
+es,dsgw,32,[No se ha definido un Gestor de directorios]
+es,dsgw,33,[No se ha especificado una cadena de búsqueda. Vuelva a intentarlo]
+es,dsgw,34,[Una de las líneas del archivo config. contiene demasiados argumentos]
+es,dsgw,35,[No ha sido posible inicializar Windows Sockets]
+es,dsgw,36,[No se han recibido las credenciales de autentificación del Administration Server]
+es,dsgw,37,[Falta un nombre distinguido en el URL ldapdb://]
+es,dsgw,38,[No se reconoce el URL o hay un error desconocido]
+es,dsgw,39,[El formato del URL no es correcto]
+es,dsgw,40,[Se ha producido un error al inicializar la base de datos ldap local]
+es,dsgw,41,[Se desconoce el tipo de servicio de directorios: utilice "local" o "remote"]
+es,dsgw,42,[Se ha producido un error al leer el archivo de configuración de base de datos]
+es,dsgw,43,[La vía de acceso a NSHOME/userdb tenía el valor NULL]
+es,dsgw,44,[No ha sido posible actualizar la configuración del servicio de directorios.]
+es,dsgw,45,[No ha sido posible leer la entrada desde el directorio.]
+es,dsgw,46,[No ha sido posible borrar la base de datos LDAP.]
+es,dsgw,47,[No está autorizado a cambiar otras entradas que no sean las suyas propias.]
+es,dsgw,48,[Problema]
+es,dsgw,49,[Problema de autentificación]
+es,dsgw,50,[.\n<P>Debe repetir la autentificación para poder continuar.\n]
+es,dsgw,51,[.\n<P>Debe repetir la autentificación para poder continuar.\n]
+es,dsgw,52,[error desconocido]
+es,dsgw,53,[La operación se ha realizado con éxito.]
+es,dsgw,54,[Se ha producido un error interno en el servidor. Por lo general,\nesto indica un fallo grave del servidor.\nComuníqueselo al administrador del servidor.]
+es,dsgw,55,[El servidor no ha entendido la solicitud que le ha llegado desde\nla pasarela.]
+es,dsgw,56,[Se ha sobrepasado el límite de tiempo para responder a su solicitud.\nSi lo que busca son entradas, es posible que obtenga mejores\nresultados si realiza una búsqueda más específica.]
+es,dsgw,57,[Se ha sobrepasado el límite de tamaño para responder a su solicitud.\nSi lo que busca son entradas, es posible que obtenga mejores\nresultados si realiza una búsqueda más específica, ya que existen\ndemasiadas entradas que cumplen los criterios de búsqueda.]
+es,dsgw,58,[La pasarela ha intentado autentificarse en el servidor\nmediante un método que el servidor no entiende.]
+es,dsgw,59,[La pasarela ha intentado autentificarse ante el servidor mediante un\nmétodo de autentificación incompatible con el servidor. ]
+es,dsgw,60,[No ha sido posible atender su solicitud, probablemente porque\nel servidor con el que se ha establecido contacto no contiene los datos que\nusted busca. Es posible que se haya recibido\nuna referencia a otro servidor\nal que no es posible acceder. Si tenía la intención\n de realizar cambios en el directorio, puede que no esté disponible el servidor\nque contiene la copia maestra de los datos.]
+es,dsgw,61,[Su solicitud ha sobrepasado un límite administrativo en el servidor.]
+es,dsgw,62,[La pasarela ha solicitado una extensión crítica que no está disponible en el servidor.]
+es,dsgw,63,[El servidor no ha podido procesar la solicitud debido a que\nésta contiene una referencia a un atributo que no\nexiste en la entrada.]
+es,dsgw,64,[El servidor no ha podido atender la solicitud debido a que\nésta no cumple con una restricción de la base de datos.]
+es,dsgw,65,[El servidor no ha podido añadir un valor a la entrada debido a que\ndicho valor ya está incluido en la entrada.]
+es,dsgw,66,[El servidor no ha encontrado la entrada. Si desea añadir\nuna entrada, compruebe que exista su entrada primaria. Si este error\nse ha producido durante una búsqueda, indica que no existe\nla entrada que se está buscando.\nSi ha intentado autentificarse como gestor de directorios y se ha producido\neste error, compruebe el archivo de configuración de la pasarela.]
+es,dsgw,67,[Un nombre distinguido no tenía el formato correcto. ]
+es,dsgw,68,[Ha intentado autentificarse mediante una entrada que no tiene un\nconjunto de contraseñas o que carece de otras credenciales\nnecesarias para la autentificación. No podrá utilizar esa entrada para la autentificación\nhasta que el gestor de directorios haya añadido\nlos atributos correspondientes.]
+es,dsgw,69,[La contraseña u otras credenciales de autentificación especificadas\nno son correctas.]
+es,dsgw,70,[No dispone de suficientes derechos de acceso para realizar la operación. ]
+es,dsgw,71,[El servidor está demasiado ocupado para atender su\nsolicitud. Vuelva a intentarlo dentro de unos minutos.]
+es,dsgw,72,[No ha sido posible establecer contacto con el servidor LDAP.]
+es,dsgw,73,[El servidor se ha negado a procesar su solicitud,\nprobablemente porque se saturaría durante la operación. También puede indicar que el servidor no está\nconfigurado para procesar su solicitud. Si está realizando una búsqueda,\nquizás convenga limitar el ámbito de la misma.]
+es,dsgw,74,[El servidor de directorios no ha podido atender su solicitud porque\nno cumple con los requisitos del esquema. Normalmente, esto suele indicar\nque no se ha especificado el valor de un campo necesario, aunque también\npodría indicar que es necesario actualizar el esquema del servidor de directorios.]
+es,dsgw,75,[El servidor de directorios no permite eliminar una entrada\nni cambiarle el nombre si tiene entradas secundarias. Si desea realizar esta operación,\ndeberá eliminar en primer lugar todas las entradas secundarias.]
+es,dsgw,76,[El servidor no ha podido añadir una entrada nueva o cambiar el nombre de\nuna entrada ya existente porque ese nombre ya se utiliza.]
+es,dsgw,77,[Su solicitud afectaría a varios servidores de directorios.]
+es,dsgw,78,[No ha sido posible establecer contacto con el servidor de directorios.\nConsulte con el administrador del servidor.]
+es,dsgw,79,[Se ha producido un error al enviar datos al servidor.]
+es,dsgw,80,[Se ha producido un error al leer datos desde el servidor.]
+es,dsgw,81,[El servidor no ha respondido a la solicitud.\nHa vencido el tiempo de espera de la solicitud.]
+es,dsgw,82,[El servidor no admite el método de autentificación que\nutiliza la pasarela.]
+es,dsgw,83,[El filtro de búsqueda que ha formado la pasarela tiene un error.]
+es,dsgw,84,[La operación se ha cancelado a solicitud del usuario.]
+es,dsgw,85,[Se ha producido un error interno en la biblioteca: un parámetro\nera incorrecto.]
+es,dsgw,86,[No ha sido posible abrir una conexión con el servidor.\nConsulte con el administrador del servidor.]
+es,dsgw,87,[Se ha producido un error desconocido.]
+es,dsgw,88,[La entrada ya existe]
+es,dsgw,89,[Ya existe una entrada con el nombre ]
+es,dsgw,90,[onMouseOver="window.status='Haga clic aquí para ver esta entrada'; return true"]
+es,dsgw,91,[ .<P>Elija otro nombre u otra ubicación.\n<P>\n]
+es,dsgw,92,[No existe la entrada primaria]
+es,dsgw,93,[No puede añadir una entrada mediante este nombre:<P><B>%s</B>,<P>\nya que no existe su entrada primaria.<P>\nPara poder añadir esta entrada, deberá añadir en primer lugar\n]
+es,dsgw,94,[su entrada primaria.\n]
+es,dsgw,95,[una entrada con este nombre:<P><B>%s</B>.\n]
+es,dsgw,96,[Advertencia: sin autentificar (continuación)...\n]
+es,dsgw,97,[%s la entrada de directorio]
+es,dsgw,98,[<PRE>DN de la entrada: %s</PRE><P>\n]
+es,dsgw,99,[Han quedado guardados los cambios realizados en <B>%s</B>]
+es,dsgw,100,[<B>%s</B> has been added.]
+es,dsgw,101,[<B>%s</B> has been deleted.]
+es,dsgw,102,[Renamed <B>%s</B> to <B>%s</B>.]
+es,dsgw,103,[<P><B>Nota:</B> debido a que ha %s la entrada que utilizó como\nautentificación, ha sido necesario descartar sus credenciales de \nautentificación. Si desea realizar más cambios,\ndeberá volver a autentificarse.\n]
+es,dsgw,104,[eliminado]
+es,dsgw,105,[cambiado el nombre de]
+es,dsgw,106,[cambiado la contraseña de]
+es,dsgw,107,[Se ha cambiado el atributo %s<BR>\n]
+es,dsgw,108,[ NO ASCII (%ld bytes)\n]
+es,dsgw,109,[No se han introducido valores. Vuelva a intentarlo.\n]
+es,dsgw,110,[No se han realizado cambios.\n]
+es,dsgw,111,[<P>Enviando %s al servidor de directorios...\n]
+es,dsgw,112,[información]
+es,dsgw,113,[cambios]
+es,dsgw,114,[<P>Se ha añadido la entrada sin problemas.\n]
+es,dsgw,115,[<P>Se ha modificado la entrada sin problemas. Los cambios han quedado guardados.\n]
+es,dsgw,116,[<P>Se ha eliminado la entrada sin problemas.\n]
+es,dsgw,117,[<PRE>El nombre nuevo de la entrada es: %s\n</PRE><HR>\n]
+es,dsgw,118,[<P>Se ha cambiado el nombre de la entrada sin problemas.\n]
+es,dsgw,119,[Es necesario especificar la contraseña antigua.]
+es,dsgw,120,[Es necesario especificar una contraseña nueva. Vuelva a intentarlo]
+es,dsgw,121,[La contraseña de confirmación no coincide con la contraseña nueva. Vuelva a intentarlo]
+es,dsgw,122,[<BR>El %s <B>%s</B> ya está en uso. Elija otro.<BR>\n]
+es,dsgw,123,[falta el elemento "%.100s" de los datos del formulario]
+es,dsgw,124,[Inicializando la información de configuración]
+es,dsgw,125,[Imposible abrir el archivo.]
+es,dsgw,126,[Archivo dbconf mal construido.]
+es,dsgw,127,[Falta un nombre de propiedad en el archivo dbconf.]
+es,dsgw,128,[Memoria agotada.]
+es,dsgw,129,[Falta una directiva en el archivo dbconf.]
+es,dsgw,130,[Imposible abrir el archivo de configuración "%s"\n]
+es,dsgw,131,[Falta un argumento en la directiva "authlifetime"\n]
+es,dsgw,132,[Falta un argumento en la directiva "dirmgr"\n]
+es,dsgw,133,[Falta un argumento en la directiva "baseurl"\n]
+es,dsgw,134,[Se ha especificado un URL erróneo para la directiva "baseurl": falta el DN de base\n]
+es,dsgw,135,[analizando la directiva baseurl]
+es,dsgw,136,[Se ha especificado un URL erróneo para la directiva "baseurl": no es un URL "ldap://"\n]
+es,dsgw,137,[Todavía no son compatibles las direcciones URL "ldap://"\n]
+es,dsgw,138,[Faltan argumentos en la directiva "template"\n]
+es,dsgw,139,[Faltan un argumento en la directiva "sslrequired"\n]
+es,dsgw,140,[Se desconoce un argumento de la directiva "sslrequired" (debería ser "never", "whenauthenticated", "always")\n]
+es,dsgw,141,[Falta un argumento en la directiva "securitypath"\n]
+es,dsgw,142,[Falta un argumento en la directiva "location-suffix"\n]
+es,dsgw,143,[La directiva "location" necesita tres argumentos\n]
+es,dsgw,144,[La directiva "newtype" necesita dos argumentos como mínimo\n]
+es,dsgw,145,[Se desconoce una ubicación en la directiva "newtype"\n]
+es,dsgw,146,[La directiva "tmplset" necesita tres o cuatro argumentos\n]
+es,dsgw,147,[La directiva "attrvset" necesita cuatro argumentos\n]
+es,dsgw,148,[Falta un argumento en la directiva "charset"\n]
+es,dsgw,149,[Falta un argumento en la directiva "ClientLanguage"\n]
+es,dsgw,150,[Falta un argumento en la directiva "AdminLanguage"\n]
+es,dsgw,151,[Falta un argumento en la directiva "DefaultLanguage"\n]
+es,dsgw,152,[Falta un nombre de archivo en la directiva "include"\n]
+es,dsgw,153,[Se desconoce una directiva del archivo config\n]
+es,dsgw,154,[<= erase_db no ha podido abrir el archivo lcache.conf "%s"\n]
+es,dsgw,155,[<FONT SIZE="+1">\n<P>Se ha eliminado la base de datos. Creando una base de datos nueva... \n</FONT>\n ]
+es,dsgw,156,[<FONT SIZE="+1">\n<P>No ha sido posible eliminar la base de datos \n</FONT>\n ]
+es,dsgw,157,[<= app_suffix no ha podido abrir el archivo ldif "%s"\n]
+es,dsgw,158,[<= app_suffix no ha podido abrir el archivo temporal "%s"\n]
+es,dsgw,159,[Imposible cambiar el nombre de %s a %s]
+es,dsgw,160,[dbconf_read_default_dbinfo() ha devuelto un puntero NULL.]
+es,dsgw,161,[El URL "ldapdb" es erróneo: falta el DN de base\n]
+es,dsgw,162,[El URL "ldapdb" es erróneo\n]
+es,dsgw,163,[Se ha especificado un URL erróneo en la directiva "baseurl": falta el DN de base\n]
+es,dsgw,164,[analizando la directiva baseurl]
+es,dsgw,165,[Se ha especificado un URL erróneo en la directiva "baseurl": no es un URL "ldap:// o ldapdb://"\n]
+es,dsgw,166,[Todavía no son compatibles las direcciones URL "ldap://"\n]
+es,dsgw,167,[No se ha dado ningún valor para binddn]
+es,dsgw,168,[No se ha dado ningún valor para bindpw]
+es,dsgw,169,[No se ha definido un servicio predeterminado de directorios en el archivo dbswitch.conf]
+es,dsgw,170,[Imposible abrir el archivo de configuración "%s" para escribir en él]
+es,dsgw,171,[Imposible cambiar el nombre de %s a %s]
+es,dsgw,172,[archivo de configuración %s: ]
+es,dsgw,173,[archivo de configuración %s: línea %d: ]
+es,dsgw,174,[máx %d]
+es,dsgw,175,[ OK ]
+es,dsgw,176,[Cerrar la ventana]
+es,dsgw,177,[Retroceder]
+es,dsgw,178,[{crypt}BLOQUEADO [%s GMT]]
+es,dsgw,179,[Volver a la pantalla principal]
+es,dsgw,181,[ Help ]
+es,dsgw,182,[Ayuda]
+es,dsgw,184,[Todavía no hay ayuda disponible.]
+es,dsgw,186,[Cerrar la ventana]
+es,dsgw,187,[Cerrar la ventana]
+es,dsgw,188,[El URL no incluía un nombre de plantilla justo después de "?"]
+es,dsgw,189,[Autentificar...]
+es,dsgw,190,[¿Desea descartar las credenciales de autentificación (finalizar la sesión?]
+es,dsgw,191,[Escriba una cadena de búsqueda]
+es,dsgw,192,[Como primer paso para autentificarse ante el directorio,\n identifíquese.<br>Introduzca su nombre:]
+es,dsgw,193,[Continuar]
+es,dsgw,194,[Continuar]
+es,dsgw,195,[Cancelar]
+es,dsgw,196,[Autentificarse como gestor de directorios"> Â (solamente para los administradores de directorios)\n]
+es,dsgw,197,[Autentificar...]
+es,dsgw,198,[¿Desea descartar las credenciales de autentificación?]
+es,dsgw,200,[Continuar]
+es,dsgw,201,[Continuar]
+es,dsgw,202,[Cancelar]
+es,dsgw,203,[Autentifíquese (inicie la sesión) en el directorio]
+es,dsgw,204,[Está a punto de autentificarse en el directorio como <B>%s</B>. Para concluir el proceso de autentificación, escriba su contraseña.\n]
+es,dsgw,206,[Para poder modificar o añadir entradas, es necesario autentificarse\n(iniciar sesión) en el directorio. Esta ventana le servirá de\nguía para realizar el proceso\nde autentificación.\n]
+es,dsgw,207,[Desde esta pantalla, es posible autentificarse (iniciar sesión)\nen el directorio. Para poder modificar entradas del directorio, es necesario\realizar la autentificación en primer lugar.\nSi intenta modificar una entrada si haberse autentificado,\nel sistema le pedirá que inicie sesión.\n]
+es,dsgw,208,[Estado de la autentificación]
+es,dsgw,209,[<form>\nActualmente, se encuentra autentificado en el directorio como ]
+es,dsgw,210,[.\nSi desea descartar las credenciales de autentificación y finalizar la sesión en el directorio, haga clic en el botón que aparece a continuación.]
+es,dsgw,211,[Descartar credenciales de autentificación (finalizar sesión)]
+es,dsgw,212,[Sus credenciales de autentificación en ]
+es,dsgw,213,[han caducado.\n<HR>\n]
+es,dsgw,214,[Actualmente, no se encuentra autentificado en el directorio.<HR>\n]
+es,dsgw,215,[falta "%s=" ]
+es,dsgw,216,[se desconoce "%s=%s"]
+es,dsgw,217,[se desconoce la opción %s]
+es,dsgw,218,[se desconoce la sintaxis=%s\n]
+es,dsgw,219,[** El tipo de HTML "%s" no es compatible **<BR>\n]
+es,dsgw,224,[Modificar]
+es,dsgw,225,[Save Changes]
+es,dsgw,226,[modify]
+es,dsgw,227,[add]
+es,dsgw,228,[Eliminar]
+es,dsgw,229,[¿Desea eliminar esta entrada?]
+es,dsgw,230,[Cambiar el nombre]
+es,dsgw,231,[Escriba un nombre nuevo para esta entrada:]
+es,dsgw,232,[Modificar como]
+es,dsgw,233,[falta %s=]
+es,dsgw,234,[Cerrar la ventana]
+es,dsgw,235,[Modificar...]
+es,dsgw,236,[falta"%s="\n]
+es,dsgw,237,[se desconoce el conjunto "%s"\n]
+es,dsgw,238,[se desconoce la sintaxis "%s"\n]
+es,dsgw,239,[Repetir la autentificación]
+es,dsgw,240,[Cerrar la ventana]
+es,dsgw,241,[Confirme que desea ]
+es,dsgw,242,[?]
+es,dsgw,243,[ Aceptar ]
+es,dsgw,244,[ Aceptar ]
+es,dsgw,245,[ Restablecer ]
+es,dsgw,246,[ Terminado ]
+es,dsgw,247,[ Cancelar ]
+es,dsgw,248,[se ha encontrado otra sentencia IF (no se admiten las sentencias IF anidadas)]
+es,dsgw,249,[se ha encontrado una sentencia ELSE, pero no aparece la IF]
+es,dsgw,250,[se ha encontrado una sentencia ELSE después de ELSE (se esperaba encontrar ENDIF)]
+es,dsgw,251,[se ha encontrado una sentencia ELIF, pero no aparece la IF]
+es,dsgw,252,[se ha encontrado una sentencia ELIF después de ELSE (se esperaba encontrar ENDIF)]
+es,dsgw,253,[se ha encontrado una sentencia ENDIF, pero no aparece la IF]
+es,dsgw,254,[<BR><B>error de plantilla:</B> %s<BR>\n]
+es,dsgw,255,[se ha intentado el proceso ldap_init/lcache_init antes de leer el archivo de configuración]
+es,dsgw,256,[no se ejecuta bajo el Administration Server]
+es,dsgw,257,[No se han podido inicializar los permisos]
+es,dsgw,258,[No ha sido posible asignar el nombre de usuario a un DN (el Administration Server ha comunicado un error)]
+es,dsgw,259,[No se ha recibido el nombre de usuario actual]
+es,dsgw,260,[No se ha recibido la contraseña del usuario actual]
+es,dsgw,261,[Error: %s]
+es,dsgw,262,[Nota: no se encuentra disponible ninguna plantilla de presentación para este tipo de\nentrada; la entrada se muestra a continuación con un método predeterminado.]
+es,dsgw,263,[La identifación de usuario no es válida o el identifador LDAP tiene el valor NULL]
+es,dsgw,264,[no coincide ninguna identificación de usuario]
+es,dsgw,265,[coinciden varias identificaciones de usuario]
+es,dsgw,266,[the entire directory]
+es,dsgw,267,[La directiva "includeset" necesita dos argumentos\n]
+es,dsgw,268,[No se ha encontrado en esta entrada el valor de atributo solicitado]
+es,dsgw,269,[Falta un argumento en la directiva "NLS"\n]
+es,dsgw,270,[Es necesario especificar un valor de identificación de usuario NT\n ]
+es,dsgw,271,[La combinación de identificaciones de usuario NT y dominio NT ya se utiliza en el directorio\n]
+es,dsgw,272,[Es necesario especificar valores de identificación de usuario NT y de dominio NT\n]
+es,dsgw,273,[La identifiación de usuario NT no puede contener más de 20 caracteres.\n]
+es,dsgw,274,[Especifique el nombre de la entrada nueva.]
+es,dsgw,275,[Seleccione la ubicación de la entrada nueva.]
+es,dsgw,276,[Entrada nueva]
+es,dsgw,277,[Para poder utilizar esta función, el archivo dsgw.conf debe contener una definición de dirmgr]
+es,dsgw,278,[La directiva "vcard-property" necesita tres o cuatro argumentos\n]
+es,dsgw,279,[La sintaxis de la propiedad VCard debe ser "cis" o "mls"\n]
+es,dsgw,280,[No se han encontrado entradas.\n%2$s]
+es,dsgw,281,[No se han encontrado entradas en las que %2$s %3$s '%4$s'.\n]
+es,dsgw,282,[Se ha realizado la búsqueda, pero no se ha encontrado ninguna entrada.\n%2$s]
+es,dsgw,283,[Se ha realizado la búsqueda, pero no se ha encontrado ninguna entrada en la que %2$s %3$s %4$s'.\n]
+es,dsgw,284,[Se ha encontrado 1 entrada.\n%2$s]
+es,dsgw,285,[Se ha encontrado 1 entrada en la que %2$s %3$s '%4$s'.\n]
+es,dsgw,286,[Se ha realizado la búsqueda y se ha encontrado 1 entrada.\n%2$s]
+es,dsgw,287,[Se ha realizado la búsqueda y se ha encontrado 1 entrada en la que %2$s %3$s '%4$s'.\n]
+es,dsgw,288,[Se han encontrado %1$li entradas.\n%2$s]
+es,dsgw,289,[Se han encontrado %1$li entradas en las que %2$s %3$s '%4$s'.\n]
+es,dsgw,290,[Se ha realizado la búsqueda y se han encontrado %1$li entradas.\n%2$s]
+es,dsgw,291,[Se ha realizado la búsqueda y se han encontrado %1$li entradas en las que %2$s %3$s '%4$s'.\n]
+es,dsgw,292,[el filtro LDAP es]
+es,dsgw,293,[El servidor no ha encontrado la entrada que usted ha utilizado el autentificarse. Es posible que se haya eliminado la entrada o que alguien le haya cambiado el nombre. Intente volver a realizar la autentificación.]
+es,dsgw,294,[La sintaxis de la contraseña nueva no es válida.\n]
+es,dsgw,295,[La contraseña nueva ya existe en el historial de contraseñas.\n]
+es,dsgw,296,[Ha sobrepasado el límite de reintentos de contraseña. Consulte con el administrador del sistema.\n]
+es,dsgw,297,[Ha sobrepasado el límite de reintentos de contraseña. Vuelva a intentarlo más adelante.\n]
+es,dsgw,298,[La contraseña ha caducado. Consulte con el administrador del sistema para restablecer la contraseña.\n]
+es,frame,-1,[$DBT: frame in DB file v1 $]
+es,frame,1,[<TITLE>No se ha encontrado</TITLE><H1>No se ha encontrado</H1> El objeto solicitado no existe en este servidor. El vínculo que ha seguido no está actualizado o no es exacto, o bien el servidor ha recibido instrucciones para no permitirle el acceso.]
+es,frame,2,[Informe al administrador de la oficina acerca de la <A HREF="%s">página que contiene la referencia</A>.]
+es,frame,3,[El navegador ha enviado una solicitud que este servidor proxy no ha entendido.]
+es,frame,4,[Es necesario disponer de la autorización adecuada para la administración de\neste servidor proxy. El navegador no puede conceder la autorización,\no la autorización no se ha podido realizar.]
+es,frame,5,[Es necesaria la autentificación de nombre de usuario para utilizar\neste servidor proxy. El navegador no puede conceder la autorización,\no la autorización no se ha podido realizar.]
+es,frame,6,[La configuración de control de acceso al servidor proxy deniega\nel acceso al objeto solicitado mediante este servidor proxy.]
+es,frame,7,[El servidor proxy ha encontrado un error interno que le impide\natender su solicitud. Lo más probable es que se deba a una configuración\nerrónea. Solicite al administrador que examine el registro de errores del servidor proxy.]
+es,frame,8,[Este servidor proxy no utiliza el método solicitado.]
+es,frame,9,[Se ha producido un error en el servidor proxy.]
+es,frame,10,[El navegador ha enviado una consulta que este servidor no ha entendido.]
+es,frame,11,[Es necesario disponer de la autorización adecuada para acceder a esta zona. El navegador no puede conceder la autorización o la autorización no se ha podido realizar]
+es,frame,12,[Su cliente no está autorizado a acceder al objeto que ha solicitado.]
+es,frame,13,[El servidor ha encontrado un error interno que le impide atender su solicitud. Lo más probable es que se deba a una configuración errónea. Solicite al administrador que examine el registro de errores del servidor.]
+es,frame,14,[Este servidor no utiliza el método solicitado.]
+es,frame,15,[Se ha producido un error.]
+es,frame,16,[El navegador ha enviado un mensaje que este servidor no ha entendido.]
+es,frame,17,[<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>\nEste documento ha sido trasladado a otra <a href="%s">ubicación</a>. Actualice los documentos y listas de acceso con los nuevos datos.</BODY></HTML>]
+es,frame,18,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="es"><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>]
+es,frame,19,[process-uri-objects]
+es,frame,20,[cannot find template %s]
+es,frame,21,[process-uri-objects]
+es,frame,22,[no partial path after object processing]
+es,frame,23,[find-service]
+es,frame,24,[invalid shexp %s]
+es,frame,25,[find-service]
+es,frame,26,[invalid shexp %s]
+es,frame,27,[handle-processed]
+es,frame,28,[no way to service request for %s]
+es,frame,29,[finish-socks-request]
+es,frame,30,[close failed (%s), csd=%d]
+es,frame,31,[This beta software has expired.\n]
+es,frame,32,[mr_accept(%d)]
+es,frame,33,[Error issuing read on accept socket]
+es,frame,34,[acb_accept_connection(%d)]
+es,frame,35,[Error getting accept socket (%d)]
+es,frame,36,[Error in accept! (%d, %s)]
+es,frame,37,[Error creating new accept request]
+es,frame,38,[accepted connection: %d (NSPR %d)]
+es,frame,39,[Error creating new session structure]
+es,frame,40,[accel_read_request()]
+es,frame,41,[Error allocating request read buffer]
+es,frame,42,[Error issuing async read request]
+es,frame,43,[acb_read_request(%d, bytes %d)]
+es,frame,44,[acb_read_req(1 session = %d)]
+es,frame,45,[Error reading request (%d, %s)]
+es,frame,46,[Client aborted connection]
+es,frame,47,[Error reading request]
+es,frame,48,[Error creating new request]
+es,frame,49,[error occurred, closing %d, io was for %d]
+es,frame,50,[accel_async_scan_headers()]
+es,frame,51,[out of memory: accel_async_scan_headers]
+es,frame,52,[out of memory: accel_async_scan_headers]
+es,frame,53,[Error during async read (%d, %s)]
+es,frame,54,[scan-headers reports: line too long]
+es,frame,55,[scan-headers reports: too many headers]
+es,frame,56,[Error reading headers]
+es,frame,57,[scan-headers reports: header missing terminator (an empty line)]
+es,frame,58,[scan-headers reports: header was empty]
+es,frame,59,[nombre sin valor: se ha recibido la línea "%s"]
+es,frame,60,[accel_send_plain_file()]
+es,frame,61,[accel_send_plain_file() - found request %d]
+es,frame,62,[Parse headers lost the URI!]
+es,frame,63,[accel_send_plain_file() - found uri %s]
+es,frame,64,[accel_send_plain_file() - found in cache?]
+es,frame,65,[malloc died!]
+es,frame,66,[Error writing back file\n]
+es,frame,67,[acb_send_plain_file(%d)]
+es,frame,68,[Error writing in acb_send_plain_file (%d, %s)]
+es,frame,69,[acb_close_connection(%d)]
+es,frame,70,[Errored IO in acb_close_connection (%d, %s)]
+es,frame,71,[Unable to close socket %d]
+es,frame,72,[accel-cache-insert: Error allocating entry]
+es,frame,73,[cache-init: server cache disabled]
+es,frame,74,[accel_file_cache: Error initializing file cache]
+es,frame,75,[accel_file_cache: Error creating cache]
+es,frame,76,[accel_file_cache_init: CacheHashSize < %d, using %d]
+es,frame,77,[accel_file_cache_init: CacheHashSize > %d, using %d]
+es,frame,78,[accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d]
+es,frame,79,[accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d]
+es,frame,80,[accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d]
+es,frame,81,[accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d]
+es,frame,82,[accel_file_cache: Error initializing file cache]
+es,frame,83,[file-cache: enabled = %s ]
+es,frame,84,[on]
+es,frame,85,[off]
+es,frame,86,[file-cache: MaxNumberOfCachedFiles %d (0x%x)]
+es,frame,87,[file-cache: CacheHashSize %d (0x%x)]
+es,frame,88,[file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)]
+es,frame,89,[accel-cache-insert: Error allocating entry]
+es,frame,90,[file-cache-cleanup: munmap failed (%s)]
+es,frame,91,[file-cache-cleanup: found mmapped file \non system without mmap]
+es,frame,92,[file_cache_init: MaxTotalCachedFileSize < %d, using %d]
+es,frame,93,[file_cache_init: MaxTotalCachedFileSize > %d, using %d]
+es,frame,94,[file cache using mmap flags 0x%x]
+es,frame,95,[file cache using mmap prots 0x%x]
+es,frame,96,[file-cache-init: could not create lock]
+es,frame,97,[file-cache: unable to create temporary directory %s.\n]
+es,frame,98,[file-cache: unable to create temporary directory %s.\n]
+es,frame,99,[file-cache: GetTempPath() Cannot find temp directory to store file!]
+es,frame,100,[file-cache-init: set max cached file size to %d]
+es,frame,101,[file-cache-init: could not create lock]
+es,frame,102,[file_cache_destroy()]
+es,frame,103,[file-cache: Unable to get temp file name. Error %s]
+es,frame,104,[file-cache: Unable to get temp file name. Error %s]
+es,frame,105,[file-cache-insert: Error allocating entry]
+es,frame,106,[file-cache-create: Error opening file %s (%s)]
+es,frame,107,[file-cache-create: Error stat()ing file %s (%s)]
+es,frame,108,[file-cache-create: Error mmap()ing file %s (%s)]
+es,frame,109,[file-cache-create: malloc failure]
+es,frame,110,[file-cache-create: error case failed to munmap(%d, %d) (%s)]
+es,frame,111,[file-cache-valid: cannot stat %s]
+es,frame,112,[dir change: invalidating %s (%d)]
+es,frame,113,[file-cache: asynchronous file change notification failed.]
+es,frame,114,[dir change: offset %d, action %d, len %d, name %s]
+es,frame,115,[unable to check async file status]
+es,frame,116,[ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s]
+es,frame,117,[file-cache-add-watch failure- unable to open directory %s. Error %s]
+es,frame,118,[ReadDirectoryChangesW failure- unable to start watching %s. Error %s]
+es,frame,119,[func_exec]
+es,frame,120,[no handler function given for directive]
+es,frame,121,[func_exec]
+es,frame,122,[cannot find function named %s]
+es,frame,123,[handle-request]
+es,frame,124,[method without URI]
+es,frame,125,[http-parse-request]
+es,frame,126,[while scanning HTTP headers, %s]
+es,frame,127,[handle-request]
+es,frame,128,[read from %s failed, error is %s]
+es,frame,129,[handle-request]
+es,frame,130,[request too long]
+es,frame,131,[start-http-response]
+es,frame,132,[write failed (%s)]
+es,frame,133,[start-http-response]
+es,frame,134,[write failed (%s)]
+es,frame,135,[http-status]
+es,frame,136,[%d is not a valid HTTP status code]
+es,frame,137,[finish-request]
+es,frame,138,[close failed (%s)]
+es,frame,139,[Unable to close socket for writing]
+es,frame,140,[os has %d objects]
+es,frame,141,[obj %d has no hash table at %d]
+es,frame,142,[obj %d has no param]
+es,frame,143,[obj %d name %s value %s]
+es,frame,144,[.....directives %d.......]
+es,frame,145,[.....directive %d]
+es,frame,146,[.......instance %d]
+es,frame,147,[...........param name %s value %s]
+es,frame,148,[ClearConfigurationParameters:RegCreateKey %s]
+es,frame,149,[ClearConfigurationParameters:RegEnumKey %s failed]
+es,frame,150,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+es,frame,151,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+es,frame,152,[Unable to allocate Subject property list.\n]
+es,frame,153,[Unable to set session ptr in Subject property list - error=%d\n]
+es,frame,154,[Unable to set request ptr in Subject property list - error=%d\n]
+es,frame,155,[file-cache-valid: cannot stat %s]
+es,frame,156,[file-cache-create: Error stat()ing file %s (%s)]
+es,httpdaemon,-1,[$DBT: httpdaemon in DB file v1 $]
+es,httpdaemon,1,[Error in ConvertThreadToFiber]
+es,httpdaemon,2,[Error in ConvertThreadToFiber]
+es,httpdaemon,3,[Error in md_start_system]
+es,httpdaemon,4,[Error in CreateFiber - idlefiber]
+es,httpdaemon,5,[Error in GetQueuedCompletionStatus]
+es,httpdaemon,6,[Error creating completion port]
+es,httpdaemon,7,[Could not SetHandleNonInheritable (%s)]
+es,httpdaemon,8,[Error accept/read new conn]
+es,httpdaemon,9,[Error in Respond()]
+es,httpdaemon,10,[Error in RespondCompleted()]
+es,httpdaemon,11,[daemon: unable to fork new process (%s)\n]
+es,httpdaemon,12,[daemon: setsid failed (%s)\n]
+es,httpdaemon,13,[daemon: can't log pid to %s (%s)\n]
+es,httpdaemon,14,[warning: could not set group id to %d (%s)\n]
+es,httpdaemon,15,[warning: could not set user id to %d (%s)\n]
+es,httpdaemon,16,[warning: daemon is running as super-user\n]
+es,httpdaemon,17,[could not determine current user name\n]
+es,httpdaemon,18,[error: chroot to %s failed (%s)\n]
+es,httpdaemon,19,[WARNING! netscape executable and library have different versions.\n]
+es,httpdaemon,20,[startup: listening to %s://%s, port %d as %s\n]
+es,httpdaemon,21,[startup: listening to %s://%s, port %d as %s\n]
+es,httpdaemon,22,[seminit failed (%s)\n]
+es,httpdaemon,23,[Using single threaded accepts.]
+es,httpdaemon,24,[Using multi threaded accepts.]
+es,httpdaemon,25,[Using partial single threaded accepts.]
+es,httpdaemon,26,[This machine has %d processors.]
+es,httpdaemon,27,[Error calling thr_seconcurrency(%d)- (%s)]
+es,httpdaemon,28,[Set conncurrency to %d.]
+es,httpdaemon,29,[can't fork new process (%s)]
+es,httpdaemon,30,[This beta software has expired.\n]
+es,httpdaemon,31,[can't create IPC pipe (%s)]
+es,httpdaemon,32,[write to wakeup pipe failed (%s)]
+es,httpdaemon,33,[select thread miss]
+es,httpdaemon,34,[startup failure: could not bind to port %d (%s)\n]
+es,httpdaemon,35,[startup failure: could not bind to port %d, IP address %s (%s)\n]
+es,libaccess,-1,[$DBT: libaccess in DB file v1 $]
+es,libaccess,1,[basic-ncsa]
+es,libaccess,2,[cannot open database %s]
+es,libaccess,3,[basic-ncsa]
+es,libaccess,4,[user %s password did not match database %s]
+es,libaccess,5,[basic-ncsa]
+es,libaccess,6,[cannot open connection to LDAP server on %s:%d]
+es,libaccess,7,[basic-ncsa]
+es,libaccess,8,[user %s password did not match LDAP on %s:%d]
+es,libaccess,9,[acl-state]
+es,libaccess,10,[missing realm]
+es,libaccess,11,[Unable to allocate ACL List Hash\n]
+es,libaccess,12,[ACLEvalBuildContext unable to PERM_MALLOC cache structure\n]
+es,libaccess,13,[ACLEvalBuildContext unable to create hash table\n]
+es,libaccess,14,[ACLEvalBuildContext unable to allocate ACE Entry\n]
+es,libaccess,15,[ACLEvalBuildContext unable to allocate ACE entry\n]
+es,libaccess,16,[ACLEvalBuildContext unable to allocate Boundary Entry\n]
+es,libaccess,17,[ACLEvalBuildContext failed.\n]
+es,libaccess,18,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n]
+es,libaccess,19,[LASDnsBuild unable to allocate hash table header\n]
+es,libaccess,20,[LASDnsBuild unable to add key %s\n]
+es,libaccess,21,[LASDnsBuild unable to add key %s\n]
+es,libaccess,22,[LASDnsBuild unable to add key %s\n]
+es,libaccess,23,[LASDnsBuild unable to add key %s\n]
+es,libaccess,24,[LASDnsBuild unable to add key %s\n]
+es,libaccess,25,[LAS DNS build received request for attribute %s\n]
+es,libaccess,26,[LASDnsEval - illegal comparator %s\n]
+es,libaccess,27,[LASDnsEval unable to allocate Context struct\n\n]
+es,libaccess,28,[LASDnsEval unable to get session address %d\n]
+es,libaccess,29,[LASDnsEval unable to get DNS - error=%s\n]
+es,libaccess,30,[LAS Group Eval received request for attribute %s\n]
+es,libaccess,31,[LASGroupEval - illegal comparator %s\n]
+es,libaccess,32,[LASGroupEval - ran out of memory\n]
+es,libaccess,33,[LASGroupEval unable to get session address %d\n]
+es,libaccess,34,[LASGroupEval unable to get session address %d\n]
+es,libaccess,35,[LASGroupEval - couldn't locate getter for auth-user\n]
+es,libaccess,36,[LASGroupEval - Attribute getter for auth-user failed\n]
+es,libaccess,37,[LASGroupEval - Attribute getter didn't set auth-user\n]
+es,libaccess,38,[Check group membership of user "%s" for group "%s"\n]
+es,libaccess,39,[LDAPU_SUCCESS for group "%s"\n]
+es,libaccess,40,[LDAPU_FAILED for group "%s"\n]
+es,libaccess,41,[LAS_EVAL_FALSE\n]
+es,libaccess,42,[LAS_EVAL_TRUE\n]
+es,libaccess,43,[LASIpTreeAlloc - no memory\n]
+es,libaccess,44,[IP LAS unable to allocate tree node\n]
+es,libaccess,45,[IP LAS unable to allocate tree node\n]
+es,libaccess,46,[LAS IP build received request for attribute %s\n]
+es,libaccess,47,[LASIpEval - illegal comparator %s\n]
+es,libaccess,48,[LASIpEval unable to get session address - error=%s\n]
+es,libaccess,49,[LASIpEval unable to allocate Context struct\n\n]
+es,libaccess,50,[LASIpEval - reach 32 bits without conclusion value=%s]
+es,libaccess,51,[LAS Program Eval received request for attribute %s\n]
+es,libaccess,52,[LASProgramEval - illegal comparator %s\n]
+es,libaccess,53,[LASProgram unable to get session address %d\n]
+es,libaccess,54,[bin]
+es,libaccess,55,[LASProgramEval: request not of type admin or bin, passing.\n]
+es,libaccess,56,[LASProgramEval: check if program %s matches pattern %s.\n]
+es,libaccess,57,[LASProgramEval: Invalid wildcard expression %s.\n]
+es,libaccess,58,[LAS_EVAL_FALSE\n]
+es,libaccess,59,[LAS_EVAL_TRUE\n]
+es,libaccess,60,[Unexpected attribute in dayOfWeek - %s\n]
+es,libaccess,61,[Illegal comparator for dayOfWeek - %s\n]
+es,libaccess,62,[Unexpected attribute in timeOfDay - %s\n]
+es,libaccess,63,[LAS User Eval received request for attribute %s\n]
+es,libaccess,64,[LASUserEval - illegal comparator %s\n]
+es,libaccess,65,[LASUserEval - ran out of memory\n]
+es,libaccess,66,[LASUserEval unable to get session address %d\n]
+es,libaccess,67,[LASUserEval unable to get session address %d\n]
+es,libaccess,68,[LASGroupEval - couldn't locate getter for auth-user\n]
+es,libaccess,69,[LASGroupEval - Attribute getter for auth-user failed\n]
+es,libaccess,70,[LASGroupEval - Attribute getter didn't set auth-user\n]
+es,libaccess,71,[Check if uid == user (i.e. check "%s" == "%s)"\n]
+es,libaccess,72,[SUCCESS for user "%s"\n]
+es,libaccess,73,[FAILED for user "%s"\n]
+es,libaccess,74,[LAS_EVAL_FALSE\n]
+es,libaccess,75,[LAS_EVAL_TRUE\n]
+es,libaccess,76,[]
+es,libaccess,77,[LASProgram unable to get request address - error=%s]
+es,libaccess,78,[LASProgram rejecting request for program %s from pattern %s]
+es,libaccess,79,[ACL_CacheFlush: unable to parse file "%s"\n]
+es,libaccess,80,[ACL_CacheFlush: unable to concatenate ACL list "%s"\n]
+es,libaccess,81,[ACL_CacheFlush: unable to open and process the magnus file "%s"\n]
+es,libaccess,82,[Illegal comparator for timeOfDay - %s\n]
+es,libaccess,83,[ACL_EvalBuildContext unable to create hash table\n]
+es,libaccess,84,[ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n]
+es,libaccess,85,[ACL_EvalBuildContext unable to allocate ACE entry\n]
+es,libaccess,86,[ACL_EvalBuildContext unable to allocate auth pointer array\n]
+es,libaccess,87,[ACL_EvalBuildContext unable to allocate auth plist\n]
+es,libaccess,88,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n]
+es,libaccess,89,[ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n]
+es,libaccess,90,[ACL_ModuleRegister: module name is missing\n]
+es,libaccess,91,[ACL_ModuleRegister: call to module init function returned a failed status\n]
+es,libaccess,92,[ACL_GetAttribute: couldn't determine method for %s\n]
+es,libaccess,93,[ACL_GetAttribute: couldn't locate getter for %s]
+es,libaccess,94,[ACL_GetAttribute: attr getter failed to get %s]
+es,libaccess,95,[ACL_GetAttribute: attr getter failed to get %s]
+es,libaccess,96,[ACL_GetAttribute: All attribute getters declined for attr %s]
+es,libaccess,97,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+es,libaccess,98,[ACL_DatabaseRegister: database name is missing]
+es,libaccess,99,[Error reading the DB Map File: %s. Reason: %s]
+es,libaccess,100,[URL is missing for database %s]
+es,libaccess,101,[Invalid property value pair for database %s]
+es,libaccess,102,["default" database must be an LDAP database]
+es,libaccess,103,[Multiple "default" databases are being registered]
+es,libaccess,104,["default" LDAP database must be registered]
+es,libaccess,105,[LASGroupEval unable to get database name - error= %s]
+es,libaccess,106,[received invalid program expression %s]
+es,libaccess,107,[parse_ldap_url: database url is missing]
+es,libaccess,108,[parse_ldap_url: database name is missing]
+es,libaccess,109,[parse_ldap_url: error in parsing ldap url. Reason: %s]
+es,libaccess,110,[ldap password check: unable to get database name - error=%s]
+es,libaccess,111,[ldap password check: unable to get parsed database %s]
+es,libaccess,112,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+es,libaccess,113,[ldap password check: LDAP error: "%s"]
+es,libaccess,114,[get_user_ismember_ldap unable to get database name - error=%s]
+es,libaccess,115,[get_user_ismember_ldap unable to get parsed database %s]
+es,libaccess,116,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+es,libaccess,117,[get_user_ismember_ldap: group %s does not exist]
+es,libaccess,118,[get_user_ismember_ldap: LDAP error: "%s"]
+es,libaccess,119,[ACL_LDAPDatabaseHandle: %s is not a registered database]
+es,libaccess,120,[ACL_LDAPDatabaseHandle: %s is not an LDAP database]
+es,libaccess,121,[ACL_LDAPDatabaseHandle: out of memory]
+es,libaccess,122,[ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s]
+es,libaccess,123,[ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s]
+es,libaccess,124,[insufficient dynamic memory]
+es,libaccess,125,[error opening file, %s: %s]
+es,libaccess,126,[duplicate definition of %s]
+es,libaccess,127,[file %s, line %s: duplicate definition of %s]
+es,libaccess,128,[file %s, line %s: syntax error]
+es,libaccess,129,[file %s, line %s: %s is undefined]
+es,libaccess,130,[in acl %s, %s %s is undefined]
+es,libaccess,131,[database %s: error accessing %s]
+es,libaccess,132,[%s]
+es,libaccess,133,[file %s, line %s: invalid syntax]
+es,libaccess,134,[file %s, line %s: syntax error at "%s"]
+es,libaccess,135,[realm %s is not defined]
+es,libaccess,136,[error code = %d]
+es,libaccess,137,[internal ACL error]
+es,libaccess,138,[invalid argument]
+es,libaccess,139,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+es,libaccess,140,[couldn't determine dbtype from: %s]
+es,libaccess,141,[Failed to register database %s]
+es,libaccess,142,[ACL call returned failed status]
+es,libaccess,143,[file %s: ACL IO error - %s]
+es,libaccess,144,[acl_user_exists: memoria agotada]
+es,libaccess,145,[acl_user_exists: ya no existe el usuario]
+es,libaccess,146,[acl_user_exists: error de plist]
+es,libadmin,-1,[$DBT: libadmin in DB file v1 $]
+es,libadmin,1,[ Help ]
+es,libadmin,2,[ OK ]
+es,libadmin,3,[ Reset ]
+es,libadmin,4,[ Done ]
+es,libadmin,5,[ Cancel ]
+es,libir,-1,[$DBT: libadmin in DB file v1 $]
+es,libir,1,[An I/O error occurred before all form data could be read.]
diff --git a/l10n/dirserv/fr/ns-slapd.txt b/l10n/dirserv/fr/ns-slapd.txt
new file mode 100644
index 00000000..394c3881
--- /dev/null
+++ b/l10n/dirserv/fr/ns-slapd.txt
@@ -0,0 +1,898 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+/**************************************************************************/
+/* The copyright notice(s) in this Source Code does not indicate actual */
+/* or intended publication of this Source Code. */
+/**************************************************************************/
+
+/* This text file was generated by program dblink */
+
+$Revision: 1.1 $
+$Log: ns-slapd.txt,v $
+Revision 1.1 2005/01/21 00:40:48 cvsadm
+Initial revision
+
+Revision 1.2.10.5 2003/09/22 19:36:42 ulfw
+Update copyright years from 2001 to 2001-2003
+
+Revision 1.2.10.4 2001/11/03 01:07:03 richm
+XXX use new copyright XXX
+
+Revision 1.2.10.3 2001/09/20 16:39:16 richm
+removed 8 bit copyright character
+
+Revision 1.2.10.3 2001/09/18 11:48:16 rmarco
+Remove copyright caracter from copyright
+
+Revision 1.2.10.2 2001/02/13 09:59:55 rmarco
+Copyrights
+
+Revision 1.2.10.1 1998/10/10 02:14:08 ggood
+Copy from Directory40RtmBranchpoint to DirectoryBranch
+
+Revision 1.2.2.3.6.1 1998/04/04 23:16:54 mcs
+merge changes made on directory31_rtm_branch into server4_directory_branch
+
+Revision 1.2.2.3.2.1 1998/02/24 05:51:56 noriko
+Synched with server3_i18npkg_branch
+
+Revision 1.1.2.5 1997/12/31 00:28:47 werudge
+UTF8 Encoded from fr/ns-slapd.txt.iso8859 : 1.1.2.6
+Based on en/ns-slapd.txt : 1.1.2.3
+
+Revision 1.1.2.6 1997/12/31 00:23:39 werudge
+Remove \n from dsgw,198 to fix JavaScript problem
+
+Revision 1.1.2.5 1997/12/19 02:03:54 werudge
+Based on en/ns-slapd.txt : 1.1.2.3
+daily 971113.1 SOLARIS-export-optimize-normal-slapd
+$EndLog$
+
+$StartStringData$
+
+fr,base,-1,[$DBT: base in DB file v1 $]
+fr,base,1,[mémoire insuffisante pour créer la table de hachage]
+fr,base,2,[mémoire insuffisante pour créer la table de hachage ]
+fr,base,3,[cache_destroy : les tables du cache semblent corrompues.]
+fr,base,4,[impossible d´allouer l´entrée de hachage]
+fr,base,5,[cache_insert : impossible de créer l´entrée de cache]
+fr,base,6,[HTTP/1.0 200 OK\nContent-type: text/html\n\n]
+fr,base,7,[<H2>Rapport d'état du cache Netscape\n(Netscape cache status report)</H2>\n]
+fr,base,8,[Aucun cache sur le système (No caches on system)<P>]
+fr,base,9,[<H2>cache %s</H2>\n]
+fr,base,10,[Rapport de connexions au cache: %d/%d (%f)\n(Cache hit ratio: as shown)</P>\n</P>\n]
+fr,base,11,[Taille du cache: %d/%d\n(Cache size: as shown)</P>\n</P>\n]
+fr,base,12,[Taille de la table de hachage: %d\n(Hash table size: as shown)</P>\n</P>\n]
+fr,base,13,[mru : %d</P>\nlru : %d</P>\n]
+fr,base,14,[<UL><TABLE BORDER=4> <TH>Compartiment (Bucket)</TH> <TH>Adresse (Address)</TH> <TH>Clef (Key)</TH> <TH>Nombre d'accès (Access Count)</TH> <TH>Supprimer (Delete)</TH> <TH>Suivant (Next)</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>Données (Data)</TH>\n]
+fr,base,15,[munmap failed (%s)]
+fr,base,16,[munmap failed (%s)]
+fr,base,17,[close failed (%s)]
+fr,base,18,[daemon: unable to fork new process (%s)\n]
+fr,base,19,[daemon: setsid failed (%s)\n]
+fr,base,20,[daemon: can't log pid to %s (%s)\n]
+fr,base,21,[warning: could not set group id to %d (%s)\n]
+fr,base,22,[warning: could not set user id to %d (%s)\n]
+fr,base,23,[warning: daemon is running as super-user\n]
+fr,base,24,[could not determine current user name\n]
+fr,base,25,[error: chroot to %s failed (%s)\n]
+fr,base,27,[, address %s]
+fr,base,28,[warning: statistics disabled (%s)\n]
+fr,base,29,[security handshake timed out for pid %d]
+fr,base,30,[warning: statistics disabled (%s)\n]
+fr,base,31,[secure handshake failed (code %d)\n]
+fr,base,32,[accept failed (%s)]
+fr,base,33,[warning: statistics disabled (%s)\n]
+fr,base,34,[select thread miss]
+fr,base,35,[keepalive worker awoken with no work to do]
+fr,base,36,[could not create new thread: %d (%s)]
+fr,base,37,[wait for sema succeeded, but nothing to dequeue]
+fr,base,38,[queue-sema creation failure]
+fr,base,39,[error getting processor info for processor %d]
+fr,base,40,[Error binding to processor %d]
+fr,base,41,[bound process %d to processor %d]
+fr,base,42,[Netscape server is not explicitly binding to any processors.]
+fr,base,43,[cache monitor exited]
+fr,base,44,[cache batch update daemon exited]
+fr,base,45,[Using single threaded accepts.]
+fr,base,46,[Using multi threaded accepts.]
+fr,base,47,[Using partial single threaded accepts.]
+fr,base,48,[This machine has %d processors.]
+fr,base,49,[Error calling thr_seconcurrency(%d)- (%s)]
+fr,base,50,[Set conncurrency to %d.]
+fr,base,51,[WARNING! netscape executable and library have different versions.\n]
+fr,base,54,[seminit failed (%s)\n]
+fr,base,55,[This beta software has expired.\n]
+fr,base,56,[Cache monitor respawned]
+fr,base,57,[Cache batch update daemon respawned]
+fr,base,58,[can't find empty statistics slot]
+fr,base,59,[can't fork new process (%s)]
+fr,base,60,[assert failed! %s\n]
+fr,base,61,[mr_table_init()]
+fr,base,62,[malloc failed]
+fr,base,63,[malloc failed!]
+fr,base,64,[mr_add_io(%d, type %d, file %d)]
+fr,base,65,[mr_add_io - stage 1]
+fr,base,66,[mr_add_io - stage 2]
+fr,base,67,[mr_add_io found invalid IO type %d]
+fr,base,68,[mr_add_io - adding timeout]
+fr,base,69,[Out of memory!\n]
+fr,base,70,[done with mr_add_io]
+fr,base,71,[mr_del_io(%d, type %d, file %d)]
+fr,base,72,[mr_del_io found invalid IO type %d]
+fr,base,73,[mr_lookup_io(%d)]
+fr,base,74,[mr_async_io(%d, %d bytes, file %d)]
+fr,base,75,[malloc failure adding async IO]
+fr,base,76,[Error adding async io!]
+fr,base,77,[Cannot seek for read!]
+fr,base,78,[read failure! (%d, %s)]
+fr,base,79,[do_read read %d bytes for file %d]
+fr,base,80,[Cannot seek for write!]
+fr,base,81,[writev failure! (%d, %s)]
+fr,base,82,[write failure! (%d, %s)]
+fr,base,83,[do_write wrote %d bytes for file %d]
+fr,base,84,[do_timeout(mrp %d)]
+fr,base,85,[do_timeout: found IO (timer=%d, time=%d)]
+fr,base,86,[error deleting io]
+fr,base,87,[timeout callback failure for %d\n]
+fr,base,88,[mr_get_event(%d) - outstanding io %d]
+fr,base,89,[mr_get_event: Waiting for reads on FD:]
+fr,base,90,[mr_get_event: Waiting for writes on FD:]
+fr,base,91,[ %d]
+fr,base,92,[ %d]
+fr,base,93,[mr_get_event set no timeout]
+fr,base,94,[mr_get_event set timeout to: %d.%d sec]
+fr,base,95,[error in select (%d, %s)]
+fr,base,96,[mr_get_event() - select found %d]
+fr,base,97,[error looking up IO fd %d]
+fr,base,98,[read failed for fd %d]
+fr,base,99,[error deleting io]
+fr,base,100,[callback failure for %d\n]
+fr,base,101,[error looking up IO fd %d]
+fr,base,102,[writing: header len %d, writelen %d, total %d]
+fr,base,103,[write failed for fd %d]
+fr,base,104,[error deleting io]
+fr,base,105,[callback failure for %d\n]
+fr,base,106,[Error creating dns cache]
+fr,base,107,[dns_cache_init: hash_size <= 0, using %d]
+fr,base,108,[dns_cache_init: cache-size <= %d, using %d]
+fr,base,109,[dns_cache_init: cache-size is %d is too large, using %d.]
+fr,base,110,[dns_cache_init: expire_time <= 0, using %d]
+fr,base,111,[dns_cache_init: expire is %d is too large, using %d seconds.]
+fr,base,112,[Error creating dns cache]
+fr,base,113,[dns-cache-insert: Error allocating entry]
+fr,base,114,[dns-cache-insert: malloc failure]
+fr,base,115,[successful server startup]
+fr,base,116,[%s B%s]
+fr,base,117,[Netscape executable and shared library have different versions]
+fr,base,118,[ executable version is %s]
+fr,base,119,[ shared library version is %s]
+fr,base,120,[error reporting shutting down]
+fr,base,121,[warning]
+fr,base,122,[config]
+fr,base,123,[security]
+fr,base,124,[failure]
+fr,base,125,[catastrophe]
+fr,base,126,[info]
+fr,base,127,[verbose]
+fr,base,128,[event_handler:Failed to wait on events %s]
+fr,base,129,[could not wait on resume event event (%s)]
+fr,base,130,[dlopen of %s failed (%s)]
+fr,base,131,[dlopen of %s failed (%s)]
+fr,base,132,[The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!]
+fr,base,133,[Terminating the server %s]
+fr,base,134,[kill_server:cannot open server event %s]
+fr,base,135,[kill_server:cannot set server event %s]
+fr,base,136,[error: could not get socket (%s)\n]
+fr,base,137,[error: could not set socket option (%s)\n]
+fr,base,138,[Terminating Service:error: could not bind to address %s port %d (%s)\n]
+fr,base,139,[Terminating Service:error: could not bind to port %d (%s)\n]
+fr,base,140,[SetHandleNonInheritable: could not duplicate socket (%s)]
+fr,base,141,[SetHandleNonInheritable: closing the original socket failed (%s)]
+fr,base,142,[Could not SetHandleInformation (%s)]
+fr,base,143,[Terminating Service:Failure: Could not open statistics file (%s)\n]
+fr,base,144,[Could not set Thread Local Storage Value for thread at slot %d]
+fr,base,145,[secure handshake failed (code %d)\n]
+fr,base,146,[accept failed %d (%s)]
+fr,base,147,[Failed to pulse Event %d %s]
+fr,base,148,[Failed to send MobGrowth Event to parent %s]
+fr,base,149,[Pulsing MobRespawn Event %d]
+fr,base,150,[respawn thread pool to %d (%d)]
+fr,base,151,[Could not open event to signal rotate application. Could not create the MoveLog event:%s]
+fr,base,152,[Failed to send MoveLog Event to rotate app %s]
+fr,base,153,[growing thread pool from %d to %d]
+fr,base,154,[Could not open the ServiceControlManager, Error %d]
+fr,base,155,[StartNetsiteService:Could not open the service %s: Error %d]
+fr,base,156,[StartNetsiteService:Could not start the service %s]
+fr,base,157,[Service Startup: Could not allocate security descriptor]
+fr,base,158,[Service Startup: Could not init security descriptor]
+fr,base,159,[Service Startup: Could not set the security Dacl]
+fr,base,160,[Terminating Service:WinSock init failed: %s]
+fr,base,161,[Httpd Server Startup failed: %s]
+fr,base,162,[can't find empty statistics slot]
+fr,base,163,[NT daemon: could not create new thread %d]
+fr,base,164,[Service Startup Failure. Terminating Service:Could not create event %d:%s]
+fr,base,165,[Service Startup Error. Could not create the MoveLog event:%s]
+fr,base,166,[Failed to wait on Event objects %s]
+fr,base,167,[Failed to wait on Event objects %s]
+fr,base,168,[pipebuf_buf2sd: pipebuf_grab IO_ERROR %d]
+fr,base,169,[pool-init: memory pools disabled]
+fr,base,170,[pool-init: free_size <= 0, using %d]
+fr,base,171,[pool-create-block: out of memory]
+fr,base,172,[pool-create: out of memory]
+fr,base,173,[pool-create: out of memory]
+fr,base,174,[pool-malloc: out of memory]
+fr,base,175,[FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.]
+fr,base,176,[regex error: %s (regex: '%s')]
+fr,base,177,[can't create IPC pipe (%s)]
+fr,base,178,[write to wakeup pipe failed (%s)]
+fr,base,179,[flushing %d connections; current %d; tot %d]
+fr,base,180,[accept failed (%s)]
+fr,base,181,[Error creating time cache]
+fr,base,182,[time-cache: cache disabled]
+fr,base,183,[time_cache_init: hash_size < %d, using default, %d]
+fr,base,184,[time_cache_init: hash_size > %d, using default, %d]
+fr,base,185,[time_cache_init: cache_size < %d, using default, %d]
+fr,base,186,[time_cache_init: cache_size > %d, using default, %d]
+fr,base,187,[Error allocating memory for time_cache]
+fr,base,188,[Error allocating memory for time_cache entry]
+fr,base,189,[Error allocating memory for time_cache entry]
+fr,base,190,[Error inserting new time_cache entry]
+fr,base,191,[Error allocating memory for time_cache]
+fr,base,192,[cs-terminate failure (%s)]
+fr,base,193,[cs-init failure (%s)]
+fr,base,194,[cs-wait failure (%s)]
+fr,base,195,[cs-post failure (%s)]
+fr,base,196,[Unable to create nonblocking socket (%s)]
+fr,base,197,[error: could not set keepalive (%s)\n]
+fr,base,198,[error: could not set recv timeout (%s)\n]
+fr,base,199,[error: could not set send timeout (%s)\n]
+fr,base,200,[Unable to create nonblocking socket (%s)]
+fr,base,201,[sem_grab failed (%s)]
+fr,base,202,[sem_release failed (%s)]
+fr,base,203,[sem_release failed (%s)]
+fr,base,204,[Could not remove temporary directory %s, Error %d]
+fr,base,205,[Could not remove temporary directory %s, Error %d]
+fr,dsgw,-1,[$DBT: dsgw in DB file v1 $]
+fr,dsgw,1,[Méthode de demande HTTP inconnue (Unknown HTTP request method)]
+fr,dsgw,2,[Données HTML de formulaire non valides ou incomplètes (Invalid or incomplete HTML form data)]
+fr,dsgw,3,[Mémoire épuisée (Out of memory)]
+fr,dsgw,4,[L´entrée de requête/formulaire exigée est manquante (Required query/form input is missing)]
+fr,dsgw,5,[Caractère non autorisé dans le chemin d´accès au fichier (Illegal character in file path)]
+fr,dsgw,6,[Fichier de configuration erroné ou manquant (Bad or missing configuration file)]
+fr,dsgw,7,[Impossible d´initialiser LDAP (Unable to initialize LDAP)]
+fr,dsgw,8,[Une erreur est survenue lors du contact du serveur LDAP (An error occurred while contacting the LDAP server)]
+fr,dsgw,9,[Type d´objet de recherche inconnu (Unknown search object type)]
+fr,dsgw,10,[Etiquette d´attribut inconnue (Unknown attribute label)]
+fr,dsgw,11,[Invite de correspondance inconnue (Unknown match prompt)]
+fr,dsgw,12,[Aucun filtre de recherche pour ce type d´objet (No search filters for object type)]
+fr,dsgw,13,[Impossible d´ouvrir le fichier de modèle HTML (Unable to open HTML template file)]
+fr,dsgw,14,[Mode de recherche inconnu; utiliser "smart", "complex", "pattern" ou "auth" (Unknown search mode - use "smart", "complex", "pattern", or "auth")]
+fr,dsgw,15,[Nom distinctif manquant dans l´URL (Distinguished Name missing in URL)]
+fr,dsgw,16,[Portée inconnue dans l´URL (doit être: base, sub ou one) (Unknown scope in URL (should be base, sub, or one))]
+fr,dsgw,17,[URL non reconnu ou erreur inconnue (Unrecognized URL or unknown error)]
+fr,dsgw,18,[Format d´URL erroné (Bad URL format)]
+fr,dsgw,19,[Erreur interne (Internal error)]
+fr,dsgw,20,[Impossible d´écrire sur le fichier d´index de modèles (Unable to write template index file)]
+fr,dsgw,21,[Impossible d´ouvrir le fichier d´index de modèles (Unable to open template index file)]
+fr,dsgw,22,[Impossible de lire le répertoire (Unable to read directory)]
+fr,dsgw,23,[Echec de l´initialisation SSL LDAP (vérifiez le chemin de sécurité) (LDAP SSL initialization failed (check the security path))]
+fr,dsgw,24,[Pour que les formulaires d'utilisateurs et de groupes puissent fonctionner sur SSL avec Administration Server, vous-même ou l'administrateur de votre système devez activer SSL. La page Encryption|On/Off peut être utilisée à cette fin.\n(For the Users and Groups forms to work over SSL, you or your server administrator needs to activate SSL for this Administration Server. The Encryption|On/Off page can be used to do so]
+fr,dsgw,25,[Références d´authentification introuvables dans la base de données d´authentification (Authentication credentials not found in authentication database)]
+fr,dsgw,26,[Erreur de récupération des données depuis la base de données d´authentification (Error retrieving data from the authentication database)]
+fr,dsgw,27,[Vos références d´authentification ont expiré (Your authentication credentials have expired)]
+fr,dsgw,28,[Impossible de créer une chaîne aléatoire]
+fr,dsgw,29,[Aucun nom distinctif n´a été fourni lors du retrait des références (No distinguished name was provided when retrieving credentials)]
+fr,dsgw,30,[Impossible d´ouvrir la base de données d´authentification (Cannot open authentication database)]
+fr,dsgw,31,[Impossible d´annexer des données à la base de données d´authentification (Could not append data to the authentication database)]
+fr,dsgw,32,[Aucun gestionnaire de répertoires n´est défini (No Directory Manager is defined)]
+fr,dsgw,33,[Aucune chaîne de recherche n´a été fournie. Veuillez essayer à nouveau (No search string was provided. Please try again)]
+fr,dsgw,34,[Le fichier de configuration comporte trop d´arguments sur une ligne (Too many arguments on one line in the config. file)]
+fr,dsgw,35,[Echec de l´initialisation des sockets Windows (Failed to initialize Windows Sockets)]
+fr,dsgw,36,[Les références d´authentification n´ont pas pu être obtenues auprès d´Administration Server (Authentication credentials could not be obtained from the Administration Server)]
+fr,dsgw,37,[Nom distinctif manquant dans l´URL ldapdb:// (Distinguished Name missing in ldapdb:// URL)]
+fr,dsgw,38,[URL non reconnu ou erreur inconnue (Unrecognized URL or unknown error)]
+fr,dsgw,39,[Format d´URL erroné (Bad URL format)]
+fr,dsgw,40,[Une erreur est survenue lors de l'initialisation de la base de données LDAP locale\n(An error occurred while initializing the local LDAP database)]
+fr,dsgw,41,[Type de service de répertoires inconnu; utiliser "local" ou "remote" (Unknown directory service type - use "local" or "remote")]
+fr,dsgw,42,[Une erreur est survenue lors de la lecture du fichier de configuration db (An error occurred while reading the db configuration file)]
+fr,dsgw,43,[Le chemin d´accès à NSHOME/userdb était NULL (NSHOME/userdb path was NULL)]
+fr,dsgw,44,[Impossible de mettre à jour la configuration du service de répertoires. (The directory service configuration could not be updated.)]
+fr,dsgw,45,[Impossible de lire l´entrée à partir du répertoire. (The entry could not be read from the directory.)]
+fr,dsgw,46,[Impossible d´effacer la base de données LDAP. (The LDAP database could not be erased.)]
+fr,dsgw,47,[Vous pouvez seulement modifier les entrées que vous avez créées. (You may not change entries besides your own.)]
+fr,dsgw,48,[Problème (Problem)]
+fr,dsgw,49,[Problème d´authentification (Authentication Problem)]
+fr,dsgw,50,[.\n<P>Vous devez ré-authentifier avant de continuer. (You must re-authenticate before continuing.)\n]
+fr,dsgw,51,[.\n<P>Vous devez ré-authentifier avant de continuer. (You must re-authenticate before continuing.)\n]
+fr,dsgw,52,[erreur inconnue (unknown error)]
+fr,dsgw,53,[L´opération a réussi. (The operation was successful.)]
+fr,dsgw,54,[Une erreur interne est survenue sur le serveur. Ceci indique généralement une sérieuse défaillance du serveur et doit être immédiatement porté à l´attention de l´administrateur de votre serveur. (An internal error occurred in the server. This usually indicates a serious malfunction in the server and should be brought to the attention of your server administrator.)]
+fr,dsgw,55,[Le serveur n´a pas compris la demande qui lui a été transmise par la passerelle. (The server could not understand the request which was sent to it by the gateway.)]
+fr,dsgw,56,[La réponse à votre demande a dépassé le temps imparti. Si vous recherchez des entrées, vous obtiendrez sans doute de meilleurs résultats en étant plus précis dans votre recherche. (A time limit was exceeded in responding to your request. If you are searching for entries, you may achieve better results if you are more specific in your search.)]
+fr,dsgw,57,[La réponse à votre demande a dépassé la taille autorisée. Si vous recherchez des entrées, vous obtiendrez sans doute de meilleurs résultats en étant plus précis car trop d´entrées répondent à vos critères de recherche. (A size limit was exceeded in responding to your request. If you are searching for entries, you may achieve better results if you are more specific in your search, because too many entries matched your search criteria.)]
+fr,dsgw,58,[La passerelle a tenté d'authentifier l'accès au serveur en utilisant\nune méthode incomprise par ce dernier.\n(The gateway attempted to authenticate to the server using\na method the server doesn't understand.)]
+fr,dsgw,59,[La passerelle a tenté d´authentifier l´accès au serveur en utilisant une méthode d´authentification non supportée par le serveur. (The gateway attempted to authenticate to the server using an authentication method which the server does not support.)]
+fr,dsgw,60,[Impossible d´honorer votre demande, sans doute parce que le serveur contacté ne contient pas les données que vous recherchez. Il est possible qu´une orientation vers un autre serveur ait été renvoyée sans avoir pu être suivie. Si vous étiez en train d´essayer de modifier le répertoire, il se peut que le serveur contenant la copie maîtresse des données ne soit pas disponible. (Your request could not be fulfilled, probably because the server that was contacted does not contain the data you are looking for. It is possible that a referral to another server was returned but could not be followed. If you were trying to make changes to the directory, it may be that the server that holds the master copy of the data is not available.)]
+fr,dsgw,61,[Votre demande a dépassé une limite administrative sur le serveur. (Your request exceeded an administrative limit in the server.)]
+fr,dsgw,62,[Une extension importante demandée par la passerelle n´est pas disponible sur ce serveur. (A critical extension that the gateway requested is not available in this server.)]
+fr,dsgw,63,[Le serveur n'a pas pu traiter la demande car celle-ci\nrenvoie à un attribut inexistant dans\nl'entrée.\n(The server was unable to process the request, because the\nrequest referred to an attribute which does not exist in the\nentry.)]
+fr,dsgw,64,[Le serveur n´a pas pu répondre à votre demande, car \ncelle-ci va à l´encontre d´une contrainte de la base de données.\n(The server was unable to fulfill your request, because the\nrequest violates a constraint.)]
+fr,dsgw,65,[Le serveur n´a pas pu ajouter une valeur à cette entrée car elle la contient déjà. (The server could not add a value to the entry, because that value is already contained in the entry.)]
+fr,dsgw,66,[Le serveur n'a pas pu localiser l'entrée. Si vous ajoutez une nouvelle entrée,\nassurez-vous qu'elle comporte une entrée principale.\nLa réception de ce message d'erreur lors d'une recherche indique que l'entrée\nrecherchée n'existe pas.\nSi vous étiez en train d'essayer d'authentifier l'accès en tant que gestionnaire de répertoires et que vous\navez vu apparaître ce message, vérifiez le fichier de configuration de la passerelle.\n(The server could not locate the entry. If adding a new entry,\nbe sure that the parent of the entry you are trying to add exists.\nIf you received this error while searching, it indicates that the\nentry which was being searched for does not exist.\nIf you were attempting to authenticate as the directory manager and\nreceived this error, check the gateway configuration file.)]
+fr,dsgw,67,[Le format d´un nom distinctif est incorrect. (A distinguished name was not in the proper format.)]
+fr,dsgw,68,[L´entrée que vous étiez en train d´essayer d´authentifier ne comporte pas de jeu de mots de passe, ou bien il lui manque d´autres références d´authentification requises. Pour que vous puissiez authentifier cette entrée, les attributs appropriés doivent avoir été ajoutés par le gestionnaire de répertoires. (The entry you attempted to authenticate as does not have a password set, or is missing other required authentication credentials. You cannot authenticate as that entry until the appropriate attributes have been added by the directory manager. )]
+fr,dsgw,69,[Le mot de passe (ou d'autres références d'authentification) que vous avez fourni\nest incorrect. (The password (or other authentication credentials) you supplied\nis incorrect. If you just changed your password, you might try exiting your browser and connecting again.)]
+fr,dsgw,70,[Vos privilèges sont insuffisants pour effectuer cette opération. (You do not have sufficient privileges to perform the operation.)]
+fr,dsgw,71,[Le serveur est trop occupé pour honorer votre demande. Essayez à nouveau dans quelques minutes. (The server is too busy to service your request. Try again in a few minutes.)]
+fr,dsgw,72,[Impossible de contacter le serveur LDAP. (The LDAP server could not be contacted.)]
+fr,dsgw,73,[Le serveur refuse de traiter votre demande. Cette dernière risquerait sans doute de le surcharger. Il se peut également qu´il ne soit pas configuré pour traiter votre demande. Si vous tentez d´effectuer une recherche, vous avez intérêt à en limiter la portée. (The server was unwilliing to process your request. Usually, this indicates that serving your request would put a heavy load on the server. It may also indicate that the server is not configured to process your request. If searching, you may wish to limit the scope of your search.)]
+fr,dsgw,74,[Le serveur de répertoires ne peut honorer votre demande car elle viole les exigences du schéma. Vous n´avez sans doute pas fourni de valeur pour un champ requis. Il se peut également que le schéma du serveur de répertoires nécessite une mise à jour. (The directory server could not honor your request because it violates the schema requirements. Typically, this means that you have not provided a value for a required field. It could also mean that the schema in the directory server needs to be updated.)]
+fr,dsgw,75,[Le serveur de répertoires ne vous permettra pas de supprimer ou de renommer une entrée qui comporte des sous-entrées. Si vous souhaitez continuer, vous devez d´abord supprimer toutes les sous-entrées. (The directory server will not allow you to delete or rename an entry if that entry has children. If you wish to do this, you must first delete all the child entries.)]
+fr,dsgw,76,[Le serveur ne peut ajouter une nouvelle entrée ni renommer une entrée existante car il existe déjà une entrée sous ce nom. (The server was unable to add a new entry, or rename an existing entry, because an entry by that name already exists.)]
+fr,dsgw,77,[Votre demande affecterait plusieurs serveurs de répertoires. (Your request would affect several directory servers.)]
+fr,dsgw,78,[Impossible de contacter le serveur de répertoires. Contactez\nl'administrateur de votre serveur de répertoires pour obtenir de l'aide.\n(The directory server could not be contacted. Contact your\ndirectory server administrator for assistance.)]
+fr,dsgw,79,[Une erreur est survenue lors de l´envoi de données au serveur. (An error occured while sending data to the server.)]
+fr,dsgw,80,[Une erreur est survenue lors de la lecture des données en provenance du serveur. (An error occured while reading data from the server.)]
+fr,dsgw,81,[Le serveur n´a pas répondu à la demande. La demande a dépassé le temps imparti. (The server did not respond to the request. The request timed out.)]
+fr,dsgw,82,[Le serveur ne supporte pas la méthode d´authentification utilisée par la passerelle. (The server does not support the authentication method used by the gateway.)]
+fr,dsgw,83,[Le filtre de recherche créé par la passerelle est erroné. (The search filter constructed by the gateway was in error.)]
+fr,dsgw,84,[L´opération a été annulée à votre demande. (The operation was cancelled at your request.)]
+fr,dsgw,85,[Une erreur interne est survenue dans la bibliothèque; un paramètre est incorrect. (An internal error occurred in the library - a parameter was incorrect.)]
+fr,dsgw,86,[Impossible d'ouvrir une connexion au serveur de répertoires. Contactez\nl'administrateur de votre serveur de répertoires pour obtenir de l'aide.\n(A connection to the directory server could not be opened. Contact your\ndirectory server administrator for assistance.)]
+fr,dsgw,87,[Une erreur inconnue est survenue. (An unknown error was encountered.)]
+fr,dsgw,88,[Cette entrée existe déjà (Entry Already Exists)]
+fr,dsgw,89,[Une entrée nommée (An entry named) ]
+fr,dsgw,90,[onMouseOver="window.status='Cliquez ici pour afficher cette entrée'; return true"\n(onMouseOver="window.status='Click here to view this entry'; return true")]
+fr,dsgw,91,[ existe déjà (already exists).<P>Veuillez choisir un autre nom et/ou une autre adresse.\n(Please choose another name and/or location.)\n<P>\n]
+fr,dsgw,92,[L´entrée principale n´existe pas (Parent entry does not exist)]
+fr,dsgw,93,[Impossible d´ajouter une entrée par le nom:<P><B>%s</B>,<P>\ncar il n´existe pas d´entrée principale.<P>\nPour pouvoir ajouter cette entrée, vous devez d´abord ajouter\n(You cannot add an entry by the name shown\nbecause the parent of that entry does not exist.<P>\nBefore you can add this entry, you must first add)\n]
+fr,dsgw,94,[l´entrée principale (its parent).\n]
+fr,dsgw,95,[une entrée nommée (an entry named):<P><B>%s</B>.\n]
+fr,dsgw,96,[Avertissement: pas d´authentification (continuation)...\n(Warning: no authentication (continuing)...)\n]
+fr,dsgw,97,[Entrée de répertoire %s (Directory Entry)]
+fr,dsgw,98,[<PRE>DN de l´entrée (Entry DN): %s</PRE><P>\n]
+fr,dsgw,99,[Les changements apportés à <B>%s</B> ont été enregistrés.]
+fr,dsgw,100,[<B>%s</B> has been added.]
+fr,dsgw,101,[<B>%s</B> has been deleted.]
+fr,dsgw,102,[Renamed <B>%s</B> to <B>%s</B>.]
+fr,dsgw,103,[<P><B>Remarque:</B> Parce que vous avez %s l´entrée pour laquelle vous étiez\nauthentifié, il a fallu mettre vos références \nd´authentification au rebut. Vous aurez besoin d´une nouvelle \nauthentification pour pouvoir apporter des modifications supplémentaires.\n(<B>Note:</B> because of your action on the entry you were \nauthenticated as, it was necessary to discard your \nauthentication credentials. You will need to authenticate \nagain to make additional changes.)\n]
+fr,dsgw,104,[supprimé (deleted)]
+fr,dsgw,105,[renommé (renamed)]
+fr,dsgw,106,[a changé le mot de passe de (changed the password of)]
+fr,dsgw,107,[L´attribut %s a été changé<BR>\n(Attribute shown was changed<BR>)\n]
+fr,dsgw,108,[ NON ASCII (%ld octets)\n(NOT ASCII (number of bytes shown))\n]
+fr,dsgw,109,[Aucune valeur n´a été entrée. Veuillez essayer à nouveau.\n(No values were entered. Please try again.)\n]
+fr,dsgw,110,[Aucun changement n´a été apporté.\n]
+fr,dsgw,111,[<P>Envoi de %s au serveur de répertoires...\n]
+fr,dsgw,112,[informations (information)]
+fr,dsgw,113,[changements (changes)]
+fr,dsgw,114,[<P>L´ajout de cette entrée a réussi.\n(Successfully added entry.)\n]
+fr,dsgw,115,[<P>La modification de cette entrée a réussi. Vos changements ont été enregistrés.\n(Successfully edited entry. Your changes have been saved.)\n]
+fr,dsgw,116,[<P>La suppression de cette entrée a réussi.\n(Successfully deleted entry.)\n]
+fr,dsgw,117,[<PRE>Le nouveau nom de cette entrée est: %s\n(The new name for the entry is as shown)\n</PRE><HR>\n]
+fr,dsgw,118,[<P>Le renommage de cette entrée a réussi.\n(Successfully renamed entry.)\n]
+fr,dsgw,119,[Vous devez fournir l´ancien mot de passe.]
+fr,dsgw,120,[Vous devez spécifier un nouveau mot de passe. Essayez à nouveau.]
+fr,dsgw,121,[Le nouveau mot de passe et sa confirmation ne correspondent pas. Veuillez essayer à nouveau]
+fr,dsgw,122,[<BR>Le %s <B>%s</B> est déjà utilisé. Veuillez en choisir un autre.\n(The item shown is already in use. Please choose a different one.)<BR>\n]
+fr,dsgw,123,[élément "%.100s" de données de formulaire manquant\n(missing form data element shown)]
+fr,dsgw,124,[Initialisation des données de configuration\n(Initializing config info)]
+fr,dsgw,125,[Impossible d´ouvrir le fichier. (Cannot open file.)]
+fr,dsgw,126,[Fichier dbconf mal formé. (Malformed dbconf file.)]
+fr,dsgw,127,[Nom du propriétaire manquant dans le fichier dbconf.\n(Missing property name in dbconf file.)]
+fr,dsgw,128,[Mémoire épuisée. (Out of memory.)]
+fr,dsgw,129,[Directive manquante dans le fichier dbconf.\n(Missing directive in dbconf file.)]
+fr,dsgw,130,[Impossible d'ouvrir le fichier de configuration "%s"\n(Cannot open config file with name shown)\n]
+fr,dsgw,131,[Argument manquant pour la directive "authlifetime"\n(Missing argument for "authlifetime" directive)\n]
+fr,dsgw,132,[Argument manquant pour la directive "dirmgr"\n(Missing argument for "dirmgr" directive)\n]
+fr,dsgw,133,[Argument manquant pour la directive "baseurl"\n(Missing argument for "baseurl" directive)\n]
+fr,dsgw,134,[URL erroné fourni pour la directive "baseurl"; le DN de base est manquant\n(Bad URL provided for "baseurl" directive - the base DN is missing)\n]
+fr,dsgw,135,[analyse de la directive baseurl\n(parsing baseurl directive)]
+fr,dsgw,136,[URL erroné fourni pour la directive "baseurl"; pas un URL "ldap://"\n(Bad URL provided for "baseurl" directive - not an "ldap://" URL)\n]
+fr,dsgw,137,[Les URL "ldaps://" ne sont pas encore supportés\n("ldaps://" URLs are not yet supported)\n]
+fr,dsgw,138,[Arguments manquants pour la directive "template"\n(Missing arguments for "template" directive)\n]
+fr,dsgw,139,[Argument manquant pour la directive "sslrequired"\n(Missing argument for "sslrequired" directive)\n]
+fr,dsgw,140,[Argument inconnu pour la directive "sslrequired" (l´argument doit être "never", "whenauthenticated", "always")\n(Unknown argument to "sslrequired" directive (should be "never", "whenauthenticated", "always"))\n]
+fr,dsgw,141,[Argument manquant pour la directive "securitypath"\n(Missing argument for "securitypath" directive)\n]
+fr,dsgw,142,[Argument manquant pour la directive "location-suffix"\n(Missing argument for "location-suffix" directive)\n]
+fr,dsgw,143,[Trois arguments sont requis pour la directive "location"\n(Three arguments are required for the "location" directive)\n]
+fr,dsgw,144,[Au moins deux arguments sont requis pour la directive "newtype"\n(At least two arguments are required for the "newtype" directive)\n]
+fr,dsgw,145,[Adresse inconnue dans la directive "newtype"\n(Unknown location in "newtype" directive)\n]
+fr,dsgw,146,[Trois ou quatre arguments sont requis pour la directive "tmplset"\n(Three or four arguments are required for the "tmplset" directive)\n]
+fr,dsgw,147,[Quatre arguments sont requis pour la directive "attrvset"\n(Four arguments are required for the "attrvset" directive)\n]
+fr,dsgw,148,[Argument manquant pour la directive "charset"\n(Missing argument for "charset" directive)\n]
+fr,dsgw,149,[Argument manquant pour la directive "ClientLanguage"\n(Missing argument for "ClientLanguage" directive)\n]
+fr,dsgw,150,[Argument manquant pour la directive "AdminLanguage"\n(Missing argument for "AdminLanguage" directive)\n]
+fr,dsgw,151,[Argument manquant pour la directive "DefaultLanguage"\n(Missing argument for "DefaultLanguage" directive)\n]
+fr,dsgw,152,[Nom de fichier manquant pour la directive "include"\n(Missing filename for "include" directive)\n]
+fr,dsgw,153,[Directive inconnue dans le fichier de configuration\n(Unknown directive in config file)\n]
+fr,dsgw,154,[<= erase_db n´a pas réussi à ouvrir le fichier lcache.conf "%s"\n(<= erase_db could not open lcache.conf file with name shown)\n]
+fr,dsgw,155,[<FONT SIZE="+1">\n<P>La base de données a été supprimée. Création d´une nouvelle base de données... \n(The database has been deleted. Creating new database...)\n</FONT>\n]
+fr,dsgw,156,[<FONT SIZE="+1">\n<P>Impossible de supprimer la base de données\n(The database could not be deleted)\n(</FONT>\n]
+fr,dsgw,157,[<= app_suffix n´a pas réussi à ouvrir le fichier ldif "%s"\n(<= app_suffix could not open ldif file with name shown)\n]
+fr,dsgw,158,[<= app_suffix n´a pas réussi à ouvrir le fichier tmp "%s"\n(<= app_suffix could not open tmp file with name shown)\n]
+fr,dsgw,159,[Impossible de renommer %s en %s (Unable to rename with names as shown)]
+fr,dsgw,160,[pointeur null renvoyé par dbconf_read_default_dbinfo().\n(null pointer returned by dbconf_read_default_dbinfo().)]
+fr,dsgw,161,[URL "ldapdb" erroné; le DN de base est manquant\n(Bad "ldapdb" URL - the base DN is missing)\n]
+fr,dsgw,162,[URL "ldapdb" erroné\n (Bad "ldapdb" URL)\n]
+fr,dsgw,163,[URL fourni pour la directive "baseurl" erroné; le DN de base est manquant\n(Bad URL provided for "baseurl" directive - the base DN is missing)\n]
+fr,dsgw,164,[analyse de la directive baseurl\n(parsing baseurl directive)]
+fr,dsgw,165,[URL fourni pour la directive "baseurl" erroné; pas un URL "ldap:// ou ldapdb://"\n(Bad URL provided for "baseurl" directive - not an "ldap:// or ldapdb://" URL)\n]
+fr,dsgw,166,[Les URL "ldaps://" ne sont pas encore supportés\n("ldaps://" URLs are not yet supported)\n]
+fr,dsgw,167,[Aucune valeur donnée pour binddn\n(No value given for binddn)]
+fr,dsgw,168,[Aucune valeur donnée pour bindpw\n(No value given for bindpw)]
+fr,dsgw,169,[Aucun service de répertoires par défaut n´est défini dans le fichier dbswitch.conf\n(There is no default directory service defined in the dbswitch.conf file)]
+fr,dsgw,170,[Impossible d'ouvrir le fichier de configuration "%s" en écriture\n(Cannot open config file with name shown for writing)\n]
+fr,dsgw,171,[Impossible de renommer %s en %s (Unable to rename with names as shown)]
+fr,dsgw,172,[fichier de configuration (config file) %s:]
+fr,dsgw,173,[fichier de configuration %s: ligne %d: \n(config file and line as shown)]
+fr,dsgw,174,[max %d]
+fr,dsgw,175,[ OK ]
+fr,dsgw,176,[Fermer la fenêtre (Close Window)]
+fr,dsgw,177,[Précédent]
+fr,dsgw,178,[{crypt}VERROUILLE (LOCKED) [%s GMT]]
+fr,dsgw,179,[Retourner à l´écran principal (Return to Main)]
+fr,dsgw,181,[ Help ]
+fr,dsgw,182,[Aide (Help)]
+fr,dsgw,184,[L´aide n´est pas encore disponible. (Help is not yet available.)]
+fr,dsgw,186,[Fermer la fenêtre (Close Window)]
+fr,dsgw,187,[Fermer la fenêtre (Close Window)]
+fr,dsgw,188,[modèle manquant? (missing ?template)]
+fr,dsgw,189,[Authentifier... (Authenticate...)]
+fr,dsgw,190,[Mettre les références d´authentification au rebut (déconnexion)?\n(Discard authentication credentials (log out)?)]
+fr,dsgw,191,[Veuillez taper une chaîne de recherche]
+fr,dsgw,192,[La première étape de l´authentification de l´accès à ce répertoire consiste en votre\npropre identification.<br>Tapez votre nom:\n(The first step in authenticating to the directory is identifying\nyourself.<br>Please type your name:)]
+fr,dsgw,193,[Continuer (Continue)]
+fr,dsgw,194,[Continuer (Continue)]
+fr,dsgw,195,[Annuler (Cancel)]
+fr,dsgw,196,[Authentifier comme gestionnaire de répertoires"> &nbsp;(uniquement disponible pour les administrateurs de répertoires)\n(Authenticate as directory manager"> &nbsp;(only available to Directory Administrators))\n]
+fr,dsgw,197,[Authentifier... (Authenticate...)]
+fr,dsgw,198,[Mettre les références d´authentification au rebut? (Discard authentication credentials?)]
+fr,dsgw,200,[Continuer (Continue)]
+fr,dsgw,201,[Continuer (Continue)]
+fr,dsgw,202,[Annuler (Cancel)]
+fr,dsgw,203,[Authentifier l´accès au répertoire (connexion)\n(Authenticate (log in) to the directory)]
+fr,dsgw,204,[Vous êtes sur le point de vous authentifier auprès de l'annuaire en tant que <B>%s</B>. Pour terminer le processus d'authentification, tapez votre mot de passe.\n]
+fr,dsgw,206,[Avant de pouvoir modifier ou ajouter des entrées, vous devez authentifier\nl´accès au répertoire (connexion). Cette fenêtre vous\nguidera tout au long du processus\nd´authentification.\n(Before you can edit or add entries, you must authenticate\n(log in) to the directory. This window will guide\nyou through the steps of the authentication\nprocess.)\n]
+fr,dsgw,207,[Cet écran vous permet d´authentifier l´accès au répertoire, \nou de vous y connecter. Vous devrez vous authentifier\navant de pouvoir modifier les entrées du répertoire. Si vous\ntentez de modifier une entrée sans authentification,\nil vous sera demandé de vous connecter.\n(From this screen you may authenticate, or log in, \nto the directory. You will need to authenticate\nbefore you can modify directory entries. If you\nattempt to modify an entry without authenticating,\nyou will be asked to log in.)\n]
+fr,dsgw,208,[Statut de l´authentification (Authentication Status)]
+fr,dsgw,209,[<form>\nVotre accès au répertoire est actuellement authentifié sous\n(You are currently authenticated to the directory as) ]
+fr,dsgw,210,[.\nSi vous voulez mettre vos références d´authentification au rebut et vous déconnecter du répertoire, cliquez sur le bouton ci-dessous.\n(.\nIf you wish to discard your authentication credentials and log out of the directory, click on the button below.)]
+fr,dsgw,211,[Mettre les références d´authentification au rebut (déconnexion)\n(Discard Authentication Credentials (log out))]
+fr,dsgw,212,[Vos références d´authentification pour \n(Your authentication credentials for )]
+fr,dsgw,213,[ont expiré (have expired).\n<HR>)\n]
+fr,dsgw,214,[Votre accès au répertoire n´est actuellement pas authentifié.\n(Currently, you are not authenticated to the directory.)<HR>\n]
+fr,dsgw,215,["%s=" manquant (missing definition shown)]
+fr,dsgw,216,["%s=%s" inconnu (unknown assignment as shown)]
+fr,dsgw,217,[option inconnue %s (unknown option as shown)]
+fr,dsgw,218,[syntaxe inconnue=%s\n(syntax shown unknown)\n]
+fr,dsgw,219,[** Type HTML "%s" non supporté **\n(** HTML type shown not supported **<BR>)\n]
+fr,dsgw,224,[Modifier (Edit)]
+fr,dsgw,225,[Save Changes]
+fr,dsgw,226,[modify]
+fr,dsgw,227,[add]
+fr,dsgw,228,[Supprimer (Delete)]
+fr,dsgw,229,[Supprimer cette entrée? (Delete this entry?)]
+fr,dsgw,230,[Renommer (Rename)]
+fr,dsgw,231,[Entrez un nouveau nom pour cette entrée: (Enter a new name for this entry:)]
+fr,dsgw,232,[Modifier sous (Edit As)]
+fr,dsgw,233,[%s= manquant (missing definition shown)]
+fr,dsgw,234,[Fermer la fenêtre (Close Window)]
+fr,dsgw,235,[Modifier... (Edit...)]
+fr,dsgw,236,["%s=" manquant\n (missing definition shown")\n]
+fr,dsgw,237,[ensemble inconnu "%s"\n (set shown is unknown)\n]
+fr,dsgw,238,[syntaxe inconnue "%s"\n (syntax shown is unknown)\n]
+fr,dsgw,239,[Ré-authentifier (Re-Authenticate)]
+fr,dsgw,240,[Fermer la fenêtre (Close Window)]
+fr,dsgw,241,[Voulez-vous vraiment (Do you really want to) ]
+fr,dsgw,242,[?]
+fr,dsgw,243,[ OK ]
+fr,dsgw,244,[ OK ]
+fr,dsgw,245,[Remettre à zéro (Reset)]
+fr,dsgw,246,[Terminé (Done)]
+fr,dsgw,247,[Annuler (Cancel)]
+fr,dsgw,248,[a trouvé un autre IF (les IF emboîtés ne sont pas supportés)\n(found another IF (nested IFs are not supported))]
+fr,dsgw,249,[a trouvé ELSE mais n´a pas vu de IF\n(found ELSE but didn't see an IF)]
+fr,dsgw,250,[a trouvé ELSE après ELSE (ENDIF attendu)\n(found ELSE after ELSE (expecting ENDIF))]
+fr,dsgw,251,[a trouvé ELIF mais n´a pas vu de IF\n(found ELIF but didn't see an IF)]
+fr,dsgw,252,[a trouvé ELIF après ELSE (ENDIF attendu)\n(found ELIF after ELSE (expecting ENDIF))]
+fr,dsgw,253,[a trouvé ENDIF mais n´a pas vu de IF\n(found ENDIF but didn't see an IF)]
+fr,dsgw,254,[<BR><B>erreur de modèle:</B> %s\n(<B>template error as shown</B>)<BR>\n]
+fr,dsgw,255,[ldap_init/lcache_init tenté avant la lecture du fichier de configuration\n(ldap_init/lcache_init attempted before config file read)]
+fr,dsgw,256,[ne tourne pas sous Administration Server\n(not running under the administration server)]
+fr,dsgw,257,[Impossible d´initialiser les permissions\n(Could not initialize permissions)]
+fr,dsgw,258,[Impossible de faire correspondre un nom d´utilisateur avec un DN (erreur d´Administration Server)\n(Could not map username to a DN (error from admin server))]
+fr,dsgw,259,[Impossible d´obtenir le nom d´utilisateur courant\n(Could not get current username)]
+fr,dsgw,260,[Impossible d´obtenir le mot de passe utilisateur courant\n(Could not get current user password)]
+fr,dsgw,261,[Erreur (Error): %s]
+fr,dsgw,262,[Remarque: aucun modèle d´affichage n´est disponible pour ce type d´entrée; une méthode par défaut\nest donc utilisée dans l´affichage ci-dessous.\n(Note: there is no display template for this type of entry available, so it is\ndisplayed below using a default method.)]
+fr,dsgw,263,[Identification de l´utilisateur ou identificateur NULL LDAP non valide\n(Invalid user id or NULL LDAP handle)]
+fr,dsgw,264,[aucune correspondance pour l´identification de l´utilisateur\n(no match for user id)]
+fr,dsgw,265,[plusieurs correspondances pour l´identification de l´utilisateur\n(more than one match for user id)]
+fr,dsgw,266,[the entire directory]
+fr,dsgw,267,[Deux arguments sont requis pour la directive "includeset"\n(Two arguments are required for the "includeset" directive)\n]
+fr,dsgw,268,[La valeur d'attribut demandée est introuvable dans l'entrée\n(An error occurred while trying to access the database)]
+fr,dsgw,269,[Argument introuvable pour la directive "NLS"]
+fr,dsgw,270,[Une valeur doit être spécifiée pour l'id d'utilisateur NT\n]
+fr,dsgw,271,[La combinaison de l'id d'utilisateur NT et de l'id de domaine NT n'est pas unique dans le répertoire.]
+fr,dsgw,272,[Des valeurs doivent être spécifiées pour l'id d'utilisateur NT et l'id de domaine NT\n]
+fr,dsgw,273,[La valeur d'id d'utilisateur NT ne doit pas dépasser 20 caractères.\n]
+fr,dsgw,274,[Veuillez créer un nom pour la nouvelle entrée.]
+fr,dsgw,275,[Veuillez sélectionner une adresse pour la nouvelle entrée.]
+fr,dsgw,276,[Nouvelle entrée]
+fr,dsgw,277,[Afin de pouvoir utiliser cette fonction, un dirmgr doit être défini dans dsgw.conf]
+fr,dsgw,278,[Trois ou quatre arguments sont requis pour la directive "vcard-property"\n]
+fr,dsgw,279,[La syntaxe de la propriété Vcard doit être "cis" ou "mls"\n]
+fr,dsgw,280,[Aucune entrée n'a été trouvée.\n%2$s]
+fr,dsgw,281,[Aucune entrée n'a été trouvée dans les %2$s %3$s '%4$s'.\n]
+fr,dsgw,282,[Aucune entrée recherchée n'a été trouvée\n%2$s]
+fr,dsgw,283,[Aucune entrée recherchée n'a été trouvée dans les %2$s %3$s %4$s'.\n]
+fr,dsgw,284,[1 entrée a été trouvée.\n%2$s]
+fr,dsgw,285,[1 entrée a été trouvée dans les %2$s %3$s '%4$s'.\n]
+fr,dsgw,286,[1 entrée recherchée a été trouvée.\n%2$s]
+fr,dsgw,287,[1 entrée recherchée a été trouvée dans les %2$s %3$s '%4$s'.\n]
+fr,dsgw,288,[%1$li entrées ont été trouvées.\n%2$s]
+fr,dsgw,289,[%1$li entrées ont été trouvées dans les %2$s %3$s '%4$s'.\n]
+fr,dsgw,290,[%1$li entrées recherchées ont été trouvées.\n%2$s]
+fr,dsgw,291,[%1$li entrées recherchées ont été trouvées dans les %2$s %3$s '%4$s'.\n ]
+fr,dsgw,292,[le filtre LDAP est]
+fr,dsgw,293,[Le serveur n´a pas pu trouver l´entrée que vous avez utilisée lors de l´authentification. Quelqu´un a peut-être renommé ou supprimé l´entrée. Procédez à une nouvelle authentification.]
+fr,dsgw,294,[La nouvelle syntaxe du mot de passe n´est pas valide.\n]
+fr,dsgw,295,[Le nouveau mot de passe figure dans l´historique des mots de passe.\n]
+fr,dsgw,296,[Vous avez atteint la limite de nouvelle tentative de mot de passe. Contactez votre administrateur système.\n]
+fr,dsgw,297,[Vous avez atteint la limite de nouvelle tentative de mot de passe. Essayez à nouveau.\n]
+fr,dsgw,298,[Le mot de passe a expiré. Contactez votre administrateur système pour redéfinir le mot de passe.\n]
+fr,frame,-1,[$DBT: frame in DB file v1 $]
+fr,frame,1,[<TITLE>Introuvable (Not Found)</TITLE><H1>Introuvable (Not Found)</H1> L'objet demandé n'existe pas sur ce serveur. Le lien que vous avez consulté est peut-être désuet, inexact, ou bien le serveur a reçu l'ordre de ne pas vous laisser y accéder.\n(The requested object does not exist on this server. The link you followed is either outdated, inaccurate, or the server has been instructed not to let you have it. )]
+fr,frame,2,[Veuillez informer l'administrateur de site de la <A HREF="%s">page de référence</A>.\n(Please inform the site administrator of the referring page.)]
+fr,frame,3,[Votre navigateur a envoyé une demande que ce Proxy n'arrive pas à comprendre.\n(Your browser sent a request that this proxy could not understand.)]
+fr,frame,4,[Une autorisation adéquate est requise pour l'administration de ce Proxy.\nVotre navigateur n'effectue peut-être pas l'autorisation, ou bien votre autorisation\na échoué.\n(Proper authorization is required for the administration of this proxy.\nEither your browser does not perform authorization, or your authorization\nhas failed.)]
+fr,frame,5,[L'authentification du nom d'utilisateur est requise pour utiliser ce Proxy.\nVotre navigateur n'effectue peut-être par l'autorisation de Proxy, ou bien votre\nautorisation a échoué.\n(Username authentication is required for using this proxy.\nEither your browser does not perform proxy authorization, or your\nauthorization has failed.)]
+fr,frame,6,[La configuration du contrôle d'accès de ce Proxy refuse l'accès à\nl'objet demandé par le biais de ce Proxy.\n(The proxy's access control configuration denies access to\nthe requested object through this proxy.)]
+fr,frame,7,[Le Proxy a rencontré une erreur interne qui l'empêche \nd'honorer votre demande. La cause la plus probable est une mauvaise configuration.\nVeuillez demander à l'administrateur de consulter le journal d'erreurs du Proxy.\n(The proxy has encountered an internal error which prevents it from\nfulfilling your request. The most likely cause is a misconfiguration.\nPlease ask the administrator to look for messages in the proxy's error log.)]
+fr,frame,8,[Ce serveur de Proxy ne met pas en oeuvre la méthode demandée.\n(This proxy server does not implement the requested method.)]
+fr,frame,9,[Une erreur est survenue sur le serveur de Proxy.\n(An error has occurred on the proxy server.)]
+fr,frame,10,[Votre navigateur a envoyé une requête que ce serveur n'arrive pas à comprendre.\n(Your browser sent a query this server could not understand.)]
+fr,frame,11,[Une autorisation adéquate est requise pour ce domaine. Votre navigateur n'effectue peut-être pas l'autorisation, ou bien votre autorisation a échoué.\n(Proper authorization is required for this area. Either your browser does not perform authorization, or your authorization has failed.)]
+fr,frame,12,[Votre client n'est pas autorisé à accéder à l'objet demandé.\n(Your client is not allowed to access the requested object.)]
+fr,frame,13,[Ce serveur a rencontré une erreur interne qui l'empêche d'honorer votre demande. La cause la plus probable est une mauvaise configuration. Veuillez demander à l'administrateur de consulter le journal d'erreurs du serveur.\n(This server has encountered an internal error which prevents it from fulfilling your request. The most likely cause is a misconfiguration. Please ask the administrator to look for messages in the server's error log.)]
+fr,frame,14,[Ce serveur ne met pas en oeuvre la méthode demandée.\n(This server does not implement the requested method.)]
+fr,frame,15,[Une erreur est survenue. (An error has occurred.)]
+fr,frame,16,[Votre navigateur a envoyé un message que ce serveur n'arrive pas à comprendre.\n(Your browser sent a message this server could not understand.)]
+fr,frame,17,[<HTML><HEAD><TITLE>%s</TITLE><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="fr"></HEAD><BODY><H1>%s</H1>\nCe document a été déplacé à une nouvelle <a href="%s">adresse</a>. Veuillez mettre à jour vos documents et listes d'accès en conséquence.\n(This document has moved to a new location. Please update your documents and hotlists accordingly.</BODY></HTML>)]
+fr,frame,18,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="fr"><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>]
+fr,frame,19,[process-uri-objects]
+fr,frame,20,[cannot find template %s]
+fr,frame,21,[process-uri-objects]
+fr,frame,22,[no partial path after object processing]
+fr,frame,23,[find-service]
+fr,frame,24,[invalid shexp %s]
+fr,frame,25,[find-service]
+fr,frame,26,[invalid shexp %s]
+fr,frame,27,[handle-processed]
+fr,frame,28,[no way to service request for %s]
+fr,frame,29,[finish-socks-request]
+fr,frame,30,[close failed (%s), csd=%d]
+fr,frame,31,[This beta software has expired.\n]
+fr,frame,32,[mr_accept(%d)]
+fr,frame,33,[Error issuing read on accept socket]
+fr,frame,34,[acb_accept_connection(%d)]
+fr,frame,35,[Error getting accept socket (%d)]
+fr,frame,36,[Error in accept! (%d, %s)]
+fr,frame,37,[Error creating new accept request]
+fr,frame,38,[accepted connection: %d (NSPR %d)]
+fr,frame,39,[Error creating new session structure]
+fr,frame,40,[accel_read_request()]
+fr,frame,41,[Error allocating request read buffer]
+fr,frame,42,[Error issuing async read request]
+fr,frame,43,[acb_read_request(%d, bytes %d)]
+fr,frame,44,[acb_read_req(1 session = %d)]
+fr,frame,45,[Error reading request (%d, %s)]
+fr,frame,46,[Client aborted connection]
+fr,frame,47,[Error reading request]
+fr,frame,48,[Error creating new request]
+fr,frame,49,[error occurred, closing %d, io was for %d]
+fr,frame,50,[accel_async_scan_headers()]
+fr,frame,51,[out of memory: accel_async_scan_headers]
+fr,frame,52,[out of memory: accel_async_scan_headers]
+fr,frame,53,[Error during async read (%d, %s)]
+fr,frame,54,[scan-headers reports: line too long]
+fr,frame,55,[scan-headers reports: too many headers]
+fr,frame,56,[Error reading headers]
+fr,frame,57,[scan-headers reports: header missing terminator (an empty line)]
+fr,frame,58,[scan-headers reports: header was empty]
+fr,frame,59,[nom sans valeur: obtention de la ligne "%s"\n(name without value: got line as shown)]
+fr,frame,60,[accel_send_plain_file()]
+fr,frame,61,[accel_send_plain_file() - found request %d]
+fr,frame,62,[Parse headers lost the URI!]
+fr,frame,63,[accel_send_plain_file() - found uri %s]
+fr,frame,64,[accel_send_plain_file() - found in cache?]
+fr,frame,65,[malloc died!]
+fr,frame,66,[Error writing back file\n]
+fr,frame,67,[acb_send_plain_file(%d)]
+fr,frame,68,[Error writing in acb_send_plain_file (%d, %s)]
+fr,frame,69,[acb_close_connection(%d)]
+fr,frame,70,[Errored IO in acb_close_connection (%d, %s)]
+fr,frame,71,[Unable to close socket %d]
+fr,frame,72,[accel-cache-insert: Error allocating entry]
+fr,frame,73,[cache-init: server cache disabled]
+fr,frame,74,[accel_file_cache: Error initializing file cache]
+fr,frame,75,[accel_file_cache: Error creating cache]
+fr,frame,76,[accel_file_cache_init: CacheHashSize < %d, using %d]
+fr,frame,77,[accel_file_cache_init: CacheHashSize > %d, using %d]
+fr,frame,78,[accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d]
+fr,frame,79,[accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d]
+fr,frame,80,[accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d]
+fr,frame,81,[accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d]
+fr,frame,82,[accel_file_cache: Error initializing file cache]
+fr,frame,83,[file-cache: enabled = %s ]
+fr,frame,84,[on]
+fr,frame,85,[off]
+fr,frame,86,[file-cache: MaxNumberOfCachedFiles %d (0x%x)]
+fr,frame,87,[file-cache: CacheHashSize %d (0x%x)]
+fr,frame,88,[file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)]
+fr,frame,89,[accel-cache-insert: Error allocating entry]
+fr,frame,90,[file-cache-cleanup: munmap failed (%s)]
+fr,frame,91,[file-cache-cleanup: found mmapped file \non system without mmap]
+fr,frame,92,[file_cache_init: MaxTotalCachedFileSize < %d, using %d]
+fr,frame,93,[file_cache_init: MaxTotalCachedFileSize > %d, using %d]
+fr,frame,94,[file cache using mmap flags 0x%x]
+fr,frame,95,[file cache using mmap prots 0x%x]
+fr,frame,96,[file-cache-init: could not create lock]
+fr,frame,97,[file-cache: unable to create temporary directory %s.\n]
+fr,frame,98,[file-cache: unable to create temporary directory %s.\n]
+fr,frame,99,[file-cache: GetTempPath() Cannot find temp directory to store file!]
+fr,frame,100,[file-cache-init: set max cached file size to %d]
+fr,frame,101,[file-cache-init: could not create lock]
+fr,frame,102,[file_cache_destroy()]
+fr,frame,103,[file-cache: Unable to get temp file name. Error %s]
+fr,frame,104,[file-cache: Unable to get temp file name. Error %s]
+fr,frame,105,[file-cache-insert: Error allocating entry]
+fr,frame,106,[file-cache-create: Error opening file %s (%s)]
+fr,frame,107,[file-cache-create: Error stat()ing file %s (%s)]
+fr,frame,108,[file-cache-create: Error mmap()ing file %s (%s)]
+fr,frame,109,[file-cache-create: malloc failure]
+fr,frame,110,[file-cache-create: error case failed to munmap(%d, %d) (%s)]
+fr,frame,111,[file-cache-valid: cannot stat %s]
+fr,frame,112,[dir change: invalidating %s (%d)]
+fr,frame,113,[file-cache: asynchronous file change notification failed.]
+fr,frame,114,[dir change: offset %d, action %d, len %d, name %s]
+fr,frame,115,[unable to check async file status]
+fr,frame,116,[ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s]
+fr,frame,117,[file-cache-add-watch failure- unable to open directory %s. Error %s]
+fr,frame,118,[ReadDirectoryChangesW failure- unable to start watching %s. Error %s]
+fr,frame,119,[func_exec]
+fr,frame,120,[no handler function given for directive]
+fr,frame,121,[func_exec]
+fr,frame,122,[cannot find function named %s]
+fr,frame,123,[handle-request]
+fr,frame,124,[method without URI]
+fr,frame,125,[http-parse-request]
+fr,frame,126,[while scanning HTTP headers, %s]
+fr,frame,127,[handle-request]
+fr,frame,128,[read from %s failed, error is %s]
+fr,frame,129,[handle-request]
+fr,frame,130,[request too long]
+fr,frame,131,[start-http-response]
+fr,frame,132,[write failed (%s)]
+fr,frame,133,[start-http-response]
+fr,frame,134,[write failed (%s)]
+fr,frame,135,[http-status]
+fr,frame,136,[%d is not a valid HTTP status code]
+fr,frame,137,[finish-request]
+fr,frame,138,[close failed (%s)]
+fr,frame,139,[Unable to close socket for writing]
+fr,frame,140,[os has %d objects]
+fr,frame,141,[obj %d has no hash table at %d]
+fr,frame,142,[obj %d has no param]
+fr,frame,143,[obj %d name %s value %s]
+fr,frame,144,[.....directives %d.......]
+fr,frame,145,[.....directive %d]
+fr,frame,146,[.......instance %d]
+fr,frame,147,[...........param name %s value %s]
+fr,frame,148,[ClearConfigurationParameters:RegCreateKey %s]
+fr,frame,149,[ClearConfigurationParameters:RegEnumKey %s failed]
+fr,frame,150,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+fr,frame,151,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+fr,frame,152,[Unable to allocate Subject property list.\n]
+fr,frame,153,[Unable to set session ptr in Subject property list - error=%d\n]
+fr,frame,154,[Unable to set request ptr in Subject property list - error=%d\n]
+fr,frame,155,[file-cache-valid: cannot stat %s]
+fr,frame,156,[file-cache-create: Error stat()ing file %s (%s)]
+fr,httpdaemon,-1,[$DBT: httpdaemon in DB file v1 $]
+fr,httpdaemon,1,[Error in ConvertThreadToFiber]
+fr,httpdaemon,2,[Error in ConvertThreadToFiber]
+fr,httpdaemon,3,[Error in md_start_system]
+fr,httpdaemon,4,[Error in CreateFiber - idlefiber]
+fr,httpdaemon,5,[Error in GetQueuedCompletionStatus]
+fr,httpdaemon,6,[Error creating completion port]
+fr,httpdaemon,7,[Could not SetHandleNonInheritable (%s)]
+fr,httpdaemon,8,[Error accept/read new conn]
+fr,httpdaemon,9,[Error in Respond()]
+fr,httpdaemon,10,[Error in RespondCompleted()]
+fr,httpdaemon,11,[daemon: unable to fork new process (%s)\n]
+fr,httpdaemon,12,[daemon: setsid failed (%s)\n]
+fr,httpdaemon,13,[daemon: can't log pid to %s (%s)\n]
+fr,httpdaemon,14,[warning: could not set group id to %d (%s)\n]
+fr,httpdaemon,15,[warning: could not set user id to %d (%s)\n]
+fr,httpdaemon,16,[warning: daemon is running as super-user\n]
+fr,httpdaemon,17,[could not determine current user name\n]
+fr,httpdaemon,18,[error: chroot to %s failed (%s)\n]
+fr,httpdaemon,19,[WARNING! netscape executable and library have different versions.\n]
+fr,httpdaemon,20,[startup: listening to %s://%s, port %d as %s\n]
+fr,httpdaemon,21,[startup: listening to %s://%s, port %d as %s\n]
+fr,httpdaemon,22,[seminit failed (%s)\n]
+fr,httpdaemon,23,[Using single threaded accepts.]
+fr,httpdaemon,24,[Using multi threaded accepts.]
+fr,httpdaemon,25,[Using partial single threaded accepts.]
+fr,httpdaemon,26,[This machine has %d processors.]
+fr,httpdaemon,27,[Error calling thr_seconcurrency(%d)- (%s)]
+fr,httpdaemon,28,[Set conncurrency to %d.]
+fr,httpdaemon,29,[can't fork new process (%s)]
+fr,httpdaemon,30,[This beta software has expired.\n]
+fr,httpdaemon,31,[can't create IPC pipe (%s)]
+fr,httpdaemon,32,[write to wakeup pipe failed (%s)]
+fr,httpdaemon,33,[select thread miss]
+fr,httpdaemon,34,[startup failure: could not bind to port %d (%s)\n]
+fr,httpdaemon,35,[startup failure: could not bind to port %d, IP address %s (%s)\n]
+fr,libaccess,-1,[$DBT: libaccess in DB file v1 $]
+fr,libaccess,1,[basic-ncsa]
+fr,libaccess,2,[cannot open database %s]
+fr,libaccess,3,[basic-ncsa]
+fr,libaccess,4,[user %s password did not match database %s]
+fr,libaccess,5,[basic-ncsa]
+fr,libaccess,6,[cannot open connection to LDAP server on %s:%d]
+fr,libaccess,7,[basic-ncsa]
+fr,libaccess,8,[user %s password did not match LDAP on %s:%d]
+fr,libaccess,9,[acl-state]
+fr,libaccess,10,[missing realm]
+fr,libaccess,11,[Unable to allocate ACL List Hash\n]
+fr,libaccess,12,[ACLEvalBuildContext unable to PERM_MALLOC cache structure\n]
+fr,libaccess,13,[ACLEvalBuildContext unable to create hash table\n]
+fr,libaccess,14,[ACLEvalBuildContext unable to allocate ACE Entry\n]
+fr,libaccess,15,[ACLEvalBuildContext unable to allocate ACE entry\n]
+fr,libaccess,16,[ACLEvalBuildContext unable to allocate Boundary Entry\n]
+fr,libaccess,17,[ACLEvalBuildContext failed.\n]
+fr,libaccess,18,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n]
+fr,libaccess,19,[LASDnsBuild unable to allocate hash table header\n]
+fr,libaccess,20,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,21,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,22,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,23,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,24,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,25,[LAS DNS build received request for attribute %s\n]
+fr,libaccess,26,[LASDnsEval - illegal comparator %s\n]
+fr,libaccess,27,[LASDnsEval unable to allocate Context struct\n\n]
+fr,libaccess,28,[LASDnsEval unable to get session address %d\n]
+fr,libaccess,29,[LASDnsEval unable to get DNS - error=%s\n]
+fr,libaccess,30,[LAS Group Eval received request for attribute %s\n]
+fr,libaccess,31,[LASGroupEval - illegal comparator %s\n]
+fr,libaccess,32,[LASGroupEval - ran out of memory\n]
+fr,libaccess,33,[LASGroupEval unable to get session address %d\n]
+fr,libaccess,34,[LASGroupEval unable to get session address %d\n]
+fr,libaccess,35,[LASGroupEval - couldn't locate getter for auth-user\n]
+fr,libaccess,36,[LASGroupEval - Attribute getter for auth-user failed\n]
+fr,libaccess,37,[LASGroupEval - Attribute getter didn't set auth-user\n]
+fr,libaccess,38,[Check group membership of user "%s" for group "%s"\n]
+fr,libaccess,39,[LDAPU_SUCCESS for group "%s"\n]
+fr,libaccess,40,[LDAPU_FAILED for group "%s"\n]
+fr,libaccess,41,[LAS_EVAL_FALSE\n]
+fr,libaccess,42,[LAS_EVAL_TRUE\n]
+fr,libaccess,43,[LASIpTreeAlloc - no memory\n]
+fr,libaccess,44,[IP LAS unable to allocate tree node\n]
+fr,libaccess,45,[IP LAS unable to allocate tree node\n]
+fr,libaccess,46,[LAS IP build received request for attribute %s\n]
+fr,libaccess,47,[LASIpEval - illegal comparator %s\n]
+fr,libaccess,48,[LASIpEval unable to get session address - error=%s\n]
+fr,libaccess,49,[LASIpEval unable to allocate Context struct\n\n]
+fr,libaccess,50,[LASIpEval - reach 32 bits without conclusion value=%s]
+fr,libaccess,51,[LAS Program Eval received request for attribute %s\n]
+fr,libaccess,52,[LASProgramEval - illegal comparator %s\n]
+fr,libaccess,53,[LASProgram unable to get session address %d\n]
+fr,libaccess,54,[bin]
+fr,libaccess,55,[LASProgramEval: request not of type admin or bin, passing.\n]
+fr,libaccess,56,[LASProgramEval: check if program %s matches pattern %s.\n]
+fr,libaccess,57,[LASProgramEval: Invalid wildcard expression %s.\n]
+fr,libaccess,58,[LAS_EVAL_FALSE\n]
+fr,libaccess,59,[LAS_EVAL_TRUE\n]
+fr,libaccess,60,[Unexpected attribute in dayOfWeek - %s\n]
+fr,libaccess,61,[Illegal comparator for dayOfWeek - %s\n]
+fr,libaccess,62,[Unexpected attribute in timeOfDay - %s\n]
+fr,libaccess,63,[LAS User Eval received request for attribute %s\n]
+fr,libaccess,64,[LASUserEval - illegal comparator %s\n]
+fr,libaccess,65,[LASUserEval - ran out of memory\n]
+fr,libaccess,66,[LASUserEval unable to get session address %d\n]
+fr,libaccess,67,[LASUserEval unable to get session address %d\n]
+fr,libaccess,68,[LASGroupEval - couldn't locate getter for auth-user\n]
+fr,libaccess,69,[LASGroupEval - Attribute getter for auth-user failed\n]
+fr,libaccess,70,[LASGroupEval - Attribute getter didn't set auth-user\n]
+fr,libaccess,71,[Check if uid == user (i.e. check "%s" == "%s)"\n]
+fr,libaccess,72,[SUCCESS for user "%s"\n]
+fr,libaccess,73,[FAILED for user "%s"\n]
+fr,libaccess,74,[LAS_EVAL_FALSE\n]
+fr,libaccess,75,[LAS_EVAL_TRUE\n]
+fr,libaccess,76,[]
+fr,libaccess,77,[LASProgram unable to get request address - error=%s]
+fr,libaccess,78,[LASProgram rejecting request for program %s from pattern %s]
+fr,libaccess,79,[ACL_CacheFlush: unable to parse file "%s"\n]
+fr,libaccess,80,[ACL_CacheFlush: unable to concatenate ACL list "%s"\n]
+fr,libaccess,81,[ACL_CacheFlush: unable to open and process the magnus file "%s"\n]
+fr,libaccess,82,[Illegal comparator for timeOfDay - %s\n]
+fr,libaccess,83,[ACL_EvalBuildContext unable to create hash table\n]
+fr,libaccess,84,[ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n]
+fr,libaccess,85,[ACL_EvalBuildContext unable to allocate ACE entry\n]
+fr,libaccess,86,[ACL_EvalBuildContext unable to allocate auth pointer array\n]
+fr,libaccess,87,[ACL_EvalBuildContext unable to allocate auth plist\n]
+fr,libaccess,88,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n]
+fr,libaccess,89,[ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n]
+fr,libaccess,90,[ACL_ModuleRegister: module name is missing\n]
+fr,libaccess,91,[ACL_ModuleRegister: call to module init function returned a failed status\n]
+fr,libaccess,92,[ACL_GetAttribute: couldn't determine method for %s\n]
+fr,libaccess,93,[ACL_GetAttribute: couldn't locate getter for %s]
+fr,libaccess,94,[ACL_GetAttribute: attr getter failed to get %s]
+fr,libaccess,95,[ACL_GetAttribute: attr getter failed to get %s]
+fr,libaccess,96,[ACL_GetAttribute: All attribute getters declined for attr %s]
+fr,libaccess,97,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+fr,libaccess,98,[ACL_DatabaseRegister: database name is missing]
+fr,libaccess,99,[Error reading the DB Map File: %s. Reason: %s]
+fr,libaccess,100,[URL is missing for database %s]
+fr,libaccess,101,[Invalid property value pair for database %s]
+fr,libaccess,102,["default" database must be an LDAP database]
+fr,libaccess,103,[Multiple "default" databases are being registered]
+fr,libaccess,104,["default" LDAP database must be registered]
+fr,libaccess,105,[LASGroupEval unable to get database name - error= %s]
+fr,libaccess,106,[received invalid program expression %s]
+fr,libaccess,107,[parse_ldap_url: database url is missing]
+fr,libaccess,108,[parse_ldap_url: database name is missing]
+fr,libaccess,109,[parse_ldap_url: error in parsing ldap url. Reason: %s]
+fr,libaccess,110,[ldap password check: unable to get database name - error=%s]
+fr,libaccess,111,[ldap password check: unable to get parsed database %s]
+fr,libaccess,112,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+fr,libaccess,113,[ldap password check: LDAP error: "%s"]
+fr,libaccess,114,[get_user_ismember_ldap unable to get database name - error=%s]
+fr,libaccess,115,[get_user_ismember_ldap unable to get parsed database %s]
+fr,libaccess,116,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+fr,libaccess,117,[get_user_ismember_ldap: group %s does not exist]
+fr,libaccess,118,[get_user_ismember_ldap: LDAP error: "%s"]
+fr,libaccess,119,[ACL_LDAPDatabaseHandle: %s is not a registered database]
+fr,libaccess,120,[ACL_LDAPDatabaseHandle: %s is not an LDAP database]
+fr,libaccess,121,[ACL_LDAPDatabaseHandle: out of memory]
+fr,libaccess,122,[ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s]
+fr,libaccess,123,[ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s]
+fr,libaccess,124,[insufficient dynamic memory]
+fr,libaccess,125,[error opening file, %s: %s]
+fr,libaccess,126,[duplicate definition of %s]
+fr,libaccess,127,[file %s, line %s: duplicate definition of %s]
+fr,libaccess,128,[file %s, line %s: syntax error]
+fr,libaccess,129,[file %s, line %s: %s is undefined]
+fr,libaccess,130,[in acl %s, %s %s is undefined]
+fr,libaccess,131,[database %s: error accessing %s]
+fr,libaccess,132,[%s]
+fr,libaccess,133,[file %s, line %s: invalid syntax]
+fr,libaccess,134,[file %s, line %s: syntax error at "%s"]
+fr,libaccess,135,[realm %s is not defined]
+fr,libaccess,136,[error code = %d]
+fr,libaccess,137,[internal ACL error]
+fr,libaccess,138,[invalid argument]
+fr,libaccess,139,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+fr,libaccess,140,[couldn't determine dbtype from: %s]
+fr,libaccess,141,[Failed to register database %s]
+fr,libaccess,142,[ACL call returned failed status]
+fr,libaccess,143,[file %s: ACL IO error - %s]
+fr,libaccess,144,[acl_user_exists: mémoire insuffisante]
+fr,libaccess,145,[acl_user_exists: l'utilisateur n'existe plus]
+fr,libaccess,146,[acl_user_exists: erreur de plist]
+fr,libadmin,-1,[$DBT: libadmin in DB file v1 $]
+fr,libadmin,1,[ Help ]
+fr,libadmin,2,[ OK ]
+fr,libadmin,3,[ Reset ]
+fr,libadmin,4,[ Done ]
+fr,libadmin,5,[ Cancel ]
+fr,libir,-1,[$DBT: libadmin in DB file v1 $]
+fr,libir,1,[An I/O error occurred before all form data could be read.]
diff --git a/l10n/dirserv/fr/ns-slapd.txt.iso8859 b/l10n/dirserv/fr/ns-slapd.txt.iso8859
new file mode 100644
index 00000000..829750db
--- /dev/null
+++ b/l10n/dirserv/fr/ns-slapd.txt.iso8859
@@ -0,0 +1,883 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/**************************************************************************/
+/* The copyright notice(s) in this Source Code does not indicate actual */
+/* or intended publication of this Source Code. */
+/**************************************************************************/
+
+/* This text file was generated by program dblink */
+
+$Revision: 1.1 $
+$Log: ns-slapd.txt.iso8859,v $
+Revision 1.1 2005/01/21 00:40:48 cvsadm
+Initial revision
+
+Revision 1.1.4.3 2003/09/22 19:36:43 ulfw
+Update copyright years from 2001 to 2001-2003
+
+Revision 1.1.4.2 2001/11/03 01:07:25 richm
+XXX use new copyright XXX
+
+Revision 1.1.4.1 1998/10/10 02:14:09 ggood
+Copy from Directory40RtmBranchpoint to DirectoryBranch
+
+Revision 1.1.2.4.2.2.6.1 1998/04/04 23:16:55 mcs
+merge changes made on directory31_rtm_branch into server4_directory_branch
+
+Revision 1.1.2.4.2.2.2.1 1998/02/24 05:51:57 noriko
+Synched with server3_i18npkg_branch
+
+Revision 1.1.2.6 1997/12/31 00:23:39 werudge
+Remove \n from dsgw,198 to fix JavaScript problem
+
+Revision 1.1.2.5 1997/12/19 02:03:54 werudge
+Based on en/ns-slapd.txt : 1.1.2.3
+daily 971113.1 SOLARIS-export-optimize-normal-slapd
+$EndLog$
+
+$StartStringData$
+
+fr,base,-1,[$DBT: base in DB file v1 $]
+fr,base,1,[mémoire insuffisante pour créer la table de hachage]
+fr,base,2,[mémoire insuffisante pour créer la table de hachage ]
+fr,base,3,[cache_destroy : les tables du cache semblent corrompues.]
+fr,base,4,[impossible d´allouer l´entrée de hachage]
+fr,base,5,[cache_insert : impossible de créer l´entrée de cache]
+fr,base,6,[HTTP/1.0 200 OK\nContent-type: text/html\n\n]
+fr,base,7,[<H2>Rapport d'état du cache Netscape\n(Netscape cache status report)</H2>\n]
+fr,base,8,[Aucun cache sur le système (No caches on system)<P>]
+fr,base,9,[<H2>cache %s</H2>\n]
+fr,base,10,[Rapport de connexions au cache: %d/%d (%f)\n(Cache hit ratio: as shown)</P>\n</P>\n]
+fr,base,11,[Taille du cache: %d/%d\n(Cache size: as shown)</P>\n</P>\n]
+fr,base,12,[Taille de la table de hachage: %d\n(Hash table size: as shown)</P>\n</P>\n]
+fr,base,13,[mru : %d</P>\nlru : %d</P>\n]
+fr,base,14,[<UL><TABLE BORDER=4> <TH>Compartiment (Bucket)</TH> <TH>Adresse (Address)</TH> <TH>Clef (Key)</TH> <TH>Nombre d'accès (Access Count)</TH> <TH>Supprimer (Delete)</TH> <TH>Suivant (Next)</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>Données (Data)</TH>\n]
+fr,base,15,[munmap failed (%s)]
+fr,base,16,[munmap failed (%s)]
+fr,base,17,[close failed (%s)]
+fr,base,18,[daemon: unable to fork new process (%s)\n]
+fr,base,19,[daemon: setsid failed (%s)\n]
+fr,base,20,[daemon: can't log pid to %s (%s)\n]
+fr,base,21,[warning: could not set group id to %d (%s)\n]
+fr,base,22,[warning: could not set user id to %d (%s)\n]
+fr,base,23,[warning: daemon is running as super-user\n]
+fr,base,24,[could not determine current user name\n]
+fr,base,25,[error: chroot to %s failed (%s)\n]
+fr,base,27,[, address %s]
+fr,base,28,[warning: statistics disabled (%s)\n]
+fr,base,29,[security handshake timed out for pid %d]
+fr,base,30,[warning: statistics disabled (%s)\n]
+fr,base,31,[secure handshake failed (code %d)\n]
+fr,base,32,[accept failed (%s)]
+fr,base,33,[warning: statistics disabled (%s)\n]
+fr,base,34,[select thread miss]
+fr,base,35,[keepalive worker awoken with no work to do]
+fr,base,36,[could not create new thread: %d (%s)]
+fr,base,37,[wait for sema succeeded, but nothing to dequeue]
+fr,base,38,[queue-sema creation failure]
+fr,base,39,[error getting processor info for processor %d]
+fr,base,40,[Error binding to processor %d]
+fr,base,41,[bound process %d to processor %d]
+fr,base,42,[Netscape server is not explicitly binding to any processors.]
+fr,base,43,[cache monitor exited]
+fr,base,44,[cache batch update daemon exited]
+fr,base,45,[Using single threaded accepts.]
+fr,base,46,[Using multi threaded accepts.]
+fr,base,47,[Using partial single threaded accepts.]
+fr,base,48,[This machine has %d processors.]
+fr,base,49,[Error calling thr_seconcurrency(%d)- (%s)]
+fr,base,50,[Set conncurrency to %d.]
+fr,base,51,[WARNING! netscape executable and library have different versions.\n]
+fr,base,54,[seminit failed (%s)\n]
+fr,base,55,[This beta software has expired.\n]
+fr,base,56,[Cache monitor respawned]
+fr,base,57,[Cache batch update daemon respawned]
+fr,base,58,[can't find empty statistics slot]
+fr,base,59,[can't fork new process (%s)]
+fr,base,60,[assert failed! %s\n]
+fr,base,61,[mr_table_init()]
+fr,base,62,[malloc failed]
+fr,base,63,[malloc failed!]
+fr,base,64,[mr_add_io(%d, type %d, file %d)]
+fr,base,65,[mr_add_io - stage 1]
+fr,base,66,[mr_add_io - stage 2]
+fr,base,67,[mr_add_io found invalid IO type %d]
+fr,base,68,[mr_add_io - adding timeout]
+fr,base,69,[Out of memory!\n]
+fr,base,70,[done with mr_add_io]
+fr,base,71,[mr_del_io(%d, type %d, file %d)]
+fr,base,72,[mr_del_io found invalid IO type %d]
+fr,base,73,[mr_lookup_io(%d)]
+fr,base,74,[mr_async_io(%d, %d bytes, file %d)]
+fr,base,75,[malloc failure adding async IO]
+fr,base,76,[Error adding async io!]
+fr,base,77,[Cannot seek for read!]
+fr,base,78,[read failure! (%d, %s)]
+fr,base,79,[do_read read %d bytes for file %d]
+fr,base,80,[Cannot seek for write!]
+fr,base,81,[writev failure! (%d, %s)]
+fr,base,82,[write failure! (%d, %s)]
+fr,base,83,[do_write wrote %d bytes for file %d]
+fr,base,84,[do_timeout(mrp %d)]
+fr,base,85,[do_timeout: found IO (timer=%d, time=%d)]
+fr,base,86,[error deleting io]
+fr,base,87,[timeout callback failure for %d\n]
+fr,base,88,[mr_get_event(%d) - outstanding io %d]
+fr,base,89,[mr_get_event: Waiting for reads on FD:]
+fr,base,90,[mr_get_event: Waiting for writes on FD:]
+fr,base,91,[ %d]
+fr,base,92,[ %d]
+fr,base,93,[mr_get_event set no timeout]
+fr,base,94,[mr_get_event set timeout to: %d.%d sec]
+fr,base,95,[error in select (%d, %s)]
+fr,base,96,[mr_get_event() - select found %d]
+fr,base,97,[error looking up IO fd %d]
+fr,base,98,[read failed for fd %d]
+fr,base,99,[error deleting io]
+fr,base,100,[callback failure for %d\n]
+fr,base,101,[error looking up IO fd %d]
+fr,base,102,[writing: header len %d, writelen %d, total %d]
+fr,base,103,[write failed for fd %d]
+fr,base,104,[error deleting io]
+fr,base,105,[callback failure for %d\n]
+fr,base,106,[Error creating dns cache]
+fr,base,107,[dns_cache_init: hash_size <= 0, using %d]
+fr,base,108,[dns_cache_init: cache-size <= %d, using %d]
+fr,base,109,[dns_cache_init: cache-size is %d is too large, using %d.]
+fr,base,110,[dns_cache_init: expire_time <= 0, using %d]
+fr,base,111,[dns_cache_init: expire is %d is too large, using %d seconds.]
+fr,base,112,[Error creating dns cache]
+fr,base,113,[dns-cache-insert: Error allocating entry]
+fr,base,114,[dns-cache-insert: malloc failure]
+fr,base,115,[successful server startup]
+fr,base,116,[%s B%s]
+fr,base,117,[Netscape executable and shared library have different versions]
+fr,base,118,[ executable version is %s]
+fr,base,119,[ shared library version is %s]
+fr,base,120,[error reporting shutting down]
+fr,base,121,[warning]
+fr,base,122,[config]
+fr,base,123,[security]
+fr,base,124,[failure]
+fr,base,125,[catastrophe]
+fr,base,126,[info]
+fr,base,127,[verbose]
+fr,base,128,[event_handler:Failed to wait on events %s]
+fr,base,129,[could not wait on resume event event (%s)]
+fr,base,130,[dlopen of %s failed (%s)]
+fr,base,131,[dlopen of %s failed (%s)]
+fr,base,132,[The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!]
+fr,base,133,[Terminating the server %s]
+fr,base,134,[kill_server:cannot open server event %s]
+fr,base,135,[kill_server:cannot set server event %s]
+fr,base,136,[error: could not get socket (%s)\n]
+fr,base,137,[error: could not set socket option (%s)\n]
+fr,base,138,[Terminating Service:error: could not bind to address %s port %d (%s)\n]
+fr,base,139,[Terminating Service:error: could not bind to port %d (%s)\n]
+fr,base,140,[SetHandleNonInheritable: could not duplicate socket (%s)]
+fr,base,141,[SetHandleNonInheritable: closing the original socket failed (%s)]
+fr,base,142,[Could not SetHandleInformation (%s)]
+fr,base,143,[Terminating Service:Failure: Could not open statistics file (%s)\n]
+fr,base,144,[Could not set Thread Local Storage Value for thread at slot %d]
+fr,base,145,[secure handshake failed (code %d)\n]
+fr,base,146,[accept failed %d (%s)]
+fr,base,147,[Failed to pulse Event %d %s]
+fr,base,148,[Failed to send MobGrowth Event to parent %s]
+fr,base,149,[Pulsing MobRespawn Event %d]
+fr,base,150,[respawn thread pool to %d (%d)]
+fr,base,151,[Could not open event to signal rotate application. Could not create the MoveLog event:%s]
+fr,base,152,[Failed to send MoveLog Event to rotate app %s]
+fr,base,153,[growing thread pool from %d to %d]
+fr,base,154,[Could not open the ServiceControlManager, Error %d]
+fr,base,155,[StartNetsiteService:Could not open the service %s: Error %d]
+fr,base,156,[StartNetsiteService:Could not start the service %s]
+fr,base,157,[Service Startup: Could not allocate security descriptor]
+fr,base,158,[Service Startup: Could not init security descriptor]
+fr,base,159,[Service Startup: Could not set the security Dacl]
+fr,base,160,[Terminating Service:WinSock init failed: %s]
+fr,base,161,[Httpd Server Startup failed: %s]
+fr,base,162,[can't find empty statistics slot]
+fr,base,163,[NT daemon: could not create new thread %d]
+fr,base,164,[Service Startup Failure. Terminating Service:Could not create event %d:%s]
+fr,base,165,[Service Startup Error. Could not create the MoveLog event:%s]
+fr,base,166,[Failed to wait on Event objects %s]
+fr,base,167,[Failed to wait on Event objects %s]
+fr,base,168,[pipebuf_buf2sd: pipebuf_grab IO_ERROR %d]
+fr,base,169,[pool-init: memory pools disabled]
+fr,base,170,[pool-init: free_size <= 0, using %d]
+fr,base,171,[pool-create-block: out of memory]
+fr,base,172,[pool-create: out of memory]
+fr,base,173,[pool-create: out of memory]
+fr,base,174,[pool-malloc: out of memory]
+fr,base,175,[FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.]
+fr,base,176,[regex error: %s (regex: '%s')]
+fr,base,177,[can't create IPC pipe (%s)]
+fr,base,178,[write to wakeup pipe failed (%s)]
+fr,base,179,[flushing %d connections; current %d; tot %d]
+fr,base,180,[accept failed (%s)]
+fr,base,181,[Error creating time cache]
+fr,base,182,[time-cache: cache disabled]
+fr,base,183,[time_cache_init: hash_size < %d, using default, %d]
+fr,base,184,[time_cache_init: hash_size > %d, using default, %d]
+fr,base,185,[time_cache_init: cache_size < %d, using default, %d]
+fr,base,186,[time_cache_init: cache_size > %d, using default, %d]
+fr,base,187,[Error allocating memory for time_cache]
+fr,base,188,[Error allocating memory for time_cache entry]
+fr,base,189,[Error allocating memory for time_cache entry]
+fr,base,190,[Error inserting new time_cache entry]
+fr,base,191,[Error allocating memory for time_cache]
+fr,base,192,[cs-terminate failure (%s)]
+fr,base,193,[cs-init failure (%s)]
+fr,base,194,[cs-wait failure (%s)]
+fr,base,195,[cs-post failure (%s)]
+fr,base,196,[Unable to create nonblocking socket (%s)]
+fr,base,197,[error: could not set keepalive (%s)\n]
+fr,base,198,[error: could not set recv timeout (%s)\n]
+fr,base,199,[error: could not set send timeout (%s)\n]
+fr,base,200,[Unable to create nonblocking socket (%s)]
+fr,base,201,[sem_grab failed (%s)]
+fr,base,202,[sem_release failed (%s)]
+fr,base,203,[sem_release failed (%s)]
+fr,base,204,[Could not remove temporary directory %s, Error %d]
+fr,base,205,[Could not remove temporary directory %s, Error %d]
+fr,dsgw,-1,[$DBT: dsgw in DB file v1 $]
+fr,dsgw,1,[Méthode de demande HTTP inconnue (Unknown HTTP request method)]
+fr,dsgw,2,[Données HTML de formulaire non valides ou incomplètes (Invalid or incomplete HTML form data)]
+fr,dsgw,3,[Mémoire épuisée (Out of memory)]
+fr,dsgw,4,[L´entrée de requête/formulaire exigée est manquante (Required query/form input is missing)]
+fr,dsgw,5,[Caractère non autorisé dans le chemin d´accès au fichier (Illegal character in file path)]
+fr,dsgw,6,[Fichier de configuration erroné ou manquant (Bad or missing configuration file)]
+fr,dsgw,7,[Impossible d´initialiser LDAP (Unable to initialize LDAP)]
+fr,dsgw,8,[Une erreur est survenue lors du contact du serveur LDAP (An error occurred while contacting the LDAP server)]
+fr,dsgw,9,[Type d´objet de recherche inconnu (Unknown search object type)]
+fr,dsgw,10,[Etiquette d´attribut inconnue (Unknown attribute label)]
+fr,dsgw,11,[Invite de correspondance inconnue (Unknown match prompt)]
+fr,dsgw,12,[Aucun filtre de recherche pour ce type d´objet (No search filters for object type)]
+fr,dsgw,13,[Impossible d´ouvrir le fichier de modèle HTML (Unable to open HTML template file)]
+fr,dsgw,14,[Mode de recherche inconnu; utiliser "smart", "complex", "pattern" ou "auth" (Unknown search mode - use "smart", "complex", "pattern", or "auth")]
+fr,dsgw,15,[Nom distinctif manquant dans l´URL (Distinguished Name missing in URL)]
+fr,dsgw,16,[Portée inconnue dans l´URL (doit être: base, sub ou one) (Unknown scope in URL (should be base, sub, or one))]
+fr,dsgw,17,[URL non reconnu ou erreur inconnue (Unrecognized URL or unknown error)]
+fr,dsgw,18,[Format d´URL erroné (Bad URL format)]
+fr,dsgw,19,[Erreur interne (Internal error)]
+fr,dsgw,20,[Impossible d´écrire sur le fichier d´index de modèles (Unable to write template index file)]
+fr,dsgw,21,[Impossible d´ouvrir le fichier d´index de modèles (Unable to open template index file)]
+fr,dsgw,22,[Impossible de lire le répertoire (Unable to read directory)]
+fr,dsgw,23,[Echec de l´initialisation SSL LDAP (vérifiez le chemin de sécurité) (LDAP SSL initialization failed (check the security path))]
+fr,dsgw,24,[Pour que les formulaires d'utilisateurs et de groupes puissent fonctionner sur SSL avec Administration Server, vous-même ou l'administrateur de votre système devez activer SSL. La page Encryption|On/Off peut être utilisée à cette fin.\n(For the Users and Groups forms to work over SSL, you or your server administrator needs to activate SSL for this Administration Server. The Encryption|On/Off page can be used to do so]
+fr,dsgw,25,[Références d´authentification introuvables dans la base de données d´authentification (Authentication credentials not found in authentication database)]
+fr,dsgw,26,[Erreur de récupération des données depuis la base de données d´authentification (Error retrieving data from the authentication database)]
+fr,dsgw,27,[Vos références d´authentification ont expiré (Your authentication credentials have expired)]
+fr,dsgw,28,[Impossible de créer une chaîne aléatoire]
+fr,dsgw,29,[Aucun nom distinctif n´a été fourni lors du retrait des références (No distinguished name was provided when retrieving credentials)]
+fr,dsgw,30,[Impossible d´ouvrir la base de données d´authentification (Cannot open authentication database)]
+fr,dsgw,31,[Impossible d´annexer des données à la base de données d´authentification (Could not append data to the authentication database)]
+fr,dsgw,32,[Aucun gestionnaire de répertoires n´est défini (No Directory Manager is defined)]
+fr,dsgw,33,[Aucune chaîne de recherche n´a été fournie. Veuillez essayer à nouveau (No search string was provided. Please try again)]
+fr,dsgw,34,[Le fichier de configuration comporte trop d´arguments sur une ligne (Too many arguments on one line in the config. file)]
+fr,dsgw,35,[Echec de l´initialisation des sockets Windows (Failed to initialize Windows Sockets)]
+fr,dsgw,36,[Les références d´authentification n´ont pas pu être obtenues auprès d´Administration Server (Authentication credentials could not be obtained from the Administration Server)]
+fr,dsgw,37,[Nom distinctif manquant dans l´URL ldapdb:// (Distinguished Name missing in ldapdb:// URL)]
+fr,dsgw,38,[URL non reconnu ou erreur inconnue (Unrecognized URL or unknown error)]
+fr,dsgw,39,[Format d´URL erroné (Bad URL format)]
+fr,dsgw,40,[Une erreur est survenue lors de l'initialisation de la base de données LDAP locale\n(An error occurred while initializing the local LDAP database)]
+fr,dsgw,41,[Type de service de répertoires inconnu; utiliser "local" ou "remote" (Unknown directory service type - use "local" or "remote")]
+fr,dsgw,42,[Une erreur est survenue lors de la lecture du fichier de configuration db (An error occurred while reading the db configuration file)]
+fr,dsgw,43,[Le chemin d´accès à NSHOME/userdb était NULL (NSHOME/userdb path was NULL)]
+fr,dsgw,44,[Impossible de mettre à jour la configuration du service de répertoires. (The directory service configuration could not be updated.)]
+fr,dsgw,45,[Impossible de lire l´entrée à partir du répertoire. (The entry could not be read from the directory.)]
+fr,dsgw,46,[Impossible d´effacer la base de données LDAP. (The LDAP database could not be erased.)]
+fr,dsgw,47,[Vous pouvez seulement modifier les entrées que vous avez créées. (You may not change entries besides your own.)]
+fr,dsgw,48,[Problème (Problem)]
+fr,dsgw,49,[Problème d´authentification (Authentication Problem)]
+fr,dsgw,50,[.\n<P>Vous devez ré-authentifier avant de continuer. (You must re-authenticate before continuing.)\n]
+fr,dsgw,51,[.\n<P>Vous devez ré-authentifier avant de continuer. (You must re-authenticate before continuing.)\n]
+fr,dsgw,52,[erreur inconnue (unknown error)]
+fr,dsgw,53,[L´opération a réussi. (The operation was successful.)]
+fr,dsgw,54,[Une erreur interne est survenue sur le serveur. Ceci indique généralement une sérieuse défaillance du serveur et doit être immédiatement porté à l´attention de l´administrateur de votre serveur. (An internal error occurred in the server. This usually indicates a serious malfunction in the server and should be brought to the attention of your server administrator.)]
+fr,dsgw,55,[Le serveur n´a pas compris la demande qui lui a été transmise par la passerelle. (The server could not understand the request which was sent to it by the gateway.)]
+fr,dsgw,56,[La réponse à votre demande a dépassé le temps imparti. Si vous recherchez des entrées, vous obtiendrez sans doute de meilleurs résultats en étant plus précis dans votre recherche. (A time limit was exceeded in responding to your request. If you are searching for entries, you may achieve better results if you are more specific in your search.)]
+fr,dsgw,57,[La réponse à votre demande a dépassé la taille autorisée. Si vous recherchez des entrées, vous obtiendrez sans doute de meilleurs résultats en étant plus précis car trop d´entrées répondent à vos critères de recherche. (A size limit was exceeded in responding to your request. If you are searching for entries, you may achieve better results if you are more specific in your search, because too many entries matched your search criteria.)]
+fr,dsgw,58,[La passerelle a tenté d'authentifier l'accès au serveur en utilisant\nune méthode incomprise par ce dernier.\n(The gateway attempted to authenticate to the server using\na method the server doesn't understand.)]
+fr,dsgw,59,[La passerelle a tenté d´authentifier l´accès au serveur en utilisant une méthode d´authentification non supportée par le serveur. (The gateway attempted to authenticate to the server using an authentication method which the server does not support.)]
+fr,dsgw,60,[Impossible d´honorer votre demande, sans doute parce que le serveur contacté ne contient pas les données que vous recherchez. Il est possible qu´une orientation vers un autre serveur ait été renvoyée sans avoir pu être suivie. Si vous étiez en train d´essayer de modifier le répertoire, il se peut que le serveur contenant la copie maîtresse des données ne soit pas disponible. (Your request could not be fulfilled, probably because the server that was contacted does not contain the data you are looking for. It is possible that a referral to another server was returned but could not be followed. If you were trying to make changes to the directory, it may be that the server that holds the master copy of the data is not available.)]
+fr,dsgw,61,[Votre demande a dépassé une limite administrative sur le serveur. (Your request exceeded an administrative limit in the server.)]
+fr,dsgw,62,[Une extension importante demandée par la passerelle n´est pas disponible sur ce serveur. (A critical extension that the gateway requested is not available in this server.)]
+fr,dsgw,63,[Le serveur n'a pas pu traiter la demande car celle-ci\nrenvoie à un attribut inexistant dans\nl'entrée.\n(The server was unable to process the request, because the\nrequest referred to an attribute which does not exist in the\nentry.)]
+fr,dsgw,64,[Le serveur n´a pas pu répondre à votre demande, car \ncelle-ci va à l´encontre d´une contrainte de la base de données.\n(The server was unable to fulfill your request, because the\nrequest violates a constraint.)]
+fr,dsgw,65,[Le serveur n´a pas pu ajouter une valeur à cette entrée car elle la contient déjà. (The server could not add a value to the entry, because that value is already contained in the entry.)]
+fr,dsgw,66,[Le serveur n'a pas pu localiser l'entrée. Si vous ajoutez une nouvelle entrée,\nassurez-vous qu'elle comporte une entrée principale.\nLa réception de ce message d'erreur lors d'une recherche indique que l'entrée\nrecherchée n'existe pas.\nSi vous étiez en train d'essayer d'authentifier l'accès en tant que gestionnaire de répertoires et que vous\navez vu apparaître ce message, vérifiez le fichier de configuration de la passerelle.\n(The server could not locate the entry. If adding a new entry,\nbe sure that the parent of the entry you are trying to add exists.\nIf you received this error while searching, it indicates that the\nentry which was being searched for does not exist.\nIf you were attempting to authenticate as the directory manager and\nreceived this error, check the gateway configuration file.)]
+fr,dsgw,67,[Le format d´un nom distinctif est incorrect. (A distinguished name was not in the proper format.)]
+fr,dsgw,68,[L´entrée que vous étiez en train d´essayer d´authentifier ne comporte pas de jeu de mots de passe, ou bien il lui manque d´autres références d´authentification requises. Pour que vous puissiez authentifier cette entrée, les attributs appropriés doivent avoir été ajoutés par le gestionnaire de répertoires. (The entry you attempted to authenticate as does not have a password set, or is missing other required authentication credentials. You cannot authenticate as that entry until the appropriate attributes have been added by the directory manager. )]
+fr,dsgw,69,[Le mot de passe (ou d'autres références d'authentification) que vous avez fourni\nest incorrect. (The password (or other authentication credentials) you supplied\nis incorrect. If you just changed your password, you might try exiting your browser and connecting again.)]
+fr,dsgw,70,[Vos privilèges sont insuffisants pour effectuer cette opération. (You do not have sufficient privileges to perform the operation.)]
+fr,dsgw,71,[Le serveur est trop occupé pour honorer votre demande. Essayez à nouveau dans quelques minutes. (The server is too busy to service your request. Try again in a few minutes.)]
+fr,dsgw,72,[Impossible de contacter le serveur LDAP. (The LDAP server could not be contacted.)]
+fr,dsgw,73,[Le serveur refuse de traiter votre demande. Cette dernière risquerait sans doute de le surcharger. Il se peut également qu´il ne soit pas configuré pour traiter votre demande. Si vous tentez d´effectuer une recherche, vous avez intérêt à en limiter la portée. (The server was unwilliing to process your request. Usually, this indicates that serving your request would put a heavy load on the server. It may also indicate that the server is not configured to process your request. If searching, you may wish to limit the scope of your search.)]
+fr,dsgw,74,[Le serveur de répertoires ne peut honorer votre demande car elle viole les exigences du schéma. Vous n´avez sans doute pas fourni de valeur pour un champ requis. Il se peut également que le schéma du serveur de répertoires nécessite une mise à jour. (The directory server could not honor your request because it violates the schema requirements. Typically, this means that you have not provided a value for a required field. It could also mean that the schema in the directory server needs to be updated.)]
+fr,dsgw,75,[Le serveur de répertoires ne vous permettra pas de supprimer ou de renommer une entrée qui comporte des sous-entrées. Si vous souhaitez continuer, vous devez d´abord supprimer toutes les sous-entrées. (The directory server will not allow you to delete or rename an entry if that entry has children. If you wish to do this, you must first delete all the child entries.)]
+fr,dsgw,76,[Le serveur ne peut ajouter une nouvelle entrée ni renommer une entrée existante car il existe déjà une entrée sous ce nom. (The server was unable to add a new entry, or rename an existing entry, because an entry by that name already exists.)]
+fr,dsgw,77,[Votre demande affecterait plusieurs serveurs de répertoires. (Your request would affect several directory servers.)]
+fr,dsgw,78,[Impossible de contacter le serveur de répertoires. Contactez\nl'administrateur de votre serveur de répertoires pour obtenir de l'aide.\n(The directory server could not be contacted. Contact your\ndirectory server administrator for assistance.)]
+fr,dsgw,79,[Une erreur est survenue lors de l´envoi de données au serveur. (An error occured while sending data to the server.)]
+fr,dsgw,80,[Une erreur est survenue lors de la lecture des données en provenance du serveur. (An error occured while reading data from the server.)]
+fr,dsgw,81,[Le serveur n´a pas répondu à la demande. La demande a dépassé le temps imparti. (The server did not respond to the request. The request timed out.)]
+fr,dsgw,82,[Le serveur ne supporte pas la méthode d´authentification utilisée par la passerelle. (The server does not support the authentication method used by the gateway.)]
+fr,dsgw,83,[Le filtre de recherche créé par la passerelle est erroné. (The search filter constructed by the gateway was in error.)]
+fr,dsgw,84,[L´opération a été annulée à votre demande. (The operation was cancelled at your request.)]
+fr,dsgw,85,[Une erreur interne est survenue dans la bibliothèque; un paramètre est incorrect. (An internal error occurred in the library - a parameter was incorrect.)]
+fr,dsgw,86,[Impossible d'ouvrir une connexion au serveur de répertoires. Contactez\nl'administrateur de votre serveur de répertoires pour obtenir de l'aide.\n(A connection to the directory server could not be opened. Contact your\ndirectory server administrator for assistance.)]
+fr,dsgw,87,[Une erreur inconnue est survenue. (An unknown error was encountered.)]
+fr,dsgw,88,[Cette entrée existe déjà (Entry Already Exists)]
+fr,dsgw,89,[Une entrée nommée (An entry named) ]
+fr,dsgw,90,[onMouseOver="window.status='Cliquez ici pour afficher cette entrée'; return true"\n(onMouseOver="window.status='Click here to view this entry'; return true")]
+fr,dsgw,91,[ existe déjà (already exists).<P>Veuillez choisir un autre nom et/ou une autre adresse.\n(Please choose another name and/or location.)\n<P>\n]
+fr,dsgw,92,[L´entrée principale n´existe pas (Parent entry does not exist)]
+fr,dsgw,93,[Impossible d´ajouter une entrée par le nom:<P><B>%s</B>,<P>\ncar il n´existe pas d´entrée principale.<P>\nPour pouvoir ajouter cette entrée, vous devez d´abord ajouter\n(You cannot add an entry by the name shown\nbecause the parent of that entry does not exist.<P>\nBefore you can add this entry, you must first add)\n]
+fr,dsgw,94,[l´entrée principale (its parent).\n]
+fr,dsgw,95,[une entrée nommée (an entry named):<P><B>%s</B>.\n]
+fr,dsgw,96,[Avertissement: pas d´authentification (continuation)...\n(Warning: no authentication (continuing)...)\n]
+fr,dsgw,97,[Entrée de répertoire %s (Directory Entry)]
+fr,dsgw,98,[<PRE>DN de l´entrée (Entry DN): %s</PRE><P>\n]
+fr,dsgw,99,[Les changements apportés à <B>%s</B> ont été enregistrés.]
+fr,dsgw,100,[<B>%s</B> has been added.]
+fr,dsgw,101,[<B>%s</B> has been deleted.]
+fr,dsgw,102,[Renamed <B>%s</B> to <B>%s</B>.]
+fr,dsgw,103,[<P><B>Remarque:</B> Parce que vous avez %s l´entrée pour laquelle vous étiez\nauthentifié, il a fallu mettre vos références \nd´authentification au rebut. Vous aurez besoin d´une nouvelle \nauthentification pour pouvoir apporter des modifications supplémentaires.\n(<B>Note:</B> because of your action on the entry you were \nauthenticated as, it was necessary to discard your \nauthentication credentials. You will need to authenticate \nagain to make additional changes.)\n]
+fr,dsgw,104,[supprimé (deleted)]
+fr,dsgw,105,[renommé (renamed)]
+fr,dsgw,106,[a changé le mot de passe de (changed the password of)]
+fr,dsgw,107,[L´attribut %s a été changé<BR>\n(Attribute shown was changed<BR>)\n]
+fr,dsgw,108,[ NON ASCII (%ld octets)\n(NOT ASCII (number of bytes shown))\n]
+fr,dsgw,109,[Aucune valeur n´a été entrée. Veuillez essayer à nouveau.\n(No values were entered. Please try again.)\n]
+fr,dsgw,110,[Aucun changement n´a été apporté.\n]
+fr,dsgw,111,[<P>Envoi de %s au serveur de répertoires...\n]
+fr,dsgw,112,[informations (information)]
+fr,dsgw,113,[changements (changes)]
+fr,dsgw,114,[<P>L´ajout de cette entrée a réussi.\n(Successfully added entry.)\n]
+fr,dsgw,115,[<P>La modification de cette entrée a réussi. Vos changements ont été enregistrés.\n(Successfully edited entry. Your changes have been saved.)\n]
+fr,dsgw,116,[<P>La suppression de cette entrée a réussi.\n(Successfully deleted entry.)\n]
+fr,dsgw,117,[<PRE>Le nouveau nom de cette entrée est: %s\n(The new name for the entry is as shown)\n</PRE><HR>\n]
+fr,dsgw,118,[<P>Le renommage de cette entrée a réussi.\n(Successfully renamed entry.)\n]
+fr,dsgw,119,[Vous devez fournir l´ancien mot de passe.]
+fr,dsgw,120,[Vous devez spécifier un nouveau mot de passe. Essayez à nouveau.]
+fr,dsgw,121,[Le nouveau mot de passe et sa confirmation ne correspondent pas. Veuillez essayer à nouveau]
+fr,dsgw,122,[<BR>Le %s <B>%s</B> est déjà utilisé. Veuillez en choisir un autre.\n(The item shown is already in use. Please choose a different one.)<BR>\n]
+fr,dsgw,123,[élément "%.100s" de données de formulaire manquant\n(missing form data element shown)]
+fr,dsgw,124,[Initialisation des données de configuration\n(Initializing config info)]
+fr,dsgw,125,[Impossible d´ouvrir le fichier. (Cannot open file.)]
+fr,dsgw,126,[Fichier dbconf mal formé. (Malformed dbconf file.)]
+fr,dsgw,127,[Nom du propriétaire manquant dans le fichier dbconf.\n(Missing property name in dbconf file.)]
+fr,dsgw,128,[Mémoire épuisée. (Out of memory.)]
+fr,dsgw,129,[Directive manquante dans le fichier dbconf.\n(Missing directive in dbconf file.)]
+fr,dsgw,130,[Impossible d'ouvrir le fichier de configuration "%s"\n(Cannot open config file with name shown)\n]
+fr,dsgw,131,[Argument manquant pour la directive "authlifetime"\n(Missing argument for "authlifetime" directive)\n]
+fr,dsgw,132,[Argument manquant pour la directive "dirmgr"\n(Missing argument for "dirmgr" directive)\n]
+fr,dsgw,133,[Argument manquant pour la directive "baseurl"\n(Missing argument for "baseurl" directive)\n]
+fr,dsgw,134,[URL erroné fourni pour la directive "baseurl"; le DN de base est manquant\n(Bad URL provided for "baseurl" directive - the base DN is missing)\n]
+fr,dsgw,135,[analyse de la directive baseurl\n(parsing baseurl directive)]
+fr,dsgw,136,[URL erroné fourni pour la directive "baseurl"; pas un URL "ldap://"\n(Bad URL provided for "baseurl" directive - not an "ldap://" URL)\n]
+fr,dsgw,137,[Les URL "ldaps://" ne sont pas encore supportés\n("ldaps://" URLs are not yet supported)\n]
+fr,dsgw,138,[Arguments manquants pour la directive "template"\n(Missing arguments for "template" directive)\n]
+fr,dsgw,139,[Argument manquant pour la directive "sslrequired"\n(Missing argument for "sslrequired" directive)\n]
+fr,dsgw,140,[Argument inconnu pour la directive "sslrequired" (l´argument doit être "never", "whenauthenticated", "always")\n(Unknown argument to "sslrequired" directive (should be "never", "whenauthenticated", "always"))\n]
+fr,dsgw,141,[Argument manquant pour la directive "securitypath"\n(Missing argument for "securitypath" directive)\n]
+fr,dsgw,142,[Argument manquant pour la directive "location-suffix"\n(Missing argument for "location-suffix" directive)\n]
+fr,dsgw,143,[Trois arguments sont requis pour la directive "location"\n(Three arguments are required for the "location" directive)\n]
+fr,dsgw,144,[Au moins deux arguments sont requis pour la directive "newtype"\n(At least two arguments are required for the "newtype" directive)\n]
+fr,dsgw,145,[Adresse inconnue dans la directive "newtype"\n(Unknown location in "newtype" directive)\n]
+fr,dsgw,146,[Trois ou quatre arguments sont requis pour la directive "tmplset"\n(Three or four arguments are required for the "tmplset" directive)\n]
+fr,dsgw,147,[Quatre arguments sont requis pour la directive "attrvset"\n(Four arguments are required for the "attrvset" directive)\n]
+fr,dsgw,148,[Argument manquant pour la directive "charset"\n(Missing argument for "charset" directive)\n]
+fr,dsgw,149,[Argument manquant pour la directive "ClientLanguage"\n(Missing argument for "ClientLanguage" directive)\n]
+fr,dsgw,150,[Argument manquant pour la directive "AdminLanguage"\n(Missing argument for "AdminLanguage" directive)\n]
+fr,dsgw,151,[Argument manquant pour la directive "DefaultLanguage"\n(Missing argument for "DefaultLanguage" directive)\n]
+fr,dsgw,152,[Nom de fichier manquant pour la directive "include"\n(Missing filename for "include" directive)\n]
+fr,dsgw,153,[Directive inconnue dans le fichier de configuration\n(Unknown directive in config file)\n]
+fr,dsgw,154,[<= erase_db n´a pas réussi à ouvrir le fichier lcache.conf "%s"\n(<= erase_db could not open lcache.conf file with name shown)\n]
+fr,dsgw,155,[<FONT SIZE="+1">\n<P>La base de données a été supprimée. Création d´une nouvelle base de données... \n(The database has been deleted. Creating new database...)\n</FONT>\n]
+fr,dsgw,156,[<FONT SIZE="+1">\n<P>Impossible de supprimer la base de données\n(The database could not be deleted)\n(</FONT>\n]
+fr,dsgw,157,[<= app_suffix n´a pas réussi à ouvrir le fichier ldif "%s"\n(<= app_suffix could not open ldif file with name shown)\n]
+fr,dsgw,158,[<= app_suffix n´a pas réussi à ouvrir le fichier tmp "%s"\n(<= app_suffix could not open tmp file with name shown)\n]
+fr,dsgw,159,[Impossible de renommer %s en %s (Unable to rename with names as shown)]
+fr,dsgw,160,[pointeur null renvoyé par dbconf_read_default_dbinfo().\n(null pointer returned by dbconf_read_default_dbinfo().)]
+fr,dsgw,161,[URL "ldapdb" erroné; le DN de base est manquant\n(Bad "ldapdb" URL - the base DN is missing)\n]
+fr,dsgw,162,[URL "ldapdb" erroné\n (Bad "ldapdb" URL)\n]
+fr,dsgw,163,[URL fourni pour la directive "baseurl" erroné; le DN de base est manquant\n(Bad URL provided for "baseurl" directive - the base DN is missing)\n]
+fr,dsgw,164,[analyse de la directive baseurl\n(parsing baseurl directive)]
+fr,dsgw,165,[URL fourni pour la directive "baseurl" erroné; pas un URL "ldap:// ou ldapdb://"\n(Bad URL provided for "baseurl" directive - not an "ldap:// or ldapdb://" URL)\n]
+fr,dsgw,166,[Les URL "ldaps://" ne sont pas encore supportés\n("ldaps://" URLs are not yet supported)\n]
+fr,dsgw,167,[Aucune valeur donnée pour binddn\n(No value given for binddn)]
+fr,dsgw,168,[Aucune valeur donnée pour bindpw\n(No value given for bindpw)]
+fr,dsgw,169,[Aucun service de répertoires par défaut n´est défini dans le fichier dbswitch.conf\n(There is no default directory service defined in the dbswitch.conf file)]
+fr,dsgw,170,[Impossible d'ouvrir le fichier de configuration "%s" en écriture\n(Cannot open config file with name shown for writing)\n]
+fr,dsgw,171,[Impossible de renommer %s en %s (Unable to rename with names as shown)]
+fr,dsgw,172,[fichier de configuration (config file) %s:]
+fr,dsgw,173,[fichier de configuration %s: ligne %d: \n(config file and line as shown)]
+fr,dsgw,174,[max %d]
+fr,dsgw,175,[ OK ]
+fr,dsgw,176,[Fermer la fenêtre (Close Window)]
+fr,dsgw,177,[Précédent]
+fr,dsgw,178,[{crypt}VERROUILLE (LOCKED) [%s GMT]]
+fr,dsgw,179,[Retourner à l´écran principal (Return to Main)]
+fr,dsgw,181,[ Help ]
+fr,dsgw,182,[Aide (Help)]
+fr,dsgw,184,[L´aide n´est pas encore disponible. (Help is not yet available.)]
+fr,dsgw,186,[Fermer la fenêtre (Close Window)]
+fr,dsgw,187,[Fermer la fenêtre (Close Window)]
+fr,dsgw,188,[modèle manquant? (missing ?template)]
+fr,dsgw,189,[Authentifier... (Authenticate...)]
+fr,dsgw,190,[Mettre les références d´authentification au rebut (déconnexion)?\n(Discard authentication credentials (log out)?)]
+fr,dsgw,191,[Veuillez taper une chaîne de recherche]
+fr,dsgw,192,[La première étape de l´authentification de l´accès à ce répertoire consiste en votre\npropre identification.<br>Tapez votre nom:\n(The first step in authenticating to the directory is identifying\nyourself.<br>Please type your name:)]
+fr,dsgw,193,[Continuer (Continue)]
+fr,dsgw,194,[Continuer (Continue)]
+fr,dsgw,195,[Annuler (Cancel)]
+fr,dsgw,196,[Authentifier comme gestionnaire de répertoires"> &nbsp;(uniquement disponible pour les administrateurs de répertoires)\n(Authenticate as directory manager"> &nbsp;(only available to Directory Administrators))\n]
+fr,dsgw,197,[Authentifier... (Authenticate...)]
+fr,dsgw,198,[Mettre les références d´authentification au rebut? (Discard authentication credentials?)]
+fr,dsgw,200,[Continuer (Continue)]
+fr,dsgw,201,[Continuer (Continue)]
+fr,dsgw,202,[Annuler (Cancel)]
+fr,dsgw,203,[Authentifier l´accès au répertoire (connexion)\n(Authenticate (log in) to the directory)]
+fr,dsgw,204,[Vous êtes sur le point de vous authentifier auprès de l'annuaire en tant que <B>%s</B>. Pour terminer le processus d'authentification, tapez votre mot de passe.\n]
+fr,dsgw,206,[Avant de pouvoir modifier ou ajouter des entrées, vous devez authentifier\nl´accès au répertoire (connexion). Cette fenêtre vous\nguidera tout au long du processus\nd´authentification.\n(Before you can edit or add entries, you must authenticate\n(log in) to the directory. This window will guide\nyou through the steps of the authentication\nprocess.)\n]
+fr,dsgw,207,[Cet écran vous permet d´authentifier l´accès au répertoire, \nou de vous y connecter. Vous devrez vous authentifier\navant de pouvoir modifier les entrées du répertoire. Si vous\ntentez de modifier une entrée sans authentification,\nil vous sera demandé de vous connecter.\n(From this screen you may authenticate, or log in, \nto the directory. You will need to authenticate\nbefore you can modify directory entries. If you\nattempt to modify an entry without authenticating,\nyou will be asked to log in.)\n]
+fr,dsgw,208,[Statut de l´authentification (Authentication Status)]
+fr,dsgw,209,[<form>\nVotre accès au répertoire est actuellement authentifié sous\n(You are currently authenticated to the directory as) ]
+fr,dsgw,210,[.\nSi vous voulez mettre vos références d´authentification au rebut et vous déconnecter du répertoire, cliquez sur le bouton ci-dessous.\n(.\nIf you wish to discard your authentication credentials and log out of the directory, click on the button below.)]
+fr,dsgw,211,[Mettre les références d´authentification au rebut (déconnexion)\n(Discard Authentication Credentials (log out))]
+fr,dsgw,212,[Vos références d´authentification pour \n(Your authentication credentials for )]
+fr,dsgw,213,[ont expiré (have expired).\n<HR>)\n]
+fr,dsgw,214,[Votre accès au répertoire n´est actuellement pas authentifié.\n(Currently, you are not authenticated to the directory.)<HR>\n]
+fr,dsgw,215,["%s=" manquant (missing definition shown)]
+fr,dsgw,216,["%s=%s" inconnu (unknown assignment as shown)]
+fr,dsgw,217,[option inconnue %s (unknown option as shown)]
+fr,dsgw,218,[syntaxe inconnue=%s\n(syntax shown unknown)\n]
+fr,dsgw,219,[** Type HTML "%s" non supporté **\n(** HTML type shown not supported **<BR>)\n]
+fr,dsgw,224,[Modifier (Edit)]
+fr,dsgw,225,[Save Changes]
+fr,dsgw,226,[modify]
+fr,dsgw,227,[add]
+fr,dsgw,228,[Supprimer (Delete)]
+fr,dsgw,229,[Supprimer cette entrée? (Delete this entry?)]
+fr,dsgw,230,[Renommer (Rename)]
+fr,dsgw,231,[Entrez un nouveau nom pour cette entrée: (Enter a new name for this entry:)]
+fr,dsgw,232,[Modifier sous (Edit As)]
+fr,dsgw,233,[%s= manquant (missing definition shown)]
+fr,dsgw,234,[Fermer la fenêtre (Close Window)]
+fr,dsgw,235,[Modifier... (Edit...)]
+fr,dsgw,236,["%s=" manquant\n (missing definition shown")\n]
+fr,dsgw,237,[ensemble inconnu "%s"\n (set shown is unknown)\n]
+fr,dsgw,238,[syntaxe inconnue "%s"\n (syntax shown is unknown)\n]
+fr,dsgw,239,[Ré-authentifier (Re-Authenticate)]
+fr,dsgw,240,[Fermer la fenêtre (Close Window)]
+fr,dsgw,241,[Voulez-vous vraiment (Do you really want to) ]
+fr,dsgw,242,[?]
+fr,dsgw,243,[ OK ]
+fr,dsgw,244,[ OK ]
+fr,dsgw,245,[Remettre à zéro (Reset)]
+fr,dsgw,246,[Terminé (Done)]
+fr,dsgw,247,[Annuler (Cancel)]
+fr,dsgw,248,[a trouvé un autre IF (les IF emboîtés ne sont pas supportés)\n(found another IF (nested IFs are not supported))]
+fr,dsgw,249,[a trouvé ELSE mais n´a pas vu de IF\n(found ELSE but didn't see an IF)]
+fr,dsgw,250,[a trouvé ELSE après ELSE (ENDIF attendu)\n(found ELSE after ELSE (expecting ENDIF))]
+fr,dsgw,251,[a trouvé ELIF mais n´a pas vu de IF\n(found ELIF but didn't see an IF)]
+fr,dsgw,252,[a trouvé ELIF après ELSE (ENDIF attendu)\n(found ELIF after ELSE (expecting ENDIF))]
+fr,dsgw,253,[a trouvé ENDIF mais n´a pas vu de IF\n(found ENDIF but didn't see an IF)]
+fr,dsgw,254,[<BR><B>erreur de modèle:</B> %s\n(<B>template error as shown</B>)<BR>\n]
+fr,dsgw,255,[ldap_init/lcache_init tenté avant la lecture du fichier de configuration\n(ldap_init/lcache_init attempted before config file read)]
+fr,dsgw,256,[ne tourne pas sous Administration Server\n(not running under the administration server)]
+fr,dsgw,257,[Impossible d´initialiser les permissions\n(Could not initialize permissions)]
+fr,dsgw,258,[Impossible de faire correspondre un nom d´utilisateur avec un DN (erreur d´Administration Server)\n(Could not map username to a DN (error from admin server))]
+fr,dsgw,259,[Impossible d´obtenir le nom d´utilisateur courant\n(Could not get current username)]
+fr,dsgw,260,[Impossible d´obtenir le mot de passe utilisateur courant\n(Could not get current user password)]
+fr,dsgw,261,[Erreur (Error): %s]
+fr,dsgw,262,[Remarque: aucun modèle d´affichage n´est disponible pour ce type d´entrée; une méthode par défaut\nest donc utilisée dans l´affichage ci-dessous.\n(Note: there is no display template for this type of entry available, so it is\ndisplayed below using a default method.)]
+fr,dsgw,263,[Identification de l´utilisateur ou identificateur NULL LDAP non valide\n(Invalid user id or NULL LDAP handle)]
+fr,dsgw,264,[aucune correspondance pour l´identification de l´utilisateur\n(no match for user id)]
+fr,dsgw,265,[plusieurs correspondances pour l´identification de l´utilisateur\n(more than one match for user id)]
+fr,dsgw,266,[the entire directory]
+fr,dsgw,267,[Deux arguments sont requis pour la directive "includeset"\n(Two arguments are required for the "includeset" directive)\n]
+fr,dsgw,268,[La valeur d'attribut demandée est introuvable dans l'entrée\n(An error occurred while trying to access the database)]
+fr,dsgw,269,[Argument introuvable pour la directive "NLS"]
+fr,dsgw,270,[Une valeur doit être spécifiée pour l'id d'utilisateur NT\n]
+fr,dsgw,271,[La combinaison de l'id d'utilisateur NT et de l'id de domaine NT n'est pas unique dans le répertoire.]
+fr,dsgw,272,[Des valeurs doivent être spécifiées pour l'id d'utilisateur NT et l'id de domaine NT\n]
+fr,dsgw,273,[La valeur d'id d'utilisateur NT ne doit pas dépasser 20 caractères.\n]
+fr,dsgw,274,[Veuillez créer un nom pour la nouvelle entrée.]
+fr,dsgw,275,[Veuillez sélectionner une adresse pour la nouvelle entrée.]
+fr,dsgw,276,[Nouvelle entrée]
+fr,dsgw,277,[Afin de pouvoir utiliser cette fonction, un dirmgr doit être défini dans dsgw.conf]
+fr,dsgw,278,[Trois ou quatre arguments sont requis pour la directive "vcard-property"\n]
+fr,dsgw,279,[La syntaxe de la propriété Vcard doit être "cis" ou "mls"\n]
+fr,dsgw,280,[Aucune entrée n'a été trouvée.\n%2$s]
+fr,dsgw,281,[Aucune entrée n'a été trouvée dans les %2$s %3$s '%4$s'.\n]
+fr,dsgw,282,[Aucune entrée recherchée n'a été trouvée\n%2$s]
+fr,dsgw,283,[Aucune entrée recherchée n'a été trouvée dans les %2$s %3$s %4$s'.\n]
+fr,dsgw,284,[1 entrée a été trouvée.\n%2$s]
+fr,dsgw,285,[1 entrée a été trouvée dans les %2$s %3$s '%4$s'.\n]
+fr,dsgw,286,[1 entrée recherchée a été trouvée.\n%2$s]
+fr,dsgw,287,[1 entrée recherchée a été trouvée dans les %2$s %3$s '%4$s'.\n]
+fr,dsgw,288,[%1$li entrées ont été trouvées.\n%2$s]
+fr,dsgw,289,[%1$li entrées ont été trouvées dans les %2$s %3$s '%4$s'.\n]
+fr,dsgw,290,[%1$li entrées recherchées ont été trouvées.\n%2$s]
+fr,dsgw,291,[%1$li entrées recherchées ont été trouvées dans les %2$s %3$s '%4$s'.\n ]
+fr,dsgw,292,[le filtre LDAP est]
+fr,dsgw,293,[Le serveur n´a pas pu trouver l´entrée que vous avez utilisée lors de l´authentification. Quelqu´un a peut-être renommé ou supprimé l´entrée. Procédez à une nouvelle authentification.]
+fr,dsgw,294,[La nouvelle syntaxe du mot de passe n´est pas valide.\n]
+fr,dsgw,295,[Le nouveau mot de passe figure dans l´historique des mots de passe.\n]
+fr,dsgw,296,[Vous avez atteint la limite de nouvelle tentative de mot de passe. Contactez votre administrateur système.\n]
+fr,dsgw,297,[Vous avez atteint la limite de nouvelle tentative de mot de passe. Essayez à nouveau.\n]
+fr,dsgw,298,[Le mot de passe a expiré. Contactez votre administrateur système pour redéfinir le mot de passe.\n]
+fr,frame,-1,[$DBT: frame in DB file v1 $]
+fr,frame,1,[<TITLE>Introuvable (Not Found)</TITLE><H1>Introuvable (Not Found)</H1> L'objet demandé n'existe pas sur ce serveur. Le lien que vous avez consulté est peut-être désuet, inexact, ou bien le serveur a reçu l'ordre de ne pas vous laisser y accéder.\n(The requested object does not exist on this server. The link you followed is either outdated, inaccurate, or the server has been instructed not to let you have it. )]
+fr,frame,2,[Veuillez informer l'administrateur de site de la <A HREF="%s">page de référence</A>.\n(Please inform the site administrator of the referring page.)]
+fr,frame,3,[Votre navigateur a envoyé une demande que ce Proxy n'arrive pas à comprendre.\n(Your browser sent a request that this proxy could not understand.)]
+fr,frame,4,[Une autorisation adéquate est requise pour l'administration de ce Proxy.\nVotre navigateur n'effectue peut-être pas l'autorisation, ou bien votre autorisation\na échoué.\n(Proper authorization is required for the administration of this proxy.\nEither your browser does not perform authorization, or your authorization\nhas failed.)]
+fr,frame,5,[L'authentification du nom d'utilisateur est requise pour utiliser ce Proxy.\nVotre navigateur n'effectue peut-être par l'autorisation de Proxy, ou bien votre\nautorisation a échoué.\n(Username authentication is required for using this proxy.\nEither your browser does not perform proxy authorization, or your\nauthorization has failed.)]
+fr,frame,6,[La configuration du contrôle d'accès de ce Proxy refuse l'accès à\nl'objet demandé par le biais de ce Proxy.\n(The proxy's access control configuration denies access to\nthe requested object through this proxy.)]
+fr,frame,7,[Le Proxy a rencontré une erreur interne qui l'empêche \nd'honorer votre demande. La cause la plus probable est une mauvaise configuration.\nVeuillez demander à l'administrateur de consulter le journal d'erreurs du Proxy.\n(The proxy has encountered an internal error which prevents it from\nfulfilling your request. The most likely cause is a misconfiguration.\nPlease ask the administrator to look for messages in the proxy's error log.)]
+fr,frame,8,[Ce serveur de Proxy ne met pas en oeuvre la méthode demandée.\n(This proxy server does not implement the requested method.)]
+fr,frame,9,[Une erreur est survenue sur le serveur de Proxy.\n(An error has occurred on the proxy server.)]
+fr,frame,10,[Votre navigateur a envoyé une requête que ce serveur n'arrive pas à comprendre.\n(Your browser sent a query this server could not understand.)]
+fr,frame,11,[Une autorisation adéquate est requise pour ce domaine. Votre navigateur n'effectue peut-être pas l'autorisation, ou bien votre autorisation a échoué.\n(Proper authorization is required for this area. Either your browser does not perform authorization, or your authorization has failed.)]
+fr,frame,12,[Votre client n'est pas autorisé à accéder à l'objet demandé.\n(Your client is not allowed to access the requested object.)]
+fr,frame,13,[Ce serveur a rencontré une erreur interne qui l'empêche d'honorer votre demande. La cause la plus probable est une mauvaise configuration. Veuillez demander à l'administrateur de consulter le journal d'erreurs du serveur.\n(This server has encountered an internal error which prevents it from fulfilling your request. The most likely cause is a misconfiguration. Please ask the administrator to look for messages in the server's error log.)]
+fr,frame,14,[Ce serveur ne met pas en oeuvre la méthode demandée.\n(This server does not implement the requested method.)]
+fr,frame,15,[Une erreur est survenue. (An error has occurred.)]
+fr,frame,16,[Votre navigateur a envoyé un message que ce serveur n'arrive pas à comprendre.\n(Your browser sent a message this server could not understand.)]
+fr,frame,17,[<HTML><HEAD><TITLE>%s</TITLE><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="fr"></HEAD><BODY><H1>%s</H1>\nCe document a été déplacé à une nouvelle <a href="%s">adresse</a>. Veuillez mettre à jour vos documents et listes d'accès en conséquence.\n(This document has moved to a new location. Please update your documents and hotlists accordingly.</BODY></HTML>)]
+fr,frame,18,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=iso-8859-1"><META HTTP-EQUIV="Content-Language" CONTENT="fr"><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>]
+fr,frame,19,[process-uri-objects]
+fr,frame,20,[cannot find template %s]
+fr,frame,21,[process-uri-objects]
+fr,frame,22,[no partial path after object processing]
+fr,frame,23,[find-service]
+fr,frame,24,[invalid shexp %s]
+fr,frame,25,[find-service]
+fr,frame,26,[invalid shexp %s]
+fr,frame,27,[handle-processed]
+fr,frame,28,[no way to service request for %s]
+fr,frame,29,[finish-socks-request]
+fr,frame,30,[close failed (%s), csd=%d]
+fr,frame,31,[This beta software has expired.\n]
+fr,frame,32,[mr_accept(%d)]
+fr,frame,33,[Error issuing read on accept socket]
+fr,frame,34,[acb_accept_connection(%d)]
+fr,frame,35,[Error getting accept socket (%d)]
+fr,frame,36,[Error in accept! (%d, %s)]
+fr,frame,37,[Error creating new accept request]
+fr,frame,38,[accepted connection: %d (NSPR %d)]
+fr,frame,39,[Error creating new session structure]
+fr,frame,40,[accel_read_request()]
+fr,frame,41,[Error allocating request read buffer]
+fr,frame,42,[Error issuing async read request]
+fr,frame,43,[acb_read_request(%d, bytes %d)]
+fr,frame,44,[acb_read_req(1 session = %d)]
+fr,frame,45,[Error reading request (%d, %s)]
+fr,frame,46,[Client aborted connection]
+fr,frame,47,[Error reading request]
+fr,frame,48,[Error creating new request]
+fr,frame,49,[error occurred, closing %d, io was for %d]
+fr,frame,50,[accel_async_scan_headers()]
+fr,frame,51,[out of memory: accel_async_scan_headers]
+fr,frame,52,[out of memory: accel_async_scan_headers]
+fr,frame,53,[Error during async read (%d, %s)]
+fr,frame,54,[scan-headers reports: line too long]
+fr,frame,55,[scan-headers reports: too many headers]
+fr,frame,56,[Error reading headers]
+fr,frame,57,[scan-headers reports: header missing terminator (an empty line)]
+fr,frame,58,[scan-headers reports: header was empty]
+fr,frame,59,[nom sans valeur: obtention de la ligne "%s"\n(name without value: got line as shown)]
+fr,frame,60,[accel_send_plain_file()]
+fr,frame,61,[accel_send_plain_file() - found request %d]
+fr,frame,62,[Parse headers lost the URI!]
+fr,frame,63,[accel_send_plain_file() - found uri %s]
+fr,frame,64,[accel_send_plain_file() - found in cache?]
+fr,frame,65,[malloc died!]
+fr,frame,66,[Error writing back file\n]
+fr,frame,67,[acb_send_plain_file(%d)]
+fr,frame,68,[Error writing in acb_send_plain_file (%d, %s)]
+fr,frame,69,[acb_close_connection(%d)]
+fr,frame,70,[Errored IO in acb_close_connection (%d, %s)]
+fr,frame,71,[Unable to close socket %d]
+fr,frame,72,[accel-cache-insert: Error allocating entry]
+fr,frame,73,[cache-init: server cache disabled]
+fr,frame,74,[accel_file_cache: Error initializing file cache]
+fr,frame,75,[accel_file_cache: Error creating cache]
+fr,frame,76,[accel_file_cache_init: CacheHashSize < %d, using %d]
+fr,frame,77,[accel_file_cache_init: CacheHashSize > %d, using %d]
+fr,frame,78,[accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d]
+fr,frame,79,[accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d]
+fr,frame,80,[accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d]
+fr,frame,81,[accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d]
+fr,frame,82,[accel_file_cache: Error initializing file cache]
+fr,frame,83,[file-cache: enabled = %s ]
+fr,frame,84,[on]
+fr,frame,85,[off]
+fr,frame,86,[file-cache: MaxNumberOfCachedFiles %d (0x%x)]
+fr,frame,87,[file-cache: CacheHashSize %d (0x%x)]
+fr,frame,88,[file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)]
+fr,frame,89,[accel-cache-insert: Error allocating entry]
+fr,frame,90,[file-cache-cleanup: munmap failed (%s)]
+fr,frame,91,[file-cache-cleanup: found mmapped file \non system without mmap]
+fr,frame,92,[file_cache_init: MaxTotalCachedFileSize < %d, using %d]
+fr,frame,93,[file_cache_init: MaxTotalCachedFileSize > %d, using %d]
+fr,frame,94,[file cache using mmap flags 0x%x]
+fr,frame,95,[file cache using mmap prots 0x%x]
+fr,frame,96,[file-cache-init: could not create lock]
+fr,frame,97,[file-cache: unable to create temporary directory %s.\n]
+fr,frame,98,[file-cache: unable to create temporary directory %s.\n]
+fr,frame,99,[file-cache: GetTempPath() Cannot find temp directory to store file!]
+fr,frame,100,[file-cache-init: set max cached file size to %d]
+fr,frame,101,[file-cache-init: could not create lock]
+fr,frame,102,[file_cache_destroy()]
+fr,frame,103,[file-cache: Unable to get temp file name. Error %s]
+fr,frame,104,[file-cache: Unable to get temp file name. Error %s]
+fr,frame,105,[file-cache-insert: Error allocating entry]
+fr,frame,106,[file-cache-create: Error opening file %s (%s)]
+fr,frame,107,[file-cache-create: Error stat()ing file %s (%s)]
+fr,frame,108,[file-cache-create: Error mmap()ing file %s (%s)]
+fr,frame,109,[file-cache-create: malloc failure]
+fr,frame,110,[file-cache-create: error case failed to munmap(%d, %d) (%s)]
+fr,frame,111,[file-cache-valid: cannot stat %s]
+fr,frame,112,[dir change: invalidating %s (%d)]
+fr,frame,113,[file-cache: asynchronous file change notification failed.]
+fr,frame,114,[dir change: offset %d, action %d, len %d, name %s]
+fr,frame,115,[unable to check async file status]
+fr,frame,116,[ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s]
+fr,frame,117,[file-cache-add-watch failure- unable to open directory %s. Error %s]
+fr,frame,118,[ReadDirectoryChangesW failure- unable to start watching %s. Error %s]
+fr,frame,119,[func_exec]
+fr,frame,120,[no handler function given for directive]
+fr,frame,121,[func_exec]
+fr,frame,122,[cannot find function named %s]
+fr,frame,123,[handle-request]
+fr,frame,124,[method without URI]
+fr,frame,125,[http-parse-request]
+fr,frame,126,[while scanning HTTP headers, %s]
+fr,frame,127,[handle-request]
+fr,frame,128,[read from %s failed, error is %s]
+fr,frame,129,[handle-request]
+fr,frame,130,[request too long]
+fr,frame,131,[start-http-response]
+fr,frame,132,[write failed (%s)]
+fr,frame,133,[start-http-response]
+fr,frame,134,[write failed (%s)]
+fr,frame,135,[http-status]
+fr,frame,136,[%d is not a valid HTTP status code]
+fr,frame,137,[finish-request]
+fr,frame,138,[close failed (%s)]
+fr,frame,139,[Unable to close socket for writing]
+fr,frame,140,[os has %d objects]
+fr,frame,141,[obj %d has no hash table at %d]
+fr,frame,142,[obj %d has no param]
+fr,frame,143,[obj %d name %s value %s]
+fr,frame,144,[.....directives %d.......]
+fr,frame,145,[.....directive %d]
+fr,frame,146,[.......instance %d]
+fr,frame,147,[...........param name %s value %s]
+fr,frame,148,[ClearConfigurationParameters:RegCreateKey %s]
+fr,frame,149,[ClearConfigurationParameters:RegEnumKey %s failed]
+fr,frame,150,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+fr,frame,151,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+fr,frame,152,[Unable to allocate Subject property list.\n]
+fr,frame,153,[Unable to set session ptr in Subject property list - error=%d\n]
+fr,frame,154,[Unable to set request ptr in Subject property list - error=%d\n]
+fr,frame,155,[file-cache-valid: cannot stat %s]
+fr,frame,156,[file-cache-create: Error stat()ing file %s (%s)]
+fr,httpdaemon,-1,[$DBT: httpdaemon in DB file v1 $]
+fr,httpdaemon,1,[Error in ConvertThreadToFiber]
+fr,httpdaemon,2,[Error in ConvertThreadToFiber]
+fr,httpdaemon,3,[Error in md_start_system]
+fr,httpdaemon,4,[Error in CreateFiber - idlefiber]
+fr,httpdaemon,5,[Error in GetQueuedCompletionStatus]
+fr,httpdaemon,6,[Error creating completion port]
+fr,httpdaemon,7,[Could not SetHandleNonInheritable (%s)]
+fr,httpdaemon,8,[Error accept/read new conn]
+fr,httpdaemon,9,[Error in Respond()]
+fr,httpdaemon,10,[Error in RespondCompleted()]
+fr,httpdaemon,11,[daemon: unable to fork new process (%s)\n]
+fr,httpdaemon,12,[daemon: setsid failed (%s)\n]
+fr,httpdaemon,13,[daemon: can't log pid to %s (%s)\n]
+fr,httpdaemon,14,[warning: could not set group id to %d (%s)\n]
+fr,httpdaemon,15,[warning: could not set user id to %d (%s)\n]
+fr,httpdaemon,16,[warning: daemon is running as super-user\n]
+fr,httpdaemon,17,[could not determine current user name\n]
+fr,httpdaemon,18,[error: chroot to %s failed (%s)\n]
+fr,httpdaemon,19,[WARNING! netscape executable and library have different versions.\n]
+fr,httpdaemon,20,[startup: listening to %s://%s, port %d as %s\n]
+fr,httpdaemon,21,[startup: listening to %s://%s, port %d as %s\n]
+fr,httpdaemon,22,[seminit failed (%s)\n]
+fr,httpdaemon,23,[Using single threaded accepts.]
+fr,httpdaemon,24,[Using multi threaded accepts.]
+fr,httpdaemon,25,[Using partial single threaded accepts.]
+fr,httpdaemon,26,[This machine has %d processors.]
+fr,httpdaemon,27,[Error calling thr_seconcurrency(%d)- (%s)]
+fr,httpdaemon,28,[Set conncurrency to %d.]
+fr,httpdaemon,29,[can't fork new process (%s)]
+fr,httpdaemon,30,[This beta software has expired.\n]
+fr,httpdaemon,31,[can't create IPC pipe (%s)]
+fr,httpdaemon,32,[write to wakeup pipe failed (%s)]
+fr,httpdaemon,33,[select thread miss]
+fr,httpdaemon,34,[startup failure: could not bind to port %d (%s)\n]
+fr,httpdaemon,35,[startup failure: could not bind to port %d, IP address %s (%s)\n]
+fr,libaccess,-1,[$DBT: libaccess in DB file v1 $]
+fr,libaccess,1,[basic-ncsa]
+fr,libaccess,2,[cannot open database %s]
+fr,libaccess,3,[basic-ncsa]
+fr,libaccess,4,[user %s password did not match database %s]
+fr,libaccess,5,[basic-ncsa]
+fr,libaccess,6,[cannot open connection to LDAP server on %s:%d]
+fr,libaccess,7,[basic-ncsa]
+fr,libaccess,8,[user %s password did not match LDAP on %s:%d]
+fr,libaccess,9,[acl-state]
+fr,libaccess,10,[missing realm]
+fr,libaccess,11,[Unable to allocate ACL List Hash\n]
+fr,libaccess,12,[ACLEvalBuildContext unable to PERM_MALLOC cache structure\n]
+fr,libaccess,13,[ACLEvalBuildContext unable to create hash table\n]
+fr,libaccess,14,[ACLEvalBuildContext unable to allocate ACE Entry\n]
+fr,libaccess,15,[ACLEvalBuildContext unable to allocate ACE entry\n]
+fr,libaccess,16,[ACLEvalBuildContext unable to allocate Boundary Entry\n]
+fr,libaccess,17,[ACLEvalBuildContext failed.\n]
+fr,libaccess,18,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n]
+fr,libaccess,19,[LASDnsBuild unable to allocate hash table header\n]
+fr,libaccess,20,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,21,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,22,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,23,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,24,[LASDnsBuild unable to add key %s\n]
+fr,libaccess,25,[LAS DNS build received request for attribute %s\n]
+fr,libaccess,26,[LASDnsEval - illegal comparator %s\n]
+fr,libaccess,27,[LASDnsEval unable to allocate Context struct\n\n]
+fr,libaccess,28,[LASDnsEval unable to get session address %d\n]
+fr,libaccess,29,[LASDnsEval unable to get DNS - error=%s\n]
+fr,libaccess,30,[LAS Group Eval received request for attribute %s\n]
+fr,libaccess,31,[LASGroupEval - illegal comparator %s\n]
+fr,libaccess,32,[LASGroupEval - ran out of memory\n]
+fr,libaccess,33,[LASGroupEval unable to get session address %d\n]
+fr,libaccess,34,[LASGroupEval unable to get session address %d\n]
+fr,libaccess,35,[LASGroupEval - couldn't locate getter for auth-user\n]
+fr,libaccess,36,[LASGroupEval - Attribute getter for auth-user failed\n]
+fr,libaccess,37,[LASGroupEval - Attribute getter didn't set auth-user\n]
+fr,libaccess,38,[Check group membership of user "%s" for group "%s"\n]
+fr,libaccess,39,[LDAPU_SUCCESS for group "%s"\n]
+fr,libaccess,40,[LDAPU_FAILED for group "%s"\n]
+fr,libaccess,41,[LAS_EVAL_FALSE\n]
+fr,libaccess,42,[LAS_EVAL_TRUE\n]
+fr,libaccess,43,[LASIpTreeAlloc - no memory\n]
+fr,libaccess,44,[IP LAS unable to allocate tree node\n]
+fr,libaccess,45,[IP LAS unable to allocate tree node\n]
+fr,libaccess,46,[LAS IP build received request for attribute %s\n]
+fr,libaccess,47,[LASIpEval - illegal comparator %s\n]
+fr,libaccess,48,[LASIpEval unable to get session address - error=%s\n]
+fr,libaccess,49,[LASIpEval unable to allocate Context struct\n\n]
+fr,libaccess,50,[LASIpEval - reach 32 bits without conclusion value=%s]
+fr,libaccess,51,[LAS Program Eval received request for attribute %s\n]
+fr,libaccess,52,[LASProgramEval - illegal comparator %s\n]
+fr,libaccess,53,[LASProgram unable to get session address %d\n]
+fr,libaccess,54,[bin]
+fr,libaccess,55,[LASProgramEval: request not of type admin or bin, passing.\n]
+fr,libaccess,56,[LASProgramEval: check if program %s matches pattern %s.\n]
+fr,libaccess,57,[LASProgramEval: Invalid wildcard expression %s.\n]
+fr,libaccess,58,[LAS_EVAL_FALSE\n]
+fr,libaccess,59,[LAS_EVAL_TRUE\n]
+fr,libaccess,60,[Unexpected attribute in dayOfWeek - %s\n]
+fr,libaccess,61,[Illegal comparator for dayOfWeek - %s\n]
+fr,libaccess,62,[Unexpected attribute in timeOfDay - %s\n]
+fr,libaccess,63,[LAS User Eval received request for attribute %s\n]
+fr,libaccess,64,[LASUserEval - illegal comparator %s\n]
+fr,libaccess,65,[LASUserEval - ran out of memory\n]
+fr,libaccess,66,[LASUserEval unable to get session address %d\n]
+fr,libaccess,67,[LASUserEval unable to get session address %d\n]
+fr,libaccess,68,[LASGroupEval - couldn't locate getter for auth-user\n]
+fr,libaccess,69,[LASGroupEval - Attribute getter for auth-user failed\n]
+fr,libaccess,70,[LASGroupEval - Attribute getter didn't set auth-user\n]
+fr,libaccess,71,[Check if uid == user (i.e. check "%s" == "%s)"\n]
+fr,libaccess,72,[SUCCESS for user "%s"\n]
+fr,libaccess,73,[FAILED for user "%s"\n]
+fr,libaccess,74,[LAS_EVAL_FALSE\n]
+fr,libaccess,75,[LAS_EVAL_TRUE\n]
+fr,libaccess,76,[]
+fr,libaccess,77,[LASProgram unable to get request address - error=%s]
+fr,libaccess,78,[LASProgram rejecting request for program %s from pattern %s]
+fr,libaccess,79,[ACL_CacheFlush: unable to parse file "%s"\n]
+fr,libaccess,80,[ACL_CacheFlush: unable to concatenate ACL list "%s"\n]
+fr,libaccess,81,[ACL_CacheFlush: unable to open and process the magnus file "%s"\n]
+fr,libaccess,82,[Illegal comparator for timeOfDay - %s\n]
+fr,libaccess,83,[ACL_EvalBuildContext unable to create hash table\n]
+fr,libaccess,84,[ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n]
+fr,libaccess,85,[ACL_EvalBuildContext unable to allocate ACE entry\n]
+fr,libaccess,86,[ACL_EvalBuildContext unable to allocate auth pointer array\n]
+fr,libaccess,87,[ACL_EvalBuildContext unable to allocate auth plist\n]
+fr,libaccess,88,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n]
+fr,libaccess,89,[ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n]
+fr,libaccess,90,[ACL_ModuleRegister: module name is missing\n]
+fr,libaccess,91,[ACL_ModuleRegister: call to module init function returned a failed status\n]
+fr,libaccess,92,[ACL_GetAttribute: couldn't determine method for %s\n]
+fr,libaccess,93,[ACL_GetAttribute: couldn't locate getter for %s]
+fr,libaccess,94,[ACL_GetAttribute: attr getter failed to get %s]
+fr,libaccess,95,[ACL_GetAttribute: attr getter failed to get %s]
+fr,libaccess,96,[ACL_GetAttribute: All attribute getters declined for attr %s]
+fr,libaccess,97,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+fr,libaccess,98,[ACL_DatabaseRegister: database name is missing]
+fr,libaccess,99,[Error reading the DB Map File: %s. Reason: %s]
+fr,libaccess,100,[URL is missing for database %s]
+fr,libaccess,101,[Invalid property value pair for database %s]
+fr,libaccess,102,["default" database must be an LDAP database]
+fr,libaccess,103,[Multiple "default" databases are being registered]
+fr,libaccess,104,["default" LDAP database must be registered]
+fr,libaccess,105,[LASGroupEval unable to get database name - error= %s]
+fr,libaccess,106,[received invalid program expression %s]
+fr,libaccess,107,[parse_ldap_url: database url is missing]
+fr,libaccess,108,[parse_ldap_url: database name is missing]
+fr,libaccess,109,[parse_ldap_url: error in parsing ldap url. Reason: %s]
+fr,libaccess,110,[ldap password check: unable to get database name - error=%s]
+fr,libaccess,111,[ldap password check: unable to get parsed database %s]
+fr,libaccess,112,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+fr,libaccess,113,[ldap password check: LDAP error: "%s"]
+fr,libaccess,114,[get_user_ismember_ldap unable to get database name - error=%s]
+fr,libaccess,115,[get_user_ismember_ldap unable to get parsed database %s]
+fr,libaccess,116,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+fr,libaccess,117,[get_user_ismember_ldap: group %s does not exist]
+fr,libaccess,118,[get_user_ismember_ldap: LDAP error: "%s"]
+fr,libaccess,119,[ACL_LDAPDatabaseHandle: %s is not a registered database]
+fr,libaccess,120,[ACL_LDAPDatabaseHandle: %s is not an LDAP database]
+fr,libaccess,121,[ACL_LDAPDatabaseHandle: out of memory]
+fr,libaccess,122,[ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s]
+fr,libaccess,123,[ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s]
+fr,libaccess,124,[insufficient dynamic memory]
+fr,libaccess,125,[error opening file, %s: %s]
+fr,libaccess,126,[duplicate definition of %s]
+fr,libaccess,127,[file %s, line %s: duplicate definition of %s]
+fr,libaccess,128,[file %s, line %s: syntax error]
+fr,libaccess,129,[file %s, line %s: %s is undefined]
+fr,libaccess,130,[in acl %s, %s %s is undefined]
+fr,libaccess,131,[database %s: error accessing %s]
+fr,libaccess,132,[%s]
+fr,libaccess,133,[file %s, line %s: invalid syntax]
+fr,libaccess,134,[file %s, line %s: syntax error at "%s"]
+fr,libaccess,135,[realm %s is not defined]
+fr,libaccess,136,[error code = %d]
+fr,libaccess,137,[internal ACL error]
+fr,libaccess,138,[invalid argument]
+fr,libaccess,139,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+fr,libaccess,140,[couldn't determine dbtype from: %s]
+fr,libaccess,141,[Failed to register database %s]
+fr,libaccess,142,[ACL call returned failed status]
+fr,libaccess,143,[file %s: ACL IO error - %s]
+fr,libaccess,144,[acl_user_exists: mémoire insuffisante]
+fr,libaccess,145,[acl_user_exists: l'utilisateur n'existe plus]
+fr,libaccess,146,[acl_user_exists: erreur de plist]
+fr,libadmin,-1,[$DBT: libadmin in DB file v1 $]
+fr,libadmin,1,[ Help ]
+fr,libadmin,2,[ OK ]
+fr,libadmin,3,[ Reset ]
+fr,libadmin,4,[ Done ]
+fr,libadmin,5,[ Cancel ]
+fr,libir,-1,[$DBT: libadmin in DB file v1 $]
+fr,libir,1,[An I/O error occurred before all form data could be read.]
diff --git a/l10n/dirserv/ja/ns-slapd.txt b/l10n/dirserv/ja/ns-slapd.txt
new file mode 100644
index 00000000..2ce736c2
--- /dev/null
+++ b/l10n/dirserv/ja/ns-slapd.txt
@@ -0,0 +1,1018 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+/**************************************************************************/
+/* The copyright notice(s) in this Source Code does not indicate actual */
+/* or intended publication of this Source Code. */
+/**************************************************************************/
+
+/* This text file was generated by program dblink */
+
+$Revision: 1.1 $
+$Log: ns-slapd.txt,v $
+Revision 1.1 2005/01/21 00:40:48 cvsadm
+Initial revision
+
+Revision 1.2.10.6 2003/09/22 19:36:43 ulfw
+Update copyright years from 2001 to 2001-2003
+
+Revision 1.2.10.5 2001/11/03 01:07:47 richm
+XXX use new copyright XXX
+
+Revision 1.2.10.4 2001/10/06 17:54:34 richm
+ns/netsite/l10n/dirserv/ja/ns-slapd.txt
+1.2.10.3
+20010918
+
+Remove copyright caracter from copyright
+
+
+====================================================
+
+Revision 1.2.10.3 2001/09/18 11:48:17 rmarco
+Remove copyright caracter from copyright
+
+Revision 1.2.10.2 2001/02/13 09:59:57 rmarco
+Copyrights
+
+Revision 1.2.10.1 1998/10/10 02:14:12 ggood
+Copy from Directory40RtmBranchpoint to DirectoryBranch
+
+Revision 1.2.2.2.6.2 1998/04/04 23:16:59 mcs
+merge changes made on directory31_rtm_branch into server4_directory_branch
+
+Revision 1.2.2.6.2.1 1998/02/24 05:39:08 noriko
+Added new updates from the translators
+
+Revision 1.1.2.7 1998/02/19 23:47:54 scronin
+Merged Noriko's edits with translated updates
+
+Revision 1.2.2.6 1998/02/17 22:01:21 noriko
+Fixed <Discard authentication credentials>
+
+Revision 1.2.2.5 1998/02/16 22:33:53 noriko
+Replaced words to display them correctly on NT Communicator 4.04 -- see also http://xiulu/ds30/l10n/translation-ja.htm
+
+Revision 1.2.2.4 1998/02/16 02:01:02 noriko
+removed the last dash from Japanese <user>
+
+Revision 1.2.2.3 1998/02/16 01:31:41 noriko
+Fixed search result message
+
+Revision 1.2.2.2 1997/12/20 03:32:16 werudge
+Copy from server3_i18npkg_branch to server3_directory_branch
+
+Revision 1.1.2.5 1997/12/19 02:19:37 werudge
+UTF8 Encoded from ja/ns-slapd.txt.eucjp : 1.1.2.5
+Based on en/ns-slapd.txt : 1.1.2.3
+
+Revision 1.1.2.5 1997/12/19 02:04:05 werudge
+Based on en/ns-slapd.txt : 1.1.2.3
+daily 971113.1 SOLARIS-export-optimize-normal-slapd
+$EndLog$
+
+$StartStringData$
+
+ja,base,-1,[$DBT: base in DB file v1 $]
+ja,base,1,[¥Ï¥Ã¥·¥å ¥Æ¡¼¥Ö¥ë¤òºîÀ®¤¹¤ë¤¿¤á¤Î¥á¥â¥ê¤¬ÉÔ­¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,base,2,[¥Ï¥Ã¥·¥å ¥Æ¡¼¥Ö¥ë¤òºîÀ®¤¹¤ë¤¿¤á¤Î¥á¥â¥ê¤¬ÉÔ­¤·¤Æ¤¤¤Þ¤¹]
+ja,base,3,[cache_destroy: ¥­¥ã¥Ã¥·¥å ¥Æ¡¼¥Ö¥ë¤¬ÉÔÀµ¤Ç¤¹¡£]
+ja,base,4,[¥Ï¥Ã¥·¥å ¥¨¥ó¥È¥ê¤ò³ä¤êÅö¤Æ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,base,5,[cache_insert: ¥­¥ã¥Ã¥·¥å ¥¨¥ó¥È¥ê¤òºîÀ®¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,base,6,[HTTP/1.0 200 OK\nContent-type: text/html\n\n]
+ja,base,7,[<H2>Netscape ¥­¥ã¥Ã¥·¥å ¥¹¥Æ¡¼¥¿¥¹ ¥ì¥Ý¡¼¥È</H2>\n]
+ja,base,8,[¥·¥¹¥Æ¥à¾å¤Ë¥­¥ã¥Ã¥·¥å¤¬Â¸ºß¤·¤Þ¤»¤ó¡£<P>]
+ja,base,9,[<H2>%s ¥­¥ã¥Ã¥·¥å</H2>\n]
+ja,base,10,[¥­¥ã¥Ã¥·¥å ¥Ò¥Ã¥È ¥ì¥·¥ª¡§ %d/%d (%f)</P>\n</P>\n]
+ja,base,11,[¥­¥ã¥Ã¥·¥å ¥µ¥¤¥º¡§ %d/%d</P>\n</P>\n]
+ja,base,12,[¥Ï¥Ã¥·¥å ¥Æ¡¼¥Ö¥ë ¥µ¥¤¥º¡§ %d</P>\n</P>\n]
+ja,base,13,[mru : %d</P>\nlru : %d</P>\n]
+ja,base,14,[<UL><TABLE BORDER=4> <TH>Bucket</TH> <TH>¥¢¥É¥ì¥¹</TH> <TH>¥­¡¼</TH> <TH>¥¢¥¯¥»¥¹²ó¿ô</TH> <TH>ºï½ü</TH> <TH>¼¡¤Ø</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>¥Ç¡¼¥¿</TH>\n]
+ja,base,15,[munmap failed (%s)]
+ja,base,16,[munmap failed (%s)]
+ja,base,17,[close failed (%s)]
+ja,base,18,[daemon: unable to fork new process (%s)\n]
+ja,base,19,[daemon: setsid failed (%s)\n]
+ja,base,20,[daemon: can't log pid to %s (%s)\n]
+ja,base,21,[warning: could not set group id to %d (%s)\n]
+ja,base,22,[warning: could not set user id to %d (%s)\n]
+ja,base,23,[warning: daemon is running as super-user\n]
+ja,base,24,[could not determine current user name\n]
+ja,base,25,[error: chroot to %s failed (%s)\n]
+ja,base,27,[, address %s]
+ja,base,28,[warning: statistics disabled (%s)\n]
+ja,base,29,[security handshake timed out for pid %d]
+ja,base,30,[warning: statistics disabled (%s)\n]
+ja,base,31,[secure handshake failed (code %d)\n]
+ja,base,32,[accept failed (%s)]
+ja,base,33,[warning: statistics disabled (%s)\n]
+ja,base,34,[select thread miss]
+ja,base,35,[keepalive worker awoken with no work to do]
+ja,base,36,[could not create new thread: %d (%s)]
+ja,base,37,[wait for sema succeeded, but nothing to dequeue]
+ja,base,38,[queue-sema creation failure]
+ja,base,39,[error getting processor info for processor %d]
+ja,base,40,[Error binding to processor %d]
+ja,base,41,[bound process %d to processor %d]
+ja,base,42,[Netscape server is not explicitly binding to any processors.]
+ja,base,43,[cache monitor exited]
+ja,base,44,[cache batch update daemon exited]
+ja,base,45,[Using single threaded accepts.]
+ja,base,46,[Using multi threaded accepts.]
+ja,base,47,[Using partial single threaded accepts.]
+ja,base,48,[This machine has %d processors.]
+ja,base,49,[Error calling thr_seconcurrency(%d)- (%s)]
+ja,base,50,[Set conncurrency to %d.]
+ja,base,51,[WARNING! netscape executable and library have different versions.\n]
+ja,base,54,[seminit failed (%s)\n]
+ja,base,55,[This beta software has expired.\n]
+ja,base,56,[Cache monitor respawned]
+ja,base,57,[Cache batch update daemon respawned]
+ja,base,58,[can't find empty statistics slot]
+ja,base,59,[can't fork new process (%s)]
+ja,base,60,[assert failed! %s\n]
+ja,base,61,[mr_table_init()]
+ja,base,62,[malloc failed]
+ja,base,63,[malloc failed!]
+ja,base,64,[mr_add_io(%d, type %d, file %d)]
+ja,base,65,[mr_add_io - stage 1]
+ja,base,66,[mr_add_io - stage 2]
+ja,base,67,[mr_add_io found invalid IO type %d]
+ja,base,68,[mr_add_io - adding timeout]
+ja,base,69,[Out of memory!\n]
+ja,base,70,[done with mr_add_io]
+ja,base,71,[mr_del_io(%d, type %d, file %d)]
+ja,base,72,[mr_del_io found invalid IO type %d]
+ja,base,73,[mr_lookup_io(%d)]
+ja,base,74,[mr_async_io(%d, %d bytes, file %d)]
+ja,base,75,[malloc failure adding async IO]
+ja,base,76,[Error adding async io!]
+ja,base,77,[Cannot seek for read!]
+ja,base,78,[read failure! (%d, %s)]
+ja,base,79,[do_read read %d bytes for file %d]
+ja,base,80,[Cannot seek for write!]
+ja,base,81,[writev failure! (%d, %s)]
+ja,base,82,[write failure! (%d, %s)]
+ja,base,83,[do_write wrote %d bytes for file %d]
+ja,base,84,[do_timeout(mrp %d)]
+ja,base,85,[do_timeout: found IO (timer=%d, time=%d)]
+ja,base,86,[error deleting io]
+ja,base,87,[timeout callback failure for %d\n]
+ja,base,88,[mr_get_event(%d) - outstanding io %d]
+ja,base,89,[mr_get_event: Waiting for reads on FD:]
+ja,base,90,[mr_get_event: Waiting for writes on FD:]
+ja,base,91,[ %d]
+ja,base,92,[ %d]
+ja,base,93,[mr_get_event set no timeout]
+ja,base,94,[mr_get_event set timeout to: %d.%d sec]
+ja,base,95,[error in select (%d, %s)]
+ja,base,96,[mr_get_event() - select found %d]
+ja,base,97,[error looking up IO fd %d]
+ja,base,98,[read failed for fd %d]
+ja,base,99,[error deleting io]
+ja,base,100,[callback failure for %d\n]
+ja,base,101,[error looking up IO fd %d]
+ja,base,102,[writing: header len %d, writelen %d, total %d]
+ja,base,103,[write failed for fd %d]
+ja,base,104,[error deleting io]
+ja,base,105,[callback failure for %d\n]
+ja,base,106,[Error creating dns cache]
+ja,base,107,[dns_cache_init: hash_size <= 0, using %d]
+ja,base,108,[dns_cache_init: cache-size <= %d, using %d]
+ja,base,109,[dns_cache_init: cache-size is %d is too large, using %d.]
+ja,base,110,[dns_cache_init: expire_time <= 0, using %d]
+ja,base,111,[dns_cache_init: expire is %d is too large, using %d seconds.]
+ja,base,112,[Error creating dns cache]
+ja,base,113,[dns-cache-insert: Error allocating entry]
+ja,base,114,[dns-cache-insert: malloc failure]
+ja,base,115,[successful server startup]
+ja,base,116,[%s B%s]
+ja,base,117,[Netscape executable and shared library have different versions]
+ja,base,118,[ executable version is %s]
+ja,base,119,[ shared library version is %s]
+ja,base,120,[error reporting shutting down]
+ja,base,121,[warning]
+ja,base,122,[config]
+ja,base,123,[security]
+ja,base,124,[failure]
+ja,base,125,[catastrophe]
+ja,base,126,[info]
+ja,base,127,[verbose]
+ja,base,128,[event_handler:Failed to wait on events %s]
+ja,base,129,[could not wait on resume event event (%s)]
+ja,base,130,[dlopen of %s failed (%s)]
+ja,base,131,[dlopen of %s failed (%s)]
+ja,base,132,[The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!]
+ja,base,133,[Terminating the server %s]
+ja,base,134,[kill_server:cannot open server event %s]
+ja,base,135,[kill_server:cannot set server event %s]
+ja,base,136,[error: could not get socket (%s)\n]
+ja,base,137,[error: could not set socket option (%s)\n]
+ja,base,138,[Terminating Service:error: could not bind to address %s port %d (%s)\n]
+ja,base,139,[Terminating Service:error: could not bind to port %d (%s)\n]
+ja,base,140,[SetHandleNonInheritable: could not duplicate socket (%s)]
+ja,base,141,[SetHandleNonInheritable: closing the original socket failed (%s)]
+ja,base,142,[Could not SetHandleInformation (%s)]
+ja,base,143,[Terminating Service:Failure: Could not open statistics file (%s)\n]
+ja,base,144,[Could not set Thread Local Storage Value for thread at slot %d]
+ja,base,145,[secure handshake failed (code %d)\n]
+ja,base,146,[accept failed %d (%s)]
+ja,base,147,[Failed to pulse Event %d %s]
+ja,base,148,[Failed to send MobGrowth Event to parent %s]
+ja,base,149,[Pulsing MobRespawn Event %d]
+ja,base,150,[respawn thread pool to %d (%d)]
+ja,base,151,[Could not open event to signal rotate application. Could not create the MoveLog event:%s]
+ja,base,152,[Failed to send MoveLog Event to rotate app %s]
+ja,base,153,[growing thread pool from %d to %d]
+ja,base,154,[Could not open the ServiceControlManager, Error %d]
+ja,base,155,[StartNetsiteService:Could not open the service %s: Error %d]
+ja,base,156,[StartNetsiteService:Could not start the service %s]
+ja,base,157,[Service Startup: Could not allocate security descriptor]
+ja,base,158,[Service Startup: Could not init security descriptor]
+ja,base,159,[Service Startup: Could not set the security Dacl]
+ja,base,160,[Terminating Service:WinSock init failed: %s]
+ja,base,161,[Httpd Server Startup failed: %s]
+ja,base,162,[can't find empty statistics slot]
+ja,base,163,[NT daemon: could not create new thread %d]
+ja,base,164,[Service Startup Failure. Terminating Service:Could not create event %d:%s]
+ja,base,165,[Service Startup Error. Could not create the MoveLog event:%s]
+ja,base,166,[Failed to wait on Event objects %s]
+ja,base,167,[Failed to wait on Event objects %s]
+ja,base,168,[pipebuf_buf2sd: pipebuf_grab IO_ERROR %d]
+ja,base,169,[pool-init: memory pools disabled]
+ja,base,170,[pool-init: free_size <= 0, using %d]
+ja,base,171,[pool-create-block: out of memory]
+ja,base,172,[pool-create: out of memory]
+ja,base,173,[pool-create: out of memory]
+ja,base,174,[pool-malloc: out of memory]
+ja,base,175,[FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.]
+ja,base,176,[regex error: %s (regex: '%s')]
+ja,base,177,[can't create IPC pipe (%s)]
+ja,base,178,[write to wakeup pipe failed (%s)]
+ja,base,179,[flushing %d connections; current %d; tot %d]
+ja,base,180,[accept failed (%s)]
+ja,base,181,[Error creating time cache]
+ja,base,182,[time-cache: cache disabled]
+ja,base,183,[time_cache_init: hash_size < %d, using default, %d]
+ja,base,184,[time_cache_init: hash_size > %d, using default, %d]
+ja,base,185,[time_cache_init: cache_size < %d, using default, %d]
+ja,base,186,[time_cache_init: cache_size > %d, using default, %d]
+ja,base,187,[Error allocating memory for time_cache]
+ja,base,188,[Error allocating memory for time_cache entry]
+ja,base,189,[Error allocating memory for time_cache entry]
+ja,base,190,[Error inserting new time_cache entry]
+ja,base,191,[Error allocating memory for time_cache]
+ja,base,192,[cs-terminate failure (%s)]
+ja,base,193,[cs-init failure (%s)]
+ja,base,194,[cs-wait failure (%s)]
+ja,base,195,[cs-post failure (%s)]
+ja,base,196,[Unable to create nonblocking socket (%s)]
+ja,base,197,[error: could not set keepalive (%s)\n]
+ja,base,198,[error: could not set recv timeout (%s)\n]
+ja,base,199,[error: could not set send timeout (%s)\n]
+ja,base,200,[Unable to create nonblocking socket (%s)]
+ja,base,201,[sem_grab failed (%s)]
+ja,base,202,[sem_release failed (%s)]
+ja,base,203,[sem_release failed (%s)]
+ja,base,204,[Could not remove temporary directory %s, Error %d]
+ja,base,205,[Could not remove temporary directory %s, Error %d]
+ja,dsgw,-1,[$DBT: dsgw in DB file v1 $]
+ja,dsgw,1,[ç†è§£ã§ããªã„ HTTP リクエストã§ã™ã€‚]
+ja,dsgw,2,[ä¸æ­£ãªã¾ãŸã¯ã€å®Œäº†ã—ã¦ã„ãªã„ HTML フォーム データã§ã™ã€‚]
+ja,dsgw,3,[メモリä¸è¶³ã§ã™ã€‚]
+ja,dsgw,4,[query/form ã®å…¥åŠ›ãŒã•ã‚Œã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,5,[ファイルã¾ãŸã¯ãƒ‘スã®æŒ‡å®šã«ä¸æ­£ãªæ–‡å­—ãŒä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™ã€‚]
+ja,dsgw,6,[設定ファイルãŒè¦‹ã¤ã‹ã‚‰ãªã„ã‹ä¸æ­£ã§ã™ã€‚]
+ja,dsgw,7,[LDAP ã‚’åˆæœŸåŒ–ã§ãã¾ã›ã‚“。]
+ja,dsgw,8,[LDAP ã¨ã®æŽ¥ç¶šæ™‚ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚]
+ja,dsgw,9,[検索ã®å¯¾è±¡ã¨ãªã‚‹ã‚ªãƒ–ジェクトをèªè­˜ã§ãã¾ã›ã‚“。]
+ja,dsgw,10,[ç†è§£ã§ããªã„属性ラベルã§ã™ã€‚]
+ja,dsgw,11,[マッムプロンプトをç†è§£ã§ãã¾ã›ã‚“。]
+ja,dsgw,12,[オブジェクト タイプã«å¯¾ã™ã‚‹æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ãŒã‚ã‚Šã¾ã›ã‚“。]
+ja,dsgw,13,[HTML テンプレート ファイルを開ãã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,14,[検索モードをç†è§£ã§ãã¾ã›ã‚“。 - "smart", "complex", "pattern", ã¾ãŸã¯ "auth" を指定ã—ã¦ãã ã•ã„。]
+ja,dsgw,15,[URL を指定ã™ã‚‹æƒ…å ±ãŒæ¬ è½ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,16,[URL ã®æŒ‡å®šãŒä¸æ˜Žã§ã™ã€‚]
+ja,dsgw,17,[未承èªã® URL ã‚‚ã—ãã¯æœªçŸ¥ã®ã‚¨ãƒ©ãƒ¼]
+ja,dsgw,18,[URL フォーマットãŒä¸æ­£ã§ã™ã€‚]
+ja,dsgw,19,[内部エラー]
+ja,dsgw,20,[テンプレート インデックス ファイルã®æ›¸ãè¾¼ã¿ã«å¤±æ•—ã—ã¾ã—ãŸã€‚]
+ja,dsgw,21,[テンプレート インデックス ファイルを開ãã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,22,[Directory を読ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,23,[LDAP SSL ã®åˆæœŸåŒ–ã«å¤±æ•—ã—ã¾ã—ãŸã€‚ (セキュリティ パスを確èªã—ã¦ãã ã•ã„。)]
+ja,dsgw,24,[SSLã§ä½œæ¥­ã™ã‚‹ãŸã‚ã®ãƒ¦ãƒ¼ã‚¶ã¨ã‚°ãƒ«ãƒ¼ãƒ— フォームã®å ´åˆã€ãƒ¦ãƒ¼ã‚¶ã¾ãŸã¯ã‚µãƒ¼ãƒç®¡ç†è€…ãŒã“ã®Administration Serverã® SSL ã‚’èµ·å‹•ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ã“れを行ã†ã®ã«[æš—å·åŒ–]ã®[オン/オフ]ページを使用ã§ãã¾ã™ã€‚]
+ja,dsgw,25,[証明書データベースã«è¨¼æ˜Žæ›¸ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,26,[エラー: 証明書データベースã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’å¾—ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,27,[ã‚ãªãŸã®è¨¼æ˜Žæ›¸ã®æœ‰åŠ¹æœŸé™ã¯åˆ‡ã‚Œã¦ã„ã¾ã™ã€‚]
+ja,dsgw,28,[無作為ã®æ–‡å­—列を作æˆã§ãã¾ã›ã‚“]
+ja,dsgw,29,[証明書を検索ã—ã¾ã—ãŸãŒã€è­˜åˆ¥åを見ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,30,[証明書データベースを開ãã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,31,[証明書データベースã«è¿½åŠ ã‚’è¡Œã†ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,32,[Directory Manager ãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,33,[検索文字列ãŒå…¥åŠ›ã•ã‚Œã¦ã„ã¾ã›ã‚“。もã†ä¸€åº¦å…¥åŠ›ã—ã¦ãã ã•ã„。]
+ja,dsgw,34,[設定ファイルã®ï¼‘行中ã«è¨­å®šé …ç›®ãŒå¤šã™ãŽã¾ã™ã€‚]
+ja,dsgw,35,[ウインドウズ ソケットã®åˆæœŸåŒ–ã«å¤±æ•—ã—ã¾ã—ãŸã€‚]
+ja,dsgw,36,[証明書をアドミニストレーション サーãƒã‹ã‚‰å¾—ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,37,[識別ã•ã‚Œã‚‹åå‰ãŒ ldapdb:// ã«è¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。]
+ja,dsgw,38,[未承èªã® URL ã¾ãŸã¯æœªçŸ¥ã®ã‚¨ãƒ©ãƒ¼]
+ja,dsgw,39,[URL ã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã«ä¸æ­£ãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,40,[ローカル LDAP データベースã®åˆæœŸåŒ–中ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ]
+ja,dsgw,41,[Directory サービスã®ã‚¿ã‚¤ãƒ—ãŒä¸æ˜Žã§ã™ã€‚ - "local" ã¾ãŸã¯ "remote" を指定ã—ã¦ãã ã•ã„。]
+ja,dsgw,42,[db 設定ファイルã®èª­ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚]
+ja,dsgw,43,[NSHOME/userdb ã®ãƒ‘スãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,44,[Directory サービスã®è¨­å®šã‚’æ›´æ–°ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,45,[エントリを Directory ã‹ã‚‰èª­ã¿è¾¼ã‚€ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,46,[LDAP データベースを消去ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,47,[エントリã®å¤‰æ›´ãŠã‚ˆã³è¿½åŠ ã‚’è¡Œã†ã“ã¨ã¯ã§ãã¾ã›ã‚“。]
+ja,dsgw,48,[å•é¡Œ]
+ja,dsgw,49,[証明書ã«å•é¡ŒãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,50,[.\n<P>次ã«ç§»ã‚‹å‰ã«å†åº¦èªè¨¼ã‚’å—ã‘ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚\n]
+ja,dsgw,51,[.\n<P>次ã«ç§»ã‚‹å‰ã«å†åº¦èªè¨¼ã‚’å—ã‘ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚\n]
+ja,dsgw,52,[未知ã®ã‚¨ãƒ©ãƒ¼]
+ja,dsgw,53,[æ“作ã¯å®Œäº†ã—ã¾ã—ãŸã€‚]
+ja,dsgw,54,[サーãƒå†…部ã§ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚\n サーãƒç®¡ç†è€…ã«ç¾åœ¨ã®çŠ¶æ…‹ã‚’連絡ã—ã¦ãã ã•ã„。]
+ja,dsgw,55,[サーãƒã¯ã‚²ãƒ¼ãƒˆã‚¦ã‚¨ã‚¤ã‹ã‚‰å—ã‘å–ã£ãŸãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’ç†è§£ã§ãã¾ã›ã‚“。]
+ja,dsgw,56,[ã‚ãªãŸã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯å¿œç­”ãŒãªã„ã¾ã¾ã‚¿ã‚¤ãƒ ã‚¢ã‚¦ãƒˆã—ã¾ã—ãŸã€‚\n å†åº¦æ¤œç´¢ã‚’è¡Œã†éš›ã«ã¯ã€æ¤œç´¢ã®çµæžœã‚’よã考慮ã—ã€åŠ¹çŽ‡ã®ã‚ˆã„方法ã§æ¤œç´¢ã‚’ãŠã“ãªã£ã¦ãã ã•ã„。]
+ja,dsgw,57,[ã‚ãªãŸã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã§å¾—ãŸçµæžœãŒå¤§ãã™ãŽã¾ã™ã€‚\n å†åº¦æ¤œç´¢ã‚’è¡Œã†éš›ã«ã¯ã€æ¤œç´¢ã®çµæžœã‚’よã考慮ã—ã€åŠ¹çŽ‡ã®ã‚ˆã„方法ã§æ¤œç´¢ã‚’ãŠã“ãªã£ã¦ãã ã•ã„。]
+ja,dsgw,58,[サーãƒãŒç†è§£ã§ããªã„方法を使用ã—ã¦ã€\nゲートウエイãŒã‚µãƒ¼ãƒã«èªè¨¼ã‚’試ã¿ã¾ã—ãŸã€‚]
+ja,dsgw,59,[ゲートウエイを経由ã—ãŸèªè¨¼ã¯ã€ã‚µãƒ¼ãƒã§è¡Œã†ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,60,[リクエストã«å¿…è¦ãªæƒ…å ±ãŒæ¬ è½ã—ã¦ã„ã¾ã™ã€‚ リクエストをサーãƒãŒ \n å—ã‘付ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。ã»ã‹ã®ã‚µãƒ¼ãƒã§ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’処ç†ã™ã‚‹ã“ã¨ãŒã§ãã‚Œã°ã€ãƒ‡ãƒ¼ã‚¿ã®ãƒžã‚¹ã‚¿ã‚³ãƒ”ーをä¿æŒã™ã‚‹ã‚µãƒ¼ãƒã‚’りよã†ã—ã¦ãã ã•ã„。]
+ja,dsgw,61,[ã‚ãªãŸã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã®å®Ÿè¡Œã¯ç®¡ç†ã®ç¯„囲を超ãˆã¦ã„ã¾ã™ã€‚]
+ja,dsgw,62,[ゲートウエイãŒè¦æ±‚ã—ãŸé‡å¤§ãªæ‹¡å¼µã¯ã“ã®ã‚µãƒ¼ãƒã§åˆ©ç”¨ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。]
+ja,dsgw,63,[エントリã«å­˜åœ¨ã—ãªã„属性ãŒè¦æ±‚ã«ã‚ˆã£ã¦å‚ç…§ã•ã‚ŒãŸãŸã‚\nã€ã‚µãƒ¼ãƒã¯ã“ã®è¦æ±‚を処ç†ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,64,[è¦æ±‚ãŒãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã®åˆ¶ç´„ã«é•åã—ã¦ã„ã‚‹ãŸã‚ã€\nサーãƒã¯è¦æ±‚を完了ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,65,[サーãƒã¯å…¥åŠ›ã•ã‚ŒãŸå€¤ã‚’追加ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚\n æ—¢ã«å…¥åŠ›ã—ãŸå€¤ãŒã‚¨ãƒ³ãƒˆãƒªã«å«ã¾ã‚Œã¦ã„ã‚‹ã“ã¨ã‚‚考ãˆã‚‰ã‚Œã¾ã™ã€‚]
+ja,dsgw,66,[サーãƒã¯ã‚¨ãƒ³ãƒˆãƒªã‚’見ã¤ã‘られã¾ã›ã‚“ã§ã—ãŸã€‚\n æ–°ã—ã„エントリを追加ã™ã‚‹å ´åˆã€è¿½åŠ ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®è¦ªãŒå¿…ãšå­˜åœ¨ã™ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。\n 検索中ã«ã“ã®ã‚¨ãƒ©ãƒ¼ã‚’å—ä¿¡ã—ãŸã‚‰ã€æ¤œç´¢ã—ã¦ã„ãŸã‚¨ãƒ³ãƒˆãƒªãŒå­˜åœ¨ã—ãªã„ã“ã¨ã‚’示ã—ã¦ã„ã¾ã™ã€‚\nDirectory Manager ã¨ã—ã¦èªè¨¼ã‚’試ã¿ã¦ã„ã‚‹å ´åˆã«ã“ã®ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ãŸã‚‰ã€ã‚²ãƒ¼ãƒˆã‚¦ã‚¨ã‚¤ã®æ§‹æˆãƒ•ã‚¡ã‚¤ãƒ«ã‚’ãƒã‚§ãƒƒã‚¯ã—ã¦ãã ã•ã„。]
+ja,dsgw,67,[識別ã•ã‚ŒãŸåå‰ã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆãŒä¸æ­£ã§ã™ã€‚]
+ja,dsgw,68,[ã‚ãªãŸãŒè©¦ã¿ãŸã‚¨ãƒ³ãƒˆãƒªã¯ã€ãƒ‘スワードを使用ã—ã¦ã„ãªã„ã‹ã€èª¤ã‚ŠãŒã‚ã‚Šã¾ã™ã€‚Directory Manager ã§åŠ ãˆã‚‰ã‚ŒãŸã‚¨ãƒ³ãƒˆãƒªãŒé©åˆ‡ãªå±žæ€§ã§ã‚ã‚‹ã‹ç¢ºèªã—ã¦ãã ã•ã„。 ]
+ja,dsgw,69,[入力ã—ãŸãƒ‘スワード(ã¾ãŸã¯ãã®ä»–ã®èªè¨¼è³‡æ ¼è¨¼æ˜Žæ›¸)ã¯æ­£ã—ãã‚ã‚Šã¾ã›ã‚“。]
+ja,dsgw,70,[æ“作を実行ã™ã‚‹ãŸã‚ã®æ¨©é™ã‚’æŒã£ã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,71,[サーãƒãŒæ··ã¿åˆã£ã¦ã„ã¾ã™ã€‚数分後ã«å†åº¦æŽ¥ç¶šã‚’è¡Œã£ã¦ãã ã•ã„。]
+ja,dsgw,72,[LDAP サーãƒã«æŽ¥ç¶šã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,73,[サーãƒã¯ã‚ãªãŸã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’処ç†ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。\n サーãƒã«å¤§ããªè² è·ãŒã‹ã‹ã£ã¦ã„ã‚‹ã‹ã€ã‚µãƒ¼ãƒãŒã‚ãªãŸã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’ \n 処ç†ã™ã‚‹ã‚ˆã†ã«è¨­å®šã•ã‚Œã¦ã„ãªã„ã“ã¨ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚]
+ja,dsgw,74,[Directory サーãƒã¯ã‚ãªãŸã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã‚’処ç†ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。\n リクエストã®å†…容ãŒæ­£ã—ããªã„ã‹ã€ã‚µãƒ¼ãƒãŒæ›´æ–°å‡¦ç†ã‚’è¡Œã£ã¦ã„ã‚‹ \n 最中ã§ã‚ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,75,[Directory サーãƒã¯æŒ‡å®šã—ãŸã‚¨ãƒ³ãƒˆãƒªã«å­ãŒã„ã‚‹å ´åˆã€\n エントリã®å‰Šé™¤ãƒ»åå‰ã®å¤‰æ›´ã‚’è¡Œã†ã“ã¨ãŒã§ãã¾ã›ã‚“。ã“ã®æ“作を行ã†ã«ã¯ã€\n æ“作ã®å‰ã«å­ã®ã‚¨ãƒ³ãƒˆãƒªã‚’å…¨ã¦å‰Šé™¤ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,76,[サーãƒã«æ–°ã—ã„エントリを追加・åå‰ã®å¤‰æ›´ã‚’è¡Œã†ã“ã¨ãŒã§ãã¾ã›ã‚“。\n æ—¢ã«åŒã˜åå‰ã®ã‚¨ãƒ³ãƒˆãƒªãŒå­˜åœ¨ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,77,[ã‚ãªãŸã®ãƒªã‚¯ã‚¨ã‚¹ãƒˆã¯è¤‡æ•°ã® Directory サーãƒã«å映ã•ã‚Œã¾ã™ã€‚]
+ja,dsgw,78,[Directory サーãƒã«æŽ¥ç¶šã§ãã¾ã›ã‚“ã§ã—ãŸã€‚\n サーãƒç®¡ç†è€…ã«ã”相談ãã ã•ã„。]
+ja,dsgw,79,[サーãƒã«ãƒ‡ãƒ¼ã‚¿ã‚’é€ä¿¡ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚]
+ja,dsgw,80,[サーãƒã‹ã‚‰ãƒ‡ãƒ¼ã‚¿ã‚’読ã¿è¾¼ã¿ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚]
+ja,dsgw,81,[サーãƒã‹ã‚‰ã®å¿œç­”ãŒã‚ã‚Šã¾ã›ã‚“。タイムアウトã—ã¾ã—ãŸã€‚]
+ja,dsgw,82,[サーãƒã¯ã‚²ãƒ¼ãƒˆã‚¦ã‚¨ã‚¤ãŒä½¿ç”¨ã™ã‚‹èªè¨¼æ–¹æ³•ã‚’サãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,83,[検索フィルタを構æˆä¸­ã«ã‚²ãƒ¼ãƒˆã‚¦ã‚¨ã‚¤ã§ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚]
+ja,dsgw,84,[æ“作ã¯ãƒªã‚¯ã‚¨ã‚¹ãƒˆã«ã‚ˆã‚Šã‚­ãƒ£ãƒ³ã‚»ãƒ«ã•ã‚Œã¾ã—ãŸã€‚]
+ja,dsgw,85,[ライブラリã§å†…部エラーãŒç™ºç”Ÿã—ã¾ã—ãŸã€‚パラメータã«ä¸æ­£ãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,86,[サーãƒã¸ã®æŽ¥ç¶šã‚’é–‹ã‘られã¾ã›ã‚“ã§ã—ãŸã€‚サーãƒç®¡ç†è€…ã«ã”相談ãã ã•ã„。]
+ja,dsgw,87,[未知ã®ã‚¨ãƒ©ãƒ¼ã«é­é‡ã—ã¾ã—ãŸã€‚]
+ja,dsgw,88,[エントリã¯æ—¢ã«å­˜åœ¨ã—ã¾ã™ã€‚]
+ja,dsgw,89,[エントリå ]
+ja,dsgw,90,[onMouseOver="window.status='エントリをå‚ç…§ã™ã‚‹ã«ã¯ã‚¯ãƒªãƒƒã‚¯ã—ã¦ãã ã•ã„。'; return true"]
+ja,dsgw,91,[ æ—¢ã«å­˜åœ¨ã—ã¾ã™ã€‚<P>別ã®åå‰ãƒ»å ´æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。\n<P>\n]
+ja,dsgw,92,[親エントリã¯å­˜åœ¨ã—ã¾ã›ã‚“。]
+ja,dsgw,93,[次ã®åå‰ã®ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ãŒã§ãã¾ã›ã‚“: <P><B>%s</B>,<P>\n 親エントリãŒå­˜åœ¨ã—ã¾ã›ã‚“。<P>\n 親エントリを最åˆã«ç™»éŒ²ã—ã¦ãã ã•ã„。\n]
+ja,dsgw,94,[ã“ã‚Œã®è¦ª\n]
+ja,dsgw,95,[エントリå: <P><B>%s</B>.\n]
+ja,dsgw,96,[警告: èªè¨¼ã•ã‚Œã¦ã„ã¾ã›ã‚“。 (次ã¸)...\n]
+ja,dsgw,97,[%s Directory エントリ]
+ja,dsgw,98,[<PRE>エントリ DN: %s</PRE><P>\n]
+ja,dsgw,99,[<B>%s</B> ã«å¤‰æ›´ã—ä¿å­˜ã—ã¾ã—ãŸã€‚]
+ja,dsgw,100,[<B>%s</B> を追加ã—ã¾ã—ãŸã€‚]
+ja,dsgw,101,[<B>%s</B> を削除ã—ã¾ã—ãŸã€‚]
+ja,dsgw,102,[<B>%s</B> ã‹ã‚‰ <B>%s</B> ã¸åå‰ã‚’変更ã—ã¾ã—ãŸã€‚]
+ja,dsgw,103,[<P><B>ノート:</B> ã‚ãªãŸã® %s エントリã¯ç ´æ£„ã•ã‚Œã¾ã—ãŸã€‚\n ã‚ãªãŸã¯å†åº¦èªè¨¼ã‚’å—ã‘変更を追加ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚\n]
+ja,dsgw,104,[削除]
+ja,dsgw,105,[åå‰ã®å¤‰æ›´]
+ja,dsgw,106,[パスワード変更]
+ja,dsgw,107,[属性 %s を変更ã—ã¾ã—ãŸã€‚<BR>\n]
+ja,dsgw,108,[ アスキーã§ã¯ãªã„ (%ld ãƒã‚¤ãƒˆ)\n]
+ja,dsgw,109,[値ãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“。 ã‚‚ã†ä¸€åº¦å…¥åŠ›ã—ã¦ãã ã•ã„。\n]
+ja,dsgw,110,[変更ã¯ã‚ã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,111,[<P>%s ã‚’ Directory サーãƒã«é€ä¿¡ã—ã¾ã—ãŸã€‚\n]
+ja,dsgw,112,[情報]
+ja,dsgw,113,[変更]
+ja,dsgw,114,[<P>円å–ã‚‹ã®è¿½åŠ ã«æˆåŠŸã—ã¾ã—ãŸã€‚\n]
+ja,dsgw,115,[<P>エントリã®ä¿®æ­£ã«æˆåŠŸã—ã¾ã—ãŸã€‚変更ã¯ä¿å­˜ã•ã‚Œã¾ã—ãŸã€‚\n]
+ja,dsgw,116,[<P>エントリã®å‰Šé™¤ã¯æˆåŠŸã—ã¾ã—ãŸã€‚\n]
+ja,dsgw,117,[<PRE>æ–°ã—ã„エントリã®åå‰ã¯ã€æ¬¡ã®ã¨ãŠã‚Šã§ã™ï¼š %s\n</PRE><HR>\n]
+ja,dsgw,118,[<P>åå‰ã®å¤‰æ›´ã«æˆåŠŸã—ã¾ã—ãŸã€‚\n]
+ja,dsgw,119,[以å‰ã®ãƒ‘スワードを用æ„ã—ã¦ãã ã•ã„。]
+ja,dsgw,120,[æ–°ã—ã„パスワードã®å…¥åŠ›ãŒå¿…è¦ã§ã™ã€‚ã‚‚ã†ä¸€åº¦è¡Œã£ã¦ãã ã•ã„。]
+ja,dsgw,121,[æ–°ã—ã„パスワードã¨ã€ç¢ºèªã®ãŸã‚ã«å…¥åŠ›ã—ãŸãƒ‘スワードãŒç•°ãªã‚Šã¾ã™ã€‚ã‚‚ã†ä¸€åº¦å…¥åŠ›ã—ã¦ãã ã•ã„。]
+ja,dsgw,122,[<BR>%s <B>%s</B> ã¯ä½¿ç”¨ä¸­ã§ã™ã€‚別ã®æŒ‡å®šã‚’è¡Œã£ã¦ãã ã•ã„。<BR>\n]
+ja,dsgw,123,[データ エレメント "%.100s" ãŒä¸è¶³ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,124,[設定情報をåˆæœŸåŒ–ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,125,[ファイルを開ãã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,126,[dbconf ファイルã®å½¢å¼ãŒä¸æ­£ã§ã™ã€‚]
+ja,dsgw,127,[dbconf ã®ä¸­ã®å±žæ€§å称ã®æŒ‡å®šãŒä¸è¶³ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,128,[メモリä¸è¶³ã§ã™ã€‚]
+ja,dsgw,129,[dbconf ファイルã®ä¸­ã®æŒ‡ä»¤ã®æŒ‡å®šãŒä¸è¶³ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,130,[構æˆãƒ•ã‚¡ã‚¤ãƒ«"%s"ã‚’é–‹ã‘られã¾ã›ã‚“\n]
+ja,dsgw,131,["authlifetime" ã®æŒ‡å®šãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,132,["dirmgr" ã®æŒ‡å®šãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,133,["baseurl" ã®æŒ‡å®šãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,134,["baseurl" ã®ä¸­ã§æŒ‡å®šã•ã‚Œã¦ã„ã‚‹ URL ãŒä¸æ­£ã§ã™ã€‚ - DN ãŒä¸è¶³ã—ã¦ã„ã¾ã™ã€‚\n]
+ja,dsgw,135,[baseurl をパースã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,136,["baseurl" ã®ä¸­ã§æŒ‡å®šã•ã‚Œã¦ã„ã‚‹ URL ãŒä¸æ­£ã§ã™ã€‚ - "ldap://" URL ã®æŒ‡å®šã§ã¯ã‚ã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,137,["ldaps://" ã® URL 指定方法ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。\n]
+ja,dsgw,138,["template" ã®æŒ‡å®šãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,139,["sslrequired" ã®æŒ‡å®šãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,140,[ç†è§£ã§ããªã„値㌠"sslrequired" ã«ã‚ã‚Šã¾ã™ã€‚("never", "whenauthenticated", "always" を指定ã—ã¦ãã ã•ã„。)\n]
+ja,dsgw,141,["securitypath" ã®æŒ‡å®šãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,142,["location-suffix" ã®æŒ‡å®šãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,143,["location" ã®æŒ‡å®šãŒå¿…è¦ã§ã™ã€‚\n]
+ja,dsgw,144,["newtype" ã®æŒ‡å®šã«ã¯ï¼’ã¤ã®å€¤ã‚’指定ã—ã¦ãã ã•ã„。\n]
+ja,dsgw,145,["newtype" ã®å ´æ‰€ãŒä¸æ˜Žã§ã™ã€‚\n]
+ja,dsgw,146,[3ã¤ã¾ãŸã¯ï¼”ã¤ã®æŒ‡å®šãŒ "tmplset" ã«ã¯å¿…è¦ã§ã™ã€‚\n]
+ja,dsgw,147,["attrvset" ã«ã¯ï¼”ã¤ã®æŒ‡å®šãŒå¿…è¦ã§ã™ã€‚\n]
+ja,dsgw,148,["charset" ã®æŒ‡å®šã‚’見ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。\n]
+ja,dsgw,149,["ClientLanguage" ã®æŒ‡å®šã‚’見ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。\n]
+ja,dsgw,150,["AdminLanguage" ã®æŒ‡å®šã‚’見ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。\n]
+ja,dsgw,151,["DefaultLanguage"ã®æŒ‡å®šã‚’見ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。\n]
+ja,dsgw,152,["include" ã«å¯¾å¿œã™ã‚‹ãƒ•ã‚¡ã‚¤ãƒ«åãŒæŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“\n]
+ja,dsgw,153,[設定ファイルã«æœªçŸ¥ã®å‘½ä»¤ãŒã‚ã‚Šã¾ã™\n]
+ja,dsgw,154,[<= erase_db lcache.conf ファイルを開ãã“ã¨ãŒã§ãã¾ã›ã‚“。"%s"\n]
+ja,dsgw,155,[<FONT SIZE="+1">\n<P>データベースã¯å‰Šé™¤ã•ã‚Œã¦ã„ã¾ã™ã€‚ æ–°ã—ã„データベースを作æˆã—ã¾ã™... \n</FONT>\n ]
+ja,dsgw,156,[<FONT SIZE="+1">\n<P>データベースを削除ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。\n</FONT>\n ]
+ja,dsgw,157,[<= app_suffix ldif ファイルを開ãã“ã¨ãŒã§ãã¾ã›ã‚“。 "%s"\n]
+ja,dsgw,158,[<= app_suffix 一時ファイルを開ãã“ã¨ãŒã§ãã¾ã›ã‚“。 "%s"\n]
+ja,dsgw,159,[%s ã‹ã‚‰ %s ã¸åå‰ã®å¤‰æ›´ã‚’è¡Œã†ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,160,[ヌル ãƒã‚¤ãƒ³ã‚¿ãŒ dbconf_read_default_dbinfo() ã‹ã‚‰è¿”ã•ã‚Œã¾ã—ãŸã€‚]
+ja,dsgw,161,["ldapdb" URL ãŒä¸æ­£ã§ã™ã€‚- ベース DN ãŒæ¬ è½ã—ã¦ã„ã¾ã™ã€‚\n]
+ja,dsgw,162,["ldapdb" URL ãŒä¸æ­£ã§ã™ã€‚\n]
+ja,dsgw,163,["baseurl" ã§è¨˜è¿°ã•ã‚ŒãŸ URL ãŒä¸æ­£ã§ã™ã€‚ - ベース DN ãŒæ¬ è½ã—ã¦ã„ã¾ã™ã€‚\n]
+ja,dsgw,164,[baseurl をパースã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,165,["baseurl" ã§è¨˜è¿°ã•ã‚ŒãŸ URL ãŒä¸æ­£ã§ã™ã€‚ - "ldap:// ã¾ãŸã¯ ldapdb://" ã® URL ã§æŒ‡å®šã—ã¦ãã ã•ã„。\n]
+ja,dsgw,166,["ldaps://" ã® URL 指定方法ã¯ã€ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。\n]
+ja,dsgw,167,[binddn ã¯å€¤ã‚’æŒã£ã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,168,[bindpw ã¯å€¤ã‚’æŒã£ã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,169,[デフォルト Directory サービス㧠dbswitch.conf ファイルãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,170,[書込ã¿ã®ãŸã‚ã«æ§‹æˆãƒ•ã‚¡ã‚¤ãƒ«"%s" ã‚’é–‹ã‘られã¾ã›ã‚“\n]
+ja,dsgw,171,[%s ã‹ã‚‰ %s ã¸åå‰ã‚’変更ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,172,[設定ファイル %s: ]
+ja,dsgw,173,[設定ファイル %s: %d 行: ]
+ja,dsgw,174,[最大 %d]
+ja,dsgw,175,[ OK ]
+ja,dsgw,176,[ウインドウを閉ã˜ã‚‹]
+ja,dsgw,177,[å‰ã¸]
+ja,dsgw,178,[{crypt}ロック中 [%s GMT]]
+ja,dsgw,179,[メインã¸]
+ja,dsgw,181,[ Help ]
+ja,dsgw,182,[Help]
+ja,dsgw,184,[Help ã¯ä½¿ç”¨ã§ãã¾ã›ã‚“。]
+ja,dsgw,186,[ウインドウを閉ã˜ã‚‹]
+ja,dsgw,187,[ウインドウを閉ã˜ã‚‹]
+ja,dsgw,188,[テンプレートãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。]
+ja,dsgw,189,[èªè¨¼ä¸­ ...]
+ja,dsgw,190,[èªè¨¼ã‚’å–り消ã—ã¾ã™ã‹ (Log out)?]
+ja,dsgw,191,[検索文字列を入力ã—ã¦ãã ã•ã„]
+ja,dsgw,192,[èªè¨¼ã®æœ€åˆã®ã‚¹ãƒ†ãƒƒãƒ—ã¯ã€Directory ã« ID を入力ã™ã‚‹ã“ã¨ã§ã™ã€‚\n<br>åå‰ã‚’入力ã—ã¦ãã ã•ã„:]
+ja,dsgw,193,[次ã¸]
+ja,dsgw,194,[次ã¸]
+ja,dsgw,195,[キャンセル]
+ja,dsgw,196,[Directory Manager ã¨ã—ã¦èªè¨¼"> &nbsp;(Directory Administrator ã®ã¿åˆ©ç”¨å¯èƒ½)\n]
+ja,dsgw,197,[èªè¨¼ ...]
+ja,dsgw,198,[èªè¨¼ã‚’å–り消ã—ã¾ã™ã‹ï¼Ÿ]
+ja,dsgw,200,[次ã¸]
+ja,dsgw,201,[次ã¸]
+ja,dsgw,202,[キャンセル]
+ja,dsgw,203,[Directory ã§èªè¨¼ (Log in)]
+ja,dsgw,204,[<B>%s</B>ã¨ã—㦠Directory ã«èªè¨¼ã—よã†ã¨ã—ã¦ã„ã¾ã™ã€‚èªè¨¼éŽç¨‹ã‚’完了ã™ã‚‹ã«ã¯ã€ãƒ‘スワードをタイプã—ã¦ãã ã•ã„。\n]
+ja,dsgw,206,[後㧠Directory ã®ã‚ãªãŸã®ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ãƒ»å¤‰æ›´ã‚’è¡Œã†ã«ã¯ã€\nDirectory ã«èªè¨¼(Log in)ã—ãŸå¾Œã€ã‚¬ã‚¤ãƒ‰ã‚’ウインドウ㫠\n 表示ã•ã›ã€ãれをå‚ç…§ã—ãªãŒã‚‰ä½œæ¥­ã‚’è¡Œã£ã¦ãã ã•ã„。\n]
+ja,dsgw,207,[ã“ã®ã‚¹ã‚¯ãƒªãƒ¼ãƒ³ä¸Šã§ Directory ã«èªè¨¼(Log in)ã—ã¦\nã„ã‚‹éš›ã«ã¯ã€æ—¢ã«è¿½åŠ ãƒ»å¤‰æ›´ã®ä½œæ¥­ã‚’è¡Œã†ã“ã¨ãŒå¯èƒ½ã§ã™ã€‚ã¾ã èªè¨¼\n(Log in)ã—ã¦ã„ãªã„å ´åˆã«ã¯ãれを行ã£ãŸã‚ã¨ä½œæ¥­ã‚’è¡Œã£ã¦ãã ã•ã„。\n]
+ja,dsgw,208,[èªè¨¼ã‚¹ãƒ†ãƒ¼ã‚¿ã‚¹]
+ja,dsgw,209,[<form>\nã‚ãªãŸã¯ç¾åœ¨ Directory ã«èªè¨¼ã•ã‚Œã¦ã„ã¾ã™ã€‚]
+ja,dsgw,210,[.\nã‚‚ã—ã‚ãªãŸãŒ Directory ã®èªè¨¼ã‚’å–り消ã™(Log out)ã®ã§ã‚ã‚Œã°ãƒœã‚¿ãƒ³ã‚’押ã—ã¦ãã ã•ã„。]
+ja,dsgw,211,[èªè¨¼ã®å–り消ã—(Log out)]
+ja,dsgw,212,[ã‚ãªãŸãŒç ´æ£„ã™ã‚‹èªè¨¼]
+ja,dsgw,213,[有効期é™ã¯åˆ‡ã‚Œã¾ã—ãŸã€‚\n<HR>\n]
+ja,dsgw,214,[ç¾åœ¨ã‚ãªãŸã¯ã€Directory ã«èªè¨¼ã•ã‚Œã¦ã„ã¾ã›ã‚“。<HR>\n]
+ja,dsgw,215,["%s=" ãŒä¸è¶³ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,216,["%s=%s" ãŒä¸æ˜Žã§ã™ã€‚]
+ja,dsgw,217,[%s オプションãŒä¸æ˜Žã§ã™ã€‚]
+ja,dsgw,218,[%s ã®æ›¸å¼ãŒä¸æ˜Žã§ã™ã€‚\n]
+ja,dsgw,219,[** HTML タイプ "%s" ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。 **<BR>\n]
+ja,dsgw,224,[修正]
+ja,dsgw,225,[変更ä¿ç®¡]
+ja,dsgw,226,[変更]
+ja,dsgw,227,[追加]
+ja,dsgw,228,[削除]
+ja,dsgw,229,[エントリを削除ã—ã¦ã‚ˆã‚ã—ã„ã§ã™ã‹ï¼Ÿ]
+ja,dsgw,230,[åå‰ã®å¤‰æ›´]
+ja,dsgw,231,[エントリã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:]
+ja,dsgw,232,[修正]
+ja,dsgw,233,[%s= ãŒä¸è¶³ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,234,[ウインドウを閉ã˜ã‚‹ã€‚]
+ja,dsgw,235,[修正 ...]
+ja,dsgw,236,["%s=" ä¸è¶³ã—ã¦ã„ã¾ã™ã€‚\n]
+ja,dsgw,237,["%s" ãŒã‚»ãƒƒãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。\n]
+ja,dsgw,238,["%s" ã®æ›¸å¼ãŒä¸æ˜Žã§ã™ã€‚\n]
+ja,dsgw,239,[å†èªè¨¼]
+ja,dsgw,240,[ウインドウを閉ã˜ã‚‹]
+ja,dsgw,241,[よã‚ã—ã„ã§ã™ã‹ï¼Ÿ]
+ja,dsgw,242,[width=400,height=130,resizable]
+ja,dsgw,243,[ OK ]
+ja,dsgw,244,[ OK ]
+ja,dsgw,245,[ リセット ]
+ja,dsgw,246,[ 終了 ]
+ja,dsgw,247,[ キャンセル ]
+ja,dsgw,248,[別㮠IF を発見(入れå­ã® IF ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œå®šã¾ã›ã‚“)]
+ja,dsgw,249,[ELESE を見ã¤ã‘ã¾ã—ãŸãŒã€IF ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。]
+ja,dsgw,250,[ELSE を見ã¤ã‘ã¾ã—ãŸãŒã€å¾Œã® ELSE ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。(ã‚‚ã—ã㯠ENDIF)]
+ja,dsgw,251,[ELIF を見ã¤ã‘ã¾ã—ãŸãŒ IF を見ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,252,[ELIF を見ã¤ã‘ã¾ã—ãŸãŒã€å¾Œã® ELSE ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。(ã‚‚ã—ã㯠ENDIF)]
+ja,dsgw,253,[ENDIF を見ã¤ã‘ã¾ã—ãŸãŒ IF ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。]
+ja,dsgw,254,[<BR><B>テンプレート エラー:</B> %s<BR>\n]
+ja,dsgw,255,[ldap_init/lcache_init ãŒè¨­å®šãƒ•ã‚¡ã‚¤ãƒ«ã‚’読ã¿è¾¼ã‚€å‰ã«å®Ÿè¡Œã•ã‚Œã¾ã—ãŸã€‚]
+ja,dsgw,256,[アドミニストレーション サーãƒã¯å®Ÿè¡Œä¸­ã§ã¯ã‚ã‚Šã¾ã›ã‚“。]
+ja,dsgw,257,[パーミッションをåˆæœŸåŒ–ã™ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,258,[DN ã«ãƒ¦ãƒ¼ã‚¶åãŒãƒžãƒƒãƒ—ã•ã‚Œã¦ã„ã¾ã›ã‚“。(アドミン サーãƒã®ã‚¨ãƒ©ãƒ¼ã§ã™ã€‚)]
+ja,dsgw,259,[ç¾åœ¨ã®ãƒ¦ãƒ¼ã‚¶åã‚’å¾—ã‚‹ã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,260,[ç¾åœ¨ã®ãƒ¦ãƒ¼ã‚¶ãƒ‘スワードを得るã“ã¨ãŒã§ãã¾ã›ã‚“。]
+ja,dsgw,261,[エラー: %s]
+ja,dsgw,262,[ノート: ディスプレイ テンプレートã¯å­˜åœ¨ã—ã¾ã›ã‚“。デフォルト値を使用ã—ã¾ã™ã€‚]
+ja,dsgw,263,[ユーザ ID ãŒä¸æ­£ã‚‚ã—ã㯠LDAP ㌠NULL ã‚’è¿”ã—ã¾ã—ãŸã€‚]
+ja,dsgw,264,[ユーザ ID ã«ãƒžãƒƒãƒã™ã‚‹ã‚‚ã®ãŒã‚ã‚Šã¾ã›ã‚“。]
+ja,dsgw,265,[ユーザ ID ãŒï¼‘ã¤ä»¥ä¸Šè©²å½“ã—ã¾ã™ã€‚]
+ja,dsgw,266,[the entire directory]
+ja,dsgw,267,["includeset" ã«ã¯ï¼’ã¤ã®å€¤ãŒå¿…è¦ã§ã™ã€‚\n]
+ja,dsgw,268,[エントリã«ã¯è¦æ±‚ã•ã‚ŒãŸå±žæ€§å€¤ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸ]
+ja,dsgw,269,["NLS" 指é‡ã®å¼•æ•°ãŒæ¬ ã‘ã¦ã„ã¾ã™\n]
+ja,dsgw,270,[NTユーザIDã®å€¤ã‚’指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™\n]
+ja,dsgw,271,[指é‡å†…ã®NTユーザIDã¨NTドメインIDã®çµ„åˆã‚ã›ã¯å›ºæœ‰ã®ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã‚“\n]
+ja,dsgw,272,[NTユーザIDã¨NTドメインIDã®ä¸¡æ–¹ã®å€¤ã‚’指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™\n]
+ja,dsgw,273,[NTユーザID値ã®é•·ã•ã¯20文字を超éŽã—ã¦ã¯ãªã‚Šã¾ã›ã‚“。\n]
+ja,dsgw,274,[æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã®åå‰ã‚’入力ã—ã¦ãã ã•ã„。]
+ja,dsgw,275,[æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã®å ´æ‰€ã‚’é¸æŠžã—ã¦ãã ã•ã„。]
+ja,dsgw,276,[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]
+ja,dsgw,277,[ã“ã®æ©Ÿèƒ½ã‚’使用ã™ã‚‹ã«ã¯ã€dsgw.confã§å®šç¾©ã•ã‚ŒãŸdirmgrãŒãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“]
+ja,dsgw,278,["vcard-property"ã®æŒ‡é‡ã«ã¯3ã¾ãŸã¯4ã¤ã®å¼•æ•°ãŒå¿…è¦ã§ã™\n]
+ja,dsgw,279,[Vcardプロパティ構文ã¯"cis" ã¾ãŸã¯ "mls"ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“\n]
+ja,dsgw,280,[エントリãŒæ¤œç´¢ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ\n%2$s]
+ja,dsgw,281,['%4$s'ãŒ%2$s%3$sã€ã‚¨ãƒ³ãƒˆãƒªã¯æ¤œç´¢ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ\n]
+ja,dsgw,282,[エントリã¯æ¤œç´¢ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ\n%2$s]
+ja,dsgw,283,['%4$s'ãŒ%2$s%3$sã€ã‚¨ãƒ³ãƒˆãƒªã¯æ¤œç´¢ã•ã‚Œã¾ã›ã‚“ã§ã—ãŸ\n]
+ja,dsgw,284,[1個ã®ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã—ãŸ\n%2$s]
+ja,dsgw,285,['%4$s'ãŒ%2$s%3$sã€1個ã®ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã—ãŸ\n]
+ja,dsgw,286,[1個ã®ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã—ãŸ\n%2$s]
+ja,dsgw,287,[%2$sãŒ'%4$s'%3$sã€1個ã®ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã—ãŸ\n]
+ja,dsgw,288,[%1$li個ã®ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã—ãŸ\n%2$s]
+ja,dsgw,289,['%4$s'ãŒ%2$s%3$sã€%1$li個ã®ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã—ãŸ\n]
+ja,dsgw,290,[%1$li個ã®ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã—ãŸ\n%2$s]
+ja,dsgw,291,['%4$s'ãŒ%2$s%3$sã€%1$li個ã®ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã—ãŸ\n]
+ja,dsgw,292,[LDAPフィルタ]
+ja,dsgw,293,[èªè¨¼ã«ä½¿ç”¨ã—ãŸã‚¨ãƒ³ãƒˆãƒªãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚エントリåãŒå¤‰æ›´ã•ã‚ŒãŸã‹ã€å‰Šé™¤ã•ã‚ŒãŸå¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚ã‚‚ã†ä¸€åº¦èªè¨¼ã‚’è¡Œã£ã¦ã¿ã¦ãã ã•ã„。]
+ja,dsgw,294,[æ–°ã—ã„パスワードã®æ§‹æ–‡ã¯ç„¡åŠ¹ã§ã™ã€‚\n]
+ja,dsgw,295,[æ–°ã—ã„パスワードã¯ãƒ‘スワード履歴ã®ä¸­ã«ã‚ã‚Šã¾ã™ã€‚\n]
+ja,dsgw,296,[パスワードå†å…¥åŠ›ã®åˆ¶é™å›žæ•°ã‚’越ãˆã¾ã—ãŸã€‚システム アドミニストレータã«é€£çµ¡ã—ã¦ãã ã•ã„。\n]
+ja,dsgw,297,[パスワードå†å…¥åŠ›ã®åˆ¶é™å›žæ•°ã‚’越ãˆã¾ã—ãŸã€‚ã‚ã¨ã§ã‚‚ã†ä¸€åº¦è¡Œã£ã¦ãã ã•ã„。\n]
+ja,dsgw,298,[ã“ã®ãƒ‘スワードã¯æœŸé™åˆ‡ã‚Œã§ã™ã€‚システム アドミニストレータã«é€£çµ¡ã—ã¦ã€ãƒ‘スワードをリセットã—ã¦ãã ã•ã„。\n]
+ja,dsgw,299,[修正ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,300,[追加ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,301,[削除ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,302,[åå‰ã‚’変更ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,303,[リストã«åå‰ãŒã‚ã‚Šã¾ã›ã‚“。]
+ja,dsgw,304,[リスト㫠<B>1</B> ã¤ã®åå‰ãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,305,[リスト㫠<B>%s</B>個ã®åå‰ãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,306,[リスト\\nã‹ã‚‰\\n削除ã—ã¾ã™ã‹ï¼Ÿ åå‰]
+ja,dsgw,307,[変更を破棄ã—ã¾ã™ã‹ï¼Ÿ]
+ja,dsgw,308,[width=300,height=130,resizable]
+ja,dsgw,309,[変更をä¿å­˜ã›ãšã«ç¶šè¡Œã—ã¾ã™ã‹ï¼Ÿ<br>ä¿å­˜ã•ã‚Œã¦ã„ãªã„変更ã¯å¤±ã‚ã‚Œã¾ã™ã€‚]
+ja,dsgw,310,[width=400,height=150,resizable]
+ja,dsgw,311,[警告]
+ja,dsgw,312,[確èª]
+ja,dsgw,313,[èªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚\n]
+ja,dsgw,314,[èªè¨¼ã«æˆåŠŸã—ã¾ã—ãŸã€‚]
+ja,dsgw,315,[ディレクトリ㫠<B>%s</B> ã¨ã—ã¦èªè¨¼ã•ã‚Œã¦ã„ã¾ã™ã€‚]
+ja,dsgw,316,[ã‚ãªãŸã®èªè¨¼è³‡æ ¼è¨¼æ˜Žæ›¸ã¯ %d 分ã§å¤±åŠ¹ã—ã¾ã™ã€‚\n]
+ja,dsgw,317,[èªè¨¼ã®å¤±åŠ¹å¾Œã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«å†åº¦èªè¨¼ã‚’å—ã‘ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚\n]
+ja,dsgw,318,[<P>ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®ãƒ‘スワード㯠<B>%s</B> ã§å¤±åŠ¹ã—ã¾ã™ã€‚\n]
+ja,dsgw,319,[èªè¨¼ã«å¤±æ•—ã—ãŸç†ç”±]
+ja,dsgw,320,[ディレクトリã«å­˜åœ¨ã—ãªã„エントリã®èªè¨¼ã‚’å—ã‘よã†ã¨ã—ãŸãŸã‚ã€èªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚\nèªè¨¼ãŒå—ã‘られるã®ã¯ã€æ—¢å­˜ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª エントリã ã‘ã§ã™ã€‚\n]
+ja,dsgw,321,[パスワードãŒè¨­å®šã•ã‚Œã¦ã„ãªã„エントリã®èªè¨¼ã‚’å—ã‘よã†ã¨ã—ãŸãŸã‚ã€èªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚\nèªè¨¼ãŒå—ã‘られるã®ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã«ã‚ˆã£ã¦ãƒ‘スワードãŒè¨­å®šã•ã‚Œã¦ã„るエントリã ã‘ã§ã™ã€‚\n]
+ja,dsgw,322,[入力ã—ãŸãƒ‘スワードãŒæ­£ã—ããªã„ãŸã‚ã€èªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚\n[ã‚‚ã†ä¸€åº¦]をクリックã—ã¦å†åº¦ãƒ‘スワードを入力ã—ã¦ãã ã•ã„。\nエントリã®ãƒ‘スワードを忘れãŸå ´åˆã¯ã€Directory Administratorã«é€£çµ¡ã—ã€ãƒ‘スワードをå†è¨­å®šã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚\n]
+ja,dsgw,323,[予期ã—ãªã„エラー: %s ãŒç™ºç”Ÿã—ãŸãŸã‚ã€èªè¨¼ã«å¤±æ•—ã—ã¾ã—ãŸã€‚\n]
+ja,dsgw,324,[å†å…¥åŠ›]
+ja,dsgw,325,[続行ã™ã‚‹ã«ã¯ã€ä¸Šè¨˜ã®ãƒªã‚¹ãƒˆã‹ã‚‰ã‚¿ã‚¹ã‚¯ã‚’é¸æŠžã—ã¦ãã ã•ã„。\n]
+ja,dsgw,326,[パスワード修正]
+ja,dsgw,327,[<H3>%s ã®ãŸã‚ã«ãƒ‘スワード失効</H3>\n]
+ja,dsgw,328,[ディレクトリ サーãƒã®ãƒ‘スワードãŒå¤±åŠ¹ã—ã¾ã—ãŸã€‚]
+ja,dsgw,329,[ ã™ãã«ãƒ‘スワードを変更ã—ã¦ãã ã•ã„。\n]
+ja,dsgw,330,[パスワードãŒå…¥åŠ›ã•ã‚Œã¦ã„ã¾ã›ã‚“。èªè¨¼ã‚’å—ã‘ã‚‹ã¨ãã¯å¿…ãšãƒ‘スワードを入力ã—ã€ã‚µãƒ¼ãƒã§æœ¬äººã§ã‚ã‚‹ã“ã¨ã‚’ç…§åˆã§ãるよã†ã«ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,331,[サーãƒã¯èªè¨¼è³‡æ ¼è¨¼æ˜Žæ›¸ã‚’生æˆã§ãã¾ã›ã‚“ã§ã—ãŸã€‚èªè¨¼ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã‚’é–‹ãã“ã¨ãŒã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,332,[サーãƒã¯èªè¨¼è³‡æ ¼è¨¼æ˜Žæ›¸ã‚’生æˆã§ãã¾ã›ã‚“ã§ã—ãŸã€‚データをèªè¨¼ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ã«è¿½åŠ ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚]
+ja,dsgw,333,[次ã¸]
+ja,dsgw,334,[ウィンドウを閉ã˜ã‚‹]
+ja,dsgw,335,[æˆåŠŸ]
+ja,dsgw,336,[èªè¨¼è³‡æ ¼è¨¼æ˜Žæ›¸ãŒç„¡åŠ¹ã«ãªã‚Šã¾ã—ãŸã€‚ç¾åœ¨Directoryã«èªè¨¼ã•ã‚Œã¦ã„ã¾ã›ã‚“。\n]
+ja,dsgw,337,[å‰ã¸]
+ja,dsgw,338,[æˆåŠŸ]
+ja,dsgw,339,[オペレーション エラー]
+ja,dsgw,340,[プロトコル エラー]
+ja,dsgw,341,[警告: タイムアウトã—ã¾ã—ãŸã€‚一致ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®ã†ã¡ã€è¡¨ç¤ºã•ã‚Œã¦ã„ãªã„ã‚‚ã®ã‚‚ã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,342,[警告: サイズã®ä¸Šé™ã‚’超ãˆã¾ã—ãŸã€‚一致ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®ã†ã¡ã€è¡¨ç¤ºã•ã‚Œã¦ã„ãªã„ã‚‚ã®ã‚‚ã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,343,[false を比較]
+ja,dsgw,344,[true を比較]
+ja,dsgw,345,[厳密ãªèªè¨¼ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,346,[厳密ãªèªè¨¼ãŒå¿…è¦ã§ã™ã€‚]
+ja,dsgw,347,[警告: 一部ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª サーãƒã«æŽ¥ç¶šã§ãã¾ã›ã‚“ã§ã—ãŸã€‚一致ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®ã†ã¡ã€è¡¨ç¤ºã•ã‚Œã¦ã„ãªã„ã‚‚ã®ã‚‚ã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,348,[レフェラルをå—ä¿¡ã—ã¾ã—ãŸã€‚]
+ja,dsgw,349,[管ç†ã®ç¯„囲を超ãˆã¦ã„ã¾ã™ã€‚]
+ja,dsgw,350,[é‡å¤§ãªæ‹¡å¼µãŒåˆ©ç”¨ã§ãã¾ã›ã‚“。]
+ja,dsgw,351,[機密性ãŒå¿…è¦ã§ã™ã€‚]
+ja,dsgw,352,[SASL ãƒã‚¤ãƒ³ãƒ‰ä¸­ã§ã™ã€‚]
+ja,dsgw,353,[ãã®ã‚ˆã†ãªå±žæ€§ã¯ã‚ã‚Šã¾ã›ã‚“。]
+ja,dsgw,354,[属性ã®ç¨®é¡žãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,355,[マッãƒãƒ³ã‚°ãŒä¸é©åˆ‡ã§ã™ã€‚]
+ja,dsgw,356,[制約é•åã§ã™ã€‚]
+ja,dsgw,357,[タイプã¾ãŸã¯å€¤ãŒå­˜åœ¨ã—ã¾ã™ã€‚]
+ja,dsgw,358,[構文ã«èª¤ã‚ŠãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,359,[ãã®ã‚ˆã†ãªã‚ªãƒ–ジェクトã¯ã‚ã‚Šã¾ã›ã‚“。]
+ja,dsgw,360,[エイリアスã«å•é¡ŒãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,361,[DN ã®æ§‹æ–‡ã«èª¤ã‚ŠãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,362,[オブジェクトã¯è‘‰ã§ã™ã€‚]
+ja,dsgw,363,[エイリアス デリファレンスã«å•é¡ŒãŒã‚ã‚Šã¾ã™ã€‚]
+ja,dsgw,364,[èªè¨¼ãŒä¸é©å½“ã§ã™ã€‚]
+ja,dsgw,365,[証明書ãŒç„¡åŠ¹ã§ã™ã€‚]
+ja,dsgw,366,[アクセスãŒä¸é©åˆ‡ã§ã™ã€‚]
+ja,dsgw,367,[DSA ãŒãƒ“ジー状態ã§ã™ã€‚]
+ja,dsgw,368,[DSA ãŒåˆ©ç”¨ã§ãã¾ã›ã‚“。]
+ja,dsgw,369,[DSA ãŒå®Ÿè¡Œã•ã‚Œã¾ã›ã‚“。]
+ja,dsgw,370,[ループãŒæ¤œå‡ºã•ã‚Œã¾ã—ãŸã€‚]
+ja,dsgw,371,[åå‰ä»˜ã‘é•å]
+ja,dsgw,372,[オブジェクト クラスé•å]
+ja,dsgw,373,[葉ノード以外ã§æ“作を行ã†ã“ã¨ã¯ã§ãã¾ã›ã‚“。]
+ja,dsgw,374,[RDN ã§æ“作を行ã†ã“ã¨ã¯ã§ãã¾ã›ã‚“。]
+ja,dsgw,375,[æ—¢ã«å­˜åœ¨ã—ã¦ã„ã¾ã™ã€‚]
+ja,dsgw,376,[オブジェクト クラスを変更ã§ãã¾ã›ã‚“。]
+ja,dsgw,377,[çµæžœãŒå¤§ãã™ãŽã¾ã™ã€‚]
+ja,dsgw,378,[複数ã®ã‚µãƒ¼ãƒã«å½±éŸ¿ã—ã¾ã™ã€‚]
+ja,dsgw,379,[原因ä¸æ˜Žã®ã‚¨ãƒ©ãƒ¼]
+ja,dsgw,380,[LDAP サーãƒã«æŽ¥ç¶šã§ãã¾ã›ã‚“。]
+ja,dsgw,381,[ローカル エラー]
+ja,dsgw,382,[エンコード エラー]
+ja,dsgw,383,[デコード エラー]
+ja,dsgw,384,[タイムアウト]
+ja,dsgw,385,[èªè¨¼æ–¹æ³•ãŒä¸æ˜Žã§ã™ã€‚]
+ja,dsgw,386,[検索フィルタãŒä¸æ­£ã§ã™ã€‚]
+ja,dsgw,387,[ユーザãŒæ“作をキャンセルã—ã¾ã—ãŸã€‚]
+ja,dsgw,388,[LDAP ルーãƒãƒ³ã«å¯¾ã™ã‚‹ãƒ‘ラメータãŒä¸æ­£ã§ã™ã€‚]
+ja,dsgw,389,[メモリä¸è¶³ã§ã™ã€‚]
+ja,dsgw,390,[LDAP サーãƒã«æŽ¥ç¶šã§ãã¾ã›ã‚“。]
+ja,dsgw,391,[ã“ã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã® LDAP プロトコルã§ã¯ã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã›ã‚“。]
+ja,dsgw,392,[è¦æ±‚ã•ã‚ŒãŸ LDAP コントロールãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。]
+ja,dsgw,393,[çµæžœãŒè¿”ã•ã‚Œã¾ã›ã‚“。]
+ja,dsgw,394,[ã•ã‚‰ã«çµæžœãŒè¿”ã•ã‚Œã¾ã™ã€‚]
+ja,dsgw,395,[クライアントãŒãƒ«ãƒ¼ãƒ—を検出ã—ã¾ã—ãŸã€‚]
+ja,dsgw,396,[レフェラル ホップ リミットを超éŽã—ã¾ã—ãŸã€‚]
+ja,frame,-1,[$DBT: frame in DB file v1 $]
+ja,frame,1,[<TITLE>¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£</TITLE><H1>¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£</H1> ¥ê¥¯¥¨¥¹¥È¤µ¤ì¤¿¥ª¥Ö¥¸¥§¥¯¥È¤ò¸«¤Ä¤±¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£¥ê¥ó¥¯¤¬ÀÚ¤ì¤Æ¤¤¤ë¡¢¥ê¥¯¥¨¥¹¥È¤¬ÉÔÀµ³Î¡¢¥¢¥¯¥»¥¹¸¢¤¬Í¿¤¨¤é¤ì¤Æ¤¤¤Ê¤¤Åù¤Î²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£ ]
+ja,frame,2,[<A HREF="%s">»²¾È¤·¤Æ¤¤¤ë¥Ú¡¼¥¸</A>¤Î¾ðÊó¤ò¥µ¥¤¥È´ÉÍý¼Ô¤ËÃΤ餻¤Æ¤¯¤À¤µ¤¤¡£]
+ja,frame,3,[¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤¬Á÷¤Ã¤¿¥ê¥¯¥¨¥¹¥È¤ò¥×¥í¥¯¥· ¥µ¡¼¥Ð¤¬Íý²ò¤Ç¤­¤Þ¤»¤ó¡£]
+ja,frame,4,[ŬÀÚ¤Êǧ¾Ú¤Ï¥×¥í¥¯¥·¤¬´ÉÍý¤Î¤¿¤á¤ËɬÍפǤ¹¡£\n¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤Îǧ¾Ú¤Ï¼ºÇÔ¤·¤Þ¤·¤¿¡£]
+ja,frame,5,[¥æ¡¼¥¶Ì¾¤Îǧ¾Ú¤Ë¤Ï¥×¥í¥¯¥·¤òÍøÍѤ¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£\n¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤Ï¥×¥í¥¯¥·¤Ë¤è¤ëǧ¾Ú¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£]
+ja,frame,6,[¥ê¥¯¥¨¥¹¥È¤µ¤ì¤¿¥ª¥Ö¥¸¥§¥¯¥È¤ËÂФ¹¤ë¥¢¥¯¥»¥¹¤Ï\n¥×¥í¥¯¥·¤ÎÀßÄê¾åµö¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,frame,7,[¥×¥í¥¯¥·¤Ï¤¢¤Ê¤¿¤Î¥ê¥¯¥¨¥¹¥È¤ò¼Â¹Ô¤¹¤ëºÝ¤Ë¥¨¥é¡¼¤òȯÀ¸¤·¤Þ¤·¤¿¡£\nÀßÄ꤬¸í¤Ã¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£\n¥×¥í¥¯¥· ¥¨¥é¡¼ ¥í¥°¤Î¥á¥Ã¥»¡¼¥¸¤ò»²¾È¤¹¤ë¤è¤¦´ÉÍý¼Ô¤Ë°ÍÍꤷ¤Æ¤¯¤À¤µ¤¤¡£]
+ja,frame,8,[¥ê¥¯¥¨¥¹¥È¤µ¤ì¤¿ÆâÍÆ¤Ï¥×¥í¥¯¥·¤Ë¼ÂÁõ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,frame,9,[¥×¥í¥¯¥·¾å¤Ç¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£]
+ja,frame,10,[¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤¬Á÷¿®¤·¤¿¥ê¥¯¥¨¥¹¥È¤Ï¡¢¥µ¡¼¥Ð¤ËÍý²ò¤¹¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¤â¤Î¤Ç¤¹¡£]
+ja,frame,11,[ŬÀÚ¤Êǧ¾Ú¤Ï¤³¤Î¥¨¥ê¥¢¤Î´ÉÍý¤Î¤¿¤á¤ËɬÍפǤ¹¡£\n¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤Îǧ¾Ú¤Ï¼ºÇÔ¤·¤Þ¤·¤¿¡£]
+ja,frame,12,[¤¢¤Ê¤¿¤Î¥¯¥é¥¤¥¢¥ó¥È¤Ï¥ª¥Ö¥¸¥§¥¯¥È¤ËÂФ¹¤ë¥¢¥¯¥»¥¹¤òµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,frame,13,[¤³¤Î¥µ¡¼¥Ð¤Ï¥ê¥¯¥¨¥¹¥È¤Î½èÍýÃæ¤Ë¥¨¥é¡¼¤ËÁø¶ø¤·¤Þ¤·¤¿¡£¸í¤Ã¤¿ÀßÄ꤬¤Ê¤µ¤ì¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£¥µ¡¼¥Ð¤Î¥¨¥é¡¼ ¥í¥°¤ò»²¾È¤¹¤ë¤è¤¦´ÉÍý¼Ô¤ËÏ¢Íí¤·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,frame,14,[¥ê¥¯¥¨¥¹¥È¤µ¤ì¤¿ÆâÍƤϥµ¡¼¥Ð¤Ë¼ÂÁõ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó]
+ja,frame,15,[¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£]
+ja,frame,16,[¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤¬¥µ¡¼¥Ð¤ËÁ÷¤Ã¤¿¥ê¥¯¥¨¥¹¥È¤Ï¥µ¡¼¥Ð¤¬Íý²ò¤Ç¤­¤Ê¤¤¥ê¥¯¥¨¥¹¥È¤Ç¤¹¡£]
+ja,frame,17,[<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>\n¤³¤Î¥É¥­¥å¥á¥ó¥È¤Ï¿·¤·¤¤¾ì½ê¤Ë°ÜÆ°¤·¤Þ¤·¤¿¡£ <a href="%s"></a>. ¥É¥­¥å¥á¥ó¥È¤È¥Û¥Ã¥È¥ê¥¹¥È¤Î¹¹¿·¤ò¤·¤Æ¤¯¤À¤µ¤¤¡£</BODY></HTML>]
+ja,frame,18,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=euc-jp"><META HTTP-EQUIV="Content-Language" CONTENT="ja"><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>]
+ja,frame,19,[process-uri-objects]
+ja,frame,20,[cannot find template %s]
+ja,frame,21,[process-uri-objects]
+ja,frame,22,[no partial path after object processing]
+ja,frame,23,[find-service]
+ja,frame,24,[invalid shexp %s]
+ja,frame,25,[find-service]
+ja,frame,26,[invalid shexp %s]
+ja,frame,27,[handle-processed]
+ja,frame,28,[no way to service request for %s]
+ja,frame,29,[finish-socks-request]
+ja,frame,30,[close failed (%s), csd=%d]
+ja,frame,31,[This beta software has expired.\n]
+ja,frame,32,[mr_accept(%d)]
+ja,frame,33,[Error issuing read on accept socket]
+ja,frame,34,[acb_accept_connection(%d)]
+ja,frame,35,[Error getting accept socket (%d)]
+ja,frame,36,[Error in accept! (%d, %s)]
+ja,frame,37,[Error creating new accept request]
+ja,frame,38,[accepted connection: %d (NSPR %d)]
+ja,frame,39,[Error creating new session structure]
+ja,frame,40,[accel_read_request()]
+ja,frame,41,[Error allocating request read buffer]
+ja,frame,42,[Error issuing async read request]
+ja,frame,43,[acb_read_request(%d, bytes %d)]
+ja,frame,44,[acb_read_req(1 session = %d)]
+ja,frame,45,[Error reading request (%d, %s)]
+ja,frame,46,[Client aborted connection]
+ja,frame,47,[Error reading request]
+ja,frame,48,[Error creating new request]
+ja,frame,49,[error occurred, closing %d, io was for %d]
+ja,frame,50,[accel_async_scan_headers()]
+ja,frame,51,[out of memory: accel_async_scan_headers]
+ja,frame,52,[out of memory: accel_async_scan_headers]
+ja,frame,53,[Error during async read (%d, %s)]
+ja,frame,54,[scan-headers reports: line too long]
+ja,frame,55,[scan-headers reports: too many headers]
+ja,frame,56,[Error reading headers]
+ja,frame,57,[scan-headers reports: header missing terminator (an empty line)]
+ja,frame,58,[scan-headers reports: header was empty]
+ja,frame,59,[̾Á°¤ËÃͤ¬¤¢¤ê¤Þ¤»¤ó¡§ "%s" ¹Ô]
+ja,frame,60,[accel_send_plain_file()]
+ja,frame,61,[accel_send_plain_file() - found request %d]
+ja,frame,62,[Parse headers lost the URI!]
+ja,frame,63,[accel_send_plain_file() - found uri %s]
+ja,frame,64,[accel_send_plain_file() - found in cache?]
+ja,frame,65,[malloc died!]
+ja,frame,66,[Error writing back file\n]
+ja,frame,67,[acb_send_plain_file(%d)]
+ja,frame,68,[Error writing in acb_send_plain_file (%d, %s)]
+ja,frame,69,[acb_close_connection(%d)]
+ja,frame,70,[Errored IO in acb_close_connection (%d, %s)]
+ja,frame,71,[Unable to close socket %d]
+ja,frame,72,[accel-cache-insert: Error allocating entry]
+ja,frame,73,[cache-init: server cache disabled]
+ja,frame,74,[accel_file_cache: Error initializing file cache]
+ja,frame,75,[accel_file_cache: Error creating cache]
+ja,frame,76,[accel_file_cache_init: CacheHashSize < %d, using %d]
+ja,frame,77,[accel_file_cache_init: CacheHashSize > %d, using %d]
+ja,frame,78,[accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d]
+ja,frame,79,[accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d]
+ja,frame,80,[accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d]
+ja,frame,81,[accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d]
+ja,frame,82,[accel_file_cache: Error initializing file cache]
+ja,frame,83,[file-cache: enabled = %s ]
+ja,frame,84,[on]
+ja,frame,85,[off]
+ja,frame,86,[file-cache: MaxNumberOfCachedFiles %d (0x%x)]
+ja,frame,87,[file-cache: CacheHashSize %d (0x%x)]
+ja,frame,88,[file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)]
+ja,frame,89,[accel-cache-insert: Error allocating entry]
+ja,frame,90,[file-cache-cleanup: munmap failed (%s)]
+ja,frame,91,[file-cache-cleanup: found mmapped file \non system without mmap]
+ja,frame,92,[file_cache_init: MaxTotalCachedFileSize < %d, using %d]
+ja,frame,93,[file_cache_init: MaxTotalCachedFileSize > %d, using %d]
+ja,frame,94,[file cache using mmap flags 0x%x]
+ja,frame,95,[file cache using mmap prots 0x%x]
+ja,frame,96,[file-cache-init: could not create lock]
+ja,frame,97,[file-cache: unable to create temporary directory %s.\n]
+ja,frame,98,[file-cache: unable to create temporary directory %s.\n]
+ja,frame,99,[file-cache: GetTempPath() Cannot find temp directory to store file!]
+ja,frame,100,[file-cache-init: set max cached file size to %d]
+ja,frame,101,[file-cache-init: could not create lock]
+ja,frame,102,[file_cache_destroy()]
+ja,frame,103,[file-cache: Unable to get temp file name. Error %s]
+ja,frame,104,[file-cache: Unable to get temp file name. Error %s]
+ja,frame,105,[file-cache-insert: Error allocating entry]
+ja,frame,106,[file-cache-create: Error opening file %s (%s)]
+ja,frame,107,[file-cache-create: Error stat()ing file %s (%s)]
+ja,frame,108,[file-cache-create: Error mmap()ing file %s (%s)]
+ja,frame,109,[file-cache-create: malloc failure]
+ja,frame,110,[file-cache-create: error case failed to munmap(%d, %d) (%s)]
+ja,frame,111,[file-cache-valid: cannot stat %s]
+ja,frame,112,[dir change: invalidating %s (%d)]
+ja,frame,113,[file-cache: asynchronous file change notification failed.]
+ja,frame,114,[dir change: offset %d, action %d, len %d, name %s]
+ja,frame,115,[unable to check async file status]
+ja,frame,116,[ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s]
+ja,frame,117,[file-cache-add-watch failure- unable to open directory %s. Error %s]
+ja,frame,118,[ReadDirectoryChangesW failure- unable to start watching %s. Error %s]
+ja,frame,119,[func_exec]
+ja,frame,120,[no handler function given for directive]
+ja,frame,121,[func_exec]
+ja,frame,122,[cannot find function named %s]
+ja,frame,123,[handle-request]
+ja,frame,124,[method without URI]
+ja,frame,125,[http-parse-request]
+ja,frame,126,[while scanning HTTP headers, %s]
+ja,frame,127,[handle-request]
+ja,frame,128,[read from %s failed, error is %s]
+ja,frame,129,[handle-request]
+ja,frame,130,[request too long]
+ja,frame,131,[start-http-response]
+ja,frame,132,[write failed (%s)]
+ja,frame,133,[start-http-response]
+ja,frame,134,[write failed (%s)]
+ja,frame,135,[http-status]
+ja,frame,136,[%d is not a valid HTTP status code]
+ja,frame,137,[finish-request]
+ja,frame,138,[close failed (%s)]
+ja,frame,139,[Unable to close socket for writing]
+ja,frame,140,[os has %d objects]
+ja,frame,141,[obj %d has no hash table at %d]
+ja,frame,142,[obj %d has no param]
+ja,frame,143,[obj %d name %s value %s]
+ja,frame,144,[.....directives %d.......]
+ja,frame,145,[.....directive %d]
+ja,frame,146,[.......instance %d]
+ja,frame,147,[...........param name %s value %s]
+ja,frame,148,[ClearConfigurationParameters:RegCreateKey %s]
+ja,frame,149,[ClearConfigurationParameters:RegEnumKey %s failed]
+ja,frame,150,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+ja,frame,151,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+ja,frame,152,[Unable to allocate Subject property list.\n]
+ja,frame,153,[Unable to set session ptr in Subject property list - error=%d\n]
+ja,frame,154,[Unable to set request ptr in Subject property list - error=%d\n]
+ja,frame,155,[file-cache-valid: cannot stat %s]
+ja,frame,156,[file-cache-create: Error stat()ing file %s (%s)]
+ja,httpdaemon,-1,[$DBT: httpdaemon in DB file v1 $]
+ja,httpdaemon,1,[Error in ConvertThreadToFiber]
+ja,httpdaemon,2,[Error in ConvertThreadToFiber]
+ja,httpdaemon,3,[Error in md_start_system]
+ja,httpdaemon,4,[Error in CreateFiber - idlefiber]
+ja,httpdaemon,5,[Error in GetQueuedCompletionStatus]
+ja,httpdaemon,6,[Error creating completion port]
+ja,httpdaemon,7,[Could not SetHandleNonInheritable (%s)]
+ja,httpdaemon,8,[Error accept/read new conn]
+ja,httpdaemon,9,[Error in Respond()]
+ja,httpdaemon,10,[Error in RespondCompleted()]
+ja,httpdaemon,11,[daemon: unable to fork new process (%s)\n]
+ja,httpdaemon,12,[daemon: setsid failed (%s)\n]
+ja,httpdaemon,13,[daemon: can't log pid to %s (%s)\n]
+ja,httpdaemon,14,[warning: could not set group id to %d (%s)\n]
+ja,httpdaemon,15,[warning: could not set user id to %d (%s)\n]
+ja,httpdaemon,16,[warning: daemon is running as super-user\n]
+ja,httpdaemon,17,[could not determine current user name\n]
+ja,httpdaemon,18,[error: chroot to %s failed (%s)\n]
+ja,httpdaemon,19,[WARNING! netscape executable and library have different versions.\n]
+ja,httpdaemon,20,[startup: listening to %s://%s, port %d as %s\n]
+ja,httpdaemon,21,[startup: listening to %s://%s, port %d as %s\n]
+ja,httpdaemon,22,[seminit failed (%s)\n]
+ja,httpdaemon,23,[Using single threaded accepts.]
+ja,httpdaemon,24,[Using multi threaded accepts.]
+ja,httpdaemon,25,[Using partial single threaded accepts.]
+ja,httpdaemon,26,[This machine has %d processors.]
+ja,httpdaemon,27,[Error calling thr_seconcurrency(%d)- (%s)]
+ja,httpdaemon,28,[Set conncurrency to %d.]
+ja,httpdaemon,29,[can't fork new process (%s)]
+ja,httpdaemon,30,[This beta software has expired.\n]
+ja,httpdaemon,31,[can't create IPC pipe (%s)]
+ja,httpdaemon,32,[write to wakeup pipe failed (%s)]
+ja,httpdaemon,33,[select thread miss]
+ja,httpdaemon,34,[startup failure: could not bind to port %d (%s)\n]
+ja,httpdaemon,35,[startup failure: could not bind to port %d, IP address %s (%s)\n]
+ja,libaccess,-1,[$DBT: libaccess in DB file v1 $]
+ja,libaccess,1,[basic-ncsa]
+ja,libaccess,2,[cannot open database %s]
+ja,libaccess,3,[basic-ncsa]
+ja,libaccess,4,[user %s password did not match database %s]
+ja,libaccess,5,[basic-ncsa]
+ja,libaccess,6,[cannot open connection to LDAP server on %s:%d]
+ja,libaccess,7,[basic-ncsa]
+ja,libaccess,8,[user %s password did not match LDAP on %s:%d]
+ja,libaccess,9,[acl-state]
+ja,libaccess,10,[missing realm]
+ja,libaccess,11,[Unable to allocate ACL List Hash\n]
+ja,libaccess,12,[ACLEvalBuildContext unable to PERM_MALLOC cache structure\n]
+ja,libaccess,13,[ACLEvalBuildContext unable to create hash table\n]
+ja,libaccess,14,[ACLEvalBuildContext unable to allocate ACE Entry\n]
+ja,libaccess,15,[ACLEvalBuildContext unable to allocate ACE entry\n]
+ja,libaccess,16,[ACLEvalBuildContext unable to allocate Boundary Entry\n]
+ja,libaccess,17,[ACLEvalBuildContext failed.\n]
+ja,libaccess,18,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n]
+ja,libaccess,19,[LASDnsBuild unable to allocate hash table header\n]
+ja,libaccess,20,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,21,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,22,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,23,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,24,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,25,[LAS DNS build received request for attribute %s\n]
+ja,libaccess,26,[LASDnsEval - illegal comparator %s\n]
+ja,libaccess,27,[LASDnsEval unable to allocate Context struct\n\n]
+ja,libaccess,28,[LASDnsEval unable to get session address %d\n]
+ja,libaccess,29,[LASDnsEval unable to get DNS - error=%s\n]
+ja,libaccess,30,[LAS Group Eval received request for attribute %s\n]
+ja,libaccess,31,[LASGroupEval - illegal comparator %s\n]
+ja,libaccess,32,[LASGroupEval - ran out of memory\n]
+ja,libaccess,33,[LASGroupEval unable to get session address %d\n]
+ja,libaccess,34,[LASGroupEval unable to get session address %d\n]
+ja,libaccess,35,[LASGroupEval - couldn't locate getter for auth-user\n]
+ja,libaccess,36,[LASGroupEval - Attribute getter for auth-user failed\n]
+ja,libaccess,37,[LASGroupEval - Attribute getter didn't set auth-user\n]
+ja,libaccess,38,[Check group membership of user "%s" for group "%s"\n]
+ja,libaccess,39,[LDAPU_SUCCESS for group "%s"\n]
+ja,libaccess,40,[LDAPU_FAILED for group "%s"\n]
+ja,libaccess,41,[LAS_EVAL_FALSE\n]
+ja,libaccess,42,[LAS_EVAL_TRUE\n]
+ja,libaccess,43,[LASIpTreeAlloc - no memory\n]
+ja,libaccess,44,[IP LAS unable to allocate tree node\n]
+ja,libaccess,45,[IP LAS unable to allocate tree node\n]
+ja,libaccess,46,[LAS IP build received request for attribute %s\n]
+ja,libaccess,47,[LASIpEval - illegal comparator %s\n]
+ja,libaccess,48,[LASIpEval unable to get session address - error=%s\n]
+ja,libaccess,49,[LASIpEval unable to allocate Context struct\n\n]
+ja,libaccess,50,[LASIpEval - reach 32 bits without conclusion value=%s]
+ja,libaccess,51,[LAS Program Eval received request for attribute %s\n]
+ja,libaccess,52,[LASProgramEval - illegal comparator %s\n]
+ja,libaccess,53,[LASProgram unable to get session address %d\n]
+ja,libaccess,54,[bin]
+ja,libaccess,55,[LASProgramEval: request not of type admin or bin, passing.\n]
+ja,libaccess,56,[LASProgramEval: check if program %s matches pattern %s.\n]
+ja,libaccess,57,[LASProgramEval: Invalid wildcard expression %s.\n]
+ja,libaccess,58,[LAS_EVAL_FALSE\n]
+ja,libaccess,59,[LAS_EVAL_TRUE\n]
+ja,libaccess,60,[Unexpected attribute in dayOfWeek - %s\n]
+ja,libaccess,61,[Illegal comparator for dayOfWeek - %s\n]
+ja,libaccess,62,[Unexpected attribute in timeOfDay - %s\n]
+ja,libaccess,63,[LAS User Eval received request for attribute %s\n]
+ja,libaccess,64,[LASUserEval - illegal comparator %s\n]
+ja,libaccess,65,[LASUserEval - ran out of memory\n]
+ja,libaccess,66,[LASUserEval unable to get session address %d\n]
+ja,libaccess,67,[LASUserEval unable to get session address %d\n]
+ja,libaccess,68,[LASGroupEval - couldn't locate getter for auth-user\n]
+ja,libaccess,69,[LASGroupEval - Attribute getter for auth-user failed\n]
+ja,libaccess,70,[LASGroupEval - Attribute getter didn't set auth-user\n]
+ja,libaccess,71,[Check if uid == user (i.e. check "%s" == "%s)"\n]
+ja,libaccess,72,[SUCCESS for user "%s"\n]
+ja,libaccess,73,[FAILED for user "%s"\n]
+ja,libaccess,74,[LAS_EVAL_FALSE\n]
+ja,libaccess,75,[LAS_EVAL_TRUE\n]
+ja,libaccess,76,[]
+ja,libaccess,77,[LASProgram unable to get request address - error=%s]
+ja,libaccess,78,[LASProgram rejecting request for program %s from pattern %s]
+ja,libaccess,79,[ACL_CacheFlush: unable to parse file "%s"\n]
+ja,libaccess,80,[ACL_CacheFlush: unable to concatenate ACL list "%s"\n]
+ja,libaccess,81,[ACL_CacheFlush: unable to open and process the magnus file "%s"\n]
+ja,libaccess,82,[Illegal comparator for timeOfDay - %s\n]
+ja,libaccess,83,[ACL_EvalBuildContext unable to create hash table\n]
+ja,libaccess,84,[ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n]
+ja,libaccess,85,[ACL_EvalBuildContext unable to allocate ACE entry\n]
+ja,libaccess,86,[ACL_EvalBuildContext unable to allocate auth pointer array\n]
+ja,libaccess,87,[ACL_EvalBuildContext unable to allocate auth plist\n]
+ja,libaccess,88,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n]
+ja,libaccess,89,[ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n]
+ja,libaccess,90,[ACL_ModuleRegister: module name is missing\n]
+ja,libaccess,91,[ACL_ModuleRegister: call to module init function returned a failed status\n]
+ja,libaccess,92,[ACL_GetAttribute: couldn't determine method for %s\n]
+ja,libaccess,93,[ACL_GetAttribute: couldn't locate getter for %s]
+ja,libaccess,94,[ACL_GetAttribute: attr getter failed to get %s]
+ja,libaccess,95,[ACL_GetAttribute: attr getter failed to get %s]
+ja,libaccess,96,[ACL_GetAttribute: All attribute getters declined for attr %s]
+ja,libaccess,97,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+ja,libaccess,98,[ACL_DatabaseRegister: database name is missing]
+ja,libaccess,99,[Error reading the DB Map File: %s. Reason: %s]
+ja,libaccess,100,[URL is missing for database %s]
+ja,libaccess,101,[Invalid property value pair for database %s]
+ja,libaccess,102,["default" database must be an LDAP database]
+ja,libaccess,103,[Multiple "default" databases are being registered]
+ja,libaccess,104,["default" LDAP database must be registered]
+ja,libaccess,105,[LASGroupEval unable to get database name - error= %s]
+ja,libaccess,106,[received invalid program expression %s]
+ja,libaccess,107,[parse_ldap_url: database url is missing]
+ja,libaccess,108,[parse_ldap_url: database name is missing]
+ja,libaccess,109,[parse_ldap_url: error in parsing ldap url. Reason: %s]
+ja,libaccess,110,[ldap password check: unable to get database name - error=%s]
+ja,libaccess,111,[ldap password check: unable to get parsed database %s]
+ja,libaccess,112,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+ja,libaccess,113,[ldap password check: LDAP error: "%s"]
+ja,libaccess,114,[get_user_ismember_ldap unable to get database name - error=%s]
+ja,libaccess,115,[get_user_ismember_ldap unable to get parsed database %s]
+ja,libaccess,116,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+ja,libaccess,117,[get_user_ismember_ldap: group %s does not exist]
+ja,libaccess,118,[get_user_ismember_ldap: LDAP error: "%s"]
+ja,libaccess,119,[ACL_LDAPDatabaseHandle: %s is not a registered database]
+ja,libaccess,120,[ACL_LDAPDatabaseHandle: %s is not an LDAP database]
+ja,libaccess,121,[ACL_LDAPDatabaseHandle: out of memory]
+ja,libaccess,122,[ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s]
+ja,libaccess,123,[ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s]
+ja,libaccess,124,[insufficient dynamic memory]
+ja,libaccess,125,[error opening file, %s: %s]
+ja,libaccess,126,[duplicate definition of %s]
+ja,libaccess,127,[file %s, line %s: duplicate definition of %s]
+ja,libaccess,128,[file %s, line %s: syntax error]
+ja,libaccess,129,[file %s, line %s: %s is undefined]
+ja,libaccess,130,[in acl %s, %s %s is undefined]
+ja,libaccess,131,[database %s: error accessing %s]
+ja,libaccess,132,[%s]
+ja,libaccess,133,[file %s, line %s: invalid syntax]
+ja,libaccess,134,[file %s, line %s: syntax error at "%s"]
+ja,libaccess,135,[realm %s is not defined]
+ja,libaccess,136,[error code = %d]
+ja,libaccess,137,[internal ACL error]
+ja,libaccess,138,[invalid argument]
+ja,libaccess,139,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+ja,libaccess,140,[couldn't determine dbtype from: %s]
+ja,libaccess,141,[Failed to register database %s]
+ja,libaccess,142,[ACL call returned failed status]
+ja,libaccess,143,[file %s: ACL IO error - %s]
+ja,libaccess,144,[acl_user_exists: ¥á¥â¥êÉÔ­¤Ç¤¹]
+ja,libaccess,145,[acl_user_exists: ¥æ¡¼¥¶¤¬¤â¤¦Â¸ºß¤·¤Þ¤»¤ó]
+ja,libaccess,146,[acl_user_exists: plist ¥¨¥é¡¼]
+ja,libadmin,-1,[$DBT: libadmin in DB file v1 $]
+ja,libadmin,1,[ Help ]
+ja,libadmin,2,[ OK ]
+ja,libadmin,3,[ Reset ]
+ja,libadmin,4,[ Done ]
+ja,libadmin,5,[ Cancel ]
+ja,libir,-1,[$DBT: libadmin in DB file v1 $]
+ja,libir,1,[An I/O error occurred before all form data could be read.]
diff --git a/l10n/dirserv/ja/ns-slapd.txt.eucjp b/l10n/dirserv/ja/ns-slapd.txt.eucjp
new file mode 100644
index 00000000..67175934
--- /dev/null
+++ b/l10n/dirserv/ja/ns-slapd.txt.eucjp
@@ -0,0 +1,981 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/**************************************************************************/
+/* The copyright notice(s) in this Source Code does not indicate actual */
+/* or intended publication of this Source Code. */
+/**************************************************************************/
+
+/* This text file was generated by program dblink */
+
+$Revision: 1.1 $
+$Log: ns-slapd.txt.eucjp,v $
+Revision 1.1 2005/01/21 00:40:48 cvsadm
+Initial revision
+
+Revision 1.1.4.3 2003/09/22 19:36:44 ulfw
+Update copyright years from 2001 to 2001-2003
+
+Revision 1.1.4.2 2001/11/03 01:08:09 richm
+XXX use new copyright XXX
+
+Revision 1.1.4.1 1998/10/10 02:14:13 ggood
+Copy from Directory40RtmBranchpoint to DirectoryBranch
+
+Revision 1.1.2.4.2.1.6.2 1998/04/04 23:17:00 mcs
+merge changes made on directory31_rtm_branch into server4_directory_branch
+
+Revision 1.1.2.4.2.5.2.2 1998/02/24 05:44:41 noriko
+Fixed backslashes
+
+Revision 1.1.2.4.2.5.2.1 1998/02/24 05:39:08 noriko
+Added new updates from the translators
+
+Revision 1.1.2.7 1998/02/12 01:55:50 scronin
+Based on en/ns-slapd.txt : 1.1.2.4
+Build by scronin on 2/8/1998 Solaris
+$EndLog$
+
+$StartStringData$
+
+ja,base,-1,[$DBT: base in DB file v1 $]
+ja,base,1,[¥Ï¥Ã¥·¥å ¥Æ¡¼¥Ö¥ë¤òºîÀ®¤¹¤ë¤¿¤á¤Î¥á¥â¥ê¤¬ÉÔ­¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,base,2,[¥Ï¥Ã¥·¥å ¥Æ¡¼¥Ö¥ë¤òºîÀ®¤¹¤ë¤¿¤á¤Î¥á¥â¥ê¤¬ÉÔ­¤·¤Æ¤¤¤Þ¤¹]
+ja,base,3,[cache_destroy: ¥­¥ã¥Ã¥·¥å ¥Æ¡¼¥Ö¥ë¤¬ÉÔÀµ¤Ç¤¹¡£]
+ja,base,4,[¥Ï¥Ã¥·¥å ¥¨¥ó¥È¥ê¤ò³ä¤êÅö¤Æ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,base,5,[cache_insert: ¥­¥ã¥Ã¥·¥å ¥¨¥ó¥È¥ê¤òºîÀ®¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,base,6,[HTTP/1.0 200 OK\nContent-type: text/html\n\n]
+ja,base,7,[<H2>Netscape ¥­¥ã¥Ã¥·¥å ¥¹¥Æ¡¼¥¿¥¹ ¥ì¥Ý¡¼¥È</H2>\n]
+ja,base,8,[¥·¥¹¥Æ¥à¾å¤Ë¥­¥ã¥Ã¥·¥å¤¬Â¸ºß¤·¤Þ¤»¤ó¡£<P>]
+ja,base,9,[<H2>%s ¥­¥ã¥Ã¥·¥å</H2>\n]
+ja,base,10,[¥­¥ã¥Ã¥·¥å ¥Ò¥Ã¥È ¥ì¥·¥ª¡§ %d/%d (%f)</P>\n</P>\n]
+ja,base,11,[¥­¥ã¥Ã¥·¥å ¥µ¥¤¥º¡§ %d/%d</P>\n</P>\n]
+ja,base,12,[¥Ï¥Ã¥·¥å ¥Æ¡¼¥Ö¥ë ¥µ¥¤¥º¡§ %d</P>\n</P>\n]
+ja,base,13,[mru : %d</P>\nlru : %d</P>\n]
+ja,base,14,[<UL><TABLE BORDER=4> <TH>Bucket</TH> <TH>¥¢¥É¥ì¥¹</TH> <TH>¥­¡¼</TH> <TH>¥¢¥¯¥»¥¹²ó¿ô</TH> <TH>ºï½ü</TH> <TH>¼¡¤Ø</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>¥Ç¡¼¥¿</TH>\n]
+ja,base,15,[munmap failed (%s)]
+ja,base,16,[munmap failed (%s)]
+ja,base,17,[close failed (%s)]
+ja,base,18,[daemon: unable to fork new process (%s)\n]
+ja,base,19,[daemon: setsid failed (%s)\n]
+ja,base,20,[daemon: can't log pid to %s (%s)\n]
+ja,base,21,[warning: could not set group id to %d (%s)\n]
+ja,base,22,[warning: could not set user id to %d (%s)\n]
+ja,base,23,[warning: daemon is running as super-user\n]
+ja,base,24,[could not determine current user name\n]
+ja,base,25,[error: chroot to %s failed (%s)\n]
+ja,base,27,[, address %s]
+ja,base,28,[warning: statistics disabled (%s)\n]
+ja,base,29,[security handshake timed out for pid %d]
+ja,base,30,[warning: statistics disabled (%s)\n]
+ja,base,31,[secure handshake failed (code %d)\n]
+ja,base,32,[accept failed (%s)]
+ja,base,33,[warning: statistics disabled (%s)\n]
+ja,base,34,[select thread miss]
+ja,base,35,[keepalive worker awoken with no work to do]
+ja,base,36,[could not create new thread: %d (%s)]
+ja,base,37,[wait for sema succeeded, but nothing to dequeue]
+ja,base,38,[queue-sema creation failure]
+ja,base,39,[error getting processor info for processor %d]
+ja,base,40,[Error binding to processor %d]
+ja,base,41,[bound process %d to processor %d]
+ja,base,42,[Netscape server is not explicitly binding to any processors.]
+ja,base,43,[cache monitor exited]
+ja,base,44,[cache batch update daemon exited]
+ja,base,45,[Using single threaded accepts.]
+ja,base,46,[Using multi threaded accepts.]
+ja,base,47,[Using partial single threaded accepts.]
+ja,base,48,[This machine has %d processors.]
+ja,base,49,[Error calling thr_seconcurrency(%d)- (%s)]
+ja,base,50,[Set conncurrency to %d.]
+ja,base,51,[WARNING! netscape executable and library have different versions.\n]
+ja,base,54,[seminit failed (%s)\n]
+ja,base,55,[This beta software has expired.\n]
+ja,base,56,[Cache monitor respawned]
+ja,base,57,[Cache batch update daemon respawned]
+ja,base,58,[can't find empty statistics slot]
+ja,base,59,[can't fork new process (%s)]
+ja,base,60,[assert failed! %s\n]
+ja,base,61,[mr_table_init()]
+ja,base,62,[malloc failed]
+ja,base,63,[malloc failed!]
+ja,base,64,[mr_add_io(%d, type %d, file %d)]
+ja,base,65,[mr_add_io - stage 1]
+ja,base,66,[mr_add_io - stage 2]
+ja,base,67,[mr_add_io found invalid IO type %d]
+ja,base,68,[mr_add_io - adding timeout]
+ja,base,69,[Out of memory!\n]
+ja,base,70,[done with mr_add_io]
+ja,base,71,[mr_del_io(%d, type %d, file %d)]
+ja,base,72,[mr_del_io found invalid IO type %d]
+ja,base,73,[mr_lookup_io(%d)]
+ja,base,74,[mr_async_io(%d, %d bytes, file %d)]
+ja,base,75,[malloc failure adding async IO]
+ja,base,76,[Error adding async io!]
+ja,base,77,[Cannot seek for read!]
+ja,base,78,[read failure! (%d, %s)]
+ja,base,79,[do_read read %d bytes for file %d]
+ja,base,80,[Cannot seek for write!]
+ja,base,81,[writev failure! (%d, %s)]
+ja,base,82,[write failure! (%d, %s)]
+ja,base,83,[do_write wrote %d bytes for file %d]
+ja,base,84,[do_timeout(mrp %d)]
+ja,base,85,[do_timeout: found IO (timer=%d, time=%d)]
+ja,base,86,[error deleting io]
+ja,base,87,[timeout callback failure for %d\n]
+ja,base,88,[mr_get_event(%d) - outstanding io %d]
+ja,base,89,[mr_get_event: Waiting for reads on FD:]
+ja,base,90,[mr_get_event: Waiting for writes on FD:]
+ja,base,91,[ %d]
+ja,base,92,[ %d]
+ja,base,93,[mr_get_event set no timeout]
+ja,base,94,[mr_get_event set timeout to: %d.%d sec]
+ja,base,95,[error in select (%d, %s)]
+ja,base,96,[mr_get_event() - select found %d]
+ja,base,97,[error looking up IO fd %d]
+ja,base,98,[read failed for fd %d]
+ja,base,99,[error deleting io]
+ja,base,100,[callback failure for %d\n]
+ja,base,101,[error looking up IO fd %d]
+ja,base,102,[writing: header len %d, writelen %d, total %d]
+ja,base,103,[write failed for fd %d]
+ja,base,104,[error deleting io]
+ja,base,105,[callback failure for %d\n]
+ja,base,106,[Error creating dns cache]
+ja,base,107,[dns_cache_init: hash_size <= 0, using %d]
+ja,base,108,[dns_cache_init: cache-size <= %d, using %d]
+ja,base,109,[dns_cache_init: cache-size is %d is too large, using %d.]
+ja,base,110,[dns_cache_init: expire_time <= 0, using %d]
+ja,base,111,[dns_cache_init: expire is %d is too large, using %d seconds.]
+ja,base,112,[Error creating dns cache]
+ja,base,113,[dns-cache-insert: Error allocating entry]
+ja,base,114,[dns-cache-insert: malloc failure]
+ja,base,115,[successful server startup]
+ja,base,116,[%s B%s]
+ja,base,117,[Netscape executable and shared library have different versions]
+ja,base,118,[ executable version is %s]
+ja,base,119,[ shared library version is %s]
+ja,base,120,[error reporting shutting down]
+ja,base,121,[warning]
+ja,base,122,[config]
+ja,base,123,[security]
+ja,base,124,[failure]
+ja,base,125,[catastrophe]
+ja,base,126,[info]
+ja,base,127,[verbose]
+ja,base,128,[event_handler:Failed to wait on events %s]
+ja,base,129,[could not wait on resume event event (%s)]
+ja,base,130,[dlopen of %s failed (%s)]
+ja,base,131,[dlopen of %s failed (%s)]
+ja,base,132,[The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!]
+ja,base,133,[Terminating the server %s]
+ja,base,134,[kill_server:cannot open server event %s]
+ja,base,135,[kill_server:cannot set server event %s]
+ja,base,136,[error: could not get socket (%s)\n]
+ja,base,137,[error: could not set socket option (%s)\n]
+ja,base,138,[Terminating Service:error: could not bind to address %s port %d (%s)\n]
+ja,base,139,[Terminating Service:error: could not bind to port %d (%s)\n]
+ja,base,140,[SetHandleNonInheritable: could not duplicate socket (%s)]
+ja,base,141,[SetHandleNonInheritable: closing the original socket failed (%s)]
+ja,base,142,[Could not SetHandleInformation (%s)]
+ja,base,143,[Terminating Service:Failure: Could not open statistics file (%s)\n]
+ja,base,144,[Could not set Thread Local Storage Value for thread at slot %d]
+ja,base,145,[secure handshake failed (code %d)\n]
+ja,base,146,[accept failed %d (%s)]
+ja,base,147,[Failed to pulse Event %d %s]
+ja,base,148,[Failed to send MobGrowth Event to parent %s]
+ja,base,149,[Pulsing MobRespawn Event %d]
+ja,base,150,[respawn thread pool to %d (%d)]
+ja,base,151,[Could not open event to signal rotate application. Could not create the MoveLog event:%s]
+ja,base,152,[Failed to send MoveLog Event to rotate app %s]
+ja,base,153,[growing thread pool from %d to %d]
+ja,base,154,[Could not open the ServiceControlManager, Error %d]
+ja,base,155,[StartNetsiteService:Could not open the service %s: Error %d]
+ja,base,156,[StartNetsiteService:Could not start the service %s]
+ja,base,157,[Service Startup: Could not allocate security descriptor]
+ja,base,158,[Service Startup: Could not init security descriptor]
+ja,base,159,[Service Startup: Could not set the security Dacl]
+ja,base,160,[Terminating Service:WinSock init failed: %s]
+ja,base,161,[Httpd Server Startup failed: %s]
+ja,base,162,[can't find empty statistics slot]
+ja,base,163,[NT daemon: could not create new thread %d]
+ja,base,164,[Service Startup Failure. Terminating Service:Could not create event %d:%s]
+ja,base,165,[Service Startup Error. Could not create the MoveLog event:%s]
+ja,base,166,[Failed to wait on Event objects %s]
+ja,base,167,[Failed to wait on Event objects %s]
+ja,base,168,[pipebuf_buf2sd: pipebuf_grab IO_ERROR %d]
+ja,base,169,[pool-init: memory pools disabled]
+ja,base,170,[pool-init: free_size <= 0, using %d]
+ja,base,171,[pool-create-block: out of memory]
+ja,base,172,[pool-create: out of memory]
+ja,base,173,[pool-create: out of memory]
+ja,base,174,[pool-malloc: out of memory]
+ja,base,175,[FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.]
+ja,base,176,[regex error: %s (regex: '%s')]
+ja,base,177,[can't create IPC pipe (%s)]
+ja,base,178,[write to wakeup pipe failed (%s)]
+ja,base,179,[flushing %d connections; current %d; tot %d]
+ja,base,180,[accept failed (%s)]
+ja,base,181,[Error creating time cache]
+ja,base,182,[time-cache: cache disabled]
+ja,base,183,[time_cache_init: hash_size < %d, using default, %d]
+ja,base,184,[time_cache_init: hash_size > %d, using default, %d]
+ja,base,185,[time_cache_init: cache_size < %d, using default, %d]
+ja,base,186,[time_cache_init: cache_size > %d, using default, %d]
+ja,base,187,[Error allocating memory for time_cache]
+ja,base,188,[Error allocating memory for time_cache entry]
+ja,base,189,[Error allocating memory for time_cache entry]
+ja,base,190,[Error inserting new time_cache entry]
+ja,base,191,[Error allocating memory for time_cache]
+ja,base,192,[cs-terminate failure (%s)]
+ja,base,193,[cs-init failure (%s)]
+ja,base,194,[cs-wait failure (%s)]
+ja,base,195,[cs-post failure (%s)]
+ja,base,196,[Unable to create nonblocking socket (%s)]
+ja,base,197,[error: could not set keepalive (%s)\n]
+ja,base,198,[error: could not set recv timeout (%s)\n]
+ja,base,199,[error: could not set send timeout (%s)\n]
+ja,base,200,[Unable to create nonblocking socket (%s)]
+ja,base,201,[sem_grab failed (%s)]
+ja,base,202,[sem_release failed (%s)]
+ja,base,203,[sem_release failed (%s)]
+ja,base,204,[Could not remove temporary directory %s, Error %d]
+ja,base,205,[Could not remove temporary directory %s, Error %d]
+ja,dsgw,-1,[$DBT: dsgw in DB file v1 $]
+ja,dsgw,1,[Íý²ò¤Ç¤­¤Ê¤¤ HTTP ¥ê¥¯¥¨¥¹¥È¤Ç¤¹¡£]
+ja,dsgw,2,[ÉÔÀµ¤Ê¤Þ¤¿¤Ï¡¢´°Î»¤·¤Æ¤¤¤Ê¤¤ HTML ¥Õ¥©¡¼¥à ¥Ç¡¼¥¿¤Ç¤¹¡£]
+ja,dsgw,3,[¥á¥â¥êÉÔ­¤Ç¤¹¡£]
+ja,dsgw,4,[query/form ¤ÎÆþÎϤ¬¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,5,[¥Õ¥¡¥¤¥ë¤Þ¤¿¤Ï¥Ñ¥¹¤Î»ØÄê¤ËÉÔÀµ¤Êʸ»ú¤¬»ÈÍѤµ¤ì¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,6,[ÀßÄê¥Õ¥¡¥¤¥ë¤¬¸«¤Ä¤«¤é¤Ê¤¤¤«ÉÔÀµ¤Ç¤¹¡£]
+ja,dsgw,7,[LDAP ¤ò½é´ü²½¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,8,[LDAP ¤È¤ÎÀܳ»þ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£]
+ja,dsgw,9,[¸¡º÷¤ÎÂоݤȤʤ륪¥Ö¥¸¥§¥¯¥È¤òǧ¼±¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,10,[Íý²ò¤Ç¤­¤Ê¤¤Â°À­¥é¥Ù¥ë¤Ç¤¹¡£]
+ja,dsgw,11,[¥Þ¥Ã¥Á ¥×¥í¥ó¥×¥È¤òÍý²ò¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,12,[¥ª¥Ö¥¸¥§¥¯¥È ¥¿¥¤¥×¤ËÂФ¹¤ë¸¡º÷¥Õ¥£¥ë¥¿¤¬¤¢¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,13,[HTML ¥Æ¥ó¥×¥ì¡¼¥È ¥Õ¥¡¥¤¥ë¤ò³«¤¯¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,14,[¸¡º÷¥â¡¼¥É¤òÍý²ò¤Ç¤­¤Þ¤»¤ó¡£ - "smart", "complex", "pattern", ¤Þ¤¿¤Ï "auth" ¤ò»ØÄꤷ¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,15,[URL ¤ò»ØÄꤹ¤ë¾ðÊ󤬷çÍ¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,16,[URL ¤Î»ØÄ꤬ÉÔÌÀ¤Ç¤¹¡£]
+ja,dsgw,17,[̤¾µÇ§¤Î URL ¤â¤·¤¯¤Ï̤ÃΤΥ¨¥é¡¼]
+ja,dsgw,18,[URL ¥Õ¥©¡¼¥Þ¥Ã¥È¤¬ÉÔÀµ¤Ç¤¹¡£]
+ja,dsgw,19,[ÆâÉô¥¨¥é¡¼]
+ja,dsgw,20,[¥Æ¥ó¥×¥ì¡¼¥È ¥¤¥ó¥Ç¥Ã¥¯¥¹ ¥Õ¥¡¥¤¥ë¤Î½ñ¤­¹þ¤ß¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£]
+ja,dsgw,21,[¥Æ¥ó¥×¥ì¡¼¥È ¥¤¥ó¥Ç¥Ã¥¯¥¹ ¥Õ¥¡¥¤¥ë¤ò³«¤¯¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,22,[Directory ¤òÆɤ߹þ¤à¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,23,[LDAP SSL ¤Î½é´ü²½¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£ (¥»¥­¥å¥ê¥Æ¥£ ¥Ñ¥¹¤ò³Îǧ¤·¤Æ¤¯¤À¤µ¤¤¡£)]
+ja,dsgw,24,[SSL¤Çºî¶È¤¹¤ë¤¿¤á¤Î¥æ¡¼¥¶¤È¥°¥ë¡¼¥× ¥Õ¥©¡¼¥à¤Î¾ì¹ç¡¢¥æ¡¼¥¶¤Þ¤¿¤Ï¥µ¡¼¥Ð´ÉÍý¼Ô¤¬¤³¤ÎAdministration Server¤Î SSL ¤òµ¯Æ°¤¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£¤³¤ì¤ò¹Ô¤¦¤Î¤Ë[°Å¹æ²½]¤Î[¥ª¥ó/¥ª¥Õ]¥Ú¡¼¥¸¤ò»ÈÍѤǤ­¤Þ¤¹¡£]
+ja,dsgw,25,[¾ÚÌÀ½ñ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ë¾ÚÌÀ½ñ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,26,[¥¨¥é¡¼¡§ ¾ÚÌÀ½ñ¥Ç¡¼¥¿¥Ù¡¼¥¹¤«¤é¥Ç¡¼¥¿¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,27,[¤¢¤Ê¤¿¤Î¾ÚÌÀ½ñ¤ÎÍ­¸ú´ü¸Â¤ÏÀÚ¤ì¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,28,[̵ºî°Ù¤Îʸ»úÎó¤òºîÀ®¤Ç¤­¤Þ¤»¤ó]
+ja,dsgw,29,[¾ÚÌÀ½ñ¤ò¸¡º÷¤·¤Þ¤·¤¿¤¬¡¢¼±ÊÌ̾¤ò¸«¤Ä¤±¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,30,[¾ÚÌÀ½ñ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò³«¤¯¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,31,[¾ÚÌÀ½ñ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ËÄɲäò¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,32,[Directory Manager ¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,33,[¸¡º÷ʸ»úÎó¤¬ÆþÎϤµ¤ì¤Æ¤¤¤Þ¤»¤ó¡£¤â¤¦°ìÅÙÆþÎϤ·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,34,[ÀßÄê¥Õ¥¡¥¤¥ë¤Î£±¹ÔÃæ¤ËÀßÄê¹àÌܤ¬Â¿¤¹¤®¤Þ¤¹¡£]
+ja,dsgw,35,[¥¦¥¤¥ó¥É¥¦¥º ¥½¥±¥Ã¥È¤Î½é´ü²½¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£]
+ja,dsgw,36,[¾ÚÌÀ½ñ¤ò¥¢¥É¥ß¥Ë¥¹¥È¥ì¡¼¥·¥ç¥ó ¥µ¡¼¥Ð¤«¤éÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,37,[¼±Ê̤µ¤ì¤ë̾Á°¤¬ ldapdb:// ¤Ë¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,38,[̤¾µÇ§¤Î URL ¤Þ¤¿¤Ï̤ÃΤΥ¨¥é¡¼]
+ja,dsgw,39,[URL ¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤ËÉÔÀµ¤¬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,40,[¥í¡¼¥«¥ë LDAP ¥Ç¡¼¥¿¥Ù¡¼¥¹¤Î½é´ü²½Ãæ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿]
+ja,dsgw,41,[Directory ¥µ¡¼¥Ó¥¹¤Î¥¿¥¤¥×¤¬ÉÔÌÀ¤Ç¤¹¡£ - "local" ¤Þ¤¿¤Ï "remote" ¤ò»ØÄꤷ¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,42,[db ÀßÄê¥Õ¥¡¥¤¥ë¤ÎÆɤ߹þ¤ßÃæ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£]
+ja,dsgw,43,[NSHOME/userdb ¤Î¥Ñ¥¹¤¬»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,44,[Directory ¥µ¡¼¥Ó¥¹¤ÎÀßÄê¤ò¹¹¿·¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,45,[¥¨¥ó¥È¥ê¤ò Directory ¤«¤éÆɤ߹þ¤à¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,46,[LDAP ¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò¾Ãµî¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,47,[¥¨¥ó¥È¥ê¤ÎÊѹ¹¤ª¤è¤ÓÄɲäò¹Ô¤¦¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,48,[ÌäÂê]
+ja,dsgw,49,[¾ÚÌÀ½ñ¤ËÌäÂ꤬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,50,[.\n<P>¼¡¤Ë°Ü¤ëÁ°¤ËºÆÅÙǧ¾Ú¤ò¼õ¤±¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£\n]
+ja,dsgw,51,[.\n<P>¼¡¤Ë°Ü¤ëÁ°¤ËºÆÅÙǧ¾Ú¤ò¼õ¤±¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£\n]
+ja,dsgw,52,[̤ÃΤΥ¨¥é¡¼]
+ja,dsgw,53,[Áàºî¤Ï´°Î»¤·¤Þ¤·¤¿¡£]
+ja,dsgw,54,[¥µ¡¼¥ÐÆâÉô¤Ç¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£\n ¥µ¡¼¥Ð´ÉÍý¼Ô¤Ë¸½ºß¤Î¾õÂÖ¤òÏ¢Íí¤·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,55,[¥µ¡¼¥Ð¤Ï¥²¡¼¥È¥¦¥¨¥¤¤«¤é¼õ¤±¼è¤Ã¤¿¥ê¥¯¥¨¥¹¥È¤òÍý²ò¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,56,[¤¢¤Ê¤¿¤Î¥ê¥¯¥¨¥¹¥È¤Ï±þÅú¤¬¤Ê¤¤¤Þ¤Þ¥¿¥¤¥à¥¢¥¦¥È¤·¤Þ¤·¤¿¡£\n ºÆÅÙ¸¡º÷¤ò¹Ô¤¦ºÝ¤Ë¤Ï¡¢¸¡º÷¤Î·ë²Ì¤ò¤è¤¯¹Íθ¤·¡¢¸úΨ¤Î¤è¤¤ÊýË¡¤Ç¸¡º÷¤ò¤ª¤³¤Ê¤Ã¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,57,[¤¢¤Ê¤¿¤Î¥ê¥¯¥¨¥¹¥È¤ÇÆÀ¤¿·ë²Ì¤¬Â礭¤¹¤®¤Þ¤¹¡£\n ºÆÅÙ¸¡º÷¤ò¹Ô¤¦ºÝ¤Ë¤Ï¡¢¸¡º÷¤Î·ë²Ì¤ò¤è¤¯¹Íθ¤·¡¢¸úΨ¤Î¤è¤¤ÊýË¡¤Ç¸¡º÷¤ò¤ª¤³¤Ê¤Ã¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,58,[¥µ¡¼¥Ð¤¬Íý²ò¤Ç¤­¤Ê¤¤ÊýË¡¤ò»ÈÍѤ·¤Æ¡¢\n¥²¡¼¥È¥¦¥¨¥¤¤¬¥µ¡¼¥Ð¤Ëǧ¾Ú¤ò»î¤ß¤Þ¤·¤¿¡£]
+ja,dsgw,59,[¥²¡¼¥È¥¦¥¨¥¤¤ò·Ðͳ¤·¤¿Ç§¾Ú¤Ï¡¢¥µ¡¼¥Ð¤Ç¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,60,[¥ê¥¯¥¨¥¹¥È¤ËɬÍפʾðÊ󤬷çÍ¤Æ¤¤¤Þ¤¹¡£ ¥ê¥¯¥¨¥¹¥È¤ò¥µ¡¼¥Ð¤¬ \n ¼õ¤±ÉÕ¤±¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£¤Û¤«¤Î¥µ¡¼¥Ð¤Ç¥ê¥¯¥¨¥¹¥È¤ò½èÍý¤¹¤ë¤³¤È¤¬¤Ç¤­¤ì¤Ð¡¢¥Ç¡¼¥¿¤Î¥Þ¥¹¥¿¥³¥Ô¡¼¤òÊÝ»ý¤¹¤ë¥µ¡¼¥Ð¤ò¤ê¤è¤¦¤·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,61,[¤¢¤Ê¤¿¤Î¥ê¥¯¥¨¥¹¥È¤Î¼Â¹Ô¤Ï´ÉÍý¤ÎÈϰϤòĶ¤¨¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,62,[¥²¡¼¥È¥¦¥¨¥¤¤¬Í׵ᤷ¤¿½ÅÂç¤Ê³ÈÄ¥¤Ï¤³¤Î¥µ¡¼¥Ð¤ÇÍøÍѤ¹¤ë¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,63,[¥¨¥ó¥È¥ê¤Ë¸ºß¤·¤Ê¤¤Â°À­¤¬Í×µá¤Ë¤è¤Ã¤Æ»²¾È¤µ¤ì¤¿¤¿¤á\n¡¢¥µ¡¼¥Ð¤Ï¤³¤ÎÍ×µá¤ò½èÍý¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,64,[Í׵᤬¥Ç¡¼¥¿¥Ù¡¼¥¹¤ÎÀ©Ìó¤Ë°ãÈ¿¤·¤Æ¤¤¤ë¤¿¤á¡¢\n¥µ¡¼¥Ð¤ÏÍ×µá¤ò´°Î»¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,65,[¥µ¡¼¥Ð¤ÏÆþÎϤµ¤ì¤¿ÃͤòÄɲäǤ­¤Þ¤»¤ó¤Ç¤·¤¿¡£\n ´û¤ËÆþÎϤ·¤¿Ãͤ¬¥¨¥ó¥È¥ê¤Ë´Þ¤Þ¤ì¤Æ¤¤¤ë¤³¤È¤â¹Í¤¨¤é¤ì¤Þ¤¹¡£]
+ja,dsgw,66,[¥µ¡¼¥Ð¤Ï¥¨¥ó¥È¥ê¤ò¸«¤Ä¤±¤é¤ì¤Þ¤»¤ó¤Ç¤·¤¿¡£\n ¿·¤·¤¤¥¨¥ó¥È¥ê¤òÄɲ乤ë¾ì¹ç¡¢Äɲ乤륨¥ó¥È¥ê¤Î¿Æ¤¬É¬¤ºÂ¸ºß¤¹¤ë¤³¤È¤ò³Îǧ¤·¤Æ¤¯¤À¤µ¤¤¡£\n ¸¡º÷Ãæ¤Ë¤³¤Î¥¨¥é¡¼¤ò¼õ¿®¤·¤¿¤é¡¢¸¡º÷¤·¤Æ¤¤¤¿¥¨¥ó¥È¥ê¤¬Â¸ºß¤·¤Ê¤¤¤³¤È¤ò¼¨¤·¤Æ¤¤¤Þ¤¹¡£\nDirectory Manager ¤È¤·¤Æǧ¾Ú¤ò»î¤ß¤Æ¤¤¤ë¾ì¹ç¤Ë¤³¤Î¥¨¥é¡¼¤¬È¯À¸¤·¤¿¤é¡¢¥²¡¼¥È¥¦¥¨¥¤¤Î¹½À®¥Õ¥¡¥¤¥ë¤ò¥Á¥§¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,67,[¼±Ê̤µ¤ì¤¿Ì¾Á°¤Î¥Õ¥©¡¼¥Þ¥Ã¥È¤¬ÉÔÀµ¤Ç¤¹¡£]
+ja,dsgw,68,[¤¢¤Ê¤¿¤¬»î¤ß¤¿¥¨¥ó¥È¥ê¤Ï¡¢¥Ñ¥¹¥ï¡¼¥É¤ò»ÈÍѤ·¤Æ¤¤¤Ê¤¤¤«¡¢¸í¤ê¤¬¤¢¤ê¤Þ¤¹¡£Directory Manager ¤Ç²Ã¤¨¤é¤ì¤¿¥¨¥ó¥È¥ê¤¬Å¬ÀڤʰÀ­¤Ç¤¢¤ë¤«³Îǧ¤·¤Æ¤¯¤À¤µ¤¤¡£ ]
+ja,dsgw,69,[ÆþÎϤ·¤¿¥Ñ¥¹¥ï¡¼¥É(¤Þ¤¿¤Ï¤½¤Î¾¤Îǧ¾Ú»ñ³Ê¾ÚÌÀ½ñ)¤ÏÀµ¤·¤¯¤¢¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,70,[Áàºî¤ò¼Â¹Ô¤¹¤ë¤¿¤á¤Î¸¢¸Â¤ò»ý¤Ã¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,71,[¥µ¡¼¥Ð¤¬º®¤ß¹ç¤Ã¤Æ¤¤¤Þ¤¹¡£¿ôʬ¸å¤ËºÆÅÙÀܳ¤ò¹Ô¤Ã¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,72,[LDAP ¥µ¡¼¥Ð¤ËÀܳ¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,73,[¥µ¡¼¥Ð¤Ï¤¢¤Ê¤¿¤Î¥ê¥¯¥¨¥¹¥È¤ò½èÍý¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£\n ¥µ¡¼¥Ð¤ËÂ礭¤ÊÉé²Ù¤¬¤«¤«¤Ã¤Æ¤¤¤ë¤«¡¢¥µ¡¼¥Ð¤¬¤¢¤Ê¤¿¤Î¥ê¥¯¥¨¥¹¥È¤ò \n ½èÍý¤¹¤ë¤è¤¦¤ËÀßÄꤵ¤ì¤Æ¤¤¤Ê¤¤¤³¤È¤¬¹Í¤¨¤é¤ì¤Þ¤¹¡£]
+ja,dsgw,74,[Directory ¥µ¡¼¥Ð¤Ï¤¢¤Ê¤¿¤Î¥ê¥¯¥¨¥¹¥È¤ò½èÍý¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£\n ¥ê¥¯¥¨¥¹¥È¤ÎÆâÍƤ¬Àµ¤·¤¯¤Ê¤¤¤«¡¢¥µ¡¼¥Ð¤¬¹¹¿·½èÍý¤ò¹Ô¤Ã¤Æ¤¤¤ë \n ºÇÃæ¤Ç¤¢¤ë²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,75,[Directory ¥µ¡¼¥Ð¤Ï»ØÄꤷ¤¿¥¨¥ó¥È¥ê¤Ë»Ò¤¬¤¤¤ë¾ì¹ç¡¢\n ¥¨¥ó¥È¥ê¤Îºï½ü¡¦Ì¾Á°¤ÎÊѹ¹¤ò¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£¤³¤ÎÁàºî¤ò¹Ô¤¦¤Ë¤Ï¡¢\n Áàºî¤ÎÁ°¤Ë»Ò¤Î¥¨¥ó¥È¥ê¤òÁ´¤Æºï½ü¤¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,76,[¥µ¡¼¥Ð¤Ë¿·¤·¤¤¥¨¥ó¥È¥ê¤òÄɲá¦Ì¾Á°¤ÎÊѹ¹¤ò¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£\n ´û¤ËƱ¤¸Ì¾Á°¤Î¥¨¥ó¥È¥ê¤¬Â¸ºß¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,77,[¤¢¤Ê¤¿¤Î¥ê¥¯¥¨¥¹¥È¤ÏÊ£¿ô¤Î Directory ¥µ¡¼¥Ð¤ËÈ¿±Ç¤µ¤ì¤Þ¤¹¡£]
+ja,dsgw,78,[Directory ¥µ¡¼¥Ð¤ËÀܳ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£\n ¥µ¡¼¥Ð´ÉÍý¼Ô¤Ë¤´ÁêÃ̤¯¤À¤µ¤¤¡£]
+ja,dsgw,79,[¥µ¡¼¥Ð¤Ë¥Ç¡¼¥¿¤òÁ÷¿®Ãæ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£]
+ja,dsgw,80,[¥µ¡¼¥Ð¤«¤é¥Ç¡¼¥¿¤òÆɤ߹þ¤ßÃæ¤Ë¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£]
+ja,dsgw,81,[¥µ¡¼¥Ð¤«¤é¤Î±þÅú¤¬¤¢¤ê¤Þ¤»¤ó¡£¥¿¥¤¥à¥¢¥¦¥È¤·¤Þ¤·¤¿¡£]
+ja,dsgw,82,[¥µ¡¼¥Ð¤Ï¥²¡¼¥È¥¦¥¨¥¤¤¬»ÈÍѤ¹¤ëǧ¾ÚÊýË¡¤ò¥µ¥Ý¡¼¥È¤·¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,83,[¸¡º÷¥Õ¥£¥ë¥¿¤ò¹½À®Ãæ¤Ë¥²¡¼¥È¥¦¥¨¥¤¤Ç¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£]
+ja,dsgw,84,[Áàºî¤Ï¥ê¥¯¥¨¥¹¥È¤Ë¤è¤ê¥­¥ã¥ó¥»¥ë¤µ¤ì¤Þ¤·¤¿¡£]
+ja,dsgw,85,[¥é¥¤¥Ö¥é¥ê¤ÇÆâÉô¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£¥Ñ¥é¥á¡¼¥¿¤ËÉÔÀµ¤¬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,86,[¥µ¡¼¥Ð¤Ø¤ÎÀܳ¤ò³«¤±¤é¤ì¤Þ¤»¤ó¤Ç¤·¤¿¡£¥µ¡¼¥Ð´ÉÍý¼Ô¤Ë¤´ÁêÃ̤¯¤À¤µ¤¤¡£]
+ja,dsgw,87,[̤ÃΤΥ¨¥é¡¼¤ËÁø¶ø¤·¤Þ¤·¤¿¡£]
+ja,dsgw,88,[¥¨¥ó¥È¥ê¤Ï´û¤Ë¸ºß¤·¤Þ¤¹¡£]
+ja,dsgw,89,[¥¨¥ó¥È¥ê̾ ]
+ja,dsgw,90,[onMouseOver="window.status='¥¨¥ó¥È¥ê¤ò»²¾È¤¹¤ë¤Ë¤Ï¥¯¥ê¥Ã¥¯¤·¤Æ¤¯¤À¤µ¤¤¡£'; return true"]
+ja,dsgw,91,[ ´û¤Ë¸ºß¤·¤Þ¤¹¡£<P>Ê̤Î̾Á°¡¦¾ì½ê¤òÁªÂò¤·¤Æ¤¯¤À¤µ¤¤¡£\n<P>\n]
+ja,dsgw,92,[¿Æ¥¨¥ó¥È¥ê¤Ï¸ºß¤·¤Þ¤»¤ó¡£]
+ja,dsgw,93,[¼¡¤Î̾Á°¤Î¥¨¥ó¥È¥ê¤ÎÄɲ䬤Ǥ­¤Þ¤»¤ó¡§ <P><B>%s</B>,<P>\n ¿Æ¥¨¥ó¥È¥ê¤¬Â¸ºß¤·¤Þ¤»¤ó¡£<P>\n ¿Æ¥¨¥ó¥È¥ê¤òºÇ½é¤ËÅÐÏ¿¤·¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,94,[¤³¤ì¤Î¿Æ\n]
+ja,dsgw,95,[¥¨¥ó¥È¥ê̾¡§ <P><B>%s</B>.\n]
+ja,dsgw,96,[·Ù¹ð¡§ ǧ¾Ú¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£ (¼¡¤Ø)...\n]
+ja,dsgw,97,[%s Directory ¥¨¥ó¥È¥ê]
+ja,dsgw,98,[<PRE>¥¨¥ó¥È¥ê DN: %s</PRE><P>\n]
+ja,dsgw,99,[<B>%s</B> ¤ËÊѹ¹¤·Êݸ¤·¤Þ¤·¤¿¡£]
+ja,dsgw,100,[<B>%s</B> ¤òÄɲä·¤Þ¤·¤¿¡£]
+ja,dsgw,101,[<B>%s</B> ¤òºï½ü¤·¤Þ¤·¤¿¡£]
+ja,dsgw,102,[<B>%s</B> ¤«¤é <B>%s</B> ¤Ø̾Á°¤òÊѹ¹¤·¤Þ¤·¤¿¡£]
+ja,dsgw,103,[<P><B>¥Î¡¼¥È¡§</B> ¤¢¤Ê¤¿¤Î %s ¥¨¥ó¥È¥ê¤ÏÇË´þ¤µ¤ì¤Þ¤·¤¿¡£\n ¤¢¤Ê¤¿¤ÏºÆÅÙǧ¾Ú¤ò¼õ¤±Êѹ¹¤òÄɲ乤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£\n]
+ja,dsgw,104,[ºï½ü]
+ja,dsgw,105,[̾Á°¤ÎÊѹ¹]
+ja,dsgw,106,[¥Ñ¥¹¥ï¡¼¥ÉÊѹ¹]
+ja,dsgw,107,[°À­ %s ¤òÊѹ¹¤·¤Þ¤·¤¿¡£<BR>\n]
+ja,dsgw,108,[ ¥¢¥¹¥­¡¼¤Ç¤Ï¤Ê¤¤ (%ld ¥Ð¥¤¥È)\n]
+ja,dsgw,109,[Ãͤ¬»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó¡£ ¤â¤¦°ìÅÙÆþÎϤ·¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,110,[Êѹ¹¤Ï¤¢¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,111,[<P>%s ¤ò Directory ¥µ¡¼¥Ð¤ËÁ÷¿®¤·¤Þ¤·¤¿¡£\n]
+ja,dsgw,112,[¾ðÊó]
+ja,dsgw,113,[Êѹ¹]
+ja,dsgw,114,[<P>±ß¼è¤ë¤ÎÄɲäËÀ®¸ù¤·¤Þ¤·¤¿¡£\n]
+ja,dsgw,115,[<P>¥¨¥ó¥È¥ê¤Î½¤Àµ¤ËÀ®¸ù¤·¤Þ¤·¤¿¡£Êѹ¹¤ÏÊݸ¤µ¤ì¤Þ¤·¤¿¡£\n]
+ja,dsgw,116,[<P>¥¨¥ó¥È¥ê¤Îºï½ü¤ÏÀ®¸ù¤·¤Þ¤·¤¿¡£\n]
+ja,dsgw,117,[<PRE>¿·¤·¤¤¥¨¥ó¥È¥ê¤Î̾Á°¤Ï¡¢¼¡¤Î¤È¤ª¤ê¤Ç¤¹¡§ %s\n</PRE><HR>\n]
+ja,dsgw,118,[<P>̾Á°¤ÎÊѹ¹¤ËÀ®¸ù¤·¤Þ¤·¤¿¡£\n]
+ja,dsgw,119,[°ÊÁ°¤Î¥Ñ¥¹¥ï¡¼¥É¤òÍÑ°Õ¤·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,120,[¿·¤·¤¤¥Ñ¥¹¥ï¡¼¥É¤ÎÆþÎϤ¬É¬ÍפǤ¹¡£¤â¤¦°ìÅٹԤäƤ¯¤À¤µ¤¤¡£]
+ja,dsgw,121,[¿·¤·¤¤¥Ñ¥¹¥ï¡¼¥É¤È¡¢³Îǧ¤Î¤¿¤á¤ËÆþÎϤ·¤¿¥Ñ¥¹¥ï¡¼¥É¤¬°Û¤Ê¤ê¤Þ¤¹¡£¤â¤¦°ìÅÙÆþÎϤ·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,122,[<BR>%s <B>%s</B> ¤Ï»ÈÍÑÃæ¤Ç¤¹¡£Ê̤λØÄê¤ò¹Ô¤Ã¤Æ¤¯¤À¤µ¤¤¡£<BR>\n]
+ja,dsgw,123,[¥Ç¡¼¥¿ ¥¨¥ì¥á¥ó¥È "%.100s" ¤¬ÉÔ­¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,124,[ÀßÄê¾ðÊó¤ò½é´ü²½¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,125,[¥Õ¥¡¥¤¥ë¤ò³«¤¯¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,126,[dbconf ¥Õ¥¡¥¤¥ë¤Î·Á¼°¤¬ÉÔÀµ¤Ç¤¹¡£]
+ja,dsgw,127,[dbconf ¤ÎÃæ¤Î°À­Ì¾¾Î¤Î»ØÄ꤬ÉÔ­¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,128,[¥á¥â¥êÉÔ­¤Ç¤¹¡£]
+ja,dsgw,129,[dbconf ¥Õ¥¡¥¤¥ë¤ÎÃæ¤Î»ØÎá¤Î»ØÄ꤬ÉÔ­¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,130,[¹½À®¥Õ¥¡¥¤¥ë"%s"¤ò³«¤±¤é¤ì¤Þ¤»¤ó\n]
+ja,dsgw,131,["authlifetime" ¤Î»ØÄ꤬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,132,["dirmgr" ¤Î»ØÄ꤬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,133,["baseurl" ¤Î»ØÄ꤬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,134,["baseurl" ¤ÎÃæ¤Ç»ØÄꤵ¤ì¤Æ¤¤¤ë URL ¤¬ÉÔÀµ¤Ç¤¹¡£ - DN ¤¬ÉÔ­¤·¤Æ¤¤¤Þ¤¹¡£\n]
+ja,dsgw,135,[baseurl ¤ò¥Ñ¡¼¥¹¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,136,["baseurl" ¤ÎÃæ¤Ç»ØÄꤵ¤ì¤Æ¤¤¤ë URL ¤¬ÉÔÀµ¤Ç¤¹¡£ - "ldap://" URL ¤Î»ØÄê¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,137,["ldaps://" ¤Î URL »ØÄêÊýË¡¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£\n]
+ja,dsgw,138,["template" ¤Î»ØÄ꤬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,139,["sslrequired" ¤Î»ØÄ꤬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,140,[Íý²ò¤Ç¤­¤Ê¤¤Ãͤ¬ "sslrequired" ¤Ë¤¢¤ê¤Þ¤¹¡£("never", "whenauthenticated", "always" ¤ò»ØÄꤷ¤Æ¤¯¤À¤µ¤¤¡£)\n]
+ja,dsgw,141,["securitypath" ¤Î»ØÄ꤬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,142,["location-suffix" ¤Î»ØÄ꤬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,143,["location" ¤Î»ØÄ꤬ɬÍפǤ¹¡£\n]
+ja,dsgw,144,["newtype" ¤Î»ØÄê¤Ë¤Ï£²¤Ä¤ÎÃͤò»ØÄꤷ¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,145,["newtype" ¤Î¾ì½ê¤¬ÉÔÌÀ¤Ç¤¹¡£\n]
+ja,dsgw,146,[£³¤Ä¤Þ¤¿¤Ï£´¤Ä¤Î»ØÄ꤬ "tmplset" ¤Ë¤ÏɬÍפǤ¹¡£\n]
+ja,dsgw,147,["attrvset" ¤Ë¤Ï£´¤Ä¤Î»ØÄ꤬ɬÍפǤ¹¡£\n]
+ja,dsgw,148,["charset" ¤Î»ØÄê¤ò¸«¤Ä¤±¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£\n]
+ja,dsgw,149,["ClientLanguage" ¤Î»ØÄê¤ò¸«¤Ä¤±¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£\n]
+ja,dsgw,150,["AdminLanguage" ¤Î»ØÄê¤ò¸«¤Ä¤±¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£\n]
+ja,dsgw,151,["DefaultLanguage"¤Î»ØÄê¤ò¸«¤Ä¤±¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£\n]
+ja,dsgw,152,["include" ¤ËÂбþ¤¹¤ë¥Õ¥¡¥¤¥ë̾¤¬»ØÄꤵ¤ì¤Æ¤¤¤Þ¤»¤ó\n]
+ja,dsgw,153,[ÀßÄê¥Õ¥¡¥¤¥ë¤Ë̤ÃΤÎÌ¿Î᤬¤¢¤ê¤Þ¤¹\n]
+ja,dsgw,154,[<= erase_db lcache.conf ¥Õ¥¡¥¤¥ë¤ò³«¤¯¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£"%s"\n]
+ja,dsgw,155,[<FONT SIZE="+1">\n<P>¥Ç¡¼¥¿¥Ù¡¼¥¹¤Ïºï½ü¤µ¤ì¤Æ¤¤¤Þ¤¹¡£ ¿·¤·¤¤¥Ç¡¼¥¿¥Ù¡¼¥¹¤òºîÀ®¤·¤Þ¤¹... \n</FONT>\n ]
+ja,dsgw,156,[<FONT SIZE="+1">\n<P>¥Ç¡¼¥¿¥Ù¡¼¥¹¤òºï½ü¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£\n</FONT>\n ]
+ja,dsgw,157,[<= app_suffix ldif ¥Õ¥¡¥¤¥ë¤ò³«¤¯¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£ "%s"\n]
+ja,dsgw,158,[<= app_suffix °ì»þ¥Õ¥¡¥¤¥ë¤ò³«¤¯¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£ "%s"\n]
+ja,dsgw,159,[%s ¤«¤é %s ¤Ø̾Á°¤ÎÊѹ¹¤ò¹Ô¤¦¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,160,[¥Ì¥ë ¥Ý¥¤¥ó¥¿¤¬ dbconf_read_default_dbinfo() ¤«¤éÊÖ¤µ¤ì¤Þ¤·¤¿¡£]
+ja,dsgw,161,["ldapdb" URL ¤¬ÉÔÀµ¤Ç¤¹¡£- ¥Ù¡¼¥¹ DN ¤¬·çÍ¤Æ¤¤¤Þ¤¹¡£\n]
+ja,dsgw,162,["ldapdb" URL ¤¬ÉÔÀµ¤Ç¤¹¡£\n]
+ja,dsgw,163,["baseurl" ¤Çµ­½Ò¤µ¤ì¤¿ URL ¤¬ÉÔÀµ¤Ç¤¹¡£ - ¥Ù¡¼¥¹ DN ¤¬·çÍ¤Æ¤¤¤Þ¤¹¡£\n]
+ja,dsgw,164,[baseurl ¤ò¥Ñ¡¼¥¹¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,165,["baseurl" ¤Çµ­½Ò¤µ¤ì¤¿ URL ¤¬ÉÔÀµ¤Ç¤¹¡£ - "ldap:// ¤Þ¤¿¤Ï ldapdb://" ¤Î URL ¤Ç»ØÄꤷ¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,166,["ldaps://" ¤Î URL »ØÄêÊýË¡¤Ï¡¢¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£\n]
+ja,dsgw,167,[binddn ¤ÏÃͤò»ý¤Ã¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,168,[bindpw ¤ÏÃͤò»ý¤Ã¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,169,[¥Ç¥Õ¥©¥ë¥È Directory ¥µ¡¼¥Ó¥¹¤Ç dbswitch.conf ¥Õ¥¡¥¤¥ë¤¬ÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,170,[½ñ¹þ¤ß¤Î¤¿¤á¤Ë¹½À®¥Õ¥¡¥¤¥ë"%s" ¤ò³«¤±¤é¤ì¤Þ¤»¤ó\n]
+ja,dsgw,171,[%s ¤«¤é %s ¤Ø̾Á°¤òÊѹ¹¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,172,[ÀßÄê¥Õ¥¡¥¤¥ë %s: ]
+ja,dsgw,173,[ÀßÄê¥Õ¥¡¥¤¥ë %s: %d ¹Ô¡§ ]
+ja,dsgw,174,[ºÇÂç %d]
+ja,dsgw,175,[ OK ]
+ja,dsgw,176,[¥¦¥¤¥ó¥É¥¦¤òÊĤ¸¤ë]
+ja,dsgw,177,[Á°¤Ø]
+ja,dsgw,178,[{crypt}¥í¥Ã¥¯Ãæ [%s GMT]]
+ja,dsgw,179,[¥á¥¤¥ó¤Ø]
+ja,dsgw,181,[ Help ]
+ja,dsgw,182,[Help]
+ja,dsgw,184,[Help ¤Ï»ÈÍѤǤ­¤Þ¤»¤ó¡£]
+ja,dsgw,186,[¥¦¥¤¥ó¥É¥¦¤òÊĤ¸¤ë]
+ja,dsgw,187,[¥¦¥¤¥ó¥É¥¦¤òÊĤ¸¤ë]
+ja,dsgw,188,[¥Æ¥ó¥×¥ì¡¼¥È¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,189,[ǧ¾ÚÃæ ...]
+ja,dsgw,190,[ǧ¾Ú¤ò¼è¤ê¾Ã¤·¤Þ¤¹¤« (Log out)¡©]
+ja,dsgw,191,[¸¡º÷ʸ»úÎó¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤]
+ja,dsgw,192,[ǧ¾Ú¤ÎºÇ½é¤Î¥¹¥Æ¥Ã¥×¤Ï¡¢Directory ¤Ë ID ¤òÆþÎϤ¹¤ë¤³¤È¤Ç¤¹¡£\n<br>̾Á°¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤¡§]
+ja,dsgw,193,[¼¡¤Ø]
+ja,dsgw,194,[¼¡¤Ø]
+ja,dsgw,195,[¥­¥ã¥ó¥»¥ë]
+ja,dsgw,196,[Directory Manager ¤È¤·¤Æǧ¾Ú"> &nbsp;(Directory Administrator ¤Î¤ßÍøÍѲÄǽ)\n]
+ja,dsgw,197,[ǧ¾Ú ...]
+ja,dsgw,198,[ǧ¾Ú¤ò¼è¤ê¾Ã¤·¤Þ¤¹¤«¡©]
+ja,dsgw,200,[¼¡¤Ø]
+ja,dsgw,201,[¼¡¤Ø]
+ja,dsgw,202,[¥­¥ã¥ó¥»¥ë]
+ja,dsgw,203,[Directory ¤Çǧ¾Ú (Log in)]
+ja,dsgw,204,[<B>%s</B>¤È¤·¤Æ Directory ¤Ëǧ¾Ú¤·¤è¤¦¤È¤·¤Æ¤¤¤Þ¤¹¡£Ç§¾Ú²áÄø¤ò´°Î»¤¹¤ë¤Ë¤Ï¡¢¥Ñ¥¹¥ï¡¼¥É¤ò¥¿¥¤¥×¤·¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,206,[¸å¤Ç Directory ¤Î¤¢¤Ê¤¿¤Î¥¨¥ó¥È¥ê¤ÎÄɲá¦Êѹ¹¤ò¹Ô¤¦¤Ë¤Ï¡¢\nDirectory ¤Ëǧ¾Ú(Log in)¤·¤¿¸å¡¢¥¬¥¤¥É¤ò¥¦¥¤¥ó¥É¥¦¤Ë \n ɽ¼¨¤µ¤»¡¢¤½¤ì¤ò»²¾È¤·¤Ê¤¬¤éºî¶È¤ò¹Ô¤Ã¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,207,[¤³¤Î¥¹¥¯¥ê¡¼¥ó¾å¤Ç Directory ¤Ëǧ¾Ú(Log in)¤·¤Æ\n¤¤¤ëºÝ¤Ë¤Ï¡¢´û¤ËÄɲá¦Êѹ¹¤Îºî¶È¤ò¹Ô¤¦¤³¤È¤¬²Äǽ¤Ç¤¹¡£¤Þ¤Àǧ¾Ú\n(Log in)¤·¤Æ¤¤¤Ê¤¤¾ì¹ç¤Ë¤Ï¤½¤ì¤ò¹Ô¤Ã¤¿¤¢¤Èºî¶È¤ò¹Ô¤Ã¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,208,[ǧ¾Ú¥¹¥Æ¡¼¥¿¥¹]
+ja,dsgw,209,[<form>\n¤¢¤Ê¤¿¤Ï¸½ºß Directory ¤Ëǧ¾Ú¤µ¤ì¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,210,[.\n¤â¤·¤¢¤Ê¤¿¤¬ Directory ¤Îǧ¾Ú¤ò¼è¤ê¾Ã¤¹(Log out)¤Î¤Ç¤¢¤ì¤Ð¥Ü¥¿¥ó¤ò²¡¤·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,211,[ǧ¾Ú¤Î¼è¤ê¾Ã¤·(Log out)]
+ja,dsgw,212,[¤¢¤Ê¤¿¤¬ÇË´þ¤¹¤ëǧ¾Ú]
+ja,dsgw,213,[Í­¸ú´ü¸Â¤ÏÀÚ¤ì¤Þ¤·¤¿¡£\n<HR>\n]
+ja,dsgw,214,[¸½ºß¤¢¤Ê¤¿¤Ï¡¢Directory ¤Ëǧ¾Ú¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£<HR>\n]
+ja,dsgw,215,["%s=" ¤¬ÉÔ­¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,216,["%s=%s" ¤¬ÉÔÌÀ¤Ç¤¹¡£]
+ja,dsgw,217,[%s ¥ª¥×¥·¥ç¥ó¤¬ÉÔÌÀ¤Ç¤¹¡£]
+ja,dsgw,218,[%s ¤Î½ñ¼°¤¬ÉÔÌÀ¤Ç¤¹¡£\n]
+ja,dsgw,219,[** HTML ¥¿¥¤¥× "%s" ¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£ **<BR>\n]
+ja,dsgw,224,[½¤Àµ]
+ja,dsgw,225,[Êѹ¹ÊÝ´É]
+ja,dsgw,226,[Êѹ¹]
+ja,dsgw,227,[ÄɲÃ]
+ja,dsgw,228,[ºï½ü]
+ja,dsgw,229,[¥¨¥ó¥È¥ê¤òºï½ü¤·¤Æ¤è¤í¤·¤¤¤Ç¤¹¤«¡©]
+ja,dsgw,230,[̾Á°¤ÎÊѹ¹]
+ja,dsgw,231,[¥¨¥ó¥È¥ê¤Î¿·¤·¤¤Ì¾Á°¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤¡§]
+ja,dsgw,232,[½¤Àµ]
+ja,dsgw,233,[%s= ¤¬ÉÔ­¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,234,[¥¦¥¤¥ó¥É¥¦¤òÊĤ¸¤ë¡£]
+ja,dsgw,235,[½¤Àµ ...]
+ja,dsgw,236,["%s=" ÉÔ­¤·¤Æ¤¤¤Þ¤¹¡£\n]
+ja,dsgw,237,["%s" ¤¬¥»¥Ã¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£\n]
+ja,dsgw,238,["%s" ¤Î½ñ¼°¤¬ÉÔÌÀ¤Ç¤¹¡£\n]
+ja,dsgw,239,[ºÆǧ¾Ú]
+ja,dsgw,240,[¥¦¥¤¥ó¥É¥¦¤òÊĤ¸¤ë]
+ja,dsgw,241,[¤è¤í¤·¤¤¤Ç¤¹¤«¡©]
+ja,dsgw,242,[width=400,height=130,resizable]
+ja,dsgw,243,[ OK ]
+ja,dsgw,244,[ OK ]
+ja,dsgw,245,[ ¥ê¥»¥Ã¥È ]
+ja,dsgw,246,[ ½ªÎ» ]
+ja,dsgw,247,[ ¥­¥ã¥ó¥»¥ë ]
+ja,dsgw,248,[Ê̤ΠIF ¤òȯ¸«(Æþ¤ì»Ò¤Î IF ¤Ï¥µ¥Ý¡¼¥È¤µ¤ìÄê¤Þ¤»¤ó)]
+ja,dsgw,249,[ELESE ¤ò¸«¤Ä¤±¤Þ¤·¤¿¤¬¡¢IF ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,250,[ELSE ¤ò¸«¤Ä¤±¤Þ¤·¤¿¤¬¡¢¸å¤Î ELSE ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£(¤â¤·¤¯¤Ï ENDIF)]
+ja,dsgw,251,[ELIF ¤ò¸«¤Ä¤±¤Þ¤·¤¿¤¬ IF ¤ò¸«¤Ä¤±¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,252,[ELIF ¤ò¸«¤Ä¤±¤Þ¤·¤¿¤¬¡¢¸å¤Î ELSE ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£(¤â¤·¤¯¤Ï ENDIF)]
+ja,dsgw,253,[ENDIF ¤ò¸«¤Ä¤±¤Þ¤·¤¿¤¬ IF ¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,254,[<BR><B>¥Æ¥ó¥×¥ì¡¼¥È ¥¨¥é¡¼¡§</B> %s<BR>\n]
+ja,dsgw,255,[ldap_init/lcache_init ¤¬ÀßÄê¥Õ¥¡¥¤¥ë¤òÆɤ߹þ¤àÁ°¤Ë¼Â¹Ô¤µ¤ì¤Þ¤·¤¿¡£]
+ja,dsgw,256,[¥¢¥É¥ß¥Ë¥¹¥È¥ì¡¼¥·¥ç¥ó ¥µ¡¼¥Ð¤Ï¼Â¹ÔÃæ¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,257,[¥Ñ¡¼¥ß¥Ã¥·¥ç¥ó¤ò½é´ü²½¤¹¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,258,[DN ¤Ë¥æ¡¼¥¶Ì¾¤¬¥Þ¥Ã¥×¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£(¥¢¥É¥ß¥ó ¥µ¡¼¥Ð¤Î¥¨¥é¡¼¤Ç¤¹¡£)]
+ja,dsgw,259,[¸½ºß¤Î¥æ¡¼¥¶Ì¾¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,260,[¸½ºß¤Î¥æ¡¼¥¶¥Ñ¥¹¥ï¡¼¥É¤òÆÀ¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,261,[¥¨¥é¡¼¡§ %s]
+ja,dsgw,262,[¥Î¡¼¥È¡§ ¥Ç¥£¥¹¥×¥ì¥¤ ¥Æ¥ó¥×¥ì¡¼¥È¤Ï¸ºß¤·¤Þ¤»¤ó¡£¥Ç¥Õ¥©¥ë¥ÈÃͤò»ÈÍѤ·¤Þ¤¹¡£]
+ja,dsgw,263,[¥æ¡¼¥¶ ID ¤¬ÉÔÀµ¤â¤·¤¯¤Ï LDAP ¤¬ NULL ¤òÊÖ¤·¤Þ¤·¤¿¡£]
+ja,dsgw,264,[¥æ¡¼¥¶ ID ¤Ë¥Þ¥Ã¥Á¤¹¤ë¤â¤Î¤¬¤¢¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,265,[¥æ¡¼¥¶ ID ¤¬£±¤Ä°Ê¾å³ºÅö¤·¤Þ¤¹¡£]
+ja,dsgw,266,[the entire directory]
+ja,dsgw,267,["includeset" ¤Ë¤Ï£²¤Ä¤ÎÃͤ¬É¬ÍפǤ¹¡£\n]
+ja,dsgw,268,[¥¨¥ó¥È¥ê¤Ë¤ÏÍ׵ᤵ¤ì¤¿Â°À­Ãͤ¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿]
+ja,dsgw,269,["NLS" »Ø¿Ë¤Î°ú¿ô¤¬·ç¤±¤Æ¤¤¤Þ¤¹\n]
+ja,dsgw,270,[NT¥æ¡¼¥¶ID¤ÎÃͤò»ØÄꤹ¤ëɬÍפ¬¤¢¤ê¤Þ¤¹\n]
+ja,dsgw,271,[»Ø¿ËÆâ¤ÎNT¥æ¡¼¥¶ID¤ÈNT¥É¥á¥¤¥óID¤ÎÁȹç¤ï¤»¤Ï¸ÇÍ­¤Î¤â¤Î¤Ç¤Ï¤¢¤ê¤Þ¤»¤ó\n]
+ja,dsgw,272,[NT¥æ¡¼¥¶ID¤ÈNT¥É¥á¥¤¥óID¤ÎξÊý¤ÎÃͤò»ØÄꤹ¤ëɬÍפ¬¤¢¤ê¤Þ¤¹\n]
+ja,dsgw,273,[NT¥æ¡¼¥¶IDÃͤÎŤµ¤Ï20ʸ»ú¤òĶ²á¤·¤Æ¤Ï¤Ê¤ê¤Þ¤»¤ó¡£\n]
+ja,dsgw,274,[¿·µ¬¥¨¥ó¥È¥ê¤Î̾Á°¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,275,[¿·µ¬¥¨¥ó¥È¥ê¤Î¾ì½ê¤òÁªÂò¤·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,276,[¿·µ¬¥¨¥ó¥È¥ê]
+ja,dsgw,277,[¤³¤Îµ¡Ç½¤ò»ÈÍѤ¹¤ë¤Ë¤Ï¡¢dsgw.conf¤ÇÄêµÁ¤µ¤ì¤¿dirmgr¤¬¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó]
+ja,dsgw,278,["vcard-property"¤Î»Ø¿Ë¤Ë¤Ï3¤Þ¤¿¤Ï4¤Ä¤Î°ú¿ô¤¬É¬ÍפǤ¹\n]
+ja,dsgw,279,[Vcard¥×¥í¥Ñ¥Æ¥£¹½Ê¸¤Ï"cis" ¤Þ¤¿¤Ï "mls"¤Ç¤Ê¤±¤ì¤Ð¤Ê¤ê¤Þ¤»¤ó\n]
+ja,dsgw,280,[¥¨¥ó¥È¥ê¤¬¸¡º÷¤µ¤ì¤Þ¤»¤ó¤Ç¤·¤¿\n%2$s]
+ja,dsgw,281,['%4$s'¤¬%2$s%3$s¡¢¥¨¥ó¥È¥ê¤Ï¸¡º÷¤µ¤ì¤Þ¤»¤ó¤Ç¤·¤¿\n]
+ja,dsgw,282,[¥¨¥ó¥È¥ê¤Ï¸¡º÷¤µ¤ì¤Þ¤»¤ó¤Ç¤·¤¿\n%2$s]
+ja,dsgw,283,['%4$s'¤¬%2$s%3$s¡¢¥¨¥ó¥È¥ê¤Ï¸¡º÷¤µ¤ì¤Þ¤»¤ó¤Ç¤·¤¿\n]
+ja,dsgw,284,[1¸Ä¤Î¥¨¥ó¥È¥ê¤¬¸¡º÷¤µ¤ì¤Þ¤·¤¿\n%2$s]
+ja,dsgw,285,['%4$s'¤¬%2$s%3$s¡¢1¸Ä¤Î¥¨¥ó¥È¥ê¤¬¸¡º÷¤µ¤ì¤Þ¤·¤¿\n]
+ja,dsgw,286,[1¸Ä¤Î¥¨¥ó¥È¥ê¤¬¸¡º÷¤µ¤ì¤Þ¤·¤¿\n%2$s]
+ja,dsgw,287,[%2$s¤¬'%4$s'%3$s¡¢1¸Ä¤Î¥¨¥ó¥È¥ê¤¬¸¡º÷¤µ¤ì¤Þ¤·¤¿\n]
+ja,dsgw,288,[%1$li¸Ä¤Î¥¨¥ó¥È¥ê¤¬¸¡º÷¤µ¤ì¤Þ¤·¤¿\n%2$s]
+ja,dsgw,289,['%4$s'¤¬%2$s%3$s¡¢%1$li¸Ä¤Î¥¨¥ó¥È¥ê¤¬¸¡º÷¤µ¤ì¤Þ¤·¤¿\n]
+ja,dsgw,290,[%1$li¸Ä¤Î¥¨¥ó¥È¥ê¤¬¸¡º÷¤µ¤ì¤Þ¤·¤¿\n%2$s]
+ja,dsgw,291,['%4$s'¤¬%2$s%3$s¡¢%1$li¸Ä¤Î¥¨¥ó¥È¥ê¤¬¸¡º÷¤µ¤ì¤Þ¤·¤¿\n]
+ja,dsgw,292,[LDAP¥Õ¥£¥ë¥¿]
+ja,dsgw,293,[ǧ¾Ú¤Ë»ÈÍѤ·¤¿¥¨¥ó¥È¥ê¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¤Ç¤·¤¿¡£¥¨¥ó¥È¥ê̾¤¬Êѹ¹¤µ¤ì¤¿¤«¡¢ºï½ü¤µ¤ì¤¿²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£¤â¤¦°ìÅÙǧ¾Ú¤ò¹Ô¤Ã¤Æ¤ß¤Æ¤¯¤À¤µ¤¤¡£]
+ja,dsgw,294,[¿·¤·¤¤¥Ñ¥¹¥ï¡¼¥É¤Î¹½Ê¸¤Ï̵¸ú¤Ç¤¹¡£\n]
+ja,dsgw,295,[¿·¤·¤¤¥Ñ¥¹¥ï¡¼¥É¤Ï¥Ñ¥¹¥ï¡¼¥ÉÍúÎò¤ÎÃæ¤Ë¤¢¤ê¤Þ¤¹¡£\n]
+ja,dsgw,296,[¥Ñ¥¹¥ï¡¼¥ÉºÆÆþÎϤÎÀ©¸Â²ó¿ô¤ò±Û¤¨¤Þ¤·¤¿¡£¥·¥¹¥Æ¥à ¥¢¥É¥ß¥Ë¥¹¥È¥ì¡¼¥¿¤ËÏ¢Íí¤·¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,297,[¥Ñ¥¹¥ï¡¼¥ÉºÆÆþÎϤÎÀ©¸Â²ó¿ô¤ò±Û¤¨¤Þ¤·¤¿¡£¤¢¤È¤Ç¤â¤¦°ìÅٹԤäƤ¯¤À¤µ¤¤¡£\n]
+ja,dsgw,298,[¤³¤Î¥Ñ¥¹¥ï¡¼¥É¤Ï´ü¸ÂÀÚ¤ì¤Ç¤¹¡£¥·¥¹¥Æ¥à ¥¢¥É¥ß¥Ë¥¹¥È¥ì¡¼¥¿¤ËÏ¢Íí¤·¤Æ¡¢¥Ñ¥¹¥ï¡¼¥É¤ò¥ê¥»¥Ã¥È¤·¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,299,[½¤Àµ¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,300,[Äɲ䷤Ƥ¤¤Þ¤¹¡£]
+ja,dsgw,301,[ºï½ü¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,302,[̾Á°¤òÊѹ¹¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,303,[¥ê¥¹¥È¤Ë̾Á°¤¬¤¢¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,304,[¥ê¥¹¥È¤Ë <B>1</B> ¤Ä¤Î̾Á°¤¬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,305,[¥ê¥¹¥È¤Ë <B>%s</B>¸Ä¤Î̾Á°¤¬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,306,[¥ê¥¹¥È\\n¤«¤é\\nºï½ü¤·¤Þ¤¹¤«¡© ̾Á°]
+ja,dsgw,307,[Êѹ¹¤òÇË´þ¤·¤Þ¤¹¤«¡©]
+ja,dsgw,308,[width=300,height=130,resizable]
+ja,dsgw,309,[Êѹ¹¤òÊݸ¤»¤º¤Ë³¹Ô¤·¤Þ¤¹¤«¡©<br>Êݸ¤µ¤ì¤Æ¤¤¤Ê¤¤Êѹ¹¤Ï¼º¤ï¤ì¤Þ¤¹¡£]
+ja,dsgw,310,[width=400,height=150,resizable]
+ja,dsgw,311,[·Ù¹ð]
+ja,dsgw,312,[³Îǧ]
+ja,dsgw,313,[ǧ¾Ú¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£\n]
+ja,dsgw,314,[ǧ¾Ú¤ËÀ®¸ù¤·¤Þ¤·¤¿¡£]
+ja,dsgw,315,[¥Ç¥£¥ì¥¯¥È¥ê¤Ë <B>%s</B> ¤È¤·¤Æǧ¾Ú¤µ¤ì¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,316,[¤¢¤Ê¤¿¤Îǧ¾Ú»ñ³Ê¾ÚÌÀ½ñ¤Ï %d ʬ¤Ç¼º¸ú¤·¤Þ¤¹¡£\n]
+ja,dsgw,317,[ǧ¾Ú¤Î¼º¸ú¸å¡¢¥Ç¥£¥ì¥¯¥È¥ê¤ËºÆÅÙǧ¾Ú¤ò¼õ¤±¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£\n]
+ja,dsgw,318,[<P>¤³¤Î¥¨¥ó¥È¥ê¤Î¥Ñ¥¹¥ï¡¼¥É¤Ï <B>%s</B> ¤Ç¼º¸ú¤·¤Þ¤¹¡£\n]
+ja,dsgw,319,[ǧ¾Ú¤Ë¼ºÇÔ¤·¤¿Íýͳ]
+ja,dsgw,320,[¥Ç¥£¥ì¥¯¥È¥ê¤Ë¸ºß¤·¤Ê¤¤¥¨¥ó¥È¥ê¤Îǧ¾Ú¤ò¼õ¤±¤è¤¦¤È¤·¤¿¤¿¤á¡¢Ç§¾Ú¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£\nǧ¾Ú¤¬¼õ¤±¤é¤ì¤ë¤Î¤Ï¡¢´û¸¤Î¥Ç¥£¥ì¥¯¥È¥ê ¥¨¥ó¥È¥ê¤À¤±¤Ç¤¹¡£\n]
+ja,dsgw,321,[¥Ñ¥¹¥ï¡¼¥É¤¬ÀßÄꤵ¤ì¤Æ¤¤¤Ê¤¤¥¨¥ó¥È¥ê¤Îǧ¾Ú¤ò¼õ¤±¤è¤¦¤È¤·¤¿¤¿¤á¡¢Ç§¾Ú¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£\nǧ¾Ú¤¬¼õ¤±¤é¤ì¤ë¤Î¤Ï¡¢¥Ç¥£¥ì¥¯¥È¥ê´ÉÍý¼Ô¤Ë¤è¤Ã¤Æ¥Ñ¥¹¥ï¡¼¥É¤¬ÀßÄꤵ¤ì¤Æ¤¤¤ë¥¨¥ó¥È¥ê¤À¤±¤Ç¤¹¡£\n]
+ja,dsgw,322,[ÆþÎϤ·¤¿¥Ñ¥¹¥ï¡¼¥É¤¬Àµ¤·¤¯¤Ê¤¤¤¿¤á¡¢Ç§¾Ú¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£\n[¤â¤¦°ìÅÙ]¤ò¥¯¥ê¥Ã¥¯¤·¤ÆºÆÅ٥ѥ¹¥ï¡¼¥É¤òÆþÎϤ·¤Æ¤¯¤À¤µ¤¤¡£\n¥¨¥ó¥È¥ê¤Î¥Ñ¥¹¥ï¡¼¥É¤ò˺¤ì¤¿¾ì¹ç¤Ï¡¢Directory Administrator¤ËÏ¢Íí¤·¡¢¥Ñ¥¹¥ï¡¼¥É¤òºÆÀßÄꤹ¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£\n]
+ja,dsgw,323,[ͽ´ü¤·¤Ê¤¤¥¨¥é¡¼: %s ¤¬È¯À¸¤·¤¿¤¿¤á¡¢Ç§¾Ú¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£\n]
+ja,dsgw,324,[ºÆÆþÎÏ]
+ja,dsgw,325,[³¹Ô¤¹¤ë¤Ë¤Ï¡¢¾åµ­¤Î¥ê¥¹¥È¤«¤é¥¿¥¹¥¯¤òÁªÂò¤·¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,326,[¥Ñ¥¹¥ï¡¼¥É½¤Àµ]
+ja,dsgw,327,[<H3>%s ¤Î¤¿¤á¤Ë¥Ñ¥¹¥ï¡¼¥É¼º¸ú</H3>\n]
+ja,dsgw,328,[¥Ç¥£¥ì¥¯¥È¥ê ¥µ¡¼¥Ð¤Î¥Ñ¥¹¥ï¡¼¥É¤¬¼º¸ú¤·¤Þ¤·¤¿¡£]
+ja,dsgw,329,[ ¤¹¤°¤Ë¥Ñ¥¹¥ï¡¼¥É¤òÊѹ¹¤·¤Æ¤¯¤À¤µ¤¤¡£\n]
+ja,dsgw,330,[¥Ñ¥¹¥ï¡¼¥É¤¬ÆþÎϤµ¤ì¤Æ¤¤¤Þ¤»¤ó¡£Ç§¾Ú¤ò¼õ¤±¤ë¤È¤­¤Ïɬ¤º¥Ñ¥¹¥ï¡¼¥É¤òÆþÎϤ·¡¢¥µ¡¼¥Ð¤ÇËܿͤǤ¢¤ë¤³¤È¤ò¾È¹ç¤Ç¤­¤ë¤è¤¦¤Ë¤¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,331,[¥µ¡¼¥Ð¤Ïǧ¾Ú»ñ³Ê¾ÚÌÀ½ñ¤òÀ¸À®¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£Ç§¾Ú¥Ç¡¼¥¿¥Ù¡¼¥¹¤ò³«¤¯¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,332,[¥µ¡¼¥Ð¤Ïǧ¾Ú»ñ³Ê¾ÚÌÀ½ñ¤òÀ¸À®¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£¥Ç¡¼¥¿¤òǧ¾Ú¥Ç¡¼¥¿¥Ù¡¼¥¹¤ËÄɲäǤ­¤Þ¤»¤ó¤Ç¤·¤¿¡£]
+ja,dsgw,333,[¼¡¤Ø]
+ja,dsgw,334,[¥¦¥£¥ó¥É¥¦¤òÊĤ¸¤ë]
+ja,dsgw,335,[À®¸ù]
+ja,dsgw,336,[ǧ¾Ú»ñ³Ê¾ÚÌÀ½ñ¤¬Ìµ¸ú¤Ë¤Ê¤ê¤Þ¤·¤¿¡£¸½ºßDirectory¤Ëǧ¾Ú¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£\n]
+ja,dsgw,337,[Á°¤Ø]
+ja,dsgw,338,[À®¸ù]
+ja,dsgw,339,[¥ª¥Ú¥ì¡¼¥·¥ç¥ó ¥¨¥é¡¼]
+ja,dsgw,340,[¥×¥í¥È¥³¥ë ¥¨¥é¡¼]
+ja,dsgw,341,[·Ù¹ð: ¥¿¥¤¥à¥¢¥¦¥È¤·¤Þ¤·¤¿¡£°ìÃפ¹¤ë¥¨¥ó¥È¥ê¤Î¤¦¤Á¡¢É½¼¨¤µ¤ì¤Æ¤¤¤Ê¤¤¤â¤Î¤â¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,342,[·Ù¹ð: ¥µ¥¤¥º¤Î¾å¸Â¤òĶ¤¨¤Þ¤·¤¿¡£°ìÃפ¹¤ë¥¨¥ó¥È¥ê¤Î¤¦¤Á¡¢É½¼¨¤µ¤ì¤Æ¤¤¤Ê¤¤¤â¤Î¤â¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,343,[false ¤òÈæ³Ó]
+ja,dsgw,344,[true ¤òÈæ³Ó]
+ja,dsgw,345,[¸·Ì©¤Êǧ¾Ú¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,346,[¸·Ì©¤Êǧ¾Ú¤¬É¬ÍפǤ¹¡£]
+ja,dsgw,347,[·Ù¹ð: °ìÉô¤Î¥Ç¥£¥ì¥¯¥È¥ê ¥µ¡¼¥Ð¤ËÀܳ¤Ç¤­¤Þ¤»¤ó¤Ç¤·¤¿¡£°ìÃפ¹¤ë¥¨¥ó¥È¥ê¤Î¤¦¤Á¡¢É½¼¨¤µ¤ì¤Æ¤¤¤Ê¤¤¤â¤Î¤â¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,348,[¥ì¥Õ¥§¥é¥ë¤ò¼õ¿®¤·¤Þ¤·¤¿¡£]
+ja,dsgw,349,[´ÉÍý¤ÎÈϰϤòĶ¤¨¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,350,[½ÅÂç¤Ê³ÈÄ¥¤¬ÍøÍѤǤ­¤Þ¤»¤ó¡£]
+ja,dsgw,351,[µ¡Ì©À­¤¬É¬ÍפǤ¹¡£]
+ja,dsgw,352,[SASL ¥Ð¥¤¥ó¥ÉÃæ¤Ç¤¹¡£]
+ja,dsgw,353,[¤½¤Î¤è¤¦¤Ê°À­¤Ï¤¢¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,354,[°À­¤Î¼ïÎबÄêµÁ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,355,[¥Þ¥Ã¥Á¥ó¥°¤¬ÉÔŬÀڤǤ¹¡£]
+ja,dsgw,356,[À©Ìó°ãÈ¿¤Ç¤¹¡£]
+ja,dsgw,357,[¥¿¥¤¥×¤Þ¤¿¤ÏÃͤ¬Â¸ºß¤·¤Þ¤¹¡£]
+ja,dsgw,358,[¹½Ê¸¤Ë¸í¤ê¤¬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,359,[¤½¤Î¤è¤¦¤Ê¥ª¥Ö¥¸¥§¥¯¥È¤Ï¤¢¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,360,[¥¨¥¤¥ê¥¢¥¹¤ËÌäÂ꤬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,361,[DN ¤Î¹½Ê¸¤Ë¸í¤ê¤¬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,362,[¥ª¥Ö¥¸¥§¥¯¥È¤ÏÍդǤ¹¡£]
+ja,dsgw,363,[¥¨¥¤¥ê¥¢¥¹ ¥Ç¥ê¥Õ¥¡¥ì¥ó¥¹¤ËÌäÂ꤬¤¢¤ê¤Þ¤¹¡£]
+ja,dsgw,364,[ǧ¾Ú¤¬ÉÔŬÅö¤Ç¤¹¡£]
+ja,dsgw,365,[¾ÚÌÀ½ñ¤¬Ìµ¸ú¤Ç¤¹¡£]
+ja,dsgw,366,[¥¢¥¯¥»¥¹¤¬ÉÔŬÀڤǤ¹¡£]
+ja,dsgw,367,[DSA ¤¬¥Ó¥¸¡¼¾õÂ֤Ǥ¹¡£]
+ja,dsgw,368,[DSA ¤¬ÍøÍѤǤ­¤Þ¤»¤ó¡£]
+ja,dsgw,369,[DSA ¤¬¼Â¹Ô¤µ¤ì¤Þ¤»¤ó¡£]
+ja,dsgw,370,[¥ë¡¼¥×¤¬¸¡½Ð¤µ¤ì¤Þ¤·¤¿¡£]
+ja,dsgw,371,[̾Á°ÉÕ¤±°ãÈ¿]
+ja,dsgw,372,[¥ª¥Ö¥¸¥§¥¯¥È ¥¯¥é¥¹°ãÈ¿]
+ja,dsgw,373,[ÍեΡ¼¥É°Ê³°¤ÇÁàºî¤ò¹Ô¤¦¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,374,[RDN ¤ÇÁàºî¤ò¹Ô¤¦¤³¤È¤Ï¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,375,[´û¤Ë¸ºß¤·¤Æ¤¤¤Þ¤¹¡£]
+ja,dsgw,376,[¥ª¥Ö¥¸¥§¥¯¥È ¥¯¥é¥¹¤òÊѹ¹¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,377,[·ë²Ì¤¬Â礭¤¹¤®¤Þ¤¹¡£]
+ja,dsgw,378,[Ê£¿ô¤Î¥µ¡¼¥Ð¤Ë±Æ¶Á¤·¤Þ¤¹¡£]
+ja,dsgw,379,[¸¶°øÉÔÌÀ¤Î¥¨¥é¡¼]
+ja,dsgw,380,[LDAP ¥µ¡¼¥Ð¤ËÀܳ¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,381,[¥í¡¼¥«¥ë ¥¨¥é¡¼]
+ja,dsgw,382,[¥¨¥ó¥³¡¼¥É ¥¨¥é¡¼]
+ja,dsgw,383,[¥Ç¥³¡¼¥É ¥¨¥é¡¼]
+ja,dsgw,384,[¥¿¥¤¥à¥¢¥¦¥È]
+ja,dsgw,385,[ǧ¾ÚÊýË¡¤¬ÉÔÌÀ¤Ç¤¹¡£]
+ja,dsgw,386,[¸¡º÷¥Õ¥£¥ë¥¿¤¬ÉÔÀµ¤Ç¤¹¡£]
+ja,dsgw,387,[¥æ¡¼¥¶¤¬Áàºî¤ò¥­¥ã¥ó¥»¥ë¤·¤Þ¤·¤¿¡£]
+ja,dsgw,388,[LDAP ¥ë¡¼¥Á¥ó¤ËÂФ¹¤ë¥Ñ¥é¥á¡¼¥¿¤¬ÉÔÀµ¤Ç¤¹¡£]
+ja,dsgw,389,[¥á¥â¥êÉÔ­¤Ç¤¹¡£]
+ja,dsgw,390,[LDAP ¥µ¡¼¥Ð¤ËÀܳ¤Ç¤­¤Þ¤»¤ó¡£]
+ja,dsgw,391,[¤³¤Î¥Ð¡¼¥¸¥ç¥ó¤Î LDAP ¥×¥í¥È¥³¥ë¤Ç¤Ï¥µ¥Ý¡¼¥È¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,dsgw,392,[Í׵ᤵ¤ì¤¿ LDAP ¥³¥ó¥È¥í¡¼¥ë¤¬¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£]
+ja,dsgw,393,[·ë²Ì¤¬ÊÖ¤µ¤ì¤Þ¤»¤ó¡£]
+ja,dsgw,394,[¤µ¤é¤Ë·ë²Ì¤¬ÊÖ¤µ¤ì¤Þ¤¹¡£]
+ja,dsgw,395,[¥¯¥é¥¤¥¢¥ó¥È¤¬¥ë¡¼¥×¤ò¸¡½Ð¤·¤Þ¤·¤¿¡£]
+ja,dsgw,396,[¥ì¥Õ¥§¥é¥ë ¥Û¥Ã¥× ¥ê¥ß¥Ã¥È¤òĶ²á¤·¤Þ¤·¤¿¡£]
+ja,frame,-1,[$DBT: frame in DB file v1 $]
+ja,frame,1,[<TITLE>¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£</TITLE><H1>¸«¤Ä¤«¤ê¤Þ¤»¤ó¡£</H1> ¥ê¥¯¥¨¥¹¥È¤µ¤ì¤¿¥ª¥Ö¥¸¥§¥¯¥È¤ò¸«¤Ä¤±¤ë¤³¤È¤¬¤Ç¤­¤Þ¤»¤ó¡£¥ê¥ó¥¯¤¬ÀÚ¤ì¤Æ¤¤¤ë¡¢¥ê¥¯¥¨¥¹¥È¤¬ÉÔÀµ³Î¡¢¥¢¥¯¥»¥¹¸¢¤¬Í¿¤¨¤é¤ì¤Æ¤¤¤Ê¤¤Åù¤Î²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£ ]
+ja,frame,2,[<A HREF="%s">»²¾È¤·¤Æ¤¤¤ë¥Ú¡¼¥¸</A>¤Î¾ðÊó¤ò¥µ¥¤¥È´ÉÍý¼Ô¤ËÃΤ餻¤Æ¤¯¤À¤µ¤¤¡£]
+ja,frame,3,[¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤¬Á÷¤Ã¤¿¥ê¥¯¥¨¥¹¥È¤ò¥×¥í¥¯¥· ¥µ¡¼¥Ð¤¬Íý²ò¤Ç¤­¤Þ¤»¤ó¡£]
+ja,frame,4,[ŬÀÚ¤Êǧ¾Ú¤Ï¥×¥í¥¯¥·¤¬´ÉÍý¤Î¤¿¤á¤ËɬÍפǤ¹¡£\n¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤Îǧ¾Ú¤Ï¼ºÇÔ¤·¤Þ¤·¤¿¡£]
+ja,frame,5,[¥æ¡¼¥¶Ì¾¤Îǧ¾Ú¤Ë¤Ï¥×¥í¥¯¥·¤òÍøÍѤ¹¤ëɬÍפ¬¤¢¤ê¤Þ¤¹¡£\n¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤Ï¥×¥í¥¯¥·¤Ë¤è¤ëǧ¾Ú¤Ë¼ºÇÔ¤·¤Þ¤·¤¿¡£]
+ja,frame,6,[¥ê¥¯¥¨¥¹¥È¤µ¤ì¤¿¥ª¥Ö¥¸¥§¥¯¥È¤ËÂФ¹¤ë¥¢¥¯¥»¥¹¤Ï\n¥×¥í¥¯¥·¤ÎÀßÄê¾åµö¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,frame,7,[¥×¥í¥¯¥·¤Ï¤¢¤Ê¤¿¤Î¥ê¥¯¥¨¥¹¥È¤ò¼Â¹Ô¤¹¤ëºÝ¤Ë¥¨¥é¡¼¤òȯÀ¸¤·¤Þ¤·¤¿¡£\nÀßÄ꤬¸í¤Ã¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£\n¥×¥í¥¯¥· ¥¨¥é¡¼ ¥í¥°¤Î¥á¥Ã¥»¡¼¥¸¤ò»²¾È¤¹¤ë¤è¤¦´ÉÍý¼Ô¤Ë°ÍÍꤷ¤Æ¤¯¤À¤µ¤¤¡£]
+ja,frame,8,[¥ê¥¯¥¨¥¹¥È¤µ¤ì¤¿ÆâÍÆ¤Ï¥×¥í¥¯¥·¤Ë¼ÂÁõ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,frame,9,[¥×¥í¥¯¥·¾å¤Ç¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£]
+ja,frame,10,[¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤¬Á÷¿®¤·¤¿¥ê¥¯¥¨¥¹¥È¤Ï¡¢¥µ¡¼¥Ð¤ËÍý²ò¤¹¤ë¤³¤È¤¬¤Ç¤­¤Ê¤¤¤â¤Î¤Ç¤¹¡£]
+ja,frame,11,[ŬÀÚ¤Êǧ¾Ú¤Ï¤³¤Î¥¨¥ê¥¢¤Î´ÉÍý¤Î¤¿¤á¤ËɬÍפǤ¹¡£\n¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤Îǧ¾Ú¤Ï¼ºÇÔ¤·¤Þ¤·¤¿¡£]
+ja,frame,12,[¤¢¤Ê¤¿¤Î¥¯¥é¥¤¥¢¥ó¥È¤Ï¥ª¥Ö¥¸¥§¥¯¥È¤ËÂФ¹¤ë¥¢¥¯¥»¥¹¤òµö²Ä¤µ¤ì¤Æ¤¤¤Þ¤»¤ó¡£]
+ja,frame,13,[¤³¤Î¥µ¡¼¥Ð¤Ï¥ê¥¯¥¨¥¹¥È¤Î½èÍýÃæ¤Ë¥¨¥é¡¼¤ËÁø¶ø¤·¤Þ¤·¤¿¡£¸í¤Ã¤¿ÀßÄ꤬¤Ê¤µ¤ì¤Æ¤¤¤ë²ÄǽÀ­¤¬¤¢¤ê¤Þ¤¹¡£¥µ¡¼¥Ð¤Î¥¨¥é¡¼ ¥í¥°¤ò»²¾È¤¹¤ë¤è¤¦´ÉÍý¼Ô¤ËÏ¢Íí¤·¤Æ¤¯¤À¤µ¤¤¡£]
+ja,frame,14,[¥ê¥¯¥¨¥¹¥È¤µ¤ì¤¿ÆâÍƤϥµ¡¼¥Ð¤Ë¼ÂÁõ¤µ¤ì¤Æ¤¤¤Þ¤»¤ó]
+ja,frame,15,[¥¨¥é¡¼¤¬È¯À¸¤·¤Þ¤·¤¿¡£]
+ja,frame,16,[¤¢¤Ê¤¿¤Î¥Ö¥é¥¦¥¶¤¬¥µ¡¼¥Ð¤ËÁ÷¤Ã¤¿¥ê¥¯¥¨¥¹¥È¤Ï¥µ¡¼¥Ð¤¬Íý²ò¤Ç¤­¤Ê¤¤¥ê¥¯¥¨¥¹¥È¤Ç¤¹¡£]
+ja,frame,17,[<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>\n¤³¤Î¥É¥­¥å¥á¥ó¥È¤Ï¿·¤·¤¤¾ì½ê¤Ë°ÜÆ°¤·¤Þ¤·¤¿¡£ <a href="%s"></a>. ¥É¥­¥å¥á¥ó¥È¤È¥Û¥Ã¥È¥ê¥¹¥È¤Î¹¹¿·¤ò¤·¤Æ¤¯¤À¤µ¤¤¡£</BODY></HTML>]
+ja,frame,18,[<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html;charset=euc-jp"><META HTTP-EQUIV="Content-Language" CONTENT="ja"><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>]
+ja,frame,19,[process-uri-objects]
+ja,frame,20,[cannot find template %s]
+ja,frame,21,[process-uri-objects]
+ja,frame,22,[no partial path after object processing]
+ja,frame,23,[find-service]
+ja,frame,24,[invalid shexp %s]
+ja,frame,25,[find-service]
+ja,frame,26,[invalid shexp %s]
+ja,frame,27,[handle-processed]
+ja,frame,28,[no way to service request for %s]
+ja,frame,29,[finish-socks-request]
+ja,frame,30,[close failed (%s), csd=%d]
+ja,frame,31,[This beta software has expired.\n]
+ja,frame,32,[mr_accept(%d)]
+ja,frame,33,[Error issuing read on accept socket]
+ja,frame,34,[acb_accept_connection(%d)]
+ja,frame,35,[Error getting accept socket (%d)]
+ja,frame,36,[Error in accept! (%d, %s)]
+ja,frame,37,[Error creating new accept request]
+ja,frame,38,[accepted connection: %d (NSPR %d)]
+ja,frame,39,[Error creating new session structure]
+ja,frame,40,[accel_read_request()]
+ja,frame,41,[Error allocating request read buffer]
+ja,frame,42,[Error issuing async read request]
+ja,frame,43,[acb_read_request(%d, bytes %d)]
+ja,frame,44,[acb_read_req(1 session = %d)]
+ja,frame,45,[Error reading request (%d, %s)]
+ja,frame,46,[Client aborted connection]
+ja,frame,47,[Error reading request]
+ja,frame,48,[Error creating new request]
+ja,frame,49,[error occurred, closing %d, io was for %d]
+ja,frame,50,[accel_async_scan_headers()]
+ja,frame,51,[out of memory: accel_async_scan_headers]
+ja,frame,52,[out of memory: accel_async_scan_headers]
+ja,frame,53,[Error during async read (%d, %s)]
+ja,frame,54,[scan-headers reports: line too long]
+ja,frame,55,[scan-headers reports: too many headers]
+ja,frame,56,[Error reading headers]
+ja,frame,57,[scan-headers reports: header missing terminator (an empty line)]
+ja,frame,58,[scan-headers reports: header was empty]
+ja,frame,59,[̾Á°¤ËÃͤ¬¤¢¤ê¤Þ¤»¤ó¡§ "%s" ¹Ô]
+ja,frame,60,[accel_send_plain_file()]
+ja,frame,61,[accel_send_plain_file() - found request %d]
+ja,frame,62,[Parse headers lost the URI!]
+ja,frame,63,[accel_send_plain_file() - found uri %s]
+ja,frame,64,[accel_send_plain_file() - found in cache?]
+ja,frame,65,[malloc died!]
+ja,frame,66,[Error writing back file\n]
+ja,frame,67,[acb_send_plain_file(%d)]
+ja,frame,68,[Error writing in acb_send_plain_file (%d, %s)]
+ja,frame,69,[acb_close_connection(%d)]
+ja,frame,70,[Errored IO in acb_close_connection (%d, %s)]
+ja,frame,71,[Unable to close socket %d]
+ja,frame,72,[accel-cache-insert: Error allocating entry]
+ja,frame,73,[cache-init: server cache disabled]
+ja,frame,74,[accel_file_cache: Error initializing file cache]
+ja,frame,75,[accel_file_cache: Error creating cache]
+ja,frame,76,[accel_file_cache_init: CacheHashSize < %d, using %d]
+ja,frame,77,[accel_file_cache_init: CacheHashSize > %d, using %d]
+ja,frame,78,[accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d]
+ja,frame,79,[accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d]
+ja,frame,80,[accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d]
+ja,frame,81,[accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d]
+ja,frame,82,[accel_file_cache: Error initializing file cache]
+ja,frame,83,[file-cache: enabled = %s ]
+ja,frame,84,[on]
+ja,frame,85,[off]
+ja,frame,86,[file-cache: MaxNumberOfCachedFiles %d (0x%x)]
+ja,frame,87,[file-cache: CacheHashSize %d (0x%x)]
+ja,frame,88,[file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)]
+ja,frame,89,[accel-cache-insert: Error allocating entry]
+ja,frame,90,[file-cache-cleanup: munmap failed (%s)]
+ja,frame,91,[file-cache-cleanup: found mmapped file \non system without mmap]
+ja,frame,92,[file_cache_init: MaxTotalCachedFileSize < %d, using %d]
+ja,frame,93,[file_cache_init: MaxTotalCachedFileSize > %d, using %d]
+ja,frame,94,[file cache using mmap flags 0x%x]
+ja,frame,95,[file cache using mmap prots 0x%x]
+ja,frame,96,[file-cache-init: could not create lock]
+ja,frame,97,[file-cache: unable to create temporary directory %s.\n]
+ja,frame,98,[file-cache: unable to create temporary directory %s.\n]
+ja,frame,99,[file-cache: GetTempPath() Cannot find temp directory to store file!]
+ja,frame,100,[file-cache-init: set max cached file size to %d]
+ja,frame,101,[file-cache-init: could not create lock]
+ja,frame,102,[file_cache_destroy()]
+ja,frame,103,[file-cache: Unable to get temp file name. Error %s]
+ja,frame,104,[file-cache: Unable to get temp file name. Error %s]
+ja,frame,105,[file-cache-insert: Error allocating entry]
+ja,frame,106,[file-cache-create: Error opening file %s (%s)]
+ja,frame,107,[file-cache-create: Error stat()ing file %s (%s)]
+ja,frame,108,[file-cache-create: Error mmap()ing file %s (%s)]
+ja,frame,109,[file-cache-create: malloc failure]
+ja,frame,110,[file-cache-create: error case failed to munmap(%d, %d) (%s)]
+ja,frame,111,[file-cache-valid: cannot stat %s]
+ja,frame,112,[dir change: invalidating %s (%d)]
+ja,frame,113,[file-cache: asynchronous file change notification failed.]
+ja,frame,114,[dir change: offset %d, action %d, len %d, name %s]
+ja,frame,115,[unable to check async file status]
+ja,frame,116,[ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s]
+ja,frame,117,[file-cache-add-watch failure- unable to open directory %s. Error %s]
+ja,frame,118,[ReadDirectoryChangesW failure- unable to start watching %s. Error %s]
+ja,frame,119,[func_exec]
+ja,frame,120,[no handler function given for directive]
+ja,frame,121,[func_exec]
+ja,frame,122,[cannot find function named %s]
+ja,frame,123,[handle-request]
+ja,frame,124,[method without URI]
+ja,frame,125,[http-parse-request]
+ja,frame,126,[while scanning HTTP headers, %s]
+ja,frame,127,[handle-request]
+ja,frame,128,[read from %s failed, error is %s]
+ja,frame,129,[handle-request]
+ja,frame,130,[request too long]
+ja,frame,131,[start-http-response]
+ja,frame,132,[write failed (%s)]
+ja,frame,133,[start-http-response]
+ja,frame,134,[write failed (%s)]
+ja,frame,135,[http-status]
+ja,frame,136,[%d is not a valid HTTP status code]
+ja,frame,137,[finish-request]
+ja,frame,138,[close failed (%s)]
+ja,frame,139,[Unable to close socket for writing]
+ja,frame,140,[os has %d objects]
+ja,frame,141,[obj %d has no hash table at %d]
+ja,frame,142,[obj %d has no param]
+ja,frame,143,[obj %d name %s value %s]
+ja,frame,144,[.....directives %d.......]
+ja,frame,145,[.....directive %d]
+ja,frame,146,[.......instance %d]
+ja,frame,147,[...........param name %s value %s]
+ja,frame,148,[ClearConfigurationParameters:RegCreateKey %s]
+ja,frame,149,[ClearConfigurationParameters:RegEnumKey %s failed]
+ja,frame,150,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+ja,frame,151,[obj.conf line %d: error in filter file "%s" at line %d: %s]
+ja,frame,152,[Unable to allocate Subject property list.\n]
+ja,frame,153,[Unable to set session ptr in Subject property list - error=%d\n]
+ja,frame,154,[Unable to set request ptr in Subject property list - error=%d\n]
+ja,frame,155,[file-cache-valid: cannot stat %s]
+ja,frame,156,[file-cache-create: Error stat()ing file %s (%s)]
+ja,httpdaemon,-1,[$DBT: httpdaemon in DB file v1 $]
+ja,httpdaemon,1,[Error in ConvertThreadToFiber]
+ja,httpdaemon,2,[Error in ConvertThreadToFiber]
+ja,httpdaemon,3,[Error in md_start_system]
+ja,httpdaemon,4,[Error in CreateFiber - idlefiber]
+ja,httpdaemon,5,[Error in GetQueuedCompletionStatus]
+ja,httpdaemon,6,[Error creating completion port]
+ja,httpdaemon,7,[Could not SetHandleNonInheritable (%s)]
+ja,httpdaemon,8,[Error accept/read new conn]
+ja,httpdaemon,9,[Error in Respond()]
+ja,httpdaemon,10,[Error in RespondCompleted()]
+ja,httpdaemon,11,[daemon: unable to fork new process (%s)\n]
+ja,httpdaemon,12,[daemon: setsid failed (%s)\n]
+ja,httpdaemon,13,[daemon: can't log pid to %s (%s)\n]
+ja,httpdaemon,14,[warning: could not set group id to %d (%s)\n]
+ja,httpdaemon,15,[warning: could not set user id to %d (%s)\n]
+ja,httpdaemon,16,[warning: daemon is running as super-user\n]
+ja,httpdaemon,17,[could not determine current user name\n]
+ja,httpdaemon,18,[error: chroot to %s failed (%s)\n]
+ja,httpdaemon,19,[WARNING! netscape executable and library have different versions.\n]
+ja,httpdaemon,20,[startup: listening to %s://%s, port %d as %s\n]
+ja,httpdaemon,21,[startup: listening to %s://%s, port %d as %s\n]
+ja,httpdaemon,22,[seminit failed (%s)\n]
+ja,httpdaemon,23,[Using single threaded accepts.]
+ja,httpdaemon,24,[Using multi threaded accepts.]
+ja,httpdaemon,25,[Using partial single threaded accepts.]
+ja,httpdaemon,26,[This machine has %d processors.]
+ja,httpdaemon,27,[Error calling thr_seconcurrency(%d)- (%s)]
+ja,httpdaemon,28,[Set conncurrency to %d.]
+ja,httpdaemon,29,[can't fork new process (%s)]
+ja,httpdaemon,30,[This beta software has expired.\n]
+ja,httpdaemon,31,[can't create IPC pipe (%s)]
+ja,httpdaemon,32,[write to wakeup pipe failed (%s)]
+ja,httpdaemon,33,[select thread miss]
+ja,httpdaemon,34,[startup failure: could not bind to port %d (%s)\n]
+ja,httpdaemon,35,[startup failure: could not bind to port %d, IP address %s (%s)\n]
+ja,libaccess,-1,[$DBT: libaccess in DB file v1 $]
+ja,libaccess,1,[basic-ncsa]
+ja,libaccess,2,[cannot open database %s]
+ja,libaccess,3,[basic-ncsa]
+ja,libaccess,4,[user %s password did not match database %s]
+ja,libaccess,5,[basic-ncsa]
+ja,libaccess,6,[cannot open connection to LDAP server on %s:%d]
+ja,libaccess,7,[basic-ncsa]
+ja,libaccess,8,[user %s password did not match LDAP on %s:%d]
+ja,libaccess,9,[acl-state]
+ja,libaccess,10,[missing realm]
+ja,libaccess,11,[Unable to allocate ACL List Hash\n]
+ja,libaccess,12,[ACLEvalBuildContext unable to PERM_MALLOC cache structure\n]
+ja,libaccess,13,[ACLEvalBuildContext unable to create hash table\n]
+ja,libaccess,14,[ACLEvalBuildContext unable to allocate ACE Entry\n]
+ja,libaccess,15,[ACLEvalBuildContext unable to allocate ACE entry\n]
+ja,libaccess,16,[ACLEvalBuildContext unable to allocate Boundary Entry\n]
+ja,libaccess,17,[ACLEvalBuildContext failed.\n]
+ja,libaccess,18,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n]
+ja,libaccess,19,[LASDnsBuild unable to allocate hash table header\n]
+ja,libaccess,20,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,21,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,22,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,23,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,24,[LASDnsBuild unable to add key %s\n]
+ja,libaccess,25,[LAS DNS build received request for attribute %s\n]
+ja,libaccess,26,[LASDnsEval - illegal comparator %s\n]
+ja,libaccess,27,[LASDnsEval unable to allocate Context struct\n\n]
+ja,libaccess,28,[LASDnsEval unable to get session address %d\n]
+ja,libaccess,29,[LASDnsEval unable to get DNS - error=%s\n]
+ja,libaccess,30,[LAS Group Eval received request for attribute %s\n]
+ja,libaccess,31,[LASGroupEval - illegal comparator %s\n]
+ja,libaccess,32,[LASGroupEval - ran out of memory\n]
+ja,libaccess,33,[LASGroupEval unable to get session address %d\n]
+ja,libaccess,34,[LASGroupEval unable to get session address %d\n]
+ja,libaccess,35,[LASGroupEval - couldn't locate getter for auth-user\n]
+ja,libaccess,36,[LASGroupEval - Attribute getter for auth-user failed\n]
+ja,libaccess,37,[LASGroupEval - Attribute getter didn't set auth-user\n]
+ja,libaccess,38,[Check group membership of user "%s" for group "%s"\n]
+ja,libaccess,39,[LDAPU_SUCCESS for group "%s"\n]
+ja,libaccess,40,[LDAPU_FAILED for group "%s"\n]
+ja,libaccess,41,[LAS_EVAL_FALSE\n]
+ja,libaccess,42,[LAS_EVAL_TRUE\n]
+ja,libaccess,43,[LASIpTreeAlloc - no memory\n]
+ja,libaccess,44,[IP LAS unable to allocate tree node\n]
+ja,libaccess,45,[IP LAS unable to allocate tree node\n]
+ja,libaccess,46,[LAS IP build received request for attribute %s\n]
+ja,libaccess,47,[LASIpEval - illegal comparator %s\n]
+ja,libaccess,48,[LASIpEval unable to get session address - error=%s\n]
+ja,libaccess,49,[LASIpEval unable to allocate Context struct\n\n]
+ja,libaccess,50,[LASIpEval - reach 32 bits without conclusion value=%s]
+ja,libaccess,51,[LAS Program Eval received request for attribute %s\n]
+ja,libaccess,52,[LASProgramEval - illegal comparator %s\n]
+ja,libaccess,53,[LASProgram unable to get session address %d\n]
+ja,libaccess,54,[bin]
+ja,libaccess,55,[LASProgramEval: request not of type admin or bin, passing.\n]
+ja,libaccess,56,[LASProgramEval: check if program %s matches pattern %s.\n]
+ja,libaccess,57,[LASProgramEval: Invalid wildcard expression %s.\n]
+ja,libaccess,58,[LAS_EVAL_FALSE\n]
+ja,libaccess,59,[LAS_EVAL_TRUE\n]
+ja,libaccess,60,[Unexpected attribute in dayOfWeek - %s\n]
+ja,libaccess,61,[Illegal comparator for dayOfWeek - %s\n]
+ja,libaccess,62,[Unexpected attribute in timeOfDay - %s\n]
+ja,libaccess,63,[LAS User Eval received request for attribute %s\n]
+ja,libaccess,64,[LASUserEval - illegal comparator %s\n]
+ja,libaccess,65,[LASUserEval - ran out of memory\n]
+ja,libaccess,66,[LASUserEval unable to get session address %d\n]
+ja,libaccess,67,[LASUserEval unable to get session address %d\n]
+ja,libaccess,68,[LASGroupEval - couldn't locate getter for auth-user\n]
+ja,libaccess,69,[LASGroupEval - Attribute getter for auth-user failed\n]
+ja,libaccess,70,[LASGroupEval - Attribute getter didn't set auth-user\n]
+ja,libaccess,71,[Check if uid == user (i.e. check "%s" == "%s)"\n]
+ja,libaccess,72,[SUCCESS for user "%s"\n]
+ja,libaccess,73,[FAILED for user "%s"\n]
+ja,libaccess,74,[LAS_EVAL_FALSE\n]
+ja,libaccess,75,[LAS_EVAL_TRUE\n]
+ja,libaccess,76,[]
+ja,libaccess,77,[LASProgram unable to get request address - error=%s]
+ja,libaccess,78,[LASProgram rejecting request for program %s from pattern %s]
+ja,libaccess,79,[ACL_CacheFlush: unable to parse file "%s"\n]
+ja,libaccess,80,[ACL_CacheFlush: unable to concatenate ACL list "%s"\n]
+ja,libaccess,81,[ACL_CacheFlush: unable to open and process the magnus file "%s"\n]
+ja,libaccess,82,[Illegal comparator for timeOfDay - %s\n]
+ja,libaccess,83,[ACL_EvalBuildContext unable to create hash table\n]
+ja,libaccess,84,[ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n]
+ja,libaccess,85,[ACL_EvalBuildContext unable to allocate ACE entry\n]
+ja,libaccess,86,[ACL_EvalBuildContext unable to allocate auth pointer array\n]
+ja,libaccess,87,[ACL_EvalBuildContext unable to allocate auth plist\n]
+ja,libaccess,88,[ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n]
+ja,libaccess,89,[ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n]
+ja,libaccess,90,[ACL_ModuleRegister: module name is missing\n]
+ja,libaccess,91,[ACL_ModuleRegister: call to module init function returned a failed status\n]
+ja,libaccess,92,[ACL_GetAttribute: couldn't determine method for %s\n]
+ja,libaccess,93,[ACL_GetAttribute: couldn't locate getter for %s]
+ja,libaccess,94,[ACL_GetAttribute: attr getter failed to get %s]
+ja,libaccess,95,[ACL_GetAttribute: attr getter failed to get %s]
+ja,libaccess,96,[ACL_GetAttribute: All attribute getters declined for attr %s]
+ja,libaccess,97,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+ja,libaccess,98,[ACL_DatabaseRegister: database name is missing]
+ja,libaccess,99,[Error reading the DB Map File: %s. Reason: %s]
+ja,libaccess,100,[URL is missing for database %s]
+ja,libaccess,101,[Invalid property value pair for database %s]
+ja,libaccess,102,["default" database must be an LDAP database]
+ja,libaccess,103,[Multiple "default" databases are being registered]
+ja,libaccess,104,["default" LDAP database must be registered]
+ja,libaccess,105,[LASGroupEval unable to get database name - error= %s]
+ja,libaccess,106,[received invalid program expression %s]
+ja,libaccess,107,[parse_ldap_url: database url is missing]
+ja,libaccess,108,[parse_ldap_url: database name is missing]
+ja,libaccess,109,[parse_ldap_url: error in parsing ldap url. Reason: %s]
+ja,libaccess,110,[ldap password check: unable to get database name - error=%s]
+ja,libaccess,111,[ldap password check: unable to get parsed database %s]
+ja,libaccess,112,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+ja,libaccess,113,[ldap password check: LDAP error: "%s"]
+ja,libaccess,114,[get_user_ismember_ldap unable to get database name - error=%s]
+ja,libaccess,115,[get_user_ismember_ldap unable to get parsed database %s]
+ja,libaccess,116,[ldap password check: couldn't initialize connection to LDAP. Reason: %s]
+ja,libaccess,117,[get_user_ismember_ldap: group %s does not exist]
+ja,libaccess,118,[get_user_ismember_ldap: LDAP error: "%s"]
+ja,libaccess,119,[ACL_LDAPDatabaseHandle: %s is not a registered database]
+ja,libaccess,120,[ACL_LDAPDatabaseHandle: %s is not an LDAP database]
+ja,libaccess,121,[ACL_LDAPDatabaseHandle: out of memory]
+ja,libaccess,122,[ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s]
+ja,libaccess,123,[ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s]
+ja,libaccess,124,[insufficient dynamic memory]
+ja,libaccess,125,[error opening file, %s: %s]
+ja,libaccess,126,[duplicate definition of %s]
+ja,libaccess,127,[file %s, line %s: duplicate definition of %s]
+ja,libaccess,128,[file %s, line %s: syntax error]
+ja,libaccess,129,[file %s, line %s: %s is undefined]
+ja,libaccess,130,[in acl %s, %s %s is undefined]
+ja,libaccess,131,[database %s: error accessing %s]
+ja,libaccess,132,[%s]
+ja,libaccess,133,[file %s, line %s: invalid syntax]
+ja,libaccess,134,[file %s, line %s: syntax error at "%s"]
+ja,libaccess,135,[realm %s is not defined]
+ja,libaccess,136,[error code = %d]
+ja,libaccess,137,[internal ACL error]
+ja,libaccess,138,[invalid argument]
+ja,libaccess,139,[ACL_DatabaseRegister: dbtype for database "%s" is not defined yet!]
+ja,libaccess,140,[couldn't determine dbtype from: %s]
+ja,libaccess,141,[Failed to register database %s]
+ja,libaccess,142,[ACL call returned failed status]
+ja,libaccess,143,[file %s: ACL IO error - %s]
+ja,libaccess,144,[acl_user_exists: ¥á¥â¥êÉÔ­¤Ç¤¹]
+ja,libaccess,145,[acl_user_exists: ¥æ¡¼¥¶¤¬¤â¤¦Â¸ºß¤·¤Þ¤»¤ó]
+ja,libaccess,146,[acl_user_exists: plist ¥¨¥é¡¼]
+ja,libadmin,-1,[$DBT: libadmin in DB file v1 $]
+ja,libadmin,1,[ Help ]
+ja,libadmin,2,[ OK ]
+ja,libadmin,3,[ Reset ]
+ja,libadmin,4,[ Done ]
+ja,libadmin,5,[ Cancel ]
+ja,libir,-1,[$DBT: libadmin in DB file v1 $]
+ja,libir,1,[An I/O error occurred before all form data could be read.]
diff --git a/ldap/Makefile b/ldap/Makefile
new file mode 100644
index 00000000..61c3f57b
--- /dev/null
+++ b/ldap/Makefile
@@ -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
+#
+
+# GNU Makefile for Directory Server and Ldap SDK
+#
+
+MCOM_ROOT = ../..
+LDAP_SRC = $(MCOM_ROOT)/ldapserver/ldap
+
+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: $(LDAP_LIBDIR) $(LDAP_BINDIR) $(LDAP_OBJDIR) ldapprogs ldapdocs
+
+ldapprogs:
+ cd include; $(MAKE) $(MFLAGS) all
+ cd libraries; $(MAKE) $(MFLAGS) buildDirectory
+ cd servers; $(MAKE) $(MFLAGS) all
+ifneq ($(ARCH), WINNT)
+ cd systools; $(MAKE) $(MFLAGS) all
+ # new unix installer
+ cd cm/newinst; $(MAKE) $(MFLAGS) all
+ifeq ($(USE_64),1)
+ # In 64-bit builds, we build the installer 32-bit, which has the side-effect that the uninstaller and ns-update scripts
+ # get copied into the 32-bit output directory by the makefile above. However, we later want to package them and expect
+ # to see them in the 64-bit output directory. So, here we copy them over.
+ $(CP) $(RELDIR_32)/bin/slapd/admin/bin/ns-update $(LDAP_ADMIN_BIN_RELDIR)
+ $(CP) $(RELDIR_32)/bin/slapd/admin/bin/uninstall $(LDAP_ADMIN_BIN_RELDIR)
+endif
+else
+ cd cm/newinstnt; $(MAKE) $(MFLAGS) all
+endif
+ cd admin; $(MAKE) $(MFLAGS) all
+
+ldapdocs:
+ if [ -d docs ]; then cd docs/dirhlp; $(MAKE) $(MFLAGS) ; fi
+ if [ -d docs ]; then cd docs/dirhlp/ag; $(MAKE) $(MFLAGS) ; fi
+ if [ -d docs ]; then cd docs/dirhlp/deploy; $(MAKE) $(MFLAGS) ; fi
+ if [ -d docs ]; then cd docs/dirhlp/cli; $(MAKE) $(MFLAGS) ; fi
+ if [ -d docs ]; then cd docs/dirhlp/schema; $(MAKE) $(MFLAGS) ; fi
+ if [ -d docs ]; then cd docs/dirhlp/install; $(MAKE) $(MFLAGS) ; fi
+ if [ -d docs ]; then cd docs/dirhlp/gwcust; $(MAKE) $(MFLAGS) ; fi
+ if [ -d docs ]; then cd docs/dirhlp/plugin; $(MAKE) $(MFLAGS) ; fi
+ if [ -d docs ]; then cd docs/dirhlp/orgchart; $(MAKE) $(MFLAGS) ; fi
+ if [ -d docs ]; then cd docs/dirhlp/dsmlgw; $(MAKE) $(MFLAGS) ; fi
+
+clientSDK: $(LDAP_LIBDIR) $(LDAP_BINDIR) $(LDAP_OBJDIR)
+ cd include; $(MAKE) $(MFLAGS) clientSDK
+ifeq ($(ARCH), WINNT)
+ cd servers/slapd/ntmsgdll; $(MAKE) $(MFLAGS) all
+endif
+ cd libraries; $(MAKE) $(MFLAGS) clientSDK
+ cd clients/tools; $(MAKE) $(MFLAGS) clientSDK
+
+clean:
+ cd include; $(MAKE) $(MFLAGS) clean
+ cd libraries; $(MAKE) $(MFLAGS) clean
+ cd servers; $(MAKE) $(MFLAGS) clean
+ cd admin; $(MAKE) $(MFLAGS) clean
+ifneq ($(ARCH), WINNT) # new unix installer
+ cd systools; $(MAKE) $(MFLAGS) clean
+ cd cm/newinst; $(MAKE) $(MFLAGS) clean
+else
+ cd cm/newinstnt; $(MAKE) $(MFLAGS) clean
+endif
+
+cleanSDK:
+ cd include; $(MAKE) $(MFLAGS) clean
+ifeq ($(ARCH), WINNT)
+ cd servers/slapd/ntmsgdll; $(MAKE) $(MFLAGS) clean
+endif
+ cd libraries; $(MAKE) $(MFLAGS) clean
+ cd clients/tools; $(MAKE) $(MFLAGS) clean
+
+veryclean: clean
+
+$(LDAP_LIBDIR):
+ $(MKDIR) $(LDAP_LIBDIR)
+
+$(LDAP_BINDIR):
+ $(MKDIR) $(LDAP_BINDIR)
+
+$(LDAP_OBJDIR):
+ $(MKDIR) $(LDAP_OBJDIR)
+
diff --git a/ldap/Makefile.client b/ldap/Makefile.client
new file mode 100644
index 00000000..b6688141
--- /dev/null
+++ b/ldap/Makefile.client
@@ -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
+#
+DEPTH = ../..
+
+SRCDIRS = build include libraries
+
+include $(DEPTH)/config/rules.mk
+
+all export:: FORCE
+ @for i in $(SRCDIRS); do \
+ echo " cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) export"; \
+ ( cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) export ); \
+ done
+
+libs install:: FORCE
+ @for i in $(SRCDIRS); do \
+ echo "cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) install"; \
+ ( cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) install ); \
+ done
+
+clean clobber:: FORCE
+ @for i in $(SRCDIRS); do \
+ echo "cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) clean"; \
+ ( cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) clean ); \
+ done
+
+realclean clobber_all:: FORCE
+ @for i in $(SRCDIRS); do \
+ echo "cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) realclean"; \
+ ( cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) realclean ); \
+ done
+
+FORCE:
+
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( &ltime );
+ sprintf( file, "%s", ctime( &ltime ) );
+ 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( &ltime );
+ sprintf( file, "%s", ctime( &ltime ) );
+ 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, &ltm );
+#endif
+ strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", &ltm );
+ 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>&lt;/[element name]&gt;</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( "&lt;" );
+ break;
+ case '&' :
+ m_pw.print( "&amp;" );
+ 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( "&lt;" );
+ break;
+ case '>':
+ m_pw.print( "&gt;" );
+ break;
+ case '&' :
+ m_pw.print( "&amp;" );
+ break;
+ case '"':
+ m_pw.print( "&quot;" );
+ break;
+ case '\'':
+ m_pw.print( "&apos;" );
+ 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
+&copyDir("$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}$_") {
+ &copyBinFile("$srcdir${PATHSEP}$_",
+ "$serverHome${PATHSEP}logs${PATHSEP}${_}.migrate");
+ }
+}
+closedir(LOGDIR);
+
+# copy the ssl directory
+&copyDir("$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") {
+ &copyBinFile(
+ "$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";
+&copyLdif;
+
+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?
+# &copyDir($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
+
+&copyBinFile("$serverHome${PATHSEP}config${PATHSEP}slapd.user_at.conf",
+ "$serverHome${PATHSEP}config${PATHSEP}slapd.user_at.conf.bak");
+&copyBinFile("$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") {
+ &copyAndEditTextFile(
+ "$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") {
+ &copyAndEditTextFile(
+ "$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 {
+ &copyBinFile($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
+ &copyDir($realDir, $DEFAULT_CHANGELOG_DIR, '\.share$');
+ }
+}
+
+if ($convertToLDIF) {
+ # Convert the db backup, bak/
+ print "Migrating database backups . . .\n";
+ &copyBak;
+} else {
+ # just copy the directories over
+ &copyDir($networkDbDir, "$serverHome${PATHSEP}db", '\.share$');
+ &copyDir("$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);
+ &copyAndEditTextFile($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);
+ &copyBinFile($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
+ &copyBinFile("$newsrc", "$newsrc.save");
+ &copyBinFile("$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;
+
+ &copyBinFile("$newldbmsrc.tmp", "$newldbmsrc");
+ &copyBinFile("$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}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$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 {
+ &copyBinFile($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 {
+ &copyBinFile("$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;
+ &registerSuffix_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);
+ &registerSuffix_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
+ &copyDir("$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 ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($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) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ if (-f $old_certdb) {
+ if (-f $certdb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$certdb already exists. backup in $certdb_backup ...");
+ &copyBinFile($certdb,$certdb_backup);
+ &copyBinFile($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) {
+ &copyBinFile($old_certdb,$certdb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$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");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$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");
+ &copyDir($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);
+ &copyDir($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;
+ &registerSuffix_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);
+ &registerSuffix_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
+ &copyDir("$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 ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($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) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($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 ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($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";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$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");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$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");
+ &copyDir($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);
+ &copyDir($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;
+ &registerSuffix_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);
+ &registerSuffix_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
+ &copyDir("$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 ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($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) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($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 ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($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";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$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");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$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");
+ &copyDir($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);
+ &copyDir($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;
+ &registerSuffix_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);
+ &registerSuffix_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
+ &copyDir("$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 ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($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) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($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 ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($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";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$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");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$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");
+ &copyDir($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);
+ &copyDir($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 {
+# &copyBinFile($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
+ &copyDir("$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 ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($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) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ if (-f $old_certdb) {
+ if (-f $certdb) {
+ if ($NO_INPUT_USER) {
+ printMsg("\n$certdb already exists. backup in $certdb_backup ...");
+ &copyBinFile($certdb,$certdb_backup);
+ &copyBinFile($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) {
+ &copyBinFile($old_certdb,$certdb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$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");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$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");
+ &copyDir($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);
+ &copyDir($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 {
+# &copyBinFile($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
+ &copyDir("$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 ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($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) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($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 ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($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";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$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");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$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");
+ &copyDir($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);
+ &copyDir($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 {
+# &copyBinFile($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
+ &copyDir("$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 ...");
+ &copyBinFile($keydb,$keydb_backup);
+ &copyBinFile($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) {
+ &copyBinFile($old_keydb,$keydb);
+ }
+ }
+ }
+ else {
+ &copyBinFile($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 ...");
+ &copyBinFile($certdb,$certdb_backup);
+ unlink($certdb) || print "Couldn't delete $certdb : $!\n";
+ &copyBinFile($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";
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ }
+ else {
+ &copyBinFile($old_certdb,$certdb7);
+ }
+ }
+ # copy the old password file
+ if (-f "$oldDir${PATHSEP}alias${PATHSEP}$type-$oldname-pin.txt") {
+ &copyBinFile(
+ "$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");
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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);
+ &copyBinFile($newCertmap,$backupCertmap);
+ &copyBinFile($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}$_") {
+ &copyDir ( "$src${PATHSEP}$_", "$dest${PATHSEP}$_" );
+ } else {
+ &copyBinFile ( "$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");
+ &copyDir($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);
+ &copyDir($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:&nbsp $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:&nbsp;</font>";
+ print "<font class=text28>$serverid</font>\n";
+
+ print "<font class=areatitle>Replica Root:&nbsp;</font>";
+ print "<font class=text28>$replicaroot</font>\n";
+
+ print "<font class=areatitle>Max CSN:&nbsp;</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;
+}
diff --git a/ldap/clients/Makefile b/ldap/clients/Makefile
new file mode 100644
index 00000000..1148c460
--- /dev/null
+++ b/ldap/clients/Makefile
@@ -0,0 +1,31 @@
+# Build Directory client apps
+#
+# 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
+
+MCOM_ROOT=../../..
+
+include ../../nsconfig.mk
+include ../../ldap/javarules.mk
+
+all:
+ cd ldaptags; $(MAKE)
+ cd online; $(MAKE)
+# cd dsgw; $(MAKE)
+ cd dsmlgw; $(MAKE)
+
+clean:
+ cd dsgw; $(MAKE) $(MFLAGS) clean
+ cd dsmlgw; $(MAKE) clean
+
diff --git a/ldap/clients/dsgw/Makefile b/ldap/clients/dsgw/Makefile
new file mode 100644
index 00000000..342b87de
--- /dev/null
+++ b/ldap/clients/dsgw/Makefile
@@ -0,0 +1,305 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+
+# Gmakefile for Directory Server Gateway
+#
+LDAP_SRC = ../..
+MCOM_ROOT = ../../../..
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+
+ifneq ($(ARCH), WINNT)
+#OLD_MCOM_ROOT := $(MCOM_ROOT)
+#MCOM_ROOT = $(shell cd $(OLD_MCOM_ROOT); pwd)
+#OLD_LDAP_SRC := $(LDAP_SRC)
+#LDAP_SRC = $(shell cd $(OLD_LDAP_SRC); pwd)
+endif
+
+NOSTDCLEAN=true # don't let nsconfig.mak define target clean
+NOSTDSTRIP=true # don't let nsconfig.mak define target strip
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+ifndef LDAP_USE_OLD_DB
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+endif
+
+include dsgw_include.mk
+
+# the dsgw binaries should use the standard rpath which includes ../../lib,
+# the clients lib location
+DSGW_RPATHFLAG=
+
+
+ifeq ($(LDAP_NO_LIBLCACHE),1)
+CFLAGS+=-DNO_LIBLCACHE
+endif
+
+ifeq ($(ARCH), HPUX)
+# Use C++ compiler when linking on HP to pick up
+# exception-handling flag (+eh). We need this because
+# we link with other objs compiled with +eh
+ifeq ($(USE_64), 1)
+ALDFLAGS += +DA2.0W +DS2.0 +Z -lpthread
+endif
+
+DSGW_LINK=$(CXX)
+else
+ifeq ($(ARCH), WINNT)
+DSGW_LINK=$(LINK_EXE)
+else
+ifeq ($(ARCH), Linux)
+DSGW_LINK=$(CXX)
+else
+ifeq ($(ARCH), OSF1)
+DSGW_LINK=$(CXX)
+else
+DSGW_LINK=$(CC)
+endif # Linux
+endif # OSF1
+endif # WINNT
+endif # HPUX
+
+ifeq ($(ARCH), SOLARIS)
+ifeq ($(USE_64), 1)
+ALDFLAGS += -xarch=v9
+endif
+# removed -lcx from following line
+CCC_LINK = -lCstd -lCrun -lm -lw -lc
+endif
+
+ifneq ($(ARCH), WINNT)
+ifdef USE_LD_RUN_PATH
+# LD_RUN_PATH instead of -R RPATH
+LD_RUN_PATH=$(RPATHFLAG):$(DSGW_RPATHFLAG)
+export LD_RUN_PATH
+else # USE_LD_RUN_PATH
+DSGW_LINK += $(RPATHFLAG_PREFIX)$(RPATHFLAG):$(DSGW_RPATHFLAG)
+endif # USE_LD_RUN_PATH
+endif # ! WINNT
+
+
+ifeq ($(ARCH), AIX)
+DSGW_LINK=$(CC)
+DSGW_LINK += -brtl -berok $(RPATHFLAG_PREFIX)$(RPATHFLAG):$(DSGW_RPATHFLAG)$(RPATHFLAG_EXTRAS)
+endif
+
+
+BINDIR=$(DSGW_BIN_RELDIR)
+OBJDEST=$(OBJDIR)/clients/dsgw/obj
+
+SRCDIR=$(MCOM_ROOT)/ldapserver/ldap/clients/dsgw
+
+ifeq ($(ARCH), WINNT)
+ALDFLAGS+=-force:multiple
+SUBSYSTEM=console
+endif
+
+ifneq ($(ARCH), WINNT)
+INSTALLOPTIONS= -m 755
+endif
+
+ifeq ($(ARCH), OSF1)
+LINKOPTIONS=-lcxx
+endif
+
+ifeq ($(ARCH), WINNT)
+NSECLIBS = $(NOSSLLIBS)
+EXTRA_LIBS += $(LIBS) $(ADMINUTIL_LINK) $(ICULINK) $(NSPRLINK) $(NSHTTPD)
+EXTRA_LIBS_DEP += $(LIBS) $(NSHTTP_DEP)
+else
+LIBS := $(DISTLIBFLAG) $(LINKOPTIONS) $(LIBLDAPU) $(LDAPLINK) \
+ $(ADMINUTIL_LINK) $(DYN_NSHTTPD) \
+ $(LDAP_LIBLDBM) $(ICULINK) $(NSPRLINK) \
+ $(LDAP_LIBLDIF) $(ALIBS) $(DBMLINK) $(SECURITYLINK) \
+ $(THREADSLIB) $(NSPRLINK) $(LDAP_LIBLITEKEY)
+LIBS_DEP = $(LIBLDAPU_DEP) $(LDAP_LIBLDBM_DEP) $(LDAP_LIBLDIF_DEP)
+LIBS_DEP += $(LDAPSDK_DEP) $(ICU_DEP) $(NSPR_DEP) $(DB_LIB_DEP)
+NSECLIBS = $(DISTLIBFLAG) $(SSLLIBFLAG) $(LINKOPTIONS) $(LIBLDAPU) \
+ $(LDAPLINK) $(ADMINUTIL_LINK) \
+ $(LDAP_LIBLDBM) $(ICULINK) $(NOSSLLIBS) \
+ $(LDAP_LIBLDIF) $(DBMLINK) $(ALIBS) \
+ $(THREADSLIB) $(NSPRLINK) $(LDAP_LIBLITEKEY)
+endif
+
+NSECLIBS_DEP=$(SECGLUEOBJS)
+NSECLIBS_DEP += $(ICU_DEP)
+
+#EXTRA_LIBS += -l$(LIBARES)
+
+ifeq ($(ARCH), Linux)
+LIBS += -lcrypt
+NSECLIBS += -lcrypt
+endif
+
+# these are the programs we must build
+PROGS= auth doauth edit domodify dnedit dosearch
+BINS= $(addprefix $(BINDIR)/, $(PROGS))
+
+# The rest of the CGI programs do not use LIBLDAP and SSL at all, so we
+# link them with glue routines instead of the full libsec. This is done
+# only to reduce our footprint.
+# these are also programs we need to build
+NEED_SECGLUE = unauth search csearch newentry tutor lang
+
+ifneq ($(ARCH), WINNT)
+NEED_SECGLUE_BINS = $(addprefix $(BINDIR)/, $(NEED_SECGLUE))
+else
+NEED_SECGLUE_BINS = $(addprefix $(BINDIR)/, $(addsuffix .exe, $(NEED_SECGLUE)))
+endif
+
+NOTSHIPPINGPROGS= browse browsesrch templateindex
+NOTSHIPPINGBINS= $(addprefix $(BINDIR)/, $(NOTSHIPPINGPROGS))
+
+CKUTILPROGS= ckput ckget ckdump ckpurge ckdel
+CKUTILBINS= $(addprefix $(BINDIR)/, $(CKUTILPROGS))
+
+CMNOBJS= htmlout.o htmlparse.o error.o cgiutil.o dsgwutil.o ldaputil.o \
+ entrydisplay.o config.o cookie.o emitauth.o emitf.o collate.o vcard.o \
+ Versiongw.o utf8compare.o
+
+# MLM
+ifeq ($(ARCH), WINNT)
+CMNOBJS += getopt.o
+endif
+
+COMMONOBJS= $(addprefix $(OBJDEST)/, $(CMNOBJS))
+COMMONOBJSREL= $(addprefix ../obj/, $(CMNOBJS))
+
+NOSSLCMNOBJS= htmlout.o htmlparse.o error.o cgiutil.o dsgwutil.o config.o \
+ cookie.o emitauth.o emitf.o collate.o Versiongw.o utf8compare.o
+NOSSLCOMMONOBJS=$(addprefix $(OBJDEST)/, $(NOSSLCMNOBJS))
+NOSSLCOMMONOBJSREL=$(addprefix ../obj/, $(NOSSLCMNOBJS))
+
+SCGLOBJS= secglue.o
+SECGLUEOBJS=$(addprefix $(OBJDEST)/, $(SCGLOBJS))
+
+ALLOBJS = dosearch.o search.o csearch.o browse.o browsesrch.o templateindex.o \
+ auth.o doauth.o unauth.o ckput.o ckget.o ckdump.o ckpurge.o ckdel.o \
+ edit.o domodify.o newentry.o genscreen.o tutor.o dnedit.o \
+ dsconfig.o dsimpldif.o dsexpldif.o lang.o utf8compare.o \
+ $(COMMONOBJS) $(SECGLUEOBJS)
+
+INCLUDES= -I$(SDKHDIR) -I$(NSCP_DISTDIR)/include $(ICU_INCLUDE) -I$(ADMINUTIL_INCPATH)
+
+DEFINES += $(DEFS) $(SSL) $(XP_FLAG)
+
+CFLAGS += $(INCLUDES) $(DEFINES) $(ACFLAGS)
+# Uncomment the following for debug output to /tmp/dsgw/<CGI> and <CGI>.out
+# if /tmp/dsgw exists and is a directory.
+#CFLAGS += -DDSGW_DEBUG -g
+# Uncomment the following line to build without SSL support
+#CFLAGS += -DDSGW_NO_SSL
+
+ifeq ($(ARCH), WINNT)
+PROGBINS = $(addsuffix .exe, $(BINS))
+NOTSHIPPINGPROGBINS = $(addsuffix .exe, $(NOTSHIPPINGBINS))
+CKUTILPROGBINS = $(addsuffix .exe, $(CKUTILBINS))
+else
+PROGBINS = $(BINS)
+NOTSHIPPINGPROGBINS = $(NOTSHIPPINGBINS)
+CKUTILPROGBINS = $(CKUTILBINS)
+endif
+
+ALLBINS= $(PROGBINS) $(NOTSHIPPINGPROGBINS) $(CKUTILPROGBINS)
+
+## make sure there's prog.exe and prog for NT. Weak, but ES
+## only works with prog, and AS needs both.
+#ifeq ($(ARCH), WINNT)
+#all: prerequisites $(PROGBINS) $(NEED_SECGLUE_BINS) nt_dsgw_bins all-html all-config
+#
+#nt_dsgw_bins:
+# +$(DO_COPY_DSGW_BINS)
+#
+#COPYBINS = $(PROGS) $(NEED_SECGLUE)
+#
+#DO_COPY_DSGW_BINS = \
+# for dsgw_bin in $(COPYBINS); do \
+# mv $(RELDIR)/clients/dsgw/bin/$$dsgw_bin.exe $(RELDIR)/clients/dsgw/bin/$$dsgw_bin; \
+# done
+#else
+all: prerequisites $(PROGBINS) $(NEED_SECGLUE_BINS) all-html all-config
+#endif
+
+prerequisites: $(BINDIR) $(OBJDEST)
+# -@echo $(NEED_SECGLUE_BINS)
+# -@echo $(PROGBINS)
+
+# if $(SECGLUEOBJ) isn't available, use $(ADMIN_SECGLUEOBJ) as a substitute:
+$(SECGLUEOBJ): $(ADMIN_SECGLUEOBJ)
+ cp $(ADMIN_SECGLUEOBJ) $(SECGLUEOBJ)
+
+all-html:
+ cd html; $(MAKE) $(MFLAGS) all
+ cd admhtml; $(MAKE) $(MFLAGS) all
+ cd userhtml; $(MAKE) $(MFLAGS) all
+ cd pbhtml; $(MAKE) $(MFLAGS) all
+
+$(OBJDEST):
+ $(MKDIR) -p $@
+
+all-config:
+ cd config; $(MAKE) $(MFLAGS) all
+ cd pbconfig; $(MAKE) $(MFLAGS) all
+
+ckutils: $(CKUTILPROGBINS)
+
+notshipping: $(NOTSHIPPINGPROGBINS)
+
+$(LDAP_LIBLDBM_DEP):
+ cd $(LDAP_SRC)/libraries; $(MAKE) $(MFLAGS) clientSDK
+
+$(LDAP_SDK_LIBLCACHE_DLL_DEP): $(LDAP_LIBLDBM_DEP)
+
+sort: $(BINDIR)/sort
+
+.PHONY: sort
+
+#
+# The remainder are the CGI programs that make up the gateway itself.
+# We ship all of these.
+#
+ifneq ($(ARCH), WINNT)
+$(PROGBINS): $(BINDIR)/%: $(OBJDEST)/%.o $(COMMONOBJS) $(LIBS_DEP)
+ $(DSGW_LINK) $(ALDFLAGS) -o $@ $< $(COMMONOBJS) $(LIBS) $(CCC_LINK)
+
+$(NEED_SECGLUE_BINS): $(BINDIR)/%: $(OBJDEST)/%.o $(NOSSLCOMMONOBJS) $(NSECLIBS_DEP)
+ $(DSGW_LINK) $(ALDFLAGS) -o $@ $< $(NOSSLCOMMONOBJS) \
+ $(NSECLIBS) $(CCC_LINK)
+else
+$(PROGBINS): $(BINDIR)/%.exe: $(OBJDEST)/%.o $(COMMONOBJS)
+ $(DSGW_LINK) $(ALDFLAGS) $< $(COMMONOBJS) \
+ $(LDAPLINK) $(SECURITYLINK) $(ICULINK) $(CCC_LINK)
+# sometimes linking executables can produce unneeded .lib or .exp files
+ -@$(RM) $(subst .exe,.lib,$@) $(subst .exe,.exp,$@)
+
+$(NEED_SECGLUE_BINS): $(BINDIR)/%.exe: $(OBJDEST)/%.o $(NOSSLCOMMONOBJS) $(SECGLUEOBJS)
+ $(DSGW_LINK) $(ALDFLAGS) $< $(NOSSLCOMMONOBJS) \
+ $(LDAPLINK) $(SECGLUEOBJS) $(ICULINK) $(CCC_LINK)
+# sometimes linking executables can produce unneeded .lib or .exp files
+ -@$(RM) $(subst .exe,.lib,$@) $(subst .exe,.exp,$@)
+endif
+
+clean: clean-html clean-config
+ rm -rf $(BINDIR)
+ rm -rf $(OBJDEST)
+
+clean-html:
+ cd html; $(MAKE) $(MFLAGS) clean
+ cd pbhtml; $(MAKE) $(MFLAGS) clean
+
+clean-config:
+ cd config; $(MAKE) $(MFLAGS) clean
+ cd pbconfig; $(MAKE) $(MFLAGS) clean
+
+strip:
+ $(STRIP) $(ALLBINS)
+
+$(OBJDEST)/%.o: %.c
+ $(CC) -c $(CFLAGS) $(MCC_INCLUDE) $< $(OFFLAG)$@
+
+CFLAGS += -I../../include
diff --git a/ldap/clients/dsgw/Versiongw.c b/ldap/clients/dsgw/Versiongw.c
new file mode 100644
index 00000000..93c5c970
--- /dev/null
+++ b/ldap/clients/dsgw/Versiongw.c
@@ -0,0 +1,25 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#if defined( XP_WIN32 )
+#undef MCC_HTTPD
+#endif
+
+#include "netsite.h" /* to get MAGNUS_VERSION_STRING */
+
+#ifdef MAGNUS_VERSION_STRING
+#define DSGW_VER_STR MAGNUS_VERSION_STRING
+#else
+#include "dirver.h" /* to get PRODUCTTEXT */
+#define DSGW_VER_STR PRODUCTTEXT
+#endif
+
+char *Versionstr = "Netscape-Directory-Gateway/"DSGW_VER_STR;
diff --git a/ldap/clients/dsgw/admhtml/Makefile b/ldap/clients/dsgw/admhtml/Makefile
new file mode 100644
index 00000000..a8cfafee
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/Makefile
@@ -0,0 +1,52 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# Gmakefile for Directory Server Gateway html files.
+#
+
+LDAP_SRC = ../../..
+MCOM_ROOT = ../../../../..
+
+NOSTDSTRIP=true # don't let nsconfig.mak define target strip
+NOSTDCLEAN=true # don't let nsconfig.mak define target clean
+NOSTDDEPEND=true # don't let nsconfig.mak define target depend
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+
+include ../dsgw_include.mk
+
+HTMLDEST = $(DSGW_HTML_RELDIR)
+
+HTML= auth.html authroot.html authtitle.html csearchtitle.html greeting.html \
+ index.html maintitle.html newentrytitle.html searchtitle.html \
+ back.gif back1.gif blankbut.gif content.gif content1.gif country.gif \
+ exit1.gif forward1.gif group.gif index1.gif netscape.gif \
+ organization.gif orgunit.gif person.gif title.gif triangle.gif
+
+BINS=$(addprefix $(HTMLDEST)/,$(HTML))
+
+# install: $(HTMLDEST) $(BINS) inst-manual inst-info
+install:
+
+all: install
+
+clean:
+ $(RM) $(BINS)
+
+$(HTMLDEST)/%: %
+ -@$(RM) $@
+ cp $< $@
+
+$(HTMLDEST)/%.gif: %.gif
+ -@$(RM) $@
+ cp $< $@
+
+strip:
+depend:
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
diff --git a/ldap/clients/dsgw/admhtml/display-country.html b/ldap/clients/dsgw/admhtml/display-country.html
new file mode 100644
index 00000000..20960338
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-country.html
@@ -0,0 +1,52 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- DS_OBJECTCLASS "value=country" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Country -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD><BODY>
+
+<TABLE>
+<TR><TD NOWRAP>
+<IMG SRC="/admin-serv/icons/country.gif" ALT="Country" HSPACE=5>
+</TD><TD><FONT SIZE="+2">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE CELLSPACING="5">
+
+<TR><TD VALIGN="TOP" NOWRAP>Country Name:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=co" "options=sort" -->
+</B></TD><TD WIDTH="20%"></TD>
+</B><TD VALIGN="TOP">Description:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP">See Also:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" -->
+</B></TD></TR>
+
+</TABLE>
+
+<HR>
+
+This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-dnedit.html b/ldap/clients/dsgw/admhtml/display-dnedit.html
new file mode 100644
index 00000000..7a1b78fc
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-dnedit.html
@@ -0,0 +1,74 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY "onLoad='document.searchForm.searchstring.focus();'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+
+<FONT SIZE="+2">
+Edit
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<TABLE CELLSPACING=0 CELLPADDING=0><TR>
+
+<TD NOWRAP>
+Find
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">Users
+<OPTION VALUE="Groups">Groups
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+matching&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<INPUT TYPE=SUBMIT VALUE=" Find and Add ">
+<BR>
+<INPUT TYPE=BUTTON VALUE=" Find and Remove " onClick="searchForm.faMode.value='remove';searchForm.submit();searchForm.searchstring.select();searchForm.searchstring.focus();">
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Save Changes " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Cancel " onClick="if ((parent.changesMade) == 0 || confirm('Discard changes?')) {parent.document.location.href=parent.completion_url}";>
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-dnedittop.html b/ldap/clients/dsgw/admhtml/display-dnedittop.html
new file mode 100644
index 00000000..89f6b6bc
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-dnedittop.html
@@ -0,0 +1,19 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- DS_ENTRYBEGIN -->
+<SCRIPT LANGUAGE="JavaScript">
+
+</SCRIPT>
+
+<FRAMESET BORDER=1 FRAMEBORDER=1 ROWS=1,150,* SCROLLING="NO" NORESIZE>
+ <FRAME SRC="javascript:parent.emptyFrame" NAME="stagingFrame">
+<!-- DS_EDDN_FRAMEDEF "template=dnedit" -->
+ <FRAME SRC="javascript:parent.emptyFrame" NAME="outputFrame">
+</FRAMESET>
+<!-- DS_ENTRYEND -->
+</HTML>
diff --git a/ldap/clients/dsgw/admhtml/display-group.html b/ldap/clients/dsgw/admhtml/display-group.html
new file mode 100644
index 00000000..d154e3eb
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-group.html
@@ -0,0 +1,122 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<SCRIPT LANGUAGE="JavaScript">
+
+function setDeleteCheckboxes(attr, checked)
+{
+ var varName = 'delete_' + attr;
+
+ for ( i = 0; i < document.modifyEntryForm.elements.length; ++i ) {
+ if ( document.modifyEntryForm.elements[i].name == varName ) {
+ document.modifyEntryForm.elements[i].checked = checked;
+ }
+ }
+ aChg(attr);
+}
+
+</SCRIPT>
+<!-- DS_OBJECTCLASS "value=groupOfNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+New Group -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfNames">
+<!-- ENDIF // Adding -->
+
+<!-- IF "!Displaying" -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="if (dsmodify_dn.length == 0) document.location.href=\'genscreen?dslsgroups&info=\' + escape(dsmodify_info); else document.location.href=\'edit/\' + dsmodify_dn + \'?&info=\' + escape(dsmodify_info);">
+<DIV ALIGN="right"><FONT SIZE="-1">* Indicates a required field</FONT></DIV>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD ALIGN="right" NOWRAP>
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+<B>Name:</B>
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD ALIGN="right" NOWRAP><B>Description:</B></TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP ALIGN="right" VALIGN="top"><B>Group Members:</B><BR>
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=member" "desc=Group Members" -->
+</TD><TD>
+<!-- DS_ATTRIBUTE "attr=member" "syntax=dn" "dncomponents=2" "options=readonly,sort" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="right" NOWRAP><B>Owner:</B><BR>
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=owner" "desc=Owner" -->
+</TD><TD>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "dncomponents=2" "options=readonly" -->
+</TD>
+</TD></TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="right" NOWRAP><B>See Also:</B><BR>
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+</TD><TD>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=2" "options=readonly" -->
+</TABLE></TD>
+</TD></TR>
+
+</TABLE>
+
+<!-- IF "AttributeHasValues" "modifyTimestamp" -->
+<TABLE BORDER=0><TR><TD><FONT SIZE="-1">
+Last modified on
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "options=readonly" -->
+ by
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "options=readonly" -->
+</FONT></TD></TR></TABLE>
+<!-- ENDIF // AttributeHasValues -->
+
+<TABLE BORDER=2 WIDTH=100%><TR><TD WIDTH=25% ALIGN="center">
+<!-- DS_SAVEBUTTON -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_RENAMEBUTTON "label=Rename Group" "prompt=Enter a new name for this group:" -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_DELETEBUTTON "label=Delete Group" "prompt=Delete this group?" -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+</TD></TR></TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-groupun.html b/ldap/clients/dsgw/admhtml/display-groupun.html
new file mode 100644
index 00000000..a11a6646
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-groupun.html
@@ -0,0 +1,122 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<SCRIPT LANGUAGE="JavaScript">
+
+function setDeleteCheckboxes(attr, checked)
+{
+ var varName = 'delete_' + attr;
+
+ for ( i = 0; i < document.modifyEntryForm.elements.length; ++i ) {
+ if ( document.modifyEntryForm.elements[i].name == varName ) {
+ document.modifyEntryForm.elements[i].checked = checked;
+ }
+ }
+ aChg(attr);
+}
+
+</SCRIPT>
+<!-- DS_OBJECTCLASS "value=groupOfUniqueNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+New Group -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+
+<!-- IF "!Displaying" -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="if (dsmodify_dn.length == 0) document.location.href=\'genscreen?dslsgroups&info=\' + escape(dsmodify_info); else document.location.href=\'edit/\' + dsmodify_dn + \'?&info=\' + escape(dsmodify_info);">
+<DIV ALIGN="right"><FONT SIZE="-1">* Indicates a required field</FONT></DIV>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD ALIGN="right" NOWRAP>
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+<B>Name:</B>
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD ALIGN="right" NOWRAP><B>Description:</B></TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP ALIGN="right" VALIGN="top"><B>Group Members:</B><BR>
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=uniquemember" "desc=Group Members" -->
+</TD><TD>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "dncomponents=2" "options=readonly,sort" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="right" NOWRAP><B>Owner:</B><BR>
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=owner" "desc=Owner" -->
+</TD><TD>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "dncomponents=2" "options=readonly" -->
+</TD>
+</TD></TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="right" NOWRAP><B>See Also:</B><BR>
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+</TD><TD>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=2" "options=readonly" -->
+</TABLE></TD>
+</TD></TR>
+
+</TABLE>
+
+<!-- IF "AttributeHasValues" "modifyTimestamp" -->
+<TABLE BORDER=0><TR><TD><FONT SIZE="-1">
+Last modified on
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "options=readonly" -->
+ by
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "options=readonly" -->
+</FONT></TD></TR></TABLE>
+<!-- ENDIF // AttributeHasValues -->
+
+<TABLE BORDER=2 WIDTH=100%><TR><TD WIDTH=25% ALIGN="center">
+<!-- DS_SAVEBUTTON -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_RENAMEBUTTON "label=Rename Group" "prompt=Enter a new name for this group:" -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_DELETEBUTTON "label=Delete Group" "prompt=Delete this group?" -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+</TD></TR></TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-licensed-user.html b/ldap/clients/dsgw/admhtml/display-licensed-user.html
new file mode 100644
index 00000000..869e8886
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-licensed-user.html
@@ -0,0 +1,71 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<!-- Netscape Client Access Licensee directory entry -->
+<!-- DS_OBJECTCLASS "value=nsLicenseUser" -->
+
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<FONT SIZE="+2">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<!-- DS_VIEW_SWITCHER -->
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nsLicenseUser">
+<!-- ENDIF // Adding -->
+
+<CENTER>
+<FONT SIZE="+1"><B>Netscape Client Access License Information</B></FONT>
+<!-- IF "!AttributeHasThisValue" "objectClass" "cis" "nsLicenseUser" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nsLicenseUser">
+<!-- ENDIF // !AttributeHasThisValue -->
+</CENTER>
+<P>
+
+<!-- IF "!Displaying" -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="if (dsmodify_dn.length == 0) document.location.href=\'genscreen?dslsusers&info=\' + escape(dsmodify_info); else document.location.href=\'edit/\' + dsmodify_dn + \'?licensed-user&info=\' + escape(dsmodify_info);">
+<!-- ENDIF -->
+
+<P>
+Mark all of the products that this person has been granted a
+Client Access License for:
+<P>
+
+<TABLE CELLSPACING="5">
+
+<INPUT TYPE="hidden" NAME="replace_nsLicensedFor" VALUE="">
+<!-- DS_ATTRVAL_SET "set=CAL" "attr=nsLicensedFor" "type=checkbox" "prefix=<TR><TD>" "suffix=</TD></TR>" -->
+
+</TABLE>
+
+<P>
+
+<TABLE BORDER=2 WIDTH=100%><TR><TD WIDTH=50% ALIGN="center">
+<!-- DS_SAVEBUTTON -->
+</TD><TD WIDTH=50% ALIGN="center">
+<!-- DS_HELPBUTTON "topic=EDIT_LICENSE_INFO" -->
+</TD>
+</TR></TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-mailgroup.html b/ldap/clients/dsgw/admhtml/display-mailgroup.html
new file mode 100644
index 00000000..4768270a
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-mailgroup.html
@@ -0,0 +1,121 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- DS_OBJECTCLASS "value=rfc822mailgroup" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Mail Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD><BODY>
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="/admin-serv/icons/group.gif" ALT="Group" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+New Mail Group
+<!-- ENDIF // Adding -->
+
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit Group" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Group" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp&nbsp</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp&nbsp</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_MAILGROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_MAILGROUP" -->
+<!-- ENDIF // Adding -->
+
+<!-- IF "Editing" -->
+</TD><TD>&nbsp&nbsp</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Group" "prompt=Enter a new name for this group:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Group" "prompt=Delete this group?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="rfc822mailgroup">
+<!-- ENDIF // Adding -->
+
+<HR>
+
+<TABLE CELLSPACING="5">
+
+<TR><TD VALIGN="TOP">Name:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="TOP">Description:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=multilineDescription" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP">Owner:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP" NOWRAP>See Also:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD NOWRAP COLSPAN="2">
+<!-- DS_ATTRIBUTE "attr=joinable" "syntax=bool" "type=radio" "true=Allow Others To Join" "false=Do Not Allow Others To Join" "defaultvalue=FALSE" -->
+</TD><TD></TD><TD NOWRAP COLSPAN="2">
+<!-- DS_ATTRIBUTE "attr=suppressNoEmailError" "syntax=bool" "type=radio" "true=Suppress 'No Email Address' Errors" "false=Return 'No Email Address' Errors" "defaultvalue=FALSE" -->
+</TD></TR>
+
+<HR>
+
+<TR><TD VALIGN="TOP" NOWRAP>Group Members:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=member" "syntax=dn" "numfields=+4" "options=sort" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP" NOWRAP>E-Mail Members:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "numfields=+4" "cols=>30" "options=sort" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedTime" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedBy" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-org.html b/ldap/clients/dsgw/admhtml/display-org.html
new file mode 100644
index 00000000..1d05a994
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-org.html
@@ -0,0 +1,129 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- DS_OBJECTCLASS "value=organization" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Organization -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD><BODY>
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="/admin-serv/icons/organization.gif" ALT="Organization" HSPACE=5>
+<TD>
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+New Organization -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit Organization" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Org." -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp&nbsp</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp&nbsp</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORG" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORG" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp&nbsp</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Org." "prompt=Enter a new name for this organization:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Org." "prompt=Delete this organization?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organization">
+<!-- ENDIF // Adding -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<DIV ALIGN="right"><B>*&nbsp</B>Indicates a required field</DIV>
+<!-- ENDIF -->
+
+<TABLE>
+<TR>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "!Displaying" -->
+<B>*&nbsp</B>
+<!-- ENDIF -->
+<B>Organization Name:</B>
+</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=o" "cols=>20" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD>Description:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</B></TR>
+
+<TR><TD>Phone:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD NOWRAP>Business Category:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</B></TD></TR>
+
+<TR><TD>Fax:<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD>Location:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Mailing Address:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">See Also:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-orgperson.html b/ldap/clients/dsgw/admhtml/display-orgperson.html
new file mode 100644
index 00000000..60660b1e
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-orgperson.html
@@ -0,0 +1,142 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<!-- inet. organizational person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+User Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<FONT SIZE="+2">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<!-- DS_VIEW_SWITCHER -->
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<!-- ENDIF // Adding -->
+
+<!-- IF "!Displaying" -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="if (dsmodify_dn.length == 0) document.location.href=\'genscreen?dslsusers&info=\' + escape(dsmodify_info); else document.location.href=\'edit/\' + dsmodify_dn + \'?&info=\' + escape(dsmodify_info);">
+<DIV ALIGN="right"><FONT SIZE="-1">* Indicates a required field</FONT></DIV>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="5">
+
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>Given Name (First Name):</B></TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>32" -->
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP>
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+<B>Surname (Last Name):</B></TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>32" -->
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="right" NOWRAP>
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+<B>Full Name(s):</B>
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>32" -->
+</B></TD>
+</TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="right" NOWRAP>
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+<B>User ID:</B>
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "numfields=1" "cols=>16" "options=unique" -->
+</B></TD>
+</TR>
+
+<!-- IF "Adding" -->
+<TR><TD COLSPAN="2"><HR></TD></TR>
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>Password:</B></TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD>
+</TR>
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>Repeat password to confirm:</B></TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+<TR><TD COLSPAN="2"><HR></TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>E-Mail Address:</B></TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>32" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>Title:</B></TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" "cols=>32" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>Telephone:</B></TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "AttributeHasValues" "modifyTimestamp" -->
+<TABLE BORDER=0><TR><TD><FONT SIZE="-1">
+Last modified on
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "options=readonly" -->
+ by
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "options=readonly" -->
+</FONT></TD></TR></TABLE>
+<!-- ENDIF // AttributeHasValues -->
+
+<TABLE BORDER=2 WIDTH=100%><TR><TD WIDTH=25% ALIGN="center">
+<!-- DS_SAVEBUTTON -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_RENAMEBUTTON "label=Rename User" "prompt=Please enter a new name for this user.\nNote that renaming only affects the Full Name field." -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_DELETEBUTTON "label=Delete User" "prompt=Delete this user?" -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_HELPBUTTON "topic=EDIT_ORGPERSON" -->
+</TD></TR></TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-orgunit.html b/ldap/clients/dsgw/admhtml/display-orgunit.html
new file mode 100644
index 00000000..0f1db1a4
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-orgunit.html
@@ -0,0 +1,95 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- DS_OBJECTCLASS "value=organizationalUnit" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Organizational Unit -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+New Organizational Unit -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalUnit">
+<!-- ENDIF // Adding -->
+
+<!-- IF "!Displaying" -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="if (dsmodify_dn.length == 0) document.location.href=\'genscreen?dslsous&info=\' + escape(dsmodify_info); else document.location.href=\'edit/\' + dsmodify_dn + \'?&info=\' + escape(dsmodify_info);">
+<DIV ALIGN="right"><FONT SIZE="-1">* Indicates a required field</FONT></DIV>
+<!-- ENDIF -->
+
+
+<TABLE>
+<TR><TD>
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+<B>Unit Name:</B>
+</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD>
+<B>Description:</B></TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD><B>Phone:</B></TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR><TD><B>Fax:</B><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP"><B>Mailing Address:</B></TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "AttributeHasValues" "modifyTimestamp" -->
+<TABLE BORDER=0><TR><TD><FONT SIZE="-1">
+Last modified on
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "options=readonly" -->
+ by
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "options=readonly" -->
+</FONT></TD></TR></TABLE>
+<!-- ENDIF // AttributeHasValues -->
+
+<TABLE BORDER=2 WIDTH=100%><TR><TD WIDTH=25% ALIGN="center">
+<!-- DS_SAVEBUTTON -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_RENAMEBUTTON "label=Rename" "prompt=Enter a new name for this organizational unit:" -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_DELETEBUTTON "label=Delete" "prompt=Delete this organizational unit?" -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_HELPBUTTON "topic=EDIT_ORGUNIT" -->
+</TD></TR></TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-person.html b/ldap/clients/dsgw/admhtml/display-person.html
new file mode 100644
index 00000000..74fc3d3a
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-person.html
@@ -0,0 +1,133 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<!-- person directory entry -->
+<!-- DS_OBJECTCLASS "value=person" -->
+
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+User Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<FONT SIZE="+2">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<!-- DS_VIEW_SWITCHER -->
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<!-- ENDIF // Adding -->
+
+<!-- IF "!Displaying" -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="if (dsmodify_dn.length == 0) document.location.href=\'genscreen?dslsusers&info=\' + escape(dsmodify_info); else document.location.href=\'edit/\' + dsmodify_dn + \'?&info=\' + escape(dsmodify_info);">
+<DIV ALIGN="right"><FONT SIZE="-1">* Indicates a required field</FONT></DIV>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="5">
+
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP>
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+<B>Surname (Last Name):</B></TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>32" -->
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="right" NOWRAP>
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+<B>Full Name(s):</B>
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>32" -->
+</B></TD>
+</TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="right" NOWRAP>
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+<B>User ID:</B>
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "numfields=1" "cols=>16" "options=unique" -->
+</B></TD>
+</TR>
+
+<!-- IF "Adding" -->
+<TR><TD COLSPAN="2"><HR></TD></TR>
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>Password:</B></TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD>
+</TR>
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>Repeat password to confirm:</B></TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+<TR><TD COLSPAN="2"><HR></TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>E-Mail Address:</B></TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>32" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>Title:</B></TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" "cols=>32" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" ALIGN="Right" NOWRAP><B>Telephone:</B></TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "AttributeHasValues" "modifyTimestamp" -->
+<TABLE BORDER=0><TR><TD><FONT SIZE="-1">
+Last modified on
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "options=readonly" -->
+ by
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "options=readonly" -->
+</FONT></TD></TR></TABLE>
+<!-- ENDIF // AttributeHasValues -->
+
+<TABLE BORDER=2 WIDTH=100%><TR><TD WIDTH=25% ALIGN="center">
+<!-- DS_SAVEBUTTON -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_RENAMEBUTTON "label=Rename User" "prompt=Please enter a new name for this user.\nNote that renaming only affects the Full Name field." -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_DELETEBUTTON "label=Delete User" "prompt=Delete this user?" -->
+</TD><TD WIDTH=25% ALIGN="center">
+<!-- DS_HELPBUTTON "topic=EDIT_ORGPERSON" -->
+</TD></TR></TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/display-umperson.html b/ldap/clients/dsgw/admhtml/display-umperson.html
new file mode 100644
index 00000000..6688b471
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/display-umperson.html
@@ -0,0 +1,177 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- U-M person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,umichPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+U-M Person Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD><BODY>
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<IMG SRC="/admin-serv/icons/person.gif" ALT="Person" HSPACE=5>
+</TD><TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+New U-M Person -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit Person" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Person" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp&nbsp</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp&nbsp</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_UMPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_UMPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp&nbsp</TD><TD>
+<!-- DS_EDITASBUTTON "label=Change Password" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Person" "prompt=Enter a new name for this person:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Person" "prompt=Delete this person?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="umichPerson">
+<!-- ENDIF // Adding -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<DIV ALIGN="right"><B>*&nbsp</B>Indicates a required field</DIV>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD VALIGN="top" NOWRAP>Last Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="top" NOWRAP>Full Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Phone:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>E-Mail Address:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Fax:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Uniqname:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Pager:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Mobile Phone:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Title:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Mailing Address:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Description:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=multilineDescription" "syntax=mls" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">See Also:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURL" "syntax=url" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Favorite Beverage:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=drink" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedTime" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedBy" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/dsconfig.html b/ldap/clients/dsgw/admhtml/dsconfig.html
new file mode 100644
index 00000000..a8ea5b2c
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/dsconfig.html
@@ -0,0 +1,191 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>User Management</TITLE>
+
+<SCRIPT language=JavaScript>
+var didSetDefaults = 0;
+
+
+function resetForm()
+{
+ if (document.modForm.dirsvctype[1].checked) {
+ document.configuredForRemote = 1;
+ document.modForm.host.focus();
+ if (document.modForm.port.value == '') {
+ document.modForm.port.value = '389';
+ }
+ } else {
+ document.configuredForRemote = 0;
+ }
+}
+
+
+function submitModify()
+{
+ var theForm = document.modForm;
+
+ // verify form fields
+ if ( theForm.dirsvctype[1].checked ) { // remote directory server
+ if ( theForm.host.value.length == 0 ) {
+ alert( 'Please provide the host name of the LDAP server.' );
+ return false;
+ }
+ if ( theForm.port.value.length == 0 ) {
+ alert( 'Please provide the port number of the LDAP server.' );
+ return false;
+ }
+ if ( theForm.port.value < 1 || theForm.port.value > 65535 ) {
+ alert( 'The port number must be between 1 and 65535.' );
+ return false;
+ }
+ if ( theForm.basedn.value.length == 0 ) {
+ alert( 'Please provide a base DN.' );
+ return false;
+ }
+ if ( theForm.bindpw.value.length > 0 &&
+ theForm.binddn.value.length == 0 ) {
+ alert( 'Please provide the Bind DN.' );
+ return false;
+ }
+ }
+
+ theForm.submit();
+ return false;
+}
+
+
+function selectedSSL( doSSL )
+{
+ var theForm = document.modForm;
+ var onWrongPort, portDesc;
+
+ // SSL On or SSL Off radio button was clicked on: offer to set the
+ // port to the standard SSL or non-SSL one as appropriate.
+
+ if ( doSSL ) {
+ onWrongPort = ( theForm.port.value == 389 );
+ portDesc = 'LDAP over SSL';
+ stdPort = 636;
+ } else {
+ onWrongPort = ( theForm.port.value == 636 );
+ portDesc = 'LDAP';
+ stdPort = 389;
+ }
+
+ if ( onWrongPort && confirm( 'The standard port for ' + portDesc + ' is ' +
+ stdPort + '.\nWould you like to switch to the standard port?' )) {
+ theForm.port.value = stdPort;
+ }
+}
+
+
+function checkForChange()
+{
+ cTLMsg = 'If you switch to local database mode,\n' +
+ 'any configuration data about directory servers\n' +
+ 'will be lost. Go ahead and change to\n' +
+ 'local database mode?';
+ cTRMsg = 'To use a directory server, you must\n' +
+ 'provide the host name, port, and base DN for\n' +
+ 'an LDAP directory server. Go ahead and\n' +
+ 'change to directory server mode?';
+
+ if (document.modForm.dirsvctype[0].checked &&
+ document.configuredForRemote) {
+ if (confirm(cTLMsg)) {
+ var tmp = document.location.href;
+ if (document.location.search == "?CHANGE") {
+ document.location.search = "";
+ } else {
+ document.location.href = tmp + "?CHANGE";
+ }
+ } else {
+ document.modForm.dirsvctype[1].checked = true;
+ }
+ } else if (document.modForm.dirsvctype[1].checked &&
+ !document.configuredForRemote) {
+ if (confirm(cTRMsg)) {
+ var tmp = document.location.href;
+ if (document.location.search == "?CHANGE") {
+ document.location.search = "";
+ } else {
+ document.location.href = tmp + "?CHANGE";
+ }
+ } else {
+ document.modForm.dirsvctype[0].checked = true;
+ }
+ }
+}
+
+</SCRIPT>
+
+</HEAD>
+<!-- BODY "onLoad='resetForm()'" -->
+
+<CENTER><TABLE BORDER="2" CELLPADDING="10" WIDTH="100%">
+<TR><TD ALIGN="center" WIDTH="100%">
+<FONT SIZE="+2"><B>Configure Directory Service</B></FONT>
+</TD></TR></TABLE></CENTER>
+
+<!-- DS_INLINE_POST_RESULTS -->
+
+<FORM METHOD="POST" ACTION="dsconfig" NAME="modForm">
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
+<TR>
+<TD ALIGN="right" NOWRAP><B>Obtain Directory Service From:</B></TD>
+<TD>
+<INPUT TYPE="radio" NAME="dirsvctype"
+VALUE="local"
+<!-- DS_CHECKED_IF_LOCAL -->
+onClick="checkForChange(this);">Local Database
+<BR>
+<INPUT TYPE="radio" NAME="dirsvctype"
+VALUE="remote"
+<!-- DS_CHECKED_IF_REMOTE -->
+onClick="checkForChange(this);">LDAP Directory Server
+</TD>
+</TR>
+</TABLE>
+<HR>
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
+<TR><TD COLSPAN="2" ALIGN="center">
+
+<!-- DS_CONFIG_INFO -->
+<BR>
+
+</B></TD></TR>
+
+<!-- DS_HOSTNAME_VALUE -->
+
+<!-- DS_PORT_VALUE -->
+
+<!-- DS_SSL_CONFIG_VALUE -->
+
+<!-- DS_BASEDN_VALUE -->
+
+<!-- DS_BINDDN_VALUE -->
+
+<!-- DS_BINDPASSWD_VALUE -->
+
+</TABLE>
+<P>
+
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center"><INPUT TYPE="button" VALUE=" Save Changes "
+ onClick="submitModify()"></TD>
+<TD WIDTH=34% ALIGN=center><INPUT TYPE="reset" VALUE=" Reset "
+ onClick="resetForm()"></TD>
+<TD WIDTH=33% ALIGN=center>
+<!-- HELPBUTTON "DSCONFIG" -->
+</TD>
+</TR></TABLE></CENTER>
+</FORM>
+
+<!-- DS_NOCERTFILE_WARNING "<SCRIPT language=JavaScript>alert('For the Users and Groups forms to work over SSL, you need to activate SSL for this Administration Server.\nChoose Encryption|On/Off to do so.');</SCRIPT>" -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/dscrgroup.html b/ldap/clients/dsgw/admhtml/dscrgroup.html
new file mode 100644
index 00000000..f51f255f
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/dscrgroup.html
@@ -0,0 +1,114 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>User Management</TITLE>
+
+<SCRIPT language=JavaScript>
+
+function resetForm()
+{
+ document.addForm.add_cn.focus();
+}
+
+
+function submitAdd()
+{
+ var theForm = document.addForm;
+ var dn, dnSuffix, i, e, prod;
+
+ if ( theForm.add_cn.value.length == 0 ) {
+ alert( 'Please provide a name for the group' );
+ theForm.add_cn.focus();
+ return;
+ }
+
+ dn = 'cn=' + theForm.add_cn.value;
+ if ( theForm.CrLoc.type == 'hidden' ) {
+ dnSuffix = unescape( theForm.CrLoc.value );
+ } else {
+ dnSuffix = unescape(
+ theForm.CrLoc.options[ theForm.CrLoc.selectedIndex ].value );
+ }
+ if ( dnSuffix.length > 0 ) {
+ dn += ', ' + dnSuffix;
+ }
+ theForm.dn.value = escape(dn);
+
+ // execute selected product-specific default functions
+ for ( i = 0; i < theForm.elements.length; ++i ) {
+ e = theForm.elements[ i ];
+ if ( e.type == 'checkbox' &&
+ e.name.substring( 0, 17 ) == 'product_checkbox_' &&
+ e.checked ) {
+ prod = e.name.substring( 17, e.name.length );
+ if ( !eval( 'product_setdefaults_' + prod + '(theForm)' )) {
+ return; // submit vetoed by product
+ }
+ }
+ }
+
+ theForm.submit();
+}
+
+
+function submitAddandEdit()
+{
+ document.addForm.completion_javascript.value =
+ "if (dsmodify_dn.length == 0) document.location.href=\"genscreen?dscrgroup&info=\" + escape(dsmodify_info); else document.location.href=\"edit/\" + dsmodify_dn + \"?&info=\" + escape(dsmodify_info);";
+
+ submitAdd();
+}
+
+</SCRIPT>
+
+</HEAD>
+<!-- BODY "onLoad='resetForm()'" -->
+
+<CENTER><TABLE BORDER="2" CELLPADDING="10" WIDTH="100%">
+<TR><TD ALIGN="center" WIDTH="100%">
+<FONT SIZE="+2"><B>New Group</B></FONT>
+</TD></TR></TABLE></CENTER>
+
+<!-- DS_LAST_OP_INFO "prefix=<P><FONT SIZE=%22%2B1%22>The group " "suffix=</FONT><HR>" -->
+
+<FORM METHOD="POST" ACTION="domodify" NAME="addForm">
+
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'genscreen?dscrgroup&info=\' + escape(dsmodify_info)">
+
+<INPUT TYPE="hidden" NAME="changetype" VALUE="add">
+<INPUT TYPE="hidden" NAME="dn" VALUE="">
+
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+
+<DIV ALIGN="right"><FONT SIZE="-1">* Indicates a required field</FONT></DIV>
+
+<TABLE CELLSPACING="0" BORDER="0">
+<TR><TD ALIGN="right"><b>* Group Name:</b></TD>
+<TD><INPUT type="text" name="add_cn" value="" size=32></TD></TR>
+<TR><TD ALIGN="right"><b>Description:</b></TD>
+<TD><INPUT type="text" name="add_description" value="" size=32></TD></TR>
+<!-- INCLUDESET dscrgroup -->
+<!-- DS_LOCATIONPOPUP "name=CrLoc" "prefix=<TR><TD ALIGN=%22right%22><b>Add New Group To:</b></TD><TD>" "suffix=</TD></TR>" "rootname=the top of the directory" -->
+</TABLE>
+<P>
+
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="25%" ALIGN="center"><INPUT TYPE="button" VALUE=" Create Group "
+ onClick="submitAdd()"></TD>
+<TD WIDTH="25%" ALIGN="center">
+ <INPUT TYPE="button" VALUE=" Create and Edit Group "
+ onClick="submitAddandEdit()"></TD>
+<TD WIDTH=25% ALIGN=center><INPUT TYPE="reset" VALUE=" Reset "
+ onClick="resetForm()"></TD>
+<TD WIDTH=25% ALIGN=center>
+<!-- HELPBUTTON "DSCRGROUP" -->
+</TD></TR></TABLE></CENTER>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/dscrou.html b/ldap/clients/dsgw/admhtml/dscrou.html
new file mode 100644
index 00000000..78ffe725
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/dscrou.html
@@ -0,0 +1,103 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>User Management</TITLE>
+
+<SCRIPT language=JavaScript>
+
+function resetForm()
+{
+ document.addForm.add_ou.focus();
+}
+
+
+function submitAdd()
+{
+ var theForm = document.addForm;
+ var dn, dnSuffix, i, e, prod;
+
+ if ( theForm.add_ou.value.length == 0 ) {
+ alert( 'Please provide a name for the org. unit.' );
+ theForm.add_ou.focus();
+ return;
+ }
+
+ dn = 'ou=' + theForm.add_ou.value;
+ if ( theForm.CrLoc.type == 'hidden' ) {
+ dnSuffix = unescape( theForm.CrLoc.value );
+ } else {
+ dnSuffix = unescape(
+ theForm.CrLoc.options[ theForm.CrLoc.selectedIndex ].value );
+ }
+ if ( dnSuffix.length > 0 ) {
+ dn += ', ' + dnSuffix;
+ }
+ theForm.dn.value = escape(dn);
+
+ // execute selected product-specific default functions
+ for ( i = 0; i < theForm.elements.length; ++i ) {
+ e = theForm.elements[ i ];
+ if ( e.type == 'checkbox' &&
+ e.name.substring( 0, 17 ) == 'product_checkbox_' &&
+ e.checked ) {
+ prod = e.name.substring( 17, e.name.length );
+ if ( !eval( 'product_setdefaults_' + prod + '(theForm)' )) {
+ return; // submit vetoed by product
+ }
+ }
+ }
+
+ theForm.submit();
+}
+</SCRIPT>
+
+</HEAD>
+<!-- BODY "onLoad='resetForm()'" -->
+
+<CENTER><TABLE BORDER="2" CELLPADDING="10" WIDTH="100%">
+<TR><TD ALIGN="center" WIDTH="100%">
+<FONT SIZE="+2"><B>New Organizational Unit</B></FONT>
+</TD></TR></TABLE></CENTER>
+
+<!-- DS_LAST_OP_INFO "prefix=<P><FONT SIZE=%22%2B1%22>The organizational unit " "suffix=</FONT><HR>" -->
+
+<FORM METHOD="POST" ACTION="domodify" NAME="addForm">
+
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'genscreen?dscrou&info=\' + escape(dsmodify_info)">
+
+<INPUT TYPE="hidden" NAME="changetype" VALUE="add">
+<INPUT TYPE="hidden" NAME="dn" VALUE="">
+
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalUnit">
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+
+<DIV ALIGN="right"><FONT SIZE="-1">* Indicates a required field</FONT></DIV>
+
+<TABLE CELLSPACING="0" BORDER="0">
+<TR><TD ALIGN="right"><b>* Unit Name:</b></TD>
+<TD><INPUT type="text" name="add_ou" value="" size=32></TD></TR>
+<TR><TD ALIGN="right"><b>Description:</b></TD>
+<TD><INPUT type="text" name="add_description" value="" size=32></TD></TR>
+<!-- INCLUDESET dscrou -->
+<!-- DS_LOCATIONPOPUP "name=CrLoc" "prefix=<TR><TD ALIGN=%22right%22><b>Add Organizational Unit To:</b></TD><TD>" "suffix=</TD></TR>" "rootname=the top of the directory" -->
+</TABLE>
+<P>
+
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+ <INPUT TYPE="button" VALUE=" Create Organizational Unit "
+ onClick="submitAdd()"></TD>
+<TD WIDTH=33% ALIGN=center><INPUT TYPE="reset" VALUE=" Reset "
+ onClick="resetForm()"></TD>
+<TD WIDTH=33% ALIGN=center>
+<!-- HELPBUTTON "DSCROU" -->
+</TD>
+</TR></TABLE></CENTER>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/dscruser.html b/ldap/clients/dsgw/admhtml/dscruser.html
new file mode 100644
index 00000000..efddfbd2
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/dscruser.html
@@ -0,0 +1,172 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>User Management</TITLE>
+
+<SCRIPT language=JavaScript>
+var didSetDefaults = 0;
+
+
+function resetForm()
+{
+ didSetDefaults = 0;
+ document.addForm.add_givenname.focus();
+}
+
+
+function submitAdd()
+{
+ var theForm = document.addForm;
+ var dn, dnSuffix, i, e, prod;
+
+ if ( theForm.add_cn.value.length == 0 ) {
+ alert( 'Please provide the user\'s full name.' );
+ theForm.add_cn.focus();
+ return;
+ }
+ if ( theForm.add_sn.value.length == 0 ) {
+ alert( 'Please provide the user\'s surname.' );
+ theForm.add_sn.focus();
+ return;
+ }
+ if ( theForm.add_unique_uid.value.length == 0 ) {
+ alert( 'Please choose a user id for this user.' );
+ theForm.add_unique_uid.focus();
+ return;
+ }
+
+ dn = 'cn=' + theForm.add_cn.value;
+ if ( theForm.CrLoc.type == 'hidden' ) {
+ dnSuffix = unescape( theForm.CrLoc.value );
+ } else {
+ dnSuffix = unescape(
+ theForm.CrLoc.options[ theForm.CrLoc.selectedIndex ].value );
+ }
+ if ( dnSuffix.length > 0 ) {
+ dn += ', ' + dnSuffix;
+ }
+ theForm.dn.value = escape(dn);
+
+ // execute selected product-specific default functions
+ for ( i = 0; i < theForm.elements.length; ++i ) {
+ e = theForm.elements[ i ];
+ if ( e.type == 'checkbox' &&
+ e.name.substring( 0, 17 ) == 'product_checkbox_' &&
+ e.checked ) {
+ prod = e.name.substring( 17, e.name.length );
+ if ( !eval( 'product_setdefaults_' + prod + '(theForm)' )) {
+ return; // submit vetoed by product
+ }
+ }
+ }
+
+ theForm.submit();
+}
+
+
+function submitAddandEdit()
+{
+ document.addForm.completion_javascript.value =
+ "if (dsmodify_dn.length == 0) document.location.href=\"genscreen?dscruser&info=\" + escape(dsmodify_info); else document.location.href=\"edit/\" + dsmodify_dn + \"?&info=\" + escape(dsmodify_info);";
+
+ submitAdd();
+}
+
+
+function setDefaults()
+{
+ var theForm = document.addForm;
+
+ if ( theForm.add_cn.value.length == 0 ) {
+ theForm.add_cn.value = theForm.add_givenname.value + ' '
+ + theForm.add_sn.value;
+ if ( theForm.add_unique_uid.value.length == 0 ) {
+ theForm.add_unique_uid.value =
+ theForm.add_givenname.value.substring(0,1).toLowerCase()
+ + theForm.add_sn.value.toLowerCase();
+ }
+ didSetDefaults = 1;
+ }
+}
+
+
+function skipIfDefaulted()
+{
+// Make this function a NOP for now since it exercises a bug in NT Navigator
+// that makes the interface very confusing (see bug # 40412 in Scopus).
+// var theForm = document.addForm;
+//
+// if ( didSetDefaults == 1 ) {
+// didSetDefaults = 0;
+// document.addForm.newpasswd.focus();
+// }
+}
+
+</SCRIPT>
+
+</HEAD>
+<!-- BODY "onLoad='resetForm()'" -->
+
+<CENTER><TABLE BORDER="2" CELLPADDING="10" WIDTH="100%">
+<TR><TD ALIGN="center" WIDTH="100%">
+<FONT SIZE="+2"><B>New User</B></FONT>
+</TD></TR></TABLE></CENTER>
+
+<!-- DS_LAST_OP_INFO "prefix=<P><FONT SIZE=%22%2B1%22>The user " "suffix=</FONT><HR>" -->
+
+<FORM METHOD="POST" ACTION="domodify" NAME="addForm">
+
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'genscreen?dscruser&info=\' + escape(dsmodify_info)">
+
+<INPUT TYPE="hidden" NAME="changetype" VALUE="add">
+<INPUT TYPE="hidden" NAME="dn" VALUE="">
+
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+
+<DIV ALIGN="right"><FONT SIZE="-1">* Indicates a required field</FONT></DIV>
+
+<TABLE CELLSPACING="0" BORDER="0">
+<TR><TD NOWRAP ALIGN="right"><b>* Given Name (First Name):</b></TD>
+<TD><INPUT type="text" name="add_givenname" value="" size=32></TD></TR>
+<TR><TD NOWRAP ALIGN="right"><b>* Surname (Last Name):</b></TD>
+<TD><INPUT type="text" name="add_sn" value="" size=32
+ onBlur="setDefaults()"> </TD></TR>
+<TR><TD NOWRAP ALIGN="right"><b>* Full Name:</b></TD>
+<TD><INPUT type="text" name="add_cn" value="" size=32
+ onFocus="skipIfDefaulted()"></TD></TR>
+<TR><TD NOWRAP ALIGN="right"><b>* User ID:</b></TD>
+<TD><INPUT type="text" name="add_unique_uid" value="" size=20></TD></TR>
+<TR><TD NOWRAP ALIGN="right"><b>Password:</b></TD>
+<TD><INPUT type=password name="newpasswd" value="" size=20></TD></TR>
+<TR><TD NOWRAP ALIGN="right"><b>Password (Again):</b></TD>
+<TD><INPUT type=password name="newpasswdconfirm" value="" size=20></TD></TR>
+<TR><TD NOWRAP ALIGN="right"><b>E-Mail Address:</b></TD>
+<TD><INPUT type="text" name="add_mail" value="" size=32></TD></TR>
+<!-- INCLUDESET dscruser -->
+<!-- DS_LOCATIONPOPUP "name=CrLoc" "prefix=<TR><TD NOWRAP ALIGN=%22right%22><b>Add New User To:</b></TD><TD>" "suffix=</TD></TR>" "rootname=the top of the directory" -->
+</TABLE>
+<P>
+
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="25%" ALIGN="center"><INPUT TYPE="button" VALUE=" Create User "
+ onClick="submitAdd()"></TD>
+<TD WIDTH="25%" ALIGN="center">
+<INPUT TYPE="button" VALUE=" Create and Edit User "
+ onClick="submitAddandEdit()"></TD>
+<TD WIDTH=25% ALIGN=center><INPUT TYPE="reset" VALUE=" Reset "
+ onClick="resetForm()"></TD>
+<TD WIDTH=25% ALIGN=center>
+<!-- HELPBUTTON "DSCRUSER" -->
+</TD></TR></TABLE></CENTER>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/dsexpldif.html b/ldap/clients/dsgw/admhtml/dsexpldif.html
new file mode 100644
index 00000000..27326c72
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/dsexpldif.html
@@ -0,0 +1,76 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>User Management</TITLE>
+
+<SCRIPT language=JavaScript>
+var didSetDefaults = 0;
+
+function submitModify()
+{
+ var theForm = document.expForm;
+
+ // verify form fields
+ if ( theForm.ldif.value.length == 0 ) {
+ alert( 'Please provide the export ldif file name.' );
+ return false;
+ }
+
+ theForm.submit();
+ return false;
+}
+
+</SCRIPT>
+
+
+</HEAD>
+<!-- BODY -->
+
+<CENTER><TABLE BORDER="2" CELLPADDING="10" WIDTH="100%">
+<TR><TD ALIGN="center" WIDTH="100%">
+<FONT SIZE="+2"><B>Export Directory Information</B></FONT>
+</TD></TR></TABLE></CENTER>
+
+<!-- DS_INLINE_POST_RESULTS -->
+
+<FORM METHOD="POST" ACTION="dsexpldif" NAME="expForm">
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
+<TR>
+<TD ALIGN="right" NOWRAP><B>Export database to LDIF file:</B></TD>
+<TD><INPUT TYPE="text" NAME="ldif"
+<!-- DS_LDIF_FILE -->
+SIZE=40></TD>
+</TR>
+
+<!-- IF "DirectoryIsLocalDB" -->
+<TR>
+<TD ALIGN="right" NOWRAP><B>Suffix to add:</B></TD>
+<TD><INPUT TYPE="text" NAME="suffix"
+<!-- DS_SUFFIX -->
+SIZE=40></TD>
+</TR>
+<!-- ENDIF -->
+
+</TABLE>
+<P>
+
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center"><INPUT TYPE="button" VALUE=" Begin Export "
+ onClick="submitModify()"></TD>
+<TD WIDTH=34% ALIGN=center><INPUT TYPE="reset" VALUE=" Reset "
+ ></TD>
+<TD WIDTH=33% ALIGN=center>
+<!-- HELPBUTTON "DSEXPLDIF" -->
+</TD>
+</TR></TABLE></CENTER>
+</FORM>
+
+<P ALIGN="right"><FONT SIZE="-2">
+<!-- DS_GATEWAY_VERSION -->
+</FONT></P>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/dsimpldif.html b/ldap/clients/dsgw/admhtml/dsimpldif.html
new file mode 100644
index 00000000..24b0e065
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/dsimpldif.html
@@ -0,0 +1,85 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>User Management</TITLE>
+
+<SCRIPT language=JavaScript>
+var didSetDefaults = 0;
+
+function submitModify()
+{
+ var theForm = document.impForm;
+
+ // verify form fields
+ if ( theForm.ldif.value.length == 0 ) {
+ alert( 'Please provide the import ldif file name.' );
+ return false;
+ }
+
+ theForm.submit();
+ return false;
+}
+
+</SCRIPT>
+
+
+</HEAD>
+<!-- BODY -->
+
+<CENTER><TABLE BORDER="2" CELLPADDING="10" WIDTH="100%">
+<TR><TD ALIGN="center" WIDTH="100%">
+<FONT SIZE="+2"><B>Import Directory Information</B></FONT>
+</TD></TR></TABLE></CENTER>
+
+<!-- DS_INLINE_POST_RESULTS -->
+
+<FORM METHOD="POST" ACTION="dsimpldif" NAME="impForm">
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
+<TR>
+<TD ALIGN="right" NOWRAP><B>Import from LDIF file:</B></TD>
+<TD><INPUT TYPE="text" NAME="ldif"
+<!-- DS_LDIF_FILE -->
+SIZE=40></TD>
+</TR>
+
+<!-- IF "DirectoryIsLocalDB" -->
+<TR>
+<TD ALIGN="right" NOWRAP>&nbsp;</TD>
+<TD>
+<INPUT TYPE="checkbox" NAME="erase" VALUE="true"
+<!-- DS_CHECKED_IF_ERASE -->
+><B>Erase existing database</B></TD>
+</TD>
+</TR>
+<!-- ENDIF -->
+
+<TR>
+<TD ALIGN="right" NOWRAP>&nbsp;</TD>
+<TD>
+<INPUT TYPE="checkbox" NAME="stop"
+VALUE="true"
+<!-- DS_CHECKED_IF_STOP -->
+><B>Stop on errors</B>
+</TD>
+</TR>
+
+
+</TABLE>
+<P>
+
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center"><INPUT TYPE="button" VALUE=" Begin Import "
+ onClick="submitModify()"></TD>
+<TD WIDTH=34% ALIGN=center><INPUT TYPE="reset" VALUE=" Reset "
+ ></TD>
+<TD WIDTH=33% ALIGN=center>
+<!-- HELPBUTTON "DSIMPLDIF" -->
+</TD>
+</TR></TABLE></CENTER>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/dslsgroups.html b/ldap/clients/dsgw/admhtml/dslsgroups.html
new file mode 100644
index 00000000..b25abb33
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/dslsgroups.html
@@ -0,0 +1,164 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD><TITLE>Manage Groups</TITLE>
+
+<SCRIPT language=JavaScript>
+
+function doList()
+{
+ var theForm = document.listForm;
+ var baseDesc;
+
+ theForm.base.value = baseDN();
+ baseDesc = baseDescription();
+
+ if ( theForm.searchstring.value.length == 0 ) {
+ theForm.filterpattern.value = '(cn=*)';
+ theForm.searchdesc.value = '<BR>All groups ' + baseDesc;
+ return( true ); // submit the form
+ }
+
+ theForm.searchdesc.value = '<BR>Groups ' + baseDesc + ' whose <B>' +
+ theForm.attr.options[ theForm.attr.selectedIndex ].text + '</B> ' +
+ theForm.patternSelect.options[ theForm.patternSelect.selectedIndex
+ ].text + ' <B>' + theForm.searchstring.value + '</B>';
+
+ theForm.filterpattern.value = theForm.patternSelect.options[
+ theForm.patternSelect.selectedIndex ].value;
+
+ return( true ); // submit
+}
+
+function doEdit()
+{
+ var theForm = document.editForm;
+
+ if ( theForm.visiblesearchstring.value.length == 0 ) {
+ theForm.searchstring.value = '*'; // a bit of a hack
+ } else {
+ theForm.searchstring.value = theForm.visiblesearchstring.value;
+ }
+
+ theForm.listtemplate.value = document.listForm.listtemplate.options[
+ document.listForm.listtemplate.selectedIndex ].value;
+ theForm.base.value = baseDN();
+
+ return( true ); // submit the form
+}
+
+function baseDN()
+{
+ var theForm = document.listForm;
+ var escapedDN;
+
+ if ( theForm.encodedbase.type == 'hidden' ) {
+ escapedDN = theForm.encodedbase.value;
+ } else {
+ escapedDN = theForm.encodedbase.options[
+ theForm.encodedbase.selectedIndex ].value;
+ }
+
+ return( unescape( escapedDN ));
+}
+
+function baseDescription()
+{
+ var theForm = document.listForm;
+
+ if ( theForm.encodedbase.type == 'hidden' ) {
+ return( '' );
+ } else {
+ return( 'in ' + theForm.encodedbase.options[
+ theForm.encodedbase.selectedIndex ].text );
+ }
+}
+</SCRIPT>
+</HEAD>
+
+<!-- BODY "onLoad='document.editForm.visiblesearchstring.focus()'" -->
+
+<CENTER><TABLE BORDER="2" CELLPADDING="10" WIDTH="100%">
+<TR><TD ALIGN="center" WIDTH="100%">
+<FONT SIZE="+2"><B>Manage Groups</B></FONT>
+</TD></TR></TABLE></CENTER>
+
+<!-- DS_LAST_OP_INFO "prefix=<P><FONT SIZE=%22%2B1%22>The group " "suffix=</FONT><HR>" -->
+
+<FORM method="POST" ACTION="dosearch" NAME="editForm"
+ onSubmit="return doEdit()">
+<INPUT TYPE="hidden" NAME="mode" VALUE="smart">
+<INPUT TYPE="hidden" NAME="type" VALUE="groups">
+<INPUT TYPE="hidden" NAME="link2edit" VALUE="true">
+<INPUT TYPE="hidden" NAME="editable" VALUE="true">
+<INPUT TYPE="hidden" NAME="goback" VALUE="Return To Manage Groups Screen">
+<INPUT TYPE="hidden" NAME="base" VALUE="">
+<INPUT TYPE="hidden" NAME="listtemplate" VALUE="">
+<INPUT TYPE="hidden" NAME="searchstring" VALUE="">
+<B>Find group:</B><BR>
+<INPUT TYPE="text" NAME="visiblesearchstring" SIZE=25 VALUE="">
+<INPUT TYPE="submit" VALUE=" Find ">
+</FORM>
+
+<FORM METHOD="POST" ACTION="dosearch" NAME="listForm"
+ onSubmit="return doList()">
+
+<INPUT TYPE="hidden" NAME="mode" VALUE="pattern">
+<INPUT TYPE="hidden" NAME="type" VALUE="Groups">
+<INPUT TYPE="hidden" NAME="filterprefix"
+ VALUE="(&(|(objectclass=groupofuniquenames)(objectclass=groupofnames))">
+<INPUT TYPE="hidden" NAME="filtersuffix" VALUE=")">
+<INPUT TYPE="hidden" NAME="filterpattern" VALUE="">
+<INPUT TYPE="hidden" NAME="searchdesc" VALUE="">
+<INPUT TYPE="hidden" NAME="listifone" VALUE="true">
+<INPUT TYPE="hidden" NAME="link2edit" VALUE="true">
+<INPUT TYPE="hidden" NAME="goback" VALUE="Return To Manage Groups Screen">
+<INPUT TYPE="hidden" NAME="base" VALUE="">
+
+<B>Find all groups whose:</B>
+<BR>
+
+<NOBR>
+<SELECT name="attr">
+<OPTION VALUE="cn">name
+<OPTION VALUE="description">description
+</SELECT>
+
+<SELECT name="patternSelect">
+<OPTION VALUE="(%a=*%v*)">contains
+<OPTION VALUE="(%a=%v)">is
+<OPTION VALUE="(!(%a=%v))">isn't
+<OPTION VALUE="(%a~=%v)">sounds like
+<OPTION VALUE="(%a=%v*)">starts with
+<OPTION VALUE="(%a=*%v)">ends with
+</SELECT>
+<INPUT TYPE="text" NAME="searchstring" VALUE="" SIZE="17">
+<INPUT TYPE="submit" VALUE=" Find "></TD>
+</NOBR>
+
+<SPACER TYPE=vertical SIZE=20>
+<TABLE BORDER=0>
+<!-- DS_LOCATIONPOPUP "name=encodedbase" "prefix=<TR><TD><B>Look within:</B></TD><TD>" "suffix="</TD></TR>" -->
+</TD></TR>
+<TR><TD>
+<B>Format:</B></TD><TD>
+<SELECT name="listtemplate">
+<OPTION VALUE="Groups">On-Screen
+<OPTION VALUE="Groups-report">Printer
+</SELECT>
+</TD></TR></TABLE>
+
+<SPACER TYPE=vertical SIZE=5>
+<TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="50%" ALIGN="center"><INPUT TYPE="reset" VALUE=" Reset "></TD>
+<TD WIDTH="50%" ALIGN="center">
+<!-- HELPBUTTON "DSLSGROUP" -->
+</TD></TR></TABLE>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/dslsous.html b/ldap/clients/dsgw/admhtml/dslsous.html
new file mode 100644
index 00000000..90a58f07
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/dslsous.html
@@ -0,0 +1,172 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD><TITLE>Manage Organizational Units </TITLE>
+
+<SCRIPT language=JavaScript>
+
+function doList()
+{
+ var theForm = document.listForm;
+ var baseDesc;
+
+ theForm.base.value = baseDN();
+ baseDesc = baseDescription();
+
+ if ( theForm.searchstring.value.length == 0 ) {
+ theForm.filterpattern.value = '(ou=*)';
+ theForm.searchdesc.value = '<BR>All organizational units ' + baseDesc;
+ return( true ); // submit the form
+ }
+
+ if ( theForm.searchstring.value.length == 0 ) {
+ alert( 'Please supply a filter string.' );
+ return( false ); // cancel the submit
+ }
+
+ theForm.searchdesc.value = '<BR>Organizational units ' + baseDesc
+ + ' whose <B>' +
+ theForm.attr.options[ theForm.attr.selectedIndex ].text + '</B> ' +
+ theForm.patternSelect.options[ theForm.patternSelect.selectedIndex
+ ].text + ' <B>' + theForm.searchstring.value + '</B>';
+
+ theForm.filterpattern.value = theForm.patternSelect.options[
+ theForm.patternSelect.selectedIndex ].value;
+
+ return( true ); // submit
+}
+
+function doEdit()
+{
+ var theForm = document.editForm;
+
+ if ( theForm.visiblesearchstring.value.length == 0 ) {
+ theForm.searchstring.value = '*'; // a bit of a hack
+ } else {
+ theForm.searchstring.value = theForm.visiblesearchstring.value;
+ }
+
+ theForm.listtemplate.value = document.listForm.listtemplate.options[
+ document.listForm.listtemplate.selectedIndex ].value;
+ theForm.base.value = baseDN();
+
+ return( true ); // submit the form
+}
+
+function baseDN()
+{
+ var theForm = document.listForm;
+ var escapedDN;
+
+ if ( theForm.encodedbase.type == 'hidden' ) {
+ escapedDN = theForm.encodedbase.value;
+ } else {
+ escapedDN = theForm.encodedbase.options[
+ theForm.encodedbase.selectedIndex ].value;
+ }
+
+ return( unescape( escapedDN ));
+}
+
+function baseDescription()
+{
+ var theForm = document.listForm;
+
+ if ( theForm.encodedbase.type == 'hidden' ) {
+ return( '' );
+ } else {
+ return( 'in ' + theForm.encodedbase.options[
+ theForm.encodedbase.selectedIndex ].text );
+ }
+}
+</SCRIPT>
+</HEAD>
+
+<!-- BODY "onLoad='document.editForm.visiblesearchstring.focus()'" -->
+
+<CENTER><TABLE BORDER="2" CELLPADDING="10" WIDTH="100%">
+<TR><TD ALIGN="center" WIDTH="100%">
+<FONT SIZE="+2"><B>Manage Organizational Units</B></FONT>
+</TD></TR></TABLE></CENTER>
+
+<!-- DS_LAST_OP_INFO "prefix=<P><FONT SIZE=%22%2B1%22>The organizational unit " "suffix=</FONT><HR>" -->
+
+<FORM method="POST" ACTION="dosearch" NAME="editForm"
+ onSubmit="return doEdit()">
+<INPUT TYPE="hidden" NAME="mode" VALUE="smart">
+<INPUT TYPE="hidden" NAME="type" VALUE="org-units">
+<INPUT TYPE="hidden" NAME="link2edit" VALUE="true">
+<INPUT TYPE="hidden" NAME="editable" VALUE="true">
+<INPUT TYPE="hidden" NAME="goback"
+ VALUE="Return To Manage Organizational Units Screen">
+<INPUT TYPE="hidden" NAME="base" VALUE="">
+<INPUT TYPE="hidden" NAME="listtemplate" VALUE="">
+<INPUT TYPE="hidden" NAME="searchstring" VALUE="">
+<B>Find organizational unit:</B><BR>
+<INPUT TYPE="text" NAME="visiblesearchstring" SIZE=25 VALUE="">
+<INPUT TYPE="submit" VALUE=" Find ">
+</FORM>
+
+<FORM METHOD="POST" ACTION="dosearch" NAME="listForm"
+ onSubmit="return doList()">
+
+<INPUT TYPE="hidden" NAME="mode" VALUE="pattern">
+<INPUT TYPE="hidden" NAME="type" VALUE="OrgUnits">
+<INPUT TYPE="hidden" NAME="filterprefix"
+ VALUE="(&(objectclass=organizationalunit)">
+<INPUT TYPE="hidden" NAME="filtersuffix" VALUE=")">
+<INPUT TYPE="hidden" NAME="filterpattern" VALUE="">
+<INPUT TYPE="hidden" NAME="searchdesc" VALUE="">
+<INPUT TYPE="hidden" NAME="listifone" VALUE="true">
+<INPUT TYPE="hidden" NAME="link2edit" VALUE="true">
+<INPUT TYPE="hidden" NAME="goback"
+ VALUE="Return To Manage Organizational Units Screen">
+<INPUT TYPE="hidden" NAME="base" VALUE="">
+
+<B>Find all units whose:</B>
+<BR>
+
+<NOBR>
+<SELECT name="attr">
+<OPTION VALUE="ou">unit name
+<OPTION VALUE="description">description
+</SELECT>
+
+<SELECT name="patternSelect">
+<OPTION VALUE="(%a=*%v*)">contains
+<OPTION VALUE="(%a=%v)">is
+<OPTION VALUE="(!(%a=%v))">isn't
+<OPTION VALUE="(%a~=%v)">sounds like
+<OPTION VALUE="(%a=%v*)">starts with
+<OPTION VALUE="(%a=*%v)">ends with
+</SELECT>
+<INPUT TYPE="text" NAME="searchstring" VALUE="" SIZE="17">
+<INPUT TYPE="submit" VALUE=" Find ">
+</NOBR>
+
+<SPACER TYPE=vertical SIZE=20>
+<TABLE BORDER=0>
+<!-- DS_LOCATIONPOPUP "name=encodedbase" "prefix=<TR><TD><B>Look within:</B></TD><TD>" "suffix="</TD></TR>" -->
+</TD></TR>
+<TR><TD>
+<B>Format:</B></TD><TD>
+<SELECT name="listtemplate">
+<OPTION VALUE="OrgUnits">On-Screen
+<OPTION VALUE="OrgUnits-report">Printer
+</SELECT>
+</TD></TR></TABLE>
+
+<SPACER TYPE=vertical SIZE=5>
+<TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="50%" ALIGN="center"><INPUT TYPE="reset" VALUE=" Reset "></TD>
+<TD WIDTH="50%" ALIGN="center">
+<!-- HELPBUTTON "DSLSOUS" -->
+</TD></TR></TABLE>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/dslsusers.html b/ldap/clients/dsgw/admhtml/dslsusers.html
new file mode 100644
index 00000000..90cf49fa
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/dslsusers.html
@@ -0,0 +1,166 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD><TITLE>Manage Users</TITLE>
+
+<SCRIPT language=JavaScript>
+
+function doList()
+{
+ var theForm = document.listForm;
+ var baseDesc;
+
+ theForm.base.value = baseDN();
+ baseDesc = baseDescription();
+
+ if ( theForm.searchstring.value.length == 0 ) {
+ theForm.filterpattern.value = '(cn=*)';
+ theForm.searchdesc.value = '<BR>All users ' + baseDesc;
+ return( true ); // submit the form
+ }
+
+ theForm.searchdesc.value = '<BR>Users ' + baseDesc + ' whose <B>' +
+ theForm.attr.options[ theForm.attr.selectedIndex ].text + '</B> ' +
+ theForm.patternSelect.options[ theForm.patternSelect.selectedIndex
+ ].text + ' <B>' + theForm.searchstring.value + '</B>';
+
+ theForm.filterpattern.value = theForm.patternSelect.options[
+ theForm.patternSelect.selectedIndex ].value;
+
+ return( true ); // submit
+}
+
+function doEdit()
+{
+ var theForm = document.editForm;
+
+ if ( theForm.visiblesearchstring.value.length == 0 ) {
+ theForm.searchstring.value = '*'; // a bit of a hack
+ } else {
+ theForm.searchstring.value = theForm.visiblesearchstring.value;
+ }
+
+ theForm.listtemplate.value = document.listForm.listtemplate.options[
+ document.listForm.listtemplate.selectedIndex ].value;
+ theForm.base.value = baseDN();
+
+ return( true ); // submit the form
+}
+
+function baseDN()
+{
+ var theForm = document.listForm;
+ var escapedDN;
+
+ if ( theForm.encodedbase.type == 'hidden' ) {
+ escapedDN = theForm.encodedbase.value;
+ } else {
+ escapedDN = theForm.encodedbase.options[
+ theForm.encodedbase.selectedIndex ].value;
+ }
+
+ return( unescape( escapedDN ));
+}
+
+function baseDescription()
+{
+ var theForm = document.listForm;
+
+ if ( theForm.encodedbase.type == 'hidden' ) {
+ return( '' );
+ } else {
+ return( 'in ' + theForm.encodedbase.options[
+ theForm.encodedbase.selectedIndex ].text );
+ }
+}
+</SCRIPT>
+</HEAD>
+
+<!-- BODY "onLoad='document.editForm.visiblesearchstring.focus()'" -->
+
+<CENTER><TABLE BORDER="2" CELLPADDING="10" WIDTH="100%">
+<TR><TD ALIGN="center" WIDTH="100%">
+<FONT SIZE="+2"><B>Manage Users</B></FONT>
+</TD></TR></TABLE></CENTER>
+
+<!-- DS_LAST_OP_INFO "prefix=<P><FONT SIZE=%22%2B1%22>The user " "suffix=</FONT><HR>" -->
+
+<FORM METHOD="POST" ACTION="dosearch" NAME="editForm"
+ onSubmit="return doEdit()">
+<INPUT TYPE="hidden" NAME="mode" value="smart">
+<INPUT TYPE="hidden" NAME="type" value="People">
+<INPUT TYPE="hidden" NAME="editable" value="true">
+<INPUT TYPE="hidden" NAME="link2edit" value="true">
+<INPUT TYPE="hidden" NAME="goback" value="Return To Manage Users Screen">
+<INPUT TYPE="hidden" NAME="base" VALUE="">
+<INPUT TYPE="hidden" NAME="listtemplate" VALUE="">
+<INPUT TYPE="hidden" NAME="searchstring" VALUE="">
+<B>Find user:</B><BR>
+<INPUT TYPE="text" NAME="visiblesearchstring" SIZE=25 VALUE="">
+<INPUT TYPE="submit" VALUE=" Find ">
+</FORM>
+
+<FORM METHOD="POST" ACTION="dosearch" NAME="listForm"
+ onSubmit="return doList()">
+<INPUT TYPE="hidden" NAME="mode" VALUE="pattern">
+<INPUT TYPE="hidden" NAME="type" VALUE="People">
+<INPUT TYPE="hidden" NAME="filterprefix" VALUE="(&(objectclass=person)">
+<INPUT TYPE="hidden" NAME="filtersuffix" VALUE=")">
+<INPUT TYPE="hidden" NAME="filterpattern" VALUE="">
+<INPUT TYPE="hidden" NAME="searchdesc" VALUE="">
+<INPUT TYPE="hidden" NAME="listifone" VALUE="true">
+<INPUT TYPE="hidden" NAME="link2edit" VALUE="true">
+<INPUT TYPE="hidden" NAME="goback" VALUE="Return To Manage Users Screen">
+<INPUT TYPE="hidden" NAME="base" VALUE="">
+
+<B>Find all users whose:</B>
+<BR>
+
+<NOBR>
+<SELECT name="attr">
+<OPTION VALUE="cn">full name
+<OPTION VALUE="sn">last name
+<OPTION VALUE="uid">user id
+<OPTION VALUE="telephonenumber">phone number
+<OPTION VALUE="mail">email address
+</SELECT>
+
+<SELECT name="patternSelect">
+<OPTION VALUE="(%a=*%v*)">contains
+<OPTION VALUE="(%a=%v)">is
+<OPTION VALUE="(!(%a=%v))">isn't
+<OPTION VALUE="(%a~=%v)">sounds like
+<OPTION VALUE="(%a=%v*)">starts with
+<OPTION VALUE="(%a=*%v)">ends with
+</SELECT>
+<INPUT TYPE="text" NAME="searchstring" VALUE="" SIZE="17">
+<INPUT TYPE="submit" VALUE=" Find "></TD>
+</NOBR>
+
+<SPACER TYPE=vertical SIZE=20>
+
+<TABLE BORDER=0>
+<!-- DS_LOCATIONPOPUP "name=encodedbase" "prefix=<TR><TD><B>Look within:</B></TD><TD>" "suffix="</TD></TR>" -->
+</TD></TR>
+<TR><TD>
+<B>Format:</B></TD><TD>
+<SELECT name="listtemplate">
+<OPTION VALUE="People">On-Screen
+<OPTION VALUE="People-report">Printer
+</SELECT>
+</TD></TR></TABLE>
+
+<SPACER TYPE=vertical SIZE=5>
+<TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="50%" ALIGN="center"><INPUT TYPE="reset" VALUE=" Reset "></TD>
+<TD WIDTH="50%" ALIGN="center">
+<!-- HELPBUTTON "DSLSUSERS" -->
+</TD></TR></TABLE>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/edit-passwd.html b/ldap/clients/dsgw/admhtml/edit-passwd.html
new file mode 100644
index 00000000..f65d3814
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/edit-passwd.html
@@ -0,0 +1,103 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- change a directory entry's password -->
+
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+<!-- IF "BoundAsThisEntry" -->
+Set
+<!-- ELSE -->
+Change
+<!-- ENDIF -->
+Password -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+</HEAD>
+
+<!-- BODY -->
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+
+function
+disableUser()
+{
+ if ( confirm( "Password-based access will be disabled by setting this " +
+ "user's password to an invalid value. Proceed?" )) {
+ document.modifyEntryForm.lockpasswd.value = 'true';
+ submitModify( 'modify', null );
+ }
+}
+
+// End hiding -->
+</SCRIPT>
+
+<FONT SIZE="+2">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<!-- DS_VIEW_SWITCHER -->
+
+<P>
+<TABLE>
+
+<!-- IF "BoundAsThisEntry" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+<B>Current password:</B>
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ENDIF //BoundAsThisEntry -->
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+<B>New password:</B>
+</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD></TR>
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+<B>New password (again):</B>
+</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+</TABLE>
+
+<P>
+
+<TABLE BORDER=2 WIDTH="100%">
+<TR>
+<TD ALIGN="center" WIDTH="33%">
+<!-- IF "BoundAsThisEntry" -->
+<!-- DS_SAVEBUTTON "label=Change Password" -->
+<!-- ELSE -->
+<!-- DS_SAVEBUTTON "label=Set Password" -->
+<!-- ENDIF -->
+<TD ALIGN="center" WIDTH="34%">
+<INPUT TYPE="button" VALUE="Disable Password" onClick="disableUser()" -->
+<TD ALIGN="center" WIDTH="33%">
+<!-- DS_HELPBUTTON "topic=MODIFYPASSWD" -->
+</TABLE>
+
+
+<!-- this next hidden field is used by the "Disable Password" feature -->
+<INPUT TYPE="hidden" NAME="lockpasswd" VALUE="false">
+
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'edit/\' + dsmodify_dn + \'?passwd&info=\' + escape(dsmodify_info)">
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/index.lst b/ldap/clients/dsgw/admhtml/index.lst
new file mode 100644
index 00000000..aea03131
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/index.lst
@@ -0,0 +1,87 @@
+;-------------------------------------------------------------------------
+; PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+; license terms. Copyright © 2001 Sun Microsystems, Inc.
+; Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+; All rights reserved.
+;-------------------------------------------------------------------------
+; Netscape admin index page master list
+;
+; Lines beginning with a ';' are comments
+; Lines beginning with '--' are dividers:
+; '--Category:[ID,NAME]' is the title of the category of options,
+; with short identifier ID and text NAME
+; '--TabIcon:[ICON]' is the name of the icon that goes on top
+; (assumes a suffix of '_on.gif' for on icon,
+; '_off.gif' for off)
+; (ex: for "users", would have URL "users" which points
+; to "users_on.gif" and "users_off.gif")
+; '--Icon:[URL]' is the icon to associate with those options
+; '--Option:[URL,TXT]' is the URL that the option should point to,
+; and the text that should be used to describe
+; it
+;
+; NOTE: Do NOT let a line have unterminated quotes, double slash
+; characters, pound signs, or slash star sequences. This file
+; is sent through the C preprocessor and that can screw it up.
+
+--Category:pref,System Settings
+--TabIcon:pref
+--Icon:prefer.gif
+--Option:stopadm,Shut Down
+--Option:confadm,Network Settings
+--Option:confopt,Logging Options
+#if defined(XP_UNIX)
+--Option:cronctrl,Cron Control
+--Option:snmpcomm,SNMP Master Agent Community
+--Option:snmptrpc,SNMP Master Agent Trap
+#endif
+--Option:
+--Option:dsconfig,Configure Directory Service
+
+--Category:acss,Access Control
+--TabIcon:acss
+--Icon:access.gif
+--Option:confacc,Admin password
+--Option:distadm,Distributed Admin
+--Option:distacl,Add Permission
+
+--Category:secy,Encryption
+--TabIcon:secy
+--Icon:encrypt.gif
+--Option:sec-pref,Security Preferences
+--Option:sec-gkey,Generate Key
+--Option:sec-pswd,Change Key Password
+--Option:sec-gcrt,Request Certificate
+--Option:sec-icrt,Install Certificate
+--Option:sec-mcrt,Manage Certificates
+
+--Category:clst,Cluster Management
+--TabIcon:clst
+--Icon:cluster.gif
+--Option:clctrl,Cluster Control
+--Option:cladd,Add Server
+--Option:clmod,Modify Server
+--Option:clrem,Remove Server
+
+--Category:user,Users and Groups
+--TabIcon:user
+--Icon:users.gif
+--Option:genscreen?dscruser,Create User
+--Option:genscreen?dseduser,Edit User
+--Option:genscreen?dsrmuser,Remove User
+--Option:genscreen?dslsusers,List Users
+--Option:
+--Option:genscreen?dscrgroup,Create Group
+--Option:genscreen?dsedgroup,Edit Group
+--Option:genscreen?dsrmgroup,Remove Group
+--Option:genscreen?dslsgroups,List Groups
+
+--Option:
+--Option:genscreen?dscrou,Create Organizational Unit (OU)
+--Option:genscreen?dsedou,Edit OU
+--Option:genscreen?dsrmou,Remove OU
+--Option:genscreen?dslsous,List OUs
+
+--Option:
+--Option:dsimpldif,Import
+--Option:dsexpldif,Export
diff --git a/ldap/clients/dsgw/admhtml/list-Anything.html b/ldap/clients/dsgw/admhtml/list-Anything.html
new file mode 100644
index 00000000..a4d47431
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-Anything.html
@@ -0,0 +1,42 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for Anything" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Name <TH NOWRAP>Phone Number
+<TH NOWRAP>E-Mail Address <TH NOWRAP>Description
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Please try a different search.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-Auth.html b/ldap/clients/dsgw/admhtml/list-Auth.html
new file mode 100644
index 00000000..cee812d3
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-Auth.html
@@ -0,0 +1,72 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Authenticate as..." -->
+
+<!--
+ The "authForm" form and the authSubmit() JavaScript function are
+ used to avoid the need for a separate form for each entry listed.
+ Each entry is tied to this single form through the magic of an
+ anchor that contains href=javascript:authSubmit().
+-->
+
+<FORM NAME="authForm" METHOD=POST ACTION="/clients/dsgw/bin/auth">
+<INPUT TYPE="hidden" NAME="escapedbinddn">
+<INPUT TYPE="hidden" NAME="authdesturl"
+<!-- DS_POSTEDVALUE "name=authdesturl" "within=VALUE=%22--value--%22" -->
+>
+</FORM>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function authSubmit(encodeddn)
+{
+ document.authForm.escapedbinddn.value = encodeddn;
+ document.authForm.submit();
+}
+// End hiding -->
+</SCRIPT>
+
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC "VERBOSE" -->
+<P>
+<!-- IF "FoundEntries" -->
+Please click on the name of the entry you would like to use for authentication.
+</FONT>
+<P>
+
+<TABLE BORDER=1 CELLPADDING=4>
+<TR>
+<TH NOWRAP>Authenticate As <TH NOWRAP>Title
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:authSubmit('--value--'); onMouseOver=%22window.status='Click to authenticate'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+<!-- ELSE "FoundEntries" -->
+Please go back and try again.
+<!-- ENDIF "FoundEntries" -->
+</CENTER>
+
+<FORM>
+<TABLE BORDER=2 WIDTH=100%%>
+<TR>
+<TD ALIGN=center width=50%%>
+<INPUT TYPE="button" VALUE="Go Back" onClick="history.back();">
+<TD ALIGN=center WIDTH=50%%>
+<!-- DS_HELPBUTTON "topic=AUTHMULTMATCH" -->
+</TABLE>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-Groups-report.html b/ldap/clients/dsgw/admhtml/list-Groups-report.html
new file mode 100644
index 00000000..89a4bfc6
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-Groups-report.html
@@ -0,0 +1,56 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "List of Groups" -->
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+<!-- DS_SEARCHDESC -->
+<P>
+
+<!-- IF "FoundEntries" -->
+<P>
+<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
+<TR>
+<TH ALIGN="left" NOWRAP><FONT SIZE="-3"><B>Group Name</B></FONT>
+<TH ALIGN="left" NOWRAP><FONT SIZE="-3"><B>Description</B></FONT>
+</TR>
+
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- Make sure attrs in lists are read-only. If they aren't, they're rendered
+ as INPUT fields, but since we're not in a form here, they don't display
+ at all.
+-->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP><FONT SIZE="-3">
+<!-- DS_ATTRIBUTE "attr=cn" "options=readonly" -->
+</FONT></TD>
+<TD NOWRAP><FONT SIZE="-3">
+<!-- DS_ATTRIBUTE "attr=description" "options=readonly" -->
+</FONT>
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-Groups-rm.html b/ldap/clients/dsgw/admhtml/list-Groups-rm.html
new file mode 100644
index 00000000..54973ad9
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-Groups-rm.html
@@ -0,0 +1,80 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function deleteEntry(encodeddn)
+{
+ if ( confirm( 'Are you sure you want to remove this group?' )) {
+ document.deleteForm.dn.value = encodeddn;
+ document.deleteForm.submit();
+ }
+}
+// End hiding -->
+</SCRIPT>
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+
+<FORM NAME="deleteForm" method="POST" ACTION="domodify">
+<INPUT TYPE="hidden" NAME="changetype" VALUE="delete">
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="dn" VALUE="">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'genscreen?dsrmgroup&info=\' + escape(dsmodify_info);">
+</FORM>
+
+<FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT>
+<P>
+
+<!-- IF "FoundEntries" -->
+<FONT SIZE=+1>
+Click on a group to remove it.
+</FONT>
+<P>
+<FORM>
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Group Name
+<TH NOWRAP>Description
+</TR>
+
+<!-- DS_SORTENTRIES -->
+
+<!-- Make sure attrs in lists are read-only. If they aren't, they're rendered
+ as INPUT fields, but since we're not in a form here, they don't display
+ at all.
+-->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:deleteEntry('--value--'); onMouseOver=%22window.status='Click here to remove this group'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "options=readonly"-->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+</FORM>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-Groups.html b/ldap/clients/dsgw/admhtml/list-Groups.html
new file mode 100644
index 00000000..50a86e0f
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-Groups.html
@@ -0,0 +1,62 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for Groups" -->
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+
+<FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Group Name
+<TH NOWRAP>Description
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "options=readonly"-->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- "Faceless" form which holds (initial) values for domodify -->
+<FORM NAME="modifyForm" ACTION="/admin-serv/bin/domodify" METHOD="POST">
+
+<INPUT TYPE="hidden" NAME="changetype" VALUE="modify">
+<INPUT TYPE="hidden" NAME="dn" VALUE="
+<!-- DS_FA_GROUPDN -->
+">
+<INPUT TYPE="hidden" NAME="add_
+<!-- DS_FA_ATTRNAME -->
+" VALUE="">
+
+
+</FORM>
+
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-Org-Units.html b/ldap/clients/dsgw/admhtml/list-Org-Units.html
new file mode 100644
index 00000000..48cf1b4f
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-Org-Units.html
@@ -0,0 +1,62 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for Organizational Units" -->
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+
+<FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Unit Name
+<TH NOWRAP>Description
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "options=readonly"-->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- "Faceless" form which holds (initial) values for domodify -->
+<FORM NAME="modifyForm" ACTION="/admin-serv/bin/domodify" METHOD="POST">
+
+<INPUT TYPE="hidden" NAME="changetype" VALUE="modify">
+<INPUT TYPE="hidden" NAME="dn" VALUE="
+<!-- DS_FA_GROUPDN -->
+">
+<INPUT TYPE="hidden" NAME="add_
+<!-- DS_FA_ATTRNAME -->
+" VALUE="">
+
+
+</FORM>
+
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-OrgUnits-report.html b/ldap/clients/dsgw/admhtml/list-OrgUnits-report.html
new file mode 100644
index 00000000..0d956628
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-OrgUnits-report.html
@@ -0,0 +1,56 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "List of Organizational Units" -->
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+<!-- DS_SEARCHDESC -->
+<P>
+
+<!-- IF "FoundEntries" -->
+<P>
+<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
+<TR>
+<TH ALIGN="left" NOWRAP><FONT SIZE="-3"><B>Unit Name</B></FONT>
+<TH ALIGN="left" NOWRAP><FONT SIZE="-3"><B>Description</B></FONT>
+</TR>
+
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- Make sure attrs in lists are read-only. If they aren't, they're rendered
+ as INPUT fields, but since we're not in a form here, they don't display
+ at all.
+-->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP><FONT SIZE="-3">
+<!-- DS_ATTRIBUTE "attr=ou" "options=readonly" -->
+</FONT></TD>
+<TD NOWRAP><FONT SIZE="-3">
+<!-- DS_ATTRIBUTE "attr=description" "options=readonly" -->
+</FONT>
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-OrgUnits.html b/ldap/clients/dsgw/admhtml/list-OrgUnits.html
new file mode 100644
index 00000000..48cf1b4f
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-OrgUnits.html
@@ -0,0 +1,62 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for Organizational Units" -->
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+
+<FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Unit Name
+<TH NOWRAP>Description
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "options=readonly"-->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- "Faceless" form which holds (initial) values for domodify -->
+<FORM NAME="modifyForm" ACTION="/admin-serv/bin/domodify" METHOD="POST">
+
+<INPUT TYPE="hidden" NAME="changetype" VALUE="modify">
+<INPUT TYPE="hidden" NAME="dn" VALUE="
+<!-- DS_FA_GROUPDN -->
+">
+<INPUT TYPE="hidden" NAME="add_
+<!-- DS_FA_ATTRNAME -->
+" VALUE="">
+
+
+</FORM>
+
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-Organizations.html b/ldap/clients/dsgw/admhtml/list-Organizations.html
new file mode 100644
index 00000000..67b028f7
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-Organizations.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for Organizations" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Organization <TH>Description <TH>Phone Number
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Please try a different search.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-Ous-rm.html b/ldap/clients/dsgw/admhtml/list-Ous-rm.html
new file mode 100644
index 00000000..1f4e1677
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-Ous-rm.html
@@ -0,0 +1,80 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function deleteEntry(encodeddn)
+{
+ if ( confirm( 'Are you sure you want to remove this organizational unit?' )) {
+ document.deleteForm.dn.value = encodeddn;
+ document.deleteForm.submit();
+ }
+}
+// End hiding -->
+</SCRIPT>
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+
+<FORM NAME="deleteForm" method="POST" ACTION="domodify">
+<INPUT TYPE="hidden" NAME="changetype" VALUE="delete">
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="dn" VALUE="">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'genscreen?dsrmou&info=\' + escape(dsmodify_info);">
+</FORM>
+
+<FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT>
+<P>
+
+<!-- IF "FoundEntries" -->
+<FONT SIZE=+1>
+Click on an organizational unit to remove it.
+</FONT>
+<P>
+<FORM>
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Unit Name
+<TH NOWRAP>Description
+</TR>
+
+<!-- DS_SORTENTRIES -->
+
+<!-- Make sure attrs in lists are read-only. If they aren't, they're rendered
+ as INPUT fields, but since we're not in a form here, they don't display
+ at all.
+-->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:deleteEntry('--value--'); onMouseOver=%22window.status='Click here to remove this org unit'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "options=readonly"-->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+</FORM>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-People-report.html b/ldap/clients/dsgw/admhtml/list-People-report.html
new file mode 100644
index 00000000..8eb33a3e
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-People-report.html
@@ -0,0 +1,60 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "List of People" -->
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+<!-- DS_SEARCHDESC -->
+<P>
+
+<!-- IF "FoundEntries" -->
+<P>
+<TABLE BORDER=1 CELLPADDING=0 CELLSPACING=0 WIDTH=100%>
+<TR>
+<TH ALIGN="left" NOWRAP><FONT SIZE="-3"><B>Name</B></FONT>
+<TH ALIGN="left" NOWRAP><FONT SIZE="-3"><B>User ID</B></FONT>
+<TH ALIGN="left" NOWRAP><FONT SIZE="-3"><B>Title</B></FONT>
+</TR>
+
+<!-- DS_SORTENTRIES "attr=sn" -->
+
+<!-- Make sure attrs in lists are read-only. If they aren't, they're rendered
+ as INPUT fields, but since we're not in a form here, they don't display
+ at all.
+-->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP><FONT SIZE="-3">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink">
+</FONT>
+<TD NOWRAP><FONT SIZE="-3">
+<!-- DS_ATTRIBUTE "attr=uid" "options=readonly" -->
+<TD NOWRAP><FONT SIZE="-3">
+</FONT>
+<!-- DS_ATTRIBUTE "attr=title" "options=readonly" -->
+</FONT>
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-People-rm.html b/ldap/clients/dsgw/admhtml/list-People-rm.html
new file mode 100644
index 00000000..bdacf2f1
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-People-rm.html
@@ -0,0 +1,81 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function deleteEntry(encodeddn)
+{
+ if ( confirm( 'Are you sure you want to remove this user?' )) {
+ document.deleteForm.dn.value = encodeddn;
+ document.deleteForm.submit();
+ }
+}
+// End hiding -->
+</SCRIPT>
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+
+<FORM NAME="deleteForm" method="POST" ACTION="domodify">
+<INPUT TYPE="hidden" NAME="changetype" VALUE="delete">
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="dn" VALUE="">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'genscreen?dsrmuser&info=\' + escape(dsmodify_info);">
+</FORM>
+
+<FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT>
+<P>
+
+<!-- IF "FoundEntries" -->
+<FONT SIZE=+1>
+Click on a user's name to remove them.
+</FONT>
+<P>
+<FORM>
+<TABLE BORDER=1 CELLPADDING=1 CELLSPACING=0 WIDTH=100%>
+<TR>
+<TH NOWRAP>Name<TH NOWRAP>User ID<TH NOWRAP>Title
+</TR>
+
+<!-- DS_SORTENTRIES "attr=sn" -->
+
+<!-- Make sure attrs in lists are read-only. If they aren't, they're rendered
+ as INPUT fields, but since we're not in a form here, they don't display
+ at all.
+-->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:deleteEntry('--value--'); onMouseOver=%22window.status='Click here to remove this user'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=uid" "options=readonly" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" "options=readonly" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+</FORM>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-People.html b/ldap/clients/dsgw/admhtml/list-People.html
new file mode 100644
index 00000000..0e023dd9
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-People.html
@@ -0,0 +1,61 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+
+<!-- IF "PostedFormValue" "goback" -->
+<FORM>
+<INPUT TYPE="button"
+<!-- DS_POSTEDVALUE "name=goback">
+onClick="history.back()">
+</FORM>
+<!-- ENDIF // PostedFormValue goback -->
+
+<FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT>
+<P>
+
+<!-- IF "FoundEntries" -->
+<FONT SIZE=+1>
+Click on a user's name to edit their entry.
+</FONT>
+<P>
+<TABLE BORDER=1 CELLPADDING=1 CELLSPACING=0 WIDTH=100%>
+<TR>
+<TH NOWRAP>Name<TH NOWRAP>User ID<TH NOWRAP>Title
+</TR>
+
+<!-- DS_SORTENTRIES "attr=sn" -->
+
+<!-- Make sure attrs in lists are read-only. If they aren't, they're rendered
+ as INPUT fields, but since we're not in a form here, they don't display
+ at all.
+-->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "hrefextra=onMouseOver=%22%0Awindow.status='Click here to edit this entry'; return true%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=uid" "options=readonly" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" "options=readonly" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<FONT SIZE=+1>
+Please try a different search.
+</FONT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-fa-Groups.html b/ldap/clients/dsgw/admhtml/list-fa-Groups.html
new file mode 100644
index 00000000..06946994
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-fa-Groups.html
@@ -0,0 +1,24 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<SCRIPT LANGUAGE="JavaScript">
+alert('No entries were found.');
+</SCRIPT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-fa-People.html b/ldap/clients/dsgw/admhtml/list-fa-People.html
new file mode 100644
index 00000000..06946994
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-fa-People.html
@@ -0,0 +1,24 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<SCRIPT LANGUAGE="JavaScript">
+alert('No entries were found.');
+</SCRIPT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-fa_people.html b/ldap/clients/dsgw/admhtml/list-fa_people.html
new file mode 100644
index 00000000..06946994
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-fa_people.html
@@ -0,0 +1,24 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<SCRIPT LANGUAGE="JavaScript">
+alert('No entries were found.');
+</SCRIPT>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/admhtml/list-urlsearch.html b/ldap/clients/dsgw/admhtml/list-urlsearch.html
new file mode 100644
index 00000000..964e6291
--- /dev/null
+++ b/ldap/clients/dsgw/admhtml/list-urlsearch.html
@@ -0,0 +1,39 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "URL-based Search" -->
+<CENTER><FONT SIZE=+1>
+Found
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Name <TH>Phone Number <TH>E-Mail Address
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Please try a different search.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/auth.c b/ldap/clients/dsgw/auth.c
new file mode 100644
index 00000000..88b2ba82
--- /dev/null
+++ b/ldap/clients/dsgw/auth.c
@@ -0,0 +1,120 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * auth.c -- CGI authentication form generator -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+static void post_request();
+static void get_request(char *binddn);
+
+int main(
+ int argc,
+ char **argv
+#ifdef DSGW_DEBUG
+ ,char *env[]
+#endif
+) {
+ int reqmethod;
+ char *binddn = NULL;
+ char *qs = NULL;
+
+ if (( qs = getenv( "QUERY_STRING" )) != NULL && *qs != '\0' ) {
+ /* parse the query string: */
+ auto char *p, *iter = NULL;
+ qs = dsgw_ch_strdup( qs );
+ for ( p = ldap_utf8strtok_r( qs, "&", &iter ); p != NULL;
+ p = ldap_utf8strtok_r( NULL, "&", &iter )) {
+
+ /*Get the context.*/
+ if ( !strncasecmp( p, "context=", 8 )) {
+ context = dsgw_ch_strdup( p + 8 );
+ dsgw_form_unescape( context );
+ continue;
+ }
+
+ /*Get the dn*/
+ if ( !strncasecmp( p, "dn=", 3 )) {
+ binddn = dsgw_ch_strdup( p + 3 );
+ dsgw_form_unescape( binddn );
+ continue;
+ }
+ }
+ free( qs ); qs = NULL;
+ }
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_POST | DSGW_METHOD_GET );
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ if ( reqmethod == DSGW_METHOD_POST ) {
+ post_request();
+ } else {
+ get_request(binddn);
+ }
+
+ exit( 0 );
+}
+
+static void
+get_request(char *binddn)
+{
+ dsgw_send_header();
+
+ if ( binddn != NULL ) {
+ if ( !strcmp( binddn, MGRDNSTR )) {
+ if ( gc->gc_rootdn == NULL ) {
+ dsgw_error( DSGW_ERR_NO_MGRDN,
+ XP_GetClientStr (DBT_noDirMgrIsDefined_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ binddn = dsgw_ch_strdup( gc->gc_rootdn );
+ } else if ( *binddn == '\0' ) {
+ binddn = NULL;
+ } else {
+ binddn = dsgw_ch_strdup( binddn );
+ dsgw_form_unescape( binddn );
+ }
+ }
+ dsgw_emit_auth_form( binddn );
+ if ( binddn != NULL ) {
+ free( binddn );
+ }
+}
+
+
+
+static void
+post_request()
+{
+ char *binddn = NULL;
+ char *dorootbind = NULL;
+
+ dsgw_send_header();
+ /*
+ * If the "authasrootdn" CGI variable is present and has the value
+ * "true" then the user clicked on the "authenticate as directory
+ * manager" button. In that case, try to bind as the root dn given
+ * in the dsgw config file.
+ */
+ dorootbind = dsgw_get_cgi_var( "authasrootdn", DSGW_CGIVAR_OPTIONAL );
+ if ( dorootbind != NULL && !strcasecmp( dorootbind, "true" )) {
+ binddn = dsgw_ch_strdup( gc->gc_rootdn );
+ } else {
+ binddn = dsgw_get_escaped_cgi_var( "escapedbinddn", "binddn",
+ DSGW_CGIVAR_OPTIONAL );
+ }
+
+ dsgw_emit_auth_form( binddn );
+}
diff --git a/ldap/clients/dsgw/cgiutil.c b/ldap/clients/dsgw/cgiutil.c
new file mode 100644
index 00000000..be2ba3db
--- /dev/null
+++ b/ldap/clients/dsgw/cgiutil.c
@@ -0,0 +1,512 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * cgiutil.c -- CGI-related utility functions -- HTTP gateway
+ *
+ * Note: tihs code is derived from the extras/changepw.c code that ships
+ * with the FastTrack 2.0 server
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+#include <prprf.h>
+#include <unicode/ucnv.h>
+#include <unicode/ustring.h>
+
+/* globals */
+static char **formvars = NULL;
+
+/* functions */
+static char **dsgw_string_to_vec(char *in);
+
+static void
+dsgw_vec_convert (char** vec)
+ /* Convert input from the charset named in it (if any) to UTF_8.
+ Either return s, or free(s) and return the converted string.
+ */
+{
+ static const char* prefix = "charset=";
+ const size_t prefix_len = strlen (prefix);
+ char** v;
+
+ if (vec) for (v = vec; *v; ++v) {
+ if (!strncmp (*v, prefix, prefix_len)) {
+ char* charset = *v + prefix_len;
+ UConverter* converter = NULL;
+ UErrorCode err = U_ZERO_ERROR;
+ if ( ! is_UTF_8 (charset) && (converter = ucnv_open(charset, &err)) &&
+ (err == U_ZERO_ERROR) ) {
+ for (v = vec; *v; ++v) {
+ char* s = strchr (*v, '=');
+ if (s != NULL) {
+ char *t = NULL;
+ const size_t nlen = (++s) - *v;
+ const size_t slen = strlen (s);
+ size_t tlen = 0;
+ size_t reallen = 0;
+ int result;
+
+ if (ucnv_getMaxCharSize(converter) == 1) {
+ tlen = slen + 2; /* best case - ascii or other 7/8 bit */
+ } else { /* assume worst case utf8 - each char is 3 bytes */
+ tlen = (slen * 3) + 2;
+ }
+ do {
+ char *tptr;
+ size_t realSlen = 0;
+ err = U_ZERO_ERROR;
+
+ if (t) {
+ t = dsgw_ch_realloc(t, nlen + tlen);
+ } else {
+ t = dsgw_ch_malloc(nlen + tlen);
+ }
+ tptr = t + nlen;
+
+ /* copy the converted characters into t after the '=', and
+ leave room for the trailing 0 */
+ result = dsgw_convert(DSGW_TO_UTF8, converter,
+ &tptr, (tlen - nlen - 1), &reallen,
+ s, slen, &realSlen, &err);
+ tlen += slen; /* if failed, make more room */
+ } while (result == 0);
+ if ((result == 1) && (err == U_ZERO_ERROR)) {
+ memcpy (t, *v, nlen);
+ t[nlen+reallen] = '\0';
+ free (*v);
+ *v = t;
+ } else {
+ free (t);
+ }
+ ucnv_reset (converter); /* back to initial shift state */
+ }
+ }
+ ucnv_close (converter);
+ }
+ if (U_FAILURE(err)) {
+ dsgw_error(DSGW_ERR_CHARSET_NOT_SUPPORTED, charset, 0, 0, 0);
+ }
+ break;
+ }
+ }
+}
+
+/* Read in the variables from stdin, unescape them, and then put them in
+ * the static vector.
+ *
+ * Return 0 if all goes well; DSGW error code otherwise
+ */
+int
+dsgw_post_begin(FILE *in)
+{
+ char *ct, *vars = NULL, *tmp = NULL;
+ int cl;
+
+ if (( ct = getenv( "CONTENT_TYPE" )) == NULL ||
+ strcasecmp( ct, "application/x-www-form-urlencoded" ) != 0 ||
+ ( tmp = getenv( "CONTENT_LENGTH" )) == NULL ) {
+ return( DSGW_ERR_BADFORMDATA );
+ }
+
+ cl = atoi(tmp);
+
+ vars = (char *)dsgw_ch_malloc(cl+1);
+
+ if ( fread(vars, 1, cl, in) != cl ) {
+ return( DSGW_ERR_BADFORMDATA );
+ }
+
+ vars[cl] = '\0';
+#ifdef DSGW_DEBUG
+ dsgw_log ("vars=\"%s\"\n", vars);
+#endif
+ formvars = dsgw_string_to_vec (vars);
+ free( vars );
+ dsgw_vec_convert (formvars);
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "formvars", formvars );
+if (0) {
+ char** var = formvars;
+ if (var) {
+ printf ("Content-type: text/html;charset=UTF-8\n\n<HTML><BODY>\n");
+ for (; *var; ++var) {
+ printf ("%s<br>\n", *var);
+ }
+ printf ("</BODY></HTML>\n");
+ exit (1);
+ }
+}
+#endif
+
+ return( 0 );
+}
+
+
+/* Unescape the %xx variables as they're sent in. */
+void
+dsgw_form_unescape(char *str)
+{
+ register int x = 0, y = 0;
+ int l = strlen(str);
+ char digit;
+
+ while(x < l) {
+ if((str[x] == '%') && (x < (l - 2))) {
+ ++x;
+ digit = (str[x] >= 'A' ?
+ ((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
+ digit *= 16;
+
+ ++x;
+ digit += (str[x] >= 'A' ?
+ ((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
+
+ str[y] = digit;
+ }
+ else if(str[x] == '+') {
+ str[y] = ' ';
+ } else {
+ str[y] = str[x];
+ }
+ x++;
+ y++;
+ }
+ str[y] = '\0';
+}
+
+
+/* Return the value of a POSTed variable, or NULL if none was sent. */
+char *
+dsgw_get_cgi_var(char *varname, int required)
+{
+ register int x = 0;
+ int len = strlen(varname);
+ char *ans = NULL;
+
+ while(formvars != NULL && formvars[x]) {
+ /* We want to get rid of the =, so len, len+1 */
+ if((!strncmp(formvars[x], varname, len)) &&
+ (*(formvars[x]+len) == '=')) {
+ ans = dsgw_ch_strdup(formvars[x] + len + 1);
+ if(!strcmp(ans, "")) {
+ free(ans);
+ ans = NULL;
+ }
+ break;
+ } else
+ x++;
+ }
+
+ if ( required == DSGW_CGIVAR_REQUIRED && ans == NULL ) {
+ char errbuf[ 256 ];
+ PR_snprintf( errbuf, 256,
+ XP_GetClientStr(DBT_missingFormDataElement100s_), varname );
+ dsgw_error( DSGW_ERR_BADFORMDATA, errbuf, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ return ans;
+}
+
+
+/*
+ * Return integer equivalent of POSTed value. If no variable POSTed,
+ * return defval.
+ */
+int
+dsgw_get_int_var( char *varname, int required, int defval )
+{
+ char *val;
+ int rc;
+
+ if (( val = dsgw_get_cgi_var( varname, required )) == NULL ) {
+ rc = defval;
+ } else {
+ rc = atoi( val );
+ free( val );
+ }
+
+ return( rc );
+}
+
+
+/*
+ * Return non-zero if POSTed variable is "true" or "yes". If !required
+ * and no variable POSTed, return defval.
+ */
+int
+dsgw_get_boolean_var( char *varname, int required, int defval )
+{
+ char *val;
+ int rc;
+
+ if (( val = dsgw_get_cgi_var( varname, required )) == NULL ) {
+ rc = defval;
+ } else {
+ rc = ( strcasecmp( val, "true" ) == 0 ||
+ strcasecmp( val, "yes" ) == 0 );
+ free( val );
+ }
+
+ return( rc );
+}
+
+
+/*
+ * If a CGI variable named "varname_escaped" was POST'd, unescape it and
+ * return its value.
+ * Otherwise if "varname" is not NULL and a CGI variable called "varname"
+ * was POST'd, return its value.
+ * Otherwise return NULL.
+ */
+char *
+dsgw_get_escaped_cgi_var( char *varname_escaped, char *varname, int required )
+{
+ char *val;
+
+ if (( val = dsgw_get_cgi_var( varname_escaped,
+ ( varname == NULL ) ? required: DSGW_CGIVAR_OPTIONAL )) != NULL ) {
+ dsgw_form_unescape( val );
+ } else if ( varname != NULL ) {
+ val = dsgw_get_cgi_var( varname, required );
+ }
+
+ return( val );
+}
+
+
+/* Convert the input from stdin to a usable variable vector. */
+static char **
+dsgw_string_to_vec(char *in)
+{
+ char **ans;
+ int vars = 0;
+ register int x = 0;
+ char *tmp;
+
+ while(in[x])
+ if(in[x++]=='=')
+ vars++;
+
+ ans = (char **) dsgw_ch_malloc((sizeof(char *)) * (vars+1));
+
+ 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]=dsgw_ch_strdup(tmp);
+ dsgw_form_unescape(ans[x++]);
+
+ while((tmp = strtok(NULL, "&"))) {
+ if ( strchr( tmp, '=' ) == NULL ) {
+ break;
+ }
+ ans[x] = dsgw_ch_strdup(tmp);
+ dsgw_form_unescape(ans[x++]);
+ }
+ ans[x] = NULL;
+
+ return(ans);
+}
+
+
+/*
+ * Step through all the CGI POSTed variables. A malloc'd copy of the variable
+ * name is returned and *valuep is set to point to the value (not malloc'd).
+ * If there are no more variables, NULL is returned.
+ *
+ * The first time this is called, *indexp should be zero. On subsequent
+ * calls, pass the same indexp as on the first call.
+ */
+char *
+dsgw_next_cgi_var( int *indexp, char **valuep )
+{
+ char *name;
+ int namelen;
+
+ if ( formvars == NULL || formvars[ *indexp ] == NULL ) {
+ return( NULL );
+ }
+
+ if (( *valuep = strchr( formvars[ *indexp ], '=' )) == NULL ) {
+ namelen = strlen( formvars[ *indexp ] );
+ } else {
+ namelen = *valuep - formvars[ *indexp ];
+ ++(*valuep);
+ }
+ name = dsgw_ch_malloc( namelen + 1 );
+ memcpy( name, formvars[ *indexp ], namelen );
+ name[ namelen ] = '\0';
+
+ *indexp += 1;
+
+ return( name );
+}
+
+/*
+ * converts a buffer of characters to/from UTF8 from/to a native charset
+ * the given converter will handle the native charset
+ * returns 0 if not all of source was converted, 1 if all of source
+ * was converted, -1 upon error
+ * all of source will be converted if there is enough room in dest to contain
+ * the entire conversion, or if dest is null and we are malloc'ing space for dest
+ */
+int
+dsgw_convert(
+ int direction, /* false for native->utf8, true for utf8->native */
+ UConverter *nativeConv, /* convert from/to native charset */
+ char **dest, /* *dest is the destination buffer - if *dest == NULL, it will be malloced */
+ size_t destSize, /* size of dest buffer (ignored if *dest == NULL) */
+ size_t *nDest, /* number of chars written to dest */
+ const char *source, /* source buffer to convert - either in native encoding (from) or utf8 (to) */
+ size_t sourceSize, /* size of source buffer - if 0, assume source is NULL terminated */
+ size_t *nSource, /* number of chars read from source buffer */
+ UErrorCode *pErrorCode /* will be reset each time through */
+)
+{
+#define CHUNK_SIZE 1024
+ UChar pivotBuffer[CHUNK_SIZE];
+ UChar *pivot, *pivot2;
+ static UConverter *utf8Converter = NULL;
+ UConverter *inConverter, *outConverter;
+ char *myDest;
+ const char *mySource;
+ const char *destLimit;
+ const char *sourceLimit;
+ int32_t destCapacity=0;
+ int destAlloc = 0; /* set to true if we allocated *dest */
+
+ *pErrorCode = U_ZERO_ERROR;
+
+ if(sourceSize<0 || source==NULL || nDest==NULL || nSource==NULL)
+ {
+ *pErrorCode=U_ILLEGAL_ARGUMENT_ERROR;
+ return -1;
+ }
+
+ *nSource = 0;
+ *nDest = 0;
+
+ /* if source size is 0, assume source is null terminated and use strlen */
+ if(sourceSize==0) {
+ sourceSize = strlen(source);
+ }
+
+ /* create the converters */
+ if (!utf8Converter) {
+ utf8Converter = ucnv_open(UNICODE_ENCODING_UTF_8, pErrorCode);
+ if(U_FAILURE(*pErrorCode)) {
+ return -1;
+ }
+ }
+ /* reset utf8Converter if done or error */
+
+ if (direction) {
+ inConverter = utf8Converter; /* source is utf8 */
+ outConverter = nativeConv; /* dest is native charset */
+ } else {
+ inConverter = nativeConv; /* source is native charset */
+ outConverter = utf8Converter; /* dest is utf8 */
+ }
+
+ /* if dest is NULL, allocate space for it - may be reallocated later */
+ if (!*dest) {
+ /* good approximation of size is n chars in source * max dest char size */
+ destSize = ucnv_getMaxCharSize(outConverter) * sourceSize;
+ *dest = dsgw_ch_malloc(destSize);
+ destAlloc = 1;
+ }
+
+ /* set up the other variables */
+ mySource = source;
+ sourceLimit = source + sourceSize;
+ pivot = pivot2 = pivotBuffer;
+ myDest = *dest;
+ destLimit = *dest + destSize;
+
+ /*
+ * loops until the input buffer is completely consumed
+ * or an error is encountered;
+ * first we convert from inConverter codepage to Unicode
+ * then from Unicode to outConverter codepage
+ */
+ do {
+ pivot = pivotBuffer;
+ ucnv_toUnicode(inConverter,
+ &pivot, pivotBuffer + CHUNK_SIZE,
+ &mySource, sourceLimit,
+ NULL,
+ TRUE,
+ pErrorCode);
+
+ /* U_BUFFER_OVERFLOW_ERROR only means that the pivot buffer is full */
+ if(U_SUCCESS(*pErrorCode) || (*pErrorCode == U_BUFFER_OVERFLOW_ERROR)) {
+ pivot2 = pivotBuffer;
+
+ /* convert and write bytes from the pivot buffer to the dest -
+ if dest is allocated and we run out of space in dest, grow
+ dest and try again - otherwise, just bail out and let the
+ caller know that their dest buffer is full and they need
+ to try again */
+ do {
+ *pErrorCode = U_ZERO_ERROR;
+ ucnv_fromUnicode(outConverter,
+ &myDest, destLimit,
+ (const UChar **)&pivot2, pivot,
+ NULL,
+ (UBool)(mySource == sourceLimit),
+ pErrorCode);
+
+ /* we overflowed dest and dest is allocated, so let's increase
+ the dest size */
+ if ((*pErrorCode == U_BUFFER_OVERFLOW_ERROR) && destAlloc) {
+ /* figure out where myDest was pointing */
+ size_t myDestOffset = myDest - *dest;
+ /* probably don't need this much more room . . . */
+ destSize += CHUNK_SIZE;
+ /* realloc *dest for new size */
+ *dest = dsgw_ch_realloc(*dest, destSize);
+ /* reset myDest in new *dest */
+ myDest = *dest + myDestOffset;
+ /* set new destLimit */
+ destLimit = *dest + destSize;
+ } else {
+ break; /* skip it */
+ }
+ } while(*pErrorCode == U_BUFFER_OVERFLOW_ERROR);
+ /*
+ * If this overflows the fixed size dest, then we must stop
+ * converting and return what we already have
+ * in this case, pErrorCode will be buffer overflow error because
+ * we have overflowed the dest buffer
+ * the outer while loop will break because !U_SUCCESS
+ */
+ }
+ } while(U_SUCCESS(*pErrorCode) && source != sourceLimit);
+
+ *nSource = mySource - source; /* n chars read from source */
+ *nDest = myDest - *dest; /* n chars written to dest */
+
+ if (U_SUCCESS(*pErrorCode) && source == sourceLimit) {
+ /* reset internal converter */
+ ucnv_reset(utf8Converter);
+ return 1; /* converted entire string */
+ }
+
+ if (source != sourceLimit) {
+ /* not done with conversion yet */
+ /* no reset here - preserve state for next call */
+ return 0;
+ }
+
+ /* error */
+ ucnv_reset(utf8Converter);
+ return -1;
+}
diff --git a/ldap/clients/dsgw/ckdel.c b/ldap/clients/dsgw/ckdel.c
new file mode 100644
index 00000000..d823da14
--- /dev/null
+++ b/ldap/clients/dsgw/ckdel.c
@@ -0,0 +1,30 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include <stdio.h>
+#include "dsgw.h"
+
+#include <ssl.h>
+#include <sec.h>
+
+main( int argc, char **argv)
+{
+ char cookie[ 512 ];
+ int rc;
+
+ printf( "Remove an entry to the cookie database\n" );
+
+ printf( "cookie: " );
+ gets( cookie );
+
+ rc = dsgw_delcookie( cookie );
+ if ( rc == 0 ) {
+ printf( "Cookie deleted\n" );
+ } else {
+ printf( "Failed, rc = %d\n", rc );
+ }
+}
diff --git a/ldap/clients/dsgw/ckdump.c b/ldap/clients/dsgw/ckdump.c
new file mode 100644
index 00000000..a7dea8da
--- /dev/null
+++ b/ldap/clients/dsgw/ckdump.c
@@ -0,0 +1,38 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include <stdio.h>
+#include "dsgw.h"
+
+#include <ssl.h>
+#include <sec.h>
+
+main()
+{
+ char *p;
+ time_t expires;
+ char dn[ 512 ];
+ char pw[ 512 ];
+ char expsec[ 512 ];
+
+#ifdef notdef /* this was some testing code... */
+{
+ char *ck, *r, *d, *p;
+ int rc;
+
+ ck = dsgw_get_auth_cookie();
+ rc = dsgw_parse_cookie( ck, &r, &d );
+ if ( rc == 0 ) {
+ (void) dsgw_ckdn2passwd( r, d, &p );
+ printf( "Got pw of <%s>\n", ( p == NULL ) ? "NULL" : p );
+ }
+}
+#endif /* notdef */
+ printf( "Dump the cookie database\n" );
+
+ dsgw_traverse_db();
+}
diff --git a/ldap/clients/dsgw/ckget.c b/ldap/clients/dsgw/ckget.c
new file mode 100644
index 00000000..b436712c
--- /dev/null
+++ b/ldap/clients/dsgw/ckget.c
@@ -0,0 +1,46 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include <stdio.h>
+#include "dsgw.h"
+
+#include <ssl.h>
+#include <sec.h>
+
+main()
+{
+ char *p;
+ time_t expires;
+ char dn[ 512 ];
+ char cookie[ 512 ];
+ int rc;
+ char *pw;
+
+
+ printf( "Retrieve an entry from the cookie database\n" );
+
+ printf( "cookie: " );
+ gets( cookie );
+ printf( "dn: " );
+ gets( dn );
+
+ rc = dsgw_ckdn2passwd( cookie, dn, &pw );
+ if ( rc == 0 ) {
+ printf( "Cookie valid, password is <%s>\n", pw );
+ } else {
+ if ( rc == DSGW_CKDB_KEY_NOT_PRESENT ) {
+ printf( "Cookie/DN pair not found in database\n" );
+ } else if ( rc == DSGW_CKDB_EXPIRED ) {
+ printf( "Cookie/DN pair expired\n" );
+ } else {
+ printf( "Unknown DB error\n" );
+ }
+ }
+ if ( pw != NULL ) {
+ free( pw );
+ }
+}
diff --git a/ldap/clients/dsgw/ckpurge.c b/ldap/clients/dsgw/ckpurge.c
new file mode 100644
index 00000000..b2192476
--- /dev/null
+++ b/ldap/clients/dsgw/ckpurge.c
@@ -0,0 +1,33 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include <stdio.h>
+#include "dsgw.h"
+
+#include <ssl.h>
+#include <sec.h>
+
+main()
+{
+ char *p;
+ time_t expires;
+ char dn[ 512 ];
+ char pw[ 512 ];
+ char expsec[ 512 ];
+ int np = 0;
+ time_t last;
+ FILE *fp;
+
+ printf( "purge the cookie database\n" );
+
+ fp = dsgw_opencookiedb();
+ last = dsgw_getlastpurged( fp );
+ dsgw_closecookiedb( fp );
+ printf( "database was last purged at %s\n", ctime( &last ));
+ np = dsgw_purgedatabase( NULL );
+ printf( "%d records purged\n", np );
+}
diff --git a/ldap/clients/dsgw/ckput.c b/ldap/clients/dsgw/ckput.c
new file mode 100644
index 00000000..09782c7c
--- /dev/null
+++ b/ldap/clients/dsgw/ckput.c
@@ -0,0 +1,63 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include <stdio.h>
+#include "dsgw.h"
+
+#include <ssl.h>
+#include <sec.h>
+
+main( int argc, char **argv)
+{
+ char *p;
+ char dn[ 512 ];
+ char pw[ 512 ];
+ char lifesec[ 512 ];
+ int rc;
+ int c;
+ extern char *optarg;
+ time_t lifetime;
+
+ printf( "Add an entry to the cookie database\n" );
+
+ SEC_Init();
+ SEC_RNGInit();
+ SEC_SystemInfoForRNG();
+
+ if ( argc > 1 ) {
+ while (( c = getopt( argc, argv, "d:l:p:" )) != EOF ) {
+ switch ( c ) {
+ case 'd':
+ strcpy( dn, optarg );
+ break;
+ case 'l':
+ strcpy( lifesec, optarg );
+ break;
+ case 'p':
+ strcpy( pw, optarg );
+ break;
+ }
+ }
+ }
+
+ if ( strlen( dn ) == 0 || strlen( pw ) == 0 || strlen( lifesec ) == 0 ) {
+ printf( "dn: " );
+ gets( dn );
+ printf( "passwd: " );
+ gets( pw );
+ printf( "expires in how many seconds? " );
+ gets( lifesec );
+ }
+
+ lifetime = atol( lifesec );
+ p = dsgw_mkcookie( dn, pw, lifetime, &rc );
+ if ( p == NULL ) {
+ fprintf( stderr, "Error storing cookie: error %d\n", rc );
+ } else {
+ printf( "success, cookie is %s\n", p );
+ }
+}
diff --git a/ldap/clients/dsgw/collate.c b/ldap/clients/dsgw/collate.c
new file mode 100644
index 00000000..23ef759e
--- /dev/null
+++ b/ldap/clients/dsgw/collate.c
@@ -0,0 +1,400 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * collate.c -- routines to collate character strings
+ *
+ * Copyright (c) 1997 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include <stdio.h>
+#include "dsgw.h"
+#include <ldap.h> /* ldap_utf8* */
+
+#include <unicode/ucol.h> /* Collation */
+#include <unicode/ucnv.h> /* Conversion */
+#include <unicode/ustring.h> /* UTF8 conversion */
+
+#ifdef _WINDOWS
+#undef strcasecmp
+#define strcasecmp _strcmpi
+#endif
+
+/*
+ Convert the given string s, encoded in UTF8, into a Unicode (UTF16 or 32, depending on sizeof(UChar))
+ string for use with collation and key generation
+ The given string U will be filled in if it's capacity (given by Ulen) is big enough,
+ otherwise, it will be malloced (or realloced if already allocated)
+*/
+static UErrorCode
+SetUnicodeStringFromUTF_8 (UChar** U, int32_t* Ulen, int *isAlloced, const char *s)
+ /* Copy the UTF-8 string bv into the UnicodeString U,
+ but remove leading and trailing whitespace, and
+ convert consecutive whitespaces into a single space.
+ Ulen is set to the number of UChars in the array (not necessarily the number of bytes!)
+ */
+{
+ size_t n;
+ int32_t len = 0; /* length of non-space string */
+ int32_t needLen = 0; /* number of bytes needed for string */
+ UErrorCode err = U_ZERO_ERROR;
+ const char* begin; /* will point to beginning of non-space in s */
+
+ /* first, set s to the first non-space char in bv->bv_val */
+ while (s && *s && ldap_utf8isspace((char *)s)) { /* cast away const */
+ const char *next = LDAP_UTF8NEXT((char *)s); /* cast away const */
+ s = next;
+ }
+ begin = s;
+
+ if (!s || !*s) {
+ return U_INVALID_FORMAT_ERROR; /* don't know what else to use here */
+ }
+
+ /* next, find the length of the non-space string */
+ while (s && *s && !ldap_utf8isspace((char *)s)) { /* cast away const */
+ const char *next = LDAP_UTF8NEXT((char *)s); /* cast away const */
+ len += (next - s); /* count bytes, not chars */
+ needLen++; /* needLen counts chars */
+ s = next;
+ }
+
+ if (needLen == 0) { /* bogus */
+ return U_INVALID_FORMAT_ERROR; /* don't know what else to use here */
+ }
+
+ needLen++; /* +1 for trailing UChar space */
+ if (needLen > *Ulen) { /* need more space */
+ if (*isAlloced) { /* realloc space */
+ *U = (UChar *)dsgw_ch_realloc((char *)*U, sizeof(UChar) * needLen);
+ } else { /* must use malloc */
+ *U = (UChar *)dsgw_ch_malloc(sizeof(UChar) * needLen);
+ *isAlloced = 1; /* no longer using fixed buffer */
+ }
+ *Ulen = needLen;
+ }
+ u_strFromUTF8(*U, sizeof(UChar) * (*Ulen), NULL, begin, len, &err);
+
+ return err;
+}
+
+static UCollator*
+get_collator (int flavor)
+{
+ static UCollator* collator[2] = {NULL, NULL};
+/* dsgw_emitf("get_collator (%i)<br>\n", flavor); */
+ if (collator[flavor] == NULL &&
+ gc->gc_ClientLanguage && gc->gc_ClientLanguage[0]) {
+ /* Try to create a Collation for the client's preferred language */
+ ACCEPT_LANGUAGE_LIST langlist;
+ size_t langs;
+/* dsgw_emitf ("ClientLanguage = \"%s\"<br>\n", gc->gc_ClientLanguage); */
+ langs = AcceptLangList (gc->gc_ClientLanguage, langlist);
+ if (langs <= 0) {
+dsgw_emitf ("AcceptLangList (%s) = %lu<br>\n",
+ gc->gc_ClientLanguage, (unsigned long)langs);
+ } else {
+ UCollator* fallback_collator = NULL;
+ UCollator* default_collator = NULL;
+ UErrorCode err = U_ZERO_ERROR;
+ size_t i;
+
+ for (i = 0; i < langs; ++i) {
+ /* Try to create a Collation for langs[i] */
+ char* lang = langlist[i];
+ collator[flavor] = ucol_open(lang, &err);
+ if (err == U_ZERO_ERROR && collator[flavor]) {
+dsgw_emitf("<!-- New Collator (%s) == SUCCESS -->\n", lang);
+ break;
+ } else {
+ if (err == U_USING_FALLBACK_WARNING) {
+ if (fallback_collator == NULL) {
+ fallback_collator = collator[flavor];
+dsgw_emitf("<!-- New Collator (%s) == USING_FALLBACK_LOCALE -->\n", lang);
+ } else {
+ ucol_close (collator[flavor]);
+ }
+ } else if (err == U_USING_DEFAULT_WARNING) {
+ if (default_collator == NULL) {
+ default_collator = collator[flavor];
+dsgw_emitf("<!-- New Collator (%s) == USING_DEFAULT_LOCALE -->\n", lang);
+ } else {
+ ucol_close (collator[flavor]);
+ }
+ } else {
+dsgw_emitf("New Collator error (%s) == %i<br>\n", lang, err);
+ }
+ collator[flavor] = NULL;
+ }
+ }
+ if (collator[flavor] == NULL) {
+ if (fallback_collator != NULL) {
+ collator[flavor] = fallback_collator;
+ fallback_collator = NULL;
+ } else if (default_collator != NULL) {
+ collator[flavor] = default_collator;
+ default_collator = NULL;
+ }
+ }
+ if (collator[flavor] != NULL) {
+ switch (flavor) {
+ case CASE_EXACT:
+dsgw_emits("<!-- CollationSetStrength (TERTIARY) -->\n");
+ ucol_setAttribute (collator[flavor], UCOL_STRENGTH, UCOL_TERTIARY, &err);
+ break;
+ default: /* CASE_IGNORE */
+ if (dsgw_scriptorder()->so_caseIgnoreAccents) {
+dsgw_emits("<!-- CollationSetStrength (PRIMARY) -->\n");
+ ucol_setAttribute (collator[flavor], UCOL_STRENGTH, UCOL_PRIMARY, &err);
+ } else {
+dsgw_emits("<!-- CollationSetStrength (SECONDARY) -->\n");
+ ucol_setAttribute (collator[flavor], UCOL_STRENGTH, UCOL_SECONDARY, &err);
+ }
+ break;
+ }
+ }
+ if (default_collator != NULL) {
+ ucol_close (default_collator);
+ default_collator = NULL;
+ }
+ if (fallback_collator != NULL) {
+ ucol_close (fallback_collator);
+ fallback_collator = NULL;
+ }
+ }
+ }
+ return collator[flavor];
+}
+
+static int
+valcmp (const char** L, const char** R)
+{
+ return strcmp (*L, *R);
+}
+
+static int
+valcasecmp (const char** L, const char** R)
+{
+ return strcasecmp (*L, *R);
+}
+
+static int
+strXcollate (int flavor, const char* L, const char* R)
+{
+ UCollator* collator = get_collator (flavor);
+ if (collator != NULL) {
+ UChar LuBuffer[128];
+ UChar* Lu = LuBuffer;
+ int32_t LuLen = u_strlen(LuBuffer);
+ int LuisAlloced = 0;
+ if (SetUnicodeStringFromUTF_8 (&Lu, &LuLen, &LuisAlloced, L) == U_ZERO_ERROR) {
+ UChar RuBuffer[128];
+ UChar* Ru = RuBuffer;
+ int32_t RuLen = u_strlen(RuBuffer);
+ int RuisAlloced = 0;
+ if (SetUnicodeStringFromUTF_8 (&Ru, &RuLen, &RuisAlloced, R) == U_ZERO_ERROR) {
+ UCollationResult colres = ucol_strcoll(collator, Lu, LuLen, Ru, RuLen);
+ int result = 0;
+ switch (colres) {
+ case UCOL_LESS:
+ result = -1;
+ break;
+ case UCOL_GREATER:
+ result = 1;
+ break;
+ default:
+ break;
+ }
+#ifdef DSGW_DEBUG
+ {
+ auto char* Le = dsgw_strdup_escaped (L);
+ auto char* Re = dsgw_strdup_escaped (R);
+ dsgw_log ("strXcollate:%s %s %s\n",
+ Le, result < 0 ? "<" : (result == 0 ? "=" : ">"), Re);
+ free (Le);
+ free (Re);
+ }
+#endif
+ if (RuisAlloced) {
+ free(Ru);
+ Ru = NULL;
+ }
+ if (LuisAlloced) {
+ free(Lu);
+ Lu = NULL;
+ }
+
+ return result;
+ }
+ if (LuisAlloced) {
+ free(Lu);
+ Lu = NULL;
+ }
+ }
+ }
+ return flavor ? strcasecmp (L, R) : strcmp (L, R);
+}
+
+static int
+strcollate (const char* L, const char* R)
+{
+ return strXcollate (CASE_EXACT, L, R);
+}
+
+static int
+strcasecollate (const char* L, const char* R)
+{
+ return strXcollate (CASE_INSENSITIVE, L, R);
+}
+
+static int
+valcollate (const char** L, const char** R)
+{
+ return strXcollate (CASE_EXACT, *L, *R);
+}
+
+static int
+valcasecollate (const char** L, const char** R)
+{
+ return strXcollate (CASE_INSENSITIVE, *L, *R);
+}
+
+strcmp_t
+dsgw_strcmp (int flavor)
+{
+ if (get_collator (flavor) != NULL) {
+ return flavor ? strcasecollate : strcollate;
+ }
+ return flavor ? strcasecmp : strcmp;
+}
+
+valcmp_t
+dsgw_valcmp (int flavor)
+{
+ if (get_collator (flavor) != NULL) {
+ return flavor ? valcasecollate : valcollate;
+ }
+ return flavor ? valcasecmp : valcmp;
+}
+
+static size_t
+dsgw_scriptof (const char* s, scriptrange_t** ranges)
+{
+ auto size_t result = 0;
+ if (s && ranges) {
+ auto unsigned long u;
+ while ((u = LDAP_UTF8GETCC (s)) != 0) {
+ auto size_t ss;
+ auto scriptrange_t* sr;
+ for (ss = 0; (sr = ranges[ss]) != NULL; ++ss) {
+ do {
+ if (sr->sr_min <= u && u <= sr->sr_max) {
+ break;
+ }
+ } while ((sr = sr->sr_next) != NULL);
+ if (sr) {
+ if (result < ss) result = ss;
+ break;
+ }
+ }
+ if (!sr) {
+ result = ss;
+ break;
+ }
+ }
+ }
+#ifdef DSGW_DEBUG
+ dsgw_log ("script %lu\n", (unsigned long)result);
+#endif
+ return result;
+}
+
+static struct berval key_first = {0, 0};
+static struct berval key_last = {0, 0};
+
+struct berval* dsgw_key_first = &key_first;
+struct berval* dsgw_key_last = &key_last;
+
+void LDAP_C LDAP_CALLBACK
+dsgw_keyfree( void *arg, const struct berval* key )
+{
+ if (key->bv_val) free (key->bv_val);
+ else if (key == dsgw_key_first || key == dsgw_key_last) return;
+ free ((void*)key);
+}
+
+int LDAP_C LDAP_CALLBACK
+dsgw_keycmp( void *arg, const struct berval *L, const struct berval *R )
+{
+ int result = 0;
+ if (L == R) {
+ } else if (L->bv_val == NULL) { /* L is either first or last */
+ result = (L == dsgw_key_last) ? 1 : -1;
+ } else if (R->bv_val == NULL) { /* R is either first or last */
+ result = (R == dsgw_key_last) ? -1 : 1;
+ } else
+ /* copied from slapi_berval_cmp(), in ../../servers/slapd/plugin.c: */
+ if (L->bv_len < R->bv_len) {
+ result = memcmp (L->bv_val, R->bv_val, L->bv_len);
+ if (result == 0)
+ result = -1;
+ } else {
+ result = memcmp (L->bv_val, R->bv_val, R->bv_len);
+ if (result == 0 && (L->bv_len > R->bv_len))
+ result = 1;
+ }
+ return result;
+}
+
+struct berval*
+dsgw_strkeygen (int flavor, const char* s)
+{
+ auto struct berval* v = (struct berval*)dsgw_ch_malloc (sizeof (struct berval));
+ auto UCollator* collator = get_collator (flavor);
+ v->bv_val = NULL;
+ if (collator != NULL) {
+ UChar uBuffer[128];
+ UChar* u = uBuffer;
+ int32_t uLen = u_strlen(uBuffer);
+ int uisAlloced = 0;
+ if (SetUnicodeStringFromUTF_8 (&u, &uLen, &uisAlloced, s) == U_ZERO_ERROR) {
+ char keyBuffer[128]; /* try to use static space buffer to avoid malloc */
+ int32_t keyLen = u_strlen(keyBuffer);
+ char* key = keyBuffer; /* but key can grow if necessary */
+ int32_t realLen = ucol_getSortKey(collator, u, uLen, (uint8_t *)key, keyLen);
+ if (realLen > keyLen) { /* need more space */
+ key = (char*)dsgw_ch_malloc(sizeof(char) * realLen);
+ keyLen = ucol_getSortKey(collator, u, uLen, (uint8_t *)key, realLen);
+ }
+ v->bv_len = realLen + 2;
+ v->bv_val = dsgw_ch_malloc (v->bv_len);
+ memcpy(v->bv_val+1, key, realLen);
+ if (uisAlloced) {
+ free(u);
+ u = NULL;
+ }
+ if (key != keyBuffer) {
+ free(key);
+ key = NULL;
+ }
+ }
+ }
+ if (v->bv_val == NULL) {
+ v->bv_len = (s ? strlen (s) : 0) + 2;
+ v->bv_val = dsgw_ch_malloc (v->bv_len);
+ if (v->bv_len > 2) memcpy (v->bv_val+1, s, v->bv_len-2);
+ if (flavor) {
+ register char* t;
+ for (t = v->bv_val+1; *t; ++t) {
+ if (isascii (*t)) *t = tolower (*t);
+ }
+ }
+ }
+ v->bv_val[0] = (char) dsgw_scriptof (s, dsgw_scriptorder()->so_sort);
+ v->bv_val[v->bv_len-1] = '\0';
+ return v;
+}
diff --git a/ldap/clients/dsgw/config.c b/ldap/clients/dsgw/config.c
new file mode 100644
index 00000000..954da599
--- /dev/null
+++ b/ldap/clients/dsgw/config.c
@@ -0,0 +1,2080 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * config.c -- parse config file for directory server gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+
+#include <limits.h> /* ULONG_MAX */
+#include <stdio.h>
+#include <stdlib.h> /* strtoul */
+#include <string.h>
+#if !defined( XP_WIN32 )
+#include <sys/param.h>
+#endif
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+#include "../../include/portable.h"
+/* MLM - Include netsite.h to get ADMSERV_VERSION_STRING */
+#ifdef AIX
+#undef HAVE_TIME_R
+#endif
+#include "netsite.h"
+#include "ldaputil/errors.h"
+#include "ldaputil/ldaputil.h"
+#include "ldaputil/dbconf.h"
+
+extern char *get_userdb_dir(void); /* Can't include libadmin.h, so this */
+static void report_ldapu_error( int ldapu_err, int dsgw_err, int erropts );
+static void adderr( dsgwconfig *gc, char *str, char *filename, int lineno );
+static void fp_parse_line( char *line, int *argcp, char **argv );
+static void fp_getline_init( int *lineno );
+static char *fp_getline( FILE *fp, int *lineno );
+static void add_location( int *loccountp, dsgwloc **locarrayp,
+ char *locsuffix, char **argv );
+static int add_newtype( dsgwnewtype **newentlistp, int loccount,
+ dsgwloc *locarray, int argc, char **argv );
+static void add_tmplset( dsgwtmplset **tslp, int argc, char **argv );
+static void add_vcardproperty( dsgwvcprop **vcpropp, int argc, char **argv );
+static void add_avset( dsgwavset **avsp, char **argv );
+static void add_includeset( dsgwinclset **isp, char **argv );
+static void add_l10nset( dsgwsubst **l10np, char **argv );
+static void read_dsgwconfig( char *filename, char *locsuffix,
+ int templatesonly, int binddnfile );
+static void get_dbconf_properties( char *filename );
+static int write_dbswitch_info( FILE *fp, dsgwconfig *cfgp, char *dbhandle );
+static int ldapdb_url_parse( char *url, LDAPDBURLDesc **ldbudpp );
+static int dsgw_valid_context();
+static int browser_is_msie40();
+static int browser_ignores_acceptcharset();
+static char *dsgw_ch_strdup_tolower( const char *s );
+static void set_dsgwcharset();
+#ifdef XP_WIN32
+static void dsgw_unix2dospath( char *path );
+#endif
+
+
+#define MAXARGS 100
+/*
+ * Open and parse the dsgw config file. If an error occurs, this function
+ * does not return.
+ */
+dsgwconfig *
+dsgw_read_config()
+{
+ char *scriptname;
+ char *p, *fname;
+ int servurllen = 0;
+ int len;
+ char *path;
+
+ /* get rid of stupid warning: */
+ if (ldapu_strings != NULL);
+
+ /*
+ * First, make sure that the context is valid. Don't want anything
+ * tricky in there like dots or slashes.
+ */
+ if (!dsgw_valid_context ()) {
+ dsgw_error( DSGW_ERR_BADFILEPATH, context,
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ /* gc is a global */
+ if (( gc = (dsgwconfig *) dsgw_ch_malloc( sizeof( dsgwconfig ))) == NULL ) {
+ dsgw_error( DSGW_ERR_NOMEMORY,
+ XP_GetClientStr(DBT_initializingConfigInfo_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ memset( gc, 0, sizeof( dsgwconfig ));
+
+ /*
+ * set non-zero configuration defaults
+ */
+ gc->gc_ldapport = LDAP_PORT;
+ gc->gc_configerrstr = dsgw_ch_strdup( "" );
+ gc->gc_sslrequired = DSGW_SSLREQ_NEVER;
+ gc->gc_authlifetime = DSGW_DEF_AUTH_LIFETIME;
+ gc->gc_configdir = DSGW_CONFIGDIR_HTTP; /* may be overridden below */
+ gc->gc_docdir = DSGW_DOCDIR_HTTP;
+ gc->gc_tmpldir = DSGW_TMPLDIR_HTTP; /* may be overridden below */
+ gc->gc_urlpfxmain = DSGW_URLPREFIX_MAIN_HTTP; /* may be overridden below */
+ /*gc->gc_urlpfxcgi = DSGW_URLPREFIX_CGI_HTTP;*/
+ gc->gc_urlpfxcgi = DSGW_URLPREFIX_BIN; /* may be overridden below */
+ gc->gc_binddn = gc->gc_bindpw = "";
+ gc->gc_charset = NULL; /* implicitly ISO-8859-1 */
+ gc->gc_ClientLanguage = "";
+ gc->gc_AdminLanguage = "";
+ gc->gc_DefaultLanguage = "";
+ gc->gc_httpversion = 0;
+ gc->gc_orgchartsearchattr = "uid";
+ /*
+ * Figure out whether we are running under the admin server or not. This
+ * also determines where our config and html files are. The hackage is:
+ * if we're running under the admin server:
+ * configdir is ../../../../admin-serv/config
+ * htmldir is ../html
+ * urlpfxmain is ""
+ * urlpfxcgi is ""
+ * dbswitchfile is NSHOME/userdb/dbswitch.conf
+ *
+ * If we're running under any other HTTP server:
+ * configdir is ../config
+ * htmldir is ../config (yes, that's right)
+ * urlpfxmain is "lang?context=dsgw&file="
+ * gc_urlpfxcgi is "/ds"
+ * dbswitchfile is not used
+ */
+
+ /* Get the admin server name and chop off the version number */
+ /* vs = dsgw_ch_strdup( ADMSERV_VERSION_STRING );
+ if (( p = strchr( vs, '/')) != NULL ) {
+ *p = '\0';
+ }*/
+
+ /*ss = getenv( "SERVER_SOFTWARE" );
+ if ( ss != NULL ) {
+ if ( !strncasecmp( vs, ss, strlen( vs ))) {
+ char *server_names;*/
+ /* We're running under the admin server */
+ /* gc->gc_admserv = 1;
+ gc->gc_configdir = DSGW_CONFIGDIR_ADMSERV;
+ gc->gc_tmpldir = DSGW_TMPLDIR_ADMSERV;
+ gc->gc_urlpfxmain = DSGW_URLPREFIX_MAIN_ADMSERV;
+ gc->gc_urlpfxcgi = DSGW_URLPREFIX_CGI_ADMSERV;*/
+ /* Check if running an end-user CGI under the admin server */
+ /* if (( server_names = getenv( "SERVER_NAMES" )) != NULL &&
+ strlen( server_names ) >= 4 &&
+ strncmp( server_names, "user", 4 ) == 0 ) {
+ gc->gc_enduser = 1;
+ }
+ }
+ }*/
+
+ /*
+ * Get the strlen of the http://admin/port because getvp returns
+ * that in the url, so we can't compare scriptname against what
+ * getvp returns. We need to skip past the server url part.
+ */
+ servurllen = strlen(getenv("SERVER_URL"));
+
+ /* Set mode (based on which CGI is currently running) */
+ if (( scriptname = getenv( "SCRIPT_NAME" )) == NULL ) {
+ gc->gc_mode = 0;
+ } else {
+ if ( !strncmp( scriptname, dsgw_getvp( DSGW_CGINUM_DOSEARCH ) + servurllen,
+ strlen( scriptname ))) {
+ gc->gc_mode = DSGW_MODE_DOSEARCH;
+ } else if ( !strncmp( scriptname, dsgw_getvp( DSGW_CGINUM_BROWSE ) + servurllen,
+ strlen( scriptname ))) {
+ gc->gc_mode = DSGW_MODE_BROWSE;
+ } else if ( !strncmp( scriptname, dsgw_getvp( DSGW_CGINUM_SEARCH ) + servurllen,
+ strlen( scriptname ))) {
+ gc->gc_mode = DSGW_MODE_SEARCH;
+ } else if ( !strncmp( scriptname, dsgw_getvp( DSGW_CGINUM_CSEARCH )+ servurllen,
+ strlen( scriptname ))) {
+ gc->gc_mode = DSGW_MODE_CSEARCH;
+ } else if ( !strncmp( scriptname, dsgw_getvp( DSGW_CGINUM_AUTH )+ servurllen,
+ strlen( scriptname ))) {
+ gc->gc_mode = DSGW_MODE_AUTH;
+ } else if ( !strncmp( scriptname, dsgw_getvp( DSGW_CGINUM_EDIT )+ servurllen,
+ strlen( scriptname ))) {
+ gc->gc_mode = DSGW_MODE_EDIT;
+ } else if ( !strncmp( scriptname, dsgw_getvp( DSGW_CGINUM_DOMODIFY )+ servurllen,
+ strlen( scriptname ))) {
+ gc->gc_mode = DSGW_MODE_DOMODIFY;
+ } else {
+ gc->gc_mode = DSGW_MODE_UNKNOWN;
+ }
+ }
+
+ if (( p = getenv( "SERVER_PROTOCOL" )) != NULL ) {
+ char *pp;
+
+ pp = strchr(p, '/');
+ if (pp != NULL) {
+ gc->gc_httpversion = (float)atof(++pp);
+ }
+ }
+
+ if (( p = getenv( "DefaultLanguage" )) != NULL ) {
+ gc->gc_DefaultLanguage = p;
+ }
+
+ if (( p = getenv( "AdminLanguage" )) != NULL ) {
+ gc->gc_AdminLanguage = p;
+ }
+
+ if (( p = getenv( "ClientLanguage" )) != NULL ) {
+ gc->gc_ClientLanguage = p;
+ }
+
+ /* Accept-Language from user overrides ClientLanguage from environment */
+ if (( p = getenv( "HTTP_ACCEPT_LANGUAGE" )) != NULL ) {
+ gc->gc_ClientLanguage = p;
+ }
+
+ /* Set rest of config. by reading the appropriate config files */
+ path = dsgw_ch_malloc( MAXPATHLEN );
+ if ( gc->gc_admserv ) {
+ PR_snprintf( path, MAXPATHLEN, "%s/dbswitch.conf", get_userdb_dir());
+ get_dbconf_properties( path );
+ }
+
+ /*
+ * If there is no config file name (context), then use
+ * DSGW_CONFIGFILE in the config directory
+ */
+ if (context == NULL) {
+ PR_snprintf( path, MAXPATHLEN, "%s$$LANGDIR/%s",
+ DSGW_CONFIGDIR_HTTP, DSGW_CONFIGFILE);
+ len = strlen( DSGW_CONFIGDIR_HTTP ) + strlen( DSGW_CONFIGFILE ) + 32;
+ } else {
+ PR_snprintf( path, MAXPATHLEN, "%s$$LANGDIR/%s.conf",
+ DSGW_CONTEXTDIR_HTTP, context);
+ /* increased the length from 11 -- fix for auth crash on AIX */
+ len = strlen( DSGW_CONTEXTDIR_HTTP ) + strlen( context ) + 32;
+ }
+ /* allocate buffers with enough extra room to fit "$$LANGDIR/" */
+ if ( NULL != gc->gc_ClientLanguage ) {
+ len += strlen( gc->gc_ClientLanguage );
+ }
+ fname = dsgw_ch_malloc( len+MAXPATHLEN );
+ if ( GetFileForLanguage( path, gc->gc_ClientLanguage, fname ) < 0 ) {
+ if (context == NULL) {
+ PR_snprintf( fname, len+MAXPATHLEN, "%s%s", DSGW_CONFIGDIR_HTTP,
+ DSGW_CONFIGFILE);
+ } else {
+ PR_snprintf( fname, len+MAXPATHLEN, "%s%s.conf",
+ DSGW_CONTEXTDIR_HTTP, context);
+ }
+ }
+ free( path );
+
+ if (context != NULL) {
+ char urlpfx[MAXPATHLEN];
+ /*set the urlpfxmain to be "lang?context=CONTEXT&file="*/
+ /*sprintf(urlpfx, "%slang?context=%s&file=", DSGW_URLPREFIX_CGI_HTTP, context);*/
+ PR_snprintf(urlpfx, MAXPATHLEN, "%s?context=%s&file=", dsgw_getvp(DSGW_CGINUM_LANG), context);
+ gc->gc_urlpfxmain = dsgw_ch_strdup( urlpfx );
+ }
+
+ read_dsgwconfig( fname, NULL, gc->gc_admserv, 0 );
+ free( fname );
+
+ /* if necessary, try to set path to certificate database */
+#ifndef DSGW_NO_SSL
+ if ( gc->gc_ldapssl && gc->gc_securitypath == NULL ) {
+ if ( gc->gc_admserv ) {
+ if (( p = get_nsadm_var( "CertFile" )) != NULL ) {
+ gc->gc_securitypath = dsgw_ch_malloc( strlen( p ) + 4 );
+ sprintf( gc->gc_securitypath, "%s.db", p );
+ }
+ } else {
+ gc->gc_securitypath = DSGW_DEFSECURITYPATH;
+ }
+ }
+#endif
+
+ if ( browser_ignores_acceptcharset() ) {
+ set_dsgwcharset();
+ } else {
+ /* Accept-Charset from user overrides charset from configuration */
+ if (( p = getenv( "HTTP_ACCEPT_CHARSET" )) != NULL ) {
+ gc->gc_charset = p;
+ /* IE 4.0 doesn't send HTTP_ACCEPT_CHARSET, so we test for it specially -RJP */
+ } else if (browser_is_msie40() ) {
+ gc->gc_charset = MSIE40_DEFAULT_CHARSET;
+ } else { /* charset file overrides charset from configuration */
+ set_dsgwcharset();
+ }
+ }
+
+ return( gc );
+}
+
+
+static void
+report_ldapu_error( int ldapu_err, int dsgw_err, int erropts )
+{
+ char *extra = "";
+
+ switch( ldapu_err ) {
+ case LDAPU_ERR_CANNOT_OPEN_FILE:
+ extra = XP_GetClientStr(DBT_cannotOpenFile_);
+ break;
+ case LDAPU_ERR_DBNAME_IS_MISSING:
+ case LDAPU_ERR_NOT_PROPVAL:
+ extra = XP_GetClientStr(DBT_malformedDbconfFile_);
+ break;
+ case LDAPU_ERR_PROP_IS_MISSING:
+ extra = XP_GetClientStr(DBT_missingPropertyNameInDbconfFile_);
+ break;
+ case LDAPU_ERR_OUT_OF_MEMORY:
+ extra = XP_GetClientStr(DBT_outOfMemory_1);
+ break;
+ case LDAPU_ERR_DIRECTIVE_IS_MISSING:
+ extra = XP_GetClientStr(DBT_missingDirectiveInDbconfFile_);
+ break;
+ }
+
+ dsgw_error( dsgw_err, extra, erropts, 0, NULL );
+}
+
+
+/*
+ * Read the gateway config file (dsgw.conf).
+ */
+static void
+read_dsgwconfig( char *filename, char *locsuffix, int templatesonly, int binddnfile )
+{
+ char buf[ MAXPATHLEN + 100 ];
+ int cargc;
+ char *cargv[ MAXARGS ];
+ FILE *fp;
+ char *line;
+ int lineno;
+ int rc;
+ LDAPURLDesc *ludp;
+
+ if (( fp = fopen( filename, "r" )) == NULL ) {
+ if ( strstr( filename, "dsgw-l10n.conf" ) != NULL ) {
+ return; /* ignore if it's dsgw-l10n.conf */
+ }
+ PR_snprintf( buf, MAXPATHLEN + 100,
+ XP_GetClientStr(DBT_cannotOpenConfigFileSN_), filename );
+ dsgw_error( DSGW_ERR_BADCONFIG, buf, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ fp_getline_init( &lineno );
+
+ while ( (line = fp_getline( fp, &lineno )) != NULL ) {
+ /* skip comments and blank lines */
+ if ( line[0] == '#' || line[0] == '\0' ) {
+ continue;
+ }
+
+ fp_parse_line( line, &cargc, cargv );
+
+ if ( cargc < 1 ) {
+ continue;
+ }
+
+ if ( strcasecmp( cargv[0], "requireauth" ) == 0 ) {
+ if ( templatesonly ) continue;
+ gc->gc_authrequired = 1;
+ }
+
+ if ( strcasecmp( cargv[0], "authlifetime" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForAuthlifetimeDi_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_authlifetime = (time_t) atol( cargv[ 1 ]);
+ } else if ( strcasecmp( cargv[ 0 ], "changeHTML" ) == 0 ) {
+ auto dsgwsubst *sub;
+ if ( templatesonly ) continue;
+ if ( cargc < 2 || cargv[ 1 ][ 0 ] == '\0') continue;
+ sub = (dsgwsubst *)dsgw_ch_malloc( sizeof( dsgwsubst ));
+ memset( sub, 0, sizeof( dsgwsubst ));
+ sub->dsgwsubst_from = dsgw_ch_strdup( cargv[ 1 ] );
+ if ( cargc > 2 ) {
+ sub->dsgwsubst_to = dsgw_ch_strdup( cargv[ 2 ] );
+ if ( cargc > 3 ) {
+ auto size_t i;
+ sub->dsgwsubst_charsets = (char **)dsgw_ch_malloc
+ (sizeof(char*) * (cargc - 2));
+ for (i = 3; i < cargc; ++i) {
+ sub->dsgwsubst_charsets[ i-3 ] = dsgw_ch_strdup( cargv[ i ] );
+ }
+ sub->dsgwsubst_charsets[ i-3 ] = NULL;
+ }
+ }
+ { /* append sub to gc->gc_changeHTML: */
+ auto dsgwsubst **s = &(gc->gc_changeHTML);
+ while (*s) s = &((*s)->dsgwsubst_next);
+ *s = sub;
+ }
+
+ } else if ( strcasecmp( cargv[0], "dirmgr" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForDirmgrDirectiv_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_rootdn = dsgw_ch_strdup( cargv[ 1 ]);
+ } else if ( strcasecmp( cargv[0], "url-orgchart-base" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForOrgChartURLDirectiv_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_orgcharturl = dsgw_ch_strdup( cargv[ 1 ]);
+ } else if ( strcasecmp( cargv[0], "orgchart-attrib-farleft-rdn" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForOrgChartSearchAttr_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_orgchartsearchattr = dsgw_ch_strdup( cargv[ 1 ]);
+ } else if ( strcasecmp( cargv[0], "enable-aim-presence" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if (cargc < 2 || strcasecmp(cargv[1], "true") == 0) {
+ gc->gc_aimpresence = 1;
+ } else {
+ gc->gc_aimpresence = 0;
+ }
+ } else if ( strcasecmp( cargv[0], "baseurl" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForBaseurlDirecti_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_baseurl = dsgw_ch_strdup( cargv[ 1 ]);
+ if (( rc = ldap_url_parse( gc->gc_baseurl, &ludp )) != 0 ) {
+ switch ( rc ) {
+ case LDAP_URL_ERR_NODN:
+ adderr( gc, XP_GetClientStr(DBT_badUrlProvidedForBaseurlDirectiv_), filename, lineno );
+ break;
+ case LDAP_URL_ERR_MEM:
+ dsgw_error( DSGW_ERR_NOMEMORY,
+ XP_GetClientStr(DBT_parsingBaseurlDirective_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ break;
+ case LDAP_URL_ERR_NOTLDAP:
+ adderr( gc, XP_GetClientStr(DBT_badUrlProvidedForBaseurlDirectiv_1), filename, lineno );
+ break;
+ }
+ } else {
+ gc->gc_ldapserver = ludp->lud_host;
+ gc->gc_ldapport = ludp->lud_port;
+ if ( ludp->lud_dn == NULL ) {
+ gc->gc_ldapsearchbase = dsgw_ch_strdup( "" );
+ } else {
+ gc->gc_ldapsearchbase = ludp->lud_dn;
+ }
+ if (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 ) {
+#ifdef DSGW_NO_SSL
+ adderr( gc, XP_GetClientStr(DBT_LdapsUrlsAreNotYetSupportedN_),
+ filename, lineno );
+#else
+ gc->gc_ldapssl = 1;
+#endif
+ }
+ }
+
+ } else if ( strcasecmp( cargv[0], "template" ) == 0 ) {
+ if ( cargc < 3 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentsForTemplateDirec_),
+ filename, lineno );
+ continue;
+ }
+ dsgw_addtemplate( &gc->gc_templates, cargv[1], cargc - 2,
+ &cargv[2] );
+
+#ifndef DSGW_NO_SSL
+ } else if ( strcasecmp( cargv[0], "sslrequired" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForSslrequiredDir_),
+ filename, lineno );
+ continue;
+ }
+ if ( strcasecmp( cargv[1], "never" ) == 0 ) {
+ gc->gc_sslrequired = DSGW_SSLREQ_NEVER;
+ } else if ( strcasecmp( cargv[1], "whenauthenticated" ) == 0 ) {
+ gc->gc_sslrequired = DSGW_SSLREQ_WHENAUTHENTICATED;
+ } else if ( strcasecmp( cargv[1], "always" ) == 0 ) {
+ gc->gc_sslrequired = DSGW_SSLREQ_ALWAYS;
+ } else {
+ adderr( gc, XP_GetClientStr(DBT_unknownArgumentToSslrequiredDire_), filename, lineno );
+ }
+
+ } else if ( strcasecmp( cargv[0], "securitypath" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForSecuritypathDi_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_securitypath = dsgw_ch_strdup( cargv[1] );
+#endif /* !DSGW_NO_SSL */
+
+ } else if ( strcasecmp( cargv[0], "htmldir" ) == 0 ) {
+ int lenth = 0;
+
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForHtmlpathDi_),
+ filename, lineno );
+ continue;
+ }
+
+ lenth = strlen(cargv[1]);
+
+ /*See if the user put a slash at the end of the htmldir directive..*/
+ if (cargv[1][lenth - 1] == '/' || cargv[1][lenth - 1] == '\\') {
+ gc->gc_docdir = dsgw_ch_strdup( cargv[1] );
+ } else {
+ /*If not, put it there*/
+ lenth ++;
+ gc->gc_docdir = dsgw_ch_malloc ((lenth+MAXPATHLEN) *sizeof (char));
+ PR_snprintf(gc->gc_docdir, lenth + MAXPATHLEN, "%s/", cargv[1]);
+ }
+ /* The nametrans used. For the gw, it's /dsgw/html/ */
+ } else if ( strcasecmp( cargv[0], "gwnametrans" ) == 0 ) {
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForNametransDi_),
+ filename, lineno );
+ continue;
+ }
+
+ /*
+ * This is needed for redirection. Can't use relative paths
+ * for Location:. If the gateway/phonebook/userDefinedGateway
+ * is running under a web server, it should be the html nametrans
+ * used to map to the html files. If it's under the admin server,
+ * it should be /dsgw/DIRECTORY_OF_HTML_FILES/ (which should be
+ * the same as the nameTrans.
+ */
+ gc->gc_gwnametrans = dsgw_ch_strdup( cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "configdir" ) == 0 ) {
+ int lenth = 0;
+
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForConfigpathDi_),
+ filename, lineno );
+ continue;
+ }
+
+ lenth = strlen(cargv[1]);
+
+ /*See if the user put a slash at the end of the htmldir directive..*/
+ if (cargv[1][lenth - 1] == '/' || cargv[1][lenth - 1] == '\\') {
+ gc->gc_configdir = dsgw_ch_strdup( cargv[1] );
+ } else {
+ /*If not, put it there*/
+ lenth ++;
+ gc->gc_configdir = dsgw_ch_malloc ((lenth+MAXPATHLEN) * sizeof (char));
+ PR_snprintf(gc->gc_configdir, lenth + MAXPATHLEN, "%s/",
+ cargv[1]);
+ }
+
+ gc->gc_tmpldir = dsgw_ch_strdup( gc->gc_configdir );
+
+ } else if ( strcasecmp( cargv[0], "location-suffix" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_missingArgumentForLocationSuffix_),
+ filename, lineno );
+ continue;
+ }
+ if ( locsuffix != NULL ) {
+ free( locsuffix );
+ }
+ locsuffix = dsgw_ch_strdup( cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "location" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 4 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_threeArgumentsAreRequiredForTheL_),
+ filename, lineno );
+ continue;
+ }
+ add_location( &gc->gc_newentryloccount, &gc->gc_newentrylocs,
+ locsuffix, &cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "newtype" ) == 0 ) {
+ if ( templatesonly ) continue;
+ if ( cargc < 3 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_atLeastTwoArgumentsAreRequiredFo_),
+ filename, lineno );
+ continue;
+ }
+ if ( add_newtype( &gc->gc_newentrytypes, gc->gc_newentryloccount,
+ gc->gc_newentrylocs, cargc - 1, &cargv[1] ) < 0 ) {
+ adderr( gc, XP_GetClientStr(DBT_unknownLocationInNewtypeDirectiv_),
+ filename, lineno );
+ }
+
+ } else if ( strcasecmp( cargv[0], "tmplset" ) == 0 ) {
+ if ( cargc != 4 && cargc != 5 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_threeOrFourArgumentsAreRequiredF_),
+ filename, lineno );
+ continue;
+ }
+ add_tmplset( &gc->gc_tmplsets, cargc - 1, &cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "attrvset" ) == 0 ) {
+ if ( cargc != 5 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_fourArgumentsAreRequiredForTheAt_),
+ filename, lineno );
+ continue;
+ }
+ add_avset( &gc->gc_avsets, &cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "includeset" ) == 0 ) {
+ if ( cargc != 3 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_twoArgumentsAreRequiredForTheInc_),
+ filename, lineno );
+ continue;
+ }
+ add_includeset( &gc->gc_includesets, &cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "charset" ) == 0 ) {
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForCharsetDirecti_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_charset = dsgw_ch_strdup( cargv[1] );
+
+/* the following is not needed because AdminServer */
+/* puts these into environment from ns-admin.conf */
+#ifdef NEED_LANG_FROM_DSGW_CONF
+ } else if ( strcasecmp( cargv[0], "ClientLanguage" ) == 0 ) {
+ if ( cargc < 2 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_missingArgumentForClientlanguage_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_ClientLanguage = dsgw_ch_strdup( cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "AdminLanguage" ) == 0 ) {
+ if ( cargc < 2 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_missingArgumentForAdminlanguageD_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_AdminLanguage = dsgw_ch_strdup( cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "DefaultLanguage" ) == 0 ) {
+ if ( cargc < 2 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_missingArgumentForDefaultlanguag_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_DefaultLanguage = dsgw_ch_strdup( cargv[1] );
+#endif
+
+ } else if ( strcasecmp( cargv[0], "NLS" ) == 0 ) {
+ if ( cargc < 2 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_missingArgumentForNLS_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_NLS = dsgw_ch_strdup( cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "vcard-property" ) == 0 ) {
+ if ( cargc != 4 && cargc != 5 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_threeOrFourArgumentsAreRequiredF_2),
+ filename, lineno );
+ continue;
+ }
+ if ( strcmp( cargv[2], "cis" ) != 0
+ && strcmp( cargv[2], "mls" ) != 0 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_vcardPropertySyntaxMustBeCisOrMl_),
+ filename, lineno );
+ continue;
+ }
+ add_vcardproperty( &gc->gc_vcardproperties, cargc - 1, &cargv[1] );
+
+ } else if ( strcasecmp( cargv[0], "ignoreAcceptCharsetFrom" ) == 0 ) {
+ int i;
+ gc->gc_clientIgnoreACharset = (char **)dsgw_ch_malloc( cargc );
+ --cargc;
+ for (i = 0; i < cargc; i++)
+ gc->gc_clientIgnoreACharset[i] = dsgw_ch_strdup_tolower( cargv[i+1] );
+ gc->gc_clientIgnoreACharset[i] = NULL;
+
+ } else if ( strcasecmp( cargv[0], "translate" ) == 0 ) {
+ if ( cargc != 3 ) {
+ adderr( gc,
+ XP_GetClientStr(DBT_twoArgumentsAreRequiredForTheInc_),
+ filename, lineno );
+ continue;
+ }
+ add_l10nset( &gc->gc_l10nsets, &cargv[1] );
+
+ /* include another config file */
+ } else if ( strcasecmp( cargv[0], "include" ) == 0 ) {
+ char *tmpfname = NULL;
+ char *path = NULL;
+ char *p;
+ int len;
+
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingFilenameForIncludeDirecti_),
+ filename, lineno );
+ continue;
+ }
+ len = strlen( cargv[1] ) + 11;
+ tmpfname = dsgw_ch_malloc( len );
+ p = strrchr( cargv[1], '/' );
+ if ( p != NULL ) {
+ *p++ = '\0';
+ sprintf( tmpfname, "%s/$$LANGDIR/%s", cargv[1], p);
+ *(--p) = DSGW_PATHSEP_CHAR;
+ } else {
+ p = cargv[1];
+ sprintf( tmpfname, "$$LANGDIR/%s", p);
+ }
+
+ /* allocate buffers with enough extra room to fit "$$LANGDIR/" */
+ if ( NULL != gc->gc_ClientLanguage ) {
+ len += strlen( gc->gc_ClientLanguage );
+ }
+ path = dsgw_ch_malloc( len );
+ if ( GetFileForLanguage( tmpfname, gc->gc_ClientLanguage, path ) < 0 )
+ strcpy( path, cargv[1] );
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "tmpfile: %s, path: %s, lang: %s\n",
+ tmpfname, path, gc->gc_ClientLanguage );
+#endif
+ read_dsgwconfig( path, locsuffix, templatesonly, 0 );
+ if ( tmpfname ) free( tmpfname );
+ if ( path ) free( path );
+
+ /*Special file that has binddn and password*/
+ } else if ( strcasecmp( cargv[0], "binddnfile" ) == 0 ) {
+ char *tmpfname;
+
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingFilenameForBinddnfileDirecti_),
+ filename, lineno );
+ continue;
+ }
+
+ /* Make sure it has at least 1 slash in it */
+ if ( strstr(cargv[1], "/") == NULL) {
+ adderr( gc, XP_GetClientStr(DBT_badFilenameForBinddnfileDirecti_),
+ filename, lineno );
+ continue;
+ }
+
+ /* ... and no ".."'s */
+ if ( strstr(cargv[1], "..") != NULL) {
+ adderr( gc, XP_GetClientStr(DBT_badFilenameForBinddnfileDirecti_),
+ filename, lineno );
+ continue;
+ }
+
+ /* And no "dsgw" in it */
+ if ( strstr(cargv[1], "/dsgw/") != NULL) {
+ adderr( gc, XP_GetClientStr(DBT_badFilenameForBinddnfileDirecti_),
+ filename, lineno );
+ continue;
+ }
+
+
+ tmpfname = dsgw_ch_strdup( cargv[1] );
+ read_dsgwconfig( tmpfname, locsuffix, templatesonly, 1 /*binddn file*/ );
+ free( tmpfname );
+ /*
+ * Only consider the binddn directive if this file was
+ * included from another file with the binddnfile
+ * directive. This is to prevent the stupid user from
+ * inlining the binddn and bindpw in dsgw.conf. This is
+ * bad because you can read dsgw.conf with a browser if
+ * you set up your web server to serve up the gateway.
+ * Just goto http://host/dsgw/context/dsgw.conf . It is
+ * my hope that the binddn file will be outside
+ * NS-HOME/dsgw, because people can get at it if it's in
+ * there.
+ */
+ } else if ( strcasecmp( cargv[0], "binddn" ) == 0 ) {
+ if (!binddnfile) {
+ adderr( gc, XP_GetClientStr(DBT_wrongPlaceForBinddnDirectiv_),
+ filename, lineno );
+ continue;
+ }
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForBinddnDirectiv_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_binddn = dsgw_ch_strdup( cargv[ 1 ]);
+
+ } else if ( strcasecmp( cargv[0], "bindpw" ) == 0 ) {
+ if (!binddnfile) {
+ adderr( gc, XP_GetClientStr(DBT_wrongPlaceForBinddnDirectiv_),
+ filename, lineno );
+ continue;
+ }
+
+ if ( templatesonly ) continue;
+ if ( cargc < 2 ) {
+ adderr( gc, XP_GetClientStr(DBT_missingArgumentForBindpwDirectiv_),
+ filename, lineno );
+ continue;
+ }
+ gc->gc_bindpw = dsgw_ch_strdup( cargv[ 1 ]);
+
+ } else {
+ adderr( gc, XP_GetClientStr(DBT_unknownDirectiveInConfigFileN_),
+ filename, lineno );
+ }
+ }
+
+ if ( gc == NULL || gc->gc_configerr > 0 ) {
+ dsgw_error( DSGW_ERR_BADCONFIG, ( gc->gc_configerrstr == NULL ) ?
+ "" : gc->gc_configerrstr, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+}
+
+int
+erase_db() {
+
+ FILE *fp;
+ int rc, lineno;
+ char *line;
+ char *cargv[ MAXARGS ];
+ int cargc;
+ char cmd[ BIG_LINE ];
+
+ if ( (fp = fopen( gc->gc_localdbconf, "r" )) == NULL ) {
+ dsgw_emitf (XP_GetClientStr(DBT_EraseDbCouldNotOpenLcacheConfFil_),
+ gc->gc_localdbconf);
+ return( -1 );
+ }
+ fp_getline_init( &lineno );
+
+ while ( (line = fp_getline( fp, &lineno )) != NULL ) {
+ fp_parse_line( line, &cargc, cargv );
+ if ( strcasecmp( cargv[0], "directory" ) == 0) {
+#ifdef XP_WIN32
+ dsgw_unix2dospath( cargv[1] );
+#endif
+ PR_snprintf (cmd, BIG_LINE, "%s %s%c* > %s 2>&1", DSGW_DELETE_CMD, cargv[1],
+ DSGW_PATHSEP_CHAR, DSGW_NULL_DEVICE);
+ fflush (0);
+ if (system (cmd) == 0) {
+ /*
+ * success: display status message
+ */
+ dsgw_emits( XP_GetClientStr(DBT_FontSize1NPTheDatabaseHasBeenDel_) );
+ rc = 0;
+ }
+ else {
+ dsgw_emits( XP_GetClientStr(DBT_FontSize1NPTheDatabaseCouldNotBe_) );
+ rc = -1;
+ }
+
+ dsgw_emits( "<HR>\n" );
+ fclose( fp );
+ return( rc );
+ }
+ }
+ return -1;
+}
+
+void
+app_suffix (char *ldif, char *suffix)
+{
+ FILE *oldfp, *newfp;
+ char *orig_line;
+ char *p;
+ char buf[BUFSIZ];
+ int i, cargc;
+ char *cargv[ 100 ];
+ char tmpldif[ 128 ];
+ char *dns[] = { "aliasedobjectname:",
+ "aliasedobjectname:",
+ "associatedname:",
+ "dependentupon:",
+ "ditredirect:",
+ "dn:",
+ "documentauthor:",
+ "documentauthor:",
+ "documentavailable:",
+ "errorsto:",
+ "errorsto:",
+ "imagefiles:",
+ "lastmodifiedby:",
+ "manager:",
+ "member:",
+ "memberofgroup:",
+ "naminglink:",
+ "naminglink:",
+ "obsoletedbydocument:",
+ "obsoletesdocument:",
+ "owner:",
+ "proxy:",
+ "reciprocalnaminglink:",
+ "reciprocalnaminglink:",
+ "replicaroot:",
+ "replicabinddn:",
+ "requeststo:",
+ "roleoccupant:",
+ "secretary:",
+ "seealso:",
+ "uniqueMember:",
+ "updatedbydocument:",
+ "updatesdocument:",
+ NULL
+ };
+
+
+ if ( (oldfp = fopen( ldif, "r" )) == NULL ) {
+ dsgw_emitf (XP_GetClientStr(DBT_AppSuffixCouldNotOpenLdifFileSN_),
+ ldif);
+ return;
+ }
+
+ PR_snprintf( tmpldif, 128, "%s.tmp", ldif);
+ if ( (newfp = fopen( tmpldif, "w" )) == NULL ) {
+ dsgw_emitf (XP_GetClientStr(DBT_AppSuffixCouldNotOpenTmpFileSN_),
+ ldif);
+ return;
+ }
+ while ( fgets( buf, sizeof(buf), oldfp ) != NULL ) {
+ /* skip comments and blank lines */
+ if ( buf[0] == '#' || buf[0] == '\0' || buf[0] == '\n') {
+ fputs( buf, newfp );
+ continue;
+ }
+ orig_line = dsgw_ch_strdup( buf );
+
+ fp_parse_line( buf, &cargc, cargv );
+ for (i=0; dns[i]!=NULL; i++) {
+ if ( strcasecmp( cargv[0], dns[i] ) == 0 ) {
+ if ( (p = strchr( orig_line, '\n' )) != NULL ) {
+ *p = '\0';
+ }
+ fprintf ( newfp, "%s, %s\n", orig_line, suffix );
+ break;
+ }
+ }
+
+ if ( dns[i] == NULL ) {
+ fputs( orig_line, newfp );
+ }
+ free (orig_line);
+ }
+ fclose(newfp);
+ fclose(oldfp);
+ unlink( ldif );
+ if ( rename( tmpldif, ldif ) != 0 ) {
+ dsgw_emitf (XP_GetClientStr(DBT_unableToRenameSToS_), tmpldif, ldif );
+ return;
+ }
+}
+
+/*
+ * Running under admserv - traverse the list of property/value pairs
+ * returned by dbconf_read_default_dbinfo().
+ */
+static void
+get_dbconf_properties( char *filename )
+{
+ DBConfDBInfo_t *db_info;
+ DBPropVal_t *dbp;
+ int rc;
+ LDAPURLDesc *ludp;
+ LDAPDBURLDesc *ldbudp;
+
+ if (( rc = dbconf_read_default_dbinfo( filename, &db_info ))
+ != LDAPU_SUCCESS ) {
+ report_ldapu_error( rc, DSGW_ERR_BADCONFIG, DSGW_ERROPT_EXIT );
+ }
+
+ if ( db_info == NULL ) {
+ dsgw_error( DSGW_ERR_DBCONF,
+ XP_GetClientStr(DBT_nullPointerReturnedByDbconfReadD_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if ( strcasecmp( db_info->dbname, DBCONF_DEFAULT_DBNAME ) != 0 ) {
+ dsgw_error( DSGW_ERR_DBCONF, db_info->dbname, DSGW_ERROPT_EXIT, 0,
+ NULL );
+ }
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "opened dbconf, dbname is %s, dburl is %s\n", db_info->dbname,
+ db_info->url );
+#endif
+
+ /* Parse the LDAPURL or LDAPDBURL */
+ gc->gc_baseurl = dsgw_ch_strdup( db_info->url );
+ rc = ldapdb_url_parse( gc->gc_baseurl, &ldbudp );
+
+ if ( rc == 0 ) {
+ gc->gc_localdbconf = dsgw_ch_strdup( ldbudp->ludb_path );
+ gc->gc_ldapserver = NULL;
+ gc->gc_ldapport = -1;
+ gc->gc_ldapsearchbase = dsgw_ch_strdup( ldbudp->ludb_dn );
+#ifndef DSGW_NO_SSL
+ gc->gc_ldapssl = 0;
+#endif
+
+ /* If url isn't "ldapdb://", let the code below have a crack */
+ } else if ( rc != DSGW_ERR_LDAPDBURL_NOTLDAPDB ) {
+ switch ( rc ) {
+ case DSGW_ERR_LDAPDBURL_NODN:
+ adderr( gc, XP_GetClientStr(DBT_badLdapdbUrlTheBaseDnIsMissingN_), NULL, 0 );
+ break;
+ case DSGW_ERR_LDAPDBURL_BAD:
+ adderr( gc, XP_GetClientStr(DBT_badLdapdbUrlN_), NULL, 0 );
+ break;
+ }
+ } else {
+ if (( rc = ldap_url_parse( gc->gc_baseurl, &ludp )) != 0 ) {
+ switch ( rc ) {
+ case LDAP_URL_ERR_NODN:
+ adderr( gc, XP_GetClientStr(DBT_badUrlProvidedForBaseurlDirectiv_2),
+ NULL, 0 );
+ break;
+ case LDAP_URL_ERR_MEM:
+ dsgw_error( DSGW_ERR_NOMEMORY,
+ XP_GetClientStr(DBT_parsingBaseurlDirective_1),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ break;
+ case LDAP_URL_ERR_NOTLDAP:
+ adderr( gc, XP_GetClientStr(DBT_badUrlProvidedForBaseurlDirectiv_3), NULL, 0 );
+ break;
+ }
+ } else {
+ gc->gc_ldapserver = ludp->lud_host;
+ gc->gc_ldapport = ludp->lud_port;
+ if ( ludp->lud_dn == NULL ) {
+ gc->gc_ldapsearchbase = dsgw_ch_strdup( "" );
+ } else {
+ gc->gc_ldapsearchbase = ludp->lud_dn;
+ }
+ if ( ( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 ) {
+#ifdef DSGW_NO_SSL
+ adderr( gc, XP_GetClientStr(DBT_LdapsUrlsAreNotYetSupportedN_1),
+ NULL, 0 );
+#else
+ gc->gc_ldapssl = 1;
+#endif
+ }
+ }
+ }
+
+ /* Look through the properties for binddn and bindpw */
+ for ( dbp = db_info->firstprop; dbp != NULL; dbp = dbp->next ) {
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "get prop: prop = %s, val = %s\n", dbp->prop, dbp->val );
+#endif
+
+ if ( strcasecmp( dbp->prop, "binddn" ) == 0 ) {
+ if ( dbp->val == NULL || strlen( dbp->val ) == 0 ) {
+ dsgw_error( DSGW_ERR_DBCONF,
+ XP_GetClientStr(DBT_noValueGivenForBinddn_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ gc->gc_binddn = dsgw_ch_strdup( dbp->val );
+
+ } else if ( strcasecmp( dbp->prop, "bindpw" ) == 0 ) {
+ if ( dbp->val == NULL || strlen( dbp->val ) == 0 ) {
+ dsgw_error( DSGW_ERR_DBCONF,
+ XP_GetClientStr(DBT_noValueGivenForBindpw_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ gc->gc_bindpw = dsgw_ch_strdup( dbp->val );
+ }
+ }
+
+ if ( gc == NULL || gc->gc_configerr > 0 ) {
+ dsgw_error( DSGW_ERR_BADCONFIG, ( gc->gc_configerrstr == NULL ) ?
+ "" : gc->gc_configerrstr, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ if ( gc->gc_baseurl == NULL ) {
+ dsgw_error( DSGW_ERR_BADCONFIG,
+ XP_GetClientStr(DBT_thereIsNoDefaultDirectoryService_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ return;
+}
+
+
+/*
+ * Update the dbswitch.conf file (used under admin. server) to reflect
+ * the local/remote directory information contained in "cfgp". Our basic
+ * strategy is to read the existing dbswitch.conf file, replacing and adding
+ * lines that look like this:
+ * directory <dbhandle> ...
+ * <dbhandle>:binddn ...
+ * <dbhandle>:encoded bindpw ...
+ * as necessary. We write a new, temporary config file (copying all other
+ * lines over unchanged) and then replace the old file with our new one.
+ *
+ * If cfgp is configured for localdb mode, we only write a directory line.
+ *
+ * We return zero if all goes well and non-zero if not.
+ *
+ * Note that all reading and writing of the dbswitch.conf file is now done
+ * using the dbconf...() functions that are part of the ldaputil library, so
+ * any comments, blank lines, or unrecognized config file lines will be lost.
+ * Also, all "bindpw" property values will be encoded when re-written.
+ *
+ * Only these members of the cfgp structure are used in this function:
+ * gc_localdbconf (NULL if using remote LDAP server)
+ * gc_ldapsearchbase
+ * gc_ldapserver
+ * gc_ldapport
+ * gc_ldapssl
+ * gc_binddn
+ * gc_bindpw
+ * Actually, if gc_localdbconf is not NULL, only it and gc_ldapsearchbase are
+ * used.
+ */
+int
+dsgw_update_dbswitch( dsgwconfig *cfgp, char *dbhandle, int erropts )
+{
+ char oldfname[ MAXPATHLEN ], newfname[ MAXPATHLEN ];
+ char *userdb_path, buf[ MAXPATHLEN + 100 ];
+ int rc, wrote_dbinfo;
+ FILE *newfp;
+ DBConfInfo_t *cip;
+ DBConfDBInfo_t *dbip;
+ DBPropVal_t *pvp;
+
+ if ( dbhandle == NULL ) {
+ dbhandle = "default";
+ }
+
+ if (( userdb_path = get_userdb_dir()) == NULL ) {
+ dsgw_error( DSGW_ERR_USERDB_PATH, NULL, erropts, 0, NULL );
+ return( -1 );
+ }
+
+ /* read old dbswitch.conf contents */
+ PR_snprintf( oldfname, MAXPATHLEN, "%s/%s", userdb_path,
+ DSGW_DBSWITCH_FILE );
+ if (( rc = dbconf_read_config_file( oldfname, &cip )) != LDAPU_SUCCESS ) {
+ report_ldapu_error( rc, DSGW_ERR_BADCONFIG, erropts );
+ return( -1 );
+ }
+
+ /* write db info to new file, replacing information for "dbhandle" */
+ PR_snprintf( newfname, MAXPATHLEN, "%s/%s", userdb_path,
+ DSGW_DBSWITCH_TMPFILE );
+ if (( newfp = fopen( newfname, "w" )) == NULL ) {
+ PR_snprintf( buf, MAXPATHLEN + 100,
+ XP_GetClientStr(DBT_cannotOpenConfigFileSForWritingN_), newfname );
+ dsgw_error( DSGW_ERR_UPDATE_DBSWITCH, buf, erropts, 0, NULL );
+ return( -1 );
+ }
+
+ wrote_dbinfo = 0;
+ for ( dbip = cip->firstdb; dbip != NULL; dbip = dbip->next ) {
+ if ( strcasecmp( dbip->dbname, dbhandle ) == 0 ) {
+ /*
+ * found db name to be replaced: replace with updated information
+ */
+ if (( rc = write_dbswitch_info( newfp, cfgp, dbhandle )) !=
+ LDAPU_SUCCESS ) {
+ report_ldapu_error( rc, DSGW_ERR_UPDATE_DBSWITCH, erropts );
+ return( -1 );
+ }
+
+ wrote_dbinfo = 1;
+
+ } else {
+ /*
+ * re-write existing db conf information without changes
+ */
+ if (( rc = dbconf_output_db_directive( newfp, dbip->dbname,
+ dbip->url )) != LDAPU_SUCCESS ) {
+ report_ldapu_error( rc, DSGW_ERR_UPDATE_DBSWITCH, erropts );
+ return( -1 );
+ }
+
+ for ( pvp = dbip->firstprop; pvp != NULL; pvp = pvp->next ) {
+ if (( rc = dbconf_output_propval( newfp, dbip->dbname,
+ pvp->prop, pvp->val,
+ strcasecmp( pvp->prop, "bindpw" ) == 0 ))
+ != LDAPU_SUCCESS ) {
+ report_ldapu_error( rc, DSGW_ERR_UPDATE_DBSWITCH, erropts );
+ return( -1 );
+ }
+ }
+ }
+ }
+
+ if ( !wrote_dbinfo ) {
+ if (( rc = write_dbswitch_info( newfp, cfgp, dbhandle )) !=
+ LDAPU_SUCCESS ) {
+ report_ldapu_error( rc, DSGW_ERR_UPDATE_DBSWITCH, erropts );
+ return( -1 );
+ }
+ }
+
+ dbconf_free_confinfo( cip );
+ fclose( newfp );
+
+ /* replace old file with new one */
+#ifdef _WIN32
+ if ( !MoveFileEx( newfname, oldfname, MOVEFILE_REPLACE_EXISTING )) {
+#else
+ if ( rename( newfname, oldfname ) != 0 ) {
+#endif
+ PR_snprintf( buf, MAXPATHLEN + 100,
+ XP_GetClientStr(DBT_unableToRenameSToS_1), newfname, oldfname );
+ dsgw_error( DSGW_ERR_UPDATE_DBSWITCH, buf, erropts, 0, NULL );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+static int
+write_dbswitch_info( FILE *fp, dsgwconfig *cfgp, char *dbhandle )
+{
+ char *escapeddn, *url;
+ int rc;
+
+ escapeddn = dsgw_strdup_escaped( cfgp->gc_ldapsearchbase );
+
+ if ( cfgp->gc_localdbconf == NULL ) { /* remote server: write ldap:// URL */
+ url = dsgw_ch_malloc( 21 + strlen( cfgp->gc_ldapserver )
+ + strlen( escapeddn )); /* room for "ldaps://HOST:PORT/DN" */
+ sprintf( url, "ldap%s://%s:%d/%s",
+#ifdef DSGW_NO_SSL
+ "",
+#else
+ cfgp->gc_ldapssl ? "s" : "",
+#endif
+ cfgp->gc_ldapserver, cfgp->gc_ldapport, escapeddn );
+ } else { /* local db: write ldapdb:// URL */
+ url = dsgw_ch_malloc( 11 + strlen( cfgp->gc_localdbconf )
+ + strlen( escapeddn )); /* room for "ldapdb://PATH/DN" */
+ sprintf( url, "ldapdb://%s/%s\n", cfgp->gc_localdbconf, escapeddn );
+ }
+
+ rc = dbconf_output_db_directive( fp, dbhandle, url );
+
+ free( url );
+ free( escapeddn );
+
+ if ( rc != LDAPU_SUCCESS ) {
+ return( rc );
+ }
+
+ if ( cfgp->gc_localdbconf == NULL ) { /* using directory server */
+ if ( cfgp->gc_binddn != NULL &&
+ ( rc = dbconf_output_propval( fp, dbhandle, "binddn",
+ cfgp->gc_binddn, 0 ) != LDAPU_SUCCESS )) {
+ return( rc );
+ }
+
+ if ( cfgp->gc_bindpw != NULL &&
+ ( rc = dbconf_output_propval( fp, dbhandle, "bindpw",
+ cfgp->gc_bindpw, 1 ) != LDAPU_SUCCESS )) {
+ return( rc );
+ }
+ }
+
+ return( LDAPU_SUCCESS );
+}
+
+
+/* pass 0 for lineno if it is unknown or not applicable */
+static void
+adderr( dsgwconfig *gc, char *str, char *filename, int lineno )
+{
+ char *lbuf = dsgw_ch_malloc( MAXPATHLEN + 200 );
+
+ gc->gc_configerr++;
+ if ( lineno == 0 ) {
+ PR_snprintf( lbuf, MAXPATHLEN + 200,
+ XP_GetClientStr(DBT_configFileS_), filename );
+ } else {
+ PR_snprintf( lbuf, MAXPATHLEN + 200,
+ XP_GetClientStr(DBT_configFileSLineD_), filename, lineno );
+ }
+ gc->gc_configerrstr = dsgw_ch_realloc( gc->gc_configerrstr,
+ strlen( gc->gc_configerrstr ) + strlen( str )
+ + strlen( lbuf ) + 6 );
+ strcat( gc->gc_configerrstr, lbuf );
+ strcat( gc->gc_configerrstr, str );
+ strcat( gc->gc_configerrstr, "<BR>\n" );
+ free( lbuf );
+}
+
+
+static void
+add_location( int *loccountp, dsgwloc **locarrayp, char *locsuffix,
+ char **argv )
+{
+ int len;
+ dsgwloc *locp;
+
+ *locarrayp = (dsgwloc *)dsgw_ch_realloc( *locarrayp,
+ ( *loccountp + 1 ) * sizeof( dsgwloc ));
+ locp = &((*locarrayp)[ *loccountp ]);
+ locp->dsloc_handle = dsgw_ch_strdup( argv[0] );
+ locp->dsloc_fullname = dsgw_ch_strdup( argv[1] );
+ len = strlen( argv[2] );
+
+ if ( argv[2][ len - 1 ] == '#' ) {
+ /* '#' implies that locsuffix is not to be appended */
+ locp->dsloc_dnsuffix = dsgw_ch_strdup( argv[2] );
+ locp->dsloc_dnsuffix[ len - 1 ] = '\0';
+
+ } else if ( locsuffix != NULL && *locsuffix != '\0' ) {
+ /* append suffix, preceded by ", " if location arg. is not "" */
+ locp->dsloc_dnsuffix = dsgw_ch_malloc( len + strlen( locsuffix ) + 3 );
+ if ( argv[2][0] != '\0' ) {
+ strcpy( locp->dsloc_dnsuffix, argv[2] );
+ strcat( locp->dsloc_dnsuffix, ", " );
+ strcat( locp->dsloc_dnsuffix, locsuffix );
+ } else {
+ strcpy( locp->dsloc_dnsuffix, locsuffix );
+ }
+
+ } else {
+ locp->dsloc_dnsuffix = dsgw_ch_strdup( argv[2] );
+ }
+ ++(*loccountp);
+}
+
+
+static int
+add_newtype( dsgwnewtype **newentlistp, int loccount, dsgwloc *locarray,
+ int argc, char **argv )
+{
+ int i, j;
+ dsgwnewtype *ntp, *prevntp;
+
+ ntp = (dsgwnewtype *)dsgw_ch_malloc( sizeof( dsgwnewtype ));
+ ntp->dsnt_template = dsgw_ch_strdup( argv[0] );
+ ntp->dsnt_fullname = dsgw_ch_strdup( argv[1] );
+ ntp->dsnt_rdnattr = dsgw_ch_strdup( argv[2] );
+ ntp->dsnt_next = NULL;
+ ntp->dsnt_loccount = argc - 3;
+ argv = &argv[3];
+
+ /* fill dsnt_locations array with indexes into gc->gc_newentrylocs */
+ if ( ntp->dsnt_loccount <= 0 ) {
+ ntp->dsnt_locations = NULL;
+ } else {
+ int foundit;
+ ntp->dsnt_locations = (int *)dsgw_ch_malloc( ntp->dsnt_loccount *
+ sizeof( int ));
+ for ( i = 0; i < ntp->dsnt_loccount; ++i ) {
+ foundit = 0;
+ for ( j = 0; j < loccount && !foundit; ++j ) {
+ if ( strcasecmp( argv[ i ], locarray[ j ].dsloc_handle )
+ == 0 ) {
+ ntp->dsnt_locations[ i ] = j;
+ foundit = 1;
+ }
+ }
+ /* if ( j >= loccount ) { */
+ if ( !foundit ) {
+ return( -1 ); /* unknown location -- error */
+ }
+ }
+ }
+
+ /* append to linked list of new entry structures */
+ if ( *newentlistp == NULL ) {
+ *newentlistp = ntp;
+ } else {
+ for ( prevntp = *newentlistp; prevntp->dsnt_next != NULL;
+ prevntp = prevntp->dsnt_next ) {
+ ;
+ }
+ prevntp->dsnt_next = ntp;
+ }
+
+ return( 0 );
+}
+
+
+static void
+add_tmplset( dsgwtmplset **tslp, int argc, char **argv )
+{
+ dsgwtmplset *prevtsp, *tsp;
+ dsgwview *prevvp, *vp;
+
+ prevtsp = NULL;
+ tsp = *tslp;
+ while ( tsp != NULL ) {
+ if ( strcasecmp( tsp->dstset_name, argv[0] ) == 0 ) {
+ break;
+ }
+ prevtsp = tsp;
+ tsp = tsp->dstset_next;
+ }
+
+ if ( tsp == NULL ) { /* new template set */
+ tsp = (dsgwtmplset *)dsgw_ch_malloc( sizeof( dsgwtmplset ));
+ memset( tsp, 0, sizeof( dsgwtmplset ));
+ tsp->dstset_name = dsgw_ch_strdup( argv[0] );
+ if ( prevtsp == NULL ) {
+ *tslp = tsp;
+ } else {
+ prevtsp->dstset_next = tsp;
+ }
+ }
+
+ /* add a new view to the end of this template set's view list */
+ vp = (dsgwview *)dsgw_ch_malloc( sizeof( dsgwview ));
+ memset( vp, 0, sizeof( dsgwview ));
+ vp->dsview_caption = dsgw_ch_strdup( argv[1] );
+ vp->dsview_template = dsgw_ch_strdup( argv[2] );
+ if ( argc > 3 ) {
+ vp->dsview_jscript = dsgw_ch_strdup( argv[3] );
+ }
+
+ if ( tsp->dstset_viewlist == NULL ) {
+ tsp->dstset_viewlist = vp;
+ } else {
+ for ( prevvp = tsp->dstset_viewlist; prevvp->dsview_next != NULL;
+ prevvp = prevvp->dsview_next ) {
+ ;
+ }
+ prevvp->dsview_next = vp;
+ }
+ ++tsp->dstset_viewcount;
+}
+
+
+static void
+add_avset( dsgwavset **avsp, char **argv ) /* 4 args. in argv[] */
+{
+ dsgwavset *prevavp, *avp;
+
+ /* is this the first element of a set? */
+ prevavp = NULL;
+ for ( avp = *avsp; avp != NULL; avp = avp->dsavset_next ) {
+ if ( strcasecmp( avp->dsavset_handle, argv[0] ) == 0 ) {
+ break;
+ }
+ prevavp = avp;
+ }
+
+ if ( avp == NULL ) { /* first element: add a new set */
+ avp = (dsgwavset *)dsgw_ch_malloc( sizeof( dsgwavset ));
+ memset( avp, 0, sizeof( dsgwavset ));
+ avp->dsavset_handle = dsgw_ch_strdup( argv[0] );
+ if ( prevavp == NULL ) {
+ *avsp = avp;
+ } else {
+ prevavp->dsavset_next = avp;
+ }
+ }
+
+ ++avp->dsavset_itemcount;
+ avp->dsavset_values = (char **)dsgw_ch_realloc( avp->dsavset_values,
+ avp->dsavset_itemcount * sizeof( char * ));
+ avp->dsavset_values[ avp->dsavset_itemcount - 1 ] =
+ dsgw_ch_strdup( argv[1] );
+ avp->dsavset_prefixes = (char **)dsgw_ch_realloc( avp->dsavset_prefixes,
+ avp->dsavset_itemcount * sizeof( char * ));
+ avp->dsavset_prefixes[ avp->dsavset_itemcount - 1 ] =
+ dsgw_ch_strdup( argv[2] );
+ avp->dsavset_suffixes = (char **)dsgw_ch_realloc( avp->dsavset_suffixes,
+ avp->dsavset_itemcount * sizeof( char * ));
+ avp->dsavset_suffixes[ avp->dsavset_itemcount - 1 ] =
+ dsgw_ch_strdup( argv[3] );
+}
+
+
+static void
+add_includeset( dsgwinclset **isp, char **argv ) /* 2 args. in argv[] */
+{
+ dsgwinclset *previsp, *tmpisp;
+
+ /* is this the first element of a set? */
+ previsp = NULL;
+ for ( tmpisp = *isp; tmpisp != NULL; tmpisp = tmpisp->dsiset_next ) {
+ if ( strcasecmp( tmpisp->dsiset_handle, argv[0] ) == 0 ) {
+ break;
+ }
+ previsp = tmpisp;
+ }
+
+ if ( tmpisp == NULL ) { /* first element: add a new set */
+ tmpisp = (dsgwinclset *)dsgw_ch_malloc( sizeof( dsgwinclset ));
+ memset( tmpisp, 0, sizeof( dsgwinclset ));
+ tmpisp->dsiset_handle = dsgw_ch_strdup( argv[0] );
+ if ( previsp == NULL ) {
+ *isp = tmpisp;
+ } else {
+ previsp->dsiset_next = tmpisp;
+ }
+ }
+
+ ++tmpisp->dsiset_itemcount;
+ tmpisp->dsiset_filenames =
+ (char **)dsgw_ch_realloc( tmpisp->dsiset_filenames,
+ tmpisp->dsiset_itemcount * sizeof( char * ));
+ tmpisp->dsiset_filenames[ tmpisp->dsiset_itemcount - 1 ] =
+ dsgw_ch_strdup( argv[1] );
+}
+
+static void
+add_l10nset( dsgwsubst **l10np, char **argv ) /* 2 args, in argv[] */
+{
+ dsgwsubst *tmpsp;
+
+ tmpsp = (dsgwsubst *)dsgw_ch_malloc( sizeof( dsgwsubst ));
+ tmpsp->dsgwsubst_from = dsgw_ch_strdup( argv[0] );
+ tmpsp->dsgwsubst_to = dsgw_ch_strdup( argv[1] );
+ tmpsp->dsgwsubst_next = *l10np;
+ *l10np = tmpsp;
+}
+
+static void
+add_vcardproperty( dsgwvcprop **vcpropp, int argc, char **argv )
+{
+ dsgwvcprop *prevvcp, *newvcp, *vcp;
+
+ newvcp = (dsgwvcprop *)dsgw_ch_malloc( sizeof( dsgwvcprop ));
+ newvcp->dsgwvcprop_next = NULL;
+ newvcp->dsgwvcprop_property = dsgw_ch_strdup( argv[0] );
+ newvcp->dsgwvcprop_syntax = dsgw_ch_strdup( argv[1] );
+ newvcp->dsgwvcprop_ldaptype = dsgw_ch_strdup( argv[2] );
+ if ( argc == 3 ) {
+ newvcp->dsgwvcprop_ldaptype2 = NULL;
+ } else {
+ newvcp->dsgwvcprop_ldaptype2 = dsgw_ch_strdup( argv[3] );
+ }
+
+ prevvcp = NULL;
+ for ( vcp = *vcpropp; vcp != NULL; vcp = vcp->dsgwvcprop_next ) {
+ prevvcp = vcp;
+ }
+
+ if ( prevvcp == NULL ) {
+ *vcpropp = newvcp;
+ } else {
+ prevvcp->dsgwvcprop_next = newvcp;
+ }
+}
+
+
+static char *
+strtok_quote( char *line, char *sep )
+ /* This implementation can't handle characters > 127 in sep.
+ But it works fine for sep == " \t".
+ */
+{
+ int inquote;
+ char *tmp;
+ static char *next;
+
+ if ( line != NULL ) {
+ next = line;
+ }
+ while ( *next && strchr( sep, *next ) ) {
+ next++;
+ }
+
+ if ( *next == '\0' ) {
+ next = NULL;
+ return( NULL );
+ }
+ tmp = next;
+
+ for ( inquote = 0; *next; ) {
+ switch ( *next ) {
+ case '"':
+ if ( inquote ) {
+ inquote = 0;
+ } else {
+ inquote = 1;
+ }
+ strcpy( next, next + 1 );
+ break;
+
+#ifndef _WIN32
+ case '\\':
+ strcpy( next, next + 1 );
+ break;
+#endif
+
+ default:
+ if ( ! inquote ) {
+ if ( strchr( sep, *next ) != NULL ) {
+ *next++ = '\0';
+ return( tmp );
+ }
+ }
+ next++;
+ break;
+ }
+ }
+
+ return( tmp );
+}
+
+static char buf[BUFSIZ];
+static char *line;
+static int lmax, lcur;
+
+#define CATLINE( buf ) { \
+ int len; \
+ len = strlen( buf ); \
+ while ( lcur + len + 1 > lmax ) { \
+ lmax += BUFSIZ; \
+ line = (char *) dsgw_ch_realloc( line, lmax ); \
+ } \
+ strcpy( line + lcur, buf ); \
+ lcur += len; \
+}
+
+
+
+static void
+fp_parse_line(
+ char *line,
+ int *argcp,
+ char **argv
+)
+{
+ char * token, buf[ 20 ];
+
+ *argcp = 0;
+ for ( token = strtok_quote( line, " \t" ); token != NULL;
+ token = strtok_quote( NULL, " \t" ) ) {
+ if ( *argcp == MAXARGS ) {
+ PR_snprintf( buf, 20,
+ XP_GetClientStr(DBT_maxD_), MAXARGS );
+ dsgw_error( DSGW_ERR_CONFIGTOOMANYARGS, buf,
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ argv[(*argcp)++] = token;
+ }
+ argv[*argcp] = NULL;
+}
+
+
+
+static char *
+fp_getline( FILE *fp, int *lineno )
+{
+ char *p;
+
+ lcur = 0;
+
+ while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
+ if ( (p = strchr( buf, '\n' )) != NULL ) {
+ *p = '\0';
+ }
+ if ( lcur > 0 && ! ldap_utf8isspace( buf ) ) {
+ return( line ); /* return previously saved line */
+ }
+ CATLINE( buf );
+ (*lineno)++;
+ if ( ! ldap_utf8isspace( buf )) {
+ return( line ); /* return this line */
+ }
+ }
+ buf[0] = '\0';
+
+ return( lcur > 0 ? line : NULL );
+}
+
+static void
+fp_getline_init( int *lineno )
+{
+ *lineno = 0;
+ buf[0] = '\0';
+}
+
+
+static int
+ldapdb_url_parse( char *url, LDAPDBURLDesc **ldbudpp )
+{
+/*
+ * Pick apart the pieces of an ldapdb:// quasi-URL
+ */
+ LDAPDBURLDesc *ldbudp;
+ char *basedn;
+
+ *ldbudpp = NULL;
+
+ if ( strncasecmp( url, LDAPDB_URL_PREFIX, LDAPDB_URL_PREFIX_LEN )) {
+ return( DSGW_ERR_LDAPDBURL_NOTLDAPDB );
+ }
+
+ /* allocate return struct */
+ ldbudp = (LDAPDBURLDesc *) dsgw_ch_malloc( sizeof( LDAPDBURLDesc ));
+
+ /* Make a copy */
+ url = dsgw_ch_strdup( url );
+ ldbudp->ludb_path = url + LDAPDB_URL_PREFIX_LEN;
+
+ /* Must start with a "/" (or "x:" on NT) */
+ if ( ldbudp->ludb_path[ 0 ] != '/'
+#ifdef _WIN32
+ && ( !ldap_utf8isalpha( ldbudp->ludb_path )
+ || ldbudp->ludb_path[ 1 ] != ':' )
+#endif
+ ) {
+ free( url );
+ free( ldbudp );
+ return( DSGW_ERR_LDAPDBURL_BAD );
+ }
+
+ /* Find base DN */
+ if (( basedn = strrchr( ldbudp->ludb_path, '/' )) == NULL ) {
+ free( url );
+ free( ldbudp );
+ return( DSGW_ERR_LDAPDBURL_BAD );
+ }
+
+ *basedn++ = '\0';
+ ldbudp->ludb_dn = basedn;
+ dsgw_form_unescape( ldbudp->ludb_dn );
+
+ *ldbudpp = ldbudp;
+ return( 0 );
+}
+
+#ifdef XP_WIN32
+/* convert forward slashes to backwards ones */
+static void
+dsgw_unix2dospath( char *path )
+{
+ if( path ) {
+ while( *path ) {
+ if( *path == '/' ) {
+ *path = '\\';
+ }
+ path++;
+ }
+ }
+}
+#endif
+
+/*
+ * Function: dsgw_valid_context
+ *
+ * Returns: 1 if context doesn't have / . \ ,etc, 0 else
+ *
+ * Description: context is the name of the config file
+ * that is passed into the CGI.
+ * Let's say context = pb
+ * then it gets translated into: ../context/pb.conf
+ * so we have to make sure that context
+ * only contains numbers or letters, and nothing else
+ *
+ * Author: RJP
+ *
+ */
+static int
+dsgw_valid_context()
+{
+ char *local_context = NULL;
+
+ /*Get a local pointer to the global context*/
+ local_context = context;
+
+ if (local_context == NULL) {
+ return(1);
+ }
+
+ for ( ; *local_context; LDAP_UTF8INC(local_context)) {
+
+ if (!ldap_utf8isalnum(local_context)) {
+
+ /*Allow dashes and underscores*/
+ if (*local_context == '-' || *local_context == '_') {
+ continue;
+ }
+ return(0);
+ }
+ }
+ return(1);
+
+}
+
+/*
+ * Function: dsgw_valid_docname
+ *
+ * Returns: 1 if context doesn't have / . \ ,etc, 0 else
+ *
+ * Description: Checks to make sure that filename contains
+ * only alphanumeric values and one dot
+ *
+ * Author: RJP
+ *
+ */
+int
+dsgw_valid_docname(char *filename)
+{
+ int dots = 0;
+ char *local_filename = NULL;
+
+ local_filename = filename;
+
+ if (local_filename == NULL) {
+ return(1);
+ }
+
+ for ( ; *local_filename; LDAP_UTF8INC(local_filename)) {
+
+ /*If it's not a number or a letter...*/
+ if (!ldap_utf8isalnum(local_filename)) {
+
+ /*If it's a dot, and there haven't been any other dots...*/
+ if (*local_filename == '.' && dots == 0) {
+ /*Then increment the dot count and continue...*/
+ dots ++;
+ continue;
+ }
+
+ /*Allow dashes and underscores*/
+ if (*local_filename == '-' || *local_filename == '_') {
+ continue;
+ }
+
+ return (0);
+ }
+ }
+
+ return(1);
+}
+
+/*
+ * Function: dsgw_get_docdir
+ *
+ * Returns: a pointer to the html directory
+ *
+ * Description: Just returns gc->gc_docdir
+ *
+ * Author: RJP
+ *
+ */
+char *
+dsgw_get_docdir(void)
+{
+ return(gc->gc_docdir);
+}
+
+/*
+ * Function: browser_is_msie40
+ *
+ * Returns: 1 if HTTP_USER_AGENT is MSIE 4.0 or greater, 0 else
+ *
+ * Description: MSIE 4.0 doesn't return HTTP_ACCEPT_CHARSET,
+ * but it does understand utf-8, so we need to
+ * make a special case for it. If the browser
+ * being used is MSIE 4.0 or greater, this function
+ * returns 1.
+ *
+ * Author: RJP
+ *
+ */
+static int
+browser_is_msie40()
+{
+ char *p = NULL;
+ char *browzer = NULL;
+ char version[6];
+ int i;
+
+ /* Get the browser name */
+ if (( p = getenv( "HTTP_USER_AGENT" )) == NULL ) {
+ return(0);
+ }
+
+ /* Try to find MSIE in there */
+ browzer = strstr (p, "MSIE ");
+
+ /* If nothing, then we're done */
+ if (browzer == NULL) {
+ return (0);
+ }
+
+ /* Skip to the version */
+ browzer += 5;
+
+ /* Accumulate the version */
+ for (i=0; i < 5 && *browzer != '.' ; i++, browzer++) {
+ version[i] = *browzer;
+ }
+
+ /* Null terminate */
+ version[i] = '\0';
+
+ if (atoi(version) > 3) {
+ return(1);
+ }
+
+ return(0);
+
+}
+
+/*
+ * Function: browser_ignores_acceptcharset
+ *
+ * Returns: 1 if ignoreAcceptCharsetFrom contains the current HTTP_USER_AGENT,
+ * 0 else
+ *
+ * Description: bug fix for #97908:
+ * The dsgw doesn't respect the "charset" variable in the dsgw.conf file.
+ * E.g., ignoreAcceptCharsetFrom Mozilla/4.01x-NSCP Mozilla/4.03C-NSCP
+ *
+ */
+static int
+browser_ignores_acceptcharset()
+{
+ char *p = NULL;
+ char *browzer = NULL;
+ int i;
+
+ if ( gc->gc_clientIgnoreACharset == NULL ||
+ gc->gc_clientIgnoreACharset[0] == NULL )
+ return 0;
+
+ /* Get the browser name */
+ if (( p = getenv( "HTTP_USER_AGENT" )) == NULL ) {
+ return 0;
+ }
+ browzer = dsgw_ch_strdup_tolower( p );
+
+ for ( i = 0; gc->gc_clientIgnoreACharset[i]; i++ ) {
+ if ( strstr( browzer, gc->gc_clientIgnoreACharset[i] ) != NULL )
+ return 1;
+ }
+ free( browzer );
+ return 0;
+}
+
+static void
+set_dsgwcharset()
+{
+ auto char* fname = dsgw_file2path (gc->gc_configdir, "dsgwcharset.conf");
+ auto FILE* f = fopen (fname, "r");
+ if (f != NULL) {
+ auto char buf[BUFSIZ];
+ if (fgets (buf, sizeof(buf), f)) {
+ auto const size_t buflen = strlen (buf);
+ if (buf[buflen-1] == '\n') {
+ buf[buflen-1] = '\0';
+ }
+ gc->gc_charset = dsgw_ch_strdup (buf);
+ }
+ fclose (f);
+ }
+ free (fname);
+}
+
+static char *
+dsgw_ch_strdup_tolower( const char *s )
+{
+ int len, i;
+ char *p, *sp, *dp;
+
+ len = strlen( s ) + 1;
+ dp = p = dsgw_ch_malloc( len );
+ sp = (char *)s;
+ for (i = 0; i < len; i++, dp++, sp++)
+ *dp = tolower(*sp);
+ return( p );
+}
+
+static scriptrange_t**
+parse_scriptranges (char** cargv, size_t cargc)
+{
+ auto scriptrange_t** result = (scriptrange_t**)
+ dsgw_ch_calloc (cargc + 1, sizeof(scriptrange_t*));
+ auto size_t i;
+ for (i = 0; i < cargc; ++i) {
+ auto scriptrange_t** last = result+i;
+ auto char* token;
+ auto char* cursor = NULL;
+ for (token = ldap_utf8strtok_r (cargv[i], ",;", &cursor); token;
+ token = ldap_utf8strtok_r (NULL, ",;", &cursor)) {
+#ifdef DSGW_DEBUG
+ dsgw_log ("parse_scriptranges %s\n", token);
+#endif
+ *last = dsgw_ch_malloc (sizeof(scriptrange_t));
+ (*last)->sr_min = (*token == '-') ? 0 : strtoul (token, &token, 16);
+ (*last)->sr_max = (*token != '-') ? (*last)->sr_min
+ : ((*++token == '\0') ? ULONG_MAX : strtoul (token, &token, 16));
+ last = &((*last)->sr_next);
+ }
+ *last = NULL;
+ }
+ result[cargc] = NULL;
+ return result;
+}
+
+scriptorder_t*
+dsgw_scriptorder()
+{
+ static scriptorder_t* result = NULL;
+ if (result == NULL) {
+ auto char* simplename = "dsgwcollate.conf";
+ auto char* fname = dsgw_file2path (gc->gc_configdir, simplename);
+ auto FILE* fp;
+ result = (scriptorder_t*) dsgw_ch_calloc (1, sizeof(scriptorder_t));
+ if (NULL == fname) {
+#ifdef DSGW_DEBUG
+ dsgw_log ("dsgw_scriptorder can't find %s\n", simplename);
+#endif
+ } else if (NULL == (fp = fopen (fname, "r"))) {
+#ifdef DSGW_DEBUG
+ dsgw_log ("dsgw_scriptorder can't open %s\n", fname);
+#endif
+ } else {
+ auto char* line;
+ auto int lineno;
+ fp_getline_init( &lineno );
+ while ( (line = fp_getline( fp, &lineno )) != NULL ) {
+ auto int cargc;
+ auto char* cargv[ MAXARGS ];
+ /* skip comments and blank lines */
+ if ( line[0] == '#' || line[0] == '\0' ) {
+ continue;
+ }
+ fp_parse_line( line, &cargc, cargv );
+ if ( !strcasecmp (cargv[0], "caseIgnoreAccents")) {
+ result->so_caseIgnoreAccents = 1;
+ } else if ( !strcasecmp (cargv[0], "sort")) {
+ result->so_sort = parse_scriptranges (cargv+1, cargc-1);
+ } else if ( !strcasecmp (cargv[0], "display")) {
+ result->so_display = parse_scriptranges (cargv+1, cargc-1);
+ } else {
+#ifdef DSGW_DEBUG
+ dsgw_log ("%s/%i: unknown keyword %s\n", fname, lineno, cargv[0]);
+#endif
+ }
+ }
+ fclose (fp);
+#ifdef DSGW_DEBUG
+ dsgw_log ("dsgw_scriptorder %s line %i\n", fname, lineno);
+#endif
+ }
+ if (fname) free (fname);
+ }
+ return result;
+}
diff --git a/ldap/clients/dsgw/config/Makefile b/ldap/clients/dsgw/config/Makefile
new file mode 100644
index 00000000..1ff82d94
--- /dev/null
+++ b/ldap/clients/dsgw/config/Makefile
@@ -0,0 +1,77 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# Gmakefile for Directory Server Gateway config files.
+#
+
+LDAP_SRC = ../../..
+MCOM_ROOT = ../../../../..
+
+NOSTDSTRIP=true # don't let nsconfig.mak define target strip
+NOSTDCLEAN=true # don't let nsconfig.mak define target clean
+NOSTDDEPEND=true # don't let nsconfig.mak define target depend
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+include ../dsgw_include.mk
+
+HTMLDEST = $(DSGW_CONF_RELDIR)
+
+HTML = dsgw.tmpl dsgwfilter.conf dsgwsearchprefs.conf \
+ dsgw-l10n.conf \
+ search.html searchString.html \
+ csearch.html csearchAttr.html csearchBase.html csearchMatch.html csearchString.html csearchType.html \
+ newentry.html newentryType.html newentryName.html \
+ authSearch.html authPassword.html \
+ display-country.html display-group.html display-groupun.html \
+ display-org.html display-orgperson.html \
+ display-orgunit.html display-person.html \
+ display-ntperson.html display-dnedit.html display-dneditpeople.html \
+ display-ntgroup.html display-dc.html \
+ edit-passwd.html \
+ list-Anything.html list-fa-People.html list-fa-Groups.html \
+ list-Auth.html list-Groups.html list-Org-Units.html \
+ list-Organizations.html list-People.html list-urlsearch.html \
+ list-NT-People.html list-NT-Groups.html list-Domaincomponent.html
+
+BINS=$(addprefix $(HTMLDEST)/,$(HTML))
+
+LANGFILES=$(wildcard $(DSGW_DEFAULT_LANG)/dsgwcollate.*) $(wildcard $(DSGW_DEFAULT_LANG)/dsgw-l10n.*)
+
+LANGDEST=$(addprefix $(DSGW_CONF_RELDIR)/, $(LANGFILES))
+
+ifeq ($(ARCH), WINNT)
+CP2=cmd /c 'sh ../../../cm/nbsp2utf8.sh $< > $@'
+else
+CP2=sh ../../../cm/nbsp2utf8.sh $< > $@
+endif
+
+all: $(HTMLDEST) $(BINS) $(HTMLDEST)/$(DSGW_DEFAULT_LANG) $(LANGDEST)
+
+install: $(HTMLDEST) $(BINS)
+
+clean:
+ $(RM) $(BINS)
+
+$(HTMLDEST)/$(DSGW_DEFAULT_LANG)/%: $(DSGW_DEFAULT_LANG)/%
+ echo $(LANGDEST)
+ -@$(RM) $@
+ $(CP2)
+
+$(HTMLDEST)/%: %
+ echo $(LANGDEST)
+ -@$(RM) $@
+ $(CP2)
+
+$(HTMLDEST)/$(DSGW_DEFAULT_LANG)/dsgwcollate.conf: $(DSGW_DEFAULT_LANG)/dsgwcollate.conf
+ echo $(LANGDEST)
+ -@$(RM) $@
+ $(CP2)
+
+strip:
+depend:
diff --git a/ldap/clients/dsgw/config/authPassword.html b/ldap/clients/dsgw/config/authPassword.html
new file mode 100644
index 00000000..d9dfbae0
--- /dev/null
+++ b/ldap/clients/dsgw/config/authPassword.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authPassword.html-->
+<TITLE>Authenticate...</TITLE>
+<!-- DS_AUTH_PASSWORD_SCRIPT -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- DS_AUTH_PASSWORD_BODY -->
+<!-- DS_AUTH_PASSWORD_INFO -->
+<!-- DS_AUTH_PASSWORD_FORM -->
+<P>
+Password for <b>
+<!-- DS_AUTH_PASSWORD_NAME -->
+</b>: <INPUT NAME="password" TYPE="password" SIZE=16>
+<P>
+<CENTER>
+<TABLE BORDER=2 WIDTH=100%>
+<TR>
+<!-- DS_AUTH_PASSWORD_BUTTONS -->
+</TABLE>
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/authSearch.html b/ldap/clients/dsgw/config/authSearch.html
new file mode 100644
index 00000000..b4103391
--- /dev/null
+++ b/ldap/clients/dsgw/config/authSearch.html
@@ -0,0 +1,35 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authSearch.html-->
+<TITLE>Authenticate...</TITLE>
+<!-- DS_AUTH_SEARCH_SCRIPT -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<!-- DS_AUTH_SEARCH_BODY -->
+<!-- DS_AUTH_SEARCH_INFO -->
+<!-- DS_AUTH_SEARCH_FORM -->
+The first step in authenticating to the directory is identifying
+yourself.<br>Please type your name:
+<!-- DS_AUTH_SEARCH_NAME -->
+<P>
+<CENTER>
+<TABLE BORDER=1 WIDTH=100%%>
+<TR>
+<!-- DS_AUTH_SEARCH_BUTTONS -->
+</TABLE>
+</FORM>
+<P>
+<!-- DS_AUTH_AS_ROOT_FORM -->
+<INPUT TYPE="submit" VALUE="Authenticate as directory manager">&nbsp;(only available to Directory Administrators)
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/csearch.html b/ldap/clients/dsgw/config/csearch.html
new file mode 100644
index 00000000..32445b74
--- /dev/null
+++ b/ldap/clients/dsgw/config/csearch.html
@@ -0,0 +1,28 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearch.html-->
+<TITLE>Netscape Directory Server Gateway: Advanced Search</TITLE>
+<!-- DS_CSEARCH_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=130,40,55,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=csearchtitle.html" SCROLLING="NO" NORESIZE>
+ <FRAMESET COLS="25%,75%" BORDER=0>
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=type" NAME="searchTypeFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=base" NAME="searchBaseFrame" NORESIZE SCROLLING="NO">
+ </FRAMESET>
+ <FRAMESET COLS="25%, 15%, 60%" BORDER=0>
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=attr" NAME="searchAttrFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=match" NAME="searchMatchFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=string" NAME="searchStringFrame" SCROLLING="NO">
+ </FRAMESET>
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=emptyFrame.html" NAME="outputFrame">
+</FRAMESET>
+</HTML>
+
+
diff --git a/ldap/clients/dsgw/config/csearchAttr.html b/ldap/clients/dsgw/config/csearchAttr.html
new file mode 100644
index 00000000..acf34ea8
--- /dev/null
+++ b/ldap/clients/dsgw/config/csearchAttr.html
@@ -0,0 +1,23 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchAttr.html-->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<!-- DS_CSEARCH_ATTR_BODY -->
+<!-- DS_CSEARCH_ATTR_FORM -->
+
+<TABLE> <TR VALIGN=BASELINE>
+<TD WIDTH="100" ALIGN="right">
+where the
+</TD>
+<TD>
+<!-- DS_CSEARCH_ATTR_SELECT -->
+</TD>
+</TR> </TABLE>
+</FORM></BODY> </HTML>
diff --git a/ldap/clients/dsgw/config/csearchBase.html b/ldap/clients/dsgw/config/csearchBase.html
new file mode 100644
index 00000000..7dd9c9be
--- /dev/null
+++ b/ldap/clients/dsgw/config/csearchBase.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchBase.html-->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<!-- DS_CSEARCH_BASE_BODY -->
+<TABLE> <TR VALIGN="middle">
+
+<TD HEIGHT="28">
+within <B>
+<!-- EVALUATE "parent.UFNsearchBase" -->
+</B> </TD>
+
+</TR> </TABLE>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/csearchMatch.html b/ldap/clients/dsgw/config/csearchMatch.html
new file mode 100644
index 00000000..1a5aefb3
--- /dev/null
+++ b/ldap/clients/dsgw/config/csearchMatch.html
@@ -0,0 +1,21 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchMatch.html-->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<!-- DS_CSEARCH_MATCH_BODY -->
+<!-- DS_CSEARCH_MATCH_FORM -->
+<TABLE> <TR VALIGN=BASELINE>
+<TD>
+<!-- DS_CSEARCH_MATCH_SELECT -->
+</TD>
+</TR> </TABLE>
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/csearchString.html b/ldap/clients/dsgw/config/csearchString.html
new file mode 100644
index 00000000..ab2d9b9b
--- /dev/null
+++ b/ldap/clients/dsgw/config/csearchString.html
@@ -0,0 +1,26 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchString.html-->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<!-- DS_CSEARCH_STRING_BODY -->
+<!-- DS_CSEARCH_STRING_FORM "target=outputFrame" -->
+<TABLE> <TR>
+<TD ALIGN="left"> <INPUT NAME="searchstring" SIZE=20> </TD>
+<TD>
+<NOBR>
+<INPUT TYPE="SUBMIT" VALUE="Search" WIDTH=72>
+<!-- DS_HELP_BUTTON "ASEARCH" -->
+</NOBR> </TD>
+</TR></TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/config/csearchType.html b/ldap/clients/dsgw/config/csearchType.html
new file mode 100644
index 00000000..ae9f7d1d
--- /dev/null
+++ b/ldap/clients/dsgw/config/csearchType.html
@@ -0,0 +1,24 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchType.html-->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<!-- DS_CSEARCH_TYPE_BODY -->
+<!-- DS_CSEARCH_TYPE_FORM -->
+<TABLE> <TR>
+<TD ALIGN="right" WIDTH="100" HEIGHT="28" VALIGN="middle">
+Find
+</TD>
+<TD HEIGHT="28" VALIGN="middle">
+<!-- DS_CSEARCH_TYPE_SELECT -->
+</TD>
+</TR> </TABLE>
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/de/authPassword.html b/ldap/clients/dsgw/config/de/authPassword.html
new file mode 100644
index 00000000..4be4573f
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/authPassword.html
@@ -0,0 +1,29 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authPassword.html-->
+<TITLE>Beglaubigen...</TITLE>
+<!-- DS_AUTH_PASSWORD_SCRIPT -->
+</HEAD>
+
+<!-- DS_AUTH_PASSWORD_BODY -->
+<!-- DS_AUTH_PASSWORD_INFO -->
+<!-- DS_AUTH_PASSWORD_FORM -->
+<P>
+Kennwort f&uuml;r<b>
+<!-- DS_AUTH_PASSWORD_NAME -->
+</b>: <INPUT NAME="password" TYPE="password" SIZE=16>
+<P>
+<CENTER>
+<TABLE BORDER=2 WIDTH=100%>
+<TR>
+<!-- DS_AUTH_PASSWORD_BUTTONS -->
+</TABLE>
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/de/authSearch.html b/ldap/clients/dsgw/config/de/authSearch.html
new file mode 100644
index 00000000..fe2c79f1
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/authSearch.html
@@ -0,0 +1,33 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authSearch.html-->
+<TITLE>Beglaubigen...</TITLE>
+<!-- DS_AUTH_SEARCH_SCRIPT -->
+</HEAD>
+<!-- DS_AUTH_SEARCH_BODY -->
+<!-- DS_AUTH_SEARCH_INFO -->
+<!-- DS_AUTH_SEARCH_FORM -->
+Um Ihren Zugriff zu dem Verzeichnis zu beglaubigen, m&uuml;ssen Sie sich zun&auml;chst zu erkennen geben.<br>Geben Sie Ihren Namen ein:
+<!-- DS_AUTH_SEARCH_NAME -->
+<P>
+<CENTER>
+<TABLE BORDER=1 WIDTH=100%%>
+<TR>
+<!-- DS_AUTH_SEARCH_BUTTONS -->
+</TABLE>
+</FORM>
+<P>
+<!-- DS_AUTH_AS_ROOT_FORM -->
+<INPUT TYPE="submit" VALUE="Als Verzeichnis-Manager beglaubigen">&nbsp;(nur f&uuml;r Verzeichnis-Administratoren verf&uuml;gbar)
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/de/csearchAttr.html b/ldap/clients/dsgw/config/de/csearchAttr.html
new file mode 100644
index 00000000..8f4831bc
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/csearchAttr.html
@@ -0,0 +1,17 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchAttr.html-->
+</HEAD>
+<!-- DS_CSEARCH_ATTR_BODY -->
+<!-- DS_CSEARCH_ATTR_FORM -->
+<table>
+<tr VALIGN=BASELINE><td ALIGN=RIGHT>wobei:</td><td>
+<!-- DS_CSEARCH_ATTR_SELECT -->
+</td></tr>
+</table></form></body></HTML>
diff --git a/ldap/clients/dsgw/config/de/csearchBase.html b/ldap/clients/dsgw/config/de/csearchBase.html
new file mode 100644
index 00000000..fc1a27fc
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/csearchBase.html
@@ -0,0 +1,17 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchBase.html-->
+</HEAD>
+<!-- DS_CSEARCH_BASE_BODY -->
+<table>
+<tr VALIGN=CENTER><th>innerhalb von:</th><td>
+<!-- EVALUATE "parent.UFNsearchBase" -->
+</td>
+</table>
+</body></HTML>
diff --git a/ldap/clients/dsgw/config/de/csearchString.html b/ldap/clients/dsgw/config/de/csearchString.html
new file mode 100644
index 00000000..e7369ad5
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/csearchString.html
@@ -0,0 +1,28 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchString.html-->
+</HEAD>
+<!-- DS_CSEARCH_STRING_BODY -->
+<!-- DS_CSEARCH_STRING_FORM "target=outputFrame" -->
+<TABLE>
+<TR VALIGN=CENTER><TD>
+<INPUT NAME="searchstring" SIZE=20></TD>
+<TD><NOBR>
+<INPUT TYPE="SUBMIT" VALUE="Suchen">
+<!-- DS_HELP_BUTTON "ASEARCH" -->
+</NOBR></TD>
+<td>&nbsp;</td><th>innerhalb von:</th><td>
+<!-- EVALUATE "parent.UFNsearchBase" -->
+</td>
+</TR></TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/config/de/csearchType.html b/ldap/clients/dsgw/config/de/csearchType.html
new file mode 100644
index 00000000..1250749d
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/csearchType.html
@@ -0,0 +1,18 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchType.html-->
+</HEAD>
+<!-- DS_CSEARCH_TYPE_BODY -->
+<!-- DS_CSEARCH_TYPE_FORM -->
+<table>
+<tr VALIGN=BASELINE><th ALIGN=RIGHT>Suchen:</th><td>
+<!-- DS_CSEARCH_TYPE_SELECT -->
+</td></tr>
+</table>
+</form></body></HTML>
diff --git a/ldap/clients/dsgw/config/de/display-country.html b/ldap/clients/dsgw/config/de/display-country.html
new file mode 100644
index 00000000..4157ff97
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-country.html
@@ -0,0 +1,54 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=country" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Land -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<TABLE>
+<TR><TD NOWRAP>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=country.gif" ALT="Land" HSPACE=5>
+</TD><TD><FONT SIZE="+2">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE CELLSPACING="5">
+
+<TR><TD VALIGN="TOP" NOWRAP>Landesname:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=co" "options=sort" -->
+</B></TD><TD WIDTH="20%"></TD>
+</B><TD VALIGN="TOP">Beschreibung:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP">Siehe auch:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" -->
+</B></TD></TR>
+
+</TABLE>
+
+<HR>
+
+Eintrag zuletzt ge&auml;ndert am <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-dnedit.html b/ldap/clients/dsgw/config/de/display-dnedit.html
new file mode 100644
index 00000000..950077dd
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-dnedit.html
@@ -0,0 +1,76 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Bearbeiten
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY "onLoad='document.searchForm.searchstring.focus();'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<!-- PCONTEXT -->
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+
+<FONT SIZE="+2">
+Bearbeiten
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<TABLE CELLSPACING=0 CELLPADDING=0><TR>
+
+<TD NOWRAP>
+Suchen von
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">Personen
+<OPTION VALUE="Groups">Gruppen
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+passend zu&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<!-- DS_DNADDBUTTON "VALUE= Suchen und Hinzuf&uuml;gen " -->
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= Suchen und Entfernen " -->
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" &Auml;nderungen speichern " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Abbrechen " onClick="if ((parent.changesMade) == 0 || confirm('&Auml;nderungen verwerfen?')) {parent.document.location.href=parent.completion_url}";>
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON "topic=EDIT_GROUPMEM" -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-dneditpeople.html b/ldap/clients/dsgw/config/de/display-dneditpeople.html
new file mode 100644
index 00000000..1e4e8c32
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-dneditpeople.html
@@ -0,0 +1,75 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Bearbeiten
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY "onLoad='document.searchForm.searchstring.focus();'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<!-- PCONTEXT -->
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+
+<FONT SIZE="+2">
+Bearbeiten
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<TABLE CELLSPACING=0 CELLPADDING=0><TR>
+
+<TD NOWRAP>
+Suchen von
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">Personen
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+passend zu&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<!-- DS_DNADDBUTTON "VALUE= Suchen und Hinzuf&uuml;gen ">
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= Suchen und L&ouml;schen ">
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" &Auml;nderungen speichern " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Abbrechen " onClick="if ((parent.changesMade) == 0 || confirm('&Auml;nderungen verwerfen?')) {parent.document.location.href=parent.completion_url}";>
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-group.html b/ldap/clients/dsgw/config/de/display-group.html
new file mode 100644
index 00000000..12b4d1cc
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-group.html
@@ -0,0 +1,150 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neuer
+<!-- ENDIF // Adding -->
+Gruppeneintrag -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Gruppe" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neue Gruppe -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Gruppe bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neue Gruppe speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Gruppe umbenennen" "prompt=Neuen Namen f&uuml;r diese Gruppe eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Gruppe l&ouml;schen" "prompt=Diese Gruppe l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfNames">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* bezeichnet einen Pflichteintrag</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>Beschreibung:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Eigent&uuml;mer:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=owner" "desc=Eigent&uuml;mer" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Siehe auch:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=seeAlso" "desc=Siehe auch" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>Sie m&uuml;ssen diesen Eintrag speichern, bevor Sie diese Felder bearbeiten k&ouml;nnen.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">Gruppenmitglieder:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=uniquemember" "desc=Gruppenmitglieder" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Eintrag zuletzt ge&auml;ndert am
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-groupun.html b/ldap/clients/dsgw/config/de/display-groupun.html
new file mode 100644
index 00000000..cac6c909
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-groupun.html
@@ -0,0 +1,150 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfUniqueNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neuer
+<!-- ENDIF // Adding -->
+Gruppeneintrag -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Gruppe" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neue Gruppe -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Gruppe bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neue Gruppe speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Gruppe umbenennen" "prompt=Neuen Namen f&uuml;r diese Gruppe eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Gruppe l&ouml;schen" "prompt=Diese Gruppe l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* bezeichnet einen Pflichteintrag</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>Beschreibung:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Eigent&uuml;mer:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=owner" "desc=Eigent&uuml;mer" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Siehe auch:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=seeAlso" "desc=Siehe auch" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>Sie m&uuml;ssen diesen Eintrag speichern, bevor Sie diese Felder bearbeiten k&ouml;nnen.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">Gruppenmitglieder:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=uniquemember" "desc=Gruppenmitglieder" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Eintrag zuletzt ge&auml;ndert am <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-mailgroup.html b/ldap/clients/dsgw/config/de/display-mailgroup.html
new file mode 100644
index 00000000..086f7309
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-mailgroup.html
@@ -0,0 +1,124 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=rfc822mailgroup" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neuer
+<!-- ENDIF // Adding -->
+E-Mail-Gruppeneintrag -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Gruppe" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neue E-Mail-Gruppe
+<!-- ENDIF // Adding -->
+
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Gruppe bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neue Gruppe speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_MAILGROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_MAILGROUP" -->
+<!-- ENDIF // Adding -->
+
+<!-- IF "Editing" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Gruppe umbenennen" "prompt=Neuen Namen f&uuml;r diese Gruppe eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Gruppe lȵschen" "prompt=Diese Gruppe l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="rfc822mailgroup">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+
+<HR>
+
+<TABLE CELLSPACING="5">
+
+<TR><TD VALIGN="TOP">Name:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="TOP">Beschreibung:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=multilineDescription" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP">Eigent&uuml;mer:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP" NOWRAP>Siehe auch:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD NOWRAP COLSPAN="2">
+<!-- DS_ATTRIBUTE "attr=joinable" "syntax=bool" "type=radio" "true=Allow Others To Join" "false=Andere Personen nicht als Mitglieder zulassen" "defaultvalue=FALSE" -->
+</TD><TD></TD><TD NOWRAP COLSPAN="2">
+<!-- DS_ATTRIBUTE "attr=suppressNoEmailError" "syntax=bool" "type=radio" "true=Fehler 'Keine E-Mail-Adresse' unterdr&uuml;cken" "false=Fehler 'Keine E-Mail-Adresse' melden" "defaultvalue=FALSE" -->
+</TD></TR>
+
+<HR>
+
+<TR><TD VALIGN="TOP" NOWRAP>Gruppenmitglieder:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=member" "syntax=dn" "numfields=+4" "options=sort" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP" NOWRAP>E-Mail-Mitglieder:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "numfields=+4" "cols=>30" "options=sort" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Eintrag zuletzt ge&auml;ndert am <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedTime" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedBy" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-ntgroup.html b/ldap/clients/dsgw/config/de/display-ntgroup.html
new file mode 100644
index 00000000..010b0b9c
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-ntgroup.html
@@ -0,0 +1,216 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=ntGroup" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neuer
+<!-- ENDIF // Adding -->
+NT-Gruppeneintrag -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Gruppe" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neue NT-Gruppe -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=NT-Gruppe bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neue Gruppe speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTGROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTGROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=NT-Gruppe umbenennen" "prompt=Neuen Namen f&uuml;r diese Gruppe eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=NT-Gruppe l&ouml;schen" "prompt=Diese Gruppe l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="ntGroup">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* bezeichnet einen Pflichteintrag</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>NT-Gruppenname:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" "options=readonly" "defaultvalue=none" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" "defaultvalue=none" -->
+<!-- ENDIF // Adding -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>NT-Gruppentyp:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "options=readonly" "cols=>16" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>NT-Gruppendom&auml;ne
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntdomain" "cols=>16" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Beschreibung:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Lokal:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Gesch&auml;ftsbereich:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Eigent&uuml;mer:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=owner" "desc=Eigent&uuml;mer" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Siehe auch:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=seeAlso" "desc=Siehe auch" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>Sie m&uuml;ssen diesen Eintrag speichern, bevor Sie diese Felder bearbeiten k&ouml;nnen.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">NT-Gruppenmitglieder:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=uniquemember" "desc=NT-Gruppenmitglieder" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>NT-Gruppe l&ouml;schen, wenn Gruppe gel&ouml;scht wird:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Ja" "false=Nein" "defaultvalue=FALSE" "attr=nTGroupDeleteGroup" -->
+</B></TD><TD></TD>
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP">Neues NT-Gruppenkonto erstellen:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Ja" "false=Nein" "defaultvalue=TRUE" "attr=nTGroupCreateNewGroup" -->
+</B></TD><TD></TD></TR>
+
+<!-- ENDIF // Adding -->
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Eintrag zuletzt ge&auml;ndert am <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-ntperson.html b/ldap/clients/dsgw/config/de/display-ntperson.html
new file mode 100644
index 00000000..f7876979
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-ntperson.html
@@ -0,0 +1,505 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- NT User person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson,nTUser" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neuer
+<!-- ENDIF // Adding -->
+NT-Benutzereintrag -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Benutzer (Anklicken, um Karte anzuzeigen)"
+ BORDER=0 HSPACE=5>
+
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neuer NT-Benutzer -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-ca-cert" -->
+>Download Certificate</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Play Audio Clip</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="Karte anzeigen" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=NT-Benutzer bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neuen NT-Benutzer speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Verzeichniskennwort &auml;ndern" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Person umbenennen" "prompt=Neuen Namen f&uuml;r diese Person eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Person l&ouml;schen" "prompt=Diese Person l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nTUser">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<B>* bezeichnet einen Pflichteintrag</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Kontaktinformationen</TD>
+</TR>
+
+<TD VALIGN="top" NOWRAP>Vorname:</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</B></TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2">Vollst&auml;ndiger Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2"><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>Nachname:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Directory-Server-Kennwort:</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</B></TD>
+<TD> Kennwort zur Best&auml;tigung wiederholen:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">Telefon:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>E-Mail-Adresse:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Fax:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Benutzer-ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+<TR>
+<TD VALIGN="TOP" NOWRAP>Pager:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Mobiltelefon:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+</TABLE>
+
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Windows NT Kontoinformationen</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">NT-Benutzer-ID:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" "options=readonly" -->
+<!-- ENDIF // Adding -->
+<!-- IF "Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NT-Dom&auml;ne:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntdomain" "cols=>16" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP>NT-Benutzerkonto l&ouml;schen, wenn Benutzer gel&ouml;scht wird:</TD>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Ja" "false=Nein" "defaultvalue=FALSE" "attr=nTUserDeleteAccount" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP" COLSPAN=2>Neues NT-Benutzerkonto erstellen:</TD>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Ja" "false=Nein" "defaultvalue=TRUE" "attr=nTUserCreateNewAccount" -->
+</B></TD></TR>
+
+<!-- ENDIF // Adding -->
+
+<!-- IF "Displaying" -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>NT-Benutzer-Kommentar:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUsrComment" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Eindeutige NT-Benutzer-ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUniqueId" "syntax=binvalue" "cols=>10" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>NT-Kennwort abgelaufen:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Ja" "false=Nein" "defaultvalue=FALSE" "attr=nTUserPasswordExpired" -->
+</B></TD>
+<TD VALIGN="TOP">Anzahl falscher NT-Kennworteingaben:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserBadPwCount" "syntax=binvalue" "options=decimal" "cols=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Letzte NT-Anmeldung:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogon" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Letzte NT-Abmeldung:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogoff" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Verfalldatum NT-Benutzerkonto:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserAcctExpires" "syntax=time" "defaultvalue=Never Expires" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Anzahl NT-Anmeldungen:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserNumLogons" "syntax=binvalue" "options=decimal" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NT-Anmelde-Server:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLogonServer" "defaultvalue=Any Server" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NT-Arbeitsstationen:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserWorkstations" "defaultvalue=No Restrictions" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NT-Codeseite:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserCodePage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NT-Landescode:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserCountryCode" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Prim&auml;re NT-Gruppen-ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserPrimaryGroupId" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NT-Profil:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserProfile" "defaultvalue=Default" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>NT-Basisverzeichnis:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDir" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP">Laufwerk des NT-Basisverzeichnisses:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDirDrive" "defaultvalue=None" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>NT-Skriptpfad:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserScriptPath" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Maximaler NT-Speicherplatz:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserMaxStorage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NT-Einheiten pro Woche:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUnitsPerWeek" "syntax=binvalue" "options=decimal" "cols=>6" -->
+</B></TD>
+<TD VALIGN="TOP">Rechte des NT-Benutzers:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserPriv" "syntax=binvalue" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Operator-Rechte des NT-Benutzers:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserAuthFlags" "syntax=binvalue" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP">Div. betr. NT-Benutzerkonto: Funktionen:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserFlags" "syntax=binvalue" "cols=>16" -->
+</B></TD></TR>
+
+<!-- ENDIF // Displaying -->
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Branchen- und Positionsinformationen</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Branche:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</B></TD>
+<TD VALIGN="TOP">Titel:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Gesch&auml;ftsbereich:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</B></TD>
+<TD VALIGN="TOP">Leiter:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dneditpeople" "attr=manager" "desc=Manager" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>Sie m&uuml;ssen diesen Eintrag speichern, bevor Sie diese Felder bearbeiten k&ouml;nnen.</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Raum:</TD>
+<TD VALIGN="TOP" NOWRAP"><B>
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</B></TD>
+</B><TD VALIGN="TOP">Sekr.:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dneditpeople" "attr=secretary" "desc=Admin." -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</B></TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Abt.-Nr.:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP">MA-Nr.:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Kfz-Kennzeichen:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</B></TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Postadresse:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=2><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Zus&auml;tzliche Informationen</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Beschreibung:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Siehe auch:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>Sie m&uuml;ssen diesen Eintrag speichern, bevor Sie diese Felder bearbeiten k&ouml;nnen.</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</B></TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP">Unique ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</B></TR>
+-->
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+Eintrag zuletzt ge&auml;ndert am <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-org.html b/ldap/clients/dsgw/config/de/display-org.html
new file mode 100644
index 00000000..82586bc5
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-org.html
@@ -0,0 +1,136 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organization" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neue
+<!-- ENDIF // Adding -->
+Firma -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=organization.gif" ALT="Firma" HSPACE=5>
+<TD>
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neue Firma -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Firma bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neue Firma speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORG" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORG" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Firma umbenennen" "prompt=Neuen Namen f&uuml;r diese Firma eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Firma l&ouml;schen" "prompt=Diese Firma l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organization">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* bezeichnet einen Pflichteintrag</B><BR>
+<!-- ENDIF -->
+
+<TABLE>
+<TR>
+<TD VALIGN="TOP" NOWRAP>Firmenname:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=o" "cols=>20" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD>Beschreibung:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</B></TR>
+
+<TR><TD>Telefon:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD NOWRAP>Branche:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</B></TD></TR>
+
+<TR><TD>Fax:<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD>Standort:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Postadresse:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Siehe auch:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Eintrag zuletzt ge&auml;ndert am <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-orgperson.html b/ldap/clients/dsgw/config/de/display-orgperson.html
new file mode 100644
index 00000000..e6ce0f0f
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-orgperson.html
@@ -0,0 +1,345 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- inet. organizational person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neuer
+<!-- ENDIF // Adding -->
+Personeneintrag -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<!-- A HREF="javascript:showVCard()" -->
+<A HREF="javascript:showVCard()">
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Benutzer (Anklicken, um Karte anzuzeigen)"
+ BORDER=0 HSPACE=5>
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neue Person -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-ca-cert" -->
+>Zertifikat laden</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Audio-Clip abspielen</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="Karte anzeigen" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Person bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neue Person speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Kennwort &auml;ndern" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Person umbenennen" "prompt=Neuen Namen f&uuml;r diese Person eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Person l&ouml;schen" "prompt=Diese Person l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<B>* bezeichnet einen Pflichteintrag</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Kontaktinformationen</TD>
+</TR>
+
+<TD VALIGN="top" NOWRAP>Vorname:</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</B></TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2">Vollst&auml;ndiger Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2"><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>Nachname:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Kennwort:</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</B></TD>
+<TD> Kennwort zur Best&auml;tigung wiederholen:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">Telefon:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>E-Mail-Adresse:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Fax:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Benutzer-ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Pager:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Mobiltelefon:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Branchen- und Positionsinformationen</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Branche:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</B></TD>
+<TD VALIGN="TOP">Titel:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Gesch&auml;ftsbereich:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</B></TD>
+<TD VALIGN="TOP">Leiter:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dneditpeople" "attr=manager" "desc=Leiter" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>Sie m&uuml;ssen diesen Eintrag speichern, bevor Sie diese Felder bearbeiten k&ouml;nnen.</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Raum:</TD>
+<TD VALIGN="TOP" NOWRAP"><B>
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</B></TD>
+</B><TD VALIGN="TOP">Sekr.:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dneditpeople" "attr=secretary" "desc=Sekr." -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</B></TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Abt.-Nr.:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP">MA-Nr.:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Kfz-Kennzeichen:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</B></TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Postadresse:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=2><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Zus&auml;tzliche Informationen</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Beschreibung:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Siehe auch:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=seeAlso" "desc=Siehe auch" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>Sie m&uuml;ssen diesen Eintrag speichern, bevor Sie dieses Feld bearbeiten k&ouml;nnen.</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</B></TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP">Unique ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</B></TR>
+-->
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+Eintrag zuletzt ge&auml;ndert am
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-orgunit.html b/ldap/clients/dsgw/config/de/display-orgunit.html
new file mode 100644
index 00000000..1d1ff1b8
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-orgunit.html
@@ -0,0 +1,136 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organizationalUnit" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neuer
+<!-- ENDIF // Adding -->
+GeschÈñftsbereich -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgunit.gif" ALT="Gesch&auml;ftsbereich " HSPACE=5>
+<TD>
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neuer Gesch&auml;ftsbereich -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Gesch&auml;ftsbereich bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neuen Gesch&auml;ftsbereich speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGUNIT" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGUNIT" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Gesch&auml;ftsbereich umbenennen" "prompt=Neuen Namen f&uuml;r den Gesch&auml;ftsbereich eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Gesch&auml;ftsbereich l&ouml;schen" "prompt=Gesch&auml;ftsbereich l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalUnit">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* bezeichnet einen Pflichteintrag</B><BR>
+<!-- ENDIF -->
+
+
+<BR>
+<TABLE>
+<TR>
+<TD>Name des Gesch&auml;ftsbereichs:<B>*</B>
+<!-- IF "!Displaying" -->
+<!-- ENDIF -->
+</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>20" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD>Beschreibung:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</B></TR>
+
+<TR><TD>Telefon:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD NOWRAP>Branche:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</B></TD></TR>
+
+<TR><TD>Fax:<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD>Standort:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Postadresse:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Siehe auch:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Eintrag zuletzt ge&auml;ndert am <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-person.html b/ldap/clients/dsgw/config/de/display-person.html
new file mode 100644
index 00000000..f5d97854
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-person.html
@@ -0,0 +1,231 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- person directory entry -->
+<!-- DS_OBJECTCLASS "value=person" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neuer
+<!-- ENDIF // Adding -->
+Personeneintrag -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Benutzer (Anklicken, um Karte anzuzeigen)"
+ BORDER=0 HSPACE=5>
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neue Person -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="Karte anzeigen" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Person bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neue Person speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_PERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_PERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Kennwort &auml;ndern" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Person umbenennen" "prompt=Neuen Namen f&uuml;r diese Person eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Person l&ouml;schen" "prompt=Diese Person l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* bezeichnet einen Pflichteintrag</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD VALIGN="top" NOWRAP>Nachname:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="top" NOWRAP>Vollst&auml;ndiger Name:</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR><TD COLSPAN="5"><HR></TD></TR>
+<TR>
+<TD>Kennwort:</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD><TD WIDTH="20%"></TD>
+<TD> Kennwort zur Best&auml;tigung wiederholen:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+<TR><TD COLSPAN="5"><HR></TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">Telefon:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>E-Mail-Adresse:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Fax:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Benutzer-ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Pager:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Mobiltelefon:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Titel:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Postadresse:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Beschreibung:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Siehe auch:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=seeAlso" "desc=Siehe auch" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4">
+<!-- IF "Adding" -->
+<I>Sie m&uuml;ssen diesen Eintrag speichern, bevor Sie diese Felder bearbeiten k&ouml;nnen.</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Lieblingsgetr&auml;nk:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=drink" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Eintrag zuletzt ge&auml;ndert am
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/display-umperson.html b/ldap/clients/dsgw/config/de/display-umperson.html
new file mode 100644
index 00000000..78cdb202
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/display-umperson.html
@@ -0,0 +1,200 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- U-M person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,umichPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Neuer
+<!-- ENDIF // Adding -->
+Personeneintrag -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+></TD>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Person" HSPACE=5>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Neue Person -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Audio-Clip abspielen</A>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Person bearbeiten" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Neue Person speichern" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Abbrechen" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_UMPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_UMPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Kennwort Èñndern" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Person umbenennen" "prompt=Neuen Namen f&uuml;r diese Person eingeben:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Bereichsleiter l&ouml;schen" "prompt=Diese Person l&ouml;schen?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="umichPerson">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* bezeichnet einen Pflichteintrag</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD VALIGN="top" NOWRAP>Nachname:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="top" NOWRAP>Vollst&auml;ndiger Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Telefon:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>E-Mail-Adresse:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Fax:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Eindeutiger Name:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Pager:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Mobiltelefon:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Titel:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Postadresse:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Beschreibung:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=multilineDescription" "syntax=mls" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Siehe auch:<BR>
+<!-- DS_DNEDITBUTTON "label=Bearbeiten..." "template=dnedit" "attr=seeAlso" "desc=Siehe auch" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURL" "syntax=url" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Lieblingsgetr&auml;nk:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=drink" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Eintrag zuletzt ge&auml;ndert am <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedTime" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> von <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedBy" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/dsgw-l10n.conf b/ldap/clients/dsgw/config/de/dsgw-l10n.conf
new file mode 100644
index 00000000..0482312b
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/dsgw-l10n.conf
@@ -0,0 +1,18 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# Note: the sample part should have double #'s for L10n.
+## translate People <People_translated_in_lang>
+## translate NT-People <NT-People_translated_in_lang>
+## translate Groups <Groups_translated_in_lang>
+## translate NT-Groups <NT-Groups_translated_in_lang>
+## translate Organizations <Organizations_translated_in_lang>
+## translate Org-Units <Org-Units_translated_in_lang>
+## translate Anything <Anything_translated_in_lang>
diff --git a/ldap/clients/dsgw/config/de/dsgw.conf b/ldap/clients/dsgw/config/de/dsgw.conf
new file mode 100644
index 00000000..64c202d1
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/dsgw.conf
@@ -0,0 +1,133 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# The baseurl directive gives the server, port, and base dn where searches
+# should be rooted. The format is:
+#
+# ldap://host.domain[:port]/basedn
+# - or -
+# ldaps://host.domain:port/basedn (for SSL)
+#
+# Where:
+# - "host.domain" is the fully-qualified domain name of the directory server
+# - "port" is the port used by the directory server. If you are using an
+# "ldaps" URL (that is, if the gateway is using SSL to communicate with the
+# directory server), then the port number is required. Otherwise, it is
+# optional and defaults to the standard LDAP port (389).
+# - "basedn" is the distinguished name of the place in the directory tree
+# where searches should start. Typically, this is the same as the
+# "suffix" directive in your slapd.conf file.
+#
+# examples:
+# baseurl "ldap://mars.aceindustry.com/o=Ace Industry, c=US"
+# - causes the gateway to use the directory server running on host
+# "mars.aceindustry.com". Since no port was given, the default LDAP
+# port (389) is used. Searches in the gateway search for entries
+# contained within o=Ace Industry, c=US.
+#
+# baseurl "ldaps://mars.aceindustry.com:636/o=Ace Industry, c=US"
+# - same as above, but uses SSL to connect to the directory server,
+# and contacts the server on port 636.
+
+baseurl "ldap://ggood.mcom.com:389/o=Netscape Communications Corp., c=US"
+#baseurl "ldap://belltower.mcom.com:9000/o=Ace%20Industry,%20c=US"
+#baseurl "ldap://belltower:9000/o=Netscape Communications Corp., c=US"
+#baseurl "ldap://ldap.itd.umich.edu:389/o=University of Michigan, c=US"
+
+# The dirmgr directive specifies the "Manager" DN for your directory.
+dirmgr "cn=Directory Manager, o=Netscape Communications Corp., c=US"
+
+# The securitypath directive gives the full path name to your
+# security databases.
+#securitypath /tmp/ssl
+
+# If the requireauth directive is present, users must authenticate to the
+# directory before they may perform any operations. XXX: not implemented
+# in 1.0b2.
+#requireauth
+
+# The authlifetime directive specifies how long authentication credentials
+# are valid (in seconds).
+authlifetime 7200
+
+# The default character set, for communication with HTTP clients.
+# A client may override this default, using an HTTP Accept-Charset header.
+# Or, this default may be overridden for a specific language, by creating
+# a LANG/dsgwcharset.conf file which contains the charset name.
+# For compatibility with HTTP clients that can't handle an HTTP response
+# with a charset parameter in the content-type, comment out this directive;
+# responses will be sent in ISO-8859-1, with no explicit charset parameter.
+# RFC 1345 defines the syntax of charset names. There is a registry of
+# charsets, at ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+# charset UTF-8
+
+# The NLS (internationalization) directory. The directory of this name
+# should contain a locales directory, which contains configuration files.
+NLS ../../../lib/nls
+
+location-suffix "o=Netscape Communications Corp., c=US"
+
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using ds/templateindex. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "umperson" and
+# "orgperson" templates are listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template groupun groupOfUniqueNames
+template mailgroup rfc822mailgroup
+template org organization
+template orgunit organizationalUnit
+template ntperson person inetOrgPerson nTUser
+template umperson person umichPerson
+template orgperson person inetOrgPerson
+template person person
+template country country
+
+#
+# The remainder of this file contains information about the locations and
+# types for new entries.
+#
+# "location" lines define places in the directory where new entries can be added
+# The format of each line is:
+# location HANDLE FRIENDLYNAME DN
+# where HANDLE is a short name which is used in the "newtype" lines (see below)
+# and FRIENDLYNAME is a human-readable name for the location
+# and DN is the Distinguished Name for this location (if it does not end with
+# '#', the location-suffix is appended to to construct a full DN; if it
+# does end with `#', it assumed to be a full DN and the `#' is removed).
+#
+location country "USA" "c=US#"
+location org "Eigene Firma" ""
+location groups "Gruppen in Firma" "ou=Groups"
+location acct "Buchhaltung" "ou=Accounting"
+location hr "Personal" "ou=Human Resources"
+location pay "Lohnbuchhaltung" "ou=Payroll"
+location pd "Produktentwicklung" "ou=Product Development"
+location test "Produkttests" "ou=Product Testing"
+
+# "newtype" lines define the types of new entries that may be added
+# The format of each line is:
+# newtype TEMPLATENAME FRIENDLYNAME RDNATTR LOCATIONS...
+# where TEMPLATENAME corresponds to an existing add-TEMPLATENAME.html file
+# and FRIENDLYNAME is a human-readable name for this type of entry
+# and RDNATTR is the attribute that is used to name entries of this type
+# and LOCATIONS is a blank-separated list of locations where these types of
+# entries can be added (corresponding to a HANDLE on a "location"
+# config. file line).
+#
+newtype orgperson "Person" cn acct hr pay pd test
+newtype ntperson "NT-Benutzer" cn acct hr pay pd test
+newtype groupun "Gruppe" cn groups
+newtype orgunit "Organisationseinheit" ou org
+newtype org "Firma" o country
diff --git a/ldap/clients/dsgw/config/de/dsgw.tmpl b/ldap/clients/dsgw/config/de/dsgw.tmpl
new file mode 100644
index 00000000..f126945d
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/dsgw.tmpl
@@ -0,0 +1,116 @@
+# The htmldir directive tells the CGIs where to find the html files
+htmldir ../html
+
+# The configdir directive tells the CGIs where to find the
+# templates/configuration files
+configdir ../config
+
+# The gwnametrans directive tells the CGIs what url to output
+# for http redirection. It should be the same nameTrans set
+# in the webserver, if any is being is used.
+gwnametrans /clients/dsgw/html/
+
+# The authlifetime directive specifies how long authentication credentials
+# are valid (in seconds).
+authlifetime 7200
+
+# The libNLS data directory. This directory should contain a directory
+# named "locales", which contains the configuration files LANG.ctx and
+# LANG.txt for each supported language (locale).
+NLS ../../../lib/nls
+
+# The default character set, for communication with HTTP clients.
+# A client may override this default, using an HTTP Accept-Charset header.
+# Or, this default may be overridden for a specific language, by creating
+# a LANG/dsgwcharset.conf file which contains the charset name.
+# For compatibility with HTTP clients that can't handle an HTTP response
+# with a charset parameter in the content-type, comment out this directive;
+# responses will be sent in ISO-8859-1, with no explicit charset parameter.
+# RFC 1345 defines the syntax of charset names. There is a registry of
+# charsets, at ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+# charset UTF-8
+
+# Substitute ideographic space for non-breaking space in Asian charsets:
+changeHTML "  " " " Shift_JIS Big5 EUC-KR
+changeHTML " " " " Shift_JIS Big5 EUC-KR
+
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using ds/templateindex. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template ntgroup groupOfUniqueNames ntGroup
+template groupun groupOfUniqueNames
+template org organization
+template orgunit organizationalUnit
+template ntperson person inetOrgPerson nTUser
+template orgperson person inetOrgPerson
+template person person
+template country country
+
+#
+# The remainder of this file contains information about the locations and
+# types for new entries.
+#
+# "location" lines define places in the directory where new entries can be added
+# The format of each line is:
+# location HANDLE FRIENDLYNAME DN
+# where HANDLE is a short name which is used in the "newtype" lines (see below)
+# and FRIENDLYNAME is a human-readable name for the location
+# and DN is the Distinguished Name for this location (if it does not end with
+# '#', the location-suffix is appended to to construct a full DN; if it
+# does end with `#', it assumed to be a full DN and the `#' is removed).
+#
+location country "USA" "c=US#"
+location org "Diese Organisation" ""
+location groups "Gruppen" "ou=Groups"
+location people "Personen" "ou=People"
+location special "Spezialbenutzer" "ou=Special Users"
+
+# "newtype" lines define the types of new entries that may be added
+# The format of each line is:
+# newtype TEMPLATENAME FRIENDLYNAME RDNATTR LOCATIONS...
+# where TEMPLATENAME corresponds to an existing display-TEMPLATENAME.html file
+# and FRIENDLYNAME is a human-readable name for this type of entry
+# and RDNATTR is the attribute that is used to name entries of this type
+# and LOCATIONS is a blank-separated list of locations where these types of
+# entries can be added (corresponding to a HANDLE on a "location"
+# config. file line).
+#
+newtype orgperson "Person" uid people special
+newtype ntperson "NT-Benutzer" uid people special
+newtype ntgroup "NT-Gruppe" cn groups
+newtype groupun "Gruppe" cn groups
+newtype orgunit "Gesch&auml;ftsbereich" ou people org
+newtype org "Firma" o country
+
+# Mappings between VCard properties and LDAP attribute types:
+# The format of each line is:
+# vcard-property VCARDPROP SYNTAX LDAPATTR [LDAPATTR2]
+# where VCARDPROP is the name of a VCard property
+# and SYNTAX is "cis" for simple strings and "mls" for multiline strings
+# and LDAPATTR is the LDAP attribute that corresponds to VCARDPROP
+# and LDAPATTR2 is an optional secondary LDAP attribute which is added to
+# the property value by appending a semicolon and then the attr2 value.
+vcard-property FN cis cn
+vcard-property N cis sn givenName
+vcard-property ORG cis o ou
+vcard-property ROLE cis businessCategory
+vcard-property ADR;WORK mls postalAddress
+vcard-property ADR;HOME mls homePostalAddress
+vcard-property EMAIL;INTERNET cis mail
+vcard-property TITLE cis title
+vcard-property TEL;WORK cis telephoneNumber
+vcard-property TEL;FAX cis facsimileTelephoneNumber
+vcard-property TEL;CELL cis mobile
+vcard-property TEL;HOME cis homePhone
+vcard-property NOTE cis description
diff --git a/ldap/clients/dsgw/config/de/dsgw_adm.conf b/ldap/clients/dsgw/config/de/dsgw_adm.conf
new file mode 100644
index 00000000..28dc9775
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/dsgw_adm.conf
@@ -0,0 +1,46 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using the templateindex program. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template groupun groupOfUniqueNames
+template org organization
+template orgunit organizationalUnit
+template orgperson person inetOrgPerson
+template person person
+template country country
+template licensed-user nsLicenseUser
+
+# Attribute Value Sets (used with DS_ATTRVAL_SET directives)
+# attrvset HANDLE VALUE PREFIX SUFFIX
+#
+attrvset CAL news "" "Netscape Collabra Server"
+attrvset CAL slapd "" "Netscape Directory Server"
+
+
+# Template Set definitions
+# Note: templates must be defined before they can be mentioned on
+# a tmplset line.
+#
+# tmplset SETNAME VIEWNAME TEMPLATENAME [HREF-LOCATION]
+#
+tmplset person "Allgemein" orgperson
+tmplset person "Kennwort:" passwd
+tmplset person "Lizenzen" licensed-user
+tmplset group "Allgemein" group
+tmplset groupun "Allgemein" groupun
diff --git a/ldap/clients/dsgw/config/de/dsgwfilter.conf b/ldap/clients/dsgw/config/de/dsgwfilter.conf
new file mode 100644
index 00000000..5b08d17c
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/dsgwfilter.conf
@@ -0,0 +1,139 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example:
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "LDAP-Filter ist"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "Telefonnummer endet mit"
+
+ "@" " " "(mail=%v))" "E-Mail-Adresse ist"
+ "(mail=%v*))" "E-Mail-Adresse beginnt mit"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "Erste Initiale + Name ist"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "Name + letzte Initiale ist"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "Name ist"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "Name &auml;hnlich wie oder enth&auml;lt"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(uid=*)))" "Name oder Benutzer-ID ist"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)(uid=%v1)))" "Name oder Benutzer-ID ist"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "Name &auml;hnlich wie oder enth&auml;lt"
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "LDAP-Filter ist"
+
+ "^\*$" " " "(cn=*))" "Name ist"
+
+ ".*" ". _" "(cn=%v1-))" "Name ist"
+ "(cn=*%v1-*))" "Name enth&auml;lt"
+ "(cn~=%v1-))" "Name &auml;hnlich wie"
+
+"dsgw-ntgroups"
+ "=" " " "(%v))" "LDAP-Filter ist"
+
+ "^\*$" " " "(cn=*))" "Name ist"
+
+ ".*" ". _" "(cn=%v1-))" "Name ist"
+ "(cn=*%v1-*))" "Name enth&auml;lt"
+ "(cn~=%v1-))" "Name &auml;hnlich wie"
+ "(ntgroupdomainid=%v:*))" "NT-Dom&auml;ne:"
+ "(ntgroupdomainid=*:%v))" "NT-Gruppe ist"
+
+"dsgw-organizations"
+ "=" " " "(%v))" "LDAP-Filter ist"
+
+ "\." " " "(associatedDomain=%v))" "Zugeh&ouml;rige Dom&auml;ne ist"
+
+ "^\*$" " " "(o=*))" "Name ist"
+
+ ".*" " " "(o=%v))" "Name ist"
+ "(o=*%v*))" "Name enth&auml;lt"
+ "(o~=%v))" "Name &auml;hnlich wie"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "LDAP-Filter ist"
+
+ "\." " " "(associatedDomain=%v))" "Zugeh&ouml;rige Dom&auml;ne ist"
+
+ "^\*$" " " "(ou=*))" "Name ist"
+
+ ".*" " " "(ou=%v))" "Name ist"
+ "(ou=*%v*))" "Name enth&auml;lt"
+ "(ou~=%v))" "Name &auml;hnlich wie"
+
+"dsgw-anything"
+ "=" " " "(%v)" "LDAP-Filter ist"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)(o=%v1-)(ou=%v1-))" "Name ist"
+ "(|(sn~=%v1-)(cn~=%v1-)(o=%v1-)(ou=%v1-))" "Name &auml;hnlich wie"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(o=*)(ou=*))" "Name ist"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)(o=%v1)(ou=%v1))" "Name ist"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)(o=%v1)(ou=%v1))" "Name &auml;hnlich wie oder enth&auml;lt"
+
+
+"dsgw-ntpeople"
+ "=" " " "(%v))" "LDAP-Filter ist"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "Telefonnummer endet mit"
+
+ "@" " " "(mail=%v))" "E-Mail-Adresse ist"
+ "(mail=%v*))" "E-Mail-Adresse beginnt mit"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "Erste Initiale + Name ist"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "Name + letzte Initiale ist"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "Name ist"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "Name &auml;hnlich wie oder enth&auml;lt"
+
+ "^\*$" " " "(|(cn=*)(sn=*)))" "Name ist"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)))" "Name ist"
+ "(ntuserlogonserver=%v))" "NT-Anmelde-Server ist"
+ "(ntuserdomainid=%v:*))" "NT-Dom&auml;nenname ist:"
+ "(ntuserdomainid=*:%v))" "NT-Benutzername ist"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "Name &auml;hnlich wie oder enth&auml;lt"
+
+# Do not remove this line, or place any directives after it.
diff --git a/ldap/clients/dsgw/config/de/dsgwfilter_adm.conf b/ldap/clients/dsgw/config/de/dsgwfilter_adm.conf
new file mode 100644
index 00000000..6abe00a2
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/dsgwfilter_adm.conf
@@ -0,0 +1,73 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example (en):
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway - for Netscape Admin Server
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "LDAP-Filter ist"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "Telefonnummer endet mit"
+
+ "@" " " "(mail=%v))" "E-Mail-Adresse ist"
+ "(mail=%v*))" "E-Mail-Adresse beginnt mit"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "erste Initiale + Name ist"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "Name + letzte Initiale ist"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "Name ist"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "Name sounds like or contains"
+
+ ".*" ". " "(uid=%v1))" "Anmelde-ID ist"
+ "(|(cn=%v1)(sn=%v1)))" "Name ist"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "Name &auml;hnlich wie oder enth&auml;lt"
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "LDAP-Filter ist"
+
+ ".*" ". _" "(cn=%v1-))" "Name ist"
+ "(cn~=%v1-))" "Name &auml;hnlich wie"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "LDAP-Filter ist"
+
+ ".*" ". _" "(ou=%v1-))" "Name des Gesch&auml;ftsbereichs ist"
+ "(ou~=%v1-))" "Name des Gesch&auml;ftsbereichs &auml;hnlich wie
+
+#Do not remove this line, or place any additional lines after it.
diff --git a/ldap/clients/dsgw/config/de/dsgwsearchprefs.conf b/ldap/clients/dsgw/config/de/dsgwsearchprefs.conf
new file mode 100644
index 00000000..bfc97e4b
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/dsgwsearchprefs.conf
@@ -0,0 +1,213 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# dsgwsearchprefs.conf - directory server gateway search object definitions
+
+
+# the current version of this file format is 1
+Version 1
+
+
+# Name for this search object
+People
+# options (the only one supported right now is "internal" which means that
+# this search object should not be presented directly to the user)
+# use "" for none
+""
+# Label to place before text box user types in
+"Suchen nach:"
+# Filter prefix to append to all searches
+"(&(objectClass=person)"
+# Tag to use for "Fewer Choices" searches - from ldapfilter.conf file
+"dsgw-people"
+# If a search results in > 1 match, retrieve this attribute to help
+# user disambiguate the entries...
+not-used-by-dsgw
+# ...and label it with this string:
+not-used-by-dsgw
+# Search scope to use when searching
+subtree
+# Follows a list of "More Choices" search options. Format is:
+# Label, attribute, select-bitmap, extra attr display name, extra attr ldap name
+# If last two are null, "Fewer Choices" name/attributes used.
+# Label should begin with the article ("the" in English) for
+# languages that require agreement between article and noun
+# (e.g genders in Spanish or French).
+
+"Vollständiger Name" cn 111111 "" ""
+"Nachname" sn 111111 "" ""
+"Telefon" "telephoneNumber" 111011 "" ""
+"E-Mail-Adresse" "mail" 111111 "" ""
+"Benutzer-ID" "uid" 111111 "" ""
+"Titel" title 111111 "" ""
+END
+# Match types
+"ist" "(%a=%v))"
+"ist nicht" "(!(%a=%v)))"
+"Mit Mustervergleich" "(%a~=%v))"
+"beginnt mit" "(%a=%v*))"
+"endet mit" "(%a=*%v))"
+"enthält" "(%a=*%v*))"
+END
+
+
+"NT-People"
+""
+"Suchen nach:"
+"(&(objectClass=ntuser)"
+"dsgw-ntpeople"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"Vollständiger Name" cn 111111 "" ""
+"Nachname" sn 111111 "" ""
+"Telefon" "telephoneNumber" 111011 "" ""
+"E-Mail-Adresse" "mail" 111111 "" ""
+"Benutzer-ID:" "uid" 111111 "" ""
+"Titel" title 111111 "" ""
+"NT-Benutzername" "ntuserdomainid" 110000 "" ""
+"NT-Domäne" "ntuserdomainid" 101000 "" ""
+"NT-Anmelde-Server:" "ntuserlogonserver" 111111 "" ""
+END
+"ist" "(%a=%v))"
+"ist nicht" "(!(%a=%v)))"
+"Mit Mustervergleich" "(%a~=%v))"
+"beginnt mit" "(%a=%v*))"
+"endet mit" "(%a=*%v))"
+"enthält" "(%a=*%v*))"
+END
+
+
+Groups
+""
+"Suchen nach:"
+"(&(|(objectClass=rfc822MailGroup)(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfCertificates))"
+"dsgw-groups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"Name" cn 111111 "" ""
+"Beschreibung:" description 111111 "" ""
+"Besitzer (DN)" "owner" 000011 "owner" "Owner"
+"Mitglied (DN)" "uniquemember" 000011 "" ""
+END
+"ist" "(%a=%v))"
+"ist nicht" "(!(%a=%v)))"
+"Mit Mustervergleich" "(%a~=%v))"
+"beginnt mit" "(%a=%v*))"
+"endet mit" "(%a=*%v))"
+"enthält" "(%a=*%v*))"
+END
+
+NT-Groups
+""
+"Suchen nach:"
+"(&(objectClass=ntGroup)"
+"dsgw-ntgroups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"Name" cn 111111 "" ""
+"NT-Domäne" "ntgroupdomainid" 110000 "" ""
+"NT-Gruppenname:" "ntgroupdomainid" 101000 "" ""
+"Beschreibung:" description 111111 "" ""
+"Besitzer (DN)" "owner" 000011 "owner" "Owner"
+"Mitglied (DN)" "uniquemember" 000011 "" ""
+END
+"ist" "(%a=%v))"
+"ist nicht" "(!(%a=%v)))"
+"Mit Mustervergleich" "(%a~=%v))"
+"beginnt mit" "(%a=%v*))"
+"endet mit" "(%a=*%v))"
+"enthält" "(%a=*%v*))"
+END
+
+
+Organizations
+""
+"Suchen nach:"
+"(&(objectClass=organization)"
+"dsgw-organizations"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"Name" o 111111 "" ""
+"Standort:" l 111111 "" ""
+"Telefon" telephoneNumber 111011 "" ""
+"Beschreibung:" description 111011 "" ""
+END
+"ist" "(%a=%v))"
+"ist nicht" "(!(%a=%v)))"
+"Mit Mustervergleich" "(%a~=%v))"
+"beginnt mit" "(%a=%v*))"
+"endet mit" "(%a=*%v))"
+"enthält" "(%a=*%v*))"
+END
+
+
+"Org-Units"
+""
+"Suchen nach:"
+"(&(objectClass=organizationalUnit)"
+"dsgw-orgunits"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"Name" ou 111111 "" ""
+"Standort:" l 111111 "" ""
+"Telefon" telephoneNumber 111011 "" ""
+"Beschreibung:" description 111011 "" ""
+END
+"ist" "(%a=%v))"
+"ist nicht" "(!(%a=%v)))"
+"Mit Mustervergleich" "(%a~=%v))"
+"beginnt mit" "(%a=%v*))"
+"endet mit" "(%a=*%v))"
+"enthält" "(%a=*%v*))"
+END
+
+Anything
+""
+"Suchen nach:"
+""
+"dsgw-anything"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"Allg. Name:" cn 111111 "" ""
+"Beschreibung:" description 111111 "" ""
+END
+"ist" "(%a=%v)"
+"ist nicht" "(!(%a=%v))"
+"Mit Mustervergleich" "(%a~=%v)"
+"beginnt mit" "(%a=%v*)"
+"endet mit" "(%a=*%v)"
+"enthält" "(%a=*%v*)"
+END
+
+Auth
+internal
+"Beglaubigen als:"
+"(&(objectClass=person)"
+"dsgw-people"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"Allg. Name:" cn 111111 "" ""
+"Vorname" sn 111111 "" ""
+"Telefon" "telephoneNumber" 111011 "" ""
+"E-Mail-Adresse" "mail" 111111 "" ""
+"Benutzer-ID:" "uid" 111111 "" ""
+"Titel" title 111111 "" ""
+END
+"ist" "(%a=%v))"
+"ist nicht" "(!(%a=%v)))"
+"Mit Mustervergleich" "(%a~=%v))"
+"beginnt mit" "(%a=%v*))"
+"endet mit" "(%a=*%v))"
+"enthält" "(%a=*%v*))"
+END
+
diff --git a/ldap/clients/dsgw/config/de/edit-passwd.html b/ldap/clients/dsgw/config/de/edit-passwd.html
new file mode 100644
index 00000000..7cc0ed1f
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/edit-passwd.html
@@ -0,0 +1,78 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- change a directory entry's password -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Kennwort &auml;ndern -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+</HEAD>
+
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<H2><CENTER>Kennwort &auml;ndern f&uuml;r
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</H2></CENTER>
+
+<HR>
+
+<P>
+<TABLE>
+
+<!-- IF "BoundAsThisEntry" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+Altes Kennwort:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ELIF "!Bound" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+Altes Kennwort:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ENDIF //BoundAsThisEntry -->
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Neues Kennwort:
+</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD></TR>
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Neues Kennwort zur Best&auml;tigung wiederholen:
+</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+</TABLE>
+
+<P>
+
+<TABLE BORDER=2 WIDTH="100%">
+<TR>
+<TD ALIGN="center" WIDTH="50%">
+<!-- IF "BoundAsThisEntry" -->
+<!-- DS_SAVEBUTTON "label=Kennwort &auml;ndern" -->
+<!-- ELSE -->
+<!-- DS_SAVEBUTTON "label=Kennwort festlegen" -->
+<!-- ENDIF -->
+<TD ALIGN="center" WIDTH="50%">
+<!-- DS_HELPBUTTON "topic=MODIFYPASSWD" -->
+</TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-Anything.html b/ldap/clients/dsgw/config/de/list-Anything.html
new file mode 100644
index 00000000..0ad13a2a
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-Anything.html
@@ -0,0 +1,42 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Suche nach Beliebigem" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Name<TH NOWRAP>Telefon
+<TH NOWRAP>E-Mail-Adresse <TH NOWRAP>Beschreibung
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Versuchen Sie es mit einem anderen Suchbegriff.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-Auth.html b/ldap/clients/dsgw/config/de/list-Auth.html
new file mode 100644
index 00000000..85183bfd
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-Auth.html
@@ -0,0 +1,73 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Authenticate as..." -->
+
+<!--
+ The "authForm" form and the authSubmit() JavaScript function are
+ used to avoid the need for a separate form for each entry listed.
+ Each entry is tied to this single form through the magic of an
+ anchor that contains href=javascript:authSubmit().
+-->
+
+<FORM NAME="authForm" METHOD=POST ACTION="auth">
+<INPUT TYPE="hidden" NAME="escapedbinddn">
+<INPUT TYPE="hidden" NAME="authdesturl"
+<!-- PCONTEXT -->
+<!-- DS_POSTEDVALUE "name=authdesturl" "within=VALUE=%22--value--%22" -->
+>
+</FORM>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function authSubmit(encodeddn)
+{
+ document.authForm.escapedbinddn.value = encodeddn;
+ document.authForm.submit();
+}
+// End hiding -->
+</SCRIPT>
+
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC "VERBOSE" -->
+<P>
+<!-- IF "FoundEntries" -->
+Klicken Sie auf den Eintrag, den Sie zur Beglaubigung verwenden m&ouml;chten.
+</FONT>
+<P>
+
+<TABLE BORDER=1 CELLPADDING=4>
+<TR>
+<TH NOWRAP>Beglaubigen als <TH NOWRAP>Titel
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:authSubmit('--value--'); onMouseOver=%22window.status='Zum Beglaubigen klicken'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+<!-- ELSE "FoundEntries" -->
+Gehen Sie zur&uuml;ck, und versuchen Sie es neu.
+<!-- ENDIF "FoundEntries" -->
+</CENTER>
+
+<FORM>
+<TABLE BORDER=2 WIDTH=100%%>
+<TR>
+<TD ALIGN=center width=50%%>
+<INPUT TYPE="button" VALUE="Zur&uuml;ck" onClick="history.back();">
+<TD ALIGN=center WIDTH=50%%>
+<!-- DS_HELPBUTTON "topic=AUTHMULTMATCH" -->
+</TABLE>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-Groups.html b/ldap/clients/dsgw/config/de/list-Groups.html
new file mode 100644
index 00000000..71e2f1eb
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-Groups.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Suche nach Gruppen" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Gruppe
+<TH NOWRAP>Beschreibung
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Versuchen Sie es mit einem anderen Suchbegriff.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-NT-Groups.html b/ldap/clients/dsgw/config/de/list-NT-Groups.html
new file mode 100644
index 00000000..340b78de
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-NT-Groups.html
@@ -0,0 +1,44 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for NT Groups" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>LDAP-Gruppenname
+<TH NOWRAP>NT-Dom&auml;nenname
+<TH NOWRAP>NT-Gruppenname:
+<TH NOWRAP>Beschreibung
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntdomain" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntgroupname" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Versuchen Sie es mit einem anderen Suchbegriff.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-NT-People.html b/ldap/clients/dsgw/config/de/list-NT-People.html
new file mode 100644
index 00000000..ebeb8529
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-NT-People.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for NT-People" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Name<TH NOWRAP>NT-Dom&auml;ne<TH NOWRAP>NT-Benutzer-ID<TH NOWRAP>TelephoneNumber
+</TR>
+
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "label=" -->
+ onMouseOver="window.status='F&uuml;r Details zu diesem Eintrag hier klicken'; return true">
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=0" "defaultvalue=name" "options=readonly" -->
+</A>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntdomain" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntuserid" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Versuchen Sie es mit einem anderen Suchbegriff.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-Org-Units.html b/ldap/clients/dsgw/config/de/list-Org-Units.html
new file mode 100644
index 00000000..cbde88f4
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-Org-Units.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Suche nach Gesch&auml;ftsbereichen" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Gesch&auml;ftsbereich<TH>Beschreibung<TH>Telefon
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Versuchen Sie es mit einem anderen Suchbegriff.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-Organizations.html b/ldap/clients/dsgw/config/de/list-Organizations.html
new file mode 100644
index 00000000..6abb6e1b
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-Organizations.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Suche nach Firmen" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Firma<TH>Beschreibung<TH>Telefon
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Versuchen Sie es mit einem anderen Suchbegriff.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-People.html b/ldap/clients/dsgw/config/de/list-People.html
new file mode 100644
index 00000000..4b6ff0dd
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-People.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Name<TH NOWRAP>Telefon<TH NOWRAP>E-Mail-Adresse<TH NOWRAP>Title
+</TR>
+
+<!-- DS_SORTENTRIES "attr=cn"-->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "label=" -->
+ onMouseOver="window.status='F&uuml;r Details zu diesem Eintrag hier klicken'; return true">
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=0" "defaultvalue=name" "options=readonly" -->
+</A>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Versuchen Sie es mit einem anderen Suchbegriff.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-fa-Groups.html b/ldap/clients/dsgw/config/de/list-fa-Groups.html
new file mode 100644
index 00000000..d69fdc72
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-fa-Groups.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Suche nach Benutzern" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-fa-People.html b/ldap/clients/dsgw/config/de/list-fa-People.html
new file mode 100644
index 00000000..d69fdc72
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-fa-People.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Suche nach Benutzern" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/list-urlsearch.html b/ldap/clients/dsgw/config/de/list-urlsearch.html
new file mode 100644
index 00000000..8ebdba8b
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/list-urlsearch.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Suche nach URL" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Name <TH>Telefon <TH>E-Mail-Adresse
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Versuchen Sie es mit einem anderen Suchbegriff.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/de/newentry.html b/ldap/clients/dsgw/config/de/newentry.html
new file mode 100644
index 00000000..fb2c21f6
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/newentry.html
@@ -0,0 +1,25 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentry.html-->
+<TITLE>Netscape Directory Server Gateway Neuer Eintrag</TITLE>
+<!-- DS_NEWENTRY_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=75,70,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=newentrytitle.html" NORESIZE SCROLLING="NO">
+ <FRAME SRC="newentry?<!-- GCONTEXT -->&file=type"
+ NAME="newentryTypeFrame" SCROLLING="NO"> <FRAME SRC="newentry?<!-- GCONTEXT -->&file=name"
+ NAME="newentryNameFrame">
+</FRAMESET>
+
+<NOFRAMES>
+<BODY>
+Sie ben&ouml;tigen einen Client, der Rahmen darstellen kann, um dieses Dokument zu betrachten.
+</BODY>
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/config/de/newentryName.html b/ldap/clients/dsgw/config/de/newentryName.html
new file mode 100644
index 00000000..0cd92a30
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/newentryName.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentryName.html-->
+</HEAD>
+<!-- DS_NEWENTRY_NAME_BODY -->
+<p>
+<!-- DS_NEWENTRY_NAME_FORM -->
+<font SIZE="+2">Schritt 2.</font>
+Geben Sie einen Namen f&uuml;r die neue
+<!-- EVALUATE "entType.fullname" -->
+.
+<p><nobr><font SIZE="+1">
+<!-- EVALUATE "entType.rdnattr" -->
+=</font>
+<input TYPE="text" NAME="entryname" SIZE="40">
+</nobr>
+<p>
+<font SIZE="+2">Schritt 3.</font>
+
+<!-- DS_NEWENTRY_LOCATION_BEGIN -->
+W&auml;hlen Sie aus der untenstehenden Liste den Verzeichnisstandort f&uuml;r diese Person.
+<!-- EVALUATE "entType.fullname" -->
+. Wenn Sie "Andere" w&auml;hlen, m&uuml;ssen Sie den gesamten unverwechselbaren Namen des Standorts eingeben, an dem dieser Eintrag hinzugef&uuml;gt werden soll.
+<p>
+<!-- DS_NEWENTRY_LOCATION_SELECT -->
+<OPTION VALUE="">Andere</OPTION>
+</SELECT>
+<input TYPE="text" NAME="dnsuffix" SIZE="70">
+<p>
+<font SIZE="+2">Schritt 4.</font>
+<!-- DS_NEWENTRY_LOCATION_END -->
+
+Klicken Sie auf "Weiter". Es erscheint ein Formular, in dem Sie Angaben machen oder &auml;ndern k&ouml;nnen. Wenn Sie alle Angaben gemacht haben, speichern Sie den Eintrag.
+<p>
+<center><table BORDER="2" WIDTH="75%">
+<tr><td ALIGN="center" WIDTH="50%">
+<input TYPE="submit" VALUE="Weiter">
+<td ALIGN="center" WIDTH="50%">
+
+<!-- DS_HELP_BUTTON "ADDING" -->
+</table></center></form>
+</body></HTML>
diff --git a/ldap/clients/dsgw/config/de/newentryType.html b/ldap/clients/dsgw/config/de/newentryType.html
new file mode 100644
index 00000000..fcf0f872
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/newentryType.html
@@ -0,0 +1,14 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!--newentryType.html-->
+<!-- DS_NEWENTRY_TYPE_BODY -->
+<!-- DS_NEWENTRY_TYPE_FORM -->
+<font SIZE="+2">Schritt 1.</font>
+W&auml;hlen Sie die Art des zu erstellenden Eintrags.
+<!-- DS_NEWENTRY_TYPE_SELECT -->
+</form></body></HTML>
diff --git a/ldap/clients/dsgw/config/de/search.html b/ldap/clients/dsgw/config/de/search.html
new file mode 100644
index 00000000..8c1a5e36
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/search.html
@@ -0,0 +1,18 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- search.html -->
+<TITLE>Netscape Directory Server Gateway: Standardsuche</TITLE>
+<!-- DS_SEARCH_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=75,100,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=searchtitle.html" SCROLLING="NO">
+ <FRAME SRC="search?<!-- GCONTEXT -->&file=string" NAME=searchFrame NORESIZE SCROLLING="NO">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=greeting.html" NAME=outputFrame>
+</FRAMESET>
+</HTML>
diff --git a/ldap/clients/dsgw/config/de/searchString.html b/ldap/clients/dsgw/config/de/searchString.html
new file mode 100644
index 00000000..ff1531b4
--- /dev/null
+++ b/ldap/clients/dsgw/config/de/searchString.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- searchString.html -->
+</HEAD>
+<!-- DS_SEARCH_BODY -->
+<!-- DS_SEARCH_FORM "target=outputFrame" -->
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
+<TR><TH ALIGN=RIGHT>Suchen: </TH><TD>
+<!-- DS_SEARCH_TYPE -->
+</TD>
+<TH>innerhalb von:</TH><TD>
+<!-- DS_SEARCH_BASE -->
+</TD></TR>
+<TR><TH ALIGN=RIGHT>Suchen nach: </TH>
+<TD COLSPAN=3>
+<INPUT NAME="searchstring" SIZE=30>
+<INPUT TYPE="SUBMIT" VALUE="Suchen">&nbsp;&nbsp;
+<!-- DS_HELP_BUTTON "SMARTSEARCH" -->
+</TD></TR>
+</TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM></BODY></HTML>
diff --git a/ldap/clients/dsgw/config/display-country.html b/ldap/clients/dsgw/config/display-country.html
new file mode 100644
index 00000000..77b677f3
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-country.html
@@ -0,0 +1,61 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=country" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Country -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+
+
+<TABLE>
+<TR><TD NOWRAP>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=country.gif" ALT="Country" HSPACE=5>
+</TD><TD class="boldbig">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TD></TR></TABLE>
+
+<TABLE CELLSPACING="5" width="90%">
+<TR class="bgColor9">
+<TD COLSPAN="5" class="bgColor9">&nbsp;</TD>
+</TR>
+
+<TR><TD VALIGN="TOP" NOWRAP class="bold">Country Name:</TD><TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=co" "options=sort" -->
+</TD><TD WIDTH="20%"></TD>
+<TD VALIGN="TOP" class="bold">Description:</TD><TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+</TD></TR>
+
+<TR><TD VALIGN="TOP" class="bold">See Also:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4">
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" class="bold">URL:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4">
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" -->
+</TD></TR>
+<TR class="bgColor9">
+<TD COLSPAN="5" class="bgColor9">&nbsp;</TD>
+</TR>
+
+</TABLE>
+
+<div class="text22">This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-dc.html b/ldap/clients/dsgw/config/display-dc.html
new file mode 100644
index 00000000..f5c63cd0
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-dc.html
@@ -0,0 +1,188 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</head>
+<!-- DS_OBJECTCLASS "value=domain" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Domaincomponent -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Domaincomponent Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO -->
+</div>
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=dc.gif" ALT="Domaincomponent" HSPACE=5>
+<TD class="boldbig">
+<!-- IF "Adding" -->
+New Domaincomponent -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit Domaincomponent" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New dc" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORG" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORG" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename dc" "prompt=Enter a new name for this domaincomponent:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete dc" "prompt=Delete this domaincomponent?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="domain">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<div class="text22">&nbsp;<B>* Indicates a required field</B><BR></DIV>
+<!-- ENDIF -->
+
+<TABLE width="90%">
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+<TR>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Domaincomponent Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=o" "cols=>20" -->
+</TD><TD WIDTH="20%"></TD>
+<TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Description:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</TR>
+
+<TR><TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Phone:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</TD><TD></TD>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Business Category:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</TD></TR>
+
+<TR><TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Fax:<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</TD><TD></TD>
+<TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Location:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Mailing Address:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>See Also:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4">
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</TR>
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<div class="text22">
+&nbsp;This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-dnedit.html b/ldap/clients/dsgw/config/display-dnedit.html
new file mode 100644
index 00000000..eec41e2d
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-dnedit.html
@@ -0,0 +1,85 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Edit
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<body bgcolor="#FFFFFF" "onLoad='document.searchForm.searchstring.focus();'" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">
+Edit
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</td>
+</tr>
+</table>
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO "suffix=<table width=90% class=bgColor9><tr><td>&nbsp;</td></tr></table>" -->
+</div>
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+<!-- PCONTEXT -->
+
+
+<CENTER>
+<TABLE CELLSPACING=0 CELLPADDING=10 border=0><TR>
+
+<TD NOWRAP>
+Find
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">People
+<OPTION VALUE="Groups">Groups
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+matching&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<!-- DS_DNADDBUTTON "VALUE= Find and Add " -->
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= Find and Remove " -->
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Save Changes " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Cancel " onClick="parent.cancel();">
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON "topic=EDIT_GROUPMEM" -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-dneditpeople.html b/ldap/clients/dsgw/config/display-dneditpeople.html
new file mode 100644
index 00000000..4df010d3
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-dneditpeople.html
@@ -0,0 +1,83 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Edit
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<body bgcolor="#FFFFFF" "onLoad='document.searchForm.searchstring.focus();'" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">
+Edit
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</td>
+</tr>
+</table>
+
+<!-- DS_LAST_OP_INFO "suffix=<table width=90% class="bgColor9"><tr><td>&nbsp;</td></tr></table>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+<!-- PCONTEXT -->
+
+<CENTER>
+<TABLE CELLSPACING=0 CELLPADDING=10 border=0><TR>
+
+<TD NOWRAP>
+Find
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">People
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+matching&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<!-- DS_DNADDBUTTON "VALUE= Find and Add " -->
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= Find and Remove " -->
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Save Changes " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Cancel " onClick="parent.cancel();">
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON "topic=EDIT_PERSON_REF" -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-group.html b/ldap/clients/dsgw/config/display-group.html
new file mode 100644
index 00000000..4774173b
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-group.html
@@ -0,0 +1,186 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Group Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO -->
+</div>
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD class="boldbig">
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Group" HSPACE=5 >
+<!-- IF "Adding" -->
+New Group -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit Group" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Group" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Group" "prompt=Enter a new name for this group:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Group" "prompt=Delete this group?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfNames">
+<!-- ENDIF // Adding -->
+
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- PCONTEXT -->
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<div class="text22">&nbsp; <B>* Indicates a required field</B><BR></div>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5" width="90%">
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Description:</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Owner:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=owner" "desc=Owner" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>See Also:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+<!-- ELSE // !Adding -->
+<I>You must save this entry before you can edit these fields.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Group Members:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=uniquemember" "desc=Group Members" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</TD></TR>
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<div class="text22">&nbsp;This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-groupun.html b/ldap/clients/dsgw/config/display-groupun.html
new file mode 100644
index 00000000..11d52851
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-groupun.html
@@ -0,0 +1,186 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfUniqueNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Group Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO -->
+</div>
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD class="boldbig">
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Group" HSPACE=5 >
+<!-- IF "Adding" -->
+New Group -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit Group" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Group" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Group" "prompt=Enter a new name for this group:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Group" "prompt=Delete this group?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- PCONTEXT -->
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<div class="text22"><b>&nbsp;* Indicates a required field</B><BR></div>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5" width="90%">
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Description:</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Owner:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=owner" "desc=Owner" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>See Also:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+<!-- ELSE // !Adding -->
+<I>You must save this entry before you can edit these fields.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Group Members:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=uniquemember" "desc=Group Members" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</TD></TR>
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+</TABLE>
+
+<!-- IF "!Adding" -->
+<div class="text22">
+&nbsp; This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-ntgroup.html b/ldap/clients/dsgw/config/display-ntgroup.html
new file mode 100644
index 00000000..cb1fa5e5
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-ntgroup.html
@@ -0,0 +1,277 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=ntGroup" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+NT Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">NT Group Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO -->
+</div>
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD class="boldbig">
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Group" HSPACE=5 >
+<!-- IF "Adding" -->
+New NT Group -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit NT Group" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Group" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTGROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTGROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename NT Group" "prompt=Enter a new name for this group:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete NT Group" "prompt=Delete this group?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="ntGroup">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<div class="text22"><B>&nbsp; * Indicates a required field</B><BR></div>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5" width="90%">
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>NT Group Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" "options=readonly" "defaultvalue=none" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>NT Group Type:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "options=readonly" "cols=>16" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>NT Group Domain:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntdomain" "cols=>16" -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Description:</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Locale:</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>40" "defaultvalue=none" -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Organizational Unit:</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>40" "defaultvalue=none" -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Owner:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=owner" "desc=Owner" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>See Also:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+<!-- ELSE // !Adding -->
+<I>You must save this entry before you can edit these fields.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>NT Group Members:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=uniquemember" "desc=NT Group Members" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Delete NT Group if Group deleted:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Yes" "false=No" "defaultvalue=FALSE" "attr=nTGroupDeleteGroup" -->
+</TD><TD></TD>
+</TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP">Create New NT Group:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Yes" "false=No" "defaultvalue=TRUE" "attr=nTGroupCreateNewGroup" -->
+</TD><TD></TD></TR>
+<!-- ENDIF // Adding -->
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+</TABLE>
+
+<!-- IF "!Adding" -->
+
+<div class="text22">
+&nbsp; This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-ntperson.html b/ldap/clients/dsgw/config/display-ntperson.html
new file mode 100644
index 00000000..89582ba4
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-ntperson.html
@@ -0,0 +1,670 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- NT User person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson,nTUser" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+NT Person Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+
+function showAimIcon()
+{
+var aimStatusText = "";
+var aimID = "";
+
+<!-- IF "DisplayAimPresence" -->
+aimStatusText =
+<!-- DS_ATTRIBUTE "attr=nsaimstatustext" "options=quoted" -->
+;
+
+aimID =
+<!-- DS_ATTRIBUTE "attr=nsaimid" "options=quoted" -->
+;
+<!-- ENDIF -->
+
+if (aimStatusText == "" || aimID == "" || aimStatusText != "ONLINE") {
+ return;
+}
+
+document.write('<a href=\"aim:goim?Screenname=' + aimID.replace(/ /,"+") + '\"><IMG SRC=\"lang?<!-- GCONTEXT -->&file=aim-online.gif\" ALT=\"Click to send an AIM to this person\" BORDER=0 HSPACE=5></a>');
+}
+// End hiding -->
+</SCRIPT>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">NT Person Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO -->
+</div>
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<A HREF="javascript:showVCard()">
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="NT Person (click to show card)"
+ BORDER=0 HSPACE=5></A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD>
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+
+</TD>
+<!-- ENDIF -->
+<TD class="boldbig">
+<!-- IF "Adding" -->
+New NT Person -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-email-cert" -->
+>Download Certificate</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Play Audio Clip</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<INPUT TYPE="button" VALUE="Show Card" onClick="showVCard()">
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Edit NT Person" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New NT Person" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Change Directory Password" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Person" "prompt=Enter a new name for this person:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Person" "prompt=Delete this person?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nTUser">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nsaimpresence">
+<!-- ENDIF // Adding -->
+
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- PCONTEXT -->
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<div class="text22"><B>&nbsp; * Indicates a required field</B></div><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+<TH COLSPAN=4 align=left>
+Contact Information</TH>
+</TR>
+<TR>
+<TD VALIGN="top" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>First Name:</TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</TD>
+<TD VALIGN="top" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Common Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Last Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>E-Mail Address:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</TD>
+</TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Directory Password:</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</TD>
+<TD> Repeat password to confirm:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Phone:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>AIM ID:</TD>
+
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nsaimid" "cols=>16" -->
+<!-- IF "DisplayAimPresence" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+showAimIcon();
+// End hiding -->
+</SCRIPT>
+<!-- ENDIF -->
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Fax:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>User ID:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Pager:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Mobile Phone:<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</TD></TR>
+
+</TABLE>
+
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+<TH COLSPAN=4 align=left>
+Windows NT Account Information</TH>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>NT User Id:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" "options=readonly" -->
+<!-- ENDIF // Adding -->
+<!-- IF "Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>NT Domain Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD><TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntdomain" "cols=>16" -->
+</TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Delete NT Account if Person deleted:</TD>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Yes" "false=No" "defaultvalue=FALSE" "attr=nTUserDeleteAccount" -->
+</TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP" COLSPAN=2>Create New NT Account :</TD>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Yes" "false=No" "defaultvalue=TRUE" "attr=nTUserCreateNewAccount" -->
+</TD></TR>
+
+<!-- ENDIF // Adding -->
+
+<!-- IF "Displaying" -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP class="bold">NT User Comment:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserUsrComment" "defaultvalue=None" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP class="bold">NT User Unique Id:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserUniqueId" "syntax=binvalue" "cols=>10" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP class="bold">NT Password Expired:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Yes" "false=No" "defaultvalue=FALSE" "attr=nTUserPasswordExpired" -->
+</TD>
+<TD VALIGN="TOP" class="bold">NT Bad Password Count:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserBadPwCount" "syntax=binvalue" "options=decimal" "cols=>4" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" class="bold">NT Last Logon Date:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogon" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP class="bold">NT Last Logoff Date:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogoff" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" class="bold">NT Account Expiration Date:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserAcctExpires" "syntax=time" "defaultvalue=Never Expires" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP class="bold">Number of NT Logons:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserNumLogons" "syntax=binvalue" "options=decimal" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" class="bold">NT Logon Server:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserLogonServer" "defaultvalue=Any Server" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP class="bold">NT Workstations:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserWorkstations" "defaultvalue=No Restrictions" "cols=>16" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" class="bold">NT Code Page:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserCodePage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP class="bold">NT Country Code:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserCountryCode" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" class="bold">NT Primary Group Id:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserPrimaryGroupId" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP class="bold">NT Profile:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserProfile" "defaultvalue=Default" "cols=>16" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP class="bold">NT Home Directory:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDir" "defaultvalue=None" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" class="bold">NT Home Directory Drive:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDirDrive" "defaultvalue=None" "cols=>20" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP class="bold">NT Script Path:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserScriptPath" "defaultvalue=None" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP class="bold">NT Max Storage:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserMaxStorage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" class="bold">NT Units Per Week:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserUnitsPerWeek" "syntax=binvalue" "options=decimal" "cols=>6" -->
+</TD>
+<TD VALIGN="TOP" class="bold">NT User's Privileges:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserPriv" "syntax=binvalue" "cols=>16" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" class="bold">NT User's Operator Privileges:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserAuthFlags" "syntax=binvalue" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" class="bold">NT User Account Misc. Features:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nTUserFlags" "syntax=binvalue" "cols=>16" -->
+</TD></TR>
+
+<!-- ENDIF // Displaying -->
+</TABLE>
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+ <TH align=left COLSPAN=4>
+ Business and Location Information</TH>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Business Category:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Title:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Organizational Unit:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Manager:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dneditpeople" "attr=manager" "desc=Manager" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>You must save this entry before you can edit these fields.</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Room Number:</TD>
+<TD VALIGN="TOP" NOWRAP">
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Admin.:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dneditpeople" "attr=secretary" "desc=Admin." -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Dept#:</TD>
+<TD VALIGN="TOP">
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Emp#:</TD>
+<TD VALIGN="TOP">
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Car License#:</TD>
+<TD VALIGN="TOP">
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Mailing Address:</TD>
+<TD VALIGN="TOP" COLSPAN="3" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+<TH align=left COLSPAN=2>
+Additional Information</TH>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Description:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>See Also:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>You must save this entry before you can edit this field.</I>
+<!-- ELSE // !Adding -->
+
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>URL:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Unique ID:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</TR>
+-->
+<tr><td colspan="2" class="bgColor9">&nbsp;</td></tr>
+</TABLE>
+
+<!-- IF "!Adding" -->
+
+<div class="text22">
+&nbsp; This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-org.html b/ldap/clients/dsgw/config/display-org.html
new file mode 100644
index 00000000..d279c5d0
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-org.html
@@ -0,0 +1,189 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organization" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Organization -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Organization Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO -->
+</div>
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=organization.gif" ALT="Organization" HSPACE=5>
+<TD class="boldbig">
+
+<!-- IF "Adding" -->
+New Organization -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit Organization" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Org." -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORG" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORG" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Org." "prompt=Enter a new name for this organization:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Org." "prompt=Delete this organization?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organization">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<div class="text22"><B>&nbsp;* Indicates a required field<BR></B></div>
+<!-- ENDIF -->
+
+<TABLE width="90%">
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+<TR>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Organization Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=o" "cols=>20" -->
+</TD><TD WIDTH="20%"></TD>
+<TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Description:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</TR>
+
+<TR><TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Phone:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</TD><TD></TD>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Business Category:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</TD></TR>
+
+<TR><TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Fax:<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</TD><TD></TD>
+<TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Location:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Mailing Address:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>See Also:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4">
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</TR>
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<div class="text22">
+&nbsp; This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-orgperson.html b/ldap/clients/dsgw/config/display-orgperson.html
new file mode 100644
index 00000000..36ae862a
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-orgperson.html
@@ -0,0 +1,501 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- inet. organizational person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Person Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+
+function showAimIcon()
+{
+var aimStatusText = "";
+var aimID = "";
+
+<!-- IF "DisplayAimPresence" -->
+aimStatusText =
+<!-- DS_ATTRIBUTE "attr=nsaimstatustext" "options=quoted" -->
+;
+
+aimID =
+<!-- DS_ATTRIBUTE "attr=nsaimid" "options=quoted" -->
+;
+<!-- ENDIF -->
+
+if (aimStatusText == "" || aimID == "" || aimStatusText != "ONLINE") {
+ return;
+}
+
+document.write('<a href=\"aim:goim?Screenname=' + aimID.replace(/ /,"+") + '\"><IMG SRC=\"lang?<!-- GCONTEXT -->&file=aim-online.gif\" ALT=\"Click to send an AIM to this person\" BORDER=0 HSPACE=5></a>');
+}
+
+// End hiding -->
+</SCRIPT>
+
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Person Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO -->
+</div>
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<A HREF="javascript:showVCard()">
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Person (click to show card)"
+ BORDER=0 HSPACE=5></A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD>
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+
+</TD>
+<!-- ENDIF -->
+<TD class="boldbig">
+<!-- IF "Adding" -->
+New Person -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-email-cert" -->
+>Download Certificate</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Play Audio Clip</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<INPUT TYPE="button" VALUE="Show Card" onClick="showVCard()">
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Edit Person" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Person" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Change Password" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Person" "prompt=Enter a new name for this person:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Person" "prompt=Delete this person?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nsaimpresence">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<div class="text22"><B>&nbsp; * Indicates a required field<BR></B></div>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+<TH COLSPAN=4 align=left>
+ Contact Information
+ </TH>
+</TR>
+<TR>
+<TD VALIGN="top" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>First Name:</TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</TD>
+<TD VALIGN="top" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Common Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Last Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>E-Mail Address:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</TD>
+</TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Password:</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</TD>
+<TD> Repeat password to confirm:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Phone:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>AIM ID:</TD>
+
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nsaimid" "cols=>16" -->
+<!-- IF "DisplayAimPresence" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+showAimIcon();
+// End hiding -->
+</SCRIPT>
+<!-- ENDIF -->
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Fax:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>User ID:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Pager:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Mobile Phone:<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+<TH align=left COLSPAN=4>
+Business and Location Information</TH>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Business Category:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Title:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Organizational Unit:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Manager:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dneditpeople" "attr=manager" "desc=Manager" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>You must save this entry before you can edit these fields.</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Room Number:</TD>
+<TD VALIGN="TOP" NOWRAP">
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Admin.:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dneditpeople" "attr=secretary" "desc=Admin." -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Dept#:</TD>
+<TD VALIGN="TOP">
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Emp#:</TD>
+<TD VALIGN="TOP">
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Car License#:</TD>
+<TD VALIGN="TOP">
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Mailing Address:</TD>
+<TD VALIGN="TOP" COLSPAN="3" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+<TH align=left COLSPAN=2>
+Additional Information</TH>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Description:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>See Also:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>You must save this entry before you can edit this field.</I>
+<!-- ELSE // !Adding -->
+
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>URL:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Unique ID:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</TR>
+-->
+<tr><td colspan="2" class="bgColor9">&nbsp;</td></tr>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+
+<div class="text22">
+&nbsp; This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-orgunit.html b/ldap/clients/dsgw/config/display-orgunit.html
new file mode 100644
index 00000000..c22478bb
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-orgunit.html
@@ -0,0 +1,191 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organizationalUnit" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Organizational Unit -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Organizational Unit Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO -->
+</div>
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgunit.gif" ALT="Org Unit" HSPACE=5>
+<TD class="boldbig">
+
+<!-- IF "Adding" -->
+New Organizational Unit -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit Organizational Unit" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Org. Unit" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGUNIT" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGUNIT" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Org. Unit" "prompt=Enter a new name for this organizational unit:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Org. Unit" "prompt=Delete this organizational unit?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalUnit">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<div class="text22"><B> &nbsp;* Indicates a required field<BR></B></div>
+<!-- ENDIF -->
+
+
+<TABLE width="90%">
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+<TR>
+<TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Unit Name:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>20" -->
+</TD><TD WIDTH="20%"></TD>
+<TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Description:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</TR>
+
+<TR><TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Phone:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</TD><TD></TD>
+<TD NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Business Category:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</TD></TR>
+
+<TR><TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Fax:<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</TD><TD></TD>
+<TD
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Location:</TD><TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Mailing Address:</TD>
+<TD VALIGN="TOP" COLSPAN="3" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>See Also:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4">
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</TR>
+<tr><td colspan="5" class="bgColor9">&nbsp;</td></tr>
+</TABLE>
+
+<!-- IF "!Adding" -->
+
+<div class="text22">
+&nbsp; This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/display-person.html b/ldap/clients/dsgw/config/display-person.html
new file mode 100644
index 00000000..5e406dc6
--- /dev/null
+++ b/ldap/clients/dsgw/config/display-person.html
@@ -0,0 +1,366 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- person directory entry -->
+<!-- DS_OBJECTCLASS "value=person" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Person Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+
+
+function showAimIcon()
+{
+var aimStatusText = "";
+var aimID = "";
+
+<!-- IF "DisplayAimPresence" -->
+aimStatusText =
+<!-- DS_ATTRIBUTE "attr=nsaimstatustext" "options=quoted" -->
+;
+
+aimID =
+<!-- DS_ATTRIBUTE "attr=nsaimid" "options=quoted" -->
+;
+<!-- ENDIF -->
+
+if (aimStatusText == "" || aimID == "" || aimStatusText != "ONLINE") {
+ return;
+}
+
+document.write('<a href=\"aim:goim?Screenname=' + aimID.replace(/ /,"+") + '\"><IMG SRC=\"lang?<!-- GCONTEXT -->&file=aim-online.gif\" ALT=\"Click to send an AIM to this person\" BORDER=0 HSPACE=5></a>');
+}
+
+// End hiding -->
+</SCRIPT>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Person Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<div class="text22">
+<!-- DS_LAST_OP_INFO -->
+</div>
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR>
+<TD>
+<A HREF="javascript:showVCard()"><IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Person (click to show card)"
+ BORDER=0 HSPACE=5></A></TD>
+<!-- IF "DisplayOrgChart" -->
+<TD>
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ ><IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a></TD>
+<!-- ENDIF -->
+<TD class="boldbig">
+<!-- IF "Adding" -->
+New Person -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</TD></TR></TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<INPUT TYPE="button" VALUE="Show Card" onClick="showVCard()">
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Edit Person" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Person" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_PERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_PERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Change Password" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Rename Person" "prompt=Enter a new name for this person:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Delete Person" "prompt=Delete this person?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nsaimpresence">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<div class="text22"><B>&nbsp; * Indicates a required field</B></div><br>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+<TH COLSPAN=4 align=left>
+ Contact Information
+ </TH>
+</TR>
+<TR>
+<TD VALIGN="top" NOWRAP ROWSPAN="2"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Last Name:</TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2">
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</TD>
+<TD VALIGN="top" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Common Name:
+<!-- IF "!Displaying" -->
+<b>*</b>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>E-Mail Address:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</TD>
+</TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Password:</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</TD>
+<TD> Repeat password to confirm:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Phone:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</TD>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>AIM ID:</TD>
+
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=nsaimid" "cols=>16" -->
+<!-- IF "DisplayAimPresence" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+showAimIcon();
+// End hiding -->
+</SCRIPT>
+<!-- ENDIF -->
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Fax:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>User ID:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Pager:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Mobile Phone:<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+<TH align=left COLSPAN=4>
+Business and Location Information</TH>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Title:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="3">
+<!-- DS_ATTRIBUTE "attr=title" -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Mailing Address:</TD>
+<TD VALIGN="TOP" COLSPAN="3" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BGCOLOR=#FFFFFF WIDTH=95%>
+<TR>
+<TH align=left COLSPAN=4>
+Additional Information</TH>
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Description:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="3">
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>See Also:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="3">
+<!-- IF "Adding" -->
+<I>You must save this entry before you can edit this field.</I>
+<!-- ELSE // !Adding -->
+
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>URL:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="3">
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>Unique ID:</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</TR>
+-->
+<tr><td colspan="4" class="bgColor9">&nbsp;</td></tr>
+</TABLE>
+
+<!-- IF "!Adding" -->
+
+<div class="text22">
+&nbsp; This entry was last modified on <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> by <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+</div>
+
+<!-- ENDIF // !Adding -->
+
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/dsgw-l10n.conf b/ldap/clients/dsgw/config/dsgw-l10n.conf
new file mode 100644
index 00000000..0482312b
--- /dev/null
+++ b/ldap/clients/dsgw/config/dsgw-l10n.conf
@@ -0,0 +1,18 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# Note: the sample part should have double #'s for L10n.
+## translate People <People_translated_in_lang>
+## translate NT-People <NT-People_translated_in_lang>
+## translate Groups <Groups_translated_in_lang>
+## translate NT-Groups <NT-Groups_translated_in_lang>
+## translate Organizations <Organizations_translated_in_lang>
+## translate Org-Units <Org-Units_translated_in_lang>
+## translate Anything <Anything_translated_in_lang>
diff --git a/ldap/clients/dsgw/config/dsgw.tmpl b/ldap/clients/dsgw/config/dsgw.tmpl
new file mode 100644
index 00000000..4bc85cb4
--- /dev/null
+++ b/ldap/clients/dsgw/config/dsgw.tmpl
@@ -0,0 +1,148 @@
+# The attribute the orgchart uses to search for entries.
+# This value should correspond to the value of attrib-farleft-rdn
+# in the orgchart's config.txt configuration file.
+orgchart-attrib-farleft-rdn uid
+
+# Check for Aim presence when the user's entry is displayed
+enable-aim-presence true
+
+# The htmldir directive tells the CGIs where to find the html files
+htmldir ../html
+
+# The configdir directive tells the CGIs where to find the
+# templates/configuration files
+configdir ../config
+
+# The gwnametrans directive tells the CGIs what url to output
+# for http redirection. It should be the same nameTrans set
+# in the webserver, if any is being is used.
+gwnametrans /clients/dsgw/html/
+
+# The authlifetime directive specifies how long authentication credentials
+# are valid (in seconds).
+authlifetime 7200
+
+# The libNLS data directory. This directory should contain a directory
+# named "locales", which contains the configuration files LANG.ctx and
+# LANG.txt for each supported language (locale).
+NLS ../../../lib/nls
+
+# The default character set, for communication with HTTP clients.
+# A client may override this default, using an HTTP Accept-Charset header.
+# Or, this default may be overridden for a specific language, by creating
+# a LANG/dsgwcharset.conf file which contains the charset name.
+# For compatibility with HTTP clients that can't handle an HTTP response
+# with a charset parameter in the content-type, comment out this directive;
+# responses will be sent in ISO-8859-1, with no explicit charset parameter.
+# RFC 1345 defines the syntax of charset names. There is a registry of
+# charsets, at ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+# charset UTF-8
+
+# ignoreAcceptCharsetFrom [ <HTTP client version string> ]
+# where each of whose values is the version string (or part of the version
+# string) sent by an HTTP client which can't / doesn't want to handle UTF-8.
+# Charset from dsgwcharset.conf or charset directive is used (in the order).
+# ignoreAcceptCharsetFrom Mozilla/4.01x-NSCP Mozilla/3
+
+# Substitute ideographic space for non-breaking space in Asian charsets:
+changeHTML "&nbsp;&nbsp;" " " Shift_JIS Big5 EUC-KR EUC-JP
+changeHTML "&nbsp;" " " Shift_JIS Big5 EUC-KR EUC-JP
+
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using ds/templateindex. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template ntgroup groupOfUniqueNames ntGroup
+template groupun groupOfUniqueNames
+template org organization
+template dc domain
+template orgunit organizationalUnit
+template ntperson person inetOrgPerson nTUser
+template orgperson person inetOrgPerson
+template person person
+template country country
+
+#
+# The remainder of this file contains information about the locations and
+# types for new entries.
+#
+# "location" lines define places in the directory where new entries can be added
+# The format of each line is:
+# location HANDLE FRIENDLYNAME DN
+# where HANDLE is a short name which is used in the "newtype" lines (see below)
+# and FRIENDLYNAME is a human-readable name for the location
+# and DN is the Distinguished Name for this location (if it does not end with
+# '#', the location-suffix is appended to to construct a full DN; if it
+# does end with `#', it assumed to be a full DN and the `#' is removed).
+#
+location country "United States" "c=US#"
+location org "This Organization" ""
+location dc "This Domaincomponent" ""
+location groups "Groups" "ou=Groups"
+location people "People" "ou=People"
+location special "Special Users" "ou=Special Users"
+
+# "newtype" lines define the types of new entries that may be added
+# The format of each line is:
+# newtype TEMPLATENAME FRIENDLYNAME RDNATTR LOCATIONS...
+# where TEMPLATENAME corresponds to an existing display-TEMPLATENAME.html file
+# and FRIENDLYNAME is a human-readable name for this type of entry
+# and RDNATTR is the attribute that is used to name entries of this type
+# and LOCATIONS is a blank-separated list of locations where these types of
+# entries can be added (corresponding to a HANDLE on a "location"
+# config. file line).
+#
+newtype orgperson "Person" uid people special
+newtype ntperson "NT Person" uid people special
+newtype ntgroup "NT Group" cn groups
+newtype groupun "Group" cn groups
+newtype orgunit "Organizational Unit" ou people org
+newtype org "Organization" o country
+newtype dc "Domaincomponent" dc dc org country people
+
+# Mappings between VCard properties and LDAP attribute types:
+# The format of each line is:
+# vcard-property VCARDPROP SYNTAX LDAPATTR [LDAPATTR2]
+# where VCARDPROP is the name of a VCard property
+# and SYNTAX is "cis" for simple strings and "mls" for multiline strings
+# and LDAPATTR is the LDAP attribute that corresponds to VCARDPROP
+# and LDAPATTR2 is an optional secondary LDAP attribute which is added to
+# the property value by appending a semicolon and then the attr2 value.
+vcard-property FN cis cn
+vcard-property N cis sn givenName
+vcard-property ORG cis o ou
+vcard-property ROLE cis businessCategory
+vcard-property ADR;WORK mls postalAddress
+vcard-property ADR;HOME mls homePostalAddress
+vcard-property EMAIL;INTERNET cis mail
+vcard-property TITLE cis title
+vcard-property TEL;WORK cis telephoneNumber
+vcard-property TEL;FAX cis facsimileTelephoneNumber
+vcard-property TEL;CELL cis mobile
+vcard-property TEL;HOME cis homePhone
+vcard-property NOTE cis description
+
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# translate People <People_translated_in_lang>
+# translate NT-People <NT-People_translated_in_lang>
+# translate Groups <Groups_translated_in_lang>
+# translate NT-Groups <NT-Groups_translated_in_lang>
+# translate Organizations <Organizations_translated_in_lang>
+# translate Org-Units <Org-Units_translated_in_lang>
+# translate Anything <Anything_translated_in_lang>
+#
+include "../config/dsgw-l10n.conf"
+
diff --git a/ldap/clients/dsgw/config/dsgw_adm.conf b/ldap/clients/dsgw/config/dsgw_adm.conf
new file mode 100644
index 00000000..46f06f4e
--- /dev/null
+++ b/ldap/clients/dsgw/config/dsgw_adm.conf
@@ -0,0 +1,46 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using the templateindex program. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template groupun groupOfUniqueNames
+template org organization
+template orgunit organizationalUnit
+template orgperson person inetOrgPerson
+template person person
+template country country
+template licensed-user nsLicenseUser
+
+# Attribute Value Sets (used with DS_ATTRVAL_SET directives)
+# attrvset HANDLE VALUE PREFIX SUFFIX
+#
+attrvset CAL news "" "Netscape Collabra Server"
+attrvset CAL slapd "" "Netscape Directory Server"
+
+
+# Template Set definitions
+# Note: templates must be defined before they can be mentioned on
+# a tmplset line.
+#
+# tmplset SETNAME VIEWNAME TEMPLATENAME [HREF-LOCATION]
+#
+tmplset person "General" orgperson
+tmplset person "Password" passwd
+tmplset person "Licenses" licensed-user
+tmplset group "General" group
+tmplset groupun "General" groupun
diff --git a/ldap/clients/dsgw/config/dsgwfilter.conf b/ldap/clients/dsgw/config/dsgwfilter.conf
new file mode 100644
index 00000000..6205b12a
--- /dev/null
+++ b/ldap/clients/dsgw/config/dsgwfilter.conf
@@ -0,0 +1,154 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example:
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "LDAP filter is"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "phone number ends with"
+
+ "@" " " "(mail=%v))" "email address is"
+ "(mail=%v*))" "email address starts with"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "first initial + name is"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "name + last initial is"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "name is"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "name sounds like or contains"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(uid=*)))" "name or user id is"
+
+ "^.$" ". " "(|(cn=%v)(sn=%v)(uid=%v)))" "name or user id is"
+
+ "^..$" ". " "(|(cn=%v*)(cn=*%v)(sn=%v*)(sn=*%v)(uid=%v*)(uid=*%v)))" "name or user id is"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)(uid=%v1)))" "name or user id is"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "name sounds like or contains"
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "LDAP filter is"
+
+ "^\*$" " " "(cn=*))" "name is"
+
+ ".*" ". _" "(cn=%v1-))" "name is"
+ "(cn=*%v1-*))" "name contains"
+ "(cn~=%v1-))" "name sounds like"
+
+"dsgw-ntgroups"
+ "=" " " "(%v))" "LDAP filter is"
+
+ "^\*$" " " "(cn=*))" "name is"
+
+ ".*" ". _" "(cn=%v1-))" "name is"
+ "(cn=*%v1-*))" "name contains"
+ "(cn~=%v1-))" "name sounds like"
+ "(ntgroupdomainid=%v:*))" "NT Domain name is"
+ "(ntgroupdomainid=*:%v))" "NT Group is"
+
+"dsgw-organizations"
+ "=" " " "(%v))" "LDAP filter is"
+
+# "\." " " "(associatedDomain=%v))" "associated domain is"
+
+ "^\*$" " " "(o=*))" "name is"
+
+ ".*" " " "(o=%v))" "name is"
+ "(o=*%v*))" "name contains"
+ "(o~=%v))" "name sounds like"
+
+"dsgw-domaincomponents"
+ "=" " " "(%v))" "LDAP filter is"
+
+ "\." " " "(associatedDomain=%v))" "associated domain is"
+
+ "^\*$" " " "(dc=*))" "name is"
+
+ ".*" " " "(dc=%v))" "name is"
+ "(dc=*%v*))" "name contains"
+ "(dc~=%v))" "name sounds like"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "LDAP filter is"
+
+ "\." " " "(associatedDomain=%v))" "associated domain is"
+
+ "^\*$" " " "(ou=*))" "name is"
+
+ ".*" " " "(ou=%v))" "name is"
+ "(ou=*%v*))" "name contains"
+ "(ou~=%v))" "name sounds like"
+
+"dsgw-anything"
+ "=" " " "(%v)" "LDAP filter is"
+
+ "[ ]" " " "(|(sn=%v1-)(cn=%v1-)(o=%v1-)(ou=%v1-))" "name is"
+ "(|(sn~=%v1-)(cn~=%v1-)(o=%v1-)(ou=%v1-))" "name sounds like"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(o=*)(ou=*))" "name is"
+
+ ".*" " " "(|(cn=%v1)(sn=%v1)(o=%v1)(ou=%v1))" "name is"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)(o=%v1)(ou=%v1))" "name sounds like or contains"
+
+
+"dsgw-ntpeople"
+ "=" " " "(%v))" "LDAP filter is"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "phone number ends with"
+
+ "@" " " "(mail=%v))" "email address is"
+ "(mail=%v*))" "email address starts with"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "first initial + name is"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "name + last initial is"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "name is"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "name sounds like or contains"
+
+ "^\*$" " " "(|(cn=*)(sn=*)))" "name is"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)))" "name is"
+ "(ntuserlogonserver=%v))" "NT logon server is"
+ "(ntuserdomainid=%v:*))" "NT Domain name is"
+ "(ntuserdomainid=*:%v))" "NT username is"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "name sounds like or contains"
+
+# Do not remove this line, or place any directives after it.
diff --git a/ldap/clients/dsgw/config/dsgwfilter_adm.conf b/ldap/clients/dsgw/config/dsgwfilter_adm.conf
new file mode 100644
index 00000000..b6654e40
--- /dev/null
+++ b/ldap/clients/dsgw/config/dsgwfilter_adm.conf
@@ -0,0 +1,73 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example (en):
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway - for Netscape Admin Server
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "LDAP filter is"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "phone number ends with"
+
+ "@" " " "(mail=%v))" "email address is"
+ "(mail=%v*))" "email address starts with"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "first initial + name is"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "name + last initial is"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "name is"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "name sounds like or contains"
+
+ ".*" ". " "(uid=%v1))" "login id is"
+ "(|(cn=%v1)(sn=%v1)))" "name is"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "name sounds like or contains"
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "LDAP filter is"
+
+ ".*" ". _" "(cn=%v1-))" "name is"
+ "(cn~=%v1-))" "name sounds like"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "LDAP filter is"
+
+ ".*" ". _" "(ou=%v1-))" "unit name is"
+ "(ou~=%v1-))" "unit name sounds like"
+
+#Do not remove this line, or place any additional lines after it.
diff --git a/ldap/clients/dsgw/config/dsgwsearchprefs.conf b/ldap/clients/dsgw/config/dsgwsearchprefs.conf
new file mode 100644
index 00000000..a0190919
--- /dev/null
+++ b/ldap/clients/dsgw/config/dsgwsearchprefs.conf
@@ -0,0 +1,234 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# dsgwsearchprefs.conf - directory server gateway search object definitions
+
+
+# the current version of this file format is 1
+Version 1
+
+
+# Name for this search object
+People
+# options (the only one supported right now is "internal" which means that
+# this search object should not be presented directly to the user)
+# use "" for none
+""
+# Label to place before text box user types in
+"Search For:"
+# Filter prefix to append to all searches
+"(&(objectClass=person)"
+# Tag to use for "Fewer Choices" searches - from ldapfilter.conf file
+"dsgw-people"
+# If a search results in > 1 match, retrieve this attribute to help
+# user disambiguate the entries...
+not-used-by-dsgw
+# ...and label it with this string:
+not-used-by-dsgw
+# Search scope to use when searching
+subtree
+# Follows a list of "More Choices" search options. Format is:
+# Label, attribute, select-bitmap, extra attr display name, extra attr ldap name
+# If last two are null, "Fewer Choices" name/attributes used.
+# Label should begin with the article ("the" in English) for
+# languages that require agreement between article and noun
+# (e.g genders in Spanish or French).
+"full name" cn 111111 "" ""
+"last name" sn 111111 "" ""
+"phone number" "telephoneNumber" 111011 "" ""
+"e-mail address" "mail" 111111 "" ""
+"user id" "uid" 111111 "" ""
+"title" title 111111 "" ""
+END
+# Match types
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
+
+
+"NT-People"
+""
+"Search For:"
+"(&(objectClass=ntuser)"
+"dsgw-ntpeople"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"full name" cn 111111 "" ""
+"last name" sn 111111 "" ""
+"phone number" "telephoneNumber" 111011 "" ""
+"e-mail address" "mail" 111111 "" ""
+"user id" "uid" 111111 "" ""
+"title" title 111111 "" ""
+"NT username" "ntuserdomainid" 110000 "" ""
+"NT domain" "ntuserdomainid" 101000 "" ""
+"NT logon server" "ntuserlogonserver" 111111 "" ""
+END
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
+
+
+Groups
+""
+"Search For:"
+"(&(|(objectClass=rfc822MailGroup)(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfCertificates))"
+"dsgw-groups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"name" cn 111111 "" ""
+"description" description 111111 "" ""
+"owner (DN)" "owner" 000011 "owner" "Owner"
+"member (DN)" "uniquemember" 000011 "" ""
+END
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
+
+NT-Groups
+""
+"Search For:"
+"(&(objectClass=ntGroup)"
+"dsgw-ntgroups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"name" cn 111111 "" ""
+"NT groupname" "ntgroupdomainid" 110000 "" ""
+"NT domain" "ntgroupdomainid" 101000 "" ""
+"description" description 111111 "" ""
+"owner (DN)" "owner" 000011 "owner" "Owner"
+"member (DN)" "uniquemember" 000011 "" ""
+END
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
+
+
+Organizations
+""
+"Search For:"
+"(&(objectClass=organization)"
+"dsgw-organizations"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"name" o 111111 "" ""
+"location" l 111111 "" ""
+"phone number" telephoneNumber 111011 "" ""
+"description" description 111011 "" ""
+END
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
+
+
+Domaincomponent
+""
+"Search For:"
+"(&(objectClass=domain)"
+"dsgw-domaincomponent"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"name" o 111111 "" ""
+"location" l 111111 "" ""
+"phone number" telephoneNumber 111011 "" ""
+"description" description 111011 "" ""
+END
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
+
+
+"Org-Units"
+""
+"Search For:"
+"(&(objectClass=organizationalUnit)"
+"dsgw-orgunits"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"name" ou 111111 "" ""
+"location" l 111111 "" ""
+"phone number" telephoneNumber 111011 "" ""
+"description" description 111111 "" ""
+END
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
+
+Anything
+""
+"Search For:"
+""
+"dsgw-anything"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"common name" cn 111111 "" ""
+"description" description 111111 "" ""
+END
+"is" "(%a=%v)"
+"is not" "(!(%a=%v))"
+"sounds like" "(%a~=%v)"
+"starts with" "(%a=%v*)"
+"ends with" "(%a=*%v)"
+"contains" "(%a=*%v*)"
+END
+
+Auth
+internal
+"Authenticate As:"
+"(&(objectClass=person)"
+"dsgw-people"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"common name" cn 111111 "" ""
+"surname" sn 111111 "" ""
+"phone number" "telephoneNumber" 111011 "" ""
+"e-mail address" "mail" 111111 "" ""
+"user id" "uid" 111111 "" ""
+"title" title 111111 "" ""
+END
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
+
diff --git a/ldap/clients/dsgw/config/edit-passwd.html b/ldap/clients/dsgw/config/edit-passwd.html
new file mode 100644
index 00000000..36769f00
--- /dev/null
+++ b/ldap/clients/dsgw/config/edit-passwd.html
@@ -0,0 +1,78 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- change a directory entry's password -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Change Password -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+</HEAD>
+
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<H2><CENTER>Change password for
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</H2></CENTER>
+
+<HR>
+
+<P>
+<TABLE>
+
+<!-- IF "BoundAsThisEntry" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+Enter the old password:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ELIF "!Bound" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+Enter the old password:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ENDIF //BoundAsThisEntry -->
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Enter the new password:
+</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD></TR>
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Enter the new password again to confirm:
+</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+</TABLE>
+
+<P>
+
+<TABLE BORDER=2 WIDTH="100%">
+<TR>
+<TD ALIGN="center" WIDTH="50%">
+<!-- IF "BoundAsThisEntry" -->
+<!-- DS_SAVEBUTTON "label=Change Password" -->
+<!-- ELSE -->
+<!-- DS_SAVEBUTTON "label=Set Password" -->
+<!-- ENDIF -->
+<TD ALIGN="center" WIDTH="50%">
+<!-- DS_HELPBUTTON "topic=MODIFYPASSWD" -->
+</TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/en-us/dsgw-l10n.conf b/ldap/clients/dsgw/config/en-us/dsgw-l10n.conf
new file mode 100644
index 00000000..0482312b
--- /dev/null
+++ b/ldap/clients/dsgw/config/en-us/dsgw-l10n.conf
@@ -0,0 +1,18 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# Note: the sample part should have double #'s for L10n.
+## translate People <People_translated_in_lang>
+## translate NT-People <NT-People_translated_in_lang>
+## translate Groups <Groups_translated_in_lang>
+## translate NT-Groups <NT-Groups_translated_in_lang>
+## translate Organizations <Organizations_translated_in_lang>
+## translate Org-Units <Org-Units_translated_in_lang>
+## translate Anything <Anything_translated_in_lang>
diff --git a/ldap/clients/dsgw/config/en-us/dsgwcollate.conf b/ldap/clients/dsgw/config/en-us/dsgwcollate.conf
new file mode 100644
index 00000000..81f9f461
--- /dev/null
+++ b/ldap/clients/dsgw/config/en-us/dsgwcollate.conf
@@ -0,0 +1,8 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# Ignore accents (diacritical marks) when doing case-insensitive comparison.
+caseIgnoreAccents
diff --git a/ldap/clients/dsgw/config/en/dsgw-l10n.conf b/ldap/clients/dsgw/config/en/dsgw-l10n.conf
new file mode 100644
index 00000000..0482312b
--- /dev/null
+++ b/ldap/clients/dsgw/config/en/dsgw-l10n.conf
@@ -0,0 +1,18 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# Note: the sample part should have double #'s for L10n.
+## translate People <People_translated_in_lang>
+## translate NT-People <NT-People_translated_in_lang>
+## translate Groups <Groups_translated_in_lang>
+## translate NT-Groups <NT-Groups_translated_in_lang>
+## translate Organizations <Organizations_translated_in_lang>
+## translate Org-Units <Org-Units_translated_in_lang>
+## translate Anything <Anything_translated_in_lang>
diff --git a/ldap/clients/dsgw/config/en/dsgwcollate.conf b/ldap/clients/dsgw/config/en/dsgwcollate.conf
new file mode 100644
index 00000000..fc799692
--- /dev/null
+++ b/ldap/clients/dsgw/config/en/dsgwcollate.conf
@@ -0,0 +1,41 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# Case 1. en and en-*
+#
+# Ignore accents (diacritical marks) when doing case-insensitive comparison.
+caseIgnoreAccents
+
+# Case 2. Latin-1 languages do not need this file
+
+# Case 3. ja and languages that have "yomi (phonetic representation)"
+#
+# Each line in this file defines a crude string collation.
+# There are two such collations, one for sorting a displayed list, and
+# another for selecting one of several alternative values to display:
+#
+## sort 20,A0,3000-30FF 3190-
+## display 20,A0,3000,3190- 3001-30FF
+#
+# In each line, each parameter defines a "script" as a set of Unicodes;
+# a character is considered to be part of the first script it matches.
+# An implicit final script contains characters that don't match any
+# parameter. Strings are collated in order of these scripts.
+# A mixed-script string is collated with the last script it contains.
+# Strings in the same script category are sorted by another algorithm,
+# which is not defined here.
+#
+# In this file, the sort scripts are Kana, Kanji and everything else,
+# and the display scripts are Kanji, Kana and everything else. So,
+# lists are sorted with pure Kana values first, Kanji values and mixed
+# Kanji/Kana values next, and finally values containing other characters.
+# When choosing a value to display, pure Kanji is preferred, Kana or
+# mixed Kanji/Kana is the next choice, and anything else is the last.
+# These choices aim to sort by Yomi (stored in Kana), but display Kanji.
+#
+# Insignificant characters (such as whitespace) should be included in
+# the first script on each line.
+
diff --git a/ldap/clients/dsgw/config/es/authPassword.html b/ldap/clients/dsgw/config/es/authPassword.html
new file mode 100644
index 00000000..4d842c1c
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/authPassword.html
@@ -0,0 +1,29 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authPassword.html-->
+<TITLE>Autenticar...</TITLE>
+<!-- DS_AUTH_PASSWORD_SCRIPT -->
+</HEAD>
+
+<!-- DS_AUTH_PASSWORD_BODY -->
+<!-- DS_AUTH_PASSWORD_INFO -->
+<!-- DS_AUTH_PASSWORD_FORM -->
+<P>
+Contrase&ntilde;a para <b>
+<!-- DS_AUTH_PASSWORD_NAME -->
+</b>: <INPUT NAME="password" TYPE="password" SIZE=16>
+<P>
+<CENTER>
+<TABLE BORDER=2 WIDTH=100%>
+<TR>
+<!-- DS_AUTH_PASSWORD_BUTTONS -->
+</TABLE>
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/es/authSearch.html b/ldap/clients/dsgw/config/es/authSearch.html
new file mode 100644
index 00000000..7671b0a0
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/authSearch.html
@@ -0,0 +1,33 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authSearch.html-->
+<TITLE>Autenticar...</TITLE>
+<!-- DS_AUTH_SEARCH_SCRIPT -->
+</HEAD>
+<!-- DS_AUTH_SEARCH_BODY -->
+<!-- DS_AUTH_SEARCH_INFO -->
+<!-- DS_AUTH_SEARCH_FORM -->
+El primer paso para autenticarse en el directorio es identificarse.<br>Escriba su nombre:
+<!-- DS_AUTH_SEARCH_NAME -->
+<P>
+<CENTER>
+<TABLE BORDER=1 WIDTH=100%%>
+<TR>
+<!-- DS_AUTH_SEARCH_BUTTONS -->
+</TABLE>
+</FORM>
+<P>
+<!-- DS_AUTH_AS_ROOT_FORM -->
+<INPUT TYPE="submit" VALUE="Autenticar como responsable de directorio">&nbsp;(s&oacute;lo disponible para administradores de directorios)
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/es/csearch.html b/ldap/clients/dsgw/config/es/csearch.html
new file mode 100644
index 00000000..d1b7ca9c
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/csearch.html
@@ -0,0 +1,23 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearch.html-->
+<TITLE>Netscape Directory Server Gateway : Advanced Search </TITLE>
+<!-- DS_CSEARCH_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS="75,70,70,*" BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=csearchtitle.html" SCROLLING="NO">
+ <FRAMESET COLS="35%,42%,*" BORDER=0>
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=type" NAME="searchTypeFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=attr" NAME="searchAttrFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=match" NAME="searchMatchFrame" NORESIZE SCROLLING="NO">
+ </FRAMESET>
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=string" NAME="searchStringFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=emptyFrame.html" NAME="outputFrame">
+</FRAMESET>
+</HTML>
diff --git a/ldap/clients/dsgw/config/es/csearchAttr.html b/ldap/clients/dsgw/config/es/csearchAttr.html
new file mode 100644
index 00000000..a118a5d3
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/csearchAttr.html
@@ -0,0 +1,18 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchAttr.html-->
+</HEAD>
+<!-- DS_CSEARCH_ATTR_BODY -->
+<!-- DS_CSEARCH_ATTR_FORM -->
+<table>
+<tr VALIGN=BASELINE><td ALIGN=RIGHT>donde el:</td><td>
+<!-- DS_CSEARCH_ATTR_SELECT -->
+</td></tr>
+</table></form></body></HTML>
+
diff --git a/ldap/clients/dsgw/config/es/csearchBase.html b/ldap/clients/dsgw/config/es/csearchBase.html
new file mode 100644
index 00000000..aedafe1f
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/csearchBase.html
@@ -0,0 +1,17 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchBase.html-->
+</HEAD>
+<!-- DS_CSEARCH_BASE_BODY -->
+<table>
+<tr VALIGN=CENTER><th>en:</th><td>
+<!-- EVALUATE "parent.UFNsearchBase" -->
+</td>
+</table>
+</body></HTML>
diff --git a/ldap/clients/dsgw/config/es/csearchString.html b/ldap/clients/dsgw/config/es/csearchString.html
new file mode 100644
index 00000000..d9c7c217
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/csearchString.html
@@ -0,0 +1,28 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchString.html-->
+</HEAD>
+<!-- DS_CSEARCH_STRING_BODY -->
+<!-- DS_CSEARCH_STRING_FORM "target=outputFrame" -->
+<TABLE>
+<TR VALIGN=CENTER><TD>
+<INPUT NAME="searchstring" SIZE=20></TD>
+<TD><NOBR>
+<INPUT TYPE="SUBMIT" VALUE="Buscar">
+<!-- DS_HELP_BUTTON "ASEARCH" -->
+</NOBR></TD>
+<td> </td><th>dentro de:</th><td>
+<!-- EVALUATE "parent.UFNsearchBase" -->
+</td>
+</TR></TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/config/es/csearchType.html b/ldap/clients/dsgw/config/es/csearchType.html
new file mode 100644
index 00000000..b51834b1
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/csearchType.html
@@ -0,0 +1,19 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchType.html-->
+</HEAD>
+<!-- DS_CSEARCH_TYPE_BODY -->
+<!-- DS_CSEARCH_TYPE_FORM -->
+<table>
+<tr VALIGN=BASELINE><th ALIGN=RIGHT>Buscar:</th><td>
+<!-- DS_CSEARCH_TYPE_SELECT -->
+</td></tr>
+</table>
+</form></body></HTML>
+
diff --git a/ldap/clients/dsgw/config/es/display-country.html b/ldap/clients/dsgw/config/es/display-country.html
new file mode 100644
index 00000000..413592f9
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-country.html
@@ -0,0 +1,54 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=country" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Pa&iacute;s:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<TABLE>
+<TR><TD NOWRAP>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=country.gif" ALT="Pa&iacute;s" HSPACE=5>
+</TD><TD><FONT SIZE="+2">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE CELLSPACING="5">
+
+<TR><TD VALIGN="TOP" NOWRAP>Nombre del pa&iacute;s:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=co" "options=sort" -->
+</B></TD><TD WIDTH="20%"></TD>
+</B><TD VALIGN="TOP">Descripci&oacute;n</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP">Ver tambi&eacute;n:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">P&aacute;gina web:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" -->
+</B></TD></TR>
+
+</TABLE>
+
+<HR>
+
+Esta entrada fue modificada por &uacute;ltima vez el <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> por <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/display-dnedit.html b/ldap/clients/dsgw/config/es/display-dnedit.html
new file mode 100644
index 00000000..fa209fdb
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-dnedit.html
@@ -0,0 +1,76 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Modificar
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY "onLoad='document.searchForm.searchstring.focus();'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+<!-- PCONTEXT -->
+
+<FONT SIZE="+2">
+Modificar
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<TABLE CELLSPACING=0 CELLPADDING=0><TR>
+
+<TD NOWRAP>
+Buscar
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">Personas
+<OPTION VALUE="Groups">Grupos
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+que concuerden con&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<!-- DS_DNADDBUTTON "VALUE= Buscar y a&ntilde;adir " -->
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= Buscar y borrar " -->
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Guardar los cambios " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Cancelar " onClick="parent.cancel();">
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON "topic=EDIT_GROUPMEM" -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/display-dneditpeople.html b/ldap/clients/dsgw/config/es/display-dneditpeople.html
new file mode 100644
index 00000000..97a299be
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-dneditpeople.html
@@ -0,0 +1,75 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Modificar
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY "onLoad='document.searchForm.searchstring.focus();'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+<!-- PCONTEXT -->
+
+<FONT SIZE="+2">
+Modificar
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<TABLE CELLSPACING=0 CELLPADDING=0><TR>
+
+<TD NOWRAP>
+Buscar
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">Personas
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+que concuerden con&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<!-- DS_DNADDBUTTON "VALUE= Buscar y a&ntilde;adir ">
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= Buscar y borrar ">
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Guardar los cambios " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Cancelar " onClick="parent.cancel();">
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON "topic=EDIT_PERSON_REF" -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/display-group.html b/ldap/clients/dsgw/config/es/display-group.html
new file mode 100644
index 00000000..b7cd01e6
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-group.html
@@ -0,0 +1,149 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nueva
+<!-- ENDIF // Adding -->
+Entrada de grupo:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Grupo" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nuevo grupo:
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Modificar grupo" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Guardar nuevo grupo" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancelar" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Cambiar nombre de grupo" "prompt=Escriba otro nombre para este grupo:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Borrar grupo" "prompt=&#191;Desea borrar este grupo?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfNames">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>El asterisco (*) indica los campos obligatorios</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>Nombre:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>Descripci&oacute;n:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Propietario:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=owner" "desc=Propietario" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Ver tambi&eacute;n:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=seeAlso" "desc=Ver tambi&eacute;n" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>Tiene que guardar esta entrada para poder modificar este campo.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">Miembros del grupo:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=uniquemember" "desc=Miembros del grupo" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Esta entrada fue modificada por &uacute;ltima vez el <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> por <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/display-groupun.html b/ldap/clients/dsgw/config/es/display-groupun.html
new file mode 100644
index 00000000..cbf21ee6
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-groupun.html
@@ -0,0 +1,149 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfUniqueNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nueva
+<!-- ENDIF // Adding -->
+Entrada de grupo:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Grupo" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nuevo grupo:
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Modificar grupo" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Guardar nuevo grupo" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancelar" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Cambiar nombre de grupo" "prompt=Escriba otro nombre para este grupo:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Borrar grupo" "prompt=&#191;Desea borrar este grupo?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>El asterisco (*) indica los campos obligatorios</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>Nombre:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>Description:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Propietario:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=owner" "desc=Propietario" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Ver tambi&eacute;n:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=seeAlso" "desc=Ver tambi&eacute;n" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>Tiene que guardar esta entrada para poder modificar este campo.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">Miembros del grupo:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=uniquemember" "desc=Miembros del grupo" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Esta entrada fue modificada por &uacute;ltima vez el <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> por <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/display-ntgroup.html b/ldap/clients/dsgw/config/es/display-ntgroup.html
new file mode 100644
index 00000000..82ab808a
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-ntgroup.html
@@ -0,0 +1,215 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=ntGroup" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nueva
+<!-- ENDIF // Adding -->
+Entrada de grupo NT:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Grupo" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nuevo grupo NT:
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Modificar grupo NT" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Guardar nuevo grupo" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancelar" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTGROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTGROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Cambiar nombre de grupo NT" "prompt=Escriba otro nombre para este grupo:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Borrar grupo NT" "prompt=&#191;Desea borrar este grupo?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="ntGroup">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>El asterisco (*) indica los campos obligatorios</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>Nombre:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>Nombre de grupo NT:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" "options=readonly" "defaultvalue=none" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" "defaultvalue=none" -->
+<!-- ENDIF // Adding -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Tipo del grupo NT:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "options=readonly" "cols=>16" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Dominio del grupo NT:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntdomain" "cols=>16" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Descripci&oacute;n:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Escenario:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Departamento:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Propietario:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=owner" "desc=Propietario" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Ver tambi&eacute;n<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=seeAlso" "desc=Ver tambi&eacute;n" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>Tiene que guardar esta entrada para poder modificar el campo.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">Miembros del grupo NT<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=uniquemember" "desc=Miembros del grupo NT" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Borrar grupo NT si el grupo borrado es:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=S&iacute;" "false=No" "defaultvalue=FALSE" "attr=nTGroupDeleteGroup" -->
+</B></TD><TD></TD>
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP">Crear nuevo grupo NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=S&iacute;" "false=No" "defaultvalue=TRUE" "attr=nTGroupCreateNewGroup" -->
+</B></TD><TD></TD></TR>
+
+<!-- ENDIF // Adding -->
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Esta entrada fue modificada por &uacute;ltima vez el <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> por <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/display-ntperson.html b/ldap/clients/dsgw/config/es/display-ntperson.html
new file mode 100644
index 00000000..a5c14dba
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-ntperson.html
@@ -0,0 +1,493 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- NT User person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson,nTUser" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nueva
+<!-- ENDIF // Adding -->
+Entrada personal NT:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Persona (haga clic para ver la tarjeta)"
+ BORDER=0 HSPACE=5>
+
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nueva persona NT:
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-ca-cert" -->
+>Recibir certificado</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Play Audio Clip</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="Ver tarjeta" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Modificar persona NT" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Guardar persona NT" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancelar" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Cambiar la contrase&ntilde;a del directorio" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Cambiar nombre de persona" "prompt=Escriba otro nombre para esta persona:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Borrar persona" "prompt=&#191;Desea borrar los datos de esta persona?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nTUser">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<B>El asterisco (*) indica los campos obligatorios</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informaci&oacute;n de contacto</TD>
+</TR>
+
+<TD VALIGN="top" NOWRAP>Nombre:</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</B></TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2">Nombre y apellidos:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2"><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>Apellidos:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Contrase&ntilde;a del directorio:</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</B></TD>
+<TD> Rep&iacute;tala para confirmar:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">Tel&eacute;fono:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Direcci&oacute;n electr&oacute;nica:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Fax:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Identificaci&oacute;n de usuario:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+<TR>
+<TD VALIGN="TOP" NOWRAP>Localizador:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Tel&eacute;fono m&oacute;vil:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+</TABLE>
+&nbsp;
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informaci&oacute;n sobre cuenta Windows NT</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Identificaci&oacute;n de usuario NT:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" "options=readonly" -->
+<!-- ENDIF // Adding -->
+<!-- IF "Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Nombre de dominio NT:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntdomain" "cols=>16" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+<TR>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP>Borrar cuenta NT si la persona borrada es:</TD>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=S&iacute;" "false=No" "defaultvalue=FALSE" "attr=nTUserDeleteAccount" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP" COLSPAN=2>Crear nueva cuenta NT:</TD>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=S&iacute;" "false=No" "defaultvalue=TRUE" "attr=nTUserCreateNewAccount" -->
+</B></TD></TR>
+
+<!-- ENDIF // Adding -->
+
+<!-- IF "Displaying" -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Comentario del usuario NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUsrComment" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Identificador exclusivo usuario NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUniqueId" "syntax=binvalue" "cols=>10" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Caducidad contrase&ntilde;a NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=S&iacute;" "false=No" "defaultvalue=FALSE" "attr=nTUserPasswordExpired" -->
+</B></TD>
+<TD VALIGN="TOP">N&ordm; de contrase&ntilde;as err&oacute;neas NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserBadPwCount" "syntax=binvalue" "options=decimal" "cols=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">&Uacute;ltima fecha de entrada NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogon" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>&Uacute;ltima fecha de salida NT</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogoff" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Fecha de caducidad cuenta NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserAcctExpires" "syntax=time" "defaultvalue=Never Expires" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>N&ordm; de accesos NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserNumLogons" "syntax=binvalue" "options=decimal" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Servidor de acceso NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLogonServer" "defaultvalue=Any Server" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Estaciones NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserWorkstations" "defaultvalue=No Restrictions" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">P&aacute;g. de c&oacute;digos NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserCodePage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>C&oacute;gido de pa&iacute;s NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserCountryCode" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Identif. grupo principal NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserPrimaryGroupId" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Perfil NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserProfile" "defaultvalue=Default" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Directorio principal NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDir" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP">Unidad directorio ppal. NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDirDrive" "defaultvalue=None" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>V&iacute;a de acceso a gui&oacute;n NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserScriptPath" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Almacenamiento m&aacute;x. NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserMaxStorage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Unidades NT por semana</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUnitsPerWeek" "syntax=binvalue" "options=decimal" "cols=>6" -->
+</B></TD>
+<TD VALIGN="TOP">Privilegios de usuario NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserPriv" "syntax=binvalue" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Privilegios de operador usuario NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserAuthFlags" "syntax=binvalue" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP">Funciones varias cta. usuario NT:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserFlags" "syntax=binvalue" "cols=>16" -->
+</B></TD></TR>
+<!-- ENDIF // Displaying -->
+</TABLE>
+&nbsp;
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informaci&oacute;n sobre actividad profesional y ubicaci&oacute;n</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Categor&iacute;a comercial:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</B></TD>
+<TD VALIGN="TOP">Cargo:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Departamento:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</B></TD>
+<TD VALIGN="TOP">Responsable:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dneditpeople" "attr=manager" "desc=Manager" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>Tiene que guardar esta entrada para poder modificar este campo.</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">N&ordm; de despacho</TD>
+<TD VALIGN="TOP" NOWRAP"><B>
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</B></TD>
+</B><TD VALIGN="TOP">Admin.:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dneditpeople" "attr=secretary" "desc=Admin." -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</B></TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP">N&ordm; de dpto.:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP">N&ordm; empleado:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</B></TD></TR>
+<TR>
+<TD VALIGN="TOP">C. identidad/pasaporte:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</B></TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+<TR>
+<TD VALIGN="TOP">Direcci&oacute;n postal:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+</TABLE>
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=2><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informaci&oacute;n adicional</TD>
+</TR>
+<TR>
+<TD VALIGN="TOP">Descripci&oacute;n:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+<TR>
+<TD VALIGN="TOP">Ver tambi&eacute;n:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>Tiene que guardar esta entrada para poder modificar este campo.</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TR>
+<TR>
+<TD VALIGN="TOP">P&aacute;gina web:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</B></TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP">Identificador exclusivo:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</B></TR>
+-->
+</TABLE>
+<!-- IF "!Adding" -->
+Esta entrada fue modificada por &uacute;ltima vez el <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> por <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/es/display-org.html b/ldap/clients/dsgw/config/es/display-org.html
new file mode 100644
index 00000000..7abf3677
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-org.html
@@ -0,0 +1,135 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organization" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nueva
+<!-- ENDIF // Adding -->
+Empresa:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=organization.gif" ALT="Empresa" HSPACE=5>
+<TD>
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nueva empresa:
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Modificar empresa" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Guardar nueva empresa." -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancelar" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORG" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORG" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Cambiar nombre empresa" "prompt=Escriba otro nombre para esta empresa:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Borrar empresa" "prompt=&#191;Desea borrar esta empresa?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organization">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>El asterisco (*) indica los campos obligatorios</B><BR>
+<!-- ENDIF -->
+
+<TABLE>
+<TR>
+<TD VALIGN="TOP" NOWRAP>Nombre de la empresa:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=o" "cols=>20" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD>Descripci&oacute;n:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</B></TR>
+
+<TR><TD>Tel&eacute;fono:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD NOWRAP>Categor&iacute;a comercial:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</B></TD></TR>
+
+<TR><TD>Fax:<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD>Direcci&oacute;n:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Direcci&oacute;n postal:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Ver tambi&eacute;n:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Esta entrada fue modificada por &uacute;ltima vez el <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> por <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/display-orgperson.html b/ldap/clients/dsgw/config/es/display-orgperson.html
new file mode 100644
index 00000000..7dbdd12f
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-orgperson.html
@@ -0,0 +1,342 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- inet. organizational person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nueva
+<!-- ENDIF // Adding -->
+Entrada personal:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Persona (haga clic para ver la tarjeta)"
+ BORDER=0 HSPACE=5>
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nueva persona:
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-ca-cert" -->
+>Recibir certificado</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Reproducir fragmento de sonido</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="Ver tarjeta" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Modificar persona" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Guardar nueva persona" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancelar" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Cambiar contrase&ntilde;a" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Cambiar nombre de persona" "prompt=Escriba otro nombre para esta persona:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Borrar persona" "prompt=&#191;Desea borrar los datos de esta persona?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<B>El asterisco (*) indica los campos obligatorios</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informaci&oacute;n de contacto</TD>
+</TR>
+
+<TD VALIGN="top" NOWRAP>Nombre:</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</B></TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2">Nombre y apellidos:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2"><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>Apellidos:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Contrase&ntilde;a:</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</B></TD>
+<TD> Repetir la contrase&ntilde;a para confirmarla:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">Tel&eacute;fono:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Direcci&oacute;n electr&oacute;nica:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Fax:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Identificador de usuario:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+<TR>
+<TD VALIGN="TOP" NOWRAP>Buscapersonas:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Tel&eacute;fono m&oacute;vil:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informaci&oacute;n sobre actividad comercial y ubicaci&oacute;n</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Categor&iacute;a comercial:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</B></TD>
+<TD VALIGN="TOP">Cargo:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Departamento:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</B></TD>
+<TD VALIGN="TOP">Responsable:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dneditpeople" "attr=manager" "desc=Responsable" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>Tiene que guardar esta entrada para poder modificar este campo.</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">N&ordm; de despacho:</TD>
+<TD VALIGN="TOP" NOWRAP"><B>
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</B></TD>
+</B><TD VALIGN="TOP">Admin.:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dneditpeople" "attr=secretary" "desc=Admin." -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</B></TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP">N&ordm; de dpto.:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP">N&ordm; empleado:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">C. identidad/pasaporte:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</B></TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Direcci&oacute;n postal:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=2><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informaci&oacute;n adicional</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Descripci&oacute;n:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Ver tambi&eacute;n:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=seeAlso" "desc=Ver tambi&eacute;n" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>Tiene que guardar esta entrada para poder modificar este campo.</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">P&aacute;gina web:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</B></TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP">Identificador exclusivo:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</B></TR>
+-->
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+Esta entrada fue modificada por &uacute;ltima vez el <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> por <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/display-orgunit.html b/ldap/clients/dsgw/config/es/display-orgunit.html
new file mode 100644
index 00000000..038d43ef
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-orgunit.html
@@ -0,0 +1,135 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organizationalUnit" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nuevo
+<!-- ENDIF // Adding -->
+Departamento:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgunit.gif" ALT="Departamento" HSPACE=5>
+<TD>
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nuevo Departamento:
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Modificar departamento" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Guardar nuevo dpto." -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancelar" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGUNIT" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGUNIT" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Cambiar nombre dpto." "prompt=Escriba otro nombre para este departamento:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Borrar departamento" "prompt=&#191;Desea borrar este departamento?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalUnit">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>El asterisco (*) indica los campos obligatorios.</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE>
+<TR>
+<TD>Nombre del dpto.:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>20" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD>Descripci&oacute;n:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</B></TR>
+
+<TR><TD>Tel&eacute;fono:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD NOWRAP>Categor&iacute;a comercial:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</B></TD></TR>
+
+<TR><TD>Fax:<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD>Direcci&oacute;n:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Direcci&oacute;n postal:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Ver tambi&eacute;n:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Esta entrada fue modificada por &uacute;ltima vez el <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> por <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/display-person.html b/ldap/clients/dsgw/config/es/display-person.html
new file mode 100644
index 00000000..e7d0409a
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/display-person.html
@@ -0,0 +1,229 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- person directory entry -->
+<!-- DS_OBJECTCLASS "value=person" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nueva
+<!-- ENDIF // Adding -->
+Entrada personal:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Persona (haga clic para ver la tarjeta)"
+ BORDER=0 HSPACE=5>
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nueva persona:
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="Ver tarjeta" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Modificar persona" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Guardar nueva persona" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancelar" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_PERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_PERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Cambiar contrase&ntilde;a" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Cambiar nombre de persona" "prompt=Escriba otro nombre para esta persona:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Borrar persona" "prompt=&#191;Desea borrar los datos de esta persona?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>El asterisco (*) indica los campos obligatorios</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD VALIGN="top" NOWRAP>Apellidos:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="top" NOWRAP>Nombre y apellidos:</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR><TD COLSPAN="5"><HR></TD></TR>
+<TR>
+<TD>Contrase&ntilde;a:</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD><TD WIDTH="20%"></TD>
+<TD> Repita la contrase&ntilde;a para confirmarla:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+<TR><TD COLSPAN="5"><HR></TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">Tel&eacute;fono:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Direcci&oacute;n electr&oacute;nica:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Fax:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>User ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+<TR>
+<TD VALIGN="TOP" NOWRAP>Buscapersonas:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Tel&eacute;fono m&oacute;vil:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Cargo:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Direcci&oacute;n postal:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Descripci&oacute;n:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Ver tambi&eacute;n:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modificar..." "template=dnedit" "attr=seeAlso" "desc=Ver tambi&eacute;n" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4">
+<!-- IF "Adding" -->
+<I>Tiene que guardar esta entrada para poder modificar el campo.</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">P&aacute;gina web:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Bebida favorita:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=drink" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+Esta entrada fue modificada por &uacute;ltima vez el <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> por <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/dsgw-l10n.conf b/ldap/clients/dsgw/config/es/dsgw-l10n.conf
new file mode 100644
index 00000000..0482312b
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/dsgw-l10n.conf
@@ -0,0 +1,18 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# Note: the sample part should have double #'s for L10n.
+## translate People <People_translated_in_lang>
+## translate NT-People <NT-People_translated_in_lang>
+## translate Groups <Groups_translated_in_lang>
+## translate NT-Groups <NT-Groups_translated_in_lang>
+## translate Organizations <Organizations_translated_in_lang>
+## translate Org-Units <Org-Units_translated_in_lang>
+## translate Anything <Anything_translated_in_lang>
diff --git a/ldap/clients/dsgw/config/es/dsgw.tmpl b/ldap/clients/dsgw/config/es/dsgw.tmpl
new file mode 100644
index 00000000..47360e0a
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/dsgw.tmpl
@@ -0,0 +1,116 @@
+# The htmldir directive tells the CGIs where to find the html files
+htmldir ../html
+
+# The configdir directive tells the CGIs where to find the
+# templates/configuration files
+configdir ../config
+
+# The gwnametrans directive tells the CGIs what url to output
+# for http redirection. It should be the same nameTrans set
+# in the webserver, if any is being is used.
+gwnametrans /clients/dsgw/html/
+
+# The authlifetime directive specifies how long authentication credentials
+# are valid (in seconds).
+authlifetime 7200
+
+# The libNLS data directory. This directory should contain a directory
+# named "locales", which contains the configuration files LANG.ctx and
+# LANG.txt for each supported language (locale).
+NLS ../../../lib/nls
+
+# The default character set, for communication with HTTP clients.
+# A client may override this default, using an HTTP Accept-Charset header.
+# Or, this default may be overridden for a specific language, by creating
+# a LANG/dsgwcharset.conf file which contains the charset name.
+# For compatibility with HTTP clients that can't handle an HTTP response
+# with a charset parameter in the content-type, comment out this directive;
+# responses will be sent in ISO-8859-1, with no explicit charset parameter.
+# RFC 1345 defines the syntax of charset names. There is a registry of
+# charsets, at ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+# charset UTF-8
+
+# Substitute ideographic space for non-breaking space in Asian charsets:
+changeHTML "  " " " Shift_JIS Big5 EUC-KR
+changeHTML " " " " Shift_JIS Big5 EUC-KR
+
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using ds/templateindex. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template ntgroup groupOfUniqueNames ntGroup
+template groupun groupOfUniqueNames
+template org organization
+template orgunit organizationalUnit
+template ntperson person inetOrgPerson nTUser
+template orgperson person inetOrgPerson
+template person person
+template country country
+
+#
+# The remainder of this file contains information about the locations and
+# types for new entries.
+#
+# "location" lines define places in the directory where new entries can be added
+# The format of each line is:
+# location HANDLE FRIENDLYNAME DN
+# where HANDLE is a short name which is used in the "newtype" lines (see below)
+# and FRIENDLYNAME is a human-readable name for the location
+# and DN is the Distinguished Name for this location (if it does not end with
+# '#', the location-suffix is appended to to construct a full DN; if it
+# does end with `#', it assumed to be a full DN and the `#' is removed).
+#
+location country "Espa&ntilde;a" "c=ES#"
+location org "Esta empresa" ""
+location groups "Grupos" "ou=Groups"
+location people "Personas" "ou=People"
+location special "Usuarios especiales" "ou=Special Users"
+
+# "newtype" lines define the types of new entries that may be added
+# The format of each line is:
+# newtype TEMPLATENAME FRIENDLYNAME RDNATTR LOCATIONS...
+# where TEMPLATENAME corresponds to an existing display-TEMPLATENAME.html file
+# and FRIENDLYNAME is a human-readable name for this type of entry
+# and RDNATTR is the attribute that is used to name entries of this type
+# and LOCATIONS is a blank-separated list of locations where these types of
+# entries can be added (corresponding to a HANDLE on a "location"
+# config. file line).
+#
+newtype orgperson "Persona" uid people special
+newtype ntperson "Persona NT" uid people special
+newtype ntgroup "Grupo NT" cn groups
+newtype groupun "Grupo" cn groups
+newtype orgunit "Departamento" ou people org
+newtype org "Empresa" o country
+
+# Mappings between VCard properties and LDAP attribute types:
+# The format of each line is:
+# vcard-property VCARDPROP SYNTAX LDAPATTR [LDAPATTR2]
+# where VCARDPROP is the name of a VCard property
+# and SYNTAX is "cis" for simple strings and "mls" for multiline strings
+# and LDAPATTR is the LDAP attribute that corresponds to VCARDPROP
+# and LDAPATTR2 is an optional secondary LDAP attribute which is added to
+# the property value by appending a semicolon and then the attr2 value.
+vcard-property FN cis cn
+vcard-property N cis sn givenName
+vcard-property ORG cis o ou
+vcard-property ROLE cis businessCategory
+vcard-property ADR;WORK mls postalAddress
+vcard-property ADR;HOME mls homePostalAddress
+vcard-property EMAIL;INTERNET cis mail
+vcard-property TITLE cis title
+vcard-property TEL;WORK cis telephoneNumber
+vcard-property TEL;FAX cis facsimileTelephoneNumber
+vcard-property TEL;CELL cis mobile
+vcard-property TEL;HOME cis homePhone
+vcard-property NOTE cis description
diff --git a/ldap/clients/dsgw/config/es/dsgw_adm.conf b/ldap/clients/dsgw/config/es/dsgw_adm.conf
new file mode 100644
index 00000000..ff662a46
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/dsgw_adm.conf
@@ -0,0 +1,46 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using the templateindex program. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template groupun groupOfUniqueNames
+template org organization
+template orgunit organizationalUnit
+template orgperson person inetOrgPerson
+template person person
+template country country
+template licensed-user nsLicenseUser
+
+# Attribute Value Sets (used with DS_ATTRVAL_SET directives)
+# attrvset HANDLE VALUE PREFIX SUFFIX
+#
+attrvset CAL news "" "Netscape Collabra Server"
+attrvset CAL slapd "" "Netscape Directory Server"
+
+
+# Template Set definitions
+# Note: templates must be defined before they can be mentioned on
+# a tmplset line.
+#
+# tmplset SETNAME VIEWNAME TEMPLATENAME [HREF-LOCATION]
+#
+tmplset person "General" orgperson
+tmplset person "Contrase&ntilde;a" passwd
+tmplset person "Licencia" licensed-user
+tmplset group "General" group
+tmplset groupun "General" groupun
diff --git a/ldap/clients/dsgw/config/es/dsgwfilter.conf b/ldap/clients/dsgw/config/es/dsgwfilter.conf
new file mode 100644
index 00000000..735facec
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/dsgwfilter.conf
@@ -0,0 +1,139 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example:
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "LDAP filtro es"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "n&uacute;mero de tel&eacute;fono termina en"
+
+ "@" " " "(mail=%v))" "direcci&oacute;n electr&oacute;nica es"
+ "(mail=%v*))" "direcci&oacute;n electr&oacute;nica comienza por"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "primera inicial + nombre es"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "nombre + &uacute;ltima inicial es"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "nombre es"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "nombre suena como o contiene"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(uid=*)))" "nombre o identificaci&oacute;n de usuario es"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)(uid=%v1)))" "nombre o identificaci&oacute;n de usuario es"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "nombre suena como o contiene"
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "LDAP filter es"
+
+ "^\*$" " " "(cn=*))" "nombre es"
+
+ ".*" ". _" "(cn=%v1-))" "nombre es"
+ "(cn=*%v1-*))" "nombre contiene"
+ "(cn~=%v1-))" "nombre suena como"
+
+"dsgw-ntgroups"
+ "=" " " "(%v))" "LDAP filter es"
+
+ "^\*$" " " "(cn=*))" "nombre es"
+
+ ".*" ". _" "(cn=%v1-))" "nombre es"
+ "(cn=*%v1-*))" "nombre suena como"
+ "(cn~=%v1-))" "nombre suena como"
+ "(ntgroupdomainid=%v:*))" "Dominio NT nombre es"
+ "(ntgroupdomainid=*:%v))" "Grupo NT es"
+
+"dsgw-organizations"
+ "=" " " "(%v))" "LDAP filter es"
+
+ "\." " " "(associatedDomain=%v))" "Dominio asociado es"
+
+ "^\*$" " " "(o=*))" "nombre es"
+
+ ".*" " " "(o=%v))" "nombre es"
+ "(o=*%v*))" "nombre contiene"
+ "(o~=%v))" "nombre suena como"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "LDAP filter es"
+
+ "\." " " "(associatedDomain=%v))" "Dominio asociado es"
+
+ "^\*$" " " "(ou=*))" "nombre es"
+
+ ".*" " " "(ou=%v))" "nombre es"
+ "(ou=*%v*))" "nombre contiene"
+ "(ou~=%v))" "nombre suena como"
+
+"dsgw-anything"
+ "=" " " "(%v)" "LDAP filter es"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)(o=%v1-)(ou=%v1-))" "nombre es"
+ "(|(sn~=%v1-)(cn~=%v1-)(o=%v1-)(ou=%v1-))" "nombre suena como"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(o=*)(ou=*))" "nombre es"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)(o=%v1)(ou=%v1))" "nombre es"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)(o=%v1)(ou=%v1))" "nombre suena como o contiene"
+
+
+"dsgw-ntpeople"
+ "=" " " "(%v))" "LDAP filter es"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "n&uacute;mero de tel&eacute;fono termina en"
+
+ "@" " " "(mail=%v))" "direcci&oacute;n electr&oacute;nica es"
+ "(mail=%v*))" "direcci&oacute;n electr&oacute;nica comienza por"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "primera inicial + nombre es"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "nombre + &uacute;ltima inicial es"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "nombre es"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "nombre suena como o contiene"
+
+ "^\*$" " " "(|(cn=*)(sn=*)))" "nombre es"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)))" "nombre es"
+ "(ntuserlogonserver=%v))" "Servidor de acceso NT"
+ "(ntuserdomainid=%v:*))" "Dominio NT nombre es"
+ "(ntuserdomainid=*:%v))" "Nombre de usuario NT"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "nombre suena como o contiene"
+
+# Do not remove this line, or place any directives after it.
diff --git a/ldap/clients/dsgw/config/es/dsgwfilter_adm.conf b/ldap/clients/dsgw/config/es/dsgwfilter_adm.conf
new file mode 100644
index 00000000..48eadf05
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/dsgwfilter_adm.conf
@@ -0,0 +1,73 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example (en):
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway - for Netscape Admin Server
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "LDAP filtro es"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "n&uacute;mero de tel&eacute;fono termina en"
+
+ "@" " " "(mail=%v))" "direcci&oacute;n electr&oacute;nica es"
+ "(mail=%v*))" "direcci&oacute;n electr&oacute;nica comienza por"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "primera inicial + nombre es"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "nombre + &uacute;ltima inicial es"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "name is"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "nombre suena como o contiene"
+
+ ".*" ". " "(uid=%v1))" "identificaci&oacute;n de acceso es"
+ "(|(cn=%v1)(sn=%v1)))" "nombre es"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "nombre suena como o contiene"
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "LDAP filter is"
+
+ ".*" ". _" "(cn=%v1-))" "nombre es"
+ "(cn~=%v1-))" "nombre suena como"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "LDAP filtro es"
+
+ ".*" ". _" "(ou=%v1-))" "nombre de la unidad es"
+ "(ou~=%v1-))" "nombre de la unidad suena como"
+
+#Do not remove this line, or place any additional lines after it.
diff --git a/ldap/clients/dsgw/config/es/dsgwsearchprefs.conf b/ldap/clients/dsgw/config/es/dsgwsearchprefs.conf
new file mode 100644
index 00000000..fee61c10
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/dsgwsearchprefs.conf
@@ -0,0 +1,213 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# dsgwsearchprefs.conf - directory server gateway search object definitions
+
+
+# the current version of this file format is 1
+Version 1
+
+
+# Name for this search object
+People
+# options (the only one supported right now is "internal" which means that
+# this search object should not be presented directly to the user)
+# use "" for none
+""
+# Label to place before text box user types in
+"Search For:"
+# Filter prefix to append to all searches
+"(&(objectClass=person)"
+# Tag to use for "Fewer Choices" searches - from ldapfilter.conf file
+"dsgw-people"
+# If a search results in > 1 match, retrieve this attribute to help
+# user disambiguate the entries...
+not-used-by-dsgw
+# ...and label it with this string:
+not-used-by-dsgw
+# Search scope to use when searching
+subtree
+# Follows a list of "More Choices" search options. Format is:
+# Label, attribute, select-bitmap, extra attr display name, extra attr ldap name
+# If last two are null, "Fewer Choices" name/attributes used.
+# Label should begin with the article ("the" in English) for
+# languages that require agreement between article and noun
+# (e.g genders in Spanish or French).
+
+"nombre y apellidos" cn 111111 "" ""
+"apellidos" sn 111111 "" ""
+"número de teléfono" "telephoneNumber" 111011 "" ""
+"dirección electrónica" "mail" 111111 "" ""
+"identificación de usuario" "uid" 111111 "" ""
+"cargo" title 111111 "" ""
+END
+# Match types
+"es" "(%a=%v))"
+"no es" "(!(%a=%v)))"
+"suena como" "(%a~=%v))"
+"comienza por" "(%a=%v*))"
+"termina en" "(%a=*%v))"
+"contiene" "(%a=*%v*))"
+END
+
+
+"NT-People"
+""
+"Search For:"
+"(&(objectClass=ntuser)"
+"dsgw-ntpeople"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nombre y apellidos" cn 111111 "" ""
+"apellidos" sn 111111 "" ""
+"número de teléfono" "telephoneNumber" 111011 "" ""
+"dirección electrónica" "mail" 111111 "" ""
+"identificación de usuario" "uid" 111111 "" ""
+"cargo" title 111111 "" ""
+"Nombre de usuario NT" "ntuserdomainid" 110000 "" ""
+"Dominio NT" "ntuserdomainid" 101000 "" ""
+"Servidor de acceso NT" "ntuserlogonserver" 111111 "" ""
+END
+"es" "(%a=%v))"
+"no es" "(!(%a=%v)))"
+"suena como" "(%a~=%v))"
+"comienza por" "(%a=%v*))"
+"termina en" "(%a=*%v))"
+"contiene" "(%a=*%v*))"
+END
+
+
+Groups
+""
+"Search For:"
+"(&(|(objectClass=rfc822MailGroup)(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfCertificates))"
+"dsgw-groups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nombre" cn 111111 "" ""
+"descripción" description 111111 "" ""
+"propietario (DN)" "owner" 000011 "owner" "Owner"
+"miembro (DN)" "member" 000011 "" ""
+END
+"es" "(%a=%v))"
+"no es" "(!(%a=%v)))"
+"suena como" "(%a~=%v))"
+"comienza por" "(%a=%v*))"
+"termina en" "(%a=*%v))"
+"contiene" "(%a=*%v*))"
+END
+
+NT-Groups
+""
+"Search For:"
+"(&(objectClass=ntGroup)"
+"dsgw-ntgroups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nombre" cn 111111 "" ""
+"Dominio NT" "ntgroupdomainid" 111111 "" ""
+"nombre de grupo NT" "ntgroupdomainid" 111111 "" ""
+"descripción" description 111111 "" ""
+"propietario (DN)" "owner" 000011 "owner" "Owner"
+"miembro (DN)" "uniquemember" 000011 "" ""
+END
+"es" "(%a=%v))"
+"no es" "(!(%a=%v)))"
+"suena como" "(%a~=%v))"
+"comienza por" "(%a=%v*))"
+"termina en" "(%a=*%v))"
+"contiene" "(%a=*%v*))"
+END
+
+
+Organizations
+""
+"Search For:"
+"(&(objectClass=organization)"
+"dsgw-organizations"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nombre" o 111111 "" ""
+"dirección" l 111111 "" ""
+"número de teléfono" telephoneNumber 111011 "" ""
+"descripción" description 111011 "" ""
+END
+"es" "(%a=%v))"
+"no es" "(!(%a=%v)))"
+"suena como" "(%a~=%v))"
+"comienza por" "(%a=%v*))"
+"termina en" "(%a=*%v))"
+"contiene" "(%a=*%v*))"
+END
+
+
+"Org-Units"
+""
+"Search For:"
+"(&(objectClass=organizationalUnit)"
+"dsgw-orgunits"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nombre" ou 111111 "" ""
+"dirección" l 111111 "" ""
+"número de teléfono" telephoneNumber 111011 "" ""
+"descripción" description 111111 "" ""
+END
+"es" "(%a=%v))"
+"no es" "(!(%a=%v)))"
+"suena como" "(%a~=%v))"
+"comienza por" "(%a=%v*))"
+"termina en" "(%a=*%v))"
+"contiene" "(%a=*%v*))"
+END
+
+Anything
+""
+"Search For:"
+""
+"dsgw-anything"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nombre común" cn 111111 "" ""
+"descripción" description 111111 "" ""
+END
+"es" "(%a=%v)"
+"no es" "(!(%a=%v))"
+"suena como" "(%a~=%v)"
+"comienza por" "(%a=%v*)"
+"termina en" "(%a=*%v)"
+"contiene" "(%a=*%v*)"
+END
+
+Auth
+internal
+"Authenticate As:"
+"(&(objectClass=person)"
+"dsgw-people"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nombre común" cn 111111 "" ""
+"apellido" sn 111111 "" ""
+"número de teléfono" "telephoneNumber" 111011 "" ""
+"dirección electrónica" "mail" 111111 "" ""
+"identificación de usuario" "uid" 111111 "" ""
+"cargo" title 111111 "" ""
+END
+"es" "(%a=%v))"
+"no es" "(!(%a=%v)))"
+"suena como" "(%a~=%v))"
+"comienza por" "(%a=%v*))"
+"termina en" "(%a=*%v))"
+"contiene" "(%a=*%v*))"
+END
+
diff --git a/ldap/clients/dsgw/config/es/edit-passwd.html b/ldap/clients/dsgw/config/es/edit-passwd.html
new file mode 100644
index 00000000..83a53661
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/edit-passwd.html
@@ -0,0 +1,78 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- change a directory entry's password -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Cambiar la contrase&ntilde;a:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+</HEAD>
+
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<H2><CENTER>Cambiar la contrase&ntilde;a de
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</H2></CENTER>
+
+<HR>
+
+<P>
+<TABLE>
+
+<!-- IF "BoundAsThisEntry" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+Escriba la contrase&ntilde;a antigua:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ELIF "!Bound" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+Escriba la contrase&ntilde;a antigua:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ENDIF //BoundAsThisEntry -->
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Escriba la nueva:
+</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD></TR>
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Vuelva a escribir la nueva para confirmarla:
+</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+</TABLE>
+
+<P>
+
+<TABLE BORDER=2 WIDTH="100%">
+<TR>
+<TD ALIGN="center" WIDTH="50%">
+<!-- IF "BoundAsThisEntry" -->
+<!-- DS_SAVEBUTTON "label=Cambiar contrase&ntilde;a" -->
+<!-- ELSE -->
+<!-- DS_SAVEBUTTON "label=Definir contrase&ntilde;a" -->
+<!-- ENDIF -->
+<TD ALIGN="center" WIDTH="50%">
+<!-- DS_HELPBUTTON "topic=MODIFYPASSWD" -->
+</TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-Anything.html b/ldap/clients/dsgw/config/es/list-Anything.html
new file mode 100644
index 00000000..40f9e784
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-Anything.html
@@ -0,0 +1,42 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Buscar todo" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nombre <TH NOWRAP>N&uacute;mero de tel&eacute;fono
+<TH NOWRAP>Direcci&oacute;n electr&oacute;nica <TH NOWRAP>Descripci&oacute;n
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Pruebe con otra b&uacute;squeda.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-Auth.html b/ldap/clients/dsgw/config/es/list-Auth.html
new file mode 100644
index 00000000..668b5d75
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-Auth.html
@@ -0,0 +1,73 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Autenticar..." -->
+
+<!--
+ The "authForm" form and the authSubmit() JavaScript function are
+ used to avoid the need for a separate form for each entry listed.
+ Each entry is tied to this single form through the magic of an
+ anchor that contains href=javascript:authSubmit().
+-->
+
+<FORM NAME="authForm" METHOD=POST ACTION="auth">
+<INPUT TYPE="hidden" NAME="escapedbinddn">
+<INPUT TYPE="hidden" NAME="authdesturl"
+<!-- DS_POSTEDVALUE "name=authdesturl" "within=VALUE=%22--value--%22" -->
+>
+<!-- PCONTEXT -->
+</FORM>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function authSubmit(encodeddn)
+{
+ document.authForm.escapedbinddn.value = encodeddn;
+ document.authForm.submit();
+}
+// End hiding -->
+</SCRIPT>
+
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC "VERBOSE" -->
+<P>
+<!-- IF "FoundEntries" -->
+Haga clic en el nombre de la entrada que desee usar para la autenticaci&oacute;n.
+</FONT>
+<P>
+
+<TABLE BORDER=1 CELLPADDING=4>
+<TR>
+<TH NOWRAP>Autenticar como <TH NOWRAP>Cargo
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:authSubmit('--value--'); onMouseOver=%22window.status='Click to authenticate'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+<!-- ELSE "FoundEntries" -->
+Retroceda y vuelva a intentarlo.
+<!-- ENDIF "FoundEntries" -->
+</CENTER>
+
+<FORM>
+<TABLE BORDER=2 WIDTH=100%%>
+<TR>
+<TD ALIGN=center width=50%%>
+<INPUT TYPE="button" VALUE="Retroceder" onClick="history.back();">
+<TD ALIGN=center WIDTH=50%%>
+<!-- DS_HELPBUTTON "topic=AUTHMULTMATCH" -->
+</TABLE>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-Groups.html b/ldap/clients/dsgw/config/es/list-Groups.html
new file mode 100644
index 00000000..e4ffb1ec
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-Groups.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "B&uacute;squeda de grupos" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nombre del grupo
+<TH NOWRAP>Descripci&oacute;n
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Pruebe con otra b&uacute;squeda.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-NT-Groups.html b/ldap/clients/dsgw/config/es/list-NT-Groups.html
new file mode 100644
index 00000000..0258b550
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-NT-Groups.html
@@ -0,0 +1,44 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "B&uacute;squeda de grupos NT" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nombre de grupo LDAP
+<TH NOWRAP>Nombre de dominio NT
+<TH NOWRAP>Nombre de grupo NT
+<TH NOWRAP>Descripci&oacute;n
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntdomain" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntgroupname" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Pruebe con otra b&uacute;squeda.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-NT-People.html b/ldap/clients/dsgw/config/es/list-NT-People.html
new file mode 100644
index 00000000..5897279a
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-NT-People.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "B&uacute;squeda de personas NT" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nombre<TH NOWRAP>Dominio NT<TH NOWRAP>Nombre de usuario<TH NOWRAP>N&uacute;mero de tel&eacute;fono
+</TR>
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "label=" -->
+ onMouseOver="window.status='Haga clic aqu&iacute; para ver esta entrada en detalle'; return true">
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=0" "defaultvalue=name" "options=readonly" -->
+</A>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntdomain" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntuserid" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Pruebe con otra b&uacute;squeda.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-Org-Units.html b/ldap/clients/dsgw/config/es/list-Org-Units.html
new file mode 100644
index 00000000..26cbccdb
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-Org-Units.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for Organizational Units" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Departamento <TH>Descripci&oacute;n <TH>N&uacute;mero de tel&eacute;fono
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Pruebe con otra b&uacute;squeda.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-Organizations.html b/ldap/clients/dsgw/config/es/list-Organizations.html
new file mode 100644
index 00000000..f06f9285
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-Organizations.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "B&uacute;squeda de organizaciones" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Empresa <TH>Descripci&oacute;n <TH>N&uacute;mero de tel&eacute;fono
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Pruebe con otra b&uacute;squeda.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-People.html b/ldap/clients/dsgw/config/es/list-People.html
new file mode 100644
index 00000000..43512b6f
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-People.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "B&uacute;squeda de personas" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nombre<TH NOWRAP>N&uacute;mero de tel&eacute;fono<TH NOWRAP>Direcci&oacute;n electr&oacute;nica<TH NOWRAP>Cargo
+</TR>
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "label=" -->
+ onMouseOver="window.status='Haga clic aqu&iacute; para ver esta entrada en detalle'; return true">
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=0" "defaultvalue=name" "options=readonly" -->
+</A>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Pruebe con otra b&uacute;squeda.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-fa-Groups.html b/ldap/clients/dsgw/config/es/list-fa-Groups.html
new file mode 100644
index 00000000..4e0b6bc7
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-fa-Groups.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Buscar personas" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-fa-People.html b/ldap/clients/dsgw/config/es/list-fa-People.html
new file mode 100644
index 00000000..bbc2e00a
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-fa-People.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/list-urlsearch.html b/ldap/clients/dsgw/config/es/list-urlsearch.html
new file mode 100644
index 00000000..f8503f73
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/list-urlsearch.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "B&uacute;squeda basada en URL" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Nombre <TH>N&uacute;mero de tel&eacute;fono <TH>Direcci&oacute;n electr&oacute;nica
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Pruebe con otra b&uacute;squeda.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/es/newentry.html b/ldap/clients/dsgw/config/es/newentry.html
new file mode 100644
index 00000000..948da868
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/newentry.html
@@ -0,0 +1,26 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentry.html-->
+<TITLE>Pasarela de Netscape Directory Server: Nueva entrada</TITLE>
+<!-- DS_NEWENTRY_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=75,70,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=newentrytitle.html" NORESIZE SCROLLING="NO">
+ <FRAME SRC="newentry?<!-- GCONTEXT -->&file=type"
+ NAME="newentryTypeFrame" SCROLLING="NO">
+ <FRAME SRC="newentry?<!-- GCONTEXT -->&file=name"
+ NAME="newentryNameFrame">
+</FRAMESET>
+
+<NOFRAMES>
+<BODY>
+Tiene que emplear un programa de acceso que admita marcos para poder ver este documento.
+</BODY>
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/config/es/newentryName.html b/ldap/clients/dsgw/config/es/newentryName.html
new file mode 100644
index 00000000..2bb3d545
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/newentryName.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentryName.html-->
+</HEAD>
+<!-- DS_NEWENTRY_NAME_BODY -->
+<p>
+<!-- DS_NEWENTRY_NAME_FORM -->
+<font SIZE="+2">Paso 2.</font>
+D&eacute; un nombre al nuevo
+<!-- EVALUATE "entType.fullname" -->
+.
+<p><nobr><font SIZE="+1">
+<!-- EVALUATE "entType.rdnattr" -->
+=</font>
+<input TYPE="text" NAME="entryname" SIZE="40">
+</nobr>
+<p>
+<font SIZE="+2">Paso 3.</font>
+
+<!-- DS_NEWENTRY_LOCATION_BEGIN -->
+Elija la direcci&oacute;n de directorio de este
+<!-- EVALUATE "entType.fullname" -->
+ o elija Otros e introduzca el nombre un&iacute;voco completo al que debe a&ntilde;adirse esta entrada.
+<p>
+<!-- DS_NEWENTRY_LOCATION_SELECT -->
+<OPTION VALUE="">Otros</OPTION>
+</SELECT>
+<input TYPE="text" NAME="dnsuffix" SIZE="70" onFocus="parent.dnsuffixFocus(this.form)">
+<p>
+<font SIZE="+2">Paso 4.</font>
+<!-- DS_NEWENTRY_LOCATION_END -->
+
+Haga clic en Continuar para abrir el cuadro de la entrada. Modifique la informaci&oacute;n contenida o introduzca nuevos datos y guarde la entrada al terminar.
+<p>
+<center><table BORDER="2" WIDTH="75%">
+<tr><td ALIGN="center" WIDTH="50%">
+<input TYPE="submit" VALUE="Continuar">
+<td ALIGN="center" WIDTH="50%">
+
+<!-- DS_HELP_BUTTON "ADDING" -->
+</table></center></form>
+</body></HTML>
diff --git a/ldap/clients/dsgw/config/es/newentryType.html b/ldap/clients/dsgw/config/es/newentryType.html
new file mode 100644
index 00000000..041c710e
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/newentryType.html
@@ -0,0 +1,14 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!--newentryType.html-->
+<!-- DS_NEWENTRY_TYPE_BODY -->
+<!-- DS_NEWENTRY_TYPE_FORM -->
+<font SIZE="+2">Paso 1.</font>
+Elija el tipo de entrada que desee crear.
+<!-- DS_NEWENTRY_TYPE_SELECT -->
+</form></body></HTML>
diff --git a/ldap/clients/dsgw/config/es/ns-license-schema.conf b/ldap/clients/dsgw/config/es/ns-license-schema.conf
new file mode 100644
index 00000000..bbe5d493
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/ns-license-schema.conf
@@ -0,0 +1,17 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+attribute nsLicensedFor cis
+attribute nsLicenseStartTime cis
+attribute nsLicenseEndTime cis
+
+objectclass nsLicenseUser
+ requires
+ objectClass
+ allows
+ nsLicensedFor
+ nsLicenseStartTime
+ nsLicenseEndTime
diff --git a/ldap/clients/dsgw/config/es/search.html b/ldap/clients/dsgw/config/es/search.html
new file mode 100644
index 00000000..de75b477
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/search.html
@@ -0,0 +1,18 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- search.html -->
+<TITLE>Pasarela de Netscape Directory Server: Standard Search</TITLE>
+<!-- DS_SEARCH_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=75,100,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=searchtitle.html" SCROLLING="NO">
+ <FRAME SRC="search?<!-- GCONTEXT -->&file=string" NAME=searchFrame NORESIZE SCROLLING="NO">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=greeting.html" NAME=outputFrame>
+</FRAMESET>
+</HTML>
diff --git a/ldap/clients/dsgw/config/es/searchString.html b/ldap/clients/dsgw/config/es/searchString.html
new file mode 100644
index 00000000..6320c0c6
--- /dev/null
+++ b/ldap/clients/dsgw/config/es/searchString.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- searchString.html -->
+</HEAD>
+<!-- DS_SEARCH_BODY -->
+<!-- DS_SEARCH_FORM "target=outputFrame" -->
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
+<TR><TH ALIGN=RIGHT>Buscar:</TH><TD>
+<!-- DS_SEARCH_TYPE -->
+</TD>
+<TH>en:</TH><TD>
+<!-- DS_SEARCH_BASE -->
+</TD></TR>
+<TR><TH ALIGN=RIGHT>Buscar esto: </TH>
+<TD COLSPAN=3>
+<INPUT NAME="searchstring" SIZE=30>
+<INPUT TYPE="SUBMIT" VALUE="Buscar">&nbsp;&nbsp;
+<!-- DS_HELP_BUTTON "SMARTSEARCH" -->
+</TD></TR>
+</TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM></BODY></HTML>
diff --git a/ldap/clients/dsgw/config/fr/authPassword.html b/ldap/clients/dsgw/config/fr/authPassword.html
new file mode 100644
index 00000000..cb42da31
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/authPassword.html
@@ -0,0 +1,29 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authPassword.html-->
+<TITLE>Authentification...</TITLE>
+<!-- DS_AUTH_PASSWORD_SCRIPT -->
+</HEAD>
+
+<!-- DS_AUTH_PASSWORD_BODY -->
+<!-- DS_AUTH_PASSWORD_INFO -->
+<!-- DS_AUTH_PASSWORD_FORM -->
+<P>
+Mot de passe pour <b>
+<!-- DS_AUTH_PASSWORD_NAME -->
+</b>: <INPUT NAME="password" TYPE="password" SIZE=16>
+<P>
+<CENTER>
+<TABLE BORDER=2 WIDTH=100%>
+<TR>
+<!-- DS_AUTH_PASSWORD_BUTTONS -->
+</TABLE>
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/fr/authSearch.html b/ldap/clients/dsgw/config/fr/authSearch.html
new file mode 100644
index 00000000..123e13ba
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/authSearch.html
@@ -0,0 +1,34 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authSearch.html-->
+<TITLE>Authentification...</TITLE>
+<!-- DS_AUTH_SEARCH_SCRIPT -->
+</HEAD>
+<!-- DS_AUTH_SEARCH_BODY -->
+<!-- DS_AUTH_SEARCH_INFO -->
+<!-- DS_AUTH_SEARCH_FORM -->
+Vous devez d'abord vous identifier avant de pouvoir authentifier votre
+acc&egrave;s au syst&egrave;me. <br>Veuillez entrer votre nom :
+<!-- DS_AUTH_SEARCH_NAME -->
+<P>
+<CENTER>
+<TABLE BORDER=1 WIDTH=100%%>
+<TR>
+<!-- DS_AUTH_SEARCH_BUTTONS -->
+</TABLE>
+</FORM>
+<P>
+<!-- DS_AUTH_AS_ROOT_FORM -->
+<INPUT TYPE="submit" VALUE="Authentifier en tant que gestionnaire d'annuaires">&nbsp;(seuls les administrateurs d'annuaires y ont acc&egrave;s)
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/fr/csearch.html b/ldap/clients/dsgw/config/fr/csearch.html
new file mode 100644
index 00000000..04851ccf
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/csearch.html
@@ -0,0 +1,23 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearch.html-->
+<TITLE>Netscape Directory Server Gateway : Advanced Search </TITLE>
+<!-- DS_CSEARCH_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=75,70,70,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=csearchtitle.html" SCROLLING="NO">
+ <FRAMESET COLS="35%,42%,*" BORDER=0>
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=type" NAME="searchTypeFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=attr" NAME="searchAttrFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=match" NAME="searchMatchFrame" NORESIZE SCROLLING="NO">
+ </FRAMESET>
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=string" NAME="searchStringFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=emptyFrame.html" NAME="outputFrame">
+</FRAMESET>
+</HTML>
diff --git a/ldap/clients/dsgw/config/fr/csearchAttr.html b/ldap/clients/dsgw/config/fr/csearchAttr.html
new file mode 100644
index 00000000..592aa92d
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/csearchAttr.html
@@ -0,0 +1,17 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchAttr.html-->
+</HEAD>
+<!-- DS_CSEARCH_ATTR_BODY -->
+<!-- DS_CSEARCH_ATTR_FORM -->
+<table>
+<tr VALIGN=BASELINE><td ALIGN=RIGHT>où :</td><td>
+<!-- DS_CSEARCH_ATTR_SELECT -->
+</td></tr>
+</table></form></body></HTML>
diff --git a/ldap/clients/dsgw/config/fr/csearchBase.html b/ldap/clients/dsgw/config/fr/csearchBase.html
new file mode 100644
index 00000000..5792cc72
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/csearchBase.html
@@ -0,0 +1,17 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchBase.html-->
+</HEAD>
+<!-- DS_CSEARCH_BASE_BODY -->
+<table>
+<tr VALIGN=CENTER><th>dans:</th><td>
+<!-- EVALUATE "parent.UFNsearchBase" -->
+</td>
+</table>
+</body></HTML>
diff --git a/ldap/clients/dsgw/config/fr/csearchString.html b/ldap/clients/dsgw/config/fr/csearchString.html
new file mode 100644
index 00000000..9c708ce4
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/csearchString.html
@@ -0,0 +1,28 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchString.html-->
+</HEAD>
+<!-- DS_CSEARCH_STRING_BODY -->
+<!-- DS_CSEARCH_STRING_FORM "target=outputFrame" -->
+<TABLE>
+<TR VALIGN=CENTER><TD>
+<INPUT NAME="searchstring" SIZE=20></TD>
+<TD><NOBR>
+<INPUT TYPE="SUBMIT" VALUE="Rechercher">
+<!-- DS_HELP_BUTTON "ASEARCH" -->
+</NOBR></TD>
+<td>&nbsp;</td><th>dans :</th><td>
+<!-- EVALUATE "parent.UFNsearchBase" -->
+</td>
+</TR></TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/config/fr/csearchType.html b/ldap/clients/dsgw/config/fr/csearchType.html
new file mode 100644
index 00000000..d018015e
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/csearchType.html
@@ -0,0 +1,18 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchType.html-->
+</HEAD>
+<!-- DS_CSEARCH_TYPE_BODY -->
+<!-- DS_CSEARCH_TYPE_FORM -->
+<table>
+<tr VALIGN=BASELINE><th ALIGN=RIGHT>Rechercher :</th><td>
+<!-- DS_CSEARCH_TYPE_SELECT -->
+</td></tr>
+</table>
+</form></body></HTML>
diff --git a/ldap/clients/dsgw/config/fr/display-country.html b/ldap/clients/dsgw/config/fr/display-country.html
new file mode 100644
index 00000000..e4782bbc
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-country.html
@@ -0,0 +1,54 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=country" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Pays -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<TABLE>
+<TR><TD NOWRAP>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=country.gif" ALT="Country" HSPACE=5>
+</TD><TD><FONT SIZE="+2">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE CELLSPACING="5">
+
+<TR><TD VALIGN="TOP" NOWRAP>Nom de pays :</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=co" "options=sort" -->
+</B></TD><TD WIDTH="20%"></TD>
+</B><TD VALIGN="TOP">Description:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP">Voir &eacute;galement :</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL :</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" -->
+</B></TD></TR>
+
+</TABLE>
+
+<HR>
+
+La derni&egrave;re modification de cette entr&eacute;e date du <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/display-dnedit.html b/ldap/clients/dsgw/config/fr/display-dnedit.html
new file mode 100644
index 00000000..500b7b1f
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-dnedit.html
@@ -0,0 +1,76 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Edition
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY "onLoad='document.searchForm.searchstring.focus();'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffixe=</FONT><HR>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<!-- PCONTEXT -->
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+
+<FONT SIZE="+2">
+Edition
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<TABLE CELLSPACING=0 CELLPADDING=0><TR>
+
+<TD NOWRAP>
+Rechercher
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">les utilisateurs
+<OPTION VALUE="Groups">les groupes
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+correspondant &eacute;&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<!-- DS_DNADDBUTTON "VALUE= Rechercher et Ajouter " -->
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= Rechercher et Supprimer " -->
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Enregistrer les modifications " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Annuler " onClick="parent.cancel();">
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON "topic=EDIT_GROUPMEM" -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/display-dneditpeople.html b/ldap/clients/dsgw/config/fr/display-dneditpeople.html
new file mode 100644
index 00000000..e57ab922
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-dneditpeople.html
@@ -0,0 +1,77 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Modification
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY "onLoad='document.searchForm.searchstring.focus();'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffixe=</FONT><HR>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<!-- PCONTEXT -->
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+
+<FONT SIZE="+2">
+Modification
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<TABLE CELLSPACING=0 CELLPADDING=0><TR>
+
+<TD NOWRAP>
+Rechercher
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">l'utilisateur
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+correspondant &eacute;&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+
+<TD>
+<!-- DS_DNADDBUTTON "VALUE= Rechercher et Ajouter ">
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= Rechercher et Supprimer ">
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Enregistrer les modifications " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" Annuler " onClick="parent.cancel();">
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON "topic=EDIT_PERSON_REF" -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/fr/display-group.html b/ldap/clients/dsgw/config/fr/display-group.html
new file mode 100644
index 00000000..80a936c6
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-group.html
@@ -0,0 +1,150 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+Entr&eacute;e de groupe
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Groupe" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouveau groupe -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Modifier le groupe" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregistrer le nouveau groupe" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Annuler" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer le groupe" "prompt=Entrer un nouveau nom pour ce groupe :" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer le groupe" "prompt=Supprimer ce groupe ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfNames">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* Indique une zone d'entr&eacute;e obligatoire</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>Nom :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>Description :</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Propri&eacute;taire :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=owner" "desc=Propri&eacute;taire " -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Voir &eacute;galement :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=seeAlso" "desc=Voir &eacute;galement" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>Vous devez enregistrer cette entr&eacute;e pour pouvoir modifier ces champs.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">Membres du groupe :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=uniquemember" "desc=Membres du groupe :" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+La derni&egrave;re modification de cette entr&eacute;e date du
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
+
diff --git a/ldap/clients/dsgw/config/fr/display-groupun.html b/ldap/clients/dsgw/config/fr/display-groupun.html
new file mode 100644
index 00000000..71451965
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-groupun.html
@@ -0,0 +1,150 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfUniqueNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+Entr&eacute;e de groupe
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Groupe" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouveau groupe -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Modifier le groupe" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregistrer le nouveau groupe" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Annuler" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer le groupe" "prompt=Entrer un nouveau nom pour ce groupe :" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer le groupe" "prompt=Supprimer ce groupe ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- PCONTEXT -->
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* Indique une zone d'entr&eacute;e obligatoire</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>Nom :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>Description :</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Propri&eacute;taire :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=owner" "desc=Propri&eacute;taire " -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Voir &eacute;galement :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=seeAlso" "desc=Voir &eacute;galement" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>Vous devez enregistrer cette entr&eacute;e pour pouvoir modifier ces champs.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">Membres du groupe :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=uniquemember" "desc=Membres du groupe :" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+La derni&egrave;re modification de cette entr&eacute;e date du
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/display-mailgroup.html b/ldap/clients/dsgw/config/fr/display-mailgroup.html
new file mode 100644
index 00000000..a258bc68
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-mailgroup.html
@@ -0,0 +1,125 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=rfc822mailgroup" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+entrȨe de groupe de courrier -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Groupe" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouveau groupe de courrier
+<!-- ENDIF // Adding -->
+
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edition du groupe" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregister le nouveau groupe" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Supprimer" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_MAILGROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_MAILGROUP" -->
+<!-- ENDIF // Adding -->
+
+<!-- IF "Editing" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer le groupe" "prompt=Entrer un nouveau nom pour ce groupe :" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer le groupe" "prompt=Supprimer ce groupe ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="rfc822mailgroup">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+
+<HR>
+
+<TABLE CELLSPACING="5">
+
+<TR><TD VALIGN="TOP">Nom :</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="TOP">Description :</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=multilineDescription" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP">Propri&eacute;taire :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP" NOWRAP>Voir &eacute;galement :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD NOWRAP COLSPAN="2">
+<!-- DS_ATTRIBUTE "attr=joinable" "syntax=bool" "type=radio" "true=Permettre Èá d'autres utilisateurs de se joindre" "false=Refuser Èá d'autres utilisateurs de se joindre" "defaultvalue=FALSE" -->
+</TD><TD></TD><TD NOWRAP COLSPAN="2">
+<!-- DS_ATTRIBUTE "attr=suppressNoEmailError" "syntax=bool" "type=radio" "true=Supprimer les erreurs 'Pas d'adresse &eacute;lectronique'" "false=Retour des erreurs 'Pas d'adresse &eacute;lectronique' Errors" "defaultvalue=FALSE" -->
+</TD></TR>
+
+<HR>
+
+<TR><TD VALIGN="TOP" NOWRAP>Membres du groupe :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=member" "syntax=dn" "numfields=+4" "options=sort" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP" NOWRAP>Membres de courrier &eacute;lectronique :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "numfields=+4" "cols=>30" "options=tri" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+La derni&egrave;re modification de cette entr&eacute;e date du <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedTime" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedBy" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/fr/display-ntgroup.html b/ldap/clients/dsgw/config/fr/display-ntgroup.html
new file mode 100644
index 00000000..3e74b5aa
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-ntgroup.html
@@ -0,0 +1,218 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=ntGroup" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+Entr&eacute;e du groupe NT -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="Groupe" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouveau groupe NT -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Modifier le groupe NT" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregistrer le nouveau groupe" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Annuler" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTGROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTGROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer le groupe NT" "prompt=Entrer un nouveau nom pour ce groupe :" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer le groupe NT" "prompt=Supprimer ce groupe ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="ntGroup">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* Indique une zone d'entr&eacute;e obligatoire</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>Nom :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>Nom du groupe NT :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" "options=readonly" "defaultvalue=none" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" "defaultvalue=none" -->
+<!-- ENDIF // Adding -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Type de groupe NT :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "options=readonly" "cols=>16" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Domaine du groupe NT :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntdomain" "cols=>16" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Description :</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Lieu :</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>Service de la soci&eacute;t&eacute; :</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Propri&eacute;taire :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=owner" "desc=Propri&eacute;taire" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">Voir &eacute;galement :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=seeAlso" "desc=Voir &eacute;galement" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>Vous devez enregistrer cette entr&eacute;e pour pouvoir modifier ces champs.</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">Membres du groupe NT :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=uniquemember" "desc=Membres du groupe NT :" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Supprimer le groupe NT si le groupe est supprim&eacute; :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Oui" "false=Non" "defaultvalue=FALSE" "attr=nTGroupDeleteGroup" -->
+</B></TD><TD></TD>
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP">Cr&eacute;er un nouveau groupe NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Oui" "false=Non" "defaultvalue=TRUE" "attr=nTGroupCreateNewGroup" -->
+</B></TD><TD></TD></TR>
+
+<!-- ENDIF // Adding -->
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+La derni&egrave;re modification de cette entr&eacute;e date du
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
+
diff --git a/ldap/clients/dsgw/config/fr/display-ntperson.html b/ldap/clients/dsgw/config/fr/display-ntperson.html
new file mode 100644
index 00000000..1e7bea60
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-ntperson.html
@@ -0,0 +1,508 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- NT User person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson,nTUser" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+Entr&eacute;e de personne NT-
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Personne (cliquez pour afficher la carte)"
+ BORDER=0 HSPACE=5>
+
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouvelle personne NT
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-ca-cert" -->
+>Download Certificate</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Play Audio Clip</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="Afficher la carteA" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Edition de la personne NT" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregistrer la nouvelle personne NT" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Annuler" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Modification du mot de passe d'annuaire" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer la personne" "prompt=Entrer un nouveau nom pour cette personne :" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer la personne" "prompt=Supprimer cette personne ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nTUser">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* Indique une zone d'entr&eacute;e obligatoire</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Contacts </TD>
+</TR>
+
+<TD VALIGN="top" NOWRAP>Pr&eacute;nom :</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</B></TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2">Nom complet :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2"><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>Nom de famille :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Mot de passe du Directory Server :</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</B></TD>
+<TD> Retaper le mot de passe pour confirmation</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">T&eacute;l&eacute;phone :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Adresse &eacute;lectronique :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">T&eacute;l&eacute;copie :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Id utilisateur :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>T&eacute;l&eacute;avertisseur :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>T&eacute;l&eacute;phone mobile :<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+</TABLE>
+
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informations sur le compte Windows NT</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Id utilisateur NT :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" "options=readonly" -->
+<!-- ENDIF // Adding -->
+<!-- IF "Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Nom de domaine NT :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntdomain" "cols=>16" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP>Supprimer le compte NT si la personne est supprim&eacute;e</TD>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Oui" "false=Non" "defaultvalue=FALSE" "attr=nTUserDeleteAccount" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP" COLSPAN=2>Cr&eacute;er un nouveau compte NT</TD>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Oui" "false=Non" "defaultvalue=TRUE" "attr=nTUserCreateNewAccount" -->
+</B></TD></TR>
+
+<!-- ENDIF // Adding -->
+
+<!-- IF "Displaying" -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Commentaire utilisateur NT</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUsrComment" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Id utilisateur NT unique :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUniqueId" "syntax=binvalue" "cols=>10" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Mot de passe NT p&eacute;rim&eacute; :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Oui" "false=Non" "defaultvalue=FALSE" "attr=nTUserPasswordExpired" -->
+</B></TD>
+<TD VALIGN="TOP">Compte de mots de passe NT incorrect :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserBadPwCount" "syntax=binvalue" "options=decimal" "cols=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Derni&egrave;re date de connexion au syst&egrave;me NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogon" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Derni&egrave;re date de d&eacute;connexion du syst&egrave;me NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogoff" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Date d'expiration du compte NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserAcctExpires" "syntax=time" "defaultvalue=Never Expires" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Nombre de connexions NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserNumLogons" "syntax=binvalue" "options=decimal" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Serveur de connexions NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLogonServer" "defaultvalue=Any Server" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Postes de travail NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserWorkstations" "defaultvalue=No Restrictions" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Page de codes NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserCodePage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Code de pays NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserCountryCode" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Id de groupe principal NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserPrimaryGroupId" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Profil NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserProfile" "defaultvalue=Default" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Annuaire personnel NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDir" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP">Lecteur d'annuaire personnel NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDirDrive" "defaultvalue=None" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Chemin script NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserScriptPath" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Mise en m&eacute;moire maximale NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserMaxStorage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Unit&eacute;s NT par semaine :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUnitsPerWeek" "syntax=binvalue" "options=decimal" "cols=>6" -->
+</B></TD>
+<TD VALIGN="TOP">Privil&egrave;ges de l'utilisateur NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserPriv" "syntax=binvalue" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Privil&egrave;ges de l'utilisateur NT :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserAuthFlags" "syntax=binvalue" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP">Diverses fonctions de compte de personne NT : Features:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserFlags" "syntax=binvalue" "cols=>16" -->
+</B></TD></TR>
+
+<!-- ENDIF // Displaying -->
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informations sur l'activit&eacute; et l'emplacement</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Secteur d'activit&eacute; :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</B></TD>
+<TD VALIGN="TOP">Titre :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Unit&eacute; organisationnelle :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</B></TD>
+<TD VALIGN="TOP">Gestionnaire :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dneditpeople" "attr=manager" "desc=Manager" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>Vous devez enregistrer cette entr&eacute;e pour pouvoir modifier ces champs.</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Num&eacute;ro de poste :</TD>
+<TD VALIGN="TOP" NOWRAP"><B>
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</B></TD>
+</B><TD VALIGN="TOP">Admin.:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dneditpeople" "attr=secretary" "desc=Admin." -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</B></TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP">N&deg; de service :</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP">N&deg; d'employ&eacute; :</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">N&deg; de permis de circulation :</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</B></TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Adresse postale :</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=2><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informations suppl&eacute;mentaires</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Description:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Voir &eacute;galement :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Edit..." "template=dnedit" "attr=seeAlso" "desc=See Also" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>Vous devez enregistrer cette entr&eacute;e pour pouvoir modifier ce champ.</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</B></TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP">Unique ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</B></TR>
+-->
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+La derni&egrave;re modification de cette entr&eacute;e date du <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> Dans <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
+
diff --git a/ldap/clients/dsgw/config/fr/display-org.html b/ldap/clients/dsgw/config/fr/display-org.html
new file mode 100644
index 00000000..8ec8a08d
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-org.html
@@ -0,0 +1,137 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organization" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+Organisation -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=organization.gif" ALT="Organization" HSPACE=5>
+<TD>
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouvelle organisation -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edition de l'organisation" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregistrer la nouvelle Org." -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Annuler" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORG" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORG" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer l'Org." "prompt=Entrer un nouveau nom pour cette organisation:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer l'Org." "prompt=Supprimer cette organisation ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organization">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* Indique une zone d'entr&eacute;e obligatoire </B><BR>
+<!-- ENDIF -->
+
+<TABLE>
+<TR>
+<TD VALIGN="TOP" NOWRAP>Nom de l'organisation :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=o" "cols=>20" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD>Description:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</B></TR>
+
+<TR><TD>T&eacute;l&eacute;phone :</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD NOWRAP>Cat&eacute;gorie commerciale :</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</B></TD></TR>
+
+<TR><TD>T&eacute;l&eacute;copie :<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD>Emplacement :</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Adresse postale :</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Voir &eacute;galement :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+La derni&egrave;re modification de cette entr&eacute;e date du <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/fr/display-orgperson.html b/ldap/clients/dsgw/config/fr/display-orgperson.html
new file mode 100644
index 00000000..b5af87a7
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-orgperson.html
@@ -0,0 +1,346 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- inet. organizational person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+Entr&eacute;e de personne
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Personne (cliquez pour afficher la carte)"
+ BORDER=0 HSPACE=5>
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouvelle personne -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-ca-cert" -->
+>T&eacute;l&eacute;charger un certificat</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Lire le clip audio</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="Afficher la carte" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Modifier la personne" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregistrer la nouvelle personne" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Annuler" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Modifier le mot de passe" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer la personne" "prompt=Entrer un nouveau nom pour cette personne :" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer la personne" "prompt=Supprimer cette personne ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<B>* Indique une zone d'entr&eacute;e obligatoire</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Contacts </TD>
+</TR>
+
+<TD VALIGN="top" NOWRAP>Pr&eacute;nom :</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</B></TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2">Nom complet :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2"><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>Nom :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Mot de passe :</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</B></TD>
+<TD> Retaper le mot de passe pour confirmation :</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">T&eacute;l&eacute;phone :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Adresse &eacute;lectronique :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">T&eacute;l&eacute;copie :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>Id d'utilisateur :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Radiomessagerie :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>T&eacute;l&eacute;phone mobile :<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+Informations sur l'activit&eacute; et l'emplacement</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Secteur d'activit&eacute; :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</B></TD>
+<TD VALIGN="TOP">Titre :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Service de la soci&eacute;t&eacute; :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</B></TD>
+<TD VALIGN="TOP">Responsable :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dneditpeople" "attr=manager" "desc=Responsable" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>Vous devez enregistrer cette entr&eacute;e avant de pouvoir modifier ces champs.</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Num&eacute;ro de poste :</TD>
+<TD VALIGN="TOP" NOWRAP"><B>
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</B></TD>
+</B><TD VALIGN="TOP">Admin. :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dneditpeople" "attr=secretary" "desc=Admin." -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</B></TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP">N&deg; de service :</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP">N&deg; d'employ&eacute; :</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">N&deg; d'immatriculation :</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</B></TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Adresse postale :</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=2><FONT FACE=ARIAL,HELVETICA COLOR=WHITE>
+ Informations suppl&eacute;mentaires</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Description :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Voir &eacute;galement :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=seeAlso" "desc=Voir &eacute;galement" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>Vous devez enregistrer cette entr&eacute;e avant de pouvoir modifier ce champ.</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</B></TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP">Unique ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</B></TR>
+-->
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+La derni&egrave;re modification de cette entr&eacute;e date du
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
+
diff --git a/ldap/clients/dsgw/config/fr/display-orgunit.html b/ldap/clients/dsgw/config/fr/display-orgunit.html
new file mode 100644
index 00000000..5cb474d9
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-orgunit.html
@@ -0,0 +1,136 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organizationalUnit" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+Unité organisationnelle -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgunit.gif" ALT="Unité Org" HSPACE=5>
+<TD>
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouvelle unité organisationnelle -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edition de l'unité organisationnelle" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregistrer la nouvelle unité Org." -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Annuler" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGUNIT" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGUNIT" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer l'unité Org." "prompt=Entrer un nouveau nom pour cette unité organisationnelle :" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer l'unité Org." "prompt=Supprimer cette unité organisationnelle ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalUnit">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* Indique une zone d'entrée obligatoire </B><BR>
+<!-- ENDIF -->
+
+
+<TABLE>
+<TR>
+<TD>Nom de l'unité :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>20" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD>Description :</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</B></TR>
+
+<TR><TD>Téléphone :</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD NOWRAP>Catégorie commerciale :</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</B></TD></TR>
+
+<TR><TD>Télécopie :<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD>Emplacement :</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Adresse postale :</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Voir également :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+La dernière modification de cette entrée date du <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/display-person.html b/ldap/clients/dsgw/config/fr/display-person.html
new file mode 100644
index 00000000..16712318
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-person.html
@@ -0,0 +1,233 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- person directory entry -->
+<!-- DS_OBJECTCLASS "value=person" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+Entr&eacute;e de personne
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Personne (cliquez pour afficher la carte)"
+ BORDER=0 HSPACE=5>
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouvelle personne
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="Afficher la carte" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=Modifier la personne" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregistrer la nouvelle personne" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Annuler" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_PERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_PERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Modifier le mot de passe" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer la personne" "prompt=Entrer un nouveau nom pour cette personne :" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer la personne" "prompt=Supprimer cette personne ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* Indique une zone d'entr&eacute;e obligatoire</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD VALIGN="top" NOWRAP>Nom :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="top" NOWRAP>Nom complet :</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR><TD COLSPAN="5"><HR></TD></TR>
+<TR>
+<TD>Mot de passe :</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD><TD WIDTH="20%"></TD>
+<TD> Retaper le mot de passe pour confirmation :</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+<TR><TD COLSPAN="5"><HR></TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">T&eacute;l&eacute;phone :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Adresse &eacute;lectronique :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">T&eacute;l&eacute;copie :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Id d'utilisateur :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>Radiomessagerie :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>T&eacute;l&eacute;phone mobile :<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Titre :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Adresse postale :</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Description :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Voir &eacute;galement :<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=seeAlso" "desc=Voir &eacute;galement" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4">
+<!-- IF "Adding" -->
+<I>Vous devez enregistrer cette entr&eacute;e avant de pouvoir modifier ce champ.</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Boisson favorite :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=drink" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+La derni&egrave;re modification de cette entr&eacute;e date du
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
+
diff --git a/ldap/clients/dsgw/config/fr/display-umperson.html b/ldap/clients/dsgw/config/fr/display-umperson.html
new file mode 100644
index 00000000..b5013a0f
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/display-umperson.html
@@ -0,0 +1,200 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- U-M person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,umichPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+Nouvelle
+<!-- ENDIF // Adding -->
+entr&eacute;e de personne U-M -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+></TD>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="Personne" HSPACE=5>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+Nouvel personne U-M -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Lecture de clip audio</A>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edition de la personne" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Enregistrer la nouvelle personne" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Annuler" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_UMPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_UMPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Modifier le mot de passe" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=Renommer la personne" "prompt=Entrer un nouveau nom pour cette personne :" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=Supprimer la personne" "prompt=Supprimer cette personne ?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="umichPerson">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* Indique une zone d'entrȨe obligatoire</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD VALIGN="top" NOWRAP>Nom de famille :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="top" NOWRAP>Nom complet :
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">T&eacute;l&eacute;phone :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Adresse &eacute;lectronique :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">T&eacute;l&eacute;copie :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>Nom unique :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>T&eacute;l&eacute;avertisseur :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>T&eacute;l&eacute;phone mobile :<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Titre :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Adresse postale :</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Description :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=multilineDescription" "syntax=mls" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Voir &eacute;galement :<BR>
+<!-- DS_DNEDITBUTTON "label=Modifier..." "template=dnedit" "attr=seeAlso" "desc=Voir Ȩgalement" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">URL :</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURL" "syntax=url" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">Boisson favorite :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=drink" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+La derni&egrave;re modification de cette entr&eacute;e date du <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedTime" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> par <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedBy" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/dsgw-l10n.conf b/ldap/clients/dsgw/config/fr/dsgw-l10n.conf
new file mode 100644
index 00000000..0482312b
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/dsgw-l10n.conf
@@ -0,0 +1,18 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# Note: the sample part should have double #'s for L10n.
+## translate People <People_translated_in_lang>
+## translate NT-People <NT-People_translated_in_lang>
+## translate Groups <Groups_translated_in_lang>
+## translate NT-Groups <NT-Groups_translated_in_lang>
+## translate Organizations <Organizations_translated_in_lang>
+## translate Org-Units <Org-Units_translated_in_lang>
+## translate Anything <Anything_translated_in_lang>
diff --git a/ldap/clients/dsgw/config/fr/dsgw.conf b/ldap/clients/dsgw/config/fr/dsgw.conf
new file mode 100644
index 00000000..f109eb84
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/dsgw.conf
@@ -0,0 +1,133 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# The baseurl directive gives the server, port, and base dn where searches
+# should be rooted. The format is:
+#
+# ldap://host.domain[:port]/basedn
+# - or -
+# ldaps://host.domain:port/basedn (for SSL)
+#
+# Where:
+# - "host.domain" is the fully-qualified domain name of the directory server
+# - "port" is the port used by the directory server. If you are using an
+# "ldaps" URL (that is, if the gateway is using SSL to communicate with the
+# directory server), then the port number is required. Otherwise, it is
+# optional and defaults to the standard LDAP port (389).
+# - "basedn" is the distinguished name of the place in the directory tree
+# where searches should start. Typically, this is the same as the
+# "suffix" directive in your slapd.conf file.
+#
+# examples:
+# baseurl "ldap://mars.aceindustry.com/o=Ace Industry, c=US"
+# - causes the gateway to use the directory server running on host
+# "mars.aceindustry.com". Since no port was given, the default LDAP
+# port (389) is used. Searches in the gateway search for entries
+# contained within o=Ace Industry, c=US.
+#
+# baseurl "ldaps://mars.aceindustry.com:636/o=Ace Industry, c=US"
+# - same as above, but uses SSL to connect to the directory server,
+# and contacts the server on port 636.
+
+baseurl "ldap://ggood.mcom.com:389/o=Netscape Communications Corp., c=US"
+#baseurl "ldap://belltower.mcom.com:9000/o=Ace%20Industry,%20c=US"
+#baseurl "ldap://belltower:9000/o=Netscape Communications Corp., c=US"
+#baseurl "ldap://ldap.itd.umich.edu:389/o=University of Michigan, c=US"
+
+# The dirmgr directive specifies the "Manager" DN for your directory.
+dirmgr "cn=Directory Manager, o=Netscape Communications Corp., c=US"
+
+# The securitypath directive gives the full path name to your
+# security databases.
+#securitypath /tmp/ssl
+
+# If the requireauth directive is present, users must authenticate to the
+# directory before they may perform any operations. XXX: not implemented
+# in 1.0b2.
+#requireauth
+
+# The authlifetime directive specifies how long authentication credentials
+# are valid (in seconds).
+authlifetime 7200
+
+# The default character set, for communication with HTTP clients.
+# A client may override this default, using an HTTP Accept-Charset header.
+# Or, this default may be overridden for a specific language, by creating
+# a LANG/dsgwcharset.conf file which contains the charset name.
+# For compatibility with HTTP clients that can't handle an HTTP response
+# with a charset parameter in the content-type, comment out this directive;
+# responses will be sent in ISO-8859-1, with no explicit charset parameter.
+# RFC 1345 defines the syntax of charset names. There is a registry of
+# charsets, at ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+# charset UTF-8
+
+# The NLS (internationalization) directory. The directory of this name
+# should contain a locales directory, which contains configuration files.
+NLS ../../../lib/nls
+
+location-suffix "o=Netscape Communications Corp., c=US"
+
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using ds/templateindex. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "umperson" and
+# "orgperson" templates are listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template groupun groupOfUniqueNames
+template mailgroup rfc822mailgroup
+template org organization
+template orgunit organizationalUnit
+template ntperson person inetOrgPerson nTUser
+template umperson person umichPerson
+template orgperson person inetOrgPerson
+template person person
+template country country
+
+#
+# The remainder of this file contains information about the locations and
+# types for new entries.
+#
+# "location" lines define places in the directory where new entries can be added
+# The format of each line is:
+# location HANDLE FRIENDLYNAME DN
+# where HANDLE is a short name which is used in the "newtype" lines (see below)
+# and FRIENDLYNAME is a human-readable name for the location
+# and DN is the Distinguished Name for this location (if it does not end with
+# '#', the location-suffix is appended to to construct a full DN; if it
+# does end with `#', it assumed to be a full DN and the `#' is removed).
+#
+location country "Etats-Unis" "c=US#"
+location org "Cette organisation" ""
+location groups "Services" "ou=Groups"
+location acct "Comptabilité" "ou=Accounting"
+location hr "Ressources humaines" "ou=Human Resources"
+location pay "Comptabilité de paye" "ou=Payroll"
+location pd "Développement des produits" "ou=Product Development"
+location test "Test de produit" "ou=Product Testing"
+
+# "newtype" lines define the types of new entries that may be added
+# The format of each line is:
+# newtype TEMPLATENAME FRIENDLYNAME RDNATTR LOCATIONS...
+# where TEMPLATENAME corresponds to an existing add-TEMPLATENAME.html file
+# and FRIENDLYNAME is a human-readable name for this type of entry
+# and RDNATTR is the attribute that is used to name entries of this type
+# and LOCATIONS is a blank-separated list of locations where these types of
+# entries can be added (corresponding to a HANDLE on a "location"
+# config. file line).
+#
+newtype orgperson "Utilisateur" cn acct hr pay pd test
+newtype ntperson "Utilisateur NT" cn acct hr pay pd test
+newtype groupun "Groupe" cn groups
+newtype orgunit "Service" ou org
+newtype org "Organisation" o country
diff --git a/ldap/clients/dsgw/config/fr/dsgw.tmpl b/ldap/clients/dsgw/config/fr/dsgw.tmpl
new file mode 100644
index 00000000..983aac2c
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/dsgw.tmpl
@@ -0,0 +1,113 @@
+# The htmldir directive tells the CGIs where to find the html files
+htmldir ../html
+
+# The configdir directive tells the CGIs where to find the
+# templates/configuration files
+configdir ../config
+
+# The gwnametrans directive tells the CGIs what url to output
+# for http redirection. It should be the same nameTrans set
+# in the webserver, if any is being is used.
+gwnametrans /clients/dsgw/html/
+
+# The authlifetime directive specifies how long authentication credentials
+# are valid (in seconds).
+authlifetime 7200
+
+# The default character set, for communication with HTTP clients.
+# A client may override this default, using an HTTP Accept-Charset header.
+# Or, this default may be overridden for a specific language, by creating
+# a LANG/dsgwcharset.conf file which contains the charset name.
+# For compatibility with HTTP clients that can't handle an HTTP response
+# with a charset parameter in the content-type, comment out this directive;
+# responses will be sent in ISO-8859-1, with no explicit charset parameter.
+# RFC 1345 defines the syntax of charset names. There is a registry of
+# charsets, at ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+# charset UTF-8
+
+# The NLS (internationalization) directory. The directory of this name
+# should contain a locales directory, which contains configuration files.
+NLS ../../../lib/nls
+
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using ds/templateindex. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template ntgroup groupOfUniqueNames ntGroup
+template groupun groupOfUniqueNames
+template org organization
+template orgunit organizationalUnit
+template ntperson person inetOrgPerson nTUser
+template orgperson person inetOrgPerson
+template person person
+template country country
+
+#
+# The remainder of this file contains information about the locations and
+# types for new entries.
+#
+# "location" lines define places in the directory where new entries can be added
+# The format of each line is:
+# location HANDLE FRIENDLYNAME DN
+# where HANDLE is a short name which is used in the "newtype" lines (see below)
+# and FRIENDLYNAME is a human-readable name for the location
+# and DN is the Distinguished Name for this location (if it does not end with
+# '#', the location-suffix is appended to to construct a full DN; if it
+# does end with `#', it assumed to be a full DN and the `#' is removed).
+#
+location country "&Eacute;tats-Unis" "c=US#"
+location org "Cette soci&eacute;t&eacute;" ""
+location groups "Groupes" "ou=Groups"
+location people "Utilisateurs" "ou=People"
+location special "Utilisateurs particuliers" "ou=Special Users"
+
+# "newtype" lines define the types of new entries that may be added
+# The format of each line is:
+# newtype TEMPLATENAME FRIENDLYNAME RDNATTR LOCATIONS...
+# where TEMPLATENAME corresponds to an existing display-TEMPLATENAME.html file
+# and FRIENDLYNAME is a human-readable name for this type of entry
+# and RDNATTR is the attribute that is used to name entries of this type
+# and LOCATIONS is a blank-separated list of locations where these types of
+# entries can be added (corresponding to a HANDLE on a "location"
+# config. file line).
+#
+newtype orgperson "Personne" uid people special
+newtype ntperson "Personne NT" uid people special
+newtype ntgroup "Groupe NT" cn groups
+newtype groupun "Groupe" cn groups
+newtype orgunit "Service de la soci&eacute;t&eacute;" ou people org
+newtype org "Soci&eacute;t&eacute;" o country
+
+# Mappings between VCard properties and LDAP attribute types:
+# The format of each line is:
+# vcard-property VCARDPROP SYNTAX LDAPATTR [LDAPATTR2]
+# where VCARDPROP is the name of a VCard property
+# and SYNTAX is "cis" for simple strings and "mls" for multiline strings
+# and LDAPATTR is the LDAP attribute that corresponds to VCARDPROP
+# and LDAPATTR2 is an optional secondary LDAP attribute which is added to
+# the property value by appending a semicolon and then the attr2 value.
+vcard-property FN cis cn
+vcard-property N cis sn givenName
+vcard-property ORG cis o ou
+vcard-property ROLE cis businessCategory
+vcard-property ADR;WORK mls postalAddress
+vcard-property ADR;HOME mls homePostalAddress
+vcard-property EMAIL;INTERNET cis mail
+vcard-property TITLE cis title
+vcard-property TEL;WORK cis telephoneNumber
+vcard-property TEL;FAX cis facsimileTelephoneNumber
+vcard-property TEL;CELL cis mobile
+vcard-property TEL;HOME cis homePhone
+vcard-property NOTE cis description
+
+
diff --git a/ldap/clients/dsgw/config/fr/dsgw_adm.conf b/ldap/clients/dsgw/config/fr/dsgw_adm.conf
new file mode 100644
index 00000000..33cc3f37
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/dsgw_adm.conf
@@ -0,0 +1,48 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using the templateindex program. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template groupun groupOfUniqueNames
+template org organization
+template orgunit organizationalUnit
+template orgperson person inetOrgPerson
+template person person
+template country country
+template licensed-user nsLicenseUser
+
+# Attribute Value Sets (used with DS_ATTRVAL_SET directives)
+# attrvset HANDLE VALUE PREFIX SUFFIX
+#
+attrvset CAL news "" "Netscape Collabra Server"
+attrvset CAL slapd "" "Netscape Directory Server"
+
+
+# Template Set definitions
+# Note: templates must be defined before they can be mentioned on
+# a tmplset line.
+#
+# tmplset SETNAME VIEWNAME TEMPLATENAME [HREF-LOCATION]
+#
+tmplset person "G&eacute;n&eacute;ral" orgperson
+tmplset person "Mot de passe" passwd
+tmplset person "Licences" licensed-user
+tmplset group "G&eacute;n&eacute;ral" group
+tmplset groupun "G&eacute;n&eacute;ral" groupun
+
+
diff --git a/ldap/clients/dsgw/config/fr/dsgwfilter.conf b/ldap/clients/dsgw/config/fr/dsgwfilter.conf
new file mode 100644
index 00000000..17a0c3ba
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/dsgwfilter.conf
@@ -0,0 +1,141 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example:
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "le filtre LDAP est"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "le num&eacute;ro de t&eacute;l&eacute;phone se termine par"
+
+ "@" " " "(mail=%v))" "l'adresse &eacute;lectronique est"
+ "(mail=%v*))" "l'adresse &eacute;lectronique commence par"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "premi&egrave;re initiale + nom est"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "nom + derni&egrave;re initiale est"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "le nom est"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "le nom ressemble &agrave; ou contient"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(uid=*)))" "le nom ou l'id d'utilisateur est"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)(uid=%v1)))" "le nom ou l'id d'utilisateur est"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "le nom ressemble &agrave; ou contient"
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "le filtre LDAP est"
+
+ "^\*$" " " "(cn=*))" "le nom est"
+
+ ".*" ". _" "(cn=%v1-))" "le nom est"
+ "(cn=*%v1-*))" "le nom contient"
+ "(cn~=%v1-))" "le nom ressemble &agrave;"
+
+"dsgw-ntgroups"
+ "=" " " "(%v))" "le filtre LDAP est"
+
+ "^\*$" " " "(cn=*))" "le nom est "
+
+ ".*" ". _" "(cn=%v1-))" "le nom est"
+ "(cn=*%v1-*))" "le nom contient"
+ "(cn~=%v1-))" "le nom ressemble &agrave;"
+ "(ntgroupdomainid=%v:*))" "le nom du domaine NT est"
+ "(ntgroupdomainid=*:%v))" "le groupe NT est"
+
+"dsgw-organizations"
+ "=" " " "(%v))" "le filtre LDAP est"
+
+ "\." " " "(associatedDomain=%v))" "le domaine associ&eacute; est"
+
+ "^\*$" " " "(o=*))" "le nom est"
+
+ ".*" " " "(o=%v))" "le nom est"
+ "(o=*%v*))" "le nom contient"
+ "(o~=%v))" "le nom ressemble &agrave;"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "le filtre LDAP est"
+
+ "\." " " "(associatedDomain=%v))" "le domaine associ&eacute; est"
+
+ "^\*$" " " "(ou=*))" "le nom est"
+
+ ".*" " " "(ou=%v))" "le nom est"
+ "(ou=*%v*))" "le nom contient"
+ "(ou~=%v))" "le nom ressemble &agrave;"
+
+"dsgw-anything"
+ "=" " " "(%v)" "le filtre LDAP est"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)(o=%v1-)(ou=%v1-))" "le nom est"
+ "(|(sn~=%v1-)(cn~=%v1-)(o=%v1-)(ou=%v1-))" "le nom ressemble &agrave;"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(o=*)(ou=*))" "le nom est"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)(o=%v1)(ou=%v1))" "le nom est"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)(o=%v1)(ou=%v1))" "le nom ressemble &agrave; ou contient"
+
+
+"dsgw-ntpeople"
+ "=" " " "(%v))" "le filtre LDAP est"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "le num&eacute;ro de t&eacute;l&eacute;phone se termine par"
+
+ "@" " " "(mail=%v))" "l'adresse &eacute;lectronique est"
+ "(mail=%v*))" "l'adresse &eacute;lectronique commence par"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "premi&egrave;re initiale + nom est"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "nom + derni&egrave;re initiale est"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "le nom est"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "le nom ressemble &agrave; ou contient"
+
+ "^\*$" " " "(|(cn=*)(sn=*)))" "le nom est"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)))" "le nom est"
+ "(ntuserlogonserver=%v))" "le serveur de connexions NT est"
+ "(ntuserdomainid=%v:*))" "le nom du domaine NT est"
+ "(ntuserdomainid=*:%v))" "le nom d'utilisateur NT est"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "le nom ressemble &agrave; ou contient"
+
+# Do not remove this line, or place any directives after it.
+
+
diff --git a/ldap/clients/dsgw/config/fr/dsgwfilter_adm.conf b/ldap/clients/dsgw/config/fr/dsgwfilter_adm.conf
new file mode 100644
index 00000000..7c387abf
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/dsgwfilter_adm.conf
@@ -0,0 +1,75 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example (en):
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway - for Netscape Admin Server
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "le filtre LDAP est"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "le num&eacute;ro de t&eacute;l&eacute;phone se termine par"
+
+ "@" " " "(mail=%v))" "l'adresse &eacute;lectronique est"
+ "(mail=%v*))" "l'adresse &eacute;lectronique commence par"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "premi&egrave;re initiale + nom est"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "nom + derni&egrave;re initiale est"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "le nom est"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "le nom ressemble &agrave; ou contient "
+
+ ".*" ". " "(uid=%v1))" "l'id de connexion est"
+ "(|(cn=%v1)(sn=%v1)))" "le nom est"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "le nom ressemble &agrave; ou contient"
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "le filtre LDAP est"
+
+ ".*" ". _" "(cn=%v1-))" "le nom est"
+ "(cn~=%v1-))" "le nom ressemble &agrave;"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "le filtre LDAP"
+
+ ".*" ". _" "(ou=%v1-))" "le nom du service est"
+ "(ou~=%v1-))" "le nom du service ressemble &agrave;"
+
+#Do not remove this line, or place any additional lines after it.
+
+
diff --git a/ldap/clients/dsgw/config/fr/dsgwsearchprefs.conf b/ldap/clients/dsgw/config/fr/dsgwsearchprefs.conf
new file mode 100644
index 00000000..ac4cec44
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/dsgwsearchprefs.conf
@@ -0,0 +1,214 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# dsgwsearchprefs.conf - directory server gateway search object definitions
+
+
+# the current version of this file format is 1
+Version 1
+
+
+# Name for this search object
+People
+# options (the only one supported right now is "internal" which means that
+# this search object should not be presented directly to the user)
+# use "" for none
+""
+# Label to place before text box user types in
+"Rechercher :"
+# Filter prefix to append to all searches
+"(&(objectClass=person)"
+# Tag to use for "Fewer Choices" searches - from ldapfilter.conf file
+"dsgw-people"
+# If a search results in > 1 match, retrieve this attribute to help
+# user disambiguate the entries...
+not-used-by-dsgw
+# ...and label it with this string:
+not-used-by-dsgw
+# Search scope to use when searching
+subtree
+# Follows a list of "More Choices" search options. Format is:
+# Label, attribute, select-bitmap, extra attr display name, extra attr ldap name
+# If last two are null, "Fewer Choices" name/attributes used.
+# Label should begin with the article ("the" in English) for
+# languages that require agreement between article and noun
+# (e.g genders in Spanish or French).
+"nom complet" cn 111111 "" ""
+"nom" sn 111111 "" ""
+"numéro de téléphone" "telephoneNumber" 111011 "" ""
+"adresse électronique" "mail" 111111 "" ""
+"id utilisateur" "uid" 111111 "" ""
+"titre" title 111111 "" ""
+END
+# Match types
+"est" "(%a=%v))"
+"n'est pas" "(!(%a=%v)))"
+"ressemble à" "(%a~=%v))"
+"commence par" "(%a=%v*))"
+"se termine par" "(%a=*%v))"
+"contient" "(%a=*%v*))"
+END
+
+
+"NT-People"
+""
+"Rechercher :"
+"(&(objectClass=ntuser)"
+"dsgw-ntpeople"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nom complet" cn 111111 "" ""
+"nom" sn 111111 "" ""
+"numéro de téléphone" "telephoneNumber" 111011 "" ""
+"adresse électronique" "mail" 111111 "" ""
+"id utilisateur" "uid" 111111 "" ""
+"titre" title 111111 "" ""
+"nom d'utilisateur NT" "ntuserdomainid" 110000 "" ""
+"domaine NT" "ntuserdomainid" 101000 "" ""
+"serveur de connexions NT" "ntuserlogonserver" 111111 "" ""
+END
+"est" "(%a=%v))"
+"n'est pas" "(!(%a=%v)))"
+"ressemble à" "(%a~=%v))"
+"commence par" "(%a=%v*))"
+"se termine par" "(%a=*%v))"
+"contient" "(%a=*%v*))"
+END
+
+
+Groups
+""
+"Rechercher :"
+"(&(|(objectClass=rfc822MailGroup)(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfCertificates))"
+"dsgw-groups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nom" cn 111111 "" ""
+"description" description 111111 "" ""
+"propriétaire (DN)" "owner" 000011 "owner" "Owner"
+"membre (DN)" "uniquemember" 000011 "" ""
+END
+"est" "(%a=%v))"
+"n'est pas" "(!(%a=%v)))"
+"ressemble à" "(%a~=%v))"
+"commence par" "(%a=%v*))"
+"se termine par" "(%a=*%v))"
+"contient" "(%a=*%v*))"
+END
+
+NT-Groups
+""
+"Rechercher :"
+"(&(objectClass=ntGroup)"
+"dsgw-ntgroups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nom" cn 111111 "" ""
+"domaine NT" "ntgroupdomainid" 110000 "" ""
+"nom du groupe NT" "ntgroupdomainid" 101000 "" ""
+"description" description 111111 "" ""
+"propriétaire (DN)" "owner" 000011 "owner" "Owner"
+"membre (DN)" "uniquemember" 000011 "" ""
+END
+"est" "(%a=%v))"
+"n'est pas" "(!(%a=%v)))"
+"ressemble à" "(%a~=%v))"
+"commence par" "(%a=%v*))"
+"se termine par" "(%a=*%v))"
+"contient" "(%a=*%v*))"
+END
+
+
+Organizations
+""
+"Rechercher :"
+"(&(objectClass=organization)"
+"dsgw-organizations"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nom" o 111111 "" ""
+"emplacement" l 111111 "" ""
+"numéro de téléphone" telephoneNumber 111011 "" ""
+"description" description 111011 "" ""
+END
+"est" "(%a=%v))"
+"n'est pas" "(!(%a=%v)))"
+"ressemble à" "(%a~=%v))"
+"commence par" "(%a=%v*))"
+"se termine par" "(%a=*%v))"
+"contient" "(%a=*%v*))"
+END
+
+
+"Org-Units"
+""
+"Rechercher :"
+"(&(objectClass=organizationalUnit)"
+"dsgw-orgunits"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nom" ou 111111 "" ""
+"emplacement" l 111111 "" ""
+"numéro de téléphone" telephoneNumber 111011 "" ""
+"description" description 111111 "" ""
+END
+"est" "(%a=%v))"
+"n'est pas" "(!(%a=%v)))"
+"ressemble à" "(%a~=%v))"
+"commence par" "(%a=%v*))"
+"se termine par" "(%a=*%v))"
+"contient" "(%a=*%v*))"
+END
+
+Anything
+""
+"Rechercher :"
+""
+"dsgw-anything"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nom commun" cn 111111 "" ""
+"description" description 111111 "" ""
+END
+"est" "(%a=%v)"
+"n'est pas" "(!(%a=%v))"
+"ressemble à" "(%a~=%v)"
+"commence par" "(%a=%v*)"
+"se termine par" "(%a=*%v)"
+"contient" "(%a=*%v*)"
+END
+
+Auth
+internal
+"Authentifier en tant que :"
+"(&(objectClass=person)"
+"dsgw-people"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"nom commun" cn 111111 "" ""
+"nom de famille" sn 111111 "" ""
+"numéro de téléphone" "telephoneNumber" 111011 "" ""
+"adresse électronique" "mail" 111111 "" ""
+"id utilisateur" "uid" 111111 "" ""
+"titre" title 111111 "" ""
+END
+"est" "(%a=%v))"
+"n'est pas" "(!(%a=%v)))"
+"ressemble à" "(%a~=%v))"
+"commence par" "(%a=%v*))"
+"se termine par" "(%a=*%v))"
+"contient" "(%a=*%v*))"
+END
+
+
+
diff --git a/ldap/clients/dsgw/config/fr/edit-passwd.html b/ldap/clients/dsgw/config/fr/edit-passwd.html
new file mode 100644
index 00000000..a934992f
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/edit-passwd.html
@@ -0,0 +1,78 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- change a directory entry's password -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Modification du mot de passe -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+</HEAD>
+
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<H2><CENTER>Modification du mot de passe
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</H2></CENTER>
+
+<HR>
+
+<P>
+<TABLE>
+
+<!-- IF "BoundAsThisEntry" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+Entrer l'ancien mot de passe :
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ELIF "!Bound" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+Entrer l'ancien mot de passe :
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ENDIF //BoundAsThisEntry -->
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Entrer le nouveau mot de passe :
+</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD></TR>
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Retaper le nouveau mot de passe pour confirmation :
+</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+</TABLE>
+
+<P>
+
+<TABLE BORDER=2 WIDTH="100%">
+<TR>
+<TD ALIGN="center" WIDTH="50%">
+<!-- IF "BoundAsThisEntry" -->
+<!-- DS_SAVEBUTTON "label=Modifier le mot de passe " -->
+<!-- ELSE -->
+<!-- DS_SAVEBUTTON "label=D&eacute;terminer le mot de passe " -->
+<!-- ENDIF -->
+<TD ALIGN="center" WIDTH="50%">
+<!-- DS_HELPBUTTON "topic=MODIFYPASSWD" -->
+</TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/list-Anything.html b/ldap/clients/dsgw/config/fr/list-Anything.html
new file mode 100644
index 00000000..38281374
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-Anything.html
@@ -0,0 +1,42 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for Anything" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nom<TH NOWRAP>Num&eacute;ro de t&eacute;l&eacute;phone
+<TH NOWRAP>Adresse &eacute;lectronique<TH NOWRAP>Description
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Veuillez effectuer une recherche diff&eacute;rente.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/list-Auth.html b/ldap/clients/dsgw/config/fr/list-Auth.html
new file mode 100644
index 00000000..f1fa4373
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-Auth.html
@@ -0,0 +1,75 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Authenticate as..." -->
+
+<!--
+ The "authForm" form and the authSubmit() JavaScript function are
+ used to avoid the need for a separate form for each entry listed.
+ Each entry is tied to this single form through the magic of an
+ anchor that contains href=javascript:authSubmit().
+-->
+
+<FORM NAME="authForm" METHOD=POST ACTION="auth">
+<INPUT TYPE="hidden" NAME="escapedbinddn">
+<INPUT TYPE="hidden" NAME="authdesturl">
+<!-- PCONTEXT -->
+<!-- DS_POSTEDVALUE "name=authdesturl" "within=VALUE=%22--value--%22" -->
+>
+</FORM>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function authSubmit(encodeddn)
+{
+ document.authForm.escapedbinddn.value = encodeddn;
+ document.authForm.submit();
+}
+// End hiding -->
+</SCRIPT>
+
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC "VERBOSE" -->
+<P>
+<!-- IF "FoundEntries" -->
+Veuillez cliquer sur le nom de l'entr&eacute;e que vous d&eacute;sirez utiliser pour l'authentification.
+</FONT>
+<P>
+
+<TABLE BORDER=1 CELLPADDING=4>
+<TR>
+<TH NOWRAP>Authentifier en tant que <TH NOWRAP>Titre
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:authSubmit('--value--'); onMouseOver=%22window.status='Cliquer pour authentifier'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+<!-- ELSE "FoundEntries" -->
+Veuillez revenir en arri&egrave;re et essayer de nouveau.
+<!-- ENDIF "FoundEntries" -->
+</CENTER>
+
+<FORM>
+<TABLE BORDER=2 WIDTH=100%%>
+<TR>
+<TD ALIGN=center width=50%%>
+<INPUT TYPE="button" VALUE="Pr&eacute;c&eacute;dent" onClick="history.back();">
+<TD ALIGN=center WIDTH=50%%>
+<!-- DS_HELPBUTTON "topic=AUTHMULTMATCH" -->
+</TABLE>
+</FORM>
+
+<!-- ENDHTML -->
+
+
diff --git a/ldap/clients/dsgw/config/fr/list-Groups.html b/ldap/clients/dsgw/config/fr/list-Groups.html
new file mode 100644
index 00000000..34390556
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-Groups.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Recherche des groupes" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nom du groupe
+<TH NOWRAP>Description
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Veuillez effectuer une recherche diff&eacute;rente.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/list-NT-Groups.html b/ldap/clients/dsgw/config/fr/list-NT-Groups.html
new file mode 100644
index 00000000..d9284475
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-NT-Groups.html
@@ -0,0 +1,46 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for NT Groups" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nom du groupe LDAP
+<TH NOWRAP>Nom du domaine NT
+<TH NOWRAP>Nom du groupe NT
+<TH NOWRAP>Description
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntdomain" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntgroupname" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Veuillez effectuer une recherche diff&eacute;rente.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
+
diff --git a/ldap/clients/dsgw/config/fr/list-NT-People.html b/ldap/clients/dsgw/config/fr/list-NT-People.html
new file mode 100644
index 00000000..71e2b32a
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-NT-People.html
@@ -0,0 +1,50 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for NT-People" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nom<TH NOWRAP>Domaine NT<TH NOWRAP>Nom d'utilisateur NT<TH NOWRAP>Num&eacute;ro de t&eacute;l&eacute;phone
+</TR>
+
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "label=" -->
+ onMouseOver="window.status='Cliquez ici pour afficher cette entr&eacute;e en d&eacute;tail'; return true">
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=0" "defaultvalue=name" "options=readonly" -->
+</A>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntdomain" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntuserid" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Veuillez effectuer une recherche diff&eacute;rente.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
+
diff --git a/ldap/clients/dsgw/config/fr/list-Org-Units.html b/ldap/clients/dsgw/config/fr/list-Org-Units.html
new file mode 100644
index 00000000..30aba506
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-Org-Units.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Recherche des unit&eacute;s organisationnelles" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Unit&eacute; organisationnelle<TH>Description <TH>Num&eacute;ro de t&eacute;l&eacute;phone
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Veuillez effectuer une recherche diff&eacute;rente.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/list-Organizations.html b/ldap/clients/dsgw/config/fr/list-Organizations.html
new file mode 100644
index 00000000..3b4b6159
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-Organizations.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Recherche des organisations" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Organisation<TH>Description <TH>Num&eacute;ro de t&eacute;l&eacute;phone
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Veuillez effectuer une recherche diff&eacute;rente.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/list-People.html b/ldap/clients/dsgw/config/fr/list-People.html
new file mode 100644
index 00000000..b58ec1a9
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-People.html
@@ -0,0 +1,50 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>Nom<TH NOWRAP>Num&eacute;ro de t&eacute;l&eacute;phone<TH NOWRAP>Adresse &eacute;lectronique<TH NOWRAP>Titre
+</TR>
+
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "label=" -->
+ onMouseOver="window.status='Cliquez ici pour afficher cette entr&eacute;e en d&eacute;tail'; return true">
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=0" "defaultvalue=name" "options=readonly" -->
+</A>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Veuillez effectuer une recherche diff&eacute;rente.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
+
diff --git a/ldap/clients/dsgw/config/fr/list-fa-Groups.html b/ldap/clients/dsgw/config/fr/list-fa-Groups.html
new file mode 100644
index 00000000..3d396c30
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-fa-Groups.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Recherche de personnes" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/list-fa-People.html b/ldap/clients/dsgw/config/fr/list-fa-People.html
new file mode 100644
index 00000000..3d396c30
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-fa-People.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Recherche de personnes" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/list-urlsearch.html b/ldap/clients/dsgw/config/fr/list-urlsearch.html
new file mode 100644
index 00000000..82e2993b
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/list-urlsearch.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Recherche Èá base d'URL" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>Nom<TH>Num&eacute;ro de t&eacute;l&eacute;phone<TH>Adresse &eacute;lectronique
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+Veuillez effectuer une recherche diff&eacute;rente.
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/fr/newentry.html b/ldap/clients/dsgw/config/fr/newentry.html
new file mode 100644
index 00000000..298d98c2
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/newentry.html
@@ -0,0 +1,27 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentry.html-->
+<TITLE>Passerelle Netscape Directory Server : New Entry </TITLE>
+<!-- DS_NEWENTRY_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=75,70,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=newentrytitle.html" NORESIZE SCROLLING="NO">
+ <FRAME SRC="newentry?<!-- GCONTEXT -->&file=type"
+ NAME="newentryTypeFrame" SCROLLING="NO">
+ <FRAME SRC="newentry?<!-- GCONTEXT -->&file=name"
+ NAME="newentryNameFrame">
+</FRAMESET>
+
+<NOFRAMES>
+<BODY>
+Vous devez utiliser un client qui g&egrave;re la fonction de cadres pour pouvoir afficher ce document.
+</BODY>
+</NOFRAMES>
+</HTML>
+
diff --git a/ldap/clients/dsgw/config/fr/newentryName.html b/ldap/clients/dsgw/config/fr/newentryName.html
new file mode 100644
index 00000000..68055b2a
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/newentryName.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentryName.html-->
+</HEAD>
+<!-- DS_NEWENTRY_NAME_BODY -->
+<p>
+<!-- DS_NEWENTRY_NAME_FORM -->
+<font SIZE="+2">Etape 2</font>
+Fournir un nom pour la nouvelle
+<!-- EVALUATE "entType.fullname" -->
+.
+<p><nobr><font SIZE="+1">
+<!-- EVALUATE "entType.rdnattr" -->
+=</font>
+<input TYPE="text" NAME="entryname" SIZE="40">
+</nobr>
+<p>
+<font SIZE="+2">Etape 3</font>
+
+<!-- DS_NEWENTRY_LOCATION_BEGIN -->
+Utilisez le menu d&eacute;roulant ci-dessous pour s&eacute;lectionner une adresse d'annuaire pour cette
+<!-- EVALUATE "entType.fullname" -->
+personne. Si vous s&eacute;lectionnez Autre, vous devez entrer le nom distinctif complet de l'emplacement o&ugrave; cette entr&eacute;e doit &ecirc;tre ajout&eacute;e.
+<p>
+<!-- DS_NEWENTRY_LOCATION_SELECT -->
+<OPTION VALUE="">Autre</OPTION>
+</SELECT>
+<input TYPE="text" NAME="dnsuffix" SIZE="70">
+<p>
+<font SIZE="+2">Etape 4</font>
+<!-- DS_NEWENTRY_LOCATION_END -->
+Cliquez sur Continuer. Une fen&ecirc;tre modifiable de l'entr&eacute;e est affich&eacute;e. Lorsque vous avez termin&eacute; d'entrer les informations demand&eacute;es, enregistrez l'entr&eacute;e.
+<p>
+<center><table BORDER="2" WIDTH="75%">
+<tr><td ALIGN="center" WIDTH="50%">
+<input TYPE="submit" VALUE="Continuer">
+<td ALIGN="center" WIDTH="50%">
+
+<!-- DS_HELP_BUTTON "ADDING" -->
+</table></center></form>
+</body></HTML>
+
diff --git a/ldap/clients/dsgw/config/fr/newentryType.html b/ldap/clients/dsgw/config/fr/newentryType.html
new file mode 100644
index 00000000..652c210c
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/newentryType.html
@@ -0,0 +1,14 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!--newentryType.html-->
+<!-- DS_NEWENTRY_TYPE_BODY -->
+<!-- DS_NEWENTRY_TYPE_FORM -->
+<font SIZE="+2">Etape 1</font>
+S&eacute;lectionner le type d'entr&eacute;e &agrave; cr&eacute;er.
+<!-- DS_NEWENTRY_TYPE_SELECT -->
+</form></body></HTML>
diff --git a/ldap/clients/dsgw/config/fr/search.html b/ldap/clients/dsgw/config/fr/search.html
new file mode 100644
index 00000000..485efdf2
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/search.html
@@ -0,0 +1,18 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- search.html -->
+<TITLE>Passerelle Netscape Directory Server : Standard Search</TITLE>
+<!-- DS_SEARCH_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=75,100,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=searchtitle.html" SCROLLING="NO">
+ <FRAME SRC="search?<!-- GCONTEXT -->&file=string" NAME=searchFrame NORESIZE SCROLLING="NO">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=greeting.html" NAME=outputFrame>
+</FRAMESET>
+</HTML>
diff --git a/ldap/clients/dsgw/config/fr/searchString.html b/ldap/clients/dsgw/config/fr/searchString.html
new file mode 100644
index 00000000..2be9d1a2
--- /dev/null
+++ b/ldap/clients/dsgw/config/fr/searchString.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- searchString.html -->
+</HEAD>
+<!-- DS_SEARCH_BODY -->
+<!-- DS_SEARCH_FORM "target=outputFrame" -->
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
+<TR><TH ALIGN=RIGHT>Rechercher : </TH><TD>
+<!-- DS_SEARCH_TYPE -->
+</TD>
+<TH>dans :</TH><TD>
+<!-- DS_SEARCH_BASE -->
+</TD></TR>
+<TR><TH ALIGN=RIGHT>Rechercher : </TH>
+<TD COLSPAN=3>
+<INPUT NAME="searchstring" SIZE=30>
+<INPUT TYPE="SUBMIT" VALUE="Rechercher">&nbsp;&nbsp;
+<!-- DS_HELP_BUTTON "SMARTSEARCH" -->
+</TD></TR>
+</TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM></BODY></HTML>
diff --git a/ldap/clients/dsgw/config/ja/authPassword.html b/ldap/clients/dsgw/config/ja/authPassword.html
new file mode 100644
index 00000000..72f47ce3
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/authPassword.html
@@ -0,0 +1,29 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authPassword.html-->
+<TITLE>èªè¨¼...</TITLE>
+<!-- DS_AUTH_PASSWORD_SCRIPT -->
+</HEAD>
+
+<!-- DS_AUTH_PASSWORD_BODY -->
+<!-- DS_AUTH_PASSWORD_INFO -->
+<!-- DS_AUTH_PASSWORD_FORM -->
+<P>
+パスワード<b>
+<!-- DS_AUTH_PASSWORD_NAME -->
+</b>: <INPUT NAME="password" TYPE="password" SIZE=16>
+<P>
+<CENTER>
+<TABLE BORDER=2 WIDTH=100%>
+<TR>
+<!-- DS_AUTH_PASSWORD_BUTTONS -->
+</TABLE>
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/ja/authSearch.html b/ldap/clients/dsgw/config/ja/authSearch.html
new file mode 100644
index 00000000..c4120b3a
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/authSearch.html
@@ -0,0 +1,33 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--authSearch.html-->
+<TITLE>Authenticate...</TITLE>
+<!-- DS_AUTH_SEARCH_SCRIPT -->
+</HEAD>
+<!-- DS_AUTH_SEARCH_BODY -->
+<!-- DS_AUTH_SEARCH_INFO -->
+<!-- DS_AUTH_SEARCH_FORM -->
+Directory ã¸ã®èªè¨¼ã«ãŠã‘る最åˆã®ã‚¹ãƒ†ãƒƒãƒ—ã¯ã€èº«åˆ†ã‚’証明ã™ã‚‹ã“ã¨ã§ã™ã€‚<br>åå‰ã‚’タイプã—ã¦ãã ã•ã„。
+<!-- DS_AUTH_SEARCH_NAME -->
+<P>
+<CENTER>
+<TABLE BORDER=1 WIDTH=100%%>
+<TR>
+<!-- DS_AUTH_SEARCH_BUTTONS -->
+</TABLE>
+</FORM>
+<P>
+<!-- DS_AUTH_AS_ROOT_FORM -->
+<INPUT TYPE="submit" VALUE="Directory Manager ã¨ã—ã¦èªè¨¼">&nbsp;(Directory Administratorã«é™ã‚Šåˆ©ç”¨å¯èƒ½)
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/ja/csearch.html b/ldap/clients/dsgw/config/ja/csearch.html
new file mode 100644
index 00000000..c7d437eb
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/csearch.html
@@ -0,0 +1,23 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearch.html-->
+<TITLE>Netscape Directory Server Gateway: Advanced Search</TITLE>
+<!-- DS_CSEARCH_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS="75,70,70,*" BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=csearchtitle.html" SCROLLING="NO">
+ <FRAMESET COLS="33%,33%,*" BORDER=0>
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=type" NAME="searchTypeFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=attr" NAME="searchAttrFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=match" NAME="searchMatchFrame" NORESIZE SCROLLING="NO">
+ </FRAMESET>
+ <FRAME SRC="csearch?<!-- GCONTEXT -->&file=string" NAME="searchStringFrame" NORESIZE SCROLLING="NO">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=emptyFrame.html" NAME="outputFrame">
+</FRAMESET>
+</HTML>
diff --git a/ldap/clients/dsgw/config/ja/csearchAttr.html b/ldap/clients/dsgw/config/ja/csearchAttr.html
new file mode 100644
index 00000000..8d67d1c6
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/csearchAttr.html
@@ -0,0 +1,17 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchAttr.html-->
+</HEAD>
+<!-- DS_CSEARCH_ATTR_BODY -->
+<!-- DS_CSEARCH_ATTR_FORM -->
+<table>
+<tr VALIGN=BASELINE><td ALIGN=RIGHT></td><td>
+<!-- DS_CSEARCH_ATTR_SELECT -->
+</td></tr>
+</table></form></body></HTML>
diff --git a/ldap/clients/dsgw/config/ja/csearchBase.html b/ldap/clients/dsgw/config/ja/csearchBase.html
new file mode 100644
index 00000000..d3b59aff
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/csearchBase.html
@@ -0,0 +1,17 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchBase.html-->
+</HEAD>
+<!-- DS_CSEARCH_BASE_BODY -->
+<table>
+<tr VALIGN=CENTER><th>存在ã™ã‚‹å ´æ‰€:</th><td>
+<!-- EVALUATE "parent.UFNsearchBase" -->
+</td>
+</table>
+</body></HTML>
diff --git a/ldap/clients/dsgw/config/ja/csearchString.html b/ldap/clients/dsgw/config/ja/csearchString.html
new file mode 100644
index 00000000..c7a8e4a5
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/csearchString.html
@@ -0,0 +1,28 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchString.html-->
+</HEAD>
+<!-- DS_CSEARCH_STRING_BODY -->
+<!-- DS_CSEARCH_STRING_FORM "target=outputFrame" -->
+<TABLE ALIGN=center>
+<TR VALIGN=CENTER><TD>
+<INPUT NAME="searchstring" SIZE=20>
+ã‚’ã€
+<!-- EVALUATE "parent.UFNsearchBase" -->
+&nbsp; ã‹ã‚‰
+<NOBR>
+<INPUT TYPE="SUBMIT" VALUE="検索">
+<!-- DS_HELP_BUTTON "ASEARCH" -->
+</NOBR></TD>
+</TR></TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/config/ja/csearchType.html b/ldap/clients/dsgw/config/ja/csearchType.html
new file mode 100644
index 00000000..f7b400e8
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/csearchType.html
@@ -0,0 +1,18 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--csearchType.html-->
+</HEAD>
+<!-- DS_CSEARCH_TYPE_BODY -->
+<!-- DS_CSEARCH_TYPE_FORM -->
+<table>
+<tr VALIGN=BASELINE><th ALIGN=RIGHT>検索:</th><td>
+<!-- DS_CSEARCH_TYPE_SELECT -->
+</td></tr>
+</table>
+</form></body></HTML>
diff --git a/ldap/clients/dsgw/config/ja/display-country.html b/ldap/clients/dsgw/config/ja/display-country.html
new file mode 100644
index 00000000..000dc09f
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-country.html
@@ -0,0 +1,54 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=country" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>国 -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<TABLE>
+<TR><TD NOWRAP>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=country.gif" ALT="Country" HSPACE=5>
+</TD><TD><FONT SIZE="+2">
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE CELLSPACING="5" >
+
+<TR><TD VALIGN="TOP" NOWRAP>国å:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=co" "options=sort" -->
+</B></TD><TD WIDTH="20%"></TD>
+</B><TD VALIGN="TOP">記述:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP">å‚ç…§:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD><TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" -->
+</B></TD></TR>
+
+</TABLE>
+
+<HR>
+
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日: <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B>変更者: <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-dnedit.html b/ldap/clients/dsgw/config/ja/display-dnedit.html
new file mode 100644
index 00000000..06626c81
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-dnedit.html
@@ -0,0 +1,76 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Edit
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY "onLoad='document.searchForm.searchstring.focus();'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<!-- PCONTEXT -->
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+
+<FONT SIZE="+2">
+修正
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<TABLE CELLSPACING=0 CELLPADDING=0><TR>
+
+<TD NOWRAP>
+一致ã™ã‚‹
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">ユーザ
+<OPTION VALUE="Groups">グループ
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+を検索&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<INPUT TYPE=SUBMIT VALUE=" 検索ã—ã¦è¿½åŠ  ">
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= 検索ã—ã¦å‰Šé™¤ " -->
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" 変更ä¿ç®¡ " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" キャンセル " onClick="parent.cancel();">
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON "topic=EDIT_GROUPMEM" -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-dneditpeople.html b/ldap/clients/dsgw/config/ja/display-dneditpeople.html
new file mode 100644
index 00000000..d1c2b855
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-dneditpeople.html
@@ -0,0 +1,75 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+<TITLE>
+Edit
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY "onLoad='document.searchForm.searchstring.focus();'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_DNSEARCHFORM -->
+<INPUT TYPE=hidden NAME=mode VALUE="smart">
+<INPUT TYPE=hidden NAME=dnlist_js VALUE="true">
+<INPUT TYPE=hidden NAME=listifone VALUE="true">
+<INPUT TYPE=hidden NAME=listtemplate VALUE="">
+<INPUT TYPE=hidden NAME=faMode VALUE="add">
+<!-- PCONTEXT -->
+<INPUT TYPE=hidden NAME=ldapsizelimit VALUE="1000">
+<INPUT TYPE=hidden NAME=ldaptimelimit VALUE="180">
+
+<FONT SIZE="+2">
+修正
+<!-- DS_DNDESC -->
+:
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+
+<TABLE CELLSPACING=0 CELLPADDING=0><TR>
+
+<TD NOWRAP>
+一致ã™ã‚‹
+<SELECT NAME="type">
+<OPTION SELECTED VALUE="People">ユーザ
+</SELECT>
+</TD>
+
+<TD NOWRAP>
+を検索&nbsp;
+<INPUT NAME="searchstring" SIZE=15>
+</TD>
+
+<TD>
+<INPUT TYPE=SUBMIT VALUE=" 検索ã—ã¦è¿½åŠ  ">
+<BR>
+<!-- DS_DNREMOVEBUTTON "VALUE= 検索ã—ã¦å‰Šé™¤ ">
+</TD>
+
+</TR>
+</TABLE>
+
+<P>
+<CENTER><TABLE BORDER="2" WIDTH="100%">
+<TR>
+<TD WIDTH="33%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" 変更ä¿ç®¡ " onClick="parent.saveChanges();">
+<TD WIDTH="34%" ALIGN="center">
+<INPUT TYPE=BUTTON VALUE=" キャンセル " onClick="parent.cancel();">
+<TD WIDTH=33% ALIGN=center>
+<!-- DS_HELPBUTTON "topic=EDIT_PERSON_REF" -->
+</TD></TR></TABLE></CENTER>
+
+<INPUT TYPE=hidden NAME=completion_javascript VALUE='parent.updateList(parent.controlFrame.document.searchForm.faMode.value, parent.dnlist, parent.stagingFrame.dnlist, parent.outputFrame);parent.controlFrame.document.searchForm.faMode.value="add";'>
+<!-- DS_END_DNSEARCHFORM -->
+
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-group.html b/ldap/clients/dsgw/config/ja/display-group.html
new file mode 100644
index 00000000..4cd85a72
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-group.html
@@ -0,0 +1,150 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="グループ" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦ã‚°ãƒ«ãƒ¼ãƒ— -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=グループã®ä¿®æ­£" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=æ–°è¦ã‚°ãƒ«ãƒ¼ãƒ—ã®ä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=グループåã®å¤‰æ›´" "prompt=ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=グループã®å‰Šé™¤" "prompt=ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—を削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfNames">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* ã¯å¿…è¦ãªãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>åå‰:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>記述:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">所有者:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=owner" "desc=所有者" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">å‚ç…§:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=seeAlso" "desc=å‚ç…§" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>ã“れらã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’修正ã™ã‚‹å‰ã«ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">グループ メンãƒãƒ¼:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=uniquemember" "desc=グループ メンãƒãƒ¼" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日: <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> 変更者: <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-groupun.html b/ldap/clients/dsgw/config/ja/display-groupun.html
new file mode 100644
index 00000000..479118c9
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-groupun.html
@@ -0,0 +1,150 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=groupOfUniqueNames" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="グループ" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦ã‚°ãƒ«ãƒ¼ãƒ— -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=グループ修正" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=グループä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_GROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_GROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=グループåã®å¤‰æ›´" "prompt=ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=グループ削除" "prompt=ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—を削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* ã¯å¿…è¦ãªãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>åå‰:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>記述:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">所有者:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=owner" "desc=所有者" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">å‚ç…§:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=seeAlso" "desc=å‚ç…§" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>ã“れらã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’修正ã™ã‚‹å‰ã«ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">グループ メンãƒãƒ¼:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=uniquemember" "desc=グループ メンãƒãƒ¼" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日: <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> 変更者: <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-mailgroup.html b/ldap/clients/dsgw/config/ja/display-mailgroup.html
new file mode 100644
index 00000000..59016d33
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-mailgroup.html
@@ -0,0 +1,124 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=rfc822mailgroup" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+æ–°è¦
+<!-- ENDIF // Adding -->
+メール グループã®ã‚¨ãƒ³ãƒˆãƒª -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="グループ" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦ãƒ¡ãƒ¼ãƒ« グループ
+<!-- ENDIF // Adding -->
+
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=グループã®ä¿®æ­£" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=æ–°è¦ã‚°ãƒ«ãƒ¼ãƒ—ã®ä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_MAILGROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_MAILGROUP" -->
+<!-- ENDIF // Adding -->
+
+<!-- IF "Editing" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=グループåã®å¤‰æ›´" "prompt=ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=グループã®å‰Šé™¤" "prompt=ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—を削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="rfc822mailgroup">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+
+<HR>
+
+<TABLE CELLSPACING="5">
+
+<TR><TD VALIGN="TOP">åå‰:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="TOP">記述:</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=multilineDescription" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP">所有者:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP" NOWRAP>å‚ç…§:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "cols=>40" -->
+</B></TD></TR>
+
+<TR><TD NOWRAP COLSPAN="2">
+<!-- DS_ATTRIBUTE "attr=joinable" "syntax=bool" "type=radio" "true=ãã®ä»–も加ãˆã‚‹" "false=ãã®ä»–を加ãˆãªã„" "defaultvalue=FALSE" -->
+</TD><TD></TD><TD NOWRAP COLSPAN="2">
+<!-- DS_ATTRIBUTE "attr=suppressNoEmailError" "syntax=bool" "type=radio" "true=「電å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ãªã—ã€ã‚¨ãƒ©ãƒ¼ã‚’表示ã—ãªã„" "false=「電å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ãªã—ã€ã‚¨ãƒ©ãƒ¼ã‚’戻ã™" "defaultvalue=FALSE" -->
+</TD></TR>
+
+<HR>
+
+<TR><TD VALIGN="TOP" NOWRAP>グループ メンãƒãƒ¼:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=member" "syntax=dn" "numfields=+4" "options=sort" -->
+</B></TD></TR>
+
+<TR><TD VALIGN="TOP" NOWRAP>é›»å­ãƒ¡ãƒ¼ãƒ«ãƒ¡ãƒ³ãƒãƒ¼:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "numfields=+4" "cols=>30" "options=sort" -->
+</B></TD></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日: <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedTime" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B>変更者: <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedBy" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-ntgroup.html b/ldap/clients/dsgw/config/ja/display-ntgroup.html
new file mode 100644
index 00000000..afa58379
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-ntgroup.html
@@ -0,0 +1,218 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=ntGroup" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+NT Group Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- Changed by: Ko-Haw Nieh, 16-Mar-1998 -->
+<!-- Changed by: Ko-Haw Nieh, 16-Mar-1998 -->
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=group.gif" ALT="グループ" HSPACE=5 >
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦NTグループ -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=NTグループ修正" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=æ–°è¦NTグループをä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTGROUP" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTGROUP" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=NTグループå変更" "prompt=ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=NTグループ削除" "prompt=ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—を削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="ntGroup">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="groupOfUniqueNames">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* ã¯å¿…è¦ãªãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD NOWRAP>åå‰:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "cols=>40" -->
+</B></TD><TD WIDTH="20%"></TD>
+</TR>
+
+<TR>
+<TD NOWRAP>NTグループå:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" "options=readonly" "defaultvalue=none" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntgroupname" "cols=>16" "defaultvalue=none" -->
+<!-- ENDIF // Adding -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>NTグループ タイプ:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "options=readonly" "cols=>16" -->
+<!-- ELSE // Adding -->
+<!-- DS_ATTRIBUTE "attr=nTGroupType" "defaultvalue=Global" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>NTグループ ドメイン:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ntGroupDomainId" "syntax=ntdomain" "cols=>16" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>記述:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>言語情報:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP>æ©Ÿé–¢å˜ä½:</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>40" "defaultvalue=none" -->
+</B></TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">所有者:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=owner" "desc=所有者" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=owner" "syntax=dn" "options=sort,readonly" -->
+</B></TD>
+
+<TR>
+<TD NOWRAP VALIGN="TOP">å‚ç…§:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=seeAlso" "desc=å‚ç…§" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP COLSPAN="4">
+<!-- IF "!Adding" -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=sort,readonly" -->
+</B>
+<!-- ELSE // !Adding -->
+<I>ã“れらã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’修正ã™ã‚‹å‰ã«ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</I>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD NOWRAP VALIGN="top">NTグループ メンãƒãƒ¼:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=uniquemember" "desc=NTグループ メンãƒãƒ¼" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uniquemember" "syntax=dn" "options=sort,readonly" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>グループを削除ã—ãŸå ´åˆã¯NTグループを削除:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=ã¯ã„" "false=ã„ã„ãˆ" "defaultvalue=FALSE" "attr=nTGroupDeleteGroup" -->
+</B></TD><TD></TD>
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP">æ–°è¦NTグループã®ä½œæˆ :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=ã¯ã„" "false=ã„ã„ãˆ" "defaultvalue=TRUE" "attr=nTGroupCreateNewGroup" -->
+</B></TD><TD></TD></TR>
+
+<!-- ENDIF // Adding -->
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日: <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> 変更者: <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-ntperson.html b/ldap/clients/dsgw/config/ja/display-ntperson.html
new file mode 100644
index 00000000..a9853b6f
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-ntperson.html
@@ -0,0 +1,506 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- NT User person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson,nTUser" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+NT Person Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<!-- Changed by: Ko-Haw Nieh, 27-Mar-1998 -->
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="ユーザ(クリックã™ã‚‹ã¨ã‚«ãƒ¼ãƒ‰ãŒè¡¨ç¤ºã•ã‚Œã¾ã™)"
+ BORDER=0 HSPACE=5>
+
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦NTユーザ -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-ca-cert" -->
+>Download Certificate</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>Play Audio Clip</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="カードを表示" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=NTユーザã®ä¿®æ­£" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=æ–°è¦NTユーザをä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_NTPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_NTPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=Directory パスワードを変更" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=ユーザåã®å¤‰æ›´" "prompt=ã“ã®ãƒ¦ãƒ¼ã‚¶ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=NTユーザã®å‰Šé™¤" "prompt=ã“ã®ãƒ¦ãƒ¼ã‚¶ã‚’削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="nTUser">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<B>* ã¯å¿…è¦ãªãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT COLOR=WHITE>
+連絡先</TD>
+</TR>
+
+<TD VALIGN="top" NOWRAP>姓:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2">æ°å:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2"><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>å:</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</B></TD>
+</TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>Directory Password:</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</B></TD>
+<TD> Repeat password to confirm:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">電話:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">ファックス:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>ユーザ ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+<TR>
+<TD VALIGN="TOP" NOWRAP>ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>æºå¸¯é›»è©±:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+</TABLE>
+
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT COLOR=WHITE>
+WindowsNTアカウント情報</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">NTユーザ ID:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- IF "!Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" "options=readonly" -->
+<!-- ENDIF // Adding -->
+<!-- IF "Adding" -->
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntuserid" "cols=>16" -->
+<!-- ENDIF // Adding -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NTドメインå:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD><TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserDomainId" "syntax=ntdomain" "cols=>16" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+<TR>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP>ユーザを削除ã—ãŸå ´åˆã¯ NTアカウントを削除:</TD>
+<TD VALIGN="TOP" COLSPAN=2 NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=ã¯ã„" "false=ã„ã„ãˆ" "defaultvalue=FALSE" "attr=nTUserDeleteAccount" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD VALIGN="TOP">æ–°è¦NTアカウントã®ä½œæˆ :</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=ã¯ã„" "false=ã„ã„ãˆ" "defaultvalue=TRUE" "attr=nTUserCreateNewAccount" -->
+</B></TD></TR>
+
+<!-- ENDIF // Adding -->
+
+<!-- IF "Displaying" -->
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>NTユーザã«é–¢ã™ã‚‹ã‚³ãƒ¡ãƒ³ãƒˆ:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUsrComment" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NTユーザã®å›ºæœ‰ ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUniqueId" "syntax=binvalue" "cols=>10" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>NTパスワード失効:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "syntax=bool" "type=radio" "true=Yes" "false=No" "defaultvalue=FALSE" "attr=nTUserPasswordExpired" -->
+</B></TD>
+<TD VALIGN="TOP">NTä¸è‰¯ãƒ‘スワード回数:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserBadPwCount" "syntax=binvalue" "options=decimal" "cols=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NTã®æœ€çµ‚ログオン日:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogon" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NT ã®æœ€çµ‚ログオフ日:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLastLogoff" "syntax=time" "cols=>10" "defaultvalue=Never Logged On" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NTアカウント失効日:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserAcctExpires" "syntax=time" "defaultvalue=Never Expires" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NTã¸ã®ãƒ­ã‚°ã‚ªãƒ³æ•°:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserNumLogons" "syntax=binvalue" "options=decimal" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NTログオンサーãƒ:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserLogonServer" "defaultvalue=Any Server" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NTワークステーション:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserWorkstations" "defaultvalue=No Restrictions" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NTコードページ:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserCodePage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NT国コード:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserCountryCode" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NT主è¦ã‚°ãƒ«ãƒ¼ãƒ— ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserPrimaryGroupId" "syntax=binvalue" "options=decimal" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NTプロファイル:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserProfile" "defaultvalue=Default" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>NTホームディレクトリ:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDir" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP">NT ホーム ディレクトリドライブ:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserHomeDirDrive" "defaultvalue=None" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>NTスクリプトパス:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserScriptPath" "defaultvalue=None" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>NT最大記憶容é‡:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserMaxStorage" "syntax=binvalue" "options=decimal" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NTユニット/週:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserUnitsPerWeek" "syntax=binvalue" "options=decimal" "cols=>6" -->
+</B></TD>
+<TD VALIGN="TOP">NTユーザã®ç‰¹æ¨©:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserPriv" "syntax=binvalue" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">NTユーザã®ã‚ªãƒšãƒ¬ãƒ¼ã‚¿ç‰¹æ¨©:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserAuthFlags" "syntax=binvalue" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP">NT ユーザ アカウントã®ãã®ä»–ã®æ©Ÿèƒ½:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=nTUserFlags" "syntax=binvalue" "cols=>16" -->
+</B></TD></TR>
+
+<!-- ENDIF // Displaying -->
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT COLOR=WHITE>
+事業ãŠã‚ˆã³å ´æ‰€ã«é–¢ã™ã‚‹æƒ…å ±</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>事業カテゴリ:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</B></TD>
+<TD VALIGN="TOP">å½¹è·:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">æ©Ÿé–¢å˜ä½:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</B></TD>
+<TD VALIGN="TOP">マãƒãƒ¼ã‚¸ãƒ£:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dneditpeople" "attr=manager" "desc=マãƒãƒ¼ã‚¸ãƒ£" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>ã“れらã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’修正ã™ã‚‹å‰ã«ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">部屋番å·:</TD>
+<TD VALIGN="TOP" NOWRAP"><B>
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</B></TD>
+</B><TD VALIGN="TOP">管ç†è€…:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dneditpeople" "attr=secretary" "desc=管ç†è€…" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</B></TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP">部署番å·:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP">社員番å·:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">自動車ã®ãƒŠãƒ³ãƒãƒ¼ãƒ—レート番å·:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</B></TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">ä½æ‰€:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=2><FONT COLOR=WHITE>
+追加情報</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">記述:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">å‚ç…§:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=seeAlso" "desc=å‚ç…§" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>ã“ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’修正ã™ã‚‹å‰ã«ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</B></TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP">Unique ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</B></TR>
+-->
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日:<B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> 変更者: <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-org.html b/ldap/clients/dsgw/config/ja/display-org.html
new file mode 100644
index 00000000..5201aeeb
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-org.html
@@ -0,0 +1,136 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organization" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Organization -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=organization.gif" ALT="æ©Ÿé–¢" HSPACE=5>
+<TD>
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦æ©Ÿé–¢ -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=æ©Ÿé–¢ã®ä¿®æ­£" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=æ–°è¦æ©Ÿé–¢ã®ä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORG" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORG" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=æ©Ÿé–¢åã®å¤‰æ›´" "prompt=ã“ã®æ©Ÿé–¢ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=æ©Ÿé–¢ã®å‰Šé™¤" "prompt=ã“ã®æ©Ÿé–¢ã‚’削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organization">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* ã¯å¿…è¦ãªãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚</B><BR>
+<!-- ENDIF -->
+
+<TABLE>
+<TR>
+<TD VALIGN="TOP" NOWRAP>æ©Ÿé–¢å:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=o" "cols=>20" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD>記述:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</B></TR>
+
+<TR><TD>電話:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD NOWRAP>事業カテゴリ:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</B></TD></TR>
+
+<TR><TD>ファックス:<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD>場所:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>ä½æ‰€:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">å‚ç…§:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日: <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B>変更者: <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-orgperson.html b/ldap/clients/dsgw/config/ja/display-orgperson.html
new file mode 100644
index 00000000..7a5e7be0
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-orgperson.html
@@ -0,0 +1,345 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- inet. organizational person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Person Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<!-- Changed by: Ko-Haw Nieh, 17-Mar-1998 -->
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0></TD>
+<TD>
+<!-- ENDIF -->
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="ユーザ (クリックã™ã‚‹ã¨ã‚«ãƒ¼ãƒ‰ãŒè¡¨ç¤ºã•ã‚Œã¾ã™)"
+ BORDER=0 HSPACE=5>
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦ãƒ¦ãƒ¼ã‚¶ -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+<A HREF=""
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-ca-cert" -->
+>証明書ã®ãƒ€ã‚¦ãƒ³ãƒ­ãƒ¼ãƒ‰</A>
+<!-- ENDIF -->
+
+<!-- DS_ATTRIBUTE "attr=audio" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "audio" -->
+&nbsp;&nbsp;
+<A HREF=""
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>オーディオクリップã®å†ç”Ÿ</A>
+<!-- ENDIF -->
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="カードを表示" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=ユーザã®ä¿®æ­£" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=æ–°è¦ãƒ¦ãƒ¼ã‚¶ã®ä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=パスワード変更" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=ユーザå変更" "prompt=ã“ã®ãƒ¦ãƒ¼ã‚¶ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=ユーザ削除" "prompt=ã“ã®ãƒ¦ãƒ¼ã‚¶ã‚’削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalPerson">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="inetOrgPerson">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<!-- IF "!Displaying" -->
+<B>* ã¯å¿…è¦ãªãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT COLOR=WHITE>
+連絡先</TD>
+</TR>
+
+<TD VALIGN="top" NOWRAP>姓:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2">æ°å:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP ROWSPAN="2"><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>å:</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=givenName" "cols=>16" -->
+</B></TD>
+</TR>
+
+<!-- IF "Adding" -->
+<TR>
+<TD>パスワード:</TD><TD>
+<!-- DS_NEWPASSWORD "cols=>16" -->
+</B></TD>
+<TD> 確èªã®ãŸã‚パスワードをå†åº¦å…¥åŠ›:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD "cols=>16" -->
+</TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">電話:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>23" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">ファックス:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>ユーザ ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+<TR>
+<TD VALIGN="TOP" NOWRAP>ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD>
+<TD VALIGN="TOP" NOWRAP>æºå¸¯é›»è©±:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=4><FONT COLOR=WHITE>
+事業ãŠã‚ˆã³å ´æ‰€ã«é–¢ã™ã‚‹æƒ…å ±</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>事業カテゴリ:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businesscategory" -->
+</B></TD>
+<TD VALIGN="TOP">å½¹è·:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">æ©Ÿé–¢å˜ä½:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" -->
+</B></TD>
+<TD VALIGN="TOP">マãƒãƒ¼ã‚¸ãƒ£:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dneditpeople" "attr=manager" "desc=マãƒãƒ¼ã‚¸ãƒ£" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "Adding" -->
+<TD VALIGN="TOP" ROWSPAN=2>
+<I>ã“れらã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’修正ã™ã‚‹å‰ã«ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</I>
+<!-- ELSE // !Adding -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=manager" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">部屋番å·:</TD>
+<TD VALIGN="TOP" NOWRAP"><B>
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" -->
+</B></TD>
+</B><TD VALIGN="TOP">管ç†è€…:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dneditpeople" "attr=secretary" "desc=管ç†è€…" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<!-- IF "!Adding" -->
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=secretary" "syntax=dn" "options=readonly" -->
+</B></TD>
+<!-- ENDIF // !Adding -->
+</TR>
+
+<TR>
+<TD VALIGN="TOP">部署番å·:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=departmentnumber" "cols=>8" -->
+</B></TD>
+<TD VALIGN="TOP">社員番å·:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=employeenumber" "cols=>6" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">自動車ã®ãƒŠãƒ³ãƒãƒ¼ãƒ—レート番å·:</TD>
+<TD VALIGN="TOP"><B>
+<!-- DS_ATTRIBUTE "attr=carlicense" "cols=>8" -->
+</B></TD>
+<!-- Note: need to include two cells that contain a non-breaking space
+character so table background colors, etc. are rendered correctly -->
+<TD>&nbsp;&nbsp;</TD>
+<TD>&nbsp;&nbsp;</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">ä½æ‰€:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+</TABLE>
+
+<TABLE CELLSPACING="2" BORDER BGCOLOR=#f2f2f2 WIDTH=95%>
+<TR>
+<TD BGCOLOR=#006666 COLSPAN=2><FONT COLOR=WHITE>
+追加情報</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">記述:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">å‚ç…§:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=seeAlso" "desc=å‚ç…§" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP>
+<!-- IF "Adding" -->
+<I>ã“ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’修正ã™ã‚‹å‰ã«ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" "options=sort" -->
+</B></TR>
+
+<!-- The following attribute should only be uncommented if you have
+ a need to allow editing of the x500UniqueIdentifier attribute.
+ Most installations will not need this functionality.
+<TR>
+<TD VALIGN="TOP">Unique ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=x500uniqueidentifier" "cols=>50" -->
+</B></TR>
+-->
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日: <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> 変更者: <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-orgunit.html b/ldap/clients/dsgw/config/ja/display-orgunit.html
new file mode 100644
index 00000000..13721e68
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-orgunit.html
@@ -0,0 +1,136 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=organizationalUnit" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+æ–°è¦
+<!-- ENDIF // Adding -->
+æ©Ÿé–¢å˜ä½ -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- Changed by: Ko-Haw Nieh, 16-Mar-1998 -->
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE>
+<TR>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgunit.gif" ALT="æ©Ÿé–¢å˜ä½" HSPACE=5>
+<TD>
+<FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦æ©Ÿé–¢å˜ä½ -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</FONT>
+</TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=æ©Ÿé–¢å˜ä½ã‚’修正" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=æ–°è¦æ©Ÿé–¢å˜ä½ã‚’ä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_ORGUNIT" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_ORGUNIT" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_RENAMEBUTTON "label=æ©Ÿé–¢å˜ä½åã®å¤‰æ›´" "prompt=ã“ã®æ©Ÿé–¢å˜ä½ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=æ©Ÿé–¢å˜ä½ã‚’削除" "prompt=ã“ã®æ©Ÿé–¢å˜ä½ã‚’削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="organizationalUnit">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* ã¯å¿…è¦ãªãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE>
+<TR>
+<TD NOWRAP>å˜ä½å:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=ou" "cols=>20" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD>記述:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>30" -->
+</B></TR>
+
+<TR><TD>電話:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD NOWRAP>事業カテゴリ:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=businessCategory" "cols=>30" -->
+</B></TD></TR>
+
+<TR><TD>ファックス:<TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD>場所:</TD><TD NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">ä½æ‰€:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">å‚ç…§:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日: <B>
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B>変更者: <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-person.html b/ldap/clients/dsgw/config/ja/display-person.html
new file mode 100644
index 00000000..7083e0ac
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-person.html
@@ -0,0 +1,230 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- person directory entry -->
+<!-- DS_OBJECTCLASS "value=person" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Person Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function showVCard()
+{
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ document.location.href = cardurl;
+}
+// End hiding -->
+</SCRIPT>
+
+</HEAD>
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<!-- A HREF="javascript:showVCard()" -->
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="ユーザ(クリックã™ã‚‹ã¨ã‚«ãƒ¼ãƒ‰ãŒè¡¨ç¤ºã•ã‚Œã¾ã™)"
+ BORDER=0 HSPACE=5>
+</A>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦ãƒ¦ãƒ¼ã‚¶ -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- INPUT TYPE="button" VALUE="カードを表示" onClick="showVCard()" -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITBUTTON "label=ユーザã®ä¿®æ­£" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=æ–°è¦ãƒ¦ãƒ¼ã‚¶ã®ä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_PERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_PERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=パスワード変更" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=ユーザå変更" "prompt=ã“ã®ãƒ¦ãƒ¼ã‚¶ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=ユーザ削除" "prompt=ã“ã®ãƒ¦ãƒ¼ã‚¶ã‚’削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<!-- ENDIF // Adding -->
+
+<!-- PCONTEXT -->
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<!-- DS_STD_COMPLETION_JS -->
+
+<HR>
+<!-- IF "!Displaying" -->
+<B>* ã¯å¿…è¦ãªãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚</B><BR>
+<!-- ENDIF -->
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD VALIGN="top" NOWRAP>è‹—å­—:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="top" NOWRAP>æ°å:</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>16" -->
+</B></TD></TR>
+
+<!-- IF "Adding" -->
+<TR><TD COLSPAN="5"><HR></TD></TR>
+<TR>
+<TD>パスワード:</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD><TD WIDTH="20%"></TD>
+<TD> 確èªã®ãŸã‚パスワードをå†åº¦å…¥åŠ›:</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+<TR><TD COLSPAN="5"><HR></TD></TR>
+<!-- ENDIF // Adding -->
+
+<TR>
+<TD VALIGN="TOP">電話:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">ファックス:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>ユーザ ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" "options=unique" -->
+</B></TD></TR>
+<INPUT TYPE="hidden" NAME="desc_uid" VALUE="user id">
+<!-- PCONTEXT -->
+<TR>
+<TD VALIGN="TOP" NOWRAP>ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>æºå¸¯é›»è©±:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">å½¹è·:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">ä½æ‰€:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">記述:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=description" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">å‚ç…§:<BR>
+<!-- IF "!Adding" -->
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=seeAlso" "desc=å‚ç…§" -->
+<!-- ENDIF // !Adding -->
+</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4">
+<!-- IF "Adding" -->
+<I>ã“ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’修正ã™ã‚‹å‰ã«ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’ä¿å­˜ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</I>
+<!-- ELSE // !Adding -->
+<B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+</TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">好ããªé£²ç‰©:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=drink" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日:
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B> 変更者: <B>
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/display-umperson.html b/ldap/clients/dsgw/config/ja/display-umperson.html
new file mode 100644
index 00000000..be3cd589
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/display-umperson.html
@@ -0,0 +1,199 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- U-M person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,umichPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+æ–°è¦
+<!-- ENDIF // Adding -->
+ミシガン大学ユーザã®ã‚¨ãƒ³ãƒˆãƒª -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE></HEAD>
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<TABLE><TR><TD>
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+></TD>
+<TD>
+<IMG SRC="lang?<!-- GCONTEXT -->&file=person.gif" ALT="ユーザ" HSPACE=5>
+</TD>
+<!-- IF "DisplayOrgChart" -->
+<TD><FONT FACE="PrimaSans BT, Verdana, Sans-Serif" SIZE="-1">
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ >
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to display organization chart" HSPACE=5></a>
+</FONT>
+</TD>
+<!-- ENDIF -->
+<TD><FONT SIZE="+2">
+<!-- IF "Adding" -->
+æ–°è¦ãƒŸã‚·ã‚¬ãƒ³å¤§å­¦ãƒ¦ãƒ¼ã‚¶ -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</FONT></TD></TR></TABLE>
+
+<A HREF=
+<!-- DS_ATTRIBUTE "attr=audio" "options=link" "mimetype=audio/basic" -->
+>オーディオクリップã®å†ç”Ÿ</A>
+
+<TABLE><TR><TD>
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=ユーザã®ä¿®æ­£" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=æ–°è¦ãƒ¦ãƒ¼ã‚¶ã®ä¿ç®¡" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=キャンセル" -->
+<!-- ENDIF // !Displaying -->
+</TD><TD>&nbsp;&nbsp;</TD><TD>
+<!-- IF "Editing" -->
+<!-- DS_HELPBUTTON "topic=EDIT_UMPERSON" -->
+<!-- ELIF "Adding" -->
+<!-- DS_HELPBUTTON "topic=ADD_UMPERSON" -->
+<!-- ENDIF // Adding -->
+</TD>
+
+<!-- IF "Editing" -->
+<TD>&nbsp;&nbsp;</TD><TD>
+<!-- DS_EDITASBUTTON "label=パスワード変更" "template=passwd" -->
+</TD><TD>
+<!-- DS_RENAMEBUTTON "label=ユーザåã®å¤‰æ›´" "prompt=ã“ã®ãƒ¦ãƒ¼ã‚¶ã®æ–°ã—ã„åå‰ã‚’入力ã—ã¦ãã ã•ã„:" -->
+</TD><TD>
+<!-- DS_DELETEBUTTON "label=ユーザã®å‰Šé™¤" "prompt=ã“ã®ãƒ¦ãƒ¼ã‚¶ã‚’削除ã—ã¾ã™ã‹?" -->
+</TD>
+<!-- ENDIF // Editing -->
+
+</TR></TABLE>
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="person">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="umichPerson">
+<!-- ENDIF // Adding -->
+<!-- PCONTEXT -->
+<HR>
+<!-- IF "!Displaying" -->
+<B>* ã¯å¿…è¦ãªãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã‚’示ã—ã¦ã„ã¾ã™ã€‚</B><BR>
+<!-- ENDIF -->
+
+
+<TABLE CELLSPACING="5">
+<TR>
+<TD VALIGN="top" NOWRAP>è‹—å­—:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=sn" "cols=>16" -->
+</B></TD><TD WIDTH="20%"></TD>
+<TD VALIGN="top" NOWRAP>æ°å:
+<!-- IF "!Displaying" -->
+<B>*</B>
+<!-- ENDIF -->
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=+1" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">電話:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>16" "numfields=+1" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>20" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">ファックス:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>固有ã®åå‰:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=uid" "cols=>16" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>16" -->
+</B></TD><TD></TD>
+<TD VALIGN="TOP" NOWRAP>æºå¸¯é›»è©±:<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>16" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">å½¹è·:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">ä½æ‰€:</TD>
+<TD VALIGN="TOP" COLSPAN="4" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "type=TEXTAREA" "cols=>40" "rows=>4" -->
+</B></TD></TR>
+
+<TR><TD COLSPAN="5"><HR></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">記述:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=multilineDescription" "syntax=mls" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">å‚ç…§:<BR>
+<!-- DS_DNEDITBUTTON "label=修正..." "template=dnedit" "attr=seeAlso" "desc=å‚ç…§" -->
+</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "options=readonly" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN="4"><B>
+<!-- DS_ATTRIBUTE "attr=labeledURL" "syntax=url" "cols=>50" -->
+</B></TR>
+
+<TR>
+<TD VALIGN="TOP">好ããªé£²ç‰©:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<!-- DS_ATTRIBUTE "attr=drink" -->
+</B></TR>
+
+</TABLE>
+
+<!-- IF "!Adding" -->
+<HR>
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€çµ‚変更日: <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedTime" "syntax=time" "defaultvalue=N/A" "options=readonly" -->
+</B>変更者: <B>
+<!-- DS_ATTRIBUTE "attr=lastModifiedBy" "syntax=dn" "defaultvalue=N/A" "options=readonly" -->
+</B>
+<!-- ENDIF // !Adding -->
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/dsgw-l10n.conf b/ldap/clients/dsgw/config/ja/dsgw-l10n.conf
new file mode 100644
index 00000000..0482312b
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/dsgw-l10n.conf
@@ -0,0 +1,18 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# Note: the sample part should have double #'s for L10n.
+## translate People <People_translated_in_lang>
+## translate NT-People <NT-People_translated_in_lang>
+## translate Groups <Groups_translated_in_lang>
+## translate NT-Groups <NT-Groups_translated_in_lang>
+## translate Organizations <Organizations_translated_in_lang>
+## translate Org-Units <Org-Units_translated_in_lang>
+## translate Anything <Anything_translated_in_lang>
diff --git a/ldap/clients/dsgw/config/ja/dsgw.conf b/ldap/clients/dsgw/config/ja/dsgw.conf
new file mode 100644
index 00000000..d818fd44
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/dsgw.conf
@@ -0,0 +1,133 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# The baseurl directive gives the server, port, and base dn where searches
+# should be rooted. The format is:
+#
+# ldap://host.domain[:port]/basedn
+# - or -
+# ldaps://host.domain:port/basedn (for SSL)
+#
+# Where:
+# - "host.domain" is the fully-qualified domain name of the directory server
+# - "port" is the port used by the directory server. If you are using an
+# "ldaps" URL (that is, if the gateway is using SSL to communicate with the
+# directory server), then the port number is required. Otherwise, it is
+# optional and defaults to the standard LDAP port (389).
+# - "basedn" is the distinguished name of the place in the directory tree
+# where searches should start. Typically, this is the same as the
+# "suffix" directive in your slapd.conf file.
+#
+# examples:
+# baseurl "ldap://mars.aceindustry.com/o=Ace Industry, c=US"
+# - causes the gateway to use the directory server running on host
+# "mars.aceindustry.com". Since no port was given, the default LDAP
+# port (389) is used. Searches in the gateway search for entries
+# contained within o=Ace Industry, c=US.
+#
+# baseurl "ldaps://mars.aceindustry.com:636/o=Ace Industry, c=US"
+# - same as above, but uses SSL to connect to the directory server,
+# and contacts the server on port 636.
+
+baseurl "ldap://ggood.mcom.com:389/o=Netscape Communications Corp., c=US"
+#baseurl "ldap://belltower.mcom.com:9000/o=Ace%20Industry,%20c=US"
+#baseurl "ldap://belltower:9000/o=Netscape Communications Corp., c=US"
+#baseurl "ldap://ldap.itd.umich.edu:389/o=University of Michigan, c=US"
+
+# The dirmgr directive specifies the "Manager" DN for your directory.
+dirmgr "cn=Directory Manager, o=Netscape Communications Corp., c=US"
+
+# The securitypath directive gives the full path name to your
+# security databases.
+#securitypath /tmp/ssl
+
+# If the requireauth directive is present, users must authenticate to the
+# directory before they may perform any operations. XXX: not implemented
+# in 1.0b2.
+#requireauth
+
+# The authlifetime directive specifies how long authentication credentials
+# are valid (in seconds).
+authlifetime 7200
+
+# The default character set, for communication with HTTP clients.
+# A client may override this default, using an HTTP Accept-Charset header.
+# Or, this default may be overridden for a specific language, by creating
+# a LANG/dsgwcharset.conf file which contains the charset name.
+# For compatibility with HTTP clients that can't handle an HTTP response
+# with a charset parameter in the content-type, comment out this directive;
+# responses will be sent in ISO-8859-1, with no explicit charset parameter.
+# RFC 1345 defines the syntax of charset names. There is a registry of
+# charsets, at ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+# charset UTF-8
+
+# The NLS (internationalization) directory. The directory of this name
+# should contain a locales directory, which contains configuration files.
+NLS ../../../lib/nls
+
+location-suffix "o=Netscape Communications Corp., c=US"
+
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using ds/templateindex. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "umperson" and
+# "orgperson" templates are listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template groupun groupOfUniqueNames
+template mailgroup rfc822mailgroup
+template org organization
+template orgunit organizationalUnit
+template ntperson person inetOrgPerson nTUser
+template umperson person umichPerson
+template orgperson person inetOrgPerson
+template person person
+template country country
+
+#
+# The remainder of this file contains information about the locations and
+# types for new entries.
+#
+# "location" lines define places in the directory where new entries can be added
+# The format of each line is:
+# location HANDLE FRIENDLYNAME DN
+# where HANDLE is a short name which is used in the "newtype" lines (see below)
+# and FRIENDLYNAME is a human-readable name for the location
+# and DN is the Distinguished Name for this location (if it does not end with
+# '#', the location-suffix is appended to to construct a full DN; if it
+# does end with `#', it assumed to be a full DN and the `#' is removed).
+#
+location country "米国" "c=US#"
+location org "ç¾åœ¨ã®æ©Ÿé–¢" ""
+location groups "機関グループ" "ou=Groups"
+location acct "経ç†" "ou=Accounting"
+location hr "人事" "ou=Human Resources"
+location pay "会計" "ou=Payroll"
+location pd "製å“開発" "ou=Product Development"
+location test "製å“テスト" "ou=Product Testing"
+
+# "newtype" lines define the types of new entries that may be added
+# The format of each line is:
+# newtype TEMPLATENAME FRIENDLYNAME RDNATTR LOCATIONS...
+# where TEMPLATENAME corresponds to an existing add-TEMPLATENAME.html file
+# and FRIENDLYNAME is a human-readable name for this type of entry
+# and RDNATTR is the attribute that is used to name entries of this type
+# and LOCATIONS is a blank-separated list of locations where these types of
+# entries can be added (corresponding to a HANDLE on a "location"
+# config. file line).
+#
+newtype orgperson "ユーザ" cn acct hr pay pd test
+newtype ntperson "NTユーザ" cn acct hr pay pd test
+newtype groupun "グループ" cn groups
+newtype orgunit "æ©Ÿé–¢å˜ä½" ou org
+newtype org "æ©Ÿé–¢" o country
diff --git a/ldap/clients/dsgw/config/ja/dsgw.tmpl b/ldap/clients/dsgw/config/ja/dsgw.tmpl
new file mode 100644
index 00000000..732e0406
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/dsgw.tmpl
@@ -0,0 +1,111 @@
+# The htmldir directive tells the CGIs where to find the html files
+htmldir ../html
+
+# The configdir directive tells the CGIs where to find the
+# templates/configuration files
+configdir ../config
+
+# The gwnametrans directive tells the CGIs what url to output
+# for http redirection. It should be the same nameTrans set
+# in the webserver, if any is being is used.
+gwnametrans /clients/dsgw/html/
+
+# The authlifetime directive specifies how long authentication credentials
+# are valid (in seconds).
+authlifetime 7200
+
+# The default character set, for communication with HTTP clients.
+# A client may override this default, using an HTTP Accept-Charset header.
+# Or, this default may be overridden for a specific language, by creating
+# a LANG/dsgwcharset.conf file which contains the charset name.
+# For compatibility with HTTP clients that can't handle an HTTP response
+# with a charset parameter in the content-type, comment out this directive;
+# responses will be sent in ISO-8859-1, with no explicit charset parameter.
+# RFC 1345 defines the syntax of charset names. There is a registry of
+# charsets, at ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+# charset UTF-8
+
+# The NLS (internationalization) directory. The directory of this name
+# should contain a locales directory, which contains configuration files.
+NLS ../../../lib/nls
+
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using ds/templateindex. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template ntgroup groupOfUniqueNames ntGroup
+template groupun groupOfUniqueNames
+template org organization
+template orgunit organizationalUnit
+template ntperson person inetOrgPerson nTUser
+template orgperson person inetOrgPerson
+template person person
+template country country
+
+#
+# The remainder of this file contains information about the locations and
+# types for new entries.
+#
+# "location" lines define places in the directory where new entries can be added
+# The format of each line is:
+# location HANDLE FRIENDLYNAME DN
+# where HANDLE is a short name which is used in the "newtype" lines (see below)
+# and FRIENDLYNAME is a human-readable name for the location
+# and DN is the Distinguished Name for this location (if it does not end with
+# '#', the location-suffix is appended to to construct a full DN; if it
+# does end with `#', it assumed to be a full DN and the `#' is removed).
+#
+location country "米国" "c=US#"
+location org "ã“ã®çµ„ç¹” -" ""
+location groups "グループ" "ou=Groups"
+location people "ユーザー" "ou=People"
+location special "特別ユーザー" "ou=Special Users"
+
+# "newtype" lines define the types of new entries that may be added
+# The format of each line is:
+# newtype TEMPLATENAME FRIENDLYNAME RDNATTR LOCATIONS...
+# where TEMPLATENAME corresponds to an existing display-TEMPLATENAME.html file
+# and FRIENDLYNAME is a human-readable name for this type of entry
+# and RDNATTR is the attribute that is used to name entries of this type
+# and LOCATIONS is a blank-separated list of locations where these types of
+# entries can be added (corresponding to a HANDLE on a "location"
+# config. file line).
+#
+newtype orgperson "ユーザー" uid people special
+newtype ntperson "NTユーザー" uid people special
+newtype ntgroup "NTグループ" cn groups
+newtype groupun "グループ" cn groups
+newtype orgunit "組織å˜ä½" ou people org
+newtype org "組織" o country
+
+# Mappings between VCard properties and LDAP attribute types:
+# The format of each line is:
+# vcard-property VCARDPROP SYNTAX LDAPATTR [LDAPATTR2]
+# where VCARDPROP is the name of a VCard property
+# and SYNTAX is "cis" for simple strings and "mls" for multiline strings
+# and LDAPATTR is the LDAP attribute that corresponds to VCARDPROP
+# and LDAPATTR2 is an optional secondary LDAP attribute which is added to
+# the property value by appending a semicolon and then the attr2 value.
+vcard-property FN cis cn
+vcard-property N cis sn givenName
+vcard-property ORG cis o ou
+vcard-property ROLE cis businessCategory
+vcard-property ADR;WORK mls postalAddress
+vcard-property ADR;HOME mls homePostalAddress
+vcard-property EMAIL;INTERNET cis mail
+vcard-property TITLE cis title
+vcard-property TEL;WORK cis telephoneNumber
+vcard-property TEL;FAX cis facsimileTelephoneNumber
+vcard-property TEL;CELL cis mobile
+vcard-property TEL;HOME cis homePhone
+vcard-property NOTE cis description
diff --git a/ldap/clients/dsgw/config/ja/dsgw_adm.conf b/ldap/clients/dsgw/config/ja/dsgw_adm.conf
new file mode 100644
index 00000000..9fbf96ea
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/dsgw_adm.conf
@@ -0,0 +1,46 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using the templateindex program. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template group groupOfNames
+template groupun groupOfUniqueNames
+template org organization
+template orgunit organizationalUnit
+template orgperson person inetOrgPerson
+template person person
+template country country
+template licensed-user nsLicenseUser
+
+# Attribute Value Sets (used with DS_ATTRVAL_SET directives)
+# attrvset HANDLE VALUE PREFIX SUFFIX
+#
+attrvset CAL news "" "Netscape Collabra Server"
+attrvset CAL slapd "" "Netscape Directory Server"
+
+
+# Template Set definitions
+# Note: templates must be defined before they can be mentioned on
+# a tmplset line.
+#
+# tmplset SETNAME VIEWNAME TEMPLATENAME [HREF-LOCATION]
+#
+tmplset person "一般" orgperson
+tmplset person "パスワード" passwd
+tmplset person "ライセンス" licensed-user
+tmplset group "一般" group
+tmplset groupun "一般" groupun
diff --git a/ldap/clients/dsgw/config/ja/dsgwcharset.conf b/ldap/clients/dsgw/config/ja/dsgwcharset.conf
new file mode 100644
index 00000000..d14e3f1d
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/dsgwcharset.conf
@@ -0,0 +1,7 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+Shift_JIS
diff --git a/ldap/clients/dsgw/config/ja/dsgwcollate.conf b/ldap/clients/dsgw/config/ja/dsgwcollate.conf
new file mode 100644
index 00000000..34377d01
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/dsgwcollate.conf
@@ -0,0 +1,31 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# Each line in this file defines a crude string collation.
+# There are two such collations, one for sorting a displayed list, and
+# another for selecting one of several alternative values to display:
+
+sort 20,A0,3000-30FF 3190-
+display 20,A0,3000,3190- 3001-30FF
+
+# In each line, each parameter defines a "script" as a set of Unicodes;
+# a character is considered to be part of the first script it matches.
+# An implicit final script contains characters that don't match any
+# parameter. Strings are collated in order of these scripts.
+# A mixed-script string is collated with the last script it contains.
+# Strings in the same script category are sorted by another algorithm,
+# which is not defined here.
+
+# In this file, the sort scripts are Kana, Kanji and everything else,
+# and the display scripts are Kanji, Kana and everything else. So,
+# lists are sorted with pure Kana values first, Kanji values and mixed
+# Kanji/Kana values next, and finally values containing other characters.
+# When choosing a value to display, pure Kanji is preferred, Kana or
+# mixed Kanji/Kana is the next choice, and anything else is the last.
+# These choices aim to sort by Yomi (stored in Kana), but display Kanji.
+
+# Insignificant characters (such as whitespace) should be included in
+# the first script on each line.
diff --git a/ldap/clients/dsgw/config/ja/dsgwfilter.conf b/ldap/clients/dsgw/config/ja/dsgwfilter.conf
new file mode 100644
index 00000000..965854a1
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/dsgwfilter.conf
@@ -0,0 +1,139 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example:
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "LDAPフィルタ: "
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "電話番å·ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹"
+
+ "@" " " "(mail=%v))" "é›»å­ãƒ¡ãƒ¼ãƒ« アドレスã«ä¸€è‡´ã™ã‚‹"
+ "(mail=%v*))" "é›»å­ãƒ¡ãƒ¼ãƒ« アドレスã®å…ˆé ­æ–‡å­—ã«ä¸€è‡´ã™ã‚‹"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "åã®é ­æ–‡å­—ã¨åå‰ã«ä¸€è‡´ã™ã‚‹"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "åå‰ã¨å§“ã®é ­æ–‡å­—ã«ä¸€è‡´ã™ã‚‹"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "é¡žä¼¼ã—ã¦ã„ã‚‹ã‹ã€å«ã¾ã‚Œã‚‹"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(uid=*)))" "åå‰ã¾ãŸã¯ãƒ¦ãƒ¼ã‚¶IDã«ä¸€è‡´ã™ã‚‹"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)(uid=%v1)))" "åå‰ã¾ãŸã¯ãƒ¦ãƒ¼ã‚¶IDã«ä¸€è‡´ã™ã‚‹"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "é¡žä¼¼ã—ã¦ã„ã‚‹ã‹ã€å«ã¾ã‚Œã‚‹"
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "LDAPフィルタ: "
+
+ "^\*$" " " "(cn=*))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+
+ ".*" ". _" "(cn=%v1-))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+ "(cn=*%v1-*))" "å«ã¾ã‚Œã‚‹"
+ "(cn~=%v1-))" "é¡žä¼¼ã—ãŸ"
+
+"dsgw-ntgroups"
+ "=" " " "(%v))" "LDAPフィルタ: "
+
+ "^\*$" " " "(cn=*))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+
+ ".*" ". _" "(cn=%v1-))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+ "(cn=*%v1-*))" "å«ã¾ã‚Œã‚‹"
+ "(cn~=%v1-))" "é¡žä¼¼ã—ãŸ"
+ "(ntgroupdomainid=%v:*))" "NTドメインåã«ä¸€è‡´ã™ã‚‹"
+ "(ntgroupdomainid=*:%v))" "NTグループã«ä¸€è‡´ã™ã‚‹"
+
+"dsgw-organizations"
+ "=" " " "(%v))" "LDAPフィルタ: "
+
+ "\." " " "(associatedDomain=%v))" "関連ドメインã«ä¸€è‡´ã™ã‚‹"
+
+ "^\*$" " " "(o=*))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+
+ ".*" " " "(o=%v))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+ "(o=*%v*))" "å«ã¾ã‚Œã‚‹"
+ "(o~=%v))" "é¡žä¼¼ã—ãŸ"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "LDAPフィルタ: "
+
+ "\." " " "(associatedDomain=%v))" "関連ドメインã«ä¸€è‡´ã™ã‚‹"
+
+ "^\*$" " " "(ou=*))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+
+ ".*" " " "(ou=%v))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+ "(ou=*%v*))" "å«ã¾ã‚Œã‚‹"
+ "(ou~=%v))" "é¡žä¼¼ã—ãŸ"
+
+"dsgw-anything"
+ "=" " " "(%v)" "LDAPフィルタ: "
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)(o=%v1-)(ou=%v1-))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+ "(|(sn~=%v1-)(cn~=%v1-)(o=%v1-)(ou=%v1-))" "é¡žä¼¼ã—ãŸ"
+
+ "^\*$" " " "(|(cn=*)(sn=*)(o=*)(ou=*))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)(o=%v1)(ou=%v1))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)(o=%v1)(ou=%v1))" "é¡žä¼¼ã—ã¦ã„ã‚‹ã‹ã€å«ã¾ã‚Œã‚‹"
+
+
+"dsgw-ntpeople"
+ "=" " " "(%v))" "LDAPフィルタ: "
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "電話番å·ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹"
+
+ "@" " " "(mail=%v))" "é›»å­ãƒ¡ãƒ¼ãƒ« アドレスã«ä¸€è‡´ã™ã‚‹"
+ "(mail=%v*))" "é›»å­ãƒ¡ãƒ¼ãƒ« アドレスã®å…ˆé ­æ–‡å­—ã«ä¸€è‡´ã™ã‚‹"
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "åã®é ­æ–‡å­—ã¨åå‰ã«ä¸€è‡´ã™ã‚‹"
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "åå‰ã¨å§“ã®é ­æ–‡å­—ã«ä¸€è‡´ã™ã‚‹"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "é¡žä¼¼ã—ã¦ã„ã‚‹ã‹ã€å«ã¾ã‚Œã‚‹"
+
+ "^\*$" " " "(|(cn=*)(sn=*)))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+
+ ".*" ". " "(|(cn=%v1)(sn=%v1)))" "åå‰ã«ä¸€è‡´ã™ã‚‹"
+ "(ntuserlogonserver=%v))" "NT ログオンサーãƒã«ä¸€è‡´ã™ã‚‹"
+ "(ntuserdomainid=%v:*))" "NTドメインåã«ä¸€è‡´ã™ã‚‹"
+ "(ntuserdomainid=*:%v))" "NTユーザåã«ä¸€è‡´ã™ã‚‹"
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "é¡žä¼¼ã—ã¦ã„ã‚‹ã‹ã€å«ã¾ã‚Œã‚‹"
+
+# Do not remove this line, or place any directives after it.
diff --git a/ldap/clients/dsgw/config/ja/dsgwfilter_adm.conf b/ldap/clients/dsgw/config/ja/dsgwfilter_adm.conf
new file mode 100644
index 00000000..87d50406
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/dsgwfilter_adm.conf
@@ -0,0 +1,73 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# ldap filter file
+#
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The <desc> should describe the filter. It should correctly complete
+# the phrases (in the resource database) DBT_Found0EntriesWhere_,
+# DBT_Found1EntryWhere_ and DBT_FoundEntriesWhere_; for example (en):
+#
+# Found 1 entry where the <desc> '%v'.
+# Found no entries where the <desc> '%v'.
+# Found 3 entries where the <desc> '%v'.
+#
+# The <desc> should begin with the article ("the" in English) for
+# languages that require agreement between article and noun (e.g
+# genders in Spanish or French).
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+
+#
+# Directory Server gateway - for Netscape Admin Server
+#
+
+"dsgw-people"
+ "=" " " "(%v))" "LDAPフィルタ: "
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v))" "電話番å·ã®æœ«å°¾: "
+
+ "@" " " "(mail=%v))" " é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹: "
+ "(mail=%v*))" "é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã®å…ˆé ­æ–‡å­—: "
+
+ "^.[. _].*" ". _" "(cn=%v1* %v2-))" "åã®é ­æ–‡å­—ã¨åå‰: "
+
+ ".*[. _].$" ". _" "(cn=%v1-*))" "åå‰ã¨è‹—å­—ã®é ­æ–‡å­—: "
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)))" "åå‰: "
+ "(|(cn=*%v1-*)(sn=*%v1-*)(cn~=%v1-)(sn~=%v1-)))" "åå‰ sounds like or contains"
+
+ ".*" ". " "(uid=%v1))" "ログインID: "
+ "(|(cn=%v1)(sn=%v1)))" "åå‰: "
+ "(|(cn=*%v1*)(sn=*%v1*)(cn~=%v1)(sn~=%v1)))" "次ã«é¡žä¼¼ã—ãŸåå‰ã¾ãŸã¯ãれをå«ã‚€åå‰: "
+
+
+"dsgw-groups"
+ "=" " " "(%v))" "LDAPフィルタ: "
+
+ ".*" ". _" "(cn=%v1-))" "åå‰: "
+ "(cn~=%v1-))" "u次ã«é¡žä¼¼ã—ãŸåå‰"
+
+"dsgw-orgunits"
+ "=" " " "(%v))" "LDAPフィルタ: "
+
+ ".*" ". _" "(ou=%v1-))" "å˜ä½å:"
+ "(ou~=%v1-))" "次ã«é¡žä¼¼ã—ãŸå˜ä½å: "
+
+#Do not remove this line, or place any additional lines after it.
diff --git a/ldap/clients/dsgw/config/ja/dsgwsearchprefs.conf b/ldap/clients/dsgw/config/ja/dsgwsearchprefs.conf
new file mode 100644
index 00000000..14146ae9
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/dsgwsearchprefs.conf
@@ -0,0 +1,213 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# dsgwsearchprefs.conf - directory server gateway search object definitions
+
+
+# the current version of this file format is 1
+Version 1
+
+
+# Name for this search object
+People
+# options (the only one supported right now is "internal" which means that
+# this search object should not be presented directly to the user)
+# use "" for none
+""
+# Label to place before text box user types in
+"検索対象:"
+# Filter prefix to append to all searches
+"(&(objectClass=person)"
+# Tag to use for "Fewer Choices" searches - from ldapfilter.conf file
+"dsgw-people"
+# If a search results in > 1 match, retrieve this attribute to help
+# user disambiguate the entries...
+not-used-by-dsgw
+# ...and label it with this string:
+not-used-by-dsgw
+# Search scope to use when searching
+subtree
+# Follows a list of "More Choices" search options. Format is:
+# Label, attribute, select-bitmap, extra attr display name, extra attr ldap name
+# If last two are null, "Fewer Choices" name/attributes used.
+# Label should begin with the article ("the" in English) for
+# languages that require agreement between article and noun
+# (e.g genders in Spanish or French).
+"æ°å" cn 111111 "" ""
+"姓" sn 111111 "" ""
+"電話番å·" "telephoneNumber" 111011 "" ""
+"é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹" "mail" 111111 "" ""
+"ユーザID" "uid" 111111 "" ""
+"å½¹è·" title 111111 "" ""
+END
+# Match types
+"ã«ä¸€è‡´ã™ã‚‹" "(%a=%v))"
+"ã«ä¸€è‡´ã—ãªã„" "(!(%a=%v)))"
+"ã«é¡žä¼¼ã™ã‚‹" "(%a~=%v))"
+"ã®å…ˆé ­ã«ä¸€è‡´ã™ã‚‹" "(%a=%v*))"
+"ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹" "(%a=*%v))"
+"ã«å«ã¾ã‚Œã‚‹" "(%a=*%v*))"
+END
+
+
+"NT-People"
+""
+"検索対象:"
+"(&(objectClass=ntuser)"
+"dsgw-ntpeople"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"æ°å" cn 111111 "" ""
+"姓" sn 111111 "" ""
+"電話番å·" "telephoneNumber" 111011 "" ""
+"é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹" "mail" 111111 "" ""
+"ユーザID" "uid" 111111 "" ""
+"å½¹è·" title 111111 "" ""
+"NTユーザå" "ntuserdomainid" 110000 "" ""
+"NTドメイン" "ntuserdomainid" 101000 "" ""
+"NT ログオンサーãƒ" "ntuserlogonserver" 111111 "" ""
+END
+"ã«ä¸€è‡´ã™ã‚‹" "(%a=%v))"
+"ã«ä¸€è‡´ã—ãªã„" "(!(%a=%v)))"
+"ã«é¡žä¼¼ã™ã‚‹" "(%a~=%v))"
+"ã®å…ˆé ­ã«ä¸€è‡´ã™ã‚‹" "(%a=%v*))"
+"ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹" "(%a=*%v))"
+"ã«å«ã¾ã‚Œã‚‹" "(%a=*%v*))"
+END
+
+Groups
+""
+"検索対象:"
+"(&(|(objectClass=rfc822MailGroup)(objectClass=groupOfNames)(objectClass=groupOfUniqueNames)(objectClass=groupOfCertificates))"
+"dsgw-groups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"åå‰" cn 111111 "" ""
+"説明" description 111111 "" ""
+"所有者 (DN)" "owner" 000011 "owner" "Owner"
+"メンãƒãƒ¼ (DN)" "member" 000011 "" ""
+END
+"ã«ä¸€è‡´ã™ã‚‹" "(%a=%v))"
+"ã«ä¸€è‡´ã—ãªã„" "(!(%a=%v)))"
+"ã«é¡žä¼¼ã™ã‚‹" "(%a~=%v))"
+"ã®å…ˆé ­ã«ä¸€è‡´ã™ã‚‹" "(%a=%v*))"
+"ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹" "(%a=*%v))"
+"ã«å«ã¾ã‚Œã‚‹" "(%a=*%v*))"
+END
+
+
+NT-Groups
+""
+"検索対象:"
+"(&(objectClass=ntGroup)"
+"dsgw-ntgroups"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"åå‰" cn 111111 "" ""
+"NTグループå" "ntgroupdomainid" 110000 "" ""
+"NTドメインå" "ntgroupdomainid" 101000 "" ""
+"説明" description 111111 "" ""
+"所有者 (DN)" "owner" 000011 "owner" "Owner"
+"メンãƒãƒ¼ (DN)" "uniquemember" 000011 "" ""
+END
+"ã«ä¸€è‡´ã™ã‚‹" "(%a=%v))"
+"ã«ä¸€è‡´ã—ãªã„" "(!(%a=%v)))"
+"ã«é¡žä¼¼ã™ã‚‹" "(%a~=%v))"
+"ã®å…ˆé ­ã«ä¸€è‡´ã™ã‚‹" "(%a=%v*))"
+"ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹" "(%a=*%v))"
+"ã«å«ã¾ã‚Œã‚‹" "(%a=*%v*))"
+END
+
+
+Organizations
+""
+"検索対象:"
+"(&(objectClass=organization)"
+"dsgw-organizations"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"åå‰" o 111111 "" ""
+"場所" l 111111 "" ""
+"電話番å·" telephoneNumber 111011 "" ""
+"説明" description 111011 "" ""
+END
+"ã«ä¸€è‡´ã™ã‚‹" "(%a=%v))"
+"ã«ä¸€è‡´ã—ãªã„" "(!(%a=%v)))"
+"ã«é¡žä¼¼ã™ã‚‹" "(%a~=%v))"
+"ã®å…ˆé ­ã«ä¸€è‡´ã™ã‚‹" "(%a=%v*))"
+"ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹" "(%a=*%v))"
+"ã«å«ã¾ã‚Œã‚‹" "(%a=*%v*))"
+END
+
+
+"Org-Units"
+""
+"検索対象:"
+"(&(objectClass=organizationalUnit)"
+"dsgw-orgunits"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"åå‰" ou 111111 "" ""
+"場所" l 111111 "" ""
+"電話番å·" telephoneNumber 111011 "" ""
+"説明" description 111111 "" ""
+END
+"ã«ä¸€è‡´ã™ã‚‹" "(%a=%v))"
+"ã«ä¸€è‡´ã—ãªã„" "(!(%a=%v)))"
+"ã«é¡žä¼¼ã™ã‚‹" "(%a~=%v))"
+"ã®å…ˆé ­ã«ä¸€è‡´ã™ã‚‹" "(%a=%v*))"
+"ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹" "(%a=*%v))"
+"ã«å«ã¾ã‚Œã‚‹" "(%a=*%v*))"
+END
+
+Anything
+""
+"検索対象:"
+""
+"dsgw-anything"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"一般å" cn 111111 "" ""
+"説明" description 111111 "" ""
+END
+"ã«ä¸€è‡´ã™ã‚‹" "(%a=%v)"
+"ã«ä¸€è‡´ã—ãªã„" "(!(%a=%v))"
+"ã«é¡žä¼¼ã™ã‚‹" "(%a~=%v)"
+"ã®å…ˆé ­ã«ä¸€è‡´ã™ã‚‹" "(%a=%v*)"
+"ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹" "(%a=*%v)"
+"ã«å«ã¾ã‚Œã‚‹" "(%a=*%v*)"
+END
+
+
+Auth
+internal
+"èªè¨¼ã®ç¨®åˆ¥:"
+"(&(objectClass=person)"
+"dsgw-people"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"一般å" cn 111111 "" ""
+"姓" sn 111111 "" ""
+"電話番å·" "telephoneNumber" 111011 "" ""
+"é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹" "mail" 111111 "" ""
+"ユーザID" "uid" 111111 "" ""
+"å½¹è·" title 111111 "" ""
+END
+"ã«ä¸€è‡´ã™ã‚‹" "(%a=%v))"
+"ã«ä¸€è‡´ã—ãªã„" "(!(%a=%v)))"
+"ã«é¡žä¼¼ã™ã‚‹" "(%a~=%v))"
+"ã®å…ˆé ­ã«ä¸€è‡´ã™ã‚‹" "(%a=%v*))"
+"ã®æœ«å°¾ã«ä¸€è‡´ã™ã‚‹" "(%a=*%v))"
+"ã«å«ã¾ã‚Œã‚‹" "(%a=*%v*))"
+END
+
diff --git a/ldap/clients/dsgw/config/ja/edit-passwd.html b/ldap/clients/dsgw/config/ja/edit-passwd.html
new file mode 100644
index 00000000..f756a121
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/edit-passwd.html
@@ -0,0 +1,78 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- change a directory entry's password -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Change Password -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+</HEAD>
+
+<!-- BODY -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<H2><CENTER>パスワード変更
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</H2></CENTER>
+
+<HR>
+
+<P>
+<TABLE>
+
+<!-- IF "BoundAsThisEntry" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+å¤ã„パスワードを入力:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ELIF "!Bound" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+å¤ã„パスワードを入力:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ENDIF //BoundAsThisEntry -->
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+æ–°è¦ãƒ‘スワードを入力:
+</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD></TR>
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+確èªã®ãŸã‚æ–°è¦ãƒ‘スワードをå†åº¦å…¥åŠ›:
+</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+</TABLE>
+
+<P>
+
+<TABLE BORDER=2 WIDTH="100%">
+<TR>
+<TD ALIGN="center" WIDTH="50%">
+<!-- IF "BoundAsThisEntry" -->
+<!-- DS_SAVEBUTTON "label=パスワード変更" -->
+<!-- ELSE -->
+<!-- DS_SAVEBUTTON "label=パスワードä¿ç®¡" -->
+<!-- ENDIF -->
+<TD ALIGN="center" WIDTH="50%">
+<!-- DS_HELPBUTTON "topic=MODIFYPASSWD" -->
+</TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-Anything.html b/ldap/clients/dsgw/config/ja/list-Anything.html
new file mode 100644
index 00000000..2bdf2531
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-Anything.html
@@ -0,0 +1,42 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "汎用検索" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>åå‰ <TH NOWRAP>電話番å·
+<TH NOWRAP>é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ <TH NOWRAP>記述
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+別ã®æ¤œç´¢ã‚’試ã¿ã¦ãã ã•ã„。
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-Auth.html b/ldap/clients/dsgw/config/ja/list-Auth.html
new file mode 100644
index 00000000..0aaa8454
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-Auth.html
@@ -0,0 +1,73 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Authenticate as..." -->
+
+<!--
+ The "authForm" form and the authSubmit() JavaScript function are
+ used to avoid the need for a separate form for each entry listed.
+ Each entry is tied to this single form through the magic of an
+ anchor that contains href=javascript:authSubmit().
+-->
+
+<FORM NAME="authForm" METHOD=POST ACTION="auth">
+<INPUT TYPE="hidden" NAME="escapedbinddn">
+<INPUT TYPE="hidden" NAME="authdesturl"
+<!-- PCONTEXT -->
+<!-- DS_POSTEDVALUE "name=authdesturl" "within=VALUE=%22--value--%22" -->
+>
+</FORM>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function authSubmit(encodeddn)
+{
+ document.authForm.escapedbinddn.value = encodeddn;
+ document.authForm.submit();
+}
+// End hiding -->
+</SCRIPT>
+
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC "VERBOSE" -->
+<P>
+<!-- IF "FoundEntries" -->
+èªè¨¼ã«ä½¿ç”¨ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªåをクリックã—ã¦ãã ã•ã„。
+</FONT>
+<P>
+
+<TABLE BORDER=1 CELLPADDING=4>
+<TR>
+<TH NOWRAP>èªè¨¼ã®ç¨®åˆ¥ <TH NOWRAP>å½¹è·
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:authSubmit('--value--'); onMouseOver=%22window.status='Click to authenticate'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+<!-- ELSE "FoundEntries" -->
+å…ƒã«æˆ»ã£ã¦å†å®Ÿè¡Œã—ã¦ãã ã•ã„。
+<!-- ENDIF "FoundEntries" -->
+</CENTER>
+
+<FORM>
+<TABLE BORDER=2 WIDTH=100%%>
+<TR>
+<TD ALIGN=center width=50%%>
+<INPUT TYPE="button" VALUE="å‰ã¸" onClick="history.back();">
+<TD ALIGN=center WIDTH=50%%>
+<!-- DS_HELPBUTTON "topic=AUTHMULTMATCH" -->
+</TABLE>
+</FORM>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-Groups.html b/ldap/clients/dsgw/config/ja/list-Groups.html
new file mode 100644
index 00000000..8e04d2f3
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-Groups.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "グループã®æ¤œç´¢" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>グループå
+<TH NOWRAP>記述
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+別ã®æ¤œç´¢ã‚’試ã¿ã¦ãã ã•ã„。
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-NT-Groups.html b/ldap/clients/dsgw/config/ja/list-NT-Groups.html
new file mode 100644
index 00000000..aa554e77
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-NT-Groups.html
@@ -0,0 +1,44 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for NT Groups" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>LDAP グループå
+<TH NOWRAP>NTドメインå
+<TH NOWRAP>NTグループå
+<TH NOWRAP>記述
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntdomain" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntgroupname" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+別ã®æ¤œç´¢ã‚’試ã¿ã¦ãã ã•ã„。
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-NT-People.html b/ldap/clients/dsgw/config/ja/list-NT-People.html
new file mode 100644
index 00000000..45eab117
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-NT-People.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for NT-People" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>åå‰<TH NOWRAP>NTドメイン<TH NOWRAP>NTユーザå<TH NOWRAP>電話番å·
+</TR>
+
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "label=" -->
+ onMouseOver="window.status='ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®è©³ç´°ã‚’表示ã™ã‚‹ã«ã¯ã“ã“をクリックã—ã¦ãã ã•ã„。'; return true">
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=0" "defaultvalue=name" "options=readonly" -->
+</A>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntdomain" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntuserid" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+別ã®æ¤œç´¢ã‚’試ã¿ã¦ãã ã•ã„。
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-Org-Units.html b/ldap/clients/dsgw/config/ja/list-Org-Units.html
new file mode 100644
index 00000000..2dfdaac0
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-Org-Units.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for Organizational Units" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>æ©Ÿé–¢å˜ä½ <TH>記述 <TH>電話番å·
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+別ã®æ¤œç´¢ã‚’試ã¿ã¦ãã ã•ã„。
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-Organizations.html b/ldap/clients/dsgw/config/ja/list-Organizations.html
new file mode 100644
index 00000000..7cdee961
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-Organizations.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for Organizations" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>æ©Ÿé–¢ <TH>記述 <TH>電話番å·
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=description" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+別ã®æ¤œç´¢ã‚’試ã¿ã¦ãã ã•ã„。
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-People.html b/ldap/clients/dsgw/config/ja/list-People.html
new file mode 100644
index 00000000..48c41d5b
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-People.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR>
+<TH NOWRAP>åå‰<TH NOWRAP>電話番å·<TH NOWRAP>é›»å­ãƒ¡ãƒ¼ãƒ« アドレス<TH NOWRAP>å½¹è·
+</TR>
+
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "label=" -->
+ onMouseOver="window.status='Click here to view this entry in detail'; return true">
+<!-- DS_ATTRIBUTE "attr=cn" "numfields=0" "defaultvalue=name" "options=readonly" -->
+</A>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+</TR>
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+別ã®æ¤œç´¢ã‚’試ã¿ã¦ãã ã•ã„。
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-fa-Groups.html b/ldap/clients/dsgw/config/ja/list-fa-Groups.html
new file mode 100644
index 00000000..bbc2e00a
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-fa-Groups.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-fa-People.html b/ldap/clients/dsgw/config/ja/list-fa-People.html
new file mode 100644
index 00000000..bbc2e00a
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-fa-People.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "Search for People" -->
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/list-urlsearch.html b/ldap/clients/dsgw/config/ja/list-urlsearch.html
new file mode 100644
index 00000000..379d7b79
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/list-urlsearch.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- TITLE "URLã«åŸºã¥ã„ãŸæ¤œç´¢" -->
+<CENTER><FONT SIZE=+1>
+<!-- DS_SEARCHDESC -->
+</FONT></CENTER>
+<P>
+
+<!-- IF "FoundEntries" -->
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=100%>
+<TR><TH>åå‰ <TH>é›»è©±ç•ªå· <TH>é›»å­ãƒ¡ãƒ¼ãƒ« アドレス
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+<TD>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+
+<!-- ELSE -->
+<P>
+<CENTER><FONT SIZE=+1>
+別ã®æ¤œç´¢ã‚’試ã¿ã¦ãã ã•ã„。
+</FONT></CENTER>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/ja/newentry.html b/ldap/clients/dsgw/config/ja/newentry.html
new file mode 100644
index 00000000..1c2dcd17
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/newentry.html
@@ -0,0 +1,26 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentry.html-->
+<TITLE>Netscape Directory Server Gateway: New Entry </TITLE>
+<!-- DS_NEWENTRY_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=75,70,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=newentrytitle.html" NORESIZE SCROLLING="NO">
+ <FRAME SRC="newentry?<!-- GCONTEXT -->&file=type"
+ NAME="newentryTypeFrame" SCROLLING="NO">
+ <FRAME SRC="newentry?<!-- GCONTEXT -->&file=name"
+ NAME="newentryNameFrame">
+</FRAMESET>
+
+<NOFRAMES>
+<BODY>
+ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’表示ã™ã‚‹ã«ã¯ãƒ•ãƒ¬ãƒ¼ãƒ ã‚’サãƒãƒ¼ãƒˆã™ã‚‹ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãŒå¿…è¦ã§ã™ã€‚
+</BODY>
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/config/ja/newentryName.html b/ldap/clients/dsgw/config/ja/newentryName.html
new file mode 100644
index 00000000..7c050a71
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/newentryName.html
@@ -0,0 +1,48 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentryName.html-->
+</HEAD>
+<!-- DS_NEWENTRY_NAME_BODY -->
+<p>
+<!-- DS_NEWENTRY_NAME_FORM -->
+<font SIZE="+2">ステップ 2.</font>
+æ–°è¦ã®ã‚¨ãƒ³ãƒˆãƒªåを入力ã—ã¾ã™ã€‚
+<!-- EVALUATE "entType.fullname" -->
+.
+<p><nobr><font SIZE="+1">
+<!-- EVALUATE "entType.rdnattr" -->
+=</font>
+<input TYPE="text" NAME="entryname" SIZE="40">
+</nobr>
+<p>
+<font SIZE="+2">ステップ 3.</font>
+
+<!-- DS_NEWENTRY_LOCATION_BEGIN -->
+ãƒãƒƒãƒ—アップメニューã‹ã‚‰ Directory ã®å ´æ‰€ã‚’é¸æŠžã—ã¾ã™ã€‚
+<!-- EVALUATE "entType.fullname" -->
+. [ãã®ä»–]ã‚’é¸æŠžã™ã‚‹å ´åˆã¯ã€ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ å ´æ‰€ã«ã€å®Œå…¨è­˜åˆ¥åを入力ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚
+<p>
+<!-- DS_NEWENTRY_LOCATION_SELECT -->
+<OPTION VALUE="">[ãã®ä»–]</OPTION>
+</SELECT>
+<input TYPE="text" NAME="dnsuffix" SIZE="70" onFocus="parent.dnsuffixFocus(this.form)">
+<p>
+<font SIZE="+2">ステップ 4.</font>
+<!-- DS_NEWENTRY_LOCATION_END -->
+
+[次ã¸]をクリックã—ã¦ãã ã•ã„。ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®ä¿®æ­£å¯èƒ½ãªãƒ“ューãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚情報ã®å…¥åŠ›ãŒçµ‚ã‚ã£ãŸã‚‰ã€ã‚¨ãƒ³ãƒˆãƒªã‚’ä¿å­˜ã—ã¾ã™ã€‚
+<p>
+<center><table BORDER="2" WIDTH="75%">
+<tr><td ALIGN="center" WIDTH="50%">
+<input TYPE="submit" VALUE="次ã¸">
+<td ALIGN="center" WIDTH="50%">
+
+<!-- DS_HELP_BUTTON "ADDING" -->
+</table></center></form>
+</body></HTML>
diff --git a/ldap/clients/dsgw/config/ja/newentryType.html b/ldap/clients/dsgw/config/ja/newentryType.html
new file mode 100644
index 00000000..cee042f2
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/newentryType.html
@@ -0,0 +1,14 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!--newentryType.html-->
+<!-- DS_NEWENTRY_TYPE_BODY -->
+<!-- DS_NEWENTRY_TYPE_FORM -->
+<font SIZE="+2">ステップ 1.</font>
+作æˆã™ã‚‹ã‚¨ãƒ³ãƒˆãƒª タイプをé¸æŠžã—ã¾ã™ã€‚
+<!-- DS_NEWENTRY_TYPE_SELECT -->
+</form></body></HTML>
diff --git a/ldap/clients/dsgw/config/ja/search.html b/ldap/clients/dsgw/config/ja/search.html
new file mode 100644
index 00000000..4fa66cf8
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/search.html
@@ -0,0 +1,18 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- search.html -->
+<TITLE>Netscape Directory Server Gateway: Standard Search </TITLE>
+<!-- DS_SEARCH_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=75,100,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=searchtitle.html" SCROLLING="NO">
+ <FRAME SRC="search?<!-- GCONTEXT -->&file=string" NAME=searchFrame NORESIZE SCROLLING="NO">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=greeting.html" NAME=outputFrame>
+</FRAMESET>
+</HTML>
diff --git a/ldap/clients/dsgw/config/ja/searchString.html b/ldap/clients/dsgw/config/ja/searchString.html
new file mode 100644
index 00000000..ab24d048
--- /dev/null
+++ b/ldap/clients/dsgw/config/ja/searchString.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- searchString.html -->
+</HEAD>
+<!-- DS_SEARCH_BODY -->
+<!-- DS_SEARCH_FORM "target=outputFrame" -->
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=0 WIDTH=100%>
+<TR><TH ALIGN=RIGHT>検索:</TH><TD>
+<!-- DS_SEARCH_TYPE -->
+</TD>
+<TH>存在ã™ã‚‹å ´æ‰€:</TH><TD>
+<!-- DS_SEARCH_BASE -->
+</TD></TR>
+<TR><TH ALIGN=RIGHT>検索対象: </TH>
+<TD COLSPAN=3>
+<INPUT NAME="searchstring" SIZE=30>
+<INPUT TYPE="SUBMIT" VALUE="検索">&nbsp;&nbsp;
+<!-- DS_HELP_BUTTON "SMARTSEARCH" -->
+</TD></TR>
+</TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM></BODY></HTML>
diff --git a/ldap/clients/dsgw/config/ko/dsgw-l10n.conf b/ldap/clients/dsgw/config/ko/dsgw-l10n.conf
new file mode 100644
index 00000000..0482312b
--- /dev/null
+++ b/ldap/clients/dsgw/config/ko/dsgw-l10n.conf
@@ -0,0 +1,18 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# Note: the sample part should have double #'s for L10n.
+## translate People <People_translated_in_lang>
+## translate NT-People <NT-People_translated_in_lang>
+## translate Groups <Groups_translated_in_lang>
+## translate NT-Groups <NT-Groups_translated_in_lang>
+## translate Organizations <Organizations_translated_in_lang>
+## translate Org-Units <Org-Units_translated_in_lang>
+## translate Anything <Anything_translated_in_lang>
diff --git a/ldap/clients/dsgw/config/ko/dsgwcharset.conf b/ldap/clients/dsgw/config/ko/dsgwcharset.conf
new file mode 100644
index 00000000..f42c2b31
--- /dev/null
+++ b/ldap/clients/dsgw/config/ko/dsgwcharset.conf
@@ -0,0 +1,7 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+euc-kr
diff --git a/ldap/clients/dsgw/config/list-Anything.html b/ldap/clients/dsgw/config/list-Anything.html
new file mode 100644
index 00000000..50581f96
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-Anything.html
@@ -0,0 +1,120 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<TITLE>Search for Anything</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</head>
+<BODY BGCOLOR="white">
+
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" class="bgColor4" align="center">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+<!-- DS_SEARCHDESC -->
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="#FFFFFF" align="center">
+ <tr align="left" bgcolor="#CCCCCC">
+ <td class="boldbig">
+ Name
+ </td>
+ <td class="boldbig">
+ Phone
+ </td>
+ <td class="boldbig">
+ E-mail
+ </td>
+ <td class="boldbig">
+ Description
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+ </td>
+
+ <td>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=description" -->
+ </td>
+ </tr>
+ <tr>
+ <td colspan="4"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+
+</table>
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+ Click on an entry's Name to bring up more information about that entry.
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+<TABLE width=360 height=216 border=1 bgcolor=#CCCCCC align=center>
+ <TR valign=top>
+ <TD>
+<TABLE width=356 border=0 cellpadding=18 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD>
+ <CENTER>
+ <TABLE width=320 border=0 height=168 cellpadding=0 cellspacing=0 class="bgColor4">
+ <TR valign=top>
+ <TD width=32>
+ <IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=message.gif" height=32 width=32 border=0>
+ </TD>
+ <TD width=9>
+ &nbsp;
+ </TD>
+ <TD>
+ <P>
+ No match found.
+ </P>
+ </TD>
+ </TR>
+ <TR valign=top>
+ <TD colspan=2>
+ </TD>
+ <TD>
+ <P>
+ No entries match the requested search term. Please try a different search.
+ </P>
+ </TD>
+ </TR>
+ </TABLE>
+ </CENTER>
+ </TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+</TABLE>
+ </center>
+</p>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/list-Auth.html b/ldap/clients/dsgw/config/list-Auth.html
new file mode 100644
index 00000000..b2bb8332
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-Auth.html
@@ -0,0 +1,78 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!--
+ The "authForm" form and the authSubmit() JavaScript function are
+ used to avoid the need for a separate form for each entry listed.
+ Each entry is tied to this single form through the magic of an
+ anchor that contains href=javascript:authSubmit().
+-->
+
+<!-- HEAD -->
+<TITLE>Authenticate as...</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</head>
+<BODY BGCOLOR="white">
+
+<FORM NAME="authForm" METHOD=POST ACTION="auth">
+<INPUT TYPE="hidden" NAME="escapedbinddn">
+<INPUT TYPE="hidden" NAME="authdesturl"
+<!-- DS_POSTEDVALUE "name=authdesturl" "within=VALUE=%22--value--%22" -->
+>
+<!-- PCONTEXT -->
+</FORM>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function authSubmit(encodeddn)
+{
+ document.authForm.escapedbinddn.value = encodeddn;
+ document.authForm.submit();
+}
+// End hiding -->
+</SCRIPT>
+
+<CENTER>
+<!-- DS_SEARCHDESC "VERBOSE" -->
+<P>
+<!-- IF "FoundEntries" -->
+Please click on the name of the entry you would like to use for authentication.
+</P>
+<P>
+
+<TABLE BORDER=1 CELLPADDING=4>
+<TR>
+<TD NOWRAP bgcolor="#CCCCCC" class="boldbig">Authenticate As </td><TD NOWRAP bgcolor="#CCCCCC" class="boldbig">Title</th>
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:authSubmit('--value--'); onMouseOver=%22window.status='Click to authenticate'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+<!-- ELSE "FoundEntries" -->
+<div class="text22">Please go back and try again.</div>
+<!-- ENDIF "FoundEntries" -->
+</CENTER>
+
+<FORM>
+<TABLE BORDER=2 WIDTH=100%%>
+<TR>
+<TD ALIGN=center width=50%%>
+<INPUT TYPE="button" VALUE="Go Back" onClick="history.back();">
+<TD ALIGN=center WIDTH=50%%>
+<!-- DS_HELPBUTTON "topic=AUTHMULTMATCH" -->
+</TABLE>
+</FORM>
+</body>
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/list-Domaincomponent.html b/ldap/clients/dsgw/config/list-Domaincomponent.html
new file mode 100644
index 00000000..3eb08d18
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-Domaincomponent.html
@@ -0,0 +1,115 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>Search for Domaincomponents</TITLE>
+</head>
+<BODY BGCOLOR="white">
+
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" class="bgColor4" align="center">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+<!-- DS_SEARCHDESC -->
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+
+<table border="0" cellpadding="1" cellspacing="0" width="100%" class="bgColor4" align="center">
+ <tr align="left" bgcolor="#CCCCCC">
+ <td class="boldbig">
+ Domaincomponent
+ </td>
+ <td class="boldbig">
+ Description
+ </td>
+ <td class="boldbig">
+ Phone
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td >
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+ </td>
+ <td >
+<!-- DS_ATTRIBUTE "attr=description" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+
+</table>
+
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+ Click on an domaincomponent's name to bring up more information about that entry.
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+<TABLE width=360 height=216 border=1 bgcolor=#CCCCCC align=center>
+ <TR valign=top>
+ <TD>
+<TABLE width=356 border=0 cellpadding=18 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD>
+ <CENTER>
+ <TABLE width=320 border=0 height=168 cellpadding=0 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD width=32>
+ <IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=message.gif" height=32 width=32 border=0>
+ </TD>
+ <TD width=9>
+ &nbsp;
+ </TD>
+ <TD>
+ <P>
+ No match found.
+ </P>
+ </TD>
+ </TR>
+ <TR valign=top>
+ <TD colspan=2>
+ </TD>
+ <TD>
+ <P>
+ No entries match the requested search term. Please try a different search.
+ </P>
+ </TD>
+ </TR>
+ </TABLE>
+ </CENTER>
+ </TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+</TABLE>
+ </center>
+</p>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/list-Groups.html b/ldap/clients/dsgw/config/list-Groups.html
new file mode 100644
index 00000000..4b4c3825
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-Groups.html
@@ -0,0 +1,110 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>Search for Groups</TITLE>
+</head>
+
+<BODY BGCOLOR="white">
+
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" bgcolor="#CCCCCC" align="center">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+<!-- DS_SEARCHDESC -->
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="#FFFFFF" align="center">
+ <tr align="left" bgcolor="#CCCCCC">
+ <td class="boldbig">
+ Group Name
+ </td>
+ <td class="boldbig">
+ Description
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td >
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->&nbsp;
+ </td>
+ <td >
+<!-- DS_ATTRIBUTE "attr=description" -->
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+
+</table>
+
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+ Click on a Group's Name to bring up more information about that entry.
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+<TABLE width=360 height=216 border=1 bgcolor=#CCCCCC align=center>
+ <TR valign=top>
+ <TD>
+<TABLE width=356 border=0 cellpadding=18 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD>
+ <CENTER>
+ <TABLE width=320 border=0 height=168 cellpadding=0 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD width=32>
+ <IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=message.gif" height=32 width=32 border=0>
+ </TD>
+ <TD width=9>
+ &nbsp;
+ </TD>
+ <TD>
+ <P>
+ No match found.
+ </P>
+ </TD>
+ </TR>
+ <TR valign=top>
+ <TD colspan=2>
+ </TD>
+ <TD>
+ <P>
+ No entries match the requested search term. Please try a different search.
+ </P>
+ </TD>
+ </TR>
+ </TABLE>
+ </CENTER>
+ </TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+</TABLE>
+ </center>
+</p>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/list-NT-Groups.html b/ldap/clients/dsgw/config/list-NT-Groups.html
new file mode 100644
index 00000000..4e948551
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-NT-Groups.html
@@ -0,0 +1,119 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>Search for NT Groups</TITLE>
+</head>
+
+<BODY BGCOLOR="white">
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" bgcolor="#CCCCCC" align="center">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+<!-- DS_SEARCHDESC -->
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="#FFFFFF" align="center">
+ <tr align="left" bgcolor="#CCCCCC">
+ <td class="boldbig">
+ LDAP Group Name
+ </td>
+ <td class="boldbig">
+ NT Domain Name
+ </td>
+ <td class="boldbig">
+ NT Group Name
+ </td>
+ <td class="boldbig">
+ Description
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td >
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+ </td>
+ <td >
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntdomain" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=ntgroupdomainid" "syntax=ntgroupname" -->
+ </td>
+ <td >
+<!-- DS_ATTRIBUTE "attr=description" -->
+ </td>
+ </tr>
+ <tr>
+ <td colspan="4"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+</table>
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+ Click on an entry's Name to bring up more information about that entry.
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+<TABLE width=360 height=216 border=1 bgcolor=#CCCCCC align=center>
+ <TR valign=top>
+ <TD>
+<TABLE width=356 border=0 cellpadding=18 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD>
+ <CENTER>
+ <TABLE width=320 border=0 height=168 cellpadding=0 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD width=32>
+ <IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=message.gif" height=32 width=32 border=0>
+ </TD>
+ <TD width=9>
+ &nbsp;
+ </TD>
+ <TD>
+ <P>
+ No match found.
+ </P>
+ </TD>
+ </TR>
+ <TR valign=top>
+ <TD colspan=2>
+ </TD>
+ <TD>
+ <P>
+ No entries match the requested search term. Please try a different search.
+ </P>
+ </TD>
+ </TR>
+ </TABLE>
+ </CENTER>
+ </TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+</TABLE>
+ </center>
+</p>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/list-NT-People.html b/ldap/clients/dsgw/config/list-NT-People.html
new file mode 100644
index 00000000..dcd0b482
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-NT-People.html
@@ -0,0 +1,152 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>Search for NT-People"</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+
+function showAimIcon(aimID, aimStatusText)
+{
+if (aimStatusText == "" || aimID == "" || aimStatusText != "ONLINE") {
+ return;
+}
+
+document.write('<a href=\"aim:goim?Screenname=' + aimID.replace(/ /,"+") + '\"><IMG SRC=\"lang?<!-- GCONTEXT -->&file=aim-online.gif\" ALT=\"Click to send an AIM to this person\" BORDER=0 HSPACE=5></a>');
+}
+// End hiding -->
+</SCRIPT>
+</head>
+
+<BODY BGCOLOR="white">
+
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" bgcolor="#CCCCCC" align="center">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+<!-- DS_SEARCHDESC -->
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="#FFFFFF" align="center">
+ <tr align="left" bgcolor="#CCCCCC">
+ <td class="boldbig">
+ Name
+ </td>
+ <td class="boldbig">
+ NT Domain
+ </td>
+ <td class="boldbig">
+ NT Username
+ </td>
+ <td class="boldbig">
+ AIM ID
+ </td>
+ <td class="boldbig">
+ Phone
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td >
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "hrefextra=onMouseOver=%22%0Awindow.status='Click here to view this entry in detail'; return true%22" -->
+ </td>
+ <td >
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntdomain" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=ntuserdomainid" "syntax=ntuserid" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=nsaimid" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+showAimIcon(
+<!-- DS_ATTRIBUTE "attr=nsaimid" "options=quoted" -->
+,
+"" //<!-- DS_ATTRIBUTE "attr=nsaimstatustext" "options=quoted" -->
+);
+//// Uncomment the above DS_ATTRIBUTE directive and remove the double ////
+//// quotes to have aim presence in search results lists ////
+
+// End hiding -->
+</SCRIPT>
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+ </td>
+ </tr>
+ <tr>
+ <td colspan="4"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+</table>
+
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+ Click on an entry's ID to bring up more information about that entry.
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+<TABLE width=360 height=216 border=1 bgcolor=#CCCCCC align=center>
+ <TR valign=top>
+ <TD>
+<TABLE width=356 border=0 cellpadding=18 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD>
+ <CENTER>
+ <TABLE width=320 border=0 height=168 cellpadding=0 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD width=32>
+ <IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=message.gif" height=32 width=32 border=0>
+ </TD>
+ <TD width=9>
+ &nbsp;
+ </TD>
+ <TD>
+ <P>
+ No match found.
+ </P>
+ </TD>
+ </TR>
+ <TR valign=top>
+ <TD colspan=2>
+ </TD>
+ <TD>
+ <P>
+ No entries match the requested search term. Please try a different search.
+ </P>
+ </TD>
+ </TR>
+ </TABLE>
+ </CENTER>
+ </TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+</TABLE>
+ </center>
+</p>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/list-Org-Units.html b/ldap/clients/dsgw/config/list-Org-Units.html
new file mode 100644
index 00000000..2476dac5
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-Org-Units.html
@@ -0,0 +1,118 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>Search for Organizational Units</TITLE>
+</head>
+<BODY BGCOLOR="white">
+
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" bgcolor="#CCCCCC" align="center">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+<!-- DS_SEARCHDESC -->
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="#FFFFFF" align="center">
+ <tr align="left" bgcolor="#CCCCCC">
+ <td class="boldbig">
+ Organizational&nbsp;Unit
+ </td>
+ <td class="boldbig">
+ Description
+ </td>
+ <td class="boldbig">
+ Phone
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td >
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "hrefextra=onMouseOver=%22%0Awindow.status='Click here to view this entry in detail'; return true%22" -->
+ </td>
+ <td >
+<!-- DS_ATTRIBUTE "attr=description" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+
+</table>
+
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+ Click on an entry's ID to bring up more information about that entry.
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+<TABLE width=360 height=216 border=1 bgcolor=#CCCCCC align=center>
+ <TR valign=top>
+ <TD>
+<TABLE width=356 border=0 cellpadding=18 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD>
+ <CENTER>
+ <TABLE width=320 border=0 height=168 cellpadding=0 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD width=32>
+ <IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=message.gif" height=32 width=32 border=0>
+ </TD>
+ <TD width=9>
+ &nbsp;
+ </TD>
+ <TD>
+ <P>
+
+ No match found.
+
+ </P>
+ </TD>
+ </TR>
+ <TR valign=top>
+ <TD colspan=2>
+ </TD>
+ <TD>
+ <P>
+
+ No entries match the requested search term. Please try a different search.
+
+ </P>
+ </TD>
+ </TR>
+ </TABLE>
+ </CENTER>
+ </TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+</TABLE>
+ </center>
+</p>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/list-Organizations.html b/ldap/clients/dsgw/config/list-Organizations.html
new file mode 100644
index 00000000..7ebd787f
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-Organizations.html
@@ -0,0 +1,127 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>Search for Organizations</TITLE>
+</head>
+<BODY BGCOLOR="white">
+
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" bgcolor="#CCCCCC" align="center">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+<!-- DS_SEARCHDESC -->
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="#FFFFFF" align="center">
+ <tr align="left" bgcolor="#CCCCCC">
+ <td class="boldbig">
+ Organization
+ </td>
+ <td class="boldbig">
+ Description
+ </td>
+ <td class="boldbig">
+ Phone
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td >
+
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+
+ </td>
+ <td >
+
+<!-- DS_ATTRIBUTE "attr=description" -->
+
+ </td>
+ <td>
+
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+
+</table>
+
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+
+ Click on an organization's name to bring up more information about that entry.
+
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+<TABLE width=360 height=216 border=1 bgcolor=#CCCCCC align=center>
+ <TR valign=top>
+ <TD>
+<TABLE width=356 border=0 cellpadding=18 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD>
+ <CENTER>
+ <TABLE width=320 border=0 height=168 cellpadding=0 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD width=32>
+ <IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=message.gif" height=32 width=32 border=0>
+ </TD>
+ <TD width=9>
+ &nbsp;
+ </TD>
+ <TD>
+ <P>
+
+ No match found.
+
+ </P>
+ </TD>
+ </TR>
+ <TR valign=top>
+ <TD colspan=2>
+ </TD>
+ <TD>
+ <P>
+
+ No entries match the requested search term. Please try a different search.
+
+ </P>
+ </TD>
+ </TR>
+ </TABLE>
+ </CENTER>
+ </TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+</TABLE>
+ </center>
+</p>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/list-People.html b/ldap/clients/dsgw/config/list-People.html
new file mode 100644
index 00000000..bcff3d65
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-People.html
@@ -0,0 +1,176 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>Search for People</TITLE>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+
+function showAimIcon(aimID, aimStatusText)
+{
+if (aimStatusText == "" || aimID == "" || aimStatusText != "ONLINE") {
+ return;
+}
+
+
+document.write('<a href=\"aim:goim?Screenname=' + aimID.replace(/ /,"+") + '\"><IMG SRC=\"lang?<!-- GCONTEXT -->&file=aim-online.gif\" ALT=\"Click to send an AIM to this person\" BORDER=0 HSPACE=5></a>');
+}
+// End hiding -->
+</SCRIPT>
+</HEAD>
+<BODY BGCOLOR="white">
+
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" bgcolor="#CCCCCC" align="center">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+
+<!-- DS_SEARCHDESC -->
+
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="#FFFFFF" align="center">
+ <tr align="left" bgcolor="#CCCCCC">
+ <td class="boldbig">
+ Name
+ </td>
+ <td class="boldbig">
+ ID
+ </td>
+ <td class="boldbig">
+ Phone
+ </td>
+ <td class="boldbig">
+ E-mail
+ </td>
+ <td class="boldbig">
+ AIM ID
+ </td>
+ <td class="boldbig">
+ Group
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td >
+
+<!-- DS_ATTRIBUTE "attr=cn" "syntax=cis" -->
+
+ </td>
+ <td >
+
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "hrefextra=onMouseOver=%22%0Awindow.status='Click here to view this entry in detail'; return true%22" -->
+
+ </td>
+ <td>
+
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=nsaimid" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+showAimIcon(
+<!-- DS_ATTRIBUTE "attr=nsaimid" "options=quoted" -->
+,
+"" //<!-- DS_ATTRIBUTE "attr=nsaimstatustext" "options=quoted" -->
+);
+//// Uncomment the above DS_ATTRIBUTE directive and remove the double ////
+//// quotes to have aim presence in search results lists ////
+
+// End hiding -->
+</SCRIPT>
+ </td>
+ <td>
+
+<!-- DS_ATTRIBUTE "attr=ou" "syntax=cis"-->
+
+ </td>
+ </tr>
+ <tr>
+ <td colspan="5"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+
+</table>
+
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+
+ Click on an entry's ID to bring up more information about that entry.
+
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+<TABLE width=360 height=216 border=1 bgcolor=#CCCCCC align=center>
+ <TR valign=top>
+ <TD>
+<TABLE width=356 border=0 cellpadding=18 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD>
+ <CENTER>
+ <TABLE width=320 border=0 height=168 cellpadding=0 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD width=32>
+ <IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=message.gif" height=32 width=32 border=0>
+ </TD>
+ <TD width=9>
+ &nbsp;
+ </TD>
+ <TD>
+ <P>
+
+ No match found.
+
+ </P>
+ </TD>
+ </TR>
+ <TR valign=top>
+ <TD colspan=2>
+ </TD>
+ <TD>
+ <P>
+
+ No entries match the requested search term. Please try a different search.
+
+ </P>
+ </TD>
+ </TR>
+ </TABLE>
+ </CENTER>
+ </TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+</TABLE>
+ </center>
+</p>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/config/list-fa-Groups.html b/ldap/clients/dsgw/config/list-fa-Groups.html
new file mode 100644
index 00000000..ddc2a572
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-fa-Groups.html
@@ -0,0 +1,26 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>Search for People</TITLE>
+</head>
+</body>
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+</body>
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/list-fa-People.html b/ldap/clients/dsgw/config/list-fa-People.html
new file mode 100644
index 00000000..ddc2a572
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-fa-People.html
@@ -0,0 +1,26 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>Search for People</TITLE>
+</head>
+</body>
+<!-- IF "FoundEntries" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+<FORM>
+<!-- DS_ENTRYBEGIN -->
+
+<!-- DS_ENTRYEND -->
+<!-- DS_END_ENTRYFORM -->
+</FORM>
+
+<!-- ELSE -->
+<!-- DS_ALERT_NOENTRIES -->
+<!-- ENDIF -->
+</body>
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/list-urlsearch.html b/ldap/clients/dsgw/config/list-urlsearch.html
new file mode 100644
index 00000000..bee6edda
--- /dev/null
+++ b/ldap/clients/dsgw/config/list-urlsearch.html
@@ -0,0 +1,129 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<TITLE>URL-based Search</TITLE>
+</head>
+<BODY BGCOLOR="white">
+
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" bgcolor="#CCCCCC" align="center">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+
+<!-- DS_SEARCHDESC -->
+
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="#FFFFFF" align="center">
+ <tr align="left" bgcolor="#CCCCCC">
+ <td class="boldbig">
+ Name
+ </td>
+ <td class="boldbig">
+ Phone
+ </td>
+ <td class="boldbig">
+ E-mail
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td >
+
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" -->
+
+ </td>
+
+ <td>
+
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+
+ </td>
+ <td >
+
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+
+ </td>
+ </tr>
+ <tr>
+ <td colspan="3"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+
+</table>
+
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+
+ Click on an entry's Name to bring up more information about that entry.
+
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+<TABLE width=360 height=216 border=1 bgcolor=#CCCCCC align=center>
+ <TR valign=top>
+ <TD>
+<TABLE width=356 border=0 cellpadding=18 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD>
+ <CENTER>
+ <TABLE width=320 border=0 height=168 cellpadding=0 cellspacing=0 bgcolor=#CCCCCC>
+ <TR valign=top>
+ <TD width=32>
+ <IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=message.gif" height=32 width=32 border=0>
+ </TD>
+ <TD width=9>
+ &nbsp;
+ </TD>
+ <TD>
+ <P>
+
+ No match found.
+
+ </P>
+ </TD>
+ </TR>
+ <TR valign=top>
+ <TD colspan=2>
+ </TD>
+ <TD>
+ <P>
+
+ No entries match the requested search term. Please try a different search.
+
+ </P>
+ </TD>
+ </TR>
+ </TABLE>
+ </CENTER>
+ </TD>
+ </TR>
+</TABLE>
+ </TD>
+ </TR>
+</TABLE>
+ </center>
+</p>
+<!-- ENDIF -->
+</body>
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/config/newentry.html b/ldap/clients/dsgw/config/newentry.html
new file mode 100644
index 00000000..cff71a66
--- /dev/null
+++ b/ldap/clients/dsgw/config/newentry.html
@@ -0,0 +1,26 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentry.html-->
+<TITLE>Netscape Directory Server Gateway: New Entry</TITLE>
+<!-- DS_NEWENTRY_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=130,70,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=newentrytitle.html" NORESIZE SCROLLING="NO">
+ <FRAME SRC="newentry?<!-- GCONTEXT -->&file=type"
+ NAME="newentryTypeFrame" SCROLLING="NO">
+ <FRAME SRC="newentry?<!-- GCONTEXT -->&file=name"
+ NAME="newentryNameFrame">
+</FRAMESET>
+
+<NOFRAMES>
+<BODY>
+You must use a client that supports frames to view this document.
+</BODY>
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/config/newentryName.html b/ldap/clients/dsgw/config/newentryName.html
new file mode 100644
index 00000000..ab65c998
--- /dev/null
+++ b/ldap/clients/dsgw/config/newentryName.html
@@ -0,0 +1,62 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!--newentryName.html-->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<!-- DS_NEWENTRY_NAME_BODY -->
+<p>
+<!-- DS_NEWENTRY_NAME_FORM -->
+<CENTER> <TABLE WIDTH="85%" CELLPADDING=3 CELLSPACING=3 BORDER=0> <TR> <TD>
+<B>Step 2.</B> Provide a name for the new
+<!-- EVALUATE "entType.fullname" -->
+.
+<BR>
+<!-- EVALUATE "entType.rdnattr" -->
+:
+
+<INPUT TYPE="text" NAME="entryname" SIZE="40">
+<P>
+
+<B>Step 3.</B>
+
+<!-- DS_NEWENTRY_LOCATION_BEGIN -->
+Select a directory location for this
+<!-- EVALUATE "entType.fullname" -->
+, or select Other and enter the complete
+distinguished name where this entry should be added.
+<p>
+<!-- DS_NEWENTRY_LOCATION_SELECT -->
+<OPTION VALUE="">Other</OPTION>
+</SELECT>
+
+<BR>
+<!--
+<INPUT TYPE="text" NAME="dnsuffix" SIZE="70" onFocus="parent.dnsuffixFocus(this.form)">
+-->
+<TEXTAREA NAME="dnsuffix" ROWS=2 COLS=40 WRAP="soft" onFocus="parent.dnsuffixFocus(this.form)">
+</TEXTAREA>
+<P>
+
+<B>Step 4.</B>
+<!-- DS_NEWENTRY_LOCATION_END -->
+
+Click Continue. You will be presented with an editable view
+of the entry. When you are done filling in information,
+save the entry.
+<P>
+
+</TD> </TR> <TR> <TD BGCOLOR="#CCCCCC" ALIGN="middle">
+
+<INPUT TYPE="submit" VALUE="Continue" WIDTH=72>
+<!-- DS_HELP_BUTTON "ADDING" -->
+<TD> </TR>
+</TABLE> </CENTER>
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/newentryType.html b/ldap/clients/dsgw/config/newentryType.html
new file mode 100644
index 00000000..d043a6ff
--- /dev/null
+++ b/ldap/clients/dsgw/config/newentryType.html
@@ -0,0 +1,25 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+<!--newentryType.html-->
+</head>
+<!-- DS_NEWENTRY_TYPE_BODY -->
+<!-- DS_NEWENTRY_TYPE_FORM -->
+<CENTER> <TABLE WIDTH="85%" CELLPADDING=3 CELLSPACING=3 BORDER=0> <TR> <TD>
+Create New Entry
+<BR>
+
+<B>Step 1.</B> Select the type of entry to create.
+<!-- DS_NEWENTRY_TYPE_SELECT -->
+
+</TD> </TR> </TABLE> </CENTER>
+</FORM>
+</BODY>
+</HTML>
+
diff --git a/ldap/clients/dsgw/config/ns-license-schema.conf b/ldap/clients/dsgw/config/ns-license-schema.conf
new file mode 100644
index 00000000..7ab2c1fe
--- /dev/null
+++ b/ldap/clients/dsgw/config/ns-license-schema.conf
@@ -0,0 +1,17 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+attribute nsLicensedFor cis
+attribute nsLicenseStartTime cis
+attribute nsLicenseEndTime cis
+
+objectclass nsLicenseUser
+ requires
+ objectClass
+ allows
+ nsLicensedFor
+ nsLicenseStartTime
+ nsLicenseEndTime
diff --git a/ldap/clients/dsgw/config/search.html b/ldap/clients/dsgw/config/search.html
new file mode 100644
index 00000000..2aa7ffd8
--- /dev/null
+++ b/ldap/clients/dsgw/config/search.html
@@ -0,0 +1,18 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- search.html -->
+<TITLE>Netscape Directory Server Gateway: Standard Search</TITLE>
+<!-- DS_SEARCH_SCRIPT -->
+</HEAD>
+<FRAMESET ROWS=130,100,* BORDER=0 onLoad="init()">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=searchtitle.html" SCROLLING="NO">
+ <FRAME SRC="search?<!-- GCONTEXT -->&file=string" NAME=searchFrame NORESIZE SCROLLING="NO">
+ <FRAME SRC="lang?<!-- GCONTEXT -->&file=greeting.html" NAME=outputFrame>
+</FRAMESET>
+</HTML>
diff --git a/ldap/clients/dsgw/config/searchString.html b/ldap/clients/dsgw/config/searchString.html
new file mode 100644
index 00000000..dfad73dc
--- /dev/null
+++ b/ldap/clients/dsgw/config/searchString.html
@@ -0,0 +1,41 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- searchString.html -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<!-- DS_SEARCH_BODY -->
+<!-- DS_SEARCH_FORM "target=outputFrame" -->
+<TABLE BORDER=0 CELLSPACING=0 CELLPADDING=3 WIDTH=100%>
+<TR> <TD ALIGN="right">
+Find
+ </TD>
+<TD>
+<!-- DS_SEARCH_TYPE -->
+within
+<B>
+<!-- DS_SEARCH_BASE -->
+</B>
+ </TD>
+</TR> <TR>
+<TD ALIGN="right">
+Search for
+ </TD>
+<TD COLSPAN=3>
+<INPUT NAME="searchstring" SIZE=30>
+
+<INPUT TYPE="SUBMIT" VALUE="Search" WIDTH="72">
+<!-- DS_HELP_BUTTON "SMARTSEARCH" -->
+ </TD>
+</TR> </TABLE>
+<INPUT TYPE="hidden" NAME="ldapsizelimit" VALUE="1000">
+<INPUT TYPE="hidden" NAME="ldaptimelimit" VALUE="180">
+<!-- PCONTEXT -->
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/config/zh/dsgw-l10n.conf b/ldap/clients/dsgw/config/zh/dsgw-l10n.conf
new file mode 100644
index 00000000..0482312b
--- /dev/null
+++ b/ldap/clients/dsgw/config/zh/dsgw-l10n.conf
@@ -0,0 +1,18 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# To localize the search type menu:
+# Locate dsgw-l10n.conf in config/<lang>/.
+# dsgw-l10n.conf contains translated words for search type pulldown menu.
+# dsgw-l10n.conf sample:
+# Note: the sample part should have double #'s for L10n.
+## translate People <People_translated_in_lang>
+## translate NT-People <NT-People_translated_in_lang>
+## translate Groups <Groups_translated_in_lang>
+## translate NT-Groups <NT-Groups_translated_in_lang>
+## translate Organizations <Organizations_translated_in_lang>
+## translate Org-Units <Org-Units_translated_in_lang>
+## translate Anything <Anything_translated_in_lang>
diff --git a/ldap/clients/dsgw/config/zh/dsgwcharset.conf b/ldap/clients/dsgw/config/zh/dsgwcharset.conf
new file mode 100644
index 00000000..d8b0f859
--- /dev/null
+++ b/ldap/clients/dsgw/config/zh/dsgwcharset.conf
@@ -0,0 +1,7 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+big5
diff --git a/ldap/clients/dsgw/cookie.c b/ldap/clients/dsgw/cookie.c
new file mode 100644
index 00000000..97c18b0d
--- /dev/null
+++ b/ldap/clients/dsgw/cookie.c
@@ -0,0 +1,990 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * cookie.c -- routines to generate and manipulate cookies for dsgw
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+
+#include "../../include/portable.h"
+
+#include <stdio.h>
+#if !defined( XP_WIN32 )
+#include <sys/param.h>
+#endif
+
+#include <ssl.h>
+#ifdef NSS38_AND_OLDER
+#include <secrng.h>
+#else
+#include "ecl-exp.h"
+#endif
+#include <nss.h>
+#include <base64.h>
+#include <sys/types.h>
+#include <limits.h>
+#include <string.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#include <time.h>
+#include <io.h>
+#include <fcntl.h>
+#include <sys/locking.h>
+#else /* _WIN32 */
+#include <unistd.h>
+#endif /* _WIN32 */
+
+#include <pk11func.h>
+#include <pkcs11.h>
+#include <pk11pqg.h>
+
+
+static char *dsgw_MungeString(const char *unmunged_string);
+static char *dsgw_UnMungeString(const char *munged_string);
+static char *dsgw_encDec(CK_ATTRIBUTE_TYPE operation, const char *msg);
+void dsgw_initNSS(void);
+
+static char tokDes[34] = "Communicator Generic Crypto Svcs";
+static char ptokDes[34] = "Internal (Software) Token ";
+
+int dsgw_NSSInitializedAlready = 0;
+
+/* Table for converting binary values to and from hexadecimal */
+static char hex[] = "0123456789abcdef";
+#if 0
+static char dec[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0 - 15 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 16 - 37 */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* ' ' - '/' */
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* '0' - '?' */
+ 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '@' - 'O' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'P' - '_' */
+ 0,10,11,12,13,14,15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* '`' - 'o' */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 'p' - DEL */
+};
+#endif
+
+
+#define CKLEN 32
+#define RNDBUFLEN ( CKLEN / 2 )
+#define CKBUFSIZ 255
+/*
+ * Given a buffer buf of length len, return a pointer to a string containing
+ * the hex-encoded version of buf. The caller is responsible for freeing
+ * the memory this routine allocates.
+ */
+static char *
+buf2str( unsigned char *buf, int len )
+{
+ char *obuf;
+ int i;
+ char *p;
+
+ if ( buf == NULL ) {
+ return NULL;
+ }
+
+ p = obuf = dsgw_ch_malloc( CKLEN + 1 );
+ for ( i = 0; i < len; i++) {
+ *p++ = hex[( buf[ i ] >> 4 ) & 0xf ];
+ *p++ = hex[( buf[ i ]) & 0xf ];
+ }
+ *p++ = '\0';
+ return obuf;
+}
+
+
+
+/*
+ * Generate a random string of hex-encoded digits, CKLEN characters in
+ * length. This routine allocates memory which the caller is responsible
+ * for freeing.
+ */
+char *
+dsgw_mkrndstr()
+{
+ unsigned char buf[ RNDBUFLEN ];
+
+ PK11_ConfigurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
+ /*NSS_NoDB_Init(NULL);*/
+ dsgw_initNSS();
+ PK11_GenerateRandom(buf, RNDBUFLEN);
+ return( buf2str( buf, RNDBUFLEN ));
+}
+
+
+FILE *
+dsgw_opencookiedb()
+{
+ FILE *fp;
+ time_t now;
+ int newfile = 0;
+ char cdb[MAXPATHLEN]; /*DSGW_COOKIEDB_FNAME + context*/
+
+#ifdef XP_WIN32
+#ifndef F_OK
+#define F_OK 0
+#endif
+#endif
+ sprintf(cdb, "%s.%s", DSGW_COOKIEDB_FNAME, context);
+
+ if ( access( cdb, F_OK ) == 0 ) {
+ fp = fopen( cdb, "r+" );
+ } else {
+ newfile = 1;
+ fp = fopen( cdb, "w" );
+ }
+ if ( fp == NULL ) {
+ return NULL;
+ }
+ /* fseek( fp, 0L, SEEK_SET ); */
+#ifdef XP_WIN32
+ (void) chmod( cdb, _S_IREAD | _S_IWRITE );
+#else
+ (void) chmod( cdb, S_IRUSR | S_IWUSR );
+#endif
+
+ /* acquire a lock */
+#ifdef _WIN32
+ while ( _locking( _fileno( fp ), LK_NBLCK, 0xFFFFFFFF ) != 0 ) {
+#else
+#ifdef USE_LOCKF
+ while ( lockf( fileno( fp ), F_LOCK, 0 ) != 0 ) {
+#else /* _WIN32 */
+ while ( flock( fileno( fp ), LOCK_EX ) != 0 ) {
+#endif
+#endif /* _WIN32 */
+ ; /* NULL */
+ }
+ if ( newfile ) {
+ time( &now );
+ fprintf( fp, "lastpurge: %-20lu\n", now );
+ fflush( fp );
+ fseek( fp, 0L, SEEK_SET );
+ }
+ return fp;
+}
+
+
+void
+dsgw_closecookiedb( FILE *fp )
+{
+#ifdef _WIN32
+ _locking( _fileno( fp ), LK_UNLCK, 0xFFFFFFFF );
+#else /* _WIN32 */
+#ifdef USE_LOCKF
+ lockf( fileno( fp ), F_ULOCK, 0 );
+#else
+ flock( fileno( fp ), LOCK_UN );
+#endif
+#endif /* _WIN32 */
+ fclose( fp );
+}
+
+
+
+/*
+ * Return a pointer to the password associated with the given
+ * cookie and dn. If the cookie was not found in the database,
+ * or if the cookie has expired, 1 is returned. On success, 0 is returned
+ * and ret_pw is set to the password from the database. As a side effect,
+ * if the database has not been purged of expired entries in more than
+ * 10 minutes, the database is purged.
+ *
+ * As a special case, if the cookie is expired and gc->gc_mode is
+ * DSGW_MODE_DOMODIFY (that is, the user is saving a modified entry), then
+ * return 0 if the cookie has been expired for no more than 5 minutes.
+ * This keeps users from being frustrated by getting an editable view of
+ * an entry and having the cookie expire while editing.
+ * The caller is responsible for freeing ret_pw.
+ */
+int
+dsgw_ckdn2passwd( char *rndstr, char *dn, char **ret_pw )
+{
+ FILE *fp;
+ char buf[ CKBUFSIZ ];
+ char *p, *pw, *lifetimestr, *cdn;
+ time_t now;
+ int expired = 0;
+
+ if ( !strcmp( rndstr, DSGW_UNAUTHSTR )) {
+ *ret_pw = NULL;
+ return 0;
+ }
+
+ if (( fp = dsgw_opencookiedb()) == NULL ) {
+ return DSGW_CKDB_CANTOPEN;
+ }
+
+ for (;;) {
+ if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
+ dsgw_closecookiedb( fp );
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_ckdn2passwd: cookie <%s> not found in db\n",
+ rndstr );
+#endif
+ return DSGW_CKDB_KEY_NOT_PRESENT;
+ }
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_ckdn2passwd: retrieved buf from db: <%s>\n", buf );
+#endif
+ if ( buf[ strlen( buf ) - 1 ] == '\n' ) {
+ buf[ strlen( buf ) - 1 ] = '\0';
+ }
+
+ if ( strncmp( buf, rndstr, strlen( rndstr ))) {
+ continue;
+ }
+
+ if (( p = strchr( buf, ':' )) == NULL ) {
+ dsgw_closecookiedb( fp );
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_ckdn2passwd: colon 1 missing\n" );
+#endif
+ return DSGW_CKDB_DBERROR;
+ }
+ *p++ = '\0';
+ lifetimestr = p;
+ if (( p = strchr( lifetimestr, ':' )) == NULL ) {
+ dsgw_closecookiedb( fp );
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_ckdn2passwd: colon 2 missing\n" );
+#endif
+ return DSGW_CKDB_DBERROR;
+ }
+ *p++ = '\0';
+ pw = p;
+
+ if (( p = strchr( pw, ':' )) == NULL ) {
+ dsgw_closecookiedb( fp );
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_ckdn2passwd: colon 3 missing\n" );
+#endif
+ return DSGW_CKDB_DBERROR;
+ }
+ *p++ = '\0';
+ cdn = p;
+
+ if ( strcmp( dn, cdn )) {
+ dsgw_closecookiedb( fp );
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_ckdn2passwd: dn <%s> != cdn <%s>\n", dn, cdn );
+#endif
+ return DSGW_CKDB_KEY_NOT_PRESENT;
+ }
+
+ /* expired? */
+ time( &now );
+ if ( gc->gc_mode == DSGW_MODE_DOMODIFY ) {
+ if ( now > ( atoi( lifetimestr ) + DSGW_MODIFY_GRACEPERIOD )) {
+ expired = 1;
+ } else {
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_ckdn2passwd: cookie expired (%ld > %ld) but within domodify grace period\n", now, atoi( lifetimestr ));
+#endif
+ }
+ } else if ( now > atoi( lifetimestr )) {
+ expired = 1;
+ }
+
+ if ( expired != 0 ) {
+ dsgw_closecookiedb( fp );
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_ckdn2passwd: expired (%ld > %ld)\n", now, atoi( lifetimestr ));
+#endif
+ return DSGW_CKDB_EXPIRED;
+ }
+
+ *ret_pw = dsgw_UnMungeString( pw );
+ dsgw_closecookiedb( fp );
+ return ( *ret_pw == NULL ) ? 1 : 0;
+ }
+}
+
+
+
+/*
+ * Store the given cookie and password into the database. The cookie
+ * is marked to expire at the time given by "expires". Returns 0 if
+ * successful, otherwise returns an error as given in dsgw.h.
+ * As a side effect, if the database has not been purged of expired
+ * entries in more than 10 minutes, the database is purged.
+ *
+ * Note: DNs are stored unescaped in the cookie database. Passwords
+ * are stored as "munged" values (encrypted using a hard-coded key and
+ * then converted to ASCII as described in RFC-1113) to make them a bit
+ * less obvious and to avoid problems which might arise from embedded ":"
+ * characters in the password (":" is the field separator in the database).
+ */
+int
+dsgw_storecookie( char *rndstr, char *dn, char *password, time_t lifetime )
+{
+ FILE *fp;
+ char *epw;
+ time_t now, lp;
+
+ if (( fp = dsgw_opencookiedb()) == NULL ) {
+ return DSGW_CKDB_CANTOPEN;
+ }
+
+ /* append record */
+ if ( fseek( fp, 0L, SEEK_END ) < 0 ) {
+ return DSGW_CKDB_CANTAPPEND;
+ }
+ if (( epw = dsgw_MungeString( password )) == NULL ) {
+ return DSGW_CKDB_CANTAPPEND; /* error msg is close enough */
+ }
+
+ time( &now );
+ if ( fprintf( fp, "%s:%lu:%s:%s\n", rndstr, lifetime + now, epw, dn )
+ < 0 ) {
+ free( epw );
+ return DSGW_CKDB_CANTAPPEND;
+ }
+
+ fflush( fp );
+
+ dsgw_closecookiedb( fp );
+ fp = dsgw_opencookiedb();
+ lp = dsgw_getlastpurged( fp );
+ dsgw_closecookiedb( fp );
+
+ if ( lp + DSGW_CKPURGEINTERVAL < now ) {
+ dsgw_purgedatabase( NULL );
+ }
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_storecookie: stored %s:%lu:%s:%s\n", rndstr, lifetime + now, epw, dn );
+#endif
+ free( epw );
+ return 0;
+}
+
+
+/*
+ * Remove a cookie from the database.
+ * Format of cookie argument is "nsdsgwauth=cookie-string:escaped-dn"
+ */
+int
+dsgw_delcookie( char *cookie )
+{
+ FILE *fp;
+ char *rndstr, *dn, *dnp, *dbdn, *p;
+ char buf[ CKBUFSIZ ];
+ int rc;
+ long buflen;
+
+ /* Parse the given cookie - find the random string */
+ if (( rndstr = strchr( cookie, '=' )) == NULL ) {
+ /* malformed cookie */
+ return -1;
+ } else {
+ /* Get the escaped DN */
+ rndstr++;
+ if (( dn = strchr( rndstr, ':' )) == NULL ) {
+ /* malformed cookie */
+ return -1;
+ } else {
+ *dn++ = '\0';
+ dsgw_form_unescape( dn );
+ }
+ }
+
+ /*
+ * Open the cookie database, find the rndstr, make sure the DNs
+ * match, and delete that entry if found.
+ */
+ if (( fp = dsgw_opencookiedb()) == NULL ) {
+ return -1;
+ }
+ fgets( buf, CKBUFSIZ, fp );
+ if ( strncmp( buf, "lastpurge:", 10 )) {
+ dsgw_closecookiedb( fp );
+ return -1;
+ }
+ rc = DSGW_CKDB_KEY_NOT_PRESENT;
+ for (;;) {
+ if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
+ break;
+ }
+ if ( strncmp( buf, rndstr, CKLEN )) {
+ continue;
+ }
+ buflen = strlen( buf );
+ /* Found the random string - check DN */
+ if (( dbdn = strrchr( buf, ':' )) == NULL ) {
+ continue;
+ } else {
+ dbdn++;
+ if ( dbdn[ strlen( dbdn) - 1 ] == '\n' ) {
+ dbdn[ strlen( dbdn) - 1 ] = '\0';
+ }
+ if ( strcmp( dbdn, dn )) {
+ continue;
+ } else {
+ /* Found it. Set the expiration time to zero and obliterate
+ * the password.
+ */
+ p = strchr( buf, ':' );
+ for ( p++; *p != ':'; p++ ) {
+ *p = '0'; /* yes, '0', not '\0' */
+ }
+ dnp = strrchr( buf, ':' );
+ for ( p++; p < dnp; p++ ) {
+ *p = 'x';
+ }
+ p++;
+ fseek( fp, -buflen, SEEK_CUR );
+ fputs( buf, fp );
+ fputs( "\n", fp );
+ fflush( fp );
+ rc = 0;
+ }
+ }
+ }
+
+ dsgw_closecookiedb( fp );
+
+ if ( rc == 0 ) {
+ dsgw_purgedatabase( dn );
+ }
+
+ return rc;
+}
+
+
+
+
+
+
+/*
+ * Retrieve the time of the last database purge. Returns zero on error.
+ * The caller must open and lock the cookie database before calling this
+ * routine. The file pointer's position in the file is preserved.
+ */
+time_t
+dsgw_getlastpurged( FILE *fp )
+{
+ char buf[ CKBUFSIZ ];
+ char *p;
+ size_t pos;
+ time_t ret;
+
+ if ( fp == NULL ) {
+ return (time_t) 0L;
+ }
+
+ pos = ftell( fp );
+ fseek( fp, 0L, SEEK_SET );
+
+ fgets( buf, CKBUFSIZ, fp );
+ if ( strncmp( buf, "lastpurge:", 10 )) {
+ ret = (time_t) 0L;
+ } else {
+ p = buf + 10;
+ if ( *p != '\0' ) {
+ ret = (time_t) atol( p );
+ } else {
+ ret = (time_t) 0L;
+ }
+ }
+ fseek( fp, pos, SEEK_SET );
+ return ret;
+}
+
+
+/*
+ * Purge the database of any expired entries. Returns the number of
+ * entries purged, or -1 if an error occurred. If "dn" is non-NULL,
+ * then this routine will also remove any entries where the DN matches
+ * "dn".
+ */
+#define DSGW_CK_DEBUG 1
+int
+dsgw_purgedatabase( char *dn )
+{
+ FILE *fp, *ofp;
+ time_t now;
+ char buf[ CKBUFSIZ ];
+ char *exp;
+ char expbuf[ 32 ];
+ char *nbuf;
+ int purged = 0;
+#ifdef _WIN32
+ int fh;
+#endif
+ size_t osize; /* original size of file */
+ size_t csize; /* current size of file */
+ char cdb[MAXPATHLEN]; /*DSGW_COOKIEDB_FNAME + context*/
+
+ sprintf(cdb, "%s.%s", DSGW_COOKIEDB_FNAME, context);
+
+ if (( fp = dsgw_opencookiedb()) == NULL ) {
+ return -1;
+ }
+
+ fseek( fp, 0L, SEEK_END );
+ osize = ftell( fp );
+ fseek( fp, 0L, SEEK_SET );
+
+ if (( ofp = fopen( cdb, "r+" )) == NULL ) {
+ dsgw_closecookiedb( fp );
+ return -1;
+ }
+
+ /* re-write the last purge time */
+ time( &now );
+ fprintf( ofp, "lastpurge: %-20lu\n", now );
+
+ for (;;) {
+ char *p;
+ char *dbdn;
+ int nukeit;
+
+ nukeit = 0;
+
+ if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
+ break;
+ }
+ if ( strncmp( buf, "lastpurge:", 10 ) == 0 ) {
+ continue;
+ }
+ if (( p = strchr( buf, ':' )) == NULL ) {
+ fclose( ofp );
+ dsgw_closecookiedb( fp );
+ return -1;
+ }
+ exp = ++p;
+ if (( p = strchr( exp, ':' )) == NULL ) {
+ fclose( ofp );
+ dsgw_closecookiedb( fp );
+ return -1;
+ }
+ strncpy( expbuf, exp, p - exp );
+ expbuf[ p - exp ] = '\0';
+ time( &now );
+
+ /* Get the entry's DN */
+ dbdn = strrchr( buf, ':' );
+ dbdn++;
+ dbdn = strdup( dbdn );
+ if ( dbdn[ strlen( dbdn) - 1 ] == '\n' ) {
+ dbdn[ strlen( dbdn) - 1 ] = '\0';
+ }
+
+ /* Should we delete? */
+ if ( dn != NULL ) {
+ if (( dbdn != NULL ) && !strcmp( dn, dbdn )) {
+ /* Entry's DN is the same as the "dn" parameter - delete */
+ nukeit = 1;
+ }
+ }
+
+ free( dbdn );
+ if ( !nukeit && ( now > atol( expbuf ))) {
+ /* expired */
+ nukeit = 1;
+ }
+
+ if ( !nukeit ) {
+ /* Entry should stay */
+ fputs( buf, ofp );
+ } else {
+ /* Entry should be purged */
+ purged++;
+ }
+ }
+
+ /*
+ * Overwrite the rest of the file so we don't leave passwords
+ * laying around.
+ */
+ csize = ftell( ofp );
+ nbuf = dsgw_ch_malloc( osize - csize + 2 );
+ memset( nbuf, 'x', osize - csize + 1 );
+ nbuf[ osize - csize + 1 ] = '\0';
+ fputs( nbuf, ofp );
+ free( nbuf );
+#ifdef _WIN32
+ dsgw_closecookiedb( fp );
+ fflush( ofp );
+ fclose( ofp );
+ fh = open( cdb, _O_RDWR | _O_TEXT );
+ chsize( fh, csize );
+ close( fh );
+#else /* _WIN32 */
+ fclose( ofp );
+ ftruncate( fileno( fp ), csize );
+ dsgw_closecookiedb( fp );
+#endif /* _WIN32 */
+ return purged;
+}
+
+
+
+/*
+ * for debugging - traverse and print the db
+ */
+void
+dsgw_traverse_db()
+{
+ FILE *fp;
+ char *exp;
+ int total, expired;
+ time_t now;
+ char buf[ CKBUFSIZ ];
+ char expbuf[ 32 ];
+
+ total = expired = 0;
+
+ if (( fp = dsgw_opencookiedb()) == NULL ) {
+ fprintf( stderr, "can't open db\n" );
+ return;
+ }
+
+ if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
+ dsgw_closecookiedb( fp );
+ printf( "Cookie database is empty (no lastpurge line)\n" );
+ return;
+ }
+ puts( buf );
+
+ for (;;) {
+ char *p;
+ if ( fgets( buf, CKBUFSIZ, fp ) == NULL ) {
+ dsgw_closecookiedb( fp );
+ printf( "%d entries, %d expired\n", total, expired );
+ return;
+ }
+ if (( p = strchr( buf, ':' )) == NULL ) {
+ dsgw_closecookiedb( fp );
+ return;
+ }
+ exp = ++p;
+ if (( p = strchr( exp, ':' )) == NULL ) {
+ dsgw_closecookiedb( fp );
+ return;
+ }
+ printf( "%s", buf );
+ strncpy( expbuf, exp, p - exp + 1 );
+ expbuf[ p - exp + 1 ] = '\0';
+ time( &now );
+ total++;
+ if ( now > atol( expbuf )) {
+ /* not yet expired */
+ printf( " (expired)\n" );
+ expired++;
+ } else {
+ printf( "\n" );
+ }
+ }
+}
+
+
+
+/*
+ * Generate a complete authentication cookie header line and store
+ * the relevant parts iit in the database.
+ * Return a pointer to the cookie. This routine allocates memory, which
+ * the caller is responsible for freeing.
+ * On error, this routine returns NULL and sets err to point to an
+ * error code.
+ */
+char *
+dsgw_mkcookie( char *dn, char *password, time_t lifetime, int *err )
+{
+ char *r;
+ char *ckbuf;
+ char *edn;
+ int rc;
+
+ if ( dn == NULL ) {
+ *err = DSGW_CKDB_NODN;
+ return NULL;
+ }
+ edn = dsgw_strdup_escaped( dn );
+
+ if (( r = dsgw_mkrndstr()) == NULL ) {
+ *err = DSGW_CKDB_RNDSTRFAIL;
+ return NULL;
+ }
+ rc = dsgw_storecookie( r, dn, password, lifetime );
+ if ( rc != 0 ) {
+ free( r );
+ free( edn );
+ *err = rc;
+ return NULL;
+ }
+
+ ckbuf = dsgw_ch_malloc( strlen( DSGW_CKHDR ) + strlen( r ) +
+ strlen( edn ) + strlen( DSGW_AUTHCKNAME ) + 2 + 20 );
+ ckbuf[ 0 ] = '\0';
+ strcpy( ckbuf, DSGW_CKHDR );
+ strcat( ckbuf, DSGW_AUTHCKNAME );
+ strcat( ckbuf, "=" );
+ strcat( ckbuf, r );
+ strcat( ckbuf, ":" );
+ strcat( ckbuf, edn );
+ strcat( ckbuf, "; path=/" );
+
+ free( r );
+ free( edn );
+ return ckbuf;
+}
+
+
+
+#if 0
+/*
+ * Given a time_t, return a GMTString representation of that time.
+ */
+char *
+dsgw_t2gmts( time_t cktime )
+{
+ time_t tnl;
+ struct tm *pt;
+#define TBUFSIZE 40
+ char tbuf[ TBUFSIZE ];
+
+ tnl = time( NULL );
+ pt = gmtime( &tnl );
+ (void)strftime( tbuf, (size_t)TBUFSIZE, "%A, %d-%b-%y %T GMT", pt);
+ return( dsgw_ch_strdup( tbuf ));
+}
+#endif
+
+
+/*
+ * Password obfuscation, etc.
+ * There is no real security here -- we just encrypt using a hard-coded key.
+ * The original functions these are based on are called SECMOZ_MungeString()
+ * and SECMOZ_UnMungeString(). They can be found in ns/lib/libsec/secmoz.c
+ * (they don't get built as part of the server builds). The only change I
+ * made was to swap a few of the bytes in the secmoz_tmmdi array and add one
+ * to all of them. -- Mark Smith <mcs@netscape.com>
+ */
+
+static unsigned char dsgw_tmmdi[] = { /* tmmdi == They Made Me Do It */
+ 0x87, /* repka, paquin */
+ 0x9d, /* freier, elgamal */
+ 0xdf, /* jonm, bobj */
+ 0xef, /* fur, sharoni */
+ 0xd1, /* jsw, karlton */
+ 0xec, /* ari, sk */
+ 0x3f, /* terry, atotic */
+ 0xc7 /* jevering, kent */
+};
+
+static char *
+dsgw_MungeString(const char *unmunged_string)
+{
+ return(dsgw_encDec(CKA_ENCRYPT, unmunged_string));
+}
+static char *
+dsgw_UnMungeString(const char *munged_string)
+{
+ return(dsgw_encDec(CKA_DECRYPT, munged_string));
+}
+
+/*
+ * key import and encryption (using RC4)
+ */
+static char *
+dsgw_encDec(CK_ATTRIBUTE_TYPE operation, const char *msg)
+{
+ CK_MECHANISM_TYPE type = CKM_RC4;
+ PK11SlotInfo *slot = 0;
+ PK11SymKey *key = 0;
+ SECItem *params = 0;
+ PK11Context *context = 0;
+ unsigned char *output;
+ unsigned char *input;
+ char *edStr;
+ int outLen;
+ int len;
+ SECStatus s;
+ SECItem keyItem = { siBuffer, dsgw_tmmdi, sizeof dsgw_tmmdi };
+ int noGood = 0;
+ unsigned int inlen;
+ FILE *pptr;
+ int i;
+
+ if (msg == NULL) {
+ return NULL;
+ }
+
+ if (*msg == '\0') {
+ return PL_strdup(msg);
+ }
+
+ if (operation == CKA_DECRYPT) {
+ input = ATOB_AsciiToData(msg, &inlen);
+ if (msg == NULL)
+ return NULL;
+ } else {
+ inlen = PL_strlen(msg);
+ input = (unsigned char *) msg;
+ }
+
+ output = (unsigned char *) malloc(inlen + 65);
+ if (output == NULL) {
+ return NULL;
+ }
+
+ /* Initialization */
+ /*NSS_NoDB_Init(".");*/
+ dsgw_initNSS();
+
+ /*
+ * Choose a "slot" to use. Slots store keys (either
+ * temporarily or permanently) and perform
+ * cryptogrphic operations.
+ *
+ * Use the built-in key slot. Another way to choose
+ * a slot is using PK11_GetBestSlot(), which chooses
+ * based on the mechanism.
+ */
+ slot = PK11_GetInternalKeySlot();
+ if (!slot)
+ {
+ noGood = 1;
+ goto dsgw_encDec_done;
+ }
+
+ /*
+ * Get the encryption key. Params may be passed in here,
+ * but most symmetric key generation requires only the key
+ * length.
+ *
+ * Warning: the key length is in bytes
+ *
+ * The key can also be imported (not recommended). See importKey()
+ * below for example code.
+ */
+ /* This code generates a random key
+ key = PK11_KeyGen(slot, type, 0, 128/8, 0);
+ if (!key)
+ {
+ goto dsgw_encDec_done;
+ }*/
+ /* Here we are using a static key. This sucks, but we don't really
+ * have much of a choice.*/
+ key = PK11_ImportSymKey(slot, CKM_RC4, PK11_OriginGenerated, operation, &keyItem, 0);
+
+ /*
+ * Some encryption algorithms require parameters. NSS provides
+ * a generic way to create parameters for any algorithm.
+ */
+ params = PK11_GenerateNewParam(type, key);
+ if (!params)
+ {
+ noGood = 1;
+ goto dsgw_encDec_done;
+ }
+
+ /*if (params->data) printBuffer(params->data, params->len);*/
+
+ /*
+ * Cryptographic operations are performed using a "context"
+ * Create one for doing encryption using the key and parameters
+ * generated above.
+ */
+ context = PK11_CreateContextBySymKey(type, operation, key, params);
+ if (!context)
+ {
+ noGood = 1;
+ goto dsgw_encDec_done;
+ }
+
+ /*
+ * Encrypt the data. In general, the input data should be in multiples
+ * of the cipher's block size, and the output size will match the input
+ * size. However, this will not be true for mechanisms that provide
+ * padding.
+ */
+ s = PK11_CipherOp(context, output, &outLen, inlen + 64, input, (int) inlen);
+ if (s != SECSuccess)
+ {
+ noGood = 1;
+ goto dsgw_encDec_done;
+ }
+
+ /*printBuffer(output, outLen);*/
+
+ /*
+ * When a mechanism that provides padding is used, there may be additional
+ * data available after the last input data is processed.
+ *
+ * NOTE: The type of the length output here is different than in PK11_CipherOp
+ */
+ s = PK11_DigestFinal(context, &output[outLen], &len, sizeof output - outLen);
+ if (s != SECSuccess)
+ {
+ noGood = 1;
+ goto dsgw_encDec_done;
+ }
+
+ /*if (len != 0) printBuffer(&output[outLen], len);*/
+
+ outLen += len;
+
+ /*
+ * Terminate the cryptographic operation. Destroying the
+ * context also performs this function.
+ */
+ PK11_Finalize(context);
+
+ /*
+ * Delete the encryption context block, this releases the reference to the key
+ * and frees the context's copy of the parameters, etc.
+ *
+ * The second argument should always be PR_TRUE to free the context structure
+ * itself, in addition to the contents.
+ */
+ PK11_DestroyContext(context, PR_TRUE);
+ context = 0;
+
+dsgw_encDec_done:
+ if (context) PK11_DestroyContext(context, PR_TRUE); /* freeit ?? */
+ if (params) SECITEM_ZfreeItem(params, PR_TRUE);
+ if (key) PK11_FreeSymKey(key);
+ if (slot) PK11_FreeSlot(slot);
+
+ if (noGood == 1) {
+ return(NULL);
+ }
+
+ if (operation == CKA_DECRYPT) {
+ edStr = (char *) output;
+ edStr[outLen] = '\0';
+ } else {
+ edStr = BTOA_DataToAscii(output, outLen);
+ free(output);
+ }
+
+ return(edStr);
+}
+
+
+void
+dsgw_initNSS(void)
+{
+ if (dsgw_NSSInitializedAlready == 1) {
+ return;
+ }
+
+ if (gc->gc_ldapssl && gc->gc_securitypath != NULL ) {
+ NSS_Init(gc->gc_securitypath);
+ } else {
+ NSS_NoDB_Init(NULL);
+ }
+ dsgw_NSSInitializedAlready = 1;
+}
diff --git a/ldap/clients/dsgw/csearch.c b/ldap/clients/dsgw/csearch.c
new file mode 100644
index 00000000..f4fe0c5b
--- /dev/null
+++ b/ldap/clients/dsgw/csearch.c
@@ -0,0 +1,336 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * csearch.c -- CGI program to generate complex search form -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+static void get_request(char *fname);
+static void emit_file(char* filename, struct ldap_searchobj* sop);
+
+
+int main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+ int reqmethod;
+ char *qs = NULL;
+ char *fname = NULL;
+
+ /* Parse out the file=blah.html from the query string*/
+ if (( qs = getenv( "QUERY_STRING" )) != NULL && *qs != '\0' ) {
+ /* parse the query string: */
+ auto char *p, *iter = NULL;
+ qs = dsgw_ch_strdup( qs );
+ for ( p = ldap_utf8strtok_r( qs, "&", &iter ); p != NULL;
+ p = ldap_utf8strtok_r( NULL, "&", &iter )) {
+
+ /*
+ * Get the conf file name. It'll be translated
+ * into /dsgw/context/CONTEXT.conf if
+ * CONTEXT is all alphanumeric (no slahes,
+ * or dots). CONTEXT is passed into the cgi.
+ * if context=CONTEXT is not there, or PATH_INFO
+ * was used, then use dsgw.conf
+ */
+ if ( !strncasecmp( p, "context=", 8 )) {
+ context = dsgw_ch_strdup( p + 8 );
+ dsgw_form_unescape( context );
+ continue;
+ }
+
+ if ( !strncasecmp( p, "file=", 5 )) {
+ fname = dsgw_ch_strdup( p + 5 );
+ dsgw_form_unescape( fname );
+ continue;
+ }
+ }
+ free( qs ); qs = NULL;
+ }
+
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_POST | DSGW_METHOD_GET );
+ dsgw_send_header();
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+{
+ char buf[ 1024 ];
+ getcwd( buf, sizeof(buf));
+ dsgw_log( "cwd: \"%s\"\n", buf );
+}
+#endif
+
+ if ( reqmethod == DSGW_METHOD_POST || reqmethod == DSGW_METHOD_GET ) {
+ get_request(fname);
+ }
+
+ exit( 0 );
+}
+
+
+static void
+get_request(char *fname)
+{
+ auto char* filename = NULL;
+ struct ldap_searchobj* sop = NULL;
+
+ if ( fname == NULL || *fname == '\0' ) {
+ filename = "csearch.html";
+ dsgw_init_searchprefs( &sop );
+ } else if ( !strcmp( fname, "type" )) {
+ filename = "csearchType.html";
+ } else if ( !strcmp( fname, "attr" )) {
+ filename = "csearchAttr.html";
+ } else if ( !strcmp( fname, "match" )) {
+ filename = "csearchMatch.html";
+ } else if ( !strcmp( fname, "string" )) {
+ filename = "csearchString.html";
+ } else if ( !strcmp( fname, "base" )) {
+ filename = "csearchBase.html";
+ }
+ if (filename) {
+ emit_file (filename, sop);
+ }
+ fflush(stdout);
+}
+
+
+static void
+dsgw_emit_options (struct ldap_searchobj** sop, char* searchType, char* searchAttr)
+ /* Emit HTML <OPTION> tags corresponding to search preferences.
+ If searchType==NULL, emit searchType options; otherwise
+ if searchAttr==NULL, emit searchAttr options for the given searchType;
+ otherwise emit searchMatch options for the given searchType and searchAttr.
+ */
+{
+ auto struct ldap_searchobj *so;
+ if (!*sop) dsgw_init_searchprefs (sop);
+ for (so = ldap_first_searchobj(*sop); so != NULLSEARCHOBJ;
+ so = ldap_next_searchobj (*sop, so)) {
+ if (LDAP_IS_SEARCHOBJ_OPTION_SET (so, LDAP_SEARCHOBJ_OPT_INTERNAL)) {
+ continue; /* Skip any marked "internal-only" */
+ }
+ if (!searchType) { /* emit searchType option */
+ dsgw_emitf ("<OPTION VALUE=\"%s\">%s</OPTION>\n",
+ so->so_objtypeprompt,
+ dsgw_get_translation( so->so_objtypeprompt ));
+ } else if (!*searchType || !strcmp (searchType, so->so_objtypeprompt)) {
+ auto struct ldap_searchattr *sa;
+ for (sa = so->so_salist; sa != NULL;
+ sa = sa->sa_next) {
+ if (!searchAttr) { /* emit searchAttr option */
+ dsgw_emitf ("<OPTION VALUE=\"%1$s\">%1$s</OPTION>\n",
+ sa->sa_attrlabel);
+ } else if (!*searchAttr || !strcmp (searchAttr, sa->sa_attrlabel)) {
+ auto int mi;
+ auto struct ldap_searchmatch *sm;
+ for (mi=0, sm = so->so_smlist; sm != NULL;
+ ++mi, sm = sm->sm_next) { /* emit searchMatch option */
+ if (sa->sa_matchtypebitmap & (1L << mi)) {
+ dsgw_emitf ("<OPTION VALUE=\"%1$s\">%1$s</OPTION>\n",
+ sm->sm_matchprompt);
+ }
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+
+static void
+emit_file (char* filename, struct ldap_searchobj* sop)
+{
+ auto FILE* html = dsgw_open_html_file( filename, DSGW_ERROPT_EXIT );
+ auto char line[ BIG_LINE ];
+ auto int argc;
+ auto char **argv;
+
+ while ( dsgw_next_html_line( html, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, dsgw_simple_cond_is_true, NULL )) {
+ if ( dsgw_directive_is( line, "HEAD" )) {
+ dsgw_head_begin();
+ dsgw_emits ("\n");
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_SCRIPT" )) {
+ dsgw_emits("<SCRIPT LANGUAGE=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript-capable browsers\n"
+ "var searchType = '';\n"
+ "var searchAttr = '';\n"
+ "var searchMatch = '';\n" );
+ dsgw_emits ("\n"
+ "function searchTypeSet(val)\n"
+ "{\n"
+ " searchType = val + '';\n"
+ "}\n"
+ "\n"
+ "function searchAttrSet(val)\n"
+ "{\n"
+ " searchAttr = val + '';\n"
+ "}\n"
+ "\n"
+ "function searchMatchSet(val)\n"
+ "{\n"
+ " searchMatch = val + '';\n"
+ "}\n"
+ "\n"
+ "function setHiddenFields(sform)\n"
+ "{\n"
+/*
+ * On Navigator 2.x, the form variable's value seems to get set
+ * *after* the onSumbit handler executes, which is unfortunate.
+ */
+ " if (sform.searchstring.value == '') {\n");
+ dsgw_emit_alert ("searchStringFrame", NULL,
+ XP_GetClientStr (DBT_youDidNotSupplyASearchString_));
+ dsgw_emits (" return false;\n"
+ " }\n"
+ " sform.type.value = searchType;\n"
+ " sform.attr.value = searchAttr;\n"
+ " sform.match.value = searchMatch;\n"
+ " sform.searchstring.select();\n"
+ " sform.searchstring.focus();\n"
+ " return true;\n"
+ "}\n"
+ "\n"
+ "function init()\n"
+ "{}\n"
+ "// End hiding -->\n"
+ "</SCRIPT>\n" );
+
+ } else if ( dsgw_directive_is( line, "EVALUATE" )) {
+ auto int i;
+ for (i = 0; i < argc; ++i) {
+ if (!strcmp (argv[i], "parent.searchBase")) {
+ dsgw_emits (gc->gc_ldapsearchbase);
+ } else if (!strcmp (argv[i], "parent.UFNsearchBase")) {
+#ifdef NOTFORNOW
+ /* ldap_dn2ufn currently gobbles up 'dc' so don't use */
+ /* it for now */
+ auto char* ufn = ldap_dn2ufn (gc->gc_ldapsearchbase);
+ dsgw_emits (ufn);
+ free( ufn );
+#else
+ dsgw_emits (gc->gc_ldapsearchbase);
+#endif
+ }
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_TYPE_BODY" )) {
+ dsgw_emitf ("<BODY %s %s>\n", dsgw_html_body_colors,
+ "onLoad=\"parent.searchTypeSet(document.searchTypeForm.searchType.options"
+ "[document.searchTypeForm.searchType.selectedIndex].value);\"");
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_ATTR_BODY" )) {
+ dsgw_emitf ("<BODY %s %s>\n", dsgw_html_body_colors,
+ "onLoad=\"parent.searchAttrSet(document.searchAttrForm.searchAttr.options"
+ "[document.searchAttrForm.searchAttr.selectedIndex].value);\"");
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_MATCH_BODY" )) {
+ dsgw_emitf ("<BODY %s %s>\n", dsgw_html_body_colors,
+ "onLoad=\"parent.searchMatchSet(document.searchMatchForm.searchMatch.options"
+ "[document.searchMatchForm.searchMatch.selectedIndex].value);\"");
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_STRING_BODY" )) {
+ dsgw_emitf ("<BODY %s %s>\n", dsgw_html_body_colors,
+ "onLoad=\"document.searchStringForm.searchstring.select();"
+ "document.searchStringForm.searchstring.focus();\"");
+ dsgw_emit_alertForm();
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_BASE_BODY" )) {
+ dsgw_emitf ("<BODY %s>\n", dsgw_html_body_colors);
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_TYPE_FORM" )) {
+ dsgw_form_begin ("searchTypeForm",
+ "action=\"%s?file=attr\" target=searchAttrFrame",
+ dsgw_getvp( DSGW_CGINUM_CSEARCH));
+ dsgw_emits("\n");
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_ATTR_FORM" )) {
+ dsgw_form_begin ("searchAttrForm",
+ "action=\"%s?file=match\" target=searchMatchFrame",
+ dsgw_getvp( DSGW_CGINUM_CSEARCH));
+ dsgw_emits("\n");
+ {
+ auto char* searchType = dsgw_get_cgi_var ("searchType", DSGW_CGIVAR_OPTIONAL);
+ if (searchType && *searchType) {
+ dsgw_emitf ("<INPUT TYPE=hidden NAME=searchType VALUE=\"%s\">\n",
+ searchType);
+ }
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_MATCH_FORM" )) {
+ dsgw_form_begin ("searchMatchForm", NULL);
+ dsgw_emits("\n");
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_STRING_FORM" )) {
+ dsgw_form_begin ("searchStringForm", "action=\"%s\" %s %s",
+ dsgw_getvp( DSGW_CGINUM_DOSEARCH ),
+ "onSubmit=\"return parent.setHiddenFields(this)\"",
+ argc > 0 ? argv[0] : "");
+ dsgw_emitf ("\n"
+ "<INPUT TYPE=hidden NAME=mode VALUE=\"complex\">\n"
+ "<INPUT TYPE=hidden NAME=base VALUE=\"%s\">\n"
+ "<INPUT TYPE=hidden NAME=ldapserver VALUE=\"%s\">\n"
+ "<INPUT TYPE=hidden NAME=ldapport VALUE=\"%d\">\n"
+ "<INPUT TYPE=hidden NAME=type>\n"
+ "<INPUT TYPE=hidden NAME=attr>\n"
+ "<INPUT TYPE=hidden NAME=match>\n"
+ "<INPUT TYPE=hidden NAME=context VALUE=\"%s\">\n",
+ gc->gc_ldapsearchbase, gc->gc_ldapserver, gc->gc_ldapport, context);
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_TYPE_SELECT" )) {
+ dsgw_emitf ("<SELECT NAME=searchType "
+ "onChange=\"parent.searchTypeSet(this.options[this.selectedIndex].value);"
+ "this.form.submit();"
+ "parent.searchMatchFrame.location='%s?context=%s&file=match&'+this.name+'='"
+ "+escape(this.options[this.selectedIndex].value);\">\n",
+ dsgw_getvp( DSGW_CGINUM_CSEARCH), context);
+ dsgw_emit_options (&sop, NULL, NULL);
+ dsgw_emits ("</SELECT>\n");
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_ATTR_SELECT" )) {
+ dsgw_emits ("<SELECT NAME=searchAttr"
+ " onChange=\"parent.searchAttrSet(this.options[this.selectedIndex].value);"
+ "this.form.submit();\">\n");
+ {
+ auto char* searchType = dsgw_get_cgi_var ("searchType", DSGW_CGIVAR_OPTIONAL);
+ dsgw_emit_options (&sop, searchType ? searchType : "", NULL);
+ }
+ dsgw_emits ("</SELECT>\n");
+
+ } else if ( dsgw_directive_is( line, "DS_CSEARCH_MATCH_SELECT" )) {
+ dsgw_emits ("<SELECT NAME=searchMatch"
+ " onChange=\"parent.searchMatchSet(this.options[this.selectedIndex].value);\">\n");
+ {
+ auto char* searchType = dsgw_get_cgi_var ("searchType", DSGW_CGIVAR_OPTIONAL);
+ auto char* searchAttr = dsgw_get_cgi_var ("searchAttr", DSGW_CGIVAR_OPTIONAL);
+ dsgw_emit_options (&sop, searchType ? searchType : "", searchAttr ? searchAttr : "");
+ }
+ dsgw_emits ("</SELECT>\n");
+
+ } else if ( dsgw_directive_is( line, "DS_HELP_BUTTON" ) && argc > 0) {
+ dsgw_emit_helpbutton (argv[0]);
+ } else {
+ dsgw_emits (line);
+ }
+ dsgw_argv_free( argv );
+ }
+ }
+ fclose (html);
+}
diff --git a/ldap/clients/dsgw/dbtdsgw.h b/ldap/clients/dsgw/dbtdsgw.h
new file mode 100644
index 00000000..2812c26e
--- /dev/null
+++ b/ldap/clients/dsgw/dbtdsgw.h
@@ -0,0 +1,447 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/**************************************************************************/
+/* CONFIDENTIAL AND PROPRIETARY SOURCE CODE */
+/* OF NETSCAPE COMMUNICATIONS CORPORATION */
+/* */
+/* Copyright © 1996,1997 Netscape Communications Corporation. All Rights */
+/* Reserved. Use of this Source Code is subject to the terms of the */
+/* applicable license agreement from Netscape Communications Corporation. */
+/* */
+/* The copyright notice(s) in this Source Code does not indicate actual */
+/* or intended publication of this Source Code. */
+/**************************************************************************/
+
+#define LIBRARY_NAME "dsgw"
+
+/* avoid warnings for this extremely annoying variable */
+#ifdef LINUX
+#define __DSGW_UNUSED __attribute__((__unused__))
+#else
+#define __DSGW_UNUSED
+#endif
+__DSGW_UNUSED static char dbtdsgwid[] = "$DBT: dsgw referenced v1 $";
+
+#include "i18n.h"
+
+BEGIN_STR(dsgw)
+ ResDef( DBT_LibraryID_, -1, dbtdsgwid )/* extracted from dbtdsgw.h*/
+ ResDef( DBT_unknownHttpRequestMethod_, 1, "Unknown HTTP request method." )/*extracted from error.c*/
+ ResDef( DBT_invalidOrIncompleteHtmlFormData_, 2, "Invalid or incomplete HTML form data." )/*extracted from error.c*/
+ ResDef( DBT_outOfMemory_, 3, "Out of memory." )/*extracted from error.c*/
+ ResDef( DBT_requiredQueryFormInputIsMissing_, 4, "Required query/form input is missing." )/*extracted from error.c*/
+ ResDef( DBT_illegalCharacterInFilePath_, 5, "Illegal character in file path." )/*extracted from error.c*/
+ ResDef( DBT_badOrMissingConfigurationFile_, 6, "Bad or missing configuration file." )/*extracted from error.c*/
+ ResDef( DBT_unableToInitializeLdap_, 7, "Unable to initialize LDAP." )/*extracted from error.c*/
+ ResDef( DBT_anErrorOccurredWhileContactingTh_, 8, "An error occurred while contacting the LDAP server." )/*extracted from error.c*/
+ ResDef( DBT_unknownSearchObjectType_, 9, "Unknown search object type." )/*extracted from error.c*/
+ ResDef( DBT_unknownAttributeLabel_, 10, "Unknown attribute label." )/*extracted from error.c*/
+ ResDef( DBT_unknownMatchPrompt_, 11, "Unknown match prompt." )/*extracted from error.c*/
+ ResDef( DBT_noSearchFiltersForObjectType_, 12, "No search filters for object type." )/*extracted from error.c*/
+ ResDef( DBT_unableToOpenHtmlTemplateFile_, 13, "Unable to open HTML template file." )/*extracted from error.c*/
+ ResDef( DBT_unknownSearchModeUseSmartComplex_, 14, "Unknown search mode - use \"smart\", \"complex\", \"pattern\", or \"auth\"." )/*extracted from error.c*/
+ ResDef( DBT_distinguishedNameMissingInUrl_, 15, "Distinguished Name missing in URL." )/*extracted from error.c*/
+ ResDef( DBT_unknownScopeInUrlShouldBeBaseSub_, 16, "Unknown scope in URL (should be base, sub, or one)." )/*extracted from error.c*/
+ ResDef( DBT_unrecognizedUrlOrUnknownError_, 17, "Unrecognized URL or unknown error." )/*extracted from error.c*/
+ ResDef( DBT_badUrlFormat_, 18, "Bad URL format." )/*extracted from error.c*/
+ ResDef( DBT_internalError_, 19, "Internal error." )/*extracted from error.c*/
+ ResDef( DBT_unableToWriteTemplateIndexFile_, 20, "Unable to write template index file." )/*extracted from error.c*/
+ ResDef( DBT_unableToOpenTemplateIndexFile_, 21, "Unable to open template index file." )/*extracted from error.c*/
+ ResDef( DBT_unableToReadDirectory_, 22, "Unable to read directory." )/*extracted from error.c*/
+ ResDef( DBT_ldapSslInitializationFailedCheck_, 23, "LDAP SSL initialization failed (check the security path)." )/*extracted from error.c*/
+ ResDef( DBT_forTheUsersAndGroupsFormsToWorkO_, 24, "For the Users and Groups forms to work over SSL, you or your server administrator needs to activate SSL for this Administration Server. The Encryption|On/Off page can be used to do so. " )/*extracted from error.c*/
+ ResDef( DBT_authenticationCredentialsNotFoun_, 25, "Authentication credentials not found in authentication database." )/*extracted from error.c*/
+ ResDef( DBT_errorRetrievingDataFromTheAuthen_, 26, "Error retrieving data from the authentication database." )/*extracted from error.c*/
+ ResDef( DBT_yourAuthenticationCredentialsHav_, 27, "Your authentication credentials have expired." )/*extracted from error.c*/
+ ResDef( DBT_unableToCreateRandomString_, 28, "Unable to create a random string." )/*extracted from error.c*/
+ ResDef( DBT_noDistinguishedNameWasProvidedWh_, 29, "No distinguished name was provided when retrieving credentials." )/*extracted from error.c*/
+ ResDef( DBT_cannotOpenAuthenticationDatabase_, 30, "Cannot open authentication database." )/*extracted from error.c*/
+ ResDef( DBT_couldNotAppendDataToTheAuthentic_, 31, "Could not append data to the authentication database." )/*extracted from error.c*/
+ ResDef( DBT_noDirectoryManagerIsDefined_, 32, "No Directory Manager is defined." )/*extracted from error.c*/
+ ResDef( DBT_noSearchStringWasProvidedPleaseT_, 33, "No search string was provided. Please try again." )/*extracted from error.c*/
+ ResDef( DBT_tooManyArgumentsOnOneLineInTheCo_, 34, "Too many arguments on one line in the config. file." )/*extracted from error.c*/
+ ResDef( DBT_failedToInitializeWindowsSockets_, 35, "Failed to initialize Windows Sockets." )/*extracted from error.c*/
+ ResDef( DBT_authenticationCredentialsCouldNo_, 36, "Authentication credentials could not be obtained from the Administration Server." )/*extracted from error.c*/
+ ResDef( DBT_distinguishedNameMissingInLdapdb_, 37, "Distinguished Name missing in ldapdb:// URL." )/*extracted from error.c*/
+ ResDef( DBT_unrecognizedUrlOrUnknownError_1, 38, "Unrecognized URL or unknown error." )/*extracted from error.c*/
+ ResDef( DBT_badUrlFormat_1, 39, "Bad URL format." )/*extracted from error.c*/
+ ResDef( DBT_anErrorOccurredWhileInitializing_, 40, "An error occurred while initializing the local ldap database." )/*extracted from error.c*/
+ ResDef( DBT_unknownDirectoryServiceTypeUseLo_, 41, "Unknown directory service type - use \"local\" or \"remote\"." )/*extracted from error.c*/
+ ResDef( DBT_anErrorOccurredWhileReadingTheDb_, 42, "An error occurred while reading the db configuration file." )/*extracted from error.c*/
+ ResDef( DBT_nshomeUserdbPathWasNull_, 43, "NSHOME/userdb path was NULL." )/*extracted from error.c*/
+ ResDef( DBT_theDirectoryServiceConfiguration_, 44, "The directory service configuration could not be updated." )/*extracted from error.c*/
+ ResDef( DBT_theEntryCouldNotBeReadFromTheDir_, 45, "The entry could not be read from the directory." )/*extracted from error.c*/
+ ResDef( DBT_theLdapDatabaseCouldNotBeErased_, 46, "The LDAP database could not be erased." )/*extracted from error.c*/
+ ResDef( DBT_youMayNotChangeEntriesBesidesYou_, 47, "You may not change entries besides your own." )/*extracted from error.c*/
+ ResDef( DBT_problem_, 48, "Problem" )/*extracted from error.c*/
+ ResDef( DBT_authenticationProblem_, 49, "Authentication Problem" )/*extracted from error.c*/
+ ResDef( DBT_NPYouMustReAuthenticateBeforeCon_, 50, ".\n<P>You must re-authenticate before continuing.\n" )/*extracted from error.c*/
+ ResDef( DBT_NPYouMustReAuthenticateBeforeCon_1, 51, ".\n<P>You must re-authenticate before continuing.\n" )/*extracted from error.c*/
+ ResDef( DBT_unknownError_, 52, "unknown error" )/*extracted from error.c*/
+ ResDef( DBT_theOperationWasSuccessful_, 53, "The operation was successful." )/*extracted from error.c*/
+ ResDef( DBT_anInternalErrorOccurredInTheServ_, 54, "An internal error occurred in the server. This usually\nindicates a serious malfunction in the server and should be\nbrought to the attention of your server administrator." )/*extracted from error.c*/
+ ResDef( DBT_theServerCouldNotUnderstandTheRe_, 55, "The server could not understand the request which was sent to\nit by the gateway." )/*extracted from error.c*/
+ ResDef( DBT_aTimeLimitWasExceededInRespondin_, 56, "A time limit was exceeded in responding to your request. If\nyou are searching for entries, you may achieve better results\nif you are more specific in your search." )/*extracted from error.c*/
+ ResDef( DBT_aSizeLimitWasExceededInRespondin_, 57, "A size limit was exceeded in responding to your request. If\nyou are searching for entries, you may achieve better results\nif you are more specific in your search, because too many entries\nmatched your search criteria." )/*extracted from error.c*/
+ ResDef( DBT_theGatewayAttemptedToAuthenticat_, 58, "The gateway attempted to authenticate to the server using\na method the server doesn't understand." )/*extracted from error.c*/
+ ResDef( DBT_theGatewayAttemptedToAuthenticat_1, 59, "The gateway attempted to authenticate to the server using an\nauthentication method which the server does not support. " )/*extracted from error.c*/
+ ResDef( DBT_yourRequestCouldNotBeFulfilledPr_, 60, "Your request could not be fulfilled, probably because the server\nthat was contacted does not contain the data you are looking\nfor. It is possible that a referral to another server was\nreturned but could not be followed. If you were trying to make\nchanges to the directory, it may be that the server that holds\nthe master copy of the data is not available." )/*extracted from error.c*/
+ ResDef( DBT_yourRequestExceededAnAdministrat_, 61, "Your request exceeded an administrative limit in the server." )/*extracted from error.c*/
+ ResDef( DBT_aCriticalExtensionThatTheGateway_, 62, "A critical extension that the gateway requested is not available in this server." )/*extracted from error.c*/
+ ResDef( DBT_theServerWasUnableToProcessTheRe_, 63, "The server was unable to process the request, becase the\nrequest referred to an attribute which does not exist in the\nentry." )/*extracted from error.c*/
+ ResDef( DBT_theServerWasUnableToFulfillYourR_, 64, "The server was unable to fulfill your request, because the\nrequest violates a constraint." )/*extracted from error.c*/
+ ResDef( DBT_theServerCouldNotAddAValueToTheE_, 65, "The server could not add a value to the entry, because that\nvalue is already contained in the entry." )/*extracted from error.c*/
+ ResDef( DBT_theServerCouldNotLocateTheEntryI_, 66, "The server could not locate the entry. If adding a new entry,\nbe sure that the parent of the entry you are trying to add exists.\nIf you received this error while searching, it indicates that the\nentry which was being searched for does not exist.\nIf you were attempting to authenticate as the directory manager and\nreceived this error, check the gateway configuration file." )/*extracted from error.c*/
+ ResDef( DBT_aDistinguishedNameWasNotInThePro_, 67, "A distinguished name was not in the proper format. " )/*extracted from error.c*/
+ ResDef( DBT_theEntryYouAttemptedToAuthentica_, 68, "The entry you attempted to authenticate as does not have a\npassword set, or is missing other required authentication\ncredentials. You cannot authenticate as that entry until the\nappropriate attributes have been added by the directory manager. " )/*extracted from error.c*/
+ ResDef( DBT_thePasswordOrOtherAuthentication_, 69, "The password (or other authentication credentials) you supplied\nis incorrect." )/*extracted from error.c*/
+ ResDef( DBT_youDoNotHaveSufficientPrivileges_, 70, "You do not have sufficient privileges to perform the operation. " )/*extracted from error.c*/
+ ResDef( DBT_theServerIsTooBusyToServiceYourR_, 71, "The server is too busy to service your request. Try again\nin a few minutes." )/*extracted from error.c*/
+ ResDef( DBT_theLdapServerCouldNotBeContacted_, 72, "The LDAP server could not be contacted." )/*extracted from error.c*/
+ ResDef( DBT_theServerWasUnwilliingToProcessY_, 73, "The server was unwilling to process your request. Usually,\nthis indicates that serving your request would put a heavy load\non the server. It may also indicate that the server is not\nconfigured to process your request. If searching, you may wish\nto limit the scope of your search." )/*extracted from error.c*/
+ ResDef( DBT_theDirectoryServerCouldNotHonorY_, 74, "The directory server could not honor your request because it\nviolates the schema requirements. Typically, this means that you\nhave not provided a value for a required field. It could also mean\nthat the schema in the directory server needs to be updated." )/*extracted from error.c*/
+ ResDef( DBT_theDirectoryServerWillNotAllowYo_, 75, "The directory server will not allow you to delete or rename\nan entry if that entry has children. If you wish to do this, you\nmust first delete all the child entries." )/*extracted from error.c*/
+ ResDef( DBT_theServerWasUnableToAddANewEntry_, 76, "The server was unable to add a new entry, or rename an existing\nentry, because an entry by that name already exists." )/*extracted from error.c*/
+ ResDef( DBT_yourRequestWouldAffectSeveralDir_, 77, "Your request would affect several directory servers." )/*extracted from error.c*/
+ ResDef( DBT_theDirectoryServerCouldNotBeCont_, 78, "The directory server could not be contacted. Contact your\nserver administrator for assistance." )/*extracted from error.c*/
+ ResDef( DBT_anErrorOccuredWhileSendingDataTo_, 79, "An error occured while sending data to the server." )/*extracted from error.c*/
+ ResDef( DBT_anErrorOccuredWhileReadingDataFr_, 80, "An error occured while reading data from the server." )/*extracted from error.c*/
+ ResDef( DBT_theServerDidNotRespondToTheReque_, 81, "The server did not respond to the request. \nThe request timed out." )/*extracted from error.c*/
+ ResDef( DBT_theServerDoesNotSupportTheAuthen_, 82, "The server does not support the authentication method used\nby the gateway." )/*extracted from error.c*/
+ ResDef( DBT_theSearchFilterConstructedByTheG_, 83, "The search filter constructed by the gateway was in error." )/*extracted from error.c*/
+ ResDef( DBT_theOperationWasCancelledAtYourRe_, 84, "The operation was cancelled at your request." )/*extracted from error.c*/
+ ResDef( DBT_anInternalErrorOccurredInTheLibr_, 85, "An internal error occurred in the library - a parameter was\nincorrect." )/*extracted from error.c*/
+ ResDef( DBT_aConnectionToTheServerCouldNotBe_, 86, "A connection to the server could not be opened. Contact your\nserver administrator for assistance." )/*extracted from error.c*/
+ ResDef( DBT_anUnknownErrorWasEncountered_, 87, "An unknown error was encountered." )/*extracted from error.c*/
+ ResDef( DBT_entryAlreadyExists_, 88, "Entry Already Exists" )/*extracted from edit.c*/
+ ResDef( DBT_anEntryNamed_, 89, "An entry named " )/*extracted from edit.c*/
+ ResDef( DBT_onmouseoverWindowStatusClickHere_, 90, "onMouseOver=\"window.status='Click here to view this entry'; return true\"" )/*extracted from edit.c*/
+ ResDef( DBT_alreadyExistsPPleaseChooseAnothe_, 91, " already exists.<P>Please choose another name and/or location.\n<P>\n" )/*extracted from edit.c*/
+ ResDef( DBT_parentEntryDoesNotExist_, 92, "Parent entry does not exist" )/*extracted from edit.c*/
+ ResDef( DBT_youCannotAddAnEntryByTheNamePBSB_, 93, "You cannot add an entry by the name:<P><B>%s</B>,<P>\nbecause the parent of that entry does not exist.<P>\nBefore you can add this entry, you must first add\n" )/*extracted from edit.c*/
+ ResDef( DBT_itsParentN_, 94, "its parent.\n" )/*extracted from edit.c*/
+ ResDef( DBT_anEntryNamedPBSBN_, 95, "an entry named:<P><B>%s</B>.\n" )/*extracted from edit.c*/
+ ResDef( DBT_warningNoAuthenticationContinuin_, 96, "Warning: no authentication (continuing)...\n" )/*extracted from domodify.c*/
+ ResDef( DBT_SDirectoryEntry_, 97, "%s Directory Entry" )/*extracted from domodify.c*/
+ ResDef( DBT_PreEntryDnSPrePN_, 98, "<PRE>Entry DN: %s</PRE><P>\n" )/*extracted from domodify.c*/
+ ResDef( DBT_changesToBSBHaveBeenSaved_, 99, "Changes to <B>%s</B> have been saved." )/*extracted from domodify.c*/
+ ResDef( DBT_BSBHasBeenAdded_, 100, "<B>%s</B> has been added." )/*extracted from domodify.c*/
+ ResDef( DBT_BSBHasBeenDeleted_, 101, "<B>%s</B> has been deleted." )/*extracted from domodify.c*/
+ ResDef( DBT_renamedBSBToBSB_, 102, "Renamed <B>%s</B> to <B>%s</B>." )/*extracted from domodify.c*/
+ ResDef( DBT_PBNoteBBecauseYouSTheEntryYouWer_, 103, "<P><B>Note:</B> because you %s the entry you were \nauthenticated as, it was necessary to discard your \nauthentication credentials. You will need to authenticate \nagain to make additional changes.\n" )/*extracted from domodify.c*/
+ ResDef( DBT_deleted_, 104, "deleted" )/*extracted from domodify.c*/
+ ResDef( DBT_renamed_, 105, "renamed" )/*extracted from domodify.c*/
+ ResDef( DBT_changedThePasswordOf_, 106, "changed the password of" )/*extracted from domodify.c*/
+ ResDef( DBT_attributeSWasChangedBrN_, 107, "Attribute %s was changed<BR>\n" )/*extracted from domodify.c*/
+ ResDef( DBT_TnotAsciiLdBytesN_, 108, "\tNOT ASCII (%ld bytes)\n" )/*extracted from domodify.c*/
+ ResDef( DBT_noValuesWereEnteredPleaseTryAgai_, 109, "No values were entered. Please try again.\n" )/*extracted from domodify.c*/
+ ResDef( DBT_noChangesWereMadeN_, 110, "No changes were made.\n" )/*extracted from domodify.c; XXXmcs: no longer used*/
+ ResDef( DBT_PSendingSToTheDirectoryServerN_, 111, "<P>Sending %s to the directory server...\n" )/*extracted from domodify.c*/
+ ResDef( DBT_information_, 112, "information" )/*extracted from domodify.c*/
+ ResDef( DBT_changes_, 113, "changes" )/*extracted from domodify.c*/
+ ResDef( DBT_PSuccessfullyAddedEntryN_, 114, "<P>Successfully added entry.\n" )/*extracted from domodify.c*/
+ ResDef( DBT_PSuccessfullyEditedEntryYourChan_, 115, "<P>Successfully edited entry. Your changes have been saved.\n" )/*extracted from domodify.c*/
+ ResDef( DBT_PSuccessfullyDeletedEntryN_, 116, "<P>Successfully deleted entry.\n" )/*extracted from domodify.c*/
+ ResDef( DBT_PreTheNewNameForTheEntryIsSNPreH_, 117, "<PRE>The new name for the entry is: %s\n</PRE><HR>\n" )/*extracted from domodify.c*/
+ ResDef( DBT_PSuccessfullyRenamedEntryN_, 118, "<P>Successfully renamed entry.\n" )/*extracted from domodify.c*/
+ ResDef( DBT_youMustProvideTheOldPassword_, 119, "You must provide the old password." )/*extracted from domodify.c*/
+ ResDef( DBT_youMustProvideANewPasswordPlease_, 120, "You must provide a new password. Please try again" )/*extracted from domodify.c*/
+ ResDef( DBT_theNewAndConfirmingPasswordsDoNo_, 121, "The new and confirming passwords do not match. Please try again" )/*extracted from domodify.c*/
+ ResDef( DBT_BrTheSBSBIsAlreadyInUsePleaseCho_, 122, "<BR>The %s <B>%s</B> is already in use. Please choose a different one.<BR>\n" )/*extracted from domodify.c*/
+ ResDef( DBT_missingFormDataElement100s_, 123, "missing form data element \"%.100s\"" )/*extracted from cgiutil.c*/
+ ResDef( DBT_initializingConfigInfo_, 124, "Initializing config info" )/*extracted from config.c*/
+ ResDef( DBT_cannotOpenFile_, 125, "Cannot open file." )/*extracted from config.c*/
+ ResDef( DBT_malformedDbconfFile_, 126, "Malformed dbconf file." )/*extracted from config.c*/
+ ResDef( DBT_missingPropertyNameInDbconfFile_, 127, "Missing property name in dbconf file." )/*extracted from config.c*/
+ ResDef( DBT_outOfMemory_1, 128, "Out of memory." )/*extracted from config.c*/
+ ResDef( DBT_missingDirectiveInDbconfFile_, 129, "Missing directive in dbconf file." )/*extracted from config.c*/
+ ResDef( DBT_cannotOpenConfigFileSN_, 130, "Cannot open config file \"%s\"\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForAuthlifetimeDi_, 131, "Missing argument for \"authlifetime\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForDirmgrDirectiv_, 132, "Missing argument for \"dirmgr\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForBaseurlDirecti_, 133, "Missing argument for \"baseurl\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_badUrlProvidedForBaseurlDirectiv_, 134, "Bad URL provided for \"baseurl\" directive - the base DN is missing\n" )/*extracted from config.c*/
+ ResDef( DBT_parsingBaseurlDirective_, 135, "parsing baseurl directive" )/*extracted from config.c*/
+ ResDef( DBT_badUrlProvidedForBaseurlDirectiv_1, 136, "Bad URL provided for \"baseurl\" directive - not an \"ldap://\" URL\n" )/*extracted from config.c*/
+ ResDef( DBT_LdapsUrlsAreNotYetSupportedN_, 137, "\"ldaps://\" URLs are not yet supported\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentsForTemplateDirec_, 138, "Missing arguments for \"template\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForSslrequiredDir_, 139, "Missing argument for \"sslrequired\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_unknownArgumentToSslrequiredDire_, 140, "Unknown argument to \"sslrequired\" directive (should be \"never\", \"whenauthenticated\", \"always\")\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForSecuritypathDi_, 141, "Missing argument for \"securitypath\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForLocationSuffix_, 142, "Missing argument for \"location-suffix\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_threeArgumentsAreRequiredForTheL_, 143, "Three arguments are required for the \"location\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_atLeastTwoArgumentsAreRequiredFo_, 144, "At least two arguments are required for the \"newtype\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_unknownLocationInNewtypeDirectiv_, 145, "Unknown location in \"newtype\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_threeOrFourArgumentsAreRequiredF_, 146, "Three or four arguments are required for the \"tmplset\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_fourArgumentsAreRequiredForTheAt_, 147, "Four arguments are required for the \"attrvset\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForCharsetDirecti_, 148, "Missing argument for \"charset\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForClientlanguage_, 149, "Missing argument for \"ClientLanguage\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForAdminlanguageD_, 150, "Missing argument for \"AdminLanguage\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForDefaultlanguag_, 151, "Missing argument for \"DefaultLanguage\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingFilenameForIncludeDirecti_, 152, "Missing filename for \"include\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_unknownDirectiveInConfigFileN_, 153, "Unknown directive in config file\n" )/*extracted from config.c*/
+ ResDef( DBT_EraseDbCouldNotOpenLcacheConfFil_, 154, "<= erase_db could not open lcache.conf file \"%s\"\n" )/*extracted from config.c*/
+ ResDef( DBT_FontSize1NPTheDatabaseHasBeenDel_, 155, "<FONT SIZE=\"+1\">\n<P>The database has been deleted. Creating new database... \n</FONT>\n " )/*extracted from config.c*/
+ ResDef( DBT_FontSize1NPTheDatabaseCouldNotBe_, 156, "<FONT SIZE=\"+1\">\n<P>The database could not be deleted \n</FONT>\n " )/*extracted from config.c*/
+ ResDef( DBT_AppSuffixCouldNotOpenLdifFileSN_, 157, "<= app_suffix could not open ldif file \"%s\"\n" )/*extracted from config.c*/
+ ResDef( DBT_AppSuffixCouldNotOpenTmpFileSN_, 158, "<= app_suffix could not open tmp file \"%s\"\n" )/*extracted from config.c*/
+ ResDef( DBT_unableToRenameSToS_, 159, "Unable to rename %s to %s" )/*extracted from config.c*/
+ ResDef( DBT_nullPointerReturnedByDbconfReadD_, 160, "null pointer returned by dbconf_read_default_dbinfo()." )/*extracted from config.c*/
+ ResDef( DBT_badLdapdbUrlTheBaseDnIsMissingN_, 161, "Bad \"ldapdb\" URL - the base DN is missing\n" )/*extracted from config.c*/
+ ResDef( DBT_badLdapdbUrlN_, 162, "Bad \"ldapdb\" URL\n" )/*extracted from config.c*/
+ ResDef( DBT_badUrlProvidedForBaseurlDirectiv_2, 163, "Bad URL provided for \"baseurl\" directive - the base DN is missing\n" )/*extracted from config.c*/
+ ResDef( DBT_parsingBaseurlDirective_1, 164, "parsing baseurl directive" )/*extracted from config.c*/
+ ResDef( DBT_badUrlProvidedForBaseurlDirectiv_3, 165, "Bad URL provided for \"baseurl\" directive - not an \"ldap:// or ldapdb://\" URL\n" )/*extracted from config.c*/
+ ResDef( DBT_LdapsUrlsAreNotYetSupportedN_1, 166, "\"ldaps://\" URLs are not yet supported\n" )/*extracted from config.c*/
+ ResDef( DBT_noValueGivenForBinddn_, 167, "No value given for binddn" )/*extracted from config.c*/
+ ResDef( DBT_noValueGivenForBindpw_, 168, "No value given for bindpw" )/*extracted from config.c*/
+ ResDef( DBT_thereIsNoDefaultDirectoryService_, 169, "There is no default directory service defined in the dbswitch.conf file" )/*extracted from config.c*/
+ ResDef( DBT_cannotOpenConfigFileSForWritingN_, 170, "Cannot open config file \"%s\" for writing\n" )/*extracted from config.c*/
+ ResDef( DBT_unableToRenameSToS_1, 171, "Unable to rename %s to %s" )/*extracted from config.c*/
+ ResDef( DBT_configFileS_, 172, "config file %s: " )/*extracted from config.c*/
+ ResDef( DBT_configFileSLineD_, 173, "config file %s: line %d: " )/*extracted from config.c*/
+ ResDef( DBT_maxD_, 174, "max %d" )/*extracted from config.c*/
+ ResDef( DBT_ok_, 175, " OK " )/*extracted from domodify.c*/
+ ResDef( DBT_closeWindow_, 176, "Close Window" )/*extracted from domodify.c*/
+ ResDef( DBT_goBack_, 177, "Go Back" )/*extracted from domodify.c*/
+ ResDef( DBT_CryptLockedSGmt_, 178, "{crypt}LOCKED [%s GMT]" )/*extracted from domodify.c*/
+ ResDef( DBT_returnToMain_, 179, "Return to Main" )/*extracted from dsgwutil.c*/
+ ResDef( DBT_help_, 181, " Help " )/*extracted from dsgwutil.c*/
+ ResDef( DBT_help_1, 182, "Help" )/*extracted from dsgwutil.c*/
+ ResDef( DBT_helpIsNotYetAvailable_, 184, "Help is not yet available." )/*extracted from dsgwutil.c*/
+ ResDef( DBT_closeWindow_1, 186, "Close Window" )/*extracted from edit.c*/
+ ResDef( DBT_closeWindow_2, 187, "Close Window" )/*extracted from edit.c*/
+ ResDef( DBT_missingTemplate_, 188, "The URL did not include a template name"
+ " (immediately following the '?')." )/*edit.c*/
+ ResDef( DBT_authenticate_, 189, "Authenticate..." )/*extracted from emitauth.c*/
+ ResDef( DBT_discardAuthenticationCredentials_, 190, "Discard authentication credentials (log out)?" )/*extracted from emitauth.c*/
+ ResDef( DBT_youDidNotSupplyASearchString_, 191, "Please type a search string" )/*extracted from emitauth.c*/
+ ResDef( DBT_theFirstStepInAuthenticatingToTh_, 192, "The first step in authenticating to the directory is identifying\nyourself.<br>Please type your name:" )/*extracted from emitauth.c*/
+ ResDef( DBT_continue_, 193, "Continue" )/*extracted from emitauth.c*/
+ ResDef( DBT_continue_1, 194, "Continue" )/*extracted from emitauth.c*/
+ ResDef( DBT_cancel_, 195, "Cancel" )/*extracted from emitauth.c*/
+ ResDef( DBT_authenticateAsDirectoryManagerNb_, 196, "Authenticate as directory manager\"> "
+ "\302\240" /* nbsp, in UTF-8 */
+ "(only available to Directory Administrators)\n" )/*extracted from emitauth.c*/
+ ResDef( DBT_authenticate_1, 197, "Authenticate..." )/*extracted from emitauth.c*/
+ ResDef( DBT_discardAuthenticationCredentials_1, 198, "Discard authentication credentials?" )/*extracted from emitauth.c*/
+ ResDef( DBT_continue_2, 200, "Continue" )/*extracted from emitauth.c*/
+ ResDef( DBT_continue_3, 201, "Continue" )/*extracted from emitauth.c*/
+ ResDef( DBT_cancel_1, 202, "Cancel" )/*extracted from emitauth.c*/
+ ResDef( DBT_authenticateLogInToTheDirectory_, 203, "Authenticate (log in) to the directory" )/*extracted from emitauth.c*/
+ ResDef( DBT_youAreAboutToAuthenticate_, 204, "You are about to authenticate to the directory as"
+ " <B>%s</B>. To complete the authentication process, type your password.\n" )
+ ResDef( DBT_beforeYouCanEditOrAddEntriesYouM_, 206, "Before you can edit or add entries, you must authenticate\n(log in) to the directory. This window will guide\nyou through the steps of the authentication\nprocess.\n" )/*extracted from emitauth.c*/
+ ResDef( DBT_fromThisScreenYouMayAuthenticate_, 207, "From this screen you may authenticate, or log in, \nto the directory. You will need to authenticate\nbefore you can modify directory entries. If you\nattempt to modify an entry without authenticating,\nyou will be asked to log in.\n" )/*extracted from emitauth.c*/
+ ResDef( DBT_authenticationStatus_, 208, "Authentication Status" )/*extracted from emitauth.c*/
+ ResDef( DBT_FormNyouAreCurrentlyAuthenticate_, 209, "<form>\nYou are currently authenticated to the directory as " )/*extracted from emitauth.c*/
+ ResDef( DBT_NifYouWishToDiscardYourAuthentic_, 210, ".\nIf you wish to discard your authentication credentials and log out of the directory, click on the button below." )/*extracted from emitauth.c*/
+ ResDef( DBT_discardAuthenticationCredentials_2, 211, "Discard Authentication Credentials (log out)" )/*extracted from emitauth.c*/
+ ResDef( DBT_yourAuthenticationCredentialsFor_, 212, "Your authentication credentials for " )/*extracted from emitauth.c*/
+ ResDef( DBT_haveExpiredN_, 213, "have expired.\n<HR>\n" )/*extracted from emitauth.c*/
+ ResDef( DBT_currentlyYouAreNotAuthenticatedT_, 214, "Currently, you are not authenticated to the directory.<HR>\n" )/*extracted from emitauth.c*/
+ ResDef( DBT_missingS_, 215, "missing \"%s=\"" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_unknownSS_, 216, "unknown \"%s=%s\"" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_unknownOptionS_, 217, "unknown option %s" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_unknownSyntaxSN_, 218, "unknown syntax=%s\n" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_HtmlTypeSNotSupportedBrN_, 219, "** HTML type \"%s\" not supported **<BR>\n" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_edit_, 224, "Edit" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_saveChanges_, 225, "Save Changes" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_obsolete_226, 226, "modify" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_obsolete_227, 227, "add" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_delete_, 228, "Delete" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_deleteThisEntry_, 229, "Delete this entry?" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_rename_, 230, "Rename" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_enterANewNameForThisEntry_, 231, "Enter a new name for this entry:" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_editAs_, 232, "Edit As" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_missingS_1, 233, "missing %s=" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_closeWindow_3, 234, "Close Window" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_edit_1, 235, "Edit..." )/*extracted from entrydisplay.c*/
+ ResDef( DBT_missingSN_, 236, "missing \"%s=\"\n" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_unknownSetSN_, 237, "unknown set \"%s\"\n" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_unknownSyntaxSN_1, 238, "unknown syntax \"%s\"\n" )/*extracted from entrydisplay.c*/
+ ResDef( DBT_reAuthenticate_, 239, "Re-Authenticate" )/*extracted from error.c*/
+ ResDef( DBT_closeWindow_4, 240, "Close Window" )/*extracted from error.c*/
+ ResDef( DBT_obsolete_241, 241, "Do you really want to " )/*extracted from htmlparse.c*/
+ ResDef( DBT_obsolete_242, 242, "?" )/*extracted from htmlparse.c*/
+ ResDef( DBT_ok_1, 243, " OK " )/*extracted from htmlparse.c*/
+ ResDef( DBT_ok_2, 244, " OK " )/*extracted from htmlparse.c*/
+ ResDef( DBT_reset_, 245, " Reset " )/*extracted from htmlparse.c*/
+ ResDef( DBT_done_, 246, " Done " )/*extracted from htmlparse.c*/
+ ResDef( DBT_cancel_2, 247, " Cancel " )/*extracted from htmlparse.c*/
+ ResDef( DBT_foundAnotherIfNestedIfsAreNotSup_, 248, "found another IF (nested IFs are not supported)" )/*extracted from htmlparse.c*/
+ ResDef( DBT_foundElseButDidnTSeeAnIf_, 249, "found ELSE but didn't see an IF" )/*extracted from htmlparse.c*/
+ ResDef( DBT_foundElseAfterElseExpectingEndif_, 250, "found ELSE after ELSE (expecting ENDIF)" )/*extracted from htmlparse.c*/
+ ResDef( DBT_foundElifButDidnTSeeAnIf_, 251, "found ELIF but didn't see an IF" )/*extracted from htmlparse.c*/
+ ResDef( DBT_foundElifAfterElseExpectingEndif_, 252, "found ELIF after ELSE (expecting ENDIF)" )/*extracted from htmlparse.c*/
+ ResDef( DBT_foundEndifButDidnTSeeAnIf_, 253, "found ENDIF but didn't see an IF" )/*extracted from htmlparse.c*/
+ ResDef( DBT_BrBTemplateErrorBSBrN_, 254, "<BR><B>template error:</B> %s<BR>\n" )/*extracted from htmlparse.c*/
+ ResDef( DBT_ldapInitLcacheInitAttemptedBefor_, 255, "ldap_init/lcache_init attempted before config file read" )/*extracted from ldaputil.c*/
+ ResDef( DBT_notRunningUnderTheAdministration_, 256, "not running under the administration server" )/*extracted from ldaputil.c*/
+ ResDef( DBT_couldNotInitializePermissions_, 257, "Could not initialize permissions" )/*extracted from ldaputil.c*/
+ ResDef( DBT_couldNotMapUsernameToADnErrorFro_, 258, "Could not map username to a DN (error from admin server)" )/*extracted from ldaputil.c*/
+ ResDef( DBT_couldNotGetCurrentUsername_, 259, "Could not get current username" )/*extracted from ldaputil.c*/
+ ResDef( DBT_couldNotGetCurrentUserPassword_, 260, "Could not get current user password" )/*extracted from ldaputil.c*/
+ ResDef( DBT_obsolete_261, 261, "Error: %s" )/*extracted from ldaputil.c*/
+ ResDef( DBT_noteThereIsNoDisplayTemplateForT_, 262, "Note: there is no display template for this type of entry available, so it is\ndisplayed below using a default method." )/*extracted from ldaputil.c*/
+ ResDef( DBT_invalidUserIdOrNullLdapHandle_, 263, "Invalid user id or NULL LDAP handle" )/*extracted from ldaputil.c*/
+ ResDef( DBT_noMatchForUserId_, 264, "no match for user id" )/*extracted from ldaputil.c*/
+ ResDef( DBT_moreThanOneMatchForUserId_, 265, "more than one match for user id" )/*extracted from ldaputil.c*/
+ ResDef( DBT_theEntireDirectory_, 266, "the entire directory" )/*extracted from ldaputil.c*/
+ ResDef( DBT_twoArgumentsAreRequiredForTheInc_, 267, "Two arguments are required for the \"includeset\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_theAttributeValueRequestedWasNot_, 268, "The attribute value requested was not found in the entry." )/* extracted from error.c*/
+ ResDef( DBT_missingArgumentForNLS_, 269, "Missing argument for \"NLS\" directive\n" )
+ ResDef( DBT_aValueMustBeSpecifiedForNTUserId, 270, "A value must be specified for NT User Id.\n" )
+ ResDef( DBT_theCombinationOfNTUserIdNTDomain_, 271, "The combination of NT User Id, NT Domain Id is not unique in the directory.\n" )
+ ResDef( DBT_valuesMustBeSpecifiedForBothNTUser_ , 272, "Values must be specified for both NT User Id and NT Domain Id.\n" )
+ ResDef( DBT_theNTUserIdValueMustNotExceed_, 273, "The NT User Id value must not exceed 20 characters in length.\n" )
+ ResDef( DBT_enterNameForNewEntry_, 274, "Please provide a name for the new entry." )
+ ResDef( DBT_enterLocationForNewEntry_, 275, "Please select a location for the new entry." )
+ ResDef( DBT_titleNewEntry_, 276, "New Entry" )
+ ResDef( DBT_noDirMgrIsDefined_, 277, "In order to use this feature, there must be a dirmgr defined in dsgw.conf")
+ ResDef( DBT_threeOrFourArgumentsAreRequiredF_2, 278, "Three or four arguments are required for the \"vcard-property\" directive\n" )
+ ResDef( DBT_vcardPropertySyntaxMustBeCisOrMl_, 279, "VCard property syntax must be \"cis\" or \"mls\"\n" )
+ ResDef( DBT_Found0Entries_, 280, "Found no entries.\n%2$s" )
+ ResDef( DBT_Found0EntriesWhere_, 281, "Found no entries where the %2$s %3$s '%4$s'.\n" )
+ ResDef( DBT_SearchFound0Entries_, 282, "Searched and found no entries.\n%2$s" )
+ ResDef( DBT_SearchFound0EntriesWhere_, 283, "Searched and found no entries where the %2$s %3$s %4$s'.\n" )
+ ResDef( DBT_Found1Entry_, 284, "Found 1 entry.\n%2$s" )
+ ResDef( DBT_Found1EntryWhere_, 285, "Found 1 entry where the %2$s %3$s '%4$s'.\n" )
+ ResDef( DBT_SearchFound1Entry_, 286, "Searched and found 1 entry.\n%2$s" )
+ ResDef( DBT_SearchFound1EntryWhere_, 287, "Searched and found 1 entry where the %2$s %3$s '%4$s'.\n" )
+ ResDef( DBT_FoundEntries_, 288, "Found %1$li entries.\n%2$s" )
+ ResDef( DBT_FoundEntriesWhere_, 289, "Found %1$li entries where the %2$s %3$s '%4$s'.\n" )
+ ResDef( DBT_SearchFoundEntries_, 290, "Searched and found %1$li entries.\n%2$s" )
+ ResDef( DBT_SearchFoundEntriesWhere_, 291, "Searched and found %1$li entries where the %2$s %3$s '%4$s'.\n" )
+ ResDef( DBT_theLDAPFilterIs_, 292, "the LDAP filter is" )
+ ResDef( DBT_theServerCouldNotLocateTheEntryY_, 293, "The server could not locate the entry you used when you authenticated. It is possible that someone renamed the entry or that is was deleted. Please try to authenticate again." )/*extracted from error.c*/
+ ResDef( DBT_InvalidPasswordSyntax_, 294, "The new password syntax is invalid.\n" )
+ ResDef( DBT_PasswordInHistory_, 295, "The new password occurs in the password history.\n" )
+ ResDef( DBT_ExceedPasswordRetryContactSysAdmin_, 296, "You've exceeded the password retry limit. Please contact your System Administrator.\n" )
+ ResDef( DBT_ExceedPasswordRetryTryLater_, 297, "You've exceeded the password retry limit. Please try again later.\n" )
+ ResDef( DBT_PasswordExpired_, 298, "The password has expired. Contact your System Administrator to reset the password.\n" )
+ ResDef( DBT_Editing_, 299, "Editing" )/*extracted from domodify.c*/
+ ResDef( DBT_Adding_, 300, "Adding" )/*extracted from domodify.c*/
+ ResDef( DBT_Deleting_, 301, "Deleting" )/*extracted from domodify.c*/
+ ResDef( DBT_Renaming_, 302, "Renaming" )/*extracted from domodify.c*/
+ ResDef( DBT_noNameInTheList_, 303, "There are <B>no</B> names in the list." )/*extracted from dnedit.c*/
+ ResDef( DBT_oneNameInTheList_, 304, "There is <B>1</B> name in the list." )/*extracted from dnedit.c*/
+ ResDef( DBT_someNamesInTheList_, 305, "There are <B>%s</B> names in the list." )/*extracted from dnedit.c*/
+ ResDef( DBT_RemoveFromList_, 306, "Remove<BR>from<BR>list? Name" )/*extracted from dnedit.c -- should be JavaScript syntax*/
+ ResDef( DBT_discardChanges_, 307, "Discard Changes?" ) /*extracted from dnedit.c */
+ ResDef( DBT_discardChangesWindow_, 308, "width=300,height=130,resizable" ) /*extracted from dnedit.c */
+ ResDef( DBT_continueWithoutSaving_, 309, "Continue without saving changes?<br>Unsaved changes will be lost." ) /*extracted from entrydisplay.c */
+ ResDef( DBT_continueWithoutSavingWindow_, 310, "width=400,height=150,resizable" ) /*extracted from dnedit.c */
+ ResDef( DBT_alertTitle_, 311, "Alert" ) /*extracted from htmlout.c */
+ ResDef( DBT_confirmTitle_, 312, "Confirm" ) /*extracted from htmlout.c */
+ ResDef( DBT_AuthenticationFailed_, 313, "Authentication Failed\n" )/*extracted from doauth.c*/
+ ResDef( DBT_AuthenticationSuccessful_, 314, "Authentication Successful" )/*extracted from doauth.c*/
+ ResDef( DBT_YouAreNowAuthenticated_, 315, "You are now authenticated to the directory as <B>%s</B>." )/*extracted from doauth.c*/
+ ResDef( DBT_YourAuthenticationCredentialsWill_, 316, "Your authentication credentials will expire in %d minutes.\n" )/*extracted from doauth.c*/
+ ResDef( DBT_AfterYourCredentialsExpire_, 317, "After your credentials expire, you will need to \nre-authenticate to the directory.\n" )/*extracted from doauth.c*/
+ ResDef( DBT_ThePasswordForThisEntryWillExpire_, 318, "<P>The password for this entry will expire <B>%s</B>.\n" )/*extracted from doauth.c*/
+ ResDef( DBT_AuthenticationFailedBecause_, 319, "Authentication failed because" )/*extracted from doauth.c*/
+ ResDef( DBT_AuthEntryNotExist_, 320, "Authentication failed because the entry you attempted to authenticate as does\nnot exist in the directory.\nYou may only authenticate as an existing directory\nentry.\n")/*extracted from doauth.c*/
+ ResDef( DBT_AuthEntryHasNoPassword_, 321, "Authentication failed because the entry you attempted to authenticate as does\nnot have a password. Before you can authenticate\nas this entry, a password must be set by a\ndirectory administrator\n")/*extracted from doauth.c*/
+ ResDef( DBT_thePasswordIsIncorrect_, 322, "Authentication failed because the password you supplied is incorrect. Please\nclick the Retry button and try again. If you have\nforgotten the password for this entry, a directory\nadministrator must reset the password for you.\n")/*extracted from doauth.c*/
+ ResDef( DBT_AuthUnexpectedError_, 323, "Authentication failed because of an unexpected error: %s\n")/*extracted from doauth.c*/
+ ResDef( DBT_Retry_, 324, "Retry" )/*extracted from doauth.c*/
+ ResDef( DBT_ToContinue_, 325, "To continue, select a task from the list above.\n" )/*extracted from doauth.c*/
+ ResDef( DBT_EditPassword_, 326, "Edit Password" )/*extracted from dsgwutil.c*/
+ ResDef( DBT_PasswordExpiredFor_, 327, "<H3>Password Expired for %s</H3>\n" )/*extracted from dsgwutil.c*/
+ ResDef( DBT_YourPasswordHasExpired_, 328, "Your Directory Server password has expired." )/*extracted from dsgwutil.c*/
+ ResDef( DBT_YouMustChangeYourPasswd_, 329, " You must change your password immediately.\n" )/*extracted from dsgwutil.c*/
+ ResDef( DBT_youDidNotProvidePasswd_, 330, "you did not provide a password. Whenever you authenticate, you must provide a password so that the server can verify your identity." )/*extracted from doauth.c*/
+ ResDef( DBT_authDBNotOpened_, 331, "the server was unable to generate authentication credentials. The authentication database could not be opened." )/*extracted from doauth.c*/
+ ResDef( DBT_DataCouldNotAppendToAuthDB_, 332, "the server was unable to generate authentication credentials. Data could not be appended to the authentication database.")/*extracted from doauth.c*/
+ ResDef( DBT_continue_4, 333, "Continue" )/*extracted from doauth.c*/
+ ResDef( DBT_closeWindow_5, 334, "Close Window" )/*extracted from doauth.c*/
+ ResDef( DBT_Success_, 335, "Success" )/*extracted from unauth.c*/
+ ResDef( DBT_YouAreNoLongerAuthenticated_, 336, "Your authentication credentials have been destroyed. You are no longer authenticated to the \ndirectory.\n")/*extracted from unauth.c*/
+ ResDef( DBT_GoBack_, 337, "Go Back")/*extracted from unauth.c*/
+
+ ResDef( DBT_LDAP_SUCCESS, 338, "Success")
+ ResDef( DBT_LDAP_OPERATIONS_ERROR, 339, "Operations error")
+ ResDef( DBT_LDAP_PROTOCOL_ERROR, 340, "Protocol error")
+ ResDef( DBT_LDAP_TIMELIMIT_EXCEEDED, 341, "Warning: a time limit was exceeded. Not all matching entries are shown.")
+ ResDef( DBT_LDAP_SIZELIMIT_EXCEEDED, 342, "Warning: a size limit was exceeded. Not all matching entries are shown.")
+ ResDef( DBT_LDAP_COMPARE_FALSE, 343, "Compare false")
+ ResDef( DBT_LDAP_COMPARE_TRUE, 344, "Compare true")
+ ResDef( DBT_LDAP_STRONG_AUTH_NOT_SUPPORTED, 345, "Strong authentication not supported")
+ ResDef( DBT_LDAP_STRONG_AUTH_REQUIRED, 346, "Strong authentication required")
+ ResDef( DBT_LDAP_PARTIAL_RESULTS, 347, "Warning: some directory servers could not be contacted. Not all matching entries are shown.")
+ ResDef( DBT_LDAP_REFERRAL, 348, "Referral received")
+ ResDef( DBT_LDAP_ADMINLIMIT_EXCEEDED, 349, "Administrative limit exceeded")
+ ResDef( DBT_LDAP_UNAVAILABLE_CRITICAL_EXTENSION, 350, "Unavailable critical extension")
+ ResDef( DBT_LDAP_CONFIDENTIALITY_REQUIRED, 351, "Confidentiality required")
+ ResDef( DBT_LDAP_SASL_BIND_IN_PROGRESS, 352, "SASL bind in progress")
+
+ ResDef( DBT_LDAP_NO_SUCH_ATTRIBUTE, 353, "No such attribute")
+ ResDef( DBT_LDAP_UNDEFINED_TYPE, 354, "Undefined attribute type")
+ ResDef( DBT_LDAP_INAPPROPRIATE_MATCHING, 355, "Inappropriate matching")
+ ResDef( DBT_LDAP_CONSTRAINT_VIOLATION, 356, "Constraint violation")
+ ResDef( DBT_LDAP_TYPE_OR_VALUE_EXISTS, 357, "Type or value exists")
+ ResDef( DBT_LDAP_INVALID_SYNTAX, 358, "Invalid syntax")
+
+ ResDef( DBT_LDAP_NO_SUCH_OBJECT, 359, "No such object")
+ ResDef( DBT_LDAP_ALIAS_PROBLEM, 360, "Alias problem")
+ ResDef( DBT_LDAP_INVALID_DN_SYNTAX, 361, "Invalid DN syntax")
+ ResDef( DBT_LDAP_IS_LEAF, 362, "Object is a leaf")
+ ResDef( DBT_LDAP_ALIAS_DEREF_PROBLEM, 363, "Alias dereferencing problem")
+
+ ResDef( DBT_LDAP_INAPPROPRIATE_AUTH, 364, "Inappropriate authentication")
+ ResDef( DBT_LDAP_INVALID_CREDENTIALS, 365, "Invalid credentials")
+ ResDef( DBT_LDAP_INSUFFICIENT_ACCESS, 366, "Insufficient access")
+ ResDef( DBT_LDAP_BUSY, 367, "DSA is busy")
+ ResDef( DBT_LDAP_UNAVAILABLE, 368, "DSA is unavailable")
+ ResDef( DBT_LDAP_UNWILLING_TO_PERFORM, 369, "DSA is unwilling to perform")
+ ResDef( DBT_LDAP_LOOP_DETECT, 370, "Loop detected")
+
+ ResDef( DBT_LDAP_NAMING_VIOLATION, 371, "Naming violation")
+ ResDef( DBT_LDAP_OBJECT_CLASS_VIOLATION, 372, "Object class violation")
+ ResDef( DBT_LDAP_NOT_ALLOWED_ON_NONLEAF, 373, "Operation not allowed on nonleaf")
+ ResDef( DBT_LDAP_NOT_ALLOWED_ON_RDN, 374, "Operation not allowed on RDN")
+ ResDef( DBT_LDAP_ALREADY_EXISTS, 375, "Already exists")
+ ResDef( DBT_LDAP_NO_OBJECT_CLASS_MODS, 376, "Cannot modify object class")
+ ResDef( DBT_LDAP_RESULTS_TOO_LARGE, 377, "Results too large")
+ ResDef( DBT_LDAP_AFFECTS_MULTIPLE_DSAS, 378, "Affects multiple servers")
+
+ ResDef( DBT_LDAP_OTHER, 379, "Unknown error")
+ ResDef( DBT_LDAP_SERVER_DOWN, 380, "Can't contact LDAP server")
+ ResDef( DBT_LDAP_LOCAL_ERROR, 381, "Local error")
+ ResDef( DBT_LDAP_ENCODING_ERROR, 382, "Encoding error")
+ ResDef( DBT_LDAP_DECODING_ERROR, 383, "Decoding error")
+ ResDef( DBT_LDAP_TIMEOUT, 384, "Timed out")
+ ResDef( DBT_LDAP_AUTH_UNKNOWN, 385, "Unknown authentication method")
+ ResDef( DBT_LDAP_FILTER_ERROR, 386, "Bad search filter")
+ ResDef( DBT_LDAP_USER_CANCELLED, 387, "User cancelled operation")
+ ResDef( DBT_LDAP_PARAM_ERROR, 388, "Bad parameter to an ldap routine")
+ ResDef( DBT_LDAP_NO_MEMORY, 389, "Out of memory")
+ ResDef( DBT_LDAP_CONNECT_ERROR, 390, "Can't connect to the LDAP server")
+ ResDef( DBT_LDAP_NOT_SUPPORTED, 391, "Not supported by this version of the LDAP protocol")
+ ResDef( DBT_LDAP_CONTROL_NOT_FOUND, 392, "Requested LDAP control not found")
+ ResDef( DBT_LDAP_NO_RESULTS_RETURNED, 393, "No results returned")
+ ResDef( DBT_LDAP_MORE_RESULTS_TO_RETURN, 394, "More results to return")
+ ResDef( DBT_LDAP_CLIENT_LOOP, 395, "Client detected loop")
+ ResDef( DBT_LDAP_REFERRAL_LIMIT_EXCEEDED, 396, "Referral hop limit exceeded")
+ ResDef( DBT_missingArgumentForHtmlpathDi_, 399, "Missing argument for \"htmldir\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_errorS_, 400, "Error: %s (%i)" )/*extracted from error.c*/
+ ResDef( DBT_doYouReallyWantTo_, 401, "Do you really want to %s?" )/*extracted from htmlparse.c*/
+ ResDef( DBT_doYouReallyWantToWindow_, 402, "width=400,height=130,resizable" )/*extracted from htmlparse.c*/
+ ResDef( DBT_missingArgumentForConfigpathDi_, 403, "Missing argument for \"configdir\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForNametransDi_, 404, "Missing argument for \"gwnametrans\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_MissingContext_, 405, "Missing context\n" )/*extracted from config.c*/
+ ResDef( DBT_missingFilenameForBinddnfileDirecti_, 406, "Missing filename for \"binddnfile\" directive\n" ) /*extracted from config.c*/
+ ResDef( DBT_missingArgumentForBinddnDirectiv_, 407, "Missing argument for \"binddn\" directive\n" )
+ ResDef( DBT_missingArgumentForBindpwDirectiv_, 408, "Missing argument for \"bindpw\" directive\n" )
+ ResDef( DBT_badFilenameForBinddnfileDirecti_, 409, "The binddn file must be specified with a full path and cannot exist under the dsgw directory\n" )
+ ResDef (DBT_wrongPlaceForBinddnDirectiv_, 410, "The bind information should not be in the main configuration file. Please put it in a separate file outside of the dsgw directory\n")
+ ResDef( DBT_NotWillingToExecute_, 411, "The directory server gateway is not available for the restricted installation. To use the gateway upgrade to the full version of the Netscape Directory Server.\n" )
+ ResDef( DBT_missingArgumentForOrgChartURLDirectiv_, 412, "Missing argument for \"url-orgchart-base\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_missingArgumentForOrgChartSearchAttr_ , 413, "Missing argument for \"orgchart-attrib-farleft-rdn\" directive\n" )/*extracted from config.c*/
+ ResDef( DBT_theCharsetIsNotSupported , 414, "The charset is not supported\n" )
+END_STR(dsgw)
+
diff --git a/ldap/clients/dsgw/dnedit.c b/ldap/clients/dsgw/dnedit.c
new file mode 100644
index 00000000..5ee761ef
--- /dev/null
+++ b/ldap/clients/dsgw/dnedit.c
@@ -0,0 +1,415 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * Generate a DN edit screen.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+#ifdef DSGW_DEBUG
+int main(int argc, char *argv[], char *env[] )
+#else /* DSGW_DEBUG */
+int main(int argc, char *argv[] )
+#endif /* DSGW_DEBUG */
+{
+ char *tmplname, *attrname, *attrdesc, *qs, *dn, *edn;
+ char *attrs[ 2 ], **attrvals, **xdn, *avedn, *js0, *js1;
+ LDAP *ld;
+ LDAPMessage *msgp;
+ int i;
+
+ /*
+ * The URL used to invoke this CGI looks like:
+ * http://host/dnedit?CONTEXT=context&TEMPLATE=tmplname&DN=dn&ATTR=attrname&DESC=description
+ *
+ * where:
+ * "tmplname" is the name of the HTML template to render
+ * "attrname" is the name of a dn-valued attribute to display
+ * "description" is a textual description of the attribute
+ *
+ * Note: original form http://host/dnedit/dn?... is supported
+ * for keeping backward compatibility.
+ */
+ tmplname = attrname = attrdesc = dn = edn = NULL;
+ if (( qs = getenv( "QUERY_STRING" )) != NULL && *qs != '\0' ) {
+ char *p, *q;
+ q = qs + strlen( qs );
+ while ((( p = strrchr( qs, '&' )) != NULL ) || ( q - qs > 1 )) {
+ if ( p )
+ *p++ = '\0';
+ else
+ p = qs;
+ q = p;
+
+ if ( p != NULL && strncasecmp( p, "dn=", 3 ) == 0 ) {
+ edn = dsgw_ch_strdup( p + 3 );
+ dn = dsgw_ch_strdup( p + 3 );
+ dsgw_form_unescape( dn );
+ } else if ( p != NULL && strncasecmp( p, "template=", 9 ) == 0 ) {
+ tmplname = dsgw_ch_strdup( p + 9 );
+ dsgw_form_unescape( tmplname );
+ } else if ( p != NULL && strncasecmp( p, "attr=", 5 ) == 0 ) {
+ attrname = dsgw_ch_strdup( p + 5 );
+ dsgw_form_unescape( attrname );
+ } else if ( p != NULL && strncasecmp( p, "desc=", 5 ) == 0 ) {
+ attrdesc = dsgw_ch_strdup( p + 5 );
+ /* Don't bother unescaping it;
+ we're only going to put it back in another URL. */
+ } else if ( p != NULL && strncasecmp( p, "context=", 8 ) == 0) {
+ context = dsgw_ch_strdup( p + 8 );
+ dsgw_form_unescape( context );
+ }
+
+ }
+
+ if ( !tmplname )
+ dsgw_error( DSGW_ERR_MISSINGINPUT, "template", DSGW_ERROPT_EXIT,
+ 0, NULL );
+ if ( !attrname )
+ dsgw_error( DSGW_ERR_MISSINGINPUT, "attr", DSGW_ERROPT_EXIT,
+ 0, NULL );
+ if ( !attrdesc )
+ dsgw_error( DSGW_ERR_MISSINGINPUT, "desc", DSGW_ERROPT_EXIT,
+ 0, NULL );
+ } else {
+ dsgw_error( DSGW_ERR_MISSINGINPUT, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if ( dn == NULL ) {
+ dsgw_error( DSGW_ERR_MISSINGINPUT, "dn", DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ (void)dsgw_init( argc, argv, DSGW_METHOD_GET );
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ dsgw_send_header();
+
+
+ /* Get the current attribute values */
+ (void) dsgw_init_ldap( &ld, NULL, 0, 0);
+ attrs[ 0 ] = attrname;
+ attrs[ 1 ] = NULL;
+ if (ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrs, 0,
+ &msgp ) != LDAP_SUCCESS ) {
+ dsgw_error( DSGW_ERR_ENTRY_NOT_FOUND, dn, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ attrvals = ldap_get_values( ld, msgp, attrname );
+
+
+ /* Send the top-level document HTML */
+ dsgw_emits( "<HTML>\n"
+ "<SCRIPT LANGUAGE=\"JavaScript\">\n" );
+ dsgw_emitf( "var emptyFrame = '';\n" );
+ dsgw_emitf( "var attrname = '%s';\n", attrname );
+ /*
+ * fix for 333110: dn should be escaped to be used in saveChanges/domodify
+ */
+ dsgw_emitf( "var dn = '%s';\n", edn );
+ dsgw_emitf( "var needToSaveChanges = false;\n" );
+ dsgw_emitf( "var completion_url = '%s?dn=%s&context=%s';\n",
+ dsgw_getvp( DSGW_CGINUM_EDIT ), edn, context);
+ dsgw_emitf(
+ /*
+ * This needs to output \\\' so that when JavaScript writeln's
+ * this string, it writes \' to the output document.
+ *
+ * I'm really, really sorry about this - ggood.
+ *
+ * Moral of the story - next time someone asks you to write C code which
+ * writes JavaScript code which writes JavaScript code... just say "no".
+ */
+ "var comp_js = 'var cu=\\\\\\\'%s?context=%s&dn=%s\\\\\\\'; this.document.location.href=cu;'\n",
+ dsgw_getvp( DSGW_CGINUM_EDIT ), context, edn );
+ dsgw_emits("var dnlist = new Array;\n" );
+ for ( i = 0; attrvals && attrvals[ i ] != NULL; i++ ) {
+ xdn = ldap_explode_dn( attrvals[ i ], 1 );
+ avedn = dsgw_strdup_escaped( attrvals[ i ]);
+ dsgw_emitf( "dnlist[%d] = new Object\n", i );
+ dsgw_emitf( "dnlist[%d].edn = '%s';\n", i, avedn );
+ js0 = dsgw_escape_quotes( xdn[ 0 ] );
+ if ( xdn[1] != NULL ) {
+ js1 = dsgw_escape_quotes( xdn[ 1 ] );
+ dsgw_emitf( "dnlist[%d].rdn = '%s, %s';\n", i, js0, js1 );
+ free( js1 );
+ } else {
+ dsgw_emitf( "dnlist[%d].rdn = '%s';\n", i, js0 );
+ }
+ free( js0 );
+ dsgw_emitf( "dnlist[%d].selected = false;\n", i );
+ free( avedn );
+ ldap_value_free( xdn );
+ }
+ dsgw_emitf( "dnlist.count = %d;\n", i );
+ dsgw_emits(
+ "var changesMade = 0;\n"
+ "\n"
+
+ /*
+ * JavaScript function processSearch
+ */
+
+ "function processSearch(f)\n"
+ "{\n"
+ " var sel = f.type;\n"
+ " var selvalue = sel.options[sel.selectedIndex].value;\n"
+ " var lt = f.listtemplate;\n"
+ " if ( f.searchstring.value.length == 0 ) {\n");
+ dsgw_emit_alert( "controlFrame", NULL, XP_GetClientStr( DBT_noSearchStringWasProvidedPleaseT_ ));
+ dsgw_emits(
+ " return false;\n"
+ " }\n"
+ " lt.value = 'fa-' + selvalue;\n");
+ dsgw_emitf(
+ " f.action = ");
+ dsgw_quote_emitf( QUOTATION_JAVASCRIPT, "%s?context=%s",
+ dsgw_getvp( DSGW_CGINUM_DOSEARCH ), context);
+ dsgw_emits( ";\n"
+ " f.searchstring.select();\n"
+ " f.searchstring.focus();\n"
+ " return true;\n"
+ "}\n"
+ "\n"
+
+ /*
+ * JavaScript function removeItem
+ */
+
+ "function removeItem(itemno, refresh)\n"
+ "{\n"
+ " var extantDNs = dnlist;\n"
+ " var extantDNsCount = dnlist.count;\n"
+ " \n"
+ " // Get rid of element in slot dup\n"
+ " for (k = itemno; k < extantDNsCount - 1; k++) {\n"
+ " extantDNs[k] = extantDNs[k+1];\n"
+ " }\n"
+ " dnlist.count--;\n"
+ " if ( refresh ) genOutputFrame(outputFrame, dnlist);\n"
+ " this.changesMade = 1;\n"
+ "}\n"
+ "\n"
+
+ /*
+ * JavaScript function dnarrcomp
+ */
+
+ "function dnarrcomp(a,b)\n"
+ "{\n"
+ " return(a.edn.toLowerCase() > b.edn.toLowerCase());\n"
+ "}\n"
+ " \n"
+#ifdef NAV30_SORT_NO_LONGER_COREDUMPS
+ /*
+ * JavaScript function sortEntries
+ */
+
+ "function sortEntries()\n"
+ "{\n"
+ " var extantDNs = dnlist;\n"
+ " extantDNs.sort(dnarrcomp);\n"
+ " genOutputFrame(outputFrame, dnlist);\n"
+ "}\n"
+ "\n"
+#endif /* NAV30_SORT_NO_LONGER_COREDUMPS */
+
+ /*
+ * JavaScript function genOutputFrame
+ */
+
+ "function genOutputFrame(oframe, dnl)\n"
+ "{\n"
+ " var d = oframe.document;\n"
+ "\n"
+ " d.open('text/html');\n"
+ " d.writeln('<HTML>');\n" );
+
+ dsgw_emitf(
+ " d.writeln('<BODY %s>');\n", dsgw_html_body_colors );
+ dsgw_emits(
+ " d.writeln(");
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT);
+ dsgw_form_begin (NULL, NULL);
+ dsgw_quotation_end();
+ dsgw_emits( ");\n");
+ dsgw_emits(
+ " d.writeln('<CENTER>');\n"
+ " if (dnl.count == 0) {\n" );
+
+ dsgw_emits( " d.write(" );
+ dsgw_quote_emits (QUOTATION_JAVASCRIPT, XP_GetClientStr (DBT_noNameInTheList_));
+ dsgw_emits( ");\n" );
+
+ dsgw_emits( " } else if (dnl.count == 1) {\n" );
+ dsgw_emits( " d.write(" );
+ dsgw_quote_emits (QUOTATION_JAVASCRIPT, XP_GetClientStr (DBT_oneNameInTheList_));
+ dsgw_emits( ");\n" );
+ dsgw_emits( " } else {\n" );
+ dsgw_emits( " d.write('");
+ dsgw_emitf( XP_GetClientStr( DBT_someNamesInTheList_ ), "' + dnl.count + '" );
+ dsgw_emits( "');\n" );
+
+ dsgw_emits(
+ " }\n"
+#ifdef NAV30_SORT_NO_LONGER_COREDUMPS
+ " d.writeln('</FONT>\\n')\n"
+ " d.writeln('<INPUT TYPE=\"button\" VALUE=\"Sort\" onClick=\"parent.sortEntries();\"></CENTER>\\n');\n"
+#else
+ " d.writeln('</FONT></CENTER>\\n');\n"
+#endif
+ " if (dnl.count > 0) {\n"
+ " d.write('<PRE><B>');\n" );
+
+ dsgw_emitf(
+ " d.write('%s</B><HR>');\n",
+ XP_GetClientStr( DBT_RemoveFromList_ ));
+
+ dsgw_emits(
+ " for (i = 0; i < dnl.count; i++) {\n"
+ " d.write('<INPUT TYPE=CHECKBOX onClick=\"parent."
+ "removeItem(' + i + ', true);\">');\n"
+ " d.write(' ');\n"
+ " d.write(dnl[i].rdn + '\\n');\n"
+ " }\n"
+ " d.writeln('</PRE></FORM><HR>');\n"
+ " }\n"
+ " d.writeln('</BODY>');\n"
+ " d.close();\n"
+ "}\n"
+ "\n"
+
+ /*
+ * JavaScript function mergeLists
+ */
+
+ "function mergeLists(mode, old, newl)\n"
+ "{\n"
+ " var dup = -1;\n"
+ " var i, j, k;\n"
+ " \n"
+ " for (i = 0; i < newl.count; i++) {\n"
+ " // Check for a duplicate\n"
+ " for (j = 0; j < old.count; j++) {\n"
+ " dup = -1;\n"
+ " if (newl[i].edn.toLowerCase() == "
+ "old[j].edn.toLowerCase()) {\n"
+ " // Duplicate - skip\n"
+ " dup = j;\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " if ((dup == -1) && (mode == \"add\")) {\n"
+ " // add new dn at end of array\n"
+ " old[old.count] = new Array;\n"
+ " old[old.count].edn = newl[i].edn;\n"
+ " old[old.count].rdn = newl[i].rdn;\n"
+ " old[old.count].sn = newl[i].sn;\n"
+ " old[old.count].selected = false;\n"
+ " old.count++;\n"
+ " } else if (dup != -1 && mode == \"remove\") {\n"
+ " removeItem(dup,false);\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "\n"
+
+ /*
+ * JavaScript function updateList
+ */
+
+ "function updateList(mode, old_list, new_list, outframe)\n"
+ "{\n"
+ " mergeLists(mode, old_list, new_list);\n"
+ " genOutputFrame(outframe, old_list);\n"
+ " this.changesMade = 1;\n"
+ "}\n"
+ "\n"
+
+ /*
+ * JavaScript function cancel
+ */
+ "function cancel ()\n"
+ "{\n"
+ " if (changesMade == 0) {\n"
+ " document.location = completion_url;\n"
+ " } else {\n");
+ dsgw_emit_confirm ("controlFrame",
+ "opener.document.location.href = opener.completion_url;",
+ NULL /* no */,
+ XP_GetClientStr(DBT_discardChangesWindow_), 1,
+ XP_GetClientStr(DBT_discardChanges_));
+ dsgw_emits (
+ " }\n"
+ "}\n"
+ "\n"
+
+ /*
+ * JavaScript function saveChanges
+ */
+
+ "function saveChanges()\n"
+ "{\n"
+ " var i, j;\n"
+ " needToSaveChanges = true;\n"
+ " of = self.stagingFrame.document;\n"
+ " of.open('text/html');\n" );
+ dsgw_emitf(
+ " of.write('<BODY onLoad=\"if ( parent.needToSaveChanges ) { parent.needToSaveChanges = false; document.stagingForm.submit() }\">');\n" );
+ dsgw_emits(
+ " of.write('");
+ dsgw_form_begin ("stagingForm",
+ "action=\"%s\" METHOD=\"POST\" TARGET=\"_parent\"",
+ dsgw_getvp( DSGW_CGINUM_DOMODIFY ));
+ dsgw_emits("\\n');\n");
+ dsgw_emits(
+ " if (self.dnlist.count < 1) {\n"
+ " of.write('<INPUT TYPE=\"hidden\" NAME=\"replace_');\n"
+ " of.write(self.attrname);\n"
+ " of.write('\" VALUE=\"\">\\n');\n"
+ " } else {\n"
+ " for (j = 0; j < self.dnlist.count; j++) {\n"
+ " of.write('<INPUT TYPE=\"hidden\" NAME=\"replace_');\n"
+ " of.write(self.attrname);\n"
+ " of.write('\" VALUE=\"');\n"
+ " of.write(unescape(self.dnlist[j].edn));\n"
+ " of.write('\">\\n');\n"
+ " }\n"
+ " }\n"
+ " of.writeln('<INPUT TYPE=\"hidden\" NAME=\"changetype\" "
+ "VALUE=\"modify\">\\n');\n"
+ " of.writeln('<INPUT TYPE=\"hidden\" NAME=\"completion_javascript\" "
+ "VALUE=\"' + comp_js + '\">');\n"
+ " of.writeln('<INPUT TYPE=\"hidden\" NAME=\"dn\" VALUE=\"' "
+ "+ self.dn + '\"\\n');\n"
+ " of.writeln('<INPUT TYPE=\"hidden\" NAME=\"context\" "
+ "VALUE=\"");
+ dsgw_emits(context);
+ dsgw_emits("\">\\n');\n"
+ " of.writeln('</FORM>\\n');\n"
+ " of.close();\n"
+ "}\n"
+
+ "</SCRIPT>\n"
+ "\n"
+ "<FRAMESET BORDER=1 FRAMEBORDER=1 ROWS=230,*,0,0 "
+ "SCROLLING=\"NO\" NORESIZE onLoad=\"genOutputFrame"
+ "(this.outputFrame, this.dnlist);\">\n" );
+ dsgw_emitf( " <FRAME SRC=\"%s?%s&dn=%s&context=%s&DNATTR=%s&"
+ "DNDESC=%s\" NAME=\"controlFrame\" SCROLLING=\"no\">\n",
+ dsgw_getvp( DSGW_CGINUM_EDIT ), tmplname, edn, context, attrname,
+ attrdesc );
+ dsgw_emitf( " <FRAME SRC=\"javascript:parent.emptyFrame\" "
+ "NAME=\"outputFrame\">\n"
+ " <FRAME SRC=\"javascript:parent.emptyFrame\" "
+ "NAME=\"stagingFrame\">\n"
+ "</FRAMESET>\n"
+ "</HTML>\n" );
+ return 0;
+}
diff --git a/ldap/clients/dsgw/doauth.c b/ldap/clients/dsgw/doauth.c
new file mode 100644
index 00000000..a621f534
--- /dev/null
+++ b/ldap/clients/dsgw/doauth.c
@@ -0,0 +1,386 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * doauth.c -- CGI authentication handler -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+static void post_request();
+static void do_autherror( int rc, char *msg, char *lderrtxt,
+ int ommitclosebutton );
+
+
+int main( argc, argv, env )
+ int argc;
+ char *argv[];
+{
+ int reqmethod;
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_POST );
+
+ post_request();
+
+ exit( 0 );
+}
+
+static void
+post_request()
+{
+ char *binddn, *password, *authdesturl, *ufn, *encodeddn, *lderrtxt;
+ LDAP *ld;
+ int rc;
+ int password_expiring = -1;
+ int msgid = 0;
+
+ binddn = dsgw_get_escaped_cgi_var( "escapedbinddn", "binddn",
+ DSGW_CGIVAR_REQUIRED );
+ encodeddn = dsgw_strdup_escaped( binddn );
+ authdesturl = dsgw_get_cgi_var( "authdesturl", DSGW_CGIVAR_OPTIONAL );
+ password = dsgw_get_cgi_var( "password", DSGW_CGIVAR_OPTIONAL );
+
+ (void) dsgw_init_ldap( &ld, NULL, 1, 0);
+
+ if ( password == NULL || strlen( password ) == 0 ) {
+ do_autherror( 0, XP_GetClientStr( DBT_youDidNotProvidePasswd_ ),
+ NULL, authdesturl == NULL );
+ exit( 0 );
+ }
+
+ if( ( msgid = ldap_simple_bind( ld, binddn, password ) ) == -1 ) {
+ rc = ldap_get_lderrno( ld, NULL, &lderrtxt );
+ do_autherror( rc, NULL, lderrtxt, authdesturl == NULL );
+ exit( 0 );
+ } else {
+
+ char *ckbuf;
+ LDAPControl **ctrls = NULL;
+ LDAPMessage *res;
+ char *errmsg = NULL;
+
+ /* Conduct password policy checks */
+ if(( rc = ldap_result( ld, msgid, 1, NULL, &res )) == -1 ) {
+ rc = ldap_get_lderrno( ld, NULL, &errmsg );
+ do_autherror( rc, NULL, errmsg, authdesturl == NULL );
+ exit( 0 );
+ }
+
+ if( ldap_parse_result( ld, res, NULL, NULL, NULL, NULL, &ctrls, 0 )
+ != LDAP_SUCCESS ) {
+ rc = ldap_get_lderrno( ld, NULL, &errmsg );
+ do_autherror( rc, NULL, errmsg, authdesturl == NULL );
+ exit( 0 );
+ }
+
+ rc = ldap_result2error( ld, res, 1 );
+ if( rc == LDAP_SUCCESS ) {
+ if( ctrls ) {
+ int i;
+ for( i = 0; ctrls[ i ] != NULL; ++i ) {
+ if( !( strcmp( ctrls[ i ]->ldctl_oid,
+ LDAP_CONTROL_PWEXPIRED) ) ) {
+ /* The password has expired. Convey this information,
+ and give the user the option to change their
+ password immediately. */
+ dsgw_password_expired_alert( binddn );
+ exit( 0 );
+ }
+ else if( !( strcmp( ctrls[ i ]->ldctl_oid,
+ LDAP_CONTROL_PWEXPIRING) ) ) {
+ /* "The password is expiring in n seconds" */
+ if( ( ctrls[ i ]->ldctl_value.bv_val != NULL ) &&
+ ( ctrls[ i ]->ldctl_value.bv_len > 0 ) ) {
+ password_expiring = atoi( ctrls[ i ]->ldctl_value.bv_val );
+ }
+ }
+ }
+ ldap_controls_free( ctrls );
+ }
+ } else if( rc == LDAP_CONSTRAINT_VIOLATION ) {
+ rc = ldap_get_lderrno( ld, NULL, &errmsg );
+ if( errmsg && strstr( errmsg,
+ "Exceed password retry limit. Contact system administrator to reset" ) ) {
+ do_autherror( rc, XP_GetClientStr(DBT_ExceedPasswordRetryContactSysAdmin_),
+ NULL, authdesturl == NULL );
+ } else if( errmsg && strstr( errmsg,
+ "Exceed password retry limit. Please try later" ) ) {
+ do_autherror( rc, XP_GetClientStr(DBT_ExceedPasswordRetryTryLater_),
+ NULL, authdesturl == NULL );
+ } else {
+ do_autherror( rc, NULL, errmsg,
+ authdesturl == NULL );
+ }
+ exit( 0 );
+ } else if( rc == LDAP_INVALID_CREDENTIALS ) {
+ if( errmsg && strstr( errmsg, "password expired" ) ) {
+ do_autherror( rc, XP_GetClientStr(DBT_PasswordExpired_),
+ NULL, authdesturl == NULL );
+ } else {
+ do_autherror( rc, NULL, errmsg,
+ authdesturl == NULL );
+ }
+ exit( 0 );
+ } else {
+ rc = ldap_get_lderrno( ld, NULL, &errmsg );
+ do_autherror( rc, NULL, errmsg, authdesturl == NULL );
+ exit( 0 );
+ }
+
+ /* Construct cookie */
+ if (( ckbuf = dsgw_mkcookie( binddn, password, gc->gc_authlifetime,
+ &rc )) == NULL ) {
+ switch ( rc ) {
+ case DSGW_CKDB_CANTOPEN:
+ do_autherror( 0, XP_GetClientStr( DBT_authDBNotOpened_ ),
+ NULL, authdesturl == NULL );
+ break;
+ case DSGW_CKDB_CANTAPPEND:
+ do_autherror( 0,
+ XP_GetClientStr( DBT_DataCouldNotAppendToAuthDB_ ),
+ NULL, authdesturl == NULL );
+ break;
+ default:
+ do_autherror( rc, NULL, NULL, authdesturl == NULL );
+ break;
+ }
+ exit( 1 );
+ }
+ dsgw_add_header( ckbuf );
+
+ /* Construct a success message */
+ dsgw_send_header();
+ dsgw_emits( "<HTML>" );
+ dsgw_head_begin();
+ dsgw_emits( "\n"
+ "<TITLE>Authentication Successful</TITLE>\n"
+ "<SCRIPT LANGUAGE=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript browsers\n" );
+
+ if ( authdesturl != NULL && strlen( authdesturl ) > 0 ) {
+ dsgw_emitf( "var authdesturl=\"%s\";\n", authdesturl );
+ } else {
+ dsgw_emitf( "var authdesturl=null;\n" );
+ }
+
+ if( password_expiring != -1 ) {
+ if ( encodeddn != NULL && strlen( encodeddn ) > 0 ) {
+ dsgw_emitf( "var editdesturl = '%s?passwd&dn=%s&context=%s';\n",
+ dsgw_getvp( DSGW_CGINUM_EDIT ), encodeddn, context );
+ } else {
+ dsgw_emitf( "var editdesturl=null;\n" );
+ }
+
+ dsgw_emits( "function editPassword()\n"
+ "{\n"
+ " if ( editdesturl != null ) {\n"
+ " top.location.href = editdesturl;\n"
+ " } else {\n"
+ " top.close();\n"
+ " }\n"
+ "}\n" );
+ }
+
+ dsgw_emits( "function finishAuth()\n"
+ "{\n"
+ " if ( authdesturl != null ) {\n"
+ " top.location.href = authdesturl;\n"
+ " } else {\n"
+ " top.close();\n"
+ " }\n"
+ "}\n"
+ "var contButtons = ");
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
+ dsgw_form_begin ("bForm", NULL);
+ if( password_expiring != -1 ) {
+ /* Create a table with 1 row and 3 columns,
+ one column for each button... */
+ dsgw_emitf(
+ "\n<TABLE BORDER COLS=3 WIDTH=100%%>\n"
+ "<TD ALIGN=CENTER>\n"
+ "<INPUT TYPE=BUTTON NAME=\"contButton\""
+ "VALUE=\"%s\" onClick=\"finishAuth();\">\n"
+ "<TD ALIGN=CENTER>\n"
+ "<INPUT TYPE=BUTTON NAME=\"editButton\""
+ "VALUE=\"%s\" onClick=\"editPassword();\">\n"
+ "<TD ALIGN=CENTER>",
+ XP_GetClientStr( DBT_continue_4 ),
+ XP_GetClientStr( DBT_EditPassword_ ));
+ } else {
+ dsgw_emitf(
+ "\n<TABLE BORDER=2 WIDTH=100%%>\n"
+ "<TD ALIGN=CENTER WIDTH=50%%>\n"
+ "<INPUT TYPE=BUTTON NAME=\"contButton\""
+ "VALUE=\"%s\" onClick=\"finishAuth();\">\n"
+ "<TD ALIGN=CENTER WIDTH=50%%>",
+ XP_GetClientStr( DBT_continue_4 ));
+ }
+ dsgw_emit_helpbutton( "AUTHSUCCESS" );
+ dsgw_emits(
+ "\n</TABLE></FORM>");
+ dsgw_quotation_end(); dsgw_emits(";\n");
+
+ dsgw_emits(
+ "var noContButtons = ");
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
+ dsgw_emits( XP_GetClientStr( DBT_ToContinue_ ));
+ dsgw_form_begin( "bForm", NULL );
+ dsgw_emits(
+ "\n<TABLE BORDER=2 WIDTH=100%>"
+ "\n<TD ALIGN=CENTER WIDTH=50%>" );
+ dsgw_emit_homebutton();
+ dsgw_emits( "\n<TD ALIGN=CENTER WIDTH=50%%>" );
+ dsgw_emit_helpbutton( "AUTHSUCCESS" );
+ dsgw_emits(
+ "\n</TABLE></FORM>\n");
+ dsgw_quotation_end(); dsgw_emits(";\n");
+
+ dsgw_emitf(
+ "// End hiding -->\n"
+ "</SCRIPT>\n"
+ "</HEAD>\n<BODY %s>\n"
+ "<CENTER>\n"
+ "<H3>%s</H3>\n"
+ "</CENTER>\n",
+ dsgw_html_body_colors,
+ XP_GetClientStr( DBT_AuthenticationSuccessful_ )
+ );
+
+#ifdef NOTFORNOW
+ /* ldap_dn2ufn currectly gobble up 'dc' so don't use it for */
+ /* now */
+ ufn = ldap_dn2ufn( binddn );
+ dsgw_emitf( XP_GetClientStr( DBT_YouAreNowAuthenticated_ ), ufn );
+#else
+ dsgw_emitf( XP_GetClientStr( DBT_YouAreNowAuthenticated_ ), binddn );
+#endif
+ dsgw_emits( "<P>\n" );
+#ifdef NOTFORNOW
+ free( ufn );
+#endif
+ dsgw_emitf( XP_GetClientStr( DBT_YourAuthenticationCredentialsWill_ ),
+ gc->gc_authlifetime / 60 );
+ dsgw_emits( XP_GetClientStr( DBT_AfterYourCredentialsExpire_ ));
+
+ if( password_expiring != -1 ) {
+ time_t cur_time, pw_exp_time_t;
+ struct tm *pw_exp_time_tm;
+
+ cur_time = dsgw_current_time();
+ pw_exp_time_t = dsgw_time_plus_sec( cur_time, password_expiring );
+ pw_exp_time_tm = localtime( &pw_exp_time_t );
+
+ dsgw_emitf(
+ XP_GetClientStr( DBT_ThePasswordForThisEntryWillExpire_ ),
+ asctime( pw_exp_time_tm ));
+ dsgw_emits( "<P>\n" );
+ }
+
+ dsgw_emits(
+ "<P>\n"
+ "<TR>\n"
+ "<SCRIPT LANGUAGE=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript browsers\n"
+ "if ( authdesturl != null ) {\n"
+ " document.write( contButtons );\n"
+ "} else {\n"
+ " document.write( noContButtons );\n"
+ "}\n"
+ "// End hiding -->\n"
+ "</SCRIPT>\n"
+ "</BODY>\n</HTML>\n" );
+
+ free( ckbuf );
+ exit( 0 );
+ }
+}
+
+
+
+
+static void
+do_autherror( int rc, char *msg, char *lderrtxt, int omitclosebutton )
+{
+ dsgw_send_header();
+ dsgw_emits( "<HTML>" );
+ dsgw_head_begin();
+ dsgw_emitf( "\n"
+ "<TITLE>Authentication Error</TITLE></HEAD>\n"
+ "<BODY %s>\n"
+ "<CENTER>\n"
+ "<FONT SIZE=+2>\n", dsgw_html_body_colors );
+
+ dsgw_emits( XP_GetClientStr( DBT_AuthenticationFailed_ ));
+ dsgw_emits(
+ "</FONT>\n"
+ "</CENTER>\n"
+ "<P>\n");
+ if ( msg != NULL ) {
+ dsgw_emitf( "%s %s\n",
+ XP_GetClientStr( DBT_AuthenticationFailedBecause_ ),
+ msg );
+ } else {
+ switch ( rc ) {
+ case LDAP_NO_SUCH_OBJECT:
+ dsgw_emits( XP_GetClientStr( DBT_AuthEntryNotExist_ ));
+ break;
+ case LDAP_INAPPROPRIATE_AUTH:
+ dsgw_emits( XP_GetClientStr( DBT_AuthEntryHasNoPassword_ ));
+ break;
+ case LDAP_INVALID_CREDENTIALS:
+ dsgw_emits( XP_GetClientStr( DBT_thePasswordIsIncorrect_ ));
+ break;
+ case DSGW_CKDB_KEY_NOT_PRESENT:
+ case DSGW_CKDB_DBERROR:
+ case DSGW_CKDB_EXPIRED:
+ case DSGW_CKDB_RNDSTRFAIL:
+ case DSGW_CKDB_NODN:
+ case DSGW_CKDB_CANTOPEN:
+ case DSGW_CKDB_CANTAPPEND:
+ dsgw_emitf( XP_GetClientStr( DBT_AuthUnexpectedError_ ), dsgw_err2string( rc ));
+ break;
+ default:
+ dsgw_emitf( XP_GetClientStr( DBT_AuthUnexpectedError_ ), dsgw_ldaperr2string( rc ));
+ break;
+ }
+ }
+ if ( lderrtxt != NULL ) {
+ dsgw_emitf( "<BR>(%s)", lderrtxt );
+ }
+ dsgw_emits( "<P>\n" );
+ dsgw_form_begin( NULL, NULL );
+ dsgw_emits(
+ "\n"
+ "<TABLE BORDER=2 WIDTH=100%%>\n"
+ "<TR>\n" );
+ if ( omitclosebutton ) {
+ dsgw_emitf( "<TD ALIGN=CENTER WIDTH=33%%>\n"
+ "<INPUT TYPE=BUTTON VALUE=\"%s\" onClick=\"history.back()\">\n"
+ "<TD ALIGN=CENTER WIDTH=33%%>\n",
+ XP_GetClientStr( DBT_Retry_ ));
+ dsgw_emit_homebutton();
+ dsgw_emits ( "<TD ALIGN=CENTER WIDTH=34%%>\n" );
+ dsgw_emit_helpbutton( "AUTHPROBLEM" );
+ } else {
+ dsgw_emitf( "<TD ALIGN=CENTER WIDTH=33%%>\n"
+ "<INPUT TYPE=BUTTON VALUE=\"%s\" onClick=\"history.back()\">\n"
+ "<TD ALIGN=CENTER WIDTH=33%%>\n"
+ "<INPUT TYPE=BUTTON VALUE=\"%s\" "
+ "onClick=\"parent.close();\">\n"
+ "<TD ALIGN=CENTER WIDTH=34%%>\n",
+ XP_GetClientStr( DBT_Retry_ ),
+ XP_GetClientStr( DBT_closeWindow_5 ));
+ dsgw_emit_helpbutton( "AUTHPROBLEM" );
+ }
+ dsgw_emits( "</TABLE>\n"
+ "</FORM>\n"
+ "</BODY></HTML>\n" );
+ fflush( stdout );
+ return;
+}
diff --git a/ldap/clients/dsgw/domodify.c b/ldap/clients/dsgw/domodify.c
new file mode 100644
index 00000000..5535311e
--- /dev/null
+++ b/ldap/clients/dsgw/domodify.c
@@ -0,0 +1,1254 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * domodify.c -- LDAP modify CGI handler -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+#define DSGW_CHANGETYPE_UNKNOWN 0
+#define DSGW_CHANGETYPE_MODIFY 1
+#define DSGW_CHANGETYPE_ADD 2
+#define DSGW_CHANGETYPE_DELETE 3
+#define DSGW_CHANGETYPE_MODRDN 4
+
+static void post_request();
+static int entry_modify_or_add( LDAP *ld, char *dn, int add, int *pwdchangedp );
+static int entry_delete( LDAP *ld, char *dn );
+static int entry_modrdn( LDAP *ld, char *dn, char *newrdn, int deleteoldrdn );
+static int gather_passwd_changes( char *dn, LDAPMod ***pmodsp,
+ int adding_entry, int *pwdchangedp );
+static void modify_error( int lderr, char *lderrtxt );
+static void addmodifyop( LDAPMod ***pmodsp, int modop, char *attr,
+ char *value, int vlen );
+static void remove_modifyops( LDAPMod **pmods, char *attr );
+static int starts_with( char *s, char *startswith );
+static char **post2multilinevals( char *postedval );
+static char **post2vals( char *postedval );
+static int require_oldpasswd( char *modifydn );
+static char *dsgw_processdomainid( LDAP *ld, char *dn, char *attr, char *val, int len);
+static int value_is_unique( LDAP *ld, char *dn, char *attr, char *value );
+static LDAPDomainIdStatus
+dsgw_checkdomain_uniqueness( LDAP *ld, char *attr, char *val, int len);
+static int verbose = 0;
+static int quiet = 0;
+static int display_results_inline = 0;
+
+
+int main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+
+ (void)dsgw_init( argc, argv, DSGW_METHOD_POST );
+ dsgw_send_header();
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ post_request();
+
+ exit( 0 );
+}
+
+
+static void
+post_request()
+{
+ LDAP *ld;
+ int rc, changetype, dnlen, i, passwd_changed, discard_authcreds;
+ char *s, *encodeddn, *dn, *newrdn, *changedesc, **rdns, **oldrdns,
+ *jscomp, *entry_name, *new_name, *success_msg;
+ char *old_dn;
+ char buf[ 256 ];
+#if 0
+ FILE *genfp;
+#endif
+
+ passwd_changed = discard_authcreds = 0;
+ s = dsgw_get_cgi_var( "changetype", DSGW_CGIVAR_REQUIRED );
+ changedesc = XP_GetClientStr(DBT_Editing_);
+
+ if ( strcasecmp( s, "modify" ) == 0 ) {
+ changetype = DSGW_CHANGETYPE_MODIFY;
+ } else if ( strcasecmp( s, "add" ) == 0 ) {
+ changetype = DSGW_CHANGETYPE_ADD;
+ changedesc = XP_GetClientStr(DBT_Adding_);
+ } else if ( strcasecmp( s, "delete" ) == 0 ) {
+ changetype = DSGW_CHANGETYPE_DELETE;
+ changedesc = XP_GetClientStr(DBT_Deleting_);
+ } else if ( strcasecmp( s, "modrdn" ) == 0 ) {
+ changetype = DSGW_CHANGETYPE_MODRDN;
+ changedesc = XP_GetClientStr(DBT_Renaming_);
+ } else {
+ changetype = DSGW_CHANGETYPE_UNKNOWN;
+ }
+
+ encodeddn = dsgw_get_cgi_var( "dn", DSGW_CGIVAR_REQUIRED );
+
+ /* undo extra level of escaping on DN */
+ dn = dsgw_ch_strdup( encodeddn );
+ dsgw_form_unescape( dn );
+ old_dn = dn;
+
+ quiet = dsgw_get_boolean_var( "quiet", DSGW_CGIVAR_OPTIONAL, 0 );
+
+#if 0
+ /*
+ * If the "genscreen" form variable is set, it is the name of a
+ * genscreen-compatible HTML template to display the domodify results
+ * within. We replace the "DS_LAST_OP_INFO" directive with our own
+ * "domodify" output. Presence of "genscreen" also turns on quiet mode.
+ */
+ if (( s = dsgw_get_cgi_var( "genscreen", DSGW_CGIVAR_OPTIONAL )) != NULL &&
+ dsgw_genscreen_begin( s, &genfp, DRCT_DS_LAST_OP_INFO, 0 ) == 0 ) {
+ quiet = display_results_inline = 1;
+ }
+#endif
+
+ verbose = dsgw_get_boolean_var( "verbose", DSGW_CGIVAR_OPTIONAL, 0 );
+ if ( verbose ) {
+ quiet = 0; /* verbose overrides quiet */
+ }
+
+ if ( dsgw_init_ldap( &ld, NULL, 0, 0) != DSGW_BOUND_ASUSER ) {
+ dsgw_emitf( XP_GetClientStr(DBT_warningNoAuthenticationContinuin_) );
+ }
+
+ if ( !quiet ) {
+ PR_snprintf( buf, 256,
+ XP_GetClientStr(DBT_SDirectoryEntry_), changedesc );
+ dsgw_html_begin( buf, 1 );
+ } else {
+ dsgw_html_begin( NULL, 0 );
+ }
+
+ dsgw_emits( "\n<FONT SIZE=+1>\n" );
+
+ rdns = ldap_explode_dn( dn, 1 );
+ if ( rdns == NULL || rdns[ 0 ] == NULL ) {
+ entry_name = dn;
+ } else {
+ entry_name = dsgw_ch_strdup( rdns[ 0 ] );
+ }
+ new_name = success_msg = "";
+ dsgw_emitf( "%s <B>%s</B>...\n</FONT>\n\n", changedesc, entry_name );
+ if ( rdns != NULL ) {
+ ldap_value_free( rdns );
+ }
+
+ if ( verbose ) {
+ dsgw_emitf( XP_GetClientStr(DBT_PreEntryDnSPrePN_), dn );
+ }
+
+ /*
+ * For end-user CGIs under admin server, if we're talking to a local DB,
+ * then there's no access control, and therefore we need to disallow
+ * people from changing entries other than their own. Do that check right
+ * here.
+ */
+ if ( gc->gc_enduser && gc->gc_localdbconf != NULL ) {
+ char *bdn;
+ (void)dsgw_get_adm_identity( ld, NULL, &bdn, NULL, DSGW_ERROPT_EXIT );
+ /* Make sure DN we're bound as matches the DN being modified */
+ if ( dsgw_dn_cmp( dn, bdn ) == 0 ) {
+ /* Not the same - generate an error and bail out */
+ dsgw_error( DSGW_ERR_LOCALDB_PERMISSION_DENIED, NULL,
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ }
+
+ rc = LDAP_SUCCESS;
+ switch( changetype ) {
+ case DSGW_CHANGETYPE_MODIFY:
+ if ( dsgw_get_boolean_var( "changed_DN", DSGW_CGIVAR_OPTIONAL, 0 )) {
+ /* Collect all the inputs named "replace_DN_attr", where
+ attr is an LDAP attribute type. Construct an AVA from
+ each such input, and combine the AVAs to form newrdn.
+ */
+ auto int i = 0;
+ auto char *varname, *val;
+ auto size_t newrdn_len;
+ newrdn = NULL;
+ while ( (varname = dsgw_next_cgi_var( &i, &val )) != NULL) {
+ if ( starts_with( varname, "replace_" )) {
+ auto char* attr = varname;
+ auto int is_rdn = 0;
+ {
+ auto char* p;
+ while (( p = strchr( attr, '_' )) != NULL ) {
+ attr = p + 1;
+ if ( starts_with( attr, "DN_" )) {
+ is_rdn = 1;
+ } /* ignore any other prefixes */
+ }
+ }
+ if (is_rdn && strlen(val) > 0) {
+ auto const size_t attrlen = strlen (attr);
+ auto const size_t val_len = strlen (val);
+ auto const size_t ava_len = attrlen + 1 + val_len;
+ auto char* ava;
+ if (newrdn == NULL) {
+ ava = newrdn = dsgw_ch_malloc (ava_len + 1);
+ newrdn_len = ava_len;
+ } else {
+ newrdn = dsgw_ch_realloc (newrdn, newrdn_len + ava_len + 2);
+ memcpy (newrdn + newrdn_len, "+", 1);
+ ava = newrdn + newrdn_len + 1;
+ newrdn_len += (ava_len + 1);
+ }
+ memcpy (ava, attr, attrlen);
+ memcpy (ava + attrlen, "=", 1);
+ memcpy (ava + attrlen + 1, val, val_len + 1);
+ }
+ }
+ free (varname);
+ }
+ if (newrdn) goto continue_modrdn;
+ /* else failed to compute newrdn */
+ }
+ break;
+ case DSGW_CHANGETYPE_MODRDN:
+ newrdn = dsgw_get_cgi_var( "newrdn", DSGW_CGIVAR_REQUIRED );
+ continue_modrdn:
+ dsgw_remove_leading_and_trailing_spaces( &newrdn );
+ rc = entry_modrdn( ld, dn, newrdn, dsgw_get_boolean_var( "deleteoldrdn",
+ DSGW_CGIVAR_OPTIONAL, 0 ));
+
+ if ( rc == LDAP_SUCCESS ) {
+
+ /* construct the new DN so we can insert correct "edit" link */
+ if (( oldrdns = ldap_explode_dn( dn, 0 )) == NULL ) {
+ dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT,
+ 0, NULL );
+ }
+
+ dnlen = strlen( newrdn ) + 1; /* room for "," */
+ for ( i = 1; oldrdns[ i ] != NULL; ++i ) {
+ dnlen += ( 1 + strlen( oldrdns[ i ] ));
+ }
+ dn = dsgw_ch_malloc( dnlen + 1 );
+ *dn = '\0';
+ strcat( dn, newrdn );
+ for ( i = 1; oldrdns[ i ] != NULL; ++i ) {
+ strcat( dn, "," );
+ strcat( dn, oldrdns[ i ] );
+ }
+ ldap_value_free( oldrdns );
+ free( encodeddn );
+ encodeddn = dsgw_strdup_escaped( dn );
+
+ success_msg = XP_GetClientStr(DBT_renamedBSBToBSB_);
+ if (( rdns = ldap_explode_rdn( newrdn, 1 )) == NULL
+ || rdns[ 0 ] == NULL ) {
+ new_name = newrdn;
+ } else {
+ new_name = dsgw_ch_strdup (rdns[ 0 ]);
+ ldap_value_free( rdns );
+ }
+ }
+ break;
+ default:
+ break;
+ }
+
+ switch( changetype ) {
+ case DSGW_CHANGETYPE_MODIFY:
+ if (rc != LDAP_SUCCESS) break;
+ case DSGW_CHANGETYPE_ADD:
+ rc = entry_modify_or_add( ld, dn, changetype == DSGW_CHANGETYPE_ADD,
+ &passwd_changed );
+ if ( changetype == DSGW_CHANGETYPE_MODIFY ) {
+ success_msg = XP_GetClientStr(DBT_changesToBSBHaveBeenSaved_);
+ } else {
+ success_msg = XP_GetClientStr(DBT_BSBHasBeenAdded_);
+ }
+ break;
+ case DSGW_CHANGETYPE_DELETE:
+ rc = entry_delete( ld, dn );
+ success_msg = XP_GetClientStr(DBT_BSBHasBeenDeleted_);
+ break;
+ case DSGW_CHANGETYPE_MODRDN:
+ break;
+ default:
+ rc = LDAP_PARAM_ERROR;
+ }
+
+ /*
+ * If we are not running under the admin. server AND the operation
+ * succeeded and the user is bound as the entry they just changed,
+ * AND one of these conditions is true:
+ * 1. we changed the password
+ * 2. we did a modrdn
+ * 3. we deleted the entry
+ * then the auth. credentials should be discarded. If we do discard, we
+ * print an informative message for the user.
+ */
+ if ( !gc->gc_admserv && rc == LDAP_SUCCESS &&
+ ( changetype == DSGW_CHANGETYPE_DELETE || dn != old_dn ||
+ ( changetype == DSGW_CHANGETYPE_MODIFY && passwd_changed )) &&
+ dsgw_bound_as_dn( old_dn, 0 )) {
+ char *authck;
+
+ /* first, remove the cookie from the cookie database (ignore errors) */
+ if (( authck = dsgw_get_auth_cookie()) != NULL ) {
+ (void)dsgw_delcookie( authck );
+ }
+
+ /* output JavaScript to clear the cookie in the user's browser */
+ dsgw_emits( "<SCRIPT LANGUAGE=\"JavaScript\">\n" );
+ dsgw_emits( "<!-- Hide from non-JavaScript browsers\n" );
+ dsgw_emitf( "document.cookie = '%s=%s; path=/'\n",
+ DSGW_AUTHCKNAME, DSGW_UNAUTHSTR );
+ dsgw_emits( "// End Hiding -->\n</SCRIPT>\n" );
+ dsgw_emitf( XP_GetClientStr(DBT_PBNoteBBecauseYouSTheEntryYouWer_),
+ ( changetype == DSGW_CHANGETYPE_DELETE ) ? XP_GetClientStr(DBT_deleted_) :
+ ( dn != old_dn ) ? XP_GetClientStr(DBT_renamed_) :
+ XP_GetClientStr(DBT_changedThePasswordOf_) );
+ }
+
+ if ( rc == LDAP_SUCCESS ) {
+ /*
+ * check for "completion_javascript" form var and
+ * execute it if present.
+ */
+ jscomp = dsgw_get_cgi_var( "completion_javascript",
+ DSGW_CGIVAR_OPTIONAL );
+ if ( jscomp != NULL ) {
+ char *entry_name_js;
+ char *new_name_js;
+
+ entry_name_js = dsgw_escape_quotes( entry_name );
+ new_name_js = dsgw_escape_quotes( new_name );
+ dsgw_emits( "<SCRIPT LANGUAGE=\"JavaScript\">\n" );
+ dsgw_emits( "dsmodify_info = '" );
+ dsgw_emitf( success_msg, entry_name_js, new_name_js );
+ dsgw_emits( "';\n" );
+ dsgw_emitf( "dsmodify_dn = '%s';\n",
+ ( changetype == DSGW_CHANGETYPE_DELETE ) ? "":
+ encodeddn );
+ dsgw_emitf( "eval('%s');\n", jscomp );
+ dsgw_emits( "</SCRIPT>\n" );
+ }
+ } else {
+ jscomp = NULL;
+ }
+
+ if (( jscomp == NULL || changetype == DSGW_CHANGETYPE_DELETE )
+ && !gc->gc_admserv ) {
+ dsgw_form_begin( NULL, NULL );
+ dsgw_emits( "\n<CENTER><TABLE border=2 width=\"100%\"><TR>\n" );
+ /*
+ * Show framed button. If the modify succeeded, it is "Close".
+ * If the modify failed, it is "Go Back."
+ */
+ dsgw_emits( "<TD WIDTH=\"100%\" ALIGN=\"center\">\n" );
+ if ( rc == LDAP_SUCCESS ) {
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"parent.close()\">\n",
+ XP_GetClientStr(DBT_closeWindow_) );
+ } else {
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"history.back()\">\n",
+ XP_GetClientStr(DBT_goBack_) );
+ }
+ dsgw_emits( "\n</TABLE></CENTER></FORM>\n" );
+ }
+
+#if 0
+ if ( display_results_inline && genfp != NULL ) {
+ dsgw_emits( "<HR>\n" );
+ dsgw_genscreen_continue( &genfp, NULL, 0 );
+ } else if ( !quiet ) {
+ dsgw_html_end();
+ }
+#else
+ if ( !quiet ) {
+ dsgw_html_end();
+ }
+#endif
+ ldap_unbind( ld );
+ if (old_dn != dn) free ( old_dn );
+ free( dn );
+}
+
+static int
+entry_modify_or_add( LDAP *ld, char *dn, int add, int *pwdchangedp )
+{
+ int lderr, i, j, opoffset, modop, mls, unique, unchanged_count;
+ char *varname, *varvalue, *retval, *attr, *p, **vals, **unchanged_attrs;
+ char *userid = NULL, *oc_ntuser = NULL;
+ char userdomainid[512];
+
+ char *groupname = NULL;
+ char groupdomainid[512];
+
+ LDAPMod **pmods;
+
+ int msgid;
+ LDAPMessage *res = NULL;
+ char *errmsg = NULL;
+
+ memset( userdomainid, 0, sizeof( userdomainid ));
+ memset( groupdomainid, 0, sizeof( groupdomainid ));
+
+ pmods = NULL;
+ unchanged_attrs = NULL;
+ unchanged_count = 0;
+
+ /*
+ * Gather up password changes (if present in CGI POST)
+ */
+ if (( lderr = gather_passwd_changes( dn, &pmods, add, pwdchangedp ))
+ != LDAP_SUCCESS ) {
+ return( lderr );
+ }
+
+ if ( verbose ) {
+ dsgw_emitf( "<PRE>\n" );
+ }
+
+ /*
+ * Gather up other changes: each attribute value is POSTed in a variable
+ * named:
+ * add_[unique_]ATTR
+ * replace_[unique_][DN_]ATTR
+ * or delete_[unique_]ATTR
+ *
+ * where ATTR is the LDAP attribute name and "unique_" is optional (if
+ * present, we check to make sure the value is not in use before accepting
+ * a replace or add).
+ *
+ * Additionally, if a variable name changed_ATTR is POSTed and its value
+ * is not "true", it is assumed that no values have changed for that
+ * ATTRibute. If no "changed_ATTR" variable is POSTed, we assume that
+ * ATTR has in fact changed.
+ */
+ i = 0;
+ while (( varname = dsgw_next_cgi_var( &i, &varvalue )) != NULL ) {
+ if ( varvalue != NULL && *varvalue == '\0' ) {
+ varvalue = NULL;
+ } else {
+ dsgw_remove_leading_and_trailing_spaces( &varvalue );
+ }
+
+ opoffset = -1;
+ if ( starts_with( varname, "add_" )) {
+ modop = LDAP_MOD_ADD;
+ opoffset = 4;
+ } else if ( starts_with( varname, "replace_" )) {
+ modop = LDAP_MOD_REPLACE;
+ opoffset = 8;
+ attr = varname + opoffset;
+ if( strcasecmp( DSGW_ATTRTYPE_NTUSERDOMAINID, attr) == 0) {
+ if( varvalue) {
+ if( !userid )
+ userid = strdup( varvalue );
+ else
+ strcpy( userdomainid, varvalue );
+ }
+ }
+ if( strcasecmp( DSGW_ATTRTYPE_NTGROUPDOMAINID, attr) == 0) {
+ if( varvalue) {
+ if( !groupname )
+ groupname = strdup( varvalue );
+ else
+ strcpy( groupdomainid, varvalue );
+ }
+ }
+ } else if ( starts_with( varname, "delete_" )) {
+ modop = LDAP_MOD_DELETE;
+ opoffset = 7;
+ } else if ( !strcmp( varname, "changed_DN" )) {
+ /* ignore it */
+ } else if ( starts_with( varname, "changed_" )) {
+ attr = varname + 8;
+ if ( verbose && strcasecmp( varvalue, "true" ) == 0 ) {
+ dsgw_emitf( XP_GetClientStr(DBT_attributeSWasChangedBrN_), attr );
+ }
+ if ( varvalue != NULL && strcasecmp( varvalue, "true" ) != 0 ) {
+ unchanged_attrs = (char **)dsgw_ch_realloc( unchanged_attrs,
+ ( 2 + unchanged_count ) * sizeof( char * ));
+ unchanged_attrs[ unchanged_count++ ] = dsgw_ch_strdup( attr );
+ unchanged_attrs[ unchanged_count ] = NULL;
+
+ if ( pmods != NULL ) {
+ remove_modifyops( pmods, attr );
+ }
+ }
+ } else if ( starts_with( varname, "replace_" )) {
+ modop = LDAP_MOD_REPLACE;
+ opoffset = 8;
+ attr = varname + opoffset;
+ if( strcasecmp( DSGW_ATTRTYPE_USERID, attr) == 0)
+ if( varvalue)
+ userid = strdup( varvalue );
+ if( strcasecmp( DSGW_ATTRTYPE_NTUSERDOMAINID, attr) == 0)
+ if( varvalue)
+ strcpy( userdomainid, varvalue );
+ if( strcasecmp( DSGW_ATTRTYPE_NTGROUPNAME, attr) == 0)
+ if( varvalue)
+ groupname = strdup( varvalue );
+ if( strcasecmp( DSGW_ATTRTYPE_NTGROUPDOMAINID, attr) == 0)
+ if( varvalue)
+ strcpy( groupdomainid, varvalue );
+ }
+
+ if ( opoffset >= 0 ) {
+ attr = varname + opoffset;
+ mls = 0;
+ unique = 0;
+ while (( p = strchr( attr, '_' )) != NULL ) {
+ if ( starts_with( attr, "mls_" )) {
+ mls = 1;
+ } else if ( starts_with( attr, "unique_" )) {
+ unique = 1;
+ } /* ignore any other prefixes */
+ attr = p + 1;
+ }
+
+ for ( j = 0; j < unchanged_count; ++j ) {
+ if ( strcasecmp( unchanged_attrs[ j ], attr ) == 0 ) {
+ break;
+ }
+ }
+
+ if ( j >= unchanged_count ) {
+ if ( varvalue == NULL || *varvalue == '\0' ) {
+ vals = NULL;
+ varvalue = NULL;
+ } else {
+ varvalue = dsgw_ch_strdup( varvalue );
+ if ( mls ) {
+ vals = post2multilinevals( varvalue );
+ } else {
+ vals = post2vals( varvalue );
+ }
+ }
+ if ( vals == NULL ) {
+ if ( modop != LDAP_MOD_ADD ) {
+ addmodifyop( &pmods, modop, attr, NULL, 0 );
+ }
+ } else {
+ for ( j = 0; vals[ j ] != NULL; ++j ) {
+ if ( unique && modop != LDAP_MOD_DELETE && ( lderr =
+ value_is_unique( ld, dn, attr, vals[ j ] )) !=
+ LDAP_SUCCESS ) {
+ return( lderr );
+ }
+ if( strcasecmp( DSGW_OC_NTUSER, varvalue) == 0 &&
+ modop == LDAP_MOD_ADD ) {
+ oc_ntuser = strdup( vals[ j ] );
+ }
+
+ if( strcasecmp( DSGW_ATTRTYPE_NTUSERDOMAINID, attr) == 0) {
+ if( modop == LDAP_MOD_ADD ) {
+ if( userid == NULL ) {
+ userid = strdup( vals[ j ] );
+ break;
+ } else {
+ memset( userdomainid, 0, sizeof( userdomainid ));
+ PR_snprintf( userdomainid, 512, "%s%c%s",
+ vals[ j ], DSGW_NTDOMAINID_SEP, userid );
+ if( dsgw_checkdomain_uniqueness( ld, attr,
+ userdomainid, strlen( userdomainid ) ) !=
+ LDAPDomainIdStatus_Unique) {
+ dsgw_error( DSGW_ERR_DOMAINID_NOTUNIQUE,
+ NULL, 0, 0, NULL );
+ return(LDAP_PARAM_ERROR);
+ } else {
+ /* don't free here because this is freed elsewhere */
+ /*
+ free( vals[ j ] );
+ */
+ vals[ j ] = strdup( userdomainid );
+ }
+ }
+ } else {
+ if(( retval = dsgw_processdomainid( ld, dn, attr,
+ vals[ j ], strlen( vals[ j ] ))) != 0) {
+ vals[ j ] = retval;
+ }
+ }
+ }
+
+ if( strcasecmp( DSGW_ATTRTYPE_NTGROUPDOMAINID, attr) == 0) {
+ if( modop == LDAP_MOD_ADD ) {
+ if( groupname == NULL ) {
+ groupname = strdup( vals[ j ] );
+ break;
+ } else {
+ memset( groupdomainid, 0, sizeof( groupdomainid ));
+ PR_snprintf( groupdomainid, 512, "%s%c%s",
+ vals[ j ], DSGW_NTDOMAINID_SEP, groupname );
+ if( dsgw_checkdomain_uniqueness( ld, attr,
+ groupdomainid, strlen( groupdomainid ) ) !=
+ LDAPDomainIdStatus_Unique) {
+ dsgw_error( DSGW_ERR_DOMAINID_NOTUNIQUE,
+ NULL, 0, 0, NULL );
+ return(LDAP_PARAM_ERROR);
+ } else {
+ /* don't free here because this is freed elsewhere */
+ /*
+ free( vals[ j ] );
+ */
+ vals[ j ] = strdup( groupdomainid );
+ }
+ }
+ } else {
+ if(( retval = dsgw_processdomainid( ld, dn, attr,
+ vals[ j ], strlen( vals[ j ] ))) != 0) {
+ vals[ j ] = retval;
+ }
+ }
+ }
+ addmodifyop( &pmods, modop, attr, vals[ j ],
+ strlen( vals[ j ] ));
+ }
+ free( vals );
+ }
+ if ( varvalue != NULL ) {
+ free( varvalue );
+ }
+ }
+ }
+
+ free( varname );
+ }
+
+ if( oc_ntuser != NULL &&
+ ((strlen( userdomainid ) == 0) || userid == NULL )) {
+ dsgw_error( DSGW_ERR_USERID_DOMAINID_REQUIRED, NULL, 0, 0, NULL );
+ return(LDAP_PARAM_ERROR);
+ }
+
+ if( strlen( userdomainid ) > 0 && userid == NULL ) {
+ dsgw_error( DSGW_ERR_USERID_REQUIRED, NULL, 0, 0, NULL );
+ return(LDAP_PARAM_ERROR);
+ }
+
+ if( strlen( userdomainid ) > 0 && userid &&
+ strlen( userid ) > MAX_NTUSERID_LEN) {
+ dsgw_error( DSGW_ERR_USERID_MAXLEN_EXCEEDED, NULL, 0, 0, NULL );
+ return(LDAP_PARAM_ERROR);
+ }
+
+ if ( verbose && pmods != NULL ) {
+ int j, notascii;
+ unsigned long k;
+ struct berval *bvp;
+
+ for ( i = 0; pmods[ i ] != NULL; ++i ) {
+ modop = pmods[ i ]->mod_op & ~LDAP_MOD_BVALUES;
+ dsgw_emitf( "%s %s:\n", modop == LDAP_MOD_REPLACE ?
+ "replace" : modop == LDAP_MOD_ADD ?
+ "add" : "delete", pmods[ i ]->mod_type );
+ if ( pmods[ i ]->mod_bvalues != NULL ) {
+ for ( j = 0; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
+ bvp = pmods[ i ]->mod_bvalues[ j ];
+ notascii = 0;
+ for ( k = 0; k < bvp->bv_len; ++k ) {
+ if ( !isascii( bvp->bv_val[ k ] )) {
+ notascii = 1;
+ break;
+ }
+ }
+ if ( notascii ) {
+ dsgw_emitf( XP_GetClientStr(DBT_TnotAsciiLdBytesN_), bvp->bv_len );
+ } else {
+ dsgw_emitf( "\t\"%s\"\n", bvp->bv_val );
+ }
+ }
+ }
+ }
+ }
+
+ if ( verbose ) {
+ dsgw_emitf( "</PRE>\n" );
+ fflush( stdout );
+ }
+
+ dsgw_emitf( "<FONT SIZE=+1>\n" );
+
+ /*
+ * apply the changes using LDAP
+ */
+ if ( pmods == NULL ) {
+ if ( add ) {
+ dsgw_emits( XP_GetClientStr(DBT_noValuesWereEnteredPleaseTryAgai_) );
+ lderr = LDAP_PARAM_ERROR;
+ } else { /* no changes -- just report success */
+ lderr = LDAP_SUCCESS;
+ if ( !quiet ) {
+ dsgw_emitf( XP_GetClientStr(DBT_PSuccessfullyEditedEntryYourChan_) );
+ }
+ }
+ } else {
+ if ( !quiet ) {
+ dsgw_emitf( XP_GetClientStr(DBT_PSendingSToTheDirectoryServerN_),
+ add ? XP_GetClientStr(DBT_information_) : XP_GetClientStr(DBT_changes_));
+ fflush( stdout );
+ }
+
+ if ( add ) {
+ lderr = ldap_add_ext( ld, dn, pmods, NULL, NULL, &msgid );
+ } else {
+ lderr = ldap_modify_ext( ld, dn, pmods, NULL, NULL, &msgid );
+ }
+
+ if( lderr == LDAP_SUCCESS ) {
+ if(( lderr = ldap_result( ld, msgid, 1, (struct timeval *)NULL, &res )) == -1 ) {
+ lderr = ldap_get_lderrno( ld, NULL, &errmsg );
+ modify_error( lderr, errmsg );
+ } else {
+ lderr = ldap_result2error( ld, res, 1 );
+ if ( lderr == LDAP_SUCCESS ) {
+ if ( !quiet ) {
+ if ( add ) {
+ dsgw_emitf( XP_GetClientStr(DBT_PSuccessfullyAddedEntryN_) );
+ } else {
+ dsgw_emitf( XP_GetClientStr(DBT_PSuccessfullyEditedEntryYourChan_) );
+ }
+ }
+ } else {
+ (void)ldap_get_lderrno( ld, NULL, &errmsg );
+ modify_error( lderr, errmsg );
+
+ /* Do some checks for password policy infractions. */
+ if( lderr == LDAP_CONSTRAINT_VIOLATION ) {
+ if( errmsg && strstr( errmsg, "invalid password syntax" ) )
+ dsgw_emitf( "<BR>(%s)", XP_GetClientStr(DBT_InvalidPasswordSyntax_) );
+ else if( errmsg && strstr( errmsg, "password in history" ) )
+ dsgw_emitf( "<BR>(%s)", XP_GetClientStr(DBT_PasswordInHistory_) );
+ }
+ }
+ }
+ } else {
+ (void)ldap_get_lderrno( ld, NULL, &errmsg );
+ modify_error( lderr, errmsg );
+ }
+
+ ldap_mods_free( pmods, 1 );
+ }
+
+ dsgw_emitf( "</FONT>\n" );
+ return( lderr );
+}
+
+
+static int
+entry_delete( LDAP *ld, char *dn )
+{
+ int lderr;
+ char *errmsg = NULL;
+
+ dsgw_emitf( "<FONT SIZE=+1>\n" );
+ if (( lderr = ldap_delete_s( ld, dn )) == LDAP_SUCCESS ) {
+ if ( !quiet ) {
+ dsgw_emitf( XP_GetClientStr(DBT_PSuccessfullyDeletedEntryN_) );
+ }
+ } else {
+ (void)ldap_get_lderrno( ld, NULL, &errmsg );
+ modify_error( lderr, errmsg );
+ }
+
+ dsgw_emitf( "</FONT>\n" );
+ return( lderr );
+}
+
+
+static int
+entry_modrdn( LDAP *ld, char *dn, char *newrdn, int deleteoldrdn )
+{
+ int lderr;
+ char *errmsg = NULL;
+
+ if ( verbose ) {
+ dsgw_emitf( XP_GetClientStr(DBT_PreTheNewNameForTheEntryIsSNPreH_),
+ newrdn );
+ }
+
+ dsgw_emitf( "<FONT SIZE=+1>\n" );
+ if (( lderr = ldap_modrdn2_s( ld, dn, newrdn, deleteoldrdn ))
+ == LDAP_SUCCESS ) {
+ if ( !quiet ) {
+ dsgw_emitf( XP_GetClientStr(DBT_PSuccessfullyRenamedEntryN_) );
+ }
+ } else {
+ (void)ldap_get_lderrno( ld, NULL, &errmsg );
+ modify_error( lderr, errmsg );
+ }
+
+ dsgw_emitf( "</FONT>\n" );
+ return( lderr );
+}
+
+
+static int
+gather_passwd_changes( char *dn, LDAPMod ***pmodsp, int adding_entry,
+ int *pwdchangedp )
+{
+ int lderr, lockpasswd;
+ char *bindpasswd, *newpasswd, *newpasswdconfirm, *errstring;
+
+ lockpasswd = dsgw_get_boolean_var( "lockpasswd", 0, 0 );
+ if ( lockpasswd ) {
+ /*
+ * the userPassword attribute to a special value that no password
+ * submitted by a user can ever match.
+ */
+ time_t curtime;
+ struct tm *gmtp;
+ char *tstr;
+
+ /* get string representation of current GMT time */
+ curtime = time( NULL );
+ gmtp = gmtime( &curtime );
+ tstr = asctime( gmtp );
+
+ /* remove trailing newline */
+ tstr[ strlen( tstr ) - 1 ] = '\0';
+
+ /* allocate room for "{crypt}LOCKED [" + tstr + " GMT]" + zero byte */
+ newpasswd = dsgw_ch_malloc( 15 + strlen( tstr ) + 5 + 1 );
+ sprintf( newpasswd, XP_GetClientStr(DBT_CryptLockedSGmt_), tstr );
+
+ } else if (( newpasswd = dsgw_get_cgi_var( "newpasswd",
+ DSGW_CGIVAR_OPTIONAL )) == NULL ) {
+ return( LDAP_SUCCESS ); /* not setting password -- nothing to do */
+ }
+
+ lderr = LDAP_PARAM_ERROR; /* pessimistic */
+
+ if ( !adding_entry && ( bindpasswd = dsgw_get_cgi_var( "passwd",
+ DSGW_CGIVAR_OPTIONAL )) == NULL && require_oldpasswd( dn )) {
+ errstring = XP_GetClientStr(DBT_youMustProvideTheOldPassword_);
+ } else if ( !lockpasswd &&
+ (( newpasswdconfirm = dsgw_get_cgi_var( "newpasswdconfirm",
+ DSGW_CGIVAR_OPTIONAL )) == NULL || strcmp( newpasswd,
+ newpasswdconfirm ) != 0 )) {
+ errstring = XP_GetClientStr(DBT_theNewAndConfirmingPasswordsDoNo_);
+ } else {
+ addmodifyop( pmodsp, adding_entry ? LDAP_MOD_ADD : LDAP_MOD_REPLACE,
+ DSGW_ATTRTYPE_USERPASSWORD, newpasswd, strlen( newpasswd ));
+ *pwdchangedp = 1;
+ lderr = LDAP_SUCCESS;
+ }
+
+ if ( lderr != LDAP_SUCCESS ) {
+ dsgw_emitf( "<FONT SIZE=+1>\n%s\n</FONT>\n", errstring );
+ }
+
+ return( lderr );
+}
+
+
+static void
+modify_error( int lderr, char *lderrtxt )
+{
+ dsgw_error( DSGW_ERR_LDAPGENERAL, dsgw_ldaperr2string( lderr ),
+ ( display_results_inline ? DSGW_ERROPT_INLINE : 0 ),
+ lderr, lderrtxt );
+}
+
+
+/*
+ * this "addmodifyop" routine is lifted with minor changes from
+ * ldap/tools/ldapmodify.c
+ */
+static void
+addmodifyop( LDAPMod ***pmodsp, int modop, char *attr, char *value, int vlen )
+{
+ LDAPMod **pmods;
+ int i, j;
+ struct berval *bvp;
+
+ if ( attr == NULL || *attr == '\0' ) {
+ return;
+ }
+
+ pmods = *pmodsp;
+ modop |= LDAP_MOD_BVALUES;
+
+ i = 0;
+ if ( pmods != NULL ) {
+ for ( ; pmods[ i ] != NULL && pmods[ i ]->mod_type != NULL; ++i ) {
+ if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 &&
+ pmods[ i ]->mod_op == modop ) {
+ break;
+ }
+ }
+ }
+
+ if ( pmods == NULL || pmods[ i ] == NULL ) {
+ pmods = (LDAPMod **)dsgw_ch_realloc( pmods, (i + 2) *
+ sizeof( LDAPMod * ));
+ *pmodsp = pmods;
+ pmods[ i + 1 ] = NULL;
+ pmods[ i ] = (LDAPMod *)dsgw_ch_malloc( sizeof( LDAPMod ));
+ memset( pmods[ i ], 0, sizeof( LDAPMod ));
+ pmods[ i ]->mod_op = modop;
+ pmods[ i ]->mod_type = dsgw_ch_strdup( attr );
+ }
+
+ if ( value != NULL ) {
+ j = 0;
+ if ( pmods[ i ]->mod_bvalues != NULL ) {
+ for ( ; pmods[ i ]->mod_bvalues[ j ] != NULL; ++j ) {
+ ;
+ }
+ }
+ pmods[ i ]->mod_bvalues =
+ (struct berval **)dsgw_ch_realloc( pmods[ i ]->mod_bvalues,
+ (j + 2) * sizeof( struct berval * ));
+ pmods[ i ]->mod_bvalues[ j + 1 ] = NULL;
+ bvp = (struct berval *)dsgw_ch_malloc( sizeof( struct berval ));
+ pmods[ i ]->mod_bvalues[ j ] = bvp;
+
+ bvp->bv_len = vlen;
+ bvp->bv_val = (char *)dsgw_ch_malloc( vlen + 1 );
+ memcpy( bvp->bv_val, value, vlen );
+ bvp->bv_val[ vlen ] = '\0';
+ }
+}
+
+
+/* remove all modify ops that refer to "attr" */
+static void
+remove_modifyops( LDAPMod **pmods, char *attr )
+{
+ int i, found_attr;
+
+ if ( pmods == NULL ) {
+ return;
+ }
+
+ do {
+ found_attr = 0;
+ for ( i = 0 ; pmods[ i ] != NULL; ++i ) {
+ if ( strcasecmp( pmods[ i ]->mod_type, attr ) == 0 ) {
+ found_attr = 1;
+ break;
+ }
+ }
+
+ if ( found_attr ) {
+ if ( pmods[ i ]->mod_bvalues != NULL ) {
+ ber_bvecfree( pmods[ i ]->mod_bvalues );
+ }
+ free( pmods[ i ] );
+
+ for ( ; pmods[ i + 1 ] != NULL; ++i ) {
+ pmods[ i ] = pmods[ i + 1 ];
+ }
+ pmods[ i ] = NULL;
+ }
+
+ } while ( found_attr );
+}
+
+
+static int
+starts_with( char *s, char *startswith )
+{
+ int len;
+
+ len = strlen( startswith );
+ return ( strlen( s ) > len && strncmp( s, startswith, len ) == 0 );
+}
+
+
+/*
+ * there is one value in "postedval" but newlines must be changed to "$",
+ * '$' characters must be changed to \24, and '\' chars. changed to \5C
+ */
+static char **
+post2multilinevals( char *postedval )
+{
+ int specials;
+ char *p, *r, **vals;
+
+ vals = dsgw_ch_malloc( 2 * sizeof( char * ));
+ vals[ 1 ] = NULL;
+
+ specials = 0;
+ for ( p = postedval; *p != '\0'; ++p ) {
+ if ( *p == '$' || *p == '\\' || *p == '\n' || *p == '\r') {
+ ++specials;
+ }
+ }
+
+ /* allocate enough room to handle any necessary escaping */
+ r = vals[ 0 ] = dsgw_ch_malloc( 2 * specials + strlen( postedval ) + 1 );
+
+ /* copy and escape as appropriate */
+ for ( p = postedval; *p != '\0'; ++p ) {
+ if ( *p == '\n' || *p == '\r' ) { /* change to "$" */
+ *r++ = '$';
+ if ( *(p+1) != '\0' && *(p+1) != *p &&
+ ( *(p+1) == '\n' || *(p+1) == '\r' )) {
+ ++p; /* skip next char. if sequence is "\r\n" or "\n\r" */
+ }
+ } else if ( *p == '$' ) { /* change to "\24" */
+ *r++ = '\\';
+ *r++ = '2';
+ *r++ = '4';
+ } else {
+ *r++ = *p;
+ if ( *p == '\\' ) { /* change to "\5C" */
+ *r++ = '5';
+ *r++ = 'C';
+ }
+ }
+ }
+
+ *r = '\0';
+
+ return( vals );
+}
+
+
+/* values are delimited by newlines, preceded by optional carriage returns */
+static char **
+post2vals( char *postedval )
+{
+ int count, len;
+ char *p, *q, **vals;
+
+ vals = NULL;
+
+ count = 0;
+ for ( p = postedval; p != NULL && *p != '\0'; p = q ) {
+ /* skip any leading CRs or NLs */
+ while (( *p == '\n' || *p == '\r' ) && *p != '\0' ) {
+ ++p;
+ }
+ if ( *p == '\0' ) {
+ break;
+ }
+
+ /* find end of this line */
+ if (( q = strchr( p, '\n' )) != NULL ) {
+ *q++ = '\0';
+ }
+
+ /* remove CR, if any */
+ len = strlen( p ) - 1;
+ if ( p[ len ] == '\r' ) {
+ p[ len ] = '\0';
+ }
+
+ /* add to values array */
+ vals = dsgw_ch_realloc( vals, ( count + 2 ) * sizeof( char * ));
+ vals[ count++ ] = p;
+ }
+ vals[ count ] = NULL;
+
+ return( vals );
+}
+
+
+/*
+ * Determine if we should insist that the old password for the entry
+ * we are modifying (modifydn) be POSTed. The rule we use is simply
+ * this: if the binddn and modifydn are the same, require the old
+ * password. This allows directory admins. to reset passwords while
+ * preventing normal users from having their password changed if they
+ * just happen to walk away from their computer for a while when they
+ * are authenticated to the gateway.
+ */
+static int
+require_oldpasswd( char *modifydn )
+{
+ return( dsgw_bound_as_dn( modifydn, 1 ));
+}
+
+
+/*
+ * search directory to find out if an attribute value is unique. If the
+ * value doesn't already exist or if it exists only in the same entry we
+ * are changing, we return LDAP_SUCCESS. If it does exist, we return
+ * LDAP_TYPE_OR_VALUE_EXISTS. If some other error occurs, we return another
+ * LDAP error code.
+ */
+static int
+value_is_unique( LDAP *ld, char *dn, char *attr, char *value )
+{
+ int rc, count;
+ char *attrs[2], *buf, *tmpdn, *attrdesc, *errmsg = NULL;
+ LDAPMessage *res, *e;
+
+ /* allocate room for "(attr=value)" filter */
+ buf = dsgw_ch_malloc( strlen( attr ) + strlen( value ) + 4 );
+ sprintf( buf, "(%s=%s)", attr, value );
+
+ attrs[ 0 ] = attr;
+ attrs[ 1 ] = NULL;
+
+ rc = ldap_search_s( ld, gc->gc_ldapsearchbase, LDAP_SCOPE_SUBTREE,
+ buf, attrs, 1, &res );
+ free( buf );
+
+ if ( rc != LDAP_SUCCESS || res == NULL ) {
+ (void)ldap_get_lderrno( ld, NULL, &errmsg );
+ modify_error( rc, errmsg );
+ return( rc );
+ }
+
+ if (( count = ldap_count_entries( ld, res )) == 0 ) {
+ rc = LDAP_SUCCESS;
+ } else if ( count > 1 ) {
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ } else { /* found one entry: see if it is the entry we are modifying */
+ if (( e = ldap_first_entry( ld, res )) == NULL ||
+ ( tmpdn = ldap_get_dn( ld, e )) == NULL ) {
+ rc = ldap_get_lderrno( ld, NULL, NULL );
+ } else if ( dsgw_dn_cmp( dn, tmpdn ) != 0 ) {
+ rc = LDAP_SUCCESS; /* same entry */
+ } else {
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+ }
+
+ ldap_msgfree( res );
+
+ if ( rc == LDAP_TYPE_OR_VALUE_EXISTS ) {
+ buf = dsgw_ch_malloc( strlen( attr ) + 6 ); /* room for "desc_" */
+ sprintf( buf, "desc_%s", attr );
+ if (( attrdesc = dsgw_get_cgi_var( buf, DSGW_CGIVAR_OPTIONAL ))
+ == NULL ) {
+ attrdesc = attr;
+ }
+ free( buf );
+
+ dsgw_emits( "\n<FONT SIZE=+1>\n" );
+ dsgw_emitf( XP_GetClientStr(DBT_BrTheSBSBIsAlreadyInUsePleaseCho_), attrdesc, value );
+ dsgw_emits( "\n</FONT>\n" );
+ }
+
+ return( rc );
+}
+
+
+/*
+ * Check that the domain:userid is unique in the directory.
+ */
+static LDAPDomainIdStatus
+dsgw_checkdomain_uniqueness( LDAP *ld, char *attr, char *val, int len)
+{
+ int rc, count;
+ LDAPMessage *msgp = NULL;
+ char filter[256];
+
+ if( val == NULL )
+ return LDAPDomainIdStatus_NullId;
+
+ if( strcasecmp( attr, DSGW_ATTRTYPE_NTUSERDOMAINID ) == 0 ) {
+ PR_snprintf( filter, 256, "%s=%s", DSGW_ATTRTYPE_NTUSERDOMAINID, val );
+ } else if ( strcasecmp( attr, DSGW_ATTRTYPE_NTGROUPDOMAINID ) == 0 ) {
+ PR_snprintf( filter, 256, "%s=%s", DSGW_ATTRTYPE_NTGROUPDOMAINID, val );
+ } else {
+ return LDAPDomainIdStatus_NullAttr;
+ }
+
+ if (( rc = ldap_search_s( ld, gc->gc_ldapsearchbase, LDAP_SCOPE_SUBTREE,
+ filter, NULL, 0, &msgp )) == LDAP_SUCCESS) {
+ count = (msgp == NULL) ? 0 : ldap_count_entries( ld, msgp );
+ if ( count > 0 ) {
+ return LDAPDomainIdStatus_Nonunique;
+ } else {
+ return LDAPDomainIdStatus_Unique;
+ }
+ } else {
+ return LDAPDomainIdStatus_Nonunique;
+ }
+}
+
+
+/*
+ * Add the current value of uid in the entry to the ntdomain id before
+ * further processing of the domain id.
+ */
+static char *
+dsgw_processdomainid( LDAP *ld, char *dn, char *attr, char *val, int len)
+{
+ int rc, count;
+ LDAPMessage *msgp = NULL;
+ LDAPMessage *entry;
+ char **attrlist, *attrs[ 2 ];
+ char *value, *newval;
+ char *pch, **vals;
+
+ if( strcasecmp( attr, DSGW_ATTRTYPE_NTUSERDOMAINID ) != 0 &&
+ strcasecmp( attr, DSGW_ATTRTYPE_NTGROUPDOMAINID ) != 0 )
+ return( NULL );
+
+ attrs[ 0 ] = NULL;
+ attrs[ 1 ] = NULL;
+ attrlist = attrs;
+
+ if(( rc = ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "(objectclass=*)", attrlist,
+ 0, &msgp )) != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT)
+ {
+ return( NULL );
+ }
+
+ count = (msgp == NULL) ? 0 : ldap_count_entries( ld, msgp );
+
+ if( count > 0 )
+ {
+ entry = ldap_first_entry( ld, msgp );
+ if( entry )
+ {
+
+ if(( vals = ldap_get_values( ld, entry,
+ strcasecmp( attr, DSGW_ATTRTYPE_NTUSERDOMAINID )?
+ DSGW_ATTRTYPE_NTGROUPDOMAINID :
+ DSGW_ATTRTYPE_NTUSERDOMAINID )) != NULL)
+ {
+ if( vals[0] != NULL )
+ {
+ value = dsgw_ch_strdup( vals[0] );
+ newval = dsgw_ch_malloc( len + strlen( value ) +1 );
+ strcpy( newval, val );
+ pch = strchr( value, DSGW_NTDOMAINID_SEP );
+ if( pch )
+ {
+ strcat( newval, pch );
+ return( newval );
+ }
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ldap/clients/dsgw/dosearch.c b/ldap/clients/dsgw/dosearch.c
new file mode 100644
index 00000000..01afe6c9
--- /dev/null
+++ b/ldap/clients/dsgw/dosearch.c
@@ -0,0 +1,352 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * dosearch.c -- CGI search handler -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+
+static void get_request(char* hostport, char *dn, char *ldapquery);
+static void post_request();
+
+
+int main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+ int reqmethod;
+ char *qs = NULL;
+ char *dn = NULL;
+ char *hostport = NULL;
+ char *ldapquery = NULL;
+#ifndef __LP64__
+#ifdef HPUX
+ /* call the static constructors in libnls */
+ _main();
+#endif
+#endif
+ /*
+ * Parse out the GET args, if any. See the comments under
+ * get_request for an explanation of what's going on here
+ */
+ if (( qs = getenv( "QUERY_STRING" )) != NULL && *qs != '\0' ) {
+ /* parse the query string: */
+ auto char *p, *iter = NULL;
+ qs = dsgw_ch_strdup( qs );
+
+ for ( p = ldap_utf8strtok_r( qs, "&", &iter ); p != NULL;
+ p = ldap_utf8strtok_r( NULL, "&", &iter )) {
+
+ /*
+ * Get the conf file name. It'll be translated
+ * into /dsgw/context/CONTEXT.conf if
+ * CONTEXT is all alphanumeric (no slahes,
+ * or dots). CONTEXT is passed into the cgi.
+ * if context=CONTEXT is not there, or PATH_INFO
+ * was used, then use dsgw.conf
+ */
+ if ( !strncasecmp( p, "context=", 8 )) {
+ context = dsgw_ch_strdup( p + 8 );
+ dsgw_form_unescape( context );
+ continue;
+ }
+
+ if ( !strncasecmp( p, "hp=", 3 )) {
+ hostport = dsgw_ch_strdup( p + 3 );
+ dsgw_form_unescape( hostport );
+ continue;
+ }
+
+ if ( !strncasecmp( p, "ldq=", 4 )) {
+ ldapquery = dsgw_ch_strdup( p + 4 );
+ dsgw_form_unescape( ldapquery );
+ continue;
+ }
+
+ if ( !strncasecmp( p, "dn=", 3 )) {
+ dn = dsgw_ch_strdup( p + 3 );
+ dsgw_form_unescape( dn );
+ continue;
+ }
+
+ /*
+ * If it doesn't match any of the above, then
+ * tack it onto the end of ldapquery.
+ */
+ if (ldapquery != NULL) {
+ ldapquery = dsgw_ch_realloc(ldapquery, sizeof(char *) * (strlen(ldapquery) + strlen(p) + 2));
+ sprintf( ldapquery, "%s&%s", ldapquery, p );
+ }
+ }
+
+ free( qs ); qs = NULL;
+ }
+
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_POST | DSGW_METHOD_GET );
+
+ /*
+ * Note: we don't call dsgw_send_header() here like we usually do because
+ * on a GET we may be asked to return a MIME type other than the default
+ * of text/html. For GET requests, we send the headers inside
+ * ldaputil.c:dsgw_ldapurl_search(). For POST requests, we send them
+ * below in post_request().
+ */
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ if ( reqmethod == DSGW_METHOD_GET ) {
+ get_request(hostport, dn, ldapquery);
+ } else {
+ post_request();
+ }
+
+ exit( 0 );
+}
+
+
+static void
+get_request(char* hostport, char *dn, char *ldapquery)
+{
+ int urllen = 0;
+ int argslen = 0;
+ char *p = NULL;
+ char *ldapurl = NULL;
+
+ /*
+ * The following comment is kept here only as a reminder of the past.
+ * It is no longer relevant. See the next comment. - RJP
+ *
+ * On a GET request, we do an LDAP URL search (which will just display
+ * a single entry if all that is included is "host:port/DN").
+ * The HTTP URL should be:
+ * .../dosearch[/host[:port]][?[dn=baseDN&][LDAPquery]]
+ * This will be converted to the LDAP URL:
+ * ldap://[host[:port]]/[baseDN][?LDAPquery]
+ *
+ * For compatibility with prior versions, the HTTP URL may be:
+ * .../dosearch/host[:port]/[baseDN][?LDAPquery]
+ * In this case, the host:port is required, since PATH_INFO can't
+ * start with a '/' (web server sees that as a different program).
+ * This older HTTP URL format is deprecated, because PATH_INFO is
+ * not 8-bit clean on Japanese Windows NT.
+ */
+
+ /*
+ * The only form supported now is:
+ * .../dosearch?context=BLAH[&hp=host[:port]][&dn=baseDN][&ldq=LDAPquery]]
+ * -RJP
+ */
+ argslen = 0;
+
+ /* get the length of all the args (dn, hostport, ldapquery)*/
+ if (hostport != NULL) {
+ argslen += strlen(hostport);
+ }
+
+ if (dn != NULL) {
+ argslen += strlen(dn);
+ }
+
+ if (ldapquery != NULL) {
+ argslen += strlen(ldapquery);
+ }
+
+ /* If nothing was supplied, exit*/
+ if ( argslen == 0 ) {
+ dsgw_error( DSGW_ERR_MISSINGINPUT, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ /* Malloc the ldapurl*/
+ urllen = LDAP_URL_PREFIX_LEN + argslen + 3;
+ p = ldapurl = (char *)dsgw_ch_malloc( urllen );
+
+ /*Slap on ldap:// */
+ strcpy( p, LDAP_URL_PREFIX );
+ p += LDAP_URL_PREFIX_LEN;
+
+ /*Slap on host:port if there is one*/
+ if ( hostport != NULL ) {
+ strcpy( p, hostport );
+ }
+
+ strcat( ldapurl, "/" );
+
+ /*Slap on /dn, if there is a dn */
+ if ( dn != NULL ) {
+ strcat( ldapurl, dn );
+ }
+
+ /*Slap on ?ldapquery */
+ if ( ldapquery != NULL ) {
+ sprintf( ldapurl + strlen( ldapurl ), "?%s", ldapquery );
+ }
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "get_request: processing LDAP URL \"%s\"\n", ldapurl );
+#endif
+ dsgw_ldapurl_search( NULL, ldapurl);
+}
+
+
+static void
+post_request()
+{
+ char *modestr, *searchstring, *type, *base;
+ LDAP *ld;
+ LDAPFiltDesc *lfdp;
+ struct ldap_searchobj *solistp, *sop;
+ int authmode, mode, options;
+
+ dsgw_send_header();
+
+ options = 0;
+ modestr = dsgw_get_cgi_var( "mode", DSGW_CGIVAR_REQUIRED );
+ searchstring = dsgw_get_cgi_var( "searchstring", DSGW_CGIVAR_OPTIONAL );
+ dsgw_remove_leading_and_trailing_spaces( &searchstring );
+#ifdef DSGW_DEBUG
+ if (searchstring) {
+ dsgw_log ("searchstring=\"%s\"\n", searchstring);
+ } else {
+ dsgw_log ("searchstring=NULL");
+ }
+#endif
+
+ authmode = 0;
+ if ( strcasecmp( modestr, DSGW_SRCHMODE_AUTH ) == 0 ) {
+ /*
+ * treat authenticate as a variant of the smart search mode
+ */
+ authmode = 1;
+ mode = DSGW_SRCHMODE_SMART_ID;
+ options |= DSGW_DISPLAY_OPT_AUTH;
+ } else if ( strcasecmp( modestr, DSGW_SRCHMODE_SMART ) == 0 ) {
+ mode = DSGW_SRCHMODE_SMART_ID;
+ } else if ( strcasecmp( modestr, DSGW_SRCHMODE_COMPLEX ) == 0 ) {
+ mode = DSGW_SRCHMODE_COMPLEX_ID;
+ } else if ( strcasecmp( modestr, DSGW_SRCHMODE_PATTERN ) == 0 ) {
+ mode = DSGW_SRCHMODE_PATTERN_ID;
+ } else {
+ dsgw_error( DSGW_ERR_SEARCHMODE, modestr, 0, 0, NULL );
+ }
+
+ if ( mode != DSGW_SRCHMODE_PATTERN_ID
+ && ( searchstring == NULL || *searchstring == '\0' )) {
+ dsgw_error( DSGW_ERR_NOSEARCHSTRING, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if (( type = dsgw_get_cgi_var( "type", authmode ? DSGW_CGIVAR_OPTIONAL :
+ DSGW_CGIVAR_REQUIRED )) == NULL ) {
+ type = DSGW_SRCHTYPE_AUTH;
+ }
+
+ if (( base = dsgw_get_cgi_var( "base", DSGW_CGIVAR_OPTIONAL )) == NULL ) {
+ base = gc->gc_ldapsearchbase;
+ }
+
+ /* check for options (carried in boolean CGI variables) */
+ if ( dsgw_get_boolean_var( "listifone", DSGW_CGIVAR_OPTIONAL, 0 )) {
+ options |= DSGW_DISPLAY_OPT_LIST_IF_ONE;
+ }
+
+ if ( dsgw_get_boolean_var( "editable", DSGW_CGIVAR_OPTIONAL, 0 )) {
+ options |= DSGW_DISPLAY_OPT_EDITABLE;
+ }
+
+ if ( dsgw_get_boolean_var( "link2edit", DSGW_CGIVAR_OPTIONAL, 0 )) {
+ options |= DSGW_DISPLAY_OPT_LINK2EDIT;
+ }
+
+ if ( dsgw_get_boolean_var( "dnlist_js", DSGW_CGIVAR_OPTIONAL, 0 )) {
+ options |= DSGW_DISPLAY_OPT_DNLIST_JS;
+ }
+
+ (void) dsgw_init_ldap( &ld, &lfdp, ( authmode == 1 ) ? 1 : 0, 0);
+
+ if ( mode != DSGW_SRCHMODE_PATTERN_ID ) {
+ dsgw_init_searchprefs( &solistp );
+
+ if (( sop = dsgw_type2searchobj( solistp, type )) == NULL ) {
+ ldap_unbind( ld );
+ dsgw_error( DSGW_ERR_UNKSRCHTYPE, type, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ }
+
+ switch( mode ) {
+ case DSGW_SRCHMODE_SMART_ID:
+ /*
+ * smart search mode -- try to do the right kind of search for the
+ * client based on what the user entered in the search box
+ */
+ dsgw_smart_search( ld, sop, lfdp, base, searchstring, options );
+ break;
+
+ case DSGW_SRCHMODE_COMPLEX_ID: {
+ /*
+ * complex search mode -- construct a specific filter based on
+ * user's form selections
+ */
+ int scope;
+ char *attrlabel, *matchprompt;
+ struct ldap_searchattr *sap;
+ struct ldap_searchmatch *smp;
+
+ attrlabel = dsgw_get_cgi_var( "attr", DSGW_CGIVAR_REQUIRED );
+ if (( sap = dsgw_label2searchattr( sop, attrlabel )) == NULL ) {
+ ldap_unbind( ld );
+ dsgw_error( DSGW_ERR_UNKATTRLABEL, attrlabel, DSGW_ERROPT_EXIT,
+ 0, NULL );
+ }
+
+ matchprompt = dsgw_get_cgi_var( "match", DSGW_CGIVAR_REQUIRED );
+ if (( smp = dsgw_prompt2searchmatch( sop, matchprompt )) == NULL ) {
+ ldap_unbind( ld );
+ dsgw_error( DSGW_ERR_UNKMATCHPROMPT, matchprompt,
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ scope = dsgw_get_int_var( "scope", DSGW_CGIVAR_OPTIONAL,
+ sop->so_defaultscope );
+ dsgw_pattern_search( ld, sop->so_objtypeprompt,
+ sap->sa_attrlabel, smp->sm_matchprompt, searchstring,
+ smp->sm_filter, sop->so_filterprefix, NULL, sap->sa_attr,
+ base, scope, searchstring, options );
+ }
+ break;
+
+ case DSGW_SRCHMODE_PATTERN_ID: {
+ /*
+ * pattern-based search mode (no searchprefs or filter file used)
+ */
+ char *attr, *pattern, *prefix, *suffix, *searchdesc;
+ int scope;
+
+ attr = dsgw_get_cgi_var( "attr", DSGW_CGIVAR_REQUIRED );
+ pattern = dsgw_get_cgi_var( "filterpattern", DSGW_CGIVAR_REQUIRED );
+ prefix = dsgw_get_cgi_var( "filterprefix", DSGW_CGIVAR_OPTIONAL );
+ suffix = dsgw_get_cgi_var( "filtersuffix", DSGW_CGIVAR_OPTIONAL );
+ scope = dsgw_get_int_var( "scope", DSGW_CGIVAR_OPTIONAL,
+ LDAP_SCOPE_SUBTREE );
+ options |= DSGW_DISPLAY_OPT_CUSTOM_SEARCHDESC;
+ searchdesc = dsgw_get_cgi_var( "searchdesc", DSGW_CGIVAR_OPTIONAL );
+ dsgw_pattern_search( ld, type, searchdesc, NULL, NULL,
+ pattern, prefix, suffix, attr,
+ base, scope, searchstring, options );
+ }
+ break;
+ }
+
+ ldap_unbind( ld );
+}
diff --git a/ldap/clients/dsgw/dsconfig.c b/ldap/clients/dsgw/dsconfig.c
new file mode 100644
index 00000000..a2ba6858
--- /dev/null
+++ b/ldap/clients/dsgw/dsconfig.c
@@ -0,0 +1,255 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * dsconfig.c -- CGI configuration update handler -- directory gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+
+static void handle_request( int reqmethod );
+static void handle_post();
+
+
+main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+ int reqmethod;
+
+ context= dsgw_ch_strdup("pb");
+ /*CHANGE THIS*/
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_POST | DSGW_METHOD_GET );
+ dsgw_send_header();
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ handle_request( reqmethod );
+
+ exit( 0 );
+}
+
+
+#define DSGWCONFIG_EMPTY_IF_NULL( s ) ( (s) == NULL ? "" : (s) )
+
+
+static void
+handle_request( int reqmethod )
+{
+ FILE *fp;
+ char **argv, *buf, line[ BIG_LINE ];
+ char *checked = " CHECKED ", *qs = NULL;
+ char *str_valuefmt = " VALUE=\"%s\" ";
+ char *int_valuefmt = " VALUE=\"%d\" ";
+ int did_post, argc, switch_mode = 0, is_localdb = 0;
+
+ buf = dsgw_ch_malloc( strlen( progname ) + 6 ); /* room for ".html\0" */
+ sprintf( buf, "%s.html", progname );
+ fp = dsgw_open_html_file( buf, DSGW_ERROPT_EXIT );
+ free( buf );
+ did_post = 0;
+ qs = getenv( "QUERY_STRING" );
+ if (( reqmethod == DSGW_METHOD_GET ) && ( qs != NULL ) &&
+ !strcasecmp( qs, "CHANGE" )) {
+ switch_mode = 1;
+ }
+
+ is_localdb = gc->gc_localdbconf != NULL;
+
+ while ( dsgw_next_html_line( fp, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, dsgw_simple_cond_is_true,
+ NULL )) {
+ if ( dsgw_directive_is( line, DRCT_DS_INLINE_POST_RESULTS )) {
+ if ( !did_post && reqmethod == DSGW_METHOD_POST ) {
+ handle_post();
+ did_post = 1;
+ /* We re-read the config file, so re-calculate is_localdb */
+ is_localdb = ( gc->gc_localdbconf != NULL );
+ }
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_CHECKED_IF_LOCAL )) {
+ if (( is_localdb && !switch_mode ) ||
+ ( !is_localdb && switch_mode )) {
+ dsgw_emits( checked );
+ }
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_CONFIG_INFO )) {
+ dsgw_emits( "<FONT SIZE=\"+1\"><B>" );
+ if (( is_localdb && !switch_mode ) ||
+ ( !is_localdb && switch_mode )) {
+ dsgw_emits( "Local Directory Configuration" );
+ } else {
+ dsgw_emits( "LDAP Directory Server Configuration" );
+ }
+ dsgw_emits( "</FONT>\n" );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_CHECKED_IF_REMOTE )) {
+ if (( !is_localdb && !switch_mode ) ||
+ ( is_localdb && switch_mode )) {
+ dsgw_emits( checked );
+ }
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_HOSTNAME_VALUE ) &&
+ (( !is_localdb && !switch_mode ) ||
+ ( is_localdb && switch_mode ))) {
+ dsgw_emits( "<TR>\n<TD ALIGN=\"right\" NOWRAP><B>Host Name:</B></TD>"
+ "<TD><INPUT TYPE=\"text\" NAME=\"host\"" );
+ dsgw_emitf( str_valuefmt,
+ DSGWCONFIG_EMPTY_IF_NULL( gc->gc_ldapserver ));
+ dsgw_emits( "SIZE=40></TD>\n</TR>\n\n" );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_PORT_VALUE ) &&
+ (( !is_localdb && !switch_mode ) ||
+ ( is_localdb && switch_mode ))) {
+ dsgw_emits( "<TR>\n<TD ALIGN=\"right\" NOWRAP><B>Port:</B></TD>\n"
+ "<TD><INPUT TYPE=\"text\" NAME=\"port\" " );
+ if ( !is_localdb ) {
+ dsgw_emitf( int_valuefmt, gc->gc_ldapport );
+ }
+ dsgw_emits( "SIZE=5></TD>\n</TR>\n\n" );
+
+
+#ifndef DSGW_NO_SSL
+ } else if ( dsgw_directive_is( line, DRCT_DS_SSL_CONFIG_VALUE ) &&
+ (( !is_localdb && !switch_mode ) ||
+ ( is_localdb && switch_mode ))) {
+ dsgw_emits( "<TR>\n<TD ALIGN=\"right\" NOWRAP>\n"
+ "<B>Use Secure<BR>Sockets Layer (SSL)<BR>for "
+ "connections?:</B></TD>\n"
+ "<TD><INPUT TYPE=\"radio\" NAME=\"ssl\" "
+ "VALUE=\"true\" onClick=\"selectedSSL(true)\"" );
+ if ( gc->gc_ldapssl ) {
+ dsgw_emits( checked );
+ }
+ dsgw_HTML_emits( ">Yes" DSGW_UTF8_NBSP "\n<INPUT TYPE=\"radio\" NAME=\"ssl\" "
+ "VALUE=\"false\" onClick=\"selectedSSL(false)\"" );
+ if ( !gc->gc_ldapssl ) {
+ dsgw_emits( checked );
+ }
+ dsgw_emits( ">No\n</TD>\n</TR>\n\n" );
+#endif
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_BASEDN_VALUE )) {
+ dsgw_emits( "<TR>\n<TD ALIGN=\"right\" NOWRAP><B>Base DN" );
+ if (( is_localdb && !switch_mode ) ||
+ ( !is_localdb && switch_mode )) {
+ dsgw_emits( " (optional)" );
+ }
+ dsgw_emits( ":</B></TD>\n<TD><INPUT TYPE=\"text\" "
+ "NAME=\"basedn\" " );
+ dsgw_emitf( str_valuefmt,
+ DSGWCONFIG_EMPTY_IF_NULL( gc->gc_ldapsearchbase ));
+ dsgw_emits( "SIZE=50></TD>\n</TR>\n\n" );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_BINDDN_VALUE ) &&
+ (( !is_localdb && !switch_mode ) ||
+ ( is_localdb && switch_mode ))) {
+ dsgw_emits( "<TR>\n<TD ALIGN=\"right\" NOWRAP><B>"
+ "Bind DN (optional):</B></TD>\n"
+ "<TD><INPUT TYPE=\"text\" NAME=\"binddn\" " );
+ if ( gc->gc_binddn == NULL || strlen( gc->gc_binddn ) == 0 ) {
+ dsgw_emits( "VALUE=\"\"" );
+ } else {
+ dsgw_emitf( "VALUE=\"%s\" ", gc->gc_binddn );
+ }
+ dsgw_emits( " SIZE=50></TD>\n</TR>\n\n" );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_BINDPASSWD_VALUE ) &&
+ (( !is_localdb && !switch_mode ) ||
+ ( is_localdb && switch_mode ))) {
+ dsgw_emits( "<TR>\n<TD ALIGN=\"right\" NOWRAP><B>"
+ "Bind Password (optional):</B></TD>\n"
+ "<TD><INPUT TYPE=\"password\" NAME=\"bindpw\" " );
+ if ( gc->gc_bindpw != NULL && ( strlen( gc->gc_bindpw ) > 0 )) {
+ dsgw_emitf( str_valuefmt, gc->gc_bindpw );
+ }
+ dsgw_emits( "SIZE=20></TD>\n</TR>\n\n" );
+ } else if ( dsgw_directive_is( line, DRCT_DS_NOCERTFILE_WARNING )
+ && ( gc->gc_securitypath == NULL )
+ && !is_localdb && gc->gc_ldapssl && argc > 0 ) {
+ /*
+ * using LDAP over SSL but no CertFile in ns-admin.conf:
+ * show a warning message
+ */
+ dsgw_emits( argv[ 0 ] );
+ }
+ }
+ }
+
+ fclose( fp );
+}
+
+
+static void
+handle_post()
+{
+ char *dirsvctype, *dbhandle;
+ dsgwconfig cfg;
+
+ memset( &cfg, 0, sizeof( cfg ));
+
+ dirsvctype = dsgw_get_cgi_var( "dirsvctype", DSGW_CGIVAR_REQUIRED );
+ dbhandle = dsgw_get_cgi_var( "dbhandle", DSGW_CGIVAR_OPTIONAL );
+ cfg.gc_ldapsearchbase = dsgw_get_cgi_var( "basedn", DSGW_CGIVAR_OPTIONAL );
+
+ if ( strcasecmp( dirsvctype, "local" ) == 0 ) {
+ char *userdb_path;
+
+ if (( userdb_path = get_userdb_dir()) == NULL ) {
+ dsgw_error( DSGW_ERR_USERDB_PATH, NULL, DSGW_ERROPT_INLINE, 0,
+ NULL );
+ return;
+ }
+ cfg.gc_localdbconf = dsgw_ch_malloc( strlen( userdb_path ) +
+ strlen( DSGW_LCACHECONF_PPATH ) +
+ strlen( DSGW_LCACHECONF_FILE ) + 2 );
+ sprintf( cfg.gc_localdbconf, "%s/%s%s", userdb_path,
+ DSGW_LCACHECONF_PPATH, DSGW_LCACHECONF_FILE );
+ } else if ( strcasecmp( dirsvctype, "remote" ) == 0 ) {
+ cfg.gc_ldapserver = dsgw_get_cgi_var( "host", DSGW_CGIVAR_REQUIRED );
+ cfg.gc_ldapport = atoi( dsgw_get_cgi_var( "port",
+ DSGW_CGIVAR_REQUIRED ));
+#ifndef DSGW_NO_SSL
+ cfg.gc_ldapssl =
+ dsgw_get_boolean_var( "ssl", DSGW_CGIVAR_OPTIONAL, 0 );
+#endif
+ cfg.gc_binddn = dsgw_get_escaped_cgi_var( "escapedbinddn", "binddn",
+ DSGW_CGIVAR_OPTIONAL );
+ cfg.gc_bindpw = dsgw_get_cgi_var( "bindpw", DSGW_CGIVAR_OPTIONAL );
+ } else {
+ dsgw_error( DSGW_ERR_SERVICETYPE, dirsvctype, DSGW_ERROPT_INLINE, 0,
+ NULL );
+ return;
+ }
+
+ if ( cfg.gc_ldapsearchbase == NULL ) {
+ cfg.gc_ldapsearchbase = "";
+ }
+
+ if ( dsgw_update_dbswitch( &cfg, dbhandle, DSGW_ERROPT_INLINE ) == 0 ) {
+ /*
+ * success: display status message and then re-read config. file
+ */
+ dsgw_emits( "<FONT SIZE=\"+1\">\n<P>The Directory Service configuration" );
+ if ( dbhandle != NULL ) {
+ dsgw_emitf( " for <B>%s</B>", dbhandle );
+ }
+ dsgw_emits( " has been updated.\n</FONT>\n" );
+
+ (void)dsgw_read_config(NULL);
+ }
+
+ dsgw_emits( "<HR>\n" );
+}
diff --git a/ldap/clients/dsgw/dsexpldif.c b/ldap/clients/dsgw/dsexpldif.c
new file mode 100644
index 00000000..613f65c8
--- /dev/null
+++ b/ldap/clients/dsgw/dsexpldif.c
@@ -0,0 +1,133 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * dsexpldif.c -- CGI configuration update handler -- directory gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "libadmin/libadmin.h"
+static void handle_request( int reqmethod );
+static void handle_post();
+
+static char *ldiffile, *suffix;
+
+main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+ int reqmethod;
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_POST | DSGW_METHOD_GET );
+ dsgw_send_header();
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ handle_request( reqmethod );
+
+ exit( 0 );
+}
+
+
+#define DSGWCONFIG_EMPTY_IF_NULL( s ) ( (s) == NULL ? "" : (s) )
+
+
+static void
+handle_request( int reqmethod )
+{
+ FILE *fp;
+ char **argv, *buf, line[ BIG_LINE ];
+ char *str_valuefmt = " VALUE=\"%s\" ";
+ int did_post, argc;
+
+ buf = dsgw_ch_malloc( strlen( progname ) + 6 ); /* room for ".html\0" */
+ sprintf( buf, "%s.html", progname );
+ fp = dsgw_open_html_file( buf, DSGW_ERROPT_EXIT );
+ free( buf );
+ did_post = 0;
+
+ while ( dsgw_next_html_line( fp, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, dsgw_simple_cond_is_true,
+ NULL )) {
+ if ( dsgw_directive_is( line, DRCT_DS_INLINE_POST_RESULTS )) {
+ if ( !did_post && reqmethod == DSGW_METHOD_POST ) {
+ handle_post();
+ did_post = 1;
+ }
+ } else if ( dsgw_directive_is( line, DS_LDIF_FILE )) {
+ dsgw_emitf( str_valuefmt,
+ DSGWCONFIG_EMPTY_IF_NULL( ldiffile ));
+ } else if ( dsgw_directive_is( line, DS_SUFFIX )) {
+ dsgw_emitf( str_valuefmt,
+ DSGWCONFIG_EMPTY_IF_NULL( suffix ));
+ }
+ }
+ }
+
+ fclose( fp );
+}
+
+
+static void
+handle_post()
+{
+ char cmd[BIG_LINE], path[BIG_LINE];
+ char *userdb_path;
+
+ ldiffile = dsgw_get_cgi_var( "ldif", DSGW_CGIVAR_REQUIRED );
+ suffix = dsgw_get_cgi_var( "suffix", DSGW_CGIVAR_OPTIONAL );
+
+ /* if the schema checking is off, put out a warning message */
+
+ if (( userdb_path = get_userdb_dir()) == NULL ) {
+ dsgw_error( DSGW_ERR_USERDB_PATH, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if (gc->gc_localdbconf == NULL) {
+ /* remote */
+ PR_snprintf (cmd, BIG_LINE,
+ "./%s -b \"%s\" -h %s -p %d \"objectclass=*\" > %s 2> %s",
+ DSGW_LDAPSEARCH, gc->gc_ldapsearchbase, gc->gc_ldapserver,
+ gc->gc_ldapport, ldiffile, DSGW_NULL_DEVICE);
+ }
+ else {
+ /* local database */
+ PR_snprintf (cmd, BIG_LINE,
+ "./%s -b \"\" -C %s \"objectclass=*\" > %s 2> %s",
+ DSGW_LDAPSEARCH, gc->gc_localdbconf, ldiffile, DSGW_NULL_DEVICE);
+ }
+ PR_snprintf (path, BIG_LINE, "%s%s", userdb_path, DSGW_TOOLSDIR);
+ chdir (path);
+
+ fflush (stdout);
+ if (system (cmd) == 0){
+
+ /* if local database and suffix is not null, append suffix to
+ appropriate attributes. */
+
+ if (( gc->gc_localdbconf != NULL) && (suffix != NULL )) {
+ app_suffix (ldiffile, suffix);
+ }
+ /*
+ * success: display status message
+ */
+ dsgw_emits( "<FONT SIZE=\"+1\">\n<P>The ldif file has been created.\n</FONT>\n" );
+ }
+ else {
+ dsgw_emits( "<FONT SIZE=\"+1\">\n<P>The ldif file could not be created.\n</FONT>\n" );
+ }
+
+ dsgw_emits( "<HR>\n" );
+}
+
diff --git a/ldap/clients/dsgw/dsgw.h b/ldap/clients/dsgw/dsgw.h
new file mode 100644
index 00000000..909ca833
--- /dev/null
+++ b/ldap/clients/dsgw/dsgw.h
@@ -0,0 +1,1053 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * dsgw.h -- defines for HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#if !defined( DSGW_NO_SSL ) && !defined( NET_SSL )
+#define DSGW_NO_SSL
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#ifdef LINUX
+#include <sys/param.h>
+#endif
+#include <ldap.h>
+#include <litekey.h>
+#include <ssl.h>
+#ifndef DSGW_NO_SSL
+#include <ldap_ssl.h>
+#endif
+#include "../../include/srchpref.h"
+
+#if defined( XP_WIN32 )
+#define util_strcasecmp strcasecomp
+#define util_strncasecmp strncasecomp
+
+#include "base/systems.h"
+#include "proto-ntutil.h"
+
+#endif
+
+#include <prprf.h>
+
+#ifdef AIXV4
+#include <strings.h>
+#endif /* AIXV4 */
+
+#include "base/util.h"
+#include "libadmin/libadmin.h"
+#include "i18n.h"
+
+#include <unicode/ucnv.h>
+#include <unicode/ucol.h>
+#include <unicode/ustring.h>
+
+#if defined( XP_WIN32 )
+#define DSGW_PATHSEP_CHAR '\\'
+#define DSGW_PATHSEP_STR "\\"
+#define DSGW_NULL_DEVICE "nul:"
+#define DSGW_DELETE_CMD "del /Q"
+#else
+#define DSGW_PATHSEP_CHAR '/'
+#define DSGW_PATHSEP_STR "/"
+#define DSGW_NULL_DEVICE "/dev/null"
+#define DSGW_DELETE_CMD "rm"
+#endif
+
+#define MSIE40_DEFAULT_CHARSET "iso-8859-1,*,utf-8"
+
+/* Used to name the converter used to convert from the users charset to UTF8 */
+#define UNICODE_ENCODING_UTF_8 "UTF-8"
+#define ISO_8859_1_ENCODING "ISO_8859-1"
+
+extern char *context ;
+extern char *langwich; /* The language chosen by libsi18n. */
+extern char *countri; /* The language chosen by libsi18n. */
+
+/*
+ * define DSGW_DEBUG to cause extensive debugging output to be written
+ * to /tmp/CGINAME and CGI's output written to /tmp/CGINAME.out
+ */
+/* #define DSGW_DEBUG */ /* turn on debugging output */
+
+#define DSGW_UTF8_NBSP "\302\240" /* u00A8, in UTF-8 */
+
+/*
+ * XXX the next group of #defines assume that HTTP server has cd'd to
+ * our CGI dir.
+ */
+#define SERVER_ROOT_PATH "../../.."
+#define DSGW_CONFIGDIR_HTTP "../config/"
+#define DSGW_CONFIGDIR_ADMSERV "../config/"
+/*#define DSGW_CONFIGDIR_ADMSERV SERVER_ROOT_PATH "/admin-serv/config/"*/
+#define DSGW_DBSWITCH_FILE "dbswitch.conf"
+#define DSGW_DBSWITCH_TMPFILE "dbswitch.tmp"
+#define DSGW_TMPLDIR_HTTP "../config/"
+#define DSGW_TMPLDIR_ADMSERV "../html/"
+#define DSGW_DOCDIR_HTTP "../html"
+#define DSGW_CONTEXTDIR_HTTP "../context/"
+#define DSGW_HTMLDIR "../html"
+#define DSGW_MANROOT SERVER_ROOT_PATH "/manual/"
+#define DSGW_MANUALSHORTCUT ".MANUAL"
+#define DSGW_MANUALSHORTCUT_LEN 7
+#define DSGW_ADMSERV_BINDIR "/admin-serv/bin/"
+#define DSGW_USER_ADM_BINDIR "/user-environment/bin/"
+#define DSGW_LCACHECONF_PPATH "ldap/config/" /* partial path from /userdb */
+#define DSGW_LCACHECONF_FILE "lcache.conf"
+#define DSGW_TOOLSDIR "/ldap/tools"
+#define DSGW_LDAPSEARCH "ldapsearch"
+#define DSGW_LDAPMODIFY "ldapmodify"
+
+#define DSGW_SEARCHPREFSFILE "dsgwsearchprefs.conf"
+#define DSGW_FILTERFILE "dsgwfilter.conf"
+#define DSGW_CONFIGFILE "dsgw.conf"
+#define DSGW_DEFSECURITYPATH "../ssl"
+
+#define DSGW_CONFIG_LISTPREFIX "list-"
+#define DSGW_CONFIG_DISPLAYPREFIX "display-"
+#define DSGW_CONFIG_EDITPREFIX "edit-"
+#define DSGW_CONFIG_ADDPREFIX "add-"
+
+#define DSGW_SRCHMODE_SMART "smart"
+#define DSGW_SRCHMODE_SMART_ID 1
+#define DSGW_SRCHMODE_COMPLEX "complex"
+#define DSGW_SRCHMODE_COMPLEX_ID 2
+#define DSGW_SRCHMODE_PATTERN "pattern"
+#define DSGW_SRCHMODE_PATTERN_ID 3
+#define DSGW_SRCHMODE_AUTH "auth"
+#define DSGW_SRCHMODE_AUTH_ID 4
+
+#define DSGW_SRCHTYPE_AUTH "auth"
+
+#define LDAP_URL_PREFIX "ldap://"
+#define LDAP_URL_PREFIX_LEN 7
+#define LDAPDB_URL_PREFIX "ldapdb://"
+#define LDAPDB_URL_PREFIX_LEN 9
+
+/* attribute types */
+#define DSGW_ATTRTYPE_OBJECTCLASS "objectClass"
+#define DSGW_ATTRTYPE_HASUBORDINATES "hasSubordinates"
+#define DSGW_ATTRTYPE_USERPASSWORD "userPassword"
+
+#define DSGW_ATTRTYPE_NTUSERDOMAINID "nTUserDomainId"
+#define DSGW_ATTRTYPE_USERID "uid"
+
+#define DSGW_OC_NTUSER "ntuser"
+
+#define DSGW_ATTRTYPE_NTGROUPDOMAINID "nTGroupDomainId"
+#define DSGW_ATTRTYPE_NTGROUPNAME "nTGroupName"
+#define DSGW_ATTRTYPE_AIMSTATUSTEXT "nsaimstatustext"
+
+#if defined( XP_WIN32 )
+#include <lmaccess.h>
+#else
+/*
+ * For Gateway's running on UNIX Platforms.
+ * These are all defined in <lmaccess.h> on Win32.
+ */
+
+/*
+ * Special Values and Constants - User
+ */
+
+/*
+ * Privilege levels (USER_INFO_X field usriX_priv (X = 0/1)).
+ */
+
+#define USER_PRIV_MASK 0x3
+#define USER_PRIV_GUEST 0
+#define USER_PRIV_USER 1
+#define USER_PRIV_ADMIN 2
+
+/*
+ * Bit masks for field usriX_flags of USER_INFO_X (X = 0/1).
+ */
+
+#define UF_SCRIPT 0x0001
+#define UF_ACCOUNTDISABLE 0x0002
+#define UF_HOMEDIR_REQUIRED 0x0008
+#define UF_LOCKOUT 0x0010
+#define UF_PASSWD_NOTREQD 0x0020
+#define UF_PASSWD_CANT_CHANGE 0x0040
+
+/*
+ * Account type bits as part of usri_flags.
+ */
+
+#define UF_TEMP_DUPLICATE_ACCOUNT 0x0100
+#define UF_NORMAL_ACCOUNT 0x0200
+#define UF_INTERDOMAIN_TRUST_ACCOUNT 0x0800
+#define UF_WORKSTATION_TRUST_ACCOUNT 0x1000
+#define UF_SERVER_TRUST_ACCOUNT 0x2000
+
+#define UF_MACHINE_ACCOUNT_MASK ( UF_INTERDOMAIN_TRUST_ACCOUNT | \
+ UF_WORKSTATION_TRUST_ACCOUNT | \
+ UF_SERVER_TRUST_ACCOUNT )
+
+#define UF_ACCOUNT_TYPE_MASK ( \
+ UF_TEMP_DUPLICATE_ACCOUNT | \
+ UF_NORMAL_ACCOUNT | \
+ UF_INTERDOMAIN_TRUST_ACCOUNT | \
+ UF_WORKSTATION_TRUST_ACCOUNT | \
+ UF_SERVER_TRUST_ACCOUNT \
+ )
+
+#define UF_DONT_EXPIRE_PASSWD 0x10000
+
+
+#define UF_SETTABLE_BITS ( \
+ UF_SCRIPT | \
+ UF_ACCOUNTDISABLE | \
+ UF_LOCKOUT | \
+ UF_HOMEDIR_REQUIRED | \
+ UF_PASSWD_NOTREQD | \
+ UF_PASSWD_CANT_CHANGE | \
+ UF_ACCOUNT_TYPE_MASK | \
+ UF_DONT_EXPIRE_PASSWD \
+ )
+
+/*
+ * Bit masks for field usri2_auth_flags of USER_INFO_2.
+ */
+
+#define AF_OP_PRINT 0x1
+#define AF_OP_COMM 0x2
+#define AF_OP_SERVER 0x4
+#define AF_OP_ACCOUNTS 0x8
+#define AF_SETTABLE_BITS (AF_OP_PRINT | AF_OP_COMM | \
+ AF_OP_SERVER | AF_OP_ACCOUNTS)
+
+#endif /* XP_WIN32 */
+
+#define MAX_NTUSERID_LEN 20
+
+/* Types of privs in usri3_priv of struct USER_INFO_3 */
+#define DSGW_NT_UP_GUEST "Guest"
+#define DSGW_NT_UP_USER "User"
+#define DSGW_NT_UP_ADMIN "Admin"
+
+/* Meaning of flags in usri3_flags of struct USER_INFO_3 */
+#define DSGW_NT_UF_SCRIPT "Logon Script Executed"
+#define DSGW_NT_UF_ACCOUNT_DISABLED "Account Disabled"
+#define DSGW_NT_UF_HOMEDIR_REQD "Home Directory Required"
+#define DSGW_NT_UF_PASSWD_NOTREQD "Password Not Required"
+#define DSGW_NT_UF_PASSWD_CANT_CHANGE "User Cannot Change Password"
+#define DSGW_NT_UF_LOCKOUT "Account Locked Out"
+#define DSGW_NT_UF_DONT_EXPIRE_PASSWORD "Password Never Expires"
+
+#define DSGW_NT_UF_NORMAL_ACCOUNT "Default Account Type"
+#define DSGW_NT_UF_TEMP_DUPLICATE_ACCOUNT "Temporary Account Type"
+#define DSGW_NT_UF_TEMP_WRKSTN_TRUST_ACCOUNT "Workstation Account Type"
+#define DSGW_NT_UF_TEMP_SERVER_TRUST_ACCOUNT "Server Account Type"
+#define DSGW_NT_UF_TEMP_INTERDOMAIN_TRUST_ACCOUNT "Interdomain Trust Account Type"
+
+#define DSGW_NT_AF_OP_PRINT "Print Operator"
+#define DSGW_NT_AF_OP_COMM "Backup Operator"
+#define DSGW_NT_AF_OP_SERVER "Server Operator"
+#define DSGW_NT_AF_OP_ACCOUNTS "Accounts Operator"
+
+/* HTTP request methods flags */
+#define DSGW_METHOD_GET 0x01
+#define DSGW_METHOD_POST 0x02
+
+/* URL prefixes specific to our gateway */
+#define DSGW_URLPREFIX_MAIN_HTTP "lang?file="
+#define DSGW_URLPREFIX_MAIN_ADMSERV ""
+/*#define DSGW_URLPREFIX_CGI_HTTP "../bin/"*/
+#define DSGW_URLPREFIX_CGI_HTTP ""
+#define DSGW_URLPREFIX_CGI_ADMSERV ""
+#define DSGW_URLPREFIX_BIN "/clients/dsgw/bin/"
+
+#define DSGW_URLPREFIX_MAIN DSGW_URLPREFIX_MAIN_HTTP
+
+#define DSGW_CGINAME_DOSEARCH "dosearch"
+#define DSGW_CGINAME_BROWSE "browse"
+#define DSGW_CGINAME_SEARCH "search"
+#define DSGW_CGINAME_CSEARCH "csearch"
+#define DSGW_CGINAME_AUTH "auth"
+#define DSGW_CGINAME_EDIT "edit"
+#define DSGW_CGINAME_DOMODIFY "domodify"
+#define DSGW_CGINAME_TUTOR "tutor"
+#define DSGW_CGINAME_DNEDIT "dnedit"
+#define DSGW_CGINAME_LANG "lang"
+
+/* definitions for modes - they type of operation we are performing */
+/* These definitions need to match, one-for-one, the DSGW_CGINAMEs */
+#define DSGW_MODE_DOSEARCH 1
+#define DSGW_CGINUM_DOSEARCH DSGW_MODE_DOSEARCH
+#define DSGW_MODE_BROWSE 2
+#define DSGW_CGINUM_BROWSE DSGW_MODE_BROWSE
+#define DSGW_MODE_SEARCH 3
+#define DSGW_CGINUM_SEARCH DSGW_MODE_SEARCH
+#define DSGW_MODE_CSEARCH 4
+#define DSGW_CGINUM_CSEARCH DSGW_MODE_CSEARCH
+#define DSGW_MODE_AUTH 5
+#define DSGW_CGINUM_AUTH DSGW_MODE_AUTH
+#define DSGW_MODE_EDIT 6
+#define DSGW_CGINUM_EDIT DSGW_MODE_EDIT
+#define DSGW_MODE_DOMODIFY 7
+#define DSGW_CGINUM_DOMODIFY DSGW_MODE_DOMODIFY
+#define DSGW_MODE_TUTOR 8
+#define DSGW_CGINUM_TUTOR DSGW_MODE_TUTOR
+#define DSGW_MODE_DNEDIT 9
+#define DSGW_CGINUM_DNEDIT DSGW_MODE_DNEDIT
+#define DSGW_MODE_LANG 10
+#define DSGW_CGINUM_LANG DSGW_MODE_LANG
+#define DSGW_MODE_LASTMODE DSGW_MODE_LANG
+#define DSGW_MODE_NUMMODES DSGW_MODE_LASTMODE
+#define DSGW_MODE_UNKNOWN 99
+
+/* error codes -- messages are in dsgw_errs[] array in error.c */
+#define DSGW_ERR_BADMETHOD 1
+#define DSGW_ERR_BADFORMDATA 2
+#define DSGW_ERR_NOMEMORY 3
+#define DSGW_ERR_MISSINGINPUT 4
+#define DSGW_ERR_BADFILEPATH 5
+#define DSGW_ERR_BADCONFIG 6
+#define DSGW_ERR_LDAPINIT 7
+#define DSGW_ERR_LDAPGENERAL 8
+#define DSGW_ERR_UNKSRCHTYPE 9
+#define DSGW_ERR_NOFILTERS 10
+#define DSGW_ERR_OPENHTMLFILE 11
+#define DSGW_ERR_SEARCHMODE 12
+#define DSGW_ERR_UNKATTRLABEL 13
+#define DSGW_ERR_UNKMATCHPROMPT 14
+#define DSGW_ERR_LDAPURL_NODN 15
+#define DSGW_ERR_LDAPURL_BADSCOPE 16
+#define DSGW_ERR_LDAPURL_NOTLDAP 17
+#define DSGW_ERR_LDAPURL_BAD 18
+#define DSGW_ERR_INTERNAL 19
+#define DSGW_ERR_OPENDIR 20
+#define DSGW_ERR_WRITEINDEXFILE 21
+#define DSGW_ERR_OPENINDEXFILE 22
+#define DSGW_ERR_SSLINIT 23
+#define DSGW_ERR_NO_MGRDN 24
+/*
+ * Note: do not add more error codes here! The cookie error codes use the
+ * same error code space as all the others. Go to the end of the "more error
+ * codes" section and add new error codes there.
+ */
+
+/* Cookie db routines - error codes */
+#define DSGW_CKDB_KEY_NOT_PRESENT 25
+#define DSGW_CKDB_DBERROR 26
+#define DSGW_CKDB_EXPIRED 27
+#define DSGW_CKDB_RNDSTRFAIL 28
+#define DSGW_CKDB_NODN 29
+#define DSGW_CKDB_CANTOPEN 30
+#define DSGW_CKDB_CANTAPPEND 31
+
+/* more error codes */
+#define DSGW_ERR_NOSECPATH 32
+#define DSGW_ERR_NOSEARCHSTRING 33
+#define DSGW_ERR_CONFIGTOOMANYARGS 34
+#define DSGW_ERR_ADMSERV_CREDFAIL 35
+#define DSGW_ERR_LDAPDBURL_NODN 36
+#define DSGW_ERR_LDAPDBURL_NOTLDAPDB 37
+#define DSGW_ERR_LDAPDBURL_BAD 38
+#define DSGW_ERR_LCACHEINIT 39
+#define DSGW_ERR_WSAINIT 40
+#define DSGW_ERR_SERVICETYPE 41
+#define DSGW_ERR_DBCONF 42
+#define DSGW_ERR_USERDB_PATH 43
+#define DSGW_ERR_UPDATE_DBSWITCH 44
+#define DSGW_ERR_ENTRY_NOT_FOUND 45
+#define DSGW_ERR_DB_ERASE 46
+#define DSGW_ERR_LOCALDB_PERMISSION_DENIED 47
+#define DSGW_ERR_NOATTRVALUE 48
+#define DSGW_ERR_USERID_REQUIRED 49
+#define DSGW_ERR_DOMAINID_NOTUNIQUE 50
+#define DSGW_ERR_USERID_DOMAINID_REQUIRED 51
+#define DSGW_ERR_USERID_MAXLEN_EXCEEDED 52
+#define DSGW_ERR_CHARSET_NOT_SUPPORTED 53
+
+/* Return codes from dsgw_init_ldap() */
+#define DSGW_BOUND_ASUSER 1
+#define DSGW_BOUND_ANONYMOUS 2
+
+/* NT Domain Id seperator */
+#define DSGW_NTDOMAINID_SEP ':'
+
+/* Cookie names */
+#define DSGW_BROWSESBCKNAME "nsdsgwbrowseSB"
+#define DSGW_SEARCHSBCKNAME "nsdsgwsearchSB"
+#define DSGW_AUTHCKNAME "nsdsgwauth"
+#define DSGW_CKHDR "Set-cookie: "
+#define DSGW_EXPSTR "expires="
+#define DSGW_UNAUTHSTR "[unauthenticated]"
+
+/* Name of cookie database - context will be appended to "cookies" for multiple GW's*/
+#define DSGW_COOKIEDB_FNAME SERVER_ROOT_PATH "/bin/slapd/authck/cookies"
+
+/* Default lifetime of authentication cookies (in seconds) */
+#define DSGW_DEF_AUTH_LIFETIME ( 60 * 60 ) /* one hour */
+
+#define DSGW_SECS_PER_DAY ( 60 * 60 * 24 ) /* one day */
+
+#define DSGW_CKPURGEINTERVAL ( 60 * 10 ) /* Ten minutes */
+
+#define DSGW_MODIFY_GRACEPERIOD ( 60 * 5 ) /* Five minutes */
+
+/* String used as DN in auth CGI to indicate "I want to bind as the root dn" */
+#define MGRDNSTR "MANAGER"
+
+/*
+ * Enum for NT Domain checking
+ */
+typedef enum _LDAPDomainIdStatus {
+ LDAPDomainIdStatus_Unique = 0,
+ LDAPDomainIdStatus_Nonunique = -1,
+ LDAPDomainIdStatus_NullAttr = -2,
+ LDAPDomainIdStatus_NullId = -3
+} LDAPDomainIdStatus;
+
+/*
+ * Structure used to associate LDAP objectClasses with display templates.
+ * These are defined by "template" config. file lines.
+ */
+typedef struct dsgwtmpl {
+ char *dstmpl_name;
+ char **dstmpl_ocvals;
+ struct dsgwtmpl *dstmpl_next;
+} dsgwtmpl;
+
+/*
+ * Structures used to keep track of template sets which are used to support
+ * more than one way to view an entry. These are defined by "tmplset"
+ * config. file lines.
+ */
+typedef struct dsgwview {
+ char *dsview_caption;
+ char *dsview_template;
+ char *dsview_jscript;
+ struct dsgwview *dsview_next;
+} dsgwview;
+
+typedef struct dsgwtmplset {
+ char *dstset_name;
+ dsgwview *dstset_viewlist;
+ int dstset_viewcount;
+ struct dsgwtmplset *dstset_next;
+} dsgwtmplset;
+
+/*
+ * Structure used to hold information about Attribute Value Sets that are
+ * used with DS_ATTRVAL_SET entry display directives. These sets are defined
+ * by "attrvset" config. file lines.
+ */
+typedef struct dsgwavset {
+ char *dsavset_handle;
+ int dsavset_itemcount;
+ char **dsavset_values;
+ char **dsavset_prefixes;
+ char **dsavset_suffixes;
+ struct dsgwavset *dsavset_next;
+} dsgwavset;
+
+/*
+ * Structure used to hold information about file include sets that are used
+ * with INCLUDESET directives. These sets are defined by "includeset" config.
+ * file lines.
+ */
+typedef struct dsgwinclset {
+ char *dsiset_handle;
+ int dsiset_itemcount;
+ char **dsiset_filenames;
+ struct dsgwinclset *dsiset_next;
+} dsgwinclset;
+
+/*
+ * structure used to track locations where new entries can be added
+ * these are created based on the "location" config. file lines
+ */
+typedef struct dsgwloc {
+ char *dsloc_handle; /* short name */
+ char *dsloc_fullname; /* friendly name */
+ char *dsloc_dnsuffix; /* new entry location (a full DN) */
+} dsgwloc;
+
+/*
+ * structure used to track types of new entries that can be added
+ * these are created based on the "newtype" config. file lines
+ */
+typedef struct dsgwnewtype {
+ char *dsnt_template; /* name of add-XXX.html template */
+ char *dsnt_fullname; /* friendly name */
+ char *dsnt_rdnattr; /* attribute used to construct RDN */
+ int *dsnt_locations; /* indexes into gc_locations array */
+ int dsnt_loccount; /* number of dsnt_locations */
+ struct dsgwnewtype *dsnt_next;
+} dsgwnewtype;
+
+/*
+ * Structure used to hold mapping from LDAP attrs. to VCard properties
+ */
+typedef struct dsgwvcprop {
+ char *dsgwvcprop_property; /* VCard property name */
+ char *dsgwvcprop_ldaptype; /* LDAP attribute type */
+ char *dsgwvcprop_ldaptype2; /* only used for "n" prop. */
+ char *dsgwvcprop_syntax; /* cis or mls only please! */
+ struct dsgwvcprop *dsgwvcprop_next;
+} dsgwvcprop;
+
+/* substring substitution structure */
+typedef struct dsgwsubst {
+ char *dsgwsubst_from;
+ char *dsgwsubst_to;
+ char **dsgwsubst_charsets; /* NULL => any charset */
+ struct dsgwsubst *dsgwsubst_next;
+} dsgwsubst;
+
+/* Configuration information structure */
+typedef struct dsgwconfig_t {
+ int gc_admserv; /* non-zero if running under admserv */
+ int gc_enduser; /* if non-zero, running end-user CGI */
+ char *gc_baseurl;
+ char *gc_ldapserver;
+ int gc_ldapport;
+ char *gc_ldapsearchbase;
+ char *gc_rootdn;
+#ifndef DSGW_NO_SSL
+ int gc_ldapssl; /* if non-zero, do LDAP over SSL */
+ char *gc_securitypath;
+#endif
+ int gc_configerr; /* if non-zero, there were cf errs */
+ char *gc_configdir; /* path to our config files */
+ char *gc_tmpldir; /* path to our HTML template files */
+ char *gc_docdir; /* path to the HTML files*/
+ char *gc_gwnametrans; /* The nametrans for the gateway (for FT)*/
+ char *gc_urlpfxmain; /* URL prefix for dsgw main page */
+ char *gc_urlpfxcgi; /* URL prefix for dsgw CGIs */
+ char *gc_configerrstr;
+ char *gc_localdbconf; /* NULL if local DB not being used */
+ /* otherwise - name of localdb conf */
+ char *gc_binddn; /* DN to bind as if user info unknown */
+ char *gc_bindpw; /* passwd to use if user info unknown */
+ float gc_httpversion; /* client's HTTP version */
+ char *gc_charset; /* character set used by CGIs & HTML */
+ char *gc_NLS; /* directory used by libnls */
+ char *gc_ClientLanguage; /* preferred language list */
+ char *gc_AdminLanguage; /* administrator language list */
+ char *gc_DefaultLanguage; /* default language list for either */
+ char **gc_clientIgnoreACharset; /* browsers uses default charset
+ instead of accept-charsets */
+ char *gc_orgcharturl; /* http base url for orgchart*/
+ char *gc_orgchartsearchattr; /* Search attribute the orgchart uses*/
+ int gc_aimpresence; /* enable aim presence*/
+ dsgwtmpl *gc_templates; /* linked list */
+ dsgwnewtype *gc_newentrytypes; /* linked list */
+ dsgwloc *gc_newentrylocs; /* array of structures */
+ int gc_newentryloccount;
+ dsgwtmplset *gc_tmplsets; /* linked list */
+ dsgwavset *gc_avsets; /* linked list */
+ dsgwinclset *gc_includesets; /* linked list */
+ dsgwvcprop *gc_vcardproperties; /* linked list */
+ int gc_httpskeysize; /* if non-zero, HTTPS is being used */
+ int gc_sslrequired;
+ time_t gc_authlifetime; /* lifetime of cookies, in seconds */
+ int gc_authrequired; /* if non-zero, disallow access unless
+ authenticated */
+#define DSGW_SSLREQ_NEVER 0
+#define DSGW_SSLREQ_WHENAUTHENTICATED 1
+#define DSGW_SSLREQ_ALWAYS 2
+ dsgwsubst *gc_changeHTML; /* linked list */
+ dsgwsubst *gc_l10nsets; /* linked list */
+ /*
+ * The following aren't strictly config file options, but are put
+ * into the gc struct.
+ */
+ int gc_mode; /* Mode (CGI being executed) */
+} dsgwconfig;
+
+/*
+ * Structure used to return broken-out ldapdb:// URL info
+ */
+typedef struct ldapdb_url_desc {
+ char *ludb_path;
+ char *ludb_dn;
+} LDAPDBURLDesc;
+
+
+/* template stuff */
+/* The number of templates defined */
+#define MAXTEMPLATE 30
+
+/* The maximum number of variables for a given template */
+#define MAXVARS 4
+
+/* The structure of a directive is fairly simple. You have:
+ *
+ * <!-- NAME var1="val" var2="val" var3="val">
+ *
+ * You _must_ put the values in quotes.
+ */
+
+/* The structure of a template. */
+typedef struct template_s {
+ char *name;
+ char *format;
+} *tmpptr;
+
+#define DIRECTIVE_START "<!-- "
+#define GCONTEXT_DIRECTIVE "<!-- GCONTEXT -->"
+#define DIRECTIVE_END '>'
+
+/* A really big form line */
+#define BIG_LINE 1024
+
+/* struct to track saved lines */
+typedef struct savedlines {
+ int svl_count;
+ int svl_current;
+ char **svl_line;
+} savedlines;
+
+
+typedef struct dsgwtmplinfo {
+ char *dsti_template;
+ int dsti_type;
+#define DSGW_TMPLTYPE_LIST 1
+#define DSGW_TMPLTYPE_DISPLAY 2
+#define DSGW_TMPLTYPE_EDIT 3
+#define DSGW_TMPLTYPE_ADD 4
+ unsigned long dsti_options;
+#define DSGW_DISPLAY_OPT_LIST_IF_ONE 0x00000001
+#define DSGW_DISPLAY_OPT_AUTH 0x00000002
+#define DSGW_DISPLAY_OPT_EDITABLE 0x00000004
+#define DSGW_DISPLAY_OPT_ADDING 0x00000008
+#define DSGW_DISPLAY_OPT_LINK2EDIT 0x00000010
+#define DSGW_DISPLAY_OPT_DNLIST_JS 0x00000020
+#define DSGW_DISPLAY_OPT_CUSTOM_SEARCHDESC 0x00000040
+ char **dsti_attrs;
+ unsigned long *dsti_attrflags;
+#define DSGW_DSTI_ATTR_SEEN 0x00000001
+ char **dsti_attrsonly_attrs;
+ char *dsti_sortbyattr;
+ int dsti_entrycount;
+ char *dsti_search2s;
+ char *dsti_search3s;
+ char *dsti_search4s;
+ char *dsti_searcherror;
+ char *dsti_searchlderrtxt;
+ LDAP *dsti_ld;
+ LDAPMessage *dsti_entry;
+ LDAPMessage *dsti_attrsonly_entry;
+ char *dsti_entrydn;
+ FILE *dsti_fp;
+ char **dsti_rdncomps; /* only set for new entries */
+ savedlines *dsti_preludelines; /* only output once */
+ savedlines *dsti_entrylines; /* output once for each entry */
+} dsgwtmplinfo;
+
+
+/*
+ * HTML template directives that are specific to DSGW
+ * Note that most of these supported only in entrydisplay.c
+ */
+#define DRCT_DS_ENTRYBEGIN "DS_ENTRYBEGIN"
+#define DRCT_DS_ENTRYEND "DS_ENTRYEND"
+#define DRCT_DS_ATTRIBUTE "DS_ATTRIBUTE"
+#define DRCT_DS_ATTRVAL_SET "DS_ATTRVAL_SET"
+#define DRCT_DS_OBJECTCLASS "DS_OBJECTCLASS"
+#define DRCT_DS_SORTENTRIES "DS_SORTENTRIES"
+#define DRCT_DS_SEARCHDESC "DS_SEARCHDESC"
+#define DRCT_DS_POSTEDVALUE "DS_POSTEDVALUE"
+#define DRCT_DS_EDITBUTTON "DS_EDITBUTTON"
+#define DRCT_DS_DELETEBUTTON "DS_DELETEBUTTON"
+#define DRCT_DS_SAVEBUTTON "DS_SAVEBUTTON"
+#define DRCT_DS_RENAMEBUTTON "DS_RENAMEBUTTON"
+#define DRCT_DS_EDITASBUTTON "DS_EDITASBUTTON"
+#define DRCT_DS_NEWPASSWORD "DS_NEWPASSWORD"
+#define DRCT_DS_CONFIRM_NEWPASSWORD "DS_CONFIRM_NEWPASSWORD"
+#define DRCT_DS_OLDPASSWORD "DS_OLDPASSWORD"
+#define DRCT_DS_HELPBUTTON "DS_HELPBUTTON"
+#define DRCT_DS_CLOSEBUTTON "DS_CLOSEBUTTON"
+#define DRCT_DS_BEGIN_ENTRYFORM "DS_BEGIN_ENTRYFORM"
+#define DRCT_DS_END_ENTRYFORM "DS_END_ENTRYFORM"
+#define DRCT_DS_EMIT_BASE_HREF "DS_EMIT_BASE_HREF"
+#define DRCT_DS_DNATTR "DS_DNATTR"
+#define DRCT_DS_DNDESC "DS_DNDESC"
+#define DRCT_DS_DNEDITBUTTON "DS_DNEDITBUTTON"
+#define DRCT_DS_BEGIN_DNSEARCHFORM "DS_BEGIN_DNSEARCHFORM"
+#define DRCT_DS_END_DNSEARCHFORM "DS_END_DNSEARCHFORM"
+#define DRCT_DS_CONFIG_INFO "DS_CONFIG_INFO"
+#define DRCT_DS_GATEWAY_VERSION "DS_GATEWAY_VERSION"
+#define DRCT_DS_VIEW_SWITCHER "DS_VIEW_SWITCHER"
+#define DRCT_DS_STD_COMPLETION_JS "DS_STD_COMPLETION_JS"
+#define DRCT_HEAD "HEAD"
+#define DRCT_DS_ALERT_NOENTRIES "DS_ALERT_NOENTRIES"
+#define DRCT_DS_ORGCHARTLINK "DS_ORGCHARTLINK"
+
+/*
+ * directives supported inside dsgw_parse_line() itself (usable anywhere)
+ * Note that these are in addition to ones in the htmlparse.c templates array
+ */
+#define DRCT_DS_LAST_OP_INFO "DS_LAST_OP_INFO"
+
+/*
+ * directives supported by genscreen
+ */
+#define DRCT_DS_LOCATIONPOPUP "DS_LOCATIONPOPUP"
+
+/*
+ * these next few are supported by dsconfig
+ */
+#define DRCT_DS_INLINE_POST_RESULTS "DS_INLINE_POST_RESULTS"
+#define DRCT_DS_CHECKED_IF_LOCAL "DS_CHECKED_IF_LOCAL"
+#define DRCT_DS_CHECKED_IF_REMOTE "DS_CHECKED_IF_REMOTE"
+#define DRCT_DS_HOSTNAME_VALUE "DS_HOSTNAME_VALUE"
+#define DRCT_DS_PORT_VALUE "DS_PORT_VALUE"
+#define DRCT_DS_CHECKED_IF_SSL "DS_CHECKED_IF_SSL"
+#define DRCT_DS_CHECKED_IF_NOSSL "DS_CHECKED_IF_NOSSL"
+#define DRCT_DS_SSL_CONFIG_VALUE "DS_SSL_CONFIG_VALUE"
+#define DRCT_DS_BASEDN_VALUE "DS_BASEDN_VALUE"
+#define DRCT_DS_BINDDN_VALUE "DS_BINDDN_VALUE"
+#define DRCT_DS_BINDPASSWD_VALUE "DS_BINDPASSWD_VALUE"
+#define DRCT_DS_NOCERTFILE_WARNING "DS_NOCERTFILE_WARNING"
+
+/*
+ * directives supported by dsimpldif
+ */
+#define DS_LDIF_FILE "DS_LDIF_FILE"
+#define DS_CHECKED_IF_ERASE "DS_CHECKED_IF_ERASE"
+#define DS_CHECKED_IF_NOTERASE "DS_CHECKED_IF_NOTERASE"
+#define DS_CHECKED_IF_STOP "DS_CHECKED_IF_STOP"
+#define DS_CHECKED_IF_NOTSTOP "DS_CHECKED_IF_NOTSTOP"
+
+#define DSGW_ARG_BUTTON_LABEL "label"
+#define DSGW_ARG_BUTTON_NAME "name"
+
+/*
+ * directives supported by dsexpldif
+ */
+#define DS_SUFFIX "DS_SUFFIX"
+
+/* conditionals -- replaces "xxx" in <!-- IF xxx --> directives */
+#define DSGW_COND_FOUNDENTRIES "FoundEntries"
+#define DSGW_COND_ADDING "Adding"
+#define DSGW_COND_EDITING "Editing"
+#define DSGW_COND_DISPLAYING "Displaying"
+#define DSGW_COND_BOUND "Bound"
+#define DSGW_COND_BOUNDASTHISENTRY "BoundAsThisEntry"
+#define DSGW_COND_ADMSERV "AdminServer"
+#define DSGW_COND_LOCALDB "DirectoryIsLocalDB"
+#define DSGW_COND_ATTRHASVALUES "AttributeHasValues"
+#define DSGW_COND_ATTRHASTHISVALUE "AttributeHasThisValue"
+#define DSGW_COND_POSTEDFORMVALUE "PostedFormValue"
+#define DSGW_COND_DISPLAYORGCHART "DisplayOrgChart"
+#define DSGW_COND_DISPLAYAIMPRESENCE "DisplayAimPresence"
+
+/* global variables */
+extern char *progname; /* set in dsgwutil.c:dsgw_init() */
+extern char *dsgw_last_op_info; /* set in edit.c and genscreen.c */
+extern char *dsgw_dnattr; /* set in edit.c */
+extern char *dsgw_dndesc; /* set in edit.c */
+extern int http_hdr_sent; /* set in dsgwutil.c:dsgw_send_header() */
+extern char *dsgw_html_body_colors; /* set in htmlparse.c */
+extern int dsgw_NSSInitializedAlready; /* set in cookie.c:dsgw_NSSInit */
+
+/* function prototypes */
+/*
+ * in cgiutil.c
+ */
+int dsgw_post_begin( FILE *in );
+void dsgw_form_unescape( char *str );
+char *dsgw_get_cgi_var( char *varname, int required );
+int dsgw_get_int_var( char *varname, int required, int defval );
+int dsgw_get_boolean_var( char *varname, int required, int defval );
+char *dsgw_get_escaped_cgi_var( char *varname_escaped, char *varname,
+ int required );
+#define DSGW_CGIVAR_OPTIONAL 0
+#define DSGW_CGIVAR_REQUIRED 1
+char *dsgw_next_cgi_var( int *indexp, char **valuep );
+
+/*
+ * in dsgwutil.c:
+ */
+extern dsgwconfig *gc;
+int dsgw_init( int argc, char **argv, int methods_handled );
+int dsgw_simple_cond_is_true( int argc, char **argv, void *arg );
+char *dsgw_file2path( char *prefix, char *filename );
+char *dsgw_file2htmlpath( char *prefix, char *filename );
+void *dsgw_ch_malloc( size_t n );
+void *dsgw_ch_calloc( size_t nelem, size_t elsize );
+void *dsgw_ch_realloc( void *p, size_t n );
+char *dsgw_ch_strdup( const char *s );
+char *dsgw_escape_quotes( char *in );
+char *dsgw_get_translation( char *in );
+void dsgw_send_header();
+void dsgw_add_header( char *line );
+char *dsgw_get_auth_cookie();
+void dsgw_emit_helpbutton( char *topic );
+void dsgw_emit_homebutton();
+char *dsgw_build_urlprefix();
+void dsgw_init_searchprefs( struct ldap_searchobj **solistp );
+void dsgw_addtemplate( dsgwtmpl **tlpp, char *template, int count,
+ char **ocvals );
+dsgwtmpl *dsgw_oc2template( char **ocvals );
+void dsgw_remove_leading_and_trailing_spaces( char **sp );
+int dsgw_parse_cookie( char *cookie, char **rndstr, char **dn );
+char *dsgw_getvp( int cginum );
+#ifdef DSGW_DEBUG
+void dsgw_log( char *fmt, ... );
+void dsgw_logstringarray( char *arrayname, char **strs );
+void dsgw_log_out (const char* s, size_t n);
+#else
+#define dsgw_log_out(s,n) ;
+#endif /* DSGW_DEBUG */
+void dsgw_head_begin();
+void dsgw_quote_emptyFrame();
+void dsgw_password_expired_alert( char *binddn );
+time_t dsgw_current_time();
+time_t dsgw_time_plus_sec (time_t l, long r);
+
+/*
+ * in entrydisplay.c
+ */
+dsgwtmplinfo *dsgw_display_init( int tmpltype, char *template,
+ unsigned long options );
+void dsgw_display_entry( dsgwtmplinfo *tip, LDAP *ld, LDAPMessage *entry,
+ LDAPMessage *attrsonly_entry, char *dn );
+void dsgw_display_done( dsgwtmplinfo *tip );
+char *dsgw_mls_convertlines( char *val, char *sep, int *linesp, int emitlines,
+ int quote_html_specials );
+void dsgw_set_searchdesc( dsgwtmplinfo *tip, char*, char*, char*);
+void dsgw_set_search_result( dsgwtmplinfo *tip, int entrycount,
+ char *searcherror, char *lderrtxt );
+
+/*
+ * in error.c
+ */
+void dsgw_error( int errcode, char *extra, int options, int lderr,
+ char *lderrtxt );
+#define DSGW_ERROPT_EXIT 0x01
+#define DSGW_ERROPT_IGNORE 0x02
+#define DSGW_ERROPT_TERSE 0x04
+#define DSGW_ERROPT_INLINE 0x08
+#define DSGW_ERROPT_DURINGBIND 0x10
+int dsgw_dn2passwd_error( int ckrc, int skipauthwarning );
+char* dsgw_err2string( int err );
+char *dsgw_ldaperr2string( int lderr );
+
+/*
+ * in htmlout.c
+ */
+void dsgw_html_begin( char *title, int titleinbody );
+void dsgw_html_end( void );
+void dsgw_html_href( char *urlprefix, char *url, char *label, char *value,
+ char *extra );
+void dsgw_strcat_escaped( char *s1, const char *s2 );
+char *dsgw_strdup_escaped( const char *s );
+void dsgw_substitute_and_output( char *s, char *tag, char *value, int escape );
+void dsgw_form_begin( const char* name, const char* format, ... );
+char *dsgw_strdup_with_entities( char *s, int *madecopyp );
+void dsgw_HTML_emits( char * );
+void dsgw_emit_cgi_var( int argc, char **argv );
+void dsgw_emit_button( int argc, char **argv, const char* format, ... );
+void dsgw_emit_alertForm();
+void dsgw_emit_alert( const char* frame, const char* windowOptions, const char* fmt, ... );
+void dsgw_emit_confirmForm();
+void dsgw_emit_confirm( const char* frame, const char* yes, const char* no,
+ const char* windowOptions, int enquote, const char* fmt, ... );
+
+/*
+ * in htmlparse.c:
+ */
+typedef int (*condfunc)( int argc, char **argv, void *arg );
+int dsgw_parse_line( char *line_input, int *argc, char ***argv, int parseonly,
+ condfunc conditionalfn, void *condarg );
+char *get_arg_by_name( char *name, int argc, char **argv );
+int dsgw_get_arg_pos_by_name( char *name, int argc, char **argv );
+FILE *dsgw_open_html_file( char *filename, int erropts );
+int dsgw_next_html_line(FILE *f, char *line);
+void dsgw_argv_free( char **argv );
+savedlines *dsgw_savelines_alloc( void );
+void dsgw_savelines_free( savedlines *svlp );
+void dsgw_savelines_save( savedlines *svlp, char *line );
+void dsgw_savelines_rewind( savedlines *svlp );
+char *dsgw_savelines_next( savedlines *svlp );
+int dsgw_directive_is(char *target, char *directive);
+
+/*
+ * in ldaputil.c
+ */
+int dsgw_init_ldap( LDAP **ldp, LDAPFiltDesc **lfdpp, int skipac, int skipauthwarning );
+int dsgw_get_adm_identity( LDAP *ld, char **uidp, char **dnp, char **pwdp,
+ int erropts );
+void dsgw_ldap_error( LDAP *ld, int erropts );
+struct ldap_searchobj *dsgw_type2searchobj( struct ldap_searchobj *solistp,
+ char *type );
+struct ldap_searchattr *dsgw_label2searchattr( struct ldap_searchobj *sop,
+ char *label );
+struct ldap_searchmatch *dsgw_prompt2searchmatch( struct ldap_searchobj *sop,
+ char *prompt );
+void dsgw_smart_search( LDAP *ld, struct ldap_searchobj *sop,
+ LDAPFiltDesc *lfdp, char *base, char *value, unsigned long options );
+void dsgw_pattern_search( LDAP *ld, char *listtmpl,
+ char *searchdesc2, char *searchdesc3, char *searchdesc4,
+ char *filtpattern, char *filtprefix, char *filtsuffix, char *attr,
+ char *base, int scope, char *value, unsigned long options );
+void dsgw_ldapurl_search( LDAP *ld, char *ldapurl );
+void dsgw_read_entry( LDAP *ld, char *dn, char **ocvals, char *tmplname,
+ char **attrs, unsigned long options );
+int dsgw_ldap_entry_exists( LDAP *ld, char *dn, char **matchedp,
+ unsigned long erropts );
+char **dsgw_rdn_values( char *dn );
+char *dsgw_get_binddn( void );
+int dsgw_bound_as_dn( char *dn, int def_answer );
+int dsgw_dn_cmp( char *dn1, char *dn2 );
+int dsgw_is_dnparent( char *dn1, char *dn2 );
+char *dsgw_dn_parent( char *dn );
+void dsgw_emit_location_popup( LDAP *ld, int argc, char **argv, int erropts );
+
+/*
+ * in config.c
+ */
+dsgwconfig *dsgw_read_config();
+int dsgw_update_dbswitch( dsgwconfig *cfgp, char *handle, int erropts );
+int dsgw_valid_docname(char *filename);
+char *dsgw_get_docdir(void) ;
+
+typedef struct scriptrange {
+ unsigned long sr_min;
+ unsigned long sr_max;
+ struct scriptrange* sr_next;
+} scriptrange_t;
+
+typedef struct scriptorder {
+ unsigned so_caseIgnoreAccents;
+ scriptrange_t** so_sort;
+ scriptrange_t** so_display;
+} scriptorder_t;
+
+scriptorder_t* dsgw_scriptorder();
+
+
+/*
+ * in cookie.c
+ */
+char *dsgw_mkcookie();
+int dsgw_ckdn2passwd( char *cookie, char *dn, char **ret_pw );
+int dsgw_storecookie( char *cookie, char *dn, char *password, time_t expires );
+void dsgw_traverse_db();
+char *dsgw_t2gmts( time_t cktime );
+int dsgw_delcookie( char *cookie );
+void dsgw_closecookiedb( FILE *fp );
+FILE *dsgw_opencookiedb();
+time_t dsgw_getlastpurged( FILE *fp );
+int dsgw_purgedatabase( char *dn );
+
+/*
+ * in emitauth.c
+ */
+void dsgw_emit_auth_form( char *binddn );
+void dsgw_emit_auth_dest( char *binddn, char* authdesturl );
+
+/*
+ * in emitf.c
+ */
+int dsgw_emits (const char* s); /* like fputs(s, stdout) */
+int dsgw_emitf (const char* format, ...); /* like printf */
+int dsgw_emitfv (const char* format, va_list argl);
+char* dsgw_emit_converts_to (char* charset);
+int is_UTF_8 (const char* charset);
+void* dsgw_emitn (void*, const char* buf, size_t len);
+size_t dsgw_fputn (FILE*, const char* buf, size_t len);
+
+#define QUOTATION_JAVASCRIPT 2
+#define QUOTATION_JAVASCRIPT_MULTILINE 3
+void dsgw_quotation_begin (int kind);
+void dsgw_quotation_end();
+int dsgw_quote_emits (int kind, const char* s);
+int dsgw_quote_emitf (int kind, const char* format, ...);
+
+/*
+ * in collate.c
+ */
+#define CASE_EXACT 0
+#define CASE_INSENSITIVE 1
+
+typedef int (*strcmp_t) (const char*, const char*);
+strcmp_t dsgw_strcmp (int);
+
+typedef int (*valcmp_t) (const char**, const char**);
+valcmp_t dsgw_valcmp (int);
+
+extern struct berval* dsgw_strkeygen (int, const char*);
+extern struct berval* dsgw_key_first;
+extern struct berval* dsgw_key_last;
+
+int LDAP_C LDAP_CALLBACK dsgw_keycmp (void*, const struct berval*, const struct berval*);
+void LDAP_C LDAP_CALLBACK dsgw_keyfree(void*, const struct berval*);
+
+/*
+ * in vcard.c
+ */
+void dsgw_vcard_from_entry( LDAP *ld, char *dn, char *mimetype );
+
+/*
+ * utf8compare.c
+ */
+int dsgw_utf8casecmp(unsigned char *s0, unsigned char *s1);
+int dsgw_utf8ncasecmp(unsigned char *s0, unsigned char *s1, int n);
+
+/*
+ * dsgwutil.c
+ */
+/******************** Accept Language List ************************/\
+#if 0 /* defined in i18n.h */
+
+#define MAX_ACCEPT_LANGUAGE 16
+#define MAX_ACCEPT_LENGTH 18
+typedef char ACCEPT_LANGUAGE_LIST[MAX_ACCEPT_LANGUAGE][MAX_ACCEPT_LENGTH];
+#endif /* MAX_ACCEPT_LANGUAGE */
+
+/* AcceptLangList
+ *
+ * Will parse an Accept-Language string of the form
+ * "en;q=1.0,fr;q=0.9..."
+ * The ACCEPT_LANGUAGE_LIST array will be loaded with the ordered
+ * language elements based on the priority of the languages specified.
+ * The number of languages will be returned as the result of the
+ * call.
+ */
+size_t
+AcceptLangList(
+ const char * acceptLanguage,
+ ACCEPT_LANGUAGE_LIST acceptLanguageList
+);
+
+/*
+ * converts a buffer of characters to/from UTF8 from/to a native charset
+ * the given converter will handle the native charset
+ * returns 0 if not all of source was converted, 1 if all of source
+ * was converted, -1 upon error
+ * all of source will be converted if there is enough room in dest to contain
+ * the entire conversion, or if dest is null and we are malloc'ing space for dest
+ */
+int
+dsgw_convert(
+ int direction, /* DSGW_TO_UTF8 or DSGW_FROM_UTF8 */
+ UConverter *nativeConv, /* convert from/to native charset */
+ char **dest, /* *dest is the destination buffer - if *dest == NULL, it will be malloced */
+ size_t destSize, /* size of dest buffer (ignored if *dest == NULL) */
+ size_t *nDest, /* number of chars written to dest */
+ const char *source, /* source buffer to convert - either in native encoding (to) or utf8 (from) */
+ size_t sourceSize, /* size of source buffer - if 0, assume source is NULL terminated */
+ size_t *nSource, /* number of chars read from source buffer */
+ UErrorCode *pErrorCode /* will be reset each time through */
+);
+#define DSGW_TO_UTF8 0
+#define DSGW_FROM_UTF8 1
diff --git a/ldap/clients/dsgw/dsgw_include.mk b/ldap/clients/dsgw/dsgw_include.mk
new file mode 100644
index 00000000..10bafd8a
--- /dev/null
+++ b/ldap/clients/dsgw/dsgw_include.mk
@@ -0,0 +1,23 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+
+# These are macro definitions for use by components of the dsgw
+DSGW_DEFAULT_LANG = en
+DSGW_BASE_RELDIR = $(RELDIR)/clients/dsgw
+DSGW_BIN_RELDIR = $(DSGW_BASE_RELDIR)/bin
+DSGW_HTML_RELDIR = $(DSGW_BASE_RELDIR)/html
+DSGW_CONF_RELDIR = $(DSGW_BASE_RELDIR)/config
+DSGW_PBHTML_RELDIR = $(DSGW_BASE_RELDIR)/pbhtml
+DSGW_PBCONF_RELDIR = $(DSGW_BASE_RELDIR)/pbconfig
+DSGW_MAN_RELDIR = $(RELDIR)/manual/$(DSGW_DEFAULT_LANG)/slapd/gw/manual
+DSGW_INFO_RELDIR = $(RELDIR)/manual/$(DSGW_DEFAULT_LANG)/slapd/gw/info
+
+# generic target to be used to make any directory dependencies
+$(DSGW_BIN_RELDIR) $(DSGW_HTML_RELDIR) $(DSGW_CONF_RELDIR) $(DSGW_PBHTML_RELDIR) \
+ $(DSGW_PBCONF_RELDIR) $(DSGW_MAN_RELDIR) $(DSGW_INFO_RELDIR) \
+ $(DSGW_CONF_RELDIR)/$(DSGW_DEFAULT_LANG) :
+ mkdir -p $@
diff --git a/ldap/clients/dsgw/dsgwutil.c b/ldap/clients/dsgw/dsgwutil.c
new file mode 100644
index 00000000..99e7f2aa
--- /dev/null
+++ b/ldap/clients/dsgw/dsgwutil.c
@@ -0,0 +1,1318 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * dsgwutil.c -- misc. utility functions -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include <limits.h> /* PATH_MAX */
+#include "dsgw.h"
+#include "dbtdsgw.h"
+#ifdef NS_DS
+#include "../lib/libsi18n/gsslapd.h"
+#else /* Admin Server */
+#include "../lib/libsi18n/gsadmserv.h"
+#endif
+
+#ifdef DSGW_DEBUG
+#include <time.h>
+#include <stdarg.h>
+#endif /* DSGW_DEBUG */
+
+static char **vpmap = NULL;
+
+extern char *Versionstr; /* from Versiongw.c */
+
+char *progname; /* set by dsgw_init() */
+dsgwconfig *gc; /* set by dsgw_init() */
+int http_hdr_sent = 0; /* non-zero if header has been sent */
+char **header_lines = NULL; /* null-terminated array of hdr lines */
+char *dsgw_html_body_colors = ""; /* reset by dsgw_init() */
+
+/*Global context variable, telling the CGI's where to look for the config file*/
+char *context = NULL; /* Gotten from the QUERY_STRING */
+char *langwich = NULL; /* The language that libsi18n
+ picks from acceptlang*/
+char *countri = NULL; /* The country that libsi18n
+ picks from acceptlang*/
+
+
+static void figure_out_langwich(void);
+
+/*
+ * dsgw_init -- initialize a dsgw CGI program:
+ * set "progname" global based on "progpath" (normally argv[0])
+ * check that REQUEST_METHOD is in "methods_handled" mask
+ * if request method is "POST", read HTML form variables from stdin
+ * handles the context variable if the CGI was called with a post.
+ * The context variable tells dsgw_read_config what config file
+ * to read.
+ *
+ * If an fatal error occurs, -1 is returned.
+ * If all goes well, returns either DSGW_METHOD_GET or DSGW_METHOD_POST
+ */
+int
+dsgw_init( int argc, char **argv, int methods_handled )
+{
+ char *m, *s;
+ int method;
+ int c, err;
+
+ (void)ADM_Init();
+
+ /* initialize the string database */
+ XP_InitStringDatabase(
+#ifdef NS_DS
+ SERVER_ROOT_PATH "/bin/slapd/property" /* Directory Server Gateway */
+#else
+ SERVER_ROOT_PATH "/admin" /* Admin Server */
+#endif
+ , DATABASE_NAME);
+ /* set default default languages for string database */
+ SetLanguage(CLIENT_LANGUAGE, "");
+ SetLanguage(ADMIN_LANGUAGE, "");
+ SetLanguage(DEFAULT_LANGUAGE, "");
+
+ if (( progname = strchr( argv[0], '/' )) == NULL ) {
+ progname = dsgw_ch_strdup( argv[0] );
+#ifdef _WIN32
+ if (( s = strrchr( progname, '.' )) != NULL
+ && strcasecmp( s, ".EXE" ) == 0 ) {
+ *s = '\0';
+ }
+#endif /* _WIN32 */
+ } else {
+ ++progname;
+ }
+
+ while (( c = getopt( argc, argv, "v" )) != EOF ) {
+ if ( c == 'v' ) {
+ printf( "%s\n", Versionstr );
+ }
+ exit( 0 );
+ }
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "%s started\n", Versionstr );
+#endif
+ err = method = 0;
+
+ /*Have to get the context before we read the config file.*/
+ if (( m = getenv( "REQUEST_METHOD" )) != NULL ) {
+ if ( strcasecmp( m, "GET" ) == 0 || strcasecmp( m, "HEAD" ) == 0 ) {
+ method = DSGW_METHOD_GET;
+ } else if ( strcasecmp( m, "POST" ) == 0 ) {
+ method = DSGW_METHOD_POST;
+ if (( err = dsgw_post_begin( stdin )) == 0 ) {
+ context = dsgw_get_cgi_var( "context", DSGW_CGIVAR_OPTIONAL );
+ }
+ }
+ }
+
+ if ( method == 0 || ( methods_handled & method ) == 0 ) {
+ dsgw_error( DSGW_ERR_BADMETHOD, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ /*If no context was given, try default.conf.*/
+ if (context == NULL) {
+ context = dsgw_ch_strdup("default");
+ }
+
+ /* If this is a LIte installation: dsgw is not enabled */
+/* this assumes the current dir is <server root>/dsgw/bin; under http servers
+other than admin server, we have to rely on relative paths to find the
+key file */
+
+ if ( is_directory_lite (SERVER_ROOT_PATH)) {
+ dsgw_error( DSGW_ERR_BADCONFIG, XP_GetClientStr(DBT_NotWillingToExecute_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ gc = dsgw_read_config();
+
+ gc->gc_charset = dsgw_emit_converts_to (gc->gc_charset);
+ {
+ /* eliminate elements of gc_changeHTML that don't apply to gc_charset: */
+ auto dsgwsubst **s = &(gc->gc_changeHTML);
+ auto char *charset = gc->gc_charset;
+ if ( charset == NULL ) charset = ""; /* Latin-1, implicitly */
+ while ( *s ) {
+ auto char **c = (*s)->dsgwsubst_charsets;
+ if ( c && *c ) {
+ for ( ; *c; ++c ) {
+ if ( strcasecmp( *c, charset ) == 0 ) {
+ break;
+ }
+ }
+ if ( *c == NULL ) {
+ *s = (*s)->dsgwsubst_next; /* eliminate **s */
+ /* This is quick and dirty: we just created garbage. */
+ continue;
+ }
+ }
+ s = &((*s)->dsgwsubst_next);
+ }
+ }
+
+ /* set languages for string database */
+ SetLanguage(CLIENT_LANGUAGE,gc->gc_ClientLanguage);
+ SetLanguage(ADMIN_LANGUAGE,gc->gc_AdminLanguage);
+ SetLanguage(DEFAULT_LANGUAGE,gc->gc_DefaultLanguage);
+
+ /* Figure out the language that libsi18n is using */
+ figure_out_langwich();
+
+ /* Get the port and servername */
+ if (method == DSGW_METHOD_POST) {
+ if (( s = dsgw_get_cgi_var( "ldapport", DSGW_CGIVAR_OPTIONAL )) != NULL ) {
+ gc->gc_ldapport = atoi( s );
+ free( s );
+ }
+ if (( s = dsgw_get_cgi_var( "ldapserver", DSGW_CGIVAR_OPTIONAL )) != NULL ) {
+ gc->gc_ldapserver = s;
+ }
+
+ }
+
+ if (( s = getenv( "HTTPS" )) == NULL || strcasecmp( s, "on" ) == 0 ||
+ ( s = getenv( "HTTPS_KEYSIZE" )) == NULL ) {
+ gc->gc_httpskeysize = 0;
+ } else {
+ gc->gc_httpskeysize = atoi( s );
+ }
+
+ /* set default color scheme */
+ if ( method == DSGW_METHOD_POST && ( s = dsgw_get_cgi_var( "colors",
+ DSGW_CGIVAR_OPTIONAL )) != NULL ) {
+ dsgw_html_body_colors = s;
+ } else if ( gc->gc_admserv ) { /* use same color scheme as libadmin */
+ dsgw_html_body_colors = "BGCOLOR=\"#C0C0C0\" LINK=\"#0000EE\" "
+ "VLINK=\"#551A8B\" ALINK=\"#FF0000\"";
+ } else {
+ dsgw_html_body_colors = "BGCOLOR=\"white\"";
+ }
+
+ return( method );
+}
+
+
+/*
+ * function called back by dsgw_parse_line() to evaluate IF directives.
+ * return non-zero for true, zero for false.
+ */
+int
+dsgw_simple_cond_is_true( int argc, char **argv, void *arg /* UNUSED */ )
+{
+ if ( strcasecmp( argv[0], DSGW_COND_ADMSERV ) == 0 ) {
+ return( gc->gc_admserv );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_LOCALDB ) == 0 ) {
+ return( gc->gc_localdbconf != NULL );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_POSTEDFORMVALUE ) == 0 ) {
+ /*
+ * format of IF statment is:
+ * <-- IF "PostedFormValue" "VARNAME" "VALUE" -->
+ * where VARNAME is the name of a POSTed CGI variable to look for and
+ * VALUE is an optional value to test it against. If VALUE is omitted,
+ * the test is just for the presence of a variable named VARNAME.
+ */
+ char *postedvalue;
+
+ if ( argc < 2 || ( postedvalue = dsgw_get_cgi_var( argv[1],
+ DSGW_CGIVAR_OPTIONAL )) == NULL ) {
+ return( 0 ); /* VARNAME is missing or not posted */
+ } else if ( argc < 3 ) {
+ return( 1 ); /* VALUE is missing, so return true */
+ } else {
+ return( strcasecmp( postedvalue, argv[ 2 ] ) == 0 );
+ }
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * return a pointer to a malloc'd string containing the path to
+ * config. file "filename", based on the DSGW_CONFIGDIR define.
+ * If "filename" contains "..", or "//" this is treated as a fatal
+ * error. If "prefix" is not NULL, it is pre-pended to "filename"
+ */
+char *
+dsgw_file2path( char *prefix, char *filename )
+{
+ char *path, *pattern;
+ int len;
+
+ if ( strstr( filename, "//" ) != NULL ||
+ strstr( filename, ".." ) != NULL ) {
+ dsgw_error( DSGW_ERR_BADFILEPATH, filename, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if ( prefix == NULL ) {
+ prefix = "";
+ }
+
+ /* allocate buffers with enough extra room to fit "$$LANGDIR/" */
+ len = strlen( prefix ) + strlen( filename ) + 11;
+ if ( NULL != gc->gc_ClientLanguage ) {
+ len += strlen( gc->gc_ClientLanguage );
+ }
+ path = dsgw_ch_malloc( len );
+ pattern = dsgw_ch_malloc( len );
+
+ /* call GetFileForLanguage() to do its I18n magic */
+ sprintf( pattern, "%s$$LANGDIR/%s", prefix, filename );
+ if ( GetFileForLanguage( pattern, gc->gc_ClientLanguage, path ) < 0 ) {
+ sprintf( path, "%s%s", prefix, filename ); /* fallback */
+ }
+ free( pattern );
+
+ return( path );
+}
+
+
+
+/*
+ * return a pointer to a malloc'd string containing the path to
+ * config. file "filename", based on the DSGW_HTMLDIR define.
+ * If "filename" contains "..", or "//" this is treated as a fatal
+ * error. If "prefix" is not NULL, it is pre-pended to "filename"
+ */
+char *
+dsgw_file2htmlpath( char *prefix, char *filename )
+{
+ char *path, *pattern;
+ int len;
+
+ if ( strstr( filename, "//" ) != NULL ||
+ strstr( filename, ".." ) != NULL ) {
+ dsgw_error( DSGW_ERR_BADFILEPATH, filename, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if ( prefix == NULL ) {
+ prefix = "";
+ }
+
+ /* allocate buffers with enough extra room to fit "$$LANGDIR/" */
+ /*len = strlen( DSGW_HTMLDIR ) + strlen( prefix ) + strlen( filename ) + 11;*/
+ len = strlen( gc->gc_docdir ) + strlen( prefix ) + strlen( filename ) + 11;
+ if ( NULL != gc->gc_ClientLanguage ) {
+ len += strlen( gc->gc_ClientLanguage );
+ }
+
+ path = dsgw_ch_malloc( len );
+ pattern = dsgw_ch_malloc( len );
+
+ /* call GetFileForLanguage() to do its I18n magic */
+ sprintf( pattern, "%s%s$$LANGDIR/%s", gc->gc_docdir, prefix, filename );
+ if ( GetFileForLanguage( pattern, gc->gc_ClientLanguage, path ) < 0 ) {
+ /* use fallback */
+ sprintf( path, "%s/%s%s", gc->gc_docdir, prefix, filename );
+ }
+ free( pattern );
+
+ return( path );
+}
+
+
+/*
+ * malloc that checks for NULL return value and exits upon failure
+ */
+void *
+dsgw_ch_malloc( size_t n )
+{
+ void *p;
+
+ if (( p = malloc( n )) == NULL ) {
+ dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ return( p );
+}
+
+void *
+dsgw_ch_calloc( size_t nelem, size_t elsize )
+{
+ register void *p = calloc( nelem, elsize );
+ if ( p == NULL ) {
+ dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ return( p );
+}
+
+/*
+ * realloc that checks for NULL return value and exits upon failure
+ * we also handle p == NULL by doing a malloc
+ */
+void *
+dsgw_ch_realloc( void *p, size_t n )
+{
+ if ( p == NULL ) {
+ p = malloc( n );
+ } else {
+ p = realloc( p, n );
+ }
+
+ if ( p == NULL ) {
+ dsgw_error( DSGW_ERR_NOMEMORY, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ return( p );
+}
+
+
+/*
+ * strdup that checks for NULL return value and exits upon failure
+ */
+char *
+dsgw_ch_strdup( const char *s )
+{
+ int len;
+ char *p;
+
+ len = strlen( s ) + 1;
+ p = dsgw_ch_malloc( len );
+ memcpy( p, s, len );
+ return( p );
+}
+
+
+
+/*
+ * Escape any single- or double-quotes with a '\'. Used when generating
+ * JavaScript code. Returns a malloc'd string which the caller is
+ * responsible for freeing.
+ */
+char *
+dsgw_escape_quotes( char *in )
+{
+ char *out;
+ char *p, *t;
+ int nq = 0;
+
+
+ if ( in == NULL ) {
+ return NULL;
+ }
+ /* count number of quotes */
+ for ( p = in; *p != '\0'; p++ ) {
+ if ( *p == '\'' || *p == '"' ) {
+ nq++;
+ }
+ }
+ out = dsgw_ch_malloc(( p - in ) + nq + 1 );
+ for ( p = in, t = out; *p != '\0'; p++ ) {
+ if ( *p == '\'' || *p == '"' ) {
+ *t++ = '\\';
+ }
+ *t++ = *p;
+ }
+ *t = '\0';
+ return out;
+}
+
+char *
+dsgw_get_translation( char *in )
+{
+ dsgwsubst *p;
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "L10n map table:\n" );
+ for ( p = gc->gc_l10nsets; p ; p = p->dsgwsubst_next ) {
+ dsgw_log( "%s -> %s\n", p->dsgwsubst_from, p->dsgwsubst_to );
+ }
+#endif
+
+ for ( p = gc->gc_l10nsets; p ; p = p->dsgwsubst_next ) {
+ if ( !strcasecmp( in, p->dsgwsubst_from ))
+ return p->dsgwsubst_to;
+ }
+ return in;
+}
+
+static void
+dsgw_puts (const char* s)
+{
+ dsgw_fputn (stdout, s, strlen(s));
+}
+
+#define CONTENT_TYPE "Content-type"
+#define TYPE_HTML "text/html"
+#define VARY "Vary"
+#define VARYLIST "Accept-Language,Accept-Charset,User-Agent"
+
+static const char* ct_prefix = CONTENT_TYPE ": " TYPE_HTML;
+static const char* cs_prefix = ";charset=";
+static const char* vr_prefix = VARY ": ";
+
+/*
+ * Send the headers we've accumulated.
+ */
+void
+dsgw_send_header()
+{
+ int i;
+
+ if ( http_hdr_sent ) {
+ return;
+ }
+ if ( header_lines == NULL ) {
+ dsgw_puts (ct_prefix);
+ if ( gc != NULL && gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
+ dsgw_puts (cs_prefix); dsgw_puts (gc->gc_charset );
+ }
+ dsgw_puts ("\n");
+ /* send Vary tag if HTTP/1.1 or greater */
+ if ( NULL != gc && gc->gc_httpversion >= 1.1 ) {
+ dsgw_puts (vr_prefix); dsgw_puts (VARYLIST); dsgw_puts ("\n");
+ }
+ } else for ( i = 0; header_lines[ i ] != NULL; i++ ) {
+ dsgw_puts (header_lines[ i ]);
+ dsgw_puts ("\n");
+ }
+ dsgw_puts ("\n");
+ http_hdr_sent = 1;
+}
+
+
+/*
+ * Add a line to the array of header lines.
+ */
+void
+dsgw_add_header( char *line )
+{
+ int i;
+
+ if ( header_lines == NULL ) {
+ header_lines = ( char ** ) dsgw_ch_malloc( 3 * sizeof( char * ));
+ if ( gc != NULL && gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
+ header_lines[ 0 ] = dsgw_ch_malloc( strlen( ct_prefix ) +
+ strlen( cs_prefix ) + strlen( gc->gc_charset ) + 1 );
+ sprintf( header_lines[ 0 ], "%s%s%s", ct_prefix, cs_prefix,
+ gc->gc_charset );
+ } else {
+ header_lines[ 0 ] = dsgw_ch_strdup( ct_prefix );
+ }
+ /* send Vary tag if HTTP/1.1 or greater */
+ if ( gc->gc_httpversion >= 1.1 ) {
+ header_lines[ 1 ] =
+ dsgw_ch_malloc( strlen( vr_prefix ) + sizeof( VARYLIST ) );
+ /* (char *) */ /* string literal */
+ sprintf( header_lines[ 1 ], "%s%s", vr_prefix, VARYLIST );
+ header_lines[ 2 ] = NULL;
+ } else {
+ header_lines[ 1 ] = NULL;
+ }
+ }
+ for ( i = 0; header_lines[ i ] != NULL; i++ );
+ header_lines = (char **) dsgw_ch_realloc( header_lines,
+ ( i + 2 ) * sizeof( char * ));
+ header_lines[ i ] = dsgw_ch_strdup( line );
+ header_lines[ i + 1 ] = NULL;
+}
+
+
+/*
+ * Check the environment for an authentication cookie. Returns the
+ * entire auth cookie if present, or returns NULL if no such cookie
+ * exists. The returned string must be freed by the caller.
+ */
+char *
+dsgw_get_auth_cookie()
+{
+ char *p, *e, *ckhdr;
+
+ ckhdr = getenv( "HTTP_COOKIE" );
+
+ if ( ckhdr == NULL ) {
+ return NULL;
+ } else {
+ ckhdr = strdup( ckhdr );
+ }
+
+ if (( p = strstr( ckhdr, DSGW_AUTHCKNAME )) == NULL ) {
+ free( ckhdr );
+ return NULL;
+ }
+
+ if (( e = strchr( p, ';' )) != NULL ) {
+ *e = '\0';
+ }
+
+ p = strdup( p );
+ free( ckhdr );
+ return p;
+}
+
+
+
+/*
+ * Break a cookie into its random string and DN parts. The DN is returned
+ * unescaped. The caller is responsible for freeing the returned DN
+ * and random string. Returns 0 on success, -1 on error. If the
+ * cookie has the value "[unauthenticated]", then 0 is returned and
+ * dn is set to NULL;
+ */
+int
+dsgw_parse_cookie( char *cookie, char **rndstr, char **dn )
+{
+ char *p, *r;
+ int rlen;
+
+ if ( cookie == NULL ) {
+ *rndstr = *dn = NULL;
+ return -1;
+ }
+
+ /* Make sure cookie starts with "nsdsgwauth" */
+ if ( strncmp( cookie, DSGW_AUTHCKNAME, strlen( DSGW_AUTHCKNAME ))) {
+ /* Cookie didn't start with "nsdsgwauth" */
+ *rndstr = *dn = NULL;
+ return -1;
+ }
+
+ r = cookie + strlen( DSGW_AUTHCKNAME );
+ if ( *r == '=' ) {
+ r++;
+ }
+
+ /* Is cookie value "[unauthenticated]" ? */
+ if ( !strncmp( r, DSGW_UNAUTHSTR, strlen( DSGW_UNAUTHSTR ))) {
+ *rndstr = strdup( DSGW_UNAUTHSTR );
+ *dn = NULL;
+ return 0;
+ }
+
+ /* find start of DN */
+ if (( p = strrchr( cookie, ':' )) == NULL ) {
+ *rndstr = *dn = NULL;
+ return -1;
+ }
+
+ rlen = p - r + 1;
+ *(rndstr) = dsgw_ch_malloc( rlen );
+ *(rndstr)[ 0 ] = '\0';
+ strncat( *rndstr, r, rlen-1 );
+ (*rndstr)[ rlen - 1 ] = '\0';
+
+ p++;
+ *dn = strdup( p );
+ dsgw_form_unescape( *dn );
+
+ return 0;
+}
+
+/*
+ * Generate a "go home" button with a link to the main entry point for
+ * the gateway. The caller is responsible for any surrounding
+ * HTML, e.g. <FORM> and <TABLE> tags.
+ */
+void
+dsgw_emit_homebutton()
+{
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"top.location.href='%s'\">", XP_GetClientStr(DBT_returnToMain_), gc->gc_urlpfxmain /*DSGW_URLPREFIX_MAIN*/ );
+}
+
+
+/*
+ * Generate a help button with a link to the tutor program for
+ * the given help topic. The caller is responsible for any surrounding
+ * HTML, e.g. <FORM> and <TABLE> tags.
+ */
+void
+dsgw_emit_helpbutton( char *topic )
+{
+ if ( topic == NULL ) {
+ return;
+ }
+
+ if ( gc->gc_admserv ) {
+ char *jscript;
+
+ if (( jscript = helpJavaScriptForTopic( topic )) == NULL ) {
+ return;
+ }
+
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" onClick=\"%s\">",
+#define LABEL_HELP "ヘルプ"
+/*LABEL_HELP*/ XP_GetClientStr(DBT_help_), jscript );
+ } else {
+ char *tutorvp;
+
+ tutorvp = dsgw_getvp( DSGW_CGINUM_TUTOR );
+
+ /*
+ * the following is based on code that was found in
+ * ldapserver/lib/libadmin/template.c inside the
+ * helpJavaScriptForTopic() function. We need our own copy because
+ * we use a different tutor CGI. Sigh.
+ */
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" onClick=\""
+ "if ( top.helpwin ) {"
+ " top.helpwin.focus();"
+ " top.helpwin.infotopic.location='%s?!%s&context=%s';"
+ "} else {"
+ " window.open('%s?%s&context=%s', 'infowin_dsgw', "
+ " 'resizable=1,width=400,height=500');"
+ "}\">\n",
+ XP_GetClientStr(DBT_help_1),tutorvp, topic, context,
+ tutorvp, topic, context );
+ }
+}
+
+
+/*
+ * Return malloc'd URL prefix that consists of:
+ * prefix + '/' + HOST:PORT + '/' (not anymore - RJP)
+ * prefix + ? + context=CONTEXT&hp=HOST:PORT&dn=
+ */
+char *
+dsgw_build_urlprefix()
+{
+ char *prefix = dsgw_getvp( DSGW_CGINUM_DOSEARCH );
+ char *p, *urlprefix;
+
+ p = ( gc->gc_ldapserver == NULL ? "" : gc->gc_ldapserver );
+ urlprefix = dsgw_ch_malloc( 16 /* room for "?:port#&dn=" + zero-term. */
+ + strlen( prefix ) + strlen( p ) +strlen(context) + 9);
+ sprintf( urlprefix, "%s?context=%s&hp=%s", prefix, context, p );
+ if ( gc->gc_ldapport != 0 && gc->gc_ldapport != LDAP_PORT ) {
+ sprintf( urlprefix + strlen( urlprefix ), ":%d", gc->gc_ldapport );
+ }
+ strcat( urlprefix,"&dn=" );
+ return( urlprefix );
+}
+
+
+void
+dsgw_addtemplate( dsgwtmpl **tlpp, char *template, int count, char **ocvals )
+{
+ int i;
+ dsgwtmpl *prevtp, *tp;
+
+ tp = (dsgwtmpl *)dsgw_ch_malloc( sizeof( dsgwtmpl ));
+ memset( tp, 0, sizeof( dsgwtmpl ));
+ tp->dstmpl_name = dsgw_ch_strdup( template );
+
+ /* each argument is one objectClass */
+ tp->dstmpl_ocvals = dsgw_ch_malloc(( count + 1 ) * sizeof( char * ));
+ for ( i = 0; i < count; ++i ) {
+ tp->dstmpl_ocvals[ i ] = dsgw_ch_strdup( ocvals[ i ] );
+ }
+ tp->dstmpl_ocvals[ count ] = NULL;
+
+ if ( *tlpp == NULL ) {
+ *tlpp = tp;
+ } else {
+ for ( prevtp = *tlpp; prevtp->dstmpl_next != NULL;
+ prevtp = prevtp->dstmpl_next ) {
+ ;
+ }
+ prevtp->dstmpl_next = tp;
+ }
+}
+
+
+dsgwtmpl *
+dsgw_oc2template( char **ocvals )
+{
+ int i, j, needcnt, matchcnt;
+ dsgwtmpl *tp;
+
+ for ( tp = gc->gc_templates; tp != NULL; tp = tp->dstmpl_next ) {
+ needcnt = matchcnt = 0;
+ for ( i = 0; tp->dstmpl_ocvals[ i ] != NULL; ++i ) {
+ for ( j = 0; ocvals[ j ] != NULL; ++j ) {
+ if ( strcasecmp( ocvals[ j ], tp->dstmpl_ocvals[ i ] ) == 0 ) {
+ ++matchcnt;
+ }
+ }
+ ++needcnt;
+ }
+
+ if ( matchcnt == needcnt ) {
+ return( tp );
+ }
+ }
+
+ return( NULL );
+}
+
+
+
+void
+dsgw_init_searchprefs( struct ldap_searchobj **solistp )
+{
+ char *path;
+
+ path = dsgw_file2path( gc->gc_configdir, DSGW_SEARCHPREFSFILE );
+ if ( ldap_init_searchprefs( path, solistp ) != 0 ) {
+ dsgw_error( DSGW_ERR_BADCONFIG, path, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ free( path );
+}
+
+
+void
+dsgw_remove_leading_and_trailing_spaces( char **sp )
+{
+ auto char *s, *p;
+
+ if ( sp == NULL || *sp == NULL ) {
+ return;
+ }
+
+ s = *sp;
+
+ /* skip past any leading spaces */
+ while ( ldap_utf8isspace( s )) {
+ LDAP_UTF8INC (s);
+ }
+
+ /* truncate to remove any trailing spaces */
+ if ( *s != '\0' ) {
+ p = s + strlen( s );
+ LDAP_UTF8DEC (p);
+ while (ldap_utf8isspace( p )) {
+ LDAP_UTF8DEC (p);
+ }
+ *LDAP_UTF8INC(p) = '\0';
+ }
+ *sp = s;
+}
+
+
+/*
+ * Return the virtual path prefix for the CGI program specified by
+ * cginum.
+ */
+char *
+dsgw_getvp( int cginum )
+{
+ char *cginame;
+ char *surl;
+ /*char *extpath;*/
+ int i;
+
+ if ( cginum < 1 || cginum > DSGW_MODE_NUMMODES ) {
+ return "";
+ }
+ if ( vpmap == NULL ) {
+ /* note: slot zero of vpmap isn't used */
+ vpmap = dsgw_ch_malloc(( DSGW_MODE_NUMMODES + 1 ) * sizeof( char * ));
+ for ( i = 0; i <= DSGW_MODE_NUMMODES; i++ ) {
+ vpmap[ i ] = NULL;
+ }
+ }
+
+ if ( vpmap[ cginum ] == NULL ) {
+ switch ( cginum ) {
+ case DSGW_CGINUM_DOSEARCH:
+ cginame = DSGW_CGINAME_DOSEARCH;
+ break;
+ case DSGW_CGINUM_BROWSE:
+ cginame = DSGW_CGINAME_BROWSE;
+ break;
+ case DSGW_CGINUM_SEARCH:
+ cginame = DSGW_CGINAME_SEARCH;
+ break;
+ case DSGW_CGINUM_CSEARCH:
+ cginame = DSGW_CGINAME_CSEARCH;
+ break;
+ case DSGW_CGINUM_AUTH:
+ cginame = DSGW_CGINAME_AUTH;
+ break;
+ case DSGW_CGINUM_EDIT:
+ cginame = DSGW_CGINAME_EDIT;
+ break;
+ case DSGW_CGINUM_DOMODIFY:
+ cginame = DSGW_CGINAME_DOMODIFY;
+ break;
+ case DSGW_CGINUM_DNEDIT:
+ cginame = DSGW_CGINAME_DNEDIT;
+ break;
+ case DSGW_CGINUM_TUTOR:
+ cginame = DSGW_CGINAME_TUTOR;
+ break;
+ case DSGW_CGINUM_LANG:
+ cginame = DSGW_CGINAME_LANG;
+ break;
+ default:
+ return "";
+ }
+
+ if (( surl = getenv( "SERVER_URL" )) == NULL ) {
+ surl = "";
+ }
+
+ /*if ( gc->gc_admserv ) {
+ *
+ * include "/admin-serv/" or "/user-environment/" if appropriate
+ *
+ * if ( gc->gc_enduser ) {
+ * extpath = DSGW_USER_ADM_BINDIR;
+ * } else {
+ * extpath = DSGW_ADMSERV_BINDIR;
+ * }
+ * } else {
+ * extpath = "";
+ * }
+ */
+ vpmap[ cginum ] = dsgw_ch_malloc( strlen( gc->gc_urlpfxcgi ) + strlen( surl )
+ /*+ strlen( extpath ) */
+ + strlen( cginame ) + 2 );
+
+ sprintf( vpmap[ cginum ], "%s%s%s", surl,
+ /*extpath, */
+ gc->gc_urlpfxcgi, cginame );
+
+ /*sprintf( vpmap[ cginum ], "%s%s%s", extpath, gc->gc_urlpfxcgi, cginame );*/
+ }
+ return( vpmap[ cginum ]);
+}
+
+
+#ifdef DSGW_DEBUG
+#include <stdio.h> /* FILE */
+
+/* Returns a directory path used for tmp log files. */
+char *
+dsgw_get_tmp_log_dir()
+{
+ static char tmp_log[MAXPATHLEN];
+ char *install_dir = NULL;
+
+#if defined( XP_WIN32 )
+ int ilen;
+ char *pch;
+ char tmp_dir[_MAX_PATH];
+#endif
+ install_dir = getenv("NETSITE_ROOT");
+ if (install_dir != NULL) {
+ sprintf(tmp_log, "%s/tmp/dsgw", install_dir);
+#if defined( XP_WIN32 )
+ for(ilen=0; ilen < strlen(tmp_log); ilen++)
+ {
+ if(tmp_log[ilen]=='/')
+ tmp_log[ilen]='\\';
+ }
+#endif /* XP_WIN32 */
+ } else {
+#if defined( XP_WIN32 )
+ ilen = strlen(tmp_dir);
+ GetTempPath( ilen+1, tmp_dir );
+ /* Remove trailing slash. */
+ pch = tmp_dir[ilen-1];
+ if( pch == '\\' || pch == '/' )
+ tmp_dir[ilen-1] = '\0';
+ sprintf(tmp_log, "%s\\DSGW", tmp_dir);
+#else
+ sprintf(tmp_log, "/tmp/dsgw");
+#endif
+ }
+ return tmp_log;
+}
+
+static FILE* log_out_fp = NULL;
+
+void
+dsgw_log_out (const char* s, size_t n)
+{
+ if ( log_out_fp == NULL ) {
+ char fname[ 256 ];
+ char* format =
+#if defined( XP_WIN32 )
+ "%s\\log%.50s.out";
+#else
+ "%s/%.50s.out";
+#endif
+ PR_snprintf( fname, 256, format, dsgw_get_tmp_log_dir(), progname );
+ log_out_fp = fopen( fname, "w" );
+ }
+ if (log_out_fp != NULL) {
+ fwrite (s, sizeof(char), n, log_out_fp);
+ fflush (log_out_fp);
+ }
+}
+
+
+/*
+ * logging function -- called like printf(); syslog-like output is written
+ * to a file called /tmp/progname where progname is derived from argv[0]
+ */
+static FILE* logfp = NULL;
+void
+dsgw_log( char *fmt, ... )
+{
+ time_t t;
+ char timebuf[ 20 ];
+ va_list ap;
+
+ t = time( NULL );
+
+ if ( logfp == NULL ) {
+ char fname[ 256 ];
+ char* format =
+#if defined( XP_WIN32 )
+ "%s\\log%.50s";
+#else
+ "%s/%.50s";
+#endif
+ PR_snprintf( fname, 256, format, dsgw_get_tmp_log_dir(), progname );
+ if (( logfp = fopen( fname, "a+" )) == NULL ) {
+ return;
+ }
+ }
+
+ memcpy( timebuf, ctime( &t ), 19 );
+ timebuf[ 19 ] = '\0';
+ fprintf( logfp, "%s %s: ", timebuf, progname );
+
+ va_start( ap, fmt );
+ (void)vfprintf( logfp, fmt, ap );
+ va_end( ap );
+ fflush( logfp );
+}
+
+
+/*
+ * log the contents of a NULL-terminated array of character strings
+ */
+void
+dsgw_logstringarray( char *arrayname, char **strs )
+{
+ int i;
+
+ if ( strs == NULL || strs[ 0 ] == NULL ) {
+ dsgw_log( "Array %s: empty\n", arrayname );
+ } else {
+ dsgw_log( "Array %s:\n", arrayname );
+
+ for ( i = 0; strs[ i ] != NULL; ++i ) {
+ dsgw_log( "\t%2d: \"%s\"\n", i, strs[ i ] );
+ }
+ }
+}
+#endif /* DSGW_DEBUG */
+
+void
+dsgw_head_begin()
+{
+ dsgw_emits ("<HEAD>");
+ if ( gc != NULL && gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
+ dsgw_emitf ("<META HTTP-EQUIV=\"%s\" CONTENT=\"%s%s%s\">",
+ CONTENT_TYPE, TYPE_HTML, cs_prefix, gc->gc_charset);
+ }
+}
+
+void
+dsgw_quote_emptyFrame()
+{
+ dsgw_quotation_begin( QUOTATION_JAVASCRIPT_MULTILINE );
+ dsgw_emits( "<HTML>" );
+ dsgw_emitf( "<BODY %s></BODY></HTML>", dsgw_html_body_colors );
+ dsgw_quotation_end();
+}
+
+/* This function contains code to alert the user that their password has
+ already expired. It gives them an opportunity to change it. */
+void
+dsgw_password_expired_alert( char *dn )
+{
+ char *ufn, *encodeddn = dsgw_strdup_escaped( dn );
+
+ dsgw_send_header();
+ dsgw_emits( "<HTML>" );
+ dsgw_head_begin();
+
+ dsgw_emits( "\n"
+ "<TITLE>Password Expired</TITLE>\n"
+ "<SCRIPT LANGUAGE=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript browsers\n" );
+
+ if ( encodeddn != NULL && strlen( encodeddn ) > 0 ) {
+ dsgw_emitf( "var editdesturl = '%s?passwd&dn=%s&context=%s';\n",
+ dsgw_getvp( DSGW_CGINUM_EDIT ), encodeddn, context );
+ } else {
+ dsgw_emitf( "var editdesturl=null;\n" );
+ }
+
+ dsgw_emits( "function EditPassword()\n"
+ "{\n"
+ " if ( editdesturl != null ) {\n"
+ " top.location.href = editdesturl;\n"
+ " } else {\n"
+ " top.close();\n"
+ " }\n"
+ "}\n"
+ "var contButtons = ");
+
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
+ dsgw_form_begin ("bForm", NULL);
+ dsgw_emits(
+ "\n<TABLE BORDER=2 WIDTH=100%>\n"
+ "<TD ALIGN=CENTER WIDTH=50%>\n"
+ "<INPUT TYPE=BUTTON NAME=\"contButton\""
+ "VALUE=\"");
+ dsgw_emits( XP_GetClientStr( DBT_EditPassword_ ));
+ dsgw_emits(
+ "\" onClick=\"EditPassword();\">\n"
+ "<TD ALIGN=CENTER WIDTH=50%%>" );
+ dsgw_emit_helpbutton( "AUTHSUCCESS" );
+ dsgw_emits(
+ "\n</TABLE></FORM>");
+ dsgw_quotation_end(); dsgw_emits(";\n");
+
+ dsgw_emits(
+ "var noContButtons = ");
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
+ dsgw_emits( XP_GetClientStr( DBT_ToContinue_ ));
+ dsgw_form_begin( "bForm", NULL );
+ dsgw_emits(
+ "\n<TABLE BORDER=2 WIDTH=100%>"
+ "\n<TD ALIGN=CENTER WIDTH=50%>" );
+ dsgw_emit_homebutton();
+ dsgw_emits( "\n<TD ALIGN=CENTER WIDTH=50%%>" );
+ dsgw_emit_helpbutton( "AUTHPROBLEM" );
+ dsgw_emits(
+ "\n</TABLE></FORM>\n");
+ dsgw_quotation_end(); dsgw_emits(";\n");
+
+#ifdef NOTFORNOW
+ /* ldap_dn2ufn currently gobbles up 'dc' so don't use it for */
+ /* now */
+ ufn = ldap_dn2ufn( dn );
+#endif
+
+ dsgw_emitf(
+ "// End hiding -->\n"
+ "</SCRIPT>\n"
+ "</HEAD>\n<BODY %s>\n"
+ "<CENTER>\n",
+ dsgw_html_body_colors );
+ dsgw_emitf( XP_GetClientStr( DBT_PasswordExpiredFor_ ), dn );
+ dsgw_emits( "</CENTER>\n" );
+ dsgw_emits( XP_GetClientStr( DBT_YourPasswordHasExpired_ ));
+ dsgw_emits( XP_GetClientStr( DBT_YouMustChangeYourPasswd_ ));
+ dsgw_emits( "<P>\n"
+ "<TR>\n"
+ "<SCRIPT LANGUAGE=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript browsers\n"
+ "if ( editdesturl != null ) {\n"
+ " document.write( contButtons );\n"
+ "} else {\n"
+ " document.write( noContButtons );\n"
+ "}\n"
+ "// End hiding -->\n"
+ "</SCRIPT>\n"
+ "</BODY>\n</HTML>\n" );
+}
+
+/* Pulled from ldapserver/ldap/servers/slapd/time.c */
+
+time_t
+dsgw_current_time()
+{
+ return( time( (time_t *)0 ));
+}
+
+#define mktime_r(from) mktime (from)
+
+time_t
+dsgw_time_plus_sec (time_t l, long r)
+ /* return the point in time 'r' seconds after 'l'. */
+{
+ /* On many (but not all) platforms this is simply l + r;
+ perhaps it would be better to implement it that way. */
+ struct tm t;
+ if (r == 0) return l; /* performance optimization */
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &l );
+ memcpy(&t, pt, sizeof(struct tm) );
+ }
+#else
+ localtime_r (&l, &t);
+#endif
+ /* Conceptually, we want to do: t.tm_sec += r;
+ but to avoid overflowing fields: */
+ r += t.tm_sec; t.tm_sec = r % 60; r /= 60;
+ r += t.tm_min; t.tm_min = r % 60; r /= 60;
+ r += t.tm_hour; t.tm_hour = r % 24; r /= 24;
+ t.tm_mday += r; /* may be > 31; mktime_r() must handle this */
+
+ /* These constants are chosen to work when the maximum
+ field values are 127 (the worst case) or more.
+ Perhaps this is excessively conservative. */
+ return mktime_r (&t);
+}
+
+/*
+ * Function: figure_out_langwich
+ *
+ * Returns: nothing
+ *
+ * Description: figures out the language/locale that libsi18n will
+ * use. This is so that non libsi18n functions can display
+ * stuff in the same language.
+ *
+ * Author: RJP
+ *
+ */
+static void
+figure_out_langwich(void)
+{
+ char *path = NULL;
+ char *iter = NULL;
+ char *p = NULL;
+ char *before = NULL;
+
+ /* Get a path to the html directory */
+ path = dsgw_file2path( gc->gc_configdir, "dsgwfilter.conf");
+
+ before = path;
+
+ /* Find the lang subdirectory part */
+ for ( p = ldap_utf8strtok_r( path, DSGW_PATHSEP_STR, &iter );
+ p != NULL && *p != '\0' && strcmp(p, "dsgwfilter.conf") != 0;
+ p = ldap_utf8strtok_r( NULL, DSGW_PATHSEP_STR, &iter )){
+ before = p;
+ }
+
+ /* If there is one, copy it. */
+ if (before != NULL && *before != '\0') {
+ langwich = dsgw_ch_strdup(before);
+ }
+
+ iter = NULL;
+
+ /* split off any country specification */
+ ldap_utf8strtok_r( langwich, "-", &iter );
+ countri = iter;
+
+ free (path);
+
+}
+
+/*
+ * Accept-Language = "Accept-Language" ":"
+ * 1#( language-range [ ";" "q" "=" qvalue ] )
+ * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+ *
+ * NLS_AccLangList() assumes that "Accept-Language:" has already
+ * been stripped off. It takes as input
+ *
+ * 1#( ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) [ ";" "q" "=" qvalue ] )
+ *
+ * and returns a list of languages, ordered by qvalues, in
+ * the array NLS_ACCEPT_LANGUAGE_LIST.
+ *
+ * If there are to many languages (>NLS_MAX_ACCEPT_LANGUAGE) the excess
+ * is ignored. If the language-range is too long (>NLS_MAX_ACCEPT_LENGTH),
+ * the language-range is ignored. In these cases, NLS_AccLangList()
+ * will quietly return, perhaps with numLang = 0. numLang is
+ * returned by the function.
+ */
+
+
+size_t
+AcceptLangList(const char* AcceptLanguage,
+ ACCEPT_LANGUAGE_LIST AcceptLanguageList)
+{
+ char* input;
+ char* cPtr;
+ char* cPtr1;
+ char* cPtr2;
+ int i;
+ int j;
+ int countLang = 0;
+
+ input = dsgw_ch_strdup(AcceptLanguage);
+ if (input == (char*)NULL){
+ return 0;
+ }
+
+ cPtr1 = input-1;
+ cPtr2 = input;
+
+ /* put in standard form */
+ while (*(++cPtr1)) {
+ if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
+ else if (isspace(*cPtr1)); /* ignore any space */
+ else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
+ else if (*cPtr1=='*'); /* ignore "*" */
+ else *cPtr2++ = *cPtr1; /* else unchanged */
+ }
+ *cPtr2 = '\0';
+
+ countLang = 0;
+
+ if (strchr(input,';')) {
+ /* deal with the quality values */
+
+ float qvalue[MAX_ACCEPT_LANGUAGE];
+ float qSwap;
+ float bias = 0.0f;
+ char* ptrLanguage[MAX_ACCEPT_LANGUAGE];
+ char* ptrSwap;
+
+ cPtr = strtok(input,",");
+ while (cPtr) {
+ qvalue[countLang] = 1.0f;
+ if (cPtr1 = strchr(cPtr,';')) {
+ sscanf(cPtr1,";q=%f",&qvalue[countLang]);
+ *cPtr1 = '\0';
+ }
+ if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
+ qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
+ ptrLanguage[countLang++] = cPtr;
+ if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
+ }
+ cPtr = strtok(NULL,",");
+ }
+
+ /* sort according to decending qvalue */
+ /* not a very good algorithm, but count is not likely large */
+ for ( i=0 ; i<countLang-1 ; i++ ) {
+ for ( j=i+1 ; j<countLang ; j++ ) {
+ if (qvalue[i]<qvalue[j]) {
+ qSwap = qvalue[i];
+ qvalue[i] = qvalue[j];
+ qvalue[j] = qSwap;
+ ptrSwap = ptrLanguage[i];
+ ptrLanguage[i] = ptrLanguage[j];
+ ptrLanguage[j] = ptrSwap;
+ }
+ }
+ }
+ for ( i=0 ; i<countLang ; i++ ) {
+ strcpy(AcceptLanguageList[i],ptrLanguage[i]);
+ }
+
+ } else {
+ /* simple case: no quality values */
+
+ cPtr = strtok(input,",");
+ while (cPtr) {
+ if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
+ strcpy(AcceptLanguageList[countLang++],cPtr);
+ if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
+ }
+ cPtr = strtok(NULL,",");
+ }
+ }
+
+ free(input);
+
+ return countLang;
+}
diff --git a/ldap/clients/dsgw/dsimpldif.c b/ldap/clients/dsgw/dsimpldif.c
new file mode 100644
index 00000000..16550f87
--- /dev/null
+++ b/ldap/clients/dsgw/dsimpldif.c
@@ -0,0 +1,150 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * dsimpldif.c -- CGI import ldif file handler -- directory gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+static void handle_request( int reqmethod );
+static void handle_post();
+
+static char *ldiffile;
+static int erase = 0, stop = 1;
+
+main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+ int reqmethod;
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_POST | DSGW_METHOD_GET );
+ dsgw_send_header();
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ handle_request( reqmethod );
+
+ exit( 0 );
+}
+
+
+#define DSGWCONFIG_EMPTY_IF_NULL( s ) ( (s) == NULL ? "" : (s) )
+
+
+static void
+handle_request( int reqmethod )
+{
+ FILE *fp;
+ char **argv, *buf, line[ BIG_LINE ];
+ char *checked = " CHECKED ";
+ char *str_valuefmt = " VALUE=\"%s\" ";
+ int did_post, argc;
+
+ buf = dsgw_ch_malloc( strlen( progname ) + 6 ); /* room for ".html\0" */
+ sprintf( buf, "%s.html", progname );
+ fp = dsgw_open_html_file( buf, DSGW_ERROPT_EXIT );
+ free( buf );
+ did_post = 0;
+
+ while ( dsgw_next_html_line( fp, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, dsgw_simple_cond_is_true,
+ NULL )) {
+ if ( dsgw_directive_is( line, DRCT_DS_INLINE_POST_RESULTS )) {
+ if ( !did_post && reqmethod == DSGW_METHOD_POST ) {
+ handle_post();
+ did_post = 1;
+ }
+ } else if ( dsgw_directive_is( line, DS_LDIF_FILE )) {
+ dsgw_emitf( str_valuefmt,
+ DSGWCONFIG_EMPTY_IF_NULL( ldiffile ));
+ } else if ( dsgw_directive_is( line, DS_CHECKED_IF_ERASE )) {
+ if ( erase ) {
+ dsgw_emits( checked );
+ }
+ } else if ( dsgw_directive_is( line, DS_CHECKED_IF_NOTERASE )) {
+ if ( !erase ) {
+ dsgw_emits( checked );
+ }
+ } else if ( dsgw_directive_is( line, DS_CHECKED_IF_STOP )) {
+ if ( stop ) {
+ dsgw_emits( checked );
+ }
+ } else if ( dsgw_directive_is( line, DS_CHECKED_IF_NOTSTOP )) {
+ if ( !stop ) {
+ dsgw_emits( checked );
+ }
+ }
+ }
+ }
+
+ fclose( fp );
+}
+
+
+static void
+handle_post()
+{
+ char cmd[ BIG_LINE ], path[BIG_LINE ];
+ char *userdb_path;
+
+ ldiffile = dsgw_get_cgi_var( "ldif", DSGW_CGIVAR_REQUIRED );
+ erase = dsgw_get_boolean_var( "erase", DSGW_CGIVAR_REQUIRED, 0 );
+ stop = dsgw_get_boolean_var( "stop", DSGW_CGIVAR_REQUIRED, 0 );
+
+ if (erase) {
+ if ( gc->gc_localdbconf == NULL) {
+ /* don't erase the real ldap database */
+ dsgw_error( DSGW_ERR_DB_ERASE, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ /* erase the local database */
+ if ( erase_db() != 0 ) {
+ return;
+ }
+ }
+
+ if (( userdb_path = get_userdb_dir()) == NULL ) {
+ dsgw_error( DSGW_ERR_USERDB_PATH, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if (gc->gc_localdbconf == NULL) {
+ /* remote */
+ PR_snprintf (cmd, BIG_LINE, "./%s -a %s -h %s -p %d -f %s > %s 2>&1",
+ DSGW_LDAPMODIFY, stop?"":"-c",gc->gc_ldapserver,
+ gc->gc_ldapport, ldiffile, DSGW_NULL_DEVICE);
+ }
+ else {
+ /* local database */
+ PR_snprintf (cmd, BIG_LINE, "./%s -a %s -C %s -f %s > %s 2>&1",
+ DSGW_LDAPMODIFY, stop?"":"-c", gc->gc_localdbconf, ldiffile,
+ DSGW_NULL_DEVICE);
+ }
+ PR_snprintf (path, BIG_LINE, "%s%s", userdb_path, DSGW_TOOLSDIR);
+ chdir ( path );
+ fflush (stdout);
+ if (system (cmd) == 0) {
+ /*
+ * success: display status message
+ */
+ dsgw_emits(
+ "<FONT SIZE=\"+1\">\n<P>The ldif file has been added.\n</FONT>\n " );
+ }
+ else {
+ dsgw_emits(
+ "<FONT SIZE=\"+1\">\n<P>The ldif file could not be added.\n</FONT>\n " );
+ }
+
+ dsgw_emits( "<HR>\n" );
+}
+
diff --git a/ldap/clients/dsgw/edit.c b/ldap/clients/dsgw/edit.c
new file mode 100644
index 00000000..c67af18f
--- /dev/null
+++ b/ldap/clients/dsgw/edit.c
@@ -0,0 +1,256 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * edit.c -- CGI editable entry display -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+static void get_request(char *dn, char *tmplname,
+ char *parent, unsigned long options);
+
+
+int main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+
+
+ char *dn, *tmplname, *p, *parent;
+ unsigned long options;
+
+ /*
+ * If the QUERY_STRING is non-NULL, it looks like this:
+ *
+ * template [&CONTEXT=context] [ &INFO=infostring ] [ &ADD ] [ &DN=dn ] \
+ * [&DNATTR=attrname&DNDESC=description]
+ *
+ * where:
+ * "template" is the name of the edit template to use for display,
+ * "dn" is escaped dn,
+ * "infostring" is a message used to replace DS_LAST_OP_INFO directives
+ * "attrname" is the name of a DN-valued attribute
+ * "dndesc" is the destriptive name of the above DN-valued attribute
+ *
+ * If "&ADD" is present, we check to make sure the entry
+ * does not exist, then we check that the parent entry exists, and then
+ * we present an "add entry" form.
+ *
+ * Note: original form http://host/edit/dn[/...]?template[&...] is
+ * supported for keeping backward compatibility.
+ * But passing DN as PATH_INFO is NOT recommended.
+ * Since PATH_INFO is passed to CGI as is (non-escaped),
+ * the content has a risk to get broken especially when
+ * it contains 8-bit UTF-8 data. (This is a known problem
+ * on localized Windows machines.)
+ */
+
+ options = DSGW_DISPLAY_OPT_EDITABLE;
+ dn = NULL;
+#ifndef __LP64__
+#ifdef HPUX
+ /* call the static constructors in libnls */
+ _main();
+#endif
+#endif
+
+ if (( tmplname = getenv( "QUERY_STRING" )) != NULL && *tmplname != '\0' ) {
+ tmplname = dsgw_ch_strdup( tmplname );
+ while ( tmplname != NULL && ((( p = strrchr( tmplname, '&' )) != NULL ) || (p=tmplname) != NULL )) {
+ if (p == tmplname) {
+ tmplname = NULL;
+ } else {
+ *p++ = '\0';
+ }
+
+ if ( strcasecmp( p, "add" ) == 0 ) {
+ options |= DSGW_DISPLAY_OPT_ADDING;
+ if (( p = strrchr( tmplname, '&' )) != NULL ) {
+ *p++ = '\0';
+ }
+ }
+
+ if ( p != NULL && strncasecmp( p, "info=", 5 ) == 0 ) {
+ dsgw_last_op_info = dsgw_ch_strdup( p + 5 );
+ dsgw_form_unescape( dsgw_last_op_info );
+ continue;
+ }
+ if ( p != NULL && strncasecmp( p, "dn=", 3 ) == 0 ) {
+ dn = dsgw_ch_strdup( p + 3 );
+ dsgw_form_unescape( dn );
+ continue;
+ }
+ if ( p != NULL && strncasecmp( p, "dnattr=", 7 ) == 0 ) {
+ dsgw_dnattr = dsgw_ch_strdup( p + 7 );
+ dsgw_form_unescape( dsgw_dnattr );
+ continue;
+ }
+ if ( p != NULL && strncasecmp( p, "dndesc=", 7 ) == 0 ) {
+ dsgw_dndesc = dsgw_ch_strdup( p + 7 );
+ dsgw_form_unescape( dsgw_dndesc );
+ continue;
+ }
+ if ( p != NULL && strncasecmp( p, "context=", 8 ) == 0) {
+ context = dsgw_ch_strdup( p + 8 );
+ dsgw_form_unescape( context );
+ continue;
+ }
+
+ /*
+ * If none of the if-statements above matched,
+ * then it's the template name
+ */
+ tmplname = p;
+ break;
+ }
+
+ } else {
+ tmplname = NULL;
+ }
+
+ (void)dsgw_init( argc, argv, DSGW_METHOD_GET );
+ dsgw_send_header();
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ get_request(dn, tmplname, parent, options);
+
+ exit( 0 );
+}
+
+
+static void
+get_request(char *dn, char *tmplname, char *parent, unsigned long options)
+{
+ LDAP *ld;
+
+ if ( dn == NULL ) { /* not found in QUERY_STRING */
+ dsgw_error( DSGW_ERR_MISSINGINPUT, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "get_request: dn: \"%s\", tmplname: \"%s\" "
+ "dnattr: \"%s\", dndesc: \"%s\"\n", dn,
+ ( tmplname == NULL ) ? "(null)" : tmplname,
+ ( dsgw_dnattr == NULL ) ? "(null)" : dsgw_dnattr,
+ ( dsgw_dndesc == NULL ) ? "(null)" : dsgw_dndesc );
+#endif
+
+ (void)dsgw_init_ldap( &ld, NULL, 0, 0);
+
+ if (( options & DSGW_DISPLAY_OPT_ADDING ) == 0 ) {
+ /*
+ * editing an existing entry -- if no DN is provided and we are running
+ * under the admin server, try to get DN from admin. server
+ */
+ if ( *dn == '\0' ) {
+ (void)dsgw_get_adm_identity( ld, NULL, &dn, NULL,
+ DSGW_ERROPT_EXIT );
+ }
+
+ dsgw_read_entry( ld, dn, NULL, tmplname, NULL, options );
+
+ } else {
+ dsgwtmplinfo *tip;
+ char *matched;
+
+ /*
+ * new entry -- check to make sure it doesn't exist
+ */
+ if ( dsgw_ldap_entry_exists( ld, dn, &matched, DSGW_ERROPT_EXIT )) {
+ char **rdns;
+
+ dsgw_html_begin( XP_GetClientStr(DBT_entryAlreadyExists_), 1 );
+ dsgw_emits( XP_GetClientStr(DBT_anEntryNamed_) );
+ rdns = ldap_explode_dn( dn, 1 );
+ dsgw_html_href(
+ dsgw_build_urlprefix(),
+ dn, ( rdns == NULL || rdns[ 0 ] == NULL ) ? dn : rdns[ 0 ],
+ NULL, XP_GetClientStr(DBT_onmouseoverWindowStatusClickHere_) );
+ if ( rdns != NULL ) {
+ ldap_value_free( rdns );
+ }
+ dsgw_emits( XP_GetClientStr(DBT_alreadyExistsPPleaseChooseAnothe_) );
+
+ dsgw_form_begin( NULL, NULL );
+ dsgw_emits( "\n<CENTER><TABLE border=2 width=\"100%\"><TR>\n" );
+ dsgw_emits( "<TD WIDTH=\"50%\" ALIGN=\"center\">\n" );
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"parent.close()\">", XP_GetClientStr(DBT_closeWindow_1) );
+ dsgw_emits( "<TD WIDTH=\"50%\" ALIGN=\"center\">\n" );
+ dsgw_emit_helpbutton( "ENTRYEXISTS" );
+ dsgw_emits( "\n</TABLE></CENTER></FORM>\n" );
+ dsgw_html_end();
+ } else if ( !dsgw_is_dnparent( matched, dn ) &&
+ !dsgw_dn_cmp( dn, gc->gc_ldapsearchbase )) {
+ /*
+ * The parent entry does not exist, and the dn being added is not
+ * the same as the suffix for which the gateway is configured.
+ */
+ dsgw_html_begin( XP_GetClientStr(DBT_parentEntryDoesNotExist_), 1 );
+ dsgw_emitf( XP_GetClientStr(DBT_youCannotAddAnEntryByTheNamePBSB_),
+ dn );
+ parent = dsgw_dn_parent( dn );
+ if ( parent == NULL || strlen( parent ) == 0 ) {
+ dsgw_emits( XP_GetClientStr(DBT_itsParentN_) );
+ } else {
+ dsgw_emitf( XP_GetClientStr(DBT_anEntryNamedPBSBN_), parent );
+ free( parent );
+ }
+ dsgw_form_begin( NULL, NULL );
+ dsgw_emits( "\n<CENTER><TABLE border=2 width=\"100%\"><TR>\n" );
+ dsgw_emits( "<TD WIDTH=\"50%\" ALIGN=\"center\">\n" );
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"parent.close()\">", XP_GetClientStr(DBT_closeWindow_2) );
+ dsgw_emits( "<TD WIDTH=\"50%\" ALIGN=\"center\">\n" );
+ dsgw_emit_helpbutton( "ADD_NOPARENT" );
+ dsgw_emits( "\n</TABLE></CENTER></FORM>\n" );
+ dsgw_html_end();
+ } else {
+ /*
+ * The parent exists, or the user is adding the entry whose DN
+ * is the same as the suffix for which the gateway is configured.
+ * Display the "add entry" form.
+ */
+
+ if ( tmplname == NULL ) {
+#ifdef DSGW_DEBUG
+ dsgw_log( "NULL tmplname\n" );
+#endif
+ dsgw_error( DSGW_ERR_MISSINGINPUT,
+ XP_GetClientStr(DBT_missingTemplate_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ tip = dsgw_display_init( DSGW_TMPLTYPE_DISPLAY, tmplname, options );
+
+ dsgw_display_entry( tip, ld, NULL, NULL, dn );
+ dsgw_display_done( tip );
+ }
+ }
+
+ ldap_unbind( ld );
+}
+
+
+
+
+
+
+
+
+
+
diff --git a/ldap/clients/dsgw/emitauth.c b/ldap/clients/dsgw/emitauth.c
new file mode 100644
index 00000000..e8b8c076
--- /dev/null
+++ b/ldap/clients/dsgw/emitauth.c
@@ -0,0 +1,317 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * emitauth.c -- generate authentication form -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+static int isexp = 0; /* Why is this static? */
+
+static void
+emit_authinfo( int isEditing, int isPwForm, char *binddn )
+{
+ char *cookie, *dn, *rndstr, *pw;
+ int rc;
+ int isauth = 0;
+
+ /* try to get the DN the user is bound as, and determine if
+ * authentication credentials have expired.
+ */
+ if (( cookie = dsgw_get_auth_cookie()) != NULL ) {
+ if ( dsgw_parse_cookie( cookie, &rndstr, &dn ) == 0 ) {
+ if ( dn == NULL ) {
+ isauth = 0;
+ } else {
+ if (( rc = dsgw_ckdn2passwd( rndstr, dn, &pw )) == 0 ) {
+ isauth = 1;
+ } else {
+ isauth = 0;
+ if ( rc == DSGW_CKDB_EXPIRED ) {
+ isexp = 1;
+ }
+ }
+ }
+ } else {
+ isauth = 0;
+ }
+ } else {
+ isauth = 0;
+ }
+
+ dsgw_emitf( "<CENTER>\n"
+ "<FONT SIZE=+2>%s</FONT>\n"
+ "</CENTER>\n"
+ "<p>", XP_GetClientStr(DBT_authenticateLogInToTheDirectory_) );
+
+ if ( isPwForm ) {
+#ifdef NOTFORNOW
+ /* ldap_dn2ufn currently gobble up 'dc' so don't use it for */
+ /* now */
+ auto char *ufn = ldap_dn2ufn( binddn );
+ dsgw_emitf( XP_GetClientStr(DBT_youAreAboutToAuthenticate_), ufn);
+ free( ufn );
+#else
+ dsgw_emitf( XP_GetClientStr(DBT_youAreAboutToAuthenticate_), binddn);
+#endif
+ } else if ( isEditing ) {
+ dsgw_emits( XP_GetClientStr(DBT_beforeYouCanEditOrAddEntriesYouM_) );
+ } else {
+ dsgw_emits( XP_GetClientStr(DBT_fromThisScreenYouMayAuthenticate_) );
+ }
+ if ( isEditing ) {
+ return;
+ }
+ dsgw_emitf( "<HR>\n"
+ "<CENTER>\n"
+ "<FONT SIZE=+2>%s</FONT>\n"
+ "</CENTER>\n"
+ "<P>\n", XP_GetClientStr(DBT_authenticationStatus_) );
+
+ if ( isauth ) {
+ auto char *ufn;
+ dsgw_emits( XP_GetClientStr(DBT_FormNyouAreCurrentlyAuthenticate_) );
+ ufn = ldap_dn2ufn( dn );
+ dsgw_emitf( "<b>%s</b>\n", ufn );
+ free( ufn );
+ dsgw_emitf( "%s<BR>"
+ "<CENTER>\n"
+ "<INPUT TYPE=BUTTON "
+ "VALUE=\"%s\""
+ "onClick=\"doUnauth();\">\n"
+ "</FORM>\n"
+ "</CENTER>\n"
+ "<HR>\n",
+ XP_GetClientStr(DBT_NifYouWishToDiscardYourAuthentic_),
+ XP_GetClientStr(DBT_discardAuthenticationCredentials_2) );
+ } else if ( isexp ) {
+ dsgw_emits( XP_GetClientStr(DBT_yourAuthenticationCredentialsFor_) );
+ dsgw_emitf( "<b>%s</b> ", dn );
+ dsgw_emits( XP_GetClientStr(DBT_haveExpiredN_) );
+ } else {
+ dsgw_emits( XP_GetClientStr(DBT_currentlyYouAreNotAuthenticatedT_) );
+ }
+}
+
+
+static void
+emit_file (char* filename, char* authdesturl, char *user )
+{
+ auto FILE* html = dsgw_open_html_file( filename, DSGW_ERROPT_EXIT );
+ auto char line[ BIG_LINE ];
+ auto int argc;
+ auto char **argv, *escaped_dn;
+
+ if ( user != NULL ) {
+ escaped_dn = dsgw_strdup_escaped( user );
+ } else {
+ escaped_dn = "";
+ }
+
+ while ( dsgw_next_html_line( html, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, dsgw_simple_cond_is_true, NULL )) {
+ if ( dsgw_directive_is( line, DRCT_HEAD )) {
+ dsgw_head_begin();
+ dsgw_emits ("\n");
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_SEARCH_SCRIPT" )) {
+ dsgw_emits ("<SCRIPT NAME=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript browsers\n"
+ "function doUnauth()\n"
+ "{\n");
+ dsgw_emits (" if ( confirm( ");
+ dsgw_quote_emits (QUOTATION_JAVASCRIPT,
+ XP_GetClientStr(DBT_discardAuthenticationCredentials_));
+ dsgw_emits (" )) {\n"
+ " window.location.href='unauth?context=");
+ dsgw_emits(context);
+ dsgw_emits("';\n"
+ " }\n"
+ "}\n");
+#if 0 /* This doesn't work with Navigator 2.x */
+ dsgw_emits ("function checkSS(sform)\n"
+ "{\n"
+ " if (sform.searchstring.value == null || sform.searchstring.value == \"\") {\n");
+ dsgw_emit_alert (NULL, NULL, XP_GetClientStr(DBT_youDidNotSupplyASearchString_));
+ dsgw_emits (" return false;\n"
+ " }\n"
+ "}\n");
+#endif
+ dsgw_emits ("function init()\n"
+ "{\n"
+ " document.authSearchForm.searchstring.select();\n"
+ " document.authSearchForm.searchstring.focus();\n"
+ " if (top.history.length == 1 && top.opener != null && top.opener.location.href != "
+ "top.location.href) {\n"
+ " if (top.closewin == true) {\n"
+ " top.opener.document.clear();\n"
+ " top.opener.document.open();\n"
+ " top.opener.document.write('');\n"
+ " top.opener.document.close();\n"
+ " }\n"
+ " }\n"
+ " top.closewin = false;\n"
+ "}\n"
+ "// End hiding -->\n"
+ "</SCRIPT>\n");
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_SEARCH_BODY" )) {
+ dsgw_emitf ("<BODY onLoad=\"setTimeout('init()', 10);\" %s>\n",
+ dsgw_html_body_colors);
+ dsgw_emit_alertForm();
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_SEARCH_INFO" )) {
+ emit_authinfo( authdesturl != NULL, 0, NULL );
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_SEARCH_FORM" )) {
+ dsgw_form_begin ("authSearchForm", "action=\"dosearch\""
+#if 0 /* This doesn't work with Navigator 2.x */
+ " onSubmit=\"return checkSS(this)\""
+#endif
+ );
+ dsgw_emits ("\n<INPUT TYPE=hidden NAME=mode VALUE=\"auth\">\n");
+ if ( authdesturl != NULL ) {
+ dsgw_emitf ("<INPUT TYPE=hidden NAME=authdesturl VALUE=\"%s\">\n",
+ authdesturl);
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_SEARCH_NAME" )) {
+ dsgw_emitf ("<INPUT NAME=\"searchstring\" VALUE=\"%s\" SIZE=40>\n",
+ ( user == NULL ) ? "" : user );
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_SEARCH_BUTTONS" )) {
+ if ( authdesturl == NULL ) {
+ dsgw_emitf ("<TD ALIGN=CENTER WIDTH=50%%>\n"
+ "<INPUT TYPE=\"submit\" VALUE=\"%s\">\n"
+ "<TD ALIGN=CENTER WIDTH=50%%>\n",
+ XP_GetClientStr(DBT_continue_) );
+ } else {
+ dsgw_emitf ("<TD ALIGN=CENTER WIDTH=33%%>\n"
+ "<INPUT TYPE=\"submit\" VALUE=\"%s\">\n"
+ "<TD ALIGN=CENTER WIDTH=33%%>\n"
+ "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"parent.close();\">\n"
+ "<TD ALIGN=CENTER WIDTH=34%%>\n",
+ XP_GetClientStr(DBT_continue_1), XP_GetClientStr(DBT_cancel_) );
+ }
+ dsgw_emit_helpbutton ("AUTHHELP_ID" );
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_AS_ROOT_FORM" )) {
+ dsgw_form_begin ("AuthAsRootDNForm", "action=\"auth\"");
+ dsgw_emits ("\n");
+ dsgw_emits ("<INPUT TYPE=hidden NAME=authasrootdn VALUE=\"true\">\n");
+ if ( authdesturl != NULL ) {
+ dsgw_emitf ("<INPUT TYPE=hidden NAME=authdesturl VALUE=\"%s\">\n",
+ authdesturl );
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_PASSWORD_SCRIPT" )) {
+ dsgw_emits ("<SCRIPT NAME=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript browsers\n");
+ /* doUnauth function - invoke CGI which tosses cookies. */
+ dsgw_emitf ("function doUnauth()\n"
+ "{\n"
+ " if ( confirm( '%s' )) {\n"
+ " window.location.href='unauth?context=%s';\n"
+ " }\n"
+ "}\n"
+ "// End hiding -->\n"
+ "</SCRIPT>\n\n",
+ XP_GetClientStr (DBT_discardAuthenticationCredentials_1), context);
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_PASSWORD_BODY" )) {
+ dsgw_emitf ("<BODY onLoad=\"document.authPwForm.password.select();document.authPwForm.password.focus();\" %s>\n",
+ dsgw_html_body_colors );
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_PASSWORD_INFO" )) {
+ emit_authinfo( authdesturl != NULL, 1, user );
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_PASSWORD_FORM" )) {
+ dsgw_form_begin( "authPwForm", "action=\"doauth\"" );
+ dsgw_emits ("\n" );
+ dsgw_emitf (
+ "<INPUT type=hidden name=escapedbinddn value=\"%s\">\n",
+ escaped_dn );
+ if ( authdesturl != NULL ) {
+ dsgw_emitf ("<INPUT type=hidden name=authdesturl value=\"%s\">\n",
+ authdesturl );
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_PASSWORD_NAME" )) {
+ auto char** xdn = ldap_explode_dn( user, 1 );
+ dsgw_emits( xdn[ 0 ] );
+ ldap_value_free( xdn );
+
+ } else if ( dsgw_directive_is( line, "DS_AUTH_PASSWORD_BUTTONS" )) {
+ if ( authdesturl == NULL ) {
+ dsgw_emitf ("<TD ALIGN=CENTER WIDTH=50%%>\n"
+ "<INPUT TYPE=\"submit\" VALUE=\"%s\">\n"
+ "<TD ALIGN=CENTER WIDTH=50%%>\n",
+ XP_GetClientStr(DBT_continue_2) );
+ } else {
+ dsgw_emitf ("<TD ALIGN=CENTER WIDTH=33%%>\n"
+ "<INPUT TYPE=\"submit\" VALUE=\"%s\">\n"
+ "<TD ALIGN=CENTER WIDTH=33%%>\n"
+ "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"parent.close();\">\n"
+ "<TD ALIGN=CENTER WIDTH=34%%>\n",
+ XP_GetClientStr(DBT_continue_3), XP_GetClientStr(DBT_cancel_1) );
+ }
+ dsgw_emit_helpbutton ("AUTHHELP_PW" );
+
+ } else if ( dsgw_directive_is( line, "DS_HELP_BUTTON" ) && argc > 0) {
+ dsgw_emit_helpbutton (argv[0]);
+ } else {
+ dsgw_emits (line);
+ }
+ dsgw_argv_free( argv );
+ }
+ }
+ fflush (stdout);
+ fclose (html);
+}
+
+
+void
+dsgw_emit_auth_form( char *binddn )
+{
+ dsgw_emit_auth_dest( binddn, dsgw_get_cgi_var( "authdesturl", DSGW_CGIVAR_OPTIONAL ));
+}
+
+void
+dsgw_emit_auth_dest( char *binddn, char* authdesturl )
+{
+ /*
+ * If dn is NULL, then we don't know who we want to bind as yet.
+ * Generate a simplified search form. This form needs to post:
+ * mode=auth
+ * searchstring
+ * authdesturl
+ *
+ * If dn was given, then prompt for the password. Needs to post:
+ * password
+ * authdesturl
+ * binddn
+ */
+ if ( binddn == NULL ) {
+ emit_file( "authSearch.html", authdesturl,
+ dsgw_get_cgi_var( "authhint", DSGW_CGIVAR_OPTIONAL ));
+ } else {
+ emit_file( "authPassword.html", authdesturl, binddn );
+ }
+}
+
+
+
+
+
+
+
diff --git a/ldap/clients/dsgw/emitf.c b/ldap/clients/dsgw/emitf.c
new file mode 100644
index 00000000..b4e6c709
--- /dev/null
+++ b/ldap/clients/dsgw/emitf.c
@@ -0,0 +1,860 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+#include <stdarg.h> /* va_list etc. */
+#include <stdio.h> /* sprintf */
+#include <stdlib.h> /* malloc, realloc, free */
+#include <string.h> /* strchr, strpbrk etc. */
+#include "dsgw.h" /* dsgw_ch_malloc, dsgw_ch_strdup */
+
+typedef void* (*dsgw_producer) (void*, const char*, size_t);
+
+static size_t
+produce_fill (dsgw_producer produce, void** parm,
+ size_t fill, unsigned zero)
+{
+ static const char* zeroes = "00000000";
+ static const char* blanks = " ";
+ size_t result = 0;
+ while (fill > 0) {
+ long n = fill;
+ if (n > 8) n = 8;
+ if (zero) {
+ *parm = produce (*parm, zeroes, n);
+ } else {
+ *parm = produce (*parm, blanks, n);
+ }
+ if (*parm == NULL) return result;
+ result += n;
+ fill -= n;
+ }
+ return result;
+}
+
+#define FLAG_LEFT 1 /* align left */
+#define FLAG_ZERO 2 /* zero fill */
+#define FLAG_CONST 4
+
+static size_t
+produce_string (dsgw_producer produce, void** parm,
+ const char* str, unsigned flags, int width, int precision)
+{
+ size_t fill;
+ size_t bytes;
+ size_t result = 0;
+ if (*parm == NULL) return result;
+ if (width < 0) {
+ width = - width;
+ flags ^= FLAG_LEFT;
+ }
+ if (width == 0 && precision < 0) {
+ fill = 0;
+ bytes = strlen (str);
+ } else {
+ char* s = (char*)str; /* cast away const (for LDAP_UTF8INC) */
+ size_t chars = 0;
+ while (*s && ((precision < 0) || (chars < precision))) {
+ LDAP_UTF8INC(s);
+ ++chars;
+ }
+ fill = (width > chars) ? (width - chars) : 0;
+ bytes = (s - str);
+ }
+ if (fill && ! (flags & FLAG_LEFT)) {
+ result += produce_fill (produce, parm, fill, flags & FLAG_ZERO);
+ }
+ if (bytes) {
+ *parm = produce (*parm, str, bytes);
+ if (*parm == NULL) return result;
+ result += bytes;
+ }
+ if (fill && (flags & FLAG_LEFT)) {
+ result += produce_fill (produce, parm, fill, flags & FLAG_ZERO);
+ }
+ return result;
+}
+
+static const char* type_chars = "%dioxXueEgGfcsp";
+
+static size_t
+count_slots (const char* s)
+{
+ size_t n = 0;
+ while ((s = strchr (s, '%')) != NULL) {
+ const char* l = strpbrk (s+1, type_chars);
+ const char* c;
+ if (l == NULL) {
+ n += 3;
+ break;
+ }
+ ++n;
+ for (c = s+1; c != l; ++c) {
+ if (*c == '*') ++n;
+ }
+ s = *l ? l+1 : l;
+ }
+ return n;
+}
+
+typedef struct {
+ char type;
+#define TYPE_I 0
+#define TYPE_U 1
+#define TYPE_F 2
+#define TYPE_LI 3
+#define TYPE_LU 4
+#define TYPE_LF 5
+#define TYPE_S 6
+#define TYPE_P 7
+#define TYPE_PERCENT 8 /* e.g. %% */
+#define TYPE_WIDTH 9
+#define TYPE_PRECISION 10
+
+ unsigned char flags;
+ int arg; /* An index into an array of dsgw_arg_t,
+ or (if flags & FLAG_CONST) the width or precision value. */
+} dsgw_slot_t;
+
+typedef union {
+ int i;
+ unsigned int u;
+ double f;
+ long li;
+ unsigned long lu;
+ long double lf;
+ const char* s;
+ void* p;
+} dsgw_arg_t;
+
+#define DEFSLOTC 8 /* A format string rarely contains more slots. */
+#define DEFFMTC 16 /* A single format rarely contains more chars. */
+
+static size_t
+dsgw_vxprintf (dsgw_producer produce, void* parm,
+ const char* format, va_list argl)
+ /* This function works like vsprintf(), except it:
+ - supports parameter reordering, using %posp$.
+ - is UTF8-aware.
+ - delivers output by calling the function 'produce'.
+ - returns the total number of bytes produced.
+ This function interprets all string parameters as UTF8.
+ */
+{
+ size_t result = 0; /* total number of bytes produced */
+
+ /* Each place that 'format' refers to an argument is called a 'slot'. */
+ dsgw_slot_t defslot[DEFSLOTC];
+ dsgw_slot_t* slot = defslot; /* in order of their appearance in format */
+ dsgw_slot_t* islot = NULL; /* next slot to process */
+ dsgw_slot_t* aslot = NULL; /* another cursor */
+
+ dsgw_arg_t defargv[DEFSLOTC];
+ dsgw_arg_t* argv = defargv; /* in order of their appearance in argl */
+ size_t argi = 0; /* index of next argument (in argl/argv) */
+
+ char deffmt[DEFFMTC];
+ char* fmt = deffmt;
+ size_t fmtc = DEFFMTC;
+
+ const char* next;
+ const char* f;
+
+ char buf [1024];
+ int i;
+
+ i = count_slots (format);
+/*fprintf (stderr, "slots: %i\n", i);*/
+ if (i > DEFSLOTC) { /* defslot isn't big enough. */
+ slot = (dsgw_slot_t*) malloc (i * sizeof(dsgw_slot_t));
+ }
+
+ /* get slot types from format: */
+ islot = slot;
+ next = format;
+ while ((f = strchr (next, '%')) != NULL) {
+ const char* l = f+1;
+ unsigned flags = 0;
+ int number = -1;
+ char size;
+
+ if (*l >= '1' && *l <= '9') {
+ number = 0;
+ do { number = (number * 10) + (*l++ - '0');
+ } while (*l >= '0' && *l <= '9');
+ }
+ if (*l == '$') {
+ ++l;
+ if (number > 0) {
+ argi = number - 1;
+ }
+ number = -1;
+ }
+ if (number >= 0) { /* width */
+ islot->arg = number;
+ flags |= FLAG_CONST;
+ } else {
+ while (1) { /* flags */
+ switch (*l) {
+ case '-': flags |= FLAG_LEFT; ++l; continue;
+ case '0': flags |= FLAG_ZERO; ++l; continue;
+ case '+':
+ case ' ':
+ case '#': ++l; continue;
+ default: break;
+ }
+ break;
+ }
+ if (*l == '*') { /* width */
+ number = 0;
+ ++l;
+ islot->arg = argi++;
+ } else if (*l >= '1' && *l <= '9') { /* width */
+ number = 0;
+ do { number = (number * 10) + (*l++ - '0');
+ } while (*l >= '0' && *l <= '9');
+ islot->arg = number;
+ flags |= FLAG_CONST;
+ }
+ }
+ if (number >= 0) {
+ islot->type = TYPE_WIDTH;
+ islot->flags = flags;
+ flags &= ~ FLAG_CONST;
+ ++islot;
+ }
+ if (*l == '.') {
+ islot->type = TYPE_PRECISION;
+ ++l;
+ if (*l == '*') {
+ ++l;
+ islot->arg = argi++;
+ islot->flags = 0;
+ } else {
+ number = 0;
+ while (*l >= '0' && *l <= '9')
+ number = (number * 10) + (*l++ - '0');
+ islot->arg = number;
+ islot->flags = FLAG_CONST;
+ }
+ ++islot;
+ }
+ switch (*l) { /* size modifier */
+ case 'h':
+ case 'l':
+ case 'L': size = *l++; break;
+ default: size = '\0';
+ }
+ islot->flags = 0;
+ switch (*l) { /* type */
+ case 'd':
+ case 'i': islot->type = (size == 'l') ? TYPE_LI : TYPE_I; break;
+ case 'o':
+ case 'x': case 'X':
+ case 'u': islot->type = (size == 'l') ? TYPE_LU : TYPE_U; break;
+ case 'e': case 'E':
+ case 'g': case 'G':
+ case 'f': islot->type = (size == 'L') ? TYPE_LF : TYPE_F; break;
+ case 'c': islot->type = TYPE_I; break;
+ case 's': islot->type = TYPE_S; break;
+ case 'p': islot->type = TYPE_P; break;
+ case '%': islot->type = TYPE_PERCENT;
+ islot->flags = FLAG_CONST; break;
+ default: /* unknown type */
+ goto bail; /* don't produce anything. */
+ /* It might be more helpful to produce the slots up to
+ this one, and maybe output this format substring, too.
+ That way, someone reading the output might get a clue
+ what went wrong.
+ */
+ }
+ if (islot->type != TYPE_PERCENT) {
+ islot->arg = argi++;
+ }
+ ++islot;
+ next = *l ? l+1 : l;
+ }
+
+ /* argi = the length of argl/argv: */
+ argi = 0;
+ for (aslot = slot; aslot != islot; ++aslot) {
+ if (argi <= aslot->arg && ! (aslot->flags & FLAG_CONST)) {
+ argi = aslot->arg + 1;
+ }
+ }
+ if (argi > DEFSLOTC) { /* defargv isn't big enough */
+ argv = (dsgw_arg_t*) malloc (argi * sizeof(dsgw_arg_t));
+ }
+
+ /* copy arguments from argl to argv: */
+/*fprintf (stderr, "slot:type:value:");*/
+ for (i = 0; i < argi; ++i) {
+ for (aslot = slot; aslot != islot; ++aslot) {
+ if ( ! (aslot->flags & FLAG_CONST) && aslot->arg == i) {
+ break;
+ }
+ }
+ if (aslot == islot) { /* No slot refers to this arg. */
+ if (va_arg (argl, const char*)); /* Skip over it. */
+ } else {
+/*fprintf (stderr, " %i:%i", (int)(aslot-slot), aslot->type);*/
+ switch (aslot->type) {
+ case TYPE_U: argv[i].u = va_arg (argl, unsigned); break;
+ case TYPE_F: argv[i].f = va_arg (argl, double); break;
+ case TYPE_LI: argv[i].li = va_arg (argl, long); break;
+ case TYPE_LU: argv[i].lu = va_arg (argl, unsigned long); break;
+ case TYPE_LF: argv[i].lf = va_arg (argl, long double); break;
+ case TYPE_P: argv[i].p = va_arg (argl, void*); break;
+ case TYPE_S: argv[i].s = va_arg (argl, const char*);
+/*fprintf (stderr, ":\"%s\"", argv[i].s);*/
+ break;
+ case TYPE_PERCENT: break; /* no arg */
+ case TYPE_WIDTH:
+ case TYPE_PRECISION:
+ case TYPE_I: argv[i].i = va_arg (argl, int);
+/*fprintf (stderr, ":%i", argv[i].i);*/
+ do {
+ switch (aslot->type) {
+ case TYPE_WIDTH:
+ case TYPE_PRECISION:
+ if ( ! (aslot->flags & FLAG_CONST) && aslot->arg == i) {
+ aslot->arg = argv[i].i;
+ aslot->flags |= FLAG_CONST;
+ }
+ break;
+ default: break;
+ }
+ } while (++aslot != islot);
+ break;
+ }
+ }
+ }
+/*fprintf (stderr, "\n");*/
+
+ /* produce output: */
+ islot = slot;
+ next = format;
+ while (parm && (f = strchr (next, '%'))) {
+ const char* l = strpbrk (f+1, type_chars);
+ if (l == NULL) {
+ break;
+ }
+ if (parm && f != next) { /* produce the substring next..f-1 */
+ const size_t n = (f - next);
+ parm = produce (parm, next, n);
+ if (parm) result += n;
+ }
+ next = l + 1;
+ { /* fmt = f..l */
+ const char* dollar;
+ const size_t fc = (next - f);
+ if (fmtc <= fc) {
+ fmtc = fc + 1;
+ if (fmt == deffmt) fmt = malloc (fmtc);
+ else fmt = realloc (fmt, fmtc);
+ }
+ memcpy (fmt, f, fc);
+ fmt[fc] = '\0';
+ if ((dollar = strchr (fmt, '$')) != NULL) {
+ /* remove posp$ from the beginning of fmt */
+ memmove (fmt + 1, dollar + 1, fc - (dollar - fmt));
+ }
+/*fprintf (stderr, "fmt: \"%s\"\n", fmt);*/
+ }
+ /* produce a single argument */
+ switch (islot->type) {
+ case TYPE_I: PR_snprintf (buf, 1024, fmt, argv[islot->arg].i); break;
+ case TYPE_U: PR_snprintf (buf, 1024, fmt, argv[islot->arg].u); break;
+ case TYPE_F: PR_snprintf (buf, 1024, fmt, argv[islot->arg].f); break;
+ case TYPE_LI: PR_snprintf (buf, 1024, fmt, argv[islot->arg].li); break;
+ case TYPE_LU: PR_snprintf (buf, 1024, fmt, argv[islot->arg].lu); break;
+ case TYPE_LF: PR_snprintf (buf, 1024, fmt, argv[islot->arg].lf); break;
+ case TYPE_P: PR_snprintf (buf, 1024, fmt, argv[islot->arg].p); break;
+ case TYPE_WIDTH:
+ case TYPE_PRECISION:
+ switch ((++islot)->type) {
+ case TYPE_I: PR_snprintf (buf, 1024, fmt, argv[islot->arg].i); break;
+ case TYPE_U: PR_snprintf (buf, 1024, fmt, argv[islot->arg].u); break;
+ case TYPE_F: PR_snprintf (buf, 1024, fmt, argv[islot->arg].f); break;
+ case TYPE_LI: PR_snprintf (buf, 1024, fmt, argv[islot->arg].li); break;
+ case TYPE_LU: PR_snprintf (buf, 1024, fmt, argv[islot->arg].lu); break;
+ case TYPE_LF: PR_snprintf (buf, 1024, fmt, argv[islot->arg].lf); break;
+ case TYPE_P: PR_snprintf (buf, 1024, fmt, argv[islot->arg].p); break;
+ case TYPE_WIDTH:
+ case TYPE_PRECISION:
+ switch ((++islot)->type) {
+ case TYPE_I: PR_snprintf (buf, 1024, fmt, argv[islot->arg].i); break;
+ case TYPE_U: PR_snprintf (buf, 1024, fmt, argv[islot->arg].u); break;
+ case TYPE_F: PR_snprintf (buf, 1024, fmt, argv[islot->arg].f); break;
+ case TYPE_LI: PR_snprintf (buf, 1024, fmt, argv[islot->arg].li); break;
+ case TYPE_LU: PR_snprintf (buf, 1024, fmt, argv[islot->arg].lu); break;
+ case TYPE_LF: PR_snprintf (buf, 1024, fmt, argv[islot->arg].lf); break;
+ case TYPE_P: PR_snprintf (buf, 1024, fmt, argv[islot->arg].p); break;
+ case TYPE_WIDTH:
+ case TYPE_PRECISION: goto bail; /* how did this happen? */
+ case TYPE_PERCENT:
+ case TYPE_S: /* with width and precision */
+ result += produce_string (produce, &parm,
+ (islot->type == TYPE_S) ? argv[islot->arg].s : "%",
+ islot[-2].flags, islot[-2].arg, islot[-1].arg);
+ goto skip_buf;
+ }
+ break;
+ case TYPE_PERCENT:
+ case TYPE_S: /* with width or precision (not both) */
+ if (islot[-1].type == TYPE_WIDTH) {
+ result += produce_string (produce, &parm,
+ (islot->type == TYPE_S) ? argv[islot->arg].s : "%",
+ islot[-1].flags, islot[-1].arg, -1);
+ } else {
+ result += produce_string (produce, &parm,
+ (islot->type == TYPE_S) ? argv[islot->arg].s : "%",
+ 0, 0, islot[-1].arg);
+ }
+ goto skip_buf;
+ }
+ break;
+ case TYPE_PERCENT:
+ case TYPE_S: /* with neither width nor precision */
+ result += produce_string (produce, &parm,
+ (islot->type == TYPE_S) ? argv[islot->arg].s : "%",
+ 0, 0, -1);
+ goto skip_buf;
+ }
+ if (parm && *buf) { /* produce buf */
+ const size_t n = strlen (buf);
+ parm = produce (parm, buf, n);
+ if (parm) result += n;
+ }
+ skip_buf:
+ ++islot;
+ }
+ if (parm && *next) { /* produce the remainder of format */
+ const size_t n = strlen (next);
+ parm = produce (parm, next, n);
+ if (parm) result += n;
+ }
+
+ bail:
+ if (fmt != deffmt) free (fmt);
+ if (argv != defargv) free (argv);
+ if (slot != defslot) free (slot);
+/*fprintf (stderr, "------\n");*/
+ return result;
+}
+
+size_t
+dsgw_fputn (FILE* f, const char* s, size_t n)
+{
+ auto const size_t result =
+ fwrite (s, sizeof(char), n, f);
+ dsgw_log_out (s, result);
+ return result;
+}
+
+static const char*
+strnbrk (const char* str, size_t n, const char* brk)
+{
+ for (; n > 0; ++str, --n) {
+ if (strchr (brk, *str)) {
+ return str;
+ }
+ }
+ return NULL;
+}
+
+static int quotation_depth = 0;
+static int quotation_type[4]; /* maximum depth */
+#define QUOTATION_JAVASCRIPT_ENDOFLINE 1
+
+static size_t
+dsgw_emitr (int depth, const char* s, size_t n)
+{
+ static const char* linebreak = "' +\n'";
+ static const size_t linebreak_len = 5;
+ auto size_t result = 0;
+ if (n == 0) {
+ return 0;
+ } else if (depth == 0) {
+ return dsgw_fputn (stdout, s, n);
+ }
+ --depth;
+ switch (quotation_type[depth]) {
+ case QUOTATION_JAVASCRIPT:
+ case QUOTATION_JAVASCRIPT_MULTILINE:
+ case QUOTATION_JAVASCRIPT_ENDOFLINE:
+ {
+ auto const char* t;
+ for (t = s; (t = strnbrk (t, n, "'\\\n")) != NULL; ++t) {
+ switch (*t) {
+ case '\n': /* output \n */
+ if (t != s) {
+ if (quotation_type[depth] == QUOTATION_JAVASCRIPT_ENDOFLINE) {
+ dsgw_emitr (depth, linebreak, linebreak_len);
+ }
+ result += dsgw_emitr (depth, s, t - s);
+ }
+ if (dsgw_emitr (depth, "\\n", 2) > 1) ++result;
+ if (quotation_type[depth] == QUOTATION_JAVASCRIPT_MULTILINE) {
+ quotation_type[depth] = QUOTATION_JAVASCRIPT_ENDOFLINE;
+ }
+ break;
+ default: /* insert \ */
+ if (quotation_type[depth] == QUOTATION_JAVASCRIPT_ENDOFLINE) {
+ quotation_type[depth] = QUOTATION_JAVASCRIPT_MULTILINE;
+ dsgw_emitr (depth, linebreak, linebreak_len);
+ }
+ result += dsgw_emitr (depth, s, t - s);
+ dsgw_emitr (depth, "\\", 1);
+ result += dsgw_emitr (depth, t, 1);
+ break;
+ }
+ n -= (t - s) + 1;
+ s = t + 1;
+ }
+ }
+ if (n > 0 &&
+ quotation_type[depth] == QUOTATION_JAVASCRIPT_ENDOFLINE) {
+ quotation_type[depth] = QUOTATION_JAVASCRIPT_MULTILINE;
+ dsgw_emitr (depth, linebreak, linebreak_len);
+ }
+ break;
+ default:
+ break;
+ }
+ if (n > 0) {
+ result += dsgw_emitr (depth, s, n);
+ }
+ return result;
+}
+
+static size_t
+dsgw_emitq (FILE* f, const char* s, size_t n)
+{
+ if (f == stdout && quotation_depth > 0) {
+ return dsgw_emitr (quotation_depth, s, n);
+ }
+ return dsgw_fputn (f, s, n);
+}
+
+void
+dsgw_quotation_begin (int kind)
+{
+ if (quotation_depth >= 4) exit (4);
+ switch (kind) {
+ case QUOTATION_JAVASCRIPT:
+ case QUOTATION_JAVASCRIPT_MULTILINE:
+ dsgw_emitq (stdout, "'", 1);
+ break;
+ default:
+ break;
+ }
+ quotation_type[quotation_depth++] = kind;
+}
+
+void
+dsgw_quotation_end()
+{
+ if (quotation_depth > 0) switch (quotation_type[--quotation_depth]) {
+ case QUOTATION_JAVASCRIPT:
+ case QUOTATION_JAVASCRIPT_MULTILINE:
+ case QUOTATION_JAVASCRIPT_ENDOFLINE:
+ dsgw_emitq (stdout, "'", 1);
+ break;
+ default:
+ break;
+ }
+}
+
+int
+dsgw_quote_emits (int kind, const char* s)
+{
+ int result;
+ dsgw_quotation_begin (kind);
+ result = dsgw_emits (s);
+ dsgw_quotation_end();
+ return result;
+}
+
+int
+dsgw_quote_emitf (int kind, const char* format, ...)
+{
+ int result;
+ va_list argl;
+ va_start (argl, format);
+ dsgw_quotation_begin (kind);
+ result = dsgw_emitfv (format, argl);
+ dsgw_quotation_end();
+ va_end (argl);
+ return result;
+}
+
+static UConverter* emit_converter = NULL;
+
+/* given string is utf8 - emit_converter converts given string
+ to some natural language encoding requested by the client */
+void*
+dsgw_emitn (void* parm, const char* s, size_t n)
+{
+ if (emit_converter == NULL) {
+ if (dsgw_emitq ((FILE*)parm, s, n) != n) {
+ return NULL;
+ }
+ } else {
+#define CONVERT_BUFSIZE 2048
+ char buf [CONVERT_BUFSIZE]; /* faster than malloc/free */
+ char *bufptr = buf;
+ size_t len = 0;
+ size_t slen = 0;
+ UErrorCode err = U_ZERO_ERROR;
+ int result;
+
+ do {
+ bufptr = buf; /* reset to beginning of buf */
+ s += slen; /* advance pointer to next unconverted chars */
+ /* convert as many chars from s as will fit in buf */
+ result = dsgw_convert(DSGW_FROM_UTF8, emit_converter,
+ &bufptr, CONVERT_BUFSIZE, &len,
+ s, n, &slen, &err);
+ /* write the converted chars to the output */
+ n = dsgw_emitq ((FILE*)parm, buf, len);
+ } while ((result == 0) && (n == len));
+
+ ucnv_reset (emit_converter);
+ if (n != len) {
+ return NULL;
+ }
+ }
+ return parm;
+}
+
+#if 0
+static void
+dsgw_convert (void* parm, const char* s, size_t n)
+ /* Transform the output, in a visually distinctive way.
+ This function is intended for testing, only.
+ */
+{
+ while (parm && n > 0) {
+ const size_t len = LDAP_UTF8LEN(s);
+ if (len == 1 && *s >= '!' && *s <= '~') { /* ASCII */
+ /* output the double-width variant of this character */
+ unsigned c = (unsigned)*s - '!' + 0xFF01;
+ unsigned char buf[3];
+ buf[2] = 0x80 | (c & 0x3F); c >>= 6;
+ buf[1] = 0x80 | (c & 0x3F); c >>= 6;
+ buf[0] = 0xE0 | (c & 0x0F);
+ parm = dsgw_emitn (parm, (char*)buf, 3);
+ } else {
+ parm = dsgw_emitn (parm, s, len);
+ }
+ if (parm) {
+ n -= len;
+ s += len;
+ }
+ }
+}
+#endif
+
+int
+dsgw_emits (const char* s)
+ /* This function works like fputs(s, stdout), except it
+ converts from UTF8 to the client's preferred charset.
+ */
+{
+ size_t n = strlen (s);
+ if (n > 0 && dsgw_emitn (stdout, s, n) == NULL) {
+ return EOF;
+ }
+ return n;
+}
+
+int
+dsgw_emitfv (const char* format, va_list argl)
+ /* This function works like vprintf(), except it:
+ - supports parameter reordering, using %posp$.
+ - is UTF8-aware.
+ - converts to the client's preferred charset.
+ This function interprets all string parameters as UTF8.
+ */
+{
+ return( dsgw_vxprintf (dsgw_emitn, stdout, format, argl));
+}
+
+int
+dsgw_emitf (const char* format, ...)
+{
+ int rc;
+
+ va_list argl;
+ va_start (argl, format);
+ rc = dsgw_emitfv (format, argl);
+ va_end (argl);
+
+ return( rc );
+}
+
+typedef struct struct_item_t {
+ char* i_val;
+ double i_q;
+} item_t;
+
+static size_t
+list_count (const char* list)
+{
+ const char* s;
+ size_t n = 1;
+ if (list == NULL || *list == '\0') return 0;
+ for (s = list - 1; (s = strchr (s + 1, ',')) != NULL; ++n);
+ return n;
+}
+
+static item_t*
+list_parse (char* slist, size_t items)
+{
+ char* s = slist;
+ item_t* item;
+ size_t i = 0;
+ if (items <= 0) return NULL;
+ item = (item_t*) dsgw_ch_malloc (items * sizeof(item_t));
+ while (ldap_utf8isspace (s)) LDAP_UTF8INC(s);
+ while (s && *s) {
+ if (i >= items) exit (1);
+ item[i].i_q = 1.0;
+ item[i++].i_val = s;
+ if ((s = strchr (s, ',')) != NULL) {
+ *s = '\0';
+ while (ldap_utf8isspace (LDAP_UTF8INC(s)));
+ }
+ }
+ if (i != items) exit (1);
+ for (i = 0; i < items; ++i) {
+ if ((s = strchr (item[i].i_val, ';')) != NULL) {
+ *s = '\0';
+ do {
+ while (ldap_utf8isspace (LDAP_UTF8INC(s)));
+ if (*s == 'q' || *s == 'Q') {
+ while (ldap_utf8isspace (LDAP_UTF8INC(s)));
+ if (*s == '=') {
+ item[i].i_q = strtod(++s, &s);
+ }
+ }
+ } while ((s = strchr (s, ';')) != NULL);
+ }
+ /* Remove trailing whitespace from item[i].i_val: */
+ s = item[i].i_val;
+ s += strlen (s);
+ while (ldap_utf8isspace (LDAP_UTF8DEC(s)));
+ s[1] = '\0';
+/*printf("%s;q=%.2f\n", item[i].i_val, item[i].i_q);*/
+ }
+ return item;
+}
+
+static void
+list_sort (item_t item[], size_t items)
+{
+ /* This implementation is suboptimal, but adequate. */
+ int sorted;
+ size_t i;
+ do {
+ sorted = 1;
+ for (i = 0; i+1 < items ; ++i) {
+ if (item[i].i_q < item[i+1].i_q) { /* swap i & i+1 */
+ auto item_t temp;
+ memcpy (&temp, &item[i], sizeof(item_t));
+ memcpy (&item[i], &item[i+1], sizeof(item_t));
+ memcpy (&item[i+1], &temp, sizeof(item_t));
+ sorted = 0;
+ }
+ }
+ } while ( ! sorted);
+}
+
+int
+is_UTF_8 (const char* charset)
+{
+ return charset != NULL &&
+ (!strcasecmp (charset, UNICODE_ENCODING_UTF_8) ||
+ !strcasecmp (charset, "UNICODE-1-1-UTF-8"));
+}
+
+static int
+charset_is_supported (char* s)
+{
+ UConverter* converter;
+ UErrorCode err = U_ZERO_ERROR;
+ if (is_UTF_8 (s)) {
+ return 1;
+ }
+ converter = ucnv_open (s, &err);
+ if (err == U_ZERO_ERROR) {
+ ucnv_close (converter);
+ return 1;
+ }
+ return 0;
+}
+
+static char*
+choose_charset (char* slist)
+ /* Return the best charset from the given list. */
+{
+ const size_t items = list_count (slist);
+ char* sbuf;
+ item_t* item;
+ size_t i;
+
+ if (items <= 0) return slist;
+ sbuf = dsgw_ch_strdup (slist);
+ item = list_parse (sbuf, items);
+ for (i = 0; i < items; ++i) {
+ if (is_UTF_8 (item[i].i_val)) {
+ break; /* choose this one */
+ }
+ }
+ if (i >= items) {
+ list_sort (item, items);
+ for (i = 0; i < items; ++i) {
+ auto char* charset = item[i].i_val;
+ if (!strcmp ("*", charset)) {
+ i = items; /* choose UTF_8 */
+ } else if (charset_is_supported (charset)) {
+ break; /* choose this one */
+ }
+ }
+ }
+ if (i >= items) {
+ strcpy (sbuf, UNICODE_ENCODING_UTF_8);
+ } else if (sbuf != item[i].i_val) {
+ memmove (sbuf, item[i].i_val, strlen(item[i].i_val) + 1);
+ }
+ free (item);
+ return sbuf;
+}
+
+char*
+dsgw_emit_converts_to (char* charset)
+{
+ const char* target;
+ if (emit_converter != NULL) {
+ ucnv_close (emit_converter);
+ emit_converter = NULL;
+ }
+ if (charset) charset = choose_charset (charset);
+ if (charset && *charset) {
+ target = charset;
+ } else {
+ target = ISO_8859_1_ENCODING;
+ }
+ if ( ! is_UTF_8 (target)) {
+ UErrorCode err = U_ZERO_ERROR;
+ emit_converter = ucnv_open(target, &err);
+ if (err != U_ZERO_ERROR) {
+ emit_converter = NULL;
+ charset = UNICODE_ENCODING_UTF_8;
+ }
+ }
+ return charset;
+}
diff --git a/ldap/clients/dsgw/entrydisplay.c b/ldap/clients/dsgw/entrydisplay.c
new file mode 100644
index 00000000..f1f4cce7
--- /dev/null
+++ b/ldap/clients/dsgw/entrydisplay.c
@@ -0,0 +1,3228 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * entrydisplay.c -- output entries one at a time or in a list -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+#include <ldap.h> /* ldap_utf8* */
+#include <unicode/udat.h>
+#include <unicode/utypes.h>
+#include <unicode/unum.h>
+#include <unicode/ucal.h>
+
+/*
+ * Note: the value of the following DSGW_ATTRHTML_XXX #defines must match
+ * their position in the attrhtmltypes[] and attrhtmlvals[] arrays.
+ */
+#define DSGW_ATTRHTML_HIDDEN 0
+#define DSGW_ATTRHTML_TEXT 1
+#define DSGW_ATTRHTML_TEXTAREA 2
+#define DSGW_ATTRHTML_RADIO 3
+#define DSGW_ATTRHTML_CHECKBOX 4
+#define DSGW_ATTRHTML_PASSWORD 5
+static char *attrhtmltypes[] = {
+ "hidden",
+ "text",
+ "textarea",
+ "radio",
+ "checkbox",
+ "password",
+ NULL
+};
+static int attrhtmlvals[] = {
+ DSGW_ATTRHTML_HIDDEN,
+ DSGW_ATTRHTML_TEXT,
+ DSGW_ATTRHTML_TEXTAREA,
+ DSGW_ATTRHTML_RADIO,
+ DSGW_ATTRHTML_CHECKBOX,
+ DSGW_ATTRHTML_PASSWORD,
+};
+
+#define DSGW_ATTROPT_SORT 0x00000001
+#define DSGW_ATTROPT_NOLINK 0x00000002
+#define DSGW_ATTROPT_DNTAGS 0x00000004
+#define DSGW_ATTROPT_DATEONLY 0x00000008 /* only for syntax=time */
+#define DSGW_ATTROPT_READONLY 0x00000010 /* over-rides ..._EDITABLE */
+#define DSGW_ATTROPT_DNPICKER 0x00000020 /* display dns for find-n-add */
+#define DSGW_ATTROPT_UNIQUE 0x00000040 /* attr values must be unique */
+#define DSGW_ATTROPT_LINK 0x00000080 /* link to attribute value */
+#define DSGW_ATTROPT_TYPEONLY 0x00000100 /* retrieve attr. type only */
+#define DSGW_ATTROPT_NO_ENTITIES 0x00000200 /* don't use entities */
+#define DSGW_ATTROPT_HEX 0x00000400 /* display as hex value */
+#define DSGW_ATTROPT_DECIMAL 0x00000800 /* display as decimal value */
+#define DSGW_ATTROPT_QUOTED 0x00001000 /* quote the result */
+#define DSGW_ATTROPT_EDITABLE 0x10000000 /* not exposed in HTML */
+#define DSGW_ATTROPT_ADDING 0x20000000 /* not exposed in HTML */
+#define DSGW_ATTROPT_LINK2EDIT 0x40000000 /* not exposed in HTML */
+static char *attroptions[] = {
+ "sort",
+ "nolink",
+ "dntags",
+ "dateonly",
+ "readonly",
+ "dnpicker",
+ "unique",
+ "link",
+ "typeonly",
+ "noentities",
+ "hex",
+ "decimal",
+ "quoted",
+ NULL
+};
+
+static unsigned long attroptvals[] = {
+ DSGW_ATTROPT_SORT,
+ DSGW_ATTROPT_NOLINK,
+ DSGW_ATTROPT_DNTAGS,
+ DSGW_ATTROPT_DATEONLY,
+ DSGW_ATTROPT_READONLY,
+ DSGW_ATTROPT_DNPICKER,
+ DSGW_ATTROPT_UNIQUE,
+ DSGW_ATTROPT_LINK,
+ DSGW_ATTROPT_TYPEONLY,
+ DSGW_ATTROPT_NO_ENTITIES,
+ DSGW_ATTROPT_HEX,
+ DSGW_ATTROPT_DECIMAL,
+ DSGW_ATTROPT_QUOTED,
+};
+
+
+#define DSGW_ATTRARG_ATTR "attr"
+#define DSGW_ATTRARG_SYNTAX "syntax"
+#define DSGW_ATTRARG_HTMLTYPE "type"
+#define DSGW_ATTRARG_OPTIONS "options"
+#define DSGW_ATTRARG_DEFAULT "defaultvalue"
+#define DSGW_ATTRARG_WITHIN "within" /* overrides href & hrefextra */
+#define DSGW_ATTRARG_HREF "href"
+#define DSGW_ATTRARG_HREFEXTRA "hrefextra"
+#define DSGW_ATTRARG_LABEL "label" /* only used with syntax=dn */
+#define DSGW_ATTRARG_DNCOMP "dncomponents" /* only used with syntax=dn */
+#define DSGW_ATTRARG_TRUESTR "true" /* only used with syntax=bool */
+#define DSGW_ATTRARG_FALSESTR "false" /* only used with syntax=bool */
+#define DSGW_ATTRARGS_SIZE "size"
+#define DSGW_ATTRARGS_ROWS "rows"
+#define DSGW_ATTRARGS_COLS "cols"
+#define DSGW_ATTRARGS_NUMFIELDS "numfields"
+#define DSGW_ATTRARGS_VALUE "value"
+#define DSGW_ATTRARG_MIMETYPE "mimetype"
+#define DSGW_ATTRARG_SCRIPT "script"
+
+#define DSGW_ARG_BUTTON_PROMPT "prompt"
+#define DSGW_ARG_BUTTON_TEMPLATE "template"
+#define DSGW_ARG_BUTTON_CHECKSUBMIT "checksubmit"
+#define DSGW_ARG_BUTTON_TOPIC "topic"
+#define DSGW_ARG_DNEDIT_LABEL "label"
+#define DSGW_ARG_DNEDIT_TEMPLATE "template"
+#define DSGW_ARG_DNEDIT_ATTR "attr"
+#define DSGW_ARG_DNEDIT_DESC "desc"
+
+#define DSGW_ARG_FABUTTON_LABEL "label"
+#define DSGW_ARG_FABUTTON_ATTRNAME "attr"
+#define DSGW_ARG_FABUTTON_ATTRDESC "attrdesc"
+
+#define DSGW_ARG_AVSET_SET "set"
+
+/*
+ * structure used simply to avoid passing a lot of parameters in call to
+ * the attribute syntax handlers
+ */
+struct dsgw_attrdispinfo {
+ struct attr_handler *adi_handlerp;
+ char *adi_attr;
+ int adi_argc;
+ char **adi_argv;
+ char **adi_vals;
+ char *adi_rdn; /* a copy of adi_vals[i] (possibly NULL) */
+ int adi_htmltype;
+ unsigned long adi_opts;
+};
+/* adi_rdn should be generalized, to support an RDN
+ that contains several values of one attribute type.
+*/
+
+typedef void (*attrdisplay)( struct dsgw_attrdispinfo *adip );
+typedef void (*attredit)( struct dsgw_attrdispinfo *adip );
+
+struct attr_handler {
+ char *ath_syntax; /* dn, tel, cis, etc. */
+ attrdisplay ath_display; /* function to display values */
+ attredit ath_edit; /* function to display for editing */
+ int ath_compare; /* compare function */
+};
+
+/* functions local to this file */
+static void append_to_array( char ***ap, int *countp, char *s );
+static unsigned long get_attr_options( int argc, char **argv );
+static void output_prelude( dsgwtmplinfo *tip );
+static void output_nonentry_line( dsgwtmplinfo *tip, char *line );
+static struct attr_handler *syntax2attrhandler( char *syntax );
+static int numfields( int argc, char **argv, int valcount );
+static void element_sizes( int argc, char **argv, char **vals, int valcount,
+ int *rowsp, int *colsp );
+#define DSGW_TEXTOPT_FOCUSHANDLERS 0x0001
+#define DSGW_TEXTOPT_CHANGEHANDLERS 0x0002
+static void output_text_elements( int argc, char **argv, char *attr,
+ char **vals, const char* rdn, char *prefix, int htmltype, unsigned long opts );
+static void output_textarea( int argc, char **argv, char *attr,
+ char **vals, int valcount, char *prefix, unsigned long opts );
+static void emit_value( char *val, int quote_html_specials );
+static void output_text_checkbox_or_radio( struct dsgw_attrdispinfo *adip,
+ char *prefix, int htmltype );
+static void do_attribute( dsgwtmplinfo *tip, char *dn, unsigned long dispopts,
+ int argc, char **argv );
+static void do_orgchartlink( dsgwtmplinfo *tip, char *dn, unsigned long dispopts,
+ int argc, char **argv );
+static void do_attrvalset( dsgwtmplinfo *tip, char *dn, unsigned long dispopts,
+ int argc, char **argv );
+static void do_editbutton( char *dn, char *encodeddn, int argc, char **argv );
+static void do_savebutton( unsigned long dispopts, int argc, char **argv );
+static void do_deletebutton( int argc, char **argv );
+#if 0
+static void do_renamebutton( char *dn, int argc, char **argv );
+#endif
+static void do_editasbutton( int argc, char **argv );
+static void do_dneditbutton( unsigned long dispopts, int argc, char **argv );
+static void do_searchdesc( dsgwtmplinfo *tip, int argc, char **argv );
+static void do_passwordfield( unsigned long dispopts, int argc, char **argv,
+ char *fieldname );
+static void do_helpbutton( unsigned long dispopts, int argc, char **argv );
+static void do_closebutton( unsigned long dispopts, int argc, char **argv );
+static void do_viewswitcher( char *template, char *dn, int argc, char **argv );
+static int did_output_as_special( int argc, char **argv, char *label,
+ char *val );
+static char *time2text( char *ldtimestr, int dateonly );
+static long gtime( struct tm *tm );
+static int looks_like_dn( char *s );
+static void do_std_completion_js( char *template, int argc, char **argv );
+static int condition_is_true( int argc, char **argv, void *arg );
+static char ** dsgw_get_values( LDAP *ld, LDAPMessage *entry,
+ const char *target, int binary_value );
+static void dsgw_value_free( void **ldvals, int binary ) ;
+static char *dsgw_time(time_t secs_since_1970);
+
+/* attribute syntax handler routines */
+static void ntdomain_display( struct dsgw_attrdispinfo *adip );
+static void ntuserid_display( struct dsgw_attrdispinfo *adip );
+static void str_display( struct dsgw_attrdispinfo *adip );
+static void str_edit( struct dsgw_attrdispinfo *adip );
+static void dn_display( struct dsgw_attrdispinfo *adip );
+static void dn_edit( struct dsgw_attrdispinfo *adip );
+static void mail_display( struct dsgw_attrdispinfo *adip );
+static void mls_display( struct dsgw_attrdispinfo *adip );
+static void mls_edit( struct dsgw_attrdispinfo *adip );
+static void binvalue_display( struct dsgw_attrdispinfo *adip );
+static void url_display( struct dsgw_attrdispinfo *adip );
+static void bool_display( struct dsgw_attrdispinfo *adip );
+static void bool_edit( struct dsgw_attrdispinfo *adip );
+static void time_display( struct dsgw_attrdispinfo *adip );
+
+
+/* static variables */
+#define DSGW_MOD_PREFIX_NORMAL 0
+#define DSGW_MOD_PREFIX_UNIQUE 1
+static char *replace_prefixes[] = { "replace_", "replace_unique_" };
+static char *replace_mls_prefixes[] = { "replace_mls_", "replace_mls_unique_" };
+static char *add_prefixes[] = { "add_", "add_unique_" };
+static char *add_mls_prefixes[] = { "add_mls_", "add_mls_unique_" };
+
+struct attr_handler attrhandlers[] = {
+ { "cis", str_display, str_edit, CASE_INSENSITIVE },
+ { "dn", dn_display, dn_edit, CASE_INSENSITIVE },
+ { "mail", mail_display, str_edit, CASE_INSENSITIVE },
+ { "mls", mls_display, mls_edit, CASE_INSENSITIVE },
+ { "tel", str_display, str_edit, CASE_INSENSITIVE },
+ { "url", url_display, str_edit, CASE_EXACT },
+ { "ces", str_display, str_edit, CASE_EXACT },
+ { "bool", bool_display, bool_edit, CASE_INSENSITIVE },
+ { "time", time_display, str_edit, CASE_INSENSITIVE },
+ { "ntdomain", ntdomain_display, str_edit, CASE_INSENSITIVE },
+ { "ntuserid", ntuserid_display, str_edit, CASE_INSENSITIVE },
+ { "ntgroupname", ntuserid_display, str_edit, CASE_INSENSITIVE },
+ { "binvalue", binvalue_display, str_edit, CASE_INSENSITIVE },
+};
+#define DSGW_AH_COUNT ( sizeof( attrhandlers ) / sizeof( struct attr_handler ))
+
+
+static char *
+template_filename( int tmpltype, char *template )
+{
+ char *fn, *prefix, *suffix = ".html";
+
+ if ( tmpltype == DSGW_TMPLTYPE_LIST ) {
+ prefix = DSGW_CONFIG_LISTPREFIX;
+ } else if ( tmpltype == DSGW_TMPLTYPE_EDIT ) {
+ prefix = DSGW_CONFIG_EDITPREFIX;
+ } else if ( tmpltype == DSGW_TMPLTYPE_ADD ) {
+ prefix = DSGW_CONFIG_ADDPREFIX;
+ } else {
+ prefix = DSGW_CONFIG_DISPLAYPREFIX;
+ }
+
+ fn = dsgw_ch_malloc( strlen( prefix ) + strlen( template )
+ + strlen( suffix ) + 1 );
+ sprintf( fn, "%s%s%s", prefix, template, suffix );
+
+ return( fn );
+}
+
+static void
+do_postedvalue( int argc, char **argv )
+{
+ dsgw_emits( "VALUE=\"" );
+ dsgw_emit_cgi_var( argc, argv );
+ dsgw_emits( "\"\n" );
+}
+
+static int
+dsgw_display_line( dsgwtmplinfo *tip, char *line, int argc, char **argv )
+{
+ if ( dsgw_directive_is( line, DRCT_DS_POSTEDVALUE )) {
+ do_postedvalue( argc, argv );
+ } else if ( dsgw_directive_is( line, DRCT_DS_HELPBUTTON )) {
+ do_helpbutton( tip->dsti_options, argc, argv );
+ } else if ( dsgw_directive_is( line, DRCT_DS_CLOSEBUTTON )) {
+ do_closebutton( tip->dsti_options, argc, argv );
+ } else if ( dsgw_directive_is( line, DRCT_DS_OBJECTCLASS )) {
+ /* omit objectClass lines */
+ } else if ( dsgw_directive_is( line, DRCT_HEAD )) {
+ dsgw_head_begin();
+ dsgw_emits ("\n");
+ } else {
+ return 0;
+ }
+ return 1;
+}
+
+dsgwtmplinfo *
+dsgw_display_init( int tmpltype, char *template, unsigned long options )
+{
+ dsgwtmplinfo *tip;
+ int argc, attrcount, attrsonlycount, skip_line, in_entry;
+ char **argv, *attr, *filename, line[ BIG_LINE ];
+ unsigned long aopts;
+
+ tip = (dsgwtmplinfo *)dsgw_ch_malloc( sizeof( dsgwtmplinfo ));
+ memset( tip, 0, sizeof( dsgwtmplinfo ));
+ tip->dsti_type = tmpltype;
+ tip->dsti_options = options;
+ tip->dsti_template = dsgw_ch_strdup( template );
+
+ if (( options & DSGW_DISPLAY_OPT_ADDING ) != 0 ) {
+ options |= DSGW_DISPLAY_OPT_EDITABLE; /* add implies editable */
+
+ if ( tmpltype != DSGW_TMPLTYPE_ADD ) {
+ /*
+ * if we are going to display an "add" view of an entry and
+ * an add template has not been explicitly requested, first look
+ * for a file called "add-TEMPLATE.html" and fall back on using
+ * whatever we would use if just editing an existing entry.
+ */
+ filename = template_filename( DSGW_TMPLTYPE_ADD, template );
+ tip->dsti_fp = dsgw_open_html_file( filename, DSGW_ERROPT_IGNORE );
+ free( filename );
+ }
+ }
+
+ if ( tip->dsti_fp == NULL && ( options & DSGW_DISPLAY_OPT_EDITABLE ) != 0
+ && tmpltype != DSGW_TMPLTYPE_EDIT ) {
+ /*
+ * if we are going to display an editable view of an entry and
+ * an edit template has not been explicitly requested, first look
+ * for a file called "edit-TEMPLATE.html" and fall back on using
+ * "list-TEMPLATE.html" or "display-TEMPLATE.html", as indicated by
+ * the value of tmpltype.
+ */
+ filename = template_filename( DSGW_TMPLTYPE_EDIT, template );
+ tip->dsti_fp = dsgw_open_html_file( filename, DSGW_ERROPT_IGNORE );
+ free( filename );
+ }
+
+ if ( tip->dsti_fp == NULL ) {
+ filename = template_filename( tmpltype, template );
+ tip->dsti_fp = dsgw_open_html_file( filename, DSGW_ERROPT_EXIT );
+ free( filename );
+ }
+
+ tip->dsti_preludelines = dsgw_savelines_alloc();
+ tip->dsti_entrylines = dsgw_savelines_alloc();
+ in_entry = 0;
+
+ /* prime attrs array so we always retrieve objectClass values */
+ attrcount = 1;
+ tip->dsti_attrs = (char **)dsgw_ch_realloc( tip->dsti_attrs,
+ 2 * sizeof( char * ));
+ tip->dsti_attrs[ 0 ] = dsgw_ch_strdup( DSGW_ATTRTYPE_OBJECTCLASS );
+ tip->dsti_attrs[ 1 ] = NULL;
+ attrsonlycount = 0;
+ tip->dsti_attrsonly_attrs = NULL;
+
+ while ( dsgw_next_html_line( tip->dsti_fp, line )) {
+ skip_line = 0;
+ if ( dsgw_parse_line( line, &argc, &argv, 1, condition_is_true, tip )) {
+ if ( in_entry && dsgw_directive_is( line, DRCT_DS_ENTRYEND )) {
+ dsgw_argv_free( argv );
+ break; /* the rest is read inside dsgw_display_done */
+ }
+ if ( dsgw_directive_is( line, DRCT_DS_ENTRYBEGIN )) {
+ in_entry = skip_line = 1;
+ } else if ( dsgw_directive_is( line, DRCT_DS_ATTRIBUTE ) ||
+ dsgw_directive_is( line, DRCT_DS_ATTRVAL_SET )) {
+ aopts = get_attr_options( argc, argv );
+ if (( attr = get_arg_by_name( DSGW_ATTRARG_ATTR, argc,
+ argv )) != NULL && strcasecmp( attr, "dn" ) != 0 &&
+ (strcasecmp(attr,DSGW_ATTRTYPE_AIMSTATUSTEXT) != 0 || gc->gc_aimpresence == 1) &&
+ ( aopts & DSGW_ATTROPT_LINK ) == 0 ) {
+ if (( aopts & DSGW_ATTROPT_TYPEONLY ) == 0 ) {
+ append_to_array( &tip->dsti_attrs, &attrcount, attr );
+ } else {
+ append_to_array( &tip->dsti_attrsonly_attrs,
+ &attrsonlycount, attr );
+ }
+ }
+ } else if ( dsgw_directive_is( line, DRCT_DS_ORGCHARTLINK )) {
+ aopts = get_attr_options( argc, argv );
+ if (( aopts & DSGW_ATTROPT_TYPEONLY ) == 0 ) {
+ append_to_array( &tip->dsti_attrs, &attrcount, gc->gc_orgchartsearchattr );
+ } else {
+ append_to_array( &tip->dsti_attrsonly_attrs,
+ &attrsonlycount, gc->gc_orgchartsearchattr);
+ }
+ } else if ( dsgw_directive_is( line, DRCT_DS_SORTENTRIES )) {
+ if (( attr = get_arg_by_name( DSGW_ATTRARG_ATTR, argc,
+ argv )) == NULL ) {
+ tip->dsti_sortbyattr = NULL; /* no attr=, so sort by DN */
+ } else {
+ tip->dsti_sortbyattr = dsgw_ch_strdup( attr );
+ }
+ skip_line = 1; /* completely done with directive */
+ }
+ dsgw_argv_free( argv );
+ }
+
+ if ( !skip_line ) {
+ if ( in_entry ) { /* in entry */
+ dsgw_savelines_save( tip->dsti_entrylines, line );
+ } else { /* in prelude */
+ dsgw_savelines_save( tip->dsti_preludelines, line );
+ }
+ }
+ }
+
+ if ( attrcount > 0 ) {
+ tip->dsti_attrflags = (unsigned long *)dsgw_ch_malloc( attrcount
+ * sizeof( unsigned long ));
+ memset( tip->dsti_attrflags, 0, attrcount * sizeof( unsigned long ));
+ }
+
+ /*
+ * Add the sortattr to the list of attrs retrieved, if it's not
+ * already in the list.
+ */
+ if ( tip->dsti_sortbyattr != NULL ) {
+ int i, found = 0;
+ for ( i = 0; i < attrcount; i++ ) {
+ if ( !strcasecmp( tip->dsti_sortbyattr, tip->dsti_attrs[ i ])) {
+ found = 1;
+ break;
+ }
+ }
+ if ( !found ) {
+ append_to_array( &tip->dsti_attrs, &attrcount,
+ tip->dsti_sortbyattr );
+ }
+ }
+
+ return( tip );
+}
+
+
+void
+dsgw_display_entry( dsgwtmplinfo *tip, LDAP *ld, LDAPMessage *entry,
+ LDAPMessage *attrsonly_entry, char *dn )
+{
+ int argc, editable, adding;
+ char **argv, *encodeddn, *line;
+
+ editable = (( tip->dsti_options & DSGW_DISPLAY_OPT_EDITABLE ) != 0 );
+ adding = (( tip->dsti_options & DSGW_DISPLAY_OPT_ADDING ) != 0 );
+
+ if ( entry == NULL && !adding ) {
+ dsgw_error( DSGW_ERR_MISSINGINPUT, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ tip->dsti_ld = ld;
+ tip->dsti_entry = entry;
+ tip->dsti_attrsonly_entry = attrsonly_entry;
+
+ if ( dn == NULL ) {
+ if ( entry == NULL ) {
+ dn = "dn=unknown";
+ } else if (( dn = ldap_get_dn( ld, entry )) == NULL ) {
+ dsgw_ldap_error( ld, DSGW_ERROPT_EXIT );
+ }
+ }
+ tip->dsti_entrydn = dsgw_ch_strdup( dn );
+ encodeddn = dsgw_strdup_escaped( dn );
+
+ if ( adding ) {
+ tip->dsti_rdncomps = dsgw_rdn_values( dn );
+ }
+
+ if ( tip->dsti_preludelines != NULL ) {
+ output_prelude( tip );
+ }
+
+
+ dsgw_savelines_rewind( tip->dsti_entrylines );
+ while (( line = dsgw_savelines_next( tip->dsti_entrylines )) != NULL ) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, condition_is_true, tip )) {
+ if ( dsgw_directive_is( line, DRCT_DS_ATTRIBUTE )) {
+ do_attribute( tip, dn, tip->dsti_options, argc, argv );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_ATTRVAL_SET )) {
+ do_attrvalset( tip, dn, tip->dsti_options, argc, argv );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_ORGCHARTLINK )) {
+ do_orgchartlink( tip, dn, tip->dsti_options, argc, argv );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_EMIT_BASE_HREF )) {
+ char *p;
+ char *sname = dsgw_ch_strdup( getenv( "SCRIPT_NAME" ));
+ if (( p = strrchr( sname, '/' )) != NULL ) {
+ *p = '\0';
+ }
+ dsgw_emitf( "<BASE HREF=\"%s%s/\">\n",
+ getenv( "SERVER_URL" ), sname );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_BEGIN_DNSEARCHFORM )) {
+ dsgw_form_begin ( "searchForm", "action=\"%s\" %s %s",
+ dsgw_getvp( DSGW_CGINUM_DOSEARCH ),
+ "target=stagingFrame",
+ "onSubmit=\"return parent.processSearch(searchForm);\"" );
+ dsgw_emitf( "\n<INPUT TYPE=\"hidden\" NAME=\"dn\" VALUE=\"%s\";>\n", encodeddn );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_BEGIN_ENTRYFORM )) {
+ if ( editable ) {
+ dsgw_form_begin("modifyEntryForm","ACTION=\"%s\"",
+ dsgw_getvp( DSGW_CGINUM_DOMODIFY ));
+ dsgw_emits( "\n<INPUT TYPE=hidden NAME=\"changetype\">\n" );
+ dsgw_emitf( "<INPUT TYPE=hidden NAME=\"dn\" VALUE=\"%s\">\n",
+ encodeddn );
+ dsgw_emits( "<INPUT TYPE=hidden NAME=\"changed_DN\" VALUE=false>\n");
+ dsgw_emits( "<INPUT TYPE=hidden NAME=\"deleteoldrdn\" VALUE=true>\n");
+
+ } else {
+ dsgw_form_begin("editEntryForm", "action=\"%s\" %s",
+ dsgw_getvp( DSGW_CGINUM_AUTH ),
+ "target=\"_blank\"" );
+ dsgw_emits( "\n" );
+ }
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_END_ENTRYFORM )) {
+ dsgw_emitf( "</FORM>\n" );
+ dsgw_emit_confirmForm();
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_END_DNSEARCHFORM )) {
+ dsgw_emitf( "</FORM>\n" );
+ dsgw_emit_alertForm();
+ dsgw_emit_confirmForm();
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_EDITBUTTON )) {
+ if ( !editable ) do_editbutton( dn, encodeddn, argc, argv );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_DELETEBUTTON )) {
+ if ( editable && !adding ) do_deletebutton( argc, argv );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_RENAMEBUTTON )) {
+ /* if ( editable && !adding ) do_renamebutton( dn, argc, argv ); */
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_EDITASBUTTON )) {
+ if ( editable ) do_editasbutton( argc, argv );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_SAVEBUTTON )) {
+ if ( editable ) do_savebutton( tip->dsti_options, argc, argv );
+
+ } else if ( dsgw_display_line( tip, line, argc, argv )) {
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_NEWPASSWORD )) {
+ if ( editable ) do_passwordfield( tip->dsti_options, argc,
+ argv, "newpasswd" );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_CONFIRM_NEWPASSWORD )) {
+ if ( editable ) do_passwordfield( tip->dsti_options, argc,
+ argv, "newpasswdconfirm" );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_OLDPASSWORD )) {
+ if ( editable ) do_passwordfield( tip->dsti_options, argc,
+ argv, "passwd" );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_DNATTR )) {
+ if ( dsgw_dnattr != NULL ) dsgw_emits( dsgw_dnattr );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_DNDESC )) {
+ if ( dsgw_dndesc != NULL ) dsgw_emits( dsgw_dndesc );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_DNEDITBUTTON )) {
+ if ( editable ) {
+ do_dneditbutton( tip->dsti_options, argc, argv );
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_DNADDBUTTON" )) {
+ dsgw_emits ("<INPUT TYPE=SUBMIT");
+ {
+ auto char* v = get_arg_by_name (DSGW_ATTRARGS_VALUE, argc, argv);
+ if (v) dsgw_emitf (" VALUE=\"%s\"", v);
+ }
+ dsgw_emits (">\n");
+
+ } else if ( dsgw_directive_is( line, "DS_DNREMOVEBUTTON" )) {
+ dsgw_emits ("<INPUT TYPE=BUTTON");
+ {
+ auto char* v = get_arg_by_name (DSGW_ATTRARGS_VALUE, argc, argv);
+ if (v) dsgw_emitf (" VALUE=\"%s\"", v);
+ }
+ dsgw_emits (" onClick=\"if (parent.processSearch(searchForm)) {"
+ "searchForm.faMode.value='remove';"
+ "searchForm.submit();"
+ "searchForm.searchstring.select();"
+ "searchForm.searchstring.focus();"
+ "}\">\n");
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_VIEW_SWITCHER ) &&
+ tip->dsti_entry != NULL ) {
+ do_viewswitcher( tip->dsti_template, tip->dsti_entrydn,
+ argc, argv );
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_STD_COMPLETION_JS )) {
+ do_std_completion_js( tip->dsti_template, argc, argv );
+
+ } else {
+ dsgw_emits( line );
+ }
+
+ dsgw_argv_free( argv );
+ }
+ }
+
+ free( encodeddn );
+}
+
+static void
+dsgw_setstr (char** into, const char* from)
+{
+ if (from) {
+ auto const size_t len = strlen (from) + 1;
+ *into = dsgw_ch_realloc (*into, len);
+ memmove (*into, from, len);
+ } else if (*into) {
+ free (*into);
+ *into = NULL;
+ }
+}
+
+void
+dsgw_set_searchdesc( dsgwtmplinfo *tip, char *s2, char *s3, char *s4 )
+{
+ dsgw_setstr( &(tip->dsti_search2s), s2 );
+ dsgw_setstr( &(tip->dsti_search3s), s3 );
+ dsgw_setstr( &(tip->dsti_search4s), s4 );
+}
+
+void
+dsgw_set_search_result( dsgwtmplinfo *tip, int entrycount, char *searcherror,
+ char *lderrtxt )
+{
+ tip->dsti_entrycount = entrycount;
+ dsgw_setstr( &(tip->dsti_searcherror), searcherror );
+ dsgw_setstr( &(tip->dsti_searchlderrtxt), lderrtxt );
+}
+
+
+void
+dsgw_display_done( dsgwtmplinfo *tip )
+{
+ char line[ BIG_LINE ], *jscomp;
+
+ if ( tip->dsti_preludelines != NULL ) {
+ output_prelude( tip );
+ }
+
+ while ( dsgw_next_html_line( tip->dsti_fp, line )) {
+ output_nonentry_line( tip, line );
+ }
+
+ /*
+ * check for "completion_javascript" form var and
+ * execute it if present.
+ */
+ jscomp = dsgw_get_cgi_var( "completion_javascript",
+ DSGW_CGIVAR_OPTIONAL );
+ if ( jscomp != NULL ) {
+ dsgw_emits( "<SCRIPT LANGUAGE=\"JavaScript\">\n" );
+ dsgw_emitf( "eval('%s');\n", jscomp );
+ dsgw_emits( "</SCRIPT>\n" );
+ }
+
+ fflush( stdout );
+ fflush( stdout );
+
+ dsgw_savelines_free( tip->dsti_entrylines );
+ fclose( tip->dsti_fp );
+ if ( tip->dsti_attrs != NULL ) {
+ ldap_value_free( tip->dsti_attrs );
+ }
+ if ( tip->dsti_attrflags != NULL ) {
+ free( tip->dsti_attrflags );
+ }
+ if ( tip->dsti_rdncomps != NULL ) {
+ ldap_value_free( tip->dsti_rdncomps );
+ }
+ free( tip );
+}
+
+
+static void
+output_prelude( dsgwtmplinfo *tip )
+{
+ int editable, adding;
+ char *line, *encodeddn;
+
+ if ( tip->dsti_preludelines != NULL ) { /* output the prelude */
+ dsgw_savelines_rewind( tip->dsti_preludelines );
+ while (( line = dsgw_savelines_next( tip->dsti_preludelines ))
+ != NULL ) {
+ output_nonentry_line( tip, line );
+ }
+ dsgw_savelines_free( tip->dsti_preludelines );
+ tip->dsti_preludelines = NULL;
+ }
+
+ /* output any JavaScript functions we want to include before the entry */
+ dsgw_emits( "<SCRIPT LANGUAGE=\"JavaScript\">\n" );
+ dsgw_emits( "<!-- Hide from non-JavaScript-capable browsers\n" );
+ dsgw_emits( "var emptyFrame = '';\n" );
+ editable = ( tip->dsti_options & DSGW_DISPLAY_OPT_EDITABLE ) != 0;
+ adding = ( tip->dsti_options & DSGW_DISPLAY_OPT_ADDING ) != 0;
+
+ if ( !editable ) {
+ char *urlprefix = dsgw_ch_malloc( strlen(gc->gc_urlpfxmain) + 128);
+
+ sprintf(urlprefix, "%semptyFrame.html", gc->gc_urlpfxmain);
+
+ /* include the functions used to support "Edit" buttons */
+ /* function haveAuthCookie() */
+ dsgw_emits( "function haveAuthCookie()\n{\n" );
+ dsgw_emitf( " return ( document.cookie.indexOf( '%s=' ) >= 0 "
+ "&& document.cookie.indexOf( '%s=%s' ) < 0 );\n}\n\n",
+ DSGW_AUTHCKNAME, DSGW_AUTHCKNAME, DSGW_UNAUTHSTR );
+
+ /* function authOrEdit() -- calls haveAuthCookie() */
+ dsgw_emits( "function authOrEdit(encodeddn)\n{\n" );
+ dsgw_emitf( " editURL = '%s?context=%s&dn=' + encodeddn;\n",
+ dsgw_getvp( DSGW_CGINUM_EDIT ), context);
+ dsgw_emits( " if ( haveAuthCookie()) {\n" );
+ dsgw_emits( "\tnw = open(editURL, \"_blank\");\n" );
+ dsgw_emits( "\twindow.location.href = " );
+ dsgw_quote_emits (QUOTATION_JAVASCRIPT, urlprefix);
+ dsgw_emits( ";\n"
+ " } else {\n"
+ "\tdocument.editEntryForm.authdesturl.value = editURL;\n"
+ "\ta = open(");
+ dsgw_quote_emits (QUOTATION_JAVASCRIPT, urlprefix);
+
+ free(urlprefix);
+ urlprefix = NULL;
+ dsgw_emits(", 'AuthWin');\n"
+ "\ta.opener = self;\n"
+ "\ta.closewin = true;\n"
+ "\tdocument.editEntryForm.target = 'AuthWin';\n"
+ "\tdocument.editEntryForm.submit();\n"
+ " }\n}\n" );
+
+ } else {
+ /* include variables and functions used to support edit mode */
+ dsgw_emits( "var changesHaveBeenMade = 0;\n\n" );
+ dsgw_emits( "var possiblyChangedAttr = null;\n\n" );
+
+ /* function aChg() -- called from onChange and onClick handlers */
+ dsgw_emits( "function aChg(attr)\n{\n" );
+ if ( !adding ) {
+ dsgw_emits( " cmd = 'document.modifyEntryForm.changed_' + "
+ "attr + '.value = \"true\"';\n" );
+ dsgw_emits( " eval( cmd );\n possiblyChangedAttr = null;\n" );
+ }
+ dsgw_emits( " changesHaveBeenMade = 1;\n}\n\n" );
+
+
+ if ( !adding ) {
+ /* function aFoc() -- called when text area gets focus. */
+ dsgw_emits( "function aFoc(attr)\n{\n"
+ " possiblyChangedAttr = attr;\n}\n\n" );
+ }
+
+ /* function submitModify() */
+ dsgw_emits( "function submitModify(changetype)\n{\n" );
+ if ( !adding ) {
+ dsgw_emits( "\tif ( possiblyChangedAttr != null ) "
+ "aChg(possiblyChangedAttr);\n" );
+ }
+ dsgw_emits( "\tdocument.modifyEntryForm.changetype.value = changetype;\n" );
+ dsgw_emits( "\tdocument.modifyEntryForm.submit();\n}\n" );
+
+ /* function confirmModify() */
+ dsgw_emits( "var changetype = '';\n\n" );
+ dsgw_emits( "function confirmModify(ctype, prompt)\n{\n" );
+ dsgw_emits( " changetype = ctype;\n" );
+ dsgw_emit_confirm (NULL, "opener.submitModify(opener.changetype);", NULL/*no*/,
+ NULL /* options */, 0, "prompt");
+ dsgw_emits( "}\n" );
+
+ /* function EditEntryAs() */
+/*
+ dsgw_emits( "function EditEntryAs(template)\n{\n" );
+ dsgw_emits( " newurl = window.location.protocol + '//' +\n"
+ "\twindow.location.host +\n"
+ "\twindow.location.pathname + '?' + template;\n" );
+ dsgw_emits( "\twindow.location.href = newurl;\n}\n" );
+*/
+
+ if ( tip->dsti_entrydn != NULL ) {
+ encodeddn = dsgw_strdup_escaped( tip->dsti_entrydn );
+ dsgw_emits( "function EditEntryAs(template)\n{\n" );
+ dsgw_emitf( " newurl = '%s?' + template + '&context=%s&dn=%s';\n",
+ dsgw_getvp( DSGW_CGINUM_EDIT ), context, encodeddn );
+ dsgw_emits( "\twindow.location.href = newurl;\n}\n" );
+ }
+
+ /* function DNEdit() */
+ if ( tip->dsti_entrydn != NULL ) {
+ encodeddn = dsgw_strdup_escaped( tip->dsti_entrydn );
+ dsgw_emits( "var DNEditURL;\n" );
+ dsgw_emits( "function DNEdit(template, attr, desc)\n{\n" );
+ dsgw_emitf( " DNEditURL = '%s?template=' + template + "
+ "'&dn=%s&context=%s&ATTR=' + attr + '&DESC=' + escape(desc);\n",
+ dsgw_getvp( DSGW_CGINUM_DNEDIT ), encodeddn, context );
+ dsgw_emits( " if( !changesMade() ) window.location.href = DNEditURL;\n"
+ " else {\n");
+ dsgw_emit_confirm( NULL, "opener.location.href = opener.DNEditURL;", NULL/*no*/,
+ XP_GetClientStr(DBT_continueWithoutSavingWindow_), 1,
+ XP_GetClientStr(DBT_continueWithoutSaving_));
+ dsgw_emits( " }\n");
+ dsgw_emits( "}\n" );
+ }
+
+ /* function changesMade() */
+ dsgw_emits( "function changesMade()\n{\n" );
+ if ( !adding ) {
+ dsgw_emits( "\tif ( possiblyChangedAttr != null ) "
+ "aChg(possiblyChangedAttr);\n" );
+ }
+ dsgw_emits( " return( changesHaveBeenMade );\n}\n" );
+
+ /* function closeIfOK() */
+ dsgw_emits( "function closeIfOK()\n{\n"
+ " if ( !changesMade() ) top.close();\n"
+ " else {\n" );
+ dsgw_emit_confirm( NULL, "opener.top.close();", NULL/*no*/,
+ XP_GetClientStr(DBT_discardChangesWindow_), 1,
+ XP_GetClientStr(DBT_discardChanges_));
+ dsgw_emits( " }\n}\n" );
+
+ /* set unload handler to catch unsaved changes */
+ dsgw_emits( "document.onUnload = \""
+ "return ( !changesMade() || prompt( 'Discard Changes?' ));\"\n" );
+ }
+
+ dsgw_emits( "// End hiding -->\n</SCRIPT>\n" );
+}
+
+
+static void
+output_nonentry_line( dsgwtmplinfo *tip, char *line )
+{
+ int argc;
+ char **argv;
+
+ if ( dsgw_parse_line( line, &argc, &argv, 0, condition_is_true, tip )) {
+ if ( dsgw_directive_is( line, DRCT_DS_SEARCHDESC )) {
+ do_searchdesc( tip, argc, argv );
+ } else if ( dsgw_display_line ( tip, line, argc, argv )) {
+ } else {
+ dsgw_emits( line );
+ }
+ dsgw_argv_free( argv );
+ }
+}
+
+static char*
+find_RDN (char* DN, char* attr, char** vals)
+ /* Return a copy of the vals[i] that is
+ part of the RDN of the given DN.
+ */
+{
+ if (DN && *DN && vals && *vals) {
+ auto char** RDNs = ldap_explode_dn (DN, 0);
+ auto char** AVAs = ldap_explode_rdn (RDNs[0], 0);
+ ldap_value_free (RDNs);
+ if (AVAs) {
+ auto char** val = NULL;
+ auto char** AVA;
+ for (AVA = AVAs; *AVA; ++AVA) {
+ auto char* RDN = strchr (*AVA, '=');
+ if (RDN) {
+ *RDN++ = '\0';
+ if (!strcasecmp (*AVA, attr)) {
+ for (val = vals; *val; ++val) {
+ if (!strcmp (RDN, *val)) {
+ break;
+ }
+ }
+ if (*val) break;
+ /* bug: what if there are other AVAs
+ that also match attr and one of vals?
+ Even if this algorithm could find them,
+ it couldn't return them (the function
+ return value can't express multiple
+ values).
+ */
+ }
+ }
+ }
+ ldap_value_free (AVAs);
+ if (val) return *val;
+ }
+ }
+ return NULL;
+}
+
+/*static int
+ *is_aim_online(dsgwtmplinfo *tip)
+ *{
+ * char **ldvals = (char **) dsgw_get_values(tip->dsti_ld, tip->dsti_entry, DSGW_ATTRTYPE_AIMSTATUSTEXT, 0);
+ *
+ * if (ldvals == NULL || *ldvals == NULL || strcmp(*ldvals, "") == 0 ) {
+ * return(0);
+ * }
+ * return(1);
+ *
+ *}
+ */
+static void
+do_orgchartlink( dsgwtmplinfo *tip, char *dn, unsigned long dispopts,
+ int argc, char **argv )
+{
+ char **ldvals = (char **) dsgw_get_values(tip->dsti_ld, tip->dsti_entry, gc->gc_orgchartsearchattr, 0);
+ char *escaped_value;
+
+ if (gc->gc_orgcharturl == NULL || ldvals == NULL || *ldvals == NULL || strcmp(*ldvals,"") == 0) {
+ dsgw_emits("\"javascript:void(0)\"");
+ return;
+ }
+ dsgw_emits("\"");
+ dsgw_emits(gc->gc_orgcharturl);
+ escaped_value = dsgw_ch_malloc( 3 * strlen( ldvals[0] ) + 1 );
+ *escaped_value = '\0';
+ dsgw_strcat_escaped( escaped_value, ldvals[0]);
+ dsgw_emits(escaped_value);
+ dsgw_emits("\"\n");
+
+ return;
+}
+
+static void
+do_attribute( dsgwtmplinfo *tip, char *dn, unsigned long dispopts,
+ int argc, char **argv )
+{
+ char *attr, *syntax, *defval, *tmpvals[ 2 ], *s;
+ char **ldvals, **vals;
+ unsigned long options;
+ int i, len, attrindex, htmltype;
+ struct dsgw_attrdispinfo adi;
+ int editable = 0;
+ int tagged_attrs = 0;
+ int binary_value = 0;
+
+ if (( attr = get_arg_by_name( DSGW_ATTRARG_ATTR, argc, argv )) == NULL ) {
+ dsgw_emitf( XP_GetClientStr(DBT_missingS_), DSGW_ATTRARG_ATTR );
+ return;
+ }
+ if (( syntax = get_arg_by_name( DSGW_ATTRARG_SYNTAX, argc, argv ))
+ == NULL ) {
+ syntax = "cis";
+ }
+
+ if (( s = get_arg_by_name( DSGW_ATTRARG_HTMLTYPE, argc, argv )) == NULL ) {
+ htmltype = DSGW_ATTRHTML_TEXT;
+ } else {
+ for ( i = 0; attrhtmltypes[ i ] != NULL; ++i ) {
+ if ( strcasecmp( s, attrhtmltypes[ i ] ) == 0 ) {
+ htmltype = attrhtmlvals[ i ];
+ break;
+ }
+ }
+ if ( attrhtmltypes[ i ] == NULL ) {
+ dsgw_emitf( XP_GetClientStr(DBT_unknownSS_), DSGW_ATTRARG_HTMLTYPE, s );
+ return;
+ }
+ }
+
+ options = get_attr_options( argc, argv );
+
+ if (( options & DSGW_ATTROPT_TYPEONLY ) != 0 ) {
+ return; /* don't actually display attr. if we only retrieved types */
+ }
+
+ if (( options & DSGW_ATTROPT_LINK ) != 0 ) {
+ /*
+ * Output a "dosearch" URL that will retrieve this attribute.
+ * These used to look like:
+ * .../dosearch/<host>:<port>?dn=<encodeddn>&<attr>&<mimetype>&<valindex>
+ *
+ * Now, thanks to me, they look like:
+ * .../dosearch?context=<blah>&hp=<host>:<port>&dn=<encodeddn>&ldq=<the rest>
+ * - RJP
+ */
+ char *urlprefix, *escapeddn, *mimetype, *prefix, *suffix;
+
+ urlprefix = dsgw_build_urlprefix();
+ escapeddn = dsgw_strdup_escaped( dn );
+ mimetype = get_arg_by_name( DSGW_ATTRARG_MIMETYPE, argc, argv );
+ if (( prefix = get_arg_by_name( "prefix", argc, argv )) == NULL ) {
+ prefix = "";
+ }
+ if (( suffix = get_arg_by_name( "suffix", argc, argv )) == NULL ) {
+ suffix = "";
+ }
+
+ /* XXXmcs
+ * always reference first value for now ( "&0" ) unless returning
+ * link to a vCard (in which case we leave the &0 off)
+ */
+ dsgw_emitf("%s\"%s%s&ldq=%s&%s%s\"%s\n", prefix, urlprefix, escapeddn, attr,
+ ( mimetype == NULL ) ? "" : mimetype,
+ ( strcasecmp( "_vcard", attr ) == 0 ) ? "" : "&0", suffix );
+ free( urlprefix );
+ free( escapeddn );
+ return;
+ }
+
+ if (( dispopts & DSGW_DISPLAY_OPT_EDITABLE ) != 0
+ && ( options & DSGW_ATTROPT_READONLY ) == 0 ) {
+ options |= DSGW_ATTROPT_EDITABLE;
+ editable = 1;
+ if (( dispopts & DSGW_DISPLAY_OPT_ADDING ) != 0 ) {
+ options |= DSGW_ATTROPT_ADDING;
+ }
+ }
+
+ if (( dispopts & DSGW_DISPLAY_OPT_LINK2EDIT ) != 0 ) {
+ options |= DSGW_ATTROPT_LINK2EDIT;
+ }
+ if ((options & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ options &= ~DSGW_ATTROPT_EDITABLE;/* always read-only */
+ options &= ~DSGW_ATTROPT_ADDING; /* always read-only */
+ options |= DSGW_ATTROPT_READONLY;
+ }
+
+ ldvals = vals = NULL;
+
+ if ( strcasecmp( attr, "dn" ) == 0 ) { /* dn pseudo-attribute */
+ tmpvals[ 0 ] = dn;
+ tmpvals[ 1 ] = NULL;
+ vals = tmpvals;
+ options &= ~DSGW_ATTROPT_EDITABLE; /* always read-only */
+ options &= ~DSGW_ATTROPT_ADDING; /* always read-only */
+ options |= DSGW_ATTROPT_READONLY;
+ } else if( strcasecmp( syntax, "binvalue" ) == 0) {
+
+ binary_value = 1;
+ /* Only display tagged stuff on searches */
+ if (editable){
+ ldvals = (char **) ldap_get_values_len(tip->dsti_ld, tip->dsti_entry, attr);
+ tagged_attrs = 0;
+ } else {
+ ldvals = (char **) dsgw_get_values(tip->dsti_ld, tip->dsti_entry, attr, 1 /*binary value*/);
+ tagged_attrs = 1;
+ }
+
+ if (ldvals != NULL) {
+ vals = ldvals;
+ }
+ } else if ( tip->dsti_entry != NULL) {
+
+ /* Only display tagged stuff on searches */
+ if ( editable){
+ ldvals = (char **) ldap_get_values( tip->dsti_ld, tip->dsti_entry, attr);
+ tagged_attrs = 0;
+ } else {
+ ldvals = (char **) dsgw_get_values( tip->dsti_ld, tip->dsti_entry, attr, 0 );
+ tagged_attrs = 1;
+ }
+ if (ldvals != NULL) {
+ vals = ldvals;
+ }
+ }
+
+ if (vals == NULL && (options & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"\"" );
+ return;
+ }
+
+ if ( vals == NULL && tip->dsti_rdncomps != NULL
+ && ( options & DSGW_ATTROPT_ADDING ) != 0 ) {
+ /*
+ * include values from the DN of new entry being added
+ */
+ len = strlen( attr );
+ ldvals = NULL;
+
+ for ( i = 0; tip->dsti_rdncomps[ i ] != NULL; ++i ) {
+ if (( s = strchr( tip->dsti_rdncomps[ i ], '=' )) != NULL &&
+ s - tip->dsti_rdncomps[ i ] == len &&
+ strncasecmp( attr, tip->dsti_rdncomps[ i ], len ) == 0 ) {
+ tmpvals[ 0 ] = ++s;
+ tmpvals[ 1 ] = NULL;
+ vals = tmpvals;
+ break;
+ }
+ }
+ }
+
+ if ( vals == NULL && ( defval = get_arg_by_name( DSGW_ATTRARG_DEFAULT,
+ argc, argv )) != NULL ) {
+ tmpvals[ 0 ] = defval;
+ tmpvals[ 1 ] = NULL;
+ vals = tmpvals;
+ }
+
+ if ( vals == NULL && ( options & DSGW_ATTROPT_EDITABLE ) == 0 ) {
+ if ( htmltype != DSGW_ATTRHTML_HIDDEN ) {
+ dsgw_HTML_emits( DSGW_UTF8_NBSP );
+ }
+ } else {
+ if (( adi.adi_handlerp = syntax2attrhandler( syntax )) == NULL ) {
+ dsgw_emitf( XP_GetClientStr(DBT_unknownSyntaxSN_), syntax );
+ } else {
+ if ( vals != NULL && vals[1] != NULL
+ && ( options & DSGW_ATTROPT_SORT ) != 0 ) {
+ ldap_sort_values( tip->dsti_ld, vals,
+ dsgw_valcmp (adi.adi_handlerp->ath_compare));
+ }
+ adi.adi_attr = attr;
+ adi.adi_argc = argc;
+ adi.adi_argv = argv;
+ adi.adi_vals = vals;
+ adi.adi_rdn = NULL;
+ adi.adi_htmltype = htmltype;
+ adi.adi_opts = options;
+
+ if (( options & DSGW_ATTROPT_EDITABLE ) == 0 ) {
+ (*adi.adi_handlerp->ath_display)( &adi );
+ } else {
+ if (( options & DSGW_ATTROPT_ADDING ) == 0 ) {
+ /* set flag to track attrs. we have seen */
+ for ( attrindex = 0; tip->dsti_attrs[ attrindex ] != NULL;
+ ++attrindex ) {
+ if ( strcasecmp( attr, tip->dsti_attrs[ attrindex ] )
+ == 0 ) {
+ break;
+ }
+ }
+ if ( tip->dsti_attrs[ attrindex ] != NULL ) {
+ if ( ! (tip->dsti_attrflags[ attrindex ] & DSGW_DSTI_ATTR_SEEN)) {
+ tip->dsti_attrflags[ attrindex ] |= DSGW_DSTI_ATTR_SEEN;
+ dsgw_emitf( "<INPUT TYPE=hidden NAME=\"changed_%s\" VALUE=false>\n",
+ attr );
+ }
+ adi.adi_rdn = find_RDN( dn, attr, vals );
+ }
+ }
+
+ /* display for editing */
+ (*adi.adi_handlerp->ath_edit)( &adi );
+ }
+ }
+ }
+
+ if ( ldvals != NULL ) {
+ if (tagged_attrs) {
+ dsgw_value_free( (void **) ldvals, binary_value );
+ } else {
+ if (binary_value) {
+ ldap_value_free_len( (struct berval **) ldvals );
+ } else {
+ ldap_value_free( ldvals );
+ }
+ }
+ }
+}
+
+
+
+static void
+append_to_array( char ***ap, int *countp, char *s )
+{
+ char **a;
+ int count;
+
+ a = *ap;
+ count = *countp;
+
+ a = (char **)dsgw_ch_realloc( a, ( count + 2 ) * sizeof( char * ));
+ a[ count++ ] = dsgw_ch_strdup( s );
+ a[ count ] = NULL;
+
+ *ap = a;
+ *countp = count;
+}
+
+
+static unsigned long
+get_attr_options( int argc, char **argv )
+{
+ int i;
+ unsigned long opts;
+ char *s;
+
+ opts = 0;
+
+ if (( s = get_arg_by_name( DSGW_ATTRARG_OPTIONS, argc, argv )) != NULL ) {
+ char *p, *q;
+
+ for ( p = dsgw_ch_strdup( s ); p != NULL; p = q ) {
+ if (( q = strchr( p, ',' )) != NULL ) {
+ *q++ = '\0';
+ }
+ for ( i = 0; attroptions[ i ] != NULL; ++i ) {
+ if ( strcasecmp( p, attroptions[ i ] ) == 0 ) {
+ opts |= attroptvals[ i ];
+ break;
+ }
+ }
+ if ( attroptions[ i ] == NULL ) {
+ dsgw_emitf( XP_GetClientStr(DBT_unknownOptionS_), p );
+ break;
+ }
+ }
+ free( p );
+ }
+
+ return( opts );
+}
+
+
+static struct attr_handler *
+syntax2attrhandler( char *syntax )
+{
+ int i;
+
+ for ( i = 0; i < DSGW_AH_COUNT; ++i ) {
+ if ( strcasecmp( syntax, attrhandlers[ i ].ath_syntax ) == 0 ) {
+ return( &attrhandlers[ i ] );
+ }
+ }
+
+ return( NULL );
+}
+
+
+static int
+numfields( int argc, char **argv, int valcount )
+{
+ char *s;
+ int fields;
+
+ if (( s = get_arg_by_name( DSGW_ATTRARGS_NUMFIELDS, argc,
+ argv )) == NULL ) {
+ fields = 1;
+ } else {
+ if ( *s == '+' || *s == ' ') {
+ /* "numfields=+N" means show N more than number of values */
+ fields = valcount + atoi( s + 1 );
+ } else {
+ if ( *s == '>' ) ++s;
+ /* "numfields=N" or "=>N" means show at least N fields */
+ fields = atoi( s );
+ }
+ }
+
+ if ( fields < 1 ) {
+ fields = 1;
+ } else if ( fields < valcount ) {
+ fields = valcount;
+ }
+
+ return( fields );
+}
+
+/*
+ * calculate size of TEXT or TEXTAREA elements based on arguments,
+ * the number of values, and the length of longest value.
+ */
+static void
+element_sizes( int argc, char **argv, char **vals, int valcount,
+ int *rowsp, int *colsp )
+{
+ int i, len, maxlen;
+ char *s;
+
+ /* set *colsp (number of columns in each input item) */
+ if ( colsp != NULL ) {
+ /*
+ * columns are set using the "cols=N" or "size=N" argument
+ * "cols=>N" can be used to indicate at least N columns should be shown
+ * "cols=+N" can be used to size to N more than longest value
+ * in the absence of any of these, we set columns to one more than
+ * the longest value in the "vals" array
+ */
+ if (( s = get_arg_by_name( DSGW_ATTRARGS_COLS, argc, argv )) == NULL ) {
+ s = get_arg_by_name( DSGW_ATTRARGS_SIZE, argc, argv );
+ }
+
+ if ( s != NULL && *s != '+' && *s != ' ' && *s != '>' ) {
+ *colsp = atoi( s ); /* extact width specified */
+ } else if ( valcount == 0 ) {
+ if ( s != NULL && *s == '>' ) {
+ *colsp = atoi( s + 1 );
+ } else {
+ *colsp = 0; /* use default width */
+ }
+ } else {
+ /* determine ( length of longest value ) + 1 */
+ maxlen = 0;
+ for ( i = 0; i < valcount; ++i ) {
+ if (( len = strlen( vals[ i ] )) > maxlen ) {
+ maxlen = len;
+ }
+ }
+ ++maxlen;
+
+ if ( s != NULL ) {
+ i = atoi( s + 1 );
+ if ( *s == ' ' || *s == '+' ) {
+ maxlen += i;
+ } else { /* '>' */
+ if ( maxlen < i ) {
+ maxlen = i;
+ }
+ }
+ }
+ *colsp = maxlen;
+ }
+ }
+
+ /* set *rowsp (number of rows in each input item) */
+ if ( rowsp != NULL ) {
+ /*
+ * rows are set using "rows=M" ("=>M" and "=+M" are supported also)
+ * in the absense of this, we set it to the number of values in the
+ * "vals" array
+ */
+ if (( s = get_arg_by_name( DSGW_ATTRARGS_ROWS, argc, argv )) == NULL ) {
+ *rowsp = valcount;
+ } else if ( *s == ' ' || *s == '+' ) {
+ *rowsp = valcount + atoi( s + 1 );
+ } else if ( *s == '>' ) {
+ if (( *rowsp = atoi( s + 1 )) < valcount ) {
+ *rowsp = valcount;
+ }
+ } else {
+ *rowsp = atoi( s );
+ }
+ }
+}
+
+
+static void
+output_text_elements( int argc, char **argv, char *attr, char **vals,
+ const char* rdn, char *prefix, int htmltype, unsigned long opts )
+{
+ int i, valcount, fields, cols;
+
+ if ( vals == NULL ) {
+ valcount = 0;
+ } else {
+ for ( valcount = 0; vals[ valcount ] != NULL; ++valcount ) {
+ char *syntax = get_arg_by_name( DSGW_ATTRARG_SYNTAX, argc, argv );
+ if ( syntax && 0 == strcasecmp( syntax, "ntdomain" )) {
+ char *pch = (char *)strchr( vals[ valcount ], DSGW_NTDOMAINID_SEP );
+ if( pch )
+ *pch = (char )NULL;
+ }
+ if ( syntax && ( 0 == strcasecmp( syntax, "ntuserid" ) || 0 == strcasecmp( syntax, "ntgroupname") ) ) {
+ char *pch = (char *)strchr( vals[ valcount ], DSGW_NTDOMAINID_SEP );
+ if( pch )
+ {
+ pch++;
+ vals[ valcount] = pch;
+ }
+ }
+ }
+ }
+
+ fields = numfields( argc, argv, valcount );
+ element_sizes( argc, argv, vals, valcount, NULL, &cols );
+
+ for ( i = 0; i < fields; ++i ) {
+ auto const int is_rdn = (i < valcount && vals[ i ] == rdn);
+
+ dsgw_emitf( "<INPUT TYPE=\"%s\"", attrhtmltypes[ htmltype ] );
+
+ dsgw_emitf( " NAME=\"%s%s%s\"", prefix, is_rdn ? "DN_" : "", attr );
+ if ( cols > 0 ) {
+ dsgw_emitf( " SIZE=%d", cols );
+ }
+
+ if ( i < valcount ) {
+ dsgw_emitf( " VALUE=\"%s\"", vals[ i ] );
+ }
+
+ if (( opts & DSGW_TEXTOPT_CHANGEHANDLERS ) != 0 ) {
+ dsgw_emitf( " onChange=\"aChg('%s')\"", is_rdn ? "DN" : attr );
+ }
+ if (( opts & DSGW_TEXTOPT_FOCUSHANDLERS ) != 0 ) {
+ dsgw_emitf( " onFocus=\"aFoc('%s')\"", is_rdn ? "DN" : attr );
+ }
+
+ dsgw_emitf( ">%s\n%s",
+ is_rdn ? " DN" : "",
+ ( i < fields - 1 &&
+ htmltype != DSGW_ATTRHTML_HIDDEN ) ? "<BR>\n" : "" );
+ }
+}
+
+
+static void
+output_textarea( int argc, char **argv, char *attr, char **vals,
+ int valcount, char *prefix, unsigned long opts )
+{
+ int i, rows, cols;
+
+ element_sizes( argc, argv, vals, valcount, &rows, &cols );
+
+ dsgw_emits( "<TEXTAREA" );
+ dsgw_emitf( " NAME=\"%s%s\"", prefix, attr );
+ if ( rows > 0 ) {
+ if ( rows == 1 ) {
+ rows = 2; /* one line TEXTAREAs are ugly! */
+ }
+ dsgw_emitf( " ROWS=%d", rows );
+ }
+
+ if ( cols > 0 ) {
+ dsgw_emitf( " COLS=%d", cols );
+ }
+
+ if (( opts & DSGW_TEXTOPT_CHANGEHANDLERS ) != 0 ) {
+ dsgw_emitf( " onChange=\"aChg('%s')\"", attr );
+ }
+ if (( opts & DSGW_TEXTOPT_FOCUSHANDLERS ) != 0 ) {
+ dsgw_emitf( " onFocus=\"aFoc('%s')\"", attr );
+ }
+
+ dsgw_emits( ">\n" );
+
+ for ( i = 0; i < valcount; ++i ) {
+ dsgw_emits( vals[ i ] );
+ dsgw_emits( "\n" );
+ }
+
+ dsgw_emits( "</TEXTAREA>\n" );
+}
+
+
+static void
+output_text_checkbox_or_radio( struct dsgw_attrdispinfo *adip, char *prefix,
+ int htmltype )
+{
+ int i, checked;
+ char *value;
+
+ /*
+ * for checkboxes or radio buttons that are associated with string values,
+ * we "check the box" if the value found in the "value=XXX" parameter is
+ * present.
+ */
+ checked = 0;
+ if (( value = get_arg_by_name( DSGW_ATTRARGS_VALUE, adip->adi_argc,
+ adip->adi_argv )) == NULL ) {
+ value = "TRUE"; /* assume LDAP Boolean value */
+ }
+ if ( adip->adi_vals == NULL ) {
+ if ( *value == '\0' ) {
+ /*
+ * There are no existing values in the entry and this checkbox or
+ * radio button has a zero-length value associated with it. We
+ * check this box/enable this radio button as a special case to
+ * support an "off" or "none of the rest" scenario.
+ */
+ checked = 1;
+ }
+
+ } else {
+ for ( i = 0; adip->adi_vals[ i ] != NULL; ++i ) {
+ if ( dsgw_valcmp(adip->adi_handlerp->ath_compare)( (const char **)&value,
+ (const char **)&(adip->adi_vals[ i ]) ) == 0 ) {
+ checked = 1;
+ break;
+ }
+ }
+ }
+ dsgw_emitf( "<INPUT TYPE=\"%s\" NAME=\"%s%s\" "
+ "VALUE=\"%s\"%s onClick=\"aChg('%s')\">\n",
+ ( htmltype == DSGW_ATTRHTML_RADIO ) ? "radio" : "checkbox",
+ prefix, adip->adi_attr, value, checked ? " CHECKED" : "",
+ adip->adi_attr );
+}
+
+
+static void
+emit_value( char *val, int quote_html_specials )
+{
+ int freeit;
+
+ if ( quote_html_specials ) {
+ val = dsgw_strdup_with_entities( val, &freeit );
+ } else {
+ freeit = 0;
+ }
+
+ dsgw_emits( val );
+
+ if ( freeit ) {
+ free( val );
+ }
+}
+
+
+/*
+ * Default display handler for binary values
+ */
+static void
+binvalue_display( struct dsgw_attrdispinfo *adip )
+{
+ int i;
+ struct berval **list_of_binvals;
+ char *checked = " CHECKED";
+ char *selected = " SELECTED";
+ int iValue;
+
+ list_of_binvals = (struct berval **)adip->adi_vals;
+
+ for ( i = 0; list_of_binvals[ i ] != NULL; ++i )
+ {
+ char szFlags[512], szFormat[512];
+ struct berval bin_data = *list_of_binvals[i];
+
+ if( !bin_data.bv_val || !bin_data.bv_len )
+ continue;
+
+ /* Now interpret the binary value if it has NT semantics */
+ if( !strcasecmp( adip->adi_attr, "ntuserpriv") )
+ {
+
+ memcpy( &iValue, bin_data.bv_val, sizeof( iValue ) );
+ fprintf( stdout, "<INPUT TYPE=\"radio\" NAME=\"%s\" "
+ "VALUE=\"TRUE\"%s>%s<BR>\n", adip->adi_attr,
+ (iValue == USER_PRIV_GUEST) ? checked : "", DSGW_NT_UP_GUEST);
+ fprintf( stdout, "<INPUT TYPE=\"radio\" NAME=\"%s\" "
+ "VALUE=\"TRUE\"%s>%s<BR>\n", adip->adi_attr,
+ (iValue == USER_PRIV_USER) ? checked : "", DSGW_NT_UP_USER);
+ fprintf( stdout, "<INPUT TYPE=\"radio\" NAME=\"%s\" "
+ "VALUE=\"TRUE\"%s>%s<BR>\n", adip->adi_attr,
+ (iValue == USER_PRIV_ADMIN) ? checked : "", DSGW_NT_UP_ADMIN);
+ }
+ else if ( strcasecmp( adip->adi_attr, "ntuserflags" ) == 0 )
+ {
+ memcpy( &iValue, bin_data.bv_val, sizeof( iValue ) );
+ fprintf( stdout, "<FONT size=-1><SELECT MULTIPLE name=\"%s\" size=5>\n", adip->adi_attr);
+
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_SCRIPT,
+ (iValue & UF_SCRIPT) ? selected : "", DSGW_NT_UF_SCRIPT );
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_ACCOUNT_DISABLED,
+ (iValue & UF_ACCOUNTDISABLE) ? selected : "",
+ DSGW_NT_UF_ACCOUNT_DISABLED);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_HOMEDIR_REQD,
+ (iValue & UF_HOMEDIR_REQUIRED) ? selected : "",
+ DSGW_NT_UF_HOMEDIR_REQD);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_PASSWD_NOTREQD,
+ (iValue & UF_PASSWD_NOTREQD) ? selected : "",
+ DSGW_NT_UF_PASSWD_NOTREQD);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_PASSWD_CANT_CHANGE,
+ (iValue & UF_PASSWD_CANT_CHANGE) ? selected : "",
+ DSGW_NT_UF_PASSWD_CANT_CHANGE);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_LOCKOUT,
+ (iValue & UF_LOCKOUT) ? selected : "", DSGW_NT_UF_LOCKOUT);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_DONT_EXPIRE_PASSWORD,
+ (iValue & UF_DONT_EXPIRE_PASSWD) ? selected : "",
+ DSGW_NT_UF_DONT_EXPIRE_PASSWORD);
+
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_NORMAL_ACCOUNT,
+ (iValue & UF_NORMAL_ACCOUNT) ? selected : "",
+ DSGW_NT_UF_NORMAL_ACCOUNT);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_TEMP_DUPLICATE_ACCOUNT,
+ (iValue & UF_TEMP_DUPLICATE_ACCOUNT) ? selected : "",
+ DSGW_NT_UF_TEMP_DUPLICATE_ACCOUNT);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_TEMP_WRKSTN_TRUST_ACCOUNT,
+ (iValue & UF_WORKSTATION_TRUST_ACCOUNT) ? selected : "",
+ DSGW_NT_UF_TEMP_WRKSTN_TRUST_ACCOUNT);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_TEMP_SERVER_TRUST_ACCOUNT,
+ (iValue & UF_SERVER_TRUST_ACCOUNT) ? selected : "",
+ DSGW_NT_UF_TEMP_SERVER_TRUST_ACCOUNT);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_UF_TEMP_INTERDOMAIN_TRUST_ACCOUNT,
+ (iValue & UF_INTERDOMAIN_TRUST_ACCOUNT) ? selected : "",
+ DSGW_NT_UF_TEMP_INTERDOMAIN_TRUST_ACCOUNT);
+
+ fprintf( stdout, "</SELECT><FONT size=+1>\n" );
+ }
+ else if ( strcasecmp( adip->adi_attr, "ntuserauthflags" ) == 0 )
+ {
+ memcpy( &iValue, bin_data.bv_val, sizeof( iValue ) );
+ fprintf( stdout, "<FONT size=-1><SELECT MULTIPLE name=\"%s\" "
+ "size=4>\n", adip->adi_attr);
+
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_AF_OP_PRINT,
+ (iValue & AF_OP_PRINT) ? selected : "", DSGW_NT_AF_OP_PRINT);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_AF_OP_COMM,
+ (iValue & AF_OP_COMM) ? selected : "", DSGW_NT_AF_OP_COMM);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_AF_OP_SERVER,
+ (iValue & AF_OP_SERVER) ? selected : "", DSGW_NT_AF_OP_SERVER);
+ fprintf( stdout, "<OPTION value=\"%s\" %s>%s\n", DSGW_NT_AF_OP_ACCOUNTS,
+ (iValue & AF_OP_ACCOUNTS) ? selected : "", DSGW_NT_AF_OP_ACCOUNTS);
+
+ fprintf( stdout, "</SELECT><FONT size=+1>\n" );
+ }
+ else if ( bin_data.bv_val && ( bin_data.bv_len != 0 ))
+ {
+ if( bin_data.bv_len == 4 )
+ {
+ memcpy( &iValue, bin_data.bv_val, sizeof( iValue ) );
+
+ if(( adip->adi_opts & DSGW_ATTROPT_DECIMAL ) != 0 )
+ PR_snprintf( szFormat, 512, "%%lu" );
+ else
+ PR_snprintf( szFormat, 512, "%%#0%lu.%lux", bin_data.bv_len*2, bin_data.bv_len*2 );
+ PR_snprintf( szFlags, 512, szFormat, iValue );
+
+ fputs( szFlags, stdout );
+
+ if ( list_of_binvals[ i + 1 ] != NULL )
+ {
+ fputs( "<BR>\n", stdout );
+ }
+ }
+ }
+ }
+}
+
+/*
+ * display handler for NT Domain Identifier string
+ */
+static void
+ntdomain_display( struct dsgw_attrdispinfo *adip )
+{
+ int i;
+
+ /* Write values with a break (<BR>) separating them,
+ removing all after ":" */
+ for ( i = 0; adip->adi_vals[ i ] != NULL; ++i ) {
+ if ( !did_output_as_special( adip->adi_argc, adip->adi_argv,
+ adip->adi_vals[ i ], adip->adi_vals[ i ] )) {
+ char *pch = strchr( adip->adi_vals[ i ], DSGW_NTDOMAINID_SEP );
+ if( pch )
+ *pch = (char )NULL;
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+
+ fputs( adip->adi_vals[ i ], stdout );
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ }
+
+ if ( adip->adi_vals[ i + 1 ] != NULL ) {
+ fputs( "<BR>\n", stdout );
+ }
+ }
+
+}
+
+
+
+/*
+ * display handler for simple strings
+ */
+static void
+str_display( struct dsgw_attrdispinfo *adip )
+{
+ int i;
+
+ if ( adip->adi_htmltype == DSGW_ATTRHTML_CHECKBOX ||
+ adip->adi_htmltype == DSGW_ATTRHTML_RADIO ) {
+ output_text_checkbox_or_radio( adip, "", adip->adi_htmltype );
+ return;
+ }
+
+ /* just write values with a break (<BR>) separating them */
+ for ( i = 0; adip->adi_vals[ i ] != NULL; ++i ) {
+
+ if ( !did_output_as_special( adip->adi_argc, adip->adi_argv,
+ adip->adi_vals[ i ], adip->adi_vals[ i ] ) &&
+ adip->adi_htmltype != DSGW_ATTRHTML_HIDDEN ) {
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ emit_value( adip->adi_vals[ i ],
+ (( adip->adi_opts & DSGW_ATTROPT_NO_ENTITIES ) == 0 ));
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ }
+
+ if ( adip->adi_htmltype != DSGW_ATTRHTML_HIDDEN &&
+ adip->adi_vals[ i + 1 ] != NULL ) {
+ dsgw_emits( "<BR>\n" );
+ }
+ }
+
+}
+
+
+static void
+ntuserid_display( struct dsgw_attrdispinfo *adip )
+{
+ int i;
+
+ /* Write values with a break (<BR>) separating them, after ":" */
+ for ( i = 0; adip->adi_vals[ i ] != NULL; ++i ) {
+ if ( !did_output_as_special( adip->adi_argc, adip->adi_argv,
+ adip->adi_vals[ i ], adip->adi_vals[ i ] )) {
+ char *pch = strchr( adip->adi_vals[ i ], DSGW_NTDOMAINID_SEP );
+ if( pch ) {
+ pch++;
+
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+
+ fputs( pch, stdout );
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ }
+ }
+
+ if ( adip->adi_vals[ i + 1 ] != NULL ) {
+ fputs( "<BR>\n", stdout );
+ }
+ }
+
+}
+
+
+
+/*
+ * edit handler for simple strings
+ */
+static void
+str_edit( struct dsgw_attrdispinfo *adip )
+{
+ int valcount, adding, pre_idx;
+ char *prefix;
+ unsigned long textopts;
+
+ adding = (( adip->adi_opts & DSGW_ATTROPT_ADDING ) != 0 );
+ if (( adip->adi_opts & DSGW_ATTROPT_UNIQUE ) == 0 ) {
+ pre_idx = DSGW_MOD_PREFIX_NORMAL;
+ } else {
+ pre_idx = DSGW_MOD_PREFIX_UNIQUE;
+ }
+ prefix = adding ? add_prefixes[ pre_idx ] : replace_prefixes[ pre_idx ];
+
+ textopts = DSGW_TEXTOPT_CHANGEHANDLERS;
+ if ( !adding ) {
+ textopts |= DSGW_TEXTOPT_FOCUSHANDLERS;
+ }
+
+ switch( adip->adi_htmltype ) {
+ case DSGW_ATTRHTML_TEXTAREA:
+ if ( adip->adi_vals == NULL ) {
+ valcount = 0;
+ } else {
+ for ( valcount = 0; adip->adi_vals[ valcount ] != NULL;
+ ++valcount ) {
+ ;
+ }
+ }
+ output_textarea( adip->adi_argc, adip->adi_argv, adip->adi_attr,
+ adip->adi_vals, valcount, prefix, textopts );
+ break;
+
+ case DSGW_ATTRHTML_TEXT:
+ case DSGW_ATTRHTML_HIDDEN:
+ output_text_elements( adip->adi_argc, adip->adi_argv, adip->adi_attr,
+ adip->adi_vals, adip->adi_rdn, prefix, adip->adi_htmltype, textopts );
+ break;
+
+ case DSGW_ATTRHTML_CHECKBOX:
+ case DSGW_ATTRHTML_RADIO:
+ output_text_checkbox_or_radio( adip, prefix, adip->adi_htmltype );
+ break;
+
+ default:
+ dsgw_emitf( XP_GetClientStr(DBT_HtmlTypeSNotSupportedBrN_),
+ attrhtmltypes[ adip->adi_htmltype ] );
+ }
+}
+
+
+/*
+ * display handler for multi-line strings, e.g. postalAddress
+ * these are funny in that over LDAP, lines are separated by " $ "
+ * this only support "htmltype=text"
+ */
+static void
+mls_display( struct dsgw_attrdispinfo *adip )
+{
+ int i;
+
+ for ( i = 0; adip->adi_vals[ i ] != NULL; ++i ) {
+ if ( !did_output_as_special( adip->adi_argc, adip->adi_argv,
+ adip->adi_vals[ i ], adip->adi_vals[ i ] )) {
+ (void)dsgw_mls_convertlines( adip->adi_vals[ i ], "<BR>\n", NULL,
+ 1, ( adip->adi_opts & DSGW_ATTROPT_NO_ENTITIES ) == 0 );
+ }
+
+ if ( adip->adi_vals[ i + 1 ] != NULL ) {
+ dsgw_emits( "<BR><BR>\n" );
+ }
+ }
+}
+
+
+/*
+ * edit handler for multi-line strings
+ */
+static void
+mls_edit( struct dsgw_attrdispinfo *adip )
+{
+ char *prefix, **valscopy, *tval[ 2 ];
+ int i, valcount, adding, pre_idx, *lines;
+ unsigned long textopts;
+
+ adding = (( adip->adi_opts & DSGW_ATTROPT_ADDING ) != 0 );
+ textopts = DSGW_TEXTOPT_CHANGEHANDLERS;
+ if ( !adding ) {
+ textopts |= DSGW_TEXTOPT_FOCUSHANDLERS;
+ }
+
+ if (( adip->adi_opts & DSGW_ATTROPT_UNIQUE ) == 0 ) {
+ pre_idx = DSGW_MOD_PREFIX_NORMAL;
+ } else {
+ pre_idx = DSGW_MOD_PREFIX_UNIQUE;
+ }
+ prefix = adding ? add_mls_prefixes[ pre_idx ] :
+ replace_mls_prefixes[ pre_idx ];
+
+ if ( adip->adi_vals == NULL ) {
+ valscopy = NULL;
+ } else {
+ for ( valcount = 0; adip->adi_vals[ valcount ] != NULL; ++valcount ) {
+ ;
+ }
+ valscopy = (char **)dsgw_ch_malloc( (valcount + 1) * sizeof( char * ));
+ lines = (int *)dsgw_ch_malloc( valcount * sizeof( int ));
+ for ( i = 0; i < valcount; ++i ) {
+ valscopy[ i ] = dsgw_mls_convertlines( adip->adi_vals[ i ], "\n",
+ &lines[ i ], 0, 0 );
+ }
+ valscopy[ valcount ] = NULL;
+ }
+
+ if ( adip->adi_htmltype == DSGW_ATTRHTML_TEXTAREA ) {
+ if ( adip->adi_vals == NULL ) {
+ output_textarea( adip->adi_argc, adip->adi_argv, adip->adi_attr,
+ NULL, 0, prefix, textopts );
+ } else {
+ tval[ 1 ] = NULL;
+ for ( i = 0; i < valcount; ++i ) {
+ tval[ 0 ] = valscopy[ i ];
+ output_textarea( adip->adi_argc, adip->adi_argv,
+ adip->adi_attr, tval, 1, prefix, textopts );
+ if ( i < valcount - 1 ) {
+ dsgw_emits( "<BR>\n" );
+ }
+ }
+ }
+ } else {
+ output_text_elements( adip->adi_argc, adip->adi_argv, adip->adi_attr,
+ valscopy, NULL, prefix, adip->adi_htmltype, textopts );
+ /* Bug: what if adip->adi_rdn != NULL? In this case,
+ the element of valscopy that is a copy of adi_rdn
+ should be passed to output_text_elements (as the rdn).
+ */
+ }
+
+ if ( valscopy != NULL ) {
+ ldap_value_free( valscopy );
+ free( lines );
+ }
+}
+
+
+/*
+ * convert all occurrences of "$" in val to sep
+ * un-escape any \HH sequences
+ * if linesp != NULL, set *linesp equal to number of lines in val
+ * if emitlines is zero, a malloc'd string is returned.
+ * if emitlines is non-zero, values are written to stdout (respecting the
+ * quote_html_specials flag) and NULL is returned.
+ */
+char *
+dsgw_mls_convertlines( char *val, char *sep, int *linesp, int emitlines,
+ int quote_html_specials )
+{
+ char *valcopy, *p, *q, *curline;
+ int i, c, lines, seplen;
+
+ if ( sep == NULL ) {
+ sep = "";
+ seplen = 0;
+ } else {
+ seplen = strlen( sep );
+ }
+
+ lines = 0;
+ for ( q = val; *q != '\0'; ++q ) {
+ if ( *q == '$' ) {
+ ++lines;
+ }
+ }
+
+ if ( linesp != NULL ) {
+ *linesp = lines;
+ }
+
+ valcopy = dsgw_ch_malloc( strlen( val ) + lines * seplen + 1 );
+
+ /*
+ * p points to the place we are copying to
+ * q points to the place within the original value that we are examining
+ * curline points to the start of the current line
+ */
+ p = curline = valcopy;
+ for ( q = val; *q != '\0'; ++q ) {
+ if ( *q == '$' ) { /* line separator */
+ if ( emitlines ) {
+ *p = '\0';
+ emit_value( curline, quote_html_specials );
+ emit_value( sep, 0 );
+ }
+ strcpy( p, sep );
+ p += seplen;
+ curline = p;
+ } else if ( *q == '\\' ) { /* undo hex escapes */
+ if ( *++q == '\0' ) {
+ break;
+ }
+ c = toupper( *q );
+ i = ( c >= 'A' ? ( c - 'A' + 10 ) : c - '0' );
+ i <<= 4;
+ if ( *++q == '\0' ) {
+ break;
+ }
+ c = toupper( *q );
+ i += ( c >= 'A' ? ( c - 'A' + 10 ) : c - '0' );
+ *p++ = i;
+ } else {
+ *p++ = *q;
+ }
+ }
+
+ *p = '\0';
+
+ if ( emitlines ) {
+ if ( p > curline ) {
+ emit_value( curline, quote_html_specials );
+ }
+ free( valcopy );
+ valcopy = NULL;
+ }
+
+ return( valcopy );
+}
+
+
+static void
+dn_edit( struct dsgw_attrdispinfo *adip )
+{
+ if (( adip->adi_opts & DSGW_ATTROPT_DNPICKER ) != 0 ) {
+ dn_display( adip );
+ } else {
+ str_edit( adip );
+ }
+ return;
+}
+
+
+static void
+dn_display( struct dsgw_attrdispinfo *adip )
+{
+ int i, j, len, dncomps;
+ char *p, *staticlabel, *tmps = NULL, *label, *urlprefix, **rdns = NULL;
+
+ staticlabel = get_arg_by_name( DSGW_ATTRARG_LABEL, adip->adi_argc,
+ adip->adi_argv );
+
+ if (( p = get_arg_by_name( DSGW_ATTRARG_DNCOMP, adip->adi_argc,
+ adip->adi_argv )) == NULL ) {
+ dncomps = 1;
+ } else {
+ dncomps = atoi( p ); /* 0 or "all" means show all components */
+ }
+
+ if (( adip->adi_opts & DSGW_ATTROPT_LINK2EDIT ) != 0 ) {
+ auto const char* vp = dsgw_getvp( DSGW_CGINUM_EDIT );
+ /* urlprefix = vp + "?&context=CONTEXT&dn=": */
+ auto const size_t vplen = strlen (vp);
+ urlprefix = dsgw_ch_malloc (vplen + 6 + strlen(context) + 9);
+ memcpy( urlprefix, vp, vplen );
+ strcat( urlprefix, "?&context=");
+ strcat( urlprefix, context);
+ strcat( urlprefix, "&dn=");
+ } else {
+ urlprefix = dsgw_build_urlprefix();
+ }
+#ifdef DSGW_DEBUG
+ dsgw_log( "dn_display: urlprefix is %s\n", urlprefix );
+#endif
+
+ for ( i = 0; adip->adi_vals != NULL && adip->adi_vals[ i ] != NULL; ++i ) {
+ if ( staticlabel != NULL ) {
+ label = staticlabel;
+ } else if ( !looks_like_dn( adip->adi_vals[ i ]) ||
+ ( rdns = ldap_explode_dn( adip->adi_vals[ i ],
+ ( adip->adi_opts & DSGW_ATTROPT_DNTAGS ) == 0 )) == NULL ) {
+ /* explode DN failed -- show entire DN */
+ label = adip->adi_vals[ i ];
+ tmps = NULL;
+ } else {
+ len = 1; /* room for zero-termination */
+ for ( j = 0; rdns[ j ] != NULL && ( dncomps == 0 || j < dncomps );
+ ++ j ) {
+ len += ( 2 + strlen( rdns[ j ] )); /* rdn + ", " */
+ }
+ label = p = tmps = dsgw_ch_malloc( len );
+ for ( j = 0; rdns[ j ] != NULL && ( dncomps == 0 || j < dncomps );
+ ++ j ) {
+ if ( j > 0 ) {
+ strcpy( p, ", " );
+ p += 2;
+ }
+ strcpy( p, rdns[ j ] );
+ p += strlen( p );
+ }
+ }
+
+ if ( !did_output_as_special( adip->adi_argc, adip->adi_argv, label,
+ adip->adi_vals[ i ] )) {
+ if (( adip->adi_opts & DSGW_ATTROPT_NOLINK ) == 0 &&
+ looks_like_dn( adip->adi_vals[ i ] )) {
+ if (( adip->adi_opts & DSGW_ATTROPT_DNPICKER ) != 0 ) {
+ dsgw_emits( "<TR><TD>" );
+ }
+ /* Don't display a link for the rootdn */
+ if ( gc->gc_rootdn && dsgw_dn_cmp(adip->adi_vals[i], gc->gc_rootdn)) {
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ dsgw_emits( label );
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ } else {
+ dsgw_html_href( urlprefix, adip->adi_vals[ i ], label,
+ adip->adi_vals[ i ],
+ get_arg_by_name( DSGW_ATTRARG_HREFEXTRA,
+ adip->adi_argc, adip->adi_argv ));
+ }
+ if (( adip->adi_opts & DSGW_ATTROPT_DNPICKER ) != 0 ) {
+ dsgw_emits( "</TD>\n<TD ALIGN=CENTER><INPUT TYPE=CHECKBOX " );
+ dsgw_emitf( "VALUE=\"%s\" NAME=delete_%s ",
+ adip->adi_vals[ i ], adip->adi_attr );
+ dsgw_emitf( "onClick=\"aChg('%s');\"</TD>\n</TR>\n",
+ adip->adi_attr );
+ }
+ } else {
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+
+ emit_value( label,
+ (( adip->adi_opts & DSGW_ATTROPT_NO_ENTITIES ) == 0 ));
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ }
+ }
+
+ if ( !( adip->adi_opts & DSGW_ATTROPT_DNPICKER ) &&
+ adip->adi_vals[ i + 1 ] != NULL ) {
+ dsgw_emits( "<BR>\n" );
+ }
+
+ if ( tmps != NULL ) {
+ free( tmps );
+ }
+
+ if ( rdns != NULL ) {
+ ldap_value_free( rdns );
+ }
+ }
+
+
+ /* Output a javascript array of values for this attribute */
+ if (( adip->adi_opts & DSGW_ATTROPT_DNPICKER ) != 0 ) {
+ dsgw_emits( "<SCRIPT LANGUAGE=\"JavaScript\">\n" );
+ dsgw_emits( "<!-- Hide from non-JavaScript-capable browsers\n" );
+ dsgw_emitf( "var %s_values = new Object;\n", adip->adi_attr );
+ for ( i = 0; adip->adi_vals != NULL && adip->adi_vals[ i ] != NULL; ++i ) {
+ char *edn;
+ edn = dsgw_strdup_escaped( adip->adi_vals[ i ]);
+ dsgw_emitf( "%s_values[%d] = \"%s\";\n", adip->adi_attr, i,
+ edn );
+ free( edn );
+ }
+ dsgw_emitf( "%s_values.count = %d;\n", adip->adi_attr, i );
+ dsgw_emits( "// End hiding -->\n" );
+ dsgw_emits( "</SCRIPT>\n" );
+ }
+
+ free( urlprefix );
+}
+
+
+static void
+mail_display( struct dsgw_attrdispinfo *adip )
+{
+ int i;
+
+ for ( i = 0; adip->adi_vals[ i ] != NULL; ++i ) {
+ if ( !did_output_as_special( adip->adi_argc, adip->adi_argv,
+ adip->adi_vals[ i ], adip->adi_vals[ i ] )) {
+ if (( adip->adi_opts & DSGW_ATTROPT_NOLINK ) == 0 ) {
+ dsgw_html_href( "mailto:", adip->adi_vals[ i ], adip->adi_vals[ i ], NULL,
+ get_arg_by_name( DSGW_ATTRARG_HREFEXTRA,
+ adip->adi_argc, adip->adi_argv ));
+ } else {
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+
+ emit_value( adip->adi_vals[ i ],
+ (( adip->adi_opts & DSGW_ATTROPT_NO_ENTITIES ) == 0 ));
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+
+ }
+ }
+
+ if ( adip->adi_vals[ i + 1 ] != NULL ) {
+ dsgw_emits( "<BR>\n" );
+ }
+ }
+
+}
+
+
+static void
+url_display( struct dsgw_attrdispinfo *adip )
+{
+ int i;
+ char *savep, *label;
+
+ for ( i = 0; adip->adi_vals[ i ] != NULL; ++i ) {
+ if (( label = strchr( adip->adi_vals[ i ], ' ' )) == NULL ) {
+ label = adip->adi_vals[ i ];
+ savep = NULL;
+ } else {
+ savep = label;
+ *label++ = '\0';
+ }
+
+ if ( !did_output_as_special( adip->adi_argc, adip->adi_argv, label,
+ adip->adi_vals[ i ] )) {
+ if (( adip->adi_opts & DSGW_ATTROPT_NOLINK ) == 0 ) {
+ dsgw_html_href( NULL, adip->adi_vals[ i ], label, NULL,
+ get_arg_by_name( DSGW_ATTRARG_HREFEXTRA,
+ adip->adi_argc, adip->adi_argv ));
+ } else {
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+
+ emit_value( adip->adi_vals[ i ],
+ (( adip->adi_opts & DSGW_ATTROPT_NO_ENTITIES ) == 0 ));
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+
+ }
+ }
+
+ if ( savep != NULL ) {
+ *savep = ' ';
+ }
+
+ if ( adip->adi_vals[ i + 1 ] != NULL ) {
+ dsgw_emits( "<BR>\n" );
+ }
+ }
+
+}
+
+
+static void
+bool_display( struct dsgw_attrdispinfo *adip )
+{
+ int boolval, free_onclick, pre_idx;
+ char *usestr, *truestr, *falsestr, *checked;
+ char *nameprefix, *onclick;
+
+ if ( adip->adi_vals == NULL || adip->adi_vals[ 0 ] == NULL ) {
+ return;
+ }
+
+ checked = " CHECKED";
+
+ if (( adip->adi_opts & DSGW_ATTROPT_EDITABLE ) == 0 ) {
+ nameprefix = onclick = "";
+ free_onclick = 0;
+ } else {
+ char *onclickfmt = " onClick=\"aChg('%s')\"";
+
+ if (( adip->adi_opts & DSGW_ATTROPT_UNIQUE ) == 0 ) {
+ pre_idx = DSGW_MOD_PREFIX_NORMAL;
+ } else {
+ pre_idx = DSGW_MOD_PREFIX_UNIQUE;
+ }
+ nameprefix = (( adip->adi_opts & DSGW_ATTROPT_ADDING ) == 0 ) ?
+ replace_prefixes[ pre_idx ] : add_prefixes[ pre_idx ];
+ onclick = dsgw_ch_malloc( strlen( onclickfmt ) +
+ strlen( adip->adi_attr ) + 1 );
+ sprintf( onclick, onclickfmt, adip->adi_attr );
+ free_onclick = 1;
+ }
+
+ if (( truestr = get_arg_by_name( DSGW_ATTRARG_TRUESTR, adip->adi_argc,
+ adip->adi_argv )) == NULL ) {
+ truestr = DSGW_ATTRARG_TRUESTR;
+ }
+ if (( falsestr = get_arg_by_name( DSGW_ATTRARG_FALSESTR, adip->adi_argc,
+ adip->adi_argv )) == NULL ) {
+ falsestr = DSGW_ATTRARG_FALSESTR;
+ }
+
+ boolval = ( toupper( adip->adi_vals[ 0 ][ 0 ] ) == 'T' );
+
+ if ( adip->adi_htmltype == DSGW_ATTRHTML_RADIO ) {
+ dsgw_emitf( "<INPUT TYPE=\"radio\" NAME=\"%s%s\" "
+ "VALUE=\"TRUE\"%s%s>%s<BR>\n", nameprefix, adip->adi_attr,
+ boolval ? checked : "", onclick, truestr );
+ dsgw_emitf( "<INPUT TYPE=\"radio\" NAME=\"%s%s\" "
+ "VALUE=\"FALSE\"%s%s>%s<BR>\n", nameprefix, adip->adi_attr,
+ boolval ? "" : checked, onclick, falsestr );
+ } else if ( adip->adi_htmltype == DSGW_ATTRHTML_CHECKBOX ) {
+ dsgw_emitf( "<INPUT TYPE=\"checkbox\" NAME=\"%s%s\" "
+ "VALUE=\"TRUE\"%s%s\">%s\n", nameprefix, adip->adi_attr,
+ boolval ? checked : "", onclick, truestr );
+ } else {
+ usestr = boolval ? truestr : falsestr;
+ if ( !did_output_as_special( adip->adi_argc, adip->adi_argv, usestr,
+ adip->adi_vals[ 0 ] )) {
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+
+ dsgw_emits( boolval ? truestr : falsestr );
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ }
+ }
+}
+
+
+static void
+bool_edit( struct dsgw_attrdispinfo *adip )
+{
+ if ( adip->adi_htmltype == DSGW_ATTRHTML_RADIO ||
+ adip->adi_htmltype == DSGW_ATTRHTML_CHECKBOX ) {
+ bool_display( adip );
+ } else {
+ str_edit( adip );
+ }
+}
+
+
+static void
+time_display( struct dsgw_attrdispinfo *adip )
+{
+ int i;
+
+ for ( i = 0; adip->adi_vals[ i ] != NULL; ++i ) {
+ if ( !did_output_as_special( adip->adi_argc, adip->adi_argv,
+ adip->adi_vals[ i ], adip->adi_vals[ i ] )) {
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ dsgw_emits( time2text( adip->adi_vals[ i ],
+ ( adip->adi_opts & DSGW_ATTROPT_DATEONLY ) != 0 ) );
+ if ((adip->adi_opts & DSGW_ATTROPT_QUOTED ) != 0 ) {
+ dsgw_emits( "\"" );
+ }
+ }
+
+ if ( adip->adi_vals[ i + 1 ] != NULL ) {
+ dsgw_emits( "<BR>\n" );
+ }
+ }
+
+}
+
+
+/*
+ * handle special "within=", "href=", and "script=" options
+ * return 0 if nothing was output or 1 if something was.
+ */
+static int
+did_output_as_special( int argc, char **argv, char *label, char *val )
+{
+ char *href = NULL;
+ char *within = NULL;
+ char *script = NULL;
+ char *newval = NULL;
+
+ if (( href = get_arg_by_name( DSGW_ATTRARG_HREF, argc, argv )) == NULL &&
+ ( within = get_arg_by_name( DSGW_ATTRARG_WITHIN, argc,
+ argv )) == NULL &&
+ ( script = get_arg_by_name( DSGW_ATTRARG_SCRIPT, argc,
+ argv )) == NULL ) {
+ return( 0 );
+ }
+
+ if ( within != NULL ) {
+ dsgw_substitute_and_output( within, "--value--", val, 1 );
+ } else if (href != NULL) {
+ dsgw_html_href( NULL, href, label, val,
+ get_arg_by_name( DSGW_ATTRARG_HREFEXTRA, argc, argv ));
+ } else if (script != NULL) {
+ newval = dsgw_strdup_escaped ( val );
+ if (newval != NULL && *newval != '\0') {
+ fputs( newval, stdout );
+ free( newval );
+ }
+ }
+
+ return( 1 );
+}
+
+
+/*
+ * The GET2BYTENUM() macro, time2text(), and gtime() functions are taken
+ * with slight changes (to handle 4-digit years) from libldap/tmplout.c
+ */
+#define GET2BYTENUM( p ) (( *p - '0' ) * 10 + ( *(p+1) - '0' ))
+#define BSIZ 1024
+
+static char *
+time2text( char *ldtimestr, int dateonly )
+{
+ int len;
+ struct tm t;
+ char *p, zone;
+ time_t gmttime;
+ char *timestr = NULL;
+
+ memset( (char *)&t, 0, sizeof( struct tm ));
+ if (( len = strlen( ldtimestr )) < 13 ) {
+ return( ldtimestr );
+ }
+ if ( len > 15 ) { /* throw away excess from 4-digit year time string */
+ len = 15;
+ } else if ( len == 14 ) {
+ len = 13; /* assume we have a time w/2-digit year (len=13) */
+ }
+
+ for ( p = ldtimestr; p - ldtimestr + 1 < len; ++p ) {
+ if ( !ldap_utf8isdigit( p )) {
+ return( ldtimestr );
+ }
+ }
+
+ p = ldtimestr;
+ t.tm_year = GET2BYTENUM( p ); p += 2;
+ if ( len == 15 ) {
+ t.tm_year = 100 * (t.tm_year - 19);
+ t.tm_year += GET2BYTENUM( p ); p += 2;
+ }
+ else {
+ /* 2 digit years...assumed to be in the range (19)70 through
+ (20)69 ...less than 70 (for now, 38) means 20xx */
+ if(t.tm_year < 70) {
+ t.tm_year += 100;
+ }
+ }
+
+ t.tm_mon = GET2BYTENUM( p ) - 1; p += 2;
+ t.tm_mday = GET2BYTENUM( p ); p += 2;
+ t.tm_hour = GET2BYTENUM( p ); p += 2;
+ t.tm_min = GET2BYTENUM( p ); p += 2;
+ t.tm_sec = GET2BYTENUM( p ); p += 2;
+
+ if (( zone = *p ) == 'Z' ) { /* GMT */
+ zone = '\0'; /* no need to indicate on screen, so we make it null */
+ }
+
+ gmttime = gtime( &t );
+
+ /* Try to get the localized string */
+ timestr = dsgw_time(gmttime);
+
+ /* Localized time string getter failed, try ctime()*/
+ if (timestr == NULL){
+ timestr = ctime( &gmttime );
+
+ /* replace trailing newline */
+ timestr[ strlen( timestr ) - 1 ] = zone;
+ if ( dateonly ) {
+ strcpy( timestr + 11, timestr + 20 );
+ }
+ }
+
+ return(timestr);
+}
+
+
+
+
+
+/* gtime.c - inverse gmtime */
+
+#if !defined( MACOS ) && !defined( _WINDOWS ) && !defined( DOS )
+#include <sys/time.h>
+#endif /* !MACOS */
+
+/* gtime(): the inverse of localtime().
+ This routine was supplied by Mike Accetta at CMU many years ago.
+ */
+
+static int dmsize[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define dysize(y) \
+ (((y) % 4) ? 365 : (((y) % 100) ? 366 : (((y) % 400) ? 365 : 366)))
+
+/*
+#define YEAR(y) ((y) >= 100 ? (y) : (y) + 1900)
+*/
+#define YEAR(y) (((y) < 1900) ? ((y) + 1900) : (y))
+
+
+/* */
+
+static long gtime ( struct tm *tm )
+{
+ register int i,
+ sec,
+ mins,
+ hour,
+ mday,
+ mon,
+ year;
+ register long result;
+
+ if ((sec = tm -> tm_sec) < 0 || sec > 59
+ || (mins = tm -> tm_min) < 0 || mins > 59
+ || (hour = tm -> tm_hour) < 0 || hour > 24
+ || (mday = tm -> tm_mday) < 1 || mday > 31
+ || (mon = tm -> tm_mon + 1) < 1 || mon > 12)
+ return ((long) -1);
+ if (hour == 24) {
+ hour = 0;
+ mday++;
+ }
+ year = YEAR (tm -> tm_year);
+
+ result = 0L;
+ for (i = 1970; i < year; i++)
+ result += dysize (i);
+ if (dysize (year) == 366 && mon >= 3)
+ result++;
+ while (--mon)
+ result += dmsize[mon - 1];
+ result += mday - 1;
+ result = 24 * result + hour;
+ result = 60 * result + mins;
+ result = 60 * result + sec;
+
+ return result;
+}
+
+
+static int
+looks_like_dn( char *s )
+{
+ return( strchr( s, '=' ) != NULL );
+}
+
+
+static void
+do_searchdesc( dsgwtmplinfo *tip, int argc, char** argv)
+{
+ auto unsigned fmt = 0;
+ auto unsigned opt = 0;
+ {
+ auto int i;
+ for (i = 0; i < argc; ++i) {
+ if (!strcasecmp (argv[i], "VERBOSE")) {
+ opt |= 1;
+ }
+ }
+ }
+ switch ( tip->dsti_entrycount ) {
+ case 0:
+ fmt = opt & 1
+ ? ((tip->dsti_options & DSGW_DISPLAY_OPT_CUSTOM_SEARCHDESC)
+ ? DBT_SearchFound0Entries_
+ : DBT_SearchFound0EntriesWhere_)
+ : ((tip->dsti_options & DSGW_DISPLAY_OPT_CUSTOM_SEARCHDESC)
+ ? DBT_Found0Entries_
+ : DBT_Found0EntriesWhere_);
+ case 1:
+ fmt = opt & 1
+ ? ((tip->dsti_options & DSGW_DISPLAY_OPT_CUSTOM_SEARCHDESC)
+ ? DBT_SearchFound1Entry_
+ : DBT_SearchFound1EntryWhere_)
+ : ((tip->dsti_options & DSGW_DISPLAY_OPT_CUSTOM_SEARCHDESC)
+ ? DBT_Found1Entry_
+ : DBT_Found1EntryWhere_);
+ default:
+ fmt = opt & 1
+ ? ((tip->dsti_options & DSGW_DISPLAY_OPT_CUSTOM_SEARCHDESC)
+ ? DBT_SearchFoundEntries_
+ : DBT_SearchFoundEntriesWhere_)
+ : ((tip->dsti_options & DSGW_DISPLAY_OPT_CUSTOM_SEARCHDESC)
+ ? DBT_FoundEntries_
+ : DBT_FoundEntriesWhere_);
+ }
+ {
+ auto char* format = XP_GetClientStr (fmt);
+ if (format == NULL || *format == '\0') {
+ format = "Found %1$li entries where the %2$s %3$s '%4$s'.\n";
+ }
+ dsgw_emitf (format, (long)tip->dsti_entrycount, /* %1$li */
+ tip->dsti_search2s ? tip->dsti_search2s : "", /* %2$s */
+ tip->dsti_search3s ? tip->dsti_search3s : "", /* %3$s */
+ tip->dsti_search4s ? tip->dsti_search4s : "");/* %4$s */
+ }
+ if ( tip->dsti_searcherror != NULL && *tip->dsti_searcherror != '\0' ) {
+ dsgw_emitf( "<BR>%s\n", tip->dsti_searcherror );
+ }
+ if ( tip->dsti_searchlderrtxt != NULL &&
+ *tip->dsti_searchlderrtxt != '\0' ) {
+ dsgw_emitf( "<BR>(%s)\n", tip->dsti_searchlderrtxt );
+ }
+}
+
+
+static void
+do_editbutton( char *dn, char *encodeddn, int argc, char **argv )
+{
+ char *buttonlabel, **rdns;
+
+ if (( buttonlabel = get_arg_by_name( DSGW_ARG_BUTTON_LABEL, argc,
+ argv )) == NULL ) {
+ buttonlabel = XP_GetClientStr(DBT_edit_);
+ }
+
+ if (( rdns = ldap_explode_dn( dn, 1 )) != NULL ) {
+ dsgw_emitf(
+ "<INPUT TYPE=\"hidden\" NAME=\"authhint\" VALUE=\"%s\">\n",
+ rdns[ 0 ] );
+ ldap_value_free( rdns );
+ }
+
+ dsgw_emitf( "<INPUT TYPE=\"hidden\" NAME=\"authdesturl\">\n"
+ "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"authOrEdit('%s')\">\n", buttonlabel, encodeddn );
+}
+
+
+static void
+do_savebutton( unsigned long dispopts, int argc, char **argv )
+{
+ char *buttonlabel, *checksubmit;
+
+ if (( buttonlabel = get_arg_by_name( DSGW_ARG_BUTTON_LABEL, argc,
+ argv )) == NULL ) {
+ buttonlabel = XP_GetClientStr(DBT_saveChanges_);
+ }
+
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" onClick=\"",
+ buttonlabel );
+ if (( checksubmit = get_arg_by_name( DSGW_ARG_BUTTON_CHECKSUBMIT, argc,
+ argv )) != NULL ) {
+ dsgw_emitf( "if (%s) ", checksubmit );
+ }
+ dsgw_emitf( "submitModify('%s')\">\n",
+ ( dispopts & DSGW_DISPLAY_OPT_ADDING ) == 0
+ ? "modify" : "add" );
+}
+
+
+static void
+do_deletebutton( int argc, char **argv )
+{
+ char *buttonlabel, *prompt;
+
+ if (( buttonlabel = get_arg_by_name( DSGW_ARG_BUTTON_LABEL, argc,
+ argv )) == NULL ) {
+ buttonlabel = XP_GetClientStr(DBT_delete_);
+ }
+
+ if (( prompt = get_arg_by_name( DSGW_ARG_BUTTON_PROMPT, argc,
+ argv )) == NULL ) {
+ prompt = XP_GetClientStr(DBT_deleteThisEntry_);
+ }
+
+ dsgw_emitf("<INPUT TYPE=BUTTON VALUE=\"%s\"", buttonlabel);
+ dsgw_emits(" onClick=\"confirmModify('delete', ");
+ dsgw_quote_emits(QUOTATION_JAVASCRIPT, prompt);
+ dsgw_emits(")\">\n");
+}
+
+
+#if 0
+static void
+do_renamebutton( char *dn, int argc, char **argv )
+{
+ char *buttonlabel, *prompt, *oldname, **rdns, *tag;
+ int len;
+
+ if (( buttonlabel = get_arg_by_name( DSGW_ARG_BUTTON_LABEL, argc,
+ argv )) == NULL ) {
+ buttonlabel = XP_GetClientStr(DBT_rename_);
+ }
+
+ if (( prompt = get_arg_by_name( DSGW_ARG_BUTTON_PROMPT, argc,
+ argv )) == NULL ) {
+ prompt = XP_GetClientStr(DBT_enterANewNameForThisEntry_);
+ }
+
+ if (( rdns = ldap_explode_dn( dn, 0 )) != NULL &&
+ ( oldname = strchr( rdns[ 0 ], '=' )) != NULL ) {
+ *oldname++ = '\0';
+ tag = rdns[ 0 ];
+ if ( *oldname == '"' ) {
+ ++oldname;
+ if (( len = strlen( oldname )) > 0
+ && oldname[ len - 1 ] == '"' ) {
+ oldname[ len - 1 ] = '\0';
+ }
+ }
+ } else {
+ oldname = dn;
+ tag = "";
+ }
+
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\""
+ " onClick=\"renameEntry('%s','%s',", buttonlabel, tag, prompt );
+ dsgw_quote_emits( QUOTATION_JAVASCRIPT, oldname );
+ dsgw_emits( ")\">\n" );
+
+ if ( rdns != NULL ) {
+ ldap_value_free( rdns );
+ }
+}
+#endif
+
+
+static void
+do_editasbutton( int argc, char **argv )
+{
+ char *template, *buttonlabel;
+
+ if (( template = get_arg_by_name( DSGW_ARG_BUTTON_TEMPLATE, argc,
+ argv )) == NULL ) {
+ template = "";
+ }
+
+ if (( buttonlabel = get_arg_by_name( DSGW_ARG_BUTTON_LABEL, argc,
+ argv )) == NULL ) {
+ buttonlabel = XP_GetClientStr(DBT_editAs_);
+ }
+
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\""
+ " onClick=\"EditEntryAs('%s')\">\n", buttonlabel, template );
+}
+
+
+static void
+do_passwordfield( unsigned long dispopts, int argc, char **argv,
+ char *fieldname )
+{
+ output_text_elements( argc, argv, fieldname, NULL, NULL, "",
+ DSGW_ATTRHTML_PASSWORD, dispopts );
+}
+
+
+static void
+do_helpbutton( unsigned long dispopts, int argc, char **argv )
+{
+ char *topic;
+
+ if (( topic = get_arg_by_name( DSGW_ARG_BUTTON_TOPIC, argc,
+ argv )) == NULL ) {
+ topic = "";
+ }
+
+ dsgw_emit_helpbutton( topic );
+}
+
+
+static void
+do_closebutton( unsigned long dispopts, int argc, char **argv )
+{
+ dsgw_emit_button( argc, argv, "onClick=\"%s\"",
+ ( dispopts & DSGW_DISPLAY_OPT_EDITABLE ) == 0
+ ? "top.close()" : "closeIfOK()" );
+}
+
+
+static void
+do_dneditbutton( unsigned long dispopts, int argc, char **argv )
+{
+ char *label, *template, *attr, *desc;
+
+ if (( label = get_arg_by_name( DSGW_ARG_DNEDIT_LABEL, argc,
+ argv )) == NULL ) {
+ label = XP_GetClientStr(DBT_edit_1);
+ }
+ if (( template = get_arg_by_name( DSGW_ARG_DNEDIT_TEMPLATE, argc,
+ argv )) == NULL ) {
+ template = "dnedit";
+ }
+ if (( attr = get_arg_by_name( DSGW_ARG_DNEDIT_ATTR, argc,
+ argv )) == NULL ) {
+ dsgw_emits( "<!-- Error: missing attr= argument in DS_DNEDITBUTTON "
+ "directive -->\n" );
+ return;
+ }
+ if (( desc = get_arg_by_name( DSGW_ARG_DNEDIT_DESC, argc,
+ argv )) == NULL ) {
+ desc = attr;
+ }
+
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\""
+ " onClick=\"DNEdit('%s', '%s', '%s')\">\n", label, template,
+ attr, desc );
+}
+
+
+static void
+do_viewswitcher( char *template, char *dn, int argc, char **argv )
+{
+ dsgwtmplset *tsp;
+ dsgwview *vp;
+ char *s, *altprefix, *altsuffix, *curprefix, *cursuffix;
+
+ /* first we see if this template is part of a template set */
+ for ( tsp = gc->gc_tmplsets; tsp != NULL; tsp = tsp->dstset_next ) {
+ for ( vp = tsp->dstset_viewlist; vp != NULL; vp = vp->dsview_next ) {
+ if ( strcasecmp( vp->dsview_template, template ) == 0 ) {
+ break;
+ }
+ }
+ if ( vp != NULL ) {
+ break;
+ }
+ }
+
+ if ( tsp == NULL || tsp->dstset_viewcount == 1 ) {
+ return; /* not part of a set at all or only one view in the set */
+ }
+
+ /* emit view switcher prefix */
+ if (( s = get_arg_by_name( "prefix", argc, argv )) == NULL ) {
+ s = "<TABLE CELLPADDING=6 BORDER=0><TR VALIGN=center>\n";
+ }
+ dsgw_emits( s );
+
+ /* retrieve view item prefix and suffix arguments */
+ if (( altprefix = get_arg_by_name( "altprefix", argc, argv )) == NULL ) {
+ altprefix = "<TD BGCOLOR=#B0B0B0>\n";
+ }
+ if (( altsuffix = get_arg_by_name( "altsuffix", argc, argv )) == NULL ) {
+ altsuffix = "</TD>\n";
+ }
+ if (( curprefix = get_arg_by_name( "curprefix", argc, argv )) ==
+ NULL ) {
+ curprefix = "<TD BGCOLOR=#808080><FONT COLOR=#000000><B>\n";
+ }
+ if (( cursuffix = get_arg_by_name( "currentsuffix", argc, argv )) ==
+ NULL ) {
+ cursuffix = "</B></FONT></TD>\n";
+ }
+
+ /* emit one table cell item (or similar) for each available view */
+ for ( vp = tsp->dstset_viewlist; vp != NULL; vp = vp->dsview_next ) {
+ if ( strcasecmp( vp->dsview_template, template ) == 0 ) {
+ dsgw_emitf( "%s%s%s", curprefix, vp->dsview_caption,
+ cursuffix );
+ } else {
+ dsgw_emitf( "%s\n<A HREF=\"", altprefix );
+ if ( vp->dsview_jscript == NULL ) {
+ dsgw_emitf( "javascript:EditEntryAs('%s')",
+ vp->dsview_template );
+ } else {
+ dsgw_substitute_and_output( vp->dsview_jscript, "--dn--",
+ dn, 1 );
+ }
+ dsgw_emitf( "\">%s</A>\n%s", vp->dsview_caption, altsuffix );
+ }
+ }
+
+ /* emit view switcher suffix */
+ if (( s = get_arg_by_name( "suffix", argc, argv )) == NULL ) {
+ s = "</TR></TABLE>\n";
+ }
+ dsgw_emits( s );
+}
+
+
+static void
+do_attrvalset( dsgwtmplinfo *tip, char *dn, unsigned long dispopts,
+ int argc, char **argv )
+{
+ dsgwavset *avp;
+ char *s, *valuearg, *prefix, *suffix;
+ int i, setpos, len, maxvallen;
+
+ /*
+ * locate "set" element in argv array so we can replace it later
+ * with "value="
+ */
+ if (( setpos = dsgw_get_arg_pos_by_name( DSGW_ARG_AVSET_SET, argc,
+ argv )) < 0 ) {
+ dsgw_emitf( XP_GetClientStr(DBT_missingSN_), DSGW_ARG_AVSET_SET );
+ return;
+ }
+ s = &argv[ setpos ][ 4 ];
+
+ for ( avp = gc->gc_avsets; avp != NULL; avp = avp->dsavset_next ) {
+ if ( strcasecmp( s, avp->dsavset_handle ) == 0 ) {
+ break;
+ }
+ }
+ if ( avp == NULL ) {
+ dsgw_emitf( XP_GetClientStr(DBT_unknownSetSN_), s );
+ return;
+ }
+
+ prefix = get_arg_by_name( "prefix", argc, argv );
+ suffix = get_arg_by_name( "suffix", argc, argv );
+
+ /* repeatedly call on do_attribute() to perform all the difficult work */
+ maxvallen = 0;
+ valuearg = NULL;
+ for ( i = 0; i < avp->dsavset_itemcount; ++i ) {
+ if ( prefix != NULL ) {
+ dsgw_emits( prefix );
+ }
+ dsgw_emits( avp->dsavset_prefixes[ i ] );
+
+ /* construct "value=XXX" arg. and place in argv array */
+ if (( len = strlen( avp->dsavset_values[ i ] )) > maxvallen ||
+ valuearg == NULL ) {
+ maxvallen = len;
+ valuearg = dsgw_ch_realloc( valuearg, maxvallen + 7 );
+ }
+ PR_snprintf( valuearg, maxvallen + 7, "value=%s", avp->dsavset_values[ i ] );
+ argv[ setpos ] = valuearg;
+
+ do_attribute( tip, dn, dispopts, argc, argv );
+
+ dsgw_emits( avp->dsavset_suffixes[ i ] );
+ if ( suffix != NULL ) {
+ dsgw_emitf( "%s\n", suffix );
+ }
+ }
+}
+
+
+static void
+do_std_completion_js( char *template, int argc, char **argv )
+{
+ if ( template != NULL ) {
+ dsgw_emitf(
+ "<INPUT TYPE=\"hidden\" NAME=\"completion_javascript\" VALUE=\""
+ "if (dsmodify_dn.length == 0) "
+ "document.writeln( \\'<FONT SIZE=+1>\\' + dsmodify_info +"
+ " \\'</FONT>\\' );"
+ " else "
+ "parent.document.location.href=\\'%s?%s"
+ "&context=%s&dn=\\' + dsmodify_dn + \\'&info=\\' + escape(dsmodify_info)\">\n",
+ dsgw_getvp( DSGW_CGINUM_EDIT ), template, context );
+ }
+}
+
+
+/*
+ * function called back by dsgw_parse_line() to evaluate IF directives.
+ * return non-zero for true, zero for false.
+ */
+static int
+condition_is_true( int argc, char **argv, void *arg )
+{
+ dsgwtmplinfo *tip;
+
+ if ( argc < 1 ) {
+ return( 0 );
+ }
+
+ tip = (dsgwtmplinfo *)arg;
+
+ if ( strcasecmp( argv[0], DSGW_COND_FOUNDENTRIES ) == 0 ) {
+ return( tip->dsti_entrycount > 0 );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_ADDING ) == 0 ) {
+ return(( tip->dsti_options & DSGW_DISPLAY_OPT_ADDING ) != 0 );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_EDITING ) == 0 ) {
+ return(( tip->dsti_options & DSGW_DISPLAY_OPT_EDITABLE ) != 0 &&
+ ( tip->dsti_options & DSGW_DISPLAY_OPT_ADDING ) == 0 );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_DISPLAYING ) == 0 ) {
+ return(( tip->dsti_options & DSGW_DISPLAY_OPT_EDITABLE ) == 0 );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_BOUND ) == 0 ) {
+ return( dsgw_get_binddn() != NULL );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_BOUNDASTHISENTRY ) == 0 ) {
+ return( dsgw_bound_as_dn( tip->dsti_entrydn, 0 ));
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_DISPLAYORGCHART ) == 0 ) {
+ return(gc->gc_orgcharturl != NULL && ((tip->dsti_options & DSGW_DISPLAY_OPT_ADDING ) == 0));
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_DISPLAYAIMPRESENCE ) == 0 ) {
+ return((gc->gc_aimpresence == 1) && ((tip->dsti_options & DSGW_DISPLAY_OPT_ADDING ) == 0));
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_ATTRHASVALUES ) == 0 ) {
+ /*
+ * format of IF statment is:
+ * <-- IF "AttributeHasValues" "ATTRIBUTE" "MINIMUM_COUNT" -->
+ * MINIMUM_COUNT is an optional number.
+ */
+ char **vals;
+ int rc, minimum;
+
+ if ( argc < 2 || tip->dsti_entry == NULL ||
+ ( vals = (char **) ldap_get_values( tip->dsti_ld, tip->dsti_entry,
+ argv[1])) == NULL ) {
+ /* check "attrsonly" information if applicable */
+ if ( argc < 3 && tip->dsti_attrsonly_entry != NULL ) {
+ (void)ldap_get_values( tip->dsti_ld, tip->dsti_attrsonly_entry, argv[1]);
+ if ( ldap_get_lderrno( tip->dsti_ld, NULL, NULL )
+ == LDAP_SUCCESS ) {
+ return( 1 );
+ }
+ }
+ return( 0 );
+ }
+ minimum = ( argc < 3 ) ? 1 : atoi( argv[ 2 ] );
+ rc = ( minimum <= 1 || ldap_count_values( vals ) >= minimum );
+ ldap_value_free( vals );
+ return( rc );
+ }
+
+ if ( strcasecmp( argv[0], DSGW_COND_ATTRHASTHISVALUE ) == 0 ) {
+ /*
+ * format of IF statment is:
+ * <-- IF "AttributeHasThisValue" "ATTRIBUTE" "SYNTAX" "VALUE" -->
+ */
+ char **vals;
+ int i, rc;
+ struct attr_handler *ahp;
+
+ if ( argc < 4 || tip->dsti_entry == NULL ||
+ ( vals = (char **) ldap_get_values( tip->dsti_ld, tip->dsti_entry,
+ argv[1])) == NULL ) {
+ return( 0 );
+ }
+ if (( ahp = syntax2attrhandler( argv[2] )) == NULL ) {
+ dsgw_emitf( XP_GetClientStr(DBT_unknownSyntaxSN_1), argv[2] );
+ return( 0 );
+ }
+
+ rc = 0;
+ for ( i = 0; vals[ i ] != NULL; ++i ) {
+ if ( dsgw_valcmp(ahp->ath_compare)( (const char **)&vals[i],
+ (const char **)&argv[3] ) == 0 ) {
+ rc = 1;
+ break;
+ }
+ }
+ ldap_value_free( vals );
+ return( rc );
+ }
+
+ /* pass unrecognized conditionals to simple conditional handler */
+ return( dsgw_simple_cond_is_true( argc, argv, NULL ));
+}
+
+/*
+ * Function: dsgw_get_values
+ *
+ * Returns: an array of values
+ *
+ * Description: This function returns the values of
+ * an attribute, taking into account any
+ * possible language or phonetic tags.
+ * pass in something like "cn" and this function
+ * will return all cn's, tagged or not.
+ * If binary_value is 1, then it'll handle
+ * everything as binary values.
+ *
+ * Author: RJP
+ *
+ */
+static char **
+dsgw_get_values( LDAP *ld, LDAPMessage *entry,
+ const char *target, int binary_value )
+{
+ BerElement *ber = NULL;
+ char *attr = NULL;
+ char *new_target = NULL;
+ int new_target_size = 0;
+ char **val_youse = NULL;
+ char **temp_vals = NULL;
+ int i = 0;
+ int j = 0;
+ int temp_val_count = 0;
+
+ /* Allocate a new target that is the original plus a semicolon*/
+ new_target = (char *) dsgw_ch_malloc (sizeof(char) * (strlen(target) + 2) );
+ sprintf (new_target, "%s;", target);
+
+ new_target_size = strlen(new_target);
+
+ /*
+ * Go through the attributes and
+ * compare the new_target with the attr name
+ */
+ for ( attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL;
+ attr = ldap_next_attribute( ld, entry, ber ) ) {
+
+ /* If the "target;" matches the attribute name, get the values*/
+ if ( strcasecmp(attr, target) == 0 ||
+ strncasecmp (attr, new_target, new_target_size) == 0) {
+ if (binary_value) {
+ temp_vals = (char **) ldap_get_values_len( ld, entry, attr );
+ } else {
+ temp_vals = (char **) ldap_get_values( ld, entry, attr );
+ }
+
+ if (temp_vals == NULL) {
+ continue;
+ }
+
+ /* Find the next open spot in val_youse*/
+ if (val_youse) {
+ for (; val_youse[i] != NULL; i++) ;
+ }
+
+ /* Count the number of values in temp_vals */
+ for (temp_val_count = 0; temp_vals[temp_val_count] != NULL;
+ temp_val_count++);
+
+ /* Realloc */
+ val_youse = (char **) dsgw_ch_realloc (val_youse, sizeof(char *) * (temp_val_count + i + 1) );
+
+ /* Start there and copy over the pointers from temp_vals */
+ for (j = 0; j < temp_val_count; j++, i++) {
+ val_youse[i] = temp_vals[j];
+ }
+
+ val_youse[i] = NULL;
+
+ ldap_memfree(temp_vals);
+
+ }
+ }
+
+ /* Free the BerElement from memory when done */
+
+ if ( ber != NULL ) {
+
+ ldap_ber_free( ber, 0 );
+
+ }
+
+ free (new_target);
+
+ return(val_youse);
+}
+
+/*
+ * Function: dsgw_value_free
+ *
+ * Returns: nothing
+ *
+ * Description: frees a half libldap and half dsge malloc'd array.
+ * Sorry. This really sucks, I know, but I didn't
+ * want to copy all that data around.
+ *
+ * Author: RJP
+ *
+ */
+static void
+dsgw_value_free( void **ldvals, int binary )
+{
+ int i;
+
+ for (i = 0; ldvals[i] != NULL; i ++) {
+ if (binary) {
+ struct berval *delete_me = NULL;
+
+ delete_me = (struct berval *) ldvals[i];
+
+ ldap_memfree(delete_me->bv_val);
+ ldap_memfree(delete_me);
+ } else {
+ ldap_memfree (ldvals[i]);
+ }
+ }
+
+ free(ldvals);
+
+
+}
+/*
+ * Function: dsgw_time
+ *
+ * Returns: a string not unlike the string returned from ctime()
+ * except it's localized
+ *
+ * Description: this function takes the number of seconds since 1970
+ * and converts it to a localized string version of that.
+ * First it tries to use the clientLanguage, if that fails,
+ * It tries the default language. if that fails, it returns
+ * NULL
+ *
+ * Author: RJP
+ *
+ */
+static char *
+dsgw_time(time_t secs_since_1970)
+{
+ UDateFormat *edatefmt;
+ UErrorCode err = U_ZERO_ERROR;
+ UChar *dstr0;
+ static char obuf[BSIZ];
+ UDate tmp_dat;
+ char *locale = NULL;
+ int32_t myStrlen = 0;
+
+ /* Create a Date/Time Format using the locale */
+ if (countri) {
+ locale = PR_smprintf("%s_%s", langwich, countri);
+ } else {
+ locale = PR_smprintf("%s", langwich);
+ }
+
+ edatefmt = udat_open(
+ UDAT_DEFAULT, /* default date style for locale */
+ UDAT_DEFAULT, /* default time style for locale */
+ locale,
+ NULL, 0, /* use default timezone */
+ NULL, 0, /* no pattern */
+ &err);
+
+ PR_smprintf_free(locale);
+ locale = NULL;
+
+ if (!edatefmt || (err != U_ZERO_ERROR)) {
+ if (edatefmt) {
+ udat_close(edatefmt);
+ }
+ err = U_ZERO_ERROR;
+ edatefmt = udat_open(
+ UDAT_DEFAULT, /* default date style for locale */
+ UDAT_DEFAULT, /* default time style for locale */
+ gc->gc_DefaultLanguage, /* default language */
+ NULL, 0, /* use default timezone */
+ NULL, 0, /* no pattern */
+ &err);
+ }
+
+ if (!edatefmt || (err != U_ZERO_ERROR)) {
+ dsgw_error( DSGW_ERR_LDAPGENERAL, NULL, DSGW_ERROPT_EXIT, err, NULL );
+ /*fprintf(stderr, "ERROR: NLS_NewDateTimeFormat(0): %d\n", err);*/
+ }
+
+ /* Get Current Date/Time */
+ tmp_dat = (UDate) secs_since_1970;
+ tmp_dat *= 1000.00;
+
+ /* Format using the first Date/Time format */
+ myStrlen = udat_format(edatefmt, tmp_dat, NULL, myStrlen, NULL, &err);
+ if(err == U_BUFFER_OVERFLOW_ERROR){
+ err = U_ZERO_ERROR;
+ dstr0 = (UChar*)dsgw_ch_malloc(sizeof(UChar) * (myStrlen+1) );
+ myStrlen = udat_format(edatefmt, tmp_dat, dstr0, myStrlen+1, NULL, &err);
+ }
+
+ if (err != U_ZERO_ERROR) {
+ dsgw_error( DSGW_ERR_LDAPGENERAL, NULL, DSGW_ERROPT_EXIT, err, NULL );
+ /*fprintf(stderr, "ERROR: NLS_FormatDate(1): %d\n", err);*/
+ }
+
+ /* convert to utf8 */
+ u_strToUTF8(obuf, BSIZ, NULL, dstr0, myStrlen, &err);
+
+ if (err != U_ZERO_ERROR) {
+ dsgw_error( DSGW_ERR_LDAPGENERAL, NULL, DSGW_ERROPT_EXIT, err, NULL );
+ /*fprintf(stderr, "ERROR: NLS_NewEncodingConverter(0): %d\n", err);*/
+ }
+ /*fprintf(stdout, "Date(0): %s\n", obuf);*/
+
+ /* Clean up -- but may not be enough... :) */
+ free(dstr0);
+
+ udat_close(edatefmt);
+ edatefmt = NULL;
+
+ return( (char *) obuf);
+}
diff --git a/ldap/clients/dsgw/error.c b/ldap/clients/dsgw/error.c
new file mode 100644
index 00000000..572702b4
--- /dev/null
+++ b/ldap/clients/dsgw/error.c
@@ -0,0 +1,542 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * error.c -- error handling functions -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+static char *dsgw_ldaperr2longstring( int err, int options );
+
+struct dsgwerr {
+ int dsgwerr_code;
+ int dsgwerr_msg;
+};
+
+
+/* all of the DSGW_ERR_... #defines are in dsgw.h */
+static struct dsgwerr dsgw_errs[] = {
+ { DSGW_ERR_BADMETHOD,
+ DBT_unknownHttpRequestMethod_ },
+ { DSGW_ERR_BADFORMDATA,
+ DBT_invalidOrIncompleteHtmlFormData_ },
+ { DSGW_ERR_NOMEMORY,
+ DBT_outOfMemory_ },
+ { DSGW_ERR_MISSINGINPUT,
+ DBT_requiredQueryFormInputIsMissing_ },
+ { DSGW_ERR_BADFILEPATH,
+ DBT_illegalCharacterInFilePath_ },
+ { DSGW_ERR_BADCONFIG,
+ DBT_badOrMissingConfigurationFile_ },
+ { DSGW_ERR_LDAPINIT,
+ DBT_unableToInitializeLdap_ },
+ { DSGW_ERR_LDAPGENERAL,
+ DBT_anErrorOccurredWhileContactingTh_ },
+ { DSGW_ERR_UNKSRCHTYPE,
+ DBT_unknownSearchObjectType_ },
+ { DSGW_ERR_UNKATTRLABEL,
+ DBT_unknownAttributeLabel_ },
+ { DSGW_ERR_UNKMATCHPROMPT,
+ DBT_unknownMatchPrompt_ },
+ { DSGW_ERR_NOFILTERS,
+ DBT_noSearchFiltersForObjectType_ },
+ { DSGW_ERR_OPENHTMLFILE,
+ DBT_unableToOpenHtmlTemplateFile_ },
+ { DSGW_ERR_SEARCHMODE,
+ DBT_unknownSearchModeUseSmartComplex_ },
+ { DSGW_ERR_LDAPURL_NODN,
+ DBT_distinguishedNameMissingInUrl_ },
+ { DSGW_ERR_LDAPURL_BADSCOPE,
+ DBT_unknownScopeInUrlShouldBeBaseSub_ },
+ { DSGW_ERR_LDAPURL_NOTLDAP,
+ DBT_unrecognizedUrlOrUnknownError_ },
+ { DSGW_ERR_LDAPURL_BAD,
+ DBT_badUrlFormat_ },
+ { DSGW_ERR_INTERNAL,
+ DBT_internalError_ },
+ { DSGW_ERR_WRITEINDEXFILE,
+ DBT_unableToWriteTemplateIndexFile_ },
+ { DSGW_ERR_OPENINDEXFILE,
+ DBT_unableToOpenTemplateIndexFile_ },
+ { DSGW_ERR_OPENDIR,
+ DBT_unableToReadDirectory_ },
+ { DSGW_ERR_SSLINIT,
+ DBT_ldapSslInitializationFailedCheck_ },
+ { DSGW_ERR_NOSECPATH,
+ DBT_forTheUsersAndGroupsFormsToWorkO_ },
+ { DSGW_CKDB_KEY_NOT_PRESENT,
+ DBT_authenticationCredentialsNotFoun_ },
+ { DSGW_CKDB_DBERROR,
+ DBT_errorRetrievingDataFromTheAuthen_ },
+ { DSGW_CKDB_EXPIRED,
+ DBT_yourAuthenticationCredentialsHav_ },
+ { DSGW_CKDB_RNDSTRFAIL,
+ DBT_unableToCreateRandomString_ },
+ { DSGW_CKDB_NODN,
+ DBT_noDistinguishedNameWasProvidedWh_ },
+ { DSGW_CKDB_CANTOPEN,
+ DBT_cannotOpenAuthenticationDatabase_ },
+ { DSGW_CKDB_CANTAPPEND,
+ DBT_couldNotAppendDataToTheAuthentic_ },
+ { DSGW_ERR_NO_MGRDN,
+ DBT_noDirectoryManagerIsDefined_ },
+ { DSGW_ERR_NOSEARCHSTRING,
+ DBT_noSearchStringWasProvidedPleaseT_ },
+ { DSGW_ERR_CONFIGTOOMANYARGS,
+ DBT_tooManyArgumentsOnOneLineInTheCo_ },
+ { DSGW_ERR_WSAINIT,
+ DBT_failedToInitializeWindowsSockets_ },
+ { DSGW_ERR_ADMSERV_CREDFAIL,
+ DBT_authenticationCredentialsCouldNo_ },
+ { DSGW_ERR_LDAPDBURL_NODN,
+ DBT_distinguishedNameMissingInLdapdb_ },
+ { DSGW_ERR_LDAPDBURL_NOTLDAPDB,
+ DBT_unrecognizedUrlOrUnknownError_1 },
+ { DSGW_ERR_LDAPDBURL_BAD,
+ DBT_badUrlFormat_1 },
+ { DSGW_ERR_LCACHEINIT,
+ DBT_anErrorOccurredWhileInitializing_ },
+ { DSGW_ERR_SERVICETYPE,
+ DBT_unknownDirectoryServiceTypeUseLo_ },
+ { DSGW_ERR_DBCONF,
+ DBT_anErrorOccurredWhileReadingTheDb_ },
+ { DSGW_ERR_USERDB_PATH,
+ DBT_nshomeUserdbPathWasNull_ },
+ { DSGW_ERR_UPDATE_DBSWITCH,
+ DBT_theDirectoryServiceConfiguration_ },
+ { DSGW_ERR_ENTRY_NOT_FOUND,
+ DBT_theEntryCouldNotBeReadFromTheDir_ },
+ { DSGW_ERR_DB_ERASE,
+ DBT_theLdapDatabaseCouldNotBeErased_ },
+ { DSGW_ERR_LOCALDB_PERMISSION_DENIED,
+ DBT_youMayNotChangeEntriesBesidesYou_ },
+ { DSGW_ERR_NOATTRVALUE,
+ DBT_theAttributeValueRequestedWasNot_ },
+ { DSGW_ERR_USERID_REQUIRED,
+ /* "A value must be specified for NT User Id" */
+ DBT_aValueMustBeSpecifiedForNTUserId },
+ { DSGW_ERR_DOMAINID_NOTUNIQUE,
+ /* "The combination of NT User Id, NT Domain Id */
+ /* is not unique in the directory" */
+ DBT_theCombinationOfNTUserIdNTDomain_ },
+ { DSGW_ERR_USERID_DOMAINID_REQUIRED,
+ /* "Values must be specified for both NT */
+ /* User Id and NT Domain Id" */
+ DBT_valuesMustBeSpecifiedForBothNTUser_ },
+ { DSGW_ERR_USERID_MAXLEN_EXCEEDED,
+ /* "The NT User Id value must not exceed 20 characters in length." */
+ DBT_theNTUserIdValueMustNotExceed_ },
+ { DSGW_ERR_CHARSET_NOT_SUPPORTED,
+ /* "The charset %s is not supported" */
+ DBT_theCharsetIsNotSupported },
+};
+#define DSGW_ERROR_CNT ( sizeof( dsgw_errs ) / sizeof( struct dsgwerr ))
+
+
+
+/*
+ * dsgw_error -- report error as HTML text
+ */
+void
+dsgw_error( int err, char *extra, int options, int ldaperr, char *lderrtxt )
+{
+ char *msg, *prelude = XP_GetClientStr(DBT_problem_);
+
+ if (( options & DSGW_ERROPT_IGNORE ) != 0 ) {
+ return;
+ }
+
+ if (( options & DSGW_ERROPT_INLINE ) == 0 ) {
+ dsgw_send_header();
+ dsgw_html_begin( prelude, 1 );
+ }
+
+ msg = dsgw_err2string( err );
+
+ dsgw_emitf( "<FONT SIZE=\"+1\">\n%s\n</FONT>\n", msg );
+ if ( extra != NULL ) {
+ if ( lderrtxt == NULL ) {
+ dsgw_emitf( "<BR>(%s)", extra );
+ } else {
+ dsgw_emitf( "<BR>(%s - %s)", extra, lderrtxt );
+ }
+ } else if ( lderrtxt != NULL ) {
+ dsgw_emitf( "<BR>(%s)", lderrtxt );
+ }
+
+#ifdef DSGW_DEBUG
+ if ( extra == NULL ) {
+ dsgw_log( "%s: %s\n", prelude, msg );
+ } else {
+ dsgw_log( "%s: %s (%s)\n", prelude, msg, extra );
+ }
+#endif
+ if ( ldaperr != 0 ) {
+ msg = dsgw_ldaperr2longstring( ldaperr, options );
+ dsgw_emitf("<P>%s", msg );
+ }
+
+ if (( options & DSGW_ERROPT_INLINE ) == 0 ) {
+ dsgw_html_end();
+ }
+
+ if (( options & DSGW_ERROPT_EXIT ) != 0 ) {
+ exit( 0 );
+ }
+}
+
+
+/*
+ * special handling for cookie expired or cookie database problems
+ * delete cookie on both server and client
+ * send helpful error with appropriate buttons:
+ * * if searching, display an error message, and a re-auth button, along
+ * with a help button.
+ * * if authenticating, (does this ever happen?)
+ * * if generating an editable view, display an error messge, and tell
+ * user to bring main window to front and requthenticate.
+ * * if submitting a modify operation, include an "Authenticate" button
+ * which brings up a new auth window, which only offers you a
+ * "close" button when finished.
+ *
+ * returns 1 if the CGI should exit.
+ * 0 if it should continue. - RJP
+ */
+int
+dsgw_dn2passwd_error( int ckrc, int skipauthwarning )
+{
+ char *authck;
+
+ /*
+ * cookie is expired or bad -- delete it on both server and client sides
+ *
+ */
+ if (( authck = dsgw_get_auth_cookie()) != NULL ) {
+ dsgw_delcookie( authck );
+ }
+
+ /* pop up a javascript alert */
+ if (gc->gc_mode == DSGW_MODE_DOSEARCH) {
+ /* Just display a helpful error message */
+ if (ckrc != DSGW_CKDB_KEY_NOT_PRESENT && !skipauthwarning) {
+ dsgw_send_header();
+ dsgw_emit_alertForm();
+ dsgw_emits( "<SCRIPT LANGUAGE=JavaScript><!--\n" );
+ dsgw_emit_alert (NULL, NULL, dsgw_err2string( ckrc ),
+ 0L, "", "", "");
+ dsgw_emits( "// -->\n</SCRIPT>\n");
+ }
+ return(0);
+ }
+ dsgw_send_header();
+
+ dsgw_html_begin( XP_GetClientStr(DBT_authenticationProblem_), 1 );
+
+ dsgw_emits( "<SCRIPT LANGUAGE=\"JavaScript\">\n<!-- hide\n\n" );
+ dsgw_emitf( "document.cookie = '%s=%s; path=/';\n\n", DSGW_AUTHCKNAME,
+ DSGW_UNAUTHSTR );
+
+ dsgw_emits( "function reAuth()\n{\n" );
+ dsgw_emitf( " a = open( '%s?context=%s', 'AuthWin');\n",
+ dsgw_getvp( DSGW_CGINUM_AUTH ), context);
+ dsgw_emits( " a.opener = self;\n" );
+ dsgw_emits( " a.closewin = false;\n" );
+ dsgw_emits( "}\n// end hiding -->\n</SCRIPT>\n" );
+
+ dsgw_emits( dsgw_err2string( ckrc ) );
+
+ if (gc->gc_mode == DSGW_MODE_EDIT || gc->gc_mode == DSGW_MODE_DOMODIFY) {
+
+ dsgw_emits( XP_GetClientStr(DBT_NPYouMustReAuthenticateBeforeCon_1) );
+ dsgw_emits( "<P>\n" );
+ dsgw_form_begin( NULL, NULL );
+ dsgw_emits("\n<CENTER><TABLE border=2 width=\"100%\"><TR>\n" );
+ dsgw_emits( "<TD WIDTH=\"50%\" ALIGN=\"center\">\n" );
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"top.close();\">\n",
+ XP_GetClientStr(DBT_closeWindow_4) );
+ dsgw_emits( "<TD WIDTH=\"50%\" ALIGN=\"center\">\n" );
+ dsgw_emit_helpbutton( "AUTHEXPIRED" );
+ dsgw_emits( "\n</TABLE></CENTER></FORM>\n" );
+
+ }
+
+ dsgw_html_end();
+ return(1);
+}
+
+
+char *
+dsgw_err2string( int err )
+{
+ int i;
+
+ for ( i = 0; i < DSGW_ERROR_CNT; ++i ) {
+ if ( dsgw_errs[ i ].dsgwerr_code == err ) {
+ return( XP_GetClientStr(dsgw_errs[ i ].dsgwerr_msg) );
+ }
+ }
+
+ return( XP_GetClientStr(DBT_unknownError_) );
+}
+
+
+static char *
+dsgw_ldaperr2longstring( int err, int options )
+{
+ char *s = "";
+
+ switch ( err ) {
+ case LDAP_SUCCESS:
+ s = XP_GetClientStr(DBT_theOperationWasSuccessful_);
+ break;
+ case LDAP_OPERATIONS_ERROR:
+ s = XP_GetClientStr(DBT_anInternalErrorOccurredInTheServ_);
+ break;
+ case LDAP_PROTOCOL_ERROR:
+ s = XP_GetClientStr(DBT_theServerCouldNotUnderstandTheRe_);
+ break;
+ case LDAP_TIMELIMIT_EXCEEDED:
+ s = XP_GetClientStr(DBT_aTimeLimitWasExceededInRespondin_);
+ break;
+ case LDAP_SIZELIMIT_EXCEEDED:
+ s = XP_GetClientStr(DBT_aSizeLimitWasExceededInRespondin_);
+ break;
+ case LDAP_COMPARE_FALSE:
+ break;
+ case LDAP_COMPARE_TRUE:
+ break;
+ case LDAP_STRONG_AUTH_NOT_SUPPORTED:
+ s = XP_GetClientStr(DBT_theGatewayAttemptedToAuthenticat_);
+ break;
+ case LDAP_STRONG_AUTH_REQUIRED:
+ s = XP_GetClientStr(DBT_theGatewayAttemptedToAuthenticat_1);
+ break;
+#ifdef LDAP_REFERRAL /* new in LDAPv3 */
+ case LDAP_REFERRAL:
+#endif
+ case LDAP_PARTIAL_RESULTS:
+ s = XP_GetClientStr(DBT_yourRequestCouldNotBeFulfilledPr_);
+ break;
+#ifdef LDAP_ADMIN_LIMIT_EXCEEDED /* new in LDAPv3 */
+ case LDAP_ADMIN_LIMIT_EXCEEDED:
+ s = XP_GetClientStr(DBT_yourRequestExceededAnAdministrat_);
+ break;
+#endif
+#ifdef LDAP_UNAVAILABLE_CRITICAL_EXTENSION /* new in LDAPv3 */
+ case LDAP_UNAVAILABLE_CRITICAL_EXTENSION:
+ s = XP_GetClientStr(DBT_aCriticalExtensionThatTheGateway_);
+ break;
+#endif
+ case LDAP_NO_SUCH_ATTRIBUTE:
+ s = XP_GetClientStr(DBT_theServerWasUnableToProcessTheRe_);
+ break;
+ case LDAP_UNDEFINED_TYPE:
+ break;
+ case LDAP_INAPPROPRIATE_MATCHING:
+ break;
+ case LDAP_CONSTRAINT_VIOLATION:
+ s = XP_GetClientStr(DBT_theServerWasUnableToFulfillYourR_);
+ break;
+ case LDAP_TYPE_OR_VALUE_EXISTS:
+ s = XP_GetClientStr(DBT_theServerCouldNotAddAValueToTheE_);
+ break;
+ case LDAP_INVALID_SYNTAX:
+ break;
+ case LDAP_NO_SUCH_OBJECT:
+ if (( options & DSGW_ERROPT_DURINGBIND ) == 0 ) {
+ s = XP_GetClientStr(DBT_theServerCouldNotLocateTheEntryI_);
+ } else {
+ s = XP_GetClientStr(DBT_theServerCouldNotLocateTheEntryY_);
+ }
+ break;
+ case LDAP_ALIAS_PROBLEM:
+ break;
+ case LDAP_INVALID_DN_SYNTAX:
+ s = XP_GetClientStr(DBT_aDistinguishedNameWasNotInThePro_);
+ break;
+ case LDAP_IS_LEAF:
+ break;
+ case LDAP_ALIAS_DEREF_PROBLEM:
+ break;
+ case LDAP_INAPPROPRIATE_AUTH:
+ s = XP_GetClientStr(DBT_theEntryYouAttemptedToAuthentica_);
+ break;
+ case LDAP_INVALID_CREDENTIALS:
+ s = XP_GetClientStr(DBT_thePasswordOrOtherAuthentication_);
+ break;
+ case LDAP_INSUFFICIENT_ACCESS:
+ s = XP_GetClientStr(DBT_youDoNotHaveSufficientPrivileges_);
+ break;
+ case LDAP_BUSY:
+ s = XP_GetClientStr(DBT_theServerIsTooBusyToServiceYourR_);
+ break;
+ case LDAP_UNAVAILABLE:
+ s = XP_GetClientStr(DBT_theLdapServerCouldNotBeContacted_);
+ break;
+ case LDAP_UNWILLING_TO_PERFORM:
+ s = XP_GetClientStr(DBT_theServerWasUnwilliingToProcessY_);
+ break;
+ case LDAP_LOOP_DETECT:
+ break;
+ case LDAP_NAMING_VIOLATION:
+ break;
+ case LDAP_OBJECT_CLASS_VIOLATION:
+ s = XP_GetClientStr(DBT_theDirectoryServerCouldNotHonorY_);
+ break;
+ case LDAP_NOT_ALLOWED_ON_NONLEAF:
+ s = XP_GetClientStr(DBT_theDirectoryServerWillNotAllowYo_);
+ break;
+ case LDAP_NOT_ALLOWED_ON_RDN:
+ break;
+ case LDAP_ALREADY_EXISTS:
+ s = XP_GetClientStr(DBT_theServerWasUnableToAddANewEntry_);
+ break;
+ case LDAP_NO_OBJECT_CLASS_MODS:
+ break;
+ case LDAP_RESULTS_TOO_LARGE:
+ break;
+#ifdef LDAP_AFFECTS_MULTIPLE_DSAS /* new in LDAPv3 */
+ case LDAP_AFFECTS_MULTIPLE_DSAS:
+ s = XP_GetClientStr(DBT_yourRequestWouldAffectSeveralDir_);
+ break;
+#endif
+ case LDAP_OTHER:
+ break;
+ case LDAP_SERVER_DOWN:
+ s = XP_GetClientStr(DBT_theDirectoryServerCouldNotBeCont_);
+ break;
+ case LDAP_LOCAL_ERROR:
+ break;
+ case LDAP_ENCODING_ERROR:
+ s = XP_GetClientStr(DBT_anErrorOccuredWhileSendingDataTo_);
+ break;
+ case LDAP_DECODING_ERROR:
+ s = XP_GetClientStr(DBT_anErrorOccuredWhileReadingDataFr_);
+ break;
+ case LDAP_TIMEOUT:
+ s = XP_GetClientStr(DBT_theServerDidNotRespondToTheReque_);
+ break;
+ case LDAP_AUTH_UNKNOWN:
+ s = XP_GetClientStr(DBT_theServerDoesNotSupportTheAuthen_);
+ break;
+ case LDAP_FILTER_ERROR:
+ s = XP_GetClientStr(DBT_theSearchFilterConstructedByTheG_);
+ break;
+ case LDAP_USER_CANCELLED:
+ s = XP_GetClientStr(DBT_theOperationWasCancelledAtYourRe_);
+ break;
+ case LDAP_PARAM_ERROR:
+ break;
+ case LDAP_NO_MEMORY:
+ s = XP_GetClientStr(DBT_anInternalErrorOccurredInTheLibr_);
+ break;
+ case LDAP_CONNECT_ERROR:
+ s = XP_GetClientStr(DBT_aConnectionToTheServerCouldNotBe_);
+ break;
+ default:
+ s = XP_GetClientStr(DBT_anUnknownErrorWasEncountered_);
+ }
+ return s;
+}
+
+static struct dsgwerr LDAP_errs[] = {
+ { LDAP_SUCCESS, DBT_LDAP_SUCCESS},
+ { LDAP_OPERATIONS_ERROR, DBT_LDAP_OPERATIONS_ERROR},
+ { LDAP_PROTOCOL_ERROR, DBT_LDAP_PROTOCOL_ERROR},
+ { LDAP_TIMELIMIT_EXCEEDED, DBT_LDAP_TIMELIMIT_EXCEEDED},
+ { LDAP_SIZELIMIT_EXCEEDED, DBT_LDAP_SIZELIMIT_EXCEEDED},
+ { LDAP_COMPARE_FALSE, DBT_LDAP_COMPARE_FALSE},
+ { LDAP_COMPARE_TRUE, DBT_LDAP_COMPARE_TRUE},
+ { LDAP_STRONG_AUTH_NOT_SUPPORTED, DBT_LDAP_STRONG_AUTH_NOT_SUPPORTED},
+ { LDAP_STRONG_AUTH_REQUIRED, DBT_LDAP_STRONG_AUTH_REQUIRED},
+ { LDAP_PARTIAL_RESULTS, DBT_LDAP_PARTIAL_RESULTS},
+ { LDAP_REFERRAL, DBT_LDAP_REFERRAL},
+ { LDAP_ADMINLIMIT_EXCEEDED, DBT_LDAP_ADMINLIMIT_EXCEEDED},
+ { LDAP_UNAVAILABLE_CRITICAL_EXTENSION, DBT_LDAP_UNAVAILABLE_CRITICAL_EXTENSION},
+ { LDAP_CONFIDENTIALITY_REQUIRED,DBT_LDAP_CONFIDENTIALITY_REQUIRED},
+ { LDAP_SASL_BIND_IN_PROGRESS, DBT_LDAP_SASL_BIND_IN_PROGRESS},
+
+ { LDAP_NO_SUCH_ATTRIBUTE, DBT_LDAP_NO_SUCH_ATTRIBUTE},
+ { LDAP_UNDEFINED_TYPE, DBT_LDAP_UNDEFINED_TYPE},
+ { LDAP_INAPPROPRIATE_MATCHING, DBT_LDAP_INAPPROPRIATE_MATCHING},
+ { LDAP_CONSTRAINT_VIOLATION, DBT_LDAP_CONSTRAINT_VIOLATION},
+ { LDAP_TYPE_OR_VALUE_EXISTS, DBT_LDAP_TYPE_OR_VALUE_EXISTS},
+ { LDAP_INVALID_SYNTAX, DBT_LDAP_INVALID_SYNTAX},
+
+ { LDAP_NO_SUCH_OBJECT, DBT_LDAP_NO_SUCH_OBJECT},
+ { LDAP_ALIAS_PROBLEM, DBT_LDAP_ALIAS_PROBLEM},
+ { LDAP_INVALID_DN_SYNTAX, DBT_LDAP_INVALID_DN_SYNTAX},
+ { LDAP_IS_LEAF, DBT_LDAP_IS_LEAF},
+ { LDAP_ALIAS_DEREF_PROBLEM, DBT_LDAP_ALIAS_DEREF_PROBLEM},
+
+ { LDAP_INAPPROPRIATE_AUTH, DBT_LDAP_INAPPROPRIATE_AUTH},
+ { LDAP_INVALID_CREDENTIALS, DBT_LDAP_INVALID_CREDENTIALS},
+ { LDAP_INSUFFICIENT_ACCESS, DBT_LDAP_INSUFFICIENT_ACCESS},
+ { LDAP_BUSY, DBT_LDAP_BUSY},
+ { LDAP_UNAVAILABLE, DBT_LDAP_UNAVAILABLE},
+ { LDAP_UNWILLING_TO_PERFORM, DBT_LDAP_UNWILLING_TO_PERFORM},
+ { LDAP_LOOP_DETECT, DBT_LDAP_LOOP_DETECT},
+
+ { LDAP_NAMING_VIOLATION, DBT_LDAP_NAMING_VIOLATION},
+ { LDAP_OBJECT_CLASS_VIOLATION, DBT_LDAP_OBJECT_CLASS_VIOLATION},
+ { LDAP_NOT_ALLOWED_ON_NONLEAF, DBT_LDAP_NOT_ALLOWED_ON_NONLEAF},
+ { LDAP_NOT_ALLOWED_ON_RDN, DBT_LDAP_NOT_ALLOWED_ON_RDN},
+ { LDAP_ALREADY_EXISTS, DBT_LDAP_ALREADY_EXISTS},
+ { LDAP_NO_OBJECT_CLASS_MODS, DBT_LDAP_NO_OBJECT_CLASS_MODS},
+ { LDAP_RESULTS_TOO_LARGE, DBT_LDAP_RESULTS_TOO_LARGE},
+ { LDAP_AFFECTS_MULTIPLE_DSAS, DBT_LDAP_AFFECTS_MULTIPLE_DSAS},
+
+ { LDAP_OTHER, DBT_LDAP_OTHER},
+ { LDAP_SERVER_DOWN, DBT_LDAP_SERVER_DOWN},
+ { LDAP_LOCAL_ERROR, DBT_LDAP_LOCAL_ERROR},
+ { LDAP_ENCODING_ERROR, DBT_LDAP_ENCODING_ERROR},
+ { LDAP_DECODING_ERROR, DBT_LDAP_DECODING_ERROR},
+ { LDAP_TIMEOUT, DBT_LDAP_TIMEOUT},
+ { LDAP_AUTH_UNKNOWN, DBT_LDAP_AUTH_UNKNOWN},
+ { LDAP_FILTER_ERROR, DBT_LDAP_FILTER_ERROR},
+ { LDAP_USER_CANCELLED, DBT_LDAP_USER_CANCELLED},
+ { LDAP_PARAM_ERROR, DBT_LDAP_PARAM_ERROR},
+ { LDAP_NO_MEMORY, DBT_LDAP_NO_MEMORY},
+ { LDAP_CONNECT_ERROR, DBT_LDAP_CONNECT_ERROR},
+ { LDAP_NOT_SUPPORTED, DBT_LDAP_NOT_SUPPORTED},
+ { LDAP_CONTROL_NOT_FOUND, DBT_LDAP_CONTROL_NOT_FOUND},
+ { LDAP_NO_RESULTS_RETURNED, DBT_LDAP_NO_RESULTS_RETURNED},
+ { LDAP_MORE_RESULTS_TO_RETURN, DBT_LDAP_MORE_RESULTS_TO_RETURN},
+ { LDAP_CLIENT_LOOP, DBT_LDAP_CLIENT_LOOP},
+ { LDAP_REFERRAL_LIMIT_EXCEEDED, DBT_LDAP_REFERRAL_LIMIT_EXCEEDED}};
+
+#define LDAP_ERROR_CNT ( sizeof( LDAP_errs ) / sizeof( struct dsgwerr ))
+
+char *
+dsgw_ldaperr2string( int lderr )
+{
+ auto int msgno = 0;
+ auto int i;
+
+ for ( i = 0; i < LDAP_ERROR_CNT; ++i ) {
+ if ( LDAP_errs[ i ].dsgwerr_code == lderr ) {
+ msgno = LDAP_errs[ i ].dsgwerr_msg;
+ break;
+ }
+ }
+ if (msgno != 0) {
+ auto char* msg = XP_GetClientStr(msgno);
+ if (msg && *msg) return dsgw_ch_strdup( msg );
+ }
+ { /* get the message string from the LDAP SDK: */
+ auto char* fmt = XP_GetClientStr(DBT_errorS_);
+ auto char* s = ldap_err2string( lderr );
+ auto char* msg = dsgw_ch_malloc( strlen( fmt ) + strlen( s ) + 20);
+ PR_snprintf( msg, strlen(fmt) + strlen(s) + 20, fmt, s, lderr );
+ return msg;
+ }
+}
diff --git a/ldap/clients/dsgw/genscreen.c b/ldap/clients/dsgw/genscreen.c
new file mode 100644
index 00000000..ab2f89cd
--- /dev/null
+++ b/ldap/clients/dsgw/genscreen.c
@@ -0,0 +1,117 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * Generate a screen.
+ */
+
+#include "dsgw.h"
+
+static int dsgw_genscreen_begin( char *fname, FILE **fpp,
+ char *stop_at_directive, int erropts );
+static int dsgw_genscreen_continue( FILE **fpp, char *stop_at_directive,
+ int erropts );
+
+static LDAP *ld = NULL;
+
+main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+ char *p, *tmplname, *buf;
+
+ context=dsgw_ch_strdup("pb");
+ /*CHANGE THIS*/
+
+ (void)dsgw_init( argc, argv, DSGW_METHOD_GET );
+ dsgw_send_header();
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ /*
+ * If the QUERY_STRING is non-NULL, it looks like this:
+ *
+ * template &CONTEXT=context [ &INFO=infostring ]
+ *
+ * where:
+ * "template" is the name of the HTML template to render
+ * "infostring" is a message used to replace DS_LAST_OP_INFO directives
+ *
+ * If the QUERY_STRING is NULL, the name of this program is used as the
+ * template.
+ */
+
+ if (( tmplname = getenv( "QUERY_STRING" )) == NULL ) {
+ tmplname = progname;
+ } else {
+ tmplname = dsgw_ch_strdup( tmplname );
+ if (( p = strrchr( tmplname, '&' )) != NULL ) {
+ *p++ = '\0';
+ if ( strncasecmp( p, "info=", 5 ) == 0 ) {
+ dsgw_last_op_info = dsgw_ch_strdup( p + 5 );
+ dsgw_form_unescape( dsgw_last_op_info );
+ }
+ }
+ }
+
+
+ buf = dsgw_ch_malloc( strlen( tmplname ) + 6 ); /* room for ".html\0" */
+ sprintf( buf, "%s.html", tmplname );
+
+ dsgw_genscreen_begin( buf, NULL, NULL, DSGW_ERROPT_EXIT );
+
+ exit( 0 );
+}
+
+
+static int
+dsgw_genscreen_begin( char *fname, FILE **fpp, char *stop_at_directive,
+ int erropts )
+{
+ FILE *html;
+
+ if ( fpp == NULL ) {
+ fpp = &html;
+ }
+
+ if (( *fpp = dsgw_open_html_file( fname, erropts )) == NULL ) {
+ *fpp = NULL;
+ return( -1 );
+ }
+
+ return( dsgw_genscreen_continue( fpp, stop_at_directive, erropts ));
+}
+
+
+static int
+dsgw_genscreen_continue( FILE **fpp, char *stop_at_directive, int erropts )
+{
+ char **argv, line[ BIG_LINE ];
+ int argc;
+
+ while ( dsgw_next_html_line( *fpp, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, dsgw_simple_cond_is_true,
+ NULL )) {
+ if ( stop_at_directive != NULL &&
+ dsgw_directive_is( line, stop_at_directive )) {
+ return( 0 );
+ }
+ if ( dsgw_directive_is( line, DRCT_DS_LOCATIONPOPUP )) {
+ dsgw_emit_location_popup( ld, argc, argv, erropts );
+ }
+ }
+ }
+
+ fclose( *fpp );
+ *fpp = NULL;
+
+ return( 0 );
+}
diff --git a/ldap/clients/dsgw/getopt.c b/ldap/clients/dsgw/getopt.c
new file mode 100644
index 00000000..a66a3770
--- /dev/null
+++ b/ldap/clients/dsgw/getopt.c
@@ -0,0 +1,115 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef _WINDOWS
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 4.12 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include "lber.h"
+#define index strchr
+#define rindex strrchr
+
+/*
+ * get option letter from argument vector
+ */
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt; /* character checked for validity */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define EMSG ""
+
+int getopt(int nargc, char *const *nargv, const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ register char *oli; /* option letter list index */
+ char *p;
+
+ if (!*place) { /* update scanning pointer */
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return(EOF);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return(EOF);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = index(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means EOF.
+ */
+ if (optopt == (int)'-')
+ return(EOF);
+ if (!*place)
+ ++optind;
+ if (opterr) {
+ if (!(p = rindex(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ (void)fprintf(stderr, "%s: illegal option -- %c\n",
+ p, optopt);
+ }
+ return(BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (!(p = rindex(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ p, optopt);
+ return(BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return(optopt); /* dump back option letter */
+}
+
+#endif
diff --git a/ldap/clients/dsgw/html/Makefile b/ldap/clients/dsgw/html/Makefile
new file mode 100644
index 00000000..6fe5280b
--- /dev/null
+++ b/ldap/clients/dsgw/html/Makefile
@@ -0,0 +1,81 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# Gmakefile for Directory Server Gateway html files.
+#
+
+LDAP_SRC = ../../..
+MCOM_ROOT = ../../../../..
+
+NOSTDSTRIP=true # don't let nsconfig.mak define target strip
+NOSTDCLEAN=true # don't let nsconfig.mak define target clean
+NOSTDDEPEND=true # don't let nsconfig.mak define target depend
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+include ../dsgw_include.mk
+
+HTMLDEST = $(DSGW_HTML_RELDIR)
+
+HTML= auth.html authroot.html authtitle.html csearchtitle.html \
+ emptyFrame.html greeting.html index.html maintitle.html \
+ newentrytitle.html searchtitle.html style.css \
+ transparent.gif back1.gif content1.gif netscape.gif \
+ country.gif exit1.gif forward1.gif group.gif index1.gif \
+ left_bottom.gif left_on.gif right_off.gif \
+ left_off.gif right_bottom.gif right_on.gif \
+ organization.gif orgunit.gif person.gif clear.gif message.gif \
+ alert.html alert.gif confirm.html confirm.gif orgicon.gif aim-online.gif
+
+BINS=$(addprefix $(HTMLDEST)/,$(HTML))
+
+ifeq ($(ARCH), WINNT)
+CP2=cmd /c 'sh ../../../cm/nbsp2utf8.sh $< >'
+else
+CP2=sh ../../../cm/nbsp2utf8.sh $< >
+endif
+
+include $(MCOM_ROOT)/ldapserver/config/webint.mk
+
+all: $(HTMLDEST) $(BINS) all-manual all-info
+
+install: $(HTMLDEST) $(BINS) inst-manual inst-info
+
+clean: clean-manual clean-info
+ $(RM) $(BINS)
+
+# gif files (and presumably other binary files) are copied, not filtered
+$(HTMLDEST)/%.gif: %.gif
+ @-$(RM) $@
+ cp $< $@
+
+# all other files are filtered
+$(HTMLDEST)/%: %
+ @-$(RM) $@
+ $(CP2) $@
+
+all-manual:
+ cd manual; $(MAKE) $(MFLAGS) all
+
+all-info:
+ cd info; $(MAKE) $(MFLAGS) all
+
+inst-manual:
+ cd manual; $(MAKE) $(MFLAGS) install
+
+inst-info:
+ cd info; $(MAKE) $(MFLAGS) install
+
+clean-manual:
+ cd manual; $(MAKE) $(MFLAGS) clean
+
+clean-info:
+ cd info; $(MAKE) $(MFLAGS) clean
+
+strip:
+depend:
diff --git a/ldap/clients/dsgw/html/aim-online.gif b/ldap/clients/dsgw/html/aim-online.gif
new file mode 100644
index 00000000..b364017e
--- /dev/null
+++ b/ldap/clients/dsgw/html/aim-online.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/alert.gif b/ldap/clients/dsgw/html/alert.gif
new file mode 100644
index 00000000..ba9c07e1
--- /dev/null
+++ b/ldap/clients/dsgw/html/alert.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/alert.html b/ldap/clients/dsgw/html/alert.html
new file mode 100644
index 00000000..278002ea
--- /dev/null
+++ b/ldap/clients/dsgw/html/alert.html
@@ -0,0 +1,24 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+<!-- DS_POSTEDVALUE "NAME=TITLE" -->
+</title>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<BODY onLoad="document.OK.btn.focus();" bgcolor="#CCCCCC">
+<TABLE cols=2 width="100%"><TR VALIGN=CENTER>
+<TD ALIGN=CENTER WIDTH=32><IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=alert.gif" HEIGHT=32 WIDTH=32 BORDER="0" ALT="Alert"></TD>
+<TD>
+<!-- DS_POSTEDVALUE "NAME=MSG" -->
+</TD></TR></TABLE>
+<FORM NAME=OK><CENTER>
+<!-- DS_CLOSEBUTTON "NAME=btn" "LABEL= OK " -->
+</CENTER></FORM>
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/html/auth.html b/ldap/clients/dsgw/html/auth.html
new file mode 100644
index 00000000..e3fabe5d
--- /dev/null
+++ b/ldap/clients/dsgw/html/auth.html
@@ -0,0 +1,26 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Netscape Directory Server Gateway: Authenticate
+</TITLE>
+</HEAD>
+
+<FRAMESET ROWS=130,* BORDER=0>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO">
+ <FRAME SRC="/clients/dsgw/bin/auth?<!-- GCONTEXT -->" NAME="authFrame" SCROLLING="auto">
+</FRAMESET>
+<NOFRAMES>
+<H3>Frames-capable browser required</H3>
+Sorry, but in order to use the Netscape Directory Server Gateway,
+you must use a browser which supports HTML forms and JavaScript, such
+as Netscape Navigator version 3 or later. To learn how to obtain
+Navigator, visit the <A HREF="http://home.netscape.com">Netscape Home Page</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/authroot.html b/ldap/clients/dsgw/html/authroot.html
new file mode 100644
index 00000000..0d32aa12
--- /dev/null
+++ b/ldap/clients/dsgw/html/authroot.html
@@ -0,0 +1,26 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Netscape Directory Server Gateway: Authenticate
+</TITLE>
+</HEAD>
+<FRAMESET ROWS=130,* BORDER=0>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO" MARGINHEIGHT=6 MARGINWIDTH=8>
+ <FRAME SRC="/clients/dsgw/bin/auth?MANAGER&<!-- GCONTEXT -->" NAME="authFrame"
+NORESIZE SCROLLING="auto" MARGINHEIGHT=8 MARGINWIDTH=8>
+</FRAMESET>
+<NOFRAMES>
+<H3>Frames-capable browser required</H3>
+Sorry, but in order to use the Netscape Directory Server Gateway,
+you must use a browser which supports HTML forms and JavaScript, such
+as Netscape Navigator version 3 or later. To learn how to obtain
+Navigator, visit the <A HREF="http://home.netscape.com">Netscape Home Page</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/authtitle.html b/ldap/clients/dsgw/html/authtitle.html
new file mode 100644
index 00000000..1bdbd3f4
--- /dev/null
+++ b/ldap/clients/dsgw/html/authtitle.html
@@ -0,0 +1,156 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<body bgcolor="#FFFFFF" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0">
+
+<TABLE width="100%" cellspacing="0" cellpadding="0" border="0" class="bgColor4">
+ <TR>
+ <TD>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td colspan="4"><img border="0" height="10" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td><a href="http://www.netscape.com"><img border="0" height="19" width="19" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=netscape.gif"></a></td>
+ <td><img border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true" align=left width="100%" class="appName">Netscape Directory Server Gateway</td>
+ </tr>
+ <tr>
+ <td colspan="4"><img border="0" height="12" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ </table>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Standard Search'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Standard Search" ALT="Standard Search">Standard Search</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Advanced Search'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Advanced Search" ALT="Advanced Search">Advanced Search</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='New Entry'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="New Entry" ALT="New Entry">New Entry</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgAtTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_on.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_on.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgAtTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><A HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html"
+ TARGET="_top" onMouseOver="self.status='Authentication'; return true;"
+ onMouseOut="self.status=''; return true;" TITLE="Authentication"
+ ALT="Authentication" class="link7">Authentication</a></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_bottom.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td><img border="0" height="1" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_bottom.gif"></td>
+ </tr>
+ </table>
+ </td>
+
+ <td width="100%"><img border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </TR>
+ <TR>
+ <TD class="bgRegTab" colspan="7"><IMG border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ <TD class="bgAtTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ <TD class="bgRegTab" colspan="1"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ <TABLE class="bgAtTab" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <TR>
+ <TD>
+ <IMG border="0" height="43" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </TD>
+ </TR>
+ <TR>
+ <TD class="bgRegTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ <TR>
+ <TD class="bgDarkRule"><IMG border="0" height="2" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/back1.gif b/ldap/clients/dsgw/html/back1.gif
new file mode 100644
index 00000000..7eaf5c47
--- /dev/null
+++ b/ldap/clients/dsgw/html/back1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/clear.gif b/ldap/clients/dsgw/html/clear.gif
new file mode 100644
index 00000000..35d42e80
--- /dev/null
+++ b/ldap/clients/dsgw/html/clear.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/confirm.gif b/ldap/clients/dsgw/html/confirm.gif
new file mode 100644
index 00000000..453d1b2b
--- /dev/null
+++ b/ldap/clients/dsgw/html/confirm.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/confirm.html b/ldap/clients/dsgw/html/confirm.html
new file mode 100644
index 00000000..5680f129
--- /dev/null
+++ b/ldap/clients/dsgw/html/confirm.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD>
+<TITLE>
+<!-- DS_POSTEDVALUE "NAME=TITLE" -->
+</TITLE>
+<!-- DS_CONFIRM_SCRIPT -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<BODY class="bgColor4">
+<TABLE COLS=2 WIDTH="100%"><TR VALIGN=CENTER>
+<TD ALIGN=CENTER WIDTH=36><IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=confirm.gif" HEIGHT=32 WIDTH=32 BORDER="0" ALT="Confirm"></TD><TD>
+<!-- DS_POSTEDVALUE "NAME=MSG" -->
+</TD></TR></TABLE>
+<FORM><TABLE COLS=4 WIDTH="100%"><TR ALIGN=CENTER>
+<TD></TD>
+<TD>
+<!-- DS_CONFIRM_BUTTON_OK -->
+</TD><TD>
+<!-- DS_CONFIRM_BUTTON_CANCEL -->
+</TD>
+<TD></TD>
+</TR></TABLE></FORM>
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/html/content1.gif b/ldap/clients/dsgw/html/content1.gif
new file mode 100644
index 00000000..bea2b976
--- /dev/null
+++ b/ldap/clients/dsgw/html/content1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/country.gif b/ldap/clients/dsgw/html/country.gif
new file mode 100644
index 00000000..910c2dc7
--- /dev/null
+++ b/ldap/clients/dsgw/html/country.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/csearchtitle.html b/ldap/clients/dsgw/html/csearchtitle.html
new file mode 100644
index 00000000..4a1d4ddc
--- /dev/null
+++ b/ldap/clients/dsgw/html/csearchtitle.html
@@ -0,0 +1,156 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<body bgcolor="#FFFFFF" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0">
+
+<TABLE width="100%" cellspacing="0" cellpadding="0" border="0" class="bgColor4">
+ <TR>
+ <TD>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td colspan="4"><img border="0" height="10" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td><a href="http://www.netscape.com"><img border="0" height="19" width="19" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=netscape.gif"></a></td>
+ <td><img border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true" align=left width="100%" class="appName">Netscape Directory Server Gateway</td>
+ </tr>
+ <tr>
+ <td colspan="4"><img border="0" height="12" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ </table>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Standard Search'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Standard Search" ALT="Standard Search">Standard Search</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgAtTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_on.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_on.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgAtTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><A HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Advanced Search'; return true;"
+ onMouseOut="self.status=''; return true;" TITLE="Advanced Search"
+ ALT="Advanced Search" class="link7">Advanced Search</a></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_bottom.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td><img border="0" height="1" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_bottom.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='New Entry'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="New Entry" ALT="New Entry">New Entry</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html"
+ TARGET="_top" onMouseOver="self.status='Authentication'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Authentication" ALT="Authentication">Authentication</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+
+ <td width="100%"><img border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </TR>
+ <TR>
+ <TD class="bgRegTab" colspan="3"><IMG border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ <TD class="bgAtTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ <TD class="bgRegTab" colspan="5"><IMG border="0" height="1" width="5" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ <TABLE class="bgAtTab" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <TR>
+ <TD>
+ <IMG border="0" height="43" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </TD>
+ </TR>
+ <TR>
+ <TD class="bgRegTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ <TR>
+ <TD class="bgDarkRule"><IMG border="0" height="2" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/dc.gif b/ldap/clients/dsgw/html/dc.gif
new file mode 100644
index 00000000..6324da4b
--- /dev/null
+++ b/ldap/clients/dsgw/html/dc.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/adsearch_off.gif b/ldap/clients/dsgw/html/de/adsearch_off.gif
new file mode 100644
index 00000000..517952ba
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/adsearch_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/adsearch_on.gif b/ldap/clients/dsgw/html/de/adsearch_on.gif
new file mode 100644
index 00000000..12ab8de5
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/adsearch_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/auth.html b/ldap/clients/dsgw/html/de/auth.html
new file mode 100644
index 00000000..60476d2a
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/auth.html
@@ -0,0 +1,24 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Netscape Directory Server Gateway: Beglaubigen
+</TITLE>
+</HEAD>
+
+<FRAMESET ROWS=100,* BORDER=2>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO">
+ <FRAME SRC="/clients/dsgw/bin/auth?<!-- GCONTEXT -->" NAME="authFrame">
+</FRAMESET>
+<NOFRAMES>
+<H3>Browser muä Rahmen verarbeiten kȸnnen</H3>
+Um das Netscape Directory Server Gateway zu verwenden, muä Ihr Browser HTML-Formulare und JavaScript verarbeiten kȸnnen, wie zum Beispiel Netscape Navigator Version 3 oder hȸher. Wie Sie Netscape Navigator bekommen, erfahren Sie auf der <A HREF="http://home.netscape.com">Netscape-Startseite</A>.
+</NOFRAMES>
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/de/authen_off.gif b/ldap/clients/dsgw/html/de/authen_off.gif
new file mode 100644
index 00000000..dc9642ff
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/authen_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/authen_on.gif b/ldap/clients/dsgw/html/de/authen_on.gif
new file mode 100644
index 00000000..bb1525b9
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/authen_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/authroot.html b/ldap/clients/dsgw/html/de/authroot.html
new file mode 100644
index 00000000..0a6a4f83
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/authroot.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Netscape Directory Server Gateway: Beglaubigen
+</TITLE>
+</HEAD>
+<FRAMESET ROWS=100,* BORDER=2>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO">
+ <FRAME SRC="/clients/dsgw/bin/auth?MANAGER&<!-- GCONTEXT -->" NAME="authFrame">
+</FRAMESET>
+<NOFRAMES>
+<H3>Browser muä Rahmen verarbeiten kȸnnen</H3>
+Um das Netscape Directory Server Gateway zu verwenden, muä Ihr Browser HTML-Formulare und JavaScript verarbeiten kȸnnen, wie zum Beispiel Netscape Navigator Version 3 oder hȸher. Wie Sie Netscape Navigator bekommen, erfahren Sie auf der <A HREF="http://home.netscape.com">Netscape-Startseite</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/de/authtitle.html b/ldap/clients/dsgw/html/de/authtitle.html
new file mode 100644
index 00000000..2e575dfd
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/authtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Standardsuche"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Erweiterte Suche"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Neuer Eintrag"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Beglaubigung"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/de/back.gif b/ldap/clients/dsgw/html/de/back.gif
new file mode 100644
index 00000000..024df22f
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/back.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/back1.gif b/ldap/clients/dsgw/html/de/back1.gif
new file mode 100644
index 00000000..a514ef9a
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/back1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/content.gif b/ldap/clients/dsgw/html/de/content.gif
new file mode 100644
index 00000000..a7eb4276
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/content.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/content1.gif b/ldap/clients/dsgw/html/de/content1.gif
new file mode 100644
index 00000000..e5955366
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/content1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/csearchtitle.html b/ldap/clients/dsgw/html/de/csearchtitle.html
new file mode 100644
index 00000000..c8e8af65
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/csearchtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Standardsuche"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Erweiterte Suche"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Neuer Eintrag"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Beglaubigung"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/de/eduser.html b/ldap/clients/dsgw/html/de/eduser.html
new file mode 100644
index 00000000..9fc755c7
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/eduser.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>Benutzer-Management</TITLE></HEAD>
+<HTML><BODY bgcolor="#C0C0C0" link="#0000EE" vlink="#551A8B" alink="#FF0000">
+
+<center><table border=2 width=100%%>
+<tr><td align=center width=100%><hr size=0 width=0><FONT size=+2><b>Benutzer bearbeiten</b></FONT><hr size=0 width=0></th></tr></table></center>
+
+<form method="POST" action=dosearch name=eduserform>
+<input type=hidden name=mode value="smart">
+<input type=hidden name=type value="people">
+<input type=hidden name=editable value="true">
+<!-- PCONTEXT -->
+
+<b>Bearbeiten des Benutzers: </b><INPUT type="text" name="searchstring" value="" size=20>
+</pre>
+<p>
+
+<center><table border=2 width=100%>
+<tr>
+<td width=33% align=center><input type=submit value="Benutzer bearbeiten"></td>
+<td width=34% align=center><input type=reset value="R&uuml;cksetzen"></td>
+<td width=33% align=center><input type=button value=" Hilfe " onclick="var hwin=window.open('', 'infowin_httpd',
+'resizable=1,width=400,height=500');if(top.helpwin==1) hwin.frames[1].location='http://ggood:2001/httpd-ggood/bin/tutor?!usradd&<!-- GCONTEXT -->';else { hwin.location='http://ggood:2001/httpd-ggood/bin/tutor?usradd&<!-- GCONTEXT -->'; hwin.rwin=top; hwin.rwin.helpwin=1; }"></td>
+</tr></table></center>
+</form>
diff --git a/ldap/clients/dsgw/html/de/exit1.gif b/ldap/clients/dsgw/html/de/exit1.gif
new file mode 100644
index 00000000..8a9e3c1b
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/exit1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/forward1.gif b/ldap/clients/dsgw/html/de/forward1.gif
new file mode 100644
index 00000000..5636496d
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/forward1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/greeting.html b/ldap/clients/dsgw/html/de/greeting.html
new file mode 100644
index 00000000..bbf31e5f
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/greeting.html
@@ -0,0 +1,64 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript browsers
+function gotoURL(h) {
+ top.location.href = h;
+}
+// End hiding -->
+</SCRIPT>
+</HEAD>
+<BODY BGCOLOR="white">
+<HR>
+<CENTER>
+<FONT SIZE="+2">Netscape Directory Server Gateway</FONT>
+</CENTER>
+<P>
+Mit dieser Schnittstelle k&ouml;nnen Sie Eintr&auml;ge zur Speicherung im Netscape Directory Server suchen, &auml;ndern oder erstellen.
+<P>
+Die Schaltfl&auml;chen oben im Fenster sind bei der Arbeit mit dem Directory Server Gateway st&auml;ndig verf&uuml;gbar. Durch Anklicken dieser Schaltfl&auml;chen k&ouml;nnen Sie die folgenden Aktionen ausf&uuml;hren lassen:
+<P>
+<TABLE BORDER=1>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top">Standardsuche</A>
+</TH>
+<TD>
+Die Standardsuche ist die einfachste M&ouml;glichkeit zum Durchsuchen des Verzeichnisses. Hierbei wird Ihre Eingabe analysiert und danach automatisch eine oder mehrere passende Verzeichnis-Suchmethoden aktiviert.
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top">Erweiterte Suche</A>
+</TH>
+<TD>
+Bei der Erweiterten Suche geben Sie genau ein, was Sie suchen, nach welchem Attribut Sie suchen und welche Art der &Uuml;bereinstimmung mit den Suchkriterien erforderlich ist.
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top">Neuer Eintrag</A>
+</TH>
+<TD>
+Mit "Neuer Eintrag" k&ouml;nnen Sie neue Eintr&auml;ge im Verzeichnis vornehmen.. Unter Umst&auml;nden hat der Systemverwalter das Verzeichnis so eingerichtet, da&szlig; Sie zum Hinzuf&uuml;gen neuer Eintr&auml;ge eine besondere Berechtigung ben&ouml;tigen. Wenn Sie nicht sicher sind, wenden Sie sich an Ihren Systemverwalter.
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top">Beglaubigung</A>
+</TH>
+<TD>
+Mit den Beblaubigungs-Eingabefenstern melden Sie sich im Verzeichnis an und ab. Sie m&uuml;ssen sich beglaubigen lassen, bevor Sie Eintr&auml;ge im dem Verzeichnis &auml;ndern und hinzuf&uuml;gen k&ouml;nnen. Sie m&uuml;ssen sich au&szlig;erdem je nach Vorgabe des Systemverwalters auch beglaubigen lassen, bevor Sie ein Verzeichnis durchsuchen k&ouml;nnen.
+</TD>
+</TR>
+</TABLE>
+</BODY>
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/de/index.html b/ldap/clients/dsgw/html/de/index.html
new file mode 100644
index 00000000..1ccbd0f7
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/index.html
@@ -0,0 +1,21 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server Gateway</TITLE>
+</HEAD>
+<FRAMESET ROWS=100,*>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=maintitle.html" NAME="buttonBarFrame" NORESIZE
+ SCROLLING="no">
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=greeting.html" NAME="greetingFrame" NORESIZE>
+</FRAMESET>
+<NOFRAMES>
+<H3>Browser muä Rahmen verarbeiten kȸnnen</H3>
+Um das Netscape Directory Server Gateway zu verwenden, muä Ihr Browser HTML-Formulare und JavaScript verarbeiten kȸnnen, wie zum Beispiel Netscape Navigator Version 3 oder hȸher. Wie Sie Netscape Navigator bekommen, erfahren Sie auf der <A HREF="http://home.netscape.com">Netscape-Startseite</A>.
+</NOFRAMES>
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/de/index1.gif b/ldap/clients/dsgw/html/de/index1.gif
new file mode 100644
index 00000000..75d03661
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/index1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/maintitle.html b/ldap/clients/dsgw/html/de/maintitle.html
new file mode 100644
index 00000000..f60e84f9
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/maintitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Standardsuche"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Erweiterte Suche"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Neuer Eintrag"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Beglaubigung"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/de/newentry_off.gif b/ldap/clients/dsgw/html/de/newentry_off.gif
new file mode 100644
index 00000000..9b302478
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/newentry_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/newentry_on.gif b/ldap/clients/dsgw/html/de/newentry_on.gif
new file mode 100644
index 00000000..25121401
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/newentry_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/newentrytitle.html b/ldap/clients/dsgw/html/de/newentrytitle.html
new file mode 100644
index 00000000..61e30b3d
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/newentrytitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Standardsuche"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Erweiterte Suche"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Neuer Eintrag"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Beglaubigung"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/de/searchtitle.html b/ldap/clients/dsgw/html/de/searchtitle.html
new file mode 100644
index 00000000..a4ae798f
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/searchtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Standardsuche"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Erweiterte Suche"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Neuer Eintrag"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Beglaubigung"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/de/stsearch_off.gif b/ldap/clients/dsgw/html/de/stsearch_off.gif
new file mode 100644
index 00000000..015e1e5a
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/stsearch_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/stsearch_on.gif b/ldap/clients/dsgw/html/de/stsearch_on.gif
new file mode 100644
index 00000000..f4446593
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/stsearch_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/de/title.gif b/ldap/clients/dsgw/html/de/title.gif
new file mode 100644
index 00000000..5fca8c94
--- /dev/null
+++ b/ldap/clients/dsgw/html/de/title.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/eduser.html b/ldap/clients/dsgw/html/eduser.html
new file mode 100644
index 00000000..3a4fd1ea
--- /dev/null
+++ b/ldap/clients/dsgw/html/eduser.html
@@ -0,0 +1,31 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>User Management</TITLE></HEAD>
+<HTML><BODY bgcolor="#C0C0C0" link="#0000EE" vlink="#551A8B" alink="#FF0000">
+
+<center><table border=2 width=100%%>
+<tr><td align=center width=100%><hr size=0 width=0><FONT size=+2><b>Edit
+User</b></FONT><hr size=0 width=0></th></tr></table></center>
+
+<form method="POST" action=dosearch name=eduserform>
+<input type=hidden name=mode value="smart">
+<input type=hidden name=type value="people">
+<input type=hidden name=editable value="true">
+<!-- PCONTEXT -->
+
+<b>Edit the user named: </b><INPUT type="text" name="searchstring" value="" size=20>
+</pre>
+<p>
+
+<center><table border=2 width=100%>
+<tr>
+<td width=33% align=center><input type=submit value="Edit User"></td>
+<td width=34% align=center><input type=reset value="Reset"></td>
+<td width=33% align=center><input type=button value=" Help " onclick="var hwin=window.open('', 'infowin_httpd',
+'resizable=1,width=400,height=500');if(top.helpwin==1) hwin.frames[1].location='http://ggood:2001/httpd-ggood/bin/tutor?!usradd';else { hwin.location='http://ggood:2001/httpd-ggood/bin/tutor?usradd'; hwin.rwin=top; hwin.rwin.helpwin=1; }"></td>
+</tr></table></center>
+</form>
diff --git a/ldap/clients/dsgw/html/emptyFrame.html b/ldap/clients/dsgw/html/emptyFrame.html
new file mode 100644
index 00000000..627efdfb
--- /dev/null
+++ b/ldap/clients/dsgw/html/emptyFrame.html
@@ -0,0 +1,7 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><BODY BGCOLOR="white"></BODY></HTML>
diff --git a/ldap/clients/dsgw/html/es/adsearch_off.gif b/ldap/clients/dsgw/html/es/adsearch_off.gif
new file mode 100644
index 00000000..6a0864b4
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/adsearch_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/adsearch_on.gif b/ldap/clients/dsgw/html/es/adsearch_on.gif
new file mode 100644
index 00000000..37ec8ad3
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/adsearch_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/auth.html b/ldap/clients/dsgw/html/es/auth.html
new file mode 100644
index 00000000..d4f8e7b0
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/auth.html
@@ -0,0 +1,23 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Pasarela de Netscape Directory Server: Autenticar
+</TITLE>
+</HEAD>
+
+<FRAMESET ROWS=75,* BORDER=0>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO">
+ <FRAME SRC="/clients/dsgw/bin/auth?<!-- GCONTEXT -->" NAME="authFrame">
+</FRAMESET>
+<NOFRAMES>
+<H3>Es necesario un navegador que admita marcos</H3>
+Lo siento, pero para poder usar la Pasarela de Netscape Directory Server, debe emplear un navegador que admita formularios HTML y JavaScript, como Netscape Navigator versi&oacute;n 3 o posterior. Para conseguir Navigator, visite la <A HREF="http://home.es.netscape.com/es/">P&aacute;gina principal de Netscape</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/es/authen_off.gif b/ldap/clients/dsgw/html/es/authen_off.gif
new file mode 100644
index 00000000..aa979dff
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/authen_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/authen_on.gif b/ldap/clients/dsgw/html/es/authen_on.gif
new file mode 100644
index 00000000..862644a7
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/authen_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/authroot.html b/ldap/clients/dsgw/html/es/authroot.html
new file mode 100644
index 00000000..2bd00b1d
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/authroot.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Pasarela de Netscape Directory Server: Autenticar
+</TITLE>
+</HEAD>
+<FRAMESET ROWS=100,* BORDER=0>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO">
+ <FRAME SRC="/clients/dsgw/bin/auth?MANAGER&<!-- GCONTEXT -->" NAME="authFrame">
+</FRAMESET>
+<NOFRAMES>
+<H3>Es necesario un navegador que admita marcos</H3>
+Lo siento, pero para poder usar la Pasarela de Netscape Directory Server, debe emplear un navegador que admita formularios HTML y JavaScript, como Netscape Navigator versi&oacute;n 3 o posterior. Para conseguir Navigator, visite la <A HREF="http://home.es.netscape.com/es/">P&aacute;gina principal de Netscape</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/es/authtitle.html b/ldap/clients/dsgw/html/es/authtitle.html
new file mode 100644
index 00000000..ce35909d
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/authtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda normal"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda avanzada"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nueva entrada"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Autenticaci&oacute;n"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/es/back1.gif b/ldap/clients/dsgw/html/es/back1.gif
new file mode 100644
index 00000000..df7c7916
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/back1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/blank.gif b/ldap/clients/dsgw/html/es/blank.gif
new file mode 100644
index 00000000..afa7fb83
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/blank.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/content1.gif b/ldap/clients/dsgw/html/es/content1.gif
new file mode 100644
index 00000000..01e83649
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/content1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/country.gif b/ldap/clients/dsgw/html/es/country.gif
new file mode 100644
index 00000000..d64220f3
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/country.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/csearchtitle.html b/ldap/clients/dsgw/html/es/csearchtitle.html
new file mode 100644
index 00000000..7def480d
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/csearchtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda normal"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda avanzada"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nueva entrada"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Autenticaci&oacute;n"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/es/eduser.html b/ldap/clients/dsgw/html/es/eduser.html
new file mode 100644
index 00000000..203a8fba
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/eduser.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>Administraci&oacute;n de usuarios</TITLE></HEAD>
+<HTML><BODY bgcolor="#C0C0C0" link="#0000EE" vlink="#551A8B" alink="#FF0000">
+
+<center><table border=2 width=100%>
+<tr><td align=center width=100%><hr size=0 width=0><FONT size=+2><b>Modificar usuario</b></FONT><hr size=0 width=0></th></tr></table></center>
+
+<form method="POST" action=dosearch name=eduserform>
+<input type=hidden name=mode value="smart">
+<input type=hidden name=type value="people">
+<input type=hidden name=editable value="true">
+<!-- PCONTEXT -->
+
+<b>Modificar este usuario: </b><INPUT type="text" name="searchstring" value="" size=20>
+</pre>
+<p>
+
+<center><table border=2 width=100%>
+<tr>
+<td width=33% align=center><input type=submit value="Modificar usuario"></td>
+<td width=34% align=center><input type=reset value="Restablecer"></td>
+<td width=33% align=center><input type=button value=" Ayuda " onclick="var hwin=window.open('', 'infowin_httpd',
+'resizable=1,width=400,height=500');if(top.helpwin==1) hwin.frames[1].location='http://ggood:2001/httpd-ggood/bin/tutor?!usradd&<!-- GCONTEXT -->';else { hwin.location='http://ggood:2001/httpd-ggood/bin/tutor?usradd&<!-- GCONTEXT -->'; hwin.rwin=top; hwin.rwin.helpwin=1; }"></td>
+</tr></table></center>
+</form>
diff --git a/ldap/clients/dsgw/html/es/exit1.gif b/ldap/clients/dsgw/html/es/exit1.gif
new file mode 100644
index 00000000..035d4ddf
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/exit1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/forward1.gif b/ldap/clients/dsgw/html/es/forward1.gif
new file mode 100644
index 00000000..34bca12c
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/forward1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/greeting.html b/ldap/clients/dsgw/html/es/greeting.html
new file mode 100644
index 00000000..f13baf6b
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/greeting.html
@@ -0,0 +1,64 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript browsers
+function gotoURL(h) {
+ top.location.href = h;
+}
+// End hiding -->
+</SCRIPT>
+</HEAD>
+<BODY BGCOLOR="white">
+<HR>
+<CENTER>
+<FONT SIZE="+2">Bienvenido a la Pasarela de Netscape Directory Server</FONT>
+</CENTER>
+<P>
+Mediante esta interfaz puede buscar, modificar y crear entradas que quedan almacenadas en el Netscape Directory Server.
+<P>
+Siempre que utilice la Pasarela de Netscape Directory Server dispondr&aacute; de la barra de herramientas de la parte superior de esta ventana. Puede hacer clic en los botones para llevar a cabo cualquiera de las siguientes tareas:
+<P>
+<TABLE BORDER=1>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top">B&uacute;squeda normal</A>
+</TH>
+<TD>
+Con esta funci&oacute;n puede buscar f&aacute;cilmente informaci&oacute;n del directorio. Esta funci&oacute;n examina los datos que haya introducido y selecciona autom&aacute;ticamente uno o varios m&eacute;todos de b&uacute;squeda en el directorio.
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top">B&uacute;squeda avanzada</A>
+</TH>
+<TD>
+Con esta funci&oacute;n puede especificar exactamente lo que est&eacute; buscando, los atributos que desee buscar y el tipo de concordancia que desee aplicar.
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top">Nueva entrada</A>
+</TH>
+<TD>
+Con esta funci&oacute;n puede crear nuevas entradas en el directorio. Seg&uacute;n la configuraci&oacute;n de directorio aplicada por el administrador del sistema, deber&aacute; disponer de un permiso especial para a&ntilde;adir entradas nuevas. Si no est&aacute; seguro, consulte al administrador del sistema.
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top">Autenticar</A>
+</TH>
+<TD>
+Con esta funci&oacute;n puede usar las pantallas de autenticaci&oacute;n para entrar y salir del directorio. Debe autenticarse para poder modificar o a&ntilde;adir entradas al directorio. Es posible que tambi&eacute;n tenga que hacerlo para poder buscar en el directorio si el administrador del sistema lo estableci&oacute; de ese modo.
+</TD>
+</TR>
+</TABLE>
+</BODY>
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/es/group.gif b/ldap/clients/dsgw/html/es/group.gif
new file mode 100644
index 00000000..c746e5f0
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/group.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/index.html b/ldap/clients/dsgw/html/es/index.html
new file mode 100644
index 00000000..a7f2f7e1
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/index.html
@@ -0,0 +1,20 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Pasarela de Netscape Directory Server</TITLE>
+</HEAD>
+<FRAMESET ROWS=75,* BORDER=0>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=maintitle.html" NAME="buttonBarFrame" NORESIZE
+ SCROLLING="no">
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=greeting.html" NAME="greetingFrame" NORESIZE>
+</FRAMESET>
+<NOFRAMES>
+<H3>Es necesario un navegador que admita marcos</H3>
+Lo siento, pero para poder usar la Pasarela de Netscape Directory Server, debe emplear un navegador que admita formularios HTML y JavaScript, como Netscape Navigator versi&oacute;n 3 o posterior. Para conseguir Navigator, visite la <A HREF="http://home.es.netscape.com/es/">P&aacute;gina principal de Netscape</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/es/index1.gif b/ldap/clients/dsgw/html/es/index1.gif
new file mode 100644
index 00000000..c19d8020
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/index1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/maintitle.html b/ldap/clients/dsgw/html/es/maintitle.html
new file mode 100644
index 00000000..9a6e7398
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/maintitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda normal"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda avanzada"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nueva entrada"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Autenticaci&oacute;n"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/es/newentry_off.gif b/ldap/clients/dsgw/html/es/newentry_off.gif
new file mode 100644
index 00000000..d9733126
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/newentry_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/newentry_on.gif b/ldap/clients/dsgw/html/es/newentry_on.gif
new file mode 100644
index 00000000..27c8058e
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/newentry_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/newentrytitle.html b/ldap/clients/dsgw/html/es/newentrytitle.html
new file mode 100644
index 00000000..a66ed5e4
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/newentrytitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda normal"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda avanzada"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nueva entrada"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Autenticaci&oacute;n"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/es/organization.gif b/ldap/clients/dsgw/html/es/organization.gif
new file mode 100644
index 00000000..2d0b1535
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/organization.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/orgunit.gif b/ldap/clients/dsgw/html/es/orgunit.gif
new file mode 100644
index 00000000..0c8be34a
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/orgunit.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/person.gif b/ldap/clients/dsgw/html/es/person.gif
new file mode 100644
index 00000000..63044811
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/person.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/searchtitle.html b/ldap/clients/dsgw/html/es/searchtitle.html
new file mode 100644
index 00000000..a2f62a02
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/searchtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda normal"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="B&uacute;squeda avanzada"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nueva entrada"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Autenticaci&oacute;n"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/es/stsearch_off.gif b/ldap/clients/dsgw/html/es/stsearch_off.gif
new file mode 100644
index 00000000..165a8adb
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/stsearch_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/stsearch_on.gif b/ldap/clients/dsgw/html/es/stsearch_on.gif
new file mode 100644
index 00000000..13552eb1
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/stsearch_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/es/title.gif b/ldap/clients/dsgw/html/es/title.gif
new file mode 100644
index 00000000..11bbaafd
--- /dev/null
+++ b/ldap/clients/dsgw/html/es/title.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/exit1.gif b/ldap/clients/dsgw/html/exit1.gif
new file mode 100644
index 00000000..56e23fa8
--- /dev/null
+++ b/ldap/clients/dsgw/html/exit1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/forward1.gif b/ldap/clients/dsgw/html/forward1.gif
new file mode 100644
index 00000000..ad75557b
--- /dev/null
+++ b/ldap/clients/dsgw/html/forward1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/adsearch_off.gif b/ldap/clients/dsgw/html/fr/adsearch_off.gif
new file mode 100644
index 00000000..b49ccfe2
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/adsearch_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/adsearch_on.gif b/ldap/clients/dsgw/html/fr/adsearch_on.gif
new file mode 100644
index 00000000..b477d5e0
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/adsearch_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/auth.html b/ldap/clients/dsgw/html/fr/auth.html
new file mode 100644
index 00000000..0b7ad796
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/auth.html
@@ -0,0 +1,24 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Passerelle Netscape Directory Server : Authentication
+</TITLE>
+</HEAD>
+
+<FRAMESET ROWS=100,* BORDER=2>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO">
+ <FRAME SRC="/clients/dsgw/bin/auth?<!-- GCONTEXT -->" NAME="authFrame">
+</FRAMESET>
+<NOFRAMES>
+<H3>Un navigateur supportant la fonction de cadres est requis</H3>
+Afin de pouvoir utiliser la passerelle Netscape Directory Server, vous devez utiliser un navigateur compatible avec les formulaires HTML et JavaScript, comme la version 3 ou toute version ultÃërieure de Netscape Navigator. Pour savoir comment vous procurer Navigator, consultez la page d'accueil de Netscape ÃÇ l'adresse : <A HREF="http://home.netscape.com">
+</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/fr/authen_off.gif b/ldap/clients/dsgw/html/fr/authen_off.gif
new file mode 100644
index 00000000..8d069b93
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/authen_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/authen_on.gif b/ldap/clients/dsgw/html/fr/authen_on.gif
new file mode 100644
index 00000000..80674d25
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/authen_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/authroot.html b/ldap/clients/dsgw/html/fr/authroot.html
new file mode 100644
index 00000000..05f98530
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/authroot.html
@@ -0,0 +1,22 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Passerelle Netscape Directory Server : authentification
+</TITLE>
+</HEAD>
+<FRAMESET ROWS=100,* BORDER=2>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO">
+ <FRAME SRC="/clients/dsgw/bin/auth/MANAGER&<!-- GCONTEXT -->" NAME="authFrame">
+</FRAMESET>
+<NOFRAMES>
+<H3> Un navigateur supportant la fonction de cadres est requis</H3>
+Afin de pouvoir utiliser la passerelle Netscape Directory Server, vous devez utiliser un navigateur compatible avec les formulaires HTML et JavaScript, comme la version 3 ou toute version ultȨrieure de Netscape Navigator. Pour savoir comment vous procurer Navigator, consultez la page d'accueil de Netscape Èá l'adresse : <A HREF="http://home.netscape.com">la page d'accueil de Netscape</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/fr/authtitle.html b/ldap/clients/dsgw/html/fr/authtitle.html
new file mode 100644
index 00000000..21cbf71e
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/authtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche standard"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche avanc&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nouvelle entr&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Authentification"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/fr/back.gif b/ldap/clients/dsgw/html/fr/back.gif
new file mode 100644
index 00000000..cc848925
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/back.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/back1.gif b/ldap/clients/dsgw/html/fr/back1.gif
new file mode 100644
index 00000000..ff77612d
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/back1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/content.gif b/ldap/clients/dsgw/html/fr/content.gif
new file mode 100644
index 00000000..b0cd53c6
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/content.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/content1.gif b/ldap/clients/dsgw/html/fr/content1.gif
new file mode 100644
index 00000000..c54e36b5
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/content1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/csearchtitle.html b/ldap/clients/dsgw/html/fr/csearchtitle.html
new file mode 100644
index 00000000..68aa6cd2
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/csearchtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche standard"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche avanc&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nouvelle entr&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Authentification"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/fr/eduser.html b/ldap/clients/dsgw/html/fr/eduser.html
new file mode 100644
index 00000000..3dcd8415
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/eduser.html
@@ -0,0 +1,32 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>Gestion des utilisateurs</TITLE></HEAD>
+<HTML><BODY bgcolor="#C0C0C0" link="#0000EE" vlink="#551A8B" alink="#FF0000">
+
+<center><table border=2 width=100%%>
+<tr><td align=center width=100%><hr size=0 width=0><FONT size=+2><b>Modifier l'utilisateur</b></FONT><hr size=0 width=0></th></tr></table></center>
+
+<form method="POST" action=dosearch name=eduserform>
+<input type=hidden name=mode value="smart">
+<input type=hidden name=type value="people">
+<input type=hidden name=editable value="true">
+<!-- PCONTEXT -->
+
+<b>Modifier l'utilisateur nomm&eacute; :</b><INPUT type="text" name="searchstring" value="" size=20>
+</pre>
+<p>
+
+<center><table border=2 width=100%>
+<tr>
+<td width=33% align=center><input type=submit value="Modifier l'utilisateur"></td>
+<td width=34% align=center><input type=reset value="Remettre &agrave; z&eacute;ro"></td>
+<td width=33% align=center><input type=button value="Aide" onclick="var hwin=window.open('', 'infowin_httpd',
+'resizable=1,width=400,height=500');if(top.helpwin==1) hwin.frames[1].location='http://ggood:2001/httpd-ggood/bin/tutor?!usradd&<!-- GCONTEXT -->';else { hwin.location='http://ggood:2001/httpd-ggood/bin/tutor?usradd&<!-- GCONTEXT -->'; hwin.rwin=top; hwin.rwin.helpwin=1; }"></td>
+</tr></table></center>
+</form>
+
+
diff --git a/ldap/clients/dsgw/html/fr/exit1.gif b/ldap/clients/dsgw/html/fr/exit1.gif
new file mode 100644
index 00000000..70af2dad
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/exit1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/forward1.gif b/ldap/clients/dsgw/html/fr/forward1.gif
new file mode 100644
index 00000000..1b80382f
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/forward1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/greeting.html b/ldap/clients/dsgw/html/fr/greeting.html
new file mode 100644
index 00000000..cb46a0fa
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/greeting.html
@@ -0,0 +1,65 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript browsers
+function gotoURL(h) {
+ top.location.href = h;
+}
+// End hiding -->
+</SCRIPT>
+</HEAD>
+<BODY BGCOLOR="white">
+<HR>
+<CENTER>
+<FONT SIZE="+2">Bienvenue dans la passerelle de Netscape Directory Server.</FONT>
+</CENTER>
+<P>
+Cette interface peut &ecirc;tre utilis&eacute;e pour rechercher, modifier et cr&eacute;er des entr&eacute;es stock&eacute;es dans Netscape Directory Server.
+<P>
+La barre d'outils qui appara&icirc;t dans la partie sup&eacute;rieure de cette fen&ecirc;tre est toujours affich&eacute;e lorsque vous utilisez la passerelle Directory Server. Vous pouvez cliquer sur ces boutons pour effectuer les t&acirc;ches suivantes :
+<P>
+<TABLE BORDER=1>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top">Recherche standard</A>
+</TH>
+<TD>
+La recherche standard est la mani&egrave;re la plus simple d'effectuer une recherche dans un annuaire. Elle examine les donn&eacute;es saisies et s&eacute;lectionne automatiquement une ou plusieurs m&eacute;thodes de recherche d'annuaires.
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top">Recherche avanc&eacute;e</A>
+</TH>
+<TD>
+Le bouton Recherche avanc&eacute;e vous permet de sp&eacute;cifier votre recherche avec exactitude &agrave; l'aide d'options de crit&egrave;res de recherche et de type de correspondance.
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top">Nouvelle entr&eacute;e</A>
+</TH>
+<TD>
+Le bouton Nouvelle entr&eacute;e vous permet de cr&eacute;er de nouvelles entr&eacute;es dans l'annuaire. Selon la fa&ccedil;on dont l'administrateur syst&egrave;me a configur&eacute; votre annuaire, vous devez peut-&ecirc;tre obtenir de celui-ci le privil&egrave;ge d'ajouter de nouvelles entr&eacute;es. Dans le doute, consultez votre administrateur syst&egrave;me.
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top">Authentification</A>
+</TH>
+<TD>
+Les &eacute;crans d'authentification vous permettent de vous connecter et de vous d&eacute;connecter d'un annuaire. Vous devez vous authentifier avant de modifier ou d'ajouter des entr&eacute;es &agrave; l'annuaire.
+</TD>
+</TR>
+</TABLE>
+</BODY>
+</HTML>
+
+
diff --git a/ldap/clients/dsgw/html/fr/index.html b/ldap/clients/dsgw/html/fr/index.html
new file mode 100644
index 00000000..0d5008d2
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/index.html
@@ -0,0 +1,20 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Passerelle Netscape Directory Server</TITLE>
+</HEAD>
+<FRAMESET ROWS=100,*>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=maintitle.html" NAME="buttonBarFrame" NORESIZE
+ SCROLLING="no">
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=greeting.html" NAME="greetingFrame" NORESIZE>
+</FRAMESET>
+<NOFRAMES>
+<H3> Un navigateur supportant la fonction de cadres est requis</H3>
+Afin de pouvoir utiliser la passerelle Netscape Directory Server, vous devez utiliser un navigateur compatible avec les formulaires HTML et JavaScript, comme la version 3 ou toute version ultȨrieure de Netscape Navigator. Pour savoir comment vous procurer Navigator, consultez la page d'accueil de Netscape Èá l'adresse : <A HREF="http://home.netscape.com">la page d'accueil de Netscape</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/fr/index1.gif b/ldap/clients/dsgw/html/fr/index1.gif
new file mode 100644
index 00000000..75d03661
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/index1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/maintitle.html b/ldap/clients/dsgw/html/fr/maintitle.html
new file mode 100644
index 00000000..f97e7ea6
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/maintitle.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche standard"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche avanc&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nouvelle entr&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Authentification"></A>
+
+</BODY>
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/fr/newentry_off.gif b/ldap/clients/dsgw/html/fr/newentry_off.gif
new file mode 100644
index 00000000..d98c6fbe
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/newentry_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/newentry_on.gif b/ldap/clients/dsgw/html/fr/newentry_on.gif
new file mode 100644
index 00000000..25e4b2d2
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/newentry_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/newentrytitle.html b/ldap/clients/dsgw/html/fr/newentrytitle.html
new file mode 100644
index 00000000..16eebece
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/newentrytitle.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche standard"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche avanc&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nouvelle entr&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Authentification"></A>
+
+</BODY>
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/fr/searchtitle.html b/ldap/clients/dsgw/html/fr/searchtitle.html
new file mode 100644
index 00000000..58e69228
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/searchtitle.html
@@ -0,0 +1,38 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche standard"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Recherche avanc&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Nouvelle entr&eacute;e"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="Authentification"></A>
+
+</BODY>
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/fr/stsearch_off.gif b/ldap/clients/dsgw/html/fr/stsearch_off.gif
new file mode 100644
index 00000000..fce290f4
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/stsearch_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/stsearch_on.gif b/ldap/clients/dsgw/html/fr/stsearch_on.gif
new file mode 100644
index 00000000..8224c0a0
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/stsearch_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/fr/title.gif b/ldap/clients/dsgw/html/fr/title.gif
new file mode 100644
index 00000000..818f6fa9
--- /dev/null
+++ b/ldap/clients/dsgw/html/fr/title.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/greeting.html b/ldap/clients/dsgw/html/greeting.html
new file mode 100644
index 00000000..aa81b54d
--- /dev/null
+++ b/ldap/clients/dsgw/html/greeting.html
@@ -0,0 +1,89 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript browsers
+function gotoURL(h) {
+ top.location.href = h;
+}
+// End hiding -->
+</SCRIPT>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<BODY>
+
+<CENTER> <TABLE CELLPADDING=5 CELLSPACING=5 WIDTH="80%">
+
+<TR> <TD COLSPAN=2>
+You are using the Netscape Directory Server Gateway. This interface can be
+used to search for, modify, and create entries that are stored in the Netscape Directory Server.
+<P>
+You are currently viewing the Standard Search screen, which provides an
+easy and convenient way to search the directory. Standard Search
+examines what you type and automatically selects one or more methods
+for searching the directory. Enter a name, telephone number, user id,
+or e-mail address in the Search For field and click the
+Search button to quickly locate directory entries. Click the Help
+button if you need additional assistance.
+
+<P>
+The toolbar you see at the top of this window is always available when you
+are using the Directory Server Gateway. In addition to Standard Search,
+you can click the other buttons to perform a variety of tasks.
+If you want to modify your own directory entry, first search for it using
+Standard or Advanced Search and then click the Edit Person button
+within the entry display.
+
+</TD> </TR>
+
+
+<TR> <TD ALIGN="center" class="bgColor9">
+ <A HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top" class="link14">
+ <B>Advanced<BR>Search</B>
+ </A></TD>
+
+ <TD BGCOLOR="#CCCCCC">
+With Advanced Search, you can specify exactly what you are looking
+for, what attribute you wish to search for, and what type of matching
+you wish to allow.
+
+ </TD> </TR>
+
+ <TR> <TD ALIGN="center" class="bgColor9">
+ <A HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top" class="link14">
+ <B>New Entry</B>
+ </A></TD>
+
+ <TD BGCOLOR="#CCCCCC">
+
+New Entry allows you to create new entries in the directory. Depending
+on how the system administrator has set up your directory you may need
+to be granted special permission to add new entries. If you are not sure, ask
+your system administrator.
+
+ </TD> </TR>
+
+ <TR> <TD ALIGN="center" class="bgColor9">
+ <A HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top" class="link14">
+ <B>Authenticate</B>
+ </A></TD>
+
+ <TD BGCOLOR="#CCCCCC">
+
+You use the authentication screens to log into and out of the directory.
+You need to authenticate before you can modify or add entries to the
+directory. You may also need to authenticate before searching the
+directory, if your system administrator requires it.
+ </TD> </TR>
+
+</TABLE> </CENTER>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/group.gif b/ldap/clients/dsgw/html/group.gif
new file mode 100644
index 00000000..182c7174
--- /dev/null
+++ b/ldap/clients/dsgw/html/group.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/index.html b/ldap/clients/dsgw/html/index.html
new file mode 100644
index 00000000..ee2012d0
--- /dev/null
+++ b/ldap/clients/dsgw/html/index.html
@@ -0,0 +1,24 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server Gateway</TITLE>
+</HEAD>
+<FRAMESET ROWS=130,* BORDER=0>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=maintitle.html" NAME="buttonBarFrame" NORESIZE
+ SCROLLING="no">
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=greeting.html" NAME="greetingFrame"
+ NORESIZE SCROLLING="auto">
+</FRAMESET>
+<NOFRAMES>
+<H3>Frames-capable browser required</H3>
+Sorry, but in order to use the Netscape Directory Server Gateway,
+you must use a browser which supports HTML forms and JavaScript, such
+as Netscape Navigator version 3 or later. To learn how to obtain
+Navigator, visit the <A HREF="http://home.netscape.com">Netscape Home Page</A>.
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/index1.gif b/ldap/clients/dsgw/html/index1.gif
new file mode 100644
index 00000000..ed37959a
--- /dev/null
+++ b/ldap/clients/dsgw/html/index1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/info/Makefile b/ldap/clients/dsgw/html/info/Makefile
new file mode 100644
index 00000000..34f3f92a
--- /dev/null
+++ b/ldap/clients/dsgw/html/info/Makefile
@@ -0,0 +1,40 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# Gmakefile for Directory Server Gateway info files.
+#
+
+LDAP_SRC = ../../../..
+MCOM_ROOT = ../../../../../..
+
+NOSTDSTRIP=true # don't let nsconfig.mak define target strip
+NOSTDCLEAN=true # don't let nsconfig.mak define target clean
+NOSTDDEPEND=true # don't let nsconfig.mak define target depend
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+include ../../dsgw_include.mk
+
+HTMLDEST = $(DSGW_INFO_RELDIR)
+
+HTML = infonav.html
+
+BINS=$(addprefix $(HTMLDEST)/,$(HTML))
+
+all: $(HTMLDEST) $(BINS)
+install: $(HTMLDEST) $(BINS)
+
+clean:
+ $(RM) $(BINS)
+
+$(HTMLDEST)/%: %
+ -@$(RM) $@
+ cp $< $@
+
+strip:
+depend:
diff --git a/ldap/clients/dsgw/html/info/infonav.html b/ldap/clients/dsgw/html/info/infonav.html
new file mode 100644
index 00000000..1cc4c62b
--- /dev/null
+++ b/ldap/clients/dsgw/html/info/infonav.html
@@ -0,0 +1,31 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<TITLE>Info</TITLE>
+
+<BODY bgcolor="#808080">
+
+<center>
+<table width=100%>
+<tr><td align=left valign=top>
+
+<a href="/clients/dsgw/bin/tutor?!contents&context=dsgw" target=infotopic>
+<img src="/clients/dsgw/html/content1.gif" border=0></a>
+
+<a href="javascript:parent.frames[1].history.go(-1)">
+<img src="/clients/dsgw/html/back1.gif" border=0></a>
+
+<a href="javascript:parent.frames[1].history.go(1)">
+<img src="/clients/dsgw/html/forward1.gif" border=0></a>
+
+</td>
+<td align=right valign=top>
+<a href="javascript:top.close()"><img src="/clients/dsgw/html/exit1.gif" border=0></a>
+</td></tr>
+</table>
+</center>
+
+</BODY>
diff --git a/ldap/clients/dsgw/html/ja/adsearch_off.gif b/ldap/clients/dsgw/html/ja/adsearch_off.gif
new file mode 100644
index 00000000..da918342
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/adsearch_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/adsearch_on.gif b/ldap/clients/dsgw/html/ja/adsearch_on.gif
new file mode 100644
index 00000000..9a2b143e
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/adsearch_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/auth.html b/ldap/clients/dsgw/html/ja/auth.html
new file mode 100644
index 00000000..788364c3
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/auth.html
@@ -0,0 +1,23 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Netscape Directory Server Gateway: Authentication
+</TITLE>
+</HEAD>
+
+<FRAMESET ROWS=100,* BORDER=2>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO">
+ <FRAME SRC="/clients/dsgw/bin/auth?<!-- GCONTEXT -->" NAME="authFrame">
+</FRAMESET>
+<NOFRAMES>
+<H3>フレーム機能をサãƒãƒ¼ãƒˆã™ã‚‹ãƒ–ラウザãŒå¿…è¦ã§ã™</H3>
+Netscape Directory Server Gatewayを使用ã™ã‚‹ã«ã¯ã€Netscape Navigatorパージョン3以é™ã®ã‚ˆã†ãªHTMLフォームã¨JavaScriptをサãƒãƒ¼ãƒˆã™ã‚‹ãƒ–ラウザãŒå¿…è¦ã§ã™ã€‚Navigatorã®å…¥æ‰‹æ–¹æ³•ã«ã¤ã„ã¦ã¯<A HREF="http://home.netscape.com">Netscapeã®ãƒ›ãƒ¼ãƒ ãƒšãƒ¼ã‚¸</A>ã‚’ã”覧ãã ã•ã„。
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/ja/authen_off.gif b/ldap/clients/dsgw/html/ja/authen_off.gif
new file mode 100644
index 00000000..9e8570a3
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/authen_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/authen_on.gif b/ldap/clients/dsgw/html/ja/authen_on.gif
new file mode 100644
index 00000000..f2e86160
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/authen_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/authroot.html b/ldap/clients/dsgw/html/ja/authroot.html
new file mode 100644
index 00000000..72b73aca
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/authroot.html
@@ -0,0 +1,23 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+Netscape Directory Server Gateway: èªè¨¼
+</TITLE>
+</HEAD>
+<FRAMESET ROWS=100,* BORDER=2>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authtitle.html" NAME="authTitleFrame" NORESIZE
+ SCROLLING="NO">
+ <FRAME SRC="/clients/dsgw/bin/auth/MANAGER&<!-- GCONTEXT -->" NAME="authFrame">
+</FRAMESET>
+<NOFRAMES>
+<H3>フレーム機能をサãƒãƒ¼ãƒˆã™ã‚‹ãƒ–ラウザãŒå¿…è¦ã§ã™</H3>
+Netscape Directory Server Gatewayを使用ã™ã‚‹ã«ã¯ã€Netscape Navigatorパージョン3以é™ã®ã‚ˆã†ãªHTMLフォームã¨JavaScriptをサãƒãƒ¼ãƒˆã™ã‚‹ãƒ–ラウザãŒå¿…è¦ã§ã™ã€‚Navigatorã®å…¥æ‰‹æ–¹æ³•ã«ã¤ã„ã¦ã¯<A HREF="http://home.netscape.com">Netscape
+ã®ãƒ›ãƒ¼ãƒ ãƒšãƒ¼ã‚¸</A>ã‚’ã”覧ãã ã•ã„。
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/ja/authtitle.html b/ldap/clients/dsgw/html/ja/authtitle.html
new file mode 100644
index 00000000..577fc94f
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/authtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="標準検索"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="拡張検索"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="æ–°è¦ã‚¨ãƒ³ãƒˆãƒª"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="èªè¨¼"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/ja/back.gif b/ldap/clients/dsgw/html/ja/back.gif
new file mode 100644
index 00000000..31080b38
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/back.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/back1.gif b/ldap/clients/dsgw/html/ja/back1.gif
new file mode 100644
index 00000000..c63d5bef
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/back1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/content.gif b/ldap/clients/dsgw/html/ja/content.gif
new file mode 100644
index 00000000..ca1149f3
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/content.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/content1.gif b/ldap/clients/dsgw/html/ja/content1.gif
new file mode 100644
index 00000000..fcd29c19
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/content1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/csearchtitle.html b/ldap/clients/dsgw/html/ja/csearchtitle.html
new file mode 100644
index 00000000..a3fda592
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/csearchtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="標準検索"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="拡張検索"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="æ–°è¦ã‚¨ãƒ³ãƒˆãƒª"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="èªè¨¼"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/ja/eduser.html b/ldap/clients/dsgw/html/ja/eduser.html
new file mode 100644
index 00000000..2b07c3ec
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/eduser.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD><TITLE>ユーザ管ç†</TITLE></HEAD>
+<HTML><BODY bgcolor="#C0C0C0" link="#0000EE" vlink="#551A8B" alink="#FF0000">
+
+<center><table border=2 width=100%%>
+<tr><td align=center width=100%><hr size=0 width=0><FONT size=+2><b>ユーザã®ç·¨é›†</b></FONT><hr size=0 width=0></th></tr></table></center>
+
+<form method="POST" action=dosearch name=eduserform>
+<input type=hidden name=mode value="smart">
+<input type=hidden name=type value="people">
+<input type=hidden name=editable value="true">
+<!-- PCONTEXT -->
+
+<b>次ã®åå‰ã®ãƒ¦ãƒ¼ã‚¶ã‚’編集: </b><INPUT type="text" name="searchstring" value="" size=20>
+</pre>
+<p>
+
+<center><table border=2 width=100%>
+<tr>
+<td width=33% align=center><input type=submit value="ユーザã®ç·¨é›†"></td>
+<td width=34% align=center><input type=reset value="リセット"></td>
+<td width=33% align=center><input type=button value=" ヘルプ " onclick="var hwin=window.open('', 'infowin_httpd',
+'resizable=1,width=400,height=500');if(top.helpwin==1) hwin.frames[1].location='http://ggood:2001/httpd-ggood/bin/tutor?!usradd&<!-- GCONTEXT -->';else { hwin.location='http://ggood:2001/httpd-ggood/bin/tutor?usradd&<!-- GCONTEXT -->'; hwin.rwin=top; hwin.rwin.helpwin=1; }"></td>
+</tr></table></center>
+</form>
diff --git a/ldap/clients/dsgw/html/ja/exit1.gif b/ldap/clients/dsgw/html/ja/exit1.gif
new file mode 100644
index 00000000..cd41fa17
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/exit1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/forward1.gif b/ldap/clients/dsgw/html/ja/forward1.gif
new file mode 100644
index 00000000..873ccc33
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/forward1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/greeting.html b/ldap/clients/dsgw/html/ja/greeting.html
new file mode 100644
index 00000000..0e75618a
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/greeting.html
@@ -0,0 +1,65 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript browsers
+function gotoURL(h) {
+ top.location.href = h;
+}
+// End hiding -->
+</SCRIPT>
+</HEAD>
+<BODY BGCOLOR="white">
+<HR>
+<CENTER>
+<FONT SIZE="+2">Netscape Directory Server Gateway ã«ã‚ˆã†ã“ã</FONT>
+</CENTER>
+<P>
+ã“ã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã¯ã€Netscape Directory Server ã«ä¿å­˜ã•ã‚Œã¦ã„るエントリã®æ¤œç´¢ã€å¤‰æ›´ã€ãŠã‚ˆã³ä½œæˆã«ä½¿ç”¨ã§ãã¾ã™ã€‚
+<P>
+Directory Server Gateway ã®ã”使用中ã¯ã€ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ä¸Šéƒ¨ã®ãƒ„ールãƒãƒ¼ã‚’ã„ã¤ã§ã‚‚ã”利用ã„ãŸã ã‘ã¾ã™ã€‚ ボタンをクリックã™ã‚Œã°ä»¥ä¸‹ã®ã‚¿ã‚¹ã‚¯ã‚’実行ã§ãã¾ã™ã€‚
+<P>
+<TABLE BORDER=1>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top">標準検索</A>
+</TH>
+<TD>
+[標準検索]ã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªæ¤œç´¢ã®æœ€ã‚‚ç°¡å˜ãªæ–¹æ³•ã§ã™ã€‚ ユーザã®å…¥åŠ›ã«åŸºã¥ã„ã¦ã€1ã¤ä»¥ä¸Šã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªæ¤œç´¢æ–¹æ³•ãŒè‡ªå‹•çš„ã«é¸æŠžã•ã‚Œã¾ã™ã€‚
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top">拡張検索</A>
+</TH>
+<TD>
+[拡張検索]を使用ã™ã‚‹ã¨ã€æ¤œç´¢å¯¾è±¡ã€æ¤œç´¢å±žæ€§ã€ãŠã‚ˆã³ä¸€è‡´ã‚¿ã‚¤ãƒ—を指定ã§ãã¾ã™ã€‚
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top">æ–°è¦ã‚¨ãƒ³ãƒˆãƒª</A>
+</TH>
+<TD>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]ã§ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã‚’作æˆã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ システム管ç†è€…ã«ã‚ˆã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®è¨­å®šæ–¹æ³•ã«ã‚ˆã£ã¦ã¯ã€æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹ã®ã«ç‰¹åˆ¥ãªè¨±å¯ã‚’æŒã£ã¦ã„ãªã‘ã‚Œã°ãªã‚‰ãªã„ã“ã¨ã‚‚ã‚ã‚Šã¾ã™ã€‚ ä¸æ˜Žã®å ´åˆã¯ã€ã‚·ã‚¹ãƒ†ãƒ ç®¡ç†è€…ã«ãŠå°‹ã­ãã ã•ã„。
+</TD>
+</TR>
+<TR>
+<TH>
+<A HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top">èªè¨¼</A>
+</TH>
+<TD>
+ディレクトリã«ãƒ­ã‚°ã‚¤ãƒ³ã¾ãŸã¯ãƒ­ã‚°ã‚¢ã‚¦ãƒˆã™ã‚‹ã«ã¯èªè¨¼ç”»é¢ã‚’使用ã—ã¾ã™ã€‚ ディレクトリã®å¤‰æ›´ã¾ãŸã¯ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ã‚’è¡Œã†å‰ã«ã¯èªè¨¼ãŒå¿…è¦ã§ã™ã€‚ システム管ç†è€…ãŒç¾©å‹™ä»˜ã‘ã¦ã„ã‚‹å ´åˆã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªæ¤œç´¢ã®å‰ã«ã‚‚èªè¨¼ãŒå¿…è¦ãªå ´åˆãŒã‚ã‚Šã¾ã™ã€‚
+</TD>
+</TR>
+</TABLE>
+</BODY>
+</HTML>
+
+
diff --git a/ldap/clients/dsgw/html/ja/index.html b/ldap/clients/dsgw/html/ja/index.html
new file mode 100644
index 00000000..2b7ad78d
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/index.html
@@ -0,0 +1,20 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server Gateway</TITLE>
+</HEAD>
+<FRAMESET ROWS=100,*>
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=maintitle.html" NAME="buttonBarFrame" NORESIZE
+ SCROLLING="no">
+ <FRAME SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=greeting.html" NAME="greetingFrame" NORESIZE>
+</FRAMESET>
+<NOFRAMES>
+<H3>フレーム機能をサãƒãƒ¼ãƒˆã™ã‚‹ãƒ–ラウザãŒå¿…è¦ã§ã™</H3>
+Netscape Directory Server Gatewayを使用ã™ã‚‹ã«ã¯ã€Netscape Navigatorパージョン3以é™ã®ã‚ˆã†ãªHTMLフォームã¨JavaScriptをサãƒãƒ¼ãƒˆã™ã‚‹ãƒ–ラウザãŒå¿…è¦ã§ã™ã€‚Navigatorã®å…¥æ‰‹æ–¹æ³•ã«ã¤ã„ã¦ã¯<A HREF="http://home.netscape.com">Netscapeã®ãƒ›ãƒ¼ãƒ ãƒšãƒ¼ã‚¸</A>ã‚’ã”覧ãã ã•ã„。
+</NOFRAMES>
+</HTML>
diff --git a/ldap/clients/dsgw/html/ja/index1.gif b/ldap/clients/dsgw/html/ja/index1.gif
new file mode 100644
index 00000000..514f57ed
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/index1.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/maintitle.html b/ldap/clients/dsgw/html/ja/maintitle.html
new file mode 100644
index 00000000..4e10147c
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/maintitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="標準検索"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="拡張検索"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="æ–°è¦ã‚¨ãƒ³ãƒˆãƒª"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="èªè¨¼"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/ja/newentry_off.gif b/ldap/clients/dsgw/html/ja/newentry_off.gif
new file mode 100644
index 00000000..cb8553d4
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/newentry_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/newentry_on.gif b/ldap/clients/dsgw/html/ja/newentry_on.gif
new file mode 100644
index 00000000..c8ca4505
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/newentry_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/newentrytitle.html b/ldap/clients/dsgw/html/ja/newentrytitle.html
new file mode 100644
index 00000000..8f215293
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/newentrytitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="標準検索"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="拡張検索"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="æ–°è¦ã‚¨ãƒ³ãƒˆãƒª"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="èªè¨¼"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/ja/searchtitle.html b/ldap/clients/dsgw/html/ja/searchtitle.html
new file mode 100644
index 00000000..e06d4b34
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/searchtitle.html
@@ -0,0 +1,37 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#ffffff" TEXT="#000000">
+
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=title.gif" HEIGHT=40 WIDTH=530 BORDER="0"
+ ALT="Netscape Directory Server"><BR>
+
+<!-- note: do not include any newlines or other whitespace between the tags -->
+<!-- below that enclose images because this leads to blank pixels -->
+<!-- between them (which we do not want). -->
+
+<IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=blank.gif" WIDTH=42 HEIGHT=24 BORDER="0"><A
+ HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=stsearch_on.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="標準検索"></A><A
+ HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=adsearch_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="拡張検索"></A><A
+ HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=newentry_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="æ–°è¦ã‚¨ãƒ³ãƒˆãƒª"></A><A
+ HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html" TARGET="_top"><IMG
+ SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=authen_off.gif" WIDTH=122 HEIGHT=24 BORDER="0"
+ ALT="èªè¨¼"></A>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/ja/stsearch_off.gif b/ldap/clients/dsgw/html/ja/stsearch_off.gif
new file mode 100644
index 00000000..4238e2f6
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/stsearch_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/stsearch_on.gif b/ldap/clients/dsgw/html/ja/stsearch_on.gif
new file mode 100644
index 00000000..b1b77861
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/stsearch_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/ja/title.gif b/ldap/clients/dsgw/html/ja/title.gif
new file mode 100644
index 00000000..155ae7df
--- /dev/null
+++ b/ldap/clients/dsgw/html/ja/title.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/left_bottom.gif b/ldap/clients/dsgw/html/left_bottom.gif
new file mode 100644
index 00000000..bbd159ca
--- /dev/null
+++ b/ldap/clients/dsgw/html/left_bottom.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/left_off.gif b/ldap/clients/dsgw/html/left_off.gif
new file mode 100644
index 00000000..041754a7
--- /dev/null
+++ b/ldap/clients/dsgw/html/left_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/left_on.gif b/ldap/clients/dsgw/html/left_on.gif
new file mode 100644
index 00000000..079675ca
--- /dev/null
+++ b/ldap/clients/dsgw/html/left_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/maintitle.html b/ldap/clients/dsgw/html/maintitle.html
new file mode 100644
index 00000000..5b5fee78
--- /dev/null
+++ b/ldap/clients/dsgw/html/maintitle.html
@@ -0,0 +1,152 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<body bgcolor="#FFFFFF" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0">
+
+<TABLE width="100%" cellspacing="0" cellpadding="0" border="0" class="bgColor4">
+ <TR>
+ <TD>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td colspan="4"><img border="0" height="10" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td><a href="http://www.netscape.com"><img border="0" height="19" width="19" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=netscape.gif"></a></td>
+ <td><img border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true" align=left width="100%" class="appName">Netscape Directory Server Gateway</td>
+ </tr>
+ <tr>
+ <td colspan="4"><img border="0" height="12" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ </table>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Standard Search'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Standard Search" ALT="Standard Search">Standard Search</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Advanced Search'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Advanced Search" ALT="Advanced Search">Advanced Search</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='New Entry'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="New Entry" ALT="New Entry">New Entry</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html"
+ TARGET="_top" onMouseOver="self.status='Authentication'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Authentication" ALT="Authentication">Authentication</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+
+ <td width="100%"><img border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </TR>
+ <TR>
+ <TD class="bgRegTab" colspan="9"><IMG border="0" height="1" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ <TABLE class="bgAtTab" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <TR>
+ <TD>
+ <IMG border="0" height="43" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </TD>
+ </TR>
+ <TR>
+ <TD class="bgRegTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ <TR>
+ <TD class="bgDarkRule"><IMG border="0" height="2" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/manual/Makefile b/ldap/clients/dsgw/html/manual/Makefile
new file mode 100644
index 00000000..c8fb1a05
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/Makefile
@@ -0,0 +1,56 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# Gmakefile for Directory Server Gateway manual files.
+#
+
+LDAP_SRC = ../../../..
+MCOM_ROOT = ../../../../../..
+
+NOSTDSTRIP=true # don't let nsconfig.mak define target strip
+NOSTDCLEAN=true # don't let nsconfig.mak define target clean
+NOSTDDEPEND=true # don't let nsconfig.mak define target depend
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+include ../../dsgw_include.mk
+
+HTMLDEST = $(DSGW_MAN_RELDIR)
+
+HTML = a.gif add.htm attribua.gif attribut.htm auth.htm \
+ contents.html intro.htm mod.htm n.gif \
+ objclass.htm search.htm t.gif y.gif index.map
+
+BINS=$(addprefix $(HTMLDEST)/,$(HTML))
+
+ifeq ($(ARCH), WINNT)
+CP2=cmd /c 'sh ../../../../cm/nbsp2utf8.sh $< >'
+else
+CP2=sh ../../../../cm/nbsp2utf8.sh $< >
+endif
+
+all: $(HTMLDEST) $(BINS)
+install: $(HTMLDEST) $(BINS)
+
+clean:
+ $(RM) $(BINS)
+
+$(HTMLDEST)/%.map: %.map
+ @-$(RM) $@
+ cp $< $@
+
+$(HTMLDEST)/%.gif: %.gif
+ @-$(RM) $@
+ cp $< $@
+
+$(HTMLDEST)/%: %
+ -@$(RM) $@
+ $(CP2) $@
+
+strip:
+depend:
diff --git a/ldap/clients/dsgw/html/manual/a.gif b/ldap/clients/dsgw/html/manual/a.gif
new file mode 100644
index 00000000..1a19dba4
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/a.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/manual/add.htm b/ldap/clients/dsgw/html/manual/add.htm
new file mode 100644
index 00000000..8aa9fb7e
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/add.htm
@@ -0,0 +1,681 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Adding Directory Entries
+</TITLE></HEAD>
+<BODY>
+
+<H1>
+<A NAME="adding"></A>Adding Entries</H1>
+You can add new entries to the directory
+using the Directory Server interface. To add
+entries, your Directory Server administrator must have granted you the right
+to do so. Before you can add an entry, you must <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A>
+to the Directory Server.
+
+<P>Using the Directory Server interface you can add:
+<UL>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#person">a person</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#NTperson">an NT person</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#group">a group</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#NTgroup">an NT group</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#ou">an organizational unit</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#dc">a domain</A></LI>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#o">an organization</A></LI>
+</UL>
+Before you add an entry for the first time, read the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#guidelines">New
+Entry Guidelines</A> section for important information about the directory
+tree structure and naming conventions.
+<H2>
+<A NAME="guidelines"></A>New Entry Guidelines</H2>
+Before you begin adding entries to the directory, make sure that you understand
+the following directory concepts:
+<UL>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#tree">directory tree structure</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#DN">distinguished name syntax</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#uniqueDN">unique distinguished names</A></LI>
+</UL>
+
+<H3>
+<A NAME="tree"></A>Directory Tree Structure</H3>
+Data in the directory is arranged in a tree hierarchy. The top of the tree
+is known as the root or suffix. The root entry usually represents the
+organization entry for the directory.
+
+<BLOCKQUOTE><B>Note:</B>
+<P>
+
+Although your directory may contain more than one suffix, the directory
+server interface only allows you to search for, add, and edit entries in
+a single suffix. Make sure that you know which suffix your Directory Server
+interface is supporting before adding new entries.
+</BLOCKQUOTE>
+
+
+<P>Below the root are branches of the tree, which usually represent organizational
+units such as marketing or accounting. Entries for people and resources
+within your organization are usually contained below these organizational
+unit branches within the directory tree structure.
+
+<P>When you add an entry, make sure that an entry representing a branch
+point is created before new entries are created under that branch. For
+example, if you want to place entries in a Marketing subtree and in an
+Accounting subtree, then create the branch point for those subtrees before
+creating entries within the subtrees:
+
+<PRE>          o=Example.com
+          ou=Marketing, o=Example.com
+          ...
+          <I>Marketing subtree entries</I>
+          ...
+          ou=Accounting, o=Example.com
+          ...
+          <I>Accounting subtree entries</I>
+</PRE>
+
+<H3>
+<A NAME="DN"></A>Distinguished Name Syntax</H3>
+An entry is uniquely identified within the Directory Server through the
+use of a distinguished name (DN). A DN identifies the entry by using a
+series of comma-separated attributes and attribute values. The left-most
+value in the DN represents the entry's name, with each subsequent
+attribute representing a branch point above the entry. For example:
+
+<PRE>uid=bjensen, ou=people, o=example.com</PRE>
+
+This DN represents the entry named <I>bjensen</I> in the subdirectory named
+<I>people</I> in the directory named <I>example.com</I>.
+
+<P>When you add a new entry to the Directory Server, you are prompted
+to enter the complete distinguished name.
+<H3><A NAME="uniqueDN"></A>Unique Distinguished Names</H3>
+
+The Directory Server interface does not allow you to create a duplicate
+entry. To avoid naming duplications, use distinguished names that begin
+with the person's user ID (uid) rather than the person's common name (CN).
+Choose user IDs that are readable; that is,
+do not use a random collection of letters and numbers for
+user IDs. If your enterprise already has an email system, one possibility
+would be to use the left-most value of each person's email address as that
+person's user ID. For example, if a person has the email address:
+
+<P>bjensen@example.com
+
+<P>then give that person's directory entry the following DN:
+
+<P>uid=bjensen, o=example.com
+
+<H2><A NAME="person"></A>Adding a Person</H2>
+
+To add a new person entry, do the following:
+<OL>
+<LI>
+Click the New Entry tab.</LI>
+
+<LI>
+Follow the steps outlined in the New Entry form. When you are done
+filling in this form, click Continue. To cancel the operation click
+the Back button in your browser window.</LI>
+
+<LI>
+If you have not authenticated before you attempt to add a new entry, or
+if your authentication has expired, the Directory Server prompts you
+to <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+When you add a person to the directory, a form that
+allows you to edit that person's data is displayed. This form is displayed in
+a new web browser window. You must supply values for the required fields.
+The required fields for a person are:</LI>
+
+<UL type="disc">
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">Full Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#surname">Last Name</A></LI>
+</UL>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for a person are:</LI>
+ 
+<P>
+<CENTER><TABLE BORDER=2 >
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#givenName">First Name</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone</A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#mail">Email Address</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#facsimileTelephoneNumber">Fax</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#uid">User ID</A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#pager">Pager</A></TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#mobile">Mobile Phone</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#title">Title</A></TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ou">Organizational Unit</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#manager">Manager</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#roomNumber">Room Number </A></TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#secretary">Admin </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#departmentNumber">Dept# </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#employeeNumber">Emp#</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#carLicnese">Car License# </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#labeledUri">URL </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#userPassword">Password</A> </TD>
+</TR>
+</TABLE>
+</CENTER>
+<BLOCKQUOTE><B>Note:</B>
+<P>
+You cannot enter values into the Manager, Admin,
+or See Also fields until you have saved the entry. Furthermore, changing uid in the New Entry screen will result in a multi-valued uid with the value selected in the first screen as the naming component.</BLOCKQUOTE>
+
+<LI>
+To cancel the entry creation, close the web browser window containing
+the form. When you are done filling in the form, click the Save New
+Person button at the top of the form.</LI>
+
+<LI>
+After saving the entry, you can <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addmanager">add values
+to the Manager and Admin fields</A> or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addowner">add
+a See Also value</A>.</LI>
+</OL>
+
+<H2>
+<A NAME="NTperson"></A>Adding an NT Person</H2>
+When creating an NT-person entry, make sure that the subtree
+in which you place the entry is the same subtree that the synchronization service
+uses to synchronize entries. If you place an NT-person entry into another
+location, it is not synchronized with the Windows network.
+
+<P>To add a new NT-person entry, do the following:
+<OL>
+<LI>
+Click the New Entry tab.</LI>
+
+<LI>
+Follow the steps outlined in the New Entry form. When you are done
+filling in this form, click Continue. To cancel the operation click
+the Back button in your browser window.</LI>
+
+<LI>
+If you have not authenticated before you attempt to add a new entry, or
+if your authentication has expired, the Directory Server prompts you
+to <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+When you add an NT-person to the directory, a form that allows you to
+edit that person's data is displayed. This form is displayed
+in a new web browser window. You must supply values for the required fields.
+The required fields for an NT-person are:</LI>
+
+<UL type="disc">
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#commonName">Full Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#surname">Last Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntUserDomainId">NT Domain Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#uid">NT User ID</A></LI>
+</UL>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for a person are:</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#givenName">First Name</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#mail">Email Address</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#fax">Fax </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#userPassword">Directory Server Password</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#pager">Pager</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#mobile">Mobile Phone</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#title">Title</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#organizationalUnitName">Organizational Unit</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#manager">Manager</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#roomNumber">Room Number</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#secretary">Admin </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#departmentNumber">Dept#</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#employeeNumber">Emp#</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#carLicnese">Car License#</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#labeledURI">URL</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#userid">User Id</A></TD>
+</TR>
+</TABLE></CENTER>
+<BLOCKQUOTE><B>Note:</B>
+<P>
+You cannot enter values into the Manager, Admin,
+or See Also fields until you have saved the entry.
+</BLOCKQUOTE>
+
+<LI>
+You can also change the value for the following two options:</LI>
+
+<UL type="disc">
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#NTUserDelete">Delete NT Account if Person deleted</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#NTUserCreateNewAccount">Create New NT Account</A></LI>
+</UL>
+The default value is shown. If you do not change the value,
+the default value is used.
+<LI>
+When you are done filling in the form, click the Save New NT Person
+button at the top of the form. To cancel the entry creation,
+close the web browser window containing the form.</LI>
+
+<LI>
+After saving the entry, you can <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addmanager">add values
+to the Manager and Admin fields</A> or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addowner">add
+a "See Also" value</A>.</LI>
+</OL>
+
+<H2>
+<A NAME="group"></A>Adding a Group</H2>
+To add a new group entry, do the following:
+<OL>
+<LI>
+Click the New Entry tab.</LI>
+
+<LI>
+Follow the steps outlined in the New Entry form. When you are done
+filling in this form, click Continue. To cancel the operation click
+the Back button in your browser window.</LI>
+
+<LI>
+If you have not authenticated before you attempt to add a new entry, or
+if your authentication has expired, the Directory Server prompts you
+to <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+When you add a group to the directory, a form that
+allows you to edit that group's data is displayed. This form is displayed in
+a new web browser window. You must supply a value for the required field
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">Name</A>.</LI>
+
+<LI>
+You can provide a value for the optional <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A>
+field now, or add it later.</LI>
+
+<BLOCKQUOTE><B>Note:</B>
+<P>
+You cannot enter values into the Owner, Group Members,
+or See Also fields until you have saved the entry.</BLOCKQUOTE>
+
+<LI>
+When you are done filling in the form, click the Save New Group button
+at the top of the form.</LI>
+
+<BR>To cancel the entry creation, close the web browser window containing
+the form.
+<LI>
+After you have saved the entry, you can <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addowner">add
+values for the Owner, Group Member, and See Also fields</A>.</LI>
+</OL>
+
+<H2>
+<A NAME="NTgroup"></A>Adding an NT Group</H2>
+To add a new NT group entry, do the following:
+<OL>
+<LI>
+Click the New Entry tab.</LI>
+
+<LI>
+Follow the steps outlined in the New Entry form. When you are done
+filling in this form, click Continue. To cancel the operation click
+the Back button in your browser window.</LI>
+
+<LI>
+If you have not authenticated before you attempt to add a new entry, or
+if your authentication has expired, the Directory Server prompts you
+to <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+When you add an NT-group to the directory, a form
+that allows you to edit that group's data is displayed. This form is contained
+in a new web browser window. You must supply a value for the required fields.
+The required fields for an NT-group are:</LI>
+
+<UL type="disc">
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntGroupId">NT Group Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntGroupType">NT Group Type</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntGroupDomainId">NT Group Domain</A></LI>
+</UL>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for an NT group are:</LI>
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#owner">Owner</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#l">Locale</A></TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#uniqueMember">NT Group Members</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ou">Organizational Unit</A></TD>
+</TR>
+</TABLE>
+</CENTER>
+<P>
+<BLOCKQUOTE><B>Note:</B>
+<P>
+You cannot enter values into the Owner, NT Group Members,
+or See Also fields until you have saved the entry.</BLOCKQUOTE>
+
+<LI>
+You may also change the value for the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#NTGroupDelete">Delete NT Group if Group Deleted</A> option.</LI>
+
+<LI>
+When you are done filling in the form, click the Save New Group button
+at the top of the form.</LI>
+
+<BR>To cancel the entry creation, close the web browser window containing
+the form.
+<LI>
+After you save the entry, you can <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addowner">add values
+for the NT Group Members, Owner, and See Also fields</A>.</LI>
+</OL>
+
+<H2>
+<A NAME="ou"></A>Adding an Organizational Unit</H2>
+To add a new organizational unit entry, do the following:
+<OL>
+<LI>
+Click the New Entry tab.</LI>
+
+<LI>
+Follow the steps outlined in the New Entry form. When you are done
+filling in this form, click Continue. To cancel the operation click
+the "Back" button in your browser window.</LI>
+
+<LI>
+If you have not authenticated before you attempt to add a new entry, or
+if your authentication has expired, the Directory Server prompts you
+to <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+When you add an organizational unit to the directory, a form that
+allows you to edit that organization's data is displayed. This
+form is displayed in a new web browser window. You must supply
+a value for the required field, <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ou">Unit Name</A>.</LI>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for an organizational unit are:</LI>
+<P>
+<CENTER><TABLE BORDER=2 >
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#fax">Fax</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#localityName">Location</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A> </TD>
+
+<TD> </TD>
+
+<TD> </TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+When you are done filling in the form, click the Save New Org. Unit
+button at the top of the form. To cancel the entry creation, close
+the web browser window containing the form.</LI>
+</OL>
+
+<H2><A NAME="dc"></A>Adding a Domain Component</H2>
+
+To add a new domain entry, do the following:
+<OL>
+<LI>
+Click the New Entry tab.</LI>
+
+<LI>
+Follow the steps outlined in the New Entry form. When you are done
+filling in this form, click Continue. To cancel the operation click
+the Back button in your browser window.</LI>
+
+<LI>
+If you have not authenticated before you attempt to add a new entry, or
+if your authentication has expired, the Directory Server prompts you
+to <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+You must supply a value for the required field, <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#dc">dc</A>.</LI>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for a domain are:</LI>
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A></TD>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone</A></TD>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A></TD></TR>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#fax">Fax</A></TD>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#localityName">Location</A></TD>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address</A></TD></TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD></TR>
+</TABLE>
+</CENTER>
+<P>
+<LI>
+When you are done filling in the form, click the Save New dc button
+at the top of the form. To cancel the entry creation, close the
+web browser window containing the form.</LI>
+</OL>
+
+<H2><A NAME="o"></A>Adding an Organization</H2>
+
+To add a new organization entry, do the following:
+<OL>
+<LI>
+Click the New Entry tab.</LI>
+
+<LI>
+Follow the steps outlined in the New Entry form. When you are done
+filling in this form, click Continue. To cancel the operation click
+the Back button in your browser window.</LI>
+
+<LI>
+If you have not authenticated before you attempt to add a new entry, or
+if your authentication has expired, the Directory Server prompts you
+to <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+Adding an organization is supported only when you initially populate your
+directory tree. The organization you add must match the organization
+you specified in the Database Subtree field when you installed your
+Directory Server. For example, if you specified a value of:</LI>
+
+<PRE>o=Example.com</PRE>
+
+to the Database Subtree field, then you must specify a value of:
+
+<PRE>o=Example.com</PRE>
+
+when you add the organization. The Directory Server checks the add operation to ensure that the directory entry can
+exist with the database subtree. Any value other than:
+
+<PRE>o=Example.com</PRE>
+
+clearly cannot reside under:
+
+<PRE>o=Example.com</PRE>
+
+As a result, the Directory Server rejects the operation.
+<LI>
+You must supply a value for the required field, <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#organizationName">Organization Name</A>.</LI>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for an organization are:</LI>
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#fax">Fax</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#localityName">Location</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A> </TD>
+
+<TD> </TD>
+
+<TD> </TD>
+</TR>
+</TABLE>
+</CENTER>
+<P>
+<LI>
+When you are done filling in the form, click the Save New Org. button
+at the top of the form. To cancel the entry creation, close the
+web browser window containing the form.</LI>
+</OL>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/manual/attribua.gif b/ldap/clients/dsgw/html/manual/attribua.gif
new file mode 100644
index 00000000..8ec4a9eb
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/attribua.gif
@@ -0,0 +1,103 @@
+%-12345X@PJL SET RESOLUTION = 600
+@PJL ENTER LANGUAGE=POSTSCRIPT
+%!PS-Adobe-3.0
+%%Title: Untitled Document
+%%Creator: Windows NT 3.5
+%%CreationDate: 12:32 11/5/1996
+%%Pages: (atend)
+%%BoundingBox: 12 12 599 780
+%%EndComments
+%%BeginProcSet: NTPSOct94
+% Copyright (c) 1991 - 1994 Microsoft Corporation
+/NTPSOct94 100 dict dup begin
+/bd{bind def}bind def/ld{load def}bd/ed{exch def}bd/a/currentpoint ld
+/c{curveto}bd/d/dup ld/e/eofill ld/f/fill ld/tr/translate ld
+/g/setgray ld/gr/grestore ld/gs/gsave ld/j/setlinejoin ld
+/L{lineto}bd/M{moveto}bd/n/newpath ld/cp/closepath ld
+/rlt/rlineto ld/rm/rmoveto ld/sl/setlinewidth ld/sd/setdash ld
+/r/setrgbcolor ld/s/stroke ld/t/show ld/aw/awidthshow ld/im/imagemask ld
+/SF{findfont exch scalefont setfont}bd/SM{cmtx setmatrix}bd
+/MF{findfont exch makefont setfont}bd/CM{/cmtx matrix currentmatrix def}bd
+/B {M exch dup 0 rlt exch 0 exch rlt neg 0 rlt} bd
+/CB {B cp eoclip} bd
+/EA {1 index 0 /G0 put 4 string 1 1 4 -1 roll
+ {3 copy neg exch cvs dup 0 71 put cvn 3 -1 roll exch put} for pop} bd
+ end def
+%%EndProcSet
+%%EndProlog
+%%BeginSetup
+mark {
+%%BeginFeature: *PageSize Letter
+ <</DeferredMediaSelection true /PageSize [612 792] /ImagingBBox null>> setpagedevice
+%%EndFeature
+} stopped cleartomark
+/#copies 1 def
+%%EndSetup
+NTPSOct94 begin
+%%Page: 1 1
+/PageSV save def
+12 780 translate 72 600 div dup neg scale
+0 0 transform .25 add round .25 sub exch .25 add round .25 sub exch itransform translate
+% Copyright (c) 1986-1995 Frame Technology Corporation.
+/FMcmyk 100 dict def
+/FmBD{bind def}bind def
+/FmLD{load def}FmBD
+/FMc {
+ FMcmyk length FMcmyk maxlength ge { /FMcmyk FMcmyk dup length dup add dict copy def } if
+ 4 array astore 4 1 roll 8 bitshift add 8 bitshift add exch FMcmyk 3 1 roll put
+}FmBD
+/setcmykcolor where { pop
+ /sc where { pop /sc load 0 get /scignore eq {
+ /FMsc /sc FmLD
+ /sc { 3 copy 8 bitshift add 8 bitshift add FMcmyk 1 index known
+ { FMcmyk exch get aload pop setcmykcolor pop pop pop } { pop FMsc } ifelse
+ }FmBD
+ } if } if
+} if
+mark { /S load
+ dup 0 get /PenW eq { dup 1 get /sl load eq {
+ dup 0 { PenW .75 sub sl } bind put 1 /exec load put
+ } if } if
+} stopped cleartomark
+/FmX matrix defaultmatrix def
+/FmDC {transform FmX itransform cvi exch cvi exch} def
+/FmBx { dup 3 index lt {3 1 roll exch} if
+ 1 index 4 index lt {4 -1 roll 3 1 roll exch 4 1 roll} if
+}FmBD
+/FmPD/cleartomark FmLD
+/FmPD2/cleartomark FmLD
+/FmPT/pop FmLD
+/FmPA{pop pop pop}FmBD
+systemdict /pdfmark known {
+ /FmPD/pdfmark FmLD
+ currentdistillerparams /CoreDistVersion get 2000 ge {
+ /FmPD2/pdfmark FmLD
+ /FmPA { mark exch /Dest exch 5 3 roll
+ /View [ /XYZ null 6 -2 roll FmDC exch pop null] /DEST FmPD
+ }FmBD
+ } if
+} if
+0 0 0 0.0 0.0 0.0 1.0 FMc
+gs
+gs
+gs
+/s {} def /e {} def
+n
+-217 183 267 6167 B
+cp
+s
+/s /stroke ld /e /eofill ld
+eoclip
+[250 0 0 -250 0 0] /Times-Bold MF
+50 6333 M
+(T)t
+gr
+gr
+gr
+showpage
+PageSV restore
+%%Trailer
+end
+%%Pages: 1
+%%EOF
+%-12345X \ No newline at end of file
diff --git a/ldap/clients/dsgw/html/manual/attribut.htm b/ldap/clients/dsgw/html/manual/attribut.htm
new file mode 100644
index 00000000..da1bc9e8
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/attribut.htm
@@ -0,0 +1,6712 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<A NAME="996822">
+<P>
+</A><A NAME="997293">
+<P>
+</A><A NAME="1002619">
+<H1>Attributes
+</H1>
+</A>
+
+<A NAME="996830">
+<br>
+This appendix includes information on attribute definitions. Most of the schema attributes used in the Directory Server are part of the standard LDAP protocol, which is in turn based on the X.500 standard. However, some of the Directory Server's attributes are extensions created by Netscape for use with its implementation of LDAP. If an attribute was created by Netscape and is not part of the standard LDAP schema, a note is made in the description of that object or attribute.<P></A>
+
+<A NAME="1071459">
+For information on what the Directory Server schema is and what it is used for, refer to the <i>Netscape Directory Server Deployment Guide</i>.<P></A>
+
+<A NAME="1078428">
+For information on the object classes in the schema, see <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1002619">Appendix A, "Object Classes."</a><P></A>
+
+
+<A NAME="1020843"> 
+</A>
+<A NAME="Attribute Definitions">
+<H2> Attribute Definitions</H2>
+</A>
+
+<A NAME="1004519">
+The following define the attributes used to describe an entry in the directory tree. To determine which attributes are required and allowed for each object class, see <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1002619">Appendix A, "Object Classes."</a><P></A>
+
+<A NAME="1004699">
+Each attribute has a corresponding syntax definition that describes the nature of the attribute information. This syntax is important only when the Directory Server is performing sorting and pattern matching; there is nothing to otherwise prevent you from, for example, placing a telephone number on an attribute that expects a distinguished name.<P></A>
+
+<A NAME="1067002">
+The possible attribute syntaxes are:<P></A>
+<ul><A NAME="1004700">
+<LI>bin -- binary.<P>
+</A>
+<A NAME="1004701">
+<LI>ces -- case exact string (case must be matched during comparison).<P>
+</A>
+<A NAME="1004702">
+<LI>cis -- case ignore string (case is ignored during comparison).<P>
+</A>
+<A NAME="1004703">
+<LI>tel -- telephone number (identical to cis, but blanks and dashes (-) are ignored during comparisons).<P>
+</A>
+<A NAME="1004704">
+<LI>dn -- distinguished name.<P>
+</A>
+<A NAME="1243260">
+<LI>int -- integer.<P>
+</A>
+<A NAME="1251525">
+<LI>operational -- for internal use only. Operational attributes are not displayed in search results.<P>
+</A>
+</ul>
+<A NAME="1201644">
+The base OID for the Netscape Directory Server is:<P></A>
+<PRE><A NAME="1255332">
+2.16.840.1.113730.3
+</A>
+</PRE>
+<A NAME="1257527">
+All Netscape defined attributes have the base:<P></A>
+<PRE><A NAME="1257537">
+2.16.840.1.113730.3.1
+</A>
+</PRE><A NAME="1255098">
+<A NAME="abstract">
+<B>abstract</B>
+</a></a>
+<P>
+
+
+<A NAME="1201645">
+Provides an abstract of a document entry.<P></A>
+
+<A NAME="1272899">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1104078">
+<A NAME="accountUnlockTime">
+<B>accountUnlockTime</B>
+</a></a>
+<P>
+
+
+<A NAME="1154996">
+Defines, in seconds, the time until a user's account is unlocked after a specified number of failed attempts to bind to the directory.<P></A>
+<PRE><A NAME="1154997">
+ accountUnlockTime: 600
+</A>
+</PRE>
+<A NAME="1259967">
+OID: <code>2.16.840.1.113730.3.1.95</code><P></A>
+
+<A NAME="1104080">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1171292">
+<A NAME="aci">
+<B>aci</B>
+</a></a>
+<P>
+
+
+<A NAME="1171293">
+Stores the Directory Server access control information for this entry. For example:<P></A>
+<PRE><A NAME="1171294">
+ aci: (target="ldap:///<I>o=Example.com</I>")(version 3.0;<br> acl "anonymous access"; allow (read, search, compare)<br> userdn=ldap:///self;)
+</A>
+</PRE>
+<A NAME="1258362">
+OID: <code>2.16.840.1.113730.3.1.55</code><P></A>
+
+<A NAME="1171296">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+
+<A NAME="1171297">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1032956">
+<A NAME="administratorContactInfo">
+<B>administratorContactInfo</B>
+</a></a>
+<P>
+
+
+<A NAME="1032957">
+Provides a URL to information about the person responsible for administering the Netscape server. This attribute is a Netscape extension used by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">netscapeServer</a> object class. Normally this attribute and this attribute value is written to the directory when a Netscape server is initially installed. For example:<P></A>
+<PRE><A NAME="1032959">
+ administratorContactInfo: ldap://<I>uid=ssarette, o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1259219">
+OID: <code>2.16.840.1.113730.3.1.74</code><P></A>
+
+<A NAME="1098446">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1098448">
+<A NAME="adminUrl">
+<B>adminUrl</B>
+</a></a>
+<P>
+
+
+<A NAME="1098449">
+Provides the URL to the administration server through which you can manage the Netscape server. This attribute is a Netscape extension used by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">netscapeServer</a> object class. Normally this attribute and this attribute value is written to the directory when a Netscape server is initially installed. For example:<P></A>
+<PRE><A NAME="1033050">
+ adminUrl: http://twain.example.com:2468
+</A>
+</PRE>
+<A NAME="1259252">
+OID: <code>2.16.840.1.113730.3.1.75</code><P></A>
+
+<A NAME="1033052">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1201653">
+<A NAME="aliasedObjectName">
+<B>aliasedObjectName</B>
+</a></a>
+<P>
+
+
+<A NAME="1206908">
+Used by the Directory Server to identify alias entries in the directory. The attribute contains the distinguished name of the entry for which it is an alias. For example:<P></A>
+<PRE><A NAME="1206909">
+ aliasedObjectName:<I> cn=jdoe, o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1266950">
+OID: <code>2.5.4.1</code><P></A>
+
+<A NAME="1206911">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1243116">
+<A NAME="altServer">
+<B>altServer</B>
+</a></a>
+<P>
+
+
+<A NAME="1243117">
+Undefined.<P></A>
+
+<A NAME="1263098">
+OID: <code>1.3.6.1.4.1.1466.101.120.6</code><P></A>
+
+<A NAME="1243120">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1201668">
+<A NAME="associatedDomain">
+<B>associatedDomain</B>
+</a></a>
+<P>
+
+
+<A NAME="1219687">
+Specifies a DNS domain associated with an object in the directory tree. For example, the entry in the directory tree with a distinguished name "C=US, O=Example Corporation" would have an associated domain of "AC.US. Note that all domains should be represented in rfc822 order. For example:<P></A>
+<PRE><A NAME="1201670">
+ associatedDomain: US
+</A>
+</PRE>
+<A NAME="1260172">
+OID: <code>0.9.2342.19200300.100.1.37</code><P></A>
+
+<A NAME="1201672">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201675">
+<A NAME="associatedName">
+<B>associatedName</B>
+</a></a>
+<P>
+
+
+<A NAME="1218672">
+Specifies an entry in the organizational directory tree associated with a DNS domain. For example:<P></A>
+<PRE><A NAME="1201677">
+ associatedName:<I> c=us</I>
+</A>
+</PRE>
+<A NAME="1266572">
+OID: <code>0.9.2342.19200300.100.1.38</code><P></A>
+
+<A NAME="1201679">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1290840">
+<A NAME="attributeTypes">
+<B>attributeTypes</B>
+</a></a>
+<P>
+
+
+<A NAME="1295396">
+Operational, multi-valued attribute that specifies the attribute types used within a subschema. Each value describes a single matching rule. <P></A>
+
+<A NAME="1263041">
+OID: <code>2.5.21.5</code><P></A>
+
+<A NAME="1242648">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1201684">
+<A NAME="audio">
+<B>audio</B>
+</a></a>
+<P>
+
+
+<A NAME="1209771">
+Contains a sound file in binary format. The attribute uses a u-law encoded sound file. For example:<P></A>
+<PRE><A NAME="1286498">
+ audio: AAAAAA==
+</A>
+</PRE>
+<A NAME="1266120">
+OID: <code>0.9.2342.19200300.100.1.55</code><P></A>
+
+<A NAME="1201686">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">Syntax: </a>bin<P></A>
+<A NAME="1201689">
+<A NAME="authorCn">
+<B>authorCn</B>
+</a></a>
+<P>
+
+
+<A NAME="1201690">
+Contains the common name of the author of a document entry. For example:<P></A>
+<PRE><A NAME="1201691">
+ authorCn: Kacey
+</A>
+</PRE>
+<A NAME="1272919">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201696">
+<A NAME="authorSn">
+<B>authorSn</B>
+</a></a>
+<P>
+
+
+<A NAME="1201697">
+Contains the surname of the author of a document entry. For example:<P></A>
+<PRE><A NAME="1201698">
+ authorSn: Doe
+</A>
+</PRE>
+<A NAME="1201700">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1207170">
+<A NAME="authorityRevocationList">
+<B>authorityRevocationList</B>
+</a></a>
+<P>
+
+
+<A NAME="1207172">
+Contains a text-encoded list of CA certificates that have been revoked. Not recommended; use authorityRevocationList;binary instead.<P></A>
+
+<A NAME="1207174">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">Syntax: </a>bin<P></A>
+<A NAME="1207178">
+<A NAME="authorityRevocationList;binary">
+<B>authorityRevocationList;binary</B>
+</a></a>
+<P>
+
+
+<A NAME="1207180">
+Contains a binary list of certification authority certificates that have been revoked. For example:<P></A>
+<PRE><A NAME="1286569">
+ authorityRevocationList: AAAAAA==
+</A>
+</PRE>
+<A NAME="1277412">
+OID: <code>2.5.4.38</code><P></A>
+
+<A NAME="1207182">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">Syntax: </a>bin<P></A>
+<A NAME="1201711">
+<A NAME="buildingName">
+<B>buildingName</B>
+</a></a>
+<P>
+
+
+<A NAME="1201712">
+Defines the building name associated with the entry. For example:<P></A>
+<PRE><A NAME="1201713">
+ buildingName: 14
+</A>
+</PRE>
+<A NAME="1266616">
+OID: <code>0.9.2342.19200300.100.1.48</code><P></A>
+
+<A NAME="1201715">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1171367">
+<A NAME="businessCategory">
+<B>businessCategory</B>
+</a></a>
+<P>
+
+
+<A NAME="1171368">
+Identifies the type of business in which the entry is engaged. This should be a broad generalization such as is made at the corporate division level. <P></A>
+
+<A NAME="1171369">
+For example:<P></A>
+<PRE><A NAME="1171370">
+ businessCategory: Engineering
+</A>
+</PRE>
+<A NAME="1267233">
+OID: <code>2.5.4.15</code><P></A>
+
+<A NAME="1208474">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1240535">
+<A NAME="c">
+<B>c</B>
+</a></a>
+<P>
+
+
+<A NAME="1240536">
+Contains the two-character code representing country names, as defined by ISO, in the directory. The two-character code for Ireland is used in the following example:<P></A>
+<PRE><A NAME="1240537">
+ countryName: IE
+</A>
+</PRE>
+<A NAME="1240538">
+or:<P></A>
+<PRE><A NAME="1240539">
+ c: IE
+</A>
+</PRE>
+<A NAME="1240541">
+Abbreviation: c<P></A>
+
+<A NAME="1267046">
+OID: <code>2.5.4.6</code><P></A>
+
+<A NAME="1240543">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1208564">
+<A NAME="cACertificate">
+<B>cACertificate</B>
+</a></a>
+<P>
+
+
+<A NAME="1208566">
+Contains a text-encoded version of the CA's certificate. Not recommended; use cACertificate;binary instead.<P></A>
+
+<A NAME="1208568">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1208584">
+<A NAME="cACertificate;binary">
+<B>cACertificate;binary</B>
+</a></a>
+<P>
+
+
+<A NAME="1208586">
+Contains the CA's certificate in binary form. For example:<P></A>
+<PRE><A NAME="1268025">
+ cACertificate;binary: AAAAAA==
+</A>
+</PRE>
+<A NAME="1287133">
+OID: <code>2.5.4.37</code><P></A>
+
+<A NAME="1208588">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1003044">
+<A NAME="carLicense">
+<B>carLicense</B>
+</a></a>
+<P>
+
+
+<A NAME="1003045">
+Identifies the entry's automobile license plate number. For example:<P></A>
+<PRE><A NAME="1003256">
+ carLicense: 6ABC246
+</A>
+</PRE>
+<A NAME="1003274">
+OID: <code>2.16.840.1.113730.3.1.1</code><P></A>
+
+<A NAME="1252881">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1007950">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1208746">
+<A NAME="certificateRevocationList">
+<B>certificateRevocationList</B>
+</a></a>
+<P>
+
+
+<A NAME="1208748">
+Contains a text-encoded version of a list of revoked user certificates. Not recommended; use certificateRevocationList;binary instead.<P></A>
+
+<A NAME="1277475">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1208727">
+<A NAME="certificateRevocationList;binary">
+<B>certificateRevocationList;binary</B>
+</a></a>
+<P>
+
+
+<A NAME="1208729">
+Contains a list, in binary form, of revoked user certificates. For example:<P></A>
+<PRE><A NAME="1287257">
+ certificateRevocationList;binary: AAAAAA==
+</A>
+</PRE>
+<A NAME="1277465">
+OID: <code>2.5.4.39</code><P></A>
+
+<A NAME="1208731">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1103361">
+<A NAME="changeLog">
+<B>changeLog</B>
+</a></a>
+<P>
+
+
+<A NAME="1251549">
+Contains the distinguished name of the container object that holds change log records for the Directory Server. For example:<P></A>
+<PRE><A NAME="1251550">
+changeLog: cn=changelog
+</A>
+</PRE>
+<A NAME="1103363">
+OID: <code>2.16.840.1.113730.3.1.35</code><P></A>
+
+<A NAME="1277486">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1171397">
+<A NAME="changeLogMaximumAge">
+<B>changeLogMaximumAge</B>
+</a></a>
+<P>
+
+
+<A NAME="1171398">
+Identifies the maximum age in seconds for entries in the change log. Entries are discarded once they become older than the maximum age specified. For example:<P></A>
+<PRE><A NAME="1171399">
+ changeLogMaximumAge: 86000
+</A>
+</PRE>
+<A NAME="1171401">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1171402">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1171405">
+<A NAME="changeLogMaximumSize">
+<B>changeLogMaximumSize</B>
+</a></a>
+<P>
+
+
+<A NAME="1171406">
+Identifies the maximum size in bytes for the change log file. Entries are discarded from this file once it reaches the maximum size. For example:<P></A>
+<PRE><A NAME="1171407">
+ changeLogMaximumSize: 2400000
+</A>
+</PRE>
+<A NAME="1171409">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1171410">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1094798">
+<A NAME="changeNumber">
+<B>changeNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1094841">
+Contains the change number of the entry as assigned by the supplier server. Must be the string representation of an integer. <P></A>
+
+<A NAME="1259352">
+OID: <code>2.16.840.1.113730.3.1.5</code><P></A>
+
+<A NAME="1095210">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1243260">int</a><P></A>
+<A NAME="1095277">
+<A NAME="changes">
+<B>changes</B>
+</a></a>
+<P>
+
+
+<A NAME="1095278">
+Reserved for future use. For example:<P></A>
+<PRE><A NAME="1251562">
+ changes: AAAAAA==
+</A>
+</PRE>
+<A NAME="1257834">
+OID: <code>2.16.840.1.113730.3.1.8</code><P></A>
+
+<A NAME="1095281">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1095285">
+<A NAME="changeTime">
+<B>changeTime</B>
+</a></a>
+<P>
+
+
+<A NAME="1095286">
+Undefined. <P></A>
+
+<A NAME="1259330">
+OID: <code>2.16.840.1.113730.3.1.77</code><P></A>
+
+<A NAME="1095289">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1094968">
+<A NAME="changeType">
+<B>changeType</B>
+</a></a>
+<P>
+
+
+<A NAME="1094969">
+Describes the type of change performed on an entry. The value for changeType can be add, delete, modify, or modrdn. For example:<P></A>
+<PRE><A NAME="1094970">
+ changeType: modify
+</A>
+</PRE>
+<A NAME="1257814">
+OID: <code>2.16.840.1.113730.3.1.7</code><P></A>
+
+<A NAME="1094972">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1103818">
+<A NAME="cirBeginORC">
+<B>cirBeginORC</B>
+</a></a>
+<P>
+
+
+<A NAME="1149985">
+Defines whether or not the consumer server should erase the contents of its directory before replication. If no value exists for this attribute, the consumer will not erase the contents. Two values are acceptable for this attribute; start and stop. Start tells the consumer server to erase the directory, and stop tells the consumer server to abort the operation. For example:<P></A>
+<PRE><A NAME="1151379">
+ cirBeginORC: start
+</A>
+</PRE>
+<A NAME="1259811">
+OID: <code>2.16.840.1.113730.3.1.90</code><P></A>
+
+<A NAME="1103820">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1101818">
+<A NAME="cirBindCredentials">
+<B>cirBindCredentials</B>
+</a></a>
+<P>
+
+
+<A NAME="1101820">
+Contains the credentials used by the consumer in consumer initiated replication (CIR) to connect to the supplier server.<P></A>
+
+<A NAME="1259645">
+OID: <code>2.16.840.1.113730.3.1.85</code><P></A>
+
+<A NAME="1101823">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1101379">
+<A NAME="cirBindDn">
+<B>cirBindDn</B>
+</a></a>
+<P>
+
+
+<A NAME="1101380">
+Contains the distinguished name used by the consumer in consumer initiated replication (CIR) when binding to the supplier server. <P></A>
+
+<A NAME="1259534">
+OID: <code>2.16.840.1.113730.3.1.82</code><P></A>
+
+<A NAME="1101383">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1101250">
+<A NAME="cirHost">
+<B>cirHost</B>
+</a></a>
+<P>
+
+
+<A NAME="1101251">
+Undefined. <P></A>
+
+<A NAME="1259486">
+OID: <code>2.16.840.1.113730.3.1.80</code><P></A>
+
+<A NAME="1101254">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1101860">
+<A NAME="cirLastUpdateApplied">
+<B>cirLastUpdateApplied</B>
+</a></a>
+<P>
+
+
+<A NAME="1122710">
+Contains the last date and time that synchronization occurred between the consumer and supplier servers. <P></A>
+
+<A NAME="1259652">
+OID: <code>2.16.840.1.113730.3.1.86</code><P></A>
+
+<A NAME="1101865">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1101283">
+<A NAME="cirPort">
+<B>cirPort</B>
+</a></a>
+<P>
+
+
+<A NAME="1101284">
+Contains the port number of the supplier server. For example:<P></A>
+<PRE><A NAME="1251598">
+ cirPort: 389
+</A>
+</PRE>
+<A NAME="1259507">
+OID: <code>2.16.840.1.113730.3.1.81</code><P></A>
+
+<A NAME="1101287">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1101135">
+<A NAME="cirReplicaRoot">
+<B>cirReplicaRoot</B>
+</a></a>
+<P>
+
+
+<A NAME="1101136">
+Root of the subtree on the supplier server to be replicated on the consumer.<P></A>
+
+<A NAME="1259453">
+OID: <code>2.16.840.1.113730.3.1.79</code><P></A>
+
+<A NAME="1101139">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1102148">
+<A NAME="cirSyncInterval">
+<B>cirSyncInterval</B>
+</a></a>
+<P>
+
+
+<A NAME="1149751">
+Periodically, the consumer server queries the supplier to find out if any changes have been made to the replicated portion of the directory. This attribute defines, in seconds, the interval between consumer queries of the supplier server. For example:<P></A>
+<PRE><A NAME="1102151">
+ cirSyncInterval: 3600
+</A>
+</PRE>
+<A NAME="1259808">
+OID: <code>2.16.840.1.113730.3.1.89</code><P></A>
+
+<A NAME="1102153">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1102114">
+<A NAME="cirUpdateFailedat">
+<B>cirUpdateFailedat</B>
+</a></a>
+<P>
+
+
+<A NAME="1146224">
+Timestamp of the last failed update attempt. <P></A>
+
+<A NAME="1259788">
+OID: <code>2.16.840.1.113730.3.1.88</code><P></A>
+
+<A NAME="1102119">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1102001">
+<A NAME="cirUpdateSchedule">
+<B>cirUpdateSchedule</B>
+</a></a>
+<P>
+
+
+<A NAME="1102003">
+Defines the hours between which replication can occur. For example:<P></A>
+<PRE><A NAME="1148927">
+ cirUpdateSchedule: 0100-0400
+</A>
+<A NAME="1148928">
+ cirUpdateSchedule: * 06
+</A>
+<A NAME="1148929">
+ cirUpdateSchedule: 1145-1300 24
+</A>
+</PRE>
+<A NAME="1148930">
+These values mean:<P></A>
+<PRE><A NAME="1148931">
+ 1:00 AM - 4:00 AM, daily
+</A>
+<A NAME="1148932">
+ All day Saturday and Sunday
+</A>
+<A NAME="1148933">
+ 11:45 AM -1:00 PM, Tuesday and Thursday
+</A>
+</PRE>
+<A NAME="1259785">
+OID: <code>2.16.840.1.113730.3.1.87</code><P></A>
+
+<A NAME="1251614">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1101691">
+<A NAME="cirUsePersistentSearch">
+<B>cirUsePersistentSearch</B>
+</a></a>
+<P>
+
+
+<A NAME="1101693">
+Undefined. <P></A>
+
+<A NAME="1259602">
+OID: <code>2.16.840.1.113730.3.1.83</code><P></A>
+
+<A NAME="1101696">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1101735">
+<A NAME="cirUseSsl">
+<B>cirUseSsl</B>
+</a></a>
+<P>
+
+
+<A NAME="1101737">
+Determines whether SSL should be used during consumer initiated replication.<P></A>
+
+<A NAME="1259621">
+OID: <code>2.16.840.1.113730.3.1.84</code><P></A>
+
+<A NAME="1101740">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1171494">
+<A NAME="cn">
+<B>cn</B>
+</a></a>
+<P>
+
+
+<A NAME="1171495">
+When in reference to an object class other than LDAPReplica or LDAPServer, cn identifies the entry's common name, or full name. For example:<P></A>
+<PRE><A NAME="1171496">
+ commonName: Bill Anderson
+</A>
+</PRE>
+<A NAME="1171497">
+or:<P></A>
+<PRE><A NAME="1171498">
+ cn: Bill Anderson
+</A>
+</PRE>
+<A NAME="1171499">
+When in reference to the LDAPReplica or LDAPServer object classes, it identifies the converted DNS name of the server and root of the replicated directory tree into distinguished name format. For example:<P></A>
+<PRE><A NAME="1171500">
+ commonName: replicater.netscape.com:17430/o%3Dexample<br> %2Cc%3us
+</A>
+</PRE>
+<A NAME="1171501">
+or:<P></A>
+<PRE><A NAME="1171502">
+ cn: replicater.netscape.com:17430/o%3Dexample%2Cc%3us
+</A>
+</PRE>
+<A NAME="1171504">
+Abbreviation: cn<P></A>
+
+<A NAME="1266999">
+OID: <code>2.5.4.3</code><P></A>
+
+<A NAME="1171506">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1265915">
+<A NAME="co">
+<B>co</B>
+</a></a>
+<P>
+
+
+<A NAME="1265916">
+Contains the name of a country. Often, the country attribute is used to describe a two-character code for a country, and the friendlyCountryName attribute is used to describe the actual country name. For example:<P></A>
+<PRE><A NAME="1265917">
+ friendlyCountryName: Ireland<br> countryName: IE
+</A>
+</PRE>
+<A NAME="1265918">
+or:<P></A>
+<PRE><A NAME="1265919">
+ co: Ireland
+</A>
+</PRE>
+<A NAME="1265921">
+Abbreviation: co<P></A>
+
+<A NAME="1265922">
+OID: <code>0.9.2342.19200300.100.1.43</code><P></A>
+
+<A NAME="1265924">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1241971">
+<A NAME="createTimestamp">
+<B>createTimestamp</B>
+</a></a>
+<P>
+
+
+<A NAME="1241973">
+Undefined. <P></A>
+
+<A NAME="1262782">
+OID: <code>2.5.18.1</code><P></A>
+
+<A NAME="1241975">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1242331">
+<A NAME="creatorsName">
+<B>creatorsName</B>
+</a></a>
+<P>
+
+
+<A NAME="1242332">
+Contains the distinguished name (dn) of the creator of an entry. For example:<P></A>
+<PRE><A NAME="1242333">
+ creatorsName: <I>cn=jdoe, o=example.com</I>
+</A>
+</PRE>
+<A NAME="1262998">
+OID: <code>2.5.18.3</code><P></A>
+
+<A NAME="1242335">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1208784">
+<A NAME="crossCertificatePair">
+<B>crossCertificatePair</B>
+</a></a>
+<P>
+
+
+<A NAME="1208786">
+Reserved for future use. Not recommended; use crossCertificatePair;binary instead.<P></A>
+
+<A NAME="1208788">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1208791">
+<A NAME="crossCertificatePair;binary">
+<B>crossCertificatePair;binary</B>
+</a></a>
+<P>
+
+
+<A NAME="1208793">
+Reserved for future use. <P></A>
+<PRE><A NAME="1287327">
+ crossCertificatePair;binary: AAAAAA==
+</A>
+</PRE>
+<A NAME="1208795">
+OID: <code>2.5.4.40</code><P></A>
+
+<A NAME="1277707">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1245094">
+<A NAME="dc">
+<B>dc</B>
+</a></a>
+<P>
+
+
+<A NAME="1245095">
+Specifies one component of a domain name. For example:<P></A>
+<PRE><A NAME="1245096">
+ domainComponent: example
+</A>
+<A NAME="1245097">
+or:
+</A>
+<A NAME="1266284">
+ dc: example
+</A>
+</PRE>
+<A NAME="1266285">
+OID: <code>0.9.2342.19200300.100.1.25</code><P></A>
+
+<A NAME="1266287">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1095547">
+<A NAME="deleteOldRdn">
+<B>deleteOldRdn</B>
+</a></a>
+<P>
+
+
+<A NAME="1095597">
+A flag that defines whether the old RDN of the entry should be retained as a distinguished attribute of the entry, or should be deleted. A value of False indicates that the RDN should be retained as a distinguished attribute, and a value of True indicates that it should not be retained as a distinguished attribute of the entry. If any value other than True or False is contained in the deleteOldRDN attribute, or if the deleteOldRDN contains multiple values, the RDN will be retained as a distinguished attribute (that is, False is the default if no values are present, or if illegal values are present).<P></A>
+<PRE><A NAME="1095550">
+ deleteOldRdn: False
+</A>
+</PRE>
+<A NAME="1257850">
+OID: <code>2.16.840.1.113730.3.1.10</code><P></A>
+
+<A NAME="1095552">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1241799">
+<A NAME="deltaRevocationList;binary">
+<B>deltaRevocationList;binary</B>
+</a></a>
+<P>
+
+
+<A NAME="1241800">
+Reserved for future use.<P></A>
+
+<A NAME="1269247">
+OID: <code>2.5.4.53</code><P></A>
+
+<A NAME="1241803">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1095560">
+<A NAME="departmentNumber">
+<B>departmentNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1095562">
+Identifies the entry's department number. For example:<P></A>
+<PRE><A NAME="1095563">
+ departmentNumber: 2604
+</A>
+</PRE>
+<A NAME="1257581">
+OID: <code>2.16.840.1.113730.3.1.2</code><P></A>
+
+<A NAME="1095565">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1095566">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1171528">
+<A NAME="description">
+<B>description</B>
+</a></a>
+<P>
+
+
+<A NAME="1171529">
+Describes the entry. For people and organizations this often includes their role or work assignment. For example:<P></A>
+<PRE><A NAME="1171530">
+ description: Quality control inspector for the ME2873 product line
+</A>
+</PRE>
+<A NAME="1267179">
+OID: <code>2.5.4.13</code><P></A>
+
+<A NAME="1171532">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1292809">
+<A NAME="destinationIndicator">
+<B>destinationIndicator</B>
+</a></a>
+<P>
+
+
+<A NAME="1292811">
+The country and city associated with the entry needed to provide Public Telegram Service. It is generally used in conjunction with <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202644">registeredAddress</a>.For example:<P></A>
+<PRE><A NAME="1251644">
+ destinationIndicator: Los Angeles, California
+</A>
+</PRE>
+<A NAME="1267786">
+OID: <code>2.5.4.27</code><P></A>
+
+<A NAME="1201828">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1283336">
+<A NAME="dITContentRules">
+<B>dITContentRules</B>
+</a></a>
+<P>
+
+
+<A NAME="1290848">
+Operational, multi-valued attribute that defines the directory tree content rules used within a subschema. Each value defines one DIT content rule.<P></A>
+
+<A NAME="1283340">
+OID: <code>2.5.21.2</code><P></A>
+
+<A NAME="1283342">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1201831">
+<A NAME="ditRedirect">
+<B>ditRedirect</B>
+</a></a>
+<P>
+
+
+<A NAME="1211719">
+Used to indicate that the object described by one entry now has a newer entry in the directory tree. This attribute may be used when an individual's place of work changes, and the individual acquires a new organizational DN. For example:<P></A>
+<PRE><A NAME="1201833">
+ ditRedirect: <I>cn=jdoe, o=example.com</I>
+</A>
+</PRE>
+<A NAME="1266700">
+OID: <code>0.9.2342.19200300.100.1.54</code><P></A>
+
+<A NAME="1283311">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1283313">
+<A NAME="dITStructureRules">
+<B>dITStructureRules</B>
+</a></a>
+<P>
+
+
+<A NAME="1291657">
+Operational, multi-valued attribute that defines the directory tree structure rules used in a subschema. Each value defines one structure rule. . <P></A>
+
+<A NAME="1281826">
+OID: <code>2.5.21.1</code><P></A>
+
+<A NAME="1281828">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1100403">
+<A NAME="dn">
+<B>dn</B>
+</a></a>
+<P>
+
+
+<A NAME="1100404">
+Defines the distinguished name (dn) for the entry. For example:<P></A>
+<PRE><A NAME="1268228">
+ <I>dn: cn=Jane Doe, ou=Quality Control, o=example.com</I>
+</A>
+</PRE>
+<A NAME="1268182">
+OID: <code>2.5.4.49</code><P></A>
+
+<A NAME="1268197">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1201841">
+<A NAME="dNSRecord">
+<B>dNSRecord</B>
+</a></a>
+<P>
+
+
+<A NAME="1218890">
+Specifies DNS resource records; including, type A (Address), type MX (Mail Exchange), type NS (Name Server), and type SOA (Start Of Authority) resource records. For example:<P></A>
+<PRE><A NAME="1218996">
+ dNSRecord: IN NS ns.uu.net.
+</A>
+</PRE>
+<A NAME="1264680">
+OID: <code>0.9.2342.19200300.100.1.26</code><P></A>
+
+<A NAME="1201844">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1241256">
+<A NAME="dnQualifier">
+<B>dnQualifier</B>
+</a></a>
+<P>
+
+
+<A NAME="1241257">
+Undefined.<P></A>
+
+<A NAME="1268140">
+OID: <code>2.5.4.46</code><P></A>
+
+<A NAME="1241260">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201847">
+<A NAME="documentAuthor">
+<B>documentAuthor</B>
+</a></a>
+<P>
+
+
+<A NAME="1201848">
+Contains the distinguished name of the author of a document entry. For example:<P></A>
+<PRE><A NAME="1201849">
+ documentAuthor: <I>cn=John Doe, o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1266431">
+OID: <code>0.9.2342.19200300.100.1.14</code><P></A>
+
+<A NAME="1201851">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">Syntax: </a>dn<P></A>
+<A NAME="1201854">
+<A NAME="documentIdentifier">
+<B>documentIdentifier</B>
+</a></a>
+<P>
+
+
+<A NAME="1214845">
+Specifies a unique identifier for a document.. For example:<P></A>
+<PRE><A NAME="1201856">
+ documentIdentifier: L3204REV1
+</A>
+</PRE>
+<A NAME="1266314">
+OID: <code>0.9.2342.19200300.100.1.11</code><P></A>
+
+<A NAME="1201858">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201861">
+<A NAME="documentLocation">
+<B>documentLocation</B>
+</a></a>
+<P>
+
+
+<A NAME="1201862">
+Defines the location of the original copy of a document entry. For example:<P></A>
+<PRE><A NAME="1201863">
+ documentLocation: Department Library
+</A>
+</PRE>
+<A NAME="1266449">
+OID: <code>0.9.2342.19200300.100.1.15</code><P></A>
+
+<A NAME="1201865">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201868">
+<A NAME="documentPublisher">
+<B>documentPublisher</B>
+</a></a>
+<P>
+
+
+<A NAME="1216107">
+The person and/or organization that published a document. For example:<P></A>
+<PRE><A NAME="1201870">
+ documentPublisher: Southeastern Publishing
+</A>
+</PRE>
+<A NAME="1260211">
+OID: <code>0.9.2342.19200300.100.1.56</code><P></A>
+
+<A NAME="1201872">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201877">
+<A NAME="documentStore">
+<B>documentStore</B>
+</a></a>
+<P>
+
+
+<A NAME="1201878">
+Undefined.<P></A>
+
+<A NAME="1201881">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201884">
+<A NAME="documentTitle">
+<B>documentTitle</B>
+</a></a>
+<P>
+
+
+<A NAME="1201885">
+Contains the title of a document entry. For example:<P></A>
+<PRE><A NAME="1201886">
+ documentTitle: Directory Administrator's Guide
+</A>
+</PRE>
+<A NAME="1266319">
+OID: <code>0.9.2342.19200300.100.1.12</code><P></A>
+
+<A NAME="1201888">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201891">
+<A NAME="documentVersion">
+<B>documentVersion</B>
+</a></a>
+<P>
+
+
+<A NAME="1201892">
+Defines the version of a document entry. For example:<P></A>
+<PRE><A NAME="1201893">
+ documentVersion: 1.1
+</A>
+</PRE>
+<A NAME="1266429">
+OID: <code>0.9.2342.19200300.100.1.13</code><P></A>
+
+<A NAME="1201895">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201909">
+<A NAME="drink">
+<B>drink</B>
+</a></a>
+<P>
+
+
+<A NAME="1201910">
+Describes favorite drink of a person entry. For example:<P></A>
+<PRE><A NAME="1201911">
+ drink: soda
+</A>
+<A NAME="1201912">
+or:
+</A>
+<A NAME="1201913">
+ favouriteDrink: soda
+</A>
+</PRE>
+<A NAME="1264462">
+OID: <code>0.9.2342.19200300.100.1.5</code><P></A>
+
+<A NAME="1201915">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1245205">
+<A NAME="dSAQuality">
+<B>dSAQuality</B>
+</a></a>
+<P>
+
+
+<A NAME="1245207">
+Undefined. <P></A>
+
+<A NAME="1266632">
+OID: <code>0.9.2342.19200300.100.1.49</code><P></A>
+
+<A NAME="1245210">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1003050">
+<A NAME="employeeNumber">
+<B>employeeNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1003051">
+Identifies the entry's employee number. For example:<P></A>
+<PRE><A NAME="1003356">
+ employeeNumber: 15300
+</A>
+</PRE>
+<A NAME="1257625">
+OID: <code>2.16.840.1.113730.3.1.3</code><P></A>
+
+<A NAME="1003382">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1008204">
+This attribute was created by Netscape for use with its LDAP implementation.<P></A>
+<A NAME="1009035">
+<A NAME="employeeType">
+<B>employeeType</B>
+</a></a>
+<P>
+
+
+<A NAME="1009036">
+Identifies the entry's type of employment. For example:<P></A>
+<PRE><A NAME="1009039">
+ employeeType: Full time
+</A>
+</PRE>
+<A NAME="1257756">
+OID: <code>2.16.840.1.113730.3.1.4</code><P></A>
+
+<A NAME="1009054">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1087204">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1241288">
+<A NAME="enhancedSearchGuide">
+<B>enhancedSearchGuide</B>
+</a></a>
+<P>
+
+
+<A NAME="1241289">
+Used by X.500 clients when construcing search filters. <P></A>
+
+<A NAME="1268147">
+OID: <code>2.5.4.47</code><P></A>
+
+<A NAME="1241292">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1171637">
+<A NAME="facsimileTelephoneNumber">
+<B>facsimileTelephoneNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1171638">
+Identifies the fax number at which the entry can be reached. For example:<P></A>
+<PRE><A NAME="1171639">
+ facsimileTelephoneNumber: 415-555-1212
+</A>
+</PRE>
+<A NAME="1171640">
+or:<P></A>
+<PRE><A NAME="1171641">
+ fax: 415-555-1212
+</A>
+</PRE>
+<A NAME="1266216">
+Abbreviation: fax<P></A>
+
+<A NAME="1267642">
+OID: <code>2.5.4.23</code><P></A>
+
+<A NAME="1266222">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004703">tel</a><P></A>
+<A NAME="1266221">
+<A NAME="filterInfo">
+<B>filterInfo</B>
+</a></a>
+<P>
+
+
+<A NAME="1284718">
+Reserved for future use.<P></A>
+
+<A NAME="1284721">
+OID: <code>2.16.840.1.113730.3.1.206</code><P></A>
+
+<A NAME="1284746">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">Syntax: cis</a><P></A>
+<A NAME="1284708">
+<A NAME="generation">
+<B>generation</B>
+</a></a>
+<P>
+
+
+<A NAME="1171658">
+Identifies a byte vector assigned to the server to distinguish it from any other generation or version of the server. The generation attribute is used only for replica synchronization.<P></A>
+
+<A NAME="1171660">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+
+<A NAME="1171661">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1104309">
+<A NAME="generationQualifier">
+<B>generationQualifier</B>
+</a></a>
+<P>
+
+
+<A NAME="1161653">
+Same as generation Qualifier in the Lightweight Internet Person Schema (LIPS).<P></A>
+
+<A NAME="1268127">
+OID: <code>2.5.4.44</code><P></A>
+
+<A NAME="1104311">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1229534">
+<A NAME="givenName">
+<B>givenName</B>
+</a></a>
+<P>
+
+
+<A NAME="1229535">
+Identifies the entry's given, or first, name. For example: <P></A>
+<PRE><A NAME="1229536">
+ givenName: Bill
+</A>
+</PRE>
+<A NAME="1268098">
+OID: <code>2.5.4.42</code><P></A>
+
+<A NAME="1229538">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201936">
+<A NAME="homePhone">
+<B>homePhone</B>
+</a></a>
+<P>
+
+
+<A NAME="1201937">
+Identifies the entry's home phone number. For example:<P></A>
+<PRE><A NAME="1201938">
+ homeTelephoneNumber: 415-555-1212
+</A>
+</PRE>
+<A NAME="1201939">
+or:<P></A>
+<PRE><A NAME="1201940">
+ homePhone: 415-555-1234
+</A>
+</PRE>
+<A NAME="1201942">
+Abbreviation: homePhone<P></A>
+
+<A NAME="1264518">
+OID: <code>0.9.2342.19200300.100.1.20</code><P></A>
+
+<A NAME="1201944">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004703">tel</a><P></A>
+<A NAME="1201947">
+<A NAME="homePostalAddress">
+<B>homePostalAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1201948">
+Identifies the entry's home mailing address. This field is intended to include multiple lines, but each line within the entry should be separated by a dollar sign ($). For example:<P></A>
+<PRE><A NAME="1201949">
+ homePostalAddress: 1234 Ridgeway Drive$Santa Clara, CA$99555
+</A>
+</PRE>
+<A NAME="1201950">
+To represent an actual dollar sign ($) or backslash (\) within this text, use the escaped hex values \24 and \5c respectively. For example, to represent the string:<P></A>
+<PRE><A NAME="1201951">
+ The dollar ($) value can be found <br> in the c:\cost file.
+</A>
+</PRE>
+<A NAME="1201952">
+provide the string:<P></A>
+<PRE><A NAME="1201953">
+ The dollar (\24) value can be found$in the c:\5ccost file.
+</A>
+</PRE>
+<A NAME="1264733">
+OID: <code>0.9.2342.19200300.100.1.39</code><P></A>
+
+<A NAME="1201955">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201958">
+<A NAME="host">
+<B>host</B>
+</a></a>
+<P>
+
+
+<A NAME="1201959">
+Defines the hostname of a computer. For example:<P></A>
+<PRE><A NAME="1201960">
+ host: mozilla
+</A>
+</PRE>
+<A NAME="1264500">
+OID: <code>0.9.2342.19200300.100.1.9</code><P></A>
+
+<A NAME="1201962">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1241726">
+<A NAME="houseIdentifier">
+<B>houseIdentifier</B>
+</a></a>
+<P>
+
+
+<A NAME="1241727">
+Contains an identifier for a house. <P></A>
+
+<A NAME="1269104">
+OID: <code>2.5.4.51</code><P></A>
+
+<A NAME="1241730">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201965">
+<A NAME="info">
+<B>info</B>
+</a></a>
+<P>
+
+
+<A NAME="1211991">
+The Information attribute type specifies any general information pertinent to an object. It is recommended that specific usage of this attribute type is avoided, and that specific requirements are met by other (possibly additional) attribute types.<P></A>
+<PRE><A NAME="1201967">
+ info: not valid
+</A>
+</PRE>
+<A NAME="1266299">
+OID: <code>0.9.2342.19200300.100.1.4</code><P></A>
+
+<A NAME="1201969">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1229543">
+<A NAME="initials">
+<B>initials</B>
+</a></a>
+<P>
+
+
+<A NAME="1229544">
+Identifies the entry's initials. For example:<P></A>
+<PRE><A NAME="1229545">
+ initials: BFA
+</A>
+</PRE>
+<A NAME="1268110">
+OID: <code>2.5.4.43</code><P></A>
+
+<A NAME="1229547">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1032705">
+<A NAME="installationTimeStamp">
+<B>installationTimeStamp</B>
+</a></a>
+<P>
+
+
+<A NAME="1212073">
+Identifies the date and time in zulu format when the Netscape server was installed. This attribute is a Netscape extension used by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097231">netscapeServer</a> object class. Normally this attribute and this attribute value are written to the directory when a Netscape server is initially installed. For example:<P></A>
+<PRE><A NAME="1212075">
+ installationTimeStamp: 199703261517z
+</A>
+</PRE>
+<A NAME="1259193">
+OID: <code>2.16.840.1.113730.3.1.73</code><P></A>
+
+<A NAME="1032810">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1224256">
+<A NAME="internationalIsdnNumber">
+<B>internationalIsdnNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1224257">
+Contains the ISDN number of the entry. This is in the internationally agreed format for ISDN addresses given in CCITT Rec. E. 164. <P></A>
+
+<A NAME="1267742">
+OID: <code>2.5.4.25</code><P></A>
+
+<A NAME="1224260">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1201988">
+<A NAME="janetMailbox">
+<B>janetMailbox</B>
+</a></a>
+<P>
+
+
+<A NAME="1212260">
+Specifies an email address. This attribute is intended for the convenience of U.K users unfamiliar with rfc822 mail addresses. Entries using this attribute must also include an rfc822Mailbox attribute. For example:<P></A>
+<PRE><A NAME="1201990">
+ janetMailbox: jdoe@example.com
+</A>
+</PRE>
+<A NAME="1266610">
+OID: <code>0.9.2342.19200300.100.1.46</code><P></A>
+
+<A NAME="1201992">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1201995">
+<A NAME="jpegPhoto">
+<B>jpegPhoto</B>
+</a></a>
+<P>
+
+
+<A NAME="1201996">
+Contains a JPEG photo of the entry. For example:<P></A>
+<PRE><A NAME="1201999">
+ jpegPhoto: AAAAAA==
+</A>
+</PRE>
+<A NAME="1287354">
+OID: <code>0.9.2342.19200300.100.1.60</code><P></A>
+
+<A NAME="1266169">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1202004">
+<A NAME="keyWords">
+<B>keyWords</B>
+</a></a>
+<P>
+
+
+<A NAME="1202005">
+Contains keywords for the entry. For example:<P></A>
+<PRE><A NAME="1202006">
+ keyWords: directory LDAP X.500
+</A>
+</PRE>
+<A NAME="1202008">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202013">
+<A NAME="knowledgeInformation">
+<B>knowledgeInformation</B>
+</a></a>
+<P>
+
+
+<A NAME="1202014">
+This attribute is no longer used.<P></A>
+
+<A NAME="1266967">
+OID: <code>2.5.4.2</code><P></A>
+<A NAME="1244534">
+<A NAME="l">
+<B>l</B>
+</a></a>
+<P>
+
+
+<A NAME="1244535">
+Identifies the county, city, or other geographical area in which the entry is located or in some other way associated with. For example:<P></A>
+<PRE><A NAME="1244536">
+ localityName: Santa Clara
+</A>
+</PRE>
+<A NAME="1244537">
+or:<P></A>
+<PRE><A NAME="1244538">
+ l: Santa Clara
+</A>
+</PRE>
+<A NAME="1244540">
+Abbreviation: l<P></A>
+
+<A NAME="1267059">
+OID: <code>2.5.4.7</code><P></A>
+
+<A NAME="1244542">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202020">
+<A NAME="labeledUri">
+<B>labeledUri</B>
+</a></a>
+<P>
+
+
+<A NAME="1202021">
+Specifies a Uniform Resource Identifier (URI) that is relevant in some way to the entry. Values placed in the attribute should consist of a URI (currently only URLs are supported) optionally followed by one or more space characters and a label. For example:<P></A>
+<PRE><A NAME="1202022">
+ labeledURI: http://home.netscape.com [Netscape corporations's <br> home page]
+</A>
+</PRE>
+<A NAME="1266144">
+OID: <code>1.3.6.1.4.1.250.1.57</code><P></A>
+
+<A NAME="1202024">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1100733">
+<A NAME="lastModifiedBy">
+<B>lastModifiedBy</B>
+</a></a>
+<P>
+
+
+<A NAME="1212108">
+Specifies the distinguished name of the last user to modify the associated entry. For example:<P></A>
+<PRE><A NAME="1202030">
+ lastModifiedby: <I>cn=Jane Doe, ou=Quality Control, o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1258536">
+OID: <code>0.9.2342.19200300.100.1.24</code><P></A>
+
+<A NAME="1280815">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1202035">
+<A NAME="lastModifiedTime">
+<B>lastModifiedTime</B>
+</a></a>
+<P>
+
+
+<A NAME="1202036">
+Defines the last time, in UTC format, that a change was made to the entry. For example:<P></A>
+<PRE><A NAME="1202037">
+ lastModifiedTime: Thursday, 22-Sep-93 14:15:00 GMT
+</A>
+</PRE>
+<A NAME="1266565">
+OID: <code>0.9.2342.19200300.100.1.23</code><P></A>
+
+<A NAME="1202039">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1243273">
+<A NAME="ldapSyntaxes">
+<B>ldapSyntaxes</B>
+</a></a>
+<P>
+
+
+<A NAME="1243274">
+Undefined.<P></A>
+
+<A NAME="1263292">
+OID: <code>1.3.6.1.4.1.1466.101.120.16</code><P></A>
+
+<A NAME="1243277">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1189404">
+<A NAME="mail">
+<B>mail</B>
+</a></a>
+<P>
+
+
+<A NAME="1189405">
+Identifies the entry's email address. For example:<P></A>
+<PRE><A NAME="1189406">
+ mail: banderson@example.com
+</A>
+</PRE>
+<A NAME="1189408">
+OID: <code>0.9.2342.19200300.100.1.3</code><P></A>
+
+<A NAME="1264446">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1024020">
+<A NAME="mailAccessDomain">
+<B>mailAccessDomain</B>
+</a></a>
+<P>
+
+
+<A NAME="1024021">
+Identifies the domain or IP address from which the user can perform a POP/IMAP logon. This attribute is a Netscape extension used by the Messaging Server. For example:<P></A>
+<PRE><A NAME="1024022">
+ mailAccessDomain: example.com
+</A>
+</PRE>
+<A NAME="1024248">
+OID: <code>2.16.840.1.113730.3.1.12</code><P></A>
+
+<A NAME="1269362">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1024250">
+<A NAME="mailAlternateAddress">
+<B>mailAlternateAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1024251">
+Identifies an alternative mail address for a mail user. This attribute is a Netscape extension used by the Messaging Server to match a mail address to a user. A mail account can have as many instances of this attribute as the user has alternate mail addresses. For example:<P></A>
+<PRE><A NAME="1024061">
+ mailAlternateAddress: Babs_Jensen@example.com<br> mailAlternateAddress: Bjensen@example.com
+</A>
+</PRE>
+<A NAME="1269367">
+OID: <code>2.16.840.1.113730.3.1.13</code><P></A>
+
+<A NAME="1269365">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1024094">
+<A NAME="mailAutoReplyMode">
+<B>mailAutoReplyMode</B>
+</a></a>
+<P>
+
+
+<A NAME="1027423">
+Identifies the mail auto reply mode for the mail user. This attribute is a Netscape extension used by the Messaging Server. Zero or one (0 - 1) instances of this attribute are expected per mail user account. Valid keywords for this attribute are:<P></A>
+<ul><A NAME="1027425">
+<LI>vacation -- Send the vacation message. The vacation message is contained on the mailAutoReplyText attribute.<P>
+</A>
+<A NAME="1027426">
+<LI>reply -- Send a fixed reply. The reply is contained on the mailAutoReplyText attribute.<P>
+</A>
+<A NAME="1027427">
+<LI>echo -- Echo the original message and send the mailAutoReplyText to the original sender of the message.<P>
+</A>
+</ul>
+<A NAME="1027428">
+For example:<P></A>
+<PRE><A NAME="1027429">
+ mailAutoReplyMode: vacation
+</A>
+</PRE>
+<A NAME="1269369">
+OID: <code>2.16.840.1.113730.3.1.14</code><P></A>
+
+<A NAME="1024098">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1024125">
+<A NAME="mailAutoReplyText">
+<B>mailAutoReplyText</B>
+</a></a>
+<P>
+
+
+<A NAME="1027662">
+Provides auto reply text for a mail user. This attribute is a Netscape extension used by Messaging Server. When represented in LDIF format, each line should be separated by a dollar sign ($). The Messaging Server expects 0 or 1 occurrences of this attribute per mail account. For example:<P></A>
+<PRE><A NAME="1027663">
+ mailAutoReplyText: On vacation$Back in the office on Monday.
+</A>
+</PRE>
+<A NAME="1034577">
+To represent an actual dollar sign ($) or backslash (\) within this text, use the escaped hex values \24 and \5c respectively. For example, to represent the string:<P></A>
+<PRE><A NAME="1034578">
+ The dollar ($) value can be found <br> in the c:\cost file.
+</A>
+</PRE>
+<A NAME="1034579">
+provide the string:<P></A>
+<PRE><A NAME="1034580">
+ The dollar (\24) value can be found$in the c:\5ccost file.
+</A>
+</PRE>
+<A NAME="1269558">
+OID: <code>2.16.840.1.113730.3.1.15</code><P></A>
+
+<A NAME="1024293">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1024295">
+<A NAME="mailDeliveryOption">
+<B>mailDeliveryOption</B>
+</a></a>
+<P>
+
+
+<A NAME="1024296">
+Identifies the mail delivery mechanism to be used for the mail user. This attribute is a Netscape extension used by the Messaging Server. Zero to three (0 - 3) instances of this attribute are expected per mail user account. However, if no instance of this attribute exists on the mail user entry, then at least one <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1026154">mailForwardingAddress</a> attribute must exist on the entry. Valid keywords for this attribute are:<P></A>
+<ul><A NAME="1027169">
+<LI>mailbox -- Indicates that mail is to be delivered to the user's POP/IMAP mailbox.<P>
+</A>
+<A NAME="1027175">
+<LI>native -- Indicates that Unix delivery is to be used. This option is available only for Messaging Servers running on a Unix host.<P>
+</A>
+<A NAME="1027197">
+<LI>program -- Indicates that program delivery is to be used. This option is available only for Messaging Servers running on a Unix host.<P>
+</A>
+</ul>
+<A NAME="1027143">
+For example:<P></A>
+<PRE><A NAME="1024297">
+ mailDeliveryOption: mailbox
+</A>
+</PRE>
+<A NAME="1269568">
+OID: <code>2.16.840.1.113730.3.1.16</code><P></A>
+
+<A NAME="1024169">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1026103">
+<A NAME="mailEnhancedUniqueMember">
+<B>mailEnhancedUniqueMember</B>
+</a></a>
+<P>
+
+
+<A NAME="1026104">
+Netscape extension used by the Messaging Server. Reserved for future use.<P></A>
+
+<A NAME="1026153">
+OID: <code>2.16.840.1.113730.3.1.31</code><P></A>
+
+<A NAME="1278474">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1026154">
+<A NAME="mailForwardingAddress">
+<B>mailForwardingAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1024197">
+Identifies a mail address to which mail is forwarded. This attribute is a Netscape extension used by the Messaging Server to forward incoming mail to the correct location. For example:<P></A>
+<PRE><A NAME="1024198">
+ mailForwardingAddress: bjensen@royalairways.com
+</A>
+</PRE>
+<A NAME="1269579">
+OID: <code>2.16.840.1.113730.3.1.17</code><P></A>
+
+<A NAME="1024200">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1024314">
+<A NAME="mailHost">
+<B>mailHost</B>
+</a></a>
+<P>
+
+
+<A NAME="1024315">
+Identifies the DNS hostname of the host on which the user's mail account resides. This attribute is a Netscape extension used by the Messaging Server to route incoming mail to the correct location. The Messaging Server expects one and only one instance of this attribute per<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#"> mail</a>Recipient entry, or zero or one instances of this attribute on a <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">mailGroup</a> entry. The value specified on this attribute must be the host's fully qualified domain name. For example:<P></A>
+<PRE><A NAME="1024316">
+ mailHost: mars.example.com
+</A>
+</PRE>
+<A NAME="1269581">
+OID: <code>2.16.840.1.113730.3.1.18</code><P></A>
+
+<A NAME="1024318">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1024377">
+<A NAME="mailMessageStore">
+<B>mailMessageStore</B>
+</a></a>
+<P>
+
+
+<A NAME="1024378">
+Identifies the absolute path on the user's mail host to the location under which the user's mailbox resides. This attribute is a Netscape extension used by the Messaging Server and this attribute is applicable only if the user's<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024295"> mailDeliveryOption</a> is set to mailbox. The Messaging Server expects zero or one (0 or 1) instances of this attribute. If no instances of this attribute exist on the user's entry, then the default configured on the user's Messaging Server is used. For example:<P></A>
+<PRE><A NAME="1024379">
+ mailMessageStore: /disk2/mail
+</A>
+</PRE>
+<A NAME="1269614">
+OID: <code>2.16.840.1.113730.3.1.19</code><P></A>
+
+<A NAME="1090714">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1202044">
+<A NAME="mailPreferenceOption">
+<B>mailPreferenceOption</B>
+</a></a>
+<P>
+
+
+<A NAME="1213101">
+Indicates a preference for inclusion of their names on mailing lists (electronic or physical). There are three acceptable values for this attribute; <code>0</code>, <code>1</code>, and <code>2</code>. A value of <code>0</code> means that the user doesn't want to be included in mailing lists. A value of <code>1</code> means that the user consents to be added to any mailing list. A value of <code>2</code> means that the user only wants to be added to mailing lists which the list provider views as related to the users professional interests. The absence of such an attribute should be interpreted as if the attribute was present with value "no-list-inclusion". This attribute should be interpreted by anyone using the directory to derive mailing lists, and its value respected. For example:<P></A>
+<PRE><A NAME="1202046">
+ mailPreferenceOption: 0
+</A>
+</PRE>
+<A NAME="1266117">
+OID: <code>0.9.2342.19200300.100.1.47</code><P></A>
+
+<A NAME="1202048">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1243260">int single</a><P></A>
+<A NAME="1024400">
+<A NAME="mailProgramDeliveryInfo">
+<B>mailProgramDeliveryInfo</B>
+</a></a>
+<P>
+
+
+<A NAME="1024401">
+Identifies one or more commands, delimited by $, to be used for programmed mail delivery. This attribute is a Netscape extension used by the Messaging Server. The Messaging Server expect zero or one (0-1) instances of this attribute per user account. This attribute is meaningful only if all of the following conditions are true:<P></A>
+<ul><A NAME="1033350">
+<LI>the Messaging Server is running on Unix<P>
+</A>
+<A NAME="1033365">
+<LI>program delivery has been enabled on the Messaging Server by the mail administrator<P>
+</A>
+<A NAME="1033405">
+<LI>the user's <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024295">mailDeliveryOption</a> is set to<B> </B>program<P>
+</A>
+</ul>
+<A NAME="1039005">
+For example:<P></A>
+<PRE><A NAME="1024402">
+ mailProgramDeliveryInfo: /usr/local/bin/procmail -f-
+</A>
+</PRE>
+<A NAME="1269616">
+OID: <code>2.16.840.1.113730.3.1.20</code><P></A>
+
+<A NAME="1024440">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1024509">
+<A NAME="mailQuota">
+<B>mailQuota</B>
+</a></a>
+<P>
+
+
+<A NAME="1024510">
+Identifies the maximum disk space in bytes that may be consumed by the user's mailbox. This attribute is a Netscape extension used by the Messaging Server and this attribute is applicable only if the user's <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024295">mailDeliveryOption</a> is set to mailbox. The Messaging Server expects zero or one (0 or 1) instances of this attribute. If no instances of this attribute exist on the user's entry, then the default configured on the user's Messaging Server is used. For example:<P></A>
+<PRE><A NAME="1024511">
+ mailQuota: 1000000
+</A>
+</PRE>
+<A NAME="1024513">
+Note that if this attribute is set to zero, then no limit is set on the disk space quota.<P></A>
+
+<A NAME="1269588">
+OID: <code>2.16.840.1.113730.3.1.21</code><P></A>
+
+<A NAME="1033421">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1241537">
+<A NAME="mailRoutingAddress">
+<B>mailRoutingAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1241538">
+Undefined. <P></A>
+
+<A NAME="1263316">
+OID: <code>2.16.840.1.113730.3.1.47</code><P></A>
+
+<A NAME="1241541">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1007859">
+<A NAME="manager">
+<B>manager</B>
+</a></a>
+<P>
+
+
+<A NAME="1007872">
+Identifies the distinguished name of the entry's manager. For example:<P></A>
+<PRE><A NAME="1007875">
+ manager:<I> cn=Jane Doe, ou=Quality Control, o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1264515">
+OID: <code>0.9.2342.19200300.100.1.10</code><P></A>
+
+<A NAME="1007908">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1242887">
+<A NAME="matchingRules">
+<B>matchingRules</B>
+</a></a>
+<P>
+
+
+<A NAME="1290968">
+Operational, multi-valued attribute that specifies the matching rules used in a subschema. Each value describes a single matching rule. <P></A>
+
+<A NAME="1263068">
+OID: <code>2.5.21.4</code><P></A>
+
+<A NAME="1242891">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1242961">
+<A NAME="matchingRuleUse">
+<B>matchingRuleUse</B>
+</a></a>
+<P>
+
+
+<A NAME="1242962">
+Operational attribute that identifies the attribute types to which a matching rule applies in a subschema. <P></A>
+
+<A NAME="1263074">
+OID: <code>2.5.21.8</code><P></A>
+
+<A NAME="1263077">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1171811">
+<A NAME="member">
+<B>member</B>
+</a></a>
+<P>
+
+
+<A NAME="1171812">
+Identifies the distinguished names for each member of the group. For example:<P></A>
+<PRE><A NAME="1171813">
+ member: <I>cn=John Doe, o=example.com</I>
+</A>
+</PRE>
+<A NAME="1267883">
+OID: <code>2.5.4.31</code><P></A>
+
+<A NAME="1171815">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1152959">
+<A NAME="memberCertificateDescription">
+<B>memberCertificateDescription</B>
+</a></a>
+<P>
+
+
+<A NAME="1152961">
+Identifies the characteristics of certificates in a particular group of certificates. If a certificate contains a subject distinguished name that matches one of the values in memberCertificateDescription, it is considered a member of the certificate group of which the attribute is a part. The format is as follows:<P></A>
+<PRE><A NAME="1153378">
+ {<I>subject_dn</I>}
+</A>
+</PRE>
+<A NAME="1153395">
+You can specify multiple subject dns by separating them with commas. You can designate more than one <code>ou</code> in the entry. If you specify multiple entries of other attribute types (not <code>ou</code>), all but the last one will be ignored.<P></A>
+
+<A NAME="1154677">
+For example, in order to be considered a member of a group with the following memberCertificateDescription, a certficiate would need to include <code>ou=x</code>, <code>ou=A</code>, and <code>o=example</code> but not <code>o=company</code>.<P></A>
+<PRE><A NAME="1126332">
+ memberCertificateDescription: {<I>ou=x, ou=A, o=company, o=example</I>}
+</A>
+</PRE>
+<A NAME="1154571">
+In order to match the group's requirements, a certificate's subject dns must contain the same ou attribute types in the same order as defined in the memberCertificateDescription attribute.<P></A>
+
+<A NAME="1263664">
+OID: <code>2.16.840.1.113730.3.1.199</code><P></A>
+
+<A NAME="1153423">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1246271">
+<A NAME="memberURL">
+<B>memberURL</B>
+</a></a>
+<P>
+
+
+<A NAME="1246272">
+Identifies a URL associated with each member of a group. For example:<P></A>
+<PRE><A NAME="1246273">
+ memberURL: ldap://<I>cn=jdoe, o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1263332">
+OID: <code>2.16.840.1.113730.3.1.198</code><P></A>
+
+<A NAME="1246275">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1025144">
+<A NAME="mgrpAllowedBroadcaster">
+<B>mgrpAllowedBroadcaster</B>
+</a></a>
+<P>
+
+
+<A NAME="1025146">
+Identifies mail users allowed to send messages to the mail group. This attribute is a Netscape extension used by the Messaging Server to manage mailing lists. If no instances of this attribute exist on the mailGroup entry, then there are no restrictions on who can send messages to the mail group unless the mgrpAllowedDomain attribute is used. <P></A>
+
+<A NAME="1028370">
+The Messaging Server expects this attribute to contain either a distinguished name or an rfc822address. If a distinguished name is used, it must represent a mailable entry or entries of type group or groupOfUniqueNames. The distinguished name must be represented in the form of a LDAP URL as described in RFC1959, <em>An LDAP URL format</em>.<P></A>
+
+<A NAME="1028354">
+For example:<P></A>
+<PRE><A NAME="1025147">
+ mgrpAllowedBroadcaster: ldap://<I>uid=bjensen, o=Example.com<br></I> mgrpAllowedBroadcaster: mailto:sys50@example.com
+</A>
+</PRE>
+<A NAME="1277878">
+OID: <code>2.16.840.1.113730.3.1.22</code><P></A>
+
+<A NAME="1025149">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1024569">
+<A NAME="mgrpAllowedDomain">
+<B>mgrpAllowedDomain</B>
+</a></a>
+<P>
+
+
+<A NAME="1024570">
+Identifies domains from which users are allowed to send messages to the mail group. This attribute is a Netscape extension used by the Messaging Server to manage mailing lists. If no instances of this attribute exist on the mailGroup entry, then there are no restrictions on who can send messages to the mail group unless the mgrpAllowedBroadcaster attribute is used. <P></A>
+
+<A NAME="1028614">
+This is by defaulted to a wild card value. That is, a value of "example.com" will match any user sending from "*.example.com"<P></A>
+
+<A NAME="1028598">
+For example:<P></A>
+<PRE><A NAME="1024571">
+ mgrpAllowedDomain: example.com
+</A>
+</PRE>
+<A NAME="1277883">
+OID: <code>2.16.840.1.113730.3.1.23</code><P></A>
+
+<A NAME="1278549">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1278551">
+<A NAME="mgrpDeliverTo">
+<B>mgrpDeliverTo</B>
+</a></a>
+<P>
+
+
+<A NAME="1278552">
+Alternative method of specifying mail group membership. This attribute is a Netscape extension used by the Messaging Server to manage mailing lists. The Messaging Server expects this attribute to contain an LDAP URL using the format described in RFC1959, <em>An LDAP URL format</em>. Any entries returned by the resulting LDAP search are members of the mailing group. For example:<P></A>
+<PRE><A NAME="1025433">
+ mgrpDeliverTo: ldap:///<I>ou=Accounting,o=Netscape,c=US??sub?(&amp;<br> (objectClass=mailRecipient)(objectClass=inetOrgPerson))</I>
+</A>
+</PRE>
+<A NAME="1277885">
+OID: <code>2.16.840.1.113730.3.1.25</code><P></A>
+
+<A NAME="1025435">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1025568">
+<A NAME="mgrpErrorsTo">
+<B>mgrpErrorsTo</B>
+</a></a>
+<P>
+
+
+<A NAME="1028828">
+Identifies a mailing address to send error messages to for notification of mail delivery problems, such as bounced mails or members of the mailing group that lack a mailing address. This attribute is a Netscape extension used by the Messaging Server to manage mailing lists. If no instances of this attribute exist on the mailGroup entry, then error handling is managed according to the default set in the Messaging Server. <P></A>
+
+<A NAME="1028829">
+The Messaging Server expects this attribute to contain either a distinguished name or a rfc822address. If a distinguished name is used, it must represent a mailable entry or entries of type group or groupOfUniqueNames. The distinguished name must be represented in the form of a LDAP URL as described in RFC1959, <em>An LDAP URL format</em>.<P></A>
+
+<A NAME="1126241">
+For example:<P></A>
+<PRE><A NAME="1126242">
+ mgrpErrorsTo: ldap://<I>uid=bjensen, o=Example.com<br></I> mgrpErrorsTo: mailto:sys50@example.com
+</A>
+</PRE>
+<A NAME="1277947">
+OID: <code>2.16.840.1.113730.3.1.26</code><P></A>
+
+<A NAME="1025572">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1025705">
+<A NAME="mgrpModerator">
+<B>mgrpModerator</B>
+</a></a>
+<P>
+
+
+<A NAME="1025706">
+Identifies a mailing address to send rejected messages to. This attribute is a Netscape extension used by the Messaging Server to manage mailing lists. This is the address that rejected mail from a mailing list is sent to. <P></A>
+
+<A NAME="1029841">
+The Messaging Server may reject mail either because it is received from an unauthorized domain (as defined by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024569">mgrpAllowedDomain</a> attribute) or is received from an mail address that is not a member of the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025144">mgrpAllowedBroadcaster</a> attribute. The Messaging Server will only forward mail to the address(es) identified by this attribute if the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025035">mgrpMsgRejectAction</a> attribute includes toModerator<B>. </B>If no instances of this attribute exist on the mailGroup entry, and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025035">mgrpMsgRejectAction</a> attribute is set to toModerator, then rejected mail that is supposed to be sent to the moderator is dumped (that is, it is deleted from the mail system with no further human interaction). <P></A>
+
+<A NAME="1029357">
+The Messaging Server expects this attribute to contain either a distinguished name or a rfc822address. If a distinguished name is used, it must represent a mailable entry or entries of type group or groupOfUniqueNames. The distinguished name must be represented in the form of a LDAP URL as described in RFC1959, <em>An LDAP URL format</em>.<P></A>
+
+<A NAME="1029358">
+For example:<P></A>
+<PRE><A NAME="1029359">
+ mgrpErrorsTo: ldap://<I>uid=bjensen, o=Example.com<br></I> mgrpErrorsTo: mailto:sys50@example.com
+</A>
+</PRE>
+<A NAME="1277952">
+OID: <code>2.16.840.1.113730.3.1.33</code><P></A>
+
+<A NAME="1025876">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1025878">
+<A NAME="mgrpMsgMaxSize">
+<B>mgrpMsgMaxSize</B>
+</a></a>
+<P>
+
+
+<A NAME="1025879">
+Identifies the maximum message size in bytes that is allowed to be sent to the mail group. This attribute is a Netscape extension used by the Messaging Server to manage mailing lists. The Messaging Server expects one and only one instance of this attribute to exist for every mailGroup entry. For example:<P></A>
+<PRE><A NAME="1025290">
+ mgrpMsgMaxSize: 2000
+</A>
+</PRE>
+<A NAME="1277962">
+OID: <code>2.16.840.1.113730.3.1.32</code><P></A>
+
+<A NAME="1025292">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1025035">
+<A NAME="mgrpMsgRejectAction">
+<B>mgrpMsgRejectAction</B>
+</a></a>
+<P>
+
+
+<A NAME="1024634">
+Identifies the action to be taken when a mail sent to a mail group is rejected. This attribute is a Netscape extension used by the Messaging Server to manage mailing lists.<P></A>
+
+<A NAME="1029427">
+The Messaging Server may reject mail either because it is received from an unauthorized domain (as defined by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024569">mgrpAllowedDomain</a> attribute), is received from an mail address that is not a member of the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025144">mgrpAllowedBroadcaster</a> attribute, or is larger than the size permitted on <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025878">mgrpMsgMaxSize</a>.<P></A>
+
+<A NAME="1031346">
+The Messaging Server expects from zero to two (0-2) instances of this attribute per mailGroup entry. If no instances of this attribute exist on the mailGroup entry, then reply is used by default. Valid keywords for this attribute are:<P></A>
+<ul><A NAME="1029629">
+<LI>reply -- send a failure notice to the sender. The text of the failure notice is stored on the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">mgrpMsgRejectTex</a>t attribute.<P>
+</A>
+<A NAME="1029638">
+<LI>bounce -- return the message to the sender with the comment stored on the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">mgrpMsgRejectTex</a>t attribute.<P>
+</A>
+<A NAME="1029664">
+<LI>toModerator -- forward the message to the moderator for processing. The moderator is identified by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025705">mgrpModerator</a> attribute.<P>
+</A>
+</ul>
+<A NAME="1029617">
+For example:<P></A>
+<PRE><A NAME="1024635">
+ mgrpMsgRejectAction: bounce
+</A>
+</PRE>
+<A NAME="1278044">
+OID: <code>2.16.840.1.113730.3.1.28</code><P></A>
+
+<A NAME="1024637">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1025981">
+<A NAME="mgrpMsgRejectText">
+<B>mgrpMsgRejectText</B>
+</a></a>
+<P>
+
+
+<A NAME="1025983">
+Identifies the text to be sent by the Messaging Server when mail sent to a mail group is rejected and the mgrpMsgRejectAction attribute is set to either bounce or reply. This attribute is a Netscape extension used by the Messaging Server to manage mailing lists. <P></A>
+
+<A NAME="1030064">
+The Messaging Server expects from zero to one (0-1) instances of this attribute to exist per mailGroup entry. Multiline text may be delimited using $ when represented in LDIF format. If no instances of this attribute exist on the mailGroup entry, then the default text set in the Messaging Server is used for rejected mail.<P></A>
+
+<A NAME="1030130">
+For example:<P></A>
+<PRE><A NAME="1025984">
+ mgrpMsgRejectText: The mail you have sent to the Crazed Bikers$<br> mailing list has been rejected because$you are not a recognized<br> member of the Crazed Bikers group.$Please contact Big Daddy Biker<br> at rsweeny@example.com for information on how to become$a<br> crazed biker.
+</A>
+</PRE>
+<A NAME="1278050">
+OID: <code>2.16.840.1.113730.3.1.29</code><P></A>
+
+<A NAME="1025986">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1102613">
+<A NAME="mgrpPassword">
+<B>mgrpPassword</B>
+</a></a>
+<P>
+
+
+<A NAME="1102614">
+Reserved for future use. For example:<P></A>
+<PRE><A NAME="1287369">
+ mgrpPassword: AAAAAA==
+</A>
+</PRE>
+<A NAME="1102615">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1024670">
+<A NAME="mgrpRFC822MailMember">
+<B>mgrpRFC822MailMember</B>
+</a></a>
+<P>
+
+
+<A NAME="1024672">
+Identifies recipients of mail sent to a <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">mailGroup</a> that are not actually members of the mail group. Conceptually, these mail addresses can be thought of as "CC recipients". That is, this attribute is used to represent mail recipients that cannot be expressed as distinguished names, or who are to be sent mail from this group but who do not have the full privileges of a unique group member. This attribute is a Netscape extension used by the Messaging Server to manage mailing lists.<P></A>
+
+<A NAME="1030207">
+The Messaging Server expects this attribute to contain rfc822 mail addresses using the following form:<P></A>
+<PRE><A NAME="1030236">
+<code> rfc822MailAddress [ % 'full' name] [ %1 (group parameter #1)]<br> [ %2 (group parameter #2)]...</code>
+</A>
+</PRE>
+<A NAME="1030231">
+where:<P></A>
+<ul><A NAME="1030278">
+<LI>rfc822MailAddress is an address such as<P>
+</A>
+</ul><PRE><A NAME="1030338">
+ bjensen@example.com
+</A>
+</PRE><ul><A NAME="1030343">
+<LI>full name is an optional parameter representing the user's full name. This parameter is reserved for future use.<P>
+</A>
+<A NAME="1030396">
+<LI>group parameters are optional parameters that are reserved for future use.<P>
+</A>
+</ul>
+<A NAME="1030305">
+For example:<P></A>
+<PRE><A NAME="1024673">
+ mgrpRFC822MailMember: bjensen@example.com%Babs Jensen
+</A>
+</PRE>
+<A NAME="1278123">
+OID: <code>2.16.840.1.113730.3.1.30</code><P></A>
+
+<A NAME="1024675">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202056">
+<A NAME="mobile">
+<B>mobile</B>
+</a></a>
+<P>
+
+
+<A NAME="1202057">
+Identifies the entry's mobile or cellular phone number. For example:<P></A>
+<PRE><A NAME="1202058">
+ mobileTelephoneNumber: 415-555-4321
+</A>
+</PRE>
+<A NAME="1202059">
+or:<P></A>
+<PRE><A NAME="1202060">
+ mobile: 415-555-4321
+</A>
+</PRE>
+<A NAME="1202062">
+Abbreviation: mobile<P></A>
+
+<A NAME="1264782">
+OID: <code>0.9.2342.19200300.100.1.41</code><P></A>
+
+<A NAME="1202064">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004703">tel</a><P></A>
+<A NAME="1242555">
+<A NAME="modifiersName">
+<B>modifiersName</B>
+</a></a>
+<P>
+
+
+<A NAME="1242556">
+Contains the distinguished name (dn) of the user that last modified an entry. For example:<P></A>
+<PRE><A NAME="1242557">
+ modifiersName: <I>cn=jdoe, o=example.com</I>
+</A>
+</PRE>
+<A NAME="1263015">
+OID: <code>2.5.18.4</code><P></A>
+
+<A NAME="1242559">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1242117">
+<A NAME="modifyTimestamp">
+<B>modifyTimestamp</B>
+</a></a>
+<P>
+
+
+<A NAME="1242119">
+Undefined.<P></A>
+
+<A NAME="1262948">
+OID: <code>2.5.18.2</code><P></A>
+
+<A NAME="1242126">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1229561">
+<A NAME="multiLineDescription">
+<B>multiLineDescription</B>
+</a></a>
+<P>
+
+
+<A NAME="1229562">
+Provides descriptive text for a mail user. This attribute is a Netscape extension used by Messaging Server. When represented in LDIF format, each line should be separated by a dollar sign ($). The Messaging Server expects 0 or 1 occurrences of this attribute per mail account. For example:<P></A>
+<PRE><A NAME="1229563">
+ multiLineDescription: Account Administrator and$directory manager.
+</A>
+</PRE>
+<A NAME="1229565">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1282059">
+<A NAME="nameForms">
+<B>nameForms</B>
+</a></a>
+<P>
+
+
+<A NAME="1282063">
+Operational, multi-valued attribute that defines the name forms used in a subschema. Each value defines one name form. OID: <code>2.5.21.7</code><P></A>
+
+<A NAME="1282065">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1243088">
+<A NAME="namingContexts">
+<B>namingContexts</B>
+</a></a>
+<P>
+
+
+<A NAME="1243089">
+Undefined.<P></A>
+
+<A NAME="1263080">
+OID: <code>1.3.6.1.4.1.1466.101.120.5</code><P></A>
+
+<A NAME="1243092">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1096606">
+<A NAME="netscapeReplicaState">
+<B>netscapeReplicaState</B>
+</a></a>
+<P>
+
+
+<A NAME="1278694">
+This attribute is reserved for use by the Netscape Directory Server and is not included in the <code>slapd.at.conf</code> file. The attribute contains a replica CN and a description of the current state of a directory replication process. The states include the following:<P></A>
+<ul><A NAME="1278883">
+<LI><B>Idle.</B> The synchronization system is not performing work at this time.<P>
+</A>
+<A NAME="1278885">
+<LI><B>Synchronizing.</B> The system is in the process of performing a replication.<P>
+</A>
+<A NAME="1278894">
+<LI><B>Populating.</B> The synchronization system is populating the consumer's directory.<P>
+</A>
+<A NAME="1279072">
+<LI><B>Halted.</B> The synchronization system has stopped.<P>
+</A>
+<A NAME="1279073">
+<LI><B>Unknown.</B> The state of the replication process is unknown.<P>
+</A>
+</ul>
+<A NAME="1279074">
+For example:<P></A>
+<PRE><A NAME="1278705">
+netscapeReplicaState: dirserver.example.com:389/o%3Dmozilla.com idle
+</A>
+</PRE>
+<A NAME="1278700">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1278579">
+<A NAME="newRdn">
+<B>newRdn</B>
+</a></a>
+<P>
+
+
+<A NAME="1096607">
+Contains the new RDN (Relative Distinguished Name) of an entry which is the target of a modRDN or modDN operation. For example:<P></A>
+<PRE><A NAME="1096608">
+ newRdn: <I>cn=Jane Doe</I>
+</A>
+</PRE>
+<A NAME="1257841">
+OID: <code>2.16.840.1.113730.3.1.9</code><P></A>
+
+<A NAME="1100958">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1126531">
+<A NAME="newSuperior">
+<B>newSuperior</B>
+</a></a>
+<P>
+
+
+<A NAME="1126532">
+This attribute gives the name of the entry which becomes the immediate superior of the existing entry, when processing a modDN operation. For example:<P></A>
+<PRE><A NAME="1126533">
+ newSuperior: <I>cn=Jane Doe</I>
+</A>
+</PRE>
+<A NAME="1257875">
+OID: <code>2.16.840.1.113730.3.1.11</code><P></A>
+
+<A NAME="1126631">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1095332">
+<A NAME="ngcomponent">
+<B>ngcomponent</B>
+</a></a>
+<P>
+
+
+<A NAME="1095333">
+Identifies a part of a the news group name. This attribute is a Netscape extension to the standard LDAP schema. It is used by the Collabra server on <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">nginfo</a> entries to uniquely identify news groups. The format and nature of the information placed on this attribute by the Collabra server is subject to change without notice.<P></A>
+
+<A NAME="1037897">
+For example, the ngcomponent attributes put in place for the comp.sys.mac newsgroup would be:<P></A>
+<PRE><A NAME="1037898">
+ dn: ngcomponent=mac, ngcomponent=sys, ngcomponent=comp,<br> ngcomponent=., <I>o=Example.com<br></I> objectclass: top<br> objectclass: nginfo<br> ngcomponent=mac<br> ngcomponent=sys<br> ngcomponent=comp<br> ngcomponent=.
+</A>
+</PRE>
+<A NAME="1272795">
+OID: <code>2.16.840.1.113730.3.1.196</code><P></A>
+
+<A NAME="1037900">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1036977">
+<A NAME="nsaclrole">
+<B>nsaclrole</B>
+</a></a>
+<P>
+
+
+<A NAME="1037146">
+Identifies the access for individual news group roles (for example, manager, poster, reader, etc). This attribute is a Netscape extension to the standard LDAP schema. It is used by the Collabra server on <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078583">nginfo</a> entries to identify access control for individual news groups. This attribute is used only on the branch point of the ngcomponent subtree. The format and nature of the information placed on this attribute by the Collabra server is subject to change without notice.<P></A>
+
+<A NAME="1036980">
+For example:<P></A>
+<PRE><A NAME="1036981">
+ nsaclrole: admin:aprv
+</A>
+</PRE>
+<A NAME="1272665">
+OID: <code>2.16.840.1.113730.3.1.192</code><P></A>
+
+<A NAME="1036983">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1104932">
+<A NAME="nsCalAccess">
+<B>nsCalAccess</B>
+</a></a>
+<P>
+
+
+<A NAME="1177104">
+This attribute is reserved for future use.<P></A>
+
+<A NAME="1177105">
+Defines whether a calendar user, administrator, or resource should be allowed or denied access to the Calendar server. For example:<P></A>
+<PRE><A NAME="1120940">
+ nsCalAccess: allow
+</A>
+</PRE>
+<A NAME="1270551">
+OID: <code>2.16.840.1.113730.3.1.112</code><P></A>
+
+<A NAME="1104935">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1177696">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server.<P></A>
+<A NAME="1166044">
+<A NAME="nsCalAccessDomain">
+<B>nsCalAccessDomain</B>
+</a></a>
+<P>
+
+
+<A NAME="1177890">
+This attribute is reserved for future use.<P></A>
+
+<A NAME="1166046">
+Contains the Internet domain or IP address from which the calendar user, administrator, or resource is allowed to access calendar data.<P></A>
+<PRE><A NAME="1120977">
+ nsCalAccessDomain: example.com
+</A>
+</PRE>
+<A NAME="1270575">
+OID: <code>2.16.840.1.113730.3.1.113</code><P></A>
+
+<A NAME="1104940">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1177866">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server.<P></A>
+<A NAME="1104994">
+<A NAME="nsCalAdmd">
+<B>nsCalAdmd</B>
+</a></a>
+<P>
+
+
+<A NAME="1161412">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains an X.400 Administration Management Domain Name. For example:<P></A>
+<PRE><A NAME="1120980">
+ nsCalAdmd: telemail
+</A>
+</PRE>
+<A NAME="1270587">
+OID: <code>2.16.840.1.113730.3.1.114</code><P></A>
+
+<A NAME="1104995">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1105005">
+<A NAME="nsCalDefaultNoteReminder">
+<B>nsCalDefaultNoteReminder</B>
+</a></a>
+<P>
+
+
+<A NAME="1162561">
+Defines the type (if any) of note reminder sent to a calendar user. The type of reminder can be none (0), visual (1), or visual and audible (2). The Length of the reminder defines the number of minutes before the note expires that the reminder should be sent to the user. The syntax is <code>type:minutes</code>. For example:<P></A>
+<PRE><A NAME="1162562">
+ nsCalDefaultNoteReminder: 1:10
+</A>
+</PRE>
+<A NAME="1270589">
+OID: <code>2.16.840.1.113730.3.1.115</code><P></A>
+
+<A NAME="1105006">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1174630">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server.<P></A>
+<A NAME="1162428">
+<A NAME="nsCalDefaultReminder">
+<B>nsCalDefaultReminder</B>
+</a></a>
+<P>
+
+
+<A NAME="1162430">
+Defines the type (if any) of event reminder sent to calendar event attendees. The type of reminder can be none (0), visual (1), or visual and audible (2). The Length of the reminder defines the number of minutes before the event that the reminder should be sent to event attendees. For example:<P></A>
+<PRE><A NAME="1162431">
+ nsCalDefaultReminder: 1:10
+</A>
+</PRE>
+<A NAME="1270594">
+OID: <code>2.16.840.1.113730.3.1.116</code><P></A>
+
+<A NAME="1162433">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1175363">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server.<P></A>
+<A NAME="1105139">
+<A NAME="nsCalDefaultTaskReminder">
+<B>nsCalDefaultTaskReminder</B>
+</a></a>
+<P>
+
+
+<A NAME="1162515">
+Defines the type (if any) of task reminder sent to a calendar user. The type of reminder can be none (0), visual (1), or visual and audible (2). The Length of the reminder defines the number of minutes before the task is due that the reminder should be sent to the user. For example:<P></A>
+<PRE><A NAME="1162516">
+ nsCalDefaultTaskReminder: 1:10
+</A>
+</PRE>
+<A NAME="1270608">
+OID: <code>2.16.840.1.113730.3.1.117</code><P></A>
+
+<A NAME="1162518">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1175448">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server.<P></A>
+<A NAME="1105164">
+<A NAME="nsCalDisplayPrefs">
+<B>nsCalDisplayPrefs</B>
+</a></a>
+<P>
+
+
+<A NAME="1161965">
+Contains the display preferences for a calendar user or resource. The syntax of this attribute is <code>Flags:StartDay:EndDay:WeekStart:TimeIncrement:ActiveDays:TimeFormat</code>. Flags is no longer used. StartDay is the time in minutes to start the day display. EndDay is the time in minutes to end the day display. WeekStart specifies the first day of the week displayed in the Calendar client, usually Sunday or Monday. TimeIncrement defines the time increment displayed in minutes. ActiveDays specifies which days to display, for example, weekdays only. TimeFormat specifies the time format (AM/PM or 24 hour) to display. In the following example, <code>4</code> represents flags and is not used. The StartDay value (480) is equivalent to 8am, EndDay (1140) is 7pm, WeekStart (0) is Sunday, the TimeIncrement is 15 minutes, the ActiveDays value is set to all, and the TimeFormat is 24 hour.<P></A>
+<PRE><A NAME="1234997">
+ nsCalDisplayPrefs: 4:480:1140:0:15:127:2
+</A>
+</PRE>
+<A NAME="1270696">
+OID: <code>2.16.840.1.113730.3.1.118</code><P></A>
+
+<A NAME="1161784">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1174421">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server.<P></A>
+<A NAME="1164493">
+<A NAME="nsCalFlags">
+<B>nsCalFlags</B>
+</a></a>
+<P>
+
+
+<A NAME="1164494">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. Reserved for future use.<P></A>
+
+<A NAME="1270698">
+OID: <code>2.16.840.1.113730.3.1.119</code><P></A>
+
+<A NAME="1235001">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1157806">
+<A NAME="nsCalHost">
+<B>nsCalHost</B>
+</a></a>
+<P>
+
+
+<A NAME="1157807">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains the hostname or IP address of the computer hosting the Calendar server. For example:<P></A>
+<PRE><A NAME="1122178">
+ nsCalHost: calserver.example.com
+</A>
+</PRE>
+<A NAME="1270812">
+OID: <code>2.16.840.1.113730.3.1.120</code><P></A>
+
+<A NAME="1105325">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1105333">
+<A NAME="nsCalLanguageId">
+<B>nsCalLanguageId</B>
+</a></a>
+<P>
+
+
+<A NAME="1162674">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute defines the language in which a user, administrator, or resource prefers to receive email notification. For example:<P></A>
+<PRE><A NAME="1122193">
+ nsCalLanguageId: english
+</A>
+</PRE>
+<A NAME="1270838">
+OID: <code>2.16.840.1.113730.3.1.121</code><P></A>
+
+<A NAME="1157843">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1157846">
+<A NAME="nsCalNodeAlias">
+<B>nsCalNodeAlias</B>
+</a></a>
+<P>
+
+
+<A NAME="1157847">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains the mnemonic name of the node on which a calendar user's information is stored. For example:<P></A>
+<PRE><A NAME="1171879">
+ nsCalNodeAlias: node10000
+</A>
+</PRE>
+<A NAME="1270844">
+OID: <code>2.16.840.1.113730.3.1.122</code><P></A>
+
+<A NAME="1118746">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1118755">
+<A NAME="nsCalNotifMechanism">
+<B>nsCalNotifMechanism</B>
+</a></a>
+<P>
+
+
+<A NAME="1162010">
+Specifies the mechanism used to notify calendar event attendees (usually email). Acceptable values for this attribute are <code>1</code> and <code>0</code> where <code>1</code> means that notification is enabled, and <code>0</code> means that notification is disabled. For example:<P></A>
+<PRE><A NAME="1122226">
+ nsCalNotifMechanism: 0
+</A>
+</PRE>
+<A NAME="1270863">
+OID: <code>2.16.840.1.113730.3.1.123</code><P></A>
+
+<A NAME="1118757">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1175516">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server.<P></A>
+<A NAME="1105631">
+<A NAME="nsCalOperatingPrefs">
+<B>nsCalOperatingPrefs</B>
+</a></a>
+<P>
+
+
+<A NAME="1161868">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute defines the operating preferences for a user or resource. Reserved for future use.<P></A>
+
+<A NAME="1270865">
+OID: <code>2.16.840.1.113730.3.1.124</code><P></A>
+
+<A NAME="1161820">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1105739">
+<A NAME="nsCalOrgUnit2">
+<B>nsCalOrgUnit2</B>
+</a></a>
+<P>
+
+
+<A NAME="1161561">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains the X.400 Organization Unit 2 (OU2) for a user or administrator. For example:<P></A>
+<PRE><A NAME="1122284">
+ nsCalOrgUnit2: marketing
+</A>
+</PRE>
+<A NAME="1270887">
+OID: <code>2.16.840.1.113730.3.1.125</code><P></A>
+
+<A NAME="1105740">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1105752">
+<A NAME="nsCalOrgUnit3">
+<B>nsCalOrgUnit3</B>
+</a></a>
+<P>
+
+
+<A NAME="1161594">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains the X.400 Organization Unit 3 (OU3) for a user or administrator. For example:<P></A>
+<PRE><A NAME="1122291">
+ nsCalOrgUnit3: sales
+</A>
+</PRE>
+<A NAME="1270897">
+OID: <code>2.16.840.1.113730.3.1.126</code><P></A>
+
+<A NAME="1105753">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1105815">
+<A NAME="nsCalOrgUnit4">
+<B>nsCalOrgUnit4</B>
+</a></a>
+<P>
+
+
+<A NAME="1164929">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains the X.400 Organization Unit 4 (OU4) for a user or administrator. For example:<P></A>
+<PRE><A NAME="1164930">
+ nsCalOrgUnit4: engineering
+</A>
+</PRE>
+<A NAME="1270918">
+OID: <code>2.16.840.1.113730.3.1.127</code><P></A>
+
+<A NAME="1105816">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1105834">
+<A NAME="nsCalPasswordRequired">
+<B>nsCalPasswordRequired</B>
+</a></a>
+<P>
+
+
+<A NAME="1162629">
+Specifies whether a calendar user must supply a password to access calendar data. Acceptable values are <code>1</code> and <code>0</code>; where <code>1</code> means a password is required, and <code>0</code> means that no password is required. For example:<P></A>
+<PRE><A NAME="1122383">
+ nsCalPasswordRequired: 1
+</A>
+</PRE>
+<A NAME="1270965">
+OID: <code>2.16.840.1.113730.3.1.128</code><P></A>
+
+<A NAME="1105835">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1175590">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server.<P></A>
+<A NAME="1105891">
+<A NAME="nsCalPrmd">
+<B>nsCalPrmd</B>
+</a></a>
+<P>
+
+
+<A NAME="1271009">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains the X.400 Private Management Domain Name for a user or administrator. For example:<P></A>
+<PRE><A NAME="1271010">
+ nsCalPrmd: example
+</A>
+</PRE>
+<A NAME="1271034">
+OID: <code>2.16.840.1.113730.3.1.129</code><P></A>
+
+<A NAME="1271012">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1105943">
+<A NAME="nsCalRefreshPrefs">
+<B>nsCalRefreshPrefs</B>
+</a></a>
+<P>
+
+
+<A NAME="1165339">
+The attribute defines whether the user's preferences should be refreshed and how often. The syntax for this attribute is <code>on/off:minutes</code>. Acceptable values for <code>on/off</code> are <code>1</code> and <code>0</code>; where <code>1</code> means preferences will be refreshed, and <code>0</code> means preferences won't be refreshed. If the <code>on/off</code> value is set to <code>1</code>, the refresh interval is entered in minutes. In the following example, nsCalRefreshPrefs is set to off:<P></A>
+<PRE><A NAME="1171900">
+ nsCalRefreshPrefs: 0:0
+</A>
+</PRE>
+<A NAME="1271056">
+OID: <code>2.16.840.1.113730.3.1.130</code><P></A>
+
+<A NAME="1105944">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1173593">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server.<P></A>
+<A NAME="1105996">
+<A NAME="nsCalResourceCapacity">
+<B>nsCalResourceCapacity</B>
+</a></a>
+<P>
+
+
+<A NAME="1163461">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute defines the capacity of a resource, for example, a conference room. For example:<P></A>
+<PRE><A NAME="1122484">
+ nsCalResourceCapacity: 65
+</A>
+</PRE>
+<A NAME="1271073">
+OID: <code>2.16.840.1.113730.3.1.131</code><P></A>
+
+<A NAME="1209240">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1209242">
+<A NAME="nsCalResourceNumber">
+<B>nsCalResourceNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1209244">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains the resource's identification number. For example:<P></A>
+<PRE><A NAME="1165759">
+ nsCalResourceNumber: 6725
+</A>
+</PRE>
+<A NAME="1271092">
+OID: <code>2.16.840.1.113730.3.1.132</code><P></A>
+
+<A NAME="1106037">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1106093">
+<A NAME="nsCalServerVersion">
+<B>nsCalServerVersion</B>
+</a></a>
+<P>
+
+
+<A NAME="1160060">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains the version number of the Calendar server hosting the calendar user's data. For example:<P></A>
+<PRE><A NAME="1122498">
+ nsCalServerVersion: 1.0
+</A>
+</PRE>
+<A NAME="1271164">
+OID: <code>2.16.840.1.113730.3.1.133</code><P></A>
+
+<A NAME="1106094">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1106115">
+<A NAME="nsCalSysopCanWritePassword">
+<B>nsCalSysopCanWritePassword</B>
+</a></a>
+<P>
+
+
+<A NAME="1162650">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute specifies whether the Calendar server administrator can overwrite user, resource, and other administrator passwords. Acceptable values for this attribute are <code>1</code> and <code>0</code> where <code>1</code> means the administrator can overwrite passwords, and <code>0</code> means that the administrator cannot overwrite passwords. For example:<P></A>
+<PRE><A NAME="1171915">
+ nsCalSysopCanWritePassword: 1
+</A>
+</PRE>
+<A NAME="1271166">
+OID: <code>2.16.840.1.113730.3.1.134</code><P></A>
+
+<A NAME="1106116">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1106160">
+<A NAME="nsCalTimezone">
+<B>nsCalTimezone</B>
+</a></a>
+<P>
+
+
+<A NAME="1162695">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains the current timezone in which the entry is located. For example:<P></A>
+<PRE><A NAME="1122560">
+ nsCalTimezone: PST
+</A>
+</PRE>
+<A NAME="1271168">
+OID: <code>2.16.840.1.113730.3.1.135</code><P></A>
+
+<A NAME="1106161">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1106218">
+<A NAME="nsCalXItemId">
+<B>nsCalXItemId</B>
+</a></a>
+<P>
+
+
+<A NAME="1159973">
+This attribute is a Netscape extension to the standard LDAP schema used by the Calendar server. The attribute contains a unique identifier for an nsCalendarObject represented in the directory. This identification is composed of the identification number of the node on which the calendar user, administrator, or resource's data is stored, and the identification number of the calendar user, administrator, or resource. The format should be <code>NodeId,ItemId</code>. For example:<P></A>
+<PRE><A NAME="1159974">
+ nsCalXItemId: 123,6547
+</A>
+</PRE>
+<A NAME="1271216">
+OID: <code>2.16.840.1.113730.3.1.136</code><P></A>
+
+<A NAME="1106219">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1037693">
+<A NAME="nscreator">
+<B>nscreator</B>
+</a></a>
+<P>
+
+
+<A NAME="1037694">
+Identifies the creator of a news group. This attribute is a Netscape extension to the standard LDAP schema that is used by the Collabra server on <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078583">nginfo</a> entries to identify a news group creator's uid. The format and nature of the information placed on this attribute by the Collabra server is subject to change without notice.<P></A>
+
+<A NAME="1037696">
+For example:<P></A>
+<PRE><A NAME="1037697">
+ nscreator: admin
+</A>
+</PRE>
+<A NAME="1272746">
+OID: <code>2.16.840.1.113730.3.1.195</code><P></A>
+
+<A NAME="1037699">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1037564">
+<A NAME="nsflags">
+<B>nsflags</B>
+</a></a>
+<P>
+
+
+<A NAME="1037565">
+Reserved for future use.<P></A>
+
+<A NAME="1272737">
+OID: <code>2.16.840.1.113730.3.1.194</code><P></A>
+
+<A NAME="1037567">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1091847">
+<A NAME="nsLicensedFor">
+<B>nsLicensedFor</B>
+</a></a>
+<P>
+
+
+<A NAME="1091848">
+Identifies the Netscape server that the user is licensed to use. The Netscape Administration Server expects each <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">nsLicenseUser</a> entry to contain zero or more instances of this attribute. Valid keywords for this attribute are currently:<P></A>
+<ul><A NAME="1091850">
+<LI>mail -- the user is a licensed client of the Messaging Server.<P>
+</A>
+<A NAME="1091851">
+<LI>news -- the user is a licensed client of the Collabra Server.<P>
+</A>
+<A NAME="1091852">
+<LI>slapd -- the user is a licensed client of the Directory Server.<P>
+</A>
+<A NAME="1091853">
+<LI>cal -- the user is a licensed client of the Calendar server.<P>
+</A>
+</ul>
+<A NAME="1091854">
+For example:<P></A>
+<PRE><A NAME="1091855">
+ nsLicensedFor: slapd
+</A>
+</PRE>
+<A NAME="1257889">
+OID: <code>2.16.840.1.113730.3.1.36</code><P></A>
+
+<A NAME="1091857">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1091859">
+<A NAME="nsLicenseStartTime">
+<B>nsLicenseStartTime</B>
+</a></a>
+<P>
+
+
+<A NAME="1091860">
+Reserved for future use.<P></A>
+
+<A NAME="1257896">
+OID: <code>2.16.840.1.113730.3.1.37</code><P></A>
+
+<A NAME="1091862">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1091864">
+<A NAME="nsLicenseEndTime">
+<B>nsLicenseEndTime</B>
+</a></a>
+<P>
+
+
+<A NAME="1091865">
+Reserved for future use.<P></A>
+
+<A NAME="1257974">
+OID: <code>2.16.840.1.113730.3.1.38</code><P></A>
+
+<A NAME="1091867">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1092030">
+<A NAME="nsnewsACL">
+<B>nsnewsACL</B>
+</a></a>
+<P>
+
+
+<A NAME="1092031">
+Identifies the access control set for individual news groups. This attribute is a Netscape extension to the standard LDAP schema. It is used by the Collabra server on <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">nginfo</a> entries to identify access control for individual news groups. The format and nature of the information placed on this attribute by the Collabra server is subject to change without notice.<P></A>
+
+<A NAME="1092033">
+For example:<P></A>
+<PRE><A NAME="1092034">
+ nsnewsACL: 2:*:a:D::admin:bpolk::d:*:a:D::manager:admin::d:
+</A>
+</PRE>
+<A NAME="1272650">
+OID: <code>2.16.840.1.113730.3.1.191</code><P></A>
+
+<A NAME="1092036">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1037277">
+<A NAME="nsprettyname">
+<B>nsprettyname</B>
+</a></a>
+<P>
+
+
+<A NAME="1037278">
+Identifies the pretty name or display name for the news group. This attribute is a Netscape extension to the standard LDAP schema that is used by the Collabra server on <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">nginfo</a> entries to identify individual news groups. The format and nature of the information placed on this attribute by the Collabra server is subject to change without notice.<P></A>
+
+<A NAME="1037280">
+For example:<P></A>
+<PRE><A NAME="1037281">
+ nsprettyname: MKTG FOR RACHU
+</A>
+</PRE>
+<A NAME="1272668">
+OID: <code>2.16.840.1.113730.3.1.193</code><P></A>
+
+<A NAME="1037283">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1122623">
+<A NAME="ntGroupAttributes">
+<B>ntGroupAttributes</B>
+</a></a>
+<P>
+
+
+<A NAME="1122625">
+Reserved for use by the NT synchronization service to store the attributes of an NT group.<P></A>
+
+<A NAME="1262720">
+OID: <code>1.2.840.113556.1.4.152</code><P></A>
+
+<A NAME="1251757">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1122633">
+<A NAME="ntGroupCreateNewGroup">
+<B>ntGroupCreateNewGroup</B>
+</a></a>
+<P>
+
+
+<A NAME="1122635">
+Reserved for use by the NT synchronization service.<P></A>
+
+<A NAME="1258152">
+OID: <code>2.16.840.1.113730.3.1.45</code><P></A>
+
+<A NAME="1258154">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">Syntax: cis</a><P></A>
+<A NAME="1103799">
+<A NAME="ntGroupDeleteGroup">
+<B>ntGroupDeleteGroup</B>
+</a></a>
+<P>
+
+
+<A NAME="1103800">
+Reserved for use by the NT synchronization service.<P></A>
+
+<A NAME="1258186">
+OID: <code>2.16.840.1.113730.3.1.46</code><P></A>
+
+<A NAME="1258188">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">Syntax: cis</a><P></A>
+<A NAME="1103684">
+<A NAME="ntGroupDomainId">
+<B>ntGroupDomainId</B>
+</a></a>
+<P>
+
+
+<A NAME="1103686">
+Used by the NT synchronization service to store the NT Global Groupname/Domain.<P></A>
+
+<A NAME="1258086">
+OID: <code>2.16.840.1.113730.3.1.44</code><P></A>
+
+<A NAME="1251773">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">Syntax: cis</a><P></A>
+<A NAME="1104232">
+<A NAME="ntGroupId">
+<B>ntGroupId</B>
+</a></a>
+<P>
+
+
+<A NAME="1104233">
+Undefined. <P></A>
+
+<A NAME="1260150">
+OID: <code>2.16.840.1.113730.3.1.110</code><P></A>
+
+<A NAME="1104234">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">Syntax: </a>bin<P></A>
+<A NAME="1283379">
+<A NAME="ntGroupType">
+<B>ntGroupType</B>
+</a></a>
+<P>
+
+
+<A NAME="1283380">
+Two valid values are global or local<P></A>
+
+<A NAME="1283381">
+OID: <code>2.16.840.1.113730.3.1.47</code><P></A>
+
+<A NAME="1283383">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">Syntax: </a>cis<P></A>
+<A NAME="1013839">
+<A NAME="ntUserAcctExpires">
+<B>ntUserAcctExpires</B>
+</a></a>
+<P>
+
+
+<A NAME="1013857">
+Indicates when the entry's Windows NT account will expire. This value is stored as a string in GMT format. For example:<P></A>
+<PRE><A NAME="1013887">
+ ntUserAcctExpires: 19961015203415Z
+</A>
+</PRE>
+<A NAME="1262459">
+OID: <code>1.2.840.113556.1.4.159</code><P></A>
+
+<A NAME="1024626">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1014052">
+<A NAME="ntUserAuthFlags">
+<B>ntUserAuthFlags</B>
+</a></a>
+<P>
+
+
+<A NAME="1014053">
+Identifies an unsigned long integer that contains the entry's operator privileges on the Windows network. For example:<P></A>
+<PRE><A NAME="1038769">
+ ntUserAuthFlags: AAAAAA==
+</A>
+</PRE>
+<A NAME="1258686">
+OID: <code>2.16.840.1.113730.3.1.60</code><P></A>
+
+<A NAME="1038770">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1038772">
+<A NAME="ntUserBadPwCount">
+<B>ntUserBadPwCount</B>
+</a></a>
+<P>
+
+
+<A NAME="1014169">
+Identifies the number of attempts to log on to the Windows account using an incorrect password. A value of 0xFFFFFFFF represents that the value is unknown. For example:<P></A>
+<PRE><A NAME="1014915">
+ ntUserBadPwCount: AAAAAA==
+</A>
+</PRE>
+<A NAME="1262557">
+OID: <code>1.2.840.113556.1.4.12</code><P></A>
+
+<A NAME="1038807">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1014973">
+<A NAME="ntUserCodePage">
+<B>ntUserCodePage</B>
+</a></a>
+<P>
+
+
+<A NAME="1014989">
+Code page for the user's language of choice. For example:<P></A>
+<PRE><A NAME="1015015">
+ ntUserCodePage: AAAAAA==
+</A>
+</PRE>
+<A NAME="1262625">
+OID: <code>1.2.840.113556.1.4.16</code><P></A>
+
+<A NAME="1246827">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1246829">
+<A NAME="ntUserComment">
+<B>ntUserComment</B>
+</a></a>
+<P>
+
+
+<A NAME="1246830">
+ASCII string representing a description or comments about this entry. For example:<P></A>
+<PRE><A NAME="1015193">
+ ntUserComment: Quality control inspector for the ME2873 <br> product line
+</A>
+</PRE>
+<A NAME="1261310">
+OID: <code>1.2.840.113556.1.4.156</code><P></A>
+
+<A NAME="1038675">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1015155">
+<A NAME="ntUserCountryCode">
+<B>ntUserCountryCode</B>
+</a></a>
+<P>
+
+
+<A NAME="1015217">
+Country code for the user's language of choice. For example:<P></A>
+<PRE><A NAME="1015224">
+ ntUserCountryCode: AAAAAA==
+</A>
+</PRE>
+<A NAME="1262579">
+OID: <code>1.2.840.113556.1.4.25</code><P></A>
+
+<A NAME="1038682">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1015239">
+<A NAME="ntUserCreateNewAccount">
+<B>ntUserCreateNewAccount</B>
+</a></a>
+<P>
+
+
+<A NAME="1015245">
+Indicates whether a corresponding NT user account should be created for the new person entry in the Directory Server. ntUserCreateNewAccount can be edited from Directory Server. If ntUserCreateNewAccount is set to True and an NT account does not exist for the specified user name, an NT account will be created. If the attribute is set to False and an NT account does not exist, an error will be logged. If an NT account exists and the attribute is set to False, the existing NT account will be updated. For example:<P></A>
+<PRE><A NAME="1015264">
+ ntUserCreateNewAccount: true
+</A>
+</PRE>
+<A NAME="1258018">
+OID: <code>2.16.840.1.113730.3.1.42</code><P></A>
+
+<A NAME="1258029">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1015309">
+<A NAME="ntUserDeleteAccount">
+<B>ntUserDeleteAccount</B>
+</a></a>
+<P>
+
+
+<A NAME="1015321">
+Indicates whether the NT user account should be deleted when the entry is deleted from the Directory Server. ntUserDeleteAccount can be edited from Directory Server. If the attribute is set to true, the NT user account will be deleted if the entry is deleted from the Directory Server. If the attribute is set to false, the NT user account will not be deleted. See "Deleting NTUser entries" for more information on deleting ntUser entries. For example:<P></A>
+<PRE><A NAME="1015367">
+ ntUserDeleteAccount: true
+</A>
+</PRE>
+<A NAME="1258034">
+OID: <code>2.16.840.1.113730.3.1.43</code><P></A>
+
+<A NAME="1038688">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1015403">
+<A NAME="ntUserDomainId">
+<B>ntUserDomainId</B>
+</a></a>
+<P>
+
+
+<A NAME="1015422">
+Identifies the NT domain name and user name of the entry in the form NT-domain-name:NT-username. NTUserDomainId can be edited from the Directory Server. For example:<P></A>
+<PRE><A NAME="1015476">
+ ntUserDomainId: workgroup:jsmith
+</A>
+</PRE>
+<A NAME="1258011">
+OID: <code>2.16.840.1.113730.3.1.41</code><P></A>
+
+<A NAME="1038691">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1015534">
+<A NAME="ntUserFlags">
+<B>ntUserFlags</B>
+</a></a>
+<P>
+
+
+<A NAME="1015550">
+Identifies values that determine several features about the user and their account. For example:<P></A>
+<PRE><A NAME="1015561">
+ ntUserFlags: AQIBAA==
+</A>
+</PRE>
+<A NAME="1262345">
+OID: <code>1.2.840.113556.1.4.38</code><P></A>
+
+<A NAME="1038821">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1015584">
+<A NAME="ntUserHomeDir">
+<B>ntUserHomeDir</B>
+</a></a>
+<P>
+
+
+<A NAME="1015596">
+ASCII string that represents the path of the user's home directory. The string can be null. For example:<P></A>
+<PRE><A NAME="1015610">
+ ntUserHomeDir: c:\u\d78\jsmith\
+</A>
+</PRE>
+<A NAME="1261296">
+OID: <code>1.2.840.113556.1.4.44</code><P></A>
+
+<A NAME="1038694">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1015624">
+<A NAME="ntUserHomeDirDrive">
+<B>ntUserHomeDirDrive</B>
+</a></a>
+<P>
+
+
+<A NAME="1015648">
+ASCII string that represents the drive letter assigned to the user's home directory. For example:<P></A>
+<PRE><A NAME="1015659">
+ ntUserHomeDirDrive: c:
+</A>
+</PRE>
+<A NAME="1262717">
+OID: <code>1.2.840.113556.1.4.45</code><P></A>
+
+<A NAME="1038697">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1015682">
+<A NAME="ntUserLastLogoff">
+<B>ntUserLastLogoff</B>
+</a></a>
+<P>
+
+
+<A NAME="1015726">
+Identifies the time of the last logoff. This value is stored as a string in GMT format. For example:<P></A>
+<PRE><A NAME="1015727">
+ ntUserLastLogoff: 19961015203415Z
+</A>
+</PRE>
+<A NAME="1019703">
+Note that if security logging is turned on, then this attribute is updated on synchronization only if some other aspect of the user's entry has changed.<P></A>
+
+<A NAME="1262403">
+OID: <code>1.2.840.113556.1.4.51</code><P></A>
+
+<A NAME="1038700">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1015722">
+<A NAME="ntUserLastLogon">
+<B>ntUserLastLogon</B>
+</a></a>
+<P>
+
+
+<A NAME="1015750">
+Identifies the time of the last logon. This value is stored as a string in GMT format. For example:<P></A>
+<PRE><A NAME="1015751">
+ ntUserLastLogon: 19961015203415Z
+</A>
+</PRE>
+<A NAME="1019919">
+Note that if security logging is turned on, then this attribute is updated on synchronization only if some other aspect of the user's entry has changed.<P></A>
+
+<A NAME="1262390">
+OID: <code>1.2.840.113556.1.4.52</code><P></A>
+
+<A NAME="1038703">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1015746">
+<A NAME="ntUserLogonHours">
+<B>ntUserLogonHours</B>
+</a></a>
+<P>
+
+
+<A NAME="1015787">
+Identifies the times during which the user may log on. Time is represented by a one-to-one correspondence between the hour of the week and a bit within the string. For example, bit 0 word 0 is Sunday, 0:00 to 0:59. Bit 1 word 0 is Sunday, 1:00 to 1:59, etc. For example:<P></A>
+<PRE><A NAME="1015803">
+ ntUserLogonHours: ///1000011100000101111111...
+</A>
+</PRE>
+<A NAME="1019921">
+Note that if security logging is turned on, then this attribute is updated on synchronization only if some other aspect of the user's entry has changed.<P></A>
+
+<A NAME="1262547">
+OID: <code>1.2.840.113556.1.4.64</code><P></A>
+
+<A NAME="1038824">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1015839">
+<A NAME="ntUserLogonServer">
+<B>ntUserLogonServer</B>
+</a></a>
+<P>
+
+
+<A NAME="1015859">
+ASCII string that represents the name of the server to which the user's logon requests are sent. Server names should be preceded by two backslashes (\\). Server names of \\* indicate that the logon request can be handled by any logon server. A null string represents that requests are sent to the domain controller. For example:<P></A>
+<PRE><A NAME="1015953">
+ ntUserLogonServer: \\firefly
+</A>
+</PRE>
+<A NAME="1259015">
+OID: <code>2.16.840.1.113730.3.1.65</code><P></A>
+
+<A NAME="1038706">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1015984">
+<A NAME="ntUserMaxStorage">
+<B>ntUserMaxStorage</B>
+</a></a>
+<P>
+
+
+<A NAME="1015997">
+Maximum amount of disk space the user may use. For example:<P></A>
+<PRE><A NAME="1016004">
+ ntUserMaxStorage: ///////W==
+</A>
+</PRE>
+<A NAME="1262471">
+OID: <code>1.2.840.113556.1.4.76</code><P></A>
+
+<A NAME="1038827">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1016030">
+<A NAME="ntUserNumLogons">
+<B>ntUserNumLogons</B>
+</a></a>
+<P>
+
+
+<A NAME="1016043">
+Identifies the number of successful logons to this account. A value of 0xFFFFFFFF indicates the value is unknown. For example:<P></A>
+<PRE><A NAME="1016085">
+ ntUserNumLogons: WwAAAA==
+</A>
+</PRE>
+<A NAME="1258789">
+OID: <code>2.16.840.1.113730.3.1.64</code><P></A>
+
+<A NAME="1038830">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1021575">
+<A NAME="ntUserParms">
+<B>ntUserParms</B>
+</a></a>
+<P>
+
+
+<A NAME="1021584">
+Unicode string reserved for use by applications. For example:<P></A>
+<PRE><A NAME="1021587">
+ ntUserParms: Temp date is today
+</A>
+</PRE>
+<A NAME="1258702">
+OID: <code>2.16.840.1.113730.3.1.62</code><P></A>
+
+<A NAME="1038709">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1016157">
+<A NAME="ntUserPasswordExpired">
+<B>ntUserPasswordExpired</B>
+</a></a>
+<P>
+
+
+<A NAME="1259827">
+Identifies if the user's NT password has expired. The value will be zero if the password has not expired, or nonzero if it has. For example:<P></A>
+<PRE><A NAME="1259828">
+ ntUserPasswordExpired: AAAAAA==
+</A>
+</PRE>
+<A NAME="1259829">
+OID: <code>2.16.840.1.113730.3.1.68</code><P></A>
+
+<A NAME="1038833">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1016246">
+<A NAME="ntUserPrimaryGroupId">
+<B>ntUserPrimaryGroupId</B>
+</a></a>
+<P>
+
+
+<A NAME="1016259">
+Identifies the relative ID (RID) of the Primary Global Group for the user. For example:<P></A>
+<PRE><A NAME="1016262">
+ ntUserPrimaryGroupId: AQJAAA==
+</A>
+</PRE>
+<A NAME="1262706">
+OID: <code>1.2.840.113556.1.4.98</code><P></A>
+
+<A NAME="1038836">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1017849">
+<A NAME="ntUserPriv">
+<B>ntUserPriv</B>
+</a></a>
+<P>
+
+
+<A NAME="1017863">
+Identifies the user's level of privilege on the Window's NT Network. For example:<P></A>
+<PRE><A NAME="1017866">
+ ntUserPriv: AgAAAA==
+</A>
+</PRE>
+<A NAME="1258612">
+OID: <code>2.16.840.1.113730.3.1.59</code><P></A>
+
+<A NAME="1038839">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1016298">
+<A NAME="ntUserProfile">
+<B>ntUserProfile</B>
+</a></a>
+<P>
+
+
+<A NAME="1016315">
+Identifies a path to the user's profile. For example:<P></A>
+<PRE><A NAME="1016326">
+ ntUserProfile: c:\u\d78\jsmith\profile.txt
+</A>
+</PRE>
+<A NAME="1259082">
+OID: <code>2.16.840.1.113730.3.1.67</code><P></A>
+
+<A NAME="1038712">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1016395">
+<A NAME="ntUserScriptPath">
+<B>ntUserScriptPath</B>
+</a></a>
+<P>
+
+
+<A NAME="1016433">
+ASCII string that represents the path to the user's logon script. For example:<P></A>
+<PRE><A NAME="1016470">
+ ntUserScriptPath: c:\u\d78\jsmith\lscript.bat
+</A>
+</PRE>
+<A NAME="1262363">
+OID: <code>1.2.840.113556.1.4.62</code><P></A>
+
+<A NAME="1038715">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1016531">
+<A NAME="ntUserUniqueId">
+<B>ntUserUniqueId</B>
+</a></a>
+<P>
+
+
+<A NAME="1016564">
+Identifies the unique identifier of an NT user. The identifier uniquely identifies the user to SAM within the domain for all time. For example:<P></A>
+<PRE><A NAME="1016605">
+ ntUserUniqueId: 6AMAAA==
+</A>
+</PRE>
+<A NAME="1259068">
+OID: <code>2.16.840.1.113730.3.1.66</code><P></A>
+
+<A NAME="1038842">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1016632">
+<A NAME="ntUserUnitsPerWeek">
+<B>ntUserUnitsPerWeek</B>
+</a></a>
+<P>
+
+
+<A NAME="1016672">
+Identifies the number of equal length time units to divide the week into in order to compute the length of ntUserLogonHours. For example:<P></A>
+<PRE><A NAME="1016675">
+ ntUserUnitsPerWeek: qAAAAA==
+</A>
+</PRE>
+<A NAME="1258767">
+OID: <code>2.16.840.1.113730.3.1.63</code><P></A>
+
+<A NAME="1038845">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><P></A>
+<A NAME="1016696">
+<A NAME="ntUserUsrComment">
+<B>ntUserUsrComment</B>
+</a></a>
+<P>
+
+
+<A NAME="1016715">
+ASCII string representing a description or comments about this entry. For example:<P></A>
+<PRE><A NAME="1016716">
+ ntUserUsrComment: Quality control inspector for the ME2873 <br> product line
+</A>
+</PRE>
+<A NAME="1262251">
+OID: <code>2.16.840.1.113730.3.1.61</code><P></A>
+
+<A NAME="1038718">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1016728">
+<A NAME="ntUserWorkstations">
+<B>ntUserWorkstations</B>
+</a></a>
+<P>
+
+
+<A NAME="1016750">
+ASCII string that represents the names of workstations from which the user may log on. Up to eight workstations may be specified by separating each with a comma. Use null to allow the user to log on from any workstation. For example:<P></A>
+<PRE><A NAME="1016869">
+ ntUserWorkstations: firefly
+</A>
+</PRE>
+<A NAME="1262383">
+OID: <code>1.2.840.113556.1.4.86</code><P></A>
+
+<A NAME="1038721">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><P></A>
+<A NAME="1281611">
+<A NAME="o">
+<B>o</B>
+</a></a>
+<P>
+
+
+<A NAME="1281612">
+Identifies the name of the organization. For example:<P></A>
+<PRE><A NAME="1281613">
+ organizationName: Example, Inc.
+</A>
+</PRE>
+<A NAME="1281614">
+or:<P></A>
+<PRE><A NAME="1281615">
+ o: Example, Inc
+</A>
+</PRE>
+<A NAME="1281616">
+Abbreviation: o<P></A>
+
+<A NAME="1281617">
+OID: <code>2.5.4.10</code><P></A>
+
+<A NAME="1281619">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1229677">
+<A NAME="objectClass">
+<B>objectClass</B>
+</a></a>
+<P>
+
+
+<A NAME="1229678">
+Reserved for use by the Directory Server.<P></A>
+
+<A NAME="1229681">
+OID: <code>2.5.4.0</code><P></A>
+
+<A NAME="1266934">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1242815">
+<A NAME="objectClasses">
+<B>objectClasses</B>
+</a></a>
+<P>
+
+
+<A NAME="1291515">
+Operational, multi-valued attribute that defines the object classes used in a subschema. Each value defines one object class. <P></A>
+
+<A NAME="1263050">
+OID: <code>2.5.21.6</code><P></A>
+
+<A NAME="1242819">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1202192">
+<A NAME="obsoletedByDocument">
+<B>obsoletedByDocument</B>
+</a></a>
+<P>
+
+
+<A NAME="1202193">
+Contains the distinguished name of a document that obsoletes the document entry.<P></A>
+
+<A NAME="1272886">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1202199">
+<A NAME="obsoletesDocument">
+<B>obsoletesDocument</B>
+</a></a>
+<P>
+
+
+<A NAME="1217320">
+Contains the distinguished name of a document that is obsoleted by the document entry.<P></A>
+
+<A NAME="1202203">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1281714">
+<A NAME="organizationalStatus">
+<B>organizationalStatus</B>
+</a></a>
+<P>
+
+
+<A NAME="1214388">
+Specifies a category by which a person is often referred to in an organization. For example:<P></A>
+<PRE><A NAME="1214389">
+ organizationalStatus: researcher
+</A>
+</PRE>
+<A NAME="1266110">
+OID: <code>0.9.2342.19200300.100.1.45</code><P></A>
+
+<A NAME="1240989">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202220">
+<A NAME="otherMailbox">
+<B>otherMailbox</B>
+</a></a>
+<P>
+
+
+<A NAME="1214414">
+Specifies values for electronic mailbox types other than X.400 and rfc822. For example:<P></A>
+<PRE><A NAME="1202222">
+ otherMailbox: internet $ jdoe@example.com
+</A>
+</PRE>
+<A NAME="1264574">
+OID: <code>0.9.2342.19200300.100.1.22</code><P></A>
+
+<A NAME="1202224">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1241174">
+<A NAME="ou">
+<B>ou</B>
+</a></a>
+<P>
+
+
+<A NAME="1241175">
+Identifies the name of an organizational unit.For example:<P></A>
+<PRE><A NAME="1241176">
+ organizationUnitName: Marketing
+</A>
+</PRE>
+<A NAME="1241177">
+or:<P></A>
+<PRE><A NAME="1241178">
+ ou: Marketing
+</A>
+</PRE>
+<A NAME="1241180">
+Abbreviation: ou<P></A>
+
+<A NAME="1267161">
+OID: <code>2.5.4.11</code><P></A>
+
+<A NAME="1241182">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1005719">
+<A NAME="owner">
+<B>owner</B>
+</a></a>
+<P>
+
+
+<A NAME="1005732">
+Identifies the distinguished name (DN) of the person responsible for the entry. For example:<P></A>
+<PRE><A NAME="1005743">
+ owner: <I>cn=John Smith, o=Netscape Communications Corp., c=US</I>
+</A>
+</PRE>
+<A NAME="1267977">
+OID: <code>2.5.4.32</code><P></A>
+
+<A NAME="1005754">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1003070">
+<A NAME="pager">
+<B>pager</B>
+</a></a>
+<P>
+
+
+<A NAME="1003071">
+Identifies the entry's pager phone number. For example:<P></A>
+<PRE><A NAME="1003777">
+ pagerTelephoneNumber: 415-555-6789
+</A>
+</PRE>
+<A NAME="1011248">
+or:<P></A>
+<PRE><A NAME="1011258">
+ pager: 415-555-6789
+</A>
+</PRE>
+<A NAME="1003795">
+Abbreviation: pager<P></A>
+
+<A NAME="1264789">
+OID: <code>0.9.2342.19200300.100.1.42</code><P></A>
+
+<A NAME="1011303">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004703">tel</a><P></A>
+<A NAME="1157269">
+<A NAME="passwordChange">
+<B>passwordChange</B>
+</a></a>
+<P>
+
+
+<A NAME="1157270">
+Defines whether or not users must, may, or can't change passwords. Valid values include <code>must</code>, <code>may</code>, and <code>no</code>. A value of <code>must</code> means that users will be required to change their password at a designated interval. A value of <code>may</code> indicates that users can change their password. A value of <code>no</code> means that users cannot change their password. For example:<P></A>
+<PRE><A NAME="1157271">
+ passwordChange: <code>no</code>
+</A>
+</PRE>
+<A NAME="1263605">
+OID: <code>2.16.840.1.113730.3.1.102</code><P></A>
+
+<A NAME="1157273">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1157285">
+<A NAME="passwordCheckSyntax">
+<B>passwordCheckSyntax</B>
+</a></a>
+<P>
+
+
+<A NAME="1157402">
+Defines whether password syntax checking is on or off. Acceptable values are <code>1</code> and <code>0</code>; where <code>1</code> means syntax checking is on, and <code>0</code> means that syntax checking is off. For example:<P></A>
+<PRE><A NAME="1157287">
+ passwordCheckSyntax: 0
+</A>
+</PRE>
+<A NAME="1263576">
+OID: <code>2.16.840.1.113730.3.1.103</code><P></A>
+
+<A NAME="1157289">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1155167">
+<A NAME="passwordExp">
+<B>passwordExp</B>
+</a></a>
+<P>
+
+
+<A NAME="1155169">
+Defines whether or not user passwords expire. Acceptable values are <code>1</code> and <code>0</code>; where <code>1</code> means passwords expire, and <code>0</code> means that passwords never expire. For example:<P></A>
+<PRE><A NAME="1155249">
+ passwordExp: 0
+</A>
+</PRE>
+<A NAME="1263339">
+OID: <code>2.16.840.1.113730.3.1.98</code><P></A>
+
+<A NAME="1155171">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1246156">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1103904">
+<A NAME="passwordExpirationTime">
+<B>passwordExpirationTime</B>
+</a></a>
+<P>
+
+
+<A NAME="1166092">
+Defines, in seconds, the time until a user's password expires.<P></A>
+<PRE><A NAME="1166093">
+ passwordExpirationTime: 8640000
+</A>
+</PRE>
+<A NAME="1259845">
+OID: <code>2.16.840.1.113730.3.1.91</code><P></A>
+
+<A NAME="1104141">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+
+<A NAME="1166110">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1293088">
+<A NAME="passwordExpWarned">
+<B>passwordExpWarned</B>
+</a></a>
+<P>
+
+
+<A NAME="1293090">
+Used by the Directory Server to keep track of password expiration warnings sent to a user. Acceptable values are <code>1</code> and <code>0</code>; where <code>1</code> indicates that a warning has been sent to the user, and <code>0</code> means that no warning has been sent. For example:<P></A>
+<PRE><A NAME="1293091">
+ passwordExpWarned: 0
+</A>
+</PRE>
+<A NAME="1293092">
+OID: <code>2.16.840.1.113730.3.1.92</code><P></A>
+
+<A NAME="1293095">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1104144">
+<A NAME="passwordHistory">
+<B>passwordHistory</B>
+</a></a>
+<P>
+
+
+<A NAME="1155016">
+Contains a history of the user's passwords. For example:<P></A>
+<PRE><A NAME="1287441">
+ passwordHistory: AAAAAA==
+</A>
+</PRE>
+<A NAME="1259973">
+OID: <code>2.16.840.1.113730.3.1.96</code><P></A>
+
+<A NAME="1104110">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+
+<A NAME="1166119">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1104470">
+<A NAME="passwordInHistory">
+<B>passwordInHistory</B>
+</a></a>
+<P>
+
+
+<A NAME="1104471">
+If password histories are being kept, the value for this attribute defines how many entries should be stored in the history list. For example:<P></A>
+<PRE><A NAME="1157501">
+ passwordInHistory: 6
+</A>
+</PRE>
+<A NAME="1260030">
+OID: <code>2.16.840.1.113730.3.1.101</code><P></A>
+
+<A NAME="1104473">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166153">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1156663">
+<A NAME="passwordKeepHistory">
+<B>passwordKeepHistory</B>
+</a></a>
+<P>
+
+
+<A NAME="1156665">
+Defines whether or not password histories should be kept for users. Acceptable values are <code>1</code> and <code>0</code>; where <code>1</code> indicates that histories will be kept, and <code>0</code> means that no histories are kept. For example:<P></A>
+<PRE><A NAME="1156666">
+ passwordKeepHistory: 0
+</A>
+</PRE>
+<A NAME="1263371">
+OID: <code>2.16.840.1.113730.3.1.100</code><P></A>
+
+<A NAME="1156668">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166196">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1156671">
+<A NAME="passwordLockout">
+<B>passwordLockout</B>
+</a></a>
+<P>
+
+
+<A NAME="1156672">
+Defines whether or not users can be locked out after a succession of failed attempts to bind to the directory. Acceptable values are <code>1</code> and <code>0</code>; where 1 means that users can be locked out, and a value of 0 indicates that users can't be locked out. For example:<P></A>
+<PRE><A NAME="1156673">
+ passwordLockout: 0
+</A>
+</PRE>
+<A NAME="1263488">
+OID: <code>2.16.840.1.113730.3.1.105</code><P></A>
+
+<A NAME="1156675">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166205">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1104188">
+<A NAME="passwordLockoutDuration">
+<B>passwordLockoutDuration</B>
+</a></a>
+<P>
+
+
+<A NAME="1104189">
+Defines how long, in seconds, to lock users out of the directory. For example:<P></A>
+<PRE><A NAME="1155990">
+ passwordLockoutDuration: 600
+</A>
+</PRE>
+<A NAME="1263555">
+OID: <code>2.16.840.1.113730.3.1.109</code><P></A>
+
+<A NAME="1104190">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166333">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1166286">
+<A NAME="passwordMaxAge">
+<B>passwordMaxAge</B>
+</a></a>
+<P>
+
+
+<A NAME="1166287">
+Defines, in seconds, how long passwords can be used before they expire.<P></A>
+<PRE><A NAME="1166288">
+ passwordMaxAge: 8640000
+</A>
+</PRE>
+<A NAME="1259984">
+OID: <code>2.16.840.1.113730.3.1.97</code><P></A>
+
+<A NAME="1104336">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166368">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1104715">
+<A NAME="passwordMaxFailure">
+<B>passwordMaxFailure</B>
+</a></a>
+<P>
+
+
+<A NAME="1104716">
+Tells the server to lock users out after a specified number of failed attempts to bind to the directory. For example:<P></A>
+<PRE><A NAME="1155781">
+ passwordMaxFailure: 3
+</A>
+</PRE>
+<A NAME="1263500">
+OID: <code>2.16.840.1.113730.3.1.106</code><P></A>
+
+<A NAME="1104718">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166400">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1104413">
+<A NAME="passwordMinLength">
+<B>passwordMinLength</B>
+</a></a>
+<P>
+
+
+<A NAME="1104414">
+Defines the minimum number of characters required for a user's password. For example:<P></A>
+<PRE><A NAME="1156233">
+ passwordMinLength: 6
+</A>
+</PRE>
+<A NAME="1260009">
+OID: <code>2.16.840.1.113730.3.1.99</code><P></A>
+
+<A NAME="1104416">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166409">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1104754">
+<A NAME="passwordResetDuration">
+<B>passwordResetDuration</B>
+</a></a>
+<P>
+
+
+<A NAME="1157530">
+Defines the time, in seconds, between a user lockout and the time the retry count for the user is reset to zero.<P></A>
+<PRE><A NAME="1157650">
+ passwordResetDuration: 600
+</A>
+</PRE>
+<A NAME="1260081">
+OID: <code>2.16.840.1.113730.3.1.107</code><P></A>
+
+<A NAME="1104757">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166437">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1103999">
+<A NAME="passwordRetryCount">
+<B>passwordRetryCount</B>
+</a></a>
+<P>
+
+
+<A NAME="1104000">
+Contains the number of times a user has tried to bind to the directory using an incorrect password.<P></A>
+<PRE><A NAME="1154824">
+ passwordRetryCount: 3
+</A>
+</PRE>
+<A NAME="1259924">
+OID: <code>2.16.840.1.113730.3.1.93</code><P></A>
+
+<A NAME="1104001">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+
+<A NAME="1166462">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1156969">
+<A NAME="passwordUnlock">
+<B>passwordUnlock</B>
+</a></a>
+<P>
+
+
+<A NAME="1157793">
+Specifies whether or not users should be locked out forever after a specified number of failed attempts to bind to the directory. Acceptable values are <code>1</code> and <code>0</code>; where <code>1</code> means users shouldn't be locked out forever, and <code>0</code> means that users should be locked out forever. For example:<P></A>
+<PRE><A NAME="1157794">
+ passwordUnlock: 0
+</A>
+</PRE>
+<A NAME="1263528">
+OID: <code>2.16.840.1.113730.3.1.108</code><P></A>
+
+<A NAME="1156973">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166485">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1104598">
+<A NAME="passwordWarning">
+<B>passwordWarning</B>
+</a></a>
+<P>
+
+
+<A NAME="1155341">
+Defines, in seconds, when to send a warning message to users about impending password expiration. In the following example, a warning message would be sent to users one day before their password expires.<P></A>
+<PRE><A NAME="1155343">
+ passwordWarning: 86400
+</A>
+</PRE>
+<A NAME="1263428">
+OID: <code>2.16.840.1.113730.3.1.104</code><P></A>
+
+<A NAME="1155421">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166523">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1202229">
+<A NAME="personalSignature">
+<B>personalSignature</B>
+</a></a>
+<P>
+
+
+<A NAME="1202230">
+A signature file, in binary format, for the entry. For example:<P></A>
+<PRE><A NAME="1266693">
+ personalSignature: AAAAAA==
+</A>
+</PRE>
+<A NAME="1287454">
+OID: <code>0.9.2342.19200300.100.1.53</code><P></A>
+
+<A NAME="1202233">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1202238">
+<A NAME="personalTitle">
+<B>personalTitle</B>
+</a></a>
+<P>
+
+
+<A NAME="1214489">
+Specifies a personal title for a person. Examples of personal titles are "Ms", "Dr", "Prof" and "Rev".<P></A>
+<PRE><A NAME="1202240">
+ personalTitle: Mr
+</A>
+</PRE>
+<A NAME="1264740">
+OID: <code>0.9.2342.19200300.100.1.40</code><P></A>
+
+<A NAME="1202242">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202247">
+<A NAME="photo">
+<B>photo</B>
+</a></a>
+<P>
+
+
+<A NAME="1202248">
+Contains a photo, in binary form, of the entry. For example:<P></A>
+<PRE><A NAME="1286389">
+ photo: AAAAAA==
+</A>
+</PRE>
+<A NAME="1266307">
+OID: <code>0.9.2342.19200300.100.1.7</code><P></A>
+
+<A NAME="1202251">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1003072">
+<A NAME="physicalDeliveryOfficeName">
+<B>physicalDeliveryOfficeName</B>
+</a></a>
+<P>
+
+
+<A NAME="1003073">
+Identifies the name of the city or village where a physical delivery office is located. For example:<P></A>
+<PRE><A NAME="1003804">
+ physicalDeliveryOfficeName: Santa Clara
+</A>
+</PRE>
+<A NAME="1267563">
+OID: <code>2.5.4.19</code><P></A>
+
+<A NAME="1107471">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1246531">
+<A NAME="pipcompassservers">
+<B>pipcompassservers</B>
+</a></a>
+<P>
+
+
+<A NAME="1246532">
+Undefined.<P></A>
+
+<A NAME="1271255">
+OID: <code>2.16.840.1.113730.3.1.138</code><P></A>
+
+<A NAME="1107499">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236180">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1111357">
+<A NAME="pipformat">
+<B>pipformat</B>
+</a></a>
+<P>
+
+
+<A NAME="1119006">
+Attribute used by the compass server to define the format of the free text search profile update sent to the user.<P></A>
+
+<A NAME="1271403">
+OID: <code>2.16.840.1.113730.3.1.144</code><P></A>
+
+<A NAME="1111360">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1246338">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1246341">
+<A NAME="pipfrequency">
+<B>pipfrequency</B>
+</a></a>
+<P>
+
+
+<A NAME="1246342">
+Attribute used by the compass server to describe how often a user receives My Compass newsletters. <P></A>
+
+<A NAME="1271346">
+OID: <code>2.16.840.1.113730.3.1.142</code><P></A>
+
+<A NAME="1111364">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236223">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1113190">
+<A NAME="pipgroup">
+<B>pipgroup</B>
+</a></a>
+<P>
+
+
+<A NAME="1119538">
+Undefined.<P></A>
+
+<A NAME="1271479">
+OID: <code>2.16.840.1.113730.3.1.158</code><P></A>
+
+<A NAME="1113191">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236260">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1111369">
+<A NAME="piphour">
+<B>piphour</B>
+</a></a>
+<P>
+
+
+<A NAME="1119581">
+Attribute used by the compass server to define the hours during the day that a user receives free text search profile updates.<P></A>
+
+<A NAME="1271454">
+OID: <code>2.16.840.1.113730.3.1.145</code><P></A>
+
+<A NAME="1111370">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236306">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1237689">
+<A NAME="pipidstcount">
+<B>pipidstcount</B>
+</a></a>
+<P>
+
+
+<A NAME="1237690">
+Attribute used by the compass server to define the last unique ID used by the user. <P></A>
+
+<A NAME="1271485">
+OID: <code>2.16.840.1.113730.3.1.159</code><P></A>
+
+<A NAME="1113341">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236324">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1113479">
+<A NAME="pipirlist">
+<B>pipirlist</B>
+</a></a>
+<P>
+
+
+<A NAME="1119793">
+Attribute used by the compass server to contain domains and newsgroups a user wishes to monitor. <P></A>
+
+<A NAME="1271508">
+OID: <code>2.16.840.1.113730.3.1.150</code><P></A>
+
+<A NAME="1113480">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237824">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1237828">
+<A NAME="pipiroption">
+<B>pipiroption</B>
+</a></a>
+<P>
+
+
+<A NAME="1237829">
+Attribute used by the compass server to define whether or not all entries in pipIrList will be updated or excluded from updates.<P></A>
+
+<A NAME="1271566">
+OID: <code>2.16.840.1.113730.3.1.151</code><P></A>
+
+<A NAME="1113621">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236383">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1112574">
+<A NAME="piplastcount">
+<B>piplastcount</B>
+</a></a>
+<P>
+
+
+<A NAME="1237876">
+Attribute used by the compass server to define the number of matches that occurred during the last update.<P></A>
+
+<A NAME="1271585">
+OID: <code>2.16.840.1.113730.3.1.153</code><P></A>
+
+<A NAME="1112575">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1246647">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1246650">
+<A NAME="pipmaxhits">
+<B>pipmaxhits</B>
+</a></a>
+<P>
+
+
+<A NAME="1246651">
+Attribute used by the compass server to define the maximum number of documents returned for each free text search profile update. <P></A>
+
+<A NAME="1271604">
+OID: <code>2.16.840.1.113730.3.1.146</code><P></A>
+
+<A NAME="1173472">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236422">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1111582">
+<A NAME="pipmedium">
+<B>pipmedium</B>
+</a></a>
+<P>
+
+
+<A NAME="1237949">
+Attribute used by the compass server to describes the medium used to send information to the user about updates on free text search profiles. <P></A>
+
+<A NAME="1271368">
+OID: <code>2.16.840.1.113730.3.1.143</code><P></A>
+
+<A NAME="1111583">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236583">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1236460">
+<A NAME="pipnotify">
+<B>pipnotify</B>
+</a></a>
+<P>
+
+
+<A NAME="1119923">
+Undefined.<P></A>
+
+<A NAME="1271613">
+OID: <code>2.16.840.1.113730.3.1.156</code><P></A>
+
+<A NAME="1236507">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236602">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1236511">
+<A NAME="pipprivilege">
+<B>pipprivilege</B>
+</a></a>
+<P>
+
+
+<A NAME="1236512">
+Undefined.<P></A>
+
+<A NAME="1271668">
+OID: <code>2.16.840.1.113730.3.1.157</code><P></A>
+
+<A NAME="1112990">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236630">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1112443">
+<A NAME="pippwp">
+<B>pippwp</B>
+</a></a>
+<P>
+
+
+<A NAME="1238042">
+Attribute used by the compass server that contains the address of a Personal Web Page (PWP) database.<P></A>
+
+<A NAME="1271682">
+OID: <code>2.16.840.1.113730.3.1.152</code><P></A>
+
+<A NAME="1112444">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236643">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1118693">
+<A NAME="pipreservedces1">
+<B>pipreservedces1</B>
+</a></a>
+<P>
+
+
+<A NAME="1120046">
+Attribute reserved for future use for the Netscape Compass Server.<P></A>
+
+<A NAME="1271719">
+OID: <code>2.16.840.1.113730.3.1.188</code><P></A>
+
+<A NAME="1118694">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+
+<A NAME="1236680">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1118699">
+<A NAME="pipreservedces2">
+<B>pipreservedces2</B>
+</a></a>
+<P>
+
+
+<A NAME="1238136">
+Attribute reserved for future use for the Netscape Compass Server.<P></A>
+
+<A NAME="1271725">
+OID: <code>2.16.840.1.113730.3.1.189</code><P></A>
+
+<A NAME="1118700">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+
+<A NAME="1236693">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1118705">
+<A NAME="pipreservedces3">
+<B>pipreservedces3</B>
+</a></a>
+<P>
+
+
+<A NAME="1238138">
+Attribute reserved for future use for the Netscape Compass Server.<P></A>
+
+<A NAME="1271783">
+OID: <code>2.16.840.1.113730.3.1.190</code><P></A>
+
+<A NAME="1118706">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+
+<A NAME="1236718">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1118350">
+<A NAME="pipreservedcis1">
+<B>pipreservedcis1</B>
+</a></a>
+<P>
+
+
+<A NAME="1238140">
+Attribute reserved for future use for the Netscape Compass Server.<P></A>
+
+<A NAME="1271796">
+OID: <code>2.16.840.1.113730.3.1.182</code><P></A>
+
+<A NAME="1118351">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236762">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1118356">
+<A NAME="pipreservedcis2">
+<B>pipreservedcis2</B>
+</a></a>
+<P>
+
+
+<A NAME="1238144">
+Attribute reserved for future use for the Netscape Compass Server.<P></A>
+
+<A NAME="1271840">
+OID: <code>2.16.840.1.113730.3.1.183</code><P></A>
+
+<A NAME="1118357">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236799">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1118362">
+<A NAME="pipreservedcis3">
+<B>pipreservedcis3</B>
+</a></a>
+<P>
+
+
+<A NAME="1238146">
+Attribute reserved for future use for the Netscape Compass Server.<P></A>
+
+<A NAME="1271850">
+OID: <code>2.16.840.1.113730.3.1.184</code><P></A>
+
+<A NAME="1118363">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236816">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1118368">
+<A NAME="pipreservedcis4">
+<B>pipreservedcis4</B>
+</a></a>
+<P>
+
+
+<A NAME="1238148">
+Attribute reserved for future use for the Netscape Compass Server.<P></A>
+
+<A NAME="1271856">
+OID: <code>2.16.840.1.113730.3.1.185</code><P></A>
+
+<A NAME="1118369">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236851">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1118374">
+<A NAME="pipreservedcis5">
+<B>pipreservedcis5</B>
+</a></a>
+<P>
+
+
+<A NAME="1238150">
+Attribute reserved for future use for the Netscape Compass Server.<P></A>
+
+<A NAME="1271872">
+OID: <code>2.16.840.1.113730.3.1.186</code><P></A>
+
+<A NAME="1118375">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236870">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1118380">
+<A NAME="pipreservedcis6">
+<B>pipreservedcis6</B>
+</a></a>
+<P>
+
+
+<A NAME="1238152">
+Attribute reserved for future use for the Netscape Compass Server.<P></A>
+
+<A NAME="1271882">
+OID: <code>2.16.840.1.113730.3.1.187</code><P></A>
+
+<A NAME="1118381">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236893">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1111729">
+<A NAME="pipresultset">
+<B>pipresultset</B>
+</a></a>
+<P>
+
+
+<A NAME="1238541">
+Attribute used by the compass server that contains a list of attributes about which the user wants to receive updates. <P></A>
+
+<A NAME="1271899">
+OID: <code>2.16.840.1.113730.3.1.147</code><P></A>
+
+<A NAME="1111730">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236920">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1111947">
+<A NAME="pipsortorder">
+<B>pipsortorder</B>
+</a></a>
+<P>
+
+
+<A NAME="1238667">
+Attribute used by the compass server that contains the sort order of the information in the summary report of the free text search profile update. <P></A>
+
+<A NAME="1271955">
+OID: <code>2.16.840.1.113730.3.1.148</code><P></A>
+
+<A NAME="1111948">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236950">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1114647">
+<A NAME="pipstatus">
+<B>pipstatus</B>
+</a></a>
+<P>
+
+
+<A NAME="1238753">
+Attribute used by the compass server to define whether a personal interest profile is enabled or disabled. <P></A>
+
+<A NAME="1271286">
+OID: <code>2.16.840.1.113730.3.1.140</code><P></A>
+
+<A NAME="1114648">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236989">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1116402">
+<A NAME="pipstcategory">
+<B>pipstcategory</B>
+</a></a>
+<P>
+
+
+<A NAME="1238824">
+Attribute used by the compass server that contains the categories or search strings a user is interested in. <P></A>
+
+<A NAME="1271969">
+OID: <code>2.16.840.1.113730.3.1.171</code><P></A>
+
+<A NAME="1116403">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237014">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1116837">
+<A NAME="pipstformat">
+<B>pipstformat</B>
+</a></a>
+<P>
+
+
+<A NAME="1238895">
+Attribute used by the compass server to describe the format of the category search profile update sent to a user. <P></A>
+
+<A NAME="1272000">
+OID: <code>2.16.840.1.113730.3.1.174</code><P></A>
+
+<A NAME="1116838">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237031">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1116521">
+<A NAME="pipstfrequency">
+<B>pipstfrequency</B>
+</a></a>
+<P>
+
+
+<A NAME="1120346">
+Attribute used by the compass server to define the frequency that a user receives update alerts. <P></A>
+
+<A NAME="1272198">
+OID: <code>2.16.840.1.113730.3.1.172</code><P></A>
+
+<A NAME="1272200">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237041">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1116707">
+<A NAME="pipsthour">
+<B>pipsthour</B>
+</a></a>
+<P>
+
+
+<A NAME="1120383">
+Attribute used by the compass server to define the hours during the day that a user receives free category profile updates.<P></A>
+
+<A NAME="1272250">
+OID: <code>2.16.840.1.113730.3.1.175</code><P></A>
+
+<A NAME="1116708">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237070">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1115462">
+<A NAME="pipstid">
+<B>pipstid</B>
+</a></a>
+<P>
+
+
+<A NAME="1120405">
+Attribute used by the compass server to contain the unique ID of a search topic included in a personal interest profile.<P></A>
+
+<A NAME="1272264">
+OID: <code>2.16.840.1.113730.3.1.160</code><P></A>
+
+<A NAME="1115463">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237108">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1115769">
+<A NAME="pipstinterest">
+<B>pipstinterest</B>
+</a></a>
+<P>
+
+
+<A NAME="1120445">
+Attribute used by the compass server to describe the importance to a user of each individual search topic in a personal interest profile. <P></A>
+
+<A NAME="1272273">
+OID: <code>2.16.840.1.113730.3.1.164</code><P></A>
+
+<A NAME="1115770">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237118">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1117562">
+<A NAME="pipstirlist">
+<B>pipstirlist</B>
+</a></a>
+<P>
+
+
+<A NAME="1120460">
+Attribute used by the compass server to contain domains and newsgroups a user wishes to monitor.<P></A>
+
+<A NAME="1272285">
+OID: <code>2.16.840.1.113730.3.1.180</code><P></A>
+
+<A NAME="1117563">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237149">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1117790">
+<A NAME="pipstiroption">
+<B>pipstiroption</B>
+</a></a>
+<P>
+
+
+<A NAME="1120493">
+Attribute used by the compass server to define whether or not all entries in pipStIrList will be updated or excluded from updates.<P></A>
+
+<A NAME="1272306">
+OID: <code>2.16.840.1.113730.3.1.181</code><P></A>
+
+<A NAME="1237168">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237182">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1237172">
+<A NAME="pipstlastcount">
+<B>pipstlastcount</B>
+</a></a>
+<P>
+
+
+<A NAME="1237173">
+Attribute used by the compass server that contains the number of category matches during the last update of a personal interest profile. <P></A>
+
+<A NAME="1272312">
+OID: <code>2.16.840.1.113730.3.1.168</code><P></A>
+
+<A NAME="1116157">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237189">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1117134">
+<A NAME="pipstmaxhits">
+<B>pipstmaxhits</B>
+</a></a>
+<P>
+
+
+<A NAME="1120565">
+Attribute used by the compass server that defines the maximum number of documents returned for each category search profile update.<P></A>
+
+<A NAME="1272354">
+OID: <code>2.16.840.1.113730.3.1.176</code><P></A>
+
+<A NAME="1117135">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237205">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1117140">
+<A NAME="pipstmedium">
+<B>pipstmedium</B>
+</a></a>
+<P>
+
+
+<A NAME="1120568">
+Attribute used by the compass server that describes the medium used to send information to a user about updates on category search profiles.<P></A>
+
+<A NAME="1272360">
+OID: <code>2.16.840.1.113730.3.1.173</code><P></A>
+
+<A NAME="1117141">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237235">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1115468">
+<A NAME="pipstname">
+<B>pipstname</B>
+</a></a>
+<P>
+
+
+<A NAME="1120598">
+Attribute used by the compass server that contains an arbitrary name created by a user to describe a search topic.<P></A>
+
+<A NAME="1272404">
+OID: <code>2.16.840.1.113730.3.1.161</code><P></A>
+
+<A NAME="1115469">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237246">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1115898">
+<A NAME="pipstprivacy">
+<B>pipstprivacy</B>
+</a></a>
+<P>
+
+
+<A NAME="1120637">
+Attribute used by the compass server that defines whether queries of this entry should be allowed or disallowed. <P></A>
+
+<A NAME="1272410">
+OID: <code>2.16.840.1.113730.3.1.166</code><P></A>
+
+<A NAME="1115899">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237266">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1115474">
+<A NAME="pipstquery">
+<B>pipstquery</B>
+</a></a>
+<P>
+
+
+<A NAME="1120668">
+Undefined.<P></A>
+
+<A NAME="1272438">
+OID: <code>2.16.840.1.113730.3.1.162</code><P></A>
+
+<A NAME="1115475">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237271">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1117321">
+<A NAME="pipstresultset">
+<B>pipstresultset</B>
+</a></a>
+<P>
+
+
+<A NAME="1120684">
+Attribute used by the compass server that contains a list of attributes about which a user wants to receive updates.<P></A>
+
+<A NAME="1272625">
+OID: <code>2.16.840.1.113730.3.1.177</code><P></A>
+
+<A NAME="1117322">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237300">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1117327">
+<A NAME="pipstsortorder">
+<B>pipstsortorder</B>
+</a></a>
+<P>
+
+
+<A NAME="1120687">
+Attribute used by the compass server that contains the sort order of the information in the summary report of a category search profile update.<P></A>
+
+<A NAME="1272444">
+OID: <code>2.16.840.1.113730.3.1.178</code><P></A>
+
+<A NAME="1117328">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237305">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1116027">
+<A NAME="pipststatus">
+<B>pipststatus</B>
+</a></a>
+<P>
+
+
+<A NAME="1120695">
+Attribute used by the compass server that defines the status of the personal interest profile. <P></A>
+
+<A NAME="1272485">
+OID: <code>2.16.840.1.113730.3.1.167</code><P></A>
+
+<A NAME="1116028">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237322">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1115480">
+<A NAME="pipsttaxonomy">
+<B>pipsttaxonomy</B>
+</a></a>
+<P>
+
+
+<A NAME="1120736">
+Attribute used by the compass server that contains the taxonomy ID.<P></A>
+
+<A NAME="1272491">
+OID: <code>2.16.840.1.113730.3.1.163</code><P></A>
+
+<A NAME="1115481">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237358">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1117445">
+<A NAME="pipsttimestamp">
+<B>pipsttimestamp</B>
+</a></a>
+<P>
+
+
+<A NAME="1120770">
+Attribute used by the compass server that contains the date the category search profile was last updated for a user.<P></A>
+
+<A NAME="1272500">
+OID: <code>2.16.840.1.113730.3.1.179</code><P></A>
+
+<A NAME="1117446">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237387">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1115516">
+<A NAME="pipsttotalcount">
+<B>pipsttotalcount</B>
+</a></a>
+<P>
+
+
+<A NAME="1120801">
+Attribute used by the compass server that contains the number of category matches to date. <P></A>
+
+<A NAME="1272537">
+OID: <code>2.16.840.1.113730.3.1.169</code><P></A>
+
+<A NAME="1115517">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237396">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1115522">
+<A NAME="pipsttotalrun">
+<B>pipsttotalrun</B>
+</a></a>
+<P>
+
+
+<A NAME="1120812">
+Attribute used by the compass server that contains the number of category search updates performed to date.<P></A>
+
+<A NAME="1272560">
+OID: <code>2.16.840.1.113730.3.1.170</code><P></A>
+
+<A NAME="1115523">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237423">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1116285">
+<A NAME="pipsttype">
+<B>pipsttype</B>
+</a></a>
+<P>
+
+
+<A NAME="1120825">
+Attribute used by the compass server that defines whether a search is a category search or a free text search. <P></A>
+
+<A NAME="1272566">
+OID: <code>2.16.840.1.113730.3.1.165</code><P></A>
+
+<A NAME="1116286">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237434">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1117682">
+<A NAME="piptimestamp">
+<B>piptimestamp</B>
+</a></a>
+<P>
+
+
+<A NAME="1120828">
+Attribute used by the compass server that contains the date the free text search profile was last updated for this user.<P></A>
+
+<A NAME="1272571">
+OID: <code>2.16.840.1.113730.3.1.149</code><P></A>
+
+<A NAME="1112096">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237497">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1237470">
+<A NAME="piptotalcount">
+<B>piptotalcount</B>
+</a></a>
+<P>
+
+
+<A NAME="1237471">
+Attribute used by the compass server that contains the number of matches that occurred during all updates to date.<P></A>
+
+<A NAME="1272577">
+OID: <code>2.16.840.1.113730.3.1.154</code><P></A>
+
+<A NAME="1112775">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237516">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1112780">
+<A NAME="piptotalrun">
+<B>piptotalrun</B>
+</a></a>
+<P>
+
+
+<A NAME="1120866">
+Attribute used by the compass server that contains the total number of personal interest profile updates to date.<P></A>
+
+<A NAME="1272619">
+OID: <code>2.16.840.1.113730.3.1.155</code><P></A>
+
+<A NAME="1112781">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237538">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1110777">
+<A NAME="pipuid">
+<B>pipuid</B>
+</a></a>
+<P>
+
+
+<A NAME="1120876">
+Attribute used by the compass server that contains the user ID of the person to whom a personal interest profile belongs.<P></A>
+
+<A NAME="1271249">
+OID: <code>2.16.840.1.113730.3.1.137</code><P></A>
+
+<A NAME="1110778">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237569">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1107663">
+<A NAME="pipuniqueid">
+<B>pipuniqueid</B>
+</a></a>
+<P>
+
+
+<A NAME="1239397">
+Attribute used by the compass server that contains the unique ID of a compass user. <P></A>
+
+<A NAME="1271284">
+OID: <code>2.16.840.1.113730.3.1.139</code><P></A>
+
+<A NAME="1108334">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237586">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1108439">
+<A NAME="pipusertype">
+<B>pipusertype</B>
+</a></a>
+<P>
+
+
+<A NAME="1120926">
+Attribute used by the compass server that describes the type of a compass user.<P></A>
+
+<A NAME="1271340">
+OID: <code>2.16.840.1.113730.3.1.141</code><P></A>
+
+<A NAME="1108473">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237595">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1230025">
+<A NAME="postalAddress">
+<B>postalAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1230026">
+Identifies the entry's mailing address. This field is intended to include multiple lines. When represented in LDIF format, each line should be separated by a dollar sign ($). For example:<P></A>
+<PRE><A NAME="1230027">
+ postalAddress: 1234 Ridgeway Drive$Santa Clara, CA$99555
+</A>
+</PRE>
+<A NAME="1230030">
+To represent an actual dollar sign ($) or backslash (\) within this text, use the escaped hex values \24 and \5c respectively. For example, to represent the string:<P></A>
+<PRE><A NAME="1230031">
+ The dollar ($) value can be found <br> in the c:\cost file.
+</A>
+</PRE>
+<A NAME="1230032">
+provide the string:<P></A>
+<PRE><A NAME="1230033">
+ The dollar (\24) value can be found$in the c:\5ccost file.
+</A>
+</PRE>
+<A NAME="1267416">
+OID: <code>2.5.4.16</code><P></A>
+
+<A NAME="1267484">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1230036">
+<A NAME="postalCode">
+<B>postalCode</B>
+</a></a>
+<P>
+
+
+<A NAME="1230037">
+Identifies the entry's zip code in the United States. For example:<P></A>
+<PRE><A NAME="1230038">
+ postalCode: 95050
+</A>
+</PRE>
+<A NAME="1267530">
+OID: <code>2.5.4.17</code><P></A>
+
+<A NAME="1230040">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1230043">
+<A NAME="postOfficeBox">
+<B>postOfficeBox</B>
+</a></a>
+<P>
+
+
+<A NAME="1230044">
+Identifies the entry's P.O. Box. For example:<P></A>
+<PRE><A NAME="1230045">
+ postOfficeBox: P.O. Box 1234
+</A>
+</PRE>
+<A NAME="1267556">
+OID: <code>2.5.4.18</code><P></A>
+
+<A NAME="1230047">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202605">
+<A NAME="preferredDeliveryMethod">
+<B>preferredDeliveryMethod</B>
+</a></a>
+<P>
+
+
+<A NAME="1202606">
+Identifies the entry's preferred contact or delivery method. For example:<P></A>
+<PRE><A NAME="1202607">
+ preferredDeliveryMethod: telephone
+</A>
+</PRE>
+<A NAME="1267850">
+OID: <code>2.5.4.28</code><P></A>
+
+<A NAME="1202609">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1103495">
+<A NAME="preferredLanguage">
+<B>preferredLanguage</B>
+</a></a>
+<P>
+
+
+<A NAME="1103496">
+Defines a person's preffered written or spoken language. The value for this attribute should conform to the syntax for HTTP Accept-Language header values.<P></A>
+
+<A NAME="1257981">
+OID: <code>2.16.840.1.113730.3.1.39</code><P></A>
+
+<A NAME="1103586">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202620">
+<A NAME="presentationAddress">
+<B>presentationAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1206932">
+Contains an OSI presentation address for the entry. The presentation address consists of an OSI Network Address and up to three selectors, one each for use by the transport, session, and presentation entities. For example:<P></A>
+<PRE><A NAME="1202622">
+ presentationAddress: TELEX+00726322+RFC-1006+02+130.59.2.1
+</A>
+</PRE>
+<A NAME="1267857">
+OID: <code>2.5.4.29</code><P></A>
+
+<A NAME="1202624">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1241471">
+<A NAME="protocolInformation">
+<B>protocolInformation</B>
+</a></a>
+<P>
+
+
+<A NAME="1241473">
+Undefined.<P></A>
+
+<A NAME="1268174">
+OID: <code>2.5.4.48</code><P></A>
+
+<A NAME="1245387">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1245389">
+<A NAME="reciprocalNamingLink">
+<B>reciprocalNamingLink</B>
+</a></a>
+<P>
+
+
+<A NAME="1235430">
+Undefined.<P></A>
+
+<A NAME="1235433">
+Syntax: dn<P></A>
+<A NAME="1100037">
+<A NAME="ref">
+<B>ref</B>
+</a></a>
+<P>
+
+
+<A NAME="1100061">
+Used in LDAPv3 to support smart referrals. Contains an LDAP URL in the format ldap://servername:portnumber/dn. The portnumber is optional. For example:<P></A>
+<PRE><A NAME="1202639">
+ ref: ldap://mozilla/<I>cn=John Doe, o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1257878">
+OID: <code>2.16.840.1.113730.3.1.34</code><P></A>
+
+<A NAME="1100064">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1202644">
+<A NAME="registeredAddress">
+<B>registeredAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1206709">
+This attribute contains a postal address where telegrams or expedited documents should be delivered. Delivery of these documents usually requires a confirmation signature from the recipient upon delivery. <P></A>
+
+<A NAME="1267772">
+OID: <code>2.5.4.26</code><P></A>
+
+<A NAME="1202648">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1092877">
+<A NAME="replicaBeginOrc">
+<B>replicaBeginOrc</B>
+</a></a>
+<P>
+
+
+<A NAME="1092878">
+Defines whether or not the supplier server should erase the contents of the consumer server before replication. If no value exists for this attribute, the supplier will not erase the contents. Two values are acceptable for this attribute; start and stop. Start tells the supplier server to erase the contents of the consumer server, and stop tells the supplier server to abort the operation. For example:<P></A>
+<PRE><A NAME="1092879">
+ replicaBeginOrc: start
+</A>
+</PRE>
+<A NAME="1258252">
+OID: <code>2.16.840.1.113730.3.1.50</code><P></A>
+
+<A NAME="1092881">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1006496">
+<A NAME="replicaBindDn">
+<B>replicaBindDn</B>
+</a></a>
+<P>
+
+
+<A NAME="1006513">
+Identifies the DN that the server uses when communicating with a replica server. This DN can be assigned privileges. For example:<P></A>
+<PRE><A NAME="1006521">
+ replicaBinddn: <I>cn=replicator o=Netscape Communications Corp., <br></I> <I>c=US</I>
+</A>
+</PRE>
+<A NAME="1258581">
+OID: <code>2.16.840.1.113730.3.1.58</code><P></A>
+
+<A NAME="1006538">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+
+<A NAME="1009992">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1006636">
+<A NAME="replicaBindMethod">
+<B>replicaBindMethod</B>
+</a></a>
+<P>
+
+
+<A NAME="1006689">
+Identifies the method of replication to be used. This attribute does not need to be present. If it is present it must be set to simple. If it is not set to simple a warning is printed and replication will proceed as if it were "simple." For example:<P></A>
+<PRE><A NAME="1006710">
+ replicaBindMethod: simple
+</A>
+</PRE>
+<A NAME="1258336">
+OID: <code>2.16.840.1.113730.3.1.53</code><P></A>
+
+<A NAME="1006720">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1009994">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1230073">
+<A NAME="replicaCredentials">
+<B>replicaCredentials</B>
+</a></a>
+<P>
+
+
+<A NAME="1230074">
+Identifies the password to be used with the replicaBinddn sent to the consumer server. It is highly recommended that this attribute be specified with strict access controls. For example:<P></A>
+<PRE><A NAME="1230075">
+ replicaCredentials: bogusPassword
+</A>
+</PRE>
+<A NAME="1296701">
+OID: <code>2.16.840.1.113730.3.1.202</code><P></A>
+
+<A NAME="1296703">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+
+<A NAME="1296704">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1148497">
+<A NAME="replicaEntryFilter">
+<B>replicaEntryFilter</B>
+</a></a>
+<P>
+
+
+<A NAME="1204405">
+Reserved for future use.<P></A>
+
+<A NAME="1280979">
+OID: <code>2.16.840.1.113730.3.1.203</code><P></A>
+
+<A NAME="1152854">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">c</a>is<P></A>
+<A NAME="1148445">
+<A NAME="replicaHost">
+<B>replicaHost</B>
+</a></a>
+<P>
+
+
+<A NAME="1148446">
+Identifies the host name of the consumer server. For example:<P></A>
+<PRE><A NAME="1148447">
+ replicaHost: slave.netscape.com
+</A>
+</PRE>
+<A NAME="1258218">
+OID: <code>2.16.840.1.113730.3.1.197</code><P></A>
+
+<A NAME="1148449">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1148453">
+<A NAME="replicaNickName">
+<B>replicaNickName</B>
+</a></a>
+<P>
+
+
+<A NAME="1148454">
+Contains a freeform name that describes a particular set of replication rules between a single supplier and a single consumer server.<P></A>
+<PRE><A NAME="1148455">
+ replicaNickName: currentset
+</A>
+</PRE>
+<A NAME="1280981">
+OID: <code>2.16.840.1.113730.3.1.204</code><P></A>
+
+<A NAME="1148552">
+Syntax:<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702"> cis</a><P></A>
+
+<A NAME="1010001">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1007660">
+<A NAME="replicaPort">
+<B>replicaPort</B>
+</a></a>
+<P>
+
+
+<A NAME="1007661">
+Identifies the port number of the consumer server. For example:<P></A>
+<PRE><A NAME="1006466">
+ replicaPort: 9872
+</A>
+</PRE>
+<A NAME="1258224">
+OID: <code>2.16.840.1.113730.3.1.48</code><P></A>
+
+<A NAME="1006484">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1010007">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1006384">
+<A NAME="replicaRoot">
+<B>replicaRoot</B>
+</a></a>
+<P>
+
+
+<A NAME="1006394">
+Identifies the DN for the subtree that is being replicated to the consumer machine. For example:<P></A>
+<PRE><A NAME="1006401">
+ replicaRoot: <I>o=Netscape Communications Corp., c=US</I>
+</A>
+</PRE>
+<A NAME="1258564">
+OID: <code>2.16.840.1.113730.3.1.57</code><P></A>
+
+<A NAME="1006414">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+
+<A NAME="1010013">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1281126">
+<A NAME="replicatedAttributeList">
+<B>replicatedAttributeList</B>
+</a></a>
+<P>
+
+
+<A NAME="1281128">
+Reserved for future use.<P></A>
+
+<A NAME="1281133">
+OID: <code>2.16.840.1.113730.3.1.205</code><P></A>
+
+<A NAME="1281135">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">c</a>is<P></A>
+<A NAME="1006918">
+<A NAME="replicaUpdateFailedAt">
+<B>replicaUpdateFailedAt</B>
+</a></a>
+<P>
+
+
+<A NAME="1006939">
+Identifies the day and time in zulu format when an update failed to complete successfully. If all updates have been successful, replicaUpdateFailedAt is blank. For example:<P></A>
+<PRE><A NAME="1006946">
+ replicaUpdateFailedAt: 199603261300z
+</A>
+</PRE>
+<A NAME="1258278">
+OID: <code>2.16.840.1.113730.3.1.49</code><P></A>
+
+<A NAME="1006957">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1010019">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1012768">
+<A NAME="replicaUpdateReplayed">
+<B>replicaUpdateReplayed</B>
+</a></a>
+<P>
+
+
+<A NAME="1012770">
+Identifies the change number of the last change propagated to the consumer server. This value is used internally between servers only.<P></A>
+
+<A NAME="1258309">
+OID: <code>2.16.840.1.113730.3.1.51</code><P></A>
+
+<A NAME="1012772">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1012758">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1006817">
+<A NAME="replicaUpdateSchedule">
+<B>replicaUpdateSchedule</B>
+</a></a>
+<P>
+
+
+<A NAME="1006849">
+Identifies the update schedule for the consumer server. If this attribute is not present, the consumer will be updated immediately. For example: <P></A>
+<PRE><A NAME="1006868">
+ replicaUpdateSchedule: 0100-0400
+</A>
+<A NAME="1007219">
+ replicaUpdateSchedule: * 06
+</A>
+<A NAME="1007229">
+ replicaUpdateSchedule: 1145-1300 24
+</A>
+</PRE>
+<A NAME="1007234">
+These values mean:<P></A>
+<PRE><A NAME="1007241">
+ 1:00 AM - 4:00 AM, daily
+</A>
+<A NAME="1007247">
+ all day Saturday and Sunday
+</A>
+<A NAME="1007252">
+ 11:45 AM -1:00 PM, Tuesday and Thursday
+</A>
+</PRE>
+<A NAME="1258316">
+OID: <code>2.16.840.1.113730.3.1.52</code><P></A>
+
+<A NAME="1006873">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1010052">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1006741">
+<A NAME="replicaUseSSL">
+<B>replicaUseSSL</B>
+</a></a>
+<P>
+
+
+<A NAME="1006754">
+Identifies whether SSL will be used to communicate with the consumer server. A non-zero value will cause SSL to be used. For example:<P></A>
+<PRE><A NAME="1006794">
+ replicaUseSSL: 0
+</A>
+</PRE>
+<A NAME="1258347">
+OID: <code>2.16.840.1.113730.3.1.54</code><P></A>
+
+<A NAME="1006801">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1010064">
+This attribute is a Netscape extension to the standard LDAP schema.<P></A>
+<A NAME="1152805">
+<A NAME="retryCountResetTime">
+<B>retryCountResetTime</B>
+</a></a>
+<P>
+
+
+<A NAME="1154931">
+Defines, in seconds, how much time should pass before the passwordRetryCount attribute should is reset to zero (0).<P></A>
+<PRE><A NAME="1154932">
+ retryCountResetTime: 600
+</A>
+</PRE>
+<A NAME="1259952">
+OID: <code>2.16.840.1.113730.3.1.94</code><P></A>
+
+<A NAME="1146199">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis </a><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1251525">operational</a><P></A>
+<A NAME="1202666">
+<A NAME="roleOccupant">
+<B>roleOccupant</B>
+</a></a>
+<P>
+
+
+<A NAME="1202667">
+Contains the distinguished name of the person acting in the role defined in the organizationalRole entry. For example:<P></A>
+<PRE><A NAME="1204472">
+ roleOccupant: cn=jdoe o=example.com
+</A>
+</PRE>
+<A NAME="1267987">
+OID: <code>2.5.4.33</code><P></A>
+
+<A NAME="1204474">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1204477">
+<A NAME="roomNumber">
+<B>roomNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1214596">
+Specifies the room number of an object. Note that the commonName attribute should be used for naming room objects. For example:<P></A>
+<PRE><A NAME="1202675">
+ roomNumber: 230
+</A>
+</PRE>
+<A NAME="1264474">
+OID: <code>0.9.2342.19200300.100.1.6</code><P></A>
+
+<A NAME="1202677">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202682">
+<A NAME="searchGuide">
+<B>searchGuide</B>
+</a></a>
+<P>
+
+
+<A NAME="1202683">
+Specifies information for a suggested search criteria when using the entry as the base object in the directory tree for a search operation. This attribute is obsoleted by <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241288">enhancedSearchGuide</a>. <P></A>
+
+<A NAME="1267193">
+OID: <code>2.5.4.14</code><P></A>
+
+<A NAME="1230091">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1202691">
+<A NAME="secretary">
+<B>secretary</B>
+</a></a>
+<P>
+
+
+<A NAME="1202692">
+Identifies the entry's secretary or administrative assistant. For example:<P></A>
+<PRE><A NAME="1202693">
+ secretary: <I>cn=John Doe, o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1264564">
+OID: <code>0.9.2342.19200300.100.1.21</code><P></A>
+
+<A NAME="1202695">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">dn</a><P></A>
+<A NAME="1172500">
+<A NAME="seeAlso">
+<B>seeAlso</B>
+</a></a>
+<P>
+
+
+<A NAME="1172501">
+Identifies another Directory Server entry that may contain information related to this entry. For example: <P></A>
+<PRE><A NAME="1172502">
+ seeAlso: <I>cn=Quality Control Inspectors, ou=manufacturing, o=Example,<br> c=US</I>
+</A>
+</PRE>
+<A NAME="1267994">
+OID: <code>2.5.4.34</code><P></A>
+
+<A NAME="1172504">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1202700">
+<A NAME="serialNumber">
+<B>serialNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1202701">
+Defines the serial number of the entry. For example:<P></A>
+<PRE><A NAME="1202702">
+ serialNumber: 555-1234-AZ
+</A>
+</PRE>
+<A NAME="1267035">
+OID: <code>2.5.4.5</code><P></A>
+
+<A NAME="1202704">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1093065">
+<A NAME="serverHostName">
+<B>serverHostName</B>
+</a></a>
+<P>
+
+
+<A NAME="1093066">
+Identifies the name of the host on which the Netscape server is installed. This attribute is a Netscape extension used by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">netscapeServer</a> object class. Normally this attribute and this attribute value is written to the directory when a Netscape server is initially installed. For example:<P></A>
+<PRE><A NAME="1032467">
+ serverHostname: twain.example.com
+</A>
+</PRE>
+<A NAME="1259312">
+OID: <code>2.16.840.1.113730.3.1.76</code><P></A>
+
+<A NAME="1032488">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1032412">
+<A NAME="serverProductName">
+<B>serverProductName</B>
+</a></a>
+<P>
+
+
+<A NAME="1032414">
+Identifies the type of the installed Netscape server. This attribute is a Netscape extension used by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">netscapeServer</a> object class. Normally this attribute and this attribute value is written to the directory when a Netscape server is initially installed. For example:<P></A>
+<PRE><A NAME="1032416">
+ serverProductName: Netscape Enterprise Server
+</A>
+</PRE>
+<A NAME="1259171">
+OID: <code>2.16.840.1.113730.3.1.71</code><P></A>
+
+<A NAME="1032418">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1032294">
+<A NAME="serverRoot">
+<B>serverRoot</B>
+</a></a>
+<P>
+
+
+<A NAME="1032296">
+Identifies the fully qualified path to the installation directory for a Netscape server. This attribute is a Netscape extension used by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#">netscapeServer</a> object class. Normally this attribute and this attribute value is written to the directory when a Netscape server is initially installed. For example:<P></A>
+<PRE><A NAME="1032297">
+ serverRoot: /usr/ns-home
+</A>
+</PRE>
+<A NAME="1259165">
+OID: <code>2.16.840.1.113730.3.1.70</code><P></A>
+
+<A NAME="1032346">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1032439">
+<A NAME="serverVersionNumber">
+<B>serverVersionNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1032441">
+Identifies the version number of the installed Netscape server. This attribute is a Netscape extension used by the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097231">netscapeServer</a> object class. Normally this attribute and this attribute value are written to the directory when a Netscape server is initially installed. For example:<P></A>
+<PRE><A NAME="1032443">
+ serverVersionNumber: 3.0
+</A>
+</PRE>
+<A NAME="1259178">
+OID: <code>2.16.840.1.113730.3.1.72</code><P></A>
+
+<A NAME="1203414">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1245426">
+<A NAME="singleLevelQuality">
+<B>singleLevelQuality</B>
+</a></a>
+<P>
+
+
+<A NAME="1245427">
+Undefined. <P></A>
+
+<A NAME="1266643">
+OID: <code>0.9.2342.19200300.100.1.50</code><P></A>
+
+<A NAME="1245430">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1290325">
+<A NAME="sn">
+<B>sn</B>
+</a></a>
+<P>
+
+
+<A NAME="1290326">
+Identifies the entry's surname, or last name. For example:<P></A>
+<PRE><A NAME="1290327">
+ surname: Anderson
+</A>
+</PRE>
+<A NAME="1290328">
+or:<P></A>
+<PRE><A NAME="1290329">
+ sn: Anderson
+</A>
+</PRE>
+<A NAME="1290330">
+Abbreviation: sn<P></A>
+
+<A NAME="1290331">
+OID: <code>2.5.4.4</code><P></A>
+
+<A NAME="1290333">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1203417">
+<A NAME="st">
+<B>st</B>
+</a></a>
+<P>
+
+
+<A NAME="1202711">
+Identifies the state or province in which the entry resides. For example:<P></A>
+<PRE><A NAME="1202712">
+ stateOrProvinceName: California
+</A>
+</PRE>
+<A NAME="1202713">
+or:<P></A>
+<PRE><A NAME="1202714">
+ st: California
+</A>
+</PRE>
+<A NAME="1202716">
+Abbreviation: st<P></A>
+
+<A NAME="1267077">
+OID: <code>2.5.4.8</code><P></A>
+
+<A NAME="1202718">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202721">
+<A NAME="street">
+<B>street</B>
+</a></a>
+<P>
+
+
+<A NAME="1202722">
+Identifies the entry's house number and street name. For example:<P></A>
+<PRE><A NAME="1202723">
+ streetAddress: 1234 Ridgeway Drive
+</A>
+</PRE>
+<A NAME="1202724">
+or:<P></A>
+<PRE><A NAME="1202725">
+ street: 1234 Ridgeway Drive
+</A>
+</PRE>
+<A NAME="1267080">
+OID: <code>2.5.4.9</code><P></A>
+
+<A NAME="1202727">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202732">
+<A NAME="subject">
+<B>subject</B>
+</a></a>
+<P>
+
+
+<A NAME="1202733">
+Contains information about the subject matter of the document entry.<P></A>
+
+<A NAME="1202736">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1242622">
+<A NAME="subschemaSubentry">
+<B>subschemaSubentry</B>
+</a></a>
+<P>
+
+
+<A NAME="1242623">
+Undefined.<P></A>
+
+<A NAME="1263030">
+OID: <code>2.5.18.10</code><P></A>
+
+<A NAME="1242626">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1099985">
+<A NAME="subtreeACI">
+<B>subtreeACI</B>
+</a></a>
+<P>
+
+
+<A NAME="1099986">
+Specifies who can update a newsaccessitem entry. <P></A>
+
+<A NAME="1259158">
+OID: <code>2.16.840.1.113730.3.1.69</code><P></A>
+
+<A NAME="1099989">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1245467">
+<A NAME="subtreeMaximumQuality">
+<B>subtreeMaximumQuality</B>
+</a></a>
+<P>
+
+
+<A NAME="1245469">
+Undefined. <P></A>
+
+<A NAME="1266679">
+OID: <code>0.9.2342.19200300.100.1.52</code><P></A>
+
+<A NAME="1245472">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1245448">
+<A NAME="subtreeMinimumQuality">
+<B>subtreeMinimumQuality</B>
+</a></a>
+<P>
+
+
+<A NAME="1245450">
+Undefined. <P></A>
+
+<A NAME="1266661">
+OID: <code>0.9.2342.19200300.100.1.51</code><P></A>
+
+<A NAME="1245453">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1241769">
+<A NAME="supportedAlgorithms;binary">
+<B>supportedAlgorithms;binary</B>
+</a></a>
+<P>
+
+
+<A NAME="1241770">
+Reserved for future use. <P></A>
+
+<A NAME="1269236">
+OID: <code>2.5.4.52</code><P></A>
+
+<A NAME="1241967">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1202747">
+<A NAME="supportedApplicationContext">
+<B>supportedApplicationContext</B>
+</a></a>
+<P>
+
+
+<A NAME="1202748">
+This attribute contains the identifiers of OSI application contexts.<P></A>
+
+<A NAME="1267860">
+OID: <code>2.5.4.30</code><P></A>
+
+<A NAME="1202751">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1243196">
+<A NAME="supportedControl">
+<B>supportedControl</B>
+</a></a>
+<P>
+
+
+<A NAME="1243198">
+Undefined.<P></A>
+
+<A NAME="1263262">
+OID: <code>1.3.6.1.4.1.1466.101.120.13</code><P></A>
+
+<A NAME="1243201">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1243163">
+<A NAME="supportedExtension">
+<B>supportedExtension</B>
+</a></a>
+<P>
+
+
+<A NAME="1243164">
+Undefined.<P></A>
+
+<A NAME="1263243">
+OID: <code>1.3.6.1.4.1.1466.101.120.7</code><P></A>
+
+<A NAME="1243167">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1243238">
+<A NAME="supportedLDAPVersion">
+<B>supportedLDAPVersion</B>
+</a></a>
+<P>
+
+
+<A NAME="1243240">
+Undefined.<P></A>
+
+<A NAME="1263280">
+OID: <code>1.3.6.1.4.1.1466.101.120.15</code><P></A>
+
+<A NAME="1243243">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1243260">int</a><P></A>
+<A NAME="1243217">
+<A NAME="supportedSASLMechanisms">
+<B>supportedSASLMechanisms</B>
+</a></a>
+<P>
+
+
+<A NAME="1243219">
+Undefined.<P></A>
+
+<A NAME="1263274">
+OID: <code>1.3.6.1.4.1.1466.101.120.14</code><P></A>
+
+<A NAME="1243222">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1094954">
+<A NAME="targetDn">
+<B>targetDn</B>
+</a></a>
+<P>
+
+
+<A NAME="1094956">
+Defines the distinguished name of an entry that was added, modified, or deleted on a supplier server. In the case of a modrdn operation, the targetDn contains the distinguished name of the entry before it was modified. For example:<P></A>
+<PRE><A NAME="1110601">
+ targetDn:<I> cn=Jane Doe, ou=Quality Control, o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1257807">
+OID: <code>2.16.840.1.113730.3.1.6</code><P></A>
+
+<A NAME="1094942">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1230129">
+<A NAME="telephoneNumber">
+<B>telephoneNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1230130">
+Identifies the entry's phone number. For example: <P></A>
+<PRE><A NAME="1230131">
+ telephoneNumber: 415-555-2233
+</A>
+</PRE>
+<A NAME="1267615">
+OID: <code>2.5.4.20</code><P></A>
+
+<A NAME="1230133">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004703">tel</a><P></A>
+<A NAME="1205004">
+<A NAME="teletexTerminalIdentifier">
+<B>teletexTerminalIdentifier</B>
+</a></a>
+<P>
+
+
+<A NAME="1205006">
+Identifies the entry's teletex terminal identifier. The format of the attribute is as follows:<P></A>
+<PRE><A NAME="1204973">
+teletex-id = ttx-term 0*("$" ttx-param)<br>ttx-term = printablestring<br>ttx-param = ttx-key ":" ttx-value<br>ttx-key = "graphic" / "control" / "misc" / "page" / "private"<br>ttx-value = octetstring
+</A>
+</PRE>
+<A NAME="1204978">
+In the above, the first printable string is the encoding of the first portion of the teletex terminal identifier to be encoded, and the subsequent 0 or more octetstrings are subsequent portions of the teletex terminal identifier.<P></A>
+
+<A NAME="1267635">
+OID: <code>2.5.4.22</code><P></A>
+
+<A NAME="1205117">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1205120">
+<A NAME="telexNumber">
+<B>telexNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1205121">
+Defines the telex number of the entry. The format of the telex number is as follows:<P></A>
+<PRE><A NAME="1204750">
+ actual-number "$" country "$" answerback
+</A>
+</PRE>
+<A NAME="1204751">
+In the above, <code>actual-number</code> is the syntactic representation of the number portion of the TELEX number being encoded, <code>country</code> is the TELEX country code, and <code>answerback</code> is the answerback code of a TELEX terminal.<P></A>
+
+<A NAME="1267618">
+OID: <code>2.5.4.21</code><P></A>
+
+<A NAME="1202779">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202782">
+<A NAME="textEncodedORAddress">
+<B>textEncodedORAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1202783">
+Defines the text-encoded Originator/Recipient (X.400) address of the entry as defined in RFC987. For example:<P></A>
+<PRE><A NAME="1266243">
+ textEncodedORAddress: /S=doe/OU=eng/O=example/ADMD=telemail/C=us/
+</A>
+</PRE>
+<A NAME="1266245">
+OID: <code>0.9.2342.19200300.100.1.2</code><P></A>
+
+<A NAME="1266267">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1266248">
+<A NAME="title">
+<B>title</B>
+</a></a>
+<P>
+
+
+<A NAME="1230153">
+Identifies the entry's title. For example:<P></A>
+<PRE><A NAME="1230154">
+ title: Senior QC Inspector
+</A>
+</PRE>
+<A NAME="1267172">
+OID: <code>2.5.4.12</code><P></A>
+
+<A NAME="1230156">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202798">
+<A NAME="ttl">
+<B>ttl</B>
+</a></a>
+<P>
+
+
+<A NAME="1230159">
+Contains the time, in seconds, that cached information about an entry should be considered valid. Once the specified time has elapsed, the information is considered out of date. A value of zero (0) indicates that the entry should not be cached.<P></A>
+<PRE><A NAME="1252259">
+ timeToLive: 120
+</A>
+</PRE>
+<A NAME="1252260">
+or:<P></A>
+<PRE><A NAME="1252261">
+ ttl: 120
+</A>
+</PRE>
+<A NAME="1219626">
+Abbreviation: ttl<P></A>
+
+<A NAME="1278376">
+OID: <code>1.3.6.1.4.1.250.1.60</code><P></A>
+
+<A NAME="1219607">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1296804">
+<A NAME="uid">
+<B>uid</B>
+</a></a>
+<P>
+
+
+<A NAME="1296805">
+Identifies the entry's userid (usually the logon ID). For example:<P></A>
+<PRE><A NAME="1296806">
+ userid: banderson
+</A>
+</PRE>
+<A NAME="1296807">
+or:<P></A>
+<PRE><A NAME="1296808">
+ uid: banderson
+</A>
+</PRE>
+<A NAME="1296809">
+Abbreviation: uid<P></A>
+
+<A NAME="1296810">
+OID: <code>0.9.2342.19200300.100.1.1</code><P></A>
+
+<A NAME="1296812">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1202809">
+<A NAME="uniqueIdentifier">
+<B>uniqueIdentifier</B>
+</a></a>
+<P>
+
+
+<A NAME="1202810">
+Identifies a specific item used to distinguish between two entries when a distinguished name has been reused. This attribute is intended to detect instance of a reference to a distinguished name that has been deleted. This attribute is assigned by the server. For example:<P></A>
+<PRE><A NAME="1286438">
+ uniqueIdentifier: AAAAAA==
+</A>
+</PRE>
+<A NAME="1266101">
+OID: <code>0.9.2342.19200300.100.1.44</code><P></A>
+
+<A NAME="1202812">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1172624">
+<A NAME="uniqueMember">
+<B>uniqueMember</B>
+</a></a>
+<P>
+
+
+<A NAME="1172625">
+Identifies a group of names associated with an entry where each name was given a uniqueIdentifier to ensure its uniqueness. A value for the uniqueMember attribute is a DN followed by the uniqueIdentifier.<P></A>
+
+<A NAME="1269101">
+OID: <code>2.5.4.50</code><P></A>
+
+<A NAME="1172627">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1202817">
+<A NAME="updatedByDocument">
+<B>updatedByDocument</B>
+</a></a>
+<P>
+
+
+<A NAME="1217372">
+Contains the distinguished name of a document that is an updated version of the document entry.<P></A>
+
+<A NAME="1202821">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1202824">
+<A NAME="updatesDocument">
+<B>updatesDocument</B>
+</a></a>
+<P>
+
+
+<A NAME="1217396">
+Contains the distinguished name of a document for which this document is an updated version. <P></A>
+
+<A NAME="1202825">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100403">dn</a><P></A>
+<A NAME="1208938">
+<A NAME="userCertificate">
+<B>userCertificate</B>
+</a></a>
+<P>
+
+
+<A NAME="1278420">
+Contains a text-encoded version of a user's certificate. Not recommended; use userCertificate;binary instead.<P></A>
+
+<A NAME="1278422">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1278425">
+<A NAME="userCertificate;binary">
+<B>userCertificate;binary</B>
+</a></a>
+<P>
+
+
+<A NAME="1208948">
+Contains a user's certificate in binary form. For example:<P></A>
+<PRE><A NAME="1278402">
+ userCertificate;binary: AAAAAA==
+</A>
+</PRE>
+<A NAME="1286463">
+OID: <code>2.5.4.36</code><P></A>
+
+<A NAME="1278404">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1202840">
+<A NAME="userClass">
+<B>userClass</B>
+</a></a>
+<P>
+
+
+<A NAME="1214739">
+Specifies a category of computer user. The semantics of this attribute are arbitrary. The organizationalStatus attribute makes no distinction between computer users and others users and may be more applicable. For example:<P></A>
+<PRE><A NAME="1202842">
+ userClass: intern
+</A>
+</PRE>
+<A NAME="1264494">
+OID: <code>0.9.2342.19200300.100.1.8</code><P></A>
+
+<A NAME="1202844">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis</a><P></A>
+<A NAME="1196547">
+<A NAME="userPassword">
+<B>userPassword</B>
+</a></a>
+<P>
+
+
+<A NAME="1196548">
+Identifies the entry's password and encryption method in the following format:<P></A>
+<PRE><A NAME="1296829">
+{encryption method}encrypted password
+</A>
+</PRE>
+<A NAME="1196550">
+For example:<P></A>
+<PRE><A NAME="1196551">
+ userPassword: {sha}FTSLQhxXpA05
+</A>
+</PRE>
+<A NAME="1268004">
+OID: <code>2.5.4.35</code><P></A>
+
+<A NAME="1196553">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1103595">
+<A NAME="userSMIMECertificate;binary">
+<B>userSMIMECertificate;binary</B>
+</a></a>
+<P>
+
+
+<A NAME="1103596">
+Used by Netscape Communicator for S/MIME. For example:<P></A>
+<PRE><A NAME="1252279">
+ userSMIMECertificate;binary: AAAAAA==
+</A>
+</PRE>
+<A NAME="1258002">
+OID: <code>2.16.840.1.113730.3.1.40</code><P></A>
+
+<A NAME="1235505">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+<A NAME="1281763">
+<A NAME="x121Address">
+<B>x121Address</B>
+</a></a>
+<P>
+
+
+<A NAME="1281764">
+Defines the X.121 address of a person. <P></A>
+
+<A NAME="1281766">
+OID: <code>2.5.4.24</code><P></A>
+
+<A NAME="1292793">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces</a><P></A>
+<A NAME="1292796">
+<A NAME="x500UniqueIdentifier">
+<B>x500UniqueIdentifier</B>
+</a></a>
+<P>
+
+
+<A NAME="1235526">
+Reserved for future use. For example:<P></A>
+<PRE><A NAME="1252291">
+ x500UniqueIdentifier: AAAAAA==
+</A>
+</PRE>
+<A NAME="1268137">
+OID: <code>2.5.4.45</code><P></A>
+
+<A NAME="1235529">
+Syntax: <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin</a><P></A>
+
+<A NAME="1296833">
+<P></A>
diff --git a/ldap/clients/dsgw/html/manual/auth.htm b/ldap/clients/dsgw/html/manual/auth.htm
new file mode 100644
index 00000000..52dfc2da
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/auth.htm
@@ -0,0 +1,286 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<html>
+
+<head>
+<title>Directory Authentication</title>
+</head>
+
+<body>
+
+<h1><a name="authenticating"></a>Authentication</h1>
+
+<p>Authentication is the
+process of identifying yourself to the Directory Server. The
+authentication process enables the Directory Server
+to determine what operations you are allowed to perform on the
+directory. Note, however, that authentication is not always
+necessary; your directory administrator can configure the system
+so that permission is not required for some procedures.</p>
+
+<p>By default, access to the directory is denied to all users
+with the exception of the directory administrator. The
+directory administrator defines the permissions that
+grant or remove access to the directory. Because permissions are
+determined on a site by site basis, you need to check with your
+directory administrator to find out what kind of access you have
+to the directory and which operations require authentication, if any.</p>
+
+<p>This chapter contains the following sections:</p>
+
+<ul>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#ustand">Understanding directory access</a></li>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">Authenticating to the directory</a></li>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#logout">Logging out of the directory</a></li>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#incorrectauth">Problems caused by improper
+ authentication</a></li>
+</ul>
+
+<h2><a name="ustand"></a>Understanding Directory Access</h2>
+
+<p>One of the key tasks of the directory administrator
+is determining which users need access to the directory and the
+types of access required. The directory administrator grants and
+denies permission to the directory through the use of the access
+control mechanism. Using the access control mechanism, the
+directory administrator can allow or deny access:</p>
+
+<ul>
+ <li>to any unauthenticated user (this is known as anonymous
+ access) </li>
+ <li>to all authenticated users</li>
+ <li>to specific authenticated users or groups</li>
+ <li>from a specific machine or DNS domain</li>
+ <li>at a specific time of day or day of the week</li>
+ <li>based on authentication method</li>
+</ul>
+
+<p>The specific rights the administrator assigns can vary from
+user to user. For example, the administrator usually would grant read
+and search access to anonymous users and would grant write access
+only to a select group of authenticated users and groups, perhaps only
+from specific machines.</p>
+
+<p>The following are just some of the things the directory
+administrator can do by applying permissions to the directory.
+The directory administrator can:</p>
+
+<ul>
+ <li>Require you to authenticate before accessing the
+ directory in any way. </li>
+ <li>Require you to authenticate before accessing certain
+ subsections of the directory. </li>
+ <li>Require you to authenticate before performing certain
+ kinds of actions in the directory, such as adding or
+ modifying entries. </li>
+ <li>Deny you access to all or parts of the directory,
+ or deny you the ability to perform certain kinds of
+ functions. </li>
+ <li>Allow anonymous access to all or parts of the directory.</li>
+ <li>Allow anonymous access for some kinds of operations (such
+ as searches), but not others (such as
+ modifications). </li>
+ <li>Allow or deny access based on the physical machine you
+ are currently using. </li>
+</ul>
+
+<p>The Directory Server interface has no way of determining if
+you are required to authenticate before attempting any directory
+access. However, the interface assumes you must authenticate
+before modifying the directory tree in any way, and if you are
+not currently authenticated, it prompts you for authentication
+before you can make any modifications. If you do not
+authenticate, you are allowed only to perform the operations
+and access the portions of the directory that your directory
+administrator has set for anonymous access.</p>
+
+<!--<p>For more information on access control, refer to Chapter 5 of
+the <em>Directory Server Administrator's Guide</em>.</p>-->
+
+<h2><a name="userauth"></a>Authenticating to the Directory</h2>
+
+<p>In some situations, the Directory Server interface
+automatically prompts you to authenticate before continuing with
+an operation. You can also explicitly choose to authenticate by
+clicking the Authentication tab. Either way, the
+authentication procedure is as follows:</p>
+
+<ol>
+ <li>Click the Authentication tab.</li>
+ <li>Enter the name you want to use to identify yourself to
+ the Directory Server:
+ <ul type="disc">
+ <li><a name="userauth2"></a>To authenticate as a regular user, enter your
+ full name and click Continue. <br>
+ Enter your name as it would appear in the
+ Directory Server (your common name or full name).
+ Do not enter your user ID or login for the local
+ operating system. </li>
+ <li><a name="managerauth2"></a>To authenticate as the privileged directory user,
+ click the "Authenticate as directory manager"
+ button.</li>
+ </ul>
+ </li>
+ <li>If the Directory Server interface displays a table of
+ matching entries, select the link that corresponds to
+ your directory entry. If your name is unique in the
+ directory, the system skips this step.</li>
+ <li>Enter your password and click Continue.<br>
+ Contact your directory manager if you do not know your
+ password. <br>
+ <a name="authsuccess"></a>After the authentication
+ operations complete successfully, the interface displays
+ a message indicating the amount of time for which your
+ authentication credentials are valid. When this time has
+ elapsed, you need to reauthenticate to the directory
+ to continue your session. If your password has already
+ expired you should either change
+ it immediately or contact your system administrator.</li>
+ <li>Click "Return to Main" to continue your
+ Directory Server interface session. </li>
+</ol>
+
+<h2><a name="logout"></a>Logging Out of the Directory</h2>
+
+<p>If you have authenticated to the Directory Server and
+want to return to anonymous access, do the following:</p>
+
+<ol>
+ <li>Click the Authentication tab.</li>
+ <li>Click the "Discard Authentication Credentials (log out)"
+ button. </li>
+</ol>
+
+<p>You are returned to anonymous access. To change from one type of
+access to another, you must authenticate to the Directory Server again. See <a
+href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth2">Authenticating as a User</a> or <a
+href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#managerauth2">Authenticating as Directory Manager</a> for
+more information. </p>
+
+<h2><a name="reauth"></a>Reauthenticating to the Directory</h2>
+
+<p>When you authenticate to the directory, you are given
+authentication credentials that are good only for a specific
+amount of time. By default, authentication credentials are valid
+for 120 minutes. However, this period is configurable by the directory administrator.
+If your authentication credentials expire before you have
+finished using the Directory Server interface, you must
+reauthenticate to the directory before your changes can be saved.
+The procedure for reauthenticating to the directory is the same
+as the procedure you originally used to <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</a>
+to the directory.</p>
+
+<h2><a name="incorrectauth"></a>Problems Caused by Incorrect
+Authentication</h2>
+
+<p>When you are not authenticated to the Directory Server, you are
+accessing the directory as an anonymous user. The types of
+operations you can perform as an anonymous user depend on the
+access controls set by your directory administrator. You
+may notice strange behavior when you try to perform a directory
+operation, such as a search. Although not explicitly stated
+by the Directory Server interface, the anomalies you encounter are
+often caused by improper authentication. The interface does not provide
+this information because doing so could compromise security.</p>
+
+<p>The following table lists symptoms of some common
+problems along with the possible causes and the
+action you can take to fix the problem.</p>
+
+<table border="2">
+ <tr>
+ <th width="30%"><b>Symptom</b></th>
+ <th><b>Cause</b></th>
+ <td width="30%"><b>Action</b></td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">Search results are empty</td>
+ <td valign="top">Either no entries match
+ the search string you entered, or you are required to
+ authenticate to the directory before performing this type of search
+ operation.</td>
+ <td valign="top" width="30%">Try a different search
+ operation. Or, if you are sure that there are entries
+ that match the criteria you entered, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</a>
+ to the directory.</td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">Search results missing
+ entries or missing attribute information from returned
+ entries.</td>
+ <td valign="top">Either you are not authenticated
+ properly or you do not have access to the information.
+ The directory administrator can specify that all or parts
+ of the directory tree require authentication to access
+ entries, or even certain entry attributes. In this situation,
+ the Directory Server does not indicate that the
+ information exists and that you do not have
+ privileges to access it. Instead, it simply acts as if
+ the information does not exist at all. This behavior is
+ driven by the concern that knowing certain information
+ exists in the tree, even if you are not allowed to see
+ it, can pose a security risk. </td>
+ <td valign="top" width="30%">Make sure you are properly <a
+ href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticated</a>. Then, verify with
+ your directory administrator that you have access to the
+ directory information you need.</td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">Operation fails after
+ completion</td>
+ <td valign="top">The directory is failing the operation
+ because of improper authentication. Although, it may seem as if
+ the interface's form action is failing the
+ operation, the form is only passing the operation to the
+ Directory Server, which is then failing the operation.
+ The Directory Server interface simply reports the results
+ of the operation. This occurs because the LDAP protocol
+ does not currently allow the interface to know whether
+ authentication is required before trying an operation.
+ Using the interface, this situation can only arise
+ if your authentication times out while you are creating
+ or modifying the directory entry. </td>
+ <td valign="top" width="30%">Make sure you are properly <a
+ href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticated</a> and that your authentication
+ has not timed out. </td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">A table of entries is
+ displayed during the authentication process</td>
+ <td valign="top">Either your full name is not unique in
+ the directory, or the name you entered does not exist in
+ the directory.</td>
+ <td valign="top" width="30%">If your entry is displayed
+ on the table, select the corresponding link and continue
+ with the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authentication</a> process.<p>If
+ your entry is not displayed on the table, click Cancel
+ and then try <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticating</a>
+ again. Be sure to use your full name and not your user
+ ID.</p>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">Username is correct, but
+ authentication fails anyway</td>
+ <td valign="top">Your password is incorrect. <p>If you
+ enter a valid username but an incorrect password, and the
+ username you supplied represents an NT person entry, the
+ Directory Server attempts to authenticate you to the
+ Windows network. </p>
+ <p>If that is not successful or the user name you
+ supplied does not represent an NT person entry, you are
+ given the choice to retry, close the window, or seek
+ help.</p>
+ </td>
+ <td valign="top" width="30%">Click Retry
+ and then reenter your password.</td>
+ </tr>
+</table>
+
+<p> </p>
+</body>
+</html>
diff --git a/ldap/clients/dsgw/html/manual/contents.html b/ldap/clients/dsgw/html/manual/contents.html
new file mode 100644
index 00000000..cbcd6c29
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/contents.html
@@ -0,0 +1,185 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.01 [en] (WinNT; U) [Netscape]">
+ <TITLE>Contents</TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+
+<H1>
+Contents</H1>
+
+<H2>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm">Chapter 1 Introduction to the Directory Server Interface</A></H2>
+
+<H2>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm">Chapter 2 Searching the Directory Tree</A></H2>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A></DD>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#Performing a Standard Search">Performing a Standard
+Search</A></DD>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#Name">Searching for Names</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#initials">Searching for Names with Initials</A></DD>
+
+<BR><A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#phone">Searching for Phone Numbers</A>
+<BR><A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#e-mail">Searching for E-mail Addresses</A>
+<BR><A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#filter">Using Search Filters</A></DL>
+</DL>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A></DD>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#Performing an Advanced Search">Performing an Advanced
+Search</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#Advanced Search Examples">Advanced Search Examples</A></DD>
+</DL>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">Viewing Search Results</A></DD>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#nomatch">No Matches</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#single">A Single Match</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#multiple">Multiple Matches</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#problems">Other Problems</A></DD>
+</DL>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#vCard">Viewing a vCard</A>
+<H2>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm">Chapter 3 Adding Entries</A></H2>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#guidelines">New Entry Guidelines</A></DD>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#tree">Directory Tree Structure</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#DN">Distinguished Name Syntax</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#uniqueDN">Unique Distinguished Names</A></DD>
+</DL>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#person">Adding a Person</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#NTperson">Adding an NT-Person</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#group">Adding a Group</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#NTgroup">Adding an NT-Group</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#ou">Adding an Organizational Unit</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#dc">Adding a Domain</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#o">Adding an Organization</A></DD>
+</DL>
+
+<H2>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm">Chapter 4 Editing Entries</A></H2>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#people">Editing People</A></DD>
+
+<DL>
+<DL><A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addmanager">Adding Values to the Manager and Admin
+Fields</A></DL>
+</DL>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#ntpeople">Editing NT-people</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#groups">Editing Groups</A></DD>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addowner">Adding Values to the Owner, See Also, and Group
+Member Fields</A></DD>
+</DL>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#NTgroups">Editing NT-Groups</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#ou">Editing Organizational Units</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#dc">Editing Domains</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#o">Editing Organizations</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#rename">Renaming Entries</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#delete">Deleting Entries</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#changepw">Changing Passwords</A></DD>
+</DL>
+
+<H2>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm">Chapter 5 Authentication</A></H2>
+
+<DL>
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#ustand">Understanding Directory Access</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">Authenticating to the Directory</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#logout">Logging Out of the Directory</A></DD>
+
+<DD>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#incorrectauth">Problems Caused by Incorrect Authentication</A></DD>
+</DL>
+
+<H2>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm">Appendix A Objectclasses</A></H2>
+
+<H2>
+<A HREF="lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm">Appendix B Attributes</A></H2>
+
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/manual/dn.htm b/ldap/clients/dsgw/html/manual/dn.htm
new file mode 100644
index 00000000..c61111ff
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/dn.htm
@@ -0,0 +1,262 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE></TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0b6Gold (WinNT; I) [Netscape]">
+</HEAD>
+<BODY>
+
+<P><A NAME="1001595"></A></P>
+
+<P><A NAME="1001596"></A></P>
+
+<P><A NAME="996824"></A></P>
+
+<H1>Distinguished Names</H1>
+
+<P><A NAME="1017708"></A>Distinguished
+Names (DNs) are the string representation for entry names in the Directory
+Server database. You use DNs to name entries when you add entries to the
+directory, add members to groups, etc..</P>
+
+<P><A NAME="1017709"></A>A DN can consist of virtually any attributes you
+wish to use. The only caveat is that if schema checking is turned on, then
+the attributes must be recognized by the Directory Server (if you do not
+know whether schema checking is turned on in the server, contact your directory
+manager, or consult the <I>Netscape Directory Server Administrator's Guide</I>
+for more information).</P>
+
+<P><A NAME="1017710"></A>Traditionally, a DN consists of:</P>
+
+<UL>
+<P><A NAME="1017711"></A></P>
+
+<LI>A common name followed by<A NAME="1017712"></A></LI>
+
+<LI>a list of regional or organizational attributes followed by<A NAME="1017713"></A></LI>
+
+<LI>a country designation.</LI>
+</UL>
+
+<P><A NAME="1017714"></A>This string of identifying attributes uniquely
+locates the entry within your Directory Server database. If you choose,
+you can also use this naming structure to uniquely identify your entries
+within the global directory tree as defined in the X.500 standard.</P>
+
+<P><A NAME="1017715"></A>Because a DN represents a path through the directory
+tree, the DN components are order-dependent. For example, the following
+DNs do not represent the same entry:</P>
+
+<P><A NAME="1017716"></A></P>
+
+<PRE>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cn=Ralph Swenson, ou=Accounting, o=Example Corp, c=US
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;cn=Ralph Swenson, o=Example Corp, ou=Accounting, c=US
+</PRE>
+
+<P><A NAME="Distinguished Name syntax"></A><A NAME="1017717"></A></P>
+
+<H2>Distinguished Name syntax</H2>
+
+<P><A NAME="1017718"></A>The traditional syntax for a DN string representation
+is as follows:</P>
+
+<P><A NAME="1017719"></A></P>
+
+<UL>
+<PRE>cn=<I>common name</I>, [street=<I>address</I>, l=<I>locality</I>, st = <I>state or province</I>,
+ou=<I>organizational unit</I>, o=<I>organization</I>], c=<I>country name</I>
+</PRE>
+</UL>
+
+<P><A NAME="1017720"></A>Generally a DN begins with a specific common name,
+and proceeds with increasingly broader areas of identification until the
+country name is specified. Note, however, that the actual DN attributes
+you use, and the order in which you choose to specify them, is up to you
+and how you want to organize your database. The only real requirement is
+that DN attributes must be separated by a comma (,) and can optionally
+use a space ( ) following the separator.</P>
+
+<P><A NAME="Distinguished Name attributes"></A><A NAME="1017721"></A></P>
+
+<H2>Distinguished Name attributes</H2>
+
+<P><A NAME="1017792"></A>The various standard attributes that comprise
+a DN are as follows:</P>
+
+<TABLE BORDER=2 >
+<CAPTION></CAPTION>
+
+<TR>
+<TH><A NAME="1017730"></A><B>Attribute</B></TH>
+
+<TH><A NAME="1017732"></A><B>Name</B></TH>
+
+<TH><A NAME="1017734"></A><B>Definition</B></TH>
+</TR>
+
+<TR>
+<TD><A NAME="1017736"></A>c</TD>
+
+<TD><A NAME="1017738"></A>country</TD>
+
+<TD><A NAME="1017740"></A>Identifies the name of the country under which
+the entry resides. For example,
+<UL>
+<P><A NAME="1017741"></A></P>
+
+<LI>c=US<A NAME="1017742"></A></LI>
+
+<LI>c=GB</LI>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1017744"></A>cn</TD>
+
+<TD><A NAME="1017746"></A>common name</TD>
+
+<TD><A NAME="1017748"></A>Required attribute that identifies the person
+or object defined by the entry. For example:
+<UL>
+<P><A NAME="1017749"></A></P>
+
+<LI>cn=Wally Henderson<A NAME="1017750"></A></LI>
+
+<LI>cn=Database Administrators<A NAME="1017751"></A></LI>
+
+<LI>cn=printer3b</LI>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1017753"></A>l</TD>
+
+<TD><A NAME="1017755"></A>locality</TD>
+
+<TD><A NAME="1017757"></A>Identifies the locality in which the entry resides.
+The locality could be a city, county, township, or other geographic region.
+For example:
+<UL>
+<P><A NAME="1017758"></A></P>
+
+<LI>l=Tucson<A NAME="1017759"></A></LI>
+
+<LI>l=Pacific Northwest<A NAME="1017760"></A></LI>
+
+<LI>l=Anoka County</LI>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1017762"></A>o</TD>
+
+<TD><A NAME="1017764"></A>organization</TD>
+
+<TD><A NAME="1017766"></A>Identifies the organization in which the entry
+resides. For example:
+<UL>
+<P><A NAME="1017767"></A></P>
+
+<LI>o=Netscape Communications Corp<A NAME="1017768"></A></LI>
+
+<LI>o=Public Power &amp; Gas</LI>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1017770"></A>ou</TD>
+
+<TD><A NAME="1017772"></A>organizational unit</TD>
+
+<TD><A NAME="1017774"></A>Identifies a unit within the organization. For
+example:
+<UL>
+<P><A NAME="1017775"></A></P>
+
+<LI>ou=Sales<A NAME="1017776"></A></LI>
+
+<LI>ou=Manufacturing</LI>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1017778"></A>st</TD>
+
+<TD><A NAME="1017780"></A>state or province name</TD>
+
+<TD><A NAME="1017782"></A>Identifies the state or province in which the
+entry resides. For example:
+<UL>
+<P><A NAME="1017783"></A></P>
+
+<LI>st=Iowa<A NAME="1017784"></A></LI>
+
+<LI>st=British Columbia</LI>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1017786"></A>street</TD>
+
+<TD><A NAME="1017788"></A>street address</TD>
+
+<TD><A NAME="1017790"></A>Identifies the street address at which the entry
+resides. For example:
+<UL>
+<P><A NAME="1017791"></A></P>
+
+<LI>street=494 Rice Creek Terrace</LI>
+</UL>
+</TD>
+</TR>
+</TABLE>
+
+<TABLE>
+<TR>
+<TD></TD>
+</TR>
+</TABLE>
+
+<P><A NAME="Distinguished Name examples"></A><A NAME="1017793"></A></P>
+
+<H2>Distinguished Name examples</H2>
+
+<P><A NAME="1017794"></A>The following are some examples of DNs:</P>
+
+<P><A NAME="1017795"></A></P>
+
+<UL>
+<PRE>cn=Wally Henderson,ou=Product Development,o=Example Corp,st=Minnesota,c=US
+</PRE>
+</UL>
+
+<P><A NAME="1017796"></A></P>
+
+<UL>
+<PRE>cn=Retch Sweeny, ou=Product Test, o=Example Corp, st=Michigan, c=US
+</PRE>
+</UL>
+
+<P><A NAME="1017797"></A></P>
+
+<UL>
+<PRE>cn=printer3b, l=room 308, o=Example Corp, c=US
+</PRE>
+</UL>
+
+<P><A NAME="997436"></A></P>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/manual/dna.gif b/ldap/clients/dsgw/html/manual/dna.gif
new file mode 100644
index 00000000..ad5872c5
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/dna.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/manual/filters.htm b/ldap/clients/dsgw/html/manual/filters.htm
new file mode 100644
index 00000000..acb47a3e
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/filters.htm
@@ -0,0 +1,622 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE></TITLE>
+ <META NAME="GENERATOR" CONTENT="Mozilla/3.0Gold (WinNT; I) [Netscape]">
+</HEAD>
+<BODY>
+
+<P><A NAME="1001595"></A></P>
+
+<P><A NAME="1001596"></A></P>
+
+<P><A NAME="996824"></A></P>
+
+<H1>Search Filters </H1>
+
+<P><A NAME="997436"></A>This chapter
+describes search filters and <A href="/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018239">how searches
+work</A>.</P>
+
+<P><A NAME="Search Filters"></A><A NAME="1018822"></A></P>
+
+<H2>Search Filters</H2>
+
+<P><A NAME="1018489"></A>To narrow a search, you can specify search filters
+directly to the <A href="/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015771">Smart Search</A> field. If
+the search field contains an equal sign (=), Smart Search assumes the value
+is a search filter, and it uses this filter directly to perform the search.</P>
+
+<P><A NAME="1018092"></A>Search filters use the value of an attribute to
+select the entries to be returned for Smart Search. For example, the following
+filter specifies a search for a common name equal to Babs Jensen:</P>
+
+<P><A NAME="1018094"></A></P>
+
+<UL>
+<UL>
+<PRE>cn=babs jensen
+</PRE>
+</UL>
+</UL>
+
+<P><A NAME="Search Filter Syntax"></A><A NAME="1018095"></A></P>
+
+<H3>Search Filter Syntax</H3>
+
+<P><A NAME="1018096"></A>The basic syntax of a search filter is:</P>
+
+<P><A NAME="1018097"></A></P>
+
+<UL>
+<UL>
+<PRE><A href="/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1019127">attribute</A> <A href="/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1019138">operator</A> value
+</PRE>
+</UL>
+</UL>
+
+<P><A NAME="1019085"></A>For example: </P>
+
+<P><A NAME="1019086"></A></P>
+
+<UL>
+<UL>
+<PRE>employeenumber &gt;= 100
+</PRE>
+</UL>
+</UL>
+
+<P><A NAME="1019090"></A>In the example above, <TT>employeenumber</TT>
+is the attribute, <TT>&gt;=</TT> is the operator, and 100 is the value.
+</P>
+
+<P><A NAME="1019104"></A>You can also define filters that use <A href="/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018167">combinations
+of different attributes</A>. </P>
+
+<P><A NAME="Using Attributes in a Filter"></A><A NAME="1019127"></A></P>
+
+<H4>Using Attributes in a Filter</H4>
+
+<P><A NAME="1019162"></A>When searching for an entry, you can specify attributes
+associated with that type of entry. For example, when you search for entries
+about people, you can use the <TT>cn</TT> attribute to search for people
+with specific common names. </P>
+
+<P><A NAME="1019183"></A>Examples of attributes for entries about people
+might include: </P>
+
+<UL>
+<P><A NAME="1019188"></A></P>
+
+<LI><TT>cn</TT> (the person's common name) <A NAME="1019189"></A></LI>
+
+<LI><TT>telephonenumber</TT> (the person's phone number) <A NAME="1019190"></A></LI>
+
+<LI><TT>employeenumber</TT> (the person's employee number) <A NAME="1019191"></A></LI>
+
+<LI><TT>l</TT> (the person's location) </LI>
+</UL>
+
+<P><A NAME="1019184"></A>For a listing of the attributes associated with
+entries, see <A href="/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1002619">Appendix A, &quot;Entries
+and attribute fields&quot;</A>. Note that you need to use the internal
+attribute names in search filters. </P>
+
+<P><A NAME="Using Operators in a Filter"></A><A NAME="1019138"></A></P>
+
+<H4>Using Operators in a Filter</H4>
+
+<P><A NAME="1018153"></A>An operator defines one of the following types
+of searches: </P>
+
+<TABLE BORDER=2 >
+<CAPTION></CAPTION>
+
+<TR>
+<TH><A NAME="1018101"></A><B>Search type</B> </TH>
+
+<TH><A NAME="1018103"></A><B>Operator</B> </TH>
+
+<TH><A NAME="1018105"></A><B>Description</B> </TH>
+</TR>
+
+<TR>
+<TD><A NAME="1018107"></A>Equality </TD>
+
+<TD><A NAME="1018109"></A>= </TD>
+
+<TD><A NAME="1018111"></A>Returns entries containing attributes which match
+the specified value. For example,
+<UL>
+<P><A NAME="1019083"></A><TT>cn=Bob Johnson</TT></P>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018113"></A>Substring </TD>
+
+<TD><A NAME="1018115"></A>=&lt;string&gt;*&lt;string&gt; </TD>
+
+<TD><A NAME="1018117"></A>Returns entries containing attributes containing
+the specified substring. For example,
+<UL>
+<P><A NAME="1018118"></A><TT>cn=Bob*</TT></P>
+
+<P><A NAME="1018119"></A><TT>cn=*Johnson</TT></P>
+
+<P><A NAME="1018120"></A><TT>cn=*John*</TT></P>
+
+<P><A NAME="1018121"></A><TT>cn=B*John</TT></P>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018123"></A>Greater than or equal to </TD>
+
+<TD><A NAME="1018125"></A>&gt;= </TD>
+
+<TD><A NAME="1018127"></A>Returns entries containing attributes that are
+greater than or equal to the specified value. For example,
+<UL>
+<P><A NAME="1018128"></A><TT>employeenumber &gt;= 100</TT></P>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018130"></A>Less than or equal to </TD>
+
+<TD><A NAME="1018132"></A>&lt;= </TD>
+
+<TD><A NAME="1018134"></A>Returns entries containing attributes that are
+less than or equal to the specified value. For example,
+<UL>
+<P><A NAME="1018135"></A><TT>employeenumber &lt;= 100</TT></P>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018137"></A>Presence </TD>
+
+<TD><A NAME="1018139"></A>=* </TD>
+
+<TD><A NAME="1018141"></A>Returns entries containing the specified attribute.
+For example,
+<UL>
+<P><A NAME="1018142"></A><TT>cn=*</TT></P>
+
+<P><A NAME="1018143"></A><TT>telephonenumber=*</TT></P>
+
+<P><A NAME="1018144"></A><TT>manager=*</TT></P>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018146"></A>Approximate </TD>
+
+<TD><A NAME="1018148"></A>~= </TD>
+
+<TD><A NAME="1018150"></A>Returns entries containing the specified attribute
+that is approximately equal to the specified value. For example,
+<UL>
+<P><A NAME="1018151"></A><TT>cn~=surette</TT></P>
+
+<P><A NAME="1018152"></A><TT>l~=san fransico</TT></P>
+</UL>
+</TD>
+</TR>
+</TABLE>
+
+<TABLE>
+<TR>
+<TD></TD>
+</TR>
+</TABLE>
+
+<P><A NAME="1018160"></A>For more information on these types of searches,
+see &quot;<A href="/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018239">How searching works</A>.&quot;
+</P>
+
+<P><A NAME="Using Multiple Search Filters"></A><A NAME="1018167"></A></P>
+
+<H4>Using Multiple Search Filters</H4>
+
+<P><A NAME="1018168"></A>You can combine different search filters by using
+boolean operators. Use the operators in prefix notation as follows:</P>
+
+<P><A NAME="1018169"></A></P>
+
+<UL>
+<PRE>(<I>boolean_operator</I>((<I>filter</I>)(<I>filter</I>)(<I>filter</I>)...))
+</PRE>
+</UL>
+
+<P><A NAME="1018170"></A>where <I>boolean_operator</I> is any one of the <A href="/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018173">boolean
+operators</A>. For example: </P>
+
+<P><A NAME="1019218"></A></P>
+
+<UL>
+<PRE>(&amp;(ou=Marketing)(cn=Ray*))
+</PRE>
+</UL>
+
+<P><A NAME="1019216"></A>In the example above, the combination of filters
+finds entries whose organizational unit is Marketing (<TT>ou=Marketing</TT>)
+and whose common name starts with Ray (<TT>cn=Ray*</TT>). The boolean operator
+for &quot;And&quot; (<TT>&amp;</TT>) is used in prefix notation, which
+means that it precedes the search criteria. </P>
+
+<P><A NAME="1019228"></A>In addition, you can nest boolean operators to
+form complex expressions, such as:</P>
+
+<P><A NAME="1018171"></A></P>
+
+<UL>
+<PRE>(boolean_operator(filter)((boolean_operator(filter)(filter)))
+</PRE>
+</UL>
+
+<P><A NAME="Boolean Operators"></A><A NAME="1018173"></A></P>
+
+<H4>Boolean Operators</H4>
+
+<P><A NAME="1018202"></A>The boolean operators available for use with search
+filters are: </P>
+
+<TABLE BORDER=2 >
+<CAPTION></CAPTION>
+
+<TR>
+<TH><A NAME="1018176"></A><B>Operator</B> </TH>
+
+<TH><A NAME="1018178"></A><B>Symbol</B> </TH>
+
+<TH><A NAME="1018180"></A><B>Description</B> </TH>
+</TR>
+
+<TR>
+<TD><A NAME="1018182"></A>And </TD>
+
+<TD><A NAME="1018184"></A>&amp; </TD>
+
+<TD><A NAME="1018186"></A>All specified filters must be true for the statement
+to be true. For example,
+<UL>
+<P><A NAME="1018187"></A><TT>(&amp;(filter1)(filter2)(filter3)...)</TT></P>
+</UL>
+
+<P><A NAME="1019015"></A>Filter1, filter2, and filter3 must all be true
+for an entry to match.</P>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018189"></A>Or </TD>
+
+<TD><A NAME="1018191"></A>| </TD>
+
+<TD><A NAME="1018193"></A>At least one specified filter must be true for
+the statement to be true. For example,
+<UL>
+<P><A NAME="1018194"></A><TT>(|(filter1)(filter2)(filter3)...)</TT></P>
+</UL>
+
+<P><A NAME="1019024"></A>If any of filter1, filter2, or filter3 match,
+the entry is returned.</P>
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018196"></A>Not </TD>
+
+<TD><A NAME="1018198"></A>! </TD>
+
+<TD><A NAME="1018200"></A>The specified statement must not be true for
+the statement to be true. Note that only one filter is affected by the
+not operator. For example,
+<UL>
+<P><A NAME="1018201"></A><TT>(!(filter))</TT></P>
+</UL>
+
+<P><A NAME="1019025"></A>Any entry not matching the filter is returned.</P>
+</TD>
+</TR>
+</TABLE>
+
+<TABLE>
+<TR>
+<TD></TD>
+</TR>
+</TABLE>
+
+<P><A NAME="Search Filter Examples"></A><A NAME="1018203"></A></P>
+
+<H4>Search Filter Examples</H4>
+
+<P><A NAME="1018204"></A>The following filter searches for entries containing
+the manager attribute. This is also known as a presence search:</P>
+
+<P><A NAME="1018205"></A></P>
+
+<PRE> manager=*
+</PRE>
+
+<P><A NAME="1018206"></A>The following filter searches for entries containing
+the common name of Ray Kultgen. This is also known as an equality search:</P>
+
+<P><A NAME="1018207"></A></P>
+
+<PRE> cn=Ray Kultgen
+</PRE>
+
+<P><A NAME="1018208"></A>The following filter returns any entries that
+do not contain the common name of Ray Kultgen:</P>
+
+<P><A NAME="1018209"></A></P>
+
+<PRE> (!(cn=Ray Kultgen))
+</PRE>
+
+<P><A NAME="1018210"></A>The following filter returns any entries that
+contain a description attribute with a substring of X.500:</P>
+
+<P><A NAME="1018211"></A></P>
+
+<PRE> description=*X.500*
+</PRE>
+
+<P><A NAME="1018212"></A>The following filter returns any entries whose
+organizational unit is Marketing and whose description field does not contain
+the substring X.500:</P>
+
+<P><A NAME="1018213"></A></P>
+
+<PRE> (&amp;(ou=Marketing)(!(description=*X.500*)))
+</PRE>
+
+<P><A NAME="1018214"></A>The following filter returns any entries whose
+organizational unit is Marketing and who have Julie Fulmer or Cindy Zwaska
+as a manager:</P>
+
+<P><A NAME="1018215"></A></P>
+
+<PRE> (&amp;(ou=Marketing)(|(manager=&quot;cn=Julie Fulmer,ou=Marketing,o=Example Corp,c=US&quot;)<br>(manager=&quot;cn=Cindy Zwaska,ou=Marketing,o=Example Corp,c=US&quot;)))
+</PRE>
+
+<P><A NAME="1018216"></A>The following filter returns any entries that
+do not represent a person:</P>
+
+<P><A NAME="1018217"></A></P>
+
+<PRE> (!(objectclass=person))
+</PRE>
+
+<P><A NAME="1018218"></A>The following filter returns any entries that
+do not represent a person and whose common name is approximately printer3b:</P>
+
+<P><A NAME="1018219"></A></P>
+
+<PRE> (&amp;(!(objectclass=person))(cn~=printer3b))
+</PRE>
+
+<P><A NAME="How Searching Works"></A><A NAME="1018239"></A></P>
+
+<H2>How Searching Works</H2>
+
+<P><A NAME="1018240"></A></P>
+
+<BLOCKQUOTE>
+<P><B>Note: </B></P>
+</BLOCKQUOTE>
+
+<P><A NAME="1019880"></A></P>
+
+<BLOCKQUOTE>
+<P>The Directory Server interface is actually a collection of forms and
+CGI programs that operate independently from the Directory Server. This
+interface acts as an LDAP client to the Directory Server. </P>
+</BLOCKQUOTE>
+
+<P><A NAME="1019775"></A>The following section explains what happens when
+you search the Directory Server:</P>
+
+<OL>
+<P><A NAME="1018241"></A></P>
+
+<LI>When you submit the form, you send a search filter to the Directory
+Server. <A NAME="1018242"></A></LI>
+
+<LI>The Directory Server examines the incoming request to verify that the
+information is in the local directory. If the information is not in the
+local directory and the Referral parameter is set for the server, the Directory
+Server returns the URL for the other Directory Server where the client
+can attempt to pursue the request. <A NAME="1018244"></A></LI>
+
+<LI>The Directory Server generates a list of entries from the directory
+tree. The Directory Server then examines each of the candidate entries
+to see if any entry matches the search criteria. Matching entries are returned
+to the Directory Server interface as each is found. <A NAME="1019576"></A>This
+process continues until the Directory Server either has examined all applicable
+entries, or until it reaches one of the following limits: </LI>
+
+<UL>
+<P><A NAME="1018252"></A></P>
+
+<LI>The maximum number of entries that can be returned in response to a
+search <A NAME="1018259"></A></LI>
+
+<LI>The maximum amount of time that can be taken for a search <A NAME="1018266"></A></LI>
+
+<LI>The maximum number of entries that can be examined during a search
+</LI>
+</UL>
+</OL>
+
+<P><A NAME="1019628"></A>Your administrator can configure these settings.
+For more detailed information on the searching algorithm, see the <I>Netscape
+Directory Server Administrator's Guide</I>. </P>
+
+<P><A NAME="1019776"></A>The rest of this section explains how approximate
+searches work and how substring searches work. </P>
+
+<P><A NAME="How Approximate ("></A><A NAME="1018301"></A></P>
+
+<H3>How Approximate (&quot;sounds like&quot;) Searches Work</H3>
+
+<P><A NAME="1018302"></A>The approximate search finds a word that &quot;sounds
+like&quot; the value you enter. In the Advanced Search interface, the approximate
+search corresponds to the &quot;sounds like&quot; search type. </P>
+
+<P><A NAME="1019677"></A>For example, an entry may include the attribute
+value cn=Robert E Lee. An approximate search allows you to find this entry
+by specifying Robert Lee, Robert, or Lee. Similarly, a search for the location
+approximately equal to San Fransico (l~=San Fransico; note the misspelling)
+would return entries including locations exactly equal to San Francisco
+(l=San Francisco).</P>
+
+<P><A NAME="1018303"></A>The Directory Server treats each value in an entry
+as a sequence of words and generates a phonetic code for each word. When
+you enter a value in an approximate search, the Directory Server also translates
+the value to a sequence of phonetic codes. An entry is considered to match
+a query if:</P>
+
+<UL>
+<P><A NAME="1018305"></A></P>
+
+<LI>All of the codes in your search criteria are present in the codes generated
+for the entry. <A NAME="1018306"></A></LI>
+
+<LI>All of the codes in your search criteria are specified in the same
+order as the codes generated for the entry. </LI>
+</UL>
+
+<P><A NAME="1018344"></A>For example: </P>
+
+<TABLE BORDER=2 >
+<CAPTION></CAPTION>
+
+<TR>
+<TH><A NAME="1018309"></A><B>Name in the directory <BR>
+(Phonetic code) </B></TH>
+
+<TH><A NAME="1018311"></A><B>Your search string <BR>
+(Phonetic code) </B></TH>
+
+<TH><A NAME="1018313"></A><B>Match comments</B> </TH>
+</TR>
+
+<TR>
+<TD><A NAME="1018315"></A>Alice B Sarette<BR>
+(ALS B SRT) </TD>
+
+<TD><A NAME="1018317"></A>Alice Sarette<BR>
+(ALS SRT) </TD>
+
+<TD><A NAME="1018319"></A>Matches. Codes are specified in the correct order.
+</TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018321"></A></TD>
+
+<TD><A NAME="1018323"></A>Alice Sarrette<BR>
+(ALS SRT) </TD>
+
+<TD><A NAME="1018325"></A>Matches. Codes are specified in the correct order
+despite the misspelling of Sarette. </TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018327"></A></TD>
+
+<TD><A NAME="1018329"></A>Surette<BR>
+(SRT) </TD>
+
+<TD><A NAME="1018331"></A>Matches. The generated code exists in the original
+name despite the misspelling of Sarette. </TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018333"></A></TD>
+
+<TD><A NAME="1018335"></A>Bertha Sarette<BR>
+(BR0 SRT) </TD>
+
+<TD><A NAME="1018337"></A>No match. The code BR0 does not exist in the
+original name. </TD>
+</TR>
+
+<TR>
+<TD><A NAME="1018339"></A></TD>
+
+<TD><A NAME="1018341"></A>Sarette, Alice<BR>
+(SRT ALS) </TD>
+
+<TD><A NAME="1018343"></A>No match. The codes are not specified in the
+correct order. </TD>
+</TR>
+</TABLE>
+
+<TABLE>
+<TR>
+<TD></TD>
+</TR>
+</TABLE>
+
+<P><A NAME="How Substring Searches Work"></A><A NAME="1018345"></A></P>
+
+<H3>How Substring Searches Work</H3>
+
+<P><A NAME="1018346"></A>The substring search finds entries that contain
+the value you have entered. In the Advanced Search interface, the substring
+search corresponds to the &quot;starts with&quot;, &quot;contains&quot;,
+and &quot;ends with&quot; search types. </P>
+
+<P><A NAME="1018347"></A>For example, searches of the form:</P>
+
+<UL>
+<UL>
+<P><A NAME="1018348"></A><TT>cn=*derson</TT><BR>
+</P>
+</UL>
+</UL>
+
+<P><A NAME="1018349"></A>would match the common names containing strings
+such as:</P>
+
+<P><A NAME="1018350"></A></P>
+
+<UL>
+<UL>
+<PRE>Bill Anderson
+Jill Anderson
+Steve Sanderson
+</PRE>
+</UL>
+</UL>
+
+<P><A NAME="1018351"></A>and so forth. Similarly, the search for</P>
+
+<UL>
+<UL>
+<P><A NAME="1018352"></A><TT>telephonenumber= *555*</TT><BR>
+</P>
+</UL>
+</UL>
+
+<P><A NAME="1018353"></A>would return all the entries in your directory
+with telephone numbers that contain 555.</P>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/manual/index.html b/ldap/clients/dsgw/html/manual/index.html
new file mode 100644
index 00000000..2d1fcdbe
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/index.html
@@ -0,0 +1,150 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<A NAME="6807">
+<H1>
+</H1>
+</A>
+
+
+<h2>Symbols</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018202">! (boolean operator) 28</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018202">&amp; (boolean operator) 28</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">&lt;= (search filter operator) 27</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">= (search filter operator) 26</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">=* (search filter operator) 27</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">&gt;= (search filter operator) 27</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015792">@ symbol in search criteria 17</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018202">| (boolean operator) 28</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">~= (search filter operator) 27</a></dl>
+</dl>
+<h2>A</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#996824">access control 51</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1019235">directory manager 56</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1019233">setting up anonymous access 55</a></dl>
+<dt><dd>adding<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#996824">entries 33</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1017016">groups 37</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1021328">NT-people 35</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1017017">organizational units 38</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1020503">organizations 38</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1017015">people 34</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016146">Admin (attribute field) 65</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015906">Advanced Search 18</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016481">examples of 22</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015914">Find field 19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016028">specifying the attribute used 20</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1020752">specifying the type of search 21</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1020751">type field 21</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015967">where field 20</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1019233">anonymous access 55</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016441">approximate search 22</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018301">how it works 30</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004519">attribute fields 64</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1011923">defined 58</a></dl>
+<dt><dd>attributes<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016028">searching based on an attribute's value 20</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1019127">using in search filters 26</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019066">authentication 6</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#996824">51</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1019235">as the directory manager 56</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016557">no matching entries found 23</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1016877">performing 52</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1019233">setting up anonymous access 55</a></dl>
+</dl>
+</dl>
+
+<h2>B</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004700">bin (attribute field format) 65</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018167">boolean operators 27</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018173">28</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003042">Business Category (attribute field) 65</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003042">businessCategory (attribute internal ID) 65</a></dl>
+</dl>
+<h2>C</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019537">c (attribute in a distinguished name) 10</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003044">Car License (attribute field) 65</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003044">carLicense (attribute internal ID) 65</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004701">ces (attribute field format) 65</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">changing a person entry's password 41</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">changing an NT-person password 43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020703">changing passwords 49</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004702">cis (attribute field format) 65</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019537">cn (attribute in a distinguished name) 10</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015820">cn (attribute internal ID) 67</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019366">common names 15</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015820">commonName (attribute internal ID) 67</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016440">"contains" search 22</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018345">how it works 31</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1017537">Create New NT Account (attribute field) 66</a></dl>
+</dl>
+<h2>D</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1017434">Delete NT Account if Person Deleted (attribute field) 66</a><dt><dd>deleting<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1017977">entries 49</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018061">group entries 44</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">NT-people entries 43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019729">organization entries 46</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018896">organizational unit entries 45</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">people's entries 41</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015879">departmentNumber (attribute internal ID) 66</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015879">Dept# (attribute field) 66</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004238">Description (attribute field) 66</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004238">description (attribute internal ID) 66</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1017847">Directory Server 5</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019066">access control 6</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#996824">51</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1017016">adding a group 37</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1017015">adding a person 34</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1021328">adding an NT-person 35</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1020503">adding an organization 38</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#1017017">adding an organizational unit 38</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019060">adding entries 5</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#996824">33</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019066">authenticating to 6</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#996824">authentication 51</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">changing NT-person passwords 43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020703">changing passwords 49</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">changing people passwords 41</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1017847">defined 5</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018061">deleting a group entry 44</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">deleting a person's entry 41</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">deleting an NT-person entry 43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019729">deleting an organization entry 46</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018896">deleting an organizational unit entry 45</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019063">deleting entries 5</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1017977">49</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018061">editing a group's entry 44</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">editing a person's entry 41</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">editing an NT-person's entry 43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019729">editing an organization entry 46</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018896">editing an organizational unit entry 45</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018240">interface defined 29</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019063">modifying entries 5</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1018798">organization of data in 7</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1016903">permissions 53</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018061">renaming a group entry 44</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">renaming a person's entry 41</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">renaming an NT-person entry 43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019729">renaming an organization entry 46</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018896">renaming an organizational unit entry 45</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019063">renaming entries 5</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019773">47</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019335">searching 5</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#997436">13</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019066">security 6</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#996824">51</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1018798">tree hierarchy 7</a></dl>
+<dt><dd>directory service<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019237">defined 6</a></dl>
+<dt><dd>distinguished name (DN)<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019610">defined 9</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019538">examples of 11</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019466">standard attributes 10</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019462">syntax 9</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004704">dn (attribute field format) 65</a></dl>
+</dl>
+<h2>E</h2>
+<dl><dl>
+<dt><dd>editing<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#996824">entries 41</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018061">group entries 44</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">NT-person entries 43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019729">organization entries 46</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018896">organizational unit entries 45</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">people's entries 41</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">43</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015992">E-Mail Address (attribute field) 66</a><dt><dd>e-mail addresses<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015791">searching for 17</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003050">Emp# (attribute field) 67</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003050">employeeNumber (attribute internal ID) 67</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016439">"ends with" search 22</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018345">how it works 31</a></dl>
+<dt><dd>entries<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019060">adding 5</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#996824">33</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019063">deleting 5</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1017977">49</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#996824">editing 41</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019063">modifying 5</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#996824">41</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019063">renaming 5</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019773">47</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016571">searching for types of 14</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1002653">entry types 58</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1002638">defined 58</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016432">exact match search 22</a></dl>
+</dl>
+<h2>F</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004782">facsimileTelephoneNumber (attribute internal ID) 67</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004782">Fax (attribute field) 67</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004782">fax (attribute internal ID) 67</a><dt><dd>Find field<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1018630">Anything 15</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019829">19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016700">Groups 14</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015931">19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015914">in Advanced Search 19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016571">in Smart Search 14</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1021638">NT-people 14</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016705">Org_Units 14</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019059">19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016702">Organizations 14</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019056">19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016698">People 14</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015916">19</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003054">First Name (attribute field) 67</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015820">Full Name (attribute field) 67</a></dl>
+</dl>
+<h2>G</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003054">givenName (attribute internal ID) 67</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005294">Group (entry type) 62</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016040">Group Members (attribute field) 68</a></dl>
+</dl>
+<h2>I</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016236">internal attribute ID 64</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016433">"is not" search 22</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016432">"is" search 22</a></dl>
+</dl>
+<h2>L</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019537">l (attribute in a distinguished name) 10</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004816">l (attribute internal ID) 68</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015921">labeledURI (attribute internal ID) 72</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015952">Last Name (attribute field) 68</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019237">Lightweight Directory Access Protocol (LDAP) 6</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004816">localityName (attribute internal ID) 68</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004816">Location (attribute field) 68</a></dl>
+</dl>
+<h2>M</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015992">mail (attribute internal ID) 66</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016103">Mailing Address (attribute field) 68</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015579">Manager (attribute field) 69</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015579">manager (attribute internal ID) 69</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016040">member (attribute internal ID) 68</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015590">mobile (attribute internal ID) 69</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015590">Mobile Phone (attribute field) 69</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015590">mobileTelephoneNumber (attribute internal ID) 69</a><dt><dd>modifying<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#996824">entries 41</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018061">group entries 44</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">NT-people entries 43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019729">organization entries 46</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018896">organizational unit entries 45</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">people's entries 41</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">43</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018167">multiple search filters 27</a></dl>
+</dl>
+<h2>N</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015595">Name (attribute field) 69</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1017346">NT Domain Name (attribute field) 69</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1017371">NT User Id (attribute field) 70</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1018209">NT-person (entry type) 60</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1017682">NTUserCreateNewAccount (attribute internal ID) 66</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1017503">NTUserDelete (attribute internal ID) 66</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1017364">NTUserDomainId (attribute internal ID) 70</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019356">numbers in search criteria 17</a></dl>
+</dl>
+<h2>O</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019537">o (attribute in a distinguished name) 11</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015598">o (attribute internal ID) 70</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005782">Organization (entry type) 64</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015598">Organization Name (attribute field) 70</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016060">Organizational Unit (attribute field) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005780">Organizational Unit (entry type) 63</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016060">organizationalUnitName (attribute internal ID) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015598">organizationName (attribute internal ID) 70</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019537">ou (attribute in a distinguished name) 11</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016060">ou (attribute internal ID) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005719">Owner (attribute field) 70</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005719">owner (attribute internal ID) 70</a></dl>
+</dl>
+<h2>P</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003070">Pager (attribute field) 70</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003070">pager (attribute internal ID) 70</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003070">pagerTelephoneNumber (attribute internal ID) 70</a><dt><dd>passwords<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">changing 41</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">43</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020703">49</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1016903">permissions 53</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005608">Person (entry type) 59</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1018209">60</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016078">Phone (attribute field) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016103">postalAddress (attribute internal ID) 68</a></dl>
+</dl>
+<h2>R</h2>
+<dl><dl>
+<dt><dd>renaming<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019773">entries 47</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018061">group entries 44</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1020767">NT-people entries 43</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1019729">organization entries 46</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018896">organizational unit entries 45</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#1018988">people's entries 41</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003082">Room Number (attribute field) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003082">roomNumber (attribute internal ID) 71</a></dl>
+</dl>
+<h2>S</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019400">search filters 17</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#996824">25</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018095">basic syntax 25</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018167">combining multiple 27</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018203">examples 28</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018167">syntax for multiple filters 27</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1019127">using attributes 26</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1019138">using operators 26</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016552">search results 23</a><dt><dd>search types<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">approximate 27</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">equality 26</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">exact match 26</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">numeric comparisons 27</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">presence 27</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1019138">search filter operators and 26</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1020752">specifying in Advanced Search 21</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018153">substring 26</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019335">searching 5</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#997436">13</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019373">case-sensitivity and 15</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1018630">for all types of entries 15</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019829">19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019372">for an exact match 15</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015791">for e-mail addresses 17</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016700">for groups 14</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019362">for names 15</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1021638">for NT-people 14</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019356">for numbers 17</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016705">for organizational units 14</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019059">19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016702">for organizations 14</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019056">19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016698">for people 14</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015916">19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016571">for specific types of entries 14</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019375">for words that sound alike 15</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018239">how it works 29</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015906">using Advanced Search 18</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019400">using filters 17</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019381">using initials 16</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015773">using Smart Search 13</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016552">working with results 23</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015931">searching for groups 19</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016146">secretary (attribute internal ID) 65</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#996824">security 51</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1019235">directory manager 56</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004337">See Also (attribute field) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004337">seeAlso (attribute internal ID) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015773">Smart Search 13</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016571">Find field 14</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#996824">search filters 25</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015791">searching for e-mail addresses 17</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019362">searching for names 15</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019381">searching for names with initials 16</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019356">searching for numbers 17</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019400">using search filters 17</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015952">sn (attribute internal ID) 68</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016441">"sounds like" search 22</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018301">how it works 30</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019537">st (attribute in a distinguished name) 11</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016434">"starts with" search 22</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018345">how it works 31</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/intro.htm#1019537">street (attribute in a distinguished name) 11</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016434">substring search 22</a><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1019375">defined 15</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/filters.htm#1018345">how it works 31</a></dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015952">surname (attribute internal ID) 68</a></dl>
+</dl>
+<h2>T</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1004703">tel (attribute field format) 65</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016078">telephoneNumber (attribute internal ID) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003096">Title (attribute field) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003096">title (attribute internal ID) 71</a><dt><dd>type field<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1020751">in Advanced Search 21</a></dl>
+</dl>
+</dl>
+<h2>U</h2>
+<dl><dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1017386">uid (attribute internal ID) 70</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016953">72</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016060">Unit Name (attribute field) 71</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015921">URL (attribute field) 72</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016953">User ID (attribute field) 72</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016953">userid (attribute internal ID) 72</a></dl>
+</dl>
+<h2>W</h2>
+<dl><dl>
+<dt><dd>where field<dl>
+<dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1015967">in Advanced Search 20</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1020749">options for finding anything 21</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016358">options for finding groups 20</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016363">options for finding organizations 21</a><dt><dd><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#1016284">options for finding people 20</a></dl>
+</dl>
diff --git a/ldap/clients/dsgw/html/manual/index.map b/ldap/clients/dsgw/html/manual/index.map
new file mode 100644
index 00000000..a70461c3
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/index.map
@@ -0,0 +1,49 @@
+;-------------------------------------------------------------------------
+; PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+; license terms. Copyright © 2001 Sun Microsystems, Inc.
+; Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+; All rights reserved.
+;-------------------------------------------------------------------------
+; -------------------------------------------MAPPINGS
+; CGIScriptName = HTMLfile#AnchorName
+; last update, sarette 10/10
+;-------------------------------------------PROGRAMS
+;
+;
+SEARCHING = search.htm
+SMARTSEARCH = search.htm#Performing a Standard Search
+ASEARCH = search.htm#Performing an Advanced Search
+
+AUTHENTICATING = auth.htm
+AUTHHELP_ID = auth.htm#userauth
+AUTHHELP_PW = auth.htm#userauth
+UNAUTH = auth.htm#logout
+AUTHPROBLEM = auth.htm#incorrectauth
+AUTHSUCCESS = auth.htm#authsuccess
+AUTHEXPIRED = auth.htm#reauth
+AUTHMULTMATCH = auth.htm#userauth
+
+EDITING = mod.htm
+EDIT_GROUP = mod.htm#groups
+EDIT_NTGROUP = mod.htm#NTgroups
+EDIT_GROUPMEM = mod.htm#addowner
+EDIT_PERSON = mod.htm#people
+EDIT_NTPERSON = mod.htm#ntpeople
+EDIT_ORG = mod.htm#o
+EDIT_ORGPERSON = mod.htm#people
+EDIT_ORGUNIT = mod.htm#ou
+MODIFYPASSWD = mod.htm#changepw
+EDIT_PERSON_REF = mod.htm#addmanager
+
+ADDING = add.htm
+ADD_NOPARENT = add.htm#tree
+ADD_GROUP = add.htm#group
+ADD_NTGROUP = add.htm#NTgroup
+ADD_PERSON = add.htm#person
+ADD_NTPERSON = add.htm#NTperson
+ADD_ORG = add.htm#o
+ADD_ORGPERSON = add.htm#person
+ADD_ORGUNIT = add.htm#ou
+ENTRYEXISTS = add.htm#uniqueDN
+
+contents = contents.html
diff --git a/ldap/clients/dsgw/html/manual/intro.htm b/ldap/clients/dsgw/html/manual/intro.htm
new file mode 100644
index 00000000..8f9ae90e
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/intro.htm
@@ -0,0 +1,70 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<html>
+<head>
+<title>Introduction to the Netscape Directory Server Interface</title>
+</head>
+
+<body>
+
+<h1>Introduction to the Directory Server Interface</h1>
+
+<p>The Netscape Directory Server is a robust, scalable server for storing, querying, and
+managing an enterprise-wide directory of users and information. Using the Directory Server, corporate IS organizations can manage
+information from a single point of control, and employees can retrieve this information from multiple network locations.</p>
+
+<p>The directory server provides a simple interface to
+corporate user information. From this interface, you can:</p>
+
+<ul>
+<P>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#search">Search the directory for
+ information about users and resources.</a> For example,
+ you can search for an employee's email address or phone
+ number. You can find more information about searching the
+ directory in <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm">Chapter 2,
+ &quot;Searching the Directory Tree.&quot;</a></li>
+<P>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#adding">Create a new entry in the
+ directory.</a> For example, you can add information about
+ a new employee, such as the employee's name and phone
+ number. This feature is usually reserved only for
+ users who have authenticated properly to the Directory
+ Server, and who have been granted write permissions by
+ the directory administrator. For information about adding
+ new users, groups, organizational units, and
+ organizations to the directory, see <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm">Chapter 3,
+ &quot;Adding Entries.&quot;</a></li>
+<P>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#editing">Modify existing entries in the
+ directory.</a> For example, if you have the appropriate
+ permissions, you can change existing values to entry
+ attributes, delete the entire entry, rename the entry,
+ or change the password for the entry.
+ This feature is usually reserved only for users who have been
+ granted write permissions by the directory administrator, and
+ have authenticated properly to the Directory Server. For
+ instructions on updating information about users, groups,
+ organizational units, and organizations, see <a
+ href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm">Chapter 4, &quot;Editing
+ Entries.&quot;</a></li>
+<P>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#authenticating">Authenticate to the
+ Directory Server.</a> If your directory manager has made
+ authentication a requirement for accessing or writing to the Directory
+ Server, you may need to enter your user name and password.
+ While the exact authentication requirements
+ vary from site to site, the Directory Server typically
+ requires authentication only if you are adding,
+ modifying, or deleting an entry in the directory. For
+ details on authenticating to the Directory Server, see <a
+ href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm">Chapter 5, &quot;Authentication.&quot;</a></li>
+</ul>
+
+<p> </p>
+</body>
+</html>
diff --git a/ldap/clients/dsgw/html/manual/ja/add.htm b/ldap/clients/dsgw/html/manual/ja/add.htm
new file mode 100644
index 00000000..ce2805e2
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/ja/add.htm
@@ -0,0 +1,517 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<TITLE>ディレクトリ エントリã®è¿½åŠ 
+</TITLE>
+</HEAD>
+<BODY>
+
+<H1>
+<A NAME="adding"></A>エントリã®è¿½åŠ </H1>
+Directory Serverインタフェースを使用ã—ã¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã§ãã¾ã™ã€‚エントリを追加ã™ã‚‹ã«ã¯ã€ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã§ãる権é™ãŒDirectory Server管ç†è€…ã‹ã‚‰ä»˜ä¸Žã•ã‚Œã¦ã„ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。エントリã®è¿½åŠ ã®å‰ã«ã¯ã€Directory Serverã¸ã®<A HREF="auth.htm#userauth">èªè¨¼</A>ãŒå¿…è¦ã§ã™ã€‚
+
+<P>Directory Serverインタフェースを使用ã—ã¦ã€ä»¥ä¸‹ã‚’追加ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚
+<UL>
+<LI>
+<A HREF="#person">ユーザ</A></LI>
+
+<LI>
+<A HREF="#NTperson">NTユーザ</A></LI>
+
+<LI>
+<A HREF="#group">グループ</A></LI>
+
+<LI>
+<A HREF="#NTgroup">NTグループ</A></LI>
+
+<LI>
+<A HREF="#ou">組織å˜ä½</A></LI>
+
+<LI>
+<A HREF="#o">組織</A></LI>
+</UL>
+åˆã‚ã¦ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹å‰ã«ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーãŠã‚ˆã³å‘½åè¦ç´„ã«é–¢ã™ã‚‹é‡è¦ãªæƒ…å ±ã«ã¤ã„ã¦ã€<A HREF="#guidelines">「新è¦ã‚¨ãƒ³ãƒˆãƒªã«é–¢ã™ã‚‹ã‚¬ã‚¤ãƒ‰ãƒ©ã‚¤ãƒ³ã€</A>ã®é …ã‚’ãŠèª­ã¿ãã ã•ã„。
+<H2>
+<A NAME="guidelines"></A>æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã«é–¢ã™ã‚‹ã‚¬ã‚¤ãƒ‰ãƒ©ã‚¤ãƒ³</H2>
+ディレクトリã«ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ã‚’始ã‚ã‚‹å‰ã«ã€ä»¥ä¸‹ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªæ¦‚念をç†è§£ã—ã¦ãŠã„ã¦ãã ã•ã„。
+<UL>
+<LI>
+<A HREF="#tree">ディレクトリ ツリー構造</A></LI>
+
+<LI>
+<A HREF="#DN">識別åã®æ§‹æ–‡</A></LI>
+
+<LI>
+<A HREF="#uniqueDN">固有ã®è­˜åˆ¥å</A></LI>
+</UL>
+
+<H3>
+<A NAME="tree"></A>ディレクトリ ツリー構造</H3>
+ディレクトリã®ãƒ‡ãƒ¼ã‚¿ã¯ãƒ„リー階層ã§æ•´ç†ã•ã‚Œã¦ã„ã¾ã™ã€‚ツリーã®æœ€ä¸Šä½ã¯ã€ãƒ«ãƒ¼ãƒˆã¾ãŸã¯ã‚µãƒ•ã‚£ãƒƒã‚¯ã‚¹ã¨å‘¼ã°ã‚Œã¾ã™ã€‚通常ルート エントリã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®çµ„織エントリã«ãªã£ã¦ã„ã¾ã™ã€‚
+
+<BLOCKQUOTE><B>ノート:</B>
+<P>
+
+ã”使用ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ã¯è¤‡æ•°ã®ã‚µãƒ•ã‚£ãƒƒã‚¯ã‚¹ãŒå«ã¾ã‚Œã¦ã„ã‚‹ã‹ã‚‚ã—ã‚Œã¾ã›ã‚“ãŒã€Directory Serverインタフェースã§ã¯ã€å˜ä¸€ã®ã‚µãƒ•ã‚£ãƒƒã‚¯ã‚¹ã«å¯¾ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®æ¤œç´¢ã€è¿½åŠ ã€ç·¨é›†ã®ã¿ãŒå¯èƒ½ã§ã™ã€‚æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ã‚’開始ã™ã‚‹å‰ã«ã€Directory ServerインタフェースãŒã‚µãƒãƒ¼ãƒˆã—ã¦ã„るサフィックスを確èªã—ã¦ãã ã•ã„。</BLOCKQUOTE>
+
+
+<P>ルートã®ä¸‹ã«ã¯ãƒ„リーã®éšŽå±¤ãŒã‚ã‚Šã€é€šå¸¸ãƒžãƒ¼ã‚±ãƒ†ã‚£ãƒ³ã‚°ã‚„財務ãªã©ã®çµ„ç¹”å˜ä½ ãŒã‚ã‚Šã¾ã™ã€‚組織内ã®ãƒ¦ãƒ¼ã‚¶ãŠã‚ˆã³ãƒªã‚½ãƒ¼ã‚¹ã®ã‚¨ãƒ³ãƒˆãƒªã¯ã€æ™®é€šã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリー構造内ã®çµ„ç¹”å˜ä½éšŽå±¤ã®ä¸‹ã«å«ã¾ã‚Œã¦ã„ã¾ã™ã€‚
+
+<P>エントリã®è¿½åŠ ã®éš›ã«ã¯ã€éšŽå±¤ã®ä¸‹ã«æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã‚’作æˆã™ã‚‹å‰ã«ã€ãã®éšŽå±¤ ãƒã‚¤ãƒ³ãƒˆã‚’示ã™ã‚¨ãƒ³ãƒˆãƒªã‚’å¿…ãšä½œæˆã—ã¦ãã ã•ã„。例ãˆã°ã€Marketingã¨Accountingã®ã‚µãƒ–ツリーã«ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹å ´åˆã€ãれらã®ã‚µãƒ–ツリー内ã«ã‚¨ãƒ³ãƒˆãƒªã‚’作æˆã™ã‚‹å‰ã«ã€ã‚µãƒ–ツリーã®éšŽå±¤ ãƒã‚¤ãƒ³ãƒˆã‚’作æˆã—ã¾ã™ã€‚
+
+<PRE>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; o=Airius.com
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=Marketing, o=Airius.com
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <I>Marketing サブツリー エントリ</I>
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ou=Accounting, o=Airius.com
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ...
+&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <I>Accounting サブツリー エントリ</I>
+</PRE>
+
+<H3>
+<A NAME="DN"></A>識別åã®æ§‹æ–‡</H3>
+識別å(Distinguished Name = DN)を使用ã—ã¦ã€Directory Server内ã§å›ºæœ‰ã«ã‚¨ãƒ³ãƒˆãƒªã‚’識別ã—ã¾ã™ã€‚一連ã®ã‚«ãƒ³ãƒžã§åŒºåˆ‡ã‚‰ã‚ŒãŸå±žæ€§ã¨å±žæ€§å€¤ã‚’使用ã—ã¦ã€DNã§ã‚¨ãƒ³ãƒˆãƒªã‚’指定ã—ã¾ã™ã€‚DNã®ä¸€ç•ªå·¦ã®å€¤ã¯ã€ã‚¨ãƒ³ãƒˆãƒªåã¨ã€ãã®ã‚¨ãƒ³ãƒˆãƒªã®ä¸Šã®éšŽå±¤ ãƒã‚¤ãƒ³ãƒˆã‚’示ã™å¾Œç¶šã®å„属性を示ã—ã¦ã„ã¾ã™ã€‚ 例:
+<PRE>uid=bjensen, ou=people, o=airius.com</PRE>
+ã“ã®DNã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª<I>airius.com</I>内ã®ã‚µãƒ–ディレクトリ<I>people</I>ã«ã‚るエントリ<I>bjensen</I>を示ã—ã¦ã„ã¾ã™ã€‚
+
+<P>Directory Serverã«æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹éš›ã¯ã€å®Œå…¨ãªè­˜åˆ¥åを入力ã™ã‚‹ã‚ˆã†ãƒ—ロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚
+<H3>
+<A NAME="uniqueDN"></A>固有ã®è­˜åˆ¥å</H3>
+Directory Serverインタフェースã§ã¯ã€é‡è¤‡ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã¯ä½œæˆã§ãã¾ã›ã‚“。åå‰ã®é‡è¤‡ã‚’é¿ã‘ã‚‹ãŸã‚ã«ã€ãƒ¦ãƒ¼ã‚¶ã®ä¸€èˆ¬å(CN)ã§ã¯ãªãã€ãƒ¦ãƒ¼ã‚¶ID (uid)ã§å§‹ã¾ã‚‹è­˜åˆ¥åを使用ã—ã¾ã™ã€‚人間ãŒè­˜åˆ¥ã§ãるユーザIDã‚’é¸ã‚“ã§ãã ã•ã„。ã¤ã¾ã‚Šã€ãƒ¦ãƒ¼ã‚¶IDã«ã¯ã€æ–‡å­—や数字を無作為ã«é›†ã‚ãŸã‚‚ã®ã¯ä½¿ç”¨ã—ãªã„ã§ãã ã•ã„。既ã«é›»å­ãƒ¡ãƒ¼ãƒ« システムをã”使用ã®å ´åˆã¯ã€ãƒ¦ãƒ¼ã‚¶IDã«å„ユーザã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレスã®ä¸€ç•ªå·¦ã®å€¤ã‚’é¸æŠžã™ã‚‹ã“ã¨ã‚‚1ã¤ã®æ–¹æ³•ã§ã™ã€‚例ãˆã°ã€ãƒ¦ãƒ¼ã‚¶ã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレスãŒ
+
+<P>bjensen@airius.com
+
+<P>ã§ã‚ã‚‹å ´åˆã€ãã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª エントリã«æ¬¡ã®DNã‚’é¸æŠžã—ã¾ã™ã€‚
+
+<P>uid=bjensen, o=airius.com
+<H2><A NAME="person"></A>ユーザã®è¿½åŠ </H2>
+æ–°è¦ãƒ¦ãƒ¼ã‚¶ã‚’追加ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã«å¾“ã£ã¦ãã ã•ã„。
+<OL>
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]タブをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]フォームã«æ¦‚説ã•ã‚Œã¦ã„るステップã«å¾“ã„ã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€[継続]をクリックã—ã¾ã™ã€‚ã“ã®æ“作をキャンセルã™ã‚‹ã«ã¯ã€ãƒ–ラウザ ウィンドウã®[戻る]ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ã‚’試ã¿ã‚‹å‰ã«èªè¨¼ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã™ã‚‹ã‚ˆã†ãƒ—ロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ディレクトリã«ãƒ¦ãƒ¼ã‚¶ã‚’追加ã™ã‚‹éš›ã«ã¯ã€ãã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ‡ãƒ¼ã‚¿ã‚’編集å¯èƒ½ã«ã™ã‚‹ãƒ•ã‚©ãƒ¼ãƒ ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã¯ã€æ–°è¦ã‚¦ã‚§ãƒ– ブラウザ ウィンドウã«è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚必須フィールドã«ã¯å€¤ã‚’入力ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。ユーザã®å¿…須フィールドã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
+</LI>
+
+<UL type="disc">
+<LI>
+<A HREF="attribut.htm#cn">[æ°å]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#sn">[姓]</A></LI>
+</UL>
+
+<LI>
+オプションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯ã€å€¤ã‚’今入力ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§è¿½åŠ ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ユーザã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚
+</LI>
+&nbsp;
+<P>
+<CENTER><TABLE BORDER=2 >
+<TR>
+<TD><A HREF="attribut.htm#givenName">[åå‰]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#telephoneNumber">[電話番å·]
+</A></TD>
+
+<TD><A HREF="attribut.htm#mail">[é›»å­ãƒ¡ãƒ¼ãƒ« アドレス]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#facsimileTelephoneNumber">[ファックス]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#uid">[ユーザID]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#pager">[ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«]&nbsp;</A></TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#mobile">[æºå¸¯é›»è©±]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#businessCategory">[事業カテゴリ]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#title">[å½¹è·]</A></TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#ou">[組織å˜ä½]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#manager">[マãƒãƒ¼ã‚¸ãƒ£]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#roomNumber">[部屋番å·]&nbsp;</A></TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#secretary">[秘書]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#departmentNumber">[部門番å·]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#employeeNumber">[社員番å·]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#carLicense">[自動車ナンãƒãƒ¼ãƒ—レート番å·]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#postalAddress">[ä½æ‰€]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#labeledUri">[URL]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#userPassword">[パスワード]</A>&nbsp;</TD>
+</TR>
+</TABLE>
+</CENTER>
+<BLOCKQUOTE><B>ノート:</B>
+<P>
+エントリをä¿å­˜ã—ã¦ã‹ã‚‰ã§ãªã„ã¨ã€[マãƒãƒ¼ã‚¸ãƒ£]ã€[秘書]ã€ã¾ãŸã¯[å‚ç…§]ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯å€¤ã‚’入力ã§ãã¾ã›ã‚“。</BLOCKQUOTE>
+
+<LI>
+エントリã®ä½œæˆã‚’キャンセルã™ã‚‹ã«ã¯ã€ãƒ•ã‚©ãƒ¼ãƒ ã®ã‚るウェブ ブラウザã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‰ã˜ã¾ã™ã€‚フォームã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€ãƒ•ã‚©ãƒ¼ãƒ ä¸Šéƒ¨ã®[æ–°è¦ãƒ¦ãƒ¼ã‚¶ã®ä¿å­˜]ボタンをクリックã—ã¾ã™ã€‚
+</LI>
+
+<LI>
+エントリをä¿å­˜ã—ãŸå¾Œã€<A HREF="mod.htm#addmanager">[マãƒãƒ¼ã‚¸ãƒ£]ã¨[秘書]ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’追加</A>ã—ãŸã‚Šã€<A HREF="mod.htm#addowner">[å‚ç…§]ã«å€¤ã‚’追加</A>ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚</LI>
+</OL>
+
+<H2>
+<A NAME="NTperson"></A>NTユーザã®è¿½åŠ </H2>
+NTユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’作æˆã™ã‚‹éš›ã«ã¯ã€ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹ã‚µãƒ–ツリーãŒã€åŒæœŸåŒ–サービスãŒã‚¨ãƒ³ãƒˆãƒªã®åŒæœŸåŒ–ã«ä½¿ç”¨ã™ã‚‹ã‚‚ã®ã¨åŒã˜ã‚µãƒ–ツリーã§ã‚ã‚‹ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。別ã®å ´æ‰€ã«NTユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹ã¨ã€Windowsãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã§åŒæœŸåŒ–ãŒè¡Œã‚ã‚Œã¾ã›ã‚“。
+
+<P>æ–°è¦NTユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作をã—ã¾ã™ã€‚
+<OL>
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]タブをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]フォームã§æ¦‚説ã•ã‚Œã¦ã„るステップã«å¾“ã„ã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€[継続]をクリックã—ã¾ã™ã€‚ã“ã®æ“作をキャンセルã™ã‚‹ã«ã¯ã€ãƒ–ラウザ ウィンドウã®[戻る]ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ã‚’試ã¿ã‚‹å‰ã«èªè¨¼ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã™ã‚‹ã‚ˆã†ãƒ—ロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ディレクトリã«NTユーザを追加ã™ã‚‹éš›ã«ã¯ã€ãã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ‡ãƒ¼ã‚¿ã‚’編集å¯èƒ½ã«ã™ã‚‹ãƒ•ã‚©ãƒ¼ãƒ ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã¯ã€æ–°è¦ã‚¦ã‚§ãƒ– ブラウザ ウィンドウã«è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚必須フィールドã«ã¯å¿…ãšå€¤ã‚’入力ã™ã‚‹ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。NTユーザã®å¿…須フィールドã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚</LI>
+
+<UL type="disc">
+<LI>
+<A HREF="attribut.htm#cn">[æ°å]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#sn">[姓]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#ntUserDomainId">[NTドメインå]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#uid">[NTユーザID]</A></LI>
+</UL>
+
+<LI>
+オプションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯ã€å€¤ã‚’今入力ã—ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§è¿½åŠ ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ユーザã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚</LI>
+<P>
+<CENTER><TABLE BORDER=2 >
+<TR>
+<TD><A HREF="attribut.htm#givenName">[åå‰]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#telephoneNumber">[電話番å·]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#mail">[é›»å­ãƒ¡ãƒ¼ãƒ« アドレス]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#facsimileTelephoneNumber">[ファックス]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#userPassword">[Directory Serverã®ãƒ‘スワード]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#pager">[ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#mobile">[æºå¸¯é›»è©±]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#businessCategory">[事業カテゴリ]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#title">[å½¹è·]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#ou">[組織å˜ä½]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#manager">[マãƒãƒ¼ã‚¸ãƒ£]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#roomNumber">[部屋番å·]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#secretary">[秘書]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#departmentNumber">[部門番å·]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#employeeNumber">[社員番å·]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#carLicense">[自動車ナンãƒãƒ¼ãƒ—レート番å·]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#postalAddress">[ä½æ‰€]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#labeledUri">[URL]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#uid">[ユーザID]</A></TD>
+</TR>
+</TABLE></CENTER>
+<BLOCKQUOTE><B>ノート:</B>
+<P>
+
+エントリをä¿å­˜ã—ã¦ã‹ã‚‰ã§ãªã„ã¨ã€[マãƒãƒ¼ã‚¸ãƒ£]ã€[秘書]ã€ã¾ãŸã¯[å‚ç…§]ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯å€¤ã‚’入力ã§ãã¾ã›ã‚“。
+</BLOCKQUOTE>
+
+<LI>
+ã¾ãŸã€ä»¥ä¸‹ã®2ã¤ã®ã‚ªãƒ—ションã®å€¤ã‚‚変更ã§ãã¾ã™ã€‚</LI>
+
+<UL type="disc">
+<LI>
+<A HREF="attribut.htm#NTUserDelete">[ユーザãŒå‰Šé™¤ã•ã‚ŒãŸã‚‰NTアカウントを削除ã™ã‚‹]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#ntUserCreateNewAccount">[æ–°è¦NTアカウントã®ä½œæˆ]</A></LI>
+</UL>
+デフォルト値ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®å€¤ã‚’変更ã—ãªã„ã¨ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆå€¤ãŒä½¿ç”¨ã•ã‚Œã¾ã™ã€‚
+<LI>
+フォームã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€ãƒ•ã‚©ãƒ¼ãƒ ä¸Šéƒ¨ã®[æ–°è¦NTユーザã®ä¿å­˜]ボタンをクリックã—ã¾ã™ã€‚エントリã®ä½œæˆã‚’キャンセルã™ã‚‹ã«ã¯ã€ãƒ•ã‚©ãƒ¼ãƒ ã®ã‚るウェブ ブラウザ ウィンドウ閉ã˜ã¾ã™ã€‚ </LI>
+
+<LI>
+エントリをä¿å­˜ã—ãŸå¾Œã€<A HREF="mod.htm#addmanager">[マãƒãƒ¼ã‚¸ãƒ£]ã¨[秘書]フィールドã«å€¤ã‚’追加ã—ãŸã‚Šã€</A><A HREF="mod.htm#addowner">[å‚ç…§]ã«å€¤ã‚’追加</A>ã—ãŸã‚Šã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚</LI>
+</OL>
+
+<H2>
+<A NAME="group"></A>グループã®è¿½åŠ </H2>
+æ–°è¦ã‚°ãƒ«ãƒ¼ãƒ—ã®ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作をã—ã¾ã™ã€‚
+<OL>
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]タブをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]フォームã§æ¦‚説ã•ã‚Œã¦ã„るステップã«å¾“ã„ã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€[継続]をクリックã—ã¾ã™ã€‚ã“ã®æ“作をキャンセルã™ã‚‹ã«ã¯ã€ãƒ–ラウザ ウィンドウã®[戻る]ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ã‚’試ã¿ã‚‹å‰ã«èªè¨¼ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã™ã‚‹ã‚ˆã†ãƒ—ロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ディレクトリã«ã‚°ãƒ«ãƒ¼ãƒ—を追加ã™ã‚‹éš›ã«ã¯ã€ãã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ãƒ‡ãƒ¼ã‚¿ã®ç·¨é›†ã‚’å¯èƒ½ã«ã™ã‚‹ãƒ•ã‚©ãƒ¼ãƒ ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã¯ã€æ–°è¦ã‚¦ã‚§ãƒ– ブラウザ ウィンドウã«å«ã¾ã‚Œã¦ã„ã¾ã™ã€‚必須フィールドã«å€¤ã‚’入力ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚
+
+<A HREF="attribut.htm#cn">[åå‰]</A></LI>
+
+<LI>
+オプションã®<A HREF="attribut.htm#description">[説明]</A>ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯ã€å€¤ã‚’今入力ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§è¿½åŠ ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</LI>
+
+<BLOCKQUOTE><B>ノート:</B>
+<P>
+
+エントリをä¿å­˜ã—ã¦ã‹ã‚‰ã§ãªã„ã¨ã€[所有者]ã€[グループ メンãƒãƒ¼]ã€ã¾ãŸã¯[å‚ç…§]ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯å€¤ã‚’入力ã§ãã¾ã›ã‚“。</BLOCKQUOTE>
+
+<LI>
+フォームã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€ãƒ•ã‚©ãƒ¼ãƒ ä¸Šéƒ¨ã®[æ–°è¦ã‚°ãƒ«ãƒ¼ãƒ—ã®ä¿å­˜]ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<BR>エントリã®ä½œæˆã‚’キャンセルã™ã‚‹ã«ã¯ã€ãƒ•ã‚©ãƒ¼ãƒ ã®ã‚るウェブ ブラウザ ウィンドウを閉ã˜ã¾ã™ã€‚
+<LI>
+エントリをä¿å­˜ã—ãŸå¾Œã€<A HREF="mod.htm#addowner">[所有者]ã€[グループ メンãƒãƒ¼]ã€ãŠã‚ˆã³[å‚ç…§]ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’追加ã§ãã¾ã™ã€‚</A></LI>
+</OL>
+
+<H2>
+<A NAME="NTgroup"></A>NTグループã®è¿½åŠ </H2>
+æ–°è¦NTグループã®ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作をã—ã¾ã™ã€‚
+<OL>
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]タブをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]フォームã§æ¦‚説ã•ã‚Œã¦ã„るステップã«å¾“ã„ã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€[継続]をクリックã—ã¾ã™ã€‚ã“ã®æ“作をキャンセルã™ã‚‹ã«ã¯ã€ãƒ–ラウザ ウィンドウã®[戻る]ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ã‚’試ã¿ã‚‹å‰ã«èªè¨¼ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã™ã‚‹ã‚ˆã†ãƒ—ロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ディレクトリã«NTグループを追加ã™ã‚‹éš›ã«ã¯ã€ãã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ãƒ‡ãƒ¼ã‚¿ã®ç·¨é›†ã‚’å¯èƒ½ã«ã™ã‚‹ãƒ•ã‚©ãƒ¼ãƒ ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã¯ã€æ–°è¦ã‚¦ã‚§ãƒ– ブラウザ ウィンドウã«å«ã¾ã‚Œã¦ã„ã¾ã™ã€‚必須フィールドã«ã¯å€¤ã‚’å¿…ãšå…¥åŠ›ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。NTグループã®å¿…須フィールドã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚</LI>
+
+<UL type="disc">
+<LI>
+<A HREF="attribut.htm#cn">[åå‰]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#ntGroupId">[NTグループå]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#ntGroupDomainId">[NTグループ ドメイン]</A></LI>
+
+</UL>
+
+<LI>
+オプションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯ã€å€¤ã‚’今入力ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§è¿½åŠ ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚NTグループã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚</LI>
+&nbsp;
+<CENTER><TABLE BORDER=2 >
+<TR>
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#owner">[所有者]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#l">[言語情報]</A></TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#uniqueMember">[NTグループ メンãƒãƒ¼]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]</A></TD>
+
+<TD><A HREF="attribut.htm#ou">[組織å˜ä½]</A></TD>
+</TR>
+</TABLE>
+
+</CENTER>
+<P>
+<BLOCKQUOTE><B>ノート:</B>
+<P>
+
+エントリをä¿å­˜ã—ã¦ã‹ã‚‰ã§ãªã„ã¨ã€[所有者]ã€[NTグループ メンãƒãƒ¼]ã€ã¾ãŸã¯[å‚ç…§]ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’入力ã§ãã¾ã›ã‚“。</BLOCKQUOTE>
+
+<LI>
+ã¾ãŸã€<A HREF="attribut.htm#ntGroupDeleteGroup">[グループãŒå‰Šé™¤ã•ã‚Œã‚‹ã¨NTグループも削除ã™ã‚‹]</A>オプションã®å€¤ã‚‚変更ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+フォームã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€ãƒ•ã‚©ãƒ¼ãƒ ä¸Šéƒ¨ã®[æ–°è¦ã‚°ãƒ«ãƒ¼ãƒ—ã®ä¿å­˜]ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<BR>エントリã®ä½œæˆã‚’キャンセルã™ã‚‹ã«ã¯ã€ãƒ•ã‚©ãƒ¼ãƒ ã‚’å«ã‚€ã‚¦ã‚§ãƒ– ブラウザ ウィンドウ閉ã˜ã¾ã™ã€‚
+<LI>
+エントリをä¿å­˜ã—ãŸå¾Œã€<A HREF="mod.htm#addowner">[NTグループ メンãƒãƒ¼]ã€[所有者]ã€ãŠã‚ˆã³[å‚ç…§]ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’追加</A>ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚</LI>
+</OL>
+
+<H2>
+<A NAME="ou"></A>組織å˜ä½ã®è¿½åŠ </H2>
+æ–°è¦çµ„ç¹”ã®ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作をã—ã¾ã™ã€‚
+<OL>
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]タブをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]フォームã§æ¦‚説ã•ã‚Œã¦ã„るステップã«å¾“ã„ã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€[継続]をクリックã—ã¾ã™ã€‚ã“ã®æ“作をキャンセルã™ã‚‹ã«ã¯ã€ãƒ–ラウザ ウィンドウã®[戻る]ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ã‚’試ã¿ã‚‹å‰ã«èªè¨¼ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã™ã‚‹ã‚ˆã†ãƒ—ロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ディレクトリã«çµ„ç¹”å˜ä½ã‚’追加ã™ã‚‹éš›ã«ã¯ã€ãã®çµ„ç¹”ã®ãƒ‡ãƒ¼ã‚¿ã®ç·¨é›†ã‚’å¯èƒ½ã«ã™ã‚‹ãƒ•ã‚©ãƒ¼ãƒ ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã¯ã€æ–°è¦ã‚¦ã‚§ãƒ– ブラウザ ウィンドウã«è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚必須フィールドã«ã¯å¿…ãšå€¤ã‚’入力ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。組織å˜ä½ã®å¿…須フィールドã¯<A HREF="attribut.htm#ou">[å˜ä½å]</A>ã§ã™ã€‚</LI>
+
+<LI>
+オプションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯ã€å€¤ã‚’今入力ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§è¿½åŠ ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚組織å˜ä½ã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚</LI>
+&nbsp;
+<CENTER><TABLE BORDER=2 >
+<TR>
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#telephoneNumber">[電話番å·]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#businessCategory">[事業カテゴリ]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#facsimileTelephoneNumber">[ファックス]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#l">[場所]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#postalAddress">[ä½æ‰€]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]</A>&nbsp;</TD>
+
+<TD>&nbsp;</TD>
+
+<TD>&nbsp;</TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+フォームã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€ãƒ•ã‚©ãƒ¼ãƒ ä¸Šéƒ¨ã®[æ–°è¦çµ„ç¹”å˜ä½ã®ä¿å­˜]ボタンをクリックã—ã¾ã™ã€‚エントリã®ä½œæˆã‚’キャンセルã™ã‚‹ã«ã¯ã€ãƒ•ã‚©ãƒ¼ãƒ ã‚’å«ã‚€ã‚¦ã‚§ãƒ– ブラウザ ウィンドウ閉ã˜ã¾ã™ã€‚</LI>
+</OL>
+
+<H2><A NAME="o"></A>組織ã®è¿½åŠ </H2>
+æ–°è¦çµ„ç¹”ã®ã‚¨ãƒ³ãƒˆãƒªã‚’追加ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作をã—ã¾ã™ã€‚
+<OL>
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]タブをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+[æ–°è¦ã‚¨ãƒ³ãƒˆãƒª]フォームã§æ¦‚説ã•ã‚Œã¦ã„るステップã«å¾“ã„ã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€[継続]をクリックã—ã¾ã™ã€‚ã“ã®æ“作をキャンセルã™ã‚‹ã«ã¯ã€ãƒ–ラウザ ウィンドウã®[戻る]ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã®è¿½åŠ ã‚’試ã¿ã‚‹å‰ã«èªè¨¼ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã™ã‚‹ã‚ˆã†ãƒ—ロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ディレクトリ ツリーã«æœ€åˆã«æƒ…報をセットアップã™ã‚‹å ´åˆã«é™ã‚Šã€çµ„ç¹”ã®è¿½åŠ ãŒã‚µãƒãƒ¼ãƒˆã•ã‚Œã¦ã„ã¾ã™ã€‚追加ã™ã‚‹çµ„ç¹”ã¯ã€Directory Serverã®ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«æ™‚ã«[データベース サブツリー]フィールドã§æŒ‡å®šã—ãŸçµ„ç¹”ã¨ä¸€è‡´ã—ã¦ã„ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。ãŸã¨ãˆã°ã€</LI>
+
+<PRE>o=Airius.com</PRE>ã®å€¤ã‚’[データベース サブツリー]フィールドã«æŒ‡å®šã—ãŸå ´åˆã¯ã€çµ„織を追加ã™ã‚‹éš›ã«ã‚‚ã€
+<PRE>o=Airius.com</PRE>ã®å€¤ã‚’指定ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚Directory Serverã¯ã€ãƒ‡ãƒ¼ã‚¿ãƒ™ãƒ¼ã‚¹ サブツリーã¨ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª エントリãŒå…±å­˜å¯èƒ½ã§ã‚ã‚‹ã‹ã‚’確èªã™ã‚‹ãŸã‚ã€è¿½åŠ æ“作をãƒã‚§ãƒƒã‚¯ã—ã¾ã™ã€‚明らã‹ã«<PRE>o=Airius.com</PRE>以外ã®å€¤ã¯ã€
+<PRE>o=Airius.com</PRE>ã®ä¸‹ã«ã¯å…±å­˜ã§ãã¾ã›ã‚“。ãã®çµæžœã€è¿½åŠ æ“作ã¯æ‹’å¦ã•ã‚Œã¾ã™ã€‚
+
+<LI>
+必須フィールドã§ã‚ã‚‹<A HREF="attribut.htm#o">[組織å]</A>ã«ã¯å¿…ãšå€¤ã‚’入力ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。</LI>
+
+<LI>
+オプションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯ã€å€¤ã‚’今入力ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§è¿½åŠ ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚組織ã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚</LI>
+<P>
+<CENTER><TABLE BORDER=2 >
+<TR>
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#telephoneNumber">[電話番å·]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#businessCategory">[事業カテゴリ]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#facsimileTelephoneNumber">[ファックス]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#l">[場所]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#postalAddress">[ä½æ‰€]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]</A>&nbsp;</TD>
+
+<TD>&nbsp;</TD>
+
+<TD>&nbsp;</TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+フォームã®å…¥åŠ›ã‚’終ãˆãŸã‚‰ã€ãƒ•ã‚©ãƒ¼ãƒ ä¸Šéƒ¨ã®[æ–°è¦çµ„ç¹”ã®ä¿å­˜]ボタンをクリックã—ã¾ã™ã€‚エントリã®ä½œæˆã‚’キャンセルã™ã‚‹ã«ã¯ã€ãƒ•ã‚©ãƒ¼ãƒ ã‚’å«ã‚€ã‚¦ã‚§ãƒ– ブラウザ ウィンドウ閉ã˜ã¾ã™ã€‚</LI>
+</OL>
+
+</BODY>
+</HTML>
+
+
diff --git a/ldap/clients/dsgw/html/manual/ja/attribut.htm b/ldap/clients/dsgw/html/manual/ja/attribut.htm
new file mode 100644
index 00000000..ee84baaf
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/ja/attribut.htm
@@ -0,0 +1,7139 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+<!-- HEAD -->
+<title></title>
+</head>
+
+<body>
+
+<A NAME="996822">
+<H1>
+</H1>
+</A>
+<A NAME="997293">
+<P>
+</A><A NAME="1002619">
+<H1>属性
+</H1>
+</A>
+
+<A NAME="996830">
+<br>
+ã“ã®ä»˜éŒ²ã§ã¯ã€å±žæ€§ã®å®šç¾©ã«ã¤ã„ã¦è§£èª¬ã—ã¦ã„ã¾ã™ã€‚Directory Serverã§ä½¿ç”¨ã•ã‚Œã‚‹ã‚¹ã‚­ãƒ¼ãƒžå±žæ€§ã®å¤§éƒ¨åˆ†ã¯æ¨™æº–LDAPプロトコルã®ä¸€éƒ¨ã§ã‚ã‚Šã€X.500è¦æ ¼ã«åŸºã¥ã„ã¦ã„ã¾ã™ã€‚ã—ã‹ã—ã€Directory Serverã®å±žæ€§ã®ãªã‹ã«ã¯ã€ LDAPã®å°Žå…¥ã«ä½¿ç”¨ã™ã‚‹ãŸã‚ã«Netscape社ãŒä½œæˆã—ãŸæ‹¡å¼µã‚‚ã‚ã‚Šã¾ã™ã€‚属性ãŒNetscape社ã«ã‚ˆã£ã¦ä½œæˆã•ã‚ŒãŸã‚‚ã®ã§ã€æ¨™æº–LDAPスキーマã®ä¸€éƒ¨ã§ãªã„å ´åˆã¯ã€ãã®ã‚ªãƒ–ジェクト クラスや属性ã®èª¬æ˜Žã«ãã®æ—¨ãŒç¤ºã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1071459">
+Directory Serverスキーマã®å†…容ãŠã‚ˆã³ç”¨é€”ã«é–¢ã™ã‚‹è©³ç´°ã¯ã€ã€ŽNetscape Directoryã®å°Žå…¥ã€ã‚’ã”覧ãã ã•ã„。<P></A>
+
+<A NAME="1078428">
+スキーマã«ãŠã‘るオブジェクト クラスã«é–¢ã™ã‚‹è©³ç´°ã¯ã€<a href="objclass.htm#1002619">付録 A「オブジェクト クラスã€</a>ã‚’ã”覧ãã ã•ã„。<P></A>
+
+
+<A NAME="1020843">&nbsp;
+</A>
+<A NAME="Attribute Definitions">
+<H2>属性ã®å®šç¾©</H2>
+</A>
+
+<A NAME="1004519">
+以下ã«ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリー内ã®ã‚¨ãƒ³ãƒˆãƒªã®è¨˜è¿°ã«ä½¿ç”¨ã•ã‚ŒãŸå±žæ€§ãŒå®šç¾©ã•ã‚Œã¦ã„ã¾ã™ã€‚å„オブジェクト クラスã«å¿…è¦ã§ã—ã‹ã‚‚許å¯ã•ã‚Œã¦ã„る属性を判定ã™ã‚‹ã«ã¯ã€<a href="objclass.htm#1002619">付録 A「オブジェクト クラスã€</a>ã‚’ã”覧ãã ã•ã„。<P></A>
+
+<A NAME="1004699">
+属性情報ã®æ€§è³ªã‚’記述ã™ã‚‹æ§‹æ–‡ã®å®šç¾©ãŒã€å±žæ€§ã”ã¨ã«è¨˜è¼‰ã•ã‚Œã¦ã„ã¾ã™ã€‚ã“ã®æ§‹æ–‡ã¯ã€Directory Serverã§ã‚½ãƒ¼ãƒˆã‚„パターンマッãƒã‚’実行ã—ã¦ã„ã‚‹ã¨ãã«é™ã‚Šé‡è¦ã¨ãªã‚Šã¾ã™ã€‚ãれ以外ã®å ´åˆã€ä¾‹ãˆã°ã€è­˜åˆ¥åã‚’è¦æ±‚ã™ã‚‹å±žæ€§ã«é›»è©±ç•ªå·ã‚’入力ã™ã‚‹ã‚ˆã†ãªå ´åˆã«ã€å…¥åŠ›ã‚’制é™ã™ã‚‹ã‚‚ã®ã§ã¯ã‚ã‚Šã¾ã›ã€‚<P></A>
+
+<A NAME="1067002">
+å¯èƒ½ãªå±žæ€§æ§‹æ–‡:<P></A>
+<ul><A NAME="1004700">
+<LI>bin -- ãƒã‚¤ãƒŠãƒª<BR>
+</A>
+<A NAME="1004701">
+<LI>ces -- 大文字å°æ–‡å­—を区別ã™ã‚‹æ–‡å­—列 (比較ã®éš›ã«å¤§å°æ–‡å­—ãŒä¸€è‡´ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚)<BR>
+</A>
+<A NAME="1004702">
+<LI>cis -- 大文字å°æ–‡å­—を区別ã—ãªã„文字列 (比較ã®éš›ã«å¤§å°æ–‡å­—ã®åŒºåˆ¥ãŒç„¡è¦–ã•ã‚Œã¾ã™ã€‚)<BR>
+</A>
+<A NAME="1004703">
+<LI>tel -- é›»è©±ç•ªå· (cisã¨åŒã˜ã§ã™ãŒã€æ¯”較ã®éš›ã«ãƒ–ランクã¨ãƒ€ãƒƒã‚·ãƒ¥ (-) ãŒç„¡è¦–ã•ã‚Œã¾ã™ã€‚)<BR>
+</A>
+<A NAME="1004704">
+<LI>dn -- 識別å<BR>
+</A>
+<A NAME="1243260">
+<LI>int -- æ•´æ•°<BR>
+</A>
+<A NAME="1251525">
+<LI>operational -- 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚検索çµæžœã«ã¯ã€å‹•ä½œå±žæ€§ã¯è¡¨ç¤ºã•ã‚Œã¾ã›ã‚“。<BR>
+</A>
+</ul>
+<A NAME="1072472">
+標準的ãªå±žæ€§ã¯ã€æ¬¡ã®ãƒ•ã‚¡ã‚¤ãƒ«ã§å®šç¾©ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+<A NAME="1072513">
+<PRE> NSHOME/slapd-[server]/config/slapd.at.conf
+</PRE>
+</A>
+
+
+<A NAME="1201644">&nbsp;
+</A>
+<A NAME="abstract">
+<H3> abstract</H3>
+</A>
+
+
+
+<A NAME="1201645">
+ドキュメント エントリã®æ¦‚è¦ã‚’示ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1201648">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1104078">&nbsp;
+</A>
+<A NAME="accountUnlockTime">
+<H3> accountUnlockTime</H3>
+</A>
+
+
+
+<A NAME="1154996">
+ディレクトリã¸ã®ãƒã‚¤ãƒ³ãƒ‰ã«æŒ‡å®šå›žæ•°å¤±æ•—ã—ãŸå¾Œã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ アカウントã®ãƒ­ãƒƒã‚¯ãŒè§£é™¤ã•ã‚Œã‚‹ã¾ã§ã®æ™‚間を秒数ã§å®šç¾©ã—ã¾ã™ã€‚<P></A>
+<A NAME="1154997">
+<PRE> accountUnlockTime: 600
+</PRE>
+</A>
+
+<A NAME="1104080">
+構文: <a href="attribut.htm#1004702">cis operational</a><P></A>
+
+
+<A NAME="1171292">&nbsp;
+</A>
+<A NAME="aci">
+<H3> aci</H3>
+</A>
+
+
+
+<A NAME="1171293">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã«é–¢ã™ã‚‹Directory Serverã®ã‚¢ã‚¯ã‚»ã‚¹åˆ¶å¾¡æƒ…報をä¿å­˜ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1171294">
+<PRE> aci: (target="ldap:///<I>o=Airius.com</I>")(version 3.0;<br>
+ acl "anonymous access"; allow (read, search, compare)<br>
+ userdn=ldap:///self;)
+</PRE>
+</A>
+
+<A NAME="1171296">
+構文: <a href="attribut.htm#1004700">ces</a><P></A>
+
+<A NAME="1171297">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1032956">&nbsp;
+</A>
+<A NAME="administratorContactInfo">
+<H3>administratorContactInfo</H3>
+</A>
+
+
+
+<A NAME="1032957">
+Netscapeサーãƒãƒ¼ã®ç®¡ç†è²¬ä»»è€…ã«é–¢ã™ã‚‹æƒ…å ±ã¸ã®ã€URLを供給ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€<a href="attribut.htm#">netscapeServer</a>オブジェクト クラスãŒä½¿ç”¨ã—ã¾ã™ã€‚通常ã€ã“ã®å±žæ€§ã¨å±žæ€§å€¤ã¯ã€Netscapeサーãƒãƒ¼ã‚’åˆã‚ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹éš›ã«ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ›¸ãè¾¼ã¾ã‚Œã¾ã™ã€‚例: <P></A>
+<A NAME="1032959">
+<PRE> administratorContactInfo: ldap://<I>uid=ssarette, o=Airius.com
+</I></PRE>
+</A>
+
+<A NAME="1098446">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1098448">&nbsp;
+</A>
+<A NAME="adminUrl">
+<H3>adminUrl</H3>
+</A>
+
+
+
+<A NAME="1098449">
+Netscapeサーãƒãƒ¼ã‚’管ç†ã§ãるアドミニストレーション サーãƒãƒ¼ã¸ã®ã€URLを供給ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€<a href="attribut.htm#">netscapeServer</a>オブジェクト クラスãŒä½¿ç”¨ã—ã¾ã™ã€‚通常ã€ã“ã®å±žæ€§ã¨å±žæ€§å€¤ã¯ã€Netscapeサーãƒãƒ¼ã‚’åˆã‚ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹éš›ã«ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ›¸ãè¾¼ã¾ã‚Œã¾ã™ã€‚ 例:<P></A>
+<A NAME="1033050">
+<PRE> adminUrl: http://twain.airius.com:2468
+</PRE>
+</A>
+
+<A NAME="1033052">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201653">&nbsp;
+</A>
+<A NAME="aliasedObjectName">
+<H3> aliasedObjectName</H3>
+</A>
+
+
+
+<A NAME="1206908">
+ディレクトリã«ãŠã‘るエイリアス エントリを示ã™ãŸã‚ã«ã€Directory Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚ ã“ã®å±žæ€§ã«ã¯ã€ã‚¨ã‚¤ãƒªã‚¢ã‚¹ã§ã‚るエントリã®å…ƒã®ã‚¨ãƒ³ãƒˆãƒªã®è­˜åˆ¥åãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1206909">
+<PRE> aliasedObjectName:<I> cn=jdoe, o=Airius.com
+</I></PRE>
+</A>
+
+<A NAME="1206911">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1243116">&nbsp;
+</A>
+<A NAME="altServer">
+<H3> altServer</H3>
+</A>
+
+
+
+<A NAME="1243117">
+未定義。<P></A>
+
+<A NAME="1243120">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1102441">&nbsp;
+</A>
+<A NAME="archiveFile">
+<H3> archiveFile</H3>
+</A>
+
+
+
+<A NAME="1102442">
+特定ã®ãƒ¡ãƒ¼ãƒ«ãƒ‹ãƒ¥ãƒ¼ã‚¹ グループã«é€ä¿¡ã•ã‚ŒãŸå„メッセージã®ã‚³ãƒ”ーãŒå«ã¾ã‚Œã¦ã„るファイルã®ãƒ‘スåãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1102443">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1201668">&nbsp;
+</A>
+<A NAME="associatedDomain">
+<H3> associatedDomain</H3>
+</A>
+
+
+<a name="1219687">
+<BLOCKQUOTE>
+DITã«ãŠã‘るオブジェクトã«é–¢ä¿‚ã™ã‚‹DNSドメインを示ã—ã¾ã™ã€‚例ãˆã°ã€
+C=US, O=Airius Corporationã¨ã„ã†è­˜åˆ¥åã‚’æŒã¤ DITã«ãŠã‘るエントリã«ã¯ã€"AC.US. ã¨ã„ã†é–¢é€£ãƒ‰ãƒ¡ã‚¤ãƒ³ãŒã‚ã‚Šã¾ã™ã€‚rfc822ã®é †ã§ã™ã¹ã¦ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã‚’示ã™å¿…è¦ãŒã‚ã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。例:
+
+</BLOCKQUOTE>
+</a>
+<A NAME="1201670">
+<PRE> associatedDomain: US
+</PRE>
+</A>
+
+<A NAME="1201672">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201675">&nbsp;
+</A>
+<A NAME="associatedName">
+<H3> associatedName</H3>
+</A>
+
+
+
+<A NAME="1218672">
+DNSドメインã«é–¢ä¿‚ã™ã‚‹çµ„織的DITã«ãŠã‘るエントリを指定ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1201677">
+<PRE> associatedName:<I> c=us
+</I></PRE>
+</A>
+
+<A NAME="1201679">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1242644">&nbsp;
+</A>
+<A NAME="attributeTypes">
+<H3> attributeTypes</H3>
+</A>
+
+
+
+<A NAME="1242645">
+未定義。<P></A>
+
+<A NAME="1242648">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201684">&nbsp;
+</A>
+<A NAME="audio">
+<H3>audio</H3>
+</A>
+
+
+
+<A NAME="1209771">
+ãƒã‚¤ãƒŠãƒªå½¢å¼ã®ã‚µã‚¦ãƒ³ãƒ‰ ファイルをå«ã¿ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€u-法ã§ã‚³ãƒ¼ãƒ‰ã•ã‚ŒãŸéŸ³å£°ãƒ•ã‚¡ã‚¤ãƒ«ã‚’使用ã—ã¾ã™ã€‚例:<P></A>
+
+<A NAME="1201686">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1201689">&nbsp;
+</A>
+<A NAME="authorCn">
+<H3> authorCn</H3>
+</A>
+
+
+
+<A NAME="1201690">
+ドキュメント エントリã®è‘—者ã®ä¸€èˆ¬åãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1201691">
+<PRE> authorCn: Kacey
+</PRE>
+</A>
+
+<A NAME="1201693">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201696">&nbsp;
+</A>
+<A NAME="authorSn">
+<H3> authorSn</H3>
+</A>
+
+
+
+<A NAME="1201697">
+ドキュメント エントリã®è‘—者ã®è‹—å­—ãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1201698">
+<PRE> authorSn: Doe
+</PRE>
+</A>
+
+<A NAME="1201700">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1207170">&nbsp;
+</A>
+<A NAME="authorityRevocationList">
+<H3>authorityRevocationList</H3>
+</A>
+
+
+
+<A NAME="1207172">
+無効ã«ãªã£ãŸCA証明書ã®ãƒ†ã‚­ã‚¹ãƒˆ コード リストをå«ã¿ã¾ã™ã€‚ã“ã‚Œã¯ãŠè–¦ã‚ã—ã¾ã›ã‚“。代ã‚ã‚Šã«authorityRevocationList;binaryã‚’ã”使用ãã ã•ã„。<P></A>
+
+<A NAME="1207174">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1207178">&nbsp;
+</A>
+<A NAME="authorityRevocationList;binary">
+<H3>authorityRevocationList;binary</H3>
+</A>
+
+
+
+<A NAME="1207180">
+無効ã«ãªã£ãŸCertification Authority証明書ã®ãƒã‚¤ãƒŠãƒª リストをå«ã¿ã¾ã™ã€‚例: <P></A>
+
+<A NAME="1207182">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1201711">&nbsp;
+</A>
+<A NAME="buildingName">
+<H3> buildingName</H3>
+</A>
+
+
+
+<A NAME="1201712">
+エントリã«é–¢ä¿‚ã™ã‚‹ãƒ“ルã®åå‰ã‚’定義ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1201713">
+<PRE> buildingName: 14
+</PRE>
+</A>
+
+<A NAME="1201715">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1171367">&nbsp;
+</A>
+<A NAME="businessCategory">
+<H3> businessCategory</H3>
+</A>
+
+
+
+<A NAME="1171368">
+エントリãŒå¾“事ã™ã‚‹äº‹æ¥­ã‚¿ã‚¤ãƒ—を示ã—ã¾ã™ã€‚ã“ã‚Œã¯ã€ä¼æ¥­ã®éƒ¨é–€ãƒ¬ãƒ™ãƒ«ã§è¡Œã‚れるよã†ãªåºƒç¯„ã§ä¸€èˆ¬çš„ãªã‚‚ã®ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。<P></A>
+
+<A NAME="1171369">
+例:<P></A>
+<A NAME="1171370">
+<PRE> businessCategory: Engineering
+</PRE>
+</A>
+
+<A NAME="1208474">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1240535">&nbsp;
+</A>
+<A NAME="c">
+<H3> c</H3>
+</A>
+
+
+
+<A NAME="1240536">
+ディレクトリã«ãŠã‘る国åを表ã™ã€ISO定義ã«ã‚ˆã‚‹2文字ã®ã‚³ãƒ¼ãƒ‰ãŒå«ã¾ã‚Œã¾ã™ã€‚例ãˆã°ã€ã‚¢ã‚¤ãƒ«ãƒ©ãƒ³ãƒ‰ã®2文字コードã¯ã€æ¬¡ã®ã‚ˆã†ã«ä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+<A NAME="1240537">
+<PRE> countryName: IE
+</PRE>
+</A>
+
+<A NAME="1240538">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1240539">
+<PRE> c: IE
+</PRE>
+</A>
+
+<A NAME="1240541">
+<a href="attribut.htm#">ç•¥å·</a>: c<P></A>
+
+<A NAME="1240543">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1208564">&nbsp;
+</A>
+<A NAME="cACertificate">
+<H3>cACertificate</H3>
+</A>
+
+
+
+<A NAME="1208566">
+CA証明書ã®ãƒ†ã‚­ã‚¹ãƒˆ コード版をå«ã¿ã¾ã™ã€‚ã“ã‚Œã¯ãŠè–¦ã‚ã—ã¾ã›ã‚“。代ã‚ã‚Šã«cACertificate;binary ã‚’ã”使用ãã ã•ã„。<P></A>
+
+<A NAME="1208568">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1208584">&nbsp;
+</A>
+<A NAME="cACertificate;binary">
+<H3> cACertificate;binary</H3>
+</A>
+
+
+
+<A NAME="1208586">
+ãƒã‚¤ãƒŠãƒªå½¢å¼ã®CAã®è¨¼æ˜Žæ›¸ãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1208588">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1003044">&nbsp;
+</A>
+<A NAME="carLicense">
+<H3> carLicense</H3>
+</A>
+
+
+
+<A NAME="1003045">
+エントリã®è‡ªå‹•è»ŠãƒŠãƒ³ãƒãƒ¼ãƒ—レート番å·ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1003256">
+<PRE> carLicense: 6ABC246
+</PRE>
+</A>
+
+<A NAME="1003274">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1007950">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1208746">&nbsp;
+</A>
+<A NAME="certificateRevocationList">
+<H3>certificateRevocationList</H3>
+</A>
+
+
+
+<A NAME="1208748">
+無効ã«ãªã£ãŸãƒ¦ãƒ¼ã‚¶è¨¼æ˜Žæ›¸ãƒªã‚¹ãƒˆã®ãƒ†ã‚­ã‚¹ãƒˆ コード版をå«ã¿ã¾ã™ã€‚ã“ã‚Œã¯ãŠè–¦ã‚ã—ã¾ã›ã‚“。代ã‚ã‚Šã«certificateRevocationList;binaryã‚’ã”使用ãã ã•ã„。<P></A>
+
+<A NAME="1208708">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1208727">&nbsp;
+</A>
+<A NAME="certificateRevocationList;binary">
+<H3> certificateRevocationList;binary</H3>
+</A>
+
+
+
+<A NAME="1208729">
+無効ã«ãªã£ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼è¨¼æ˜Žæ›¸ãƒªã‚¹ãƒˆãŒãƒã‚¤ãƒŠãƒªå½¢å¼ã§å«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1208731">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1103361">&nbsp;
+</A>
+<A NAME="changelog">
+<H3>changeLog</H3>
+</A>
+
+
+
+<A NAME="1251549">
+Directory Serverã®å¤‰æ›´ãƒ­ã‚°è¨˜éŒ²ã‚’ä¿æŒã™ã‚‹ã‚³ãƒ³ãƒ†ãƒŠ オブジェクトã®è­˜åˆ¥åã‚’å«ã¿ã¾ã™ã€‚例: <P></A>
+<PRE><A NAME="1251550">
+changeLog: cn=changelog
+</A>
+</PRE>
+<A NAME="1103363">
+OID: <code>2.16.840.1.113730.3.1.35</code><P></A>
+
+<A NAME="1277486">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+<P>
+<A NAME="1171397">&nbsp;
+</A>
+<A NAME="changeLogMaximumAge">
+<H3> changeLogMaximumAge</H3>
+</A>
+
+
+
+<A NAME="1171398">
+変更ログ内ã®ã‚¨ãƒ³ãƒˆãƒªã®æœ€é«˜å¹´é½¢ã‚’秒å˜ä½ã§ç¤ºã—ã¾ã™ã€‚指定ã•ã‚ŒãŸæœ€é«˜å¹´é½¢ã‚’越ãˆã‚‹ã¨ã‚¨ãƒ³ãƒˆãƒªã¯ç ´æ£„ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1171399">
+<PRE> changeLogMaximumAge: 86000
+</PRE>
+</A>
+
+<A NAME="1171401">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1171402">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1171405">&nbsp;
+</A>
+<A NAME="changeLogMaximumSize">
+<H3> changeLogMaximumSize</H3>
+</A>
+
+
+
+<A NAME="1171406">
+変更ログファイルã®æœ€å¤§å®¹é‡ã‚’ãƒã‚¤ãƒˆã§ç¤ºã—ã¾ã™ã€‚最大容é‡ã‚’越ãˆã‚‹ã¨ã‚¨ãƒ³ãƒˆãƒªã¯ã“ã®ãƒ•ã‚¡ã‚¤ãƒ«ã‹ã‚‰ç ´æ£„ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1171407">
+<PRE> changeLogMaximumSize: 2400000
+</PRE>
+</A>
+
+<A NAME="1171409">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1171410">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1094798">&nbsp;
+</A>
+<A NAME="changeNumber">
+<H3> changeNumber</H3>
+</A>
+
+
+
+<A NAME="1094841">
+未定義。<P></A>
+
+<A NAME="1095210">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1095277">&nbsp;
+</A>
+<A NAME="changes">
+<H3> changes</H3>
+</A>
+
+
+
+<A NAME="1095278">
+未定義。<P></A>
+
+<A NAME="1095281">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1095285">&nbsp;
+</A>
+<A NAME="changeTime">
+<H3> changeTime</H3>
+</A>
+
+
+
+<A NAME="1095286">
+未定義。<P></A>
+
+<A NAME="1095289">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1094968">&nbsp;
+</A>
+<A NAME="changeType">
+<H3> changeType</H3>
+</A>
+
+
+
+<A NAME="1094969">
+エントリã«è¡Œã‚ã‚ŒãŸå¤‰æ›´ã®ã‚¿ã‚¤ãƒ—を示ã—ã¾ã™ã€‚changeTypeã®å€¤ã¯ã€addã€deleteã€modifyã€ã¾ãŸã¯modrdnã§ã™ã€‚例:<P></A>
+<A NAME="1094970">
+<PRE> changeType: modify
+</PRE>
+</A>
+
+<A NAME="1094972">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1103818">&nbsp;
+</A>
+<A NAME="cirBeginORC">
+<H3> cirBeginORC</H3>
+</A>
+
+
+
+<A NAME="1149985">
+複製ã®å‰ã«ã€æ¶ˆè²»ã‚µãƒ¼ãƒãƒ¼ãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®å†…容を消去ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã®å€¤ãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€å†…容ã¯æ¶ˆåŽ»ã•ã‚Œã¾ã›ã‚“。ã“ã®å±žæ€§ã«ã¯ã€startã¨stopã®å€¤ãŒè¨±å¯ã•ã‚Œã¦ã„ã¾ã™ã€‚startã§ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®å†…容ãŒæ¶ˆåŽ»ã•ã‚Œã€stopã§ã“ã®å‹•ä½œãŒä¸­æ­¢ã•ã‚Œã¾ã™ã€‚ 例:<P></A>
+<A NAME="1151379">
+<PRE> cirBeginORC: start
+</PRE>
+</A>
+
+<A NAME="1103820">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1101818">&nbsp;
+</A>
+<A NAME="cirBindCredentials">
+<H3> cirBindCredentials</H3>
+</A>
+
+
+
+<A NAME="1101820">
+未定義。<P></A>
+
+<A NAME="1101823">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1101379">&nbsp;
+</A>
+<A NAME="cirBindDn">
+<H3> cirBindDn</H3>
+</A>
+
+
+
+<A NAME="1101380">
+未定義。 <P></A>
+
+<A NAME="1101383">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1101250">&nbsp;
+</A>
+<A NAME="cirHost">
+<H3> cirHost</H3>
+</A>
+
+
+
+<A NAME="1101251">
+未定義。 <P></A>
+
+<A NAME="1101254">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1101860">&nbsp;
+</A>
+<A NAME="cirLastUpdateApplied">
+<H3> cirLastUpdateApplied</H3>
+</A>
+
+
+
+<A NAME="1122710">
+未定義。<P></A>
+
+<A NAME="1101865">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1101283">&nbsp;
+</A>
+<A NAME="cirPort">
+<H3> cirPort</H3>
+</A>
+
+
+
+<A NAME="1101284">
+未定義。 <P></A>
+
+<A NAME="1101287">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1101135">&nbsp;
+</A>
+<A NAME="cirReplicaRoot">
+<H3> cirReplicaRoot</H3>
+</A>
+
+
+
+<A NAME="1101136">
+未定義。 <P></A>
+
+<A NAME="1101139">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1102148">&nbsp;
+</A>
+<A NAME="cirSyncInterval">
+<H3> cirSyncInterval</H3>
+</A>
+
+
+
+<A NAME="1149751">
+ディレクトリã®è¤‡è£½éƒ¨åˆ†ã«å¤‰æ›´ãŒè¡Œã‚ã‚ŒãŸã‹ã©ã†ã‹ã‚’定期的ã«ãƒã‚§ãƒƒã‚¯ã™ã‚‹ãŸã‚ã€æ¶ˆè²»ã‚µãƒ¼ãƒãƒ¼ã«ã‚ˆã£ã¦ä¾›çµ¦ã‚µãƒ¼ãƒãƒ¼ã«å•åˆã›ãŒè¡Œã‚ã‚Œã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€æ¶ˆè²»ã‚µãƒ¼ãƒãƒ¼ã«ã‚ˆã‚‹ä¾›çµ¦ã‚µãƒ¼ãƒãƒ¼ã¸ã®å•åˆã›é–“隔を秒å˜ä½ã§å®šç¾©ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1102151">
+<PRE> cirSyncInterval: 3600
+</PRE>
+</A>
+
+<A NAME="1102153">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1102114">&nbsp;
+</A>
+<A NAME="cirUpdateFailedat">
+<H3> cirUpdateFailedat</H3>
+</A>
+
+
+
+<A NAME="1146224">
+未定義。<P></A>
+
+<A NAME="1102119">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1102001">&nbsp;
+</A>
+<A NAME="cirUpdateSchedule">
+<H3> cirUpdateSchedule</H3>
+</A>
+
+
+
+<A NAME="1102003">
+複製ã®ç™ºç”ŸãŒå¯èƒ½ãªæ™‚間帯を定義ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1148927">
+<PRE> cirUpdateSchedule: 0100-0400
+</PRE>
+</A>
+<A NAME="1148928">
+<PRE> cirUpdateSchedule: * 06
+</PRE>
+</A>
+<A NAME="1148929">
+<PRE> cirUpdateSchedule: 1145-1300 24
+</PRE>
+</A>
+
+<A NAME="1148930">
+ã“れらã®å€¤ã®æ„味:<P></A>
+<A NAME="1148931">
+<PRE> 毎日ã€åˆå‰1時ã‹ã‚‰åˆå‰4時ã¾ã§
+</PRE>
+</A>
+<A NAME="1148932">
+<PRE> 土曜ã¨æ—¥æ›œã®çµ‚æ—¥
+</PRE>
+</A>
+<A NAME="1148933">
+<PRE> ç«æ›œã¨æœ¨æ›œã®åˆå‰11時45分ã‹ã‚‰åˆå¾Œ1時ã¾ã§
+</PRE>
+</A>
+
+
+<A NAME="1101691">&nbsp;
+</A>
+<A NAME="cirUsePersistentSearch">
+<H3> cirUsePersistentSearch</H3>
+</A>
+
+
+
+<A NAME="1101693">
+未定義。 <P></A>
+
+<A NAME="1101696">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1101735">&nbsp;
+</A>
+<A NAME="cirUseSsl">
+<H3> cirUseSsl</H3>
+</A>
+
+
+
+<A NAME="1101737">
+未定義。 <P></A>
+
+<A NAME="1101740">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1171494">&nbsp;
+</A>
+<A NAME="cn">
+<H3> cn</H3>
+</A>
+
+
+
+<A NAME="1171495">
+LDAPReplicaã¾ãŸã¯LDAPServer以外ã®ã‚ªãƒ–ジェクト クラスã¸ã®å‚照時ã«ã€cnã§ã‚¨ãƒ³ãƒˆãƒªã®ä¸€èˆ¬åã¾ãŸã¯æ°åãŒç¤ºã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1171496">
+<PRE> commonName: Bill Anderson
+</PRE>
+</A>
+
+<A NAME="1171497">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1171498">
+<PRE> cn: Bill Anderson
+</PRE>
+</A>
+
+<A NAME="1171499">
+LDAPReplicaã¾ãŸã¯LDAPServer以外ã®ã‚ªãƒ–ジェクト クラスã¸ã®å‚照時ã«ã€è¤‡è£½ã•ã‚ŒãŸãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã®ã‚µãƒ¼ãƒãƒ¼ã¨ãƒ«ãƒ¼ãƒˆã®DNSåを識別åå½¢å¼ã«å¤‰æ›ã—ãŸã‚‚ã®ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1171500">
+<PRE> commonName: replicater.netscape.com:17430/o%3Dairius<br>
+ %2Cc%3us
+</PRE>
+</A>
+
+<A NAME="1171501">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1171502">
+<PRE> cn: replicater.netscape.com:17430/o%3Dairius%2Cc%3us
+</PRE>
+</A>
+
+<A NAME="1171504">
+<a href="attribut.htm#">ç•¥å·</a>: cn<P></A>
+
+<A NAME="1171506">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1241971">&nbsp;
+</A>
+<A NAME="createTimestamp">
+<H3> createTimestamp</H3>
+</A>
+
+
+
+<A NAME="1241973">
+未定義。 <P></A>
+
+<A NAME="1241975">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1242331">&nbsp;
+</A>
+<A NAME="creatorsName">
+<H3> creatorsName</H3>
+</A>
+
+
+
+<A NAME="1242332">
+エントリ作æˆè€…ã®è­˜åˆ¥å(dn)ãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1242333">
+<PRE> creatorsName: <I>cn=jdoe, o=airius.com
+</I></PRE>
+</A>
+
+<A NAME="1242335">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1208784">&nbsp;
+</A>
+<A NAME="crossCertificatePair">
+<H3>crossCertificatePair</H3>
+</A>
+
+
+
+<A NAME="1208786">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„。ã“ã‚Œã¯ãŠè–¦ã‚ã—ã¾ã›ã‚“。代ã‚ã‚Šã«crossCertificatePair;binaryã‚’ã”使用ãã ã•ã„。<P></A>
+
+<A NAME="1208788">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1208791">&nbsp;
+</A>
+<A NAME="crossCertificatePair;binary">
+<H3> crossCertificatePair;binary</H3>
+</A>
+
+
+
+<A NAME="1208793">
+å°†æ¥ã®ä½¿ç”¨ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1208795">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1245094">&nbsp;
+</A>
+<A NAME="dc">
+<H3> dc</H3>
+</A>
+
+
+
+<A NAME="1245095">
+DNSドメインを指定ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1245096">
+<PRE> domainComponent: uk
+</PRE>
+</A>
+<A NAME="1245097">
+<PRE>ã¾ãŸã¯ã€
+</PRE>
+</A>
+<A NAME="1245098">
+<PRE> dc: uk
+</PRE>
+</A>
+
+<A NAME="1245100">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1095547">&nbsp;
+</A>
+<A NAME="deleteOldRdn">
+<H3> deleteOldRdn</H3>
+</A>
+
+
+
+<A NAME="1095597">
+エントリã®è­˜åˆ¥å±žæ€§ã¨ã—ã¦ã‚¨ãƒ³ãƒˆãƒªã®å¤ã„RDNã‚’ä¿æŒã™ã‚‹ã‹ã€ã¾ãŸã¯å‰Šé™¤ã™ã‚‹ã‹ã‚’定義ã™ã‚‹ãƒ•ãƒ©ã‚°ã€‚値<code>False</code>ã¯è­˜åˆ¥å±žæ€§ã¨ã—ã¦RDNãŒä¿æŒã•ã‚Œã‚‹ã“ã¨ã‚’ã€å€¤<code>True</code>ã¯ã‚¨ãƒ³ãƒˆãƒªã®è­˜åˆ¥å±žæ€§ã¨ã—ã¦RDNãŒä¿æŒã•ã‚Œãªã„ã“ã¨ã‚’示ã—ã¾ã™ã€‚<code>True</code>ã¾ãŸã¯<code>False</code>以外ã®å€¤ãŒdeleteOldRDNã®å±žæ€§ã«å«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã‚„ã€deleteOldRDNã«è¤‡æ•°ã®å€¤ãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã¯ã€RDNãŒè­˜åˆ¥å±žæ€§ã¨ã—ã¦ä¿æŒã•ã‚Œã¾ã™(ã¤ã¾ã‚Šã€å€¤ãŒå­˜åœ¨ã—ãªã‹ã£ãŸã‚Šã€ç„¡åŠ¹ãªå€¤ãŒå­˜åœ¨ã™ã‚‹å ´åˆã€<code>False</code>ãŒãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã§ã™)。<P></A>
+<A NAME="1095550">
+<PRE> deleteOldRdn: False
+</PRE>
+</A>
+
+<A NAME="1095552">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1241799">&nbsp;
+</A>
+<A NAME="deltaRevocationList;binary">
+<H3> deltaRevocationList;binary</H3>
+</A>
+
+
+
+<A NAME="1241800">
+未定義。<P></A>
+
+<A NAME="1241803">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1095560">&nbsp;
+</A>
+<A NAME="departmentNumber">
+<H3> departmentNumber</H3>
+</A>
+
+
+
+<A NAME="1095562">
+Identifies the entryユs department number. 例:<P></A>
+<A NAME="1095563">
+<PRE> departmentNumber: 2604
+</PRE>
+</A>
+
+<A NAME="1095565">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1095566">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1171528">&nbsp;
+</A>
+<A NAME="description">
+<H3> description</H3>
+</A>
+
+
+
+<A NAME="1171529">
+エントリを説明ã—ã¾ã™ã€‚ユーザーや組織ã®å ´åˆã«ã€ãã®å½¹å‰²ã‚„作業ã®å‰²å½“ã¦ãŒèª¬æ˜Žã«å«ã¾ã‚Œã‚‹ã“ã¨ãŒã‚ˆãã‚ã‚Šã¾ã™ã€‚例:<P></A>
+<A NAME="1171530">
+<PRE> description: Quality control inspector for the ME2873 product line (ME2873製å“ラインã®å“質管ç†æ¤œæŸ»è€…)
+</PRE>
+</A>
+
+<A NAME="1171532">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201824">&nbsp;
+</A>
+<A NAME="destinationIndicator">
+<H3> destinationIndicator</H3>
+</A>
+
+
+
+<A NAME="1201825">
+ã“ã®å±žæ€§ã¯é›»å ±ã‚µãƒ¼ãƒ“スã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1201828">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201831">&nbsp;
+</A>
+<A NAME="ditRedirect">
+<H3> ditRedirect</H3>
+</A>
+
+
+
+<A NAME="1211719">
+ã‚るエントリã§è¨˜è¿°ã•ã‚Œã‚‹ã‚ªãƒ–ジェクトãŒã€DIT内ã«ã‚ˆã‚Šæ–°ã—ã„エントリをæŒã¤ã‚ˆã†ã«ãªã£ãŸã“ã¨ã‚’示ã™ã®ã«ä½¿ç”¨ã—ã¾ã™ã€‚個人ã®ä»•äº‹å ´ãŒå¤‰ã‚ã£ãŸãŸã‚æ–°ã—ã„組織DNã‚’å¾—ãŸå ´åˆãªã©ã«ã€ã“ã®å±žæ€§ã‚’使用ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1201833">
+<PRE> ditRedirect: <I>cn=jdoe, o=airius.com
+</I></PRE>
+</A>
+
+<A NAME="1201835">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1100403">&nbsp;
+</A>
+<A NAME="dn">
+<H3> dn</H3>
+</A>
+
+
+
+<A NAME="1100404">
+エントリã®è­˜åˆ¥å (dn - distinguished name)を定義ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1171552">
+<PRE> <I>dn: cn=Jane Doe, ou=Quality Control, o=airius.com
+</I></PRE>
+</A>
+
+<A NAME="1100407">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1201841">&nbsp;
+</A>
+<A NAME="dnsRecord">
+<H3> dnsRecord</H3>
+</A>
+
+
+
+<A NAME="1218890">
+タイプA (Address)ã€ã‚¿ã‚¤ãƒ—MX (Mail Exchange)ã€ã‚¿ã‚¤ãƒ—NS (Name Server)ã€ãŠã‚ˆã³ã‚¿ã‚¤ãƒ— SOA (Start Of Authority) ã®ãƒªã‚½ãƒ¼ã‚¹ レコードをå«ã‚€DNS リソース レコードを指定ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1218996">
+<PRE> dnsRecord: IN NS ns.uu.net.
+</PRE>
+</A>
+
+<A NAME="1201844">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1241256">&nbsp;
+</A>
+<A NAME="dnQualifier">
+<H3> dnQualifier</H3>
+</A>
+
+
+
+<A NAME="1241257">
+未定義。<P></A>
+
+<A NAME="1241260">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201847">&nbsp;
+</A>
+<A NAME="documentAuthor">
+<H3> documentAuthor</H3>
+</A>
+
+
+
+<A NAME="1201848">
+ドキュメント エントリã®è‘—者ã®è­˜åˆ¥åãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1201849">
+<PRE> documentAuthor: <I>cn=John Doe, o=Airius.com</I>
+</PRE>
+</A>
+
+<A NAME="1201851">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1201854">&nbsp;
+</A>
+<A NAME="documentIdentifier">
+<H3> documentIdentifier</H3>
+</A>
+
+
+
+<A NAME="1214845">
+ドキュメントã®ä¸€æ„ã®è­˜åˆ¥å­ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1201856">
+<PRE> documentIdentifier: L3204REV1
+</PRE>
+</A>
+
+<A NAME="1201858">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201861">&nbsp;
+</A>
+<A NAME="documentLocation">
+<H3> documentLocation</H3>
+</A>
+
+
+
+<A NAME="1201862">
+ドキュメント エントリã®å…ƒã®ã‚³ãƒ”ー場所を定義ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1201863">
+<PRE> documentLocation: Department Library
+</PRE>
+</A>
+
+<A NAME="1201865">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201868">&nbsp;
+</A>
+<A NAME="documentPublisher">
+<H3> documentPublisher</H3>
+</A>
+
+
+
+<A NAME="1216107">
+ドキュメントをパブリッシュã—ãŸãƒ¦ãƒ¼ã‚¶ãƒ¼ãŠã‚ˆã³/ã¾ãŸã¯çµ„織。例:<P></A>
+<A NAME="1201870">
+<PRE> documentPublisher: Southeastern Publishing
+</PRE>
+</A>
+
+<A NAME="1201872">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201877">&nbsp;
+</A>
+<A NAME="documentStore">
+<H3> documentStore</H3>
+</A>
+
+
+
+<A NAME="1201878">
+未定義。<P></A>
+
+<A NAME="1201881">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201884">&nbsp;
+</A>
+<A NAME="documentTitle">
+<H3> documentTitle</H3>
+</A>
+
+
+
+<A NAME="1201885">
+ドキュメント エントリã®é¡ŒåãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1201886">
+<PRE> documentTitle: Directory Administratorユs Guide
+</PRE>
+</A>
+
+<A NAME="1201888">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201891">&nbsp;
+</A>
+<A NAME="documentVersion">
+<H3> documentVersion</H3>
+</A>
+
+
+
+<A NAME="1201892">
+ドキュメント エントリã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’定義ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1201893">
+<PRE> documentVersion: 1.1
+</PRE>
+</A>
+
+<A NAME="1201895">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201909">&nbsp;
+</A>
+<A NAME="drink">
+<H3> drink</H3>
+</A>
+
+
+
+<A NAME="1201910">
+ユーザー エントリã®å¥½ã¿ã®é£²ç‰©ã‚’説明ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1201911">
+<PRE> drink: soda
+</PRE>
+</A>
+<A NAME="1201912">
+<PRE>ã¾ãŸã¯ã€
+</PRE>
+</A>
+<A NAME="1201913">
+<PRE> favouriteDrink: soda
+</PRE>
+</A>
+
+<A NAME="1201915">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1245205">&nbsp;
+</A>
+<A NAME="dSAQuality">
+<H3> dSAQuality</H3>
+</A>
+
+
+
+<A NAME="1245207">
+未定義。 <P></A>
+
+<A NAME="1245210">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1003050">&nbsp;
+</A>
+<A NAME="employeeNumber">
+<H3> employeeNumber</H3>
+</A>
+
+
+
+<A NAME="1003051">
+エントリã®ç¤¾ï¿½ï¿½ç•ªå·ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1003356">
+<PRE> employeeNumber: 15300
+</PRE>
+</A>
+
+<A NAME="1003382">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1008204">
+ã“ã®å±žæ€§ã¯ã€LDAPå°Žå…¥ã¨ã®ä½µç”¨ã®ãŸã‚ã«Netscape社ãŒä½œæˆã—ãŸã‚‚ã®ã§ã™ã€‚<P></A>
+
+
+<A NAME="1009035">&nbsp;
+</A>
+<A NAME="employeeType">
+<H3> employeeType</H3>
+</A>
+
+
+
+<A NAME="1009036">
+エントリã®æŽ¡ç”¨ã‚¿ã‚¤ãƒ—を示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1009039">
+<PRE> employeeType: Full time
+</PRE>
+</A>
+
+<A NAME="1009054">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1087204">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1241288">&nbsp;
+</A>
+<A NAME="enhancedSearchGuide">
+<H3> enhancedSearchGuide</H3>
+</A>
+
+
+
+<A NAME="1241289">
+未定義。 <P></A>
+
+<A NAME="1241292">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1171637">&nbsp;
+</A>
+<A NAME="facsimileTelephoneNumber">
+<H3> facsimileTelephoneNumber</H3>
+</A>
+
+
+
+<A NAME="1171638">
+エントリã«é€£çµ¡å¯èƒ½ãªãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1171639">
+<PRE> facsimileTelephoneNumber: 415-555-1212
+</PRE>
+</A>
+
+<A NAME="1171640">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1171641">
+<PRE> fax: 415-555-1212
+</PRE>
+</A>
+
+<A NAME="1171643">
+<a href="attribut.htm#">ç•¥å·</a>: fax<P></A>
+
+<A NAME="1171645">
+構文: <a href="attribut.htm#1004703">tel</a><P></A>
+
+
+<A NAME="1229525">&nbsp;
+</A>
+<A NAME="co">
+<H3> co</H3>
+</A>
+
+
+
+<A NAME="1229526">
+国åãŒå«ã¾ã‚Œã¾ã™ã€‚country属性ã¯å›½ã®2文字コードを示ã—ã€friendlyCountryName属性ã¯å®Ÿéš›ã®å›½åを示ã™ã®ã«ä½¿ç”¨ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1229527">
+<PRE> friendlyCountryName: Ireland<br>
+ countryName: IE
+</PRE>
+</A>
+
+<A NAME="1244785">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1244786">
+<PRE> co: Ireland
+</PRE>
+</A>
+
+<A NAME="1244788">
+<a href="attribut.htm#">ç•¥å·</a>: co<P></A>
+
+<A NAME="1229529">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1171657">&nbsp;
+</A>
+<A NAME="generation">
+<H3> generation</H3>
+</A>
+
+
+
+<A NAME="1171658">
+サーãƒãƒ¼ã‚’ãã®åˆ¥ã®ä¸–代ã¾ãŸã¯ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‹ã‚‰åŒºåˆ¥ã™ã‚‹ãŸã‚ã«ã€ã‚µãƒ¼ãƒãƒ¼ã«å‰²ã‚Šå½“ã¦ã‚‹ãƒã‚¤ãƒˆ ベクトルを示ã—ã¾ã™ã€‚generation属性ã¯è¤‡è£½åŒæœŸåŒ–ã®ã¿ã«ä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1171660">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+<A NAME="1171661">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1104309">&nbsp;
+</A>
+<A NAME="generationQualifier">
+<H3>generationQualifier</H3>
+</A>
+
+
+
+<A NAME="1161653">
+Lightweight Internet Person Schema (LIPS)ã®Generation Qualifierã¨åŒã˜ã§ã™ã€‚<P></A>
+
+<A NAME="1104311">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1229534">&nbsp;
+</A>
+<A NAME="givenName">
+<H3> givenName</H3>
+</A>
+
+
+
+<A NAME="1229535">
+エントリã®åã¾ãŸã¯ãƒ•ã‚¡ãƒ¼ã‚¹ãƒˆãƒãƒ¼ãƒ ã‚’示ã—ã¾ã™ã€‚例: <P></A>
+<A NAME="1229536">
+<PRE> givenName: Bill
+</PRE>
+</A>
+
+<A NAME="1229538">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201936">&nbsp;
+</A>
+<A NAME="homePhone">
+<H3> homePhone</H3>
+</A>
+
+
+
+<A NAME="1201937">
+エントリã®è‡ªå®…電話番å·ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1201938">
+<PRE> homeTelephoneNumber: 415-555-1212
+</PRE>
+</A>
+
+<A NAME="1201939">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1201940">
+<PRE> homePhone: 415-555-1234
+</PRE>
+</A>
+
+<A NAME="1201942">
+<a href="attribut.htm#">ç•¥å·</a>: homePhone<P></A>
+
+<A NAME="1201944">
+構文: <a href="attribut.htm#1004703">tel</a><P></A>
+
+
+<A NAME="1201947">&nbsp;
+</A>
+<A NAME="homePostalAddress">
+<H3> homePostalAddress</H3>
+</A>
+
+
+
+<A NAME="1201948">
+エントリã®è‡ªå®…郵便ä½æ‰€ã‚’示ã—ã¾ã™ã€‚ã“ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯è¤‡æ•°è¡Œã‚’å«ã‚€ã‚ˆã†æ„図ã•ã‚Œã¦ã„ã¾ã™ãŒã€ã‚¨ãƒ³ãƒˆãƒªå†…ã®å„行をドル記å·($)ã§åŒºåˆ‡ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚例:<P></A>
+<A NAME="1201949">
+<PRE> homePostalAddress: 1234 Ridgeway Drive$Santa Clara, CA$99555
+</PRE>
+</A>
+
+<A NAME="1201950">
+テキスト内ã§ã®åŒºåˆ‡ã‚Šã¨ã—ã¦ã§ã¯ãªãã€å®Ÿéš›ã®ãƒ‰ãƒ«è¨˜å·($)ã¾ãŸã¯ãƒãƒƒã‚¯ã‚¹ãƒ©ãƒƒã‚·ãƒ¥(\)を示ã™ã«ã¯ã€ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—ã•ã‚ŒãŸ16進値 \24㨠\5cを使用ã—ã¾ã™ã€‚例ãˆã°ã€æ¬¡ã®ã‚ˆã†ãªæ–‡å­—列を示ã™å ´åˆã€<P></A>
+<A NAME="1201951">
+<PRE> The dollar ($) value can be found <br>
+ in the c:\cost file.
+</PRE>
+</A>
+
+<A NAME="1201952">
+次ã®ã‚ˆã†ã«ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—文字を使用ã—ã¾ã™ã€‚<P></A>
+<A NAME="1201953">
+<PRE> The dollar (\24) value can be found$in the c:\5ccost file.
+</PRE>
+</A>
+
+<A NAME="1201955">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201958">&nbsp;
+</A>
+<A NAME="host">
+<H3> host</H3>
+</A>
+
+
+
+<A NAME="1201959">
+コンピュータã®ãƒ›ã‚¹ãƒˆåを定義ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1201960">
+<PRE> host: mozilla
+</PRE>
+</A>
+
+<A NAME="1201962">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1241726">&nbsp;
+</A>
+<A NAME="houseIdentifier">
+<H3> houseIdentifier</H3>
+</A>
+
+
+
+<A NAME="1241727">
+家ã®è­˜åˆ¥å­ãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1241730">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201965">&nbsp;
+</A>
+<A NAME="info">
+<H3> info</H3>
+</A>
+
+
+
+<A NAME="1211991">
+Informationã®å±žæ€§ã‚¿ã‚¤ãƒ—ã¯ã€ã‚ªãƒ–ジェクトã«é–¢ä¿‚ã™ã‚‹ä¸€èˆ¬çš„ãªæƒ…報を示ã™ã‚‚ã®ã§ã™ã€‚ã“ã®å±žæ€§ã‚¿ã‚¤ãƒ—ã§ã¯ç‰¹å®šã®ä½¿ç”¨ã‚’é¿ã‘ã€ã•ã‚‰ã«ã€ç‰¹å®šã®è¦ä»¶ãŒä»–ã® (ã¾ãŸã¯è¿½åŠ ã®)属性タイプã«ã‚ˆã£ã¦æº€ãŸã•ã‚Œã‚‹ã‚ˆã†ã«ã™ã‚‹ã“ã¨ã‚’ãŠè–¦ã‚ã—ã¾ã™ã€‚<P></A>
+<A NAME="1201967">
+<PRE> info: not valid
+</PRE>
+</A>
+
+<A NAME="1201969">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1229543">&nbsp;
+</A>
+<A NAME="initials">
+<H3> initials</H3>
+</A>
+
+
+
+<A NAME="1229544">
+エントリã®ã‚¤ãƒ‹ã‚·ãƒ£ãƒ«ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1229545">
+<PRE> initials: BFA
+</PRE>
+</A>
+
+<A NAME="1229547">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1032705">&nbsp;
+</A>
+<A NAME="installationTimeStamp">
+<H3>installationTimeStamp</H3>
+</A>
+
+
+
+<A NAME="1212073">
+Netscapeサーãƒãƒ¼ãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚ŒãŸæ—¥ã¨æ™‚é–“ã‚’zuluå½¢å¼ã§è¡¨ç¤ºã—ã¾ã™ã€‚ ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€<a href="attribut.htm#">netscapeServer</a>オブジェクト クラスãŒä½¿ç”¨ã—ã¾ã™ã€‚通常ã€ã“ã®å±žæ€§ã¨å±žæ€§å€¤ã¯ã€Netscapeサーãƒã‚’åˆã‚ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹éš›ã«ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ›¸ãè¾¼ã¾ã‚Œã¾ã™ã€‚例: <P></A>
+<A NAME="1212075">
+<PRE><A NAME="1212075">
+ installationTimeStamp: 199703261517z
+</A>
+</PRE>
+<A NAME="1259193">
+OID: <code>2.16.840.1.113730.3.1.73</code><P></A>
+
+<A NAME="1032810">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1224256">&nbsp;
+</A>
+<A NAME="internationalIsdnNumber">
+<H3> internationalIsdnNumber</H3>
+</A>
+
+
+
+<A NAME="1224257">
+エントリã®å›½éš›ISDN番å·ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1224260">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1201988">&nbsp;
+</A>
+<A NAME="janetMailBox">
+<H3> janetMailBox</H3>
+</A>
+
+
+
+<A NAME="1212260">
+é›»å­ãƒ¡ãƒ¼ãƒ« アドレスを示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€rfc822メール アドレスã«æ…£ã‚Œã¦ã„ãªã„英国ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ä¾¿å®œã‚’図るãŸã‚ã®ã‚‚ã®ã§ã™ã€‚ã“ã®å±žæ€§ã‚’使用ã—ãŸã‚¨ãƒ³ãƒˆãƒªã«ã¯ã€rfc822Mailboxã®å±žæ€§ã‚‚å«ã¾ã‚Œã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚例:<P></A>
+<A NAME="1201990">
+<PRE> janetMailBox: jdoe@airius.com
+</PRE>
+</A>
+
+<A NAME="1201992">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1201995">&nbsp;
+</A>
+<A NAME="jpegPhoto">
+<H3> jpegPhoto</H3>
+</A>
+
+
+
+<A NAME="1201996">
+エントリã®JPEG写真ãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1201999">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1202004">&nbsp;
+</A>
+<A NAME="keyWords">
+<H3> keyWords</H3>
+</A>
+
+
+
+<A NAME="1202005">
+エントリã®ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰ãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1202006">
+<PRE> keyWords: directory LDAP X.500
+</PRE>
+</A>
+
+<A NAME="1202008">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202013">&nbsp;
+</A>
+<A NAME="knowledgeInformation">
+<H3> knowledgeInformation</H3>
+</A>
+
+
+
+<A NAME="1202014">
+ã“ã®å±žæ€§ã¯ç¾åœ¨ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã›ã‚“。<P></A>
+
+
+<A NAME="1244534">&nbsp;
+</A>
+<A NAME="l">
+<H3> l</H3>
+</A>
+
+
+
+<A NAME="1244535">
+エントリãŒå­˜åœ¨ã—ã¦ã„ã‚‹ã€ã¾ãŸã¯ã‚¨ãƒ³ãƒˆãƒªãŒä½•ã‚‰ã‹ã®æ–¹æ³•ã§é–¢ä¿‚ã™ã‚‹å›½ã€éƒ½å¸‚ã€ãã®ä»–ã®åœ°ç†çš„領域を示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1244536">
+<PRE> localityName: Santa Clara
+</PRE>
+</A>
+
+<A NAME="1244537">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1244538">
+<PRE> l: Santa Clara
+</PRE>
+</A>
+
+<A NAME="1244540">
+<a href="attribut.htm#">ç•¥å·</a>: l<P></A>
+
+<A NAME="1244542">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202020">&nbsp;
+</A>
+<A NAME="labeledUri">
+<H3> labeledUri</H3>
+</A>
+
+
+
+<A NAME="1202021">
+何らã‹ã®æ–¹æ³•ã§ã‚¨ãƒ³ãƒˆãƒªã«é–¢ä¿‚ã™ã‚‹ã€Uniform Resource Identifier (URI)を示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã®å…¥åŠ›å€¤ã¯ã€URIã¨(ç¾åœ¨ã¯URLã«é™ã‚Šã‚µãƒãƒ¼ãƒˆ)ã€ã‚ªãƒ—ションã¨ã—ã¦ã€å¾Œç¶šã™ã‚‹ä¸€ã¤ä»¥ä¸Šã®ã‚¹ãƒšãƒ¼ã‚¹æ–‡å­—ã¨ãƒ©ãƒ™ãƒ«ä¸€ã¤ã‹ã‚‰æ§‹æˆã•ã‚Œãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。例:<P></A>
+<A NAME="1202022">
+<PRE> labeledURI: http://home.netscape.com [Netscape社ã®ãƒ›ãƒ¼ãƒ ãƒšãƒ¼ã‚¸<br>
+ ]
+</PRE>
+</A>
+
+<A NAME="1202024">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1100733">&nbsp;
+</A>
+<A NAME="lastModifiedBy">
+<H3> lastModifiedBy</H3>
+</A>
+
+
+
+<A NAME="1212108">
+関連エントリã®æœ€çµ‚変更者ã®è­˜åˆ¥åを示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202030">
+<PRE> lastModifiedby: <I>cn=Jane Doe, ou=Quality Control, o=Airius.com
+</I></PRE>
+</A>
+
+<A NAME="1100642">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1202035">&nbsp;
+</A>
+<A NAME="lastModifiedTime">
+<H3> lastModifiedTime</H3>
+</A>
+
+
+
+<A NAME="1202036">
+エントリãŒå¤‰æ›´ã•ã‚ŒãŸæœ€çµ‚時刻をUTCå½¢å¼ã§å®šç¾©ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202037">
+<PRE> lastModifiedTime: Thursday, 22-Sep-93 14:15:00 GMT
+</PRE>
+</A>
+
+<A NAME="1202039">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1243273">&nbsp;
+</A>
+<A NAME="ldap構文es">
+<H3> ldap構文es</H3>
+</A>
+
+
+
+<A NAME="1243274">
+未定義。<P></A>
+
+<A NAME="1243277">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1189404">&nbsp;
+</A>
+<A NAME="mail">
+<H3> mail</H3>
+</A>
+
+
+
+<A NAME="1189405">
+エントリã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレスを示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1189406">
+<PRE> mail: banderson@airius.com
+</PRE>
+</A>
+
+<A NAME="1189408">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1024020">&nbsp;
+</A>
+<A NAME="mailAccessDomain">
+<H3>mailAccessDomain</H3>
+</A>
+
+
+
+<A NAME="1024021">
+ユーザãŒPOP/IMAPログオンを実行ã™ã‚‹ãƒ‰ãƒ¡ã‚¤ãƒ³ã¾ãŸã¯IPアドレスを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1024022">
+<PRE><A NAME="1024022">
+ mailAccessDomain: airius.com
+</A>
+</PRE>
+<A NAME="1024248">
+OID: <code>2.16.840.1.113730.3.1.12</code><P></A>
+
+<A NAME="1269362">
+構文:<a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1024250">
+<A NAME="mailAlternateAddress">
+<B>mailAlternateAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1024251">
+メール ユーザã®ä»£æ›¿ãƒ¡ãƒ¼ãƒ« アドレスを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€ãƒ¡ãƒ¼ãƒ« アドレスã¨ãƒ¦ãƒ¼ã‚¶ã‚’ç…§åˆã™ã‚‹ãŸã‚ã«Messaging ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚メール アカウントã¯ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚’ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ä»£æ›¿ãƒ¡ãƒ¼ãƒ« アドレスã¨åŒæ•°æŒã¤ã“ã¨ãŒã§ãã¾ã™ã€‚例:<P></A>
+<A NAME="1024061">
+<PRE><A NAME="1024061">
+ mailAlternateAddress: Babs_Jensen@airius.com<br> mailAlternateAddress: Bjensen@airius.com
+</A>
+</PRE>
+<A NAME="1269367">
+OID: <code>2.16.840.1.113730.3.1.13</code><P></A>
+
+<A NAME="1269365">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1024094">
+<A NAME="mailAutoReplyMode">
+<B>mailAutoReplyMode</B>
+</a></a>
+<P>
+
+
+<A NAME="1027423">
+メール ユーザã®ãƒ¡ãƒ¼ãƒ«è‡ªå‹•å¿œç­”モードを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚å„メール ユーザ アカウントã«ã¤ãã€ã“ã®å±žæ€§ãŒã‚¼ãƒ­ã¾ãŸã¯1 (0〜1)インスタンス必è¦ã§ã™ã€‚ã“ã®å±žæ€§ã®æœ‰åŠ¹ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰ã¯ã€æ¬¡ã®ã¨ãŠã‚Šã§ã™ã€‚<P></A>
+<ul><A NAME="1027425">
+<LI>vacation -- 休暇メッセージをé€ä¿¡ã—ã¾ã™ã€‚休暇メッセージã¯mailAutoReplyText属性ã«å«ã¾ã‚Œã¦ã„ã¾ã™ã€‚<BR>
+</A>
+<A NAME="1027426">
+<LI>reply --一定ã®å¿œç­”ã‚’é€ä¿¡ã—ã¾ã™ã€‚応答ã¯mailAutoReplyText属性ã«å«ã¾ã‚Œã¦ã„ã¾ã™ã€‚<BR>
+</A>
+<A NAME="1027427">
+<LI>echo -- å…ƒã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’エコーã—ã¦ã€ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®å…ƒã®é€ä¿¡è€…ã«mailAutoReplyTextã‚’é€ä¿¡ã—ã¾ã™ã€‚<BR>
+</A>
+</ul>
+<A NAME="1027428">
+例:<P></A>
+<PRE><A NAME="1027429">
+ mailAutoReplyMode: vacation
+</A>
+</PRE>
+<A NAME="1269369">
+OID: <code>2.16.840.1.113730.3.1.14</code><P></A>
+
+<A NAME="1024098">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1024125">
+<A NAME="mailAutoReplyText">
+<B>mailAutoReplyText</B>
+</a></a>
+<P>
+
+
+<A NAME="1027662">
+メール ユーザã«è‡ªå‹•å¿œç­”テキストをæä¾›ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚LDIFå½¢å¼ã§è¡¨ã‚ã™å ´åˆã€å„行をドル記å·($)ã§åŒºåˆ‡ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚Messaging Serverã§ã¯ã€å„メール アカウントã«ã¤ãã“ã®å±žæ€§ãŒ0ã¾ãŸã¯1回発生ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ 例:<P></A>
+<PRE><A NAME="1027663">
+ mailAutoReplyText: 休暇中$月曜日ã«æˆ»ã‚Šã¾ã™ã€‚
+</A>
+</PRE>
+<A NAME="1034577">
+テキスト内ã§ã®åŒºåˆ‡ã‚Šã¨ã—ã¦ã§ã¯ãªãã€å®Ÿéš›ã®ãƒ‰ãƒ«è¨˜å·($)ã¾ãŸã¯ãƒãƒƒã‚¯ã‚¹ãƒ©ãƒƒã‚·ãƒ¥(\)を示ã™ã«ã¯ã€ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—ã•ã‚ŒãŸ16進値\24㨠\5cを使用ã—ã¾ã™ã€‚例ãˆã°ã€æ¬¡ã®ã‚ˆã†ãªæ–‡å­—列を示ã™å ´åˆã€<P></A>
+<A NAME="1034578">
+<PRE> The dollar ($) value can be found <br>
+ in the c:\cost file.
+</PRE>
+</A>
+
+<A NAME="1034579">
+次ã®ã‚ˆã†ã«ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—文字を使用ã—ã¾ã™ã€‚<P></A>
+<A NAME="1034580">
+<PRE> The dollar (\24) value can be found$in the c:\5ccost file.
+</PRE>
+</A>
+<A NAME="1269558">
+OID: <code>2.16.840.1.113730.3.1.15</code><P></A>
+
+<A NAME="1024293">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1024295">
+<A NAME="mailDeliveryOption">
+<B>mailDeliveryOption</B>
+</a></a>
+<P>
+
+
+<A NAME="1024296">
+メール ユーザãŒä½¿ç”¨ã™ã‚‹ãƒ¡ãƒ¼ãƒ«é…信機構を識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚å„メール ユーザ アカウントã«ã¤ãã€ã“ã®å±žæ€§ãŒã‚¼ãƒ­ã¾ãŸã¯3(0〜3)インスタンス必è¦ã§ã™ã€‚ãŸã ã—ã€ãƒ¡ãƒ¼ãƒ« ユーザー エントリã«ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒç„¡ã„å ´åˆã¯ã€æœ€ä½Žä¸€ã¤ã®<a href="attribut.htm#1026154">mailForwardingAddress</a>属性ãŒã‚¨ãƒ³ãƒˆãƒªã«å­˜åœ¨ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。ã“ã®å±žæ€§ã®æœ‰åŠ¹ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰ã¯æ¬¡ã®ã¨ãŠã‚Šã§ã™ã€‚<P></A>
+<ul><A NAME="1027169">
+<LI>mailbox --ユーザã®POP/IMAPメールボックスã«ãƒ¡ãƒ¼ãƒ«ãŒé…ä¿¡ã•ã‚Œã‚‹ã®ã‚’示ã—ã¾ã™ã€‚<P>
+</A>
+<A NAME="1027175">
+<LI>native -- Unixé…ä¿¡ãŒä½¿ç”¨ã•ã‚Œã¦ã„ã‚‹ã®ã‚’示ã—ã¾ã™ã€‚Unixホストã§å®Ÿè¡Œã•ã‚Œã¦ã„ã‚‹Messaging Serversã«é™ã‚Šã“ã®ã‚ªãƒ—ションを利用ã§ãã¾ã™ã€‚<P>
+</A>
+<A NAME="1027197">
+<LI>program -- プログラムé…ä¿¡ãŒä½¿ç”¨ã•ã‚Œã¦ã„ã‚‹ã®ã‚’示ã—ã¾ã™ã€‚Unixホストã§å®Ÿè¡Œã•ã‚Œã¦ã„ã‚‹Messaging Serversã«é™ã‚Šã“ã®ã‚ªãƒ—ションを利用ã§ãã¾ã™ã€‚<P>
+</A>
+</ul>
+<A NAME="1027143">
+例:<P></A>
+<PRE><A NAME="1024297">
+ mailDeliveryOption: mailbox
+</A>
+</PRE>
+<A NAME="1269568">
+OID: <code>2.16.840.1.113730.3.1.16</code><P></A>
+
+<A NAME="1024169">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1026103">
+<A NAME="mailEnhancedUniqueMember">
+<B>mailEnhancedUniqueMember</B>
+</a></a>
+<P>
+
+
+<A NAME="1026104">
+Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã®ãŸã‚予約。<P></A>
+
+<A NAME="1026153">
+OID: <code>2.16.840.1.113730.3.1.31</code><P></A>
+
+<A NAME="1278474">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+<P>
+<A NAME="1026154">
+<A NAME="mailForwardingAddress">
+<B>mailForwardingAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1024197">
+メールãŒè»¢é€ã•ã‚Œã‚‹ãƒ¡ãƒ¼ãƒ« アドレスを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€æ­£ã—ã„場所ã«ç€ä¿¡ãƒ¡ãƒ¼ãƒ«ã‚’転é€ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1024198">
+ mailForwardingAddress: bjensen@royalairways.com
+</A>
+</PRE>
+<A NAME="1269579">
+OID: <code>2.16.840.1.113730.3.1.17</code><P></A>
+
+<A NAME="1024200">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1024314">
+<A NAME="mailHost">
+<B>mailHost</B>
+</a></a>
+<P>
+
+
+<A NAME="1308000">
+ユーザã®ãƒ¡ãƒ¼ãƒ« アカウントãŒå­˜åœ¨ã™ã‚‹ãƒ›ã‚¹ãƒˆã®DNSホストåを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€æ­£ã—ã„場所ã«ç€ä¿¡ãƒ¡ãƒ¼ãƒ«ã‚’ルートã—ã¾ã™ã€‚Messaging Serverã§ã¯ã€å„<a href="attribut.htm#">mail</a>Recipientエントリã«ã¤ãã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå¿…ãšä¸€ã¤ã ã‘ã€å„<a href="attribut.htm#">mailGroup</a>エントリã«ã¤ãã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã‚¼ãƒ­ã¾ãŸã¯ä¸€ã¤å¿…è¦ã§ã™ã€‚ã“ã®å±žæ€§ã®æŒ‡å®šå€¤ã¯ã€ãƒ›ã‚¹ãƒˆã®å®Œå…¨ä¿®é£¾ãƒ‰ãƒ¡ã‚¤ãƒ³åã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。例:<P></A>
+<PRE><A NAME="1024316">
+ mailHost: mars.airius.com
+</A>
+</PRE>
+<A NAME="1269581">
+OID: <code>2.16.840.1.113730.3.1.18</code><P></A>
+
+<A NAME="1024318">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1024377">
+<A NAME="mailMessageStore">
+<B>mailMessageStore</B>
+</a></a>
+<P>
+
+
+<A NAME="1024378">
+ユーザã®ãƒ¡ãƒ¼ãƒ« ホスト上ã§ã€ãƒ¦ãƒ¼ã‚¶ã®ãƒ¡ãƒ¼ãƒ« ボックスãŒå­˜åœ¨ã™ã‚‹å ´æ‰€ã¸ã®çµ¶å¯¾ãƒ‘スを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Messaging ServerãŒä½¿ç”¨ã™ã‚‹Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®<a href="attribut.htm#1024295"> mailDeliveryOption</a>ãŒ<I>mailbox</I>ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã«é™ã‚Šã“ã®å±žæ€§ã‚’é©ç”¨ã§ãã¾ã™ã€‚Messaging Serverã§ã¯ã€ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã‚¼ãƒ­ã¾ãŸã¯ä¸€ã¤ (0〜1)å¿…è¦ã§ã™ã€‚ユーザー エントリã«ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®Messaging Serverã§è¨­å®šã•ã‚Œã¦ã„るデフォルトãŒä½¿ç”¨ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1024379">
+ mailMessageStore: /disk2/mail
+</A>
+</PRE>
+<A NAME="1269614">
+OID: <code>2.16.840.1.113730.3.1.19</code><P></A>
+
+<A NAME="1090714">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1202044">&nbsp;
+</A>
+<A NAME="mailPreferenceOption">
+<H3> mailPreferenceOption</H3>
+</A>
+
+
+
+<A NAME="1213101">
+メール リスト (é›»å­ã¾ãŸã¯ç‰©ç†çš„)ã«ãƒ¦ãƒ¼ã‚¶ãƒ¼åã‚’å«ã‚ã‚‹ã‹ã©ã†ã‹ã®ç’°å¢ƒè¨­å®šã‚’示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã®3ã¤ã®è¨±å®¹å€¤ã¯<code>0</code>ã€<code>1</code>ã€ãŠã‚ˆã³<code>2</code>ã§ã™ã€‚<code>0</code>ã®å€¤ã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒãƒ¡ãƒ¼ãƒ« リストã¸ã®è¿½åŠ ã‚’希望ã—ãªã„ã“ã¨ã€<code>1</code>ã®å€¤ã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒä»»æ„ã®ãƒ¡ãƒ¼ãƒ« リストã¸ã®è¿½åŠ ã«åŒæ„ã™ã‚‹ã“ã¨ã€<code>2</code>ã®å€¤ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®å°‚門的ãªé–¢å¿ƒäº‹ã§ã‚ã‚‹ã¨ãƒ¡ãƒ¼ãƒ« リストæ供者ãŒè¦‹ãªã™ã‚ˆã†ãªãƒ¡ãƒ¼ãƒ« リストã«ã®ã¿ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’追加ã™ã‚‹ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚属性値ã®æŒ‡å®šãŒãªã„å ´åˆã¯ã€å±žæ€§ã®å€¤ãŒ "no-list-inclusion" (リストã«å«ã¾ãªã„)ã§ã‚ã¨è§£é‡ˆã•ã‚Œã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãŠã„ã¦ãƒ¡ãƒ¼ãƒ« リストãŠã‚ˆã³ãã®ç’°å¢ƒè¨­å®šå€¤ã‚’å–り出ã™ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ã™ã¹ã¦ãŒè§£é‡ˆã§ãã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚例:<P></A>
+<A NAME="1202046">
+<PRE> mailPreferenceOption: 0
+</PRE>
+</A>
+
+<A NAME="1202048">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1024400">&nbsp;
+</A>
+<A NAME="mailProgramDeliveryInfo">
+<H3>mailProgramDeliveryInfo</H3>
+</A>
+
+
+
+<A NAME="1024401">
+プログラムã«ã‚ˆã‚‹ãƒ¡ãƒ¼ãƒ«é…ä¿¡ã§ä½¿ç”¨ã™ã‚‹ã€$ã§åŒºåˆ‡ã‚‰ã‚ŒãŸä¸€ã¤ä»¥ä¸Šã®ã‚³ãƒžãƒ³ãƒ‰ã‚’識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚Messaging Serverã§ã¯ã€å„ユーザー アカウントã«ã¤ãã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã‚¼ãƒ­ã¾ãŸã¯ä¸€ã¤ (0〜1)å¿…è¦ã§ã™ã€‚次ã®æ¡ä»¶ãŒã™ã¹ã¦çœŸã§ã‚ã‚‹å ´åˆã«é™ã‚Šã€ã“ã®å±žæ€§ã«ã¯æ„味ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+<ul><A NAME="1033350">
+<LI>Messaging ServerãŒUNIXã§å®Ÿè¡Œã•ã‚Œã¦ã„ã‚‹<P>
+</A>
+<A NAME="1033365">
+<LI>メール管ç†è€…ãŒã€Messaging Serverã§ãƒ—ログラムé…信を使用å¯èƒ½ã«ã—ã¦ã„ã‚‹<P>
+</A>
+<A NAME="1033405">
+<LI>ユーザã®<a href="attribut.htm#1024295">mailDeliveryOption</a>ãŒ<B> </B><I>program</I>ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹<P>
+</A>
+</ul>
+<A NAME="1039005">
+例:<P></A>
+<PRE><A NAME="1024402">
+ mailProgramDeliveryInfo: /usr/local/bin/procmail -f-
+</A>
+</PRE>
+<A NAME="1269616">
+OID: <code>2.16.840.1.113730.3.1.20</code><P></A>
+
+<A NAME="1024440">
+<A NAME="1024440">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+<P>
+<A NAME="1024509">
+<A NAME="mailQuota">
+<B>mailQuota</B>
+</a></a>
+<P>
+
+
+<A NAME="1024510">
+ユーザã®ãƒ¡ãƒ¼ãƒ«ãƒœãƒƒã‚¯ã‚¹ãŒä½¿ç”¨å¯èƒ½ãªæœ€å¤§ãƒ‡ã‚£ã‚¹ã‚¯å®¹é‡ã‚’ãƒã‚¤ãƒˆæ•°ã§è¡¨ç¤ºã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã€ãƒ¦ãƒ¼ã‚¶ã®<a href="attribut.htm#1024295">mailDeliveryOption</a>ãŒ<I>mailbox</I>ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã«é™ã‚Šã“ã®å±žæ€§ã‚’é©ç”¨ã§ãã¾ã™ã€‚Messaging Serverã§ã¯ã€ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã‚¼ãƒ­ã¾ãŸã¯ä¸€ã¤ (0〜1)å¿…è¦ã§ã™ã€‚ユーザ エントリã«ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€ãƒ¦ãƒ¼ã‚¶ã®Messaging Serverã§è¨­å®šã•ã‚Œã¦ã„るデフォルトãŒä½¿ç”¨ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1024511">
+ mailQuota: 1000000
+</A>
+</PRE>
+<A NAME="1024513">
+ã“ã®å±žæ€§ãŒã‚¼ãƒ­ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã¯ã€ãƒ‡ã‚£ã‚¹ã‚¯å®¹é‡ã®å‰²å½“ã¦ãŒç„¡åˆ¶é™ã§ã‚ã‚‹ã®ã«æ³¨æ„ã—ã¦ãã ã•ã„。<P></A>
+
+<A NAME="1269588">
+OID: <code>2.16.840.1.113730.3.1.21</code><P></A>
+
+<A NAME="1033421">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1241537">
+<A NAME="mailRoutingAddress">
+<B>mailRoutingAddress</B>
+</a></a>
+<P>
+
+
+<A NAME="1241538">
+未定義。 <P></A>
+
+<A NAME="1241541">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1007859">&nbsp;
+</A>
+<A NAME="manager">
+<H3> manager</H3>
+</A>
+
+
+
+<A NAME="1007872">
+エントリã®ä¸Šå¸ã®è­˜åˆ¥åを示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1007875">
+<PRE> manager:<I> cn=Jane Doe, ou=Quality Control, o=Airius.com
+</I></PRE>
+</A>
+
+<A NAME="1007908">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1242887">&nbsp;
+</A>
+<A NAME="matchingRules">
+<H3> matchingRules</H3>
+</A>
+
+
+
+<A NAME="1242888">
+未定義。<P></A>
+
+<A NAME="1242891">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1242961">&nbsp;
+</A>
+<A NAME="matchingRuleUse">
+<H3> matchingRuleUse</H3>
+</A>
+
+
+
+<A NAME="1242962">
+未定義。<P></A>
+
+<A NAME="1242965">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1171811">&nbsp;
+</A>
+<A NAME="member">
+<H3> member</H3>
+</A>
+
+
+
+<A NAME="1171812">
+グループã®å„メンãƒãƒ¼ã®è­˜åˆ¥åを示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1171813">
+<PRE> member: <I>cn=John Doe, o=airius.com
+</I></PRE>
+</A>
+
+<A NAME="1171815">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1152959">&nbsp;
+</A>
+<A NAME="memberCertificateDescription">
+<H3> memberCertificateDescription</H3>
+</A>
+
+
+
+<A NAME="1152961">
+特定グループã®è¨¼æ˜Žæ›¸ã«ãŠã‘る証明書ã®ç‰¹å¾´ã‚’示ã—ã¾ã™ã€‚memberCertificateDescriptionã®å€¤ã®ä¸€ã¤ã«ä¸€è‡´ã™ã‚‹ä¸»é¡Œè­˜åˆ¥åãŒè¨¼æ˜Žæ›¸ã«å«ã¾ã‚Œã‚‹å ´åˆã€ãã‚Œã¯ã€ã“ã®å±žæ€§ãŒå±žã™ã‚‹è¨¼æ˜Žæ›¸ã‚°ãƒ«ãƒ¼ãƒ—ã®ãƒ¡ãƒ³ãƒãƒ¼ã§ã‚ã‚‹ã¨è¦‹ãªã•ã‚Œã¾ã™ã€‚<P></A>
+<A NAME="1153378">
+<PRE> {<I>subject_dn</I>}
+</PRE>
+</A>
+
+<A NAME="1153395">
+カンマã§åŒºåˆ‡ã‚‹ã¨è¤‡æ•°ã®ä¸»é¡Œdnを指定ã§ãã¾ã™ã€‚エントリã«ãŠã„ã¦è¤‡æ•°ã®<code>ou</code>を指定ã§ãã¾ã™ã€‚(<code>ou</code>ã§ãªã„)ä»–ã®å±žæ€§ã‚¿ã‚¤ãƒ—ã®è¤‡æ•°ã‚¨ãƒ³ãƒˆãƒªã‚’指定ã™ã‚‹å ´åˆã€æœ€å¾Œã‚’除ãã™ã¹ã¦ãŒç„¡è¦–ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1154677">
+例ãˆã°ã€æ¬¡ã®memberCertificateDescriptionã‚’æŒã¤ã‚°ãƒ«ãƒ¼ãƒ—ã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’考慮ã™ã‚‹ã«ã¯ã€è¨¼æ˜Žæ›¸ã«ã¯<code>o=company</code>を除ãã€<code>ou=x</code>ã€<code>ou=A</code>ã€ãŠã‚ˆã³<code>o=airius</code>ã‚’å«ã‚ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+<A NAME="1126332">
+<PRE> memberCertificateDescription: {<I>ou=x, ou=A, o=company, o=airius</I>}
+</PRE>
+</A>
+
+<A NAME="1154571">
+グループã®è¦ä»¶ãŒæº€ãŸã•ã‚Œã‚‹ã«ã¯ã€è¨¼æ˜Žæ›¸ã®ä¸»é¡Œdnã«ã€memberCertificateDescriptionã®å±žæ€§ã§å®šç¾©ã•ã‚Œã¦ã„ã‚‹ã®ã¨åŒã˜é †åºã§ouã®å±žæ€§ã‚¿ã‚¤ãƒ—ãŒå«ã¾ã‚Œã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1153423">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1246271">&nbsp;
+</A>
+<A NAME="memberURL">
+<H3> memberURL</H3>
+</A>
+
+
+
+<A NAME="1246272">
+グループã®å„メンãƒãƒ¼ã«é–¢ä¿‚ã™ã‚‹URLを示ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1246273">
+ memberURL: ldap://<I>cn=jdoe, o=Airius.com</I>
+</A>
+</PRE>
+<A NAME="1263332">
+OID: <code>2.16.840.1.113730.3.1.198</code><P></A>
+
+
+<A NAME="1025144">&nbsp;
+</A>
+<A NAME="mgrpAllowedBroadcaster">
+<H3>mgrpAllowedBroadcaster</H3>
+</A>
+
+
+
+<A NAME="1025146">
+メール グループã¸ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸é€ä¿¡ã‚’許ã•ã‚Œã¦ã„るメール ユーザを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¡ãƒ¼ãƒ« リストを管ç†ã—ã¾ã™ã€‚mailGroupエントリã«ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€mgrpAllowedDomain属性を使用ã—ãªã„é™ã‚Šã€ãƒ¡ãƒ¼ãƒ« グループã«ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’é€ä¿¡ã§ãるユーザã®åˆ¶é™ã¯ä¸€åˆ‡ã‚ã‚Šã¾ã›ã‚“。<P></A>
+
+<A NAME="1028370">
+Messaging Serverã§ã¯ã€è­˜åˆ¥åã¾ãŸã¯rfc822addressã®ã„ãšã‚Œã‹ã‚’å«ã‚€å±žæ€§ãŒå¿…è¦ã§ã™ã€‚識別åを使用ã™ã‚‹å ´åˆã¯ã€ãƒ¡ãƒ¼ãƒ«å¯èƒ½ãªã‚¨ãƒ³ãƒˆãƒªã€ã‚¿ã‚¤ãƒ—groupã®ã‚¨ãƒ³ãƒˆãƒªã€ã¾ãŸã¯groupOfUniqueNamesを識別åãŒè¡¨ç¤ºã—ã¦ã„ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。識別åã¯ã€RFC1959ã®<em>LDAP URLフォーマット</em>ã§è¨˜è¿°ã•ã‚Œã¦ã„るよã†ã«ã€LDAP URLフォーマットã§è¡¨ç¤ºã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1028354">
+例:<P></A>
+<PRE><A NAME="1025147">
+ mgrpAllowedBroadcaster: ldap://<I>uid=bjensen, o=Airius.com<br></I> mgrpAllowedBroadcaster: mailto:sys50@airius.com
+</A>
+</PRE>
+<A NAME="1277878">
+OID: <code>2.16.840.1.113730.3.1.22</code><P></A>
+
+<A NAME="1025149">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+<P>
+<A NAME="1024569">
+<A NAME="mgrpAllowedDomain">
+<B>mgrpAllowedDomain</B>
+</a></a>
+<P>
+
+
+<A NAME="1024570">
+ユーザãŒãƒ¡ãƒ¼ãƒ« グループã¸ã®ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸é€ä¿¡ã‚’許ã•ã‚Œã¦ã„ã‚‹é€ä¿¡å…ƒãƒ‰ãƒ¡ã‚¤ãƒ³ã‚’識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¡ãƒ¼ãƒ« リストを管ç†ã—ã¾ã™ã€‚mailGroupエントリã«ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€mgrpAllowedBroadcaster属性を使用ã—ãªã„é™ã‚Šã€ãƒ¡ãƒ¼ãƒ« グループã«ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã‚’é€ä¿¡ã§ãるユーザーã®åˆ¶é™ã¯ä¸€åˆ‡ã‚ã‚Šã¾ã›ã‚“。 <P></A>
+
+<A NAME="1028614">
+ã“ã‚Œã¯ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã§ãƒ¯ã‚¤ãƒ«ãƒ‰ã‚«ãƒ¼ãƒ‰å€¤ã«è¨­å®šã•ã‚Œã¾ã™ã€‚ã¤ã¾ã‚Šã€å€¤ "airius.com"ã¯"*.airius.com"ã‹ã‚‰é€ä¿¡ã—ã¦ã„ã‚‹ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ã¨ç…§åˆã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1028598">
+例:<P></A>
+<PRE><A NAME="1024571">
+ mgrpAllowedDomain: airius.com
+</A>
+</PRE>
+<A NAME="1277883">
+OID: <code>2.16.840.1.113730.3.1.23</code><P></A>
+<A NAME="1278549">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1278551">
+<A NAME="mgrpDeliverTo">
+<B>mgrpDeliverTo</B>
+</a></a>
+<P>
+
+
+<A NAME="1278552">
+メール グループã®ãƒ¡ãƒ³ãƒãƒ¼ã‚·ãƒƒãƒ—を指定ã™ã‚‹ä»£æ›¿æ–¹æ³•ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¡ãƒ¼ãƒ« リストを管ç†ã—ã¾ã™ã€‚Messaging Serverã§ã¯ã€ã“ã®å±žæ€§ãŒRFC1959ã®<em>LDAP URLフォーマット</em>ã§è¨˜è¿°ã•ã‚Œã¦ã„るフォーマットを使用ã—ãŸLDAP URLã‚’å«ã‚“ã§ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚LDAP検索ãŒè¿”ã—ã¦ãるエントリã¯ã€ã“ã®ãƒ¡ãƒ¼ãƒ« グループã®ãƒ¡ãƒ³ãƒãƒ¼ã§ã™ã€‚例:<P></A>
+<PRE><A NAME="1025433">
+ mgrpDeliverTo: ldap:///<I>ou=Accounting,o=Netscape,c=US??sub?(&amp;<br> (objectClass=mailRecipient)(objectClass=inetOrgPerson))</I>
+</A>
+</PRE>
+<A NAME="1277885">
+OID: <code>2.16.840.1.113730.3.1.25</code><P></A>
+
+<A NAME="1025435">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+<P>
+<A NAME="1025568">
+<A NAME="mgrpErrorsTo">
+<B>mgrpErrorsTo</B>
+</a></a>
+<P>
+
+
+<A NAME="1028828">
+è·³ã­è¿”ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ã‚„ã€ãƒ¡ãƒ¼ãƒ« アドレスã®ãªã„メール グループã®ãƒ¡ãƒ³ãƒãƒ¼ãªã©ã€ãƒ¡ãƒ¼ãƒ«é…信上ã®å•é¡Œã‚’通知ã™ã‚‹ã‚¨ãƒ©ãƒ¼ メッセージã®é€ä¿¡ãƒ¡ãƒ¼ãƒ« アドレスを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¡ãƒ¼ãƒ« リストを管ç†ã—ã¾ã™ã€‚mailGroupエントリã«ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€Messaging Serverã§è¨­å®šã•ã‚Œã¦ã„るデフォルトã«åŸºã¥ã„ã¦ã‚¨ãƒ©ãƒ¼å‡¦ç†ãŒè¡Œã‚ã‚Œã¾ã™ã€‚ <P></A>
+
+<A NAME="1028829">
+Messaging Serverã§ã¯ã€è­˜åˆ¥åã¾ãŸã¯rfc822addressã®ã„ãšã‚Œã‹ã‚’å«ã‚€å±žæ€§ãŒå¿…è¦ã§ã™ã€‚識別åを使用ã™ã‚‹å ´åˆã¯ã€ãƒ¡ãƒ¼ãƒ«å¯èƒ½ãªã‚¨ãƒ³ãƒˆãƒªã€ã‚¿ã‚¤ãƒ—groupã®ã‚¨ãƒ³ãƒˆãƒªã€ã¾ãŸã¯groupOfUniqueNamesを表示ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚識別åã¯ã€RFC1959ã®<em>LDAP URLフォーマット</em>ã§è¨˜è¿°ã•ã‚Œã¦ã„るよã†ã«LDAP URLフォーマットã§è¡¨ç¤ºã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。<P></A>
+
+<A NAME="1126241">
+例:<P></A>
+<PRE><A NAME="1126242">
+ mgrpErrorsTo: ldap://<I>uid=bjensen, o=Airius.com<br></I> mgrpErrorsTo: mailto:sys50@airius.com
+</A>
+</PRE>
+<A NAME="1277947">
+OID: <code>2.16.840.1.113730.3.1.26</code><P></A>
+
+<A NAME="1025572">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+<P>
+<A NAME="1025705">
+<A NAME="mgrpModerator">
+<B>mgrpModerator</B>
+</a></a>
+<P>
+
+
+<A NAME="1025706">
+æ‹’å¦ã•ã‚ŒãŸãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®é€ä¿¡å…ˆãƒ¡ãƒ¼ãƒ« アドレスを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¡ãƒ¼ãƒ« リストを管ç†ã—ã¾ã™ã€‚ã“ã‚Œã¯ã€æ‹’å¦ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ãŒé€ã‚‰ã‚ŒãŸãƒ¡ãƒ¼ãƒ« リストã‹ã‚‰ã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã§ã™ã€‚<P></A>
+
+<A NAME="1029841">
+Messaging Serverã¯ã€ï¼ˆ<a href="attribut.htm#1024569">mgrpAllowedDomain</a>属性ã§å®šç¾©ã•ã‚ŒãŸ) 未許å¯ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã‹ã‚‰å—ã‘å–ã£ãŸã‹ã€ã¾ãŸã¯<a href="attribut.htm#1025144">mgrpAllowedBroadcaster</a>属性ã®ãƒ¡ãƒ³ãƒãƒ¼ã§ãªã„メール アドレスã‹ã‚‰å—ã‘å–ã£ãŸãƒ¡ãƒ¼ãƒ«ã‚’ã€æ‹’å¦ã™ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚<a href="attribut.htm#1025035">mgrpMsgRejectAction</a>属性ã«<I>toModerator</I>ãŒå«ã¾ã‚Œã¦ã„ã‚‹å ´åˆã€Messaging Serverã¯ã€ã“ã®å±žæ€§ã§æŒ‡å®šã•ã‚ŒãŸã‚¢ãƒ‰ãƒ¬ã‚¹ã«ã®ã¿ãƒ¡ãƒ¼ãƒ«ã‚’転é€ã—ã¾ã™<B>。</B> mailGroupエントリã«ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå­˜åœ¨ã›ãšã€ã•ã‚‰ã«<a href="attribut.htm#1025035">mgrpMsgRejectAction</a>属性ãŒ<I>toModerator</I>, ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã¯ã€moderatorã«é€ä¿¡ã•ã‚Œã‚‹ã¯ãšã®æ‹’å¦ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ã¯ç ´æ£„ã•ã‚Œã¾ã™ (ã¤ã¾ã‚Šã€äººçš„介入ãªã—ã«ãƒ¡ãƒ¼ãƒ« システムã‹ã‚‰å‰Šé™¤ã•ã‚Œã¾ã™)。<P></A>
+
+Messaging Serverã§ã¯ã€ã“ã®å±žæ€§ãŒè­˜åˆ¥åã¾ãŸã¯rfc822addressã®ã„ãšã‚Œã‹ã‚’å«ã‚€å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚識別åを使用ã™ã‚‹å ´åˆã¯ã€ãƒ¡ãƒ¼ãƒ«å¯èƒ½ãªã‚¨ãƒ³ãƒˆãƒªã€ã‚¿ã‚¤ãƒ—groupã®ã‚¨ãƒ³ãƒˆãƒªã€ã¾ãŸã¯groupOfUniqueNamesを表示ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。識別åã¯ã€RFC1959ã®<em>LDAP URLフォーマット</em>ã§è¨˜è¿°ã•ã‚Œã¦ã„るよã†ã«LDAP URLフォーマットã§è¡¨ç¤ºã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1029358">
+例:<P></A>
+<PRE><A NAME="1029359">
+ mgrpErrorsTo: ldap://<I>uid=bjensen, o=Airius.com<br></I> mgrpErrorsTo: mailto:sys50@airius.com
+</A>
+</PRE>
+<A NAME="1277952">
+OID: <code>2.16.840.1.113730.3.1.33</code><P></A>
+
+<A NAME="1025876">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+<P>
+<A NAME="1025878">
+<A NAME="mgrpMsgMaxSize">
+<B>mgrpMsgMaxSize</B>
+</a></a>
+<P>
+
+
+<A NAME="1025879">
+メール グループã«é€ä¿¡ãŒè¨±å¯ã•ã‚Œã¦ã„る最大メッセージ サイズをãƒã‚¤ãƒˆæ•°ã§è¡¨ç¤ºã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¡ãƒ¼ãƒ« リストを管ç†ã—ã¾ã™ã€‚Messaging Serverã§ã¯ã€å„everymailGroupエントリã«ã¤ãå¿…ãšä¸€ã¤ã ã‘ã€ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå­˜åœ¨ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1025290">
+ mgrpMsgMaxSize: 2000
+</A>
+</PRE>
+<A NAME="1277962">
+OID: <code>2.16.840.1.113730.3.1.32</code><P></A>
+
+<A NAME="1025292">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1025035">
+<A NAME="mgrpMsgRejectAction">
+<B>mgrpMsgRejectAction</B>
+</a></a>
+<P>
+
+
+<A NAME="1024634">
+メール グループã«é€ä¿¡ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ãŒæ‹’å¦ã•ã‚ŒãŸéš›ã®å¯¾ç­–を示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¡ãƒ¼ãƒ« リストを管ç†ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1029427">
+Messaging Serverã¯ã€ (<a href="attribut.htm#1024569">mgrpAllowedDomain</a>属性ã§å®šç¾©ã•ã‚ŒãŸ) 未許å¯ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã‹ã‚‰å—ã‘å–ã£ãŸã‹ã€<a href="attribut.htm#1025144">mgrpAllowedBroadcaster</a>属性ã®ãƒ¡ãƒ³ãƒãƒ¼ã§ãªã„メール アドレスã‹ã‚‰å—ã‘å–ã£ãŸã‹ã€ã¾ãŸã¯<a href="attribut.htm#1025878">mgrpMsgMaxSize</a>ã§è¨±å¯ã•ã‚ŒãŸã‚µã‚¤ã‚ºã‚’越ãˆã‚‹ãƒ¡ãƒ¼ãƒ«ã§ã‚ã‚‹ãŸã‚ã€ãƒ¡ãƒ¼ãƒ«ã‚’æ‹’å¦ã™ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1031346">
+Messaging Serverã§ã¯ã€å„mailGroupエントリã«ã¤ãã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã‚¼ãƒ­ã‹ã‚‰2(0〜2)å¿…è¦ã§ã™ã€‚ãŸã ã—ã€mailGroupエントリã«ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã¾ã£ãŸã存在ã—ãªã„å ´åˆã¯ã€ãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®<I>reply</I>ãŒä½¿ç”¨ã•ã‚Œã¾ã™ã€‚ã“ã®å±žæ€§ã®æœ‰åŠ¹ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰ã¯ã€æ¬¡ã®ã¨ãŠã‚Šã§ã™ã€‚<P></A>
+<ul><A NAME="1029629">
+<LI>reply -- é€ä¿¡è€…ã«å¤±æ•—通知ãŒé€ä¿¡ã•ã‚Œã¾ã™ã€‚失敗通知ã®ãƒ†ã‚­ã‚¹ãƒˆã¯<a href="attribut.htm#1025981">mgrpMsgRejectText </a>属性ã«ä¿å­˜ã•ã‚Œã¾ã™ã€‚<P>
+</A>
+<A NAME="1029638">
+<LI>bounce -- <a href="attribut.htm#1025981">mgrpMsgRejectText</a>属性ã§ä¿å­˜ã•ã‚ŒãŸæ³¨é‡ˆã‚’ä¼´ãªã†ãƒ¡ã‚»ãƒ¼ã‚¸ãŒé€ä¿¡è€…ã«è¿”ã•ã‚Œã¾ã™ã€‚<P>
+</A>
+<A NAME="1029664">
+<LI>toModerator -- 処ç†ã®ãŸã‚メッセージを仲è£è€…ã«è»¢é€ã—ã¾ã™ã€‚仲è£è€…ã¯ã€<a href="attribut.htm#1025705">mgrpModerator</a>属性ã§æŒ‡å®šã•ã‚Œã¾ã™ã€‚<P>
+</A>
+</ul>
+<A NAME="1029617">
+例:<P></A>
+<PRE><A NAME="1024635">
+ mgrpMsgRejectAction: bounce
+</A>
+</PRE>
+<A NAME="1278044">
+OID: <code>2.16.840.1.113730.3.1.28</code><P></A>
+
+<A NAME="1024637">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1025981">
+<A NAME="mgrpMsgRejectText">
+<B>mgrpMsgRejectText</B>
+</a></a>
+<P>
+
+
+<A NAME="1025983">
+メール グループã«é€ä¿¡ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ãŒæ‹’å¦ã•ã‚Œã€ã•ã‚‰ã«ã€mgrpMsgRejectAction属性㌠<I>bounce</I>ã¾ãŸã¯<I>reply</I>ã®ã„ãšã‚Œã‹ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã«ã€Messaging Serverã«ã‚ˆã£ã¦é€ä¿¡ã•ã‚Œã‚‹ãƒ†ã‚­ã‚¹ãƒˆã‚’表示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¡ãƒ¼ãƒ« リストを管ç†ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1030064">
+Messaging Serverã§ã¯ã€å„mailGroupエントリã«ã¤ãã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã‚¼ãƒ­ã‹ã‚‰1(0〜1)å¿…è¦ã§ã™ã€‚LDIFå½¢å¼ã§ç¤ºã™å ´åˆã¯ã€$を使用ã—ã¦è¤‡æ•°è¡Œã®ãƒ†ã‚­ã‚¹ãƒˆã‚’区切るã“ã¨ãŒã§ãã¾ã™ã€‚mailGroupエントリã«ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒã¾ã£ãŸã存在ã—ãªã„å ´åˆã¯ã€Messaging Serverã§è¨­å®šã•ã‚ŒãŸãƒ‡ãƒ•ã‚©ãƒ«ãƒˆã®ãƒ†ã‚­ã‚¹ãƒˆãŒã€æ‹’å¦ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ã«å¯¾ã—ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1030130">
+例:<P></A>
+<PRE><A NAME="1025984">
+ mgrpMsgRejectText: Crazed Bikersメール リストã«é€ä¿¡ã—ãŸãƒ¡ãƒ¼ãƒ«ã¯$<br> æ‹’å¦ã•ã‚Œã¾ã—ãŸã€‚$ã‚ãªãŸã¯Crazed Bikersグループã®<br> メンãƒãƒ¼ã§ã¯ã‚ã‚Šã¾ã›ã‚“。$ Big Daddy Biker<br> (ä½æ‰€ã¯rsweeny@airius.com)ã«é€£çµ¡ã—ã¦ã€$crazed bikerã®ãƒ¡ãƒ³ãƒãƒ¼ã«ãªã‚‹<br> 情報をå–å¾—ã—ã¦ãã ã•ã„。
+</A>
+</PRE>
+<A NAME="1278050">
+OID: <code>2.16.840.1.113730.3.1.29</code><P></A>
+
+<A NAME="1025986">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+<P>
+<A NAME="1102613">
+<A NAME="mgrpPassword">
+<B>mgrpPassword</B>
+</a></a>
+<P>
+
+
+<A NAME="1102614">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„。例:<P></A>
+<PRE><A NAME="1287369">
+ mgrpPassword: AAAAAA==
+</A>
+</PRE>
+<A NAME="1102615">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+<P>
+<A NAME="1024670">
+<A NAME="mgrpRFC822MailMember">
+<B>mgrpRFC822MailMember</B>
+</a></a>
+<P>
+
+
+<A NAME="1024672">
+<a href="attribut.htm#">mailGroup</a>ã«é€ä¿¡ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ã§ã€ãƒ¡ãƒ¼ãƒ« グループã®å®Ÿéš›ã®ãƒ¡ãƒ³ãƒãƒ¼ã§ãªã„å—信者を示ã—ã¾ã™ã€‚概念的ã«ã¯ã€ã“れらã®ãƒ¡ãƒ¼ãƒ« アドレスã¯ã€Œã‚«ãƒ¼ãƒœãƒ³ コピーã®å—信者ã€ã¨ã—ã¦è€ƒãˆã‚‰ã‚Œã¾ã™ã€‚ã¤ã¾ã‚Šã€ã“ã®å±žæ€§ã¯ã€è­˜åˆ¥åã§è¡¨ç¾ã§ããªã„メールå—信者やã€ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã‹ã‚‰ã®ãƒ¡ãƒ¼ãƒ«é€ä¿¡å…ˆã¨ã¯ãªã‚‹ãŒã€ã‚°ãƒ«ãƒ¼ãƒ— メンãƒãƒ¼ç‰¹æœ‰ã®å®Œå…¨ãªç‰¹æ¨©ã‚’æŒãŸãªã„メールå—信者を示ã™ã®ã«ä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¡ãƒ¼ãƒ« リストを管ç†ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1030207">
+Messaging Serverã§ã¯ã€ã“ã®å±žæ€§ãŒæ¬¡ã®å½¢å¼ã‚’使用ã—ãŸrfc822メール アドレスをå«ã‚€å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+<PRE><A NAME="1030236">
+<code> rfc822MailAddress [ % ユfullユ name] [ %1 (group parameter #1)]<br> [ %2 (group parameter #2)]...</code>
+</A>
+</PRE>
+<A NAME="1030231">
+説明:<P></A>
+<ul><A NAME="1030278">
+<LI>rfc822MailAddressã¯ã€æ¬¡ã®ã‚ˆã†ãªã‚¢ãƒ‰ãƒ¬ã‚¹ã§ã™ã€‚<P>
+</A>
+</ul><PRE><A NAME="1030338">
+ bjensen@airius.com
+</A>
+</PRE><ul><A NAME="1030343">
+<LI> full nameã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®æ°åを表示ã™ã‚‹ã‚ªãƒ—ションã®ãƒ‘ラメータã§ã™ã€‚ã“ã®ãƒ‘ラメータã¯å°†æ¥ã®ä½¿ç”¨ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P>
+</A>
+<A NAME="1030396">
+<LI> groupパラメータã¯ã€å°†æ¥ã®ä½¿ç”¨ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„るオプションã®ãƒ‘ラメータã§ã™ã€‚<P>
+</A>
+</ul>
+<A NAME="1030305">
+例:<P></A>
+<PRE><A NAME="1024673">
+ mgrpRFC822MailMember: bjensen@airius.com%Babs Jensen
+</A>
+</PRE>
+<A NAME="1278123">
+OID: <code>2.16.840.1.113730.3.1.30</code><P></A>
+
+<A NAME="1024675">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202056">&nbsp;
+</A>
+<A NAME="mobile">
+<H3> mobile</H3>
+</A>
+
+
+
+<A NAME="1202057">
+エントリã®æºå¸¯é›»è©±ç•ªå·ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202058">
+<PRE> mobileTelephoneNumber: 415-555-4321
+</PRE>
+</A>
+
+<A NAME="1202059">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1202060">
+<PRE> mobile: 415-555-4321
+</PRE>
+</A>
+
+<A NAME="1202062">
+<a href="attribut.htm#">ç•¥å·</a>: mobile<P></A>
+
+<A NAME="1202064">
+構文: <a href="attribut.htm#1004703">tel</a><P></A>
+
+
+<A NAME="1242555">&nbsp;
+</A>
+<A NAME="modifiersName">
+<H3> modifiersName</H3>
+</A>
+
+
+
+<A NAME="1242556">
+エントリã®æœ€çµ‚変更者ã®è­˜åˆ¥å(dn - distinguished name)ãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1242557">
+<PRE> modifiersName: <I>cn=jdoe, o=airius.com
+</I></PRE>
+</A>
+
+<A NAME="1242559">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1242117">&nbsp;
+</A>
+<A NAME="modifyTimestamp">
+<H3> modifyTimestamp</H3>
+</A>
+
+
+
+<A NAME="1242119">
+未定義。<P></A>
+
+<A NAME="1242126">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1229561">&nbsp;
+</A>
+<A NAME="multiLineDescription">
+<H3>multiLineDescription</H3>
+</A>
+
+
+
+<A NAME="1229562">
+メール ユーザを記述ã™ã‚‹ãƒ†ã‚­ã‚¹ãƒˆã‚’æä¾›ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Messaging ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚LDIFå½¢å¼ã§è¡¨ç¤ºã™ã‚‹å ´åˆã¯ã€å„行をドル記å·($)ã§åŒºåˆ‡ã‚Šã¾ã™ã€‚Messaging Serverã§ã¯ã€å„メール アカウントã«ã¤ãã“ã®å±žæ€§ãŒ0ã¾ãŸã¯1回æä¾›ã•ã‚Œã‚‹ã“ã¨ãŒå¿…è¦ã§ã™ã€‚例:<P></A>
+<PRE><A NAME="1229563">
+ multiLineDescription: アカウント管ç†è€…ãŠã‚ˆã³$ディレクトリ マãƒãƒ¼ã‚¸ãƒ£ã€‚
+</A>
+</PRE>
+<A NAME="1229565">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1243088">&nbsp;
+</A>
+<A NAME="namingContexts">
+<H3> namingContexts</H3>
+</A>
+
+
+
+<A NAME="1243089">
+未定義。<P></A>
+
+<A NAME="1243092">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1096606">&nbsp;
+</A>
+<A NAME="newRdn">
+<H3> newRdn</H3>
+</A>
+
+
+
+<A NAME="1096607">
+modRDNã¾ãŸã¯modDN動作ã®ã‚¿ãƒ¼ã‚²ãƒƒãƒˆã§ã‚るエントリã®æ–°è¦RDN (Relative Distinguished Name)ãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1096608">
+<PRE> newRdn: <I>cn=Jane Doe
+</I></PRE>
+</A>
+
+<A NAME="1100958">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1126531">&nbsp;
+</A>
+<A NAME="newSuperior">
+<H3> newSuperior</H3>
+</A>
+
+
+
+<A NAME="1126532">
+modDN動作ã®å‡¦ç†ã®éš›ã«ã€ç¾å­˜ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®ç›´ã上ã«ãªã‚‹ã‚¨ãƒ³ãƒˆãƒªåを示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1126533">
+<PRE> newSuperior: <I>cn=Jane Doe
+</I></PRE>
+</A>
+
+<A NAME="1126631">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1126633">&nbsp;
+</A>
+<A NAME="newsComponentName">
+<H3> newsComponentName</H3>
+</A>
+
+
+
+<A NAME="1126540">
+ã“ã®å±žæ€§ã«ã¯è¨Žè«– (ニュース)グループåãŒå«ã¾ã‚Œã¾ã™ã€‚ã“ã®åå‰ã¯ã€è¨Žè«–グループã®è­˜åˆ¥åã«ã‚‚使用ã§ãã¾ã™ã€‚例:<P></A>
+<A NAME="1126541">
+<PRE> newsComponentName: <I>marketing
+</I></PRE>
+</A>
+
+<A NAME="1126543">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1095332">&nbsp;
+</A>
+<A NAME="ngcomponent">
+<H3>ngcomponent</H3>
+</A>
+
+
+
+<A NAME="1095333">
+ニュース グループåã®ä¸€éƒ¨ã‚’識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚ニュース グループを一æ„ã«è­˜åˆ¥ã™ã‚‹ãŸã‚ã€Collabra ServerãŒ<a href="attribut.htm#">nginfo</a>エントリã§ä½¿ç”¨ã—ã¾ã™ã€‚Collabra ServerãŒã“ã®å±žæ€§ã«å…¥åŠ›ã™ã‚‹æƒ…å ±ã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã¨æ€§è³ªã¯ã€äºˆå‘Šãªã—ã«å¤‰æ›´ã•ã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1037897">
+例ãˆã°ã€comp.sys.mac newsgroup用ã«å…¥åŠ›ã•ã‚ŒãŸngcomponent属性ã¯æ¬¡ã®ã‚ˆã†ã«ãªã‚Šã¾ã™ã€‚<P></A>
+<PRE><A NAME="1037898">
+ dn: ngcomponent=mac, ngcomponent=sys, ngcomponent=comp,<br> ngcomponent=., <I>o=Airius.com<br></I> objectclass: top<br> objectclass: nginfo<br> ngcomponent=mac<br> ngcomponent=sys<br> ngcomponent=comp<br> ngcomponent=.
+</A>
+</PRE>
+<A NAME="1272795">
+OID: <code>2.16.840.1.113730.3.1.196</code><P></A>
+
+<A NAME="1037900">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+<P>
+<A NAME="1036977">
+<A NAME="nsaclrole">
+<B>nsaclrole</B>
+</a></a>
+<P>
+
+
+<A NAME="1037146">
+個々ã®ãƒ‹ãƒ¥ãƒ¼ã‚¹ グループã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹éš›ã®å½¹å‰² (マãƒãƒ¼ã‚¸ãƒ£ã€æŽ²ç¤ºè€…ã€èª­è€…ãªã©)を表示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚ã“ã‚Œã¯ã€<a href="objclass.htm#1078583">nginfo</a>エントリã§Collabra ServerãŒä½¿ç”¨ã—ã€å€‹ã€…ã®ãƒ‹ãƒ¥ãƒ¼ã‚¹ グループã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’管ç†ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ngcomponent subtreeã®ãƒ–ランムãƒã‚¤ãƒ³ãƒˆã«ãŠã„ã¦ã®ã¿ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚Collabra ServerãŒã“ã®å±žæ€§ã«å…¥åŠ›ã™ã‚‹æƒ…å ±ã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã¨æ€§è³ªã¯ã€äºˆå‘Šãªã—ã«å¤‰æ›´ã•ã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1036980">
+例:<P></A>
+<PRE><A NAME="1036981">
+ nsaclrole: admin:aprv
+</A>
+</PRE>
+<A NAME="1272665">
+OID: <code>2.16.840.1.113730.3.1.192</code><P></A>
+
+<A NAME="1036983">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1104932">
+<A NAME="nsCalAccess">
+<B>nsCalAccess</B>
+</a></a>
+<P>
+
+
+<A NAME="1177104">
+ã“ã®å±žæ€§ã¯å°†æ¥ã®ä½¿ç”¨ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1177105">
+Calendarユーザã€ç®¡ç†è€…ã€ã¾ãŸã¯ãƒªã‚½ãƒ¼ã‚¹ã«ã€Calendar Serverã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã®èªå¦ã‚’定義ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1120940">
+ nsCalAccess: allow
+</A>
+</PRE>
+<A NAME="1270551">
+OID: <code>2.16.840.1.113730.3.1.112</code><P></A>
+
+<A NAME="1104935">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1177696">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+<P>
+<A NAME="1166044">
+<A NAME="nsCalAccessDomain">
+<B>nsCalAccessDomain</B>
+</a></a>
+<P>
+
+
+<A NAME="1177890">
+Calendarユーザã€ç®¡ç†è€…ã€ã¾ãŸã¯ãƒªã‚½ãƒ¼ã‚¹ãŒCalendarデータã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã•ã‚Œã‚‹ã€ã‚¢ã‚¯ã‚»ã‚¹å…ƒã®ã‚¤ãƒ³ã‚¿ãƒ¼ãƒãƒƒãƒˆ ドメインã¾ãŸã¯IPアドレスをå«ã¿ã¾ã™ã€‚<P></A>
+<PRE><A NAME="1120977">
+ nsCalAccessDomain: airius.com
+</A>
+</PRE>
+<A NAME="1270575">
+OID: <code>2.16.840.1.113730.3.1.113</code><P></A>
+
+<A NAME="1104940">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1177866">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+<P>
+<A NAME="1104994">
+<A NAME="nsCalAdmd">
+<B>nsCalAdmd</B>
+</a></a>
+<P>
+
+
+<A NAME="1161412">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã«ã¯ã€X.400 Administration Management Domain NameãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1120980">
+ nsCalAdmd: telemail
+</A>
+</PRE>
+<A NAME="1270587">
+OID: <code>2.16.840.1.113730.3.1.114</code><P></A>
+
+<A NAME="1104995">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1105005">&nbsp;
+</A>
+<A NAME="nsCalDefaultNoteReminder">
+<H3> nsCalDefaultNoteReminder</H3>
+</A>
+
+
+
+<A NAME="1162561">
+Calendarユーザーã«é€ä¿¡ã•ã‚Œã‚‹ãƒŽãƒ¼ãƒˆ リマインダã®ã‚¿ã‚¤ãƒ—ãŒã‚ã‚‹å ´åˆã€ã“れを定義ã—ã¾ã™ã€‚リマインダ タイプã¯none (0)ã€visual (1)ã€ã¾ãŸã¯visual and audible (2)ã§ã™ã€‚Length of the reminder (リマインダã®é•·ã•)ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€ä¿¡ã•ã‚Œã‚‹ãƒªãƒžã‚¤ãƒ³ãƒ€ã®ãƒŽãƒ¼ãƒˆã®æœ‰åŠ¹æ™‚間を分å˜ä½ã§å®šç¾©ã—ã¾ã™ã€‚構文㯠<code>タイプ:分</code>ã§ã™ã€‚例:<P></A>
+<PRE><A NAME="1162562">
+ nsCalDefaultNoteReminder: 1:10
+</A>
+</PRE>
+<A NAME="1270589">
+OID: <code>2.16.840.1.113730.3.1.115</code><P></A>
+
+<A NAME="1105006">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1174630">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+<P>
+<A NAME="1162428">&nbsp;
+</A>
+<A NAME="nsCalDefaultReminder">
+<H3> nsCalDefaultReminder</H3>
+</A>
+
+
+
+<A NAME="1162430">
+カレンダーã®ã‚¤ãƒ™ãƒ³ãƒˆå‚加者ã«é€ä¿¡ã•ã‚Œã‚‹ã‚¤ãƒ™ãƒ³ãƒˆ リマインダã®ã‚¿ã‚¤ãƒ—ãŒã‚ã‚‹å ´åˆã€ã“れを定義ã—ã¾ã™ã€‚リマインダ タイプã¯none (0)ã€visual (1)ã€ã¾ãŸã¯ visual and audible (2)ã§ã™ã€‚Length of the reminder (リマインダã®é•·ã•)ã¯ã€ã‚¤ãƒ™ãƒ³ãƒˆå‚加者ã«é€ä¿¡ã•ã‚Œã‚‹ãƒªãƒžã‚¤ãƒ³ãƒ€ã®ã‚¤ãƒ™ãƒ³ãƒˆã¾ã§ã®æ™‚間を分å˜ä½ã§å®šç¾©ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1162431">
+<PRE><A NAME="1162431">
+ nsCalDefaultReminder: 1:10
+</A>
+</PRE>
+<A NAME="1270594">
+OID: <code>2.16.840.1.113730.3.1.116</code><P></A>
+
+<A NAME="1162433">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1175363">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+
+
+<A NAME="1105139">&nbsp;
+</A>
+<A NAME="nsCalDefaultTaskReminder">
+<H3> nsCalDefaultTaskReminder</H3>
+</A>
+
+
+
+<A NAME="1162515">
+Calendarユーザーã«é€ä¿¡ã•ã‚Œã‚‹ã‚¿ã‚¹ã‚¯ リマインダã®ã‚¿ã‚¤ãƒ—ãŒã‚ã‚‹å ´åˆã€ã“れを定義ã—ã¾ã™ã€‚リマインダ タイプã¯none (0)ã€visual (1)ã€ã¾ãŸã¯ visual and audible (2)ã§ã™ã€‚Length of the reminder (リマインダã®é•·ã•)ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€ä¿¡ã•ã‚Œã‚‹ãƒªãƒžã‚¤ãƒ³ãƒ€ã®ã‚¿ã‚¹ã‚¯ç· åˆ‡ã‚Šã¾ã§ã®æ™‚間を分å˜ä½ã§å®šç¾©ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1162516">
+ nsCalDefaultTaskReminder: 1:10
+</A>
+</PRE>
+<A NAME="1270608">
+OID: <code>2.16.840.1.113730.3.1.117</code><P></A>
+
+<A NAME="1162518">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1175448">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+
+
+<A NAME="1105164">
+<A NAME="nsCalDisplayPrefs">
+<B>nsCalDisplayPrefs</B>
+</a></a>
+<P>
+
+
+<A NAME="1161965">
+Calendarユーザã¾ãŸã¯ãƒªã‚½ãƒ¼ã‚¹ã®è¡¨ç¤ºç’°å¢ƒè¨­å®šã‚’å«ã¿ã¾ã™ã€‚ã“ã®å±žæ€§ã®æ§‹æ–‡ã¯ã€æ¬¡ã®ã¨ãŠã‚Šã§ã™ã€‚<code>Flags:StartDay:EndDay:WeekStart:TimeIncrement:ActiveDays:TimeFormat</code>. Flagsã¯ç¾åœ¨ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã›ã‚“。StartDayã¯æ—¥ä»˜è¡¨ç¤ºã®é–‹å§‹æ™‚é–“(分)〠EndDayã¯æ—¥ä»˜è¡¨ç¤ºã®çµ‚了時間(分)ã€WeekStartã¯Calendarクライアントã§è¡¨ç¤ºã™ã‚‹é€±ã®ç¬¬1日目ã§ã€é€šå¸¸ã¯æ—¥æ›œã‹æœˆæ›œã‚’示ã—ã¾ã™ã€‚TimeIncrementã§ã¯è¡¨ç¤ºã™ã‚‹æ™‚é–“å˜ä½(分)を定義ã—ã¾ã™ã€‚ActiveDaysã§ã¯ã€å¹³æ—¥ã®ã¿ãªã©ã€è¡¨ç¤ºã™ã‚‹æ—¥ã‚’指定ã—ã¾ã™ã€‚TimeFormatã§ã¯è¡¨ç¤ºæ™‚é–“å½¢å¼ (AM/PMã¾ãŸã¯24時間)を示ã—ã¾ã™ã€‚以下ã®ä¾‹ã§ã¯ã€<code>4</code>ã¯ãƒ•ãƒ©ã‚°ã‚’示ã—ã€ãƒ•ãƒ©ã‚°ã¯ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã›ã‚“。StartDay値 (480)ã¯åˆå‰8時ã€EndDay (1140)ã¯åˆå¾Œ7時ã€WeekStart (0)ã¯æ—¥æ›œã€TimeIncrementã¯15 分ã€ActiveDays値ã¯ã™ã¹ã¦ã€TimeFormatã¯24時間ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+<A NAME="1234997">
+<PRE><A NAME="1234997">
+ nsCalDisplayPrefs: 4:480:1140:0:15:127:2
+</A>
+</PRE>
+<A NAME="1270696">
+OID: <code>2.16.840.1.113730.3.1.118</code><P></A>
+
+<A NAME="1161784">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1174421">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+
+
+<A NAME="1164493">
+<A NAME="nsCalFlags">
+<B>nsCalFlags</B>
+</a></a>
+<P>
+
+
+<A NAME="1164494">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1270698">
+OID: <code>2.16.840.1.113730.3.1.119</code><P></A>
+
+<A NAME="1235001">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1157806">
+<A NAME="nsCalHost">
+<B>nsCalHost</B>
+</a></a>
+<P>
+
+
+<A NAME="1157807">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€Calendar Serverをホストã™ã‚‹ãƒ›ã‚¹ãƒˆåã¾ãŸã¯IPアドレスをå«ã¿ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1122178">
+ nsCalHost: calserver.airius.com
+</A>
+</PRE>
+<A NAME="1270812">
+OID: <code>2.16.840.1.113730.3.1.120</code><P></A>
+
+<A NAME="1105325">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1105333">
+<A NAME="nsCalLanguageId">
+<B>nsCalLanguageId</B>
+</a></a>
+<P>
+
+
+<A NAME="1162674">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã€ç®¡ç†è€…ã€ã¾ãŸã¯ãƒªã‚½ãƒ¼ã‚¹ãŒé›»å­ãƒ¡ãƒ¼ãƒ«é€šçŸ¥ã‚’å—ä¿¡ã™ã‚‹è¨€èªžã‚’定義ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1122193">
+ nsCalLanguageId: english
+</A>
+</PRE>
+<A NAME="1270838">
+OID: <code>2.16.840.1.113730.3.1.121</code><P></A>
+
+<A NAME="1157843">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1157846">
+<A NAME="nsCalNodeAlias">
+<B>nsCalNodeAlias</B>
+</a></a>
+<P>
+
+
+<A NAME="1157847">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€Calendarユーザã®æƒ…å ±ãŒä¿å­˜ã•ã‚Œã¦ã„るノードã®ãƒ‹ãƒ¼ãƒ¢ãƒ‹ãƒƒã‚¯åã‚’å«ã¿ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1171879">
+ nsCalNodeAlias: node10000
+</A>
+</PRE>
+<A NAME="1270844">
+OID: <code>2.16.840.1.113730.3.1.122</code><P></A>
+
+<A NAME="1118746">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1118755">
+<A NAME="nsCalNotifMechanism">
+<B>nsCalNotifMechanism</B>
+</a></a>
+<P>
+
+
+<A NAME="1162010">
+カレンダー イベントå‚加者ã®é€šçŸ¥(通常ã¯é›»å­ãƒ¡ãƒ¼ãƒ«)ã«ä½¿ç”¨ã•ã‚Œã‚‹æ©Ÿæ§‹ã‚’指定ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã®è¨±å®¹å€¤ã¯<code>1</code>ãŠã‚ˆã³<code>0</code> ã§ã€<code>1</code> ã¯é€šçŸ¥ãŒä½¿ç”¨å¯èƒ½ã§ã€<code>0</code>ã¯é€šçŸ¥ãŒä½¿ç”¨ä¸èƒ½ã§ã‚ã‚‹ã®ã‚’æ„味ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1122226">
+ nsCalNotifMechanism: 0
+</A>
+</PRE>
+<A NAME="1270863">
+OID: <code>2.16.840.1.113730.3.1.123</code><P></A>
+
+<A NAME="1118757">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1175516">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+<P>
+<A NAME="1105631">
+<A NAME="nsCalOperatingPrefs">
+<B>nsCalOperatingPrefs</B>
+</a></a>
+<P>
+
+
+<A NAME="1161868">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒ¦ãƒ¼ã‚¶ã¾ãŸã¯ãƒªã‚½ãƒ¼ã‚¹ã®OS環境設定を定義ã—ã¾ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1270865">
+OID: <code>2.16.840.1.113730.3.1.124</code><P></A>
+
+<A NAME="1161820">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1105739">
+<A NAME="nsCalOrgUnit2">
+<B>nsCalOrgUnit2</B>
+</a></a>
+<P>
+
+
+<A NAME="1161561">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒ¦ãƒ¼ã‚¶ã¾ãŸã¯ç®¡ç†è€…ã®X.400 Organization Unit 2(OU2)ã‚’å«ã¿ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1122284">
+ nsCalOrgUnit2: marketing
+</A>
+</PRE>
+<A NAME="1270887">
+OID: <code>2.16.840.1.113730.3.1.125</code><P></A>
+
+<A NAME="1105740">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1105752">
+<A NAME="nsCalOrgUnit3">
+<B>nsCalOrgUnit3</B>
+</a></a>
+<P>
+
+
+<A NAME="1161594">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒ¦ãƒ¼ã‚¶ã¾ãŸã¯ç®¡ç†è€…ã®X.400 Organization Unit 3(OU3)ã‚’å«ã¿ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1122291">
+ nsCalOrgUnit3: sales
+</A>
+</PRE>
+<A NAME="1270897">
+OID: <code>2.16.840.1.113730.3.1.126</code><P></A>
+
+<A NAME="1105753">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1105815">
+<A NAME="nsCalOrgUnit4">
+<B>nsCalOrgUnit4</B>
+</a></a>
+<P>
+
+
+<A NAME="1164929">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒ¦ãƒ¼ã‚¶ã¾ãŸã¯ç®¡ç†è€…ã®X.400 Organization Unit 4(OU4)ã‚’å«ã¿ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1164930">
+ nsCalOrgUnit4: engineering
+</A>
+</PRE>
+<A NAME="1270918">
+OID: <code>2.16.840.1.113730.3.1.127</code><P></A>
+
+<A NAME="1105816">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1105834">
+<A NAME="nsCalPasswordRequired">
+<B>nsCalPasswordRequired</B>
+</a></a>
+<P>
+
+
+<A NAME="1162629">
+Calendarデータã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹éš›ã«ã€CalendarユーザãŒãƒ‘スワードを入力ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚許容値ã¯ã€<code>1</code>ãŠã‚ˆã³<code>0</code>ã§ã€<code>1</code>ã¯ãƒ‘スワードãŒå¿…è¦ã§ã‚ã‚Šã€<code>0</code>ã¯ãƒ‘スワードãŒå¿…è¦ã§ãªã„ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1122383">
+ nsCalPasswordRequired: 1
+</A>
+</PRE>
+<A NAME="1270965">
+OID: <code>2.16.840.1.113730.3.1.128</code><P></A>
+
+<A NAME="1105835">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1175590">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+<P>
+<A NAME="1105891">
+<A NAME="nsCalPrmd">
+<B>nsCalPrmd</B>
+</a></a>
+<P>
+
+
+<A NAME="1161468">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒ¦ãƒ¼ã‚¶ã¾ãŸã¯ç®¡ç†è€…ã®X.400 Private Management Domain Nameã‚’å«ã¿ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1271010">
+ nsCalPrmd: airius
+</A>
+</PRE>
+<A NAME="1271034">
+OID: <code>2.16.840.1.113730.3.1.129</code><P></A>
+
+<A NAME="1271012">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1105943">
+<A NAME="nsCalRefreshPrefs">
+<B>nsCalRefreshPrefs</B>
+</a></a>
+<P>
+
+
+<A NAME="1165339">
+ã“ã®å±žæ€§ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ç’°å¢ƒè¨­å®šã‚’æ›´æ–°ã™ã‚‹ã‹ã©ã†ã‹ã€ã¾ãŸãã®æ›´æ–°é »åº¦ã‚’定義ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã®æ§‹æ–‡ã¯ <code>オン/オフ:分</code>ã§ã™ã€‚<code>オン/オフ</code>ã®è¨±å®¹å€¤ã¯<code>1</code>ãŠã‚ˆã³<code>0</code>ã§ã€<code>1</code>ã¯ç’°å¢ƒè¨­å®šã‚’æ›´æ–°ã—ã€<code>0</code> ã¯ç’°å¢ƒè¨­å®šã‚’æ›´æ–°ã—ãªã„ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚ <code>オン/オフ</code>ã®å€¤ã‚’<code>1</code>ã«è¨­å®šã—ã¦ã„ã‚‹å ´åˆã€æ›´æ–°é–“éš”ã¯åˆ†ã§å…¥åŠ›ã—ã¾ã™ã€‚次ã®ä¾‹ã§ã¯ã€nsCalRefreshPrefsã¯ã‚ªãƒ•ã«è¨­å®šã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+<PRE><A NAME="1171900">
+ nsCalRefreshPrefs: 0:0
+</A>
+</PRE>
+<A NAME="1271056">
+OID: <code>2.16.840.1.113730.3.1.130</code><P></A>
+
+<A NAME="1105944">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1173593">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+<P>
+<A NAME="1105996">
+<A NAME="nsCalResourceCapacity">
+<B>nsCalResourceCapacity</B>
+</a></a>
+<P>
+
+
+<A NAME="1163461">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ä¾‹ãˆã°ä¼šè­°å®¤ã®ã‚ˆã†ãªãƒªã‚½ãƒ¼ã‚¹ã®å®¹é‡ã‚’定義ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1122484">
+ nsCalResourceCapacity: 65
+</A>
+</PRE>
+<A NAME="1271073">
+OID: <code>2.16.840.1.113730.3.1.131</code><P></A>
+
+<A NAME="1209240">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<A NAME="1209242">
+<A NAME="nsCalResourceNumber">
+<B>nsCalResourceNumber</B>
+</a></a>
+<P>
+
+
+<A NAME="1209244">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒªã‚½ãƒ¼ã‚¹ã®è­˜åˆ¥ç•ªå·ã‚’å«ã¿ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1165759">
+ nsCalResourceNumber: 6725
+</A>
+</PRE>
+<A NAME="1271092">
+OID: <code>2.16.840.1.113730.3.1.132</code><P></A>
+
+<A NAME="1106037">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1106093">
+<A NAME="nsCalServerVersion">
+<B>nsCalServerVersion</B>
+</a></a>
+<P>
+
+
+<A NAME="1160060">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€Calendarユーザã®ãƒ‡ãƒ¼ã‚¿ã‚’ホストã—ã¦ã„ã‚‹Calendar Serverã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç•ªå·ã‚’å«ã¿ã¾ã™ã€‚例:<P></A>
+<A NAME="1122498">
+<PRE><A NAME="1122498">
+ nsCalServerVersion: 1.0
+</A>
+</PRE>
+<A NAME="1271164">
+OID: <code>2.16.840.1.113730.3.1.133</code><P></A>
+
+<A NAME="1106094">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1106115">
+<A NAME="nsCalSysopCanWritePassword">
+<B>nsCalSysopCanWritePassword</B>
+</a></a>
+<P>
+
+
+<A NAME="1162650">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€Calendar Server管ç†è€…ãŒãƒ¦ãƒ¼ã‚¶ã€ãƒªã‚½ãƒ¼ã‚¹ã€ãŠã‚ˆã³ä»–ã®ç®¡ç†è€…ã®ãƒ‘スワードを上書ãã§ãã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã®è¨±å®¹å€¤ã¯<code>1</code>ãŠã‚ˆã³<code>0</code>ã§ã€<code>1</code>ã¯ç®¡ç†è€…ãŒãƒ‘スワードを上書ãã§ãã€<code>0</code>ã¯ç®¡ç†è€…ãŒãƒ‘スワードを上書ãã§ããªã„ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1171915">
+ nsCalSysopCanWritePassword: 1
+</A>
+</PRE>
+<A NAME="1271166">
+OID: <code>2.16.840.1.113730.3.1.134</code><P></A>
+
+<A NAME="1106116">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1106160">
+<A NAME="nsCalTimezone">
+<B>nsCalTimezone</B>
+</a></a>
+<P>
+
+
+<A NAME="1162695">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒªã‚½ãƒ¼ã‚¹ã®ç¾åœ¨ã®æ™‚間帯をå«ã¿ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1122560">
+ nsCalTimezone: PST
+</A>
+</PRE>
+<A NAME="1271168">
+OID: <code>2.16.840.1.113730.3.1.135</code><P></A>
+
+<A NAME="1106161">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1106218">
+<A NAME="nsCalXItemId">
+<B>nsCalXItemId</B>
+</a></a>
+<P>
+
+
+<A NAME="1159973">
+ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Calendar ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’代表ã™ã‚‹nsCalendarObjectã®ä¸€æ„ã®è­˜åˆ¥å­ã‚’å«ã¿ã¾ã™ã€‚ã“ã®è­˜åˆ¥å­ã¯ã€Calendarユーザーã€ç®¡ç†è€…ã€ã¾ãŸã¯ãƒªã‚½ãƒ¼ã‚¹ã®ãƒ‡ãƒ¼ã‚¿ãŒä¿å­˜ã•ã‚Œã¦ã„るノードã®è­˜åˆ¥ç•ªå·ã¨ã€Calendarユーザーã€ç®¡ç†è€…ã€ã¾ãŸã¯ãƒªã‚½ãƒ¼ã‚¹ã®è­˜åˆ¥ç•ªå·ã¨ã‹ã‚‰æ§‹æˆã•ã‚Œã¦ã„ã¾ã™ã€‚å½¢å¼ã¯<code>NodeId,ItemId</code>ã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。例:<P></A>
+<PRE><A NAME="1159974">
+ nsCalXItemId: 123,6547
+</A>
+</PRE>
+<A NAME="1271216">
+OID: <code>2.16.840.1.113730.3.1.136</code><P></A>
+
+<A NAME="1106219">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1037693">
+<A NAME="nscreator">
+<B>nscreator</B>
+</a></a>
+<P>
+
+
+<A NAME="1037694">
+ニュース グループã®ä½œæˆè€…を識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Collabra ServerãŒä½¿ç”¨ã—ã¦ã€<a href="objclass.htm#1078583">nginfo</a>エントリã§ãƒ‹ãƒ¥ãƒ¼ã‚¹ グループã®ä½œæˆè€…uidを識別ã—ã¾ã™ã€‚Collabra ServerãŒã“ã®å±žæ€§ã«å…¥åŠ›ã™ã‚‹æƒ…å ±ã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã¨æ€§è³ªã¯ã€äºˆå‘Šãªã—ã«å¤‰æ›´ã•ã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1037696">
+例:<P></A>
+<PRE><A NAME="1037697">
+ nscreator: admin
+</A>
+</PRE>
+<A NAME="1272746">
+OID: <code>2.16.840.1.113730.3.1.195</code><P></A>
+
+<A NAME="1037699">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1037564">
+<A NAME="nsflags">
+<B>nsflags</B>
+</a></a>
+<P>
+
+<A NAME="1037565">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1272737">
+OID: <code>2.16.840.1.113730.3.1.194</code><P></A>
+
+<A NAME="1037567">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1091847">
+<A NAME="nsLicensedFor">
+<B>nsLicensedFor</B>
+</a></a>
+<P>
+
+
+<A NAME="1305579">
+ユーザãŒä½¿ç”¨è¨±è«¾å¥‘ç´„ã‚’æŒã¤Netscapeサーãƒã‚’識別ã—ã¾ã™ã€‚Netscape Administration Serverã§ã¯ã€ã“ã®å±žæ€§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ãŒå„<a href="attribut.htm#">nsLicenseUser</a>エントリã«ã¤ã„ã¦ã€ã‚¼ãƒ­ã¾ãŸã¯ãれ以上å«ã¾ã‚Œã¦ã„ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ç¾åœ¨ã“ã®å±žæ€§ã®æœ‰åŠ¹ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰ã¯ã€æ¬¡ã®ã¨ãŠã‚Šã§ã™ã€‚<P></A>
+<ul><A NAME="1305581">
+<LI><code>mail</code>--ユーザã¯ã€Messaging Serverã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹å¥‘ç´„ã‚’æŒã¤ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã§ã™ã€‚<P>
+</A>
+<A NAME="1305582">
+<LI><code>news</code>--ユーザã¯ã€Collabra Serverã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹å¥‘ç´„ã‚’æŒã¤ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã§ã™ã€‚<P>
+</A>
+<A NAME="1091852">
+<LI><code>slapd</code>--ユーザã¯ã€Directory Serverã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹å¥‘ç´„ã‚’æŒã¤ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã§ã™ã€‚<P>
+</A>
+<A NAME="1091853">
+<LI><code>cal</code>--ユーザã¯ã€Calendar Serverã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹å¥‘ç´„ã‚’æŒã¤ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆã§ã™ã€‚<P>
+</A>
+</ul>
+<A NAME="1091854">
+例:<P></A>
+<PRE><A NAME="1091855">
+ nsLicensedFor: slapd
+</A>
+</PRE>
+<A NAME="1257889">
+OID: <code>2.16.840.1.113730.3.1.36</code><P></A>
+
+<A NAME="1091857">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1091859">
+<A NAME="nsLicenseStartTime">
+<B>nsLicenseStartTime</B>
+</a></a>
+<P>
+
+
+<A NAME="1091860">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1257896">
+OID: <code>2.16.840.1.113730.3.1.37</code><P></A>
+
+<A NAME="1091862">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1091864">
+<A NAME="nsLicenseEndTime">
+<B>nsLicenseEndTime</B>
+</a></a>
+<P>
+
+<A NAME="1091865">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1257974">
+OID: <code>2.16.840.1.113730.3.1.38</code><P></A>
+
+<A NAME="1091867">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1092030">
+<A NAME="nsnewsACL">
+<B>nsnewsACL</B>
+</a></a>
+<P>
+
+
+<A NAME="1092031">
+個々ã®ãƒ‹ãƒ¥ãƒ¼ã‚¹ グループã«è¨­å®šã•ã‚ŒãŸã‚¢ã‚¯ã‚»ã‚¹åˆ¶å¾¡ã‚’識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚Collabra ServerãŒä½¿ç”¨ã—ã¦ã€<a href="attribut.htm#">nginfo</a>エントリã§å€‹ã€…ã®ãƒ‹ãƒ¥ãƒ¼ã‚¹ グループã®ã‚¢ã‚¯ã‚»ã‚¹åˆ¶å¾¡ã‚’識別ã—ã¾ã™ã€‚Collabra ServerãŒã“ã®å±žæ€§ã«å…¥åŠ›ã™ã‚‹æƒ…å ±ã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã¨æ€§è³ªã¯ã€äºˆå‘Šãªã—ã«å¤‰æ›´ã•ã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1092033">
+例:<P></A>
+<PRE><A NAME="1092034">
+ nsnewsACL: 2:*:a:D::admin:bpolk::d:*:a:D::manager:admin::d:
+</A>
+</PRE>
+<A NAME="1272650">
+OID: <code>2.16.840.1.113730.3.1.191</code><P></A>
+
+<A NAME="1092036">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1037277">
+<A NAME="nsprettyname">
+<B>nsprettyname</B>
+</a></a>
+<P>
+
+
+<A NAME="1037278">
+ニュース グループã®æ´’è½ãŸåå‰ã¾ãŸã¯è¡¨ç¤ºåを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€Collabra ServerãŒä½¿ç”¨ã—ã¦ã€<a href="attribut.htm#">nginfo</a>エントリã§å€‹ã€…ã®ãƒ‹ãƒ¥ãƒ¼ã‚¹ グループを識別ã—ã¾ã™ã€‚Collabra ServerãŒã“ã®å±žæ€§ã«å…¥åŠ›ã™ã‚‹æƒ…å ±ã®ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã¨æ€§è³ªã¯ã€äºˆå‘Šãªã—ã«å¤‰æ›´ã•ã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1037280">
+例:<P></A>
+<PRE><A NAME="1037281">
+ nsprettyname: MKTG FOR RACHU
+</A>
+</PRE>
+<A NAME="1272668">
+OID: <code>2.16.840.1.113730.3.1.193</code><P></A>
+
+<A NAME="1037283">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1122623">
+<A NAME="ntGroupAttributes">
+<B>ntGroupAttributes</B>
+</a></a>
+<P>
+
+
+<A NAME="1122625">
+NTåŒæœŸåŒ–サービスãŒã€NTグループã®å±žæ€§ä¿å­˜ã«ä½¿ç”¨ã™ã‚‹ãŸã‚予約。<P></A>
+
+<A NAME="1262720">
+OID: <code>1.2.840.113556.1.4.152</code><P></A>
+
+<A NAME="1251757">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+<P>
+<A NAME="1122633">
+<A NAME="ntGroupCreateNewGroup">
+<B>ntGroupCreateNewGroup</B>
+</a></a>
+<P>
+
+
+<A NAME="1122635">
+NTåŒæœŸåŒ–サービスã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1258152">
+OID: <code>2.16.840.1.113730.3.1.45</code><P></A>
+
+<A NAME="1258154">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1103799">
+<A NAME="ntGroupDeleteGroup">
+<B>ntGroupDeleteGroup</B>
+</a></a>
+<P>
+
+
+<A NAME="1103800">
+NTåŒæœŸåŒ–サービスã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1258186">
+OID: <code>2.16.840.1.113730.3.1.46</code><P></A>
+
+<A NAME="1258188">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1103684">
+<A NAME="ntGroupDomainId">
+<B>ntGroupDomainId</B>
+</a></a>
+<P>
+
+
+<A NAME="1103686">
+NTåŒæœŸåŒ–サービスã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã€NT Global Groupname/Domainã‚’ä¿å­˜ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1258086">
+OID: <code>2.16.840.1.113730.3.1.44</code><P></A>
+
+<A NAME="1251773">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1104232">
+<A NAME="ntGroupId">
+<B>ntGroupId</B>
+</a></a>
+<P>
+
+
+<A NAME="1104233">
+未定義<P></A>
+
+<A NAME="1260150">
+OID: <code>2.16.840.1.113730.3.1.110</code><P></A>
+
+<A NAME="1104234">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+<P>
+<A NAME="1283379">
+<A NAME="ntGroupType">
+<B>ntGroupType</B>
+</a></a>
+<P>
+
+
+<A NAME="1283380">
+2ã¤ã®æœ‰åŠ¹å€¤ã¯globalãŠã‚ˆã³localã§ã™ã€‚<P></A>
+
+<A NAME="1283381">
+OID: <code>2.16.840.1.113730.3.1.47</code><P></A>
+
+<A NAME="1283383">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1013839">&nbsp;
+</A>
+<A NAME="ntUserAcctExpires">
+<H3> ntUserAcctExpires</H3>
+</A>
+
+
+
+<A NAME="1013857">
+エントリã®Windows NTアカウント失効日を示ã—ã¾ã™ã€‚ã“ã®å€¤ã¯ã€GMTå½¢å¼ã®æ–‡å­—列ã¨ã—ã¦ä¿å­˜ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1013887">
+<PRE> ntUserAcctExpires: 19961015203415Z
+</PRE>
+</A>
+
+<A NAME="1024626">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1014052">&nbsp;
+</A>
+<A NAME="ntUserAuthFlags">
+<H3> ntUserAuthFlags</H3>
+</A>
+
+
+
+<A NAME="1014053">
+Windowsãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã«ãŠã‘るエントリã®å‘½ä»¤ç‰¹æ¨©ãŒå«ã¾ã‚Œã‚‹ç¬¦å·ãªã—ã®é•·æ•´æ•°ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1038769">
+<PRE> ntUserAuthFlags: AAAAAA==
+</PRE>
+</A>
+
+<A NAME="1038770">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1038772">&nbsp;
+</A>
+<A NAME="ntUserBadPwCount">
+<H3> ntUserBadPwCount</H3>
+</A>
+
+
+
+<A NAME="1014169">
+æ­£ã—ããªã„パスワードを使用ã—ã¦Windowsアカウントã«ãƒ­ã‚°ã‚ªãƒ³ã‚’試ã¿ãŸå›žæ•°ã‚’示ã—ã¾ã™ã€‚ 0xFFFFFFFFã®å€¤ã¯ã€å€¤ãŒä¸æ˜Žã§ã‚ã‚‹ã“ã¨ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1014915">
+<PRE> ntUserBadPwCount: AAAAAA==
+</PRE>
+</A>
+
+<A NAME="1038807">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1014973">&nbsp;
+</A>
+<A NAME="ntUserCodePage">
+<H3> ntUserCodePage</H3>
+</A>
+
+
+
+<A NAME="1014989">
+ユーザーã®é¸æŠžè¨€èªžã®ã‚³ãƒ¼ãƒ‰ ページ。例:<P></A>
+<A NAME="1015015">
+<PRE> ntUserCodePage: AAAAAA==
+</PRE>
+</A>
+
+<A NAME="1246827">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1246829">&nbsp;
+</A>
+<A NAME="ntUsercomment">
+<H3> ntUsercomment</H3>
+</A>
+
+
+
+<A NAME="1246830">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã«é–¢ã™ã‚‹è¨˜è¿°ã¾ãŸã¯æ³¨é‡ˆã‚’示ã™ASCII文字列。例:<P></A>
+<A NAME="1015193">
+<PRE> ntUserComment: Quality control inspector for the ME2873 <br>
+ product line
+</PRE>
+</A>
+
+<A NAME="1038675">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+
+
+<A NAME="1015155">&nbsp;
+</A>
+<A NAME="ntUserCountryCode">
+<H3> ntUserCountryCode</H3>
+</A>
+
+
+
+<A NAME="1015217">
+ユーザーã®é¸æŠžè¨€èªžã®å›½ã‚³ãƒ¼ãƒ‰ã€‚例:<P></A>
+<A NAME="1015224">
+<PRE> ntUserCountryCode: AAAAAA==
+</PRE>
+</A>
+
+<A NAME="1038682">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+
+
+<A NAME="1015239">&nbsp;
+</A>
+<A NAME="ntUserCreateNewAccount">
+<H3> ntUserCreateNewAccount</H3>
+</A>
+
+
+
+<A NAME="1015245">
+Directory Serverã®æ–°è¦ãƒ¦ãƒ¼ã‚¶ãƒ¼ エントリã«å¯¾å¿œã™ã‚‹NTユーザー アカウントを作æˆã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚ ntUserCreateNewAccountã¯Directory Serverã‹ã‚‰ç·¨é›†ã§ãã¾ã™ã€‚ntUserCreateNewAccountãŒ<code>True</code>ã«è¨­å®šã•ã‚Œã¦ãŠã‚Šã€ã—ã‹ã‚‚特定ユーザーåã®NTアカウントãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€NTアカウントãŒä½œæˆã•ã‚Œã¾ã™ã€‚ã“ã®å±žæ€§ãŒ<code>False</code>ã«è¨­å®šã•ã‚Œã¦ãŠã‚Šã€ã—ã‹ã‚‚NTアカウントãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€ã‚¨ãƒ©ãƒ¼ãŒè¨˜éŒ²ã•ã‚Œã¾ã™ã€‚NTアカウントãŒå­˜åœ¨ã—ã€å±žæ€§ãŒ<code>False</code>ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã¯ã€æ—¢å­˜ã®NTアカウントãŒæ›´æ–°ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1015264">
+ ntUserCreateNewAccount: true
+</A>
+</PRE>
+<A NAME="1258018">
+OID: <code>2.16.840.1.113730.3.1.42</code><P></A>
+
+<A NAME="1258029">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1015309">
+<A NAME="NTUserDelete">
+<B>ntUserDeleteAccount</B>
+</a></a>
+<P>
+<A NAME="1015321">
+Directory Serverã‹ã‚‰ã‚¨ãƒ³ãƒˆãƒªã‚’削除ã™ã‚‹éš›ã«NTユーザー アカウントを削除ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚ntUserDeleteAccountã¯Directory Serverã‹ã‚‰ç·¨é›†ã§ãã¾ã™ã€‚ã“ã®å±žæ€§ãŒ<code>true</code>ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã¯ã€Directory Serverã‹ã‚‰ã‚¨ãƒ³ãƒˆãƒªã‚’削除ã™ã‚‹ã¨ NTユーザー アカウントãŒå‰Šé™¤ã•ã‚Œã¾ã™ã€‚ã“ã®å±žæ€§ãŒ<code>false</code>ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã¯ã€NTユーザー アカウントã¯å‰Šé™¤ã•ã‚Œã¾ã›ã‚“。ntUserエントリã®å‰Šé™¤ã®è©³ç´°ã¯ã€ã€ŒNTUserエントリã®å‰Šé™¤ã€ã‚’ã”覧ãã ã•ã„。例:<P></A>
+<A NAME="1015367">
+<PRE> ntUserDeleteAccount: true
+</PRE>
+</A>
+
+<A NAME="1038688">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1015403">
+<A NAME="ntUserDomainId">
+<B>ntUserDomainId</B>
+</a></a>
+<P>
+
+
+<A NAME="1015422">
+エントリã®NTドメインåã¨ãƒ¦ãƒ¼ã‚¶ãƒ¼åã‚’NT-domain-name:NT-usernameã®å½¢å¼ã§ç¤ºã—ã¾ã™ã€‚NTUserDomainIdã¯Directory Serverã‹ã‚‰ç·¨é›†ã§ãã¾ã™ã€‚例:<P></A>
+<A NAME="1015476">
+<PRE> ntUserDomainId: workgroup:jsmith
+</PRE>
+</A>
+
+<A NAME="1038691">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1015534">
+<A NAME="ntUserFlags">
+<B>ntUserFlags</B>
+</a></a>
+<P>
+
+
+<A NAME="1015550">
+ユーザーã¨ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«é–¢ã™ã‚‹ã„ãã¤ã‹ã®æ©Ÿèƒ½ã‚’判定ã™ã‚‹å€¤ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1015561">
+<PRE> ntUserFlags: AQIBAA==
+</PRE>
+</A>
+
+<A NAME="1038821">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1015584">&nbsp;
+</A>
+<A NAME="ntUserHomeDir">
+<H3> ntUserHomeDir</H3>
+</A>
+
+
+
+<A NAME="1015596">
+ユーザーã®ãƒ›ãƒ¼ãƒ  ディレクトリã®ãƒ‘スを示ã™ASCII文字列。文字列ã«ã¯ãƒŒãƒ«ã‚’使用ã§ãã¾ã™ã€‚例:<P></A>
+<A NAME="1015610">
+<PRE> ntUserHomeDir: c:\u\d78\jsmith\
+</PRE>
+</A>
+
+<A NAME="1038694">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1015624">
+<A NAME="ntUserHomeDirDrive">
+<B>ntUserHomeDirDrive</B>
+</a></a>
+<P>
+
+
+<A NAME="1015648">
+ユーザーã®ãƒ›ãƒ¼ãƒ  ディレクトリã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸãƒ‰ãƒ©ã‚¤ãƒ–ã®æ–‡å­—を示ã™ASCII文字列。例:<P></A>
+<A NAME="1015659">
+<PRE> ntUserHomeDirDrive: c:
+</PRE>
+</A>
+
+<A NAME="1038697">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1015682">
+<A NAME="ntUserLastLogoff">
+<B>ntUserLastLogoff</B>
+</a></a>
+<P>
+
+
+<A NAME="1015726">
+最後ã®ãƒ­ã‚°ã‚ªãƒ•æ™‚刻を示ã—ã¾ã™ã€‚ã“ã®å€¤ã¯GMTå½¢å¼ã®æ–‡å­—列ã¨ã—ã¦ä¿å­˜ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1015727">
+<PRE> ntUserLastLogoff: 19961015203415Z
+</PRE>
+</A>
+
+<A NAME="1019703">
+セキュリティ ログãŒã‚ªãƒ³ã«ãªã£ã¦ã„ã¦ã€ãã®ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ エントリã«å¤‰æ›´ã•ã‚Œã¦ã„ã‚‹ã‚‚ã®ãŒã‚ã‚‹å ´åˆã«é™ã‚Šã€ã“ã®å±žæ€§ãŒåŒæœŸåŒ–ã®éš›ã«æ›´æ–°ã•ã‚Œã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。<P></A>
+
+<A NAME="1038700">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1015722">
+<A NAME="ntUserLastLogon">
+<B>ntUserLastLogon</B>
+</a></a>
+<P>
+
+
+<A NAME="1015750">
+最後ã®ãƒ­ã‚°ã‚ªãƒ³æ™‚刻を示ã—ã¾ã™ã€‚ã“ã®å€¤ã¯GMTå½¢å¼ã®æ–‡å­—列ã¨ã—ã¦ä¿å­˜ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1015751">
+<PRE> ntUserLastLogon: 19961015203415Z
+</PRE>
+</A>
+
+<A NAME="1019919">
+セキュリティ ログãŒã‚ªãƒ³ã«ãªã£ã¦ã„ã¦ã€ãã®ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ エントリã«å¤‰æ›´ã•ã‚Œã¦ã„ã‚‹ã‚‚ã®ãŒã‚ã‚‹å ´åˆã«é™ã‚Šã€ã“ã®å±žæ€§ãŒåŒæœŸåŒ–ã®éš›ã«æ›´æ–°ã•ã‚Œã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。<P></A>
+
+<A NAME="1038703">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1015746">
+<A NAME="ntUserLogonHours">
+<B>ntUserLogonHours</B>
+</a></a>
+<P>
+
+
+<A NAME="1015787">
+ユーザーãŒãƒ­ã‚°ã‚ªãƒ³å¯èƒ½ãªæ™‚間帯を示ã—ã¾ã™ã€‚時刻ã¯ã€æ–‡å­—列内ã«ãŠã„ã¦æ›œæ—¥ã®æ™‚é–“ã¨ãƒ“ットã¨ã®1対1対応ã§ç¤ºã•ã‚Œã¾ã™ã€‚例ãˆã°ã€ãƒ“ット 0ワード0ã¯æ—¥æ›œã® 0:00ã‹ã‚‰0:59ã§ã™ã€‚ビット1 ワード0ã¯æ—¥æ›œã®1:00ã‹ã‚‰1:59ã§ã™ã€‚例:<P></A>
+<A NAME="1015803">
+<PRE> ntUserLogonHours: ///1000011100000101111111...
+</PRE>
+</A>
+
+<A NAME="1019921">
+セキュリティ ログãŒã‚ªãƒ³ã«ãªã£ã¦ã„ã¦ã€ãã®ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ エントリã«å¤‰æ›´ã•ã‚Œã¦ã„ã‚‹ã‚‚ã®ãŒã‚ã‚‹å ´åˆã«é™ã‚Šã€ã“ã®å±žæ€§ãŒåŒæœŸåŒ–ã®éš›ã«æ›´æ–°ã•ã‚Œã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。<P></A>
+
+<A NAME="1038824">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1015839">&nbsp;
+</A>
+<A NAME="ntUserLogonServer">
+<H3> ntUserLogonServer</H3>
+</A>
+
+
+
+<A NAME="1015859">
+ユーザーã®ãƒ­ã‚°ã‚ªãƒ³è¦æ±‚ãŒé€ä¿¡ã•ã‚ŒãŸã‚µãƒ¼ãƒãƒ¼åを示ã™ASCII文字列。サーãƒãƒ¼åã¯2個ã®ãƒãƒƒã‚¯ã‚¹ãƒ©ãƒƒã‚·ãƒ¥(\\)ã«ã‚ˆã£ã¦å…ˆè¡Œã•ã‚Œãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。\\*ã®ã‚µãƒ¼ãƒãƒ¼åã¯ã€ãƒ­ã‚°ã‚ªãƒ³è¦æ±‚ãŒä»»æ„ã®ãƒ­ã‚°ã‚ªãƒ³ã‚µãƒ¼ãƒãƒ¼ã«ã‚ˆã£ã¦å‡¦ç†å¯èƒ½ãªã“ã¨ã‚’示ã—ã¾ã™ã€‚ヌル文字列ã¯ã€è¦æ±‚ãŒãƒ‰ãƒ¡ã‚¤ãƒ³ コントローラã«é€ä¿¡ã•ã‚Œã‚‹ã“ã¨ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1015953">
+<PRE> ntUserLogonServer: \\firefly
+</PRE>
+</A>
+
+<A NAME="1038706">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1015984">
+<A NAME="ntUserMaxStorage">
+<B>ntUserMaxStorage</B>
+</a></a>
+<P>
+
+
+<A NAME="1015997">
+ユーザーãŒä½¿ç”¨ã§ãる最大ディスク容é‡ã€‚例:<P></A>
+<A NAME="1016004">
+<PRE> ntUserMaxStorage: ///////W==
+</PRE>
+</A>
+
+<A NAME="1038827">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1016030">&nbsp;
+</A>
+<A NAME="ntUserNumLogons">
+<H3> ntUserNumLogons</H3>
+</A>
+
+
+
+<A NAME="1016043">
+ã“ã®ã‚¢ã‚«ã‚¦ãƒ³ãƒˆã«æˆåŠŸã—ãŸãƒ­ã‚°ã‚ªãƒ³å›žæ•°ã‚’示ã—ã¾ã™ã€‚0xFFFFFFFFã®å€¤ã¯ã€å€¤ãŒä¸æ˜Žã§ã‚ã‚‹ã“ã¨ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1016085">
+<PRE> ntUserNumLogons: WwAAAA==
+</PRE>
+</A>
+
+<A NAME="1038830">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1021575">&nbsp;
+</A>
+<A NAME="ntUserParms">
+<H3> ntUserParms</H3>
+</A>
+
+
+
+<A NAME="1021584">
+アプリケーションã«ã‚ˆã‚‹ä½¿ç”¨ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„るユニコード文字列。例:<P></A>
+<A NAME="1021587">
+<PRE> ntUserParms: Temp date is today
+</PRE>
+</A>
+
+<A NAME="1038709">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1016157">
+<A NAME="ntUserPasswordExpired">
+<B>ntUserPasswordExpired</B>
+</a></a>
+<P>
+
+
+<A NAME="1259827">
+ユーザーã®NTパスワードãŒå¤±åŠ¹ã—ã¦ã„ã‚‹ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚パスワードãŒå¤±åŠ¹ã—ã¦ã„ãªã„å ´åˆã¯å€¤ã¯ã‚¼ãƒ­ã§ã€å¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯éžã‚¼ãƒ­ã§ã™ã€‚例:<P></A>
+<PRE><A NAME="1259828">
+ ntUserPasswordExpired: AAAAAA==
+</A>
+</PRE>
+<A NAME="1259829">
+OID: <code>2.16.840.1.113730.3.1.68</code><P></A>
+
+<A NAME="1038833">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1016246">&nbsp;
+</A>
+<A NAME="ntUserPrimaryGroupId">
+<H3> ntUserPrimaryGroupId</H3>
+</A>
+
+
+
+<A NAME="1016259">
+ユーザーã«ã¤ã„ã¦ã®Primary Global Groupã®ç›¸å¯¾ID (RID)を示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1016262">
+<PRE> ntUserPrimaryGroupId: AQJAAA==
+</PRE>
+</A>
+
+<A NAME="1038836">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1017849">&nbsp;
+</A>
+<A NAME="ntUserPriv">
+<H3> ntUserPriv</H3>
+</A>
+
+
+
+<A NAME="1017863">
+Windowsãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã«ãŠã‘るユーザーã®ç‰¹æ¨©ãƒ¬ãƒ™ãƒ«ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1017866">
+<PRE> ntUserPriv: AgAAAA==
+</PRE>
+</A>
+
+<A NAME="1038839">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1016298">&nbsp;
+</A>
+<A NAME="ntUserProfile">
+<H3> ntUserProfile</H3>
+</A>
+
+
+
+<A NAME="1016315">
+ユーザーã®ãƒ—ロフィールã¸ã®ãƒ‘スを示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1016326">
+<PRE> ntUserProfile: c:\u\d78\jsmith\profile.txt
+</PRE>
+</A>
+
+<A NAME="1038712">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1016395">
+<A NAME="ntUserScriptPath">
+<B>ntUserScriptPath</B>
+</a></a>
+<P>
+
+
+<A NAME="1016433">
+ユーザーã®ãƒ­ã‚°ã‚¤ãƒ³ スクリプトã¸ã®ãƒ‘スを示ã™ASCII文字列。例:<P></A>
+<A NAME="1016470">
+<PRE> ntUserScriptPath: c:\u\d78\jsmith\lscript.bat
+</PRE>
+</A>
+
+<A NAME="1038715">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1016531">
+<A NAME="ntUserUniqueId">
+<B>ntUserUniqueId</B>
+</a></a>
+<P>
+
+
+<A NAME="1016564">
+ユーザーã®ç›¸å¯¾ID (RID)を示ã—ã¾ã™ã€‚RIDã¯ã€ãƒ‰ãƒ¡ã‚¤ãƒ³å†…ã®SAMã«å¯¾ã—ユーザーã®èº«åˆ†ã‚’証明ã™ã‚‹ã‚‚ã®ã§ã™ã€‚例:<P></A>
+<A NAME="1016605">
+<PRE> ntUserUniqueId: 6AMAAA==
+</PRE>
+</A>
+
+<A NAME="1038842">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1016632">&nbsp;
+</A>
+<A NAME="ntUserUnitsPerWeek">
+<H3> ntUserUnitsPerWeek</H3>
+</A>
+
+
+
+<A NAME="1016672">
+ntUserLogonHoursã®é•·ã•ã‚’計算ã™ã‚‹ãŸã‚ã«ã€é€±ã‚’å‡ç­‰ã®æ™‚é–“å˜ä½ã«åˆ†å‰²ã™ã‚‹æ•°ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1016675">
+<PRE> ntUserUnitsPerWeek: qAAAAA==
+</PRE>
+</A>
+
+<A NAME="1038845">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1016696">&nbsp;
+</A>
+<A NAME="ntUserusrComment">
+<H3> ntUserusrComment</H3>
+</A>
+
+
+
+<A NAME="1016715">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã«é–¢ã™ã‚‹è¨˜è¿°ã¾ãŸã¯æ³¨é‡ˆã‚’示ã™ASCII文字列。例:<P></A>
+<A NAME="1016716">
+<PRE> ntUserComment: Quality control inspector for the ME2873 <br>
+ product line
+</PRE>
+</A>
+
+<A NAME="1038718">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1016728">
+<A NAME="ntUserWorkstations">
+<B>ntUserWorkstations</B>
+</a></a>
+<P>
+
+
+<A NAME="1016750">
+ユーザーãŒãƒ­ã‚°ã‚ªãƒ³ã™ã‚‹ã®ã«ä½¿ç”¨ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒ†ãƒ¼ã‚·ãƒ§ãƒ³åを示ã™ASCII文字列。カンマã§åŒºåˆ‡ã£ã¦ã€æœ€é«˜8å°ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒ†ãƒ¼ã‚·ãƒ§ãƒ³ã‚’指定ã§ãã¾ã™ã€‚ä»»æ„ã®ãƒ¯ãƒ¼ã‚¯ã‚¹ãƒ†ãƒ¼ã‚·ãƒ§ãƒ³ã‹ã‚‰ãƒ­ã‚°ã‚ªãƒ³ã™ã‚‹å ´åˆã¯ãƒŒãƒ«ã‚’使用ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1016869">
+<PRE> ntUserWorkstations: firefly
+</PRE>
+</A>
+
+<A NAME="1038721">
+構文: <a href="attribut.htm#1004702">cis </a><P></A>
+<P>
+<A NAME="1281611">
+<A NAME="o">
+<B>o</B>
+</a></a>
+<P>
+
+
+<A NAME="1281612">
+組織åを指定ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1281613">
+ organizationName: Airius, Inc.
+</A>
+</PRE>
+<A NAME="1281614">
+ã¾ãŸã¯<P></A>
+<PRE><A NAME="1281615">
+ o: Airius, Inc
+</A>
+</PRE>
+<A NAME="1281616">
+ç•¥å·: o<P></A>
+
+<A NAME="1281617">
+OID: <code>2.5.4.10</code><P></A>
+
+<A NAME="1281619">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1229677">
+<A NAME="objectClass">
+<B>objectClass</B>
+</a></a>
+<P>
+
+
+<A NAME="1229678">
+ディレクトリサーãƒãƒ¼ã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1229681">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1242815">&nbsp;
+</A>
+<A NAME="objectClasses">
+<H3> objectClasses</H3>
+</A>
+
+
+
+<A NAME="1242816">
+予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1242819">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202192">&nbsp;
+</A>
+<A NAME="obsoletedByDocument">
+<H3> obsoletedByDocument</H3>
+</A>
+
+
+
+<A NAME="1202193">
+ドキュメント エントリを使用ã—ãªããªã£ãŸãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®è­˜åˆ¥åãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1202196">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1202199">&nbsp;
+</A>
+<A NAME="obsoletesDocument">
+<H3> obsoletesDocument</H3>
+</A>
+
+
+
+<A NAME="1217320">
+ドキュメント エントリã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œãªããªã£ãŸãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®è­˜åˆ¥åãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1202203">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1202208">&nbsp;
+</A>
+<A NAME="organizationalStatus">
+<H3> organizationalStatus</H3>
+</A>
+
+
+
+<A NAME="1214388">
+組織ã«ãŠã„ã¦ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒé »ç¹ã«å‚ç…§ã•ã‚Œã‚‹ã‚«ãƒ†ã‚´ãƒªã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1214389">
+<PRE> organizationalStatus: researcher
+</PRE>
+</A>
+
+<A NAME="1240989">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202220">&nbsp;
+</A>
+<A NAME="otherMailbox">
+<H3> otherMailbox</H3>
+</A>
+
+
+
+<A NAME="1214414">
+X.400ã¨rfc822以外ã®é›»å­ãƒ¡ãƒ¼ãƒ«ãƒœãƒƒã‚¯ã‚¹ タイプã®å€¤ã‚’示ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1202221">
+. 例:<P></A>
+<A NAME="1202222">
+<PRE> otherMailbox: internet $ jdoe@airius.com
+</PRE>
+</A>
+
+<A NAME="1202224">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1241174">&nbsp;
+</A>
+<A NAME="ou">
+<H3> ou</H3>
+</A>
+
+
+
+<A NAME="1241175">
+組織å˜ä½åを示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1241176">
+<PRE> organizationUnitName: Marketing
+</PRE>
+</A>
+
+<A NAME="1241177">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1241178">
+<PRE> ou: Marketing
+</PRE>
+</A>
+
+<A NAME="1241180">
+<a href="attribut.htm#">ç•¥å·</a>: ou<P></A>
+
+<A NAME="1241182">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1005719">&nbsp;
+</A>
+<A NAME="owner">
+<H3> owner</H3>
+</A>
+
+
+
+<A NAME="1005732">
+エントリã®è²¬ä»»è€…ã®è­˜åˆ¥å (DN - distinguished name)を示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1005743">
+<PRE> owner: <I>cn=John Smith, o=Netscape Communications Corp., c=US
+</I></PRE>
+</A>
+
+<A NAME="1005754">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1003070">&nbsp;
+</A>
+<A NAME="pager">
+<H3> pager</H3>
+</A>
+
+
+
+<A NAME="1003071">
+エントリã®ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«ç•ªå·ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1003777">
+<PRE> pagerTelephoneNumber: 415-555-6789
+</PRE>
+</A>
+
+<A NAME="1011248">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1011258">
+<PRE> pager: 415-555-6789
+</PRE>
+</A>
+
+<A NAME="1003795">
+<a href="attribut.htm#">ç•¥å·</a>: pager<P></A>
+
+<A NAME="1011303">
+構文: <a href="attribut.htm#1004703">tel</a><P></A>
+
+
+<A NAME="1157269">&nbsp;
+</A>
+<A NAME="passwordChange">
+<H3> passwordChange</H3>
+</A>
+
+
+
+<A NAME="1157270">
+ユーザーã«ã‚ˆã‚‹ãƒ‘スワードã®å¤‰æ›´ãŒã€å¿…é ˆã€å¯èƒ½ã€ä¸å¯èƒ½ã®ã„ãšã‚Œã§ã‚ã‚‹ã‹å®šç¾©ã—ã¾ã™ã€‚有効値ã¯ã€<code>must</code>ã€<code>may</code>ã€ã¾ãŸã¯<code>no</code>ã§ã™ã€‚<code>must</code>ã®å€¤ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒæŒ‡å®šé–“éš”ã§ãƒ‘スワードを変更ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã“ã¨ã‚’示æ„味ã—ã¾ã™ã€‚<code>may</code>ã®å€¤ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒãƒ‘スワードを変更ã§ãã‚‹ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚<code>no</code>ã®å€¤ã¯ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒãƒ‘スワードを変更ã§ããªã„ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1157271">
+<PRE> passwordChange: <code>no
+</code></PRE>
+</A>
+
+<A NAME="1157273">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1157285">&nbsp;
+</A>
+<A NAME="passwordCheck構文">
+<H3>passwordCheck構文</H3>
+</A>
+
+
+
+<A NAME="1157402">
+パスワードã®æ§‹æ–‡ãƒã‚§ãƒƒã‚¯ãŒã‚ªãƒ³ã€ã‚ªãƒ•ã®ã„ãšã‚Œã§ã‚ã‚‹ã‹å®šç¾©ã—ã¾ã™ã€‚許容値ã¯<code>1</code>ãŠã‚ˆã³<code>0</code>ã§ã€<code>1</code>ã¯æ§‹æ–‡ãƒã‚§ãƒƒã‚¯ãŒã‚ªãƒ³ã€<code>0</code>ã¯æ§‹æ–‡ãƒã‚§ãƒƒã‚¯ãŒã‚ªãƒ•ã§ã‚ã‚‹ã®ã‚’æ„味ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1157287">
+<PRE> passwordCheck構文: 0
+</PRE>
+</A>
+
+<A NAME="1157289">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1155167">&nbsp;
+</A>
+<A NAME="passwordExp">
+<H3>passwordExp</H3>
+</A>
+
+
+
+<A NAME="1155169">
+ユーザ パスワードãŒæœŸé™åˆ‡ã‚Œã«ãªã‚‹ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚許容値ã¯<code>1</code>ãŠã‚ˆã³<code>0</code>ã§ã€<code>1</code>ã¯ãƒ‘スワードãŒæœŸé™åˆ‡ã‚Œã«ãªã‚‹ã“ã¨ã€<code>0</code>ã¯ãƒ‘スワードãŒæœŸé™åˆ‡ã‚Œã—ãªã„ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1155249">
+<PRE> passwordExp: 0
+</PRE>
+</A>
+
+<A NAME="1155171">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1246150">&nbsp;
+</A>
+<A NAME="passwordExpWarned">
+<H3>passwordExpWarned</H3>
+</A>
+
+
+
+<A NAME="1246152">
+ユーザーã«é€ä¿¡ã•ã‚Œã‚‹ãƒ‘スワード失効警告を追跡ã™ã‚‹ãŸã‚ã«ã€Directory ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚許容値ã¯<code>1</code>ã¨<code>0</code>ã§ã€<code>1</code>ã¯è­¦å‘ŠãŒãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€ä¿¡ã•ã‚Œã‚‹ã“ã¨ã€ <code>0</code>ã¯è­¦å‘ŠãŒãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€ä¿¡ã•ã‚Œãªã„ã“ã¨æ„味ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1246153">
+<PRE> passwordExpWarned: 0
+</PRE>
+</A>
+
+<A NAME="1246155">
+構文: <a href="attribut.htm#1004702">cis operational</a><P></A>
+
+<A NAME="1246156">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1103904">&nbsp;
+</A>
+<A NAME="passwordExpirationTime">
+<H3>passwordExpirationTime</H3>
+</A>
+
+
+
+<A NAME="1166092">
+ユーザã®ãƒ‘スワードãŒæœŸé™åˆ‡ã‚Œã«ãªã‚‹ã¾ã§ã®æ™‚間を秒数ã§å®šç¾©ã—ã¾ã™ã€‚<P></A>
+<A NAME="1166093">
+<PRE> passwordExpirationTime: 8640000
+</PRE>
+</A>
+
+<A NAME="1104141">
+構文: <a href="attribut.htm#1004702">cis operational</a><P></A>
+
+<A NAME="1166110">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+<P>
+<A NAME="1293088">
+<A NAME="passwordExpWarned">
+<B>passwordExpWarned</B>
+</a></a>
+<P>
+
+
+<A NAME="1293090">
+Directory ServerãŒä½¿ç”¨ã—ã¦ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€ä¿¡ã•ã‚Œã‚‹ãƒ‘スワード失効警告を追跡ã—ã¾ã™ã€‚許容値ã¯<code>1</code>ãŠã‚ˆã³<code>0</code>ã§ã€<code>1</code>ã¯è­¦å‘ŠãŒãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€ä¿¡ã•ã‚ŒãŸã“ã¨ã€<code>0</code>ã¯è­¦å‘ŠãŒãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€ä¿¡ã•ã‚Œã¦ã„ãªã„ã“ã¨æ„味ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1293091">
+ passwordExpWarned: 0
+</A>
+</PRE>
+<A NAME="1293092">
+OID: <code>2.16.840.1.113730.3.1.92</code><P></A>
+
+<A NAME="1293095">
+構文: <a href="attribut.htm#1004702">cis </a><a href="attribut.htm#1251525">operational</a><P></A>
+<P>
+
+<A NAME="1104144">
+<A NAME="passwordHistory">
+<B>passwordHistory</B>
+</a></a>
+<P>
+
+
+<A NAME="1155016">
+ユーザ パスワードã®å±¥æ­´ã‚’å«ã¿ã¾ã™ã€‚例:<P></A>
+
+<A NAME="1104110">
+構文: <a href="attribut.htm#1004700">bin operational</a><P></A>
+
+<A NAME="1166119">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+<P>
+<A NAME="1104470">
+<A NAME="passwordInHistory">
+<B>passwordInHistory</B>
+</a></a>
+<P>
+
+
+<A NAME="1104471">
+パスワード履歴ãŒä¿å­˜ã•ã‚Œã¦ã„ã‚‹å ´åˆã€ã“ã®å±žæ€§å€¤ã¯å±¥æ­´ãƒªã‚¹ãƒˆã«ä¿å­˜ã•ã‚Œã‚‹ã‚¨ãƒ³ãƒˆãƒªã®æ•°ã‚’定義ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1157501">
+ passwordInHistory: 6
+</A>
+</PRE>
+<A NAME="1260030">
+OID: <code>2.16.840.1.113730.3.1.101</code><P></A>
+
+<A NAME="1104473">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166153">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1156663">
+<A NAME="passwordKeepHistory">
+<B>passwordKeepHistory</B>
+</a></a>
+<P>
+
+
+<A NAME="1156665">
+ユーザ パスワードã®å±¥æ­´ã‚’ä¿å­˜ã™ã‚‹ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚許容値ã¯<code>1</code>ãŠã‚ˆã³<code>0</code>ã§ã€<code>1</code>ã¯å±¥æ­´ã‚’ä¿å­˜ã™ã‚‹ã“ã¨ã€<code>0</code>ã¯å±¥æ­´ã‚’ä¿å­˜ã—ãªã„ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1156666">
+<PRE> passwordKeepHistory: 0
+</PRE>
+</A>
+
+<A NAME="1156668">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166196">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1156671">&nbsp;
+</A>
+<A NAME="passwordLockout">
+<H3>passwordLockout</H3>
+</A>
+
+
+
+<A NAME="1156672">
+ディレクトリã¸ã®ãƒã‚¤ãƒ³ãƒ‰å¤±æ•—ãŒé€£ç¶šã—ãŸå ´åˆã€ãƒ¦ãƒ¼ã‚¶ã‚’ç· ã‚出ã™ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚許容値ã¯<code>1</code>ãŠã‚ˆã³<code>0</code>ã§ã€1ã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒç· ã‚出ã•ã‚Œã‚‹ã“ã¨ã€0ã¯ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒç· ã‚出ã•ã‚Œãªã„ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1156673">
+<PRE> passwordLockout: 0
+</PRE>
+</A>
+
+<A NAME="1156675">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166205">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1104188">&nbsp;
+</A>
+<A NAME="passwordLockoutDuration">
+<H3> passwordLockoutDuration</H3>
+</A>
+
+
+
+<A NAME="1104189">
+ディレクトリã‹ã‚‰ãƒ¦ãƒ¼ã‚¶ãƒ¼ã‚’ç· ã‚出ã™æ™‚間を秒å˜ä½ã§å®šç¾©ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1155990">
+<PRE> passwordLockoutDuration: 600
+</PRE>
+</A>
+
+<A NAME="1104190">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166333">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1166286">&nbsp;
+</A>
+<A NAME="passwordMaxAge">
+<H3> passwordMaxAge</H3>
+</A>
+
+
+
+<A NAME="1166287">
+パスワード失効ã¾ã§ã®ãƒ‘スワードã®ä½¿ç”¨æ™‚間を秒å˜ä½ã§å®šç¾©ã—ã¾ã™ã€‚<P></A>
+<A NAME="1166288">
+<PRE> passwordMaxAge: 8640000
+</PRE>
+</A>
+
+<A NAME="1104336">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166368">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1104715">&nbsp;
+</A>
+<A NAME="passwordMaxFailure">
+<H3>passwordMaxFailure</H3>
+</A>
+
+
+
+<A NAME="1104716">
+ディレクトリã¸ã®ãƒã‚¤ãƒ³ãƒ‰å¤±æ•—を指定回数繰り返ã—ãŸã‚‰ã€ãƒ¦ãƒ¼ã‚¶ã‚’締出ã™ã‚ˆã†ã‚µãƒ¼ãƒã«æŒ‡ç¤ºã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1155781">
+<PRE> passwordMaxFailure: 3
+</PRE>
+</A>
+
+<A NAME="1104718">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166400">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1104413">&nbsp;
+</A>
+<A NAME="passwordMinLength">
+<H3>passwordMinLength</H3>
+</A>
+
+
+
+<A NAME="1104414">
+ユーザ パスワードã«å¿…è¦ãªæœ€ä½Žã®æ–‡å­—数を定義ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1156233">
+<PRE> passwordMinLength: 6
+</PRE>
+</A>
+
+<A NAME="1104416">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166409">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1104754">&nbsp;
+</A>
+<A NAME="passwordResetDuration">
+<H3> passwordResetDuration</H3>
+</A>
+
+
+
+<A NAME="1157530">
+ユーザーã®ç· å‡ºã—ã‹ã‚‰ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ‘スワードå†å…¥åŠ›å›žæ•°ã‚’ゼロã«è¨­å®šã—ç›´ã™ã¾ã§ã®æ™‚間を秒å˜ä½ã§å®šç¾©ã—ã¾ã™ã€‚<P></A>
+<A NAME="1157650">
+<PRE> passwordResetDuration: 600
+</PRE>
+</A>
+
+<A NAME="1104757">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166437">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1103999">&nbsp;
+</A>
+<A NAME="passwordRetryCount">
+<H3>passwordRetryCount</H3>
+</A>
+
+
+
+<A NAME="1104000">
+ユーザãŒé–“é•ã£ãŸãƒ‘スワードを使ã£ã¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®ãƒã‚¤ãƒ³ãƒ‰ã‚’試ã¿ãŸå›žæ•°ã‚’å«ã¿ã¾ã™ã€‚<P></A>
+<A NAME="1154824">
+<PRE> passwordRetryCount: 3
+</PRE>
+</A>
+
+<A NAME="1104001">
+構文: <a href="attribut.htm#1004702">cis operational</a><P></A>
+
+<A NAME="1166462">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1156969">&nbsp;
+</A>
+<A NAME="passwordUnlock">
+<H3>passwordUnlock</H3>
+</A>
+
+
+
+<A NAME="1157793">
+ディレクトリã¸ã®ãƒã‚¤ãƒ³ãƒ‰ã‚’指定回数失敗ã—ãŸå ´åˆã€ãƒ¦ãƒ¼ã‚¶ã‚’永久ã«ç· ã‚出ã™ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚許容値ã¯<code>1</code>ãŠã‚ˆã³<code>0</code>ã§ã€<code>1</code>ã¯ãƒ¦ãƒ¼ã‚¶ã‚’永久ã«ç· ã‚出ã•ãªã„ã“ã¨ã‚’ã€<code>0</code>ã¯æ°¸ä¹…ã«ç· ã‚出ã™ã“ã¨ã‚’æ„味ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1157794">
+<PRE> passwordUnlock: 0
+</PRE>
+</A>
+
+<A NAME="1156973">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166485">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1104598">&nbsp;
+</A>
+<A NAME="passwordWarning">
+<H3>passwordWarning</H3>
+</A>
+
+
+
+<A NAME="1155341">
+é–“ã‚‚ãªãパスワードãŒå¤±åŠ¹ã™ã‚‹ã®ã‚’ã€è­¦å‘Šã™ã‚‹ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã®é€ä¿¡æ™‚期を秒数ã§å®šç¾©ã—ã¾ã™ã€‚次ã®ä¾‹ã§ã¯ã€è­¦å‘Šãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒãƒ‘スワード失効ã®1æ—¥å‰ã«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«é€ä¿¡ã•ã‚Œã¾ã™ã€‚<P></A>
+<A NAME="1155343">
+<PRE> passwordWarning: 86400
+</PRE>
+</A>
+
+<A NAME="1155421">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1166523">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1202229">&nbsp;
+</A>
+<A NAME="personalSignature">
+<H3> personalSignature</H3>
+</A>
+
+
+
+<A NAME="1202230">
+エントリã®ãƒã‚¤ãƒŠãƒªå½¢å¼ã®ç½²åファイル。<P></A>
+
+<A NAME="1202233">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1202238">&nbsp;
+</A>
+<A NAME="personalTitle">
+<H3> personalTitle</H3>
+</A>
+
+
+
+<A NAME="1214489">
+ユーザーã®å€‹äººçš„ãªè‚©æ›¸ãを示ã—ã¾ã™ã€‚個人的ãªè‚©æ›¸ãã®ä¾‹ã¯ã€Msã€Drã€Profã€Revãªã©ã§ã™ã€‚<P></A>
+<A NAME="1202240">
+<PRE> personalTitle: Mr
+</PRE>
+</A>
+
+<A NAME="1202242">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202247">&nbsp;
+</A>
+<A NAME="photo">
+<H3> photo</H3>
+</A>
+
+
+
+<A NAME="1202248">
+エントリã®å†™çœŸãŒãƒã‚¤ãƒŠãƒªå½¢å¼ã§å«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+
+<A NAME="1202251">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1003072">&nbsp;
+</A>
+<A NAME="physicalDeliveryOfficeName">
+<H3> physicalDeliveryOfficeName</H3>
+</A>
+
+
+
+<A NAME="1003073">
+物ç†çš„ãªé…é€ã‚ªãƒ•ã‚£ã‚¹ãŒæ‰€åœ¨ã™ã‚‹å¸‚町æ‘ã®åå‰ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1003804">
+<PRE> physicalDeliveryOfficeName: Santa Clara
+</PRE>
+</A>
+
+<A NAME="1107471">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1246531">&nbsp;
+</A>
+<A NAME="pipcompassservers">
+<H3>pipcompassservers</H3>
+</A>
+
+
+
+<A NAME="1246532">
+未定義。<P></A>
+
+<A NAME="1271255">
+OID: <code>2.16.840.1.113730.3.1.138</code><P></A>
+
+<A NAME="1107499">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236180">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1111357">&nbsp;
+</A>
+<A NAME="pipformat">
+<H3>pipformat</H3>
+</A>
+
+
+
+<A NAME="1119006">
+Compass ServerãŒä½¿ç”¨ã™ã‚‹å±žæ€§ã§ã€ãƒ¦ãƒ¼ã‚¶ã«é€ä¿¡ã™ã‚‹ç„¡æ–™ã®ãƒ†ã‚­ã‚¹ãƒˆæ¤œç´¢ãƒ—ロフィールã®æ›´æ–°ãƒ•ã‚©ãƒ¼ãƒžãƒƒãƒˆã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1271403">
+OID: <code>2.16.840.1.113730.3.1.144</code><P></A>
+
+<A NAME="1111360">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1246338">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1246341">&nbsp;
+</A>
+<A NAME="pipfrequency">
+<H3>pipfrequency</H3>
+</A>
+
+
+
+<A NAME="1246342">
+Compass ServerãŒä½¿ç”¨ã™ã‚‹å±žæ€§ã§ã€My Compassニュースレターã®å—信頻度を記述ã—ã¾ã™ã€‚<P></A>
+
+
+<A NAME="1271346">
+OID: <code>2.16.840.1.113730.3.1.142</code><P></A>
+
+<A NAME="1111364">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236223">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1113190">&nbsp;
+</A>
+<A NAME="pipgroup">
+<H3>pipgroup</H3>
+</A>
+
+
+<A NAME="1119538">
+未定義。<P></A>
+
+<A NAME="1271479">
+OID: <code>2.16.840.1.113730.3.1.158</code><P></A>
+
+<A NAME="1113191">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236260">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1111369">&nbsp;
+</A>
+<A NAME="piphour">
+<H3> piphour</H3>
+</A>
+
+
+
+<A NAME="1119581">
+ユーザーãŒç„¡æ–™ãƒ†ã‚­ã‚¹ãƒˆæ¤œç´¢ãƒ—ロフィール更新をå—ä¿¡ã™ã‚‹æ—¥ä¸­ã®æ™‚間帯を定義ã™ã‚‹ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271454">
+OID: <code>2.16.840.1.113730.3.1.145</code><P></A>
+
+<A NAME="1111370">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236306">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1237689">&nbsp;
+</A>
+<A NAME="pipidstcount">
+<H3>pipidstcount</H3>
+</A>
+
+
+
+<A NAME="1237690">
+Compass ServerãŒä½¿ç”¨ã™ã‚‹å±žæ€§ã§ã€ãƒ¦ãƒ¼ã‚¶ãƒ¼ãŒä½¿ç”¨ã™ã‚‹æœ€å¾Œã®ä¸€æ„ã®IDを定義ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1271485">
+OID: <code>2.16.840.1.113730.3.1.159</code><P></A>
+
+<A NAME="1113341">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236324">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1113479">&nbsp;
+</A>
+<A NAME="pipirlist">
+<H3> pipirlist</H3>
+</A>
+
+
+
+<A NAME="1119793">
+ユーザーãŒãƒ¢ãƒ‹ã‚¿ãƒ¼ã™ã‚‹ãƒ‰ãƒ¡ã‚¤ãƒ³ã¨ãƒ‹ãƒ¥ãƒ¼ã‚¹ã‚°ãƒ«ãƒ¼ãƒ—ã‚’å«ã‚€ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271508">
+OID: <code>2.16.840.1.113730.3.1.150</code><P></A>
+
+<A NAME="1113480">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237824">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1237828">&nbsp;
+</A>
+<A NAME="pipiroption">
+<H3> pipiroption</H3>
+</A>
+
+
+
+<A NAME="1237829">
+pipIrListã®ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªã‚’æ›´æ–°ã™ã‚‹ã‹ã€ã¾ãŸã¯æ›´æ–°ã‹ã‚‰é™¤å¤–ã™ã‚‹ã‹ã‚’定義ã™ã‚‹ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271566">
+OID: <code>2.16.840.1.113730.3.1.151</code><P></A>
+
+<A NAME="1113621">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236383">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1112574">&nbsp;
+</A>
+<A NAME="piplastcount">
+<H3>piplastcount</H3>
+</A>
+
+
+
+<A NAME="1237876">
+Compass ServerãŒä½¿ç”¨ã™ã‚‹å±žæ€§ã§ã€æœ€å¾Œã®æ›´æ–°æ™‚ã«ç™ºç”Ÿã—ãŸç…§åˆæ•°ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1271585">
+OID: <code>2.16.840.1.113730.3.1.153</code><P></A>
+
+<A NAME="1112575">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1246647">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1246650">&nbsp;
+</A>
+<A NAME="pipmaxhits">
+<H3> pipmaxhits</H3>
+</A>
+
+
+
+<A NAME="1246651">
+無料テキスト検索プロフィール更新ã”ã¨ã«æˆ»ã•ã‚Œã‚‹æœ€å¤§ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆæ•°ã‚’定義ã™ã‚‹ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271604">
+OID: <code>2.16.840.1.113730.3.1.146</code><P></A>
+
+<A NAME="1173472">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236422">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1111582">&nbsp;
+</A>
+<A NAME="pipmedium">
+<H3> pipmedium</H3>
+</A>
+
+
+
+<A NAME="1237949">
+無料テキスト検索プロフィール更新ã«é–¢ã™ã‚‹æƒ…報をユーザーã«é€ä¿¡ã™ã‚‹æ‰‹æ®µã‚’示ã™ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271368">
+OID: <code>2.16.840.1.113730.3.1.143</code><P></A>
+
+<A NAME="1111583">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236583">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1236460">&nbsp;
+</A>
+<A NAME="pipnotify">
+<H3>pipnotify</H3>
+</A>
+
+
+
+<A NAME="1119923">
+未定義。<P></A>
+
+<A NAME="1271613">
+OID: <code>2.16.840.1.113730.3.1.156</code><P></A>
+
+<A NAME="1236507">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236602">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1236511">&nbsp;
+</A>
+<A NAME="pipprivilege">
+<H3>pipprivilege</H3>
+</A>
+
+
+
+<A NAME="1236512">
+未定義。<P></A>
+
+<A NAME="1271668">
+OID: <code>2.16.840.1.113730.3.1.157</code><P></A>
+
+<A NAME="1112990">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236630">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1112443">&nbsp;
+</A>
+<A NAME="pippwp">
+<H3> pippwp</H3>
+</A>
+
+
+
+<A NAME="1238042">
+Personal Web Page (PWP)データベースã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271682">
+OID: <code>2.16.840.1.113730.3.1.152</code><P></A>
+
+<A NAME="1112444">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236643">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1118693">&nbsp;
+</A>
+<A NAME="pipreservedces1">
+<H3>pipreservedces1</H3>
+</A>
+
+
+
+<A NAME="1120046">
+Netscape Compass Serverã§å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚ŒãŸå±žæ€§ã§ã™ã€‚<P></A>
+
+<A NAME="1271719">
+OID: <code>2.16.840.1.113730.3.1.188</code><P></A>
+
+<A NAME="1118694">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+<A NAME="1236680">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1118699">&nbsp;
+</A>
+<A NAME="pipreservedces2">
+<H3>pipreservedces2</H3>
+</A>
+
+
+
+<A NAME="1238136">
+Netscape Compass Serverã§å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚ŒãŸå±žæ€§ã§ã™ã€‚<P></A>
+
+<A NAME="1271725">
+OID: <code>2.16.840.1.113730.3.1.189</code><P></A>
+
+<A NAME="1118700">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+<A NAME="1236693">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1118705">&nbsp;
+</A>
+<A NAME="pipreservedces3">
+<H3>pipreservedces3</H3>
+</A>
+
+
+
+<A NAME="1238138">
+Netscape Compass Serverã§å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚ŒãŸå±žæ€§ã§ã™ã€‚<P></A>
+
+<A NAME="1271783">
+OID: <code>2.16.840.1.113730.3.1.190</code><P></A>
+
+<A NAME="1118706">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+<A NAME="1236718">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1118350">&nbsp;
+</A>
+<A NAME="pipreservedcis1">
+<H3>pipreservedcis1</H3>
+</A>
+
+
+
+<A NAME="1238140">
+Netscape Compass Serverã§å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚ŒãŸå±žæ€§ã§ã™ã€‚<P></A>
+
+<A NAME="1271796">
+OID: <code>2.16.840.1.113730.3.1.182</code><P></A>
+
+<A NAME="1118351">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236762">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1118356">&nbsp;
+</A>
+<A NAME="pipreservedcis2">
+<H3>pipreservedcis2</H3>
+</A>
+
+
+
+<A NAME="1238144">
+Netscape Compass Serverã§å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚ŒãŸå±žæ€§ã§ã™ã€‚<P></A>
+
+<A NAME="1271840">
+OID: <code>2.16.840.1.113730.3.1.183</code><P></A>
+
+<A NAME="1118357">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236799">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1118362">&nbsp;
+</A>
+<A NAME="pipreservedcis3">
+<H3>pipreservedcis3</H3>
+</A>
+
+
+
+<A NAME="1238146">
+Netscape Compass Serverã§å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚ŒãŸå±žæ€§ã§ã™ã€‚<P></A>
+
+<A NAME="1271850">
+OID: <code>2.16.840.1.113730.3.1.184</code><P></A>
+
+<A NAME="1118363">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236816">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1118368">&nbsp;
+</A>
+<A NAME="pipreservedcis4">
+<H3>pipreservedcis4</H3>
+</A>
+
+
+
+<A NAME="1238148">
+Netscape Compass Serverã§å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚ŒãŸå±žæ€§ã§ã™ã€‚<P></A>
+
+<A NAME="1271856">
+OID: <code>2.16.840.1.113730.3.1.185</code><P></A>
+
+<A NAME="1118369">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236851">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1118374">&nbsp;
+</A>
+<A NAME="pipreservedcis5">
+<H3>pipreservedcis5</H3>
+</A>
+
+
+
+<A NAME="1238150">
+Netscape Compass Serverã§å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚ŒãŸå±žæ€§ã§ã™ã€‚<P></A>
+
+<A NAME="1271872">
+OID: <code>2.16.840.1.113730.3.1.186</code><P></A>
+
+<A NAME="1118375">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236870">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1118380">&nbsp;
+</A>
+<A NAME="pipreservedcis6">
+<H3>pipreservedcis6</H3>
+</A>
+
+
+
+<A NAME="1238152">
+Netscape Compass Serverã§å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚ŒãŸå±žæ€§ã§ã™ã€‚<P></A>
+
+<A NAME="1271882">
+OID: <code>2.16.840.1.113730.3.1.187</code><P></A>
+
+<A NAME="1118381">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236893">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1111729">&nbsp;
+</A>
+<A NAME="pipresultset">
+<H3> pipresultset</H3>
+</A>
+
+
+
+<A NAME="1238541">
+ユーザーãŒæ›´æ–°ã®å—信を希望ã™ã‚‹å±žæ€§ã®ãƒªã‚¹ãƒˆã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271899">
+OID: <code>2.16.840.1.113730.3.1.147</code><P></A>
+
+<A NAME="1111730">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236920">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1111947">&nbsp;
+</A>
+<A NAME="pipsortorder">
+<H3> pipsortorder</H3>
+</A>
+
+
+
+<A NAME="1238667">
+無料テキスト検索プロフィール更新ã®æ¦‚è¦ãƒ¬ãƒãƒ¼ãƒˆã«ãŠã‘る情報ã®ä¸¦ã¹æ›¿ãˆé †åºã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271955">
+OID: <code>2.16.840.1.113730.3.1.148</code><P></A>
+
+<A NAME="1111948">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236950">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1114647">&nbsp;
+</A>
+<A NAME="pipstatus">
+<H3> pipstatus</H3>
+</A>
+
+
+
+<A NAME="1238753">
+Personal Interest Profile (PIP)を使用å¯èƒ½ã€ä½¿ç”¨ç¦æ­¢ã®ã„ãšã‚Œã«ã™ã‚‹ã‹ã‚’定義ã™ã‚‹ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271286">
+OID: <code>2.16.840.1.113730.3.1.140</code><P></A>
+
+<A NAME="1114648">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1236989">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1116402">&nbsp;
+</A>
+<A NAME="pipstcategory">
+<H3> pipstcategory</H3>
+</A>
+
+
+
+<A NAME="1238824">
+ユーザーãŒé–¢å¿ƒã‚’æŒã¤ã‚«ãƒ†ã‚´ãƒªã¾ãŸã¯æ¤œç´¢æ–‡å­—列をå«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271969">
+OID: <code>2.16.840.1.113730.3.1.171</code><P></A>
+
+<A NAME="1116403">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237014">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1116837">&nbsp;
+</A>
+<A NAME="pipstformat">
+<H3> pipstformat</H3>
+</A>
+
+
+
+<A NAME="1238895">
+ユーザーã«é€ä¿¡ã•ã‚Œã‚‹ã‚«ãƒ†ã‚´ãƒªæ¤œç´¢ãƒ—ロフィール更新形å¼ã‚’示ã™ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272000">
+OID: <code>2.16.840.1.113730.3.1.174</code><P></A>
+
+<A NAME="1116838">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237031">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1116521">&nbsp;
+</A>
+<A NAME="pipstfrequency">
+<H3>pipstfrequency</H3>
+</A>
+
+
+
+<A NAME="1120346">
+Compass ServerãŒä½¿ç”¨ã™ã‚‹å±žæ€§ã§ã€ãƒ¦ãƒ¼ã‚¶ãŒæ›´æ–°è­¦å‘Šã‚’å—ä¿¡ã™ã‚‹é »åº¦ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1272198">
+OID: <code>2.16.840.1.113730.3.1.172</code><P></A>
+
+<A NAME="1116522">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237041">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1116707">&nbsp;
+</A>
+<A NAME="pipsthour">
+<H3> pipsthour</H3>
+</A>
+
+
+
+<A NAME="1120383">
+ユーザーãŒç„¡æ–™ã‚«ãƒ†ã‚´ãƒª プロフィール更新をå—ä¿¡ã™ã‚‹æ—¥ä¸­ã®æ™‚間帯を定義ã™ã‚‹ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272250">
+OID: <code>2.16.840.1.113730.3.1.175</code><P></A>
+
+<A NAME="1116708">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237070">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1115462">&nbsp;
+</A>
+<A NAME="pipstid">
+<H3> pipstid</H3>
+</A>
+
+
+
+<A NAME="1120405">
+Personal Interest Profile (PIP)内ã®æ¤œç´¢ãƒˆãƒ”ックã®ä¸€æ„ã®IDã‚’å«ã‚ã‚‹ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272264">
+OID: <code>2.16.840.1.113730.3.1.160</code><P></A>
+
+<A NAME="1115463">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237108">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1115769">&nbsp;
+</A>
+<A NAME="pipstinterest">
+<H3> pipstinterest</H3>
+</A>
+
+
+
+<A NAME="1120445">
+Personal Interest Profile (PIP)内ã®æ¤œç´¢ãƒˆãƒ”ックã®å€‹ã€…ã®ãƒˆãƒ”ックã®é‡è¦æ€§ã‚’ユーザーã«ç¤ºã™ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272273">
+OID: <code>2.16.840.1.113730.3.1.164</code><P></A>
+
+<A NAME="1115770">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237118">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1117562">&nbsp;
+</A>
+<A NAME="pipstirlist">
+<H3> pipstirlist</H3>
+</A>
+
+
+
+<A NAME="1120460">
+ユーザーãŒãƒ¢ãƒ‹ã‚¿ãƒ¼ã™ã‚‹ãƒ‰ãƒ¡ã‚¤ãƒ³ã¨ãƒ‹ãƒ¥ãƒ¼ã‚¹ã‚°ãƒ«ãƒ¼ãƒ—ã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272285">
+OID: <code>2.16.840.1.113730.3.1.180</code><P></A>
+
+<A NAME="1117563">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237149">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1117790">&nbsp;
+</A>
+<A NAME="pipstiroption">
+<H3> pipstiroption</H3>
+</A>
+
+
+
+<A NAME="1120493">
+pipStIrListã®ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªã‚’æ›´æ–°ã™ã‚‹ã‹ã€ã¾ãŸã¯æ›´æ–°ã‹ã‚‰é™¤å¤–ã™ã‚‹ã‹ã‚’定義ã™ã‚‹ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272306">
+OID: <code>2.16.840.1.113730.3.1.181</code><P></A>
+
+<A NAME="1237168">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237182">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1237172">&nbsp;
+</A>
+<A NAME="pipstlastcount">
+<H3> pipstlastcount</H3>
+</A>
+
+
+
+<A NAME="1237173">
+Personal Interest Profile (PIP)ã®æœ€å¾Œã®æ›´æ–°æ™‚ã«ãŠã‘るカテゴリ一致数をå«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272312">
+OID: <code>2.16.840.1.113730.3.1.168</code><P></A>
+
+<A NAME="1116157">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237189">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1117134">&nbsp;
+</A>
+<A NAME="pipstmaxhits">
+<H3> pipstmaxhits</H3>
+</A>
+
+
+
+<A NAME="1120565">
+カテゴリ検索プロフィール更新ã”ã¨ã«æˆ»ã•ã‚Œã‚‹æœ€å¤§ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆæ•°ã‚’定義ã™ã‚‹ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272354">
+OID: <code>2.16.840.1.113730.3.1.176</code><P></A>
+
+<A NAME="1117135">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237205">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1117140">&nbsp;
+</A>
+<A NAME="pipstmedium">
+<H3> pipstmedium</H3>
+</A>
+
+
+
+<A NAME="1120568">
+カテゴリ検索プロフィール更新ã«é–¢ã™ã‚‹æƒ…報をé€ä¿¡ã™ã‚‹æ‰‹æ®µã‚’示ã™ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272360">
+OID: <code>2.16.840.1.113730.3.1.173</code><P></A>
+
+<A NAME="1117141">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237235">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1115468">&nbsp;
+</A>
+<A NAME="pipstname">
+<H3> pipstname</H3>
+</A>
+
+
+
+<A NAME="1120598">
+検索トピックを示ã™ãŸã‚ã«ãƒ¦ãƒ¼ã‚¶ãƒ¼ã«ã‚ˆã£ã¦ä½œæˆã•ã‚ŒãŸä»»æ„ã®åå‰ã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272404">
+OID: <code>2.16.840.1.113730.3.1.161</code><P></A>
+
+<A NAME="1115469">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237246">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1115898">&nbsp;
+</A>
+<A NAME="pipstprivacy">
+<H3> pipstprivacy</H3>
+</A>
+
+
+
+<A NAME="1120637">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®å•åˆã›ã‚’許å¯ã™ã‚‹ã‹å´ä¸‹ã™ã‚‹ã‹ã‚’定義ã™ã‚‹ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272410">
+OID: <code>2.16.840.1.113730.3.1.166</code><P></A>
+
+<A NAME="1115899">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237266">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1115474">&nbsp;
+</A>
+<A NAME="pipstquery">
+<H3>pipstquery</H3>
+</A>
+
+
+
+<A NAME="1120668">
+未定義。<P></A>
+
+<A NAME="1272438">
+OID: <code>2.16.840.1.113730.3.1.162</code><P></A>
+
+<A NAME="1115475">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237271">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1117321">&nbsp;
+</A>
+<A NAME="pipstresultset">
+<H3> pipstresultset</H3>
+</A>
+
+
+
+<A NAME="1120684">
+ユーザーãŒæ›´æ–°ã‚’å—ä¿¡ã™ã‚‹å±žæ€§ãƒªã‚¹ãƒˆã‚’å«ã‚€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§<P></A>
+
+<A NAME="1272625">
+OID: <code>2.16.840.1.113730.3.1.177</code><P></A>
+
+<A NAME="1117322">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237300">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1117327">&nbsp;
+</A>
+<A NAME="pipstsortorder">
+<H3> pipstsortorder</H3>
+</A>
+
+
+
+<A NAME="1120687">
+カテゴリ検索プロフィール更新ã®æ¦‚è¦ãƒ¬ãƒãƒ¼ãƒˆã«ãŠã‘る情報ã®ä¸¦ã¹æ›¿ãˆé †åºã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272444">
+OID: <code>2.16.840.1.113730.3.1.178</code><P></A>
+
+<A NAME="1117328">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237305">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1116027">&nbsp;
+</A>
+<A NAME="pipststatus">
+<H3> pipststatus</H3>
+</A>
+
+
+
+<A NAME="1120695">
+Personal Interest Profile (PIP)ã®çŠ¶æ…‹ã‚’定義ã—ã¾ã™ã€‚Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ 。<P></A>
+
+<A NAME="1272485">
+OID: <code>2.16.840.1.113730.3.1.167</code><P></A>
+
+<A NAME="1116028">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237322">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1115480">&nbsp;
+</A>
+<A NAME="pipsttaxonomy">
+<H3> pipsttaxonomy</H3>
+</A>
+
+
+
+<A NAME="1120736">
+分類法IDã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚ <P></A>
+
+<A NAME="1272491">
+OID: <code>2.16.840.1.113730.3.1.163</code><P></A>
+
+<A NAME="1115481">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237358">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1117445">&nbsp;
+</A>
+<A NAME="pipsttimestamp">
+<H3> pipsttimestamp</H3>
+</A>
+
+
+
+<A NAME="1120770">
+ユーザーã®ã‚«ãƒ†ã‚´ãƒªæ¤œç´¢ãƒ—ロフィールã®æœ€çµ‚更新日をå«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272500">
+OID: <code>2.16.840.1.113730.3.1.179</code><P></A>
+
+<A NAME="1117446">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237387">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1115516">&nbsp;
+</A>
+<A NAME="pipsttotalcount">
+<H3> pipsttotalcount</H3>
+</A>
+
+
+
+<A NAME="1120801">
+ç¾åœ¨ã¾ã§ã®ã‚«ãƒ†ã‚´ãƒªä¸€è‡´æ•°ã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272537">
+OID: <code>2.16.840.1.113730.3.1.169</code><P></A>
+
+<A NAME="1115517">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237396">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1115522">&nbsp;
+</A>
+<A NAME="pipsttotalrun">
+<H3> pipsttotalrun</H3>
+</A>
+
+
+
+<A NAME="1120812">
+ç¾åœ¨ã¾ã§ã«å®Ÿè¡Œã•ã‚ŒãŸã‚«ãƒ†ã‚´ãƒªæ¤œç´¢æ›´æ–°æ•°ã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272560">
+OID: <code>2.16.840.1.113730.3.1.170</code><P></A>
+
+<A NAME="1115523">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237423">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1116285">&nbsp;
+</A>
+<A NAME="pipsttype">
+<H3> pipsttype</H3>
+</A>
+
+
+
+<A NAME="1120825">
+ 検索ãŒã‚«ãƒ†ã‚´ãƒªæ¤œç´¢ã¾ãŸã¯ç„¡æ–™ãƒ†ã‚­ã‚¹ãƒˆæ¤œç´¢ã§ã‚ã‚‹ã‹ã‚’定義ã™ã‚‹ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272566">
+OID: <code>2.16.840.1.113730.3.1.165</code><P></A>
+
+<A NAME="1116286">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237434">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1117682">&nbsp;
+</A>
+<A NAME="piptimestamp">
+<H3> piptimestamp</H3>
+</A>
+
+
+
+<A NAME="1120828">
+ã“ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ç„¡æ–™ãƒ†ã‚­ã‚¹ãƒˆæ¤œç´¢ãƒ—ロフィールã®æœ€çµ‚更新日をå«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272571">
+OID: <code>2.16.840.1.113730.3.1.149</code><P></A>
+
+<A NAME="1112096">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237497">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1237470">&nbsp;
+</A>
+<A NAME="piptotalcount">
+<H3> piptotalcount</H3>
+</A>
+
+
+<A NAME="1237471">
+ç¾åœ¨ã¾ã§ã®ã™ã¹ã¦ã®æ›´æ–°ä¸­ã«ç™ºç”Ÿã—ãŸä¸€è‡´æ•°ã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272577">
+OID: <code>2.16.840.1.113730.3.1.154</code><P></A>
+
+<A NAME="1112775">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237516">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1112780">&nbsp;
+</A>
+<A NAME="piptotalrun">
+<H3> piptotalrun</H3>
+</A>
+
+
+
+<A NAME="1120866">
+ç¾åœ¨ã¾ã§ã®Personal Interest Profile (PIP)æ›´æ–°åˆè¨ˆæ•°ã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1272619">
+OID: <code>2.16.840.1.113730.3.1.155</code><P></A>
+
+<A NAME="1112781">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237538">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1110777">&nbsp;
+</A>
+<A NAME="pipuid">
+<H3> pipuid</H3>
+</A>
+
+
+
+<A NAME="1120876">
+Personal Interest Profile (PIP)ã®å±žã™ã‚‹ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼IDã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271249">
+OID: <code>2.16.840.1.113730.3.1.137</code><P></A>
+
+<A NAME="1110778">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237569">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1107663">&nbsp;
+</A>
+<A NAME="pipuniqueid">
+<H3> pipuniqueid</H3>
+</A>
+
+
+
+<A NAME="1239397">
+Compassユーザーã®ä¸€æ„ã®IDã‚’å«ã‚€ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271284">
+OID: <code>2.16.840.1.113730.3.1.139</code><P></A>
+
+<A NAME="1108334">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237586">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1108439">&nbsp;
+</A>
+<A NAME="pipusertype">
+<H3> pipusertype</H3>
+</A>
+
+
+
+<A NAME="1120926">
+Compassユーザー タイプを記述ã™ã‚‹ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚<P></A>
+
+<A NAME="1271340">
+OID: <code>2.16.840.1.113730.3.1.141</code><P></A>
+
+<A NAME="1108473">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1237595">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1230025">&nbsp;
+</A>
+<A NAME="postalAddress">
+<H3> postalAddress</H3>
+</A>
+
+
+
+<A NAME="1230026">
+エントリã®ãƒ¡ãƒ¼ãƒªãƒ³ã‚° アドレスを示ã—ã¾ã™ã€‚ã“ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯è¤‡æ•°è¡ŒãŒå«ã¾ã‚Œã‚‹ã‚ˆã†æ„図ã•ã‚Œã¦ã„ã¾ã™ã€‚LDIFå½¢å¼ã§ç¤ºã™å ´åˆã¯ã€å„行をドル記å·($)ã§åŒºåˆ‡ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚例:<P></A>
+<A NAME="1230027">
+<PRE> postalAddress: 1234 Ridgeway Drive$Santa Clara, CA$99555
+</PRE>
+</A>
+
+<A NAME="1230029">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1230030">
+テキスト内ã§ã®åŒºåˆ‡ã‚Šã¨ã—ã¦ã§ã¯ãªãã€å®Ÿéš›ã®ãƒ‰ãƒ«è¨˜å·($)ã¾ãŸã¯ãƒãƒƒã‚¯ã‚¹ãƒ©ãƒƒã‚·ãƒ¥(\)を示ã™ã«ã¯ã€ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—ã•ã‚ŒãŸ16進値\24㨠\5cを使用ã—ã¾ã™ã€‚例ãˆã°ã€æ¬¡ã®ã‚ˆã†ãªæ–‡å­—列を示ã™å ´åˆã€<P></A>
+<A NAME="1230031">
+<PRE> The dollar ($) value can be found <br>
+ in the c:\cost file.
+</PRE>
+</A>
+
+<A NAME="1230032">
+次ã®ã‚ˆã†ã«ã‚¨ã‚¹ã‚±ãƒ¼ãƒ—文字を使用ã—ã¾ã™ã€‚<P></A>
+<A NAME="1230033">
+<PRE> The dollar (\24) value can be found$in the c:\5ccost file.
+</PRE>
+</A>
+
+
+<A NAME="1230036">&nbsp;
+</A>
+<A NAME="postalCode">
+<H3> postalCode</H3>
+</A>
+
+
+
+<A NAME="1230037">
+米国ã«ãŠã‘るエントリã®éƒµä¾¿ç•ªå·ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1230038">
+<PRE> postalCode: 95050
+</PRE>
+</A>
+
+<A NAME="1230040">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1230043">&nbsp;
+</A>
+<A NAME="postOfficeBox">
+<H3> postOfficeBox</H3>
+</A>
+
+
+
+<A NAME="1230044">
+エントリã®ç§æ›¸ç®±ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1230045">
+<PRE> postOfficeBox: P.O. Box 1234
+</PRE>
+</A>
+
+<A NAME="1230047">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202605">&nbsp;
+</A>
+<A NAME="preferredDeliveryMethod">
+<H3> preferredDeliveryMethod</H3>
+</A>
+
+
+
+<A NAME="1202606">
+エントリãŒå¸Œæœ›ã™ã‚‹é€£çµ¡æ–¹æ³•ã¾ãŸã¯é…信方法を示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202607">
+<PRE> preferredDeliveryMethod: telephone
+</PRE>
+</A>
+
+<A NAME="1202609">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1103495">&nbsp;
+</A>
+<A NAME="preferredLanguage">
+<H3>preferredLanguage</H3>
+</A>
+
+
+
+<A NAME="1103496">
+ユーザーãŒå¸Œæœ›ã™ã‚‹æ›¸è¨€èªžã¾ãŸã¯è©±è¨€èªžã‚’定義ã—ã¾ã™ã€‚ã“ã®å±žæ€§å€¤ã¯ã€HTTP Accept-Languageヘッダ値ã®æ§‹æ–‡ã«æº–æ‹ ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。<P></A>
+
+<A NAME="1103586">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202620">&nbsp;
+</A>
+<A NAME="presentationAddress">
+<H3> presentationAddress</H3>
+</A>
+
+
+
+<A NAME="1206932">
+エントリã®OSI表示アドレスãŒå«ã¾ã‚Œã¾ã™ã€‚表示アドレスã¯ä¸€ã¤ã®OSI Network Addressã¨æœ€é«˜3ã¤ã®ã‚»ãƒ¬ã‚¯ã‚¿ã‹ã‚‰æ§‹æˆã•ã‚Œã€ç§»é€ã€ã‚»ãƒƒã‚·ãƒ§ãƒ³ã€ã¾ãŸã¯è¡¨ç¤ºã®ã‚¨ãƒ³ãƒ†ã‚£ãƒ†ã‚£ãŒã“ã®ã‚»ãƒ¬ã‚¯ã‚¿ã‚’å„一ã¤ãšã¤ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1202622">
+<PRE> presentationAddress: TELEX+00726322+RFC-1006+02+130.59.2.1
+</PRE>
+</A>
+
+<A NAME="1202624">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1241471">&nbsp;
+</A>
+<A NAME="protocolInformation">
+<H3> protocolInformation</H3>
+</A>
+
+
+
+<A NAME="1241473">
+未定義。<P></A>
+
+<A NAME="1245387">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1245389">&nbsp;
+</A>
+<A NAME="reciprocalNamingLink">
+<H3> reciprocalNamingLink</H3>
+</A>
+
+
+
+<A NAME="1235430">
+未定義。<P></A>
+
+<A NAME="1235433">
+構文: dn<P></A>
+
+
+<A NAME="1100037">&nbsp;
+</A>
+<A NAME="ref">
+<H3> ref</H3>
+</A>
+
+
+
+<A NAME="1100061">
+スマートå‚照をサãƒãƒ¼ãƒˆã™ã‚‹ãŸã‚ã«LDAPv3ã§ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚LDAP URLãŒã€ldap://サーãƒãƒ¼å:ãƒãƒ¼ãƒˆç•ªå·/dnã®æ›¸å¼ã§å«ã¾ã‚Œã¾ã™ã€‚ãƒãƒ¼ãƒˆç•ªå·ã¯ã‚ªãƒ—ションã§ã™ã€‚例:<P></A>
+<A NAME="1202639">
+<PRE> ref: ldap://mozilla/<I>cn=John Doe, o=Airius.com
+</I></PRE>
+</A>
+
+<A NAME="1100064">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1202644">&nbsp;
+</A>
+<A NAME="registeredAddress">
+<H3> registeredAddress</H3>
+</A>
+
+
+
+<A NAME="1206709">
+ã“ã®å±žæ€§ã«ã¯ã€å—å–人ãŒé…é€ã‚’å—ç†ã™ã‚‹å¿…è¦ã®ã‚る電報や急é€ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®å—ç†ã«é©åˆ‡ãªéƒµä¾¿ä½æ‰€ã‚’入力ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1202648">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1092877">&nbsp;
+</A>
+<A NAME="replicaBeginOrc">
+<H3> replicaBeginOrc</H3>
+</A>
+
+
+
+<A NAME="1092878">
+複製å‰ã«ä¾›çµ¦ã‚µãƒ¼ãƒãƒ¼ãŒæ¶ˆè²»ã‚µãƒ¼ãƒãƒ¼ã®å†…容を消去ã™ã¹ãã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã«å€¤ãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€ä¾›çµ¦ã‚µãƒ¼ãƒãƒ¼ã«ã‚ˆã£ã¦ãã®å†…容ãŒæ¶ˆåŽ»ã•ã‚Œã¾ã™ã€‚ã“ã®å±žæ€§ã®è¨±å®¹å€¤ã¯startã¨stopã®2ã¤ã§ã™ã€‚startã§æ¶ˆè²»ã‚µãƒ¼ãƒãƒ¼ã®å†…容ãŒæ¶ˆåŽ»ã•ã‚Œã€stopã§ä¾›çµ¦ã‚µãƒ¼ãƒãƒ¼ã«ã‚ˆã‚‹ã“ã®å‹•ä½œãŒä¸­æ­¢ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1092879">
+<PRE> replicaBeginOrc: start
+</PRE>
+</A>
+
+<A NAME="1092881">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1006496">&nbsp;
+</A>
+<A NAME="replicaBindDn">
+<H3> replicaBindDn</H3>
+</A>
+
+
+
+<A NAME="1006513">
+複製サーãƒãƒ¼ã¨ã®é€šä¿¡ã®éš›ã«ã‚µãƒ¼ãƒãƒ¼ãŒä½¿ç”¨ã™ã‚‹DNを示ã—ã¾ã™ã€‚ã“ã®DNã¯å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸç‰¹æ¨©ã§ã‚ã‚‹å ´åˆã‚‚ã‚ã‚Šã¾ã™ã€‚例:<P></A>
+<A NAME="1006521">
+<PRE> replicaBinddn: <I>cn=replicator o=Netscape Communications Corp., <br>
+</I> <I>c=US
+</I></PRE>
+</A>
+
+<A NAME="1006538">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+<A NAME="1009992">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1006636">&nbsp;
+</A>
+<A NAME="replicaBindMethod">
+<H3> replicaBindMethod</H3>
+</A>
+
+
+
+<A NAME="1006689">
+使用ã™ã‚‹è¤‡è£½æ–¹æ³•ã‚’示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯å­˜åœ¨ã™ã‚‹å¿…è¦ã¯ã‚ã‚Šã¾ã›ã‚“。存在ã™ã‚‹å ´åˆã¯<code>simple</code>ã«è¨­å®šã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。<code>simple</code>ã«è¨­å®šã—ã¦ã„ãªã„ã¨ã€è­¦å‘ŠãŒå°åˆ·ã•ã‚Œã€simpleã¨ã—ã¦è¤‡è£½ãŒå‡¦ç†ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1006710">
+<PRE> replicaBindMethod: simple
+</PRE>
+</A>
+
+<A NAME="1006720">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1009994">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1230073">&nbsp;
+</A>
+<A NAME="replicaCredentials">
+<H3> replicaCredentials</H3>
+</A>
+
+
+
+<A NAME="1230074">
+消費サーãƒãƒ¼ã«é€ä¿¡ã•ã‚Œã‚‹replicaBinddnã¨ã¨ã‚‚ã«ä½¿ç”¨ã™ã‚‹ãƒ‘スワードを示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€åŽ³æ ¼ãªã‚¢ã‚¯ã‚»ã‚¹åˆ¶å¾¡ã§æŒ‡å®šã™ã‚‹ã“ã¨ãŒç‰¹ã«æŽ¨å¥¨ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1230075">
+<PRE> replicaCredentials: bogusPassword
+</PRE>
+</A>
+
+<A NAME="1230077">
+構文: <a href="attribut.htm#1004700">bin</a> (plain text)<P></A>
+
+<A NAME="1230078">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1148497">&nbsp;
+</A>
+<A NAME="replicaEntryFilter">
+<H3>replicaEntryFilter</H3>
+</A>
+
+
+
+<A NAME="1204405">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1280979">
+OID: <code>2.16.840.1.113730.3.1.203</code><P></A>
+
+<A NAME="1152854">
+構文: <a href="attribut.htm#1004702">c</a>is<P></A>
+<P>
+<A NAME="1148445">
+<A NAME="replicaHost">
+<B>replicaHost</B>
+</a></a>
+<P>
+
+
+<A NAME="1148446">
+消費サーãƒãƒ¼ã®ãƒ›ã‚¹ãƒˆåを示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1148447">
+<PRE><A NAME="1148447">
+ replicaHost: slave.netscape.com
+</A>
+</PRE>
+<A NAME="1258218">
+OID: <code>2.16.840.1.113730.3.1.197</code><P></A>
+
+<A NAME="1148449">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1148453">&nbsp;
+</A>
+<A NAME="replicaNickname">
+<H3> replicaNickname</H3>
+</A>
+
+
+
+<A NAME="1148454">
+å˜ä¸€ã®ä¾›çµ¦ã‚µãƒ¼ãƒãƒ¼ã¨å˜ä¸€ã®æ¶ˆè²»ã‚µãƒ¼ãƒãƒ¼é–“ã«ãŠã‘る特定ã®è¤‡è£½ãƒ«ãƒ¼ãƒ«ã‚’記述ã™ã‚‹è‡ªç”±å½¢å¼ã®åå‰ãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+<A NAME="1148455">
+<PRE><A NAME="1148455">
+ replicaNickName: currentset
+</A>
+</PRE>
+<A NAME="1280981">
+OID: <code>2.16.840.1.113730.3.1.204</code><P></A>
+
+<A NAME="1148552">
+構文:<a href="attribut.htm#1004702"> cis</a><P></A>
+
+<A NAME="1010001">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+<A NAME="1007660">
+<A NAME="replicaPort">
+<B>replicaPort</B>
+</a></a>
+<P>
+
+
+<A NAME="1007661">
+消費サーãƒãƒ¼ã®ãƒãƒ¼ãƒˆç•ªå·ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1006466">
+ replicaPort: 9872
+</A>
+</PRE>
+<A NAME="1258224">
+OID: <code>2.16.840.1.113730.3.1.48</code><P></A>
+
+<A NAME="1006484">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1010007">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1006384">&nbsp;
+</A>
+<A NAME="replicaRoot">
+<H3> replicaRoot</H3>
+</A>
+
+
+
+<A NAME="1006394">
+消費マシンã«è¤‡è£½ä¸­ã®ã‚µãƒ–ツリーã®DNを示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1006401">
+<PRE><A NAME="1006401">
+ replicaRoot: <I>o=Netscape Communications Corp., c=US</I>
+</A>
+</PRE>
+<A NAME="1258564">
+OID: <code>2.16.840.1.113730.3.1.57</code><P></A>
+
+<A NAME="1006414">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+<A NAME="1010013">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+<A NAME="1281126">
+<A NAME="replicatedAttributeList">
+<B>replicatedAttributeList</B>
+</a></a>
+<P>
+
+
+<A NAME="1281128">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„。<P></A>
+
+<A NAME="1281133">
+OID: <code>2.16.840.1.113730.3.1.205</code><P></A>
+
+<A NAME="1281135">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+<P>
+<A NAME="1006918">&nbsp;
+</A>
+<A NAME="replicaUpdateFailedAt">
+<H3> replicaUpdateFailedAt</H3>
+</A>
+
+
+
+<A NAME="1006939">
+更新完了ã«å¤±æ•—ã—ãŸæ—¥æ™‚ã‚’zuluå½¢å¼ã§ç¤ºã—ã¾ã™ã€‚ã™ã¹ã¦ã®æ›´æ–°ãŒæˆåŠŸã—ãŸå ´åˆã€replicaUpdateFailedAtã¯ç©ºç™½ã§ã™ã€‚例:<P></A>
+<A NAME="1006946">
+<PRE> replicaUpdateFailedAt: 199603261300z
+</PRE>
+</A>
+
+<A NAME="1006957">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1010019">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1012768">&nbsp;
+</A>
+<A NAME="replicaUpdateReplayed">
+<H3> replicaUpdateReplayed</H3>
+</A>
+
+
+
+<A NAME="1012770">
+消費サーãƒãƒ¼ã«ä¼ãˆã‚‰ã‚ŒãŸæœ€çµ‚変更ã®å¤‰æ›´ç•ªå·ã‚’示ã—ã¾ã™ã€‚ã“ã®å€¤ã¯ã‚µãƒ¼ãƒãƒ¼é–“ã®å†…部ã§ã®ã¿ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1012772">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1012758">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1006817">&nbsp;
+</A>
+<A NAME="replicaUpdateSchedule">
+<H3> replicaUpdateSchedule</H3>
+</A>
+
+
+
+<A NAME="1006849">
+消費サーãƒãƒ¼ã®æ›´æ–°ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã‚’示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ãŒå­˜åœ¨ã—ãªã„å ´åˆã¯ã€æ¶ˆè²»ã‚µãƒ¼ãƒãƒ¼ã¯ç›´ã¡ã«æ›´æ–°ã•ã‚Œã¾ã™ã€‚例: <P></A>
+<A NAME="1006868">
+<PRE> replicaUpdateSchedule: 0100-0400
+</PRE>
+</A>
+<A NAME="1007219">
+<PRE> replicaUpdateSchedule: * 06
+</PRE>
+</A>
+<A NAME="1007229">
+<PRE> replicaUpdateSchedule: 1145-1300 24
+</PRE>
+</A>
+
+<A NAME="1007234">
+ã“れらã®å€¤ã®æ„味:<P></A>
+<A NAME="1007241">
+<PRE> 毎日ã€åˆå‰1時ã‹ã‚‰åˆå‰4時ã¾ã§
+</PRE>
+</A>
+<A NAME="1007247">
+<PRE> 土曜ã¨æ—¥æ›œã®çµ‚æ—¥
+</PRE>
+</A>
+<A NAME="1007252">
+<PRE> ç«æ›œã¨æœ¨æ›œã®åˆå‰11時45分ã‹ã‚‰åˆå¾Œ1時ã¾ã§
+</PRE>
+</A>
+
+<A NAME="1006873">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1010052">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+
+<A NAME="1006741">&nbsp;
+</A>
+<A NAME="replicaUseSsl">
+<H3> replicaUseSsl</H3>
+</A>
+
+
+
+<A NAME="1006754">
+消費サーãƒãƒ¼ã¨ã®é€šä¿¡ã«SSLを使用ã™ã‚‹ã‹ã©ã†ã‹ã‚’示ã—ã¾ã™ã€‚éžã‚¼ãƒ­ã®å€¤ãŒã‚ã‚‹ã¨SSLãŒä½¿ç”¨ã•ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1006794">
+<PRE> replicaUseSsl: 0
+</PRE>
+</A>
+
+<A NAME="1006801">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+<A NAME="1010064">
+ã“ã®å±žæ€§ã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µã§ã™ã€‚<P></A>
+<P>
+<A NAME="1152805">
+<A NAME="retryCountResetTime">
+<B>retryCountResetTime</B>
+</a></a>
+<P>
+
+
+<A NAME="1154931">
+passwordRetryCount属性ãŒã‚¼ãƒ­ (0)ã«ãƒªã‚»ãƒƒãƒˆã•ã‚Œã‚‹ã¾ã§ã®æ™‚間を秒数ã§å®šç¾©ã—ã¾ã™ã€‚<P></A>
+<A NAME="1154932">
+<PRE> retryCountResetTime: 600
+</PRE>
+</A>
+
+<A NAME="1146199">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202666">&nbsp;
+</A>
+<A NAME="roleOccupant">
+<H3> roleOccupant</H3>
+</A>
+
+
+
+<A NAME="1202667">
+organizationalRoleエントリã§å®šç¾©ã•ã‚ŒãŸå½¹å‰²ã‚’å—ã‘æŒã¤ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®è­˜åˆ¥åãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1204472">
+<PRE> roleOccupant: cn=jdoe o=airius.com
+</PRE>
+</A>
+
+<A NAME="1204474">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1204477">&nbsp;
+</A>
+<A NAME="roomNumber">
+<H3> roomNumber</H3>
+</A>
+
+
+
+<A NAME="1214596">
+オブジェクトã®éƒ¨å±‹ç•ªå·ã‚’示ã—ã¾ã™ã€‚部屋オブジェクトã®å‘½åã«commonName属性を使用ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。例:<P></A>
+<A NAME="1202675">
+<PRE> roomNumber: 230
+</PRE>
+</A>
+
+<A NAME="1202677">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202682">&nbsp;
+</A>
+<A NAME="searchGuide">
+<H3> searchGuide</H3>
+</A>
+
+
+
+<A NAME="1202683">
+検索動作ã®ãŸã‚ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã®ãƒ™ãƒ¼ã‚¹ オブジェクトã¨ã—ã¦ã‚¨ãƒ³ãƒˆãƒªã‚’使用ã™ã‚‹éš›ã«ã€æ案ã•ã‚Œã‚‹æ¤œç´¢åŸºæº–ã«é–¢ã™ã‚‹æƒ…報を示ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1230091">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1202691">&nbsp;
+</A>
+<A NAME="secretary">
+<H3> secretary</H3>
+</A>
+
+
+
+<A NAME="1202692">
+エントリã®ç§˜æ›¸ã¾ãŸã¯ã‚¢ã‚·ã‚¹ã‚¿ãƒ³ãƒˆã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202693">
+<PRE> secretary: <I>cn=John Doe, o=Airius.com
+</I></PRE>
+</A>
+
+<A NAME="1202695">
+構文: <a href="attribut.htm#1004702">dn</a><P></A>
+
+
+<A NAME="1172500">&nbsp;
+</A>
+<A NAME="seeAlso">
+<H3> seeAlso</H3>
+</A>
+
+
+
+<A NAME="1172501">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã«é–¢ä¿‚ã™ã‚‹æƒ…報をå«ã‚€å¯èƒ½æ€§ã®ã‚る別ã®Directory Serverã®ã‚¨ãƒ³ãƒˆãƒªã‚’示ã—ã¾ã™ã€‚ 例: <P></A>
+<A NAME="1172502">
+<PRE> seeAlso: <I>cn=Quality Control Inspectors, ou=manufacturing, o=Airius,<br>
+ c=US
+</I></PRE>
+</A>
+
+<A NAME="1172504">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1202700">&nbsp;
+</A>
+<A NAME="serialNumber">
+<H3> serialNumber</H3>
+</A>
+
+
+
+<A NAME="1202701">
+エントリã®ã‚·ãƒªã‚¢ãƒ«ç•ªå·ã‚’定義ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202702">
+<PRE> serialNumber: 555-1234-AZ
+</PRE>
+</A>
+
+<A NAME="1202704">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1093065">&nbsp;
+</A>
+<A NAME="serverHostName">
+<H3>serverHostName</H3>
+</A>
+
+
+
+<A NAME="1093066">
+NetscapeサーãƒãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„るホストåを示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€<a href="attribut.htm#">netscapeServer</a>ã®ã‚ªãƒ–ジェクト クラスãŒä½¿ç”¨ã—ã¾ã™ã€‚通常ã€ã“ã®å±žæ€§ã¨å±žæ€§å€¤ã¯ã€Netscapeサーãƒã‚’åˆã‚ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹éš›ã«ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ›¸ãè¾¼ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1032467">
+ serverHostname: twain.airius.com
+</A>
+</PRE>
+<A NAME="1259312">
+OID: <code>2.16.840.1.113730.3.1.76</code><P></A>
+
+<A NAME="1032488">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1032412">&nbsp;
+</A>
+<A NAME="serverProductName">
+<H3>serverProductName</H3>
+</A>
+
+
+
+<A NAME="1032414">
+インストールã•ã‚Œã¦ã„ã‚‹Netscapeサーãƒã®ã‚¿ã‚¤ãƒ—を識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€<a href="attribut.htm#">netscapeServer</a>ã®ã‚ªãƒ–ジェクト クラスãŒä½¿ç”¨ã—ã¾ã™ã€‚通常ã€ã“ã®å±žæ€§ã¨å±žæ€§å€¤ã¯ã€Netscapeサーãƒã‚’åˆã‚ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹éš›ã«ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ›¸ãè¾¼ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1032416">
+ serverProductName: Netscape Enterprise Server
+</A>
+</PRE>
+<A NAME="1259171">
+OID: <code>2.16.840.1.113730.3.1.71</code><P></A>
+
+<A NAME="1032418">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1032294">&nbsp;
+</A>
+<A NAME="serverRoot">
+<H3>serverRoot</H3>
+</A>
+
+
+
+<A NAME="1032296">
+NetscapeサーãƒãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„るディレクトリã¸ã®ã€å®Œå…¨ãªãƒ‘スを識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€<a href="attribut.htm#">netscapeServer</a>ã®ã‚ªãƒ–ジェクト クラスãŒä½¿ç”¨ã—ã¾ã™ã€‚通常ã€ã“ã®å±žæ€§ã¨å±žæ€§å€¤ã¯ã€Netscapeサーãƒã‚’åˆã‚ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹éš›ã«ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ›¸ãè¾¼ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1032297">
+ serverRoot: /usr/ns-home
+</A>
+</PRE>
+<A NAME="1259165">
+OID: <code>2.16.840.1.113730.3.1.70</code><P></A>
+
+<A NAME="1032346">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1032439">&nbsp;
+</A>
+<A NAME="serverVersionNumber">
+<H3>serverVersionNumber</H3>
+</A>
+
+
+
+<A NAME="1032441">
+インストールã•ã‚ŒãŸNetscapeサーãƒã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç•ªå·ã‚’識別ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã€<a href="objclass.htm#1097231">netscapeServer</a>ã®ã‚ªãƒ–ジェクト クラスãŒä½¿ç”¨ã—ã¾ã™ã€‚通常ã€ã“ã®å±žæ€§ã¨å±žæ€§å€¤ã¯ã€Netscapeサーãƒã‚’åˆã‚ã¦ã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã™ã‚‹éš›ã«ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ›¸ãè¾¼ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<PRE><A NAME="1032443">
+ serverVersionNumber: 3.0
+</A>
+</PRE>
+<A NAME="1259178">
+OID: <code>2.16.840.1.113730.3.1.72</code><P></A>
+
+<A NAME="1203414">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1245426">&nbsp;
+</A>
+<A NAME="singleLevelQuality">
+<H3> singleLevelQuality</H3>
+</A>
+
+
+
+<A NAME="1245427">
+未定義。 <P></A>
+
+<A NAME="1245430">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1203417">&nbsp;
+</A>
+<A NAME="st">
+<H3> st</H3>
+</A>
+
+
+
+<A NAME="1202711">
+エントリã®å±…ä½ã™ã‚‹å·žã¾ãŸã¯éƒ½é“府県を示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202712">
+<PRE> stateOrProvinceName: California
+</PRE>
+</A>
+
+<A NAME="1202713">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1202714">
+<PRE> st: California
+</PRE>
+</A>
+
+<A NAME="1202716">
+<a href="attribut.htm#">ç•¥å·</a>: st<P></A>
+
+<A NAME="1202718">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202721">&nbsp;
+</A>
+<A NAME="street">
+<H3> street</H3>
+</A>
+
+
+
+<A NAME="1202722">
+エントリã®å®¶ã®ç•ªåœ°ã¨è¡—è·¯ã®åå‰ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202723">
+<PRE> streetAddress: 1234 Ridgeway Drive
+</PRE>
+</A>
+
+<A NAME="1202724">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1202725">
+<PRE> street: 1234 Ridgeway Drive
+</PRE>
+</A>
+
+<A NAME="1202727">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202732">&nbsp;
+</A>
+<A NAME="subject">
+<H3> subject</H3>
+</A>
+
+
+
+<A NAME="1202733">
+ドキュメント エントリã®ä¸»é¡Œã«é–¢ã™ã‚‹æƒ…å ±ãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1202736">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1242622">&nbsp;
+</A>
+<A NAME="subschemaSubentry">
+<H3> subschemaSubentry</H3>
+</A>
+
+
+
+<A NAME="1242623">
+未定義。<P></A>
+
+<A NAME="1242626">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1099985">&nbsp;
+</A>
+<A NAME="subtreeaci">
+<H3> subtreeaci</H3>
+</A>
+
+
+
+<A NAME="1099986">
+ newsaccessitemエントリを更新ã§ãるユーザーを示ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1099989">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1245467">&nbsp;
+</A>
+<A NAME="subtreeMaximumQuality">
+<H3> subtreeMaximumQuality</H3>
+</A>
+
+
+
+<A NAME="1245469">
+未定義。 <P></A>
+
+<A NAME="1245472">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1245448">&nbsp;
+</A>
+<A NAME="subtreeMinimumQuality">
+<H3> subtreeMinimumQuality</H3>
+</A>
+
+
+
+<A NAME="1245450">
+未定義。 <P></A>
+
+<A NAME="1245453">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1241769">&nbsp;
+</A>
+<A NAME="supportedAlgorithms;binary">
+<H3> supportedAlgorithms;binary</H3>
+</A>
+
+
+
+<A NAME="1241770">
+未定義。 <P></A>
+
+<A NAME="1241967">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1202747">&nbsp;
+</A>
+<A NAME="supportedApplicationContext">
+<H3> supportedApplicationContext</H3>
+</A>
+
+
+
+<A NAME="1202748">
+ã“ã®å±žæ€§ã«ã¯OSIアプリケーション コンテキストã®è­˜åˆ¥å­ãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1202751">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1243196">&nbsp;
+</A>
+<A NAME="supportedControl">
+<H3> supportedControl</H3>
+</A>
+
+
+
+<A NAME="1243198">
+未定義。<P></A>
+
+<A NAME="1243201">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1243163">&nbsp;
+</A>
+<A NAME="supportedExtension">
+<H3> supportedExtension</H3>
+</A>
+
+
+
+<A NAME="1243164">
+未定義。<P></A>
+
+<A NAME="1243167">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1243238">&nbsp;
+</A>
+<A NAME="supportedLDAPVersion">
+<H3> supportedLDAPVersion</H3>
+</A>
+
+
+
+<A NAME="1243240">
+未定義。<P></A>
+
+<A NAME="1243243">
+構文: <a href="attribut.htm#1243260">int</a><P></A>
+
+
+<A NAME="1243217">&nbsp;
+</A>
+<A NAME="supportedSASLMechanisms">
+<H3> supportedSASLMechanisms</H3>
+</A>
+
+
+
+<A NAME="1243219">
+未定義。<P></A>
+
+<A NAME="1243222">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1230116">&nbsp;
+</A>
+<A NAME="sn">
+<H3> sn</H3>
+</A>
+
+
+
+<A NAME="1230117">
+エントリã®è‹—å­—ã€ã¾ãŸã¯ãƒ©ã‚¹ãƒˆãƒãƒ¼ãƒ ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1230118">
+<PRE> surname: Anderson
+</PRE>
+</A>
+
+<A NAME="1230119">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1230120">
+<PRE> sn: Anderson
+</PRE>
+</A>
+
+<A NAME="1230122">
+<a href="attribut.htm#">ç•¥å·</a>: sn<P></A>
+
+<A NAME="1230124">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1094954">&nbsp;
+</A>
+<A NAME="targetDn">
+<H3> targetDn</H3>
+</A>
+
+
+
+<A NAME="1094956">
+供給サーãƒãƒ¼ã«ãŠã„ã¦è¿½åŠ ã€å¤‰æ›´ã€ã¾ãŸã¯å‰Šé™¤ã•ã‚ŒãŸã‚¨ãƒ³ãƒˆãƒªã®è­˜åˆ¥åを定義ã—ã¾ã™ã€‚modrdn動作ã®å ´åˆã€targetDnã«ã¯ã€å¤‰æ›´å‰ã®ã‚¨ãƒ³ãƒˆãƒªã®è­˜åˆ¥åãŒå«ã¾ã‚Œã¾ã™ã€‚例:<P></A>
+<A NAME="1110601">
+<PRE> targetDn:<I> cn=Jane Doe, ou=Quality Control, o=Airius.com
+</I></PRE>
+</A>
+
+<A NAME="1094942">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1230129">&nbsp;
+</A>
+<A NAME="telephoneNumber">
+<H3> telephoneNumber</H3>
+</A>
+
+
+
+<A NAME="1230130">
+エントリã®é›»è©±ç•ªå·ã‚’示ã—ã¾ã™ã€‚例: <P></A>
+<A NAME="1230131">
+<PRE> telephoneNumber: 415-555-2233
+</PRE>
+</A>
+
+<A NAME="1230133">
+構文: <a href="attribut.htm#1004703">tel</a><P></A>
+
+
+<A NAME="1205004">&nbsp;
+</A>
+<A NAME="teletexTerminalIdentifier">
+<H3> teletexTerminalIdentifier</H3>
+</A>
+
+
+
+<A NAME="1205006">
+エントリã®ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナルã®è­˜åˆ¥å­ã‚’示ã—ã¾ã™ã€‚属性ã®å½¢å¼ã¯æ¬¡ã®é€šã‚Šã§ã™ã€‚<P></A>
+<A NAME="1204973">
+<PRE>teletex-id = ttx-term 0*("$" ttx-param)<br>
+ttx-term = å°åˆ·å¯èƒ½æ–‡å­—列<br>
+ttx-param = ttx-key ":" ttx-value<br>
+ttx-key = "graphic" / "control" / "misc" / "page" / "private"<br>
+ttx-value = オクテット文字列
+</PRE>
+</A>
+<a name="1204978">
+<BLOCKQUOTE>
+上記ã§ã¯ã€æœ€åˆã®å°åˆ·å¯èƒ½æ–‡å­—列ã¯ã€æš—å·åŒ–ã•ã‚Œã‚‹ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナル識別å­ã®æœ€åˆã®éƒ¨åˆ†ã®æš—å·ã§ã€å¾Œã®0以上ã®ã‚ªã‚¯ãƒ†ãƒƒãƒˆæ–‡å­—列ã¯ã“ã®ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナル識別å­ã®å¾Œç¶šéƒ¨åˆ†ã§ã™ã€‚
+
+</BLOCKQUOTE>
+</a>
+<a name="1205117">
+<BLOCKQUOTE>
+構文: <a href="attribut.htm#1004703">tel
+</a>
+</BLOCKQUOTE>
+</a>
+
+
+<A NAME="1205120">&nbsp;
+</A>
+<A NAME="telexNumber">
+<H3> telexNumber</H3>
+</A>
+
+
+
+<A NAME="1205121">
+エントリã®ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ç•ªå·ã‚’定義ã—ã¾ã™ã€‚テレックス番å·ã®å½¢å¼ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚<P></A>
+<A NAME="1204750">
+<PRE> actual-number "$" country "$" answerback
+</PRE>
+</A>
+
+<A NAME="1204751">
+上記ã§ã¯ã€<code>actual-number</code>ã¯æš—å·åŒ–ã•ã‚Œã‚‹ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ç•ªå·ã®ç•ªå·éƒ¨ã‚’構文的ã«è¡¨ç¤ºã—ãŸã‚‚ã®ã§ã€<code>country</code>ã¯ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ã®å›½ã‚³ãƒ¼ãƒ‰ã€<code>answerback</code>ã¯ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ ターミナル㮠返信コードã§ã™ã€‚<P></A>
+
+<A NAME="1202779">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202782">&nbsp;
+</A>
+<A NAME="textEncodedOrAddress">
+<H3> textEncodedOrAddress</H3>
+</A>
+
+
+
+<A NAME="1202783">
+RFC987ã§å®šç¾©ã•ã‚Œã¦ã„る通りã«ã€ã‚¨ãƒ³ãƒˆãƒªã®ãƒ†ã‚­ã‚¹ãƒˆæš—å·åŒ–ã•ã‚ŒãŸç™ºä¿¡å…ƒ/å—信者 (X.400)アドレスを定義ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202784">
+<PRE> textEncodedOrAddress: /S=doe/OU=eng/O=airius/ADMD=telemail/C=us/
+</PRE>
+</A>
+
+<A NAME="1202786">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1230152">&nbsp;
+</A>
+<A NAME="title">
+<H3> title</H3>
+</A>
+
+
+
+<A NAME="1230153">
+エントリã®å½¹è·ã‚’示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1230154">
+<PRE> title: Senior QC Inspector
+</PRE>
+</A>
+
+<A NAME="1230156">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202798">&nbsp;
+</A>
+<A NAME="ttl">
+<H3> ttl</H3>
+</A>
+
+
+
+<A NAME="1230159">
+å°†æ¥ã®ä½¿ç”¨ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1219626">
+<a href="attribut.htm#">ç•¥å·</a>: ttl<P></A>
+<a name="1219607">
+<BLOCKQUOTE>
+構文: <a href="attribut.htm#1004702">cis
+</a>
+</BLOCKQUOTE>
+</a>
+
+
+<A NAME="1202809">&nbsp;
+</A>
+<A NAME="uniqueIdentifier">
+<H3> uniqueIdentifier</H3>
+</A>
+
+
+
+<A NAME="1202810">
+識別åãŒå†ä½¿ç”¨ã•ã‚Œã‚‹éš›ã«2ã¤ã®ã‚¨ãƒ³ãƒˆãƒªã‚’区別ã™ã‚‹ã®ã«ä½¿ç”¨ã™ã‚‹ç‰¹å®šé …目を示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€å‰Šé™¤ã•ã‚ŒãŸè­˜åˆ¥åã¸ã®å‚ç…§ã®ã‚¤ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã‚’検出ã™ã‚‹ãŸã‚ã®ã‚‚ã®ã§ã™ã€‚ã“ã®å±žæ€§ã¯ã‚µãƒ¼ãƒãƒ¼ã«ã‚ˆã£ã¦å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1202812">
+構文: <a href="attribut.htm#1004700">bin</a> (ビット文字列)<P></A>
+
+
+<A NAME="1172624">&nbsp;
+</A>
+<A NAME="uniqueMember">
+<H3> uniqueMember</H3>
+</A>
+
+
+
+<A NAME="1172625">
+一æ„性をä¿è¨¼ã™ã‚‹ãŸã‚ã«å„åå‰ã«uniqueIdentifierãŒä¸Žãˆã‚‰ã‚ŒãŸã€ã‚¨ãƒ³ãƒˆãƒªã¨é–¢ä¿‚ã™ã‚‹åå‰ã®ã‚°ãƒ«ãƒ¼ãƒ—を示ã—ã¾ã™ã€‚uniqueMemberã®å±žæ€§å€¤ã¯uniqueIdentifierãŒå¾Œã«ç¶šãDNã§ã™ã€‚<P></A>
+
+<A NAME="1172627">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1202817">&nbsp;
+</A>
+<A NAME="updatedByDocument">
+<H3> updatedByDocument</H3>
+</A>
+
+
+
+<A NAME="1217372">
+ドキュメント エントリã®æ›´æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã‚るドキュメントã®è­˜åˆ¥åãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1202821">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1202824">&nbsp;
+</A>
+<A NAME="updatesDocument">
+<H3> updatesDocument</H3>
+</A>
+
+
+
+<A NAME="1217396">
+æ›´æ–°ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã§ã‚ã‚‹ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®å…ƒã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®è­˜åˆ¥åãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1202825">
+構文: <a href="attribut.htm#1100403">dn</a><P></A>
+
+
+<A NAME="1208938">&nbsp;
+</A>
+<A NAME="userCertificate">
+<H3>userCertificate</H3>
+</A>
+
+
+
+<A NAME="1208940">
+ユーザーã®è¨¼æ˜Žæ›¸ã®ãƒ†ã‚­ã‚¹ãƒˆã‚³ãƒ¼ãƒ‰ ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã‚’å«ã¿ã¾ã™ã€‚ã“ã‚Œã¯ãŠè–¦ã‚ã—ã¾ã›ã‚“。代ã‚ã‚Šã«userCertificate;binaryã‚’ã”使用ãã ã•ã„。<P></A>
+
+<A NAME="1208942">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1208946">&nbsp;
+</A>
+<A NAME="userCertificate;binary">
+<H3> userCertificate;binary</H3>
+</A>
+
+
+
+<A NAME="1208948">
+ユーザーã®è¨¼æ˜Žæ›¸ãŒãƒã‚¤ãƒŠãƒªå½¢å¼ã§å«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1208950">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1202840">&nbsp;
+</A>
+<A NAME="userClass">
+<H3> userClass</H3>
+</A>
+
+
+
+<A NAME="1214739">
+コンピュータ ユーザーã®ã‚«ãƒ†ã‚´ãƒªã‚’示ã—ã¾ã™ã€‚ã“ã®å±žæ€§ã®æ„味ã¯ä»»æ„ã®ã‚‚ã®ã§ã™ã€‚organizationalStatus属性ã§ã¯ã‚³ãƒ³ãƒ”ュータ ユーザーã¨ä»–ã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ã®åŒºåˆ¥ãŒãªã„ãŸã‚ã€é©ç”¨æ€§ãŒé«˜ã„å ´åˆãŒã‚ã‚Šã¾ã™ã€‚例:<P></A>
+<A NAME="1202842">
+<PRE> userClass: intern
+</PRE>
+</A>
+
+<A NAME="1202844">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1202847">&nbsp;
+</A>
+<A NAME="uid">
+<H3> uid</H3>
+</A>
+
+
+
+<A NAME="1202848">
+エントリã®ãƒ¦ãƒ¼ã‚¶ãƒ¼ID(通常ã¯ãƒ­ã‚°ã‚ªãƒ³ ID)を示ã—ã¾ã™ã€‚例:<P></A>
+<A NAME="1202849">
+<PRE> userid: banderson
+</PRE>
+</A>
+
+<A NAME="1202850">
+ã¾ãŸã¯ã€<P></A>
+<A NAME="1202851">
+<PRE> uid: banderson
+</PRE>
+</A>
+
+<A NAME="1202853">
+<a href="attribut.htm#">ç•¥å·</a>: uid<P></A>
+
+<A NAME="1202855">
+構文: <a href="attribut.htm#1004702">cis</a><P></A>
+
+
+<A NAME="1196547">&nbsp;
+</A>
+<A NAME="userPassword">
+<H3> userPassword</H3>
+</A>
+
+
+
+<A NAME="1196548">
+エントリã®ãƒ‘スワードã¨æš—å·åŒ–方法をã€{æš—å·åŒ–方法}æš—å·åŒ–パスワードã®å½¢å¼ã§ç¤ºã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1196550">
+例:<P></A>
+<A NAME="1196551">
+<PRE> userPassword: {sha}FTSLQhxXpA05
+</PRE>
+</A>
+
+<A NAME="1196553">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1103595">&nbsp;
+</A>
+<A NAME="userSMIMECertificate;binary">
+<H3>userSMIMECertificate;binary</H3>
+</A>
+
+
+
+<A NAME="1103596">
+S/MIMEã§Netscape CommunicatorãŒä½¿ç”¨ã—ã¾ã™ã€‚例: <P></A>
+
+<A NAME="1235505">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+
+
+<A NAME="1202876">&nbsp;
+</A>
+<A NAME="x121Address">
+<H3> x121Address</H3>
+</A>
+
+
+
+<A NAME="1202877">
+ユーザーã®X.121アドレスを定義ã—ã¾ã™ã€‚<P></A>
+
+<A NAME="1202880">
+構文: <a href="attribut.htm#1004701">ces</a><P></A>
+
+
+<A NAME="1235525">&nbsp;
+</A>
+<A NAME="x500UniqueIdentifier">
+<H3> x500UniqueIdentifier</H3>
+</A>
+
+
+
+<A NAME="1235526">
+未定義。 <P></A>
+
+<A NAME="1235529">
+構文: <a href="attribut.htm#1004700">bin</a><P></A>
+<a name="1241249">
+<BLOCKQUOTE>
+
+
+</BLOCKQUOTE>
+</a>
+
+<p>
+
+<hr width="80%" size="2">
+<FONT SIZE="-2">
+<CENTER>
+Copyright 1997 Netscape Communications Corporation. All rights reserved.
+</CENTER>
+</FONT>
+
+</body>
+</html>
+
diff --git a/ldap/clients/dsgw/html/manual/ja/auth.htm b/ldap/clients/dsgw/html/manual/ja/auth.htm
new file mode 100644
index 00000000..2b611322
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/ja/auth.htm
@@ -0,0 +1,151 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+<!-- HEAD -->
+
+<title>ディレクトリã¸ã®èªè¨¼</title>
+</head>
+<body>
+
+<h1><a name="authenticating"></a>èªè¨¼</h1>
+
+<p>èªè¨¼ã¯ã€Directory Serverã«èº«åˆ†ã‚’証明ã™ã‚‹å‡¦ç†ã§ã™ã€‚èªè¨¼å‡¦ç†ã«ã‚ˆã£ã¦ã€Directory Serverã¯ã€ãƒ¦ãƒ¼ã‚¶ã«è¨±å¯ã™ã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®æ“作を決ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ã—ã‹ã—ã€èªè¨¼ã¯å¿…ãšå¿…è¦ã§ã‚ã‚‹ã¨ã¯é™ã‚‰ãªã„ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。ディレクトリ管ç†è€…ã¯ã€ã‚る処ç†ã«å¯¾ã—ã¦ã¯è¨±å¯ã‚’ä¸è¦ã«ã™ã‚‹ã‚ˆã†ã«ã‚·ã‚¹ãƒ†ãƒ ã‚’設定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚</p>
+
+<p>デフォルトã§ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…以外ã®ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’æ‹’å¦ã•ã‚Œã¾ã™ã€‚ディレクトリ管ç†è€…ãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã®ä»˜ä¸Žã¾ãŸã¯å‰Šé™¤ã‚’è¡Œã„ã¾ã™ã€‚ã“ã®ã‚ˆã†ãªè¨±å¯ã¯ã‚µã‚¤ãƒˆã”ã¨ã«æ±ºå®šã•ã‚Œã‚‹ãŸã‚ã€è‡ªåˆ†ãŒä¿æŒã—ã¦ã„るディレクトリã¸ã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã®ç¨®é¡žã‚„ã©ã®æ“作ã«èªè¨¼ãŒå¿…è¦ã‹ã«ã¤ã„ã¦ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã«å°‹ã­ã¦ãã ã•ã„。</p>
+
+<p>本章ã®å†…容:</p>
+
+<ul>
+ <li><a href="#ustand">ディレクトリ アクセスã«ã¤ã„ã¦</a></li>
+ <li><a href="#userauth">ディレクトリã¸ã®èªè¨¼</a></li>
+ <li><a href="#logout">ディレクトリã‹ã‚‰ã®ãƒ­ã‚°ã‚¢ã‚¦ãƒˆ</a></li>
+ <li><a href="#incorrectauth">ä¸é©åˆ‡ãªèªè¨¼ã«ã‚ˆã£ã¦ç™ºç”Ÿã™ã‚‹å•é¡Œ</a></li>
+</ul>
+
+<h2><a name="ustand"></a>ディレクトリ アクセスã«ã¤ã„ã¦</h2>
+
+<p>ディレクトリã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã®å¿…è¦ãªãƒ¦ãƒ¼ã‚¶ã‚„å¿…è¦ã¨ã•ã‚Œã‚‹ã‚¢ã‚¯ã‚»ã‚¹ タイプを決定ã™ã‚‹ã“ã¨ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã®é‡è¦ãªä»•äº‹ã®1ã¤ã§ã™ã€‚ディレクトリ管ç†è€…ã¯ã€ã‚¢ã‚¯ã‚»ã‚¹åˆ¶å¾¡æ©Ÿæ§‹ã‚’使用ã—ã¦ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®ã‚¢ã‚¯ã‚»ã‚¹è¨±å¯ã‚’付与ã¾ãŸã¯ç¦æ­¢ã—ã¾ã™ã€‚アクセス制御機構を使用ã—ã¦ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã¯ä»¥ä¸‹ã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã‚’付与ã¾ãŸã¯ç¦æ­¢ã§ãã¾ã™ã€‚
+ </p>
+
+<ul>
+ <li>ã™ã¹ã¦ã®æœªèªè¨¼ã®ãƒ¦ãƒ¼ã‚¶ã«å¯¾ã™ã‚‹ã‚¢ã‚¯ã‚»ã‚¹æ¨©(ã“ã‚Œã¯åŒ¿åアクセスã¨å‘¼ã°ã‚Œã¾ã™) </li>
+ <li>ã™ã¹ã¦ã®èªè¨¼ãƒ¦ãƒ¼ã‚¶ã«å¯¾ã™ã‚‹ã‚¢ã‚¯ã‚»ã‚¹æ¨©</li>
+ <li>特定ã®èªè¨¼ãƒ¦ãƒ¼ã‚¶ã¾ãŸã¯ã‚°ãƒ«ãƒ¼ãƒ—ã«å¯¾ã™ã‚‹ã‚¢ã‚¯ã‚»ã‚¹æ¨©</li>
+ <li>特定ã®ãƒžã‚·ãƒ³ã¾ãŸã¯DNSドメインã‹ã‚‰ã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©</li>
+ <li>特定ã®æ™‚é–“ã¾ãŸã¯æ›œæ—¥ã«ãŠã‘るアクセス権</li>
+ <li>èªè¨¼æ–¹æ³•ã«åŸºã¥ãアクセス権</li>
+</ul>
+
+<p>管ç†è€…ãŒå‰²ã‚Šå½“ã¦ã‚‹ç‰¹å®šã®æ¨©é™ã¯ã€ãƒ¦ãƒ¼ã‚¶ã«ã‚ˆã£ã¦ç•°ãªã‚‹ã“ã¨ã‚‚ã‚ã‚Šã¾ã™ã€‚例ãˆã°ã€åŒ¿åユーザã«ã¯èª­è¾¼ã¿ãŠã‚ˆã³æ¤œç´¢ã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ã®ã¿ãŒé€šå¸¸ä»˜ä¸Žã•ã‚Œã¾ã™ãŒã€ç‰¹å®šã®èªè¨¼ãƒ¦ãƒ¼ã‚¶ã€ã¾ãŸã¯ã‚°ãƒ«ãƒ¼ãƒ—ã®ã¿ã«æ›¸è¾¼ã¿ã‚¢ã‚¯ã‚»ã‚¹æ¨©ãŒä»˜ä¸Žã•ã‚ŒãŸã‚Šã€ã¾ãŸã¯ç‰¹å®šã®ãƒžã‚·ãƒ³ã‹ã‚‰æ“作ã«ã®ã¿æ›¸è¾¼ã¿ã‚¢ã‚¯ã‚»ã‚¹æ¨©ãŒä»˜ä¸Žã•ã‚Œã‚‹ã“ã¨ã‚‚ã‚ã‚Šã¾ã™ã€‚</p>
+
+<p>ディレクトリ管ç†è€…ãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«è¨±å¯ã‚’é©ç”¨ã—ã¦å®Ÿè¡Œã§ãã‚‹æ“作をã€ä»¥ä¸‹ã«ã„ãã¤ã‹ç¤ºã—ã¾ã™ã€‚ディレクトリ管ç†è€…ãŒå®Ÿè¡Œå¯èƒ½ãªã“ã¨:</p>
+
+<ul>
+ <li>ä»»æ„ã®æ–¹æ³•ã§ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹å‰ã«èªè¨¼ã‚’義務付ã‘ã‚‹</li>
+ <li>ディレクトリã®ç‰¹å®šã®ã‚µãƒ–セクションã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹å‰ã«èªè¨¼ã‚’義務付ã‘ã‚‹ </li>
+ <li>エントリã®è¿½åŠ ã¾ãŸã¯å¤‰æ›´ãªã©ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãŠã‘る特定ã®æ“作を実行ã™ã‚‹å‰ã«èªè¨¼ã‚’義務付ã‘ã‚‹</li>
+ <li>ディレクトリ全体ã¾ãŸã¯ä¸€éƒ¨ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’æ‹’å¦ã—ãŸã‚Šã€ã¾ãŸã¯ç‰¹å®šã®æ“作ã®å®Ÿè¡Œã‚’æ‹’å¦ã™ã‚‹</li>
+ <li>ディレクトリ全体ã¾ãŸã¯ä¸€éƒ¨ã®åŒ¿åアクセスを許å¯ã™ã‚‹ </li>
+ <li>ã‚る種ã®å‹•ä½œ(検索ãªã©)ã®åŒ¿åアクセスを許å¯ã™ã‚‹ãŒã€ãã®ä»–ã®æ“作(変更ãªã©)ã®åŒ¿åアクセスをç¦æ­¢ã™ã‚‹</li>
+ <li>ç¾åœ¨ä½¿ç”¨ä¸­ã®ç‰©ç†çš„マシンã«åŸºã¥ã„ã¦ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã¾ãŸã¯æ‹’å¦ã™ã‚‹ </li>
+</ul>
+
+<p>Directory Serverゲートウェイインタフェースã§ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª アクセスを試ã¿ã‚‹å‰ã«èªè¨¼ãŒç¾©å‹™ä»˜ã‘られã¦ã„ã‚‹ã‹ã©ã†ã‹ã‚’èªè­˜ã™ã‚‹æ‰‹æ®µãŒã‚ã‚Šã¾ã›ã‚“。ã—ã‹ã—ã€ã“ã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã§ã¯ã€ä»»æ„ã®æ–¹æ³•ã§ãƒ¦ãƒ¼ã‚¶ãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーを変更ã™ã‚‹å‰ã«èªè¨¼ãŒå¿…è¦ã§ã‚ã‚‹ã“ã¨ãŒè¨­å®šã•ã‚Œã¦ãŠã‚Šã€ç¾åœ¨ãƒ¦ãƒ¼ã‚¶ãŒèªè¨¼ã—ã¦ã„ãªã„å ´åˆã¯ã€å¤‰æ›´å‰ã«èªè¨¼ã™ã‚‹ã‚ˆã†ãƒ—ロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚èªè¨¼ã—ãªã„å ´åˆã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ãŒåŒ¿åアクセス用ã«è¨­å®šã—ãŸæ“作ã¨ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªéƒ¨åˆ†ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã®ã¿ãŒè¨±å¯ã•ã‚Œã¾ã™ã€‚</p>
+
+<!--<p>アクセス制御ã®è©³ç´°ã¯ã€ã€ŽDirectory Server管ç†è€…用ガイドã€ã‚’ã”覧ãã ã•ã„。</p>-->
+
+<h2><a name="userauth"></a>ディレクトリã¸ã®èªè¨¼</h2>
+
+<p>å ´åˆã«ã‚ˆã£ã¦ã¯ã€ã‚ã‚‹æ“作å‰ã«èªè¨¼ã™ã‚‹ã‚ˆã†ãƒ—ロンプトãŒè‡ªå‹•çš„ã«è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ ã¾ãŸã€[èªè¨¼]タブをクリックã—ã¦ã€æ˜Žç¤ºçš„ã«èªè¨¼ã‚’é¸æŠžã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚ã„ãšã‚Œã®å ´åˆã‚‚ã€èªè¨¼éŽç¨‹ã¯ä»¥ä¸‹ã®é€šã‚Šã§ã™ã€‚</p>
+
+<ol>
+ <li>[èªè¨¼]タブをクリックã—ã¾ã™ã€‚</li>
+ <li>Directory Serverã«èº«åˆ†ã‚’証明ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹åå‰ã‚’入力ã—ã¾ã™ã€‚
+ <ul type="disc">
+ <li><a name="userauth2"></a>通常ã®ãƒ¦ãƒ¼ã‚¶ã¨ã—ã¦èªè¨¼ã™ã‚‹ã«ã¯ã€æ°åを入力ã—ã¦[継続]をクリックã—ã¾ã™ã€‚<br>
+ Directory Serverã«è¡¨ç¤ºã•ã‚Œã‚‹é€šã‚Šã«åå‰(一般åã€æ°åã‚ã‚‹ã„ã¯ãƒ¦ãƒ¼ã‚¶ID)を入力ã—ã¾ã™ã€‚
+ ローカルã®ã‚ªãƒšãƒ¬ãƒ¼ãƒ†ã‚£ãƒ³ã‚° システムã®ãƒ¦ãƒ¼ã‚¶IDã¾ãŸã¯ãƒ­ã‚°ã‚¤ãƒ³ã‚’入力ã—ãªã„ã§ãã ã•ã„。 </li>
+ <li><a name="managerauth2"></a>特権ã®ã‚るディレクトリ ユーザã¨ã—ã¦èªè¨¼ã™ã‚‹ã«ã¯ã€<b>[ディレクトリ管ç†è€…ã¨ã—ã¦èªè¨¼]</b>ボタンをクリックã—ã¾ã™ã€‚</li>
+ </ul>
+ </li>
+ <li>一致ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®ãƒ†ãƒ¼ãƒ–ルãŒè¤‡æ•°è¡¨ç¤ºã•ã‚ŒãŸå ´åˆã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª エントリã«å¯¾å¿œã™ã‚‹ãƒªãƒ³ã‚¯ã‚’é¸æŠžã—ã¾ã™ã€‚åå‰ãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãŠã„ã¦å›ºæœ‰ã®ã‚‚ã®ã§ã‚ã‚‹å ´åˆã¯ã€ã‚·ã‚¹ãƒ†ãƒ ã¯ã“ã®ã‚¹ãƒ†ãƒƒãƒ—を飛ã°ã—ã¾ã™ã€‚</li>
+ <li>パスワードを入力ã—ã¦[継続]をクリックã—ã¾ã™ã€‚<br>
+ 自分ã®ãƒ‘スワードãŒä¸æ˜Žã®å ´åˆã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã«ãŠå°‹ã­ãã ã•ã„。<br>
+ <a name="authsuccess"></a>èªè¨¼å‹•ä½œã®å®Œäº†ã«æˆåŠŸã—ãŸã‚‰ã€èªè¨¼ã®æœ‰åŠ¹æ™‚間を示ã™ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®æ™‚é–“ãŒéŽãŽãŸã‚‰ã€ã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚’継続ã™ã‚‹ãŸã‚ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«å†åº¦èªè¨¼ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚パスワードãŒå¤±åŠ¹ã—ã¦ã„ã‚Œã°ã€ãã®å ´ã§ãƒ‘スワードを変更ã™ã‚‹ã‹ã€ã‚·ã‚¹ãƒ†ãƒ ç®¡ç†è€…ã«é€£çµ¡ã—ã¦ãã ã•ã„。</li>
+ <li>[メインã¸æˆ»ã‚‹]をクリックã—ã¦Directory Serverインタフェースã®ã‚»ãƒƒã‚·ãƒ§ãƒ³ã‚’継続ã—ã¾ã™ã€‚</li>
+</ol>
+
+<h2><a name="logout"></a>ディレクトリã‹ã‚‰ã®ãƒ­ã‚°ã‚¢ã‚¦ãƒˆ</h2>
+
+<p>Directory Serverã«æ—¢ã«èªè¨¼æ¸ˆã¿ã§ã€åŒ¿åアクセスã«æˆ»ã‚‹å ´åˆã¯ã€ä»¥ä¸‹ã‚’実行ã—ã¦ãã ã•ã„。</p>
+
+<ol>
+ <li>[èªè¨¼]タブをクリックã—ã¾ã™ã€‚</li>
+ <li> <b>[èªè¨¼ã®ç ´æ£„(ログアウト)]</b>ボタンをクリックã—ã¾ã™ã€‚ </li>
+</ol>
+
+<p>ã“ã‚Œã§åŒ¿åアクセスã«æˆ»ã‚Šã¾ã™ã€‚アクセスã®ã‚¿ã‚¤ãƒ—を変更ã™ã‚‹ã«ã¯ã€å†åº¦Directory Serverã«èªè¨¼ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚詳細ã¯ã€<a
+href="#userauth2">「ユーザã¨ã—ã¦èªè¨¼ã€</a>ã¾ãŸã¯<a
+href="#managerauth2">「ディレクトリ管ç†è€…ã¨ã—ã¦èªè¨¼ã€</a>ã‚’ã”覧ãã ã•ã„。</p>
+
+<h2><a name="reauth"></a>ディレクトリã¸ã®å†åº¦èªè¨¼</h2>
+
+<p>ディレクトリã«èªè¨¼ã™ã‚‹ã¨ã€ç‰¹å®šæ™‚間有効ãªèªè¨¼è¨¼æ˜Žæ›¸ãŒä»˜ä¸Žã•ã‚Œã¾ã™ã€‚デフォルトã§ã¯ã€èªè¨¼è¨¼æ˜Žæ›¸ã¯120分間有効ã§ã™ã€‚ãŸã ã—ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ãŒæœ‰åŠ¹æœŸé–“を設定ã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚Directory Serverインタフェースã®ä½¿ç”¨ãŒçµ‚ã‚ã‚‹å‰ã«èªè¨¼è¨¼æ˜Žæ›¸ãŒå¤±åŠ¹ã™ã‚‹å ´åˆã€å¤‰æ›´ã‚’ä¿å­˜ã™ã‚‹ã«ã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«å†åº¦èªè¨¼ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ディレクトリã¸ã®å†åº¦èªè¨¼æ‰‹é †ã¯ã€æœ€åˆã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®<a href="#userauth">èªè¨¼</a>ã«ä½¿ç”¨ã—ãŸã‚‚ã®ã¨åŒã˜ã§ã™ã€‚</p>
+
+<h2><a name="incorrectauth"></a>ä¸é©åˆ‡ãªèªè¨¼ã«ã‚ˆã£ã¦ç™ºç”Ÿã™ã‚‹å•é¡Œ</h2>
+
+<p>Directory Serverã«èªè¨¼ã—ã¦ã„ãªã„å ´åˆã¯ã€åŒ¿åユーザã¨ã—ã¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ã‚¢ã‚¯ã‚»ã‚¹ã—ã¦ã„ã¾ã™ã€‚匿åユーザã¨ã—ã¦å®Ÿè¡Œå¯èƒ½ãªå‹•ä½œã®ã‚¿ã‚¤ãƒ—ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã«ã‚ˆã£ã¦è¨­å®šã•ã‚ŒãŸã‚¢ã‚¯ã‚»ã‚¹åˆ¶å¾¡ã«ã‚ˆã£ã¦ç•°ãªã‚Šã¾ã™ã€‚検索ãªã©ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªæ“作ã®å®Ÿè¡Œã‚’試ã¿ã‚‹ã¨ã€å¥‡å¦™ãªå‹•ä½œã‚’ã™ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚Directory Serverインタフェースã«ã‚ˆã£ã¦æ˜Žç¤ºçš„ã«ç¤ºã•ã‚Œã¦ã¯ã„ã¾ã›ã‚“ãŒã€ç™ºç”Ÿã™ã‚‹ç•°å¸¸ã¯ä¸é©åˆ‡ãªèªè¨¼ã«ã‚ˆã‚‹ã“ã¨ãŒè€ƒãˆã‚‰ã‚Œã¾ã™ã€‚インタフェース上ã§ã“ã®æƒ…報をæä¾›ã—ãªã„ã®ã¯ã€ãã‚Œã«ã‚ˆã£ã¦ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ãŒå¼±ã‚られるå¯èƒ½æ€§ãŒã‚ã‚‹ã‹ã‚‰ã§ã™ã€‚</p>
+
+<p>下表ã«ã¯ã€ä¸€èˆ¬çš„ãªå•é¡Œã®å…†å€™ã€è€ƒãˆã‚‰ã‚Œã‚‹åŽŸå› ã€ãŠã‚ˆã³å•é¡Œã®è§£æ±ºç­–ãŒãƒªã‚¹ãƒˆã•ã‚Œã¦ã„ã¾ã™ã€‚</p>
+
+<table border="2">
+ <tr>
+ <th width="30%"><b>兆候</b></th>
+ <th><b>原因</b></th>
+ <td width="30%"><b>解決策</b></td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">検索çµæžœãŒä½•ã‚‚ãªã„。</td>
+ <td valign="top">入力ã—ãŸæ¤œç´¢æ–‡å­—列ã«ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒãªã„ã‹ã€ã¾ãŸã¯ã“ã®ã‚¿ã‚¤ãƒ—ã®æ¤œç´¢å‹•ä½œã®å®Ÿè¡Œå‰ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®èªè¨¼ãŒç¾©å‹™ä»˜ã‘られã¦ã„ã¾ã™ã€‚</td>
+ <td valign="top" width="30%">ç•°ãªã£ãŸæ¤œç´¢å‹•ä½œã‚’試ã—ã¦ã¿ã¦ãã ã•ã„。ã¾ãŸã¯ã€å…¥åŠ›ã—ãŸåŸºæº–ã«ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒå¿…ãšã‚ã‚‹ã“ã¨ãŒåˆ†ã‹ã£ã¦ã„ã‚‹å ´åˆã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«<a href="#userauth">èªè¨¼</a>ã—ã¾ã™ã€‚</td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">検索çµæžœã«ã‚¨ãƒ³ãƒˆãƒªãŒæ¬ ã‘ã¦ã„ã‚‹ã‹ã€ã¾ãŸã¯æˆ»ã•ã‚ŒãŸã‚¨ãƒ³ãƒˆãƒªã‹ã‚‰å±žæ€§æƒ…å ±ãŒæ¬ ã‘ã¦ã„る。</td>
+ <td valign="top">æ­£ã—ãèªè¨¼ã—ã¦ã„ãªã„ã‹ã€ã‚ã‚‹ã„ã¯æƒ…å ±ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹æ¨©ãŒä»˜ä¸Žã•ã‚Œã¦ã„ã¾ã›ã‚“。ディレクトリ管ç†è€…ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリー全体ã¾ãŸã¯ä¸€éƒ¨ã§ã‚¨ãƒ³ãƒˆãƒªã¾ãŸã¯ç‰¹å®šã®ã‚¨ãƒ³ãƒˆãƒªå±žæ€§ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã«èªè¨¼ãŒå¿…è¦ã§ã‚ã‚‹ã“ã¨ã‚’指定ã§ãã¾ã™ã€‚ã“ã®å ´åˆã€æƒ…å ±ãŒå­˜åœ¨ã™ã‚‹ã‹ã€ã•ã‚‰ã«ãã®æƒ…å ±ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹æ¨©é™ã‚’ユーザãŒä¿æŒã—ã¦ã„ã‚‹ã‹ã¯Directory Serverã§ã¯ç¤ºã•ã‚Œã¾ã›ã‚“。代ã‚ã‚Šã«ã€æƒ…å ±ãŒã¾ã£ãŸã存在ã—ãªã„ã‹ã®ã‚ˆã†ã«å‹•ä½œã—ã¾ã™ã€‚ツリーã«ãŠã‘る特定ã®æƒ…報を表示ã§ããªãã¦ã‚‚ã€ãã‚ŒãŒå­˜åœ¨ã™ã‚‹ã“ã¨ã‚’知ã£ã¦ã„ã‚‹ã“ã¨ã¯ã€ã‚»ã‚­ãƒ¥ãƒªãƒ†ã‚£ä¸Šã®ãƒªã‚¹ã‚¯ã¨ãªã‚Šã†ã‚‹ã¨ã®é…æ…®ã‹ã‚‰ã€ã“ã®ã‚ˆã†ã«å‹•ä½œã™ã‚‹ã‚ˆã†ã«ãªã£ã¦ã„ã¾ã™ã€‚ </td>
+ <td valign="top" width="30%">æ­£ã—ã<a
+ href="#userauth">èªè¨¼ã•ã‚Œã¦ã„ã‚‹</a>ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。必è¦ãªãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªæƒ…å ±ã«ã‚¢ã‚¯ã‚»ã‚¹æ¨©ãŒã‚ã‚‹ã“ã¨ã‚’ディレクトリ管ç†è€…ã«ç¢ºèªã—ã¾ã™ã€‚</td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">完了後ã€å‹•ä½œã«å¤±æ•—ã™ã‚‹ã€‚</td>
+ <td valign="top">ä¸é©åˆ‡ãªèªè¨¼ã®ãŸã‚ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªãŒå‹•ä½œã«å¤±æ•—ã—ã¦ã„ã¾ã™ã€‚ã‚ãŸã‹ã‚‚インタフェースã®ãƒ•ã‚©ãƒ¼ãƒ ã®å‹•ä½œãŒå¤±æ•—ã—ã¦ã„るよã†ã«è¦‹ãˆã¾ã™ãŒã€ãƒ•ã‚©ãƒ¼ãƒ ã¯å‹•ä½œã‚’Directory Serverã«å‹•ä½œã‚’å—ã‘渡ã™ã ã‘ã§ã€å®Ÿéš›ã¯Directory ServerãŒå‹•ä½œã«å¤±æ•—ã—ã¦ã„ã¾ã™ã€‚Directory Serverインタフェースã¯ã€å˜ã«å‹•ä½œã®çµæžœã‚’報告ã™ã‚‹ã ã‘ã®ã‚‚ã®ã§ã™ã€‚ç¾åœ¨ã€LDAPプロトコルã§ã¯ã€å‹•ä½œãŒè©¦ã¿ã‚‰ã‚Œã‚‹å‰ã«èªè¨¼ãŒå¿…è¦ã§ã‚ã‚‹ã‹ãŒã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã«ã‚ˆã£ã¦èªè­˜ã§ããªã„よã†ã«ãªã£ã¦ã„ã‚‹ãŸã‚ã«ã€ã“ã®äº‹æ…‹ãŒç™ºç”Ÿã—ã¾ã™ã€‚ディレクトリ エントリã®ä½œæˆã¾ãŸã¯å¤‰æ›´ä¸­ã«èªè¨¼ãŒå¤±åŠ¹ã—ãŸå ´åˆã«é™ã‚Šã€ã“ã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ä½¿ç”¨ä¸­ã«ã“ã®äº‹æ…‹ãŒç™ºç”Ÿã™ã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚</td>
+ <td valign="top" width="30%">æ­£ã—ã<a
+ href="#userauth">èªè¨¼ã•ã‚Œã¦ã„ã‚‹</a>ã“ã¨ã¨èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ãªã„ã“ã¨ã‚’確èªã—ã¦ãã ã•ã„。</td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">èªè¨¼éŽç¨‹ä¸­ã«ã‚¨ãƒ³ãƒˆãƒªã®ãƒ†ãƒ¼ãƒ–ルãŒè¡¨ç¤ºã•ã‚Œã‚‹ã€‚</td>
+ <td valign="top">æ°åãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãŠã„ã¦å›ºæœ‰ã®ã‚‚ã®ã§ãªã„ã‹ã€ã¾ãŸã¯å…¥åŠ›ã—ãŸåå‰ãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«å­˜åœ¨ã—ã¾ã›ã‚“。</td>
+ <td valign="top" width="30%">エントリãŒãƒ†ãƒ¼ãƒ–ルã«è¡¨ç¤ºã•ã‚ŒãŸã‚‰ã€å¯¾å¿œã™ã‚‹ãƒªãƒ³ã‚¯ã‚’é¸æŠžã—〠<a href="#userauth">èªè¨¼</a>éŽç¨‹ã‚’継続ã—ã¾ã™ã€‚<p>エントリãŒãƒ†ãƒ¼ãƒ–ルã«è¡¨ç¤ºã•ã‚Œãªã„å ´åˆã¯ã€
+ <strong>[キャンセル]</strong>
+ をクリックã—ã€<a href="#userauth">èªè¨¼</a>
+ ã‚’å†åº¦è©¦ã¿ã¾ã™ã€‚ユーザIDã§ãªãã€æ°åã‚’å¿…ãšä½¿ç”¨ã—ã¦ãã ã•ã„。</p>
+ </td>
+ </tr>
+ <tr>
+ <td valign="top" width="30%">ユーザåã¯æ­£ã—ã„ã®ã«ã€èªè¨¼ã«å¤±æ•—ã—ãŸã€‚</td>
+ <td valign="top">パスワードãŒæ­£ã—ãã‚ã‚Šã¾ã›ã‚“。 <p>有効ãªãƒ¦ãƒ¼ã‚¶åã¨æ­£ã—ããªã„パスワードを入力ã—ã€ã—ã‹ã‚‚入力ã—ãŸãƒ¦ãƒ¼ã‚¶åãŒNTユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’示ã™å ´åˆã¯ã€Windowsãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã§èªè¨¼ãŒè©¦ã¿ã‚‰ã‚Œã¾ã™ã€‚</p>
+ <p>ãã‚ŒãŒæˆåŠŸã—ãªã‹ã£ãŸã‚Šã€å…¥åŠ›ã—ãŸãƒ¦ãƒ¼ã‚¶åãŒNTユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’示ã•ãªã„å ´åˆã¯ã€å†åº¦å®Ÿè¡Œã€ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‚’é–‰ã˜ã‚‹ã€ã¾ãŸã¯ãƒ˜ãƒ«ãƒ—ã®ã‚ªãƒ—ションãŒä¸Žãˆã‚‰ã‚Œã¾ã™ã€‚</p>
+ </td>
+ <td valign="top" width="30%"><strong>[Retry]</strong>
+ をクリックã—ã¦ãƒ‘スワードをå†åº¦å…¥åŠ›ã—ã¾ã™ã€‚</td>
+ </tr>
+</table>
+
+<p>&nbsp;</p>
+</body>
+</html>
+
+
diff --git a/ldap/clients/dsgw/html/manual/ja/contents.html b/ldap/clients/dsgw/html/manual/ja/contents.html
new file mode 100644
index 00000000..360311e8
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/ja/contents.html
@@ -0,0 +1,172 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+ <TITLE>Directory Serverインタフェースã®ç›®æ¬¡</TITLE>
+</HEAD>
+<BODY BGCOLOR="#FFFFFF">
+
+<H1>
+目次</H1>
+
+<H2>
+<A HREF="intro.htm">第1ç«  Directory Serverインタフェースã«ã¤ã„ã¦</A></H2>
+
+<H2>
+<A HREF="search.htm">第2ç«  ディレクトリ ツリーã®æ¤œç´¢ </A></H2>
+
+<DL>
+<DD>
+<A HREF="search.htm#standard">標準検索</A></DD>
+
+<DL>
+<DD>
+<A HREF="search.htm#Performing a Standard Search">[標準検索]ã®å®Ÿè¡Œ</A></DD>
+
+<DL>
+<DD>
+<A HREF="search.htm#Name">æ°åã®æ¤œç´¢</A></DD>
+
+<DD>
+<A HREF="search.htm#initials">イニシャルを伴ãªã†æ°åã®æ¤œç´¢</A></DD>
+
+<BR><A HREF="search.htm#phone">電話番å·ã®æ¤œç´¢</A>
+<BR><A HREF="search.htm#e-mail">é›»å­ãƒ¡ãƒ¼ãƒ« アドレスã®æ¤œç´¢</A>
+<BR><A HREF="search.htm#filter">検索フィルタã®ä½¿ç”¨</A></DL>
+</DL>
+
+<DD>
+<A HREF="search.htm#advanced">拡張検索</A></DD>
+
+<DL>
+<DD>
+<A HREF="search.htm#Performing an Advanced Search">[拡張検索]ã®å®Ÿè¡Œ</A></DD>
+
+<DD>
+<A HREF="search.htm#Advanced Search Examples">[拡張検索]ã®ä¾‹</A></DD>
+</DL>
+
+<DD>
+<A HREF="search.htm#results">検索çµæžœã®è¡¨ç¤º</A></DD>
+
+<DL>
+<DD>
+<A HREF="search.htm#nomatch">一致ãªã—</A></DD>
+
+<DD>
+<A HREF="search.htm#single">1件ã®ä¸€è‡´</A></DD>
+
+<DD>
+<A HREF="search.htm#multiple">複数ã®ä¸€è‡´</A></DD>
+
+<DD>
+<A HREF="search.htm#problems">ãã®ä»–ã®å•é¡Œ</A></DD>
+</DL>
+<A HREF="search.htm#vCard">vCardã®è¡¨ç¤º</A>
+<DL>
+<H2>
+<A HREF="add.htm">第3ç«  エントリã®è¿½åŠ </A></H2>
+
+<DL>
+<DD>
+<A HREF="add.htm#guidelines">æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã«é–¢ã™ã‚‹ã‚¬ã‚¤ãƒ‰ãƒ©ã‚¤ãƒ³</A></DD>
+
+<DL>
+<DD>
+<A HREF="add.htm#tree">ディレクトリ ツリー構造</A></DD>
+
+<DD>
+<A HREF="add.htm#DN">識別åã®æ§‹æ–‡</A></DD>
+
+<DD>
+<A HREF="add.htm#uniqueDN">固有ã®è­˜åˆ¥å</A></DD>
+</DL>
+
+<DD>
+<A HREF="add.htm#person">ユーザã®è¿½åŠ </A></DD>
+
+<DD>
+<A HREF="add.htm#NTperson">NTユーザã®è¿½åŠ </A></DD>
+
+<DD>
+<A HREF="add.htm#group">グループã®è¿½åŠ </A></DD>
+
+<DD>
+<A HREF="add.htm#NTgroup">NTグループã®è¿½åŠ </A></DD>
+
+<DD>
+<A HREF="add.htm#ou">組織å˜ä½ã®è¿½åŠ </A></DD>
+
+<DD>
+<A HREF="add.htm#o">組織ã®è¿½åŠ </A></DD>
+</DL>
+
+<H2>
+<A HREF="mod.htm">第4ç«  エントリã®ç·¨é›†</A></H2>
+
+<DL>
+<DD>
+<A HREF="mod.htm#people">ユーザã®ç·¨é›†</A></DD>
+
+<DL>
+<DL><A HREF="mod.htm#addmanager">[マãƒãƒ¼ã‚¸ãƒ£]ã¨[秘書]フィールドã¸ã®å€¤ã®è¿½åŠ 
+</A></DL>
+</DL>
+
+<DD>
+<A HREF="mod.htm#ntpeople">NTユーザã®ç·¨é›†</A></DD>
+
+<DD>
+<A HREF="mod.htm#groups">グループã®ç·¨é›†</A></DD>
+
+<DL>
+<DD>
+<A HREF="mod.htm#addowner">[åŒæ™‚å‚ç…§]ã€[所有者]ã€ãŠã‚ˆã³[グループ メンãƒãƒ¼]フィールドã¸ã®
+値ã®è¿½åŠ </A></DD>
+</DL>
+
+<DD>
+<A HREF="mod.htm#NTgroups">NTグループã®ç·¨é›†</A></DD>
+
+<DD>
+<A HREF="mod.htm#ou">組織å˜ä½ã®ç·¨é›†</A></DD>
+
+<DD>
+<A HREF="mod.htm#o">組織ã®ç·¨é›†</A></DD>
+
+<DD>
+<A HREF="mod.htm#rename">エントリåã®å¤‰æ›´</A></DD>
+
+<DD>
+<A HREF="mod.htm#delete">エントリã®å‰Šé™¤</A></DD>
+
+<DD>
+<A HREF="mod.htm#changepw">パスワードã®å¤‰æ›´</A></DD>
+</DL>
+
+<H2>
+<A HREF="auth.htm">第5ç«  èªè¨¼</A></H2>
+
+<DL>
+<DD>
+<A HREF="auth.htm#ustand">ディレクトリ アクセスã«ã¤ã„ã¦</A></DD>
+
+<DD>
+<A HREF="auth.htm#userauth">ディレクトリã¸ã®èªè¨¼</A></DD>
+
+<DD>
+<A HREF="auth.htm#logout">ディレクトリã‹ã‚‰ã®ãƒ­ã‚°ã‚¢ã‚¦ãƒˆ</A></DD>
+
+<DD>
+<A HREF="auth.htm#incorrectauth">ä¸é©åˆ‡ãªèªè¨¼ã«ã‚ˆã£ã¦ç™ºç”Ÿã™ã‚‹å•é¡Œ</A></DD>
+</DL>
+<P>
+<H2><A HREF="attribut.htm">属性</A></H2>
+
+</BODY>
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/manual/ja/filters.htm b/ldap/clients/dsgw/html/manual/ja/filters.htm
new file mode 100644
index 00000000..23288a6d
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/ja/filters.htm
@@ -0,0 +1,1062 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+
+<!-- HEAD-->
+ <TITLE>Netscape ディレクトリ インタフェィス 検索フィルタ</TITLE>
+
+</HEAD>
+
+<BODY>
+
+
+
+<P><A NAME="1001595"></A></P>
+
+
+
+<P><A NAME="1001596"></A></P>
+
+
+
+<P><A NAME="996824"></A></P>
+
+
+
+<H1>検索フィルタ</H1>
+
+
+
+<P><A NAME="997436"></A>本章ã§ã¯ã€æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ãŠã‚ˆã³<A HREF="filters.htm#1018239">検索ã®ä»•çµ„ã¿</A>を説明ã—ã¦ã„ã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="Search Filters"></A><A NAME="1018822"></A></P>
+
+
+
+<H2>検索フィルタ</H2>
+
+
+
+<P><A NAME="1018489"></A>検索範囲をé™å®šã™ã‚‹ãŸã‚ã«ã€ <A HREF="search.htm#1015771">[標準検索]</A>フィールドã«ç›´æŽ¥æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã‚’指定ã§ãã¾ã™ã€‚検索ã«ç­‰å·è¨˜å·(=)ãŒå«ã¾ã‚Œã‚‹å ´åˆã¯ã€[標準検索]ã§ã¯å€¤ãŒæ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã§ã‚ã‚‹ã‚‚ã®ã¨æƒ³å®šã•ã‚Œã€ã“ã®ãƒ•ã‚£ãƒ«ã‚¿ãŒç›´æŽ¥ä½¿ç”¨ã•ã‚Œã¦æ¤œç´¢ãŒå®Ÿè¡Œã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018092"></A>検索フィルタã§ã¯ã€[標準検索]ã®ãŸã‚ã«æˆ»ã•ã‚Œã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’é¸æŠžã™ã‚‹ã®ã«ã€å±žæ€§ã®å€¤ãŒä½¿ç”¨ã•ã‚Œã¾ã™ã€‚例ãˆã°ã€æ¬¡ã®æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã§ã¯ã€Babs Jensenã«ç­‰ã—ã„一般åã®æ¤œç´¢ãŒæŒ‡å®šã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018094"></A></P>
+
+
+
+<UL>
+
+<UL>
+
+<PRE>cn=babs jensen
+
+</PRE>
+
+</UL>
+
+</UL>
+
+
+
+<P><A NAME="Search filter syntax"></A><A NAME="1018095"></A></P>
+
+
+
+<H3>検索フィルタã®æ§‹æ–‡</H3>
+
+
+
+<P><A NAME="1018096"></A>検索フィルタã®åŸºæœ¬æ§‹æ–‡:</P>
+
+
+
+<P><A NAME="1018097"></A></P>
+
+
+
+<UL>
+
+<UL>
+
+<PRE><A HREF="filters.htm#1019127">属性</A> <A HREF="filters.htm#1019138">演算å­</A>値
+
+</PRE>
+
+</UL>
+
+</UL>
+
+
+
+<P><A NAME="1019085"></A>例: </P>
+
+
+
+<P><A NAME="1019086"></A></P>
+
+
+
+<UL>
+
+<UL>
+
+<PRE>employeenumber &gt;= 100
+
+</PRE>
+
+</UL>
+
+</UL>
+
+
+
+<P><A NAME="1019090"></A>上記ã®ä¾‹ã§ã¯ã€<TT>employeenumber</TT>ã¯å±žæ€§ã€<TT>&gt;=</TT> ã¯æ¼”ç®—å­ã€100ã¯å€¤ã§ã™ã€‚
+</P>
+
+
+
+<P><A NAME="1019104"></A><A HREF="filters.htm#1018167">ç•°ãªã£ãŸå±žæ€§ã®çµ„åˆã›</A>を使用ã™ã‚‹ãƒ•ã‚£ãƒ«ã‚¿ã‚‚定義ã§ãã¾ã™ã€‚ </P>
+
+
+
+<P><A NAME="Using attributes in a filter"></A><A NAME="1019127"></A></P>
+
+
+
+<H4>フィルタã«ãŠã‘る属性ã®ä½¿ç”¨</H4>
+
+
+
+<P><A NAME="1019162"></A>エントリã®æ¤œç´¢ã®éš›ã«ã€ãã®ã‚¿ã‚¤ãƒ—ã®ã‚¨ãƒ³ãƒˆãƒªã¨é–¢ä¿‚ã™ã‚‹å±žæ€§ã‚’指定ã§ãã¾ã™ã€‚例ãˆã°ã€ãƒ¦ãƒ¼ã‚¶ã«é–¢ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã™ã‚‹å ´åˆã€ç‰¹å®šã®ä¸€èˆ¬åã‚’æŒã¤ãƒ¦ãƒ¼ã‚¶ã®æ¤œç´¢ã«<TT>cn</TT>属性を使用ã§ãã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1019183"></A>ユーザã«é–¢ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®ä¾‹ã¨ã—ã¦æ¬¡ã®ã‚‚ã®ãŒå«ã¾ã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚</P>
+
+
+
+<UL>
+
+<P><A NAME="1019188"></A></P>
+
+
+
+<LI><TT>cn</TT> (ユーザã®ä¸€èˆ¬å) <A NAME="1019189"></A></LI>
+
+
+
+<LI><TT>telephonenumber</TT> (ユーザã®é›»è©±ç•ªå·) <A NAME="1019190"></A></LI>
+
+
+
+<LI><TT>employeenumber</TT> (ユーザã®ç¤¾å“¡ç•ªå·) <A NAME="1019191"></A></LI>
+
+
+
+<LI><TT>l</TT> (ユーザã®å ´æ‰€) </LI>
+
+</UL>
+
+
+
+<P><A NAME="1019184"></A>エントリã«é–¢ä¿‚ã™ã‚‹å±žæ€§ã®ãƒªã‚¹ãƒˆã«ã¤ã„ã¦ã¯ã€<A HREF="attribut.htm#1002619">付録A「エントリã¨å±žæ€§ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã€</A>ã‚’ã”覧ãã ã•ã„。 検索フィルタã«ãŠã„ã¦å†…部属性åを使用ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。</P>
+
+
+
+<P><A NAME="Using operators in a filter"></A><A NAME="1019138"></A></P>
+
+
+
+<H4>フィルタã«ãŠã‘る演算å­ã®ä½¿ç”¨</H4>
+
+
+
+<P><A NAME="1018153"></A>演算å­ã§ä»¥ä¸‹ã®ã‚¿ã‚¤ãƒ—ã®æ¤œç´¢ã‚’定義ã—ã¾ã™ã€‚</P>
+
+
+
+<TABLE BORDER=2 >
+
+<CAPTION></CAPTION>
+
+
+
+<TR>
+
+<TH><A NAME="1018101"></A><B>検索タイプ</B> </TH>
+
+
+
+<TH><A NAME="1018103"></A><B>演算å­</B> </TH>
+
+
+
+<TH><A NAME="1018105"></A><B>説明</B> </TH>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018107"></A>ç­‰å·</TD>
+
+
+
+<TD><A NAME="1018109"></A>= </TD>
+
+
+
+<TD><A NAME="1018111"></A>指定値ã«ä¸€è‡´ã™ã‚‹å±žæ€§ã‚’å«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã¾ã™ã€‚例:
+
+<UL>
+
+<P><A NAME="1019083"></A><TT>cn=Bob Johnson</TT></P>
+
+</UL>
+
+</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018113"></A>副文字列</TD>
+
+
+
+<TD><A NAME="1018115"></A>=&lt;文字列&gt;*&lt;文字列&gt; </TD>
+
+
+
+<TD><A NAME="1018117"></A>指定副文字をæŒã¤ 列属性をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã¾ã™ã€‚例:
+<UL>
+
+<P><A NAME="1018118"></A><TT>cn=Bob*</TT></P>
+
+
+
+<P><A NAME="1018119"></A><TT>cn=*Johnson</TT></P>
+
+
+
+<P><A NAME="1018120"></A><TT>cn=*John*</TT></P>
+
+
+
+<P><A NAME="1018121"></A><TT>cn=B*John</TT></P>
+
+</UL>
+
+</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018123"></A>大ãªã‚Šã¾ãŸã¯ç­‰ä¾¡</TD>
+
+
+
+<TD><A NAME="1018125"></A>&gt;= </TD>
+
+
+
+<TD><A NAME="1018127"></A>指定値より大ãã„ã‹ã€ç­‰ã—ã„属性をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã¾ã™ã€‚例:
+
+<UL>
+
+<P><A NAME="1018128"></A><TT>employeenumber &gt;= 100</TT></P>
+
+</UL>
+
+</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018130"></A>å°ãªã‚Šã¾ãŸã¯ç­‰ä¾¡</TD>
+
+
+
+<TD><A NAME="1018132"></A>&lt;= </TD>
+
+
+
+<TD><A NAME="1018134"></A>指定値よりå°ã•ã„ã‹ã€ç­‰ã—ã„属性をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã¾ã™ã€‚例:
+<UL>
+
+<P><A NAME="1018135"></A><TT>employeenumber &lt;= 100</TT></P>
+
+</UL>
+
+</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018137"></A>存在</TD>
+
+
+
+<TD><A NAME="1018139"></A>=* </TD>
+
+
+
+<TD><A NAME="1018141"></A>指定属性をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã¾ã™ã€‚例:
+
+<UL>
+
+<P><A NAME="1018142"></A><TT>cn=*</TT></P>
+
+
+
+<P><A NAME="1018143"></A><TT>telephonenumber=*</TT></P>
+
+
+
+<P><A NAME="1018144"></A><TT>manager=*</TT></P>
+
+</UL>
+
+</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018146"></A>è¿‘ä¼¼</TD>
+
+
+
+<TD><A NAME="1018148"></A>~= </TD>
+
+
+
+<TD><A NAME="1018150"></A>指定値ã«ã»ã¼ç­‰ã—ã„指定属性をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã¾ã™ã€‚例:
+
+<UL>
+
+<P><A NAME="1018151"></A><TT>cn~=surette</TT></P>
+
+
+
+<P><A NAME="1018152"></A><TT>l~=san fransico</TT></P>
+
+</UL>
+
+</TD>
+
+</TR>
+
+</TABLE>
+
+
+
+<TABLE>
+
+<TR>
+
+<TD></TD>
+
+</TR>
+
+</TABLE>
+
+
+
+<P><A NAME="1018160"></A>ã“れらã®æ¤œç´¢ã‚¿ã‚¤ãƒ—ã®è©³ç´°ã¯ã€<A HREF="filters.htm#1018239">「検索ã®ä»•çµ„ã¿ã€</A>ã‚’ã”覧ãã ã•ã„。
+
+</P>
+
+
+
+<P><A NAME="Using multiple search filters"></A><A NAME="1018167"></A></P>
+
+
+
+<H4>複数ã®æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã®ä½¿ç”¨</H4>
+
+
+
+<P><A NAME="1018168"></A>ブール演算å­ã‚’使用ã—ã¦ã€ç•°ãªã£ãŸæ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã‚’組ã¿åˆã‚ã›ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚接頭辞表記ã«ä»¥ä¸‹ã®æ¼”ç®—å­ã‚’使用ã§ãã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018169"></A></P>
+
+
+
+<UL>
+
+<PRE>(<I>ブール_演算å­</I>((<I>フィルタ</I>)(<I>フィルタ</I>)(<I>フィルタ</I>)...))
+
+</PRE>
+
+</UL>
+
+
+
+<P><A NAME="1018170"></A>ã“ã®å ´åˆã€ãƒ–ール_演算å­ã¯ã€ä»»æ„ã®<A HREF="filters.htm#1018173">ブール演算å­</A>ã§ã™ã€‚例: </P>
+
+
+
+<P><A NAME="1019218"></A></P>
+
+
+
+<UL>
+
+<PRE>(&amp;(ou=Marketing)(cn=Ray*))
+
+</PRE>
+
+</UL>
+
+
+
+<P><A NAME="1019216"></A>上記ã®ä¾‹ã§ã¯ã€ãƒ•ã‚£ãƒ«ã‚¿ã®çµ„åˆã›ã«ã‚ˆã£ã¦ã€çµ„ç¹”å˜ä½ãŒMarketing (<TT>ou=Marketing</TT>)ã§ã€ä¸€èˆ¬åãŒRay (<TT>cn=Ray*</TT>)ã§å§‹ã¾ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚And(<TT>&amp;</TT>)ã®ãƒ–ール演算å­ã¯ã€ã“ã®æ¼”ç®—å­ãŒæ¤œç´¢åŸºæº–を先行ã™ã‚‹æŽ¥é ­è¾žè¡¨è¨˜æ³•ã§ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1019228"></A>ã•ã‚‰ã«ã€ä»¥ä¸‹ã®ã‚ˆã†ã«ã€è¤‡é›‘ãªå¼ã‚’å½¢æˆã™ã‚‹ã®ã«ãƒ–ール演算å­ã‚’入れå­ã«ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018171"></A></P>
+
+
+
+<UL>
+
+<PRE>(ブール_演算å­(フィルタ)((ブール_演算å­(フィルタ)(フィルタ)))
+
+</PRE>
+
+</UL>
+
+
+
+<P><A NAME="Boolean operators"></A><A NAME="1018173"></A></P>
+
+
+
+<H4>ブール演算å­</H4>
+
+
+
+<P><A NAME="1018202"></A>検索フィルタã¨ã¨ã‚‚ã«ä½¿ç”¨ã§ãるブール演算å­: </P>
+
+
+
+<TABLE BORDER=2 >
+
+<CAPTION></CAPTION>
+
+
+
+<TR>
+
+<TH><A NAME="1018176"></A><B>演算å­</B> </TH>
+
+
+
+<TH><A NAME="1018178"></A><B>記å·</B> </TH>
+
+
+
+<TH><A NAME="1018180"></A><B>説明</B> </TH>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018182"></A>And </TD>
+
+
+
+<TD><A NAME="1018184"></A>&amp; </TD>
+
+
+
+<TD><A NAME="1018186"></A>æ–‡ãŒçœŸã§ã‚ã‚‹ãŸã‚ã«ã¯ã€ã™ã¹ã¦ã®æŒ‡å®šãƒ•ã‚£ãƒ«ã‚¿ãŒçœŸã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。例:
+
+<UL>
+
+<P><A NAME="1018187"></A><TT>(&amp;(フィルタ1)(フィルタ2)(フィルタ3)...)</TT></P>
+
+</UL>
+
+
+
+<P><A NAME="1019015"></A>エントリãŒä¸€è‡´ã™ã‚‹ãŸã‚ã«ã¯ã€ãƒ•ã‚£ãƒ«ã‚¿1ã€ãƒ•ã‚£ãƒ«ã‚¿2ã€ãŠã‚ˆã³ãƒ•ã‚£ãƒ«ã‚¿3ãŒã™ã¹ã¦çœŸã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。</P>
+
+</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018189"></A>Or </TD>
+
+
+
+<TD><A NAME="1018191"></A>| </TD>
+
+
+
+<TD><A NAME="1018193"></A>æ–‡ãŒçœŸã§ã‚ã‚‹ãŸã‚ã«ã¯ã€æœ€ä½Žä¸€ã¤ã®æŒ‡å®šãƒ•ã‚£ãƒ«ã‚¿ãŒçœŸã§ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。例:
+
+<UL>
+
+<P><A NAME="1018194"></A><TT>(|(フィルタ1)(フィルタ2)(フィルタ3)...)</TT></P>
+
+</UL>
+
+
+
+<P><A NAME="1019024"></A>フィルタ1ã€ãƒ•ã‚£ãƒ«ã‚¿2ã€ã¾ãŸã¯ãƒ•ã‚£ãƒ«ã‚¿3ã®ä¸€ã¤ã§ã‚‚一致ã™ã‚‹ã¨ã€ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018196"></A>Not </TD>
+
+
+
+<TD><A NAME="1018198"></A>! </TD>
+
+
+
+<TD><A NAME="1018200"></A>æ–‡ãŒçœŸã§ã‚ã‚‹ãŸã‚ã«ã¯ã€æŒ‡å®šã•ã‚ŒãŸæ–‡ãŒçœŸã§ã‚ã£ã¦ã¯ãªã‚Šã¾ã›ã‚“。一ã¤ã®ãƒ•ã‚£ãƒ«ã‚¿ã®ã¿ãŒNot演算å­ã«ã‚ˆã£ã¦å½±éŸ¿ã•ã‚Œã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。例:
+
+
+<UL>
+
+<P><A NAME="1018201"></A><TT>(!(フィルタ))</TT></P>
+
+</UL>
+
+
+
+<P><A NAME="1019025"></A>フィルタã«ä¸€è‡´ã—ãªã„エントリãŒæˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+</TD>
+
+</TR>
+
+</TABLE>
+
+
+
+<TABLE>
+
+<TR>
+
+<TD></TD>
+
+</TR>
+
+</TABLE>
+
+
+
+<P><A NAME="Search filter examples"></A><A NAME="1018203"></A></P>
+
+
+
+<H4>検索フィルタã®ä¾‹</H4>
+
+
+
+<P><A NAME="1018204"></A>マãƒãƒ¼ã‚¸ãƒ£å±žæ€§ã‚’å«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæ¬¡ã®ãƒ•ã‚£ãƒ«ã‚¿ã«ã‚ˆã£ã¦æ¤œç´¢ã•ã‚Œã¾ã™ã€‚ã“ã‚Œã¯å­˜åœ¨æ¤œç´¢ã¨ã‚‚呼ã°ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018205"></A></P>
+
+
+
+<PRE> manager=*
+
+</PRE>
+
+
+
+<P><A NAME="1018206"></A>Ray Kultgenã®ä¸€èˆ¬åã‚’å«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæ¬¡ã®ãƒ•ã‚£ãƒ«ã‚¿ã«ã‚ˆã£ã¦æ¤œç´¢ã•ã‚Œã¾ã™ã€‚ã“ã‚Œã¯ç­‰å·æ¤œç´¢ã¨ã—ã¦ã‚‚呼ã°ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018207"></A></P>
+
+
+
+<PRE> cn=Ray Kultgen
+
+</PRE>
+
+
+
+<P><A NAME="1018208"></A>Ray Kultgenã®ä¸€èˆ¬åã‚’å«ã¾ãªã„エントリãŒæ¬¡ã®ãƒ•ã‚£ãƒ«ã‚¿ã«ã‚ˆã£ã¦æˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018209"></A></P>
+
+
+
+<PRE> (!(cn=Ray Kultgen))
+
+</PRE>
+
+
+
+<P><A NAME="1018210"></A>X.500ã®å‰¯æ–‡å­—列をæŒã¤[description]属性をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæ¬¡ã®ãƒ•ã‚£ãƒ«ã‚¿ã«ã‚ˆã£ã¦æˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018211"></A></P>
+
+
+
+<PRE> description=*X.500*
+
+</PRE>
+
+
+
+<P><A NAME="1018212"></A>組織å˜ä½ãŒMarketingã§ã€[description]フィールドã«å‰¯æ–‡å­—列X.500ãŒå«ã¾ã‚Œãªã„エントリãŒæ¬¡ã®ãƒ•ã‚£ãƒ«ã‚¿ã«ã‚ˆã£ã¦æˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018213"></A></P>
+
+
+
+<PRE> (&amp;(ou=Marketing)(!(description=*X.500*)))
+
+</PRE>
+
+
+
+<P><A NAME="1018214"></A>組織å˜ä½ãŒMarketingã§ã€ãƒžãƒãƒ¼ã‚¸ãƒ£ãŒJulie Fulmerã¾ãŸã¯Cindy Zwaskaã§ã‚るエントリãŒæ¬¡ã®ãƒ•ã‚£ãƒ«ã‚¿ã«ã‚ˆã£ã¦æˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018215"></A></P>
+
+
+
+<PRE> (&amp;(ou=Marketing)(|(manager=&quot;cn=Julie
+Fulmer,ou=Marketing,o=Airius,c=US&quot;)(manager=&quot;cn=Cindy
+Zwaska,ou=Marketing,o=Airius,
+c=US&quot;)))
+
+</PRE>
+
+
+
+<P><A NAME="1018216"></A>ユーザを示ã•ãªã„エントリãŒæ¬¡ã®ãƒ•ã‚£ãƒ«ã‚¿ã«ã‚ˆã£ã¦æˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018217"></A></P>
+
+
+
+<PRE> (!(objectclass=person))
+
+</PRE>
+
+
+
+<P><A NAME="1018218"></A>ユーザ(person)を示ã•ãšã€ã—ã‹ã‚‚一般å(cn)ãŒãƒ—リンタ3bã«é¡žä¼¼ã—ãŸã‚¨ãƒ³ãƒˆãƒªãŒæ¬¡ã®ãƒ•ã‚£ãƒ«ã‚¿ã«ã‚ˆã£ã¦æˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018219"></A></P>
+
+
+
+<PRE> (&amp;(!(objectclass=person))(cn~=printer3b))
+
+</PRE>
+
+
+
+<P><A NAME="How searching works"></A><A NAME="1018239"></A></P>
+
+
+
+<H2>検索ã®ä»•çµ„ã¿</H2>
+
+
+
+<P><A NAME="1018240"></A></P>
+
+
+
+<BLOCKQUOTE>
+
+<P><B>注: </B></P>
+
+</BLOCKQUOTE>
+
+
+
+<P><A NAME="1019880"></A></P>
+
+
+
+<BLOCKQUOTE>
+
+<P>Directory Serverインタフェースã¯ã€å®Ÿéš›ã€Directory Serverã‹ã‚‰ç‹¬ç«‹ã—ã¦å‹•ä½œã™ã‚‹ãƒ•ã‚©ãƒ¼ãƒ ã¨CGIプログラムã®é›†ã¾ã‚Šã§ã™ã€‚ã“ã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã¯ã€Directory Serverã«å¯¾ã—ã¦LDAPクライアントã¨ã—ã¦å‹•ä½œã™ã‚‹ã‚‚ã®ã§ã™ã€‚</P>
+
+</BLOCKQUOTE>
+
+
+
+<P><A NAME="1019775"></A>以下ã«ã¯ã€Directory Serverを検索ã™ã‚‹éš›ã®ä»•çµ„ã¿ãŒèª¬æ˜Žã•ã‚Œã¦ã„ã¾ã™ã€‚</P>
+
+
+
+<OL>
+
+<P><A NAME="1018241"></A></P>
+
+
+
+<LI>フォームをé€ä¿¡ã™ã‚‹ã¨ã€Directory Serverã«æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ãŒé€ä¿¡ã•ã‚Œã¾ã™ã€‚ <A NAME="1018242"></A></LI>
+
+
+
+<LI>Directory Serverã§ã¯ã€æƒ…å ±ãŒãƒ­ãƒ¼ã‚«ãƒ« ディレクトリã«ã‚ã‚‹ã‹ã‚’確èªã™ã‚‹ãŸã‚ç€ä¿¡ã—ãŸè¦æ±‚ãŒãƒã‚§ãƒƒã‚¯ã•ã‚Œã¾ã™ã€‚ãã®æƒ…å ±ãŒãƒ­ãƒ¼ã‚«ãƒ« ディレクトリã«ãªãã€[Referral]パラメータãŒã‚µãƒ¼ãƒãƒ¼ã«è¨­å®šã•ã‚Œã¦ã„ã‚‹å ´åˆã¯ã€ãã®ã‚¯ãƒ©ã‚¤ã‚¢ãƒ³ãƒˆãŒè¦æ±‚ã®è¿½æ±‚を試ã¿ã‚‰ã‚Œã‚‹ä»–ã®Directory Serverã®URLãŒæˆ»ã•ã‚Œã¾ã™ã€‚<A NAME="1018244"></A></LI>
+
+
+
+<LI>Directory Serverã«ã‚ˆã£ã¦ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã‹ã‚‰ã‚¨ãƒ³ãƒˆãƒª リストãŒç”Ÿæˆã•ã‚Œã¾ã™ã€‚ 検索基準ã«ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒã‚ã‚‹ã‹ã©ã†ã‹å„候補エントリãŒãƒã‚§ãƒƒã‚¯ã•ã‚Œã¾ã™ã€‚一致エントリãŒæ¤œå‡ºã•ã‚Œã‚‹ãŸã³ã«ã€ãã‚ŒãŒDirectory Serverインタフェースã«æˆ»ã•ã‚Œã¾ã™ã€‚<A NAME="1019576"></A>Directory Serverã«ã‚ˆã£ã¦è©²å½“ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒã™ã¹ã¦ãƒã‚§ãƒƒã‚¯ã•ã‚Œã‚‹ã‹ã€ã¾ãŸã¯ä»¥ä¸‹ã®é™åº¦ã®ä¸€ã¤ã«é”ã™ã‚‹ã¾ã§ã€ã“ã®éŽç¨‹ãŒç¶™ç¶šã•ã‚Œã¾ã™ã€‚</LI>
+
+
+
+<UL>
+
+<P><A NAME="1018252"></A></P>
+
+
+
+<LI>検索ã«å¯¾ã—ã¦æˆ»ã•ã‚Œã‚‹ã“ã¨ãŒè¨±ã•ã‚Œã¦ã„る最大エントリ数<A NAME="1018259"></A></LI>
+
+
+
+<LI>許ã•ã‚Œã¦ã„る最高検索所è¦æ™‚é–“ <A NAME="1018266"></A></LI>
+
+
+
+<LI>検索中ã«ãƒã‚§ãƒƒã‚¯ã™ã‚‹ã“ã¨ãŒè¨±ã•ã‚Œã¦ã„る最大エントリ数
+
+</LI>
+
+</UL>
+
+</OL>
+
+
+
+<P><A NAME="1019628"></A>ディレクトリ管ç†è€…ãŒã“れらã®è¨­å®šã‚’構æˆã§ãã¾ã™ã€‚検索アルゴリズムã®è©³ç´°ã¯ã€ã€ŽNetscape Directory Server管ç†è€…用ガイドã€ã‚’ã”覧ãã ã•ã„。</P>
+
+
+
+<P><A NAME="1019776"></A>以下ã«ã¯ã€è¿‘似検索ãŠã‚ˆã³å‰¯æ–‡å­—列検索ã®ä»•çµ„ã¿ãŒèª¬æ˜Žã•ã‚Œã¦ã„ã¾ã™ã€‚ </P>
+
+
+
+<P><A NAME="How approximate ("></A><A NAME="1018301"></A></P>
+
+
+
+<H3>è¿‘ä¼¼(é¡žä¼¼)検索ã®ä»•çµ„ã¿</H3>
+
+
+
+<P><A NAME="1018302"></A>近似検索ã§ã¯å…¥åŠ›å€¤ã«é¡žä¼¼ã—ãŸèªžãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚[拡張検索]インタフェースã§ã¯ã€è¿‘似検索ã¯sounds like (é¡žä¼¼)検索タイプã«å¯¾å¿œã—ã¦ã„ã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1019677"></A>例ãˆã°ã€ã‚¨ãƒ³ãƒˆãƒªã«å±žæ€§å€¤cn=Robert E LeeãŒå«ã¾ã‚Œã‚‹ã¨ã—ã¾ã™ã€‚ 近似検索ã§ã¯ã€Robert Leeã€Robertã€ã¾ãŸã¯Leeを指定ã—ã¦ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã§ãã¾ã™ã€‚åŒæ§˜ã«ã€ San Fransico (l~=San Fransicoã®ã‚¹ãƒšãƒ«é–“é•ã„ã«æ³¨æ„)ã«ã»ã¼ç­‰ã—ã„場所ã®æ¤œç´¢ã§ã¯ã€San Francisco
+(l=San Francisco)ã«å®Œå…¨ã«ä¸€è‡´ã™ã‚‹å ´æ‰€ã‚’å«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018303"></A>Directory Serverã§ã¯ã€ã‚¨ãƒ³ãƒˆãƒªã®å„値ãŒä¸€é€£ã®èªžã¨ã—ã¦å‡¦ç†ã•ã‚Œã€å„語ã®è¡¨éŸ³ã‚³ãƒ¼ãƒ‰ãŒä½œæˆã•ã‚Œã¾ã™ã€‚ã¾ãŸã€è¿‘似検索ã«å€¤ã‚’入力ã™ã‚‹ã¨ã€ãã®å€¤ãŒä¸€é€£ã®è¡¨éŸ³ã‚³ãƒ¼ãƒ‰ã«ç¿»è¨³ã•ã‚Œã¾ã™ã€‚以下ã®å ´åˆã«ã‚¨ãƒ³ãƒˆãƒªãŒå•åˆã›ã«ä¸€è‡´ã™ã‚‹ã¨è¦‹ãªã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+<UL>
+
+<P><A NAME="1018305"></A></P>
+
+
+
+<LI>検索基準ã«ãŠã‘ã‚‹ã™ã¹ã¦ã®ã‚³ãƒ¼ãƒ‰ãŒç”Ÿæˆã•ã‚ŒãŸã‚¨ãƒ³ãƒˆãƒªã®ã‚³ãƒ¼ãƒ‰ã«å­˜åœ¨ã™ã‚‹å ´åˆ <A NAME="1018306"></A></LI>
+
+
+
+<LI>検索基準ã«ãŠã‘ã‚‹ã™ã¹ã¦ã®ã‚³ãƒ¼ãƒ‰ãŒç”Ÿæˆã•ã‚ŒãŸã‚¨ãƒ³ãƒˆãƒªã®ã‚³ãƒ¼ãƒ‰ã¨åŒã˜é †åºã§æŒ‡å®šã•ã‚Œã¦ã„ã‚‹å ´åˆ</LI>
+
+</UL>
+
+
+
+<P><A NAME="1018344"></A>例: </P>
+
+
+
+<TABLE BORDER=2 >
+
+<CAPTION></CAPTION>
+
+
+
+<TR>
+
+<TH><A NAME="1018309"></A><B>ディレクトリã«ãŠã‘ã‚‹åå‰<BR>
+
+(表音コード) </B></TH>
+
+
+
+<TH><A NAME="1018311"></A><B>検索文字列<BR>
+
+(表音コード) </B></TH>
+
+
+
+<TH><A NAME="1018313"></A><B>一致ã«é–¢ã™ã‚‹æ³¨é‡ˆ</B> </TH>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018315"></A>Alice B Sarette<BR>
+
+(ALS B SRT) </TD>
+
+
+
+<TD><A NAME="1018317"></A>Alice Sarette<BR>
+
+(ALS SRT) </TD>
+
+
+
+<TD><A NAME="1018319"></A>一致。コードãŒæ­£ã—ã„é †åºã§æŒ‡å®šã•ã‚Œã¦ã„ã¾ã™ã€‚
+
+</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018321"></A></TD>
+
+
+
+<TD><A NAME="1018323"></A>Alice Sarrette<BR>
+
+(ALS SRT) </TD>
+
+
+
+<TD><A NAME="1018325"></A>一致。Saretteã®ã‚¹ãƒšãƒ«ãŒé–“é•ã£ã¦ã„ã‚‹ã«ã‚‚é–¢ã‚らãšã€ã‚³ãƒ¼ãƒ‰ãŒæ­£ã—ã„é †åºã§æŒ‡å®šã•ã‚Œã¦ã„ã¾ã™ã€‚ </TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018327"></A></TD>
+
+
+
+<TD><A NAME="1018329"></A>Surette<BR>
+
+(SRT) </TD>
+
+
+
+<TD><A NAME="1018331"></A>一致。Saretteã®ã‚¹ãƒšãƒ«ãŒé–“é•ã£ã¦ã„ã‚‹ã«ã‚‚é–¢ã‚らãšã€ç”Ÿæˆã•ã‚ŒãŸã‚³ãƒ¼ãƒ‰ã«ã¯å…ƒã®åå‰ãŒå­˜åœ¨ã—ã¾ã™ã€‚</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018333"></A></TD>
+
+
+
+<TD><A NAME="1018335"></A>Bertha Sarette<BR>
+
+(BR0 SRT) </TD>
+
+
+
+<TD><A NAME="1018337"></A>一致ãªã—。コードBR0ã¯å…ƒã®åå‰ã«ã¯å­˜åœ¨ã—ã¾ã›ã‚“。</TD>
+
+</TR>
+
+
+
+<TR>
+
+<TD><A NAME="1018339"></A></TD>
+
+
+
+<TD><A NAME="1018341"></A>Sarette, Alice<BR>
+
+(SRT ALS) </TD>
+
+
+
+<TD><A NAME="1018343"></A>一致ãªã—ã€ã‚³ãƒ¼ãƒ‰ãŒæ­£ã—ã„é †åºã§æŒ‡å®šã•ã‚Œã¦ã„ã¾ã›ã‚“。</TD>
+
+</TR>
+
+</TABLE>
+
+
+
+<TABLE>
+
+<TR>
+
+<TD></TD>
+
+</TR>
+
+</TABLE>
+
+
+
+<P><A NAME="How substring searches work"></A><A NAME="1018345"></A></P>
+
+
+
+<H3>副文字列検索ã®ä»•çµ„ã¿</H3>
+
+
+
+<P><A NAME="1018346"></A>副文字列検索ã§ã¯ã€å…¥åŠ›ã—ãŸå€¤ã‚’å«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚[拡張検索]インタフェースã§ã¯ã€å‰¯æ–‡å­—列検索starts with(開始文字)ã€contains (å«æœ‰)ã€ãŠã‚ˆã³ends with (終了文字)ã®æ¤œç´¢ã«å¯¾å¿œã—ã¾ã™ã€‚</P>
+
+
+
+<P><A NAME="1018347"></A>例ãˆã°ã€</P>
+
+
+
+<UL>
+
+<UL>
+
+<P><A NAME="1018348"></A><TT>cn=*derson</TT><BR>
+
+</P>
+
+</UL>
+
+</UL>
+
+
+
+<P><A NAME="1018349"></A>ã®ãƒ•ã‚©ãƒ¼ãƒ ã®æ¤œç´¢ã§ã¯ã€ä»¥ä¸‹ã®æ–‡å­—列をå«ã‚€ä¸€èˆ¬åã«ä¸€è‡´ã—ã¾ã™ã€‚ </P>
+
+
+
+<P><A NAME="1018350"></A></P>
+
+
+
+<UL>
+
+<UL>
+
+<PRE>Bill Anderson
+
+Jill Anderson
+
+Steve Sanderson
+
+</PRE>
+
+</UL>
+
+</UL>
+
+
+
+<P><A NAME="1018351"></A>åŒæ§˜ã«ã€</P>
+
+
+
+<UL>
+
+<UL>
+
+<P><A NAME="1018352"></A><TT>telephonenumber= *555*</TT><BR>
+
+</P>
+
+</UL>
+
+</UL>
+
+
+
+<P><A NAME="1018353"></A>ã®æ¤œç´¢ã§ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãŠã„ã¦555ã‚’å«ã‚€é›»è©±ç•ªå·ã‚’æŒã¤ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã¾ã™ã€‚</P>
+
+
+
+</BODY>
+
+</HTML>
+
+
diff --git a/ldap/clients/dsgw/html/manual/ja/intro.htm b/ldap/clients/dsgw/html/manual/ja/intro.htm
new file mode 100644
index 00000000..484d980d
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/ja/intro.htm
@@ -0,0 +1,39 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+<!-- HEAD -->
+<title>Netscape Directory Serverインタフェースã«ã¤ã„ã¦</title>
+</head>
+
+<body>
+
+<h1>Directory Serverインタフェースã«ã¤ã„ã¦</h1>
+
+<p>Netscape Directory Serverã¯ã€ä¼æ¥­å…¨ä½“ã®ãƒ¦ãƒ¼ã‚¶ã¨æƒ…å ±ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ä¿å­˜ã€æ¤œç´¢ã€ãŠã‚ˆã³ç®¡ç†ã‚’ã™ã‚‹ãŸã‚ã«è¨­è¨ˆã•ã‚ŒãŸä¿¡é ¼æ€§ãŒé«˜ãæ‹¡å¼µå¯èƒ½ãªã‚µãƒ¼ãƒãƒ¼ã§ã™ã€‚Directory Serverを使用ã™ã‚‹ã¨ã€ä¼æ¥­ã®æƒ…報処ç†éƒ¨é–€ã¯ã€æƒ…報を一箇所ã‹ã‚‰åˆ¶å¾¡ã—ã¦ç®¡ç†ã§ãã‚‹ã¨åŒæ™‚ã«ã€ä¼æ¥­ã®ãƒ¦ãƒ¼ã‚¶ã¯è¤‡æ•°ã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ä¸Šã®å ´æ‰€ã‹ã‚‰ã“ã®æƒ…報をå–り出ã™ã“ã¨ãŒã§ãã¾ã™ã€‚</p>
+
+<p>Directory Serverã«ã‚ˆã‚Šã€ä¼æ¥­ã®ãƒ¦ãƒ¼ã‚¶æƒ…å ±ã¸ã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ãŒå¾—られã¾ã™ã€‚ã“ã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã‹ã‚‰ä»¥ä¸‹ã®ã“ã¨ãŒå®Ÿè¡Œã§ãã¾ã™ã€‚</p>
+
+<ul>
+<P>
+ <li><a href="search.htm#search">ユーザã¨ãƒªã‚½ãƒ¼ã‚¹ã«é–¢ã™ã‚‹æƒ…å ±ã«ã¤ã„ã¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã‚’検索ã§ãã¾ã™ã€‚</a> 例ãˆã°ã€ç¤¾å“¡ã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレスや電話番å·ãŒæ¤œç´¢ã§ãã¾ã™ã€‚ <a href="search.htm">「ディレクトリ ツリーã®æ¤œç´¢ã€</a>ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®æ¤œç´¢ã«ã¤ã„ã¦ã®è©³ç´°ãŒè¨˜è¼‰ã•ã‚Œã¦ã„ã¾ã™ã€‚</li>
+<P>
+ <li><a href="add.htm#adding">ディレクトリã«æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã‚’作æˆã§ãã¾ã™ã€‚</a>例ãˆã°ã€æ–°å…¥ç¤¾å“¡ã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレスや電話番å·ãªã©ãã®ç¤¾å“¡ã«é–¢ã™ã‚‹æƒ…報を追加ã§ãã¾ã™ã€‚通常ã€ã“ã®æ©Ÿèƒ½ã¯ã€Directory Serverã«é©åˆ‡ã«èªè¨¼ã—ãŸãƒ¦ãƒ¼ã‚¶ã¨ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã«ã‚ˆã‚Šæ›¸è¾¼ã¿è¨±å¯ã‚’付与ã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶å°‚用ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚ディレクトリã«æ–°è¦ãƒ¦ãƒ¼ã‚¶ã€ã‚°ãƒ«ãƒ¼ãƒ—ã€çµ„ç¹”å˜ä½ãŠã‚ˆã³çµ„織を追加ã™ã‚‹ã“ã¨ã«é–¢ã™ã‚‹è©³ç´°ã¯ã€<a href="add.htm">「エントリã®è¿½åŠ ã€
+</a>ã‚’ã”覧ãã ã•ã„。</li>
+
+
+<P>
+ <li><a href="mod.htm#editing">ディレクトリã®æ—¢å­˜ã‚¨ãƒ³ãƒˆãƒªã‚’変更ã§ãã¾ã™ã€‚</a>例ãˆã°ã€é©åˆ‡ãªãƒ‘ーミッションãŒã‚ã‚Œã°ã€ã‚¨ãƒ³ãƒˆãƒªå±žæ€§ã«å¯¾ã™ã‚‹æ—¢å­˜å€¤ã®å¤‰æ›´ã€ã‚¨ãƒ³ãƒˆãƒªå…¨ä½“ã®å‰Šé™¤ã€ã‚¨ãƒ³ãƒˆãƒªåã®å¤‰æ›´ã€ã¾ãŸã¯ã‚¨ãƒ³ãƒˆãƒª パスワードã®å¤‰æ›´ãªã©ã‚’実行ã§ãã¾ã™ã€‚通常ã€ã“ã®æ©Ÿèƒ½ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã‹ã‚‰æ›¸ãè¾¼ã¿æ¨©ã‚’与ãˆã‚‰ã‚Œã€Directory Serverã«é©åˆ‡ã«èªè¨¼ã—ãŸãƒ¦ãƒ¼ã‚¶å°‚用ã¨ãªã£ã¦ã„ã¾ã™ã€‚ユーザã€ã‚°ãƒ«ãƒ¼ãƒ—ã€çµ„ç¹”å˜ä½ã€ãŠã‚ˆã³çµ„ç¹”ã«é–¢ã™ã‚‹æƒ…報更新方法ã«ã¤ã„ã¦ã¯ã€<a href="mod.htm">「エントリã®ç·¨é›†ã€</a>ã‚’ã”覧ãã ã•ã„。</li>
+</P>
+ <li><a href="auth.htm#authenticating">Directory Serverã«èªè¨¼ã§ãã¾ã™ã€‚</a>Directory Serverã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã‹æ›¸ã込むãŸã‚ã®èªè¨¼å¿…è¦æ¡ä»¶ãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã«ã‚ˆã£ã¦å®šã‚られã¦ã„ã‚‹å ´åˆã¯ã€ãƒ¦ãƒ¼ã‚¶åã¨ãƒ‘スワードã®å…¥åŠ›ãŒå¿…è¦ãªå ´åˆã‚‚ã‚ã‚Šã¾ã™ã€‚正確ãªèªè¨¼å¿…è¦æ¡ä»¶ã¯ã€ã‚µã‚¤ãƒˆã«ã‚ˆã£ã¦ç•°ãªã‚Šã¾ã™ãŒã€é€šå¸¸ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãŠã‘るエントリã®è¿½åŠ ã€å¤‰æ›´ã€ã¾ãŸã¯å‰Šé™¤ã®éš›ã«é™ã‚Šã€èªè¨¼ãŒå¿…è¦ã¨ãªã‚Šã¾ã™ã€‚Directory Serverã¸ã®èªè¨¼ã«ã¤ã„ã¦ã®è©³ç´°ã¯ã€<a
+ href="auth.htm">「ディレクトリã¸ã®èªè¨¼ã€</a>ã‚’ã”覧ãã ã•ã„。</li>
+</ul>
+
+<p> </p>
+</body>
+</html>
+
+
diff --git a/ldap/clients/dsgw/html/manual/ja/mod.htm b/ldap/clients/dsgw/html/manual/ja/mod.htm
new file mode 100644
index 00000000..13e71bca
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/ja/mod.htm
@@ -0,0 +1,670 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<TITLE>ディレクトリ エントリã®è¿½åŠ </TITLE>
+</HEAD>
+<BODY>
+
+<H1><A NAME="editing"></A>エントリã®è¿½åŠ </H1>
+
+Directory Server インタフェースã§ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã«ã‚るエントリを編集ã§ãã¾ã™ã€‚<A HREF="search.htm">エントリを探ã—ã¦</A>ã€<A HREF="search.htm#results">表示ã•ã›ã¦ã‹ã‚‰</A>ã€[編集]ボタンをクリックã—ã¾ã™ã€‚
+
+<P>エントリã®ç·¨é›†ã‚’試ã¿ã‚‹å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«èªè¨¼ã™ã‚‹ã‚ˆã†ã«æ±‚ã‚るプロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚
+
+<P>以下を編集ã§ãã¾ã™ã€‚
+<UL>
+<LI>
+<A HREF="mod.htm#people">ユーザ</A></LI>
+
+<LI>
+<A HREF="mod.htm#ntpeople">NT ユーザ</A></LI>
+
+<LI>
+<A HREF="mod.htm#groups">グループ</A></LI>
+
+<LI>
+<A HREF="#NTgroups">NT グループ</A></LI>
+
+<LI>
+<A HREF="mod.htm#o">組織</A></LI>
+
+<LI>
+<A HREF="mod.htm#ou">組織å˜ä½</A></LI>
+</UL>
+
+<H2>
+<A NAME="people"></A>ユーザã®ç·¨é›†</H2>
+ユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作をã—ã¾ã™ã€‚
+<OL>
+<LI>
+<A HREF="search.htm#standard">[標準検索]</A>
+ã¾ãŸã¯ <A HREF="search.htm#advanced">[拡張検索]</A>を使ã£ã¦ã€ç›®çš„ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</LI>
+
+<LI>
+<A HREF="search.htm#results">エントリを表示ã•ã›ã¾ã™</A>。</LI>
+
+<LI>
+[ユーザã®ç·¨é›†] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+エントリã®ç·¨é›†ã‚’試ã¿ã‚‹å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«èªè¨¼ã™ã‚‹ã‚ˆã†ã«æ±‚ã‚るプロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€å„フィールドã«å¸Œæœ›ã®å€¤ã‚’入力ã—ã¾ã™ã€‚必須フィールドã«ã¯ã‹ãªã‚‰ãšå€¤ã‚’入力ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ユーザã®å¿…須フィールドã«ã¯æ¬¡ã®ã‚‚ã®ãŒã‚ã‚Šã¾ã™ã€‚</LI>
+
+<UL type="disc">
+<LI>
+<A HREF="attribut.htm#cn">[æ°å]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#sn">[姓]</A></LI>
+</UL>
+
+<LI>
+ã“ã“ã§ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’入力ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§ã“れらã®å€¤ã‚’変更ã™ã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚ユーザã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯ä»¥ä¸‹ã®ã‚‚ã®ãŒã‚ã‚Šã¾ã™ã€‚</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A HREF="attribut.htm#givenName">[åå‰]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#telephoneNumber">[電話番å·]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#mail">[é›»å­ãƒ¡ãƒ¼ãƒ« アドレス]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#facsimileTelephoneNumber">[ファックス]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#uid">[ユーザID]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#pager">[ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«]&nbsp;</A></TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#mobile">[æºå¸¯é›»è©±]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#businessCategory">[事業カテゴリ]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#title">[å½¹è·]&nbsp;</A></TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#ou">[組織å˜ä½]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#manager">[マãƒãƒ¼ã‚¸ãƒ£]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#roomNumber">[部屋番å·]&nbsp;</A></TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#secretary">[秘書]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#departmentNumber">[部門番å·]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#employeeNumber">[社員番å·]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#carLicense">[自動車ナンãƒãƒ¼ãƒ—レート番å·]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#postalAddress">[ä½æ‰€]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#labeledUri">[URL]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#userPassword">[パスワード]</A>&nbsp;</TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+対応ã™ã‚‹ [編集] ボタンをクリックã—ã¦ã€<A HREF="#addmanager">[マãƒãƒ¼ã‚¸ãƒ£] ã‚„ [秘書] フィールドã«å€¤ã‚’追加</A>ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+対応ã™ã‚‹ [編集] ボタンをクリックã—ã¦ã€<A HREF="#addowner">[å‚ç…§] フィールドã«å€¤ã‚’追加</A>ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+フィールドã®ç·¨é›†ãŒçµ‚ã‚ã£ãŸã‚‰ã€[変更ä¿å­˜] をクリックã—ã¾ã™ã€‚</LI>
+</OL>
+ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ã‚‰ã¯ä»¥ä¸‹ã®æ“作もå¯èƒ½ã§ã™ã€‚
+<UL>
+<LI>
+<A HREF="#rename">エントリåã®å¤‰æ›´</A></LI>
+
+<LI>
+<A HREF="mod.htm#delete">エントリã®å‰Šé™¤</A></LI>
+
+<LI>
+<A HREF="#changepw">パスワードã®å¤‰æ›´</A></LI>
+</UL>
+
+<H3><A NAME="addmanager"></A>[マãƒãƒ¼ã‚¸ãƒ£] 㨠[秘書] フィールドã¸ã®å€¤ã®è¿½åŠ </H3>
+
+[マãƒãƒ¼ã‚¸ãƒ£] ã¾ãŸã¯ [秘書] フィールド中㮠[編集] ボタンをクリックã™ã‚‹ã¨ã€è©²å½“ã™ã‚‹å±žæ€§å€¤ã‚’追加ã—ãŸã‚Šå‰Šé™¤ã™ã‚‹ãŸã‚ã®æ–°ã—ã„フォームãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚
+[マãƒãƒ¼ã‚¸ãƒ£] ã‚„ [秘書] ã®å±žæ€§ã¨ã—ã¦ãƒ¦ãƒ¼ã‚¶ã‚’追加ã™ã‚‹ãŸã‚ã«ã¯ã€ä»¥ä¸‹ã®æ‰‹é †ã«å¾“ã£ã¦ãã ã•ã„。
+
+<OL>
+<LI>
+テキスト ボックス中ã«ã€ç›®çš„ã®ãƒžãƒãƒ¼ã‚¸ãƒ£ã¾ãŸã¯ç§˜æ›¸ã®ã‚¨ãƒ³ãƒˆãƒªã‚’探ã™ãŸã‚ã«ä½¿ç”¨ã™ã‚‹æ¤œç´¢æ–‡å­—列を入力ã—ã¾ã™ã€‚以下ã®ã†ã¡ã€ã©ã‚Œã§ã‚‚入力ã—ã¦ãã ã•ã„。</LI>
+
+<UL type="disc">
+<LI>
+åå‰ã€‚æ°å全体ã¾ãŸã¯ä¸€éƒ¨ã‚’入力ã—ã¾ã™ã€‚ãã®æ¤œç´¢æ–‡å­—列ã«ä¸€è‡´ã™ã‚‹ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªãŒè¿”ã•ã‚Œã¾ã™ã€‚該当ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒè¦‹ã¤ã‹ã‚‰ãªã„å ´åˆã¯ã€æ¤œç´¢æ–‡å­—列をå«ã‚€ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªãŒè¿”ã•ã‚Œã¾ã™ã€‚検索文字列をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒè¦‹ã¤ã‹ã‚‰ãªã„å ´åˆã¯ã€æ¤œç´¢æ–‡å­—列ã«é¡žä¼¼ã—ãŸã‚¨ãƒ³ãƒˆãƒªãŒè¿”ã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ユーザ ID (ユーザ エントリを検索ã—ã¦ã„ã‚‹å ´åˆï¼‰</LI>
+
+<LI>
+電話番å·ã€‚電話番å·ã®ä¸€éƒ¨ã ã‘を入力ã™ã‚‹ã¨ã€ãã®æ¤œç´¢ç•ªå·ã§çµ‚ã‚ã‚‹ã™ã¹ã¦ã®é›»è©±ç•ªå·ãŒè¿”ã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+é›»å­ãƒ¡ãƒ¼ãƒ« アドレス。アットマーク(@)をå«ã‚“ã§ã„る文字列ã¯ã™ã¹ã¦é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã¨ã¿ãªã•ã‚Œã¾ã™ã€‚完全ã«ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒè¦‹ã¤ã‹ã‚‰ãªã„å ´åˆã¯ã€ãã®æ¤œç´¢æ–‡å­—列ã§å§‹ã¾ã‚‹ã™ã¹ã¦ã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレスãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+アスタリスク(*)を使ã†ã¨ã€ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã«ã‚ã‚‹ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªã‚„グループを表示ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+ä»»æ„ã®<A HREF="search.htm#filter">LDAP 検索フィルタ</A>。 ç­‰å· (=) ã‚’å«ã‚“ã§ã„る文字列ã¯ã™ã¹ã¦ã€æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã¨ã¿ãªã•ã‚Œã¾ã™ã€‚</LI>
+</UL>
+
+<LI>
+[検索ã—ã¦è¿½åŠ ]をクリックã—ã€ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’見ã¤ã‘ã¦ãƒªã‚¹ãƒˆã«è¿½åŠ ã—ã¾ã™ã€‚マãƒãƒ¼ã‚¸ãƒ£ã‚„秘書ã¨ã—ã¦æŒ‡å®šã—ãŸããªã„エントリãŒã‚ã‚‹å ´åˆã¯ã€[リストã‹ã‚‰å‰Šé™¤] 欄ã®ãƒœãƒƒã‚¯ã‚¹ã‚’クリックã—ã¾ã™ã€‚削除ã—ãŸã„エントリã«ä¸€è‡´ã™ã‚‹æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã‚’作æˆã—ã¦ã‹ã‚‰ã€[検索ã—ã¦å‰Šé™¤] をクリックã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+グループ メンãƒãƒ¼ã®ãƒªã‚¹ãƒˆãŒå®Œæˆã—ãŸã‚‰ã€[変更ä¿å­˜] をクリックã—ã¾ã™ã€‚ã“ã®æ™‚点ã§è¡¨ç¤ºã•ã‚Œã¦ã„るエントリãŒã€ãƒžãƒãƒ¼ã‚¸ãƒ£ã¾ãŸã¯ç§˜æ›¸å±žæ€§ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã®å€¤ã«ãªã£ã¦ã„ã¾ã™ã€‚</LI>
+</OL>
+
+<H2>
+<A NAME="ntpeople"></A>NT ユーザã®ç·¨é›†</H2>
+NT ユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作を行ã„ã¾ã™ã€‚
+<OL>
+<LI>
+<A HREF="search.htm#standard">[標準検索]</A>
+ã¾ãŸã¯ <A HREF="search.htm#advanced">[拡張検索]</A>を使ã£ã¦ã€ç›®çš„ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</LI>
+
+<LI>
+<A HREF="search.htm#results">エントリを表示ã•ã›ã¾ã™</A>。</LI>
+
+<LI>
+[NT ユーザã®ç·¨é›†] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+エントリã®ç·¨é›†ã‚’試ã¿ã‚‹å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«èªè¨¼ã™ã‚‹ã‚ˆã†ã«æ±‚ã‚るプロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€å„フィールドã«å¸Œæœ›ã®å€¤ã‚’入力ã—ã¾ã™ã€‚必須フィールドã«ã¯ã‹ãªã‚‰ãšå€¤ã‚’入力ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚NT ユーザã®å¿…須フィールドã«ã¯æ¬¡ã®ã‚‚ã®ãŒã‚ã‚Šã¾ã™ã€‚</LI>
+
+<UL type="disc">
+<LI>
+<A HREF="attribut.htm#cn">[æ°å]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#sn">[姓]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#ntUserDomainId">[NT ドメインå] </A></LI>
+
+<LI>
+<A HREF="attribut.htm#ntUserDomainId">[NT ユーザ ID]</A></LI>
+</UL>
+
+<LI>
+ã“ã“ã§ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’入力ã—ãŸã‚Šã€å¾Œã«ã“れらã®å€¤ã‚’変更ã™ã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚NT ユーザã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯æ¬¡ã®é€šã‚Šã§ã™ã€‚</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A HREF="attribut.htm#givenName">[åå‰]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#telephoneNumber">[電話番å·]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#mail">[é›»å­ãƒ¡ãƒ¼ãƒ« アドレス]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#facsimileTelephoneNumber">[ファックス]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#userPassword">[Directory Server パスワード] </A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#pager">[ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#mobile">[æºå¸¯é›»è©±]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#businessCategory">[事業カテゴリ]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#title">[å½¹è·]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#ou">[組織å˜ä½]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#manager">[マãƒãƒ¼ã‚¸ãƒ£]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#roomNumber">[部屋番å·]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#secretary">[秘書]&nbsp;</A></TD>
+
+<TD><A HREF="attribut.htm#departmentNumber">[部門番å·]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#employeeNumber">[社員番å·]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#carLicense">[自動車ナンãƒãƒ¼ãƒ—レート番å·]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#postalAddress">[ä½æ‰€]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#labeledUri">[URL]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#uid">[ユーザ ID]</A>&nbsp;</TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+<A HREF="attribut.htm#NTUserDelete">[ユーザを削除ã—ãŸå ´åˆã¯ NTアカウントを削除]</A> オプションã®å€¤ã‚’変更ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+対応ã™ã‚‹ [編集] ボタンをクリックã—ã¦ã€<A HREF="#addmanager"> [マãƒãƒ¼ã‚¸ãƒ£] ã‚„ [秘書] フィールドã«å€¤ã‚’追加</A>ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+対応ã™ã‚‹ [編集] ボタンをクリックã—ã¦ã€<A HREF="#addowner"> [å‚ç…§] フィールドã«å€¤ã‚’追加</A>ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+フィールドã®ç·¨é›†ãŒçµ‚ã‚ã£ãŸã‚‰ã€[変更ä¿å­˜] をクリックã—ã¾ã™ã€‚</LI>
+</OL>
+ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ã‚‰ã¯ä»¥ä¸‹ã‚‚実行ã§ãã¾ã™ã€‚
+<UL>
+<LI>
+<A HREF="#rename">エントリåã®å¤‰æ›´</A></LI>
+
+<LI>
+<A HREF="mod.htm#delete">エントリã®å‰Šé™¤</A></LI>
+
+<LI>
+<A HREF="#changepw">パスワードã®å¤‰æ›´</A></LI>
+</UL>
+
+<H2><A NAME="groups"></A>グループã®ç·¨é›†</H2>
+
+グループã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作を行ã„ã¾ã™ã€‚
+<OL>
+<LI>
+<A HREF="search.htm#standard">[標準検索]</A>
+ã¾ãŸã¯ <A HREF="search.htm#advanced">[拡張検索]</A>を使ã£ã¦ã€ç›®çš„ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</LI>
+
+<LI>
+<A HREF="search.htm#results">エントリを表示ã•ã›ã¾ã™</A>。</LI>
+
+<LI>
+[グループã®ç·¨é›†] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+エントリã®ç·¨é›†ã‚’試ã¿ã‚‹å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«èªè¨¼ã™ã‚‹ã‚ˆã†ã«æ±‚ã‚るプロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+グループã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€å„フィールドã«ç·¨é›†ã—ãŸå€¤ã‚’入力ã—ã¾ã™ã€‚必須フィールドã§ã‚ã‚‹<A HREF="attribut.htm#cn"> [åå‰] </A>ã«ã¯ã‹ãªã‚‰ãšå€¤ã‚’入力ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚
+
+<LI>
+ã“ã“ã§ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’入力ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§ã“れらã®å€¤ã‚’変更ã™ã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚グループã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯æ¬¡ã®ã‚‚ã®ãŒã‚ã‚Šã¾ã™ã€‚</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#owner">[所有者]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#member">[グループ メンãƒãƒ¼]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]</A></TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+対応ã™ã‚‹ [編集] ボタンをクリックã—ã¦ã€<A HREF="#addowner"> [å‚ç…§]ã€[所有者] ãŠã‚ˆã³ [秘書] フィールドã«å€¤ã‚’追加</A>ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+フィールドã®ç·¨é›†ãŒçµ‚ã‚ã£ãŸã‚‰ã€[変更ä¿å­˜] をクリックã—ã¾ã™ã€‚</LI>
+</OL>
+ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ã‚‰ã¯ä»¥ä¸‹ã®æ“作も行ãˆã¾ã™ã€‚
+<UL>
+<LI>
+<A HREF="#rename">エントリåã®å¤‰æ›´</A></LI>
+
+<LI>
+<A HREF="mod.htm#delete">エントリã®å‰Šé™¤</A></LI>
+</UL>
+
+<H3><A NAME="addowner"></A>[所有者]ã€[å‚ç…§] ãŠã‚ˆã³ [グループ メンãƒãƒ¼] フィールドã¸ã®å€¤ã®è¿½åŠ </H3>
+
+[所有者]ã€[å‚ç…§] ã¾ãŸã¯ [グループ メンãƒãƒ¼] フィールド㮠[編集] ボタンをクリックã™ã‚‹ã¨ã€ãƒ¡ãƒ³ãƒãƒ¼ã‚’追加ã—ãŸã‚Šå‰Šé™¤ã™ã‚‹ãŸã‚ã®æ–°ã—ã„フォームãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚[所有者]ã€[å‚ç…§]ã€ã¾ãŸã¯[グループ メンãƒãƒ¼]ã¯å€‹äººã¾ãŸã¯ã‚°ãƒ«ãƒ¼ãƒ—ã§ã™ã€‚ã¤ã¾ã‚Šã€[所有者]ã€[å‚ç…§]ã€ã¾ãŸã¯[グループ メンãƒãƒ¼]ã¨ã—ã¦ã‚°ãƒ«ãƒ¼ãƒ—を追加ã™ã‚‹å ´åˆã€ã‚°ãƒ«ãƒ¼ãƒ—ã«å±žã™ã‚‹ãƒ¦ãƒ¼ã‚¶ã¯ã™ã¹ã¦ãƒªã‚¹ãƒˆã®ãƒ¡ãƒ³ãƒãƒ¼ã«ãªã‚Šã¾ã™ã€‚例ãˆã°ã€Barbara Jensen ãŒãƒžãƒ¼ã‚±ãƒ†ã‚£ãƒ³ã‚° マãƒãƒ¼ã‚¸ãƒ£ グループã®ãƒ¡ãƒ³ãƒãƒ¼ã§ã€ãƒžãƒ¼ã‚±ãƒ†ã‚£ãƒ³ã‚° マãƒãƒ¼ã‚¸ãƒ£ グループをマーケティング人事グループã®ãƒ¡ãƒ³ãƒãƒ¼ã«ã—ãŸå ´åˆã€Barbara Jensenもマーケティング人事グループã®ãƒ¡ãƒ³ãƒãƒ¼ã«ãªã‚Šã¾ã™ã€‚[グループ メンãƒãƒ¼]ã€[所有者]ã€ã¾ãŸã¯[å‚ç…§]を追加ã™ã‚‹ãŸã‚ã«ã¯ã€ä»¥ä¸‹ã®æ‰‹é †ã«å¾“ã£ã¦ãã ã•ã„。
+<OL>
+<LI>
+リストã«ãƒ¦ãƒ¼ã‚¶ エントリを追加ã™ã‚‹å ´åˆã¯ã€[ユーザ]ãŒæœ€åˆã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãƒœãƒƒã‚¯ã‚¹ã«è¡¨ç¤ºã•ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¾ã™ã€‚グループã«ã‚°ãƒ«ãƒ¼ãƒ— エントリを追加ã™ã‚‹å ´åˆã¯ã€[グループ]ãŒè¡¨ç¤ºã•ã‚Œã¦ã„ã‚‹ã“ã¨ã‚’確èªã—ã¾ã™ã€‚</LI>
+
+<LI>
+2番目ã®ãƒ€ã‚¤ã‚¢ãƒ­ã‚°ãƒœãƒƒã‚¯ã‚¹ã«æ¤œç´¢æ–‡å­—列を入力ã—ã¾ã™ã€‚以下ã®ã†ã¡ã€ã©ã‚Œã§ã‚‚入力ã—ã¦ãã ã•ã„。</LI>
+
+<UL type="disc">
+<LI>
+åå‰ã€‚æ°å全体ã¾ãŸã¯ä¸€éƒ¨ã‚’入力ã—ã¾ã™ã€‚ãã®æ¤œç´¢æ–‡å­—列ã«ä¸€è‡´ã™ã‚‹ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªãŒè¿”ã•ã‚Œã¾ã™ã€‚該当ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒè¦‹ã¤ã‹ã‚‰ãªã„å ´åˆã¯ã€æ¤œç´¢æ–‡å­—列をå«ã‚€ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªãŒè¿”ã•ã‚Œã¾ã™ã€‚検索文字列をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªãŒè¦‹ã¤ã‹ã‚‰ãªã„å ´åˆã¯ã€æ¤œç´¢æ–‡å­—列ã«é¡žä¼¼ã—ãŸã‚¨ãƒ³ãƒˆãƒªãŒè¿”ã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ユーザ ID (ユーザ エントリを検索ã—ã¦ã„ã‚‹å ´åˆï¼‰</LI>
+
+<LI>
+電話番å·ã€‚電話番å·ã®ä¸€éƒ¨ã ã‘を入力ã™ã‚‹ã¨ã€ãã®æ¤œç´¢ç•ªå·ã§çµ‚ã‚ã‚‹ã™ã¹ã¦ã®é›»è©±ç•ªå·ãŒè¿”ã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+é›»å­ãƒ¡ãƒ¼ãƒ« アドレス。アットマーク(@)をå«ã‚“ã§ã„る文字列ã¯ã™ã¹ã¦é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã¨ã¿ãªã•ã‚Œã¾ã™ã€‚完全ã«ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒè¦‹ã¤ã‹ã‚‰ãªã„å ´åˆã¯ã€ãã®æ¤œç´¢æ–‡å­—列ã§å§‹ã¾ã‚‹ã™ã¹ã¦ã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレスãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+アスタリスク(*)を使ã†ã¨ã€ç¾åœ¨ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªä¸­ã«ã‚ã‚‹ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªã‚„グループを表示ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+ä»»æ„ã®<A HREF="search.htm#filter">LDAP 検索フィルタ</A>ã€‚ç­‰å· (=) ã‚’å«ã‚“ã§ã„る文字列ã¯ã™ã¹ã¦ã€æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã¨ã¿ãªã•ã‚Œã¾ã™ã€‚</LI>
+</UL>
+
+<LI>
+[検索ã—ã¦è¿½åŠ ]をクリックã—ã€ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’見ã¤ã‘ã¦ãƒªã‚¹ãƒˆã«è¿½åŠ ã—ã¾ã™ã€‚リストã«å«ã‚ãŸããªã„エントリãŒã‚ã‚‹å ´åˆã¯ã€[リストã‹ã‚‰å‰Šé™¤] 欄ã®ãƒœãƒƒã‚¯ã‚¹ã‚’クリックã—ã¾ã™ã€‚削除ã—ãŸã„エントリã«ä¸€è‡´ã™ã‚‹æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã‚’作æˆã—ã¦ã‹ã‚‰ã€[検索ã—ã¦å‰Šé™¤] をクリックã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+グループ メンãƒãƒ¼ã®ãƒªã‚¹ãƒˆãŒå®Œæˆã—ãŸã‚‰ã€[変更ä¿å­˜] をクリックã—ã¾ã™ã€‚ã“ã®æ™‚点ã§è¡¨ç¤ºã•ã‚Œã¦ã„るエントリãŒã€ãƒªã‚¹ãƒˆã«åŠ ãˆã‚‰ã‚Œã¾ã™ã€‚</LI>
+</OL>
+
+<H2>
+<A NAME="NTgroups"></A>NT グループã®ç·¨é›†</H2>
+NT グループã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作を行ã„ã¾ã™ã€‚
+<OL>
+<LI>
+<A HREF="search.htm#standard">[標準検索]</A>
+ã¾ãŸã¯ <A HREF="search.htm#advanced">[拡張検索]</A>を使ã£ã¦ã€ç›®çš„ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</LI>
+
+<LI>
+<A HREF="search.htm#results">エントリを表示ã•ã›ã¾ã™</A>。</LI>
+
+<LI>
+[NT グループã®ç·¨é›†] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+エントリã®ç·¨é›†ã‚’試ã¿ã‚‹å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«èªè¨¼ã™ã‚‹ã‚ˆã†ã«æ±‚ã‚るプロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+ãã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€å„フィールドã«ç·¨é›†ã—ãŸå€¤ã‚’入力ã—ã¾ã™ã€‚必須フィールドã«ã¯ã‹ãªã‚‰ãšå€¤ã‚’入力ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚NT グループã®å¿…須フィールドã«ã¯æ¬¡ã®ã‚‚ã®ãŒã‚ã‚Šã¾ã™ã€‚</LI>
+
+<UL type="disc">
+<LI>
+<A HREF="attribut.htm#cn">[åå‰]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#ntGroupId">[NT グループå]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#ntGroupDomainId">[NT ドメインå]</A></LI>
+
+<LI>
+<A HREF="attribut.htm#ntGroupType">[NTグループ タイプ]</A></LI>
+
+</UL>
+
+<LI>
+ã“ã“ã§ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’入力ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§ã“れらã®å€¤ã‚’変更ã™ã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚NT グループã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯æ¬¡ã®ã‚‚ã®ãŒã‚ã‚Šã¾ã™ã€‚</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#owner">[所有者]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#l">[言語情報]</A></TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#member">[グループ メンãƒãƒ¼]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]</A></TD>
+
+<TD><A HREF="attribut.htm#ou">[組織å˜ä½]</A></TD>
+</TR>
+</TABLE></CENTER>
+&nbsp;
+<LI>
+<A HREF="attribut.htm#ntGroupDeleteGroup">[グループを削除ã—ãŸå ´åˆã¯ NTグループアカウントを削除]</A> オプションã®å€¤ã‚’変更ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+対応ã™ã‚‹ [編集] ボタンをクリックã—ã¦ã€<A HREF="#addmanager"> [å‚ç…§]ã€[所有者]ã€ãŠã‚ˆã³ [グループ メンãƒãƒ¼] フィールドã«å€¤ã‚’追加</A>ã§ãã¾ã™ã€‚</LI>
+
+<LI>
+編集ãŒçµ‚ã‚ã£ãŸã‚‰ã€[変更ä¿å­˜] をクリックã—ã¾ã™ã€‚</LI>
+</OL>
+ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ã‚‰ã¯ä»¥ä¸‹ã®æ“作も行ãˆã¾ã™ã€‚
+<UL>
+<LI>
+<A HREF="#rename">エントリåã®å¤‰æ›´</A></LI>
+
+<LI>
+<A HREF="mod.htm#delete">エントリã®å‰Šé™¤</A></LI>
+</UL>
+
+<H2>
+<A NAME="ou"></A>組織å˜ä½ã®ç·¨é›†</H2>
+組織å˜ä½ã‚’編集ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作を行ã„ã¾ã™ã€‚
+<OL>
+<LI>
+<A HREF="search.htm#standard">[標準検索]</A>
+ã¾ãŸã¯ <A HREF="search.htm#advanced">[拡張検索]</A>を使ã£ã¦ã€ç›®çš„ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</LI>
+
+<LI>
+<A HREF="search.htm#results">エントリを表示ã•ã›ã¾ã™</A>。</LI>
+
+<LI>
+[組織å˜ä½ã®ç·¨é›†] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+エントリã®ç·¨é›†ã‚’試ã¿ã‚‹å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«èªè¨¼ã™ã‚‹ã‚ˆã†ã«æ±‚ã‚るプロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+組織å˜ä½ã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€å„フィールドã«ç·¨é›†ã—ãŸå€¤ã‚’入力ã—ã¾ã™ã€‚必須フィールドã«ã¯ã‹ãªã‚‰ãšå€¤ã‚’入力ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</LI>
+
+<LI>
+組織å˜ä½ã®å¿…須フィールドã¯ã€<A HREF="attribut.htm#ou">[å˜ä½å]</A>ã§ã™ã€‚</LI>
+
+<LI>
+ã“ã“ã§ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’入力ã—ãŸã‚Šã€å¾Œã«ã“れらã®å€¤ã‚’変更ã™ã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚組織å˜ä½ã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯æ¬¡ã®é€šã‚Šã§ã™ã€‚</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#telephoneNumber">[電話番å·]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#businessCategory">[事業カテゴリ]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#facsimileTelephoneNumber">[ファックス]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#l">[場所]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#postalAddress">[ä½æ‰€]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]</A>&nbsp;</TD>
+
+<TD>&nbsp;</TD>
+
+<TD>&nbsp;</TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+編集ãŒçµ‚ã‚ã£ãŸã‚‰ã€[変更ä¿å­˜] をクリックã—ã¾ã™ã€‚</LI>
+</OL>
+ã“ã®ã‚¦ã‚£ãƒ³ãƒ‰ã‚¦ã‹ã‚‰ã¯ä»¥ä¸‹ã‚‚実行ã§ãã¾ã™ã€‚
+<UL>
+<LI>
+<A HREF="#rename">エントリåã®å¤‰æ›´</A></LI>
+
+<LI>
+<A HREF="mod.htm#delete">エントリã®å‰Šé™¤</A></LI>
+</UL>
+
+<H2>
+<A NAME="o"></A>組織ã®ç·¨é›†</H2>
+組織ã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作をã—ã¾ã™ã€‚
+<OL>
+<LI>
+<A HREF="search.htm#standard">[標準検索]</A>
+ã¾ãŸã¯ <A HREF="search.htm#advanced">[拡張検索]</A>を使ã£ã¦ã€ç›®çš„ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</LI>
+
+<LI>
+<A HREF="search.htm#results">エントリを表示ã•ã›ã¾ã™</A>。</LI>
+
+<LI>
+[組織ã®ç·¨é›†] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+エントリã®ç·¨é›†ã‚’試ã¿ã‚‹å‰ã«<A HREF="auth.htm#userauth">èªè¨¼</A>ã—ã¦ã„ãªã‹ã£ãŸã‚Šã€èªè¨¼ãŒå¤±åŠ¹ã—ã¦ã„ã‚‹å ´åˆã¯ã€å…ˆã«é€²ã‚€å‰ã«èªè¨¼ã™ã‚‹ã‚ˆã†ã«æ±‚ã‚るプロンプトãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</LI>
+
+<LI>
+組織ã®ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹ã«ã¯ã€å„フィールドã«ç·¨é›†ã—ãŸå€¤ã‚’入力ã—ã¾ã™ã€‚必須フィールドã«ã¯ã‹ãªã‚‰ãšå€¤ã‚’入力ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</LI>
+
+<LI>
+組織ã®å¿…須フィールドã¯ã€<A HREF="attribut.htm#o">[組織å]</A>ã§ã™ã€‚</LI>
+
+<LI>
+ã“ã“ã§ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å€¤ã‚’入力ã™ã‚‹ã“ã¨ã‚‚ã€å¾Œã§ã“れらã®å€¤ã‚’変更ã™ã‚‹ã“ã¨ã‚‚å¯èƒ½ã§ã™ã€‚組織ã®ã‚ªãƒ—ションã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯æ¬¡ã®é€šã‚Šã§ã™ã€‚</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A HREF="attribut.htm#description">[説明]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#telephoneNumber">[電話番å·]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#businessCategory">[事業カテゴリ]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#facsimileTelephoneNumber">[ファックス]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#l">[場所]</A>&nbsp;</TD>
+
+<TD><A HREF="attribut.htm#postalAddress">[ä½æ‰€]</A>&nbsp;</TD>
+</TR>
+
+<TR>
+<TD><A HREF="attribut.htm#seeAlso">[å‚ç…§]</A>&nbsp;</TD>
+
+<TD>&nbsp;</TD>
+
+<TD>&nbsp;</TD>
+</TR>
+</TABLE></CENTER>
+&nbsp;
+<LI>
+編集ãŒçµ‚ã‚ã£ãŸã‚‰ã€[変更ä¿å­˜] をクリックã—ã¾ã™ã€‚</LI>
+</OL>
+
+<H2><A NAME="rename"></A>エントリåã®å¤‰æ›´</H2>
+エントリåを変更ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã‚’実行ã—ã¦ãã ã•ã„。
+<OL>
+<LI>
+<A HREF="search.htm#standard">[標準検索]</A>
+ã¾ãŸã¯ <A HREF="search.htm#advanced">[拡張検索]</A>を使ã£ã¦ã€ç›®çš„ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</LI>
+
+<LI>
+<A HREF="search.htm#results">エントリを表示ã•ã›ã¾ã™</A>。</LI>
+
+<LI>
+[編集] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+エントリã®æ–°ã—ã„一般åを入力ã—ã¾ã™ã€‚</LI>
+
+<LI>
+[変更ä¿å­˜]をクリックã—ã¾ã™ã€‚</LI>
+</OL>
+エントリåã®å¤‰æ›´ã«é–¢ã™ã‚‹ä»¥ä¸‹ã®è¦å‰‡ã«æ³¨æ„ã—ã¦ãã ã•ã„。
+<UL>
+<LI>
+エントリã®<A HREF="add.htm#DN">識別å</A>ã®ä¸€ç•ªå·¦ã®å€¤ã«é™ã‚Šå¤‰æ›´ã§ãã¾ã™ã€‚ã“ã‚Œã¯ã€å®Ÿè³ªçš„ã«ã‚¨ãƒ³ãƒˆãƒªåã«é™ã‚Šå¤‰æ›´ã§ãã‚‹ã“ã¨ã‚’æ„味ã—ã¦ã„ã¾ã™ã€‚ã“ã®æ–¹å¼ã‚’使ã£ã¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®åˆ¥ã®ãƒ–ランãƒã«ã‚¨ãƒ³ãƒˆãƒªã‚’移動ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。例ãˆã°ã€</LI>
+
+<PRE>uid=tandrew, ou=Accounting, o=Airius.com</PRE>
+
+ã® DN ã‚’æŒã¤ã‚¨ãƒ³ãƒˆãƒªãŒã‚ã‚‹å ´åˆã¯ã€ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®ãƒ¦ãƒ¼ã‚¶ ID (uid) 部分ã®åå‰ã«é™ã‚Šå¤‰æ›´ã§ãã¾ã™ã€‚ã—ã‹ã—ã€Marketing ã®ã‚µãƒ–ツリーã«ãƒ¦ãƒ¼ã‚¶ tandrew を移動ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。移動ã™ã‚‹ã«ã¯ã€Marketing ã®ã‚µãƒ–ツリー㫠tandrew ã®æ–°è¦ã‚¨ãƒ³ãƒˆãƒªã‚’作æˆã—ã¦ã‹ã‚‰ã€Accounting ã®ãƒ„リーã«ã‚ã‚‹å…ƒã®ã‚¨ãƒ³ãƒˆãƒªã‚’削除ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚
+<LI>
+組織å˜ä½ã®ãƒ„リーã®ä¸‹ã«ã‚¨ãƒ³ãƒˆãƒªãŒã‚ã‚‹å ´åˆã¯ãã®çµ„ç¹”å˜ä½ã®åå‰ã‚’変更ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。ディレクトリ ツリーã®ãƒ–ランムãƒã‚¤ãƒ³ãƒˆåを変更ã™ã‚‹ã«ã¯ã€ãƒ„リー内ã®ãã®ãƒã‚¤ãƒ³ãƒˆã®ä¸‹ã«ã‚ã‚‹ã‚‚ã®ã™ã¹ã¦ã‚’削除ã—ã¦ã‹ã‚‰ã€ãã®ã‚¨ãƒ³ãƒˆãƒªåを変更ã—ã¾ã™ã€‚</LI>
+</UL>
+
+<H2>
+<A NAME="delete"></A>エントリã®å‰Šé™¤</H2>
+エントリåを削除ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã‚’実行ã—ã¦ãã ã•ã„。
+<OL>
+<LI>
+<A HREF="search.htm#standard">[標準検索]</A>
+ã¾ãŸã¯ <A HREF="search.htm#advanced">[拡張検索]</A>を使ã£ã¦ã€ç›®çš„ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</LI>
+
+<LI>
+<A HREF="search.htm#results">エントリを表示ã•ã›ã¾ã™</A>。</LI>
+
+<LI>
+[編集] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+[削除]ボタンをクリックã—ã¾ã™ã€‚</LI>
+</OL>
+エントリã«å­ã®ã‚¨ãƒ³ãƒˆãƒªãŒã‚ã‚‹å ´åˆã¯ãã®ã‚¨ãƒ³ãƒˆãƒªã‚’削除ã§ããªã„ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。特ã«ã€çµ„ç¹”å˜ä½ã®ãƒ„リーã®ä¸‹ã«ã‚¨ãƒ³ãƒˆãƒªãŒã‚ã‚‹å ´åˆã¯ãã®çµ„ç¹”å˜ä½ã‚’削除ã™ã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。ディレクトリ ツリーã®ãƒ–ランムãƒã‚¤ãƒ³ãƒˆã‚’削除ã™ã‚‹ã«ã¯ã€ãƒ„リー内ã®ãã®ãƒã‚¤ãƒ³ãƒˆã®ä¸‹ã«ã‚ã‚‹ã‚‚ã®ã™ã¹ã¦ã‚’削除ã—ã¦ã‹ã‚‰ã€ãã®ã‚¨ãƒ³ãƒˆãƒªã‚’削除ã—ã¾ã™ã€‚
+<H2>
+<A NAME="changepw"></A>パスワードã®å¤‰æ›´</H2>
+Directory Server インタフェースã§ã€è‡ªåˆ†ã®ãƒ‘スワードを変更ã§ãã¾ã™ã€‚ã¾ãŸã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª マãƒãƒ¼ã‚¸ãƒ£ã¾ãŸã¯ãƒ‘スワード属性ã«å¯¾ã™ã‚‹æ›¸è¾¼ã¿ç‰¹æ¨©ã‚’æŒã¤æœªåˆ¶é™ãƒ¦ãƒ¼ã‚¶ã§ã‚ã‚‹å ´åˆã¯ã€åˆ¥ã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ‘スワードも変更ã§ãã¾ã™ã€‚
+
+<P>パスワードを変更ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã®æ“作をã—ã¾ã™ã€‚
+<OL>
+<LI>
+<A HREF="search.htm#standard">[標準検索]</A>
+ã¾ãŸã¯ <A HREF="search.htm#advanced">[拡張検索]</A>を使ã£ã¦ã€ç›®çš„ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</LI>
+
+<LI>
+<A HREF="search.htm#results">エントリを表示ã•ã›ã¾ã™</A>。</LI>
+
+<LI>
+[編集] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<LI>
+[パスワード変更] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+<BR>自分ã®ãƒ‘スワードを変更ã™ã‚‹å ´åˆã€å¤‰æ›´ã‚³ãƒžãƒ³ãƒ‰ã§ãƒ‘スワードを変更ã™ã‚‹ã«ã¯å¤ã„パスワードを入力ã—ãªã‘ã‚Œã°ãªã‚Šã¾ã›ã‚“。 (ç¾åœ¨ã®ã‚¨ãƒ³ãƒˆãƒªä»¥å¤–ã®ãƒ¦ãƒ¼ã‚¶ã¨ã—ã¦èªè¨¼ã•ã‚Œã¦ã„ã‚‹å ´åˆã¯ã€å¤ã„パスワードã®å…¥åŠ›ã‚’促ã•ã‚Œã‚‹ã“ã¨ã¯ã‚ã‚Šã¾ã›ã‚“。)
+<LI>
+[パスワード変更] ボタンをクリックã—ã¾ã™ã€‚</LI>
+
+</OL>
+
+</BODY>
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/manual/ja/objclass.htm b/ldap/clients/dsgw/html/manual/ja/objclass.htm
new file mode 100644
index 00000000..7da45679
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/ja/objclass.htm
@@ -0,0 +1,7249 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+
+<A NAME="1096805">
+<P>
+</A><A NAME="1096807">
+<P>
+</A><A NAME="1002619">
+<H1>オブジェクト クラス
+</H1>
+</A>
+
+<A NAME="996830">
+<br>
+ã“ã®ä»˜éŒ²ã§ã¯ã€ã‚ªãƒ–ジェクト クラスã®å®šç¾©ã‚’解説ã—ã¦ã„ã¾ã™ã€‚Directory Serverã§ä½¿ç”¨ã•ã‚Œã‚‹ã‚¹ã‚­ãƒ¼ãƒžè¦ç´ ã®å¤§éƒ¨åˆ†ã¯æ¨™æº–LDAPプロトコルã®ä¸€éƒ¨ã§ã‚ã‚Šã€X.500è¦æ ¼ã«åŸºã¥ã„ã¦ã„ã¾ã™ã€‚ã—ã‹ã—ã€Directory Serverã®ã‚ªãƒ–ジェクト クラスã®ãªã‹ã«ã¯ã€LDAPã®å°Žå…¥ã«ä½¿ç”¨ã™ã‚‹ãŸã‚ã«Netscape社ãŒä½œæˆã—ãŸæ‹¡å¼µã‚‚ã‚ã‚Šã¾ã™ã€‚オブジェクト クラスãŒNetscape社ã«ã‚ˆã£ã¦ä½œæˆã•ã‚ŒãŸã‚‚ã®ã§ã€æ¨™æº–LDAPスキーマã®ä¸€éƒ¨ã§ãªã„å ´åˆã¯ã€ãã®ã‚ªãƒ–ジェクト クラスã®èª¬æ˜Žã«ãã®æ—¨ãŒç¤ºã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1080540">
+Directory Serverã®ã‚¹ã‚­ãƒ¼ãƒžã¨ãã®ç”¨é€”ã®è©³ç´°ã¯ã€ã€ŽNetscapeディレクトリã®å°Žå…¥ã‚¬ã‚¤ãƒ‰ã‚’ã”覧ãã ã•ã„。<P></A>
+
+<A NAME="1080543">
+スキーマã«ãŠã‘る属性ã®è©³ç´°ã¯ã€<a href="attribut.htm#1002619">「属性ã€</A>ã‚’ã”覧ãã ã•ã„。<P></A>
+<A NAME="1080587">
+以下ã®ã‚¿ã‚¤ãƒ—ã®ã‚ªãƒ–ジェクト クラスãŒèª¬æ˜Žã•ã‚Œã¦ã„ã¾ã™ã€‚<P>
+</A><ul><A NAME="1080589">
+<LI><a href="objclass.htm#1005608">グループ</A><P>
+</A>
+<A NAME="1080591">
+<LI><a href="objclass.htm#1005780">複製</A><P>
+</A>
+<A NAME="1011931">
+<LI><a href="objclass.htm#1005591">場所</A><P>
+</A>
+<A NAME="1002658">
+<LI><a href="objclass.htm#1004915">組織</A><P>
+</A>
+<A NAME="1002659">
+<LI><a href="objclass.htm#1004958">ユーザ</A><P>
+</A>
+<A NAME="1021627">
+<LI><a href="objclass.htm#1078660">Calendar Serverã®æ‹¡å¼µ</A><P>
+</A>
+<A NAME="1085862">
+<LI><a href="objclass.htm#1078479">Certificate Serverã®æ‹¡å¼µ</A><P>
+</A>
+<A NAME="1085922">
+<LI><a href="objclass.htm#1078576">Collabra Serverã®æ‹¡å¼µ</A><P>
+</A>
+<A NAME="1085927">
+<LI><a href="objclass.htm#1078655">Compass Serverã®æ‹¡å¼µ</A><P>
+</A>
+<A NAME="1085932">
+<LI><a href="objclass.htm#1097229">Directory Serverã®æ‹¡å¼µ</A><P>
+</A>
+<A NAME="1085945">
+<LI><a href="objclass.htm#1097091">Media Serverã®æ‹¡å¼µ</A><P>
+</A>
+<A NAME="1100342">
+<LI><a href="objclass.htm#1097135">Messaging Serverã®æ‹¡å¼µ</A><P>
+</A>
+<A NAME="1085950">
+<LI><a href="objclass.htm#1086191">Proxy Serverã®æ‹¡å¼µ</A><P>
+</A>
+<A NAME="1085955">
+<LI><a href="objclass.htm#1081607">Web Serverã®æ‹¡å¼µ</A><P>
+</A>
+<A NAME="1089730">
+<LI><a href="objclass.htm#1108799">予約ã•ã‚ŒãŸã‚ªãƒ–ジェクト クラス</A><P>
+</A>
+</ul>
+<A NAME="1108856">
+Netscape Directory Server ã®ãƒ™ãƒ¼ã‚¹OIDã¯ä»¥ä¸‹ã®ã¨ãŠã‚Šã§ã™ã€‚<P></A>
+<PRE><A NAME="1108857">
+2.16.840.1.113730.3
+</A>
+</PRE>
+<A NAME="1108858">
+Netscape ãŒå®šç¾©ã—ãŸã™ã¹ã¦ã®ã‚ªãƒ–ジェクト クラスã¯ä»¥ä¸‹ã®ãƒ™ãƒ¼ã‚¹å€¤ã‚’æŒã£ã¦ã„ã¾ã™ã€‚<P></A>
+<PRE><A NAME="1108859">
+2.16.840.1.113730.3.2
+</A>
+</PRE>
+
+<A NAME="1005608">&nbsp;
+</A>
+<A NAME="Groups">
+<H2> グループ</H2>
+</A>
+
+<A NAME="1080703">
+以下ã®ã‚ªãƒ–ジェクト クラスã¯ã€å€‹ã€…ã®ã‚ªãƒ–ジェクトã¾ãŸã¯ãã®ä»–ã®ã‚ªãƒ–ジェクト グループã®åå‰ãŒé †åºä¸åŒã§ç¤ºã•ã‚ŒãŸã‚¨ãƒ³ãƒˆãƒªã‚’記述ã—ã¾ã™ã€‚グループã®ãƒ¡ãƒ³ãƒãƒ¼ã‚·ãƒƒãƒ—ã¯é™çš„ã§ã™ã€‚管ç†æ´»å‹•ã«ã‚ˆã£ã¦ã®ã¿ã‚°ãƒ«ãƒ¼ãƒ—を変更ã§ã(メンãƒãƒ¼ã®è¿½åŠ ãªã©)ã€ã‚°ãƒ«ãƒ¼ãƒ—ãŒå‚ç…§ã•ã‚Œã‚‹ãŸã³ã«ãƒ¡ãƒ³ãƒãƒ¼ã‚·ãƒƒãƒ—ãŒå‹•çš„ã«æ±ºå®šã•ã‚Œã‚‹ã‚ã‘ã§ã¯ã‚ã‚Šã¾ã›ã‚“。å„オブジェクト クラスã«ã¯ã€ã‚°ãƒ«ãƒ¼ãƒ—ã¨ãã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’記述ã™ã‚‹å±žæ€§ãŒå«ã¾ã‚Œã¾ã™ã€‚ã“ã“ã§èª¬æ˜Žã•ã‚Œã¦ã„るオブジェクト クラスã¯ã€<a href="objclass.htm#1080708">groupOfNames</A>ã¨<a href="objclass.htm#1005294">groupOfUniqueNames</A>ã¨<a href="objclass.htm#1100399">NTGroup</A>ã§ã™ã€‚<P></A>
+
+<A NAME="1080708">&nbsp;
+</A>
+<A NAME="groupOfNames">
+<H3> groupOfNames</H3>
+</A>
+
+<A NAME="1080709">
+グループåã®ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1096982">
+OID: <CODE>2.5.6.9</CODE><P></A>
+
+<A NAME="1067760">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075396">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075398">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1069038">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1069041">
+(å¿…é ˆ) グループã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1069044">
+<a href="attribut.htm#1171811">member</A><P></A>
+<td>
+<A NAME="1069047">
+(å¿…é ˆ) 識別åå½¢å¼ã®ã‚°ãƒ«ãƒ¼ãƒ— メンãƒãƒ¼ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069050">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1069052">
+グループãŒå¾“事ã™ã‚‹è·ç¨®ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069055">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1069057">
+グループã®ç›®çš„ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104361">
+<a href="attribut.htm#1246271">memberURL</A><P></A>
+<td>
+<A NAME="1104363">
+グループ メンãƒã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1069060">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1069062">
+グループãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1104337">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1069067">
+グループãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104340">
+<a href="attribut.htm#1005719">owner</A><P></A>
+<td>
+<A NAME="1069072">
+グループã®ã‚ªãƒ¼ãƒŠã€‚<P></A>
+
+<tr><td>
+<A NAME="1069075">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1069077">
+グループã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005294">&nbsp;
+</A>
+<A NAME="groupOfUniqueNames">
+<H3> groupOfUniqueNames</H3>
+</A>
+
+
+
+<A NAME="1005764">
+一æ„ã®åå‰ã‚’æŒã¤ã‚°ãƒ«ãƒ¼ãƒ—ã®ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1097009">
+OID: <CODE>2.5.6.17</CODE><P></A>
+
+<A NAME="1067761">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075392">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075394">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1069137">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1069140">
+(å¿…é ˆ) グループã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1069144">
+<a href="attribut.htm#1172624">uniqueMember</A><P></A>
+<td>
+<A NAME="1069147">
+(å¿…é ˆ) 識別åå½¢å¼ã®ã‚°ãƒ«ãƒ¼ãƒ— メンãƒãƒ¼ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104391">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1069152">
+グループãŒå¾“事ã™ã‚‹è·ç¨®ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104396">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1069157">
+グループã®ç›®çš„ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104401">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1069162">
+グループãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1104406">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1069167">
+グループãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104411">
+<a href="attribut.htm#1005719">owner</A><P></A>
+<td>
+<A NAME="1069172">
+グループã®ã‚ªãƒ¼ãƒŠã€‚<P></A>
+
+<tr><td>
+<A NAME="1104416">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1069177">
+グループã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1100399">&nbsp;
+</A>
+<A NAME="NTGroup">
+<H3> NTGroup</H3>
+</A>
+
+
+
+<A NAME="1100400">
+NT åŒæœŸã‚µãƒ¼ãƒ“スãŒä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€NTグループã®å±žæ€§ã‚’ディレクトリã®ã‚¨ãƒ³ãƒˆãƒªã«ãƒžãƒƒãƒ—ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1100401">
+OID: <CODE>2.16.840.1.113730.3.2.9</CODE><P></A>
+
+<A NAME="1100458">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1100404">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1100406">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1100410">
+<a href="attribut.htm#1103684">ntGroupDomainId</A><P></A>
+<td>
+<A NAME="1100412">
+(å¿…é ˆ) NT Global Groupname/Domainã‚’ä¿å­˜ã™ã‚‹ãŸã‚ã«ã€NTåŒæœŸåŒ–サービスã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1100415">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1100417">
+NTグループã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1100420">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1100422">
+サーãƒã®ã‚る場所ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104514">
+<a href="attribut.htm#1122623">ntGroupAttributes</A><P></A>
+<td>
+<A NAME="1104516">
+NTグループã®å±žæ€§ã‚’ä¿å­˜ã™ã‚‹ãŸã‚ã«ã€NTåŒæœŸåŒ–サービスã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104538">
+<a href="attribut.htm#1122633">ntGroupCreateNewGroup</A><P></A>
+<td>
+<A NAME="1104540">
+NTåŒæœŸåŒ–サービスã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹ãŸã‚ã€äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104480">
+<a href="attribut.htm#1103799">ntGroupDeleteGroup</A><P></A>
+<td>
+<A NAME="1104482">
+NTåŒæœŸåŒ–サービスã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹ãŸã‚ã€äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104557">
+<a href="attribut.htm#1104232">ntGroupId</A><P></A>
+<td>
+<A NAME="1104559">
+グループã®è­˜åˆ¥å­ã‚’ä¿å­˜ã™ã‚‹ãŸã‚ã«ã€NTåŒæœŸåŒ–サービスã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1100425">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1100427">
+グループãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1100435">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1100437">
+グループã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005780">&nbsp;
+</A>
+<A NAME="Replication">
+<H2> 複製</H2>
+</A>
+
+<A NAME="1005974">
+以下ã®ã‚ªãƒ–ジェクト クラスã¯ã€Directory Serverを定義ã—ã¾ã™ã€‚最åˆã®ã‚ªãƒ–ジェクト クラスã¯ã€ãƒžã‚¹ã‚¿ãƒ¼ã¾ãŸã¯ä¾›çµ¦ã‚µãƒ¼ãƒã‚’指定ã—ã¾ã™ã€‚2番目ã®ã‚ªãƒ–ジェクト クラスã¯ã€æ¶ˆè²»ã‚µãƒ¼ãƒãŠã‚ˆã³ãれらã®æ¶ˆè²»ã‚µãƒ¼ãƒã«ä¾›çµ¦ã•ã‚Œã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’指定ã—ã¾ã™ã€‚オブジェクト クラスã«ã¯a href="objclass.htm#1100614">cirReplicaSource</A>ã€<a href="objclass.htm#1005781">LDAPServer</A>ãŠã‚ˆã³ <a href="objclass.htm#1005782">LDAPReplica</A>ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+
+<A NAME="1100614">&nbsp;
+</A>
+<A NAME="cirReplicaSource">
+<H3> cirReplicaSource</H3>
+</A>
+
+
+
+<A NAME="1100615">
+Netscape Directory ServerãŒã€æ¶ˆè²»è€…åˆæœŸåŒ–ã®è¤‡è£½ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®ç‰¹å®šã®ã‚µãƒ–ツリーã«é–¢ã™ã‚‹ã™ã¹ã¦ã®è¤‡è£½æƒ…報をå«ã¿ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1100616">
+OID: <CODE>2.16.840.1.113730.3.2.11</CODE><P></A>
+
+<A NAME="1100703">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1100619">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1100621">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1100624">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1100626">
+(å¿…é ˆ) 供給サーãƒã®ä¸€æ„ã®è­˜åˆ¥å­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104680">
+<a href="attribut.htm#1103818">cirBeginORC</A><P></A>
+<td>
+<A NAME="1104682">
+複製ã®å‰ã«ã€æ¶ˆè²»ã‚µãƒ¼ãƒãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®å†…容を消去ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104646">
+<a href="attribut.htm#1101818">cirBindCredentials</A><P></A>
+<td>
+<A NAME="1104648">
+供給サーãƒã¸ã®æŽ¥ç¶šã«ä½¿ç”¨ã™ã‚‹ãƒã‚¤ãƒ³ãƒ‰è¨¼æ˜Žæ›¸ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104607">
+<a href="attribut.htm#1101379">cirBindDn</A><P></A>
+<td>
+<A NAME="1104609">
+供給サーãƒã¸ã®ãƒã‚¤ãƒ³ãƒ‰ã«ä½¿ç”¨ã™ã‚‹è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1104731">
+<a href="attribut.htm#1101250">cirHost</A><P></A>
+<td>
+<A NAME="1104733">
+供給サーãƒã®ãƒ›ã‚¹ãƒˆå。<P></A>
+
+<tr><td>
+<A NAME="1104629">
+<a href="attribut.htm#1101860">cirLastUpdateApplied</A><P></A>
+<td>
+<A NAME="1104631">
+消費サーãƒã¨ä¾›çµ¦ã‚µãƒ¼ãƒé–“ã§æœ€å¾Œã«ç™ºç”Ÿã—ãŸåŒæœŸåŒ–ã®æ—¥ä»˜ã¨æ™‚刻。<P></A>
+
+<tr><td>
+<A NAME="1100639">
+<a href="attribut.htm#1101283">cirPort</A><P></A>
+<td>
+<A NAME="1100641">
+供給サーãƒã®ãƒãƒ¼ãƒˆç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104589">
+<a href="attribut.htm#1101135">cirReplicaRoot</A><P></A>
+<td>
+<A NAME="1104591">
+消費サーãƒã«è¤‡è£½ã•ã‚Œã‚‹ä¾›çµ¦ã‚µãƒ¼ãƒã®ã‚µãƒ–ツリーã®ãƒ«ãƒ¼ãƒˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1104766">
+<a href="attribut.htm#1102148">cirSyncInterval</A><P></A>
+<td>
+<A NAME="1104768">
+ディレクトリã®è¤‡è£½éƒ¨åˆ†ã«å¤‰æ›´ãŒè¡Œã‚ã‚ŒãŸã‹ã©ã†ã‹ã‚’定期的ã«ãƒã‚§ãƒƒã‚¯ã™ã‚‹ãŸã‚ã€æ¶ˆè²»ã‚µãƒ¼ãƒã‹ã‚‰ä¾›çµ¦ã‚µãƒ¼ãƒã«å•åˆã›ãŒè¡Œã‚ã‚Œã¾ã™ã€‚ã“ã®å±žæ€§ã¯ã€æ¶ˆè²»ã‚µãƒ¼ãƒã«ã‚ˆã‚‹ä¾›çµ¦ã‚µãƒ¼ãƒã¸ã®å•åˆã›é–“隔を秒å˜ä½ã§å®šç¾©ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104811">
+<a href="attribut.htm#1102114">cirUpdateFailedat</A><P></A>
+<td>
+<A NAME="1104813">
+æ›´æ–°ãŒæœ€å¾Œã«å¤±æ•—ã—ãŸã¨ãã®ã‚¿ã‚¤ãƒ  スタンプ。<P></A>
+
+<tr><td>
+<A NAME="1104814">
+<a href="attribut.htm#1102001">cirUpdateSchedule</A><P></A>
+<td>
+<A NAME="1104792">
+複製を行ã£ã¦ã‚‚よã„時間帯。<P></A>
+
+<tr><td>
+<A NAME="1100650">
+<a href="attribut.htm#1101691">cirUsePersistentSearch</A><P></A>
+<td>
+<A NAME="1100652">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1100655">
+<a href="attribut.htm#1101735">cirUseSsl</A><P></A>
+<td>
+<A NAME="1100657">
+供給サーãƒã«ãƒã‚¤ãƒ³ãƒ‰ã™ã‚‹éš›ã«SSL接続を使用ã™ã‚‹ã‚ˆã†æ¶ˆè²»ã‚µãƒ¼ãƒã«æŒ‡ç¤ºã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104823">
+<a href="attribut.htm#1148497">replicaEntryFilter</A><P></A>
+<td>
+<A NAME="1104699">
+複製中ã«è¤‡è£½ã¾ãŸã¯çœç•¥ã™ã‚‹å±žæ€§ã‚’示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1100690">
+<a href="attribut.htm#1148453">replicaNickName</A><P></A>
+<td>
+<A NAME="1100692">
+å˜ä¸€ã®ä¾›çµ¦ã‚µãƒ¼ãƒã¨å˜ä¸€ã®æ¶ˆè²»ã‚µãƒ¼ãƒé–“ã®è¤‡è£½ãƒ«ãƒ¼ãƒ«ã®ç‰¹å®šã®ã‚»ãƒƒãƒˆã‚’示ã™è‡ªç”±å½¢å¼ã®åå‰ã€‚<P></A>
+
+<tr><td>
+<A NAME="1100700">
+<a href="attribut.htm#1281126">replicatedAttributeList</A><P></A>
+<td>
+<A NAME="1100702">
+複製中ã«è¤‡è£½ã¾ãŸã¯çœç•¥ã™ã‚‹å±žæ€§ã‚’示ã—ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1105809">&nbsp;
+</A>
+<A NAME="glue">
+<H3> glue</H3>
+</A>
+
+
+
+<A NAME="1105810">
+複製を容易ã«ã™ã‚‹ãŸã‚ã«Netscape Directory Server ãŒä½¿ç”¨ã™ã‚‹æ‹¡å¼µå¯èƒ½ãªã‚ªãƒ–ジェクト クラス。拡張å¯èƒ½ãªã‚ªãƒ–ジェクト クラスã«é–¢ã™ã‚‹è©³ç´°ã¯ã€ã€ŽNetscape Directory Server 導入ガイドã€ã®ã€Œã‚ªãƒ–ジェクト クラスã®ã‚¿ã‚¤ãƒ—ã€ã‚’å‚ç…§ã—ã¦ãã ã•ã„。予約済。ã“ã®ã‚ªãƒ–ジェクトクラスã¯æ¨™æº–LDAPスキーマã«å¯¾ã™ã‚‹Netscapeã®æ‹¡å¼µã§ã™ã€‚<P></A>
+
+<A NAME="1105811">
+OID: <CODE>2.16.840.1.113730.3.2.30</CODE><P></A>
+
+
+<A NAME="1005781">&nbsp;
+</A>
+<A NAME="LDAPServer">
+<H3> LDAPServer</H3>
+</A>
+
+
+
+<A NAME="1042902">
+ローカル サーãƒã‚’指定ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1098493">
+OID: <CODE>2.16.840.1.113730.3.2.35</CODE><P></A>
+
+<A NAME="1067762">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075388">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075390">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1069192">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1069195">
+(å¿…é ˆ) サーãƒã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1069199">
+<a href="attribut.htm#1171397">changeLogMaximumAge</A><P></A>
+<td>
+<A NAME="1100535">
+サーãƒã®å¤‰æ›´ãƒ­ã‚°ã«è¨±ã•ã‚Œã‚‹å¤ã•ã®æœ€å¤§å€¤ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069204">
+<a href="attribut.htm#1171405">changeLogMaximumSize</A><P></A>
+<td>
+<A NAME="1069206">
+サーãƒã®å¤‰æ›´ãƒ­ã‚°ã«è¨±ã•ã‚Œã‚‹ã‚µã‚¤ã‚ºã®æœ€å¤§å€¤ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069209">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1069211">
+サーãƒã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069214">
+<a href="attribut.htm#1171657">generation</A><P></A>
+<td>
+<A NAME="1069216">
+複製ã®ç›®çš„ã®ãŸã‚ã«ã‚µãƒ¼ãƒã‚’示ã™å›ºæœ‰ã®ãƒã‚¤ãƒˆ ベクトル。<P></A>
+
+<tr><td>
+<A NAME="1069219">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1069221">
+サーãƒã®ã‚る場所ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069224">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1069226">
+サーãƒãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069229">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1069231">
+サーãƒã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005782">&nbsp;
+</A>
+<A NAME="LDAPReplica">
+<H3> LDAPReplica</H3>
+</A>
+
+
+
+<A NAME="1006031">
+ローカル サーãƒå†…ã®ã‚¨ãƒ³ãƒˆãƒªã§ãƒªãƒ¢ãƒ¼ãƒˆ サーãƒã«è¤‡è£½ã•ã‚Œã‚‹ã‚‚ã®ã‚’指定ã—ã€ã‚¨ãƒ³ãƒˆãƒªè¤‡è£½å…ˆã®ãƒªãƒ¢ãƒ¼ãƒˆ サーãƒã‚’指定ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1098496">
+OID: <CODE>2.16.840.1.113730.3.2.36</CODE><P></A>
+
+<A NAME="1067881">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075384">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075386">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1069247">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1069250">
+(å¿…é ˆ) エントリã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1069253">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1069255">
+エントリã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104907">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1069260">
+エントリãŒå­˜åœ¨ã™ã‚‹å ´æ‰€ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104912">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1069265">
+エントリãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106807">
+<a href="attribut.htm#1092877">replicaBeginOrc</A><P></A>
+<td>
+<A NAME="1106809">
+複製ã®å‰ã«ã€ä¾›çµ¦ã‚µãƒ¼ãƒãŒæ¶ˆè²»ã‚µãƒ¼ãƒã®å†…容を消去ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069268">
+<a href="attribut.htm#1006496">replicaBindDn</A><P></A>
+<td>
+<A NAME="1069270">
+ローカル サーãƒãŒæ¶ˆè²»ã‚µãƒ¼ãƒã«ãƒã‚¤ãƒ³ãƒ‰ã™ã‚‹ã®ã«ä½¿ç”¨ã™ã‚‹DN。<P></A>
+
+<tr><td>
+<A NAME="1069273">
+<a href="attribut.htm#1006636">replicaBindMethod</A><P></A>
+<td>
+<A NAME="1069275">
+ローカル サーãƒãŒæ¶ˆè²»ã‚µãƒ¼ãƒã«ãƒã‚¤ãƒ³ãƒ‰ã™ã‚‹ã®ã«ä½¿ç”¨ã™ã‚‹ãƒ¡ã‚½ãƒƒãƒ‰ã€‚ç¾åœ¨ã€ã“ã®å±žæ€§ã¯<CODE>simple</CODE>ã«è¨­å®šã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069278">
+<a href="attribut.htm#1230073">replicaCredentials</A><P></A>
+<td>
+<A NAME="1069280">
+ローカル サーãƒãŒæ¶ˆè²»ã‚µãƒ¼ãƒã«ãƒã‚¤ãƒ³ãƒ‰ã™ã‚‹ã®ã«ä½¿ç”¨ã™ã‚‹ãƒ‘スワード。<P></A>
+
+<tr><td>
+<A NAME="1106878">
+<a href="attribut.htm#1148497">replicaEntryFilter</A><P></A>
+<td>
+<A NAME="1106880">
+フィルタ付ã複製è¦ç´„ã§ã©ã®å±žæ€§ã‚’複製ã—ã€ã©ã®å±žæ€§ã‚’除ãã®ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069283">
+<a href="attribut.htm#1148445">replicaHost</A><P></A>
+<td>
+<A NAME="1069285">
+消費サーãƒã®ãƒ›ã‚¹ãƒˆå。<P></A>
+
+<tr><td>
+<A NAME="1106816">
+<a href="attribut.htm#1148453">replicaNickName</A><P></A>
+<td>
+<A NAME="1106818">
+複製è¦ç´„ã®è‡ªç”±å½¢å¼ã®åå‰ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069288">
+<a href="attribut.htm#1007660">replicaPort</A><P></A>
+<td>
+<A NAME="1069290">
+消費サーãƒãŒLDAP通信ã«ä½¿ç”¨ã™ã‚‹ãƒãƒ¼ãƒˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1069293">
+<a href="attribut.htm#1006384">replicaRoot</A><P></A>
+<td>
+<A NAME="1069295">
+消費サーãƒã«ä¾›çµ¦ã™ã‚‹ã‚µãƒ–ツリーã®ãƒ­ãƒ¼ã‚«ãƒ« サーãƒã«ãŠã‘る識別å。<P></A>
+
+<tr><td>
+<A NAME="1106928">
+<a href="attribut.htm#1281126">replicatedAttributeList</A><P></A>
+<td>
+<A NAME="1106930">
+é¸æŠžå±žæ€§è¤‡è£½è¦ç´„ã§ã©ã®å±žæ€§ã‚’複製ã—ã€ã©ã®å±žæ€§ã‚’除ãã®ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069298">
+<a href="attribut.htm#1006918">replicaUpdateFailedAt</A><P></A>
+<td>
+<A NAME="1069300">
+消費サーãƒã¸ã®æ›´æ–°ãŒå¤±æ•—ã—ãŸã¨ãã®ã‚¿ã‚¤ãƒ  スタンプ。<P></A>
+
+<tr><td>
+<A NAME="1069303">
+<a href="attribut.htm#1012768">replicaUpdateReplayed</A><P></A>
+<td>
+<A NAME="1069305">
+消費サーãƒã«ä¾›çµ¦ã•ã‚ŒãŸæœ€å¾Œã®å¤‰æ›´ã®å¤‰æ›´ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069308">
+<a href="attribut.htm#1006817">replicaUpdateSchedule</A><P></A>
+<td>
+<A NAME="1069310">
+ローカル サーãƒãŒæ¶ˆè²»ã‚µãƒ¼ãƒã¸ã®æ›´æ–°ã‚’開始ã™ã‚‹ã‚¹ã‚±ã‚¸ãƒ¥ãƒ¼ãƒ«ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069313">
+<a href="attribut.htm#1006741">replicaUseSSL</A><P></A>
+<td>
+<A NAME="1069315">
+消費サーãƒã¨ã®é€šä¿¡ã«SSLを使用ã™ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1069318">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1069320">
+サーãƒã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005591">&nbsp;
+</A>
+<A NAME="Locations">
+<H2> 場所</H2>
+</A>
+
+<A NAME="1005809">
+以下ã®ã‚ªãƒ–ジェクト クラスã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã«ãŠã‘ã‚‹ä½ç½®ã‚’記述ã—ã¾ã™ã€‚å„オブジェクト クラスã«ã¯ã€å›½åや記述ãªã©ã€å ´æ‰€ã‚’説明ã™ã‚‹å±žæ€§ãŒå«ã¾ã‚Œã¾ã™ã€‚ã“ã“ã§èª¬æ˜Žã•ã‚Œã¦ã„るオブジェクト クラスã¯ã€<a href="objclass.htm#1005812">country</A>ã¨<a href="objclass.htm#1005427">locality</A>ã§ã™ã€‚<P></A>
+
+
+<A NAME="1005812">&nbsp;
+</A>
+<A NAME="country">
+<H3> country</H3>
+</A>
+
+
+
+<A NAME="1005813">
+国を表示ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1096900">
+OID: <CODE>2.5.6.2</CODE><P></A>
+
+<A NAME="1068820">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1088379">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1088381">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1088384">
+<a href="attribut.htm#1240535">c</A><P></A>
+<td>
+<A NAME="1088387">
+(å¿…é ˆ) エントリã®å›½å<P></A>
+
+<tr><td>
+<A NAME="1088390">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1088392">
+国ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088397">
+<a href="attribut.htm#1202682">searchGuide</A><P></A>
+<td>
+<A NAME="1088399">
+検索動作ã®ãŸã‚ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã®ãƒ™ãƒ¼ã‚¹ オブジェクトã¨ã—ã¦ã‚¨ãƒ³ãƒˆãƒªã‚’使用ã™ã‚‹éš›ã«ã€æ案ã•ã‚Œã‚‹æ¤œç´¢åŸºæº–ã®æƒ…報を指定ã—ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005427">&nbsp;
+</A>
+<A NAME="locality">
+<H3> locality</H3>
+</A>
+
+
+
+<A NAME="1005428">
+地域ã¾ãŸã¯åœ°ç†çš„領域を表示ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1096910">
+OID: <CODE>2.5.6.3</CODE><P></A>
+
+<A NAME="1068821">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075380">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075382">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1071009">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1071011">
+地域性ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1071014">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1071016">
+エントリã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106986">
+<a href="attribut.htm#1202682">searchGuide</A><P></A>
+<td>
+<A NAME="1106988">
+検索動作ã®ãŸã‚ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã®ãƒ™ãƒ¼ã‚¹ オブジェクトã¨ã—ã¦ã‚¨ãƒ³ãƒˆãƒªã‚’使用ã™ã‚‹éš›ã«ã€æ案ã•ã‚Œã‚‹æ¤œç´¢åŸºæº–ã®æƒ…報を指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1071019">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1071021">
+地域ã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1071024">
+<a href="attribut.htm#1203417">st</A><P></A>
+<td>
+<A NAME="1071026">
+ãã®åœ°åŸŸæ€§ã®å±žã™ã‚‹å·žã¾ãŸã¯éƒ½é“府県を示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1071029">
+<a href="attribut.htm#1202721">street</A><P></A>
+<td>
+<A NAME="1071031">
+ãã®åœ°åŸŸæ€§ã«é–¢é€£ã™ã‚‹è¡—è·¯ã¨ç•ªåœ°ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1004915">&nbsp;
+</A>
+<A NAME="Organizations">
+<H2> 組織</H2>
+</A>
+
+<A NAME="1004913">
+以下ã®ã‚ªãƒ–ジェクト クラスã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã«ãŠã‘る組織を示ã™ã‚¨ãƒ³ãƒˆãƒªã‚’記述ã—ã¾ã™ã€‚å„オブジェクト クラスã«ã¯ã€çµ„ç¹”ã®åå‰ã‚„記述ãªã©ã€çµ„織を説明ã™ã‚‹å±žæ€§ãŒå«ã¾ã‚Œã¾ã™ã€‚ã“ã“ã§èª¬æ˜Žã•ã‚Œã¦ã„るオブジェクト クラスã¯ã€<a href="objclass.htm#1004980">organization</A>ã¨<a href="objclass.htm#1005108">organizationalUnit</A>ã§ã™ã€‚<P></A>
+
+
+<A NAME="1004980">&nbsp;
+</A>
+<A NAME="organization">
+<H3> organization</H3>
+</A>
+
+
+
+<A NAME="1004981">
+組織を示ã™ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚一般ã«ã€çµ„ç¹”ã¯ã€å¤§ããªä¼æ¥­ã‚„事業内ã«ãŠã‘る大ããªæ¯”較的é™çš„ãªã‚°ãƒ«ãƒ¼ãƒ—ã§ã‚ã‚‹ã“ã¨ã‚’想定ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1096920">
+OID: <CODE>2.5.6.4</CODE><P></A>
+
+<A NAME="1068822">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1107038">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1107040">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1107045">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1107047">
+(å¿…é ˆ) 組織å<P></A>
+
+<tr><td>
+<A NAME="1107052">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1107054">
+組織ãŒé–¢ä¸Žã™ã‚‹äº‹æ¥­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107059">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1107061">
+組織ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107065">
+<a href="attribut.htm#1171637">facsimileTelephoneNumber</A><P></A>
+<td>
+<A NAME="1107068">
+組織ã«é–¢ä¿‚ã™ã‚‹ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107073">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1107075">
+組織ã®ã‚る場所。<P></A>
+
+<tr><td>
+<A NAME="1107079">
+<a href="attribut.htm#1003072">physicalDeliveryOfficeName</A><P></A>
+<td>
+<A NAME="1107082">
+物ç†çš„ã«ã‚‚ã®ã‚’é…é”ã™ã‚‹ãŸã‚ã®çµ„ç¹”ã®å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107087">
+<a href="attribut.htm#1230025">postalAddress</A><P></A>
+<td>
+<A NAME="1107089">
+郵é€ã®ãŸã‚ã®çµ„ç¹”ã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107094">
+<a href="attribut.htm#1230036">postalCode</A><P></A>
+<td>
+<A NAME="1107096">
+組織ã®éƒµä¾¿ç•ªå·(米国ã«ãŠã‘る郵便番å·ãªã©)。<P></A>
+
+<tr><td>
+<A NAME="1107101">
+<a href="attribut.htm#1230043">postOfficeBox</A><P></A>
+<td>
+<A NAME="1107103">
+組織ã®ç§æ›¸ç®±ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107108">
+<a href="attribut.htm#1202605">preferredDeliveryMethod</A><P></A>
+<td>
+<A NAME="1107110">
+組織ãŒå¸Œæœ›ã™ã‚‹é€£çµ¡æ–¹æ³•ã¾ãŸã¯é…é”方法。<P></A>
+
+<tr><td>
+<A NAME="1107115">
+<a href="attribut.htm#1202682">searchGuide</A><P></A>
+<td>
+<A NAME="1107117">
+検索動作ã®ãŸã‚ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã®ãƒ™ãƒ¼ã‚¹ オブジェクトã¨ã—ã¦ã‚¨ãƒ³ãƒˆãƒªã‚’使用ã™ã‚‹éš›ã«ã€æ案ã•ã‚Œã‚‹æ¤œç´¢åŸºæº–ã®æƒ…報を指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107122">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1107124">
+組織ã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1107129">
+<a href="attribut.htm#1203417">st</A><P></A>
+<td>
+<A NAME="1107131">
+組織ã®ã‚ã‚‹å·žã¾ãŸã¯éƒ½é“府県。<P></A>
+
+<tr><td>
+<A NAME="1107136">
+<a href="attribut.htm#1202721">street</A><P></A>
+<td>
+<A NAME="1107138">
+組織ã®ã‚ã‚‹è¡—è·¯ã¨ç•ªåœ°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107143">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1107145">
+組織ã«é–¢é€£ã™ã‚‹é›»è©±ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107150">
+<a href="attribut.htm#1205004">teletexTerminalIdentifier</A><P></A>
+<td>
+<A NAME="1107152">
+組織ã®ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナルã®è­˜åˆ¥å­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107157">
+<a href="attribut.htm#1205120">telexNumber</A><P></A>
+<td>
+<A NAME="1107159">
+組織ã®ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ç•ªå·<P></A>
+
+<tr><td>
+<A NAME="1107171">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1107173">
+エントリãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãƒã‚¤ãƒ³ãƒ‰ã§ãるパスワード。<P></A>
+
+<tr><td>
+<A NAME="1107164">
+<a href="attribut.htm#1281763">x121Address</A><P></A>
+<td>
+<A NAME="1107166">
+組織ã®X.121アドレス<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005108">&nbsp;
+</A>
+<A NAME="organizationalUnit">
+<H3> organizationalUnit</H3>
+</A>
+
+
+
+<A NAME="1005109">
+組織å˜ä½ã‚’示ã™ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚一般ã«ã€çµ„ç¹”å˜ä½ã¯ã€ã•ã‚‰ã«å¤§ããªçµ„ç¹”ã«ãŠã‘る比較的é™çš„ãªã‚°ãƒ«ãƒ¼ãƒ—ã§ã‚ã‚‹ã¨æƒ³å®šã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1096923">
+OID: <CODE>2.5.6.5</CODE><P></A>
+
+<A NAME="1068823">
+.
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1107182">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1107184">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1107189">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1107191">
+(å¿…é ˆ) 組織å˜ä½å<P></A>
+
+<tr><td>
+<A NAME="1107196">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1107198">
+組織å˜ä½ãŒé–¢ä¸Žã™ã‚‹äº‹æ¥­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107203">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1107205">
+組織å˜ä½ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107326">
+<a href="attribut.htm#1201824">destinationIndicator</A><P></A>
+<td>
+<A NAME="1107328">
+公衆電報サービスをæä¾›ã™ã‚‹ã«ã¯çµ„ç¹”å˜ä½ã«é–¢é€£ã™ã‚‹å›½ã‚„都市ã®æƒ…å ±ãŒå¿…è¦ã§ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107209">
+<a href="attribut.htm#1171637">facsimileTelephoneNumber</A><P></A>
+<td>
+<A NAME="1107212">
+組織å˜ä½ã«é–¢ä¿‚ã™ã‚‹ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107337">
+<a href="attribut.htm#1224256">internationalIsdnNumber</A><P></A>
+<td>
+<A NAME="1107339">
+組織å˜ä½ã®ISDN番å·ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107217">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1107219">
+組織å˜ä½ã®å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107223">
+<a href="attribut.htm#1003072">physicalDeliveryOfficeName</A><P></A>
+<td>
+<A NAME="1107226">
+物ç†çš„ã«ã‚‚ã®ã‚’é…é”ã™ã‚‹ãŸã‚ã®çµ„ç¹”å˜ä½ã®å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107231">
+<a href="attribut.htm#1230025">postalAddress</A><P></A>
+<td>
+<A NAME="1107233">
+組織å˜ä½ã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107238">
+<a href="attribut.htm#1230036">postalCode</A><P></A>
+<td>
+<A NAME="1107240">
+組織å˜ä½ã®éƒµä¾¿ç•ªå·(米国ã«ãŠã‘る郵便番å·ãªã©)。<P></A>
+
+<tr><td>
+<A NAME="1107245">
+<a href="attribut.htm#1230043">postOfficeBox</A><P></A>
+<td>
+<A NAME="1107247">
+組織å˜ä½ã®ç§æ›¸ç®±ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107252">
+<a href="attribut.htm#1202605">preferredDeliveryMethod</A><P></A>
+<td>
+<A NAME="1107254">
+組織å˜ä½ãŒå¸Œæœ›ã™ã‚‹é€£çµ¡æ–¹æ³•ã¾ãŸã¯é…é”方法。<P></A>
+
+<tr><td>
+<A NAME="1107352">
+<a href="attribut.htm#1202644">registeredAddress</A><P></A>
+<td>
+<A NAME="1107366">
+緊急ã®æ›¸é¡žã®å—ã‘å–ã‚Šãªã©ã€å—å–人ãŒé…é”を確èªã™ã‚‹å¿…è¦ã®ã‚ã‚‹ã‚‚ã®ã‚’é…é”ã™ã‚‹ã®ã«ãµã•ã‚ã—ã„郵é€ç”¨ã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107259">
+<a href="attribut.htm#1202682">searchGuide</A><P></A>
+<td>
+<A NAME="1107261">
+検索動作ã®ãŸã‚ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã®ãƒ™ãƒ¼ã‚¹ オブジェクトã¨ã—ã¦ã‚¨ãƒ³ãƒˆãƒªã‚’使用ã™ã‚‹éš›ã«ã€æ案ã•ã‚Œã‚‹æ¤œç´¢åŸºæº–ã®æƒ…報を指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107266">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1107268">
+組織å˜ä½ã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1107273">
+<a href="attribut.htm#1203417">st</A><P></A>
+<td>
+<A NAME="1107275">
+組織å˜ä½ã®å±žã™ã‚‹å·žã¾ãŸã¯éƒ½é“府県。<P></A>
+
+<tr><td>
+<A NAME="1107280">
+<a href="attribut.htm#1202721">street</A><P></A>
+<td>
+<A NAME="1107282">
+組織å˜ä½ã®ã‚ã‚‹è¡—è·¯ã¨ç•ªåœ°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107287">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1107289">
+組織å˜ä½ã«é–¢é€£ã™ã‚‹é›»è©±ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107322">
+<a href="attribut.htm#1205004">teletexTerminalIdentifier</A><P></A>
+<td>
+<A NAME="1107324">
+組織ã®ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナルã®è­˜åˆ¥å­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107315">
+<a href="attribut.htm#1205120">telexNumber</A><P></A>
+<td>
+<A NAME="1107317">
+組織ã®ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ç•ªå·<P></A>
+
+<tr><td>
+<A NAME="1107308">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1107310">
+エントリãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãƒã‚¤ãƒ³ãƒ‰ã§ãるパスワード。<P></A>
+
+<tr><td>
+<A NAME="1107301">
+<a href="attribut.htm#1281763">x121Address</A><P></A>
+<td>
+<A NAME="1107303">
+組織ã®X.121アドレス<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1004958">&nbsp;
+</A>
+<A NAME="People">
+<H2> ユーザ</H2>
+</A>
+
+<A NAME="1100949">
+以下ã®ã‚ªãƒ–ジェクト クラスã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãŠã‘るユーザを示ã™ã‚¨ãƒ³ãƒˆãƒªã‚’記述ã—ã¾ã™ã€‚å„オブジェクト クラスã«ã¯ã€åå‰ã€é›»è©±ç•ªå·ã€ä½æ‰€ãªã©ã€ãƒ¦ãƒ¼ã‚¶ã‚’説明ã™ã‚‹å±žæ€§ãŒå«ã¾ã‚Œã¾ã™ã€‚ã“ã“ã§èª¬æ˜Žã•ã‚Œã¦ã„るオブジェクト クラスã¯ã€<a href="objclass.htm#1089249">inetOrgPerson</A>ã€<a href="objclass.htm#1100980">newPilotPerson</A>ã€<a href="objclass.htm#1100862">nsLicenseUser</A>, <a href="objclass.htm#1089442">ntUser</A>ã€<a href="objclass.htm#1002805">organizationalPerson</A>ã€<a href="objclass.htm#1088567">organizationalRole</A>ã€<a href="objclass.htm#1089681">person</A>ãŠã‚ˆã³<a href="objclass.htm#1106267">residentialPerson</A>ã§ã™ã€‚<P></A>
+
+
+<A NAME="1089249">&nbsp;
+</A>
+<A NAME="inetOrgPerson">
+<H3> inetOrgPerson</H3>
+</A>
+
+
+
+<A NAME="1089250">
+組織ã®ã‚¤ãƒ³ãƒˆãƒ©ãƒãƒƒãƒˆã®ãƒ¦ãƒ¼ã‚¶ã‚’示ã™ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1096822">
+OID: <CODE>2.16.840.1.113730.3.2.2</CODE><P></A>
+
+<A NAME="1089439">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1089253">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1089255">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1102952">
+<a href="attribut.htm#1201684">audio</A><P></A>
+<td>
+<A NAME="1102954">
+ãƒã‚¤ãƒŠãƒªå½¢å¼ã®ã‚µã‚¦ãƒ³ãƒ‰ ファイル。<P></A>
+
+<tr><td>
+<A NAME="1089270">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1089272">
+ユーザãŒé–¢ä¸Žã™ã‚‹äº‹æ¥­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089275">
+<a href="attribut.htm#1003044">carLicense</A><P></A>
+<td>
+<A NAME="1089277">
+ユーザã®è‡ªå‹•è»Šã®ãƒ©ã‚¤ã‚»ãƒ³ã‚¹ プレート番å·<P></A>
+
+<tr><td>
+<A NAME="1089280">
+<a href="attribut.htm#1095560">departmentNumber</A><P></A>
+<td>
+<A NAME="1089282">
+ユーザãŒå‹¤å‹™ã™ã‚‹éƒ¨é–€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089290">
+<a href="attribut.htm#1111357">employeeNumber</A><P></A>
+<td>
+<A NAME="1089292">
+ユーザã®ç¤¾å“¡ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089295">
+<a href="attribut.htm#1009035">employeeType</A><P></A>
+<td>
+<A NAME="1089297">
+ユーザã®é›‡ç”¨ã‚¿ã‚¤ãƒ—(フルタイムãªã©)。<P></A>
+
+<tr><td>
+<A NAME="1089305">
+<a href="attribut.htm#1229534">givenName</A><P></A>
+<td>
+<A NAME="1089307">
+ユーザã®åå‰ã€ã¤ã¾ã‚Šãƒ•ã‚¡ãƒ¼ã‚¹ãƒˆãƒãƒ¼ãƒ ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089310">
+<a href="attribut.htm#1201936">homePhone</A><P></A>
+<td>
+<A NAME="1089312">
+ユーザã®é›»è©±ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089315">
+<a href="attribut.htm#1201947">homePostalAddress</A><P></A>
+<td>
+<A NAME="1089317">
+ユーザã®è‡ªå®…ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089320">
+<a href="attribut.htm#1229543">initials</A><P></A>
+<td>
+<A NAME="1089322">
+ユーザã®ã‚¤ãƒ‹ã‚·ãƒ£ãƒ«ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089325">
+<a href="attribut.htm#1201995">jpegPhoto</A><P></A>
+<td>
+<A NAME="1089327">
+jpegå½¢å¼ã®ã‚¤ãƒ¡ãƒ¼ã‚¸ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107552">
+<a href="attribut.htm#1202020">labeledUri</A><P></A>
+<td>
+<A NAME="1089337">
+ユーザã«é–¢ä¿‚ã™ã‚‹universal resource locator (URL)。<P></A>
+
+<tr><td>
+<A NAME="1089340">
+<a href="attribut.htm#1189404">mail</A><P></A>
+<td>
+<A NAME="1089342">
+ユーザã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレス。<P></A>
+
+<tr><td>
+<A NAME="1089345">
+<a href="attribut.htm#1007859">manager</A><P></A>
+<td>
+<A NAME="1089347">
+ユーザã®ä¸Šå¸ã‚’示ã™è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1089350">
+<a href="attribut.htm#1202056">mobile</A><P></A>
+<td>
+<A NAME="1089352">
+ユーザã®æºå¸¯é›»è©±ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089361">
+<a href="attribut.htm#1003070">pager</A><P></A>
+<td>
+<A NAME="1089363">
+ユーザã®ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107511">
+<a href="attribut.htm#1202247">photo</A><P></A>
+<td>
+<A NAME="1107514">
+ãƒã‚¤ãƒŠãƒªå½¢å¼ã®å†™çœŸã€‚<P></A>
+
+<tr><td>
+<A NAME="1107521">
+<a href="attribut.htm#1103495">preferredLanguage</A><P></A>
+<td>
+<A NAME="1107523">
+ユーザãŒæ›¸ã„ãŸã‚Šè©±ã—ãŸã‚Šã™ã‚‹è¨€èªžã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089391">
+<a href="attribut.htm#1204477">roomNumber</A><P></A>
+<td>
+<A NAME="1089393">
+ユーザã®éƒ¨å±‹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089396">
+<a href="attribut.htm#1202691">secretary</A><P></A>
+<td>
+<A NAME="1089398">
+ユーザã®ç§˜æ›¸ã¾ãŸã¯ã‚¢ã‚·ã‚¹ã‚¿ãƒ³ãƒˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1089406">
+<a href="attribut.htm#1202847">uid</A><P></A>
+<td>
+<A NAME="1089408">
+エントリã®ãƒ¦ãƒ¼ã‚¶ID(通常ã¯ãƒ­ã‚°ã‚ªãƒ³ID)を示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089431">
+<a href="attribut.htm#1208938">userCertificate</A><P></A>
+<td>
+<A NAME="1089433">
+クリアテキスト形å¼ã®ãƒ¦ãƒ¼ã‚¶ã®è¨¼æ˜Žæ›¸(未使用)<P></A>
+
+<tr><td>
+<A NAME="1107557">
+<a href="attribut.htm#1208946">userCertificate;binary</A><P></A>
+<td>
+<A NAME="1107559">
+ãƒã‚¤ãƒŠãƒªå½¢å¼ã®ãƒ¦ãƒ¼ã‚¶ã®è¨¼æ˜Žæ›¸ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089436">
+<a href="attribut.htm#1103595">userSMIMECertificate;binary</A><P></A>
+<td>
+<A NAME="1107562">
+ãƒã‚¤ãƒŠãƒªå½¢å¼ã®ãƒ¦ãƒ¼ã‚¶ã®è¨¼æ˜Žæ›¸ã€‚Netscape Communicator(コミュニケータ)ãŒS/MIMEã§ä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1095842">
+<a href="attribut.htm#1292796">x500UniqueIdentifier</A><P></A>
+<td>
+<A NAME="1095844">
+未定義。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1100980">&nbsp;
+</A>
+<A NAME="newPilotPerson">
+<H3> newPilotPerson</H3>
+</A>
+
+
+
+<A NAME="1100981">
+人物ã®ã‚µãƒ–クラスã¨ã—ã¦ä½¿ã‚ã‚Œã€ãŸãã•ã‚“ã®è¿½åŠ å±žæ€§ã‚’使用ã—ã¦ãã®äººç‰©ã®ã‚ªãƒ–ジェクト クラスã®ã‚¨ãƒ³ãƒˆãƒªã«å‰²ã‚Šå½“ã¦ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1100982">
+OID: <CODE>0.9.2342.19200300.100.4.4</CODE><P></A>
+
+<A NAME="1101121">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1100985">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1100987">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1100992">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1100994">
+ã“ã®ãƒ¦ãƒ¼ã‚¶ãŒå¾“事ã™ã‚‹äº‹æ¥­ã‚¿ã‚¤ãƒ—。<P></A>
+
+<tr><td>
+<A NAME="1100999">
+<a href="attribut.htm#1201909">drink</A><P></A>
+<td>
+<A NAME="1101001">
+ユーザã®å¥½ã¿ã®é£²ã¿ç‰©<P></A>
+
+<tr><td>
+<A NAME="1101006">
+<a href="attribut.htm#1201936">homePhone</A><P></A>
+<td>
+<A NAME="1101008">
+ユーザã®é›»è©±ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101013">
+<a href="attribut.htm#1201947">homePostalAddress</A><P></A>
+<td>
+<A NAME="1101015">
+ユーザã®è‡ªå®…ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101020">
+<a href="attribut.htm#1201988">janetMailbox</A><P></A>
+<td>
+<A NAME="1101022">
+ユーザã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレス。<P></A>
+
+<tr><td>
+<A NAME="1101027">
+<a href="attribut.htm#1189404">mail</A><P></A>
+<td>
+<A NAME="1101029">
+ユーザã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレス。<P></A>
+
+<tr><td>
+<A NAME="1101034">
+<a href="attribut.htm#1202044">mailPreferenceOption</A><P></A>
+<td>
+<A NAME="1101036">
+(é›»å­ã¾ãŸã¯ç‰©ç†çš„ãª)メーリング リストã«ãƒ¦ãƒ¼ã‚¶åã‚’å«ã‚ã‚‹ã“ã¨ã«é–¢ã™ã‚‹ç’°å¢ƒè¨­å®šã‚’示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101041">
+<a href="attribut.htm#1202056">mobile</A><P></A>
+<td>
+<A NAME="1101043">
+ユーザã®æºå¸¯é›»è©±ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101048">
+<a href="attribut.htm#1202208">organizationalStatus</A><P></A>
+<td>
+<A NAME="1101175">
+ユーザã®é›‡ç”¨ã‚¿ã‚¤ãƒ—(フルタイムãªã©)。<P></A>
+
+<tr><td>
+<A NAME="1101055">
+<a href="attribut.htm#1202220">otherMailbox</A><P></A>
+<td>
+<A NAME="1101057">
+X.400ã¨rfc822以外ã®é›»å­ãƒ¡ãƒ¼ãƒ«ãƒœãƒƒã‚¯ã‚¹ タイプã®å€¤ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101062">
+<a href="attribut.htm#1003070">pager</A><P></A>
+<td>
+<A NAME="1101064">
+ユーザã®ãƒã‚±ãƒƒãƒˆãƒ™ãƒ«ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101069">
+<a href="attribut.htm#1202229">personalSignature</A><P></A>
+<td>
+<A NAME="1101071">
+ユーザã®ç½²åファイル。<P></A>
+
+<tr><td>
+<A NAME="1101076">
+<a href="attribut.htm#1202238">personalTitle</A><P></A>
+<td>
+<A NAME="1101078">
+ユーザã®å€‹äººã®å½¹è·<P></A>
+
+<tr><td>
+<A NAME="1101083">
+<a href="attribut.htm#1202605">preferredDeliveryMethod</A><P></A>
+<td>
+<A NAME="1101085">
+ユーザãŒå¸Œæœ›ã™ã‚‹é€£çµ¡æ–¹æ³•ã¾ãŸã¯é…é”方法。<P></A>
+
+<tr><td>
+<A NAME="1101090">
+<a href="attribut.htm#1204477">roomNumber</A><P></A>
+<td>
+<A NAME="1101092">
+ユーザã®éƒ¨å±‹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101097">
+<a href="attribut.htm#1202691">secretary</A><P></A>
+<td>
+<A NAME="1101099">
+ユーザã®ç§˜æ›¸ã¾ãŸã¯ã‚¢ã‚·ã‚¹ã‚¿ãƒ³ãƒˆã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1101104">
+<a href="attribut.htm#1202782">textEncodedORAddress</A><P></A>
+<td>
+<A NAME="1101106">
+æš—å·åŒ–ã•ã‚ŒãŸãƒ†ã‚­ã‚¹ãƒˆã«ã‚ˆã‚‹ãƒ¦ãƒ¼ã‚¶ã®Originator/Recipient (X.400)アドレス。<P></A>
+
+<tr><td>
+<A NAME="1101111">
+<a href="attribut.htm#1296804">uid</A><P></A>
+<td>
+<A NAME="1101113">
+ユーザã®ãƒ­ã‚°ã‚ªãƒ³ID。<P></A>
+
+<tr><td>
+<A NAME="1101118">
+<a href="attribut.htm#1202840">userClass</A><P></A>
+<td>
+<A NAME="1101120">
+ユーザã®ã‚«ãƒ†ã‚´ãƒªã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1100862">&nbsp;
+</A>
+<A NAME="nsLicenseUser">
+<H3> nsLicenseUser</H3>
+</A>
+
+
+
+<A NAME="1100863">
+クライアントã”ã¨ã«å¥‘ç´„ã•ã‚Œã¦ã„ã‚‹Netscape サーãƒã®ä½¿ç”¨è¨±è«¾æ›¸ã®è¿½è·¡ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。nsLicenseUserã¯ã€inetOrgPersonオブジェクト クラスã¨ä½µç”¨ã•ã‚Œã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã®å†…容ã¯ã€Netscape管ç†ã‚µãƒ¼ãƒã®[ユーザãŠã‚ˆã³ã‚°ãƒ«ãƒ¼ãƒ—]領域ã§ç®¡ç†ã§ãã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1100864">
+OID: <CODE>2.16.840.1.113730.3.2.7</CODE><P></A>
+
+<A NAME="1100891">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1100867">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1100869">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1100873">
+<a href="attribut.htm#1091847">nsLicensedFor</A><P></A>
+<td>
+<A NAME="1100875">
+ユーザãŒä½¿ç”¨è¨±è«¾å¥‘ç´„ã‚’æŒã¤Netscapeサーãƒã€‚<P></A>
+
+<tr><td>
+<A NAME="1107587">
+<a href="attribut.htm#1091864">nsLicenseEndTime</A><P></A>
+<td>
+<A NAME="1107589">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1100880">
+<a href="attribut.htm#1091859">nsLicenseStartTime</A><P></A>
+<td>
+<A NAME="1100882">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089442">&nbsp;
+</A>
+<A NAME="ntUser">
+<H3> ntUser</H3>
+</A>
+
+
+
+<A NAME="1089443">
+Directory Serverã¨Windows NTãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯é–“ã§åŒæœŸåŒ–ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’指定ã—ã¾ã™ã€‚ntUserã«ã‚ˆã£ã¦å®šç¾©ã•ã‚Œã‚‹å±žæ€§ã¯ã€NTåŒæœŸåŒ–を支æ´ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1098670">
+OID: <CODE>2.16.840.1.113730.3.2.8</CODE><P></A>
+<a name="1089444">
+<B>
+
+<P>
+ノート
+</P>
+</B>
+
+</a>
+
+
+<A NAME="1089445">
+ntUserCreateNewAccountã€ntUserDomainIdã€ntUserDeleteAccountを除ãã€ntUser属性ã¯ã™ã¹ã¦èª­è¾¼ã¿å°‚用ã§ã™ã€‚次ã®NTåŒæœŸåŒ–ãŒè¡Œã‚れる際ã«ã€èª­è¾¼ã¿å°‚用ntUser属性ã¸ã®å¤‰æ›´ãŒå‰Šé™¤ã•ã‚Œã€å…ƒã®å€¤ã¨ç½®ãæ›ãˆã‚‰ã‚Œã¾ã™ã€‚<P></A>
+
+<A NAME="1089446">
+Directory Serverã®å±žæ€§ã®ã„ãã¤ã‹ã¯ã€[NT user account]フィールドã«ç›´æŽ¥å¯¾å¿œã—ã¦ã„ã¾ã™ã€‚NTã¨åŒæœŸåŒ–ã™ã‚‹æ–°è¦ãƒ¦ãƒ¼ã‚¶ã®ã‚¨ãƒ³ãƒˆãƒªã‚’Directory Serverã«ä½œæˆã™ã‚‹å ´åˆã€Directory Serverã®å±žæ€§ãŒæ¬¡ã®ã‚ˆã†ã«NTユーザ アカウント フィールドã«å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã¾ã™ã€‚
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><td>
+<A NAME="1089449">
+Directory Serverã®å±žæ€§<P></A>
+<td>
+<A NAME="1089451">
+NTユーザ アカウント フィールド<P></A>
+
+<tr><td>
+<A NAME="1089453">
+cnã¾ãŸã¯commonName<P></A>
+<td>
+<A NAME="1089455">
+full_name<P></A>
+
+<tr><td>
+<A NAME="1089457">
+description<P></A>
+<td>
+<A NAME="1089459">
+comment<P></A>
+
+<tr><td>
+<A NAME="1089461">
+userid<P></A>
+<td>
+<A NAME="1089463">
+name<P></A>
+
+<tr><td>
+<A NAME="1089465">
+userPassword<P></A>
+<td>
+<A NAME="1089467">
+password<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+<A NAME="1098497">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1089470">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1089472">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1107594">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1107596">
+ユーザã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107601">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1107603">
+ユーザã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107608">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1107610">
+ユーザãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107615">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1107617">
+ユーザã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1089476">
+<a href="attribut.htm#1015403">ntUserDomainId</A><P></A>
+<td>
+<A NAME="1089479">
+(å¿…é ˆ) 対応ã™ã‚‹NT ユーザã¨ãƒ‰ãƒ¡ã‚¤ãƒ³å。<P></A>
+
+<tr><td>
+<A NAME="1089482">
+<a href="attribut.htm#1013839">ntUserAcctExpires</A><P></A>
+<td>
+<A NAME="1089484">
+ユーザã®NTアカウントã®å¤±åŠ¹æ™‚期を示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089487">
+<a href="attribut.htm#1014052">ntUserAuthFlags</A><P></A>
+<td>
+<A NAME="1089489">
+NTãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ã«ãŠã‘るユーザã®ç‰¹æ¨©ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089492">
+<a href="attribut.htm#1038772">ntUserBadPwCount</A><P></A>
+<td>
+<A NAME="1089494">
+ユーザã®NTログインIDを使用ã—ã¦NTã§å¤±æ•—ã—ãŸãƒ­ã‚°ã‚¤ãƒ³è©¦è¡Œå›žæ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089497">
+<a href="attribut.htm#1014973">ntUserCodePage</A><P></A>
+<td>
+<A NAME="1089499">
+ユーザã®ã‚³ãƒ¼ãƒ‰ ページ。<P></A>
+
+<tr><td>
+<A NAME="1089502">
+<a href="attribut.htm#1246829">ntUserComment</A><P></A>
+<td>
+<A NAME="1089504">
+ユーザã®NTアカウントã®èª¬æ˜Žã€‚<P></A>
+
+<tr><td>
+<A NAME="1089507">
+<a href="attribut.htm#1015155">ntUserCountryCode</A><P></A>
+<td>
+<A NAME="1089509">
+ユーザã®å›½ã‚³ãƒ¼ãƒ‰ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089512">
+<a href="attribut.htm#1015239">ntUserCreateNewAccount</A><P></A>
+<td>
+<A NAME="1089514">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’Directory Serverã«ä½œæˆã™ã‚‹éš›ã«ã€NTアカウントを作æˆã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089517">
+<a href="attribut.htm#1015309">ntUserDeleteAccount</A><P></A>
+<td>
+<A NAME="1089519">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã‚’Directory Serverã«å‰Šé™¤ã™ã‚‹éš›ã«ã€NTアカウントを削除ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089522">
+<a href="attribut.htm#1015534">ntUserFlags</A><P></A>
+<td>
+<A NAME="1089524">
+ã•ã¾ã–ã¾ãªNTアカウント フラグを指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089527">
+<a href="attribut.htm#1015584">ntUserHomeDir</A><P></A>
+<td>
+<A NAME="1089529">
+ユーザã®ãƒ›ãƒ¼ãƒ  ディレクトリã¸ã®ãƒ‘ス。<P></A>
+
+<tr><td>
+<A NAME="1089532">
+<a href="attribut.htm#1015624">ntUserHomeDirDrive</A><P></A>
+<td>
+<A NAME="1089534">
+ユーザã®ãƒ›ãƒ¼ãƒ  ディレクトリã«å‰²ã‚Šå½“ã¦ã‚‰ã‚ŒãŸãƒ‰ãƒ©ã‚¤ãƒ–ã®æ–‡å­—。<P></A>
+
+<tr><td>
+<A NAME="1089537">
+<a href="attribut.htm#1015682">ntUserLastLogoff</A><P></A>
+<td>
+<A NAME="1089539">
+ユーザãŒNTã‹ã‚‰æœ€å¾Œã«ãƒ­ã‚°ã‚ªãƒ•ã—ãŸæ™‚刻。<P></A>
+
+<tr><td>
+<A NAME="1089542">
+<a href="attribut.htm#1015722">ntUserLastLogon</A><P></A>
+<td>
+<A NAME="1089544">
+ユーザãŒNTã«æœ€å¾Œã«ãƒ­ã‚°ã‚ªãƒ³ã—ãŸæ™‚刻。<P></A>
+
+<tr><td>
+<A NAME="1089547">
+<a href="attribut.htm#1015746">ntUserLogonHours</A><P></A>
+<td>
+<A NAME="1089549">
+ユーザãŒNTã«ãƒ­ã‚°ã‚ªãƒ³ã§ãる時間帯。<P></A>
+
+<tr><td>
+<A NAME="1101276">
+<a href="attribut.htm#1015839">ntUserLogonServer</A><P></A>
+<td>
+<A NAME="1089554">
+ユーザã®NTログオンè¦æ±‚ãŒé€ä¿¡ã•ã‚Œã‚‹ã‚µãƒ¼ãƒã€‚<P></A>
+
+<tr><td>
+<A NAME="1089557">
+<a href="attribut.htm#1015984">ntUserMaxStorage</A><P></A>
+<td>
+<A NAME="1089559">
+NTã«ãŠã„ã¦ãƒ¦ãƒ¼ã‚¶ãŒåˆ©ç”¨ã§ãる最大ディスク容é‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089562">
+<a href="attribut.htm#1016030">ntUserNumLogons</A><P></A>
+<td>
+<A NAME="1089564">
+ユーザã®NTアカウントã¸ã®ãƒ­ã‚°ã‚ªãƒ³æˆåŠŸå›žæ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101297">
+<a href="attribut.htm#1021575">ntUserParms</A><P></A>
+<td>
+<A NAME="1101299">
+アプリケーションãŒä½¿ç”¨ã™ã‚‹ãŸã‚ã«äºˆç´„ã•ã‚ŒãŸUnicode文字列。<P></A>
+
+<tr><td>
+<A NAME="1089567">
+<a href="attribut.htm#1016157">ntUserPasswordExpired</A><P></A>
+<td>
+<A NAME="1089569">
+ユーザã®NTパスワードãŒå¤±åŠ¹ã—ã¦ã„ã‚‹ã‹ã‚’示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089572">
+<a href="attribut.htm#1016246">ntUserPrimaryGroupId</A><P></A>
+<td>
+<A NAME="1089574">
+ユーザã®ä¸»è¦ã‚°ãƒ­ãƒ¼ãƒãƒ« グループ。<P></A>
+
+<tr><td>
+<A NAME="1101331">
+<a href="attribut.htm#1017849">ntUserPriv</A><P></A>
+<td>
+<A NAME="1101333">
+Windows NTãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ä¸Šã§ã®ãƒ¦ãƒ¼ã‚¶ã®ç‰¹æ¨©ãƒ¬ãƒ™ãƒ«ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089577">
+<a href="attribut.htm#1016298">ntUserProfile</A><P></A>
+<td>
+<A NAME="1089579">
+ユーザã®NTプロフィールã¸ã®ãƒ‘ス。<P></A>
+
+<tr><td>
+<A NAME="1089582">
+<a href="attribut.htm#1016395">ntUserScriptPath</A><P></A>
+<td>
+<A NAME="1089584">
+ユーザã®NTログイン スクリプトã¸ã®ãƒ‘ス。<P></A>
+
+<tr><td>
+<A NAME="1089587">
+<a href="attribut.htm#1016531">ntUserUniqueId</A><P></A>
+<td>
+<A NAME="1089589">
+ユーザã®NT RIDを示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089592">
+<a href="attribut.htm#1016632">ntUserUnitsPerWeek</A><P></A>
+<td>
+<A NAME="1089594">
+ユーザã®NTUserLogonHoursã®è¨ˆç®—ã«ä½¿ç”¨ã•ã‚Œã‚‹å€¤ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089597">
+<a href="attribut.htm#1016696">ntUserUsrComment</A><P></A>
+<td>
+<A NAME="1089599">
+ユーザã®NTエントリã«é–¢ã™ã‚‹æ³¨é‡ˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1089607">
+<a href="attribut.htm#1016728">ntUserWorkstations</A><P></A>
+<td>
+<A NAME="1089609">
+ユーザãŒNTドメインã«ãƒ­ã‚°ã‚¤ãƒ³ã™ã‚‹ã®ã«ä½¿ç”¨ã§ãã‚‹NTワークステーション。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1002805">&nbsp;
+</A>
+<A NAME="organizationalPerson">
+<H3> organizationalPerson</H3>
+</A>
+
+
+
+<A NAME="1002806">
+組織ã®å¾“業員ã§ã‚ã‚‹ã€ã¾ãŸã¯çµ„ç¹”ã®é–¢ä¿‚者ã§ã‚るユーザã®ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚organizationalPersonã¯personオブジェクト クラスã®æ‹¡å¼µã§ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1096977">
+OID: <CODE>2.5.6.7</CODE><P></A>
+
+<A NAME="1068825">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1070698">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1070700">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1070715">
+<a href="attribut.htm#1292809">destinationIndicator</A><P></A>
+<td>
+<A NAME="1070717">
+公衆電報サービスをæä¾›ã™ã‚‹ã«ã¯ãƒ¦ãƒ¼ã‚¶ã«é–¢é€£ã™ã‚‹å›½ã‚„都市ã®æƒ…å ±ãŒå¿…è¦ã§ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1070720">
+<a href="attribut.htm#1171637">facsimileTelephoneNumber</A><P></A>
+<td>
+<A NAME="1070722">
+ユーザã®ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107649">
+<a href="attribut.htm#1224256">internationalIsdnNumber</A><P></A>
+<td>
+<A NAME="1107651">
+ユーザã®ISDN番å·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1070725">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1070727">
+ユーザãŒå±…ä½ã™ã‚‹å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1070731">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1070733">
+ユーザãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1070736">
+<a href="attribut.htm#1003072">physicalDeliveryOfficeName</A><P></A>
+<td>
+<A NAME="1070738">
+物ç†çš„ã«ã‚‚ã®ã‚’é…é”ã™ã‚‹ãŸã‚ã®ãƒ¦ãƒ¼ã‚¶ã®å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1070741">
+<a href="attribut.htm#1230025">postalAddress</A><P></A>
+<td>
+<A NAME="1070743">
+ユーザã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1070746">
+<a href="attribut.htm#1230036">postalCode</A><P></A>
+<td>
+<A NAME="1070748">
+ユーザã®éƒµä¾¿ç•ªå·(米国ã«ãŠã‘る郵便番å·ãªã©)。<P></A>
+
+<tr><td>
+<A NAME="1070751">
+<a href="attribut.htm#1230043">postOfficeBox</A><P></A>
+<td>
+<A NAME="1070753">
+ユーザã®ç§æ›¸ç®±ã€‚<P></A>
+
+<tr><td>
+<A NAME="1070756">
+<a href="attribut.htm#1202605">preferredDeliveryMethod</A><P></A>
+<td>
+<A NAME="1070758">
+ユーザãŒå¸Œæœ›ã™ã‚‹é€£çµ¡æ–¹æ³•ã¾ãŸã¯é…é”方法。<P></A>
+
+<tr><td>
+<A NAME="1107658">
+<a href="attribut.htm#1202644">registeredAddress</A><P></A>
+<td>
+<A NAME="1107671">
+緊急ã®æ›¸é¡žã®å—ã‘å–ã‚Šãªã©ã€å—å–人ãŒé…é”を確èªã™ã‚‹å¿…è¦ã®ã‚ã‚‹ã‚‚ã®ã‚’é…é”ã™ã‚‹ã®ã«ãµã•ã‚ã—ã„郵é€ç”¨ã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1070766">
+<a href="attribut.htm#1203417">st</A><P></A>
+<td>
+<A NAME="1070768">
+ユーザãŒå±…ä½ã™ã‚‹å·žã¾ãŸã¯éƒ½é“府県。<P></A>
+
+<tr><td>
+<A NAME="1070771">
+<a href="attribut.htm#1202721">street</A><P></A>
+<td>
+<A NAME="1070773">
+ユーザãŒå±…ä½ã™ã‚‹è¡—è·¯ã¨ç•ªåœ°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107723">
+<a href="attribut.htm#1205004">teletexTerminalIdentifier</A><P></A>
+<td>
+<A NAME="1107725">
+組織ã®ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナルã®è­˜åˆ¥å­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1107716">
+<a href="attribut.htm#1205120">telexNumber</A><P></A>
+<td>
+<A NAME="1107718">
+組織ã®ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ç•ªå·<P></A>
+
+<tr><td>
+<A NAME="1107709">
+<a href="attribut.htm#1230152">title</A><P></A>
+<td>
+<A NAME="1107711">
+ユーザã®ä»•äº‹ä¸Šã®å½¹è·<P></A>
+
+<tr><td>
+<A NAME="1107702">
+<a href="attribut.htm#1281763">x121Address</A><P></A>
+<td>
+<A NAME="1107704">
+組織ã®X.121アドレス<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1088567">&nbsp;
+</A>
+<A NAME="organizationalRole">
+<H3> organizationalRole</H3>
+</A>
+
+
+
+<A NAME="1088568">
+組織内ã®äººã€…ãŒæŒã¤å½¹å‰²ã‚’表示ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1096979">
+OID: <CODE>2.5.6.8</CODE><P></A>
+
+<A NAME="1088606">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1088571">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1088573">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1088576">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1088579">
+(å¿…é ˆ) 役割ã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1088588">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1088590">
+役割ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088716">
+<a href="attribut.htm#1292809">destinationIndicator</A><P></A>
+<td>
+<A NAME="1088718">
+ã“ã®å±žæ€§ã¯ã€ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã¸ã®é›»å ±ã‚µãƒ¼ãƒ“スã«ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088780">
+<a href="attribut.htm#1171637">facsimileTelephoneNumber</A><P></A>
+<td>
+<A NAME="1088782">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088726">
+<a href="attribut.htm#1224256">internationalIsdnNumber</A><P></A>
+<td>
+<A NAME="1088728">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®ISDN番å·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088806">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1088808">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ãŒå±…ä½ã™ã‚‹å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088812">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1088814">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088817">
+<a href="attribut.htm#1003072">physicalDeliveryOfficeName</A><P></A>
+<td>
+<A NAME="1088819">
+物ç†çš„ã«ã‚‚ã®ã‚’é…é”ã™ã‚‹ãŸã‚ã®ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101602">
+<a href="attribut.htm#1230025">postalAddress</A><P></A>
+<td>
+<A NAME="1088824">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®å‹¤å‹™å…ˆä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101607">
+<a href="attribut.htm#1230036">postalCode</A><P></A>
+<td>
+<A NAME="1088829">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®å‹¤å‹™å…ˆéƒµä¾¿ç•ªå·(米国ã«ãŠã‘る郵便番å·ãªã©)。<P></A>
+
+<tr><td>
+<A NAME="1101612">
+<a href="attribut.htm#1230043">postOfficeBox</A><P></A>
+<td>
+<A NAME="1088834">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®å‹¤å‹™å…ˆã®ç§æ›¸ç®±ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101617">
+<a href="attribut.htm#1202605">preferredDeliveryMethod</A><P></A>
+<td>
+<A NAME="1088839">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ãŒå¸Œæœ›ã™ã‚‹é€£çµ¡æ–¹æ³•ã¾ãŸã¯é…é”方法。<P></A>
+
+<tr><td>
+<A NAME="1088771">
+<a href="attribut.htm#1202644">registeredAddress</A><P></A>
+<td>
+<A NAME="1106144">
+緊急ã®æ›¸é¡žã®å—ã‘å–ã‚Šãªã©ã€å—å–人ãŒé…é”を確èªã™ã‚‹å¿…è¦ã®ã‚ã‚‹ã‚‚ã®ã‚’é…é”ã™ã‚‹ã®ã«ãµã•ã‚ã—ã„郵é€ç”¨ã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088863">
+<a href="attribut.htm#1202666">roleOccupant</A><P></A>
+<td>
+<A NAME="1088865">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1088593">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1088595">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1101632">
+<a href="attribut.htm#1203417">st</A><P></A>
+<td>
+<A NAME="1088879">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ãŒå±…ä½ã™ã‚‹å·žã¾ãŸã¯éƒ½é“府県。<P></A>
+
+<tr><td>
+<A NAME="1101637">
+<a href="attribut.htm#1202721">street</A><P></A>
+<td>
+<A NAME="1088884">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ãŒå±…ä½ã™ã‚‹è¡—è·¯ã¨ç•ªåœ°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1101642">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1088600">
+ユーザã®é›»è©±ç•ªå·<P></A>
+
+<tr><td>
+<A NAME="1088888">
+<a href="attribut.htm#1205004">teletexTerminalIdentifier</A><P></A>
+<td>
+<A NAME="1088890">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナルã®è­˜åˆ¥å­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088937">
+<a href="attribut.htm#1205120">telexNumber</A><P></A>
+<td>
+<A NAME="1088939">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1088978">
+<a href="attribut.htm#1281763">x121Address</A><P></A>
+<td>
+<A NAME="1088980">
+ã“ã®å½¹å‰²ã®ãƒ¦ãƒ¼ã‚¶ã®X.121アドレス。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089681">&nbsp;
+</A>
+<A NAME="person">
+<H3> person</H3>
+</A>
+
+
+
+<A NAME="1089682">
+人々を概念的ã«è¡¨ç¤ºã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€organizationalPersonオブジェクト クラスã®åŸºæœ¬ã‚¯ãƒ©ã‚¹ã§ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1096975">
+OID: <CODE>2.5.6.6</CODE><P></A>
+
+<A NAME="1089720">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1089685">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1089687">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1089690">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1089693">
+(å¿…é ˆ) ユーザã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1089696">
+<a href="attribut.htm#1230116">sn</A><P></A>
+<td>
+<A NAME="1089699">
+(å¿…é ˆ) ユーザã®å§“ã€ã¤ã¾ã‚Šãƒ©ã‚¹ãƒˆãƒãƒ¼ãƒ ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089702">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1089704">
+ユーザã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1089707">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1089709">
+ユーザã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1089712">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1089714">
+ユーザã®é›»è©±ç•ªå·<P></A>
+
+<tr><td>
+<A NAME="1089717">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1089719">
+ユーザãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãƒã‚¤ãƒ³ãƒ‰ã§ãるパスワード。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1106267">&nbsp;
+</A>
+<A NAME="residentialPerson">
+<H3> residentialPerson</H3>
+</A>
+
+
+
+<A NAME="1106268">
+Directory ServerãŒä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€äººç‰©ã®ä½å±…情報をå«ã¿ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚<P></A>
+
+<A NAME="1106269">
+OID: <CODE>2.5.6.10</CODE><P></A>
+
+<A NAME="1106387">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1106272">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1106274">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1106279">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1106281">
+(å¿…é ˆ) ユーザãŒå±…ä½ã™ã‚‹å ´æ‰€ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106286">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1106288">
+ユーザãŒé–¢ä¸Žã™ã‚‹äº‹æ¥­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106293">
+<a href="attribut.htm#1292809">destinationIndicator</A><P></A>
+<td>
+<A NAME="1106295">
+ã“ã®å±žæ€§ã¯ã€ã“ã®ãƒ¦ãƒ¼ã‚¶ã¸ã®é›»å ±ã‚µãƒ¼ãƒ“スã«ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106299">
+<a href="attribut.htm#1171637">facsimileTelephoneNumber</A><P></A>
+<td>
+<A NAME="1106302">
+ユーザã®ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106307">
+<a href="attribut.htm#1224256">internationalIsdnNumber</A><P></A>
+<td>
+<A NAME="1106309">
+ユーザã®ISDN番å·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106313">
+<a href="attribut.htm#1003072">physicalDeliveryOfficeName</A><P></A>
+<td>
+<A NAME="1106316">
+物ç†çš„ãªé…é€ãŒã§ãる場所。<P></A>
+
+<tr><td>
+<A NAME="1106321">
+<a href="attribut.htm#1230025">postalAddress</A><P></A>
+<td>
+<A NAME="1106323">
+ユーザã®å‹¤å‹™å…ˆéƒµé€ç”¨ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106328">
+<a href="attribut.htm#1230036">postalCode</A><P></A>
+<td>
+<A NAME="1106330">
+ユーザã®å‹¤å‹™å…ˆéƒµä¾¿ç•ªå·(米国ã«ãŠã‘る郵便番å·ãªã©)。<P></A>
+
+<tr><td>
+<A NAME="1106335">
+<a href="attribut.htm#1230043">postOfficeBox</A><P></A>
+<td>
+<A NAME="1106337">
+ユーザã®å‹¤å‹™å…ˆã®ç§æ›¸ç®±ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106342">
+<a href="attribut.htm#1202605">preferredDeliveryMethod</A><P></A>
+<td>
+<A NAME="1106344">
+ユーザãŒå¸Œæœ›ã™ã‚‹é€£çµ¡æ–¹æ³•ã¾ãŸã¯é…é”方法。<P></A>
+
+<tr><td>
+<A NAME="1106349">
+<a href="attribut.htm#1202644">registeredAddress</A><P></A>
+<td>
+<A NAME="1106351">
+緊急ã®æ›¸é¡žã®å—ã‘å–ã‚Šãªã©ã€å—å–人ãŒé…é”を確èªã™ã‚‹å¿…è¦ã®ã‚ã‚‹ã‚‚ã®ã‚’é…é”ã™ã‚‹ã®ã«ãµã•ã‚ã—ã„郵é€ç”¨ã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106356">
+<a href="attribut.htm#1203417">st</A><P></A>
+<td>
+<A NAME="1106358">
+ユーザãŒå±…ä½ã™ã‚‹å·žã¾ãŸã¯éƒ½é“府県。<P></A>
+
+<tr><td>
+<A NAME="1106363">
+<a href="attribut.htm#1202721">street</A><P></A>
+<td>
+<A NAME="1106365">
+ユーザãŒå±…ä½ã™ã‚‹è¡—è·¯ã¨ç•ªåœ°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106370">
+<a href="attribut.htm#1205004">teletexTerminalIdentifier</A><P></A>
+<td>
+<A NAME="1106372">
+ユーザã®ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナルã®è­˜åˆ¥å­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106377">
+<a href="attribut.htm#1205120">telexNumber</A><P></A>
+<td>
+<A NAME="1106379">
+ユーザã®ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106384">
+<a href="attribut.htm#1281763">x121Address</A><P></A>
+<td>
+<A NAME="1106386">
+ユーザã®X.121アドレス。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078660">&nbsp;
+</A>
+<A NAME="Calendar Server Extensions">
+<H2> Calendar Serverã®æ‹¡å¼µ</H2>
+</A>
+
+<A NAME="1081153">
+以下ã®ã‚ªãƒ–ジェクト クラスã¯ã€Netscape Calendar Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚ã“ã“ã§èª¬æ˜Žã•ã‚Œã¦ã„るオブジェクト クラスã¯ã€<a href="objclass.htm#1078663">netscapeCalendarServer</A>ã€<a href="objclass.htm#1097420">nsCalAdmin</A>ã€<a href="objclass.htm#1084445">nsCalResource</A>ã€ãŠã‚ˆã³<a href="objclass.htm#1078672">nsCalUser</A>ã§ã™ã€‚<P></A>
+
+
+<A NAME="1078663">&nbsp;
+</A>
+<A NAME="netscapeCalendarServer">
+<H3> netscapeCalendarServer</H3>
+</A>
+
+
+
+<A NAME="1078664">
+Netscape Calendar Server(カレンダーサーãƒï¼‰ã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097056">
+OID: <CODE>2.16.840.1.113730.3.2.17</CODE><P></A>
+
+<A NAME="1107920">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1107742">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1107744">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1107749">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1107751">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+<A NAME="1097417">
+<P></A>
+
+
+<A NAME="1097420">&nbsp;
+</A>
+<A NAME="nsCalAdmin">
+<H3> nsCalAdmin</H3>
+</A>
+
+
+
+<A NAME="1097421">
+Netscape Calendar Server(カレンダーサーãƒï¼‰ãŒä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€ã‚«ãƒ¬ãƒ³ãƒ€ サーãƒã‚¢ãƒ‰ãƒŸãƒ‹ã‚¹ãƒˆãƒ¬ãƒ¼ã‚¿ã®æƒ…報をディレクトリã§ä¿å­˜ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1097052">
+OID: <CODE>2.16.840.1.113730.3.2.15</CODE><P></A>
+
+<A NAME="1084442">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1102028">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1102030">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108105">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108107">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1108100">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1102037">
+管ç†è€…ã®ä¸€èˆ¬å。<P></A>
+
+<tr><td>
+<A NAME="1102042">
+<a href="attribut.htm#1171637">facsimileTelephoneNumber</A><P></A>
+<td>
+<A NAME="1102044">
+管ç†è€…ã®ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·<P></A>
+
+<tr><td>
+<A NAME="1102049">
+<a href="attribut.htm#1104309">generationQualifier</A><P></A>
+<td>
+<A NAME="1102051">
+Lightweight Internet Person Schema (LIPS)ã®generation Qualifierã¨åŒã˜ã§ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102056">
+<a href="attribut.htm#1229534">givenName</A><P></A>
+<td>
+<A NAME="1102058">
+管ç†è€…ã®åã¾ãŸã¯ãƒ•ã‚¡ãƒ¼ã‚¹ãƒˆãƒãƒ¼ãƒ ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102063">
+<a href="attribut.htm#1229543">initials</A><P></A>
+<td>
+<A NAME="1102065">
+管ç†è€…ã®ã‚¤ãƒ‹ã‚·ãƒ£ãƒ«ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102193">
+<a href="attribut.htm#1104932">nsCalAccess</A><P></A>
+<td>
+<A NAME="1102195">
+管ç†è€…ã«Calendar Serverã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã™ã‚‹ã‹æ‹’å¦ã™ã‚‹ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102198">
+<a href="attribut.htm#1166044">nsCalAccessDomain</A><P></A>
+<td>
+<A NAME="1102200">
+Calendar Server管ç†è€…ãŒCalendar Serverデータã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã«ä½¿ç”¨ã§ãるインターãƒãƒƒãƒˆ ドメインã¾ãŸã¯IPアドレス。ã“ã®å±žæ€§ã¯å°†æ¥ã®ä½¿ç”¨ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102203">
+<a href="attribut.htm#1104994">nsCalAdmd</A><P></A>
+<td>
+<A NAME="1102205">
+管ç†è€…ã®X.400管ç†ãƒ‰ãƒ¡ã‚¤ãƒ³å<P></A>
+
+<tr><td>
+<A NAME="1102208">
+<a href="attribut.htm#1164493">nsCalFlags</A><P></A>
+<td>
+<A NAME="1102210">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102213">
+<a href="attribut.htm#1157806">nsCalHost</A><P></A>
+<td>
+<A NAME="1102215">
+Calendar Server管ç†è€…ã®æƒ…報をホストã™ã‚‹ã‚³ãƒ³ãƒ”ュータã®ãƒ›ã‚¹ãƒˆåã¾ãŸã¯IPアドレス。<P></A>
+
+<tr><td>
+<A NAME="1102218">
+<a href="attribut.htm#1105333">nsCalLanguageId</A><P></A>
+<td>
+<A NAME="1102220">
+é›»å­ãƒ¡ãƒ¼ãƒ«é€šçŸ¥ã‚’å—ã‘ã‚‹ã®ã«ç®¡ç†è€…ãŒå¸Œæœ›ã™ã‚‹è¨€èªžã€‚<P></A>
+
+<tr><td>
+<A NAME="1102223">
+<a href="attribut.htm#1157846">nsCalNodeAlias</A><P></A>
+<td>
+<A NAME="1102225">
+管ç†è€…データãŒä¿å­˜ã•ã‚Œã¦ã„るノードã®ãƒ‹ãƒ¼ãƒ¢ãƒ‹ãƒƒã‚¯å。<P></A>
+
+<tr><td>
+<A NAME="1102228">
+<a href="attribut.htm#1105739">nsCalOrgUnit2</A><P></A>
+<td>
+<A NAME="1102230">
+X.400 Organization Unit 2 (OU2)<P></A>
+
+<tr><td>
+<A NAME="1102233">
+<a href="attribut.htm#1105752">nsCalOrgUnit3</A><P></A>
+<td>
+<A NAME="1102235">
+X.400 Organization Unit 3 (OU3)<P></A>
+
+<tr><td>
+<A NAME="1102238">
+<a href="attribut.htm#1105815">nsCalOrgUnit4</A><P></A>
+<td>
+<A NAME="1102240">
+X.400 Organization Unit 4 (OU4)<P></A>
+
+<tr><td>
+<A NAME="1102243">
+<a href="attribut.htm#1105834">nsCalPasswordRequired</A><P></A>
+<td>
+<A NAME="1102245">
+CalendarユーザãŒCalendarデータã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã«ãƒ‘スワードを入力ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102248">
+<a href="attribut.htm#1105891">nsCalPrmd</A><P></A>
+<td>
+<A NAME="1102250">
+管ç†è€…ã®X.400 プライベート管ç†ãƒ‰ãƒ¡ã‚¤ãƒ³å。<P></A>
+
+<tr><td>
+<A NAME="1102253">
+<a href="attribut.htm#1106093">nsCalServerVersion</A><P></A>
+<td>
+<A NAME="1102255">
+Calendar Server管ç†è€…ã®ãƒ‡ãƒ¼ã‚¿ã‚’ホストã™ã‚‹Calendar Serverã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102258">
+<a href="attribut.htm#1106115">nsCalSysopCanWritePassword</A><P></A>
+<td>
+<A NAME="1102260">
+Calendar Server管ç†è€…ãŒãƒ¦ãƒ¼ã‚¶æƒ…報を上書ãã§ãã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102263">
+<a href="attribut.htm#1106218">nsCalXItemId</A><P></A>
+<td>
+<A NAME="1102265">
+管ç†è€…データãŒä¿å­˜ã•ã‚Œã¦ã„るノードã®ãƒ‹ãƒ¼ãƒ¢ãƒ‹ãƒƒã‚¯å。<P></A>
+
+<tr><td>
+<A NAME="1102070">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1102072">
+管ç†è€…ãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102077">
+<a href="attribut.htm#1230025">postalAddress</A><P></A>
+<td>
+<A NAME="1102079">
+管ç†è€…ã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102084">
+<a href="attribut.htm#1290325">sn</A><P></A>
+<td>
+<A NAME="1102086">
+管ç†è€…ã®å§“ã¾ãŸã¯ãƒ©ã‚¹ãƒˆãƒãƒ¼ãƒ ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102091">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1102093">
+リソースã®é›»è©±ç•ªå·<P></A>
+
+<tr><td>
+<A NAME="1102098">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1102100">
+管ç†è€…ã®ãƒ‘スワード。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1084445">&nbsp;
+</A>
+<A NAME="nsCalResource">
+<H3> nsCalResource</H3>
+</A>
+
+
+
+<A NAME="1084446">
+Netscape Calendar ServerãŒä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€ä¼šè­°å®¤ãªã©ã®ã‚«ãƒ¬ãƒ³ãƒ€è³‡æºã«é–¢ã™ã‚‹æƒ…報をディレクトリã§ä¿å­˜ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1097054">
+OID: <CODE>2.16.840.1.113730.3.2.16</CODE><P></A>
+
+<A NAME="1079532">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1079408">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1079410">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108114">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108116">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102373">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1080905">
+リソースã®ä¸€èˆ¬å。<P></A>
+
+<tr><td>
+<A NAME="1102378">
+<a href="attribut.htm#1171637">facsimileTelephoneNumber</A><P></A>
+<td>
+<A NAME="1081264">
+リソースã«é–¢ä¿‚ã™ã‚‹ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102455">
+<a href="attribut.htm#1104932">nsCalAccess</A><P></A>
+<td>
+<A NAME="1083840">
+リソースãŒCalendar Serverã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã‚’許å¯ã™ã‚‹ã‹æ‹’å¦ã™ã‚‹ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102460">
+<a href="attribut.htm#1166044">nsCalAccessDomain</A><P></A>
+<td>
+<A NAME="1083873">
+CalendarリソースãŒCalendarデータã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã«ä½¿ç”¨ã§ãるインターãƒãƒƒãƒˆ ドメインã¾ãŸã¯IPアドレス。ã“ã®å±žæ€§ã¯å°†æ¥ã®ä½¿ç”¨ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079434">
+<a href="attribut.htm#1105005">nsCalDefaultNoteReminder</A><P></A>
+<td>
+<A NAME="1084773">
+ノート リマインダã®ã‚¿ã‚¤ãƒ—ãŒã‚ã‚‹å ´åˆã€å…¥åŠ›ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079439">
+<a href="attribut.htm#1162428">nsCalDefaultReminder</A><P></A>
+<td>
+<A NAME="1084609">
+イベント リマインダã®ã‚¿ã‚¤ãƒ—ãŒã‚ã‚‹å ´åˆã€å…¥åŠ›ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079444">
+<a href="attribut.htm#1105139">nsCalDefaultTaskReminder</A><P></A>
+<td>
+<A NAME="1084642">
+タスク リマインダã®ã‚¿ã‚¤ãƒ—ãŒã‚ã‚‹å ´åˆã€å…¥åŠ›ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079449">
+<a href="attribut.htm#1105164">nsCalDisplayPrefs</A><P></A>
+<td>
+<A NAME="1084565">
+リソースã®è¡¨ç¤ºè¨­å®šã€‚<P></A>
+
+<tr><td>
+<A NAME="1102485">
+<a href="attribut.htm#1164493">nsCalFlags</A><P></A>
+<td>
+<A NAME="1079456">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102490">
+<a href="attribut.htm#1157806">nsCalHost</A><P></A>
+<td>
+<A NAME="1083661">
+Calendarリソースã®æƒ…報をä¿æŒã™ã‚‹ã‚³ãƒ³ãƒ”ュータã®ãƒ›ã‚¹ãƒˆåã¾ãŸã¯IPアドレス。<P></A>
+
+<tr><td>
+<A NAME="1102495">
+<a href="attribut.htm#1105333">nsCalLanguageId</A><P></A>
+<td>
+<A NAME="1085033">
+リソース管ç†è€…ãŒé›»å­ãƒ¡ãƒ¼ãƒ«é€šçŸ¥ã‚’å—ã‘ã¨ã‚ŠãŸã„言語。<P></A>
+
+<tr><td>
+<A NAME="1102500">
+<a href="attribut.htm#1157846">nsCalNodeAlias</A><P></A>
+<td>
+<A NAME="1083631">
+管ç†è€…データãŒä¿å­˜ã•ã‚Œã¦ã„るノードã®ãƒ‹ãƒ¼ãƒ¢ãƒ‹ãƒƒã‚¯å。<P></A>
+
+<tr><td>
+<A NAME="1079474">
+<a href="attribut.htm#1118755">nsCalNotifMechanism</A><P></A>
+<td>
+<A NAME="1079476">
+イベントã®å‚加者ã¸ã®é€šçŸ¥ã«ä½¿ç”¨ã™ã‚‹ãƒ¡ã‚«ãƒ‹ã‚ºãƒ (通常ã¯é›»å­ãƒ¡ãƒ¼ãƒ«)。<P></A>
+
+<tr><td>
+<A NAME="1079479">
+<a href="attribut.htm#1105631">nsCalOperatingPrefs</A><P></A>
+<td>
+<A NAME="1084552">
+リソースã®å‹•ä½œè¨­å®šã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079613">
+<a href="attribut.htm#1105834">nsCalPasswordRequired</A><P></A>
+<td>
+<A NAME="1084950">
+ã“ã®ãƒªã‚½ãƒ¼ã‚¹ã«ã¤ã„ã¦ã®ã‚«ãƒ¬ãƒ³ãƒ€ データã«ã‚«ãƒ¬ãƒ³ãƒ€ ユーザãŒã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã«ãƒ‘スワードを入力ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079509">
+<a href="attribut.htm#1105943">nsCalRefreshPrefs</A><P></A>
+<td>
+<A NAME="1079511">
+リソースã®å‹•ä½œç’°å¢ƒã‚’リフレッシュã™ã‚‹ã‹ã©ã†ã‹ã€ã¾ãŸãã®é »åº¦ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079626">
+<a href="attribut.htm#1105996">nsCalResourceCapacity</A><P></A>
+<td>
+<A NAME="1079619">
+部屋ã«å…¥ã‚Œã‚‹æœ€å¤§äººæ•°ãªã©ã®ãƒªã‚½ãƒ¼ã‚¹ã®åŽå®¹èƒ½åŠ›ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079631">
+<a href="attribut.htm#1209242">nsCalResourceNumber</A><P></A>
+<td>
+<A NAME="1079623">
+リソースã®ID番å·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079514">
+<a href="attribut.htm#1106093">nsCalServerVersion</A><P></A>
+<td>
+<A NAME="1083778">
+Calendarリソースã®ãƒ‡ãƒ¼ã‚¿ã‚’ホストã™ã‚‹Calendar Serverã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079519">
+<a href="attribut.htm#1106115">nsCalSysopCanWritePassword</A><P></A>
+<td>
+<A NAME="1085009">
+Calendar Serverã®ç®¡ç†è€…ãŒãƒªã‚½ãƒ¼ã‚¹ã®ãƒ‘スワードを上書ãã§ãã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079524">
+<a href="attribut.htm#1106160">nsCalTimezone</A><P></A>
+<td>
+<A NAME="1079526">
+リソースãŒã‚ã‚‹ã¨ã“ã‚ã®ç¾åœ¨ã®ã‚¿ã‚¤ãƒ ã‚¾ãƒ¼ãƒ³ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079529">
+<a href="attribut.htm#1106218">nsCalXItemId</A><P></A>
+<td>
+<A NAME="1084486">
+カレンダ リソース データãŒä¿å­˜ã•ã‚Œã¦ã„るノードã®ID番å·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102416">
+<a href="attribut.htm#1230025">postalAddress</A><P></A>
+<td>
+<A NAME="1102418">
+リソースã®éƒµé€ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102409">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1102411">
+リソースã®é›»è©±ç•ªå·<P></A>
+
+<tr><td>
+<A NAME="1102402">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1102404">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078672">&nbsp;
+</A>
+<A NAME="nsCalUser">
+<H3> nsCalUser</H3>
+</A>
+
+
+
+<A NAME="1078673">
+Netscape Calendar ServerãŒä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€ã‚«ãƒ¬ãƒ³ãƒ€ ユーザã«é–¢ã™ã‚‹æƒ…報をディレクトリã§ä¿å­˜ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1097050">
+OID: <CODE>2.16.840.1.113730.3.2.14</CODE><P></A>
+
+<A NAME="1078727">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078677">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078679">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108154">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108156">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078683">
+<a href="attribut.htm#1104309">generationQualifier</A><P></A>
+<td>
+<A NAME="1078686">
+Lightweight Internet Person Schema (LIPS)ã®generation Qualifierã¨åŒã˜ã§ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102672">
+<a href="attribut.htm#1104932">nsCalAccess</A><P></A>
+<td>
+<A NAME="1083848">
+ユーザã«Calendar Serverã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ã‚’許å¯ã™ã‚‹ã‹å¦å®šã™ã‚‹ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102677">
+<a href="attribut.htm#1166044">nsCalAccessDomain</A><P></A>
+<td>
+<A NAME="1078696">
+CalendarユーザãŒCalendarデータã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã«ä½¿ç”¨ã§ãるインターãƒãƒƒãƒˆ ドメインã¾ãŸã¯IPアドレス。ã“ã®å±žæ€§ã¯å°†æ¥ã®ä½¿ç”¨ã®ãŸã‚ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102682">
+<a href="attribut.htm#1104994">nsCalAdmd</A><P></A>
+<td>
+<A NAME="1083983">
+ユーザã®X.400管ç†ãƒ‰ãƒ¡ã‚¤ãƒ³å。<P></A>
+
+<tr><td>
+<A NAME="1102697">
+<a href="attribut.htm#1105005">nsCalDefaultNoteReminder</A><P></A>
+<td>
+<A NAME="1084798">
+ノート リマインダã®ã‚¿ã‚¤ãƒ—ãŒã‚ã‚‹å ´åˆã€å…¥åŠ›ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102702">
+<a href="attribut.htm#1162428">nsCalDefaultReminder</A><P></A>
+<td>
+<A NAME="1078711">
+イベント リマインダã®ã‚¿ã‚¤ãƒ—ãŒã‚ã‚‹å ´åˆã€å…¥åŠ›ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102707">
+<a href="attribut.htm#1105139">nsCalDefaultTaskReminder</A><P></A>
+<td>
+<A NAME="1084619">
+タスク リマインダã®ã‚¿ã‚¤ãƒ—ãŒã‚ã‚‹å ´åˆã€å…¥åŠ›ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102712">
+<a href="attribut.htm#1105164">nsCalDisplayPrefs</A><P></A>
+<td>
+<A NAME="1078721">
+ユーザã®è¡¨ç¤ºè¨­å®šã€‚<P></A>
+
+<tr><td>
+<A NAME="1102717">
+<a href="attribut.htm#1164493">nsCalFlags</A><P></A>
+<td>
+<A NAME="1078726">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102722">
+<a href="attribut.htm#1157806">nsCalHost</A><P></A>
+<td>
+<A NAME="1083672">
+Calendarユーザã®æƒ…報をä¿æŒã™ã‚‹ã‚³ãƒ³ãƒ”ュータã®ãƒ›ã‚¹ãƒˆåã¾ãŸã¯IPアドレスã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102727">
+<a href="attribut.htm#1105333">nsCalLanguageId</A><P></A>
+<td>
+<A NAME="1085040">
+é›»å­ãƒ¡ãƒ¼ãƒ«é€šçŸ¥ã‚’å—ã‘ã‚‹ã®ã«ãƒ¦ãƒ¼ã‚¶ãŒå¸Œæœ›ã™ã‚‹è¨€èªžã€‚<P></A>
+
+<tr><td>
+<A NAME="1102732">
+<a href="attribut.htm#1157846">nsCalNodeAlias</A><P></A>
+<td>
+<A NAME="1083651">
+ユーザデータãŒä¿å­˜ã•ã‚Œã¦ã„るノードã®ãƒ‹ãƒ¼ãƒ¢ãƒ‹ãƒƒã‚¯å。<P></A>
+
+<tr><td>
+<A NAME="1102737">
+<a href="attribut.htm#1118755">nsCalNotifMechanism</A><P></A>
+<td>
+<A NAME="1084582">
+イベントã®å‚加者ã¸ã®é€šçŸ¥ã«ä½¿ç”¨ã™ã‚‹ãƒ¡ã‚«ãƒ‹ã‚ºãƒ (通常ã¯é›»å­ãƒ¡ãƒ¼ãƒ«)。<P></A>
+
+<tr><td>
+<A NAME="1102742">
+<a href="attribut.htm#1105631">nsCalOperatingPrefs</A><P></A>
+<td>
+<A NAME="1078828">
+ユーザã®å‹•ä½œè¨­å®šã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078821">
+<a href="attribut.htm#1105739">nsCalOrgUnit2</A><P></A>
+<td>
+<A NAME="1078823">
+X.400 Organization Unit 2 (OU2)<P></A>
+
+<tr><td>
+<A NAME="1078816">
+<a href="attribut.htm#1105752">nsCalOrgUnit3</A><P></A>
+<td>
+<A NAME="1083904">
+X.400 Organization Unit 3 (OU3)<P></A>
+
+<tr><td>
+<A NAME="1078811">
+<a href="attribut.htm#1105815">nsCalOrgUnit4</A><P></A>
+<td>
+<A NAME="1083922">
+X.400 Organization Unit 4 (OU4)<P></A>
+
+<tr><td>
+<A NAME="1102762">
+<a href="attribut.htm#1105834">nsCalPasswordRequired</A><P></A>
+<td>
+<A NAME="1082746">
+カレンダ ユーザãŒã‚«ãƒ¬ãƒ³ãƒ€ãƒ‡ãƒ¼ã‚¿ã«ã‚¢ã‚¯ã‚»ã‚¹ã™ã‚‹ã®ã«ãƒ‘スワードを入力ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1102767">
+<a href="attribut.htm#1105891">nsCalPrmd</A><P></A>
+<td>
+<A NAME="1083961">
+ユーザã®X.400プライベート管ç†ãƒ‰ãƒ¡ã‚¤ãƒ³å。<P></A>
+
+<tr><td>
+<A NAME="1078796">
+<a href="attribut.htm#1105943">nsCalRefreshPrefs</A><P></A>
+<td>
+<A NAME="1084526">
+ユーザã®ã‚«ãƒ¬ãƒ³ãƒ€æƒ…å ±ãŒæœ€æ–°ã®ã‚‚ã®ã§æ›´æ–°ã•ã‚Œã‚‹ã¹ãã‹ã€ã©ã‚Œãらã„ã®é »åº¦ã§è¡Œã‚れるã¹ãã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078791">
+<a href="attribut.htm#1106093">nsCalServerVersion</A><P></A>
+<td>
+<A NAME="1083785">
+Calendarユーザã®ãƒ‡ãƒ¼ã‚¿ã‚’ホストã™ã‚‹Calendar Serverã®ãƒãƒ¼ã‚¸ãƒ§ãƒ³ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078786">
+<a href="attribut.htm#1106115">nsCalSysopCanWritePassword</A><P></A>
+<td>
+<A NAME="1085016">
+Calendar Serverã®ç®¡ç†è€…ãŒãƒ¦ãƒ¼ã‚¶ã®ãƒ‘スワードを上書ãã§ãã‚‹ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078781">
+<a href="attribut.htm#1106160">nsCalTimezone</A><P></A>
+<td>
+<A NAME="1085063">
+ユーザã®ç¾åœ¨ã®ã‚¿ã‚¤ãƒ ã‚¾ãƒ¼ãƒ³ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078836">
+<a href="attribut.htm#1106218">nsCalXItemId</A><P></A>
+<td>
+<A NAME="1084493">
+カレンダ ユーザã®ãƒ‡ãƒ¼ã‚¿ãŒä¿å­˜ã•ã‚Œã¦ã„るノードã®ID番å·ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078479">&nbsp;
+</A>
+<A NAME="Certificate Server Extensions">
+<H2> Certificate Serverã®æ‹¡å¼µ</H2>
+</A>
+
+<A NAME="1080510">
+ã“ã®ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã§ã¯ã€Netscape Certificate Serverã§ä½¿ç”¨ã•ã‚Œã¦ã„ã‚‹<a href="objclass.htm#1078501">netscapeCertificateServer</A>ã®ã‚ªãƒ–ジェクト クラスãŒèª¬æ˜Žã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+<A NAME="1078501">&nbsp;
+</A>
+<A NAME="netscapeCertificateServer">
+<H3> netscapeCertificateServer</H3>
+</A>
+
+
+
+<A NAME="1078564">
+Netscape証明書サーãƒã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097058">
+OID: <CODE>2.16.840.1.113730.3.2.18</CODE><P></A>
+
+<A NAME="1108183">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108173">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108175">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108180">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108182">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078576">&nbsp;
+</A>
+<A NAME="Collabra Server Extensions">
+<H2> Collabra Serverã®æ‹¡å¼µ</H2>
+</A>
+
+<A NAME="1080748">
+ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€Netscape Collabra Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚ã“ã“ã§èª¬æ˜Žã•ã‚Œã¦ã„るオブジェクト クラスã¯ã€<a href="objclass.htm#1078579">netscapeNewsServer</A>ã¨<a href="objclass.htm#1078583">nginfo</A>ã§ã™ã€‚<P></A>
+
+
+<A NAME="1078579">&nbsp;
+</A>
+<A NAME="netscapeNewsServer">
+<H3> netscapeNewsServer</H3>
+</A>
+
+
+
+<A NAME="1108221">
+Netscape Collabra Serverã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097154">
+OID: <CODE>2.16.840.1.113730.3.2.27</CODE><P></A>
+
+<A NAME="1108205">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108195">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108197">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108202">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108204">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078583">&nbsp;
+</A>
+<A NAME="nginfo">
+<H3> nginfo</H3>
+</A>
+
+
+
+<A NAME="1078584">
+Netscape Collabra ServerãŒä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€discussion(news)グループã®æƒ…報をä¿å­˜ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1098802">
+OID: <CODE>2.16.840.1.113730.3.2.26</CODE><P></A>
+
+<A NAME="1105306">
+ã“ã®ã‚¿ã‚¤ãƒ—ã®ã‚ªãƒ–ジェクト クラスã¯<I>ou=Netscape Servers</I>ã®ä¸‹ã®å€‹åˆ¥ã®ã‚µãƒ–ツリーã«ä¿å­˜ã•ã‚Œã¦ã„ã¾ã™ã€‚ブランムãƒã‚¤ãƒ³ãƒˆã¯ <I>ngcomponent=.</I> エントリã«ã‚ˆã£ã¦ç¤ºã•ã‚Œã¾ã™ã€‚ã—ãŸãŒã£ã¦ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®æŽ¥å°¾è¾žãŒ<I>o=Airius.com</I>ã§ã‚ã‚‹å ´åˆã¯ã€ã™ã¹ã¦ã®è¨Žè«–グループ情報ã¯æ¬¡ã®ã‚µãƒ–ツリーã«ä¿å­˜ã•ã‚Œã¦ã¾ã™ã€‚<P></A>
+<PRE><A NAME="1078586">
+<I>ngcomponent=., o=Airius.com</I>
+</A>
+</PRE>
+<A NAME="1078587">
+ã“ã®ã‚µãƒ–ツリーã¨ãã®å†…容ã¯ã€Collabra Serverã«ã‚ˆã£ã¦ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«æ›¸ãè¾¼ã¾ã‚Œã¾ã™ã€‚ã“ã®ãƒ„リーã®æ§‹é€ <CODE>nginfo<CODE>ã®ã‚ªãƒ–ジェクト クラスã®å½¢å¼ã¨ä½¿ç”¨æ³•ã€ãŠã‚ˆã³<CODE>nginfo</CODE>属性ã®å½¢å¼ã¨ä½¿ç”¨æ³•ã¯ã€äºˆå‘Šãªã—ã«å¤‰æ›´ã•ã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+
+<A NAME="1078640">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078590">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078592">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1078596">
+<a href="attribut.htm#1095332">ngcomponent</A><P></A>
+<td>
+<A NAME="1078599">
+(å¿…é ˆ) 討論グループåã®ä¸€éƒ¨ã€‚<P></A>
+
+<tr><td>
+<A NAME="1108256">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108258">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078602">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1078604">
+討論グループã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103112">
+<a href="attribut.htm#1036977">nsaclrole</A><P></A>
+<td>
+<A NAME="1103114">
+ã•ã¾ã–ã¾ãªCollabraã®å½¹å‰²ã®ã‚¢ã‚¯ã‚»ã‚¹è¨±å¯ã‚»ãƒƒãƒˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1103119">
+<a href="attribut.htm#1037693">nscreator</A><P></A>
+<td>
+<A NAME="1103121">
+討論グループ作æˆè€…ã®ãƒ¦ãƒ¼ã‚¶ID。<P></A>
+
+<tr><td>
+<A NAME="1103133">
+<a href="attribut.htm#1037564">nsflags</A><P></A>
+<td>
+<A NAME="1103135">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103140">
+<a href="attribut.htm#1092030">nsnewsACL</A><P></A>
+<td>
+<A NAME="1103142">
+討論グループã®ã‚¢ã‚¯ã‚»ã‚¹åˆ¶å¾¡ã‚»ãƒƒãƒˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1078627">
+<a href="attribut.htm#1037277">nsprettyname</A><P></A>
+<td>
+<A NAME="1078629">
+討論グループå。<P></A>
+
+<tr><td>
+<A NAME="1108272">
+<a href="attribut.htm#1099985">subtreeACI</A><P></A>
+<td>
+<A NAME="1108274">
+予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078655">&nbsp;
+</A>
+<A NAME="Compass Server Extensions">
+<H2> Compass Serverã®æ‹¡å¼µ</H2>
+</A>
+
+<A NAME="1080778">
+ã“ã“ã§èª¬æ˜Žã•ã‚Œã¦ã„るオブジェクト クラスã¯ã€Netscape Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚ã“れらã®ã‚ªãƒ–ジェクト クラスã¯ã€<a href="objclass.htm#1080497">netscapeCompassServer</A>, <a href="objclass.htm#1079636">personalInterestProfile</A>ã€<a href="objclass.htm#1080358">PIPUser</A>ã€ãŠã‚ˆã³<a href="objclass.htm#1080065">PIPUserInfo</A>ã§ã™ã€‚<P></A>
+
+
+<A NAME="1080497">&nbsp;
+</A>
+<A NAME="netscapeCompassServer">
+<H3> netscapeCompassServer</H3>
+</A>
+
+
+
+<A NAME="1080498">
+Netscape Compass Serverã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097064">
+OID: <CODE>2.16.840.1.113730.3.2.19</CODE><P></A>
+
+<A NAME="1108299">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108289">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108291">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108296">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108298">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1079636">&nbsp;
+</A>
+<A NAME="personalInterestProfile">
+<H3> personalInterestProfile</H3>
+</A>
+
+
+
+<A NAME="1082056">
+Compassユーザã®å€‹äººã®èˆˆå‘³ã«é–¢ã™ã‚‹æƒ…報をä¿å­˜ã™ã‚‹ãŸã‚ã«ã€Compass Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹ã‚ªãƒ–ジェクト クラス。個人ã®èˆˆå‘³ã«é–¢ã™ã‚‹æƒ…å ±ã®è©³ç´°ã¯ã€ã€ŽNetscape Compass Server管ç†è€…ガイドã€ã‚’ã”覧ãã ã•ã„。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1097066">
+OID: <CODE>2.16.840.1.113730.3.2.20</CODE><P></A>
+
+<A NAME="1079693">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1079643">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1079645">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108309">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108311">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079649">
+<a href="attribut.htm#1110777">pipuid</A><P></A>
+<td>
+<A NAME="1079652">
+(å¿…é ˆ) ã“ã®ãƒ—ロフィールãŒå±žã™ã‚‹ãƒ¦ãƒ¼ã‚¶ã®ãƒ¦ãƒ¼ã‚¶ID。<P></A>
+
+<tr><td>
+<A NAME="1079655">
+<a href="attribut.htm#1107663">pipuniqueid</A><P></A>
+<td>
+<A NAME="1088167">
+ã“ã®ãƒ—ロフィールãŒå±žã™ã‚‹ãƒ¦ãƒ¼ã‚¶ã®å›ºæœ‰ã®ID。<P></A>
+
+<tr><td>
+<A NAME="1079660">
+<a href="attribut.htm#1114647">pipstatus</A><P></A>
+<td>
+<A NAME="1079662">
+プロフィールãŒä½¿ç”¨å¯èƒ½ã§ã‚ã‚‹ã‹ä½¿ç”¨ç¦æ­¢ã§ã‚ã‚‹ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079665">
+<a href="attribut.htm#1108439">pipusertype</A><P></A>
+<td>
+<A NAME="1079667">
+ã“ã®ãƒ—ロフィールãŒå±žã™ã‚‹ãƒ¦ãƒ¼ã‚¶ã®ã‚¿ã‚¤ãƒ—。<P></A>
+
+<tr><td>
+<A NAME="1079670">
+<a href="attribut.htm#1116521">pipstfrequency</A><P></A>
+<td>
+<A NAME="1079672">
+カテゴリを更新ã—ãŸMy Compassニュースレターã®å—信頻度を示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079675">
+<a href="attribut.htm#1111582">pipmedium</A><P></A>
+<td>
+<A NAME="1079677">
+無料テキスト検索プロフィール更新情報をユーザã«é€ä¿¡ã™ã‚‹ã®ã«ä½¿ç”¨ã™ã‚‹æ‰‹æ®µã€‚<P></A>
+
+<tr><td>
+<A NAME="1108316">
+<a href="attribut.htm#1111357">pipformat</A><P></A>
+<td>
+<A NAME="1108318">
+ユーザã«é€ä¿¡ã•ã‚Œã‚‹ç„¡æ–™ãƒ†ã‚­ã‚¹ãƒˆæ¤œç´¢ãƒ—ロフィール更新ã®å½¢å¼ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079680">
+<a href="attribut.htm#1246341">pipfrequency</A><P></A>
+<td>
+<A NAME="1079682">
+コンパス サーãƒã§ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã€‚ユーザãŒãƒ•ãƒªãƒ¼ テキスト検索ã§æ›´æ–°ã•ã‚ŒãŸã€ŒMy Compassã€ãƒ‹ãƒ¥ãƒ¼ã‚¹ãƒ¬ã‚¿ãƒ¼ã‚’ã©ã®ã‚ˆã†ãªé »åº¦ã§å—ã‘å–ã‚‹ã‹ã‚’記述ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079685">
+<a href="attribut.htm#1111369">piphour</A><P></A>
+<td>
+<A NAME="1079687">
+ユーザãŒç„¡æ–™ãƒ†ã‚­ã‚¹ãƒˆæ¤œç´¢ãƒ—ロフィール更新をé€ä¿¡ã™ã‚‹æ™‚間帯。<P></A>
+
+<tr><td>
+<A NAME="1079690">
+<a href="attribut.htm#1246650">pipmaxhits</A><P></A>
+<td>
+<A NAME="1079692">
+無料テキスト検索プロフィール更新ã”ã¨ã«æˆ»ã•ã‚Œã‚‹æœ€å¤§ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆæ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086287">
+<a href="attribut.htm#1111729">pipresultset</A><P></A>
+<td>
+<A NAME="1079792">
+ユーザãŒæ›´æ–°ã®å—信を希望ã™ã‚‹å±žæ€§ãƒªã‚¹ãƒˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1079799">
+<a href="attribut.htm#1111947">pipsortorder</A><P></A>
+<td>
+<A NAME="1079788">
+無料テキスト検索プロフィール更新ã®æ¦‚è¦ãƒ¬ãƒãƒ¼ãƒˆã®æƒ…報を並ã¹æ›¿ãˆã‚‹é †åºã€‚<P></A>
+
+<tr><td>
+<A NAME="1079802">
+<a href="attribut.htm#1117682">piptimestamp</A><P></A>
+<td>
+<A NAME="1079784">
+ã“ã®ãƒ¦ãƒ¼ã‚¶ã«ã¤ã„ã¦ã®ç„¡æ–™ãƒ†ã‚­ã‚¹ãƒˆæ¤œç´¢ãƒ—ロフィールã®æœ€çµ‚更新日。<P></A>
+
+<tr><td>
+<A NAME="1079805">
+<a href="attribut.htm#1113479">pipirlist</A><P></A>
+<td>
+<A NAME="1105425">
+ユーザãŒãƒ¢ãƒ‹ã‚¿ãƒ¼ã™ã‚‹ãƒ‰ãƒ¡ã‚¤ãƒ³ã¨ãƒ‹ãƒ¥ãƒ¼ã‚¹ã‚°ãƒ«ãƒ¼ãƒ—。<P></A>
+
+<tr><td>
+<A NAME="1079808">
+<a href="attribut.htm#1237828">pipiroption</A><P></A>
+<td>
+<A NAME="1079776">
+pipIrListã®ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªã‚’æ›´æ–°ã™ã‚‹ã‹ã€ã¾ãŸã¯æ›´æ–°ã‹ã‚‰é™¤å¤–ã™ã‚‹ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079811">
+<a href="attribut.htm#1112443">pippwp</A><P></A>
+<td>
+<A NAME="1079772">
+Personal Web Page (PWP) データベースã®ã‚¢ãƒ‰ãƒ¬ã‚¹ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079814">
+<a href="attribut.htm#1112574">piplastcount</A><P></A>
+<td>
+<A NAME="1079768">
+最後ã®æ›´æ–°ä¸­ã«ç™ºç”Ÿã—ãŸä¸€è‡´æ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079817">
+<a href="attribut.htm#1237470">piptotalcount</A><P></A>
+<td>
+<A NAME="1082119">
+ç¾åœ¨ã«è‡³ã‚‹ã¾ã§ã®ã™ã¹ã¦ã®æ›´æ–°ä¸­ã«ç™ºç”Ÿã—ãŸä¸€è‡´æ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079820">
+<a href="attribut.htm#1112780">piptotalrun</A><P></A>
+<td>
+<A NAME="1079760">
+ç¾åœ¨ã«è‡³ã‚‹ã¾ã§ã®æ›´æ–°ç·æ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079824">
+<a href="attribut.htm#1236460">pipnotify</A><P></A>
+<td>
+<A NAME="1079756">
+未定義。<P></A>
+
+<tr><td>
+<A NAME="1079827">
+<a href="attribut.htm#1236511">pipprivilege</A><P></A>
+<td>
+<A NAME="1079752">
+未定義。<P></A>
+
+<tr><td>
+<A NAME="1086357">
+<a href="attribut.htm#1113190">pipgroup</A><P></A>
+<td>
+<A NAME="1079748">
+未定義。<P></A>
+
+<tr><td>
+<A NAME="1086370">
+<a href="attribut.htm#1237689">pipidstcount</A><P></A>
+<td>
+<A NAME="1082159">
+ユーザã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚ŒãŸæœ€å¾Œã®ä¸€æ„ã®ID。<P></A>
+
+<tr><td>
+<A NAME="1086382">
+<a href="attribut.htm#1115462">pipstid</A><P></A>
+<td>
+<A NAME="1079861">
+プロフィールã«å«ã¾ã‚Œã¦ã„る検索トピックã®ä¸€æ„ã®ID。<P></A>
+
+<tr><td>
+<A NAME="1079875">
+<a href="attribut.htm#1115468">pipstname</A><P></A>
+<td>
+<A NAME="1079857">
+検索トピックを説明ã™ã‚‹ãŸã‚ã«ã€ãƒ¦ãƒ¼ã‚¶ã«ã‚ˆã£ã¦ä½œæˆã•ã‚ŒãŸä»»æ„ã®åå‰ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079878">
+<a href="attribut.htm#1115474">pipstquery</A><P></A>
+<td>
+<A NAME="1079853">
+未定義。<P></A>
+
+<tr><td>
+<A NAME="1079881">
+<a href="attribut.htm#1115480">pipsttaxonomy</A><P></A>
+<td>
+<A NAME="1079849">
+検索トピックã®åˆ†é¡žId。<P></A>
+
+<tr><td>
+<A NAME="1079884">
+<a href="attribut.htm#1115769">pipstinterest</A><P></A>
+<td>
+<A NAME="1099692">
+個々ã®æ¤œç´¢ãƒˆãƒ”ックã”ã¨ã®ãƒ¦ãƒ¼ã‚¶ã«å¯¾ã™ã‚‹é‡è¦åº¦ã‚’説明ã—ã¾ã™ã€‚(ã“ã®å±žæ€§ã¯Netscape Compass Server Professionalã§ã®ã¿ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚)<P></A>
+
+<tr><td>
+<A NAME="1079887">
+<a href="attribut.htm#1116285">pipsttype</A><P></A>
+<td>
+<A NAME="1079841">
+検索ãŒã‚«ãƒ†ã‚´ãƒªæ¤œç´¢ã§ã‚ã‚‹ã‹ç„¡æ–™ãƒ†ã‚­ã‚¹ãƒˆæ¤œç´¢ã§ã‚ã‚‹ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079890">
+<a href="attribut.htm#1115898">pipstprivacy</A><P></A>
+<td>
+<A NAME="1079837">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®å•åˆã›ã‚’許å¯ã™ã‚‹ã‹æ‹’å¦ã™ã‚‹ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079955">
+<a href="attribut.htm#1116027">pipststatus</A><P></A>
+<td>
+<A NAME="1079950">
+Personal Interest Profile (PIP)ã®çŠ¶æ…‹ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079958">
+<a href="attribut.htm#1237172">pipstlastcount</A><P></A>
+<td>
+<A NAME="1079946">
+最後ã®æ›´æ–°ä¸­ã«ä¸€è‡´ã—ãŸã‚«ãƒ†ã‚´ãƒªæ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079961">
+<a href="attribut.htm#1115516">pipsttotalcount</A><P></A>
+<td>
+<A NAME="1082234">
+ç¾åœ¨ã«è‡³ã‚‹ã¾ã§ã«ä¸€è‡´ã—ãŸã‚«ãƒ†ã‚´ãƒªæ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079964">
+<a href="attribut.htm#1115522">pipsttotalrun</A><P></A>
+<td>
+<A NAME="1082240">
+ç¾åœ¨ã«è‡³ã‚‹ã¾ã§ã«å®Ÿè¡Œã•ã‚ŒãŸã‚«ãƒ†ã‚´ãƒªæ¤œç´¢æ›´æ–°æ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079967">
+<a href="attribut.htm#1116402">pipstcategory</A><P></A>
+<td>
+<A NAME="1079934">
+ユーザãŒèˆˆå‘³ã®ã‚るカテゴリã¾ãŸã¯æ¤œç´¢æ–‡å­—列。<P></A>
+
+<tr><td>
+<A NAME="1079970">
+<a href="attribut.htm#1116521">pipstfrequency</A><P></A>
+<td>
+<A NAME="1079930">
+ユーザãŒæ›´æ–°ã®è­¦å‘Šã‚’å—ã‘る頻度。<P></A>
+
+<tr><td>
+<A NAME="1079973">
+<a href="attribut.htm#1117140">pipstmedium</A><P></A>
+<td>
+<A NAME="1096703">
+カテゴリ検索プロフィールã®æ›´æ–°æƒ…報をユーザã«é€ä¿¡ã™ã‚‹ã®ã«ä½¿ç”¨ã™ã‚‹æ‰‹æ®µã€‚<P></A>
+
+<tr><td>
+<A NAME="1079976">
+<a href="attribut.htm#1116837">pipstformat</A><P></A>
+<td>
+<A NAME="1082369">
+ユーザã«é€ä¿¡ã•ã‚Œã‚‹ã‚«ãƒ†ã‚´ãƒªæ¤œç´¢ãƒ—ロフィール更新ã®å½¢å¼ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079979">
+<a href="attribut.htm#1116707">pipsthour</A><P></A>
+<td>
+<A NAME="1082375">
+ユーザãŒç„¡æ–™ã‚«ãƒ†ã‚´ãƒª プロフィール更新をé€ä¿¡ã™ã‚‹æ™‚間帯。<P></A>
+
+<tr><td>
+<A NAME="1079982">
+<a href="attribut.htm#1117134">pipstmaxhits</A><P></A>
+<td>
+<A NAME="1082402">
+カテゴリ検索プロフィール更新ã”ã¨ã«æˆ»ã•ã‚Œã‚‹æœ€å¤§ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆæ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079985">
+<a href="attribut.htm#1117321">pipstresultset</A><P></A>
+<td>
+<A NAME="1082414">
+ユーザãŒæ›´æ–°ã®å—信を希望ã™ã‚‹ã‚«ãƒ†ã‚´ãƒª リストãŒå«ã¾ã‚Œã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1079988">
+<a href="attribut.htm#1117327">pipstsortorder</A><P></A>
+<td>
+<A NAME="1082427">
+カテゴリ検索プロフィール更新ã®æ¦‚è¦ãƒ¬ãƒãƒ¼ãƒˆã®æƒ…報を並ã¹æ›¿ãˆã‚‹é †åºã€‚<P></A>
+
+<tr><td>
+<A NAME="1079991">
+<a href="attribut.htm#1117445">pipsttimestamp</A><P></A>
+<td>
+<A NAME="1082432">
+ã“ã®ãƒ¦ãƒ¼ã‚¶ã«ã¤ã„ã¦ã®ã‚«ãƒ†ã‚´ãƒªæ¤œç´¢ãƒ—ロフィールã®æœ€çµ‚更新日。<P></A>
+
+<tr><td>
+<A NAME="1079994">
+<a href="attribut.htm#1117562">pipstirlist</A><P></A>
+<td>
+<A NAME="1082443">
+ユーザãŒãƒ¢ãƒ‹ã‚¿ãƒ¼ã—ãŸã„ドメインã¨ãƒ‹ãƒ¥ãƒ¼ã‚¹ã‚°ãƒ«ãƒ¼ãƒ—。<P></A>
+
+<tr><td>
+<A NAME="1079997">
+<a href="attribut.htm#1117790">pipstiroption</A><P></A>
+<td>
+<A NAME="1082447">
+pipstirlistã®ã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªã‚’æ›´æ–°ã™ã‚‹ã‹ã€ã¾ãŸã¯ã‚«ãƒ†ã‚´ãƒªã®æ›´æ–°ã‹ã‚‰é™¤å¤–ã™ã‚‹ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1080036">
+<a href="attribut.htm#1118693">pipreservedces1</A><P></A>
+<td>
+<A NAME="1080033">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1080041">
+<a href="attribut.htm#1118699">pipreservedces2</A><P></A>
+<td>
+<A NAME="1082335">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1080044">
+<a href="attribut.htm#1118705">pipreservedces3</A><P></A>
+<td>
+<A NAME="1080025">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1080047">
+<a href="attribut.htm#1118350">pipreservedcis1</A><P></A>
+<td>
+<A NAME="1080021">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1080050">
+<a href="attribut.htm#1118356">pipreservedcis2</A><P></A>
+<td>
+<A NAME="1080017">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1080053">
+<a href="attribut.htm#1118362">pipreservedcis3</A><P></A>
+<td>
+<A NAME="1080013">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1080056">
+<a href="attribut.htm#1118368">pipreservedcis4</A><P></A>
+<td>
+<A NAME="1080009">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1080059">
+<a href="attribut.htm#1118374">pipreservedcis5</A><P></A>
+<td>
+<A NAME="1080005">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1080062">
+<a href="attribut.htm#1118380">pipreservedcis6</A><P></A>
+<td>
+<A NAME="1080001">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1080358">&nbsp;
+</A>
+<A NAME="PIPUser">
+<H3> PIPUser</H3>
+</A>
+
+
+
+<A NAME="1082531">
+Netscape Compass ServerãŒä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€Personal Interest Profile (PIP)ユーザã®æƒ…報をå«ã¿ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚PIPã®è©³ç´°ã¯ã€ã€ŽNetscape Compass Server Administrator's Guideã€ã‚’ã”覧ãã ã•ã„。将æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097068">
+OID: <CODE>2.16.840.1.113730.3.2.22</CODE><P></A>
+
+<A NAME="1080396">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1080362">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1080364">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108446">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108448">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086592">
+<a href="attribut.htm#1246531">pipcompassservers</A><P></A>
+<td>
+<A NAME="1080405">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086632">
+<a href="attribut.htm#1118693">pipreservedces1</A><P></A>
+<td>
+<A NAME="1080442">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086637">
+<a href="attribut.htm#1118699">pipreservedces2</A><P></A>
+<td>
+<A NAME="1080447">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086642">
+<a href="attribut.htm#1118705">pipreservedces3</A><P></A>
+<td>
+<A NAME="1080452">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086647">
+<a href="attribut.htm#1118350">pipreservedcis1</A><P></A>
+<td>
+<A NAME="1080457">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086652">
+<a href="attribut.htm#1118356">pipreservedcis2</A><P></A>
+<td>
+<A NAME="1080462">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086657">
+<a href="attribut.htm#1118362">pipreservedcis3</A><P></A>
+<td>
+<A NAME="1080467">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086662">
+<a href="attribut.htm#1118368">pipreservedcis4</A><P></A>
+<td>
+<A NAME="1080484">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086667">
+<a href="attribut.htm#1118374">pipreservedcis5</A><P></A>
+<td>
+<A NAME="1080489">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1086672">
+<a href="attribut.htm#1118380">pipreservedcis6</A><P></A>
+<td>
+<A NAME="1080494">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1108453">
+<a href="attribut.htm#1107663">pipuniqueid</A><P></A>
+<td>
+<A NAME="1108455">
+ユーザ固有ã®ID。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1080065">&nbsp;
+</A>
+<A NAME="PIPUserInfo">
+<H3> PIPUserInfo</H3>
+</A>
+
+
+
+<A NAME="1080066">
+ユーザIDã‚’æŒãŸãªã„Personal Interest Profile (PIP)ユーザ情報をå«ã‚ã‚‹ãŸã‚ã«ã€Netscape Compass ServerãŒä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã«å¯¾ã™ã‚‹Netscape社ã®æ‹¡å¼µã§ã™ã€‚PIPã®è©³ç´°ã¯ã€ã€ŽNetscape Compass Server Administrator's Guideã€ã‚’ã”覧ãã ã•ã„。将æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097070">
+OID: <CODE>2.16.840.1.113730.3.2.21</CODE><P></A>
+
+<A NAME="1097227">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1105721">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1105723">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1105728">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1105730">
+(å¿…é ˆ) ユーザã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1108460">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108462">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1105735">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1105737">
+自由形å¼ã§ã®ãƒ¦ãƒ¼ã‚¶ã®èª¬æ˜Žã€‚<P></A>
+
+<tr><td>
+<A NAME="1105763">
+<a href="attribut.htm#1189404">mail</A><P></A>
+<td>
+<A NAME="1105765">
+ユーザã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレス。<P></A>
+
+<tr><td>
+<A NAME="1105742">
+<a href="attribut.htm#1246531">pipcompassservers</A><P></A>
+<td>
+<A NAME="1105744">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1105749">
+<a href="attribut.htm#1107663">pipuniqueid</A><P></A>
+<td>
+<A NAME="1105751">
+ユーザ固有ã®ID。<P></A>
+
+<tr><td>
+<A NAME="1105756">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1105758">
+ユーザã®ãƒ‘スワード<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097229">&nbsp;
+</A>
+<A NAME="Directory Server Extensions">
+<H2> Directory Serverã®æ‹¡å¼µ</H2>
+</A>
+
+<A NAME="1077861">
+以下ã®ã‚ªãƒ–ジェクト クラスã¯Netscape Directory Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚ã“ã“ã§èª¬æ˜Žã•ã‚Œã¦ã„るオブジェクト クラスã¯ã€<a href="objclass.htm#1077794">changeLogEntry</A>ã€href="objclass.htm#1100614">cirReplicaSource</A>ã€<a href="objclass.htm#1098555">groupOfCertificates</A>ã€<a href="objclass.htm#1106267">residentialPerson</A>ã€<a href="objclass.htm#1078109">netscapeMachineData</A>ã€<a href="objclass.htm#1097231">netscapeServer</A>ã€<a href="objclass.htm#1100862">nsLicenseUser</A>ã€<a href="objclass.htm#1100399">NTGroup</A>ã€<a href="objclass.htm#1081708">passwordObject</A>ã€<a href="objclass.htm#1081724">passwordPolicy</A>ã€<a href="objclass.htm#1097669">referral</A>ãŠã‚ˆã³<a href="objclass.htm#1097986">subschema</A>ã§ã™ã€‚<P></A>
+
+
+<A NAME="1077794">&nbsp;
+</A>
+<A NAME="changeLogEntry">
+<H3> changeLogEntry</H3>
+</A>
+
+
+
+<A NAME="1077795">
+Netscape Directory ServerãŒä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®å¤‰æ›´ã‚’表示ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1098541">
+OID: <CODE>2.16.840.1.113730.3.2.1</CODE><P></A>
+
+<A NAME="1077846">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1077798">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1077800">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1077816">
+<a href="attribut.htm#1094798">changeNumber</A><P></A>
+<td>
+<A NAME="1077819">
+(å¿…é ˆ) 変更ログã«å‰²ã‚Šå½“ã¦ã‚‰ã‚Œã‚‹ä»»æ„ã®ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1108478">
+<a href="attribut.htm#1095285">changeTime</A><P></A>
+<td>
+<A NAME="1108480">
+(å¿…é ˆ) 変更ãŒè¡Œã‚ã‚ŒãŸæ™‚刻を定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1077822">
+<a href="attribut.htm#1094968">changeType</A><P></A>
+<td>
+<A NAME="1077825">
+(å¿…é ˆ) エントリã«è¡Œã‚ã‚ŒãŸå¤‰æ›´ã®ã‚¿ã‚¤ãƒ—。<P></A>
+
+<tr><td>
+<A NAME="1108471">
+<a href="attribut.htm#1094954">targetDn</A><P></A>
+<td>
+<A NAME="1108473">
+(å¿…é ˆ) 供給サーãƒã«ãŠã„ã¦è¿½åŠ ã€å¤‰æ›´ã€ã¾ãŸã¯å‰Šé™¤ã•ã‚ŒãŸã‚¨ãƒ³ãƒˆãƒªã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1077828">
+<a href="attribut.htm#1095277">changes</A><P></A>
+<td>
+<A NAME="1077830">
+Directory Serverã«è¡Œã‚ã‚ŒãŸå¤‰æ›´ã€‚<P></A>
+
+<tr><td>
+<A NAME="1077833">
+<a href="attribut.htm#1095547">deleteOldRdn</A><P></A>
+<td>
+<A NAME="1077835">
+エントリã®è­˜åˆ¥å±žæ€§ã¨ã—ã¦ã€ã‚¨ãƒ³ãƒˆãƒªã®å¤ã„RDN(Relative Distinguished Name=相対識別å)ã‚’ä¿æŒã™ã‚‹ã‹ã€ã¾ãŸã¯å‰Šé™¤ã™ã‚‹ã‹ã‚’定義ã™ã‚‹ãƒ•ãƒ©ã‚°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1098195">
+<a href="attribut.htm#1266221">filterInfo</A><P></A>
+<td>
+<A NAME="1098197">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1077838">
+<a href="attribut.htm#1096606">newRdn</A><P></A>
+<td>
+<A NAME="1077840">
+modRDNã¾ãŸã¯modDNã®å‹•ä½œã®ç›®æ¨™ã¨ãªã‚‹ã‚¨ãƒ³ãƒˆãƒªã®æ–°è¦RDN。<P></A>
+
+<tr><td>
+<A NAME="1077843">
+<a href="attribut.htm#1126531">newSuperior</A><P></A>
+<td>
+<A NAME="1077845">
+modDN動作ã®å‡¦ç†ä¸­ã«ã€æ—¢å­˜ã‚¨ãƒ³ãƒˆãƒªã®ç›´ã上ä½ã«ãªã‚‹ã‚¨ãƒ³ãƒˆãƒªã®åå‰ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1098555">&nbsp;
+</A>
+<A NAME="groupOfCertificates">
+<H3> groupOfCertificates</H3>
+</A>
+
+
+
+<A NAME="1098563">
+X.509証明書ã®ã‚°ãƒ«ãƒ¼ãƒ—情報をå«ã‚ã‚‹ãŸã‚ã«ã€Netscape Directory Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹ã‚ªãƒ–ジェクト クラス。<a href="attribut.htm#1152959">memberCertificateDescription</A>ã®å€¤ã«ä¸€è‡´ã™ã‚‹è¨¼æ˜Žæ›¸ã¯ã€ã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ãƒ¡ãƒ³ãƒãƒ¼ã¨è¦‹ãªã•ã‚Œã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1098564">
+OID: <CODE>2.16.840.1.113730.3.2.31</CODE><P></A>
+
+<A NAME="1081487">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1081442">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1081444">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1081448">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1081451">
+(å¿…é ˆ) グループã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1081454">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1082983">
+グループãŒé–¢ä¸Žã™ã‚‹äº‹æ¥­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1081459">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1081461">
+自由形å¼ã§ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®èª¬æ˜Žã€‚<P></A>
+
+<tr><td>
+<A NAME="1081464">
+<a href="attribut.htm#1152959">memberCertificateDescription</A><P></A>
+<td>
+<A NAME="1081466">
+特定ã®è¨¼æ˜Žæ›¸ãŒã“ã®ã‚°ãƒ«ãƒ¼ãƒ—ã®ãƒ¡ãƒ³ãƒãƒ¼ã§ã‚ã‚‹ã‹ã©ã†ã‹ã®åˆ¤å®šã«ä½¿ç”¨ã•ã‚Œã‚‹å€¤ã€‚<P></A>
+
+<tr><td>
+<A NAME="1081469">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1081471">
+証明書ã®ã‚°ãƒ«ãƒ¼ãƒ—を制御ã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1081474">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1081476">
+グループãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1081479">
+<a href="attribut.htm#1005719">owner</A><P></A>
+<td>
+<A NAME="1081481">
+グループã®ã‚ªãƒ¼ãƒŠã€‚<P></A>
+
+<tr><td>
+<A NAME="1081484">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1081486">
+グループã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089068">&nbsp;
+</A>
+<A NAME="netscapeDirectoryServer">
+<H3> netscapeDirectoryServer</H3>
+</A>
+
+
+
+<A NAME="1089069">
+Netscape Directory Serverã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097076">
+OID: <CODE>2.16.840.1.113730.3.2.23</CODE><P></A>
+
+<A NAME="1108594">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108584">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108586">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108591">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108593">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078109">&nbsp;
+</A>
+<A NAME="netscapeMachineData">
+<H3> netscapeMachineData</H3>
+</A>
+
+
+
+<A NAME="1097236">
+Netscape Directory ServerãŒãƒžã‚·ãƒ³ データã¨éžãƒžã‚·ãƒ³ データを区別ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。マシン データã¯è¤‡è£½ä¸­ã«ãƒ•ã‚£ãƒ«ã‚¿ã«ã‚ˆã£ã¦é™¤å¤–ã•ã‚Œã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097237">
+OID: <CODE>2.16.840.1.113730.3.2.32</CODE><P></A>
+
+
+<A NAME="1097231">&nbsp;
+</A>
+<A NAME="netscapeServer">
+<H3> netscapeServer</H3>
+</A>
+
+
+
+<A NAME="1098570">
+ディレクトリã«ãƒã‚¤ãƒ³ãƒ‰ã—ãŸã¨ãã€NetscapeサーãƒãŒä½¿ç”¨ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’識別ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1098571">
+OID: <CODE>2.16.840.1.113730.3.2.10</CODE><P></A>
+
+<A NAME="1078166">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078113">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078115">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1078118">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1078121">
+(å¿…é ˆ) サーãƒã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1103187">
+<a href="attribut.htm#1032956">administratorContactInfo</A><P></A>
+<td>
+<A NAME="1103189">
+Netscapeサーãƒã®ç®¡ç†è²¬ä»»è€…ã«é–¢é€£ã—ãŸæƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1103192">
+<a href="attribut.htm#1098448">adminUrl</A><P></A>
+<td>
+<A NAME="1103194">
+NetscapeサーãƒãŒå®Ÿè¡Œä¸­ã®ç®¡ç†ã‚µãƒ¼ãƒã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1078124">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1078126">
+サーãƒã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103205">
+<a href="attribut.htm#1032705">installationTimeStamp</A><P></A>
+<td>
+<A NAME="1103207">
+NetscapeãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚ŒãŸæ™‚刻。<P></A>
+
+<tr><td>
+<A NAME="1078137">
+<a href="attribut.htm#1093065">serverHostName</A><P></A>
+<td>
+<A NAME="1078139">
+NetscapeサーãƒãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„るホストå。<P></A>
+
+<tr><td>
+<A NAME="1078143">
+<a href="attribut.htm#1032412">serverProductName</A><P></A>
+<td>
+<A NAME="1078145">
+Netscapeサーãƒè£½å“å。<P></A>
+
+<tr><td>
+<A NAME="1103220">
+<a href="attribut.htm#1032294">serverRoot</A><P></A>
+<td>
+<A NAME="1103222">
+サームインストール ルートã¸ã®ãƒ‘ス。<P></A>
+
+<tr><td>
+<A NAME="1108651">
+<a href="attribut.htm#1032439">serverVersionNumber</A><P></A>
+<td>
+<A NAME="1108653">
+Netscapeサームãƒãƒ¼ã‚¸ãƒ§ãƒ³ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078148">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1078150">
+サーãƒã«å¯¾ã™ã‚‹ãƒ‘スワードをä¿æŒã—ã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1081708">&nbsp;
+</A>
+<A NAME="passwordObject">
+<H3> passwordObject</H3>
+</A>
+
+
+
+<A NAME="1098598">
+ディレクトリ内ã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ‘スワード情報をå«ã‚€ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1098599">
+OID: <CODE>2.16.840.1.113730.3.2.12</CODE><P></A>
+
+<A NAME="1081721">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1081712">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1081714">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108661">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108663">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103292">
+<a href="attribut.htm#1104078">accountUnlockTime</A><P></A>
+<td>
+<A NAME="1103294">
+ユーザ アカウントã®ãƒ­ãƒƒã‚¯ã‚’ã„ã¤è§£é™¤ã™ã‚‹ã‹ã‚’示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1108668">
+<a href="attribut.htm#1103904">passwordExpirationTime</A><P></A>
+<td>
+<A NAME="1108670">
+ユーザ パスワードã®å¤±åŠ¹æ™‚期。<P></A>
+
+<tr><td>
+<A NAME="1081718">
+<a href="attribut.htm#1293088">passwordExpWarned</A><P></A>
+<td>
+<A NAME="1081720">
+ユーザã«é€ã£ãŸãƒ‘スワード失効ã®è­¦å‘Šã®è¨˜éŒ²ã‚’ä¿æŒã™ã‚‹ãŸã‚ã«Directory ServerãŒä½¿ç”¨ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103273">
+<a href="attribut.htm#1104144">passwordHistory</A><P></A>
+<td>
+<A NAME="1103275">
+ユーザã®ãƒ‘スワード履歴。<P></A>
+
+<tr><td>
+<A NAME="1083145">
+<a href="attribut.htm#1103999">passwordRetryCount</A><P></A>
+<td>
+<A NAME="1083110">
+ユーザã®ãƒ‘スワード入力失敗回数。<P></A>
+
+<tr><td>
+<A NAME="1083153">
+<a href="attribut.htm#1152805">retryCountResetTime</A><P></A>
+<td>
+<A NAME="1083106">
+passwordRetryCountã‚’ã„ã¤ã‚¼ãƒ­ (0)ã«å†è¨­å®šã™ã‚‹ã‹ã‚’示ã—ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1081724">&nbsp;
+</A>
+<A NAME="passwordPolicy">
+<H3> passwordPolicy</H3>
+</A>
+
+
+
+<A NAME="1098606">
+全ディレクトリã«ã‚ã‚‹ã€ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ‘スワード方é‡ã‚’å«ã‚€ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1098607">
+OID: <CODE>2.16.840.1.113730.3.2.13</CODE><P></A>
+
+<A NAME="1081725">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1103339">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1103341">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108677">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108679">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103461">
+<a href="attribut.htm#1157269">passwordChange</A><P></A>
+<td>
+<A NAME="1103463">
+ユーザã«ã‚ˆã‚‹ãƒ‘スワードã®å¤‰æ›´ãŒã€å¿…è¦ã€å¯èƒ½ã€ä¸å¯èƒ½ã®ã„ãšã‚Œã§ã‚ã‚‹ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103478">
+<a href="attribut.htm#1157285">passwordCheckSyntax</A><P></A>
+<td>
+<A NAME="1103480">
+ユーザ パスワードã§æ§‹æ–‡ãƒã‚§ãƒƒã‚¯ã‚’実行ã™ã‚‹ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103346">
+<a href="attribut.htm#1155167">passwordExp</A><P></A>
+<td>
+<A NAME="1103348">
+ユーザ パスワードãŒå¤±åŠ¹ã™ã‚‹ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103444">
+<a href="attribut.htm#1104470">passwordInHistory</A><P></A>
+<td>
+<A NAME="1103446">
+パスワード履歴をä¿å­˜ã™ã‚‹å ´åˆã€å±¥æ­´ãƒªã‚¹ãƒˆã«è¨˜éŒ²ã™ã‚‹ãƒ‘スワード数を定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103427">
+<a href="attribut.htm#1156663">passwordKeepHistory</A><P></A>
+<td>
+<A NAME="1103429">
+ユーザ パスワードã®å±¥æ­´ã‚’ä¿å­˜ã™ã‚‹ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103495">
+<a href="attribut.htm#1156671">passwordLockout</A><P></A>
+<td>
+<A NAME="1103497">
+é–“é•ã£ãŸãƒ‘スワードを特定回数使用ã—ãŸã‚‰ãƒ¦ãƒ¼ã‚¶ã‚’ç· ã‚出ã™ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103551">
+<a href="attribut.htm#1104188">passwordLockoutDuration</A><P></A>
+<td>
+<A NAME="1103553">
+特定回数ã®å†è©¦è¡Œå¾Œã«ãƒ¦ãƒ¼ã‚¶ã‚’ç· ã‚出ã™æœŸé–“を定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103353">
+<a href="attribut.htm#1166286">passwordMaxAge</A><P></A>
+<td>
+<A NAME="1103355">
+パスワードã®æœ‰åŠ¹æœŸé–“を定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103512">
+<a href="attribut.htm#1104715">passwordMaxFailure</A><P></A>
+<td>
+<A NAME="1103514">
+ユーザãŒç· ã‚出ã•ã‚Œã‚‹å‰ã«å…¥åŠ›ã§ãるパスワードã®æœ€å¤§å…¥åŠ›å›žæ•°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103360">
+<a href="attribut.htm#1104413">passwordMinLength</A><P></A>
+<td>
+<A NAME="1103362">
+ユーザ パスワードã«ä½¿ç”¨å¯èƒ½ãªæœ€å°æ–‡å­—数を定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103529">
+<a href="attribut.htm#1104754">passwordResetDuration</A><P></A>
+<td>
+<A NAME="1103531">
+サーãƒãŒãƒ¦ãƒ¼ã‚¶ã‚’ç· ã‚出ã—ã¦ã‹ã‚‰ãƒªãƒˆãƒ©ã‚¤ カウントをゼロã«æˆ»ã™ã¾ã§ã®çµŒéŽæ™‚間を指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103534">
+<a href="attribut.htm#1156969">passwordUnlock</A><P></A>
+<td>
+<A NAME="1103536">
+特定回数ã®å†è©¦è¡Œå¾Œã«ãƒ¦ãƒ¼ã‚¶ã‚’永久ã«ç· ã‚出ã™ã‹ã©ã†ã‹ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103387">
+<a href="attribut.htm#1104598">passwordWarning</A><P></A>
+<td>
+<A NAME="1103389">
+パスワード失効ã®è­¦å‘Šã‚’失効ã®ã©ã‚Œãらã„å‰ã«ã«ãƒ¦ãƒ¼ã‚¶ã«é€ä¿¡ã™ã‚‹ã‹ã‚’指定ã—ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097669">&nbsp;
+</A>
+<A NAME="referral">
+<H3> referral</H3>
+</A>
+
+
+
+<A NAME="1097670">
+エントリã«ã€ã‚¹ãƒžãƒ¼ãƒˆå‚照を入れるã®ã‚’å¯èƒ½ã«ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1078339">
+OID: <CODE>2.16.840.1.113730.3.2.6</CODE><P></A>
+
+<A NAME="1098034">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078330">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078332">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1078336">
+<a href="attribut.htm#1100037">ref</A><P></A>
+<td>
+<A NAME="1078338">
+LDAP URLãŒä»¥ä¸‹ã®å½¢å¼ã§ä¿æŒã•ã‚Œã¦ã„ã¾ã™ã€‚<br>ldap://servername:portnumber/dn.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097986">&nbsp;
+</A>
+<A NAME="subschema">
+<H3> subschema</H3>
+</A>
+
+
+
+<A NAME="1097987">
+与ãˆã‚‰ã‚ŒãŸDirectory Serverã®ã€ã™ã¹ã¦ã®å±žæ€§ã¨ã‚ªãƒ–ジェクト クラスをå«ã‚€ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚Directory Serverã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1098036">
+OID: <CODE>2.5.20.1</CODE><P></A>
+
+<A NAME="1097998">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1097990">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1097992">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1098110">
+<a href="attribut.htm#1242644">attributeTypes</A><P></A>
+<td>
+<A NAME="1098112">
+サブスキーマ内ã§ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ã‚¿ã‚¤ãƒ—。<P></A>
+
+<tr><td>
+<A NAME="1098086">
+<a href="attribut.htm#1283336">dITContentRules</A><P></A>
+<td>
+<A NAME="1098088">
+サブスキーマ内ã§ä½¿ç”¨ã•ã‚Œã‚‹ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリー内容ã«é–¢ã™ã‚‹ãƒ«ãƒ¼ãƒ«ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1098082">
+<a href="attribut.htm#1283313">dITStructureRules</A><P></A>
+<td>
+<A NAME="1098084">
+サブスキーマ内ã§ä½¿ç”¨ã•ã‚Œã‚‹ãƒ„リー構造ã®ãƒ«ãƒ¼ãƒ«ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1098078">
+<a href="attribut.htm#1242887">matchingRules</A><P></A>
+<td>
+<A NAME="1098080">
+サブスキーマ内ã§ä½¿ç”¨ã•ã‚Œã‚‹ãƒžãƒƒãƒãƒ³ã‚° ルールを定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1098074">
+<a href="attribut.htm#1242961">matchingRuleUse</A><P></A>
+<td>
+<A NAME="1098076">
+サブスキーマ内ã§ãƒžãƒƒãƒãƒ³ã‚° ルールãŒé©ç”¨ã•ã‚Œã‚‹å±žæ€§ã‚¿ã‚¤ãƒ—を示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1098070">
+<a href="attribut.htm#1282059">nameForms</A><P></A>
+<td>
+<A NAME="1098072">
+サブスキーマ内ã§ä½¿ç”¨ã•ã‚Œã‚‹ãƒ•ã‚©ãƒ¼ãƒ ã®åå‰ã‚’定義ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1098066">
+<a href="attribut.htm#1242815">objectClasses</A><P></A>
+<td>
+<A NAME="1098068">
+サブスキーマ内ã§ä½¿ç”¨ã•ã‚Œã‚‹ã‚ªãƒ–ジェクト クラスを定義ã—ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097091">&nbsp;
+</A>
+<A NAME="Media Server Extensions">
+<H2> Media Serverã®æ‹¡å¼µ</H2>
+</A>
+
+<A NAME="1097095">
+以下ã¯ã€Netscape Media Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹<a href="objclass.htm#1097098">netscapeMediaServer</A>ã®ã‚ªãƒ–ジェクト クラスã®èª¬æ˜Žã§ã™ã€‚<P></A>
+
+
+<A NAME="1097098">&nbsp;
+</A>
+<A NAME="netscapeMediaServer">
+<H3> netscapeMediaServer</H3>
+</A>
+
+
+
+<A NAME="1097132">
+Netscape Media Serverã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097133">
+OID: <CODE>2.16.840.1.113730.3.2.25</CODE><P></A>
+
+<A NAME="1108693">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108683">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108685">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108690">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108692">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097135">&nbsp;
+</A>
+<A NAME="Messaging Server Extensions">
+<H2> Messaging Serverã®æ‹¡å¼µ</H2>
+</A>
+
+<A NAME="1108700">
+以下ã®ã‚ªãƒ–ジェクト クラスã¯Netscape Messaging Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚ã“ã“ã§èª¬æ˜Žã•ã‚Œã¦ã„るオブジェクト クラスã¯ã€<a href="objclass.htm#1108716">groupOfMailEnhancedUniqueNames</A>ã€<a href="objclass.htm#1077922">mailRecipient</A>ã€<a href="objclass.htm#1078007">mailGroup</A>ã€ãŠã‚ˆã³<a href="objclass.htm#1081545">netscapeMailServer</A>ã§ã™ã€‚<P></A>
+
+
+<A NAME="1108716">&nbsp;
+</A>
+<A NAME="groupOfMailEnhancedUniqueNames">
+<H3> groupOfMailEnhancedUniqueNames</H3>
+</A>
+
+
+
+<A NAME="1098817">
+Messaging ServerãŒãƒ¡ãƒ¼ãƒ« グループã«é–¢ã™ã‚‹æƒ…報をä¿å­˜ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1098818">
+OID: <CODE>2.16.840.1.113730.3.2.5</CODE><P></A>
+
+<A NAME="1077920">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1077885">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1077887">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1077890">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1077893">
+(å¿…é ˆ) グループã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1108721">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108723">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1077896">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1077898">
+メール グループãŒé–¢ä¸Žã™ã‚‹äº‹æ¥­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1077901">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1077903">
+グループã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1108728">
+<a href="attribut.htm#1026103">mailEnhancedUniqueMember</A><P></A>
+<td>
+<A NAME="1108730">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1077906">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1077908">
+グループãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1108738">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1108740">
+グループãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1077912">
+<a href="attribut.htm#1005719">owner</A><P></A>
+<td>
+<A NAME="1077914">
+グループã®ã‚ªãƒ¼ãƒŠã€‚<P></A>
+
+<tr><td>
+<A NAME="1077917">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1077919">
+グループã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1077922">&nbsp;
+</A>
+<A NAME="mailRecipient">
+<H3> mailRecipient</H3>
+</A>
+
+
+
+<A NAME="1077923">
+inetOrgPersonã®æ©Ÿèƒ½æ‹¡å¼µã¨ã—ã¦ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€Netscape Messaging Serverユーザを定義ã—ã¾ã™ã€‚ã™ãªã‚ã¡ã€mailRecipientã¯ãƒ¡ãƒ¼ãƒ« アカウントを表示ã—ã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1097030">
+OID: <CODE>2.16.840.1.113730.3.2.3</CODE><P></A>
+
+<A NAME="1078005">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1087545">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1087547">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1087550">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1087553">
+(å¿…é ˆ) ユーザã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1087556">
+<a href="attribut.htm#1189404">mail</A><P></A>
+<td>
+<A NAME="1087558">
+ユーザã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレス。<P></A>
+
+<tr><td>
+<A NAME="1087561">
+<a href="attribut.htm#1024020">mailAccessDomain</A><P></A>
+<td>
+<A NAME="1087563">
+メール ユーザãŒãƒ¡ãƒ¼ãƒ«ã‚’入手ã™ã‚‹ã®ã«ãƒ­ã‚°ã‚¤ãƒ³å…ƒã¨ã—ã¦ä½¿ç”¨ã§ãるドメイン。<P></A>
+
+<tr><td>
+<A NAME="1103655">
+<a href="attribut.htm#1024250">mailAlternateAddress</A><P></A>
+<td>
+<A NAME="1087568">
+ユーザã®ä»£æ›¿é›»å­ãƒ¡ãƒ¼ãƒ« アドレス。複数ã®ä»£æ›¿é›»å­ãƒ¡ãƒ¼ãƒ« アドレスãŒå¯èƒ½ã§ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1087571">
+<a href="attribut.htm#1024094">mailAutoReplyMode</A><P></A>
+<td>
+<A NAME="1087573">
+メール ユーザã®ãŸã‚ã«è¨­å®šã•ã‚ŒãŸè‡ªå‹•å¿œç­”モード。<P></A>
+
+<tr><td>
+<A NAME="1087576">
+<a href="attribut.htm#1024125">mailAutoReplyText</A><P></A>
+<td>
+<A NAME="1087578">
+自動応答ãŒãƒ¦ãƒ¼ã‚¶ã«é€ä¿¡ã•ã‚Œã‚‹éš›ã®é€ä¿¡ãƒ†ã‚­ã‚¹ãƒˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1087581">
+<a href="attribut.htm#1024295">mailDeliveryOption</A><P></A>
+<td>
+<A NAME="1087583">
+メール ユーザã®ãŸã‚ã«ä½¿ç”¨ã•ã‚Œã‚‹ãƒ¡ãƒ¼ãƒ«é…信機構。<P></A>
+
+<tr><td>
+<A NAME="1087586">
+<a href="attribut.htm#1026154">mailForwardingAddress</A><P></A>
+<td>
+<A NAME="1087588">
+ユーザã®ãƒ¡ãƒ¼ãƒ«ã®è»¢é€å…ˆãƒ¡ãƒ¼ãƒ« アドレス。<P></A>
+
+<tr><td>
+<A NAME="1087591">
+<a href="attribut.htm#1024314">mailHost</A><P></A>
+<td>
+<A NAME="1087593">
+ユーザã®ãƒ¡ãƒ¼ãƒ« アカウントãŒå­˜åœ¨ã™ã‚‹ãƒ›ã‚¹ãƒˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1087596">
+<a href="attribut.htm#1024377">mailMessageStore</A><P></A>
+<td>
+<A NAME="1087598">
+ユーザã®ãƒ¡ãƒ¼ãƒ«ãƒœãƒƒã‚¯ã‚¹ãŒå«ã¾ã‚Œã¦ã„るディレクトリã¸ã®ãƒ‘ス。<P></A>
+
+<tr><td>
+<A NAME="1087601">
+<a href="attribut.htm#1024400">mailProgramDeliveryInfo</A><P></A>
+<td>
+<A NAME="1087603">
+プログラムã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«é…ä¿¡ã«ä½¿ç”¨ã•ã‚Œã‚‹ã‚³ãƒžãƒ³ãƒ‰ã€‚<P></A>
+
+<tr><td>
+<A NAME="1087606">
+<a href="attribut.htm#1024509">mailQuota</A><P></A>
+<td>
+<A NAME="1087608">
+ユーザã®ãƒ¡ãƒ¼ãƒ«ãƒœãƒƒã‚¯ã‚¹ã®æœ€å¤§è¨±å®¹ãƒ‡ã‚£ã‚¹ã‚¯å®¹é‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1087611">
+<a href="attribut.htm#1229561">multiLineDescription</A><P></A>
+<td>
+<A NAME="1087613">
+メール ユーザã«ã¤ã„ã¦ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1087616">
+<a href="attribut.htm#1296804">uid</A><P></A>
+<td>
+<A NAME="1087618">
+メール ユーザã®ãƒ¦ãƒ¼ã‚¶ID。<P></A>
+
+<tr><td>
+<A NAME="1087621">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1087623">
+メール ユーザãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ãƒã‚¤ãƒ³ãƒ‰ã§ãã‚‹ãŸã‚ã®ãƒ‘スワード。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078007">&nbsp;
+</A>
+<A NAME="mailGroup">
+<H3> mailGroup</H3>
+</A>
+
+
+
+<A NAME="1078009">
+<a href="objclass.htm#1005294">groupOfUniqueNames</A>ã®æ‹¡å¼µæ©Ÿèƒ½ã¨ã—ã¦ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€ãƒ¡ãƒ¼ãƒ«å—å–人ã®ã‚°ãƒ«ãƒ¼ãƒ—を定義ã—ã¾ã™ã€‚ã™ãªã‚ã¡ã€mailGroupã¯ã€Messaging Serverメール リストã®ä¿å­˜ã«ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚<P></A>
+
+<A NAME="1097032">
+OID: <CODE>2.16.840.1.113730.3.2.4</CODE><P></A>
+
+<A NAME="1078087">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078012">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078014">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1078017">
+<a href="attribut.htm#1189404">mail</A><P></A>
+<td>
+<A NAME="1078020">
+(å¿…é ˆ) グループã®é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ã€‚<P></A>
+
+<tr><td>
+<A NAME="1108751">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108753">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078023">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1078025">
+クループã®ä¸€èˆ¬å<P></A>
+
+<tr><td>
+<A NAME="1103727">
+<a href="attribut.htm#1024250">mailAlternateAddress</A><P></A>
+<td>
+<A NAME="1078030">
+グループã®ä»£æ›¿é›»å­ãƒ¡ãƒ¼ãƒ« アドレス。<P></A>
+
+<tr><td>
+<A NAME="1078033">
+<a href="attribut.htm#1024314">mailHost</A><P></A>
+<td>
+<A NAME="1078035">
+グループã®ãƒ¡ãƒ¼ãƒ« アカウントãŒå­˜åœ¨ã™ã‚‹ãƒ›ã‚¹ãƒˆã‚’示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078038">
+<a href="attribut.htm#1025144">mgrpAllowedBroadcaster</A><P></A>
+<td>
+<A NAME="1078040">
+メール グループã«ãƒ¡ãƒ¼ãƒ«ã‚’é€ä¿¡ã§ãるメール ユーザを示ã™URL。<P></A>
+
+<tr><td>
+<A NAME="1078043">
+<a href="attribut.htm#1024569">mgrpAllowedDomain</A><P></A>
+<td>
+<A NAME="1078045">
+ユーザãŒãƒ¡ãƒ¼ãƒ« グループã«ãƒ¡ãƒ¼ãƒ«ã‚’é€ä¿¡ã§ãã‚‹é€ä¿¡å…ƒãƒ‰ãƒ¡ã‚¤ãƒ³ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078048">
+<a href="attribut.htm#1278551">mgrpDeliverTo</A><P></A>
+<td>
+<A NAME="1078050">
+メール グループã®ãƒ¡ãƒ³ãƒãƒ¼ã‚’指定ã™ã‚‹ä»£æ›¿æ–¹æ³•ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078053">
+<a href="attribut.htm#1025568">mgrpErrorsTo</A><P></A>
+<td>
+<A NAME="1078055">
+メールé…信エラー メッセージã®é€ä¿¡å…ˆãƒ¡ãƒ¼ãƒ« アドレス。<P></A>
+
+<tr><td>
+<A NAME="1078058">
+<a href="attribut.htm#1025705">mgrpModerator</A><P></A>
+<td>
+<A NAME="1078060">
+æ‹’å¦ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ« メッセージã®é€ä¿¡å…ˆãƒ¡ãƒ¼ãƒ« アドレス。<P></A>
+
+<tr><td>
+<A NAME="1078063">
+<a href="attribut.htm#1025878">mgrpMsgMaxSize</A><P></A>
+<td>
+<A NAME="1078065">
+メール グループã«é€ä¿¡ã§ãる最大メッセージ サイズ。<P></A>
+
+<tr><td>
+<A NAME="1078068">
+<a href="attribut.htm#1025035">mgrpMsgRejectAction</A><P></A>
+<td>
+<A NAME="1078070">
+メール グループã«é€ä¿¡ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ãŒæ‹’å¦ã•ã‚ŒãŸå ´åˆã®å¯¾ç­–を示ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1078073">
+<a href="attribut.htm#1025981">mgrpMsgRejectText</A><P></A>
+<td>
+<A NAME="1078075">
+メール グループã«é€ä¿¡ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ãŒæ‹’å¦ã•ã‚ŒãŸå ´åˆã«é€ä¿¡ã™ã‚‹ãƒ†ã‚­ã‚¹ãƒˆã€‚<P></A>
+
+<tr><td>
+<A NAME="1078078">
+<a href="attribut.htm#1024670">mgrpRFC822MailMember</A><P></A>
+<td>
+<A NAME="1078080">
+実際ã¯ãƒ¡ãƒ¼ãƒ« グループã®ãƒ¡ãƒ³ãƒãƒ¼ã§ã¯ãªã„ユーザã§ã€ãƒ¡ãƒ¼ãƒ« グループã«é€ä¿¡ã•ã‚ŒãŸãƒ¡ãƒ¼ãƒ«ã‚’å—ã‘å–ã‚‹å—信者。<P></A>
+
+<tr><td>
+<A NAME="1078084">
+<a href="attribut.htm#1005719">owner</A><P></A>
+<td>
+<A NAME="1078086">
+メール グループã®ã‚ªãƒ¼ãƒŠã®è­˜åˆ¥å。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1081545">&nbsp;
+</A>
+<A NAME="netscapeMailServer">
+<H3> netscapeMailServer</H3>
+</A>
+
+
+
+<A NAME="1081546">
+Netscape Messaging Serverã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ä¿å­˜ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097044">
+OID: <CODE>2.16.840.1.113730.3.2.24</CODE><P></A>
+
+<A NAME="1108767">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108757">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108759">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108764">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108766">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1086191">&nbsp;
+</A>
+<A NAME="Proxy Server Extensions">
+<H2> Proxy Serverã®æ‹¡å¼µ</H2>
+</A>
+
+<A NAME="1086195">
+以下ã¯ã€Netscape Proxy Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹<a href="objclass.htm#1081588">netscapeProxyServer</A>ã®ã‚ªãƒ–ジェクト クラスã®èª¬æ˜Žã§ã™ã€‚<P></A>
+
+
+<A NAME="1081588">&nbsp;
+</A>
+<A NAME="netscapeProxyServer">
+<H3> netscapeProxyServer</H3>
+</A>
+
+
+
+<A NAME="1081589">
+Netscape Proxy Serverã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097160">
+OID: <CODE>2.16.840.1.113730.3.2.28</CODE><P></A>
+
+<A NAME="1108781">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108771">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108773">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108778">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108780">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1081607">&nbsp;
+</A>
+<A NAME="Web Server Extensions">
+<H2> Web Serverã®æ‹¡å¼µ</H2>
+</A>
+
+<A NAME="1081611">
+以下ã¯ã€Netscape Web Serverã«ã‚ˆã£ã¦ä½¿ç”¨ã•ã‚Œã‚‹<a href="objclass.htm#1081614">netscapeWebServer</A>ã®ã‚ªãƒ–ジェクト クラスã®èª¬æ˜Žã§ã™ã€‚<P></A>
+
+
+<A NAME="1081614">&nbsp;
+</A>
+<A NAME="netscapeWebServer">
+<H3> netscapeWebServer</H3>
+</A>
+
+
+
+<A NAME="1081615">
+Netscapeウェブ サーãƒã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯æ¨™æº–LDAPスキーマã¸ã®Netscape社ã®æ‹¡å¼µæ©Ÿèƒ½ã§ã™ã€‚å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1108796">
+OID: <CODE>2.16.840.1.113730.3.2.29</CODE><P></A>
+
+<A NAME="1108814">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108804">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108806">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108811">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1108813">
+(å¿…é ˆ) 予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1108799">&nbsp;
+</A>
+<A NAME="Reserved Object Classes">
+<H2> 予約ã•ã‚ŒãŸã‚ªãƒ–ジェクト クラス</H2>
+</A>
+
+<A NAME="1108800">
+ã“ã®ç¯€ã§ã¯ã€æœ¬ãƒªãƒªãƒ¼ã‚¹ã§å®šç¾©ã•ã‚Œã¦ã„ãªã„ã‹ã€Netscape Directory ServerãŒå°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã—ã¦ã„るオブジェクト クラスã«ã¤ã„ã¦èª¬æ˜Žã—ã¾ã™ã€‚<P></A>
+
+
+<A NAME="1091117">&nbsp;
+</A>
+<A NAME="account">
+<H3> account</H3>
+</A>
+
+
+
+<A NAME="1091854">
+予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1098856">
+OID: <CODE>0.9.2342.19200300.100.4.5</CODE><P></A>
+
+<A NAME="1091903">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091857">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091859">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091907">
+<a href="attribut.htm#1296804">uid</A><P></A>
+<td>
+<A NAME="1091909">
+(å¿…é ˆ) アカウントã®ãƒ¦ãƒ¼ã‚¶ID。<P></A>
+
+<tr><td>
+<A NAME="1091874">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1091876">
+アカウントã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1091917">
+<a href="attribut.htm#1201958">host</A><P></A>
+<td>
+<A NAME="1091919">
+アカウントãŒå­˜åœ¨ã™ã‚‹ã‚³ãƒ³ãƒ”ュータã®ãƒ›ã‚¹ãƒˆå。<P></A>
+
+<tr><td>
+<A NAME="1091879">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1091881">
+アカウントãŒå­˜åœ¨ã™ã‚‹å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1091884">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1091886">
+アカウントãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1091890">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1091892">
+アカウントãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1091895">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1091897">
+アカウントã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089961">&nbsp;
+</A>
+<A NAME="alias">
+<H3> alias</H3>
+</A>
+
+
+
+<A NAME="1089993">
+ディレクトリ ツリーã®ä»–ã®ã‚¨ãƒ³ãƒˆãƒªã‚’指ã™ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096898">
+OID: <CODE>2.5.6.1</CODE><P></A>
+
+<A NAME="1090031">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1089996">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1089998">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1090103">
+<a href="attribut.htm#1201653">aliasedObjectName</A><P></A>
+<td>
+<A NAME="1090004">
+(å¿…é ˆ) エイリアスã§ã‚ã‚‹ã“ã®ã‚¨ãƒ³ãƒˆãƒªã®å…ƒã¨ãªã‚‹ã‚¨ãƒ³ãƒˆãƒªã®è­˜åˆ¥å。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091270">&nbsp;
+</A>
+<A NAME="applicationEntity">
+<H3> applicationEntity</H3>
+</A>
+
+
+
+<A NAME="1106068">
+ディレクトリã§ã‚¢ãƒ—リケーション エンティティを表示ã™ã‚‹ãŸã‚ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096990">
+OID: <CODE>2.5.6.12</CODE><P></A>
+
+<A NAME="1091320">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091274">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091276">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091279">
+<a href="attribut.htm#1202620">presentationAddress</A><P></A>
+<td>
+<A NAME="1091282">
+(å¿…é ˆ) エンティティã®OSIプレゼンテーション アドレス。<P></A>
+
+<tr><td>
+<A NAME="1091285">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1091288">
+(å¿…é ˆ) エンティティã®ä¸€èˆ¬å。<P></A>
+
+<tr><td>
+<A NAME="1091291">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1091293">
+エンティティã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1091296">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1091298">
+エンティティãŒå­˜åœ¨ã™ã‚‹å ´æ‰€ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103836">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1091303">
+エンティティãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1103841">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1091309">
+エンティティãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103846">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1091314">
+エンティティã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1091317">
+<a href="attribut.htm#1202747">supportedApplicationContext</A><P></A>
+<td>
+<A NAME="1091319">
+OSIアプリケーション コンテキストã®è­˜åˆ¥å­ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1090381">&nbsp;
+</A>
+<A NAME="applicationProcess">
+<H3> applicationProcess</H3>
+</A>
+
+
+
+<A NAME="1106091">
+ディレクトリã§ã‚¢ãƒ—リケーション プロセスを表示ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®å®šç¾©ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096988">
+OID: <CODE>2.5.6.11</CODE><P></A>
+
+<A NAME="1090515">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1090555">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1090557">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1103871">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1090563">
+(å¿…é ˆ) プロセスã®ä¸€èˆ¬å。<P></A>
+
+<tr><td>
+<A NAME="1103876">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1090574">
+プロセスã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103866">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1090599">
+プロセスã®ã‚る場所ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103856">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1090585">
+プロセスãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103861">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1090590">
+プロセスã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091421">&nbsp;
+</A>
+<A NAME="cacheObject">
+<H3> cacheObject</H3>
+</A>
+
+
+
+<A NAME="1093594">
+timeToLive (<a href="attribut.htm#1202798">ttl</A>)属性をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªã‚’å¯èƒ½ã«ã™ã‚‹ã‚ªãƒ–ジェクト クラス。<P></A>
+
+<A NAME="1098472">
+OID: <CODE>1.3.6.1.4.1.250.3.18</CODE><P></A>
+
+<A NAME="1093607">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093597">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093599">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093604">
+<a href="attribut.htm#1202798">ttl</A><P></A>
+<td>
+<A NAME="1093606">
+エントリã«ã¤ã„ã¦ã®ã‚­ãƒ£ãƒƒã‚·ãƒ¥ã•ã‚ŒãŸæƒ…å ±ãŒæœ‰åŠ¹ã§ã‚ã‚‹ã¨ã™ã‚‹æ™‚間(秒å˜ä½ï¼‰ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091225">&nbsp;
+</A>
+<A NAME="certificationAuthority">
+<H3> certificationAuthority</H3>
+</A>
+
+
+
+<A NAME="1091226">
+ディレクトリã®è¨¼æ˜Žæ›¸ç™ºè¡Œæ¨©é™ï¼ˆCertificate Authoritiesã€CAs)ã«é–¢ã™ã‚‹æƒ…報をä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1097006">
+OID: <CODE>2.5.6.16</CODE><P></A>
+
+<A NAME="1091261">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091229">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091231">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091236">
+<a href="attribut.htm#1208584">cACertificate;binary</A><P></A>
+<td>
+<A NAME="1091239">
+(å¿…é ˆ) 証明書èªå¯è€…ã‹ã‚‰ã®è¨¼æ˜Žæ›¸ãŒãƒã‚¤ãƒŠãƒªå½¢å¼ã€‚<P></A>
+
+<tr><td>
+<A NAME="1091243">
+<a href="attribut.htm#1207178">authorityRevocationList;binary</A><P></A>
+<td>
+<A NAME="1091246">
+ã™ã§ã«ç„¡åŠ¹ã«ã•ã‚Œã¦ã„ã‚‹ã®ã§ã€æœ‰åŠ¹ã‚ã‚‹ã„ã¯å®‰å…¨ã¨ã¯ã¿ãªã•ã‚Œãªã„CA証明書ã®ãƒªã‚¹ãƒˆ(ãƒã‚¤ãƒŠãƒªå½¢å¼)。<P></A>
+
+<tr><td>
+<A NAME="1091250">
+<a href="attribut.htm#1208727">certificateRevocationList;binary</A><P></A>
+<td>
+<A NAME="1091253">
+ã™ã§ã«ç„¡åŠ¹ã«ã•ã‚ŒãŸãƒ¦ãƒ¼ã‚¶è¨¼æ˜Žæ›¸ãƒªã‚¹ãƒˆ(ãƒã‚¤ãƒŠãƒªå½¢å¼)。<P></A>
+
+<tr><td>
+<A NAME="1091258">
+<a href="attribut.htm#1208791">crossCertificatePair;binary</A><P></A>
+<td>
+<A NAME="1091260">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097268">&nbsp;
+</A>
+<A NAME="dcObject">
+<H3> dcObject</H3>
+</A>
+
+
+
+<A NAME="1097806">
+エントリã®ãƒ‰ãƒ¡ã‚¤ãƒ³ コンãƒãƒ¼ãƒãƒ³ãƒˆã®å®šç¾©ã‚’å¯èƒ½ã«ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€é€šå¸¸ã€<a href="objclass.htm#1004980">organization</A>ã€<a href="objclass.htm#1005108">organizationalUnit</A>ã€ã¾ãŸã¯<a href="objclass.htm#1005427">locality</A>ãªã©ã€ä»–ã®ã‚ªãƒ–ジェクト クラスã¨ã®çµ„åˆã›ã§ä½¿ç”¨ã•ã‚Œã‚‹ã®ã§ã€å‰¯æ¬¡çš„オブジェクトã¨å®šç¾©ã•ã‚Œã¾ã™ã€‚例ãˆã°ã€ä»¥ä¸‹ã®ã‚‚ã®ãŒã‚ã‚Šã¾ã™ã€‚<P></A>
+<PRE><A NAME="1097855">
+dn: dc=airius,dc=com<br>objectClass: top<br>objectClass: organization<br>objectClass: dcObject<br>dc: airius<br>o: Airius Corp.
+</A>
+</PRE>
+<A NAME="1097270">
+OID: <CODE>1.3.6.1.4.1.1466.344</CODE><P></A>
+
+<A NAME="1097318">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1097273">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1097275">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1097278">
+<a href="attribut.htm#1245094">dc</A><P></A>
+<td>
+<A NAME="1097281">
+(å¿…é ˆ) エントリã®ãƒ‰ãƒ¡ã‚¤ãƒ³ コンãƒãƒ¼ãƒãƒ³ãƒˆã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1090760">&nbsp;
+</A>
+<A NAME="device">
+<H3> device</H3>
+</A>
+
+
+
+<A NAME="1090817">
+プリンタãªã©ã®ãƒãƒƒãƒˆãƒ¯ãƒ¼ã‚¯ デãƒã‚¤ã‚¹ã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096996">
+OID: <CODE>2.5.6.14</CODE><P></A>
+
+<A NAME="1090828">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1103908">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1103910">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1103915">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1103917">
+(å¿…é ˆ) デãƒã‚¤ã‚¹ã®ä¸€èˆ¬å。<P></A>
+
+<tr><td>
+<A NAME="1103922">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1103924">
+デãƒã‚¤ã‚¹ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103960">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1103929">
+デãƒã‚¤ã‚¹ã®ã‚る場所ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103965">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1103934">
+デãƒã‚¤ã‚¹ãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1103970">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1103940">
+デãƒã‚¤ã‚¹ãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103943">
+<a href="attribut.htm#1005719">owner</A><P></A>
+<td>
+<A NAME="1103945">
+デãƒã‚¤ã‚¹ã®è²¬ä»»è€…ã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1103948">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1103950">
+デãƒã‚¤ã‚¹ã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1103953">
+<a href="attribut.htm#1202700">serialNumber</A><P></A>
+<td>
+<A NAME="1103955">
+デãƒã‚¤ã‚¹ã®ã‚·ãƒªã‚¢ãƒ«ç•ªå·ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091390">&nbsp;
+</A>
+<A NAME="DNSDomain">
+<H3> DNSDomain</H3>
+</A>
+
+
+
+<A NAME="1093025">
+ドメインã®ã‚µãƒ–クラスã¨ã—ã¦ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラスã§ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«DNSリソース レコードをä¿å­˜ã—ã¾ã™ã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096887">
+OID: <CODE>0.9.2342.19200300.100.4.15</CODE><P></A>
+
+<A NAME="1093023">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093008">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093010">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093013">
+<a href="attribut.htm#1201841">dNSRecord</A><P></A>
+<td>
+<A NAME="1093015">
+DNSリソース レコード。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091348">&nbsp;
+</A>
+<A NAME="document">
+<H3> document</H3>
+</A>
+
+
+
+<A NAME="1092549">
+ディレクトリã§ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’表示ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®å®šç¾©ã«ä½¿ç”¨ã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096874">
+OID: <CODE>0.9.2342.19200300.100.4.6</CODE><P></A>
+
+<A NAME="1091981">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092165">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092167">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092172">
+<a href="attribut.htm#1201854">documentIdentifier</A><P></A>
+<td>
+<A NAME="1092175">
+(å¿…é ˆ) ドキュメント固有ã®è­˜åˆ¥å­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092180">
+<a href="attribut.htm#1201644">abstract</A><P></A>
+<td>
+<A NAME="1092182">
+ドキュメントã®æ¦‚è¦ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092187">
+<a href="attribut.htm#1201689">authorCn</A><P></A>
+<td>
+<A NAME="1092189">
+著者ã®ä¸€èˆ¬åã€ã¾ãŸã¯åå‰ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092194">
+<a href="attribut.htm#1201696">authorSn</A><P></A>
+<td>
+<A NAME="1092196">
+著者ã®å§“。<P></A>
+
+<tr><td>
+<A NAME="1092201">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1092203">
+ドキュメントã®ä¸€èˆ¬å。<P></A>
+
+<tr><td>
+<A NAME="1092206">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1092208">
+内容ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092213">
+<a href="attribut.htm#1201847">documentAuthor</A><P></A>
+<td>
+<A NAME="1092215">
+ドキュメントã®è‘—者ã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1092220">
+<a href="attribut.htm#1201861">documentLocation</A><P></A>
+<td>
+<A NAME="1092222">
+å…ƒã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092227">
+<a href="attribut.htm#1201868">documentPublisher</A><P></A>
+<td>
+<A NAME="1092229">
+ドキュメントをパブリッシュã—ãŸãƒ¦ãƒ¼ã‚¶ã¾ãŸã¯çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1092234">
+<a href="attribut.htm#1201877">documentStore</A><P></A>
+<td>
+<A NAME="1092236">
+未定義。<P></A>
+
+<tr><td>
+<A NAME="1092241">
+<a href="attribut.htm#1201884">documentTitle</A><P></A>
+<td>
+<A NAME="1092243">
+ドキュメントã®é¡Œå。<P></A>
+
+<tr><td>
+<A NAME="1092248">
+<a href="attribut.htm#1201891">documentVersion</A><P></A>
+<td>
+<A NAME="1092250">
+ドキュメントã®æ”¹è¨‚番å·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092255">
+<a href="attribut.htm#1202004">keyWords</A><P></A>
+<td>
+<A NAME="1092257">
+ドキュメントを記述ã™ã‚‹ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰ã€‚<P></A>
+
+<tr><td>
+<A NAME="1103998">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1092262">
+ドキュメントãŒå­˜åœ¨ã™ã‚‹å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104003">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1092267">
+ドキュメントãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1092272">
+<a href="attribut.htm#1202192">obsoletedByDocument</A><P></A>
+<td>
+<A NAME="1092274">
+ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã‚’旧版ã«ã—ãŸãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1092279">
+<a href="attribut.htm#1202199">obsoletesDocument</A><P></A>
+<td>
+<A NAME="1092281">
+ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆãŒæ—§ç‰ˆã«ã—ãŸãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1104008">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1092299">
+ドキュメントãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104013">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1092293">
+ドキュメントã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1092306">
+<a href="attribut.htm#1202732">subject</A><P></A>
+<td>
+<A NAME="1092308">
+ドキュメントã®ä¸»é¡Œã€‚<P></A>
+
+<tr><td>
+<A NAME="1092330">
+<a href="attribut.htm#1202817">updatedByDocument</A><P></A>
+<td>
+<A NAME="1092334">
+ã“ã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®æ›´æ–°ç‰ˆãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1092323">
+<a href="attribut.htm#1202824">updatesDocument</A><P></A>
+<td>
+<A NAME="1092340">
+ã“ã®æ›´æ–°ç‰ˆãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®å…ƒã®ãƒ‰ã‚­ãƒ¥ãƒ¡ãƒ³ãƒˆã®è­˜åˆ¥å。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091354">&nbsp;
+</A>
+<A NAME="documentSeries">
+<H3> documentSeries</H3>
+</A>
+
+
+
+<A NAME="1092560">
+ドキュメントã®ã‚·ãƒªãƒ¼ã‚ºã‚’表示ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®å®šç¾©ã«ä½¿ç”¨ã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096876">
+OID: <CODE>0.9.2342.19200300.100.4.9</CODE><P></A>
+
+<A NAME="1092547">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092502">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092504">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092507">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1092579">
+(å¿…é ˆ) シリーズã®ä¸€èˆ¬å。<P></A>
+
+<tr><td>
+<A NAME="1104028">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1092515">
+シリーズã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104033">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1092520">
+シリーズã®ã‚る場所ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104038">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1092525">
+シリーズãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1104043">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1092531">
+シリーズãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104048">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1092541">
+シリーズã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1092600">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1092602">
+シリーズ責任者ã®é›»è©±ç•ªå·ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091357">&nbsp;
+</A>
+<A NAME="domain">
+<H3> domain</H3>
+</A>
+
+
+
+<A NAME="1097945">
+ディレクトリã§ã€DNSドメインを表示ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã®ã‚¨ãƒ³ãƒˆãƒªã®å‘½åã«ã¯ã€domainComponent属性を使用ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096879">
+OID: <CODE>0.9.2342.19200300.100.4.13</CODE><P></A>
+
+<A NAME="1092674">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092632">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092634">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092639">
+<a href="attribut.htm#1245094">dc</A><P></A>
+<td>
+<A NAME="1092642">
+(å¿…é ˆ) ドメインåã®ã‚³ãƒ³ãƒãƒ¼ãƒãƒ³ãƒˆã®1ã¤ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092701">
+<a href="attribut.htm#1201675">associatedName</A><P></A>
+<td>
+<A NAME="1092708">
+DNSドメインã¨ã«é–¢é€£ã—ãŸçµ„ç¹”ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリー内ã®ã‚¨ãƒ³ãƒˆãƒªã€‚<P></A>
+
+<tr><td>
+<A NAME="1092721">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1092723">
+ã“ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ãŒå¾“事ã™ã‚‹äº‹æ¥­ã‚¿ã‚¤ãƒ—。<P></A>
+
+<tr><td>
+<A NAME="1092645">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1092647">
+ドメインã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092735">
+<a href="attribut.htm#1292809">destinationIndicator</A><P></A>
+<td>
+<A NAME="1092737">
+ã“ã®å±žæ€§ã¯ã€ã“ã®ãƒ‰ãƒ¡ã‚¤ãƒ³ã¸ã®é›»å ±ã‚µãƒ¼ãƒ“スã«ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092741">
+<a href="attribut.htm#1171637">facsimileTelephoneNumber</A><P></A>
+<td>
+<A NAME="1092744">
+ドメインã«é–¢ä¿‚ã™ã‚‹ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092749">
+<a href="attribut.htm#1224256">internationalIsdnNumber</A><P></A>
+<td>
+<A NAME="1092751">
+ドメインã«é–¢ä¿‚ã™ã‚‹ISDN番å·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092650">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1092652">
+ドメインã®ã‚る場所ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092778">
+<a href="attribut.htm#1007859">manager</A><P></A>
+<td>
+<A NAME="1092780">
+ドメインã«é–¢ä¿‚ã™ã‚‹ãƒžãƒãƒ¼ã‚¸ãƒ£ã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1092655">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1092657">
+ドメインãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1092789">
+<a href="attribut.htm#1003072">physicalDeliveryOfficeName</A><P></A>
+<td>
+<A NAME="1092791">
+物ç†çš„ãªé…é€ãŒã§ãる場所。<P></A>
+
+<tr><td>
+<A NAME="1092794">
+<a href="attribut.htm#1230025">postalAddress</A><P></A>
+<td>
+<A NAME="1092796">
+ドメインã«é–¢ä¿‚ã™ã‚‹éƒµä¾¿ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092799">
+<a href="attribut.htm#1230036">postalCode</A><P></A>
+<td>
+<A NAME="1092801">
+ドメインã®çµ„ç¹”ã®éƒµä¾¿ç•ªå·(米国ã«ãŠã‘る郵便番å·ãªã©)。<P></A>
+
+<tr><td>
+<A NAME="1092804">
+<a href="attribut.htm#1230043">postOfficeBox</A><P></A>
+<td>
+<A NAME="1092806">
+ドメインã®ç§æ›¸ç®±ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092809">
+<a href="attribut.htm#1202605">preferredDeliveryMethod</A><P></A>
+<td>
+<A NAME="1092811">
+ドメインãŒå¸Œæœ›ã™ã‚‹é€£çµ¡æ–¹æ³•ã¾ãŸã¯é…é”方法。<P></A>
+
+<tr><td>
+<A NAME="1092824">
+<a href="attribut.htm#1202644">registeredAddress</A><P></A>
+<td>
+<A NAME="1092826">
+緊急ã®æ›¸é¡žã®å—ã‘å–ã‚Šãªã©ã€å—å–人ãŒé…é”を確èªã™ã‚‹å¿…è¦ã®ã‚ã‚‹ã‚‚ã®ã‚’é…é”ã™ã‚‹ã®ã«ãµã•ã‚ã—ã„郵é€ç”¨ã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092857">
+<a href="attribut.htm#1202682">searchGuide</A><P></A>
+<td>
+<A NAME="1092859">
+検索動作ã®ãŸã‚ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã®ãƒ™ãƒ¼ã‚¹ オブジェクトã¨ã—ã¦ã‚¨ãƒ³ãƒˆãƒªã‚’使用ã™ã‚‹éš›ã«ã€æ案ã•ã‚Œã‚‹æ¤œç´¢åŸºæº–ã®æƒ…報を指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092871">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1092873">
+ドメインã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1092829">
+<a href="attribut.htm#1203417">st</A><P></A>
+<td>
+<A NAME="1092831">
+ドメインã®å­˜åœ¨ã™ã‚‹å·žã¾ãŸã¯éƒ½é“府県。<P></A>
+
+<tr><td>
+<A NAME="1092834">
+<a href="attribut.htm#1202721">street</A><P></A>
+<td>
+<A NAME="1092836">
+ドメインã«é–¢ä¿‚ã™ã‚‹è¡—è·¯ã¨ç•ªåœ°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092882">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1092884">
+ドメインã«é–¢ä¿‚ã™ã‚‹é›»è©±ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092839">
+<a href="attribut.htm#1205004">teletexTerminalIdentifier</A><P></A>
+<td>
+<A NAME="1092841">
+ドメインã«é–¢ä¿‚ã™ã‚‹ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナルã®è­˜åˆ¥å­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092844">
+<a href="attribut.htm#1205120">telexNumber</A><P></A>
+<td>
+<A NAME="1092846">
+ドメインã«é–¢ä¿‚ã™ã‚‹ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092909">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1092911">
+å°†æ¥ã®ä½¿ç”¨ã«äºˆç´„ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092851">
+<a href="attribut.htm#1281763">x121Address</A><P></A>
+<td>
+<A NAME="1092853">
+ドメインã«é–¢ä¿‚ã™ã‚‹ X.121アドレス。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091384">&nbsp;
+</A>
+<A NAME="domainRelatedObject">
+<H3> domainRelatedObject</H3>
+</A>
+
+
+
+<A NAME="1093633">
+通常ã€çµ„ç¹”ã¾ãŸã¯çµ„ç¹”å˜ä½ã§ã‚ã‚‹X.500ドメインã«ç­‰ã—ã„DNSドメインを示ã™ã‚¨ãƒ³ãƒˆãƒªã®å®šç¾©ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1098880">
+OID: <CODE>0.9.2342.19200300.100.4.17</CODE><P></A>
+
+<A NAME="1097753">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1097743">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1097745">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1097750">
+<a href="attribut.htm#1201668">associatedDomain</A><P></A>
+<td>
+<A NAME="1097752">
+ディレクトリ ツリー内ã®ã‚ªãƒ–ジェクトã«é–¢ä¿‚ã™ã‚‹DNSドメイン。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097756">&nbsp;
+</A>
+<A NAME="dSA">
+<H3> dSA</H3>
+</A>
+
+
+
+<A NAME="1097757">
+ディレクトリã§ã€DSAを表示ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®å®šç¾©ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096993">
+OID: <CODE>2.5.6.13</CODE><P></A>
+
+<A NAME="1091405">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091397">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091399">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091402">
+<a href="attribut.htm#1202013">knowledgeInformation</A><P></A>
+<td>
+<A NAME="1091404">
+ã“ã®å±žæ€§ã¯ç¾åœ¨ä½¿ç”¨ã•ã‚Œã¦ã„ã¾ã›ã‚“。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091415">&nbsp;
+</A>
+<A NAME="friendlyCountry">
+<H3> friendlyCountry</H3>
+</A>
+
+
+
+<A NAME="1093062">
+ディレクトリ ツリーã§ã€å›½ã®ã‚¨ãƒ³ãƒˆãƒªã‚’定義ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスを使用ã™ã‚‹ã¨ã€å›½ã‚ªãƒ–ジェクト クラスã§è¨±ã•ã‚Œã¦ã„るよりもã€ã‚‚ã£ã¨ãƒ¦ãƒ¼ã‚¶ フレンドリãªå›½åãŒå¯èƒ½ã«ãªã‚Šã¾ã™ã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1098883">
+OID: <CODE>0.9.2342.19200300.100.4.18</CODE><P></A>
+
+<A NAME="1093060">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093050">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093052">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093057">
+<a href="attribut.htm#1265915">co</A><P></A>
+<td>
+<A NAME="1093059">
+国åã‚’ä¿æŒã—ã¦ã„ã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091443">&nbsp;
+</A>
+<A NAME="labeledURIObject">
+<H3> labeledURIObject</H3>
+</A>
+
+
+
+<A NAME="1096833">
+ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€æ—¢å­˜ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª オブジェクトã«è¿½åŠ ã—ã¦ã€URI値ã«å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚ã“ã®ã‚¢ãƒ—ローãƒã¯ã€labeledURI属性を他ã®ã‚ªãƒ–ジェクト クラスã«ç›´æŽ¥å…¥ã‚Œã‚‹ã®ã‚’妨ã’ã¾ã›ã‚“(é©åˆ‡ãªå ´åˆï¼‰ã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096829">
+OID: <CODE>1.3.6.1.4.1.250.3.15</CODE><P></A>
+
+<A NAME="1093588">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093578">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093580">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093585">
+<a href="attribut.htm#1202020">labeledUri</A><P></A>
+<td>
+<A NAME="1093587">
+エントリã«é–¢ä¿‚ã™ã‚‹Uniform Resource Identifier (URI)。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091410">&nbsp;
+</A>
+<A NAME="pilotObject">
+<H3> pilotObject</H3>
+</A>
+
+
+
+<A NAME="1091508">
+ä»–ã®ã™ã¹ã¦ã®ã‚ªãƒ–ジェクト クラスã®ã‚¨ãƒ³ãƒˆãƒªã«è¿½åŠ ã®å±žæ€§ã‚’割り当ã¦ã‚‰ã‚Œã‚‹ã‚ˆã†ã«ã™ã‚‹ã‚µãƒ–クラスã¨ã—ã¦ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096860">
+OID: <CODE>0.9.2342.19200300.100.4.3</CODE><P></A>
+
+<A NAME="1091544">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091536">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091538">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091541">
+<a href="attribut.htm#1201684">audio</A><P></A>
+<td>
+<A NAME="1091543">
+サウンド ファイル。<P></A>
+
+<tr><td>
+<A NAME="1091579">
+<a href="attribut.htm#1201831">ditRedirect</A><P></A>
+<td>
+<A NAME="1091581">
+エントリã®ãƒªãƒ€ã‚¤ãƒ¬ã‚¯ã‚·ãƒ§ãƒ³ã«ä½¿ç”¨ã™ã‚‹è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1091575">
+<a href="attribut.htm#1201965">info</A><P></A>
+<td>
+<A NAME="1091577">
+オブジェクトã®æƒ…報。<P></A>
+
+<tr><td>
+<A NAME="1091571">
+<a href="attribut.htm#1201995">jpegPhoto</A><P></A>
+<td>
+<A NAME="1091573">
+JPEGå½¢å¼ã®å†™çœŸã€‚<P></A>
+
+<tr><td>
+<A NAME="1091567">
+<a href="attribut.htm#1100733">lastModifiedBy</A><P></A>
+<td>
+<A NAME="1091569">
+オブジェクトã®æœ€çµ‚変更者ã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1091563">
+<a href="attribut.htm#1202035">lastModifiedTime</A><P></A>
+<td>
+<A NAME="1091565">
+オブジェクトã®æœ€çµ‚変更時刻。<P></A>
+
+<tr><td>
+<A NAME="1091559">
+<a href="attribut.htm#1007859">manager</A><P></A>
+<td>
+<A NAME="1091561">
+オブジェクトã®ãƒžãƒãƒ¼ã‚¸ãƒ£ã®è­˜åˆ¥å。<P></A>
+
+<tr><td>
+<A NAME="1091555">
+<a href="attribut.htm#1202247">photo</A><P></A>
+<td>
+<A NAME="1091557">
+オブジェクトã®å†™çœŸã€‚<P></A>
+
+<tr><td>
+<A NAME="1091551">
+<a href="attribut.htm#1202809">uniqueIdentifier</A><P></A>
+<td>
+<A NAME="1091553">
+識別åãŒå†ä½¿ç”¨ã•ã‚Œã¦ã„ã‚‹å ´åˆã«ã€2ã¤ã®ã‚¨ãƒ³ãƒˆãƒªã‚’区別ã™ã‚‹ã®ã«ä½¿ç”¨ã™ã‚‹ç‰¹å®šé …目。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091437">&nbsp;
+</A>
+<A NAME="pilotOrganization">
+<H3> pilotOrganization</H3>
+</A>
+
+
+
+<A NAME="1093224">
+organizationã¨organizationalUnitã®ã‚ªãƒ–ジェクト クラスã®ã‚¨ãƒ³ãƒˆãƒªã«è¿½åŠ ã®å±žæ€§ã‚’割り当ã¦ã‚‰ã‚Œã‚‹ã‚ˆã†ã«ã™ã‚‹ã‚µãƒ–クラスã¨ã—ã¦ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096890">
+OID: <CODE>0.9.2342.19200300.100.4.20</CODE><P></A>
+
+<A NAME="1093387">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093251">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093253">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093394">
+<a href="attribut.htm#1281611">o</A><P></A>
+<td>
+<A NAME="1093396">
+(å¿…é ˆ) エントリãŒå±žã™ã‚‹çµ„織。<P></A>
+
+<tr><td>
+<A NAME="1093400">
+<a href="attribut.htm#1241174">ou</A><P></A>
+<td>
+<A NAME="1093402">
+(å¿…é ˆ) エントリãŒå±žã™ã‚‹çµ„ç¹”å˜ä½ã€‚<P></A>
+
+<tr><td>
+<A NAME="1093418">
+<a href="attribut.htm#1201711">buildingName</A><P></A>
+<td>
+<A NAME="1093420">
+エントリãŒã‚る建物ã®åå‰ã€‚<P></A>
+
+<tr><td>
+<A NAME="1093258">
+<a href="attribut.htm#1171367">businessCategory</A><P></A>
+<td>
+<A NAME="1093260">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªãŒå¾“事ã™ã‚‹äº‹æ¥­ã‚¿ã‚¤ãƒ—。<P></A>
+
+<tr><td>
+<A NAME="1093265">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1093267">
+エントリã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1093433">
+<a href="attribut.htm#1292809">destinationIndicator</A><P></A>
+<td>
+<A NAME="1093435">
+ã“ã®å±žæ€§ã¯ã€ã“ã®ã‚¨ãƒ³ãƒˆãƒªã¸ã®é›»å ±ã‚µãƒ¼ãƒ“スã«ä½¿ç”¨ã•ã‚Œã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1093439">
+<a href="attribut.htm#1171637">facsimileTelephoneNumber</A><P></A>
+<td>
+<A NAME="1093442">
+エントリã«é–¢ä¿‚ã™ã‚‹ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1093447">
+<a href="attribut.htm#1224256">internationalIsdnNumber</A><P></A>
+<td>
+<A NAME="1093449">
+エントリã«é–¢ä¿‚ã™ã‚‹ISDN番å·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1093452">
+<a href="attribut.htm#1244534">l</A><P></A>
+<td>
+<A NAME="1093454">
+エントリãŒå­˜åœ¨ã™ã‚‹å ´æ‰€ã®åœ°åŸŸæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1093516">
+<a href="attribut.htm#1003072">physicalDeliveryOfficeName</A><P></A>
+<td>
+<A NAME="1093518">
+物ç†çš„ã«ã‚‚ã®ã‚’é…é”ã™ã‚‹ãŸã‚ã®ã‚¨ãƒ³ãƒˆãƒªã®å ´æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104165">
+<a href="attribut.htm#1230025">postalAddress</A><P></A>
+<td>
+<A NAME="1093513">
+エントリã®å‹¤å‹™å…ˆéƒµé€ç”¨ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104170">
+<a href="attribut.htm#1230036">postalCode</A><P></A>
+<td>
+<A NAME="1093508">
+エントリã®å‹¤å‹™å…ˆéƒµä¾¿ç•ªå·(米国ã«ãŠã‘る郵便番å·ãªã©)。<P></A>
+
+<tr><td>
+<A NAME="1104175">
+<a href="attribut.htm#1230043">postOfficeBox</A><P></A>
+<td>
+<A NAME="1093503">
+エントリã®å‹¤å‹™å…ˆã®ç§æ›¸ç®±ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104180">
+<a href="attribut.htm#1202605">preferredDeliveryMethod</A><P></A>
+<td>
+<A NAME="1093498">
+エントリãŒå¸Œæœ›ã™ã‚‹é€£çµ¡æ–¹æ³•ã¾ãŸã¯é…é”方法。<P></A>
+
+<tr><td>
+<A NAME="1104185">
+<a href="attribut.htm#1202644">registeredAddress</A><P></A>
+<td>
+<A NAME="1106134">
+緊急ã®æ›¸é¡žã®å—ã‘å–ã‚Šãªã©ã€å—å–人ãŒé…é”を確èªã™ã‚‹å¿…è¦ã®ã‚ã‚‹ã‚‚ã®ã‚’é…é”ã™ã‚‹ã®ã«ãµã•ã‚ã—ã„郵é€ç”¨ã®ä½æ‰€ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104190">
+<a href="attribut.htm#1202682">searchGuide</A><P></A>
+<td>
+<A NAME="1093532">
+検索動作ã®ãŸã‚ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã®ãƒ™ãƒ¼ã‚¹ オブジェクトã¨ã—ã¦ã‚¨ãƒ³ãƒˆãƒªã‚’使用ã™ã‚‹éš›ã«ã€æ案ã•ã‚Œã‚‹æ¤œç´¢åŸºæº–ã®æƒ…報を指定ã—ã¾ã™ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104195">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1093544">
+エントリã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1104200">
+<a href="attribut.htm#1203417">st</A><P></A>
+<td>
+<A NAME="1093488">
+エントリã®å­˜åœ¨ã™ã‚‹å·žã¾ãŸã¯éƒ½é“府県。<P></A>
+
+<tr><td>
+<A NAME="1104205">
+<a href="attribut.htm#1202721">street</A><P></A>
+<td>
+<A NAME="1093483">
+エントリã®ã‚ã‚‹è¡—è·¯ã¨ç•ªåœ°ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104210">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1093557">
+エントリã«é–¢é€£ã™ã‚‹é›»è©±ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104215">
+<a href="attribut.htm#1205004">teletexTerminalIdentifier</A><P></A>
+<td>
+<A NAME="1093478">
+エントリã®ãƒ†ãƒ¬ãƒ†ãƒƒã‚¯ã‚¹ ターミナルã®è­˜åˆ¥å­ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104220">
+<a href="attribut.htm#1205120">telexNumber</A><P></A>
+<td>
+<A NAME="1093473">
+エントリã®ãƒ†ãƒ¬ãƒƒã‚¯ã‚¹ç•ªå·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1104225">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1093572">
+エントリã®ãƒ‘スワードã¨æš—å·åŒ–方法。<P></A>
+
+<tr><td>
+<A NAME="1104230">
+<a href="attribut.htm#1281763">x121Address</A><P></A>
+<td>
+<A NAME="1093468">
+エントリã®X.121アドレス。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091375">&nbsp;
+</A>
+<A NAME="RFC822LocalPart">
+<H3> RFC822LocalPart</H3>
+</A>
+
+
+
+<A NAME="1092973">
+RFC822メール アドレスã®ãƒ­ãƒ¼ã‚«ãƒ«éƒ¨åˆ†ã‚’表示ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®å®šç¾©ã«ä½¿ç”¨ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ディレクトリã¯ã€RFC822アドレスã®ã“ã®éƒ¨åˆ†ã‚’ドメインã¨ã—ã¦å–り扱ã„ã¾ã™ã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1096884">
+OID: <CODE>0.9.2342.19200300.100.4.14</CODE><P></A>
+
+<A NAME="1092966">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092920">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092922">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092931">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1092934">
+エントリã®ä¸€èˆ¬åã¾ãŸã¯åå‰ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092963">
+<a href="attribut.htm#1290325">sn</A><P></A>
+<td>
+<A NAME="1092965">
+エントリã®å§“<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091363">&nbsp;
+</A>
+<A NAME="room">
+<H3> room</H3>
+</A>
+
+
+
+<A NAME="1092427">
+ディレクトリã§ã€éƒ¨å±‹ã«ã¤ã„ã¦ã®æƒ…報をä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1098891">
+OID: <CODE>0.9.2342.19200300.100.4.7</CODE><P></A>
+
+<A NAME="1098892">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092361">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092363">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092443">
+<a href="attribut.htm#1171494">cn</A><P></A>
+<td>
+<A NAME="1092446">
+(å¿…é ˆ) 部屋ã®ä¸€èˆ¬å。<P></A>
+
+<tr><td>
+<A NAME="1092449">
+<a href="attribut.htm#1171528">description</A><P></A>
+<td>
+<A NAME="1092451">
+部屋ã®èª¬æ˜Žæ–‡ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092468">
+<a href="attribut.htm#1204477">roomNumber</A><P></A>
+<td>
+<A NAME="1092470">
+部屋番å·ã€‚<P></A>
+
+<tr><td>
+<A NAME="1092477">
+<a href="attribut.htm#1172500">seeAlso</A><P></A>
+<td>
+<A NAME="1092479">
+部屋ã«é–¢ä¿‚ã™ã‚‹æƒ…å ±ã¸ã®URL。<P></A>
+
+<tr><td>
+<A NAME="1092491">
+<a href="attribut.htm#1230129">telephoneNumber</A><P></A>
+<td>
+<A NAME="1092493">
+部屋ã®é›»è©±ç•ªå·<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091431">&nbsp;
+</A>
+<A NAME="simpleSecurityObject">
+<H3> simpleSecurityObject</H3>
+</A>
+
+
+
+<A NAME="1093131">
+主オブジェクト クラスãŒå±žæ€§ã‚¿ã‚¤ãƒ—ã¨ã—ã¦userPasswordを許ã•ãªã„å ´åˆã«ã€userPassword属性をå«ã‚€ã‚¨ãƒ³ãƒˆãƒªã‚’å¯èƒ½ã«ã™ã‚‹ã‚ªãƒ–ジェクト クラス。予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1093125">
+OID: <CODE>0.9.2342.19200300.100.4.19</CODE><P></A>
+
+<A NAME="1098903">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093106">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093108">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093113">
+<a href="attribut.htm#1196547">userPassword</A><P></A>
+<td>
+<A NAME="1093116">
+(å¿…é ˆ) エントリã®ãƒ‘スワードã¨æš—å·åŒ–方法。<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089871">&nbsp;
+</A>
+<A NAME="strongAuthenticationUser">
+<H3> strongAuthenticationUser</H3>
+</A>
+
+
+
+<A NAME="1090921">
+クライアントã¨è¨¼æ˜Žæ›¸ã®æƒ…報をã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ä¿å­˜ã™ã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1106458">
+OID: <CODE>2.5.6.15</CODE><P></A>
+
+<A NAME="1106478">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1106461">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1106463">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1106468">
+<a href="attribut.htm#1208938">userCertificate</A><P></A>
+<td>
+<A NAME="1106470">
+未使用。<P></A>
+
+<tr><td>
+<A NAME="1106475">
+<a href="attribut.htm#1278425">userCertificate;binary</A><P></A>
+<td>
+<A NAME="1106477">
+(å¿…é ˆ) ãƒã‚¤ãƒŠãƒªå½¢å¼ã®ãƒ¦ãƒ¼ã‚¶ã®è¨¼æ˜Žæ›¸ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1106481">&nbsp;
+</A>
+<A NAME="top">
+<H3> top</H3>
+</A>
+
+
+
+<A NAME="1106482">
+ディレクトリã§ã€ä»–ã®ã™ã¹ã¦ã®ã‚ªãƒ–ジェクト クラスã®ã‚µãƒ–クラスã¨ã—ã¦ä½¿ç”¨ã•ã‚Œã‚‹ã‚ªãƒ–ジェクト クラス。ã“ã®ã‚ªãƒ–ジェクト クラスã¯ã€X.500 Directory Servicesã‹ã‚‰ç¶™æ‰¿ã•ã‚Œã¾ã—ãŸã€‚予約ã•ã‚Œã¦ã„ã¾ã™ã€‚<P></A>
+
+<A NAME="1106020">
+OID: <CODE>2.5.6.0</CODE><P></A>
+
+<A NAME="1106503">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1106486">
+<B>属性</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1106488">
+<B>属性ã®èª¬æ˜Ž</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1106493">
+<a href="attribut.htm#1229677">objectClass</A><P></A>
+<td>
+<A NAME="1106495">
+(å¿…é ˆ) ã™ã¹ã¦ã®ã‚ªãƒ–ジェクト クラスã«å¿…é ˆã®å±žæ€§ã€‚<P></A>
+
+<tr><td>
+<A NAME="1106500">
+<a href="attribut.htm#1171292">aci</A><P></A>
+<td>
+<A NAME="1106502">
+ã“ã®ã‚¨ãƒ³ãƒˆãƒªã«å¯¾ã™ã‚‹Directory Serverアクセス制御情報をä¿å­˜ã—ã¦ã‚ã‚Šã¾ã™ã€‚<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+<A NAME="1106011">
+<P></A>
+
+</HTML>
+
diff --git a/ldap/clients/dsgw/html/manual/ja/search.htm b/ldap/clients/dsgw/html/manual/ja/search.htm
new file mode 100644
index 00000000..7593acfc
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/ja/search.htm
@@ -0,0 +1,380 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+
+<html>
+<!-- HEAD -->
+<title>ディレクトリ ツリーã®æ¤œç´¢</title>
+</head>
+
+<body>
+
+<h1><a name="search"></a>ディレクトリ ツリーã®æ¤œç´¢</h1>
+
+<p>Directory Serverã«ã¯ã€ä¼æ¥­ã®ãƒ¦ãƒ¼ã‚¶ã¨ãƒªã‚½ãƒ¼ã‚¹ã«é–¢ã™ã‚‹è²´é‡ãªæƒ…å ±ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚Directory Serverã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã‚’使用ã—ã¦ã€å¿…è¦ãªæƒ…報を簡å˜ã«è¦‹ã¤ã‘ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚検索プロセスを簡略化ã™ã‚‹ãŸã‚ã€ã“ã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã§ã¯2種類ã®æ¤œç´¢ã‚’æä¾›ã—ã¦ã„ã¾ã™ã€‚</p>
+
+<ul>
+ <li><a href="#standard">標準検索</a> -- 指定ã—ãŸå€¤ã«åŸºã¥ã„ã¦é©åˆ‡ãªæ¤œç´¢æ–¹æ³•ãŒé¸æŠžã•ã‚Œã¾ã™ã€‚例ãˆã°ã€moz@airius.comを指定ã™ã‚‹ã¨ã€æ¨™æº–検索ã§ã¯ä¸€è‡´ã™ã‚‹é›»å­ãƒ¡ãƒ¼ãƒ« アドレスãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚</li>
+<P>
+ <li><a href="#advanced">拡張検索</a>特定ã®ã‚¨ãƒ³ãƒˆãƒªå±žæ€§ã«å¯¾ã™ã‚‹ç°¡å˜ãªæ¤œç´¢æ–¹æ³•ã‚’æä¾›ã—ã¾ã™ã€‚例ãˆã°ã€åå­—ãŒ<b>k</b>ã§å§‹ã¾ã‚Šã€é›»è©±ç•ªå·ãŒ<b>2110</b>ã§çµ‚ã‚るユーザを検索ã™ã‚‹ã‚ˆã†ã«æŒ‡å®šã§ãã¾ã™ã€‚</li>
+</ul>
+
+<p>ã„ãšã‚Œã®ã‚¿ã‚¤ãƒ—ã®æ¤œç´¢ã‚’使用ã™ã‚‹å ´åˆã§ã‚‚ã€æ¤œç´¢ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã®ã‚¿ã‚¤ãƒ—ã‚’é¸æŠžã§ãã¾ã™ã€‚以下ã®ã‚¨ãƒ³ãƒˆãƒª タイプを検索ã§ãã¾ã™ã€‚</p>
+
+<table border="2">
+ <tr>
+ <th><a name="type"></a><b>エントリ タイプ</b></th>
+ <th>説明</th>
+ </tr>
+ <tr>
+ <td valign="top">ユーザ</td>
+ <td valign="top">ユーザを記述ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã€‚</td>
+ </tr>
+ <tr>
+ <td valign="top">NTユーザ</td>
+ <td valign="top">NTユーザを記述ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã€‚</td>
+ </tr>
+ <tr>
+ <td valign="top">グループ<b> </b></td>
+ <td valign="top">グループを記述ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã€‚グループã¯ã€1ã¤ã¾ãŸã¯è¤‡æ•°ã®ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª エントリã®é›†ã¾ã‚Šã§ã™ã€‚例ãˆã°ã€ã‚·ã‚¹ãƒ†ãƒ ç®¡ç†è€…ã®ã‚°ãƒ«ãƒ¼ãƒ—ã€ãƒ†ã‚¯ãƒ‹ã‚«ãƒ«ãƒ©ã‚¤ã‚¿ãƒ¼ã®ã‚°ãƒ«ãƒ¼ãƒ—ã€é‡£ã‚Šã«èˆˆå‘³ã®ã‚る全ユーザã®ã‚°ãƒ«ãƒ¼ãƒ—ãªã©ã‚’サイトã§å®šç¾©ã§ãã¾ã™ã€‚グループã¯å¿…ãšã—もユーザã®é›†ã¾ã‚Šã§ã‚ã‚‹å¿…è¦ã¯ã‚ã‚Šã¾ã›ã‚“。例ãˆã°ã€ã‚µã‚¤ãƒˆã«ãŠã‘ã‚‹ã™ã¹ã¦ã®ã‚«ãƒ©ãƒ¼ プリンタやファクシミリã®ã‚°ãƒ«ãƒ¼ãƒ—ãªã©ã‚’定義ã§ãã¾ã™ã€‚ã¾ãŸã€ã‚°ãƒ«ãƒ¼ãƒ—ã«ä»–ã®ã‚°ãƒ«ãƒ¼ãƒ—ã‚’å«ã‚ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</td>
+ </tr>
+ <tr>
+ <td>NTグループ</td>
+ <td>NTユーザã®ã‚°ãƒ«ãƒ¼ãƒ—を記述ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã€‚</td>
+ </tr>
+ <tr>
+ <td valign="top">組織</td>
+ <td valign="top">組織を記述ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã€‚一般ã«ã€çµ„ç¹”ã¯ã€ä¼æ¥­ã‚„大学ãªã©ã®å˜ä¸€ã®å¤§è¦æ¨¡ã®çµ„織を表ã—ã¾ã™ã€‚通常ã¯ãƒ¦ãƒ¼ã‚¶ã‚„デãƒã‚¤ã‚¹ã®é›†ã¾ã‚Šã§ã‚るグループã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«å®Ÿä½“ãŒè¿½åŠ ã¾ãŸã¯å‰Šé™¤ã•ã‚Œã‚‹ã¨å¤‰åŒ–ã™ã‚‹ã“ã¨ãŒã‚ã‚Šã€ã“ã®ç‚¹ã§çµ„ç¹”ã¯ã‚°ãƒ«ãƒ¼ãƒ—ã¨ã¯ç•°ãªã‚Šã¾ã™ã€‚ã“ã‚Œã«å¯¾ã—ã¦çµ„ç¹”ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã®æ¯”較的安定ã—ãŸä¸»è¦éƒ¨åˆ†ã¾ãŸã¯ãƒ–ランãƒã‚’表ã—ã¾ã™ã€‚組織エントリã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªå†…ã§ã®ã‚¨ãƒ³ãƒ†ã‚£ãƒ†ã‚£ã®è¿½åŠ ã‚„削除ã«ã‚ˆã£ã¦å½±éŸ¿ã‚’å—ã‘ã‚‹ã“ã¨ã¯ã‚ã¾ã‚Šã‚ã‚Šã¾ã›ã‚“。</td>
+ </tr>
+ <tr>
+ <td valign="top">組織å˜ä½</td>
+ <td valign="top">組織å˜ä½ã‚’記述ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã€‚一般ã«ã€çµ„ç¹”å˜ä½ã¯ã€æ¯”較的大ããªçµ„織内ã§ã®ä¸»è¦éƒ¨é–€ã‚’表ã—ã¾ã™ã€‚ä¼æ¥­ã‚„大学ãªã©ã®å˜ä¸€ã®å¤§è¦æ¨¡ãªçµ„織エントリã¨ã¯ç•°ãªã‚Šã€çµ„ç¹”å˜ä½ã¯ã€ä¼šè¨ˆéƒ¨ã€è²©å£²éƒ¨ã€äººæ–‡å­¦éƒ¨ã€ç”Ÿç‰©å­¦éƒ¨ãªã©ã€ã‚ˆã‚Šå°ã•ãªçµ„織を表ã—ã¾ã™ã€‚</td>
+ </tr>
+ <tr>
+ <td valign="top">ä»»æ„ã®ã‚¿ã‚¤ãƒ—</td>
+ <td valign="top">ディレクトリ内ã§æ¤œç´¢åŸºæº–ã«ä¸€è‡´ã™ã‚‹ä»»æ„ã®ã‚¿ã‚¤ãƒ—ã®ã‚¨ãƒ³ãƒˆãƒªã€‚ä»»æ„ã®ã‚¿ã‚¤ãƒ—ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªå†…ã®ã‚¨ãƒ³ãƒˆãƒªãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã«ã‚ˆã£ã¦ã©ã®ã‚ˆã†ã«æŒ‡å®šã•ã‚Œã¦ã„ã‚‹ã‹ä¸æ˜Žãªå ´åˆã«ä½¿ç”¨ã—ã¾ã™ã€‚検索ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒª タイプãŒãƒ¦ãƒ¼ã‚¶ã€ã‚°ãƒ«ãƒ¼ãƒ—ã€çµ„ç¹”ã®ã„ãšã‚Œã§ã‚‚ãªã„å ´åˆã«ã¯ã€ä»»æ„ã®ã‚¿ã‚¤ãƒ—ãŒä¾¿åˆ©ã§ã™ã€‚</td>
+ </tr>
+</table>
+
+<p>Directory ServerãŒæ¤œç´¢ã‚’完了ã—ãŸå¾Œã€ä¸€è‡´ã—ãŸã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªã¸ã®ãƒªãƒ³ã‚¯ã‚’示ã™<a href="#results">検索çµæžœ</a>ãŒã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã«ã‚ˆã£ã¦è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚検索çµæžœãƒªã‚¹ãƒˆã«è¡¨ç¤ºã•ã‚Œã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’クリックã™ã‚‹ã¨ã€ãã®ã‚¨ãƒ³ãƒˆãƒªã«é–¢ã™ã‚‹è©³ç´°æƒ…å ±ãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚エントリãŒãƒ¦ãƒ¼ã‚¶ã®å ´åˆã€<a href="#vCard">ãã®ãƒ¦ãƒ¼ã‚¶ã®ãƒ‡ã‚¸ã‚¿ãƒ«å刺ã€ã¤ã¾ã‚ŠvCardを表示</a>ã™ã‚‹ã‚ˆã†ã«é¸æŠžã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚vCardを使用ã™ã‚‹ã¨ã€ãƒœã‚¿ãƒ³ã‚’クリックã™ã‚‹ã ã‘ã§ã€ãƒ¦ãƒ¼ã‚¶ã‚’Communicatorã®ã‚¢ãƒ‰ãƒ¬ã‚¹å¸³ã«ç°¡å˜ã«è¿½åŠ ã§ãã¾ã™ã€‚</p>
+
+<h2><a name="standard"></a>標準検索</h2>
+
+<p>標準検索ã¯ã€æŒ‡å®šã•ã‚ŒãŸãƒ‡ãƒ¼ã‚¿ã®æ€§è³ªã«ã‚ˆã£ã¦ç•°ãªã‚‹ã‚¿ã‚¤ãƒ—ã®æ¤œç´¢ã‚’実行ã—ã¾ã™ã€‚ã¤ã¾ã‚Šã€æ¤œç´¢ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«å…¥åŠ›ã—ãŸå†…容ã«ã‚ˆã£ã¦ã€ä¸€è‡´ã™ã‚‹<a href="#Name">æ°å</a>ã€<a href="#phone">電話番å·</a>ã€<a href="#email">é›»å­ãƒ¡ãƒ¼ãƒ« アドレス</a>ãªã©ã®æ¤œç´¢ãŒã§ãã¾ã™ã€‚</p>
+
+<p>入力ã—ãŸå†…容ã«å¿œã˜ã¦ã€æ¨™æº–検索ã§ã¯ã€åŸºæº–ã«å®Œå…¨ã«ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã€åŸºæº–ã‚’å«ã‚€ã‚¨ãƒ³ãƒˆãƒªã€åŸºæº–ã«é¡žä¼¼ã—ãŸéŸ³ã®èªžã‚’å«ã‚€ã‚¨ãƒ³ãƒˆãƒªã®ã„ãšã‚Œã‚’検索ã™ã‚‹ã‹ãŒåˆ¤å®šã•ã‚Œã¾ã™ã€‚ã¾ãŸã€[標準検索] フィールド㫠LDAP (Lightweight Directory Access Protocol) <a href="#filter">検索フィルタ</a>を指定ã—ã¦æ¤œç´¢ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</p>
+
+<h3><a name="Performing a Standard Search"></a>標準検索ã®å®Ÿè¡Œ</h3>
+
+<ol>
+ <li>[標準検索] タブをクリックã—ã¾ã™ã€‚</li>
+ <li>[検索] ã®ãƒ‰ãƒ­ãƒƒãƒ—ダウン リストã‹ã‚‰ã€æ¤œç´¢ã—ãŸã„<a href="#type">エントリ タイプ</a>ã‚’é¸æŠžã—ã¾ã™ã€‚</li>
+ <li>[検索対象] フィールドã«ã€æ¤œç´¢ã—ãŸã„値を入力ã—ã¾ã™ã€‚[検索対象] フィールドã¯å¤§æ–‡å­—/å°æ–‡å­—を区別ã—ã¾ã›ã‚“。以下ã®ã„ãšã‚Œã§ã‚‚入力ã§ãã¾ã™ã€‚
+ <ul type="disc">
+ <li><a href="#Name">æ°å</a>ã¾ãŸã¯æ°åã®ä¸€éƒ¨</li>
+ <li>ユーザã®<a href="#initials">イニシャル</a> </li>
+ <li><a href="#phone">電話番å·</a>ã®ä¸€éƒ¨ã¾ãŸã¯å…¨éƒ¨
+ </li>
+ <li><a href="#email">é›»å­ãƒ¡ãƒ¼ãƒ« アドレス</a>ã®ä¸€éƒ¨ã¾ãŸã¯å…¨éƒ¨</li>
+ <li>LDAP <a href="#filter">検索フィルタ</a></li>
+ </ul>
+ </li>
+ <li>[é€ä¿¡] をクリックã—ã¾ã™ã€‚<br>
+ フォーム データをDirectory Serverã«é€ä¿¡ã™ã‚‹ã¨ã€å…¥åŠ›ã—ãŸå€¤ã«å®Œå…¨ä¸€è‡´ã€éƒ¨åˆ†ä¸€è‡´ã€ã¾ãŸã¯é¡žä¼¼ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚一致çµæžœã¯ã€<a href="#results">検索çµæžœ</a>テーブルã«è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</li>
+</ol>
+
+<h4><a name="Name"></a>æ°åを検索ã™ã‚‹</h4>
+
+<p>以下ã®ã‚ˆã†ãªæ–‡å­—列を指定ã—ãŸå ´åˆ:</p>
+
+<ul>
+ <li>数字以外ã®æ–‡å­—ã‚’å«ã‚€</li>
+ <li>アット (@) 記å·ã‚’å«ã¾ãªã„</li>
+</ul>
+
+<p>標準検索ã§ã¯ã€æŒ‡å®šã—ãŸå€¤ã«å®Œå…¨ä¸€è‡´ã€éƒ¨åˆ†ä¸€è‡´ã€ã¾ãŸã¯é¡žä¼¼ã™ã‚‹æ°åã€åã€åå­—ã®æ¤œç´¢ãŒè©¦ã¿ã‚‰ã‚Œã¾ã™ã€‚</p>
+
+<p>例ãˆã°ã€æ–‡å­—列「<font face="Courier">son</font>ã€ã‚’指定ã™ã‚‹ã¨ã€ä»¥ä¸‹ã®ã‚ˆã†ãªçµæžœãŒæˆ»ã•ã‚Œã¾ã™ã€‚</p>
+
+<p>
+<ul>
+ <li>Gary Stevenson</li>
+ <li>Mary Sun</li>
+ <li>Allison Barker</li>
+</ul>
+
+<h4><a name="initials"></a>イニシャルを伴ãªã†æ°åを検索ã™ã‚‹</h4>
+
+<p>以下ã®é †åºã§ä»¥ä¸‹ã®é …目をå«ã‚€å€¤ã‚’指定ã—ãŸå ´åˆ:</p>
+
+<ol>
+ <li>1文字</li>
+ <li>スペース ( )ã€ãƒ”リオド (.)ã€ã¾ãŸã¯ãƒ”リオドã¨ã‚¹ãƒšãƒ¼ã‚¹ã‚’ä»»æ„ã®é †åºã§</li>
+ <li>1ã¤ã¾ãŸã¯è¤‡æ•°ã®æ–‡å­—</li>
+</ol>
+
+標準検索ã§ã¯ã€åを表ã™ã‚¤ãƒ‹ã‚·ãƒ£ãƒ«ã®å¾Œã«åå­—ãŒç¶šãã‚‚ã®ãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚例ãˆã°ã€æ–‡å­—列「S.Andersonã€ã‚’指定ã™ã‚‹ã¨ã€ä»¥ä¸‹ã®ã‚ˆã†ãªçµæžœãŒæˆ»ã•ã‚Œã¾ã™ã€‚</p>
+
+<ul>
+ <li>Sally Anderson</li>
+ <li>Steve Anderson</li>
+ <li>Sue Anderson</li>
+</ul>
+
+<p>åŒæ§˜ã«ã€ä»¥ä¸‹ã®é †åºã§ä»¥ä¸‹ã®é …目をå«ã‚€å€¤ã‚’指定ã—ãŸå ´åˆ:</p>
+
+<ol>
+ <li>複数ã®æ–‡å­—</li>
+ <li>スペース ( )ã€ãƒ”リオド (.)ã€ã¾ãŸã¯ãƒ”リオドã¨ã‚¹ãƒšãƒ¼ã‚¹ã‚’ä»»æ„ã®é †åºã§</li>
+ <li>1文字</li>
+</ol>
+
+<p>標準検索ã§ã¯ã€åã®å¾Œã«å字を表ã™ã‚¤ãƒ‹ã‚·ãƒ£ãƒ«ãŒç¶šãã‚‚ã®ãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚例ãˆã°ã€æ–‡å­—列「<font face="Courier New"></font>Mark
+.Pã€ã‚’指定ã™ã‚‹ã¨ã€ä»¥ä¸‹ã®ã‚ˆã†ãªçµæžœãŒæˆ»ã•ã‚Œã¾ã™ã€‚</p>
+
+<ul>
+ <li>Mark Payne</li>
+ <li>Mark Peck</li>
+ <li>Mark Polk</li>
+</ul>
+
+<blockquote>
+ <p><b>注: </b></p>
+ <p>イニシャルを使用ã—ãŸå ´åˆã€æ¨™æº–検索ã§ã¯å®Œå…¨ä¸€è‡´ã®æ¤œç´¢ã ã‘ãŒå®Ÿè¡Œã•ã‚Œã¾ã™ã€‚検索ã§æŒ‡å®šã—ãŸé€šã‚Šã®ã‚¤ãƒ‹ã‚·ãƒ£ãƒ«ã¨åå‰ã‚’æŒã¤ã‚¨ãƒ³ãƒˆãƒªã®ã¿ãŒæˆ»ã•ã‚Œã¾ã™ã€‚é¡žä¼¼ (発音ãŒä¼¼ã¦ã„ã‚‹) 検索ã¨å‰¯æ–‡å­—列検索ã¯å®Ÿè¡Œã•ã‚Œã¾ã›ã‚“。</p>
+</blockquote>
+
+<h4><a name="phone"></a>電話番å·ã‚’検索ã™ã‚‹</h4>
+
+<p>標準検索ã§ã¯ã€å…¥åŠ›ã—ãŸå€¤ãŒæ•°å­—ã ã‘ã‹ã‚‰æˆã‚‹å ´åˆã€é›»è©±ç•ªå·ãŒè‡ªå‹•çš„ã«æ¤œç´¢ã•ã‚Œã¾ã™ã€‚å°‘ãªãã¨ã‚‚1ã¤ã®æ•°å­—ã®å¾Œã«ç¶šã1ã¤ã®ãƒã‚¤ãƒ•ãƒ³ (-) を使用ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚</p>
+
+<p>ã“ã®ã‚¿ã‚¤ãƒ—ã®æ¤œç´¢ã¯ã€ã€Œçµ‚了文字ã€æ¤œç´¢ã§ã™ã€‚ã¤ã¾ã‚Šã€Directory Serverã¯æŒ‡å®šã•ã‚ŒãŸå€¤ã§çµ‚了ã™ã‚‹é›»è©±ç•ªå·ã‚’検索ã—ã¾ã™ã€‚例ãˆã°ã€å€¤<tt>123</tt>を入力ã—ãŸå ´åˆã€123ã§çµ‚了ã™ã‚‹ã™ã¹ã¦ã®é›»è©±ç•ªå·ãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚</p>
+
+<h4><a name="email"></a>é›»å­ãƒ¡ãƒ¼ãƒ« アドレスを検索ã™ã‚‹</h4>
+
+<p>標準検索ã§ã¯ã€å…¥åŠ›ã—ãŸå€¤ã«ã‚¢ãƒƒãƒˆ (@) 記å·ãŒå«ã¾ã‚Œã‚‹å ´åˆã€ä¸€è‡´ã™ã‚‹é›»å­ãƒ¡ãƒ¼ãƒ« アドレスãŒè‡ªå‹•çš„ã«æ¤œç´¢ã•ã‚Œã¾ã™ã€‚ã¾ãšã€å…¥åŠ›å€¤ã«å®Œå…¨ã«ä¸€è‡´ã™ã‚‹é›»å­ãƒ¡ãƒ¼ãƒ« アドレスãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚一致エントリãŒè¦‹ã¤ã‹ã‚‰ãªã‹ã£ãŸå ´åˆã¯ã€å…¥åŠ›å€¤ã§é–‹å§‹ã•ã‚Œã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚</p>
+
+<p>例ãˆã°ã€æ–‡å­—列「<font face="Courier">son@</font>ã€ã‚’指定ã™ã‚‹ã¨ã€æ¬¡ã®ã‚ˆã†ãªçµæžœãŒæˆ»ã•ã‚Œã¾ã™ã€‚</p>
+
+<ul>
+ <li>son@</li>
+</ul>
+ã¾ãŸã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªå†…ã§ä¸€è‡´ã‚¨ãƒ³ãƒˆãƒªãŒè¦‹ã¤ã‹ã‚‰ãªã‹ã£ãŸå ´åˆã¯ã€æ¬¡ã®ã‚ˆã†ãªçµæžœãŒæˆ»ã•ã‚Œã¾ã™ã€‚
+<ul>
+ <li>son@aardvark.org</li>
+ <li>son@acme.com</li>
+</ul>
+
+<h4><a name="filter"></a>検索フィルタを使用ã™ã‚‹</h4>
+
+<p>標準検索ã«æ­£ã—ã„検索ã®ã‚¿ã‚¤ãƒ—を判定ã•ã›ã‚‹ä»£ã‚Šã«ã€LDAP検索フィルタを明示的ã«æŒ‡å®šã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚LDAP検索フィルタを使用ã™ã‚‹ã¨ã€ç‰¹å®šã®<a HREF="attribut.htm">属性</a>値を対象ã«ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã§ãã¾ã™ã€‚標準検索ã§ã¯ã€ç­‰å·è¨˜å· (=) ã‚’å«ã‚€æ–‡å­—列ã¯ã™ã¹ã¦LDAP検索フィルタã§ã‚ã‚‹ã¨ã¿ãªã•ã‚Œã¾ã™ã€‚例ãˆã°ã€</p>
+
+<pre>cn=*eve*</pre>
+
+<p>ã¯LDAP検索フィルタã§ã‚ã‚Šã€æ–‡å­—列<tt>eve</tt>ã‚’å«ã‚€ä¸€èˆ¬å (common name - CN) を探ã™å‰¯æ–‡å­—列検索を実行ã—ã¾ã™ã€‚LDAP検索フィルタ内ã§å±žæ€§ã‚’指定ã™ã‚‹ã¨ãã€Directory Serverã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã§è¡¨ç¤ºã•ã‚Œã‚‹å±žæ€§ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰åã§ã¯ãªãã€Directory Server内部ã§ä½¿ç”¨ã•ã‚Œã‚‹å±žæ€§ãƒ©ãƒ™ãƒ« (内部ID) を使用ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。例ãˆã°ã€[æ°å] 属性フィールドã®å†…部IDã¯ã€<TT>cn</TT>ã§ã™ã€‚標準検索ã§æ¤œç´¢ãƒ•ã‚£ãƒ«ã‚¿ã‚’入力ã™ã‚‹ã«ã¯ã€æ¬¡ã®ã‚ˆã†ã«ã€å±žæ€§ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰å (æ°å) ã§ã¯ãªãã€å†…部ID (commonName) を使用ã—ã¦ãã ã•ã„。
+</P>
+<P><TT>commonName=Smith Fukuda</TT></P>
+
+<P>属性フィールドã®ä¸­ã«ã¯ã€ç¬¬äºŒã®çœç•¥å½¢ã®å†…部IDã‚’æŒã¤ã‚‚ã®ãŒã‚ã‚Šã¾ã™ã€‚例ãˆã°ã€[æ°å] フィールドã«ã¯ã€commonNameã¨cnã®2ã¤ã®å†…部IDãŒã‚ã‚Šã¾ã™ã€‚検索フィルタã§ã¯ã€ã“れらã®ã„ãšã‚Œã§ã‚‚使用ã§ãã¾ã™ã€‚</p>
+
+<p>検索フィルタã®è©³ç´°ã¯ã€ã€Ž<em>Directory Server管ç†è€…用ガイド</em>ã€ã‚’å‚ç…§ã—ã¦ãã ã•ã„。</p>
+
+<h2><a name="advanced"></a>拡張検索</h2>
+
+<p>拡張検索を使用ã—ã¦ã€ç‰¹å®šã®å±žæ€§ãŒæŒ‡å®šã®å€¤ã‚’æŒã¤ã‚ˆã†ãªã‚¨ãƒ³ãƒˆãƒªã‚’検索ã§ãã¾ã™ã€‚例ãˆã°ã€æŒ‡å®šã—ãŸå€¤ã®é›»å­ãƒ¡ãƒ¼ãƒ« アドレスをæŒã¤ãƒ¦ãƒ¼ã‚¶ã‚’検索ã§ãã¾ã™ã€‚ã¾ãŸã€æŒ‡å®šã—ãŸå±žæ€§å€¤ã‚’<i>å«ã¾ãªã„</i>エントリを検索ã™ã‚‹ã“ã¨ã‚‚ã§ãã¾ã™ã€‚例ãˆã°ã€åå­—ãŒSmithã§ãªã„ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ã‚’検索ã§ãã¾ã™ (ã“ã®ã‚ˆã†ãªæ¤œç´¢ã§ã¯å¤§é‡ã®çµæžœãŒæˆ»ã•ã‚Œã‚‹ãŸã‚ã€ã“ã®ç¨®ã®æ¤œç´¢ã®å®Ÿè¡Œã¯é¿ã‘ã¦ãã ã•ã„)。</p>
+
+<p>拡張検索ã§ã¯ã€å…¥åŠ›ã—ãŸèªžã«å®Œå…¨ã«ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªã‚’戻ã™å®Œå…¨ä¸€è‡´æ¤œç´¢ãŒè¡Œã‚ã‚Œã¾ã™ã€‚検索を構築ã™ã‚‹ãŸã‚ã® [拡張検索] フォームã«ã¯ã€4ã¤ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ãŒã‚ã‚Šã¾ã™ã€‚ã“れら4ã¤ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã‚ˆã£ã¦ã€æ¤œç´¢ã‚’指定ã™ã‚‹æ–‡ãŒç¤ºã•ã‚Œã¾ã™ã€‚一般ã«ã€ã“ã®æ–‡ã®ã¯æ¬¡ã®ã‚ˆã†ã«æ§‹æˆã•ã‚Œã¾ã™ã€‚</p>
+
+<p><a href="#type">検索:</a><i> [エントリ タイプ] </i><a
+href="search.htm#wherethe">ãŸã ã—:</a><i> [属性] </i><a
+href="search.htm#typeofsearch">[検索タイプ]</a><i> [検索文字列]</i></p>
+
+<p>ã“れらã®æœ€åˆã®3ã¤ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã®ã‚ªãƒ—ションã¯ãƒ—ルダウン メニューã§é¸æŠžã§ãã¾ã™ã€‚最後ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã«ã¯ã€å®Ÿéš›ã®æ¤œç´¢æ–‡å­—列を入力ã—ã¾ã™ã€‚例ãˆã°ã€æ¬¡ã®ã‚ˆã†ã«æ¤œç´¢ã‚’構築ã§ãã¾ã™ã€‚</p>
+
+<p><b>検索:</b><i> </i>[ユーザ]<i> </i><b>ãŸã ã—: </b>[åå­—] [is (一致)] [Bowker]</p>
+
+<p>ã¾ãŸã¯ã€æ¬¡ã®ã‚ˆã†ã«æ¤œç´¢ã‚’構築ã§ãã¾ã™ã€‚</p>
+
+<p><b>検索: </b>[ユーザ] <b>ãŸã ã—: </b>[æ°å] [sounds like (é¡žä¼¼)] [tree]</p>
+
+<h3><a name="Performing an Advanced Search"></a>拡張検索ã®å®Ÿè¡Œ</h3>
+
+<ol>
+ <li>[拡張検索] タブをクリックã—ã¾ã™ã€‚</li>
+ <li>[検索] ã®ãƒ‰ãƒ­ãƒƒãƒ—ダウン リストã‹ã‚‰ã€æ¤œç´¢ã—ãŸã„<a href="#type">エントリ タイプ</a>ã‚’é¸æŠžã—ã¾ã™ã€‚</li>
+ <li>[ãŸã ã—] フィールドã®ãƒ‰ãƒ­ãƒƒãƒ—ダウン リストã‹ã‚‰ã€æ¤œç´¢ã—ãŸã„属性をé¸æŠžã—ã¾ã™ã€‚é¸æŠžè‚¢ã¯ã€[検索] フィールドã§é¸æŠžã—ãŸã‚¨ãƒ³ãƒˆãƒª タイプã«ã‚ˆã£ã¦ç•°ãªã‚Šã¾ã™ã€‚下表ã«ã€é¸æŠžå¯èƒ½ãªã‚ªãƒ—ションã¨ãã®èª¬æ˜Žã‚’示ã—ã¾ã™ã€‚<br>
+<P>
+ <table border="2">
+ <tr>
+ <th><a name="wherethe"></a><b>[検索]フィールドã®å†…容. . .</b></th>
+ <th><b>é¸æŠžè‚¢. . .</b></th>
+ </tr>
+ <tr>
+ <td>ユーザã¾ãŸã¯NTユーザ</td>
+ <td><a HREF="attribut.htm#cn">æ°å</a>ã€
+ <a HREF="attribut.htm#sn">åå­—</a>ã€<a
+ HREF="attribut.htm#telephoneNumber">電話番å·</a>ã€
+ <a HREF="attribut.htm#mail">é›»å­ãƒ¡ãƒ¼ãƒ« アドレス</a>ã€<a
+ HREF="attribut.htm#uid">ユーザID</a>ã€ã¾ãŸã¯<a
+ HREF="attribut.htm#title">å½¹è·</a></td>
+ </tr>
+ <tr>
+ <td>グループã¾ãŸã¯NTグループ</td>
+ <td><a HREF="attribut.htm#description">記述</a>ã€
+ <a HREF="attribut.htm#owner">所有者</a>ã€ã¾ãŸã¯
+ <a HREF="attribut.htm#ntGroupType">NTグループ タイプ</a> (NTグループã®å ´åˆ)</td>
+ </tr>
+ <tr>
+ <td>組織</td>
+ <td><a HREF="attribut.htm#l">場所</a>ã€
+ <a HREF="attribut.htm#telephoneNumber">電話番å·
+ </a>ã€ã¾ãŸã¯<a HREF="attribut.htm#description">記述</a></td>
+ </tr>
+ <tr>
+ <td>ä»»æ„ã®ã‚¿ã‚¤ãƒ—</td>
+ <td><a HREF="attribut.htm#cn">å</a>ã¾ãŸã¯
+ <a HREF="attribut.htm#description">記述</a></td>
+ </tr>
+ </table>
+ </li>
+<P>
+ <li>実行ã—ãŸã„検索ã®ã‚¿ã‚¤ãƒ—ã‚’é¸æŠžã—ã¾ã™ã€‚<br>
+ <br>
+ 一般ã«ã€ã“ã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã¯ã€æ¤œç´¢ãŒç­‰å·æ¤œç´¢ã€å‰¯æ–‡å­—列検索ã€é¡žä¼¼
+ (発音ãŒä¼¼ã¦ã„ã‚‹) 検索ã®ã„ãšã‚Œã§ã‚ã‚‹ã‹ã‚’示ã—ã¾ã™ã€‚下表ã«ã€ä½¿ç”¨å¯èƒ½ãªå„キーワードã¨ã€ãã‚Œãžã‚ŒãŒè¡¨ã™æ¤œç´¢ã‚¿ã‚¤ãƒ—ã®å®šç¾©ã‚’示ã—ã¾ã™ã€‚ã“れらã®ã‚­ãƒ¼ãƒ¯ãƒ¼ãƒ‰ã®ã™ã¹ã¦ãŒå„検索ã§ä½¿ç”¨ã§ãã‚‹ã‚ã‘ã§ã¯ã‚ã‚Šã¾ã›ã‚“。実際ã«ä½¿ç”¨ã§ãるキーワードã¯ã€[検索] フィールド㨠[ãŸã ã—] フィールドã§é¸æŠžã—ãŸå€¤ã«ã‚ˆã£ã¦ç•°ãªã‚Šã¾ã™ã€‚以下ã®ã„ãšã‚Œã‹1ã¤ã‚’é¸æŠžã§ãã¾ã™ã€‚
+<p>
+ <table border="2">
+ <tr>
+ <th><a name="typeofsearch"></a><b>検索タイプ</b></th>
+ <th><b>説明</b></th>
+ </tr>
+ <tr>
+ <td>is (一致)</td>
+ <td>完全一致ãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚ã¤ã¾ã‚Šã€ã“ã®ã‚ªãƒ—ションã¯ç­‰å·æ¤œç´¢ã‚’指定ã—ã¾ã™ã€‚エントリã®å±žæ€§ã®å®Œå…¨ãªå€¤ãŒåˆ†ã‹ã£ã¦ã„ã‚‹å ´åˆã«ã“ã®ã‚ªãƒ—ションを使用ã—ã¾ã™ã€‚例ãˆã°ã€ãƒ¦ãƒ¼ã‚¶ã®åå­—ã®å®Œå…¨ãªã‚¹ãƒšãƒ«ãŒåˆ†ã‹ã£ã¦ã„ã‚‹å ´åˆã«ä½¿ç”¨ã—ã¾ã™ã€‚</td>
+ </tr>
+ <tr>
+ <td>is not (ä¸ä¸€è‡´)</td>
+ <td>検索文字列ã«å®Œå…¨ã«ä¸€è‡´ã—ãªã„属性値をæŒã¤ã‚¨ãƒ³ãƒˆãƒªãŒã™ã¹ã¦æˆ»ã•ã‚Œã¾ã™ã€‚例ãˆã°ã€åå­—ãŒSmithã§ãªã„ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶ã‚’ディレクトリã§æ¤œç´¢ã™ã‚‹å ´åˆã«ã“ã®ã‚ªãƒ—ションを使用ã—ã¾ã™ã€‚ãŸã ã—ã€ã“ã®ã‚ªãƒ—ションを使用ã™ã‚‹ã¨ã€å¤§é‡ã®ã‚¨ãƒ³ãƒˆãƒªãŒæˆ»ã•ã‚Œã‚‹ã“ã¨ãŒã‚ã‚‹ã®ã§æ³¨æ„ã—ã¦ãã ã•ã„。</td>
+ </tr>
+ <tr>
+ <td>sounds like (é¡žä¼¼)</td>
+ <td>発音ã«å³ã—ãŸæ¤œç´¢ãŒå®Ÿè¡Œã•ã‚Œã¾ã™ã€‚属性値ã¯åˆ†ã‹ã£ã¦ã„ã‚‹ãŒã€ã‚¹ãƒšãƒ«ãŒä¸æ˜Žã®å ´åˆã«ã“ã®ã‚ªãƒ—ションを使用ã—ã¾ã™ã€‚例ãˆã°ã€ãƒ¦ãƒ¼ã‚¶ã®åå­—ã®ã‚¹ãƒšãƒ«ãŒSarretã€Saretteã€Sarettã®ã„ãšã‚Œã§ã‚ã‚‹ã‹ä¸æ˜Žã®å ´åˆã«ä½¿ç”¨ã—ã¾ã™ã€‚</td>
+ </tr>
+ <tr>
+ <td>starts with (開始文字)</td>
+ <td>副文字列検索ãŒå®Ÿè¡Œã•ã‚Œã¾ã™ã€‚指定ã—ãŸæ¤œç´¢æ–‡å­—列ã§é–‹å§‹ã™ã‚‹å€¤ã‚’æŒã¤å±žæ€§ãŒæˆ»ã•ã‚Œã¾ã™ã€‚例ãˆã°ã€ãƒ¦ãƒ¼ã‚¶ã®åãŒSteveã§ã‚ã‚‹ã¨åˆ†ã‹ã£ã¦ã„ã‚‹ãŒã€åå­—ãŒä¸æ˜Žã®å ´åˆã«ã€ã“ã®ã‚ªãƒ—ションを使用ã—ã¦æ°åを検索ã§ãã¾ã™ã€‚</td>
+ </tr>
+ <tr>
+ <td>ends with (終了文字)</td>
+ <td>副文字列検索ãŒå®Ÿè¡Œã•ã‚Œã¾ã™ã€‚指定ã—ãŸæ¤œç´¢æ–‡å­—列ã§çµ‚了ã™ã‚‹å€¤ã‚’æŒã¤å±žæ€§ãŒæˆ»ã•ã‚Œã¾ã™ã€‚例ãˆã°ã€ãƒ¦ãƒ¼ã‚¶ã®é›»è©±ç•ªå·ã®æœ€å¾Œã®4æ¡ãŒ9876ã§ã‚ã‚‹ã¨åˆ†ã‹ã£ã¦ã„ã‚‹å ´åˆã«ã€ã“ã®ã‚ªãƒ—ションを使用ã—ã¦ãã®ãƒ¦ãƒ¼ã‚¶ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</td>
+ </tr>
+ <tr>
+ <td>contains (å«æœ‰)</td>
+ <td>副文字列検索ãŒå®Ÿè¡Œã•ã‚Œã¾ã™ã€‚指定ã—ãŸæ¤œç´¢æ–‡å­—列をå«ã‚€å€¤ã‚’æŒã¤å±žæ€§ãŒæˆ»ã•ã‚Œã¾ã™ã€‚例ãˆã°ã€çµ„ç¹”ã®è¨˜è¿°ã«ãŠãらãsupportã¨ã„ã†èªžãŒå«ã¾ã‚Œã‚‹ã¨æ€ã†å ´åˆã«ã€ã“ã®ã‚ªãƒ—ションã§æ¤œç´¢æ–‡å­—列「supportã€ã‚’使用ã—ã¦ãã®çµ„ç¹”ã®ã‚¨ãƒ³ãƒˆãƒªã‚’検索ã—ã¾ã™ã€‚</td>
+ </tr>
+ </table>
+ </li>
+<p>
+ <li>検索ã—ãŸã„文字列をテキストボックスã«å…¥åŠ›ã—ã€[検索] をクリックã—ã¾ã™ã€‚<br>
+ Directory Serverã«ãƒ•ã‚©ãƒ¼ãƒ  データをé€ä¿¡ã™ã‚‹ã¨ã€æŒ‡å®šã—ãŸå€¤ã«å®Œå…¨ã«ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒæ¤œç´¢ã•ã‚Œã¾ã™ã€‚一致çµæžœã¯æ¤œç´¢çµæžœãƒªã‚¹ãƒˆã¨ã—ã¦è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</li>
+</ol>
+
+<h3><a name="Advanced Search Examples"></a>拡張検索ã®ä¾‹</h3>
+
+<p>以下ã¯ã€[拡張検索]フォームã®ä½¿ç”¨ä¾‹ã§ã™ã€‚åž‚ç›´ãƒãƒ¼ (|) ã¯ãƒ•ã‚©ãƒ¼ãƒ ä¸Šã®ãƒ•ã‚£ãƒ¼ãƒ«ãƒ‰ã®åŒºåˆ‡ã‚Šã‚’表ã—ã¾ã™ã€‚</p>
+
+<table border="2">
+ <tr>
+ <th><b>検索項目. . .</b></th>
+ <th><b>入力内容. . .</b></th>
+ </tr>
+ <tr>
+ <td>Darleneã¨ã„ã†åã®ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶</td>
+ <td><b>検索:</b> ユーザ | <b>ãŸã ã—:</b> æ°å |
+ starts with (開始文字) | Darlene</td>
+ </tr>
+ <tr>
+ <td>åå­—ãŒSweeneyã®ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶</td>
+ <td><b>検索:</b> ユーザ | <b>ãŸã ã—:</b> åå­— |
+ is (一致) | Sweeny</td>
+ </tr>
+ <tr>
+ <td>Vice President (副社長) ã§ã‚ã‚‹ã™ã¹ã¦ã®ãƒ¦ãƒ¼ã‚¶</td>
+ <td><b>検索:</b> ユーザ | <b>ãŸã ã—:</b> å½¹è· |
+ contains (å«æœ‰) | Vice President</td>
+ </tr>
+ <tr>
+ <td>Accounting (会計) ã¨ã„ã†åå‰ã®çµ„ç¹”</td>
+ <td><b>検索:</b> 組織 | <b>ãŸã ã—:</b> åå‰ |
+ is (一致) | Accounting</td>
+ </tr>
+ <tr>
+ <td>Scuba Diving (スキューãƒãƒ€ã‚¤ãƒ“ング) ã«èˆˆå‘³ã®ã‚るグループ</td>
+ <td><b>検索:</b> グループ | <b>ãŸã ã—:</b> 記述 |
+ contains (å«æœ‰) | scuba</td>
+ </tr>
+ <tr>
+ <td>printerã¨ã„ã†èªžã‚’å«ã‚€åã‚’æŒã¤ã‚¨ãƒ³ãƒˆãƒª</td>
+ <td><b>検索:</b> ä»»æ„ã®ã‚¿ã‚¤ãƒ— | <b>ãŸã ã—:</b> åå‰ |
+ contains (å«æœ‰) | printer</td>
+ </tr>
+</table>
+
+<h2><a name="results"></a>検索çµæžœã®è¡¨ç¤º</h2>
+
+<p>標準検索ã¾ãŸã¯æ‹¡å¼µæ¤œç´¢ã‚’実行ã™ã‚‹ã¨ãã€æ¤œç´¢ãƒ‡ãƒ¼ã‚¿ãŒDirectory Serverインタフェースã«ã‚ˆã£ã¦Directory Serverã¸é€ä¿¡ã•ã‚Œã¾ã™ã€‚Directory Serverã§æ¤œç´¢ãŒå®Ÿè¡Œã•ã‚Œã€ä¸€è‡´ã—ãŸã‚¨ãƒ³ãƒˆãƒªãŒDirectory Serverã®ã‚¤ãƒ³ã‚¿ãƒ•ã‚§ãƒ¼ã‚¹ã¸æˆ»ã•ã‚Œã¾ã™ã€‚çµæžœã®è¡¨ç¤ºæ–¹æ³•ã¯ã€ä»¥ä¸‹ã®ã‚ˆã†ãªä¸€è‡´ã®ç¨®é¡žã«ã‚ˆã£ã¦ç•°ãªã‚Šã¾ã™ã€‚</p>
+
+<ul>
+ <li><a href="#nomatch">一致ãªã—</a></li>
+ <li><a href="#single">1件ã®ä¸€è‡´</a></li>
+ <li><a href="#multiple">複数ã®ä¸€è‡´</a></li>
+</ul>
+
+<p>ã“ã®ã‚»ã‚¯ã‚·ãƒ§ãƒ³ã§ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリーã§æ¤œç´¢ã‚’試ã¿ã‚‹ã¨ãã«é­é‡ã™ã‚‹<a href="#problems">ãã®ä»–ã®å•é¡Œ</a>ã«ã¤ã„ã¦ã‚‚説明ã—ã¦ã„ã¾ã™ã€‚</p>
+
+<h3><a name="nomatch"></a>一致ãªã—</h3>
+
+<p>検索çµæžœã¨ã—ã¦ä¸€è‡´ãªã—ãŒæˆ»ã•ã‚ŒãŸå ´åˆã€ä»¥ä¸‹ã®ã„ãšã‚Œã‹ã‚’æ„味ã—ã¾ã™ã€‚</p>
+
+<ul>
+ <li>検索基準ã«ä¸€è‡´ã™ã‚‹ã‚¨ãƒ³ãƒˆãƒªãŒãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªå†…ã«å­˜åœ¨ã—ãªã„ã“ã¨ã€‚ã“ã‚ŒãŒæ­£ã—ããªã„ã¨æ€ã‚れる場åˆã¯ã€ä»–ã®çµæžœãŒå¾—られるã‹ã©ã†ã‹ã€å¤šå°‘ç•°ãªã‚‹ãƒ‘ラメータを使用ã—ã¦åˆ¥ã®æ¤œç´¢ã‚’試ã¿ã¦ãã ã•ã„。</li>
+ <li>検索を実行ã™ã‚‹å‰ã«<a href="auth.htm#1016877">èªè¨¼</a>ã‚’è¡Œã‚ãªã‹ã£ãŸã“ã¨ã€‚èªè¨¼ã®å¿…è¦æ¡ä»¶ã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ãŒæ±ºå®šã—ã¾ã™ã€‚ディレクトリ管ç†è€…ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã«ã‚¢ã‚¯ã‚»ã‚¹åˆ¶å¾¡ã‚’設定ã™ã‚‹ã“ã¨ã«ã‚ˆã‚Šã€ãƒ„リーを検索ã™ã‚‹å‰ã«ãƒ¦ãƒ¼ã‚¶ãŒèªè¨¼ã—ãªã‘ã‚Œã°ãªã‚‰ãªã„よã†ã«ã§ãã¾ã™ã€‚アクセス制御ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª ツリー全体ã¾ãŸã¯ãƒ„リーã®ä¸€éƒ¨ã®ã¿ã‚’対象ã«è¨­å®šã§ãã¾ã™ã€‚ディレクトリ ツリーを検索ã™ã‚‹å‰ã«èªè¨¼ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã®ã«ã€æ¤œç´¢ã®å®Ÿè¡Œå‰ã«èªè¨¼ã—ãªã‹ã£ãŸå ´åˆã€Directory Serverã¯ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã§ä¸€è‡´ã‚¨ãƒ³ãƒˆãƒªãŒè¦‹ã¤ã‹ã‚‰ãªã‹ã£ãŸã‹ã®ã‚ˆã†ã«å‹•ä½œã—ã¾ã™ã€‚セキュリティã®ç†ç”±ã‹ã‚‰ã€èªè¨¼ãŒå¿…è¦ã§ã‚ã‚‹ã“ã¨ã‚’知らã›ã‚‹ãƒ¡ãƒƒã‚»ãƒ¼ã‚¸ã¯ã¾ã£ãŸã表示ã•ã‚Œã¾ã›ã‚“。検索ã®å®Ÿè¡Œå‰ã«Directory Serverã«èªè¨¼ã™ã‚‹å¿…è¦ãŒã‚ã‚‹ã‹ã©ã†ã‹ã¯ã€ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªç®¡ç†è€…ã«ãŠå°‹ã­ãã ã•ã„。èªè¨¼ã®è©³ç´°ã¯ã€ã€Œãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒªã¸ã®èªè¨¼ã€ã‚’å‚ç…§ã—ã¦ãã ã•ã„。</li>
+ <li>èªè¨¼ã®å¿…è¦æ€§ã«é–¢ã‚らãšã€ãƒ„リーã®ã‚¢ã‚¯ã‚»ã‚¹åˆ¶å¾¡ã«ã‚ˆã‚Šã€ã‚¨ãƒ³ãƒˆãƒªã®è¡¨ç¤ºãŒç¦æ­¢ã•ã‚Œã¦ã„ã‚‹ã“ã¨ã€‚</li>
+</ul>
+
+<h3><a name="single"></a>1件ã®ä¸€è‡´<b> </b></h3>
+
+<p>「is (一致)ã€æ¤œç´¢ã«å¯¾ã—ã¦1件ã ã‘ã®ä¸€è‡´ãŒæˆ»ã•ã‚ŒãŸå ´åˆã€Directory Serverインタフェースã«ã‚ˆã£ã¦ã€ãã®ã‚¨ãƒ³ãƒˆãƒªã«é–¢ã™ã‚‹æƒ…å ±ãŒæ¤œç´¢çµæžœã¨ã—ã¦è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚ã“ã®1件ã®ä¸€è‡´ãŒä»–ã®æ¤œç´¢æ–¹æ³•ã§ã‚‚見ã¤ã‹ã£ãŸå ´åˆã¯ãƒ†ãƒ¼ãƒ–ルã«è¡¨ç¤ºã•ã‚Œã‚‹ã®ã§ã€ãƒªãƒ³ã‚¯ã‚’クリックã—ã¦ãã®ã‚¨ãƒ³ãƒˆãƒªã®è©³ç´°æƒ…報を表示ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚ã“ã®ãƒ•ã‚©ãƒ¼ãƒ ã«ã¯ã€ã‚¨ãƒ³ãƒˆãƒªã‚’<a href="mod.htm">編集</a>ã™ã‚‹ãŸã‚ã®ãƒœã‚¿ãƒ³ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚エントリを編集ã™ã‚‹ã«ã¯é©åˆ‡ãªè¨±å¯ãŒå¿…è¦ã§ã™ã€‚ã¾ãŸã€ã‚¨ãƒ³ãƒˆãƒªã‚’編集ã™ã‚‹å‰ã«ã€<a href="auth.htm#userauth">èªè¨¼</a>ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚</p>
+
+<h3><a name="multiple"></a>複数ã®ä¸€è‡´<b> </b></h3>
+
+<p>検索ã«å¯¾ã—ã¦è¤‡æ•°ã®ä¸€è‡´ãŒæˆ»ã•ã‚ŒãŸå ´åˆã€Directory Serverインタフェースã«ã‚ˆã£ã¦ã€ä¸€è‡´ã—ãŸã™ã¹ã¦ã®ã‚¨ãƒ³ãƒˆãƒªã¨ã€å„エントリã®é–¢é€£æƒ…å ± (エントリã®é›»è©±ç•ªå·ã‚„é›»å­ãƒ¡ãƒ¼ãƒ«ã‚¢ãƒ‰ãƒ¬ã‚¹ãªã©) ãŒãƒ†ãƒ¼ãƒ–ルã«è¡¨ç¤ºã•ã‚Œã¾ã™ã€‚実際ã«è¡¨ç¤ºã•ã‚Œã‚‹æƒ…å ±ã¯ã€æ¤œç´¢ä¸­ã®ã‚¨ãƒ³ãƒˆãƒªã®ã‚¿ã‚¤ãƒ—ã«ã‚ˆã£ã¦æ±ºå®šã•ã‚Œã¾ã™ã€‚特定ã®ã‚¨ãƒ³ãƒˆãƒªã«ã¤ã„ã¦è©³ç´°ã‚’表示ã™ã‚‹ã«ã¯ã€ãƒ†ãƒ¼ãƒ–ルã®æœ€åˆã®åˆ—ã«ã‚るエントリã®åå‰ã‚’クリックã—ã¾ã™ã€‚</p>
+
+<h3><a name="problems"></a><b>ãã®ä»–ã®å•é¡Œ</b></h3>
+
+<p>数値を検索ã™ã‚‹å ´åˆã€å¥‡å¦™ãªçµæžœãŒè¡¨ç¤ºã•ã‚Œã‚‹ã“ã¨ãŒã‚ã‚Šã¾ã™ã€‚ã“ã‚Œã¯ã€Directory Serverã§ã¯ã€å®Ÿéš›ã«æ•°å€¤ (電話番å·ã‚„部屋番å·) ã§ã‚ã‚‹ã‹ã©ã†ã‹ã«é–¢ã‚ãšã€ã™ã¹ã¦ã®å€¤ãŒæ–‡å­—列ã¨ã—ã¦ä¿å­˜ã•ã‚Œã‚‹ãŸã‚ã§ã™ã€‚ã“ã®ãŸã‚ã€æ•°å€¤ã‚’検索ã™ã‚‹ã¨ãã¯ã€ã‚¹ãƒšãƒ¼ã‚¹ã‚„先行ã™ã‚‹ã‚¼ãƒ­ãŒã‚ã‚‹å ´åˆã€ãれらもã™ã¹ã¦å«ã‚るよã†ã«æ³¨æ„ã—ã¦ãã ã•ã„。</p>
+
+<p>ã¾ãŸã€Directory Serverインタフェースã«ã‚ˆã£ã¦ã€å…ˆè¡ŒãŠã‚ˆã³å¾Œç¶šã®ç©ºç™½ã‚¹ãƒšãƒ¼ã‚¹ãŒæ¤œç´¢åŸºæº–ã‹ã‚‰ã™ã¹ã¦é™¤åŽ»ã•ã‚Œã‚‹ã“ã¨ã«æ³¨æ„ã—ã¦ãã ã•ã„。実際ã«ãƒ‡ã‚£ãƒ¬ã‚¯ãƒˆãƒª エントリã®å€¤ã«å…ˆè¡Œã¾ãŸã¯å¾Œç¶šã®ç©ºç™½ã‚¹ãƒšãƒ¼ã‚¹ãŒå«ã¾ã‚Œã‚‹ã“ã¨ã¯ã»ã¨ã‚“ã©ã‚ã‚Šã¾ã›ã‚“ãŒã€å«ã¾ã‚Œã‚‹å ´åˆã‚‚ã‚ã‚Šã¾ã™ã€‚ã“ã®ãŸã‚ã«ã€å…ˆè¡Œã¾ãŸã¯å¾Œç¶šã®ç©ºç™½ã‚¹ãƒšãƒ¼ã‚¹ãŒå«ã¾ã‚Œã‚‹å€¤ã«å¯¾ã™ã‚‹å®Œå…¨ä¸€è‡´ã®æ¤œç´¢ãŒå¤±æ•—ã—ã¾ã™ã€‚ã“ã®å•é¡ŒãŒç™ºç”Ÿã—ãŸå ´åˆã¯ã€å®Œå…¨ä¸€è‡´æ¤œç´¢ã®ä»£ã‚ã‚Šã«ã€<a
+href="filters.htm#1018345">副文字列検索</a> (contains (å«æœ‰) 検索) を使用ã™ã‚‹ã¨è‰¯ã„ã§ã—ょã†ã€‚</p>
+
+<h2><a name="vCard"></a>vCardã®è¡¨ç¤º</h2>
+
+<p>vCardã¨ã¯ãƒ‡ã‚¸ã‚¿ãƒ«å¼ã®å刺ã§ã™ã€‚普通ã®å刺ã¨åŒæ§˜ã€vCardã«ã¯ã€ãƒ¦ãƒ¼ã‚¶ã®åå‰ã€å½¹è·ã€é›»è©±ãŠã‚ˆã³ãƒ•ã‚¡ãƒƒã‚¯ã‚¹ç•ªå·ã€é›»å­ãƒ¡ãƒ¼ãƒ« アドレスãªã©ã®é€£çµ¡å…ˆæƒ…å ±ãŒå«ã¾ã‚Œã¦ã„ã¾ã™ã€‚ãŸã ã—ã€æ™®é€šã®å刺ã¨ç•°ãªã‚Šã€vCardã«ã¯ã€ç”»åƒã€éŸ³å£°ã€ãƒ“デオãªã©ã®ãƒžãƒ«ãƒãƒ¡ãƒ‡ã‚£ã‚¢è¦ç´ ã‚‚å«ã‚ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚vCardを表示ã™ã‚‹ã«ã¯ã€ä»¥ä¸‹ã«å¾“ã£ã¦ãã ã•ã„。</p>
+
+<ol>
+ <li><a href="#standard">標準検索</a>ã¾ãŸã¯<a
+ href="#advanced">拡張検索</a>機能を使用ã—ã¦ã€è¡¨ç¤ºã—ãŸã„vCardã®æ‰€æœ‰è€…を検索ã—ã¾ã™ã€‚</li>
+ <li>[View Card] ボタンをクリックã—ã¾ã™ã€‚<br>
+ Directory Serverインタフェースã«ã‚ˆã£ã¦ã€vCardã®ç¸®å°ç‰ˆãŒè¡¨ç¤ºã•ã‚Œã¾ã™ã€‚</li>
+ <li>詳細を表示ã™ã‚‹ã«ã¯ã€[View
+ Complete Card] をクリックã—ã¾ã™ã€‚</li>
+ <li>Communicatorã®ã‚¢ãƒ‰ãƒ¬ã‚¹å¸³ã«ãã®ãƒ¦ãƒ¼ã‚¶ã‚’追加ã™ã‚‹ã«ã¯ã€
+ [Add to Address Book] をクリックã—㦠[OK] をクリックã—ã¾ã™ã€‚</li>
+</ol>
+</body>
+</html>
+
+
+
diff --git a/ldap/clients/dsgw/html/manual/mod.htm b/ldap/clients/dsgw/html/manual/mod.htm
new file mode 100644
index 00000000..1cb9e64d
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/mod.htm
@@ -0,0 +1,828 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Editing Directory Entries</TITLE>
+</HEAD>
+<BODY>
+
+<H1><A NAME="editing"></A>Editing Entries</H1>
+
+You can modify existing entries in
+the directory using the Directory Server interface. Modify an entry
+by <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm">searching for the entry</A>, <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">viewing
+it</A>, and then clicking the edit button.
+
+<P>If you have not <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticated</A> before
+you attempt to edit an entry, or if your authentication has expired, the
+Directory Server prompts you to authenticate before continuing.
+
+<P>You can edit:
+<UL>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#people">people</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#ntpeople">NT people</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#groups">groups</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#NTgroups">NT groups</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#o">organizations</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#dc">domains</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#ou">organizational units</A></LI>
+</UL>
+
+<H2>
+<A NAME="people"></A>Editing People</H2>
+To edit a person's entry, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit Person button.</LI>
+
+<LI>
+If you have not authenticated before you attempt to edit an entry, or if
+your authentication has expired, the Directory Server prompts you to
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+To edit the person's entry, type the value you desire for each
+field. You must supply values for the required fields. The required fields
+for a person are:</LI>
+
+<UL type="disc">
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#commonName">Full Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#surname">Last Name</A></LI>
+</UL>
+
+<LI>
+You can provide values for the optional fields now, or edit them later.
+The optional fields for a person are:</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#givenName">First Name</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#mail">Email Address</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#fax">Fax</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#userid">User ID </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#pager">Pager </A></TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#mobile">Mobile Phone</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#title">Title </A></TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#organizationalUnitName">Organizational Unit</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#manager">Manager</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#roomNumber">Room Number </A></TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#secretary">Admin </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#departmentNumber">Dept# </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#employeeNumber">Emp#</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#carLicnese">Car License# </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#labeledURI">URL </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#userPassword">Password</A> </TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+You may <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addmanager">add values to the Manager and Admin
+fields</A> by clicking the corresponding Edit button.</LI>
+
+<LI>
+You may <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addowner">add values to the See Also field</A>
+by clicking the corresponding Edit button.</LI>
+
+<LI>
+When you are done editing the fields, click Save Changes.</LI>
+</OL>
+From this window you can also:
+<UL>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#rename">Rename an entry</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#delete">Delete an entry</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#changepw">Change a password</A></LI>
+</UL>
+
+<H3><A NAME="addmanager"></A>Adding Values to the Manager and Admin Fields</H3>
+
+When you click the Edit button in the Manager or Admin field,
+a new form that allows you to add or delete the corresponding
+attribute value is displayed. To add an individual to the Manager or Admin attribute,
+do the following:
+<OL>
+<LI>
+In the text box, enter a search string to be used to locate the entry of
+the person who is the manager or admin. Enter any of the following:</LI>
+
+<UL type="disc">
+<LI>
+A name. Enter a full name or a partial name. All entries that equally match
+the search string are returned. If no such entries are found, all entries
+that contain the search string are returned. If no such entries are found,
+any entries that sound like the search string are returned.</LI>
+
+<LI>
+A user ID (if you are searching for user entries).</LI>
+
+<LI>
+A telephone number. If you enter only a partial number, any entries that
+have telephone numbers ending in the search number are returned.</LI>
+
+<LI>
+An email address. Any search string containing an at (@) symbol is assumed
+to be an email address. If an exact match cannot be found, then a search
+is performed to find all email addresses that begin with the search string.</LI>
+
+<LI>
+An asterisk (*) to see all of the entries or groups currently residing
+in your directory.</LI>
+
+<LI>
+Any <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#filter">LDAP search filter</A>. Any string that
+contains an equal sign (=) is considered to be a search filter.</LI>
+</UL>
+
+<LI>
+Click "Find and Add" to find the matching entry and add it to the
+list. If any entries that you do not want to designate as manager
+or admin are listed, click the box in the "Remove from list" column. You can
+also construct a search filter to match the entries you want removed and
+then click "Find and Remove."</LI>
+
+<LI>
+When the list of group members is complete, click Save Changes.
+The currently displayed entry is now the value for the manager or admin
+attribute field.</LI>
+</OL>
+
+<H2>
+<A NAME="ntpeople"></A>Editing NT People</H2>
+To edit an NT person's entry, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit NT Person button.</LI>
+
+<LI>
+If you have not authenticated before you attempt to edit an entry, or if
+your authentication has expired, the Directory Server prompts you to
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+To edit the person's entry, type in the new value for each
+field. You must supply values for the required fields. The required fields
+for an NT person are:</LI>
+
+<UL type="disc">
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#commonName">Full Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#surname">Last Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntUserDomainId">NT Domain Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#uid">NT User ID</A></LI>
+</UL>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for an NT person are:</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#givenName">First Name</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#mail">Email Address</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#fax">Fax </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#userPassword">Directory Server Password</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#pager">Pager</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#mobile">Mobile Phone</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#title">Title</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#organizationalUnitName">Organizational Unit</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#manager">Manager</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#roomNumber">Room Number</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#secretary">Admin </A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#departmentNumber">Dept#</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#employeeNumber">Emp#</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#carLicnese">Car License#</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#labeledURI">URL</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#userid">User Id</A> </TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+You can also change the value for the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntUserDeleteAccount">Delete
+NT Account if Person deleted</A> option.</LI>
+
+<LI>
+To <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addmanager">add values to the Manager and Admin
+fields</A>, click the corresponding Edit button.</LI>
+
+<LI>
+To <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addowner">add values to the See Also field</A>,
+click the corresponding Edit button.</LI>
+
+<LI>
+When you are done editing the fields, click Save Changes.</LI>
+</OL>
+From this window you can also:
+<UL>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#rename">Rename the entry</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#delete">Delete an entry</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#changepw">Change the password</A></LI>
+</UL>
+
+<H2><A NAME="groups"></A>Editing Groups</H2>
+
+To edit a group entry, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit Group button.</LI>
+
+<LI>
+If you have not authenticated before you attempt to edit an entry, or if
+your authentication has expired, the Directory Server prompts you to
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+To edit the group's entry, type the new value for each
+field. You must supply values for the required field,
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#name">Name</A>.
+
+<LI>
+You can provide values for the optional fields now, or edit them later.
+The optional fields for a group are:</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#owner">Owner</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#member">Group Members</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A></TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+To <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addowner">add values to the See Also, Owners, and Group
+Members fields</A> click the corresponding Edit button.</LI>
+
+<LI>
+When you are done editing the fields, click Save Changes.</LI>
+</OL>
+From this window you can also:
+<UL>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#rename">Rename the entry</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#delete">Delete an entry</A></LI>
+</UL>
+
+<H3><A NAME="addowner"></A>Adding Values to the Owner, See Also, and
+Group Member Fields</H3>
+
+When you click the Edit button for Owner, See Also, or Group
+Members, a new form that allows you to add or delete members is displayed.
+An owner, see also, or group member can be either an individual or a group.
+That is, if you add a group as an owner, see also, or group member, anyone
+belonging to the group becomes a member of the list. For example,
+if Barbara Jensen is a member of the Marketing Managers group, and you make
+the Marketing Managers group a member of the Marketing Personnel group,
+then Barbara Jensen is also a member of the Marketing Personnel group. To add
+members, owners, or see alsos, do the following:
+<OL>
+<LI>
+If you want to add user entries to the list, make sure People is shown
+in the first dialog box. If you want to add group entries to the group,
+make sure Group is shown.</LI>
+
+<LI>
+In the second dialog box, enter a search string. Enter any of the following:</LI>
+
+<UL type="disc">
+<LI>
+A name. Enter a full name or a partial name. All entries that equally match
+the search string are returned. If no such entries are found, all entries
+that contain the search string are found. If no such entries are found,
+any entries that sounds like the search string are returned.</LI>
+
+<LI>
+A user ID, (if you are searching for user entries).</LI>
+
+<LI>
+A telephone number. If you enter only a partial number, any entries that
+have telephone numbers ending in the search number are returned.</LI>
+
+<LI>
+An email address. Any search string containing an at (@) symbol is assumed
+to be an email address. If an exact match cannot be found, then a search
+is performed to find all email addresses that begin with the search string.</LI>
+
+<LI>
+An asterisk (*) to see all of the entries or groups currently residing
+in your directory.</LI>
+
+<LI>
+Any <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#filter">LDAP search filter</A>. Any string that
+contains an equal sign (=) is considered to be a search filter.</LI>
+</UL>
+
+<LI>
+Click "Find and Add" to find all the matching entries and add them
+to the list. If any entries are shown that you do not want to include in
+the list, click the box in the "Remove from list" column. You
+can also construct a search filter to match the entries you want removed
+and then click "Find and Remove."</LI>
+
+<LI>
+When the list of group members is complete, click Save Changes.
+The currently displayed entries now belong to the list.</LI>
+</OL>
+
+<H2>
+<A NAME="NTgroups"></A>Editing NT Groups</H2>
+To edit an NT group entry, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit NT Group button.</LI>
+
+<LI>
+If you have not authenticated before you attempt to edit an entry, or if
+your authentication has expired, the Directory Server prompts you to
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+To edit the group's entry, type in the value for each
+field. You must supply values for the required fields. The required fields
+for an NT group are:</LI>
+
+<UL type="disc">
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntGroupId">NT Group Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntGroupDomainId">NT Domain Name</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntGroupType">NT Group Type</A></LI>
+
+</UL>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for an NT group are:</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#owner">Owner</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#l">Locale</A></TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#uniqueMember">Group Members</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A></TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#organizationalUnitName">Organizational Unit</A></TD>
+</TR>
+</TABLE></CENTER>
+ 
+<LI>
+You can also change the value for the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#ntGroupDeleteGroup">Delete NT Group if Group Deleted</A> option.</LI>
+
+<LI>
+You can <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#addowner">add values to the See Also, Owners, and Group
+Members fields</A> by clicking the corresponding "Edit" button.</LI>
+
+<LI>
+When you are done editing, click Save Changes.</LI>
+</OL>
+From this window you can also:
+<UL>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#rename">Rename an entry</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#delete">Delete an entry</A></LI>
+</UL>
+
+<H2>
+<A NAME="ou"></A>Editing Organizational Units</H2>
+To edit an organizational unit, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit Organizational Unit button.</LI>
+
+<LI>
+If you have not authenticated before you attempt to edit an entry, or if
+your authentication has expired, the Directory Server prompts you to
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+To edit the organizational unit's entry, type in the value
+for each field. You must supply values for the required fields.</LI>
+
+<LI>
+The required field for an organizational unit is <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#organizationalUnitName">Unit Name</A>.</LI>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for an organizational unit are:</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#fax">Fax</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#localityName">Location</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A> </TD>
+
+<TD> </TD>
+
+<TD> </TD>
+</TR>
+</TABLE></CENTER>
+<P>
+<LI>
+When you are done editing, click Save Changes.</LI>
+</OL>
+From this window you can also:
+<UL>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#rename">Rename an entry</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#delete">Delete an entry</A></LI>
+</UL>
+
+<H2>
+<A NAME="dc"></A>Editing Domain Components</H2>
+To edit a domain, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit Domaincomponent button.</LI>
+
+<LI>
+If you have not authenticated before you attempt to edit an entry, or if
+your authentication has expired, the Directory Server prompts you to
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+To edit the domain's entry, type in the value
+for each field. You must supply values for the required fields.</LI>
+
+<LI>
+The required field for a domain is <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#name">Domaincomponent Name</A>.</LI>
+
+<LI>
+You can provide values for the optional fields now, or add them later.
+The optional fields for a domain are:</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A></TD>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone</A></TD>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A></TD></TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#fax">Fax</A></TD>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#localityName">Location</A></TD>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address</A></TD></TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A></TD>
+<TD>&nbsp;</TD>
+<TD>&nbsp;</TD></TR>
+</TABLE></CENTER>
+<P>
+<LI>
+When you are done editing, click Save Changes.</LI>
+</OL>
+From this window you can also:
+<UL>
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#rename">Rename an entry</A></LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm#delete">Delete an entry</A></LI>
+</UL>
+
+<H2>
+<A NAME="o"></A>Editing Organizations</H2>
+To edit an organization entry, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit Organization button.</LI>
+
+<LI>
+If you have not authenticated before you attempt to edit an entry, or if
+your authentication has expired, the Directory Server prompts you to
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</A> before continuing.</LI>
+
+<LI>
+To edit the organizational unit's entry, type in the value
+for each field. You must supply values for the required fields.</LI>
+
+<LI>
+The required fields for an organization is <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#organizationName">Organization Name</A>.</LI>
+
+<LI>
+You may provide values for the optional fields now, or edit them later.
+The optional fields for an organization are:</LI>
+
+<P>
+<CENTER><TABLE BORDER=2>
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">Description</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">Phone</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#businessCategory">Business Category</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#fax">Fax</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#l">Location</A> </TD>
+
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#postalAddress">Mailing Address</A> </TD>
+</TR>
+
+<TR>
+<TD><A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#seeAlso">See Also</A> </TD>
+
+<TD> </TD>
+
+<TD> </TD>
+</TR>
+</TABLE></CENTER>
+ 
+<LI>
+When you are done editing, click Save Changes.</LI>
+</OL>
+
+<H2><A NAME="rename"></A>Renaming Entries</H2>
+To rename an entry, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit button.</LI>
+
+<LI>
+Enter the new common name for the entry.</LI>
+
+<LI>
+Click Save Changes.</LI>
+</OL>
+Note the following rules about renaming an entry:
+<UL>
+<LI>
+You can change only the left-most value in an entry's <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/add.htm#DN">distinguished
+name</A>. This effectively means you can only change the entry's name;
+you cannot move the entry to another branch in the directory through this
+mechanism. For example, if you have an entry that has a DN of:</LI>
+
+<PRE>uid=tandrew, ou=Accounting, o=Example.com</PRE>
+
+you can rename only the user ID (uid) part of this entry. You cannot, however,
+move user tandrew to the Marketing subtree. To do that, you must create
+a new entry for tandrew in the Marketing subtree, and then delete his old
+entry in the Accounting tree.
+<LI>
+You cannot rename an organizational unit if it has any entries below it
+in the tree. To rename a branch point in the directory tree, you must first
+delete everything below that point in the tree, and then rename the entry.</LI>
+</UL>
+
+<H2>
+<A NAME="delete"></A>Deleting Entries</H2>
+To delete an entry, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit button.</LI>
+
+<LI>
+Click the Delete button.</LI>
+</OL>
+Note that you cannot delete an entry if it has any child entries. Specifically,
+you cannot delete an organizational unit if it has any entries below it
+in the tree. To delete a branch point in the directory tree, you must first
+delete everything below that point in the tree, and then delete the entry.
+<H2>
+<A NAME="changepw"></A>Changing Passwords</H2>
+In the Directory Server interface, you can change your own password. You
+can also change another person's password if you are the directory manager
+or an unrestricted user with write privileges to the password attribute.
+
+<P>To change a password, do the following:
+<OL>
+<LI>
+Search for the entry using the <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</A>
+or <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</A> mechanism.</LI>
+
+<LI>
+<A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">View the entry</A>.</LI>
+
+<LI>
+Click the Edit button.</LI>
+
+<LI>
+Click the Change Password button.</LI>
+
+<BR>If you are changing your own password, you must enter the old password
+for the change command to succeed. (If you are authenticated as
+anyone besides the current entry, you are not prompted to enter the
+old password.)
+<LI>
+Click the Change Password button.</LI>
+
+</OL>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/manual/n.gif b/ldap/clients/dsgw/html/manual/n.gif
new file mode 100644
index 00000000..1dd64dbf
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/n.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/manual/objclass.htm b/ldap/clients/dsgw/html/manual/objclass.htm
new file mode 100644
index 00000000..708746fa
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/objclass.htm
@@ -0,0 +1,7246 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<A NAME="1096805">
+<P>
+</A><A NAME="1096807">
+<P>
+</A><A NAME="1002619">
+<H1>Object Classes
+</H1>
+</A>
+
+<A NAME="996830">
+<br>
+This appendix includes information on object class definitions. Most of the schema elements used in the Directory Server are part of the standard LDAP protocol, which is in turn based on the X.500 standard. However, some of the Directory Server's object classes are extensions created by Netscape for use with its implementation of LDAP. If an object class was created by Netscape and is not part of the standard LDAP schema, a note is made in the description of that object class. <P></A>
+
+<A NAME="1080540">
+For information on what the Directory Server schema is and what it is used for, refer to the <i>Netscape Directory Server Deployment Guide</i>.<P></A>
+
+<A NAME="1080543">
+For information on the attributes in the schema, see <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1002619">Appendix B, "Attributes."</a><P></A>
+<A NAME="1080587">
+The following types of object classes are described here:<P>
+</A><ul><A NAME="1080589">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005608">Groups</a><P>
+</A>
+<A NAME="1080591">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005780">Replication</a><P>
+</A>
+<A NAME="1011931">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005591">Locations</a><P>
+</A>
+<A NAME="1002658">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1004915">Organizations</a><P>
+</A>
+<A NAME="1002659">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1004958">People</a><P>
+</A>
+<A NAME="1021627">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078660">Calendar Server Extensions</a><P>
+</A>
+<A NAME="1085862">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078479">Certificate Server Extensions</a><P>
+</A>
+<A NAME="1085922">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078576">Collabra Server Extensions</a><P>
+</A>
+<A NAME="1085927">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078655">Compass Server Extensions</a><P>
+</A>
+<A NAME="1085932">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097229">Directory Server Extensions</a><P>
+</A>
+<A NAME="1085945">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097091">Media Server Extensions</a><P>
+</A>
+<A NAME="1100342">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097135">Messaging Server Extensions</a><P>
+</A>
+<A NAME="1085950">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1086191">Proxy Server Extensions</a><P>
+</A>
+<A NAME="1085955">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1081607">Web Server Extensions</a><P>
+</A>
+<A NAME="1089730">
+<LI><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1108799">Reserved Object Classes</a><P>
+</A>
+</ul>
+<A NAME="1108856">
+The base OID for the Netscape Directory Server is:<P></A>
+<PRE><A NAME="1108857">
+2.16.840.1.113730.3
+</A>
+</PRE>
+<A NAME="1108858">
+All Netscape defined object classes have the base:<P></A>
+<PRE><A NAME="1108859">
+2.16.840.1.113730.3.2
+</A>
+</PRE>
+
+<A NAME="1005608"> 
+</A>
+<A NAME="Groups">
+<H2> Groups</H2>
+</A>
+
+<A NAME="1080703">
+The following object classes describe entries representing an unordered set of names that represent individual objects or other groups of objects. Membership of a group is static: only administrative action can modify a group (such as adding a member), the membership is not determined dynamically each time a reference is made to the group. Each object class contains attributes that describe the group and its members. The object classes described here are <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1080708">groupOfNames</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005294">groupOfUniqueNames</a>, and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1100399">NTGroup</a>.<P></A>
+
+
+<A NAME="1080708"> 
+</A>
+<A NAME="groupOfNames">
+<H3> groupOfNames</H3>
+</A>
+
+
+
+<A NAME="1080709">
+Defines entries for a group of names. This object class was inherited from X.500 Directory Services. <P></A>
+
+<A NAME="1096982">
+OID: <code>2.5.6.9</code><P></A>
+
+<A NAME="1067760">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075396">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075398">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1069038">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1069041">
+(Required) The group's common name.<P></A>
+
+<tr><td>
+<A NAME="1069044">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171811">member</a><P></A>
+<td>
+<A NAME="1069047">
+(Required) A group member in distinguished name format.<P></A>
+
+<tr><td>
+<A NAME="1069050">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1069052">
+Type of business in which the group is engaged.<P></A>
+
+<tr><td>
+<A NAME="1069055">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1069057">
+Text description of the group's purpose.<P></A>
+
+<tr><td>
+<A NAME="1104361">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1246271">memberURL</a><P></A>
+<td>
+<A NAME="1104363">
+URL to information relevant to a group member.<P></A>
+
+<tr><td>
+<A NAME="1069060">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1069062">
+Organization to which the group belongs.<P></A>
+
+<tr><td>
+<A NAME="1104337">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1069067">
+Organizational unit to which the group belongs.<P></A>
+
+<tr><td>
+<A NAME="1104340">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005719">owner</a><P></A>
+<td>
+<A NAME="1069072">
+The group's owner.<P></A>
+
+<tr><td>
+<A NAME="1069075">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1069077">
+URL to information relevant to the group.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005294"> 
+</A>
+<A NAME="groupOfUniqueNames">
+<H3> groupOfUniqueNames</H3>
+</A>
+
+
+
+<A NAME="1005764">
+Defines entries for a group of unique names. This object class was inherited from X.500 Directory Services. <P></A>
+
+<A NAME="1097009">
+OID: <code>2.5.6.17</code><P></A>
+
+<A NAME="1067761">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075392">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075394">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1069137">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1069140">
+(Required) The group's common name.<P></A>
+
+<tr><td>
+<A NAME="1069144">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172624">uniqueMember</a><P></A>
+<td>
+<A NAME="1069147">
+(Required) A unique group member in distinguished name format.<P></A>
+
+<tr><td>
+<A NAME="1104391">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1069152">
+Type of business in which the group is engaged.<P></A>
+
+<tr><td>
+<A NAME="1104396">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1069157">
+Text description of the group's purpose.<P></A>
+
+<tr><td>
+<A NAME="1104401">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1069162">
+Organization to which the group belongs.<P></A>
+
+<tr><td>
+<A NAME="1104406">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1069167">
+Organizational unit to which the group belongs.<P></A>
+
+<tr><td>
+<A NAME="1104411">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005719">owner</a><P></A>
+<td>
+<A NAME="1069172">
+The group's owner.<P></A>
+
+<tr><td>
+<A NAME="1104416">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1069177">
+URL to information relevant to the group.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1100399"> 
+</A>
+<A NAME="NTGroup">
+<H3> NTGroup</H3>
+</A>
+
+
+
+<A NAME="1100400">
+Object class used by the NT synchronization service to map the attributes of an NT group to an entry in the directory. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1100401">
+OID: <code>2.16.840.1.113730.3.2.9</code><P></A>
+
+<A NAME="1100458">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1100404">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1100406">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1100410">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1103684">ntGroupDomainId</a><P></A>
+<td>
+<A NAME="1100412">
+(Required) Used by the NT synchronization service to store the NT Global Groupname/Domain.<P></A>
+
+<tr><td>
+<A NAME="1100415">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1100417">
+Text description of the NT group.<P></A>
+
+<tr><td>
+<A NAME="1100420">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1100422">
+Locality in which the server resides.<P></A>
+
+<tr><td>
+<A NAME="1104514">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1122623">ntGroupAttributes</a><P></A>
+<td>
+<A NAME="1104516">
+Used by the NT synchronization service to store attributes for an NT group.<P></A>
+
+<tr><td>
+<A NAME="1104538">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1122633">ntGroupCreateNewGroup</a><P></A>
+<td>
+<A NAME="1104540">
+Reserved for use by the NT synchronization service.<P></A>
+
+<tr><td>
+<A NAME="1104480">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1103799">ntGroupDeleteGroup</a><P></A>
+<td>
+<A NAME="1104482">
+Reserved for use by the NT synchronization service.<P></A>
+
+<tr><td>
+<A NAME="1104557">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104232">ntGroupId</a><P></A>
+<td>
+<A NAME="1104559">
+Used by the NT synchronization service to store the identifier for the group.<P></A>
+
+<tr><td>
+<A NAME="1100425">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1100427">
+Organizational unit to which the group belongs.<P></A>
+
+<tr><td>
+<A NAME="1100435">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1100437">
+URL to information relevant to the group.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005780"> 
+</A>
+<A NAME="Replication">
+<H2> Replication</H2>
+</A>
+
+<A NAME="1005974">
+The following object classes define Directory Servers. The first object class identifies the master or supplier server. The second object class identifies consumer servers and the entries to be supplied to those consumers. The object classes are <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1100614">cirReplicaSource</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005781">LDAPServer</a>, and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005782">LDAPReplica</a>. <P></A>
+
+
+<A NAME="1100614"> 
+</A>
+<A NAME="cirReplicaSource">
+<H3> cirReplicaSource</H3>
+</A>
+
+
+
+<A NAME="1100615">
+Object class used by the Netscape Directory Server for consumer initiated replication that contains all the replication information for a particular subtree of the directory. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1100616">
+OID: <code>2.16.840.1.113730.3.2.11</code><P></A>
+
+<A NAME="1100703">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1100619">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1100621">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1100624">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1100626">
+(Required) unique identifier of the supplier server.<P></A>
+
+<tr><td>
+<A NAME="1104680">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1103818">cirBeginORC</a><P></A>
+<td>
+<A NAME="1104682">
+Defines whether or not the consumer server should erase the contents of its directory before replication.<P></A>
+
+<tr><td>
+<A NAME="1104646">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1101818">cirBindCredentials</a><P></A>
+<td>
+<A NAME="1104648">
+Bind credentials used to connect to the supplier server.<P></A>
+
+<tr><td>
+<A NAME="1104607">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1101379">cirBindDn</a><P></A>
+<td>
+<A NAME="1104609">
+Distinguished name used to bind to the supplier server.<P></A>
+
+<tr><td>
+<A NAME="1104731">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1101250">cirHost</a><P></A>
+<td>
+<A NAME="1104733">
+Hostname of the supplier server.<P></A>
+
+<tr><td>
+<A NAME="1104629">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1101860">cirLastUpdateApplied</a><P></A>
+<td>
+<A NAME="1104631">
+Last date and time that synchronization occurred between the consumer and supplier servers.<P></A>
+
+<tr><td>
+<A NAME="1100639">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1101283">cirPort</a><P></A>
+<td>
+<A NAME="1100641">
+Port number of the supplier server.<P></A>
+
+<tr><td>
+<A NAME="1104589">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1101135">cirReplicaRoot</a><P></A>
+<td>
+<A NAME="1104591">
+Root of the subtree on the supplier server to be replicated on the consumer.<P></A>
+
+<tr><td>
+<A NAME="1104766">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1102148">cirSyncInterval</a><P></A>
+<td>
+<A NAME="1104768">
+Periodically, the consumer server queries the supplier to find out if any changes have been made to the replicated portion of the directory. This attribute defines, in seconds, the interval between consumer queries of the supplier server.<P></A>
+
+<tr><td>
+<A NAME="1104811">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1102114">cirUpdateFailedat</a><P></A>
+<td>
+<A NAME="1104813">
+Timestamp of the last failed update attempt.<P></A>
+
+<tr><td>
+<A NAME="1104814">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1102001">cirUpdateSchedule</a><P></A>
+<td>
+<A NAME="1104792">
+Hours between which replication can occur.<P></A>
+
+<tr><td>
+<A NAME="1100650">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1101691">cirUsePersistentSearch</a><P></A>
+<td>
+<A NAME="1100652">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1100655">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1101735">cirUseSsl</a><P></A>
+<td>
+<A NAME="1100657">
+Tells the consumer server to use an SSL connection when binding to the supplier server.<P></A>
+
+<tr><td>
+<A NAME="1104823">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1148497">replicaEntryFilter</a><P></A>
+<td>
+<A NAME="1104699">
+Specifies which attributes should be replicated or omitted during replication.<P></A>
+
+<tr><td>
+<A NAME="1100690">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1148453">replicaNickName</a><P></A>
+<td>
+<A NAME="1100692">
+Freeform name that describes a particular set of replication rules between a single supplier and a single consumer server.<P></A>
+
+<tr><td>
+<A NAME="1100700">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281126">replicatedAttributeList</a><P></A>
+<td>
+<A NAME="1100702">
+Specifies which attributes should be replicated or omitted during replication.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1105809"> 
+</A>
+<A NAME="glue">
+<H3> glue</H3>
+</A>
+
+
+
+<A NAME="1105810">
+Extensible object class used by the Netscape Directory Server to facilitate replication. For more information about extensible object classes, see "Types of Object Classes" in the Netscape Directory Server Deployment Guide. Reserved. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1105811">
+OID: <code>2.16.840.1.113730.3.2.30</code><P></A>
+
+
+<A NAME="1005781"> 
+</A>
+<A NAME="LDAPServer">
+<H3> LDAPServer</H3>
+</A>
+
+
+
+<A NAME="1042902">
+Identifies the local server. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1098493">
+OID: <code>2.16.840.1.113730.3.2.35</code><P></A>
+
+<A NAME="1067762">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075388">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075390">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1069192">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1069195">
+(Required) The server's common name.<P></A>
+
+<tr><td>
+<A NAME="1069199">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171397">changeLogMaximumAge</a><P></A>
+<td>
+<A NAME="1100535">
+Maximum age permitted for the server's change log.<P></A>
+
+<tr><td>
+<A NAME="1069204">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171405">changeLogMaximumSize</a><P></A>
+<td>
+<A NAME="1069206">
+Maximum size permitted for the server's change log.<P></A>
+
+<tr><td>
+<A NAME="1069209">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1069211">
+Text description of the server.<P></A>
+
+<tr><td>
+<A NAME="1069214">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1284708">generation</a><P></A>
+<td>
+<A NAME="1069216">
+Unique byte vector that identifies the server for replication purposes.<P></A>
+
+<tr><td>
+<A NAME="1069219">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1069221">
+Locality in which the server resides.<P></A>
+
+<tr><td>
+<A NAME="1069224">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1069226">
+Organizational unit to which the server belongs.<P></A>
+
+<tr><td>
+<A NAME="1069229">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1069231">
+URL to information relevant to the server.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005782"> 
+</A>
+<A NAME="LDAPReplica">
+<H3> LDAPReplica</H3>
+</A>
+
+
+
+<A NAME="1006031">
+Identifies entries in the local server that are replicated to a remote server, and identifies the remote server to which the entries are replicated. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1098496">
+OID: <code>2.16.840.1.113730.3.2.36</code><P></A>
+
+<A NAME="1067881">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075384">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075386">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1069247">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1069250">
+(Required) The entry's common name.<P></A>
+
+<tr><td>
+<A NAME="1069253">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1069255">
+Text description of the entry.<P></A>
+
+<tr><td>
+<A NAME="1104907">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1069260">
+Locality in which the entry resides.<P></A>
+
+<tr><td>
+<A NAME="1104912">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1069265">
+Organizational unit in which the entry resides.<P></A>
+
+<tr><td>
+<A NAME="1106807">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1092877">replicaBeginOrc</a><P></A>
+<td>
+<A NAME="1106809">
+Defines whether or not the supplier server should erase the contents of the consumer server before replication.<P></A>
+
+<tr><td>
+<A NAME="1069268">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1006496">replicaBindDn</a><P></A>
+<td>
+<A NAME="1069270">
+DN used by the local server to bind to the consumer server.<P></A>
+
+<tr><td>
+<A NAME="1069273">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1006636">replicaBindMethod</a><P></A>
+<td>
+<A NAME="1069275">
+Method used by the local server to bind to the consumer. Currently this attribute must be set to <code>simple</code>.<P></A>
+
+<tr><td>
+<A NAME="1069278">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230073">replicaCredentials</a><P></A>
+<td>
+<A NAME="1069280">
+Password used by the local server to bind to the consumer.<P></A>
+
+<tr><td>
+<A NAME="1106878">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1148497">replicaEntryFilter</a><P></A>
+<td>
+<A NAME="1106880">
+Specifies which attributes should be replicated or omitted in a filtered replication agreement.<P></A>
+
+<tr><td>
+<A NAME="1069283">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1148445">replicaHost</a><P></A>
+<td>
+<A NAME="1069285">
+Hostname of the consumer server.<P></A>
+
+<tr><td>
+<A NAME="1106816">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1148453">replicaNickName</a><P></A>
+<td>
+<A NAME="1106818">
+Contains a freeform name for the replication agreement.<P></A>
+
+<tr><td>
+<A NAME="1069288">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1007660">replicaPort</a><P></A>
+<td>
+<A NAME="1069290">
+Port used by the consumer server for LDAP communications.<P></A>
+
+<tr><td>
+<A NAME="1069293">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1006384">replicaRoot</a><P></A>
+<td>
+<A NAME="1069295">
+Distinguished name representing the subtree on the local server that is to be supplied to the consumer server.<P></A>
+
+<tr><td>
+<A NAME="1106928">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281126">replicatedAttributeList</a><P></A>
+<td>
+<A NAME="1106930">
+Specifies which attributes should be replicated or omitted in a selected attribute replication agreement.<P></A>
+
+<tr><td>
+<A NAME="1069298">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1006918">replicaUpdateFailedAt</a><P></A>
+<td>
+<A NAME="1069300">
+Time stamp when an update to the consumer server failed.<P></A>
+
+<tr><td>
+<A NAME="1069303">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1012768">replicaUpdateReplayed</a><P></A>
+<td>
+<A NAME="1069305">
+Change number of the last change supplied to the consumer server.<P></A>
+
+<tr><td>
+<A NAME="1069308">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1006817">replicaUpdateSchedule</a><P></A>
+<td>
+<A NAME="1069310">
+Schedule when the local server begins an update to the consumer server.<P></A>
+
+<tr><td>
+<A NAME="1069313">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1006741">replicaUseSSL</a><P></A>
+<td>
+<A NAME="1069315">
+Indicates whether SSL is to be used for communications with the consumer server.<P></A>
+
+<tr><td>
+<A NAME="1069318">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1069320">
+URL to information relevant to the server.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005591"> 
+</A>
+<A NAME="Locations">
+<H2> Locations</H2>
+</A>
+
+<A NAME="1005809">
+The following object classes describe locations in the directory tree. Each object class contains attributes that describe a location, such as the country name and description. The object classes described here are <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005812">country</a> and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005427">locality</a>.<P></A>
+
+
+<A NAME="1005812"> 
+</A>
+<A NAME="country">
+<H3> country</H3>
+</A>
+
+
+
+<A NAME="1005813">
+Defines entries that represent countries. This object class was inherited from X.500 Directory Services. <P></A>
+
+<A NAME="1096900">
+OID: <code>2.5.6.2</code><P></A>
+
+<A NAME="1068820">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1088379">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1088381">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1088384">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1240535">c</a><P></A>
+<td>
+<A NAME="1088387">
+(Required) The entry's country name.<P></A>
+
+<tr><td>
+<A NAME="1088390">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1088392">
+Text description of the country.<P></A>
+
+<tr><td>
+<A NAME="1088397">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202682">searchGuide</a><P></A>
+<td>
+<A NAME="1088399">
+Specifies information for suggested search criteria when using the entry as the base object in the directory tree for a search operation.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005427"> 
+</A>
+<A NAME="locality">
+<H3> locality</H3>
+</A>
+
+
+
+<A NAME="1005428">
+Defines entries that represent localities or geographic areas. This object class was inherited from X.500 Directory Services. <P></A>
+
+<A NAME="1096910">
+OID: <code>2.5.6.3</code><P></A>
+
+<A NAME="1068821">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1075380">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1075382">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1071009">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1071011">
+Text description of the locality.<P></A>
+
+<tr><td>
+<A NAME="1071014">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1071016">
+The entry's locality.<P></A>
+
+<tr><td>
+<A NAME="1106986">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202682">searchGuide</a><P></A>
+<td>
+<A NAME="1106988">
+Specifies information for a suggested search criteria when using the entry as the base object in the directory tree for a search operation.<P></A>
+
+<tr><td>
+<A NAME="1071019">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1071021">
+URL to information relevant to the locality.<P></A>
+
+<tr><td>
+<A NAME="1071024">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1203417">st</a><P></A>
+<td>
+<A NAME="1071026">
+State or province to which the locality belongs.<P></A>
+
+<tr><td>
+<A NAME="1071029">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202721">street</a><P></A>
+<td>
+<A NAME="1071031">
+Street address associated with the locality.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1004915"> 
+</A>
+<A NAME="Organizations">
+<H2> Organizations</H2>
+</A>
+
+<A NAME="1004913">
+The following object classes describe entries representing organizations in the directory tree. Each object class contains attributes that describe an organization, such as its name and description. The object classes described here are <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1004980">organization</a> and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005108">organizationalUnit</a>.<P></A>
+
+
+<A NAME="1004980"> 
+</A>
+<A NAME="organization">
+<H3> organization</H3>
+</A>
+
+
+
+<A NAME="1004981">
+Defines entries that represent organizations. An organization is generally assumed to be a large, relatively static grouping within a larger corporation or enterprise. This object class was inherited from X.500 Directory Services. <P></A>
+
+<A NAME="1096920">
+OID: <code>2.5.6.4</code><P></A>
+
+<A NAME="1068822">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1107038">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1107040">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1107045">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1107047">
+(Required) The organization's name.<P></A>
+
+<tr><td>
+<A NAME="1107052">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1107054">
+Business in which the organization is involved.<P></A>
+
+<tr><td>
+<A NAME="1107059">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1107061">
+Text description of the organization.<P></A>
+
+<tr><td>
+<A NAME="1107065">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171637">facsimileTelephoneNumber</a><P></A>
+<td>
+<A NAME="1107068">
+Fax number associated with the organization.<P></A>
+
+<tr><td>
+<A NAME="1107073">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1107075">
+The organization's location.<P></A>
+
+<tr><td>
+<A NAME="1107079">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003072">physicalDeliveryOfficeName</a><P></A>
+<td>
+<A NAME="1107082">
+A location where physical deliveries can be made to the organization.<P></A>
+
+<tr><td>
+<A NAME="1107087">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230025">postalAddress</a><P></A>
+<td>
+<A NAME="1107089">
+The organization's mailing address.<P></A>
+
+<tr><td>
+<A NAME="1107094">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230036">postalCode</a><P></A>
+<td>
+<A NAME="1107096">
+The organization's postal code (such as a United States zip code).<P></A>
+
+<tr><td>
+<A NAME="1107101">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230043">postOfficeBox</a><P></A>
+<td>
+<A NAME="1107103">
+The organization's post office box.<P></A>
+
+<tr><td>
+<A NAME="1107108">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202605">preferredDeliveryMethod</a><P></A>
+<td>
+<A NAME="1107110">
+The organization's preferred method of contact or delivery.<P></A>
+
+<tr><td>
+<A NAME="1107115">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202682">searchGuide</a><P></A>
+<td>
+<A NAME="1107117">
+Specifies information for suggested search criteria when using the entry as the base object in the directory tree for a search operation.<P></A>
+
+<tr><td>
+<A NAME="1107122">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1107124">
+URL to information relevant to the organization.<P></A>
+
+<tr><td>
+<A NAME="1107129">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1203417">st</a><P></A>
+<td>
+<A NAME="1107131">
+State or province in which the organization resides.<P></A>
+
+<tr><td>
+<A NAME="1107136">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202721">street</a><P></A>
+<td>
+<A NAME="1107138">
+Street address at which the organization is located.<P></A>
+
+<tr><td>
+<A NAME="1107143">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1107145">
+Telephone number associated with the organization.<P></A>
+
+<tr><td>
+<A NAME="1107150">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205004">teletexTerminalIdentifier</a><P></A>
+<td>
+<A NAME="1107152">
+Identifier for the teletex terminal of the organization.<P></A>
+
+<tr><td>
+<A NAME="1107157">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205120">telexNumber</a><P></A>
+<td>
+<A NAME="1107159">
+Telex number of the organization.<P></A>
+
+<tr><td>
+<A NAME="1107171">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1107173">
+Password with which the entry can bind to the directory.<P></A>
+
+<tr><td>
+<A NAME="1107164">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281763">x121Address</a><P></A>
+<td>
+<A NAME="1107166">
+X.121 address of the organization.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1005108"> 
+</A>
+<A NAME="organizationalUnit">
+<H3> organizationalUnit</H3>
+</A>
+
+
+
+<A NAME="1005109">
+Defines entries that represent organizational units. An organizational unit is generally assumed to be a relatively static grouping within a larger organization. This object class was inherited from X.500 Directory Services. <P></A>
+
+<A NAME="1096923">
+OID: <code>2.5.6.5</code><P></A>
+
+<A NAME="1068823">
+.
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1107182">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1107184">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1107189">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1107191">
+(Required) The organizational unit's name.<P></A>
+
+<tr><td>
+<A NAME="1107196">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1107198">
+Business in which the organizational unit is involved.<P></A>
+
+<tr><td>
+<A NAME="1107203">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1107205">
+Text description of the organizational unit.<P></A>
+
+<tr><td>
+<A NAME="1107326">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1292809">destinationIndicator</a><P></A>
+<td>
+<A NAME="1107328">
+The country and city associated with the organizational unit needed to provide Public Telegram Service.<P></A>
+
+<tr><td>
+<A NAME="1107209">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171637">facsimileTelephoneNumber</a><P></A>
+<td>
+<A NAME="1107212">
+Fax number associated with the organizational unit.<P></A>
+
+<tr><td>
+<A NAME="1107337">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1224256">internationalIsdnNumber</a><P></A>
+<td>
+<A NAME="1107339">
+Contains an ISDN number for the organizational unit.<P></A>
+
+<tr><td>
+<A NAME="1107217">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1107219">
+The organizational unit's location.<P></A>
+
+<tr><td>
+<A NAME="1107223">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003072">physicalDeliveryOfficeName</a><P></A>
+<td>
+<A NAME="1107226">
+Location where physical deliveries can be made to the organizational unit.<P></A>
+
+<tr><td>
+<A NAME="1107231">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230025">postalAddress</a><P></A>
+<td>
+<A NAME="1107233">
+The organizational unit's mailing address.<P></A>
+
+<tr><td>
+<A NAME="1107238">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230036">postalCode</a><P></A>
+<td>
+<A NAME="1107240">
+The organizational unit's postal code (such as a United States zip code).<P></A>
+
+<tr><td>
+<A NAME="1107245">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230043">postOfficeBox</a><P></A>
+<td>
+<A NAME="1107247">
+The organizational unit's post office box.<P></A>
+
+<tr><td>
+<A NAME="1107252">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202605">preferredDeliveryMethod</a><P></A>
+<td>
+<A NAME="1107254">
+The organizational unit's preferred method of contact or delivery.<P></A>
+
+<tr><td>
+<A NAME="1107352">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202644">registeredAddress</a><P></A>
+<td>
+<A NAME="1107366">
+Postal address suitable for reception of expedited documents, where the recipient must verify delivery.<P></A>
+
+<tr><td>
+<A NAME="1107259">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202682">searchGuide</a><P></A>
+<td>
+<A NAME="1107261">
+Specifies information for suggested search criteria when using the entry as the base object in the directory tree for a search operation.<P></A>
+
+<tr><td>
+<A NAME="1107266">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1107268">
+URL to information relevant to the organizational unit.<P></A>
+
+<tr><td>
+<A NAME="1107273">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1203417">st</a><P></A>
+<td>
+<A NAME="1107275">
+State or province in which the organizational unit resides.<P></A>
+
+<tr><td>
+<A NAME="1107280">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202721">street</a><P></A>
+<td>
+<A NAME="1107282">
+Street address at which the organizational unit is located.<P></A>
+
+<tr><td>
+<A NAME="1107287">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1107289">
+Telephone number associated with the organizational unit.<P></A>
+
+<tr><td>
+<A NAME="1107322">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205004">teletexTerminalIdentifier</a><P></A>
+<td>
+<A NAME="1107324">
+Identifier for the teletex terminal of the organization.<P></A>
+
+<tr><td>
+<A NAME="1107315">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205120">telexNumber</a><P></A>
+<td>
+<A NAME="1107317">
+Telex number of the organization.<P></A>
+
+<tr><td>
+<A NAME="1107308">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1107310">
+Password with which the entry can bind to the directory.<P></A>
+
+<tr><td>
+<A NAME="1107301">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281763">x121Address</a><P></A>
+<td>
+<A NAME="1107303">
+X.121 address of the organization.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1004958"> 
+</A>
+<A NAME="People">
+<H2> People</H2>
+</A>
+
+<A NAME="1100949">
+The following object classes describe entries representing people in the directory. Each object class contains attributes that describe a person, such as name, telephone number, and address. The object classes described here are <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1089249">inetOrgPerson</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1100980">newPilotPerson</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1100862">nsLicenseUser</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1089442">ntUser</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1002805">organizationalPerson</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1088567">organizationalRole</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1089681">person</a>, and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1106267">residentialPerson</a>. <P></A>
+
+
+<A NAME="1089249"> 
+</A>
+<A NAME="inetOrgPerson">
+<H3> inetOrgPerson</H3>
+</A>
+
+
+
+<A NAME="1089250">
+Defines entries representing people in an organization's intranet. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1096822">
+OID: <code>2.16.840.1.113730.3.2.2</code><P></A>
+
+<A NAME="1089439">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1089253">
+<I></I>Attribute<P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1089255">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1102952">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201684">audio</a><P></A>
+<td>
+<A NAME="1102954">
+Contains a sound file in binary format.<P></A>
+
+<tr><td>
+<A NAME="1089270">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1089272">
+Business in which the person is involved.<P></A>
+
+<tr><td>
+<A NAME="1089275">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003044">carLicense</a><P></A>
+<td>
+<A NAME="1089277">
+The license plate number of the person's vehicle.<P></A>
+
+<tr><td>
+<A NAME="1089280">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1095560">departmentNumber</a><P></A>
+<td>
+<A NAME="1089282">
+Department for which the person works.<P></A>
+
+<tr><td>
+<A NAME="1089290">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1111357">employeeNumber</a><P></A>
+<td>
+<A NAME="1089292">
+The person's employee number.<P></A>
+
+<tr><td>
+<A NAME="1089295">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1009035">employeeType</a><P></A>
+<td>
+<A NAME="1089297">
+The person's type of employment (for example, full time).<P></A>
+
+<tr><td>
+<A NAME="1089305">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229534">givenName</a><P></A>
+<td>
+<A NAME="1089307">
+The person's given, or first, name.<P></A>
+
+<tr><td>
+<A NAME="1089310">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201936">homePhone</a><P></A>
+<td>
+<A NAME="1089312">
+The person's home phone number.<P></A>
+
+<tr><td>
+<A NAME="1089315">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201947">homePostalAddress</a><P></A>
+<td>
+<A NAME="1089317">
+The person's home mailing address.<P></A>
+
+<tr><td>
+<A NAME="1089320">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229543">initials</a><P></A>
+<td>
+<A NAME="1089322">
+The person's initials.<P></A>
+
+<tr><td>
+<A NAME="1089325">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201995">jpegPhoto</a><P></A>
+<td>
+<A NAME="1089327">
+An image in JPEG format.<P></A>
+
+<tr><td>
+<A NAME="1107552">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202020">labeledUri</a><P></A>
+<td>
+<A NAME="1089337">
+Universal resource locator that is relevant to the person.<P></A>
+
+<tr><td>
+<A NAME="1089340">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1189404">mail</a><P></A>
+<td>
+<A NAME="1089342">
+The person's electronic mailing address.<P></A>
+
+<tr><td>
+<A NAME="1089345">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1007859">manager</a><P></A>
+<td>
+<A NAME="1089347">
+Distinguished name representing the person's manager.<P></A>
+
+<tr><td>
+<A NAME="1089350">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202056">mobile</a><P></A>
+<td>
+<A NAME="1089352">
+The person's mobile phone number.<P></A>
+
+<tr><td>
+<A NAME="1089361">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003070">pager</a><P></A>
+<td>
+<A NAME="1089363">
+The person's pager number.<P></A>
+
+<tr><td>
+<A NAME="1107511">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202247">photo</a><P></A>
+<td>
+<A NAME="1107514">
+Contains a photo, in binary form.<P></A>
+
+<tr><td>
+<A NAME="1107521">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1103495">preferredLanguage</a><P></A>
+<td>
+<A NAME="1107523">
+Defines a person's preffered written or spoken language.<P></A>
+
+<tr><td>
+<A NAME="1089391">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1204477">roomNumber</a><P></A>
+<td>
+<A NAME="1089393">
+The room number in which the person is located.<P></A>
+
+<tr><td>
+<A NAME="1089396">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202691">secretary</a><P></A>
+<td>
+<A NAME="1089398">
+The person's secretary or administrator.<P></A>
+
+<tr><td>
+<A NAME="1089406">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1296804">uid</a><P></A>
+<td>
+<A NAME="1089408">
+Identifies the entry's userid (usually the logon ID).<P></A>
+
+<tr><td>
+<A NAME="1089431">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1208938">userCertificate</a><P></A>
+<td>
+<A NAME="1089433">
+Contains a user's certificate in cleartext (not used).<P></A>
+
+<tr><td>
+<A NAME="1107557">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1278425">userCertificate;binary</a><P></A>
+<td>
+<A NAME="1107559">
+Contains a user's certificate in binary form.<P></A>
+
+<tr><td>
+<A NAME="1089436">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1103595">userSMIMECertificate;binary</a><P></A>
+<td>
+<A NAME="1107562">
+Contains a user's certificate in binary form. Used by Netscape Communicator for S/MIME.<P></A>
+
+<tr><td>
+<A NAME="1095842">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1292796">x500UniqueIdentifier</a><P></A>
+<td>
+<A NAME="1095844">
+Undefined.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1100980"> 
+</A>
+<A NAME="newPilotPerson">
+<H3> newPilotPerson</H3>
+</A>
+
+
+
+<A NAME="1100981">
+Used as a subclass of person, to allow the use of a number of additional attributes to be assigned to entries of the person object class. Reserved.<P></A>
+
+<A NAME="1100982">
+OID: <code>0.9.2342.19200300.100.4.4</code><P></A>
+
+<A NAME="1101121">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1100985">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1100987">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1100992">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1100994">
+Type of business this person is engaged in.<P></A>
+
+<tr><td>
+<A NAME="1100999">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201909">drink</a><P></A>
+<td>
+<A NAME="1101001">
+The person's favorite drink.<P></A>
+
+<tr><td>
+<A NAME="1101006">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201936">homePhone</a><P></A>
+<td>
+<A NAME="1101008">
+The person's home phone number.<P></A>
+
+<tr><td>
+<A NAME="1101013">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201947">homePostalAddress</a><P></A>
+<td>
+<A NAME="1101015">
+The person's home address.<P></A>
+
+<tr><td>
+<A NAME="1101020">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201988">janetMailbox</a><P></A>
+<td>
+<A NAME="1101022">
+An email address for the person.<P></A>
+
+<tr><td>
+<A NAME="1101027">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1189404">mail</a><P></A>
+<td>
+<A NAME="1101029">
+An email address for the person.<P></A>
+
+<tr><td>
+<A NAME="1101034">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202044">mailPreferenceOption</a><P></A>
+<td>
+<A NAME="1101036">
+Indicates a preference for inclusion of the person's name on mailing lists (electronic or physical).<P></A>
+
+<tr><td>
+<A NAME="1101041">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202056">mobile</a><P></A>
+<td>
+<A NAME="1101043">
+The person's mobile phone number.<P></A>
+
+<tr><td>
+<A NAME="1101048">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281714">organizationalStatus</a><P></A>
+<td>
+<A NAME="1101175">
+The person's type of employment (for example, full time).<P></A>
+
+<tr><td>
+<A NAME="1101055">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202220">otherMailbox</a><P></A>
+<td>
+<A NAME="1101057">
+Values for electronic mailbox types other than X.400 and rfc822.<P></A>
+
+<tr><td>
+<A NAME="1101062">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003070">pager</a><P></A>
+<td>
+<A NAME="1101064">
+The person's pager number.<P></A>
+
+<tr><td>
+<A NAME="1101069">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202229">personalSignature</a><P></A>
+<td>
+<A NAME="1101071">
+The person's signature file.<P></A>
+
+<tr><td>
+<A NAME="1101076">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202238">personalTitle</a><P></A>
+<td>
+<A NAME="1101078">
+The person's personal title.<P></A>
+
+<tr><td>
+<A NAME="1101083">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202605">preferredDeliveryMethod</a><P></A>
+<td>
+<A NAME="1101085">
+The person's preferred contact or delivery method.<P></A>
+
+<tr><td>
+<A NAME="1101090">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1204477">roomNumber</a><P></A>
+<td>
+<A NAME="1101092">
+Room number of the person.<P></A>
+
+<tr><td>
+<A NAME="1101097">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202691">secretary</a><P></A>
+<td>
+<A NAME="1101099">
+Distinguished name of the person's secretary or administrative assistant.<P></A>
+
+<tr><td>
+<A NAME="1101104">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202782">textEncodedORAddress</a><P></A>
+<td>
+<A NAME="1101106">
+Text-encoded Originator/Recipient (X.400) address of the person.<P></A>
+
+<tr><td>
+<A NAME="1101111">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1296804">uid</a><P></A>
+<td>
+<A NAME="1101113">
+Logon ID of the person.<P></A>
+
+<tr><td>
+<A NAME="1101118">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202840">userClass</a><P></A>
+<td>
+<A NAME="1101120">
+Category of user.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1100862"> 
+</A>
+<A NAME="nsLicenseUser">
+<H3> nsLicenseUser</H3>
+</A>
+
+
+
+<A NAME="1100863">
+Object class used to track licenses for Netscape servers that are licensed on a per-client basis. nsLicenseUser is intended to be used with the inetOrgPerson object class. You can manage the contents of this object class through the Users and Groups area of the Netscape Administration Server. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1100864">
+OID: <code>2.16.840.1.113730.3.2.7</code><P></A>
+
+<A NAME="1100891">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1100867">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1100869">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1100873">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1091847">nsLicensedFor</a><P></A>
+<td>
+<A NAME="1100875">
+Netscape server that the user is licensed to use.<P></A>
+
+<tr><td>
+<A NAME="1107587">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1091864">nsLicenseEndTime</a><P></A>
+<td>
+<A NAME="1107589">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1100880">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1091859">nsLicenseStartTime</a><P></A>
+<td>
+<A NAME="1100882">
+Reserved for future use.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089442"> 
+</A>
+<A NAME="ntUser">
+<H3> ntUser</H3>
+</A>
+
+
+
+<A NAME="1089443">
+Defines entries that are to be synchronized between the Directory Server and a Windows NT network. The attributes defined by ntUser assist in NT Synchronization. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1098670">
+OID: <code>2.16.840.1.113730.3.2.8</code><P></A>
+<a name="1089444">
+<B>
+<UL>
+
+Note
+
+</B>
+</UL>
+</a>
+
+
+<A NAME="1089445">
+All ntUser attributes are read-only, except for ntUserCreateNewAccount, ntUserDomainId, and ntUserDeleteAccount. Any modifications you make to read-only ntUser attributes will be deleted and the original values will be replaced when the next NT Synchronization occurs.<P></A>
+
+<A NAME="1089446">
+Several Directory Server attributes correspond directly to NT user account fields. When you create a new person entry in the Directory Server that is to be synchronized with NT, Directory Server attributes will be assigned to NT user account fields as follows:
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><td>
+<A NAME="1089449">
+Directory Server attribute<P></A>
+<td>
+<A NAME="1089451">
+NT user account field<P></A>
+
+<tr><td>
+<A NAME="1089453">
+cn or commonName<P></A>
+<td>
+<A NAME="1089455">
+full_name<P></A>
+
+<tr><td>
+<A NAME="1089457">
+description<P></A>
+<td>
+<A NAME="1089459">
+comment<P></A>
+
+<tr><td>
+<A NAME="1089461">
+userid<P></A>
+<td>
+<A NAME="1089463">
+name<P></A>
+
+<tr><td>
+<A NAME="1089465">
+userPassword<P></A>
+<td>
+<A NAME="1089467">
+password<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+<A NAME="1098497">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1089470">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1089472">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1107594">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1107596">
+Text description of the user.<P></A>
+
+<tr><td>
+<A NAME="1107601">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1107603">
+The user's locality.<P></A>
+
+<tr><td>
+<A NAME="1107608">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1107610">
+The organizational unit to which the user belongs.<P></A>
+
+<tr><td>
+<A NAME="1107615">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1107617">
+URL to information relevant to the user.<P></A>
+
+<tr><td>
+<A NAME="1089476">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015403">ntUserDomainId</a><P></A>
+<td>
+<A NAME="1089479">
+(Required) Corresponding NT user and domain name.<P></A>
+
+<tr><td>
+<A NAME="1089482">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1013839">ntUserAcctExpires</a><P></A>
+<td>
+<A NAME="1089484">
+Identifies when the user's NT account will expire.<P></A>
+
+<tr><td>
+<A NAME="1089487">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1014052">ntUserAuthFlags</a><P></A>
+<td>
+<A NAME="1089489">
+The user's privileges on the NT network.<P></A>
+
+<tr><td>
+<A NAME="1089492">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1038772">ntUserBadPwCount</a><P></A>
+<td>
+<A NAME="1089494">
+Number of times that a failed login attempt occurred in NT using the user's NT login ID.<P></A>
+
+<tr><td>
+<A NAME="1089497">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1014973">ntUserCodePage</a><P></A>
+<td>
+<A NAME="1089499">
+The user's code page.<P></A>
+
+<tr><td>
+<A NAME="1089502">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1246829">ntUserComment</a><P></A>
+<td>
+<A NAME="1089504">
+Description for the user's NT account.<P></A>
+
+<tr><td>
+<A NAME="1089507">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015155">ntUserCountryCode</a><P></A>
+<td>
+<A NAME="1089509">
+The user's country code.<P></A>
+
+<tr><td>
+<A NAME="1089512">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015239">ntUserCreateNewAccount</a><P></A>
+<td>
+<A NAME="1089514">
+Identifies whether an NT account should be created when this entry is created in the Directory Server.<P></A>
+
+<tr><td>
+<A NAME="1089517">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015309">ntUserDeleteAccount</a><P></A>
+<td>
+<A NAME="1089519">
+Identifies whether the user's NT account should be deleted when this entry is deleted from the Directory Server.<P></A>
+
+<tr><td>
+<A NAME="1089522">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015534">ntUserFlags</a><P></A>
+<td>
+<A NAME="1089524">
+Identifies various NT account flags.<P></A>
+
+<tr><td>
+<A NAME="1089527">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015584">ntUserHomeDir</a><P></A>
+<td>
+<A NAME="1089529">
+Path to the user's home directory.<P></A>
+
+<tr><td>
+<A NAME="1089532">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015624">ntUserHomeDirDrive</a><P></A>
+<td>
+<A NAME="1089534">
+Drive letter assigned to the user's home directory.<P></A>
+
+<tr><td>
+<A NAME="1089537">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015682">ntUserLastLogoff</a><P></A>
+<td>
+<A NAME="1089539">
+Time of the user's last logoff from NT.<P></A>
+
+<tr><td>
+<A NAME="1089542">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015722">ntUserLastLogon</a><P></A>
+<td>
+<A NAME="1089544">
+Time of the user's last logon to NT.<P></A>
+
+<tr><td>
+<A NAME="1089547">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015746">ntUserLogonHours</a><P></A>
+<td>
+<A NAME="1089549">
+Times when the user is allowed to log on to NT.<P></A>
+
+<tr><td>
+<A NAME="1101276">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015839">ntUserLogonServer</a><P></A>
+<td>
+<A NAME="1089554">
+Server to which the user's NT logon requests are sent.<P></A>
+
+<tr><td>
+<A NAME="1089557">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1015984">ntUserMaxStorage</a><P></A>
+<td>
+<A NAME="1089559">
+Maximum disk space available to the user under NT.<P></A>
+
+<tr><td>
+<A NAME="1089562">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016030">ntUserNumLogons</a><P></A>
+<td>
+<A NAME="1089564">
+Number of successful logins to the user's NT account.<P></A>
+
+<tr><td>
+<A NAME="1101297">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1021575">ntUserParms</a><P></A>
+<td>
+<A NAME="1101299">
+Unicode string reserved for use by applications.<P></A>
+
+<tr><td>
+<A NAME="1089567">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016157">ntUserPasswordExpired</a><P></A>
+<td>
+<A NAME="1089569">
+Identifies if the user's NT password has expired.<P></A>
+
+<tr><td>
+<A NAME="1089572">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016246">ntUserPrimaryGroupId</a><P></A>
+<td>
+<A NAME="1089574">
+The user's primary global group.<P></A>
+
+<tr><td>
+<A NAME="1101331">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1017849">ntUserPriv</a><P></A>
+<td>
+<A NAME="1101333">
+User's level of privilege on the Windows NT Network.<P></A>
+
+<tr><td>
+<A NAME="1089577">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016298">ntUserProfile</a><P></A>
+<td>
+<A NAME="1089579">
+Path to the user's NT profile.<P></A>
+
+<tr><td>
+<A NAME="1089582">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016395">ntUserScriptPath</a><P></A>
+<td>
+<A NAME="1089584">
+Path to the user's NT login script.<P></A>
+
+<tr><td>
+<A NAME="1089587">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016531">ntUserUniqueId</a><P></A>
+<td>
+<A NAME="1089589">
+Identifies the user's NT RID.<P></A>
+
+<tr><td>
+<A NAME="1089592">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016632">ntUserUnitsPerWeek</a><P></A>
+<td>
+<A NAME="1089594">
+Value used to compute the user's NTUserLogonHours.<P></A>
+
+<tr><td>
+<A NAME="1089597">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016696">ntUserUsrComment</a><P></A>
+<td>
+<A NAME="1089599">
+Comments regarding the user's NT entry.<P></A>
+
+<tr><td>
+<A NAME="1089607">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1016728">ntUserWorkstations</a><P></A>
+<td>
+<A NAME="1089609">
+NT workstations from which the user is allowed to log into the NT domain.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1002805"> 
+</A>
+<A NAME="organizationalPerson">
+<H3> organizationalPerson</H3>
+</A>
+
+
+
+<A NAME="1002806">
+Defines entries for people employed by or associated with an organization. The organizationalPerson object class is an extension of the person object class. This object class was inherited from X.500 Directory Services. <P></A>
+
+<A NAME="1096977">
+OID: <code>2.5.6.7</code><P></A>
+
+<A NAME="1068825">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1070698">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1070700">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1070715">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1292809">destinationIndicator</a><P></A>
+<td>
+<A NAME="1070717">
+The country and city associated with the person needed to provide Public Telegram Service.<P></A>
+
+<tr><td>
+<A NAME="1070720">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171637">facsimileTelephoneNumber</a><P></A>
+<td>
+<A NAME="1070722">
+The person's fax number.<P></A>
+
+<tr><td>
+<A NAME="1107649">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1224256">internationalIsdnNumber</a><P></A>
+<td>
+<A NAME="1107651">
+The person's ISDN number.<P></A>
+
+<tr><td>
+<A NAME="1070725">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1070727">
+Location at which the person resides.<P></A>
+
+<tr><td>
+<A NAME="1070731">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1070733">
+Organizational unit to which the person belongs.<P></A>
+
+<tr><td>
+<A NAME="1070736">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003072">physicalDeliveryOfficeName</a><P></A>
+<td>
+<A NAME="1070738">
+Location where physical deliveries can be made to this person.<P></A>
+
+<tr><td>
+<A NAME="1070741">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230025">postalAddress</a><P></A>
+<td>
+<A NAME="1070743">
+The person's mailing address.<P></A>
+
+<tr><td>
+<A NAME="1070746">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230036">postalCode</a><P></A>
+<td>
+<A NAME="1070748">
+The person's postal code (such as a United States zip code).<P></A>
+
+<tr><td>
+<A NAME="1070751">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230043">postOfficeBox</a><P></A>
+<td>
+<A NAME="1070753">
+The person's post office box.<P></A>
+
+<tr><td>
+<A NAME="1070756">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202605">preferredDeliveryMethod</a><P></A>
+<td>
+<A NAME="1070758">
+The person's preferred method of contact or delivery.<P></A>
+
+<tr><td>
+<A NAME="1107658">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202644">registeredAddress</a><P></A>
+<td>
+<A NAME="1107671">
+Postal address suitable for reception of expedited documents, where the recipient must verify delivery.<P></A>
+
+<tr><td>
+<A NAME="1070766">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1203417">st</a><P></A>
+<td>
+<A NAME="1070768">
+State or province in which the person resides.<P></A>
+
+<tr><td>
+<A NAME="1070771">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202721">street</a><P></A>
+<td>
+<A NAME="1070773">
+Street address at which the person is located.<P></A>
+
+<tr><td>
+<A NAME="1107723">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205004">teletexTerminalIdentifier</a><P></A>
+<td>
+<A NAME="1107725">
+Identifier for the teletex terminal of the organization.<P></A>
+
+<tr><td>
+<A NAME="1107716">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205120">telexNumber</a><P></A>
+<td>
+<A NAME="1107718">
+Telex number of the organization.<P></A>
+
+<tr><td>
+<A NAME="1107709">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1266248">title</a><P></A>
+<td>
+<A NAME="1107711">
+The person's job title.<P></A>
+
+<tr><td>
+<A NAME="1107702">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281763">x121Address</a><P></A>
+<td>
+<A NAME="1107704">
+X.121 address of the organization.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1088567"> 
+</A>
+<A NAME="organizationalRole">
+<H3> organizationalRole</H3>
+</A>
+
+
+
+<A NAME="1088568">
+Defines entries that represent roles held by people within an organization. This object class was inherited from X.500 Directory Services. <P></A>
+
+<A NAME="1096979">
+OID: <code>2.5.6.8</code><P></A>
+
+<A NAME="1088606">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1088571">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1088573">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1088576">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1088579">
+(Required) The role's common name.<P></A>
+
+<tr><td>
+<A NAME="1088588">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1088590">
+Text description of the role.<P></A>
+
+<tr><td>
+<A NAME="1088716">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1292809">destinationIndicator</a><P></A>
+<td>
+<A NAME="1088718">
+This attribute is used for telegram services to the person in this role.<P></A>
+
+<tr><td>
+<A NAME="1088780">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171637">facsimileTelephoneNumber</a><P></A>
+<td>
+<A NAME="1088782">
+Fax number of the person in the role.<P></A>
+
+<tr><td>
+<A NAME="1088726">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1224256">internationalIsdnNumber</a><P></A>
+<td>
+<A NAME="1088728">
+ISDN number of the person in the role.<P></A>
+
+<tr><td>
+<A NAME="1088806">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1088808">
+Location in which the person in the role resides.<P></A>
+
+<tr><td>
+<A NAME="1088812">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1088814">
+Organizational unit to which the person in the role belongs.<P></A>
+
+<tr><td>
+<A NAME="1088817">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003072">physicalDeliveryOfficeName</a><P></A>
+<td>
+<A NAME="1088819">
+Location where physical deliveries can be made to the person in this role.<P></A>
+
+<tr><td>
+<A NAME="1101602">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230025">postalAddress</a><P></A>
+<td>
+<A NAME="1088824">
+Business mailing address for the person in this role.<P></A>
+
+<tr><td>
+<A NAME="1101607">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230036">postalCode</a><P></A>
+<td>
+<A NAME="1088829">
+Business postal code (such as a United States zip code) for the person in this role.<P></A>
+
+<tr><td>
+<A NAME="1101612">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230043">postOfficeBox</a><P></A>
+<td>
+<A NAME="1088834">
+Business post office box for the person in this role.<P></A>
+
+<tr><td>
+<A NAME="1101617">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202605">preferredDeliveryMethod</a><P></A>
+<td>
+<A NAME="1088839">
+Preferred method of contact or delivery of the person in this role.<P></A>
+
+<tr><td>
+<A NAME="1088771">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202644">registeredAddress</a><P></A>
+<td>
+<A NAME="1106144">
+Postal address suitable for reception of expedited documents, where the recipient must verify delivery.<P></A>
+
+<tr><td>
+<A NAME="1088863">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202666">roleOccupant</a><P></A>
+<td>
+<A NAME="1088865">
+Distinguished name of the person in this role.<P></A>
+
+<tr><td>
+<A NAME="1088593">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1088595">
+URL to information relevant to the person in the role.<P></A>
+
+<tr><td>
+<A NAME="1101632">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1203417">st</a><P></A>
+<td>
+<A NAME="1088879">
+State or province in which the person in this role resides.<P></A>
+
+<tr><td>
+<A NAME="1101637">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202721">street</a><P></A>
+<td>
+<A NAME="1088884">
+Street address at which the person in this role is located.<P></A>
+
+<tr><td>
+<A NAME="1101642">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1088600">
+The person's telephone number.<P></A>
+
+<tr><td>
+<A NAME="1088888">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205004">teletexTerminalIdentifier</a><P></A>
+<td>
+<A NAME="1088890">
+Identifier for the teletex terminal of the person in this role.<P></A>
+
+<tr><td>
+<A NAME="1088937">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205120">telexNumber</a><P></A>
+<td>
+<A NAME="1088939">
+Telex number of the person in this role.<P></A>
+
+<tr><td>
+<A NAME="1088978">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281763">x121Address</a><P></A>
+<td>
+<A NAME="1088980">
+X.121 address of the person in this role.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089681"> 
+</A>
+<A NAME="person">
+<H3> person</H3>
+</A>
+
+
+
+<A NAME="1089682">
+Defines entries that generically represent people. This object class is the base class for the organizationalPerson object class. This object class was inherited from X.500 Directory Services. <P></A>
+
+<A NAME="1096975">
+OID: <code>2.5.6.6</code><P></A>
+
+<A NAME="1089720">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1089685">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1089687">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1089690">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1089693">
+(Required) The person's common name.<P></A>
+
+<tr><td>
+<A NAME="1089696">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1290325">sn</a><P></A>
+<td>
+<A NAME="1089699">
+(Required) The person's surname, or last name.<P></A>
+
+<tr><td>
+<A NAME="1089702">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1089704">
+Text description of the person.<P></A>
+
+<tr><td>
+<A NAME="1089707">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1089709">
+URL to information relevant to the person.<P></A>
+
+<tr><td>
+<A NAME="1089712">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1089714">
+The person's telephone number.<P></A>
+
+<tr><td>
+<A NAME="1089717">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1089719">
+Password with which the person can bind to the directory.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1106267"> 
+</A>
+<A NAME="residentialPerson">
+<H3> residentialPerson</H3>
+</A>
+
+
+
+<A NAME="1106268">
+Object class used by the Directory Server to contain a person's residential information. This object class was inherited from X.500 Directory Services.<P></A>
+
+<A NAME="1106269">
+OID: <code>2.5.6.10</code><P></A>
+
+<A NAME="1106387">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1106272">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1106274">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1106279">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1106281">
+(Required) Locality in which the person resides.<P></A>
+
+<tr><td>
+<A NAME="1106286">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1106288">
+Business in which the person is involved.<P></A>
+
+<tr><td>
+<A NAME="1106293">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1292809">destinationIndicator</a><P></A>
+<td>
+<A NAME="1106295">
+This attribute is used for telegram services to this person.<P></A>
+
+<tr><td>
+<A NAME="1106299">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171637">facsimileTelephoneNumber</a><P></A>
+<td>
+<A NAME="1106302">
+Fax number for the person.<P></A>
+
+<tr><td>
+<A NAME="1106307">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1224256">internationalIsdnNumber</a><P></A>
+<td>
+<A NAME="1106309">
+ISDN number of the person.<P></A>
+
+<tr><td>
+<A NAME="1106313">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003072">physicalDeliveryOfficeName</a><P></A>
+<td>
+<A NAME="1106316">
+Location where physical deliveries can be made.<P></A>
+
+<tr><td>
+<A NAME="1106321">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230025">postalAddress</a><P></A>
+<td>
+<A NAME="1106323">
+Business mailing address for the person.<P></A>
+
+<tr><td>
+<A NAME="1106328">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230036">postalCode</a><P></A>
+<td>
+<A NAME="1106330">
+Business postal code (such as a United States zip code) for the person.<P></A>
+
+<tr><td>
+<A NAME="1106335">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230043">postOfficeBox</a><P></A>
+<td>
+<A NAME="1106337">
+Business post office box for the person.<P></A>
+
+<tr><td>
+<A NAME="1106342">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202605">preferredDeliveryMethod</a><P></A>
+<td>
+<A NAME="1106344">
+Preferred method of contact or delivery of the person.<P></A>
+
+<tr><td>
+<A NAME="1106349">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202644">registeredAddress</a><P></A>
+<td>
+<A NAME="1106351">
+Postal address suitable for reception of expedited documents, where the recipient must verify delivery.<P></A>
+
+<tr><td>
+<A NAME="1106356">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1203417">st</a><P></A>
+<td>
+<A NAME="1106358">
+State or province in which the person resides.<P></A>
+
+<tr><td>
+<A NAME="1106363">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202721">street</a><P></A>
+<td>
+<A NAME="1106365">
+Street address at which the person is located.<P></A>
+
+<tr><td>
+<A NAME="1106370">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205004">teletexTerminalIdentifier</a><P></A>
+<td>
+<A NAME="1106372">
+Identifier for the teletex terminal of the person.<P></A>
+
+<tr><td>
+<A NAME="1106377">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205120">telexNumber</a><P></A>
+<td>
+<A NAME="1106379">
+Telex number of the person.<P></A>
+
+<tr><td>
+<A NAME="1106384">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281763">x121Address</a><P></A>
+<td>
+<A NAME="1106386">
+X.121 address of the person.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078660"> 
+</A>
+<A NAME="Calendar Server Extensions">
+<H2> Calendar Server Extensions</H2>
+</A>
+
+<A NAME="1081153">
+The following object classes are used by the Netscape Calendar Server. The object classes described here include <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078663">netscapeCalendarServer</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097420">nsCalAdmin</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1084445">nsCalResource</a>, and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078672">nsCalUser</a>.<P></A>
+
+
+<A NAME="1078663"> 
+</A>
+<A NAME="netscapeCalendarServer">
+<H3> netscapeCalendarServer</H3>
+</A>
+
+
+
+<A NAME="1078664">
+Object class used to store information about the Netscape Calendar Server in the directory. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1097056">
+OID: <code>2.16.840.1.113730.3.2.17</code><P></A>
+
+<A NAME="1107920">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1107742">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1107744">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1107749">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1107751">
+(Required) Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+<A NAME="1097417">
+<P></A>
+
+
+<A NAME="1097420"> 
+</A>
+<A NAME="nsCalAdmin">
+<H3> nsCalAdmin</H3>
+</A>
+
+
+
+<A NAME="1097421">
+Object class used by the Netscape Calendar Server to store information about the calendar server administrator in the directory. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1097052">
+OID: <code>2.16.840.1.113730.3.2.15</code><P></A>
+
+<A NAME="1084442">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1102028">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1102030">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108105">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108107">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1108100">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1102037">
+The administrator's common name.<P></A>
+
+<tr><td>
+<A NAME="1102042">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171637">facsimileTelephoneNumber</a><P></A>
+<td>
+<A NAME="1102044">
+The administrator's fax number.<P></A>
+
+<tr><td>
+<A NAME="1102049">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104309">generationQualifier</a><P></A>
+<td>
+<A NAME="1102051">
+Same as generation Qualifier in the Lightweight Internet Person Schema (LIPS).<P></A>
+
+<tr><td>
+<A NAME="1102056">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229534">givenName</a><P></A>
+<td>
+<A NAME="1102058">
+The administrator's given, or first name.<P></A>
+
+<tr><td>
+<A NAME="1102063">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229543">initials</a><P></A>
+<td>
+<A NAME="1102065">
+The administrator's initials.<P></A>
+
+<tr><td>
+<A NAME="1102193">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104932">nsCalAccess</a><P></A>
+<td>
+<A NAME="1102195">
+Defines whether the administrator should be allowed or denied access to the calendar server.<P></A>
+
+<tr><td>
+<A NAME="1102198">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1166044">nsCalAccessDomain</a><P></A>
+<td>
+<A NAME="1102200">
+Internet domain or IP address from which the calendar administrator is allowed to access calendar data. This attribute is reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1102203">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104994">nsCalAdmd</a><P></A>
+<td>
+<A NAME="1102205">
+X.400 Administration Management Domain Name of the administrator.<P></A>
+
+<tr><td>
+<A NAME="1102208">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1164493">nsCalFlags</a><P></A>
+<td>
+<A NAME="1102210">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1102213">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1157806">nsCalHost</a><P></A>
+<td>
+<A NAME="1102215">
+Hostname, or IP address, of the computer hosting the calendar administrator's information.<P></A>
+
+<tr><td>
+<A NAME="1102218">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105333">nsCalLanguageId</a><P></A>
+<td>
+<A NAME="1102220">
+Language in which the administrator prefers to receive email.<P></A>
+
+<tr><td>
+<A NAME="1102223">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1157846">nsCalNodeAlias</a><P></A>
+<td>
+<A NAME="1102225">
+Mnemonic name of the node on which the administrator's data is stored.<P></A>
+
+<tr><td>
+<A NAME="1102228">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105739">nsCalOrgUnit2</a><P></A>
+<td>
+<A NAME="1102230">
+X.400 Organization Unit 2 (OU2).<P></A>
+
+<tr><td>
+<A NAME="1102233">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105752">nsCalOrgUnit3</a><P></A>
+<td>
+<A NAME="1102235">
+X.400 Organization Unit 3 (OU3).<P></A>
+
+<tr><td>
+<A NAME="1102238">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105815">nsCalOrgUnit4</a><P></A>
+<td>
+<A NAME="1102240">
+X.400 Organization Unit 4 (OU4).<P></A>
+
+<tr><td>
+<A NAME="1102243">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105834">nsCalPasswordRequired</a><P></A>
+<td>
+<A NAME="1102245">
+Specifies whether a calendar administrator must supply a password to access calendar data.<P></A>
+
+<tr><td>
+<A NAME="1102248">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105891">nsCalPrmd</a><P></A>
+<td>
+<A NAME="1102250">
+X.400 Private Management Domain Name of the administrator.<P></A>
+
+<tr><td>
+<A NAME="1102253">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106093">nsCalServerVersion</a><P></A>
+<td>
+<A NAME="1102255">
+Version number of the calendar server hosting the calendar administrator's data.<P></A>
+
+<tr><td>
+<A NAME="1102258">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106115">nsCalSysopCanWritePassword</a><P></A>
+<td>
+<A NAME="1102260">
+Specifies if the calendar server administrator can overwrite user passwords.<P></A>
+
+<tr><td>
+<A NAME="1102263">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106218">nsCalXItemId</a><P></A>
+<td>
+<A NAME="1102265">
+Identification number of the node on which the calendar administrator's data is stored.<P></A>
+
+<tr><td>
+<A NAME="1102070">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1102072">
+Organizational unit to which the administrator belongs.<P></A>
+
+<tr><td>
+<A NAME="1102077">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230025">postalAddress</a><P></A>
+<td>
+<A NAME="1102079">
+The administrator's postal address.<P></A>
+
+<tr><td>
+<A NAME="1102084">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1290325">sn</a><P></A>
+<td>
+<A NAME="1102086">
+The administrator's surname or last name.<P></A>
+
+<tr><td>
+<A NAME="1102091">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1102093">
+The administrator's telephone number.<P></A>
+
+<tr><td>
+<A NAME="1102098">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1102100">
+The administrator's password.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1084445"> 
+</A>
+<A NAME="nsCalResource">
+<H3> nsCalResource</H3>
+</A>
+
+
+
+<A NAME="1084446">
+Object class used by the Netscape Calendar Server to store information about calendar resources, such as conference rooms, in the directory. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1097054">
+OID: <code>2.16.840.1.113730.3.2.16</code><P></A>
+
+<A NAME="1079532">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1079408">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1079410">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108114">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108116">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1102373">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1080905">
+The resource's common name.<P></A>
+
+<tr><td>
+<A NAME="1102378">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171637">facsimileTelephoneNumber</a><P></A>
+<td>
+<A NAME="1081264">
+Fax number associated with the resource.<P></A>
+
+<tr><td>
+<A NAME="1102455">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104932">nsCalAccess</a><P></A>
+<td>
+<A NAME="1083840">
+Defines whether the resource should be allowed or denied access to the calendar server.<P></A>
+
+<tr><td>
+<A NAME="1102460">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1166044">nsCalAccessDomain</a><P></A>
+<td>
+<A NAME="1083873">
+Internet domain or IP address from which the calendar resource is allowed to access calendar data. This attribute is reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1079434">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105005">nsCalDefaultNoteReminder</a><P></A>
+<td>
+<A NAME="1084773">
+Type (if any) of note reminder.<P></A>
+
+<tr><td>
+<A NAME="1079439">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1162428">nsCalDefaultReminder</a><P></A>
+<td>
+<A NAME="1084609">
+Type (if any) of event reminder.<P></A>
+
+<tr><td>
+<A NAME="1079444">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105139">nsCalDefaultTaskReminder</a><P></A>
+<td>
+<A NAME="1084642">
+Type (if any) of task reminder.<P></A>
+
+<tr><td>
+<A NAME="1079449">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105164">nsCalDisplayPrefs</a><P></A>
+<td>
+<A NAME="1084565">
+Display preferences for the resource.<P></A>
+
+<tr><td>
+<A NAME="1102485">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1164493">nsCalFlags</a><P></A>
+<td>
+<A NAME="1079456">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1102490">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1157806">nsCalHost</a><P></A>
+<td>
+<A NAME="1083661">
+Hostname, or IP address, of the computer hosting the calendar resource's information.<P></A>
+
+<tr><td>
+<A NAME="1102495">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105333">nsCalLanguageId</a><P></A>
+<td>
+<A NAME="1085033">
+Language in which the person responsible for the resource prefers to receive email notification.<P></A>
+
+<tr><td>
+<A NAME="1102500">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1157846">nsCalNodeAlias</a><P></A>
+<td>
+<A NAME="1083631">
+Mnemonic name of the node on which the resource's data is stored.<P></A>
+
+<tr><td>
+<A NAME="1079474">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118755">nsCalNotifMechanism</a><P></A>
+<td>
+<A NAME="1079476">
+Mechanism used to notify event attendees (usually email).<P></A>
+
+<tr><td>
+<A NAME="1079479">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105631">nsCalOperatingPrefs</a><P></A>
+<td>
+<A NAME="1084552">
+Operating preferences for the resource. Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1079613">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105834">nsCalPasswordRequired</a><P></A>
+<td>
+<A NAME="1084950">
+Specifies whether a calendar user must supply a password to access calendar data about this resource.<P></A>
+
+<tr><td>
+<A NAME="1079509">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105943">nsCalRefreshPrefs</a><P></A>
+<td>
+<A NAME="1079511">
+Defines whether the resource's preferences should be refreshed and how often.<P></A>
+
+<tr><td>
+<A NAME="1079626">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105996">nsCalResourceCapacity</a><P></A>
+<td>
+<A NAME="1079619">
+Capacity of the resource, such as maximum room occupancy.<P></A>
+
+<tr><td>
+<A NAME="1079631">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1209242">nsCalResourceNumber</a><P></A>
+<td>
+<A NAME="1079623">
+The resource's identification number.<P></A>
+
+<tr><td>
+<A NAME="1079514">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106093">nsCalServerVersion</a><P></A>
+<td>
+<A NAME="1083778">
+Version number of the calendar server hosting the calendar resource's data.<P></A>
+
+<tr><td>
+<A NAME="1079519">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106115">nsCalSysopCanWritePassword</a><P></A>
+<td>
+<A NAME="1085009">
+Specifies if the calendar server administrator can overwrite the resource's password.<P></A>
+
+<tr><td>
+<A NAME="1079524">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106160">nsCalTimezone</a><P></A>
+<td>
+<A NAME="1079526">
+The current timezone in which the resource is located.<P></A>
+
+<tr><td>
+<A NAME="1079529">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106218">nsCalXItemId</a><P></A>
+<td>
+<A NAME="1084486">
+Identification number of the node on which the calendar resource's data is stored.<P></A>
+
+<tr><td>
+<A NAME="1102416">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230025">postalAddress</a><P></A>
+<td>
+<A NAME="1102418">
+Postal address of the resource.<P></A>
+
+<tr><td>
+<A NAME="1102409">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1102411">
+The resource's telephone number.<P></A>
+
+<tr><td>
+<A NAME="1102402">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1102404">
+Reserved for future use.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078672"> 
+</A>
+<A NAME="nsCalUser">
+<H3> nsCalUser</H3>
+</A>
+
+
+
+<A NAME="1078673">
+Object class used by the Netscape Calendar Server to store information about calendar users in the directory. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1097050">
+OID: <code>2.16.840.1.113730.3.2.14</code><P></A>
+
+<A NAME="1078727">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078677">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078679">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108154">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108156">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1078683">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104309">generationQualifier</a><P></A>
+<td>
+<A NAME="1078686">
+Same as generation Qualifier in the Lightweight Internet Person Schema (LIPS).<P></A>
+
+<tr><td>
+<A NAME="1102672">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104932">nsCalAccess</a><P></A>
+<td>
+<A NAME="1083848">
+Defines whether the user should be allowed or denied access to the calendar server.<P></A>
+
+<tr><td>
+<A NAME="1102677">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1166044">nsCalAccessDomain</a><P></A>
+<td>
+<A NAME="1078696">
+Internet domain or IP address from which the calendar user is allowed to access calendar data. This attribute is reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1102682">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104994">nsCalAdmd</a><P></A>
+<td>
+<A NAME="1083983">
+X.400 Administration Management Domain Name of the user.<P></A>
+
+<tr><td>
+<A NAME="1102697">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105005">nsCalDefaultNoteReminder</a><P></A>
+<td>
+<A NAME="1084798">
+Type (if any) of note reminder.<P></A>
+
+<tr><td>
+<A NAME="1102702">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1162428">nsCalDefaultReminder</a><P></A>
+<td>
+<A NAME="1078711">
+Type (if any) of event reminder.<P></A>
+
+<tr><td>
+<A NAME="1102707">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105139">nsCalDefaultTaskReminder</a><P></A>
+<td>
+<A NAME="1084619">
+Type (if any) of task reminder.<P></A>
+
+<tr><td>
+<A NAME="1102712">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105164">nsCalDisplayPrefs</a><P></A>
+<td>
+<A NAME="1078721">
+Display preferences for the user.<P></A>
+
+<tr><td>
+<A NAME="1102717">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1164493">nsCalFlags</a><P></A>
+<td>
+<A NAME="1078726">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1102722">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1157806">nsCalHost</a><P></A>
+<td>
+<A NAME="1083672">
+Hostname, or IP address, of the computer hosting the calendar user's information.<P></A>
+
+<tr><td>
+<A NAME="1102727">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105333">nsCalLanguageId</a><P></A>
+<td>
+<A NAME="1085040">
+Language in which the user prefers to receive email.<P></A>
+
+<tr><td>
+<A NAME="1102732">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1157846">nsCalNodeAlias</a><P></A>
+<td>
+<A NAME="1083651">
+Mnemonic name of the node on which the user's data is stored.<P></A>
+
+<tr><td>
+<A NAME="1102737">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118755">nsCalNotifMechanism</a><P></A>
+<td>
+<A NAME="1084582">
+Mechanism used to notify event attendees (usually email).<P></A>
+
+<tr><td>
+<A NAME="1102742">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105631">nsCalOperatingPrefs</a><P></A>
+<td>
+<A NAME="1078828">
+Operating preferences for the user. Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1078821">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105739">nsCalOrgUnit2</a><P></A>
+<td>
+<A NAME="1078823">
+X.400 Organization Unit 2 (OU2).<P></A>
+
+<tr><td>
+<A NAME="1078816">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105752">nsCalOrgUnit3</a><P></A>
+<td>
+<A NAME="1083904">
+X.400 Organization Unit 3 (OU3).<P></A>
+
+<tr><td>
+<A NAME="1078811">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105815">nsCalOrgUnit4</a><P></A>
+<td>
+<A NAME="1083922">
+X.400 Organization Unit 4 (OU4).<P></A>
+
+<tr><td>
+<A NAME="1102762">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105834">nsCalPasswordRequired</a><P></A>
+<td>
+<A NAME="1082746">
+Specifies whether the user must supply a password to access calendar data.<P></A>
+
+<tr><td>
+<A NAME="1102767">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105891">nsCalPrmd</a><P></A>
+<td>
+<A NAME="1083961">
+X.400 Private Management Domain Name of the user.<P></A>
+
+<tr><td>
+<A NAME="1078796">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1105943">nsCalRefreshPrefs</a><P></A>
+<td>
+<A NAME="1084526">
+Defines whether the user's calendar information should be refreshed and how often.<P></A>
+
+<tr><td>
+<A NAME="1078791">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106093">nsCalServerVersion</a><P></A>
+<td>
+<A NAME="1083785">
+Version number of the calendar server hosting the calendar user's data.<P></A>
+
+<tr><td>
+<A NAME="1078786">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106115">nsCalSysopCanWritePassword</a><P></A>
+<td>
+<A NAME="1085016">
+Specifies if the calendar server administrator can overwrite the user's password.<P></A>
+
+<tr><td>
+<A NAME="1078781">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106160">nsCalTimezone</a><P></A>
+<td>
+<A NAME="1085063">
+The user's current timezone.<P></A>
+
+<tr><td>
+<A NAME="1078836">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1106218">nsCalXItemId</a><P></A>
+<td>
+<A NAME="1084493">
+Identification number of the node on which the calendar user's data is stored.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078479"> 
+</A>
+<A NAME="Certificate Server Extensions">
+<H2> Certificate Server Extensions</H2>
+</A>
+
+<A NAME="1080510">
+This section describes the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078501">netscapeCertificateServer</a> object class used by the Netscape Certificate Server.<P></A>
+
+
+<A NAME="1078501"> 
+</A>
+<A NAME="netscapeCertificateServer">
+<H3> netscapeCertificateServer</H3>
+</A>
+
+
+
+<A NAME="1078564">
+Object class used to store information about the Netscape Certificate Server in the directory. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1097058">
+OID: <code>2.16.840.1.113730.3.2.18</code><P></A>
+
+<A NAME="1108183">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108173">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108175">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108180">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108182">
+(Required) Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078576"> 
+</A>
+<A NAME="Collabra Server Extensions">
+<H2> Collabra Server Extensions</H2>
+</A>
+
+<A NAME="1080748">
+The object classes in this section are used by the Netscape Collabra Server. The object classes described here include <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078579">netscapeNewsServer</a> and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078583">nginfo</a>.<P></A>
+
+
+<A NAME="1078579"> 
+</A>
+<A NAME="netscapeNewsServer">
+<H3> netscapeNewsServer</H3>
+</A>
+
+
+
+<A NAME="1108221">
+Object class used to store information about the Netscape Collabra Server in the directory. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1097154">
+OID: <code>2.16.840.1.113730.3.2.27</code><P></A>
+
+<A NAME="1108205">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108195">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108197">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108202">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108204">
+(Required) Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078583"> 
+</A>
+<A NAME="nginfo">
+<H3> nginfo</H3>
+</A>
+
+
+
+<A NAME="1078584">
+Object class used by the Netscape Collabra Server to store discussion (news) group information. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1098802">
+OID: <code>2.16.840.1.113730.3.2.26</code><P></A>
+
+<A NAME="1105306">
+Object classes of this type are stored in a separate subtree under <I>ou=Netscape Servers</I>. The branch point is represented by the ngcomponent=. entry. Thus, if your directory's suffix is <I>o=Example.com</I>, then all discussion group information is stored in the subtree:<P></A>
+<PRE><A NAME="1078586">
+<I>ngcomponent=., o=Example.com</I>
+</A>
+</PRE>
+<A NAME="1078587">
+This subtree and it's contents are written to the directory by the Collabra server. The structure of this tree, the format and usage of the <code>nginfo</code> object class, and the format and usage of the <code>nginfo</code> attributes are subject to change without notice.<P></A>
+
+<A NAME="1078640">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078590">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078592">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1078596">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1095332">ngcomponent</a><P></A>
+<td>
+<A NAME="1078599">
+(Required) A single part of the discussion group's name.<P></A>
+
+<tr><td>
+<A NAME="1108256">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108258">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1078602">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1078604">
+Text description of the discussion group.<P></A>
+
+<tr><td>
+<A NAME="1103112">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1036977">nsaclrole</a><P></A>
+<td>
+<A NAME="1103114">
+Access permissions set for the various Collabra roles.<P></A>
+
+<tr><td>
+<A NAME="1103119">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1037693">nscreator</a><P></A>
+<td>
+<A NAME="1103121">
+User ID of the discussion group's creator.<P></A>
+
+<tr><td>
+<A NAME="1103133">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1037564">nsflags</a><P></A>
+<td>
+<A NAME="1103135">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1103140">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1092030">nsnewsACL</a><P></A>
+<td>
+<A NAME="1103142">
+Access control set for the discussion group.<P></A>
+
+<tr><td>
+<A NAME="1078627">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1037277">nsprettyname</a><P></A>
+<td>
+<A NAME="1078629">
+The discussion group's name.<P></A>
+
+<tr><td>
+<A NAME="1108272">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1099985">subtreeACI</a><P></A>
+<td>
+<A NAME="1108274">
+Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078655"> 
+</A>
+<A NAME="Compass Server Extensions">
+<H2> Compass Server Extensions</H2>
+</A>
+
+<A NAME="1080778">
+The object classes in this section are used by the Netscape Compass Server. The object classes described here include <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1080497">netscapeCompassServer</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1079636">personalInterestProfile</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1080358">PIPUser</a>, and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1080065">PIPUserInfo</a>.<P></A>
+
+
+<A NAME="1080497"> 
+</A>
+<A NAME="netscapeCompassServer">
+<H3> netscapeCompassServer</H3>
+</A>
+
+
+
+<A NAME="1080498">
+Object class used to store information about the Netscape Compass Server in the directory. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1097064">
+OID: <code>2.16.840.1.113730.3.2.19</code><P></A>
+
+<A NAME="1108299">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108289">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108291">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108296">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108298">
+(Required) Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1079636"> 
+</A>
+<A NAME="personalInterestProfile">
+<H3> personalInterestProfile</H3>
+</A>
+
+
+
+<A NAME="1082056">
+Object class used by the Netscape Compass Server to store personal interest profile information for Compass server users. For more information on personal interest profiles, see the Netscape Compass Server Administrator's Guide. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1097066">
+OID: <code>2.16.840.1.113730.3.2.20</code><P></A>
+
+<A NAME="1079693">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1079643">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1079645">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108309">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108311">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1079649">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1110777">pipuid</a><P></A>
+<td>
+<A NAME="1079652">
+(Required) User ID of the person to whom this profile belongs.<P></A>
+
+<tr><td>
+<A NAME="1079655">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1107663">pipuniqueid</a><P></A>
+<td>
+<A NAME="1088167">
+Unique ID of the user to whom this profile belongs.<P></A>
+
+<tr><td>
+<A NAME="1079660">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1114647">pipstatus</a><P></A>
+<td>
+<A NAME="1079662">
+Defines whether the profile is enabled or disabled.<P></A>
+
+<tr><td>
+<A NAME="1079665">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1108439">pipusertype</a><P></A>
+<td>
+<A NAME="1079667">
+Type of user to whom this profile belongs.<P></A>
+
+<tr><td>
+<A NAME="1079670">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1116521">pipstfrequency</a><P></A>
+<td>
+<A NAME="1079672">
+Describes how often the user receives "My Compass" newsletters with category updates.<P></A>
+
+<tr><td>
+<A NAME="1079675">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1111582">pipmedium</a><P></A>
+<td>
+<A NAME="1079677">
+Medium used to send information to the user about updates on free text search profiles.<P></A>
+
+<tr><td>
+<A NAME="1108316">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1111357">pipformat</a><P></A>
+<td>
+<A NAME="1108318">
+Format of the free text search profile update sent to the user.<P></A>
+
+<tr><td>
+<A NAME="1079680">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1246341">pipfrequency</a><P></A>
+<td>
+<A NAME="1079682">
+Attribute used by the compass server to describe how often a user receives "My Compass" newsletters with free text search updates.<P></A>
+
+<tr><td>
+<A NAME="1079685">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1111369">piphour</a><P></A>
+<td>
+<A NAME="1079687">
+Hours during the day that the user receives free text search profile updates.<P></A>
+
+<tr><td>
+<A NAME="1079690">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1246650">pipmaxhits</a><P></A>
+<td>
+<A NAME="1079692">
+Maximum number of documents returned for each free text search profile update.<P></A>
+
+<tr><td>
+<A NAME="1086287">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1111729">pipresultset</a><P></A>
+<td>
+<A NAME="1079792">
+List of attributes about which the user wants to receive updates.<P></A>
+
+<tr><td>
+<A NAME="1079799">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1111947">pipsortorder</a><P></A>
+<td>
+<A NAME="1079788">
+Sort order of the information in the summary report of the free text search profile update.<P></A>
+
+<tr><td>
+<A NAME="1079802">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1117682">piptimestamp</a><P></A>
+<td>
+<A NAME="1079784">
+Date the free text search profile was last updated for this user.<P></A>
+
+<tr><td>
+<A NAME="1079805">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1113479">pipirlist</a><P></A>
+<td>
+<A NAME="1105425">
+Domains and newsgroups the user wishes to monitor.<P></A>
+
+<tr><td>
+<A NAME="1079808">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1237828">pipiroption</a><P></A>
+<td>
+<A NAME="1079776">
+Defines whether or not all entries in pipirlist should be updated or excluded from updates.<P></A>
+
+<tr><td>
+<A NAME="1079811">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1112443">pippwp</a><P></A>
+<td>
+<A NAME="1079772">
+Address of the Personal Web Page (PWP) database.<P></A>
+
+<tr><td>
+<A NAME="1079814">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1112574">piplastcount</a><P></A>
+<td>
+<A NAME="1079768">
+Number of matches that occurred during the last update.<P></A>
+
+<tr><td>
+<A NAME="1079817">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1237470">piptotalcount</a><P></A>
+<td>
+<A NAME="1082119">
+Number of matches that occurred during all updates to date.<P></A>
+
+<tr><td>
+<A NAME="1079820">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1112780">piptotalrun</a><P></A>
+<td>
+<A NAME="1079760">
+Total number of updates to date.<P></A>
+
+<tr><td>
+<A NAME="1079824">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1236460">pipnotify</a><P></A>
+<td>
+<A NAME="1079756">
+Undefined.<P></A>
+
+<tr><td>
+<A NAME="1079827">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1236511">pipprivilege</a><P></A>
+<td>
+<A NAME="1079752">
+Undefined.<P></A>
+
+<tr><td>
+<A NAME="1086357">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1113190">pipgroup</a><P></A>
+<td>
+<A NAME="1079748">
+Undefined.<P></A>
+
+<tr><td>
+<A NAME="1086370">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1237689">pipidstcount</a><P></A>
+<td>
+<A NAME="1082159">
+Last unique ID used by the user.<P></A>
+
+<tr><td>
+<A NAME="1086382">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1115462">pipstid</a><P></A>
+<td>
+<A NAME="1079861">
+Unique ID of a search topic included in the profile.<P></A>
+
+<tr><td>
+<A NAME="1079875">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1115468">pipstname</a><P></A>
+<td>
+<A NAME="1079857">
+Arbitrary name created by the user to describe a search topic.<P></A>
+
+<tr><td>
+<A NAME="1079878">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1115474">pipstquery</a><P></A>
+<td>
+<A NAME="1079853">
+Undefined.<P></A>
+
+<tr><td>
+<A NAME="1079881">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1115480">pipsttaxonomy</a><P></A>
+<td>
+<A NAME="1079849">
+Taxonomy ID of a search topic.<P></A>
+
+<tr><td>
+<A NAME="1079884">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1115769">pipstinterest</a><P></A>
+<td>
+<A NAME="1099692">
+Describes the importance to the user of each individual search topic. (This attribute is used with Netscape Compass Server Professional only.)<P></A>
+
+<tr><td>
+<A NAME="1079887">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1116285">pipsttype</a><P></A>
+<td>
+<A NAME="1079841">
+Defines whether a search is a category search or a free text search.<P></A>
+
+<tr><td>
+<A NAME="1079890">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1115898">pipstprivacy</a><P></A>
+<td>
+<A NAME="1079837">
+Defines whether queries of this entry should be allowed or disallowed.<P></A>
+
+<tr><td>
+<A NAME="1079955">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1116027">pipststatus</a><P></A>
+<td>
+<A NAME="1079950">
+Status of the personal interest profile.<P></A>
+
+<tr><td>
+<A NAME="1079958">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1237172">pipstlastcount</a><P></A>
+<td>
+<A NAME="1079946">
+Number of category matches during the last update.<P></A>
+
+<tr><td>
+<A NAME="1079961">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1115516">pipsttotalcount</a><P></A>
+<td>
+<A NAME="1082234">
+Number of category matches to date.<P></A>
+
+<tr><td>
+<A NAME="1079964">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1115522">pipsttotalrun</a><P></A>
+<td>
+<A NAME="1082240">
+Number of category search updates performed to date.<P></A>
+
+<tr><td>
+<A NAME="1079967">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1116402">pipstcategory</a><P></A>
+<td>
+<A NAME="1079934">
+Categories or search strings the user is interested in.<P></A>
+
+<tr><td>
+<A NAME="1079970">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1116521">pipstfrequency</a><P></A>
+<td>
+<A NAME="1079930">
+Frequency that the user receives category update alerts.<P></A>
+
+<tr><td>
+<A NAME="1079973">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1117140">pipstmedium</a><P></A>
+<td>
+<A NAME="1096703">
+Medium used to send information to the user about updates on category search profiles.<P></A>
+
+<tr><td>
+<A NAME="1079976">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1116837">pipstformat</a><P></A>
+<td>
+<A NAME="1082369">
+Format of the category search profile update sent to the user.<P></A>
+
+<tr><td>
+<A NAME="1079979">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1116707">pipsthour</a><P></A>
+<td>
+<A NAME="1082375">
+Hours during the day that the user receives free category profile updates.<P></A>
+
+<tr><td>
+<A NAME="1079982">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1117134">pipstmaxhits</a><P></A>
+<td>
+<A NAME="1082402">
+Maximum number of documents returned for each category search profile update.<P></A>
+
+<tr><td>
+<A NAME="1079985">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1117321">pipstresultset</a><P></A>
+<td>
+<A NAME="1082414">
+List of categories about which the user wants to receive updates.<P></A>
+
+<tr><td>
+<A NAME="1079988">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1117327">pipstsortorder</a><P></A>
+<td>
+<A NAME="1082427">
+Sort order of the information in the summary report of the category search profile update.<P></A>
+
+<tr><td>
+<A NAME="1079991">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1117445">pipsttimestamp</a><P></A>
+<td>
+<A NAME="1082432">
+Date the category search profile was last updated for this user.<P></A>
+
+<tr><td>
+<A NAME="1079994">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1117562">pipstirlist</a><P></A>
+<td>
+<A NAME="1082443">
+Domains and newsgroups the user wants to monitor.<P></A>
+
+<tr><td>
+<A NAME="1079997">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1117790">pipstiroption</a><P></A>
+<td>
+<A NAME="1082447">
+Defines whether or not all entries in pipstirlist will be updated or excluded from category updates.<P></A>
+
+<tr><td>
+<A NAME="1080036">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118693">pipreservedces1</a><P></A>
+<td>
+<A NAME="1080033">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1080041">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118699">pipreservedces2</a><P></A>
+<td>
+<A NAME="1082335">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1080044">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118705">pipreservedces3</a><P></A>
+<td>
+<A NAME="1080025">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1080047">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118350">pipreservedcis1</a><P></A>
+<td>
+<A NAME="1080021">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1080050">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118356">pipreservedcis2</a><P></A>
+<td>
+<A NAME="1080017">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1080053">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118362">pipreservedcis3</a><P></A>
+<td>
+<A NAME="1080013">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1080056">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118368">pipreservedcis4</a><P></A>
+<td>
+<A NAME="1080009">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1080059">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118374">pipreservedcis5</a><P></A>
+<td>
+<A NAME="1080005">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1080062">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118380">pipreservedcis6</a><P></A>
+<td>
+<A NAME="1080001">
+Reserved for future use.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1080358"> 
+</A>
+<A NAME="PIPUser">
+<H3> PIPUser</H3>
+</A>
+
+
+
+<A NAME="1082531">
+Object class used by the Netscape Compass Server to contain information about Personal Interest Profile (PIP) users. This object class is a Netscape extension to the standard LDAP schema. For more information about PIPs, see the Netscape Compass Server Administrator's Guide. Reserved for future use.<P></A>
+
+<A NAME="1097068">
+OID: <code>2.16.840.1.113730.3.2.22</code><P></A>
+
+<A NAME="1080396">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1080362">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1080364">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108446">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108448">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1086592">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1246531">pipcompassservers</a><P></A>
+<td>
+<A NAME="1080405">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1086632">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118693">pipreservedces1</a><P></A>
+<td>
+<A NAME="1080442">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1086637">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118699">pipreservedces2</a><P></A>
+<td>
+<A NAME="1080447">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1086642">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118705">pipreservedces3</a><P></A>
+<td>
+<A NAME="1080452">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1086647">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118350">pipreservedcis1</a><P></A>
+<td>
+<A NAME="1080457">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1086652">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118356">pipreservedcis2</a><P></A>
+<td>
+<A NAME="1080462">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1086657">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118362">pipreservedcis3</a><P></A>
+<td>
+<A NAME="1080467">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1086662">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118368">pipreservedcis4</a><P></A>
+<td>
+<A NAME="1080484">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1086667">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118374">pipreservedcis5</a><P></A>
+<td>
+<A NAME="1080489">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1086672">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1118380">pipreservedcis6</a><P></A>
+<td>
+<A NAME="1080494">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1108453">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1107663">pipuniqueid</a><P></A>
+<td>
+<A NAME="1108455">
+Unique ID of the user.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1080065"> 
+</A>
+<A NAME="PIPUserInfo">
+<H3> PIPUserInfo</H3>
+</A>
+
+
+
+<A NAME="1080066">
+Object class used by the Netscape Compass Server to contain information about Personal Interest Profile (PIP) users that do not have a user ID. This object class is a Netscape extension to the standard LDAP schema. For more information about PIPs, see the Netscape Compass Server Administrator's Guide. Reserved for future use.<P></A>
+
+<A NAME="1097070">
+OID: <code>2.16.840.1.113730.3.2.21</code><P></A>
+
+<A NAME="1097227">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1105721">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1105723">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1105728">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1105730">
+(Required) The user's common name.<P></A>
+
+<tr><td>
+<A NAME="1108460">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108462">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1105735">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1105737">
+Freeform description of the user.<P></A>
+
+<tr><td>
+<A NAME="1105763">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1189404">mail</a><P></A>
+<td>
+<A NAME="1105765">
+Email address of the user.<P></A>
+
+<tr><td>
+<A NAME="1105742">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1246531">pipcompassservers</a><P></A>
+<td>
+<A NAME="1105744">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1105749">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1107663">pipuniqueid</a><P></A>
+<td>
+<A NAME="1105751">
+Unique ID of the user.<P></A>
+
+<tr><td>
+<A NAME="1105756">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1105758">
+The user's password.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097229"> 
+</A>
+<A NAME="Directory Server Extensions">
+<H2> Directory Server Extensions</H2>
+</A>
+
+<A NAME="1077861">
+The following object classes are used by the Netscape Directory Server. The object classes described here include <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1077794">changeLogEntry</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1100614">cirReplicaSource</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1098555">groupOfCertificates</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1106267">residentialPerson</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078109">netscapeMachineData</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097231">netscapeServer</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1100862">nsLicenseUser</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1100399">NTGroup</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1081708">passwordObject</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1081724">passwordPolicy</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097669">referral</a>, and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097986">subschema</a>.<P></A>
+
+
+<A NAME="1077794"> 
+</A>
+<A NAME="changeLogEntry">
+<H3> changeLogEntry</H3>
+</A>
+
+
+
+<A NAME="1077795">
+Object class used by the Netscape Directory Server to represent a change made to its directory. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1098541">
+OID: <code>2.16.840.1.113730.3.2.1</code><P></A>
+
+<A NAME="1077846">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1077798">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1077800">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1077816">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1094798">changeNumber</a><P></A>
+<td>
+<A NAME="1077819">
+(Required) Arbitrarily assigned number to the changelog.<P></A>
+
+<tr><td>
+<A NAME="1108478">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1095285">changeTime</a><P></A>
+<td>
+<A NAME="1108480">
+(Required) The time a change took place.<P></A>
+
+<tr><td>
+<A NAME="1077822">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1094968">changeType</a><P></A>
+<td>
+<A NAME="1077825">
+(Required) Type of change performed on an entry.<P></A>
+
+<tr><td>
+<A NAME="1108471">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1094954">targetDn</a><P></A>
+<td>
+<A NAME="1108473">
+(Required) Distinguished name of an entry that was added, modified, or deleted on a supplier server.<P></A>
+
+<tr><td>
+<A NAME="1077828">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1095277">changes</a><P></A>
+<td>
+<A NAME="1077830">
+Changes made to a Directory Server.<P></A>
+
+<tr><td>
+<A NAME="1077833">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1095547">deleteOldRdn</a><P></A>
+<td>
+<A NAME="1077835">
+A flag that defines whether the old Relative Distinguished Name (RDN) of the entry should be retained as a distinguished attribute of the entry, or should be deleted.<P></A>
+
+<tr><td>
+<A NAME="1098195">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1266221">filterInfo</a><P></A>
+<td>
+<A NAME="1098197">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1077838">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1278579">newRdn</a><P></A>
+<td>
+<A NAME="1077840">
+New RDN of an entry that is the target of a modRDN or modDN operation.<P></A>
+
+<tr><td>
+<A NAME="1077843">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1126531">newSuperior</a><P></A>
+<td>
+<A NAME="1077845">
+Name of the entry that becomes the immediate superior of the existing entry, when processing a modDN operation.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1098555"> 
+</A>
+<A NAME="groupOfCertificates">
+<H3> groupOfCertificates</H3>
+</A>
+
+
+
+<A NAME="1098563">
+Object class used by the Netscape Directory Server to contain information about a group of X.509 certificates. Any certificate that matches the values in <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1152959">memberCertificateDescription</a> is considered to be a member of the group. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1098564">
+OID: <code>2.16.840.1.113730.3.2.31</code><P></A>
+
+<A NAME="1081487">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1081442">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1081444">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1081448">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1081451">
+(Required) The group's common name.<P></A>
+
+<tr><td>
+<A NAME="1081454">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1082983">
+Business in which the group is involved.<P></A>
+
+<tr><td>
+<A NAME="1081459">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1081461">
+Freeform description of the group.<P></A>
+
+<tr><td>
+<A NAME="1081464">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1152959">memberCertificateDescription</a><P></A>
+<td>
+<A NAME="1081466">
+Values used to determine if a particular certificate is a member of this group.<P></A>
+
+<tr><td>
+<A NAME="1081469">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1081471">
+Organization that controls the group of certificates.<P></A>
+
+<tr><td>
+<A NAME="1081474">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1081476">
+Organizational unit to which the group belongs.<P></A>
+
+<tr><td>
+<A NAME="1081479">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005719">owner</a><P></A>
+<td>
+<A NAME="1081481">
+The group's owner.<P></A>
+
+<tr><td>
+<A NAME="1081484">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1081486">
+URL to information relevant to the group.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089068"> 
+</A>
+<A NAME="netscapeDirectoryServer">
+<H3> netscapeDirectoryServer</H3>
+</A>
+
+
+
+<A NAME="1089069">
+Object class used to store information about the Netscape Directory Server in the directory. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1097076">
+OID: <code>2.16.840.1.113730.3.2.23</code><P></A>
+
+<A NAME="1108594">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108584">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108586">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108591">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108593">
+(Required) Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078109"> 
+</A>
+<A NAME="netscapeMachineData">
+<H3> netscapeMachineData</H3>
+</A>
+
+
+
+<A NAME="1097236">
+Object class used by the Netscape Directory Server to distinguish between machine data and non-machine data. Machine data is filtered out during replication. This object class is a Netscape extension to the standard LDAP schema. Reserved.<P></A>
+
+<A NAME="1097237">
+OID: <code>2.16.840.1.113730.3.2.32</code><P></A>
+
+
+<A NAME="1097231"> 
+</A>
+<A NAME="netscapeServer">
+<H3> netscapeServer</H3>
+</A>
+
+
+
+<A NAME="1098570">
+Object class that identifies entries used by Netscape servers when they bind to the directory. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1098571">
+OID: <code>2.16.840.1.113730.3.2.10</code><P></A>
+
+<A NAME="1078166">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078113">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078115">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1078118">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1078121">
+(Required) The server's common name.<P></A>
+
+<tr><td>
+<A NAME="1103187">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1032956">administratorContactInfo</a><P></A>
+<td>
+<A NAME="1103189">
+URL to information relevant to the person responsible for administering the Netscape server.<P></A>
+
+<tr><td>
+<A NAME="1103192">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1098448">adminUrl</a><P></A>
+<td>
+<A NAME="1103194">
+URL to the administration server under which the Netscape server is running.<P></A>
+
+<tr><td>
+<A NAME="1078124">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1078126">
+Text description of the server.<P></A>
+
+<tr><td>
+<A NAME="1103205">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1032705">installationTimeStamp</a><P></A>
+<td>
+<A NAME="1103207">
+Time when the Netscape server was installed.<P></A>
+
+<tr><td>
+<A NAME="1078137">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1093065">serverHostName</a><P></A>
+<td>
+<A NAME="1078139">
+Hostname on which the Netscape server is installed.<P></A>
+
+<tr><td>
+<A NAME="1078143">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1032412">serverProductName</a><P></A>
+<td>
+<A NAME="1078145">
+Netscape server's product name.<P></A>
+
+<tr><td>
+<A NAME="1103220">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1032294">serverRoot</a><P></A>
+<td>
+<A NAME="1103222">
+Path to the server's installation root.<P></A>
+
+<tr><td>
+<A NAME="1108651">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1032439">serverVersionNumber</a><P></A>
+<td>
+<A NAME="1108653">
+Netscape server's version number.<P></A>
+
+<tr><td>
+<A NAME="1078148">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1078150">
+Contains a password for the server.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1081708"> 
+</A>
+<A NAME="passwordObject">
+<H3> passwordObject</H3>
+</A>
+
+
+
+<A NAME="1098598">
+Object class that contains password information for a user in the directory. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1098599">
+OID: <code>2.16.840.1.113730.3.2.12</code><P></A>
+
+<A NAME="1081721">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1081712">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1081714">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108661">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108663">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1103292">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104078">accountUnlockTime</a><P></A>
+<td>
+<A NAME="1103294">
+When the user account will be unlocked.<P></A>
+
+<tr><td>
+<A NAME="1108668">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1103904">passwordExpirationTime</a><P></A>
+<td>
+<A NAME="1108670">
+When the user's password expires.<P></A>
+
+<tr><td>
+<A NAME="1081718">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1293088">passwordExpWarned</a><P></A>
+<td>
+<A NAME="1081720">
+Used by the Directory Server to keep track of password expiration warnings sent to a user.<P></A>
+
+<tr><td>
+<A NAME="1103273">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104144">passwordHistory</a><P></A>
+<td>
+<A NAME="1103275">
+Password history of the user.<P></A>
+
+<tr><td>
+<A NAME="1083145">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1103999">passwordRetryCount</a><P></A>
+<td>
+<A NAME="1083110">
+Password failure count for the user.<P></A>
+
+<tr><td>
+<A NAME="1083153">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1152805">retryCountResetTime</a><P></A>
+<td>
+<A NAME="1083106">
+Describes when the passwordRetryCount should be reset to zero (0).<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1081724"> 
+</A>
+<A NAME="passwordPolicy">
+<H3> passwordPolicy</H3>
+</A>
+
+
+
+<A NAME="1098606">
+Object class that contains the password policy for all users in the entire directory. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1098607">
+OID: <code>2.16.840.1.113730.3.2.13</code><P></A>
+
+<A NAME="1081725">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1103339">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1103341">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108677">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108679">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1103461">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1157269">passwordChange</a><P></A>
+<td>
+<A NAME="1103463">
+Defines whether users must, may, or cannot change passwords.<P></A>
+
+<tr><td>
+<A NAME="1103478">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1157285">passwordCheckSyntax</a><P></A>
+<td>
+<A NAME="1103480">
+Defines whether or not a syntax check is performed on user passwords.<P></A>
+
+<tr><td>
+<A NAME="1103346">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1155167">passwordExp</a><P></A>
+<td>
+<A NAME="1103348">
+Defines whether or not user passwords expire.<P></A>
+
+<tr><td>
+<A NAME="1103444">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104470">passwordInHistory</a><P></A>
+<td>
+<A NAME="1103446">
+If password histories are being kept, this attribute defines how many passwords to keep in the history list.<P></A>
+
+<tr><td>
+<A NAME="1103427">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1156663">passwordKeepHistory</a><P></A>
+<td>
+<A NAME="1103429">
+Defines whether or not a history of user passwords should be saved.<P></A>
+
+<tr><td>
+<A NAME="1103495">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1156671">passwordLockout</a><P></A>
+<td>
+<A NAME="1103497">
+Defines whether or not users should be locked out after using an incorrect password a specified number of times.<P></A>
+
+<tr><td>
+<A NAME="1103551">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104188">passwordLockoutDuration</a><P></A>
+<td>
+<A NAME="1103553">
+Defines how long users should be locked out after a specified number of retries.<P></A>
+
+<tr><td>
+<A NAME="1103353">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1166286">passwordMaxAge</a><P></A>
+<td>
+<A NAME="1103355">
+Defines how long passwords can be used before they expire.<P></A>
+
+<tr><td>
+<A NAME="1103512">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104715">passwordMaxFailure</a><P></A>
+<td>
+<A NAME="1103514">
+Maximum number of retries allowed before a user is locked out.<P></A>
+
+<tr><td>
+<A NAME="1103360">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104413">passwordMinLength</a><P></A>
+<td>
+<A NAME="1103362">
+Defines the minimum number of characters allowed in user passwords.<P></A>
+
+<tr><td>
+<A NAME="1103529">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104754">passwordResetDuration</a><P></A>
+<td>
+<A NAME="1103531">
+Specifies how much time passes between the server locking a user out and resetting the retry count to zero.<P></A>
+
+<tr><td>
+<A NAME="1103534">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1156969">passwordUnlock</a><P></A>
+<td>
+<A NAME="1103536">
+Defines whether or not users should be locked out forever after a specified number of retries.<P></A>
+
+<tr><td>
+<A NAME="1103387">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1104598">passwordWarning</a><P></A>
+<td>
+<A NAME="1103389">
+Specifies how much time prior to password expiration to send a warning to the user.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097669"> 
+</A>
+<A NAME="referral">
+<H3> referral</H3>
+</A>
+
+
+
+<A NAME="1097670">
+Object class that allows smart referrals to be placed in an entry. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1078339">
+OID: <code>2.16.840.1.113730.3.2.6</code><P></A>
+
+<A NAME="1098034">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078330">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078332">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1078336">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100037">ref</a><P></A>
+<td>
+<A NAME="1078338">
+LDAP URL in the format<br>ldap://servername:portnumber/dn.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097986"> 
+</A>
+<A NAME="subschema">
+<H3> subschema</H3>
+</A>
+
+
+
+<A NAME="1097987">
+Object class that contains all the attributes and object classes for a given Directory Server. This object class was inherited from X.500 Directory Services. Reserved for use by the Directory Server.<P></A>
+
+<A NAME="1098036">
+OID: <code>2.5.20.1</code><P></A>
+
+<A NAME="1097998">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1097990">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1097992">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1098110">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1290840">attributeTypes</a><P></A>
+<td>
+<A NAME="1098112">
+Attribute types used within a subschema.<P></A>
+
+<tr><td>
+<A NAME="1098086">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1283336">dITContentRules</a><P></A>
+<td>
+<A NAME="1098088">
+Defines directory tree content rules used within a subschema.<P></A>
+
+<tr><td>
+<A NAME="1098082">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1283313">dITStructureRules</a><P></A>
+<td>
+<A NAME="1098084">
+Defines directory tree structure rules used in a subschema.<P></A>
+
+<tr><td>
+<A NAME="1098078">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1242887">matchingRules</a><P></A>
+<td>
+<A NAME="1098080">
+Defines matching rules used in a subschema.<P></A>
+
+<tr><td>
+<A NAME="1098074">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1242961">matchingRuleUse</a><P></A>
+<td>
+<A NAME="1098076">
+Identifies the attribute types to which a matching rule applies in a subschema.<P></A>
+
+<tr><td>
+<A NAME="1098070">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1282059">nameForms</a><P></A>
+<td>
+<A NAME="1098072">
+Defines the name forms used in a subschema.<P></A>
+
+<tr><td>
+<A NAME="1098066">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1242815">objectClasses</a><P></A>
+<td>
+<A NAME="1098068">
+Defines the object classes used in a subschema.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097091"> 
+</A>
+<A NAME="Media Server Extensions">
+<H2> Media Server Extensions</H2>
+</A>
+
+<A NAME="1097095">
+This section describes the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1097098">netscapeMediaServer</a> object class used by the Netscape Media Server.<P></A>
+
+
+<A NAME="1097098"> 
+</A>
+<A NAME="netscapeMediaServer">
+<H3> netscapeMediaServer</H3>
+</A>
+
+
+
+<A NAME="1097132">
+Object class used to store information about the Netscape Media Server in the directory. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1097133">
+OID: <code>2.16.840.1.113730.3.2.25</code><P></A>
+
+<A NAME="1108693">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108683">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108685">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108690">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108692">
+(Required) Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097135"> 
+</A>
+<A NAME="Messaging Server Extensions">
+<H2> Messaging Server Extensions</H2>
+</A>
+
+<A NAME="1108700">
+The following object classes are used by the Netscape Messaging Server. The object classes described here include <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1108716">groupOfMailEnhancedUniqueNames</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1077922">mailRecipient</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1078007">mailGroup</a>,and <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1081545">netscapeMailServer</a>.<P></A>
+
+
+<A NAME="1108716"> 
+</A>
+<A NAME="groupOfMailEnhancedUniqueNames">
+<H3> groupOfMailEnhancedUniqueNames</H3>
+</A>
+
+
+
+<A NAME="1098817">
+Netscape extension used by the Messaging Server to store information about a mail group. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1098818">
+OID: <code>2.16.840.1.113730.3.2.5</code><P></A>
+
+<A NAME="1077920">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1077885">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1077887">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1077890">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1077893">
+(Required) The group's common name.<P></A>
+
+<tr><td>
+<A NAME="1108721">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108723">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1077896">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1077898">
+Business in which the mail group is involved.<P></A>
+
+<tr><td>
+<A NAME="1077901">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1077903">
+Text description of the group.<P></A>
+
+<tr><td>
+<A NAME="1108728">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1026103">mailEnhancedUniqueMember</a><P></A>
+<td>
+<A NAME="1108730">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1077906">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1077908">
+Organization to which the group belongs.<P></A>
+
+<tr><td>
+<A NAME="1108738">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1108740">
+Organizational unit to which the group belongs.<P></A>
+
+<tr><td>
+<A NAME="1077912">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005719">owner</a><P></A>
+<td>
+<A NAME="1077914">
+The group's owner.<P></A>
+
+<tr><td>
+<A NAME="1077917">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1077919">
+URL to information relevant to the group.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1077922"> 
+</A>
+<A NAME="mailRecipient">
+<H3> mailRecipient</H3>
+</A>
+
+
+
+<A NAME="1077923">
+Object class used as an enhancement to inetOrgPerson to define a Netscape Messaging Server user. That is, mailRecipient represents a mail account. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1097030">
+OID: <code>2.16.840.1.113730.3.2.3</code><P></A>
+
+<A NAME="1078005">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1087545">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1087547">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1087550">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1087553">
+(Required) The user's common name.<P></A>
+
+<tr><td>
+<A NAME="1087556">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1189404">mail</a><P></A>
+<td>
+<A NAME="1087558">
+The user's electronic mailing address.<P></A>
+
+<tr><td>
+<A NAME="1087561">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024020">mailAccessDomain</a><P></A>
+<td>
+<A NAME="1087563">
+Domain from which the mail user can login to obtain mail.<P></A>
+
+<tr><td>
+<A NAME="1103655">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024250">mailAlternateAddress</a><P></A>
+<td>
+<A NAME="1087568">
+Alternate mail address for the user. More than one alternate address is acceptable.<P></A>
+
+<tr><td>
+<A NAME="1087571">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024094">mailAutoReplyMode</a><P></A>
+<td>
+<A NAME="1087573">
+Auto reply mode set for the mail user.<P></A>
+
+<tr><td>
+<A NAME="1087576">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024125">mailAutoReplyText</a><P></A>
+<td>
+<A NAME="1087578">
+Text sent when autoreplying to mail sent to the user.<P></A>
+
+<tr><td>
+<A NAME="1087581">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024295">mailDeliveryOption</a><P></A>
+<td>
+<A NAME="1087583">
+Mail delivery mechanism to be used for the mail user.<P></A>
+
+<tr><td>
+<A NAME="1087586">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1026154">mailForwardingAddress</a><P></A>
+<td>
+<A NAME="1087588">
+Mail address to which the user's mail should be forwarded.<P></A>
+
+<tr><td>
+<A NAME="1087591">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024314">mailHost</a><P></A>
+<td>
+<A NAME="1087593">
+Host on which the user's mail account resides.<P></A>
+
+<tr><td>
+<A NAME="1087596">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024377">mailMessageStore</a><P></A>
+<td>
+<A NAME="1087598">
+Path to the directory containing the user's mail box.<P></A>
+
+<tr><td>
+<A NAME="1087601">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024400">mailProgramDeliveryInfo</a><P></A>
+<td>
+<A NAME="1087603">
+Commands used for programmed mail delivery.<P></A>
+
+<tr><td>
+<A NAME="1087606">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024509">mailQuota</a><P></A>
+<td>
+<A NAME="1087608">
+Maximum disk space allowed for the user's mail box.<P></A>
+
+<tr><td>
+<A NAME="1087611">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229561">multiLineDescription</a><P></A>
+<td>
+<A NAME="1087613">
+Descriptive text about the mail user.<P></A>
+
+<tr><td>
+<A NAME="1087616">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1296804">uid</a><P></A>
+<td>
+<A NAME="1087618">
+Mail user's user ID.<P></A>
+
+<tr><td>
+<A NAME="1087621">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1087623">
+Password with which the mail user can bind to the directory.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1078007"> 
+</A>
+<A NAME="mailGroup">
+<H3> mailGroup</H3>
+</A>
+
+
+
+<A NAME="1078009">
+Object class used as an enhancement to <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005294">groupOfUniqueNames</a> to define a group of mail recipients. That is, mailGroup is used to store Messaging Server mailing lists. This object class is a Netscape extension to the standard LDAP schema.<P></A>
+
+<A NAME="1097032">
+OID: <code>2.16.840.1.113730.3.2.4</code><P></A>
+
+<A NAME="1078087">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1078012">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1078014">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1078017">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1189404">mail</a><P></A>
+<td>
+<A NAME="1078020">
+(Required) The group's electronic mailing address.<P></A>
+
+<tr><td>
+<A NAME="1108751">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108753">
+(Required) Reserved.<P></A>
+
+<tr><td>
+<A NAME="1078023">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1078025">
+The group's common name.<P></A>
+
+<tr><td>
+<A NAME="1103727">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024250">mailAlternateAddress</a><P></A>
+<td>
+<A NAME="1078030">
+Alternate mail address for the group.<P></A>
+
+<tr><td>
+<A NAME="1078033">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024314">mailHost</a><P></A>
+<td>
+<A NAME="1078035">
+Host on which the group's mail account resides.<P></A>
+
+<tr><td>
+<A NAME="1078038">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025144">mgrpAllowedBroadcaster</a><P></A>
+<td>
+<A NAME="1078040">
+URL identifying a mail user that is allowed to send mail to the mail group.<P></A>
+
+<tr><td>
+<A NAME="1078043">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024569">mgrpAllowedDomain</a><P></A>
+<td>
+<A NAME="1078045">
+Domain from which users can send mail to the mail group.<P></A>
+
+<tr><td>
+<A NAME="1078048">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1278551">mgrpDeliverTo</a><P></A>
+<td>
+<A NAME="1078050">
+Alternative method of identifying members of the mail group.<P></A>
+
+<tr><td>
+<A NAME="1078053">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025568">mgrpErrorsTo</a><P></A>
+<td>
+<A NAME="1078055">
+Mailing address to which mail delivery error messages are sent.<P></A>
+
+<tr><td>
+<A NAME="1078058">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025705">mgrpModerator</a><P></A>
+<td>
+<A NAME="1078060">
+Mailing address to which rejected mail messages are sent.<P></A>
+
+<tr><td>
+<A NAME="1078063">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025878">mgrpMsgMaxSize</a><P></A>
+<td>
+<A NAME="1078065">
+Maximum message size that can be sent to the mail group.<P></A>
+
+<tr><td>
+<A NAME="1078068">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025035">mgrpMsgRejectAction</a><P></A>
+<td>
+<A NAME="1078070">
+Specifies the action to the taken in the event that mail sent to the mail group is rejected.<P></A>
+
+<tr><td>
+<A NAME="1078073">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1025981">mgrpMsgRejectText</a><P></A>
+<td>
+<A NAME="1078075">
+Text to be sent in the event that mail sent to the mail group is rejected.<P></A>
+
+<tr><td>
+<A NAME="1078078">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1024670">mgrpRFC822MailMember</a><P></A>
+<td>
+<A NAME="1078080">
+Recipient of mail that is sent to the mail group, but who is not in actuality a member of the mail group.<P></A>
+
+<tr><td>
+<A NAME="1078084">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005719">owner</a><P></A>
+<td>
+<A NAME="1078086">
+Distinguished name of the mail group's owner.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1081545"> 
+</A>
+<A NAME="netscapeMailServer">
+<H3> netscapeMailServer</H3>
+</A>
+
+
+
+<A NAME="1081546">
+Object class used to store information about the Netscape Messaging Server in the directory. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1097044">
+OID: <code>2.16.840.1.113730.3.2.24</code><P></A>
+
+<A NAME="1108767">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108757">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108759">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108764">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108766">
+(Required) Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1086191"> 
+</A>
+<A NAME="Proxy Server Extensions">
+<H2> Proxy Server Extensions</H2>
+</A>
+
+<A NAME="1086195">
+This section describes the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1081588">netscapeProxyServer</a> object class used by the Netscape Proxy Server.<P></A>
+
+
+<A NAME="1081588"> 
+</A>
+<A NAME="netscapeProxyServer">
+<H3> netscapeProxyServer</H3>
+</A>
+
+
+
+<A NAME="1081589">
+Object class used to store information about the Netscape Proxy Server in the directory. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1097160">
+OID: <code>2.16.840.1.113730.3.2.28</code><P></A>
+
+<A NAME="1108781">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108771">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108773">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108778">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108780">
+(Required) Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1081607"> 
+</A>
+<A NAME="Web Server Extensions">
+<H2> Web Server Extensions</H2>
+</A>
+
+<A NAME="1081611">
+This section describes the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1081614">netscapeWebServer</a> object class used by Netscape's web servers.<P></A>
+
+
+<A NAME="1081614"> 
+</A>
+<A NAME="netscapeWebServer">
+<H3> netscapeWebServer</H3>
+</A>
+
+
+
+<A NAME="1081615">
+Object class used to store information about a Netscape web server in the directory. This object class is a Netscape extension to the standard LDAP schema. Reserved for future use.<P></A>
+
+<A NAME="1108796">
+OID: <code>2.16.840.1.113730.3.2.29</code><P></A>
+
+<A NAME="1108814">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1108804">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1108806">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1108811">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1108813">
+(Required) Reserved.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1108799"> 
+</A>
+<A NAME="Reserved Object Classes">
+<H2> Reserved Object Classes</H2>
+</A>
+
+<A NAME="1108800">
+This section describes object classes that are not defined for this release or are reserved for future use by the Netscape Directory Server.<P></A>
+
+
+<A NAME="1091117"> 
+</A>
+<A NAME="account">
+<H3> account</H3>
+</A>
+
+
+
+<A NAME="1091854">
+Reserved.<P></A>
+
+<A NAME="1098856">
+OID: <code>0.9.2342.19200300.100.4.5</code><P></A>
+
+<A NAME="1091903">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091857">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091859">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091907">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1296804">uid</a><P></A>
+<td>
+<A NAME="1091909">
+(Required) The account's user ID.<P></A>
+
+<tr><td>
+<A NAME="1091874">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1091876">
+Text description of the account.<P></A>
+
+<tr><td>
+<A NAME="1091917">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201958">host</a><P></A>
+<td>
+<A NAME="1091919">
+Hostname of the computer on which the account resides.<P></A>
+
+<tr><td>
+<A NAME="1091879">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1091881">
+Locality in which the account resides.<P></A>
+
+<tr><td>
+<A NAME="1091884">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1091886">
+Organization to which the account belongs.<P></A>
+
+<tr><td>
+<A NAME="1091890">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1091892">
+Organizational unit to which the account belongs.<P></A>
+
+<tr><td>
+<A NAME="1091895">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1091897">
+URL to information relevant to the account.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089961"> 
+</A>
+<A NAME="alias">
+<H3> alias</H3>
+</A>
+
+
+
+<A NAME="1089993">
+Object class used to point to other entries in the directory tree. This object class was inherited from X.500 Directory Services. Reserved.<P></A>
+
+<A NAME="1096898">
+OID: <code>2.5.6.1</code><P></A>
+
+<A NAME="1090031">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1089996">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1089998">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1090103">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201653">aliasedObjectName</a><P></A>
+<td>
+<A NAME="1090004">
+(Required) Distinguished name of the entry for which this entry is an alias.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091270"> 
+</A>
+<A NAME="applicationEntity">
+<H3> applicationEntity</H3>
+</A>
+
+
+
+<A NAME="1106068">
+Object class used to represent application entities in the directory. This object class was inherited from X.500 Directory Services. Reserved.<P></A>
+
+<A NAME="1096990">
+OID: <code>2.5.6.12</code><P></A>
+
+<A NAME="1091320">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091274">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091276">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091279">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202620">presentationAddress</a><P></A>
+<td>
+<A NAME="1091282">
+(Required) OSI presentation address of the entity.<P></A>
+
+<tr><td>
+<A NAME="1091285">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1091288">
+(Required) Common name of the entity.<P></A>
+
+<tr><td>
+<A NAME="1091291">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1091293">
+Text description of the entity.<P></A>
+
+<tr><td>
+<A NAME="1091296">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1091298">
+Locality in which the entity resides.<P></A>
+
+<tr><td>
+<A NAME="1103836">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1091303">
+Organization to which the entity belongs.<P></A>
+
+<tr><td>
+<A NAME="1103841">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1091309">
+Organizational unit to which the entity belongs.<P></A>
+
+<tr><td>
+<A NAME="1103846">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1091314">
+URL to information relevant to the entity.<P></A>
+
+<tr><td>
+<A NAME="1091317">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202747">supportedApplicationContext</a><P></A>
+<td>
+<A NAME="1091319">
+Identifiers of OSI application contexts.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1090381"> 
+</A>
+<A NAME="applicationProcess">
+<H3> applicationProcess</H3>
+</A>
+
+
+
+<A NAME="1106091">
+Object class used to define entries representing application processes in the directory. This object class was inherited from X.500 Directory Services. Reserved.<P></A>
+
+<A NAME="1096988">
+OID: <code>2.5.6.11</code><P></A>
+
+<A NAME="1090515">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1090555">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1090557">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1103871">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1090563">
+(Required) Common name of the process.<P></A>
+
+<tr><td>
+<A NAME="1103876">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1090574">
+Text description of the process.<P></A>
+
+<tr><td>
+<A NAME="1103866">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1090599">
+Locality in which the process resides.<P></A>
+
+<tr><td>
+<A NAME="1103856">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1090585">
+Organizational unit to which the process belongs.<P></A>
+
+<tr><td>
+<A NAME="1103861">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1090590">
+URL to information relevant to the process.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091421"> 
+</A>
+<A NAME="cacheObject">
+<H3> cacheObject</H3>
+</A>
+
+
+
+<A NAME="1093594">
+Object class that allows an entry to contain the timeToLive (<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202798">ttl</a>) attribute.<P></A>
+
+<A NAME="1098472">
+OID: <code>1.3.6.1.4.1.250.3.18</code><P></A>
+
+<A NAME="1093607">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093597">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093599">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093604">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202798">ttl</a><P></A>
+<td>
+<A NAME="1093606">
+Time, in seconds, that cached information about an entry should be considered valid.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091225"> 
+</A>
+<A NAME="certificationAuthority">
+<H3> certificationAuthority</H3>
+</A>
+
+
+
+<A NAME="1091226">
+Object class used to store information about Certificate Authorities (CAs) in the directory. This object class was inherited from X.500 Directory Services. Reserved.<P></A>
+
+<A NAME="1097006">
+OID: <code>2.5.6.16</code><P></A>
+
+<A NAME="1091261">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091229">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091231">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091236">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1208584">cACertificate;binary</a><P></A>
+<td>
+<A NAME="1091239">
+(Required) Certificate, in binary form, from a certification authority.<P></A>
+
+<tr><td>
+<A NAME="1091243">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1207178">authorityRevocationList;binary</a><P></A>
+<td>
+<A NAME="1091246">
+List, in binary form, of CA certificates that have been revoked and are no longer considered valid or secure.<P></A>
+
+<tr><td>
+<A NAME="1091250">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1208727">certificateRevocationList;binary</a><P></A>
+<td>
+<A NAME="1091253">
+List, in binary form, of user certificates that have been revoked.<P></A>
+
+<tr><td>
+<A NAME="1091258">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1208791">crossCertificatePair;binary</a><P></A>
+<td>
+<A NAME="1091260">
+Reserved for future use.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097268"> 
+</A>
+<A NAME="dcObject">
+<H3> dcObject</H3>
+</A>
+
+
+
+<A NAME="1097806">
+Object class that allows domain components to be defined for an entry. This object class is defined as auxiliary because it is commonly used in combination with another object class, such as <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1004980">organization</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005108">organizationalUnit</a>, or <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/objclass.htm#1005427">locality</a>. For example,<P></A>
+<PRE><A NAME="1097855">
+dn: dc=example,dc=com<br>objectClass: top<br>objectClass: organization<br>objectClass: dcObject<br>dc: example<br>o: Example Corp.
+</A>
+</PRE>
+<A NAME="1097270">
+OID: <code>1.3.6.1.4.1.1466.344</code><P></A>
+
+<A NAME="1097318">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1097273">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1097275">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1097278">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1245094">dc</a><P></A>
+<td>
+<A NAME="1097281">
+(Required) Domain component of the entry.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1090760"> 
+</A>
+<A NAME="device">
+<H3> device</H3>
+</A>
+
+
+
+<A NAME="1090817">
+Object class used to store information about network devices, such as printers, in the directory. This object class was inherited from X.500 Directory Services. Reserved.<P></A>
+
+<A NAME="1096996">
+OID: <code>2.5.6.14</code><P></A>
+
+<A NAME="1090828">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1103908">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1103910">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1103915">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1103917">
+(Required) Common name of the device.<P></A>
+
+<tr><td>
+<A NAME="1103922">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1103924">
+Text description of the device.<P></A>
+
+<tr><td>
+<A NAME="1103960">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1103929">
+Locality in which the device resides.<P></A>
+
+<tr><td>
+<A NAME="1103965">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1103934">
+Organization to which the device belongs.<P></A>
+
+<tr><td>
+<A NAME="1103970">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1103940">
+Organizational unit to which the device belongs.<P></A>
+
+<tr><td>
+<A NAME="1103943">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1005719">owner</a><P></A>
+<td>
+<A NAME="1103945">
+Distinguished name of the person responsible for the device.<P></A>
+
+<tr><td>
+<A NAME="1103948">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1103950">
+URL to information relevant to the device.<P></A>
+
+<tr><td>
+<A NAME="1103953">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202700">serialNumber</a><P></A>
+<td>
+<A NAME="1103955">
+Serial number of the device.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091390"> 
+</A>
+<A NAME="DNSDomain">
+<H3> DNSDomain</H3>
+</A>
+
+
+
+<A NAME="1093025">
+Object class used as a subclass of domain to store DNS resource records in the directory. Reserved.<P></A>
+
+<A NAME="1096887">
+OID: <code>0.9.2342.19200300.100.4.15</code><P></A>
+
+<A NAME="1093023">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093008">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093010">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093013">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201841">dNSRecord</a><P></A>
+<td>
+<A NAME="1093015">
+DNS resource records.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091348"> 
+</A>
+<A NAME="document">
+<H3> document</H3>
+</A>
+
+
+
+<A NAME="1092549">
+Used to define entries which represent documents in the directory. Reserved.<P></A>
+
+<A NAME="1096874">
+OID: <code>0.9.2342.19200300.100.4.6</code><P></A>
+
+<A NAME="1091981">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092165">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092167">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092172">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201854">documentIdentifier</a><P></A>
+<td>
+<A NAME="1092175">
+(Required) Unique identifier for a document.<P></A>
+
+<tr><td>
+<A NAME="1092180">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1255098">abstract</a><P></A>
+<td>
+<A NAME="1092182">
+Abstract of the document.<P></A>
+
+<tr><td>
+<A NAME="1092187">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201689">authorCn</a><P></A>
+<td>
+<A NAME="1092189">
+Author's common, or given, name.<P></A>
+
+<tr><td>
+<A NAME="1092194">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201696">authorSn</a><P></A>
+<td>
+<A NAME="1092196">
+The author's surname.<P></A>
+
+<tr><td>
+<A NAME="1092201">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1092203">
+Common name of the document.<P></A>
+
+<tr><td>
+<A NAME="1092206">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1092208">
+Text description of the description.<P></A>
+
+<tr><td>
+<A NAME="1092213">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201847">documentAuthor</a><P></A>
+<td>
+<A NAME="1092215">
+Distinguished name of the document author.<P></A>
+
+<tr><td>
+<A NAME="1092220">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201861">documentLocation</a><P></A>
+<td>
+<A NAME="1092222">
+Location of the original document.<P></A>
+
+<tr><td>
+<A NAME="1092227">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201868">documentPublisher</a><P></A>
+<td>
+<A NAME="1092229">
+Person or organization that published the document.<P></A>
+
+<tr><td>
+<A NAME="1092234">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201877">documentStore</a><P></A>
+<td>
+<A NAME="1092236">
+Not defined.<P></A>
+
+<tr><td>
+<A NAME="1092241">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201884">documentTitle</a><P></A>
+<td>
+<A NAME="1092243">
+The document's title.<P></A>
+
+<tr><td>
+<A NAME="1092248">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201891">documentVersion</a><P></A>
+<td>
+<A NAME="1092250">
+The document's version number.<P></A>
+
+<tr><td>
+<A NAME="1092255">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202004">keyWords</a><P></A>
+<td>
+<A NAME="1092257">
+Keywords that describe the document.<P></A>
+
+<tr><td>
+<A NAME="1103998">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1092262">
+Locality in which the document resides.<P></A>
+
+<tr><td>
+<A NAME="1104003">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1092267">
+Organization to which the document belongs.<P></A>
+
+<tr><td>
+<A NAME="1092272">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202192">obsoletedByDocument</a><P></A>
+<td>
+<A NAME="1092274">
+Distinguished name of a document that obsoletes this document.<P></A>
+
+<tr><td>
+<A NAME="1092279">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202199">obsoletesDocument</a><P></A>
+<td>
+<A NAME="1092281">
+Distinguished name of a document that is obsoleted by this document.<P></A>
+
+<tr><td>
+<A NAME="1104008">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1092299">
+Organizational unit to which the document belongs.<P></A>
+
+<tr><td>
+<A NAME="1104013">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1092293">
+URL to information relevant to the document.<P></A>
+
+<tr><td>
+<A NAME="1092306">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202732">subject</a><P></A>
+<td>
+<A NAME="1092308">
+Subject of the document.<P></A>
+
+<tr><td>
+<A NAME="1092330">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202817">updatedByDocument</a><P></A>
+<td>
+<A NAME="1092334">
+Distinguished name of a document that is an updated version of this document.<P></A>
+
+<tr><td>
+<A NAME="1092323">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202824">updatesDocument</a><P></A>
+<td>
+<A NAME="1092340">
+Distinguished name of a document for which this document is an updated version.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091354"> 
+</A>
+<A NAME="documentSeries">
+<H3> documentSeries</H3>
+</A>
+
+
+
+<A NAME="1092560">
+Used to define an entry that represents a series of documents. Reserved.<P></A>
+
+<A NAME="1096876">
+OID: <code>0.9.2342.19200300.100.4.9</code><P></A>
+
+<A NAME="1092547">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092502">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092504">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092507">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1092579">
+(Required) The common name of the series.<P></A>
+
+<tr><td>
+<A NAME="1104028">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1092515">
+Text description of the series.<P></A>
+
+<tr><td>
+<A NAME="1104033">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1092520">
+Locality in which the series resides.<P></A>
+
+<tr><td>
+<A NAME="1104038">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1092525">
+Organization to which the series belongs.<P></A>
+
+<tr><td>
+<A NAME="1104043">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1092531">
+Organizational unit to which the series belongs.<P></A>
+
+<tr><td>
+<A NAME="1104048">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1092541">
+URL to information relevant to the series.<P></A>
+
+<tr><td>
+<A NAME="1092600">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1092602">
+Telephone number of the person responsible for the series.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091357"> 
+</A>
+<A NAME="domain">
+<H3> domain</H3>
+</A>
+
+
+
+<A NAME="1097945">
+Object class used to define entries that represent DNS domains in the directory. The domainComponent attribute should be used for naming entries of this object class. Reserved.<P></A>
+
+<A NAME="1096879">
+OID: <code>0.9.2342.19200300.100.4.13</code><P></A>
+
+<A NAME="1092674">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092632">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092634">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092639">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1245094">dc</a><P></A>
+<td>
+<A NAME="1092642">
+(Required) One component of a domain name.<P></A>
+
+<tr><td>
+<A NAME="1092701">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201675">associatedName</a><P></A>
+<td>
+<A NAME="1092708">
+Entry in the organizational directory tree associated with a DNS domain.<P></A>
+
+<tr><td>
+<A NAME="1092721">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1092723">
+Type of business this domain is engaged in.<P></A>
+
+<tr><td>
+<A NAME="1092645">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1092647">
+Text description of the domain.<P></A>
+
+<tr><td>
+<A NAME="1092735">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1292809">destinationIndicator</a><P></A>
+<td>
+<A NAME="1092737">
+This attribute is used for telegram services to this domain.<P></A>
+
+<tr><td>
+<A NAME="1092741">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171637">facsimileTelephoneNumber</a><P></A>
+<td>
+<A NAME="1092744">
+Fax number associated with the domain.<P></A>
+
+<tr><td>
+<A NAME="1092749">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1224256">internationalIsdnNumber</a><P></A>
+<td>
+<A NAME="1092751">
+ISDN number associated with the domain.<P></A>
+
+<tr><td>
+<A NAME="1092650">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1092652">
+Locality in which the domain resides.<P></A>
+
+<tr><td>
+<A NAME="1092778">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1007859">manager</a><P></A>
+<td>
+<A NAME="1092780">
+Distinguished name of a manager associated with the domain.<P></A>
+
+<tr><td>
+<A NAME="1092655">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1092657">
+Organization to which the domain belongs.<P></A>
+
+<tr><td>
+<A NAME="1092789">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003072">physicalDeliveryOfficeName</a><P></A>
+<td>
+<A NAME="1092791">
+Location where physical deliveries can be made.<P></A>
+
+<tr><td>
+<A NAME="1092794">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230025">postalAddress</a><P></A>
+<td>
+<A NAME="1092796">
+Mailing address associated with the domain.<P></A>
+
+<tr><td>
+<A NAME="1092799">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230036">postalCode</a><P></A>
+<td>
+<A NAME="1092801">
+Domain's postal code (such as a United States zip code).<P></A>
+
+<tr><td>
+<A NAME="1092804">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230043">postOfficeBox</a><P></A>
+<td>
+<A NAME="1092806">
+Domain's post office box.<P></A>
+
+<tr><td>
+<A NAME="1092809">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202605">preferredDeliveryMethod</a><P></A>
+<td>
+<A NAME="1092811">
+Domain's preferred method of contact or delivery.<P></A>
+
+<tr><td>
+<A NAME="1092824">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202644">registeredAddress</a><P></A>
+<td>
+<A NAME="1092826">
+Postal address suitable for reception of expedited documents, where the recipient must verify delivery.<P></A>
+
+<tr><td>
+<A NAME="1092857">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202682">searchGuide</a><P></A>
+<td>
+<A NAME="1092859">
+Specifies information for suggested search criteria when using the entry as the base object in the directory tree for a search operation.<P></A>
+
+<tr><td>
+<A NAME="1092871">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1092873">
+URL to information relevant to the domain.<P></A>
+
+<tr><td>
+<A NAME="1092829">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1203417">st</a><P></A>
+<td>
+<A NAME="1092831">
+State or province in which the domain resides.<P></A>
+
+<tr><td>
+<A NAME="1092834">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202721">street</a><P></A>
+<td>
+<A NAME="1092836">
+Street address associated with the domain.<P></A>
+
+<tr><td>
+<A NAME="1092882">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1092884">
+Telephone number associated with the domain.<P></A>
+
+<tr><td>
+<A NAME="1092839">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205004">teletexTerminalIdentifier</a><P></A>
+<td>
+<A NAME="1092841">
+Identifier for a teletex terminal associated with the domain.<P></A>
+
+<tr><td>
+<A NAME="1092844">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205120">telexNumber</a><P></A>
+<td>
+<A NAME="1092846">
+Telex number associated with the domain.<P></A>
+
+<tr><td>
+<A NAME="1092909">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1092911">
+Reserved for future use.<P></A>
+
+<tr><td>
+<A NAME="1092851">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281763">x121Address</a><P></A>
+<td>
+<A NAME="1092853">
+X.121 address associated with the domain.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091384"> 
+</A>
+<A NAME="domainRelatedObject">
+<H3> domainRelatedObject</H3>
+</A>
+
+
+
+<A NAME="1093633">
+Object class used to define entries that represent a DNS domain that is equivalent to an X.500 domain, usually an organization or organizational unit. Reserved.<P></A>
+
+<A NAME="1098880">
+OID: <code>0.9.2342.19200300.100.4.17</code><P></A>
+
+<A NAME="1097753">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1097743">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1097745">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1097750">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201668">associatedDomain</a><P></A>
+<td>
+<A NAME="1097752">
+DNS domain associated with an object in the directory tree.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1097756"> 
+</A>
+<A NAME="dSA">
+<H3> dSA</H3>
+</A>
+
+
+
+<A NAME="1097757">
+Object class used to define entries representing DSAs in the directory. This object class was inherited from X.500 Directory Services. Reserved.<P></A>
+
+<A NAME="1096993">
+OID: <code>2.5.6.13</code><P></A>
+
+<A NAME="1091405">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091397">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091399">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091402">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202013">knowledgeInformation</a><P></A>
+<td>
+<A NAME="1091404">
+This attribute is no longer used.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091415"> 
+</A>
+<A NAME="friendlyCountry">
+<H3> friendlyCountry</H3>
+</A>
+
+
+
+<A NAME="1093062">
+Object class used to define country entries in the directory tree. This object class is used to allow more user-friendly country names than those allowed by the country object class. Reserved.<P></A>
+
+<A NAME="1098883">
+OID: <code>0.9.2342.19200300.100.4.18</code><P></A>
+
+<A NAME="1093060">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093050">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093052">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093057">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1265915">co</a><P></A>
+<td>
+<A NAME="1093059">
+Contains the name of a country.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091443"> 
+</A>
+<A NAME="labeledURIObject">
+<H3> labeledURIObject</H3>
+</A>
+
+
+
+<A NAME="1096833">
+This object class can be added to existing directory objects to allow for inclusion of URI values. This approach does not preclude including the labeledURI attribute type directly in other object classes as appropriate. Reserved.<P></A>
+
+<A NAME="1096829">
+OID: <code>1.3.6.1.4.1.250.3.15</code><P></A>
+
+<A NAME="1093588">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093578">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093580">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093585">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202020">labeledUri</a><P></A>
+<td>
+<A NAME="1093587">
+A Uniform Resource Identifier (URI) that is relevant to the entry.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091410"> 
+</A>
+<A NAME="pilotObject">
+<H3> pilotObject</H3>
+</A>
+
+
+
+<A NAME="1091508">
+Object class used as a subclass to allow additional attributes to be assigned to entries of all other object classes. Reserved.<P></A>
+
+<A NAME="1096860">
+OID: <code>0.9.2342.19200300.100.4.3</code><P></A>
+
+<A NAME="1091544">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1091536">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1091538">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1091541">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201684">audio</a><P></A>
+<td>
+<A NAME="1091543">
+Sound file.<P></A>
+
+<tr><td>
+<A NAME="1091579">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201831">ditRedirect</a><P></A>
+<td>
+<A NAME="1091581">
+Distinguished name to use as a redirect for the entry.<P></A>
+
+<tr><td>
+<A NAME="1091575">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201965">info</a><P></A>
+<td>
+<A NAME="1091577">
+Information about the object.<P></A>
+
+<tr><td>
+<A NAME="1091571">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201995">jpegPhoto</a><P></A>
+<td>
+<A NAME="1091573">
+Photo in jpeg format.<P></A>
+
+<tr><td>
+<A NAME="1091567">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1100733">lastModifiedBy</a><P></A>
+<td>
+<A NAME="1091569">
+Distinguished name of the last user to modify the object.<P></A>
+
+<tr><td>
+<A NAME="1091563">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202035">lastModifiedTime</a><P></A>
+<td>
+<A NAME="1091565">
+Last time the object was modified.<P></A>
+
+<tr><td>
+<A NAME="1091559">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1007859">manager</a><P></A>
+<td>
+<A NAME="1091561">
+Distinguished name of the object's manager.<P></A>
+
+<tr><td>
+<A NAME="1091555">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202247">photo</a><P></A>
+<td>
+<A NAME="1091557">
+Photo of the object.<P></A>
+
+<tr><td>
+<A NAME="1091551">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202809">uniqueIdentifier</a><P></A>
+<td>
+<A NAME="1091553">
+Specific item used to distinguish between two entries when a distinguished name has been reused.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091437"> 
+</A>
+<A NAME="pilotOrganization">
+<H3> pilotOrganization</H3>
+</A>
+
+
+
+<A NAME="1093224">
+Object class used as a subclass to allow additional attributes to be assigned to organization and organizationalUnit object class entries. Reserved.<P></A>
+
+<A NAME="1096890">
+OID: <code>0.9.2342.19200300.100.4.20</code><P></A>
+
+<A NAME="1093387">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093251">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093253">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093394">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281611">o</a><P></A>
+<td>
+<A NAME="1093396">
+(Required) Organization to which the entry belongs.<P></A>
+
+<tr><td>
+<A NAME="1093400">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1241174">ou</a><P></A>
+<td>
+<A NAME="1093402">
+(Required) Organizational unit to which the entry belongs.<P></A>
+
+<tr><td>
+<A NAME="1093418">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1201711">buildingName</a><P></A>
+<td>
+<A NAME="1093420">
+Name of the building in which the entry resides.<P></A>
+
+<tr><td>
+<A NAME="1093258">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171367">businessCategory</a><P></A>
+<td>
+<A NAME="1093260">
+Type of business this entry is engaged in.<P></A>
+
+<tr><td>
+<A NAME="1093265">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1093267">
+Text description of the entry.<P></A>
+
+<tr><td>
+<A NAME="1093433">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1292809">destinationIndicator</a><P></A>
+<td>
+<A NAME="1093435">
+This attribute is used for telegram services to this entry.<P></A>
+
+<tr><td>
+<A NAME="1093439">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171637">facsimileTelephoneNumber</a><P></A>
+<td>
+<A NAME="1093442">
+Fax number associated with the entry.<P></A>
+
+<tr><td>
+<A NAME="1093447">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1224256">internationalIsdnNumber</a><P></A>
+<td>
+<A NAME="1093449">
+ISDN number associated with the entry.<P></A>
+
+<tr><td>
+<A NAME="1093452">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1244534">l</a><P></A>
+<td>
+<A NAME="1093454">
+Locality in which the entry resides.<P></A>
+
+<tr><td>
+<A NAME="1093516">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1003072">physicalDeliveryOfficeName</a><P></A>
+<td>
+<A NAME="1093518">
+Location where physical deliveries can be made to this entry.<P></A>
+
+<tr><td>
+<A NAME="1104165">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230025">postalAddress</a><P></A>
+<td>
+<A NAME="1093513">
+Business mailing address for the entry.<P></A>
+
+<tr><td>
+<A NAME="1104170">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230036">postalCode</a><P></A>
+<td>
+<A NAME="1093508">
+Business postal code (such as a United States zip code) for the entry.<P></A>
+
+<tr><td>
+<A NAME="1104175">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230043">postOfficeBox</a><P></A>
+<td>
+<A NAME="1093503">
+Business post office box for the entry.<P></A>
+
+<tr><td>
+<A NAME="1104180">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202605">preferredDeliveryMethod</a><P></A>
+<td>
+<A NAME="1093498">
+Preferred method of contact or delivery of the entry.<P></A>
+
+<tr><td>
+<A NAME="1104185">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202644">registeredAddress</a><P></A>
+<td>
+<A NAME="1106134">
+Postal address suitable for reception of expedited documents, where the recipient must verify delivery.<P></A>
+
+<tr><td>
+<A NAME="1104190">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202682">searchGuide</a><P></A>
+<td>
+<A NAME="1093532">
+Specifies information for suggested search criteria when using the entry as the base object in the directory tree for a search operation.<P></A>
+
+<tr><td>
+<A NAME="1104195">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1093544">
+URL to information relevant to the entry.<P></A>
+
+<tr><td>
+<A NAME="1104200">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1203417">st</a><P></A>
+<td>
+<A NAME="1093488">
+State or province in which the entry resides.<P></A>
+
+<tr><td>
+<A NAME="1104205">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1202721">street</a><P></A>
+<td>
+<A NAME="1093483">
+Street address at which the entry is located.<P></A>
+
+<tr><td>
+<A NAME="1104210">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1093557">
+Telephone number associated with the entry.<P></A>
+
+<tr><td>
+<A NAME="1104215">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205004">teletexTerminalIdentifier</a><P></A>
+<td>
+<A NAME="1093478">
+Identifier for the teletex terminal of the entry.<P></A>
+
+<tr><td>
+<A NAME="1104220">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1205120">telexNumber</a><P></A>
+<td>
+<A NAME="1093473">
+Telex number of the entry.<P></A>
+
+<tr><td>
+<A NAME="1104225">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1093572">
+The entry's password and encryption method.<P></A>
+
+<tr><td>
+<A NAME="1104230">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1281763">x121Address</a><P></A>
+<td>
+<A NAME="1093468">
+X.121 address of the entry.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091375"> 
+</A>
+<A NAME="RFC822LocalPart">
+<H3> RFC822LocalPart</H3>
+</A>
+
+
+
+<A NAME="1092973">
+Object class used to define entries that represent the local part of RFC822 mail addresses. The directory treats this part of an RFC822 address as a domain. Reserved.<P></A>
+
+<A NAME="1096884">
+OID: <code>0.9.2342.19200300.100.4.14</code><P></A>
+
+<A NAME="1092966">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092920">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092922">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092931">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1092934">
+Common, or given name of the entry.<P></A>
+
+<tr><td>
+<A NAME="1092963">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1290325">sn</a><P></A>
+<td>
+<A NAME="1092965">
+Surname of the entry.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091363"> 
+</A>
+<A NAME="room">
+<H3> room</H3>
+</A>
+
+
+
+<A NAME="1092427">
+Object class used to store information about a room in the directory. Reserved.<P></A>
+
+<A NAME="1098891">
+OID: <code>0.9.2342.19200300.100.4.7</code><P></A>
+
+<A NAME="1098892">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1092361">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1092363">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1092443">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171494">cn</a><P></A>
+<td>
+<A NAME="1092446">
+(Required) Common name of the room.<P></A>
+
+<tr><td>
+<A NAME="1092449">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171528">description</a><P></A>
+<td>
+<A NAME="1092451">
+Text description of the room.<P></A>
+
+<tr><td>
+<A NAME="1092468">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1204477">roomNumber</a><P></A>
+<td>
+<A NAME="1092470">
+The room's number.<P></A>
+
+<tr><td>
+<A NAME="1092477">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1172500">seeAlso</a><P></A>
+<td>
+<A NAME="1092479">
+URL to information relevant to the room.<P></A>
+
+<tr><td>
+<A NAME="1092491">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1230129">telephoneNumber</a><P></A>
+<td>
+<A NAME="1092493">
+The room's telephone number.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1091431"> 
+</A>
+<A NAME="simpleSecurityObject">
+<H3> simpleSecurityObject</H3>
+</A>
+
+
+
+<A NAME="1093131">
+Object class used to allow an entry to contain the userPassword attribute when an entry's principal object classes do not allow userPassword as an attribute type. Reserved.<P></A>
+
+<A NAME="1093125">
+OID: <code>0.9.2342.19200300.100.4.19</code><P></A>
+
+<A NAME="1098903">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1093106">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1093108">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1093113">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1196547">userPassword</a><P></A>
+<td>
+<A NAME="1093116">
+(Required) The entry's password and encryption method.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1089871"> 
+</A>
+<A NAME="strongAuthenticationUser">
+<H3> strongAuthenticationUser</H3>
+</A>
+
+
+
+<A NAME="1090921">
+Object class used to store information about clients and certificates in the directory. This object class was inherited from X.500 Directory Services. Reserved.<P></A>
+
+<A NAME="1106458">
+OID: <code>2.5.6.15</code><P></A>
+
+<A NAME="1106478">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1106461">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1106463">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1106468">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1208938">userCertificate</a><P></A>
+<td>
+<A NAME="1106470">
+Not used.<P></A>
+
+<tr><td>
+<A NAME="1106475">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1278425">userCertificate;binary</a><P></A>
+<td>
+<A NAME="1106477">
+(Required) User's certificate in binary form.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+
+<A NAME="1106481"> 
+</A>
+<A NAME="top">
+<H3> top</H3>
+</A>
+
+
+
+<A NAME="1106482">
+Object class used as a superclass for all other object classes in the directory. This object class was inherited from X.500 Directory Services. Reserved.<P></A>
+
+<A NAME="1106020">
+OID: <code>2.5.6.0</code><P></A>
+
+<A NAME="1106503">
+
+<TABLE BORDER="1" cellpadding="1">
+<CAPTION></caption>
+<tr><th valign=baseline align=left><b>
+<A NAME="1106486">
+<B>Attribute</B><P></A>
+<B><th valign=baseline align=left><b>
+<A NAME="1106488">
+<B>Attribute Description</B><P></A>
+<B></tr>
+<tr><td>
+<A NAME="1106493">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1229677">objectClass</a><P></A>
+<td>
+<A NAME="1106495">
+(Required) Mandatory attribute for all object classes.<P></A>
+
+<tr><td>
+<A NAME="1106500">
+<a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#1171292">aci</a><P></A>
+<td>
+<A NAME="1106502">
+Stores the Directory Server access control information for this entry.<P></A>
+
+
+</TABLE>
+
+<TABLE>
+<tr><td>
+</TABLE>
+<P></A>
+
+<A NAME="1106011">
+<P></A>
diff --git a/ldap/clients/dsgw/html/manual/search.htm b/ldap/clients/dsgw/html/manual/search.htm
new file mode 100644
index 00000000..95665f0f
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/search.htm
@@ -0,0 +1,651 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+ All rights reserved.
+ -->
+<html>
+<head>
+<title>Searching the Directory Tree</title>
+</head>
+
+<body>
+
+<h1><a name="search"></a>Searching the Directory Tree</h1>
+
+<p>The Directory Server
+contains information about the people and resources in
+your organization. Using the Directory Server interface, you can
+easily find the information you need. To simplify the search
+process, the Directory Server interface provides two types of
+searches:</p>
+
+<ul>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</a> -- Selects an
+ appropriate method of searching based on the value you
+ specify. For example, if you search for moz@example.com,
+ Standard Search searches for matching email
+ addresses. </li>
+<P>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</a> -- Provides a
+ simple method for searching against specific entry
+ attributes. For example, you can specify that you want to
+ search for users whose last names start with <b>k</b> and
+ whose phone numbers end with <b>2110</b>. </li>
+</ul>
+
+<p>Both types of searches allow you select the type of entry to
+search for. You can search for any of the following types of
+entries:</p>
+
+<table border="2">
+ <tr>
+ <th><a name="type"></a><b>Type of Entry</b></th>
+ <th>Description</th>
+ </tr>
+ <tr>
+ <td valign="top">People</td>
+ <td valign="top">Entries that describe a person. </td>
+ </tr>
+ <tr>
+ <td valign="top">NT people</td>
+ <td valign="top">Entries that describe an NT user.</td>
+ </tr>
+ <tr>
+ <td valign="top">Groups<b> </b></td>
+ <td valign="top">Entries that describe a group. Groups
+ are collections of one or more directory
+ entries. For example, groups may be defined at your site
+ that include the System Administrators, the Technical
+ Writers, or all the people interested in fishing. Note
+ that a group does not always have to identify a
+ collection of people. For example, a group could be
+ defined that identifies all the color printers or fax machines
+ at your site. Groups can also contain other groups. </td>
+ </tr>
+ <tr>
+ <td>NT Groups</td>
+ <td>Entries that describe a group of NT users.</td>
+ </tr>
+ <tr>
+ <td valign="top">Organizations</td>
+ <td valign="top">Entries that describe an organization.
+ An organization is usually a single, very
+ large organization such as a corporation or a university.
+ An organization differs from a group in that a
+ group is typically an arbitrary collection of people or
+ devices that is subject to change as entities are added
+ to or removed from the directory. Organizations, however,
+ represent a major, relatively static, subdivision or
+ branching of the directory. Additions and
+ subtractions of entities within the directory do not usually
+ affect organization entries.</td>
+ </tr>
+ <tr>
+ <td valign="top">Domain Components</td>
+ <td valign="top">Entries that describe your domain.
+ The Domain Component represents your directory suffix by
+ breaking your domain name into its component parts. In a
+ single enterprise environment, a directory suffix typically
+ aligns with a DNS name or Internet domain name of your
+ enterprise. For example, if your enterprise owns the domain
+ name of example.com, then your directory suffix would be of
+ the form dc=example,dc=com.
+ </tr>
+ <tr>
+ <td valign="top">Org-Units</td>
+ <td valign="top">Entries that describe an organizational
+ unit. Organizational units usually identify major
+ subdivisions within a larger organization. In contrast to
+ entries from a single, very large organization such as a
+ corporation or university, organizational units describe
+ smaller organizations such as accounting, marketing, the
+ humanities, or Biology. </td>
+ </tr>
+ <tr>
+ <td valign="top">Anything </td>
+ <td valign="top">Any type of entry within the directory
+ that matches the search criteria. Use Anything
+ if you are unsure of how the directory manager
+ represented an entry within the directory. Anything is
+ also useful if the type of entry for which you are
+ searching is not a person, group, or organization.</td>
+ </tr>
+</table>
+
+<p>After the Directory Server completes the search, the Directory
+Server interface displays the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">search results</a>,
+which provide links to all matching entries. When you click an
+entry displayed on the search results list, the Directory Server
+displays detailed information about the entry. If the entry is a
+person, you can also choose to <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#vCard">view the person's
+digital business card</a>, or vCard. Using the vCard, you can
+add the person to your Communicator address book with a
+click of a button.</p>
+
+<h2><a name="standard"></a>Standard Search</h2>
+
+<p>Standard search performs different types of searches according to the
+nature of the data that you specify. Depending on what
+you type in the search field, Standard Search attempts to find
+matching <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#Name">names</a>, <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#phone">telephone
+numbers</a>, or <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#email">email addresses</a>. </p>
+
+<p>Depending on what you enter, Standard Search
+determines whether to find entries that exactly match your
+criteria, entries that contain your criteria, or entries that
+contain words or syllables that sound like your criteria. You can also use
+an LDAP (Lightweight Directory Access Protocol) <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#filter">search filter</a>
+in the Standard Search field.</p>
+
+<h3><a name="Performing a Standard Search"></a>Performing a
+Standard Search</h3>
+
+<ol>
+ <li>Click the Standard Search tab.</li>
+ <li>Select the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#type">type of entry</a> you want to
+ search for from the Find drop-down list.</li>
+ <li>Enter the value you want to find in the "Search
+ for" field. The "Search for" field
+ is not case sensitive. You can enter any of the following:
+ <ul type="disc">
+ <li>A <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#Name">name</a> or part of a name </li>
+ <li>A person's <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#initials">initials</a> </li>
+ <li>Some or all of a <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#phone">phone number</a>
+ </li>
+ <li>Some or all of an <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#email">email
+ address</a> </li>
+ <li>An LDAP <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#filter">search filter</a></li>
+ </ul>
+ </li>
+ <li>Click Submit. <br>
+ Once the form data has been submitted to the Directory
+ Server, the server searches for any entries
+ that exactly match, partially match, or sound like the
+ value you supplied. The resulting matches are displayed
+ as a <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#results">search results</a> table.</li>
+</ol>
+
+<h4><a name="Name"></a>Searching for Names</h4>
+
+<p>If the string you specify:</p>
+
+<ul>
+ <li>contains characters other than numbers </li>
+ <li>does not contain an at (@) symbol </li>
+</ul>
+
+<p>Standard Search attempts to find full names, first names, or
+last names that exactly match, partially match, or sound like the
+supplied value.</p>
+
+<p>For example, specifying the string <font face="Courier">son</font>
+could return results such as: </p>
+
+<p>
+<ul>
+ <li>Gary Stevenson</li>
+ <li>Mary Sun</li>
+ <li>Allison Barker</li>
+</ul>
+
+<h4><a name="initials"></a>Searching for Names with Initials</h4>
+
+<p>If you specify a value that includes the following items in
+the following order:</p>
+
+<ol>
+ <li>a single letter </li>
+ <li>a space ( ), period (.), or period and space in any order</li>
+ <li>one or more characters </li>
+</ol>
+
+<p>then Standard Search executes the search as if you
+requested a first initial followed by a last name. For example,
+specifying the string &quot;S.Anderson&quot; could return results
+such as:</p>
+
+<ul>
+ <li>Sally Anderson</li>
+ <li>Steve Anderson</li>
+ <li>Sue Anderson</li>
+</ul>
+
+<p>Similarly, if you specify a value that has the following items
+in the following order:</p>
+
+<ol>
+ <li>more than one character</li>
+ <li>a space ( ), period (.), or period and space in any order</li>
+ <li>a single character </li>
+</ol>
+
+<p>then Standard Search executes the search as if you
+requested a first name followed by a last initial. For example,
+specifying the string <font face="Courier New">&quot;</font>Mark
+.P&quot; could return search results such as:</p>
+
+<ul>
+ <li>Mark Payne</li>
+ <li>Mark Peck</li>
+ <li>Mark Polk</li>
+</ul>
+
+<blockquote>
+ <p><b>Note: </b></p>
+ <p>When you use initials Standard Search looks only for exact matches.
+ It returns entries with names that use the
+ same initial and name as you specify on the search.
+ Approximate (or &quot;sounds-like&quot;) and substring
+ searches are not performed. </p>
+</blockquote>
+
+<h4><a name="phone"></a>Searching for Phone Numbers</h4>
+
+<p>Standard Search automatically searches for a phone number if
+the value you enter consists only of numerical digits. A single
+hyphen (-) is also allowed if at least one digit precedes
+it.</p>
+
+<p>This type of search is an &quot;ends with&quot; search. That
+is, the Directory Server searches for any phone numbers that end
+with the specified value. For example, if you enter a value such
+as <tt>123</tt>, the Directory Server searches for all phone numbers that
+end with 123.</p>
+
+<h4><a name="email"></a>Searching for Email Addresses</h4>
+
+<p>Standard Search automatically searches for matching email
+addresses if you provide a value that contains an at (@) symbol.
+Standard Search first searches for any email addresses that
+exactly match the value you entered. If Standard Search doesn't
+find any matching entries, it then searches for any entries that
+start with the value you entered. </p>
+
+<p>For example, specifying the string <font face="Courier">son@</font>
+could return:</p>
+
+<ul>
+ <li>son@</li>
+</ul>
+or, if no exact match exists in the directory:
+<ul>
+ <li>son@aardvark.org</li>
+ <li>son@acme.com</li>
+</ul>
+
+<h4><a name="filter"></a>Using Search Filters</h4>
+
+<p>Rather than allowing Standard Search to determine the correct
+type of search, you can explicitly specify an LDAP search filter.
+An LDAP search filter allows you to search for entries with a
+specific <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm">attribute</a> value.
+Standard Search assumes that any string containing an equal sign
+(=) is an LDAP search filter. For example,</p>
+
+<pre>cn=*eve*</pre>
+
+<p>is an LDAP search filter that performs a substring search for
+any common name (CN) containing the string <tt>eve</tt>.
+When specifying attributes within an LDAP search filter, you
+must use the attribute label used by the Directory Server
+internally, the internal ID, rather than the attribute
+field name as displayed in the Directory Server interface.
+For example, the internal ID for the Full Name attribute field
+is <TT>cn</TT>. When you enter a search filter in Standard Search,
+use the internal ID (commonName) rather than the attribute field name (Full Name)
+as follows:
+</P>
+<P><TT>commonName=Smith Fukuda</TT></P>
+
+<P>Some attribute fields also have a second, abbreviated internal ID. For example, the Full Name field has two
+internal IDs: commonName and cn. You can use either name in the search filter.
+</p>
+
+<p>For more information on search filters, refer to
+the <em>Directory Server Administrator's Guide</em>.</p>
+
+<h2><a name="advanced"></a>Advanced Search</h2>
+
+<p>With Advanced Search, you can search for entries that have
+specific values for certain attributes. For example, Advanced
+Search allows you to look for a person whose email address is a
+specified value. Advanced Search also allows you to look up
+entries that do <i>not</i> include a specified attribute value. For
+example, you can find all the people whose last name is not
+&quot;Smith&quot; (such a search is likely to return a
+large number of results, so you may want to avoid these kinds of
+searches).</p>
+
+<p>Advanced Search performs an exact search, returning entries
+that exactly match the words you enter. There are four fields in
+the Advanced Search form that you use to construct your search.
+Together these four fields represent a sentence specifying the
+search. In general, the sentence is constructed as follows: </p>
+
+<p><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#type">Find:</a><i> [a type of entry] </i><a
+href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#wherethe">where the:</a><i> [attribute] </i><a
+href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#typeofsearch">[type of search]</a><i> [search
+string]</i></p>
+
+<p>The options
+for the first three of these fields are provided in pull-down
+menus. The last field contains the actual search string. For example, you can
+construct a search to:</p>
+
+<p><b>Find:</b><i> </i>[People]<i> </i><b>where the: </b>[Last
+Name] [is] [Bowker]</p>
+
+<p>Or you can construct a search to: </p>
+
+<p><b>Find: </b>[People] <b>where the: </b>[Full Name] [sounds
+like] [tree]</p>
+
+<h3><a name="Performing an Advanced Search"></a>Performing an
+Advanced Search</h3>
+
+<ol>
+ <li>Click the Advanced Search tab.</li>
+ <li>Select the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#type">type of entry</a> you want to
+ search for from the Find drop-down list.</li>
+ <li>Select the attribute you want to search for from the "where
+ the" field drop-down list. The choices
+ vary depending on the type of entry you selected in the Find
+ field. The options are explained in the following table.<br>
+<P>
+ <table border="2">
+ <tr>
+ <th><a name="wherethe"></a><b>If the Find field
+ is . . .</b></th>
+ <th><b>You can choose . . .</b></th>
+ </tr>
+ <tr>
+ <td>People</td>
+ <td><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">full name</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#surname">last name</a>, <a
+ href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">phone number</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#mail">email address</a>, <a
+ href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#uid">user ID</a>, or <a
+ href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#title">title</a></td>
+ </tr>
+ <tr>
+ <td>Groups</td>
+ <td><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">name</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">description</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#owner">owner</a>, or
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#member">member</a></td>
+ </tr>
+ <tr>
+ <td>Organizations</td>
+ <td><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">name</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#l">location</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">phone
+ number</a>, or <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">description</a></td>
+ </tr>
+ <tr>
+ <td>Domaincomponent</td>
+ <td><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">name</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#l">location</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">phone
+ number</a>, or <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">description</a></td>
+ </tr>
+ <tr>
+ <td>Org-Units</td>
+ <td><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">name</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#l">location</a>,
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#telephoneNumber">phone
+ number</a>, or <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">description</a></td>
+ </tr>
+ <tr>
+ <td>Anything</td>
+ <td><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#cn">name</a> or
+ <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/attribut.htm#description">description</a></td>
+ </tr>
+ </table>
+ </li>
+<P>
+ <li>Select the type of search you want to perform. <br>
+ <br>
+ In general, this field indicates if the search is to be
+ an equality search, substring search, or approximate
+ (&quot;sounds like&quot;) search. The following defines
+ all of the available keywords and the type of search
+ that each represents. Not all of these keywords
+ are available for every search; the actual keywords you
+ can use depends on the values you select for the 'Find'
+ and "where the" fields. You can
+ choose one of the following:
+<p>
+ <table border="2">
+ <tr>
+ <th><a name="typeofsearch"></a><b>Type of search</b></th>
+ <th><b>Description</b></th>
+ </tr>
+ <tr>
+ <td>is</td>
+ <td>Finds an exact match. That is,
+ this option specifies an equality search. Use
+ this option when you know the exact value of an
+ entry's attribute. For example, if you know the
+ exact spelling of a person's last name, use this
+ option. </td>
+ </tr>
+ <tr>
+ <td>is not</td>
+ <td>Returns all the entries having an attribute value
+ that does not exactly match the search string. That
+ is, if you want to find all the people in the
+ directory whose last name is not
+ &quot;Smith,&quot; use this option. Be aware,
+ however, that use of this option can return an
+ extremely large number of entries. </td>
+ </tr>
+ <tr>
+ <td>sounds like</td>
+ <td>Finds phonetic matches. Use this option if you know an
+ attribute's value, but you are unsure of the
+ spelling. For example, if you are not sure if a
+ person's last name is spelled &quot;Sarret,&quot;
+ &quot;Sarette,&quot; or &quot;Sarett,&quot; use
+ this option. </td>
+ </tr>
+ <tr>
+ <td>starts with</td>
+ <td>Performs a substring search.
+ Entries having attributes with values starting with the
+ specified search string are returned. For
+ example, if you know a person's first name is
+ &quot;Steve,&quot; but you do not know the last
+ name, use this option on a full name search. </td>
+ </tr>
+ <tr>
+ <td>ends with</td>
+ <td>Performs a substring search.
+ Entries having attributes with values ending with the specified
+ search string are returned. For example, if you
+ know the last four digits of a person's telephone
+ number are &quot;9876,&quot; use this option to
+ locate the person's entry. </td>
+ </tr>
+ <tr>
+ <td>contains</td>
+ <td>Performs a substring search.
+ Entries having attributes with values containing the specified
+ search string are returned. For example, if you
+ know an organization's description
+ contains the word &quot;support,&quot; use this
+ option with the search string &quot;support&quot;
+ to find the organization's entry.</td>
+ </tr>
+ </table>
+ </li>
+<p>
+ <li>Enter the string you want to search against in the text
+ box and click Search.<br>
+ Once the form data has been submitted to the directory
+ server, the Directory Server searches for any entries
+ that exactly match the value you supplied. The resulting
+ matches are displayed as a search results list.</li>
+</ol>
+
+<h3><a name="Advanced Search Examples"></a>Advanced Search
+Examples</h3>
+
+<p>The following examples show a few possible uses of the
+Advanced Search form. The vertical bars (|) delimit the various
+fields in the form.</p>
+
+<table border="2">
+ <tr>
+ <th><b>To find . . .</b></th>
+ <th><b>Enter . . .</b></th>
+ </tr>
+ <tr>
+ <td>All people named Darlene</td>
+ <td><b>Find:</b> People | <b>where the:</b> full name |
+ starts with | Darlene</td>
+ </tr>
+ <tr>
+ <td>All people with the last name Sweeney</td>
+ <td><b>Find:</b> People | <b>where the:</b> last name |
+ is | Sweeny</td>
+ </tr>
+ <tr>
+ <td>All the people who are vice presidents</td>
+ <td><b>Find:</b> People | <b>where the:</b> title |
+ contains | Vice President</td>
+ </tr>
+ <tr>
+ <td>The organization named Accounting</td>
+ <td><b>Find:</b> Organization | <b>where the:</b> name |
+ is | Accounting</td>
+ </tr>
+ <tr>
+ <td>Groups interested in scuba diving</td>
+ <td><b>Find:</b> Groups | <b>where the:</b> description |
+ contains | scuba</td>
+ </tr>
+ <tr>
+ <td>Any entry with a name that contains the word
+ &quot;printer&quot;</td>
+ <td><b>Find:</b> Anything | <b>where the:</b> name |
+ contains | printer</td>
+ </tr>
+</table>
+
+<h2><a name="results"></a>Viewing Search Results</h2>
+
+<p>When you perform a search using either a Standard Search or an
+Advanced Search, the Directory Server interface sends the search
+data to the Directory Server. The Directory Server performs the
+search and then returns any matching entries to the directory
+server interface. The resulting display depends on whether there
+were:</p>
+
+<ul>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#nomatch">no matches</a></li>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#single">a single match</a></li>
+ <li><a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#multiple">multiple matches</a></li>
+</ul>
+
+<p>This section also discusses some of the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#problems">other
+problems</a> you may run into when attempting to search the
+directory tree.</p>
+
+<h3><a name="nomatch"></a>No Matches </h3>
+
+<p>A search result that returns no matches means one of the
+following. </p>
+
+<ul>
+ <li>No entries in the directory match your search
+ criteria. If you believe that this is the problem, try
+ another search using slightly different parameters to
+ see if you can get any other results.</li>
+ <li>You did not <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#1016877">authenticate</a>
+ before performing the search. The directory administrator
+ determines Authentication requirements. Your
+ directory administrator can set the access control on the
+ directory so that you are required to
+ authenticate before you can search the tree. This access
+ control can be set for the entire directory or for
+ just part of it. If you are required to
+ authenticate before you can search the directory tree,
+ and you do not authenticate before running the search,
+ the Directory Server acts as if no matching
+ entries were found in the directory; no message informs you
+ that you need to authenticate. This is for security reasons. Contact your
+ directory administrator to find out if you must
+ authenticate to the Directory Server before running a
+ search. See Chapter 5, &quot;Authentication&quot;
+ for more information on authentication.</li>
+ <li>The access control for the tree disallows you
+ from viewing the entry or entries; regardless of authentication.</li>
+</ul>
+
+<h3><a name="single"></a>A Single Match<b> </b></h3>
+
+<p>If one and only one match is returned in response to an
+&quot;is&quot; search, the Directory Server interface displays
+information about that entry as a result of the search. If the
+single result was found using any other search method, it is
+displayed in a table, and you must click the link to view
+detailed information about the entry. This form
+contains a button that allows you to <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/mod.htm">edit</a>
+the entry. You must have the appropriate permissions to edit an
+entry, and you need to <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/auth.htm#userauth">authenticate</a>
+before doing so. </p>
+
+<h3><a name="multiple"></a>Multiple Matches<b> </b></h3>
+
+<p>If multiple matches are found in response to your
+search, the directory interface displays
+a table listing each of the matching entries and
+certain relevant information for each entry, such as the entry's
+phone number and email address. The type of entry for which
+you are searching determines this information.
+To view more information on a specific entry, click the
+entry's name in the first column of the table. </p>
+
+<h3><a name="problems"></a><b>Other Problems</b></h3>
+
+<p>You may see odd results if you are searching for numerical
+values because the Directory Server stores all values as
+strings, regardless of whether they are actually numerical values
+(such as telephone or room numbers). Consequently, when you
+search for numerical values, be sure to include all spaces and
+leading zeros, if any. </p>
+
+<p>Also note that the Directory Server interface strips all
+leading and trailing blank spaces from your search criteria.
+While it is unlikely that directory entries actually have leading
+and trailing blank spaces in their values, the possibility still
+exists. Because of this, exact matches against values that have
+leading and trailing blank spaces fail. If you encounter
+this problem, try using a substring search (a
+&quot;contains&quot; search) instead of an exact search. </p>
+
+<h2><a name="vCard"></a>Viewing a vCard</h2>
+
+<p>A vCard is a digital business card. Like a regular business
+card, a vCard contains contact information about a person such as
+name, title, telephone and fax numbers, and email
+address. Unlike a regular business card, however, the vCard can
+also contain multimedia elements such as graphics, sound,
+and video. To view a vCard, do the following:</p>
+
+<ol>
+ <li>Use the <a href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#standard">Standard Search</a> or <a
+ href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=.MANUAL/search.htm#advanced">Advanced Search</a> mechanism to locate
+ the person whose vCard you want to view.</li>
+ <li>Click the View Card button.<br>
+ The Directory Server interface displays a condensed
+ version of the vCard.</li>
+ <li>If you want to see more details, click View
+ Complete Card.</li>
+ <li>If you want to add the person to your Communicator
+ address book, click "Add to Address Book"
+ and then click OK.</li>
+</ol>
+</body>
+</html>
diff --git a/ldap/clients/dsgw/html/manual/t.gif b/ldap/clients/dsgw/html/manual/t.gif
new file mode 100644
index 00000000..8068a16f
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/t.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/manual/y.gif b/ldap/clients/dsgw/html/manual/y.gif
new file mode 100644
index 00000000..1a27f360
--- /dev/null
+++ b/ldap/clients/dsgw/html/manual/y.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/message.gif b/ldap/clients/dsgw/html/message.gif
new file mode 100644
index 00000000..e46c67a0
--- /dev/null
+++ b/ldap/clients/dsgw/html/message.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/netscape.gif b/ldap/clients/dsgw/html/netscape.gif
new file mode 100644
index 00000000..81a3e4a6
--- /dev/null
+++ b/ldap/clients/dsgw/html/netscape.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/newentrytitle.html b/ldap/clients/dsgw/html/newentrytitle.html
new file mode 100644
index 00000000..4c668396
--- /dev/null
+++ b/ldap/clients/dsgw/html/newentrytitle.html
@@ -0,0 +1,156 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<body bgcolor="#FFFFFF" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0">
+
+<TABLE width="100%" cellspacing="0" cellpadding="0" border="0" class="bgColor4">
+ <TR>
+ <TD>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td colspan="4"><img border="0" height="10" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td><a href="http://www.netscape.com"><img border="0" height="19" width="19" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=netscape.gif"></a></td>
+ <td><img border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true" align=left width="100%" class="appName">Netscape Directory Server Gateway</td>
+ </tr>
+ <tr>
+ <td colspan="4"><img border="0" height="12" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ </table>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Standard Search'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Standard Search" ALT="Standard Search">Standard Search</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Advanced Search'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Advanced Search" ALT="Advanced Search">Advanced Search</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgAtTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_on.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_on.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgAtTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><A HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='New Entry'; return true;"
+ onMouseOut="self.status=''; return true;" TITLE="New Entry"
+ ALT="New Entry" class="link7">New Entry</a></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_bottom.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td><img border="0" height="1" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_bottom.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html"
+ TARGET="_top" onMouseOver="self.status='Authentication'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Authentication" ALT="Authentication">Authentication</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+
+ <td width="100%"><img border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </TR>
+ <TR>
+ <TD class="bgRegTab" colspan="5"><IMG border="0" height="1" width="5" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ <TD class="bgAtTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ <TD class="bgRegTab" colspan="3"><IMG border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ <TABLE class="bgAtTab" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <TR>
+ <TD>
+ <IMG border="0" height="43" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </TD>
+ </TR>
+ <TR>
+ <TD class="bgRegTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ <TR>
+ <TD class="bgDarkRule"><IMG border="0" height="2" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+</TABLE>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/organization.gif b/ldap/clients/dsgw/html/organization.gif
new file mode 100644
index 00000000..6324da4b
--- /dev/null
+++ b/ldap/clients/dsgw/html/organization.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/orgicon.gif b/ldap/clients/dsgw/html/orgicon.gif
new file mode 100644
index 00000000..034f2c20
--- /dev/null
+++ b/ldap/clients/dsgw/html/orgicon.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/orgunit.gif b/ldap/clients/dsgw/html/orgunit.gif
new file mode 100644
index 00000000..56b7c59e
--- /dev/null
+++ b/ldap/clients/dsgw/html/orgunit.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/person.gif b/ldap/clients/dsgw/html/person.gif
new file mode 100644
index 00000000..958547e0
--- /dev/null
+++ b/ldap/clients/dsgw/html/person.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/right_bottom.gif b/ldap/clients/dsgw/html/right_bottom.gif
new file mode 100644
index 00000000..b49e450e
--- /dev/null
+++ b/ldap/clients/dsgw/html/right_bottom.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/right_off.gif b/ldap/clients/dsgw/html/right_off.gif
new file mode 100644
index 00000000..cf5b930b
--- /dev/null
+++ b/ldap/clients/dsgw/html/right_off.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/right_on.gif b/ldap/clients/dsgw/html/right_on.gif
new file mode 100644
index 00000000..643b540b
--- /dev/null
+++ b/ldap/clients/dsgw/html/right_on.gif
Binary files differ
diff --git a/ldap/clients/dsgw/html/searchtitle.html b/ldap/clients/dsgw/html/searchtitle.html
new file mode 100644
index 00000000..41719512
--- /dev/null
+++ b/ldap/clients/dsgw/html/searchtitle.html
@@ -0,0 +1,157 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>Netscape Directory Server</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<body bgcolor="#FFFFFF" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0">
+
+<TABLE width="100%" cellspacing="0" cellpadding="0" border="0" class="bgColor4">
+ <TR>
+ <TD>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td colspan="4"><img border="0" height="10" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td><a href="http://www.netscape.com"><img border="0" height="19" width="19" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=netscape.gif"></a></td>
+ <td><img border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true" align=left width="100%" class="appName">Netscape Directory Server Gateway</td>
+ </tr>
+ <tr>
+ <td colspan="4"><img border="0" height="12" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </td>
+ </tr>
+ </table>
+ <table class="bgColor1" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <tr>
+ <td><img border="0" height="1" width="15" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgAtTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_on.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_on.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgAtTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><A HREF="/clients/dsgw/bin/search?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Standard Search'; return true;"
+ onMouseOut="self.status=''; return true;" TITLE="Standard Search"
+ ALT="Standard Search" class="link7">Standard Search</a></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_bottom.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td><img border="0" height="1" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_bottom.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/csearch?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='Advanced Search'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Advanced Search" ALT="Advanced Search">Advanced Search</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/newentry?<!-- GCONTEXT -->"
+ TARGET="_top" onMouseOver="self.status='New Entry'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="New Entry" ALT="New Entry">New Entry</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+ <td><img border="0" height="1" width="3" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td>
+ <table class="bgRegTab" border="0" cellpadding="0" cellspacing="0">
+ <tr>
+ <td rowspan="3"><img border="0" height="23" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=left_off.gif"></td>
+ <td colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td rowspan="3"><img border="0" height="23" width="9" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=right_off.gif"></td>
+ </tr>
+ <tr>
+ <td class="bgRegTabHighlight" colspan="2"><img border="0" height="1" width="2" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ <tr>
+ <td><img border="0" height="21" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ <td nowrap="true"><a class="link6" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=auth.html"
+ TARGET="_top" onMouseOver="self.status='Authentication'; return true;"
+ onMouseOut="self.status=''; return true;"
+ TITLE="Authentication" ALT="Authentication">Authentication</a></td>
+ </tr>
+ <tr>
+ <td class="bgColor1" colspan="4"><img border="0" height="1" width="4" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </tr>
+ </table>
+ </td>
+
+ <td width="100%"><img border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></td>
+ </TR>
+ <TR>
+ <TD class="bgRegTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ <TD class="bgAtTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ <TD class="bgRegTab" colspan="7"><IMG border="0" height="1" width="7" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ <TABLE class="bgAtTab" border="0" cellpadding="0" cellspacing="0" width="100%">
+ <TR>
+ <TD>
+ <IMG border="0" height="43" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif">
+ </TD>
+ </TR>
+ <TR>
+ <TD class="bgRegTab"><IMG border="0" height="1" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ <TR>
+ <TD class="bgDarkRule"><IMG border="0" height="2" width="1" src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif"></TD>
+ </TR>
+ </TABLE>
+ </TD>
+ </TR>
+</TABLE>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/html/style.css b/ldap/clients/dsgw/html/style.css
new file mode 100644
index 00000000..d6d59a0e
--- /dev/null
+++ b/ldap/clients/dsgw/html/style.css
@@ -0,0 +1,142 @@
+/* ======================================================= *
+ * Style sheet for the Directory Express application *
+ * ======================================================= */
+
+/* All Links */
+A:link {font-family: verdana, Arial, Helvetica, sans-serif; color: #0033cc; font-size: 11px}
+A:active {color: #0033cc; font-size: 11px;}
+A:visited {color: #0033cc; font-size: 11px;}
+
+/*All Regular Table Data--for the whole application*/
+body {
+ background-color: #FFFFFF;
+ font-family: Verdana, Arial, Helvetica, san-serif;
+ font-size: 11px;
+}
+
+td {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ color: #000000;
+ vertical-align : middle;
+}
+
+th {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ font-weight: bold;
+ color: #ffffff;
+ vertical-align : middle;
+ background-color: #336699;
+}
+
+
+p {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ color: #000000;
+}
+
+
+td.bold {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ vertical-align : middle;
+ color: #000000;
+ font-weight: bold;
+}
+
+td.boldbig {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align : middle;
+ color: #000000;
+ font-weight: bold;
+}
+
+input {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ /*color: #000000;*/
+}
+
+
+A.searchlinknorm:link {color: #CCFFFF}
+A.searchlinknorm:visited {color: #CCFFFF}
+A.searchlinknorm:active {color: #CCFFFF}
+
+A.searchlinkspec:link {color: #FF0000}
+A.searchlinkspec:visited {color: #FF0000}
+A.searchlinkspec:active {color: #CCFFFF}
+
+/* *********Search frame*************/
+
+body.Search {
+ background-color: #003366;
+ font-family: Verdana, Arial, Helvetica, san-serif;
+ color: #ccffff;
+ font-size: 12px;
+}
+
+td.appName {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align : middle;
+ color: #ccffff;
+ font-weight: bold;
+}
+
+.apptext {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align: middle;
+ color: #ccffff;
+}
+
+/* Special Links */
+.linknodec {text-decoration:none; color:#000000; font-family: verdana, Arial, Helvetica, sans-serif; font-size: 11px}
+
+.link3 {color: #ccffff; font-size: 11px;}
+.link3:Link {color: #ccffff; font-size: 11px;}
+.link3:Active {color: #ccffff; font-size: 11px;}
+.link3:Visited {color: #ccffff; font-size: 11px;}
+.link3:Hover {color: #ccffff; font-size: 11px;}
+
+.link6 {color: #ffffff; font-size: 12px; font-weight: bold; text-decoration: none;}
+.link6:Link {color: #ffffff; font-size: 12px; font-weight: bold; text-decoration: none;}
+.link6:Hover {color: #ffffff; font-size: 12px; font-weight: bold; text-decoration: none;}
+.link6:Visited {color: #ffffff; font-size: 12px; font-weight: bold; text-decoration: none;}
+.link6:Active {color: #ffffff; font-size: 12px; font-weight: bold; text-decoration: none;}
+
+.link7 {color: #003366; font-size: 12px; font-weight: bold; text-decoration: none;}
+.link7:Link {color: #003366; font-size: 12px; font-weight: bold; text-decoration: none;}
+.link7:Hover {color: #003366; font-size: 12px; font-weight: bold; text-decoration: none;}
+.link7:Visited {color: #003366; font-size: 12px; font-weight: bold; text-decoration: none;}
+.link7:Active {color: #003366; font-size: 12px; font-weight: bold; text-decoration: none;}
+
+.link14 {color: #ffffff; font-size: 11px;}
+.link14:Link {color: #ffffff; font-size: 11px;}
+.link14:Hover {color: #ffffff; font-size: 11px;}
+.link14:Visited {color: #ffffff; font-size: 11px;}
+.link14:Active {color: #ffffff; font-size: 11px;}
+
+/* Fonts */
+.text8 {color: #0099cc; font-size: 11px; font-family: Verdana, Arial, Helvetica; font-weight: bold;}
+.text15 {color: #ffffff; font-size: 12px; font-family: Verdana, Arial, Helvetica; font-weight: bold;}
+.text30 {color: #CCFFFF; font-size: 8px; font-family: Verdana, Arial, Helvetica;}
+.text31 {color: #000000; font-size: 14px; font-family: Verdana, Arial, Helvetica; font-weight: bold;}
+.text22 {color: #000000; font-size: 11px; font-family: Verdana, Arial, Helvetica;}
+
+.bgColor1 {background-color: #003366;}
+.bgColor4 {background-color: #cccccc;}
+.bgColor7 {background-color: #66ccff;}
+.bgColor9 {background-color: #336699;}
+.bgColor16 {background-color: #0033CC;}
+
+/* background colors for tabs and tab area */
+.bgAtTab {background-color: #ccffff;}
+.bgAtTabHighlight {background-color: #ffffff;}
+.bgRegTab {background-color: #0099cc;}
+.bgRegTabHighlight {background-color: #66ccff;}
+.bgInsideRule {background-color: #66ccff;}
+.bgDarkRule {background-color: #000000;}
diff --git a/ldap/clients/dsgw/html/transparent.gif b/ldap/clients/dsgw/html/transparent.gif
new file mode 100644
index 00000000..afa7fb83
--- /dev/null
+++ b/ldap/clients/dsgw/html/transparent.gif
Binary files differ
diff --git a/ldap/clients/dsgw/htmlout.c b/ldap/clients/dsgw/htmlout.c
new file mode 100644
index 00000000..456a649a
--- /dev/null
+++ b/ldap/clients/dsgw/htmlout.c
@@ -0,0 +1,431 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * htmlout.c -- routines to output HTML elements -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+#define DSGW_POSTEDVARARG_NAME "name"
+
+static char*
+dsgw_change( char *s, dsgwsubst *changes )
+{
+ auto dsgwsubst *ch;
+ if ( changes == NULL ) return s;
+ for ( ch = changes; ch; ch = ch->dsgwsubst_next ) {
+ if ( strstr( s, ch->dsgwsubst_from ) ) {
+ break;
+ }
+ }
+ if ( ch != NULL ) {
+ auto char *cs = dsgw_ch_strdup( s );
+ for ( ch = changes; ch; ch = ch->dsgwsubst_next ) {
+ auto const size_t from_len = strlen( ch->dsgwsubst_from );
+ auto const size_t to_len = strlen( ch->dsgwsubst_to );
+ auto const long change_len = to_len - from_len;
+ auto char *p;
+ for ( p = cs; (p = strstr( p, ch->dsgwsubst_from )) != NULL; p += to_len ) {
+ if ( change_len ) {
+ if ( change_len > 0 ) { /* allocate more space: */
+ auto const size_t offset = p - cs;
+ cs = dsgw_ch_realloc( cs, strlen( cs ) + change_len + 1 );
+ p = cs + offset;
+ }
+ memmove( p + to_len, p + from_len, strlen( p + from_len ) + 1 );
+ }
+ if ( to_len != 0 ) {
+ memcpy( p, ch->dsgwsubst_to, to_len );
+ }
+ }
+ }
+ return cs;
+ }
+ return s;
+}
+
+void
+dsgw_HTML_emits( char *s )
+{
+ auto char *sc = dsgw_change( s, gc->gc_changeHTML );
+ dsgw_emits( sc );
+ if ( sc != s ) free( sc );
+}
+
+void
+dsgw_html_begin( char *title, int titleinbody )
+{
+ static int header_done = 0;
+
+ if ( !header_done ) {
+ dsgw_emits( "<HTML>" );
+ dsgw_head_begin();
+ dsgw_emits( "\n" );
+ if ( title != NULL ) {
+ dsgw_emitf( "<TITLE>%s</TITLE>\n", title );
+ }
+ dsgw_emitf( "</HEAD>\n<BODY %s>\n", dsgw_html_body_colors );
+ } else {
+ dsgw_emits( "\n<HR>\n" );
+ }
+
+ if (( title != NULL ) && ( header_done || titleinbody )) {
+ dsgw_emitf( "<CENTER><TABLE BORDER=\"2\" CELLPADDING=\"10\" WIDTH=100%%>\n"
+ "<TR><TD ALIGN=\"center\" WIDTH=\"100%%\">\n<FONT SIZE=\"+2\">"
+ "<B>%s</B></FONT></TD></TR></TABLE></CENTER>\n<P>\n", title );
+ }
+
+ header_done = 1;
+}
+
+
+void
+dsgw_html_end()
+{
+ dsgw_emits( "</BODY></HTML>\n" );
+
+ /* make sure everything has been written to the server before we exit */
+ fflush( stdout );
+ fflush( stderr );
+}
+
+
+/*
+ * output a hypertext reference/URL:
+ * if "urlprefix" != NULL, it is prepended to "url" and "url" is hex-escaped.
+ * if "urlprefix" == NULL, "url" is assumed to be already escaped as needed.
+ *
+ * if "value" != NULL, any occurrence of "--value--" in "url" is replaced by
+ * a URL-escaped version of the actual value.
+ * if "value" == NULL, no substitution is done.
+ *
+ * if "label" == NULL or is of zero length, the closing ">LABEL</A>" is omitted.
+ */
+void
+dsgw_html_href( char *urlprefix, char *url, char *label, char *value,
+ char *extra )
+{
+ char *escaped_url, *tag = "--value--";
+ char *newlabel = NULL;
+ int freenewlabel;
+
+ if ( urlprefix == NULL ) {
+ dsgw_emits( "<A HREF=" );
+ escaped_url = NULL;
+ } else {
+ dsgw_emitf( "<A HREF=%s", urlprefix );
+ escaped_url = dsgw_ch_malloc( 3 * strlen( url ) + 1 );
+ *escaped_url = '\0';
+ dsgw_strcat_escaped( escaped_url, url );
+ url = escaped_url;
+ }
+
+ if ( value != NULL ) {
+ dsgw_substitute_and_output( url, tag, value, 1 );
+ } else {
+ dsgw_emits( url );
+ }
+
+ if ( extra != NULL ) {
+ dsgw_emits( " " );
+ if ( value != NULL ) {
+ dsgw_substitute_and_output( extra, tag, value, 1 );
+ } else {
+ dsgw_emits( extra );
+ }
+ }
+
+ newlabel = dsgw_strdup_with_entities( label, &freenewlabel );
+ if ( newlabel != NULL && *newlabel != '\0' ) {
+ dsgw_emitf( ">%s</A>\n", newlabel );
+ if ( freenewlabel ) {
+ free( newlabel );
+ }
+ } else {
+ dsgw_emits( "></A>\n" );
+ }
+
+ if ( escaped_url != NULL ) {
+ free( escaped_url );
+ }
+}
+
+
+void
+dsgw_substitute_and_output( char *s, char *tag, char *value, int escape )
+{
+ char *p, *escval;
+
+ escval = NULL;
+
+ while ( ( p = strstr( s, tag )) != NULL ) {
+ if ( p > s ) {
+ dsgw_emitn( stdout, s, p - s );
+ }
+ if ( escape ) {
+ if ( escval == NULL ) {
+ escval = dsgw_strdup_escaped( value );
+ }
+ dsgw_emits( escval );
+ } else {
+ dsgw_emits( value );
+ }
+
+ s = p + strlen( tag );
+ }
+
+ if ( escval != NULL ) {
+ free( escval );
+ }
+
+ if ( *s != '\0' ) {
+ dsgw_emits( s );
+ }
+}
+
+
+char *
+dsgw_strdup_escaped( const char *s )
+{
+ char *p;
+
+ p = dsgw_ch_malloc( 3 * strlen( s ) + 1 );
+ *p = '\0';
+ dsgw_strcat_escaped( p, s );
+ return( p );
+}
+
+
+/* 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 copied from libldap/tmplout.c:strcat_escaped */
+void
+dsgw_strcat_escaped( char *s1, const char *s2 )
+{
+ unsigned char *q;
+ char *p, *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[ 0x0F & ((*(unsigned char*)q) >> 4) ];
+ *p++ = hexdig[ 0x0F & *q ];
+ }
+ }
+
+ *p = '\0';
+}
+
+
+#define DSGW_MAX_ENTITY_LEN 6 /* &quot; */
+static char *specials = "&\"<>";
+static char *entities[] = { "&amp;", "&quot;", "&lt;", "&gt;" };
+static int entitylen[] = { 5, 6, 4, 4 };
+
+char *
+dsgw_strdup_with_entities( char *s, int *madecopyp )
+{
+/*
+ * If the UTF8 string "s" contains any HTML special characters, make a
+ * duplicate where the appropriate HTML "entities" have been substituted
+ * for the special chars. For example, "<mcs@ace.com>" will be translated
+ * to "&lt;mcs@ace.com&gt;".
+ *
+ * If "s" does not contain any special characters, it is returned and
+ * *madecopyp is set to 0.
+ * Otherwise a malloc'd string is returned and *madecopyp is set to 1.
+ */
+ int spcount, idx;
+ char *p, *q, *r, *d;
+
+ spcount = 0;
+ for ( p = s; *p != '\0'; LDAP_UTF8INC( p )) {
+ if ( ((*p) & 0x80) == 0 && strchr( specials, *p ) != NULL ) {
+ ++spcount;
+ }
+ }
+
+ if ( spcount == 0 ) {
+ *madecopyp = 0;
+ return( s );
+ }
+
+ d = r = dsgw_ch_malloc( strlen( s ) + 1 + spcount * DSGW_MAX_ENTITY_LEN );
+ for ( p = s; *p != '\0'; LDAP_UTF8INC( p )) {
+ if ( ((*p) & 0x80) == 0 && ( q = strchr( specials, *p )) != NULL ) {
+ idx = ( q - specials );
+ memcpy( r, entities[ idx ], entitylen[ idx ] );
+ r += entitylen[ idx ];
+ } else {
+ r += LDAP_UTF8COPY( r, p );
+ }
+ }
+ *r = '\0';
+
+ *madecopyp = 1;
+ return( d );
+}
+
+
+void
+dsgw_form_begin( const char* name, const char* format, ... )
+{
+ dsgw_emits ("<FORM method=POST");
+ if (name) {
+ dsgw_emitf (" name=\"%s\"", name);
+ }
+ if (format) {
+ va_list argl;
+ va_start (argl, format);
+ dsgw_emits (" ");
+ dsgw_emitfv (format, argl);
+ va_end (argl);
+ }
+ dsgw_emits (">");
+ dsgw_emitf("<INPUT type=hidden name=context value=\"%s\">", context);
+ dsgw_emitf ("<INPUT type=hidden name=charset value=\"%s\">",
+ (gc->gc_charset && *(gc->gc_charset)) ? gc->gc_charset : ISO_8859_1_ENCODING );
+}
+
+void
+dsgw_emit_cgi_var( int argc, char **argv )
+{
+ char *name, *postedvalue;
+
+ if (( name = get_arg_by_name( DSGW_POSTEDVARARG_NAME, argc, argv ))
+ == NULL ) {
+ dsgw_emitf( XP_GetClientStr(DBT_missingS_1), DSGW_POSTEDVARARG_NAME );
+ } else if (( postedvalue = dsgw_get_cgi_var( name, DSGW_CGIVAR_OPTIONAL ))
+ != NULL ) {
+ dsgw_emits( postedvalue );
+ }
+}
+
+void
+dsgw_emit_button( int argc, char **argv, const char* format, ... )
+{
+ auto char *name = get_arg_by_name( DSGW_ARG_BUTTON_NAME, argc, argv );
+ auto char *label = get_arg_by_name( DSGW_ARG_BUTTON_LABEL, argc, argv );
+
+ if ( !label ) label = XP_GetClientStr( DBT_closeWindow_3 );
+
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\"", label );
+ if ( name ) dsgw_emitf( " NAME=\"%s\"", name );
+ if ( format ) {
+ va_list argl;
+ va_start( argl, format );
+ dsgw_emits( " " );
+ dsgw_emitfv( format, argl );
+ va_end( argl );
+ }
+ dsgw_emits( ">" );
+}
+
+void
+dsgw_emit_alertForm ()
+{
+ dsgw_form_begin ("alertForm", "action=\"%s\" target=alertWindow",
+ DSGW_URLPREFIX_MAIN_HTTP "alert.html");
+ dsgw_emitf ("<INPUT TYPE=hidden NAME=TITLE VALUE=\"%s\">", XP_GetClientStr(DBT_alertTitle_));
+ dsgw_emits ("<INPUT TYPE=hidden NAME=MSG VALUE=\"\">"
+ "</FORM>\n");
+}
+
+void
+dsgw_emit_confirmForm ()
+{
+ dsgw_form_begin ("confirmForm", "action=\"%s\" target=confirmWindow",
+ DSGW_URLPREFIX_MAIN_HTTP "confirm.html");
+ dsgw_emitf ("<INPUT TYPE=hidden NAME=TITLE VALUE=\"%s\">", XP_GetClientStr(DBT_confirmTitle_));
+ dsgw_emits ("<INPUT TYPE=hidden NAME=MSG VALUE=\"\">"
+ "<INPUT TYPE=hidden NAME=YES VALUE=\"\">"
+ "<INPUT TYPE=hidden NAME=NO VALUE=\"\">"
+ "</FORM>\n");
+}
+
+static const char*
+defaultWindowOptions = "width=350,height=130,resizable";
+
+void
+dsgw_emit_alert (const char* frame, const char* windowOptions, const char* format, ...)
+{
+ if (!windowOptions) windowOptions = defaultWindowOptions;
+ dsgw_emits (" var aw = window.open(");
+ dsgw_emits ("''");
+/* dsgw_quote_emits (QUOTATION_JAVASCRIPT, DSGW_URLPREFIX_MAIN_HTTP "emptyFrame.html"); */
+ dsgw_emits ( ", 'alertWindow', ");
+ dsgw_quote_emits (QUOTATION_JAVASCRIPT, windowOptions);
+ dsgw_emits ( ");\n"
+ " aw.focus();\n"
+ " window."); /* Navigator 3 needs this */
+ if (frame) dsgw_emitf ("%s.", frame);
+ dsgw_emits ( "document.alertForm.MSG.value =");
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT);
+ if (format) {
+ va_list argl;
+ va_start (argl, format);
+ dsgw_emitfv (format, argl);
+ va_end (argl);
+ }
+ dsgw_quotation_end();
+ dsgw_emits ( ";\n"
+ " window.");
+ if (frame) dsgw_emitf ("%s.", frame);
+ dsgw_emits ("document.alertForm.submit();\n");
+}
+
+void
+dsgw_emit_confirm (const char* frame, const char* yes, const char* no,
+ const char* windowOptions, int enquote, const char* format, ...)
+{
+ if (!windowOptions) windowOptions = defaultWindowOptions;
+ dsgw_emits (" cw = window.open ('', 'confirmWindow', ");
+ dsgw_quote_emits (QUOTATION_JAVASCRIPT, windowOptions);
+ dsgw_emits ( ");\n"
+ " cw.focus();\n"
+ " if (cw.opener == null) cw.opener = self;\n" /* Navigator 2 needs this */
+ " window."); /* Navigator 3 needs this */
+ if (frame) dsgw_emitf ("%s.", frame);
+ dsgw_emits ( "document.confirmForm.MSG.value = ");
+ if (enquote) dsgw_quotation_begin (QUOTATION_JAVASCRIPT);
+ if (format) {
+ va_list argl;
+ va_start (argl, format);
+ dsgw_emitfv (format, argl);
+ va_end (argl);
+ }
+ if (enquote) dsgw_quotation_end();
+ dsgw_emits ( ";\n");
+
+ dsgw_emits (" window.");
+ if (frame) dsgw_emitf ("%s.", frame);
+ dsgw_emits ( "document.confirmForm.YES.value = ");
+ dsgw_quote_emits (QUOTATION_JAVASCRIPT, yes ? yes : "");
+ dsgw_emits ( ";\n");
+
+ dsgw_emits (" window.");
+ if (frame) dsgw_emitf ("%s.", frame);
+ dsgw_emits ( "document.confirmForm.NO.value = ");
+ dsgw_quote_emits (QUOTATION_JAVASCRIPT, no ? no : "");
+ dsgw_emits ( ";\n");
+
+ dsgw_emits (" window.");
+ if (frame) dsgw_emitf ("%s.", frame);
+ dsgw_emits ( "document.confirmForm.submit();\n");
+}
diff --git a/ldap/clients/dsgw/htmlparse.c b/ldap/clients/dsgw/htmlparse.c
new file mode 100644
index 00000000..cbb706af
--- /dev/null
+++ b/ldap/clients/dsgw/htmlparse.c
@@ -0,0 +1,805 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * htmlparse.c -- routines to parse HTML templates -- HTTP gateway.
+ * Stolen from libadmin/template.c and libadmin/form_get.c, originally
+ * by Mike McCool.
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+extern char *Versionstr; /* from Versiongw.c */
+
+/* global variables */
+char *dsgw_last_op_info; /* set in edit.c and genscreen.c */
+char *dsgw_dnattr; /* set in edit.c */
+char *dsgw_dndesc; /* set in edit.c */
+
+/*
+ * Save yourself a lot of grief and put a space after the name.
+ */
+
+static struct template_s templates[] = {
+ {"IF ", "FUNC conditional"},
+ {"ELSE ", "FUNC conditional"},
+ {"ELIF ", "FUNC conditional"},
+ {"ENDIF ", "FUNC conditional"},
+ {"TITLE ", "FUNC title"},
+ {"BODY ", "FUNC body"},
+ {"COLORS ", "FUNC colors"},
+ {"PAGEHEADER ", "FUNC pageheader"},
+ {"BEGININFO ", "<table border=2 width=100%% cellpadding=2>\n"
+ "<tr><td align=center colspan=2>"
+ "<b><FONT size=+1>%s</FONT></b></td></tr>"
+ "<td colspan=2>\n"},
+ {"ADDINFO ", "</td></tr><tr><td colspan=2>"},
+ {"ENDINFO ", "</td></tr></table>\n<hr width=10%%>\n"},
+ {"SUBMIT ", "FUNC submit\n"},
+ {"BEGINELEM ", "<pre>"},
+ {"ELEM ", "\n<b>%s</b>"},
+ {"ENDELEM ", "</pre>\n"},
+ {"ELEMADD ", "<b>%s</b>"},
+ {"ELEMDIV ", "\n"},
+ {"INDEX ", "<a href=\"index\">%s</a>\n"},
+ {"HELPBUTTON", "FUNC helpbutton"},
+ {"DIALOGSUBMIT", "FUNC dialogsubmit"},
+ {DRCT_DS_LAST_OP_INFO, "FUNC emit_last_op_info"},
+ {DRCT_DS_GATEWAY_VERSION, "FUNC emit_version_str"},
+ {DRCT_DS_ALERT_NOENTRIES " ", "FUNC emit_alert_noentries"},
+ {"ENDHTML", "</BODY></HTML>"},
+ {"GCONTEXT ", "context=%s"},
+ {"PCONTEXT ", "<INPUT TYPE=\"hidden\" NAME=\"context\" VALUE=\"%s\">\n"},
+ { NULL, NULL }
+};
+
+/* global to track output status */
+#define DSGW_PARSE_STATUS_NO_IF_SEEN -1
+#define DSGW_PARSE_STATUS_NO_OUTPUT 0
+#define DSGW_PARSE_STATUS_OUTPUT 1
+static int parse_status = DSGW_PARSE_STATUS_NO_IF_SEEN;
+
+static int dsgw_get_directive(char *string);
+static char **dsgw_get_vars(char *string, int *argc);
+static void dsgw_pageheader(int argc, char **argv);
+static void dsgw_title(int argc, char **argv);
+static void dsgw_body(int argc, char **argv);
+static void dsgw_colors(int argc, char **argv);
+static void dsgw_submit(int verify, char **vars);
+static void dsgw_dialogsubmit(void);
+static void dsgw_conditional(char *name, int argc, char **argv,
+ condfunc conditionalfn, void *condarg);
+static int dsgw_condition_true( int argc, char **argv,
+ condfunc conditionalfn, void *condarg );
+static void emit_last_op_info(int argc, char **argv);
+static void emit_version_str( void );
+static void emit_alert_noentries( void );
+static void template_error( char *msg );
+
+/* Filter a page. Takes the page to filter as an argument. Uses above
+ * filters to process. If we encounter a directive we don't know about,
+ * we set argc and argv, and return -1. The caller is responsible for
+ * figuring out what to do with the directive and arg vector.
+ *
+ * If parseonly is non-zero, this routine will just parse lines that contain
+ * directives -- nothing will be written to stdout.
+ */
+int
+dsgw_parse_line(
+char *line_input,
+int *argc,
+char ***argv,
+int parseonly,
+condfunc conditionalfn,
+void *condarg
+)
+{
+ register int index;
+ char *position;
+ int dirlen = strlen(DIRECTIVE_START);
+ char **vars;
+ int func_flag = 0;
+
+
+ *argc = 0;
+ *argv = NULL;
+ if ( !strncmp( line_input, DIRECTIVE_START, dirlen )) {
+ position = (char *) ( line_input + dirlen );
+ if ( parseonly ) {
+ index = -1; /* treat all directives as "unknown" */
+ } else {
+ index = dsgw_get_directive( position );
+ }
+
+ /* did we get one? */
+ if ( index != -1 ) {
+ /* if so, get the vars. */
+ position += strlen( templates[index].name );
+ vars = dsgw_get_vars( position, argc );
+ /* Dispatch the correct function (done for readability) */
+ if ( !strncmp(templates[ index ].format, "FUNC ", 5 )) {
+ func_flag = 1;
+ }
+
+ /* Don't check the parse_status for conditionals -RJP */
+ if (func_flag == 1 &&
+ !strncmp( templates[index].format+5, "conditional", 11 )) {
+ dsgw_conditional( templates[index].name, *argc, vars,
+ conditionalfn, condarg );
+ /* But do so for the other directives */
+ } else if (func_flag == 1 && parse_status != DSGW_PARSE_STATUS_NO_OUTPUT) {
+ if ( !strncmp( templates[ index ].format+5, "pageheader",10 ))
+ dsgw_pageheader( *argc, vars );
+ else if ( !strncmp( templates[index].format+5,"title",5))
+ dsgw_title( *argc, vars );
+ else if ( !strncmp( templates[index].format+5,"body",4))
+ dsgw_body( *argc, vars );
+ else if ( !strncmp( templates[index].format+5,"colors",6))
+ dsgw_colors( *argc, vars );
+ else if ( !strncmp( templates[ index ].format+5, "submit",6 ))
+ dsgw_submit( 0, vars );
+ else if ( !strncmp( templates[ index ].format+5, "verify",6 ))
+ dsgw_submit( 1, vars );
+ else if ( !strncmp( templates[index].format+5,
+ "dialogsubmit",12 ))
+ dsgw_dialogsubmit();
+ else if ( !strncmp( templates[index].format+5, "helpbutton", 10 ) && ( *argc > 0 ))
+ dsgw_emit_helpbutton( vars[ 0 ] );
+ else if ( !strncmp( templates[index].format+5,"emit_last_op_info", 17 ))
+ emit_last_op_info( *argc, vars );
+ else if ( !strncmp( templates[index].format+5, "emit_version_str", 16 ))
+ emit_version_str();
+ else if ( !strncmp( templates[index].format+5, "emit_alert_noentries", 20 ))
+ emit_alert_noentries();
+ else { /* We don't know what this template is. Send it back. */
+ *argv = vars;
+ return -1;
+ }
+ /*
+ * Handle the context case specially, because there is no
+ * vars generated, yet the format has a %s in it. Handle
+ * both the GCONTEXT and the PCONTEXT case (GET AND POST)
+ */
+ } else if ( parse_status != DSGW_PARSE_STATUS_NO_OUTPUT &&
+ !strcmp(templates[ index ].name + 1, "CONTEXT ")) {
+ char line[ BIG_LINE ];
+ PR_snprintf( line, BIG_LINE, templates[ index ].format, context);
+ dsgw_emits( line );
+
+ } else if ( parse_status != DSGW_PARSE_STATUS_NO_OUTPUT ) {
+ /* I just can't believe there's no easy way to create
+ * a va_list. */
+ char line[ BIG_LINE ];
+ PR_snprintf( line, BIG_LINE, templates[ index ].format,
+ ( *argc > 0 && vars[ 0 ] != NULL ) ? vars[ 0 ]: "",
+ ( *argc > 1 && vars[ 1 ] != NULL ) ? vars[ 1 ]: "",
+ ( *argc > 2 && vars[ 2 ] != NULL ) ? vars[ 2 ]: "",
+ ( *argc > 3 && vars[ 3 ] != NULL ) ? vars[ 3 ]: "");
+ dsgw_emits( line );
+ }
+ } else if ( parse_status != DSGW_PARSE_STATUS_NO_OUTPUT ) {
+ /* We found a directive, but we can't identify it. Return non-zero
+ * value so caller knows to deal with it.
+ */
+ vars = dsgw_get_vars( position, argc );
+ *argv = vars;
+ return -1;
+ }
+ } else if ( !parseonly && parse_status != DSGW_PARSE_STATUS_NO_OUTPUT ) {
+ auto char *gcontext = NULL;
+ auto char *start_of_newline = (char *) dsgw_ch_strdup(line_input);
+ auto char *new_line_input = start_of_newline;
+
+ /* We found no directive at the beginning. Look for GCONTEXT
+ * It could be anywhere in the line. Sorry, but that's the way
+ * It has to be. - RJP
+ */
+ for (gcontext = strstr(new_line_input, GCONTEXT_DIRECTIVE);
+ gcontext != NULL;
+ gcontext = strstr(new_line_input, GCONTEXT_DIRECTIVE)){
+
+ *gcontext = '\0';
+ /*
+ * Print the new_line_input (everything up to the first
+ * GCONTEXT_DIRECTIVE
+ */
+ dsgw_HTML_emits( new_line_input );
+
+
+ /*Now print "context=whatever"*/
+ dsgw_emitf("context=%s", context);
+
+ /* Now skip past the directive */
+ new_line_input = gcontext + strlen(GCONTEXT_DIRECTIVE);
+ }
+
+ /* If there's anything left, output it*/
+ if (*new_line_input) {
+ dsgw_HTML_emits( new_line_input );
+ }
+
+ free ((void*)start_of_newline);
+ }
+
+ /* If we're here, we either handled it correctly or the line was benign.*/
+ return 0;
+}
+
+
+FILE *
+dsgw_open_html_file(char *filename, int erropts)
+{
+ FILE *f;
+ char *tfname = NULL;
+
+ tfname = dsgw_file2path( gc->gc_tmpldir, filename);
+ if (!(f = fopen(tfname, "r"))) {
+ /* punt */
+ dsgw_error(DSGW_ERR_OPENHTMLFILE, tfname, erropts, 0, NULL );
+ }
+
+ free( tfname );
+
+ return f;
+}
+
+
+#define DSGW_INCLUDE_DRCT "<!-- INCLUDE "
+#define DSGW_INCLUDE_DRCT_LEN 13
+#define DSGW_INCLSET_DRCT "<!-- INCLUDESET "
+#define DSGW_INCLSET_DRCT_LEN 16
+
+int
+dsgw_next_html_line(FILE *f, char *line)
+{
+ char *p, *incfile;
+ int linelen;
+ static FILE *incfp = NULL;
+ static FILE *parentfp = NULL;
+ static int incset_index = 0;
+ static dsgwinclset *incsetp = NULL;
+
+ if ( incfp != NULL && parentfp == f ) {
+ /* we're in the midst of an include -- read from include file */
+ if ( fgets(line, BIG_LINE, incfp ) != 0 ) {
+ return 1; /* success */
+ }
+
+ /* end of include file */
+ fclose( incfp );
+
+ /* if in middle of an include set, open and use next file in set */
+ if ( incsetp != NULL && ++incset_index < incsetp->dsiset_itemcount ) {
+ incfp = dsgw_open_html_file(
+ incsetp->dsiset_filenames[ incset_index ],
+ DSGW_ERROPT_EXIT );
+ return( dsgw_next_html_line( f, line ));
+ }
+ incfp = NULL;
+ incsetp = NULL;
+ }
+
+ if(!(fgets(line, BIG_LINE, f))) {
+ return 0; /* end of file */
+ }
+
+ if ( incfp != NULL ) {
+ return 1; /* ignore nested includes */
+ }
+
+ /* check for start of a simple or an include set based include */
+ incfile = NULL;
+ linelen = strlen( line );
+ if ( linelen > DSGW_INCLUDE_DRCT_LEN && strncasecmp( line,
+ DSGW_INCLUDE_DRCT, DSGW_INCLUDE_DRCT_LEN ) == 0 ) {
+ incfile = line + DSGW_INCLUDE_DRCT_LEN;
+ if (( p = strchr( incfile, ' ' )) != NULL ) {
+ *p = '\0';
+ }
+ } else if ( linelen > DSGW_INCLSET_DRCT_LEN && strncasecmp( line,
+ DSGW_INCLSET_DRCT, DSGW_INCLSET_DRCT_LEN ) == 0 ) {
+ char *sethandle;
+
+ sethandle = line + DSGW_INCLSET_DRCT_LEN;
+ if (( p = strchr( sethandle, ' ' )) != NULL ) {
+ *p = '\0';
+ }
+
+ for ( incsetp = gc->gc_includesets; incsetp != NULL;
+ incsetp = incsetp->dsiset_next ) {
+ if ( strcasecmp( sethandle, incsetp->dsiset_handle ) == 0 ) {
+ break;
+ }
+ }
+ if ( incsetp == NULL ) { /* set not found -- ignore it */
+ if ( p != NULL ) {
+ *p = ' ';
+ }
+ return( 1 );
+ }
+ incset_index = 0;
+ incfile = incsetp->dsiset_filenames[ 0 ];
+ }
+
+ if ( incfile != NULL ) {
+ incfp = dsgw_open_html_file( incfile, DSGW_ERROPT_EXIT );
+ parentfp = f;
+ return( dsgw_next_html_line( f, line ));
+ }
+
+ return 1;
+}
+
+
+static void
+dsgw_pageheader(int argc, char **argv)
+{
+ char line[BIG_LINE];
+
+ dsgw_emits("<center><table border=2 width=100%%>\n");
+
+ util_snprintf(line, BIG_LINE, "<tr>");
+ dsgw_emits(line);
+
+ util_snprintf(line, BIG_LINE, "<td align=center width=100%%>");
+ dsgw_emits(line);
+ util_snprintf(line, BIG_LINE, "<hr size=0 width=0>");
+ dsgw_emits(line);
+ util_snprintf(line, BIG_LINE, "<FONT size=+2><b>%s</b></FONT>"
+ "<hr size=0 width=0>"
+ "</th>", ( argc > 0 ) ? argv[0] : "" );
+ dsgw_emits(line);
+
+ dsgw_emits("</tr></table></center>\n");
+}
+
+
+static void
+dsgw_title( int argc, char **argv)
+{
+ char line[BIG_LINE];
+ dsgw_emits("<HTML>");
+ dsgw_head_begin();
+ util_snprintf(line, BIG_LINE, "\n<TITLE>%s</TITLE></HEAD>\n"
+ "<BODY %s>\n", ( argc > 0 ) ? argv[0] : "", dsgw_html_body_colors );
+ dsgw_emits(line);
+}
+
+
+static void
+dsgw_body( int argc, char **argv)
+{
+ char line[BIG_LINE];
+
+ if ( argc > 0 ) {
+ util_snprintf(line, BIG_LINE, "<BODY %s %s>\n", dsgw_html_body_colors,
+ ( argc > 0 ) ? argv[0] : "" );
+ } else {
+ util_snprintf(line, BIG_LINE, "<BODY %s>\n", dsgw_html_body_colors );
+ }
+
+ dsgw_emits(line);
+}
+
+
+static void
+dsgw_colors( int argc, char **argv)
+{
+ if ( argc > 0 ) {
+ dsgw_html_body_colors = dsgw_ch_strdup( argv[0] );
+ } else {
+ dsgw_html_body_colors = "";
+ }
+}
+
+
+static void
+dsgw_submit(int verify, char **vars)
+{
+ if(verify) {
+ dsgw_emits ("<SCRIPT language=JavaScript><!--\n"
+ "function verify(form)\n{\n"
+ " window.confirmedForm = form;\n");
+ dsgw_emit_confirm (NULL, "opener.confirmedForm.submit();", NULL /* no */,
+ XP_GetClientStr(DBT_doYouReallyWantToWindow_), 1,
+ XP_GetClientStr(DBT_doYouReallyWantTo_), vars[0]);
+ dsgw_emits ("}\n"
+ "// -->\n"
+ "</SCRIPT>\n");
+ }
+
+ dsgw_emits("<center><table border=2 width=100%%><tr>");
+
+ if(!verify) {
+ char outstr[256];
+ PR_snprintf(outstr, 256, "<td width=50%% align=center>"
+ "<input type=submit value=\"%s\">"
+ "</td>\n",
+ XP_GetClientStr(DBT_ok_1));
+ dsgw_emits(outstr);
+ } else {
+ char outstr[256];
+ PR_snprintf(outstr, 256, "<td width=50%% align=center>"
+ "<input type=button value=\"%s\" "
+ "onclick=\"verify(this.form)\">"
+ "</td>\n",
+ XP_GetClientStr(DBT_ok_2));
+ dsgw_emits(outstr);
+ }
+ {
+ char outstr[256];
+ PR_snprintf(outstr, 256, "<td width=50%% align=center>"
+ "<input type=reset value=\"%s\"></td>\n",
+ XP_GetClientStr(DBT_reset_));
+ dsgw_emits(outstr);
+ }
+
+ dsgw_emits("</tr></table></center>\n");
+
+ dsgw_emits("</form>\n");
+
+ dsgw_emits("<SCRIPT language=JavaScript>\n");
+ dsgw_emits("</SCRIPT>\n");
+}
+
+
+static void
+dsgw_dialogsubmit(void)
+{
+ char outstr[256];
+
+ dsgw_emits("<center><table border=2 width=100%%><tr>");
+
+ PR_snprintf(outstr, 256, "<td width=50%% align=center>"
+ "<input type=submit value=\"%s\">"
+ "</td>\n",
+ XP_GetClientStr(DBT_done_));
+ dsgw_emits(outstr);
+ PR_snprintf(outstr, 256, "<td width=50%% align=center>"
+ "<input type=button value=\"%s\" "
+ "onClick=\"top.close()\"></td>\n",
+ XP_GetClientStr(DBT_cancel_2));
+ dsgw_emits(outstr);
+
+ dsgw_emits("</tr></table></center>\n");
+
+ dsgw_emits("</form>\n");
+
+ dsgw_emits("<SCRIPT language=JavaScript>\n");
+ dsgw_emits("</SCRIPT>\n");
+}
+
+
+static void
+dsgw_conditional( char *name, int argc, char **argv, condfunc conditionalfn,
+ void *condarg )
+{
+#define DSGW_COND_STATUS_NO_COND_SEEN 0
+#define DSGW_COND_STATUS_IN_IF 1
+#define DSGW_COND_STATUS_IN_ELSE 2
+#define DSGW_COND_STATUS_IN_ELIF 3
+
+ static int cond_status = DSGW_COND_STATUS_NO_COND_SEEN;
+ static int cond_was_true = 0;
+
+ if ( strncmp( name, "IF", 2 ) == 0 ) {
+ if ( cond_status != DSGW_COND_STATUS_NO_COND_SEEN ) {
+ template_error( XP_GetClientStr(DBT_foundAnotherIfNestedIfsAreNotSup_) );
+ return;
+ }
+ cond_was_true = dsgw_condition_true( argc, argv, conditionalfn,
+ condarg );
+ parse_status = cond_was_true ? DSGW_PARSE_STATUS_OUTPUT
+ : DSGW_PARSE_STATUS_NO_OUTPUT;
+ cond_status = DSGW_COND_STATUS_IN_IF;
+
+ } else if ( strncmp( name, "ELSE", 4 ) == 0 ) {
+ if ( cond_status == DSGW_COND_STATUS_NO_COND_SEEN ) {
+ template_error( XP_GetClientStr(DBT_foundElseButDidnTSeeAnIf_) );
+ return;
+ }
+ if ( cond_status == DSGW_COND_STATUS_IN_ELSE ) {
+ template_error( XP_GetClientStr(DBT_foundElseAfterElseExpectingEndif_) );
+ return;
+ }
+ parse_status = cond_was_true ? DSGW_PARSE_STATUS_NO_OUTPUT
+ : DSGW_PARSE_STATUS_OUTPUT;
+ cond_status = DSGW_COND_STATUS_IN_ELSE;
+
+ } else if ( strncmp( name, "ELIF", 4 ) == 0 ) {
+ if ( cond_status == DSGW_COND_STATUS_NO_COND_SEEN ) {
+ template_error( XP_GetClientStr(DBT_foundElifButDidnTSeeAnIf_) );
+ return;
+ }
+ if ( cond_status == DSGW_COND_STATUS_IN_ELSE ) {
+ template_error( XP_GetClientStr(DBT_foundElifAfterElseExpectingEndif_) );
+ return;
+ }
+
+ if ( cond_was_true ) {
+ parse_status = DSGW_PARSE_STATUS_NO_OUTPUT;
+ } else {
+ cond_was_true = dsgw_condition_true( argc, argv, conditionalfn,
+ condarg );
+ parse_status = cond_was_true ? DSGW_PARSE_STATUS_OUTPUT
+ : DSGW_PARSE_STATUS_NO_OUTPUT;
+ }
+ cond_status = DSGW_COND_STATUS_IN_ELIF;
+
+ } else if ( strncmp( name, "ENDIF", 5 ) == 0 ) {
+ if ( cond_status == DSGW_COND_STATUS_NO_COND_SEEN ) {
+ template_error( XP_GetClientStr(DBT_foundEndifButDidnTSeeAnIf_) );
+ }
+ parse_status = DSGW_PARSE_STATUS_NO_IF_SEEN;
+ cond_status = DSGW_COND_STATUS_NO_COND_SEEN;
+ }
+}
+
+
+static void
+emit_last_op_info( int argc, char **argv )
+{
+ char *s;
+
+ if ( dsgw_last_op_info != NULL ) {
+ if (( s = get_arg_by_name( "prefix", argc, argv )) != NULL ) {
+ dsgw_emits( s );
+ }
+
+ dsgw_emits( dsgw_last_op_info );
+
+ if (( s = get_arg_by_name( "suffix", argc, argv )) != NULL ) {
+ dsgw_emits( s );
+ }
+ }
+}
+
+
+static void
+emit_version_str()
+{
+ dsgw_emits( Versionstr );
+}
+
+
+static void
+emit_alert_noentries()
+{
+ dsgw_emit_alertForm();
+ dsgw_emits( "<SCRIPT LANGUAGE=JavaScript><!--\n" );
+ dsgw_emit_alert (NULL, NULL, XP_GetClientStr(DBT_SearchFound0Entries_),
+ 0L, "", "", "");
+ dsgw_emits( "// -->\n</SCRIPT>\n");
+}
+
+
+static void
+template_error( char *msg )
+{
+ dsgw_emitf( XP_GetClientStr(DBT_BrBTemplateErrorBSBrN_), msg );
+}
+
+
+static int
+dsgw_condition_true( int argc, char **argv, condfunc conditionalfn,
+ void *condarg )
+{
+ char *save_argv0;
+ int rc;
+
+ if ( argc < 1 || conditionalfn == NULL ) {
+ return( 1 ); /* unknown, but we default to true */
+ }
+
+ if ( argv[0][0] == '!' ) { /* NOT */
+ save_argv0 = argv[0];
+ argv[0] = save_argv0 + 1;
+ } else {
+ save_argv0 = NULL;
+ }
+
+ rc = (*conditionalfn)( argc, argv, condarg );
+
+ if ( save_argv0 != NULL ) {
+ argv[0] = save_argv0;
+ rc = !rc; /* '!' was seen -- reverse the result */
+ }
+
+ return( rc );
+}
+
+static int
+dsgw_get_directive(
+char *string
+)
+{
+ int index = -1;
+ register int x;
+
+ for ( x = 0; templates[ x ].name != NULL; x++ ) {
+ if ( !strncmp( string, templates[ x ].name,
+ strlen( templates[ x ].name ))) {
+ index = x;
+ break;
+ }
+ }
+ return index;
+}
+
+int
+dsgw_directive_is(char *target, char *directive)
+{
+ char *position = (target + strlen(DIRECTIVE_START));
+ return(!(strncmp(directive, position, strlen(directive))));
+}
+
+static char **
+dsgw_get_vars(
+char *string,
+int *argc
+)
+{
+ char **vars = (char **) NULL;
+ register int x;
+ int isvar;
+ char scratch[BIG_LINE];
+ char lastchar, *p;
+ int numvars = 0;
+
+ isvar = -1;
+ x = 0;
+ scratch[0] = '\0';
+ lastchar = ' ';
+
+ while ( *string != '\0' ) {
+ if (( *string == '\"' ) && ( lastchar != '\\' )) {
+ if ( isvar != -1 ) {
+ numvars++;
+ vars = (char **)dsgw_ch_realloc( vars,
+ ( numvars + 1 ) * sizeof ( char * ));
+ vars[ numvars - 1 ] = (char *) dsgw_ch_strdup( scratch );
+ if (( p = strchr( vars[ numvars - 1 ], '=' )) != NULL ) {
+ dsgw_form_unescape( p + 1 );
+ }
+ vars[ numvars ] = NULL;
+ isvar = -1;
+ } else {
+ isvar = 0;
+ }
+ } else {
+ if ( isvar != -1 ) {
+ isvar += LDAP_UTF8COPY(scratch + isvar, string);
+ scratch[ isvar ] = '\0';
+ } else {
+ if ( *string == DIRECTIVE_END ) {
+ break;
+ }
+ }
+ }
+ lastchar = *string;
+ LDAP_UTF8INC(string);
+ }
+ *argc = numvars;
+ return vars;
+}
+
+
+
+
+/*
+ * Search the given arg vector for a "tag=value" string where "tag" is
+ * the same string as "name". If found, return a pointer to the beginning
+ * of the "value" string. If the value string is missing (e.g. "tag="
+ * was given), return a zero-length string. If no matching tag was found,
+ * return NULL.
+ */
+char *
+get_arg_by_name( char *name, int argc, char **argv )
+{
+ int i;
+
+ if (( i = dsgw_get_arg_pos_by_name( name, argc, argv )) >= 0 ) {
+ return( &argv[ i ][ strlen( name ) + 1 ] );
+ } else {
+ return( NULL );
+ }
+}
+
+
+int
+dsgw_get_arg_pos_by_name( char *name, int argc, char **argv )
+{
+ int i;
+ int nl = strlen( name );
+
+ for ( i = 0; i < argc; i++ ) {
+ if ( argv[ i ] != NULL ) {
+ if ( !strncasecmp( name, argv[ i ], nl )) {
+ if (( argv[ i ][ nl ] == '=' )) {
+ return( i );
+ }
+ }
+ }
+ }
+ return( -1 );
+}
+
+
+void
+dsgw_argv_free( char **argv )
+{
+ char **p;
+
+ if ( argv != NULL ) {
+ for ( p = argv; *p != NULL; ++p ) {
+ free( *p );
+ }
+ free( argv );
+ }
+}
+
+
+savedlines *
+dsgw_savelines_alloc()
+{
+ savedlines *slp;
+
+ slp = dsgw_ch_malloc( sizeof( savedlines ));
+ memset( slp, 0, sizeof( savedlines ));
+ return( slp );
+}
+
+
+void
+dsgw_savelines_free( savedlines *svlp )
+{
+ int i;
+
+ for ( i = 0; i < svlp->svl_count; ++i ) {
+ free( svlp->svl_line[ i ] );
+ }
+ free( svlp );
+}
+
+
+void
+dsgw_savelines_rewind( savedlines *svlp )
+{
+ svlp->svl_current = 0;
+}
+
+
+void
+dsgw_savelines_save( savedlines *svlp, char *line )
+{
+ svlp->svl_line = (char **)dsgw_ch_realloc( svlp->svl_line,
+ (1 + svlp->svl_count ) * sizeof( char * ));
+ svlp->svl_line[ svlp->svl_count++ ] = dsgw_ch_strdup( line );
+}
+
+
+char *
+dsgw_savelines_next( savedlines *svlp )
+{
+ char *p;
+
+ if ( svlp->svl_current >= svlp->svl_count ) {
+ return( NULL );
+ }
+
+ p = svlp->svl_line[ svlp->svl_current ];
+ ++svlp->svl_current;
+
+ return( p );
+}
diff --git a/ldap/clients/dsgw/lang.c b/ldap/clients/dsgw/lang.c
new file mode 100644
index 00000000..3771ead5
--- /dev/null
+++ b/ldap/clients/dsgw/lang.c
@@ -0,0 +1,246 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * Convert a document from ../html, or redirect the server to it.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+#ifdef XP_WIN
+#define PATH_SLASH "\\"
+#else
+#define PATH_SLASH "/"
+#endif
+
+static int
+doc_is_UTF_8 (const char* docname)
+{
+ static const char* suffixes [] = {".html", ".htm", NULL};
+ const size_t doclen = strlen (docname);
+ const char** suf = suffixes;
+ for (suf = suffixes; *suf; ++suf) {
+ const size_t suflen = strlen (*suf);
+ if (doclen >= suflen && !strcasecmp (*suf, docname + doclen - suflen)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static const char*
+skip_prefix (const char* prefix, const char* s)
+{
+ const size_t prelen = strlen (prefix);
+ if (!strncmp (prefix, s, prelen)) return s + prelen;
+ return s;
+}
+
+static int
+doc_convert( FILE** fpp, char* stop_at_directive, int erropts )
+{
+ char **argv, line[ BIG_LINE ];
+ int argc;
+
+ while ( dsgw_next_html_line( *fpp, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, dsgw_simple_cond_is_true,
+ NULL )) {
+ if ( stop_at_directive != NULL &&
+ dsgw_directive_is( line, stop_at_directive )) {
+ return( 0 );
+
+ } else if ( dsgw_directive_is( line, DRCT_HEAD )) {
+ dsgw_head_begin();
+ dsgw_emits ("\n");
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_POSTEDVALUE )) {
+ dsgw_emit_cgi_var (argc, argv);
+
+ } else if ( dsgw_directive_is( line, DRCT_DS_CLOSEBUTTON )) {
+ dsgw_emit_button (argc, argv, "onClick=\"top.close()\"");
+
+ } else if ( dsgw_directive_is( line, "DS_CONFIRM_SCRIPT" )) {
+ {
+ auto char* yes = dsgw_get_cgi_var ("YES", DSGW_CGIVAR_OPTIONAL);
+ auto char* no = dsgw_get_cgi_var ("NO", DSGW_CGIVAR_OPTIONAL);
+ dsgw_emitf ("<SCRIPT LANGUAGE=JavaScript><!--\n"
+ "function OK() {\n");
+ if (yes) dsgw_emitf (" %s\n", yes);
+ dsgw_emits (" top.close();\n"
+ "}\n"
+ "\n"
+ "function Cancel() {\n");
+ if (no) dsgw_emitf (" %s\n", no);
+ dsgw_emits (" top.close();\n"
+ "}\n"
+ "// -->\n"
+ "</SCRIPT>\n");
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_CONFIRM_BUTTON_OK" )) {
+ dsgw_emitf ("<INPUT TYPE=BUTTON VALUE=\"%s\" onClick=\"parent.OK()\">\n",
+ XP_GetClientStr(DBT_ok_2));
+
+ } else if ( dsgw_directive_is( line, "DS_CONFIRM_BUTTON_CANCEL" )) {
+ dsgw_emitf ("<INPUT TYPE=BUTTON VALUE=\"%s\" onClick=\"parent.Cancel()\">\n",
+ XP_GetClientStr(DBT_cancel_2));
+
+ } else {
+ dsgw_emits (line);
+ }
+ }
+ }
+ fclose( *fpp );
+ *fpp = NULL;
+ return( 0 );
+}
+
+int
+main( int argc, char *argv[]
+#ifdef DSGW_DEBUG
+ , char *env[]
+#endif
+ )
+{
+ /*static char* docdir = ".." PATH_SLASH "html" PATH_SLASH;*/
+ static char* docdir = NULL;
+ static char* helpdir = NULL;
+ char* docname = NULL;
+ char* tfname;
+ int result = 0;
+ char *qs = NULL;
+ int manual_file = 0; /* Flag: is the file a documentation file? */
+
+ /* Parse out the file=blah.html */
+ if (( qs = getenv( "QUERY_STRING" )) != NULL && *qs != '\0' ) {
+ /* parse the query string: */
+ auto char *p, *iter = NULL;
+ qs = dsgw_ch_strdup( qs );
+
+ for ( p = ldap_utf8strtok_r( qs, "&", &iter ); p != NULL;
+ p = ldap_utf8strtok_r( NULL, "&", &iter )) {
+
+ /*
+ * Get the conf file name. It'll be translated
+ * into /dsgw/context/CONTEXT.conf if
+ * CONTEXT is all alphanumeric (no slahes,
+ * or dots). CONTEXT is passed into the cgi.
+ * if context=CONTEXT is not there, or PATH_INFO
+ * was used, then use dsgw.conf
+ */
+ if ( !strncasecmp( p, "context=", 8 )) {
+ context = dsgw_ch_strdup( p + 8 );
+ dsgw_form_unescape( context );
+ continue;
+ }
+
+
+ /*Get the filename and check it for naughtiness -RJP*/
+ if ( !strncasecmp( p, "file=", 5 )) {
+
+ /*If there is no file specified, go with index.html*/
+ if (strlen(p) == 5) {
+ docname = dsgw_ch_strdup("index.html");
+ } else {
+ docname = dsgw_ch_strdup( p + 5 );
+ dsgw_form_unescape( docname );
+ }
+
+
+ /*If we're handling a help page, forgo the filename check*/
+ if ( strlen( docname ) > DSGW_MANUALSHORTCUT_LEN &&
+ strncmp( docname, DSGW_MANUALSHORTCUT,
+ DSGW_MANUALSHORTCUT_LEN ) == 0 ) {
+ manual_file = 1;
+ }
+
+ /*
+ * Make sure the person isn't trying to get
+ * some file not in the gateway.
+ */
+ if (manual_file == 0 && !dsgw_valid_docname(docname)) {
+ dsgw_error( DSGW_ERR_BADFILEPATH, docname,
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ continue;
+ }
+
+
+ }
+
+ free( qs ); qs = NULL;
+ }
+
+ (void)dsgw_init( argc, argv, DSGW_METHOD_GET | DSGW_METHOD_POST );
+ docdir = dsgw_get_docdir();
+
+ /*If there is no docname, default to index.html*/
+ if (docname == NULL) {
+ docname = dsgw_ch_strdup("index.html");
+ }
+
+ if (!strcmp (docname, "/")) {
+ printf( "Location: %s?context=%s\n\n",
+ dsgw_getvp( DSGW_CGINUM_SEARCH ), context );
+ return( result );
+ } else {
+ char* p;
+ if (*docname == '/') ++docname;
+ docname = dsgw_ch_strdup( docname );
+ if (( p = strrchr( docname, '&' )) != NULL ) {
+ *p++ = '\0';
+ if ( strncasecmp( p, "info=", 5 ) == 0 ) {
+ dsgw_last_op_info = dsgw_ch_strdup( p + 5 );
+ dsgw_form_unescape( dsgw_last_op_info );
+ }
+ }
+ }
+
+ if (manual_file) {
+ helpdir = dsgw_file2path ( DSGW_MANROOT, "slapd/gw/manual/" );
+ tfname = (char *)dsgw_ch_malloc( strlen( helpdir ) +
+ strlen( docname + DSGW_MANUALSHORTCUT_LEN ) +
+ 1 );
+ sprintf( tfname, "%s%s",
+ helpdir, docname + DSGW_MANUALSHORTCUT_LEN);
+ free( helpdir );
+
+ } else {
+ tfname = dsgw_file2path (docdir, docname);
+ }
+
+ if ( ! doc_is_UTF_8 (tfname)) { /* Redirect the Web server: */
+ printf ("Location: %s%s%s\n\n",
+ getenv("SERVER_URL"), gc->gc_gwnametrans, skip_prefix (docdir, tfname));
+ /* It's tempting to also redirect if is_UTF_8(gc->gc_charset).
+ But it would be wrong: the Web server would transmit an
+ HTTP Content-type with no charset parameter. The header
+ must include ";charset=UTF-8". So we transmit it:
+ */
+ } else { /* Transmit the document: */
+ const int erropts = DSGW_ERROPT_EXIT;
+ auto FILE* docfile;
+
+ dsgw_send_header();
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+ if ((docfile = fopen(tfname, "r")) == NULL) {
+ dsgw_error( DSGW_ERR_OPENHTMLFILE, tfname, erropts, 0, NULL );
+ return( -1 );
+ }
+ result = doc_convert( &docfile, NULL, erropts );
+ }
+/*
+ * XXXmcs: the following free() causes a crash on NT... so don't do it!
+ */
+#if 0
+ free( tfname );
+#endif
+
+ return result;
+}
diff --git a/ldap/clients/dsgw/ldaputil.c b/ldap/clients/dsgw/ldaputil.c
new file mode 100644
index 00000000..d574cd1f
--- /dev/null
+++ b/ldap/clients/dsgw/ldaputil.c
@@ -0,0 +1,1564 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * ldaputil.c -- LDAP utility functions -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+#include "../../include/disptmpl.h"
+#ifndef NO_LIBLCACHE
+#include <lcache.h>
+#endif
+#if XP_WIN32
+#include <windows.h>
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+static dsgwtmplinfo *init_listdisplay( char *tmplname, unsigned long options );
+static int do_search( dsgwtmplinfo *tip, LDAP *ld, char *base, int scope,
+ char *filter, LDAPMessage **msgpp );
+static void handle_search_results( dsgwtmplinfo *tip, LDAP *ld, int rc,
+ LDAPMessage *msgp, unsigned long options );
+static int LDAP_CALL LDAP_CALLBACK
+ get_rebind_credentials( LDAP *ld, char **whop, char **credp,
+ int *methodp, int freeit, void *arg );
+static void strcpy_special_undo( char *d, char *s );
+static int entry2htmlwrite( void *fp, char *buf, int len );
+static void emit_one_loc_dn( char *dn, char *friendlyname, char *rootname,
+ int only_one );
+static char *uid2dn( LDAP *ld, char *uid, char *base, int *ldaprc,
+ char **lderrtxtp, char **errsp );
+static void return_one_attr( LDAP *ld, LDAPMessage *entry, char *attrtype,
+ char *mimetype, int valindex );
+static void break_up_one_attr( char *attr, char **attrtypep, char **mimetypep,
+ int *valindexp );
+
+/* binddn and bindpasswd are used in get_rebind_credentials() */
+static char *binddn = NULL, *bindpasswd = NULL;
+
+#ifndef DSGW_NO_SSL
+/*static CERTCertDBHandle certdbh;*/
+static char * certdbh;
+
+#endif
+
+/*
+ * initialize various LDAP library things -- any non-NULL parameters are
+ * initialized and set. If an error occurs, this function will not
+ * return at all.
+ * If an LDAP connection was opened, this function will return either
+ * DSGW_BOUND_ASUSER if a valid cookie was found in the environment
+ * and we were able to bind to the directory as that user. If no
+ * cookie was found, or the cookie would not be used to bind, then
+ * an anonymous bind is performed and DSGW_BOUND_ANONYMOUS is returned.
+ * If skipac (skip authentication check) is non-zero, then this
+ * function will always authenticate as NULL.
+ *
+ * If we are configured to use a local LDAP database instead of a real
+ * directory server, we always do an unauthenticated bind but we return
+ * DSGW_BOUND_ASUSER. This is done to keep our CGIs that check for a
+ * return code of DSGW_BOUND_ASUSER happy.
+ *
+ * If skipauthwarning is set, then we don't display the javascript
+ * auth warning for searches. - RJP
+ */
+int
+dsgw_init_ldap( LDAP **ldp, LDAPFiltDesc **lfdpp, int skipac, int skipauthwarning )
+{
+ char *path;
+ char *userid, *dn, *rndstr, *passwd, *cookie, *p;
+ int ret = 0, optval, limit;
+#ifdef XP_WIN32
+ WSADATA wsadata;
+#endif
+
+ /* LDAP search filters */
+ if ( lfdpp != NULL ) {
+ path = dsgw_file2path( gc->gc_configdir, DSGW_FILTERFILE );
+ if (( *lfdpp = ldap_init_getfilter( path )) == NULL ) {
+ dsgw_error( DSGW_ERR_BADCONFIG, path, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ free( path );
+ ret = 0;
+ }
+
+#ifdef XP_WIN32
+
+ if( ret = WSAStartup(0x0101, &wsadata ) != 0 )
+ dsgw_error( DSGW_ERR_WSAINIT, NULL, DSGW_ERROPT_EXIT, 0, NULL );
+
+#endif /* XP_WIN32 */
+
+ /* LDAP connection */
+ if ( ldp != NULL ) {
+ if ( gc == NULL ) {
+ dsgw_error( DSGW_ERR_INTERNAL,
+ XP_GetClientStr(DBT_ldapInitLcacheInitAttemptedBefor_),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ if ( gc->gc_localdbconf == NULL ) {
+ /* "Real LDAP server" case */
+#ifdef DSGW_NO_SSL
+ *ldp = ldap_init( gc->gc_ldapserver, gc->gc_ldapport );
+#else /* DSGW_NO_SSL */
+ if ( gc->gc_ldapssl ) {
+ if ( gc->gc_securitypath == NULL ) {
+ dsgw_error( DSGW_ERR_NOSECPATH, NULL, DSGW_ERROPT_EXIT,
+ 0, NULL );
+ }
+ if ( ldapssl_client_init( gc->gc_securitypath,
+ &certdbh ) < 0 ) {
+ dsgw_error( DSGW_ERR_SSLINIT, gc->gc_securitypath,
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ *ldp = ldapssl_init( gc->gc_ldapserver, gc->gc_ldapport, 1 );
+ dsgw_NSSInitializedAlready = 1;
+ } else {
+ *ldp = ldap_init( gc->gc_ldapserver, gc->gc_ldapport );
+ }
+#endif /* !DSGW_NO_SSL */
+ if ( *ldp == NULL ) {
+ dsgw_error( DSGW_ERR_LDAPINIT, NULL, DSGW_ERROPT_EXIT, 0,
+ NULL );
+ }
+
+ }
+#ifndef NO_LIBLCACHE
+else {
+ /* Local DB case */
+ if (( *ldp = ldap_init( NULL, 0 )) == NULL ) {
+ dsgw_error( DSGW_ERR_LDAPINIT, NULL, DSGW_ERROPT_EXIT, 0,
+ NULL );
+ }
+ if ( lcache_init( *ldp, gc->gc_localdbconf ) != 0 ) {
+ dsgw_error( DSGW_ERR_LCACHEINIT, strerror(errno),
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ optval = 1;
+ (void) ldap_set_option( *ldp, LDAP_OPT_CACHE_ENABLE, &optval );
+ optval = LDAP_CACHE_LOCALDB;
+ (void) ldap_set_option( *ldp, LDAP_OPT_CACHE_STRATEGY, &optval );
+ }
+#endif
+ rndstr = dn = NULL;
+ passwd = dsgw_get_cgi_var( "passwd", DSGW_CGIVAR_OPTIONAL );
+
+ if (( p = dsgw_get_cgi_var( "ldapsizelimit", DSGW_CGIVAR_OPTIONAL ))
+ != NULL ) {
+ limit = atoi( p );
+ (void) ldap_set_option( *ldp, LDAP_OPT_SIZELIMIT, &limit );
+ }
+
+ if (( p = dsgw_get_cgi_var( "ldaptimelimit", DSGW_CGIVAR_OPTIONAL ))
+ != NULL ) {
+ limit = atoi( p );
+ (void) ldap_set_option( *ldp, LDAP_OPT_TIMELIMIT, &limit );
+ }
+
+ /*
+ * we don't bother with authentication if:
+ * the "skipac" flag is non-zero OR
+ * no "passwd" form element was passed in and we are using local db
+ */
+ if ( !skipac && ( passwd != NULL || gc->gc_localdbconf == NULL )) {
+ /*
+ * There are several ways in which authentication might
+ * happen.
+ */
+ if ( gc->gc_admserv ) {
+ /*
+ * We're running under the admin server, so ask libadmin
+ * for the user's credentials. If a password comes as a form
+ * field, it overrides value we get from admin server
+ */
+ (void)dsgw_get_adm_identity( *ldp, &userid, &dn,
+ ( passwd == NULL ) ? &passwd : NULL, DSGW_ERROPT_EXIT );
+
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_init_ldap: run under admserv, user id = %s, "
+ "dn = %s, passwd = %s, skipac = %d, dn = 0x%x\n",
+ userid == NULL ? "NULL" : userid,
+ dn == NULL ? "NULL" : dn,
+ passwd == NULL ? "NULL" : passwd,
+ skipac, dn );
+#endif
+ } else {
+ /*
+ * Not running under admin server. The DN and password
+ * might come in as form fields, or the authentication
+ * might be accomplished via a client-side cookie which
+ * gets looked up in the gateway's cookie database.
+ */
+
+ /* check for dn/binddn in request */
+ if ( passwd != NULL ) {
+ if (( dn = dsgw_get_escaped_cgi_var( "escapedbinddn",
+ "binddn", DSGW_CGIVAR_OPTIONAL )) == NULL &&
+ ( dn = dsgw_get_cgi_var( "dn",
+ DSGW_CGIVAR_OPTIONAL )) == NULL ) {
+ free( passwd );
+ passwd = NULL;
+ } else {
+ /* got DN: undo extra level of escaping */
+ dsgw_form_unescape( dn );
+ }
+ }
+
+ if ( passwd == NULL ) {
+ /* Check for a valid authentication cookie */
+ cookie = dsgw_get_auth_cookie();
+ if ( cookie != NULL ) {
+ if ( dsgw_parse_cookie( cookie, &rndstr, &dn ) == 0 ) {
+ int ckrc;
+ if (( ckrc = dsgw_ckdn2passwd( rndstr, dn,
+ &passwd )) != 0 ) {
+
+ passwd = NULL;
+ dn = NULL;
+ /*
+ * Delete the cookie and print out the error message.
+ * dn2passwd_error() returns 1 if the CGI should exit,
+ * 0 if it should continue.
+ */
+ if (dsgw_dn2passwd_error( ckrc, skipauthwarning )) {
+ exit( 0 );
+ }
+
+ }
+ }
+ }
+
+ if ( rndstr != NULL ) {
+ free( rndstr );
+ }
+ if ( cookie != NULL ) {
+ free( cookie );
+ }
+ }
+ }
+ }
+
+ /*
+ * try to use LDAP version 3 but fall back to v2 if bind fails
+ */
+ optval = LDAP_VERSION3;
+ (void)ldap_set_option( *ldp, LDAP_OPT_PROTOCOL_VERSION, &optval );
+
+ /*
+ * If everything above failed to set the dn/password, then use
+ * the binddn and bindpw, if any.
+ */
+ if (dn == NULL && passwd == NULL &&
+ strlen(gc->gc_binddn) > 0 && strlen(gc->gc_bindpw) > 0) {
+ dn = dsgw_ch_strdup(gc->gc_binddn);
+ passwd = dsgw_ch_strdup(gc->gc_bindpw);
+ }
+
+ if (( ret = ldap_simple_bind_s( *ldp, dn, passwd ))
+ == LDAP_PROTOCOL_ERROR ) {
+ optval = LDAP_VERSION2;
+ (void)ldap_set_option( *ldp, LDAP_OPT_PROTOCOL_VERSION,
+ &optval );
+ ret = ldap_simple_bind_s( *ldp, dn, passwd );
+ }
+
+ if ( ret != LDAP_SUCCESS ){
+ dsgw_ldap_error( *ldp, DSGW_ERROPT_DURINGBIND );
+
+ /* Display back button */
+ dsgw_form_begin( NULL, NULL );
+ dsgw_emits( "\n<CENTER><TABLE border=2 width=\"100%\"><TR>\n" );
+ dsgw_emits( "<TD WIDTH=\"100%\" ALIGN=\"center\">\n" );
+ dsgw_emitf( "<INPUT TYPE=\"button\" VALUE=\"%s\" "
+ "onClick=\"history.back()\">\n",
+ XP_GetClientStr(DBT_goBack_) );
+ dsgw_emits( "\n</TABLE></CENTER></FORM>\n" );
+ exit(0);
+ }
+
+ if (( dn != NULL ) && ( passwd != NULL )) {
+ ret = DSGW_BOUND_ASUSER;
+ binddn = dn;
+ bindpasswd = passwd;
+ ldap_set_rebind_proc( *ldp, get_rebind_credentials, NULL );
+ } else if ( gc->gc_localdbconf != NULL ) {
+ ret = DSGW_BOUND_ASUSER; /* a small, harmless lie */
+ } else {
+ ret = DSGW_BOUND_ANONYMOUS;
+ }
+
+ }
+ return ret;
+}
+
+
+/*
+ * get user identity from the admin. server (if running under it)
+ * if uidp is non-NULL, it is set to point to user's login id.
+ * if dnp is non-NULL, it is set to point to user's DN.
+ * if pwdp is non-NULL, it is set to point to user's password.
+ * Returns: 0 if all goes well, -1 if an error occurs.
+ *
+ * Note that ld is used only if dnp != NULL, and then only if the admin server
+ * returns NULL when asked for the DN.
+ */
+int
+dsgw_get_adm_identity( LDAP *ld, char **uidp, char **dnp, char **pwdp,
+ int erropts )
+{
+ int rc, need_to_get_dn;
+ char *uid;
+ static int adm_inited = 0;
+
+ if ( !gc->gc_admserv ) {
+ dsgw_error( DSGW_ERR_ADMSERV_CREDFAIL,
+ XP_GetClientStr(DBT_notRunningUnderTheAdministration_),
+ erropts, 0, NULL );
+ return( -1 );
+ }
+
+ if ( !adm_inited ) {
+ if ( ADM_InitializePermissions( &rc ) < 0 ) {
+ dsgw_error( DSGW_ERR_ADMSERV_CREDFAIL,
+ XP_GetClientStr(DBT_couldNotInitializePermissions_),
+ erropts, 0, NULL );
+ return( -1 );
+ }
+ adm_inited = 1;
+ }
+
+ need_to_get_dn = ( dnp != NULL );
+
+ if ( need_to_get_dn && ADM_GetUserDNString( &rc, dnp ) < 0 ) {
+ dsgw_error( DSGW_ERR_ADMSERV_CREDFAIL,
+ XP_GetClientStr(DBT_couldNotMapUsernameToADnErrorFro_),
+ erropts, 0, NULL );
+ return( -1 );
+ }
+
+ /*
+ * get userid if:
+ * 1. requested by caller (uidp != NULL)
+ * or 2. DN was requested but Admin Server didn't return the DN
+ */
+ if (( uidp != NULL || ( need_to_get_dn && *dnp == NULL )) &&
+ ( ADM_GetCurrentUsername( &rc, &uid ) < 0 || uid == NULL )) {
+ dsgw_error( DSGW_ERR_ADMSERV_CREDFAIL,
+ XP_GetClientStr(DBT_couldNotGetCurrentUsername_), erropts,
+ 0, NULL );
+ return( -1 );
+ }
+
+ if ( uidp != NULL ) {
+ *uidp = uid;
+ }
+
+ if ( need_to_get_dn && *dnp == NULL ) {
+ /*
+ * try to map userid to DN using LDAP search
+ */
+ int lderr;
+ char *errstr, *lderrtxt;
+
+ if (( *dnp = uid2dn( ld, uid, gc->gc_ldapsearchbase, &lderr,
+ &lderrtxt, &errstr )) == NULL ) {
+ dsgw_error( DSGW_ERR_ADMSERV_CREDFAIL, errstr, erropts, lderr,
+ lderrtxt );
+ return( -1 );
+ }
+ }
+
+ if ( pwdp != NULL && ADM_GetCurrentPassword( &rc, pwdp ) < 0 ) {
+ dsgw_error( DSGW_ERR_ADMSERV_CREDFAIL,
+ XP_GetClientStr(DBT_couldNotGetCurrentUserPassword_), erropts,
+ 0, NULL );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+void
+dsgw_ldap_error( LDAP *ld, int erropts )
+{
+ int lderr;
+ char *lderrtxt = NULL;
+
+ lderr = ldap_get_lderrno( ld, NULL, &lderrtxt );
+ dsgw_error( DSGW_ERR_LDAPGENERAL, dsgw_ldaperr2string( lderr ),
+ erropts, lderr, lderrtxt );
+}
+
+
+struct ldap_searchobj *
+dsgw_type2searchobj( struct ldap_searchobj *solistp, char *type )
+{
+ struct ldap_searchobj *sop;
+
+ for ( sop = ldap_first_searchobj( solistp ); sop != NULL;
+ sop = ldap_next_searchobj( solistp, sop )) {
+ if ( strcasecmp( type, sop->so_objtypeprompt ) == 0 ) {
+ return( sop );
+ }
+ }
+
+ return( NULL );
+}
+
+
+struct ldap_searchattr *
+dsgw_label2searchattr( struct ldap_searchobj *sop, char *label )
+{
+ struct ldap_searchattr *sap;
+
+ for ( sap = sop->so_salist; sap != NULL; sap = sap->sa_next ) {
+ if ( strcasecmp( label, sap->sa_attrlabel ) == 0 ) {
+ return( sap );
+ }
+ }
+
+ return( NULL );
+}
+
+
+struct ldap_searchmatch *
+dsgw_prompt2searchmatch( struct ldap_searchobj *sop, char *prompt )
+{
+ struct ldap_searchmatch *smp;
+
+ for ( smp = sop->so_smlist; smp != NULL; smp = smp->sm_next ) {
+ if ( strcasecmp( prompt, smp->sm_matchprompt ) == 0 ) {
+ return( smp );
+ }
+ }
+
+ return( NULL );
+}
+
+
+static dsgwtmplinfo *
+init_listdisplay( char *tmplname, unsigned long options )
+{
+ char *s;
+
+ if (( s = dsgw_get_cgi_var( "listtemplate", DSGW_CGIVAR_OPTIONAL ))
+ != NULL ) {
+ tmplname = s;
+ }
+
+ return( dsgw_display_init( DSGW_TMPLTYPE_LIST, tmplname, options ));
+}
+
+
+void
+dsgw_smart_search( LDAP *ld, struct ldap_searchobj *sop, LDAPFiltDesc *lfdp,
+ char *base, char *value, unsigned long options )
+{
+ int rc;
+ LDAPFiltInfo *lfip;
+ dsgwtmplinfo *tip;
+ LDAPMessage *msgp;
+
+ ldap_setfilteraffixes( lfdp, sop->so_filterprefix, NULL );
+ tip = init_listdisplay( sop->so_objtypeprompt, options );
+
+ if (( lfip = ldap_getfirstfilter( lfdp, sop->so_filtertag, value ))
+ == NULL ) {
+ dsgw_error( DSGW_ERR_NOFILTERS, sop->so_objtypeprompt,
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ for ( ; lfip != NULL; lfip = ldap_getnextfilter( lfdp )) {
+ dsgw_set_searchdesc( tip, NULL, lfip->lfi_desc, value );
+
+ rc = do_search( tip, ld, base, sop->so_defaultscope, lfip->lfi_filter,
+ &msgp );
+
+ if ( rc != LDAP_SUCCESS ||
+ ( msgp != NULL && ldap_count_entries( ld, msgp ) > 0 )) {
+ if ( strstr( lfip->lfi_filter, "~=" ) != NULL ) {
+ /* always list if approximate filter used to find entry */
+ options |= DSGW_DISPLAY_OPT_LIST_IF_ONE;
+ }
+ break; /* error or got some entries: stop searching */
+ }
+ }
+
+ handle_search_results( tip, ld, rc, msgp, options );
+}
+
+
+void
+dsgw_pattern_search( LDAP *ld, char *listtmpl,
+ char *searchdesc2, char *searchdesc3, char *searchdesc4,
+ char *filtpattern, char *filtprefix, char *filtsuffix, char *attr,
+ char *base, int scope, char *value, unsigned long options )
+{
+ char buf[ 4096 ];
+ int rc;
+ dsgwtmplinfo *tip;
+ LDAPMessage *msgp;
+
+ tip = init_listdisplay( listtmpl, options );
+
+ ldap_build_filter( buf, sizeof( buf ), filtpattern,
+ filtprefix, filtsuffix, attr, value, NULL );
+
+ dsgw_set_searchdesc( tip, searchdesc2, searchdesc3, searchdesc4 );
+
+ rc = do_search( tip, ld, base, scope, buf, &msgp );
+ handle_search_results( tip, ld, rc, msgp, options );
+}
+
+
+/*
+ * Perform URL-based search.
+ * Note that if "ld" is NULL, this routine sets gc->gc_ldapserver and
+ * gc->gc_ldapport globals itself, calls dsgw_init_ldap(), and then does
+ * the URL-based search. If "ld" is not NULL, no initialization is done
+ * here.
+ */
+void
+dsgw_ldapurl_search( LDAP *ld, char *ldapurl )
+{
+ int rc, ec, saveport, did_init_ldap;
+ LDAPMessage *msgp;
+ LDAPURLDesc *ludp;
+ char *saveserver;
+ unsigned long no_options = 0;
+ int one_attr = 0;
+
+ if (( rc = ldap_url_parse( ldapurl, &ludp )) != 0 ) {
+ switch ( rc ) {
+ case LDAP_URL_ERR_NODN:
+ ec = DSGW_ERR_LDAPURL_NODN;
+ break;
+ case LDAP_URL_ERR_BADSCOPE:
+ ec = DSGW_ERR_LDAPURL_BADSCOPE;
+ break;
+ case LDAP_URL_ERR_MEM:
+ ec = DSGW_ERR_NOMEMORY;
+ break;
+ case LDAP_URL_ERR_NOTLDAP:
+ default:
+ ec = DSGW_ERR_LDAPURL_NOTLDAP;
+ break;
+ }
+ dsgw_error( ec, ldapurl, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if ( ld == NULL ) {
+ saveserver = gc->gc_ldapserver;
+ gc->gc_ldapserver = ludp->lud_host;
+ saveport = gc->gc_ldapport;
+ gc->gc_ldapport = ludp->lud_port;
+ one_attr = ( ludp->lud_attrs != NULL && ludp->lud_attrs[ 0 ] != NULL && ludp->lud_attrs[ 1 ] == NULL );
+ (void)dsgw_init_ldap( &ld, NULL, 0, one_attr );
+ did_init_ldap = 1;
+ } else {
+ did_init_ldap = 0;
+ }
+
+ /* XXX a bit of a hack: if it looks like only a DN was included, we
+ * assume that a read of the entry is desired.
+ */
+ if ( ludp->lud_scope == LDAP_SCOPE_BASE && strcasecmp( ludp->lud_filter,
+ "(objectClass=*)" ) == 0 ) {
+ dsgw_read_entry( ld, ludp->lud_dn, NULL, NULL, ludp->lud_attrs,
+ no_options );
+ } else {
+ dsgwtmplinfo *tip;
+
+ dsgw_send_header();
+ tip = init_listdisplay( "urlsearch", no_options );
+ dsgw_set_searchdesc( tip, NULL, XP_GetClientStr(DBT_theLDAPFilterIs_), ldapurl );
+ rc = do_search( tip, ld, ludp->lud_dn, ludp->lud_scope,
+ ludp->lud_filter, &msgp );
+ handle_search_results( tip, ld, rc, msgp, no_options );
+ }
+
+ if ( did_init_ldap ) {
+ ldap_unbind( ld );
+ gc->gc_ldapserver = saveserver;
+ gc->gc_ldapport = saveport;
+ }
+}
+
+
+/*
+ * do the actual search over LDAP. Return an LDAP error code.
+ */
+static int
+do_search( dsgwtmplinfo *tip, LDAP *ld, char *base, int scope, char *filter,
+ LDAPMessage **msgpp )
+{
+ char **attrlist, *attrs[ 3 ];
+
+ *msgpp = NULL;
+
+ if ( tip == NULL || tip->dsti_attrs == NULL ) {
+ attrs[ 0 ] = DSGW_ATTRTYPE_OBJECTCLASS;
+ if ( tip != NULL && tip->dsti_sortbyattr != NULL ) {
+ attrs[ 1 ] = tip->dsti_sortbyattr;
+ attrs[ 2 ] = NULL;
+ } else {
+ attrs[ 1 ] = NULL;
+ }
+ attrlist = attrs;
+ } else {
+ attrlist = tip->dsti_attrs;
+ }
+#ifdef DSGW_DEBUG
+ dsgw_log ("ldap_search_s(ld,\"%s\",%i,\"%s\")\n", base, scope, filter);
+#endif
+ return( ldap_search_s( ld, base, scope, filter, attrlist, 0, msgpp ));
+}
+
+
+static int
+is_subtype( const char *sub, const char *sup )
+{
+ auto const size_t subLen = strlen( sub );
+ auto const size_t supLen = strlen( sup );
+ if ( subLen < supLen ) return 0;
+ if ( subLen == supLen ) return !strcasecmp( sub, sup );
+ if ( sub[supLen] != ';' ) return 0;
+ return !strncasecmp( sub, sup, strlen( sup ));
+}
+
+static const struct berval* LDAP_C LDAP_CALLBACK
+dsgw_keygen( void *arg, LDAP *ld, LDAPMessage *entry )
+{
+ auto const char* sortbyattr = (char*)arg;
+ auto struct berval* result = NULL;
+
+ if (sortbyattr == NULL) { /* sort by DN */
+ auto char* DN = ldap_get_dn( ld, entry );
+ if (DN) {
+ result = dsgw_strkeygen( CASE_INSENSITIVE, DN );
+ ldap_memfree( DN );
+ }
+ } else {
+ auto char* attr;
+ auto BerElement *ber;
+ for (attr = ldap_first_attribute( ld, entry, &ber ); attr != NULL;
+ attr = ldap_next_attribute ( ld, entry, ber ) ) {
+ auto char **vals;
+ if ( is_subtype( attr, sortbyattr ) &&
+ NULL != ( vals = ldap_get_values( ld, entry, attr ))) {
+ auto size_t i;
+ for ( i = 0; vals[i] != NULL; ++i ) {
+ auto struct berval* key = dsgw_strkeygen( CASE_INSENSITIVE, vals[i] );
+ if ( result == NULL || dsgw_keycmp( NULL, key, result ) < 0 ) {
+ auto struct berval* tmp = result;
+ result = key;
+ key = tmp;
+#ifdef DSGW_DEBUG
+ {
+ auto char* ev = dsgw_strdup_escaped( vals[i] );
+ auto char* DN = ldap_get_dn( ld, entry );
+ dsgw_log( "dsgw_keygen(%s,%s) %p %s\n", sortbyattr, DN, (void*)result, ev );
+ ldap_memfree( DN );
+ free( ev );
+ }
+#endif
+ }
+ if ( key != NULL ) {
+ dsgw_keyfree( arg, key );
+ }
+ }
+ ldap_value_free( vals );
+ }
+ ldap_memfree( attr );
+ }
+ if ( ber != NULL ) {
+ ldap_ber_free( ber, 0 );
+ }
+ }
+ return result ? result : /* no such attribute */ dsgw_key_last;
+}
+
+static void
+handle_search_results( dsgwtmplinfo *tip, LDAP *ld, int rc, LDAPMessage *msgp,
+ unsigned long options )
+{
+ int count;
+ LDAPMessage *entry;
+ char *dn, *errortext, *lderrtxt, **ocvals;
+
+ count = ( msgp == NULL ) ? 0 : ldap_count_entries( ld, msgp );
+ if ( rc == LDAP_SUCCESS ) {
+ errortext = NULL;
+ lderrtxt = NULL;
+ } else {
+ errortext = dsgw_ldaperr2string( rc );
+ (void)ldap_get_lderrno( ld, NULL, &lderrtxt );
+ }
+ dsgw_set_search_result( tip, count, errortext, lderrtxt );
+
+ if ( count > 0 ) {
+ entry = ldap_first_entry( ld, msgp );
+
+ if ( count == 1 && ( options & DSGW_DISPLAY_OPT_LIST_IF_ONE ) == 0 ) {
+ /* found exactly one entry: read and display it */
+ dn = ldap_get_dn( ld, entry );
+ ocvals = ldap_get_values( ld, entry, DSGW_ATTRTYPE_OBJECTCLASS );
+ ldap_msgfree( msgp );
+
+ dsgw_read_entry( ld, dn, ocvals, NULL, NULL, options );
+
+ if ( ocvals != NULL ) {
+ ldap_value_free( ocvals );
+ }
+ return;
+ }
+
+ /* list entries */
+#ifdef DSGW_DEBUG
+ dsgw_log( "handle_search_results: sort entries by %s\n",
+ tip->dsti_sortbyattr ? tip->dsti_sortbyattr : "DN" );
+#endif
+ ldap_keysort_entries( ld, &msgp, tip->dsti_sortbyattr,
+ dsgw_keygen, dsgw_keycmp, dsgw_keyfree );
+ for ( entry = ldap_first_entry( ld, msgp ); entry != NULL;
+ entry = ldap_next_entry( ld, entry )) {
+ dsgw_display_entry( tip, ld, entry, NULL, NULL );
+ }
+ if ( options & DSGW_DISPLAY_OPT_DNLIST_JS ) {
+ int i;
+ char *edn, *js0, *js1;
+ char **xdn;
+ char **sn;
+
+ dsgw_emits( "<SCRIPT LANGUAGE=\"JavaScript\">\n" );
+ dsgw_emits( "var dnlist = new Array;\n" );
+ for ( i = 0, entry = ldap_first_entry( ld, msgp ); entry != NULL;
+ i++, entry = ldap_next_entry( ld, entry )) {
+ dn = ldap_get_dn( ld, entry );
+ edn = dsgw_strdup_escaped( dn );
+ xdn = ldap_explode_dn( dn, 1 );
+ dsgw_emitf( "dnlist[%d] = new Object\n", i );
+ dsgw_emitf( "dnlist[%d].edn = '%s';\n", i, edn );
+ js0 = dsgw_escape_quotes( xdn[ 0 ] );
+ if ( xdn[1] != NULL ) {
+ js1 = dsgw_escape_quotes( xdn[ 1 ] );
+ dsgw_emitf( "dnlist[%d].rdn = '%s, %s';\n", i, js0, js1 );
+ free( js1 );
+ } else {
+ dsgw_emitf( "dnlist[%d].rdn = '%s';\n", i, js0 );
+ }
+ free( js0 );
+ if (( sn = ldap_get_values( ld, entry, "sn" )) == NULL ) {
+ js0 = NULL;
+ } else {
+ js0 = dsgw_escape_quotes( sn[ 0 ] );
+ ldap_value_free( sn );
+ }
+ dsgw_emitf( "dnlist[%d].sn = '%s';\n", i, ( js0 == NULL ) ?
+ " " : js0 );
+ if ( js0 != NULL ) {
+ free( js0 );
+ }
+
+ dsgw_emitf( "dnlist[%d].selected = false;\n", i );
+ free( edn );
+ ldap_value_free( xdn );
+ ldap_memfree( dn );
+ }
+ dsgw_emitf( "dnlist.count = %d;\n", i );
+ dsgw_emitf( "</SCRIPT>\n" );
+ }
+ ldap_msgfree( msgp );
+ } else {
+ /* Count <= 0 */
+ if ( options & DSGW_DISPLAY_OPT_DNLIST_JS ) {
+ dsgw_emitf( "<SCRIPT LANGUAGE=\"JavaScript\">\n" );
+ dsgw_emitf( "var dnlist = new Array;\n" );
+ dsgw_emitf( "dnlist.count = 0;\n" );
+ dsgw_emitf( "</SCRIPT>\n" );
+ }
+ }
+
+ dsgw_display_done( tip );
+}
+
+
+/*
+ * read and display a single entry. If ocvals is non-NULL, it should
+ * contain the list of objectClass values for this entry.
+ */
+void
+dsgw_read_entry( LDAP *ld, char *dn, char **ocvals, char *tmplname,
+ char **attrs, unsigned long options )
+{
+ int rc, one_attr, freeocvals, valindex;
+ char *tmpattr, *attr0, *mimetype;
+ LDAPMessage *msgp, *entry, *aomsgp, *aoentry;
+ dsgwtmpl *tmpl;
+ dsgwtmplinfo *tip;
+
+ if (( options & DSGW_DISPLAY_OPT_AUTH ) != 0 ) {
+ /*
+ * XXX hack -- if we are trying to authenticate, we don't generate an
+ * entry display at all. Instead, we generate an authenticate form.
+ */
+ dsgw_send_header();
+ dsgw_emit_auth_form( dn );
+ return;
+ }
+
+ one_attr = ( attrs != NULL && attrs[ 0 ] != NULL && attrs[ 1 ] == NULL );
+ if ( one_attr ) {
+ break_up_one_attr( attrs[ 0 ], &tmpattr, &mimetype, &valindex );
+ if ( strcasecmp( tmpattr, "_vcard" ) == 0 ) { /* VCards are special */
+ dsgw_vcard_from_entry( ld, dn, mimetype );
+ return;
+ }
+ attr0 = attrs[ 0 ]; /* replace first & only attr. */
+ attrs[ 0 ] = tmpattr;
+ } else {
+ attr0 = NULL;
+ }
+
+ if ( tmplname == NULL && ( tmplname = dsgw_get_cgi_var( "displaytemplate",
+ DSGW_CGIVAR_OPTIONAL )) == NULL && attrs == NULL ) {
+ /* determine what display template to use based on objectClass values */
+ freeocvals = 0;
+ if ( ocvals == NULL ) { /* read entry to get objectClasses */
+ char *attrs[ 2 ];
+
+ attrs[ 0 ] = DSGW_ATTRTYPE_OBJECTCLASS;
+ attrs[ 1 ] = NULL;
+
+ if (( rc = ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+ attrs, 0, &msgp )) != LDAP_SUCCESS ||
+ ( entry = ldap_first_entry( ld, msgp )) == NULL ) {
+ dsgw_ldap_error( ld, DSGW_ERROPT_EXIT );
+ }
+ ocvals = ldap_get_values( ld, msgp, DSGW_ATTRTYPE_OBJECTCLASS );
+ freeocvals = 1;
+ ldap_msgfree( msgp );
+ }
+
+
+ if ( ocvals == NULL || ( tmpl = dsgw_oc2template( ocvals )) == NULL ) {
+ tmplname = NULL;
+ } else {
+ tmplname = tmpl->dstmpl_name;
+ }
+
+ if ( freeocvals ) {
+ ldap_value_free( ocvals );
+ }
+ }
+
+ if ( tmplname == NULL ) {
+ tip = NULL;
+
+ if ( !one_attr ) {
+ char *title;
+
+ if (( title = ldap_dn2ufn( dn )) == NULL ) {
+ title = dn;
+ }
+ dsgw_send_header();
+ dsgw_html_begin( title, 1 );
+ dsgw_emitf( "<FONT SIZE=\"+1\">\n%s\n</FONT>\n",
+ XP_GetClientStr(DBT_noteThereIsNoDisplayTemplateForT_) );
+ }
+
+ } else if (( tip = dsgw_display_init( DSGW_TMPLTYPE_DISPLAY, tmplname,
+ options )) != NULL ) {
+ dsgw_send_header();
+ attrs = tip->dsti_attrs;
+ }
+
+ /* now read the attributes needed for the template */
+ if (( rc = ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+ attrs, 0, &msgp )) != LDAP_SUCCESS ) {
+ dsgw_ldap_error( ld, DSGW_ERROPT_EXIT );
+ }
+
+ if (( entry = ldap_first_entry( ld, msgp )) == NULL ) {
+ ldap_msgfree( msgp );
+ dsgw_ldap_error( ld, DSGW_ERROPT_EXIT );
+ }
+
+ /* and retrieve attribute types only if we need any of them */
+ if ( one_attr || tip == NULL || tip->dsti_attrsonly_attrs == NULL ) {
+ aomsgp = NULL;
+ } else {
+ if (( rc = ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+ tip->dsti_attrsonly_attrs, 1, &aomsgp )) != LDAP_SUCCESS ) {
+ dsgw_ldap_error( ld, DSGW_ERROPT_EXIT );
+ }
+
+ /*
+ * if no entries were returned, "aoentry" will be set to NULL by the
+ * next statement. We don't treat that as an error since we know the
+ * entry exists. It probably just means none of the "attrsonly" types
+ * were present in the entry.
+ */
+ aoentry = ldap_first_entry( ld, aomsgp );
+ }
+
+ /* display it (finally!) */
+ if ( one_attr ) {
+ return_one_attr( ld, entry, attrs[ 0 ], mimetype, valindex );
+ } else if ( tip == NULL ) {
+ /* no template available -- display in an ugly but complete manner */
+ if (( rc = ldap_entry2html( ld, NULL, entry, NULL, NULL, NULL,
+ entry2htmlwrite, stdout, "\n", 0, LDAP_DISP_OPT_HTMLBODYONLY,
+ NULL, NULL )) != LDAP_SUCCESS ) {
+ dsgw_ldap_error( ld, DSGW_ERROPT_EXIT );
+ }
+ dsgw_html_end();
+ } else {
+ /* use template to create a nicely formatted display */
+ dsgw_display_entry( tip, ld, entry, aoentry, NULL );
+ dsgw_display_done( tip );
+ }
+
+ if ( attr0 != NULL ) {
+ attrs[ 0 ] = attr0; /* if we replaced this, put original back */
+ }
+
+ if ( msgp != NULL ) {
+ ldap_msgfree( msgp );
+ }
+ if ( aomsgp != NULL ) {
+ ldap_msgfree( aomsgp );
+ }
+}
+
+
+/*
+ * return 1 if the entry already exists, 0 if not, -1 if some error occurs
+ */
+int
+dsgw_ldap_entry_exists( LDAP *ld, char *dn, char **matchedp,
+ unsigned long erropts )
+{
+ LDAPMessage *msgp;
+ int rc;
+
+ msgp = NULL;
+ if ( matchedp != NULL ) {
+ *matchedp = NULL;
+ }
+
+ if (( rc = do_search( NULL, ld, dn, LDAP_SCOPE_BASE, "(objectClass=*)",
+ &msgp )) != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT ) {
+ dsgw_ldap_error( ld, erropts );
+ }
+
+ if ( msgp == NULL || rc == LDAP_NO_SUCH_OBJECT ) {
+ rc = 0;
+ if ( matchedp != NULL ) {
+ (void)ldap_get_lderrno( ld, matchedp, NULL );
+ }
+ } else {
+ rc = ( ldap_count_entries( ld, msgp ) > 0 ? 1 : 0 );
+ ldap_msgfree( msgp );
+ }
+
+ return( rc );
+}
+
+
+static int
+entry2htmlwrite( void *fp, char *buf, int len )
+{
+ return( fwrite( buf, len, 1, (FILE *)fp ) == 0 ? -1 : len );
+}
+
+
+/*
+ * return 1 if the entry's parent exists, 0 if not, -1 if some error occurs.
+ * If the entry is the same as gc->gc_ldapsearchbase, then we return 1,
+ * so we don't prevent people from adding their organizational entry.
+ */
+int
+dsgw_ldap_parent_exists( LDAP *ld, char *dn, unsigned long erropts )
+{
+ LDAPMessage *msgp;
+ int rc;
+
+ /* Is "dn" == gc->gc_ldapsearchbase? */
+ msgp = NULL;
+ if (( rc = do_search( NULL, ld, dn, LDAP_SCOPE_BASE, "(objectClass=*)",
+ &msgp )) != LDAP_SUCCESS && rc != LDAP_NO_SUCH_OBJECT ) {
+ dsgw_ldap_error( ld, erropts );
+ }
+
+ if ( msgp == NULL ) {
+ rc = 0;
+ } else {
+ rc = ( ldap_count_entries( ld, msgp ) > 0 ? 1 : 0 );
+ ldap_msgfree( msgp );
+ }
+
+ return( rc );
+}
+
+
+
+/*
+ * this function is called back by LIBLDAP when chasing referrals
+ */
+static int LDAP_CALL LDAP_CALLBACK
+get_rebind_credentials( LDAP *ld, char **whop, char **credp,
+ int *methodp, int freeit, void *arg )
+{
+ if ( !freeit ) {
+ *whop = binddn;
+ *credp = bindpasswd;
+ *methodp = LDAP_AUTH_SIMPLE;
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+char *
+dsgw_get_binddn()
+{
+ return( binddn );
+}
+
+/*
+ * return 1 if bound using "dn"
+ * return 0 if definitely bound as someone else
+ * return "def_answer" is we can't tell for sure
+ */
+int
+dsgw_bound_as_dn( char *dn, int def_answer )
+{
+ int i, rc;
+ char **rdns1, **rdns2;
+
+ if ( binddn == NULL ) {
+ /*
+ * not authenticated: if not using local db or using it as an
+ * end-user, return the default
+ */
+ if ( gc->gc_localdbconf == NULL || gc->gc_enduser ) {
+ return( def_answer );
+ }
+
+ /*
+ * if using local db as an admin, return "bound as someone else"
+ * since there is no access control enforced anyways.
+ */
+ return( 0 );
+ }
+
+ /* first try a simple case-insensitive comparison */
+ if ( strcasecmp( binddn, dn ) == 0 ) {
+ return( 1 ); /* DNs are the same */
+ }
+
+ /*
+ * These DNs may not have the same spacing or punctuation. Compare RDN
+ * components to eliminate any differences.
+ */
+ if (( rdns1 = ldap_explode_dn( binddn, 0 )) == NULL ) {
+ return( def_answer ); /* we don't know: return the default */
+ }
+
+ if (( rdns2 = ldap_explode_dn( dn, 0 )) == NULL ) {
+ ldap_value_free( rdns1 );
+ return( def_answer ); /* we don't know: return the default */
+ }
+
+ for ( i = 0; rdns1[ i ] != NULL && rdns2[ i ] != NULL; ++i ) {
+ if ( strcasecmp( rdns1[ i ], rdns2[ i ] ) != 0 ) {
+ break; /* DNs are not the same */
+ }
+ }
+
+ rc = ( rdns1[ i ] == NULL && rdns2[ i ] == NULL );
+
+ ldap_value_free( rdns1 );
+ ldap_value_free( rdns2 );
+
+ return( rc );
+}
+
+
+
+/*
+ * Compare 2 DNs. Return 1 if they are equivalent, 0 if not.
+ */
+int
+dsgw_dn_cmp( char *dn1, char *dn2 )
+{
+ int i, rc;
+ char **rdns1, **rdns2;
+
+ /* first try a simple case-insensitive comparison */
+ if ( dsgw_utf8casecmp( (unsigned char *)dn1, (unsigned char *)dn2 ) == 0 ) {
+ return( 1 ); /* DNs are the same */
+ }
+
+ /*
+ * These DNs may not have the same spacing or punctuation. Compare RDN
+ * components to eliminate any differences.
+ */
+ if (( rdns1 = ldap_explode_dn( dn1, 0 )) == NULL ) {
+ return( 0 ); /* we don't know: return 0 */
+ }
+
+ if (( rdns2 = ldap_explode_dn( dn2, 0 )) == NULL ) {
+ ldap_value_free( rdns1 );
+ return( 0 ); /* we don't know: return 0 */
+ }
+
+ for ( i = 0; rdns1[ i ] != NULL && rdns2[ i ] != NULL; ++i ) {
+ if ( dsgw_utf8casecmp( (unsigned char *)rdns1[ i ], (unsigned char *)rdns2[ i ] ) != 0 ) {
+ break; /* DNs are not the same */
+ }
+ }
+
+ rc = ( rdns1[ i ] == NULL && rdns2[ i ] == NULL );
+
+ ldap_value_free( rdns1 );
+ ldap_value_free( rdns2 );
+
+ return( rc );
+}
+
+
+/*
+ * Return the parent of dn. The caller is responsible for freeing the
+ * returned value. Returns NULL on error.
+ */
+char *
+dsgw_dn_parent( char *dn )
+{
+ char *dnp;
+ int i;
+ char **rdns;
+
+ if ( dn == NULL ) {
+ return( NULL );
+ }
+
+ dnp = dsgw_ch_malloc( strlen( dn ));
+ dnp[ 0 ] = '\0';
+ if (( rdns = ldap_explode_dn( dn, 0 )) == NULL ) {
+ return NULL;
+ }
+ for ( i = 1; rdns[ i ] != NULL; i++ ) {
+ strcat( dnp, rdns[ i ] );
+ strcat( dnp, "," );
+ }
+ /* Get rid of the trailing "," we just appended */
+ dnp[ strlen( dnp ) - 1 ] = '\0';
+ ldap_value_free( rdns );
+ return( dnp );
+}
+
+
+/*
+ * Return 1 if dn1 is the immediate ancestor of dn2, 0 otherwise.
+ */
+int
+dsgw_is_dnparent( char *dn1, char *dn2 )
+{
+ char *dnp;
+ int rc;
+
+ /* A null or zero-length DN cannot have a parent */
+ if ( dn2 == NULL || strlen( dn2 ) == 0 ) {
+ return 0;
+ }
+
+ dnp = dsgw_dn_parent( dn2 );
+ rc = dsgw_dn_cmp( dn1, dnp );
+ free( dnp );
+
+ return rc;
+}
+
+
+/*
+ * return malloc'd array of RDN attribute value pairs
+ * each element of the array is a string that looks like: TAG=VALUE
+ * this is used to extract values from the RDN when a new entry is added
+ */
+char **
+dsgw_rdn_values( char *dn )
+{
+ char **rdns, **rdncomps, *val;
+ int i;
+
+ if (( rdns = ldap_explode_dn( dn, 0 )) == NULL ) {
+ return( NULL );
+ }
+
+ rdncomps = ldap_explode_rdn( rdns[0], 0 );
+ ldap_value_free( rdns );
+ if ( rdncomps == NULL ) {
+ return( NULL );
+ }
+
+ for ( i = 0; rdncomps[ i ] != NULL; ++i ) {
+ if (( val = strchr( rdncomps[ i ], '=' )) == NULL ) {
+ ldap_value_free( rdncomps );
+ return( NULL );
+ }
+ ++val;
+ strcpy_special_undo( val, val ); /* undo in place */
+ }
+
+ return( rdncomps );
+}
+
+
+/*
+ * the following routine was lifted from servers/slapd/ava.c
+ * it removes special quoting, etc. from values that appear in an LDAP DN
+ */
+static void
+strcpy_special_undo( char *d, char *s )
+{
+ int quote;
+
+ quote = 0;
+ if ( *s == '"' ) {
+ s++;
+ quote = 1;
+ }
+ for ( ; *s; LDAP_UTF8INC(s)) {
+ switch ( *s ) {
+ case '"':
+ break;
+ case '\\':
+ s++;
+ /* FALL */
+ default:
+ d += LDAP_UTF8COPY (d, s);
+ break;
+ }
+ }
+ *d = '\0'; LDAP_UTF8DEC(d);
+ if ( quote && *d == '"' ) {
+ *d = '\0';
+ }
+}
+
+
+static char *
+uid2dn( LDAP *ld, char *uid, char *base, int *ldaprc, char **lderrtxtp,
+ char **errsp )
+{
+ char *attrs[] = { "objectclass", NULL };
+ char filtbuf[ 85 ]; /* max of 80 char. uid + "uid=" + zero terminator */
+ int rc, count;
+ LDAPMessage *result;
+ LDAPMessage *e;
+ char *dn;
+
+ *ldaprc = LDAP_SUCCESS; /* optimistic */
+ *errsp = *lderrtxtp = NULL;
+
+ if ( ld == NULL || uid == NULL || strlen( uid ) > 80 ) {
+ *errsp = XP_GetClientStr(DBT_invalidUserIdOrNullLdapHandle_);
+ return NULL;
+ }
+ PR_snprintf( filtbuf, 85, "uid=%s", uid );
+
+ if (( rc = ldap_search_s( ld, base, LDAP_SCOPE_SUBTREE, filtbuf,
+ attrs, 1, &result )) != LDAP_SUCCESS ) {
+ *ldaprc = rc;
+ (void)ldap_get_lderrno( ld, NULL, lderrtxtp );
+ return NULL;
+ }
+ if (( count = ldap_count_entries( ld, result )) != 1 ) {
+ /* Search either returned no entries, or more than one entry */
+ ldap_msgfree( result );
+ if ( count == 0 ) {
+ *errsp = XP_GetClientStr(DBT_noMatchForUserId_);
+ } else {
+ *errsp = XP_GetClientStr(DBT_moreThanOneMatchForUserId_);
+ }
+ return NULL;
+ }
+
+ dn = NULL;
+ if (( e = ldap_first_entry( ld, result )) == NULL ||
+ ( dn = ldap_get_dn( ld, e )) == NULL ) {
+ *ldaprc = ldap_get_lderrno( ld, NULL, NULL );
+ }
+ ldap_msgfree( result );
+ return( dn );
+}
+
+
+/*
+ * Emit an HTML "SELECT" object that contains all the o's and ou's that
+ * are underneath our default searchbase. If there are none other than
+ * the searchbase, we emit a hidden HTML TEXT object that contains the
+ * searchbase and the "prefix" and "suffix" are not used. The values for
+ * the SELECT options and for the TEXT object are all escaped DNs.
+ *
+ * Location popup directives look like this:
+ * <-- DS_LOCATIONPOPUP "name=VARNAME" "prefix=PREFIX" "suffix=SUFFIX" -->
+ *
+ * If "prefix" and/or "suffix" are omitted, they default to "".
+ * If "name" is omitted it defaults to "base".
+ *
+ * If there are "location" directives in the dsgw.conf file, we use those
+ * instead of actually searching the directory.
+ */
+void
+dsgw_emit_location_popup( LDAP *ld, int argc, char **argv, int erropts )
+{
+ char line[BIG_LINE];
+ char *varname, *prefix, *suffix, *rootname, *dn;
+ int i, count, did_init_ldap;
+ LDAPMessage *res, *e;
+
+ if (( varname = get_arg_by_name( "name", argc, argv )) == NULL ) {
+ varname = "base";
+ }
+ if (( prefix = get_arg_by_name( "prefix", argc, argv )) == NULL ) {
+ prefix = "";
+ }
+ if (( suffix = get_arg_by_name( "suffix", argc, argv )) == NULL ) {
+ suffix = "";
+ }
+ rootname = get_arg_by_name( "rootname", argc, argv );
+
+ did_init_ldap = 0;
+ res = NULL;
+
+ if ( gc->gc_newentryloccount > 0 ) {
+ count = gc->gc_newentryloccount;
+ } else {
+ char *attrs[ 3 ];
+ int rc;
+
+ if ( ld == NULL ) {
+ (void)dsgw_init_ldap( &ld, NULL, 0, 0 );
+ did_init_ldap = 1;
+ }
+ attrs[ 0 ] = "o";
+ attrs[ 1 ] = "ou";
+ attrs[ 2 ] = NULL;
+
+ rc = ldap_search_s( ld, gc->gc_ldapsearchbase, LDAP_SCOPE_SUBTREE,
+ "(|(objectclass=organization)(objectclass=organizationalunit))",
+ attrs, 1, &res );
+ if ( rc != LDAP_SUCCESS || res == NULL ) {
+ dsgw_ldap_error( ld, erropts );
+ return;
+ }
+
+ count = ldap_count_entries( ld, res );
+ if ( gc->gc_ldapsearchbase == NULL || *gc->gc_ldapsearchbase == '\0' ) {
+ ++count; /* include base DN even if it is "" */
+ } else {
+ /*
+ * check to see if search base was one of the entries returned
+ * we want to always list the base entry, so we need to check
+ */
+ for ( e = ldap_first_entry( ld, res ); e != NULL;
+ e = ldap_next_entry( ld, e )) {
+ if (( dn = ldap_get_dn( ld, e )) == NULL ) {
+ dsgw_ldap_error( ld, erropts );
+ ldap_msgfree( res );
+ return;
+ }
+
+ rc = dsgw_dn_cmp( dn, gc->gc_ldapsearchbase );
+ free( dn );
+ if ( rc ) { /* base DN was returned */
+ break;
+ }
+ }
+ if ( e == NULL ) {
+ ++count; /* include base DN even if was not returned */
+ }
+ }
+ }
+
+ if ( count > 1 ) {
+ util_snprintf( line, BIG_LINE, "%s\n<SELECT NAME=\"%s\">\n",
+ prefix, varname );
+ } else {
+ util_snprintf( line, BIG_LINE, "<INPUT TYPE=\"hidden\" NAME=\"%s\" ",
+ varname );
+ }
+ dsgw_emits( line );
+
+ if ( gc->gc_newentryloccount > 0 ) {
+ for ( i = 0; i < gc->gc_newentryloccount; ++i ) {
+ emit_one_loc_dn( gc->gc_newentrylocs[ i ].dsloc_dnsuffix,
+ gc->gc_newentrylocs[i].dsloc_fullname, rootname,
+ ( count < 2 ));
+ }
+ } else {
+ /* always include the base dn first */
+ emit_one_loc_dn( gc->gc_ldapsearchbase, NULL, rootname, ( count < 2 ));
+
+ /* XXXmcs it would be nice to do a more intelligent sort here */
+#ifdef DSGW_DEBUG
+ dsgw_log( "dsgw_emit_location_popup: ldap_sort_entries(NULL)\n" );
+#endif
+ ldap_sort_entries( ld, &res, NULL, dsgw_strcmp (CASE_INSENSITIVE));
+
+ for ( e = ldap_first_entry( ld, res ); e != NULL;
+ e = ldap_next_entry( ld, e )) {
+ if (( dn = ldap_get_dn( ld, e )) == NULL ) {
+ dsgw_ldap_error( ld, erropts );
+ ldap_msgfree( res );
+ return;
+ }
+
+ if ( !dsgw_dn_cmp( dn, gc->gc_ldapsearchbase )) {
+ emit_one_loc_dn( dn, NULL, rootname, ( count < 2 ));
+ }
+ free( dn );
+ }
+ }
+
+ if ( count > 1 ) {
+ util_snprintf( line, BIG_LINE, "</SELECT>\n%s\n", suffix );
+ dsgw_emits( line );
+ }
+
+ if ( res != NULL ) {
+ ldap_msgfree( res );
+ }
+ if ( did_init_ldap ) {
+ ldap_unbind( ld );
+ }
+}
+
+
+static void
+emit_one_loc_dn( char *dn, char *friendlyname, char *rootname, int only_one )
+{
+ char *escapeddn, **rdns, line[ BIG_LINE ];
+
+ rdns = NULL;
+ escapeddn = dsgw_strdup_escaped( dn );
+
+ if ( !only_one ) {
+ dsgw_emits( "<OPTION" );
+ }
+
+ if ( friendlyname == NULL ) { /* use first component of DN */
+ if ( *dn == '\0' ) {
+ friendlyname = ( rootname == NULL ? XP_GetClientStr(DBT_theEntireDirectory_)
+ : rootname );
+ } else if (( rdns = ldap_explode_dn( dn, 1 )) == NULL
+ || rdns[ 0 ] == NULL ) {
+ friendlyname = dn;
+ } else {
+ friendlyname = rdns[ 0 ];
+ }
+ }
+
+ util_snprintf( line, BIG_LINE, " VALUE=\"%s\">%s\n", escapeddn,
+ only_one ? "" : friendlyname );
+ free( escapeddn );
+ if ( rdns != NULL ) {
+ ldap_value_free( rdns );
+ }
+ dsgw_emits( line );
+}
+
+
+/*
+ * Return a MIME document that contains a single value.
+ * XXX: does this really belong in ldaputil.c?
+ */
+static void
+return_one_attr( LDAP *ld, LDAPMessage *entry, char *attrtype, char *mimetype,
+ int valindex )
+{
+ char *val;
+ struct berval **bvals;
+ unsigned long vlen;
+
+ if (( bvals = ldap_get_values_len( ld, entry, attrtype )) == NULL ) {
+ dsgw_error( DSGW_ERR_NOATTRVALUE, attrtype, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ if ( valindex > ldap_count_values_len( bvals )) {
+ dsgw_error( DSGW_ERR_NOATTRVALUE, attrtype, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+
+ val = bvals[ valindex ]->bv_val;
+ vlen = bvals[ valindex ]->bv_len;
+
+ fprintf( stdout, "Content-Type: %s\n", mimetype );
+ fprintf( stdout, "Content-Length: %ld\n\n", vlen );
+
+#ifdef XP_WIN32
+ /* flush any data on stdout before changing the mode */
+ fflush( stdout );
+
+ /* set the mode to binary
+ so windows doesn't replace with carriage
+ return line feed and mess everything up
+ */
+ _setmode( _fileno( stdout ), _O_BINARY );
+#endif
+
+ fwrite( val, vlen, 1, stdout );
+
+#ifdef XP_WIN32
+ /* flush any remaining binary data */
+ fflush( stdout );
+
+ /* set the mode back to text */
+ _setmode( _fileno( stdout ), _O_TEXT );
+#endif
+
+ ldap_value_free_len( bvals );
+ free( attrtype );
+}
+
+
+/*
+ * The general format of attrtype is:
+ * <attrtype> [ &<mimetype> ] [ &<valindex> ]
+ * This routine breaks it up. Callers should free( *attrtypep ) after they
+ * are done using attrtypep and mimetypep.
+ */
+static void
+break_up_one_attr( char *attr, char **attrtypep, char **mimetypep,
+ int *valindexp )
+{
+ char *p;
+
+ *attrtypep = dsgw_ch_strdup( attr );
+
+ *mimetypep = "text/plain"; /* default */
+ *valindexp = 0; /* default: retrieve first value */
+
+ if (( p = strchr( *attrtypep, '&' )) != NULL ) {
+ *p++ = '\0';
+ if ( *p != '\0' ) {
+ *mimetypep = p;
+ if (( p = strchr( *mimetypep, '&' )) != NULL ) {
+ *p++ = '\0';
+ *valindexp = atoi( p );
+ }
+ }
+ }
+}
diff --git a/ldap/clients/dsgw/newentry.c b/ldap/clients/dsgw/newentry.c
new file mode 100644
index 00000000..67145195
--- /dev/null
+++ b/ldap/clients/dsgw/newentry.c
@@ -0,0 +1,447 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * newentry.c -- CGI program to generate newentry form -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+static void emit_file(char* filename, dsgwnewtype* entType);
+
+#if 0 /* unused */
+static void
+unquote_emits(char* s)
+{
+ dsgw_quotation_end();
+ dsgw_emits (s);
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
+}
+
+static void
+quote_emit_file(char* filename)
+{
+ dsgw_quotation_begin (QUOTATION_JAVASCRIPT_MULTILINE);
+ emit_file (filename, NULL);
+ dsgw_quotation_end();
+}
+#endif
+
+static void
+emit_file (char* filename, dsgwnewtype* entType)
+{
+ auto FILE* html = dsgw_open_html_file( filename, DSGW_ERROPT_EXIT );
+ auto char line[ BIG_LINE ];
+ auto int argc;
+ auto char **argv;
+ char *deleteme = NULL;
+
+ while ( dsgw_next_html_line( html, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, dsgw_simple_cond_is_true, NULL )) {
+ if ( dsgw_directive_is( line, DRCT_HEAD )) {
+ dsgw_head_begin();
+ dsgw_emits ("\n");
+
+ } else if ( dsgw_directive_is( line, "DS_NEWENTRY_SCRIPT" )) {
+ dsgw_emits ("<SCRIPT LANGUAGE=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript-capable browsers\n"
+ "var selectedType = -1;\n"
+ "\n"
+ "function typeChange(selectType)\n"
+ "{\n"
+ " var newType = selectType.selectedIndex;\n"
+ " if ( newType != selectedType ) {\n"
+ " selectedType = newType;\n"
+ " newentryNameFrame.location.href = '"
+ DSGW_URLPREFIX_CGI_HTTP
+ "newentry?context=");
+ dsgw_emits(context);
+ dsgw_emits( "&file=name&etype=' +\n"
+ " escape (selectType.options[newType].value);\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "var previousLocation = '';\n"
+ "var locationChangedRecently = false;\n"
+ "\n"
+ "function locationChange(nameForm)\n"
+ "{\n"
+ " var location = nameForm.selectLocation.options[nameForm.selectLocation.selectedIndex].value;\n"
+ " if ( location != previousLocation ) {\n"
+ " if ( nameForm.dnsuffix != null ) {\n"
+ " if ( location != '' ) {\n"
+ " nameForm.dnsuffix.blur();\n"
+ " nameForm.dnsuffix.value = '';\n"
+ " // In Navigator for Macintosh, the preceding code\n"
+ " // causes a subsequent focus event in dnsuffix.\n"
+ " // Prevent dnsuffixFocus from acting on it:\n"
+ " locationChangedRecently = true;\n"
+ " setTimeout ('locationChangedRecently = false', 100);\n"
+ " } else {\n"
+ " nameForm.dnsuffix.value = previousLocation;\n"
+ " nameForm.dnsuffix.focus();\n"
+ " nameForm.dnsuffix.select();\n"
+ " }\n"
+ " }\n"
+ " previousLocation = location;\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "function dnsuffixFocus(nameForm)\n"
+ "{\n"
+ " var location = nameForm.selectLocation.options[nameForm.selectLocation.selectedIndex].value;\n"
+ " if ( location != '' && ( ! locationChangedRecently )) {\n"
+ " if ( nameForm.dnsuffix.value == '' ) {\n"
+ " nameForm.dnsuffix.value = location;\n"
+ " setTimeout ('newentryNameFrame.document.nameForm.dnsuffix.select()', 75);\n"
+ " // This is not done immediately, to avoid interference from mouse-up.\n"
+ " }\n"
+ " for ( i = 0; i < nameForm.selectLocation.length; i++ ) {\n"
+ " if ( nameForm.selectLocation.options[i].value == '' ) {\n"
+ " previousLocation = '';\n"
+ " nameForm.selectLocation.selectedIndex = i;\n"
+ " break;\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n"
+ "\n"
+ "function submitNameForm(nameForm)\n"
+ "{\n"
+ " if ( nameForm.entryname.value == '' ) {\n");
+ deleteme = XP_GetClientStr (DBT_enterNameForNewEntry_);
+
+ dsgw_emit_alert ("newentryNameFrame", "width=400,height=130,resizable",
+ XP_GetClientStr (DBT_enterNameForNewEntry_));
+ dsgw_emits (" return false;\n"
+ " } else if ( nameForm.selectLocation.options[nameForm.selectLocation.selectedIndex].value == '' &&\n"
+ " ( nameForm.dnsuffix == null ||\n"
+ " nameForm.dnsuffix.value == '' )) {\n");
+ dsgw_emit_alert ("newentryNameFrame", "width=400,height=130,resizable",
+ XP_GetClientStr (DBT_enterLocationForNewEntry_));
+ dsgw_emits (" return false;\n"
+ " } else {\n"
+ " open('', 'NewEntryWindow');\n"
+ " }\n"
+ " return true;\n"
+ "}\n"
+ "\n"
+ "function init()\n"
+ "{\n"
+ "}\n"
+ "\n"
+ "// end hiding -->\n"
+ "</SCRIPT>\n");
+
+ } else if ( dsgw_directive_is( line, "DS_NEWENTRY_TYPE_BODY" )) {
+ dsgw_emitf ("<BODY %s>\n",
+ dsgw_html_body_colors );
+
+ } else if ( dsgw_directive_is( line, "DS_NEWENTRY_TYPE_FORM" )) {
+ dsgw_form_begin ("typeForm", NULL);
+ dsgw_emits ("\n");
+
+ } else if ( dsgw_directive_is( line, "DS_NEWENTRY_TYPE_SELECT" )) {
+ auto dsgwnewtype* ntp;
+ dsgw_emits ("<SELECT NAME=\"selectType\" onChange=\"parent.typeChange(this)\">\n");
+ for (ntp = gc->gc_newentrytypes; ntp; ntp = ntp->dsnt_next) {
+ dsgw_emitf ("<OPTION VALUE=\"%s\">%s</OPTION>\n",
+ ntp->dsnt_template ? ntp->dsnt_template : "",
+ ntp->dsnt_fullname ? ntp->dsnt_fullname : "");
+ }
+ dsgw_emits ("</SELECT>\n" );
+
+ } else if ( dsgw_directive_is( line, "DS_NEWENTRY_NAME_BODY" )) {
+ dsgw_emits ("<BODY onLoad=\"");
+ if (entType && entType->dsnt_loccount) {
+ dsgw_emits ("parent.locationChange(document.nameForm);");
+ }
+ dsgw_emitf ("document.nameForm.entryname.focus()\" %s>\n",
+ dsgw_html_body_colors );
+ dsgw_emit_alertForm();
+
+ } else if ( dsgw_directive_is( line, "DS_NEWENTRY_NAME_FORM" )) {
+ dsgw_form_begin ("nameForm", "action=\"" DSGW_URLPREFIX_CGI_HTTP "newentry\""
+ " target=NewEntryWindow"
+ " onSubmit=\"return parent.submitNameForm(this)\"");
+ dsgw_emits ("\n");
+
+ if (entType) {
+ if (entType->dsnt_rdnattr) {
+ dsgw_emitf ("<INPUT TYPE=\"hidden\" NAME=\"rdntag\" VALUE=\"%s\">\n",
+ entType->dsnt_rdnattr);
+ }
+ if (entType->dsnt_template) {
+ dsgw_emitf ("<INPUT TYPE=\"hidden\" NAME=\"entrytype\" VALUE=\"%s\">\n",
+ entType->dsnt_template);
+ }
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_NEWENTRY_LOCATION_BEGIN" )) {
+ if ( ! (entType && entType->dsnt_loccount)) {
+ while ( dsgw_next_html_line( html, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 1, dsgw_simple_cond_is_true, NULL )) {
+ if ( dsgw_directive_is( line, "DS_NEWENTRY_LOCATION_END" )) {
+ break;
+ }
+ }
+ }
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_NEWENTRY_LOCATION_SELECT" )) {
+ dsgw_emits ("<SELECT NAME=\"selectLocation\""
+ " onChange=\"parent.locationChange(this.form)\">\n");
+ if (entType) {
+ auto dsgwloc* locarray = gc->gc_newentrylocs;
+ auto const int loccount = gc->gc_newentryloccount;
+ auto int j;
+ for ( j = 0; j < entType->dsnt_loccount; ++j ) {
+ auto const int i = entType->dsnt_locations[j];
+ if (i < loccount) {
+ dsgw_emits ("<OPTION VALUE=");
+ dsgw_emitf ("\"%s\"", locarray[i].dsloc_dnsuffix); /* XXX should escape '"' in dnsuffix */
+ dsgw_emitf (">%s</OPTION>\n", locarray[i].dsloc_fullname);
+ }
+ }
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_NEWENTRY_LOCATION_END" )) {
+
+ } else if ( dsgw_directive_is( line, "EVALUATE" )) {
+ if (entType) {
+ auto int i;
+ for (i = 0; i < argc; ++i) {
+ if (!strcmp (argv[i], "entType.fullname")) {
+ if (entType->dsnt_fullname) dsgw_emits (entType->dsnt_fullname);
+ } else if (!strcmp (argv[i], "entType.rdnattr")) {
+ if (entType->dsnt_rdnattr) dsgw_emits (entType->dsnt_rdnattr);
+ } else if (!strcmp (argv[i], "entType.template")) {
+ if (entType->dsnt_template) dsgw_emits (entType->dsnt_template);
+ }
+ }
+ }
+
+ } else if ( dsgw_directive_is( line, "DS_HELP_BUTTON" ) && argc > 0) {
+ dsgw_emit_helpbutton (argv[0]);
+ } else {
+ dsgw_emits (line);
+ }
+ dsgw_argv_free( argv );
+ }
+ }
+ fclose (html);
+}
+
+static char*
+compute_newurl()
+{
+ auto char* entryType = dsgw_get_cgi_var( "entrytype", DSGW_CGIVAR_REQUIRED );
+ auto char* entryName = dsgw_get_cgi_var( "entryname", DSGW_CGIVAR_REQUIRED );
+ auto char* rdnTag = dsgw_get_cgi_var( "rdntag", DSGW_CGIVAR_REQUIRED );
+ auto char* dnSuffix = dsgw_get_cgi_var( "selectLocation", DSGW_CGIVAR_OPTIONAL );
+ auto size_t entryTypeLen = strlen (entryType);
+ auto size_t entryNameLen = strlen (entryName);
+ auto size_t rdnTagLen = strlen (rdnTag);
+ auto size_t dnSuffixLen;
+ auto char* dn;
+ auto char* newurl = NULL;
+
+ if (!dnSuffix || !*dnSuffix) {
+ dnSuffix = dsgw_get_cgi_var( "dnsuffix", DSGW_CGIVAR_REQUIRED );
+ }
+ dnSuffixLen = strlen (dnSuffix);
+ dn = dsgw_ch_malloc (rdnTagLen + 1 + entryNameLen + 2 + 1 + dnSuffixLen + 1);
+ memcpy (dn, rdnTag, rdnTagLen + 1);
+ strcat (dn, "=");
+ if ( strchr (entryName, ',') || strchr (entryName, ';') ) {
+ strcat (dn, "\"");
+ strcat (dn, entryName);
+ strcat (dn, "\"");
+ } else {
+ strcat (dn, entryName);
+ }
+ strcat (dn, ",");
+ strcat (dn, dnSuffix);
+ {
+ auto char* edn = dsgw_strdup_escaped (dn);
+ auto const char* const prefix = DSGW_URLPREFIX_CGI_HTTP "edit?";
+ auto const char* const suffix = "&ADD";
+ auto const size_t ednLen = strlen (edn);
+ auto const size_t prefixLen = strlen (prefix);
+ auto const size_t suffixLen = strlen (suffix);
+ auto const size_t contextLen = strlen (context) + 9;
+
+ newurl = dsgw_ch_malloc (prefixLen + entryTypeLen + contextLen + suffixLen + 4 + ednLen + 1);
+
+ memcpy (newurl, prefix, prefixLen + 1);
+ strcat (newurl, entryType);
+ strcat (newurl, "&context=");
+ strcat (newurl, context);
+ strcat (newurl, suffix);
+ strcat (newurl, "&dn=");
+ strcat (newurl, edn);
+ free (edn);
+ }
+ free (dn);
+ return newurl;
+}
+
+static int
+client_is_authenticated()
+{
+ auto char* cookie = dsgw_get_auth_cookie();
+ auto char* rndstr = NULL;
+ auto char* dn = NULL;
+ auto int answer = 0;
+ if (cookie == NULL) return 0;
+ if (dsgw_parse_cookie (cookie, &rndstr, &dn) == 0) {
+ if (dn) {
+ answer = 1;
+ free (dn);
+ }
+ if (rndstr) free (rndstr);
+ }
+ free (cookie);
+ return answer;
+}
+
+static dsgwnewtype*
+find_entryType (char* query)
+{
+ auto dsgwnewtype* ntp = gc->gc_newentrytypes;
+ if (query && *query) {
+ auto char* template = dsgw_ch_strdup (query);
+ dsgw_form_unescape (template);
+ for ( ; ntp; ntp = ntp->dsnt_next) {
+ if (ntp->dsnt_template && !strcmp (ntp->dsnt_template, template)) {
+ break;
+ }
+ }
+ free (template);
+ }
+ return ntp;
+}
+
+static void
+get_request(char *docname, char *etype)
+{
+ if ( docname == NULL || *docname == '\0' ) {
+ emit_file ("newentry.html", NULL);
+ } else if ( !strcmp( docname, "type" )) {
+ emit_file ("newentryType.html", NULL);
+ } else if ( !strcmp( docname, "name" )) {
+ /*emit_file ("newentryName.html", find_entryType (getenv ("QUERY_STRING")));*/
+ emit_file ("newentryName.html", find_entryType (etype));
+ }
+}
+
+static void
+post_request()
+{
+ auto char* newurl = compute_newurl();
+ if (client_is_authenticated()) {
+ /* Direct the client to GET newurl */
+ dsgw_emits ("<HTML>" );
+ dsgw_head_begin();
+ dsgw_emitf ("\n<TITLE>%s</TITLE>\n", XP_GetClientStr (DBT_titleNewEntry_));
+ dsgw_emits ("</HEAD>\n"
+ "<FRAMESET ROWS=*,1>\n");
+ dsgw_emitf (" <FRAME SRC=\"%s\" NORESIZE>\n", newurl);
+ dsgw_emits ("</FRAMESET>\n"
+ "</HTML>\n");
+ /* It's tempting to use server redirection, like this:
+ printf ("Location: %s\n\n", newurl);
+ ... but it won't work, because we're handling a POST,
+ and the client should GET newurl.
+ */
+ } else {
+#ifdef DSGW_DEBUG
+ dsgw_log ("dsgw_emit_auth_dest (NULL, %s)\n",
+ newurl ? newurl : "NULL");
+#endif
+ dsgw_emit_auth_dest (NULL, newurl);
+ }
+ if (newurl) free (newurl);
+}
+
+int
+main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+ auto int reqmethod;
+ char *qs = NULL;
+ char *docname = NULL;
+ char *etype = NULL;
+
+ /* Parse out the file=blah.html */
+ if (( qs = getenv( "QUERY_STRING" )) != NULL && *qs != '\0' ) {
+ /* parse the query string: */
+ auto char *p, *iter = NULL;
+ qs = dsgw_ch_strdup( qs );
+
+ for ( p = ldap_utf8strtok_r( qs, "&", &iter ); p != NULL;
+ p = ldap_utf8strtok_r( NULL, "&", &iter )) {
+
+ /*
+ * Get the conf file name. It'll be translated
+ * into /dsgw/context/CONTEXT.conf if
+ * CONTEXT is all alphanumeric (no slahes,
+ * or dots). CONTEXT is passed into the cgi.
+ * if context=CONTEXT is not there, or PATH_INFO
+ * was used, then use dsgw.conf
+ */
+ if ( !strncasecmp( p, "context=", 8 )) {
+ context = dsgw_ch_strdup( p + 8 );
+ dsgw_form_unescape( context );
+ continue;
+ }
+
+ /*
+ * file will be either "name", "type", or nothing.
+ * It'll be mapped into an html file in get_request
+ */
+ if ( !strncasecmp( p, "file=", 5 )) {
+ docname = dsgw_ch_strdup( p + 5 );
+ dsgw_form_unescape( docname );
+
+ continue;
+ }
+
+ /* etype will be ntgroup, or person, etc */
+ if ( !strncasecmp( p, "etype=", 6 )) {
+ etype = dsgw_ch_strdup( p + 6 );
+ dsgw_form_unescape( etype );
+
+ continue;
+ }
+ }
+ free( qs ); qs = NULL;
+ }
+
+ if (docname != NULL && *docname == '/') {
+ docname++;
+ }
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_POST | DSGW_METHOD_GET);
+ dsgw_send_header();
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ if ( reqmethod == DSGW_METHOD_GET ) {
+ get_request(docname, etype);
+ } else {
+ post_request();
+ }
+ exit( 0 );
+}
diff --git a/ldap/clients/dsgw/pbconfig/Makefile b/ldap/clients/dsgw/pbconfig/Makefile
new file mode 100644
index 00000000..f81f381d
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/Makefile
@@ -0,0 +1,50 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# Gmakefile for Directory Server Gateway config files.
+#
+
+LDAP_SRC = ../../..
+MCOM_ROOT = ../../../../..
+
+NOSTDSTRIP=true # don't let nsconfig.mak define target strip
+NOSTDCLEAN=true # don't let nsconfig.mak define target clean
+NOSTDDEPEND=true # don't let nsconfig.mak define target depend
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+include ../dsgw_include.mk
+
+HTMLDEST = $(DSGW_PBCONF_RELDIR)
+
+HTML = pb.tmpl dsgwsearchprefs.conf display-room.html edit-passwd.html\
+ display-orgperson.html list-Auth.html authPassword.html \
+ list-People.html authSearch.html display-orgunit.html \
+ dsgwfilter.conf
+
+BINS=$(addprefix $(HTMLDEST)/,$(HTML))
+
+ifeq ($(ARCH), WINNT)
+CP2=cmd /c 'sh ../../../cm/nbsp2utf8.sh $< >'
+else
+CP2=sh ../../../cm/nbsp2utf8.sh $< >
+endif
+
+all: $(HTMLDEST) $(BINS)
+
+install: $(HTMLDEST) $(BINS)
+
+clean:
+ $(RM) $(BINS)
+
+$(HTMLDEST)/%: %
+ -@$(RM) $@
+ $(CP2) $@
+
+strip:
+depend:
diff --git a/ldap/clients/dsgw/pbconfig/authPassword.html b/ldap/clients/dsgw/pbconfig/authPassword.html
new file mode 100644
index 00000000..98395470
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/authPassword.html
@@ -0,0 +1,43 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!--
+ | $Id: authPassword.html,v 1.1 2005/01/21 00:40:49 cvsadm Exp $
+ |
+ | AUTHOR:
+ |
+ | SYNOPSIS:
+ | Display the vendor information.
+ |
+ | HISTORY:
+ |
+ +------------------------------------------------------------------------
+-->
+
+<HTML>
+<!-- HEAD -->
+<!--authPassword.html-->
+<TITLE>Authenticate...</TITLE>
+<!-- DS_AUTH_PASSWORD_SCRIPT -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<!-- DS_AUTH_PASSWORD_BODY -->
+<!-- DS_AUTH_PASSWORD_INFO -->
+<!-- DS_AUTH_PASSWORD_FORM -->
+<P>
+Password for <b>
+<!-- DS_AUTH_PASSWORD_NAME -->
+</b>: <INPUT NAME="password" TYPE="password" SIZE=16>
+<P>
+<CENTER>
+<TABLE BORDER=2 WIDTH=100%>
+<TR>
+<!-- DS_AUTH_PASSWORD_BUTTONS -->
+</TABLE>
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/pbconfig/authSearch.html b/ldap/clients/dsgw/pbconfig/authSearch.html
new file mode 100644
index 00000000..dc2c1fc7
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/authSearch.html
@@ -0,0 +1,44 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- ---------------------------------------------------------------------------
+ | $Id: authSearch.html,v 1.1 2005/01/21 00:40:49 cvsadm Exp $
+ |
+ | AUTHOR:
+ |
+ | SYNOPSIS:
+ | Display the vendor information.
+ |
+ | HISTORY:
+ |
+ +------------------------------------------------------------------------------ -->
+
+<HTML>
+<!-- HEAD -->
+<!--authSearch.html-->
+<TITLE>Authenticate...</TITLE>
+<!-- DS_AUTH_SEARCH_SCRIPT -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<!-- DS_AUTH_SEARCH_BODY -->
+<!-- DS_AUTH_SEARCH_INFO -->
+<!-- DS_AUTH_SEARCH_FORM -->
+The first step in authenticating to the directory is identifying
+yourself.<br>Please type your name:
+<!-- DS_AUTH_SEARCH_NAME -->
+<P>
+<CENTER>
+<TABLE BORDER=1 WIDTH=100%%>
+<TR>
+<!-- DS_AUTH_SEARCH_BUTTONS -->
+</TABLE>
+</FORM>
+<P>
+<!-- DS_AUTH_AS_ROOT_FORM -->
+<INPUT TYPE="submit" VALUE="Authenticate as directory manager"> (only available to Directory Administrators)
+</FORM>
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/pbconfig/display-orgperson.html b/ldap/clients/dsgw/pbconfig/display-orgperson.html
new file mode 100644
index 00000000..b7eea966
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/display-orgperson.html
@@ -0,0 +1,388 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+<!-- HEAD -->
+<!-- inet. organizational person directory entry -->
+<!-- DS_OBJECTCLASS "value=person,inetOrgPerson" -->
+
+<!-- DS_ENTRYBEGIN -->
+<title>
+
+
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Person Entry -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</title>
+
+<script language="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+
+var cardurl;
+
+function locator(){
+
+<!-- DS_ATTRIBUTE "attr=_vcard" "options=link" "mimetype=text/x-vcard" "prefix=var cardurl=" "suffix=";" -->
+
+ card.cards.document.location = cardurl;
+}
+
+function showVCard()
+{
+
+ card = window.open("/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=carded.html","leif","width=525,height=250,toolbar=no");
+
+ setTimeout("locator()",1000);
+
+}
+
+function showAimIcon()
+{
+var aimStatusText = "";
+var aimID = "";
+
+<!-- IF "DisplayAimPresence" -->
+aimStatusText =
+<!-- DS_ATTRIBUTE "attr=nsaimstatustext" "options=quoted" -->
+;
+
+aimID =
+<!-- DS_ATTRIBUTE "attr=nsaimid" "options=quoted" -->
+;
+<!-- ENDIF -->
+
+if (aimStatusText == "" || aimID == "" || aimStatusText != "ONLINE") {
+ return;
+}
+
+document.write('<a href=\"aim:goim?Screenname=' + aimID.replace(/ /,"+") + '\"><IMG SRC=\"lang?<!-- GCONTEXT -->&file=aim-online.gif\" ALT=\"Click to send an AIM to this person\" BORDER=0 HSPACE=5></a>');
+}
+
+// End hiding -->
+</script>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</head>
+
+
+<!-- COLORS "BGCOLOR=white" -->
+<!-- IF "!Displaying" -->
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Person Entry</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+<!-- ELSE -->
+<body bgcolor="#FFFFFF">
+<!-- ENDIF -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<!-- IF "Adding" -->
+ <input type="hidden" name="add_objectClass" value="top">
+ <input type="hidden" name="add_objectClass" value="person">
+ <input type="hidden" name="add_objectClass" value="organizationalPerson">
+ <input type="hidden" name="add_objectClass" value="inetOrgPerson">
+ <input type="hidden" name="add_objectClass" value="nsAIMpresence">
+<!-- PCONTEXT -->
+<!-- ENDIF // Adding -->
+
+
+<!-- --------------- Begin Header Info ------------------ -->
+<!-- single-pixel gif to enforce left alignment -->
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="1" width="1" hspace="20" align="left" border="0">
+
+<table width="90%" border="0" cellpadding="2" cellspacing="0" align="left" bgcolor="#FFFFFF">
+ <tr valign="middle" align="left" class="bgcolor4">
+ <td width="10" nowrap align="center">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=32-person.gif" height="32" width="32" border="0" align="center">
+ </td>
+ <td nowrap class="boldbig">
+<!-- IF "Adding" -->
+ New Person -
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=cn" "syntax=cis" "options=readonly" -->
+ </td>
+ <td align="right">
+<!-- IF "DisplayOrgChart" -->
+<A HREF=
+<!-- DS_ORGCHARTLINK -->
+ class="linknodec">
+<IMG SRC="lang?<!-- GCONTEXT -->&file=orgicon.gif" BORDER=0 ALT="Click to view this person's organization chart." HSPACE=5><span style="text-decoration:none;color:black">&nbsp;org chart</span></a>
+<!-- ENDIF -->
+ <a href="javascript:showVCard()" onMouseOver="top.status='View this person\'s digital business card.'; return true" class="linknodec"><img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=tiny_vcard.gif" align="texttop" border="0" height="20"
+ width="20" alt="Click to view this person's digital business card."><span style="text-decoration:none;color:black">&nbsp; vCard</span></a>
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "userCertificate;binary" -->
+ &nbsp;&nbsp;
+<a href=
+<!-- DS_ATTRIBUTE "attr=userCertificate;binary" "options=link" "mimetype=application/x-x509-email-cert" -->
+onMouseOver="top.status='Retrieve this person\'s security certificate.'; return true"><img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=tiny_cert.gif" align="texttop" border="0" height="20" width="20" alt="Click to retrieve this
+person's security certificate."><span style="text-decoration:none;color:black">&nbsp;Get&nbsp;Certificate</span></a>
+<!-- ENDIF -->
+ &nbsp;
+ </td>
+ </tr>
+ <tr valign="top" align="left">
+ <td>
+ &nbsp;
+ </td>
+ <td colspan="2" nowrap>
+<!-- DS_ATTRIBUTE "attr=title" "type=hidden" "options=typeonly" -->
+<!-- IF "AttributeHasValues" "title" -->
+<!-- DS_ATTRIBUTE "attr=title" "options=readonly" -->
+<br>
+<!-- ENDIF -->
+<!-- DS_ATTRIBUTE "attr=ou" "options=readonly" -->
+ </td>
+ </tr>
+
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "type=hidden" "options=typeonly" -->
+
+ <tr valign="top">
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+ <td colspan="2">
+<!-- ELSE -->
+ <td colspan="3">
+<!-- ENDIF -->
+
+<!-- ---------------- Begin Table Data ------------------ -->
+
+<table border="0" cellpadding="4" cellspacing="1" width="100%" align="center">
+
+ <tr>
+ <td colspan="2">&nbsp;</td>
+ </tr>
+
+
+ <tr valign="top">
+ <td align="right" nowrap width="25%"
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Work Phone
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>20" "numfields=+1" "options=readonly"-->
+ </td>
+ </tr>
+
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Email Address
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" "cols=>20" "options=readonly" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ AIM ID
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=nsaimid" "cols=>16" -->
+<!-- IF "DisplayAimPresence" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+showAimIcon();
+// End hiding -->
+</SCRIPT>
+<!-- ENDIF -->
+ </td>
+ </tr>
+
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Homepage
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=labeledURI" "syntax=url" "cols=>60" "hrefextra=TARGET=_top" -->
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Home Phone
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=homePhone" "numfields=+1" "cols=>20" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Mobile Phone
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=mobile" "syntax=tel" "cols=>20" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Pager
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=pager" "syntax=tel" "cols=>20" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ FAX
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>20" -->
+ </td>
+ </tr>
+
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Mailing Address
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=postalAddress" "cols=>60" "options=readonly" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Mailstop
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=physicalDeliveryOfficeName" "cols=>10" "options=readonly" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Location
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=l" "cols=>30" "options=readonly" -->
+ </td>
+ </tr>
+
+
+
+ <tr valign="top">
+ <td align="right" nowrap
+<!-- IF "Displaying" -->
+ class="bold"
+<!-- ENDIF -->
+>
+ Cube Number
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>8" "options=readonly"-->
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">&nbsp;</td>
+ </tr>
+
+</table>
+
+<!-- ---------------------------------------------- -->
+ </td>
+
+<!-- IF "AttributeHasValues" "jpegPhoto" -->
+ <td align="left" bgcolor="white">
+<IMG SRC=
+<!-- DS_ATTRIBUTE "attr=jpegPhoto" "options=link" "mimetype=image/jpeg" -->
+BORDER=0>
+ </td>
+<!-- ENDIF -->
+
+ </tr>
+ <tr align="right">
+ <td colspan="4" class="bgColor4">
+<!-- IF "Displaying" -->
+<!-- DS_EDITBUTTON "label=Edit Person" -->
+<!-- ELIF "Adding" -->
+<!-- DS_SAVEBUTTON "label=Save New Person" -->
+<!-- ELIF "Editing" -->
+<!-- DS_SAVEBUTTON -->
+<!-- ENDIF // Editing -->
+
+<!-- IF "!Displaying" -->
+<!-- DS_CLOSEBUTTON "label=Cancel" -->
+<!-- ENDIF // !Displaying -->
+
+<!-- DS_EDITASBUTTON "label=Change Password" "template=passwd" -->
+ </td>
+
+ </tr>
+
+</table>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+</body>
+</html>
diff --git a/ldap/clients/dsgw/pbconfig/display-orgunit.html b/ldap/clients/dsgw/pbconfig/display-orgunit.html
new file mode 100644
index 00000000..5a999993
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/display-orgunit.html
@@ -0,0 +1,198 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- ---------------------------------------------------------------------------
+ | $Id: display-orgunit.html,v 1.1 2005/01/21 00:40:49 cvsadm Exp $
+ |
+ | AUTHOR:
+ |
+ | SYNOPSIS:
+ | Display the vendor information.
+ |
+ | HISTORY:
+ |
+ |
+ +--------------------------------------------------------------------------- -->
+
+<HTML>
+<!-- HEAD -->
+<!-- inet. organizational person directory entry -->
+<!-- DS_OBJECTCLASS "value=organizationalUnit" -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Organizational Unit Entry
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+<BODY bgcolor=WHITE>
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<!-- IF "Adding" -->
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="top">
+<INPUT TYPE="hidden" NAME="add_objectClass" VALUE="ou">
+<!-- ENDIF // Adding -->
+
+
+
+<!-- --------------- Begin Header Info ------------------ -->
+<!-- single-pixel gif to enforce left alignment -->
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="1" width="1" hspace="20" align="left" border="0">
+
+<table width="90%" border="0" cellpadding="2" cellspacing="0" align="left" bgcolor="#FFFFFF">
+ <tr valign="middle" align="left" class="bgColor4">
+ <td width="10" nowrap align="center">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=department.gif" height="32" width="32" border="0" align="center">
+ </td>
+ <td nowrap class="boldbig">
+<!-- DS_ATTRIBUTE "attr=ou" "syntax=cis" "options=readonly" -->
+ </td>
+ <td align="right">
+ </td>
+ </tr>
+ <tr valign="top" align="left">
+ <td>
+ &nbsp;
+ </td>
+ <td colspan="2" nowrap>
+ </td>
+ </tr>
+ <tr valign="top">
+ <td colspan="3">
+
+<!-- ---------------- Begin Table Data ------------------ -->
+
+<table border="0" cellpadding="4" cellspacing="1" width="100%" align="center">
+
+ <tr>
+ <td colspan="2">&nbsp;</td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap width="25%" class="bold">
+ Business Category
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=businessCategory" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ Description
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=description" "cols=>60" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ Contact Phone
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>20" "numfields=+1" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ Fax
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=facsimiletelephonenumber" "syntax=tel" "cols=>20 -->
+ </td>
+ </tr>
+
+
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ Location
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=l" "cols=>60" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ Mailing Address
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=postalAddress" "syntax=mls" "cols=>60" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ Mailstop
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=physicalDeliveryOfficeName" "cols=>10" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ Postal Code
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=postalCode" "cols=>10" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ Post Office Box
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=PostOfficeBox" "cols=>10" -->
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="4">&nbsp;</td>
+ </tr>
+
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ See Also
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "dncomponents=3" "cols=>50" -->
+ </td>
+ </tr>
+
+ <tr>
+ <td colspan="2">&nbsp;</td>
+ </tr>
+
+</table>
+
+<!-- ---------------------------------------------- -->
+
+ </td>
+ </tr>
+ <tr valign="middle" align="left" class="bgColor4">
+ <td colspan="2">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" border="0" height="20" width="91">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" border="0" height="20" width="107">
+ </td>
+ </tr>
+
+</table>
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/pbconfig/display-room.html b/ldap/clients/dsgw/pbconfig/display-room.html
new file mode 100644
index 00000000..baa4ee4f
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/display-room.html
@@ -0,0 +1,124 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+<!-- HEAD -->
+<!-- DS_OBJECTCLASS "value=Room" -->
+
+<!-- DS_ENTRYBEGIN -->
+<title>
+<!-- IF "Adding" -->
+New
+<!-- ENDIF // Adding -->
+Room Entry
+</title>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</head>
+<body bgcolor="white">
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<!-- IF "Adding" -->
+ <input type="hidden" name="add_objectClass" value="top">
+ <input type="hidden" name="add_objectClass" value="Room">
+<!-- PCONTEXT -->
+<!-- ENDIF // Adding -->
+
+<!-- --------------- Begin Header Info ------------------ -->
+<!-- single-pixel gif to enforce left alignment -->
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="1" width="1" hspace="20" align="left" border="0">
+
+<table width="90%" border="0" cellpadding="2" cellspacing="0" align="left" bgcolor="#FFFFFF">
+ <tr valign="middle" align="left" class="bgColor4">
+ <td width="10" nowrap align="center">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=32-conference.gif" height="32" width="32" border="0" align="center">
+ </td>
+ <td nowrap class="boldbig">
+<!-- IF "Adding" -->
+ New Room
+<!-- ENDIF // Adding -->
+<!-- DS_ATTRIBUTE "attr=cn" "syntax=dn" "options=readonly" -->
+ </td>
+ <td align="right">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" border="0" height="20" width="91">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" border="0" height="20" width="107">
+ </td>
+ </tr>
+ <tr valign="top" align="left">
+ <td>
+ &nbsp;
+ </td>
+ <td colspan="2" nowrap>
+<!-- IF "AttributeHasValues" "roomNumber" -->
+&nbsp;Room
+<!-- DS_ATTRIBUTE "attr=roomNumber" "cols=>5"-->
+<!-- ENDIF -->
+ </td>
+ </tr>
+ <tr valign="top">
+ <td colspan="3">
+
+<!-- ---------------- Begin Table Data ------------------ -->
+
+<table border="0" cellpadding="4" cellspacing="1" width="100%" align="center">
+
+ <tr>
+ <td colspan="2">&nbsp;</td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap width="25%" class="bold">
+ Phone Number
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>20" "numfields=+1" "options=readonly"-->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap class="bold">
+ Description
+ </td>
+ <td align="left" nowrap>
+<!-- DS_ATTRIBUTE "attr=description" "type=TEXTAREA" "cols=>50" "rows=>4" -->
+ </td>
+ </tr>
+
+ <tr valign="top">
+ <td align="right" nowrap width="25%" class="bold">
+ See Also
+ </td>
+ <td align="left" bgcolor="white">
+<!-- DS_ATTRIBUTE "attr=seeAlso" "syntax=dn" "cols=>50" "numfields=+1" "options=readonly"-->
+ </td>
+ </tr>
+
+
+ <tr>
+ <td colspan="2">&nbsp;</td>
+ </tr>
+
+</table>
+
+ </td>
+ </tr>
+ <tr valign="middle" align="left" class="bgColor4">
+ <td colspan="3">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" border="0" height="20" width="91">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" border="0" height="20" width="107">
+ </td>
+ </tr>
+
+</table>
+
+<br clear="ALL">
+
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/pbconfig/dsgwfilter.conf b/ldap/clients/dsgw/pbconfig/dsgwfilter.conf
new file mode 100644
index 00000000..2c083f00
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/dsgwfilter.conf
@@ -0,0 +1,89 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+################################################################################
+#
+# $Id: dsgwfilter.conf,v 1.1 2005/01/21 00:40:49 cvsadm Exp $
+#
+# AUTHOR:
+#
+# SYNOPSIS:
+# LDAP filter file.
+#
+# HISTORY:
+# 10-Oct-1997 Leif Put Phonebook under CVS control.
+#
+################################################################################
+
+
+################################################################################
+# lines like this that start with # or empty lines are ignored
+#
+# syntax:
+#
+# <tag>
+# <pattern1> <delimiters> <filter1-1> <desc1-1> [<scope>]
+# <filter1-2> <desc1-2> [<scope>]
+#
+# <pattern2> <delimiters> <filter2-1> <desc2-1> [<scope>] ...
+#
+# The "desc" should describe the filter and it should correctly complete
+# both of the following phrases:
+#
+# One <desc> match was found for...
+# Three <desc> matches were found for...
+#
+# The scope is optional, and should be one of:
+# "base"
+# "onelevel"
+# "subtree"
+# if it is included.
+#
+
+
+################################################################################
+# People searches.
+#
+"dsgw-people"
+ "^[a-zA-Z0-9]+=" " " "(%v))" "LDAP filter is"
+
+ "^[+]*[0-9][ 0-9-]*$" " " "(telephoneNumber=*%v*))" "phone number ends with"
+
+ "@" " " "(mail=%v))" "email address is"
+ "(mail=%v*))" "email address starts with"
+
+ "^.[. _].*" ". _" "(|(cn=%v1* %v2-)(&(ou=%v1* %v2-)(objectclass=organizationalUnit))))" "first initial + name is"
+
+ ".*[. _].$" ". _" "(|(cn=%v1-*)(&(ou=%v1-*)(objectclass=organizationalUnit))))" "name + last initial is"
+
+ "[. _]" ". _" "(|(sn=%v1-)(cn=%v1-)(&(ou=%v1-)(objectclass=organizationalUnit))))" "name is"
+
+ "^\*$" " " "(|(cn=*)(&(ou=*)(objectclass=organizationalUnit))))" "name or user id is"
+
+ "^.$" ". " "(|(cn=%v)(&(ou=%v)(objectclass=organizationalUnit))))" "full name is"
+
+ "^..$" ". " "(|(|(cn=%v*)(cn=*%v))(&(|(ou=%v*)(ou=*%v))(objectclass=organizationalUnit))))" "full name is"
+
+ ".*" ". " "(|(cn=*%v1*)(uid=%v1)(&(ou=*%v1*)(objectclass=organizationalUnit))))" "name or user id is"
+
+# Replace the line above with the following line if you are substring
+# indexing uid. If not, then only exact matches for uid will be found.
+#
+# ".*" ". " "(|(cn=*%v1*)(uid=*%v1*)(&(ou=*%v1*)(objectclass=organizationalUnit))))" "name or user id is"
+
+
+################################################################################
+# Authentication searches, prioritize UID first.
+#
+"dsgw-auth"
+ ".*" " " "(uid=%v))" "UID is"
+ "(cn=*%v1*))" "user name is"
+
+# Replace the line above with the following line if you are substring
+# indexing uid.
+#
+# "(|(cn=*%v1*)(uid=*%v1*)))" "user name is"
+
diff --git a/ldap/clients/dsgw/pbconfig/dsgwsearchprefs.conf b/ldap/clients/dsgw/pbconfig/dsgwsearchprefs.conf
new file mode 100644
index 00000000..528e66d7
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/dsgwsearchprefs.conf
@@ -0,0 +1,126 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+################################################################################
+#
+# $Id: dsgwsearchprefs.conf,v 1.1 2005/01/21 00:40:49 cvsadm Exp $
+#
+# AUTHOR:
+#
+# SYNOPSIS:
+# Search preference configuration file.
+#
+# HISTORY:
+# 10-Oct-1997 Leif Put Phonebook under CVS control.
+#
+################################################################################
+
+
+################################################################################
+# dsgwsearchprefs.conf - directory server gateway search object definitions
+# the current version of this file format is 1
+#
+Version 1
+
+
+################################################################################
+#
+# Name for this search object
+People
+
+
+################################################################################
+# options (the only one supported right now is "internal" which means that
+# this search object should not be presented directly to the user)
+# use "" for none
+#
+""
+
+
+################################################################################
+# Label to place before text box user types in
+#
+"Search For:"
+
+
+################################################################################
+# Filter prefix to append to all searches
+#
+"(&(|(objectClass=Person)(objectClass=inetOrgPerson)(objectClass=organizationalUnit)(objectClass=Room))"
+
+
+################################################################################
+# Tag to use for "Fewer Choices" searches - from ldapfilter.conf file
+#
+"dsgw-people"
+
+
+################################################################################
+# If a search results in > 1 match, retrieve this attribute to help
+# user disambiguate the entries...
+#
+not-used-by-dsgw
+
+
+################################################################################
+# ...and label it with this string:
+#
+not-used-by-dsgw
+
+
+################################################################################
+# Search scope to use when searching
+#
+subtree
+
+
+################################################################################
+# Follows a list of "More Choices" search options. Format is:
+# Label, attribute, select-bitmap, extra attr display name, extra attr ldap name
+# If last two are null, "Fewer Choices" name/attributes used
+#
+"full name" cn 111111 "" ""
+"last name" sn 111111 "" ""
+"phone number" "telephoneNumber" 111011 "" ""
+"e-mail address" "mail" 111111 "" ""
+"user id" "uid" 111111 "" ""
+"title" title 111111 "" ""
+END
+# Match types
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
+
+
+################################################################################
+# Authentication search configuration, used when editing an entry.
+#
+Auth
+internal
+"Authenticate As:"
+"(&(objectClass=person)"
+"dsgw-auth"
+not-used-by-dsgw
+not-used-by-dsgw
+subtree
+"common name" cn 111111 "" ""
+"surname" sn 111111 "" ""
+"phone number" "telephoneNumber" 111011 "" ""
+"e-mail address" "mail" 111111 "" ""
+"user id" "uid" 111111 "" ""
+"title" title 111111 "" ""
+END
+"is" "(%a=%v))"
+"is not" "(!(%a=%v)))"
+"sounds like" "(%a~=%v))"
+"starts with" "(%a=%v*))"
+"ends with" "(%a=*%v))"
+"contains" "(%a=*%v*))"
+END
diff --git a/ldap/clients/dsgw/pbconfig/edit-passwd.html b/ldap/clients/dsgw/pbconfig/edit-passwd.html
new file mode 100644
index 00000000..b4fff245
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/edit-passwd.html
@@ -0,0 +1,111 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<!-- HEAD -->
+<!-- change a directory entry's password -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Change Password -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0"
+>
+
+<table width="100%" class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width="100%" class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Person Entry</td>
+</tr>
+</table>
+
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="1" width="1" hspace="20" align="left" border="0">
+
+<TABLE width="90%" border="0" cellpadding="2" cellspacing="0" bgcolor="#FFFFFF">
+ <tr class="bgColor4">
+ <td width="10" nowrap >
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=32-person.gif" height="32" width="32" border="0" >
+ </td>
+
+ <td nowrap class="boldbig">
+ Change Password for
+<!-- DS_ATTRIBUTE "attr=cn" "syntax=cis" "options=readonly" -->
+ </td>
+
+ </tr>
+</TABLE>
+
+<P>
+<!-- DS_BEGIN_ENTRYFORM -->
+
+
+<TABLE>
+
+<!-- IF "BoundAsThisEntry" -->
+<TR>
+<TD ALIGN="right" NOWRAP>
+Enter the old password:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ELIF "!Bound" -->
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Enter the old password:
+</TD><TD>
+<!-- DS_OLDPASSWORD -->
+</TD></TR>
+<!-- ENDIF //BoundAsThisEntry -->
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Enter the new password:
+</TD><TD>
+<!-- DS_NEWPASSWORD -->
+</TD></TR>
+
+<TR>
+<TD ALIGN="right" NOWRAP>
+Enter the new password again to confirm:
+</TD><TD>
+<!-- DS_CONFIRM_NEWPASSWORD -->
+</TD></TR>
+</TABLE>
+
+<P>
+
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="1" width="1" hspace="20" align="left" border="0">
+
+<TABLE width="90%" border="0" cellpadding="2" cellspacing="0" bgcolor="#FFFFFF">
+ <tr class="bgColor4">
+ <td nowrap align="right">
+<!-- IF "BoundAsThisEntry" -->
+<!-- DS_SAVEBUTTON "label=Change Password" -->
+<!-- ELSE -->
+<!-- DS_SAVEBUTTON "label=Set Password" -->
+<!-- ENDIF -->
+
+<!-- DS_HELPBUTTON "topic=MODIFYPASSWD" -->
+ </td>
+ </tr>
+</TABLE>
+
+
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/pbconfig/list-Auth.html b/ldap/clients/dsgw/pbconfig/list-Auth.html
new file mode 100644
index 00000000..d3711e0d
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/list-Auth.html
@@ -0,0 +1,116 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- ---------------------------------------------------------------------------
+ | $Id: list-Auth.html,v 1.1 2005/01/21 00:40:49 cvsadm Exp $
+ |
+ | AUTHOR:
+ |
+ | SYNOPSIS:
+ | Display the vendor information.
+ |
+ | HISTORY:
+ |
+ |------------------------------------------------------------------------------ -->
+<!-- HEAD -->
+<TITLE>Authenticate as...</TITLE>
+
+<!--
+ The "authForm" form and the authSubmit() JavaScript function are
+ used to avoid the need for a separate form for each entry listed.
+ Each entry is tied to this single form through the magic of an
+ anchor that contains href=javascript:authSubmit().
+-->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</head>
+<body bgcolor="#FFFFFF" marginheight=0 marginwidth=0 leftmargin="0" topmargin="0" rightmargin="0">
+<table width=100% class="bgColor1" cellspacing="0" cellpadding="0" border="0">
+<tr width=100% class="bgColor1">
+<TD valign="top" class="bgColor1"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="45" border="0"></TD>
+<TD valign="middle" align="left" class="text15" width="100%">Authenticate as...</td>
+</tr>
+</table>
+<table cellspacing="0" cellpadding="0">
+<tr>
+<td><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="10" border="0"></td>
+</tr>
+</table>
+
+<FORM NAME="authForm" METHOD=POST ACTION="/clients/dsgw/bin/auth">
+<INPUT TYPE="hidden" NAME="escapedbinddn">
+<INPUT TYPE="hidden" NAME="authdesturl"
+<!-- DS_POSTEDVALUE "name=authdesturl" "within=VALUE=%22--value--%22" -->
+>
+<!-- PCONTEXT -->
+</FORM>
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+function authSubmit(encodeddn)
+{
+ document.authForm.escapedbinddn.value = encodeddn;
+ document.authForm.submit();
+}
+// End hiding -->
+</SCRIPT>
+
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="1" width="1" hspace="20" align="left" border="0">
+
+<TABLE width="90%" border="0" cellpadding="2" cellspacing="0" bgcolor="#FFFFFF">
+ <tr class="bgColor4">
+ <td nowrap align="right" class="boldbig">
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" height="32" width="1" border="0" >
+ </td>
+ </tr>
+</TABLE>
+<P>
+
+<CENTER>
+<!-- DS_SEARCHDESC "VERBOSE" -->
+<P>
+<!-- IF "FoundEntries" -->
+Please click on the name of the entry you would like to use for authentication.
+</P>
+<P>
+
+<TABLE BORDER=1 CELLPADDING=4>
+<TR>
+<TD NOWRAP class="boldbig">Authenticate As</td>
+<TD NOWRAP class="boldbig">Title</td>
+
+<!-- DS_SORTENTRIES -->
+
+<!-- DS_ENTRYBEGIN -->
+<TR>
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "href=javascript:authSubmit('--value--'); onMouseOver=%22window.status='Click to authenticate'; return true;%22" -->
+<TD NOWRAP>
+<!-- DS_ATTRIBUTE "attr=title" -->
+
+<!-- DS_ENTRYEND -->
+
+</TABLE>
+<!-- ELSE "FoundEntries" -->
+Please go back and try again.
+<!-- ENDIF "FoundEntries" -->
+</CENTER>
+
+<FORM>
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="1" width="1" hspace="20" align="left" border="0">
+
+<TABLE width="90%" border="0" cellpadding="2" cellspacing="0" bgcolor="#FFFFFF">
+ <tr class="bgColor4">
+ <td nowrap align="right" class="boldbig">
+ <INPUT TYPE="button" VALUE="Go Back" onClick="history.back();">
+<!-- DS_HELPBUTTON "topic=AUTHMULTMATCH" -->
+ </td>
+ </tr>
+</TABLE>
+
+</FORM>
+</body>
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/pbconfig/list-People.html b/ldap/clients/dsgw/pbconfig/list-People.html
new file mode 100644
index 00000000..71100da1
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/list-People.html
@@ -0,0 +1,125 @@
+<html>
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!-- HEAD -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+
+function showAimIcon(aimID, aimStatusText)
+{
+if (aimStatusText == "" || aimID == "" || aimStatusText != "ONLINE") {
+ return;
+}
+
+document.write('<a href=\"aim:goim?Screenname=' + aimID.replace(/ /,"+") + '\"><IMG SRC=\"lang?<!-- GCONTEXT -->&file=aim-online.gif\" ALT=\"Click to send an AIM to this person\" BORDER=0 HSPACE=5></a>');
+}
+// End hiding -->
+</SCRIPT>
+</head>
+
+<body bgcolor=white>
+
+<!-- single-pixel gif to enforce left alignment -->
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="1" width="1" hspace="20" align="left" border="0">
+
+<!-- IF "FoundEntries" -->
+
+<table width="85%" border="0" cellpadding="0" cellspacing="0" class="bgColor4" align="left">
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td bgcolor="white">
+<!-- DS_SEARCHDESC -->
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="#FFFFFF" align="center">
+ <tr align="left" class="bgColor4">
+ <td class="boldbig">
+ Name
+ </td>
+ <td class="boldbig">
+ ID
+ </td>
+ <td class="boldbig">
+ Phone
+ </td>
+ <td class="boldbig">
+ E-mail
+ </td>
+ <td class="boldbig">
+ AIM ID
+ </td>
+ <td class="boldbig">
+ Group
+ </td>
+ </tr>
+<!-- DS_SORTENTRIES "attr=cn" -->
+
+<!-- DS_ENTRYBEGIN -->
+ <tr valign="top" bgcolor="#FFFFFF">
+ <td >
+<!-- DS_ATTRIBUTE "attr=cn" "syntax=cis" -->
+ </td>
+ <td >
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "hrefextra=onMouseOver=%22%0Awindow.status='Click here to view this entry in detail'; return true%22" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" -->
+ </td>
+ <td >
+<!-- DS_ATTRIBUTE "attr=mail" "syntax=mail" -->
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=nsaimid" -->
+<SCRIPT LANGUAGE="JavaScript">
+<!-- Hide from non-JavaScript-capable browsers
+showAimIcon(
+<!-- DS_ATTRIBUTE "attr=nsaimid" "options=quoted" -->
+,
+""//<!-- DS_ATTRIBUTE "attr=nsaimstatustext" "options=quoted" -->
+);
+//// Uncomment the above DS_ATTRIBUTE directive and remove the double ////
+//// quotes to have aim presence in search results lists ////
+
+// End hiding -->
+</SCRIPT>
+ </td>
+ <td>
+<!-- DS_ATTRIBUTE "attr=ou" "syntax=cis"-->
+ </td>
+ </tr>
+ <tr>
+ <td colspan="5"></td>
+ </tr>
+<!-- DS_ENTRYEND -->
+
+</table>
+
+ </td>
+ </tr>
+ <tr bgcolor="#FFFFFF">
+ <td>
+ &nbsp;<br>
+ Click on an entry's ID to bring up more information about that entry.
+ </td>
+ </tr>
+</table>
+
+<!-- ELSE -->
+<p>
+ <center>
+ No entries match the requested search term. Please try a different search.
+ </center>
+</p>
+<!-- ENDIF -->
+
+<!-- ENDHTML -->
+
diff --git a/ldap/clients/dsgw/pbconfig/pb.tmpl b/ldap/clients/dsgw/pbconfig/pb.tmpl
new file mode 100644
index 00000000..57ec10d8
--- /dev/null
+++ b/ldap/clients/dsgw/pbconfig/pb.tmpl
@@ -0,0 +1,126 @@
+# The attribute the orgchart uses to search for entries.
+# This value should correspond to the value of attrib-farleft-rdn
+# in the orgchart's config.txt configuration file.
+orgchart-attrib-farleft-rdn uid
+
+# Check for Aim presence when the user's entry is displayed
+enable-aim-presence true
+
+# The htmldir directive tells the CGIs where to find the html files
+htmldir ../pbhtml
+
+# The configdir directive tells the CGIs where to find the
+# templates/configuration files
+configdir ../pbconfig
+
+# The gwnametrans directive tells the CGIs what url to output
+# for http redirection. It should be the same nameTrans set
+# in the webserver, if any is being is used.
+gwnametrans /clients/dsgw/pbhtml/
+
+# The authlifetime directive specifies how long authentication credentials
+# are valid (in seconds).
+authlifetime 7200
+
+# The libNLS data directory. This directory should contain a directory
+# named "locales", which contains the configuration files LANG.ctx and
+# LANG.txt for each supported language (locale).
+NLS ../../../lib/nls
+
+# The default character set, for communication with HTTP clients.
+# A client may override this default, using an HTTP Accept-Charset header.
+# Or, this default may be overridden for a specific language, by creating
+# a LANG/dsgwcharset.conf file which contains the charset name.
+# For compatibility with HTTP clients that can't handle an HTTP response
+# with a charset parameter in the content-type, comment out this directive;
+# responses will be sent in ISO-8859-1, with no explicit charset parameter.
+# RFC 1345 defines the syntax of charset names. There is a registry of
+# charsets, at ftp://ftp.isi.edu/in-notes/iana/assignments/character-sets
+# charset UTF-8
+
+# ignoreAcceptCharsetFrom [ <HTTP client version string> ]
+# where each of whose values is the version string (or part of the version
+# string) sent by an HTTP client which can't / doesn't want to handle UTF-8.
+# Charset from dsgwcharset.conf or charset directive is used (in the order).
+# ignoreAcceptCharsetFrom Mozilla/4.01x-NSCP Mozilla/3
+
+# Substitute ideographic space for non-breaking space in Asian charsets:
+changeHTML "&nbsp;&nbsp;" " " Shift_JIS Big5 EUC-KR EUC-JP
+changeHTML "&nbsp;" " " Shift_JIS Big5 EUC-KR EUC-JP
+
+# Mapping between config/display-XXX.html templates and LDAP objectClasses.
+# This can be generated by using ds/templateindex. The format is:
+#
+# template TEMPLATENAME OBJECTCLASSES
+#
+# where "display-TEMPLATENAME.html" is the name of a display template
+# that is found in this config directory (e.g., "display-group.html") and
+# OBJECTCLASSES is a list of one or more objectClass values. For a given
+# template to be used, all the objectClass values listed must be present
+# in the directory entry, so the order of these template lines is
+# significant (e.g. note that the more specific "orgperson" template is
+# listed before the one for an ordinary "person").
+#
+template orgunit organizationalUnit
+template room room
+template orgperson person inetOrgPerson
+
+
+#
+# The remainder of this file contains information about the locations and
+# types for new entries.
+#
+# "location" lines define places in the directory where new entries can be added
+# The format of each line is:
+# location HANDLE FRIENDLYNAME DN
+# where HANDLE is a short name which is used in the "newtype" lines (see below)
+# and FRIENDLYNAME is a human-readable name for the location
+# and DN is the Distinguished Name for this location (if it does not end with
+# '#', the location-suffix is appended to to construct a full DN; if it
+# does end with `#', it assumed to be a full DN and the `#' is removed).
+#
+location country "United States" "c=US#"
+location org "This Organization" ""
+location groups "Groups" "ou=Groups"
+location people "People" "ou=People"
+location special "Special Users" "ou=Special Users"
+
+# "newtype" lines define the types of new entries that may be added
+# The format of each line is:
+# newtype TEMPLATENAME FRIENDLYNAME RDNATTR LOCATIONS...
+# where TEMPLATENAME corresponds to an existing display-TEMPLATENAME.html file
+# and FRIENDLYNAME is a human-readable name for this type of entry
+# and RDNATTR is the attribute that is used to name entries of this type
+# and LOCATIONS is a blank-separated list of locations where these types of
+# entries can be added (corresponding to a HANDLE on a "location"
+# config. file line).
+#
+newtype orgperson "Person" uid people special
+newtype ntperson "NT Person" uid people special
+newtype ntgroup "NT Group" cn groups
+newtype groupun "Group" cn groups
+newtype orgunit "Organizational Unit" ou people org
+newtype org "Organization" o country
+
+# Mappings between VCard properties and LDAP attribute types:
+# The format of each line is:
+# vcard-property VCARDPROP SYNTAX LDAPATTR [LDAPATTR2]
+# where VCARDPROP is the name of a VCard property
+# and SYNTAX is "cis" for simple strings and "mls" for multiline strings
+# and LDAPATTR is the LDAP attribute that corresponds to VCARDPROP
+# and LDAPATTR2 is an optional secondary LDAP attribute which is added to
+# the property value by appending a semicolon and then the attr2 value.
+vcard-property FN cis cn
+vcard-property N cis sn givenName
+vcard-property ORG cis o ou
+vcard-property ROLE cis businessCategory
+vcard-property ADR;WORK mls postalAddress
+vcard-property ADR;HOME mls homePostalAddress
+vcard-property EMAIL;INTERNET cis mail
+vcard-property TITLE cis title
+vcard-property TEL;WORK cis telephoneNumber
+vcard-property TEL;FAX cis facsimileTelephoneNumber
+vcard-property TEL;CELL cis mobile
+vcard-property TEL;HOME cis homePhone
+vcard-property NOTE cis description
+
diff --git a/ldap/clients/dsgw/pbhtml/16-conference.gif b/ldap/clients/dsgw/pbhtml/16-conference.gif
new file mode 100644
index 00000000..57b9bfdf
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/16-conference.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/16-person.gif b/ldap/clients/dsgw/pbhtml/16-person.gif
new file mode 100644
index 00000000..456e9b2a
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/16-person.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/32-alert.gif b/ldap/clients/dsgw/pbhtml/32-alert.gif
new file mode 100644
index 00000000..453d1b2b
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/32-alert.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/32-conference.gif b/ldap/clients/dsgw/pbhtml/32-conference.gif
new file mode 100644
index 00000000..2c0d72e1
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/32-conference.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/32-message.gif b/ldap/clients/dsgw/pbhtml/32-message.gif
new file mode 100644
index 00000000..e46c67a0
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/32-message.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/32-office.gif b/ldap/clients/dsgw/pbhtml/32-office.gif
new file mode 100644
index 00000000..0e3591fa
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/32-office.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/32-person.gif b/ldap/clients/dsgw/pbhtml/32-person.gif
new file mode 100644
index 00000000..93439d0c
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/32-person.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/Makefile b/ldap/clients/dsgw/pbhtml/Makefile
new file mode 100644
index 00000000..38b4807f
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/Makefile
@@ -0,0 +1,53 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# Gmakefile for Directory Server Phonebook html files.
+# 1/21/98 - RJP
+#
+
+LDAP_SRC = ../../..
+MCOM_ROOT = ../../../../..
+
+NOSTDSTRIP=true # don't let nsconfig.mak define target strip
+NOSTDCLEAN=true # don't let nsconfig.mak define target clean
+NOSTDDEPEND=true # don't let nsconfig.mak define target depend
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+include ../dsgw_include.mk
+
+HTMLDEST = $(DSGW_PBHTML_RELDIR)
+
+HTML= emptyFrame.html index.html 16-conference.gif \
+ office.gif report.html 16-person.gif conference.gif \
+ pbrd.jpg department.gif person.gif clear.gif \
+ vendor.gif style.css intro.html phone.html view_vcard.gif \
+ phone.js view_vcard_sm.gif \
+ brandblock.gif get_cert.gif \
+ carded.html get_cert_sm.gif pixel.gif \
+ 32-office.gif 32-alert.gif 32-conference.gif 32-person.gif \
+ 32-message.gif nullStringError.html tiny_cert.gif \
+ tiny_vcard.gif confirm.html alert.html orgicon.gif aim-online.gif
+
+BINS=$(addprefix $(HTMLDEST)/,$(HTML))
+
+include $(MCOM_ROOT)/ldapserver/config/webint.mk
+
+all: $(HTMLDEST) $(BINS)
+
+install: $(HTMLDEST) $(BINS)
+
+clean:
+ $(RM) $(BINS)
+
+$(HTMLDEST)/%: %
+ @-$(RM) $@
+ cp $< $@
+
+strip:
+depend:
diff --git a/ldap/clients/dsgw/pbhtml/aim-online.gif b/ldap/clients/dsgw/pbhtml/aim-online.gif
new file mode 100644
index 00000000..b364017e
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/aim-online.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/alert.html b/ldap/clients/dsgw/pbhtml/alert.html
new file mode 100644
index 00000000..c5afda96
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/alert.html
@@ -0,0 +1,24 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+<!-- DS_POSTEDVALUE "NAME=TITLE" -->
+</title>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<BODY onLoad="document.OK.btn.focus();" bgcolor="#CCCCCC">
+<TABLE cols=2 width="100%"><TR VALIGN=CENTER>
+<TD ALIGN=CENTER WIDTH=32><IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=32-alert.gif" HEIGHT=32 WIDTH=32 BORDER="0" ALT="Alert"></TD>
+<TD>
+<!-- DS_POSTEDVALUE "NAME=MSG" -->
+</TD></TR></TABLE>
+<FORM NAME=OK><CENTER>
+<!-- DS_CLOSEBUTTON "NAME=btn" "LABEL= OK " -->
+</CENTER></FORM>
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/pbhtml/brandblock.gif b/ldap/clients/dsgw/pbhtml/brandblock.gif
new file mode 100644
index 00000000..4cfea04f
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/brandblock.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/carded.html b/ldap/clients/dsgw/pbhtml/carded.html
new file mode 100644
index 00000000..f26f7409
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/carded.html
@@ -0,0 +1,44 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+ <head>
+ <title>vCard</title>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+ </head>
+
+<script language=javascript>
+
+function autoCloser(){
+
+var closeHTML=
+'<body bgcolor="#CCCCCC">\n' +
+'<center>\n' +
+'<form name=adios>\n' +
+'<font face="primasans bt,verdana,arial,helvetica,sans-serif" size="-1">\n' +
+'<input type=button value="Close Window" onclick="window.parent.close()">\n' +
+'</font>\n' +
+'</form>\n' +
+'</center>\n' +
+'</body></html>';
+
+self.closer.document.write(closeHTML);
+
+}
+
+
+function init(){
+autoCloser();
+}
+
+</script>
+
+<frameset rows="200,50" border="0" onload="init();">
+ <frame name="cards" src="javascript:parent.emptyFrame" scrolling="AUTO">
+ <frame name="closer" src="javascript:parent.emptyFrame" scrolling="NO">
+</frameset>
+
+</html>
diff --git a/ldap/clients/dsgw/pbhtml/clear.gif b/ldap/clients/dsgw/pbhtml/clear.gif
new file mode 100644
index 00000000..35d42e80
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/clear.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/conference.gif b/ldap/clients/dsgw/pbhtml/conference.gif
new file mode 100644
index 00000000..ce0222d0
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/conference.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/confirm.html b/ldap/clients/dsgw/pbhtml/confirm.html
new file mode 100644
index 00000000..3d418e78
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/confirm.html
@@ -0,0 +1,30 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<TITLE>
+<!-- DS_POSTEDVALUE "NAME=TITLE" -->
+</TITLE>
+<!-- DS_CONFIRM_SCRIPT -->
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</HEAD>
+
+<BODY>
+<TABLE COLS=2 WIDTH="100%"><TR VALIGN=CENTER>
+<TD ALIGN=CENTER WIDTH=36><IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=32-alert.gif" HEIGHT=32 WIDTH=32 BORDER="0" ALT="Confirm"></TD><TD>
+<!-- DS_POSTEDVALUE "NAME=MSG" -->
+</TD></TR></TABLE>
+<FORM><TABLE COLS=4 WIDTH="100%"><TR ALIGN=CENTER>
+<TD></TD>
+<TD>
+<!-- DS_CONFIRM_BUTTON_OK -->
+</TD><TD>
+<!-- DS_CONFIRM_BUTTON_CANCEL -->
+</TD>
+<TD></TD>
+</TR></TABLE></FORM>
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/pbhtml/department.gif b/ldap/clients/dsgw/pbhtml/department.gif
new file mode 100644
index 00000000..2d0b1535
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/department.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/emptyFrame.html b/ldap/clients/dsgw/pbhtml/emptyFrame.html
new file mode 100644
index 00000000..627efdfb
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/emptyFrame.html
@@ -0,0 +1,7 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><BODY BGCOLOR="white"></BODY></HTML>
diff --git a/ldap/clients/dsgw/pbhtml/get_cert.gif b/ldap/clients/dsgw/pbhtml/get_cert.gif
new file mode 100644
index 00000000..9f08a221
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/get_cert.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/get_cert_sm.gif b/ldap/clients/dsgw/pbhtml/get_cert_sm.gif
new file mode 100644
index 00000000..c0c76885
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/get_cert_sm.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/index.html b/ldap/clients/dsgw/pbhtml/index.html
new file mode 100644
index 00000000..b97706d6
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/index.html
@@ -0,0 +1,41 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+<head>
+<meta
+ name="keywords"
+ content="Netscape server product, Directory Server 6.2, LDAP Corporate Directory"
+>
+<meta name="description" content="Netscape Directory Express:
+ A Searchable Index of People and Resources for your enterprise.">
+<meta name="keywords" content="phonebook, directory, express, search, enterprise, people, users, conference rooms, spooky!">
+<title>Netscape Directory Express</title>
+
+</head>
+
+<frameset rows="50,*" frameborder="no" border="0" framespacing="0">
+ <frame
+ src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=phone.html"
+ name="buttonBarFrame"
+ marginwidth="0"
+ marginheight="0"
+ scrolling="no"
+ >
+ <frame
+ src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=intro.html"
+ name="resultframe"
+ marginwidth="10"
+ marginheight="10"
+ scrolling="auto"
+ >
+</frameset>
+<noframe>
+<body>
+
+</body>
+</noframe>
+</html>
diff --git a/ldap/clients/dsgw/pbhtml/intro.html b/ldap/clients/dsgw/pbhtml/intro.html
new file mode 100644
index 00000000..0d4ff66b
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/intro.html
@@ -0,0 +1,207 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+<head>
+<title>Netscape Directory Express</title>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</head>
+
+<body bgcolor="#FFFFFF">
+
+<!-- single-pixel gif to enforce left alignment -->
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="0" width="0" hspace="20" align="left" border="0">
+
+<table border="0" cellpadding="0" cellspacing="0" width="90%" align="left">
+ <tr>
+ <td colspan=5 align="left">
+ <p>
+ &nbsp;<br>
+ <span class="text31"><B>About Directory Express</B></span>
+ <br>&nbsp;
+ </p>
+ </td>
+ </tr>
+ <tr>
+ <td colspan=5 align="left">
+ Directory Express displays people, conference rooms, buildings and branch offices.
+ If multiple entries are found, the results are displayed in a table:
+ </td>
+ </tr>
+ <tr>
+ <td>
+ &nbsp;
+ </td>
+ </tr>
+</table>
+
+<br clear="ALL">
+
+<!-- single-pixel gif to enforce left alignment -->
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="0" width="0" hspace="20" align="left" border="0">
+
+
+<table width="90%" border="0" cellpadding="0" cellspacing="0" bgcolor="#CCCCCC" align="left">
+ <tr valign="top">
+ <td align="left" bgcolor="#FFFFFF">
+ Found <b>x</b> entries where the name or user ID matches '<b>your search</b>'.
+ <br>&nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td>
+<!-- ------------------------------------------------------------- -->
+<table border="0" cellpadding="1" cellspacing="0" width="100%" bgcolor="white">
+ <tr align="left" class="bgColor4">
+ <td class="bgColor4">
+ &nbsp;
+ </td>
+ <td nowrap class="bgColor4">
+ <b>Name</b>
+ </td>
+ <td nowrap class="bgColor4">
+ <b>ID</b>
+ </td>
+ <td nowrap class="bgColor4">
+ <b>Phone</b>
+ </td>
+ <td nowrap class="bgColor4">
+ <b>E-mail</b>
+ </td>
+ <td nowrap class="bgColor4">
+ <b>Group</b>
+ </td>
+ </tr>
+ <tr align="left">
+ <td width="10">
+ <a href="javascript:void(0)" onMouseOver="top.status='This entry is a person.'; return true" name="Person"><img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=16-person.gif" height="16" width="16" vspace="3" border="0"></a>
+ </td>
+ <td nowrap>
+ Jane Castle
+ </td>
+ <td nowrap>
+ <a href="javascript:void(0)" onMouseOver="top.status='Click the entry\'s ID to view the entire record.'; return true">jane</a>
+ </td>
+ <td nowrap>
+ 4444
+ </td>
+ <td nowrap>
+ <a href="javascript:void(0)" onMouseOver="top.status='Click the entry\'s Email address to send a message.'; return true">jane@example.com</a>
+ </td>
+ <td nowrap>
+ engineering
+ </td>
+ </tr>
+ <tr>
+ <td colspan="6"></td>
+ </tr>
+ <tr align="left" bgcolor="#FFFFFF">
+ <td width="10">
+ <a href="javascript:void(0)" onMouseOver="top.status='This entry is a person.'; return true" name="Person"><img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=16-person.gif" height="16" width="16" vspace="3" border="0"></a>
+ </td>
+ <td nowrap>
+ John Castle
+ </td>
+ <td nowrap>
+ <a href="javascript:void(0)" onMouseOver="top.status='Click the entry\'s ID to view the entire record.'; return true">john</a>
+ </td>
+ <td nowrap>
+ 5555
+ </td>
+ <td nowrap>
+ <a href="javascript:void(0)" onMouseOver="top.status='Click the entry\'s Email address to send a message.'; return true">john@example.com</a>
+ </td>
+ <td nowrap>
+ marketing
+ </td>
+ </tr>
+ <tr>
+ <td colspan="6"></td>
+ </tr>
+ <tr align="left" bgcolor="#FFFFFF">
+ <td width="10">
+ <a href="javascript:void(0)" onMouseOver="top.status='This entry is a conference room.'; return true" name="Conference Room"><img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=16-conference.gif" height="16" width="16" vspace="3" border="0"></a>
+ </td>
+ <td nowrap>
+ King's Castle
+ </td>
+ <td nowrap>
+ <a href="javascript:void(0)" onMouseOver="top.status='Click the entry\'s ID to view the entire record.'; return true">King's Castle</a>
+ </td>
+ <td nowrap>
+ 2121
+ </td>
+ <td nowrap>
+ &nbsp;
+ </td>
+ <td nowrap>
+ &nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td colspan="6"></td>
+ </tr> <tr align="left" bgcolor="#FFFFFF">
+ <td width="10">
+ <a href="javascript:void(0)" onMouseOver="top.status='This entry is a person.'; return true" name="Person"><img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=16-person.gif" height="16" width="16" vspace="3" border="0"></a>
+ </td>
+ <td nowrap>
+ Quincy Castlegate
+ </td>
+ <td nowrap>
+ <a href="javascript:void(0)" onMouseOver="top.status='Click the entry\'s ID to view the entire record.'; return true">quincy</a>
+ </td>
+ <td nowrap>
+ 7777
+ </td>
+ <td nowrap>
+ <a href="javascript:void(0)" onMouseOver="top.status='Click the entry\'s Email address to send a message.'; return true">quincy@example.com</a>
+ </td>
+ <td nowrap>
+ product development
+ </td>
+ </tr>
+ <tr>
+ <td colspan="6"></td>
+ </tr>
+</table>
+<!-- ------------------------------------------------------------- -->
+ </td>
+ </tr>
+ <tr align="left" bgcolor="#FFFFFF">
+ <td bgcolor="white" align="left">
+ &nbsp;<br>
+ Click on an entry's ID to bring up more information about that entry.
+ </td>
+ </tr>
+</table>
+
+<br clear="ALL">
+
+<!-- single-pixel gif to enforce left alignment -->
+<img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=pixel.gif" height="0" width="0" hspace="20" align="left" border="0">
+
+<table border="0" cellpadding="0" cellspacing="0" width="90%" align="left">
+ <tr>
+ <td>
+ &nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td colspan=5 bgcolor="white" align="left">
+ If a single, unique entry is found, all information pertaining to that entry is
+ displayed. Users can edit portions of their personal information by displaying
+ their information as described above, and clicking the &quot;Edit Person&quot;
+ button at the bottom of the their entry.
+ </td>
+ </tr>
+</table>
+
+</body>
+</html>
+
+
+
+
diff --git a/ldap/clients/dsgw/pbhtml/modify.html b/ldap/clients/dsgw/pbhtml/modify.html
new file mode 100644
index 00000000..a44c18b5
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/modify.html
@@ -0,0 +1,292 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!--
+ | $Id: modify.html,v 1.1 2005/01/21 00:40:49 cvsadm Exp $
+ |
+ | AUTHOR:
+ |
+ | SYNOPSIS:
+ | User instructions for using Directory Express, and misc. links for
+ | Directory Express usage.
+ |
+ | HISTORY:
+ |
+ +-------------------------------------------------------------------------- -->
+
+<HTML>
+<HEAD>
+<TITLE>
+Directory Express
+</TITLE></HEAD>
+
+<BODY bgcolor=WHITE>
+
+
+<CENTER>
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=80% BGCOLOR=#F2F2F2>
+<TR>
+<TD COLSPAN=2 BGCOLOR=TEAL ALIGN=CENTER><FONT SIZE=+1 COLOR=WHITE FACE=ARIAL, HELVETICA>
+LEGEND
+</FONT>
+
+
+<TR>
+ <TD> User-editable</TD>
+ <TD> Users can edit their own information.</TD>
+</TR>
+<TR>
+ <TD> Administrator</TD>
+ <TD> Email changes to the Directory Express Administrator team.</TD>
+</TR>
+<TR>
+ <TD> Help Request</TD>
+ <TD> Fill out an online Help Request.</TD>
+</TR>
+<TR>
+ <TD> Call Helpdesk 555-1111</TD>
+ <TD> Please don't call between 10-12, and 2-4 Pacific Time</TD>
+</TR>
+<TR>
+ <TD> PeopleSoft Form- <B>Employees</B></TD>
+ <TD> Legal Name changes: Use the online Change of Employee Information form.
+<HR>
+ All others: Download the Employee Change Sheet, print it, fill it out and give it to your divisional HR representative.</TD>
+</TR>
+<TR>
+ <TD>Special Email- <B>Vendors, Services, and Other Contractors</B></TD>
+ <TD>The conditions of your contract determine who gets your Email request.</TD>
+</TR>
+</TABLE>
+<P>
+
+
+
+</CENTER>
+
+<HR>
+<TABLE><TR><TD>
+<IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=person.gif" ALT="Person" HSPACE=5>
+</TD><TD><FONT SIZE="+2">
+Your Name Here</FONT></TD>
+<TD VALIGN=BOTTOM></TD>
+</TR>
+</TABLE>
+
+</CENTER>
+
+<TABLE BORDER BGCOLOR=#f2f2f2 WIDTH=575>
+<TR>
+<TD BGCOLOR=TEAL COLSPAN=4><FONT SIZE=+1 FACE=ARIAL,HELVETICA COLOR=WHITE>Contact Information</TD></TR>
+
+
+<TR>
+<TD VALIGN="TOP">Phone:</TD>
+<TD VALIGN="TOP" NOWRAP><FONT COLOR="blueviolet"><B>
+<A href="mailto:administrator@example.com?subject=Please update my phone number">Administrator</A>
+</B></FONT></TD>
+
+<TD VALIGN="TOP" NOWRAP>E-Mail Address:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<A HREF=/clients/dsgw/pbhtml/emptyFrame.html>Help Request</A>
+</TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP" NOWRAP>User ID:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+<A HREF=/clients/dsgw/pbhtml/emptyFrame.html>Help Request</A>
+</B></TD>
+
+<TD VALIGN="TOP">Mailstop:
+</TD>
+<TD VALIGN="TOP"><B>
+<A href="mailto:administrator@example.com?subject=Please update my phone number">Administrator</A>
+</B></TD>
+</TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>First Name:</TD>
+<TD VALIGN="top" NOWRAP><B>
+Call Helpdesk 555-1111
+</B></TD>
+
+<TD VALIGN="TOP" NOWRAP>Pager:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+User-editable
+</B></TD>
+</TR>
+
+<TR>
+<TD VALIGN="top" NOWRAP>Last Name:
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+Call Helpdesk 555-1111
+</B></TD>
+
+
+
+<TD VALIGN="TOP" NOWRAP>Legal Name:</TD>
+<TD VALIGN="top"><B>Employees:
+<A HREF=/clients/dsgw/pbhtml/emptyFrame.html onClick="alert('Note: Please use the HR form to update your Legal Name ONLY.')"> PeopleSoft
+Form</A><BR>Vendors, Services, and Other Contractors: <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=nonemp.html">Special Email
+</A>
+</B></TD>
+</TR>
+
+
+<TR>
+<TD VALIGN="top" NOWRAP>Home Phone: <BR>(optional)
+</TD>
+<TD VALIGN="top" NOWRAP><B>
+User-editable
+</B></TD>
+
+<TD VALIGN="TOP" NOWRAP>Mobile Phone:<TD VALIGN="TOP" NOWRAP><B>
+User-editable
+</B></TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Fax:</TD>
+<TD VALIGN="TOP" NOWRAP><B>
+User-editable
+</B></TD>
+
+</TR>
+
+</TABLE>
+
+
+
+
+<P>
+<P>
+
+<TABLE BORDER BGCOLOR=#f2f2f2 WIDTH=575>
+<TR>
+<TD BGCOLOR=TEAL COLSPAN=4><FONT SIZE=+1 FACE=ARIAL,HELVETICA COLOR=WHITE>Location Information</FONT></TD></TR>
+<TR>
+<TD VALIGN="TOP">Mailing Address:</TD>
+<TD VALIGN="TOP" NOWRAP COLSPAN=3><B><A href="mailto:administrator@example.com?subject=Please update my mailing address">Administrator</A></B></TD></TR>
+<TR>
+<TD VALIGN="TOP" NOWRAP>Building #:</TD>
+<TD VALIGN="TOP"><B><A href="mailto:administrator@example.com?subject=Please update my building number">Administrator</A></B></TD>
+<TD VALIGN="TOP" NOWRAP>Building Level:</TD>
+<TD VALIGN="TOP"><B><A href="mailto:administrator@example.com?subject=Please update my building level">Administrator</A></B></TD>
+</TR>
+<TR>
+<TD VALIGN="TOP">Physical Location: </TD>
+<TD VALIGN="TOP" COLSPAN=3><B><A href="mailto:administrator@example.com?subject=Please update my physical location">Administrator</A></B></TD></TR>
+</TABLE>
+
+<P>
+<P>
+
+<TABLE BORDER BGCOLOR=#f2f2f2 WIDTH=575>
+<TR>
+<TD BGCOLOR=TEAL COLSPAN=4><FONT SIZE=+1 FACE=ARIAL,HELVETICA COLOR=WHITE>Business Information</FONT></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Business Category:</TD>
+<TD VALIGN="TOP"><B>Employees:<A HREF=/clients/dsgw/pbhtml/emptyFrame.html>PeopleSoft Form</A><BR>Vendors, Services, and Other Contractors: <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=nonemp.html">Special Email</A></B></TD>
+<TD VALIGN="TOP">Title:</TD>
+<TD VALIGN="TOP"><B>Employees:<A HREF=/clients/dsgw/pbhtml/emptyFrame.html>PeopleSoft Form</A><BR>Vendors, Services, and Other Contractors: <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=nonemp.html">Special Email</A></B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Organizational Unit:</TD>
+<TD VALIGN="TOP"><B>Employees:<A HREF=/clients/dsgw/pbhtml/emptyFrame.html>PeopleSoft Form</A><BR>Vendors, Services, and Other Contractors <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=nonemp.html">Special Email</A></B></TD>
+<TD VALIGN="TOP">Manager:</TD>
+<TD VALIGN="TOP"><B>Employees:<A HREF=/clients/dsgw/pbhtml/emptyFrame.html>PeopleSoft Form</A><BR><B>Vendors, Services, and Other Contractors: <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=nonemp.html">Special Email</A></B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Cube #:</TD>
+<TD VALIGN="TOP" NOWRAP"><B><A href="mailto:administrator@example.com?subject=Please update my cube number">Administrator</A></B></TD>
+</B><TD VALIGN="TOP">Admin.:</TD>
+<TD VALIGN="TOP" NOWRAP><B><A href="mailto:administrator@example.com?subject=Please update my admin">Administrator</A></B></TD></TR>
+
+
+<TR>
+<TD VALIGN="TOP">Dept#:</TD>
+<TD VALIGN="TOP"><B>Employees:<A HREF=/clients/dsgw/pbhtml/emptyFrame.html>PeopleSoft Form</A><BR>Vendors, Services, and Other Contractors: <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=nonemp.html">Special Email</A></B></TD>
+<TD VALIGN="TOP" BGCOLOR=teal><FONT COLOR=lightyellow><B>Employee Status:</B></FONT></TD>
+<TD VALIGN="TOP"><B>Employees:<A HREF=/clients/dsgw/pbhtml/emptyFrame.html>PeopleSoft Form</A><BR>Vendors, Services, and Other Contractors: <A href="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&nonemp.html">Special Email</A></B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Vehicle License#:</TD>
+<TD VALIGN="TOP"><B>User-editable</B></TD>
+
+<TD VALIGN="TOP">Current Contact Info.</TD>
+<TD VALIGN="TOP"><B>User-editable</B></TD>
+</TR>
+
+</TABLE>
+
+
+<P>
+<P>
+<TABLE BORDER BGCOLOR=#f2f2f2 WIDTH=575>
+
+<TR>
+<TD BGCOLOR=TEAL COLSPAN=2><FONT SIZE=+1 FACE=ARIAL,HELVETICA COLOR=WHITE>Additional Information</FONT></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">Description:</TD>
+<TD VALIGN="TOP" NOWRAP><B>User-editable</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">See Also:</TD>
+<TD VALIGN="TOP" NOWRAP><B>User-editable</B></TD></TR>
+
+<TR>
+<TD VALIGN="TOP">URL:</TD>
+<TD VALIGN="TOP" NOWRAP><B>User-editable</B></TD></TR>
+
+</TABLE>
+
+<P>
+<P>
+<TABLE BORDER BGCOLOR=#f2f2f2 WIDTH=575>
+<TR>
+<TD BGCOLOR=TEAL COLSPAN=4><FONT SIZE=+1 FACE=ARIAL,HELVETICA COLOR=WHITE>Mail Information</FONT></TD></TR>
+<TR>
+<TD VALIGN="TOP">Mail Server:
+</TD>
+<TD VALIGN="TOP"><B><A HREF=/clients/dsgw/pbhtml/emptyFrame.html>Help Request</A></B></TD>
+<TD VALIGN="TOP">Mail Addresses:</TD>
+<TD VALIGN="TOP"><B><A HREF=/clients/dsgw/pbhtml/emptyFrame.html>Help Request</A></B></TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Autoreply mode:</TD>
+<TD VALIGN="TOP" NOWRAP><B>User-editable</B></TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Autoreply Text:</TD>
+<TD VALIGN="TOP" COLSPAN=3><B>User-editable</B></TD>
+</TR>
+
+<TR>
+<TD VALIGN="TOP">Mail Delivery Option:
+</TD>
+<TD VALIGN="TOP"><B>User-editable</B></TD>
+
+<TD VALIGN="TOP">Forwarding Addresses:</TD>
+<TD VALIGN="TOP"><B>User-editable</B></TD>
+</TR>
+</TABLE>
+
+<P>
+<P>
+
+
+
+
+
+</FORM>
+
+</BODY></HTML>
diff --git a/ldap/clients/dsgw/pbhtml/nonemp.html b/ldap/clients/dsgw/pbhtml/nonemp.html
new file mode 100644
index 00000000..dfd156a8
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/nonemp.html
@@ -0,0 +1,69 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!--
+ | $Id: nonemp.html,v 1.1 2005/01/21 00:40:49 cvsadm Exp $
+ |
+ | AUTHOR:
+ |
+ | SYNOPSIS:
+ | User instructions for using Directory Express, and misc. links for
+ | Directory Express usage.
+ |
+ | HISTORY:
+ |
+ +-------------------------------------------------------------------------- -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+
+<HTML>
+<HEAD>
+ <TITLE>Non-employee Directory Express Changes</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="White">
+
+<CENTER>
+<H2>Non-employee Directory Express Changes</H2>
+</CENTER>
+
+<P>Send your change requests to the person that matches your affiliation.</P>
+
+
+<TABLE BORDER=1 CELLPADDING=4 WIDTH=80% BGCOLOR=#F2F2F2>
+<TR>
+<TD COLSPAN=2 BGCOLOR=TEAL ALIGN=CENTER><FONT SIZE=+1 COLOR=WHITE FACE=ARIAL, HELVETICA>
+The Amazing Non-employee Request Director
+</FONT>
+
+<TR>
+ <TH>Your Affiliation:</TH>
+ <TH>Send Requests to:</TH>
+</TR>
+
+<TR>
+ <TD>Independent Contractor</TD>
+ <TD><A HREF="mailto:administrator@example.com?subject=Please modify my Directory Express information">Christina Champagne</A></TD>
+</TR>
+
+<TR>
+ <TD>Interim Temporary</TD>
+ <TD><B>Administrative</B> Temps. or Contractors contact <A
+ HREF="mailto:administrator@example.com?subject=Please modify my Directory Express
+ information">Lisa Holcomb</A><BR>
+ <B>Technical</B> Temps. or Contractors contact <A
+ HREF="mailto:administrator@example.com?subject=Please modify my
+ Directory Express information">Lisa Livingston</A</TD>
+</TR>
+
+<TR>
+ <TD>Vendors & Services</TD>
+ <TD><A HREF="mailto:administrator@example.com?subject=Please modify my Directory Express information">Andrea Kimerer</A></TD>
+</TR>
+
+</TABLE>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/pbhtml/nullStringError.html b/ldap/clients/dsgw/pbhtml/nullStringError.html
new file mode 100644
index 00000000..0aefa11f
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/nullStringError.html
@@ -0,0 +1,64 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+<head>
+<title>Error!</title>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</head>
+<body bgcolor="white">
+
+<p>
+ &nbsp;
+</p>
+<table width="360" border="1" bgcolor="#CCCCCC" align="center">
+ <tr>
+ <td>
+
+<table border="0" cellpadding="18" cellspacing="0">
+ <tr>
+ <td>
+ <center>
+
+ <table border="0">
+ <tr>
+ <td>
+ <img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=32-alert.gif" height="32" width="32" border="0">
+ </td>
+ <td>
+ &nbsp;
+ </td>
+ <td>
+ No search term entered.
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ &nbsp;
+ </td>
+ </tr>
+ <tr>
+ <td colspan="2">
+ &nbsp;
+ </td>
+ <td>
+ Directory Express searches against an entry's name, user ID, and phone extension.
+ Please enter a search term and try again.
+ </td>
+ </tr>
+ </table>
+
+ </center>
+ </td>
+ </tr>
+</table>
+
+ </td>
+ </tr>
+</table>
+
+</body>
+</html>
diff --git a/ldap/clients/dsgw/pbhtml/office.gif b/ldap/clients/dsgw/pbhtml/office.gif
new file mode 100644
index 00000000..558ba18d
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/office.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/orgicon.gif b/ldap/clients/dsgw/pbhtml/orgicon.gif
new file mode 100644
index 00000000..034f2c20
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/orgicon.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/pbrd.jpg b/ldap/clients/dsgw/pbhtml/pbrd.jpg
new file mode 100644
index 00000000..ab92e6e0
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/pbrd.jpg
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/person.gif b/ldap/clients/dsgw/pbhtml/person.gif
new file mode 100644
index 00000000..671869cb
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/person.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/phone.html b/ldap/clients/dsgw/pbhtml/phone.html
new file mode 100644
index 00000000..a9f49612
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/phone.html
@@ -0,0 +1,87 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<html>
+<head>
+<meta http-equiv="content-type" content="text/html;charset=utf-8">
+<title>Netscape Directory Express</title>
+
+<script language="javascript">
+//<!--
+
+function gotourl(i){
+window.location.href=i;
+}
+
+//-->
+</script>
+<script language="javascript" src="/clients/dsgw/pbhtml/phone.js">
+</script>
+<LINK REL=stylesheet TYPE="text/css" HREF="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=style.css">
+</head>
+
+<body class="Search" onLoad="fieldFocus();" marginwidth="0" marginheight="0" leftmargin="0" topmargin="0">
+
+<form method="post" name="searchform" target="resultframe" action="/clients/dsgw/bin/dosearch" onSubmit="return checkForNullString()">
+
+ <!-- hidden fields: edit these to customize your Directory Express. -->
+ <input type=hidden name="type" value="people">
+ <input type=hidden name="mode" value="smart">
+ <input type=hidden name="querytype" value="people">
+<!-- PCONTEXT -->
+
+<table BORDER="0" width="100%" cellpadding=0 cellspacing=0>
+
+<TR>
+<TD valign="top" colspan="5" width="100%"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="5" border="0"></TD>
+</TR>
+
+<tr>
+<td>
+<IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="10" height="37" border="0">
+</td>
+<TD ALIGN=LEFT VALIGN=CENTER nowrap>
+<a href="javascript:alert('Powered by Netscape Directory Server 6.2')" onMouseOver="window.status='Click for more information about Netscape Directory Express.'; return true"><img src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=brandblock.gif" border="0" align="left"></a></td>
+<TD valign="top"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="7" height="1" border="0"></TD>
+<TD valign="top" class="appName" nowrap>Netscape Directory Express</td>
+<TD ALIGN=LEFT width="75%">
+ <TABLE BORDER=0>
+ <TR>
+ <TD valign="top"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="15" height="1" border="0"></TD>
+ <TD nowrap VALIGN=CENTER ALIGN=CENTER>
+ <span class="apptext">Search for:</span>
+ </TD>
+ <TD nowrap VALIGN=CENTER>
+ <span class="apptext">
+ <font face=\"verdana, Arial, Helvetica, sans-serif\" style=\"font-size: 12px\">
+ <input type="text" name="searchstring" size=30>
+ <input type="submit" value="Search" name="submitbutton">
+ </font>
+ </span>
+ </TD>
+ </TR></TABLE>
+ </TD>
+</tr>
+
+<!-- TR>
+<td></td>
+<td></td>
+<td align=left class="text30">(Enter any part of a name, user ID, or phone number)
+</td></tr -->
+
+<TR>
+<TD valign="top" colspan="5" width="100%"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" width="1" height="5" border="0"></TD>
+</TR>
+
+<TR>
+<TD width="100%" colspan="5" class="bgColor7"><IMG src="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&file=clear.gif" height="1" border="0"></TD>
+</TR>
+
+</table>
+</form>
+</body>
+</html>
+
diff --git a/ldap/clients/dsgw/pbhtml/phone.js b/ldap/clients/dsgw/pbhtml/phone.js
new file mode 100755
index 00000000..f51d06dc
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/phone.js
@@ -0,0 +1,43 @@
+//
+// PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+// license terms. Copyright © 2001 Sun Microsystems, Inc.
+// Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+// all rights reserved.
+//
+function goToURL(i){
+window.location.href=i;
+}
+
+function easter(){
+if (document.forms[0].searchstring.value=='worker and parasite'){
+ window.open ("worker.qt","worker","scrollbars=no,menubar=no,resizable=no,width=300,height=300");
+ }
+}
+
+function flipImg(currImg,newImg) {
+ document.images[currImg].src = newImg;
+}
+
+function phoneTeam (){
+
+ window.open ("team.html","rah_team","scrollbars=no,menubar=no,resizable=yes,width=500,height=500");
+
+}
+
+function fieldFocus(){
+setTimeout("document.forms[0].searchstring.focus()",400);
+}
+
+function checkForNullString(){
+if (document.forms[0].searchstring.value != "")
+ {
+ return true;
+ }
+else
+ {
+ parent.resultframe.location="/dsgw/bin/lang?context=pb&file=nullStringError.html";
+ return false;
+ }
+}
+
+
diff --git a/ldap/clients/dsgw/pbhtml/pixel.gif b/ldap/clients/dsgw/pbhtml/pixel.gif
new file mode 100644
index 00000000..e66849ac
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/pixel.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/report.html b/ldap/clients/dsgw/pbhtml/report.html
new file mode 100644
index 00000000..0c5a35b2
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/report.html
@@ -0,0 +1,155 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
+<HTML>
+<HEAD>
+ <TITLE>Netscape Telephone Book: Reports</TITLE>
+ <META NAME="GENERATOR" CONTENT="User-Agent: Mozilla/3.01Gold-C (Macintosh; U; PPC)">
+</HEAD>
+<BODY TEXT="#0B0547" BGCOLOR="#FFFFFF" LINK="#0000FF" VLINK="#551A8B" ALINK="#0000FF">
+
+<CENTER><P><FORM method="GET" action="/clients/dsgw/bin/report.pl" TARGET="response"></P></CENTER>
+
+<CENTER><P><IMG SRC="/clients/dsgw/bin/lang?<!-- GCONTEXT -->&pbrd.jpg" HEIGHT=46 WIDTH=491 ALIGN=ABSCENTER></P></CENTER>
+
+<CENTER><P><B><FONT SIZE=+1>Make a report that looks like this table:</FONT></B>
+</P></CENTER>
+
+<CENTER><P>
+<HR SIZE=3 WIDTH="95%"></P></CENTER>
+
+<CENTER><TABLE>
+<TR>
+<TD>
+<CENTER><P><INPUT name="num_fields" type=hidden value="7"></P></CENTER>
+</TD>
+
+<TD><SELECT name="field1" SIZE=1><OPTION SELECTED><FONT SIZE=-1>FullName
+<OPTION>LastName <OPTION>FirstName <OPTION>Initials <OPTION>Email <OPTION>Phone
+<OPTION>Fax <OPTION>Pager <OPTION>Mobile <OPTION>Dept# <OPTION>Group <OPTION>Title
+<OPTION>Admin <OPTION>Location <OPTION>Floor <OPTION>Cube# <OPTION>Mailstop
+<OPTION>EmpType <OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr <OPTION>Car#
+</FONT></SELECT></TD>
+
+<TD><SELECT name="field2" SIZE=1><OPTION><FONT SIZE=-1>FullName <OPTION>LastName
+<OPTION>FirstName <OPTION>Initials <OPTION SELECTED>Email <OPTION>Phone
+<OPTION>Fax <OPTION>Pager <OPTION>Mobile <OPTION>Dept# <OPTION>Group <OPTION>Title
+<OPTION>Admin <OPTION>Location <OPTION>Floor <OPTION>Cube# <OPTION>Mailstop
+<OPTION>EmpType <OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr <OPTION>BLANK
+</FONT></SELECT></TD>
+
+<TD><SELECT name="field3" SIZE=1><OPTION><FONT SIZE=-1>FullName <OPTION>LastName
+<OPTION>FirstName <OPTION>Initials <OPTION>Email <OPTION SELECTED>Phone
+<OPTION>Fax <OPTION>Pager <OPTION>Mobile <OPTION>Dept# <OPTION>Group <OPTION>Title
+<OPTION>Admin <OPTION>Location <OPTION>Floor <OPTION>Cube# <OPTION>Mailstop
+<OPTION>EmpType <OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr <OPTION>Car#
+<OPTION>BLANK </FONT></SELECT></TD>
+
+<TD><SELECT name="field4" SIZE=1><OPTION><FONT SIZE=-1>FullName <OPTION>LastName
+<OPTION>FirstName <OPTION>Initials <OPTION>Email <OPTION>Phone <OPTION>Fax
+<OPTION>Pager <OPTION>Mobile <OPTION>Dept# <OPTION SELECTED>Group <OPTION>Title
+<OPTION>Admin <OPTION>Location <OPTION>Floor <OPTION>Cube# <OPTION>Mailstop
+<OPTION>EmpType <OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr <OPTION>Car#
+<OPTION>BLANK </FONT></SELECT></TD>
+
+<TD><SELECT name="field5" SIZE=1><OPTION><FONT SIZE=-1>Email <OPTION>Phone
+<OPTION>Fax <OPTION>Pager <OPTION>Mobile <OPTION SELECTED>Dept# <OPTION>Group
+<OPTION>Title <OPTION>Admin <OPTION>Location <OPTION>Floor <OPTION>Cube#
+<OPTION>Mailstop <OPTION>EmpType <OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr
+<OPTION>Car# <OPTION>BLANK </FONT></SELECT></TD>
+
+<TD><SELECT name="field6" SIZE=1><OPTION><FONT SIZE=-1>Email <OPTION>Phone
+<OPTION>Fax <OPTION>Pager <OPTION>Mobile <OPTION>Dept# <OPTION>Group <OPTION>Title
+<OPTION>Admin <OPTION SELECTED>Location <OPTION>Floor <OPTION>Cube# <OPTION>Mailstop
+<OPTION>EmpType <OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr <OPTION>Car#
+<OPTION>BLANK </FONT></SELECT></TD>
+
+<TD><SELECT name="field7" SIZE=1><OPTION><FONT SIZE=-1>Email <OPTION>Phone
+<OPTION>Fax <OPTION>Pager <OPTION>Mobile <OPTION>Dept# <OPTION>Group <OPTION>Title
+<OPTION SELECTED>Admin <OPTION>Location <OPTION>Floor <OPTION>Cube# <OPTION>Mailstop
+<OPTION>EmpType <OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr <OPTION>Car#
+<OPTION>BLANK </FONT></SELECT></TD>
+</TR>
+</TABLE></CENTER>
+
+<CENTER><P>
+<HR SIZE=3 WIDTH="95%"></P></CENTER>
+
+<CENTER><TABLE>
+<TR>
+<TD><B>The report has entries where</B> </TD>
+
+<TD><SELECT name="searchfor" SIZE=1><OPTION SELECTED>FullName <OPTION>LastName
+<OPTION>FirstName <OPTION>Email <OPTION>Phone <OPTION>Fax <OPTION>Dept#
+<OPTION>Group <OPTION>Title <OPTION>Admin <OPTION>Location <OPTION>Floor
+<OPTION>Cube# <OPTION>Mailstop <OPTION>EmpType <OPTION>MailAddr <OPTION>MailSrvr
+<OPTION>Car# </SELECT></TD>
+
+<TD><B>includes</B> </TD>
+
+<TD><INPUT name="contains" size=20 maxsize=128 value=""></TD>
+</TR>
+</TABLE></CENTER>
+
+<CENTER><TABLE>
+<TR>
+<TD>
+<CENTER><P><INPUT name="num_sorts" type=hidden value="3"></P></CENTER>
+</TD>
+
+<TD><B>and is sorted by</B> </TD>
+
+<TD><SELECT name="sortattr1" SIZE=1><OPTION SELECTED>FullName <OPTION>LastName
+<OPTION>FirstName <OPTION>Initials <OPTION>Email <OPTION>Phone <OPTION>Fax
+<OPTION>Pager <OPTION>Mobile <OPTION>Dept# <OPTION>Group <OPTION>Title
+<OPTION>Admin <OPTION>Location <OPTION>Floor <OPTION>Cube# <OPTION>Mailstop
+<OPTION>EmpType <OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr <OPTION>BLANK
+</SELECT></TD>
+
+<TD><B>and then by</B> </TD>
+
+<TD><SELECT name="sortattr2" SIZE=1><OPTION>FullName <OPTION>LastName <OPTION>FirstName
+<OPTION>Initials <OPTION>Email <OPTION>Phone <OPTION>Fax <OPTION>Pager
+<OPTION>Mobile <OPTION>Dept# <OPTION SELECTED>Group <OPTION>Title <OPTION>Admin
+<OPTION>Location <OPTION>Floor <OPTION>Cube# <OPTION>EmpType <OPTION>Mailstop
+<OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr <OPTION>BLANK </SELECT></TD>
+
+<TD><B>and then by</B> </TD>
+
+<TD><SELECT name="sortattr3" SIZE=1><OPTION>FullName <OPTION>LastName <OPTION>FirstName
+<OPTION>Initials <OPTION>Email <OPTION>Phone <OPTION>Fax <OPTION>Pager
+<OPTION>Mobile <OPTION SELECTED>Dept# <OPTION>Group <OPTION>Title <OPTION>Admin
+<OPTION>Location <OPTION>Floor <OPTION>Cube# <OPTION>Mailstop <OPTION>EmpType
+<OPTION>Emp# <OPTION>MailAddr <OPTION>MailSrvr <OPTION>BLANK </SELECT><B>.</B>
+</TD>
+</TR>
+</TABLE></CENTER>
+
+<CENTER><TABLE>
+<TR>
+<TD><B>Should the report have multiple smaller tables?&nbsp;</B> <INPUT type="radio" name="grouping" value="on" CHECKED>Yes
+<INPUT type="radio" name="grouping" value="off">No </TD>
+</TR>
+</TABLE></CENTER>
+
+<CENTER><P><BR>
+<BR>
+<BR>
+</P></CENTER>
+
+<CENTER><TABLE>
+<TR>
+<TD><INPUT type="reset" value="Reset"></TD>
+
+<TD><INPUT type="submit" value="Make Report"></TD>
+</TR>
+</TABLE></CENTER>
+
+<P></FORM></P>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/pbhtml/style.css b/ldap/clients/dsgw/pbhtml/style.css
new file mode 100644
index 00000000..e4739d6f
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/style.css
@@ -0,0 +1,88 @@
+/* ======================================================= *
+ * Style sheet for the Directory Express application *
+ * ======================================================= */
+
+/* All Links */
+A:link { font-family: verdana, Arial, Helvetica, sans-serif; font-size: 11px}
+A:active { color: #FF0000;}
+
+.linknodec {text-decoration:none; color:#000000; font-family: verdana, Arial, Helvetica, sans-serif; font-size: 11px}
+
+/*All Regular Table Data--for the whole application*/
+td {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ color: #000000;
+ vertical-align : middle;
+}
+
+p {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ color: #000000;
+}
+
+
+td.bold {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ vertical-align : middle;
+ color: #000000;
+ font-weight: bold;
+}
+
+td.boldbig {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align : middle;
+ color: #000000;
+ font-weight: bold;
+}
+
+input {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 11px;
+ /*color: #000000;*/
+}
+
+
+A.searchlinknorm:link {color: #CCFFFF}
+A.searchlinknorm:visited {color: #CCFFFF}
+A.searchlinknorm:active {color: #CCFFFF}
+
+A.searchlinkspec:link {color: #FF0000}
+A.searchlinkspec:visited {color: #FF0000}
+A.searchlinkspec:active {color: #CCFFFF}
+
+/* *********Search frame*************/
+
+body.Search {
+ background-color: #003366;
+ font-family: Verdana, Arial, Helvetica, san-serif;
+ color: #ccffff;
+ font-size: 12px;
+}
+
+td.appName {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align : middle;
+ color: #ccffff;
+ font-weight: bold;
+}
+
+.apptext {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align: middle;
+ color: #ccffff;
+}
+
+/* Fonts */
+.text15 {color: #ffffff; font-size: 12px; font-family: Verdana, Arial, Helvetica; font-weight: bold;}
+.text30 {color: #CCFFFF; font-size: 8px; font-family: Verdana, Arial, Helvetica;}
+.text31 {color: #000000; font-size: 14px; font-family: Verdana, Arial, Helvetica; font-weight: bold;}
+
+.bgColor1 {background-color: #003366;}
+.bgColor4 {background-color: #cccccc;}
+.bgColor7 {background-color: #66ccff;}
diff --git a/ldap/clients/dsgw/pbhtml/tiny_cert.gif b/ldap/clients/dsgw/pbhtml/tiny_cert.gif
new file mode 100644
index 00000000..c8cec6ea
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/tiny_cert.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/tiny_vcard.gif b/ldap/clients/dsgw/pbhtml/tiny_vcard.gif
new file mode 100644
index 00000000..a1fcd542
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/tiny_vcard.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/vendor.gif b/ldap/clients/dsgw/pbhtml/vendor.gif
new file mode 100644
index 00000000..d2aafd12
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/vendor.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/view_vcard.gif b/ldap/clients/dsgw/pbhtml/view_vcard.gif
new file mode 100644
index 00000000..61f34205
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/view_vcard.gif
Binary files differ
diff --git a/ldap/clients/dsgw/pbhtml/view_vcard_sm.gif b/ldap/clients/dsgw/pbhtml/view_vcard_sm.gif
new file mode 100644
index 00000000..98aa322f
--- /dev/null
+++ b/ldap/clients/dsgw/pbhtml/view_vcard_sm.gif
Binary files differ
diff --git a/ldap/clients/dsgw/search.c b/ldap/clients/dsgw/search.c
new file mode 100644
index 00000000..90b40fcc
--- /dev/null
+++ b/ldap/clients/dsgw/search.c
@@ -0,0 +1,217 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * search.c -- CGI program to generate smart search form -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+static void get_request(char *docname);
+static void do_searchtype_popup( struct ldap_searchobj *sop );
+
+
+int main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+ auto int reqmethod;
+ char *docname = NULL;
+ char *qs = NULL;
+
+ /* Parse out the file=blah.html */
+ if (( qs = getenv( "QUERY_STRING" )) != NULL && *qs != '\0' ) {
+ /* parse the query string: */
+ auto char *p, *iter = NULL;
+ qs = dsgw_ch_strdup( qs );
+
+ for ( p = ldap_utf8strtok_r( qs, "&", &iter ); p != NULL;
+ p = ldap_utf8strtok_r( NULL, "&", &iter )) {
+
+ /*
+ * Get the conf file name. It'll be translated
+ * into /dsgw/context/CONTEXT.conf if
+ * CONTEXT is all alphanumeric (no slahes,
+ * or dots). CONTEXT is passed into the cgi.
+ * if context=CONTEXT is not there, or PATH_INFO
+ * was used, then use dsgw.conf
+ */
+ if ( !strncasecmp( p, "context=", 8 )) {
+ context = dsgw_ch_strdup( p + 8 );
+ dsgw_form_unescape( context );
+ continue;
+ }
+
+
+ /*Get the filename and check it for naughtiness -RJP*/
+ if ( !strncasecmp( p, "file=", 5 )) {
+ docname = dsgw_ch_strdup( p + 5 );
+ dsgw_form_unescape( docname );
+
+ /*
+ * Make sure the person isn't trying to get
+ * some file not in the gateway.
+ */
+ if (! dsgw_valid_docname(docname)) {
+ dsgw_error( DSGW_ERR_BADFILEPATH, docname,
+ DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ continue;
+ }
+
+
+ }
+
+ free( qs ); qs = NULL;
+ }
+
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_GET );
+ dsgw_send_header();
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+{
+ char buf[ 1024 ];
+ getcwd( buf, sizeof(buf));
+ dsgw_log( "cwd: \"%s\"\n", buf );
+}
+#endif
+
+ if ( reqmethod == DSGW_METHOD_GET ) {
+ get_request(docname);
+ }
+ exit( 0 );
+}
+
+
+static void
+get_request(char *docname)
+{
+
+ auto char* filename = NULL;
+ auto struct ldap_searchobj* sop = NULL;
+
+ if (docname != NULL && *docname == '/') {
+ docname++;
+ }
+
+ if ( docname == NULL || *docname == '\0' ) {
+ filename = "search.html";
+ } else if ( !strcmp( docname, "string" )) {
+ filename = "searchString.html";
+ dsgw_init_searchprefs( &sop );
+ }
+ if (filename) {
+ auto FILE* html = dsgw_open_html_file( filename, DSGW_ERROPT_EXIT );
+ auto char line[ BIG_LINE ];
+ auto int argc;
+ auto char **argv;
+
+ while ( dsgw_next_html_line( html, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 0, dsgw_simple_cond_is_true, NULL )) {
+ if ( dsgw_directive_is( line, "HEAD" )) {
+ dsgw_head_begin();
+ dsgw_emits ("\n");
+ } else if ( dsgw_directive_is( line, "DS_SEARCH_SCRIPT" )) {
+ dsgw_emits ("<SCRIPT LANGUAGE=\"JavaScript\">\n"
+ "<!-- Hide from non-JavaScript-capable browsers\n"
+ "\n"
+ "function validate(sform)\n"
+ "{\n"
+ " if (sform.searchstring.value == '') {\n");
+/*
+ * It would have been nice to detect when the user pressed return without
+ * typing anything into the searchstring area, but on Navigator 2.x, the
+ * form variable's value seems to get set *after* the onSubmit handler
+ * executes, which is unfortunate.
+ */
+ dsgw_emit_alert ("searchFrame", NULL, /* "%s<br>(search base %s)", */
+ XP_GetClientStr (DBT_youDidNotSupplyASearchString_),
+ gc->gc_ldapsearchbase);
+ dsgw_emits (" return false;\n"
+ " }\n"
+ " sform.searchstring.select();\n"
+ " sform.searchstring.focus();\n"
+ " return true;\n"
+ "}\n"
+ "\n"
+ "function init()\n"
+ "{}\n"
+ "// End hiding -->\n"
+ "</SCRIPT>\n");
+
+ } else if ( dsgw_directive_is( line, "DS_SEARCH_BODY" )) {
+ dsgw_emitf ("<BODY onLoad=\""
+ "document.searchForm.searchstring.select();"
+ "document.searchForm.searchstring.focus();\" %s>\n",
+ dsgw_html_body_colors );
+ dsgw_emit_alertForm();
+
+ } else if ( dsgw_directive_is( line, "DS_SEARCH_FORM" )) {
+ dsgw_form_begin ("searchForm", "action=\"%s\" %s %s",
+ dsgw_getvp( DSGW_CGINUM_DOSEARCH ),
+ "onSubmit=\"return top.validate(this)\"",
+ argc > 0 ? argv[0] : "");
+ dsgw_emitf ("\n"
+ "<INPUT TYPE=hidden NAME=\"mode\" VALUE=\"smart\">\n"
+ "<INPUT TYPE=hidden NAME=\"base\" VALUE=\"%s\">\n"
+ "<INPUT TYPE=hidden NAME=\"ldapserver\" VALUE=\"%s\">\n"
+ "<INPUT TYPE=hidden NAME=\"ldapport\" VALUE=\"%d\">\n",
+ gc->gc_ldapsearchbase, gc->gc_ldapserver, gc->gc_ldapport );
+ } else if ( dsgw_directive_is( line, "DS_SEARCH_BASE" )) {
+#ifdef NOTFORNOW
+ /* ldap_dn2ufn currently gobbles up 'dc' so don't use */
+ /* it for now */
+ auto char* ufn = ldap_dn2ufn( gc->gc_ldapsearchbase );
+ dsgw_emits( ufn );
+ free( ufn );
+#else
+ dsgw_emits( gc->gc_ldapsearchbase );
+#endif
+ } else if ( dsgw_directive_is( line, "DS_SEARCH_TYPE" )) {
+ do_searchtype_popup( sop );
+ } else if ( dsgw_directive_is( line, "DS_HELP_BUTTON" )) {
+ dsgw_emit_helpbutton (argc > 0 ? argv[0] : "");
+ } else {
+ dsgw_emits (line);
+ }
+ dsgw_argv_free( argv );
+ }
+ }
+ fclose (html);
+ }
+}
+
+
+static void
+do_searchtype_popup(
+struct ldap_searchobj *sop
+)
+{
+ int first = 1;
+ struct ldap_searchobj *so;
+
+ dsgw_emits( "<SELECT NAME=\"type\">\n" );
+ for ( so = ldap_first_searchobj( sop ); so != NULL;
+ so = ldap_next_searchobj( sop, so ), first = 0) {
+ /* Skip any marked "internal-only" */
+ if ( LDAP_IS_SEARCHOBJ_OPTION_SET( so, LDAP_SEARCHOBJ_OPT_INTERNAL )) {
+ continue;
+ }
+ dsgw_emitf( "<OPTION%s value=\"%s\">%s</OPTION>\n",
+ first ? " selected" : "",
+ so->so_objtypeprompt,
+ dsgw_get_translation( so->so_objtypeprompt ));
+ }
+ dsgw_emits( "</SELECT>\n" );
+}
diff --git a/ldap/clients/dsgw/secglue.c b/ldap/clients/dsgw/secglue.c
new file mode 100644
index 00000000..3a317185
--- /dev/null
+++ b/ldap/clients/dsgw/secglue.c
@@ -0,0 +1,174 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * secglue.c: Glue routines for the httpd.so shared object. These are
+ * necessary because on many system no garbage collection is performed for
+ * shared objects.
+ *
+ * Rob McCool
+ *
+ * Adapted for DSGW by Mark Smith 18 Aug 1997.
+ * Copied from revision 1.4.4.6.4.1 of ldapserver/httpd/newadmin/src/secglue.c
+ */
+
+
+#include "base/systems.h"
+
+#ifdef __cplusplus
+#define FUNC(name) extern "C" { void name (void) {} }
+#else
+#define FUNC(name) void name (void) {}
+#endif
+
+FUNC(DS_Alloc)
+FUNC(DS_Free)
+FUNC(DS_Zfree)
+FUNC(SEC_CertChainFromCert)
+FUNC(SEC_CertTimesValid)
+FUNC(SEC_CheckPassword)
+FUNC(SEC_CloseKeyDB)
+FUNC(SEC_CompareItem)
+FUNC(SEC_ConvertToPublicKey)
+FUNC(CERT_DestroyCertificate)
+FUNC(SECKEY_DestroyPrivateKey)
+FUNC(SEC_DestroyPublicKey)
+FUNC(SECITEM_DupItem)
+FUNC(SEC_ExtractPublicKey)
+FUNC(SEC_FindCertByNickname)
+FUNC(SEC_FindKeyByName)
+FUNC(SECITEM_FreeItem)
+FUNC(CERT_GetAVATag)
+FUNC(SEC_GetPassword)
+FUNC(SEC_GetSSLCACerts)
+FUNC(CERT_NameToAscii)
+FUNC(SEC_OpenCertDB)
+FUNC(CERT_RFC1485_EscapeAndQuote)
+FUNC(SEC_ResetRandom)
+FUNC(SEC_UTCTimeToAscii)
+FUNC(SECKEY_UpdateKeyDBPass1)
+FUNC(SECKEY_UpdateKeyDBPass2)
+FUNC(SSL_Accept)
+FUNC(SSL_AcceptHook)
+FUNC(SSL_AuthCertificate)
+FUNC(SSL_AuthCertificateHook)
+FUNC(SSL_BadCertHook)
+FUNC(SSL_Bind)
+FUNC(SSL_BindForSockd)
+FUNC(SSL_CheckDirectSock)
+FUNC(SSL_Close)
+FUNC(SSL_ConfigSecureServer)
+FUNC(SSL_ConfigServerSessionIDCache)
+FUNC(SSL_ConfigSockd)
+FUNC(SSL_Connect)
+FUNC(SSL_DataPending)
+FUNC(SSL_DataPendingHack)
+FUNC(SSL_Enable)
+FUNC(SSL_EnableCipher)
+FUNC(SSL_EnableDefault)
+FUNC(SSL_ForceHandshake)
+FUNC(SSL_GetClientAuthDataHook)
+FUNC(SSL_GetPeerName)
+FUNC(SSL_GetSessionID)
+FUNC(SSL_GetSockOpt)
+FUNC(SSL_HandshakeCallback)
+FUNC(SSL_Import)
+FUNC(SSL_ImportFd)
+FUNC(SSL_InvalidateSession)
+FUNC(SSL_Ioctl)
+FUNC(SSL_IsDomestic)
+FUNC(SSL_Listen)
+FUNC(SSL_PeerCertificate)
+FUNC(SSL_Read)
+FUNC(SSL_Recv)
+FUNC(SSL_RedoHandshake)
+FUNC(SSL_ResetHandshake)
+FUNC(SSL_SecurityCapabilities)
+FUNC(SSL_SecurityStatus)
+FUNC(SSL_Send)
+FUNC(SSL_SetSockOpt)
+FUNC(SSL_SetURL)
+FUNC(SSL_Shutdown)
+FUNC(SSL_Socket)
+FUNC(SSL_Write)
+/*
+ * DSGWmcs: added the functions below:
+ */
+FUNC(SEC_RNGInit)
+FUNC(SEC_CheckKeyDBPassword)
+FUNC(SEC_ZfreeItem)
+FUNC(SEC_DataToAscii)
+FUNC(SEC_AsciiToData)
+FUNC(ldapssl_init) /* called by something in ns-httpd.so */
+FUNC(SSL_DefaultBadCertHandler) /* called by something in ns-httpd.so */
+/* DSGW kristian added: */
+FUNC(CERT_GetDomainComponentName)
+FUNC(CERT_GetCertEmailAddress)
+FUNC(CERT_GetCertUid)
+FUNC(CERT_GetCommonName)
+FUNC(CERT_GetCountryName)
+FUNC(CERT_GetLocalityName)
+FUNC(CERT_GetOrgName)
+FUNC(CERT_GetStateName)
+FUNC(CERT_IsExportVersion)
+FUNC(CERT_PublicModulusLen)
+
+#ifdef FORTEZZA
+FUNC(SSL_EnableGroup)
+FUNC(SEC_OpenVolatileCertDB)
+FUNC(FortezzaConfigureServer)
+FUNC(SSL_IsEnabledGroup)
+#endif /* FORTEZZA */
+
+/* DSGW pkennedy added, for HCL integration */
+FUNC(BTOA_DataToAscii)
+FUNC(ATOB_AsciiToData)
+FUNC(SSL_ImportFD)
+FUNC(PK11_FindKeyByAnyCert)
+FUNC(PK11_GetTokenName)
+FUNC(PK11_SetPasswordFunc)
+FUNC(PK11_FindCertFromNickname)
+FUNC(PK11_FortezzaHasKEA)
+FUNC(PK11_ConfigurePKCS11)
+FUNC(SSL_SetPolicy)
+FUNC(CERT_VerifyCertNow)
+FUNC(SSL_RevealURL)
+FUNC(CERT_VerifyCertName)
+FUNC(PORT_SetError)
+
+/* DSGW richm added, for nss 2.8.x support */
+FUNC(SSL_OptionSet)
+FUNC(NSS_SetDomesticPolicy)
+
+/* DSGW powers added, for NSS 3.4.x support*/
+FUNC(NSS_NoDB_Init)
+FUNC(NSS_Initialize)
+FUNC(NSS_Init)
+FUNC(PK11_GenerateRandom)
+FUNC(PK11_GetInternalKeySlot)
+FUNC(PK11_KeyGen)
+FUNC(PK11_ImportSymKey)
+FUNC(PK11_GenerateNewParam)
+FUNC(PK11_CreateContextBySymKey)
+FUNC(PK11_CipherOp)
+FUNC(PK11_DigestFinal)
+FUNC(PK11_Finalize)
+FUNC(PK11_DestroyContext)
+FUNC(PK11_FreeSlot)
+FUNC(PK11_DigestBegin)
+FUNC(PK11_FreeSymKey)
+FUNC(PK11_DigestOp)
+FUNC(PK11_CloneContext)
+FUNC(PK11_HashBuf)
+FUNC(PK11_CreateDigestContext)
+FUNC(SECITEM_ZfreeItem)
+FUNC(SSL_CipherPrefSetDefault)
+FUNC(SSL_OptionGetDefault)
+FUNC(SSL_OptionSetDefault)
+FUNC(SSL_CipherPolicySet )
+FUNC(CERT_GetDefaultCertDB)
+FUNC(CERT_OpenCertDBFilename)
+
diff --git a/ldap/clients/dsgw/sort.c b/ldap/clients/dsgw/sort.c
new file mode 100644
index 00000000..f88a1282
--- /dev/null
+++ b/ldap/clients/dsgw/sort.c
@@ -0,0 +1,138 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/* Copyright (c) 1998 Netscape Communications Corp. All rights reserved. */
+
+/* DON'T SHIP THIS PROGRAM. It's terribly un-secure, as it
+ enables an HTTP client to read the contents of any file.
+*/
+
+/* This is a Gateway CGI program, for testing collation.
+ It reads the text file named by $PATH_INFO and outputs its lines, sorted,
+ in a table with the script and collation key computed by dsgw_strkeygen.
+ The locale is controlled by the Accept-Language header in the HTTP request,
+ like any Gateway CGI.
+*/
+
+#include <errno.h>
+#include <stdio.h> /* fopen, fgets, perror */
+#include <stdlib.h> /* getenv, qsort */
+#include "dsgw.h"
+
+static const char*
+fgetln(FILE* f, int* error)
+{
+ auto size_t buflen = 128;
+ auto char* buf = dsgw_ch_malloc (buflen);
+ *buf = '\0';
+ while (fgets (buf, buflen, f)) {
+ auto const size_t read = strlen(buf);
+ if (buf[read-1] == '\n') {
+ buf[read-1] = '\0';
+ return buf;
+ }
+ buflen *= 2;
+ buf = dsgw_ch_realloc (buf, buflen);
+ }
+ if (feof(f) && *buf) return buf;
+ free (buf);
+ return NULL;
+}
+
+typedef struct keystring {
+ const char* ks_val;
+ struct berval* ks_key;
+} keystring_t;
+
+static int
+keystring_cmp (const void* Lv, const void* Rv)
+{
+ auto const keystring_t** L = (const keystring_t**)Lv;
+ auto const keystring_t** R = (const keystring_t**)Rv;
+ return dsgw_keycmp (NULL, (*L)->ks_key, (*R)->ks_key);
+}
+
+int
+main( int argc, char* argv[] )
+{
+ auto int error = 0;
+ auto const int reqmethod = dsgw_init (argc, argv, DSGW_METHOD_GET);
+ auto char* fname = getenv ("PATH_INFO");
+
+ dsgw_send_header();
+ dsgw_emits ("<HTML>\n");
+ dsgw_head_begin();
+ dsgw_emits ("\n</head>\n<body>\n");
+
+ if (!fname) {
+ dsgw_emits ("!PATH_INFO\n");
+ error = 1;
+ } else {
+ auto FILE* f = fopen (fname, "r");
+ if (!f) {
+ dsgw_emitf ("%s: errno %i\n", fname, errno);
+ error = 2;
+ } else {
+ auto const char* line;
+ auto keystring_t* v = NULL;
+ auto size_t vlen = 0;
+ while (line = fgetln(f, &error)) {
+ v = (keystring_t*) dsgw_ch_realloc (v, (vlen+1) * sizeof(keystring_t));
+ v[vlen].ks_val = line;
+ v[vlen].ks_key = dsgw_strkeygen (CASE_INSENSITIVE, line);
+ ++vlen;
+ }
+ fclose (f);
+ if (vlen) {
+ auto keystring_t** vp;
+ auto size_t i;
+ vp = (keystring_t**) dsgw_ch_malloc (vlen * sizeof(keystring_t*));
+ for (i = 0; i < vlen; ++i) {
+ vp[i] = v + i;
+ }
+
+ qsort (vp, vlen, sizeof(keystring_t*), keystring_cmp);
+
+ dsgw_emits ("<table align=left cols=5>\n");
+ dsgw_emits (" <tr>"
+ "<th width=20>" DSGW_UTF8_NBSP "</th>"
+ "<th align=left>line</th>"
+ "<th width=25>script</th>"
+ "<th width=20>" DSGW_UTF8_NBSP "</th>"
+ "<th align=left>Sort Key</th>"
+ "</tr>\n");
+ for (i = 0; i < vlen; ++i) {
+ auto size_t j;
+ dsgw_emits (" <tr valign=baseline>");
+ dsgw_emitf ("<th align=right>%lu:</th>", 1 + (unsigned long)(vp[i]-v));
+ dsgw_emitf ("<td>%s</td>", vp[i]->ks_val);
+ dsgw_emits ("<td align=center>");
+ if (vp[i]->ks_key->bv_len) {
+ dsgw_emitf ("%u", 0xFF & (unsigned)(vp[i]->ks_key->bv_val[0]));
+ } else {
+ dsgw_emits (DSGW_UTF8_NBSP);
+ }
+ dsgw_emits ("</td>");
+ dsgw_emitf ("<td align=right>%lu:</td>", (unsigned long)(vp[i]->ks_key->bv_len) - 2);
+ dsgw_emits ("<td><font size=\"-2\">");
+ for (j = 1; j < vp[i]->ks_key->bv_len - 1; ++j) {
+ dsgw_emitf ("%02x", 0xFF & (unsigned)(vp[i]->ks_key->bv_val[j]));
+ }
+ dsgw_emits ("</font></td>");
+ dsgw_emits ("</tr>\n");
+ }
+ dsgw_emits ("</table>\n");
+ free (vp);
+ for (i = 0; i < vlen; ++i) {
+ dsgw_keyfree (NULL, v[i].ks_key);
+ }
+ free (v);
+ }
+ }
+ }
+ dsgw_emits ("</body></HTML>\n");
+ return error;
+}
diff --git a/ldap/clients/dsgw/templateindex.c b/ldap/clients/dsgw/templateindex.c
new file mode 100644
index 00000000..103b4fa1
--- /dev/null
+++ b/ldap/clients/dsgw/templateindex.c
@@ -0,0 +1,184 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * templateindex.c -- CGI template indexer -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#if defined( XP_WIN32 )
+#include <io.h>
+struct dirent {
+ char d_name[1];
+};
+#else
+#include <dirent.h>
+#endif
+
+static void build_index();
+
+#if defined( XP_WIN32 )
+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 + 1 ) ) ) != NULL )
+ ret[ nfiles++ ] = strdup( fileinfo.name);
+ }
+ }
+
+ _findclose( hFile );
+
+ ret[ nfiles ] = NULL;
+ return ret;
+}
+#endif ( XP_WIN32 )
+
+
+main( argc, argv, env )
+ int argc;
+ char *argv[];
+#ifdef DSGW_DEBUG
+ char *env[];
+#endif
+{
+ int reqmethod;
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_GET );
+ dsgw_send_header();
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ dsgw_html_begin( "Directory Server Gateway Template Indexer", 1 );
+
+ build_index();
+
+ dsgw_html_end();
+
+ exit( 0 );
+}
+
+
+static void
+build_index()
+{
+ FILE *htmlfp;
+#if !defined( XP_WIN32 )
+ DIR *dirp;
+#endif
+ struct dirent *dep;
+ char *path, **argv, *classes, *p, line[ BIG_LINE ];
+ char **filelist;
+ int errcount, prefixlen, count, argc, filecount = 0;
+
+
+ path = dsgw_file2path( gc->gc_tmpldir, "" );
+
+#if defined( XP_WIN32 )
+ if (( filelist = ds_get_file_list( path )) == NULL ) {
+#else
+ if (( dirp = opendir( path )) == NULL ) {
+#endif
+ dsgw_error( DSGW_ERR_OPENDIR, path, DSGW_ERROPT_EXIT, 0, NULL );
+ }
+ free( path );
+
+ prefixlen = strlen( DSGW_CONFIG_DISPLAYPREFIX );
+ errcount = count = 0;
+
+ dsgw_emitf( "Remove any lines that begin with \"template\" from \n" );
+ dsgw_emitf( "your dsgw.conf file and add these lines:<BR><PRE>\n" );
+
+#if defined( XP_WIN32 )
+ while( filelist != NULL && filelist[filecount] != NULL ) {
+ dep = (struct dirent *)filelist[filecount];
+#else
+ while (( dep = readdir( dirp )) != NULL ) {
+#endif
+ if ( strlen( dep->d_name ) > prefixlen && strncasecmp( dep->d_name,
+ DSGW_CONFIG_DISPLAYPREFIX, prefixlen ) == 0 && strcmp(
+ ".html", dep->d_name + strlen( dep->d_name ) - 5 ) == 0 ) {
+ ++count;
+ htmlfp = dsgw_open_html_file( dep->d_name, DSGW_ERROPT_EXIT );
+
+ while ( dsgw_next_html_line( htmlfp, line )) {
+ if ( dsgw_parse_line( line, &argc, &argv, 1,
+ dsgw_simple_cond_is_true, NULL )) {
+ if ( dsgw_directive_is( line, DRCT_DS_OBJECTCLASS )) {
+ if (( classes = get_arg_by_name( "value", argc, argv ))
+ == NULL ) {
+ dsgw_emitf(
+ "Missing \"value=objectclass\" on line &lt%s<BR>\n", line+1 );
+ ++errcount;
+ continue;
+ }
+ dsgw_emitf( "template %.*s",
+ strlen( dep->d_name ) - prefixlen - 5,
+ dep->d_name + prefixlen );
+ for ( ; classes != NULL && *classes != '\0';
+ classes = p ) {
+ if (( p = strchr( classes, ',' )) != NULL ) {
+ *p++ = '\0';
+ while ( ldap_utf8isspace( p )) {
+ LDAP_UTF8INC(p);
+ }
+ }
+ dsgw_emitf( " %s", classes );
+ }
+ dsgw_emits( "\n" );
+ }
+ }
+ }
+ fclose( htmlfp );
+ filecount++;
+ }
+ }
+
+#if !defined( XP_WIN32 )
+ closedir( dirp );
+#endif
+
+ dsgw_emits( "</PRE><H3>Template indexing " );
+
+ if ( errcount == 0 ) {
+ dsgw_emitf( "complete (%d files).<H3>\n", count );
+ } else {
+ dsgw_emitf( "failed (%d errors).<H3>\n", errcount );
+ }
+}
diff --git a/ldap/clients/dsgw/tutor.c b/ldap/clients/dsgw/tutor.c
new file mode 100644
index 00000000..682e0843
--- /dev/null
+++ b/ldap/clients/dsgw/tutor.c
@@ -0,0 +1,276 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * tutor.c - Take a qs, and spit out the appropriate tutorial
+ *
+ * All blame to Mike McCool
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "dsgw.h"
+
+#define BASE_MAN_DIRECTORY "manual/"
+#define BASE_INFO_DIRECTORY "info/"
+#define HELP_INDEX_HTML "manual/index.html"
+/*#define MANUAL_HPATH "bin/lang?file=" DSGW_MANUALSHORTCUT "/"*/
+
+/* Copied from ldapserver/lib/base/util.c */
+static int
+my_util_uri_is_evil(char *t)
+{
+ register int x;
+
+ for(x = 0; t[x]; ++x) {
+ if(t[x] == '/') {
+ if(t[x+1] == '/')
+ return 1;
+ if(t[x+1] == '.') {
+ switch(t[x+2]) {
+ case '.':
+ if((!t[x+3]) || (t[x+3] == '/'))
+ return 1;
+ case '/':
+ case '\0':
+ return 1;
+ }
+ }
+ }
+#ifdef XP_WIN32
+ /* On NT, the directory "abc...." is the same as "abc"
+ * The only cheap way to catch this globally is to disallow
+ * names with the trailing "."s. Hopefully this is not over
+ * restrictive
+ */
+ if ((t[x] == '.') && ( (t[x+1] == '/') || (t[x+1] == '\0') )) {
+ return 1;
+ }
+#endif
+ }
+ return 0;
+}
+
+
+FILE *
+_open_html_file( char *filename )
+{
+ FILE *f;
+ char *mypath;
+ char *p;
+
+ p = dsgw_file2path( DSGW_MANROOT, "slapd/gw/" );
+ mypath = (char *)dsgw_ch_malloc( strlen( p ) +
+ strlen( filename ) + 1 );
+ sprintf( mypath, "%s%s", p, filename );
+
+ if (!(f = fopen( mypath, "r" ))) {
+ dsgw_error( DSGW_ERR_OPENHTMLFILE, filename, DSGW_ERROPT_EXIT,
+ 0, NULL );
+ }
+
+ free( p );
+ free( mypath );
+
+ return f;
+}
+
+
+
+/* Had to copy and paste so wouldn't set referer. */
+void _my_return_html_file(char *filename, char *base) {
+ char line[BIG_LINE];
+ FILE *html = _open_html_file(filename);
+
+ if(base) {
+ char *tmp;
+ char *surl=getenv("SERVER_URL");
+ char *sn=dsgw_ch_strdup(getenv("SCRIPT_NAME"));
+ tmp=strchr(&(sn[1]), '/');
+ *tmp='\0';
+ dsgw_emitf("<BASE href=\"%s%s/%s\">\n", surl, sn, base);
+ }
+ while( fgets(line, BIG_LINE, html)) {
+ dsgw_emits( line );
+ }
+}
+
+
+int
+main(
+ int argc,
+ char *argv[]
+#ifdef DSGW_DEBUG
+ ,char *env[]
+#endif
+)
+{
+ char *qs = getenv("QUERY_STRING");
+ char *html=NULL;
+ char *base=NULL;
+
+#ifdef DSGW_DEBUG
+ dsgw_logstringarray( "env", env );
+#endif
+
+ if(qs == NULL || *qs == '\0') {
+ dsgw_send_header();
+ _my_return_html_file(BASE_MAN_DIRECTORY HELP_INDEX_HTML, NULL);
+ exit(0);
+ } else {
+ /* parse the query string: */
+ auto char *p, *iter = NULL;
+
+ /*get a pointer to the context. It should be the last part of the qs*/
+ p = ldap_utf8strtok_r( qs, "&", &iter );
+
+ /*
+ * Get the conf file name. It'll be translated
+ * into /dsgw/context/CONTEXT.conf if
+ * CONTEXT is all alphanumeric (no slahes,
+ * or dots). CONTEXT is passed into the cgi.
+ * if context=CONTEXT is not there, or PATH_INFO
+ * was used, then use dsgw.conf
+ */
+ if ( iter != NULL && !strncasecmp( iter, "context=", 8 )) {
+ context = dsgw_ch_strdup( iter + 8 );
+ dsgw_form_unescape( context );
+ }
+
+ }
+
+ dsgw_init( argc, argv, DSGW_METHOD_GET );
+
+ html = (char *) dsgw_ch_malloc(strlen(qs)+10+10);
+ sprintf(html, "%s.html", qs);
+ if (my_util_uri_is_evil(html)) {
+ dsgw_send_header();
+ dsgw_emits( "<CENTER><H2>Error</H2></CENTER>\n"
+ "<P>\n"
+ "URL contains dangerous characters. Cannot display\n"
+ "help text." );
+ exit( 0 );
+ }
+
+ if(qs[0]=='!') {
+ qs++;
+ if(!strncmp(qs, BASE_INFO_DIRECTORY, strlen(BASE_INFO_DIRECTORY))) {
+ sprintf(html, "%s.html", qs);
+ } else if(!strncmp(qs, BASE_MAN_DIRECTORY, strlen(BASE_MAN_DIRECTORY))) {
+ if(!strstr(qs, ".html")) {
+ sprintf(html, "%s.htm", qs);
+ } else {
+ sprintf(html, "%s", qs);
+ }
+ base=qs;
+ }
+ else {
+ char line[BIG_LINE];
+ FILE *map=NULL;
+ char *man_index=NULL;
+
+ man_index = dsgw_file2path ( DSGW_MANROOT, "slapd/gw/manual/index.map" );
+
+ html[0]='\0';
+
+ map=fopen(man_index, "r");
+ if(!map)
+ goto ohwell;
+ while(fgets(line, BIG_LINE, map)) {
+ if(line[0]==';')
+ continue;
+ else if(ldap_utf8isspace(line))
+ continue;
+ else {
+ /* parse out the line */
+ register char *head=NULL, *tail=NULL;
+ int found;
+
+ head=&(line[0]);
+ tail=head;
+ found=0;
+ while(*tail) {
+ if(ldap_utf8isspace(tail) || *tail=='=') {
+ *tail='\0';
+ found=1;
+ /* get rid of extra stuff at the end */
+ tail++;
+ while(1) {
+ if (*tail == 0) {
+ ++tail; /* This looks wrong. */
+ break;
+ }
+ LDAP_UTF8INC(tail);
+ if((!ldap_utf8isspace(tail)) && (*tail!='='))
+ break;
+ }
+ break;
+ }
+ LDAP_UTF8INC(tail);
+ }
+ if(!found) continue;
+
+ /* script name is in head */
+ if(strncasecmp(head, qs, strlen(qs))) {
+ continue;
+ }
+ /* match found. get the actual file name */
+ head=tail;
+/* Step on CRs and LFs. */
+ while(*tail) {
+ if((*tail=='\r') || (*tail=='\n') || (*tail==';')) {
+ *tail='\0';
+ break;
+ }
+ LDAP_UTF8INC(tail);
+ }
+#if 0
+/* No longer remove whitespace at end of line. Now is whitespace in link. */
+ while(*LDAP_UTF8DEC(tail)) {
+ if(ldap_utf8isspace(tail)) *tail='\0';
+ else break;
+ }
+#endif
+ /* assumedly, head should now have the proper HTML file
+ * from the manual inside. redirect the client 'cause
+ * there's no other way to get them to jump to the
+ * right place.
+ * Looks like:
+ * http://host:port/dsgw/bin/lang?context=CONTEXT&file=.MANUAL/FILE.HTM
+ * Where MANUAL is literal
+ */
+ dsgw_emitf("Location: %s%s/%s\n\n",
+ gc->gc_urlpfxmain, DSGW_MANUALSHORTCUT, head);
+
+ fclose(map);
+ exit(0);
+ }
+ }
+ fclose(map);
+ free( man_index );
+
+ohwell:
+ if(!html[0])
+ sprintf(html, "%s%s.html", BASE_MAN_DIRECTORY, qs);
+ }
+ dsgw_send_header();
+ _my_return_html_file(html, base);
+ } else {
+ dsgw_send_header();
+ dsgw_emits("<TITLE>Directory Server Gateway Help</TITLE>\n");
+ dsgw_emits("\n");
+ dsgw_emits("<frameset BORDER=0 FRAMEBORDER=NO rows=\"57,*\" "
+ "onLoad=\"top.master=top.opener.top;top.master.helpwin=self;\" "
+ "onUnload=\"if (top.master) { top.master.helpwin=0; }\">\n" );
+ dsgw_emitf("<frame src=\"%s?!info/infonav&context=%s\" scrolling=no "
+ "marginwidth=0 marginheight=0 "
+ "name=\"infobuttons\">\n", dsgw_getvp(DSGW_CGINUM_TUTOR), context);
+ dsgw_emitf("<frame src=\"%s?!%s&context=%s\" "
+ "name=\"infotopic\">\n", dsgw_getvp(DSGW_CGINUM_TUTOR), qs, context);
+ dsgw_emits("</frameset>\n");
+ }
+ return 1;
+}
diff --git a/ldap/clients/dsgw/unauth.c b/ldap/clients/dsgw/unauth.c
new file mode 100644
index 00000000..3dec0bd7
--- /dev/null
+++ b/ldap/clients/dsgw/unauth.c
@@ -0,0 +1,165 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * unauth.c -- CGI to discard cookies -- HTTP gateway
+ *
+ * Copyright (c) 1996 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+
+char *get_auth_cookie( char *cookie );
+void generate_message( int type );
+
+#define CKEXP_SUCCESS 1
+#define CKEXP_FAILURE 2
+
+int main( int argc, char **argv )
+{
+ int reqmethod;
+ char *expck;
+ char *authck;
+ int rc;
+ char *qs = NULL;
+
+ /* Parse out the context=blah.html */
+ if (( qs = getenv( "QUERY_STRING" )) != NULL && *qs != '\0' ) {
+ /* parse the query string: */
+ auto char *p, *iter = NULL;
+ qs = dsgw_ch_strdup( qs );
+
+ for ( p = ldap_utf8strtok_r( qs, "&", &iter ); p != NULL;
+ p = ldap_utf8strtok_r( NULL, "&", &iter )) {
+
+ /*
+ * Get the conf file name. It'll be translated
+ * into /dsgw/context/CONTEXT.conf if
+ * CONTEXT is all alphanumeric (no slahes,
+ * or dots). CONTEXT is passed into the cgi.
+ * if context=CONTEXT is not there, or PATH_INFO
+ * was used, then use dsgw.conf
+ */
+ if ( !strncasecmp( p, "context=", 8 )) {
+ context = dsgw_ch_strdup( p + 8 );
+ dsgw_form_unescape( context );
+ continue;
+ }
+
+ }
+
+ free( qs ); qs = NULL;
+ }
+
+
+ reqmethod = dsgw_init( argc, argv, DSGW_METHOD_GET );
+
+ authck = dsgw_get_auth_cookie();
+ if ( authck == NULL ) {
+ /* No cookie. Generate an informational message. */
+ generate_message( CKEXP_SUCCESS );
+ free( authck );
+ exit( 0 );
+ }
+
+ /* Remove the cookie from the cookie database */
+ rc = dsgw_delcookie( authck );
+
+ /* Generate a cookie header with the cookie set to [unauthenticated] */
+ expck = dsgw_ch_malloc( strlen( DSGW_CKHDR ) + strlen( DSGW_AUTHCKNAME ) +
+ strlen( DSGW_UNAUTHSTR ) + strlen( "=; path=/" ) + 2 );
+ sprintf( expck, "%s%s=%s; path=/", DSGW_CKHDR, DSGW_AUTHCKNAME, DSGW_UNAUTHSTR );
+ dsgw_add_header( expck );
+ generate_message( CKEXP_SUCCESS );
+ free( authck );
+ free( expck );
+ exit( 0 );
+}
+
+
+
+/*
+ * It's quite likely that there will be more than one cookie in the
+ * Cookie: header. See if we've got an authentication cookie, and if
+ * so, parse it out and return a pointer to it. If no auth cookie
+ * is present, return NULL.
+ */
+char *
+get_auth_cookie( char *cookie )
+{
+ char *p, *e;
+
+ if ( cookie == NULL ) {
+ return NULL;
+ }
+
+ if (( p = strstr( cookie, DSGW_AUTHCKNAME )) == NULL ) {
+ return NULL;
+ }
+
+ if (( e = strchr( p, ';' )) != NULL ) {
+ *e = '\0';
+ }
+
+ return p;
+}
+
+
+
+void
+generate_message( int type )
+{
+ dsgw_send_header();
+ dsgw_emits( "<HTML>" );
+ dsgw_head_begin();
+ dsgw_emits( "\n<TITLE>" );
+ if ( type == CKEXP_SUCCESS ) {
+ dsgw_emits( "Success" );
+ } else if ( type == CKEXP_FAILURE ) {
+ dsgw_emits( "Error" );
+ }
+ dsgw_emits( "</TITLE>\n</HEAD>\n" );
+ dsgw_emitf( "<BODY %s>\n", dsgw_html_body_colors );
+
+ dsgw_emitf( "<CENTER>\n"
+ "<FONT SIZE=+2>\n"
+ "%s"
+ "</FONT>\n"
+ "</CENTER>\n"
+ "<P>\n"
+ "%s",
+ XP_GetClientStr( DBT_Success_ ),
+ XP_GetClientStr( DBT_YouAreNoLongerAuthenticated_ ));
+
+ if ( type != CKEXP_SUCCESS ) {
+ /*
+ * Something went wrong, so generate some JavaScript to
+ * discard the cookie.
+ */
+ dsgw_emits( "<SCRIPT LANGUAGE=\"JavaScript\">\n" );
+ dsgw_emitf( "document.cookie = '%s=%s; path=/';\n", DSGW_AUTHCKNAME,
+ DSGW_UNAUTHSTR );
+ dsgw_emits( "</SCRIPT>\n" );
+ }
+ dsgw_form_begin (NULL, NULL);
+ dsgw_emits( "\n"
+ "<TABLE BORDER=2 WIDTH=100%>\n"
+ "<TR>\n"
+ "<TD ALIGN=CENTER WIDTH=50%>\n");
+ dsgw_emitf(
+ "<INPUT TYPE=BUTTON VALUE=\"%s\"", XP_GetClientStr( DBT_GoBack_ ));
+ dsgw_emits(
+ " onClick=\"window.location.href=");
+ dsgw_quote_emitf(QUOTATION_JAVASCRIPT, "auth?context=%s", context);
+ dsgw_emits(";\"></TD>\n"
+ "<TD ALIGN=CENTER WIDTH=50%>\n" );
+ dsgw_emit_helpbutton( "UNAUTH" );
+ dsgw_emits( "</TABLE></FORM>\n"
+ "</BODY></HTML>\n" );
+}
+
diff --git a/ldap/clients/dsgw/userhtml/Makefile b/ldap/clients/dsgw/userhtml/Makefile
new file mode 100644
index 00000000..6cc32c6f
--- /dev/null
+++ b/ldap/clients/dsgw/userhtml/Makefile
@@ -0,0 +1,60 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright © 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# Gmakefile for Directory Server Gateway html files.
+#
+
+LDAP_SRC = ../../..
+MCOM_ROOT = ../../../../..
+
+NOSTDSTRIP=true # don't let nsconfig.mak define target strip
+NOSTDCLEAN=true # don't let nsconfig.mak define target clean
+NOSTDDEPEND=true # don't let nsconfig.mak define target depend
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+include ../dsgw_include.mk
+
+HTML= $(wildcard *.html)
+
+ifeq ($(BUILD_MODULE), HTTP_ADMIN)
+HTMLDEST = $(OBJDIR)/user-forms/html
+else
+HTMLDEST = $(DSGW_HTML_RELDIR)
+endif
+
+DEFINES += $(DEFS)
+
+CFLAGS += $(INCLUDES) $(DEFINES) $(ACFLAGS)
+
+BINS=$(addprefix $(HTMLDEST)/,$(HTML))
+
+ifeq ($(BUILD_MODULE), HTTP_ADMIN)
+all: $(HTMLDEST) $(BINS)
+
+$(HTMLDEST):
+ mkdir -p $(HTMLDEST)
+
+else
+all: $(HTMLDEST)
+endif
+
+clean: clean-manual clean-info
+ $(RM) $(BINS)
+
+$(HTMLDEST)/%.htm: %.htm
+ cp $< $(HTMLDEST)/$*.htm
+
+$(HTMLDEST)/%.html: %.html
+ cp $< $(HTMLDEST)/$*.html
+
+$(HTMLDEST)/%.gif: %.gif
+ cp $< $(HTMLDEST)/$*.gif
+
+strip:
+depend:
diff --git a/ldap/clients/dsgw/userhtml/edit-userpasswd.html b/ldap/clients/dsgw/userhtml/edit-userpasswd.html
new file mode 100644
index 00000000..e79423e5
--- /dev/null
+++ b/ldap/clients/dsgw/userhtml/edit-userpasswd.html
@@ -0,0 +1,85 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML><HEAD>
+<!-- change a user's password in the directory -->
+
+<!-- DS_ENTRYBEGIN -->
+<TITLE>Change Password -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+</TITLE>
+
+</HEAD>
+
+<!-- COLORS "TEXT=#000000 BGCOLOR=#FFFFFF LINK=#FF0000 VLINK=#8000FF ALINK=#FF0000" -->
+
+<!-- BODY "onLoad='document.forms[0].passwd.focus()'" -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT><HR>" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="colors" VALUE="TEXT=#000000 BGCOLOR=#FFFFFF LINK=#FF0000 VLINK=#8000FF ALINK=#FF0000">
+
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'edit/?userpasswd&info=\' + escape(dsmodify_info);">
+
+<TABLE BORDER=2 CELLSPACING=0 CELLPADDING=10 BGCOLOR="#F0F0F0">
+<TR BGCOLOR="#F1C40E">
+<TD>
+<H3>Password for
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "options=nolink" -->
+<FONT COLOR="#FFFFFF"> </FONT></H3>
+</TD>
+</TR>
+
+<TR>
+<TD><I><FONT SIZE=+0>Use this form to change your system password</FONT></I>.
+</TD>
+</TR>
+
+<TR>
+<TD>
+<UL>
+<TABLE CELLSPACING=0 CELLPADDING=0 >
+<TR ALIGN=LEFT VALIGN=CENTER>
+<TD><B>1.</B> Enter your <B>current </B>password:</TD>
+<TD>
+<!-- DS_OLDPASSWORD "size=12" -->
+</TD></TR>
+
+<TR VALIGN=CENTER>
+<TD><B>2.</B> Enter your <B>new </B>password: </TD>
+<TD>
+<!-- DS_NEWPASSWORD "size=12" -->
+</TD></TR>
+
+<TR ALIGN=LEFT VALIGN=CENTER>
+<TD><B>3.</B> Enter <B>new </B>password again:</TD>
+<TD>
+<!-- DS_CONFIRM_NEWPASSWORD "size=12" -->
+</TD></TR>
+</TABLE>
+</UL>
+</TD>
+</TR>
+
+<TR>
+<TD>
+<CENTER><P>
+<!-- DS_SAVEBUTTON "label= OK " -->
+</P></CENTER>
+</TD>
+</TR>
+</TABLE>
+
+
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'edit/\' + dsmodify_dn + \'?&info=\' + escape(dsmodify_info)">
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/userhtml/edit-userpinfo.html b/ldap/clients/dsgw/userhtml/edit-userpinfo.html
new file mode 100644
index 00000000..ebd7b3dc
--- /dev/null
+++ b/ldap/clients/dsgw/userhtml/edit-userpinfo.html
@@ -0,0 +1,92 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HTML>
+<HEAD>
+<!-- DS_ENTRYBEGIN -->
+<!-- DS_EMIT_BASE_HREF -->
+</HEAD>
+
+<!-- COLORS "TEXT=#000000 BGCOLOR=#FFFFFF LINK=#FF0000 VLINK=#8000FF ALINK=#FF0000" -->
+
+<!-- BODY -->
+
+<!-- DS_LAST_OP_INFO "prefix=<FONT SIZE=%22%2B1%22>" "suffix=</FONT>" -->
+
+<!-- DS_BEGIN_ENTRYFORM -->
+
+<INPUT TYPE="hidden" NAME="quiet" VALUE="true">
+<INPUT TYPE="hidden" NAME="colors" VALUE="TEXT=#000000 BGCOLOR=#FFFFFF LINK=#FF0000 VLINK=#8000FF ALINK=#FF0000">
+<INPUT TYPE="hidden" NAME="completion_javascript" VALUE="document.location.href=\'edit/?userpinfo&info=\' + escape(dsmodify_info);">
+
+<TABLE BORDER=2 CELLSPACING=0 CELLPADDING=5 BGCOLOR="#F0F0F0" >
+<TR BGCOLOR="#F1C40E">
+<TD COLSPAN=2>
+<H3>Personal Information -
+<!-- DS_ATTRIBUTE "attr=dn" "syntax=dn" "dncomponents=2" "options=nolink" -->
+</H3>
+</TD>
+</TR>
+
+<TR>
+<TD COLSPAN=2><I><FONT SIZE=+0>Use this form to change your personal information
+</FONT></I>.
+</TD>
+</TR>
+
+<TR>
+<TD>First Name:</TD>
+<TD>
+<!-- DS_ATTRIBUTE "attr=givenName" "size=>20" -->
+</TD></TR>
+
+<TR>
+<TD>Last Name:</TD>
+<TD>
+<!-- DS_ATTRIBUTE "attr=sn" "size=>20" -->
+</TD></TR>
+
+<TR>
+<TD>Phone Number:</TD>
+<TD>
+<!-- DS_ATTRIBUTE "attr=telephoneNumber" "syntax=tel" "cols=>20" "numfields=+1" -->
+</TD></TR>
+
+<TR>
+<TD>Fax Number:</TD>
+<TD>
+<!-- DS_ATTRIBUTE "attr=facsimileTelephoneNumber" "syntax=tel" "cols=>20" -->
+</TD></TR>
+
+<TR>
+<TD>Title:</TD>
+<TD>
+<!-- DS_ATTRIBUTE "attr=title" "cols=>20" -->
+</TD></TR>
+
+<TR>
+<TD COLSPAN=2>
+<CENTER>
+<!-- DS_SAVEBUTTON "label= OK " -->
+</CENTER>
+
+<!-- IF "AttributeHasValues" "modifyTimestamp" -->
+<TR>
+<TD COLSPAN=2>
+<FONT SIZE="-1">
+Your directory entry was last modified
+<!-- DS_ATTRIBUTE "attr=modifyTimestamp" "syntax=time" "options=readonly" -->
+ by
+<!-- DS_ATTRIBUTE "attr=modifiersName" "syntax=dn" "defaultvalue=N/A" "options=readonly,nolink" -->
+</TD></TR>
+<!-- ENDIF // AttributeHasValues -->
+
+</TABLE>
+
+<!-- DS_END_ENTRYFORM -->
+<!-- DS_ENTRYEND -->
+
+<!-- ENDHTML -->
diff --git a/ldap/clients/dsgw/userhtml/index.html b/ldap/clients/dsgw/userhtml/index.html
new file mode 100644
index 00000000..06b26dae
--- /dev/null
+++ b/ldap/clients/dsgw/userhtml/index.html
@@ -0,0 +1,29 @@
+<!--
+ PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ license terms. Copyright © 2001 Sun Microsystems, Inc.
+ Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ All rights reserved.
+ -->
+<HEAD>
+<TITLE>Netscape User Environment</TITLE>
+</HEAD>
+<HTML>
+<BODY TEXT="#000000" BGCOLOR="#FFFFFF" LINK="#FF0000" VLINK="#8000FF"
+ ALINK="#FF0000">
+<TABLE BORDER=1 CELLSPACING=0 CELLPADDING=10 WIDTH="100%" BGCOLOR="#F1F1F1" >
+<TR>
+<TD><FONT SIZE=+2>Welcome!</FONT>
+<P><B><FONT SIZE=+1>This page enables you to change some information about
+yourself and your accounts on this system.</FONT></B></P>
+
+<P><B><FONT SIZE=+1>Your options are listed on the left.</FONT></B></P>
+</TD>
+</TR>
+</TABLE>
+
+<P><BR>
+<BR>
+</P>
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/dsgw/userhtml/index.lst b/ldap/clients/dsgw/userhtml/index.lst
new file mode 100644
index 00000000..83156146
--- /dev/null
+++ b/ldap/clients/dsgw/userhtml/index.lst
@@ -0,0 +1,29 @@
+;-------------------------------------------------------------------------
+; PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+; license terms. Copyright © 2001 Sun Microsystems, Inc.
+; Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+; All rights reserved.
+;-------------------------------------------------------------------------
+; Netscape admin index page master list
+;
+; Lines beginning with a ';' are comments
+; Lines beginning with '--' are dividers:
+; '--Category:[ID,NAME]' is the title of the category of options,
+; with short identifier ID and text NAME
+; '--TabIcon:[ICON]' is the name of the icon that goes on top
+; (assumes a suffix of '_on.gif' for on icon,
+; '_off.gif' for off)
+; (ex: for "users", would have URL "users" which points
+; to "users_on.gif" and "users_off.gif")
+; '--Icon:[URL]' is the icon to associate with those options
+; '--Option:[URL,TXT]' is the URL that the option should point to,
+; and the text that should be used to describe
+; it
+;
+; NOTE: Do NOT let a line have unterminated quotes, double slash
+; characters, pound signs, or slash star sequences. This file
+; is sent through the C preprocessor and that can screw it up.
+
+--Category:general,General
+--Option:edit/?userpasswd,Password
+--Option:edit/?userpinfo,Personal Information
diff --git a/ldap/clients/dsgw/utf8compare.c b/ldap/clients/dsgw/utf8compare.c
new file mode 100644
index 00000000..59c85253
--- /dev/null
+++ b/ldap/clients/dsgw/utf8compare.c
@@ -0,0 +1,2236 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include "ldap.h"
+#include "dsgw.h"
+
+typedef struct sUpperLowerTbl {
+ char *upper, *lower;
+ int tsz; /* target size */
+} UpperLowerTbl_t;
+
+/*
+ * dsgw_has8thBit: check the input string
+ * return 1 if the string contains 8-bit character
+ * return 0 otherwise
+ */
+int
+dsgw_has8thBit(unsigned char *s)
+{
+ unsigned char *p, *tail;
+ tail = s + strlen((char *)s);
+ for (p = s; p < tail; p++) {
+ if (0x80 & *p) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * UpperToLower Tables: sorted by upper characters
+ */
+UpperLowerTbl_t Upper2LowerTbl20[] = {
+ /* upper, lower */
+ {"\303\200", "\303\240", 2},
+ {"\303\201", "\303\241", 2},
+ {"\303\202", "\303\242", 2},
+ {"\303\203", "\303\243", 2},
+ {"\303\204", "\303\244", 2},
+ {"\303\205", "\303\245", 2},
+ {"\303\206", "\303\246", 2},
+ {"\303\207", "\303\247", 2},
+ {"\303\210", "\303\250", 2},
+ {"\303\211", "\303\251", 2},
+ {"\303\212", "\303\252", 2},
+ {"\303\213", "\303\253", 2},
+ {"\303\214", "\303\254", 2},
+ {"\303\215", "\303\255", 2},
+ {"\303\216", "\303\256", 2},
+ {"\303\217", "\303\257", 2},
+ {"\303\220", "\303\260", 2},
+ {"\303\221", "\303\261", 2},
+ {"\303\222", "\303\262", 2},
+ {"\303\223", "\303\263", 2},
+ {"\303\224", "\303\264", 2},
+ {"\303\225", "\303\265", 2},
+ {"\303\226", "\303\266", 2},
+ {"\303\230", "\303\270", 2},
+ {"\303\231", "\303\271", 2},
+ {"\303\232", "\303\272", 2},
+ {"\303\233", "\303\273", 2},
+ {"\303\234", "\303\274", 2},
+ {"\303\235", "\303\275", 2},
+ {"\303\236", "\303\276", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl21[] = {
+ {"\304\200", "\304\201", 2},
+ {"\304\202", "\304\203", 2},
+ {"\304\204", "\304\205", 2},
+ {"\304\206", "\304\207", 2},
+ {"\304\210", "\304\211", 2},
+ {"\304\212", "\304\213", 2},
+ {"\304\214", "\304\215", 2},
+ {"\304\216", "\304\217", 2},
+ {"\304\220", "\304\221", 2},
+ {"\304\222", "\304\223", 2},
+ {"\304\224", "\304\225", 2},
+ {"\304\226", "\304\227", 2},
+ {"\304\230", "\304\231", 2},
+ {"\304\232", "\304\233", 2},
+ {"\304\234", "\304\235", 2},
+ {"\304\236", "\304\237", 2},
+ {"\304\240", "\304\241", 2},
+ {"\304\242", "\304\243", 2},
+ {"\304\244", "\304\245", 2},
+ {"\304\246", "\304\247", 2},
+ {"\304\250", "\304\251", 2},
+ {"\304\252", "\304\253", 2},
+ {"\304\254", "\304\255", 2},
+ {"\304\256", "\304\257", 2},
+ {"\304\260", "\151", 1},
+ {"\304\262", "\304\263", 2},
+ {"\304\264", "\304\265", 2},
+ {"\304\266", "\304\267", 2},
+ {"\304\271", "\304\272", 2},
+ {"\304\273", "\304\274", 2},
+ {"\304\275", "\304\276", 2},
+ {"\304\277", "\305\200", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl22[] = {
+ {"\305\201", "\305\202", 2},
+ {"\305\203", "\305\204", 2},
+ {"\305\205", "\305\206", 2},
+ {"\305\207", "\305\210", 2},
+ {"\305\212", "\305\213", 2},
+ {"\305\214", "\305\215", 2},
+ {"\305\216", "\305\217", 2},
+ {"\305\220", "\305\221", 2},
+ {"\305\222", "\305\223", 2},
+ {"\305\224", "\305\225", 2},
+ {"\305\226", "\305\227", 2},
+ {"\305\230", "\305\231", 2},
+ {"\305\232", "\305\233", 2},
+ {"\305\234", "\305\235", 2},
+ {"\305\236", "\305\237", 2},
+ {"\305\240", "\305\241", 2},
+ {"\305\242", "\305\243", 2},
+ {"\305\244", "\305\245", 2},
+ {"\305\246", "\305\247", 2},
+ {"\305\250", "\305\251", 2},
+ {"\305\252", "\305\253", 2},
+ {"\305\254", "\305\255", 2},
+ {"\305\256", "\305\257", 2},
+ {"\305\260", "\305\261", 2},
+ {"\305\262", "\305\263", 2},
+ {"\305\264", "\305\265", 2},
+ {"\305\266", "\305\267", 2},
+ {"\305\270", "\303\277", 2},
+ {"\305\271", "\305\272", 2},
+ {"\305\273", "\305\274", 2},
+ {"\305\275", "\305\276", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl23[] = {
+ {"\306\201", "\311\223", 2},
+ {"\306\202", "\306\203", 2},
+ {"\306\204", "\306\205", 2},
+ {"\306\206", "\311\224", 2},
+ {"\306\207", "\306\210", 2},
+ {"\306\211", "\311\226", 2},
+ {"\306\212", "\311\227", 2},
+ {"\306\213", "\306\214", 2},
+ {"\306\216", "\311\230", 2},
+ {"\306\217", "\311\231", 2},
+ {"\306\220", "\311\233", 2},
+ {"\306\221", "\306\222", 2},
+ {"\306\223", "\311\240", 2},
+ {"\306\224", "\311\243", 2},
+ {"\306\226", "\311\251", 2},
+ {"\306\227", "\311\250", 2},
+ {"\306\230", "\306\231", 2},
+ {"\306\234", "\311\257", 2},
+ {"\306\235", "\311\262", 2},
+ {"\306\237", "\306\237", 2},
+ {"\306\240", "\306\241", 2},
+ {"\306\242", "\306\243", 2},
+ {"\306\244", "\306\245", 2},
+ {"\306\246", "\306\246", 2},
+ {"\306\247", "\306\250", 2},
+ {"\306\251", "\312\203", 2},
+ {"\306\254", "\306\255", 2},
+ {"\306\256", "\312\210", 2},
+ {"\306\257", "\306\260", 2},
+ {"\306\261", "\312\212", 2},
+ {"\306\262", "\312\213", 2},
+ {"\306\263", "\306\264", 2},
+ {"\306\265", "\306\266", 2},
+ {"\306\267", "\312\222", 2},
+ {"\306\270", "\306\271", 2},
+ {"\306\274", "\306\275", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl24[] = {
+ {"\307\204", "\307\205", 2},
+ {"\307\205", "\307\204", 2},
+ {"\307\207", "\307\210", 2},
+ {"\307\210", "\307\207", 2},
+ {"\307\212", "\307\213", 2},
+ {"\307\213", "\307\212", 2},
+ {"\307\215", "\307\216", 2},
+ {"\307\217", "\307\220", 2},
+ {"\307\221", "\307\222", 2},
+ {"\307\223", "\307\224", 2},
+ {"\307\225", "\307\226", 2},
+ {"\307\227", "\307\230", 2},
+ {"\307\231", "\307\232", 2},
+ {"\307\233", "\307\234", 2},
+ {"\307\236", "\307\237", 2},
+ {"\307\240", "\307\241", 2},
+ {"\307\242", "\307\243", 2},
+ {"\307\244", "\307\245", 2},
+ {"\307\246", "\307\247", 2},
+ {"\307\250", "\307\251", 2},
+ {"\307\252", "\307\253", 2},
+ {"\307\254", "\307\255", 2},
+ {"\307\256", "\307\257", 2},
+ {"\307\261", "\307\262", 2},
+ {"\307\262", "\307\261", 2},
+ {"\307\264", "\307\265", 2},
+ {"\307\272", "\307\273", 2},
+ {"\307\274", "\307\275", 2},
+ {"\307\276", "\307\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl25[] = {
+ {"\310\200", "\310\201", 2},
+ {"\310\202", "\310\203", 2},
+ {"\310\204", "\310\205", 2},
+ {"\310\206", "\310\207", 2},
+ {"\310\210", "\310\211", 2},
+ {"\310\212", "\310\213", 2},
+ {"\310\214", "\310\215", 2},
+ {"\310\216", "\310\217", 2},
+ {"\310\220", "\310\221", 2},
+ {"\310\222", "\310\223", 2},
+ {"\310\224", "\310\225", 2},
+ {"\310\226", "\310\227", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl26[] = {
+ {"\316\206", "\316\254", 2},
+ {"\316\210", "\316\255", 2},
+ {"\316\211", "\316\256", 2},
+ {"\316\212", "\316\257", 2},
+ {"\316\214", "\317\214", 2},
+ {"\316\216", "\317\215", 2},
+ {"\316\217", "\317\216", 2},
+ {"\316\221", "\316\261", 2},
+ {"\316\222", "\316\262", 2},
+ {"\316\223", "\316\263", 2},
+ {"\316\224", "\316\264", 2},
+ {"\316\225", "\316\265", 2},
+ {"\316\226", "\316\266", 2},
+ {"\316\227", "\316\267", 2},
+ {"\316\230", "\316\270", 2},
+ {"\316\231", "\316\271", 2},
+ {"\316\232", "\316\272", 2},
+ {"\316\233", "\316\273", 2},
+ {"\316\234", "\316\274", 2},
+ {"\316\235", "\316\275", 2},
+ {"\316\236", "\316\276", 2},
+ {"\316\237", "\316\277", 2},
+ {"\316\240", "\317\200", 2},
+ {"\316\241", "\317\201", 2},
+ {"\316\243", "\317\203", 2},
+ {"\316\244", "\317\204", 2},
+ {"\316\245", "\317\205", 2},
+ {"\316\246", "\317\206", 2},
+ {"\316\247", "\317\207", 2},
+ {"\316\250", "\317\210", 2},
+ {"\316\251", "\317\211", 2},
+ {"\316\252", "\317\212", 2},
+ {"\316\253", "\317\213", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl27[] = {
+ {"\317\222", "\317\222", 2},
+ {"\317\223", "\317\223", 2},
+ {"\317\224", "\317\224", 2},
+ {"\317\232", "\317\232", 2},
+ {"\317\234", "\317\234", 2},
+ {"\317\236", "\317\236", 2},
+ {"\317\240", "\317\240", 2},
+ {"\317\242", "\317\243", 2},
+ {"\317\244", "\317\245", 2},
+ {"\317\246", "\317\247", 2},
+ {"\317\250", "\317\251", 2},
+ {"\317\252", "\317\253", 2},
+ {"\317\254", "\317\255", 2},
+ {"\317\256", "\317\257", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl28[] = {
+ {"\320\201", "\321\221", 2},
+ {"\320\202", "\321\222", 2},
+ {"\320\203", "\321\223", 2},
+ {"\320\204", "\321\224", 2},
+ {"\320\205", "\321\225", 2},
+ {"\320\206", "\321\226", 2},
+ {"\320\207", "\321\227", 2},
+ {"\320\210", "\321\230", 2},
+ {"\320\211", "\321\231", 2},
+ {"\320\212", "\321\232", 2},
+ {"\320\213", "\321\233", 2},
+ {"\320\214", "\321\234", 2},
+ {"\320\216", "\321\236", 2},
+ {"\320\217", "\321\237", 2},
+ {"\320\220", "\320\260", 2},
+ {"\320\221", "\320\261", 2},
+ {"\320\222", "\320\262", 2},
+ {"\320\223", "\320\263", 2},
+ {"\320\224", "\320\264", 2},
+ {"\320\225", "\320\265", 2},
+ {"\320\226", "\320\266", 2},
+ {"\320\227", "\320\267", 2},
+ {"\320\230", "\320\270", 2},
+ {"\320\231", "\320\271", 2},
+ {"\320\232", "\320\272", 2},
+ {"\320\233", "\320\273", 2},
+ {"\320\234", "\320\274", 2},
+ {"\320\235", "\320\275", 2},
+ {"\320\236", "\320\276", 2},
+ {"\320\237", "\320\277", 2},
+ {"\320\240", "\321\200", 2},
+ {"\320\241", "\321\201", 2},
+ {"\320\242", "\321\202", 2},
+ {"\320\243", "\321\203", 2},
+ {"\320\244", "\321\204", 2},
+ {"\320\245", "\321\205", 2},
+ {"\320\246", "\321\206", 2},
+ {"\320\247", "\321\207", 2},
+ {"\320\250", "\321\210", 2},
+ {"\320\251", "\321\211", 2},
+ {"\320\252", "\321\212", 2},
+ {"\320\253", "\321\213", 2},
+ {"\320\254", "\321\214", 2},
+ {"\320\255", "\321\215", 2},
+ {"\320\256", "\321\216", 2},
+ {"\320\257", "\321\217", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl29[] = {
+ {"\321\240", "\321\241", 2},
+ {"\321\242", "\321\243", 2},
+ {"\321\244", "\321\245", 2},
+ {"\321\246", "\321\247", 2},
+ {"\321\250", "\321\251", 2},
+ {"\321\252", "\321\253", 2},
+ {"\321\254", "\321\255", 2},
+ {"\321\256", "\321\257", 2},
+ {"\321\260", "\321\261", 2},
+ {"\321\262", "\321\263", 2},
+ {"\321\264", "\321\265", 2},
+ {"\321\266", "\321\267", 2},
+ {"\321\270", "\321\271", 2},
+ {"\321\272", "\321\273", 2},
+ {"\321\274", "\321\275", 2},
+ {"\321\276", "\321\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl2a[] = {
+ {"\322\200", "\322\201", 2},
+ {"\322\220", "\322\221", 2},
+ {"\322\222", "\322\223", 2},
+ {"\322\224", "\322\225", 2},
+ {"\322\226", "\322\227", 2},
+ {"\322\230", "\322\231", 2},
+ {"\322\232", "\322\233", 2},
+ {"\322\234", "\322\235", 2},
+ {"\322\236", "\322\237", 2},
+ {"\322\240", "\322\241", 2},
+ {"\322\242", "\322\243", 2},
+ {"\322\244", "\322\245", 2},
+ {"\322\246", "\322\247", 2},
+ {"\322\250", "\322\251", 2},
+ {"\322\252", "\322\253", 2},
+ {"\322\254", "\322\255", 2},
+ {"\322\256", "\322\257", 2},
+ {"\322\260", "\322\261", 2},
+ {"\322\262", "\322\263", 2},
+ {"\322\264", "\322\265", 2},
+ {"\322\266", "\322\267", 2},
+ {"\322\270", "\322\271", 2},
+ {"\322\272", "\322\273", 2},
+ {"\322\274", "\322\275", 2},
+ {"\322\276", "\322\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl2b[] = {
+ {"\323\201", "\323\202", 2},
+ {"\323\203", "\323\204", 2},
+ {"\323\207", "\323\210", 2},
+ {"\323\213", "\323\214", 2},
+ {"\323\220", "\323\221", 2},
+ {"\323\222", "\323\223", 2},
+ {"\323\224", "\323\225", 2},
+ {"\323\226", "\323\227", 2},
+ {"\323\230", "\323\231", 2},
+ {"\323\232", "\323\233", 2},
+ {"\323\234", "\323\235", 2},
+ {"\323\236", "\323\237", 2},
+ {"\323\240", "\323\241", 2},
+ {"\323\242", "\323\243", 2},
+ {"\323\244", "\323\245", 2},
+ {"\323\246", "\323\247", 2},
+ {"\323\250", "\323\251", 2},
+ {"\323\252", "\323\253", 2},
+ {"\323\256", "\323\257", 2},
+ {"\323\260", "\323\261", 2},
+ {"\323\262", "\323\263", 2},
+ {"\323\264", "\323\265", 2},
+ {"\323\270", "\323\271", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl2c[] = {
+ {"\324\261", "\325\241", 2},
+ {"\324\262", "\325\242", 2},
+ {"\324\263", "\325\243", 2},
+ {"\324\264", "\325\244", 2},
+ {"\324\265", "\325\245", 2},
+ {"\324\266", "\325\246", 2},
+ {"\324\267", "\325\247", 2},
+ {"\324\270", "\325\250", 2},
+ {"\324\271", "\325\251", 2},
+ {"\324\272", "\325\252", 2},
+ {"\324\273", "\325\253", 2},
+ {"\324\274", "\325\254", 2},
+ {"\324\275", "\325\255", 2},
+ {"\324\276", "\325\256", 2},
+ {"\324\277", "\325\257", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl2d[] = {
+ {"\325\200", "\325\260", 2},
+ {"\325\201", "\325\261", 2},
+ {"\325\202", "\325\262", 2},
+ {"\325\203", "\325\263", 2},
+ {"\325\204", "\325\264", 2},
+ {"\325\205", "\325\265", 2},
+ {"\325\206", "\325\266", 2},
+ {"\325\207", "\325\267", 2},
+ {"\325\210", "\325\270", 2},
+ {"\325\211", "\325\271", 2},
+ {"\325\212", "\325\272", 2},
+ {"\325\213", "\325\273", 2},
+ {"\325\214", "\325\274", 2},
+ {"\325\215", "\325\275", 2},
+ {"\325\216", "\325\276", 2},
+ {"\325\217", "\325\277", 2},
+ {"\325\220", "\326\200", 2},
+ {"\325\221", "\326\201", 2},
+ {"\325\222", "\326\202", 2},
+ {"\325\223", "\326\203", 2},
+ {"\325\224", "\326\204", 2},
+ {"\325\225", "\326\205", 2},
+ {"\325\226", "\326\206", 2},
+ {NULL, NULL, 0}
+ /* upper, lower */
+};
+
+UpperLowerTbl_t Upper2LowerTbl30[] = {
+ /* upper, lower */
+ {"\341\202\240", "\341\203\220", 3},
+ {"\341\202\241", "\341\203\221", 3},
+ {"\341\202\242", "\341\203\222", 3},
+ {"\341\202\243", "\341\203\223", 3},
+ {"\341\202\244", "\341\203\224", 3},
+ {"\341\202\245", "\341\203\225", 3},
+ {"\341\202\246", "\341\203\226", 3},
+ {"\341\202\247", "\341\203\227", 3},
+ {"\341\202\250", "\341\203\230", 3},
+ {"\341\202\251", "\341\203\231", 3},
+ {"\341\202\252", "\341\203\232", 3},
+ {"\341\202\253", "\341\203\233", 3},
+ {"\341\202\254", "\341\203\234", 3},
+ {"\341\202\255", "\341\203\235", 3},
+ {"\341\202\256", "\341\203\236", 3},
+ {"\341\202\257", "\341\203\237", 3},
+ {"\341\202\260", "\341\203\240", 3},
+ {"\341\202\261", "\341\203\241", 3},
+ {"\341\202\262", "\341\203\242", 3},
+ {"\341\202\263", "\341\203\243", 3},
+ {"\341\202\264", "\341\203\244", 3},
+ {"\341\202\265", "\341\203\245", 3},
+ {"\341\202\266", "\341\203\246", 3},
+ {"\341\202\267", "\341\203\247", 3},
+ {"\341\202\270", "\341\203\250", 3},
+ {"\341\202\271", "\341\203\251", 3},
+ {"\341\202\272", "\341\203\252", 3},
+ {"\341\202\273", "\341\203\253", 3},
+ {"\341\202\274", "\341\203\254", 3},
+ {"\341\202\275", "\341\203\255", 3},
+ {"\341\202\276", "\341\203\256", 3},
+ {"\341\202\277", "\341\203\257", 3},
+ {"\341\203\200", "\341\203\260", 3},
+ {"\341\203\201", "\341\203\261", 3},
+ {"\341\203\202", "\341\203\262", 3},
+ {"\341\203\203", "\341\203\263", 3},
+ {"\341\203\204", "\341\203\264", 3},
+ {"\341\203\205", "\341\203\265", 3},
+ {"\341\270\200", "\341\270\201", 3},
+ {"\341\270\202", "\341\270\203", 3},
+ {"\341\270\204", "\341\270\205", 3},
+ {"\341\270\206", "\341\270\207", 3},
+ {"\341\270\210", "\341\270\211", 3},
+ {"\341\270\212", "\341\270\213", 3},
+ {"\341\270\214", "\341\270\215", 3},
+ {"\341\270\216", "\341\270\217", 3},
+ {"\341\270\220", "\341\270\221", 3},
+ {"\341\270\222", "\341\270\223", 3},
+ {"\341\270\224", "\341\270\225", 3},
+ {"\341\270\226", "\341\270\227", 3},
+ {"\341\270\230", "\341\270\231", 3},
+ {"\341\270\232", "\341\270\233", 3},
+ {"\341\270\234", "\341\270\235", 3},
+ {"\341\270\236", "\341\270\237", 3},
+ {"\341\270\240", "\341\270\241", 3},
+ {"\341\270\242", "\341\270\243", 3},
+ {"\341\270\244", "\341\270\245", 3},
+ {"\341\270\246", "\341\270\247", 3},
+ {"\341\270\250", "\341\270\251", 3},
+ {"\341\270\252", "\341\270\253", 3},
+ {"\341\270\254", "\341\270\255", 3},
+ {"\341\270\256", "\341\270\257", 3},
+ {"\341\270\260", "\341\270\261", 3},
+ {"\341\270\262", "\341\270\263", 3},
+ {"\341\270\264", "\341\270\265", 3},
+ {"\341\270\266", "\341\270\267", 3},
+ {"\341\270\270", "\341\270\271", 3},
+ {"\341\270\272", "\341\270\273", 3},
+ {"\341\270\274", "\341\270\275", 3},
+ {"\341\270\276", "\341\270\277", 3},
+ {"\341\271\200", "\341\271\201", 3},
+ {"\341\271\202", "\341\271\203", 3},
+ {"\341\271\204", "\341\271\205", 3},
+ {"\341\271\206", "\341\271\207", 3},
+ {"\341\271\210", "\341\271\211", 3},
+ {"\341\271\212", "\341\271\213", 3},
+ {"\341\271\214", "\341\271\215", 3},
+ {"\341\271\216", "\341\271\217", 3},
+ {"\341\271\220", "\341\271\221", 3},
+ {"\341\271\222", "\341\271\223", 3},
+ {"\341\271\224", "\341\271\225", 3},
+ {"\341\271\226", "\341\271\227", 3},
+ {"\341\271\230", "\341\271\231", 3},
+ {"\341\271\232", "\341\271\233", 3},
+ {"\341\271\234", "\341\271\235", 3},
+ {"\341\271\236", "\341\271\237", 3},
+ {"\341\271\240", "\341\271\241", 3},
+ {"\341\271\242", "\341\271\243", 3},
+ {"\341\271\244", "\341\271\245", 3},
+ {"\341\271\246", "\341\271\247", 3},
+ {"\341\271\250", "\341\271\251", 3},
+ {"\341\271\252", "\341\271\253", 3},
+ {"\341\271\254", "\341\271\255", 3},
+ {"\341\271\256", "\341\271\257", 3},
+ {"\341\271\260", "\341\271\261", 3},
+ {"\341\271\262", "\341\271\263", 3},
+ {"\341\271\264", "\341\271\265", 3},
+ {"\341\271\266", "\341\271\267", 3},
+ {"\341\271\270", "\341\271\271", 3},
+ {"\341\271\272", "\341\271\273", 3},
+ {"\341\271\274", "\341\271\275", 3},
+ {"\341\271\276", "\341\271\277", 3},
+ {"\341\272\200", "\341\272\201", 3},
+ {"\341\272\202", "\341\272\203", 3},
+ {"\341\272\204", "\341\272\205", 3},
+ {"\341\272\206", "\341\272\207", 3},
+ {"\341\272\210", "\341\272\211", 3},
+ {"\341\272\212", "\341\272\213", 3},
+ {"\341\272\214", "\341\272\215", 3},
+ {"\341\272\216", "\341\272\217", 3},
+ {"\341\272\220", "\341\272\221", 3},
+ {"\341\272\222", "\341\272\223", 3},
+ {"\341\272\224", "\341\272\225", 3},
+ {"\341\272\240", "\341\272\241", 3},
+ {"\341\272\242", "\341\272\243", 3},
+ {"\341\272\244", "\341\272\245", 3},
+ {"\341\272\246", "\341\272\247", 3},
+ {"\341\272\250", "\341\272\251", 3},
+ {"\341\272\252", "\341\272\253", 3},
+ {"\341\272\254", "\341\272\255", 3},
+ {"\341\272\256", "\341\272\257", 3},
+ {"\341\272\260", "\341\272\261", 3},
+ {"\341\272\262", "\341\272\263", 3},
+ {"\341\272\264", "\341\272\265", 3},
+ {"\341\272\266", "\341\272\267", 3},
+ {"\341\272\270", "\341\272\271", 3},
+ {"\341\272\272", "\341\272\273", 3},
+ {"\341\272\274", "\341\272\275", 3},
+ {"\341\272\276", "\341\272\277", 3},
+ {"\341\273\200", "\341\273\201", 3},
+ {"\341\273\202", "\341\273\203", 3},
+ {"\341\273\204", "\341\273\205", 3},
+ {"\341\273\206", "\341\273\207", 3},
+ {"\341\273\210", "\341\273\211", 3},
+ {"\341\273\212", "\341\273\213", 3},
+ {"\341\273\214", "\341\273\215", 3},
+ {"\341\273\216", "\341\273\217", 3},
+ {"\341\273\220", "\341\273\221", 3},
+ {"\341\273\222", "\341\273\223", 3},
+ {"\341\273\224", "\341\273\225", 3},
+ {"\341\273\226", "\341\273\227", 3},
+ {"\341\273\230", "\341\273\231", 3},
+ {"\341\273\232", "\341\273\233", 3},
+ {"\341\273\234", "\341\273\235", 3},
+ {"\341\273\236", "\341\273\237", 3},
+ {"\341\273\240", "\341\273\241", 3},
+ {"\341\273\242", "\341\273\243", 3},
+ {"\341\273\244", "\341\273\245", 3},
+ {"\341\273\246", "\341\273\247", 3},
+ {"\341\273\250", "\341\273\251", 3},
+ {"\341\273\252", "\341\273\253", 3},
+ {"\341\273\254", "\341\273\255", 3},
+ {"\341\273\256", "\341\273\257", 3},
+ {"\341\273\260", "\341\273\261", 3},
+ {"\341\273\262", "\341\273\263", 3},
+ {"\341\273\264", "\341\273\265", 3},
+ {"\341\273\266", "\341\273\267", 3},
+ {"\341\273\270", "\341\273\271", 3},
+ {"\341\274\210", "\341\274\200", 3},
+ {"\341\274\211", "\341\274\201", 3},
+ {"\341\274\212", "\341\274\202", 3},
+ {"\341\274\213", "\341\274\203", 3},
+ {"\341\274\214", "\341\274\204", 3},
+ {"\341\274\215", "\341\274\205", 3},
+ {"\341\274\216", "\341\274\206", 3},
+ {"\341\274\217", "\341\274\207", 3},
+ {"\341\274\230", "\341\274\220", 3},
+ {"\341\274\231", "\341\274\221", 3},
+ {"\341\274\232", "\341\274\222", 3},
+ {"\341\274\233", "\341\274\223", 3},
+ {"\341\274\234", "\341\274\224", 3},
+ {"\341\274\235", "\341\274\225", 3},
+ {"\341\274\250", "\341\274\240", 3},
+ {"\341\274\251", "\341\274\241", 3},
+ {"\341\274\252", "\341\274\242", 3},
+ {"\341\274\253", "\341\274\243", 3},
+ {"\341\274\254", "\341\274\244", 3},
+ {"\341\274\255", "\341\274\245", 3},
+ {"\341\274\256", "\341\274\246", 3},
+ {"\341\274\257", "\341\274\247", 3},
+ {"\341\274\270", "\341\274\260", 3},
+ {"\341\274\271", "\341\274\261", 3},
+ {"\341\274\272", "\341\274\262", 3},
+ {"\341\274\273", "\341\274\263", 3},
+ {"\341\274\274", "\341\274\264", 3},
+ {"\341\274\275", "\341\274\265", 3},
+ {"\341\274\276", "\341\274\266", 3},
+ {"\341\274\277", "\341\274\267", 3},
+ {"\341\275\210", "\341\275\200", 3},
+ {"\341\275\211", "\341\275\201", 3},
+ {"\341\275\212", "\341\275\202", 3},
+ {"\341\275\213", "\341\275\203", 3},
+ {"\341\275\214", "\341\275\204", 3},
+ {"\341\275\215", "\341\275\205", 3},
+ {"\341\275\231", "\341\275\221", 3},
+ {"\341\275\233", "\341\275\223", 3},
+ {"\341\275\235", "\341\275\225", 3},
+ {"\341\275\237", "\341\275\227", 3},
+ {"\341\275\250", "\341\275\240", 3},
+ {"\341\275\251", "\341\275\241", 3},
+ {"\341\275\252", "\341\275\242", 3},
+ {"\341\275\253", "\341\275\243", 3},
+ {"\341\275\254", "\341\275\244", 3},
+ {"\341\275\255", "\341\275\245", 3},
+ {"\341\275\256", "\341\275\246", 3},
+ {"\341\275\257", "\341\275\247", 3},
+ {"\341\276\210", "\341\276\200", 3},
+ {"\341\276\211", "\341\276\201", 3},
+ {"\341\276\212", "\341\276\202", 3},
+ {"\341\276\213", "\341\276\203", 3},
+ {"\341\276\214", "\341\276\204", 3},
+ {"\341\276\215", "\341\276\205", 3},
+ {"\341\276\216", "\341\276\206", 3},
+ {"\341\276\217", "\341\276\207", 3},
+ {"\341\276\230", "\341\276\220", 3},
+ {"\341\276\231", "\341\276\221", 3},
+ {"\341\276\232", "\341\276\222", 3},
+ {"\341\276\233", "\341\276\223", 3},
+ {"\341\276\234", "\341\276\224", 3},
+ {"\341\276\235", "\341\276\225", 3},
+ {"\341\276\236", "\341\276\226", 3},
+ {"\341\276\237", "\341\276\227", 3},
+ {"\341\276\250", "\341\276\240", 3},
+ {"\341\276\251", "\341\276\241", 3},
+ {"\341\276\252", "\341\276\242", 3},
+ {"\341\276\253", "\341\276\243", 3},
+ {"\341\276\254", "\341\276\244", 3},
+ {"\341\276\255", "\341\276\245", 3},
+ {"\341\276\256", "\341\276\246", 3},
+ {"\341\276\257", "\341\276\247", 3},
+ {"\341\276\270", "\341\276\260", 3},
+ {"\341\276\271", "\341\276\261", 3},
+ {"\341\276\272", "\341\275\260", 3},
+ {"\341\276\273", "\341\275\261", 3},
+ {"\341\276\274", "\341\276\263", 3},
+ {"\341\276\276", "\341\276\276", 3},
+ {"\341\277\210", "\341\275\262", 3},
+ {"\341\277\211", "\341\275\263", 3},
+ {"\341\277\212", "\341\275\264", 3},
+ {"\341\277\213", "\341\275\265", 3},
+ {"\341\277\214", "\341\277\203", 3},
+ {"\341\277\230", "\341\277\220", 3},
+ {"\341\277\231", "\341\277\221", 3},
+ {"\341\277\232", "\341\275\266", 3},
+ {"\341\277\233", "\341\275\267", 3},
+ {"\341\277\250", "\341\277\240", 3},
+ {"\341\277\251", "\341\277\241", 3},
+ {"\341\277\252", "\341\275\272", 3},
+ {"\341\277\253", "\341\275\273", 3},
+ {"\341\277\254", "\341\277\245", 3},
+ {"\341\277\270", "\341\275\270", 3},
+ {"\341\277\271", "\341\275\271", 3},
+ {"\341\277\272", "\341\275\274", 3},
+ {"\341\277\273", "\341\275\275", 3},
+ {"\341\277\274", "\341\277\263", 3},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl31[] = {
+ {"\357\274\241", "\357\275\201", 3},
+ {"\357\274\242", "\357\275\202", 3},
+ {"\357\274\243", "\357\275\203", 3},
+ {"\357\274\244", "\357\275\204", 3},
+ {"\357\274\245", "\357\275\205", 3},
+ {"\357\274\246", "\357\275\206", 3},
+ {"\357\274\247", "\357\275\207", 3},
+ {"\357\274\250", "\357\275\210", 3},
+ {"\357\274\251", "\357\275\211", 3},
+ {"\357\274\252", "\357\275\212", 3},
+ {"\357\274\253", "\357\275\213", 3},
+ {"\357\274\254", "\357\275\214", 3},
+ {"\357\274\255", "\357\275\215", 3},
+ {"\357\274\256", "\357\275\216", 3},
+ {"\357\274\257", "\357\275\217", 3},
+ {"\357\274\260", "\357\275\220", 3},
+ {"\357\274\261", "\357\275\221", 3},
+ {"\357\274\262", "\357\275\222", 3},
+ {"\357\274\263", "\357\275\223", 3},
+ {"\357\274\264", "\357\275\224", 3},
+ {"\357\274\265", "\357\275\225", 3},
+ {"\357\274\266", "\357\275\226", 3},
+ {"\357\274\267", "\357\275\227", 3},
+ {"\357\274\270", "\357\275\230", 3},
+ {"\357\274\271", "\357\275\231", 3},
+ {"\357\274\272", "\357\275\232", 3},
+ {NULL, NULL, 0}
+ /* upper, lower */
+};
+
+UpperLowerTbl_t *Upper2LowerTbl2[] = {
+ Upper2LowerTbl20, /* \303 */
+ Upper2LowerTbl21, /* \304 */
+ Upper2LowerTbl22, /* \305 */
+ Upper2LowerTbl23, /* \306 */
+ Upper2LowerTbl24, /* \307 */
+ Upper2LowerTbl25, /* \310 */
+ NULL, /* \311 */
+ NULL, /* \312 */
+ NULL, /* \313 */
+ NULL, /* \314 */
+ NULL, /* \315 */
+ Upper2LowerTbl26, /* \316 */
+ Upper2LowerTbl27, /* \317 */
+ Upper2LowerTbl28, /* \320 */
+ Upper2LowerTbl29, /* \321 */
+ Upper2LowerTbl2a, /* \322 */
+ Upper2LowerTbl2b, /* \323 */
+ Upper2LowerTbl2c, /* \324 */
+ Upper2LowerTbl2d /* \325 */
+};
+
+UpperLowerTbl_t *Upper2LowerTbl3[] = {
+ Upper2LowerTbl30, /* \341 */
+ NULL, /* \342 */
+ NULL, /* \343 */
+ NULL, /* \344 */
+ NULL, /* \345 */
+ NULL, /* \346 */
+ NULL, /* \347 */
+ NULL, /* \350 */
+ NULL, /* \351 */
+ NULL, /* \352 */
+ NULL, /* \353 */
+ NULL, /* \354 */
+ NULL, /* \355 */
+ NULL, /* \356 */
+ Upper2LowerTbl31 /* \357 */
+};
+
+#define UL2S (unsigned char)'\303'
+#define UL2E (unsigned char)'\325'
+#define UL3S (unsigned char)'\341'
+#define UL3E (unsigned char)'\357'
+
+/*
+ * dsgw_utf8StrToLower: translate upper-case string to lower-case
+ *
+ * input: a null terminated UTF-8 string
+ * output: a null terminated UTF-8 string which characters are
+ * converted to lower-case; characters which are not
+ * upper-case are copied as is. If it's not considered
+ * a UTF-8 string, NULL is returned.
+ *
+ * Notes: This function takes a string (made of multiple UTF-8 characters)
+ * for the input (not one character as in "tolower").
+ * Output string is allocated in this function, which needs to be
+ * released when it's not needed any more.
+ */
+unsigned char *
+dsgw_utf8StrToLower(unsigned char *s)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *p, *np, *tail;
+ unsigned char *lp, *lphead;
+ int len, sz;
+
+ if (s == NULL || *s == '\0') {
+ return s;
+ }
+ len = strlen((char *)s);
+ tail = s + len;
+ lphead = lp = (unsigned char *)dsgw_ch_malloc(len + 1);
+ p = s;
+ while ((np = (unsigned char *)ldap_utf8next((char *)p)) <= tail) {
+ switch(sz = np - p) {
+ case 1:
+ sprintf((char *)lp, "%c", tolower(*p));
+ break;
+ case 2:
+ if (*p < UL2S || *p > UL2E) { /* out of range */
+ memcpy(lp, p, sz);
+ break;
+ }
+ for (ultp = Upper2LowerTbl2[*p - UL2S];
+ ultp && ultp->upper && memcmp(p, ultp->upper, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memcpy(lp, p, sz);
+ } if (ultp->upper) { /* matched */
+ memcpy(lp, ultp->lower, ultp->tsz);
+ sz = ultp->tsz;
+ } else {
+ memcpy(lp, p, sz);
+ }
+ break;
+ case 3:
+ if (*p != UL3S && *p != UL3E) { /* out of range */
+ memcpy(lp, p, sz);
+ break;
+ }
+ for (ultp = Upper2LowerTbl3[*p - UL3S];
+ ultp && ultp->upper && memcmp(p, ultp->upper, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memcpy(lp, p, sz);
+ } if (ultp->upper) { /* matched */
+ memcpy(lp, ultp->lower, sz);
+ } else {
+ memcpy(lp, p, sz);
+ }
+ break;
+ case 4:
+ memcpy(lp, p, sz);
+ break;
+ default: /* not UTF-8 */
+ free(lphead);
+ return NULL;
+ }
+ lp += sz;
+ p = np;
+ if (p == tail) {
+ break;
+ }
+ }
+ *lp = '\0';
+ return lphead;
+}
+
+/*
+ * dsgw_utf8ToLower: translate upper-case character to lower-case
+ *
+ * input: a UTF-8 character (s)
+ * output: a UTF-8 character which is converted to lower-case (d)
+ * length (in bytes) of input character (ssz) and
+ * output character (dsz)
+ *
+ * Notes: This function takes a UTF-8 character (could be multiple bytes)
+ * for the input. Memory for the output character is NOT allocated
+ * in this function, caller should have allocated it (d).
+ * "memmove" is used since (s) and (d) are overlapped.
+ */
+void
+dsgw_utf8ToLower(unsigned char *s, unsigned char *d, int *ssz, int *dsz)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *tail;
+
+ if (s == NULL || *s == '\0') {
+ *ssz = *dsz = 0;
+ return;
+ }
+ if (!(*s & 0x80)) { /* ASCII */
+ *dsz = *ssz = 1;
+ *d = tolower(*s);
+ return;
+ }
+ tail = (unsigned char *)ldap_utf8next((char *)s);
+ *dsz = *ssz = tail - s;
+ switch(*ssz) {
+ case 1: /* ASCII */
+ *d = tolower(*s);
+ break;
+ case 2: /* 2 bytes */
+ if (*s < UL2S || *s > UL2E) { /* out of range */
+ memmove(d, s, *ssz);
+ break;
+ }
+ for (ultp = Upper2LowerTbl2[*s - UL2S];
+ ultp && ultp->upper && memcmp(s, ultp->upper, *ssz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memmove(d, s, *ssz);
+ } else if (ultp->upper) { /* matched */
+ memmove(d, ultp->lower, ultp->tsz);
+ *dsz = ultp->tsz;
+ } else {
+ memmove(d, s, *ssz);
+ }
+ break;
+ case 3: /* 3 bytes */
+ if (*s != UL3S && *s != UL3E) { /* out of range */
+ memmove(d, s, *ssz);
+ break;
+ }
+ for (ultp = Upper2LowerTbl3[*s - UL3S];
+ ultp && ultp->upper && memcmp(s, ultp->upper, *ssz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memmove(d, s, *ssz);
+ } else if (ultp->upper) { /* matched */
+ memmove(d, ultp->lower, *ssz);
+ } else {
+ memmove(d, s, *ssz);
+ }
+ break;
+ }
+ return;
+}
+
+/*
+ * dsgw_utf8isUpper: tests for a character that is a upper-case letter in
+ * UTF-8
+ *
+ * input: a UTF-8 character (could be multi-byte)
+ * output: 1 if the character is a upper-case letter
+ * 0 if the character is not a upper-case letter
+ */
+int
+dsgw_utf8isUpper(unsigned char *s)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *next;
+ int sz;
+
+ if (s == NULL || *s == '\0') {
+ return 0;
+ }
+ if (!(*s & 0x80)) { /* ASCII */
+ return isupper(*s);
+ }
+ next = (unsigned char *)ldap_utf8next((char *)s);
+ switch(sz = next - s) {
+ case 1: /* ASCII */
+ return isupper(*s);
+ case 2:
+ if (*s < UL2S || *s > UL2E) { /* out of range */
+ return 0;
+ }
+ for (ultp = Upper2LowerTbl2[*s - UL2S];
+ ultp && ultp->upper && memcmp(s, ultp->upper, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ return 0;
+ } if (ultp->upper) { /* matched */
+ return 1;
+ } else {
+ return 0;
+ }
+ case 3:
+ if (*s < UL3S || *s > UL3E) { /* out of range */
+ return 0;
+ }
+ for (ultp = Upper2LowerTbl3[*s - UL3S];
+ ultp && ultp->upper && memcmp(s, ultp->upper, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ return 0;
+ } if (ultp->upper) { /* matched */
+ return 1;
+ } else {
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Lower2Upper Tables: sorted by lower characters
+ */
+UpperLowerTbl_t Lower2UpperTbl20[] = {
+ /* upper, lower */
+ {"\303\200", "\303\240", 2},
+ {"\303\201", "\303\241", 2},
+ {"\303\202", "\303\242", 2},
+ {"\303\203", "\303\243", 2},
+ {"\303\204", "\303\244", 2},
+ {"\303\205", "\303\245", 2},
+ {"\303\206", "\303\246", 2},
+ {"\303\207", "\303\247", 2},
+ {"\303\210", "\303\250", 2},
+ {"\303\211", "\303\251", 2},
+ {"\303\212", "\303\252", 2},
+ {"\303\213", "\303\253", 2},
+ {"\303\214", "\303\254", 2},
+ {"\303\215", "\303\255", 2},
+ {"\303\216", "\303\256", 2},
+ {"\303\217", "\303\257", 2},
+ {"\303\220", "\303\260", 2},
+ {"\303\221", "\303\261", 2},
+ {"\303\222", "\303\262", 2},
+ {"\303\223", "\303\263", 2},
+ {"\303\224", "\303\264", 2},
+ {"\303\225", "\303\265", 2},
+ {"\303\226", "\303\266", 2},
+ {"\303\230", "\303\270", 2},
+ {"\303\231", "\303\271", 2},
+ {"\303\232", "\303\272", 2},
+ {"\303\233", "\303\273", 2},
+ {"\303\234", "\303\274", 2},
+ {"\303\235", "\303\275", 2},
+ {"\303\236", "\303\276", 2},
+ {"\305\270", "\303\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl21[] = {
+ {"\304\200", "\304\201", 2},
+ {"\304\202", "\304\203", 2},
+ {"\304\204", "\304\205", 2},
+ {"\304\206", "\304\207", 2},
+ {"\304\210", "\304\211", 2},
+ {"\304\212", "\304\213", 2},
+ {"\304\214", "\304\215", 2},
+ {"\304\216", "\304\217", 2},
+ {"\304\220", "\304\221", 2},
+ {"\304\222", "\304\223", 2},
+ {"\304\224", "\304\225", 2},
+ {"\304\226", "\304\227", 2},
+ {"\304\230", "\304\231", 2},
+ {"\304\232", "\304\233", 2},
+ {"\304\234", "\304\235", 2},
+ {"\304\236", "\304\237", 2},
+ {"\304\240", "\304\241", 2},
+ {"\304\242", "\304\243", 2},
+ {"\304\244", "\304\245", 2},
+ {"\304\246", "\304\247", 2},
+ {"\304\250", "\304\251", 2},
+ {"\304\252", "\304\253", 2},
+ {"\304\254", "\304\255", 2},
+ {"\304\256", "\304\257", 2},
+ {"\111", "\304\261", 1},
+ {"\304\262", "\304\263", 2},
+ {"\304\264", "\304\265", 2},
+ {"\304\266", "\304\267", 2},
+ {"\304\271", "\304\272", 2},
+ {"\304\273", "\304\274", 2},
+ {"\304\275", "\304\276", 2},
+ {NULL, NULL}
+};
+
+UpperLowerTbl_t Lower2UpperTbl22[] = {
+ {"\304\277", "\305\200", 2},
+ {"\305\201", "\305\202", 2},
+ {"\305\203", "\305\204", 2},
+ {"\305\205", "\305\206", 2},
+ {"\305\207", "\305\210", 2},
+ {"\305\212", "\305\213", 2},
+ {"\305\214", "\305\215", 2},
+ {"\305\216", "\305\217", 2},
+ {"\305\220", "\305\221", 2},
+ {"\305\222", "\305\223", 2},
+ {"\305\224", "\305\225", 2},
+ {"\305\226", "\305\227", 2},
+ {"\305\230", "\305\231", 2},
+ {"\305\232", "\305\233", 2},
+ {"\305\234", "\305\235", 2},
+ {"\305\236", "\305\237", 2},
+ {"\305\240", "\305\241", 2},
+ {"\305\242", "\305\243", 2},
+ {"\305\244", "\305\245", 2},
+ {"\305\246", "\305\247", 2},
+ {"\305\250", "\305\251", 2},
+ {"\305\252", "\305\253", 2},
+ {"\305\254", "\305\255", 2},
+ {"\305\256", "\305\257", 2},
+ {"\305\260", "\305\261", 2},
+ {"\305\262", "\305\263", 2},
+ {"\305\264", "\305\265", 2},
+ {"\305\266", "\305\267", 2},
+ {"\305\271", "\305\272", 2},
+ {"\305\273", "\305\274", 2},
+ {"\305\275", "\305\276", 2},
+ {"\123", "\305\277", 1},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl23[] = {
+ {"\306\202", "\306\203", 2},
+ {"\306\204", "\306\205", 2},
+ {"\306\207", "\306\210", 2},
+ {"\306\213", "\306\214", 2},
+ {"\306\221", "\306\222", 2},
+ {"\306\230", "\306\231", 2},
+ {"\306\240", "\306\241", 2},
+ {"\306\242", "\306\243", 2},
+ {"\306\244", "\306\245", 2},
+ {"\306\247", "\306\250", 2},
+ {"\306\254", "\306\255", 2},
+ {"\306\257", "\306\260", 2},
+ {"\306\263", "\306\264", 2},
+ {"\306\265", "\306\266", 2},
+ {"\306\270", "\306\271", 2},
+ {"\306\274", "\306\275", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl24[] = {
+ {"\307\204", "\307\206", 2},
+ {"\307\207", "\307\211", 2},
+ {"\307\212", "\307\214", 2},
+ {"\307\215", "\307\216", 2},
+ {"\307\217", "\307\220", 2},
+ {"\307\221", "\307\222", 2},
+ {"\307\223", "\307\224", 2},
+ {"\307\225", "\307\226", 2},
+ {"\307\227", "\307\230", 2},
+ {"\307\231", "\307\232", 2},
+ {"\307\233", "\307\234", 2},
+ {"\307\236", "\307\237", 2},
+ {"\307\240", "\307\241", 2},
+ {"\307\242", "\307\243", 2},
+ {"\307\244", "\307\245", 2},
+ {"\307\246", "\307\247", 2},
+ {"\307\250", "\307\251", 2},
+ {"\307\252", "\307\253", 2},
+ {"\307\254", "\307\255", 2},
+ {"\307\256", "\307\257", 2},
+ {"\307\261", "\307\263", 2},
+ {"\307\264", "\307\265", 2},
+ {"\307\272", "\307\273", 2},
+ {"\307\274", "\307\275", 2},
+ {"\307\276", "\307\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl25[] = {
+ {"\310\200", "\310\201", 2},
+ {"\310\202", "\310\203", 2},
+ {"\310\204", "\310\205", 2},
+ {"\310\206", "\310\207", 2},
+ {"\310\210", "\310\211", 2},
+ {"\310\212", "\310\213", 2},
+ {"\310\214", "\310\215", 2},
+ {"\310\216", "\310\217", 2},
+ {"\310\220", "\310\221", 2},
+ {"\310\222", "\310\223", 2},
+ {"\310\224", "\310\225", 2},
+ {"\310\226", "\310\227", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl26[] = {
+ {"\306\201", "\311\223", 2},
+ {"\306\206", "\311\224", 2},
+ {"\306\211", "\311\226", 2},
+ {"\306\212", "\311\227", 2},
+ {"\306\216", "\311\230", 2},
+ {"\306\217", "\311\231", 2},
+ {"\306\220", "\311\233", 2},
+ {"\306\223", "\311\240", 2},
+ {"\306\224", "\311\243", 2},
+ {"\306\227", "\311\250", 2},
+ {"\306\226", "\311\251", 2},
+ {"\306\234", "\311\257", 2},
+ {"\306\235", "\311\262", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl27[] = {
+ {"\306\251", "\312\203", 2},
+ {"\306\256", "\312\210", 2},
+ {"\306\261", "\312\212", 2},
+ {"\306\262", "\312\213", 2},
+ {"\306\267", "\312\222", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl28[] = {
+ {"\316\206", "\316\254", 2},
+ {"\316\210", "\316\255", 2},
+ {"\316\211", "\316\256", 2},
+ {"\316\212", "\316\257", 2},
+ {"\316\221", "\316\261", 2},
+ {"\316\222", "\316\262", 2},
+ {"\316\223", "\316\263", 2},
+ {"\316\224", "\316\264", 2},
+ {"\316\225", "\316\265", 2},
+ {"\316\226", "\316\266", 2},
+ {"\316\227", "\316\267", 2},
+ {"\316\230", "\316\270", 2},
+ {"\316\231", "\316\271", 2},
+ {"\316\232", "\316\272", 2},
+ {"\316\233", "\316\273", 2},
+ {"\316\234", "\316\274", 2},
+ {"\316\235", "\316\275", 2},
+ {"\316\236", "\316\276", 2},
+ {"\316\237", "\316\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl29[] = {
+ {"\316\240", "\317\200", 2},
+ {"\316\241", "\317\201", 2},
+ {"\316\243", "\317\202", 2},
+ {"\316\243", "\317\203", 2},
+ {"\316\244", "\317\204", 2},
+ {"\316\245", "\317\205", 2},
+ {"\316\246", "\317\206", 2},
+ {"\316\247", "\317\207", 2},
+ {"\316\250", "\317\210", 2},
+ {"\316\251", "\317\211", 2},
+ {"\316\252", "\317\212", 2},
+ {"\316\253", "\317\213", 2},
+ {"\316\214", "\317\214", 2},
+ {"\316\216", "\317\215", 2},
+ {"\316\217", "\317\216", 2},
+ {"\316\222", "\317\220", 2},
+ {"\316\230", "\317\221", 2},
+ {"\316\246", "\317\225", 2},
+ {"\316\240", "\317\226", 2},
+ {"\317\242", "\317\243", 2},
+ {"\317\244", "\317\245", 2},
+ {"\317\246", "\317\247", 2},
+ {"\317\250", "\317\251", 2},
+ {"\317\252", "\317\253", 2},
+ {"\317\254", "\317\255", 2},
+ {"\317\256", "\317\257", 2},
+ {"\316\232", "\317\260", 2},
+ {"\316\241", "\317\261", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2a[] = {
+ {"\320\220", "\320\260", 2},
+ {"\320\221", "\320\261", 2},
+ {"\320\222", "\320\262", 2},
+ {"\320\223", "\320\263", 2},
+ {"\320\224", "\320\264", 2},
+ {"\320\225", "\320\265", 2},
+ {"\320\226", "\320\266", 2},
+ {"\320\227", "\320\267", 2},
+ {"\320\230", "\320\270", 2},
+ {"\320\231", "\320\271", 2},
+ {"\320\232", "\320\272", 2},
+ {"\320\233", "\320\273", 2},
+ {"\320\234", "\320\274", 2},
+ {"\320\235", "\320\275", 2},
+ {"\320\236", "\320\276", 2},
+ {"\320\237", "\320\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2b[] = {
+ {"\320\240", "\321\200", 2},
+ {"\320\241", "\321\201", 2},
+ {"\320\242", "\321\202", 2},
+ {"\320\243", "\321\203", 2},
+ {"\320\244", "\321\204", 2},
+ {"\320\245", "\321\205", 2},
+ {"\320\246", "\321\206", 2},
+ {"\320\247", "\321\207", 2},
+ {"\320\250", "\321\210", 2},
+ {"\320\251", "\321\211", 2},
+ {"\320\252", "\321\212", 2},
+ {"\320\253", "\321\213", 2},
+ {"\320\254", "\321\214", 2},
+ {"\320\255", "\321\215", 2},
+ {"\320\256", "\321\216", 2},
+ {"\320\257", "\321\217", 2},
+ {"\320\201", "\321\221", 2},
+ {"\320\202", "\321\222", 2},
+ {"\320\203", "\321\223", 2},
+ {"\320\204", "\321\224", 2},
+ {"\320\205", "\321\225", 2},
+ {"\320\206", "\321\226", 2},
+ {"\320\207", "\321\227", 2},
+ {"\320\210", "\321\230", 2},
+ {"\320\211", "\321\231", 2},
+ {"\320\212", "\321\232", 2},
+ {"\320\213", "\321\233", 2},
+ {"\320\214", "\321\234", 2},
+ {"\320\216", "\321\236", 2},
+ {"\320\217", "\321\237", 2},
+ {"\321\240", "\321\241", 2},
+ {"\321\242", "\321\243", 2},
+ {"\321\244", "\321\245", 2},
+ {"\321\246", "\321\247", 2},
+ {"\321\250", "\321\251", 2},
+ {"\321\252", "\321\253", 2},
+ {"\321\254", "\321\255", 2},
+ {"\321\256", "\321\257", 2},
+ {"\321\260", "\321\261", 2},
+ {"\321\262", "\321\263", 2},
+ {"\321\264", "\321\265", 2},
+ {"\321\266", "\321\267", 2},
+ {"\321\270", "\321\271", 2},
+ {"\321\272", "\321\273", 2},
+ {"\321\274", "\321\275", 2},
+ {"\321\276", "\321\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2c[] = {
+ {"\322\200", "\322\201", 2},
+ {"\322\220", "\322\221", 2},
+ {"\322\222", "\322\223", 2},
+ {"\322\224", "\322\225", 2},
+ {"\322\226", "\322\227", 2},
+ {"\322\230", "\322\231", 2},
+ {"\322\232", "\322\233", 2},
+ {"\322\234", "\322\235", 2},
+ {"\322\236", "\322\237", 2},
+ {"\322\240", "\322\241", 2},
+ {"\322\242", "\322\243", 2},
+ {"\322\244", "\322\245", 2},
+ {"\322\246", "\322\247", 2},
+ {"\322\250", "\322\251", 2},
+ {"\322\252", "\322\253", 2},
+ {"\322\254", "\322\255", 2},
+ {"\322\256", "\322\257", 2},
+ {"\322\260", "\322\261", 2},
+ {"\322\262", "\322\263", 2},
+ {"\322\264", "\322\265", 2},
+ {"\322\266", "\322\267", 2},
+ {"\322\270", "\322\271", 2},
+ {"\322\272", "\322\273", 2},
+ {"\322\274", "\322\275", 2},
+ {"\322\276", "\322\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2d[] = {
+ {"\323\201", "\323\202", 2},
+ {"\323\203", "\323\204", 2},
+ {"\323\207", "\323\210", 2},
+ {"\323\213", "\323\214", 2},
+ {"\323\220", "\323\221", 2},
+ {"\323\222", "\323\223", 2},
+ {"\323\224", "\323\225", 2},
+ {"\323\226", "\323\227", 2},
+ {"\323\230", "\323\231", 2},
+ {"\323\232", "\323\233", 2},
+ {"\323\234", "\323\235", 2},
+ {"\323\236", "\323\237", 2},
+ {"\323\240", "\323\241", 2},
+ {"\323\242", "\323\243", 2},
+ {"\323\244", "\323\245", 2},
+ {"\323\246", "\323\247", 2},
+ {"\323\250", "\323\251", 2},
+ {"\323\252", "\323\253", 2},
+ {"\323\256", "\323\257", 2},
+ {"\323\260", "\323\261", 2},
+ {"\323\262", "\323\263", 2},
+ {"\323\264", "\323\265", 2},
+ {"\323\270", "\323\271", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2e[] = {
+ {"\324\261", "\325\241", 2},
+ {"\324\262", "\325\242", 2},
+ {"\324\263", "\325\243", 2},
+ {"\324\264", "\325\244", 2},
+ {"\324\265", "\325\245", 2},
+ {"\324\266", "\325\246", 2},
+ {"\324\267", "\325\247", 2},
+ {"\324\270", "\325\250", 2},
+ {"\324\271", "\325\251", 2},
+ {"\324\272", "\325\252", 2},
+ {"\324\273", "\325\253", 2},
+ {"\324\274", "\325\254", 2},
+ {"\324\275", "\325\255", 2},
+ {"\324\276", "\325\256", 2},
+ {"\324\277", "\325\257", 2},
+ {"\325\200", "\325\260", 2},
+ {"\325\201", "\325\261", 2},
+ {"\325\202", "\325\262", 2},
+ {"\325\203", "\325\263", 2},
+ {"\325\204", "\325\264", 2},
+ {"\325\205", "\325\265", 2},
+ {"\325\206", "\325\266", 2},
+ {"\325\207", "\325\267", 2},
+ {"\325\210", "\325\270", 2},
+ {"\325\211", "\325\271", 2},
+ {"\325\212", "\325\272", 2},
+ {"\325\213", "\325\273", 2},
+ {"\325\214", "\325\274", 2},
+ {"\325\215", "\325\275", 2},
+ {"\325\216", "\325\276", 2},
+ {"\325\217", "\325\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2f[] = {
+ {"\325\220", "\326\200", 2},
+ {"\325\221", "\326\201", 2},
+ {"\325\222", "\326\202", 2},
+ {"\325\223", "\326\203", 2},
+ {"\325\224", "\326\204", 2},
+ {"\325\225", "\326\205", 2},
+ {"\325\226", "\326\206", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl30[] = {
+ {"\341\202\240", "\341\203\220", 3},
+ {"\341\202\241", "\341\203\221", 3},
+ {"\341\202\242", "\341\203\222", 3},
+ {"\341\202\243", "\341\203\223", 3},
+ {"\341\202\244", "\341\203\224", 3},
+ {"\341\202\245", "\341\203\225", 3},
+ {"\341\202\246", "\341\203\226", 3},
+ {"\341\202\247", "\341\203\227", 3},
+ {"\341\202\250", "\341\203\230", 3},
+ {"\341\202\251", "\341\203\231", 3},
+ {"\341\202\252", "\341\203\232", 3},
+ {"\341\202\253", "\341\203\233", 3},
+ {"\341\202\254", "\341\203\234", 3},
+ {"\341\202\255", "\341\203\235", 3},
+ {"\341\202\256", "\341\203\236", 3},
+ {"\341\202\257", "\341\203\237", 3},
+ {"\341\202\260", "\341\203\240", 3},
+ {"\341\202\261", "\341\203\241", 3},
+ {"\341\202\262", "\341\203\242", 3},
+ {"\341\202\263", "\341\203\243", 3},
+ {"\341\202\264", "\341\203\244", 3},
+ {"\341\202\265", "\341\203\245", 3},
+ {"\341\202\266", "\341\203\246", 3},
+ {"\341\202\267", "\341\203\247", 3},
+ {"\341\202\270", "\341\203\250", 3},
+ {"\341\202\271", "\341\203\251", 3},
+ {"\341\202\272", "\341\203\252", 3},
+ {"\341\202\273", "\341\203\253", 3},
+ {"\341\202\274", "\341\203\254", 3},
+ {"\341\202\275", "\341\203\255", 3},
+ {"\341\202\276", "\341\203\256", 3},
+ {"\341\202\277", "\341\203\257", 3},
+ {"\341\203\200", "\341\203\260", 3},
+ {"\341\203\201", "\341\203\261", 3},
+ {"\341\203\202", "\341\203\262", 3},
+ {"\341\203\203", "\341\203\263", 3},
+ {"\341\203\204", "\341\203\264", 3},
+ {"\341\203\205", "\341\203\265", 3},
+ {"\341\270\200", "\341\270\201", 3},
+ {"\341\270\202", "\341\270\203", 3},
+ {"\341\270\204", "\341\270\205", 3},
+ {"\341\270\206", "\341\270\207", 3},
+ {"\341\270\210", "\341\270\211", 3},
+ {"\341\270\212", "\341\270\213", 3},
+ {"\341\270\214", "\341\270\215", 3},
+ {"\341\270\216", "\341\270\217", 3},
+ {"\341\270\220", "\341\270\221", 3},
+ {"\341\270\222", "\341\270\223", 3},
+ {"\341\270\224", "\341\270\225", 3},
+ {"\341\270\226", "\341\270\227", 3},
+ {"\341\270\230", "\341\270\231", 3},
+ {"\341\270\232", "\341\270\233", 3},
+ {"\341\270\234", "\341\270\235", 3},
+ {"\341\270\236", "\341\270\237", 3},
+ {"\341\270\240", "\341\270\241", 3},
+ {"\341\270\242", "\341\270\243", 3},
+ {"\341\270\244", "\341\270\245", 3},
+ {"\341\270\246", "\341\270\247", 3},
+ {"\341\270\250", "\341\270\251", 3},
+ {"\341\270\252", "\341\270\253", 3},
+ {"\341\270\254", "\341\270\255", 3},
+ {"\341\270\256", "\341\270\257", 3},
+ {"\341\270\260", "\341\270\261", 3},
+ {"\341\270\262", "\341\270\263", 3},
+ {"\341\270\264", "\341\270\265", 3},
+ {"\341\270\266", "\341\270\267", 3},
+ {"\341\270\270", "\341\270\271", 3},
+ {"\341\270\272", "\341\270\273", 3},
+ {"\341\270\274", "\341\270\275", 3},
+ {"\341\270\276", "\341\270\277", 3},
+ {"\341\271\200", "\341\271\201", 3},
+ {"\341\271\202", "\341\271\203", 3},
+ {"\341\271\204", "\341\271\205", 3},
+ {"\341\271\206", "\341\271\207", 3},
+ {"\341\271\210", "\341\271\211", 3},
+ {"\341\271\212", "\341\271\213", 3},
+ {"\341\271\214", "\341\271\215", 3},
+ {"\341\271\216", "\341\271\217", 3},
+ {"\341\271\220", "\341\271\221", 3},
+ {"\341\271\222", "\341\271\223", 3},
+ {"\341\271\224", "\341\271\225", 3},
+ {"\341\271\226", "\341\271\227", 3},
+ {"\341\271\230", "\341\271\231", 3},
+ {"\341\271\232", "\341\271\233", 3},
+ {"\341\271\234", "\341\271\235", 3},
+ {"\341\271\236", "\341\271\237", 3},
+ {"\341\271\240", "\341\271\241", 3},
+ {"\341\271\242", "\341\271\243", 3},
+ {"\341\271\244", "\341\271\245", 3},
+ {"\341\271\246", "\341\271\247", 3},
+ {"\341\271\250", "\341\271\251", 3},
+ {"\341\271\252", "\341\271\253", 3},
+ {"\341\271\254", "\341\271\255", 3},
+ {"\341\271\256", "\341\271\257", 3},
+ {"\341\271\260", "\341\271\261", 3},
+ {"\341\271\262", "\341\271\263", 3},
+ {"\341\271\264", "\341\271\265", 3},
+ {"\341\271\266", "\341\271\267", 3},
+ {"\341\271\270", "\341\271\271", 3},
+ {"\341\271\272", "\341\271\273", 3},
+ {"\341\271\274", "\341\271\275", 3},
+ {"\341\271\276", "\341\271\277", 3},
+ {"\341\272\200", "\341\272\201", 3},
+ {"\341\272\202", "\341\272\203", 3},
+ {"\341\272\204", "\341\272\205", 3},
+ {"\341\272\206", "\341\272\207", 3},
+ {"\341\272\210", "\341\272\211", 3},
+ {"\341\272\212", "\341\272\213", 3},
+ {"\341\272\214", "\341\272\215", 3},
+ {"\341\272\216", "\341\272\217", 3},
+ {"\341\272\220", "\341\272\221", 3},
+ {"\341\272\222", "\341\272\223", 3},
+ {"\341\272\224", "\341\272\225", 3},
+ {"\341\272\240", "\341\272\241", 3},
+ {"\341\272\242", "\341\272\243", 3},
+ {"\341\272\244", "\341\272\245", 3},
+ {"\341\272\246", "\341\272\247", 3},
+ {"\341\272\250", "\341\272\251", 3},
+ {"\341\272\252", "\341\272\253", 3},
+ {"\341\272\254", "\341\272\255", 3},
+ {"\341\272\256", "\341\272\257", 3},
+ {"\341\272\260", "\341\272\261", 3},
+ {"\341\272\262", "\341\272\263", 3},
+ {"\341\272\264", "\341\272\265", 3},
+ {"\341\272\266", "\341\272\267", 3},
+ {"\341\272\270", "\341\272\271", 3},
+ {"\341\272\272", "\341\272\273", 3},
+ {"\341\272\274", "\341\272\275", 3},
+ {"\341\272\276", "\341\272\277", 3},
+ {"\341\273\200", "\341\273\201", 3},
+ {"\341\273\202", "\341\273\203", 3},
+ {"\341\273\204", "\341\273\205", 3},
+ {"\341\273\206", "\341\273\207", 3},
+ {"\341\273\210", "\341\273\211", 3},
+ {"\341\273\212", "\341\273\213", 3},
+ {"\341\273\214", "\341\273\215", 3},
+ {"\341\273\216", "\341\273\217", 3},
+ {"\341\273\220", "\341\273\221", 3},
+ {"\341\273\222", "\341\273\223", 3},
+ {"\341\273\224", "\341\273\225", 3},
+ {"\341\273\226", "\341\273\227", 3},
+ {"\341\273\230", "\341\273\231", 3},
+ {"\341\273\232", "\341\273\233", 3},
+ {"\341\273\234", "\341\273\235", 3},
+ {"\341\273\236", "\341\273\237", 3},
+ {"\341\273\240", "\341\273\241", 3},
+ {"\341\273\242", "\341\273\243", 3},
+ {"\341\273\244", "\341\273\245", 3},
+ {"\341\273\246", "\341\273\247", 3},
+ {"\341\273\250", "\341\273\251", 3},
+ {"\341\273\252", "\341\273\253", 3},
+ {"\341\273\254", "\341\273\255", 3},
+ {"\341\273\256", "\341\273\257", 3},
+ {"\341\273\260", "\341\273\261", 3},
+ {"\341\273\262", "\341\273\263", 3},
+ {"\341\273\264", "\341\273\265", 3},
+ {"\341\273\266", "\341\273\267", 3},
+ {"\341\273\270", "\341\273\271", 3},
+ {"\341\274\210", "\341\274\200", 3},
+ {"\341\274\211", "\341\274\201", 3},
+ {"\341\274\212", "\341\274\202", 3},
+ {"\341\274\213", "\341\274\203", 3},
+ {"\341\274\214", "\341\274\204", 3},
+ {"\341\274\215", "\341\274\205", 3},
+ {"\341\274\216", "\341\274\206", 3},
+ {"\341\274\217", "\341\274\207", 3},
+ {"\341\274\230", "\341\274\220", 3},
+ {"\341\274\231", "\341\274\221", 3},
+ {"\341\274\232", "\341\274\222", 3},
+ {"\341\274\233", "\341\274\223", 3},
+ {"\341\274\234", "\341\274\224", 3},
+ {"\341\274\235", "\341\274\225", 3},
+ {"\341\274\250", "\341\274\240", 3},
+ {"\341\274\251", "\341\274\241", 3},
+ {"\341\274\252", "\341\274\242", 3},
+ {"\341\274\253", "\341\274\243", 3},
+ {"\341\274\254", "\341\274\244", 3},
+ {"\341\274\255", "\341\274\245", 3},
+ {"\341\274\256", "\341\274\246", 3},
+ {"\341\274\257", "\341\274\247", 3},
+ {"\341\274\270", "\341\274\260", 3},
+ {"\341\274\271", "\341\274\261", 3},
+ {"\341\274\272", "\341\274\262", 3},
+ {"\341\274\273", "\341\274\263", 3},
+ {"\341\274\274", "\341\274\264", 3},
+ {"\341\274\275", "\341\274\265", 3},
+ {"\341\274\276", "\341\274\266", 3},
+ {"\341\274\277", "\341\274\267", 3},
+ {"\341\275\210", "\341\275\200", 3},
+ {"\341\275\211", "\341\275\201", 3},
+ {"\341\275\212", "\341\275\202", 3},
+ {"\341\275\213", "\341\275\203", 3},
+ {"\341\275\214", "\341\275\204", 3},
+ {"\341\275\215", "\341\275\205", 3},
+ {"\341\275\231", "\341\275\221", 3},
+ {"\341\275\233", "\341\275\223", 3},
+ {"\341\275\235", "\341\275\225", 3},
+ {"\341\275\237", "\341\275\227", 3},
+ {"\341\275\250", "\341\275\240", 3},
+ {"\341\275\251", "\341\275\241", 3},
+ {"\341\275\252", "\341\275\242", 3},
+ {"\341\275\253", "\341\275\243", 3},
+ {"\341\275\254", "\341\275\244", 3},
+ {"\341\275\255", "\341\275\245", 3},
+ {"\341\275\256", "\341\275\246", 3},
+ {"\341\275\257", "\341\275\247", 3},
+ {"\341\276\272", "\341\275\260", 3},
+ {"\341\276\273", "\341\275\261", 3},
+ {"\341\277\210", "\341\275\262", 3},
+ {"\341\277\211", "\341\275\263", 3},
+ {"\341\277\212", "\341\275\264", 3},
+ {"\341\277\213", "\341\275\265", 3},
+ {"\341\277\232", "\341\275\266", 3},
+ {"\341\277\233", "\341\275\267", 3},
+ {"\341\277\270", "\341\275\270", 3},
+ {"\341\277\271", "\341\275\271", 3},
+ {"\341\277\252", "\341\275\272", 3},
+ {"\341\277\253", "\341\275\273", 3},
+ {"\341\277\272", "\341\275\274", 3},
+ {"\341\277\273", "\341\275\275", 3},
+ {"\341\276\210", "\341\276\200", 3},
+ {"\341\276\211", "\341\276\201", 3},
+ {"\341\276\212", "\341\276\202", 3},
+ {"\341\276\213", "\341\276\203", 3},
+ {"\341\276\214", "\341\276\204", 3},
+ {"\341\276\215", "\341\276\205", 3},
+ {"\341\276\216", "\341\276\206", 3},
+ {"\341\276\217", "\341\276\207", 3},
+ {"\341\276\230", "\341\276\220", 3},
+ {"\341\276\231", "\341\276\221", 3},
+ {"\341\276\232", "\341\276\222", 3},
+ {"\341\276\233", "\341\276\223", 3},
+ {"\341\276\234", "\341\276\224", 3},
+ {"\341\276\235", "\341\276\225", 3},
+ {"\341\276\236", "\341\276\226", 3},
+ {"\341\276\237", "\341\276\227", 3},
+ {"\341\276\250", "\341\276\240", 3},
+ {"\341\276\251", "\341\276\241", 3},
+ {"\341\276\252", "\341\276\242", 3},
+ {"\341\276\253", "\341\276\243", 3},
+ {"\341\276\254", "\341\276\244", 3},
+ {"\341\276\255", "\341\276\245", 3},
+ {"\341\276\256", "\341\276\246", 3},
+ {"\341\276\257", "\341\276\247", 3},
+ {"\341\276\270", "\341\276\260", 3},
+ {"\341\276\271", "\341\276\261", 3},
+ {"\341\276\274", "\341\276\263", 3},
+ {"\341\277\214", "\341\277\203", 3},
+ {"\341\277\230", "\341\277\220", 3},
+ {"\341\277\231", "\341\277\221", 3},
+ {"\341\277\250", "\341\277\240", 3},
+ {"\341\277\251", "\341\277\241", 3},
+ {"\341\277\254", "\341\277\245", 3},
+ {"\341\277\274", "\341\277\263", 3},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl31[] = {
+ {"\357\274\241", "\357\275\201", 3},
+ {"\357\274\242", "\357\275\202", 3},
+ {"\357\274\243", "\357\275\203", 3},
+ {"\357\274\244", "\357\275\204", 3},
+ {"\357\274\245", "\357\275\205", 3},
+ {"\357\274\246", "\357\275\206", 3},
+ {"\357\274\247", "\357\275\207", 3},
+ {"\357\274\250", "\357\275\210", 3},
+ {"\357\274\251", "\357\275\211", 3},
+ {"\357\274\252", "\357\275\212", 3},
+ {"\357\274\253", "\357\275\213", 3},
+ {"\357\274\254", "\357\275\214", 3},
+ {"\357\274\255", "\357\275\215", 3},
+ {"\357\274\256", "\357\275\216", 3},
+ {"\357\274\257", "\357\275\217", 3},
+ {"\357\274\260", "\357\275\220", 3},
+ {"\357\274\261", "\357\275\221", 3},
+ {"\357\274\262", "\357\275\222", 3},
+ {"\357\274\263", "\357\275\223", 3},
+ {"\357\274\264", "\357\275\224", 3},
+ {"\357\274\265", "\357\275\225", 3},
+ {"\357\274\266", "\357\275\226", 3},
+ {"\357\274\267", "\357\275\227", 3},
+ {"\357\274\270", "\357\275\230", 3},
+ {"\357\274\271", "\357\275\231", 3},
+ {"\357\274\272", "\357\275\232", 3},
+ {NULL, NULL, 0}
+ /* upper, lower */
+};
+
+UpperLowerTbl_t *Lower2UpperTbl2[] = {
+ Lower2UpperTbl20, /* \303 */
+ Lower2UpperTbl21, /* \304 */
+ Lower2UpperTbl22, /* \305 */
+ Lower2UpperTbl23, /* \306 */
+ Lower2UpperTbl24, /* \307 */
+ Lower2UpperTbl25, /* \310 */
+ Lower2UpperTbl26, /* \311 */
+ Lower2UpperTbl27, /* \312 */
+ NULL, /* \313 */
+ NULL, /* \314 */
+ NULL, /* \315 */
+ Lower2UpperTbl28, /* \316 */
+ Lower2UpperTbl29, /* \317 */
+ Lower2UpperTbl2a, /* \320 */
+ Lower2UpperTbl2b, /* \321 */
+ Lower2UpperTbl2c, /* \322 */
+ Lower2UpperTbl2d, /* \323 */
+ NULL, /* \324 */
+ Lower2UpperTbl2e, /* \325 */
+ Lower2UpperTbl2f /* \326 */
+};
+
+UpperLowerTbl_t *Lower2UpperTbl3[] = {
+ Lower2UpperTbl30, /* \341 */
+ NULL, /* \342 */
+ NULL, /* \343 */
+ NULL, /* \344 */
+ NULL, /* \345 */
+ NULL, /* \346 */
+ NULL, /* \347 */
+ NULL, /* \350 */
+ NULL, /* \351 */
+ NULL, /* \352 */
+ NULL, /* \353 */
+ NULL, /* \354 */
+ NULL, /* \355 */
+ NULL, /* \356 */
+ Lower2UpperTbl31 /* \357 */
+};
+
+#define LU2S (unsigned char)'\303'
+#define LU2E (unsigned char)'\326'
+#define LU3S (unsigned char)'\341'
+#define LU3E (unsigned char)'\357'
+
+/*
+ * dsgw_utf8StrToUpper: translate lower-case string to upper-case
+ *
+ * input: a null terminated UTF-8 string
+ * output: a null terminated UTF-8 string which characters are
+ * converted to upper-case; characters which are not
+ * lower-case are copied as is. If it's not considered
+ * a UTF-8 string, NULL is returned.
+ *
+ * Notes: This function takes a string (made of multiple UTF-8 characters)
+ * for the input (not one character as in "toupper").
+ * Output string is allocated in this function, which needs to be
+ * released when it's not needed any more.
+ */
+unsigned char *
+dsgw_utf8StrToUpper(unsigned char *s)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *p, *np, *tail;
+ unsigned char *up, *uphead;
+ int len, sz;
+
+ if (s == NULL || *s == '\0') {
+ return s;
+ }
+ len = strlen((char *)s);
+ tail = s + len;
+ uphead = up = (unsigned char *)dsgw_ch_malloc(len + 1);
+ p = s;
+ while ((np = (unsigned char *)ldap_utf8next((char *)p)) <= tail) {
+ switch(sz = np - p) {
+ case 1: /* ASCII */
+ sprintf((char *)up, "%c", toupper(*p));
+ break;
+ case 2: /* 2 bytes */
+ if (*p < LU2S || *p > LU2E) { /* out of range */
+ memcpy(up, p, sz);
+ break;
+ }
+ for (ultp = Lower2UpperTbl2[*p - LU2S];
+ ultp && ultp->lower && memcmp(p, ultp->lower, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memcpy(up, p, sz);
+ } if (ultp->lower) { /* matched */
+ memcpy(up, ultp->upper, ultp->tsz);
+ sz = ultp->tsz;
+ } else {
+ memcpy(up, p, sz);
+ }
+ break;
+ case 3: /* 3 bytes */
+ if (*p != LU3S && *p != LU3E) { /* out of range */
+ memcpy(up, p, sz);
+ break;
+ }
+ for (ultp = Lower2UpperTbl3[*p - LU3S];
+ ultp && ultp->lower && memcmp(p, ultp->lower, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memcpy(up, p, sz);
+ } if (ultp->lower) { /* matched */
+ memcpy(up, ultp->upper, sz);
+ } else {
+ memcpy(up, p, sz);
+ }
+ break;
+ case 4:
+ memcpy(up, p, sz);
+ break;
+ default: /* not UTF-8 */
+ free(uphead);
+ return NULL;
+ }
+ up += sz;
+ p = np;
+ if (p == tail) {
+ break;
+ }
+ }
+ *up = '\0';
+ return uphead;
+}
+
+/*
+ * dsgw_utf8ToUpper: translate lower-case character to upper-case
+ *
+ * input: a UTF-8 character (s)
+ * output: a UTF-8 character which is converted to upper-case (d)
+ * length (in bytes) of input character (ssz) and
+ * output character (dsz)
+ *
+ * Notes: This function takes a UTF-8 character (could be multiple bytes)
+ * for the input. Memory for the output character is NOT allocated
+ * in this function, caller should have allocated it (d).
+ * "memmove" is used since (s) and (d) are overlapped.
+ */
+void
+dsgw_utf8ToUpper(unsigned char *s, unsigned char *d, int *ssz, int *dsz)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *tail;
+
+ if (s == NULL || *s == '\0') {
+ *ssz = *dsz = 0;
+ return;
+ }
+ if (!(*s & 0x80)) { /* ASCII */
+ *dsz = *ssz = 1;
+ *d = toupper(*s);
+ return;
+ }
+ tail = (unsigned char *)ldap_utf8next((char *)s);
+ *dsz = *ssz = tail - s;
+ switch(*ssz) {
+ case 1: /* ASCII */
+ *d = toupper(*s);
+ break;
+ case 2: /* 2 bytes */
+ if (*s < LU2S || *s > LU2E) { /* out of range */
+ memmove(d, s, *ssz);
+ break;
+ }
+ for (ultp = Lower2UpperTbl2[*s - LU2S];
+ ultp && ultp->lower && memcmp(s, ultp->lower, *ssz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memmove(d, s, *ssz);
+ } else if (ultp->lower) { /* matched */
+ memmove(d, ultp->upper, ultp->tsz);
+ *dsz = ultp->tsz;
+ } else {
+ memmove(d, s, *ssz);
+ }
+ break;
+ case 3: /* 3 bytes */
+ if (*s != LU3S && *s != LU3E) { /* out of range */
+ memmove(d, s, *ssz);
+ break;
+ }
+ for (ultp = Lower2UpperTbl3[*s - LU3S];
+ ultp && ultp->lower && memcmp(s, ultp->lower, *ssz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memmove(d, s, *ssz);
+ } else if (ultp->lower) { /* matched */
+ memmove(d, ultp->upper, *ssz);
+ } else {
+ memmove(d, s, *ssz);
+ }
+ break;
+ }
+ return;
+}
+
+/*
+ * dsgw_utf8isLower: tests for a character that is a lower-case letter in
+ * UTF-8
+ *
+ * input: a UTF-8 character (could be multi-byte)
+ * output: 1 if the character is a lower-case letter
+ * 0 if the character is not a lower-case letter
+ */
+int
+dsgw_utf8isLower(unsigned char *s)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *next;
+ int sz;
+
+ if (s == NULL || *s == '\0') {
+ return 0;
+ }
+ if (!(*s & 0x80)) { /* ASCII */
+ return islower(*s);
+ }
+ next = (unsigned char *)ldap_utf8next((char *)s);
+ switch(sz = next - s) {
+ case 1: /* ASCII */
+ return islower(*s);
+ case 2:
+ if (*s < LU2S || *s > LU2E) { /* out of range */
+ return 0;
+ }
+ for (ultp = Lower2UpperTbl2[*s - LU2S];
+ ultp && ultp->lower && memcmp(s, ultp->lower, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ return 0;
+ } if (ultp->lower) { /* matched */
+ return 1;
+ } else {
+ return 0;
+ }
+ case 3:
+ if (*s < LU3S || *s > LU3E) { /* out of range */
+ return 0;
+ }
+ for (ultp = Lower2UpperTbl3[*s - LU3S];
+ ultp && ultp->lower && memcmp(s, ultp->lower, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ return 0;
+ } if (ultp->lower) { /* matched */
+ return 1;
+ } else {
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+/*
+ * dsgw_utf8casecmp: case-insensitive string compare for UTF-8 strings
+ *
+ * input: two UTF-8 strings (s0, s1) to be compared
+ * output: positive number, if s0 is after s1
+ * 0, if the two strings are identical ignoring the case
+ * negative number, if s1 is after s0
+ *
+ * Rules: If both UTF-8 strings are NULL or 0-length, 0 is returned.
+ * If one of the strings is NULL or 0-length, the NULL/0-length
+ * string is smaller.
+ * If one or both of the strings are not UTF-8, system provided
+ * strcasecmp is used.
+ * If one of the two strings contains no 8-bit characters,
+ * strcasecmp is used.
+ * The strings are compared after converted to lower-case UTF-8.
+ * Each character is compared from the beginning.
+ * Evaluation goes in this order:
+ * If the length of one character is shorter then the other,
+ * the difference of the two lengths is returned.
+ * If the length of the corresponsing characters is same,
+ * each byte in the characters is compared.
+ * If there's a difference between two bytes,
+ * the diff is returned.
+ * If one string is shorter then the other, the diff is returned.
+ *
+ * Notes: Don't use this function for collation
+ * 1) there's no notion of locale in this function.
+ * 2) it's UTF-8 code order, which is different from the locale
+ * based collation.
+ */
+int
+dsgw_utf8casecmp(unsigned char *s0, unsigned char *s1)
+{
+ unsigned char *d0, *d1; /* store lower-case strings */
+ unsigned char *p0, *p1; /* current UTF-8 char */
+ unsigned char *n0, *n1; /* next UTF-8 char */
+ unsigned char *t0, *t1; /* tail of the strings */
+ unsigned char *x0, *x1; /* current byte in a char */
+ int i0, i1; /* length of characters */
+ int l0, l1; /* length of leftover */
+ int rval;
+ int has8_s0;
+ int has8_s1;
+
+ d0 = d1 = NULL;
+ if (s0 == NULL || *s0 == '\0') {
+ if (s1 == NULL || *s1 == '\0') {
+ rval = 0;
+ } else {
+ rval = -1; /* regardless s1, s0 < s1 */
+ }
+ goto end;
+ } else if (s1 == NULL || *s1 == '\0') {
+ rval = 1; /* regardless s0, s0 > s1 */
+ goto end;
+ }
+
+ has8_s0 = dsgw_has8thBit(s0);
+ has8_s1 = dsgw_has8thBit(s1);
+ if (has8_s0 == has8_s1) { /* both has-8th-bit or both do not */
+ if (has8_s0 == 0) { /* neither has-8th-bit */
+ rval = strcasecmp((char *)s0, (char *)s1);
+ goto end;
+ }
+ } else { /* one has and the other do not */
+ rval = strcasecmp((char *)s0, (char *)s1);
+ goto end;
+ }
+
+ d0 = dsgw_utf8StrToLower(s0);
+ d1 = dsgw_utf8StrToLower(s1);
+ if (d0 == NULL || d1 == NULL || /* either is not a UTF-8 string */
+ (d0 && *d0 == '\0') || (d1 && *d1 == '\0')) {
+ rval = strcasecmp((char *)s0, (char *)s1);
+ goto end;
+ }
+
+ p0 = d0;
+ p1 = d1;
+
+ t0 = d0 + strlen((char *)d0);
+ t1 = d1 + strlen((char *)d1);
+
+ rval = 0;
+ while (1) {
+ n0 = (unsigned char *)ldap_utf8next((char *)p0);
+ n1 = (unsigned char *)ldap_utf8next((char *)p1);
+ if (n0 > t0 || n1 > t1) {
+ break;
+ }
+
+ i0 = n0 - p0;
+ i1 = n1 - p1;
+ rval = i0 - i1;
+ if (rval) { /* length is different */
+ goto end;
+ }
+
+ /* i0 == i1: same length */
+ for (x0 = p0, x1 = p1; x0 < n0; x0++, x1++) {
+ rval = *x0 - *x1;
+ if (rval) {
+ goto end;
+ }
+ }
+
+ p0 = n0; p1 = n1; /* goto next */
+ }
+ /* finished scanning the shared part and check the leftover */
+ l0 = t0 - n0;
+ l1 = t1 - n1;
+ rval = l0 - l1;
+
+end:
+ if (d0)
+ free(d0);
+ if (d1)
+ free(d1);
+
+ return rval;
+}
+
+/*
+ * dsgw_utf8ncasecmp: case-insensitive string compare (n chars) for UTF-8
+ * strings
+ *
+ * input: two UTF-8 strings (s0, s1) to be compared
+ * number or characters
+ * output: positive number, if s0 is after s1
+ * 0, if the two strings are identical ignoring the case
+ * negative number, if s1 is after s0
+ *
+ * Rules: Same as dsgw_utf8casecmp except the n characters limit.
+ *
+ * Notes: Don't use this function for collation
+ * 1) there's no notion of locale in this function.
+ * 2) it's UTF-8 code order, which is different from the locale
+ * based collation.
+ * n characters, NOT n bytes
+ */
+int
+dsgw_utf8ncasecmp(unsigned char *s0, unsigned char *s1, int n)
+{
+ unsigned char *d0, *d1; /* store lower-case strings */
+ unsigned char *p0, *p1; /* current UTF-8 char */
+ unsigned char *n0, *n1; /* next UTF-8 char */
+ unsigned char *t0, *t1; /* tail of the strings */
+ unsigned char *x0, *x1; /* current byte in a char */
+ int i0, i1; /* length of characters */
+ int l0, l1; /* length of leftover */
+ int cnt;
+ int rval;
+ int has8_s0;
+ int has8_s1;
+
+ d0 = d1 = NULL;
+ if (s0 == NULL || *s0 == '\0') {
+ if (s1 == NULL || *s1 == '\0') {
+ rval = 0;
+ } else {
+ rval = -1; /* regardless s1, s0 < s1 */
+ }
+ goto end;
+ } else if (s1 == NULL || *s1 == '\0') {
+ rval = 1; /* regardless s0, s0 > s1 */
+ goto end;
+ }
+
+ has8_s0 = dsgw_has8thBit(s0);
+ has8_s1 = dsgw_has8thBit(s1);
+ if (has8_s0 == has8_s1) { /* both has-8th-bit or both do not */
+ if (has8_s0 == 0) { /* neither has-8th-bit */
+ rval = strncasecmp((char *)s0, (char *)s1, n);
+ goto end;
+ }
+ } else { /* one has and the other do not */
+ rval = strncasecmp((char *)s0, (char *)s1, n);
+ goto end;
+ }
+
+ d0 = dsgw_utf8StrToLower(s0);
+ d1 = dsgw_utf8StrToLower(s1);
+ if (d0 == NULL || d1 == NULL || /* either is not a UTF-8 string */
+ (d0 && *d0 == '\0') || (d1 && *d1 == '\0')) {
+ rval = strncasecmp((char *)s0, (char *)s1, n);
+ goto end;
+ }
+
+ p0 = d0;
+ p1 = d1;
+
+ t0 = d0 + strlen((char *)d0);
+ t1 = d1 + strlen((char *)d1);
+
+ rval = 0;
+ cnt = 0;
+ while (1) {
+ n0 = (unsigned char *)ldap_utf8next((char *)p0);
+ n1 = (unsigned char *)ldap_utf8next((char *)p1);
+ if (n0 > t0 || n1 > t1 || cnt == n) {
+ break;
+ }
+
+ i0 = n0 - p0;
+ i1 = n1 - p1;
+ rval = i0 - i1;
+ if (rval) /* length is different */
+ goto end;
+
+ /* i0 == i1: same length */
+ for (x0 = p0, x1 = p1; x0 < n0; x0++, x1++) {
+ rval = *x0 - *x1;
+ if (rval)
+ goto end;
+ }
+
+ p0 = n0; p1 = n1; /* goto next */
+ cnt++;
+ }
+ if (cnt == n)
+ rval = 0;
+ else {
+ /* finished scanning the shared part and check the leftover */
+ l0 = t0 - n0;
+ l1 = t1 - n1;
+ rval = l0 - l1;
+ }
+
+end:
+ if (d0)
+ free(d0);
+ if (d1)
+ free(d1);
+
+ return rval;
+}
+
diff --git a/ldap/clients/dsgw/vcard.c b/ldap/clients/dsgw/vcard.c
new file mode 100644
index 00000000..89a6a801
--- /dev/null
+++ b/ldap/clients/dsgw/vcard.c
@@ -0,0 +1,258 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright © 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright © 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * vcard.c -- vCard utility functions -- HTTP gateway
+ *
+ * Copyright (c) 1997 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#include "dsgw.h"
+#include "dbtdsgw.h"
+#include "ldif.h"
+
+
+static int entry2vcard( LDAP *ld, char *dn, char *mimetype,
+ dsgwvcprop *vcprops, char **lderrtxtp );
+static void write_vcard_property( char *prop, char *val, char *val2,
+ int is_mls );
+static void emit_vcard_headers( char *mimetype );
+static char **vcard_ldapattrs( dsgwvcprop *vcprops );
+static void dsgw_puts( char *s );
+
+
+#define DSGW_VCARD_MIMEHDR_TEXTDIR "text/directory;profile=vcard"
+#define DSGW_VCARD_MIMEHDR_XVCARD "text/x-vcard"
+#define DSGW_VCARD_VERSION "2.1"
+#define DSGW_VCARD_PROP_VERSION "VERSION"
+#define DSGW_VCARD_PROP_BEGIN "BEGIN"
+#define DSGW_VCARD_PROP_END "END"
+#define DSGW_VCARD_BEGINEND_VALUE "vCard"
+
+
+void
+dsgw_vcard_from_entry( LDAP *ld, char *dn, char *mimetype )
+{
+ int lderr;
+ char *lderrtxt;
+
+ if (( lderr = entry2vcard( ld, dn, mimetype, gc->gc_vcardproperties,
+ &lderrtxt )) != LDAP_SUCCESS ) {
+ dsgw_error( DSGW_ERR_LDAPGENERAL, NULL, DSGW_ERROPT_EXIT, lderr,
+ lderrtxt );
+ }
+}
+
+
+/*
+ * Retrieve the LDAP entry "dn" and write a vCard representation of it
+ * to stdout.
+ */
+static int
+entry2vcard( LDAP *ld, char *dn, char *mimetype, dsgwvcprop *vcprops,
+ char **lderrtxtp )
+{
+ int i, rc, is_mls;
+ char **ldattrs, **vals, **vals2;
+ dsgwvcprop *vcp;
+ LDAPMessage *msgp, *entry;
+
+
+ ldattrs = vcard_ldapattrs( vcprops );
+
+ /* Read the entry. */
+ if (( rc = ldap_search_s( ld, dn, LDAP_SCOPE_BASE, "objectClass=*",
+ ldattrs, 0, &msgp )) != LDAP_SUCCESS ) {
+ (void)ldap_get_lderrno( ld, NULL, lderrtxtp );
+ return( rc );
+ }
+ if (( entry = ldap_first_entry( ld, msgp )) == NULL ) {
+ ldap_msgfree( msgp );
+ return( ldap_get_lderrno( ld, NULL, lderrtxtp ));
+ }
+
+ /*
+ * Output the vCard headers plus the BEGIN marker and VERSION tag.
+ * once we do this we are committed to producing a vCard MIME object
+ * so we must return LDAP_SUCCESS.
+ */
+ emit_vcard_headers( mimetype );
+ write_vcard_property( DSGW_VCARD_PROP_BEGIN, DSGW_VCARD_BEGINEND_VALUE,
+ NULL, 0 );
+ write_vcard_property( DSGW_VCARD_PROP_VERSION, DSGW_VCARD_VERSION,
+ NULL, 0 );
+
+ /* Output the properties.
+ * Note that for the secondary LDAP attribute we only use the
+ * first value returned by the server. I am sure someone won't
+ * like this but anything else is silly since the main vCard
+ * property we use a secondary LDAP attribute for is the "N"
+ * property which looks like "sn;givenName". We really have no way
+ * of knowing which surname goes with which givenName so it looks
+ * better not to create lots of "N" properties if there are multiple
+ * givenNames.
+ */
+ for ( vcp = vcprops; vcp != NULL; vcp = vcp->dsgwvcprop_next ) {
+ vals = ldap_get_values( ld, entry, vcp->dsgwvcprop_ldaptype );
+ if ( vcp->dsgwvcprop_ldaptype2 == NULL ) {
+ vals2 = NULL;
+ } else {
+ vals2 = ldap_get_values( ld, entry, vcp->dsgwvcprop_ldaptype2 );
+ }
+
+ if ( vals == NULL && vals2 == NULL ) {
+ continue;
+ }
+
+ is_mls = ( strcmp( vcp->dsgwvcprop_syntax, "mls" ) == 0 );
+
+ if ( vals != NULL ) {
+ for ( i = 0; vals[ i ] != NULL; ++i ) {
+ write_vcard_property( vcp->dsgwvcprop_property,
+ vals[i], vals2 == NULL ? NULL : vals2[0], is_mls );
+ }
+ } else {
+ for ( i = 0; vals2[ i ] != NULL; ++i ) {
+ write_vcard_property( vcp->dsgwvcprop_property,
+ NULL, vals2[i], is_mls );
+ }
+ }
+
+ if ( vals != NULL ) {
+ ldap_value_free( vals );
+ }
+ if ( vals2 != NULL ) {
+ ldap_value_free( vals2 );
+ }
+ }
+
+
+ /* Output the vCard END marker. */
+ write_vcard_property( DSGW_VCARD_PROP_END, DSGW_VCARD_BEGINEND_VALUE,
+ NULL, 0 );
+
+ /* Cleanup after ourselves. */
+ ldap_msgfree( msgp );
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * output a single vCard text property.
+ */
+static void
+write_vcard_property( char *prop, char *val, char *val2, int is_mls )
+{
+ char *s, *p, *tmpv, *mlsv;
+
+ tmpv = mlsv = NULL;
+
+ if ( val == NULL ) {
+ val = "";
+ }
+
+ if ( val2 != NULL ) {
+ tmpv = (char *)dsgw_ch_malloc( strlen( val ) + strlen( val2 ) + 2 );
+ sprintf( tmpv, "%s;%s", val, val2 );
+ val = tmpv;
+ }
+
+ if ( is_mls ) {
+ val = mlsv = dsgw_mls_convertlines( val, ";", NULL, 0, 0 );
+ }
+
+ if (( s = ldif_type_and_value( prop, val, strlen( val ))) != NULL ) {
+ /*
+ * vCard base64 rules are different than for LDIF so check and repair
+ * if necessary.
+ */
+ if (( p = strchr( s, ':' )) != NULL && *(p+1) == ':' ) {
+ *p++ = '\0'; ++p;
+ dsgw_emits( s );
+ dsgw_emits( ";BASE64:\n " );
+ dsgw_emits( p );
+ dsgw_emits( "\n" );
+ } else {
+ dsgw_emits( s );
+ }
+ free( s );
+ }
+
+ if ( tmpv != NULL ) {
+ free( tmpv );
+ }
+ if ( mlsv != NULL ) {
+ free( mlsv );
+ }
+}
+
+
+/*
+ * emit vCard Content-Type header, etc.
+ */
+static void
+emit_vcard_headers( char *mimetype )
+{
+ if ( mimetype == NULL || *mimetype == '\0' ) {
+ mimetype = DSGW_VCARD_MIMEHDR_TEXTDIR; /* default */
+ }
+
+ dsgw_puts( "Content-Type: " );
+ dsgw_puts( mimetype );
+ if ( gc->gc_charset != NULL && *gc->gc_charset != '\0' ) {
+ dsgw_puts( ";charset=" );
+ dsgw_puts( gc->gc_charset );
+ }
+ dsgw_puts( "\n\n" );
+}
+
+
+/*
+ * output a simple string without charset conversion (used for MIME headers)
+ */
+static void
+dsgw_puts( char *s )
+{
+ dsgw_fputn( stdout, s, strlen( s ));
+}
+
+
+/*
+ * return list of LDAP attributes we need to fetch
+ */
+static char **
+vcard_ldapattrs( dsgwvcprop *vcprops )
+{
+ dsgwvcprop *vcp;
+ int count;
+ static char **attrs = NULL;
+
+ if ( attrs != NULL ) {
+ return( attrs );
+ }
+
+ count = 0;
+ for ( vcp = vcprops; vcp != NULL; vcp = vcp->dsgwvcprop_next ) {
+ ++count;
+ if ( vcp->dsgwvcprop_ldaptype2 != NULL ) {
+ ++count;
+ }
+ }
+
+ attrs = (char **)dsgw_ch_malloc(( count + 1 ) * sizeof( char * ));
+ count = 0;
+ for ( vcp = vcprops; vcp != NULL; vcp = vcp->dsgwvcprop_next ) {
+ attrs[ count++ ] = vcp->dsgwvcprop_ldaptype;
+ if ( vcp->dsgwvcprop_ldaptype2 != NULL ) {
+ attrs[ count++ ] = vcp->dsgwvcprop_ldaptype2;
+ }
+ }
+ attrs[ count ] = NULL;
+
+ return( attrs );
+}
diff --git a/ldap/clients/dsmlgw/Makefile b/ldap/clients/dsmlgw/Makefile
new file mode 100644
index 00000000..e63f565c
--- /dev/null
+++ b/ldap/clients/dsmlgw/Makefile
@@ -0,0 +1,16 @@
+NOSTDCLEAN=true
+NO_BUILD_NUM=true
+COMPONENT_DEPS=true
+
+
+MCOM_ROOT=../../../..
+
+include ../../../nsconfig.mk
+include ../../../ldap/javarules.mk
+
+all: $(TOMCAT_DEP) $(ANT_DEP) $(LDAPJDK_DEP)
+ $(ANT)
+
+clean:
+ $(ANT) clean
+
diff --git a/ldap/clients/dsmlgw/build.xml b/ldap/clients/dsmlgw/build.xml
new file mode 100644
index 00000000..b94d2ae7
--- /dev/null
+++ b/ldap/clients/dsmlgw/build.xml
@@ -0,0 +1,67 @@
+<?xml version='1.0'?>
+<!-- ANT build script for the new dsml gateway -->
+<!-- Possible to compile by hand, use
+ cd /ldapserver/ldap/clients/dsmlgw
+ ant -Dxerces=../../../../dist/classes/jakarta-tomcat-5.0.27/common/endorsed
+ -->
+<project name="dsmlgw" default="dist" basedir=".">
+
+<!-- ******************** Adjustable Properties *********************** -->
+<property name="mcom.root" value="../../../.."/>
+<property name="globaldist.dir" value="${mcom.root}/dist/classes"/>
+<property name="app.name" value="dsmlgw"/>
+<property name="taglib.name" value="dsmlgw"/>
+
+<property name="ldapjdk.jar" value="${globaldist.dir}/ldapjdk.jar"/>
+<property name="activation.jar" value="${globaldist.dir}/activation.jar"/>
+<property name="jaxrpc-api.jar" value="${globaldist.dir}/jaxrpc-api.jar"/>
+<property name="jaxrpc.jar" value="${globaldist.dir}/jaxrpc.jar"/>
+<property name="saaj.jar" value="${globaldist.dir}/saaj.jar"/>
+<property name="xercesImpl.jar" value="${globaldist.dir}/xercesImpl.jar"/>
+<property name="xmlParserAPIs.jar" value="${globaldist.dir}/xml-apis.jar"/>
+
+<path id="class.path">
+<pathelement location="${ldapjdk.jar}"/>
+<pathelement location="${activation.jar}"/>
+<pathelement location="${jaxrpc-api.jar}"/>
+<pathelement location="${jaxrpc.jar}"/>
+<pathelement location="${saaj.jar}"/>
+
+<pathelement location="${xercesImpl.jar}"/>
+<pathelement location="${xmlParserAPIs.jar}"/>
+</path>
+
+<property name="build.dir" value="${mcom.root}/ldapserver/built/dsmlgw"/>
+<property name="dist.dir" value="${mcom.root}/dist/dsmlgw"/>
+
+
+
+<target name="prepare" description="prepares the output directories">
+ <mkdir dir="${build.dir}"/>
+ <mkdir dir="${dist.dir}"/>
+</target>
+
+<target name="library" depends="classpath,prepare" description="builds it">
+<javac srcdir="." destdir="${build.dir}" classpathref="class.path" debug="on"/>
+</target>
+
+
+ <!-- Create the library distribution files -->
+<target name="dist" depends="classpath,library" description="makes the distribution">
+ <jar jarfile="${dist.dir}/dsmlgw.jar" basedir="${build.dir}"/>
+
+ </target>
+
+ <target name="clean" description="makes clean">
+ <delete dir="${build.dir}"/>
+ <delete dir="${dist.dir}"/>
+ </target>
+
+<property name="classpath" refid="class.path"/>
+ <target name="classpath">
+ <echo message="${classpath}"/>
+ </target>
+
+
+</project>
+
diff --git a/ldap/clients/dsmlgw/misc/dsmlgw.cfg b/ldap/clients/dsmlgw/misc/dsmlgw.cfg
new file mode 100644
index 00000000..d9686aa9
--- /dev/null
+++ b/ldap/clients/dsmlgw/misc/dsmlgw.cfg
@@ -0,0 +1,13 @@
+#properties file for the
+#Netscape DSMLGW
+# DSML Gateway
+
+ServerHost=localhost
+ServerPort=389
+BindDN=
+BindPW=
+
+MinLoginPool=1
+MaxLoginPool=2
+MinPool=3
+MaxPool=15
diff --git a/ldap/clients/dsmlgw/misc/server-config.wsdd b/ldap/clients/dsmlgw/misc/server-config.wsdd
new file mode 100644
index 00000000..8740196b
--- /dev/null
+++ b/ldap/clients/dsmlgw/misc/server-config.wsdd
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<deployment xmlns="http://xml.apache.org/axis/wsdd/" xmlns:java="http://xml.apache.org/axis/wsdd/providers/java">
+ <globalConfiguration>
+ <parameter name="adminPassword" value="admin"/>
+ <parameter name="sendMultiRefs" value="true"/>
+ <parameter name="sendXsiTypes" value="true"/>
+ <parameter name="attachments.implementation" value="org.apache.axis.attachments.AttachmentsImpl"/>
+ <parameter name="sendXMLDeclaration" value="true"/>
+ <requestFlow>
+ <handler type="java:org.apache.axis.handlers.JWSHandler">
+ <parameter name="scope" value="session"/>
+ </handler>
+ <handler type="java:org.apache.axis.handlers.JWSHandler">
+ <parameter name="scope" value="request"/>
+ <parameter name="extension" value=".jwr"/>
+ </handler>
+ </requestFlow>
+ </globalConfiguration>
+ <handler name="LocalResponder" type="java:org.apache.axis.transport.local.LocalResponder"/>
+ <handler name="URLMapper" type="java:org.apache.axis.handlers.http.URLMapper"/>
+ <requestFlow name="checks">
+ <handler type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
+ <handler type="java:org.apache.axis.handlers.SimpleAuthorizationHandler"/>
+ </requestFlow>
+ <handler name="Authenticate" type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
+
+ <service name="dsmlgw" provider="java:RPC">
+<!-- this is for the javax.xml.rpc.handler's -->
+<handlerInfoChain>
+ <handlerInfo classname="com.netscape.dsml.gateway.gatewayHandler">
+ <parameter name="server" value="bison"/>
+ <parameter name="port" value="38900"/>
+ <parameter name="dn" value="ou=People,dc=mtbrook,dc=bozemanpass,dc=com"/>
+ <parameter name="foo" value="bar"/>
+ <header qname="QNAME" xmlns:ns="DSML2core"/>
+ </handlerInfo>
+ <role soapActorName="URI"/>
+</handlerInfoChain>
+
+
+ <operation name="process" returnQName="returnqname" returnType="ns1:DataHandler" xmlns:ns1="dsmlgw">
+ <parameter name="in1" type="ns1:DataHandler"/>
+ </operation>
+ <parameter name="allowedMethods" value="process batchRequest"/>
+ <parameter name="className" value="com.netscape.dsml.gateway.gatewayService"/>
+ <typeMapping deserializer="org.apache.axis.encoding.ser.JAFDataHandlerDeserializerFactory" encodingStyle="http://schemas.xmlsoap.org/soap/encoding/" qname="ns2:DataHandler" serializer="org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory" type="java:javax.activation.DataHandler" xmlns:ns2="DSMLService"/>
+ </service>
+
+
+ <service name="Version" provider="java:RPC">
+ <parameter name="allowedMethods" value="getVersion"/>
+ <parameter name="className" value="org.apache.axis.Version"/>
+ </service>
+ <service name="urn:xmltoday-delayed-quotes" provider="java:RPC">
+ <requestFlow name="checks">
+ <handler type="java:org.apache.axis.handlers.SimpleAuthenticationHandler"/>
+ <handler type="java:org.apache.axis.handlers.SimpleAuthorizationHandler"/>
+ </requestFlow>
+ <parameter name="allowedRoles" value="user1,user2"/>
+ <parameter name="allowedMethods" value="getQuote test"/>
+ <parameter name="wsdlServicePort" value="GetQuote"/>
+ <parameter name="className" value="samples.stock.StockQuoteService"/>
+ </service>
+
+ <transport name="http">
+ <requestFlow>
+ <handler type="URLMapper"/>
+ <handler type="java:org.apache.axis.handlers.http.HTTPAuthHandler"/>
+ </requestFlow>
+ <parameter name="qs:list" value="org.apache.axis.transport.http.QSListHandler"/>
+ <parameter name="qs:wsdl" value="org.apache.axis.transport.http.QSWSDLHandler"/>
+ <parameter name="qs:method" value="org.apache.axis.transport.http.QSMethodHandler"/>
+ </transport>
+ <transport name="local">
+ <responseFlow>
+ <handler type="LocalResponder"/>
+ </responseFlow>
+ </transport>
+</deployment>
diff --git a/ldap/clients/dsmlgw/misc/web-app_2_3.dtd b/ldap/clients/dsmlgw/misc/web-app_2_3.dtd
new file mode 100644
index 00000000..5e3ab01c
--- /dev/null
+++ b/ldap/clients/dsmlgw/misc/web-app_2_3.dtd
@@ -0,0 +1,1063 @@
+<!--
+Copyright (c) 2000 Sun Microsystems, Inc.,
+901 San Antonio Road,
+Palo Alto, California 94303, U.S.A.
+All rights reserved.
+
+Sun Microsystems, Inc. has intellectual property rights relating to
+technology embodied in the product that is described in this document.
+In particular, and without limitation, these intellectual property
+rights may include one or more of the U.S. patents listed at
+http://www.sun.com/patents and one or more additional patents or
+pending patent applications in the U.S. and in other countries.
+
+This document and the product to which it pertains are distributed
+under licenses restricting their use, copying, distribution, and
+decompilation. This document may be reproduced and distributed but may
+not be changed without prior written authorization of Sun and its
+licensors, if any.
+
+Third-party software, including font technology, is copyrighted and
+licensed from Sun suppliers.
+
+Sun, Sun Microsystems, the Sun logo, Java, JavaServer Pages, Java
+Naming and Directory Interface, JDBC, JDK, JavaMail and and
+Enterprise JavaBeans are trademarks or registered trademarks of Sun
+Microsystems, Inc. in the U.S. and other countries.
+
+Federal Acquisitions: Commercial Software - Government Users Subject to
+Standard License Terms and Conditions.
+
+DOCUMENTATION IS PROVIDED "AS IS" AND ALL EXPRESS OR IMPLIED
+CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY IMPLIED
+WARRANTY OF MERCHANTABILITY, FITNESS FOR FOR A PARTICULAR PURPOSE OR
+NON-INFRINGEMENT, ARE DISCLAIMED, EXCEPT TO THE EXTENT THAT SUCH
+DISCLAIMERS ARE HELD TO BE LEGALLY INVALID.
+
+
+_________________________________________________________________________
+
+Copyright (c) 2000 Sun Microsystems, Inc.,
+901 San Antonio Road,
+Palo Alto, California 94303, E'tats-Unis.
+Tous droits re'serve's.
+
+Sun Microsystems, Inc. a les droits de proprie'te' intellectuels
+relatants a` la technologie incorpore'e dans le produit qui est de'crit
+dans ce document. En particulier, et sans la limitation, ces droits de
+proprie'te' intellectuels peuvent inclure un ou plus des brevets
+ame'ricains e'nume're's a` http://www.sun.com/patents et un ou les
+brevets plus supple'mentaires ou les applications de brevet en attente
+dans les E'tats-Unis et dans les autres pays.
+
+Ce produit ou document est prote'ge' par un copyright et distribue'
+avec des licences qui en restreignent l'utilisation, la copie, la
+distribution, et la de'compilation. Ce documention associe n peut
+e^tre reproduite et distribuer, par quelque moyen que ce soit, sans
+l'autorisation pre'alable et e'crite de Sun et de ses bailleurs de
+licence, le cas e'che'ant.
+
+Le logiciel de'tenu par des tiers, et qui comprend la technologie
+relative aux polices de caracte`res, est prote'ge' par un copyright et
+licencie' par des fournisseurs de Sun.
+
+Sun, Sun Microsystems, le logo Sun, Java, JavaServer Pages, Java
+Naming and Directory Interface, JDBC, JDK, JavaMail et and
+Enterprise JavaBeans sont des marques de fabrique ou des marques
+de'pose'es de Sun Microsystems, Inc. aux E'tats-Unis et dans d'autres
+pays.
+
+LA DOCUMENTATION EST FOURNIE "EN L'E'TAT" ET TOUTES AUTRES CONDITIONS,
+DECLARATIONS ET GARANTIES EXPRESSES OU TACITES SONT FORMELLEMENT
+EXCLUES, DANS LA MESURE AUTORISEE PAR LA LOI APPLICABLE, Y COMPRIS
+NOTAMMENT TOUTE GARANTIE IMPLICITE RELATIVE A LA QUALITE MARCHANDE, A
+L'APTITUDE A UNE UTILISATION PARTICULIERE OU A L'ABSENCE DE
+CONTREFAC,ON.
+-->
+
+<!--
+This is the XML DTD for the Servlet 2.3 deployment descriptor.
+All Servlet 2.3 deployment descriptors must include a DOCTYPE
+of the following form:
+
+ <!DOCTYPE web-app PUBLIC
+ "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
+ "http://java.sun.com/dtd/web-app_2_3.dtd">
+
+-->
+
+<!--
+The following conventions apply to all J2EE deployment descriptor
+elements unless indicated otherwise.
+
+- In elements that contain PCDATA, leading and trailing whitespace
+ in the data may be ignored.
+
+- In elements whose value is an "enumerated type", the value is
+ case sensitive.
+
+- In elements that specify a pathname to a file within the same
+ JAR file, relative filenames (i.e., those not starting with "/")
+ are considered relative to the root of the JAR file's namespace.
+ Absolute filenames (i.e., those starting with "/") also specify
+ names in the root of the JAR file's namespace. In general, relative
+ names are preferred. The exception is .war files where absolute
+ names are preferred for consistency with the servlet API.
+-->
+
+
+<!--
+The web-app element is the root of the deployment descriptor for
+a web application.
+-->
+<!ELEMENT web-app (icon?, display-name?, description?, distributable?,
+context-param*, filter*, filter-mapping*, listener*, servlet*,
+servlet-mapping*, session-config?, mime-mapping*, welcome-file-list?,
+error-page*, taglib*, resource-env-ref*, resource-ref*, security-constraint*,
+login-config?, security-role*, env-entry*, ejb-ref*, ejb-local-ref*)>
+
+<!--
+The auth-constraint element indicates the user roles that should
+be permitted access to this resource collection. The role-name
+used here must either correspond to the role-name of one of the
+security-role elements defined for this web application, or be
+the specially reserved role-name "*" that is a compact syntax for
+indicating all roles in the web application. If both "*" and
+rolenames appear, the container interprets this as all roles.
+If no roles are defined, no user is allowed access to the portion of
+the web application described by the containing security-constraint.
+The container matches role names case sensitively when determining
+access.
+
+
+Used in: security-constraint
+-->
+<!ELEMENT auth-constraint (description?, role-name*)>
+
+<!--
+The auth-method element is used to configure the authentication
+mechanism for the web application. As a prerequisite to gaining access to any web resources which are protected by an authorization
+constraint, a user must have authenticated using the configured
+mechanism. Legal values for this element are "BASIC", "DIGEST",
+"FORM", or "CLIENT-CERT".
+
+Used in: login-config
+-->
+<!ELEMENT auth-method (#PCDATA)>
+
+<!--
+The context-param element contains the declaration of a web
+application's servlet context initialization parameters.
+
+Used in: web-app
+-->
+<!ELEMENT context-param (param-name, param-value, description?)>
+
+<!--
+The description element is used to provide text describing the parent
+element. The description element should include any information that
+the web application war file producer wants to provide to the consumer of
+the web application war file (i.e., to the Deployer). Typically, the tools
+used by the web application war file consumer will display the description
+when processing the parent element that contains the description.
+
+Used in: auth-constraint, context-param, ejb-local-ref, ejb-ref,
+env-entry, filter, init-param, resource-env-ref, resource-ref, run-as,
+security-role, security-role-ref, servlet, user-data-constraint,
+web-app, web-resource-collection
+-->
+<!ELEMENT description (#PCDATA)>
+
+<!--
+The display-name element contains a short name that is intended to be
+displayed by tools. The display name need not be unique.
+
+Used in: filter, security-constraint, servlet, web-app
+
+Example:
+
+<display-name>Employee Self Service</display-name>
+-->
+<!ELEMENT display-name (#PCDATA)>
+
+<!--
+The distributable element, by its presence in a web application
+deployment descriptor, indicates that this web application is
+programmed appropriately to be deployed into a distributed servlet
+container
+
+Used in: web-app
+-->
+<!ELEMENT distributable EMPTY>
+
+<!--
+The ejb-link element is used in the ejb-ref or ejb-local-ref
+elements to specify that an EJB reference is linked to an
+enterprise bean.
+
+The name in the ejb-link element is composed of a
+path name specifying the ejb-jar containing the referenced enterprise
+bean with the ejb-name of the target bean appended and separated from
+the path name by "#". The path name is relative to the war file
+containing the web application that is referencing the enterprise bean.
+This allows multiple enterprise beans with the same ejb-name to be
+uniquely identified.
+
+Used in: ejb-local-ref, ejb-ref
+
+Examples:
+
+ <ejb-link>EmployeeRecord</ejb-link>
+
+ <ejb-link>../products/product.jar#ProductEJB</ejb-link>
+
+-->
+<!ELEMENT ejb-link (#PCDATA)>
+
+<!--
+The ejb-local-ref element is used for the declaration of a reference to
+an enterprise bean's local home. The declaration consists of:
+
+ - an optional description
+ - the EJB reference name used in the code of the web application
+ that's referencing the enterprise bean
+ - the expected type of the referenced enterprise bean
+ - the expected local home and local interfaces of the referenced
+ enterprise bean
+ - optional ejb-link information, used to specify the referenced
+ enterprise bean
+
+Used in: web-app
+-->
+<!ELEMENT ejb-local-ref (description?, ejb-ref-name, ejb-ref-type,
+ local-home, local, ejb-link?)>
+
+<!--
+The ejb-ref element is used for the declaration of a reference to
+an enterprise bean's home. The declaration consists of:
+
+ - an optional description
+ - the EJB reference name used in the code of
+ the web application that's referencing the enterprise bean
+ - the expected type of the referenced enterprise bean
+ - the expected home and remote interfaces of the referenced
+ enterprise bean
+ - optional ejb-link information, used to specify the referenced
+ enterprise bean
+
+Used in: web-app
+-->
+<!ELEMENT ejb-ref (description?, ejb-ref-name, ejb-ref-type,
+ home, remote, ejb-link?)>
+
+<!--
+The ejb-ref-name element contains the name of an EJB reference. The
+EJB reference is an entry in the web application's environment and is
+relative to the java:comp/env context. The name must be unique
+within the web application.
+
+It is recommended that name is prefixed with "ejb/".
+
+Used in: ejb-local-ref, ejb-ref
+
+Example:
+
+<ejb-ref-name>ejb/Payroll</ejb-ref-name>
+-->
+<!ELEMENT ejb-ref-name (#PCDATA)>
+
+<!--
+The ejb-ref-type element contains the expected type of the
+referenced enterprise bean.
+
+The ejb-ref-type element must be one of the following:
+
+ <ejb-ref-type>Entity</ejb-ref-type>
+ <ejb-ref-type>Session</ejb-ref-type>
+
+Used in: ejb-local-ref, ejb-ref
+-->
+<!ELEMENT ejb-ref-type (#PCDATA)>
+
+<!--
+The env-entry element contains the declaration of a web application's
+environment entry. The declaration consists of an optional
+description, the name of the environment entry, and an optional
+value. If a value is not specified, one must be supplied
+during deployment.
+-->
+<!ELEMENT env-entry (description?, env-entry-name, env-entry-value?,
+env-entry-type)>
+
+<!--
+The env-entry-name element contains the name of a web applications's
+environment entry. The name is a JNDI name relative to the
+java:comp/env context. The name must be unique within a web application.
+
+Example:
+
+<env-entry-name>minAmount</env-entry-name>
+
+Used in: env-entry
+-->
+<!ELEMENT env-entry-name (#PCDATA)>
+
+<!--
+The env-entry-type element contains the fully-qualified Java type of
+the environment entry value that is expected by the web application's
+code.
+
+The following are the legal values of env-entry-type:
+
+ java.lang.Boolean
+ java.lang.Byte
+ java.lang.Character
+ java.lang.String
+ java.lang.Short
+ java.lang.Integer
+ java.lang.Long
+ java.lang.Float
+ java.lang.Double
+
+Used in: env-entry
+-->
+<!ELEMENT env-entry-type (#PCDATA)>
+
+<!--
+The env-entry-value element contains the value of a web application's
+environment entry. The value must be a String that is valid for the
+constructor of the specified type that takes a single String
+parameter, or for java.lang.Character, a single character.
+
+Example:
+
+<env-entry-value>100.00</env-entry-value>
+
+Used in: env-entry
+-->
+<!ELEMENT env-entry-value (#PCDATA)>
+
+<!--
+The error-code contains an HTTP error code, ex: 404
+
+Used in: error-page
+-->
+<!ELEMENT error-code (#PCDATA)>
+
+<!--
+The error-page element contains a mapping between an error code
+or exception type to the path of a resource in the web application
+
+Used in: web-app
+-->
+<!ELEMENT error-page ((error-code | exception-type), location)>
+
+<!--
+The exception type contains a fully qualified class name of a
+Java exception type.
+
+Used in: error-page
+-->
+<!ELEMENT exception-type (#PCDATA)>
+
+<!--
+The extension element contains a string describing an
+extension. example: "txt"
+
+Used in: mime-mapping
+-->
+<!ELEMENT extension (#PCDATA)>
+
+<!--
+Declares a filter in the web application. The filter is mapped to
+either a servlet or a URL pattern in the filter-mapping element, using
+the filter-name value to reference. Filters can access the
+initialization parameters declared in the deployment descriptor at
+runtime via the FilterConfig interface.
+
+Used in: web-app
+-->
+<!ELEMENT filter (icon?, filter-name, display-name?, description?,
+filter-class, init-param*)>
+
+<!--
+The fully qualified classname of the filter.
+
+Used in: filter
+-->
+<!ELEMENT filter-class (#PCDATA)>
+
+<!--
+Declaration of the filter mappings in this web application. The
+container uses the filter-mapping declarations to decide which filters
+to apply to a request, and in what order. The container matches the
+request URI to a Servlet in the normal way. To determine which filters
+to apply it matches filter-mapping declarations either on servlet-name,
+or on url-pattern for each filter-mapping element, depending on which
+style is used. The order in which filters are invoked is the order in
+which filter-mapping declarations that match a request URI for a
+servlet appear in the list of filter-mapping elements.The filter-name
+value must be the value of the <filter-name> sub-elements of one of the
+<filter> declarations in the deployment descriptor.
+
+Used in: web-app
+-->
+<!ELEMENT filter-mapping (filter-name, (url-pattern | servlet-name))>
+
+<!--
+The logical name of the filter. This name is used to map the filter.
+Each filter name is unique within the web application.
+
+Used in: filter, filter-mapping
+-->
+<!ELEMENT filter-name (#PCDATA)>
+
+<!--
+The form-error-page element defines the location in the web app
+where the error page that is displayed when login is not successful
+can be found. The path begins with a leading / and is interpreted
+relative to the root of the WAR.
+
+Used in: form-login-config
+-->
+<!ELEMENT form-error-page (#PCDATA)>
+
+<!--
+The form-login-config element specifies the login and error pages
+that should be used in form based login. If form based authentication
+is not used, these elements are ignored.
+
+Used in: login-config
+-->
+<!ELEMENT form-login-config (form-login-page, form-error-page)>
+
+<!--
+The form-login-page element defines the location in the web app
+where the page that can be used for login can be found. The path
+begins with a leading / and is interpreted relative to the root of the WAR.
+
+Used in: form-login-config
+-->
+<!ELEMENT form-login-page (#PCDATA)>
+
+<!--
+The home element contains the fully-qualified name of the enterprise
+bean's home interface.
+
+Used in: ejb-ref
+
+Example:
+
+<home>com.aardvark.payroll.PayrollHome</home>
+-->
+<!ELEMENT home (#PCDATA)>
+
+<!--
+The http-method contains an HTTP method (GET | POST |...).
+
+Used in: web-resource-collection
+-->
+<!ELEMENT http-method (#PCDATA)>
+
+<!--
+The icon element contains small-icon and large-icon elements that
+specify the file names for small and a large GIF or JPEG icon images
+used to represent the parent element in a GUI tool.
+
+Used in: filter, servlet, web-app
+-->
+<!ELEMENT icon (small-icon?, large-icon?)>
+
+<!--
+The init-param element contains a name/value pair as an
+initialization param of the servlet
+
+Used in: filter, servlet
+-->
+<!ELEMENT init-param (param-name, param-value, description?)>
+
+<!--
+The jsp-file element contains the full path to a JSP file within
+the web application beginning with a `/'.
+
+Used in: servlet
+-->
+<!ELEMENT jsp-file (#PCDATA)>
+
+<!--
+The large-icon element contains the name of a file
+containing a large (32 x 32) icon image. The file
+name is a relative path within the web application's
+war file.
+
+The image may be either in the JPEG or GIF format.
+The icon can be used by tools.
+
+Used in: icon
+
+Example:
+
+<large-icon>employee-service-icon32x32.jpg</large-icon>
+-->
+<!ELEMENT large-icon (#PCDATA)>
+
+<!--
+The listener element indicates the deployment properties for a web
+application listener bean.
+
+Used in: web-app
+-->
+<!ELEMENT listener (listener-class)>
+
+<!--
+The listener-class element declares a class in the application must be
+registered as a web application listener bean. The value is the fully qualified classname of the listener class.
+
+
+Used in: listener
+-->
+<!ELEMENT listener-class (#PCDATA)>
+
+<!--
+The load-on-startup element indicates that this servlet should be
+loaded (instantiated and have its init() called) on the startup
+of the web application. The optional contents of
+these element must be an integer indicating the order in which
+the servlet should be loaded. If the value is a negative integer,
+or the element is not present, the container is free to load the
+servlet whenever it chooses. If the value is a positive integer
+or 0, the container must load and initialize the servlet as the
+application is deployed. The container must guarantee that
+servlets marked with lower integers are loaded before servlets
+marked with higher integers. The container may choose the order
+of loading of servlets with the same load-on-start-up value.
+
+Used in: servlet
+-->
+<!ELEMENT load-on-startup (#PCDATA)>
+
+<!--
+
+The local element contains the fully-qualified name of the
+enterprise bean's local interface.
+
+Used in: ejb-local-ref
+
+-->
+<!ELEMENT local (#PCDATA)>
+
+<!--
+
+The local-home element contains the fully-qualified name of the
+enterprise bean's local home interface.
+
+Used in: ejb-local-ref
+-->
+<!ELEMENT local-home (#PCDATA)>
+
+<!--
+The location element contains the location of the resource in the web
+application relative to the root of the web application. The value of
+the location must have a leading `/'.
+
+Used in: error-page
+-->
+<!ELEMENT location (#PCDATA)>
+
+<!--
+The login-config element is used to configure the authentication
+method that should be used, the realm name that should be used for
+this application, and the attributes that are needed by the form login
+mechanism.
+
+Used in: web-app
+-->
+<!ELEMENT login-config (auth-method?, realm-name?, form-login-config?)>
+
+<!--
+The mime-mapping element defines a mapping between an extension
+and a mime type.
+
+Used in: web-app
+-->
+<!ELEMENT mime-mapping (extension, mime-type)>
+
+<!--
+The mime-type element contains a defined mime type. example:
+"text/plain"
+
+Used in: mime-mapping
+-->
+<!ELEMENT mime-type (#PCDATA)>
+
+<!--
+The param-name element contains the name of a parameter. Each parameter
+name must be unique in the web application.
+
+
+Used in: context-param, init-param
+-->
+<!ELEMENT param-name (#PCDATA)>
+
+<!--
+The param-value element contains the value of a parameter.
+
+Used in: context-param, init-param
+-->
+<!ELEMENT param-value (#PCDATA)>
+
+<!--
+The realm name element specifies the realm name to use in HTTP
+Basic authorization.
+
+Used in: login-config
+-->
+<!ELEMENT realm-name (#PCDATA)>
+
+<!--
+The remote element contains the fully-qualified name of the enterprise
+bean's remote interface.
+
+Used in: ejb-ref
+
+Example:
+
+<remote>com.wombat.empl.EmployeeService</remote>
+-->
+<!ELEMENT remote (#PCDATA)>
+
+<!--
+The res-auth element specifies whether the web application code signs
+on programmatically to the resource manager, or whether the Container
+will sign on to the resource manager on behalf of the web application. In the
+latter case, the Container uses information that is supplied by the
+Deployer.
+
+The value of this element must be one of the two following:
+
+ <res-auth>Application</res-auth>
+ <res-auth>Container</res-auth>
+
+Used in: resource-ref
+-->
+<!ELEMENT res-auth (#PCDATA)>
+
+<!--
+The res-ref-name element specifies the name of a resource manager
+connection factory reference. The name is a JNDI name relative to the
+java:comp/env context. The name must be unique within a web application.
+
+Used in: resource-ref
+-->
+<!ELEMENT res-ref-name (#PCDATA)>
+
+<!--
+The res-sharing-scope element specifies whether connections obtained
+through the given resource manager connection factory reference can be
+shared. The value of this element, if specified, must be one of the
+two following:
+
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ <res-sharing-scope>Unshareable</res-sharing-scope>
+
+The default value is Shareable.
+
+Used in: resource-ref
+-->
+<!ELEMENT res-sharing-scope (#PCDATA)>
+
+<!--
+The res-type element specifies the type of the data source. The type
+is specified by the fully qualified Java language class or interface
+expected to be implemented by the data source.
+
+Used in: resource-ref
+-->
+<!ELEMENT res-type (#PCDATA)>
+
+<!--
+The resource-env-ref element contains a declaration of a web application's
+reference to an administered object associated with a resource
+in the web application's environment. It consists of an optional
+description, the resource environment reference name, and an
+indication of the resource environment reference type expected by
+the web application code.
+
+Used in: web-app
+
+Example:
+
+<resource-env-ref>
+ <resource-env-ref-name>jms/StockQueue</resource-env-ref-name>
+ <resource-env-ref-type>javax.jms.Queue</resource-env-ref-type>
+</resource-env-ref>
+-->
+<!ELEMENT resource-env-ref (description?, resource-env-ref-name,
+ resource-env-ref-type)>
+
+<!--
+The resource-env-ref-name element specifies the name of a resource
+environment reference; its value is the environment entry name used in
+the web application code. The name is a JNDI name relative to the
+java:comp/env context and must be unique within a web application.
+
+Used in: resource-env-ref
+-->
+<!ELEMENT resource-env-ref-name (#PCDATA)>
+
+<!--
+The resource-env-ref-type element specifies the type of a resource
+environment reference. It is the fully qualified name of a Java
+language class or interface.
+
+Used in: resource-env-ref
+-->
+<!ELEMENT resource-env-ref-type (#PCDATA)>
+
+<!--
+The resource-ref element contains a declaration of a web application's
+reference to an external resource. It consists of an optional
+description, the resource manager connection factory reference name,
+the indication of the resource manager connection factory type
+expected by the web application code, the type of authentication
+(Application or Container), and an optional specification of the
+shareability of connections obtained from the resource (Shareable or
+Unshareable).
+
+Used in: web-app
+
+Example:
+
+ <resource-ref>
+ <res-ref-name>jdbc/EmployeeAppDB</res-ref-name>
+ <res-type>javax.sql.DataSource</res-type>
+ <res-auth>Container</res-auth>
+ <res-sharing-scope>Shareable</res-sharing-scope>
+ </resource-ref>
+-->
+<!ELEMENT resource-ref (description?, res-ref-name, res-type, res-auth,
+ res-sharing-scope?)>
+
+<!--
+The role-link element is a reference to a defined security role. The
+role-link element must contain the name of one of the security roles
+defined in the security-role elements.
+
+Used in: security-role-ref
+-->
+<!ELEMENT role-link (#PCDATA)>
+
+<!--
+The role-name element contains the name of a security role.
+
+The name must conform to the lexical rules for an NMTOKEN.
+
+Used in: auth-constraint, run-as, security-role, security-role-ref
+-->
+<!ELEMENT role-name (#PCDATA)>
+
+<!--
+The run-as element specifies the run-as identity to be used for the
+execution of the web application. It contains an optional description, and
+the name of a security role.
+
+Used in: servlet
+-->
+<!ELEMENT run-as (description?, role-name)>
+
+<!--
+The security-constraint element is used to associate security
+constraints with one or more web resource collections
+
+Used in: web-app
+-->
+<!ELEMENT security-constraint (display-name?, web-resource-collection+,
+auth-constraint?, user-data-constraint?)>
+
+<!--
+The security-role element contains the definition of a security
+role. The definition consists of an optional description of the
+security role, and the security role name.
+
+Used in: web-app
+
+Example:
+
+ <security-role>
+ <description>
+ This role includes all employees who are authorized
+ to access the employee service application.
+ </description>
+ <role-name>employee</role-name>
+ </security-role>
+-->
+<!ELEMENT security-role (description?, role-name)>
+
+<!--
+The security-role-ref element contains the declaration of a security
+role reference in the web application's code. The declaration consists
+of an optional description, the security role name used in the code,
+and an optional link to a security role. If the security role is not
+specified, the Deployer must choose an appropriate security role.
+
+The value of the role-name element must be the String used as the
+parameter to the EJBContext.isCallerInRole(String roleName) method
+or the HttpServletRequest.isUserInRole(String role) method.
+
+Used in: servlet
+
+-->
+<!ELEMENT security-role-ref (description?, role-name, role-link?)>
+
+<!--
+The servlet element contains the declarative data of a
+servlet. If a jsp-file is specified and the load-on-startup element is
+present, then the JSP should be precompiled and loaded.
+
+Used in: web-app
+-->
+<!ELEMENT servlet (icon?, servlet-name, display-name?, description?,
+(servlet-class|jsp-file), init-param*, load-on-startup?, run-as?, security-role-ref*)>
+
+<!--
+The servlet-class element contains the fully qualified class name
+of the servlet.
+
+Used in: servlet
+-->
+<!ELEMENT servlet-class (#PCDATA)>
+
+<!--
+The servlet-mapping element defines a mapping between a servlet
+and a url pattern
+
+Used in: web-app
+-->
+<!ELEMENT servlet-mapping (servlet-name, url-pattern)>
+
+<!--
+The servlet-name element contains the canonical name of the
+servlet. Each servlet name is unique within the web application.
+
+Used in: filter-mapping, servlet, servlet-mapping
+-->
+<!ELEMENT servlet-name (#PCDATA)>
+
+<!--
+The session-config element defines the session parameters for
+this web application.
+
+Used in: web-app
+-->
+<!ELEMENT session-config (session-timeout?)>
+
+<!--
+The session-timeout element defines the default session timeout
+interval for all sessions created in this web application. The
+specified timeout must be expressed in a whole number of minutes.
+If the timeout is 0 or less, the container ensures the default
+behaviour of sessions is never to time out.
+
+Used in: session-config
+-->
+<!ELEMENT session-timeout (#PCDATA)>
+
+<!--
+The small-icon element contains the name of a file
+containing a small (16 x 16) icon image. The file
+name is a relative path within the web application's
+war file.
+
+The image may be either in the JPEG or GIF format.
+The icon can be used by tools.
+
+Used in: icon
+
+Example:
+
+<small-icon>employee-service-icon16x16.jpg</small-icon>
+-->
+<!ELEMENT small-icon (#PCDATA)>
+
+<!--
+The taglib element is used to describe a JSP tag library.
+
+Used in: web-app
+-->
+<!ELEMENT taglib (taglib-uri, taglib-location)>
+
+<!--
+the taglib-location element contains the location (as a resource
+relative to the root of the web application) where to find the Tag
+Libary Description file for the tag library.
+
+Used in: taglib
+-->
+<!ELEMENT taglib-location (#PCDATA)>
+
+<!--
+The taglib-uri element describes a URI, relative to the location
+of the web.xml document, identifying a Tag Library used in the Web
+Application.
+
+Used in: taglib
+-->
+<!ELEMENT taglib-uri (#PCDATA)>
+
+<!--
+The transport-guarantee element specifies that the communication
+between client and server should be NONE, INTEGRAL, or
+CONFIDENTIAL. NONE means that the application does not require any
+transport guarantees. A value of INTEGRAL means that the application
+requires that the data sent between the client and server be sent in
+such a way that it can't be changed in transit. CONFIDENTIAL means
+that the application requires that the data be transmitted in a
+fashion that prevents other entities from observing the contents of
+the transmission. In most cases, the presence of the INTEGRAL or
+CONFIDENTIAL flag will indicate that the use of SSL is required.
+
+Used in: user-data-constraint
+-->
+<!ELEMENT transport-guarantee (#PCDATA)>
+
+<!--
+The url-pattern element contains the url pattern of the mapping. Must
+follow the rules specified in Section 11.2 of the Servlet API
+Specification.
+
+Used in: filter-mapping, servlet-mapping, web-resource-collection
+-->
+<!ELEMENT url-pattern (#PCDATA)>
+
+<!--
+The user-data-constraint element is used to indicate how data
+communicated between the client and container should be protected.
+
+Used in: security-constraint
+-->
+<!ELEMENT user-data-constraint (description?, transport-guarantee)>
+
+<!--
+The web-resource-collection element is used to identify a subset
+of the resources and HTTP methods on those resources within a web
+application to which a security constraint applies. If no HTTP methods
+are specified, then the security constraint applies to all HTTP
+methods.
+
+Used in: security-constraint
+-->
+<!ELEMENT web-resource-collection (web-resource-name, description?,
+url-pattern*, http-method*)>
+
+<!--
+The web-resource-name contains the name of this web resource
+collection.
+
+Used in: web-resource-collection
+-->
+<!ELEMENT web-resource-name (#PCDATA)>
+
+<!--
+The welcome-file element contains file name to use as a default
+welcome file, such as index.html
+
+Used in: welcome-file-list
+-->
+<!ELEMENT welcome-file (#PCDATA)>
+
+<!--
+The welcome-file-list contains an ordered list of welcome files
+elements.
+
+Used in: web-app
+-->
+<!ELEMENT welcome-file-list (welcome-file+)>
+
+<!--
+The ID mechanism is to allow tools that produce additional deployment
+information (i.e., information beyond the standard deployment
+descriptor information) to store the non-standard information in a
+separate file, and easily refer from these tool-specific files to the
+information in the standard deployment descriptor.
+
+Tools are not allowed to add the non-standard information into the
+standard deployment descriptor.
+-->
+
+<!ATTLIST auth-constraint id ID #IMPLIED>
+<!ATTLIST auth-method id ID #IMPLIED>
+<!ATTLIST context-param id ID #IMPLIED>
+<!ATTLIST description id ID #IMPLIED>
+<!ATTLIST display-name id ID #IMPLIED>
+<!ATTLIST distributable id ID #IMPLIED>
+<!ATTLIST ejb-link id ID #IMPLIED>
+<!ATTLIST ejb-local-ref id ID #IMPLIED>
+<!ATTLIST ejb-ref id ID #IMPLIED>
+<!ATTLIST ejb-ref-name id ID #IMPLIED>
+<!ATTLIST ejb-ref-type id ID #IMPLIED>
+<!ATTLIST env-entry id ID #IMPLIED>
+<!ATTLIST env-entry-name id ID #IMPLIED>
+<!ATTLIST env-entry-type id ID #IMPLIED>
+<!ATTLIST env-entry-value id ID #IMPLIED>
+<!ATTLIST error-code id ID #IMPLIED>
+<!ATTLIST error-page id ID #IMPLIED>
+<!ATTLIST exception-type id ID #IMPLIED>
+<!ATTLIST extension id ID #IMPLIED>
+<!ATTLIST filter id ID #IMPLIED>
+<!ATTLIST filter-class id ID #IMPLIED>
+<!ATTLIST filter-mapping id ID #IMPLIED>
+<!ATTLIST filter-name id ID #IMPLIED>
+<!ATTLIST form-error-page id ID #IMPLIED>
+<!ATTLIST form-login-config id ID #IMPLIED>
+<!ATTLIST form-login-page id ID #IMPLIED>
+<!ATTLIST home id ID #IMPLIED>
+<!ATTLIST http-method id ID #IMPLIED>
+<!ATTLIST icon id ID #IMPLIED>
+<!ATTLIST init-param id ID #IMPLIED>
+<!ATTLIST jsp-file id ID #IMPLIED>
+<!ATTLIST large-icon id ID #IMPLIED>
+<!ATTLIST listener id ID #IMPLIED>
+<!ATTLIST listener-class id ID #IMPLIED>
+<!ATTLIST load-on-startup id ID #IMPLIED>
+<!ATTLIST local id ID #IMPLIED>
+<!ATTLIST local-home id ID #IMPLIED>
+<!ATTLIST location id ID #IMPLIED>
+<!ATTLIST login-config id ID #IMPLIED>
+<!ATTLIST mime-mapping id ID #IMPLIED>
+<!ATTLIST mime-type id ID #IMPLIED>
+<!ATTLIST param-name id ID #IMPLIED>
+<!ATTLIST param-value id ID #IMPLIED>
+<!ATTLIST realm-name id ID #IMPLIED>
+<!ATTLIST remote id ID #IMPLIED>
+<!ATTLIST res-auth id ID #IMPLIED>
+<!ATTLIST res-ref-name id ID #IMPLIED>
+<!ATTLIST res-sharing-scope id ID #IMPLIED>
+<!ATTLIST res-type id ID #IMPLIED>
+<!ATTLIST resource-env-ref id ID #IMPLIED>
+<!ATTLIST resource-env-ref-name id ID #IMPLIED>
+<!ATTLIST resource-env-ref-type id ID #IMPLIED>
+<!ATTLIST resource-ref id ID #IMPLIED>
+<!ATTLIST role-link id ID #IMPLIED>
+<!ATTLIST role-name id ID #IMPLIED>
+<!ATTLIST run-as id ID #IMPLIED>
+<!ATTLIST security-constraint id ID #IMPLIED>
+<!ATTLIST security-role id ID #IMPLIED>
+<!ATTLIST security-role-ref id ID #IMPLIED>
+<!ATTLIST servlet id ID #IMPLIED>
+<!ATTLIST servlet-class id ID #IMPLIED>
+<!ATTLIST servlet-mapping id ID #IMPLIED>
+<!ATTLIST servlet-name id ID #IMPLIED>
+<!ATTLIST session-config id ID #IMPLIED>
+<!ATTLIST session-timeout id ID #IMPLIED>
+<!ATTLIST small-icon id ID #IMPLIED>
+<!ATTLIST taglib id ID #IMPLIED>
+<!ATTLIST taglib-location id ID #IMPLIED>
+<!ATTLIST taglib-uri id ID #IMPLIED>
+<!ATTLIST transport-guarantee id ID #IMPLIED>
+<!ATTLIST url-pattern id ID #IMPLIED>
+<!ATTLIST user-data-constraint id ID #IMPLIED>
+<!ATTLIST web-app id ID #IMPLIED>
+<!ATTLIST web-resource-collection id ID #IMPLIED>
+<!ATTLIST web-resource-name id ID #IMPLIED>
+<!ATTLIST welcome-file id ID #IMPLIED>
+<!ATTLIST welcome-file-list id ID #IMPLIED>
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/BatchProcessor.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/BatchProcessor.java
new file mode 100644
index 00000000..31f9ca50
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/BatchProcessor.java
@@ -0,0 +1,229 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import org.w3c.dom.*;
+
+import org.apache.xerces.parsers.DOMParser;
+import java.util.logging.*;
+import netscape.ldap.controls.LDAPProxiedAuthControl;
+import netscape.ldap.LDAPSearchConstraints;
+
+public class BatchProcessor {
+
+ private static Logger logger = Logger.getLogger("com.netscape.dsml.gateway.BatchProcessor");
+
+ private boolean attribute_resumeOnError = false;
+ private boolean FirstRequest = true;
+ private boolean dontHalt = true;
+
+ private javax.xml.soap.SOAPElement root = null;
+ private javax.xml.soap.SOAPElement batch = null;
+ private java.util.Vector requests = new java.util.Vector(1);
+
+ static private javax.xml.soap.MessageFactory messageFactory ;
+ static private javax.xml.soap.SOAPFactory sef ;
+
+ private IConnectionManager ldap_pool = null;
+
+ public javax.xml.parsers.DocumentBuilderFactory dbf;
+ public javax.xml.parsers.DocumentBuilder builder;
+ LDAPSearchConstraints proxyAuth = null;
+
+ public BatchProcessor(javax.xml.soap.SOAPBody sb) {
+
+ root = (javax.xml.soap.SOAPElement) sb;
+
+
+
+ }
+
+ public void init() throws gatewayException {
+
+ try {
+ ProxyConnMgrFactory pmc = new ProxyConnMgrFactory();
+ ldap_pool = pmc.getInstance();
+ }
+ catch (Exception e) {
+ throw new gatewayException( e.getMessage() );
+
+ }
+
+ try {
+ dbf = javax.xml.parsers.DocumentBuilderFactory.newInstance();
+ builder = dbf.newDocumentBuilder();
+ org.w3c.dom.Document d = builder.newDocument();
+
+ }
+ catch (Exception e) {
+ throw new gatewayException( e.getMessage() );
+ }
+
+ }
+
+ public void setProxy(String DN){
+ LDAPProxiedAuthControl ctrl = new LDAPProxiedAuthControl( DN, true );
+ proxyAuth = new LDAPSearchConstraints();
+ proxyAuth.setServerControls( ctrl );
+
+ }
+
+ public boolean preprocess() throws javax.xml.soap.SOAPException {
+
+ if (root.getChildElements().hasNext() &&
+ ((javax.xml.soap.SOAPElement) root.getChildElements().next()).getLocalName().equalsIgnoreCase("batchRequest")) {
+
+ this.batch = (javax.xml.soap.SOAPElement) root.getChildElements().next();
+
+ /* attributes for batchRequest:
+ * "reponseOrder" -- not implemented
+ * "processing" -- not implemented
+ * "onError" -- implemented
+ */
+ if (batch.getAttribute("onError") == null )
+ attribute_resumeOnError = false;
+ else
+ attribute_resumeOnError = (batch.getAttribute("onError").equalsIgnoreCase("resume ")) ? true : false ;
+
+ java.util.Iterator i = batch.getChildElements();
+
+ while (i.hasNext()) {
+ requests.add( i.next() );
+ logger.log(Level.INFO, "adding request");
+ }
+ return true;
+ }
+ else {
+ // error, no batchrequest... exit gracefully
+
+ logger.log(Level.INFO, "NO batchRequest in this envelope");
+ return false;
+ }
+
+
+
+ }
+
+ protected void finalize() {
+ try { ldap_pool.shutdown(); }
+ catch (Exception e) { }
+ }
+
+ void process(int index) {
+ netscape.ldap.LDAPConnection ldc = null;
+
+ ldc = ldap_pool.getConnection("");
+
+ if (ldc == null) {
+ requests.set(index,null);
+ }
+ else {
+
+ /* This is a hack:
+ * This code is required because of Axis' incomplete
+ * implementation. Without these, whenever getNodeValue() and friends are
+ * called, exceptions are deliberately thrown. When Axis is fully
+ * functional it should be able to be removed. The following lines
+ * probably impact performance negatively. */
+ DOMParser p = new DOMParser();
+ try {
+ p.parse(new org.xml.sax.InputSource(new java.io.StringReader(this.requests.get(index).toString())));
+ } catch (Exception E) { E.printStackTrace(); }
+ /* END */
+
+ Document doc = p.getDocument();
+ Node myRequest = doc.getDocumentElement();
+
+ String RequestType = myRequest.getLocalName();
+ gatewayContext context = new gatewayContext();
+
+
+ Node res = null;
+ if (proxyAuth != null)
+ context.setConstraints( proxyAuth);
+ context.setLdapConnection(ldc);
+ context.setRootNode(myRequest.cloneNode(true));
+
+ logger.log(Level.INFO, "Processing: starting {0}", RequestType);
+
+ if (FirstRequest && RequestType.equals("authRequest")){
+ if (FirstRequest) {
+
+ OperationAuth CurrentOperation = new OperationAuth();
+ res = CurrentOperation.getResponse(context) ;
+
+ FirstRequest = false;
+ } else {
+ // error
+ }
+
+ } else if (RequestType.equals("searchRequest")) {
+
+ OperationSearch CurrentOperation = new OperationSearch();
+ res = CurrentOperation.getResponse(context) ;
+
+ } else if (RequestType.equals("modifyRequest")){
+
+ OperationModify CurrentOperation= new OperationModify();
+ res = CurrentOperation.getResponse(context) ;
+
+ } else if (RequestType.equals("addRequest")) {
+
+ OperationAdd CurrentOperation = new OperationAdd();
+ res = CurrentOperation.getResponse(context) ;
+
+ } else if (RequestType.equals("delRequest")) {
+
+ OperationDelete CurrentOperation = new OperationDelete();
+ res = CurrentOperation.getResponse(context) ;
+
+ } else if (RequestType.equals("modDNRequest")) {
+
+ OperationModifyDN CurrentOperation = new OperationModifyDN();
+ res = CurrentOperation.getResponse(context) ;
+
+ } else if (RequestType.equals("compareRequest")) {
+
+ OperationCompare CurrentOperation = new OperationCompare();
+ res = CurrentOperation.getResponse(context) ;
+
+ } else if (RequestType.equals("extendedRequest")) {
+
+ OperationExtended CurrentOperation = new OperationExtended();
+ res = CurrentOperation.getResponse(context) ;
+
+ } else {
+ // output = echoHeaderStringHandler.sef.createElement("errorReponse");
+ }
+
+
+
+
+ requests.set(index,res);
+ logger.log(Level.INFO, "Processing: finished {0}", RequestType);
+ FirstRequest = false;
+
+ ldap_pool.releaseConnection("", ldc);
+ }
+ }
+
+
+
+ public boolean Error(){
+ return !this.dontHalt;
+ }
+
+ public int getRequestCount(){
+ return this.requests.size();
+ }
+
+ public javax.xml.soap.SOAPElement getRequestItem(int index) {
+ return (javax.xml.soap.SOAPElement) this.requests.get(index);
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/Configuration.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/Configuration.java
new file mode 100644
index 00000000..98f78a62
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/Configuration.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import java.io.*;
+import java.util.Properties;
+import java.util.logging.*;
+
+public class Configuration {
+ private static Logger logger = Logger.getLogger("com.netscape.dsml.gateway.Configuration");
+
+ private static String propertiesFilename;
+ private final static String header = "properties file for the Netscape DSMLGW";
+ private final static String[][] defaults = new String[][]
+ { { "MinPool", "5" },
+ { "MaxPool", "10" },
+ { "MinLoginPool", "2" },
+ { "MaxLoginPool", "5" },
+ { "ServerHost", "localhost" },
+ { "ServerPort", "389" },
+ { "BindDN", "" },
+ { "BindPW" , "" },
+ { "UseAuth", "false" }
+ };
+
+ private static Configuration _instance = null;
+ private static Object lock = new Object();
+ private static Properties properties = null;
+
+ /** Creates a new instance of Config */
+ private Configuration() {
+
+ propertiesFilename = System.getProperty("user.home","") + System.getProperty("file.separator") + "dsmlgw.cfg";
+ logger.log( Level.CONFIG, "using properties filename " + propertiesFilename);
+ load();
+ }
+
+ public static Configuration getInstance() {
+ if (null == _instance ) {
+ synchronized(lock) {
+ if (_instance == null )
+ _instance = new Configuration();
+
+ }
+ }
+ return _instance;
+ }
+
+
+ private void load() {
+ try {
+
+ properties = new Properties();
+
+ for (int i=0; i< defaults.length; i++)
+ properties.setProperty(defaults[i][0], defaults[i][1] );
+
+
+ FileInputStream in = null;
+ in = new FileInputStream(propertiesFilename);
+ properties.load(in);
+
+ } catch (java.io.FileNotFoundException e) {
+
+ System.err.println("Can't find properties file: " + propertiesFilename + ". " +
+ "Using defaults.");
+
+ } catch (java.io.IOException e) {
+
+ System.err.println("Can't read properties file: " + propertiesFilename + ". " +
+ "Using defaults.");
+
+ }
+
+ }
+
+
+ public int getMinPool() { return Integer.parseInt(properties.getProperty("MinPool")); }
+ public int getMaxPool() { return Integer.parseInt(properties.getProperty("MaxPool")); }
+ public int getMinLoginPool() { return Integer.parseInt(properties.getProperty("MinLoginPool")); }
+ public int getMaxLoginPool() { return Integer.parseInt(properties.getProperty("MaxLoginPool")); }
+ public int getServerPort() { return Integer.parseInt(properties.getProperty("ServerPort")); }
+
+ public String getServerHost() { return properties.getProperty("ServerHost"); }
+
+ public String getBindDN() { return properties.getProperty("BindDN"); }
+ public String getBindPW() { return properties.getProperty("BindPW"); }
+
+ public boolean getUseAuth() { return Boolean.valueOf( properties.getProperty("UseAuth").trim() ).booleanValue(); }
+
+}
+
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/Constants.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/Constants.java
new file mode 100644
index 00000000..6bb14f41
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/Constants.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+/**
+ * Constants used in the code.
+ */
+public class Constants
+{
+ public static final String DSML20_URN = "urn:oasis:dsml:names:tc:DSML:2:0:core";
+ public static final String BATCH_REQUEST = "batchRequest";
+ public static final String BATCH_RESPONSE = "batchResponse";
+
+ public static final String DSML_REQUEST = "DSMLRequest";
+ public static final String DSML_RESPONSE = "DSMLResponse";
+
+ public static final String AUTH_REQUEST = "authRequest";
+ public static final String SEARCH_REQUEST = "searchRequest";
+ public static final String MODIFY_REQUEST = "modifyRequest";
+ public static final String ADD_REQUEST = "addRequest";
+ public static final String DEL_REQUEST = "delRequest";
+ public static final String MODDN_REQUEST = "modDNRequest";
+ public static final String COMPARE_REQUEST = "compareRequest";
+ public static final String ABANDON_REQUEST = "abandonRequest";
+ public static final String EXTENDED_REQ = "extendedRequest";
+
+
+ public static final String AUTH_RESPONSE = "authResponse";
+ public static final String SEARCH_RES_ENTRY = "searchResultEntry";
+ public static final String SEARCH_RES_REF = "searchResultReference";
+ public static final String SEARCH_RES_DONE = "searchResultDone";
+ public static final String MODIFY_RESPONSE = "modifyResponse";
+ public static final String ADD_RESPONSE = "addResponse";
+ public static final String DEL_RESPONSE = "delResponse";
+ public static final String MODDN_RESPONSE = "modDNResponse";
+ public static final String COMPARE_RESPONSE = "compareResponse";
+ public static final String ABANDON_RESPONSE = "abandonResponse";
+ public static final String EXTENDED_RESPONSE= "extendedResponse";
+ public static final String ERROR_RESPONSE = "errorResponse";
+ public static final String SEARCH_RESPONSE = "searchResponse";
+
+ public static final String ERROR_TYPE = "type";
+ public static final String ERROR_MESSAGE = "message";
+
+
+ public static final String REQUEST_ID = "requestID";
+
+ public static final String PROCESSING = "processing";
+ public static final String SEQUENTIAL = "sequential";
+ public static final String PARALLEL = "parallel";
+
+ public static final String RESPONSE_ORDER = "responseOrder";
+ public static final String UNORDERED = "unOrdered";
+
+ public static final String ON_ERROR = "onError";
+ public static final String RESUME = "resume";
+ public static final String EXIT = "exit";
+
+
+ public static final String NOT_ATTEMPTED = "notAttempted";
+ public static final String UNKNOWN_REQ = "Unknown Request";
+
+ public static final String BINDREQ_ERROR_MESSAGE = "Found a BindRequest which is not the first request";
+ public static final String BATCH_RESPONSE_START_TAG = "<batchResponse xmlns=\"" + DSML20_URN + "\">";
+ public static final String BATCH_RESPONSE_END_TAG = "</batchResponse>";
+
+ public static final String DN = "dn";
+ //Modify Request
+ public static final String ATTR = "attr";
+ public static final String OPERATION = "operation";
+ public static final String ADD_OPERATION = "add";
+ public static final String DELETE_OPERATION = "delete";
+ public static final String REPLACE_OPERATION = "replace";
+ public static final String NAME = "name";
+ public static final String VALUE = "value";
+ public static final String RESULT_CODE = "resultCode";
+ public static final String CODE = "code";
+ public static final String DESC = "desc";
+
+ public static final String FILTER = "filter";
+ public static final String SUBSTRINGS = "substrings";
+ public static final String EQUALITY_MATCH = "equalityMatch";
+ public static final String GREATER_OR_EQAUAL = "greaterOrEqual";
+ public static final String LESS_OR_EQAUAL = "lessOrEqual";
+ public static final String PRESENT = "present";
+ public static final String APPROX_MATCH = "approxMatch";
+ public static final String EXTENSIBLE_MATCH = "extensibleMatch";
+ public static final String MATCHING_RULE = "matchingRule";
+ public static final String DN_ATTRIBUTES = "dnAttributes";
+ public static final String AND = "and";
+ public static final String OR = "or";
+ public static final String NOT = "not";
+
+ public static final String SUBSTRING_INITIAL = "initial";
+ public static final String SUBSTRING_ANY = "any";
+ public static final String SUBSTRING_FINAL = "final";
+
+ public static final String CONTROL = "control";
+ public static final String CONTROL_TYPE = "type";
+ public static final String CONTROL_CRITICALITY = "criticality";
+ public static final String CONTROL_VALUE = "controlValue";
+
+ public static final String SCOPE = "scope";
+ public static final String BASE_SCOPE = "baseObject";
+ public static final String SINGLE_LEVEL_SCOPE = "singleLevel";
+ public static final String WHOLE_TREE_SCOPE = "wholeSubTree";
+
+
+ public static final String DREF_ALIASES = "derefAliases";
+ public static final String NEVER_DREF_ALIASES = "neverDerefAliases";
+ public static final String DEREF_IN_SEARCH = "derefInSearching";
+ public static final String DREF_FIND_BASE_OBJ = "derefFindingBaseObj";
+ public static final String DREF_ALWAYS = "derefAlways";
+
+ public static final String SIZE_LIMIT = "sizeLimit";
+ public static final String TIME_LIMIT = "timeLimit";
+ public static final String TYPES_ONLY = "typesOnly";
+
+ public static final String ATTRIBUTES = "attributes";
+ public static final String ATTRIBUTE = "attribute";
+
+ public static final String ERRORMESSAGE = "errorMessage";
+ public static final String MATCHED_DN = "matchedDN";
+ public static final String ERR_REFERRAL_STR = "referral";
+ public static final String REF = "ref";
+ public static final String NEWRDN = "newrdn";
+ public static final String DELETEOLDRDN = "deleteoldrdn";
+ public static final String NEWSUPERIOR = "newSuperior";
+ public static final String ASSERTION = "assertion";
+ public static final String REQUESTNAME = "requestName";
+ public static final String REQUESTVALUE = "requestValue";
+ public static final String DSMLNS = "dsml:";
+
+ public static final int BATCH = 0;
+ public static final int DSML_REQ = 1;
+ public static final int DEFAULT_PORT = 389;
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/GenericOperation.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/GenericOperation.java
new file mode 100644
index 00000000..b718c519
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/GenericOperation.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+
+/**
+ *
+ * @author elliot
+ *
+ * This {interface|class} is the standard request. Specific requests / reponses
+ * inherit from this.
+ */
+class GenericOperation {
+ org.w3c.dom.Node root = null;
+ LDAPConnection ldapConn = null;
+ javax.xml.soap.MessageFactory messageFactory = null ;
+ javax.xml.soap.SOAPFactory sef = null;
+
+ /** Creates a new instance of OperationCompare */
+ public GenericOperation() {
+ try {
+ messageFactory = javax.xml.soap.MessageFactory.newInstance();
+ sef = javax.xml.soap.SOAPFactory.newInstance();
+ } catch (Exception E) {E.printStackTrace();}
+ }
+
+
+ public void setRoot(org.w3c.dom.Node op) {
+ if (root == null)
+ root = op;
+
+ }
+
+ public void setLDAPConnection(LDAPConnection lc) {
+ if (ldapConn == null)
+ ldapConn = lc;
+ }
+ // abstract javax.xml.soap.SOAPElement getResponse(gatewayContext ctx);
+} \ No newline at end of file
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/IConnMgrFactoryFunctor.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/IConnMgrFactoryFunctor.java
new file mode 100644
index 00000000..c13a9503
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/IConnMgrFactoryFunctor.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+/**
+ * This interface defines the factory interfaces. Each connection manager implements
+ * must use the factory interface. The design patterns used are: Abstract Factory,
+ * Factory Method and Functor patterns in the GoF book.
+ */
+
+public interface IConnMgrFactoryFunctor
+{
+ /**
+ * @return An instance of the connection manager factory
+ */
+ public IConnectionManager getInstance() throws Exception;
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/IConnectionManager.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/IConnectionManager.java
new file mode 100644
index 00000000..ee4300f8
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/IConnectionManager.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import java.io.IOException;
+import netscape.ldap.LDAPConnection;
+
+public interface IConnectionManager {
+
+
+ public void shutdown();
+ public LDAPConnection getConnection();
+ public LDAPConnection getLoginConnection();
+ public void releaseConnection(LDAPConnection ld);
+ /**
+ * release the connection
+ *
+ * @param the login ctx
+ * @param the LDAP connection
+ */
+ public void releaseConnection(String loginCtx, LDAPConnection ld);
+ public LDAPConnection getConnection(String loginCtx);
+
+
+} \ No newline at end of file
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/LDAPAuthenticator.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/LDAPAuthenticator.java
new file mode 100644
index 00000000..017c067b
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/LDAPAuthenticator.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+/**
+ *
+ * @author elliot
+ */
+public class LDAPAuthenticator {
+
+ String DN = null;
+ String PW = null;
+
+
+ /** Creates a new instance of LDAPAuthenticator */
+ public LDAPAuthenticator(String username, String password) {
+ DN = username;
+ PW = password;
+ }
+
+ public int authenticate() {
+
+ if (DN == null && PW == null)
+ return 0;
+
+ LDAPConnection ldc = null;
+
+ ProxyConnMgrFactory pmc = new ProxyConnMgrFactory();
+ IConnectionManager ldap_pool= pmc.getInstance();
+
+ ldc = ldap_pool.getLoginConnection();
+
+ if (ldc != null) {
+ try {
+ ldc.authenticate( DN, PW );
+ } catch ( LDAPException e ) {
+ switch( e.getLDAPResultCode() ) {
+ case LDAPException.NO_SUCH_OBJECT:
+ // System.out.println( "The specified user does not exist." );
+ return LDAPException.NO_SUCH_OBJECT;
+
+ case LDAPException.INVALID_CREDENTIALS:
+ // System.out.println( "Invalid password." );
+ return LDAPException.INVALID_CREDENTIALS;
+
+ default:
+ // System.out.println( "Error number: " + e.getLDAPResultCode() );
+ // System.out.println( "Failed to authentice as " + DN );
+ return e.getLDAPResultCode() ;
+
+ }
+ }
+ // System.out.println( "Authenticated as " + DN );
+ return 0;
+ } else {
+
+ // System.out.println( "Can't establish connection to LDAP server");
+ return LDAPException.UNAVAILABLE ;
+ }
+ }
+} \ No newline at end of file
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationAdd.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationAdd.java
new file mode 100644
index 00000000..5b3046c2
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationAdd.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+
+public class OperationAdd extends GenericOperation {
+
+ public javax.xml.soap.SOAPElement getResponse(gatewayContext ctx) {
+
+ ldapConn = ctx.getLdapConnection();
+ root = ctx.getRootNode();
+
+ LDAPAttributeSet ldAttrSet = new LDAPAttributeSet();
+ // XXX is this really necessary?
+ // if (ldAttrSet == null ) {
+ // throw new Exception("MEMORY_ALLOCATION_ERROR");
+ // }
+
+ String dn = root.getAttributes().getNamedItem("dn").getNodeValue().trim();
+
+ org.w3c.dom.NodeList nl = root.getChildNodes();
+ for (int i=0; i< nl.getLength(); i++) {
+
+ if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
+ try {
+ Node attr = nl.item(i).getFirstChild();
+ if (attr.getNodeType() == Node.TEXT_NODE)
+ attr = attr.getNextSibling();
+
+ String attrName = nl.item(i).getAttributes().getNamedItem("name").getNodeValue();
+ String attrValue;
+
+ if (attr.getNodeType() == Node.ELEMENT_NODE)
+ attrValue=attr.getFirstChild().getNodeValue();
+ else
+ attrValue=attr.getNextSibling().getFirstChild().getNodeValue();
+
+ LDAPAttribute ldapAttr = new LDAPAttribute( attrName, attrValue);
+
+ if (ldapAttr != null ) {
+ ldAttrSet.add(ldapAttr);
+ }
+
+
+
+ }
+ catch (Exception e) { e.printStackTrace();}
+ }
+
+ }
+
+ int resultCode= 0;
+ String errorMessage = "completed";
+ LDAPEntry entry = new LDAPEntry(dn,ldAttrSet);
+ javax.xml.soap.SOAPElement output = null;
+
+ try {
+
+
+
+
+ if (ctx.getConstraints() != null) {
+ ldapConn.add(entry, ctx.getConstraints() ); }
+ else {
+ ldapConn.add( entry ); }
+
+
+ } catch (LDAPException E) {
+ resultCode = E.getLDAPResultCode();
+ errorMessage = E.getLDAPErrorMessage();
+
+
+ }
+ javax.xml.soap.SOAPBodyElement sbe = null;
+ try {
+ sbe = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("addResponse") );
+ sbe.addChildElement("resultCode").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), new Integer(resultCode).toString() );
+ if (errorMessage != null)
+ sbe.addChildElement("errorMessage").addTextNode(errorMessage);
+
+
+ } catch (Exception E) {
+ E.printStackTrace();
+ }
+
+ return sbe;
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationAuth.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationAuth.java
new file mode 100644
index 00000000..776aeeb3
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationAuth.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+
+public class OperationAuth extends GenericOperation {
+
+ public javax.xml.soap.SOAPElement getResponse(gatewayContext ctx) {
+
+ ldapConn = ctx.getLdapConnection();
+ root = ctx.getRootNode();
+
+
+ javax.xml.soap.SOAPBodyElement sbe = null;
+ try {
+ sbe = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("authResponse") );
+ sbe.addChildElement("resultCode").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), new Integer( netscape.ldap.LDAPException.AUTH_METHOD_NOT_SUPPORTED).toString() );
+
+ } catch (Exception E) {
+ E.printStackTrace();
+ }
+
+ return sbe;
+ }
+
+
+
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationCompare.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationCompare.java
new file mode 100644
index 00000000..45939c32
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationCompare.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+
+public class OperationCompare extends GenericOperation {
+
+ public javax.xml.soap.SOAPElement getResponse(gatewayContext ctx) {
+
+ ldapConn = ctx.getLdapConnection();
+ root = ctx.getRootNode();
+
+
+ String dn = root.getAttributes().getNamedItem("dn").getNodeValue().trim();
+
+ LDAPAttribute attr = null;
+ org.w3c.dom.NodeList nl = root.getChildNodes();
+ for (int i=0; i< nl.getLength(); i++) {
+ if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
+ try {
+ if (nl.item(i).getLocalName().equals("assertion") ) {
+
+ String field = nl.item(i).getAttributes().getNamedItem("name").getNodeValue();
+ attr = new LDAPAttribute(field);
+
+ NodeList Values = nl.item(i).getChildNodes();
+
+ for (int j=0; j< Values.getLength(); j++) {
+ if (Values.item(j).getNodeType() == Node.ELEMENT_NODE &&
+ Values.item(j).getLocalName().equals("value")) {
+ attr.addValue(Values.item(j).getFirstChild().getNodeValue());
+
+ }
+
+ }
+ }
+ } catch (Exception e) { }
+ }
+ }
+
+ boolean result;
+ int resultCode= 0;
+ String errorMessage = "completed";
+
+ javax.xml.soap.SOAPElement output = null;
+ LDAPAttribute attribute=null;
+
+
+
+ try {
+ if (ctx.getConstraints() != null)
+ result = ldapConn.compare(dn, attr, ctx.getConstraints() );
+ else
+ result = ldapConn.compare(dn, attr);
+
+ } catch (LDAPException E) {
+ resultCode = E.getLDAPResultCode();
+ errorMessage = E.getLDAPErrorMessage() ;
+ }
+ javax.xml.soap.SOAPBodyElement sbe = null;
+ try {
+ sbe = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("modDNResponse") );
+ sbe.addChildElement("resultCode").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), new Integer(resultCode).toString() );
+ if (errorMessage != null)
+ sbe.addChildElement("errorMessage").addTextNode(errorMessage);
+
+
+ } catch (Exception E) {
+ E.printStackTrace();
+ }
+
+ return sbe;
+
+ }
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationDelete.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationDelete.java
new file mode 100644
index 00000000..995fc2bf
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationDelete.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+
+
+public class OperationDelete extends GenericOperation {
+
+
+ public javax.xml.soap.SOAPElement getResponse(gatewayContext ctx) {
+
+ ldapConn = ctx.getLdapConnection();
+ root = ctx.getRootNode();
+
+
+ String dn = root.getAttributes().getNamedItem("dn").getNodeValue().trim();
+
+ int resultCode= 0;
+ String errorMessage = "completed";
+
+ javax.xml.soap.SOAPElement output = null;
+
+
+
+ try {
+ if (ctx.getConstraints() != null)
+ ldapConn.delete(dn, ctx.getConstraints() );
+ else
+ ldapConn.delete(dn);
+
+ } catch (LDAPException E) {
+ resultCode = E.getLDAPResultCode();
+ errorMessage = E.getLDAPErrorMessage() ;
+ }
+ javax.xml.soap.SOAPBodyElement sbe = null;
+ try {
+ sbe = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("deleteResponse") );
+ sbe.addChildElement("resultCode").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), new Integer(resultCode).toString() );
+ if (errorMessage != null)
+ sbe.addChildElement("errorMessage").addTextNode(errorMessage);
+
+ } catch (Exception E) {
+ E.printStackTrace();
+ }
+
+ return sbe;
+
+
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationExtended.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationExtended.java
new file mode 100644
index 00000000..bbffd947
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationExtended.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+import netscape.ldap.util.ByteBuf;
+import netscape.ldap.util.MimeBase64Decoder;
+
+public class OperationExtended extends GenericOperation {
+
+ public javax.xml.soap.SOAPElement getResponse(gatewayContext ctx) {
+
+ ldapConn = ctx.getLdapConnection();
+ root = ctx.getRootNode();
+
+
+
+
+
+ LDAPException ldException = null;
+ LDAPSearchResults results = null;
+ LDAPSearchConstraints searchConstraint = new LDAPSearchConstraints();
+ java.util.Vector modifications = new java.util.Vector(1);
+
+ String oid = new String();
+ ByteBuf value=new ByteBuf();
+ String binaryStr = null;
+ org.w3c.dom.NodeList nl = root.getChildNodes();
+ for (int i=0; i< nl.getLength(); i++) {
+ if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
+ try {
+ if (nl.item(i).getLocalName().equals("requestName") ) {
+ oid = nl.item(i).getFirstChild().getNodeValue().trim();
+
+ } else if (nl.item(i).getLocalName().equals("requestValue") ) {
+
+ // Assuming the it is base64Binary
+ binaryStr = nl.item(i).getFirstChild().getNodeValue();
+ ByteBuf inputBuf = new ByteBuf(binaryStr);
+ value = new ByteBuf();
+ MimeBase64Decoder decoder = new MimeBase64Decoder();
+ decoder.translate(inputBuf, value);
+ decoder.eof(value);
+
+ }
+
+ } catch (Exception e) { }
+ }
+ }
+
+
+ LDAPExtendedOperation extendedOperation = new LDAPExtendedOperation(oid, null );
+
+ int resultCode= 0;
+ String errorMessage = "completed";
+
+ javax.xml.soap.SOAPElement output = null;
+
+
+ LDAPExtendedOperation result = null;
+ try {
+ if (ctx.getConstraints() != null)
+ result = ldapConn.extendedOperation(extendedOperation, ctx.getConstraints() );
+ else
+ result = ldapConn.extendedOperation(extendedOperation);
+
+ } catch (LDAPException E) {
+ resultCode = E.getLDAPResultCode();
+ errorMessage = E.getLDAPErrorMessage() ;
+ }
+ javax.xml.soap.SOAPBodyElement sbe = null;
+ try {
+ sbe = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("extendedResponse") );
+ sbe.addChildElement("resultCode").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), new Integer(resultCode).toString() );
+ sbe.addChildElement("reponse").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("xsi:type"), "xsd:base64Binary" ).setNodeValue( result.getValue().toString() );
+
+
+ } catch (Exception E) {
+ E.printStackTrace();
+ }
+
+ return sbe;
+
+
+
+ }
+} \ No newline at end of file
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationModify.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationModify.java
new file mode 100644
index 00000000..f9d47ecb
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationModify.java
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+import java.util.logging.*;
+
+public class OperationModify extends GenericOperation {
+ private static Logger logger = Logger.getLogger("com.netscape.dsml.gateway.OperationModify");
+ org.w3c.dom.Node root = null;
+ LDAPConnection ldapConn = null;
+ javax.xml.soap.MessageFactory messageFactory = null ;
+ javax.xml.soap.SOAPFactory sef = null;
+
+ OperationModify(){
+ try {
+ messageFactory = javax.xml.soap.MessageFactory.newInstance();
+ sef = javax.xml.soap.SOAPFactory.newInstance();
+ } catch (Exception E) {E.printStackTrace();
+ }
+ }
+
+ public javax.xml.soap.SOAPElement getResponse(gatewayContext ctx) {
+
+ ldapConn = ctx.getLdapConnection();
+ root = ctx.getRootNode();
+
+
+ LDAPException ldException = null;
+ LDAPSearchResults results = null;
+ LDAPSearchConstraints searchConstraint = new LDAPSearchConstraints();
+ java.util.Vector modifications = new java.util.Vector(1);
+ String dn = root.getAttributes().getNamedItem("dn").getNodeValue().trim();
+
+ org.w3c.dom.NodeList nl = root.getChildNodes();
+ for (int i=0; i< nl.getLength(); i++) {
+ if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
+ try {
+ if (nl.item(i).getLocalName().equals("modification") ) {
+
+ // should check to make sure there's only one child to this filter
+
+ Node mod = nl.item(i);
+
+ String modify_field = mod.getAttributes().getNamedItem("name").getNodeValue().trim();
+ String modify_op = mod.getAttributes().getNamedItem("operation").getNodeValue();
+
+ logger.log(Level.INFO, "modify_field: {0}", modify_field);
+ logger.log(Level.INFO, "modify_op: {0}", modify_op);
+
+ int op = -1;
+ LDAPAttribute attr = new LDAPAttribute(modify_field);
+
+ NodeList Values = mod.getChildNodes();
+
+ for (int j=0; j< Values.getLength(); j++) {
+ if (Values.item(j).getNodeType() == Node.ELEMENT_NODE &&
+ Values.item(j).getLocalName().equals("value")) {
+ attr.addValue(Values.item(j).getFirstChild().getNodeValue());
+
+ }
+
+ }
+
+
+
+ if (modify_op.equals("replace")) {
+ op =LDAPModification.REPLACE;
+ } else if (modify_op.equals("delete")) {
+ op =LDAPModification.DELETE;
+ } else if (modify_op.equals("add")) {
+ op =LDAPModification.ADD;
+ }
+
+ modifications.add(new LDAPModification(op, attr));
+
+ }
+
+
+
+ }
+ catch (Exception e) { e.printStackTrace();}
+
+ }
+ }
+
+ LDAPModification[] lm = new LDAPModification[modifications.size()];
+ for (int i=0; i< modifications.size(); i++)
+ lm[i] = (LDAPModification) modifications.get(i);
+
+ int resultCode= 0;
+ String errorMessage = "completed";
+
+ javax.xml.soap.SOAPElement output = null;
+
+
+
+ try {
+ if (ctx.getConstraints() != null)
+ ldapConn.modify(dn, lm, ctx.getConstraints() );
+ else
+ ldapConn.modify(dn, lm);
+
+
+ } catch (LDAPException E) {
+ resultCode = E.getLDAPResultCode();
+ errorMessage = E.getLDAPErrorMessage() ;
+ }
+ javax.xml.soap.SOAPBodyElement sbe = null;
+ try {
+ sbe = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("modifyResponse") );
+ sbe.addChildElement("resultCode").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), new Integer(resultCode).toString() );
+ if (errorMessage != null)
+ sbe.addChildElement("errorMessage").addTextNode(errorMessage);
+
+
+ } catch (Exception E) {
+ E.printStackTrace();
+ }
+
+ return sbe;
+
+
+ }
+
+
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationModifyDN.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationModifyDN.java
new file mode 100644
index 00000000..138edb60
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationModifyDN.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+
+public class OperationModifyDN extends GenericOperation {
+
+ org.w3c.dom.Node root = null;
+ LDAPConnection ldapConn = null;
+ javax.xml.soap.MessageFactory messageFactory = null ;
+ javax.xml.soap.SOAPFactory sef = null;
+
+ OperationModifyDN(){
+ try {
+ messageFactory = javax.xml.soap.MessageFactory.newInstance();
+ sef = javax.xml.soap.SOAPFactory.newInstance();
+ } catch (Exception E) {E.printStackTrace();
+ }
+ }
+
+ public javax.xml.soap.SOAPElement getResponse(gatewayContext ctx) {
+
+ ldapConn = ctx.getLdapConnection();
+ root = ctx.getRootNode();
+
+
+ ldapConn = ctx.getLdapConnection();
+ root = ctx.getRootNode();
+
+
+ LDAPException ldException = null;
+ LDAPSearchResults results = null;
+ LDAPSearchConstraints searchConstraint = new LDAPSearchConstraints();
+
+ String dn = root.getAttributes().getNamedItem("dn").getNodeValue().trim();
+ String newRDN= root.getAttributes().getNamedItem("newrdn").getNodeValue().trim();
+
+ boolean deleteOldRDN= true;
+
+ try {
+ if (root.getAttributes().getNamedItem("deleteoldrdn") != null)
+ deleteOldRDN = new Boolean( root.getAttributes().getNamedItem("deleteoldrdn").getNodeValue().trim()).booleanValue();
+ } catch (Exception e) { }
+
+
+ // This is unsupported, but it's here for the sake of completion.
+ String newSuperior = null;
+ try {
+ if (root.getAttributes().getNamedItem("newSuperior") != null)
+ newSuperior = root.getAttributes().getNamedItem("newSuperior").getNodeValue().trim();
+ } catch (Exception e) { newSuperior = null; }
+
+ int resultCode= 0;
+ String errorMessage = "completed";
+
+ javax.xml.soap.SOAPElement output = null;
+
+
+
+ try {
+ if (ctx.getConstraints() != null)
+ ldapConn.rename(dn, newRDN, newSuperior, deleteOldRDN,ctx.getConstraints() );
+ else
+ ldapConn.rename(dn, newRDN, newSuperior, deleteOldRDN);
+
+ } catch (LDAPException E) {
+ resultCode = E.getLDAPResultCode();
+ errorMessage = E.getLDAPErrorMessage() ;
+ }
+ javax.xml.soap.SOAPBodyElement sbe = null;
+ try {
+ sbe = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("modDNResponse") );
+ sbe.addChildElement("resultCode").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), new Integer(resultCode).toString() );
+ if (errorMessage != null)
+ sbe.addChildElement("errorMessage").addTextNode(errorMessage);
+
+
+ } catch (Exception E) {
+ E.printStackTrace();
+ }
+
+ return sbe;
+
+
+ }
+
+
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationSearch.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationSearch.java
new file mode 100644
index 00000000..f75d8238
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/OperationSearch.java
@@ -0,0 +1,322 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+
+import java.util.logging.*;
+
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Node;
+import org.w3c.dom.traversal.NodeIterator;
+import org.w3c.dom.traversal.DocumentTraversal;
+import org.w3c.dom.traversal.TreeWalker;
+import org.w3c.dom.traversal.NodeFilter;
+
+class OperationSearch extends GenericOperation {
+
+ org.w3c.dom.Node root = null;
+ LDAPConnection ldapConn = null;
+ javax.xml.soap.MessageFactory messageFactory = null ;
+ javax.xml.soap.SOAPFactory sef = null;
+ private static Logger logger =
+ Logger.getLogger("com.netscape.dsml.service.ProxyConnectionManager");
+
+ OperationSearch(){
+ try {
+ messageFactory = javax.xml.soap.MessageFactory.newInstance();
+ sef = javax.xml.soap.SOAPFactory.newInstance();
+ } catch (Exception E) {E.printStackTrace();
+ }
+ }
+
+ public void setRoot(org.w3c.dom.Node op){
+ if (root == null)
+ root = op;
+ }
+
+ public void setLDAPConnection(LDAPConnection lc) {
+ if (ldapConn == null)
+ ldapConn = lc;
+ }
+
+ public javax.xml.soap.SOAPElement getResponse(gatewayContext ctx) {
+
+ ldapConn = ctx.getLdapConnection();
+ root = ctx.getRootNode();
+
+
+ int scope = -1;
+ int derefAliases = -1;
+
+ LDAPException ldException = null;
+ LDAPSearchResults results = null;
+
+ String dn = root.getAttributes().getNamedItem("dn").getNodeValue().trim();
+ String scopeRaw = root.getAttributes().getNamedItem("scope").getNodeValue().trim();
+ String derefAliasesRaw = root.getAttributes().getNamedItem("derefAliases").getNodeValue().trim();
+
+ int sizeLimit = 0;
+ try {
+ if ( root.getAttributes().getNamedItem("sizeLimit") != null)
+ sizeLimit = Integer.parseInt( root.getAttributes().getNamedItem("sizeLimit").getNodeValue());
+ } catch (Exception e) {}
+
+
+ int timeLimit = 0;
+ try {
+ if ( root.getAttributes().getNamedItem("timeLimit") != null)
+ timeLimit = Integer.parseInt( root.getAttributes().getNamedItem("timeLimit").getNodeValue());
+ } catch (Exception e) {}
+
+ boolean typesOnly = false;
+ try {
+ if ( root.getAttributes().getNamedItem("typesOnly") != null )
+ typesOnly = Boolean.valueOf(root.getAttributes().getNamedItem("typesOnly").getNodeValue()).booleanValue();
+ } catch (Exception e) {}
+
+
+ String attributeList[] = null;
+ java.util.Vector attributeRaw = new java.util.Vector();
+ java.util.Vector Controls = new java.util.Vector();
+ String filterString = new String();
+
+ root.normalize();
+
+ int whattoshow = NodeFilter.SHOW_ALL;
+ NodeFilter nodefilter = null;
+ boolean expandreferences = false;
+
+
+ org.w3c.dom.NodeList nl = root.getChildNodes();
+ for (int i=0; i< nl.getLength(); i++) {
+ if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
+ try {
+ if (nl.item(i).getLocalName().equals("filter") ) {
+ // should check to make sure there's only one child to this filter
+ NodeList filters = nl.item(i).getChildNodes();
+ for (int j=0; j< filters.getLength(); j++) {
+ if (filters.item(j).getNodeType() == Node.ELEMENT_NODE){
+ filterString = ParseFilter.parseFilterFromNode( filters.item(j));
+ }
+ }
+
+
+ } else if (nl.item(i).getLocalName().equals("attributes") ) {
+ NodeList attributes = nl.item(i).getChildNodes();
+
+ for (int j=0; j< attributes.getLength(); j++) {
+ if (attributes.item(j).getNodeType() == Node.ELEMENT_NODE){
+ attributeRaw.add( attributes.item(j).getAttributes().getNamedItem("name").getNodeValue() );
+ }
+ }
+ attributeList= new String[ attributeRaw.size()];
+ for (int j=0; j< attributeRaw.size(); j++)
+ attributeList[j] = (String) attributeRaw.get(j);
+
+ } else if (nl.item(i).getLocalName().equals("control") ) {
+ Controls.add( ParseControl.parseControlFromNode(nl.item(i)) );
+
+ }
+
+ }
+ catch (Exception e) { e.printStackTrace();}
+
+ } }
+ // XXX
+
+ if (scopeRaw.equals("baseObject"))
+ scope = ldapConn.SCOPE_BASE;
+ else if (scopeRaw.equals("singleLevel"))
+ scope = ldapConn.SCOPE_ONE;
+ else if (scopeRaw.equals("wholeSubtree"))
+ scope = ldapConn.SCOPE_SUB;
+ else
+ scope = ldapConn.SCOPE_BASE;
+
+
+ if (derefAliasesRaw.equals("neverDerefAliases"))
+ derefAliases = ldapConn.DEREF_NEVER;
+ else if (derefAliasesRaw.equals("derefInSearching"))
+ derefAliases = ldapConn.DEREF_SEARCHING;
+ else if (derefAliasesRaw.equals("derefFindingBaseObj"))
+ derefAliases = ldapConn.DEREF_FINDING;
+ else if (derefAliasesRaw.equals("derefAlways"))
+ derefAliases = ldapConn.DEREF_ALWAYS;
+ else
+ derefAliases = ldapConn.DEREF_NEVER;
+
+
+
+ logger.log(Level.INFO, "dn: {0}", dn);
+ logger.log(Level.INFO, "scope: {0}", scopeRaw);
+ logger.log(Level.INFO, "derefAliases: {0}", derefAliasesRaw);
+
+ logger.log(Level.INFO, "sizeLimit: {0}", String.valueOf(sizeLimit) );
+ logger.log(Level.INFO, "timeLimit: {0}", String.valueOf(timeLimit) );
+ logger.log(Level.INFO, "typesOnly: {0}", String.valueOf(typesOnly) );
+ if (attributeList ==null)
+ logger.log(Level.INFO, "attributeList: {0}", "null");
+ else
+ logger.log(Level.INFO, "attributeList: {0}", attributeList.toString() );
+ logger.log(Level.INFO, "filter: {0}", filterString );
+
+ /*
+ * System.out.println("dn : " + dn );
+ * System.out.println("scope : " + scopeRaw );
+ * System.out.println("derefAliases : " + derefAliasesRaw );
+ * System.out.println("sizeLimit : " + sizeLimit );
+ * System.out.println("timeLimit : " + timeLimit );
+ * System.out.println("typesOnly : " + typesOnly );
+ * System.out.println("filterString : " + filterString );
+ *
+ * System.out.println("attributeList[]");
+ * if (attributeList == null)
+ * System.out.println("null");
+ * else {
+ * for (int i=0; i < attributeList.length ; i++ )
+ * System.out.println("attributeList[" + i + "] : " + attributeList[i]);
+ *}
+ */
+
+ int resultCode = 0;
+ String errorMessage = "completed";
+
+ ctx.setConstraints( new LDAPSearchConstraints() );
+ ctx.getConstraints().setTimeLimit(timeLimit);
+ ctx.getConstraints().setDereference(derefAliases);
+ ctx.getConstraints().setMaxResults(sizeLimit);
+
+ try {
+ if (Controls.size() >0 ) {
+ if (ctx.getConstraints() == null) {
+ ctx.setConstraints( new LDAPSearchConstraints() );
+ }
+ // XXX this gave a class cast exception, don't understand why
+
+ netscape.ldap.LDAPControl tmp[] = new netscape.ldap.LDAPControl[ Controls.size() ];
+ for (int i=0; i< Controls.size(); i++) {
+ tmp[i] = (netscape.ldap.LDAPControl) Controls.get(i);
+ }
+
+ ctx.getConstraints().setServerControls( tmp );
+
+ }
+
+
+ if (ctx.getConstraints() != null)
+ results = ldapConn.search(dn, scope, filterString, attributeList, false, ctx.getConstraints() );
+ else
+ results = ldapConn.search( dn, scope, filterString, attributeList, false);
+
+ } catch (LDAPException E) {
+ resultCode = E.getLDAPResultCode();
+ errorMessage = "LDAP Error code " + new Integer(resultCode).toString();
+ // This line should work
+ // XXX errorMessage = LDAPException.errorCodeToString(resultCode);
+ E.printStackTrace();
+ }
+
+
+ javax.xml.soap.SOAPEnvelope elementFactory = null;
+ javax.xml.soap.SOAPBody entryFactory = null;
+ javax.xml.soap.SOAPBodyElement sbe = null;
+ try {
+ sbe = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("searchResponse") );
+ entryFactory = messageFactory.createMessage().getSOAPBody();
+ elementFactory = messageFactory.createMessage().getSOAPPart().getEnvelope();
+ } catch (Exception E) { };
+
+ if (results != null) {
+ while (results.hasMoreElements()) {
+ try {
+ LDAPEntry entry = results.next();
+ LDAPAttributeSet attributeset = entry.getAttributeSet();
+ java.util.Enumeration attribs = attributeset.getAttributes();
+ dn = entry.getDN();
+
+ javax.xml.soap.SOAPBodyElement searchresultentry = null;
+ try {
+ searchresultentry = entryFactory.addBodyElement(elementFactory.createName("searchResultEntry") );
+ searchresultentry.addAttribute(elementFactory.createName("dn"), dn);
+ sbe.addChildElement(searchresultentry);
+ } catch (Exception E) { E.printStackTrace(); }
+
+
+ while (attribs.hasMoreElements()) {
+ LDAPAttribute att = (LDAPAttribute) attribs.nextElement();
+
+ String[] values = att.getStringValueArray();
+ javax.xml.soap.SOAPElement attr = null;
+ attr = searchresultentry.addChildElement( elementFactory.createName("attr"));
+ attr.addAttribute(elementFactory.createName( "name" ), att.getName() );
+
+ for (int k=0; k< values.length;k++) {
+ javax.xml.soap.SOAPElement val = attr.addChildElement("value");
+ val.addTextNode( values[k] );
+ }
+
+ }
+
+ } catch (LDAPException E) {
+ resultCode = E.getLDAPResultCode();
+ errorMessage = E.getLDAPErrorMessage() ;
+ } catch (Exception E) { E.printStackTrace(); }
+
+ }
+
+ }
+
+ try {
+ javax.xml.soap.SOAPBodyElement resultdone = null;
+
+ resultdone = messageFactory.createMessage().getSOAPBody().addBodyElement(elementFactory.createName("searchResultDone") );
+
+ /* if there are controls to add to this envelope, they go in the searchresultdone tag */
+
+ netscape.ldap.LDAPControl serverControls[] = null;
+ if (results!=null)
+ serverControls = results.getResponseControls();
+
+ if (serverControls != null && serverControls.length >0) {
+
+ for (int k=0; k< serverControls.length; k++) {
+ if ( serverControls[k] instanceof netscape.ldap.controls.LDAPVirtualListResponse ) {
+ netscape.ldap.controls.LDAPVirtualListResponse lvlr = (netscape.ldap.controls.LDAPVirtualListResponse) serverControls[k];
+ javax.xml.soap.SOAPBodyElement ctl = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("control") );
+ ctl.addAttribute( messageFactory.createMessage().getSOAPPart().getEnvelope().createName("type"), netscape.ldap.controls.LDAPVirtualListResponse.VIRTUALLISTRESPONSE );
+ resultCode = lvlr.getResultCode();
+
+ javax.xml.soap.SOAPElement controlValue = messageFactory.createMessage().getSOAPBody().addChildElement("controlValue", "", "");
+ controlValue.addChildElement("begin", "").addTextNode( new Integer( lvlr.getFirstPosition() ).toString() );
+ controlValue.addChildElement("count", "").addTextNode( new Integer( lvlr.getContentCount() ).toString() );
+
+ resultdone.addChildElement( controlValue);
+
+ resultdone.addChildElement(ctl);
+ } else if ( serverControls[k] instanceof netscape.ldap.controls.LDAPSortControl ) {
+ netscape.ldap.controls.LDAPSortControl lsc = (netscape.ldap.controls.LDAPSortControl) serverControls[k];
+ javax.xml.soap.SOAPBodyElement ctl = messageFactory.createMessage().getSOAPBody().addBodyElement(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("control") );
+ ctl.addAttribute( messageFactory.createMessage().getSOAPPart().getEnvelope().createName("type"), netscape.ldap.controls.LDAPSortControl.SORTRESPONSE );
+ resultdone.addChildElement(ctl);
+ resultCode = lsc.getResultCode(); // new result code now by way of control
+ }
+ }
+ } /* end of control section */
+
+
+ resultdone.addChildElement("resultCode").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), new Integer(resultCode).toString() );
+ sbe.addChildElement(resultdone);
+ } catch (Exception E) {E.printStackTrace(); }
+
+ return sbe;
+
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ParseControl.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ParseControl.java
new file mode 100644
index 00000000..c0ac27a1
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ParseControl.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import org.w3c.dom.*;
+import java.util.logging.*;
+
+public class ParseControl {
+
+ public static netscape.ldap.LDAPControl parseControlFromNode(org.w3c.dom.Node n) {
+ Logger logger = Logger.getLogger("com.netscape.dsml.gateway.ParseControl");
+ String type = null;
+ byte[] value = null;
+ boolean criticality = false;
+
+
+ try {
+ type = n.getAttributes().getNamedItem("type").getNodeValue();
+ } catch (Exception e) {
+ // throw new gatewayException("control type can not be omitted");
+ }
+
+ try {
+ criticality = Boolean.valueOf( n.getAttributes().getNamedItem("criticality").getNodeValue() ).booleanValue();
+ } catch (Exception e) { /* ignore */ }
+
+
+ netscape.ldap.LDAPControl lc = null;
+ if (type.equals( netscape.ldap.controls.LDAPSortControl.SORTREQUEST ) ) {
+ try {
+ java.util.Vector ldskv = new java.util.Vector();
+
+ org.w3c.dom.NodeList nl = n.getFirstChild().getNextSibling().getChildNodes();
+ for (int i=0; i< nl.getLength(); i++) {
+ if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
+
+ if (nl.item(i).getLocalName().equals("attr") ) {
+
+ // should check to make sure there's only one child to this filter
+
+ Node mod = nl.item(i);
+
+ String attribute = mod.getAttributes().getNamedItem("name").getNodeValue().trim();
+ boolean reverse = false;
+
+ try {
+ reverse = new Boolean( mod.getAttributes().getNamedItem("reverse").getNodeValue().trim()).booleanValue();
+ } catch (Exception e) {}
+
+ netscape.ldap.LDAPSortKey ldsk = new netscape.ldap.LDAPSortKey(attribute, reverse);
+ logger.log(Level.FINE, "SSS: reverse: {0}", String.valueOf(reverse));
+ logger.log(Level.FINE, "SSS: attribute: {0}", attribute );
+
+ ldskv.add(ldsk);
+
+ }
+ }
+ }
+
+ netscape.ldap.LDAPSortKey sortkeys[] = new netscape.ldap.LDAPSortKey[ ldskv.size() ];
+ for (int j=0; j< ldskv.size(); j++)
+ sortkeys[j] = (netscape.ldap.LDAPSortKey) ldskv.get(j);
+ lc = new netscape.ldap.controls.LDAPSortControl(sortkeys, criticality);
+
+ } catch (Exception e)
+ { e.printStackTrace(); }
+
+
+ } else if (type.equals( netscape.ldap.controls.LDAPVirtualListControl.VIRTUALLIST ) ) {
+ //lc = new netscape.ldap.controls.LDAPVirtualListControl(,);
+ int index = 0;
+ int before = 0;
+ int after = 0;
+ int content = 0;
+ java.util.Vector ldskv = new java.util.Vector();
+
+ org.w3c.dom.NodeList nl = n.getFirstChild().getNextSibling().getChildNodes();
+ for (int i=0; i< nl.getLength(); i++) {
+ if (nl.item(i).getNodeType() == Node.ELEMENT_NODE) {
+
+ if (nl.item(i).getLocalName().equals("index") ) {
+ try {
+ index = Integer.parseInt( nl.item(i).getFirstChild().getNodeValue() );
+ } catch (Exception e) {}
+
+ } else if (nl.item(i).getLocalName().equals("before") ) {
+ try {
+ before = Integer.parseInt( nl.item(i).getFirstChild().getNodeValue() );
+ } catch (Exception e) {}
+
+ } else if (nl.item(i).getLocalName().equals("after") ) {
+ try {
+ after = Integer.parseInt( nl.item(i).getFirstChild().getNodeValue() );
+ } catch (Exception e) {}
+ } else if (nl.item(i).getLocalName().equals("count") ) {
+ try {
+ content = Integer.parseInt( nl.item(i).getFirstChild().getNodeValue() );
+ } catch (Exception e) {}
+
+
+
+ }
+ }
+ }
+
+ logger.log(Level.FINE, "VLV: index: {0}", String.valueOf(index));
+ logger.log(Level.FINE, "VLV: before: {0}", String.valueOf(before));
+ logger.log(Level.FINE, "VLV: after: {0}", String.valueOf(after));
+ logger.log(Level.FINE, "VLV: content: {0}", String.valueOf(content));
+ lc = new netscape.ldap.controls.LDAPVirtualListControl( index, before, after, content );
+
+ } else {
+ if (criticality) {
+ // throw new gatewayException("unrecognized control oid");
+ } else {
+ // do nothing
+ }
+
+ }
+
+
+
+ return lc;
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ParseFilter.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ParseFilter.java
new file mode 100644
index 00000000..85b884df
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ParseFilter.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import org.w3c.dom.*;
+import java.util.logging.*;
+
+public class ParseFilter {
+
+ public static String parseFilterFromNode(org.w3c.dom.Node n) {
+ Logger logger = Logger.getLogger("com.netscape.dsml.gateway.FilterProcess");
+ StringBuffer sb = new java.lang.StringBuffer();
+ String output = new String();
+
+ if ( n != null && n.getNodeType() != Node.TEXT_NODE) {
+ String NodeName = n.getLocalName();
+
+ if ( NodeName.equals("present") ) {
+ logger.log(Level.ALL, "got filter: present");
+ sb.append(n.getAttributes().getNamedItem("name").getNodeValue());
+ sb.append("=*");
+
+ } else if ( NodeName.equals("and") ) {
+ logger.log(Level.FINE, "got filter: and");
+ Node it = n.getFirstChild();
+
+ sb.append('&');
+
+ while (it != null ) {
+ if (it.getNodeType() != Node.TEXT_NODE)
+ sb.append( parseFilterFromNode( it ) );
+ it = it.getNextSibling();
+ }
+
+ } else if ( NodeName.equals("or") ) {
+ logger.log(Level.FINE, "got filter: or");
+ Node it = n.getFirstChild();
+
+ sb.append('|');
+
+ while (it != null ) {
+ if (it.getNodeType() != Node.TEXT_NODE)
+ sb.append( parseFilterFromNode( it ) );
+ it = it.getNextSibling();
+ }
+
+ } else if ( NodeName.equals("not") ) {
+ logger.log(Level.FINE, "got filter: not");
+ Node it = n.getFirstChild();
+
+ sb.append('!');
+
+ if (it.getNodeType() == Node.TEXT_NODE)
+ it = it.getNextSibling();
+
+ sb.append( parseFilterFromNode(it) );
+
+ } else if ( NodeName.equals("greaterOrEqual") ) {
+ logger.log(Level.FINE, "got filter: greaterOrEqual");
+ sb.append(n.getAttributes().getNamedItem("name").getNodeValue());
+ sb.append(">=");
+
+ Node it = n.getFirstChild();
+ if (it.getNodeType() == Node.TEXT_NODE)
+ it = it.getNextSibling();
+
+ sb.append(it.getFirstChild().getNodeValue());
+
+ // if (n.getFirstChild().getNextSibling().getFirstChild().getNodeValue() != null)
+ // sb.append(it.getFirstChild().getNodeValue());
+ // else
+ // sb.append( n.getFirstChild().getFirstChild().getNodeValue());
+
+ } else if ( NodeName.equals("lessOrEqual") ) {
+ logger.log(Level.FINE, "got filter: lessOrEqual");
+ sb.append(n.getAttributes().getNamedItem("name").getNodeValue());
+ sb.append("<=");
+ Node it = n.getFirstChild();
+ if (it.getNodeType() == Node.TEXT_NODE)
+ it = it.getNextSibling();
+
+ sb.append(it.getFirstChild().getNodeValue());
+
+ } else if ( NodeName.equals("equalityMatch") ) {
+ logger.log(Level.FINE, "got filter: equalityMatch");
+ logger.log(Level.FINER," eq: " + n.getAttributes().getNamedItem("name").getNodeValue());
+ sb.append(n.getAttributes().getNamedItem("name").getNodeValue() );
+ logger.log(Level.FINER," eq: = ");
+ sb.append('=');
+ Node it = n.getFirstChild();
+ if (it.getNodeType() == Node.TEXT_NODE)
+ it = it.getNextSibling();
+
+ sb.append(it.getFirstChild().getNodeValue());
+
+
+ } else if ( NodeName.equals("approxMatch") ) {
+ logger.log(Level.FINE, "got filter: approxMatch");
+ sb.append(n.getAttributes().getNamedItem("name").getNodeValue() );
+ sb.append("~=");
+ Node it = n.getFirstChild();
+ if (it.getNodeType() == Node.TEXT_NODE)
+ it = it.getNextSibling();
+
+ sb.append(it.getFirstChild().getNodeValue());
+
+
+ } else if ( NodeName.equals("substrings") ) {
+ logger.log(Level.FINE, "got filter: substrings");
+
+ Node it = n.getFirstChild();
+
+ sb.append(n.getAttributes().getNamedItem("name").getNodeValue());
+ sb.append('=');
+
+ boolean noStar = false;
+
+
+ while (it != null) {
+
+ if (it.getNodeType() != Node.TEXT_NODE){
+ if (it.getLocalName().equals("any")){
+ if ( ! noStar )
+ sb.append('*');
+ noStar = true;
+ sb.append(it.getFirstChild().getNodeValue());
+ sb.append('*');
+ } else if (it.getLocalName().equals("initial")){
+ noStar = true;
+ sb.append(it.getFirstChild().getNodeValue());
+ sb.append('*');
+ } if (it.getLocalName().equals("final")){
+ if (! noStar)
+ sb.append('*');
+ sb.append(it.getFirstChild().getNodeValue());
+ }
+ }
+ it=it.getNextSibling();
+ }
+ } else return new String();
+
+
+ }
+ logger.log(Level.INFO, "returning: (" + sb.toString() + ")" );
+ return new StringBuffer().append('(').append(sb).append(')').toString();
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ProxyConnMgrFactory.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ProxyConnMgrFactory.java
new file mode 100644
index 00000000..278d5a8c
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ProxyConnMgrFactory.java
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+/**
+ * This provides a factory interface to the proxy connection manager. In the
+ * proxy mode, the user connections are bound to the directory server using a
+ * proxy user.
+ */
+
+public class ProxyConnMgrFactory implements IConnMgrFactoryFunctor {
+
+ public ProxyConnMgrFactory() {
+ }
+
+ /**
+ * @return An instance of the connection manager
+ *
+ * @exception DSMLConfigException if unable to initialize.
+ */
+ public synchronized IConnectionManager getInstance() {
+
+ if (_proxyConnMgr == null) {
+ _proxyConnMgr = ProxyConnectionManager.getInstance();
+ }
+ return _proxyConnMgr;
+ }
+ private ProxyConnectionManager _proxyConnMgr= null;
+
+
+
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ProxyConnectionManager.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ProxyConnectionManager.java
new file mode 100644
index 00000000..230ca108
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/ProxyConnectionManager.java
@@ -0,0 +1,260 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import java.lang.Exception ;
+import java.util.*;
+import java.util.logging.*;
+import netscape.ldap.LDAPConnection;
+import netscape.ldap.util.ConnectionPool;
+import netscape.ldap.LDAPConstraints;
+import netscape.ldap.LDAPSearchConstraints;
+import netscape.ldap.controls.LDAPProxiedAuthControl;
+import netscape.ldap.LDAPBind;
+import netscape.ldap.LDAPException;
+import java.io.IOException;
+
+/**
+ * ProxyConnectionManager is respossible for creating a pool of connections
+ * to the directory server. The pool is initialized with configured set of
+ * connections. Two pools are created; one for authentication and the other
+ * for operations. The pool parameters (max and min) can be configured.
+ *
+ */
+class ProxyConnectionManager implements IConnectionManager {
+ /*
+ * Default maximum backlog queue size
+ */
+ static final int MAX_BACKLOG = 100;
+ static final String LDAP_MAXBACKLOG = "maxbacklog";
+ static final String LDAP_REFERRAL = "referral";
+
+
+ private static Logger logger =
+ Logger.getLogger("com.netscape.dsml.service.ProxyConnectionManager");
+ static private ConnectionPool _ldapPool = null;
+ static private ConnectionPool _ldapLoginPool = null;
+ static private LDAPConnection _trialConn = null;
+ static private LDAPSearchConstraints _defaultSearchConstraints = null;
+ static private ProxyConnectionManager m_instance = null;
+
+ private String m_host = null;
+ private int m_port = 0;
+ private String m_user = "";
+ private String m_password = "";
+
+ /**
+ * Initialize by reading the informaton from the config manager.
+ *
+ * throws DSMLConfigException if unable to get the config
+ * information.
+ */
+ private ProxyConnectionManager() {
+ init();
+ }
+
+
+ private void init() {
+ // Get an instance of the config manager
+ Configuration config = Configuration.getInstance();
+
+ m_host = config.getServerHost();
+ m_port = config.getServerPort();
+ m_user = config.getBindDN();
+ m_password = config.getBindPW();
+
+ logger.log(Level.INFO, "m_host: {0}", m_host);
+ logger.log(Level.INFO, "m_port: {0}", String.valueOf(m_port) );
+ logger.log(Level.INFO, "m_user: {0}", m_user);
+ logger.log(Level.INFO, "m_password: {0}", m_password);
+
+ logger.log(Level.FINER, "Initializing the ldap pool");
+ initLdapPool( config.getMinPool(), config.getMaxPool());
+
+ logger.log(Level.FINER, "Initializing the ldap LOGIN pool");
+ initLoginPool(config.getMinLoginPool(), config.getMaxLoginPool());
+
+ logger.log(Level.FINER, "Pool initialization done");
+ }
+
+
+ /**
+ * create the singelton LDAPLayer object if it doesn't exist already.
+ *
+ * @exception DSMLConfigException if unable initialize configurations.
+ */
+ public static synchronized ProxyConnectionManager getInstance( ) {
+ if (m_instance == null) {
+ m_instance = new ProxyConnectionManager();
+ }
+ return m_instance;
+ }
+
+ /**
+ * Get a connection to authenticate.
+ *
+ * @return a ldap connection handle
+ *
+ */
+ public LDAPConnection getLoginConnection() {
+ if (_ldapLoginPool == null ) {
+ return null;
+ }
+ return _ldapLoginPool.getConnection();
+ }
+
+ /**
+ * Returns the connection (used for authentication) to the pool.
+ *
+ */
+ public void releaseLoginConnection(String _loginCtx, LDAPConnection conn ) {
+ // Release the connection
+ _ldapLoginPool.close( conn );
+ }
+
+ public void releaseLoginConnection(LDAPConnection conn ) {
+ // Release the connection
+ _ldapLoginPool.close( conn );
+ }
+
+ /**
+ * Get connection from pool. This connection is used for
+ * all operations except authentication.
+ *
+ * @param the loginctx (or the authenticated token)
+ * @return connection that is available to use or null otherwise
+ */
+ public LDAPConnection getConnection(String loginCtx) {
+
+ // XXX this behaves poorly if the server goes down.
+ if (_ldapPool == null ) {
+ return null;
+ }
+
+ LDAPConnection conn ;
+
+ conn= _ldapPool.getConnection();
+
+ return conn;
+ }
+
+
+ public LDAPConnection getConnection() {
+ return getConnection("");
+ }
+
+ /**
+ * Just call the pool method to release the connection so that the
+ * given connection is free for others to use
+ *
+ * @param the login ctx used.
+ * @param conn connection in the pool to be released for others to use
+ */
+ public void releaseConnection( String loginCtx, LDAPConnection conn ) {
+ // Since we return the connecton to the pool and use a
+ //proxy mode, loginCtx is not used.
+ // XXX should change function signature
+
+ if (_ldapPool == null || conn == null) return;
+
+ // XXX reset the original constraints after before connection is released
+ // conn.setSearchConstraints(_defaultSearchConstraints);
+
+ // A soft close on the connection.
+ // Returns the connection to the pool and make it available.
+ _ldapPool.close( conn );
+ }
+
+
+ public void releaseConnection( LDAPConnection conn ) {
+ if (_ldapPool == null || conn == null)
+ return;
+
+ // reset the original constraints
+ conn.setSearchConstraints(_defaultSearchConstraints);
+
+ // A soft close on the connection.
+ // Returns the connection to the pool and make it available.
+ _ldapPool.close( conn );
+ }
+
+
+ /**
+ * Initialize the pool shared by all. It is expected that the
+ * host and port (and all configuration) information has been
+ * initialized.
+ */
+ private synchronized void initLdapPool(int poolMin, int poolMax) {
+ // Don't do anything if pool is already initialized
+ if (_ldapPool != null) {
+ logger.log(Level.FINER, "The pool is already initialized");
+ return;
+ }
+ int maxBackLog = 10;
+ boolean referrals = false;
+
+ try {
+ logger.log(Level.FINER, "Host={0}", m_host);
+ logger.log(Level.FINER, "Port={0}", String.valueOf(m_port) );
+ logger.log(Level.FINER, "DN={0}", m_user);
+ logger.log(Level.FINE, "password={0}", m_password);
+
+ _ldapPool = new ConnectionPool(poolMin, poolMax, m_host, m_port, m_user, m_password);
+
+ logger.log(Level.FINER, "Pool initialized");
+
+ } catch (LDAPException lde) {
+ _ldapPool = null;
+ logger.log(Level.SEVERE, "Pool not initialized\nError Code: " +
+ lde.getLDAPResultCode() + "\n" + lde.getMessage() );
+
+ } catch (Exception ex) {
+ //logger.log(Level.SEVERE, "Pool init failed:{0}", ex.getMessage());
+ //XXX throw new Exception("couldn't connect to ldap server");
+
+ }
+ }
+
+ /*
+ * Initialize the login pool. This pool of connections is used
+ * for authentication.
+ */
+ private synchronized void initLoginPool(int poolMin, int poolMax) {
+ if ( _ldapLoginPool != null)
+ return;
+
+ LDAPConnection conn = new LDAPConnection();
+ logger.log(Level.FINER, "Creating the LOGIN Pool");
+ try {
+ conn.connect(3, m_host, m_port, m_user, m_password);
+ _ldapLoginPool = new ConnectionPool(poolMin, poolMax, m_host, m_port, m_user, m_password);
+
+ } catch (LDAPException lde) {
+ _ldapLoginPool = null;
+ logger.log(Level.SEVERE, "Pool not initialized\nError Code: " +
+ lde.getLDAPResultCode() + "\n" +
+ lde.getMessage() );
+
+ } catch (Exception ex) {
+ // logger.log(Level.SEVERE, "Pool init failed:{0}", ex.getMessage());
+ //XXX throw new Exception("couldn't connect to ldap server");
+ _ldapLoginPool = null;
+ }
+ }
+
+ public void shutdown() {
+ try {
+ _ldapPool.destroy();
+ } catch (java.lang.NullPointerException e ) {}
+ try {
+ _ldapLoginPool.destroy();
+ } catch (java.lang.NullPointerException e) {}
+ }
+
+
+} \ No newline at end of file
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayContext.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayContext.java
new file mode 100644
index 00000000..d737e8bb
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayContext.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import netscape.ldap.*;
+import org.w3c.dom.*;
+
+
+/**
+ *
+ * @author elliot
+ */
+public class gatewayContext {
+
+
+ /**
+ * Holds value of property ldapConnection.
+ */
+ private LDAPConnection ldapConnection;
+
+ /**
+ * Holds value of property constraints.
+ */
+ private netscape.ldap.LDAPSearchConstraints constraints;
+
+ /**
+ * Holds value of property rootNode.
+ */
+ private org.w3c.dom.Node rootNode;
+
+ /**
+ * Getter for property ldapConnection.
+ * @return Value of property ldapConnection.
+ */
+ public LDAPConnection getLdapConnection() {
+ return this.ldapConnection;
+ }
+
+ /**
+ * Setter for property ldapConnection.
+ * @param ldapConnection New value of property ldapConnection.
+ */
+ public void setLdapConnection(LDAPConnection ldapConnection) {
+ this.ldapConnection = ldapConnection;
+ }
+
+ /**
+ * Getter for property constraints.
+ * @return Value of property constraints.
+ */
+ public netscape.ldap.LDAPSearchConstraints getConstraints() {
+ return this.constraints;
+ }
+
+ /**
+ * Setter for property constraints.
+ * @param constraints New value of property constraints.
+ */
+ public void setConstraints(netscape.ldap.LDAPSearchConstraints constraints) {
+ this.constraints = constraints;
+ }
+
+ /**
+ * Getter for property rootNode.
+ * @return Value of property rootNode.
+ */
+ public org.w3c.dom.Node getRootNode() {
+ return this.rootNode;
+ }
+
+ /**
+ * Setter for property rootNode.
+ * @param rootNode New value of property rootNode.
+ */
+ public void setRootNode(org.w3c.dom.Node rootNode) {
+ this.rootNode = rootNode;
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayException.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayException.java
new file mode 100644
index 00000000..8bb5fb76
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayException.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+
+package com.netscape.dsml.gateway;
+
+public class gatewayException extends Exception {
+
+ /** Creates a new instance of gatewayException */
+ public gatewayException(String message) {
+ super(message);
+ }
+
+ public gatewayException() {
+ super("LDAP Server Unavailable");
+ }
+
+ public Throwable getCause() {
+ Throwable retValue;
+
+ retValue = super.getCause();
+ return retValue;
+ }
+
+ public String getMessage() {
+ String retValue;
+
+ retValue = super.getMessage();
+ return retValue;
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayHandler.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayHandler.java
new file mode 100644
index 00000000..6598dda3
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayHandler.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+
+package com.netscape.dsml.gateway;
+
+import java.io.*;
+import java.util.Iterator;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.*;
+import javax.xml.rpc.handler.Handler;
+import javax.xml.rpc.handler.HandlerInfo;
+import javax.xml.rpc.handler.MessageContext;
+import javax.xml.rpc.handler.soap.SOAPMessageContext;
+import javax.xml.soap.Name;
+import javax.xml.soap.SOAPEnvelope;
+import javax.xml.soap.SOAPHeader;
+import javax.xml.soap.SOAPHeaderElement;
+import javax.xml.soap.SOAPMessage;
+import javax.xml.soap.SOAPPart;
+import javax.xml.soap.SOAPConstants;
+import javax.xml.transform.*;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+import org.w3c.dom.Document;
+import org.xml.sax.*;
+import org.w3c.dom.*;
+import javax.xml.soap.*;
+
+public class gatewayHandler implements Handler {
+ private HandlerInfo handlerInfo;
+ static private javax.xml.soap.MessageFactory messageFactory ;
+ static private javax.xml.soap.SOAPFactory sef ;
+ private static boolean ready = false;
+
+ public gatewayHandler() {
+ super();
+
+ try {
+ messageFactory = javax.xml.soap.MessageFactory.newInstance();
+ sef = javax.xml.soap.SOAPFactory.newInstance();
+ } catch (Exception e) { }
+ }
+
+
+
+
+ public boolean handleRequest(MessageContext context) {
+ /*
+ * this section will set user, pwd, if it came via a http authentication header
+ *
+ */
+ Configuration config = Configuration.getInstance();
+ String tmp = (String)context.getProperty("Authorization");
+
+ String user=null ;
+ String pwd =null;
+ if ( tmp != null )
+ tmp = tmp.trim();
+ if ( tmp != null && tmp.startsWith("Basic ") ) {
+
+ int i ;
+ sun.misc.BASE64Decoder bd = new sun.misc.BASE64Decoder();
+ try {
+ tmp = new String( (bd.decodeBuffer(tmp.substring(6) )));
+ }
+ catch (Exception e) {
+ // couldn't decode auth info
+ }
+
+ i = tmp.indexOf( ':' );
+ if ( i == -1 )
+ user = new String(tmp) ;
+ else
+ user = new String(tmp.substring( 0, i));
+
+ if ( i != -1 ) {
+ pwd= new String(tmp.substring(i+1));
+ if ( pwd != null && pwd.equals("") ) pwd = null ;
+
+ }
+ }
+
+ SOAPMessage out_m = null;
+ SOAPEnvelope out_env = null;
+ javax.xml.soap.SOAPBody out_body = null;
+ javax.xml.soap.SOAPElement out_fResponse = null;
+
+ try {
+ javax.xml.soap.SOAPPart sp = ((SOAPMessageContext) context).getMessage().getSOAPPart();
+ javax.xml.soap.SOAPEnvelope se = sp.getEnvelope();
+ javax.xml.soap.SOAPBody sb = se.getBody();
+
+ out_m = messageFactory.createMessage();
+ out_env = out_m.getSOAPPart().getEnvelope();
+ out_body = out_env.getBody();
+ out_fResponse = out_body.addBodyElement(out_env.createName("batchResponse"));
+ out_fResponse.addAttribute(out_env.createName("xmlns"), "urn:oasis:names:tc:DSML:2:0:core");
+
+ int authorizationCode = new com.netscape.dsml.gateway.LDAPAuthenticator(user, pwd).authenticate();
+
+ if (config.getUseAuth() && authorizationCode >0 ) {
+ out_fResponse.addChildElement("errorResponse").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), String.valueOf(authorizationCode) );
+ }
+ else {
+ BatchProcessor batchProcessor = new BatchProcessor(sb);
+ batchProcessor.init();
+
+ if (config.getUseAuth())
+ batchProcessor.setProxy(user);
+ else
+ batchProcessor.setProxy("");
+
+ if (batchProcessor.preprocess()) {
+ int i = -1;
+ int NumberRequests = batchProcessor.getRequestCount();
+
+ while (++i < NumberRequests && ! batchProcessor.Error()) {
+ batchProcessor.process(i);
+ SOAPElement RequestedItem = batchProcessor.getRequestItem(i);
+ if ( RequestedItem != null )
+ out_fResponse.addChildElement( RequestedItem );
+ }
+ }
+
+ if ( out_fResponse.getChildElements().hasNext() == false) {
+ try {
+ /* This is slightly inaccurate. This simply checks to see if the batch is empty, and if it is, return
+ * something. the error isn't always 91, but hopefully it's slightly more descriptive to the end user */
+ out_fResponse.addChildElement("errorResponse").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), "91" );
+ }
+ catch (javax.xml.soap.SOAPException soapException) { } /* Not important to catch this */
+ }
+ }
+ }
+ catch (gatewayException gwe) {
+ try {
+ out_fResponse.addChildElement("errorResponse").addAttribute(messageFactory.createMessage().getSOAPPart().getEnvelope().createName("code"), "81" );
+ }
+ catch (javax.xml.soap.SOAPException soapException) {
+ /* We did our best to try and exit gracefully. Give up. */
+ }
+ }
+
+ catch (javax.xml.soap.SOAPException soapException) {
+ }
+ catch (Exception e) {
+ e.printStackTrace();
+
+ }
+
+ /* To return false means do not try and continue onto the
+ * deployed service. Since we context.setProperty our
+ * SOAPResponse message, it will be sent as soon as the request
+ * turns the other way into a reponse.
+ */
+ context.setProperty("RESPONSE", out_m);
+ return false;
+
+ }
+
+ /**
+ * @see javax.xml.rpc.handler.Handler#handleResponse(MessageContext)
+ */
+ public boolean handleResponse(MessageContext context) {
+ SOAPMessage m;
+ m = (SOAPMessage) context.getProperty("RESPONSE");
+
+ try {
+ ((SOAPMessageContext)context).setMessage(m);
+ }
+ catch (Exception e) {
+ }
+
+ return true;
+ }
+
+ public boolean handleFault(MessageContext context) {
+ return false;
+ }
+
+ public void init(HandlerInfo config) {
+ handlerInfo = config;
+ }
+
+ public QName[] getHeaders() {
+ return handlerInfo.getHeaders();
+ }
+
+ public void destroy() {
+
+ /* Bad things happen if the pool isn't shutdown before the servlet goes away */
+ IConnectionManager ldap_pool = null;
+ ProxyConnMgrFactory pmc = new ProxyConnMgrFactory();
+ try {
+ ldap_pool = pmc.getInstance();
+ ldap_pool.shutdown();
+ }
+ catch (Exception e) { }
+
+
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayService.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayService.java
new file mode 100644
index 00000000..4dba8fd0
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/gateway/gatewayService.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ *
+ *
+ *
+ */
+package com.netscape.dsml.gateway;
+
+import javax.activation.DataHandler;
+
+
+/**
+ * This is the dummy endpoint for axis. It doesn't actually do anything. The
+ * "real" meat is in gatewayHandler.
+ * @author elliot@bozemanpass.com
+ */
+public class gatewayService {
+
+
+ public gatewayService() {
+ }
+
+ /**
+ *
+ * @param inputData
+ * @return
+ */
+ public javax.activation.DataHandler process( javax.activation.DataHandler inputData) {
+ return inputData;
+ }
+
+ /**
+ *
+ * @param inputData the javax.activation.DataHandler "attachment" of the incoming xml data
+ * from the SOAP client.
+ * @return the javax.activation.DataHandler "attachment" of the outgoing xml data
+ * (responses) to the SOAP client.
+ */
+ public javax.activation.DataHandler batchRequest(javax.activation.DataHandler inputData) {
+ return inputData;
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/test/SOAPClient.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/test/SOAPClient.java
new file mode 100644
index 00000000..9b891469
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/test/SOAPClient.java
@@ -0,0 +1,74 @@
+/*
+ * SOAPClient.java
+ *
+ * Created on June 24, 2004, 3:00 PM
+ */
+
+
+
+package com.netscape.dsml.test;
+
+
+import java.util.Properties;
+import java.io.*;
+import java.net.*;
+import java.io.FileInputStream;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.soap.*;
+/**
+ *
+ * @author elliot
+ */
+public class SOAPClient {
+
+ private String in = null;
+ private String out = null;
+ private String SOAPUrl = null;
+
+ public SOAPClient() { }
+
+ public void setIn(String in) {
+ this.in = in;
+ }
+
+ public void setOut(String out) {
+ this.out = out;
+ }
+
+ public void setSOAPUrl(String SOAPUrl) {
+ this.SOAPUrl = SOAPUrl;
+ }
+
+ public void go() throws Exception {
+
+ String SOAPAction = "";
+
+ URL url = new URL(SOAPUrl);
+ URLConnection connection = url.openConnection();
+ HttpURLConnection httpConn = (HttpURLConnection) connection;
+
+ FileInputStream fin = new FileInputStream(in);
+ FileOutputStream fout = new FileOutputStream(out);
+
+ SOAPMessage message = javax.xml.soap.MessageFactory.newInstance().createMessage();
+
+ SOAPPart soapPart = message.getSOAPPart();
+
+ StreamSource preppedMsgSrc = new StreamSource(new FileInputStream(in));
+
+ soapPart.setContent(preppedMsgSrc);
+ message.saveChanges();
+
+ SOAPConnection con = SOAPConnectionFactory.newInstance().createConnection();
+
+ SOAPMessage response = con.call(message, url);
+
+ response.writeTo(fout);
+
+ fout.close();
+ fin.close();
+ con.close();
+
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/test/dsmlClient.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/test/dsmlClient.java
new file mode 100644
index 00000000..98fd255a
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/test/dsmlClient.java
@@ -0,0 +1,90 @@
+package com.netscape.dsml.test;
+
+import javax.xml.parsers.*;
+import org.w3c.dom.*;
+import org.w3c.dom.traversal.*;
+import org.xml.sax.SAXException;
+import java.io.IOException;
+import java.io.File;
+
+public class dsmlClient {
+
+
+ public dsmlClient() {
+ }
+
+
+ public static void main(String[] args) {
+ File f = null;
+
+ if (args.length==2) {
+ try {
+
+ SOAPClient mySoapClient = new SOAPClient();
+ f = File.createTempFile("TET-DSML",null);
+ f.deleteOnExit();
+ mySoapClient.setIn( args[1] );
+ mySoapClient.setOut( f.getPath() );
+
+ mySoapClient.setSOAPUrl( args[0] );
+ // mySoapClient.setSOAPUrl("http://desktop3:8180/axis/services/dsmlgw");
+
+ mySoapClient.go(); }
+ catch (Exception e) {
+ e.printStackTrace();
+ System.exit( 254 ); // no response or other error like it's not a dsml file
+
+ }
+
+
+
+ try {
+ java.io.BufferedReader in = new java.io.BufferedReader(new java.io.FileReader(f));
+ String str;
+ while ((str = in.readLine()) != null) {
+ System.out.println(str);
+ }
+ in.close();
+ } catch (IOException e) {
+ }
+
+ try {
+ javax.xml.parsers.DocumentBuilder db= javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ org.w3c.dom.Document doc = db.parse( f );
+
+ // Create the NodeIterator
+ DocumentTraversal traversable = (DocumentTraversal) doc;
+ NodeIterator iterator = traversable.createNodeIterator(doc, NodeFilter.SHOW_ALL , null, true);
+
+ // Iterate over the comments
+ Node node;
+ while ((node = iterator.nextNode()) != null) {
+ if (node.getNodeName().equals("resultCode")) {
+ int result = Integer.parseInt(node.getAttributes().getNamedItem("code").getNodeValue());
+ System.exit(result);
+ }
+ }
+
+ }
+ catch (javax.xml.parsers.ParserConfigurationException pce ) {
+ pce.printStackTrace();
+ System.exit( 254 ); }
+ catch (org.xml.sax.SAXException saxe) {
+ saxe.printStackTrace();
+ System.exit( 254 ); } // ?
+ catch (java.io.IOException ioe) {
+ ioe.printStackTrace();
+ System.exit( 254 ); } // bad url
+ catch (Exception e) {
+ e.printStackTrace();
+ System.exit( 254 ); } // bad url
+
+ }
+ else {
+ System.err.println("wrong number of arguments");
+ System.err.println("usage: dsmlClient soap-url dsml-file");
+ System.exit(255); // wrong arguments
+ }
+ }
+
+}
diff --git a/ldap/clients/dsmlgw/src/com/netscape/dsml/test/dsmlSearch.java b/ldap/clients/dsmlgw/src/com/netscape/dsml/test/dsmlSearch.java
new file mode 100644
index 00000000..bd0d8f8a
--- /dev/null
+++ b/ldap/clients/dsmlgw/src/com/netscape/dsml/test/dsmlSearch.java
@@ -0,0 +1,55 @@
+package com.netscape.dsml.test;
+
+import javax.xml.parsers.*;
+import org.w3c.dom.*;
+import org.w3c.dom.traversal.*;
+import org.xml.sax.SAXException;
+import java.io.IOException;
+import java.io.File;
+import java.io.BufferedReader;
+import java.io.FileReader;
+
+public class dsmlSearch {
+
+ public static void main(String[] args) {
+ File f = null;
+
+ if (args.length==2) {
+ try {
+
+ SOAPClient mySoapClient = new SOAPClient();
+ f = File.createTempFile("TET-DSML",null);
+ f.deleteOnExit();
+ mySoapClient.setIn( args[1] );
+ mySoapClient.setOut( f.getPath() );
+
+ mySoapClient.setSOAPUrl( args[0] );
+
+ mySoapClient.go(); }
+ catch (Exception e) {
+ e.printStackTrace();
+ System.exit( 254 ); // no response or other error like it's not a dsml file
+
+ }
+
+ try {
+ BufferedReader in = new BufferedReader(new FileReader( f.getPath() ));
+ String str;
+ while (( str = in.readLine()) != null) {
+
+ System.out.println(str); }
+ in.close(); }
+ catch (IOException e) {
+ e.printStackTrace();
+ System.exit( 254 );
+ }
+
+ }
+ else {
+ System.err.println("wrong number of arguments");
+ System.err.println("usage: dsmlSearch soap-url dsml-file");
+ System.exit(255); // wrong arguments
+ }
+ }
+
+}
diff --git a/ldap/clients/orgchart/aim-online.gif b/ldap/clients/orgchart/aim-online.gif
new file mode 100644
index 00000000..b364017e
--- /dev/null
+++ b/ldap/clients/orgchart/aim-online.gif
Binary files differ
diff --git a/ldap/clients/orgchart/arrow.gif b/ldap/clients/orgchart/arrow.gif
new file mode 100644
index 00000000..94eff507
--- /dev/null
+++ b/ldap/clients/orgchart/arrow.gif
Binary files differ
diff --git a/ldap/clients/orgchart/botframe.html b/ldap/clients/orgchart/botframe.html
new file mode 100644
index 00000000..2af83848
--- /dev/null
+++ b/ldap/clients/orgchart/botframe.html
@@ -0,0 +1,26 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
+<html>
+<head>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
+ <title>Netscape Directory Server Org Chart</title>
+ <LINK REL=stylesheet TYPE="text/css" HREF="styles.css">
+</head>
+<body bgcolor="#FFFFFF">
+<table cellspacing="-1" cellpadding="2" border="0" width="100%">
+<tr>
+<td align="left" class="pageHeader">Welcome!<br><br></td>
+</tr>
+<tr>
+<td align="left" class="startPage">
+To find a person in your corporate organization chart, enter their<br>
+name in the search box above, then click "Go"<br><br>
+Below is a sample of an organization chart, with a description of the<br>
+types of actions you can take<BR><BR>
+Thank you for using Netscape Directory Server Org Chart!
+</td>
+</tr>
+</table>
+<br><br>
+<tr align="center"><img src="starthelp.gif" border="0" alt=""></tr>
+</body>
+</html>
diff --git a/ldap/clients/orgchart/branch-cc1.gif b/ldap/clients/orgchart/branch-cc1.gif
new file mode 100644
index 00000000..80aec59b
--- /dev/null
+++ b/ldap/clients/orgchart/branch-cc1.gif
Binary files differ
diff --git a/ldap/clients/orgchart/config.tmpl b/ldap/clients/orgchart/config.tmpl
new file mode 100644
index 00000000..6ebf6890
--- /dev/null
+++ b/ldap/clients/orgchart/config.tmpl
@@ -0,0 +1,185 @@
+#ldap-host localhost
+#ldap-port 389
+#ldap-search-base dc=example,dc=com
+
+#
+# A name that has no value after it equates to "" for the value,
+# like the two below settings.
+#
+# Not listing an entire name/value pair at all in this file
+# sets its value to "" as well.
+#
+# So the below two names therefore don't even need to be in this file
+# (but are here to show them as possible options that can be changed).
+#
+# Having no value below for "ldap-bind-dn" and "ldap-bind-pass"
+# indicates that you want anonymous binding to the LDAP server.
+#
+
+ldap-bind-dn
+ldap-bind-pass
+
+#
+# Allowed values for below icon-related setting:
+#
+# forefront means show this icon next to the person's name
+# layer means show this icon inside the person's floating layer
+# no means never show this icon anywhere, but MyOrgChart settings can override this setting.
+# disabled means never show this icon. Period. So MyOrgChart will not even show this icon as a setting.
+#
+
+icons-aim-visible no
+icons-email-visible layer
+icons-phonebook-visible forefront
+icons-locator-visible disabled
+
+#
+# There is also the same concept below for a person-locator
+# type application, to show graphically where a given employee's office is located.
+# You also specify the partial URL, up until where the user's URL-
+# encoded cn value will be concatenated.
+#
+# url-locator-base http://hostname.domain.com/submit.cgi?empfullname=
+#
+
+url-locator-base http://maps.example.com/submit2.cgi?r_loc=
+
+
+
+#
+# This is where you specify which specific LDAP attributes
+# from your LDAP server that you would like used for both org chart
+# generation as well as final display values.
+#
+# The value of the attribute specified for "attrib-job-title" will
+# be listed below anybody's name that is listed in their own box.
+# If you don't specify this setting in this file, the default used
+# will be "title".
+#
+# For "attrib-farleft-rdn", this specifies which attribute you are
+# using as the leftmost RDN for the DN's of your user entries.
+#
+
+attrib-job-title title
+attrib-manager manager
+attrib-farleft-rdn uid
+
+#
+# This is where you specify the maximum levels that are allowed
+# to be generated for any given org chart, and the MyOrgChart version
+# of this setting will never be allowed to be higher than the below.
+#
+# A "level" is defined as a reporting level, meaning that if you
+# generate an org chart for a given director, all direct reports to him
+# (whether they have people below them or not) are level 1, people below
+# any of them are level 2, etc.
+#
+# So a setting of 1 would list the full name of the user entered, and
+# then just people that directly report to that person only.
+#
+# The purpose of having this configuration setting is to give you
+# control over users that may try to generate an org chart on the
+# CEO of a company, and heavily tax the LDAP server to generate
+# an org chart that may be thousands of people deep.
+#
+# If this setting is not listed below, the default is 3.
+#
+# The valid range of values for this setting would be a minimum of 1,
+# with no hard-coded maximum.
+#
+
+max-levels-drawn 3
+
+#
+# The below setting relates to whether a specific assumption should be made
+# on all values that you currently have stored for your manager LDAP attribute.
+#
+# The assumption: That all user entries are stored in LDAP on the
+# same flat level location, at least for a given
+# group of people that org charts will be generated for.
+#
+# So when you enter:
+#
+# Steve Jones
+#
+# to generate an org chart on, which let's say equates to this DN:
+#
+# uid=sjones, ou=People, dc=acme, dc=com
+#
+# then should this application assume that the manager attrib value
+# of this entry is in this same location as Steve Jones:
+#
+# manager = "uid=XXXXXX, ou=People, dc=acme, dc=com"
+#
+# or is it possible that the manager's LDAP entry is at another level?
+#
+#
+# The below two options for this setting specifies one of two scenarios,
+# based on how you have configured your directory information tree:
+#
+#
+# Either the value:
+#
+# same This means assume the same location (such as
+# "ou=People, dc=acme, dc=com" above) that the inital
+# user entry is found at for all subsequent entries
+# involved in drawing that given org chart.
+#
+# In other words, this setting assumes a totally
+# flat namespace, at least for all users that will
+# be in a given generated org chart.
+#
+# search This means there is no guarantee that other entries
+# that need to be discovered to draw the org chart
+# are in the same area of the directory tree, so when
+# searching the manager attribute DN values for a given
+# exact uid, search like this instead:
+#
+# manager = "uid=sjones,*"
+#
+# This will be much more expensive of a search, so
+# if you fit this scenario, at least make sure on your LDAP
+# server that you have the substring index created for your
+# manager attribute, to make drawing the org chart as fast
+# as possible.
+#
+# Default value (if this setting is not listed in this file): same
+#
+
+
+manager-DN-location same
+
+
+#
+# This setting helps you configure against users entering LDAP
+# queries for "A" or "MI" and then taxing the LDAP server by asking
+# for thousands of search results back.
+#
+# The value you specify below for "min-chars-searchstring" means
+# that the user must enter AT LEAST this many characters for
+# their request to even make it to the LDAP server. If they type
+# less characters than this setting, they will get a message that
+# they need to enter at least X characters to search, where X will
+# be the below value.
+#
+# NOTE: This setting purposely does not apply to allowing a user
+# to search for an exact UID (to avoid search results). The logic
+# is that:
+#
+# [1] Search LDAP for an equality search of (uid=XXXX), regardless
+# of both this below setting / how many characters were entered.
+#
+# [2] If this single LDAP entry was not found, then make sure the
+# number of characters entered for the search are at least the below
+# number of characters, before sending a broader search to LDAP.
+#
+# If this setting is not configured below (the line is absent),
+# the default value used is 4.
+
+min-chars-searchstring 4
+
+# Allowed characters in search filters. If the user enters a search that
+# contains a character not in the allowed-filter-chars list, the user
+# will be notified the search needs to be modified.
+
+allowed-filter-chars abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 _-
diff --git a/ldap/clients/orgchart/index.html b/ldap/clients/orgchart/index.html
new file mode 100644
index 00000000..7e0e573f
--- /dev/null
+++ b/ldap/clients/orgchart/index.html
@@ -0,0 +1,33 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
+<META HTTP-EQUIV="Expires" CONTENT="Thu, 01 Feb 1996 00:00:00 GMT">
+ <TITLE>Netscape Directory Server Org Chart</TITLE>
+
+
+<SCRIPT LANGUAGE="javascript">
+
+
+ var agt = navigator.userAgent.toLowerCase();
+ var is_major = parseInt(navigator.appVersion);
+ var is_nav = ((agt.indexOf('mozilla')!=-1) && (agt.indexOf('spoofer')==-1)
+ && (agt.indexOf('compatible') == -1) && (agt.indexOf('opera')==-1)
+ && (agt.indexOf('webtv')==-1));
+
+ if (!is_nav || (is_major < 5))
+ {
+ //document.write('<BASE HREF="http://localhost/cvsorg/">');
+ }
+
+</SCRIPT>
+</HEAD>
+
+
+<frameset frameborder=no border=0 framespacing="0" ROWS="50,*">
+ <frame name="input_window" src="topframe.html" SCROLLING=NO noresize marginwidth="5" marginheight="5">
+ <frame name="output_window" src="botframe.html" marginwidth="10" marginheight="10">
+
+</frameset>
+
+
+</HTML>
diff --git a/ldap/clients/orgchart/ldap-person.gif b/ldap/clients/orgchart/ldap-person.gif
new file mode 100644
index 00000000..f3b86d11
--- /dev/null
+++ b/ldap/clients/orgchart/ldap-person.gif
Binary files differ
diff --git a/ldap/clients/orgchart/mag.gif b/ldap/clients/orgchart/mag.gif
new file mode 100644
index 00000000..03b4a27f
--- /dev/null
+++ b/ldap/clients/orgchart/mag.gif
Binary files differ
diff --git a/ldap/clients/orgchart/mail.gif b/ldap/clients/orgchart/mail.gif
new file mode 100644
index 00000000..7747a009
--- /dev/null
+++ b/ldap/clients/orgchart/mail.gif
Binary files differ
diff --git a/ldap/clients/orgchart/myorg.bat b/ldap/clients/orgchart/myorg.bat
new file mode 100644
index 00000000..88f10c11
--- /dev/null
+++ b/ldap/clients/orgchart/myorg.bat
@@ -0,0 +1,2 @@
+@set path=..\..\..\bin\slapd\admin\bin;%path%
+@perl myorg.pl
diff --git a/ldap/clients/orgchart/myorg.pl b/ldap/clients/orgchart/myorg.pl
new file mode 100755
index 00000000..0e61b819
--- /dev/null
+++ b/ldap/clients/orgchart/myorg.pl
@@ -0,0 +1,632 @@
+#!../../../bin/slapd/admin/bin/perl
+#
+#set ts=4
+
+$|=1;
+print "Content-type: text/html;charset=UTF-8\n\n";
+#print "Content-type: text/html\n\n";
+
+#
+# Read config.txt settings for MyOrgChart-specific items
+#
+&read_config_file();
+
+#-------------------------------------
+print "
+<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">
+<html>
+<head>
+<title>Customize: Netscape Directory Server Org Chart</title>
+<LINK REL=stylesheet TYPE=\"text/css\" HREF=\"../html/styles.css\">
+";
+#-------------------------------------
+
+&print_javascript();
+
+print "</head>";
+
+&print_body();
+
+print "</html>";
+
+exit(0);
+
+
+#==============================================================================
+
+sub read_config_file()
+{
+
+ if (!open (FILE, "../config.txt") )
+ {
+ print "\n\n<BR><BR>Can't open configuration file: config.txt\n\n<BR><BR>Error from OS: $!\n\n";
+ exit;
+ }
+
+ #
+ # let's set some default values, so in case a setting
+ # does not exist both in the config.txt file, as well
+ # as does not exist via a user's MyOrgChart cookie,
+ # we at least have some type of valid value present.
+ #
+ %config_tokens = (
+ "icons-aim-visible","disabled",
+ "icons-email-visible","disabled",
+ "icons-phonebook-visible","disabled",
+ "icons-locator-visible","disabled",
+ "max-levels-drawn", "3",
+ );
+
+ #
+ # read in the config.txt file
+ #
+ while(<FILE>)
+ {
+ chop;
+
+ foreach $f (keys %config_tokens)
+ {
+ $config_tokens{$f} = $1 if ($_ =~ /^$f[ \t]+(.+)/);
+ }
+ }
+ close (FILE);
+
+ #
+ # check the "max-levels-drawn" setting for numeric, and to
+ # make sure it is a number greater than zero.
+ #
+ # If a bad setting, let's set it to 3 so that at least it
+ # is set to a valid number, but then a user's MyOrgChart
+ # preferences can override it (if their setting is 1, 2,
+ # or 3 only).
+ #
+
+ # check for non-numeric first
+
+ $temp = $config_tokens{"max-levels-drawn"};
+ $temp =~ s/[\d]//g;
+
+ if ( length($temp) != 0 )
+ {
+ # a non-numeric setting
+ $config_tokens{"max-levels-drawn"} = 3;
+ }
+ else
+ {
+ # a numeric setting, but: check for less than value of 1
+ if ( $config_tokens{"max-levels-drawn"} < 1 )
+ {
+ $config_tokens{"max-levels-drawn"} = 3;
+ }
+ }
+
+
+ #
+ # if every icon has been disabled, set a state so that later on
+ # we don't draw the header and the footer text for the icons.
+ #
+ if ( ($config_tokens{"icons-email-visible"} eq "disabled") && ($config_tokens{"icons-phonebook-visible"} eq "disabled") && ($config_tokens{"icons-aim-visible"} eq "disabled") && ($config_tokens{"icons-locator-visible"} eq "disabled") )
+ {
+ $all_icons_disabled = "yes";
+ }
+ else
+ {
+ $all_icons_disabled = "no";
+ }
+}
+
+#==============================================================================
+
+sub print_body()
+{
+
+print "
+
+<body bgcolor=\"#FFFFFF\" leftmargin=0 topmargin=0 marginwidth=0 marginheight=0 onLoad=\"initValues()\">
+<FORM name=\"customize\">
+
+
+<table width=\"500\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">
+ <tr>
+ <td height=\"20\">&nbsp;</td></tr>
+</table>
+
+<table width=\"500\" border=\"1\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">
+<tr>
+ <td width=\"500\" height=\"22\" valign=\"top\" bgcolor=\"#cccccc\" class=\"pageHeader\">Customize View</td>
+</tr>
+
+<tr>
+ <td height=\"236\" valign=\"top\">
+ <table width=\"100%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\">
+ <tr height=\"7\"></tr>
+";
+
+
+#
+# If all icons are "disabled" by the admin, we better not display the
+# window dressing (header and footer) text that normally surrounds the
+# icon options. This is the header.
+#
+if ( "$all_icons_disabled" eq "no" )
+{
+ print "
+
+ <tr>
+ <td width=\"28\" height=\"21\" valign=\"top\">&nbsp;</td>
+ <td valign=\"top\" colspan=\"4\" class=\"prefsPageHead\">Icon Settings</td>
+ </tr>
+ <tr height =\"7\"></tr>
+ <tr>
+ <td width=\"35\" height=\"21\"></td>
+ <td width=\"35\" valign=\"top\" class=\"prefsPageData\">Icon:</td>
+ <td width=\"25\"></td>
+ <td width=\"105\" valign=\"top\" class=\"prefsPageData\">Description:</td>
+ <td width=\"21\"></td>
+ <td width=\"205\" valign=\"top\" class=\"prefsPageData\">Location:</td>
+ </tr>
+ ";
+}
+
+#
+# don't draw the email option if admin has disabled it !
+#
+if ( $config_tokens{"icons-email-visible"} ne "disabled" )
+{
+
+ print "
+
+ <tr height=\"6\"></tr>
+ <tr>
+ <td width=\"33\" height=\"21\"></td>
+ <td width=\"20\" valign=\"top\" class=\"prefsPageData\">&nbsp;<img src=\"../html/mail.gif\" alt=\"\" width=\"14\" height=\"16\" border=\"0\"></td>
+ <td width=\"25\"></td>
+ <td width=\"105\" valign=\"top\" class=\"prefsPageData\">EMail</td>
+ <td width=\"21\"></td>
+ <td width=\"205\" valign=\"center\" class=\"prefsPageData\"><select NAME=\"email\">
+";
+
+# --------------------------------------------
+
+$selected1 = $selected2 = $selected3 = "";
+if ($config_tokens{"icons-email-visible"} eq "no") { $selected1 = " SELECTED"; }
+if ($config_tokens{"icons-email-visible"} eq "forefront") { $selected2 = " SELECTED"; }
+if ($config_tokens{"icons-email-visible"} eq "layer") { $selected3 = " SELECTED"; }
+
+# --------------------------------------------
+
+print "
+ <option value=\"no\"$selected1>Never display this icon</option>
+ <option value=\"forefront\"$selected2>Next to name</option>
+ <option value=\"layer\"$selected3>In floating layer</option>
+ </select></td>
+
+ </tr>
+ ";
+}
+
+#
+# don't draw the phonebook option if admin has disabled it !
+#
+if ( $config_tokens{"icons-phonebook-visible"} ne "disabled" )
+{
+ print "
+ <tr height=\"6\"></tr>
+ <tr>
+ <td width=\"33\" height=\"21\"></td>
+ <td width=\"20\" valign=\"top\" class=\"prefsPageData\">&nbsp;<img src=\"../html/ldap-person.gif\" alt=\"\" width=\"12\" height=\"16\" border=\"0\"></td>
+ <td width=\"25\"></td>
+ <td width=\"125\" valign=\"top\" class=\"prefsPageData\" nowrap>Phonebook Entry</td>
+ <td width=\"21\"></td>
+ <td width=\"205\" valign=\"center\" class=\"prefsPageData\"><select NAME=\"phonebook\">
+";
+
+# --------------------------------------------
+
+$selected1 = $selected2 = $selected3 = "";
+if ($config_tokens{"icons-phonebook-visible"} eq "no") { $selected1 = " SELECTED"; }
+if ($config_tokens{"icons-phonebook-visible"} eq "forefront") { $selected2 = " SELECTED"; }
+if ($config_tokens{"icons-phonebook-visible"} eq "layer") { $selected3 = " SELECTED"; }
+
+# --------------------------------------------
+
+print "
+ <option value=\"no\"$selected1>Never display this icon</option>
+ <option value=\"forefront\"$selected2>Next to name</option>
+ <option value=\"layer\"$selected3>In floating layer</option>
+ </select></td>
+ </tr>
+ ";
+}
+
+#
+# don't draw the locator option if admin has disabled it !
+#
+if ( $config_tokens{"icons-locator-visible"} ne "disabled" )
+{
+
+ print "
+
+ <tr height=\"6\"></tr>
+ <tr>
+ <td width=\"33\" height=\"21\"></td>
+ <td width=\"20\" valign=\"top\" class=\"prefsPageData\">&nbsp;<img src=\"../html/mag.gif\" alt=\"\" width=\"15\" height=\"15\" border=\"0\"></td>
+ <td width=\"25\"></td>
+ <td width=\"125\" valign=\"top\" class=\"prefsPageData\" nowrap>Locate User</td>
+ <td width=\"21\"></td>
+ <td width=\"205\" valign=\"top\" class=\"prefsPageData\"><select NAME=\"locate\">
+
+";
+
+# --------------------------------------------
+
+$selected1 = $selected2 = $selected3 = "";
+if ($config_tokens{"icons-locator-visible"} eq "no") { $selected1 = " SELECTED"; }
+if ($config_tokens{"icons-locator-visible"} eq "forefront") { $selected2 = " SELECTED"; }
+if ($config_tokens{"icons-locator-visible"} eq "layer") { $selected3 = " SELECTED"; }
+
+# --------------------------------------------
+
+print "
+ <option value=\"no\"$selected1>Never display this icon</option>
+ <option value=\"forefront\"$selected2>Next to name</option>
+ <option value=\"layer\"$selected3>In floating layer</option>
+ </select></td>
+ </tr>
+ ";
+}
+
+#
+# don't draw the AIM option if admin has disabled it !
+#
+if ( $config_tokens{"icons-aim-visible"} ne "disabled" )
+{
+
+ print "
+ <tr height=\"6\"></tr>
+ <tr>
+ <td width=\"33\" height=\"21\"></td>
+ <td width=\"20\" valign=\"top\" class=\"prefsPageData\">&nbsp;<img src=\"../html/aim-online.gif\" alt=\"\" width=\"15\" height=\"15\" border=\"0\"></td>
+ <td width=\"25\"></td>
+ <td width=\"125\" valign=\"top\" class=\"prefsPageData\" nowrap>AIM Presence</td>
+ <td width=\"21\"></td>
+ <td width=\"205\" valign=\"top\" class=\"prefsPageData\"><select NAME=\"aim\">
+";
+
+# --------------------------------------------
+
+$selected1 = $selected2 = $selected3 = "";
+if ($config_tokens{"icons-aim-visible"} eq "no") { $selected1 = " SELECTED"; }
+if ($config_tokens{"icons-aim-visible"} eq "forefront") { $selected2 = " SELECTED"; }
+if ($config_tokens{"icons-aim-visible"} eq "layer") { $selected3 = " SELECTED"; }
+
+# --------------------------------------------
+
+print "
+ <option value=\"no\"$selected1>Never display this icon</option>
+ <option value=\"forefront\"$selected2>Next to name</option>
+ <option value=\"layer\"$selected3>In floating layer</option>
+ </select></td>
+ </tr>
+ ";
+}
+
+#
+# If all icons are "disabled" by the admin, we better not display the
+# window dressing (header and footer) text that normally surrounds the
+# icon options. This is the footer.
+#
+if ( "$all_icons_disabled" eq "no" )
+{
+ print "
+ <tr height=\"15\">
+ </tr>
+ <tr>
+ <td width=\"28\" height=\"21\" valign=\"top\">&nbsp;</td>
+ <td valign=\"middle\" colspan=\"4\"><hr></td>
+ </tr>
+ ";
+}
+
+print "
+ <tr>
+ <td width=\"28\" height=\"21\" valign=\"top\">&nbsp;</td>
+ <td valign=\"top\" colspan=\"4\" class=\"prefsPageHead\">Organization Chart Depth</td>
+ </tr>
+ <tr height=\"10\">
+ </tr>
+ <tr>
+ <td width=\"35\" height=\"28\"></td>
+ <td width=\"10\" valign=\"top\" class=\"prefsPageData\">Show&nbsp;&nbsp;</td>
+ <td width=\"20\" valign=\"top\" class=\"prefsPageData\"><select NAME=\"leveldepth\">
+";
+
+for ( $num = 1 ; $num <= $config_tokens{"max-levels-drawn"} ; $num++ )
+{
+ if ( $num < $config_tokens{"max-levels-drawn"} )
+ {
+ print "<option value=\"$num\">$num</option>";
+ }
+ else
+ {
+ print "<option value=\"$num\" SELECTED>$num</option>";
+ }
+}
+
+print "
+ </select></td>
+ <td width=\"350\" colspan=\"3\" class=\"prefsPageData\">&nbsp;&nbsp;levels of organization depth</td>
+ </tr>
+ <td height=\"30\"></td>
+ </table>
+ </td>
+ </tr>
+
+</table>
+
+<table width=\"500\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\" align=\"center\">
+ <tr>
+ <td height=\"20\">&nbsp;</td></tr>
+ <tr>
+ <td align=\"right\"><input type=\"button\" name=\"save\" value=\" Finished \" onClick=\"saveSettings();\"></td>
+ <td width=\"20\"</td>
+ <td><input type=\"button\" name=\"del_cookie\" value=\"Restore Defaults\" onClick=\"deleteCookie();\"></td>
+ </tr>
+ </table>
+</form>
+</body>
+";
+
+}
+
+#==============================================================================
+
+sub print_javascript()
+{
+
+print "
+
+<SCRIPT language=\"javascript\">
+
+var today = new Date();
+var expires = new Date();
+var expired = new Date(today.getTime() - 1000 * 24 * 60 * 60 * 1000);
+
+function initValues()
+{
+ var myorgsettings = getCookie(\"MyOrgChart\");
+ var possvalues = new Array(\"no\",\"forefront\",\"layer\");
+";
+
+
+# --------------------------------------------------------------
+
+#
+# let's build up a string like the contents below of Array
+# (if max-levels-drawn was 3):
+#
+# var posslevelvalues = new Array("1","2","3");
+#
+$finalstring = "var posslevelvalues = new Array(";
+
+for ( $num = 1 ; $num <= $config_tokens{"max-levels-drawn"} ; $num++ )
+{
+ $finalstring = "$finalstring\"$num\"";
+
+ if ( $num != $config_tokens{"max-levels-drawn"} )
+ {
+ $finalstring = "$finalstring,";
+ }
+}
+$finalstring = "$finalstring);";
+
+# --------------------------------------------------------------
+
+print "
+
+ $finalstring
+
+ // If there is a cookie already set, let's correct the
+ // values of the HTML form to be based on their personal
+ // settings, for easier editing and also lack of confusion
+ if ( myorgsettings != \"\" )
+ {
+ var splitorgvalues = myorgsettings.split(\"&\");
+ var tempstr;
+
+ // alert(myorgsettings);
+
+ for (var loop=0; loop < splitorgvalues.length; loop++)
+ {
+ tempstr = splitorgvalues[loop].split(\"=\");
+";
+
+# --start---------------------------------------------------------
+
+if ( $config_tokens{"icons-email-visible"} ne "disabled" )
+{
+
+print "
+ if ( tempstr[0] == \"email\" )
+ {
+ for (var innerloop=0; innerloop < possvalues.length; innerloop++)
+ {
+ if ( tempstr[1] == possvalues[innerloop] )
+ document.customize.email.options[innerloop].selected = true;
+ }
+ }
+";
+}
+
+# --end---------------------------------------------------------
+
+# --start---------------------------------------------------------
+
+if ( $config_tokens{"icons-phonebook-visible"} ne "disabled" )
+{
+
+print "
+
+ if ( tempstr[0] == \"pb\" )
+ {
+ for (var innerloop=0; innerloop < possvalues.length; innerloop++)
+ {
+ if ( tempstr[1] == possvalues[innerloop] )
+ document.customize.phonebook[innerloop].selected = true;
+ }
+ }
+";
+}
+
+# --end---------------------------------------------------------
+
+# --start---------------------------------------------------------
+
+if ( $config_tokens{"icons-locator-visible"} ne "disabled" )
+{
+
+print "
+
+ if ( tempstr[0] == \"maps\" )
+ {
+ for (var innerloop=0; innerloop < possvalues.length; innerloop++)
+ {
+ if ( tempstr[1] == possvalues[innerloop] )
+ document.customize.locate[innerloop].selected = true;
+ }
+ }
+";
+}
+
+# --end---------------------------------------------------------
+
+# --start---------------------------------------------------------
+
+if ( $config_tokens{"icons-aim-visible"} ne "disabled" )
+{
+
+print "
+
+ if ( tempstr[0] == \"aim\" )
+ {
+ for (var innerloop=0; innerloop < possvalues.length; innerloop++)
+ {
+ if ( tempstr[1] == possvalues[innerloop] )
+ document.customize.aim[innerloop].selected = true;
+ }
+ }
+";
+}
+
+# --end---------------------------------------------------------
+
+print "
+
+ if ( tempstr[0] == \"maxlevels\" )
+ {
+ for (var innerloop=0; innerloop < $config_tokens{\"max-levels-drawn\"}; innerloop++)
+ {
+ if ( tempstr[1] == posslevelvalues[innerloop] )
+ document.customize.leveldepth.options[innerloop].selected=true;
+ }
+ }
+ }
+
+ }
+
+ return;
+}
+
+function getCookie(Name)
+{
+ var search = Name + \"=\"
+ if (document.cookie.length > 0)
+ { // if there are any cookies
+ offset = document.cookie.indexOf(search)
+ if (offset != -1)
+ { // if cookie exists
+ offset += search.length // set index of beginning of value
+ end = document.cookie.indexOf(\";\", offset) // set index of end of cookie value
+ if (end == -1)
+ end = document.cookie.length
+ return unescape(document.cookie.substring(offset, end))
+ }
+ }
+
+ return (\"\");
+}
+
+function deleteCookie()
+{
+ document.cookie=\"MyOrgChart\" + \"=null; expires=\" + expired.toGMTString();
+ alert(\"Your preferences have been deleted from your browser.\");
+ document.location.href = \"myorg\";
+}
+
+function saveSettings()
+{
+ var i;
+ var finalString;
+
+ finalString = \"\";
+
+ // alert(document.customize.email.options[document.customize.email.selectedIndex].value);
+
+";
+
+if ( $config_tokens{"icons-email-visible"} ne "disabled" )
+{
+print"
+ finalString += \"&email=\" + document.customize.email.options[document.customize.email.selectedIndex].value;
+";
+}
+
+if ( $config_tokens{"icons-phonebook-visible"} ne "disabled" )
+{
+print"
+ finalString += \"&pb=\" + document.customize.phonebook.options[document.customize.phonebook.selectedIndex].value;
+";
+}
+
+if ( $config_tokens{"icons-locator-visible"} ne "disabled" )
+{
+print"
+ finalString += \"&maps=\" + document.customize.locate.options[document.customize.locate.selectedIndex].value;
+";
+}
+
+if ( $config_tokens{"icons-aim-visible"} ne "disabled" )
+{
+print"
+ finalString += \"&aim=\" + document.customize.aim.options[document.customize.aim.selectedIndex].value;
+";
+}
+
+print "
+
+ finalString += \"&maxlevels=\" + document.customize.leveldepth.options[document.customize.leveldepth.selectedIndex].value;
+
+ expires.setTime(today.getTime() + 1000*60*60*24*365);
+ setCookie(\"MyOrgChart\", finalString, expires);
+
+ alert(\"Your preferences have been saved in your browser.\");
+ // alert(\"Your preferences have been saved in your browser as:\\n\" + finalString);
+ return;
+}
+
+function setCookie(name, value, expire)
+{
+ document.cookie = name + \"=\" + escape(value)
+ + ((expire == null) ? \"\" : (\"; expires=\" + expire.toGMTString()));
+}
+
+</SCRIPT>
+
+";
+
+}
+
+#==============================================================================
+
+
+
diff --git a/ldap/clients/orgchart/new-branch-blank.gif b/ldap/clients/orgchart/new-branch-blank.gif
new file mode 100644
index 00000000..e5dfeebb
--- /dev/null
+++ b/ldap/clients/orgchart/new-branch-blank.gif
Binary files differ
diff --git a/ldap/clients/orgchart/new-branch-first.gif b/ldap/clients/orgchart/new-branch-first.gif
new file mode 100644
index 00000000..aa371353
--- /dev/null
+++ b/ldap/clients/orgchart/new-branch-first.gif
Binary files differ
diff --git a/ldap/clients/orgchart/new-branch-straight.gif b/ldap/clients/orgchart/new-branch-straight.gif
new file mode 100644
index 00000000..9e379047
--- /dev/null
+++ b/ldap/clients/orgchart/new-branch-straight.gif
Binary files differ
diff --git a/ldap/clients/orgchart/nslogo.gif b/ldap/clients/orgchart/nslogo.gif
new file mode 100644
index 00000000..e688bb41
--- /dev/null
+++ b/ldap/clients/orgchart/nslogo.gif
Binary files differ
diff --git a/ldap/clients/orgchart/org.bat b/ldap/clients/orgchart/org.bat
new file mode 100644
index 00000000..c36e890b
--- /dev/null
+++ b/ldap/clients/orgchart/org.bat
@@ -0,0 +1,2 @@
+@set path=..\..\..\bin\slapd\admin\bin;%path%
+@perl org.pl
diff --git a/ldap/clients/orgchart/org.pl b/ldap/clients/orgchart/org.pl
new file mode 100755
index 00000000..e8aadb57
--- /dev/null
+++ b/ldap/clients/orgchart/org.pl
@@ -0,0 +1,2004 @@
+#!../../../bin/slapd/admin/bin/perl
+#
+#set ts=4
+
+# ------------
+#
+# Notes for anybody reading the code below:
+#
+# [1] The concept of the $uid variable throughout the code
+# is whatever the leftmost RDN value is for a given user DN,
+# and this relates to the "attrib-farleft-rdn" setting in
+# config.txt, of what the attribute name will always be.
+#
+# ------------
+
+
+use Mozilla::LDAP::Conn;
+use Mozilla::LDAP::Utils qw(:all);
+
+use CGI;
+$cg = new CGI;
+
+$|=1;
+print "Content-type: text/html;charset=UTF-8\n\n";
+
+##########################################
+#
+# Let's find out what browswer they are using
+#
+##########################################
+
+$agentstring = $ENV{'HTTP_USER_AGENT'};
+
+# IE 6.0 : ---Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)---
+# Comm478 : ---Mozilla/4.78 [en] (Windows NT 5.0; U)---
+# Nscp622 : ---Mozilla/5.0 (Windows; U; Windows NT 5.0; en-US; rv:0.9.4.1) Gecko/20020314 Netscape6/6.2.2---
+
+$browser_is_msie = "MSIE" if $agentstring =~ /MSIE/;
+
+# is this Windows?
+$isWindows = -d '\\';
+
+##########################################
+#
+# Read config.txt settings, set by the administrator
+#
+##########################################
+
+&read_config_file();
+
+##########################################
+#
+# Let's look at what is being passed in, from the user.
+#
+##########################################
+
+
+#
+# "data" is a generic FORM variable name from
+# the topframe.html document that we receive our incoming query
+# from.
+#
+# (See comment at start of this file about "$uid" variable.)
+#
+if ( defined $cg->param("data") )
+{
+ $uid = $cg->param("data");
+}
+
+#
+# For coexistence with the DSGW, when we crosslink, we need to
+# make sure that the user is taken back to the correct dsgw
+# context
+#
+$contextParamString = "";
+if ( defined $cg->param("context") )
+{
+ $context = $cg->param("context");
+ $contextParamString = "context=${context}&";
+ $config_tokens{"url-phonebook-base"} =~ s/context=.*?&/$contextParamString/g;
+}
+
+#
+# But they may have entered this code from clicking on an org
+# chart icon from an already-drawn org chart, in which case
+# we know what the RDN attribute name is (cn, uid, etc.), so i
+# that has priority, if present.
+#
+if ( defined $cg->param("$config_tokens{'attrib-farleft-rdn'}") )
+{
+ $uid = $cg->param("$config_tokens{'attrib-farleft-rdn'}")
+}
+
+if ($uid eq "")
+{
+ &output_html_header("no-javascript");
+ print "No username selected...</BODY></HTML>";
+ #print "\n</BODY></HTML>";
+ exit(0);
+}
+
+##########################################
+#
+# If the user has asked this org chart to be prepared for printing
+#
+##########################################
+
+if ( (defined $cg->param("print")) && ( $cg->param("print") eq "yes" ) )
+{
+ $print_mode = 1;
+}
+else
+{
+ $print_mode = 0;
+}
+
+if ( !($print_mode) )
+{
+ $fontstring="<font face=\"verdana, Arial, Helvetica, sans-serif\" style=\"font-size: 11px\">";
+}
+else
+{
+ # if printing, let's make the font smaller, to fit more org chart on one page
+ #
+ $fontstring="<font face=\"verdana, Arial, Helvetica, sans-serif\" style=\"font-size: 8px\">";
+}
+
+##########################################
+#
+# See if the user has their own preferences to use.
+#
+#
+##########################################
+
+&check_myorgchart_settings();
+
+
+##########################################
+#
+# Let's configure which attributes to request from LDAP,
+# based on preferences read above...
+#
+##########################################
+
+&config_ldap_return_attrib_list();
+
+
+##########################################
+#
+# global variable descriptions:
+#
+# $total : stores the displayed statistic of "Total # of people" that is printed under org chart
+# $display_indent : helps track how deeply "indented" in the org chart hierarchy a given person is, to help
+# draw an internal data structure of the hierarchy. See details in get_org_data() function.
+# $tempnum : just generic variable used for different reasons, always within a very small (controllable)
+# scope within a given function only, since a generic all-purpose variable
+# $anothertempnum : same idea as $tempnum, just another variable for the same generic purpose
+# $tempstr : same idea as $tempnum, just another variable for the same generic purpose
+#
+#
+##########################################
+
+$total = 0;
+$display_indent = 0;
+$tempnum = 0;
+$anothertempnum = 0;
+$tempstr = "";
+
+##########################################
+#
+# The $incomplete variable tracks whether an org chart cannot
+# be fully drawn because the "max number of levels to draw"
+# setting has been exceeded. We'll use this variable value
+# to: [1] store this fact during initial LDAP data gathering,
+# [2] to make sure we draw org chart icons (hyperlinks) next
+# to people that have people below them purposely
+# not displayed (purposely chopped off)
+#
+##########################################
+
+$incomplete = 0;
+
+##########################################
+#
+# Let's take what the end-user entered and search on it.
+# If not found as an exact uid=XXX match, then let's
+# broader their search to try to give them some results to
+# pick from.
+#
+##########################################
+
+&search_for_enduser_query();
+
+##########################################
+#
+# Before we draw any part of the org chart,
+# let's send the javascript code needed back
+# to the browser first, as well as open BODY tag
+#
+##########################################
+
+&output_html_header("with-javascript");
+
+
+##########################################
+#
+# This single DIV layer HTML code will be used as the only layer in the final output.
+# It is dynamically changed, as far as its content, based on which person that the
+# end-user hovers the mouse cursor over. This is much faster (WAY less code to send
+# to the browser) compared to sending a unique hardcoded DIV for each and every
+# person that appears on the org chart.
+#
+##########################################
+
+&print_single_div_html();
+
+##########################################
+#
+# For some reason, Nav4 browsers ignore onMouseOver and onMouseOut
+# event handlers if they are inside the DIV HTML tag itself, so
+# you have to assign them to the DIV after declaring the DIV above.
+#
+##########################################
+
+&nav4_specific_event_handlers();
+
+##########################################
+#
+# Start drawing the org chart to the browser.
+#
+##############
+#
+# Let's first put the full name of the person submitted to us in a box,
+# along with their manager listed underneath them.
+#
+##########################################
+
+&print_topmost_box();
+
+##########################################
+#
+# See if the "manager-DN-location" config.txt setting is
+# either "search" or else assume "same".
+#
+# See config.txt file for detailed description.
+#
+##########################################
+
+if ( $config_tokens{"manager-DN-location"} eq "search" )
+{
+ $tempstr = "*"
+}
+else
+{
+ # if we are assuming "same", then strip the leftmost RDN component
+ # out of the entered LDAP user's DN, and assume that location
+ # for all user entry locations we will be dealing with.be dealing with.
+ #
+ ($tempstr) = ($entry->{dn} =~ /[^,]+=[^,]+,(.+)/ );
+}
+
+##########################################
+#
+# This is where the heavy lifting is done. Generate an 2D array
+# that stores all the org chart people data we need, to later draw it.
+#
+##########################################
+
+&get_org_data($entry->{$config_tokens{'attrib-farleft-rdn'}}[0], $config_tokens{'attrib-farleft-rdn'} , $tempstr);
+
+
+##########################################
+#
+# Let's sort the return results array, mainly to help put
+# the hierarchy in order, to help us draw the final result.
+#
+##########################################
+
+@sortedPeople = sort { $a->[0] cmp $b->[0] } @people;
+
+
+##########################################
+#
+# If they exceeded max depth allowed, let's still figure out
+# which people are managers of some type and make sure we
+# still put an org chart icon next to their name, even if the
+# people below them will not be shown because of being on the
+# side that was chopped off (past the max depth), so that at
+# least the end user knows people in reality report to that
+# person, even though not displayed on purpose.
+#
+##########################################
+
+&detect_nonleaf_depth_exceeded();
+
+##########################################
+#
+# This function will print just the tree branch that is below the
+# topmost box.
+#
+##########################################
+
+&print_toplevel_tree_branch();
+
+##########################################
+#
+# Now let's analyze the remaining branch structure to draw,
+# and pre-markup some details about how to draw this branch structure,
+# as it can get quite complex for some org charts.
+#
+# we need to scan up and down several times certain parts of the
+# org chart data in certain areas to learn things about how to draw
+# the structure to the screen. This just makes life easier at the
+# final drawing stage.
+#
+##########################################
+
+&pre_markup_remaining_branches();
+
+##########################################
+#
+# Draw the rest of the org chart.
+# (with "rest" meaning non-leaf entries below the uid that the end-user entered,
+# so this means both the 2nd layer of boxes that have a single name in each
+# box, as well as then the tree branches under each of those boxes)
+#
+##########################################
+
+&draw_remaining_branches();
+
+##########################################
+#
+# The org chart is basically drawn now. We just need
+# to close some tables that we have open, and print the
+# total number of reports shown on the entire org chart.
+#
+##########################################
+
+print "</TD></TR></TABLE></center>";
+print "\n\n";
+print "<BR><BR><HR>\n$fontstring";
+print "Total number of reports shown above: " . $total . "\n</font><BR><BR><BR><BR><BR><BR><BR><BR>";
+print "</TD><TD NOWRAP>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</TD></TABLE></CENTER></BODY></HTML>\n";
+
+exit;
+
+
+#==============================================================================
+#
+# End of "main()" part of script. All the subroutines are below, that were
+# used above.
+#
+#==============================================================================
+
+
+##########################################
+#
+# get_org_data(): A recursive function that gets all the needed LDAP data on all people
+# necessary to later draw the resulting org chart.
+#
+##########################################
+
+sub get_org_data
+{
+ local ($attrib_value, $attrib_name, $managerDNlocation) = @_;
+ local ($manager)="$attrib_name=" . $attrib_value . ",$managerDNlocation";
+ local ($search) = "$config_tokens{'attrib-manager'}=$manager";
+ local ($entry);
+ local ($conn);
+
+ $conn = new Mozilla::LDAP::Conn($config_tokens{"ldap-host"}, $config_tokens{"ldap-port"}, $config_tokens{"ldap-bind-dn"}, $config_tokens{"ldap-bind-pass"});
+ die "Could't connect to LDAP server $config_tokens{\"ldap-host\"}" unless $conn;
+ $entry = $conn->search($config_tokens{"ldap-search-base"}, "subtree", $search, 0, @return_attribs);
+
+ $display_indent += 1;
+
+ while ($entry)
+ {
+ if (not_terminated($entry) && not_own_manager($entry))
+ {
+ $total++;
+
+ $indentname[$display_indent] = $entry->{cn}[0];
+
+ $people[$total-1][0] = "/";
+ for ( $tempnum = 1 ; $tempnum < $display_indent+1 ; $tempnum++ )
+ {
+ $people[$total-1][0] = "$people[$total-1][0]$indentname[$tempnum]/";
+ }
+ $people[$total-1][1] = $entry->{$config_tokens{'attrib-farleft-rdn'}}[0];
+ $people[$total-1][2] = url_encode($entry->{dn});
+ $people[$total-1][3] = $entry->{mail}[0];
+ $people[$total-1][4] = $entry->{$config_tokens{"attrib-job-title"}}[0];
+
+ # AIM
+ $people[$total-1][5] = "(none)";
+
+ if ( $config_tokens{"icons-aim-visible"} ne "no" )
+ {
+ if ( "$entry->{nsAIMStatusText}[0]" eq "ONLINE" )
+ {
+ $people[$total-1][5] = $entry->{nsaimid}[0];
+ }
+ if ( "$entry->{nsAIMStatusText}[0]" eq "OFFLINE" )
+ {
+ $people[$total-1][5] = "OFFLINE";
+ }
+ }
+
+ # locator
+ $people[$total-1][6] = url_encode($entry->{cn}[0]);
+
+
+ if ( $display_indent < $config_tokens{"max-levels-drawn"}+1 )
+ {
+ get_org_data($entry->{$config_tokens{'attrib-farleft-rdn'}}[0], $config_tokens{'attrib-farleft-rdn'} , $managerDNlocation);
+ }
+ else
+ {
+ $incomplete = 1;
+ }
+
+ }
+
+ $entry = $conn->nextEntry();
+ }
+
+
+ $display_indent -= 1;
+}
+
+##########################################
+#
+# not_terminated(): Should we leave this in the shipping version, since most companies
+# may want to modify it for how they mark LDAP entries as inactive?
+#
+# Can't do any harm technically to leave it here, but may just look
+# like loose ends to the customer and gives away part of our internal
+# way of doing things. I'll leave it up to you, the code reviewer,
+# to make the call. (I see pros and cons both ways.)
+#
+##########################################
+
+sub not_terminated
+{
+ my($person) = @_;
+
+ for ($j=0; $person->{objectclass}[$j] ; $j++)
+ {
+ if ($person->{objectclass}[$j] eq "nscphidethis")
+ {
+ return(0);
+ }
+ }
+ return(1);
+}
+
+##########################################
+#
+# not_own_manager(): See if person reports to himself, and if so then
+# we need to tell the calling function that, so we
+# don't get caught in an infinite loop while discovering
+# the reporting chain.
+#
+##########################################
+
+sub not_own_manager
+{
+ my ($entry) = @_;
+
+ @manager= split (/,/ , $entry->{$config_tokens{'attrib-manager'}}[0]);
+ @splitagain = split (/=/, @manager[0] );
+ $manageruid = @splitagain[1];
+
+ if ( $entry->{$config_tokens{'attrib-farleft-rdn'}}[0] eq $manageruid)
+ {
+ print "ATTENTION: $entry->{cn}[0] is his own manager!<BR>\n";
+ return(0);
+ }
+ else
+ {
+ return(1);
+ }
+}
+
+
+##########################################
+#
+# Print the locator icon icon next to the person's name,
+# if that's what we are configured to do, and only if not in
+# print mode ("print mode": if the page is not being generated
+# in a stripped-down way [sans icons] for printing)
+#
+##########################################
+
+sub print_locator_icon_if_outside_layer
+{
+ my ($visible, $locator) = @_;
+
+ if ( ($visible eq "forefront") && (!($print_mode)) )
+ {
+ print " <a href=\"$config_tokens{\"url-locator-base\"}";
+ print "$locator\"><img src=\"../html/mag.gif\" border=0 align=TEXTTOP></a>";
+ }
+
+ return;
+}
+
+##########################################
+#
+# Print the phonebook icon icon next to the person's name,
+# if that's what we are configured to do, and only if not in
+# print mode ("print mode": if the page is not being generated
+# in a stripped-down way [sans icons] for printing)
+#
+##########################################
+
+sub print_pb_icon_if_outside_layer
+{
+ my ($visible, $dn) = @_;
+
+ if ( ($visible eq "forefront") && (!($print_mode)) )
+ {
+
+ print " <a href=\"$config_tokens{'url-phonebook-base'}";
+ print "$dn\">";
+ print "<img src=\"../html/ldap-person.gif \" border=0 align=TEXTTOP>";
+ print "</a>";
+ }
+
+ return;
+}
+
+##########################################
+#
+# Print the email icon icon next to the person's name,
+# if that's what we are configured to do, and only if not in
+# print mode ("print mode": if the page is not being generated
+# in a stripped-down way [sans icons] for printing)
+#
+##########################################
+
+sub print_email_icon_if_outside_layer
+{
+ my ($visible, $email) = @_;
+
+ if ( ($visible eq "forefront") && ( $email =~ /@/ ) && (!($print_mode)) )
+ {
+ print " <a href=\"mailto:$email\">";
+ print "<img src=\"../html/mail.gif \" border=0 align=TEXTTOP>";
+ print "</a>";
+ }
+
+ return;
+}
+
+##########################################
+#
+# Print the AIM icon icon next to the person's name,
+# if that's what we are configured to do, and only if not in
+# print mode ("print mode": if the page is not being generated
+# in a stripped-down way [sans icons] for printing), and if the person is ONLINE
+#
+##########################################
+
+sub print_aim_icon_if_outside_layer
+{
+ my ($visible, $status, $screenname) = @_;
+
+ if ( ($visible eq "forefront") && (!($print_mode)) )
+ {
+ if ( $status eq "discover" )
+ {
+ if ( ($screenname eq "(none)") || ($screenname eq "OFFLINE") )
+ {
+ $status = "OFFLINE";
+ }
+ else
+ {
+ $status = "ONLINE";
+ }
+ }
+
+ if ( $status eq "ONLINE" )
+ {
+ $screenname =~ tr/ /+/;
+ print " <a href=\"aim:goim?Screenname=$screenname\">";
+ print "<img src=\"../html/aim-online.gif\" border=0 align=TEXTTOP></a>";
+ }
+ }
+
+ return;
+}
+
+##########################################
+#
+# Figure out if we are supposed to be putting the locator icon
+# inside the floating layer, if that's what we are configured to do.
+# If not, then return "(none)", which client-side javascript then
+# knows how to react off of (to not display anything).
+#
+##########################################
+
+sub is_locator_in_layer
+{
+ my ($visible, $locator) = @_;
+ my ($returnvalue) = "(none)";
+
+ if ( $visible eq "layer" )
+ {
+ $returnvalue = $locator;
+ }
+
+ return ( $returnvalue );
+}
+
+##########################################
+#
+# Figure out if we are supposed to be putting the phonebook icon
+# inside the floating layer, if that's what we are configured to do.
+# If not, then return "(none)", which client-side javascript then
+# knows how to react off of (to not display anything).
+#
+##########################################
+
+sub is_pb_in_layer
+{
+ my ($visible, $pb) = @_;
+ my ($returnvalue) = "(none)";
+
+ if ( $visible eq "layer" )
+ {
+ $returnvalue = $pb;
+ }
+
+ return ( $returnvalue );
+}
+
+##########################################
+#
+# Figure out if we are supposed to be putting the email icon
+# inside the floating layer, if that's what we are configured to do.
+# If not, then return "(none)", which client-side javascript then
+# knows how to react off of (to not display anything).
+#
+##########################################
+
+sub is_email_in_layer
+{
+ my ($visible, $email) = @_;
+ my ($returnvalue) = "(none)";
+
+ if ( ($visible eq "layer") && ( $email =~ /@/ ) )
+ {
+ $returnvalue = $email;
+ }
+
+ return ( $returnvalue );
+}
+
+##########################################
+#
+# Figure out if we are supposed to be putting the AIM icon
+# inside the floating layer, if that's what we are configured to do.
+# If not, then return "(none)", which client-side javascript then
+# knows how to react off of (to not display anything).
+# knows how to react off of (to not display anything).
+#
+##########################################
+
+sub is_aimid_in_layer
+{
+ my ($visible, $status, $screenname) = @_;
+
+ my ($returnvalue) = "(none)";
+
+ if ( $status eq "discover" )
+ {
+ if ( ($screenname eq "(none)") || ($screenname eq "OFFLINE") )
+ {
+ $status = "OFFLINE";
+ }
+ else
+ {
+ $status = "ONLINE";
+ }
+ }
+
+
+ if ( ($visible eq "layer") && ($status eq "ONLINE") )
+ {
+ $screenname =~ tr/ /+/;
+ $returnvalue = $screenname;
+ }
+
+ return ( $returnvalue );
+}
+
+##########################################
+#
+# Generic encoder function, used in several places for building
+# correct URL's for the user to click on.
+#
+##########################################
+
+sub url_encode
+{
+ my ($tempstr) = @_;
+
+ $tempstr =~ s/([\W])/"%" . uc(sprintf("%2.2x",ord($1)))/eg;
+
+ return($tempstr);
+}
+
+##########################################
+#
+# This javascript below is needed for whenever an org chart of any
+# nature is drawn. It contains the DHTML-related javascript to
+# dynamically construct and display (and then hide) a given floating
+# layer of information and links for a given employee that is being
+#
+##########################################
+
+sub print_javascript
+{
+
+print "<SCRIPT>
+
+
+var left = 0;
+var top = 0;
+
+var W3C = document.getElementById? true : false;
+var NN4 = document.layers? true : false;
+var IE4 = document.all? true : false;
+var MOZ5 = ((navigator.userAgent.toLowerCase().indexOf(\"mozilla\")==0) && (navigator.userAgent.toLowerCase().charAt(8) >= 5) && (navigator.userAgent.toLowerCase().indexOf(\"compatible\")<0));
+var OP = navigator.userAgent.toLowerCase().indexOf(\"opera\")>=0;
+
+var isOver = false;
+var timer = null;
+
+function OverLayer()
+{
+ clearTimeout(timer);
+ isOver = true;
+}
+
+function OutLayer()
+{
+ clearTimeout(timer);
+ isOver = false;
+ timer = setTimeout(\"hideLayer()\",500);
+}
+
+
+function hideLayer()
+{
+ if (!isOver)
+ {
+ if ( W3C )
+ {
+ document.getElementById(\"test\").style.visibility = \"hidden\";
+ }
+
+ if ( NN4 )
+ {
+ document.layers[\"test\"].visibility = \"hidden\";
+ }
+
+ if ( IE4 )
+ {
+ document.all[\"test\"].style.visibility = \"hidden\";
+ }
+
+ }
+
+
+}
+
+
+function showLayer(cn,title,mail,dn,locator,aimid)
+{
+ var finalhtml;
+ var num = 0;
+
+ clearTimeout(timer);
+ hideLayer();
+
+ finalhtml = '<TABLE border=1 CELLPADDING=15 BGCOLOR=\"#CBCBFD\"><TR><TD><TABLE BORDER=0>';
+ finalhtml += '<TR><TD COLSPAN=2 NOWRAP>$fontstring<B>' + unescape(cn) + '</B></font></TD></TR>';
+ finalhtml += '<TR><TD COLSPAN=2 NOWRAP>$fontstring' + title + '</font></TD></TR>';
+ finalhtml += '<TR><TD COLSPAN=2 NOWRAP>';
+
+ if ( (mail == '(none)') && (dn == '(none)') && (locator == '(none)') && (aimid == '(none)') )
+ {
+ // don't draw HR line
+ }
+ else
+ {
+ finalhtml += '<HR>';
+ }
+
+ finalhtml += '</TD></TR>';
+
+ if ( mail != '(none)' )
+ {
+ finalhtml += '<TR><TD align=center><a href=\"mailto:' + mail + '\">';
+ finalhtml += '<img src=\"../html/mail.gif\" border=0 align=TEXTTOP></a></TD>';
+ finalhtml += '<TD NOWRAP>$fontstring &nbsp;&nbsp;&nbsp;';
+ finalhtml += '<a href=\"mailto:' + mail + '\">Email</a></font></TD></TR>';
+ }
+
+ if ( dn != '(none)' )
+ {
+ finalhtml += '<TR><TD align=center>';
+ finalhtml += '<a href=\"$config_tokens{\"url-phonebook-base\"}';
+ finalhtml += dn + '\"><img src=\"../html/ldap-person.gif\" border=0 align=TEXTTOP></a></TD>';
+ finalhtml += '<TD NOWRAP>$fontstring &nbsp;&nbsp;&nbsp;';
+ finalhtml += '<a href=\"$config_tokens{\"url-phonebook-base\"}' + dn + '\">';
+ finalhtml += 'Phonebook</a></font></TD></TR>';
+ }
+
+ if ( locator != '(none)' )
+ {
+ finalhtml += '<TR><TD align=center>';
+ finalhtml += '<a href=\"$config_tokens{\"url-locator-base\"}';
+ finalhtml += locator + '\"><img src=\"../html/mag.gif\" border=0 align=TEXTTOP></a></TD>';
+ finalhtml += '<TD NOWRAP>$fontstring &nbsp;&nbsp;&nbsp;';
+ finalhtml += '<a href=\"$config_tokens{\"url-locator-base\"}' + locator + '\">';
+ finalhtml += 'Locator</a></font></TD></TR>';
+ }
+
+ if ( aimid != '(none)' )
+ {
+ finalhtml += '<TR><TD align=center>';
+ finalhtml += '<a href=\"aim:goim?Screenname=' + aimid + '\">';
+ finalhtml += '<img src=\"../html/aim-online.gif\" border=0 align=TEXTTOP></a></TD>';
+ finalhtml += '<TD NOWRAP>$fontstring &nbsp;&nbsp;&nbsp;';
+ finalhtml += '<a href=\"aim:goim?Screenname=' + aimid + '\">';
+ finalhtml += 'Currently online</a></font></TD></TR>';
+ }
+
+ finalhtml += '</TABLE></TD></TR></TABLE>';
+
+
+ if ( W3C )
+ {
+ document.getElementById(\"test\").innerHTML = finalhtml;
+
+ if (navigator.userAgent.toLowerCase().indexOf('opera')>-1)
+ {
+ // Opera bug - don't use the units
+ document.getElementById(\"test\").style.left = left + 25;
+ document.getElementById(\"test\").style.top = top + 5;
+ }
+ else
+ {
+ document.getElementById(\"test\").style.left = left + 25 + \"px\";
+ document.getElementById(\"test\").style.top = top + 5 + \"px\";
+ }
+
+ document.getElementById(\"test\").style.visibility = \"visible\";
+ }
+
+
+ if ( IE4 )
+ {
+ test.innerHTML = finalhtml;
+
+ document.all[\"test\"].style.pixelLeft = left + 25;
+ document.all[\"test\"].style.pixelTop = top + 5;
+ document.all[\"test\"].style.visibility = \"visible\";
+ }
+
+
+ if ( NN4 )
+ {
+ document.test.document.write(finalhtml);
+ document.test.document.close();
+
+ document.layers[\"test\"].left = left + 25;
+ document.layers[\"test\"].top = top + 5;
+ document.layers[\"test\"].visibility = \"show\";
+ }
+
+}
+
+function setMouseCoordinate(e)
+{
+ if (MOZ5 || NN4)
+ {
+ left = e.pageX;
+ top = e.pageY;
+ }
+ else if (IE4 || OP)
+ {
+ left = document.body.scrollLeft + event.clientX;
+ top = document.body.scrollTop + event.clientY;
+ }
+}
+
+
+if ( NN4 )
+{
+ document.captureEvents(Event.MOUSEMOVE);
+}
+document.onmousemove = setMouseCoordinate;
+
+
+
+</SCRIPT>
+
+";
+
+}
+
+##########################################
+#
+# Read the "config.txt" file for admin's desired settings.
+#
+#
+# See the file itself for details on what each setting
+# represents, and what the possible values are.
+#
+##########################################
+
+sub read_config_file()
+{
+my $curdir;
+if ($isWindows) {
+ $curdir = `cd`; chop($curdir);
+} else {
+ $curdir = `pwd`; chop($curdir);
+}
+if (!open (FILE, "../config.txt") )
+{
+ &output_html_header("no-javascript");
+ print "\n\n<BR><BR>Can't open configuration file: $curdir/config.txt\n\n<BR><BR>Error from OS: $!\n\n";
+ print "\n</BODY></HTML>";
+ exit;
+}
+
+%config_tokens = ( "ldap-host","none",
+ "ldap-port","none",
+ "ldap-search-base","none",
+ "ldap-bind-dn","",
+ "ldap-bind-pass","",
+ "icons-aim-visible","no",
+ "icons-email-visible","no",
+ "icons-phonebook-visible","no",
+ "icons-locator-visible","no",
+ "url-phonebook-base", "none",
+ "url-locator-base", "none",
+ "attrib-job-title", "title",
+ "attrib-manager", "manager",
+ "attrib-farleft-rdn", "uid",
+ "max-levels-drawn", "3",
+ "manager-DN-location", "same",
+ "min-chars-searchstring", "4",
+ "allowed-filter-chars", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 _-"
+ );
+
+while(<FILE>)
+{
+ chop;
+
+ foreach $f (keys %config_tokens)
+ {
+ $config_tokens{$f} = $1 if ($_ =~ /^$f[ \t]+(.+)/);
+ }
+}
+
+close (FILE);
+
+
+if ( $config_tokens{"ldap-host"} eq "none" )
+{
+ &output_html_header("no-javascript");
+ print "<BR><BR>The administrator of this application needs to configure an LDAP host to use.<BR><BR>";
+ print "\n</BODY></HTML>";
+ exit(0);
+}
+if ( $config_tokens{"ldap-port"} eq "none" )
+{
+ &output_html_header("no-javascript");
+ print "<BR><BR>The administrator of this application needs to configure an LDAP port number to use.<BR><BR>";
+ print "\n</BODY></HTML>";
+ exit(0);
+}
+if ( $config_tokens{"ldap-search-base"} eq "none" )
+{
+ &output_html_header("no-javascript");
+ print "<BR><BR>The administrator of this application needs to configure an LDAP search base.<BR><BR>";
+ print "\n</BODY></HTML>";
+ exit(0);
+}
+if ( ($config_tokens{"url-phonebook-base"} eq "none") && ( $config_tokens{"icons-phonebook-visible"} ne "disabled") )
+{
+ &output_html_header("no-javascript");
+ print "<BR><BR>The administrator of this application has configured phonebook icons to be enabled, but has not yet configured a phonebook partial base URL to use for those phonebook icons.<BR><BR>";
+ print "\n</BODY></HTML>";
+ exit(0);
+}
+if ( ($config_tokens{"url-locator-base"} eq "none") && ( $config_tokens{"icons-locator-visible"} ne "disabled") )
+{
+ &output_html_header("no-javascript");
+ print "<BR><BR>The administrator of this application has configured locator icons to be enabled, but has not configured a locator partial base URL to use for those locator icons.<BR><BR>";
+ print "\n</BODY></HTML>";
+ exit(0);
+}
+}
+
+
+##########################################
+#
+# Let's read in (and validate) any personal settings
+# that the user has, which they can set from clicking
+# the "Customize" link.
+#
+##########################################
+
+
+sub check_myorgchart_settings()
+{
+
+ my $query = new CGI;
+ my $cookie_in = $query->cookie("MyOrgChart");
+
+ #
+ # if client-side browser cookie was found...
+ #
+ if ($cookie_in)
+ {
+ @cookiedata = split (/&/ , $cookie_in);
+
+ foreach $f (@cookiedata)
+ {
+ if ( $f =~ /=/ )
+ {
+ @individ = split (/=/ , $f);
+ $cookie_tokens{$individ[0]} = $individ[1];
+ }
+ }
+ }
+
+# =========================================================
+#
+# begin ---> Check for MyOrgChart overriding settings
+# (that may override settings the admin set
+# in config.txt)
+#
+# =========================================================
+
+if ( (defined $cookie_tokens{"email"}) && ($config_tokens{"icons-email-visible"} ne "disabled") )
+{
+ $config_tokens{"icons-email-visible"} = $cookie_tokens{"email"};
+}
+if ( (defined $cookie_tokens{"pb"}) && ($config_tokens{"icons-phonebook-visible"} ne "disabled") )
+{
+ $config_tokens{"icons-phonebook-visible"} = $cookie_tokens{"pb"};
+}
+if ( (defined $cookie_tokens{"maps"}) && ( $config_tokens{"icons-locator-visible"} ne "disabled" ) )
+{
+ $config_tokens{"icons-locator-visible"} = $cookie_tokens{"maps"};
+}
+if ( (defined $cookie_tokens{"aim"}) && ($config_tokens{"icons-aim-visible"} ne "disabled") )
+{
+ $config_tokens{"icons-aim-visible"} = $cookie_tokens{"aim"};
+}
+if ( defined $cookie_tokens{"maxlevels"} )
+{
+ if ( $cookie_tokens{"maxlevels"} < $config_tokens{"max-levels-drawn"} )
+ {
+ #
+ # Just to make life easier (coding-wise), if the user specified a
+ # a personal preference of having a smaller number of "maxlevels"
+ # (how many levels drawn for any org chart they generate) drawn than
+ # the admin-configured value, let's just set the admin-config'ed value
+ # (just in memory, so just for a few seconds) to the user's value
+ #
+ $config_tokens{"max-levels-drawn"} = $cookie_tokens{"maxlevels"};
+ }
+}
+
+
+# =========================================================
+#
+# end ---> Check for MyOrgChart overriding settings
+#
+# =========================================================
+
+# Hold on, one final important step before we leave this function....
+#
+# Below (as far as just this Perl CGI file is concerned only) it is a lot less code
+# to just treat "disabled" settings as "no" for the icons, to accomplish the
+# same end result in both cases, of not showing the given icon(s).
+#
+# But in the MyOrgChart.cgi, we do care about this distinction, because for the
+# "disable" setting we don't want the user to have the option listed to enable
+# that icon to now be displayed in some way. This is why we need to have the
+# below code right after the MyOrgChart overrides above, to make sure the
+# below has the final say, for the icon-related settings.
+#
+if ( $config_tokens{"icons-aim-visible"} eq "disabled" ) { $config_tokens{"icons-aim-visible"} eq "no"; }
+if ( $config_tokens{"icons-email-visible"} eq "disabled" ) { $config_tokens{"icons-email-visible"} eq "no"; }
+if ( $config_tokens{"icons-phonebook-visible"} eq "disabled" ) { $config_tokens{"icons-phonebook-visible"} eq "no"; }
+if ( $config_tokens{"icons-locator-visible"} eq "disabled" ) { $config_tokens{"icons-locator-visible"} = "no"; }
+
+}
+
+##########################################
+#
+# See location this function is called from for comments on purpose.
+#
+##########################################
+
+sub print_single_div_html()
+{
+
+print "\n<DIV id=\"test\" onMouseOver=\"OverLayer();\" onMouseOut=\"OutLayer();\" style=\"LEFT:0px;POSITION:absolute;TOP:0px;VISIBILITY:visible;Z-INDEX:0\">";
+print "</DIV>";
+
+print "\n\n";
+
+}
+
+##########################################
+#
+# See location this function is called from for comments on purpose.
+#
+##########################################
+
+sub nav4_specific_event_handlers()
+{
+ print "<script type=\"text/javascript\">\n";
+ print "\n";
+ print "if ( NN4 ) \n";
+ print "{\n";
+ print " document.layers['test'].onmouseover=OverLayer; \n";
+ print " document.layers['test'].onmouseout=OutLayer; \n";
+ print "}\n";
+ print "</script>\n\n";
+}
+
+##########################################
+#
+# See location this function is called from for comments on purpose.
+#
+##########################################
+
+sub config_ldap_return_attrib_list()
+{
+
+ @return_attribs = ("businesscategory", "cn", "dn", "mail", "$config_tokens{'attrib-manager'}", "objectclass", "ou", "telephonenumber", "$config_tokens{'attrib-job-title'}", "uid");
+
+
+ $found = 0;
+ foreach $f (@return_attribs)
+ {
+ if ( $f eq $config_tokens{'attrib-farleft-rdn'} )
+ {
+ $found = 1;
+ }
+ }
+ if ( $found == 0 )
+ {
+ #
+ # If the RDN attribute name defined in config.txt is not already
+ # listed in the above @return_attribs array, then we need to add
+ # it to the array, so that we get the value back from searches.
+ #
+ push @return_attribs, $config_tokens{'attrib-farleft-rdn'};
+ }
+
+
+
+ #
+ # It is really expensive currently, per design of the AIM Presence plugin
+ # in DS 6.0x, to ask LDAP for AIM status, so let's only request this for each
+ # and every user in the org chart if we absolutely have to (per MyOrgChart
+ # preferences having AIM icons turned on)
+ #
+ if ( $config_tokens{"icons-aim-visible"} ne "no" )
+ {
+ push @return_attribs, "nsAIMStatusText";
+ push @return_attribs, "nsaimid";
+ }
+}
+
+##########################################
+#
+# See location this function is called from for comments on purpose.
+#
+##########################################
+
+sub search_for_enduser_query()
+{
+ #
+ # Check that filter contains only allowed characters by comparing to
+ # allowed-filter-chars in config.txt.
+
+ $allowedlist = $config_tokens{"allowed-filter-chars"};
+ for($i=0; $i < length($uid); $i++) {
+ if(substr($uid,$i,1) !~ /[$allowedlist]/) {
+ &output_html_header("no-javascript");
+ print "<BR><BR>\"";
+ print substr($uid,$i,1) . "\" is not allowed in search filters.<BR><BR>";
+ print "Please modify your search and try again.<BR>";
+ print "\n</BODY></HTML>";
+ exit (0);
+ }
+ }
+
+ #
+ # Get the full user entry of the uid entered by the end-user
+ #
+ # ...so if end user enters "steveh", then the below $search = "uid=steveh"
+
+ $search = "$config_tokens{'attrib-farleft-rdn'}=" . $uid;
+
+ $conn = new Mozilla::LDAP::Conn($config_tokens{"ldap-host"}, $config_tokens{"ldap-port"}, $config_tokens{"ldap-bind-dn"}, $config_tokens{"ldap-bind-pass"});
+ die "Couldn't connect to LDAP server $config_tokens{\"ldap-host\"}" unless $conn;
+ $entry = $conn->search($config_tokens{"ldap-search-base"}, "subtree", $search, 0 , @return_attribs);
+
+ #
+ # If no entries found for the above exact UID match, before we
+ # broaden the search filter to help the user out, let's first check how
+ # many characters they submitted as compared to the "min-chars-searchstring"
+ # setting in config.txt, to avoid potential heavy loads on the LDAP server.
+
+ if (! $entry)
+ {
+ if ( length($uid) < $config_tokens{"min-chars-searchstring"} )
+ {
+ &output_html_header("no-javascript");
+ print "<BR><BR>I did not find an exact userid match for what you entered.<BR><BR>";
+ print "Please enter at least $config_tokens{\"min-chars-searchstring\"} characters to broaden the search more.<BR>";
+ print "\n</BODY></HTML>";
+ exit (0);
+ }
+ }
+
+ # if (no entries found), let's try broading the search, to give them some
+ # search results to pick from (I guess they did not enter an exact uid)
+ #
+ if (! $entry)
+ {
+ $uid =~ tr/ /*/;
+
+ $search = "(|(cn=*$uid*)(mail=*$uid*))";
+
+ $conn = new Mozilla::LDAP::Conn($config_tokens{"ldap-host"}, $config_tokens{"ldap-port"}, $config_tokens{"ldap-bind-dn"}, $config_tokens{"ldap-bind-pass"});
+ die "Couldn't connect to LDAP server $config_tokens{\"ldap-host\"}" unless $conn;
+ $entry = $conn->search($config_tokens{"ldap-search-base"}, "subtree", $search, 0, @return_attribs);
+
+ $anothertempnum = 0;
+ while ($entry)
+ {
+
+#print "Entry Count: ".Mozilla::LDAP::API::ldap_count_entries($conn->getLD(), $conn->getRes())."\n";
+ $results[$anothertempnum][0] = "<a href=\"org?${contextParamString}" . $config_tokens{'attrib-farleft-rdn'} . "=" . url_encode( $entry->{$config_tokens{'attrib-farleft-rdn'}}[0] ) . "\">";
+
+ $results[$anothertempnum][1] = $entry->{cn}[0];
+
+ if ( $entry->{telephonenumber}[0] ne "" )
+ {
+ $results[$anothertempnum][2] = $entry->{telephonenumber}[0];
+ }
+ else
+ {
+ $results[$anothertempnum][2] = "&nbsp";
+ }
+
+ if ( $entry->{mail}[0] ne "" )
+ {
+ if ( $entry->{mail}[0] =~ /@/ )
+ {
+ $results[$anothertempnum][3] = "<a href=\"mailto:$entry->{mail}[0]\">$entry->{mail}[0]</a>";
+ }
+ }
+ else
+ {
+ $results[$anothertempnum][3] = "&nbsp";
+ }
+
+ if ( $entry->{businesscategory}[0] ne "" )
+ {
+ $results[$anothertempnum][4] = $entry->{businesscategory}[0];
+ }
+ else
+ {
+ $results[$anothertempnum][4] = "&nbsp";
+ }
+
+
+ if ( $entry->{ou}[0] ne "" )
+ {
+ $results[$anothertempnum][5] = $entry->{ou}[0];
+ }
+ else
+ {
+ $results[$anothertempnum][5] = "&nbsp";
+ }
+
+ $lastentry = $entry;
+ $entry = $conn->nextEntry();
+ ++$anothertempnum;
+ }
+
+ if ( $anothertempnum == 0 )
+ {
+ &output_html_header("no-javascript");
+ print "<BR><BR>No search results found!<BR>";
+ }
+ elsif ( $anothertempnum == 1)
+ {
+ #
+ # If we only have one match, let's display the org chart
+ # for that person, as opposed to just showing a single search result.
+ #
+ $entry = $lastentry;
+ $uid = $entry->{$config_tokens{'attrib-farleft-rdn'}}[0];
+ }
+ else
+ {
+
+#---------------------------------------------
+#
+# Let's print the LDAP entries found, that match the string entered.
+#
+#---------------------------------------------
+
+&output_html_header("no-javascript");
+print "
+
+<br>
+<table cellspacing=\"-1\" cellpadding=\"2\" border=\"0\" width=\"100%\">
+<tr>
+<td align=\"left\" class=\"pageHeader\">Search Results: $anothertempnum users</td>
+<td align=\"right\" class=\"searchHelp\"><img src=\"../html/orgicon.gif\" width=\"16\" height=\"14\" border=\"0\"> = view organization chart</td>
+</tr>
+<tr><td>&nbsp;</td></tr>
+</table>
+<table bgcolor=\"#FFFFFF\" cellspacing=\"-1\" cellpadding=\"3\" border=\"1\" width=\"100%\">
+<tr>
+ <th align=\"left\" class=\"resultsHeader\">Name</th>
+ <th align=\"left\" class=\"resultsHeader\">Phone</th>
+ <th align=\"left\" class=\"resultsHeader\">EMail</th>
+ <th align=\"left\" class=\"resultsHeader\">Group</th>
+ <th align=\"left\" class=\"resultsHeader\">Business Category</th>
+</tr>
+";
+
+
+for ( $num = 0 ; $num < $anothertempnum ; $num++ )
+{
+
+print "
+<tr>
+ <td align=\"left\" nowrap>$results[$num][0]<img src=\"../html/orgicon.gif\" width=\"16\" height=\"14\" border=\"0\" alt=\"View Organization Chart\"></a>&nbsp;&nbsp;$results[$num][1]</td>
+ <td align=\"left\" nowrap>$results[$num][2]</td>
+ <td align=\"left\">$results[$num][3]</td>
+ <td align=\"left\">$results[$num][4]</td>
+ <td align=\"left\">$results[$num][5]</td>
+</tr>
+
+";
+
+}
+print "</table>";
+#---------------------------------------------
+
+ }
+
+ # if there was only one search result (which we purposely
+ # did not print to the browser above), then let's draw the
+ # org chart for that single search result
+ #
+ # if zero or more than one search result, let's end things
+ # here, as there isn't anything else to do, code-wise.
+ if ( $anothertempnum != 1 )
+ {
+ print "\n</BODY></HTML>";
+ exit(0);
+ }
+ }
+}
+
+##########################################
+#
+# See location this function is called from for comments on purpose.
+#
+##########################################
+
+sub print_topmost_box()
+{
+ if ( !($print_mode) )
+ {
+ # let's print the "Prepare for Printing" link if not already doing so
+ #
+ print "<font face=\"verdana, Arial, Helvetica, sans-serif\" style=\"font-size: 14px\">";
+
+ print "<a href=\"org?${contextParamString}" . $config_tokens{'attrib-farleft-rdn'} . "=" . url_encode($uid) . "&print=yes\" target=\"org_print_window\">Prepare this page for printing</A><BR>";
+ print "</font>";
+ }
+
+ print "<CENTER><table border=0><tr><td NOWRAP>";
+
+ print "<center>";
+
+ #
+ # special exception: seems like when hardcopy printing org chart from IE browser,
+ # the boxes that people are in are not printed, so by making
+ # border=1, at least you can see the box on the hardcopy version
+ #
+ if ( ( "$browser_is_msie" ) && ( $print_mode ) )
+ {
+ print "<table border=1 CELLSPACING=1 > \n";
+ }
+ else
+ {
+ print "<table border=0 CELLSPACING=1 > \n";
+ }
+
+ print "<tr>\n";
+ print "<td ALIGN=CENTER BGCOLOR=\"#000000\" NOWRAP>\n";
+ print "<table border=0 CELLSPACING=0 CELLPADDING=6 >\n";
+ print "<tr>\n";
+ print "<td BGCOLOR=\"#CCCCCC\" ALIGN=CENTER VALIGN=CENTER NOWRAP>\n";
+ print "<table cellspacing=0 border=0><tr><td NOWRAP>";
+ print "$fontstring<center>";
+
+ $tempstr = url_encode($entry->{dn});
+ $tempstr2 = url_encode($entry->{cn}[0]);
+
+ $aimid = is_aimid_in_layer ( $config_tokens{"icons-aim-visible"} , $entry->{nsAIMStatusText}[0] , $entry->{nsaimid}[0] );
+ $emailstr = is_email_in_layer ( $config_tokens{"icons-email-visible"}, $entry->{mail}[0] );
+ $pbstr = is_pb_in_layer ( $config_tokens{"icons-phonebook-visible"}, $tempstr );
+ $locatorstr = is_locator_in_layer ( $config_tokens{"icons-locator-visible"}, $tempstr2 );
+
+ if ( !($print_mode) )
+ {
+ print "\n\n <A HREF='javascript:return false;' target=_top onMouseOver=\"showLayer('$tempstr2','$entry->{$config_tokens{\"attrib-job-title\"}}[0]','$emailstr','$pbstr','$locatorstr','$aimid');\" onMouseOut=\"OutLayer();\">";
+ print "<img src=\"../html/arrow.gif\" border=0 align=TEXTTOP>";
+ print "</A> \n";
+ }
+
+ print "<B>$entry->{cn}[0]</B>";
+
+ print_aim_icon_if_outside_layer( $config_tokens{"icons-aim-visible"}, $entry->{nsAIMStatusText}[0], $entry->{nsaimid}[0] );
+ print_email_icon_if_outside_layer( $config_tokens{"icons-email-visible"}, $entry->{mail}[0] );
+ print_pb_icon_if_outside_layer( $config_tokens{"icons-phonebook-visible"}, $tempstr );
+ print_locator_icon_if_outside_layer( $config_tokens{"icons-locator-visible"}, $tempstr2 );
+
+ print "<BR>\n";
+ print "$entry->{$config_tokens{\"attrib-job-title\"}}[0]<BR>\n</font>";
+
+ #
+ # Get the full name of the manager of the uid entered by the end-user
+ #
+
+ @manager= split (/,/ , $entry->{$config_tokens{'attrib-manager'}}[0]);
+ @splitagain = split (/=/, @manager[0] );
+ $manager = @splitagain[1];
+ $managerSearch = $config_tokens{'attrib-farleft-rdn'} . "=" . $manager;
+ $managerEntry = $conn->search($config_tokens{"ldap-search-base"},"subtree", $managerSearch, 0, @return_attribs);
+
+ print "$fontstring";
+ print "Manager: ";
+
+ if ($managerEntry)
+ {
+ $tempstr = url_encode($managerEntry->{dn});
+ $tempstr2 = url_encode($managerEntry->{cn}[0]);
+ $managertitle = $managerEntry->{$config_tokens{"attrib-job-title"}}[0];
+
+ $aimid = is_aimid_in_layer ( $config_tokens{"icons-aim-visible"} , $managerEntry->{nsAIMStatusText}[0] , $managerEntry->{nsaimid}[0] );
+ $emailstr = is_email_in_layer ( $config_tokens{"icons-email-visible"}, $managerEntry->{mail}[0] );
+ $pbstr = is_pb_in_layer ( $config_tokens{"icons-phonebook-visible"}, $tempstr );
+ $locatorstr = is_locator_in_layer ( $config_tokens{"icons-locator-visible"}, $tempstr2 );
+
+ if ( !($print_mode) )
+ {
+ print "\n\n <A HREF='javascript:return false;' target=_top onMouseOver=\"showLayer('$tempstr2','$managertitle','$emailstr','$pbstr','$locatorstr','$aimid');\" onMouseOut=\"OutLayer();\">";
+ print "<img src=\"../html/arrow.gif\" border=0 align=TEXTTOP>";
+ print "</A> \n";
+ }
+
+ print $managerEntry->{cn}[0];
+
+ if ( !($print_mode) )
+ {
+ print " <A HREF=org?${contextParamString}" . $config_tokens{'attrib-farleft-rdn'} . "=" . url_encode($manager) . "><img src=\"../html/orgicon.gif\" border=0 height=15 width=17 align=TEXTTOP></a>";
+ }
+
+ print_aim_icon_if_outside_layer( $config_tokens{"icons-aim-visible"}, $managerEntry->{nsAIMStatusText}[0], $managerEntry->{nsaimid}[0] );
+ print_email_icon_if_outside_layer( $config_tokens{"icons-email-visible"}, $managerEntry->{mail}[0] );
+ print_pb_icon_if_outside_layer( $config_tokens{"icons-phonebook-visible"}, $tempstr );
+ print_locator_icon_if_outside_layer( $config_tokens{"icons-locator-visible"}, $tempstr2 );
+
+ print "</font>";
+ }
+
+ if (!$managerEntry)
+ {
+ print "<B>(no manager listed)</B>";
+ }
+
+ print"</center></td> </tr> </table> </td> </tr> </table> </td> </tr> </table> <BR>";
+}
+
+##########################################
+#
+# See location this function is called from for comments on purpose.
+#
+##########################################
+
+sub print_toplevel_tree_branch()
+{
+ #
+ # Are there any leaf entries directly under top level person?
+ #
+ # If yes, then don't put them in their own boxes, but instead
+ # list them in a tree branch underneath the top level person's box.
+ #
+
+ print "\n<center><table border=0><tr><td NOWRAP>";
+ $anothertempnum = @sortedPeople;
+ for ( $tempnum = 0 ; $tempnum < $anothertempnum ; $tempnum++ )
+ {
+ $f = $sortedPeople[$tempnum][0];
+ $count = ($f =~ tr/\///);
+
+ if ( $count == 2 )
+ {
+ @tempdata = split(/\//, $f );
+ $entry = $tempdata[1];
+
+ #
+ # if we are at the end of the array, we want to avoid
+ # the else block below, because we don't want to add one
+ # more blank element to the array with the "+1", or that
+ # will make our @sortedPeople value be a fake one element higher
+ #
+ if ( $tempnum == $anothertempnum-1 )
+ {
+ $nextentry = "";
+ }
+ else
+ {
+ $info = $sortedPeople[$tempnum+1][0];
+ @tempdata = split(/\//, $info);
+ $nextentry = @tempdata[1];
+ }
+
+ if ( "$entry" ne "$nextentry" )
+ {
+ print "$fontstring";
+ print "\n<img SRC=\"../html/new-branch-first.gif\" align=TEXTTOP>";
+
+ $aimid = is_aimid_in_layer ( $config_tokens{"icons-aim-visible"} , "discover" , $sortedPeople[$tempnum][5] );
+ $emailstr = is_email_in_layer ( $config_tokens{"icons-email-visible"}, $sortedPeople[$tempnum][3] );
+ $pbstr = is_pb_in_layer ( $config_tokens{"icons-phonebook-visible"}, $sortedPeople[$tempnum][2] );
+ $locatorstr = is_locator_in_layer ( $config_tokens{"icons-locator-visible"}, $sortedPeople[$tempnum][6] );
+
+ if ( !($print_mode) )
+ {
+ print "\n\n <A HREF='javascript:return false;' target=_top onMouseOver=\"showLayer('$sortedPeople[$tempnum][6]','$sortedPeople[$tempnum][4]','$emailstr','$pbstr','$locatorstr','$aimid');\" onMouseOut=\"OutLayer();\">";
+ print "<img src=\"../html/arrow.gif\" border=0 align=TEXTTOP>";
+ print "</A> \n";
+ }
+
+ print "\n $entry ";
+
+ if ( $sortedPeople[$tempnum][7] =~ /nonleaf/ )
+ {
+ #
+ # If we are only supposed to draw one level for the org chart,
+ # and there are nonleaf entries, display org chart icon next
+ # to the person's name, to indicate they have people below them.
+ #
+ print "<a href=org?${contextParamString}" . $config_tokens{'attrib-farleft-rdn'} . "=" . url_encode($sortedPeople[$tempnum][1]) . ">";
+ print "<img src=\"../html/orgicon.gif\" border=0 height=15 width=17 align=TEXTTOP></a>";
+ }
+
+ print_aim_icon_if_outside_layer( $config_tokens{"icons-aim-visible"}, "discover", $sortedPeople[$tempnum][5] );
+ print_email_icon_if_outside_layer( $config_tokens{"icons-email-visible"}, $sortedPeople[$tempnum][3] );
+ print_pb_icon_if_outside_layer( $config_tokens{"icons-phonebook-visible"}, $sortedPeople[$tempnum][2] );
+ print_locator_icon_if_outside_layer( $config_tokens{"icons-locator-visible"}, $sortedPeople[$tempnum][6] );
+
+ print "</font><BR>\n";
+ $sortedPeople[$tempnum][0] = "--skip--";
+ }
+ }
+ }
+
+ print "\n</td></tr></table></center>\n\n";
+}
+
+##########################################
+#
+# See location this function is called from for comments on purpose.
+#
+##########################################
+
+sub pre_markup_remaining_branches()
+{
+
+ #
+ # Below let's scan the org chart entries and record
+ # some notes next to some of the entries (to be used later on
+ # in drawing the final display) on which tree branch pieces
+ # need to be rounded, which need to be draw in a special way, etc.
+ #
+ # cc1 below ("corner case 1") is the condition where the last leaf
+ # user entry under a given boxed user entry (manager entry) is at
+ # the farthest left justification/indent level.
+ #
+ # cc2 is the trickier condition, and is anything other than cc1 above.
+ # Meaning there are user entries at the end of the branch that are
+ # indented one or more times to the right, so we need to draw
+ # blank space in the areas where we indent (we cannot have lines there)
+ #
+ # Below, we iterate throught the org chart data in reverse order
+ # (reverse order to make things easiest to program, for the marking up)
+ # and we save details in the same org chart array, to help the org chart
+ # drawing code later on know what to draw when there is indenting
+ # (whether to draw lines or no lines, or combination of the two)
+ #
+
+ $inside_cc1 = "no";
+ $inside_cc2 = "no";
+ $deeper_inside_cc2 = "no";
+ $last_count = 0;
+
+ $last_manager = "";
+
+ $anothertempnum = @sortedPeople;
+ for ( $tempnum = @sortedPeople - 1 ; $tempnum >= 0 ; $tempnum-- )
+ {
+ if ( "$sortedPeople[$tempnum][0]" ne "--skip--" )
+ {
+ $f = $sortedPeople[$tempnum][0];
+ $count = ($f =~ tr/\///) - 1;
+
+ @tempdata = split(/\//, $sortedPeople[$tempnum][0] );
+ $specvalue = $tempdata[1];
+
+ if ( ( $count == 2 ) && ( "$last_manager" ne "$specvalue" ) )
+ {
+ $sortedPeople[$tempnum][8]="cc1";
+ $inside_cc1 = "yes";
+ $inside_cc2 = "no";
+ $deeper_inside_cc2 = "no";
+ }
+ else
+ {
+ if ( ( "$inside_cc1" eq "yes" ) && ( "$last_manager" ne "$specvalue" ) )
+ {
+ $inside_cc1 = "no";
+ }
+
+ }
+
+ if ( "$inside_cc1" eq "yes" )
+ {
+ if ( ( $count >= 3 ) && ( $last_count != $count ) )
+ {
+ $sortedPeople[$tempnum][8]="cc1";
+ }
+ }
+
+
+ if ( ( $count > 2 ) && ( "$last_manager" ne "$specvalue" ) )
+ {
+ $inside_cc2 = "yes";
+ $deeper_inside_cc2 = "no";
+ $inside_cc1 = "no";
+ }
+
+ if ( "$inside_cc2" eq "yes" )
+ {
+ if ( ($count == 2 ) && ( "$deeper_inside_cc2" eq "no" ) )
+ {
+ $deeper_inside_cc2 = "yes";
+ $tempstr = "rounded";
+ }
+ elsif ( ( $count >= 3 ) && ( $last_count != $count ) )
+ {
+ $tempstr = "rounded";
+ }
+ else
+ {
+ $tempstr = "tee";
+ }
+
+
+ if ( "$deeper_inside_cc2" eq "no" )
+ {
+ $sortedPeople[$tempnum][8]="cc2-bottom-$tempstr";
+ }
+ else
+ {
+ $sortedPeople[$tempnum][8]="cc2-upper-$tempstr";
+ }
+
+ }
+
+ $last_count = $count;
+ $last_manager = "$specvalue";
+ }
+ }
+}
+
+##########################################
+#
+# See location this function is called from for comments on purpose.
+#
+##########################################
+
+sub draw_remaining_branches()
+{
+
+ print "\n";
+ print "<center><table border=0 cellpadding=10><tr VALIGN=top>";
+
+ $current_indent = 1;
+ $one_time_td = 0;
+
+ $maxitems = @sortedPeople;
+
+ for ( $tempnum = 0 ; $tempnum < $maxitems ; $tempnum++ )
+ {
+ if ( "$sortedPeople[$tempnum][0]" ne "--skip--" )
+ {
+ $count = ($sortedPeople[$tempnum][0] =~ tr/\///) - 1;
+
+ while ( $count > $current_indent )
+ {
+ $current_indent = $current_indent + 1;
+ }
+
+ while ( $count < $current_indent )
+ {
+ $current_indent = $current_indent - 1;
+ }
+
+ @tempdata = split(/\//, $sortedPeople[$tempnum][0] );
+
+ if ( $current_indent == 1 )
+ {
+ if ( $one_time_td == 0 )
+ {
+ print "<TD NOWRAP>\n";
+ $one_time_td = 1;
+ }
+ else
+ {
+ print "</TD><TD NOWRAP>\n";
+ }
+ }
+
+
+ if ( $current_indent == 1 )
+ {
+ # special exception: seems like when printing org chart from IE browser,
+ # the boxes that people are in are not printed, so by making
+ # border=1, at least you can see the box on the hardcopy version
+ #
+ if ( ( "$browser_is_msie" ) && ( $print_mode ) )
+ {
+ print "<table border=1 CELLSPACING=1 > \n";
+ }
+ else
+ {
+ print "<table border=0 CELLSPACING=1 > \n";
+ }
+
+ print "<tr>\n";
+ print "<td ALIGN=CENTER BGCOLOR=\"#000000\">\n";
+ print "<table border=0 CELLSPACING=0 CELLPADDING=6 >\n";
+ print "<tr>\n";
+ print "<td BGCOLOR=\"#CCCCCC\" ALIGN=CENTER VALIGN=CENTER>\n";
+ print "<table cellspacing=0 border=0><tr><td NOWRAP><CENTER>";
+
+ #
+ # See comment just a few lines below about being careful on
+ # not moving this font tag past the IMG SRC tags
+ #
+ print "$fontstring";
+ }
+ else
+ {
+ #
+ # Be careful on moving this font tag after the below IMG SRC
+ # tags for drawing branch pieces ---> to have the branch pieces
+ # stay connected on Netscape 6.x, the open FONT tag needs to be
+ # BEFORE the IMG SRC tags for the branch pieces....
+ #
+ print "$fontstring";
+
+ if ( $sortedPeople[$tempnum][8] =~ /^cc2-bottom/ )
+ {
+ for ( $anothertempnum = 0 ; $anothertempnum < $current_indent - 2 ; $anothertempnum++ )
+ {
+ print "<img SRC=\"../html/new-branch-blank.gif\" align=TEXTTOP>";
+ }
+ }
+ else
+ {
+ for ( $anothertempnum = 0 ; $anothertempnum < $current_indent - 2 ; $anothertempnum++ )
+ {
+ print "<img SRC=\"../html/new-branch-straight.gif\" align=TEXTTOP>";
+ }
+ }
+
+
+ if ( ("$sortedPeople[$tempnum][8]" eq "cc1") || ( $sortedPeople[$tempnum][8] =~ /rounded/ ) )
+ {
+ print "<img SRC=\"../html/branch-cc1.gif\" align=TEXTTOP>";
+ }
+ else
+ {
+ print "<img SRC=\"../html/new-branch-first.gif\" align=TEXTTOP>";
+ }
+ }
+
+
+ $aimid = is_aimid_in_layer ( $config_tokens{"icons-aim-visible"} , "discover" , $sortedPeople[$tempnum][5] );
+ $emailstr = is_email_in_layer ( $config_tokens{"icons-email-visible"}, $sortedPeople[$tempnum][3] );
+ $pbstr = is_pb_in_layer ( $config_tokens{"icons-phonebook-visible"}, $sortedPeople[$tempnum][2] );
+ $locatorstr = is_locator_in_layer ( $config_tokens{"icons-locator-visible"}, $sortedPeople[$tempnum][6] );
+
+ if ( !($print_mode) )
+ {
+ print "\n\n <A HREF='javascript:return false;' target=_top onMouseOver=\"showLayer('$sortedPeople[$tempnum][6]','$sortedPeople[$tempnum][4]','$emailstr','$pbstr','$locatorstr','$aimid');\" onMouseOut=\"OutLayer();\">";
+ print "<img src=\"../html/arrow.gif\" border=0 align=TEXTTOP>";
+ print "</A> \n";
+ }
+
+ print "$tempdata[@tempdata-1] \n";
+
+ #
+ # If they are a nonleaf entry based on the next person being below them, or if they
+ # are a nonleaf person based on "nonleaf" value which happens when max depth is exceeded
+ # such that all people below them were chopped off (were on the next level that was chopped
+ # off, hence why we needed to previously record "nonleaf" before the chop happened)
+ #
+ # then print the org chart icon
+ #
+ if ( ( $sortedPeople[$tempnum+1][0] =~ /$tempdata[@tempdata-1]/ ) || ( $sortedPeople[$tempnum][7] =~ /nonleaf/ ) )
+ {
+ if ( ($print_mode) && ($current_indent == 1 ) )
+ {
+ # special exception #1 of 2:
+ # if we are in "prepare this page for printing" mode, and drawing a user in
+ # a box, then let's not print the org icon next to their name ---> not needed
+ # in the hardcopy printout (not helpful)
+ }
+ else
+ {
+ if ( ($print_mode) && ( $sortedPeople[$tempnum+1][0] =~ /$tempdata[@tempdata-1]/ ) )
+ {
+ # special exception #2 of 2: if we are preparing this org chart for printing,
+ # and if the org icon we are about to draw is for a group of people that are
+ # already being printed on this same org chart under that person, there is
+ # no point in hardcopy printing this icon next to the person's name
+ #
+ # but in the "else" block below, we do want to print the icon next to their name
+ # (both for print and non-print org charts) because it signifies people underneath
+ # that person when we CANNOT/WON'T see those people listed under that person
+ }
+ else
+ {
+ if ( !( $sortedPeople[$tempnum+1][0] =~ /$tempdata[@tempdata-1]\/$/ ) )
+ {
+ print "<a href=org?${contextParamString}" . $config_tokens{'attrib-farleft-rdn'} . "=" . url_encode($sortedPeople[$tempnum][1]) . ">";
+ print "<img src=\"../html/orgicon.gif\" border=0 height=15 width=17 align=TEXTTOP></a>";
+ }
+ }
+ }
+ }
+
+
+ print_aim_icon_if_outside_layer( $config_tokens{"icons-aim-visible"}, "discover", $sortedPeople[$tempnum][5] );
+ print_email_icon_if_outside_layer( $config_tokens{"icons-email-visible"}, $sortedPeople[$tempnum][3] );
+ print_pb_icon_if_outside_layer( $config_tokens{"icons-phonebook-visible"}, $sortedPeople[$tempnum][2] );
+ print_locator_icon_if_outside_layer( $config_tokens{"icons-locator-visible"}, $sortedPeople[$tempnum][6] );
+
+ #
+ # if the person's name is being printed within a box,
+ # then also print their title below their name
+ #
+ if ( $current_indent == 1 )
+ {
+
+ print "<BR>$sortedPeople[$tempnum][4]";
+ }
+
+ print "</font>";
+
+ if ( $current_indent == 1 )
+ {
+ print" </CENTER></td></tr> </table> </td> </tr> </table> </td> </tr> </table> ";
+ }
+
+ print "<BR>";
+
+ }
+ }
+
+}
+
+##########################################
+#
+# If they exceeded max depth allowed, let's still figure out
+# which people are managers of some type and make sure we
+# still put an org chart icon next to their name, so that the
+# user can tell that there is extra org chart branches that were
+# chopped off.
+#
+# We do this by over-filling the array of the org chart structure,
+# and then make sure that when we chop off the extra level below,
+# we record for the manager-types that have now chopped-off people
+# that they are a non-leaf item (which needs an org chart icon next
+# to their name
+#
+##########################################
+
+sub detect_nonleaf_depth_exceeded()
+{
+
+ if ( $incomplete == 1 )
+ {
+ $indelete = 0;
+ $anothertempnum = @sortedPeople;
+ for ( $tempnum = $anothertempnum-1 ; $tempnum >= 0 ; $tempnum-- )
+ {
+ # number of levels in current array element
+ #
+ $num = ($sortedPeople[$tempnum][0] =~ tr/\//\//) - 1;
+
+ if ( $num > $config_tokens{"max-levels-drawn"} )
+ {
+ splice(@sortedPeople,$tempnum,1);
+ $indelete = 1;
+ # $total is the total number of people we read in from LDAP
+ # as reporting to the person entered. But now that we are
+ # chopping people off that exceed the max depth, we better
+ # adjust the $total accordingly as well, or else the
+ # "Total Reports: XXX" summary info at bottom of org chart
+ # will be too high/inaccurate.
+ #
+ --$total;
+ }
+ else
+ {
+ if ( $indelete == 1 )
+ {
+ $indelete = 0;
+ $sortedPeople[$tempnum][7] = "nonleaf";
+ }
+ else
+ {
+ $sortedPeople[$tempnum][7] = "leaf";
+ }
+ }
+ }
+ }
+
+}
+
+##########################################
+#
+# See location this function is called from for comments on purpose.
+#
+##########################################
+
+sub output_html_header()
+{
+ my ($js_output) = @_;
+
+ print "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Transitional//EN\">\n";
+ print "<HTML>\n";
+ print "<HEAD>\n";
+ print " <title>Netscape Directory Server Org Chart</title>\n";
+
+ if ( $js_output ne "with-javascript" )
+ {
+ print " <LINK REL=stylesheet TYPE=\"text/css\" HREF=\"../html/styles.css\">\n";
+ }
+ if ( $js_output eq "with-javascript" )
+ {
+ &print_javascript();
+ }
+
+ print "</HEAD>\n";
+ print "<BODY BGCOLOR=\"#FFFFFF\">\n";
+
+}
+
+#=== end ===================================================================
+
+
diff --git a/ldap/clients/orgchart/orgicon.gif b/ldap/clients/orgchart/orgicon.gif
new file mode 100644
index 00000000..84ff0bd0
--- /dev/null
+++ b/ldap/clients/orgchart/orgicon.gif
Binary files differ
diff --git a/ldap/clients/orgchart/starthelp.gif b/ldap/clients/orgchart/starthelp.gif
new file mode 100644
index 00000000..9ce3eeca
--- /dev/null
+++ b/ldap/clients/orgchart/starthelp.gif
Binary files differ
diff --git a/ldap/clients/orgchart/styles.css b/ldap/clients/orgchart/styles.css
new file mode 100644
index 00000000..37b683e6
--- /dev/null
+++ b/ldap/clients/orgchart/styles.css
@@ -0,0 +1,146 @@
+/* ======================================================================= *
+ * Style sheet for the Netscape Directory Server Org Chart application *
+ * ======================================================================= */
+
+.bgColor7 {background-color: #66ccff;}
+
+/* All Links */
+
+A:link { font-family: verdana, Arial, Helvetica, sans-serif; font-size: 12px}
+A:active { color: #FF0000;}
+
+
+
+/*All Regular Table Data--for the whole application*/
+
+td {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align : middle;
+}
+
+td.bold {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align : middle;
+ font-weight: bold;
+}
+
+
+/* *********Start Page Text*************/
+td.startPage {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ color:#003366;
+ vertical-align : middle;
+}
+
+A.searchlinknorm:link {color: #CCFFFF}
+A.searchlinknorm:visited {color: #CCFFFF}
+A.searchlinknorm:active {color: #CCFFFF}
+
+A.searchlinkspec:link {color: #FF0000}
+A.searchlinkspec:visited {color: #FF0000}
+A.searchlinkspec:active {color: #CCFFFF}
+
+
+/* *********Search frame*************/
+
+body.Search {
+ background-color: #003366;
+ font-family: Verdana, Arial, Helvetica, san-serif;
+ color: #ccffff;
+ font-size: 12px;
+}
+
+td.appName {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align : middle;
+ color: #ccffff;
+ font-weight: bold;
+}
+
+.apptext {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ vertical-align: middle;
+ color: #ccffff;
+}
+
+/* *********Search results frame*************/
+
+th.resultsHeader {
+ font-family: Verdana, Arial, Helvetica, san-serif;
+ color: #003366;
+ background-color: #CCCCCC;
+ font-size: 13px;
+}
+
+td.pageHeader {
+ font-family: Verdana, Arial, Helvetica, san-serif;
+ color: #003366;
+ font-size: 14px;
+ font-weight : bold;
+}
+
+td.searchHelp {
+ font-family: Verdana, Arial, Helvetica, san-serif;
+ color: #003366;
+ font-size: 12px;
+}
+
+/* *********Org Chart frame*************/
+
+td.hidden {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 19px;
+ vertical-align : top;
+}
+
+tr.hidden {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 19px;
+ vertical-align : top;
+}
+
+td.selected {
+/* background-color: transparent; */
+ color: #000000;
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ font-weight : bold;
+}
+
+body.orgWindow {
+/* background-color: transparent; */
+ font-family: Verdana, Arial, Helvetica, san-serif;
+ color: #003366;
+ font-size: 12px;
+}
+
+.thinline {
+ font-size : 5px;
+}
+
+/* *********Preference "Customize View" Page*************/
+td.prefsPageHead {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 13px;
+ color:#003366;
+ font-weight: bold;
+ vertical-align : middle;
+ border : none;
+}
+
+td.prefsPageData {
+ font-family: verdana, Arial, Helvetica, sans-serif;
+ font-size: 12px;
+ color:#003366;
+ vertical-align : middle;
+ border : none;
+}
+
+tr.prefs{
+ border : none;
+}
diff --git a/ldap/clients/orgchart/topframe.html b/ldap/clients/orgchart/topframe.html
new file mode 100644
index 00000000..25452788
--- /dev/null
+++ b/ldap/clients/orgchart/topframe.html
@@ -0,0 +1,88 @@
+<HTML>
+<HEAD>
+<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
+<META HTTP-EQUIV="Expires" CONTENT="Thu, 01 Feb 1996 00:00:00 GMT">
+<SCRIPT LANGUAGE="javascript">
+
+// Do the Search
+
+function doSearch(searchstring)
+{
+
+ if ( searchstring == "" )
+ {
+ alert("Please enter something in the search field...");
+ return false;
+ }
+ else
+ {
+
+ if ( navigator.appName == "Microsoft Internet Explorer")
+ {
+ self.parent.output_window.location="generating.html";
+ // the below code in the else block seems to cause things
+ // not to work in internet explorer
+ }
+ else
+ {
+ totalInput = "<HTML><BODY><BR><BR><BR><BR><font face=\"verdana, Arial, Helvetica, sans-serif\" style=\"font-size: 14px\"><B>Generating...</B></font></BODY></HTML>";
+
+ viewFrame = self.parent.output_window.document;
+ viewFrame.open();
+ viewFrame.write(totalInput);
+ viewFrame.close();
+ }
+
+
+ //self.parent.output_window.location="../bin/org?data="+escape(searchstring);
+ return true;
+
+ }
+
+
+}
+
+</SCRIPT>
+<LINK REL=stylesheet TYPE="text/css" HREF="styles.css">
+</HEAD>
+
+
+<BODY class="Search" onLoad="self.parent.input_window.focus(); document.form2.data.focus();">
+
+
+<CENTER>
+<TABLE BORDER="0" width="100%" cellpadding=0 cellspacing=0>
+
+<TR>
+<TD ALIGN=LEFT VALIGN=CENTER class="appName" nowrap>&nbsp;Netscape Directory Server Org Chart</TD>
+<TD ALIGN=LEFT VALIGN=CENTER width="75%">
+ <TABLE BORDER=0>
+ <TR><TD nowrap VALIGN=CENTER ALIGN=CENTER>
+ <span class="apptext">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Search for:</span>
+ </TD>
+ <TD nowrap VALIGN=CENTER>
+ <span class="apptext">
+ <FORM name="form2" Method=POST action="../bin/org" target="output_window" onsubmit="return doSearch(document.form2.data.value)">
+ <font face=\"verdana, Arial, Helvetica, sans-serif\" style=\"font-size: 12px\">
+ <INPUT TYPE="TEXT" NAME="data" SIZE=20 MAXLENGTH=20>
+ <input type="submit" name="Submit" value="Go">
+ </font>
+ </span>
+ </TD>
+ </FORM>
+ </TR></TABLE>
+ </TD>
+ <TD ALIGN=RIGHT>
+ <a href="../bin/myorg" target="output_window" class="searchlinknorm">Customize</a>
+ </TD>
+<TD ALIGN=RIGHT VALIGN=CENTER>&nbsp;&nbsp;<IMG SRC="nslogo.gif"></TD>
+
+</TR>
+</TABLE>
+</CENTER>
+
+
+
+
+</BODY>
+</HTML>
diff --git a/ldap/clients/orgchart/wrapper.c b/ldap/clients/orgchart/wrapper.c
new file mode 100644
index 00000000..1cead680
--- /dev/null
+++ b/ldap/clients/orgchart/wrapper.c
@@ -0,0 +1,89 @@
+/***********************************************************************
+** Copyright 1996 - Netscape Communications Corporation
+**
+** Contact: Fred Cox <flc@netscape.com>
+**
+** Name: perl.c
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+#include <stdlib.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+/*#include "libadmin/libadmin.h"*/
+
+#ifdef XP_UNIX
+#include <unistd.h>
+#define PERL "../../bin/slapd/admin/bin/perl"
+#define PATH_SEP '/'
+#ifndef PATH_MAX
+#define PATH_MAX 512
+#endif
+#else
+#include <direct.h>
+#include <process.h>
+#define PERL "..\\..\\bin\\slapd\\admin\\bin\\perl.exe"
+#define PATH_SEP '\\'
+#define PATH_MAX 512
+#endif
+
+char *get_perl_file(char *);
+
+
+/*
+ * Use environment to figure out what admin perl script to execute
+ */
+
+void
+main( int argc, char **argv )
+{
+ char script[PATH_MAX];
+ struct stat statbuf;
+
+ printf("Content-type:text/html;charset=UTF-8\n\n<html>Hi\n");
+
+ get_perl_file(script);
+
+ if (strchr(script, '/') != NULL || strchr(script, '\\') != NULL) {
+ printf("Paths not allowed. Filenames only.\n");
+ exit(0);
+ }
+
+ printf("<br>script:%s</html>\n", script);
+ if (stat(script, &statbuf) != 0) {
+ printf("Can't find %s\n", script);
+ exit(0);
+ }
+
+ execl( PERL, script, script, 0 );
+}
+
+char *
+get_perl_file(char *script) {
+ char *qs = getenv("QUERY_STRING");
+ char *p1 = NULL;
+ char *p2 = NULL;
+
+ if (qs == NULL || *qs == '\0') {
+ printf("No QUERY_STRING found\n");
+ exit(0);
+ }
+ p1 = strstr(qs, "file=");
+ if (p1 == NULL) {
+ printf("No file variable in QUERY_STRING found.\n");
+ exit(0);
+ }
+
+ p1 += 5;
+
+ for (p2 = p1; *p2 != '\0' && *p2 != '&'; p2++);
+
+ strncpy(script, p1, p2-p1);
+ script[p2-p1] = '\0';
+}
diff --git a/ldap/cm/Makefile b/ldap/cm/Makefile
new file mode 100644
index 00000000..057569a0
--- /dev/null
+++ b/ldap/cm/Makefile
@@ -0,0 +1,938 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Makefile to Create packages for Directory Server and LDAP SDK
+#
+
+default help :
+ @echo "The following targets are available:"
+ @echo ""
+ @echo " releaseDirectory"
+ @echo " packageDirectory"
+
+ @echo ""
+
+
+MCOM_ROOT=../../..
+TREE_ROOT=$(MCOM_ROOT)
+
+# make sure we pull the admin server component here
+ADMSERV_DEPS = 1
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(MCOM_ROOT)/ldapserver/ldap/nsldap.mk
+include $(MCOM_ROOT)/ldapserver/ldap/javarules.mk
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+include $(MCOM_ROOT)/ldapserver/ns_usesh.mk
+
+NSDISTMODE = copy
+
+ifneq ($(ARCH), WINNT)
+# tar must support the -h flag to follow symlinks and not copy them
+TAR=tar
+endif
+
+MMDD = $(shell date +%m.%d)
+
+# we don't want to build with warnings-as-errors for the cm/ stuff, because
+# it's 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
+
+# Absolute path to .ldap/cm is needed for AIX packaging. Due to NFS problems on AIX 4.2.1
+# the build script RSH's to cindercone but it tries to cd to $(RELDIR) which is relative
+# to the CWD of this Makefile in current build environment. So, the cd to RELDIR fails
+# since the RSH set the new CWD to /u/svbld. By determining its location in the tree then
+# cd'ing to same location on cindercone the cd to RELDIR finds the correct "release" directory.
+# This hack can go away when we use a version of AIX that fixes the NFS problem(s). (tfox)
+TMP_CM_PWD := $(shell pwd)
+LDAP_CM_ABS_PATH := $(TMP_CM_PWD:/tmp_mnt/%=/%) # AIX prefixes /tmp_mnt to path.
+
+ifneq ($(ARCH), WINNT)
+RELTOOLS=$(MCOM_ROOT)/../reltools/ftpname_new.pl
+SUF=-suf .tar
+SUFEXE=-suf .tar.gz
+BACKGROUND=&
+else
+RELTOOLSDIR=$(shell pwd)/../../../reltools
+NT_RELTOOLS=$(RELTOOLSDIR)
+RELTOOLS=perl $(RELTOOLSDIR)/ftpname.pl
+SUF=-suf .zip
+SUFEXE=-suf .exe
+ifdef BUILD_SHIP
+ifndef BuildDir
+HOST=$(shell hostname)
+BuildDir=$(shell cd $(RELTOOLSDIR);perl getdefaults -var BuildDir -if $(RELTOOLSDIR)/init/directory/directory5.init -machine $(HOST))
+endif
+endif
+endif
+
+ifdef USE_64
+VERSION=-ver 7.0-64bit
+else
+VERSION=-ver 7.0
+endif
+
+ifeq ($(ARCH), HPUX)
+RSH=remsh
+REMSH=$(RSH) anuurn -l root
+else
+RSH=rsh
+REMSH=$(RSH) anuurn -l root
+endif
+
+
+ifdef PRODUCT_MARKET
+ifeq ($(PRODUCT_MARKET), JA)
+INTL=-intl ja
+INTL_INSTALL=-DJA=1
+endif
+ifeq ($(PRODUCT_MARKET), EU)
+INTL=-intl eu
+endif
+else
+INTL=-intl us
+endif
+
+ifeq ($(BUILD_SECURITY), domestic)
+SEC=-sec domestic
+ifdef FORTEZZA
+SEC=-sec fortezza
+endif
+else
+SEC=-sec export
+endif
+
+ifneq ($(DEBUG), optimize)
+DBG=-debug full
+else
+DBG=-debug optimize
+endif
+
+FTPNAME = $(shell $(RELTOOLS) -name directory $(VERSION) $(INTL) $(SEC) $(DBG) $(SUF))
+FTPNAMEGZ = $(shell $(RELTOOLS) -name directory $(VERSION) $(INTL) $(SEC) $(DBG) $(SUFEXE) )
+
+
+# regular NT
+
+ifeq ($(ARCH), WINNT)
+
+INSTALL = nsinstall -t
+PLAT_ID = 32
+CONVERTER = cp
+DOTTXT = .txt
+
+# NT Alpha
+
+ifeq ($(PROCESSOR_ARCHITECTURE), ALPHA)
+PLAT_ID = 64
+endif
+
+else
+INSTALL = $(OBJDIR)/nsinstall -t
+CONVERTER = cp
+endif
+
+PROD_ID = dk
+
+ifeq ($(DEBUG), optimize)
+STRIP = strip
+BLDTYPE_ID =
+else
+STRIP = true
+BLDTYPE_ID = d
+endif
+
+DOTDLL = .$(DLL_SUFFIX)
+DOTLIB = .$(LIB_SUFFIX)
+
+ifeq ($(ARCH), WINNT)
+DOTEXE = .exe
+PACKAGE_STAGE_DIR=$(OBJDIR)/package
+endif
+
+SHARETOP = $(COMPONENTS_DIR)/ldapsdk
+BUILD_DATE = $(shell date +%Y%m%d)
+SHAREDIR = $(SHARETOP)/$(BUILD_DATE)/$(NC_BUILD_FLAVOR)
+#ADM_VERSDIR = admserv40
+#ADM_RELDATE = untested/19980119
+IMPORTADMINSRV = $(IMPORTADMINSRV_BASE)/$(NSOBJDIR_NAME_32)
+IMPORTADMINSRVNOTAR = $(COMPONENTS_DIR)/$(ADM_VERSDIR)/$(ADM_VERSION)/untar/$(NSOBJDIR_NAME)
+# these are files and directories in the import adminsrv directory which we don't
+# make a local copy of, we just import directly into the tar file or create a
+# symlink to
+ADMIN_IMPORTS=setup base admin svrcore silent.inf LICENSE.txt README.txt
+ADMIN_SERVER_TARGZ=admserv.tar.gz
+ADMIN_IMPORTS_TARGZ=$(ADMIN_SERVER_TARGZ)
+
+# Release directory for ldapsdk
+RELSDK = $(MCOM_DRIVE)$(RELTOP)/ldapsdk/$(OBJDIR_BASE)
+RELJDK = $(MCOM_DRIVE)$(RELTOP)/ldapjdk
+
+# these are files we need to put in the command line/console only package
+#LDAPSDK_IMPORTS=ldapsearch ldapdelete ldapmodify
+
+# perl script to add the slapd information to the base installer
+# setup information file
+FIX_SETUP_INF = $(MCOM_ROOT)/ldapserver/ldap/cm/fixSetupInf.pl
+FIX_BASE_INF = $(MCOM_ROOT)/ldapserver/ldap/cm/fixBaseInf.pl
+
+ifndef INSTDIR
+ifeq ($(ARCH), WINNT)
+INSTDIR = $(TREE_ROOT)/$(MMDD)
+else
+INSTDIR = $(MCOM_DRIVE)$(MCOM_ROOT)/$(MMDD)
+ABS_INSTDIR = $(ABS_ROOT)/$(MMDD)
+endif
+endif
+# This is the directory where we put what we're making: the files which go on the CD.
+INST_TARGET=$(INSTDIR)/$(NS_BUILD_FLAVOR)
+INST_TARGET_RESKIT=$(INSTDIR)/$(NS_BUILD_FLAVOR)/reskit
+INST_TARGET_INTL=./$(PRODUCT_MARKET)dir
+
+LDAPDIR = $(MCOM_ROOT)/ldapserver/ldap
+
+NSDIST = $(MCOM_ROOT)/dist
+
+DS_JAR_SRC_PATH = $(NSDIST)/$(BUILD_DEBUG)
+DS_JAR_DEST_PATH = java/jars
+DS_JAR_FILE = ds70.jar
+DS_JAR_LANG_FILE = ds70_en.jar
+XMLTOOLS_JAR_FILE = xmltools.jar
+
+UNZIP=unzip -o
+UNZIPNOPATHS=$(UNZIP) -j
+ZIP=zip
+ZIP_FLAGS=-r -T
+EXCLUDED_FILES=-x lib/aolsnauth-plugin.*
+# Linux Zip has problems zipping gif file over NFS (??)
+ifeq ($(ARCH), Linux)
+ZIP_FLAGS=-r -T -n .gif
+endif
+
+ifeq ($(USE_64), 1)
+MAKEARCH=$(ARCH)64
+else
+MAKEARCH=$(ARCH)
+endif
+
+PACKAGE_SETUP_LIBS_32=$(subst $(NS64TAG),,$(PACKAGE_SETUP_LIBS))
+
+# Borland libraries are build on NT only
+
+dummy:
+ -@echo SITEHACK = $(SITEHACK)
+ -@echo PACKAGE_SRC_DEST = $(PACKAGE_SRC_DEST)
+
+importAdmin:
+
+releaseDirectory:
+# LIBS_TO_PKG is defined in components.mk - these are component files (not directories) to install
+# with the other component files that we don't necessarily pick up from the admin server build
+# see below for windows packaging
+ifneq ($(ARCH), WINNT)
+ for file in $(LIBS_TO_PKG) ; \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(RELDIR)/bin/slapd/lib ; \
+ fi ; \
+ done
+# these are files to copy to the shared/bin directory - ldap cmd line tools, sec tools, etc.
+ for file in $(BINS_TO_PKG_SHARED); \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(RELDIR)/shared/bin ; \
+ fi ; \
+ done
+# these are files to copy to the shared/lib directory - ldap cmd line tools, sec tools, etc.
+ for file in $(LIBS_TO_PKG_SHARED); \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(RELDIR)/shared/lib ; \
+ fi ; \
+ done
+# these are libs to copy to clients/lib on unix to support dsgw & pb
+ for file in $(LIBS_TO_PKG_CLIENTS); \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(RELDIR)/clients/lib ; \
+ fi ; \
+ done
+endif
+
+# PACKAGE_SRC_DEST is defined in components.mk - these are component files and directories to install
+# with the other component files that we don't necessarily pick up from the admin server build
+# these can go in any directory
+ -@for dest in $(PACKAGE_SRC_DEST) ; \
+ do if [ "$$src" ] ; \
+ then if [ ! -d $(RELDIR)/$$dest ] ; then mkdir -p $(RELDIR)/$$dest ; fi ; \
+ if [ -d $$src ] ; \
+ then bs=`basename $$src` ; \
+ if [ -d $(RELDIR)/$$dest/$$bs ] ; then rm -rf $(RELDIR)/$$dest/$$bs ; fi ; \
+ cp -r $$src $(RELDIR)/$$dest ; \
+ else $(INSTALL) -m 755 $$src $(RELDIR)/$$dest ; \
+ fi ; \
+ src= ; \
+ else src=$$dest ; \
+ fi ; \
+ done
+
+# install the DSMLGW into the client directory
+ $(MKDIR) $(RELDIR)/clients/dsmlgw
+ $(CP) -R $(NSDIST)/classes/$(AXIS_REL_DIR)/webapps/axis/* $(RELDIR)/clients/dsmlgw/
+
+ $(INSTALL) -m 644 $(NSDIST)/dsmlgw/dsmlgw.jar $(RELDIR)/clients/dsmlgw/WEB-INF/lib
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/dsmlgw/misc/server-config.wsdd $(RELDIR)/clients/dsmlgw/WEB-INF
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/dsmlgw/misc/web-app_2_3.dtd $(RELDIR)/clients/dsmlgw/
+
+
+# now time to move the necessary jars in place
+ $(INSTALL) -m 644 $(NSDIST)/classes/ldapjdk.jar $(RELDIR)/clients/dsmlgw/WEB-INF/lib
+ $(INSTALL) -m 644 $(NSDIST)/classes/activation.jar $(RELDIR)/clients/dsmlgw/WEB-INF/lib
+ $(INSTALL) -m 644 $(NSDIST)/classes/jaxrpc-api.jar $(RELDIR)/clients/dsmlgw/WEB-INF/lib
+ $(INSTALL) -m 644 $(NSDIST)/classes/jaxrpc.jar $(RELDIR)/clients/dsmlgw/WEB-INF/lib
+ $(INSTALL) -m 644 $(NSDIST)/classes/saaj.jar $(RELDIR)/clients/dsmlgw/WEB-INF/lib
+ $(INSTALL) -m 644 $(NSDIST)/classes/xercesImpl.jar $(RELDIR)/clients/dsmlgw/WEB-INF/lib
+ $(INSTALL) -m 644 $(NSDIST)/classes/xml-apis.jar $(RELDIR)/clients/dsmlgw/WEB-INF/lib
+
+
+# PACKAGE_UNDER_JAVA is defined in components.mk - these are component .jar files to install
+# with the other component files that we don't necessarily pick up from the admin server build
+# these go in the java/ directory
+ -@for file in $(PACKAGE_UNDER_JAVA) ; \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(RELDIR)/$(DS_JAR_DEST_PATH) ; \
+ fi ; \
+ done
+
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/ldif/*.ldif $(RELDIR)/bin/slapd/install/ldif
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/dsml/*.dsml $(RELDIR)/bin/slapd/install/dsml
+# Package online and ldaptags only if they exist: they are only built on
+# Solaris and NT but packaged on all platforms
+ if [ -d $(MCOM_DRIVE)$(MCOM_ROOT)/dist/online ] ; then \
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/dist/online/*.war $(RELDIR)/clients/slapd ; \
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/online/doc/*.html $(RELDIR)/clients/slapd ; \
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/online/ldif/*.ldif $(RELDIR)/clients/slapd ; \
+ fi
+# if [ -d $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/ldaptags ] ; then \
+# $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/ldaptags/doc/*.html $(RELDIR)/clients/slapd ; \
+# fi
+
+### Package up the orgchart ###
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/orgchart/*.gif $(RELDIR)/clients/orgchart/html
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/orgchart/*.html $(RELDIR)/clients/orgchart/html
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/orgchart/*.css $(RELDIR)/clients/orgchart/html
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/orgchart/*.tmpl $(RELDIR)/clients/orgchart
+
+ifeq ($(ARCH), WINNT)
+ $(INSTALL) -m 755 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/orgchart/*.bat $(RELDIR)/clients/orgchart/bin
+ $(INSTALL) -m 755 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/orgchart/*.pl $(RELDIR)/clients/orgchart/bin
+else
+ $(MKDIR) $(RELDIR)/clients/orgchart/bin
+ $(CP) $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/orgchart/org.pl $(RELDIR)/clients/orgchart/bin/org
+ $(CP) $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/clients/orgchart/myorg.pl $(RELDIR)/clients/orgchart/bin/myorg
+ chmod 755 $(RELDIR)/clients/orgchart/bin/org
+ chmod 755 $(RELDIR)/clients/orgchart/bin/myorg
+endif
+### end orgchart package ###
+
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/schema/*.ldif $(RELDIR)/bin/slapd/install/schema
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/schema/slapd-collations.conf $(RELDIR)/bin/slapd/install/config
+
+# libdb for windows special and smartheap
+ifeq ($(ARCH), WINNT)
+ $(INSTALL) -m 755 $(DB_LIBPATH)/$(DB_LIBNAME).$(DLL_SUFFIX) $(RELDIR)/bin/slapd/server
+#Install smartheap dll in the server binary directory
+ifeq ($(DEBUG), optimize)
+ $(INSTALL) -m 755 $(SH_LIBPATH)/shsmp.$(DLL_SUFFIX) $(RELDIR)/bin/slapd/server
+ $(INSTALL) -m 755 $(SH_LIBPATH)/shsmp.$(DLL_SUFFIX) $(RELDIR)/lib
+endif
+endif
+ifeq ($(ARCH), SOLARIS)
+ifeq ($(DEBUG), optimize)
+ifndef LDAP_DONT_USE_SMARTHEAP
+ $(INSTALL) -m 755 $(SH_LIBPATH)/libsh.$(DLL_SUFFIX) $(RELDIR)/bin/slapd/server
+ $(INSTALL) -m 755 $(OBJDIR)/lib/libsh_stub/libsh_stub.so $(RELDIR)/bin/slapd/server
+endif
+endif
+endif
+ifeq ($(ARCH), HPUX)
+ifeq ($(DEBUG), optimize)
+ifndef LDAP_DONT_USE_SMARTHEAP
+ $(INSTALL) -m 755 $(SH_LIBPATH)/libsh.$(DLL_SUFFIX) $(RELDIR)/bin/slapd/server
+endif
+endif
+endif
+
+# the plugin API
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/slapi-plugin.h $(RELDIR)/plugins/slapd/slapi/include
+ $(INSTALL) -m 644 $(NSPR_BUILD_DIR)/include/*.h $(RELDIR)/plugins/slapd/slapi/include
+ $(INSTALL) -m 644 $(NSPR_BUILD_DIR)/include/obsolete/*.h $(RELDIR)/plugins/slapd/slapi/include/obsolete
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/slapi-plugin-compat4.h $(RELDIR)/plugins/slapd/slapi/include
+# if [ -f $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/docs/plugin/README ] ; \
+# then $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/docs/plugin/README $(RELDIR)/plugins/slapd ; \
+# fi
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/test-plugins/*.c $(RELDIR)/plugins/slapd/slapi/examples
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/test-plugins/*.h $(RELDIR)/plugins/slapd/slapi/examples
+ $(INSTALL) -m 644 $(DB_INCLUDE)/db.h $(RELDIR)/plugins/slapd/slapi/examples
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/test-plugins/README $(RELDIR)/plugins/slapd/slapi/examples
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/test-plugins/clients/*.* $(RELDIR)/plugins/slapd/slapi/examples/clients
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/test-plugins/clients/README $(RELDIR)/plugins/slapd/slapi/examples/clients
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/plugins/distrib/*.c $(RELDIR)/plugins/slapd/slapi/examples/distrib
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/plugins/distrib/README $(RELDIR)/plugins/slapd/slapi/examples/distrib
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/test-plugins/Makefile.$(MAKEARCH) $(RELDIR)/plugins/slapd/slapi/examples
+ $(MV) $(RELDIR)/plugins/slapd/slapi/examples/Makefile.$(MAKEARCH) $(RELDIR)/plugins/slapd/slapi/examples/Makefile
+ $(CP) $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/plugins/distrib/Makefile.$(MAKEARCH) $(RELDIR)/plugins/slapd/slapi/examples/distrib/Makefile
+ifeq ($(ARCH), WINNT)
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/test-plugins/testplugin.mak $(RELDIR)/plugins/slapd/slapi/examples
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/test-plugins/testplugin.def $(RELDIR)/plugins/slapd/slapi/examples
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/slapd/test-plugins/testplugin.dsp $(RELDIR)/plugins/slapd/slapi/examples
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/plugins/distrib/distrib.dsp $(RELDIR)/plugins/slapd/slapi/examples/distrib
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/plugins/distrib/libdistrib.def $(RELDIR)/plugins/slapd/slapi/examples/distrib
+endif
+ifeq ($(ARCH), WINNT)
+ $(INSTALL) -m 755 $(LIBSLAPD) $(RELDIR)/plugins/slapd/slapi/lib
+ $(INSTALL) -m 755 $(NSPR_LIBPATH)/*.lib $(RELDIR)/plugins/slapd/slapi/lib
+# needed only for testdatainterop plugin in the plugins examples
+ mkdir -p $(RELDIR)/plugins/slapd/slapi/examples/lib
+ $(INSTALL) -m 755 $(DB_LIBPATH)/$(DB_LIBNAME).lib $(RELDIR)/plugins/slapd/slapi/examples/lib
+endif
+
+# the httpd library
+ifneq ($(ARCH), WINNT)
+ $(INSTALL) -m 755 $(OBJDIR)/$(NSHTTPD_DLL)$(DLL_PRESUF).$(DLL_SUFFIX)* $(RELDIR)/bin/slapd/lib
+ $(INSTALL) -m 755 $(OBJDIR)/$(NSHTTPD_DLL)$(DLL_PRESUF).$(DLL_SUFFIX)* $(RELDIR)/clients/lib
+endif
+
+# install the ds jar file in the <server root>/$(DS_JAR_DEST_PATH) directory
+# also install the other jar files we use
+ $(INSTALL) -m 644 $(DS_JAR_SRC_PATH)/$(DS_JAR_FILE) $(RELDIR)/$(DS_JAR_DEST_PATH)
+ $(INSTALL) -m 644 $(DS_JAR_SRC_PATH)/$(DS_JAR_LANG_FILE) $(RELDIR)/$(DS_JAR_DEST_PATH)
+ $(INSTALL) -m 644 $(DS_JAR_SRC_PATH)/$(XMLTOOLS_JAR_FILE) $(RELDIR)/$(DS_JAR_DEST_PATH)
+ $(INSTALL) -m 644 $(NSDIST)/classes/$(CRIMSONJAR) $(RELDIR)/$(DS_JAR_DEST_PATH)
+ $(INSTALL) -m 644 $(NSDIST)/classes/$(CRIMSON_LICENSE) $(RELDIR)/$(DS_JAR_DEST_PATH)
+
+# Images for IM Presence plugin
+ $(INSTALL) -m 644 $(MCOM_DRIVE)$(MCOM_ROOT)/ldapserver/ldap/servers/plugins/presence/images/*.gif $(RELDIR)/bin/slapd/install/presence
+
+# docs
+ if [ -d $(OBJDIR)/manual/slapd ] ; \
+ then $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/cli/*.* $(RELDIR)/manual/en/slapd/cli ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/ag/*.* $(RELDIR)/manual/en/slapd/ag ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/help/*.* $(RELDIR)/manual/en/slapd/help ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/index.map $(RELDIR)/manual/en/slapd/ ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/index.htm $(RELDIR)/manual/en/slapd/ ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/pixel.gif $(RELDIR)/manual/en/slapd/ ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/netscape48.gif $(RELDIR)/manual/en/slapd/ ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/topicindex.htm $(RELDIR)/manual/en/slapd/ ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/tokens.map $(RELDIR)/manual/en/slapd/ ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/copyright/*.* $(RELDIR)/manual/en/slapd/copyright ; \
+ fi
+ if [ -d $(OBJDIR)/manual/slapd ] ; \
+ then $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/install/*.* $(RELDIR)/manual/en/slapd/install ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/deploy/*.* $(RELDIR)/manual/en/slapd/deploy ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/dsmlgw/*.* $(RELDIR)/manual/en/slapd/dsmlgw ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/dsmlgw/graphics/*.* $(RELDIR)/manual/en/slapd/dsmlgw/graphics ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/gwcust/*.* $(RELDIR)/manual/en/slapd/gwcust ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/gwcust/graphics/*.* $(RELDIR)/manual/en/slapd/gwcust/graphics ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/schema/*.* $(RELDIR)/manual/en/slapd/schema ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/ag/graphics/*.* $(RELDIR)/manual/en/slapd/ag/graphics ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/cli/graphics/*.* $(RELDIR)/manual/en/slapd/cli/graphics ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/deploy/graphics/*.* $(RELDIR)/manual/en/slapd/deploy/graphics ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/install/graphics/*.* $(RELDIR)/manual/en/slapd/install/graphics ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/plugin/*.* $(RELDIR)/manual/en/slapd/plugin ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/plugin/graphics/*.* $(RELDIR)/manual/en/slapd/plugin/graphics ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/orgchart/*.* $(RELDIR)/manual/en/slapd/orgchart ; \
+ $(INSTALL) -m 644 $(OBJDIR)/manual/slapd/orgchart/graphics/*.* $(RELDIR)/manual/en/slapd/orgchart/graphics ; \
+ fi
+ifdef USE_PURIFY
+ -$(INSTALL) -m 755 $(DB_LIBPATH)/*.so_pure* $(RELDIR)/lib
+ -$(INSTALL) -m 755 $(NSCP_DISTDIR)/lib/*.so_pure* $(RELDIR)/lib
+ rm -f $(RELDIR)/bin/slapd/server/ns-slapd
+ mv -f $(RELDIR)/bin/slapd/server/ns-slapd.pure $(RELDIR)/bin/slapd/server/ns-slapd
+endif
+ifdef USE_QUANTIFY
+ rm -f $(RELDIR)/bin/slapd/server/ns-slapd
+ mv -f $(RELDIR)/bin/slapd/server/ns-slapd.quantify $(RELDIR)/bin/slapd/server/ns-slapd
+endif
+
+# Copy DSRK tools
+ $(INSTALL) -m 755 $(DSRK_BUILD_DIR)/perl/logconv.pl $(RELDIR)/bin/slapd/server
+ifneq ($(ARCH), WINNT)
+ $(INSTALL) -m 755 $(DSRK_BUILD_DIR)/bin/n$(DSRKCOMP_DIR)/dbscan $(RELDIR)/bin/slapd/server
+else
+ $(INSTALL) -m 755 $(DSRK_BUILD_DIR)/bin/n$(DSRKCOMP_DIR)/dbscan$(DOTEXE) $(RELDIR)/bin/slapd/server
+endif
+
+ $(INSTALL) -m 755 $(DB_BINPATH)/db_printlog* $(RELDIR)/bin/slapd/server
+ $(INSTALL) -m 755 $(DB_BINPATH)/db_verify* $(RELDIR)/bin/slapd/server
+
+ $(INSTALL) -m 755 $(OBJDIR)/lib/libsi18n/ns-slapd.properties $(RELDIR)/bin/slapd/property;
+
+# Install LDAP Readme and License files at root of SLAPD Release sub-directory.
+ifeq ($(ARCH), WINNT)
+ if [ -d $(LDAPDIR)/docs ] ; then \
+ cd $(LDAPDIR)/docs; \
+ perl $(NT_RELTOOLS)/unx2dos.plx WINNT LICENSE.txt $(RELDIR)/bin/slapd; \
+ perl $(NT_RELTOOLS)/unx2dos.plx WINNT LICENSE.txt $(RELDIR); \
+ perl $(NT_RELTOOLS)/unx2dos.plx WINNT README.txt $(RELDIR)/bin/slapd; \
+ perl $(NT_RELTOOLS)/unx2dos.plx WINNT README.txt $(RELDIR); \
+ fi
+else
+ if [ -d $(LDAPDIR)/docs ] ; then \
+ cd $(LDAPDIR)/docs; \
+ $(INSTALL) -m 755 README.txt LICENSE.txt $(RELDIR)/bin/slapd; \
+ $(INSTALL) -m 755 README.txt LICENSE.txt $(RELDIR); \
+ fi
+endif
+
+# include the old configuration files in the package so we can use them
+# for comparison purposes during migration
+ $(INSTALL) -m 444 $(LDAPDIR)/cm/v1confs/*.* $(RELDIR)/bin/slapd/install/version1
+ $(INSTALL) -m 444 $(LDAPDIR)/cm/v3confs/*.* $(RELDIR)/bin/slapd/install/version3
+ $(INSTALL) -m 444 $(LDAPDIR)/cm/v4confs/40/*.* $(RELDIR)/bin/slapd/install/version4/40
+ $(INSTALL) -m 444 $(LDAPDIR)/cm/v4confs/41/*.* $(RELDIR)/bin/slapd/install/version4/41
+ $(INSTALL) -m 444 $(LDAPDIR)/cm/v4confs/411/*.* $(RELDIR)/bin/slapd/install/version4/411
+ $(INSTALL) -m 444 $(LDAPDIR)/cm/v4confs/412/*.* $(RELDIR)/bin/slapd/install/version4/412
+
+ find $(RELDIR) -exec chmod go-w {} \;
+# $(RELDIR)/bin/slapd/server may host a core file.
+# For security reason, it's readable only by the owner
+ chmod 700 $(RELDIR)/bin/slapd/server
+
+# this is the rule to pull the Infozip utilities
+ifndef INFOZIP_PULL_METHOD
+INFOZIP_PULL_METHOD = FTP
+endif
+
+$(INSTDIR)/$(NS_BUILD_FLAVOR)/tools/infozip.zip:
+ $(RM) $@
+ $(FTP_PULL) -method $(INFOZIP_PULL_METHOD) \
+ -objdir $(dir $@) \
+ -componentdir $(COMPONENTS_DIR)/infozip/$(INFOZIP_RELDATE)/$(NSOBJDIR_NAME_32) \
+ -files infozip.zip
+ @if [ ! -f $@ ] ; \
+ then echo "Error: could not get component INFOZIP file $@" ; \
+ exit 1 ; \
+ fi
+
+# this is the rule to pull PerLDAP
+ifndef PERLDAP_PULL_METHOD
+PERLDAP_PULL_METHOD = FTP
+endif
+
+$(INSTDIR)/$(NS_BUILD_FLAVOR)/perldap/$(PERLDAP_ZIP_FILE):
+ $(RM) $@
+ $(FTP_PULL) -method $(PERLDAP_PULL_METHOD) \
+ -objdir $(dir $@) \
+ -componentdir $(PERLDAP_COMPONENT_DIR) \
+ -files $(notdir $@),perldap.inf
+ @if [ ! -f $@ ] ; \
+ then echo "Error: could not get component PERLDAP file $@" ; \
+ exit 1 ; \
+ fi
+ $(PERL) -w fixPerlDAPInf.pl $(dir $@)/perldap.inf
+
+# this is the rule to pull nsPerl
+ifndef NSPERL_PULL_METHOD
+NSPERL_PULL_METHOD = FTP
+endif
+
+$(INSTDIR)/$(NS_BUILD_FLAVOR)/nsperl/$(NSPERL_ZIP_FILE):
+ $(RM) $@
+ $(FTP_PULL) -method $(NSPERL_PULL_METHOD) \
+ -objdir $(dir $@) \
+ -componentdir $(NSPERL_COMPONENT_DIR) \
+ -files $(notdir $@),nsperl.inf
+ @if [ ! -f $@ ] ; \
+ then echo "Error: could not get component NSPERL file $@" ; \
+ exit 1 ; \
+ fi
+ $(PERL) -w fixNSPerlInf.pl $(dir $@)/nsperl.inf nsperl561
+# one more hack to nsperl - we must remove LDIF.pm because it
+# conflicts with the one in perldap - bug 600138
+# SITEHACK is defined in nsperl.mk
+ $(ZIP) -d $(dir $@)/$(NSPERL_ZIP_FILE) lib/nsPerl5.6.1/$(SITEHACK)/Mozilla/LDAP/LDIF.pm
+
+$(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd:
+ $(MKDIR) -p $@
+
+# Packaging for UNIX is totally different than NT, so we conditionally execute here
+
+ifneq ($(ARCH), WINNT)
+
+# ---THE UNIX PACKAGE---
+packageDirectory: $(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd \
+ $(INSTDIR)/$(NS_BUILD_FLAVOR)/nsperl/$(NSPERL_ZIP_FILE) \
+ $(INSTDIR)/$(NS_BUILD_FLAVOR)/perldap/$(PERLDAP_ZIP_FILE) \
+ $(INSTDIR)/$(NS_BUILD_FLAVOR)/tools/infozip.zip \
+ $(ADMSERV_DEP)
+
+# copy over the setup sdk stuff
+# hack - remove once admin server bundles setupsdk 6.02
+# cp -R $(SETUP_SDK_BUILD_DIR)/bin/* $(INSTDIR)/$(NS_BUILD_FLAVOR)
+
+# copy in our product .inf files
+ $(INSTALL) -m 755 $(OBJDIR_32)/*.inf $(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd
+
+# strip the executables in the optimized build
+ifeq ($(DEBUG), optimize)
+# purify doesn't like stripped executables
+ifndef USE_PURIFY
+ifndef USE_QUANTIFY
+ifdef SAVE_UNSTRIP
+ mkdir -p $(RELDIR_UNSTRIP)
+ cp -R $(RELDIR)/* $(RELDIR_UNSTRIP)
+endif
+ ifeq ($(SECURITY_RELDATE), NSS_3_7_9_RTM)
+ ./unixstrip $(PERL) $(RELDIR)
+ else
+ ./unixstrip $(PERL) $(RELDIR) $(SECURITY_BUILD_DIR)/bin/shlibsign $(SECURITY_BUILD_DIR)/lib:$(NSPR_BUILD_DIR)/lib
+ endif
+endif
+endif
+endif
+# create the slapd-client.zip file, which only has the ds jar file for the console and
+# the ldap client utility programs
+ rm -f $(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd/slapd-client.zip
+ifdef RSH_ZIP_HOST
+# Workaround for problems with ZIP and some SunOS5.6 nfs servers
+# Usage : RSH_ZIP_HOST=remote host for zipping RSH_ZIP_PATH=full path on remote host for zip binary
+ $(RSH) $(RSH_ZIP_HOST) "cd $(TMP_CM_PWD)/$(RELDIR); $(RSH_ZIP_PATH)/$(ZIP) $(ZIP_FLAGS) $(ABS_INSTDIR)/$(NS_BUILD_FLAVOR)/slapd/slapd-client.zip ./java"
+else
+# Normal way to ZIP the bits
+ cd $(RELDIR); $(ZIP) $(ZIP_FLAGS) $(ABS_INSTDIR)/$(NS_BUILD_FLAVOR)/slapd/slapd-client.zip ./java
+endif
+
+#; for file in $(LDAPSDK_IMPORTS) ; \
+# do $(ZIP) $(ZIP_FLAGS) -g $(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd/slapd-client.zip bin/slapd/server/$$file$(DOTEXE) ; \
+# done
+
+# create the slapd zip file
+ rm -f $(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd/ns$(DIR).zip
+# create installable package
+ifdef RSH_ZIP_HOST
+# Workaround for problems with ZIP and some SunOS5.6 nfs servers (see above)
+ rsh $(RSH_ZIP_HOST) "cd $(TMP_CM_PWD)/$(RELDIR); $(RSH_ZIP_PATH)/$(ZIP) $(ZIP_FLAGS) $(ABS_INSTDIR)/$(NS_BUILD_FLAVOR)/slapd/ns$(DIR).zip * $(EXCLUDED_FILES) "
+else
+# Normal way to ZIP the bits
+ cd $(RELDIR); $(ZIP) $(ZIP_FLAGS) $(ABS_INSTDIR)/$(NS_BUILD_FLAVOR)/slapd/ns$(DIR).zip * $(EXCLUDED_FILES)
+endif
+
+# do one last check for aix. aix zip doesn't like -r -T
+ $(ZIP) -T $(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd/ns$(DIR).zip
+# install the ns-config file into the slapd package directory
+ $(INSTALL) -m 755 $(RELDIR_32)/bin/slapd/admin/bin/ns-config $(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd
+
+# if we are packaging our own version of the components, we need them during setup too
+ -@for file in $(PACKAGE_SETUP_LIBS_32) ; \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd ; \
+ fi ; \
+ done
+
+# if the untar directory is there, hooray; otherwise, we will have to unpack the
+# binaries ourselves . . .
+ @curdir=`pwd`; cd $(INSTDIR)/$(NS_BUILD_FLAVOR) ; \
+ if [ ! -d $(IMPORTADMINSRVNOTAR) ] ; \
+ then for file in $(ADMIN_IMPORTS_TARGZ) ; \
+ do rm -rf $$file ; \
+ $(GUNZIP) -c $(ADMSERV_DIR)/$$file | $(TAR) xvf - ; \
+ done ; \
+ cd $$curdir ; \
+ $(PERL) -w $(FIX_SETUP_INF) $(INSTDIR)/$(NS_BUILD_FLAVOR)/setup.inf \
+ $(INSTDIR)/$(NS_BUILD_FLAVOR)/setup.inf.tmp ; \
+ mv $(INSTDIR)/$(NS_BUILD_FLAVOR)/setup.inf.tmp \
+ $(INSTDIR)/$(NS_BUILD_FLAVOR)/setup.inf ; \
+ else \
+ for file in $(ADMIN_IMPORTS) ; \
+ do rm -rf $$file ; \
+ ln -s $(IMPORTADMINSRVNOTAR)/$$file $$file ; \
+ done ; \
+ $(PERL) -w $(FIX_SETUP_INF) $(IMPORTADMINSRVNOTAR)/setup.inf setup.inf ; \
+ fi
+
+# we must remove the nsbase.zip file - we package those files now
+ rm -f $(INSTDIR)/$(NS_BUILD_FLAVOR)/base/nsbase.zip
+# we also need to remove the Archive directive from the [base] section of the
+# base.inf file
+ $(PERL) -w $(FIX_BASE_INF) $(INSTDIR)/$(NS_BUILD_FLAVOR)/base/base.inf
+
+# We must remove the JRE per Red Hat. The user will download the jre
+ rm -f $(INSTDIR)/$(NS_BUILD_FLAVOR)/base/nsjre.zip
+
+# Move setup binary to dssetup
+ mv $(INSTDIR)/$(NS_BUILD_FLAVOR)/setup $(INSTDIR)/$(NS_BUILD_FLAVOR)/dssetup
+# Move the new setup wrappers into place
+ cp $(MCOM_ROOT)/ldapserver/ldap/cm/newinst/setup.pl $(INSTDIR)/$(NS_BUILD_FLAVOR)/setup.pl
+ cp $(MCOM_ROOT)/ldapserver/ldap/cm/newinst/setup.sh $(INSTDIR)/$(NS_BUILD_FLAVOR)/setup
+
+# We need to package perl for the new setup wrapper to run
+ mkdir $(INSTDIR)/$(NS_BUILD_FLAVOR)/tmp
+ $(UNZIP) $(INST_TARGET)/nsperl/$(NSPERL_ZIP_FILE) \
+ lib/nsPerl5.6.1/\* -d $(INSTDIR)/$(NS_BUILD_FLAVOR)/tmp
+ cp -R $(INSTDIR)/$(NS_BUILD_FLAVOR)/tmp/lib/nsPerl5.6.1 \
+ $(INSTDIR)/$(NS_BUILD_FLAVOR)/tools
+ rm -rf $(INSTDIR)/$(NS_BUILD_FLAVOR)/tmp
+
+# We also need to package the infozip utilities
+ $(UNZIP) -j $(INSTDIR)/$(NS_BUILD_FLAVOR)/tools/infozip.zip \
+ -d $(INSTDIR)/$(NS_BUILD_FLAVOR)/tools
+ rm -f $(INSTDIR)/$(NS_BUILD_FLAVOR)/tools/infozip.zip
+
+# Install LDAP Readme and License files at root of Installation (dated pre-packaging) directory.
+# And, replace the License.txt file that is packaged in nssvrcore.zip.
+ if [ -d $(LDAPDIR)/docs ] ; then \
+ rm -rf $(INSTDIR)/$(NS_BUILD_FLAVOR)/LICENSE.txt $(INSTDIR)/$(NS_BUILD_FLAVOR)/README.txt; \
+ $(INSTALL) -m 755 $(LDAPDIR)/docs/README.txt $(LDAPDIR)/docs/LICENSE.txt $(INSTDIR)/$(NS_BUILD_FLAVOR); \
+ fi
+
+# Install dsktune at root of Installation
+ cp $(RELDIR)/bin/slapd/server/dsktune $(INSTDIR)/$(NS_BUILD_FLAVOR)
+
+# copy the sample silent.inf from setup
+ if [ ! -f $(INSTDIR)/$(NS_BUILD_FLAVOR)/silent.inf ] ; \
+ then cp $(SETUPSDK_BINPATH)/silent.inf $(INSTDIR)/$(NS_BUILD_FLAVOR) ; \
+ fi
+
+ifndef NO_INSTALLER_TAR_FILES
+# build the slapd package tar file
+ cd $(INSTDIR)/$(NS_BUILD_FLAVOR); $(TAR) cvf - slapd \
+ | gzip -f > ../$(NS_BUILD_FLAVOR).tar.gz
+# build the combined packages tar file; use h flag to follow symlinks
+ifdef BUILD_SHIP
+ cd $(INSTDIR)/$(NS_BUILD_FLAVOR); $(TAR) cvfh - setup.inf dssetup setup.pl slapd nsperl \
+ perldap dsktune tools $(ADMIN_IMPORTS) | gzip -f > $(BUILD_SHIP)/$(FTPNAMEGZ)
+ifeq ($(DEBUG), optimize)
+# $(REMSH) "/u/svbld/bin/preRtm $(BUILD_SHIP) $(FTPNAMEGZ) svbld"
+endif
+else
+ cd $(INSTDIR)/$(NS_BUILD_FLAVOR); $(TAR) cvfh - setup.inf dssetup setup.pl slapd nsperl \
+ perldap dsktune tools $(ADMIN_IMPORTS) | gzip -f > ../all$(NS_BUILD_FLAVOR).tar.gz
+endif
+#cp $(INSTDIR)/$(NS_BUILD_FLAVOR).tar.gz $(BUILD_SHIP)
+#cp $(INSTDIR)/all$(NS_BUILD_FLAVOR).tar.gz $(BUILD_SHIP)
+# $(INSTDIR)/$(NS_BUILD_FLAVOR) is used to build international products.
+endif
+
+else
+
+# ---THE NT PACKAGE---
+$(PACKAGE_STAGE_DIR):
+ mkdir -p $@
+
+$(INSTDIR):
+ mkdir -p $@
+
+$(INST_TARGET): $(INSTDIR)
+ mkdir -p $@
+
+###self-extracting EXE using EXEBUILD and MAKE the INI file on the fly ##
+# and rename OBJDIR_BASE directroy to temp since EXEBUILDER chokes on LFNS
+# when building across NFS, then rename it back. davidk
+
+make_zip:
+ if [ -d $(LDAPDIR)/docs ] ; then \
+ rm -rf $(INSTDIR)/$(NS_BUILD_FLAVOR)/license-nt.txt $(INSTDIR)/$(NS_BUILD_FLAVOR)/slapd.txt $(INSTDIR)/$(NS_BUILD_FLAVOR)/README.txt $(INSTDIR)/$(NS_BUILD_FLAVOR)/LICENSE.txt; \
+ cd $(LDAPDIR)/docs; $(INSTALL) -m 755 README.txt LICENSE.txt $(INSTDIR)/$(NS_BUILD_FLAVOR); \
+ fi
+ifdef BUILD_SHIP
+ cd $(INST_TARGET); zip -r $(BUILD_SHIP)/$(FTPNAME) *
+endif
+
+endif
+
+## Run Acceptance Test from the auto builds
+## Run it only on domestic - optimized
+## davidk
+
+ifeq ($(BUILD_SECURITY), domestic)
+ifeq ($(BUILD_DEBUG), optimize)
+acceptdir=../../../tetframework/testcases/DS/6.0/acceptance
+longdir=../../../tetframework/testcases/DS/6.0/longduration
+endif
+endif
+
+Acceptance:
+ifdef BUILD_SHIP
+ifeq ($(BUILD_SECURITY), domestic)
+ifeq ($(BUILD_DEBUG), optimize)
+ifeq ($(ARCH), HPUX)
+ifeq ($(USE_64), 1) # only run acceptance on 64-bit HPUX builds
+ $(acceptdir)/accept $(BUILD_SHIP)/$(FTPNAMEGZ) &
+endif # USE_64
+else
+ $(acceptdir)/accept $(BUILD_SHIP)/$(FTPNAMEGZ) &
+endif # HPUX
+endif # optimize
+endif # domestic
+endif # BUILD_SHIP
+
+Longduration:
+ifdef BUILD_SHIP
+ifeq ($(BUILD_SECURITY), domestic)
+ifeq ($(BUILD_DEBUG), optimize)
+ifeq ($(ARCH), HPUX)
+ifeq ($(USE_64), 1) # only run long duration on 64-bit HPUX builds
+ $(longdir)/longduration $(BUILD_SHIP)/$(FTPNAMEGZ) &
+endif # USE_64
+else
+ $(longdir)/longduration $(BUILD_SHIP)/$(FTPNAMEGZ) &
+endif # HPUX
+endif # optimize
+endif # domestic
+endif # BUILD_SHIP
+
+cleanDirectory:
+ cd $(LDAPDIR); $(MAKE) clean
+ rm -rf $(MCOM_ROOT)/dist/$(NC_BUILD_FLAVOR)
+ rm -rf $(MCOM_ROOT)/ldapserver/built/$(NS_BUILD_FLAVOR)
+
+
+ifeq ($(ARCH), WINNT)
+copyLibslapd: $(OBJDIRLIB)
+ $(CP) $(INST_TARGET_RESKIT)/libslapd.$(DLL_SUFFIX) $(LIBSLAPD_DEP)
+ $(CP) $(INST_TARGET_RESKIT)/libslapd.$(LIB_SUFFIX) $(LIBSLAPD)
+else
+copyLibslapd: $(OBJDIRLIB)
+ $(CP) $(INST_TARGET_RESKIT)/libslapd.$(DLL_SUFFIX) $(LIBSLAPD_DEP)
+endif
+
+packageReskit:
+ifdef BUILD_SHIP
+ rm -rf $(BUILD_SHIP)/$(NS_BUILD_FLAVOR)
+ $(MKDIR) $(BUILD_SHIP)/$(NS_BUILD_FLAVOR)
+ifeq ($(ARCH), WINNT)
+ $(INSTALL) -m 755 $(LIBSLAPD) $(BUILD_SHIP)/$(NS_BUILD_FLAVOR)/lib
+ $(INSTALL) -m 755 $(OBJDIRLIB)/cos-plugin.$(LIB_SUFFIX) $(BUILD_SHIP)/$(NS_BUILD_FLAVOR)/lib
+endif
+ $(INSTALL) -m 755 $(LIBSLAPD_DEP) $(BUILD_SHIP)/$(NS_BUILD_FLAVOR)/lib
+ $(INSTALL) -m 755 $(OBJDIRLIB)/cos-plugin.$(DLL_SUFFIX) $(BUILD_SHIP)/$(NS_BUILD_FLAVOR)/lib
+endif
+### END OF DS4.x RESOURCE KIT STUFF
+#####################################################
+
+ifeq ($(ARCH), WINNT)
+
+SLAPD_DIR=slapd
+
+_perl: $(INSTDIR)/$(NS_BUILD_FLAVOR)/nsperl/$(NSPERL_ZIP_FILE) \
+ $(INSTDIR)/$(NS_BUILD_FLAVOR)/perldap/$(PERLDAP_ZIP_FILE)
+
+# ------------------------- all below this line is packageDirectory --------------------------
+
+packageDirectory: $(INST_TARGET)/$(SLAPD_DIR) _admserv_files _perl _slapd_files _setup_files make_zip
+
+#-------------------------- admserv rules ----------------------------------------------------
+_admserv_files: $(INST_TARGET) $(ADMSERV_DEP)
+# we don't want to copy the tarball with the other setup files . . .
+ mv $(ADMSERV_DIR)/$(ADMIN_SERVER_TARGZ) $(ADMSERV_DIR)/..
+# copy in the setup.exe, setup.inf, dlls, etc.
+ cp $(ADMSERV_DIR)/*.* $(INST_TARGET)
+# move the tarball back after the copy
+ mv $(ADMSERV_DIR)/../$(ADMIN_SERVER_TARGZ) $(ADMSERV_DIR)
+# make sure our packages are in the setup.inf file
+ $(PERL) -w $(FIX_SETUP_INF) $(ADMSERV_DIR)/setup.inf $(INST_TARGET)/setup.inf
+# move setup.exe to dssetup.exe
+ mv $(INST_TARGET)/setup.exe $(INST_TARGET)/dssetup.exe
+# copy in the new setup wrapper script
+ cp $(MCOM_ROOT)/ldapserver/ldap/cm/newinst/setup.pl $(INST_TARGET)
+ cp $(MCOM_ROOT)/ldapserver/ldap/cm/newinstnt/setup.bat $(INST_TARGET)
+
+
+#---------------------------- slapd rules --------------------------------------------------
+
+# Files which go in the distibution and which we make ourselves
+SLAPD_ZIPFILE=$(ABS_ROOT)/$(MMDD)/$(NS_BUILD_FLAVOR)/$(SLAPD_DIR)/slapd.z
+DSJARS_ZIPFILE=$(ABS_ROOT)/$(MMDD)/$(NS_BUILD_FLAVOR)/$(SLAPD_DIR)/dsjars.z
+
+.PHONY: _slapd_files
+
+_slapd_files: $(INST_TARGET)/$(SLAPD_DIR) \
+ $(INST_TARGET)/$(SLAPD_DIR)/slapd.z \
+ $(INST_TARGET)/$(SLAPD_DIR)/dsjars.z
+
+$(INST_TARGET)/$(SLAPD_DIR)/dsjars.z: $(DS_JAR_SRC_PATH)/$(DS_JAR_FILE) \
+ $(DS_JAR_SRC_PATH)/$(DS_JAR_LANG_FILE) $(DS_JAR_SRC_PATH)/$(XMLTOOLS_JAR_FILE)
+ rm -f $(DSJARS_ZIPFILE); cd $(RELDIR); zip -r $(DSJARS_ZIPFILE) java
+
+$(INST_TARGET)/$(SLAPD_DIR)/slapd.z:
+# see components.mk for a description of LIBS_TO_PKG
+ -@for file in $(LIBS_TO_PKG) ; \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(RELDIR)/bin/slapd/server ; \
+ $(INSTALL) -m 755 $$file $(RELDIR)/bin/slapd/admin/bin ; \
+ fi ; \
+ done
+# these are files to copy to the shared/bin directory - ldap cmd line tools, sec tools, etc.
+ for file in $(BINS_TO_PKG_SHARED) $(LIBS_TO_PKG_SHARED); \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(RELDIR)/shared/bin ; \
+ fi ; \
+ done
+# these are dlls to copy to the clients/dsgw/bin directory to support dsgw & pb
+ for file in $(LIBS_TO_PKG_CLIENTS); \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(RELDIR)/clients/dsgw/bin ; \
+ fi ; \
+ done
+ $(INSTALL) -m 755 $(OBJDIR)/$(BUILD_HTTPDLL_NAME).dll $(RELDIR)/bin/slapd/server
+ $(INSTALL) -m 755 $(OBJDIR)/$(BUILD_HTTPDLL_NAME).dll $(RELDIR)/clients/dsgw/bin
+ rm -f $(SLAPD_ZIPFILE); cd $(RELDIR); zip -r $(SLAPD_ZIPFILE) *
+
+#----------------------------- setup rules ---------------------------------------------------
+
+_setup_files: $(INST_TARGET)/$(SLAPD_DIR)/dsinst.dll \
+ $(INST_TARGET)/$(SLAPD_DIR)/slapd.inf \
+ $(INST_TARGET)/admin $(INST_TARGET)/base \
+ $(INST_TARGET)/svrcore $(INST_TARGET)/tools
+# see components.mk for a description of PACKAGE_SETUP_LIBS
+ -@for file in $(PACKAGE_SETUP_LIBS) ; \
+ do if [ -f $$file ] ; \
+ then $(INSTALL) -m 755 $$file $(INST_TARGET) ; \
+ fi ; \
+ done
+
+$(INST_TARGET)/$(SLAPD_DIR)/dsinst.dll: $(OBJDIR)/setup/dsinst.dll
+ cp $< $@
+
+$(INST_TARGET)/$(SLAPD_DIR)/slapd.inf: $(OBJDIR)/setup/slapd.inf
+ cp $< $@
+
+$(INST_TARGET)/admin: $(ADMSERV_DIR)/admin
+ cp -R $< $@
+
+$(INST_TARGET)/base: $(ADMSERV_DIR)/base
+ cp -R $< $@
+ rm -f $@/base.z
+ rm -f $@/basesys.z
+# we need to remove the jre per Red Hat. Users will download their own jre
+ rm -f $(INST_TARGET)/base/jre.z
+# we also need to remove the Archive directive from the [base] section of the
+# base.inf file
+ $(PERL) -w $(FIX_BASE_INF) $@/base.inf
+
+$(INST_TARGET)/svrcore: $(ADMSERV_DIR)/svrcore
+ cp -R $< $@
+
+$(INST_TARGET)/tools: $(INSTDIR)/$(NS_BUILD_FLAVOR)/tools/infozip.zip
+ $(UNZIP) -j $(INST_TARGET)/nsperl/$(NSPERL_ZIP_FILE) \
+ lib/nsPerl5.6.1/bin/perl$(DOTEXE) -d $@
+ $(UNZIP) -j $(INST_TARGET)/nsperl/$(NSPERL_ZIP_FILE) \
+ lib/nsPerl5.6.1/bin/perl56.dll -d $@
+# We need to pull out the perl lib directory for perl to work
+ mkdir $@/tmp
+ $(UNZIP) $(INST_TARGET)/nsperl/$(NSPERL_ZIP_FILE) \
+ lib/nsPerl5.6.1/lib/\* -d $@/tmp
+ cp -R $@/tmp/lib/nsPerl5.6.1/lib $@
+ rm -rf $@/tmp
+ $(UNZIP) -j $< -d $@
+ rm -f $<
+
+endif
+
+$(OBJDIR)/lib/libsi18n/ns-slapd.properties:
+ cd $(MCOM_ROOT)/ldapserver/lib/libsi18n ; $(MAKE) $(MFLAGS) all
diff --git a/ldap/cm/filterfiles.sh b/ldap/cm/filterfiles.sh
new file mode 100644
index 00000000..7ab1e3c9
--- /dev/null
+++ b/ldap/cm/filterfiles.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Usage: filterfiles.sh filter into-dir from-dir from-file ...
+# echo filterdir.sh "$@"
+
+FILTER="$1"; shift
+INTO="$1"; shift
+FROM="$1"; shift
+if [ ! -d ${INTO} ]; then mkdir ${INTO}; fi
+for PATTERN in "$@"; do
+ for FILE in ${FROM}/${PATTERN}; do
+ if [ -f ${FILE} ]; then
+ BASE=`basename ${FILE}`
+ case ${BASE} in
+ *.gif )
+ echo "cp ${FILE} ${INTO}"
+ cp ${FILE} ${INTO} || exit $? ;;
+ * )
+ echo "sh ${FILTER} ${FILE} > ${INTO}/${BASE}"
+ sh ${FILTER} ${FILE} > ${INTO}/${BASE} || exit $? ;;
+ esac
+ fi
+ done
+done
diff --git a/ldap/cm/fixBaseInf.pl b/ldap/cm/fixBaseInf.pl
new file mode 100644
index 00000000..cadbfa74
--- /dev/null
+++ b/ldap/cm/fixBaseInf.pl
@@ -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
+#
+
+# the first argument is the full path and filename of ths nsperl.inf file
+# the second argument is the name of the sub component to use
+
+$infile = $ARGV[0];
+$outfile = $ARGV[0] . ".tmp";
+open(IN, $infile) or die "Error: could not read file $infile: $!";
+open(OUT, ">$outfile") or die "Error: could not write file $outfile: $!";
+
+$inBaseSection = 0;
+while (<IN>) {
+ my $printIt = 1;
+ if ($inBaseSection && /^Archive/) {
+ $printIt = 0; # remove the Archive directives
+ } elsif ($inBaseSection && /^System32Archive/) {
+ $printIt = 0; # remove the Archive directives
+ } elsif ($inBaseSection && /^RestoreFiles/) {
+ $printIt = 0; # these files may not be present
+ }
+ if (/^\[base\]/) {
+ $inBaseSection = 1;
+ } elsif (/^\[/) {
+ $inBaseSection = 0;
+ }
+ print OUT if $printIt;
+}
+
+close OUT;
+close IN;
+
+unlink $infile;
+rename $outfile, $infile;
diff --git a/ldap/cm/fixNSPerlInf.pl b/ldap/cm/fixNSPerlInf.pl
new file mode 100644
index 00000000..afdf00eb
--- /dev/null
+++ b/ldap/cm/fixNSPerlInf.pl
@@ -0,0 +1,55 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# the first argument is the full path and filename of ths nsperl.inf file
+# the second argument is the name of the sub component to use
+
+$infile = $ARGV[0];
+$outfile = $ARGV[0] . ".tmp";
+open(IN, $infile) or die "Error: could not read file $infile: $!";
+open(OUT, ">$outfile") or die "Error: could not write file $outfile: $!";
+
+$PRINT = 1;
+while (<IN>) {
+ if (/^Components\s*=\s*/) {
+ if ($' =~ /$ARGV[1]/) {
+ $_ = "Components=$ARGV[1]\n";
+ } else {
+ die "Error: the version of nsPerl in $infile does not contain $ARGV[1]\n";
+ }
+ }
+ if (/^Archive=/) {
+ $_ = "Archive=nsperl561.zip\n";
+ }
+ if (/^\[(\w+)\]/) {
+ if (($1 eq $ARGV[1]) || ($1 eq General)) {
+ $PRINT = 1;
+ } else {
+ $PRINT = 0;
+ }
+ }
+
+ if ($PRINT) {
+ if (/^Description/) {
+ s/The Sun \| Netscape Alliance/Netscape/g;
+ s/iPlanet/Netscape/g;
+ } elsif (/^Vendor/) {
+ s/Sun \| Netscape Alliance/Netscape Communications Corp./g;
+ }
+ print OUT;
+ if (/^RunPostInstall/) {
+ print OUT "Checked=TRUE\nVisible=FALSE\n";
+ }
+ }
+}
+
+close OUT;
+close IN;
+
+unlink $infile;
+rename $outfile, $infile;
diff --git a/ldap/cm/fixPerlDAPInf.pl b/ldap/cm/fixPerlDAPInf.pl
new file mode 100644
index 00000000..fe87dad0
--- /dev/null
+++ b/ldap/cm/fixPerlDAPInf.pl
@@ -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
+#
+
+# the argument is the full path and filename of the perldap.inf file
+
+$infile = $ARGV[0];
+$outfile = $ARGV[0] . ".tmp";
+open(IN, $infile) or die "Error: could not read file $infile: $!";
+open(OUT, ">$outfile") or die "Error: could not write file $outfile: $!";
+
+while (<IN>) {
+ if (/^Description/) {
+ s/The Sun \| Netscape Alliance/Netscape/g;
+ s/iPlanet/Netscape/g;
+ } elsif (/^Vendor/) {
+ s/Sun \| Netscape Alliance/Netscape Communications Corp./g;
+ }
+ print OUT;
+ if (/^Archive=perldap14.zip/) {
+ print OUT "Visible=FALSE\n";
+ }
+}
+
+close OUT;
+close IN;
+
+unlink $infile;
+rename $outfile, $infile;
diff --git a/ldap/cm/fixSetupInf.pl b/ldap/cm/fixSetupInf.pl
new file mode 100644
index 00000000..a973af31
--- /dev/null
+++ b/ldap/cm/fixSetupInf.pl
@@ -0,0 +1,82 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+#
+
+$isNT = -d '\\';
+
+if ($isNT) {
+ $ServerDir = "/Netscape/Servers";
+} else {
+ $ServerDir = "/usr/netscape/servers";
+}
+$ServerDirKey = "DefaultInstallDirectory";
+
+$input = shift;
+$output = shift;
+die "cannot open input file $input" unless open( FILE, $input );
+die "cannot open output file $output" unless open( OUT, ">$output" );
+$inGeneralSection = 0;
+$addServerDir = 1; # add the server dir if it's not already there
+while ( <FILE> ) {
+ # if the line begins with Components and does not contain
+ # slapd already, add ", slapd" to the end
+ # else, just copy the line to output
+ if ( /^Components/ ) {
+ chomp;
+ if (! /slapd/) {
+ $_ .= ", slapd";
+ $addedSlapd = 1;
+ }
+ if (! /nsperl/) {
+ $_ .= ", nsperl";
+ $addedNSperl = 1;
+ }
+ if (! /perldap/) {
+ $_ .= ", perldap";
+ $addedPerLDAP = 1;
+ }
+ $_ .= "\n";
+ }
+ if ( $inGeneralSection && /^$ServerDirKey/ ) {
+ $addServerDir = 0; # already there, don't add it
+ }
+ if ( $inGeneralSection && /^\[/ ) {
+ if ( $addServerDir ) {
+ $_ = "$ServerDirKey = $ServerDir\n$_";
+ $addServerDir = 0;
+ }
+ $inGeneralSection = 0;
+ }
+ if ( /^\[General\]/ ) {
+ $inGeneralSection = 1;
+ }
+ print OUT $_;
+}
+
+close ( FILE );
+
+# now, print the slapd section information
+if ($addedSlapd) {
+ print OUT "\n[slapd]\n";
+ print OUT "ComponentInfoFile = slapd/slapd.inf\n";
+}
+
+if ($addedNSperl) {
+ print OUT "\n[nsperl]\n";
+ print OUT "ComponentInfoFile = nsperl/nsperl.inf\n";
+}
+
+if ($addedPerLDAP) {
+ print OUT "\n[perldap]\n";
+ print OUT "ComponentInfoFile = perldap/perldap.inf\n";
+}
+
+close ( OUT );
+
+exit(0);
diff --git a/ldap/cm/ldapjava.mpw b/ldap/cm/ldapjava.mpw
new file mode 100644
index 00000000..914dbfd5
--- /dev/null
+++ b/ldap/cm/ldapjava.mpw
@@ -0,0 +1,8 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# this is mapped via and NTFS Appleshare volume from //Keefer/java # this is a Macintosh Programmers Workshop File (MPW) # created by David Keefer e-mail davidk@netscape.com set location 'java:ldapserver:built:release:ldapjdk-mac:' for DosFile in `WhereIs -d -s {location} .htm` set dave "{DosFile}" echo setting {DosFile} ... SetFile -t TEXT -c MOSS {dave} end for DosFile in `WhereIs -d -s {location} .txt ` set dave "{DosFile}" echo setting {DosFile} ... SetFile -t TEXT -c ttxt {dave} end for ftype in .java .mf .jsb for DosFile in `WhereIs -d -s {location} {ftype} ` set dave "{DosFile}" echo setting {DosFile} ... SetFile -t TEXT -c 'R*ch' {dave} end end for DosFile in `WhereIs -d -s {location} .class ` set dave "{DosFile}" echo setting {DosFile} ... SetFile -t TEXT -c Javc {dave} for DosFile in `WhereIs -d -s {location} .gif ` set dave "{DosFile}" echo setting {DosFile} ... SetFile -t TEXT -c MOSS {dave} end
diff --git a/ldap/cm/nbsp2utf8.sh b/ldap/cm/nbsp2utf8.sh
new file mode 100644
index 00000000..1f7df9b1
--- /dev/null
+++ b/ldap/cm/nbsp2utf8.sh
@@ -0,0 +1,15 @@
+#!/bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Note that due to a bug in the Bourne shell on Digital UNIX 4.0, this
+# script should always be invoked with one argument, e.g., like this:
+#
+# ./nbsp2utf8.sh infile > outfile
+#
+exec sed -e 's/&nbsp;/ /g' "$@"
diff --git a/ldap/cm/newinst/Makefile b/ldap/cm/newinst/Makefile
new file mode 100644
index 00000000..9fa0867e
--- /dev/null
+++ b/ldap/cm/newinst/Makefile
@@ -0,0 +1,159 @@
+#
+# 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 install forms and CGI programs
+
+.SUFFIXES: .cc
+
+# We do this to force a 32-bit build of this stuff, even in a 64-bit build
+# (because we want to avoid various complexities inherenet in having a 64-bit
+# installer rubbing shoulders with other 32-bit stuff at install time).
+COMPONENT_DEPS := 1
+override USE_64=
+
+MCOM_ROOT = ../../../..
+LDAP_SRC = ../..
+
+MODULE=slapdInstallBin
+# override BUILD_MODULE = HTTP_ADMIN
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+test:
+ echo $(SETUPSDK_VERSION)
+ echo $(SETUPSDK_RELEASE)
+
+# MODULE_CFLAGS = -DUSE_ADMSERV
+
+BINDEST=$(LDAP_ADMIN_BIN_RELDIR)
+OBJDEST=$(LDAP_ADMOBJDIR)
+
+ifndef $(OFFLAG)
+OFFLAG=-o
+endif
+
+# we don't want to build with warnings-as-errors for the cm/ stuff, because
+# it's 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
+
+NOSTDCLEAN=true
+NOSTDSTRIP=true
+
+OSOBJS=
+OBJS1=$(OBJDEST)/ux-dialog.o $(OBJDEST)/ux-config.o $(OBJDEST)/ux-dsalib_dn.o
+OBJS1GT=$(OBJDEST)/ux-guesses.o
+
+PROGS= ns-config
+ifeq ($(ARCH),WINNT)
+BINS=
+OSOBJS=
+OBJS1=
+OBJS2=
+OSLIBS=
+OSDEPLIBS=
+LIBS=
+else
+BINS=$(addprefix $(BINDEST)/, $(PROGS))
+endif
+INFO= $(OBJDIR)/$(DIR)
+
+# Source for staged installation utilities
+INCDIR=$(SETUPSDK_INCLUDE) -I$(LDAP_SRC)/admin/include -I$(LDAP_SRC)/admin/lib -I$(LDAP_SRC)/admin/src
+
+# ADM_VERSDIR = admserv40
+# ADM_RELDATE = 19980112
+
+all: $(OBJDEST) $(BINDEST) $(SETUPSDK_DEP) $(LDAPSDK_DEP) $(SECURITY_DEP) $(NSPR_DEP) $(OSOBJS) $(OBJS1) $(OBJS2) $(BINS) $(INFO) $(BINDEST)/ns-update $(BINDEST)/uninstall
+# removed ns-keygen from build - it was only used for Dir Lite
+# $(BINDEST)/ns-keygen
+ifeq ($(ARCH), BSDI)
+CFLAGS += -DNO_DOMAINNAME
+endif
+
+ifeq ($(ARCH), IRIX)
+CFLAGS += -exceptions
+EXTRA_LIBS += -lm -lc
+endif
+
+ifeq ($(ARCH), OSF1)
+EXTRA_LIBS += -lm
+endif
+
+#LIBLDAPU= ldapu
+#LIBLDAP= $(LDAP_LIBPATH)/libldap$(LDAP_SUF).a
+#DEPLIBS=$(addprefix $(OBJDIR)/lib/lib, \
+# $(addsuffix .$(LIB_SUFFIX), $(LIBLDAPU))) $(OSDEPLIBS)
+
+ifeq ($(ARCH), HPUX)
+
+ifeq ($(NSOS_RELEASE),B.10.10)
+CURSES=-lHcurses
+endif
+
+ifeq ($(NSOS_RELEASE),B.11.00)
+ MODERNHP=1
+endif
+
+ifeq ($(NSOS_RELEASE),B.11.11)
+ MODERNHP=1
+endif
+
+ifeq ($(MODERNHP),1)
+CURSES=-lHcurses
+else
+CURSES=/usr/lib/libcurses.a
+endif
+ifeq ($(USE_64), 1)
+CURSES=-lcurses
+endif
+else
+CURSES=-lcurses -ltermcap
+endif
+
+ifeq ($(ARCH), AIX)
+CURSES=-lcurses
+endif
+
+$(BINDEST)/ns-update : ns-update
+ -@$(RM) $@
+ $(CP) $< $@
+
+$(BINDEST)/ns-keygen: ns-keygen
+ -@$(RM) $@
+ $(CP) $< $@
+
+$(BINDEST)/uninstall: uninstall
+ -@$(RM) $@
+ $(CP) $< $@
+
+$(BINDEST)/ns-config: $(OBJS1) $(OBJS2)
+ $(PURIFY) $(CXX) $(SHARED_FLAG) $(CFLAGS) $(MCC_INCLUDE) $(INCDIR) \
+ -o $(BINDEST)/ns-config $(RPATHFLAG_PREFIX)$(RPATHFLAG)$(RPATHFLAG_EXTRAS) $(OBJS1) $(OBJS2) $(SETUPSDKLINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) \
+ $(EXTRA_LIBS) $(CURSES)
+
+ifeq ($(ARCH), WINNT)
+$(INFO):
+ $(PERL) fixINF.pl $(BUILD_MODULE) $(DIR_VERSION) $(MCOM_ROOT)/ldapserver/$(BUILD_ARCH)/buildnum.dat slapd.inf $(SECURITY) $(PRODUCT) $(IS_DIR_LITE) $(INSTANCE_NAME_PREFIX) $@.inf $(BUILD_BOMB) "bin/admin/ns-admin,bin/admin/ns-admin.so"
+else
+$(INFO):
+ $(PERL) fixINF.pl $(BUILD_MODULE) $(DIR_VERSION) $(MCOM_ROOT)/ldapserver/$(BUILD_ARCH)/buildnum.dat slapd.inf $(SECURITY) $(PRODUCT) $(IS_DIR_LITE) $(INSTANCE_NAME_PREFIX) $@.inf $(BUILD_BOMB) "$(addprefix lib/,$(LDAP_SOLIBS)) bin/admin/libnsslapd.sl bin/slapd/bin/ns-slapd bin/slapd/bin/ns-slapd.so bin/slapd/bin/libnsslapd_shr.a"
+endif
+
+$(OBJDEST)/%.o: %.c
+ $(CC) $(NONSHARED) $(CFLAGS) $(MCC_INCLUDE) $(INCDIR) -c $< $(OFFLAG)$@
+
+$(OBJDEST)/%.o: %.cc
+ $(CXX) $(NONSHARED) $(CFLAGS) $(MCC_INCLUDE) $(INCDIR) -c $< $(OFFLAG)$@
+
+ns-config-gt: $(OBJS1GT)
+ $(PURIFY) $(CXX) $(NONSHARED) $(CFLAGS) $(MCC_INCLUDE) $(INCDIR) \
+ -o ns-config-gt $(OBJS1GT) $(SETUPSDKLINK) $(LIBLDAP) \
+ $(EXTRA_LIBS) $(CURSES)
diff --git a/ldap/cm/newinst/fixINF.pl b/ldap/cm/newinst/fixINF.pl
new file mode 100644
index 00000000..0861a9b9
--- /dev/null
+++ b/ldap/cm/newinst/fixINF.pl
@@ -0,0 +1,50 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# parameters: BUILD_MODULE versionString buildnum.dat input security name isdirLite output [expDefine]
+
+$module = shift;
+$version = shift;
+$buildFile = shift;
+$input = shift;
+$security = shift;
+$name = shift;
+$isdirLite = shift;
+$instanceNamePrefix = shift;
+$output = shift;
+$expDefine = shift;
+if ($expDefine) {
+ ( $junk, $expires ) = split( /=/, $expDefine );
+ if ( ! $expires ) {
+ $expires = 0;
+ }
+} else {
+ $expires = 0;
+}
+
+# get the build number
+open( FILE, $buildFile );
+while ( <FILE> ) {
+ last if ( $buildNum ) = /\\"(.*)\\"/;
+}
+close( FILE );
+
+# copy the input file to the output file changing stuff along the way
+open( FILE, $input );
+open( OUT, ">$output" );
+while ( <FILE> ) {
+ s/%%%INSTANCE_NAME_PREFIX%%%/$instanceNamePrefix/;
+ s/%%%SERVER_NAME%%%/$name/;
+ s/%%%SERVER_VERSION%%%/$version/;
+ s/%%%SERVER_BUILD_NUM%%%/$buildNum/;
+ s/%%%PUMPKIN_HOUR%%%/$expires/;
+ s/%%%SECURITY%%%/$security/;
+ s/%%%IS_DIR_LITE%%%/$isdirLite/;
+ print OUT;
+}
+close( OUT );
+close( FILE );
diff --git a/ldap/cm/newinst/ns-keygen b/ldap/cm/newinst/ns-keygen
new file mode 100755
index 00000000..599c8e2f
--- /dev/null
+++ b/ldap/cm/newinst/ns-keygen
@@ -0,0 +1,168 @@
+#!/bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Usage ns-keygen password_file fully_qualified_hostname
+# Example:
+# ./ns-keygen ../password.txt myhost.netscape.com
+#
+# Assumes that NSHOME is Set
+# if NSHOME is not set, it will be derived from the path of this script, which is
+# usually NSHOME/bin/slapd/admin/bin
+
+if [ $# -ge 2 ]
+then
+ passwd_file="$1"
+ certDN="$2"
+else
+ echo "ERROR:Incorrect Usage: $0 password_file certDN"
+ exit
+fi
+
+if [ ! "$NSHOME" ]; then
+ fullpath=`pwd`
+ if echo $0 | grep \^/ > /dev/null 2>&1 ; then # is absolute
+ fullpath=`dirname $0`
+ else # is a relative path - could be ./ or ../ or something else
+ base=`basename $0`
+ if [ "$base" != $0 ]; then # e.g. ns-keygen bare from that directory
+ savedir=$fullpath
+ cd `dirname $0`
+ fullpath=`pwd`
+ cd $savedir
+ fi
+ fi
+ # is $0 relative or absolute path?
+ NSHOME=`echo $fullpath | sed -e s@/bin/slapd/admin/bin@@g`
+fi
+
+# set the LD_LIBRARY_PATH - required for the cert tools
+TOOL_PATH=$NSHOME/bin/slapd/admin/bin ; export TOOL_PATH
+# for HPUX
+SHLIB_PATH=$TOOL_PATH:$TOOL_PATH/../lib:$TOOL_PATH/../../lib:$TOOL_PATH/../../../lib:$TOOL_PATH/../../../../lib:$SHLIB_PATH ; export SHLIB_PATH
+# for other unix
+LD_LIBRARY_PATH=$TOOL_PATH:$TOOL_PATH/../lib:$TOOL_PATH/../../lib:$TOOL_PATH/../../../lib:$TOOL_PATH/../../../../lib:$LD_LIBRARY_PATH ; export LD_LIBRARY_PATH
+
+#echo password file name is: $passwd_file
+#echo certDN is: $certDN
+
+rm -f key3.db key4.db cert7.db cert8.db secmodule.db secmod.db random.dat keyid.dat
+
+# Check for password file
+
+#
+# Set umask for best security
+#
+umask 077
+
+#
+# Create some "random" data.
+#
+ps -ale >>random.dat
+date >>random.dat
+netstat -a >>random.dat
+
+if [ ! -s "$passwd_file" ]
+then
+ echo "Error:Password file is missing."
+ exit 1
+fi
+
+#
+# Set the key database password
+#
+$TOOL_PATH/certutil -W -d . -f "$passwd_file"
+RC=$?
+if [ $RC != 0 ]
+then
+ echo "Error:Unable to set the key database password."
+ exit 1
+fi
+
+#
+# Create and sign a self-signed certificate for this
+# server using the server name
+#
+$TOOL_PATH/certutil -S -s "$certDN" -x -t u,, \
+ -v 60 -d . -n Server-Cert -f "$passwd_file" -z random.dat
+RC=$?
+if [ $RC != 0 ]
+then
+ echo "Error:Unable to create the cert."
+ exit 1
+fi
+
+hostname=`uname -n`
+
+#
+# Copy the key/cert db & password file to the correct place.
+#
+keydb=key3.db
+if [ -f key4.db ] ; then
+ keydb=key4.db
+fi
+
+if [ -f $NSHOME/alias/slapd-$hostname-$keydb ]; then
+ echo "Found existing key database - copying to $NSHOME/alias/slapd-$hostname-$keydb.bak"
+ cp $NSHOME/alias/slapd-$hostname-$keydb $NSHOME/alias/slapd-$hostname-$keydb.bak
+ if [ ! -f $NSHOME/alias/slapd-$hostname-$keydb.orig ] ; then
+ cp $NSHOME/alias/slapd-$hostname-$keydb $NSHOME/alias/slapd-$hostname-$keydb.orig
+ fi
+fi
+cp $keydb $NSHOME/alias/slapd-$hostname-$keydb
+RC=$?
+if [ $RC != 0 ]
+then
+ echo "Error:Key Database $keydb could not be copied"
+ exit 1
+fi
+
+certdb=cert7.db
+if [ -f cert8.db ] ; then
+ certdb=cert8.db
+fi
+if [ -f $NSHOME/alias/slapd-$hostname-$certdb ]; then
+ echo "Found existing cert database - copying to $NSHOME/alias/slapd-$hostname-$certdb.bak"
+ cp $NSHOME/alias/slapd-$hostname-$certdb $NSHOME/alias/slapd-$hostname-$certdb.bak
+ if [ ! -f $NSHOME/alias/slapd-$hostname-$certdb.orig ] ; then
+ cp $NSHOME/alias/slapd-$hostname-$certdb $NSHOME/alias/slapd-$hostname-$certdb.orig
+ fi
+fi
+cp $certdb $NSHOME/alias/slapd-$hostname-$certdb
+RC=$?
+if [ $RC != 0 ]
+then
+ echo "Error:Cert Database $certdb could not be copied"
+ exit 1
+fi
+
+# create and copy pin file
+passwd=`cat $passwd_file`
+if [ -f $NSHOME/alias/slapd-$hostname-pin.txt ]; then
+ echo "Found existing pin file - copying to $NSHOME/alias/slapd-$hostname-pin.txt.bak"
+ cp $NSHOME/alias/slapd-$hostname-pin.txt $NSHOME/alias/slapd-$hostname-pin.txt.bak
+ if [ ! -f $NSHOME/alias/slapd-$hostname-pin.txt.orig ]; then
+ cp $NSHOME/alias/slapd-$hostname-pin.txt $NSHOME/alias/slapd-$hostname-pin.txt.orig
+ fi
+fi
+echo "Internal (Software) Token:$passwd" > $NSHOME/alias/slapd-$hostname-pin.txt
+RC=$?
+if [ $RC != 0 ]
+then
+ echo "Error:password file could not be copied"
+ exit 1
+fi
+# Test the new location for the files.
+
+#
+# Cleanup
+rm -f random.dat
+
+#
+# End
+#
diff --git a/ldap/cm/newinst/ns-update b/ldap/cm/newinst/ns-update
new file mode 100755
index 00000000..a4c86788
--- /dev/null
+++ b/ldap/cm/newinst/ns-update
@@ -0,0 +1,135 @@
+#!/bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# This file essentially serves as a wrapper around the instance
+# creation and configuration program (index) since it must be run from
+# the directory it lives in due to run time shared library
+# dependencies
+
+sroot=`echo $0 | sed s#/bin/slapd/admin/bin/.\*##g`
+PERL=$sroot/bin/slapd/admin/bin/perl
+
+start_server()
+{
+ NETSITE_ROOT=$1
+ REQUEST_METHOD=GET
+ export NETSITE_ROOT REQUEST_METHOD
+ QUERY_STRING="InstanceName=$2"
+ SERVER_NAMES=$2
+ export QUERY_STRING SERVER_NAMES
+ cwd=`pwd`
+ cd `dirname $0`
+ ./start 2>&1 | grep -v '^Content' | grep -v '^ds_'
+ cd $cwd
+}
+
+install_nsperl()
+{
+ # the current version of nsPerl to use is defined in the slapd.inf
+ nsperlinst=`grep '^NSPerlPostInstall' setup/slapd/slapd.inf | cut -f2 -d=`
+ # run the nsperl installer
+ $nsperlinst > setup/nsperl/install.log
+ # use nsperl as our local copy of perl
+ cp `dirname $nsperlinst`/nsperl $PERL
+}
+
+wrap_security_tools()
+{
+ cwd=`pwd`
+ SECURITY_BINNAMES="certutil derdump modutil pk12util pp ssltap"
+ arch=`uname`
+ if [ $arch = HP-UX ]; then
+ env_ld_library_path=SHLIB_PATH
+ elif [ $arch = AIX ]; then
+ env_ld_library_path=LIBPATH
+ else
+ env_ld_library_path=LD_LIBRARY_PATH
+ fi
+ cd $sroot/shared/bin
+ for file in $SECURITY_BINNAMES
+ do
+ if [ -f $file -a ! -f $file-bin ]; then
+ mv $file $file-bin
+ echo "#!/bin/sh" > $file
+ echo $env_ld_library_path=$sroot/shared/lib >> $file
+ echo "export $env_ld_library_path" >> $file
+ echo "$sroot/shared/bin/$file-bin " '${1+"$@"}' >> $file
+ chmod 755 $file
+ fi
+ done
+ cd $cwd
+}
+
+# if the -r flag is present, this means we're doing a
+# reinstall or an upgrade, so restart the servers
+for arg in $* ; do
+ if [ "$arg" = "-r" ]; then
+ reconfig=1
+ fi
+ if [ "$arg" = "-S" ]; then
+ iDSISolaris=1
+ fi
+
+done
+
+extraflags=
+# For Solaris 9+ specific installation, the following
+# method of determining reconfiguration by checking
+# the existence of <sroot>/slapd-nickname/config
+# directory cannot be used. This is because the
+# server_root is the same for all instances. Also, it
+# uses standard Solaris supplied perl.
+if [ "$iDSISolaris" = "" ]; then
+ # for some reason, we are not being passed the -r flag during
+ # reinstall; so, determine if there are existing server
+ # instances in this server root, and assume -r if there
+ # are
+ if [ "$reconfig" = "" ]; then
+ cd $sroot
+ for dir in slapd-* ; do
+ if [ -d $dir/config ]; then
+ reconfig=1
+ extraflags="-r"
+ break
+ fi
+ done
+ fi
+
+ install_nsperl
+fi
+
+if [ $reconfig ] ; then
+ cd $sroot
+ for dir in slapd-* ; do
+ # first, fix any old password files
+ if [ -d alias ]; then
+ cd alias
+ echo Converting $dir to new format password file . . .
+ $PERL $sroot/bin/slapd/admin/bin/migratePwdFile $sroot $dir
+ cd ..
+ fi
+ # Copy new schema ldiffiles
+ echo Copying new schema ldiffiles . . .
+ $PERL $sroot/bin/slapd/admin/bin/upgradeServer $sroot $dir
+
+ # next, start the server
+ echo Starting $dir . . .
+ start_server $sroot $dir
+ echo ""
+ done
+fi
+
+wrap_security_tools $sroot
+
+cd `dirname $0`
+
+if [ "$iDSISolaris" = "" ]; then
+ exec ./ds_create $* $extraflags
+else
+ exec $PERL -w Install.pl $* $extraflags
+fi
diff --git a/ldap/cm/newinst/replaceToken.pl b/ldap/cm/newinst/replaceToken.pl
new file mode 100644
index 00000000..13265efe
--- /dev/null
+++ b/ldap/cm/newinst/replaceToken.pl
@@ -0,0 +1,34 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# The first argument is the file to edit
+# The remaining arguments are pairs of values: the first value of the pair is
+# the token to look for, and the second is the value to replace it with e.g.
+# if the input file foo contains
+# $NETSITE_ROOT/%%%PERL_RUNTIME%%% -w perlscript ...
+# then running $(PERL) thisscript foo %%%PERL_RUNTIME%%% foo/bar/perl5 > output/foo
+# will result in output/foo containing
+# NETSITE_ROOT/foo/bar/perl5 -w perlscript ...
+
+($input, %tokens) = @ARGV;
+
+if (! $input) {
+ print STDERR "Usage: $ $0 <inputfilename> [token1 replace1] ... [tokenN replaceN]\n";
+ exit 1;
+}
+
+open(INPUT, $input) or die "Error: could not open file $input: $!";
+
+while (<INPUT>) {
+ while (($key, $value) = each %tokens) {
+ s/$key/$value/g;
+ }
+ print;
+}
+
+close INPUT;
diff --git a/ldap/cm/newinst/setup.pl b/ldap/cm/newinst/setup.pl
new file mode 100755
index 00000000..f5c95b65
--- /dev/null
+++ b/ldap/cm/newinst/setup.pl
@@ -0,0 +1,141 @@
+#!./tools/perl
+# Author: Nathan Kinder
+#
+# This program will package a downloaded JRE into a nsjre.zip
+# file suitable for a DS install.
+
+use lib './lib';
+use FileHandle;
+
+autoflush STDERR 1;
+autoflush STDOUT 1;
+
+delete $ENV{LD_LIBRARY_PATH};
+
+# Set required JRE version
+if ($^O eq "hpux") {
+ $jdkVersion = "HP's 32-bit HP-UX";
+ $reqVersion = "1.4.2.04";
+ delete $ENV{SHLIB_PATH};
+} elsif ($^O eq "MSWin32") {
+ $jdkVersion = "Sun's 32-bit MS Windows";
+ $reqVersion = "1.4.2_05";
+} elsif ($^O eq "linux") {
+ $jdkVersion = "Sun's 32-bit Linux";
+ $reqVersion = "1.4.2_05";
+} elsif ($^O eq "solaris") {
+ $jdkVersion = "Sun's 32-bit Solaris";
+ $reqVersion = "1.4.2_05";
+} else {
+ print("Unsupported operating system: $^O!\n");
+ exit;
+}
+
+# Check if base/nsjre.zip or base/jre.z already exists
+unless (-e "./base/nsjre.zip" || -e "./base/jre.z") {
+ # Check if NSJRE environment variable is set
+ if ($ENV{NSJRE}) {
+ chomp ($jrepath = $ENV{NSJRE});
+ print ("Using NSJRE environment variable: $jrepath\n");
+ } else {
+ print ("In order to run setup, you need to have version");
+ print (" $reqVersion of\n");
+ print ("$jdkVersion Java runtime environment on your system.\n\n");
+ print ("Enter the path to the unpackaged JRE: ");
+ chomp ($jrepath = <STDIN>);
+ }
+
+ VerifyJRE();
+ CreatePackage();
+ CleanUp();
+}
+
+# Kick off setup
+exec("./dssetup @ARGV");
+
+sub VerifyJRE {
+ print ("\nVerifying JRE...");
+ unless (-e "$jrepath" && -r "$jrepath") { die ("\nError: Can't access JRE: $!\n"); }
+ unless (-e "$jrepath/bin" && -r "$jrepath/bin") { die ("\nError: Can't access $jrepath/bin: $!\n"); }
+ unless (-e "$jrepath/bin" && -r "$jrepath/lib") { die ("\nError: Can't access $jrepath/lib: $!\n"); }
+ unless (-e "$jrepath/bin/java" || -e "$jrepath/bin/java.exe") { die ("\nError: Invalid JRE found: $!\n"); }
+
+ my $jreVersion = `\"$jrepath/bin/java\" -version 2>&1`;
+ $jreVersion =~ /".*"/;
+ $foundVersion = $&;
+ print (" Found JRE $foundVersion\n");
+ unless ($foundVersion =~ $reqVersion) {
+ print ("\nWarning: This product was certified with JRE version \"$reqVersion\". You have version $foundVersion.\n");
+ print ("The product may not behave correctly if you use this JRE.\n");
+ print ("Would you like to continue anyway [yes/no]? ");
+ chomp ($answer = <STDIN>);
+ unless ($answer eq "yes") { exit; }
+ }
+}
+
+sub CreatePackage {
+ print ("Creating JRE package...");
+
+ # Create packaging area
+ mkdir ("bin", 0755) || die ("Error: Can't create ./bin: $!\n");
+ mkdir ("bin/base", 0755) || die ("Error: Can't create ./bin/base: $!\n");
+ mkdir ("bin/base/jre", 0755) || die ("Error: Can't create ./bin/base/jre: $!\n");
+
+ # Copy bin and lib from JRE into packaging area, then create zip archive
+ if ($^O eq "MSWin32") {
+ system ("xcopy /E /I /Q \"$jrepath/bin\" \"bin/base/jre/bin\"") == 0 ||
+ die ("\nError: Can't copy JRE: $!\n");
+ system ("xcopy /E /I /Q \"$jrepath/lib\" \"bin/base/jre/lib\"") == 0 ||
+ die ("\nError: Can't copy JRE: $!\n");
+ system ("./tools/zip -q -r ./base/jre.z ./bin") == 0 ||
+ die ("\nError: Can't create JRE archive: $!\n");
+ } else {
+ system ("cp -R $jrepath/bin ./bin/base/jre") == 0 ||
+ die ("\nError: Can't copy JRE: $!\n");
+ system ("cp -R $jrepath/lib ./bin/base/jre") == 0 ||
+ die ("\nError: Can't copy JRE: $!\n");
+
+ # On HP-UX, we need to move some libraries in the JRE package
+ if ($^O eq "hpux") {
+ system ("cp -f ./bin/base/jre/lib/PA_RISC/native_threads/libhpi.sl ./bin/base/jre/lib/PA_RISC/libhpi.sl") == 0 ||
+ die ("\nError: Can't create JRE archive: $!\n");
+ system ("cp -f ./bin/base/jre/lib/PA_RISC2.0/native_threads/libhpi.sl ./bin/base/jre/lib/PA_RISC2.0/libhpi.sl") == 0 ||
+ die ("\nError: Can't create JRE archive: $!\n");
+ system ("cp -f ./bin/base/jre/lib/PA_RISC2.0W/native_threads/libhpi.sl ./bin/base/jre/lib/PA_RISC2.0W/libhpi.sl") == 0 ||
+ die ("\nError: Can't create JRE archive: $!\n");
+ }
+
+ system ("./tools/zip -q -r ./base/nsjre.zip ./bin") == 0 ||
+ die ("\nError: Can't create JRE archive: $!\n");
+ }
+
+ print (" Done\n");
+}
+
+sub CleanUp {
+ print ("Cleaning up...");
+
+ # Remove packaging area
+ RemoveFiles ("./bin");
+ rmdir ("./bin") || die ("Error: can't remove ./bin: $!\n");
+
+ print (" Done\n");
+}
+
+sub RemoveFiles {
+ my $dir = shift;
+ opendir (DIR, $dir) || die ("Error: Can't open $dir: $!");
+ my @entries = map { "$dir/$_" } grep { !/^\.$|^\.\.$/ } readdir DIR;
+ closedir DIR;
+ for (@entries) {
+ if (-l $_) {
+ unlink || die ("Error: Can't remove $_: $!\n");
+ } elsif (-d $_) {
+ RemoveFiles($_);
+ rmdir($_) || die ("Error: Can't remove $_: $!\n");
+ } else {
+ unlink || die ("Error: Can't remove $_: $!\n");
+ }
+ }
+}
+
diff --git a/ldap/cm/newinst/setup.sh b/ldap/cm/newinst/setup.sh
new file mode 100755
index 00000000..a4059e94
--- /dev/null
+++ b/ldap/cm/newinst/setup.sh
@@ -0,0 +1,10 @@
+#!/bin/sh
+
+# Configure nsPerl
+if [ ! -f "./tools/perl" ]; then
+ ./tools/nsPerl5.6.1/install > /dev/null
+ ln -s ./nsPerl5.6.1/nsperl ./tools/perl
+fi
+
+# Kick off setup script
+./setup.pl $*
diff --git a/ldap/cm/newinst/slapd.inf b/ldap/cm/newinst/slapd.inf
new file mode 100644
index 00000000..50ccb706
--- /dev/null
+++ b/ldap/cm/newinst/slapd.inf
@@ -0,0 +1,48 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+[General]
+Name=Netscape Directory Suite
+Components=slapd, slapd-client
+
+[slapd]
+Name= %%%SERVER_NAME%%%
+InstanceNamePrefix= %%%INSTANCE_NAME_PREFIX%%%
+NickName= slapd
+Version= %%%SERVER_VERSION%%%
+Compatible= 4.0
+BuildNumber= %%%SERVER_BUILD_NUM%%%
+Expires= %%%PUMPKIN_HOUR%%%
+Security= %%%SECURITY%%%
+Vendor= Netscape Communications Corp.
+Description= %%%SERVER_NAME%%%
+Dependencies= base/4.5, svrcore/4.5, nsperl561/1.13, perldap14/1.01
+ProductName=Directory Server
+IsDirLite=%%%IS_DIR_LITE%%%
+SourcePath=slapd
+Archive= nsslapd.zip
+PrePreInstall= dsktune
+PreInstall= ns-config
+PostInstall= bin/slapd/admin/bin/ns-update
+PreUninstall= bin/slapd/admin/bin/uninstall
+PostUninstall=
+Checked=True
+Mandatory=False
+IsLdap=True
+NSPerlPostInstall=lib/nsPerl5.6.1/install
+
+[slapd-client]
+Name= Netscape Directory Server Console
+NickName= slapd-client
+Version= %%%SERVER_VERSION%%%
+Compatible= 4.0
+Checked=True
+Mandatory=False
+IsLdap=False
+SourcePath=slapd
+IsMCC=True
+Archive=slapd-client.zip
diff --git a/ldap/cm/newinst/uninstall b/ldap/cm/newinst/uninstall
new file mode 100755
index 00000000..cdcc2491
--- /dev/null
+++ b/ldap/cm/newinst/uninstall
@@ -0,0 +1,75 @@
+#!/bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# determine server root directory from $0; this script is being run
+# from server root/bin/slapd/admin/bin
+
+sroot=`echo $0 | sed 's#/bin/slapd/admin/bin/.*##g'`
+
+# check if Solaris 9+ specific un-installation
+for arg in $* ; do
+ if [ "$arg" = "-S" ]; then
+ iDSISolaris=1
+ fi
+done
+
+if [ "$iDSISolaris" = "1" ]; then
+ vardir=`echo $sroot | sed 's#/usr/iplanet/#/var/#'`
+ etcdir=`echo $sroot | sed 's#/usr/#/etc/#'`
+fi
+
+# search for all slapd-* directories
+
+cd $sroot || {
+ echo "Could not change dir to server root directory $sroot"
+ exit 1
+}
+
+NETSITE_ROOT=$sroot
+REQUEST_METHOD=GET
+export NETSITE_ROOT REQUEST_METHOD
+# for each server instance
+for dir in slapd-* ; do
+ QUERY_STRING="InstanceName=$dir"
+ SERVER_NAMES=$dir
+ export QUERY_STRING SERVER_NAMES
+ # try to remove the nice way . . .
+ cd bin/slapd/admin/bin
+ status=0
+ ./ds_remove $* > /dev/null 2>&1 || status=$?
+ cd $sroot
+ # wait for that to finish
+ sleep 2
+ if [ $status -ne 0 -o -d $dir ]; then
+ # something went wrong; kill with extreme prejudice . . .
+ # Solaris 9+ specific un-installation
+ if [ -f $dir/logs/pid ]; then
+ pid=`cat $dir/logs/pid`
+ # kill the server
+ kill -9 $pid > /dev/null 2>&1
+ # wait for it to stop
+ sleep 2
+ fi
+ # remove the instance directory
+ rm -rf $dir
+ fi
+ # Solaris 9+ specific un-installation
+ if [ "$iDSISolaris" = "1" ]; then
+ rm -rf $etcdir/$dir
+ rm -rf $vardir/$dir
+ fi
+
+done
+
+# remove some other stuff which is dynamically created
+if [ "$iDSISolaris" = "" ]; then
+ rm -rf bin/slapd
+fi
+
+exit 0
diff --git a/ldap/cm/newinst/ux-config.cc b/ldap/cm/newinst/ux-config.cc
new file mode 100644
index 00000000..64f936f2
--- /dev/null
+++ b/ldap/cm/newinst/ux-config.cc
@@ -0,0 +1,1151 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*********************************************************************
+**
+** NAME:
+** ux-config.cc
+**
+** DESCRIPTION:
+** Netscape Directory Server Pre-installation Program
+**
+** NOTES:
+** This program is intended for UNIX only and is NOT thread-safe.
+** Based on the original ux-config.c.
+**
+*********************************************************************/
+
+extern "C" {
+#include <stdio.h>
+#include <string.h>
+#ifdef AIX
+#include <strings.h>
+#endif
+}
+/* Newer g++ wants the new std header forms */
+#if defined( Linux )
+#include <strstream>
+using std::ostrstream;
+/* But some platforms won't accept those (specifically HP-UX aCC */
+#else
+#include <strstream.h>
+#endif
+#include "dialog.h"
+#include "ux-config.h"
+#include "ux-dialog.h"
+#include "install_keywords.h"
+#include "utf8.h"
+extern "C" {
+#include <dsalib.h>
+
+#if defined(__sun) || defined(__hppa) || defined(__osf__) || defined(__linux__) || defined(linux)
+#include <netdb.h>
+#endif
+}
+
+extern const char *DEFAULT_SYSUSER = "root";
+extern const char *DEFAULT_OLDROOT = "/usr/ns-home";
+static const char *DEFAULT_SLAPDCONF = "slapd.conf";
+
+const int RECONFIG_EXIT_CODE = 7;
+
+/*
+ * 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;
+
+static int
+isLiteMode()
+{
+ int ret = 0;
+ InstallInfo infFile("slapd/slapd.inf");
+ InstallInfo *slapdInf = infFile.getSection("slapd");
+ if (!slapdInf || !slapdInf->get("IsDirLite"))
+ {
+ infFile.read("slapd.inf");
+ slapdInf = infFile.getSection("slapd");
+ }
+
+ const char *tmp;
+ ret = (slapdInf && (tmp = slapdInf->get("IsDirLite")) &&
+ !strcasecmp(tmp, "true"));
+
+ return ret;
+}
+
+static char *
+my_strdup(const char *s)
+{
+ char *ret = 0;
+ if (s)
+ {
+ ret = new char[strlen(s) + 1];
+ strcpy(ret, s);
+ }
+
+ return ret;
+}
+
+/*********************************************************************
+**
+** METHOD:
+** main
+** DESCRIPTION:
+** This is the ns-config program. This program functions as
+** - The Pre-installation program used during the Installation
+** of the Directory Server. In this case, the program
+** is supposed to be executed by the common installer (ns-setup)
+** and can be executed from anywhere.
+**
+** - The stand-alone configuration program used to re-configure
+** the directory server. In this case, the program has
+** to be executed from the serverroot.
+**
+** SIDE EFFECTS:
+** None
+** RESTRICTIONS:
+**
+** ALGORITHM:
+**
+**********************************************************************/
+int
+main(int argc, char **argv)
+{
+ int err = 0;
+
+ SlapdPreInstall program(argc, argv);
+
+ err = program.init();
+ if (!err)
+ {
+ err = program.start();
+ }
+
+ return err;
+}
+
+SlapdPreInstall::SlapdPreInstall(int argc, char **argv) : _reconfig(False)
+{
+ setInstallMode(Interactive);
+ setInstallType(Typical);
+ _configured = False;
+
+ getOptions(argc, argv);
+
+}
+
+SlapdPreInstall::~SlapdPreInstall()
+{
+}
+
+void
+SlapdPreInstall::getOptions(int argc, char **argv)
+{
+ int opt;
+
+ while ((opt = getopt(argc,argv, "l:f:m:rsS")) != EOF)
+ {
+ switch (opt)
+ {
+ case 'l':
+ _logFile = strdup(optarg);
+ break;
+ case 'f':
+ _infoFile = strdup(optarg);
+ break;
+ case 's':
+ setInstallMode(Silent);
+ break;
+ case 'm':
+ setInstallType((InstallType)atoi(optarg));
+ break;
+ case 'r':
+ _reconfig = True;
+ break;
+ case 'S':
+ /*
+ * Solaris 9+ specific installation
+ */
+ iDSISolaris = 1;
+ break;
+ default:
+ fprintf(stderr, "SlapdPreInstall::getOptions(): "
+ "invalid option [%s]\n", argv[optind-1]);
+ break;
+ }
+ }
+}
+
+
+int
+SlapdPreInstall::init()
+{
+ char errMsg[40];
+ struct stat fi;
+ Bool shell = True;
+
+ _installInfo = NULL;
+ _slapdInfo = new InstallInfo;
+
+ if (installMode() != Silent)
+ {
+/* richm 20011005 - we can't do this until we get setupsdk46 - if ever
+ if (iDSISolaris)
+ Dialog::initDisplay("Directory", (const char *) NULL, "Configuration");
+ else
+*/
+ Dialog::initDisplay("Directory");
+ }
+
+ if ((installMode() == Silent && _infoFile == (char *) NULL) ||
+ (_infoFile != (char *) NULL && InstUtil::fileExists(_infoFile) == False))
+ {
+ sprintf(errMsg, "ERROR: answer cache not found\n");
+ if (installMode() == Silent)
+ {
+ printf(errMsg);
+ }
+ else
+ {
+ DialogAlert alert(errMsg);
+ alert.execute();
+ }
+ return -1;
+ }
+
+ _serverRoot = InstUtil::getCurrentDir();
+ if (installMode() != Silent)
+ {
+ if (_infoFile == (char *) NULL)
+ {
+ // Not executing from the Shell, check if this is the server
+ if (stat ("admin-serv", &fi) != 0)
+ {
+ sprintf(errMsg, "ERROR: %s is not a server root\n",_serverRoot.data());
+ DialogAlert alert(errMsg);
+ alert.execute();
+ return -1;
+ }
+ shell = False;
+ // if we are here, we are being run to reconfigure
+ _reconfig = True;
+ }
+ }
+
+ if (installMode() == Silent)
+ {
+ if (_logFile == (char *) NULL)
+ {
+ // Should have a logfile
+ _logFile = _serverRoot + "/setup/install.log";
+ }
+ _installLog = new InstallLog (_logFile);
+ }
+
+ if (shell)
+ {
+ _installInfo = new InstallInfo(_infoFile);
+ _serverRoot = _installInfo->get(SLAPD_KEY_SERVER_ROOT);
+ if (!(_adminInfo = _installInfo->getSection("admin")))
+ {
+ _adminInfo = new InstallInfo;
+ }
+ }
+ else
+ {
+ // Retrieve configuration data into installInfo
+ _infoFile = _serverRoot + "/" + "setup/install.inf";
+ _installInfo = new InstallInfo();
+ if (initDefaultConfig() == -1) {
+ const char *guess_host = InstUtil::guessHostname();
+ if (guess_host) {
+ sprintf(errMsg, "ERROR: %s is not an addressable hostname\n",
+ guess_host);
+ } else {
+ sprintf(errMsg, "ERROR: cannot determine an addressable hostname\n");
+ }
+ DialogAlert alert(errMsg);
+ alert.execute();
+ return -1;
+ }
+ if (getDNSDomain() == NULL) {
+ const char *guess_domain = InstUtil::guessDomain();
+
+ if (guess_domain == NULL) {
+ sprintf(errMsg, "ERROR: cannot determine domainname\n");
+ } else {
+ sprintf(errMsg, "ERROR: domainname is not valid for DNS\n");
+ }
+ DialogAlert alert(errMsg);
+ alert.execute();
+ return -1;
+ }
+ }
+
+ setDefaultScript(_slapdInfo);
+
+ char *url = 0;
+ char *adminid = 0;
+ char *admin_domain = 0;
+ getDefaultLdapInfo(_serverRoot, &url, &adminid, &admin_domain);
+ if (url && admin_domain) // in some cases adminid is NULL
+ {
+ if (!adminid)
+ {
+ // look up the admin ID in the config ds
+ }
+ // use these values as our default values
+ _installInfo->set(SLAPD_KEY_K_LDAP_URL, url);
+ if (adminid)
+ {
+ _installInfo->set(SLAPD_KEY_SERVER_ADMIN_ID, adminid);
+ }
+ _installInfo->set(SLAPD_KEY_ADMIN_DOMAIN, admin_domain);
+ // since this server root is already configured to use
+ // an existing configuration directory server, we will
+ // not allow the user to install another one here, so
+ // the directory server created here will be a user
+ // directory; we will still need to ask for the admin
+ // user password
+ _slapdInfo->set(SLAPD_KEY_USE_EXISTING_MC, "Yes");
+ _slapdInfo->set(SLAPD_KEY_USE_EXISTING_UG, "No");
+ _slapdInfo->set(SLAPD_KEY_SLAPD_CONFIG_FOR_MC, "No");
+ }
+ else
+ {
+ _slapdInfo->set(SLAPD_KEY_SLAPD_CONFIG_FOR_MC, "Yes");
+ }
+
+ return 0;
+}
+/*
+ * PVO
+ */
+
+int
+SlapdPreInstall::initDefaultConfig()
+{
+ // PVO - should read from DS instead
+ if (_adminInfo->isEmpty())
+ {
+ const char *guess_host = InstUtil::guessHostname();
+
+ if (guess_host) {
+#if defined(__sun) || defined(__hppa) || defined(__osf__) || defined(__linux__) || defined(linux)
+ static char test_host[BIG_BUF] = {0};
+ struct hostent *hp;
+
+ strcpy(test_host,guess_host);
+ hp = gethostbyname(test_host);
+ if (hp == NULL) {
+ return -1;
+ }
+#endif
+ }
+ _installInfo->set(SLAPD_KEY_SERVER_ROOT, _serverRoot);
+ _installInfo->set(SLAPD_KEY_FULL_MACHINE_NAME, guess_host);
+ _installInfo->set(SLAPD_KEY_K_LDAP_URL, NSString("ldap://")
+ + guess_host
+ + "/"
+ + DEFAULT_LDAP_SUFFIX);
+ _installInfo->set(SLAPD_KEY_SUITESPOT_USERID, DEFAULT_SSUSER);
+ _installInfo->set(SS_GROUP, DEFAULT_SSGROUP);
+ }
+ else
+ {
+ _configured = True;
+ }
+ return 0;
+}
+
+inline void
+changeIndex(int &ii, int incr, int min, int max)
+{
+ ii += incr;
+ if (ii < min)
+ ii = min;
+ if (ii > max)
+ ii = max;
+}
+
+int
+SlapdPreInstall::start()
+{
+ // if we're in silent install mode, don't execute any of the dialogs, just
+ // assume the user knows what he/she is doing . . .
+ if (installMode() == Silent)
+ {
+ if (_reconfig)
+ shutdownServers();
+ return 0;
+ }
+
+ // only enable win mode if we are not doing a silent install because
+ // it messes up terminal settings
+ enableWinMode();
+
+ DialogAction action = DIALOG_NEXT;
+ int err = 0;
+ Dialog *advancedDialogList[] = {
+ &askUseExistingMC,
+ &askMCHost,
+ &askMCPort,
+ &askMCDN,
+ &askMCAdminDomain,
+ &askUseExistingUG,
+ &askUGHost,
+ &askUGPort,
+ &askUGSuffix,
+ &askUGDN,
+ &askSlapdPort,
+ &askSlapdServerID,
+ &askMCAdminID,
+ &askSlapdSuffix,
+ &askSlapdRootDN,
+ &askAdminDomain,
+ /*
+ &askReplication,
+ &askSIR,
+ &askChangeLogSuffix,
+ &askChangeLogDir,
+ &askConsumerDN,
+ &askSIRHost,
+ &askSIRPort,
+ &askSIRDN,
+ &askSIRSuffix,
+ &askSIRDays,
+ &askSIRTimes,
+ &askCIR,
+ &askCIRHost,
+ &askCIRPort,
+ &askCIRDN,
+ &askCIRSuffix,
+ &askCIRInterval,
+ &askCIRDays,
+ &askCIRTimes,
+ &askReplicationDN,
+ */
+ &askSample,
+ &askPopulate,
+ &askDisableSchemaChecking
+ };
+ Dialog *advancedDialogLiteList[] = {
+ &askUseExistingMC,
+ &askMCHost,
+ &askMCPort,
+ &askMCDN,
+ &askMCAdminDomain,
+ &askUseExistingUG,
+ &askUGHost,
+ &askUGPort,
+ &askUGSuffix,
+ &askUGDN,
+ &askSlapdPort,
+ &askSlapdServerID,
+ &askMCAdminID,
+ &askSlapdSuffix,
+ &askSlapdRootDN,
+ &askAdminDomain,
+ &askSample,
+ &askPopulate,
+ &askDisableSchemaChecking
+ };
+ Dialog *advancediDSISolarisForceUGDialogList[] = {
+ &askSlapdPort,
+ &askSlapdServerID,
+ &askMCHost,
+ &askMCPort,
+ &askMCDN,
+ &askSlapdSuffix,
+ &askSlapdRootDN,
+ &askSample,
+ &askPopulate,
+ &askDisableSchemaChecking
+ };
+ Dialog *normalDialogList[] = {
+ &askUseExistingMC,
+ &askMCHost,
+ &askMCPort,
+ &askMCDN,
+ &askUseExistingUG,
+ &askUGHost,
+ &askUGPort,
+ &askUGSuffix,
+ &askUGDN,
+ &askSlapdPort,
+ &askSlapdServerID,
+ &askMCAdminID,
+ &askSlapdSuffix,
+ &askSlapdRootDN,
+ &askAdminDomain
+ };
+ Dialog *normalForceUGDialogList[] = {
+ &askSlapdPort,
+ &askSlapdServerID,
+ &askMCDN,
+ &askSlapdSuffix,
+ &askSlapdRootDN
+ };
+ Dialog *normaliDSISolarisForceUGDialogList[] = {
+ &askSlapdPort,
+ &askSlapdServerID,
+ &askMCHost,
+ &askMCPort,
+ &askMCDN,
+ &askSlapdSuffix,
+ &askSlapdRootDN
+ };
+ Dialog *expressDialogList[] = {
+ &askMCAdminID,
+ &askSlapdRootDN
+ };
+ Dialog *expressForceUGDialogList[] = {
+ &askMCDN,
+ &askSlapdRootDN
+ };
+ Dialog *expressiDSISolarisForceUGDialogList[] = {
+ &askMCHost,
+ &askMCPort,
+ &askMCDN,
+ &askSlapdRootDN
+ };
+ Dialog *reconfigDialogList[] = {
+ &askReconfigMCAdminPwd
+ };
+ const int nNormalDialogs = sizeof(normalDialogList) / sizeof(normalDialogList[0]);
+ const int nExpressDialogs = sizeof(expressDialogList) / sizeof(expressDialogList[0]);
+ const int nExpressForceUGDialogs = sizeof(expressForceUGDialogList) / sizeof(expressForceUGDialogList[0]);
+ const int nExpressiDSISolarisForceUGDialogs = sizeof(expressiDSISolarisForceUGDialogList) / sizeof(expressiDSISolarisForceUGDialogList[0]);
+ const int nAdvancedDialogs = sizeof(advancedDialogList) / sizeof(advancedDialogList[0]);
+ const int nAdvancedLiteDialogs = sizeof(advancedDialogLiteList) / sizeof(advancedDialogLiteList[0]);
+ const int nAdvancediDSISolarisForceUGDialogs = sizeof(advancediDSISolarisForceUGDialogList) / sizeof(advancediDSISolarisForceUGDialogList[0]);
+ const int nReconfigDialogs = sizeof(reconfigDialogList) / sizeof(reconfigDialogList[0]);
+ const int nNormalForceUGDialogs = sizeof(normalForceUGDialogList) / sizeof(normalForceUGDialogList[0]);
+ const int nNormaliDSISolarisForceUGDialogs = sizeof(normaliDSISolarisForceUGDialogList) / sizeof(normaliDSISolarisForceUGDialogList[0]);
+
+ int liteMode = 0;
+ int nDialogs = nNormalDialogs;
+ Dialog** dialogList = normalDialogList;
+ if (_reconfig)
+ {
+ nDialogs = nReconfigDialogs;
+ dialogList = reconfigDialogList;
+ }
+ else if (installType() == Express)
+ {
+ nDialogs = nExpressDialogs;
+ dialogList = expressDialogList;
+ }
+ else if (installType() == Custom)
+ {
+ if (liteMode = isLiteMode())
+ {
+ nDialogs = nAdvancedLiteDialogs;
+ dialogList = advancedDialogLiteList;
+ }
+ else
+ {
+ nDialogs = nAdvancedDialogs;
+ dialogList = advancedDialogList;
+ }
+ }
+ else if (!iDSISolaris && featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ {
+ if (installType() == Typical)
+ {
+ nDialogs = nNormalForceUGDialogs;
+ dialogList = normalForceUGDialogList;
+ }
+ else if (installType() == Express)
+ {
+ nDialogs = nExpressForceUGDialogs;
+ dialogList = expressForceUGDialogList;
+ }
+ }
+
+ if (iDSISolaris && featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ {
+ if (installType() == Typical)
+ {
+ nDialogs = nNormaliDSISolarisForceUGDialogs;
+ dialogList = normaliDSISolarisForceUGDialogList;
+ }
+ else if (installType() == Express)
+ {
+ nDialogs = nExpressiDSISolarisForceUGDialogs;
+ dialogList = expressiDSISolarisForceUGDialogList;
+ }
+ else if (installType() == Custom)
+ {
+ nDialogs = nAdvancediDSISolarisForceUGDialogs;
+ dialogList = advancediDSISolarisForceUGDialogList;
+ }
+
+ }
+
+ getDefaultScript()->set(SLAPD_KEY_SECURITY_ON, "No");
+
+ int ii = 0;
+
+ // initialize all dialogs
+
+ if (!_reconfig)
+ {
+ for (ii = 0; ii < nAdvancedDialogs; ++ii)
+ {
+ advancedDialogList[ii]->registerDialogNext(this);
+ advancedDialogList[ii]->enable8BitInput();
+ // this next bit of hackery allows us to use the dialog->setup()
+ // method of each dialog to setup the default values for the
+ // .inf file; if the SETUP_ONLY flag is set, each setup() method
+ // will just return DIALOG_NEXT after setting up the default
+ // values; pretty sneaky, huh?
+ advancedDialogList[ii]->setUserData(SETUP_DEFAULTS, SETUP_ONLY);
+ advancedDialogList[ii]->setUserData(ACTION, DIALOG_NEXT);
+ advancedDialogList[ii]->execute();
+ advancedDialogList[ii]->setUserData(SETUP_DEFAULTS, (long)0);
+ }
+ advancedDialogList[nAdvancedDialogs-1]->registerDialogLast(this);
+ }
+ else
+ {
+ for (ii = 0; ii < nReconfigDialogs; ++ii)
+ {
+ reconfigDialogList[ii]->registerDialogNext(this);
+ reconfigDialogList[ii]->enable8BitInput();
+ }
+ reconfigDialogList[nReconfigDialogs-1]->registerDialogLast(this);
+ }
+
+ ii = 0;
+ int min = 0;
+ // keep looping until we hit the end
+ while (ii < nDialogs)
+ {
+ int incr = 1; // go to next by default
+ Dialog *d = dialogList[ii];
+
+ // tell the dialog what the action was that brought it here so that
+ // the dialog knows if it was called as the result of a next or
+ // a prev or whatever
+ d->setUserData(ACTION, (long)action);
+// cerr << "set action in dialog " << ii << " to " << action << endl;
+// cerr << "DIALOG_PREV, SAME, NEXT = " << DIALOG_PREV << "," << DIALOG_SAME << "," << DIALOG_NEXT << endl;
+
+ // execute the dialog
+// cerr << "executing dialog number " << ii << endl;
+ action = d->execute();
+ if (action == DIALOG_PREV)
+ {
+ incr = -1; // go to prev
+// cerr << "prev" << endl;
+ }
+ else if (action == DIALOG_SAME)
+ {
+ incr = 0; // repeat this state
+// cerr << "same" << endl;
+ }
+ else if (action != DIALOG_NEXT)
+ {
+ incr = nDialogs;
+ err = -1; // could just break here, I suppose . . .
+ }
+ else
+ {
+// cerr << "next" << endl;
+ }
+
+ changeIndex(ii, incr, min, nDialogs);
+ }
+
+ if (err == 0)
+ {
+ if (!_reconfig)
+ {
+ _installInfo->addSection("slapd", _slapdInfo);
+ if (!_installInfo->getSection("admin") && _adminInfo &&
+ !_adminInfo->isEmpty())
+ {
+ _installInfo->addSection("admin", _adminInfo);
+ delete _adminInfo;
+ _adminInfo = 0;
+ }
+
+ if (!_installInfo->get(SLAPD_KEY_K_LDAP_HOST))
+ {
+ _installInfo->set(SLAPD_KEY_K_LDAP_HOST,
+ _installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME));
+ }
+ if (!_installInfo->get(SLAPD_KEY_K_LDAP_PORT))
+ {
+ _installInfo->set(SLAPD_KEY_K_LDAP_PORT,
+ _slapdInfo->get(SLAPD_KEY_SERVER_PORT));
+ }
+ const char *test = 0;
+ if (!(test = _installInfo->get(SLAPD_KEY_BASE_SUFFIX)) || !*test)
+ {
+ // if there's no config directory suffix we must use
+ // o=NetscapeRoot
+ _installInfo->set(SLAPD_KEY_BASE_SUFFIX, DEFAULT_ROOT_DN);
+ }
+
+ // only UG directories have a user base suffix . . .
+ if (featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ _slapdInfo->remove(SLAPD_KEY_SUFFIX);
+
+ // if there is no LdapURL and other ldap info in the installInfo, write
+ // it
+ if (!_installInfo->get(SLAPD_KEY_K_LDAP_URL))
+ {
+ // construct a new LdapURL based on host, port, and suffix
+ const char *suffix = _installInfo->get(SLAPD_KEY_BASE_SUFFIX);
+ if (!suffix || !*suffix)
+ suffix = DEFAULT_ROOT_DN;
+ NSString ldapURL = NSString("ldap://") +
+ _installInfo->get(SLAPD_KEY_K_LDAP_HOST) + ":" +
+ _installInfo->get(SLAPD_KEY_K_LDAP_PORT) + "/" +
+ suffix;
+ _installInfo->set(SLAPD_KEY_K_LDAP_URL, ldapURL);
+ }
+
+ if (!featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ {
+ // if this is to be both the MC and the UG host . . .
+ if (!featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ {
+ // use the MC admin ID for the UG admin ID
+ if (!_installInfo->get(SLAPD_KEY_USER_GROUP_ADMIN_ID))
+ _installInfo->set(SLAPD_KEY_USER_GROUP_ADMIN_ID,
+ _installInfo->get(SLAPD_KEY_SERVER_ADMIN_ID));
+
+ if (!_installInfo->get(SLAPD_KEY_USER_GROUP_ADMIN_PWD))
+ _installInfo->set(SLAPD_KEY_USER_GROUP_ADMIN_PWD,
+ _installInfo->get(SLAPD_KEY_SERVER_ADMIN_PWD));
+ }
+ }
+
+ // set the ug ldap url if we need one
+ if (!_installInfo->get(SLAPD_KEY_USER_GROUP_LDAP_URL))
+ {
+ if (featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ {
+ NSString url = NSString("ldap://") +
+ _installInfo->get(SLAPD_KEY_UG_HOST) + ":" +
+ _installInfo->get(SLAPD_KEY_UG_PORT) + "/" +
+ _installInfo->get(SLAPD_KEY_UG_SUFFIX);
+ _installInfo->set(SLAPD_KEY_USER_GROUP_LDAP_URL, url);
+ }
+ else // the directory we're creating is the UG
+ {
+ NSString url = NSString("ldap://") +
+ _installInfo->get(SLAPD_KEY_FULL_MACHINE_NAME) + ":" +
+ _slapdInfo->get(SLAPD_KEY_SERVER_PORT) + "/" +
+ _slapdInfo->get(SLAPD_KEY_SUFFIX);
+ _installInfo->set(SLAPD_KEY_USER_GROUP_LDAP_URL, url);
+ }
+ }
+
+ if (!_installInfo->get(SLAPD_KEY_USER_GROUP_ADMIN_ID))
+ _installInfo->set(SLAPD_KEY_USER_GROUP_ADMIN_ID,
+ _slapdInfo->get(SLAPD_KEY_ROOTDN));
+
+ if (!_installInfo->get(SLAPD_KEY_USER_GROUP_ADMIN_PWD))
+ _installInfo->set(SLAPD_KEY_USER_GROUP_ADMIN_PWD,
+ _slapdInfo->get(SLAPD_KEY_ROOTDNPWD));
+ } else {
+ // for reconfigure, just shutdown the servers
+ shutdownServers();
+ }
+
+ // remove the fields we don't need
+ _installInfo->remove(SLAPD_KEY_K_LDAP_HOST);
+ _installInfo->remove(SLAPD_KEY_K_LDAP_PORT);
+ _installInfo->remove(SLAPD_KEY_BASE_SUFFIX);
+ _installInfo->remove(SLAPD_KEY_UG_HOST);
+ _installInfo->remove(SLAPD_KEY_UG_PORT);
+ _installInfo->remove(SLAPD_KEY_UG_SUFFIX);
+
+ // normalize and convert the DN valued attributes to LDAPv3 style
+ normalizeDNs();
+
+ // format for .inf file
+ _installInfo->setFormat(1);
+
+ // convert internally stored UTF8 to local
+ _installInfo->toLocal();
+ _installInfo->write(_infoFile);
+ }
+
+ disableWinMode();
+
+ return err;
+}
+
+int
+SlapdPreInstall::cont()
+{
+ return 0;
+}
+
+void
+SlapdPreInstall::clear()
+{
+}
+
+void
+SlapdPreInstall::add(Dialog *p)
+{
+ p = p;
+}
+void
+SlapdPreInstall::resetLast()
+{
+}
+
+void
+SlapdPreInstall::addLast(Dialog *p)
+{
+ p = p;
+}
+void
+SlapdPreInstall::setParent(void *parent)
+{
+ parent = parent;
+ return;
+}
+void *
+SlapdPreInstall::parent() const
+{
+ return (void *) this;
+}
+
+void
+SlapdPreInstall::setAdminScript(InstallInfo *script)
+{
+ _adminInfo = script;
+}
+
+InstallInfo *
+SlapdPreInstall::getAdminScript() const
+{
+ return _adminInfo;
+}
+
+InstallInfo *
+SlapdPreInstall::getBaseScript() const
+{
+ return _installInfo;
+}
+
+void
+SlapdPreInstall::showAlert(const char *msg)
+{
+ char *localMsg = UTF8ToLocal(msg);
+ DialogAlert alert(localMsg);
+ alert.execute();
+ nsSetupFree(localMsg);
+
+ return;
+}
+
+int
+SlapdPreInstall::verifyRemoteLdap(
+ const char *host,
+ const char *port,
+ const char *suffix,
+ const char *binddn,
+ const char *binddnpwd
+) const
+{
+ const char *myhost = getDefaultScript()->get(host);
+ if (!myhost)
+ myhost = getBaseScript()->get(host);
+ const char *myport = getDefaultScript()->get(port);
+ if (!myport)
+ myport = getBaseScript()->get(port);
+ const char *mysuffix = getDefaultScript()->get(suffix);
+ if (!mysuffix)
+ mysuffix = getBaseScript()->get(suffix);
+ if (!mysuffix)
+ mysuffix = DEFAULT_ROOT_DN;
+ const char *mydn = getDefaultScript()->get(binddn);
+ if (!mydn)
+ mydn = getBaseScript()->get(binddn);
+ const char *mypwd = getDefaultScript()->get(binddnpwd);
+ if (!mypwd)
+ mypwd = getBaseScript()->get(binddnpwd);
+
+ char *s = (char *)malloc(10 + strlen(myhost) + strlen(myport) +
+ ((suffix && mysuffix) ? strlen(mysuffix):0));
+ strcpy(s, "ldap://");
+ strcat(s, myhost);
+ strcat(s, ":");
+ strcat(s, myport);
+ strcat(s, "/");
+ if (suffix && mysuffix)
+ strcat(s, mysuffix);
+ int status = authLdapUser(s, mydn, mypwd, NULL, NULL);
+ free(s);
+ return status;
+}
+
+int
+SlapdPreInstall::verifyAdminDomain(
+ const char *host,
+ const char *port,
+ const char *suffix,
+ const char *admin_domain,
+ const char *binddn,
+ const char *binddnpwd
+) const
+{
+ const char *myhost = getDefaultScript()->get(host);
+ if (!myhost)
+ myhost = getBaseScript()->get(host);
+ const char *myport = getDefaultScript()->get(port);
+ if (!myport)
+ myport = getBaseScript()->get(port);
+ const char *mysuffix = getDefaultScript()->get(suffix);
+ if (!mysuffix)
+ mysuffix = getBaseScript()->get(suffix);
+ if (!mysuffix)
+ mysuffix = DEFAULT_ROOT_DN;
+ const char *mydn = getDefaultScript()->get(binddn);
+ if (!mydn)
+ mydn = getBaseScript()->get(binddn);
+ const char *mypwd = getDefaultScript()->get(binddnpwd);
+ if (!mypwd)
+ mypwd = getBaseScript()->get(binddnpwd);
+ const char *myadmin_domain = getDefaultScript()->get(admin_domain);
+ if (!myadmin_domain)
+ myadmin_domain = getBaseScript()->get(admin_domain);
+
+ char *s = (char *)malloc(10 + strlen(myhost) + strlen(myport) +
+ ((suffix && mysuffix) ? strlen(mysuffix):0));
+ strcpy(s, "ldap://");
+ strcat(s, myhost);
+ strcat(s, ":");
+ strcat(s, myport);
+ strcat(s, "/");
+ if (suffix && mysuffix)
+ strcat(s, mysuffix);
+ LdapError ldapErr;
+ Ldap ldap(ldapErr, s, mydn, mypwd);
+ int status = ldapErr;
+ if (!status && admin_domain && myadmin_domain && mysuffix)
+ {
+ LdapEntry ad(&ldap);
+ NSString dn = NSString("ou=") + myadmin_domain + ", " + mysuffix;
+ status = ad.retrieve(dn);
+ }
+
+ free(s);
+ return status;
+}
+
+const char *
+SlapdPreInstall::getDNSDomain() const
+{
+ static char domain[BIG_BUF] = {0};
+
+ if (domain[0])
+ return domain;
+
+ const char *FQDN =
+ getBaseScript()->get(SLAPD_KEY_FULL_MACHINE_NAME);
+ if (!FQDN) {
+ FQDN = InstUtil::guessHostname();
+ }
+
+ const char *ptr = NULL;
+ if (FQDN != NULL) {
+ // copy the domain name part (not the hostname) into the suffix
+ // find the last '.' in the FQDN
+ ptr = strchr(FQDN, '.');
+ }
+
+ if (FQDN == NULL || ptr == NULL) {
+ const char *guess_domain = InstUtil::guessDomain();
+
+ if (guess_domain) {
+ /* ensure domain is of at least 2 components */
+ const char *dptr = strchr(guess_domain, '.');
+ if (dptr == NULL) {
+ return NULL;
+ }
+
+ strcpy(domain, guess_domain);
+ return domain;
+ } else {
+ return NULL;
+ }
+ }
+
+ ++ptr;
+ strcpy(domain, ptr);
+
+ return domain;
+}
+
+const char *
+SlapdPreInstall::getDefaultSuffix() const
+{
+ const char *SUF = "dc=";
+ const int SUF_LEN = 3;
+ static char suffix[BIG_BUF] = {0};
+
+ if (suffix[0])
+ return suffix;
+
+ char *sptr = suffix;
+ strcat(sptr, SUF);
+ sptr += SUF_LEN;
+ for (const char *ptr = getDNSDomain(); ptr && *ptr; *ptr++) {
+ if (*ptr == '.') {
+ strcat(sptr, ", ");
+ sptr += 2;
+ strcat(sptr, SUF);
+ sptr += SUF_LEN;
+ } else {
+ *sptr++ = *ptr;
+ }
+ }
+ *sptr = 0;
+ if (!*suffix)
+ sprintf(suffix, "%s%s", SUF, "unknown-domain");
+
+ return suffix;
+}
+
+const char *
+SlapdPreInstall::getConsumerDN() const
+{
+ static char dn[BIG_BUF];
+
+ dn[0] = 0;
+ const char *suffix =
+ getDefaultScript()->get(SLAPD_KEY_SUFFIX);
+ if (suffix)
+ sprintf(dn, "cn=Replication Consumer, %s", suffix);
+ else
+ sprintf(dn, "cn=Replication Consumer");
+
+ return dn;
+}
+
+int
+SlapdPreInstall::featureIsEnabled(const char *which) const
+{
+ const char *val = getDefaultScript()->get(which);
+ if (!val)
+ val = getBaseScript()->get(which);
+ if (!val || !*val || !strncasecmp(val, "no", strlen(val)))
+ return 0; // feature is disabled
+
+ return 1; // feature is enabled
+}
+
+void
+SlapdPreInstall::shutdownServers()
+{
+ const char *nick = "slapd";
+ const char *script = "stop-slapd";
+ int len = strlen(nick);
+ const char *sroot = getBaseScript()->get(SLAPD_KEY_SERVER_ROOT);
+ if (!sroot)
+ return;
+
+ DIR* srootdir = opendir(sroot);
+ if (!srootdir)
+ return;
+
+ struct dirent* entry = 0;
+ while (entry = readdir(srootdir))
+ {
+ // look for instance directories
+ if (!strncasecmp(entry->d_name, nick, len))
+ {
+ NSString instanceDir = NSString(sroot) + "/" + entry->d_name;
+ if (InstUtil::dirExists(instanceDir))
+ {
+ NSString prog = instanceDir + "/" + script;
+ // call the stop-slapd script
+ if (InstUtil::fileExists(prog))
+ {
+ cout << "Shutting down server " << entry->d_name
+ << " . . . " << flush;
+ int status = InstUtil::execProgram(prog);
+ if (status)
+ // attempt to determine cause of failure
+ cout << "Could not shutdown server: status=" << status
+ << " error=" << errno << endl;
+ else
+ cout << "Done." << endl;
+ }
+ }
+ }
+ }
+ closedir(srootdir);
+
+ return;
+}
+
+void
+SlapdPreInstall::normalizeDNs()
+{
+ static const char *DN_VALUED_ATTRS[] = {
+ SLAPD_KEY_SUFFIX,
+ SLAPD_KEY_ROOTDN,
+ SLAPD_KEY_CIR_SUFFIX,
+ SLAPD_KEY_CIR_BINDDN,
+ 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->remove(attr);
+ _slapdInfo->set(attr, dn_normalize_convert(dn));
+ fflush(stdout);
+ 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));
+ if (dn)
+ {
+ char port[6];
+ sprintf(port, "%d", desc->lud_port);
+ NSString newurl = NSString("ldap://") + desc->lud_host +
+ ":" + port + "/" + dn;
+ _installInfo->set(attr, newurl);
+ delete [] dn;
+ }
+ }
+ if (desc)
+ ldap_free_urldesc(desc);
+ }
+}
diff --git a/ldap/cm/newinst/ux-config.h b/ldap/cm/newinst/ux-config.h
new file mode 100644
index 00000000..dbce264a
--- /dev/null
+++ b/ldap/cm/newinst/ux-config.h
@@ -0,0 +1,172 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*********************************************************************
+**
+**
+** NAME:
+** ux-config.h
+**
+** DESCRIPTION:
+** Netscape Directory Server Pre-installation Program
+**
+** NOTES:
+**
+** HISTORY:
+** $Log: ux-config.h,v $
+** Revision 1.1 2005/01/21 00:40:49 cvsadm
+** Initial revision
+**
+** Revision 1.1.2.6.8.9 2005/01/14 01:22:10 nhosoi
+** For the open-source project.
+** 1) eliminated 'netsite' level
+** 2) moved ns/config one level lower
+** 3) moved fasttime to lib/base
+**
+** Revision 1.1.2.6.8.8 2003/09/22 19:38:51 ulfw
+** Update copyright years from 2001 to 2001-2003
+**
+** Revision 1.1.2.6.8.7 2001/11/02 23:32:56 richm
+** XXX use new copyright XXX
+**
+** Revision 1.1.2.6.8.6 2001/10/06 20:01:04 richm
+** ldapserver/ldap/cm/newinst/ux-config.h
+** 1.1.2.6.8.5
+** 20010918
+**
+** Remove copyright caracter form copyright
+**
+**
+** ====================================================
+**
+** Revision 1.1.2.6.8.5 2001/09/21 15:25:29 richm
+** rebrand to Netscape and change version to 6.0
+**
+** Revision 1.1.2.6.8.4 2001/02/13 09:40:08 rmarco
+** copyrights
+**
+** Revision 1.1.2.6.8.3 2000/08/22 10:07:32 elp
+** First bunch of branding fixes.
+** Replaced 'Netscape Directory Server' by 'iPlanet Directory Server'.
+**
+** Revision 1.1.2.6.8.2 2000/08/08 19:34:10 mwahl
+** ensure domainname is valid before beginning install
+**
+** Revision 1.1.2.6.8.1 1999/02/23 02:14:08 ggood
+** Merge changes made on server4_directory_branch after 4.0 RTM to DirectoryBranch
+**
+** Revision 1.1.2.7 1998/11/25 02:07:59 rweltman
+** Merging from DS 4.0 RTM into server4_directory_branch
+**
+** Revision 1.1.2.6.4.2 1998/11/06 21:33:15 richm
+** added normalizeDNs
+**
+** Revision 1.1.2.6.4.1 1998/10/15 18:23:05 richm
+** check for bogus admin domain
+**
+** Revision 1.1.2.6 1998/07/23 21:32:39 richm
+** allow re-installation into existing server root
+**
+** Revision 1.1.2.5 1998/06/15 23:52:08 richm
+** added support for user/group separation, better flow control, and support for AS 0611
+**
+** Revision 1.1.2.4 1997/12/17 21:10:19 richm
+** updated for minor 19971216 changes to admin setup sdk
+**
+** Revision 1.1.2.3 1997/12/06 01:43:18 richm
+** upgraded to latest changes from 12.03 admin
+**
+** Revision 1.1.2.2 1997/11/12 23:42:57 richm
+** updates for unix installer
+**
+** Revision 1.1.2.1 1997/11/04 01:57:53 richm
+** Kingpin UNIX installation modules
+**
+** Revision 1.1.2.4 1997/10/22 02:46:08 pvo
+** Removed restore().
+**
+** Revision 1.1.2.3 1997/10/01 17:24:11 pvo
+** Changed include path.
+**
+** Revision 1.1.2.2 1997/09/27 02:43:39 pvo
+** Check in.
+**
+**
+*********************************************************************/
+#include "dialog.h"
+#include "ux-util.h"
+extern const char *DEFAULT_SYSUSER;
+extern const char *DEFAULT_OLDROOT;
+
+
+class SlapdPreInstall:public DialogManager
+{
+public:
+
+ SlapdPreInstall(int, char **);
+ ~SlapdPreInstall();
+
+ int init();
+
+ int start();
+ void add (Dialog *);
+ void addLast(Dialog *);
+ void resetLast();
+ void clear();
+ int cont();
+ void setParent(void *);
+ void *parent() const;
+
+ void setAdminScript(InstallInfo *script);
+ InstallInfo *getAdminScript() const;
+
+ InstallInfo *getBaseScript() const;
+
+ int verifyRemoteLdap(const char *host, const char *port, const char *suffix,
+ const char *binddn, const char *binddnpwd) const;
+
+ int verifyAdminDomain(const char *host, const char *port, const char *suffix,
+ const char *admin_domain,
+ const char *binddn, const char *binddnpwd) const;
+
+ const char *getDNSDomain() const;
+ const char *getDefaultSuffix() const;
+ const char *getConsumerDN() const;
+ int featureIsEnabled(const char *which) const;
+
+ static void showAlert(const char *msg);
+
+private:
+
+ NSString _serverRoot;
+
+ NSString _infoFile;
+ InstallInfo *_installInfo;
+ InstallInfo *_slapdInfo;
+ InstallInfo *_adminInfo;
+
+ NSString _logFile;
+ InstallLog *_installLog;
+
+ Bool _configured;
+ Bool _reconfig;
+
+
+ void getOptions(int argc, char **argv);
+ int initDefaultConfig();
+
+ void shutdownServers();
+
+ void normalizeDNs();
+};
+
+typedef SlapdPreInstall DialogManagerType;
+
+inline DialogManagerType*
+getManager(Dialog *me)
+{
+ return (DialogManagerType*)me->manager();
+}
+
diff --git a/ldap/cm/newinst/ux-dialog.cc b/ldap/cm/newinst/ux-dialog.cc
new file mode 100644
index 00000000..30ca68c8
--- /dev/null
+++ b/ldap/cm/newinst/ux-dialog.cc
@@ -0,0 +1,4332 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*********************************************************************
+**
+** NAME:
+** ux-dialog.cc
+**
+** DESCRIPTION:
+** Netscape Directory Server Pre-installation Program
+** Definitions for UI dialogs.
+**
+** NOTES:
+**
+**
+*********************************************************************/
+
+#include <errno.h>
+#include <iostream.h>
+#include <fstream.h>
+/* Newer g++ wants the new std header forms */
+#if defined( Linux )
+#include <strstream>
+using std::ostrstream;
+/* But some platforms won't accept those (specifically HP-UX aCC */
+#else
+#include <strstream.h>
+#endif
+#include <stdio.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <string.h>
+#include <strings.h>
+#include "utf8.h"
+#include "ux-util.h"
+#include "dialog.h"
+#include "ux-dialog.h"
+#include "ux-config.h"
+#include "install_keywords.h"
+extern "C" {
+#include "dsalib.h"
+}
+
+static const char *DEFAULT_SLAPDUSER = "cn=Directory Manager";
+
+// #define DEBUG 2
+
+/*
+** Forward References
+*/
+
+static DialogAction yesNoDefaultNo (const char *answer);
+static DialogAction askReconfigNext (Dialog *me);
+static DialogAction askSlapdServerNameSetup (Dialog *me);
+static DialogAction askSlapdServerNameNext(Dialog *me);
+static DialogAction askAdminPortSetup (Dialog *me);
+static DialogAction askAdminPortNext(Dialog *me);
+static DialogAction askSlapdPortSetup (Dialog *me);
+static DialogAction askSlapdPortNext(Dialog *me);
+static DialogAction askSecurityNext (Dialog *me);
+static DialogAction askSlapdSecPortSetup (Dialog *me);
+static DialogAction askSlapdSecPortNext(Dialog *me);
+static DialogAction askSlapdServerIDSetup (Dialog *me);
+static DialogAction askSlapdServerIDNext(Dialog *me);
+static DialogAction askSr2xInfoSetup(Dialog *me);
+static DialogAction askSr2xInfoNext(Dialog *me);
+static DialogAction askSlapdRootDNSetup(Dialog *me);
+static DialogAction askSlapdRootDNNext (Dialog *me);
+static DialogAction askSlapdSysUserSetup (Dialog *me);
+static DialogAction askSlapdSysUserNext (Dialog *me);
+static DialogAction askConfigForMCNext (Dialog *me);
+static DialogAction askMCAdminIDSetup (Dialog *me);
+static DialogAction askMCAdminIDNext (Dialog *me);
+static DialogAction askReconfigMCAdminPwdSetup (Dialog *me);
+static DialogAction askReconfigMCAdminPwdNext (Dialog *me);
+static DialogAction askSlapdSuffixSetup (Dialog *me);
+static DialogAction askSlapdSuffixNext (Dialog *me);
+static DialogAction askSampleSetup (Dialog *me);
+static DialogAction askSampleNext (Dialog *me);
+static DialogAction askPopulateSetup (Dialog *me);
+static DialogAction askPopulateNext (Dialog *me);
+static DialogAction askOrgSizeSetup (Dialog *me);
+static DialogAction askOrgSizeNext (Dialog *me);
+static DialogAction askCIRSetup(Dialog *me);
+static DialogAction askCIRNext(Dialog *me);
+static DialogAction askCIRHostSetup(Dialog *me);
+static DialogAction askCIRHostNext(Dialog *me);
+static DialogAction askCIRPortSetup(Dialog *me);
+static DialogAction askCIRPortNext(Dialog *me);
+static DialogAction askCIRDNSetup(Dialog *me);
+static DialogAction askCIRDNNext(Dialog *me);
+static DialogAction askCIRSuffixSetup(Dialog *me);
+static DialogAction askCIRSuffixNext(Dialog *me);
+static DialogAction askCIRSSLSetup(Dialog *me);
+static DialogAction askCIRSSLNext(Dialog *me);
+static DialogAction askCIRIntervalSetup(Dialog *me);
+static DialogAction askCIRIntervalNext(Dialog *me);
+static DialogAction askCIRDaysSetup(Dialog *me);
+static DialogAction askCIRDaysNext(Dialog *me);
+static DialogAction askCIRTimesSetup(Dialog *me);
+static DialogAction askCIRTimesNext(Dialog *me);
+static DialogAction askSIRSetup(Dialog *me);
+static DialogAction askSIRNext(Dialog *me);
+static DialogAction askChangeLogSuffixSetup(Dialog *me);
+static DialogAction askChangeLogSuffixNext(Dialog *me);
+static DialogAction askChangeLogDirSetup(Dialog *me);
+static DialogAction askChangeLogDirNext(Dialog *me);
+static DialogAction askReplicationDNSetup(Dialog *me);
+static DialogAction askReplicationDNNext(Dialog *me);
+static DialogAction askReplicationSetup(Dialog *me);
+static DialogAction askReplicationNext(Dialog *me);
+static DialogAction askConsumerDNSetup(Dialog *me);
+static DialogAction askConsumerDNNext(Dialog *me);
+static DialogAction askSIRHostSetup(Dialog *me);
+static DialogAction askSIRHostNext(Dialog *me);
+static DialogAction askSIRPortSetup(Dialog *me);
+static DialogAction askSIRPortNext(Dialog *me);
+static DialogAction askSIRDNSetup(Dialog *me);
+static DialogAction askSIRDNNext(Dialog *me);
+static DialogAction askSIRSuffixSetup(Dialog *me);
+static DialogAction askSIRSuffixNext(Dialog *me);
+static DialogAction askSIRSSLSetup(Dialog *me);
+static DialogAction askSIRSSLNext(Dialog *me);
+static DialogAction askSIRDaysSetup(Dialog *me);
+static DialogAction askSIRDaysNext(Dialog *me);
+static DialogAction askSIRTimesSetup(Dialog *me);
+static DialogAction askSIRTimesNext(Dialog *me);
+static DialogAction askUseExistingMCSetup(Dialog *me);
+static DialogAction askUseExistingMCNext(Dialog *me);
+static DialogAction askMCHostSetup(Dialog *me);
+static DialogAction askMCHostNext(Dialog *me);
+static DialogAction askMCPortSetup(Dialog *me);
+static DialogAction askMCPortNext(Dialog *me);
+static DialogAction askMCDNSetup(Dialog *me);
+static DialogAction askMCDNNext(Dialog *me);
+static DialogAction askDisableSchemaCheckingSetup(Dialog *me);
+static DialogAction askDisableSchemaCheckingNext(Dialog *me);
+static DialogAction askMCAdminDomainSetup(Dialog *me);
+static DialogAction askMCAdminDomainNext(Dialog *me);
+static DialogAction askAdminDomainSetup(Dialog *me);
+static DialogAction askAdminDomainNext(Dialog *me);
+static DialogAction askUseExistingUGSetup(Dialog *me);
+static DialogAction askUseExistingUGNext(Dialog *me);
+static DialogAction askUGHostSetup(Dialog *me);
+static DialogAction askUGHostNext(Dialog *me);
+static DialogAction askUGPortSetup(Dialog *me);
+static DialogAction askUGPortNext(Dialog *me);
+static DialogAction askUGDNSetup(Dialog *me);
+static DialogAction askUGDNNext(Dialog *me);
+static DialogAction askUGSuffixSetup(Dialog *me);
+static DialogAction askUGSuffixNext(Dialog *me);
+
+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] ||
+ !*rdnNoTypes[0] || !strcasecmp(rdnList[0], rdnNoTypes[0]))
+ {
+ ret = 0;
+ }
+ if (rdnList)
+ ldap_value_free(rdnList);
+ if (rdnNoTypes)
+ ldap_value_free(rdnNoTypes);
+ }
+
+ if ((ret == 1) && ds_dn_uses_LDAPv2_quoting(dn_to_test))
+ {
+ char *newdn = strdup(dn_to_test);
+ dn_normalize_convert(newdn);
+ char *oldlocaldn = UTF8ToLocal(dn_to_test);
+ char *newlocaldn = UTF8ToLocal(newdn);
+ free(newdn);
+ NSString msg = NSString(
+ "The given value [") + oldlocaldn + "] is quoted in the deprecated LDAPv2 style\n" +
+ "quoting format. It will be automatically converted to use the\n" +
+ "LDAPv3 style escaped format [" + newlocaldn + "].";
+ DialogManagerType::showAlert(msg);
+ nsSetupFree(oldlocaldn);
+ nsSetupFree(newlocaldn);
+ }
+
+ return ret;
+}
+
+static int
+contains8BitChars(const char *s)
+{
+ int ret = 0;
+
+ if (s && *s)
+ {
+ for (; !ret && *s; ++s)
+ {
+ ret = (*s & 0x80);
+ }
+ }
+
+ return ret;
+}
+
+static int
+rootDNPwdIsValid(const char *pwd)
+{
+ if (!pwd || !*pwd || (strlen(pwd) < 8))
+ return 0;
+
+ return !contains8BitChars(pwd);
+}
+
+static int
+isValid(const char *s)
+{
+ if (!s)
+ return 1; // null is a valid response (means to accept default)
+
+ int ret = 1;
+
+ char *ncs = (char *)s; // cast away const-ness for ldaputf8 stuff
+ // trim spaces from the beginning of the string
+ while (*ncs && ldap_utf8isspace(ncs))
+ LDAP_UTF8INC(ncs);
+
+ if (!*ncs) // empty string or all spaces
+ ret = 0;
+
+ return ret;
+}
+
+static int
+isValidServerID(const char *s)
+{
+ if (!s || !*s)
+ return 0;
+
+ if (!isValid(s))
+ return 0;
+
+ if (contains8BitChars(s))
+ return 0;
+
+ // server ID should contain alphanum, _, -, . since it will
+ // be used for both a filename and a DN component
+ const char *badChars = "`~!@#$%^&*()[]|\\\"\':;,+=/<>?";
+ const char *p = s;
+ for (; *p && !strchr(badChars, *p); ++p)
+ ;
+
+ if (!*p) // the string contains all valid chars
+ return 1;
+
+ return 0;
+}
+
+static int
+isValidYesNo(const char *s)
+{
+ if (!s)
+ return 1; // null means accept default
+
+ const char *msg = 0;
+ if (isValid(s))
+ {
+ int len = strlen(s);
+ if (strncasecmp(s, "yes", len) && strncasecmp(s, "no", len))
+ {
+ msg = "Please type yes or no.";
+ }
+ }
+ else
+ {
+ msg = "Please specify a valid string.";
+ }
+
+ if (msg)
+ {
+ DialogManagerType::showAlert(msg);
+ return 0;
+ }
+
+ return 1;
+}
+
+static DialogAction
+yesNoDefaultNo(const char *answer)
+{
+ if (answer[0] == '\0' || answer[0] == '\n')
+ return DIALOG_EXIT;
+ else if (answer[0] != 'y' && answer[0] != 'Y')
+ return DIALOG_EXIT;
+ else
+ return DIALOG_NEXT;
+}
+
+static int
+dialogSetup (Dialog *me, const char *which, const char *defaultAns)
+{
+ const char *ans = getManager(me)->getDefaultScript()->get(which);
+ if (!ans)
+ ans = getManager(me)->getAdminScript()->get(which);
+ if (!ans)
+ ans = getManager(me)->getBaseScript()->get(which);
+
+ int status;
+ if (ans == NULL)
+ status = 0;
+ else
+ status = 1;
+/*
+ int status = (int)ans; // 0 - there was already a value in the script
+ // not zero - no value already in script
+*/
+ if (ans)
+ me->setDefaultAns(ans);
+ else if (defaultAns)
+ me->setDefaultAns(defaultAns);
+
+ return status;
+}
+
+DialogInput askSlapdPort(
+"The standard directory server network port number is 389. However, if\n"
+"you are not logged as the superuser, or port 389 is in use, the\n"
+"default value will be a random unused port number greater than 1024.\n"
+"If you want to use port 389, make sure that you are logged in as the\n"
+"superuser, that port 389 is not in use, and that you run the admin\n"
+"server as the superuser.\n",
+
+"Directory server network port",
+
+NULL,
+
+askSlapdPortSetup,
+askSlapdPortNext
+);
+
+static DialogAction
+askSlapdPortSetup(Dialog *me)
+{
+#if DEBUG > 1
+ cerr << "Entering askSlapdPortSetup" << endl;
+#endif
+ char tmp[10];
+ int port = 389;
+ const char *defPort =
+ getManager(me)->getDefaultScript()->get(SLAPD_KEY_SERVER_PORT);
+
+ if (defPort && *defPort && atoi(defPort) > 0)
+ {
+ strcpy(tmp, defPort);
+ port = atoi(defPort);
+ }
+ else
+ sprintf(tmp, "%d", port);
+
+ // see if default port is available
+ if (InstUtil::portAvailable(port) == False)
+ {
+ // start with a random port number, and keep going until we find
+ // an available port
+ int origport = port = InstUtil::guessPort();
+ while (InstUtil::portAvailable(port) == False)
+ {
+ ++port;
+ if (port > MAXPORT)
+ port = MINPORT;
+ if (port == origport)
+ {
+ port = -1; // NO AVAILABLE PORTS!!!!!!!
+ break;
+ }
+ }
+ }
+
+ if (port == -1) // NO AVAILABLE PORTS!!!!!!!
+ {
+#if DEBUG > 1
+ cerr << "Leaving askSlapdPortSetup DIALOG_ERROR" << endl;
+#endif
+ return DIALOG_ERROR;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SERVER_PORT, (long)port);
+
+ dialogSetup(me, SLAPD_KEY_SERVER_PORT, tmp);
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ {
+#if DEBUG > 1
+ cerr << "Leaving askSlapdPortSetup DIALOG_NEXT" << endl;
+#endif
+ return DIALOG_NEXT;
+ }
+
+#if DEBUG > 1
+ cerr << "Leaving askSlapdPortSetup DIALOG_SAME" << endl;
+#endif
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSlapdPortNext(Dialog *me)
+{
+#if DEBUG > 1
+ cerr << "Entering askSlapdPortNext" << endl;
+#endif
+ const char *buf = me->input();
+ const char *tmp;
+ char testbuf[1024];
+ int port, err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SERVER_PORT, tmp);
+
+ port = atoi(tmp);
+ sprintf(testbuf, "%d", port);
+ if (strncmp(testbuf, tmp, 6) || port > MAXPORT || port < 1)
+ {
+ sprintf(testbuf, "OVERFLOW ERROR: Unable to bind to port %d\n"
+ "Please choose another port between 1 and %d.\n\n",
+ port, MAXPORT);
+ err = -1;
+ }
+ else if (InstUtil::portAvailable(port) == False)
+ {
+ sprintf(testbuf, "ERROR: Unable to bind to port %d\n"
+ "Please choose another port.\n\n", port);
+ err = -1;
+ }
+
+ if (err)
+ {
+ DialogManagerType::showAlert(testbuf);
+ return DIALOG_SAME;
+ }
+
+#if DEBUG > 1
+ cerr << "Leaving askSlapdPortNext" << endl;
+#endif
+ return DIALOG_NEXT;
+}
+
+DialogInput askSlapdServerID(
+"Each instance of a directory server requires a unique identifier.\n"
+"Press Enter to accept the default, or type in another name and press\n"
+"Enter.\n",
+
+"Directory server identifier",
+
+NULL,
+
+askSlapdServerIDSetup,
+askSlapdServerIDNext
+);
+
+static DialogAction
+askSlapdServerIDSetup(Dialog *me)
+{
+#if DEBUG > 1
+ cerr << "Entering askSlapdServerIDSetup" << endl;
+#endif
+ // extract the hostname part of the FQDN
+ const char *tmp = 0;
+ char *basehost = 0;
+ if (tmp = getManager(me)->getBaseScript()->get(SLAPD_KEY_FULL_MACHINE_NAME)) {
+ basehost = strdup(tmp);
+ } else {
+ basehost = strdup(InstUtil::guessHostname());
+ }
+ if (!basehost)
+ return DIALOG_ERROR;
+ char *ptr = strchr(basehost, '.');
+ if (ptr)
+ {
+ *ptr = 0;
+ }
+ else
+ {
+ free(basehost);
+ basehost = 0;
+ }
+
+ const char *ans =
+ getManager(me)->getDefaultScript()->get(SLAPD_KEY_SERVER_IDENTIFIER);
+
+ if (!ans && basehost)
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SERVER_IDENTIFIER,
+ basehost);
+ else if (!ans && !basehost)
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SERVER_IDENTIFIER,
+ InstUtil::guessHostname());
+
+ if (ans)
+ {
+ me->setDefaultAns(ans);
+ }
+ else if (basehost)
+ {
+ me->setDefaultAns(basehost);
+ }
+ else
+ {
+ me->setDefaultAns(InstUtil::guessHostname());
+ }
+
+ if (basehost)
+ free(basehost);
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ {
+#if DEBUG > 1
+ cerr << "Leaving askSlapdServerIDSetup DIALOG_SAME" << endl;
+#endif
+ return DIALOG_NEXT;
+ }
+
+#if DEBUG > 1
+ cerr << "Leaving askSlapdServerIDSetup DIALOG_SAME" << endl;
+#endif
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSlapdServerIDNext(Dialog *me)
+{
+ const char *ans =
+ getManager(me)->getDefaultScript()->get(SLAPD_KEY_SERVER_IDENTIFIER);
+
+ const char *buf = me->input();
+ const char *tmp;
+ char testbuf[1024];
+ int err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ if (!tmp)
+ {
+ err = -1;
+ sprintf(testbuf, "The name must not be empty");
+ }
+ else if (!isValid(tmp))
+ {
+ err = -1;
+ sprintf(testbuf, "Please specify a valid value for the name.");
+ }
+ else if (contains8BitChars(tmp))
+ {
+ err = -1;
+ sprintf(testbuf, "The server ID must contain 7 bit ascii only.");
+ }
+ else if (!isValidServerID(tmp))
+ {
+ err = -1;
+ sprintf(testbuf, "The server ID must be a valid filename and DN component.");
+ }
+
+ if (!err)
+ {
+ // see if an instance by the same name already exists
+
+ NSString instanceDir = NSString(
+ getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ROOT)
+ ) + "/slapd-" + tmp;
+ if (InstUtil::fileExists(instanceDir))
+ {
+ sprintf(testbuf, "ERROR: a server instance named [%s] already exists."
+ " Please choose a unique name.\n", tmp);
+ err = -1;
+ }
+ }
+
+ if (tmp)
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SERVER_IDENTIFIER, tmp);
+
+ if (err)
+ {
+ DialogManagerType::showAlert(testbuf);
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askMCAdminID(
+"Please enter the administrator ID for the Netscape configuration\n"
+"directory server. This is the ID typically used to log in to the\n"
+"console. You will also be prompted for the password.\n",
+
+"Netscape configuration directory server\nadministrator ID",
+
+"admin",
+
+askMCAdminIDSetup,
+askMCAdminIDNext
+);
+
+static DialogAction
+askMCAdminIDSetup(Dialog *me)
+{
+#if DEBUG > 1
+ cerr << "Entering askMCAdminIDSetup" << endl;
+#endif
+ if (getManager(me)->getAdminScript() &&
+ getManager(me)->getAdminScript()->get(SLAPD_KEY_ADMIN_SERVER_ID) &&
+ getManager(me)->getAdminScript()->get(SLAPD_KEY_ADMIN_SERVER_PWD))
+ {
+ // see if the MC Admin ID has been provided
+ if (getManager(me)->getBaseScript() &&
+ !(getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ADMIN_ID) &&
+ getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ADMIN_PWD)))
+ {
+ getManager(me)->getBaseScript()->set(
+ SLAPD_KEY_SERVER_ADMIN_ID,
+ getManager(me)->getAdminScript()->get(SLAPD_KEY_ADMIN_SERVER_ID)
+ );
+ getManager(me)->getBaseScript()->set(
+ SLAPD_KEY_SERVER_ADMIN_PWD,
+ getManager(me)->getAdminScript()->get(SLAPD_KEY_ADMIN_SERVER_PWD)
+ );
+ }
+ }
+
+ dialogSetup(me, SLAPD_KEY_SERVER_ADMIN_ID, "admin");
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ {
+#if DEBUG > 1
+ cerr << "Leaving askMCAdminIDSetup setup DIALOG_NEXT" << endl;
+#endif
+ return DIALOG_NEXT;
+ }
+
+ // this dialog is only used for creating the MC Admin; don't use it if
+ // we will be using an existing MC i.e. we are not creating the MC host
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ {
+#if DEBUG > 1
+ cerr << "Leaving askMCAdminIDSetup DIALOG_NEXT" << endl;
+#endif
+ return action;
+ }
+
+#if DEBUG > 1
+ cerr << "Leaving askMCAdminIDSetup DIALOG_SAME" << endl;
+#endif
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askMCAdminIDNext(Dialog *me)
+{
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return DIALOG_NEXT;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ {
+#if DEBUG > 1
+ cerr << "Leaving askMCAdminIDNext setup DIALOG_NEXT" << endl;
+#endif
+ return DIALOG_NEXT;
+ }
+
+ const char *adminUser;
+ const char *adminPwd;
+ const char *buf;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ {
+ adminUser = me->defaultAns();
+ }
+ else
+ {
+ adminUser = buf;
+ }
+
+ if (!isValid(adminUser))
+ {
+ DialogManagerType::showAlert("Please enter a valid ID.");
+ return DIALOG_SAME;
+ }
+ else if (!isAValidDN(adminUser) && contains8BitChars(adminUser))
+ {
+ DialogManagerType::showAlert("The user ID value must be 7 bit ASCII only.");
+ return DIALOG_SAME;
+ }
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_SERVER_ADMIN_ID, adminUser);
+
+ while (1)
+ {
+// cerr << "before password in askMCAdminIDNext" << endl;
+ me->showString("Password: ");
+// cerr << "after password in askMCAdminIDNext" << endl;
+ if (me->getPassword () == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ char *inp = strdup(me->input());
+
+ if (inp[0] == 0)
+ {
+ continue;
+ }
+ else if (contains8BitChars(inp))
+ {
+ DialogManagerType::showAlert("Password must contain 7 bit characters only.");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(inp))
+ {
+ DialogManagerType::showAlert("Please enter a valid password.");
+ return DIALOG_SAME;
+ }
+ else
+ {
+ me->showString("Password (again): ");
+ if (me->getPassword() == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ adminPwd = me->input();
+ if (strcmp(inp,adminPwd))
+ {
+ DialogManagerType::showAlert("Passwords don't match.");
+ return DIALOG_SAME;
+ }
+ break;
+ }
+ }
+ free(inp);
+ }
+ }
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_SERVER_ADMIN_PWD, adminPwd);
+ return DIALOG_NEXT;
+}
+
+DialogInput askSlapdSuffix(
+"The suffix is the root of your directory tree. You may have more than\n"
+"one suffix.\n",
+
+"Suffix",
+
+NULL,
+
+askSlapdSuffixSetup,
+askSlapdSuffixNext
+);
+
+static DialogAction
+askSlapdSuffixSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ return action;
+
+ if (!getManager(me)->getDefaultScript()->get(SLAPD_KEY_SUFFIX)) {
+ getManager(me)->getDefaultScript()->set(
+ SLAPD_KEY_SUFFIX, getManager(me)->getDefaultSuffix());
+ }
+
+ dialogSetup(me, SLAPD_KEY_SUFFIX, getManager(me)->getDefaultSuffix());
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSlapdSuffixNext(Dialog *me)
+{
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SUFFIX, val);
+
+ // check the value to see if it is a valid DN
+ if (!isAValidDN(val))
+ {
+ DialogManagerType::showAlert("A suffix must be a valid DN.");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(val))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askSlapdRootDN(
+"Certain directory server operations require an administrative user.\n"
+"This user is referred to as the Directory Manager and typically has a\n"
+"bind Distinguished Name (DN) of cn=Directory Manager. Press Enter to\n"
+"accept the default value, or enter another DN. In either case, you\n"
+"will be prompted for the password for this user. The password must\n"
+"be at least 8 characters long.\n",
+
+"Directory Manager DN",
+
+DEFAULT_SLAPDUSER,
+
+askSlapdRootDNSetup,
+askSlapdRootDNNext
+);
+
+static DialogAction
+askSlapdRootDNSetup(Dialog *me)
+{
+ if (!getManager(me)->getDefaultScript()->get(SLAPD_KEY_ROOTDN))
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_ROOTDN,
+ DEFAULT_SLAPDUSER);
+
+ dialogSetup(me, SLAPD_KEY_ROOTDN, DEFAULT_SLAPDUSER);
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSlapdRootDNNext(Dialog *me)
+{
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ {
+#if DEBUG > 1
+ cerr << "Leaving askSlapdRootDNNext setup DIALOG_NEXT" << endl;
+#endif
+ return DIALOG_NEXT;
+ }
+
+ const char *slapdUser;
+ const char *slapdPwd;
+ const char *buf;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ {
+ slapdUser = me->defaultAns();
+ }
+ else
+ {
+ slapdUser = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_ROOTDN, slapdUser);
+
+ // check the value to see if it is a valid DN
+ if (!isAValidDN(slapdUser))
+ {
+ DialogManagerType::showAlert("The Directory Manager must be a valid DN.");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(slapdUser))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ while (1)
+ {
+// cerr << "before password in askSlapdRootDNNext" << endl;
+ me->showString("Password: ");
+// cerr << "after password in askSlapdRootDNNext" << endl;
+ if (me->getPassword () == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ char *inp = strdup(me->input());
+
+ if (inp[0] == 0)
+ {
+ continue;
+ }
+ else if (contains8BitChars(inp))
+ {
+ DialogManagerType::showAlert("Password must contain 7 bit characters only.");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(inp))
+ {
+ DialogManagerType::showAlert("Please enter a valid password.");
+ return DIALOG_SAME;
+ }
+ else
+ {
+ me->showString("Password (again): ");
+ if (me->getPassword() == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ slapdPwd = me->input();
+ if (strcmp(inp,slapdPwd))
+ {
+ DialogManagerType::showAlert("Passwords don't match.");
+ return DIALOG_SAME;
+ }
+ else if (!rootDNPwdIsValid(inp))
+ {
+ DialogManagerType::showAlert("Password must be at least 8 characters long");
+ return DIALOG_SAME;
+ }
+ break;
+ }
+ }
+ free(inp);
+ }
+ }
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_ROOTDNPWD, slapdPwd);
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askSample(
+"You may install some sample entries in this directory instance. These\n"
+"entries will be installed in a separate suffix and will not interfere\n"
+"with the normal operation of the directory server.\n",
+
+"Do you want to install the sample entries?",
+
+"No",
+
+askSampleSetup,
+askSampleNext
+);
+
+static DialogAction
+askSampleSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER))
+ return action;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSampleNext(Dialog *me)
+{
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "No";
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_ADD_SAMPLE_ENTRIES, buf);
+
+ if (!isValidYesNo(buf))
+ return DIALOG_SAME;
+
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askPopulate(
+"You may wish to populate your new directory instance with some data.\n"
+"You may already have a file in LDIF format to use or some suggested\n"
+"entries can be added. If you want to import entries from an LDIF\n"
+"file, you may type in the full path and filename at the prompt. If\n"
+"you want the install program to add the suggested entries, type the\n"
+"word suggest at the prompt. The suggested entries are common\n"
+"container entries under your specified suffix, such as ou=People and\n"
+"ou=Groups, which are commonly used to hold the entries for the persons\n"
+"and groups in your organization. If you do not want to add any of\n"
+"these entries, type the word none at the prompt.\n",
+
+"Type the full path and filename, the word suggest, or the word none\n",
+
+"none",
+
+askPopulateSetup,
+askPopulateNext
+);
+
+static DialogAction
+askPopulateSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER))
+ return action;
+
+ // if setting up a UG host, by default setup the suggested entries
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ {
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_INSTALL_LDIF_FILE,
+ "suggest");
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_ADD_ORG_ENTRIES,
+ "Yes");
+ }
+
+ dialogSetup(me, SLAPD_KEY_INSTALL_LDIF_FILE, "none");
+ me->setInputLen(1024); // it seems to get reset somewhere . . .
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askPopulateNext(Dialog *me)
+{
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "No";
+ }
+
+ if (buf && !strncasecmp(buf, "none", strlen(buf)))
+ {
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_ADD_ORG_ENTRIES, "No");
+ getManager(me)->getDefaultScript()->
+ set(SLAPD_KEY_INSTALL_LDIF_FILE, "none");
+ }
+ else if (buf && !strncasecmp(buf, "suggest", strlen(buf)))
+ {
+ getManager(me)->getDefaultScript()->
+ set(SLAPD_KEY_INSTALL_LDIF_FILE, "suggest");
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_ADD_ORG_ENTRIES, "Yes");
+ } else {
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_INSTALL_LDIF_FILE, buf);
+ if (!InstUtil::fileExists(buf))
+ {
+ NSString msg = NSString("The specified filename ") + buf + "\n" +
+ "does not exist. Please try again.\n";
+ DialogManagerType::showAlert(msg);
+ return DIALOG_SAME;
+ }
+ else
+ {
+ getManager(me)->getDefaultScript()->
+ set(SLAPD_KEY_ADD_ORG_ENTRIES, "Yes");
+ getManager(me)->getDefaultScript()->
+ set(SLAPD_KEY_INSTALL_LDIF_FILE, buf);
+ }
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askOrgSize(
+"Your directory will be populated with entries based on the size of\n"
+"your organization. The choices are small or large. Please specify 1\n"
+"for small and 2 for large.\n",
+
+"Organization size (1 or 2)",
+
+"1",
+
+askOrgSizeSetup,
+askOrgSizeNext
+);
+
+static DialogAction
+askOrgSizeSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER))
+ return action;
+
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_ADD_ORG_ENTRIES))
+ return action;
+ else if (dialogSetup(me, SLAPD_KEY_ORG_SIZE, "1") &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askOrgSizeNext(Dialog *me)
+{
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER))
+ return DIALOG_NEXT;
+
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_ADD_ORG_ENTRIES))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+ char testbuf[1024];
+ int num, err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_ORG_SIZE, tmp);
+
+ num = atoi(tmp);
+ if (num != 1 && num != 2)
+ {
+ sprintf(testbuf, "Please enter a 1 or a 2\n\n");
+ err = -1;
+ }
+
+ if (err)
+ {
+ DialogManagerType::showAlert(testbuf);
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askReplication(
+"Replication is used to duplicate all or part of a directory server to\n"
+"another directory server. This can be used for failsafe purposes, to\n"
+"ensure that the directory data is always online and up-to-date in case\n"
+"one server goes down. It is also useful for distributing directory\n"
+"data from a central main repository to remote directory servers.\n",
+
+"Do you want to configure this directory server\nto use replication?",
+
+"No",
+
+askReplicationSetup,
+askReplicationNext
+);
+
+static DialogAction
+askReplicationSetup(Dialog *me)
+{
+ me = me;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askReplicationNext(Dialog *me)
+{
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "No";
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_USE_REPLICATION, buf);
+
+ if (!isValidYesNo(buf))
+ return DIALOG_SAME;
+
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_REPLICATION))
+ {
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SETUP_SUPPLIER, "No");
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SETUP_CONSUMER, "No");
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askCIR(
+"You may want to set up your directory server as a consumer server to\n"
+"receive replicated entries from another directory server. The first\n"
+"two of the following methods configure this server as a consumer:\n\n"
+"1) The supplier server will push its entries to this server (SIR)\n"
+"2) This server will pull the entries from the supplier (CIR)\n"
+"3) This server will not be a consumer for replication (NONE)\n",
+
+"Do you want to set up this server as a consumer\n"
+"for replication? (1, 2, or 3)",
+
+"3",
+
+askCIRSetup,
+askCIRNext
+);
+
+static DialogAction
+askCIRSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_REPLICATION))
+ return action;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askCIRNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_REPLICATION))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "3";
+ }
+
+ int val = atoi(buf);
+ if (!val || val < 1 || val > 3)
+ {
+ DialogManagerType::showAlert("Please enter a 1, 2, or 3.");
+ return DIALOG_SAME;
+ }
+ else if (val == 3)
+ {
+ buf = "No";
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SETUP_CONSUMER, buf);
+
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askSIR(
+"You may want to set up your directory server as a supplier server to\n"
+"replicate its entries to another directory server. The first two of\n"
+"the following methods configure this server as a supplier:\n\n"
+"1) This server will push its entries to another one (SIR)\n"
+"2) Another server will pull entries from this one (CIR)\n"
+"3) This server will not be a supplier for replication (NONE)\n",
+
+"Do you want to set up this server as a supplier\n"
+"for replication? (1, 2, or 3)",
+
+"3",
+
+askSIRSetup,
+askSIRNext
+);
+
+static DialogAction
+askSIRSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_REPLICATION))
+ return action;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSIRNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_REPLICATION))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "3";
+ }
+
+ int val = atoi(buf);
+ if (!val || val < 1 || val > 3)
+ {
+ DialogManagerType::showAlert("Please enter a 1, 2, or 3.");
+ return DIALOG_SAME;
+ }
+ else if (val == 3)
+ {
+ buf = "No";
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SETUP_SUPPLIER, buf);
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askCIRHost(
+"Please specify the host name of the server from which the replicated\n"
+"entries will be copied.\n",
+
+"Supplier host name",
+
+0,
+
+askCIRHostSetup,
+askCIRHostNext
+);
+
+static DialogAction
+askCIRHostSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return action;
+ else if (dialogSetup(me, SLAPD_KEY_CIR_HOST, 0) &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askCIRHostNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+ int err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_HOST, tmp);
+
+ if (!tmp || !isValid(tmp))
+ {
+ DialogManagerType::showAlert("Please enter a valid hostname");
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askCIRPort(
+"Please specify the port of the server from which the replicated\n"
+"entries will be copied.\n",
+
+"Supplier port",
+
+"389",
+
+askCIRPortSetup,
+askCIRPortNext
+);
+
+static DialogAction
+askCIRPortSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return action;
+
+ const char *defaultPort = "389";
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_CIR_SECURITY_ON))
+ defaultPort = "636";
+
+ if (dialogSetup(me, SLAPD_KEY_CIR_PORT, defaultPort) &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askCIRPortNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+ char testbuf[1024];
+ int port, err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_PORT, tmp);
+
+ port = atoi(tmp);
+ sprintf(testbuf, "%d", port);
+ if (strncmp(testbuf, tmp, 6) || port > MAXPORT || port < 1)
+ {
+ sprintf(testbuf, "OVERFLOW ERROR: Unable to bind to port %d\n"
+ "Please choose another port between 1 and %d.\n\n",
+ port, MAXPORT);
+ err = -1;
+ }
+
+ if (err)
+ {
+ DialogManagerType::showAlert(testbuf);
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askCIRDN(
+"Replication requires that this consumer has access to the portion of\n"
+"the remote directory to be replicated. This requires a bind DN and\n"
+"password for access to the supplier. You will first be asked for the\n"
+"bind DN, then the password.\n",
+
+"Replication DN",
+
+NULL,
+
+askCIRDNSetup,
+askCIRDNNext
+);
+
+static DialogAction
+askCIRDNSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_CIR_BINDDN, getManager(me)->getConsumerDN()) &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askCIRDNNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return DIALOG_NEXT;
+
+ const char *slapdUser;
+ char *slapdPwd = 0;
+ const char *buf;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ {
+ slapdUser = me->defaultAns();
+ }
+ else
+ {
+ slapdUser = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_BINDDN, slapdUser);
+
+ // check to see if it is a valid DN
+ if (!isAValidDN(slapdUser))
+ {
+ DialogManagerType::showAlert("The consumer must be a valid DN.");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(slapdUser))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ while (1)
+ {
+ me->showString("Password: ");
+ if (me->getPassword () == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ char *inp = strdup(me->input());
+
+ if (inp[0] == 0)
+ {
+ free(inp);
+ continue;
+ }
+ else
+ {
+ slapdPwd = inp;
+ break;
+ }
+ }
+ }
+
+ if (slapdPwd)
+ {
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_BINDDNPWD, slapdPwd);
+ free(slapdPwd);
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askCIRSuffix(
+"Please enter the full DN of the part of the tree to replicate,\n"
+"including the suffix (e.g. ou=People, o=company.com).\n",
+
+"Enter the directory path",
+
+NULL,
+
+askCIRSuffixSetup,
+askCIRSuffixNext
+);
+
+static DialogAction
+askCIRSuffixSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_CIR_SUFFIX, getManager(me)->getDefaultSuffix()) &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askCIRSuffixNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_SUFFIX, val);
+
+ // check val to see if it is a valid DN
+ if (!isAValidDN(val))
+ {
+ DialogManagerType::showAlert("The suffix must be a valid DN.");
+ return DIALOG_SAME;
+ }
+ if (!isValid(val))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ int status;
+ if (status = getManager(me)->verifyRemoteLdap(
+ SLAPD_KEY_CIR_HOST,
+ SLAPD_KEY_CIR_PORT,
+ SLAPD_KEY_CIR_SUFFIX,
+ SLAPD_KEY_CIR_BINDDN,
+ SLAPD_KEY_CIR_BINDDNPWD
+ )
+ )
+ {
+ ostrstream msg;
+ msg << "Could not connect to ldap://"
+ << getManager(me)->getDefaultScript()->get(SLAPD_KEY_CIR_HOST)
+ << ":"
+ << getManager(me)->getDefaultScript()->get(SLAPD_KEY_CIR_PORT)
+ << "/"
+ << getManager(me)->getDefaultScript()->get(SLAPD_KEY_CIR_SUFFIX)
+ << endl << "for bind DN "
+ << getManager(me)->getDefaultScript()->get(SLAPD_KEY_CIR_BINDDN)
+ << " status = " << status << endl
+ << "Please check your typing. If you have mis-typed, you can backup"
+ << endl
+ << "and retype. Otherwise, the remote server may be down at this time."
+ << endl
+ << "The replication agreement will be created anyway. Proceeding..."
+ << endl << ends;
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_NEXT;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askCIRSSL(
+"You may use SSL authentication for replication if you have enabled it\n"
+"on the remote server.\n",
+
+"Do you want to use SSL?",
+
+"No",
+
+askCIRSSLSetup,
+askCIRSSLNext
+);
+
+static DialogAction
+askCIRSSLSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return action;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askCIRSSLNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "No";
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_SECURITY_ON, buf);
+
+ if (!isValidYesNo(buf))
+ return DIALOG_SAME;
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askCIRInterval(
+"Please specify the time interval to check the remote server for new\n"
+"entries to be replicated. Use the directory server console to set up\n"
+"more fine-grained control. Specify the time in minutes. Use a 0\n"
+"(zero) to indicate that changes should be propagated immediately all\n"
+"the time.\n",
+
+"Replication Sync Interval (in minutes)",
+
+"10",
+
+askCIRIntervalSetup,
+askCIRIntervalNext
+);
+
+static DialogAction
+askCIRIntervalSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_CIR_INTERVAL, "10") &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askCIRIntervalNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+ char testbuf[1024];
+ int interval, err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_INTERVAL, tmp);
+
+ interval = atoi(tmp);
+ if (!isdigit((*tmp)) || interval < 0)
+ {
+ sprintf(testbuf, "Please specify an integer greater than or equal to 0");
+ err = -1;
+ }
+
+ if (err)
+ {
+ DialogManagerType::showAlert(testbuf);
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askChangeLogSuffix(
+"Changes to the database will be kept under a separate suffix in the\n"
+"directory tree. These changes are used to replicate changes to other\n"
+"directory servers.\n",
+
+"Changelog suffix",
+
+"cn=changelog",
+
+askChangeLogSuffixSetup,
+askChangeLogSuffixNext
+);
+
+static DialogAction
+askChangeLogSuffixSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_CHANGELOGSUFFIX, "cn=changelog") &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askChangeLogSuffixNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CHANGELOGSUFFIX, val);
+
+ // check to see if val is a valid DN
+ if (!isAValidDN(val))
+ {
+ DialogManagerType::showAlert("The ChangeLog suffix must be a valid DN");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(val))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askChangeLogDir(
+"Changes to the main database will be kept in a separate database\n"
+"stored in a separate directory path, usually under your server\n"
+"instance directory.\n",
+
+"Changelog database\n"
+"directory",
+
+NULL,
+
+askChangeLogDirSetup,
+askChangeLogDirNext
+);
+
+static DialogAction
+askChangeLogDirSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER))
+ return action;
+
+ NSString dir = NSString(
+ getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ROOT)
+ ) + "/slapd-" +
+ getManager(me)->getDefaultScript()->get(SLAPD_KEY_SERVER_IDENTIFIER) +
+ "/logs/changelogdb";
+ if (dialogSetup(me, SLAPD_KEY_CHANGELOGDIR, dir) &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askChangeLogDirNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CHANGELOGDIR, val);
+
+ if (InstUtil::dirExists(val) && !InstUtil::dirWritable(val))
+ {
+ DialogManagerType::showAlert("You do not have access to that directory. Please try again.");
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askReplicationDN(
+"In order to allow remote servers to replicate new entries to this\n"
+"server, the remote server must have the ability to bind to this server\n"
+"as some entity with permission to do so. The Supplier DN is the DN of\n"
+"the entity the remote server will use to connect to this server to\n"
+"supply updates. The Supplier DN also requires a password which you\n"
+"will be prompted for after the DN.\n",
+
+"Supplier Bind DN",
+
+"cn=supplier",
+
+askReplicationDNSetup,
+askReplicationDNNext
+);
+
+static DialogAction
+askReplicationDNSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "1"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_REPLICATIONDN, "cn=supplier") &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askReplicationDNNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "1"))
+ return DIALOG_NEXT;
+
+ const char *replicationdn;
+ const char *replicationpw;
+ const char *buf;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ {
+ replicationdn = me->defaultAns();
+ }
+ else
+ {
+ replicationdn = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_REPLICATIONDN, replicationdn);
+
+ // check to see if it is a valid DN
+ if (!isAValidDN(replicationdn))
+ {
+ DialogManagerType::showAlert("The Supplier Bind DN must be a valid DN");
+ return DIALOG_SAME;
+ }
+ if (!isValid(replicationdn))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ while (1)
+ {
+ me->showString("Password: ");
+ if (me->getPassword () == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ char *inp = strdup(me->input());
+
+ if (inp[0] == 0)
+ {
+ continue;
+ }
+ else if (contains8BitChars(inp))
+ {
+ DialogManagerType::showAlert("Password must contain 7 bit characters only.");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(inp))
+ {
+ DialogManagerType::showAlert("Please enter a valid password.");
+ return DIALOG_SAME;
+ }
+ else
+ {
+ me->showString("Password (again): ");
+ if (me->getPassword() == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ replicationpw = me->input();
+ if (strcmp(inp,replicationpw))
+ {
+ DialogManagerType::showAlert("Passwords don't match.");
+ return DIALOG_SAME;
+ }
+ break;
+ }
+ }
+ free(inp);
+ }
+ }
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_REPLICATIONPWD, replicationpw);
+ return DIALOG_NEXT;
+}
+
+DialogInput askConsumerDN(
+"In order to allow remote servers to replicate new entries from this\n"
+"server, the remote server must have the ability to bind to this server\n"
+"as some entity with permission to do so. The Consumer DN is the DN of\n"
+"the entity the remote server will use to connect to this server to\n"
+"pull the new entries. This entity will have access to the entire\n"
+"database as well as the changelog entries. The Consumer DN also\n"
+"requires a password which you will be prompted for after the DN. If\n"
+"you leave this entry blank, no consumer bind DN will be created. The\n"
+"default is no consumer bind DN.\n",
+
+"Consumer Bind DN",
+
+NULL,
+
+askConsumerDNSetup,
+askConsumerDNNext
+);
+
+static DialogAction
+askConsumerDNSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "2"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_CONSUMERDN, 0) &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askConsumerDNNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "2"))
+ return DIALOG_NEXT;
+
+ const char *consumerdn;
+ const char *consumerpw;
+ const char *buf;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ {
+ consumerdn = me->defaultAns();
+ }
+ else
+ {
+ consumerdn = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CONSUMERDN, consumerdn);
+
+ if (!consumerdn || !*consumerdn ||
+ !strncasecmp(consumerdn, "none", strlen(consumerdn)))
+ {
+ getManager(me)->getDefaultScript()->remove(SLAPD_KEY_CONSUMERDN);
+ return DIALOG_NEXT;
+ }
+
+ // check to see if it is a valid dn
+ if (!isAValidDN(consumerdn))
+ {
+ DialogManagerType::showAlert("The Consumer Bind DN must be a valid DN");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(consumerdn))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ while (1)
+ {
+ me->showString("Password: ");
+ if (me->getPassword () == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ char *inp = strdup(me->input());
+
+ if (inp[0] == 0)
+ {
+ continue;
+ }
+ else if (contains8BitChars(inp))
+ {
+ DialogManagerType::showAlert("Password must contain 7 bit characters only.");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(inp))
+ {
+ DialogManagerType::showAlert("Please enter a valid password.");
+ return DIALOG_SAME;
+ }
+ else
+ {
+ me->showString("Password (again): ");
+ if (me->getPassword() == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ consumerpw = me->input();
+ if (strcmp(inp,consumerpw))
+ {
+ DialogManagerType::showAlert("Passwords don't match.");
+ return DIALOG_SAME;
+ }
+ break;
+ }
+ }
+ free(inp);
+ }
+ }
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CONSUMERPWD, consumerpw);
+ return DIALOG_NEXT;
+}
+
+DialogInput askSIRHost(
+"Please specify the host name of the server to which the replicated\n"
+"entries will be pushed.\n",
+
+"Consumer host name",
+
+0,
+
+askSIRHostSetup,
+askSIRHostNext
+);
+
+static DialogAction
+askSIRHostSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return action;
+ else if (dialogSetup(me, SLAPD_KEY_SIR_HOST, 0) &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSIRHostNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+ int err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SIR_HOST, tmp);
+
+ if (!tmp || !isValid(tmp))
+ {
+ DialogManagerType::showAlert("Please enter a valid hostname");
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askSIRPort(
+"Please specify the port of the server to which the replicated entries\n"
+"will be pushed.\n",
+
+"Consumer port",
+
+"389",
+
+askSIRPortSetup,
+askSIRPortNext
+);
+
+static DialogAction
+askSIRPortSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return action;
+
+ const char *defaultPort = "389";
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_SIR_SECURITY_ON))
+ defaultPort = "636";
+
+ if (dialogSetup(me, SLAPD_KEY_SIR_PORT, defaultPort) &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSIRPortNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+ char testbuf[1024];
+ int port, err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SIR_PORT, tmp);
+
+ port = atoi(tmp);
+ sprintf(testbuf, "%d", port);
+ if (strncmp(testbuf, tmp, 6) || port > MAXPORT || port < 1)
+ {
+ sprintf(testbuf, "OVERFLOW ERROR: Unable to bind to port %d\n"
+ "Please choose another port between 1 and %d.\n\n",
+ port, MAXPORT);
+ err = -1;
+ }
+
+ if (err)
+ {
+ DialogManagerType::showAlert(testbuf);
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askSIRDN(
+"Replication requires that this supplier has access to the portion of\n"
+"the remote directory to be replicated. This requires a bind DN and\n"
+"password for access to the consumer. You will first be asked for the\n"
+"bind DN, then the password. This is the same as the Supplier DN on\n"
+"the consumer.\n",
+
+"Replication DN on the Consumer",
+
+"cn=supplier",
+
+askSIRDNSetup,
+askSIRDNNext
+);
+
+static DialogAction
+askSIRDNSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_SIR_BINDDN, "cn=supplier") &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSIRDNNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return DIALOG_NEXT;
+
+ const char *slapdUser;
+ char *slapdPwd = 0;
+ const char *buf;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ {
+ slapdUser = me->defaultAns();
+ }
+ else
+ {
+ slapdUser = buf;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SIR_BINDDN, slapdUser);
+
+ // check to see if it is a valid dn
+ if (!isAValidDN(slapdUser))
+ {
+ DialogManagerType::showAlert("The Consumer Replication DN must be a valid DN");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(slapdUser))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ while (1)
+ {
+ me->showString("Password: ");
+ if (me->getPassword () == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ char *inp = strdup(me->input());
+
+ if (inp[0] == 0)
+ {
+ free(inp);
+ continue;
+ }
+ else
+ {
+ slapdPwd = inp;
+ break;
+ }
+ }
+ }
+
+ if (slapdPwd)
+ {
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SIR_BINDDNPWD, slapdPwd);
+ free(slapdPwd);
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askSIRSuffix(
+"Please enter the full DN of the part of the tree to replicate,\n"
+"including the suffix (e.g. ou=People, o=company.com).\n",
+
+"Directory path (DN)",
+
+NULL,
+
+askSIRSuffixSetup,
+askSIRSuffixNext
+);
+
+static DialogAction
+askSIRSuffixSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_SIR_SUFFIX, getManager(me)->getDefaultSuffix()) &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSIRSuffixNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SIR_SUFFIX, val);
+
+ // check to see if it is a valid dn
+ if (!isAValidDN(val))
+ {
+ DialogManagerType::showAlert("The suffix must be a valid DN");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(val))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ int status;
+ if (status = getManager(me)->verifyRemoteLdap(
+ SLAPD_KEY_SIR_HOST,
+ SLAPD_KEY_SIR_PORT,
+ SLAPD_KEY_SIR_SUFFIX,
+ SLAPD_KEY_SIR_BINDDN,
+ SLAPD_KEY_SIR_BINDDNPWD
+ )
+ )
+ {
+ ostrstream msg;
+ msg << "Could not connect to ldap://"
+ << getManager(me)->getDefaultScript()->get(SLAPD_KEY_SIR_HOST)
+ << ":"
+ << getManager(me)->getDefaultScript()->get(SLAPD_KEY_SIR_PORT)
+ << "/"
+ << getManager(me)->getDefaultScript()->get(SLAPD_KEY_SIR_SUFFIX)
+ << endl << "for bind DN "
+ << getManager(me)->getDefaultScript()->get(SLAPD_KEY_SIR_BINDDN)
+ << " status = " << status << endl
+ << "Please check your typing. If you have mis-typed, you can backup"
+ << endl
+ << "and retype. Otherwise, the remote server may be down at this time."
+ << endl
+ << "The replication agreement will be created anyway. Proceeding..."
+ << endl << ends;
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_NEXT;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askSIRSSL(
+"You may use SSL authentication for replication if you have enabled it\n"
+"on the remote server.\n",
+
+"Do you want to use SSL?",
+
+"No",
+
+askSIRSSLSetup,
+askSIRSSLNext
+);
+
+static DialogAction
+askSIRSSLSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return action;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSIRSSLNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "No";
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SIR_SECURITY_ON, buf);
+
+ if (!isValidYesNo(buf))
+ return DIALOG_SAME;
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askCIRDays(
+"Please enter the days of the week on which you would like replication\n"
+"to occur. The days are specified by a number. For example, use 0 for\n"
+"Sunday, 1 for Monday, etc. Use 6 for Saturday. You may not specify a\n"
+"number greater than 6 or less than 0. The numbers should be entered\n"
+"one after another in a list. For example, 0123 would be Sunday,\n"
+"Monday, Tuesday, and Wednesday. 06 would be Sunday and Saturday. The\n"
+"default is everyday.\n",
+
+"Enter the replication days",
+
+"all",
+
+askCIRDaysSetup,
+askCIRDaysNext
+);
+
+static DialogAction
+askCIRDaysSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_CIR_DAYS, "all") &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ const char *tmp;
+ if ((tmp = getManager(me)->getDefaultScript()->get(SLAPD_KEY_SIR_DAYS)) &&
+ !*tmp)
+ me->setDefaultAns("all");
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askCIRDaysNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_DAYS, val);
+
+ int status = 0;
+ ostrstream msg;
+
+ char realval[8] = "-------";
+ if (!strncasecmp(val, "all", strlen(val)))
+ strcpy(realval, ""); // default is everyday
+ else
+ {
+ for (const char *ptr = val; *ptr; ++ptr)
+ {
+ if (!isdigit(*ptr))
+ {
+ msg << "The string [" << val << "] contains non-digit characters."
+ << " Please re enter the string." << ends;
+ status = 1;
+ break;
+ }
+
+ int ival = (int)(*ptr) - (int)'0';
+ if (ival > 6)
+ {
+ msg << "The string contains an invalid value [" << ival << "]."
+ << " Please re enter the string." << ends;
+ status = 2;
+ break;
+ }
+
+ // this step makes sure we get the numbers in order with no duplicates
+ realval[ival] = *ptr;
+ }
+
+ if (status)
+ {
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_SAME;
+ }
+
+ // realval now contains a string like
+ // 0---4-6, but we really want 046
+ int index = 0;
+ for (char *p2 = realval; *p2; ++p2)
+ {
+ if (*p2 != '-')
+ realval[index++] = *p2;
+ }
+ realval[index] = 0;
+
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_DAYS, realval);
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askSIRDays(
+"Please enter the days of the week on which you would like replication\n"
+"to occur. The days are specified by a number. For example, use 0 for\n"
+"Sunday, 1 for Monday, etc. Use 6 for Saturday. You may not specify a\n"
+"number greater than 6 or less than 0. The numbers should be entered\n"
+"one after another in a list. For example, 0123 would be Sunday,\n"
+"Monday, Tuesday, and Wednesday. 06 would be Sunday and Saturday. The\n"
+"default is everyday.\n",
+
+"Enter the replication days",
+
+"all",
+
+askSIRDaysSetup,
+askSIRDaysNext
+);
+
+static DialogAction
+askSIRDaysSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_SIR_DAYS, "all") &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ const char *tmp;
+ if ((tmp = getManager(me)->getDefaultScript()->get(SLAPD_KEY_SIR_DAYS)) &&
+ !*tmp)
+ me->setDefaultAns("all");
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSIRDaysNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SIR_DAYS, val);
+
+ int status = 0;
+ ostrstream msg;
+
+ char realval[8] = "-------";
+ if (!strncasecmp(val, "all", strlen(val)))
+ strcpy(realval, ""); // default is everyday
+ else
+ {
+ for (const char *ptr = val; *ptr; ++ptr)
+ {
+ if (!isdigit(*ptr))
+ {
+ msg << "The string [" << val << "] contains non-digit characters."
+ << " Please re enter the string." << ends;
+ status = 1;
+ break;
+ }
+
+ int ival = (int)(*ptr) - (int)'0';
+ if (ival > 6)
+ {
+ msg << "The string contains an invalid value [" << ival << "]."
+ << " Please re enter the string." << ends;
+ status = 2;
+ break;
+ }
+
+ // this step makes sure we get the numbers in order with no duplicates
+ realval[ival] = *ptr;
+ }
+
+ if (status)
+ {
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_SAME;
+ }
+
+ // realval now contains a string like
+ // 0---4-6, but we really want 046
+ int index = 0;
+ for (char *p2 = realval; *p2; ++p2)
+ {
+ if (*p2 != '-')
+ realval[index++] = *p2;
+ }
+ realval[index] = 0;
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SIR_DAYS, realval);
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askCIRTimes(
+"Please enter the time of day you would like replication to occur. The\n"
+"time is specified as a range in the form HHMM-HHMM in 24 hour time.\n"
+"HH represents the hour portion of the time, and MM the minutes.\n"
+"Numbers less than 10 should be preceeded by a 0. For example, to\n"
+"enable replication between 1 am and 4:30 am, specify 0100-0430. To\n"
+"specify 11 am to 9 pm, use 1100-2100. 12 am to 12:59 am is specified\n"
+"as 0000-0059. The default is all day.\n",
+
+"Enter the replication times",
+
+"all day",
+
+askCIRTimesSetup,
+askCIRTimesNext
+);
+
+static DialogAction
+askCIRTimesSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_CIR_TIMES, "all day") &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askCIRTimesNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_CONSUMER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_CONSUMER), "2"))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ if (!strncasecmp(val, "all day", strlen(val)))
+ {
+ val = "";
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_CIR_TIMES, val);
+ return DIALOG_NEXT;
+ }
+
+ int status = 0;
+ ostrstream msg;
+
+ int pos = 0;
+ // format should be HHMM-HHMM
+ int maxvals[9] = {0, 23, 0, 59, 0, 0, 23, 0, 59};
+ char teststr[3]; // 2 digits plus \0
+ int testindex = 0;
+ for (const char *ptr = val; *ptr; ++ptr, ++pos)
+ {
+ // position 4 should contain the '-'
+ if (pos == 4 && *ptr != '-')
+ {
+ msg << "The time specification [" << val << "] is invalid.\n"
+ << "Please re enter the string." << ends;
+ status = 1;
+ break;
+ }
+ else if (pos == 4)
+ continue;
+
+ if (!isdigit(*ptr) && pos != 4)
+ {
+ msg << "The time specification [" << val << "] contains non-digit characters.\n"
+ << "Please re enter the string." << ends;
+ status = 2;
+ break;
+ }
+
+ teststr[testindex++] = *ptr;
+ if (pos == 1 || pos == 3 || pos == 6 || pos == 8)
+ {
+ teststr[testindex] = 0;
+ testindex = 0;
+ if (teststr[0] == '0')
+ teststr[0] = ' ';
+ int ival = atoi(teststr);
+ if (ival > maxvals[pos])
+ {
+ msg << "The string contains an invalid value [" << ival << "].\n"
+ << "Please re enter the string." << ends;
+ status = 3;
+ break;
+ }
+ }
+ }
+
+ if (pos != 9)
+ {
+ msg << "The string [" << val << "] is invalid.\n"
+ << "Please re enter the string." << ends;
+ status = 4;
+ }
+
+ if (status)
+ {
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askSIRTimes(
+"Please enter the time of day you would like replication to occur. The\n"
+"time is specified as a range in the form HHMM-HHMM in 24 hour time.\n"
+"HH represents the hour portion of the time, and MM the minutes.\n"
+"Numbers less than 10 should be preceeded by a 0. For example, to\n"
+"enable replication between 1 am and 4:30 am, specify 0100-0430. To\n"
+"specify 11 am to 9 pm, use 1100-2100. 12 am to 12:59 am is specified\n"
+"as 0000-0059. The default is all day.\n",
+
+"Enter the replication times",
+
+"all day",
+
+askSIRTimesSetup,
+askSIRTimesNext
+);
+
+static DialogAction
+askSIRTimesSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return action;
+
+ if (dialogSetup(me, SLAPD_KEY_SIR_TIMES, "all day") &&
+ getManager(me)->installMode() == Silent)
+ return DIALOG_ERROR;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askSIRTimesNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_SETUP_SUPPLIER) ||
+ strcmp(getManager(me)->getDefaultScript()->get(SLAPD_KEY_SETUP_SUPPLIER), "1"))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ if (!strncasecmp(val, "all day", strlen(val)))
+ {
+ val = "";
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SIR_TIMES, val);
+ return DIALOG_NEXT;
+ }
+
+ int status = 0;
+ ostrstream msg;
+
+ int pos = 0;
+ // format should be HHMM-HHMM
+ int maxvals[9] = {0, 23, 0, 59, 0, 0, 23, 0, 59};
+ char teststr[3]; // 2 digits plus \0
+ int testindex = 0;
+ for (const char *ptr = val; *ptr; ++ptr, ++pos)
+ {
+ // position 4 should contain the '-'
+ if (pos == 4 && *ptr != '-')
+ {
+ msg << "The time specification [" << val << "] is invalid.\n"
+ << "Please re enter the string." << ends;
+ status = 1;
+ break;
+ }
+ else if (pos == 4)
+ continue;
+
+ if (!isdigit(*ptr) && pos != 4)
+ {
+ msg << "The time specification [" << val << "] contains non-digit characters.\n"
+ << "Please re enter the string." << ends;
+ status = 2;
+ break;
+ }
+
+ teststr[testindex++] = *ptr;
+ if (pos == 1 || pos == 3 || pos == 6 || pos == 8)
+ {
+ teststr[testindex] = 0;
+ testindex = 0;
+ if (teststr[0] == '0')
+ teststr[0] = ' ';
+ int ival = atoi(teststr);
+ if (ival > maxvals[pos])
+ {
+ msg << "The string contains an invalid value [" << ival << "].\n"
+ << "Please re enter the string." << ends;
+ status = 3;
+ break;
+ }
+ }
+ }
+
+ if (pos != 9)
+ {
+ msg << "The string [" << val << "] is invalid.\n"
+ << "Please re enter the string." << ends;
+ status = 4;
+ }
+
+ if (status)
+ {
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askUseExistingMC(
+"Netscape server information is stored in the Netscape configuration\n"
+"directory server, which you may have already set up. If so, you\n"
+"should configure this server to be managed by the configuration\n"
+"server. To do so, the following information about the configuration\n"
+"server is required: the fully qualified host name of the form\n"
+"<hostname>.<domainname>(e.g. hostname.domain.com), the port number,\n"
+"the suffix, and the DN and password of a user having permission to\n"
+"write the configuration information, usually the Netscape\n"
+"configuration directory administrator.\n\n"
+"If you want to install this software as a standalone server, or if you\n"
+"want this instance to serve as your Netscape configuration directory\n"
+"server, press Enter.\n",
+
+"Do you want to register this software with an existing\n"
+"Netscape configuration directory server?",
+
+"No",
+
+askUseExistingMCSetup,
+askUseExistingMCNext
+);
+
+static DialogAction
+askUseExistingMCSetup(Dialog *me)
+{
+#if DEBUG > 1
+ cerr << "Entering askUseExistingMCSetup" << endl;
+#endif
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+
+ if (action != DIALOG_PREV)
+ {
+ if (getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_URL))
+ {
+ // tell the instance creator not to create the Config entries
+ // new instance
+ getManager(me)->getDefaultScript()->set(
+ SLAPD_KEY_USE_EXISTING_MC, "Yes");
+ getManager(me)->getDefaultScript()->set(
+ SLAPD_KEY_SLAPD_CONFIG_FOR_MC, "No");
+ }
+ else
+ {
+ getManager(me)->getDefaultScript()->set(
+ SLAPD_KEY_USE_EXISTING_MC, "No");
+ getManager(me)->getDefaultScript()->set(
+ SLAPD_KEY_SLAPD_CONFIG_FOR_MC, "Yes");
+ }
+ }
+
+ dialogSetup(me, SLAPD_KEY_USE_EXISTING_MC, "No");
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ {
+#if DEBUG > 1
+ cerr << "Leaving askUseExistingMCSetup DIALOG_NEXT" << endl;
+#endif
+ return DIALOG_NEXT;
+ }
+
+#if DEBUG > 1
+ cerr << "Leaving askUseExistingMCSetup DIALOG_SAME" << endl;
+#endif
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askUseExistingMCNext(Dialog *me)
+{
+#if DEBUG > 1
+ cerr << "Entering askUseExistingMCNext" << endl;
+#endif
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "No";
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_USE_EXISTING_MC, buf);
+
+ if (!isValidYesNo(buf))
+ return DIALOG_SAME;
+
+#if DEBUG > 1
+ cerr << "Leaving askUseExistingMCNext" << endl;
+#endif
+ return DIALOG_NEXT;
+}
+
+DialogInput askMCHost(
+"Enter the fully qualified domain name of the Netscape configuration\n"
+"directory server host in the form <hostname>.<domainname>\n"
+"(e.g. hostname.domain.com).\n",
+
+"Netscape configuration directory server\nhost name",
+
+0,
+
+askMCHostSetup,
+askMCHostNext
+);
+
+static DialogAction
+askMCHostSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return action;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askMCHostNext(Dialog *me)
+{
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_K_LDAP_HOST, tmp);
+
+ if (!tmp || !isValid(tmp))
+ {
+ DialogManagerType::showAlert("Please enter a valid hostname");
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askMCPort(
+"Please specify the port number on which the Netscape configuration\n"
+"directory server listens.\n",
+
+"Netscape configuration directory server\nport number",
+
+"389",
+
+askMCPortSetup,
+askMCPortNext
+);
+
+static DialogAction
+askMCPortSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return action;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askMCPortNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+ char testbuf[1024];
+ int port, err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_K_LDAP_PORT, tmp);
+
+ port = atoi(tmp);
+ sprintf(testbuf, "%d", port);
+ if (strncmp(testbuf, tmp, 6) || port > MAXPORT || port < 1)
+ {
+ sprintf(testbuf, "OVERFLOW ERROR: Unable to bind to port %d\n"
+ "Please choose another port between 1 and %d.\n\n",
+ port, MAXPORT);
+ err = -1;
+ }
+
+ if (err)
+ {
+ DialogManagerType::showAlert(testbuf);
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askMCDN(
+"To write configuration information into the Netscape configuration\n"
+"directory, you must bind to the server as an entity with the\n"
+"appropriate permissions. Usually, the Netscape configuration\n"
+"directory administrator is used for this purpose, although you can\n"
+"give other directory accounts the proper access.\n",
+
+"Netscape configuration directory server\nadministrator ID",
+
+0,
+
+askMCDNSetup,
+askMCDNNext
+);
+
+static DialogAction
+askMCDNSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return action;
+
+ dialogSetup(me, SLAPD_KEY_SERVER_ADMIN_ID, "admin");
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askMCDNNext(Dialog *me)
+{
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return DIALOG_NEXT;
+
+ const char *slapdUser;
+ char *slapdPwd = 0;
+ const char *buf;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ {
+ slapdUser = me->defaultAns();
+ }
+ else
+ {
+ slapdUser = buf;
+ }
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_SERVER_ADMIN_ID, slapdUser);
+
+ if (!isValid(slapdUser))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ while (1)
+ {
+ me->showString("Password: ");
+ if (me->getPassword () == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ char *inp = strdup(me->input());
+
+ if (inp[0] == 0)
+ {
+ free(inp);
+ continue;
+ }
+ else
+ {
+ slapdPwd = inp;
+ break;
+ }
+ }
+ }
+
+ if (slapdPwd)
+ {
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_SERVER_ADMIN_PWD, slapdPwd);
+ free(slapdPwd);
+
+ int status;
+ if (status = getManager(me)->verifyRemoteLdap(
+ SLAPD_KEY_K_LDAP_HOST,
+ SLAPD_KEY_K_LDAP_PORT,
+ SLAPD_KEY_BASE_SUFFIX,
+ SLAPD_KEY_SERVER_ADMIN_ID,
+ SLAPD_KEY_SERVER_ADMIN_PWD
+ )
+ )
+ {
+ ostrstream msg;
+ msg << "Could not connect to ldap://"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_HOST)
+ << ":"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_PORT)
+ << "/"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_BASE_SUFFIX)
+ << endl << "for bind DN "
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ADMIN_ID)
+ << " status = " << status << endl
+ << "Please check your typing. If you have mis-typed, you can backup"
+ << endl
+ << "and retype. Otherwise, the remote server may be down at this time."
+ << endl
+ << "The installation cannot proceed."
+ << endl << ends;
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_SAME;
+ }
+ else if ((getManager(me)->installType() < Custom) &&
+ (status = getManager(me)->verifyAdminDomain(
+ SLAPD_KEY_K_LDAP_HOST,
+ SLAPD_KEY_K_LDAP_PORT,
+ SLAPD_KEY_BASE_SUFFIX,
+ SLAPD_KEY_ADMIN_DOMAIN,
+ SLAPD_KEY_SERVER_ADMIN_ID,
+ SLAPD_KEY_SERVER_ADMIN_PWD
+ ))
+ )
+ {
+ ostrstream msg;
+ msg << "Could not find the Admin Domain "
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_ADMIN_DOMAIN)
+ << " in the server" << endl << "ldap://"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_HOST)
+ << ":"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_PORT)
+ << "/"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_BASE_SUFFIX)
+ << endl << "for bind DN "
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ADMIN_ID)
+ << " status = " << status << endl
+ << "You may need to re-run setup in Custom mode in order to specify"
+ << endl
+ << "the correct Admin Domain."
+ << endl
+ << "The installation cannot proceed."
+ << endl << ends;
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_SAME;
+ }
+ }
+
+ // tell the instance creator not to create the config entries in the
+ // new instance
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_SLAPD_CONFIG_FOR_MC, "No");
+
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askDisableSchemaChecking(
+"If you are going to import an old database immediately after or during\n"
+"installation, and you think you may have problems with your old\n"
+"schema, you may want to turn off schema checking until after the\n"
+"import. If you choose to do this, schema checking will remain off\n"
+"until you manually turn it back on. Netscape recommends that you turn\n"
+"it back on as soon as possible.\n",
+
+"Do you want to disable schema checking?",
+
+"No",
+
+askDisableSchemaCheckingSetup,
+askDisableSchemaCheckingNext
+);
+
+static DialogAction
+askDisableSchemaCheckingSetup(Dialog *me)
+{
+ me = me;
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askDisableSchemaCheckingNext(Dialog *me)
+{
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "No";
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_DISABLE_SCHEMA_CHECKING, buf);
+
+ if (!isValidYesNo(buf))
+ return DIALOG_SAME;
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askMCAdminDomain(
+"The Administration Domain is a part of the configuration directory\n"
+"server used to store information about Netscape software. If you are\n"
+"managing multiple software releases at the same time, or managing\n"
+"information about multiple domains, you may use the Administration\n"
+"Domain to keep them separate.\n\n"
+"If you are not using administrative domains, press Enter to select the\n"
+"default. Otherwise, enter some descriptive, unique name for the\n"
+"administration domain, such as the name of the organization responsible\n"
+"for managing the domain.\n",
+
+"Administration Domain",
+
+NULL,
+
+askMCAdminDomainSetup,
+askMCAdminDomainNext
+);
+
+static DialogAction
+askMCAdminDomainSetup(Dialog *me)
+{
+ if (!getManager(me)->getBaseScript()->get(SLAPD_KEY_ADMIN_DOMAIN)) {
+ getManager(me)->getBaseScript()->set(
+ SLAPD_KEY_ADMIN_DOMAIN, getManager(me)->getDNSDomain());
+ }
+
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ {
+#if DEBUG > 1
+ cerr << "leaving askMCAdminDomainSetup " << action << endl;
+#endif
+ return action;
+ }
+
+ // if we are creating the Configuration server, the admin domain will not
+ // yet exist, and we need to ask the user to create one. Otherwise, we are
+ // installing into an existing one
+
+ dialogSetup(me, SLAPD_KEY_ADMIN_DOMAIN, getManager(me)->getDNSDomain());
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askMCAdminDomainNext(Dialog *me)
+{
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ int status = 0;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_ADMIN_DOMAIN, val);
+
+ if (!isValid(val))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+ else if (isAValidDN(val))
+ {
+ DialogManagerType::showAlert("A DN is not allowed here. Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+ else if (status = getManager(me)->verifyAdminDomain(
+ SLAPD_KEY_K_LDAP_HOST,
+ SLAPD_KEY_K_LDAP_PORT,
+ SLAPD_KEY_BASE_SUFFIX,
+ SLAPD_KEY_ADMIN_DOMAIN,
+ SLAPD_KEY_SERVER_ADMIN_ID,
+ SLAPD_KEY_SERVER_ADMIN_PWD
+ )
+ )
+ {
+ ostrstream msg;
+ msg << "Could not find the Admin Domain "
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_ADMIN_DOMAIN)
+ << " in the server" << endl << "ldap://"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_HOST)
+ << ":"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_PORT)
+ << "/"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_BASE_SUFFIX)
+ << endl << "for bind DN "
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ADMIN_ID)
+ << " status = " << status << endl
+ << "Please check your typing. If you have mis-typed, you can backup"
+ << endl
+ << "and retype. Otherwise, the remote server may be down at this time."
+ << endl
+ << "The installation cannot proceed."
+ << endl << ends;
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askAdminDomain(
+"The Administration Domain is a part of the configuration directory\n"
+"server used to store information about Netscape software. If you are\n"
+"managing multiple software releases at the same time, or managing\n"
+"information about multiple domains, you may use the Administration\n"
+"Domain to keep them separate.\n\n"
+"If you are not using administrative domains, press Enter to select the\n"
+"default. Otherwise, enter some descriptive, unique name for the\n"
+"administration domain, such as the name of the organization responsible\n"
+"for managing the domain.\n",
+
+"Administration Domain",
+
+NULL,
+
+askAdminDomainSetup,
+askAdminDomainNext
+);
+
+static DialogAction
+askAdminDomainSetup(Dialog *me)
+{
+ if (!getManager(me)->getBaseScript()->get(SLAPD_KEY_ADMIN_DOMAIN)) {
+ getManager(me)->getBaseScript()->set(
+ SLAPD_KEY_ADMIN_DOMAIN, getManager(me)->getDNSDomain());
+ }
+
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return action;
+
+ // if we are creating the Configuration server, the admin domain will not
+ // yet exist, and we need to ask the user to create one. Otherwise, we are
+ // installing into an existing one
+
+ dialogSetup(me, SLAPD_KEY_ADMIN_DOMAIN, getManager(me)->getDNSDomain());
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askAdminDomainNext(Dialog *me)
+{
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_ADMIN_DOMAIN, val);
+
+ if (!isValid(val))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ if (isAValidDN(val))
+ {
+ DialogManagerType::showAlert("A DN is not allowed here. Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogYesNo askUseExistingUG(
+"If you already have a directory server you want to use to store your\n"
+"data, such as user and group information, answer Yes to the following\n"
+"question. You will be prompted for the host, port, suffix, and bind\n"
+"DN to use for that directory server.\n\n"
+"If you want this directory server to store your data, answer No.\n",
+
+"Do you want to use another directory to store your data?",
+
+"No",
+
+askUseExistingUGSetup,
+askUseExistingUGNext
+);
+
+static DialogAction
+askUseExistingUGSetup(Dialog *me)
+{
+#if DEBUG > 1
+ cerr << "Entering askUseExistingUGSetup" << endl;
+#endif
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ // if this server is not an MC host, it must be a UG host
+ if (getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_MC))
+ {
+ getManager(me)->getDefaultScript()->set(
+ SLAPD_KEY_USE_EXISTING_UG, "No");
+#if DEBUG > 1
+ cerr << "Leaving askUseExistingUGSetup DIALOG_NEXT" << endl;
+#endif
+ return action;
+ }
+ else if (getManager(me)->getBaseScript()->get(SLAPD_KEY_USER_GROUP_LDAP_URL))
+ {
+ getManager(me)->getDefaultScript()->set(
+ SLAPD_KEY_USE_EXISTING_UG, "Yes");
+ }
+ else
+ {
+ getManager(me)->getDefaultScript()->set(
+ SLAPD_KEY_USE_EXISTING_UG, "No");
+ }
+
+ dialogSetup(me, SLAPD_KEY_USE_EXISTING_UG, "No");
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ {
+#if DEBUG > 1
+ cerr << "Leaving askUseExistingUGSetup DIALOG_NEXT" << endl;
+#endif
+ return DIALOG_NEXT;
+ }
+
+#if DEBUG > 1
+ cerr << "Leaving askUseExistingUGSetup DIALOG_SAME" << endl;
+#endif
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askUseExistingUGNext(Dialog *me)
+{
+#if DEBUG > 1
+ cerr << "Entering askUseExistingUGNext" << endl;
+#endif
+ const char *buf = me->input();
+ if (!buf || !*buf)
+ {
+ buf = me->defaultAns();
+ if (!buf || !*buf)
+ buf = "No";
+ }
+
+ getManager(me)->getDefaultScript()->set(SLAPD_KEY_USE_EXISTING_UG, buf);
+
+ if (!isValidYesNo(buf))
+ return DIALOG_SAME;
+
+#if DEBUG > 1
+ cerr << "Leaving askUseExistingUGNext DIALOG_NEXT" << endl;
+#endif
+ return DIALOG_NEXT;
+}
+
+DialogInput askUGHost(
+"Enter the fully qualified domain name of the user directory host of\n"
+"the form <hostname>.<domainname> (e.g. hostname.domain.com).\n",
+
+"User directory host name",
+
+0,
+
+askUGHostSetup,
+askUGHostNext
+);
+
+static DialogAction
+askUGHostSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ return action;
+
+ dialogSetup(me, SLAPD_KEY_UG_HOST, 0);
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askUGHostNext(Dialog *me)
+{
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_UG_HOST, tmp);
+
+ if (!tmp || !isValid(tmp))
+ {
+ DialogManagerType::showAlert("Please enter a valid hostname");
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askUGPort(
+"Please specify the port number on which the user directory listens.\n",
+
+"User directory port number",
+
+"389",
+
+askUGPortSetup,
+askUGPortNext
+);
+
+static DialogAction
+askUGPortSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ return action;
+
+ dialogSetup(me, SLAPD_KEY_UG_PORT, me->defaultAns());
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askUGPortNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ return DIALOG_NEXT;
+
+ const char *buf = me->input();
+ const char *tmp;
+ char testbuf[1024];
+ int port, err = 0;
+
+ if (buf[0] == 0)
+ {
+ tmp = me->defaultAns();
+ }
+ else
+ {
+ tmp = buf;
+ }
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_UG_PORT, tmp);
+
+ port = atoi(tmp);
+ sprintf(testbuf, "%d", port);
+ if (strncmp(testbuf, tmp, 6) || port > MAXPORT || port < 1)
+ {
+ sprintf(testbuf, "OVERFLOW ERROR: Unable to bind to port %d\n"
+ "Please choose another port between 1 and %d.\n\n",
+ port, MAXPORT);
+ err = -1;
+ }
+
+ if (err)
+ {
+ DialogManagerType::showAlert(testbuf);
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askUGDN(
+"In order to add and modify information in the user directory, you must\n"
+"be able to bind to the server as an entity with the correct\n"
+"permissions. This user is usually the Directory Manager, although\n"
+"other users may be given the proper access. You will also be asked to\n"
+"provide the password.\n",
+
+"User directory administrator ID",
+
+0,
+
+askUGDNSetup,
+askUGDNNext
+);
+
+static DialogAction
+askUGDNSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ return action;
+
+ dialogSetup(me, SLAPD_KEY_USER_GROUP_ADMIN_ID, DEFAULT_SLAPDUSER);
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askUGDNNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ return DIALOG_NEXT;
+
+ const char *slapdUser;
+ char *slapdPwd = 0;
+ const char *buf;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ {
+ slapdUser = me->defaultAns();
+ }
+ else
+ {
+ slapdUser = buf;
+ }
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_USER_GROUP_ADMIN_ID, slapdUser);
+
+ if (!isValid(slapdUser))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ while (1)
+ {
+ me->showString("Password: ");
+ if (me->getPassword () == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ char *inp = strdup(me->input());
+
+ if (inp[0] == 0)
+ {
+ free(inp);
+ continue;
+ }
+ else
+ {
+ slapdPwd = inp;
+ break;
+ }
+ }
+ }
+
+ if (slapdPwd)
+ {
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_USER_GROUP_ADMIN_PWD, slapdPwd);
+ free(slapdPwd);
+
+ int status;
+ if (status = getManager(me)->verifyRemoteLdap(
+ SLAPD_KEY_UG_HOST,
+ SLAPD_KEY_UG_PORT,
+ SLAPD_KEY_UG_SUFFIX,
+ SLAPD_KEY_USER_GROUP_ADMIN_ID,
+ SLAPD_KEY_USER_GROUP_ADMIN_PWD
+ )
+ )
+ {
+ ostrstream msg;
+ msg << "Could not connect to ldap://"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_UG_HOST)
+ << ":"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_UG_PORT)
+ << "/"
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_UG_SUFFIX)
+ << endl << "for bind DN "
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_USER_GROUP_ADMIN_ID)
+ << " status = " << status << endl
+ << "Please check your typing. If you have mis-typed, you can backup"
+ << endl
+ << "and retype. Otherwise, the remote server may be down at this time."
+ << endl
+ << "The installation cannot proceed."
+ << endl << ends;
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_SAME;
+ }
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askUGSuffix(
+"Please specify the suffix for the user directory server.\n",
+
+"User directory server suffix",
+
+NULL,
+
+askUGSuffixSetup,
+askUGSuffixNext
+);
+
+static DialogAction
+askUGSuffixSetup(Dialog *me)
+{
+ DialogAction action = DIALOG_NEXT;
+ long actionval = 0;
+ me->getUserData(ACTION, actionval);
+ action = (DialogAction)actionval;
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ return action;
+
+ dialogSetup(me, SLAPD_KEY_UG_SUFFIX, getManager(me)->getDefaultSuffix());
+
+ long setupval = 0;
+ if (me->getUserData(SETUP_DEFAULTS, setupval) == SETUP_ONLY ||
+ setupval == SETUP_ONLY)
+ return DIALOG_NEXT;
+
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askUGSuffixNext(Dialog *me)
+{
+ if (!getManager(me)->featureIsEnabled(SLAPD_KEY_USE_EXISTING_UG))
+ return DIALOG_NEXT;
+
+ const char *buf;
+ NSString val;
+
+ buf = me->input();
+ if (buf[0] == 0)
+ val = me->defaultAns();
+ else
+ val = buf;
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_UG_SUFFIX, val);
+
+ // check to see if it is a valid dn
+ if (!isAValidDN(val))
+ {
+ DialogManagerType::showAlert("The suffix must be a valid DN");
+ return DIALOG_SAME;
+ }
+ if (!isValid(val))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ return DIALOG_NEXT;
+}
+
+DialogInput askReconfigMCAdminPwd(
+(const char*)0,
+"Netscape configuration directory server\nadministrator ID",
+
+(const char*)0,
+
+askReconfigMCAdminPwdSetup,
+askReconfigMCAdminPwdNext
+);
+
+static DialogAction
+askReconfigMCAdminPwdSetup(Dialog *me)
+{
+#if DEBUG > 1
+ cerr << "Entering askReconfigMCAdminPwdSetup" << endl;
+#endif
+ NSString msg = NSString(
+"In order to reconfigure your installation, the Configuration Directory\n"
+"Administrator password is required. Here is your current information:\n\n"
+"Configuration Directory: ") +
+ getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_URL) + "\n" +
+"Configuration Administrator ID: " +
+ getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ADMIN_ID) + "\n" +
+"\nAt the prompt, please enter the password for the Configuration Administrator.\n";
+
+ me->setText(msg);
+
+ me->setDefaultAns(getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ADMIN_ID));
+#if DEBUG > 1
+ cerr << "Leaving askReconfigMCAdminPwdSetup" << endl;
+#endif
+ return DIALOG_SAME;
+}
+
+static DialogAction
+askReconfigMCAdminPwdNext(Dialog *me)
+{
+ const char *buf;
+
+ buf = me->input();
+ if (!buf || buf[0] == 0)
+ {
+ buf = me->defaultAns();
+ }
+
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_SERVER_ADMIN_ID, buf);
+
+ if (!isValid(buf))
+ {
+ DialogManagerType::showAlert("Please enter a valid string.");
+ return DIALOG_SAME;
+ }
+
+ me->showString("Password: ");
+ while (1)
+ {
+ if (me->getPassword () == 0)
+ {
+ return DIALOG_PREV;
+ }
+ else
+ {
+ char *inp = strdup(me->input());
+
+ if (inp[0] == 0)
+ {
+ me->showString("Password: ");
+ continue;
+ }
+ else if (contains8BitChars(inp))
+ {
+ DialogManagerType::showAlert("Password must contain 7 bit characters only.");
+ return DIALOG_SAME;
+ }
+ else if (!isValid(inp))
+ {
+ DialogManagerType::showAlert("Please enter a valid password.");
+ return DIALOG_SAME;
+ }
+ else
+ {
+ int status;
+ if (status = authLdapUser(
+ getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_URL),
+ getManager(me)->getBaseScript()->get(SLAPD_KEY_SERVER_ADMIN_ID),
+ inp, 0, 0))
+ {
+ ostrstream msg;
+ msg << "Could not connect to "
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_K_LDAP_URL)
+ << endl << "for ID "
+ << getManager(me)->getBaseScript()->get(SLAPD_KEY_USER_GROUP_ADMIN_ID)
+ << " status = " << status << endl
+ << "Please check your typing. If you have mis-typed, you can backup"
+ << endl
+ << "and retype. Otherwise, the remote server may be down at this time."
+ << endl
+ << "The reconfiguration cannot proceed."
+ << endl << ends;
+ DialogManagerType::showAlert(msg.str());
+ delete [] msg.str();
+ return DIALOG_SAME;
+ }
+ }
+ getManager(me)->getBaseScript()->set(SLAPD_KEY_SERVER_ADMIN_PWD, inp);
+ free(inp);
+ break;
+ }
+ }
+
+ return DIALOG_NEXT;
+}
diff --git a/ldap/cm/newinst/ux-dialog.h b/ldap/cm/newinst/ux-dialog.h
new file mode 100644
index 00000000..bc8b47b8
--- /dev/null
+++ b/ldap/cm/newinst/ux-dialog.h
@@ -0,0 +1,69 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _UX_DIALOG_H_
+#define _UX_DIALOG_H_
+
+#include "dialog.h"
+extern DialogYesNo askReconfig;
+extern DialogInput askSlapdServerName;
+extern DialogInput askAdminPort;
+extern DialogInput askSlapdPort;
+extern DialogYesNo askSecurity;
+extern DialogInput askSlapdSecPort;
+extern DialogInput askSlapdServerID;
+extern DialogInput askSlapdSysUser;
+extern DialogYesNo askConfigForMC;
+extern DialogInput askMCAdminID;
+extern DialogInput askSlapdSuffix;
+extern DialogInput askSlapdRootDN;
+extern DialogYesNo askReplication;
+extern DialogYesNo askSample;
+extern DialogYesNo askPopulate;
+extern DialogInput askOrgSize;
+extern DialogYesNo askCIR;
+extern DialogInput askCIRHost;
+extern DialogInput askCIRPort;
+extern DialogInput askCIRDN;
+extern DialogInput askCIRSuffix;
+extern DialogYesNo askCIRSSL;
+extern DialogInput askCIRInterval;
+extern DialogInput askCIRDays;
+extern DialogInput askCIRTimes;
+extern DialogYesNo askSIR;
+extern DialogInput askChangeLogSuffix;
+extern DialogInput askChangeLogDir;
+extern DialogInput askReplicationDN;
+extern DialogInput askConsumerDN;
+extern DialogYesNo askSIR;
+extern DialogInput askSIRHost;
+extern DialogInput askSIRPort;
+extern DialogInput askSIRDN;
+extern DialogInput askSIRSuffix;
+extern DialogYesNo askSIRSSL;
+extern DialogInput askSIRDays;
+extern DialogInput askSIRTimes;
+extern DialogYesNo askUseExistingMC;
+extern DialogInput askMCHost;
+extern DialogInput askMCPort;
+extern DialogInput askMCDN;
+extern DialogYesNo askDisableSchemaChecking;
+extern DialogInput askMCAdminDomain;
+extern DialogInput askAdminDomain;
+extern DialogYesNo askUseExistingUG;
+extern DialogInput askUGHost;
+extern DialogInput askUGPort;
+extern DialogInput askUGDN;
+extern DialogInput askUGSuffix;
+extern DialogInput askReconfigMCAdminPwd;
+
+// these keywords and values are used in the Dialog::setUserData to
+// control the behavior of the dialogs
+#define SETUP_DEFAULTS "SETUP_DEFAULTS"
+const int SETUP_ONLY = 1;
+#define ACTION "ACTION"
+
+#endif // _UX_DIALOG_H_
diff --git a/ldap/cm/newinst/ux-dsalib_dn.c b/ldap/cm/newinst/ux-dsalib_dn.c
new file mode 100644
index 00000000..535bf53f
--- /dev/null
+++ b/ldap/cm/newinst/ux-dsalib_dn.c
@@ -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 **/
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+#include <dsalib_dn.c>
+#ifdef __cplusplus
+}
+#endif
diff --git a/ldap/cm/newinst/ux-guesses.cc b/ldap/cm/newinst/ux-guesses.cc
new file mode 100644
index 00000000..6b54127c
--- /dev/null
+++ b/ldap/cm/newinst/ux-guesses.cc
@@ -0,0 +1,125 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* Print guesses of host and domain name as made by the setup SDK. */
+
+
+
+/* $RCSfile: ux-guesses.cc,v $ $Revision: 1.1 $ $Date: 2005/01/21 00:40:49 $ $State: Exp $ */
+/*
+ * $Log: ux-guesses.cc,v $
+ * Revision 1.1 2005/01/21 00:40:49 cvsadm
+ * Initial revision
+ *
+ * Revision 1.1.2.4 2004/07/14 01:39:20 dboreham
+ * changes to make newer C++ compilers happy
+ *
+ * Revision 1.1.1.1 2004/06/03 22:32:45 telackey
+ * Initial import Thu Jun 3 15:32:43 PDT 2004
+ *
+ * Revision 1.1.2.3 2003/09/22 19:38:52 ulfw
+ * Update copyright years from 2001 to 2001-2003
+ *
+ * Revision 1.1.2.2 2001/11/02 23:33:04 richm
+ * XXX use new copyright XXX
+ *
+ * Revision 1.1.2.1 2000/08/07 15:14:28 mwahl
+ * rename functions
+ *
+ *
+ */
+
+#include "dialog.h"
+
+extern "C" {
+#if defined(__sun) || defined(__hppa) || defined(__osf__) || defined(__linux__) || defined(linux)
+#include <netdb.h>
+#endif
+}
+
+
+class PrintGuessPreInstall:public DialogManager
+{
+public:
+
+ PrintGuessPreInstall(int, char **);
+ ~PrintGuessPreInstall();
+
+ int init();
+
+ int start();
+
+
+ void setParent(void *) { }
+ void *parent() const { return 0;}
+ void resetLast() { }
+ void add (Dialog *) { }
+ void addLast(Dialog *) { }
+ void clear() { }
+ int cont() { return -1;}
+
+
+private:
+ Bool _reconfig;
+ Bool _configured;
+};
+
+PrintGuessPreInstall::PrintGuessPreInstall(int argc, char **argv) : _reconfig(False)
+{
+ setInstallMode(Interactive);
+ setInstallType(Typical);
+ _configured = False;
+
+ /* getOptions(argc, argv); */
+
+}
+
+PrintGuessPreInstall::~PrintGuessPreInstall()
+{
+
+}
+
+int PrintGuessPreInstall::init()
+{
+ return 0;
+}
+
+int PrintGuessPreInstall::start()
+{
+ const char *hno = InstUtil::guessHostname();
+ printf("hostname: %s\n",hno ? hno : "<unknown>");
+ if (hno) {
+#if defined(__sun) || defined(__hppa) || defined(__osf__) || defined(__linux__) || defined(linux)
+ static char test_host[BIG_BUF] = {0};
+ struct hostent *hp;
+
+ strcpy(test_host,hno);
+ hp = gethostbyname(test_host);
+ if (hp == NULL) {
+ printf("addressable: no\n");
+ } else {
+ printf("addressable: yes\n");
+ }
+#endif
+ }
+ const char *dno = InstUtil::guessDomain();
+ printf("domain: %s\n",dno ? dno : "<unknown>");
+ return 0;
+}
+
+
+
+int main(int argc,char **argv)
+{
+ PrintGuessPreInstall program(argc,argv);
+
+ int err = program.init();
+ if (!err) {
+ err = program.start();
+ }
+ return err;
+
+}
diff --git a/ldap/cm/newinstnt/Makefile b/ldap/cm/newinstnt/Makefile
new file mode 100644
index 00000000..c7d3163a
--- /dev/null
+++ b/ldap/cm/newinstnt/Makefile
@@ -0,0 +1,91 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Makefile for Directory Server 40 installation plug-in
+#
+#
+# XXXstevross: note change the makeclean to work
+#
+#
+
+MCOM_ROOT=../../../..
+LDAP_SRC= $(MCOM_ROOT)/ldapserver/ldap
+
+NOSTDCLEAN=1
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+OUTDIR=$(OBJDIR)/setup
+
+CFLAGS=/nologo /MD /W3 /Gm /GX /Zi /Od $(SETUPSDK_INCLUDE) $(LDAPSDK_INCLUDE) \
+ /I "$(LDAP_SRC)/admin/include" /I "$(LDAP_SRC)/admin/lib" \
+ /I "$(LDAP_SRC)/admin/src" /D \
+ "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fp"$(OUTDIR)/dsinst.pch" /YX \
+ /Fo"$@" /Fd"$(OUTDIR)/" /c
+
+RCFLAGS=/l 0x409 /d "_DEBUG"
+
+LFLAGS= /nologo /subsystem:windows /dll /incremental:no\
+ /pdb:none /debug /machine:I386
+
+DSLFLAGS= /out:"$(OUTDIR)/dsinst.dll" /implib:"$(OUTDIR)/dsinst.lib"
+
+LIBS= \
+ kernel32.lib user32.lib gdi32.lib comdlg32.lib\
+ comctl32.lib advapi32.lib shell32.lib uuid.lib\
+ wsock32.lib\
+ $(SETUPSDKLINK) $(LDAP_SDK_LIBLDAP_DLL)
+
+DSOBJS= \
+ $(OUTDIR)/dsinst_dsalib_dn.obj \
+ $(OUTDIR)/dsinst.obj \
+ $(OUTDIR)/dsinst.res
+
+CONSOLOBJS= \
+ $(OUTDIR)/consolinst.obj
+
+LIBINSTOBJS = \
+ $(OUTDIR)/libinst.obj
+
+CFLAGS+= /I "$(MCOM_ROOT)/ldapserver/include/nt" /I "$(MCOM_ROOT)/ldapserver/ldap/include" /I "$(MCOM_ROOT)/ldapserver/include" $(ADMINUTIL_INCLUDE) $(NSPR_INCLUDE) /D "NS_DS" /D "XP_WIN32"
+
+CC=cl.exe
+LD=link.exe
+RC=rc.exe
+RM=erase /F /Q
+FIXINF= ../newinst/fixINF.pl
+
+all: $(SETUPSDK_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(ADMINUTIL_DEP) $(OUTDIR)/dsinst.dll $(OUTDIR)/slapd.inf
+
+clean:
+ -rm -rf "$(OUTDIR)"
+
+$(OUTDIR):
+ @mkdir "$(OUTDIR)"
+
+# dependencies only, no commands
+$(OUTDIR)/dsinst.obj: dsinst.c dsinst.h
+
+$(OUTDIR)/dsinst_dsalib_dn.obj: dsinst_dsalib_dn.c
+
+$(OUTDIR)/consolinst.obj: consolinst.c consolinst.h
+
+$(OUTDIR)/libinst.obj: libinst.c libinst.h
+
+# now the commands
+$(OUTDIR)/dsinst.dll: $(OUTDIR) $(DSOBJS) $(CONSOLOBJS) $(LIBINSTOBJS)
+ $(LD) $(LFLAGS) $(DSLFLAGS) $(DSOBJS) $(CONSOLOBJS) $(LIBINSTOBJS) $(LIBS)
+
+$(OUTDIR)/%.obj: %.c
+ $(CC) $(CFLAGS) $<
+
+$(OUTDIR)/%.inf: %.inf
+ $(PERL) $(FIXINF) $(BUILD_MODULE) $(DIR_VERSION) $(MCOM_ROOT)/ldapserver/$(BUILD_ARCH)/buildnum.dat $< $(SECURITY) "DoesntOnNT" $(IS_DIR_LITE) '$(INSTANCE_NAME_PREFIX)' $@ $(BUILD_BOMB)
+
+$(OUTDIR)/%.res: %.rc
+ $(RC) $(RCFLAGS) /fo"$@" $<
diff --git a/ldap/cm/newinstnt/consolinst.c b/ldap/cm/newinstnt/consolinst.c
new file mode 100644
index 00000000..aced950a
--- /dev/null
+++ b/ldap/cm/newinstnt/consolinst.c
@@ -0,0 +1,320 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST.c - Netscape Directory Server Installation Plug-In
+//
+//
+#include <windows.h>
+#include <commctrl.h>
+#include <nssetup.h>
+
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <process.h>
+#include <memory.h>
+#include <regstr.h>
+#include <ldap.h>
+#include "resource.h"
+#include "consolinst.h"
+
+#define NUM_PROP_PAGES 1
+
+#define INDEX_FIRST_PAGE 0
+#define INDEX_LAST_PAGE 0
+
+
+static MODULEINFO mi = {
+ NULL, // m_hModule
+ NULL, // m_hwndParent
+ NS_WIZERROR, // m_nResult
+};
+
+//////////////////////////////////////////////////////////////////////////////
+// _DialogProcs
+//
+// The dialog procedure for a single property page. You will need to create
+// one of these for each property page used in the property sheet. This
+// procedure processes dialog messages sent to your property page by Windows.
+// See the Windows SDK documentation for more information about this function.
+//
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// TMPL_PreInstall
+//
+// This function is called by the installation framework before asking the
+// user any questions. Here you should determine if all of the requisites
+// for installing this component are being met. If this operation succeeds
+// return TRUE, otherwise display an error message and return FALSE to abort
+// installation.
+//
+
+BOOL __declspec(dllexport)
+CONSOLINST_PreInstall(LPCSTR lpszInstallPath)
+{
+ // TODO: Add code to check for pre-installation requirements.
+
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST_AskOptions
+//
+// This function is called by the installation framework to query the user for
+// information about your component. Here you should ask all of the questions
+// required to install your component as a series of wizard property sheets.
+//
+
+INT __declspec(dllexport)
+CONSOLINST_AskOptions(HWND hwndParent, INT nDirection)
+{
+ PROPSHEETPAGE psp[NUM_PROP_PAGES];
+ UINT uStartPage;
+ INT nNumPages;
+
+ // TODO: Initialize a property page for each dialog template/resource
+ // required to query the user for options related to your server
+ // installation. Don't forget to increment the count of pages contained
+ // in NUM_PROP_PAGES at the top of this file.
+
+
+
+ if( SILENTMODE == MODE)
+ {
+ mi.m_nResult = NS_WIZNEXT;
+ }else{
+
+ if(EXPRESSMODE == MODE)
+ {
+
+ }else if( (NORMALMODE == MODE) || (CUSTOMMODE == MODE) ){
+ /* ask for server settings, SuitespotID and Unrestricted User */
+ }
+
+ /* add additional pages for custom mode */
+ if( (CUSTOMMODE == MODE) )
+ {
+
+ }
+
+ // Must initialize the result to an error code before calling WizardDialog
+ mi.m_nResult = NS_WIZERROR;
+
+ // Set the first page to display based on the direction we are travelling
+ uStartPage = (nDirection == NS_WIZBACK) ? INDEX_LAST_PAGE : INDEX_FIRST_PAGE;
+
+ // Call WizardDialog to display the set of property pages
+ if (WizardDialog(mi.m_hModule, hwndParent, psp, nNumPages, uStartPage) < 0)
+ {
+ mi.m_nResult = NS_WIZERROR;
+ }
+
+ }
+ return mi.m_nResult;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST_GetSummary
+//
+// This function is called by the installation framework after all questions,
+// for all components, have been asked. Here you should provide a detailed
+// summary explaining all of the choices selected by the user.
+//
+// IMPORTANT NOTE: Each line MUST end in a carriage return/line feed
+// combination ("\r\n") as this string is placed in an edit control. Edit
+// controls do not properly handle single "\n" end-of-line characters.
+//
+
+VOID __declspec(dllexport)
+CONSOLINST_GetSummary(LPSTR lpszSummary)
+{
+
+ // TODO: Add code to fill in the summary information entered by the user
+ char *psz = lpszSummary;
+
+ *psz = '\0';
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST_WriteGlobalCache
+//
+// This function is called by the installation framework when the user clicks
+// Next at the summary screen. Here you should write all information entered
+// by the user into the installation cache for use during silent installation.
+// Data written to this section of the file may be interpreted by the
+// framework. If this operation succeeds return TRUE, otherwise display an
+// error message and return FALSE to indicate an error.
+//
+
+BOOL __declspec(dllexport)
+CONSOLINST_WriteGlobalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
+{
+ // TODO: Add code to write data to the cache file (INI format) under the
+ // specified section name.
+
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST_WriteLocalCache
+//
+// This function is called by the installation framework when the user clicks
+// Next at the summary screen. Here you should write all information entered
+// by the user into the installation cache for use during silent installation.
+// Data written to this file is not interpreted by the framework, and may
+// consist of any values that you will need to perform the installation (not
+// just values entered by the user). If this operation succeeds return TRUE,
+// otherwise display an error message and return FALSE to indicate an error.
+//
+
+BOOL __declspec(dllexport)
+CONSOLINST_WriteLocalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
+{
+ // TODO: Add code to write data to the cache file (INI format) under the
+ // specified section name.
+
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST_ReadGlobalCache
+//
+// This function is called by the installation framework during silent install
+// to initialize your data from the cache file you created above. Here you
+// should read any information stored in the installation cache's global
+// section that you need. If this operation succeeds return TRUE, otherwise
+// display an error message and return FALSE to indicate an error.
+//
+
+BOOL __declspec(dllexport)
+CONSOLINST_ReadGlobalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
+{
+
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST_ReadLocalCache
+//
+// This function is called by the installation framework during silent install
+// to intialize your data from the local section of the cache created above.
+// Here you should read any information stored in the installation cache's
+// local section that you need. If this operation succeeds return TRUE,
+// otherwise display an error message and return FALSE to indicate an error.
+//
+
+BOOL __declspec(dllexport)
+CONSOLINST_ReadLocalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
+{
+ // TODO: Add code to read data from the cache file (INI format) under the
+ // specified section name.
+
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST_Install
+//
+// The framework calls this function to perform installation. Here you should
+// define the file sets that are required to place your files on the
+// destination disk. You should not however perform the extraction, as the
+// calling level will do that once the file sets for all products have been
+// defined. This ensures that the progress indicator shows the results for
+// the entire range of user selections as a whole. If the function
+// successfully defines the file set return TRUE, otherwise return FALSE to
+// indicate an error.
+//
+
+BOOL __declspec(dllexport)
+CONSOLINST_Install(VOID)
+{
+ HFILESET hfs;
+ UINT uFlags;
+ CHAR szSavedPath[MAX_PATH];
+ CHAR szDirName[MAX_PATH];
+ BOOL bResult = FALSE;
+
+ hfs = FileSetCreate(CON_ID_DIR);
+
+ if (hfs == INVALID_FILESET_HANDLE)
+ return FALSE;
+
+ uFlags = FS_UPDATE_VERSION | FS_SHAREDFILE;
+ FileSetAddArchive(hfs, CON_JAR, "*.*", CON_MESSAGE,
+ uFlags);
+
+ FileSetClose(hfs);
+
+ return TRUE;
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST_PostInstall
+//
+// The framework calls this function to perform post-installation
+// configuration. Here you should set values in any product configuration
+// files, install services, add registry keys, start servers, and anything
+// else that can only be done once the binaries are layed down on the disk.
+// If the function succeeds return TRUE, otherwise return FALSE to indicate
+// an error.
+//
+
+BOOL __declspec(dllexport)
+CONSOLINST_PostInstall(VOID)
+{
+ // TODO: Add code to perform configuration.
+ BOOL bRC = TRUE;
+
+ return bRC;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// PreUninst
+//
+//
+// Do things before uninstalling like turn off the server
+//
+//
+//
+//
+
+BOOL __declspec(dllexport)
+CONSOLINST_PreUnInstall(LPCSTR pszServerRoot)
+{
+ BOOL bRC = TRUE;
+
+ return bRC;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// PostUninst
+//
+//
+// Clean up registry keys etc
+//
+//
+//
+//
+BOOL __declspec(dllexport)
+CONSOLINST_PostUnInstall(LPCSTR pszServerRoot)
+{
+
+ BOOL bRC = TRUE;
+ return bRC;
+}
+
+
diff --git a/ldap/cm/newinstnt/consolinst.h b/ldap/cm/newinstnt/consolinst.h
new file mode 100644
index 00000000..6bd3f4e4
--- /dev/null
+++ b/ldap/cm/newinstnt/consolinst.h
@@ -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 **/
+//////////////////////////////////////////////////////////////////////////////
+// CONSOLINST.h - Netscape SuiteSpot Installation Plug-In Directory Server
+//
+//
+
+#ifndef __CONSOLINST_H
+#define __CONSOLINST_H
+
+
+extern __declspec(dllexport) INT __cdecl CONSOLINST_AskOptions(HWND hwndParent, INT nDirection);
+extern __declspec(dllexport) VOID __cdecl CONSOLINST_GetSummary(LPSTR lpszSummary);
+extern __declspec(dllexport) BOOL __cdecl CONSOLINST_WriteCacheGlobal(LPCSTR lpszCacheFileName, LPCSTR lpszSection);
+extern __declspec(dllexport) BOOL __cdecl CONSOLINST_WriteCacheLocal(LPCSTR lpszCacheFileName, LPCSTR lpszSection);
+extern __declspec(dllexport) BOOL __cdecl CONSOLINST_ReadCacheGlobal(LPCSTR lpszCacheFileName, LPCSTR lpszSection);
+extern __declspec(dllexport) BOOL __cdecl CONSOLINST_ReadCacheLocal(LPCSTR lpszCacheFileName, LPCSTR lpszSection);
+extern __declspec(dllexport) BOOL __cdecl CONSOLINST_PreInstall(LPCSTR lpszInstallPath);
+extern __declspec(dllexport) BOOL __cdecl CONSOLINST_Install(void);
+extern __declspec(dllexport) BOOL __cdecl CONSOLINST_PostInstall(void);
+extern __declspec(dllexport) BOOL __cdecl CONSOLINST_PreUnInstall(LPCSTR pszServerRoot);
+extern __declspec(dllexport) BOOL __cdecl CONSOLINST_PostUnInstall(LPCSTR pszServerRoot);
+
+
+typedef struct tagMODULEINFO {
+ HINSTANCE m_hModule;
+ HWND m_hwndParent;
+ INT m_nResult;
+} MODULEINFO;
+
+#define MAX_STR_SIZE 512
+#define CON_ID_DIR "slapd-client"
+#define CON_TARGET "java"
+#define CON_JAR "ds40jars.z"
+#define CON_MESSAGE "Installing Directory Server Management Console..."
+#endif // __CONSOLINST_H
diff --git a/ldap/cm/newinstnt/dsinst.aps b/ldap/cm/newinstnt/dsinst.aps
new file mode 100644
index 00000000..685e4910
--- /dev/null
+++ b/ldap/cm/newinstnt/dsinst.aps
Binary files differ
diff --git a/ldap/cm/newinstnt/dsinst.c b/ldap/cm/newinstnt/dsinst.c
new file mode 100644
index 00000000..17749f81
--- /dev/null
+++ b/ldap/cm/newinstnt/dsinst.c
@@ -0,0 +1,8316 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+///////////////////////////////////////////////////////////////////////////////
+// dsinst.c - Netscape Directory Server Installation Plug-In
+//
+#include <windows.h>
+#include <commctrl.h>
+#include <nssetup.h>
+#include <ldapu.h>
+
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <process.h>
+#include <regstr.h>
+#include <ldap.h>
+#include <wingdi.h>
+#include "resource.h"
+#include "dsinst.h"
+#include "install_keywords.h"
+#include "libinst.h"
+
+#ifdef TARGETDIR
+#undef TARGETDIR
+#endif
+
+#define NUM_PROP_PAGES 16
+
+// this is the path to perl, relative to the server root directory
+#define PERL_EXE "bin\\slapd\\admin\\bin\\perl.exe"
+// this is the keyword to lookup in slapd.inf
+#define NSPERL_POST_INSTALL_PROG "NSPerlPostInstall"
+
+#define INDEX_FIRST_PAGE 0
+#define INDEX_LAST_PAGE 14
+
+#define NUM_CIR_ATTR 12
+#define NUM_ORC_ATTR 1
+#define NUM_SIR_ATTR 10
+static MODULEINFO mi = {
+ NULL, // m_hModule
+ NULL, // m_hwndParent
+ NS_WIZERROR, // m_nResult
+ 0, // m_nReInstall
+ NULL, // m_szMCCBindAs
+};
+
+static INFDATA cd;
+
+static void normalizeDNs();
+
+extern int ds_dn_uses_LDAPv2_quoting(const char *utf8dn);
+extern char *dn_normalize_convert(char *dn);
+static void fixDN(char *dn);
+static char *dialogMessage; /* used by shutdownDialogProc */
+#define OLD_VERSION_SIZE 32
+static char oldVersion[OLD_VERSION_SIZE]; /* used by reinstall */
+
+static void
+storeUserDirectoryInfo()
+{
+ char *utf8UserGroupAdmin = NULL;
+ char *utf8UserGroupAdminPW = NULL;
+ char *utf8UserGroupURL = NULL;
+
+ if (mi.m_nReInstall == 1)
+ return; // do nothing if reinstall
+
+ if(mi.m_nExistingUG == 0)
+ {
+ /* the user is creating a new UG with this instance */
+ if(mi.m_nExistingMCC == 0)
+ {
+ /* the user is also creating a new MCC so set UG admin to MCC admin */
+ lstrcpy(mi.m_szUserGroupAdmin, mi.m_szMCCBindAs);
+ lstrcpy(mi.m_szUserGroupAdminPW, mi.m_szMCCPw);
+
+ }else{
+ /* user is using an existing MCC so only creating UG, make UG user same as
+ Root DN */
+ lstrcpy(mi.m_szUserGroupAdmin, mi.m_szInstanceUnrestrictedUser);
+ lstrcpy(mi.m_szUserGroupAdminPW, mi.m_szInstancePassword);
+
+ }
+ sprintf(mi.m_szUserGroupURL, "ldap://%s:%d/%s", mi.m_szInstanceHostName,
+ mi.m_nInstanceServerPort, mi.m_szInstanceSuffix);
+ }
+
+ SetLdapUserDirInit(TRUE);
+
+ utf8UserGroupAdmin = localToUTF8(mi.m_szUserGroupAdmin);
+ utf8UserGroupAdminPW = localToUTF8(mi.m_szUserGroupAdminPW);
+ utf8UserGroupURL = localToUTF8(mi.m_szUserGroupURL);
+ SetLdapUserDirID(utf8UserGroupAdmin);
+ SetLdapUserDirPWD(utf8UserGroupAdminPW);
+ SetLdapUserDirURL(utf8UserGroupURL);
+ nsSetupFree(utf8UserGroupAdmin);
+ nsSetupFree(utf8UserGroupAdminPW);
+ nsSetupFree(utf8UserGroupURL);
+}
+
+/* converts server ID of the form slapd-foo to foo, and NULL to "" */
+static const char *
+getShortName(const char *serverID)
+{
+ const char *retval = serverID;
+ const char *prefix = "slapd-";
+ int preflen = strlen(prefix);
+
+ if (serverID && !strncmp(serverID, prefix, preflen))
+ retval = serverID + preflen;
+
+ if (!retval)
+ retval = "";
+
+ return retval;
+}
+
+static FILE*
+getLogFileP()
+{
+ static FILE* logfp = 0;
+
+ if (!getenv("USE_LOGFILE"))
+ return logfp;
+
+ if (!logfp)
+ logfp = fopen("c:\\debug.out", "w");
+
+ return logfp;
+}
+
+static void
+myLogData(const char *s, ...)
+{
+ FILE* logfp = getLogFileP();
+ va_list ap;
+
+ if (!logfp)
+ return;
+
+ va_start(ap, s);
+ vfprintf(logfp, s, ap);
+ va_end(ap);
+ fprintf(logfp, "\n");
+ fflush(logfp);
+}
+
+/* Will return a malloc'd "" if no error - so caller should always use LocalFree() with
+ the returned value
+*/
+static LPVOID
+getLastErrorMessage()
+{
+ LPVOID lpMsgBuf = NULL;
+
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL);
+
+ /* always return something . . . */
+ if (lpMsgBuf == NULL) {
+ lpMsgBuf = strdup("");
+ }
+
+ return lpMsgBuf;
+}
+
+static void
+myLogError(const char *s, ...)
+{
+ va_list ap;
+ LPVOID lpMsgBuf;
+ FILE* logfp = getLogFileP();
+
+ if (!logfp)
+ return;
+
+ if (lpMsgBuf = getLastErrorMessage()) {
+ fprintf(logfp, "Error: %d (%s): at ", GetLastError(), lpMsgBuf);
+ // Free the buffer.
+ LocalFree( lpMsgBuf );
+ }
+
+ va_start(ap, s);
+ vfprintf(logfp, s, ap);
+ va_end(ap);
+}
+
+/*
+ prints a message if the given dn uses LDAPv2 style quoting
+*/
+void
+checkForLDAPv2Quoting(const char *dn_to_test)
+{
+ char *utf8dn = localToUTF8(dn_to_test);
+ if (ds_dn_uses_LDAPv2_quoting(utf8dn))
+ {
+ char *newdn = strdup(dn_to_test);
+ fixDN(newdn);
+ DSMessageBoxOK(WARN_USING_LDAPV2_QUOTES_TITLE,
+ WARN_USING_LDAPV2_QUOTES,
+ dn_to_test, dn_to_test, newdn);
+ free(newdn);
+ }
+ if (utf8dn)
+ nsSetupFree(utf8dn);
+
+ return;
+}
+
+int
+IsValidAdminDomain(
+ const char *host,
+ int port,
+ const char *suffix,
+ const char *admin_domain,
+ const char *binddn,
+ const char *binddnpwd
+)
+{
+ char ldapurl[4096];
+ int status = FALSE;
+ Ldap *ldap = NULL;
+
+ sprintf(ldapurl, "ldap://%s:%d/%s", host, port, suffix);
+ if (createLdap(&ldap, ldapurl, binddn, binddnpwd, 0, 0) == OKAY)
+ {
+ LdapEntry *le = createLdapEntry(ldap);
+ char *dn = formAdminDomainDN(admin_domain);
+ if (le && dn && entryExists(le, dn))
+ status = TRUE;
+ if (dn)
+ nsSetupFree(dn);
+ if (le)
+ destroyLdapEntry(le);
+ }
+
+ if (ldap)
+ destroyLdap(ldap);
+
+ return status;
+}
+
+void ControlSlapdInstance(char *pszServiceName, BOOL bOn);
+static void ConvertPasswordToPin(char *pszServerRoot, char *pszServiceName);
+static void ReinstallUpgradeServer(char *pszServerRoot, char *pszServiceName);
+
+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, &ltm );
+#endif
+ strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", &ltm );
+ return buf;
+}
+
+char *onezero2yesno(int value)
+{
+
+ if (1 == value)
+ {
+ return "yes";
+ }else{
+ return "no";
+ }
+
+}
+
+int yesno2onezero(char *value)
+{
+
+ if(!lstrcmpi("yes", value) )
+ {
+ return 1;
+ }else{
+ return 0;
+ }
+
+}
+
+////////////////
+///
+// determine whether a string contains 8 bit characters
+//
+static int
+contains8BitChars(const char *s)
+{
+ int ret = 0;
+
+ if (s && *s)
+ {
+ for (; !ret && *s; ++s)
+ {
+ ret = (*s & 0x80);
+ }
+ }
+
+ return ret;
+}
+
+////////////////
+///
+// determine whether a dn is valid or not
+//
+static int
+isAValidDN(const char *dn_to_test)
+{
+ int ret = 1;
+
+ if (!dn_to_test || !*dn_to_test)
+ {
+ ret = 0;
+ }
+ else
+ {
+ char *utf8dn = localToUTF8(dn_to_test);
+ char **rdnList = ldap_explode_dn(utf8dn, 0);
+ char **rdnNoTypes = ldap_explode_dn(utf8dn, 1);
+ if (!rdnList || !rdnList[0] || !rdnNoTypes || !rdnNoTypes[0] ||
+ !*rdnNoTypes[0] || !stricmp(rdnList[0], rdnNoTypes[0]))
+ {
+ ret = 0;
+ }
+ if (rdnList)
+ ldap_value_free(rdnList);
+ if (rdnNoTypes)
+ ldap_value_free(rdnNoTypes);
+ if (utf8dn)
+ nsSetupFree(utf8dn);
+ }
+
+ if ((ret == 1) && dn_to_test)
+ checkForLDAPv2Quoting(dn_to_test);
+
+ return ret;
+}
+
+
+////////////////
+///
+// check if DN is valid, display error if not
+// returns 1 if dn is valid
+// 0 if dn is invalid
+int isValidDN(char *dn)
+{
+ int nReturn;
+
+ if( 0 == (nReturn = isAValidDN(dn)) )
+ DSMessageBoxOK(ERR_INVALID_DN_TITLE, ERR_INVALID_DN, dn, dn);
+
+ return nReturn;
+}
+
+////////////////
+///
+// check if port is valid, display error if not
+// returns 1 if port is valid
+// 0 if port is invalid
+int isValidPort(int port)
+{
+ int nReturn = 1;
+ if (port <= 0 || port > MAXPORT)
+ {
+ DSMessageBoxOK(ERR_INVALID_PORT_TITLE, ERR_INVALID_PORT, 0,
+ port);
+ nReturn = 0;
+ }
+
+ return nReturn;
+}
+
+////////////////
+///
+// get the components out of an ldapurl
+//
+//
+
+int GetURLComponents(char *szURL, char *szHost, int *nPort, char *szBase)
+{
+
+ LDAPURLDesc *ludpp;
+
+ int res;
+
+ if ( ( res = ldap_url_parse( szURL, &ludpp ) ) != 0 )
+ {
+ return res;
+ }
+
+ if( NULL != ludpp->lud_host)
+ {
+ strcpy(szHost, ludpp->lud_host);
+ }else{
+ strcpy(szHost, "\0");
+ }
+
+ *nPort = ludpp->lud_port;
+
+ if( NULL != ludpp->lud_dn)
+ {
+ strcpy(szBase, ludpp->lud_dn);
+ }else{
+ strcpy(szBase, "\0");
+ }
+
+
+ ldap_free_urldesc( ludpp );
+
+ return 0;
+
+}
+
+////////////////
+///
+//
+//
+void StartWSA()
+{
+WORD wVersionRequested;
+WSADATA wsaData;
+int err;
+
+wVersionRequested = MAKEWORD( 2, 0 );
+
+err = WSAStartup( wVersionRequested, &wsaData );
+if ( err != 0 ) {
+ /* Tell the user that we couldn't find a usable */
+ /* WinSock DLL. */
+ DSMessageBoxOK(ERR_NO_WINSOCK_TITLE, ERR_NO_WINSOCK, 0);
+ return;
+}
+
+/* Confirm that the WinSock DLL supports 2.0.*/
+/* Note that if the DLL supports versions greater */
+/* than 2.0 in addition to 2.0, it will still return */
+/* 2.0 in wVersion since that is the version we */
+/* requested. */
+
+if ( LOBYTE( wsaData.wVersion ) != 2 ||
+ HIBYTE( wsaData.wVersion ) != 0 ) {
+ /* Tell the user that we couldn't find a usable */
+ /* WinSock DLL. */
+ DSMessageBoxOK(ERR_NO_WINSOCK_VER_TITLE, ERR_NO_WINSOCK_VER, 0);
+ WSACleanup( );
+ return;
+}
+
+/* The WinSock DLL is acceptable. Proceed. */
+
+}
+
+////////////////
+//
+//
+//
+
+BOOL FullyQualifyHostName(char * HostName)
+{
+ static char * domain = 0;
+ struct hostent * hptr;
+ BOOL bRC = TRUE;
+
+ hptr = (struct hostent*)gethostbyname(HostName);
+ if (hptr) {
+ /* See if h_name is fully-qualified */
+ if (hptr->h_name) {
+ domain = strchr(hptr->h_name, '.');
+ sprintf(HostName,"%s",hptr->h_name);
+ return bRC;
+ }
+
+ /* Otherwise look for a fully qualified alias */
+ if ((domain == 0) &&
+ (hptr->h_aliases && hptr->h_aliases[0])) {
+ char **p;
+ for (p = hptr->h_aliases; *p; ++p) {
+ domain = strchr(*p, '.');
+ if (domain) break;
+ }
+ }
+ }
+
+ if (domain != 0)
+ {
+ if (domain[0] == '.')
+ {
+ ++domain;
+ }
+ sprintf(HostName,"%s.%s", HostName, domain);
+ } else
+ {
+ bRC = FALSE;
+ }
+
+ return bRC;
+}
+
+/////////////////
+//
+// UTF8IsValidLdapUser
+//
+// converts necessary things to UTF8 before calling server
+//
+
+BOOL UTF8IsValidLdapUser(char *szHost, int nPort, char *szSuffix, char *szBindAs, char *szPw, BOOL bParam)
+{
+
+ char *utf8Host=NULL;
+ char *utf8Suffix=NULL;
+ char *utf8BindAs=NULL;
+ char *utf8Pw=NULL;
+ BOOL bReturn;
+
+ /* convert to UTF8 first incase international data */
+ utf8Host = localToUTF8(szHost);
+ utf8Suffix = localToUTF8(szSuffix);
+ utf8BindAs = localToUTF8(szBindAs);
+ utf8Pw = localToUTF8(szPw);
+
+ bReturn = IsValidLdapUser(utf8Host, nPort, utf8Suffix, &utf8BindAs, utf8Pw, bParam);
+
+ if( utf8Host) nsSetupFree(utf8Host);
+ if( utf8Suffix) nsSetupFree(utf8Suffix);
+ if( utf8BindAs) nsSetupFree(utf8BindAs);
+ if( utf8Pw) nsSetupFree(utf8Pw);
+
+ return bReturn;
+
+}
+
+/////////////////
+//
+// UTF8IsValidAdminDomain
+//
+// converts necessary things to UTF8 before calling server
+//
+
+BOOL UTF8IsValidAdminDomain(char *szHost, int nPort, char *szSuffix, char *szAdminDomain, char *szBindAs, char *szPw)
+{
+
+ char *utf8Host=NULL;
+ char *utf8Suffix=NULL;
+ char *utf8BindAs=NULL;
+ char *utf8Pw=NULL;
+ char *utf8AdminDomain=NULL;
+ BOOL bReturn;
+
+ /* convert to UTF8 first incase international data */
+ utf8Host = localToUTF8(szHost);
+ utf8Suffix = localToUTF8(szSuffix);
+ utf8BindAs = localToUTF8(szBindAs);
+ utf8Pw = localToUTF8(szPw);
+ utf8AdminDomain = localToUTF8(szAdminDomain);
+
+ bReturn = IsValidAdminDomain(utf8Host, nPort, utf8Suffix, utf8AdminDomain, utf8BindAs, utf8Pw);
+
+ if( utf8Host) nsSetupFree(utf8Host);
+ if( utf8Suffix) nsSetupFree(utf8Suffix);
+ if( utf8BindAs) nsSetupFree(utf8BindAs);
+ if( utf8Pw) nsSetupFree(utf8Pw);
+ if( utf8AdminDomain) nsSetupFree(utf8AdminDomain);
+
+ return bReturn;
+
+}
+
+
+void getAdminServInfo()
+{
+ char *pszAdminSection="admin";
+ char szTempDir[MAX_PATH];
+ char szCacheFile[MAX_PATH];
+
+ GetEnvironmentVariable("TEMP", szTempDir, sizeof(szTempDir));
+
+ sprintf(szCacheFile, "%s\\install.inf", szTempDir);
+
+ mi.m_nAdminServerPort = GetPrivateProfileInt(pszAdminSection, SLAPD_KEY_ADMIN_SERVER_PORT,
+ -1, szCacheFile);
+ if (mi.m_nAdminServerPort == -1) {
+ myLogData("Warning: Could not determine admin server port for Directory Server Gateway and Orgchart configuration files. Please update them manually.");
+ mi.m_nAdminServerPort = DEFAULT_ADMIN_PORT;
+ }
+
+}
+
+BOOL writeINFfile(const char *filename)
+{
+ FILE *fp = fopen(filename, "wb");
+
+
+ if (NULL == fp)
+ return FALSE;
+
+
+ if(0 == lstrcmp("\0", mi.m_szInstallDN) )
+ {
+ char * szAdminDN = NULL;
+ szAdminDN = formAdminDomainDN(mi.m_szAdminDomain);
+ if (szAdminDN)
+ {
+ sprintf(mi.m_szInstallDN, szAdminDN);
+ nsSetupFree(szAdminDN);
+ }
+ else
+ {
+ //note probably should fail.
+ LogData(NULL, "Warning: Slapd unable to Form Admin Domain, guessing");
+ sprintf(mi.m_szInstallDN, "ou=%s, o=NetscapeRoot", mi.m_szAdminDomain);
+ }
+ }
+
+ // write global section header
+ fprintf(fp, "[General]\n");
+ fprintf(fp, "%s= %s\n", GLOBAL_INF_LDAP_USED, "TRUE");
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SERVER_ADMIN_ID, mi.m_szMCCBindAs);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SERVER_ADMIN_PWD, mi.m_szMCCPw);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_FULL_MACHINE_NAME, mi.m_szInstanceHostName);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SERVER_ROOT, TARGETDIR);
+
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_K_LDAP_URL, mi.m_szLdapURL);
+
+
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_ADMIN_DOMAIN, mi.m_szAdminDomain);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_USER_GROUP_LDAP_URL, mi.m_szUserGroupURL);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_USER_GROUP_ADMIN_ID, mi.m_szUserGroupAdmin);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_USER_GROUP_ADMIN_PWD, mi.m_szUserGroupAdminPW);
+
+ // write Admin section header.
+ getAdminServInfo(); /* Right now this only gets the admin port. If you want more,
+ you'll have to change getAdminServInfo.*/
+ fprintf(fp, "\n[admin]\n");
+ fprintf(fp, "%s= %d\n", SLAPD_KEY_ADMIN_SERVER_PORT, mi.m_nAdminServerPort);
+
+
+ // write DS section header
+ fprintf(fp, "\n[slapd]\n");
+ fprintf(fp, "%s= %d\n", SLAPD_KEY_SERVER_PORT, mi.m_nInstanceServerPort);
+ if(0 == mi.m_nExistingUG)
+ {
+ /* don't write this key when config only directory */
+ /* config only directory when using existing data store */
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SUFFIX, mi.m_szInstanceSuffix);
+ }
+
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_USE_EXISTING_MC,
+ onezero2yesno(mi.m_nExistingMCC));
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_USE_EXISTING_UG,
+ onezero2yesno(mi.m_nExistingUG));
+
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_ROOTDN, mi.m_szInstanceUnrestrictedUser);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_ROOTDNPWD, mi.m_szInstancePassword);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SERVER_IDENTIFIER, mi.m_szServerIdentifier);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SLAPD_CONFIG_FOR_MC, onezero2yesno(mi.m_nCfgSspt) );
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_ADD_SAMPLE_ENTRIES, onezero2yesno(mi.m_nPopulateSampleEntries));
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_ADD_ORG_ENTRIES, onezero2yesno(mi.m_nPopulateSampleOrg));
+
+
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_USE_REPLICATION, onezero2yesno(
+ (mi.m_nSetupConsumerReplication || mi.m_nSetupSupplierReplication) ));
+
+ /* consumer replication settings */
+ fprintf(fp, "%s= %d\n", SLAPD_KEY_SETUP_CONSUMER, mi.m_nSetupConsumerReplication);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CIR_HOST, mi.m_szConsumerHost);
+ fprintf(fp, "%s= %d\n", SLAPD_KEY_CIR_PORT, mi.m_nConsumerPort);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CIR_SUFFIX, mi.m_szConsumerRoot);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CIR_BINDDN, mi.m_szConsumerBindAs);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CIR_BINDDNPWD, mi.m_szConsumerPw);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CIR_SECURITY_ON, onezero2yesno(mi.m_nConsumerSSL));
+ fprintf(fp, "%s= %d\n", SLAPD_KEY_CIR_INTERVAL, mi.m_nCIRInterval);
+
+ if(!strcmp(DEFAULT_CIR_DAYS, mi.m_szCIRDays) )
+ {
+ /* if default of all days write null to inf file as that is what cgi wants */
+ fprintf(fp, "%s=\n", SLAPD_KEY_CIR_DAYS);
+ }else{
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CIR_DAYS, mi.m_szCIRDays);
+ }
+
+ if(!strcmp(DEFAULT_CIR_TIMES, mi.m_szCIRTimes) )
+ {
+ /* if default of all times write null to inf file as that is what cgi wants */
+ fprintf(fp, "%s=\n", SLAPD_KEY_CIR_TIMES);
+ }else{
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CIR_TIMES, mi.m_szCIRTimes);
+ }
+
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_REPLICATIONDN, mi.m_szSupplierDN);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_REPLICATIONPWD, mi.m_szSupplierPW);
+
+
+ /* Supplier replication settings */
+ fprintf(fp, "%s= %d\n", SLAPD_KEY_SETUP_SUPPLIER, mi.m_nSetupSupplierReplication);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CHANGELOGDIR, mi.m_szChangeLogDbDir);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CHANGELOGSUFFIX, mi.m_szChangeLogSuffix);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SIR_HOST, mi.m_szSupplierHost);
+ fprintf(fp, "%s= %d\n", SLAPD_KEY_SIR_PORT, mi.m_nSupplierPort);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SIR_SUFFIX, mi.m_szSupplierRoot);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SIR_BINDDN, mi.m_szSupplierBindAs);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SIR_BINDDNPWD, mi.m_szSupplierPw);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SIR_SECURITY_ON, onezero2yesno(mi.m_nSupplierSSL));
+
+ if(!strcmp(DEFAULT_SIR_DAYS, mi.m_szSIRDays) )
+ {
+ /* if default of all days write null to inf file as that is what cgi wants */
+ fprintf(fp, "%s=\n", SLAPD_KEY_SIR_DAYS);
+ }else{
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SIR_DAYS, mi.m_szSIRDays);
+ }
+
+ if(!strcmp(DEFAULT_SIR_TIMES, mi.m_szSIRTimes) )
+ {
+ /* if default of all times write null to inf file as that is what cgi wants */
+ fprintf(fp, "%s=\n", SLAPD_KEY_SIR_TIMES);
+ }else{
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SIR_TIMES, mi.m_szSIRTimes);
+ }
+
+ fprintf(fp, "%s= %s\n", LOCAL_INF_CONFIG_CONSUMER_DN, onezero2yesno(mi.m_nConfigConsumerDN));
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CONSUMERDN, mi.m_szConsumerDN);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_CONSUMERPWD, mi.m_szConsumerPW);
+
+
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_INSTALL_LDIF_FILE, mi.m_szPopLdifFile);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_DISABLE_SCHEMA_CHECKING, onezero2yesno(mi.m_nDisableSchemaChecking));
+
+ fprintf(fp, "%s= %d\n", LOCAL_INF_SNMP_ON, mi.m_nSNMPOn);
+ fprintf(fp, "%s= %s\n", SLAPD_INSTALL_LOG_FILE_NAME, LOGFILE );
+
+ fclose(fp);
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// isValidServerID(char *pszServerIdentifier)
+//
+// check if valid serverid, for n
+//
+
+BOOL isValidServerID(char *pszServerIdentifier)
+{
+
+ char *fullId;
+ char line[MAX_PATH];
+ DWORD Result;
+ HKEY hServerKey;
+ BOOL bRC = TRUE;
+
+ /* first check that it only contains 7 bit characters */
+ if( contains8BitChars(pszServerIdentifier) )
+ {
+ DSMessageBoxOK(ERR_8BIT_SERVID_TITLE, ERR_8BIT_SERVID, 0);
+ bRC = FALSE;
+ }else{
+ /* looks ok, now check if it already exists */
+
+ /* for now just check registry to see if this server ID exists,
+ in future add might want to add more sanity checks */
+
+ fullId = (char *)malloc(lstrlen(DS_ID_SERVICE) + lstrlen(pszServerIdentifier) + 6);
+ sprintf(fullId, "%s-%s", DS_ID_SERVICE, pszServerIdentifier);
+
+ sprintf(line, "%s\\%s", KEY_SERVICES, fullId);
+
+ Result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ line,
+ 0,
+ KEY_ALL_ACCESS,
+ &hServerKey);
+
+
+ if (Result == ERROR_SUCCESS)
+ {
+ /* it already exists */
+ DSMessageBoxOK(ERR_SERVER_ID_EXISTS_TITLE, ERR_SERVER_ID_EXISTS,
+ getShortName(pszServerIdentifier),
+ getShortName(pszServerIdentifier));
+ bRC = FALSE;
+
+ }
+
+ free(fullId);
+ }
+
+ return bRC;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// set_default_ldap_settings()
+//
+// hostname = getHostName
+// serverid = hostname up to first period
+// suffix = o=(rest of hostname) ie o=mcom.com
+// port = 389
+// rootDn = DirectoryManager
+
+
+int set_default_ldap_settings()
+{
+
+ int i, j = 0;
+
+ DSGetHostName(mi.m_szInstanceHostName, MAX_STR_SIZE);
+ /* assumption: hostname up to first period for serverid */
+ for( i = 0; !( (mi.m_szInstanceHostName[i] == '\0')
+ || (mi.m_szInstanceHostName[i] == '.' ) );
+ i++)
+ {
+ mi.m_szServerIdentifier[i] = mi.m_szInstanceHostName[i];
+ }
+ /* null terminate it */
+ mi.m_szServerIdentifier[i]='\0';
+ if (mi.m_szInstanceHostName[0] && strchr(mi.m_szInstanceHostName, '.'))
+ {
+ DSGetDefaultSuffix(mi.m_szInstanceSuffix, mi.m_szInstanceHostName);
+ }
+ else
+ {
+ strcpy(mi.m_szInstanceSuffix, "dc=example, dc=com");
+ }
+
+ /* default admin domain is also derived from the FQDN */
+ ++i;
+ sprintf(mi.m_szAdminDomain, "%s", mi.m_szInstanceHostName+i);
+
+ mi.m_nInstanceServerPort=DEFAULT_SERVER_PORT;
+
+ sprintf(mi.m_szInstanceUnrestrictedUser, DEFAULT_UNRESTRICTED_USER);
+
+ mi.m_nCfgSspt = DEFAULT_CONFIG_SSPT;
+
+ sprintf(mi.m_szSsptUid, DEFAULT_SSPT_USER);
+
+ /* stevross: don't want default for these in silent mode, user must specify them */
+ if( SILENTMODE != MODE)
+ {
+ sprintf(mi.m_szSupplierDN, DEFAULT_SUPPLIER_DN);
+ sprintf(mi.m_szChangeLogSuffix, DEFAULT_CHANGELOGSUFFIX);
+
+ }
+
+
+
+ /* don't want to use these unless they were asked in dialog, then this flag will be
+ changed */
+ mi.m_nSetupSupplierReplication = NO_REPLICATION;
+ mi.m_nSetupConsumerReplication = NO_REPLICATION;
+
+ mi.m_nUseSupplierSettings = 0;
+ mi.m_nUseChangeLogSettings = 0;
+
+
+ lstrcpy(mi.m_szSIRDays, DEFAULT_SIR_DAYS);
+ lstrcpy(mi.m_szSIRTimes, DEFAULT_SIR_TIMES);
+ mi.m_nSupplierPort = DEFAULT_SERVER_PORT;
+
+ lstrcpy(mi.m_szCIRDays, DEFAULT_CIR_DAYS);
+ lstrcpy(mi.m_szCIRTimes, DEFAULT_CIR_TIMES);
+ mi.m_nConsumerPort = DEFAULT_SERVER_PORT;
+
+ mi.m_nCIRInterval = DEFAULT_CIR_INTERVAL;
+
+
+ /* default MCC settings */
+ lstrcpy(mi.m_szMCCSuffix, NS_DOMAIN_ROOT);
+ mi.m_nMCCPort=DEFAULT_SERVER_PORT;
+
+ mi.m_szMCCBindAs = malloc(MAX_STR_SIZE);
+ sprintf(mi.m_szMCCBindAs, "%s", DEFAULT_SSPT_USER);
+
+ lstrcpy(mi.m_szUGSuffix, mi.m_szInstanceSuffix);
+ mi.m_nUGPort=DEFAULT_SERVER_PORT;
+ lstrcpy(mi.m_szUserGroupAdmin, DEFAULT_UNRESTRICTED_USER);
+
+ mi.m_nPopulateSampleEntries = DEFAULT_POPULATE_SAMPLE_ENTRIES;
+ mi.m_nDisableSchemaChecking = DEFAULT_DISABLE_SCHEMA_CHECKING;
+
+ return 0;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// verify_ldap_settings()
+//
+// verifys that ldap settings are valid before installing instance
+//
+//
+int verify_ldap_settings()
+{
+ /* XXX stevross: may want to add checks for other things later */
+
+ /* for now just make sure port is valid */
+ if( IsValidNetworkPort( mi.m_nInstanceServerPort ) )
+ {
+ return 0;
+ }else{
+ DSMessageBoxOK(ERR_SERV_RUN_ON_PORT_TITLE, ERR_SERV_RUN_ON_PORT,
+ 0, mi.m_nInstanceServerPort);
+ return -1;
+ }
+
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// set_ldap_settings()
+//
+// registers ldap settings with framework for use by other installers
+//
+//
+
+void set_ldap_settings()
+{
+
+ char *utf8MCCHost=NULL;
+ char *utf8MCCSuffix=NULL;
+ char *utf8MCCBindAs=NULL;
+ char *utf8MCCPw=NULL;
+ char *utf8AdminDomain=NULL;
+ char szFullAdminDN[MAX_STR_SIZE];
+
+ if(1 != mi.m_nExistingMCC && SILENTMODE != MODE)
+ {
+ /* this new instance will be MCC, but only copy over things
+ if not silent mode, in silent mode it will read correct
+ mcc stuff from the cache */
+ lstrcpy(mi.m_szMCCHost, mi.m_szInstanceHostName);
+ mi.m_nMCCPort = mi.m_nInstanceServerPort;
+ lstrcpy(mi.m_szMCCSuffix, NS_DOMAIN_ROOT);
+ sprintf(mi.m_szMCCBindAs, "%s", mi.m_szSsptUid);
+ lstrcpy(mi.m_szMCCPw, mi.m_szSsptUidPw);
+
+ }
+
+ /* use existing MCC stuff we read in */
+
+ /* convert to UTF8 first for international stuff */
+ utf8MCCHost = localToUTF8(mi.m_szMCCHost);
+ utf8MCCSuffix = localToUTF8(mi.m_szMCCSuffix);
+ utf8MCCBindAs = localToUTF8(mi.m_szMCCBindAs);
+ utf8MCCPw = localToUTF8(mi.m_szMCCPw);
+
+ wsprintf(szFullAdminDN, NS_ADMIN_DOMAIN, mi.m_szAdminDomain);
+ utf8AdminDomain = localToUTF8(szFullAdminDN);
+ SetLdapHost(utf8MCCHost);
+ SetLdapPort(mi.m_nMCCPort);
+ SetLdapSuffix(utf8MCCSuffix);
+ SetLdapUser(utf8MCCBindAs);
+ SetLdapPassword(utf8MCCPw);
+ SetLdapInstallDN(utf8AdminDomain);
+
+ if( utf8MCCHost) nsSetupFree(utf8MCCHost);
+ if( utf8MCCSuffix) nsSetupFree(utf8MCCSuffix);
+ if( utf8MCCBindAs) nsSetupFree(utf8MCCBindAs);
+ if( utf8MCCPw) nsSetupFree(utf8MCCPw);
+ if( utf8AdminDomain) nsSetupFree(utf8AdminDomain);
+
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// _DialogProcs
+//
+// The dialog procedure for a single property page. You will need to create
+// one of these for each property page used in the property sheet. This
+// procedure processes dialog messages sent to your property page by Windows.
+// See the Windows SDK documentation for more information about this function.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+// Setup8bitInputDisplay
+//
+// sets up dialog components to handle 8bit entry/display for I18n requirement
+//
+//
+//
+
+void Setup8bitInputDisplay(HWND hwndDlg, INT hControls[])
+{
+ INT i;
+
+ for(i=0; hControls[i] != -1; i++)
+ {
+ SendDlgItemMessage (hwndDlg, hControls[i], WM_SETFONT,
+ (WPARAM) GetStockObject(DEFAULT_GUI_FONT) , MAKELPARAM(TRUE, 0));
+
+ }
+
+}
+
+
+
+/////////////////////////////////////////////////////////////////////////////
+// EnableControls
+//
+// toggles editable state of Fields
+//
+//
+//
+
+BOOL EnableControls(INT Controls[], HWND hwndDlg, BOOL bEnable)
+{
+ INT i;
+ HWND hControl;
+
+ for(i=0; Controls[i] != -1; i++)
+ {
+
+ hControl = GetDlgItem(hwndDlg, Controls[i]);
+ EnableWindow(hControl, bEnable);
+ }
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// EnableLDAPURLSettingsFields
+//
+// toggles editable state of MCC Settings Fields
+//
+//
+//
+
+BOOL EnableLDAPURLSettingsFields(HWND hwndDlg, BOOL bEnable)
+{
+ INT LDAPURL_Controls[]={IDC_EDIT_HOST,
+ IDC_EDIT_PORT,
+ IDC_EDIT_SUFFIX,
+ IDC_EDIT_BIND_AS,
+ IDC_EDIT_PW, -1};
+
+ EnableControls(LDAPURL_Controls, hwndDlg, bEnable);
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// EnableConsumerDNFields
+//
+// toggles editable state of Consumer DN Fields
+//
+//
+//
+
+BOOL EnableConsumerDNFields(HWND hwndDlg, BOOL bEnable)
+{
+ INT Consumer_DN_Controls[]={IDC_EDIT_CONSUMER_DN,
+ IDC_EDIT_PASSWORD,
+ IDC_EDIT_PASSWORD_AGAIN,
+ -1};
+
+ EnableControls(Consumer_DN_Controls, hwndDlg, bEnable);
+
+ return TRUE;
+}
+
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// SaveDlgServerInfo
+//
+// Gets host, port, suffix, bind as, pw from dialog
+// used for MCC Settings, UG Settings, Replication Agreement Dialogs
+//
+
+void SaveDlgServerInfo(HWND hwndDlg,
+ PSZ pszHost,
+ INT *pnPort,
+ PSZ pszSuffix,
+ PSZ pszBindAs,
+ PSZ pszPw)
+{
+ BOOL bTrans;
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_HOST,
+ pszHost,
+ MAX_STR_SIZE);
+
+ *pnPort = GetDlgItemInt(hwndDlg,
+ IDC_EDIT_PORT,
+ &bTrans,
+ FALSE);
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_SUFFIX,
+ pszSuffix,
+ MAX_STR_SIZE);
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_BIND_AS,
+ pszBindAs,
+ MAX_STR_SIZE);
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_PW,
+ pszPw,
+ MAX_STR_SIZE);
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// LoadDlgServerInfo
+//
+// Sets host, port, suffix, bind as, pw from dialog
+// used for MCC Settings, UG Settings, Replication Agreement Dialogs
+//
+
+void LoadDlgServerInfo(HWND hwndDlg,
+ PSZ pszHost,
+ INT nPort,
+ PSZ pszSuffix,
+ PSZ pszBindAs,
+ PSZ pszPw)
+{
+ BOOL bResult;
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_HOST,
+ pszHost);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ bResult = SetDlgItemInt(hwndDlg,
+ IDC_EDIT_PORT,
+ nPort,
+ TRUE);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_SUFFIX,
+ pszSuffix);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_BIND_AS,
+ pszBindAs);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_PW,
+ pszPw);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// VerifyServerInfo
+//
+// verifies Server settings are ok
+//
+// Returns TRUE if there is an invalid setting
+// Returns FALSE if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+BOOL VerifyServerInfo( PSZ pszHost,
+ INT *pnPort,
+ PSZ pszSuffix,
+ PSZ pszBindAs,
+ PSZ pszPw,
+ BOOL bVerifyBindAs)
+{
+ BOOL bValueReturned = TRUE;
+
+ if ( 0 == strlen( pszHost) )
+ {
+ DSMessageBoxOK(ERR_NO_HOST_TITLE, ERR_NO_HOST, 0);
+ } else if ( 0 == *pnPort )
+ {
+ DSMessageBoxOK(ERR_NO_PORT_TITLE, ERR_NO_PORT, 0);
+ } else if ( 0 == strlen( pszSuffix) )
+ {
+ DSMessageBoxOK(ERR_NO_SUFFIX_TITLE, ERR_NO_SUFFIX, 0);
+ } else if ( !isValidDN(pszSuffix) )
+ {
+ /* error message displayed by isvalidDN */
+ } else if ( 0 == strlen( pszBindAs) )
+ {
+ DSMessageBoxOK(ERR_NO_BIND_DN_TITLE, ERR_NO_BIND_DN, 0);
+ }else if ( 0 == strlen( pszPw) )
+ {
+ DSMessageBoxOK(ERR_NO_PW_TITLE, ERR_NO_PW, 0);
+ } else if (contains8BitChars(pszPw) )
+ {
+
+ DSMessageBoxOK(ERR_8BIT_PW_TITLE, ERR_8BIT_PW, 0);
+ } else
+ {
+ /* all settings look good */
+ bValueReturned = FALSE;
+ }
+
+ /* try to verify valid dn if need to and no
+ previous invalid fields */
+
+ if( !bValueReturned && bVerifyBindAs )
+ {
+ /* error message displayed by isvalidDN */
+ if ( !isValidDN(pszBindAs) )
+ {
+ /* dn is invalid return true from here */
+ bValueReturned = TRUE;
+ }
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SaveDialogInput_MCC_Settings
+//
+// save MCC settings entered on Dialog on back and next
+//
+//
+//
+
+void SaveDialogInput_MCC_Settings(HWND hwndDlg)
+{
+
+ if( 1 == mi.m_nExistingMCC )
+ {
+ SaveDlgServerInfo(hwndDlg,
+ mi.m_szMCCHost,
+ &mi.m_nMCCPort,
+ mi.m_szMCCSuffix,
+ mi.m_szMCCBindAs,
+ mi.m_szMCCPw);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// VerifyDialogInput_MCC_Settings
+//
+// verify MCC settings entered on Dialog on back and next
+//
+//
+// Returns TRUE if there is an invalid setting
+// Returns FALSE if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+
+BOOL Verify_MCC_Settings()
+{
+ BOOL bValueReturned = FALSE;
+
+ /* only check if configuring to use existing MCC */
+ if (1 == mi.m_nExistingMCC)
+ {
+ if( FALSE == ( bValueReturned = VerifyServerInfo(mi.m_szMCCHost,
+ &mi.m_nMCCPort,
+ mi.m_szMCCSuffix,
+ mi.m_szMCCBindAs,
+ mi.m_szMCCPw,
+ FALSE) ) )
+ {
+ /* server info ok, now check rest of the settigns */
+ if (FALSE == FullyQualifyHostName(mi.m_szMCCHost) )
+ {
+ /* can't qualify host name, must be invalid */
+ DSMessageBoxOK(ERR_INVALID_HOST_TITLE, ERR_INVALID_HOST,
+ mi.m_szMCCHost, mi.m_szMCCHost);
+ bValueReturned = TRUE;
+ } else
+ {
+ /* now that all settings entered, check to see if valid user */
+ if (FALSE == (UTF8IsValidLdapUser( mi.m_szMCCHost,
+ mi.m_nMCCPort,
+ mi.m_szMCCSuffix,
+ mi.m_szMCCBindAs,
+ mi.m_szMCCPw,
+ FALSE) ) )
+ {
+ DSMessageBoxOK(ERR_CANT_FIND_DS_TITLE,
+ ERR_CANT_FIND_DS, 0,
+ mi.m_szMCCHost,
+ mi.m_nMCCPort,
+ mi.m_szMCCBindAs);
+ bValueReturned = TRUE;
+ }
+ /* now that all settings entered, find admin domain */
+ else if ((CUSTOMMODE != MODE) &&
+ (FALSE == (UTF8IsValidAdminDomain( mi.m_szMCCHost,
+ mi.m_nMCCPort,
+ mi.m_szMCCSuffix,
+ mi.m_szAdminDomain,
+ mi.m_szMCCBindAs,
+ mi.m_szMCCPw) ) ) )
+ {
+ DSMessageBoxOK(ERR_CANT_FIND_ADMIN_DOMAIN_TITLE,
+ ERR_CANT_FIND_ADMIN_DOMAIN, mi.m_szAdminDomain,
+ mi.m_szAdminDomain,
+ mi.m_szMCCHost,
+ mi.m_nMCCPort,
+ mi.m_szMCCBindAs);
+ bValueReturned = TRUE;
+ }
+
+ /* all settings good */
+
+ /* don't want to cfg sspt if already have mcc user */
+ mi.m_nCfgSspt = 0;
+ }
+
+ }
+
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// MCC_Settings_DialogProc
+//
+// dialog proc to choose MCC server settings
+//
+//
+//
+
+static BOOL CALLBACK
+MCC_Settings_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_HOST,
+ IDC_EDIT_SUFFIX,
+ IDC_EDIT_BIND_AS,
+ IDC_EDIT_PW, -1};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ ShowWindow(GetDlgItem(hwndDlg, IDC_EDIT_SUFFIX), FALSE);
+ ShowWindow(GetDlgItem(hwndDlg, IDC_STATIC_MCC_SUFFIX), FALSE);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_USE_EXISTING_SERVER) )
+ {
+ EnableLDAPURLSettingsFields(hwndDlg, TRUE);
+ mi.m_nExistingMCC = 1;
+ }else if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_USE_THIS_SERVER) ){
+ EnableLDAPURLSettingsFields(hwndDlg, FALSE);
+ mi.m_nExistingMCC = 0;
+ }
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+ LoadDlgServerInfo(hwndDlg,
+ mi.m_szMCCHost,
+ mi.m_nMCCPort,
+ mi.m_szMCCSuffix,
+ mi.m_szMCCBindAs,
+ mi.m_szMCCPw);
+
+ CheckRadioButton(hwndDlg, IDC_RADIO_USE_THIS_SERVER,
+ IDC_RADIO_USE_EXISTING_SERVER,
+ ( (1 == mi.m_nExistingMCC) ? IDC_RADIO_USE_EXISTING_SERVER :
+ IDC_RADIO_USE_THIS_SERVER));
+
+ if(1 == mi.m_nExistingMCC)
+ {
+ EnableLDAPURLSettingsFields(hwndDlg, TRUE);
+ }else{
+ EnableLDAPURLSettingsFields(hwndDlg, FALSE);
+ }
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+
+ SaveDialogInput_MCC_Settings(hwndDlg);
+
+ /* first dialog, so send wizback to previous module */
+ mi.m_nResult = NS_WIZBACK;
+ SendMessage(GetParent(hwndDlg), WM_CLOSE, 0, 0);
+
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+
+ SaveDialogInput_MCC_Settings(hwndDlg);
+ if( TRUE == (bValueReturned = Verify_MCC_Settings() ) )
+ {
+ // one of the settings was invalid so stay on this page
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// SaveDialogInput_ReInstall
+//
+// saves settings entered in ReInstall Dlg
+//
+
+void SaveDialogInput_ReInstall(HWND hwndDlg)
+{
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_BIND_AS,
+ mi.m_szMCCBindAs,
+ MAX_STR_SIZE);
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_PW,
+ mi.m_szMCCPw,
+ MAX_STR_SIZE);
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Verify_ReInstall
+//
+// verify ReInstall settings entered on Dialog on back and next
+//
+//
+// Returns TRUE if there is an invalid setting
+// Returns FALSE if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+
+BOOL Verify_ReInstall()
+{
+ BOOL bValueReturned = FALSE;
+
+ /* Get URL components so we can verify all MCC settings */
+ if( GetURLComponents(mi.m_szLdapURL, mi.m_szMCCHost,
+ &mi.m_nMCCPort, mi.m_szMCCSuffix) != 0)
+ {
+ /* error Getting URL Components*/
+ DSMessageBoxOK(ERR_NO_CONFIG_URL_TITLE, ERR_NO_CONFIG_URL, 0);
+ bValueReturned = TRUE;
+ }else{
+
+ /* since we have all MCC info,
+ pass it thorugh Verify_MCC_Settings
+ to do all the same verifications.*/
+
+ /* set this to one so MCC Settings get checked */
+ mi.m_nExistingMCC = 1;
+
+ bValueReturned = Verify_MCC_Settings();
+ }
+
+ return bValueReturned;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// ReInstall Dialog Proc
+//
+// ask configuration information needed on reinstall
+//
+//
+//
+//
+
+static BOOL CALLBACK
+ReInstall_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_BIND_AS,
+ -1};
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+ char * szLdapUrl;
+
+ case PSN_SETACTIVE:
+
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ /* This dialog is displayed in the following ways */
+ /* Creating MCC Custom & normal mode ( after MCC admin page) */
+ /* or */
+ /* Using existing MCC Custom Mode Only (after MCC Settings Page ) */
+
+ szLdapUrl = stripConfigLdapURL(mi.m_szLdapURL);
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_CONFIG_URL_VAL,
+ szLdapUrl);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_BIND_AS,
+ mi.m_szMCCBindAs);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_PW,
+ mi.m_szMCCPw);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+
+ SaveDialogInput_ReInstall(hwndDlg);
+
+ // this is only dialog, so set back to go to other module */
+
+ mi.m_nResult = NS_WIZBACK;
+ SendMessage(GetParent(hwndDlg), WM_CLOSE, 0, 0);
+
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+
+ SaveDialogInput_ReInstall(hwndDlg);
+ if (TRUE == (bValueReturned = Verify_ReInstall() ) )
+ {
+ /* setting is invalid stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }else{
+
+ /* everything looks ok */
+
+ // this is only dialog, so set back to go to other module */
+ mi.m_nResult = NS_WIZNEXT;
+ SendMessage(GetParent(hwndDlg), WM_CLOSE, 0, 0);
+ }
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// SaveDialogInput_AdminDomain
+//
+//
+// save settings entered in admin domain dialog proc
+//
+//
+
+void SaveDialogInput_AdminDomain(HWND hwndDlg)
+{
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_ADMIN_DOMAIN,
+ mi.m_szAdminDomain,
+ MAX_STR_SIZE);
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Verify_AdminDomain
+//
+//
+// verify and save settings entered in admin domain dialog proc
+//
+// Returns TRUE if there is an invalid setting
+// Returns False if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+BOOL VerifyAdminDomain()
+{
+ BOOL bValueReturned = TRUE;
+
+ if(0 == strlen(mi.m_szAdminDomain) )
+ {
+ DSMessageBoxOK(ERR_NO_ADMIN_DOMAIN_TITLE, ERR_NO_ADMIN_DOMAIN, 0);
+ }else if(isAValidDN(mi.m_szAdminDomain) ){
+ /* admin domain is not allowed to be a DN, so if it is
+ prompt user and return error */
+ DSMessageBoxOK(ERR_ADMIN_DOMAIN_DN_TITLE, ERR_ADMIN_DOMAIN_DN,
+ mi.m_szAdminDomain, mi.m_szAdminDomain);
+ }else if (0 == mi.m_nExistingMCC){
+ /* we are creating the Config Directory, so we don't need to check if
+ the admin domain is present */
+ bValueReturned = FALSE;
+ /* now that all settings entered, find admin domain */
+ }else if (FALSE == (UTF8IsValidAdminDomain( mi.m_szMCCHost,
+ mi.m_nMCCPort,
+ mi.m_szMCCSuffix,
+ mi.m_szAdminDomain,
+ mi.m_szMCCBindAs,
+ mi.m_szMCCPw) ) )
+ {
+ DSMessageBoxOK(ERR_CANT_FIND_ADMIN_DOMAIN_TITLE,
+ ERR_CANT_FIND_ADMIN_DOMAIN, mi.m_szAdminDomain,
+ mi.m_szAdminDomain,
+ mi.m_szMCCHost,
+ mi.m_nMCCPort,
+ mi.m_szMCCBindAs);
+ bValueReturned = TRUE;
+ }else{
+ /* all settings ok, return false */
+ bValueReturned = FALSE;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Admin Domain Dialog Proc
+//
+// dialog proc to ask for admin domain
+//
+//
+//
+//
+
+static BOOL CALLBACK
+AdminDomain_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_ADMIN_DOMAIN
+ -1};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ /* This dialog is displayed in the following ways */
+ /* Creating MCC Custom & normal mode ( after MCC admin page) */
+ /* or */
+ /* Using existing MCC Custom Mode Only (after MCC Settings Page ) */
+
+
+ if(1 == mi.m_nExistingMCC )
+ {
+ /* not creating an MCC so don't ask this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_ADMIN_DOMAIN,
+ mi.m_szAdminDomain);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDialogInput_AdminDomain(hwndDlg);
+
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ SaveDialogInput_AdminDomain(hwndDlg);
+ if (TRUE == (bValueReturned = VerifyAdminDomain() ) )
+ {
+ /* setting is invalid stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Admin Domain Custom Dialog Proc
+//
+// dialog proc to ask for admin domain in custom mode when we are installing
+// into existing MCC
+//
+// basically the same as Admin Domain with some added code to lookup domain
+// kind of lame to duplicate code, but this was the best way to get flow to match unix
+//
+
+static BOOL CALLBACK
+AdminDomainCustom_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_ADMIN_DOMAIN
+ -1};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ /* This dialog is displayed in the following ways */
+ /* Creating MCC Custom & normal mode ( after MCC admin page) */
+ /* or */
+ /* Using existing MCC Custom Mode Only (after MCC Settings Page ) */
+
+
+ /* only display this page in Custom Mode if installing into existing MCC */
+ if( (0 == mi.m_nExistingMCC) || CUSTOMMODE != MODE)
+ {
+ /* dont display this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+ }
+
+ /* since we are installing into existing mcc we can search it for admin domains */
+
+ /* stevross: add code to search for admin domains here */
+
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_ADMIN_DOMAIN,
+ mi.m_szAdminDomain);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDialogInput_AdminDomain(hwndDlg);
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ SaveDialogInput_AdminDomain(hwndDlg);
+ if (TRUE == (bValueReturned = VerifyAdminDomain() ) )
+ {
+ /* setting is invalid stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// SaveDialogInput_UG_Settings(HWND hwndDlg)
+//
+// Save values entered in UG dialog on back and next
+//
+//
+
+void SaveDialogInput_UG_Settings(HWND hwndDlg)
+{
+
+ if (1 == mi.m_nExistingUG)
+ {
+ SaveDlgServerInfo(hwndDlg,
+ mi.m_szUGHost,
+ &mi.m_nUGPort,
+ mi.m_szUGSuffix,
+ mi.m_szUserGroupAdmin,
+ mi.m_szUserGroupAdminPW);
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Verify_UG_Settings()
+//
+// verify values entered in UG dialog on back and next
+//
+//
+
+BOOL Verify_UG_Settings()
+{
+ BOOL bValueReturned = FALSE;
+
+ /* only verify if installing into existing UG */
+ if (1 == mi.m_nExistingUG)
+ {
+ bValueReturned = VerifyServerInfo(mi.m_szUGHost,
+ &mi.m_nUGPort,
+ mi.m_szUGSuffix,
+ mi.m_szUserGroupAdmin,
+ mi.m_szUserGroupAdminPW,
+ FALSE);
+
+ if (FALSE == bValueReturned)
+ {
+ /* server info looks ok, now check the rest of the stuff */
+
+ if (FALSE == FullyQualifyHostName(mi.m_szUGHost) )
+ {
+ /* failed to fully qualify host name */
+ DSMessageBoxOK(ERR_INVALID_HOST_TITLE,
+ ERR_INVALID_HOST,
+ mi.m_szUGHost, mi.m_szUGHost);
+ bValueReturned = TRUE;
+ } else
+ {
+ /* now that all settings entered, check to see if valid user */
+ if (FALSE == UTF8IsValidLdapUser(mi.m_szUGHost, mi.m_nUGPort,
+ mi.m_szUGSuffix,
+ mi.m_szUserGroupAdmin,
+ mi.m_szUserGroupAdminPW,
+ FALSE) )
+ {
+
+ DSMessageBoxOK(ERR_CANT_FIND_DS_TITLE,
+ ERR_CANT_FIND_DS, 0, mi.m_szUGHost,
+ mi.m_nUGPort, mi.m_szUserGroupAdmin);
+ bValueReturned = TRUE;
+ } else
+ {
+ /* all settings good */
+ /* set UG LDAP URL */
+ sprintf(mi.m_szUserGroupURL, "ldap://%s:%d/%s",
+ mi.m_szUGHost, mi.m_nUGPort, mi.m_szUGSuffix);
+ }
+ }
+ }
+ }
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// UG_Settings_DialogProc
+//
+// dialog proc to choose User Group server settings
+//
+//
+//
+
+static BOOL CALLBACK
+UG_Settings_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+ CHAR szTemp[MAX_STR_SIZE] = {0};
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_HOST,
+ IDC_EDIT_SUFFIX,
+ IDC_EDIT_BIND_AS,
+ IDC_EDIT_PW, -1};
+
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_USE_EXISTING_SERVER) )
+ {
+ EnableLDAPURLSettingsFields(hwndDlg, TRUE);
+ mi.m_nExistingUG = 1;
+ }else if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_USE_THIS_SERVER) ){
+ EnableLDAPURLSettingsFields(hwndDlg, FALSE);
+ mi.m_nExistingUG = 0;
+ }
+
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ /* setup static text with user and group strings */
+
+ /* don't want to show this page if not installing into an existing MCC */
+ if( 1 == mi.m_nExistingMCC)
+ {
+ /* dont display this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+ }
+
+ LoadString( mi.m_hModule, IDS_UG_DESC, szTemp, MAX_STR_SIZE);
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_STATIC_DESC,
+ szTemp);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ LoadString( mi.m_hModule, IDS_UG_GB_DESC, szTemp, MAX_STR_SIZE);
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_STATIC_SETTINGS,
+ szTemp);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+
+
+ LoadString( mi.m_hModule, IDS_UG_RADIO_CREATE, szTemp, MAX_STR_SIZE);
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_RADIO_USE_THIS_SERVER,
+ szTemp);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ LoadString( mi.m_hModule, IDS_UG_RADIO_EXIST, szTemp, MAX_STR_SIZE);
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_RADIO_USE_EXISTING_SERVER,
+ szTemp);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ /* set defaults for text edit fields in this dialog */
+ LoadDlgServerInfo(hwndDlg,
+ mi.m_szUGHost,
+ mi.m_nUGPort,
+ mi.m_szUGSuffix,
+ mi.m_szUserGroupAdmin,
+ mi.m_szUserGroupAdminPW);
+
+
+ CheckRadioButton(hwndDlg, IDC_RADIO_USE_THIS_SERVER,
+ IDC_RADIO_USE_EXISTING_SERVER,
+ ( (1 == mi.m_nExistingUG) ? IDC_RADIO_USE_EXISTING_SERVER :
+ IDC_RADIO_USE_THIS_SERVER));
+
+ if(1 == mi.m_nExistingUG)
+ {
+ EnableLDAPURLSettingsFields(hwndDlg, TRUE);
+ }else{
+ EnableLDAPURLSettingsFields(hwndDlg, FALSE);
+ }
+
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDialogInput_UG_Settings(hwndDlg);
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ SaveDialogInput_UG_Settings(hwndDlg);
+ if(TRUE == (bValueReturned = Verify_UG_Settings() ) )
+ {
+ /* one of the settings was invalid */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// SaveDialogInput_Server_Settings
+//
+// save settings entered in Server_Setting_DialogProc
+// called on back and next
+//
+//
+//
+void SaveDialogInput_Server_Settings(HWND hwndDlg)
+{
+ BOOL bResult = FALSE;
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_SERVER_IDENTIFIER,
+ mi.m_szServerIdentifier,
+ MAX_STR_SIZE);
+
+ /* get the suffix */
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_SUFFIX,
+ mi.m_szInstanceSuffix,
+ MAX_STR_SIZE);
+
+ mi.m_nInstanceServerPort = (int ) GetDlgItemInt(hwndDlg,
+ IDC_EDIT_SERVER_PORT,
+ &bResult,
+ TRUE);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Verify_Server_Settings
+//
+// verify settings entered in Server_Setting_DialogProc
+//
+// Returns TRUE if there is an invalid setting
+// Returns FALSE if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+BOOL Verify_Server_Settings()
+{
+ BOOL bValueReturned = TRUE;
+
+ if ( 0 == strlen(mi.m_szServerIdentifier) )
+ {
+ /* no value entered for server id */
+ DSMessageBoxOK(ERR_NO_SERVER_ID_TITLE, ERR_NO_SERVER_ID, 0);
+ } else if (FALSE == isValidServerID(mi.m_szServerIdentifier) )
+ {
+ /* server id is invalid */
+ /* error reported by isValidServerID */
+ } else if (0 == strlen(mi.m_szInstanceSuffix) && !mi.m_nExistingUG )
+ {
+ /* ok not to specify suffix when using existing UG hence above
+ otherwise it must be specified */
+ /* no value entered for suffix */
+ DSMessageBoxOK(ERR_NO_SUFFIX_TITLE, ERR_NO_SUFFIX, 0);
+ }else if (!mi.m_nExistingUG && !isValidDN(mi.m_szInstanceSuffix) )
+ {
+ /* don't check dn if ExistingUG since suffix is null */
+ /* error message displayed by isValidDN */
+ } else if ( !isValidPort(mi.m_nInstanceServerPort))
+ {
+ /* error displayed by isValidPort */
+ }else{
+ /* all items in this dialogue look good */
+ bValueReturned = FALSE;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Server_Settings_DialogProc
+//
+// dialog proc to choose server settings
+//
+// used by typical mode
+//
+//
+
+static BOOL CALLBACK
+Server_Settings_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+ HWND hCtrl;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_SERVER_IDENTIFIER,
+ IDC_EDIT_SUFFIX,
+ -1};
+ INT nCmdShow = SW_SHOW;
+ static CHAR szSavedSuffix[MAX_STR_SIZE]="\0";
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_SERVER_PORT, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_EDIT_SERVER_PORT), 0);
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_SERVER_PORT, UDM_SETRANGE, 0, MAKELONG((short)UD_MAXVAL, (short)1));
+
+ lstrcpy(szSavedSuffix, mi.m_szInstanceSuffix);
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ if(mi.m_nExistingUG)
+ {
+ /* hide suffix when creating config only directory */
+ if( 0 != strlen(mi.m_szInstanceSuffix) )
+ {
+ lstrcpy(szSavedSuffix, mi.m_szInstanceSuffix);
+ memset(mi.m_szInstanceSuffix, '\0', MAX_STR_SIZE);
+ }
+ nCmdShow = SW_HIDE;
+ }else{
+ lstrcpy(mi.m_szInstanceSuffix, szSavedSuffix);
+ nCmdShow = SW_SHOW;
+ }
+
+ hCtrl = GetDlgItem(hwndDlg, IDC_EDIT_SUFFIX);
+ ShowWindow(hCtrl,nCmdShow);
+
+ hCtrl = GetDlgItem(hwndDlg, IDC_STATIC_SUFFIX);
+ ShowWindow(hCtrl,nCmdShow);
+
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_SERVER_IDENTIFIER,
+ mi.m_szServerIdentifier);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_SUFFIX,
+ mi.m_szInstanceSuffix);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ bResult = SetDlgItemInt(hwndDlg,
+ IDC_EDIT_SERVER_PORT,
+ mi.m_nInstanceServerPort,
+ TRUE);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDialogInput_Server_Settings(hwndDlg);
+ // save the suffix typed in by the user
+ lstrcpy(szSavedSuffix, mi.m_szInstanceSuffix);
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ SaveDialogInput_Server_Settings(hwndDlg);
+ // save the suffix typed in by the user
+ lstrcpy(szSavedSuffix, mi.m_szInstanceSuffix);
+ if( TRUE == (bValueReturned = Verify_Server_Settings()) )
+ {
+ /* one of the settings was invalid stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// BOOL SaveDialogPasswords
+//
+// helper for ROOTDN and SUITESPOTDN Dialogs
+//
+//
+// saves passwords entered into dialog
+//
+//
+
+void SaveDialogPasswords(HWND hwndDlg, PSZ pszPassword, PSZ pszPasswordAgain)
+{
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_PASSWORD,
+ pszPassword,
+ MAX_STR_SIZE);
+
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_PASSWORD_AGAIN,
+ pszPasswordAgain,
+ MAX_STR_SIZE);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// BOOL LoadDialogPasswords
+//
+// helper for ROOTDN and SUITESPOTDN Dialogs
+//
+//
+// loads passwords entered into dialog
+//
+//
+void LoadDialogPasswords(HWND hwndDlg, PSZ pszPassword, PSZ pszPasswordAgain)
+{
+
+ BOOL bResult;
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_PASSWORD,
+ pszPassword);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ if (pszPasswordAgain)
+ {
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_PASSWORD_AGAIN,
+ pszPasswordAgain);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+ }
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// BOOL VerifyPasswords
+//
+// helper for ROOTDN and SUITESPOTDN Dialogs
+//
+//
+// check that passwords are valid
+//
+// Returns TRUE if there is an invalid setting
+// Returns False if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+
+BOOL VerifyPasswords(PSZ pszPassword, PSZ pszPasswordAgain, UINT min_pw_len)
+{
+ BOOL bValueReturned = TRUE;
+
+ if (min_pw_len > strlen(pszPassword))
+ {
+ /* password failed minimum length check */
+ DSMessageBoxOK(ERR_PW_TOO_SHORT_TITLE, ERR_PW_TOO_SHORT, 0,
+ min_pw_len);
+
+ } else if ( contains8BitChars(pszPassword) )
+ {
+ /* check to make sure pw doesn't contain any 8bit chars */
+ DSMessageBoxOK(ERR_8BIT_PW_TITLE, ERR_8BIT_PW, 0);
+
+ } else if ( 0 == strlen(pszPasswordAgain) )
+ {
+ /* second password to verify missing */
+
+ DSMessageBoxOK(ERR_NO_PW_AGAIN_TITLE, ERR_NO_PW_AGAIN, 0);
+ } else if ( 0 != lstrcmp(pszPassword, pszPasswordAgain) )
+ {
+ /* passwords don't match */
+ DSMessageBoxOK(ERR_PW_DIFFER_TITLE, ERR_PW_DIFFER, 0);
+ }else{
+ /* passwords satisfied all checks so return false */
+ bValueReturned = FALSE;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SaveDialogInput_RootDN
+//
+// saves input in root dn DialogProc
+//
+//
+//
+//
+
+void SaveDialogInput_ROOTDN(HWND hwndDlg)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_UNRESTRICTED_USER,
+ mi.m_szInstanceUnrestrictedUser,
+ MAX_STR_SIZE);
+
+
+ SaveDialogPasswords(hwndDlg,
+ mi.m_szInstancePassword,
+ mi.m_szInstancePasswordAgain);
+
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Verify_RootDN
+//
+// verifies input in root dn DialogProc
+//
+
+//
+// Returns TRUE if there is an invalid setting
+// Returns FALSE if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+BOOL Verify_ROOTDN()
+{
+ BOOL bValueReturned = FALSE;
+
+ if ( 0 == strlen(mi.m_szInstanceUnrestrictedUser) )
+ {
+ /* no value entered */
+ DSMessageBoxOK(ERR_NO_ROOT_DN_TITLE, ERR_NO_ROOT_DN, 0);
+ bValueReturned = TRUE;
+ }else if ( !isValidDN(mi.m_szInstanceUnrestrictedUser) )
+ {
+ /* error message displayed by isvalidDN */
+ bValueReturned = TRUE;
+ } else
+ {
+ /* only bother to check passwords if username is valid */
+ bValueReturned = VerifyPasswords(mi.m_szInstancePassword,
+ mi.m_szInstancePasswordAgain,
+ SLAPD_MIN_PW_LEN);
+ }
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// RootDN_DialogProc
+//
+// dialog proc for the RootDN install page
+//
+//
+//
+//
+
+static BOOL CALLBACK
+RootDN_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_UNRESTRICTED_USER,
+ IDC_EDIT_PASSWORD,
+ IDC_EDIT_PASSWORD_AGAIN,
+ -1};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_UNRESTRICTED_USER,
+ mi.m_szInstanceUnrestrictedUser);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ LoadDialogPasswords(hwndDlg,
+ mi.m_szInstancePassword,
+ mi.m_szInstancePasswordAgain);
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDialogInput_ROOTDN(hwndDlg);
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ SaveDialogInput_ROOTDN(hwndDlg);
+ if ( FALSE == (bValueReturned = Verify_ROOTDN() ) )
+ {
+
+ /* all settings on this dialogue look good */
+
+ /* verify ldap settings */
+ if (0 != verify_ldap_settings() )
+ {
+ /* dont allow next until settings corrected */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+
+ } else
+ {
+ /* set ldap settings for other installs */
+ set_ldap_settings();
+
+ }
+
+ /* if not advanced mode move on to other installs */
+ if (CUSTOMMODE != MODE)
+ {
+ mi.m_nResult = NS_WIZNEXT;
+ SendMessage(GetParent(hwndDlg), WM_CLOSE, 0, 0);
+ }
+ } else
+ {
+ /* one of the settings was invalid, stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// SaveDialogInput_SuitespotId
+//
+//
+
+//
+void SaveDialogInput_SuitespotId(HWND hwndDlg)
+{
+
+
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_SUITESPOT_USER,
+ mi.m_szSsptUid,
+ MAX_STR_SIZE);
+
+
+ SaveDialogPasswords(hwndDlg,
+ mi.m_szSsptUidPw,
+ mi.m_szSsptUidPwAgain);
+
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Verify_SuitespotId
+//
+// Returns TRUE if there is an invalid setting
+// Returns FALSE if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+BOOL Verify_SuitespotId()
+{
+
+ BOOL bValueReturned = FALSE;
+
+ if ( 0 == strlen(mi.m_szSsptUid) )
+ {
+ /* no value entered for sspt user */
+ DSMessageBoxOK(ERR_NO_SS_ADMIN_TITLE, ERR_NO_SS_ADMIN, 0);
+ bValueReturned = TRUE;
+ } else if (!isAValidDN(mi.m_szSsptUid) &&
+ contains8BitChars(mi.m_szSsptUid))
+ {
+ /* admin uid value not 7 bit */
+ DSMessageBoxOK(ERR_8BIT_UID_TITLE, ERR_8BIT_UID, 0);
+ bValueReturned = TRUE;
+ } else
+ {
+ /* only bother to check passwords if username is valid */
+ bValueReturned = VerifyPasswords(mi.m_szSsptUidPw,
+ mi.m_szSsptUidPwAgain,
+ SSPT_MIN_PW_LEN);
+ }
+
+ return bValueReturned;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// SuitespotID_DialogProc
+//
+// dialog proc for the SUITESPOTID install page
+//
+//
+//
+//
+
+static BOOL CALLBACK
+SuitespotID_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_SUITESPOT_USER,
+ IDC_EDIT_PASSWORD,
+ IDC_EDIT_PASSWORD_AGAIN,
+ -1};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ if(1 == mi.m_nExistingMCC)
+ {
+ /* don't display this dialog if using existing MCC since asked for it
+ there */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_SUITESPOT_USER,
+ mi.m_szSsptUid);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ LoadDialogPasswords(hwndDlg,
+ mi.m_szSsptUidPw,
+ mi.m_szSsptUidPwAgain);
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+
+
+ SaveDialogInput_SuitespotId(hwndDlg);
+
+ // in express mode this is the first dialog, so set back to go to other module */
+
+ if (EXPRESSMODE == MODE)
+ {
+ mi.m_nResult = NS_WIZBACK;
+ SendMessage(GetParent(hwndDlg), WM_CLOSE, 0, 0);
+ }
+
+
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ SaveDialogInput_SuitespotId(hwndDlg);
+ if(TRUE == (bValueReturned = Verify_SuitespotId() ) )
+ {
+ /* one of the settings was invalid stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Admin_ID_Only_DialogProc
+//
+// dialog proc for the ADMIN_ID_ONLY install page
+//
+//
+//
+//
+
+static BOOL CALLBACK
+Admin_ID_Only_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_SUITESPOT_USER,
+ IDC_EDIT_PASSWORD,
+ -1};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_SUITESPOT_USER,
+ mi.m_szMCCBindAs);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ LoadDialogPasswords(hwndDlg,
+ mi.m_szMCCPw,
+ 0);
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_SUITESPOT_USER,
+ mi.m_szMCCBindAs,
+ MAX_STR_SIZE);
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_PASSWORD,
+ mi.m_szMCCPw,
+ MAX_STR_SIZE);
+
+ // in express mode this is the first dialog, so set back to go to other module */
+
+ if (EXPRESSMODE == MODE)
+ {
+ mi.m_nResult = NS_WIZBACK;
+ SendMessage(GetParent(hwndDlg), WM_CLOSE, 0, 0);
+ }
+
+
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_SUITESPOT_USER,
+ mi.m_szMCCBindAs,
+ MAX_STR_SIZE);
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_PASSWORD,
+ mi.m_szMCCPw,
+ MAX_STR_SIZE);
+ if(TRUE == (bValueReturned = Verify_MCC_Settings() ) )
+ {
+ /* one of the settings was invalid stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Choose_Replication_DialogProc
+//
+// choose the type of replicatin to do, determine which pages to ask next
+//
+//
+//
+//
+
+static BOOL CALLBACK
+Choose_Replication_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ /* consumer replication */
+ if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_NO_CONSUMER_REPLICATION ) )
+ {
+ mi.m_nSetupConsumerReplication = NO_REPLICATION;
+ }else if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_CONSUMER_CIR ) ){
+ mi.m_nSetupConsumerReplication = CONSUMER_CIR_REPLICATION;
+ }else if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_CONSUMER_SIR ) ){
+ mi.m_nSetupConsumerReplication = CONSUMER_SIR_REPLICATION;
+ }
+
+ /* supplier replication */
+ if( BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_NO_SUPPLIER_REPLICATION ) )
+ {
+ mi.m_nSetupSupplierReplication = NO_REPLICATION;
+ }else if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_SUPPLIER_CIR ) ){
+ mi.m_nSetupSupplierReplication = SUPPLIER_CIR_REPLICATION;
+ }else if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_SUPPLIER_SIR ) ){
+ mi.m_nSetupSupplierReplication = SUPPLIER_SIR_REPLICATION;
+ }
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ /* set buttons for appropriate replication type */
+ if(CONSUMER_CIR_REPLICATION == mi.m_nSetupConsumerReplication)
+ {
+ CheckDlgButton(hwndDlg, IDC_RADIO_CONSUMER_CIR, BST_CHECKED);
+ }else if(CONSUMER_SIR_REPLICATION == mi.m_nSetupConsumerReplication){
+ CheckDlgButton(hwndDlg, IDC_RADIO_CONSUMER_SIR, BST_CHECKED);
+ }else{
+ CheckDlgButton(hwndDlg, IDC_RADIO_NO_CONSUMER_REPLICATION, BST_CHECKED);
+ }
+
+ if(SUPPLIER_CIR_REPLICATION == mi.m_nSetupSupplierReplication)
+ {
+ CheckDlgButton(hwndDlg, IDC_RADIO_SUPPLIER_CIR, BST_CHECKED);
+ }else if(SUPPLIER_SIR_REPLICATION == mi.m_nSetupSupplierReplication){
+ CheckDlgButton(hwndDlg, IDC_RADIO_SUPPLIER_SIR, BST_CHECKED);
+ }else{
+ CheckDlgButton(hwndDlg, IDC_RADIO_NO_SUPPLIER_REPLICATION, BST_CHECKED);
+ }
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+
+ // simple dialog, all button state gets saved in WM_COMMAND proccessing
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+
+ // simple dialog, all button state gets saved in WM_COMMAND proccessing
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SaveDialogInput_Consumer_Replication
+//
+// save settings from ConsumerReplication Dialog
+//
+//
+//
+//
+
+void SaveDialogInput_Consumer_Replication(HWND hwndDlg)
+{
+
+
+ if ( CONSUMER_SIR_REPLICATION == mi.m_nSetupConsumerReplication )
+ {
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_SUPPLIER_DN,
+ mi.m_szSupplierDN,
+ MAX_STR_SIZE);
+
+
+
+ SaveDialogPasswords(hwndDlg,
+ mi.m_szSupplierPW,
+ mi.m_szSupplierPWAgain);
+
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Verify_Consumer_Replication
+//
+// save settings from ConsumerReplication Dialog
+//
+//
+// Returns TRUE if there is an invalid setting
+// Returns FALSE if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+
+BOOL Verify_Consumer_Replication()
+{
+ BOOL bValueReturned = FALSE;
+
+ /* only check if configuring consumer replication */
+ if ( CONSUMER_SIR_REPLICATION == mi.m_nSetupConsumerReplication )
+ {
+
+ if ( 0 == strlen(mi.m_szSupplierDN) )
+ {
+ /* no value entered for Supplier DN */
+ DSMessageBoxOK(ERR_NO_SUPPLIER_DN_TITLE,
+ ERR_NO_SUPPLIER_DN, 0);
+ bValueReturned = TRUE;
+ }else if ( !isValidDN(mi.m_szSupplierDN) )
+ {
+ /* error message displayed by isvalidDN */
+ bValueReturned = TRUE;
+ } else
+ {
+
+ bValueReturned = VerifyPasswords(mi.m_szSupplierPW,
+ mi.m_szSupplierPWAgain,
+ SLAPD_MIN_PW_LEN);
+ }
+ }
+ return bValueReturned;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Consumer_Replication_DialogProc
+//
+// ask common settings needed for this server to be a consumer
+//
+//
+//
+//
+
+static BOOL CALLBACK
+Consumer_Replication_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_SUPPLIER_DN,
+ IDC_EDIT_PASSWORD,
+ IDC_EDIT_PASSWORD_AGAIN,
+ -1};
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+ if( CONSUMER_SIR_REPLICATION != mi.m_nSetupConsumerReplication )
+ {
+ /* we only want this dialog for Consumer SIR replication */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_SUPPLIER_DN,
+ mi.m_szSupplierDN);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+
+ LoadDialogPasswords(hwndDlg,
+ mi.m_szSupplierPW,
+ mi.m_szSupplierPWAgain);
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDialogInput_Consumer_Replication(hwndDlg);
+
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ SaveDialogInput_Consumer_Replication(hwndDlg);
+ if( TRUE == (bValueReturned = Verify_Consumer_Replication() ) )
+ {
+ /* a setting was invalid stay on this page*/
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }else{
+ /* all settings on this dialogue look good */
+
+ /* these settings were specified, ok to use them */
+ mi.m_nUseSupplierSettings = 1;
+ }
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SaveDialogInput_Supplier_Replication
+//
+// save supplier settings
+//
+//
+//
+//
+
+void SaveDialogInput_Supplier_Replication(HWND hwndDlg)
+{
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_CHANGELOG_DB_DIR,
+ mi.m_szChangeLogDbDir,
+ MAX_STR_SIZE);
+
+
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_CHANGELOG_DB_SUFFIX,
+ mi.m_szChangeLogSuffix,
+ MAX_STR_SIZE);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Verify_Supplier_Replication
+//
+// save supplier settings
+//
+//
+// Returns TRUE if there is an invalid setting
+// Returns FALSE if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+BOOL Verify_Supplier_Replication()
+{
+ BOOL bValueReturned = TRUE;
+
+ if ( 0 == strlen(mi.m_szChangeLogDbDir) )
+ {
+ DSMessageBoxOK(ERR_NO_CHANGELOG_DB_TITLE,
+ ERR_NO_CHANGELOG_DB, 0);
+ } else if ( contains8BitChars(mi.m_szChangeLogDbDir) )
+ {
+ /* make sure the path doesnt contain international characters */
+ DSMessageBoxOK(ERR_8BIT_PATH_TITLE, ERR_8BIT_PATH, 0);
+ } else if ( 0 == strlen(mi.m_szChangeLogSuffix) )
+ {
+ DSMessageBoxOK(ERR_NO_CHANGELOG_SUFFIX_TITLE,
+ ERR_NO_CHANGELOG_SUFFIX, 0);
+ } else if ( !isValidDN(mi.m_szChangeLogSuffix) )
+ {
+ /* error message displayed by isValidDN */
+ }else{
+ /* all settings lookg good */
+ bValueReturned = FALSE;
+ }
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Supplier_Replication_DialogProc
+//
+// ask common settings for this server to be a suppplier
+//
+//
+//
+//
+
+static BOOL CALLBACK
+Supplier_Replication_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+ static INT nInitialized = 0;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_CHANGELOG_DB_DIR,
+ IDC_EDIT_CHANGELOG_DB_SUFFIX,
+ -1};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ // need to initialize the changelog dir the first time
+ // this dialog is created. This is because
+ // the default values are set on dllMain and it wouldn't
+ // pick up the users change of target dir to calculate it
+ // reason for nInitialized is so it doesn't blow away
+ // users changes after leaving module and window is recreated
+ // and wm_init is called again
+ if( !nInitialized )
+ {
+ sprintf(mi.m_szChangeLogDbDir,"%s\\%s-%s\\%s", TARGETDIR,
+ DS_ID_SERVICE, mi.m_szServerIdentifier, DEFAULT_CHANGELOGDIR);
+ nInitialized = 1;
+ }
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+ if( NO_REPLICATION == mi.m_nSetupSupplierReplication)
+ {
+ /* we dont want to display this page unless this server is a supplier*/
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+
+ }
+
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_CHANGELOG_DB_SUFFIX,
+ mi.m_szChangeLogSuffix);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_CHANGELOG_DB_DIR,
+ mi.m_szChangeLogDbDir);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDialogInput_Supplier_Replication(hwndDlg);
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ SaveDialogInput_Supplier_Replication(hwndDlg);
+
+ if ( FALSE == (bValueReturned = Verify_Supplier_Replication() ) )
+ {
+ /* all settings look good */
+ /* user chose these settings through dialog so use them */
+ mi.m_nUseChangeLogSettings = 1;
+ }else{
+ /* one of the settings is invalid, stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SaveDialogInput_Consumer_DN
+//
+//
+// save input for Consumer DN dialog
+//
+//
+
+void SaveDialogInput_Consumer_DN(HWND hwndDlg)
+{
+
+ if (1 == mi.m_nConfigConsumerDN)
+ {
+ GetDlgItemText(hwndDlg,
+ IDC_EDIT_CONSUMER_DN,
+ mi.m_szConsumerDN,
+ MAX_STR_SIZE);
+
+ SaveDialogPasswords(hwndDlg,
+ mi.m_szConsumerPW,
+ mi.m_szConsumerPWAgain);
+
+
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Verify_Consumer_DN
+//
+//
+// verify input for Consumer DN dialog
+//
+// Returns TRUE if there is an invalid setting
+// Returns FALSE if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+BOOL Verify_Consumer_DN()
+{
+
+ BOOL bValueReturned = FALSE;
+
+ /* only verify if trying to use these settings */
+ if (1 == mi.m_nConfigConsumerDN)
+ {
+
+ if ( 0 == strlen(mi.m_szConsumerDN) )
+ {
+ /* no value entered for consumer dn */
+ DSMessageBoxOK(ERR_NO_CONSUMER_DN_TITLE, ERR_NO_CONSUMER_DN, 0);
+ bValueReturned = TRUE;
+ }else if ( !isValidDN(mi.m_szConsumerDN) )
+ {
+ /* error message displayed by isvalidDN */
+ bValueReturned = TRUE;
+ } else
+ {
+ /* only bother to check passwords if username is valid */
+ bValueReturned = VerifyPasswords(mi.m_szConsumerPW,
+ mi.m_szConsumerPWAgain,
+ SLAPD_MIN_PW_LEN);
+ }
+
+ }
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Consumer_DN_DialogProc
+//
+// dialog proc for the Consumer DN page
+// displayed only under Supplier CIR replication
+//
+//
+
+static BOOL CALLBACK
+Consumer_DN_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_CONSUMER_DN,
+ IDC_EDIT_PASSWORD,
+ IDC_EDIT_PASSWORD_AGAIN,
+ -1};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ sprintf(mi.m_szConsumerDN, "%s,%s", DEFAULT_CONSUMER_DN, mi.m_szInstanceSuffix);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_CONFIG_CONSUMER_DN_YES) )
+ {
+ EnableConsumerDNFields(hwndDlg, TRUE);
+ mi.m_nConfigConsumerDN = 1;
+ }else if(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_CONFIG_CONSUMER_DN_NO) ){
+ EnableConsumerDNFields(hwndDlg, FALSE);
+ mi.m_nConfigConsumerDN = 0;
+ }
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ if( SUPPLIER_CIR_REPLICATION != mi.m_nSetupSupplierReplication )
+ {
+ /* we only ask consumer dn for supplier cir*/
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+
+ }
+
+ bResult = SetDlgItemText(hwndDlg,
+ IDC_EDIT_CONSUMER_DN,
+ mi.m_szConsumerDN);
+ if(FALSE == bResult)
+ {
+ DSMessageBoxOK(ERR_INIT_DIALOG_TITLE, ERR_INIT_DIALOG, 0);
+ }
+
+ LoadDialogPasswords(hwndDlg,
+ mi.m_szConsumerPW,
+ mi.m_szConsumerPWAgain);
+
+
+ CheckRadioButton(hwndDlg, IDC_RADIO_CONFIG_CONSUMER_DN_YES, IDC_RADIO_CONFIG_CONSUMER_DN_NO,
+ ( (1 == mi.m_nConfigConsumerDN) ? IDC_RADIO_CONFIG_CONSUMER_DN_YES :
+ IDC_RADIO_CONFIG_CONSUMER_DN_NO));
+
+
+ if(1 == mi.m_nConfigConsumerDN)
+ {
+ EnableConsumerDNFields(hwndDlg, TRUE);
+ }else{
+ EnableConsumerDNFields(hwndDlg, FALSE);
+ }
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDialogInput_Consumer_DN(hwndDlg);
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+ SaveDialogInput_Consumer_DN(hwndDlg);
+ if( TRUE == (bValueReturned = Verify_Consumer_DN(hwndDlg) ) )
+ {
+ /* one of the settings is invalid, stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SetDlgReplDays
+//
+// helper function to convert string to checked days in repl agreement dialog proc
+//
+//
+//
+//
+
+
+BOOL SetDlgReplDays(HWND hwndDlg,
+ PSZ szReplDays)
+{
+ INT Days[7] = {0};
+ INT i, tmp=0;
+ INT DayControls[] ={IDC_CHECK_SUN, IDC_CHECK_MON, IDC_CHECK_TUE,
+ IDC_CHECK_WED, IDC_CHECK_THUR, IDC_CHECK_FRI,
+ IDC_CHECK_SAT, -1};
+
+ for(i=0; szReplDays != NULL && szReplDays[i] != '\0'; i++)
+ {
+ tmp = ( (INT) szReplDays[i] ) - ASCII_ZERO;
+ if( tmp >= 0 && tmp < 7)
+ {
+ CheckDlgButton(hwndDlg, DayControls[tmp], BST_CHECKED);
+ }
+
+ }
+
+ return TRUE;
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// GetDlgReplDays
+//
+// helper function to convert checked days to string for repl agreement dialog procs
+//
+//
+//
+//
+
+
+BOOL GetDlgReplDays(HWND hwndDlg,
+ PSZ szReplDays)
+{
+ INT Days[7] = {0};
+ INT i, pos;
+ INT DayControls[] ={IDC_CHECK_SUN, IDC_CHECK_MON, IDC_CHECK_TUE,
+ IDC_CHECK_WED, IDC_CHECK_THUR, IDC_CHECK_FRI,
+ IDC_CHECK_SAT, -1};
+ pos=0;
+ for(i=0; DayControls[i] != -1; i++)
+ {
+
+ if( IsDlgButtonChecked(hwndDlg, DayControls[i]) )
+ {
+ szReplDays[pos]=(char) (i + ASCII_ZERO);
+ pos++;
+ }
+
+ }
+ szReplDays[pos]='\0';
+
+ return TRUE;
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SetDlgReplTimes
+// Initialize Time Controls/Spinners in ReplAgreementDlgProc
+//
+//
+//
+//
+
+BOOL SetDlgReplTimes(HWND hwndDlg, PSZ szTimes)
+{
+ CHAR s_hh[3]="\0", s_mm[3]="\0";
+ CHAR e_hh[3]="\0", e_mm[3]="\0";
+ INT i;
+
+ for(i=0; i <2; i++)
+ {
+ s_hh[i] = szTimes[i];
+ s_mm[i] = szTimes[i+2];
+ e_hh[i] = szTimes[i+5];
+ e_mm[i] = szTimes[i+7];
+ }
+
+ SetDlgItemText(hwndDlg, IDC_EDIT_REPL_START_TIME_HH, s_hh);
+ SetDlgItemText(hwndDlg, IDC_EDIT_REPL_START_TIME_MM, s_mm);
+
+ SetDlgItemText(hwndDlg, IDC_EDIT_REPL_END_TIME_HH, e_hh);
+ SetDlgItemText(hwndDlg, IDC_EDIT_REPL_END_TIME_MM, e_mm);
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_START_TIME_HH, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_EDIT_REPL_START_TIME_HH), 0);
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_START_TIME_HH, UDM_SETRANGE, 0, MAKELONG((short)23, (short)0));
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_START_TIME_MM, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_EDIT_REPL_START_TIME_MM), 0);
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_START_TIME_MM, UDM_SETRANGE, 0, MAKELONG((short)59, (short)0));
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_END_TIME_HH, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_EDIT_REPL_END_TIME_HH), 0);
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_END_TIME_HH, UDM_SETRANGE, 0, MAKELONG((short)23, (short)0));
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_END_TIME_MM, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_EDIT_REPL_END_TIME_MM), 0);
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_END_TIME_MM, UDM_SETRANGE, 0, MAKELONG((short)59, (short)0));
+
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// writeTime
+// make Time Component always be 2 digits
+//
+//
+//
+//
+BOOL writeTime(int nn, char *szTime)
+{
+ if( nn > 9)
+ {
+ sprintf(szTime, "%d", nn);
+ }else{
+ sprintf(szTime, "0%d", nn);
+ }
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// GetDlgReplTimes
+// Get Repl Times From the Dialog
+//
+//
+//
+//
+
+BOOL GetDlgReplTimes(HWND hwndDlg, PSZ szTimes)
+{
+ CHAR s_hh[3]="\0", s_mm[3]="\0";
+ CHAR e_hh[3]="\0", e_mm[3]="\0";
+ INT ns_hh, ns_mm;
+ INT ne_hh, ne_mm;
+ BOOL bTrans;
+
+ ns_hh = GetDlgItemInt(hwndDlg, IDC_EDIT_REPL_START_TIME_HH, &bTrans, FALSE);
+ ns_mm = GetDlgItemInt(hwndDlg, IDC_EDIT_REPL_START_TIME_MM, &bTrans, FALSE);
+ ne_hh = GetDlgItemInt(hwndDlg, IDC_EDIT_REPL_END_TIME_HH, &bTrans, FALSE);
+ ne_mm = GetDlgItemInt(hwndDlg, IDC_EDIT_REPL_END_TIME_MM, &bTrans, FALSE);
+
+
+ writeTime(ns_hh, s_hh);
+ writeTime(ns_mm, s_mm);
+ writeTime(ne_hh, e_hh);
+ writeTime(ne_mm, e_mm);
+
+ sprintf(szTimes, "%s%s-%s%s", s_hh, s_mm, e_hh, e_mm);
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SaveDlgReplAgreement
+//
+// save information for replication agreements from dialog
+//
+//
+//
+
+void SaveDlgReplAgreement(HWND hwndDlg,
+ PSZ pszReplHost,
+ INT *pnReplPort,
+ PSZ pszReplRoot,
+ PSZ pszReplBindAs,
+ PSZ pszReplPw,
+ PSZ pszReplDays,
+ PSZ pszReplTimes)
+{
+
+ SaveDlgServerInfo(hwndDlg,
+ pszReplHost,
+ pnReplPort,
+ pszReplRoot,
+ pszReplBindAs,
+ pszReplPw);
+
+ /* get replication days */
+ GetDlgReplDays(hwndDlg, pszReplDays);
+
+ /* get replication times */
+ GetDlgReplTimes(hwndDlg, pszReplTimes);
+
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// LoadDlgReplAgreement
+//
+//load information for replication agreements into dialog
+//
+//
+//
+
+void LoadDlgReplAgreement(HWND hwndDlg,
+ PSZ pszReplHost,
+ INT nReplPort,
+ PSZ pszReplRoot,
+ PSZ pszReplBindAs,
+ PSZ pszReplPw,
+ PSZ pszReplDays,
+ PSZ pszReplTimes)
+{
+
+ LoadDlgServerInfo(hwndDlg,
+ pszReplHost,
+ nReplPort,
+ pszReplRoot,
+ pszReplBindAs,
+ pszReplPw);
+
+ SetDlgReplDays(hwndDlg, pszReplDays);
+
+ /* get replication times */
+ SetDlgReplTimes(hwndDlg, pszReplTimes);
+
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// VerifyReplAgreement
+//
+// Verify replication agreement
+//
+// Returns TRUE if there is an invalid setting
+// Returns False if all settings are valid
+//
+// SideEffect: displays error (or writes to log in silent mode)
+
+
+BOOL VerifyReplAgreement( PSZ pszReplHost,
+ INT *pnReplPort,
+ PSZ pszReplRoot,
+ PSZ pszReplBindAs,
+ PSZ pszReplPw,
+ PSZ pszReplDays,
+ PSZ pszReplTimes)
+{
+ BOOL bValueReturned = FALSE;
+
+
+ if( TRUE == (bValueReturned = VerifyServerInfo(pszReplHost,
+ pnReplPort,
+ pszReplRoot,
+ pszReplBindAs,
+ pszReplPw,
+ TRUE) ) )
+ {
+ /* problem with the server info, just return true for Error */
+
+
+ } else if (FALSE == FullyQualifyHostName(pszReplHost) )
+ {
+ /* can't qualify host name, must be invalid */
+ DSMessageBoxOK(ERR_INVALID_HOST_TITLE, ERR_INVALID_HOST,
+ pszReplHost, pszReplHost);
+
+ bValueReturned = TRUE;
+
+ } else if (FALSE == UTF8IsValidLdapUser( pszReplHost,
+ *pnReplPort,
+ pszReplRoot,
+ pszReplBindAs,
+ pszReplPw,
+ FALSE) )
+ {
+ /* can't bind to host with info entered */
+ if( IDNO == DSMessageBox(MB_YESNO, ERR_CANT_FIND_DS_REPL_TITLE,
+ ERR_CANT_FIND_DS_REPL, 0, pszReplHost,
+ *pnReplPort, pszReplBindAs) )
+ {
+ /* user wants to stay on this page and fix value, otherwise,
+ allows them to continue even though cant find host
+ for replication */
+
+ bValueReturned = TRUE;
+ }
+ }
+
+ /* may want to add more verification here */
+
+ return bValueReturned;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Supplier_Replication_Agreement_DialogProc
+//
+// get information for replication agreements
+//
+//
+//
+//
+
+static BOOL CALLBACK
+Supplier_Replication_Agreement_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+ HWND hCtrl;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_HOST,
+ IDC_EDIT_SUFFIX,
+ IDC_EDIT_BIND_AS,
+ IDC_EDIT_PW,
+ -1};
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ /* stevross: will have to come back to display this twice for middle case */
+ if( SUPPLIER_SIR_REPLICATION != mi.m_nSetupSupplierReplication )
+ {
+ /* we only setup replication agreements for SUPPLIER SIR */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+ }
+
+ /* set text to say Supplier Repl Agreement */
+ SetDlgItemText(hwndDlg, IDC_STATIC_REPLICATION_AGREEMENT, SUPPLIER_REPL_AGREE);
+
+ /* display values */
+ LoadDlgReplAgreement(hwndDlg,
+ mi.m_szSupplierHost,
+ mi.m_nSupplierPort,
+ mi.m_szSupplierRoot,
+ mi.m_szSupplierBindAs,
+ mi.m_szSupplierPw,
+ mi.m_szSIRDays,
+ mi.m_szSIRTimes);
+
+ /* hide the repl sync interval stuff because it only makes since for CIR */
+ hCtrl = GetDlgItem(hwndDlg, IDC_EDIT_REPL_SYNC_INTERVAL);
+ ShowWindow(hCtrl,SW_HIDE);
+
+ hCtrl = GetDlgItem(hwndDlg, IDC_STATIC_REPL_SYNC);
+ ShowWindow(hCtrl,SW_HIDE);
+
+ hCtrl = GetDlgItem(hwndDlg, IDC_SPIN_REPL_SYNC_INTERVAL);
+ ShowWindow(hCtrl,SW_HIDE);
+
+
+ /* center window n stuff */
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDlgReplAgreement(hwndDlg,
+ mi.m_szSupplierHost,
+ &mi.m_nSupplierPort,
+ mi.m_szSupplierRoot,
+ mi.m_szSupplierBindAs,
+ mi.m_szSupplierPw,
+ mi.m_szSIRDays,
+ mi.m_szSIRTimes);
+
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+
+ /* only bother to check passwords if username is valid */
+
+ SaveDlgReplAgreement(hwndDlg,
+ mi.m_szSupplierHost,
+ &mi.m_nSupplierPort,
+ mi.m_szSupplierRoot,
+ mi.m_szSupplierBindAs,
+ mi.m_szSupplierPw,
+ mi.m_szSIRDays,
+ mi.m_szSIRTimes);
+
+ if( TRUE == (bValueReturned = VerifyReplAgreement(mi.m_szSupplierHost,
+ &mi.m_nSupplierPort,
+ mi.m_szSupplierRoot,
+ mi.m_szSupplierBindAs,
+ mi.m_szSupplierPw,
+ mi.m_szSIRDays,
+ mi.m_szSIRTimes) ) )
+ {
+ /* one of the settings is invalid, stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// SaveDlgInput_Consumer_Replication_Agreement_DialogProc
+//
+// get info for consumer replication agreements
+//
+//
+//
+//
+void SaveDlgInput_Consumer_Replication_Agreement(HWND hwndDlg)
+{
+
+ BOOL bTrans;
+
+ SaveDlgReplAgreement(hwndDlg,
+ mi.m_szConsumerHost,
+ &mi.m_nConsumerPort,
+ mi.m_szConsumerRoot,
+ mi.m_szConsumerBindAs,
+ mi.m_szConsumerPw,
+ mi.m_szCIRDays,
+ mi.m_szCIRTimes);
+
+
+ /* get the CIR Interval */
+ mi.m_nCIRInterval = GetDlgItemInt(hwndDlg, IDC_EDIT_REPL_SYNC_INTERVAL, &bTrans , FALSE);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Consumer_Replication_Agreement_DialogProc
+//
+// get information for replication agreements
+//
+//
+//
+//
+
+static BOOL CALLBACK
+Consumer_Replication_Agreement_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_EDIT_HOST,
+ IDC_EDIT_SUFFIX,
+ IDC_EDIT_BIND_AS,
+ IDC_EDIT_PW,
+ -1};
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_SYNC_INTERVAL, UDM_SETBUDDY, (WPARAM)GetDlgItem(hwndDlg, IDC_EDIT_REPL_SYNC_INTERVAL), 0);
+ SendDlgItemMessage(hwndDlg, IDC_SPIN_REPL_SYNC_INTERVAL, UDM_SETRANGE, 0, MAKELONG((short)59, (short)0));
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ /* stevross: will have to come back to display this twice for middle case */
+ if( CONSUMER_CIR_REPLICATION != mi.m_nSetupConsumerReplication )
+ {
+ /* we only setup replication agreements for CONSUMER CIR */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+
+ }
+
+
+ /* make title consumer replication agreement */
+ SetDlgItemText(hwndDlg, IDC_STATIC_REPLICATION_AGREEMENT, CONSUMER_REPL_AGREE);
+
+ /* display values */
+ LoadDlgReplAgreement(hwndDlg,
+ mi.m_szConsumerHost,
+ mi.m_nConsumerPort,
+ mi.m_szConsumerRoot,
+ mi.m_szConsumerBindAs,
+ mi.m_szConsumerPw,
+ mi.m_szCIRDays,
+ mi.m_szCIRTimes);
+
+ SetDlgItemInt(hwndDlg, IDC_EDIT_REPL_SYNC_INTERVAL, mi.m_nCIRInterval, FALSE);
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+ SaveDlgInput_Consumer_Replication_Agreement(hwndDlg);
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+
+ /* only bother to check passwords if username is valid */
+
+ SaveDlgInput_Consumer_Replication_Agreement(hwndDlg);
+ if( TRUE == (bValueReturned = VerifyReplAgreement(mi.m_szConsumerHost,
+ &mi.m_nConsumerPort,
+ mi.m_szConsumerRoot,
+ mi.m_szConsumerBindAs,
+ mi.m_szConsumerPw,
+ mi.m_szCIRDays,
+ mi.m_szCIRTimes) ) )
+ {
+ /* one of the settings invalid, stay on this page */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ }
+
+
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// Sample_Entries_Org_DialogProc
+//
+// ask user if they want to populate with sample entries and sample organization
+//
+//
+//
+//
+
+static BOOL CALLBACK
+Sample_Entries_Org_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+ CHAR szMustHaveBase[MAX_STR_SIZE]="\0";
+ static CHAR szCustomFileName[MAX_STR_SIZE]="\0";
+ static CHAR szSampleFileName[MAX_STR_SIZE]="\0";
+
+ /* list of controls to be setup for 8bit input/display */
+ INT h8bitControls[]={IDC_STATIC_MUST_HAVE_BASE,
+ IDC_STATIC_LDIF_FILE_NAME,
+ -1};
+
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ /* default is to populate with sample entries */
+
+ Setup8bitInputDisplay(hwndDlg, h8bitControls);
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ switch (LOWORD(wParam))
+ {
+
+ case IDC_BUTTON_CHOOSE_LDIF_FILE:
+ GetFileName(hwndDlg, "Choose ldif file to import",
+ "Ldif Files|*.ldif|All Files|*.*|",
+ NULL, szCustomFileName, MAX_PATH );
+
+ /* assume by browsing user will want this file so check custom radio button for them
+ and set file to be displayed */
+ sprintf(mi.m_szPopLdifFile, "%s", szCustomFileName);
+ CheckRadioButton(hwndDlg, IDC_RADIO_DONT_POPULATE, IDC_RADIO_POPULATE_CUSTOM, IDC_RADIO_POPULATE_CUSTOM);
+
+ default:
+
+ mi.m_nPopulateSampleOrg = (int )(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHECK_POPULATE_ORG_ENTRIES ) );
+
+ if( BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_POPULATE_SAMPLE ) )
+ {
+ mi.m_nPopulateSampleEntries = 1;
+ sprintf(mi.m_szPopLdifFile, "%s", szSampleFileName);
+ }else if( BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_RADIO_POPULATE_CUSTOM ) ){
+ mi.m_nPopulateSampleEntries = 0;
+ mi.m_nPopulateSampleOrg = 1;
+// sprintf(mi.m_szPopLdifFile, "%s", szCustomFileName);
+ }else{
+ mi.m_nPopulateSampleEntries = 0;
+ sprintf(mi.m_szPopLdifFile, "\0");
+ }
+
+
+ break;
+
+ }
+ /* update ldif file name if changed */
+ SetDlgItemText(hwndDlg, IDC_STATIC_LDIF_FILE_NAME, mi.m_szPopLdifFile);
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+ if( (CONSUMER_CIR_REPLICATION == mi.m_nSetupConsumerReplication)
+ || (CONSUMER_SIR_REPLICATION == mi.m_nSetupConsumerReplication ) )
+ {
+ /* we only want to populate if they are not doing CIR */
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ return TRUE;
+
+ }
+
+ /* warn user about suffix and database import */
+ sprintf(szMustHaveBase, "(note: must have base %s)", mi.m_szInstanceSuffix );
+ SetDlgItemText(hwndDlg, IDC_STATIC_MUST_HAVE_BASE, szMustHaveBase);
+ sprintf(szSampleFileName, "%s\\%s", TARGETDIR, SAMPLE_LDIF);
+
+ if(mi.m_nExistingUG == 0)
+ {
+ /* the user is creating a new UG with this instance */
+
+ /* create ou=People/ou=Groups */
+// mi.m_nPopulateSampleOrg = 1;
+// lstrcpy(mi.m_szPopLdifFile, SUGGEST_LDIF);
+ }
+
+ if(mi.m_nPopulateSampleEntries)
+ {
+ CheckRadioButton(hwndDlg, IDC_RADIO_DONT_POPULATE,
+ IDC_RADIO_POPULATE_CUSTOM,
+ IDC_RADIO_POPULATE_SAMPLE);
+ } else if (mi.m_szPopLdifFile[0]) {
+ CheckRadioButton(hwndDlg, IDC_RADIO_DONT_POPULATE,
+ IDC_RADIO_POPULATE_CUSTOM,
+ IDC_RADIO_POPULATE_CUSTOM);
+ } else {
+ CheckRadioButton(hwndDlg, IDC_RADIO_DONT_POPULATE,
+ IDC_RADIO_POPULATE_CUSTOM,
+ IDC_RADIO_DONT_POPULATE);
+ }
+
+ if(mi.m_nPopulateSampleOrg)
+ {
+ CheckDlgButton(hwndDlg, IDC_CHECK_POPULATE_ORG_ENTRIES, BST_CHECKED);
+ }
+
+ SetDlgItemText(hwndDlg, IDC_STATIC_LDIF_FILE_NAME, mi.m_szPopLdifFile);
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+
+ /* all settings for this dailog are saved in WM_COMMAND processing */
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+
+ /* all settings for this dailog are saved in WM_COMMAND processing */
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+
+
+//////////////////////////////////////////////////////////////////////////////
+// Disable_Schema_Checking_DialogProc
+//
+// ask user if they want to disable schema checking
+//
+//
+//
+//
+
+static BOOL CALLBACK
+Disable_Schema_Checking_DialogProc(HWND hwndDlg, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ BOOL bValueReturned = FALSE;
+ UINT uResult = 0;
+ BOOL bResult = FALSE;
+
+
+ switch (uMsg)
+ {
+ case WM_INITDIALOG:
+ // This message is sent when the property page is first created. Here
+ // you can perform any one time initialization that you require.
+ /* default is to populate with sample entries */
+
+ break;
+
+
+ case WM_COMMAND:
+ // Windows sends WM_COMMAND messages whenever the user clicks on
+ // a control in your property page. If you need to perform some
+ // special action, such as validating data or responding to a
+ // button click, do it here.
+
+ switch (LOWORD(wParam))
+ {
+
+ default:
+
+ mi.m_nDisableSchemaChecking = (int )(BST_CHECKED == IsDlgButtonChecked(hwndDlg, IDC_CHECK_DISABLE_SCHEMA_CHECKING ) );
+ break;
+
+ }
+
+ break;
+
+ case WM_NOTIFY:
+ // Windows sends WM_NOTIFY messages to your property page whenever
+ // something interesting happens to the page. This could be page
+ // activation/deactivation, a button click, etc. The wParam parameter
+ // contains a pointer to the property page. The lParam parameter
+ // contains a pointer to an NMHDR structure. The code field of this
+ // structure contains the notification message code being sent. The
+ // property sheet API allows you to alter the behavior of these
+ // messages by returning a value for each message. To return a value,
+ // use the SetWindowLong Windows SDK function.
+
+ switch (((NMHDR*)lParam)->code)
+ {
+
+
+ case PSN_SETACTIVE:
+ // This notification is sent upon activation of the property page.
+ // The property sheet should be centered each time it is activated
+ // in case the user has moved the stupid thing (this duplicates
+ // InstallShield functionality). You should also set the state of
+ // the wizard buttons here.
+ //
+ // NOTE: If you do not wish this page to become active, return -1.
+
+ if(mi.m_nDisableSchemaChecking)
+ {
+ CheckDlgButton(hwndDlg, IDC_CHECK_DISABLE_SCHEMA_CHECKING, BST_CHECKED);
+ }
+
+ CenterWindow(GetParent(hwndDlg));
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_KILLACTIVE:
+ // This notification is sent upon deactivation of the property page.
+ // Here you can do whatever might be necessary for this action, such
+ // as saving the state of the controls. You should also reset the
+ // the state of the wizard buttons here, as both the Back and Next
+ // buttons should be active when you leave the AskOptions function.
+ //
+ // NOTE: If you do not want the page deactivated, return -1.
+
+ PropSheet_SetWizButtons(GetParent(hwndDlg), PSWIZB_BACK | PSWIZB_NEXT);
+ break;
+
+ case PSN_WIZBACK:
+ // The user clicked the back button from the first property page.
+ // Set the result code NS_WIZBACK to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the first property sheet, you should ignore this
+ // notification and simply let windows go to the previous page.
+ //
+ // NOTE: To prevent the wizard from stepping back, return -1.
+
+ /* all settings for this dailog are saved in WM_COMMAND processing */
+ break;
+
+ case PSN_WIZNEXT:
+ // The user clicked the next button from the last property page.
+ // Set the result code NS_WIZNEXT to indicate this action and close
+ // the property sheet using brute force. If this procedure is not
+ // being used by the last property sheet, you should ignore this
+ // notification and simply let windows go to the next page.
+ //
+ // NOTE: To prevent the wizard from stepping ahead, return -1.
+
+
+ /* this is the last property page of advanced mode whenever we display it*/
+ mi.m_nResult = NS_WIZNEXT;
+ SendMessage(GetParent(hwndDlg), WM_CLOSE, 0, 0);
+
+ /* all settings for this dailog are saved in WM_COMMAND processing */
+ break;
+
+ case PSN_QUERYCANCEL:
+ // This notification is sent when the user clicks the Cancel button.
+ // It is also sent in response to the WM_CLOSE messages issued
+ // by PSN_WIZBACK and PSN_WIZNEXT. Make sure that we only process
+ // this message if the result is not back or next so that we don't
+ // nuke the return value assigned by PSN_WIZBACK or PSN_WIZNEXT.
+ //
+ // NOTE: To prevent the cancel from occuring, return -1.
+
+ if (mi.m_nResult != NS_WIZBACK && mi.m_nResult != NS_WIZNEXT)
+ {
+ if (QueryExit(hwndDlg))
+ {
+ mi.m_nResult = NS_WIZCANCEL;
+ }
+ else
+ {
+ SetWindowLong(hwndDlg, DWL_MSGRESULT, -1);
+ bValueReturned = TRUE;
+ }
+ }
+ break;
+ }
+ break;
+ }
+
+ return bValueReturned;
+}
+
+void initialize_module()
+{
+
+ mi.m_nResult = 0;
+ mi.m_szMCCBindAs = NULL;
+ mi.m_nInstanceServerPort = 0;
+ mi.m_nAdminServerPort = 0;
+ mi.m_nCfgSspt = 0;
+ mi.m_nPopulateSampleEntries = 0;
+ mi.m_nPopulateSampleOrg = 1;
+ mi.m_nSetupConsumerReplication = 0;
+ mi.m_nSetupSupplierReplication = 0;
+ mi.m_nMaxChangeLogRecords = 0;
+ mi.m_nMaxChangeLogAge = 0;
+ mi.m_nChangeLogAgeMagnitude = 0;
+ mi.m_nConsumerSSL = 0;
+ mi.m_nSupplierSSL = 0;
+ mi.m_nUseSupplierSettings = 0;
+ mi.m_nUseChangeLogSettings = 0;
+ mi.m_nCIRInterval = 0;
+ mi.m_nConsumerPort = 0;
+ mi.m_nSupplierPort = 0;
+ mi.m_nMCCPort = 0;
+ mi.m_nExistingMCC = 0;
+ mi.m_nUGPort = 0;
+ mi.m_nExistingUG = 0;
+ mi.m_nDisableSchemaChecking = 0;
+ mi.m_nSNMPOn = 0;
+ mi.m_nConfigConsumerDN = 0;
+
+ memset(mi.m_szMCCPw, '\0', MAX_STR_SIZE);
+ memset(mi.m_szMCCHost, '\0', MAX_STR_SIZE);
+ memset(mi.m_szMCCSuffix, '\0', MAX_STR_SIZE);
+ memset(mi.m_szUGPw, '\0', MAX_STR_SIZE);
+ memset(mi.m_szUGHost, '\0', MAX_STR_SIZE);
+ memset(mi.m_szUGSuffix, '\0', MAX_STR_SIZE);
+ memset(mi.m_szAdminDomain, '\0', MAX_STR_SIZE);
+ memset(mi.m_szLdapURL, '\0', MAX_STR_SIZE);
+ memset(mi.m_szUserGroupURL, '\0', MAX_STR_SIZE);
+ memset(mi.m_szUserGroupAdmin, '\0', MAX_STR_SIZE);
+ memset(mi.m_szUserGroupAdminPW, '\0', MAX_STR_SIZE);
+ memset(mi.m_szInstallDN, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSsptUid, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSsptUidPw, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSsptUidPwAgain, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSsptUser, '\0', MAX_STR_SIZE);
+ memset(mi.m_szServerIdentifier, '\0', MAX_STR_SIZE);
+ memset(mi.m_szInstanceSuffix, '\0', MAX_STR_SIZE);
+ memset(mi.m_szInstanceUnrestrictedUser, '\0', MAX_STR_SIZE);
+ memset(mi.m_szInstancePassword, '\0', MAX_STR_SIZE);
+ memset(mi.m_szInstancePasswordAgain, '\0', MAX_STR_SIZE);
+ memset(mi.m_szInstanceHostName, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSupplierDN, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSupplierPW, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSupplierPWAgain, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSSLClients, '\0', MAX_STR_SIZE);
+ memset(mi.m_szChangeLogDbDir, '\0', MAX_STR_SIZE);
+ memset(mi.m_szChangeLogSuffix, '\0', MAX_STR_SIZE);
+ memset(mi.m_szConsumerDN, '\0', MAX_STR_SIZE);
+ memset(mi.m_szConsumerPW, '\0', MAX_STR_SIZE);
+ memset(mi.m_szConsumerPWAgain, '\0', MAX_STR_SIZE);
+ memset(mi.m_szConsumerHost, '\0', MAX_STR_SIZE);
+ memset(mi.m_szConsumerRoot, '\0', MAX_STR_SIZE);
+ memset(mi.m_szConsumerBindAs, '\0', MAX_STR_SIZE);
+ memset(mi.m_szConsumerPw, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSupplierHost, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSupplierRoot, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSupplierBindAs, '\0', MAX_STR_SIZE);
+ memset(mi.m_szSupplierPw, '\0', MAX_STR_SIZE);
+ memset(mi.m_szPopLdifFile, '\0', MAX_STR_SIZE);
+ memset(mi.m_szCIRDays, '\0', N_DAYS);
+ memset(mi.m_szCIRTimes, '\0', N_TIMES);
+ memset(mi.m_szSIRDays, '\0', N_DAYS);
+ memset(mi.m_szSIRTimes, '\0', N_TIMES);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//getSNMPStatus()
+//
+// sets module info for state of SNMPService
+// if its on asks user if ok to turn it off
+// if user says no or there is an error it returns false
+//
+
+BOOL getSNMPStatus()
+{
+
+ BOOL bReturn = TRUE;
+
+ if ( TRUE == isServiceRunning(SNMP_SERVICE) )
+ {
+ // its running
+ if (SILENTMODE == MODE)
+ {
+ /* don't prompt user, jsut turn it off */
+ if ( 0 == ControlServer(SNMP_SERVICE, FALSE) )
+ {
+ DSMessageBoxOK(ERR_SNMP_BAD_SHUTDOWN_TITLE,
+ ERR_SNMP_BAD_SHUTDOWN, 0);
+ bReturn = FALSE;
+ }
+ mi.m_nSNMPOn = 1;
+ } else
+ {
+
+ /* ask the user what they want to do */
+ if ( IDOK == DSMessageBox(MB_OKCANCEL, ERR_SNMP_IS_RUNNING_TITLE,
+ ERR_SNMP_IS_RUNNING, 0) )
+ {
+ /* save state for later use by cache so we know what to do in post install */
+ mi.m_nSNMPOn = 1;
+ if ( 0 == ControlServer(SNMP_SERVICE, FALSE) )
+ {
+ DSMessageBoxOK(ERR_SNMP_BAD_SHUTDOWN_TITLE,
+ ERR_SNMP_BAD_SHUTDOWN, 0);
+ bReturn = FALSE;
+ }
+
+ } else
+ {
+ UINT uExitCode = 1;
+ /* stevross: use ExitProcess until admin server provides us with
+ better way to exit framework and cleanup */
+ ExitProcess(uExitCode);
+ }
+
+ }
+
+ } else
+ {
+ mi.m_nSNMPOn = 0;
+ }
+
+ return bReturn;
+
+}
+
+
+/////////////////////////////////////////////////////////////////
+//
+// somehow determine if slapd is installed under this server root
+//
+//
+
+BOOL slapdExists(char *pszServerRoot)
+{
+ BOOL bReturn = FALSE;
+ WIN32_FIND_DATA fileData;
+ HANDLE hFileHandle;
+ CHAR szCurrentDir[MAX_STR_SIZE]="\0";
+
+ /* not sure what the right way to check is, try this for now */
+ /* check if any slapd instances exist in server root */
+ /* later look in directory for anything slapd- */
+
+ /* get current dir so we have it for later */
+ GetCurrentDirectory(MAX_STR_SIZE, szCurrentDir);
+
+ /* change current dir to server root */
+ SetCurrentDirectory(pszServerRoot);
+
+ hFileHandle = FindFirstFile("slapd-*", &fileData);
+
+ if( INVALID_HANDLE_VALUE != hFileHandle)
+ {
+ /* found slapd- something */
+ bReturn = TRUE;
+ }
+
+ /* set back to previous current directory */
+ SetCurrentDirectory(szCurrentDir);
+
+ return bReturn;
+}
+
+
+/////////////////////////////////////////////////////////////////
+//
+// turn slapd instances in this server root on or off
+//
+//
+
+BOOL ControlSlapdServers(char *pszServerRoot, BOOL bOn, BOOL fixPwd)
+{
+ BOOL bReturn = FALSE;
+ WIN32_FIND_DATA fileData;
+ HANDLE hFileHandle;
+ CHAR szCurrentDir[MAX_STR_SIZE]="\0";
+
+ /* not sure what the right way to check is, try this for now */
+ /* check if any slapd instances exist in server root */
+ /* later look in directory for anything slapd- */
+
+ /* get current dir so we have it for later */
+ GetCurrentDirectory(MAX_STR_SIZE, szCurrentDir);
+
+ /* change current dir to server root */
+ SetCurrentDirectory(pszServerRoot);
+
+ hFileHandle = FindFirstFile("slapd-*", &fileData);
+ if( INVALID_HANDLE_VALUE != hFileHandle)
+ {
+ if (fixPwd)
+ {
+ /* convert password file to new pin format */
+ ConvertPasswordToPin(pszServerRoot, fileData.cFileName);
+ /* do any server upgrade stuff */
+ ReinstallUpgradeServer(pszServerRoot, fileData.cFileName);
+ }
+
+ /* turn on server */
+ ControlSlapdInstance(fileData.cFileName, bOn);
+
+ while(TRUE == FindNextFile(hFileHandle, &fileData) )
+ {
+ if (fixPwd)
+ {
+ /* convert password file to new pin format */
+ ConvertPasswordToPin(pszServerRoot, fileData.cFileName);
+ /* do any server upgrade stuff */
+ ReinstallUpgradeServer(pszServerRoot, fileData.cFileName);
+ }
+
+ /* turn on server */
+ ControlSlapdInstance(fileData.cFileName, bOn);
+ }
+ }
+
+ /* wait to make sure give server enough time startup/shutdown*/
+ /* this time should be long enough for all instances we just */
+ /* tried to shutdown/startup */
+ Sleep(SLAPD_SHUTDOWN_TIME_MILLISECONDS);
+
+
+ /* set back to previous current directory */
+ SetCurrentDirectory(szCurrentDir);
+
+ return bReturn;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// TMPL_PreInstall
+//
+// This function is called by the installation framework before asking the
+// user any questions. Here you should determine if all of the requisites
+// for installing this component are being met. If this operation succeeds
+// return TRUE, otherwise display an error message and return FALSE to abort
+// installation.
+//
+
+BOOL __declspec(dllexport)
+DSINST_PreInstall(LPCSTR lpszInstallPath)
+{
+ BOOL bReturn = FALSE;
+ // TODO: Add code to check for pre-installation requirements.
+
+ if( TRUE == getSNMPStatus() )
+ {
+ char * szLdapURL = NULL;
+ char * szLdapUser = NULL;
+ char * szAdminDomain = NULL;
+
+ getDefaultLdapInfo(TARGETDIR, &szLdapURL, &szLdapUser,
+ &szAdminDomain);
+ if (szLdapURL && szAdminDomain)
+ {
+ lstrcpy(mi.m_szLdapURL, szLdapURL);
+ GetURLComponents(mi.m_szLdapURL, mi.m_szMCCHost,
+ &mi.m_nMCCPort, mi.m_szMCCSuffix);
+ if (mi.m_szMCCSuffix[0] == 0)
+ lstrcpy(mi.m_szMCCSuffix, NS_DOMAIN_ROOT);
+ if (szLdapUser && mi.m_szMCCBindAs)
+ lstrcpy(mi.m_szMCCBindAs, szLdapUser);
+ lstrcpy(mi.m_szAdminDomain, szAdminDomain);
+ // since this server root is already configured to use
+ // an existing configuration directory server, we will
+ // not allow the user to install another one here, so
+ // the directory server created here will be a user
+ // directory; we will still need to ask for the admin
+ // user password
+ mi.m_nExistingMCC = 1;
+ mi.m_nExistingUG = 0;
+ mi.m_nCfgSspt = 0;
+
+ // it's only a reinstall if there is already a slapd
+ // installed in this server root
+ if( slapdExists(TARGETDIR) )
+ mi.m_nReInstall = 1;
+ else
+ mi.m_nReInstall = 0;
+ }
+ bReturn = TRUE;
+ }
+
+ if (mi.m_nReInstall) {
+ char infFile[MAX_PATH] = {0};
+ sprintf(infFile, "%s\\setup\\slapd\\slapd.inf", TARGETDIR);
+ GetProductInfoStringWithTok(SETUP_INF_VERSION, "=", oldVersion,
+ OLD_VERSION_SIZE, infFile);
+ myLogData("file %s old version is %s", infFile, oldVersion);
+ }
+
+ return bReturn;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// DSINST_AskOptions
+//
+// This function is called by the installation framework to query the user for
+// information about your component. Here you should ask all of the questions
+// required to install your component as a series of wizard property sheets.
+//
+
+INT __declspec(dllexport)
+DSINST_AskOptions(HWND hwndParent, INT nDirection)
+{
+ PROPSHEETPAGE psp[NUM_PROP_PAGES];
+ UINT uStartPage;
+ INT nNumPages = 0;
+ static INT wasExistingMCC = -1;
+
+ // TODO: Initialize a property page for each dialog template/resource
+ // required to query the user for options related to your server
+ // installation. Don't forget to increment the count of pages contained
+ // in NUM_PROP_PAGES at the top of this file.
+
+ /* Keep the value of mi.m_nExistingMCC at the first invocation */
+ if (wasExistingMCC == -1)
+ {
+ wasExistingMCC = mi.m_nExistingMCC;
+ }
+
+ /* if in silent mode or reinstalling, don't display any property pages */
+ if ( SILENTMODE == MODE )
+ {
+ mi.m_nResult = nDirection; // keep moving in same direction...
+ }else
+ {
+ if(1 == mi.m_nReInstall)
+ {
+ uStartPage = ((nDirection == NS_WIZNEXT) ? 0 : 0);
+ AddWizardPage(mi.m_hModule, &psp[0], IDD_REINSTALL_CONFIG, ReInstall_DialogProc);
+ nNumPages = 1;
+ }else{
+
+ if (EXPRESSMODE == MODE)
+ {
+ /* just ask for Suitespot ID and Unrestricted User */
+ uStartPage = ((nDirection == NS_WIZNEXT) ? 0 : 1);
+ if (mi.m_nExistingMCC) // just need admin id and pwd
+ AddWizardPage(mi.m_hModule, &psp[0], IDD_ADMIN_ID_ONLY,
+ Admin_ID_Only_DialogProc);
+ else
+ AddWizardPage(mi.m_hModule, &psp[0], IDD_SUITESPOTID,
+ SuitespotID_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[1], IDD_ROOTDN, RootDN_DialogProc);
+
+ /* make sure to set numprop pages to actual number */
+ nNumPages = 2;
+ } else if ( (NORMALMODE == MODE) || (CUSTOMMODE == MODE) )
+ {
+ /* ask for server settings, SuitespotID and Unrestricted User */
+
+ if ((NORMALMODE == MODE) && wasExistingMCC)
+ {
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_SERVER_SETTINGS, Server_Settings_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_ADMIN_ID_ONLY, Admin_ID_Only_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_ROOTDN, RootDN_DialogProc);
+ }
+ else
+ {
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_MCC_SETTINGS, MCC_Settings_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_ADMIN_DOMAIN, AdminDomainCustom_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_MCC_SETTINGS, UG_Settings_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_SERVER_SETTINGS, Server_Settings_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_SUITESPOTID, SuitespotID_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_ADMIN_DOMAIN, AdminDomain_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_ROOTDN, RootDN_DialogProc);
+ }
+
+ /* add additional pages for custom mode */
+ if ( (CUSTOMMODE == MODE) )
+ {
+#ifdef CUSTOM_REPL_FOR_4X
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_CHOOSE_REPLICATION_SETUP,
+ Choose_Replication_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_SUPPLIER_REPLICATION_SETTINGS,
+ Supplier_Replication_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_CONSUMER_DN, Consumer_DN_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_REPLICATION_AGREEMENT,
+ Supplier_Replication_Agreement_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_CONSUMER_REPLICATION_SETTINGS,
+ Consumer_Replication_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_REPLICATION_AGREEMENT,
+ Consumer_Replication_Agreement_DialogProc);
+#endif
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_SAMPLE_ENTRIES_ORG,
+ Sample_Entries_Org_DialogProc);
+ AddWizardPage(mi.m_hModule, &psp[nNumPages++],
+ IDD_DISABLE_SCHEMA_CHECKING,
+ Disable_Schema_Checking_DialogProc);
+ }
+ uStartPage = ((nDirection == NS_WIZNEXT) ? 0 : (nNumPages-1));
+ }
+
+ }
+
+ // Must initialize the result to an error code before calling WizardDialog
+ mi.m_nResult = NS_WIZERROR;
+
+ // Set the first page to display based on the direction we are travelling
+
+
+ // Call WizardDialog to display the set of property pages
+ if (WizardDialog(mi.m_hModule, hwndParent, psp, nNumPages, uStartPage) < 0)
+ {
+ mi.m_nResult = NS_WIZERROR;
+ }
+
+ }
+
+ // convert all DN valued attributes to LDAPv3 quoting
+ normalizeDNs();
+
+ // store the User directory information
+ storeUserDirectoryInfo();
+
+ if (1 == mi.m_nReInstall)
+ {
+ set_ldap_settings();
+ }
+
+ return mi.m_nResult;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// DSINST_GetSummary
+//
+// This function is called by the installation framework after all questions,
+// for all components, have been asked. Here you should provide a detailed
+// summary explaining all of the choices selected by the user.
+//
+// IMPORTANT NOTE: Each line MUST end in a carriage return/line feed
+// combination ("\r\n") as this string is placed in an edit control. Edit
+// controls do not properly handle single "\n" end-of-line characters.
+//
+
+VOID __declspec(dllexport)
+DSINST_GetSummary(LPSTR lpszSummary)
+{
+
+ // TODO: Add code to fill in the summary information entered by the user
+ char *psz = lpszSummary;
+
+ /* only use replication settings written to slapd.conf if dialogs were
+ seen by user... otherwise set them to null so posted as null */
+
+ if ( 1 != mi.m_nUseSupplierSettings)
+ {
+ memset(mi.m_szSupplierDN, '\0', MAX_STR_SIZE);
+ }
+ if ( 1 != mi.m_nUseChangeLogSettings)
+ {
+ memset(mi.m_szChangeLogDbDir, '\0', MAX_STR_SIZE);
+ memset(mi.m_szChangeLogSuffix, '\0', MAX_STR_SIZE);
+ }
+
+ if ( 1 != mi.m_nConfigConsumerDN)
+ {
+ memset(mi.m_szConsumerDN, '\0', MAX_STR_SIZE);
+ }
+
+ /* display in order of dialogs */
+ if ( 1 == mi.m_nReInstall )
+ {
+ psz += WriteSummaryStringRC(psz, " %s\r\n", mi.m_hModule, SUM_REINSTALL, NULL);
+ } else
+ {
+
+
+ /* if installing into existing configuration directory display settings entered */
+ if ( 1 == mi.m_nExistingMCC)
+ {
+ psz += WriteSummaryStringRC(psz, " %s\r\n", mi.m_hModule, SUM_CONFIG_DS_TITLE, NULL);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_HOST, mi.m_szMCCHost);
+ psz += WriteSummaryIntRC(psz, " %s: %d\r\n", mi.m_hModule, SUM_PORT, mi.m_nMCCPort);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_SUFFIX, mi.m_szMCCSuffix);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_BIND_AS, mi.m_szMCCBindAs);
+ }
+
+ /* if storing data in existing directory display options entered */
+ if ( 1 == mi.m_nExistingUG)
+ {
+ psz += WriteSummaryStringRC(psz, " %s\r\n", mi.m_hModule, SUM_DATA_DS_TITLE, NULL);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_HOST, mi.m_szUGHost);
+ psz += WriteSummaryIntRC(psz, " %s: %d\r\n", mi.m_hModule, SUM_PORT, mi.m_nUGPort);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_SUFFIX, mi.m_szUGSuffix);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_BIND_AS, mi.m_szUserGroupAdmin);
+ }
+
+ /* display instance settings */
+ psz += WriteSummaryStringRC(psz, " %s\r\n", mi.m_hModule, SUM_DS_SET_TITLE, NULL);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_SERVER_IDENTIFIER, mi.m_szServerIdentifier);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_SUFFIX, mi.m_szInstanceSuffix);
+ psz += WriteSummaryIntRC(psz, " %s: %d\r\n", mi.m_hModule, SUM_PORT, mi.m_nInstanceServerPort);
+
+ if ( 1 != mi.m_nExistingMCC)
+ {
+ /* if not using Existing MCC display configuration Admin id*/
+ /* otherwise it is displayed as the Bind As under Configuration Directory */
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_CFG_ADM_ID, mi.m_szSsptUid);
+ }
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_ADMIN_DOMAIN, mi.m_szAdminDomain);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_DIRECTORY_MANAGER, mi.m_szInstanceUnrestrictedUser);
+
+ /* replication settings */
+ if (mi.m_nSetupSupplierReplication != NO_REPLICATION)
+ {
+ psz += WriteSummaryStringRC(psz, " %s\r\n", mi.m_hModule, SUM_SUPPLIER_REPL_TITLE, NULL);
+
+ /* display changelog DB dir and suffix for both supplier replication modes */
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_CHANGELOG_DB_DIR, mi.m_szChangeLogDbDir);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_CHANGELOG_SUFFIX, mi.m_szChangeLogSuffix);
+ }
+
+ if (SUPPLIER_SIR_REPLICATION == mi.m_nSetupSupplierReplication)
+ {
+ /* display replication agreement */
+ psz += WriteSummaryStringRC(psz, " %s\r\n", mi.m_hModule, SUM_REPL_AGR_TITLE, NULL);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_HOST, mi.m_szSupplierHost);
+ psz += WriteSummaryIntRC(psz, " %s: %d\r\n", mi.m_hModule, SUM_PORT, mi.m_nSupplierPort);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_REPL_ROOT, mi.m_szSupplierRoot);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_BIND_AS, mi.m_szSupplierBindAs);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_REPL_DAYS, mi.m_szSIRDays);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_REPL_TIMES, mi.m_szSIRTimes);
+ }
+
+ if (SUPPLIER_CIR_REPLICATION == mi.m_nSetupSupplierReplication )
+ {
+ /* if configuring consumer BIND DN display what user entered */
+ if (1 == mi.m_nConfigConsumerDN)
+ {
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_CONSUMER_BIND_DN, mi.m_szConsumerDN);
+ }
+ }
+
+ if (CONSUMER_SIR_REPLICATION == mi.m_nSetupConsumerReplication)
+ {
+ psz += WriteSummaryStringRC(psz, " %s\r\n", mi.m_hModule, SUM_CONSUMER_REPL_TITLE, NULL);
+ /* display supplier bind dn */
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_SUPPLIER_DN, mi.m_szSupplierDN);
+ }
+
+ if (CONSUMER_CIR_REPLICATION == mi.m_nSetupConsumerReplication)
+ {
+ psz += WriteSummaryStringRC(psz, " %s\r\n", mi.m_hModule, SUM_CONSUMER_REPL_TITLE, NULL);
+ /* display replication agreement */
+ /* display replication agreement */
+ psz += WriteSummaryStringRC(psz, " %s\r\n", mi.m_hModule, SUM_REPL_AGR_TITLE, NULL);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_HOST, mi.m_szConsumerHost);
+ psz += WriteSummaryIntRC(psz, " %s: %d\r\n", mi.m_hModule, SUM_PORT, mi.m_nConsumerPort);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_REPL_ROOT, mi.m_szConsumerRoot);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_BIND_AS, mi.m_szConsumerBindAs);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_REPL_DAYS, mi.m_szCIRDays);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_REPL_TIMES, mi.m_szCIRTimes);
+ psz += WriteSummaryIntRC(psz, " %s: %d\r\n", mi.m_hModule, SUM_REPL_SYNC_INTERVAL, mi.m_nCIRInterval);
+ }
+
+ if ( CUSTOMMODE == MODE)
+ {
+ /* display org & ldif files */
+
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_POP_ORG_STRUCT, onezero2yesno(mi.m_nPopulateSampleOrg) );
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_POP_DB_FILE, mi.m_szPopLdifFile);
+ psz += WriteSummaryStringRC(psz, " %s: %s\r\n", mi.m_hModule, SUM_DISABLE_SCHEMA_CHECKING, onezero2yesno(mi.m_nDisableSchemaChecking) );
+ }
+
+ }
+
+ *psz = '\0';
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// DSINST_WriteGlobalCache
+//
+// This function is called by the installation framework when the user clicks
+// Next at the summary screen. Here you should write all information entered
+// by the user into the installation cache for use during silent installation.
+// Data written to this section of the file may be interpreted by the
+// framework. If this operation succeeds return TRUE, otherwise display an
+// error message and return FALSE to indicate an error.
+//
+
+BOOL __declspec(dllexport)
+DSINST_WriteGlobalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
+{
+
+ if(1 == mi.m_nReInstall)
+ {
+
+ /* write configuration directory info, thats the only thing we know about */
+ /* during reinstall */
+ WritePrivateProfileString(lpszSectionName, GLOBAL_INF_LDAP_USER, mi.m_szMCCBindAs,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, GLOBAL_INF_LDAP_PASSWD, mi.m_szMCCPw,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_K_LDAP_URL, mi.m_szLdapURL,
+ lpszCacheFileName);
+
+
+ /* where do we get admin domain from on ReInstall ??? is default ok? */
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_ADMIN_DOMAIN, mi.m_szAdminDomain,
+ lpszCacheFileName);
+
+
+ /* shut down all slapd servers so no file conflicts*/
+ ControlSlapdServers(TARGETDIR, FALSE, FALSE);
+
+ return TRUE;
+ }
+
+ /* this is the first thing called after last dialog, setup UG stuff here if creating UG directory */
+ /* stevross: is there a better place to put this ? possibly in GetSummary, */
+ /* but what happens in silent mode ?*/
+
+ /* construct the LDAPURL */
+ /* suffix must always be o=netscape root */
+ sprintf(mi.m_szLdapURL, "ldap://%s:%d/%s", mi.m_szMCCHost, mi.m_nMCCPort, NS_DOMAIN_ROOT);
+
+ if(mi.m_nExistingUG == 0)
+ {
+ /* the user is creating a new UG with this instance */
+
+ /* create ou=People/ou=Groups */
+// mi.m_nPopulateSampleOrg = 1;
+// lstrcpy(mi.m_szPopLdifFile, SUGGEST_LDIF);
+
+ if(mi.m_nExistingMCC == 0)
+ {
+ /* the user is also creating a new MCC so set UG admin to MCC admin */
+ lstrcpy(mi.m_szUserGroupAdmin, mi.m_szMCCBindAs);
+ lstrcpy(mi.m_szUserGroupAdminPW, mi.m_szMCCPw);
+
+ }else{
+ /* user is using an existing MCC so only creating UG, make UG user same as
+ Root DN */
+ lstrcpy(mi.m_szUserGroupAdmin, mi.m_szInstanceUnrestrictedUser);
+ lstrcpy(mi.m_szUserGroupAdminPW, mi.m_szInstancePassword);
+
+ }
+ sprintf(mi.m_szUserGroupURL, "ldap://%s:%d/%s", mi.m_szInstanceHostName,
+ mi.m_nInstanceServerPort, mi.m_szInstanceSuffix);
+ }
+
+ WritePrivateProfileString(lpszSectionName, GLOBAL_INF_LDAP_USER, mi.m_szMCCBindAs,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, GLOBAL_INF_LDAP_PASSWD, mi.m_szMCCPw,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_ADMIN_DOMAIN, mi.m_szAdminDomain,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_K_LDAP_URL, mi.m_szLdapURL,
+ lpszCacheFileName);
+
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_USER_GROUP_LDAP_URL, mi.m_szUserGroupURL,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_USER_GROUP_ADMIN_ID, mi.m_szUserGroupAdmin,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_USER_GROUP_ADMIN_PWD, mi.m_szUserGroupAdminPW,
+ lpszCacheFileName);
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// DSINST_WriteLocalCache
+//
+// This function is called by the installation framework when the user clicks
+// Next at the summary screen. Here you should write all information entered
+// by the user into the installation cache for use during silent installation.
+// Data written to this file is not interpreted by the framework, and may
+// consist of any values that you will need to perform the installation (not
+// just values entered by the user). If this operation succeeds return TRUE,
+// otherwise display an error message and return FALSE to indicate an error.
+//
+
+BOOL __declspec(dllexport)
+DSINST_WriteLocalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
+{
+ // TODO: Add code to write data to the cache file (INI format) under the
+ // specified section name.
+
+ CHAR szInt[BUFSIZ];
+
+ /* don't want to over write with bogus default values on ReInstall*/
+ if(1 == mi.m_nReInstall)
+ {
+ /* just write snmp status cause thats the only thing we really know*/
+ /* will allow to control it on reinstall also */
+ WritePrivateProfileString(lpszSectionName, LOCAL_INF_SNMP_ON, onezero2yesno(mi.m_nSNMPOn),
+ lpszCacheFileName);
+
+ return TRUE;
+ }
+
+
+ /* general settings */
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_USE_EXISTING_MC, onezero2yesno(mi.m_nExistingMCC),
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_USE_EXISTING_UG, onezero2yesno(mi.m_nExistingUG),
+ lpszCacheFileName);
+
+ sprintf(szInt, "%d", mi.m_nInstanceServerPort);
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SERVER_PORT, szInt,
+ lpszCacheFileName);
+
+ if(!mi.m_nExistingUG)
+ {
+ /* don't write this key when config only directory */
+ /* config only directory when using existing data store */
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SUFFIX, mi.m_szInstanceSuffix,
+ lpszCacheFileName);
+ }
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_ROOTDN, mi.m_szInstanceUnrestrictedUser,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_ROOTDNPWD, mi.m_szInstancePassword,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SERVER_IDENTIFIER, mi.m_szServerIdentifier,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SLAPD_CONFIG_FOR_MC, onezero2yesno(mi.m_nCfgSspt),
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_ADD_SAMPLE_ENTRIES,
+ onezero2yesno(mi.m_nPopulateSampleEntries),
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_ADD_ORG_ENTRIES, onezero2yesno(mi.m_nPopulateSampleOrg),
+ lpszCacheFileName);
+
+ sprintf(szInt, "%s", onezero2yesno( ( (NO_REPLICATION != mi.m_nSetupConsumerReplication) || (NO_REPLICATION != mi.m_nSetupSupplierReplication) ) ) );
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_USE_REPLICATION, szInt,
+ lpszCacheFileName);
+
+ /* consumer replication settings */
+
+ /* write no instead of number for no replication to be like unix installer */
+ if(NO_REPLICATION != mi.m_nSetupConsumerReplication)
+ {
+ sprintf(szInt, "%d", mi.m_nSetupConsumerReplication);
+ }else{
+ sprintf(szInt, "no");
+ }
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SETUP_CONSUMER, szInt,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_HOST, mi.m_szConsumerHost,
+ lpszCacheFileName);
+
+ sprintf(szInt, "%d", mi.m_nConsumerPort );
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_PORT, szInt,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_SUFFIX, mi.m_szConsumerRoot,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_BINDDN, mi.m_szConsumerBindAs,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_BINDDNPWD, mi.m_szConsumerPw,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_SECURITY_ON, onezero2yesno(mi.m_nConsumerSSL),
+ lpszCacheFileName);
+
+ sprintf(szInt, "%d", mi.m_nCIRInterval );
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_INTERVAL, szInt,
+ lpszCacheFileName);
+
+ if(!strcmp(DEFAULT_CIR_DAYS, mi.m_szCIRDays) )
+ {
+ /* if default of all days write null to inf file as that is what cgi wants */
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_DAYS, "\0",
+ lpszCacheFileName);
+ }else{
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_DAYS, mi.m_szCIRDays,
+ lpszCacheFileName);
+ }
+
+ if(!strcmp(DEFAULT_CIR_TIMES, mi.m_szCIRTimes) )
+ {
+ /* if default of all times write null to inf file as that is what cgi wants */
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_TIMES, "\0",
+ lpszCacheFileName);
+ }else{
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_TIMES, mi.m_szCIRTimes,
+ lpszCacheFileName);
+ }
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_REPLICATIONDN, mi.m_szSupplierDN,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_REPLICATIONPWD, mi.m_szSupplierPW,
+ lpszCacheFileName);
+
+ /* Supplier replication settings */
+
+ /* write no instead of number for no replication to be like unix installer */
+ if(NO_REPLICATION != mi.m_nSetupSupplierReplication)
+ {
+ sprintf(szInt, "%d", mi.m_nSetupSupplierReplication);
+ }else{
+ sprintf(szInt, "no");
+ }
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SETUP_SUPPLIER, szInt,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CHANGELOGDIR, mi.m_szChangeLogDbDir,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CHANGELOGSUFFIX, mi.m_szChangeLogSuffix,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_HOST, mi.m_szSupplierHost,
+ lpszCacheFileName);
+
+ sprintf(szInt, "%d", mi.m_nSupplierPort );
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_PORT, szInt,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_SUFFIX, mi.m_szSupplierRoot,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_BINDDN, mi.m_szSupplierBindAs,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_BINDDNPWD, mi.m_szSupplierPw,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_SECURITY_ON, onezero2yesno( mi.m_nSupplierSSL),
+ lpszCacheFileName);
+
+ if(!strcmp(DEFAULT_SIR_DAYS, mi.m_szSIRDays) )
+ {
+ /* if default of all days write null to inf file as that is what cgi wants */
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_DAYS, "\0",
+ lpszCacheFileName);
+ }else{
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_DAYS, mi.m_szSIRDays,
+ lpszCacheFileName);
+ }
+
+ if(!strcmp(DEFAULT_SIR_TIMES, mi.m_szSIRTimes) )
+ {
+ /* if default of all times write null to inf file as that is what cgi wants */
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_TIMES, "\0",
+ lpszCacheFileName);
+ }else{
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_TIMES, mi.m_szSIRTimes,
+ lpszCacheFileName);
+ }
+
+ WritePrivateProfileString(lpszSectionName, LOCAL_INF_CONFIG_CONSUMER_DN, onezero2yesno(mi.m_nConfigConsumerDN),
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CONSUMERDN, mi.m_szConsumerDN,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_CONSUMERPWD, mi.m_szConsumerPW,
+ lpszCacheFileName);
+
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_INSTALL_LDIF_FILE, mi.m_szPopLdifFile,
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, SLAPD_KEY_DISABLE_SCHEMA_CHECKING, onezero2yesno(mi.m_nDisableSchemaChecking),
+ lpszCacheFileName);
+
+ WritePrivateProfileString(lpszSectionName, LOCAL_INF_SNMP_ON, onezero2yesno(mi.m_nSNMPOn),
+ lpszCacheFileName);
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// DSINST_ReadGlobalCache
+//
+// This function is called by the installation framework during silent install
+// to initialize your data from the cache file you created above. Here you
+// should read any information stored in the installation cache's global
+// section that you need. If this operation succeeds return TRUE, otherwise
+// display an error message and return FALSE to indicate an error.
+//
+
+BOOL __declspec(dllexport)
+DSINST_ReadGlobalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
+{
+ // TODO: Add code to read data from the cache file (INI format) under the
+ // specified section name.
+
+ /* stevross: this may be null when reading cache for post install or something, so
+ make sure to allocate it again */
+ CHAR szFormat[MAX_STR_SIZE];
+
+ if(1 == mi.m_nReInstall)
+ {
+ /* just read config directory stuff */
+ /* this is the only stuff we are need and are guaranteed to have */
+ LoadString( mi.m_hModule, ERR_READ_GLOBAL_CACHE, szFormat, MAX_STR_SIZE);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_FULL_MACHINE_NAME, "\0",
+ mi.m_szInstanceHostName, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ if (mi.m_szInstanceHostName[0] == 0)
+ DSGetHostName(mi.m_szInstanceHostName, MAX_STR_SIZE);
+
+ if(NULL == mi.m_szMCCBindAs )
+ {
+ mi.m_szMCCBindAs = malloc(MAX_STR_SIZE);
+ }
+
+ GetPrivateProfileString(lpszSectionName, GLOBAL_INF_LDAP_USER, "\0",
+ mi.m_szMCCBindAs, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ if ( 0 == lstrcmp(mi.m_szMCCBindAs, "\0") )
+ {
+ DSMessageBoxOK(ERR_NO_SS_ADMIN_TITLE, ERR_NO_SS_ADMIN, 0);
+ return FALSE;
+ }else{
+
+ /* stevross: now that cgi can handle full DN
+ Sspt UID is same user as MCC BindAs no matter what
+ look into removing later once get instance creatin working */
+ lstrcpy(mi.m_szSsptUid, mi.m_szMCCBindAs);
+ }
+
+ GetPrivateProfileString(lpszSectionName, GLOBAL_INF_LDAP_PASSWD, "\0",
+ mi.m_szMCCPw, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ if ( 0 == lstrcmp(mi.m_szMCCPw, "\0") )
+ {
+ DSMessageBoxOK(ERR_NO_PW_TITLE, ERR_NO_PW, 0);
+ return FALSE;
+ }else{
+ /* use password for sspt user since this is the ssptuser */
+ lstrcpy(mi.m_szSsptUidPw, mi.m_szMCCPw);
+ lstrcpy(mi.m_szSsptUidPwAgain, mi.m_szSsptUidPw);
+ }
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_ADMIN_DOMAIN, "\0",
+ mi.m_szAdminDomain, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_K_LDAP_URL, "\0",
+ mi.m_szLdapURL, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ if( GetURLComponents(mi.m_szLdapURL, mi.m_szMCCHost,
+ &mi.m_nMCCPort, mi.m_szMCCSuffix) != 0)
+ {
+ DSMessageBoxOK(ERR_NO_CONFIG_URL_TITLE, ERR_NO_CONFIG_URL, 0);
+ return FALSE;
+ }
+
+
+ return TRUE;
+ }
+
+
+ LoadString( mi.m_hModule, ERR_READ_GLOBAL_CACHE, szFormat, MAX_STR_SIZE);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_FULL_MACHINE_NAME, "\0",
+ mi.m_szInstanceHostName, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ if (mi.m_szInstanceHostName[0] == 0)
+ DSGetHostName(mi.m_szInstanceHostName, MAX_STR_SIZE);
+
+ if(NULL == mi.m_szMCCBindAs )
+ {
+ mi.m_szMCCBindAs = malloc(MAX_STR_SIZE);
+ }
+
+ GetPrivateProfileString(lpszSectionName, GLOBAL_INF_LDAP_USER, "\0",
+ mi.m_szMCCBindAs, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ if ( 0 == lstrcmp(mi.m_szMCCBindAs, "\0") )
+ {
+ DSMessageBoxOK(ERR_NO_SS_ADMIN_TITLE, ERR_NO_SS_ADMIN, 0);
+ return FALSE;
+ }else{
+
+ /* stevross: now that cgi can handle full DN
+ Sspt UID is same user as MCC BindAs no matter what
+ look into removing later once get instance creatin working */
+ lstrcpy(mi.m_szSsptUid, mi.m_szMCCBindAs);
+ }
+
+ GetPrivateProfileString(lpszSectionName, GLOBAL_INF_LDAP_PASSWD, "\0",
+ mi.m_szMCCPw, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ if ( 0 == lstrcmp(mi.m_szMCCPw, "\0") )
+ {
+ DSMessageBoxOK(ERR_NO_PW_TITLE, ERR_NO_PW, 0);
+ return FALSE;
+ }else{
+ /* use password for sspt user since this is the ssptuser */
+ lstrcpy(mi.m_szSsptUidPw, mi.m_szMCCPw);
+ lstrcpy(mi.m_szSsptUidPwAgain, mi.m_szSsptUidPw);
+ }
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_ADMIN_DOMAIN, "\0",
+ mi.m_szAdminDomain, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_K_LDAP_URL, "\0",
+ mi.m_szLdapURL, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ if( GetURLComponents(mi.m_szLdapURL, mi.m_szMCCHost,
+ &mi.m_nMCCPort, mi.m_szMCCSuffix) != 0)
+ {
+ DSMessageBoxOK(ERR_NO_CONFIG_URL_TITLE, ERR_NO_CONFIG_URL, 0);
+ return FALSE;
+ }
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_USER_GROUP_LDAP_URL, "\0",
+ mi.m_szUserGroupURL, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ if( GetURLComponents(mi.m_szUserGroupURL, mi.m_szUGHost,
+ &mi.m_nUGPort, mi.m_szUGSuffix) != 0)
+ {
+ DSMessageBoxOK(ERR_NO_USER_URL_TITLE, ERR_NO_USER_URL, 0);
+ return FALSE;
+ }
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_USER_GROUP_ADMIN_ID, "\0",
+ mi.m_szUserGroupAdmin, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_USER_GROUP_ADMIN_PWD, "\0",
+ mi.m_szUserGroupAdminPW, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// DSINST_ReadLocalCache
+//
+// This function is called by the installation framework during silent install
+// to intialize your data from the local section of the cache created above.
+// Here you should read any information stored in the installation cache's
+// local section that you need. If this operation succeeds return TRUE,
+// otherwise display an error message and return FALSE to indicate an error.
+//
+
+BOOL __declspec(dllexport)
+DSINST_ReadLocalCache(LPCSTR lpszCacheFileName, LPCSTR lpszSectionName)
+{
+ // TODO: Add code to read data from the cache file (INI format) under the
+ // specified section name.
+ char szTemp[BUFSIZ];
+ CHAR szFormat[MAX_STR_SIZE];
+
+ /* only ting we know on this section during reinstall is SNMP value */
+ if(1 == mi.m_nReInstall)
+ {
+
+ GetPrivateProfileString(lpszSectionName, LOCAL_INF_SNMP_ON, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nSNMPOn = yesno2onezero(szTemp);
+
+ return TRUE;
+ }
+
+
+ LoadString( mi.m_hModule, ERR_READ_LOCAL_CACHE, szFormat, MAX_STR_SIZE);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_USE_EXISTING_MC, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nExistingMCC = yesno2onezero(szTemp);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_USE_EXISTING_UG, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nExistingUG = yesno2onezero(szTemp);
+
+ mi.m_nInstanceServerPort = GetPrivateProfileInt(lpszSectionName,
+ SLAPD_KEY_SERVER_PORT, DEFAULT_SERVER_PORT, lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SUFFIX, "\0",
+ mi.m_szInstanceSuffix, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_ROOTDN, "\0",
+ mi.m_szInstanceUnrestrictedUser, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_ROOTDNPWD, "\0",
+ mi.m_szInstancePassword, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ lstrcpy(mi.m_szInstancePasswordAgain, mi.m_szInstancePassword);
+
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SERVER_IDENTIFIER, "\0",
+ mi.m_szServerIdentifier, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SLAPD_CONFIG_FOR_MC, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nCfgSspt = yesno2onezero(szTemp);
+
+ /*stevross: should I add more error checking below? These are only required in certain cases*/
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_ADD_SAMPLE_ENTRIES, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nPopulateSampleEntries = yesno2onezero(szTemp);
+
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_ADD_ORG_ENTRIES, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nPopulateSampleOrg = yesno2onezero(szTemp);
+
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SETUP_CONSUMER, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ /* value should be no, 1 or 2 to be like unix installer*/
+ if(!strcmpi(szTemp, "no") )
+ {
+ mi.m_nSetupConsumerReplication = NO_REPLICATION;
+ }else{
+ mi.m_nSetupConsumerReplication = GetPrivateProfileInt(lpszSectionName, SLAPD_KEY_SETUP_CONSUMER,
+ DEFAULT_SETUP_CONSUMER, lpszCacheFileName);
+ }
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_HOST, "\0",
+ mi.m_szConsumerHost, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ mi.m_nConsumerPort = GetPrivateProfileInt(lpszSectionName, SLAPD_KEY_CIR_PORT,
+ DEFAULT_CIR_PORT, lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_SUFFIX, "\0",
+ mi.m_szConsumerRoot, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_BINDDN, "\0",
+ mi.m_szConsumerBindAs, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_BINDDNPWD, "\0",
+ mi.m_szConsumerPw, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_SECURITY_ON, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nConsumerSSL = yesno2onezero(szTemp);
+
+
+ mi.m_nCIRInterval = GetPrivateProfileInt(lpszSectionName, SLAPD_KEY_CIR_INTERVAL,
+ DEFAULT_CIR_INTERVAL, lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_DAYS, DEFAULT_CIR_DAYS,
+ mi.m_szCIRDays, N_DAYS,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CIR_TIMES, DEFAULT_CIR_TIMES,
+ mi.m_szCIRTimes, N_TIMES,
+ lpszCacheFileName);
+
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_REPLICATIONDN, "\0",
+ mi.m_szSupplierDN, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_REPLICATIONPWD, "\0",
+ mi.m_szSupplierPW, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ /* read from cache, so copy it to mi.m_szSupplierPWAgain); */
+ lstrcpy(mi.m_szSupplierPWAgain, mi.m_szSupplierPW);
+
+ /* Supplier replication settings */
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SETUP_SUPPLIER, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ /* value should be no, 1 or 2 to be like unix installer*/
+ if(!strcmpi(szTemp, "no"))
+ {
+ mi.m_nSetupSupplierReplication = NO_REPLICATION;
+ }else{
+ mi.m_nSetupSupplierReplication = GetPrivateProfileInt(lpszSectionName, SLAPD_KEY_SETUP_SUPPLIER,
+ DEFAULT_SETUP_CONSUMER, lpszCacheFileName);
+ }
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CHANGELOGDIR, "\0",
+ mi.m_szChangeLogDbDir, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CHANGELOGSUFFIX, "\0",
+ mi.m_szChangeLogSuffix, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_HOST, "\0",
+ mi.m_szSupplierHost, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ mi.m_nSupplierPort = GetPrivateProfileInt(lpszSectionName, SLAPD_KEY_SIR_PORT,
+ DEFAULT_SIR_PORT, lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_SUFFIX, "\0",
+ mi.m_szSupplierRoot, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_BINDDN, "\0",
+ mi.m_szSupplierBindAs, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_BINDDNPWD, "\0",
+ mi.m_szSupplierPw, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_SECURITY_ON, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nSupplierSSL = yesno2onezero(szTemp);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_DAYS,DEFAULT_SIR_DAYS,
+ mi.m_szSIRDays, N_DAYS,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_SIR_TIMES, DEFAULT_SIR_TIMES,
+ mi.m_szSIRTimes, N_TIMES,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, LOCAL_INF_CONFIG_CONSUMER_DN, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nConfigConsumerDN = yesno2onezero(szTemp);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CONSUMERDN, "\0",
+ mi.m_szConsumerDN, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_CONSUMERPWD, "\0",
+ mi.m_szConsumerPW, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+ lstrcpy(mi.m_szConsumerPWAgain, mi.m_szConsumerPW);
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_INSTALL_LDIF_FILE, DEFAULT_INF_POP_LDIF_FILE,
+ mi.m_szPopLdifFile, MAX_STR_SIZE,
+ lpszCacheFileName);
+
+
+ GetPrivateProfileString(lpszSectionName, SLAPD_KEY_DISABLE_SCHEMA_CHECKING, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nDisableSchemaChecking = yesno2onezero(szTemp);
+
+
+
+ GetPrivateProfileString(lpszSectionName, LOCAL_INF_SNMP_ON, "\0",
+ szTemp, BUFSIZ,
+ lpszCacheFileName);
+
+ mi.m_nSNMPOn = yesno2onezero(szTemp);
+
+ if ( SILENTMODE == MODE)
+ {
+ /* verify settings here as they didn't get verified in dialog */
+ /* stop install if find something bad */
+
+ /* things that always need to be checked */
+ if ( Verify_Server_Settings() )
+ {
+ /* error in server settings */
+ return FALSE;
+ }
+
+ if ( Verify_ROOTDN() )
+ {
+ return FALSE;
+ }
+
+#ifdef CUSTOM_REPL_FOR_4X
+ if (SUPPLIER_SIR_REPLICATION == mi.m_nSetupSupplierReplication)
+ {
+ /* always need to check changelogdb and suffix */
+ if ( Verify_Supplier_Replication() )
+ {
+ return FALSE;
+
+ }
+
+ /* check replication agreement */
+ if ( VerifyReplAgreement(mi.m_szSupplierHost,
+ &mi.m_nSupplierPort,
+ mi.m_szSupplierRoot,
+ mi.m_szSupplierBindAs,
+ mi.m_szSupplierPw,
+ mi.m_szSIRDays,
+ mi.m_szSIRTimes) )
+ {
+ return FALSE;
+ }
+
+
+ }
+
+ if (SUPPLIER_CIR_REPLICATION == mi.m_nSetupSupplierReplication)
+ {
+ /* always need to check changelogdb and suffix */
+ if ( Verify_Supplier_Replication() )
+ {
+ return FALSE;
+
+
+ }
+
+ if ( Verify_Consumer_DN() )
+ {
+ return FALSE;
+ }
+ }
+
+ if (CONSUMER_SIR_REPLICATION == mi.m_nSetupConsumerReplication)
+ {
+ if ( Verify_Consumer_Replication() )
+ {
+ return FALSE;
+ }
+ }
+
+ if (CONSUMER_CIR_REPLICATION == mi.m_nSetupConsumerReplication)
+ {
+ if ( VerifyReplAgreement(mi.m_szConsumerHost,
+ &mi.m_nConsumerPort,
+ mi.m_szConsumerRoot,
+ mi.m_szConsumerBindAs,
+ mi.m_szConsumerPw,
+ mi.m_szCIRDays,
+ mi.m_szCIRTimes) )
+ {
+ return FALSE;
+ }
+
+ }
+#endif
+ }
+
+ /* set ldap settings for silent install mode */
+ if(1 != mi.m_nReInstall)
+ {
+ set_ldap_settings();
+ }
+
+ return TRUE;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// DSINST_ReadComponentInf
+//
+//
+
+BOOL __declspec(dllexport) DSINST_ReadComponentInf(LPCSTR pszCacheFile, LPCSTR pszSection)
+{
+
+ char szValue[MAX_PATH];
+
+ myLogData("In DSINST_ReadComponentInf: file [%s] section [%s]",
+ pszCacheFile, pszSection);
+ GetPrivateProfileString(pszSection, SETUP_INF_COM_VENDOR, "", szValue, sizeof(szValue), pszCacheFile);
+ cd.szVendor = _strdup(szValue);
+ GetPrivateProfileString(pszSection, SETUP_INF_COM_DESC, "", szValue, sizeof(szValue), pszCacheFile);
+ cd.szDescription = _strdup(szValue);
+ GetPrivateProfileString(pszSection, SETUP_INF_COM_NAME, "", szValue, sizeof(szValue), pszCacheFile);
+ cd.szName = _strdup(szValue);
+ GetPrivateProfileString(pszSection, SETUP_INF_COM_NICKNAME, "", szValue, sizeof(szValue), pszCacheFile);
+ cd.szNickname = _strdup(szValue);
+ GetPrivateProfileString(pszSection, SETUP_INF_COM_VERSION, "", szValue, sizeof(szValue), pszCacheFile);
+ cd.szVersion = _strdup(szValue);
+ GetPrivateProfileString(pszSection, SETUP_INF_COM_BUILDNUMBER, "", szValue, sizeof(szValue), pszCacheFile);
+ cd.szBuildNumber = _strdup(szValue);
+ GetPrivateProfileString(pszSection, SETUP_INF_COM_REVISION, "", szValue, sizeof(szValue), pszCacheFile);
+ cd.szRevision = _strdup(szValue);
+ GetPrivateProfileString(pszSection, SETUP_INF_COM_EXPIRY, "", szValue, sizeof(szValue), pszCacheFile);
+ cd.szExpireDate = _strdup(szValue);
+ GetPrivateProfileString(pszSection, SETUP_INF_COM_SECURITY, "", szValue, sizeof(szValue), pszCacheFile);
+ cd.szSecurity = _strdup(szValue);
+ cd.szTimeStamp = _strdup(getGMT());
+
+ myLogData("In DSINST_ReadComponentInf: name=%s nick=%s version=%s build=%s "
+ "rev=%s time=%s",
+ cd.szName, cd.szNickname, cd.szVersion, cd.szBuildNumber, cd.szRevision,
+ cd.szTimeStamp);
+ return TRUE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// run_cgi
+//
+//
+// runs a cgi
+//
+//
+//
+//
+//
+
+static int
+run_cgi(const char *serverroot, const char *cgipath, const char *args)
+{
+ int status = 0;
+ DWORD procResult;
+ DWORD dwLastError = 0;
+ char prog[MAX_STR_SIZE] = {0};
+ char cmdLine[MAX_STR_SIZE] = {0};
+ char netsiteRootEnvVar[MAX_STR_SIZE] = {0};
+ LPVOID lpMsgBuf;
+
+ sprintf(netsiteRootEnvVar, "NETSITE_ROOT=%s", serverroot);
+ _putenv(netsiteRootEnvVar);
+ if ( getenv("DEBUG_DSINST") )
+ DebugBreak();
+ /* everything is set, start the program */
+ sprintf(prog, "%s\\%s", serverroot, cgipath);
+ if (!FileExists(prog))
+ {
+ lpMsgBuf = getLastErrorMessage();
+
+ DSMessageBoxOK(ERR_NO_FIND_INST_PROG_TITLE,
+ ERR_NO_FIND_INST_PROG, 0, prog, lpMsgBuf, LOGFILE);
+
+
+ status = -1;
+ myLogData("Error: could not find program %s: %d (%s)", prog, GetLastError(), lpMsgBuf);
+ LocalFree( lpMsgBuf );
+ }
+ else
+ {
+ sprintf(cmdLine, "\"%s\" %s", prog, args);
+
+ myLogData("run_cgi: before execution of %s", cmdLine);
+ if ( (procResult = _LaunchAndWait(cmdLine, INFINITE)) != 0)
+ {
+ dwLastError = GetLastError();
+ lpMsgBuf = getLastErrorMessage();
+
+ myLogData("Error: could not run %s: %d (%s)", cmdLine, dwLastError, lpMsgBuf);
+ if(0 == dwLastError)
+ {
+ DSMessageBoxOK(ERR_EXEC_INST_PROG_TITLE, ERR_UNK_INST_CREATE, 0,
+ prog, LOGFILE);
+ }else {
+ DSMessageBoxOK(ERR_EXEC_INST_PROG_TITLE, ERR_EXEC_INST_PROG, 0,
+ prog, lpMsgBuf, LOGFILE);
+ }
+
+ LocalFree( lpMsgBuf );
+ status = -1;
+ }
+ myLogData("run_cgi: after execution of %s", cmdLine);
+ }
+
+ return status;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// create_slapd_instance
+//
+//
+// creates a instance of slapd
+//
+//
+//
+//
+//
+
+
+static int
+create_slapd_instance(const char *hostname, const char *serverroot)
+{
+ int status = 0;
+ char INFfile[MAX_STR_SIZE] = {0};
+ char debugFile[MAX_STR_SIZE] = {0};
+ struct _stat statbuf;
+ static char contentLength[100] = {0};
+ static char admservRoot[MAX_STR_SIZE] = {0};
+ static char serverUrl[MAX_STR_SIZE] = {0};
+ static char scriptName[MAX_STR_SIZE] = {0};
+ char szCGIArgs[MAX_STR_SIZE]= {0};
+ LPVOID lpMsgBuf;
+
+ /* create an .inf file to pass to index */
+ /* write the data to a temp file */
+ sprintf(INFfile, "%s\\temp%d.inf", TEMPDIR, _getpid());
+ myLogData("create_slapd_instance: inf file is %s", INFfile);
+
+ if (TRUE == (status = writeINFfile(INFfile)) )
+ {
+ if (status = _stat(INFfile, &statbuf))
+ {
+ lpMsgBuf = getLastErrorMessage();
+ DSMessageBoxOK(ERR_NO_STAT_TMP_FILE_TITLE,
+ ERR_NO_STAT_TMP_FILE, 0, INFfile, lpMsgBuf);
+
+ LocalFree(lpMsgBuf);
+ }
+ else
+ {
+ /* set temp file for admin output */
+ sprintf(debugFile, "DEBUG_FILE=%s\\debug.%d", TEMPDIR, _getpid());
+ _putenv(debugFile);
+ sprintf(szCGIArgs, "\"%s\\bin\\slapd\\admin\\bin\\Install.pl\"",
+ serverroot);
+ if (mi.m_nReInstall)
+ {
+ strcat(szCGIArgs, " -r -f ");
+ /* add the -r flag if reinstalling */
+ } else
+ {
+ strcat(szCGIArgs, " -f ");
+ }
+ strcat(szCGIArgs, "\"");
+ strcat(szCGIArgs, INFfile);
+ strcat(szCGIArgs, "\"");
+ myLogData("create_slapd_instance: executing %s %s",
+ PERL_EXE, szCGIArgs);
+ status = run_cgi(serverroot, PERL_EXE, szCGIArgs);
+ }
+ }
+
+ if (!getenv("USE_LOGFILE"))
+ _unlink(INFfile);
+
+ return status;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// generate_mcc_bat
+//
+// make bat file with correct classpath, and host/port to start console
+//
+//
+
+int generate_mcc_bat()
+{
+
+ FILE *fp;
+ CHAR szFilename[MAX_STR_SIZE];
+ CHAR szJavaDir[MAX_STR_SIZE];
+ INT rc = 0;
+
+ // don't generate the file unless asked
+ if (!getenv("GENERATE_MCC_BAT")) {
+ return rc;
+ }
+
+ sprintf(szFilename, "%s\\%s-%s\\mcc.bat", TARGETDIR, DS_ID_SERVICE,
+ mi.m_szServerIdentifier);
+ fp = fopen(szFilename, "wb");
+ if (!fp)
+ {
+ DSMessageBoxOK(ERR_NO_CREATE_FILE_TITLE,
+ ERR_NO_CREATE_FILE, 0, szFilename);
+ rc = -1;
+ }else{
+ sprintf(szJavaDir, "%s\\java", TARGETDIR);
+
+ fprintf(fp, "pushd \"%s\"\n", szJavaDir);
+
+ /* use jre */
+ fprintf(fp, "%s\\jre\\bin\\jre.exe -cp ", TARGETDIR);
+
+ /* classes for classpath -cp option on jre */
+ fprintf(fp, "%s\\ds50.jar;", szJavaDir);
+ fprintf(fp, "%s\\ds50_en.jar;", szJavaDir);
+ fprintf(fp, "%s\\admserv45.jar;", szJavaDir);
+ fprintf(fp, "%s\\admserv45_en.jar;", szJavaDir);
+ fprintf(fp, "%s\\mcc45.jar;", szJavaDir);
+ fprintf(fp, "%s\\mcc45_en.jar;", szJavaDir);
+ fprintf(fp, "%s\\ldapjdk.jar;", szJavaDir);
+ fprintf(fp, "%s\\nmclf45.jar;", szJavaDir);
+ fprintf(fp, "%s\\nmclf45_en.jar;", szJavaDir);
+ fprintf(fp, "%s\\ssl.zip;", szJavaDir);
+ fprintf(fp, "%s\\base.jar;", szJavaDir);
+ fprintf(fp, "%s ", szJavaDir);
+
+ /* command and arguments to execute the console for this server */
+ fprintf(fp, "com.netscape.management.client.console.Console -d %s -p %d -b \"%s\"\n",
+ mi.m_szMCCHost, mi.m_nMCCPort, mi.m_szMCCSuffix);
+ fprintf(fp, "popd\n");
+
+ fclose(fp);
+
+ rc = 0;
+ }
+
+ return rc;
+
+}
+
+
+//
+// Generates bat file to install ldap ctrs, since have to be in the same directory to get .h file
+//
+
+
+int generate_install_ldapctrs_bat()
+{
+
+ FILE *fp;
+ CHAR szFilename[MAX_STR_SIZE];
+ INT rc = 0;
+
+ sprintf(szFilename, "%s\\%s", TARGETDIR, INSTALL_CTRS_BAT);
+ fp = fopen(szFilename, "wb");
+ if (!fp)
+ {
+ DSMessageBoxOK(ERR_NO_CREATE_FILE_TITLE,
+ ERR_NO_CREATE_FILE, 0, szFilename);
+ rc = -1;
+ }else{
+ fprintf(fp, "copy %s\\%s\\nsldapctr*.* %s\n",
+ TARGETDIR, BIN_SLAPD_INSTALL_BIN, WINSYSDIR);
+
+ fprintf(fp, "%s\\lodctr nsldapctrs.ini\n", WINSYSDIR);
+
+ fprintf(fp, "del %s\\nsldapctr*.*\n", WINSYSDIR);
+
+ fclose(fp);
+ rc = 0;
+ }
+
+ return rc;
+
+}
+
+
+//--------------------------------------------------------------------------//
+// Install perfmon //
+// Creates Registry keys and loads counters for permon etc //
+//--------------------------------------------------------------------------//
+BOOL _InstallPerfmon(char *szServerRoot)
+{
+ BOOL bReturn = FALSE;
+ HKEY hKey;
+ DWORD dwDisposition;
+ char szKey[MAX_PATH];
+ char szTemp[MAX_PATH];
+ int maxpath = MAX_PATH;
+ char *reg = REGSTR_PATH_SERVICES;
+ char *id = SVR_ID_SERVICE;
+ char *ver = SVR_VERSION;
+ char *key = KEY_PERFORMANCE;
+
+ wsprintf(szKey, "%s\\%s%s\\%s", REGSTR_PATH_SERVICES, SVR_ID_SERVICE, SVR_VERSION, KEY_PERFORMANCE);
+ if(RegCreateKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, "", REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDisposition) == ERROR_SUCCESS)
+ {
+ RegSetValueEx(hKey, "Open", 0, REG_SZ, PERF_OPEN_FUNCTION, lstrlen(PERF_OPEN_FUNCTION)+2);
+ RegSetValueEx(hKey, "Collect", 0, REG_SZ, PERF_COLLECT_FUNCTION, lstrlen(PERF_COLLECT_FUNCTION)+2);
+ RegSetValueEx(hKey, "Close", 0, REG_SZ, PERF_CLOSE_FUNCTION, lstrlen(PERF_CLOSE_FUNCTION)+2);
+ wsprintf(szTemp, "%s\\bin\\slapd\\server\\nsldapctr.dll", szServerRoot);
+ RegSetValueEx(hKey, "Library", 0, REG_SZ, szTemp, lstrlen(szTemp)+2);
+ RegCloseKey(hKey);
+
+ wsprintf(szTemp, "unlodctr %s%s", SVR_ID_SERVICE, SVR_VERSION);
+ _LaunchAndWait(szTemp, INFINITE);
+
+ generate_install_ldapctrs_bat();
+
+ wsprintf(szTemp, "%s\\%s", szServerRoot, INSTALL_CTRS_BAT);
+ _LaunchAndWait(szTemp, INFINITE);
+
+ DeleteFile(szTemp);
+
+ }
+
+
+
+ return(bReturn);
+}
+
+static void
+CopyAndDeleteKey(
+ HKEY srcBase, const char *srcName,
+ HKEY destBase, const char *destName
+)
+{
+ DWORD index = 0;
+ LONG retval = 0;
+ HKEY srcHKEY;
+ HKEY destHKEY;
+ char className[MAX_PATH+1] = {0};
+ DWORD classLen = MAX_PATH+1;
+ DWORD nKeys = 0, maxKeyLen = 0, maxClassLen = 0, nValues = 0,
+ maxValueNameLen = 0, maxValueDataLen = 0;
+ DWORD disposition = 0;
+
+ // open the source key
+ retval = RegOpenKey(srcBase, srcName, &srcHKEY);
+ if (retval != ERROR_SUCCESS) {
+ myLogError("CopyAndDeleteKey: could not open src key %s: ret = %d\n",
+ srcName, retval);
+ return;
+ }
+
+ // get the info from the old key
+ retval = RegQueryInfoKey(srcHKEY, className, &classLen, 0, &nKeys, &maxKeyLen,
+ &maxClassLen, &nValues, &maxValueNameLen,
+ &maxValueDataLen, 0, 0);
+ if (retval != ERROR_SUCCESS) {
+ myLogError("CopyAndDeleteKey: could not read src key info %s: ret = %d\n",
+ srcName, retval);
+ return;
+ }
+
+ // create the new key based on the info in the old key
+ retval = RegCreateKeyEx(destBase, destName, 0, className,
+ REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, 0,
+ &destHKEY, &disposition);
+ if (retval != ERROR_SUCCESS) {
+ myLogError("CopyAndDeleteKey: creating new key %s: ret = %d\n",
+ destName, retval);
+ return;
+ }
+
+ // copy all of the values from the old key to the new key
+ for (index = 0; index < nValues; ++index) {
+ DWORD valueNameLen = maxValueNameLen+1;
+ DWORD valueType = 0;
+ DWORD valueDataLen = maxValueDataLen+1;
+ char *valueName = calloc(1, valueNameLen);
+ char *valueData = calloc(1, valueDataLen);
+ retval = RegEnumValue(srcHKEY, index, valueName, &valueNameLen, 0,
+ &valueType, valueData, &valueDataLen);
+ if (retval == ERROR_SUCCESS) {
+ retval = RegSetValueEx(destHKEY, valueName, 0, valueType,
+ valueData, valueDataLen);
+ if (retval != ERROR_SUCCESS) {
+ myLogError("CopyAndDeleteKey: could not write value %s to key %s\n",
+ valueName, destName);
+ }
+ } else {
+ myLogError("CopyAndDeleteKey: could not read value %d:%s from key %s\n",
+ index, (valueName ? valueName : "null"), destName);
+ }
+ free(valueName);
+ free(valueData);
+ }
+
+ // copy all of the sub keys as well; since we're deleting keys as we go along,
+ // the actual nKeys will change
+ if (nKeys > 0) {
+ for (index = nKeys; index; --index) {
+ DWORD keyNameLen = maxKeyLen+1;
+ char *keyName = calloc(1, keyNameLen);
+ retval = RegEnumKey(srcHKEY, index-1, keyName, keyNameLen);
+ if (retval == ERROR_SUCCESS) {
+ CopyAndDeleteKey(srcHKEY, keyName, destHKEY, keyName);
+ } else {
+ myLogError("CopyAndDeleteKey: could not get key %d:%s of nKeys %d:"
+ "error %d\n", index-1, (keyName ? keyName : "null"),
+ nKeys, retval);
+ }
+ free(keyName);
+ }
+ }
+
+ // close the destination key
+ retval = RegCloseKey(destHKEY);
+ if (retval != ERROR_SUCCESS) {
+ myLogError("CopyAndDeleteKey: could not close dest key %s\n",
+ destName);
+ }
+
+ // close the source key
+ retval = RegCloseKey(srcHKEY);
+ if (retval != ERROR_SUCCESS) {
+ myLogError("CopyAndDeleteKey: could not close source key %s\n",
+ srcName);
+ }
+
+ // delete the source key
+ retval = RegDeleteKey(srcBase, srcName);
+ if (retval != ERROR_SUCCESS) {
+ myLogError("CopyAndDeleteKey: could not delete source key %s\n",
+ srcName);
+ }
+
+ return;
+}
+
+// This function will rename the registry keys from the old version to
+// the new version
+static void
+updateRegistryKeys(const char *oldVersion, const char *newVersion)
+{
+ char oldKey[MAX_PATH] = {0};
+ char newKey[MAX_PATH] = {0};
+ int retval = 0;
+ DWORD index = 0;
+ HKEY svrHKEY;
+ DWORD nKeys = 0;
+ DWORD maxKeyLen = 0;
+ char *ptr = 0;
+
+ // There are three places we need to change
+ // the first place is under
+ // HKEY_LOCAL_MACHINE\SOFTWARE\Netscape\Directory\oldVersion
+ // we need to change oldVersion to newVersion
+ sprintf(newKey, "%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT);
+ strcpy(oldKey, newKey);
+ if (ptr = strstr(oldKey, SVR_VERSION)) {
+ strncpy(ptr, oldVersion, strlen(oldVersion));
+ }
+
+ myLogData("updateRegistryKeys: copying %s to %s\n",
+ oldKey, newKey);
+ CopyAndDeleteKey(HKEY_LOCAL_MACHINE, oldKey, HKEY_LOCAL_MACHINE,
+ newKey);
+
+ // the second place is under
+ // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\slapdoldVersoin
+ // we need to change oldVersion to newVersion
+ sprintf(oldKey, "%s\\%s%s", KEY_SERVICES, PRODUCT_NAME,
+ oldVersion);
+ sprintf(newKey, "%s\\%s%s", KEY_SERVICES, PRODUCT_NAME,
+ SVR_VERSION);
+
+ CopyAndDeleteKey(HKEY_LOCAL_MACHINE, oldKey, HKEY_LOCAL_MACHINE,
+ newKey);
+
+ // the third place is under
+ // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\slapd-instance
+ // for each instance, we need to replace the DisplayName value with
+ // the new display name
+
+ // open the services key
+ retval = RegOpenKey(HKEY_LOCAL_MACHINE, KEY_SERVICES, &svrHKEY);
+
+ // get the info from the key
+ retval = RegQueryInfoKey(svrHKEY, 0, 0, 0, &nKeys, &maxKeyLen,
+ 0, 0, 0,
+ 0, 0, 0);
+ if (retval != ERROR_SUCCESS) {
+ myLogError("updateRegistryKeys: could not read info %s: ret = %d\n",
+ KEY_SERVICES, retval);
+ return;
+ }
+
+ // iterate the keys under Services
+ for (index = 0; index < nKeys; ++index) {
+ DWORD keyNameLen = maxKeyLen+1;
+ char *keyName = calloc(1, keyNameLen);
+ retval = RegEnumKey(svrHKEY, index, keyName, keyNameLen);
+ if (retval == ERROR_SUCCESS && keyName &&
+ !strncmp(keyName, PRODUCT_NAME, strlen(PRODUCT_NAME))) {
+ // read the DisplayName value from the key
+ HKEY key;
+ retval = RegOpenKey(svrHKEY, keyName, &key);
+ if (retval == ERROR_SUCCESS) {
+ DWORD type = REG_SZ;
+ char oldValue[MAX_PATH+1] = {0};
+ DWORD oldValueLen = MAX_PATH+1;
+ char *ptr = 0;
+
+ retval = RegQueryValueEx(key, "DisplayName", 0, &type,
+ oldValue, &oldValueLen);
+ // if the DisplayName contains the old version number . . .
+ if ((retval == ERROR_SUCCESS) &&
+ (ptr = strstr(oldValue, oldVersion))) {
+ // . . . replace it
+ strncpy(ptr, SVR_VERSION, strlen(SVR_VERSION));
+ retval = RegSetValueEx(key, "DisplayName", 0, type,
+ oldValue, oldValueLen);
+ if (retval != ERROR_SUCCESS) {
+ myLogError("updateRegistryKeys: could not set value %s "
+ "for key %s\n",
+ oldValue, keyName);
+ }
+ } else {
+ myLogError("updateRegistryKeys: could not read DisplayName"
+ "from key %s:%s\n", keyName, oldValue);
+ }
+ RegCloseKey(key);
+ } else {
+ myLogError("updateRegistryKeys: could not open service key %s\n",
+ keyName);
+ }
+ } else {
+ myLogError("updateRegistryKeys: could not get key %d:%s of nKeys %d:"
+ "error %d\n", index, (keyName ? keyName : "null"),
+ nKeys, retval);
+ }
+ free(keyName);
+ }
+
+ RegCloseKey(svrHKEY);
+
+ // finally, remove the old Uninstall string
+#define REG_UNINST "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\Netscape Server Family 4.0"
+ myLogData("Deleting key %s", REG_UNINST);
+ DeleteServerRegistryKey(HKEY_LOCAL_MACHINE, REG_UNINST);
+}
+
+// This function makes sure nsperl is installed and running before the main slapd
+// post install runs, which needs nsperl to run
+static BOOL
+NSPERLINST_PostInstall(VOID)
+{
+ BOOL bRC = TRUE;
+ char *p = 0;
+ char instDir[BUFSIZ] = {0};
+ char nsPerlPostInstall[MAX_PATH] = {0};
+ char infFile[MAX_PATH] = {0};
+ char srcPath[MAX_PATH] = {0};
+ char destPath[MAX_PATH] = {0};
+ char szCurrentDir[MAX_STR_SIZE] = {0};
+
+ if (GetCurrentDirectory(MAX_STR_SIZE, szCurrentDir) == 0) {
+ myLogError("NSPERLINST_PostInstall could not determine the current directory");
+ return FALSE;
+ }
+
+ // hack to work around potential bug in setupsdk . . .
+ SetCurrentDirectory("../slapd");
+ sprintf(infFile, "slapd.inf");
+ GetProductInfoStringWithTok(NSPERL_POST_INSTALL_PROG, "=", nsPerlPostInstall,
+ BUFSIZ, infFile);
+
+ p = strrchr(nsPerlPostInstall, '/');
+ if (!p)
+ p = strrchr(nsPerlPostInstall, '\\');
+ if (!p) {
+ // punt
+ myLogError("NSPERLINST_PostInstall: could not get the post install program %s"
+ " from the info file %s", nsPerlPostInstall, infFile);
+ return FALSE;
+ }
+
+ // get the RunPostInstall attribute from the inf; this is the name
+ // of the post install program
+ *p = 0; // p points at last dir sep in the path, so null it
+ sprintf(instDir, "%s\\%s", TARGETDIR, nsPerlPostInstall);
+ p++;
+
+ // change directory to the directory of the post install program and
+ // execute it
+ if (SetCurrentDirectory(instDir) == 0) {
+ myLogError("NSPERLINST_PostInstall: could not change directory to %s",
+ instDir);
+ return FALSE;
+ }
+
+ if (_LaunchAndWait(p, INFINITE) != 0) {
+ myLogError("NSPERLINST_PostInstall: could not run the nsperl post install"
+ " program %s from directory %s", p, instDir);
+
+ SetCurrentDirectory(szCurrentDir);
+ return FALSE;
+ }
+
+ SetCurrentDirectory(szCurrentDir);
+
+ sprintf(srcPath, "%s\\nsperl.exe", instDir);
+ sprintf(destPath, "%s\\%s", TARGETDIR, PERL_EXE);
+
+ if (FALSE == CopyFile(srcPath, destPath, FALSE)) { // FALSE to overwrite file if exists
+ myLogError("NSPERLINST_PostInstall: could not copy file %s to %s",
+ srcPath, destPath);
+ bRC = FALSE;
+ }
+
+ myLogData("Successfully installed nsPerl");
+ return bRC;
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// DSINST_PostInstall
+//
+// The framework calls this function to perform post-installation
+// configuration. Here you should set values in any product configuration
+// files, install services, add registry keys, start servers, and anything
+// else that can only be done once the binaries are layed down on the disk.
+// If the function succeeds return TRUE, otherwise return FALSE to indicate
+// an error.
+//
+
+BOOL __declspec(dllexport)
+DSINST_PostInstall(VOID)
+{
+ // TODO: Add code to perform configuration.
+ BOOL rc;
+
+ myLogData("DSINST_PostInstall: BEGIN");
+
+ rc = NSPERLINST_PostInstall();
+
+ /* install perfmon*/
+ _InstallPerfmon(TARGETDIR);
+
+ if (1 == mi.m_nReInstall )
+ {
+ myLogData("DSINST_PostInstall: doing a reinstall");
+ /* if the old version is not equal to the new version, we need to
+ update the various registry keys */
+ if (strcmp(oldVersion, SVR_VERSION)) {
+ updateRegistryKeys(oldVersion, SVR_VERSION);
+ }
+
+ /* turn servers back on */
+ ControlSlapdServers(TARGETDIR, TRUE, TRUE);
+
+ /* do any other ReInstall things here */
+ }
+
+ /*create slapd instance detects reinstall and calls index with -r */
+ myLogData("DSINST_PostInstall: before create_slapd_instance %s", mi.m_szInstanceHostName);
+ if (0 == create_slapd_instance(mi.m_szInstanceHostName, TARGETDIR) )
+ {
+ if ( 0 == generate_mcc_bat() )
+ {
+ rc = TRUE;
+ } else
+ {
+ DSMessageBoxOK(ERR_CREATE_MCC_BAT_TITLE, ERR_CREATE_MCC_BAT, 0);
+ rc = FALSE;
+ }
+ } else
+ {
+ DSMessageBoxOK(ERR_CREATE_DS_INSTANCE_TITLE, ERR_CREATE_DS_INSTANCE, 0);
+ rc = FALSE;
+ }
+
+ /* turn SNMP service back on if it was running */
+ if ( 1 == mi.m_nSNMPOn)
+ {
+ if ( 0 == ControlServer(SNMP_SERVICE, TRUE) )
+ {
+ /* complain but continue with install */
+ DSMessageBoxOK(ERR_SNMP_BAD_STARTUP_TITLE, ERR_SNMP_BAD_STARTUP, 0);
+ }
+ }
+
+ return rc;
+}
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+
+static BOOL RemoveSNMPValue(void)
+{
+
+ char line[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;
+
+ /* open registry key for Microsoft SNMP service */
+ sprintf(line, "%s\\%s", KEY_SERVICES, KEY_SNMP_SERVICE);
+ Result = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
+ line,
+ 0,
+ KEY_ALL_ACCESS,
+ &hServerKey);
+
+ /* if Microsoft SNMP Service is installed look
+ for slapd snmp value to remove */
+ if (Result == ERROR_SUCCESS)
+ {
+ 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++)
+ {
+ 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(!lstrcmp(value_data_buffer, line))
+ {
+ /* remove the value */
+ Result = RegDeleteValue(hServerKey, NumValuesBuf);
+ break;
+ }
+ }
+ }
+ }
+ RegCloseKey(hServerKey);
+
+ return (Result == ERROR_SUCCESS);
+}
+
+BOOL RemoveSNMPKeys(void)
+{
+
+ char line[MAX_PATH];
+ BOOL bRC = TRUE;
+
+ /* open registry key for Directory SNMP s */
+ memset(line, '\0', MAX_PATH);
+ sprintf(line, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT,
+ KEY_SNMP_CURRENTVERSION);
+
+ RegDeleteKey(HKEY_LOCAL_MACHINE, line);
+
+ memset(line, '\0', MAX_PATH);
+ sprintf(line, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT,
+ SNMP_SERVICE_NAME);
+
+ RegDeleteKey(HKEY_LOCAL_MACHINE, line);
+
+ return bRC;
+}
+
+
+BOOL RemovePerfMon(void)
+{
+
+ char szTemp[MAX_PATH];
+ BOOL bRC = TRUE;
+
+ // uninstall perfmon counters and keys
+ wsprintf(szTemp, "unlodctr %s%s", SVR_ID_SERVICE, SVR_VERSION);
+ _LaunchAndWait(szTemp, 10000);
+
+ wsprintf(szTemp, "%s\\%s%s\\%s", REGSTR_PATH_SERVICES,
+ SVR_ID_SERVICE, SVR_VERSION, KEY_PERFORMANCE);
+ RegDeleteKey(HKEY_LOCAL_MACHINE, szTemp );
+
+ wsprintf(szTemp, "%s\\%s%s", REGSTR_PATH_SERVICES,
+ SVR_ID_SERVICE, SVR_VERSION);
+ RegDeleteKey(HKEY_LOCAL_MACHINE, szTemp );
+
+ return bRC;
+}
+
+BOOL RemoveDirectoryRootKey()
+{
+ char line[MAX_PATH];
+ BOOL bRC = TRUE;
+
+ memset(line, '\0', MAX_PATH);
+ sprintf(line, "%s\\%s", KEY_SOFTWARE_NETSCAPE, DS_NAME_SHORT);
+
+ RegDeleteKey(HKEY_LOCAL_MACHINE, line);
+
+ return bRC;
+}
+
+static void
+_PumpMessage(HWND hwndMsgDlg)
+{
+ MSG msg;
+
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// ShutdownDialogProc
+//
+// winproc for status window users sees when trying to shutdown instance so
+// install doesn't appear to be hung
+//
+//
+
+
+BOOL CALLBACK ShutdownDialogProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
+{
+ int retval;
+
+ myLogData("ShutdownDialog Proc iMsg=%d wParam=%d lParam=%d", iMsg, wParam, lParam);
+
+ switch (iMsg)
+ {
+
+ case WM_INITDIALOG:
+ retval = SetWindowText(hwnd, dialogMessage);
+ myLogData("19 SetWindowText returns %d", retval);
+ if (!retval) myLogError("19 SetWindowText");
+ retval = SetDlgItemText(hwnd, IDC_STOPPING_SERVER_MESSAGE,
+ dialogMessage);
+ myLogData("20 SetDlgItemText returns %d", retval);
+ if (!retval) myLogError("20 SetDlgItemText");
+ myLogData("iMsg=%d WM_INITDIALOG=%d WM_CREATE=%d msg=%s",
+ iMsg, WM_INITDIALOG, WM_CREATE, dialogMessage);
+ return TRUE;
+
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ }
+
+ return FALSE;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// shutdownDialog
+//
+// thread proc for creating shutdown dialog acts as win main translating and
+// dispatching events
+//
+//
+
+
+void shutdownDialog(ShutdownArg *shutdownargs)
+{
+ CHAR dbg[MAX_STR_SIZE]="\0";
+ int retval;
+
+ dialogMessage = shutdownargs->pszServiceName;
+ myLogData("Before createDialog");
+ shutdownargs->hwnd = CreateDialog(mi.m_hModule,
+ MAKEINTRESOURCE(IDD_UNINSTALL_STATUS),
+ NULL,
+ ShutdownDialogProc);
+ myLogData("After createDialog");
+ if (shutdownargs->hwnd == NULL)
+ {
+ return;
+ }
+
+ CenterWindow(shutdownargs->hwnd);
+ retval = SetWindowText(shutdownargs->hwnd, dialogMessage);
+ myLogData("1 SetWindowText returns %d", retval);
+ retval = GetWindowText(shutdownargs->hwnd, dbg, MAX_STR_SIZE);
+ myLogData("GetWindowText string [%s] retval %d", dbg, retval);
+ retval = SetDlgItemText(shutdownargs->hwnd, IDC_STOPPING_SERVER_MESSAGE,
+ dialogMessage);
+ myLogData("3 SetDlgItemText returns %d", retval);
+ retval = UpdateWindow(shutdownargs->hwnd);
+ myLogData("5 UpdateWindow returns %d", retval);
+ retval = ShowWindow(shutdownargs->hwnd, SW_SHOWNORMAL);
+ myLogData("6 ShowWindow returns %d", retval);
+ retval = UpdateWindow(shutdownargs->hwnd);
+ myLogData("7 UpdateWindow returns %d", retval);
+ retval = SetWindowText(shutdownargs->hwnd, dialogMessage);
+ myLogData("8 SetWindowText returns %d", retval);
+ retval = GetWindowText(shutdownargs->hwnd, dbg, MAX_STR_SIZE);
+ myLogData("9 GetWindowText string [%s] retval %d", dbg, retval);
+ retval = UpdateWindow(shutdownargs->hwnd);
+ myLogData("10 retval=%d msg=%s\n", retval, dialogMessage);
+
+ _PumpMessage(shutdownargs->hwnd);
+}
+
+BOOL writeUninstINFfile(const char *filename,
+ const char *pszServerRoot,
+ const char *pszServiceName)
+{
+ FILE *fp = fopen(filename, "wb");
+ CHAR szHostName[MAX_STR_SIZE]="\0";
+
+ DSGetHostName(szHostName, MAX_STR_SIZE);
+
+ if (NULL == fp)
+ return FALSE;
+
+ // write section header
+ fprintf(fp, "[uninstall]\n");
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_FULL_MACHINE_NAME, szHostName);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SERVER_ROOT, pszServerRoot);
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SERVER_IDENTIFIER, pszServiceName);
+ fprintf(fp, "%s= %s\n", GLOBAL_INF_LDAP_HOST, GetLdapHost() );
+ fprintf(fp, "%s= %d\n", GLOBAL_INF_LDAP_PORT, GetLdapPort() );
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SUFFIX, GetLdapSuffix() );
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SERVER_ADMIN_ID, GetLdapUser() );
+ fprintf(fp, "%s= %s\n", SLAPD_KEY_SERVER_ADMIN_PWD, GetLdapPassword() );
+ fprintf(fp, "%s= %s\n", SLAPD_INSTALL_LOG_FILE_NAME, LOGFILE );
+
+ fclose(fp);
+
+ return TRUE;
+}
+
+//////////////////////////////
+//
+// try to turn a server instance on or off
+// displays dialog while doing so
+//
+//
+
+void ControlSlapdInstance(char *pszServiceName, BOOL bOn)
+{
+ INT shutdown_tries=0;
+ BOOL bServerRunning=0;
+ CHAR szLog[MAX_STR_SIZE]="\0";
+ CHAR szFormat[MAX_STR_SIZE]="\0";
+ ShutdownArg shutdownargs;
+ CHAR szMessage[MAX_STR_SIZE]="\0";
+ const CHAR *shortName = getShortName(pszServiceName);
+
+ myLogData("Begin ControlSlapdInstance");
+ if(bOn)
+ {
+ LoadString( mi.m_hModule, IDS_STARTING_SERVICE, szFormat, MAX_STR_SIZE);
+ }else{
+ LoadString( mi.m_hModule, IDS_STOPPING_SERVICE, szFormat, MAX_STR_SIZE);
+ }
+
+ sprintf(szMessage, szFormat, shortName);
+
+ myLogData(szMessage);
+ ZeroMemory(&shutdownargs, sizeof(shutdownargs));
+ /* strategy here is to try and turn on/off the server,
+ sometimes it may take more than the first try
+ if can't do it after N tries then give up
+ and warn user */
+
+ /* check for opposite of bOn (ie starting server bOn = true, check if its down = false) */
+ while ( shutdown_tries < MAX_SLAPD_SHUTDOWN_TRIES
+ && (bOn != (bServerRunning = isServiceRunning( pszServiceName ) ) ) )
+ {
+ /* try to turn of the server */
+ sprintf(szLog, szMessage);
+ LogData(NULL, szLog);
+ myLogData(szLog);
+
+ /* setup and launch thread to display window to user
+ so it doesn't think install is hung */
+ shutdownargs.pszServiceName = szMessage;
+ _beginthread(shutdownDialog, 0, &shutdownargs);
+
+ ControlServer( pszServiceName, bOn );
+
+ /* give it some time to shutdown */
+ /* unneeded? */
+
+ if(bOn)
+ {
+ LoadString( mi.m_hModule, IDS_WAIT_SERVICE_START, szFormat, MAX_STR_SIZE);
+ }else{
+ LoadString( mi.m_hModule, IDS_WAIT_SERVICE_STOP, szFormat, MAX_STR_SIZE);
+ }
+
+ sprintf(szLog, szFormat, shortName);
+ LogData(NULL, szLog);
+ myLogData(szLog);
+
+ Sleep(SLAPD_SHUTDOWN_TIME_MILLISECONDS);
+
+ shutdown_tries++;
+ }
+
+ if ((shutdown_tries > 0) && (shutdownargs.hwnd > 0))
+ {
+ SendMessage(shutdownargs.hwnd, WM_DESTROY, 0, 0);
+ }
+
+ if ( MAX_SLAPD_SHUTDOWN_TRIES == shutdown_tries)
+ {
+ /* check if it got it the last time */
+
+ /* it should be whatever user wanted in bOn at this point*/
+ if (bOn == (bServerRunning = isServiceRunning( pszServiceName ) ) )
+ {
+ /* warn user, ask if they want to continue */
+
+ if ( IDOK == DSMessageBox(MB_OKCANCEL, ERR_SLAPD_SHUTDOWN_TITLE,
+ ERR_SLAPD_SHUTDOWN, shortName, shortName) )
+ {
+
+ } else
+ {
+ UINT uExitCode = 1;
+ /* stevross: use ExitProcess until admin server provides us with
+ better way to exit framework and cleanup */
+ ExitProcess(uExitCode);
+ }
+
+ }
+
+ }
+ myLogData("End ControlSlapdInstance");
+}
+
+static void ConvertPasswordToPin(char *pszServerRoot, char *pszServiceName)
+{
+ CHAR szFormat[MAX_STR_SIZE*4]="\0";
+ CHAR szCurrentDir[MAX_STR_SIZE]="\0";
+ CHAR szNewDir[MAX_STR_SIZE]="\0";
+
+ myLogData("Begin ConvertPasswordToPin");
+
+ /* get current dir so we have it for later */
+ if (GetCurrentDirectory(MAX_STR_SIZE, szCurrentDir) == 0)
+ {
+ myLogData("ConvertPasswordToPin: could not get current directory: %d",
+ GetLastError());
+ return;
+ }
+ /* have to be in the alias directory to run this */
+ sprintf(szNewDir, "%s\\alias", pszServerRoot);
+ /* change current dir to the alias directory */
+ if (SetCurrentDirectory(szNewDir) == 0)
+ {
+ myLogData("ConvertPasswordToPin: could not set current directory to %s: %d",
+ szNewDir, GetLastError());
+ return;
+ }
+
+ /* spawn the perl script which does the conversion */
+ sprintf(szFormat, "\"%s\\bin\\slapd\\admin\\bin\\migratePwdFile\" \"%s\" %s",
+ pszServerRoot, pszServerRoot, pszServiceName);
+ run_cgi(pszServerRoot, PERL_EXE, szFormat);
+
+ if (SetCurrentDirectory(szCurrentDir) == 0)
+ {
+ myLogData("ConvertPasswordToPin: could not set current directory back to %s: %d",
+ szCurrentDir, GetLastError());
+ return;
+ }
+
+ myLogData("End ConvertPasswordToPin");
+}
+
+static void ReinstallUpgradeServer(char *pszServerRoot, char *pszServiceName)
+{
+ CHAR szFormat[MAX_STR_SIZE*4]="\0";
+ CHAR szCurrentDir[MAX_STR_SIZE]="\0";
+
+ myLogData("Begin ReinstallUpgradeServer");
+
+ /* get current dir so we have it for later */
+ if (GetCurrentDirectory(MAX_STR_SIZE, szCurrentDir) == 0)
+ {
+ myLogData("ReinstallUpgradeServer: could not get current directory: %d",
+ GetLastError());
+ return;
+ }
+ /* have to be in the server root directory to run this */
+ if (SetCurrentDirectory(pszServerRoot) == 0)
+ {
+ myLogData("ReinstallUpgradeServer: could not set current directory to %s: %d",
+ pszServerRoot, GetLastError());
+ return;
+ }
+
+ /* spawn the perl script which does the conversion */
+ sprintf(szFormat, "\"%s\\bin\\slapd\\admin\\bin\\upgradeServer\" \"%s\" %s",
+ pszServerRoot, pszServerRoot, pszServiceName);
+ run_cgi(pszServerRoot, PERL_EXE, szFormat);
+
+ if (SetCurrentDirectory(szCurrentDir) == 0)
+ {
+ myLogData("ReinstallUpgradeServer: could not set current directory back to %s: %d",
+ szCurrentDir, GetLastError());
+ return;
+ }
+
+ myLogData("End ReinstallUpgradeServer");
+}
+
+BOOL RemoveSlapdInstance(LPCSTR pszServerRoot, char *pszServiceName)
+{
+ int status = 0;
+ char szINFfile[MAX_STR_SIZE] = "\0";
+ CHAR szCGIArgs[MAX_STR_SIZE]="\0";
+
+
+ /* try to turn of service */
+ ControlSlapdInstance(pszServiceName, FALSE);
+
+ /* now try to remove the instance */
+
+ /* call remove cgi with inf */
+ sprintf(szINFfile, "%s/unin%d.inf", TEMPDIR, _getpid());
+ writeUninstINFfile( szINFfile, pszServerRoot, pszServiceName);
+ sprintf(szCGIArgs, " -f \"%s\"", szINFfile);
+
+ /* remove this instance */
+ status = run_cgi(pszServerRoot, "bin\\slapd\\admin\\bin\\ds_remove.exe", szCGIArgs);
+
+ /* remove temp inffile */
+ _unlink(szINFfile);
+
+ return (status == 0); /* return true if run_cgi succeeded */
+}
+
+
+BOOL RemoveMiscRegistryEntries(void)
+{
+ BOOL bRC = TRUE;
+
+
+ RemoveSNMPKeys();
+ RemoveSNMPValue();
+
+ return bRC;
+}
+
+BOOL RemoveMiscSlapdFiles(pszServerRoot)
+{
+
+ char *miscFilesList[] =
+ {
+ "dsgw",
+ "plugins\\slapd",
+ "plugins\\snmp\\netscape-ldap.mib",
+ "bin\\slapd",
+ "manual\\slapd",
+ "relnotes.gif",
+ "relnotes.html",
+ "slapd.txt",
+ "unsynch.exe",
+ "mcc.bat",
+ "authdb",
+ "setup\\slapd",
+ "ldap.info",
+ NULL
+ };
+
+ int i;
+
+ CHAR szFileName[MAX_STR_SIZE];
+
+ for(i=0; miscFilesList[i] != NULL; i++)
+ {
+ memset(szFileName, '\0', MAX_STR_SIZE);
+ sprintf(szFileName, "%s\\%s", pszServerRoot, miscFilesList[i] );
+ DeleteRecursively(szFileName);
+ }
+
+ return TRUE;
+ }
+
+//////////////////////////////////////////////////////////////////////////////
+// PreUninst
+//
+//
+// Do things before uninstalling like turn off the server
+//
+//
+//
+//
+
+BOOL __declspec(dllexport)
+DSINST_PreUnInstall(LPCSTR pszServerRoot)
+{
+ BOOL rc = TRUE;
+ BOOL snmpstatus;
+ WIN32_FIND_DATA fileData;
+ HANDLE hFileHandle;
+ CHAR szCurrentDir[MAX_STR_SIZE]="\0";
+
+ /* for now just turn of the one instance we install */
+ /* later look in directory for anything slapd- and turn that off */
+
+ /* stevross: do this here until decide what to do with
+ DeleteServerRegistryKeys in Remove Instance */
+
+ /* get current dir so we have it for later */
+ GetCurrentDirectory(MAX_STR_SIZE, szCurrentDir);
+
+ /* change current dir to server root */
+ SetCurrentDirectory(pszServerRoot);
+
+ /* Turn off SNMP Service if Running */
+ snmpstatus = getSNMPStatus();
+
+ /* remove SNMP keys and any other Misc stuff */
+ RemoveMiscRegistryEntries();
+
+ hFileHandle = FindFirstFile("slapd-*", &fileData);
+
+ if( INVALID_HANDLE_VALUE != hFileHandle)
+ {
+ rc = RemoveSlapdInstance(pszServerRoot, fileData.cFileName);
+ while(TRUE == FindNextFile(hFileHandle, &fileData) )
+ {
+ BOOL status = RemoveSlapdInstance(pszServerRoot, fileData.cFileName);
+ /* we want to report failure even if only 1 instance removal fails */
+ if (rc)
+ {
+ rc = status;
+ }
+ }
+ FindClose(hFileHandle);
+ }
+
+ /* turn SNMP service back on if it was running */
+ if (snmpstatus)
+ {
+ if( 1 == mi.m_nSNMPOn)
+ {
+ if( 0 == ControlServer(SNMP_SERVICE, TRUE) )
+ {
+ /* complain but continue with install */
+ DSMessageBoxOK(ERR_SNMP_BAD_STARTUP_TITLE,
+ ERR_SNMP_BAD_STARTUP, 0);
+ }
+ }
+ }
+
+ /* set back to previous current directory */
+ SetCurrentDirectory(szCurrentDir);
+
+ /* unfortunately, if we just return FALSE here, uninstall will continue
+ happily along, and ultimately remove the uninst.exe program which we
+ need to run again after we figure out what went wrong
+ So, we must exit here
+ */
+ if (!rc) {
+ DSMessageBoxOK(ERR_UNINSTALL_DS_TITLE,
+ ERR_UNINSTALL_DS, 0, LOGFILE);
+ ExitProcess(1);
+ }
+
+ return rc;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// PostUninst
+//
+//
+// Clean up registry keys etc
+//
+//
+//
+//
+BOOL __declspec(dllexport)
+DSINST_PostUnInstall(LPCSTR pszServerRoot)
+{
+
+ BOOL bRC = TRUE;
+
+ /* remove misc files */
+
+
+ RemovePerfMon();
+ RemoveMiscSlapdFiles(pszServerRoot);
+ RemoveDirectoryRootKey();
+
+ return bRC;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// DllMain
+//
+// The Windows DLL main entry point. Called upon loading the DLL into memory.
+// Perform all initialization in the DLL_PROCESS_ATTACH reason handler, and
+// release any resources that you have allocated in the DLL_PROCESS_DETACH
+// message handler. See the Windows SDK documentation for more information
+// on this function.
+//
+
+BOOL WINAPI
+DllMain(HANDLE hModule, ULONG ulReasonForCall, LPVOID lpReserved)
+{
+ switch (ulReasonForCall)
+ {
+ case DLL_PROCESS_ATTACH:
+ mi.m_hModule = hModule;
+ StartWSA();
+ initialize_module();
+
+ /* set default server settings */
+ set_default_ldap_settings();
+ break;
+ case DLL_PROCESS_DETACH:
+ break;
+ case DLL_THREAD_ATTACH:
+ break;
+ case DLL_THREAD_DETACH:
+ break;
+ }
+ return TRUE;
+}
+
+static void
+fixDN(char *dn)
+{
+ if (dn && *dn)
+ {
+ char *utf8dn = localToUTF8(dn);
+ char *localdn = NULL;
+ dn_normalize_convert(utf8dn);
+ localdn = UTF8ToLocal(utf8dn);
+ strcpy(dn, localdn);
+ nsSetupFree(utf8dn);
+ nsSetupFree(localdn);
+ }
+}
+
+static void
+fixURL(char *url)
+{
+ if (url && *url)
+ {
+ char host[MAX_STR_SIZE];
+ int port;
+ char base[MAX_STR_SIZE];
+ GetURLComponents(url, host, &port, base);
+ fixDN(base);
+ sprintf(url, "ldap://%s:%d/%s", host, port, base);
+ }
+}
+
+
+static void
+normalizeDNs()
+{
+ fixDN(mi.m_szMCCSuffix);
+ fixDN(mi.m_szUGSuffix);
+ fixDN(mi.m_szInstallDN);
+ fixDN(mi.m_szInstanceSuffix);
+ fixDN(mi.m_szInstanceUnrestrictedUser);
+ fixDN(mi.m_szSupplierDN);
+ fixDN(mi.m_szChangeLogSuffix);
+ fixDN(mi.m_szConsumerDN);
+ fixDN(mi.m_szConsumerBindAs);
+ fixDN(mi.m_szSupplierBindAs);
+ fixDN(mi.m_szConsumerRoot);
+ fixDN(mi.m_szSupplierRoot);
+ fixURL(mi.m_szLdapURL);
+ fixURL(mi.m_szUserGroupURL);
+}
+
+/*
+ Usage:
+ DSMessageBox(type, titleKey, msgKey, titlearg, msgarg1, ..., msgargN);
+*/
+int
+DSMessageBox(UINT type, UINT titleKey, UINT msgKey, const char *titlearg, ...)
+{
+ int retval = 0;
+ va_list ap;
+ CHAR msgFormat[MAX_STR_SIZE] = {0};
+ CHAR msg[MAX_STR_SIZE*2] = {0};
+ CHAR titleFormat[MAX_STR_SIZE] = {0};
+ CHAR title[MAX_STR_SIZE] = {0};
+
+ LoadString(mi.m_hModule, msgKey, msgFormat, MAX_STR_SIZE);
+ if (!msgFormat[0])
+ return retval;
+
+ if (titleKey >= 0)
+ LoadString(mi.m_hModule, titleKey, titleFormat, MAX_STR_SIZE);
+
+ va_start(ap, titlearg);
+ vsprintf(msg, msgFormat, ap);
+ va_end(ap);
+
+ LogData(NULL, msg);
+ myLogData(msg);
+ if (SILENTMODE != MODE)
+ {
+ if (titleFormat[0])
+ {
+ sprintf(title, titleFormat, titlearg);
+ retval = NsSetupMessageBox(NULL, msg, title, type);
+ }
+ else
+ retval = NsSetupMessageBox(NULL, msg, NULL, type);
+ }
+ else
+ {
+ retval = IDOK; /* force OK for silent mode */
+ }
+
+ return retval;
+}
+
+/*
+ Usage:
+ DSMessageBoxOK(titleKey, msgKey, titlearg, msgarg1, ..., msgargN);
+*/
+int
+DSMessageBoxOK(UINT titleKey, UINT msgKey, const char *titlearg, ...)
+{
+ int retval = 0;
+ va_list ap;
+ CHAR msgFormat[MAX_STR_SIZE] = {0};
+ CHAR msg[MAX_STR_SIZE*2] = {0};
+ CHAR titleFormat[MAX_STR_SIZE] = {0};
+ CHAR title[MAX_STR_SIZE] = {0};
+
+ LoadString(mi.m_hModule, msgKey, msgFormat, MAX_STR_SIZE);
+ if (!msgFormat[0])
+ return retval;
+
+ if (titleKey >= 0)
+ LoadString(mi.m_hModule, titleKey, titleFormat, MAX_STR_SIZE);
+
+ va_start(ap, titlearg);
+ vsprintf(msg, msgFormat, ap);
+ va_end(ap);
+
+ LogData(NULL, msg);
+ if (MODE != SILENTMODE)
+ {
+ if (titleFormat[0])
+ {
+ sprintf(title, titleFormat, titlearg);
+ retval = NsSetupMessageBox(NULL, msg, title, MB_OK);
+ }
+ else
+ retval = NsSetupMessageBox(NULL, msg, NULL, MB_OK);
+ }
+ else
+ {
+ myLogData(msg); /* log the message */
+ retval = IDOK; /* force true return if silent mode */
+ }
+
+ return retval;
+}
diff --git a/ldap/cm/newinstnt/dsinst.h b/ldap/cm/newinstnt/dsinst.h
new file mode 100644
index 00000000..0788a398
--- /dev/null
+++ b/ldap/cm/newinstnt/dsinst.h
@@ -0,0 +1,248 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+//////////////////////////////////////////////////////////////////////////////
+// dsinst.h - Netscape SuiteSpot Installation Plug-In Directory Server
+//
+//
+
+#ifndef __DSINST_H
+#define __DSINST_H
+
+
+
+#include <regparms.h>
+#include "libinst.h"
+
+extern __declspec(dllexport) DSINST_ReadComponentInf(LPCSTR pszCacheFile, LPCSTR pszSection);
+extern __declspec(dllexport) INT __cdecl DSINST_AskOptions(HWND hwndParent, INT nDirection);
+extern __declspec(dllexport) VOID __cdecl DSINST_GetSummary(LPSTR lpszSummary);
+extern __declspec(dllexport) BOOL __cdecl DSINST_WriteCacheGlobal(LPCSTR lpszCacheFileName, LPCSTR lpszSection);
+extern __declspec(dllexport) BOOL __cdecl DSINST_WriteCacheLocal(LPCSTR lpszCacheFileName, LPCSTR lpszSection);
+extern __declspec(dllexport) BOOL __cdecl DSINST_ReadCacheGlobal(LPCSTR lpszCacheFileName, LPCSTR lpszSection);
+extern __declspec(dllexport) BOOL __cdecl DSINST_ReadCacheLocal(LPCSTR lpszCacheFileName, LPCSTR lpszSection);
+extern __declspec(dllexport) BOOL __cdecl DSINST_PreInstall(LPCSTR lpszInstallPath);
+extern __declspec(dllexport) BOOL __cdecl DSINST_Install(void);
+extern __declspec(dllexport) BOOL __cdecl DSINST_PostInstall(void);
+extern __declspec(dllexport) BOOL __cdecl DSINST_PreUnInstall(LPCSTR pszServerRoot);
+extern __declspec(dllexport) BOOL __cdecl DSINST_PostUnInstall(LPCSTR pszServerRoot);
+
+/* no attr we add uses more the 5 */
+#define MAX_LDAP_ATTR_VALUES 5
+
+/* shutdown tries * shutdown time should == 10 minutes */
+#define MAX_SLAPD_SHUTDOWN_TRIES 2400
+#define SLAPD_SHUTDOWN_TIME_MILLISECONDS 15000
+
+/* stevross: GLOBAL_INF_ only here to speed integration until
+ admin header file gets updated */
+#define GLOBAL_INF_LDAP_INSTALL_DN "InstallationRootDN"
+
+#define LOCAL_INF_HOST "InstanceHost"
+#define LOCAL_INF_PORT "InstancePort"
+#define LOCAL_INF_SUFFIX "InstanceSuffix"
+#define LOCAL_INF_ROOTDN "RootDN"
+#define LOCAL_INF_ROOTDN_PASSWD "RootDNPwd"
+#define LOCAL_INF_CONFIG_SSPT "ConfigSspt"
+
+#define LOCAL_INF_CONFIG_CONSUMER_DN "ConfigConsumerDN"
+#define LOCAL_INF_SNMP_ON "SNMPServiceOn"
+#define NETSCAPEROOT "NetscapeRoot"
+
+/* for now admin wants suffix always to be o=netscaperoot,
+ have it defined here in case it changes */
+#define CONFIG_DIR_SUFFIX "o=netscaperoot"
+
+/* default settings */
+#define DEFAULT_UNRESTRICTED_USER "cn=Directory Manager"
+#define DEFAULT_SERVER_PORT 389
+#define DEFAULT_SECURITY_ON 0
+#define DEFAULT_CONFIG_SSPT 1
+#define DEFAULT_START_SERVER 1
+#define DEFAULT_LDAP_INSTALL_DN "ou=mcom.com, o=NetscapeRoot"
+#define DEFAULT_SSPT_USER "admin"
+#define DEFAULT_SUPPLIER_DN "cn=Replication Manager"
+#define DEFAULT_CHANGELOGDIR "logs\\changelogdb"
+#define DEFAULT_CHANGELOGSUFFIX "cn=changelog"
+#define DEFAULT_ADD_SAMPLE_ENTRIES 0
+#define DEFAULT_ADD_ORG_ENTRIES 0
+#define DEFAULT_SETUP_CONSUMER 0
+#define DEFAULT_CIR_HOST "\0"
+#define DEFAULT_CIR_PORT 389
+#define DEFAULT_CIR_SUFFIX "\0"
+#define DEFAULT_CIR_BINDDN "cn=Replication Consumer"
+#define DEFAULT_CIR_BINDDN_PWD "\0"
+#define DEFAULT_CIR_INTERVAL 10
+#define DEFAULT_CIR_DAYS "0123456"
+#define DEFAULT_CIR_TIMES "0000-2359"
+#define DEFAULT_REPLICATION_DN "cn=supplier"
+#define DEFAULT_REPLICATION_PWD "\0"
+#define DEFAULT_SETUP_SUPPLIER 0
+#define DEFAULT_SIR_HOST "\0"
+#define DEFAULT_SIR_PORT 389
+#define DEFAULT_SIR_SUFFIX "\0"
+#define DEFAULT_SIR_BINDDN "cn=supplier"
+#define DEFAULT_SIR_BINDDN_PWD "\0"
+#define DEFAULT_SIR_DAYS "0123456"
+#define DEFAULT_SIR_TIMES "0000-2359"
+#define DEFAULT_CONFIG_CONSUMER_DN 0
+#define DEFAULT_CONSUMER_DN "cn=Replication Consumer"
+#define DEFAULT_CONSUMER_PWD "\0"
+#define DEFAULT_INF_POP_LDIF_FILE "\0"
+#define DEFAULT_POPULATE_SAMPLE_ENTRIES 0
+#define DEFAULT_DISABLE_SCHEMA_CHECKING 0
+#define DEFAULT_SNMP_ON 0
+#define DEFAULT_ADMIN_PORT 80
+
+#define SUGGEST_LDIF "suggest"
+#define SAMPLE_LDIF "bin\\slapd\\install\\ldif\\Example.ldif"
+#define TEMPLATE_LDIF "bin\\slapd\\install\\ldif\\template.ldif"
+#define PROCESSED_TEMPLATE_LDIF "ldif\\sample-org.ldif"
+#define LDAP_MODIFY_EXE "bin\\slapd\\server\\ldapmodify.exe"
+#define INSTALL_CTRS_BAT "install-nsldapctrs.bat"
+#define BIN_SLAPD_INSTALL_BIN "bin\\slapd\\install\\bin"
+
+
+#define ROOT_DN "RootDN"
+#define ROOT_DN_PWD "RootDNPwd"
+#define SERVER_IDENTIFIER "ServerId"
+
+
+#define CONSUMER_REPL_AGREE "Consumer Replication Agreement"
+#define SUPPLIER_REPL_AGREE "Supplier Replication Agreement"
+#define SERVER_MIGRATION_CLASS "com.netscape.admin.dirserv.task.MigrateCreate"
+#define SERVER_CREATION_CLASS "com.netscape.admin.dirserv.task.MigrateCreate"
+
+#define NO_REPLICATION 3
+#define CONSUMER_SIR_REPLICATION 1
+#define CONSUMER_CIR_REPLICATION 2
+
+#define SUPPLIER_SIR_REPLICATION 1
+#define SUPPLIER_CIR_REPLICATION 2
+
+
+/// inf file stuff
+
+#define SETUP_INF_COM_VENDOR "Vendor"
+#define SETUP_INF_COM_DESC "Description"
+#define SETUP_INF_COM_NAME "Name"
+#define SETUP_INF_COM_NICKNAME "NickName"
+#define SETUP_INF_COM_VERSION "Version"
+#define SETUP_INF_COM_BUILDNUMBER "BuildNumber"
+#define SETUP_INF_COM_REVISION "Revision"
+#define SETUP_INF_COM_CREATIONDATE "CreationDate"
+#define SETUP_INF_COM_EXPIRY "Expires"
+#define SETUP_INF_COM_SECURITY "Security"
+
+#define SLAPD_MIN_PW_LEN 8
+#define SSPT_MIN_PW_LEN 1
+
+#define N_DAYS 8
+#define N_TIMES 10
+
+#define SNMP_SERVICE "SNMP"
+
+/* error messages */
+
+#define ASCII_ZERO 48
+
+typedef struct tagMODULEINFO {
+ HINSTANCE m_hModule;
+ HWND m_hwndParent;
+ INT m_nResult;
+ INT m_nReInstall;
+ CHAR *m_szMCCBindAs;
+ INT m_nInstanceServerPort;
+ INT m_nAdminServerPort;
+ INT m_nCfgSspt;
+ INT m_nPopulateSampleEntries;
+ INT m_nPopulateSampleOrg;
+ INT m_nSetupConsumerReplication;
+ INT m_nSetupSupplierReplication;
+ INT m_nMaxChangeLogRecords;
+ INT m_nMaxChangeLogAge;
+ INT m_nChangeLogAgeMagnitude;
+ INT m_nConsumerSSL;
+ INT m_nSupplierSSL;
+ INT m_nUseSupplierSettings;
+ INT m_nUseChangeLogSettings;
+ INT m_nCIRInterval;
+ INT m_nConsumerPort;
+ INT m_nSupplierPort;
+ INT m_nMCCPort;
+ INT m_nExistingMCC;
+ INT m_nUGPort;
+ INT m_nExistingUG;
+ INT m_nDisableSchemaChecking;
+ INT m_nSNMPOn;
+ INT m_nConfigConsumerDN;
+ CHAR m_szMCCPw[MAX_STR_SIZE];
+ CHAR m_szMCCHost[MAX_STR_SIZE];
+ CHAR m_szMCCSuffix[MAX_STR_SIZE];
+ CHAR m_szUGPw[MAX_STR_SIZE];
+ CHAR m_szUGHost[MAX_STR_SIZE];
+ CHAR m_szUGSuffix[MAX_STR_SIZE];
+ CHAR m_szAdminDomain[MAX_STR_SIZE];
+ CHAR m_szLdapURL[MAX_STR_SIZE];
+ CHAR m_szUserGroupURL[MAX_STR_SIZE];
+ CHAR m_szUserGroupAdmin[MAX_STR_SIZE];
+ CHAR m_szUserGroupAdminPW[MAX_STR_SIZE];
+ CHAR m_szInstallDN[MAX_STR_SIZE];
+ CHAR m_szSsptUid[MAX_STR_SIZE];
+ CHAR m_szSsptUidPw[MAX_STR_SIZE];
+ CHAR m_szSsptUidPwAgain[MAX_STR_SIZE];
+ CHAR m_szSsptUser[MAX_STR_SIZE];
+ CHAR m_szServerIdentifier[MAX_STR_SIZE];
+ CHAR m_szInstanceSuffix[MAX_STR_SIZE];
+ CHAR m_szInstanceUnrestrictedUser[MAX_STR_SIZE];
+ CHAR m_szInstancePassword[MAX_STR_SIZE];
+ CHAR m_szInstancePasswordAgain[MAX_STR_SIZE];
+ CHAR m_szInstanceHostName[MAX_STR_SIZE];
+ CHAR m_szSupplierDN[MAX_STR_SIZE];
+ CHAR m_szSupplierPW[MAX_STR_SIZE];
+ CHAR m_szSupplierPWAgain[MAX_STR_SIZE];
+ CHAR m_szSSLClients[MAX_STR_SIZE];
+ CHAR m_szChangeLogDbDir[MAX_STR_SIZE];
+ CHAR m_szChangeLogSuffix[MAX_STR_SIZE];
+ CHAR m_szConsumerDN[MAX_STR_SIZE];
+ CHAR m_szConsumerPW[MAX_STR_SIZE];
+ CHAR m_szConsumerPWAgain[MAX_STR_SIZE];
+ CHAR m_szConsumerHost[MAX_STR_SIZE];
+ CHAR m_szConsumerRoot[MAX_STR_SIZE];
+ CHAR m_szConsumerBindAs[MAX_STR_SIZE];
+ CHAR m_szConsumerPw[MAX_STR_SIZE];
+ CHAR m_szSupplierHost[MAX_STR_SIZE];
+ CHAR m_szSupplierRoot[MAX_STR_SIZE];
+ CHAR m_szSupplierBindAs[MAX_STR_SIZE];
+ CHAR m_szSupplierPw[MAX_STR_SIZE];
+ CHAR m_szPopLdifFile[MAX_STR_SIZE];
+ CHAR m_szCIRDays[N_DAYS];
+ CHAR m_szCIRTimes[N_TIMES];
+ CHAR m_szSIRDays[N_DAYS];
+ CHAR m_szSIRTimes[N_TIMES];
+} MODULEINFO;
+
+typedef struct tagINFDATA
+{
+ char* szVendor;
+ char* szDescription;
+ char* szName;
+ char* szNickname;
+ char* szVersion;
+ char* szBuildNumber;
+ char* szRevision;
+ char* szTimeStamp;
+ char* szExpireDate;
+ char* szSecurity;
+} INFDATA;
+
+typedef struct tagShutdownArgs
+{
+ HWND hwnd;
+ char* pszServiceName;
+
+} ShutdownArg;
+
+#endif // __DSINST_H
diff --git a/ldap/cm/newinstnt/dsinst.rc b/ldap/cm/newinstnt/dsinst.rc
new file mode 100644
index 00000000..a70c64a0
--- /dev/null
+++ b/ldap/cm/newinstnt/dsinst.rc
@@ -0,0 +1,710 @@
+//Microsoft Developer Studio generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (U.S.) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+#ifdef _WIN32
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+#endif //_WIN32
+
+#ifndef _MAC
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION 1,0,0,1
+ PRODUCTVERSION 1,0,0,1
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x2L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "Netscape\0"
+ VALUE "FileDescription", "Directory Server 7.0\0"
+ VALUE "FileVersion", "1, 0, 0, 1\0"
+ VALUE "InternalName", "Directory Server 7.0\0"
+ VALUE "LegalCopyright", "Copyright 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002 Netscape Communications Corporation. All rights reserved.\0"
+ VALUE "OriginalFilename", "\0"
+ VALUE "ProductName", "Netscape Server Products\0"
+ VALUE "ProductVersion", "7, 0, 0, 0\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
+
+#endif // !_MAC
+
+
+#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
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MCC_SETTINGS DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_EDIT_HOST,158,68,103,13,ES_AUTOHSCROLL | WS_DISABLED
+ EDITTEXT IDC_EDIT_PORT,158,86,29,13,ES_AUTOHSCROLL | WS_DISABLED
+ EDITTEXT IDC_EDIT_SUFFIX,158,140,103,13,ES_AUTOHSCROLL |
+ WS_DISABLED
+ EDITTEXT IDC_EDIT_BIND_AS,158,104,103,13,ES_AUTOHSCROLL |
+ WS_DISABLED
+ EDITTEXT IDC_EDIT_PW,158,122,103,13,ES_PASSWORD | ES_AUTOHSCROLL |
+ WS_DISABLED
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ LTEXT "Host:",IDC_STATIC_MCC_HOST,136,70,17,8
+ LTEXT "Port:",IDC_STATIC_MCC_PORT,137,88,16,8
+ LTEXT "Suffix:",IDC_STATIC_MCC_SUFFIX,130,142,23,8
+ LTEXT "Bind As:",IDC_STATIC_MCC_BIND_AS,126,106,27,8
+ LTEXT "Password:",IDC_STATIC_MCC_PW,117,124,36,8
+ GROUPBOX "Configuration Directory Server",IDC_STATIC_SETTINGS,91,
+ 37,191,121
+ CONTROL "This instance will be the configuration directory server",
+ IDC_RADIO_USE_THIS_SERVER,"Button",BS_AUTORADIOBUTTON,97,
+ 47,184,10
+ CONTROL "Use existing configuration directory server",
+ IDC_RADIO_USE_EXISTING_SERVER,"Button",
+ BS_AUTORADIOBUTTON,97,57,165,10
+ LTEXT "Netscape server information is stored in the Netscape configuration directory server, which you may have already set up. If so, you should configure this server to be managed by the configuration server.",
+ IDC_STATIC_DESC,92,3,172,33
+END
+
+IDD_ROOTDN DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Directory Manager Settings"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ EDITTEXT IDC_EDIT_UNRESTRICTED_USER,168,74,112,14,ES_AUTOHSCROLL
+ LTEXT "Directory Manager DN:",IDC_STATIC_UNRESTRICTED_USER,88,
+ 74,73,8
+ LTEXT "Password:",IDC_STATIC_PASSWORD,88,96,34,8
+ EDITTEXT IDC_EDIT_PASSWORD,168,96,112,14,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ LTEXT "Password (again):",IDC_STATIC_PASSWORD_AGAIN,88,119,57,
+ 8
+ EDITTEXT IDC_EDIT_PASSWORD_AGAIN,168,119,111,14,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ GROUPBOX "Directory Manager Settings",
+ IDC_STATIC_UNRESTRICTED_USER_GROUPBOX,84,58,203,84
+ LTEXT "Certain directory server operations require an administrative user. This user is referred to as the Directory Manager and typically has a bind Distinguished Name (DN) of cn=Directory Manager.",
+ IDC_STATIC_DM_DESC,84,11,202,26
+ LTEXT "The password for the Directory Manager must be at least 8 characters long.",
+ IDC_STATIC,84,39,202,18
+END
+
+IDD_SUITESPOTID DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION
+"Directory Server 7.0 Netscape configuration directory server administrator "
+
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ EDITTEXT IDC_EDIT_SUITESPOT_USER,173,51,114,14,ES_AUTOHSCROLL
+ LTEXT "Configuration Directory Administrator ID:",
+ IDC_STATIC_SUITESPOT_USER,94,51,73,17
+ LTEXT "Password:",IDC_STATIC_PASSWORD,94,74,34,8
+ EDITTEXT IDC_EDIT_PASSWORD,173,74,114,14,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ LTEXT "Password (again):",IDC_STATIC_PASSWORD_AGAIN,94,97,57,8
+ EDITTEXT IDC_EDIT_PASSWORD_AGAIN,173,97,114,14,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ GROUPBOX "Configuration Directory Server Administrator ",
+ IDC_STATIC_SUITESPOT_ADMIN_GROUPBOX,88,35,204,91
+ LTEXT "The Netscape configuration directory administrator is the ID typically used to log in to the console.",
+ IDC_STATIC_MCA_DESC,88,10,196,18
+END
+
+IDD_SERVER_SETTINGS DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Server Settings"
+FONT 8, "MS Sans Serif"
+BEGIN
+ GROUPBOX "General Settings",IDC_STATIC_GENERAL_SETTINGS,97,33,194,
+ 68
+ EDITTEXT IDC_EDIT_SERVER_IDENTIFIER,175,46,105,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_EDIT_SERVER_PORT,175,62,35,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_EDIT_SUFFIX,175,78,105,12,ES_AUTOHSCROLL
+ CONTROL "Spin1",IDC_SPIN_SERVER_PORT,"msctls_updown32",
+ UDS_SETBUDDYINT | UDS_ARROWKEYS | UDS_NOTHOUSANDS,209,62,
+ 10,12
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ LTEXT "Server Identifier:",IDC_STATIC_SERVER_IDENTIFIER,116,46,
+ 52,8
+ LTEXT "Server Port: ",IDC_STATIC_SERVER_PORT,129,62,39,8
+ LTEXT "Suffix: ",IDC_STATIC_SUFFIX,146,78,22,8
+ LTEXT "Settings this directory server will use for basic operation.",
+ IDC_STATIC_SERV_SETTINGS_DESC,103,20,180,10
+END
+
+IDD_SAMPLE_ENTRIES_ORG DIALOG DISCARDABLE 0, 0, 377, 179
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Populate Database"
+FONT 8, "MS Sans Serif"
+BEGIN
+ GROUPBOX "Sample Organizational Structure",
+ IDC_STATIC_DEFAULT_ORG_GROUP,89,5,285,50
+ CONTROL "Install Sample Organizational Structure",
+ IDC_CHECK_POPULATE_ORG_ENTRIES,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,104,41,146,10
+ GROUPBOX "Populate Database",IDC_STATIC_SAMPLE_GROUP,89,64,285,95
+ CONTROL "Don't Populate",IDC_RADIO_DONT_POPULATE,"Button",
+ BS_AUTORADIOBUTTON | WS_GROUP,96,93,63,10
+ CONTROL "Populate with sample database",
+ IDC_RADIO_POPULATE_SAMPLE,"Button",BS_AUTORADIOBUTTON,96,
+ 102,114,11
+ CONTROL "Populate with custom database",
+ IDC_RADIO_POPULATE_CUSTOM,"Button",BS_AUTORADIOBUTTON,96,
+ 112,115,10
+ PUSHBUTTON "Browse",IDC_BUTTON_CHOOSE_LDIF_FILE,96,130,51,14,
+ WS_GROUP
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,176
+ LTEXT "Populate the new directory server instance with some commonly used organizational entries, to provide some default structure to the directory.",
+ IDC_STATIC_ORG_ENTRIES,96,15,180,26
+ LTEXT "(must have base )",IDC_STATIC_MUST_HAVE_BASE,106,121,
+ 154,8
+ LTEXT "File:",IDC_STATIC_FILE_NAME_COLON,96,146,15,10
+ LTEXT "",IDC_STATIC_LDIF_FILE_NAME,96,146,188,9
+ LTEXT "You may choose at this time to populate the database with an LDIF file or create a sample database.",
+ IDC_STATIC,96,75,186,17
+END
+
+IDD_CONSUMER_REPLICATION_SETTINGS DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Consumer Replication Settings"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ LTEXT "In order to allow remote servers to replicate new entries to this server, the remote server must have the ability to bind to this server as some entity with permission to do so. ",
+ IDC_STATIC_CIR_DESCRIPTION,93,7,186,24
+ LTEXT "Supplier Bind DN:",IDC_STATIC_SUPPLIER_DN,97,80,71,8
+ LTEXT "Supplier Password:",IDC_STATIC_SUPPLIER_PW,97,96,61,8
+ LTEXT "Supplier Password (again):",IDC_STATIC_SUPPLIER_PW2,97,
+ 112,86,11
+ EDITTEXT IDC_EDIT_SUPPLIER_DN,188,80,95,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_EDIT_PASSWORD,188,96,95,12,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ EDITTEXT IDC_EDIT_PASSWORD_AGAIN,188,112,95,12,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ GROUPBOX "Consumer Server Replication Settings",IDC_CONSUMER,90,
+ 62,201,66
+ LTEXT "The Supplier DN is the DN of the entity the remote server will use to connect to this server to supply updates.",
+ IDC_STATIC_CIR_DESCRIPTION2,93,36,186,16
+END
+
+IDD_SUPPLIER_REPLICATION_SETTINGS DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Supplier Replication Settings"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ LTEXT "Settings which configure this server to send replication updates to other servers.",
+ IDC_STATIC_SIR_DESCRIPTION,91,13,186,17
+ LTEXT "Changelog DB Directory:",IDC_STATIC_CHANGELOG_DB_DIR,91,
+ 55,79,8
+ LTEXT "Changelog Suffix:",IDC_STATIC_CHANGELOG_SUFFIX,91,74,56,
+ 8
+ EDITTEXT IDC_EDIT_CHANGELOG_DB_DIR,182,55,95,12,ES_AUTOHSCROLL
+ EDITTEXT IDC_EDIT_CHANGELOG_DB_SUFFIX,182,73,95,12,ES_AUTOHSCROLL
+ GROUPBOX "Supplier Server Replication Settings",
+ IDC_SIR_DESCRIPTION,83,40,201,55
+END
+
+IDD_CONSUMER_DN DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Consumer DN Settings "
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ EDITTEXT IDC_EDIT_CONSUMER_DN,163,77,111,14,ES_AUTOHSCROLL
+ LTEXT "Consumer Bind DN:",IDC_STATIC_CONSUMER_DN,90,77,67,8
+ LTEXT "Password:",IDC_STATIC_CONSUMER_PW,90,100,36,8
+ EDITTEXT IDC_EDIT_PASSWORD,163,100,111,14,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ LTEXT "Password (again):",IDC_STATIC_PASSWORD_AGAIN,90,123,57,
+ 8
+ EDITTEXT IDC_EDIT_PASSWORD_AGAIN,163,123,112,14,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ GROUPBOX "Supplier CIR Replication Settings",
+ IDC_STATIC_SUPPLIER_CIR,84,59,208,89
+ LTEXT "Do you wish to create an entry which can be used by CIR Consumers to bind to this Supplier? \nNote: This user will have acess to the entire database as well as the changelog.",
+ IDC_STATIC,84,5,206,32
+ CONTROL "Yes",IDC_RADIO_CONFIG_CONSUMER_DN_YES,"Button",
+ BS_AUTORADIOBUTTON,149,45,28,10
+ CONTROL "No",IDC_RADIO_CONFIG_CONSUMER_DN_NO,"Button",
+ BS_AUTORADIOBUTTON,181,45,25,10
+END
+
+IDD_REPLICATION_AGREEMENT DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Configure Replication Agreement"
+FONT 8, "MS Sans Serif"
+BEGIN
+ EDITTEXT IDC_EDIT_HOST,159,13,80,13,ES_AUTOHSCROLL
+ EDITTEXT IDC_EDIT_PORT,159,30,24,13,ES_AUTOHSCROLL
+ EDITTEXT IDC_EDIT_SUFFIX,159,48,80,13,ES_AUTOHSCROLL
+ EDITTEXT IDC_EDIT_BIND_AS,159,65,80,13,ES_AUTOHSCROLL
+ EDITTEXT IDC_EDIT_PW,159,82,80,13,ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ LTEXT "Host:",IDC_STATIC_REPLICATION_HOST,137,13,18,8
+ LTEXT "Port:",IDC_STATIC_REPLICATION_PORT,139,30,16,8
+ LTEXT "Root of Replication:",IDC_STATIC_REPLICATION_ROOT,91,48,
+ 64,8
+ LTEXT "Bind As:",IDC_STATIC_REPLICATION_BIND_AS,128,65,27,8
+ LTEXT "Password:",IDC_STATIC_REPLICATION_PW,119,82,34,8
+ GROUPBOX "Replication Agreement",IDC_STATIC_REPLICATION_AGREEMENT,
+ 84,2,207,155
+ GROUPBOX "Replication Days",IDC_STATIC_REPL_DAYS,90,93,197,22
+ CONTROL "Sun",IDC_CHECK_SUN,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,92,102,25,10
+ CONTROL "Mon",IDC_CHECK_MON,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,119,102,28,10
+ CONTROL "Tue",IDC_CHECK_TUE,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,147,102,25,10
+ CONTROL "Wed",IDC_CHECK_WED,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,173,102,27,10
+ CONTROL "Thur",IDC_CHECK_THUR,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,201,102,27,10
+ CONTROL "Fri",IDC_CHECK_FRI,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,229,102,25,10
+ CONTROL "Sat",IDC_CHECK_SAT,"Button",BS_AUTOCHECKBOX |
+ WS_TABSTOP,254,102,25,10
+ GROUPBOX "Replication Times",IDC_STATIC,89,117,83,37
+ LTEXT "Start:",IDC_STATIC_REPL_START_TIME,95,126,16,8
+ EDITTEXT IDC_EDIT_REPL_START_TIME_HH,113,126,15,12,ES_AUTOHSCROLL
+ LTEXT "End:",IDC_STATIC_REPL_END_TIME,95,140,16,8
+ EDITTEXT IDC_EDIT_REPL_END_TIME_HH,113,140,15,12,ES_AUTOHSCROLL
+ CONTROL "Spin1",IDC_SPIN_REPL_START_TIME_MM,"msctls_updown32",
+ UDS_WRAP | UDS_SETBUDDYINT | UDS_ARROWKEYS,155,126,10,12
+ EDITTEXT IDC_EDIT_REPL_SYNC_INTERVAL,238,126,25,12,ES_AUTOHSCROLL
+ LTEXT "Replication Sync Interval(minutes)",
+ IDC_STATIC_REPL_SYNC,182,126,55,17
+ CONTROL "Spin1",IDC_SPIN_REPL_SYNC_INTERVAL,"msctls_updown32",
+ UDS_WRAP | UDS_SETBUDDYINT | UDS_ARROWKEYS,262,126,11,11
+ EDITTEXT IDC_EDIT_REPL_START_TIME_MM,141,126,15,12,ES_AUTOHSCROLL
+ CONTROL "Spin1",IDC_SPIN_REPL_START_TIME_HH,"msctls_updown32",
+ UDS_WRAP | UDS_SETBUDDYINT | UDS_ARROWKEYS,128,126,11,12
+ CONTROL "Spin1",IDC_SPIN_REPL_END_TIME_HH,"msctls_updown32",
+ UDS_WRAP | UDS_SETBUDDYINT | UDS_ARROWKEYS,128,140,11,12
+ EDITTEXT IDC_EDIT_REPL_END_TIME_MM,141,140,15,12,ES_AUTOHSCROLL
+ CONTROL "Spin1",IDC_SPIN_REPL_END_TIME_MM,"msctls_updown32",
+ UDS_WRAP | UDS_SETBUDDYINT | UDS_ARROWKEYS,155,140,11,12
+END
+
+IDD_CHOOSE_REPLICATION_SETUP DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Configure Server for Replication"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL "A Consumer that will pull updates",
+ IDC_RADIO_CONSUMER_CIR,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,119,117,125,9
+ CONTROL "A Consumer that will have updates",
+ IDC_RADIO_CONSUMER_SIR,"Button",BS_AUTORADIOBUTTON,119,
+ 95,127,10
+ CONTROL "Do not configure as a Consumer",
+ IDC_RADIO_NO_CONSUMER_REPLICATION,"Button",
+ BS_AUTORADIOBUTTON,119,138,113,10
+ CONTROL "A Supplier that will have updates",
+ IDC_RADIO_SUPPLIER_CIR,"Button",BS_AUTORADIOBUTTON |
+ WS_GROUP,118,42,122,10
+ CONTROL "A Supplier that will push updates",
+ IDC_RADIO_SUPPLIER_SIR,"Button",BS_AUTORADIOBUTTON,118,
+ 20,121,10
+ CONTROL "Do not configure as as Supplier",
+ IDC_RADIO_NO_SUPPLIER_REPLICATION,"Button",
+ BS_AUTORADIOBUTTON,118,65,113,10
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ LTEXT "from another server (CIR)",
+ IDC_STATIC_CONSUMER_CIR_EXTRA,132,126,80,8
+ LTEXT "pushed to it from another server (SIR)",
+ IDC_STATIC_CONSUMER_SIR_EXTRA,132,105,118,8
+ LTEXT "pulled from it by another server (CIR)",
+ IDC_STATIC_SUPPLIER_CIR_EXTRA,131,53,115,8
+ LTEXT "to another server (SIR)",IDC_STATIC_SUPPLIER_SIR_EXTRA,
+ 131,31,72,8
+ GROUPBOX "Consumer Replications Settings",
+ IDC_STATIC_CONSUMER_REPL,113,84,144,68
+ GROUPBOX "Supplier Replication Settings",
+ IDC_STATIC_SUPPLIER_REPLICATION,112,9,145,71
+END
+
+IDD_DISABLE_SCHEMA_CHECKING DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Disable Schema Checking"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ LTEXT "If you are going to import an old database immediately after or during installation, and you think you may have problems with your old schema, you may wish to turn off schema checking until after the import.",
+ IDC_STATIC_DISABLE_SCHEMA_TXT,95,37,188,34
+ LTEXT "If you choose to do this, schema checking will remain off until you manually turn it back on. It is recommended that you turn it back on as soon as possible.",
+ IDC_STATIC_DISABLE_SCHEMA_TEXT_CONT,95,76,187,28
+ GROUPBOX "Disable Schema Checking",
+ IDC_STATIC_DISABLE_SCHEMA_CHECKING_GROUP,90,27,198,102
+ CONTROL "Disable Schema Checking",
+ IDC_CHECK_DISABLE_SCHEMA_CHECKING,"Button",
+ BS_AUTOCHECKBOX | WS_TABSTOP,95,111,99,10
+END
+
+IDD_ADMIN_DOMAIN DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Administration Domain"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ LTEXT "The Administration Domain is a part of the configuration directory server used to store information about Netscape software.",
+ IDC_STATIC_ADMIN_DOMAIN_DESC,90,8,203,16
+ EDITTEXT IDC_EDIT_ADMIN_DOMAIN,157,113,118,14,ES_AUTOHSCROLL
+ LTEXT "Administration Domain:",IDC_STATIC_ADMIN_DOMAIN,104,113,
+ 51,16
+ GROUPBOX "Administration Domain Settings",
+ IDC_STATIC_ADMIN_DOMAIN_GB,90,99,187,40
+ LTEXT "If you are managing multiple software releases at the same time, or managing information about multiple domains, you may use the the Administration Domain to keep them separate.",
+ IDC_STATIC_ADMIN_DOMAIN_DESC2,90,29,197,25
+ LTEXT "If you are not using administrative domains, select the default. Otherwise, enter a descriptive, unique name for the administration domain, such as the name of the organization responsible for managing the domain.",
+ IDC_STATIC_ADMIN_DOMAIN_DESC3,90,58,197,33
+END
+
+IDD_REINSTALL_CONFIG DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION "Directory Server 7.0 Reinstall Settings"
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ LTEXT "Setup has detected that you are reinstalling into an existing server root. ",
+ IDC_STATIC_ADMIN_REINSTALL_DESC,90,8,203,16
+ LTEXT "config url is displayed here",IDC_CONFIG_URL_VAL,96,52,
+ 184,8
+ LTEXT "Bind As:",IDC_STATIC_BIND_AS,96,67,27,8
+ EDITTEXT IDC_EDIT_BIND_AS,145,65,132,14,ES_AUTOHSCROLL
+ LTEXT "Password:",IDC_STATIC_PW,96,88,34,8
+ EDITTEXT IDC_EDIT_PW,145,87,132,14,ES_PASSWORD | ES_AUTOHSCROLL
+ GROUPBOX "Configuration Directory",IDC_STATIC_CONFIG_DIR_SETTING,
+ 87,36,206,89
+END
+
+IDD_UNINSTALL_STATUS DIALOG DISCARDABLE 0, 0, 291, 72
+STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION
+FONT 8, "MS Sans Serif"
+BEGIN
+ CTEXT "",IDC_STOPPING_SERVER_MESSAGE,10,29,270,13,
+ SS_CENTERIMAGE
+END
+
+IDD_ADMIN_ID_ONLY DIALOG DISCARDABLE 0, 0, 297, 163
+STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+CAPTION
+"Directory Server 7.0 Netscape configuration directory server administrator "
+
+FONT 8, "MS Sans Serif"
+BEGIN
+ CONTROL 102,IDC_STATIC,"Static",SS_BITMAP | SS_SUNKEN,0,0,85,160
+ EDITTEXT IDC_EDIT_SUITESPOT_USER,173,51,114,14,ES_AUTOHSCROLL
+ LTEXT "Configuration Directory Administrator ID:",
+ IDC_STATIC_SUITESPOT_USER,94,51,73,17
+ LTEXT "Password:",IDC_STATIC_PASSWORD,94,74,34,8
+ EDITTEXT IDC_EDIT_PASSWORD,173,74,114,14,ES_PASSWORD |
+ ES_AUTOHSCROLL
+ GROUPBOX "Configuration Directory Server Administrator ",
+ IDC_STATIC_SUITESPOT_ADMIN_GROUPBOX,88,35,204,61
+ LTEXT "The Netscape configuration directory administrator is the ID typically used to log in to the console.",
+ IDC_STATIC_MCA_DESC,88,10,196,18
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO DISCARDABLE
+BEGIN
+ IDD_SAMPLE_ENTRIES_ORG, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 176
+ END
+
+ IDD_REPLICATION_AGREEMENT, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 160
+ END
+
+ IDD_CHOOSE_REPLICATION_SETUP, DIALOG
+ BEGIN
+ BOTTOMMARGIN, 160
+ END
+
+ IDD_UNINSTALL_STATUS, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 284
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 65
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Bitmap
+//
+
+IDB_WIZARD BITMAP DISCARDABLE "wizard.bmp"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ERR_NO_WINSOCK "Cant find usable winsock DLL > 2.0"
+ ERR_NO_WINSOCK_VER "Cant find usable winsock DLL > 2.0"
+ ERR_NO_HOST "You must enter a Host."
+ ERR_NO_PORT "You must enter a Port."
+ ERR_NO_SUFFIX "You must enter a suffix."
+ ERR_NO_BIND_DN "You must enter a Bind DN."
+ ERR_NO_PW "You must enter a password."
+ ERR_INIT_DIALOG "Fatal Error Initializing Dialog"
+ ERR_NO_SERVER_ID "You must enter a Server Identifier."
+ ERR_SERVER_ID_EXISTS "A server already exists with the identifier %s. Choose a unique identifier."
+ ERR_INVALID_PORT "The server port %d is invalid. Please choose another one."
+ ERR_PW_TOO_SHORT "You must enter a password of at least %d characters."
+ ERR_NO_PW_AGAIN "You must enter password again to confirm."
+ ERR_PW_DIFFER "Passwords differ, try again."
+ ERR_NO_ROOT_DN "You must enter an unrestricted user."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ERR_NO_SS_ADMIN "You must enter a Configuration Administrator."
+ ERR_NO_SUPPLIER_DN "You must enter a Supplier DN."
+ ERR_NO_CHANGELOG_DB "You must enter a Changelog DB."
+ ERR_NO_CHANGELOG_SUFFIX "You must enter a Changelog Suffix."
+ ERR_NO_CONSUMER_DN "You must enter a consumer bind dn."
+ ERR_READ_GLOBAL_CACHE "Error Reading Global Cache: Invalid %s"
+ ERR_READ_LOCAL_CACHE "Error Reading Local Cache: Invalid %s"
+ ERR_NO_FIND_INST_PROG "Could not find program %s: %s"
+ ERR_EXEC_INST_PROG "Error executing program %s: %s\nPlease refer to the log file %s for more information."
+ ERR_NO_STAT_TMP_FILE "Could not stat the temp file %s: %s"
+ ERR_NO_CREATE_FILE "Could not create file %s"
+ ERR_CREATE_MCC_BAT "Fatal Error Creating Directory Server Mcc"
+ ERR_CREATE_DS_INSTANCE "Fatal Error Creating Directory Server Instance"
+ ERR_REMOVE_EVLOG_KEY "Error Removing Directory Server EventLog Key"
+ ERR_REMOVE_INSTANCE "Error: unable to remove server instance: %s."
+ ERR_REM_INST_REG_KEYS "Error: unable to remove registry keys for server %s."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ERR_SERV_RUN_ON_PORT "You have another server running on port %d. Turn off that server before continuing with installation."
+ ERR_INVALID_HOST "The hostname %s could not be verified. Please enter another hostname."
+ ERR_CANT_FIND_DS "Could not connect to ldap://%s:%d/ for bind DN %s\nPlease check your settings. Otherwise, the remote server may be down at this time.\nThe installation cannot proceed."
+ ERR_SNMP_IS_RUNNING "The SNMP Service is running. It will be turned off automatically and restarted when this operation is complete if you choose to continue."
+ ERR_SNMP_BAD_SHUTDOWN "Error stopping the SNMP Service. Setup can not continue"
+ ERR_SNMP_BAD_STARTUP "Error starting the SNMP Service"
+ ERR_SLAPD_SHUTDOWN "Unable to shutdown the Directory Server (%s).\nWarning, all files and registry keys may not be removed.\nWould you like to continue uninstalling?"
+ ERR_UNK_INST_CREATE "An unknown error occured while executing program %s.\nPlease refer to the log file %s for more information."
+ IDS_UG_DESC "You may already have a directory server you want to use to store your data, such as user and group information."
+ IDS_UG_GB_DESC "Directory to store data"
+ IDS_UG_RADIO_EXIST "Store data in an existing directory server"
+ IDS_UG_RADIO_CREATE "Store data in this directory server"
+ IDS_UG_DLG_CAPTION " "
+ ERR_NO_ADMIN_DOMAIN "You must enter an Admin Domain."
+ ERR_8BIT_PW "Passwords must contain 7 bit characters only."
+ ERR_8BIT_SERVID "Server identifiers must contain 7 bit characters only."
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ERR_8BIT_PATH "Paths must contain 7 bit characters only."
+ SUM_DS_SET_TITLE "Directory Server Settings"
+ SUM_SERVER_IDENTIFIER "Server Identifier"
+ SUM_SUFFIX "Suffix"
+ SUM_PORT "Port"
+ SUM_CONFIG_DS_TITLE "Configuration Directory Server Settings"
+ SUM_HOST "Host"
+ SUM_BIND_AS "Bind As"
+ SUM_DATA_DS_TITLE "Data Directory Server Settings"
+ SUM_CFG_ADM_ID "Configuration Directory Administrator ID"
+ SUM_ADMIN_DOMAIN "Administration Domain"
+ SUM_DIRECTORY_MANAGER "Directory Manager DN"
+ SUM_SUPPLIER_REPL_TITLE "Supplier Replication Settings"
+ SUM_CHANGELOG_DB_DIR "Changelog DB Directory"
+ SUM_CHANGELOG_SUFFIX "Changelog Suffix"
+ SUM_REPL_AGR_TITLE "Replication Agreement"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ SUM_REPL_ROOT "Root of Replication"
+ SUM_REPL_DAYS "Replication Days"
+ SUM_REPL_TIMES "Replication Times"
+ SUM_CONSUMER_BIND_DN "Consumer Bind DN"
+ SUM_CONSUMER_REPL_TITLE "Consumer Replication Settings"
+ SUM_SUPPLIER_DN "Supplier Bind DN"
+ SUM_REPL_SYNC_INTERVAL "Replication Sync Interval"
+ SUM_POP_ORG_STRUCT "Install Sample Organizational Structure"
+ SUM_POP_DB_FILE "Populate Database with"
+ SUM_DISABLE_SCHEMA_CHECKING "Disable Schema Checking"
+ ERR_INVALID_DN "%s is not a valid DN."
+ SUM_REINSTALL "Files will be updated, no configuration changes."
+ ERR_CANT_FIND_DS_REPL "Could not connect to ldap://%s:%d/ for bind DN %s Please check your settings. Otherwise, the remote server may be down at this time. You may need to manually start replication after installation. Would you like to continue using these settings?"
+ IDS_STARTING_SERVICE "Starting Netscape Directory Server (%s)"
+ IDS_STOPPING_SERVICE "Stopping Netscape Directory Server (%s)"
+ IDS_WAIT_SERVICE_START "Waiting for Netscape Directory Server (%s) to start"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_WAIT_SERVICE_STOP "Waiting for Netscape Directory Server (%s) to stop"
+ ERR_ADMIN_DOMAIN_DN "A DN [%s] is not allowed here. Please enter a valid string."
+ ERR_CANT_FIND_ADMIN_DOMAIN
+ "Could not find the Admin Domain %s in ldap://%s:%d/ for bind DN %s\nPlease check your settings. You may need to install using Custom mode in order to specify the Admin domain.\nThe installation cannot proceed."
+ WARN_USING_LDAPV2_QUOTES
+ "The given value [%s] is quoted in the deprecated LDAPv2 style\nquoting format. It will be automatically converted to use the\nLDAPv3 style escaped format [%s]."
+ ERR_8BIT_UID "The UID value must contain 7 bit characters only."
+ ERR_SERVER_ID_EXISTS_TITLE "Directory Server (%s) Already Exists"
+ ERR_NO_CONFIG_URL "The Config Directory URL could not be found."
+ WARN_USING_LDAPV2_QUOTES_TITLE "Warning: Deprecated Quoting Style [%s]"
+ ERR_INVALID_DN_TITLE "Invalid DN: %s"
+ ERR_NO_WINSOCK_TITLE "Could Not Find Winsock"
+ ERR_NO_WINSOCK_VER_TITLE "Invalid Winsock Version"
+ ERR_8BIT_SERVID_TITLE "Invalid Server ID"
+ ERR_SERV_RUN_ON_PORT_TITLE "Port Is In Use"
+ ERR_INIT_DIALOG_TITLE "Could Not Initialize Dialog"
+ ERR_NO_HOST_TITLE "Host Required"
+ ERR_NO_PORT_TITLE "Port Required"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ERR_NO_SUFFIX_TITLE "Suffix Required"
+ ERR_NO_BIND_DN_TITLE "Bind DN Required"
+ ERR_NO_PW_TITLE "Password Required"
+ ERR_NO_SERVER_ID_TITLE "Server ID Required"
+ ERR_INVALID_PORT_TITLE "Port Is Invalid"
+ ERR_PW_TOO_SHORT_TITLE "Password Length Too Short"
+ ERR_NO_PW_AGAIN_TITLE "Enter Password Again"
+ ERR_PW_DIFFER_TITLE "Passwords Are Different"
+ ERR_NO_ROOT_DN_TITLE "Root DN Required"
+ ERR_NO_SS_ADMIN_TITLE "Configuration Administrator Required"
+ ERR_NO_SUPPLIER_DN_TITLE "Supplier DN Required"
+ ERR_NO_CHANGELOG_DB_TITLE "Changelog DB Required"
+ ERR_NO_CHANGELOG_SUFFIX_TITLE "Changelog Suffix Required"
+ ERR_NO_CONSUMER_DN_TITLE "Consumer DN Required"
+ ERR_NO_FIND_INST_PROG_TITLE "Program Not Found"
+ ERR_EXEC_INST_PROG_TITLE "Could Not Execute Program"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ERR_NO_STAT_TMP_FILE_TITLE "File Not Found"
+ ERR_NO_CREATE_FILE_TITLE "Could Not Create File"
+ ERR_CREATE_MCC_BAT_TITLE "Could Not Create Script File"
+ ERR_CREATE_DS_INSTANCE_TITLE "Could Not Create Directory Server Instance"
+ ERR_REMOVE_EVLOG_KEY_TITLE "Could Not Remove EVLOG Key"
+ ERR_REMOVE_INSTANCE_TITLE "Could Not Remove Directory Server Instance"
+ ERR_REM_INST_REG_KEYS_TITLE "Could Not Remove Registry Keys"
+ ERR_INVALID_HOST_TITLE "Invalid Host: %s"
+ ERR_CANT_FIND_DS_TITLE "Could Not Contact Directory Server"
+ ERR_SNMP_IS_RUNNING_TITLE "SNMP Is Running"
+ ERR_SNMP_BAD_SHUTDOWN_TITLE "Error Shutting Down SNMP"
+ ERR_SNMP_BAD_STARTUP_TITLE "Could Not Start SNMP"
+ ERR_SLAPD_SHUTDOWN_TITLE "Error Shutting Down Directory Server (%s)"
+ ERR_NO_ADMIN_DOMAIN_TITLE "Admin Domain Required"
+ ERR_8BIT_PW_TITLE "Invalid Password"
+ ERR_8BIT_PATH_TITLE "Invalid Path"
+END
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ ERR_CANT_FIND_DS_REPL_TITLE "Could Not Connect To Replication Server"
+ ERR_ADMIN_DOMAIN_DN_TITLE "Invalid Admin Domain %s"
+ ERR_CANT_FIND_ADMIN_DOMAIN_TITLE "Admin Domain %s Not Found"
+ ERR_8BIT_UID_TITLE "Invalid User ID Value"
+ ERR_NO_CONFIG_URL_TITLE "Configuration Directory Information Not Found"
+ ERR_NO_USER_URL "The information about the User Directory could not be found."
+ ERR_NO_USER_URL_TITLE "Could Nof Find User Directory Information"
+ ERR_UNINSTALL_DS "Could not uninstall Directory Server. Please check the log file\n%s for problems,\ncorrect them, and uninstall again. Exiting."
+ ERR_UNINSTALL_DS_TITLE "Could not uninstall Directory Server"
+ ERR_REG_DEL_KEY_TITLE "Could Not Delete Registry Key"
+ ERR_REG_DEL_KEY "Could not delete the registry key %s - error %d (%s)."
+ ERR_REG_CREATE_KEY_TITLE "Could not Create Registry Key"
+ ERR_REG_CREATE_KEY "Could not create the registry key %s - error %d (%s)."
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/ldap/cm/newinstnt/dsinst_dsalib_dn.c b/ldap/cm/newinstnt/dsinst_dsalib_dn.c
new file mode 100644
index 00000000..4d2c358c
--- /dev/null
+++ b/ldap/cm/newinstnt/dsinst_dsalib_dn.c
@@ -0,0 +1,7 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <dsalib_dn.c>
diff --git a/ldap/cm/newinstnt/libinst.c b/ldap/cm/newinstnt/libinst.c
new file mode 100644
index 00000000..81c04930
--- /dev/null
+++ b/ldap/cm/newinstnt/libinst.c
@@ -0,0 +1,136 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "libinst.h"
+#include <stdio.h>
+
+//--------------------------------------------------------------------------//
+// Use this instead of installer installer sdk stuff so window is hidden //
+//--------------------------------------------------------------------------//
+DWORD _LaunchAndWait(char *szCommandLine, DWORD dwTimeout)
+{
+ PROCESS_INFORMATION pi;
+ STARTUPINFO si;
+ DWORD dwExitCode = 0;
+
+ ZeroMemory(&pi, sizeof(pi));
+ ZeroMemory(&si, sizeof(si));
+ si.cb = sizeof(STARTUPINFO);
+ si.dwFlags = STARTF_USESHOWWINDOW;
+ // si.wShowWindow = SW_HIDE;
+ // show for debuggin for now
+ si.dwFlags = SW_SHOW;
+
+ if(CreateProcess(NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
+ {
+ if(WaitForSingleObject(pi.hProcess, dwTimeout) == WAIT_OBJECT_0)
+ GetExitCodeProcess(pi.hProcess, &dwExitCode);
+ CloseHandle(pi.hThread);
+ CloseHandle(pi.hProcess);
+ }
+ return(dwExitCode);
+}
+
+
+//////////////////////////////////////////////////////////////////////////////
+// WriteSummaryStringRC
+//
+// write summary info string using resource
+//
+// returns number of bytes written by wsprintf
+//
+
+int WriteSummaryStringRC(LPSTR psz, char *format, HINSTANCE hModule, UINT uStringID, char *value)
+{
+
+ char szTempString[MAX_STR_SIZE]={0};
+ int nReturn= 0;
+
+ LoadString( hModule, uStringID, szTempString, MAX_STR_SIZE);
+
+ if(value)
+ {
+ nReturn = wsprintf(psz, format, szTempString, value);
+ }else{
+ nReturn = wsprintf(psz, format, szTempString);
+ }
+
+ return nReturn;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+// WriteSummaryStringRC
+//
+// write summary info integer using resource
+//
+// returns number of bytes written by wsprintf
+//
+
+int WriteSummaryIntRC(LPSTR psz, char *format, HINSTANCE hModule, UINT uStringID, int value)
+{
+
+ char szTempString[MAX_STR_SIZE]={0};
+ int nReturn = 0;
+
+
+ LoadString( hModule, uStringID, szTempString, MAX_STR_SIZE);
+ nReturn = wsprintf(psz, format, szTempString, value);
+
+ return nReturn;
+}
+
+void
+DSGetHostName(char *hostname, int bufsiz)
+{
+ char *setupHostname = setupGetHostName();
+ if (setupHostname) {
+ int len = strlen(setupHostname);
+ if (len >= bufsiz)
+ len = bufsiz - 1;
+ strncpy(hostname, setupHostname, len);
+ hostname[len] = 0;
+ setupFree(setupHostname);
+ } else {
+ GetHostName(hostname, bufsiz);
+ }
+}
+
+void
+DSGetDefaultSuffix(char *suffix, const char *hostname)
+{
+ const char *SUF = "dc=";
+ const int SUF_LEN = 3;
+ char *sptr = suffix;
+ const char *ptr = 0;
+
+ if (!hostname) {
+ sprintf(sptr, "%s%s", SUF, "unknown-suffix");
+ return; /* bogus domain name */
+ } else {
+ ptr = strchr(hostname, '.'); /* skip to first . in hostname */
+ if (!ptr) {
+ sprintf(sptr, "%s%s", SUF, hostname);
+ return; /* no domain name */
+ }
+ ptr++; /* skip to beginning of domain name */
+ }
+
+ *sptr = 0;
+ strcat(sptr, SUF);
+ sptr += SUF_LEN;
+ for (; *ptr; ++ptr) {
+ if (*ptr == '.') {
+ strcat(sptr, ", ");
+ sptr += 2;
+ strcat(sptr, SUF);
+ sptr += SUF_LEN;
+ } else {
+ *sptr++ = *ptr;
+ }
+ }
+ *sptr = 0;
+
+ return;
+}
diff --git a/ldap/cm/newinstnt/libinst.h b/ldap/cm/newinstnt/libinst.h
new file mode 100644
index 00000000..fd161031
--- /dev/null
+++ b/ldap/cm/newinstnt/libinst.h
@@ -0,0 +1,26 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+//////////////////////////////////////////////////////////////////////////////
+// libinst.h - Netscape SuiteSpot Installation Plug-In Directory Server
+//
+//
+// routines common to each component install dll
+#ifndef __LIBINST_H
+#define __LIBINST_H
+
+#include <windows.h>
+#include <nssetup.h>
+
+#define MAX_STR_SIZE 512
+
+DWORD _LaunchAndWait(char *szCommandLine, DWORD dwTimeout);
+int WriteSummaryStringRC(LPSTR lpsz, char *format, HINSTANCE hModule, UINT uStringID, char *value);
+int WriteSummaryIntRC(LPSTR lpsz, char *format, HINSTANCE hModule, UINT uStringID, int value);
+int DSMessageBox(UINT type, UINT titleKey, UINT msgKey, const char *titlearg, ...);
+int DSMessageBoxOK(UINT titleKey, UINT msgKey, const char *titlearg, ...);
+void DSGetHostName(char *hostname, int bufsiz);
+void DSGetDefaultSuffix(char *suffix, const char *hostname);
+#endif
diff --git a/ldap/cm/newinstnt/resource.h b/ldap/cm/newinstnt/resource.h
new file mode 100644
index 00000000..6c8d6af3
--- /dev/null
+++ b/ldap/cm/newinstnt/resource.h
@@ -0,0 +1,334 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by dsinst.rc
+//
+#define ERR_NO_WINSOCK 1
+#define ERR_NO_WINSOCK_VER 2
+#define ERR_NO_HOST 3
+#define ERR_NO_PORT 4
+#define ERR_NO_SUFFIX 5
+#define ERR_NO_BIND_DN 6
+#define ERR_NO_PW 7
+#define ERR_INIT_DIALOG 8
+#define ERR_NO_SERVER_ID 9
+#define ERR_SERVER_ID_EXISTS 10
+#define ERR_INVALID_PORT 11
+#define ERR_PW_TOO_SHORT 12
+#define ERR_NO_PW_AGAIN 13
+#define ERR_PW_DIFFER 14
+#define ERR_NO_ROOT_DN 15
+#define ERR_NO_SS_ADMIN 16
+#define ERR_NO_SUPPLIER_DN 17
+#define ERR_NO_CHANGELOG_DB 18
+#define ERR_NO_CHANGELOG_SUFFIX 19
+#define ERR_NO_CONSUMER_DN 20
+#define ERR_READ_GLOBAL_CACHE 21
+#define ERR_READ_LOCAL_CACHE 22
+#define ERR_NO_FIND_INST_PROG 23
+#define ERR_EXEC_INST_PROG 24
+#define ERR_NO_STAT_TMP_FILE 25
+#define ERR_NO_CREATE_FILE 26
+#define ERR_CREATE_MCC_BAT 27
+#define ERR_CREATE_DS_INSTANCE 28
+#define ERR_REMOVE_EVLOG_KEY 29
+#define ERR_REMOVE_INSTANCE 30
+#define ERR_REM_INST_REG_KEYS 31
+#define ERR_SERV_RUN_ON_PORT 32
+#define ERR_INVALID_HOST 33
+#define ERR_CANT_FIND_DS 34
+#define ERR_SNMP_IS_RUNNING 35
+#define ERR_SNMP_BAD_SHUTDOWN 36
+#define ERR_SNMP_BAD_STARTUP 37
+#define ERR_SLAPD_SHUTDOWN 38
+#define ERR_UNK_INST_CREATE 39
+#define IDS_UG_DESC 40
+#define IDS_UG_GB_DESC 41
+#define IDS_UG_RADIO_EXIST 42
+#define IDS_UG_RADIO_CREATE 43
+#define IDS_UG_DLG_CAPTION 44
+#define ERR_NO_ADMIN_DOMAIN 45
+#define ERR_8BIT_PW 46
+#define ERR_8BIT_SERVID 47
+#define ERR_8BIT_PATH 48
+#define SUM_DS_SET_TITLE 49
+#define SUM_SERVER_IDENTIFIER 50
+#define SUM_SUFFIX 51
+#define SUM_PORT 52
+#define SUM_CONFIG_DS_TITLE 53
+#define SUM_HOST 54
+#define SUM_BIND_AS 55
+#define SUM_DATA_DS_TITLE 56
+#define SUM_CFG_ADM_ID 57
+#define SUM_ADMIN_DOMAIN 58
+#define SUM_DIRECTORY_MANAGER 59
+#define SUM_SUPPLIER_REPL_TITLE 60
+#define SUM_CHANGELOG_DB_DIR 61
+#define SUM_CHANGELOG_SUFFIX 62
+#define SUM_REPL_AGR_TITLE 63
+#define SUM_REPL_ROOT 64
+#define SUM_REPL_DAYS 65
+#define SUM_REPL_TIMES 66
+#define SUM_CONSUMER_BIND_DN 67
+#define SUM_CONSUMER_REPL_TITLE 68
+#define SUM_SUPPLIER_DN 69
+#define SUM_REPL_SYNC_INTERVAL 70
+#define SUM_POP_ORG_STRUCT 71
+#define SUM_POP_DB_FILE 72
+#define SUM_DISABLE_SCHEMA_CHECKING 73
+#define ERR_INVALID_DN 74
+#define SUM_REINSTALL 75
+#define ERR_CANT_FIND_DS_REPL 76
+#define IDS_STARTING_SERVICE 77
+#define IDS_STOPPING_SERVICE 78
+#define IDS_WAIT_SERVICE_START 79
+#define IDS_WAIT_SERVICE_STOP 80
+#define ERR_ADMIN_DOMAIN_DN 81
+#define ERR_CANT_FIND_ADMIN_DOMAIN 82
+#define WARN_USING_LDAPV2_QUOTES 83
+#define ERR_8BIT_UID 84
+#define ERR_SERVER_ID_EXISTS_TITLE 85
+#define ERR_NO_CONFIG_URL 86
+#define WARN_USING_LDAPV2_QUOTES_TITLE 87
+#define ERR_INVALID_DN_TITLE 88
+#define ERR_NO_WINSOCK_TITLE 89
+#define ERR_NO_WINSOCK_VER_TITLE 90
+#define ERR_8BIT_SERVID_TITLE 91
+#define ERR_SERV_RUN_ON_PORT_TITLE 92
+#define ERR_INIT_DIALOG_TITLE 93
+#define ERR_NO_HOST_TITLE 94
+#define ERR_NO_PORT_TITLE 95
+#define ERR_NO_SUFFIX_TITLE 96
+#define ERR_NO_BIND_DN_TITLE 97
+#define ERR_NO_PW_TITLE 98
+#define ERR_NO_SERVER_ID_TITLE 99
+#define ERR_INVALID_PORT_TITLE 100
+#define ERR_PW_TOO_SHORT_TITLE 101
+#define IDB_WIZARD 102
+#define ERR_NO_PW_AGAIN_TITLE 102
+#define ERR_PW_DIFFER_TITLE 103
+#define ERR_NO_ROOT_DN_TITLE 104
+#define IDD_SERVER_SETTINGS 105
+#define ERR_NO_SS_ADMIN_TITLE 105
+#define IDD_SUITESPOTID 106
+#define ERR_NO_SUPPLIER_DN_TITLE 106
+#define IDD_CONSUMER_REPLICATION_SETTINGS 107
+#define ERR_NO_CHANGELOG_DB_TITLE 107
+#define IDD_SUPPLIER_REPLICATION_SETTINGS 108
+#define ERR_NO_CHANGELOG_SUFFIX_TITLE 108
+#define IDD_ROOTDN 109
+#define ERR_NO_CONSUMER_DN_TITLE 109
+#define ERR_NO_FIND_INST_PROG_TITLE 110
+#define ERR_EXEC_INST_PROG_TITLE 111
+#define IDD_CHOOSE_REPLICATION_SETUP 112
+#define ERR_NO_STAT_TMP_FILE_TITLE 112
+#define IDD_REPLICATION_AGREEMENT 113
+#define ERR_NO_CREATE_FILE_TITLE 113
+#define ERR_CREATE_MCC_BAT_TITLE 114
+#define IDD_SAMPLE_ENTRIES_ORG 115
+#define ERR_CREATE_DS_INSTANCE_TITLE 115
+#define IDD_CONSUMER_DN 116
+#define ERR_REMOVE_EVLOG_KEY_TITLE 116
+#define IDD_MCC_SETTINGS 117
+#define ERR_REMOVE_INSTANCE_TITLE 117
+#define ERR_REM_INST_REG_KEYS_TITLE 118
+#define IDD_DISABLE_SCHEMA_CHECKING 119
+#define ERR_INVALID_HOST_TITLE 119
+#define IDD_ADMIN_DOMAIN 120
+#define ERR_CANT_FIND_DS_TITLE 120
+#define IDD_REINSTALL_CONFIG 121
+#define ERR_SNMP_IS_RUNNING_TITLE 121
+#define IDD_UNINSTALL_STATUS 122
+#define ERR_SNMP_BAD_SHUTDOWN_TITLE 122
+#define ERR_SNMP_BAD_STARTUP_TITLE 123
+#define IDD_ADMIN_ID_ONLY 123
+#define ERR_SLAPD_SHUTDOWN_TITLE 124
+#define ERR_NO_ADMIN_DOMAIN_TITLE 125
+#define ERR_8BIT_PW_TITLE 126
+#define ERR_8BIT_PATH_TITLE 127
+#define ERR_CANT_FIND_DS_REPL_TITLE 128
+#define ERR_ADMIN_DOMAIN_DN_TITLE 129
+#define ERR_CANT_FIND_ADMIN_DOMAIN_TITLE 130
+#define ERR_8BIT_UID_TITLE 131
+#define ERR_NO_CONFIG_URL_TITLE 132
+#define ERR_NO_USER_URL 133
+#define ERR_NO_USER_URL_TITLE 134
+#define ERR_UNINSTALL_DS 135
+#define ERR_UNINSTALL_DS_TITLE 136
+#define ERR_REG_DEL_KEY_TITLE 137
+#define ERR_REG_DEL_KEY 138
+#define ERR_REG_CREATE_KEY_TITLE 139
+#define ERR_REG_CREATE_KEY 140
+#define IDC_EDIT_UNRESTRICTED_USER 1000
+#define IDC_EDIT_PASSWORD 1001
+#define IDC_EDIT_PASSWORD_AGAIN 1002
+#define IDC_STATIC_UNRESTRICTED_USER 1003
+#define IDC_STATIC_PASSWORD 1004
+#define IDC_STATIC_PASSWORD_AGAIN 1005
+#define IDC_STATIC_PASSWORD_AGAIN2 1006
+#define IDC_STATIC_SERVER_PORT 1012
+#define IDC_STATIC_SECURITY_ENABLED 1013
+#define IDC_STATIC_SERVER_IDENTIFIER 1014
+#define IDC_STATIC_SUFFIX 1015
+#define IDC_STATIC_SECURE_SERVER_PORT 1016
+#define IDC_EDIT_SERVER_IDENTIFIER 1017
+#define IDC_EDIT_SUFFIX 1018
+#define IDC_EDIT_SERVER_PORT 1019
+#define IDC_STATIC_GENERAL_SETTINGS 1020
+#define IDC_EDIT_SECURE_SERVER_PORT 1021
+#define IDC_STATIC_SECURITY_SETTINGS 1022
+#define IDC_RADIO_SEC_YES 1023
+#define IDC_RADIO_SEC_NO 1024
+#define IDC_SPIN_SERVER_PORT 1025
+#define IDC_SPIN_SECURE_SERVER_PORT 1026
+#define IDC_STATIC_CIR_DESCRIPTION 1027
+#define IDC_EDIT_SUITESPOT_USER 1028
+#define IDC_STATIC_CIR_DESCRIPTION2 1028
+#define IDC_STATIC_SUPPLIER_DN 1029
+#define IDC_STATIC_SUITESPOT_USER 1030
+#define IDC_STATIC_SUPPLIER_PW 1031
+#define IDC_STATIC_SUPPLIER_PW2 1032
+#define IDC_EDIT_SUPPLIER_DN 1033
+#define IDC_EDIT_SUPPLIER_PW 1034
+#define IDC_SUPPLIER_PW_AGAIN 1035
+#define IDC_CONSUMER 1036
+#define IDC_STATIC_SUPPLIER_SSL 1037
+#define IDC_EDIT_SUPPLIER_SSL_CLIENTS 1038
+#define IDC_STATIC_SIR_DESCRIPTION 1039
+#define IDC_STATIC_CHANGELOG_DB_DIR 1040
+#define IDC_STATIC_CHANGELOG_SUFFIX 1041
+#define IDC_STATIC_MAX_CHANGELOG_RECORDS 1042
+#define IDC_STATIC_MAX_CHANGELOG_RECORDS2 1043
+#define IDC_EDIT_CHANGELOG_DB_DIR 1044
+#define IDC_EDIT_CHANGELOG_DB_SUFFIX 1045
+#define IDC_EDIT_MAX_CHANGELOG_AGE 1046
+#define IDC_EDIT_MAX_CHANGELOG_RECORDS 1047
+#define IDC_COMBO_MAX_CHANGELOG_AGE 1049
+#define IDC_SIR_DESCRIPTION 1050
+#define IDC_STATIC_SIR_AGREEMENTS 1051
+#define IDC_STATIC_SIR_AGREEMENTS_GROUP 1052
+#define IDC_LIST_CONSUMERS 1053
+#define IDC_RADIO_CONSUMER_CIR 1056
+#define IDC_STATIC_SIR_AGREEMENTS2 1057
+#define IDC_RADIO_CONSUMER_SIR 1057
+#define IDC_STATIC_CIR_AGREEMENTS_GROUP 1058
+#define IDC_RADIO_SUPPLIER_SIR 1058
+#define IDC_RADIO_SUPPLIER_CIR 1059
+#define IDC_STATIC_CHANGELOG_DB_DIR2 1060
+#define IDC_RADIO_NO_REPLICATION 1060
+#define IDC_RADIO_NO_CONSUMER_REPLICATION 1060
+#define IDC_STATIC_REPLICA_CONFIG 1061
+#define IDC_RADIO_NO_SUPPLIER_REPLICATION 1061
+#define IDC_STATIC_REPLICATION_HOST 1062
+#define IDC_STATIC_REPLICATION_PORT 1063
+#define IDC_STATIC_REPLICATION_ROOT 1064
+#define IDC_STATIC_REPLICATION_BIND_AS 1065
+#define IDC_STATIC_REPLICATION_PW 1066
+#define IDC_EDIT_REPLICATION_HOST 1067
+#define IDC_EDIT_REPLICATION_ROOT 1068
+#define IDC_EDIT_REPLICATION_BIND_AS 1069
+#define IDC_EDIT_REPLICATION_PW 1070
+#define IDC_EDIT_REPLICATION_PORT 1071
+#define IDC_STATIC_REPLICATION_AGREEMENT 1072
+#define IDC_CHECK_REPLICATION_SSL 1073
+#define IDC_STATIC_SAMPLE_ENTRIES_DESCRIPTION 1074
+#define IDC_CHECK_SAMPLE_ENTRIES 1075
+#define IDC_CHECK_POPULATE_SAMPLE_ENTRIES 1075
+#define IDC_STATIC_ORG_ENTRIES 1076
+#define IDC_CHECK_POPULATE_ORG_ENTRIES 1077
+#define IDC_STATIC_SAMPLE_GROUP 1078
+#define IDC_STATIC_DEFAULT_ORG_GROUP 1079
+#define IDC_EDIT_CONSUMER_DN 1080
+#define IDC_STATIC_CONSUMER_DN 1081
+#define IDC_STATIC_CONSUMER_PW 1082
+#define IDC_STATIC_SUPPLIER_CIR 1083
+#define IDC_STATIC_UNRESTRICTED_USER_GROUPBOX 1084
+#define IDC_STATIC_SUITESPOT_ADMIN_GROUPBOX 1085
+#define IDC_STATIC_CONSUMER_CIR_EXTRA 1086
+#define IDC_STATIC_CONSUMER_SIR_EXTRA 1087
+#define IDC_STATIC_SUPPLIER_CIR_EXTRA 1088
+#define IDC_STATIC_SUPPLIER_SIR_EXTRA 1089
+#define IDC_STATIC_CONSUMER_REPL 1090
+#define IDC_STATIC_SUPPLIER_REPLICATION 1091
+#define IDC_BUTTON_CHOOSE_LDIF_FILE 1093
+#define IDC_RADIO_DONT_POPULATE 1097
+#define IDC_RADIO_POPULATE_SAMPLE 1098
+#define IDC_RADIO_POPULATE_CUSTOM 1099
+#define IDC_STATIC_MUST_HAVE_BASE 1100
+#define IDC_STATIC_FILE_NAME_COLON 1101
+#define IDC_STATIC_LDIF_FILE_NAME 1102
+#define IDC_STATIC_REPL_DAYS 1103
+#define IDC_CHECK_SUN 1104
+#define IDC_CHECK_MON 1105
+#define IDC_CHECK_TUE 1106
+#define IDC_CHECK_WED 1107
+#define IDC_CHECK_THUR 1108
+#define IDC_CHECK_FRI 1109
+#define IDC_CHECK_SAT 1110
+#define IDC_STATIC_REPL_START_TIME 1111
+#define IDC_EDIT_REPL_START_TIME_HH 1112
+#define IDC_STATIC_REPL_END_TIME 1113
+#define IDC_EDIT_REPL_END_TIME_HH 1114
+#define IDC_SPIN_REPL_START_TIME_MM 1115
+#define IDC_SPIN_REPL_SYNC_INTERVAL 1117
+#define IDC_EDIT_REPL_SYNC_INTERVAL 1118
+#define IDC_EDIT_REPL_START_TIME_MM 1119
+#define IDC_STATIC_REPL_SYNC 1120
+#define IDC_SPIN_REPL_START_TIME_HH 1121
+#define IDC_SPIN_REPL_END_TIME_HH 1122
+#define IDC_EDIT_REPL_END_TIME_MM 1123
+#define IDC_SPIN_REPL_END_TIME_MM 1124
+#define IDC_EDIT_MCC_HOST 1125
+#define IDC_EDIT_HOST 1125
+#define IDC_EDIT_MCC_PORT 1126
+#define IDC_EDIT_PORT 1126
+#define IDC_EDIT_MCC_SUFFIX 1127
+#define IDC_EDIT_MCC_BIND_AS 1128
+#define IDC_EDIT_BIND_AS 1128
+#define IDC_EDIT_MCC_PW 1129
+#define IDC_EDIT_PW 1129
+#define IDC_STATIC_MCC_HOST 1130
+#define IDC_STATIC_MCC_PORT 1131
+#define IDC_STATIC_MCC_SUFFIX 1132
+#define IDC_STATIC_MCC_BIND_AS 1133
+#define IDC_STATIC_MCC_PW 1134
+#define IDC_STATIC_MCC_SETTINGS 1135
+#define IDC_STATIC_SETTINGS 1135
+#define IDC_RADIO_MCC_USE_THIS_SERVER 1136
+#define IDC_RADIO_USE_THIS_SERVER 1136
+#define IDC_RADIO_MCC_USE_EXISTING_SERVER 1137
+#define IDC_RADIO_USE_EXISTING_SERVER 1137
+#define IDC_STATIC_MCC_DESC 1138
+#define IDC_STATIC_DESC 1138
+#define IDC_STATIC_MCA_DESC 1139
+#define IDC_STATIC_DM_DESC 1140
+#define IDC_RADIO_CONFIG_CONSUMER_DN_YES 1142
+#define IDC_RADIO3 1143
+#define IDC_RADIO_CONFIG_CONSUMER_DN_NO 1143
+#define IDC_STATIC_DISABLE_SCHEMA_TXT 1144
+#define IDC_STATIC_DISABLE_SCHEMA_CHECKING_GROUP 1145
+#define IDC_CHECK_DISABLE_SCHEMA_CHECKING 1146
+#define IDC_STATIC_DISABLE_SCHEMA_TEXT_CONT 1147
+#define IDC_STATIC_SERV_SETTINGS_DESC 1148
+#define IDC_EDIT_ADMIN_DOMAIN 1149
+#define IDC_STATIC_ADMIN_DOMAIN_DESC 1150
+#define IDC_STATIC_ADMIN_DOMAIN 1151
+#define IDC_STATIC_ADMIN_DOMAIN_GB 1152
+#define IDC_STATIC_ADMIN_DOMAIN_DESC2 1153
+#define IDC_STATIC_ADMIN_REINSTALL_DESC 1154
+#define IDC_STATIC_ADMIN_DOMAIN_DESC3 1155
+#define IDC_CONFIG_URL_VAL 1156
+#define IDC_STATIC_BIND_AS 1157
+#define IDC_STATIC_PW 1158
+#define IDC_STATIC_CONFIG_DIR_SETTING 1161
+#define IDC_STOPPING_SERVER_MESSAGE 1163
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 123
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1166
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/ldap/cm/newinstnt/setup.bat b/ldap/cm/newinstnt/setup.bat
new file mode 100644
index 00000000..ce42aaf2
--- /dev/null
+++ b/ldap/cm/newinstnt/setup.bat
@@ -0,0 +1,3 @@
+@echo off
+
+tools\perl setup.pl %*
diff --git a/ldap/cm/newinstnt/setup.inf b/ldap/cm/newinstnt/setup.inf
new file mode 100644
index 00000000..52430144
--- /dev/null
+++ b/ldap/cm/newinstnt/setup.inf
@@ -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
+#
+#
+# Sample Netscape SuiteSpot Server Package Information File
+#
+# Components: lists the components to be installed as specified
+# in subsequent sections. If the section or the ComponentInfoFile
+# does note exist the setup program will ignore the component
+
+[General]
+Name = Netscape Server Family
+Vendor = Netscape Communications Corp.
+Description = Netscape Server Family
+Version = %%%SERVER_VERSION%%%
+Components = svrcore, base, admin, slapd, dssynch, msg, mcc
+
+# Package Contents
+[svrcore]
+ComponentInfoFile = svrcore/svrcore.inf
+
+[base]
+ComponentInfoFile = base/base.inf
+
+[admin]
+ComponentInfoFile = admin/admin.inf
+
+[slapd]
+ComponentInfoFile = slapd/slapd.inf
+
+[dssynch]
+ComponentInfoFile=dssynch\dssynch.inf
+
+[msg]
+ComponentInfoFile = msg/msg.inf
+
+[mcc]
+ComponentInfoFile = mcc/mcc.inf
diff --git a/ldap/cm/newinstnt/slapd.inf b/ldap/cm/newinstnt/slapd.inf
new file mode 100644
index 00000000..c9233bc2
--- /dev/null
+++ b/ldap/cm/newinstnt/slapd.inf
@@ -0,0 +1,62 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+[General]
+Name=Netscape Directory Suite
+Components=slapd,slapd-client
+Checked=TRUE
+Description=Netscape Directory Server
+
+[slapd]
+Name=Netscape Directory Server
+InstanceNamePrefix= %%%INSTANCE_NAME_PREFIX%%%
+NickName=slapd
+Version= %%%SERVER_VERSION%%%
+Compatible= %%%SERVER_VERSION%%%
+BuildNumber= %%%SERVER_BUILD_NUM%%%
+Expires= %%%PUMPKIN_HOUR%%%
+Security= %%%SECURITY%%%
+Vendor=Netscape Communications Corp.
+Description=Netscape Directory Server
+DefaultAcceptLanguage=en
+Dependencies=admin/4.5,nsperl561/1.10,perldap14/1.01
+Revision=
+Checked=TRUE
+IsLdap=TRUE
+IsDirLite=%%%IS_DIR_LITE%%%
+Mandatory=FALSE
+#install files for admin
+Archive=slapd.z
+PlugIn=dsinst.dll
+ReadInf=DSINST_ReadComponentInf
+PreInstall=DSINST_PreInstall
+AskOptions=DSINST_AskOptions
+GetSummary=DSINST_GetSummary
+WriteLocalCache=DSINST_WriteLocalCache
+WriteGlobalCache=DSINST_WriteGlobalCache
+ReadLocalCache=DSINST_ReadLocalCache
+ReadGlobalCache=DSINST_ReadGlobalCache
+PostInstall=DSINST_PostInstall
+PreUninstall=DSINST_PreUnInstall
+PostUninstall=DSINST_PostUnInstall
+NSPerlPostInstall=lib\nsPerl5.6.1\install.bat
+
+[slapd-client]
+NickName=slapd-client
+Dependencies=base-client/4.5
+Name=Netscape Directory Server Console
+Description=Netscape Directory Server Console
+Version= %%%SERVER_VERSION%%%
+Compatible= %%%SERVER_VERSION%%%
+BuildNumber= %%%SERVER_BUILD_NUM%%%
+Expires= %%%PUMPKIN_HOUR%%%
+IsMCC=TRUE
+IsLdap=FALSE
+Checked=TRUE
+Mandatory=FALSE
+#install files admin-client component
+Archive=dsjars.z
diff --git a/ldap/cm/newinstnt/wizard.bmp b/ldap/cm/newinstnt/wizard.bmp
new file mode 100644
index 00000000..6941f566
--- /dev/null
+++ b/ldap/cm/newinstnt/wizard.bmp
Binary files differ
diff --git a/ldap/cm/ntpack.sh b/ldap/cm/ntpack.sh
new file mode 100644
index 00000000..b99f87ee
--- /dev/null
+++ b/ldap/cm/ntpack.sh
@@ -0,0 +1,76 @@
+#!/bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+#######################################################################
+#
+# Script to pack ldapsdk on NT (uses rtpatch)
+#
+# Mahesh Purswani (3/97)
+#######################################################################
+
+# Path to the rtpatch installation
+RTPATCH=/rtpatch
+
+outfile=outname
+reldir=.
+olddir=/nonedir
+while [ $# -gt 0 ]
+do
+ case "$1" in
+ -o)
+ shift
+ outfile=$1;;
+ -r)
+ shift
+ reldir=$1;;
+ *)
+ echo ""
+ echo "Usage: $0 [-o outfile] [-r sourcedir]"
+ echo ""
+ exit 1;;
+ esac
+ shift
+done
+
+if [ ! -d "$olddir" ] ; then
+ echo "Making empty old directory $olddir"
+ mkdir $olddir
+fi
+
+rolddir=`echo $olddir | sed 's#/#\\\\#g'`
+rreldir=`echo $reldir | sed 's#/#\\\\#g'`
+
+cat <<EOF > pack.txt
+OLDDIR $rolddir /F
+NEWDIR $rreldir /F
+OUTPUT $outfile
+FILE *.*
+PATCHFILE
+LONGNAMES
+PARTIAL
+SUBDIRSEARCH
+NOPATHSEARCH
+IGNOREMISSING
+EOF
+
+cat <<EOF > bind.txt
+[General]
+Platform=Console32
+DirectoryPrompt=Please specify install directory (default is current directory):
+IncludeDLL=1
+PatchFile=$outfile.rtp
+OutputFile=$outfile.exe
+EOF
+
+# Run rtpatch
+$RTPATCH/pbld-nt @pack.txt
+$RTPATCH/pbind bind.txt
+
+echo "Packed release dir = $reldir"
+echo "To outfile = $outfile"
diff --git a/ldap/cm/unixstrip b/ldap/cm/unixstrip
new file mode 100755
index 00000000..102c5c4c
--- /dev/null
+++ b/ldap/cm/unixstrip
@@ -0,0 +1,31 @@
+#!/bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# usage unixstrip <location>
+
+perl="$1"
+
+arch=`uname -s`
+if [ "$arch" = "HP-UX" ]; then
+ SHLIB_PATH="$4"
+ export SHLIB_PATH
+else
+ LD_LIBRARY_PATH="$4"
+ export LD_LIBRARY_PATH
+fi
+
+if [ $# > 2 ]; then
+exec "$perl" unixstrip.pl "$2" "$3"
+else
+exec "$perl" unixstrip.pl "$2"
+fi
+
+#for StripFile in `find . -type f -print `
+#do
+# strip $StripFile
+#done
diff --git a/ldap/cm/unixstrip.pl b/ldap/cm/unixstrip.pl
new file mode 100644
index 00000000..9d9ae308
--- /dev/null
+++ b/ldap/cm/unixstrip.pl
@@ -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
+#
+use File::Find;
+
+#
+# usage: unixstrip.pl [ directory ... ] [ shlibsign ]
+#
+# if no arguments are passed, strip files under the current directory.
+#
+# if 1 argument is passed, strip files under the given directory.
+#
+# if 2 or more arguments are passed,
+# the last argument is considered the path to nss utility shlibsign (NSS3.9~),
+# the preceding args are directories, under which files are to be stripped.
+# And nss libraries libsoftokn3, libfreebl_pure32_3, libfreebl_hybrid_3
+# are to be checksum'ed with shlibsign.
+
+my $SHLIBSIGN = "";
+if (@ARGV > 1) {
+ $SHLIBSIGN = $ARGV[$#ARGV];
+ print STDERR "set $SHLIBSIGN \n";
+ for (my $i = 0; $i < $#ARGV; $i++)
+ {
+ print STDERR "args[$i]: $ARGV[$i]\n";
+ find(\&find_cb, $ARGV[$i]);
+ }
+} elsif (@ARGV == 1) {
+ find(\&find_cb, @ARGV);
+} else {
+ find(\&find_cb, '.');
+}
+
+sub find_cb {
+ return if (! -f $_); # only look at plain files
+ return if (! -B $_); # skip text files
+ return if (/\.jpg$/); # skip jpg files
+ return if (/\.gif$/); # skip gif files
+ return if (/\.jar$/); # skip jar files
+ return if (/\.zip$/); # skip zip files
+ return if (/\.gz$/); # skip gzip files
+ return if (/\.chk$/); # skip chk files
+ print STDERR "about to strip $_ .\n";
+ system("strip $_");
+ print STDERR "strip $_ done.\n";
+ if ($SHLIBSIGN ne "" && /libsoftokn3|libfreebl_pure32_3|libfreebl_hybrid_3/)
+ {
+ print STDERR "$SHLIBSIGN $_\n";
+ system("$SHLIBSIGN -v -i $_");
+ }
+}
+
+exit 0;
diff --git a/ldap/cm/v1confs/ns-calendar-globopt.conf b/ldap/cm/v1confs/ns-calendar-globopt.conf
new file mode 100644
index 00000000..752d8574
--- /dev/null
+++ b/ldap/cm/v1confs/ns-calendar-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+index nsCalXItemId pres,eq,sub
+
diff --git a/ldap/cm/v1confs/ns-calendar-schema.conf b/ldap/cm/v1confs/ns-calendar-schema.conf
new file mode 100644
index 00000000..16e3f222
--- /dev/null
+++ b/ldap/cm/v1confs/ns-calendar-schema.conf
@@ -0,0 +1,131 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute generationQualifier cis
+attribute nsCalAccess cis
+attribute nsCalAccessDomain cis
+attribute nsCalAdmd cis
+attribute nsCalDefaultNoteReminder cis
+attribute nsCalDefaultReminder cis
+attribute nsCalDefaultTaskReminder cis
+attribute nsCalDisplayPrefs cis
+attribute nsCalFlags cis
+attribute nsCalHost cis
+attribute nsCalLanguageId cis
+attribute nsCalNodeAlias cis
+attribute nsCalNotifMechanism cis
+attribute nsCalOperatingPrefs cis
+attribute nsCalOrgUnit2 cis
+attribute nsCalOrgUnit3 cis
+attribute nsCalOrgUnit4 cis
+attribute nsCalPasswordRequired cis
+attribute nsCalPrmd cis
+attribute nsCalRefreshPrefs cis
+attribute nsCalResourceCapacity cis
+attribute nsCalResourceNumber cis
+attribute nsCalServerVersion cis
+attribute nsCalSysopCanWritePassword cis
+attribute nsCalTimezone cis
+attribute nsCalXItemId cis
+
+
+objectclass nsCalUser
+ requires
+ objectClass
+ allows
+ generationQualifier,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalRefreshPrefs,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass nsCalAdmin
+ requires
+ objectClass
+ allows
+ cn,
+ facsimileTelephoneNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ ou,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalXItemId
+
+objectclass nsCalResource
+ requires
+ objectClass
+ allows
+ cn,
+ facsimileTelephoneNumber,
+ postalAddress,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalPasswordRequired,
+ nsCalRefreshPrefs,
+ nsCalResourceCapacity,
+ nsCalResourceNumber,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass netscapeCalendarServer
+ requires
+ objectclass
+
+
diff --git a/ldap/cm/v1confs/ns-certificate-globopt.conf b/ldap/cm/v1confs/ns-certificate-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v1confs/ns-certificate-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v1confs/ns-certificate-schema.conf b/ldap/cm/v1confs/ns-certificate-schema.conf
new file mode 100644
index 00000000..173a6d75
--- /dev/null
+++ b/ldap/cm/v1confs/ns-certificate-schema.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+objectclass netscapeCertificateServer
+ requires
+ objectclass
+
diff --git a/ldap/cm/v1confs/ns-compass-globopt.conf b/ldap/cm/v1confs/ns-compass-globopt.conf
new file mode 100644
index 00000000..4d2e1e21
--- /dev/null
+++ b/ldap/cm/v1confs/ns-compass-globopt.conf
@@ -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
+#
+# Used by Netscape Directory Server
+index pipuid pres,eq,sub
+index pipstatus eq
+
diff --git a/ldap/cm/v1confs/ns-compass-schema.conf b/ldap/cm/v1confs/ns-compass-schema.conf
new file mode 100644
index 00000000..3875f41b
--- /dev/null
+++ b/ldap/cm/v1confs/ns-compass-schema.conf
@@ -0,0 +1,169 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+
+# Compass server specific (not currently used)
+
+objectclass netscapeCompassServer
+ requires
+ objectclass
+
+
+# Attributes for personal interest profile classes
+
+attribute pipuid cis
+attribute pipcompassservers cis
+attribute pipuniqueid cis
+attribute pipstatus cis
+attribute pipusertype cis
+attribute pipfrequency cis
+attribute pipmedium cis
+attribute pipformat cis
+attribute piphour cis
+attribute pipmaxhits cis
+attribute pipresultset cis
+attribute pipsortorder cis
+attribute piptimestamp cis
+attribute pipirlist cis
+attribute pipiroption cis
+attribute pippwp cis
+attribute piplastcount cis
+attribute piptotalcount cis
+attribute piptotalrun cis
+attribute pipnotify cis
+attribute pipprivilege cis
+attribute pipgroup cis
+attribute pipidstcount cis
+attribute pipstid cis
+attribute pipstname cis
+attribute pipstquery cis
+attribute pipsttaxonomy cis
+attribute pipstinterest cis
+attribute pipsttype cis
+attribute pipstprivacy cis
+attribute pipststatus cis
+attribute pipstlastcount cis
+attribute pipsttotalcount cis
+attribute pipsttotalrun cis
+attribute pipstcategory cis
+attribute pipstfrequency cis
+attribute pipstmedium cis
+attribute pipstformat cis
+attribute pipsthour cis
+attribute pipstmaxhits cis
+attribute pipstresultset cis
+attribute pipstsortorder cis
+attribute pipsttimestamp cis
+attribute pipstirlist cis
+attribute pipstiroption cis
+attribute pipreservedcis1 cis
+attribute pipreservedcis2 cis
+attribute pipreservedcis3 cis
+attribute pipreservedcis4 cis
+attribute pipreservedcis5 cis
+attribute pipreservedcis6 cis
+attribute pipreservedces1 ces
+attribute pipreservedces2 ces
+attribute pipreservedces3 ces
+
+
+# Each interest profile is one of these and sits under the compass SIE
+
+objectclass personalInterestProfile
+ requires
+ objectclass,
+ pipuid
+ allows
+ pipuniqueid,
+ pipstatus,
+ pipusertype,
+ pipfrequency,
+ pipmedium,
+ pipformat,
+ piphour,
+ pipmaxhits,
+ pipresultset,
+ pipsortorder,
+ piptimestamp,
+ pipirlist,
+ pipiroption,
+ pippwp,
+ piplastcount,
+ piptotalcount,
+ piptotalrun,
+ pipnotify,
+ pipprivilege,
+ pipgroup,
+ pipidstcount,
+ pipstid,
+ pipstname,
+ pipstquery,
+ pipsttaxonomy,
+ pipstinterest,
+ pipsttype,
+ pipstprivacy,
+ pipststatus,
+ pipstlastcount,
+ pipsttotalcount,
+ pipsttotalrun,
+ pipstcategory,
+ pipstfrequency,
+ pipstmedium,
+ pipstformat,
+ pipsthour,
+ pipstmaxhits,
+ pipstresultset,
+ pipstsortorder,
+ pipsttimestamp,
+ pipstirlist,
+ pipstiroption,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
+
+# Replication of user info for template users, completeness, etc.
+# (not currently used)
+
+objectclass PIPUserInfo
+ requires
+ objectclass
+ allows
+ cn,
+ mail,
+ userPassword,
+ description,
+ pipcompassservers,
+ pipuniqueid
+
+
+# Enhancements to a normal user entry (not currently used)
+
+objectclass PIPUser
+ requires
+ objectclass
+ allows
+ pipuniqueid,
+ pipcompassservers,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
diff --git a/ldap/cm/v1confs/ns-directory-globopt.conf b/ldap/cm/v1confs/ns-directory-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v1confs/ns-directory-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v1confs/ns-directory-schema.conf b/ldap/cm/v1confs/ns-directory-schema.conf
new file mode 100644
index 00000000..9aaf263a
--- /dev/null
+++ b/ldap/cm/v1confs/ns-directory-schema.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+objectclass netscapeDirectoryServer
+ requires
+ objectclass
+
diff --git a/ldap/cm/v1confs/ns-mail-globopt.conf b/ldap/cm/v1confs/ns-mail-globopt.conf
new file mode 100644
index 00000000..1c4ef195
--- /dev/null
+++ b/ldap/cm/v1confs/ns-mail-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+index uid,mail,mailAlternateAddress,mailHost eq
+index uniquemember,member eq
diff --git a/ldap/cm/v1confs/ns-mail-schema.conf b/ldap/cm/v1confs/ns-mail-schema.conf
new file mode 100644
index 00000000..bd069bfa
--- /dev/null
+++ b/ldap/cm/v1confs/ns-mail-schema.conf
@@ -0,0 +1,93 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+attribute mailAccessDomain 2.16.840.1.113730.3.1.12 cis
+attribute mailAlternateAddress 2.16.840.1.113730.3.1.13 cis
+attribute mailAutoReplyMode 2.16.840.1.113730.3.1.14 cis
+attribute mailAutoReplyText 2.16.840.1.113730.3.1.15 cis
+attribute mailDeliveryOption 2.16.840.1.113730.3.1.16 cis
+attribute mailForwardingAddress 2.16.840.1.113730.3.1.17 cis
+attribute mailHost 2.16.840.1.113730.3.1.18 cis
+attribute mailQuota 2.16.840.1.113730.3.1.21 cis
+attribute mailRoutingAddress 2.16.840.1.113730.3.1.47 cis
+
+attribute mailMessageStore 2.16.840.1.113730.3.1.19 ces
+attribute mailProgramDeliveryInfo 2.16.840.1.113730.3.1.20 ces
+
+objectClass mailRecipient
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAccessDomain,
+ mailAlternateAddress,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailHost,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota,
+ mailRoutingAddress,
+ multiLineDescription,
+ uid,
+ userPassword
+
+attribute mgrpAllowedDomain 2.16.840.1.113730.3.1.23 cis
+attribute mgrpMsgRejectAction 2.16.840.1.113730.3.1.28 cis
+attribute mgrpRFC822MailMember 2.16.840.1.113730.3.1.30 cis
+attribute mgrpMsgMaxSize 2.16.840.1.113730.3.1.32 cis
+
+attribute mgrpAllowedBroadcaster 2.16.840.1.113730.3.1.22 ces
+attribute mgrpDeliverTo 2.16.840.1.113730.3.1.25 ces
+attribute mgrpErrorsTo 2.16.840.1.113730.3.1.26 ces
+attribute mgrpModerator 2.16.840.1.113730.3.1.33 ces
+attribute mgrpMsgRejectText 2.16.840.1.113730.3.1.29 ces
+
+#attribute groupPassword 2.16.840.1.113730.3.1.27 bin
+
+objectClass mailGroup
+ requires
+ objectClass,
+ mail
+ allows
+ cn,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mgrpAllowedBroadcaster,
+ mgrpAllowedDomain,
+ mgrpDeliverTo,
+ mgrpErrorsTo,
+ mgrpModerator,
+ mgrpMsgMaxSize,
+ mgrpMsgRejectAction,
+ mgrpMsgRejectText,
+ mgrpRFC822MailMember,
+ owner
+
+attribute mailEnhancedUniqueMember 2.16.840.1.113730.3.1.31 dn
+
+objectClass groupOfMailEnhancedUniqueNames
+ requires
+ objectClass,
+ cn
+ allows
+ businessCategory,
+ description,
+ mailEnhancedUniqueMember,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectClass netscapeMailServer
+ requires
+ objectClass
diff --git a/ldap/cm/v1confs/ns-media-globopt.conf b/ldap/cm/v1confs/ns-media-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v1confs/ns-media-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v1confs/ns-media-schema.conf b/ldap/cm/v1confs/ns-media-schema.conf
new file mode 100644
index 00000000..bc3bca5d
--- /dev/null
+++ b/ldap/cm/v1confs/ns-media-schema.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+objectclass netscapeMediaServer
+ requires
+ objectclass
+
diff --git a/ldap/cm/v1confs/ns-news-globopt.conf b/ldap/cm/v1confs/ns-news-globopt.conf
new file mode 100644
index 00000000..7e5d8ca3
--- /dev/null
+++ b/ldap/cm/v1confs/ns-news-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+index uniquemember,member eq
+
diff --git a/ldap/cm/v1confs/ns-news-schema.conf b/ldap/cm/v1confs/ns-news-schema.conf
new file mode 100644
index 00000000..381ed6ff
--- /dev/null
+++ b/ldap/cm/v1confs/ns-news-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+attribute nsnewsACL cis
+attribute nsaclrole cis
+attribute nsprettyname cis
+attribute nsflags cis
+attribute nscreator cis
+
+attribute ngcomponent dn
+
+objectclass nginfo
+ requires
+ objectClass,
+ ngcomponent
+ allows
+ nsnewsACL,
+ subtreeACI,
+ description,
+ nsaclrole,
+ nsprettyname,
+ nsflags,
+ nscreator
+
+objectClass netscapeNewsServer
+ requires
+ objectClass
+
diff --git a/ldap/cm/v1confs/ns-proxy-globopt.conf b/ldap/cm/v1confs/ns-proxy-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v1confs/ns-proxy-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v1confs/ns-proxy-schema.conf b/ldap/cm/v1confs/ns-proxy-schema.conf
new file mode 100644
index 00000000..878348cd
--- /dev/null
+++ b/ldap/cm/v1confs/ns-proxy-schema.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+objectclass netscapeProxyServer
+ requires
+ objectclass
+
diff --git a/ldap/cm/v1confs/ns-web-globopt.conf b/ldap/cm/v1confs/ns-web-globopt.conf
new file mode 100644
index 00000000..7e5d8ca3
--- /dev/null
+++ b/ldap/cm/v1confs/ns-web-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+index uniquemember,member eq
+
diff --git a/ldap/cm/v1confs/ns-web-schema.conf b/ldap/cm/v1confs/ns-web-schema.conf
new file mode 100644
index 00000000..af8002b0
--- /dev/null
+++ b/ldap/cm/v1confs/ns-web-schema.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+objectclass netscapeWebServer
+ requires
+ objectclass
+
diff --git a/ldap/cm/v1confs/slapd.at.conf b/ldap/cm/v1confs/slapd.at.conf
new file mode 100644
index 00000000..28509c3f
--- /dev/null
+++ b/ldap/cm/v1confs/slapd.at.conf
@@ -0,0 +1,276 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# slapd.at.conf
+#
+attribute abstract cis
+attribute ad addmdname cis
+attribute affiliationcode cis
+attribute ambiance cis
+attribute ansiorgnumericcode cis
+attribute appearance cis
+attribute associateddomain cis
+attribute authorcn documentauthorcommonname cis
+attribute authorsn documentauthorsurname cis
+attribute automgt automatedmanagement cis
+attribute average-price cis
+attribute buildingname cis
+attribute businesscategory cis
+attribute c countryname cis
+attribute carlicense cis
+attribute category cis
+attribute changelogmaximumage cis
+attribute changelogmaximumsize cis
+attribute citation cis
+attribute classstanding cis
+attribute closed cis
+attribute cn commonname cis
+attribute cnamerecord cis
+attribute co friendlycountryname cis
+attribute colordepth cis
+attribute copyright cis
+attribute creditcardsaccepted cis
+attribute dc domaincomponent cis
+attribute departmentnumber cis
+attribute description cis
+attribute destinationindicator cis
+attribute dnsrecord cis
+attribute documentidentifier cis
+attribute documentlocation cis
+attribute documentpublisher cis
+attribute documentseriestitle cis
+attribute documentstore cis
+attribute documenttitle cis
+attribute documenttitle cis
+attribute documentversion cis
+attribute donotdelete cis
+attribute donotmove cis
+attribute drink favouritedrink cis
+attribute employeenumber cis
+attribute employeetype cis
+attribute expire cis
+attribute fileformat cis
+attribute filesize cis
+attribute fips55 fipsplacenumericcode cis
+attribute fipscountynumericcode cis
+attribute fipsstatealphacode cis
+attribute fipsstatenumericcode cis
+attribute givenname cis
+attribute height cis
+attribute homepostaladdress cis
+attribute host cis
+attribute hoursofoperation cis
+attribute info cis
+attribute initials cis
+attribute janetmailbox cis
+attribute joinable cis
+attribute keepnames cis
+attribute keywords cis
+attribute knowledgeinformation cis
+attribute kosher cis
+attribute krbname cis
+attribute l localityname cis
+attribute lastmodifiedtime cis
+attribute mail rfc822mailbox cis
+attribute mailpreferenceoption cis
+attribute max-price cis
+attribute maximuminparty cis
+attribute min-price cis
+attribute moderator cis
+attribute multilineabstract cis
+attribute multilinedescription cis
+attribute music cis
+attribute mxrecord cis
+attribute nobatchupdates cis
+attribute notice cis
+attribute notrecommended cis
+attribute notregistered cis
+attribute nsrecord cis
+attribute o organizationname cis
+attribute objectclass cis
+attribute onvacation cis
+attribute organizationalstatus cis
+attribute othermailbox cis
+attribute ou organizationalunitname cis
+attribute outdoorseating cis
+attribute parking cis
+attribute personaltitle cis
+attribute physicaldeliveryofficename cis
+attribute platform cis
+attribute postaladdress cis
+attribute postalcode cis
+attribute postofficebox cis
+attribute predominantcolor cis
+attribute preferreddeliverymethod cis
+attribute product cis
+attribute provider cis
+attribute qualityofservice cis
+attribute qualitypriceratio cis
+attribute ratingdescription cis
+attribute ratingtime cis
+attribute recommended cis
+attribute recommendedby cis
+attribute registeredaddress cis
+attribute registeredaddress cis
+attribute registrationstatus cis
+attribute replicahost cis
+attribute replicaport cis
+attribute replicaupdatefailedat cis
+attribute replicaupdatereplayed cis
+attribute replicaupdateschedule cis
+attribute replicabindmethod cis
+attribute replicausessl cis
+attribute reservation cis
+attribute resolution cis
+attribute rfc822errorsto cis
+attribute rfc822requeststo cis
+attribute roomnumber cis
+attribute serialnumber cis
+attribute servicearea cis
+attribute servicerating cis
+attribute servicespeed cis
+attribute sn surname cis
+attribute soarecord cis
+attribute specialty cis
+attribute st stateorprovincename cis
+attribute street streetAddress cis
+attribute subject cis
+attribute supplementaryinformation cis
+attribute supportedapplicationcontext cis
+attribute supportedapplicationcontext cis
+attribute suppressnoemailerror cis
+attribute taux-de-frequentation cis
+attribute telexnumber cis
+attribute textencodedoraddress cis
+attribute title cis
+attribute transportationmeans cis
+attribute ttl timetolive cis
+attribute uid cis
+attribute universityid cis
+attribute uniqueidentifier cis
+attribute updatesource cis
+attribute userclass cis
+attribute vacationmessage cis
+attribute width cis
+
+attribute aci bin
+attribute audio bin
+attribute authorityrevocationlist;binary bin
+attribute authorityrevocationlist bin
+attribute cacertificate;binary bin
+attribute cacertificate bin
+attribute certificate;binary bin
+attribute certificate bin
+attribute certificaterevocationlist;binary bin
+attribute certificaterevocationlist bin
+attribute crosscertificatepair;binary bin
+attribute crosscertificatepair bin
+attribute jpegphoto bin
+attribute personalsignature bin
+attribute personalsignature bin
+attribute photo bin
+attribute usercertificate;binary bin
+attribute usercertificate bin
+attribute x500uniqueidentifier bin
+attribute userpassword bin
+attribute replicacredentials bin
+
+attribute generation ces
+attribute internationalisdnnumber ces
+attribute labeleduri labeledurl ces
+attribute nadfsearchguide ces
+attribute presentationaddress ces
+attribute searchguide ces
+attribute subtreeaci ces
+attribute x121address ces
+
+attribute facsimiletelephonenumber fax tel
+attribute homephone tel
+attribute mobile mobiletelephonenumber tel
+attribute pager pagertelephonenumber tel
+attribute telephonenumber tel
+
+attribute aliasedobjectname dn
+attribute aliasedobjectname dn
+attribute associatedname dn
+attribute dependentupon dn
+attribute ditredirect dn
+attribute dn dn
+attribute documentauthor dn
+attribute documentauthor dn
+attribute documentavailable dn
+attribute errorsto dn
+attribute errorsto dn
+attribute imagefiles dn
+attribute lastmodifiedby dn
+attribute manager dn
+attribute member dn
+attribute memberofgroup dn
+attribute naminglink dn
+attribute naminglink dn
+attribute obsoletedbydocument dn
+attribute obsoletesdocument dn
+attribute owner dn
+attribute proxy dn
+attribute reciprocalnaminglink dn
+attribute reciprocalnaminglink dn
+attribute replicaroot dn
+attribute replicabinddn dn
+attribute requeststo dn
+attribute roleoccupant dn
+attribute secretary dn
+attribute seealso dn
+attribute uniqueMember dn
+attribute updatedbydocument dn
+attribute updatesdocument dn
+
+attribute ntUserDomainId cis
+attribute ntUserPriv bin
+attribute ntUserHomeDir cis
+attribute ntUserComment cis
+attribute ntUserFlags bin
+attribute ntUserScriptPath cis
+attribute ntUserAuthFlags bin
+attribute ntUserUsrComment cis
+attribute ntUserParms cis
+attribute ntUserWorkstations cis
+attribute ntUserLastLogon cis
+attribute ntUserLastLogoff cis
+attribute ntUserAcctExpires cis
+attribute ntUserMaxStorage bin
+attribute ntUserUnitsPerWeek bin
+attribute ntUserLogonHours bin
+attribute ntUserBadPwCount bin
+attribute ntUserNumLogons bin
+attribute ntUserLogonServer cis
+attribute ntUserCountryCode cis
+attribute ntUserCodePage bin
+attribute ntUserUniqueId bin
+attribute ntUserPrimaryGroupId bin
+attribute ntUserProfile cis
+attribute ntUserHomeDirDrive cis
+attribute ntUserPasswordExpired bin
+attribute ntUserCreateNewAccount cis
+attribute ntUserDeleteAccount cis
+
+# attributes below added for Netscape Directory Server 1.02
+
+attribute serverRoot cis
+attribute serverProductName cis
+attribute serverVersionNumber cis
+attribute installationTimeStamp cis
+attribute administratorContactInfo cis
+attribute adminURL ces
+attribute serverHostName cis
+
+attribute nsLicensedFor cis
+attribute nsLicenseStartTime cis
+attribute nsLicenseEndTime cis
+
+attribute preferredlanguage cis
+attribute usersmimecertificate;binary bin
diff --git a/ldap/cm/v1confs/slapd.oc.conf b/ldap/cm/v1confs/slapd.oc.conf
new file mode 100644
index 00000000..cf673f78
--- /dev/null
+++ b/ldap/cm/v1confs/slapd.oc.conf
@@ -0,0 +1,1077 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# slapd.oc.conf
+#
+objectclass top
+ requires
+ objectClass
+
+objectclass alias
+ requires
+ aliasedObjectName,
+ objectClass
+
+objectclass country
+ requires
+ objectClass,
+ c
+ allows
+ searchGuide,
+ description
+
+objectclass locality
+ requires
+ objectClass
+ allows
+ description,
+ l,
+ searchGuide,
+ seeAlso,
+ st,
+ street
+
+objectclass organization
+ requires
+ objectClass,
+ o
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass organizationalUnit
+ requires
+ objectClass,
+ ou
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass person
+ requires
+ objectClass,
+ sn,
+ cn
+ allows
+ description,
+ seeAlso,
+ telephoneNumber,
+ userPassword
+
+objectclass organizationalPerson
+ requires
+ objectClass,
+ sn,
+ cn
+ allows
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ title,
+ userPassword,
+ x121Address
+
+objectclass inetOrgPerson
+ requires
+ objectClass,
+ sn,
+ cn
+ allows
+ audio,
+ businessCategory,
+ carLicense,
+ departmentNumber,
+ description,
+ destinationIndicator,
+ employeeType,
+ employeeNumber,
+ facsimileTelephoneNumber,
+ givenName,
+ homePhone,
+ homePostalAddress,
+ initials,
+ internationaliSDNNumber,
+ jpegPhoto,
+ l,
+ labeledURI,
+ ou,
+ manager,
+ mobile,
+ pager,
+ photo,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ preferredLanguage,
+ registeredAddress,
+ mail,
+ roomNumber,
+ secretary,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ title,
+ uid,
+ x500uniqueIdentifier,
+ userPassword,
+ userCertificate,
+ userCertificate;binary,
+ userSMimeCertificate;binary,
+ x121Address
+
+objectclass ntUser
+ requires
+ objectClass,
+ ntUserDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntUserPriv,
+ ntUserHomeDir,
+ ntUserComment,
+ ntUserFlags,
+ ntUserScriptPath,
+ ntUserAuthFlags,
+ ntUserUsrComment,
+ ntUserParms,
+ ntUserWorkstations,
+ ntUserLastLogon,
+ ntUserLastLogoff,
+ ntUserAcctExpires,
+ ntUserMaxStorage,
+ ntUserUnitsPerWeek,
+ ntUserLogonHours,
+ ntUserBadPwCount,
+ ntUserNumLogons,
+ ntUserLogonServer,
+ ntUserCountryCode,
+ ntUserCodePage,
+ ntUserUniqueId,
+ ntUserPrimaryGroupId,
+ ntUserProfile,
+ ntUserHomeDirDrive,
+ ntUserPasswordExpired,
+ ntUserCreateNewAccount,
+ ntUserDeleteAccount
+
+objectclass organizationalRole
+ requires
+ objectClass,
+ cn
+ allows
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ roleOccupant,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass groupOfNames
+ requires
+ objectClass,
+ cn
+ allows
+ member,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfUniqueNames
+ requires
+ objectClass,
+ cn
+ allows
+ uniqueMember,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass residentialPerson
+ requires
+ objectClass,
+ sn,
+ cn,
+ l
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass applicationProcess
+ requires
+ objectClass,
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso
+
+objectclass LDAPServer
+ requires
+ objectClass,
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ generation,
+ changeLogMaximumAge,
+ changeLogMaximumSize
+
+objectclass LDAPReplica
+ requires
+ objectClass,
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ replicaRoot,
+ replicaHost,
+ replicaPort,
+ replicaBinddn,
+ replicaCredentials,
+ replicaBindMethod,
+ replicaUseSSL,
+ replicaUpdateSchedule,
+ replicaUpdateReplayed,
+ replicaUpdateFailedAt
+
+objectclass applicationEntity
+ requires
+ objectClass,
+ presentationAddress,
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ supportedApplicationContext
+
+objectclass dSA
+ requires
+ objectClass,
+ presentationAddress,
+ cn
+ allows
+ knowledgeInformation
+
+objectclass device
+ requires
+ objectClass,
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+objectclass strongAuthenticationUser
+ requires
+ objectClass,
+ userCertificate,
+ userCertificate;binary
+
+objectclass certificationAuthority
+ requires
+ objectClass,
+ cACertificate;binary
+ allows
+ authorityRevocationList;binary,
+ certificateRevocationList;binary,
+ crossCertificatePair;binary
+
+objectclass pilotObject
+ requires
+ objectClass
+ allows
+ audio,
+ dITRedirect,
+ info,
+ jpegPhoto,
+ lastModifiedBy,
+ lastModifiedTime,
+ manager,
+ photo,
+ uniqueIdentifier
+
+objectclass newPilotPerson
+ requires
+ objectClass,
+ sn,
+ cn
+ allows
+ businessCategory,
+ description,
+ drink,
+ homePhone,
+ homePostalAddress,
+ janetMailbox,
+ mail,
+ mailPreferenceOption,
+ mobile,
+ organizationalStatus,
+ otherMailbox,
+ pager,
+ personalSignature,
+ personalTitle,
+ preferredDeliveryMethod,
+ roomNumber,
+ secretary,
+ seeAlso,
+ telephoneNumber,
+ textEncodedORaddress,
+ uid,
+ userClass,
+ userPassword
+
+objectclass account
+ requires
+ objectClass,
+ uid
+ allows
+ description,
+ host,
+ l,
+ o,
+ ou,
+ seeAlso
+
+objectclass document
+ requires
+ objectClass,
+ documentIdentifier
+ allows
+ abstract,
+ audio,
+ authorCN,
+ authorSN,
+ cn,
+ dITRedirect,
+ description,
+ documentAuthor,
+ documentLocation,
+ documentPublisher,
+ documentStore,
+ documentTitle,
+ documentVersion,
+ info,
+ jpegPhoto,
+ keywords,
+ l,
+ lastModifiedBy,
+ lastModifiedTime,
+ manager,
+ o,
+ obsoletedByDocument,
+ obsoletesDocument,
+ ou,
+ photo,
+ seeAlso,
+ subject,
+ uniqueIdentifier,
+ updatedByDocument,
+ updatesDocument
+
+objectclass room
+ requires
+ objectClass,
+ cn
+ allows
+ description,
+ roomNumber,
+ seeAlso,
+ telephoneNumber
+
+objectclass documentSeries
+ requires
+ objectClass,
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ telephoneNumber
+
+objectclass domain
+ requires
+ objectClass,
+ dc
+ allows
+ associatedName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ manager,
+ o,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass RFC822localPart
+ requires
+ objectClass,
+ dc
+ allows
+ associatedName,
+ businessCategory,
+ cn,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ o,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ sn,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass DNSDomain
+ requires
+ objectClass,
+ dc
+ allows
+ associatedName,
+ businessCategory,
+ dNSRecord,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ o,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass domainRelatedObject
+ requires
+ objectClass,
+ associatedDomain
+
+objectclass friendlyCountry
+ requires
+ objectClass,
+ c,
+ co
+ allows
+ description,
+ searchGuide
+
+objectclass simpleSecurityObject
+ requires
+ objectClass,
+ userPassword
+
+objectclass pilotOrganization
+ requires
+ objectClass,
+ ou,
+ o
+ allows
+ buildingName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass nadfObject
+ requires
+ objectClass
+ allows
+ lastModifiedTime,
+ nadfSearchGuide,
+ supplementaryInformation
+
+objectclass usStateOrEquivalent
+ requires
+ objectClass,
+ st,
+ fipsStateAlphaCode,
+ fipsStateNumericCode,
+ l
+ allows
+ description,
+ lastModifiedTime,
+ nadfSearchGuide,
+ searchGuide,
+ seeAlso,
+ street,
+ supplementaryInformation
+
+objectclass usPlace
+ requires
+ objectClass,
+ fips55,
+ l
+ allows
+ description,
+ lastModifiedTime,
+ nadfSearchGuide,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ supplementaryInformation
+
+objectclass usCountyOrEquivalent
+ requires
+ objectClass,
+ fipsCountyNumericCode,
+ fips55,
+ l
+ allows
+ description,
+ lastModifiedTime,
+ nadfSearchGuide,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ supplementaryInformation
+
+objectclass ansiOrgObject
+ requires
+ objectClass,
+ ansiOrgNumericCode
+
+objectclass nadfApplicationEntity
+ requires
+ objectClass,
+ supportedApplicationContext,
+ presentationAddress,
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ supportedApplicationContext
+
+objectclass nadfADDMD
+ requires
+ objectClass,
+ ad
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ lastModifiedTime,
+ nadfSearchGuide,
+ o,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ supplementaryInformation,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass publicObject
+ requires
+ objectClass,
+ namingLink
+
+objectclass providerObject
+ requires
+ objectClass,
+ reciprocalNamingLink
+
+objectclass nationalObject
+ requires
+ objectClass,
+ c
+
+objectclass fips55Object
+ requires
+ objectClass,
+ fips55
+ allows
+ st
+
+objectclass restaurant
+ requires
+ objectClass,
+ description,
+ telephoneNumber,
+ street
+ allows
+ Ambiance,
+ Appearance,
+ Average-price,
+ Closed,
+ CreditCardsAccepted,
+ Kosher,
+ Max-price,
+ MaximumInParty,
+ Min-price,
+ Music,
+ NotRecommended,
+ OutdoorSeating,
+ Parking,
+ QualityOfService,
+ QualityPriceRatio,
+ Recommended,
+ RecommendedBy,
+ Reservation,
+ ServiceSpeed,
+ Specialty,
+ Taux-de-frequentation,
+ TransportationMeans,
+ facsimileTelephoneNumber,
+ postalAddress
+
+objectclass kerberosSecurityObject
+ requires
+ objectClass,
+ krbName
+
+objectclass umichPerson
+ requires
+ objectClass,
+ sn,
+ cn,
+ universityID
+ allows
+ affiliationCode,
+ audio,
+ businessCategory,
+ classStanding,
+ description,
+ destinationIndicator,
+ doNotDelete,
+ doNotMove,
+ drink,
+ expire,
+ facsimileTelephoneNumber,
+ homePhone,
+ homePostalAddress,
+ internationaliSDNNumber,
+ janetMailbox,
+ jpegPhoto,
+ keepNames,
+ krbName,
+ l,
+ labeledURI,
+ mail,
+ mailPreferenceOption,
+ memberOfGroup,
+ mobile,
+ multiLineDescription,
+ noBatchUpdates,
+ notRegistered,
+ notice,
+ onVacation,
+ organizationalStatus,
+ otherMailbox,
+ ou,
+ pager,
+ personalSignature,
+ personalTitle,
+ photo,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ proxy,
+ registeredAddress,
+ registrationStatus,
+ roomNumber,
+ secretary,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ textEncodedORaddress,
+ title,
+ uid,
+ updateSource,
+ userCertificate,
+ userCertificate;binary,
+ userClass,
+ userPassword,
+ vacationMessage,
+ x121Address,
+ xacl
+
+objectclass rfc822MailGroup
+ requires
+ objectClass,
+ owner,
+ cn
+ allows
+ associatedDomain,
+ autoMgt,
+ description,
+ destinationIndicator,
+ errorsTo,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ joinable,
+ krbName,
+ labeledURI,
+ mail,
+ member,
+ memberOfGroup,
+ moderator,
+ multiLineDescription,
+ notice,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ requestsTo,
+ rfc822ErrorsTo,
+ rfc822RequestsTo,
+ seeAlso,
+ street,
+ suppressNoEmailError,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address,
+ xacl
+
+objectclass image
+ requires
+ objectClass,
+ cn
+ allows
+ citation,
+ copyright,
+ imageFiles,
+ jpegPhoto,
+ keywords,
+ multiLineDescription,
+ owner,
+ predominantColor
+
+objectclass imageFile
+ requires
+ objectClass,
+ cn
+ allows
+ colorDepth,
+ documentLocation,
+ fileFormat,
+ fileSize,
+ height,
+ resolution,
+ seeAlso,
+ width
+
+objectclass service
+ requires
+ objectClass,
+ cn
+ allows
+ category,
+ dependentUpon,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ hoursOfOperation,
+ internationaliSDNNumber,
+ jpegPhoto,
+ keywords,
+ labeledURI,
+ mail,
+ multiLineDescription,
+ owner,
+ physicalDeliveryOfficeName,
+ platform,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ product,
+ provider,
+ ratingDescription,
+ ratingTime,
+ registeredAddress,
+ seeAlso,
+ serviceArea,
+ serviceRating,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass umichDocument
+ requires
+ objectClass,
+ documentIdentifier
+ allows
+ abstract,
+ audio,
+ authorCN,
+ authorSN,
+ category,
+ cn,
+ dITRedirect,
+ description,
+ documentAuthor,
+ documentAvailable,
+ documentLocation,
+ documentPublisher,
+ documentSeriesTitle,
+ documentStore,
+ documentTitle,
+ documentVersion,
+ info,
+ jpegPhoto,
+ keywords,
+ l,
+ labeledURI,
+ lastModifiedBy,
+ lastModifiedTime,
+ manager,
+ multiLineAbstract,
+ o,
+ obsoletedByDocument,
+ obsoletesDocument,
+ ou,
+ owner,
+ photo,
+ platform,
+ product,
+ seeAlso,
+ serviceArea,
+ subject,
+ uniqueIdentifier,
+ updatedByDocument,
+ updatesDocument
+
+objectclass documentDescription
+ requires
+ objectClass,
+ cn
+ allows
+ labeledURI,
+ multiLineDescription,
+ owner
+
+objectclass labeledURIObject
+ requires
+ objectClass
+ allows
+ labeledURI
+
+objectclass cacheObject
+ requires
+ objectClass
+ allows
+ ttl
+
+# objectclasses below added for Netscape Directory Server 1.02
+
+objectclass netscapeServer
+ requires
+ objectClass,
+ cn
+ allows
+ description,
+ serverRoot,
+ serverProductName,
+ serverVersionNumber,
+ installationTimeStamp,
+ administratorContactInfo,
+ userpassword,
+ adminURL,
+ serverHostName
+
+objectclass nsLicenseUser
+ requires
+ objectClass
+ allows
+ nsLicensedFor,
+ nsLicenseStartTime,
+ nsLicenseEndTime
diff --git a/ldap/cm/v3confs/ns-calendar-globopt.conf b/ldap/cm/v3confs/ns-calendar-globopt.conf
new file mode 100644
index 00000000..0bdb7dd9
--- /dev/null
+++ b/ldap/cm/v3confs/ns-calendar-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+index nsCalXItemId pres,eq,sub
diff --git a/ldap/cm/v3confs/ns-calendar-schema.conf b/ldap/cm/v3confs/ns-calendar-schema.conf
new file mode 100644
index 00000000..f36574a4
--- /dev/null
+++ b/ldap/cm/v3confs/ns-calendar-schema.conf
@@ -0,0 +1,135 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsCalAccess 2.16.840.1.113730.3.1.112 cis
+attribute nsCalAccessDomain 2.16.840.1.113730.3.1.113 cis
+attribute nsCalAdmd 2.16.840.1.113730.3.1.114 cis
+attribute nsCalDefaultNoteReminder 2.16.840.1.113730.3.1.115 cis
+attribute nsCalDefaultReminder 2.16.840.1.113730.3.1.116 cis
+attribute nsCalDefaultTaskReminder 2.16.840.1.113730.3.1.117 cis
+attribute nsCalDisplayPrefs 2.16.840.1.113730.3.1.118 cis
+attribute nsCalFlags 2.16.840.1.113730.3.1.119 cis
+attribute nsCalHost 2.16.840.1.113730.3.1.120 cis
+attribute nsCalLanguageId 2.16.840.1.113730.3.1.121 cis
+attribute nsCalNodeAlias 2.16.840.1.113730.3.1.122 cis
+attribute nsCalNotifMechanism 2.16.840.1.113730.3.1.123 cis
+attribute nsCalOperatingPrefs 2.16.840.1.113730.3.1.124 cis
+attribute nsCalOrgUnit2 2.16.840.1.113730.3.1.125 cis
+attribute nsCalOrgUnit3 2.16.840.1.113730.3.1.126 cis
+attribute nsCalOrgUnit4 2.16.840.1.113730.3.1.127 cis
+attribute nsCalPasswordRequired 2.16.840.1.113730.3.1.128 cis
+attribute nsCalPrmd 2.16.840.1.113730.3.1.129 cis
+attribute nsCalRefreshPrefs 2.16.840.1.113730.3.1.130 cis
+attribute nsCalResourceCapacity 2.16.840.1.113730.3.1.131 cis
+attribute nsCalResourceNumber 2.16.840.1.113730.3.1.132 cis
+attribute nsCalServerVersion 2.16.840.1.113730.3.1.133 cis
+attribute nsCalSysopCanWritePassword 2.16.840.1.113730.3.1.134 cis
+attribute nsCalTimezone 2.16.840.1.113730.3.1.135 cis
+attribute nsCalXItemId 2.16.840.1.113730.3.1.136 cis
+
+
+objectclass nsCalUser
+ oid 2.16.840.1.113730.3.2.14
+ requires
+ objectClass
+ allows
+ generationQualifier,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalRefreshPrefs,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass nsCalAdmin
+ oid 2.16.840.1.113730.3.2.15
+ requires
+ objectClass
+ allows
+ cn,
+ facsimileTelephoneNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ ou,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalXItemId
+
+objectclass nsCalResource
+ oid 2.16.840.1.113730.3.2.16
+ requires
+ objectClass
+ allows
+ cn,
+ facsimileTelephoneNumber,
+ postalAddress,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalPasswordRequired,
+ nsCalRefreshPrefs,
+ nsCalResourceCapacity,
+ nsCalResourceNumber,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass netscapeCalendarServer
+ oid 2.16.840.1.113730.3.2.17
+ requires
+ objectclass
+
+
+
diff --git a/ldap/cm/v3confs/ns-certificate-globopt.conf b/ldap/cm/v3confs/ns-certificate-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v3confs/ns-certificate-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v3confs/ns-certificate-schema.conf b/ldap/cm/v3confs/ns-certificate-schema.conf
new file mode 100644
index 00000000..f4578018
--- /dev/null
+++ b/ldap/cm/v3confs/ns-certificate-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeCertificateServer
+ oid 2.16.840.1.113730.3.2.18
+ requires
+ objectclass
+
diff --git a/ldap/cm/v3confs/ns-compass-globopt.conf b/ldap/cm/v3confs/ns-compass-globopt.conf
new file mode 100644
index 00000000..4d2e1e21
--- /dev/null
+++ b/ldap/cm/v3confs/ns-compass-globopt.conf
@@ -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
+#
+# Used by Netscape Directory Server
+index pipuid pres,eq,sub
+index pipstatus eq
+
diff --git a/ldap/cm/v3confs/ns-compass-schema.conf b/ldap/cm/v3confs/ns-compass-schema.conf
new file mode 100644
index 00000000..be13bc44
--- /dev/null
+++ b/ldap/cm/v3confs/ns-compass-schema.conf
@@ -0,0 +1,173 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+
+# Compass server specific (not currently used)
+
+objectclass netscapeCompassServer
+ oid 2.16.840.1.113730.3.2.19
+ requires
+ objectclass
+
+
+# Attributes for personal interest profile classes
+
+attribute pipuid 2.16.840.1.113730.3.1.137 cis
+attribute pipcompassservers 2.16.840.1.113730.3.1.138 cis
+attribute pipuniqueid 2.16.840.1.113730.3.1.139 cis
+attribute pipstatus 2.16.840.1.113730.3.1.140 cis
+attribute pipusertype 2.16.840.1.113730.3.1.141 cis
+attribute pipfrequency 2.16.840.1.113730.3.1.142 cis
+attribute pipmedium 2.16.840.1.113730.3.1.143 cis
+attribute pipformat 2.16.840.1.113730.3.1.144 cis
+attribute piphour 2.16.840.1.113730.3.1.145 cis
+attribute pipmaxhits 2.16.840.1.113730.3.1.146 cis
+attribute pipresultset 2.16.840.1.113730.3.1.147 cis
+attribute pipsortorder 2.16.840.1.113730.3.1.148 cis
+attribute piptimestamp 2.16.840.1.113730.3.1.149 cis
+attribute pipirlist 2.16.840.1.113730.3.1.150 cis
+attribute pipiroption 2.16.840.1.113730.3.1.151 cis
+attribute pippwp 2.16.840.1.113730.3.1.152 cis
+attribute piplastcount 2.16.840.1.113730.3.1.153 cis
+attribute piptotalcount 2.16.840.1.113730.3.1.154 cis
+attribute piptotalrun 2.16.840.1.113730.3.1.155 cis
+attribute pipnotify 2.16.840.1.113730.3.1.156 cis
+attribute pipprivilege 2.16.840.1.113730.3.1.157 cis
+attribute pipgroup 2.16.840.1.113730.3.1.158 cis
+attribute pipidstcount 2.16.840.1.113730.3.1.159 cis
+attribute pipstid 2.16.840.1.113730.3.1.160 cis
+attribute pipstname 2.16.840.1.113730.3.1.161 cis
+attribute pipstquery 2.16.840.1.113730.3.1.162 cis
+attribute pipsttaxonomy 2.16.840.1.113730.3.1.163 cis
+attribute pipstinterest 2.16.840.1.113730.3.1.164 cis
+attribute pipsttype 2.16.840.1.113730.3.1.165 cis
+attribute pipstprivacy 2.16.840.1.113730.3.1.166 cis
+attribute pipststatus 2.16.840.1.113730.3.1.167 cis
+attribute pipstlastcount 2.16.840.1.113730.3.1.168 cis
+attribute pipsttotalcount 2.16.840.1.113730.3.1.169 cis
+attribute pipsttotalrun 2.16.840.1.113730.3.1.170 cis
+attribute pipstcategory 2.16.840.1.113730.3.1.171 cis
+attribute pipstfrequency 2.16.840.1.113730.3.1.172 cis
+attribute pipstmedium 2.16.840.1.113730.3.1.173 cis
+attribute pipstformat 2.16.840.1.113730.3.1.174 cis
+attribute pipsthour 2.16.840.1.113730.3.1.175 cis
+attribute pipstmaxhits 2.16.840.1.113730.3.1.176 cis
+attribute pipstresultset 2.16.840.1.113730.3.1.177 cis
+attribute pipstsortorder 2.16.840.1.113730.3.1.178 cis
+attribute pipsttimestamp 2.16.840.1.113730.3.1.179 cis
+attribute pipstirlist 2.16.840.1.113730.3.1.180 cis
+attribute pipstiroption 2.16.840.1.113730.3.1.181 cis
+attribute pipreservedcis1 2.16.840.1.113730.3.1.182 cis
+attribute pipreservedcis2 2.16.840.1.113730.3.1.183 cis
+attribute pipreservedcis3 2.16.840.1.113730.3.1.184 cis
+attribute pipreservedcis4 2.16.840.1.113730.3.1.185 cis
+attribute pipreservedcis5 2.16.840.1.113730.3.1.186 cis
+attribute pipreservedcis6 2.16.840.1.113730.3.1.187 cis
+attribute pipreservedces1 2.16.840.1.113730.3.1.188 ces
+attribute pipreservedces2 2.16.840.1.113730.3.1.189 ces
+attribute pipreservedces3 2.16.840.1.113730.3.1.190 ces
+
+
+# Each interest profile is one of these and sits under the compass SIE
+
+objectclass personalInterestProfile
+ oid 2.16.840.1.113730.3.2.20
+ requires
+ objectclass,
+ pipuid
+ allows
+ pipuniqueid,
+ pipstatus,
+ pipusertype,
+ pipfrequency,
+ pipmedium,
+ pipformat,
+ piphour,
+ pipmaxhits,
+ pipresultset,
+ pipsortorder,
+ piptimestamp,
+ pipirlist,
+ pipiroption,
+ pippwp,
+ piplastcount,
+ piptotalcount,
+ piptotalrun,
+ pipnotify,
+ pipprivilege,
+ pipgroup,
+ pipidstcount,
+ pipstid,
+ pipstname,
+ pipstquery,
+ pipsttaxonomy,
+ pipstinterest,
+ pipsttype,
+ pipstprivacy,
+ pipststatus,
+ pipstlastcount,
+ pipsttotalcount,
+ pipsttotalrun,
+ pipstcategory,
+ pipstfrequency,
+ pipstmedium,
+ pipstformat,
+ pipsthour,
+ pipstmaxhits,
+ pipstresultset,
+ pipstsortorder,
+ pipsttimestamp,
+ pipstirlist,
+ pipstiroption,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
+
+# Replication of user info for template users, completeness, etc.
+# (not currently used)
+
+objectclass PIPUserInfo
+ oid 2.16.840.1.113730.3.2.21
+ requires
+ objectclass
+ allows
+ cn,
+ mail,
+ userPassword,
+ description,
+ pipcompassservers,
+ pipuniqueid
+
+
+# Enhancements to a normal user entry (not currently used)
+
+objectclass PIPUser
+ oid 2.16.840.1.113730.3.2.22
+ requires
+ objectclass
+ allows
+ pipuniqueid,
+ pipcompassservers,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
diff --git a/ldap/cm/v3confs/ns-directory-globopt.conf b/ldap/cm/v3confs/ns-directory-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v3confs/ns-directory-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v3confs/ns-directory-schema.conf b/ldap/cm/v3confs/ns-directory-schema.conf
new file mode 100644
index 00000000..7c0611ee
--- /dev/null
+++ b/ldap/cm/v3confs/ns-directory-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeDirectoryServer
+ oid 2.16.840.1.113730.3.2.23
+ requires
+ objectclass
+
diff --git a/ldap/cm/v3confs/ns-mail-globopt.conf b/ldap/cm/v3confs/ns-mail-globopt.conf
new file mode 100644
index 00000000..1c4ef195
--- /dev/null
+++ b/ldap/cm/v3confs/ns-mail-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+index uid,mail,mailAlternateAddress,mailHost eq
+index uniquemember,member eq
diff --git a/ldap/cm/v3confs/ns-mail-schema.conf b/ldap/cm/v3confs/ns-mail-schema.conf
new file mode 100644
index 00000000..076cc065
--- /dev/null
+++ b/ldap/cm/v3confs/ns-mail-schema.conf
@@ -0,0 +1,97 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+attribute mailAccessDomain 2.16.840.1.113730.3.1.12 cis
+attribute mailAlternateAddress 2.16.840.1.113730.3.1.13 cis
+attribute mailAutoReplyMode 2.16.840.1.113730.3.1.14 cis
+attribute mailAutoReplyText 2.16.840.1.113730.3.1.15 cis
+attribute mailDeliveryOption 2.16.840.1.113730.3.1.16 cis
+attribute mailForwardingAddress 2.16.840.1.113730.3.1.17 cis
+attribute mailHost 2.16.840.1.113730.3.1.18 cis
+attribute mailQuota 2.16.840.1.113730.3.1.21 cis
+attribute mailRoutingAddress 2.16.840.1.113730.3.1.47 cis
+
+attribute mailMessageStore 2.16.840.1.113730.3.1.19 ces
+attribute mailProgramDeliveryInfo 2.16.840.1.113730.3.1.20 ces
+
+objectClass mailRecipient
+ oid 2.16.840.1.113730.3.2.3
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAccessDomain,
+ mailAlternateAddress,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailHost,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota,
+ mailRoutingAddress,
+ multiLineDescription,
+ uid,
+ userPassword
+
+attribute mgrpAllowedDomain 2.16.840.1.113730.3.1.23 cis
+attribute mgrpMsgRejectAction 2.16.840.1.113730.3.1.28 cis
+attribute mgrpRFC822MailMember 2.16.840.1.113730.3.1.30 cis
+attribute mgrpMsgMaxSize 2.16.840.1.113730.3.1.32 cis
+
+attribute mgrpAllowedBroadcaster 2.16.840.1.113730.3.1.22 ces
+attribute mgrpDeliverTo 2.16.840.1.113730.3.1.25 ces
+attribute mgrpErrorsTo 2.16.840.1.113730.3.1.26 ces
+attribute mgrpModerator 2.16.840.1.113730.3.1.33 ces
+attribute mgrpMsgRejectText 2.16.840.1.113730.3.1.29 ces
+
+#attribute groupPassword 2.16.840.1.113730.3.1.27 bin
+
+objectClass mailGroup
+ oid 2.16.840.1.113730.3.2.4
+ requires
+ objectClass,
+ mail
+ allows
+ cn,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mgrpAllowedBroadcaster,
+ mgrpAllowedDomain,
+ mgrpDeliverTo,
+ mgrpErrorsTo,
+ mgrpModerator,
+ mgrpMsgMaxSize,
+ mgrpMsgRejectAction,
+ mgrpMsgRejectText,
+ mgrpRFC822MailMember,
+ owner
+
+attribute mailEnhancedUniqueMember 2.16.840.1.113730.3.1.31 dn
+
+objectClass groupOfMailEnhancedUniqueNames
+ oid 2.16.840.1.113730.3.2.5
+ requires
+ objectClass,
+ cn
+ allows
+ businessCategory,
+ description,
+ mailEnhancedUniqueMember,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectClass netscapeMailServer
+ oid 2.16.840.1.113730.3.2.24
+ requires
+ objectClass
diff --git a/ldap/cm/v3confs/ns-media-globopt.conf b/ldap/cm/v3confs/ns-media-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v3confs/ns-media-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v3confs/ns-media-schema.conf b/ldap/cm/v3confs/ns-media-schema.conf
new file mode 100644
index 00000000..d4afa271
--- /dev/null
+++ b/ldap/cm/v3confs/ns-media-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeMediaServer
+ oid 2.16.840.1.113730.3.2.25
+ requires
+ objectclass
+
diff --git a/ldap/cm/v3confs/ns-news-globopt.conf b/ldap/cm/v3confs/ns-news-globopt.conf
new file mode 100644
index 00000000..7e5d8ca3
--- /dev/null
+++ b/ldap/cm/v3confs/ns-news-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+index uniquemember,member eq
+
diff --git a/ldap/cm/v3confs/ns-news-schema.conf b/ldap/cm/v3confs/ns-news-schema.conf
new file mode 100644
index 00000000..777f339a
--- /dev/null
+++ b/ldap/cm/v3confs/ns-news-schema.conf
@@ -0,0 +1,35 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsnewsACL 2.16.840.1.113730.3.1.191 cis
+attribute nsaclrole 2.16.840.1.113730.3.1.192 cis
+attribute nsprettyname 2.16.840.1.113730.3.1.193 cis
+attribute nsflags 2.16.840.1.113730.3.1.194 cis
+attribute nscreator 2.16.840.1.113730.3.1.195 cis
+attribute ngcomponent 2.16.840.1.113730.3.1.196 dn
+
+objectclass nginfo
+ oid 2.16.840.1.113730.3.2.26
+ requires
+ objectClass,
+ ngcomponent
+ allows
+ nsnewsACL,
+ subtreeACI,
+ description,
+ nsaclrole,
+ nsprettyname,
+ nsflags,
+ nscreator
+
+objectClass netscapeNewsServer
+ oid 2.16.840.1.113730.3.2.27
+ requires
+ objectClass
+
diff --git a/ldap/cm/v3confs/ns-proxy-globopt.conf b/ldap/cm/v3confs/ns-proxy-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v3confs/ns-proxy-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v3confs/ns-proxy-schema.conf b/ldap/cm/v3confs/ns-proxy-schema.conf
new file mode 100644
index 00000000..3d26bacb
--- /dev/null
+++ b/ldap/cm/v3confs/ns-proxy-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeProxyServer
+ oid 2.16.840.1.113730.3.2.28
+ requires
+ objectclass
+
diff --git a/ldap/cm/v3confs/ns-web-globopt.conf b/ldap/cm/v3confs/ns-web-globopt.conf
new file mode 100644
index 00000000..7e5d8ca3
--- /dev/null
+++ b/ldap/cm/v3confs/ns-web-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+index uniquemember,member eq
+
diff --git a/ldap/cm/v3confs/ns-web-schema.conf b/ldap/cm/v3confs/ns-web-schema.conf
new file mode 100644
index 00000000..ce5c2b16
--- /dev/null
+++ b/ldap/cm/v3confs/ns-web-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeWebServer
+ oid 2.16.840.1.113730.3.2.29
+ requires
+ objectclass
+
diff --git a/ldap/cm/v3confs/slapd.at.conf b/ldap/cm/v3confs/slapd.at.conf
new file mode 100644
index 00000000..01e31155
--- /dev/null
+++ b/ldap/cm/v3confs/slapd.at.conf
@@ -0,0 +1,319 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.at.conf for Netscape Directory Server 3.1
+#
+# DO NOT MODIFY!
+#
+# The attributes listed in this file are Standard Attributes and are
+# expected to present in Directory Server 3.1. Editing this file could
+# cause interoperability problems.
+#
+# User Defined Attributes should be added by selecting
+# Schema | Edit or View Attributes from the Admin Server.
+#
+# User Defined Attributes are placed in slapd.user_at.conf.
+#
+# All attributes are viewable over LDAP in the cn=schema entry under
+# attributetypes.
+#
+# The format of this file is:
+#
+# attribute attribute-name [attribute-aliases] [attribute-oid] syntax
+#
+# If no OID is specified, <attribute-name>-oid will be used as the OID
+#
+
+########################################################################
+# X.500(93) User Schema for use with LDAP
+# Taken from <draft-ietf-asid-ldapv3schema-x500-00.txt>
+########################################################################
+
+attribute objectClass 2.5.4.0 cis
+attribute aliasedObjectName 2.5.4.1 dn
+attribute knowledgeInformation 2.5.4.2 cis
+attribute cn commonName 2.5.4.3 cis
+attribute sn surName 2.5.4.4 cis
+attribute serialNumber 2.5.4.5 cis
+attribute c countryName 2.5.4.6 cis
+attribute l locality localityname 2.5.4.7 cis
+attribute st stateOrProvinceName 2.5.4.8 cis
+attribute street streetaddress 2.5.4.9 cis
+attribute o organizationname 2.5.4.10 cis
+attribute ou organizationalUnitName 2.5.4.11 cis
+attribute title 2.5.4.12 cis
+attribute description 2.5.4.13 cis
+attribute searchGuide 2.5.4.14 ces
+attribute businessCategory 2.5.4.15 cis
+attribute postalAddress 2.5.4.16 cis
+attribute postalCode 2.5.4.17 cis
+attribute postOfficeBox 2.5.4.18 cis
+attribute physicalDeliveryOfficeName 2.5.4.19 cis
+attribute telephoneNumber 2.5.4.20 tel
+attribute telexNumber 2.5.4.21 cis
+attribute teletexTerminalIdentifier 2.5.4.22 cis
+attribute facsimileTelephoneNumber fax 2.5.4.23 tel
+attribute x121Address 2.5.4.24 ces
+attribute internationalIsdnNumber 2.5.4.25 ces
+attribute registeredAddress 2.5.4.26 cis
+attribute destinationIndicator 2.5.4.27 cis
+attribute preferredDeliveryMethod 2.5.4.28 cis
+attribute presentationAddress 2.5.4.29 ces
+attribute supportedApplicationContext 2.5.4.30 cis
+attribute member 2.5.4.31 dn
+attribute owner 2.5.4.32 dn
+attribute roleOccupant 2.5.4.33 dn
+attribute seeAlso 2.5.4.34 dn
+attribute userPassword 2.5.4.35 bin
+attribute userCertificate;binary userCertificate 2.5.4.36 bin
+attribute cACertificate;binary cACertificate 2.5.4.37 bin
+attribute authorityRevocationList;binary authorityRevocationList 2.5.4.38 bin
+attribute certificateRevocationList;binary certificateRevocationList 2.5.4.39 bin
+attribute crossCertificatePair;binary crossCertificatePair 2.5.4.40 bin
+attribute givenName 2.5.4.42 cis
+attribute initials 2.5.4.43 cis
+attribute generationQualifier 2.5.4.44 cis
+attribute x500UniqueIdentifier 2.5.4.45 bin
+attribute dnQualifier 2.5.4.46 cis
+attribute enhancedSearchGuide 2.5.4.47 cis
+attribute protocolInformation 2.5.4.48 cis
+attribute dn distinguishedName 2.5.4.49 dn
+attribute uniqueMember 2.5.4.50 dn
+attribute houseIdentifier 2.5.4.51 cis
+attribute supportedAlgorithms;binary 2.5.4.52 bin
+attribute deltaRevocationList;binary 2.5.4.53 bin
+
+#######################################################################
+# LDAP Attributes #
+# Taken from <draft-ietf-asid-ldapv3-attributes-07.txt> #
+#######################################################################
+
+attribute createTimestamp 2.5.18.1 cis
+attribute modifyTimestamp 2.5.18.2 cis
+attribute creatorsName 2.5.18.3 dn
+attribute modifiersName 2.5.18.4 dn
+attribute subschemaSubentry 2.5.18.10 dn
+attribute attributeTypes 2.5.21.5 cis
+attribute objectClasses 2.5.21.6 cis
+attribute matchingRules 2.5.21.4 cis
+attribute matchingRuleUse 2.5.21.8 cis
+attribute dITStructureRules 2.5.21.1 cis
+attribute dITContentRules 2.5.21.2 cis
+attribute nameForms 2.5.21.7 cis
+
+attribute namingContexts 1.3.6.1.4.1.1466.101.120.5 dn
+attribute altServer 1.3.6.1.4.1.1466.101.120.6 ces
+attribute supportedExtension 1.3.6.1.4.1.1466.101.120.7 cis
+attribute supportedControl 1.3.6.1.4.1.1466.101.120.13 cis
+attribute supportedSASLMechanisms 1.3.6.1.4.1.1466.101.120.14 cis
+attribute supportedLDAPVersion 1.3.6.1.4.1.1466.101.120.15 int
+attribute ldapSyntaxes 1.3.6.1.4.1.1466.101.120.16 cis
+
+#######################################################################
+# Pilot X.500 schema for use in LDAPv3 #
+# Taken from <draft-ietf-asid-schema-pilot-00.txt> #
+#######################################################################
+
+attribute uid 0.9.2342.19200300.100.1.1 cis
+attribute textEncodedORAddress 0.9.2342.19200300.100.1.2 cis
+attribute mail rfc822mailbox 0.9.2342.19200300.100.1.3 cis
+attribute info 0.9.2342.19200300.100.1.4 cis
+attribute drink 0.9.2342.19200300.100.1.5 cis
+attribute roomNumber 0.9.2342.19200300.100.1.6 cis
+attribute userClass 0.9.2342.19200300.100.1.8 cis
+attribute host 0.9.2342.19200300.100.1.9 cis
+attribute manager 0.9.2342.19200300.100.1.10 dn
+attribute documentIdentifier 0.9.2342.19200300.100.1.11 cis
+attribute documentTitle 0.9.2342.19200300.100.1.12 cis
+attribute documentVersion 0.9.2342.19200300.100.1.13 cis
+attribute documentAuthor 0.9.2342.19200300.100.1.14 dn
+attribute documentLocation 0.9.2342.19200300.100.1.15 cis
+attribute homePhone 0.9.2342.19200300.100.1.20 tel
+attribute secretary 0.9.2342.19200300.100.1.21 dn
+attribute otherMailbox 0.9.2342.19200300.100.1.22 cis
+attribute dc domaincomponent 0.9.2342.19200300.100.1.25 cis
+attribute dNSRecord 0.9.2342.19200300.100.1.26 cis
+attribute associatedName 0.9.2342.19200300.100.1.38 dn
+attribute homePostalAddress 0.9.2342.19200300.100.1.39 cis
+attribute personalTitle 0.9.2342.19200300.100.1.40 cis
+attribute mobile mobileTelephoneNumber 0.9.2342.19200300.100.1.41 tel
+attribute pager pagerTelephoneNumber 0.9.2342.19200300.100.1.42 tel
+attribute co friendlycountryname 0.9.2342.19200300.100.1.43 cis
+attribute uniqueIdentifier 0.9.2342.19200300.100.1.44 cis
+attribute organizationalStatus 0.9.2342.19200300.100.1.45 cis
+attribute janetMailbox 0.9.2342.19200300.100.1.46 cis
+attribute mailPreferenceOption 0.9.2342.19200300.100.1.47 int single
+attribute buildingName 0.9.2342.19200300.100.1.48 cis
+attribute dSAQuality 0.9.2342.19200300.100.1.49 cis single
+attribute singleLevelQuality 0.9.2342.19200300.100.1.50 cis single
+attribute subtreeMinimumQuality 0.9.2342.19200300.100.1.51 cis single
+attribute subtreeMaximumQuality 0.9.2342.19200300.100.1.52 cis single
+attribute personalSignature 0.9.2342.19200300.100.1.53 bin
+attribute ditRedirect 0.9.2342.19200300.100.1.54 dn
+attribute audio 0.9.2342.19200300.100.1.55 bin
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis
+attribute jpegPhoto 0.9.2342.19200300.100.1.60 bin
+
+#definitions subsequent to RFC 1274
+
+attribute labeledUri labeledurl 1.3.6.1.4.1.250.1.57 ces
+
+
+############################################################################
+# Netscape Defined Attributes
+#
+# The Netscape base OID is 2.16.840.1.113730
+# The base OID for the Netscape Directory Server is 2.16.840.1.113730.3
+# Netscape defined attributes have base 2.16.840.1.113730.3.1
+#
+# More Netscape defined attributes can be found included in ns-schema.conf
+############################################################################
+
+attribute carLicense 2.16.840.1.113730.3.1.1 cis
+attribute departmentNumber 2.16.840.1.113730.3.1.2 cis
+attribute employeeNumber 2.16.840.1.113730.3.1.3 cis
+attribute employeeType 2.16.840.1.113730.3.1.4 cis
+attribute changeNumber 2.16.840.1.113730.3.1.5 int
+attribute targetDn 2.16.840.1.113730.3.1.6 dn
+attribute changeType 2.16.840.1.113730.3.1.7 cis
+attribute changes 2.16.840.1.113730.3.1.8 bin
+attribute newRdn 2.16.840.1.113730.3.1.9 dn
+attribute deleteOldRdn 2.16.840.1.113730.3.1.10 cis
+attribute newSuperior 2.16.840.1.113730.3.1.11 dn
+attribute ref 2.16.840.1.113730.3.1.34 ces
+attribute nsLicensedFor 2.16.840.1.113730.3.1.36 cis
+attribute nsLicenseStartTime 2.16.840.1.113730.3.1.37 cis
+attribute nsLicenseEndTime 2.16.840.1.113730.3.1.38 cis
+attribute preferredLanguage 2.16.840.1.113730.3.1.39 cis
+attribute userSMIMECertificate;binary 2.16.840.1.113730.3.1.40 bin
+attribute ntUserDomainId 2.16.840.1.113730.3.1.41 cis single
+attribute ntUserCreateNewAccount 2.16.840.1.113730.3.1.42 cis single
+attribute ntUserDeleteAccount 2.16.840.1.113730.3.1.43 cis single
+attribute ntGroupDomainId 2.16.840.1.113730.3.1.44 cis single
+attribute ntGroupCreateNewGroup 2.16.840.1.113730.3.1.45 cis single
+attribute ntGroupDeleteGroup 2.16.840.1.113730.3.1.46 cis single
+attribute ntGroupType 2.16.840.1.113730.3.1.47 cis single
+attribute replicaPort 2.16.840.1.113730.3.1.48 cis
+attribute replicaUpdateFailedAt 2.16.840.1.113730.3.1.49 cis
+attribute replicaBeginOrc 2.16.840.1.113730.3.1.50 cis
+attribute replicaUpdateReplayed 2.16.840.1.113730.3.1.51 cis
+attribute replicaUpdateSchedule 2.16.840.1.113730.3.1.52 cis
+attribute replicaBindMethod 2.16.840.1.113730.3.1.53 cis
+attribute replicaUseSSL 2.16.840.1.113730.3.1.54 cis
+attribute aci 2.16.840.1.113730.3.1.55 bin
+attribute lastModifiedBy 0.9.2342.19200300.100.1.24 dn
+attribute replicaRoot 2.16.840.1.113730.3.1.57 dn
+attribute replicaBindDn 2.16.840.1.113730.3.1.58 dn
+attribute ntUserPriv 2.16.840.1.113730.3.1.59 bin single
+attribute ntUserAuthFlags 2.16.840.1.113730.3.1.60 bin single
+attribute ntUserUsrComment 2.16.840.1.113730.3.1.61 cis single
+attribute ntUserParms 2.16.840.1.113730.3.1.62 cis single
+attribute ntUserUnitsPerWeek 2.16.840.1.113730.3.1.63 bin single
+attribute ntUserNumLogons 2.16.840.1.113730.3.1.64 bin single
+attribute ntUserLogonServer 2.16.840.1.113730.3.1.65 cis single
+attribute ntUserUniqueId 2.16.840.1.113730.3.1.66 bin single
+attribute ntUserProfile 2.16.840.1.113730.3.1.67 cis single
+attribute ntUserPasswordExpired 2.16.840.1.113730.3.1.68 bin single
+attribute subtreeACI 2.16.840.1.113730.3.1.69 ces
+attribute serverRoot 2.16.840.1.113730.3.1.70 cis
+attribute serverProductName 2.16.840.1.113730.3.1.71 cis
+attribute serverVersionNumber 2.16.840.1.113730.3.1.72 cis
+attribute installationTimeStamp 2.16.840.1.113730.3.1.73 cis
+attribute administratorContactInfo 2.16.840.1.113730.3.1.74 cis
+attribute adminUrl 2.16.840.1.113730.3.1.75 ces
+attribute serverHostName 2.16.840.1.113730.3.1.76 cis
+attribute changeTime 2.16.840.1.113730.3.1.77 cis
+attribute cirReplicaRoot 2.16.840.1.113730.3.1.79 dn
+attribute cirHost 2.16.840.1.113730.3.1.80 cis
+attribute cirPort 2.16.840.1.113730.3.1.81 cis
+attribute cirBindDn 2.16.840.1.113730.3.1.82 dn
+attribute cirUsePersistentSearch 2.16.840.1.113730.3.1.83 cis
+attribute cirUseSsl 2.16.840.1.113730.3.1.84 cis
+attribute cirBindCredentials 2.16.840.1.113730.3.1.85 ces
+attribute cirLastUpdateApplied 2.16.840.1.113730.3.1.86 cis
+attribute cirUpdateSchedule 2.16.840.1.113730.3.1.87 cis
+attribute cirUpdateFailedat 2.16.840.1.113730.3.1.88 cis
+attribute cirSyncInterval 2.16.840.1.113730.3.1.89 cis
+attribute cirBeginORC 2.16.840.1.113730.3.1.90 cis
+attribute passwordExpirationTime 2.16.840.1.113730.3.1.91 cis operational
+attribute passwordExpWarned 2.16.840.1.113730.3.1.92 cis operational
+attribute passwordRetryCount 2.16.840.1.113730.3.1.93 cis operational
+attribute retryCountResetTime 2.16.840.1.113730.3.1.94 cis operational
+attribute accountUnlockTime 2.16.840.1.113730.3.1.95 cis operational
+attribute passwordHistory 2.16.840.1.113730.3.1.96 bin operational
+attribute passwordMaxAge 2.16.840.1.113730.3.1.97 cis
+attribute passwordExp 2.16.840.1.113730.3.1.98 cis
+attribute passwordMinLength 2.16.840.1.113730.3.1.99 cis
+attribute passwordKeepHistory 2.16.840.1.113730.3.1.100 cis
+attribute passwordInHistory 2.16.840.1.113730.3.1.101 cis
+attribute passwordChange 2.16.840.1.113730.3.1.102 cis
+attribute passwordCheckSyntax 2.16.840.1.113730.3.1.103 cis
+attribute passwordWarning 2.16.840.1.113730.3.1.104 cis
+attribute passwordLockout 2.16.840.1.113730.3.1.105 cis
+attribute passwordMaxFailure 2.16.840.1.113730.3.1.106 cis
+attribute passwordResetDuration 2.16.840.1.113730.3.1.107 cis
+attribute passwordUnlock 2.16.840.1.113730.3.1.108 cis
+attribute passwordLockoutDuration 2.16.840.1.113730.3.1.109 cis
+attribute ntGroupId 2.16.840.1.113730.3.1.110 bin single
+attribute replicaHost 2.16.840.1.113730.3.1.197 cis
+attribute memberURL 2.16.840.1.113730.3.1.198 ces
+attribute memberCertificateDescription 2.16.840.1.113730.3.1.199 ces
+attribute replicaCredentials 2.16.840.1.113730.3.1.202 bin
+attribute replicaEntryFilter 2.16.840.1.113730.3.1.203 ces
+attribute replicaNickName 2.16.840.1.113730.3.1.204 cis
+attribute filterInfo 2.16.840.1.113730.3.1.206 cis
+attribute replicaCFUpdated 2.16.840.1.113730.3.1.217 cis
+attribute replicaAbandonedChanges 2.16.840.1.113730.3.1.218 cis
+
+#
+# Attribute types with OIDs
+#
+
+attribute associatedDomain 0.9.2342.19200300.100.1.37 cis
+attribute ntUserHomeDir 1.2.840.113556.1.4.44 cis single
+attribute ntUserComment 1.2.840.113556.1.4.156 cis single
+attribute ntUserFlags 1.2.840.113556.1.4.38 bin single
+attribute ntUserScriptPath 1.2.840.113556.1.4.62 cis single
+attribute ntUserWorkstations 1.2.840.113556.1.4.86 cis single
+attribute ntUserLastLogon 1.2.840.113556.1.4.52 cis single
+attribute ntUserLastLogoff 1.2.840.113556.1.4.51 cis single
+attribute ntUserAcctExpires 1.2.840.113556.1.4.159 cis single
+attribute ntUserMaxStorage 1.2.840.113556.1.4.76 bin single
+attribute ntUserLogonHours 1.2.840.113556.1.4.64 bin single
+attribute ntUserBadPwCount 1.2.840.113556.1.4.12 bin single
+attribute ntUserCountryCode 1.2.840.113556.1.4.25 cis single
+attribute ntUserCodePage 1.2.840.113556.1.4.16 bin single
+attribute ntUserPrimaryGroupId 1.2.840.113556.1.4.98 bin single
+attribute ntUserHomeDirDrive 1.2.840.113556.1.4.45 cis single
+attribute ntGroupAttributes 1.2.840.113556.1.4.152 bin single
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis single
+
+
+#
+# Attributes which are used by some objectClass, but with unknown OID
+#
+
+attribute abstract abstract-oid cis
+attribute authorCn documentauthorcommonname authorcn-oid cis
+attribute authorSn documentauthorsurname authorsn-oid cis
+attribute changeLog 2.16.840.1.113730.3.1.35 dn
+attribute changeLogMaximumAge 2.16.840.1.113730.3.1.200 cis
+attribute changeLogMaximumSize 2.16.840.1.113730.3.1.201 cis
+attribute documentStore documentStore-oid cis
+attribute keyWords keyWords-oid cis
+attribute lastModifiedTime 0.9.2342.19200300.100.1.23 cis
+attribute multiLineDescription multiLineDescription-oid cis
+attribute subject subject-oid cis
+attribute ttl timeToLive 1.3.6.1.4.1.250.1.60 cis
+attribute photo 0.9.2342.19200300.100.1.7 bin
+attribute generation generation-oid ces
+attribute obsoletedByDocument obsoletedByDocument-oid dn
+attribute obsoletesDocument obsoletesDocument-oid dn
+attribute reciprocalNamingLink reciprocalNaminglink-oid dn
+attribute updatedByDocument updatedByDocument-oid dn
+attribute updatesDocument updatesDocument-oid dn
+
diff --git a/ldap/cm/v3confs/slapd.oc.conf b/ldap/cm/v3confs/slapd.oc.conf
new file mode 100644
index 00000000..57e05f4b
--- /dev/null
+++ b/ldap/cm/v3confs/slapd.oc.conf
@@ -0,0 +1,779 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.oc.conf for Netscape Directory Server 3.1
+#
+# DO NOT MODIFY!
+#
+# The ObjectClasses in this file are Standard ObjectClasses and are expected
+# to be present in Directory Server 3.1 unchanged. Modifing this file may
+# cause interoperability problems.
+#
+# User Defined ObjectClasses should be added by selecting
+# Schema | Create ObjectClasses from the Admin Server.
+#
+# User Defined ObjectClasses are saved in slapd.user_oc.conf
+#
+# All ObjectClasses are viewable in the cn=schema entry under objectclasses.
+#
+# The format of this file is:
+#
+# objectclass ObjectClassName
+# [ oid ObjectIdentifier ]
+# [ superior ParentObjectClass ]
+# [ requires <comma separated list of required attributes> ]
+# [ allows <comma separated list of allowed attributes> ]
+#
+
+objectclass top
+ oid 2.5.6.0
+ requires
+ objectClass
+ allows
+ aci
+
+objectclass alias
+ oid 2.5.6.1
+ superior top
+ requires
+ aliasedObjectName
+
+objectclass country
+ oid 2.5.6.2
+ superior top
+ requires
+ c
+ allows
+ searchGuide,
+ description
+
+objectclass locality
+ oid 2.5.6.3
+ superior top
+ allows
+ description,
+ l,
+ searchGuide,
+ seeAlso,
+ st,
+ street
+
+objectclass organization
+ oid 2.5.6.4
+ superior top
+ requires
+ o
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass organizationalUnit
+ oid 2.5.6.5
+ superior top
+ requires
+ ou
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass person
+ oid 2.5.6.6
+ superior top
+ requires
+ sn,
+ cn
+ allows
+ description,
+ seeAlso,
+ telephoneNumber,
+ userPassword
+
+objectclass organizationalPerson
+ oid 2.5.6.7
+ superior person
+ allows
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ title,
+ x121Address
+
+objectclass inetOrgPerson
+ oid 2.16.840.1.113730.3.2.2
+ superior organizationalPerson
+ allows
+ audio,
+ businessCategory,
+ carLicense,
+ departmentNumber,
+ employeeType,
+ employeeNumber,
+ givenName,
+ homePhone,
+ homePostalAddress,
+ initials,
+ jpegPhoto,
+ labeledURI,
+ manager,
+ mobile,
+ pager,
+ photo,
+ preferredLanguage,
+ mail,
+ roomNumber,
+ secretary,
+ uid,
+ x500uniqueIdentifier,
+ userCertificate,
+ userCertificate;binary,
+ userSMimeCertificate;binary
+
+objectclass ntUser
+ oid 2.16.840.1.113730.3.2.8
+ superior top
+ requires
+ ntUserDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntUserPriv,
+ ntUserHomeDir,
+ ntUserComment,
+ ntUserFlags,
+ ntUserScriptPath,
+ ntUserAuthFlags,
+ ntUserUsrComment,
+ ntUserParms,
+ ntUserWorkstations,
+ ntUserLastLogon,
+ ntUserLastLogoff,
+ ntUserAcctExpires,
+ ntUserMaxStorage,
+ ntUserUnitsPerWeek,
+ ntUserLogonHours,
+ ntUserBadPwCount,
+ ntUserNumLogons,
+ ntUserLogonServer,
+ ntUserCountryCode,
+ ntUserCodePage,
+ ntUserUniqueId,
+ ntUserPrimaryGroupId,
+ ntUserProfile,
+ ntUserHomeDirDrive,
+ ntUserPasswordExpired,
+ ntUserCreateNewAccount,
+ ntUserDeleteAccount
+
+objectclass ntGroup
+ oid 2.16.840.1.113730.3.2.9
+ superior top
+ requires
+ ntGroupDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntGroupId,
+ ntGroupAttributes,
+ ntGroupCreateNewGroup,
+ ntGroupDeleteGroup,
+ ntGroupType
+
+objectclass organizationalRole
+ oid 2.5.6.8
+ superior top
+ requires
+ cn
+ allows
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ roleOccupant,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass groupOfNames
+ oid 2.5.6.9
+ superior top
+ requires
+ cn
+ allows
+ member,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfUniqueNames
+ oid 2.5.6.17
+ superior top
+ requires
+ cn
+ allows
+ uniqueMember,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfCertificates
+ oid 2.16.840.1.113730.3.2.31
+ superior top
+ requires
+ cn
+ allows
+ memberCertificateDescription,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfURLs
+ oid 2.16.840.1.113730.3.2.33
+ superior top
+ requires
+ cn
+ allows
+ memberURL,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass residentialPerson
+ oid 2.5.6.10
+ superior person
+ requires
+ l
+ allows
+ businessCategory,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass applicationProcess
+ oid 2.5.6.11
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso
+
+objectclass LDAPServer
+ oid 2.16.840.1.113730.3.2.35
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ generation,
+ changeLogMaximumAge,
+ changeLogMaximumSize
+
+objectclass LDAPReplica
+ oid 2.16.840.1.113730.3.2.36
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ replicaRoot,
+ replicaHost,
+ replicaPort,
+ replicaBindDn,
+ replicaCredentials,
+ replicaBindMethod,
+ replicaUseSSL,
+ replicaUpdateSchedule,
+ replicaUpdateReplayed,
+ replicaUpdateFailedAt,
+ replicaBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList,
+ replicaCFUpdated,
+ replicaAbandonedChanges
+
+objectclass applicationEntity
+ oid 2.5.6.12
+ superior top
+ requires
+ presentationAddress,
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ supportedApplicationContext
+
+objectclass dSA
+ oid 2.5.6.13
+ superior applicationEntity
+ allows
+ knowledgeInformation
+
+objectclass device
+ oid 2.5.6.14
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+objectclass strongAuthenticationUser
+ oid 2.5.6.15
+ superior top
+ requires
+ userCertificate,
+ userCertificate;binary
+
+objectclass certificationAuthority
+ oid 2.5.6.16
+ superior top
+ requires
+ cACertificate;binary
+ allows
+ authorityRevocationList;binary,
+ certificateRevocationList;binary,
+ crossCertificatePair;binary
+
+objectclass pilotObject
+ oid 0.9.2342.19200300.100.4.3
+ superior top
+ allows
+ audio,
+ dITRedirect,
+ info,
+ jpegPhoto,
+ lastModifiedBy,
+ lastModifiedTime,
+ manager,
+ photo,
+ uniqueIdentifier
+
+objectclass newPilotPerson
+ oid 0.9.2342.19200300.100.4.4
+ superior person
+ allows
+ businessCategory,
+ drink,
+ homePhone,
+ homePostalAddress,
+ janetMailbox,
+ mail,
+ mailPreferenceOption,
+ mobile,
+ organizationalStatus,
+ otherMailbox,
+ pager,
+ personalSignature,
+ personalTitle,
+ preferredDeliveryMethod,
+ roomNumber,
+ secretary,
+ textEncodedORAddress,
+ uid,
+ userClass
+
+objectclass account
+ oid 0.9.2342.19200300.100.4.5
+ superior top
+ requires
+ uid
+ allows
+ description,
+ host,
+ l,
+ o,
+ ou,
+ seeAlso
+
+objectclass document
+ oid 0.9.2342.19200300.100.4.6
+ superior pilotObject
+ requires
+ documentIdentifier
+ allows
+ abstract,
+ authorCN,
+ authorSN,
+ cn,
+ description,
+ documentAuthor,
+ documentLocation,
+ documentPublisher,
+ documentStore,
+ documentTitle,
+ documentVersion,
+ keywords,
+ l,
+ o,
+ obsoletedByDocument,
+ obsoletesDocument,
+ ou,
+ seeAlso,
+ subject,
+ updatedByDocument,
+ updatesDocument
+
+objectclass room
+ oid 0.9.2342.19200300.100.4.7
+ superior top
+ requires
+ cn
+ allows
+ description,
+ roomNumber,
+ seeAlso,
+ telephoneNumber
+
+objectclass documentSeries
+ oid 0.9.2342.19200300.100.4.9
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ telephoneNumber
+
+objectclass domain
+ oid 0.9.2342.19200300.100.4.13
+ superior top
+ requires
+ dc
+ allows
+ associatedName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ manager,
+ o,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass RFC822localPart
+ oid 0.9.2342.19200300.100.4.14
+ superior domain
+ allows
+ cn,
+ sn
+
+objectclass DNSDomain
+ oid 0.9.2342.19200300.100.4.15
+ superior domain
+ allows
+ dNSRecord
+
+objectclass domainRelatedObject
+ oid 0.9.2342.19200300.100.4.17
+ superior top
+ requires
+ associatedDomain
+
+objectclass friendlyCountry
+ oid 0.9.2342.19200300.100.4.18
+ superior country
+ requires
+ co
+
+objectclass simpleSecurityObject
+ oid 0.9.2342.19200300.100.4.19
+ superior top
+ requires
+ userPassword
+
+objectclass pilotOrganization
+ oid pilotOrganization-OID
+ superior top
+ requires
+ ou,
+ o
+ allows
+ buildingName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+
+objectclass labeledURIObject
+ oid 1.3.6.1.4.1.250.3.15
+ superior top
+ allows
+ labeledURI
+
+objectclass cacheObject
+ oid 1.3.6.1.4.1.250.3.18
+ superior top
+ allows
+ ttl
+
+# objectclasses below added since Netscape Directory Server 1.01
+
+objectclass netscapeServer
+ oid 2.16.840.1.113730.3.2.10
+ superior top
+ requires
+ cn
+ allows
+ description,
+ serverRoot,
+ serverProductName,
+ serverVersionNumber,
+ installationTimeStamp,
+ administratorContactInfo,
+ userpassword,
+ adminURL,
+ serverHostName
+
+objectclass nsLicenseUser
+ oid 2.16.840.1.113730.3.2.7
+ superior top
+ allows
+ nsLicensedFor,
+ nsLicenseStartTime,
+ nsLicenseEndTime
+
+objectclass changeLogEntry
+ oid 2.16.840.1.113730.3.2.1
+ superior top
+ requires
+ targetdn,
+ changeTime,
+ changenumber,
+ changeType
+ allows
+ changes,
+ newrdn,
+ deleteoldrdn,
+ newsuperior,
+ filterinfo
+
+objectclass cirReplicaSource
+ oid 2.16.840.1.113730.3.2.11
+ requires
+ cn
+ allows
+ cirReplicaRoot,
+ cirHost,
+ cirPort,
+ cirBindDN,
+ cirUsePersistentSearch,
+ cirUseSSL,
+ cirBindCredentials,
+ cirLastUpdateApplied,
+ cirUpdateSchedule,
+ cirSyncInterval,
+ cirUpdateFailedAt,
+ cirBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList
+
+objectclass referral
+ oid 2.16.840.1.113730.3.2.6
+ allows
+ ref
+
+objectclass passwordObject
+ oid 2.16.840.1.113730.3.2.12
+ requires
+ objectClass
+ allows
+ passwordExpirationTime,
+ passwordExpWarned,
+ passwordRetryCount,
+ retryCountResetTime,
+ accountUnlockTime,
+ passwordHistory
+
+objectclass passwordPolicy
+ oid 2.16.840.1.113730.3.2.13
+ requires
+ objectClass
+ allows
+ passwordMaxAge,
+ passwordExp,
+ passwordMinLength,
+ passwordKeepHistory,
+ passwordInHistory,
+ passwordChange,
+ passwordWarning,
+ passwordLockout,
+ passwordMaxFailure,
+ passwordResetDuration,
+ passwordUnlock,
+ passwordLockoutDuration,
+ passwordCheckSyntax
+
+objectclass glue
+ oid 2.16.840.1.113730.3.2.30
+ superior top
+
+objectclass netscapeMachineData
+ oid 2.16.840.1.113730.3.2.32
+ superior top
+
+objectclass dcObject
+ oid 1.3.6.1.4.1.1466.344
+ superior top
+ requires
+ dc
+
+objectclass subschema
+ oid 2.5.20.1
+ superior top
+ allows
+ cn,
+ dITStructureRules,
+ nameForms,
+ dITContentRules,
+ objectClasses,
+ attributeTypes,
+ matchingRules,
+ matchingRuleUse
diff --git a/ldap/cm/v4confs/40/java-object-schema.conf b/ldap/cm/v4confs/40/java-object-schema.conf
new file mode 100644
index 00000000..1ba36b8c
--- /dev/null
+++ b/ldap/cm/v4confs/40/java-object-schema.conf
@@ -0,0 +1,58 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Schema for storing java objects and java object references
+
+attribute javaClassName 1.3.6.1.4.1.42.2.27.4.1.6 ces single
+
+attribute javaCodebase 1.3.6.1.4.1.42.2.27.4.1.7 ces
+
+attribute javaSerializedData 1.3.6.1.4.1.42.2.27.4.1.8 bin single
+
+attribute javaFactory 1.3.6.1.4.1.42.2.27.4.1.10 ces single
+
+attribute javaReferenceAddress 1.3.6.1.4.1.42.2.27.4.1.11 ces
+
+attribute javaDoc 1.3.6.1.4.1.42.2.27.4.1.12 ces
+
+attribute javaClassNames 1.3.6.1.4.1.42.2.27.4.1.13 ces
+
+objectclass javaContainer
+ oid 1.3.6.1.4.1.42.2.27.4.2.1
+ superior top
+ requires
+ cn
+
+objectclass javaObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.4
+ superior top
+ requires
+ javaClassName
+ allows
+ javaClassNames,
+ javaCodebase,
+ javaDoc,
+ description
+
+objectclass javaSerializedObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.5
+ superior javaObject
+ requires
+ javaSerializedData
+
+objectclass javaNamingReference
+ oid 1.3.6.1.4.1.42.2.27.4.2.7
+ superior javaObject
+ allows
+ javaReferenceAddress,
+ javaFactory
+
+objectclass javaMarshalledObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.8
+ superior javaObject
+ requires
+ javaSerializedData
diff --git a/ldap/cm/v4confs/40/ns-admin-schema.conf b/ldap/cm/v4confs/40/ns-admin-schema.conf
new file mode 100644
index 00000000..0bd125de
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-admin-schema.conf
Binary files differ
diff --git a/ldap/cm/v4confs/40/ns-calendar-globopt.conf b/ldap/cm/v4confs/40/ns-calendar-globopt.conf
new file mode 100644
index 00000000..0bdb7dd9
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-calendar-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+index nsCalXItemId pres,eq,sub
diff --git a/ldap/cm/v4confs/40/ns-calendar-schema.conf b/ldap/cm/v4confs/40/ns-calendar-schema.conf
new file mode 100644
index 00000000..2a35ae3c
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-calendar-schema.conf
@@ -0,0 +1,148 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsCalAccess 2.16.840.1.113730.3.1.112 cis
+attribute nsCalAccessDomain 2.16.840.1.113730.3.1.113 cis
+attribute nsCalAdmd 2.16.840.1.113730.3.1.114 cis
+attribute nsCalDefaultNoteReminder 2.16.840.1.113730.3.1.115 cis
+attribute nsCalDefaultReminder 2.16.840.1.113730.3.1.116 cis
+attribute nsCalDefaultTaskReminder 2.16.840.1.113730.3.1.117 cis
+attribute nsCalDisplayPrefs 2.16.840.1.113730.3.1.118 cis
+attribute nsCalFlags 2.16.840.1.113730.3.1.119 cis
+attribute nsCalHost 2.16.840.1.113730.3.1.120 cis
+attribute nsCalLanguageId 2.16.840.1.113730.3.1.121 cis
+attribute nsCalNodeAlias 2.16.840.1.113730.3.1.122 cis
+attribute nsCalNotifMechanism 2.16.840.1.113730.3.1.123 cis
+attribute nsCalOperatingPrefs 2.16.840.1.113730.3.1.124 cis
+attribute nsCalOrgUnit2 2.16.840.1.113730.3.1.125 cis
+attribute nsCalOrgUnit3 2.16.840.1.113730.3.1.126 cis
+attribute nsCalOrgUnit4 2.16.840.1.113730.3.1.127 cis
+attribute nsCalPasswordRequired 2.16.840.1.113730.3.1.128 cis
+attribute nsCalPrmd 2.16.840.1.113730.3.1.129 cis
+attribute nsCalRefreshPrefs 2.16.840.1.113730.3.1.130 cis
+attribute nsCalResourceCapacity 2.16.840.1.113730.3.1.131 cis
+attribute nsCalResourceNumber 2.16.840.1.113730.3.1.132 cis
+attribute nsCalServerVersion 2.16.840.1.113730.3.1.133 cis
+attribute nsCalSysopCanWritePassword 2.16.840.1.113730.3.1.134 cis
+attribute nsCalTimezone 2.16.840.1.113730.3.1.135 cis
+attribute nsCalXItemId 2.16.840.1.113730.3.1.136 cis
+
+
+objectclass nsCalUser
+ oid 2.16.840.1.113730.3.2.14
+ requires
+ objectClass
+ allows
+ c,
+ employeeNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ mail,
+ o,
+ ou,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalRefreshPrefs,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass nsCalAdmin
+ oid 2.16.840.1.113730.3.2.15
+ requires
+ objectClass
+ allows
+ c,
+ cn,
+ facsimileTelephoneNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ mail,
+ o,
+ ou,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalXItemId
+
+objectclass nsCalResource
+ oid 2.16.840.1.113730.3.2.16
+ requires
+ objectClass
+ allows
+ cn,
+ facsimileTelephoneNumber,
+ givenName,
+ mail,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalPasswordRequired,
+ nsCalRefreshPrefs,
+ nsCalResourceCapacity,
+ nsCalResourceNumber,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass netscapeCalendarServer
+ oid 2.16.840.1.113730.3.2.17
+ requires
+ objectclass
+
+
+
diff --git a/ldap/cm/v4confs/40/ns-certificate-globopt.conf b/ldap/cm/v4confs/40/ns-certificate-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-certificate-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/40/ns-certificate-schema.conf b/ldap/cm/v4confs/40/ns-certificate-schema.conf
new file mode 100644
index 00000000..a9ef7b9d
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-certificate-schema.conf
@@ -0,0 +1,24 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+attribute nsCertConfig cis
+
+objectclass netscapeCertificateServer
+ oid 2.16.840.1.113730.3.2.18
+ requires
+ objectclass
+
+objectclass nsCertificateServer
+ requires
+ objectclass,
+ nsServerID
+ allows
+ serverHostName,
+ nsServerPort,
+ nsCertConfig
+
+
diff --git a/ldap/cm/v4confs/40/ns-common-schema.conf b/ldap/cm/v4confs/40/ns-common-schema.conf
new file mode 100644
index 00000000..3b934a1a
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-common-schema.conf
@@ -0,0 +1,245 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Common LDAP schema configuration file
+#
+# Version: 4.0
+# Description:
+# This configuration file contains objectclasses and attributes
+# common to the Mission Control Framework
+#
+
+#############################################################
+# Attributes
+#############################################################
+
+#
+# Common Attributes
+#
+attribute nsServerID cis
+attribute nsBaseDN cis
+attribute nsBindDN cis
+attribute nsBindPassword cis
+attribute nsServerPort cis
+attribute nsServerAddress cis
+attribute nsDirectoryInfoRef dn
+attribute nsDirectoryURL ces
+
+#
+# nsAdminDomain
+#
+attribute nsAdminDomainName cis
+
+#
+# nsHost
+#
+attribute nsHostLocation cis
+attribute nsHardwarePlatform cis
+attribute nsOsVersion cis
+
+#
+# nsAdminGroup
+#
+attribute nsAdminGroupName cis
+attribute nsConfigRoot cis
+attribute nsAdminSIEDN dn
+
+#
+# nsApplication
+#
+attribute nsVendor cis
+attribute nsProductName cis
+attribute nsNickName cis
+attribute nsProductVersion cis
+attribute nsBuildNumber cis
+attribute nsRevisionNumber cis
+attribute nsSerialNumber cis
+attribute nsInstalledLocation cis
+attribute nsExpirationDate cis
+attribute nsBuildSecurity cis
+attribute nsServerMigrationClassname cis
+attribute nsServerCreationClassname cis
+attribute nsLdapSchemaVersion cis
+
+#
+# nsConfig
+#
+attribute nsSuiteSpotUser cis
+attribute nsErrorLog cis
+attribute nsPidLog cis
+attribute nsAccessLog cis
+attribute nsDefaultAcceptLanguage cis
+attribute nsServerSecurity cis
+
+#
+# nsEncryptionConfig
+#
+attribute nsCertfile cis
+attribute nsKeyfile cis
+attribute nsSSL2 cis
+attribute nsSSL3 cis
+attribute nsSSLClientAuth cis
+attribute nsSSLSessionTimeout cis
+attribute nsSSL3SessionTimeout cis
+attribute nsSSL2Ciphers cis
+attribute nsSSL3Ciphers cis
+
+#
+# nsEncryptionModule
+#
+attribute nsSSLToken cis
+attribute nsSSLPersonalitySSL cis
+attribute nsSSLActivation cis
+
+#
+# nsTask
+#
+attribute nsTaskLabel cis
+attribute nsHelpRef cis
+attribute nsExecRef cis
+attribute nsLogSuppress cis
+
+#
+# nsAdminObject
+#
+attribute nsJarfilename cis
+attribute nsClassname cis
+
+
+#############################################################
+# Object Classes
+#############################################################
+objectclass nsAdminDomain
+ superior organizationalUnit
+ allows
+ nsAdminDomainName
+
+objectclass nsHost
+ superior top
+ requires
+ cn
+ allows
+ serverHostName,
+ description,
+ l,
+ nsHostLocation,
+ nsHardwarePlatform,
+ nsOsVersion
+
+objectclass nsAdminGroup
+ superior top
+ requires
+ cn
+ allows
+ nsAdminGroupName,
+ description,
+ nsConfigRoot,
+ nsAdminSIEDN
+
+objectclass nsApplication
+ superior top
+ requires
+ cn
+ allows
+ nsVendor,
+ description,
+ nsProductName,
+ nsNickName,
+ nsProductVersion,
+ nsBuildNumber,
+ nsRevisionNumber,
+ nsSerialNumber,
+ nsInstalledLocation,
+ installationTimeStamp,
+ nsExpirationDate,
+ nsBuildSecurity,
+ nsLdapSchemaVersion,
+ nsServerMigrationClassname,
+ nsServerCreationClassname
+
+objectclass nsEncryptionConfig
+ superior top
+ requires
+ cn
+ allows
+ nsCertfile,
+ nsKeyfile,
+ nsSSL2,
+ nsSSL3,
+ nsSSLSessionTimeout,
+ nsSSL3SessionTimeout,
+ nsSSLClientAuth,
+ nsSSL2Ciphers,
+ nsSSL3Ciphers
+
+objectclass nsEncryptionModule
+ superior top
+ requires
+ cn
+ allows
+ nsSSLToken,
+ nsSSLPersonalityssl,
+ nsSSLActivation
+
+
+objectclass nsResourceRef
+ superior top
+ requires
+ cn
+ allows
+ seeAlso
+
+objectclass nsTask
+ superior top
+ requires
+ cn
+ allows
+ nsTaskLabel,
+ nsHelpref,
+ nsExecref,
+ nsLogSuppress
+
+objectclass nsTaskGroup
+ superior top
+ requires
+ cn
+ allows
+ nsTaskLabel
+
+objectclass nsAdminObject
+ superior top
+ requires
+ cn
+ allows
+ nsJarFilename,
+ nsClassName
+
+objectclass nsConfig
+ superior top
+ requires
+ cn
+ allows
+ description,
+ nsServerPort,
+ nsServerAddress,
+ nsSuiteSpotUser,
+ nsErrorLog,
+ nsPidLog,
+ nsAccessLog,
+ nsDefaultAcceptLanguage,
+ nsServerSecurity
+
+objectclass nsDirectoryInfo
+ superior top
+ requires
+ cn
+ allows
+ nsBindDN,
+ nsBindPassword,
+ nsDirectoryURL,
+ nsDirectoryInfoRef
diff --git a/ldap/cm/v4confs/40/ns-compass-globopt.conf b/ldap/cm/v4confs/40/ns-compass-globopt.conf
new file mode 100644
index 00000000..4d2e1e21
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-compass-globopt.conf
@@ -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
+#
+# Used by Netscape Directory Server
+index pipuid pres,eq,sub
+index pipstatus eq
+
diff --git a/ldap/cm/v4confs/40/ns-compass-schema.conf b/ldap/cm/v4confs/40/ns-compass-schema.conf
new file mode 100644
index 00000000..be13bc44
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-compass-schema.conf
@@ -0,0 +1,173 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+
+# Compass server specific (not currently used)
+
+objectclass netscapeCompassServer
+ oid 2.16.840.1.113730.3.2.19
+ requires
+ objectclass
+
+
+# Attributes for personal interest profile classes
+
+attribute pipuid 2.16.840.1.113730.3.1.137 cis
+attribute pipcompassservers 2.16.840.1.113730.3.1.138 cis
+attribute pipuniqueid 2.16.840.1.113730.3.1.139 cis
+attribute pipstatus 2.16.840.1.113730.3.1.140 cis
+attribute pipusertype 2.16.840.1.113730.3.1.141 cis
+attribute pipfrequency 2.16.840.1.113730.3.1.142 cis
+attribute pipmedium 2.16.840.1.113730.3.1.143 cis
+attribute pipformat 2.16.840.1.113730.3.1.144 cis
+attribute piphour 2.16.840.1.113730.3.1.145 cis
+attribute pipmaxhits 2.16.840.1.113730.3.1.146 cis
+attribute pipresultset 2.16.840.1.113730.3.1.147 cis
+attribute pipsortorder 2.16.840.1.113730.3.1.148 cis
+attribute piptimestamp 2.16.840.1.113730.3.1.149 cis
+attribute pipirlist 2.16.840.1.113730.3.1.150 cis
+attribute pipiroption 2.16.840.1.113730.3.1.151 cis
+attribute pippwp 2.16.840.1.113730.3.1.152 cis
+attribute piplastcount 2.16.840.1.113730.3.1.153 cis
+attribute piptotalcount 2.16.840.1.113730.3.1.154 cis
+attribute piptotalrun 2.16.840.1.113730.3.1.155 cis
+attribute pipnotify 2.16.840.1.113730.3.1.156 cis
+attribute pipprivilege 2.16.840.1.113730.3.1.157 cis
+attribute pipgroup 2.16.840.1.113730.3.1.158 cis
+attribute pipidstcount 2.16.840.1.113730.3.1.159 cis
+attribute pipstid 2.16.840.1.113730.3.1.160 cis
+attribute pipstname 2.16.840.1.113730.3.1.161 cis
+attribute pipstquery 2.16.840.1.113730.3.1.162 cis
+attribute pipsttaxonomy 2.16.840.1.113730.3.1.163 cis
+attribute pipstinterest 2.16.840.1.113730.3.1.164 cis
+attribute pipsttype 2.16.840.1.113730.3.1.165 cis
+attribute pipstprivacy 2.16.840.1.113730.3.1.166 cis
+attribute pipststatus 2.16.840.1.113730.3.1.167 cis
+attribute pipstlastcount 2.16.840.1.113730.3.1.168 cis
+attribute pipsttotalcount 2.16.840.1.113730.3.1.169 cis
+attribute pipsttotalrun 2.16.840.1.113730.3.1.170 cis
+attribute pipstcategory 2.16.840.1.113730.3.1.171 cis
+attribute pipstfrequency 2.16.840.1.113730.3.1.172 cis
+attribute pipstmedium 2.16.840.1.113730.3.1.173 cis
+attribute pipstformat 2.16.840.1.113730.3.1.174 cis
+attribute pipsthour 2.16.840.1.113730.3.1.175 cis
+attribute pipstmaxhits 2.16.840.1.113730.3.1.176 cis
+attribute pipstresultset 2.16.840.1.113730.3.1.177 cis
+attribute pipstsortorder 2.16.840.1.113730.3.1.178 cis
+attribute pipsttimestamp 2.16.840.1.113730.3.1.179 cis
+attribute pipstirlist 2.16.840.1.113730.3.1.180 cis
+attribute pipstiroption 2.16.840.1.113730.3.1.181 cis
+attribute pipreservedcis1 2.16.840.1.113730.3.1.182 cis
+attribute pipreservedcis2 2.16.840.1.113730.3.1.183 cis
+attribute pipreservedcis3 2.16.840.1.113730.3.1.184 cis
+attribute pipreservedcis4 2.16.840.1.113730.3.1.185 cis
+attribute pipreservedcis5 2.16.840.1.113730.3.1.186 cis
+attribute pipreservedcis6 2.16.840.1.113730.3.1.187 cis
+attribute pipreservedces1 2.16.840.1.113730.3.1.188 ces
+attribute pipreservedces2 2.16.840.1.113730.3.1.189 ces
+attribute pipreservedces3 2.16.840.1.113730.3.1.190 ces
+
+
+# Each interest profile is one of these and sits under the compass SIE
+
+objectclass personalInterestProfile
+ oid 2.16.840.1.113730.3.2.20
+ requires
+ objectclass,
+ pipuid
+ allows
+ pipuniqueid,
+ pipstatus,
+ pipusertype,
+ pipfrequency,
+ pipmedium,
+ pipformat,
+ piphour,
+ pipmaxhits,
+ pipresultset,
+ pipsortorder,
+ piptimestamp,
+ pipirlist,
+ pipiroption,
+ pippwp,
+ piplastcount,
+ piptotalcount,
+ piptotalrun,
+ pipnotify,
+ pipprivilege,
+ pipgroup,
+ pipidstcount,
+ pipstid,
+ pipstname,
+ pipstquery,
+ pipsttaxonomy,
+ pipstinterest,
+ pipsttype,
+ pipstprivacy,
+ pipststatus,
+ pipstlastcount,
+ pipsttotalcount,
+ pipsttotalrun,
+ pipstcategory,
+ pipstfrequency,
+ pipstmedium,
+ pipstformat,
+ pipsthour,
+ pipstmaxhits,
+ pipstresultset,
+ pipstsortorder,
+ pipsttimestamp,
+ pipstirlist,
+ pipstiroption,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
+
+# Replication of user info for template users, completeness, etc.
+# (not currently used)
+
+objectclass PIPUserInfo
+ oid 2.16.840.1.113730.3.2.21
+ requires
+ objectclass
+ allows
+ cn,
+ mail,
+ userPassword,
+ description,
+ pipcompassservers,
+ pipuniqueid
+
+
+# Enhancements to a normal user entry (not currently used)
+
+objectclass PIPUser
+ oid 2.16.840.1.113730.3.2.22
+ requires
+ objectclass
+ allows
+ pipuniqueid,
+ pipcompassservers,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
diff --git a/ldap/cm/v4confs/40/ns-cos-schema.conf b/ldap/cm/v4confs/40/ns-cos-schema.conf
new file mode 100644
index 00000000..3d0f9f1a
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-cos-schema.conf
@@ -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
+#
+# Attributes used by Class of Service
+
+attribute cosAttribute 2.16.840.1.113730.3.1.550 cis
+attribute cosSpecifier 2.16.840.1.113730.3.1.551 cis
+attribute cosTargetTree 2.16.840.1.113730.3.1.552 cis
+attribute cosTemplateDn 2.16.840.1.113730.3.1.553 cis
+
+# Object classes used by Class of Service
+
+objectclass cosDefinition
+ oid 2.16.840.1.113730.3.2.84
+ superior top
+ requires
+ objectclass
+ allows
+ aci,
+ cn,
+ uid,
+ costargettree,
+ costemplatedn,
+ cosspecifier,
+ cosattribute
diff --git a/ldap/cm/v4confs/40/ns-delegated-admin-schema.conf b/ldap/cm/v4confs/40/ns-delegated-admin-schema.conf
new file mode 100644
index 00000000..b25c9146
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-delegated-admin-schema.conf
@@ -0,0 +1,62 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Netscape Delegated Administrator LDAP Schema
+#
+# Version: 1.0
+#
+# Attributes and objectclasses for:
+#
+# Netscape Delegated Administrator 1.0
+#
+# DT 9/24/98
+
+#############################################################
+# Delegated User Administration Attributes
+#############################################################
+
+attribute nsNumUsers cis
+attribute nsMaxUsers cis
+attribute nsNumDepts cis
+attribute nsMaxDepts cis
+attribute nsNumDomains cis
+attribute nsDefaultMaxDeptSize cis
+attribute nsSearchFilter cis
+
+#############################################################
+# Delegated User Administration Objectclasses
+#############################################################
+
+objectclass nsManagedISP
+ superior top
+ allows
+ nsNumDomains
+
+objectclass nsManagedDomain
+ superior top
+ allows
+ owner,
+ nsNumUsers,
+ nsMaxUsers,
+ nsNumDepts,
+ nsMaxDepts,
+ nsDefaultMaxDeptSize
+
+objectclass nsManagedDept
+ superior groupofuniquenames
+ allows
+ owner,
+ nsNumUsers,
+ nsMaxUsers
+
+objectclass nsManagedPerson
+ superior top
+ allows
+ owner,
+ nsSearchFilter
+
diff --git a/ldap/cm/v4confs/40/ns-directory-globopt.conf b/ldap/cm/v4confs/40/ns-directory-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-directory-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/40/ns-directory-schema.conf b/ldap/cm/v4confs/40/ns-directory-schema.conf
new file mode 100644
index 00000000..d928081f
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-directory-schema.conf
@@ -0,0 +1,27 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsSecureServerPort cis
+
+objectclass netscapeDirectoryServer
+ oid 2.16.840.1.113730.3.2.23
+ requires
+ objectclass
+
+objectclass nsDirectoryServer
+ requires
+ objectclass,
+ nsServerID
+ allows
+ serverHostName,
+ nsServerPort,
+ nsSecureServerPort,
+ nsBindPassword,
+ nsBindDN,
+ nsBaseDN
diff --git a/ldap/cm/v4confs/40/ns-legacy-schema.conf b/ldap/cm/v4confs/40/ns-legacy-schema.conf
new file mode 100644
index 00000000..88424b82
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-legacy-schema.conf
@@ -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
+#
+attribute url cis
+
+#use by Netscape Admin Server 4.0 for LegacyServers
+
+objectclass nsLegacyAdminGroup
+ superior
+ nsAdminGroup
+ allows
+ adminUrl
+
+objectclass nsLegacyApplication
+ superior
+ nsApplication
+ allows
+
+objectclass nsLegacyAdminServer
+ superior
+ nsAdminServer
+ allows
+
+objectclass nsLegacyServer
+ superior
+ netscapeServer
+ allows
+ nsServerID,
+ url
diff --git a/ldap/cm/v4confs/40/ns-mail-globopt.conf b/ldap/cm/v4confs/40/ns-mail-globopt.conf
new file mode 100644
index 00000000..2e6cac65
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-mail-globopt.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Messaging Server
+index mailAlternateAddress eq
+index mailHost eq
+#index uid,mail eq
+#index uniquemember,member eq
diff --git a/ldap/cm/v4confs/40/ns-mail-schema.conf b/ldap/cm/v4confs/40/ns-mail-schema.conf
new file mode 100644
index 00000000..13af6135
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-mail-schema.conf
@@ -0,0 +1,132 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+attribute mailAccessDomain 2.16.840.1.113730.3.1.12 cis
+attribute mailAlternateAddress 2.16.840.1.113730.3.1.13 cis
+attribute mailAutoReplyMode 2.16.840.1.113730.3.1.14 cis
+attribute mailAutoReplyText 2.16.840.1.113730.3.1.15 cis
+attribute mailDeliveryOption 2.16.840.1.113730.3.1.16 cis
+attribute mailForwardingAddress 2.16.840.1.113730.3.1.17 cis
+attribute mailHost 2.16.840.1.113730.3.1.18 cis
+attribute mailQuota 2.16.840.1.113730.3.1.21 cis
+attribute mailRoutingAddress 2.16.840.1.113730.3.1.47 cis
+
+attribute mailMessageStore 2.16.840.1.113730.3.1.19 ces
+attribute mailProgramDeliveryInfo 2.16.840.1.113730.3.1.20 ces
+
+# mailRecipient is used to designate an LDAP entry as representing some
+# entity that can receive mail, e.g. a mail user or mail group.
+# Note: attributes 'mailAccessDomain' through 'userPassword' do not
+# belong to mailRecipient, but are included here for backward compatibility.
+objectClass mailRecipient
+ oid 2.16.840.1.113730.3.2.3
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mailAccessDomain,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota,
+ multiLineDescription,
+ uid,
+ userPassword
+
+# nsMessagingServerUser is used to designate an LDAP entry as representing a
+# Netscape Messaging Server user account. It is used in combination with
+# mailRecipient.
+objectClass nsMessagingServerUser
+ oid 2.16.840.113730.3.2.37
+ requires
+ objectClass
+ allows
+ cn,
+ mailAccessDomain,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota
+
+attribute mgrpAllowedDomain 2.16.840.1.113730.3.1.23 cis
+attribute mgrpMsgRejectAction 2.16.840.1.113730.3.1.28 cis
+attribute mgrpRFC822MailMember 2.16.840.1.113730.3.1.30 cis
+attribute mgrpMsgMaxSize 2.16.840.1.113730.3.1.32 cis single
+attribute mgrpBroadcasterPolicy cis single
+attribute mgrpNoDuplicateChecks cis single
+attribute mgrpRemoveHeader cis
+
+attribute mgrpAllowedBroadcaster 2.16.840.1.113730.3.1.22 ces
+attribute mgrpDeliverTo 2.16.840.1.113730.3.1.25 ces
+attribute mgrpErrorsTo 2.16.840.1.113730.3.1.26 ces single
+attribute mgrpModerator 2.16.840.1.113730.3.1.33 ces
+attribute mgrpMsgRejectText 2.16.840.1.113730.3.1.29 ces
+attribute mgrpAddHeader ces
+
+attribute mgrpApprovePassword ces single
+
+# mailGroup is used to designate an LDAP entry as representing a mail group
+# (mailing list). It is used in combination with mailRecipient.
+# Note: attributes 'mail' through 'mailRoutingAddress' belong to mailRecipient,
+# but are also included here for backward compatibility.
+objectClass mailGroup
+ oid 2.16.840.1.113730.3.2.4
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mgrpAddHeader,
+ mgrpAllowedBroadcaster,
+ mgrpAllowedDomain,
+ mgrpApprovePassword,
+ mgrpBroadcasterPolicy,
+ mgrpDeliverTo,
+ mgrpErrorsTo,
+ mgrpModerator,
+ mgrpMsgMaxSize,
+ mgrpMsgRejectAction,
+ mgrpMsgRejectText,
+ mgrpNoDuplicateChecks,
+ mgrpRemoveHeader,
+ mgrpRFC822MailMember,
+ owner
+
+attribute mailEnhancedUniqueMember 2.16.840.1.113730.3.1.31 dn
+
+objectClass groupOfMailEnhancedUniqueNames
+ oid 2.16.840.1.113730.3.2.5
+ requires
+ objectClass,
+ cn
+ allows
+ businessCategory,
+ description,
+ mailEnhancedUniqueMember,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectClass netscapeMailServer
+ oid 2.16.840.1.113730.3.2.24
+ requires
+ objectClass
diff --git a/ldap/cm/v4confs/40/ns-mcd-browser-schema.conf b/ldap/cm/v4confs/40/ns-mcd-browser-schema.conf
new file mode 100644
index 00000000..dd2e228f
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-mcd-browser-schema.conf
@@ -0,0 +1,179 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-browser-schema.conf
+#
+# Netscape Mission Control Desktop browser client schema
+# This schema is used to hold browser client preferences.
+#
+
+attribute nsBCStartupBrowser 2.16.840.1.113730.3.1.409 cis
+attribute nsBCStartupMail 2.16.840.1.113730.3.1.410 cis
+attribute nsBCStartupEditor 2.16.840.1.113730.3.1.411 cis
+attribute nsBCStartupCalendar 2.16.840.1.113730.3.1.412 cis
+attribute nsBCChromeButtonStyle 2.16.840.1.113730.3.1.413 cis
+attribute nsBCUseDocumentFonts 2.16.840.1.113730.3.1.414 cis
+attribute nsBCForegroundColor 2.16.840.1.113730.3.1.415 cis
+attribute nsBCBackgroundColor 2.16.840.1.113730.3.1.416 cis
+attribute nsBCAnchorColor 2.16.840.1.113730.3.1.417 cis
+attribute nsBCVisitedColor 2.16.840.1.113730.3.1.418 cis
+attribute nsBCUnderlineAnchors 2.16.840.1.113730.3.1.419 cis
+attribute nsBCUseDocumentColors 2.16.840.1.113730.3.1.420 cis
+attribute nsBCStartupPage 2.16.840.1.113730.3.1.421 cis
+attribute nsBCStartupHomePage 2.16.840.1.113730.3.1.422 cis
+attribute nsBCLinkExpiration 2.16.840.1.113730.3.1.423 cis
+attribute nsBCIntlAcceptLanguages 2.16.840.1.113730.3.1.424 cis
+attribute nsBCMimeType 2.16.840.1.113730.3.1.425 cis
+attribute nsBCMimeAllowAdd 2.16.840.1.113730.3.1.426 cis
+attribute nsBCMimeAllowEdit 2.16.840.1.113730.3.1.427 cis
+attribute nsBCMimeAllowRemove 2.16.840.1.113730.3.1.428 cis
+attribute nsBCRelatedEnabled 2.16.840.1.113730.3.1.429 cis
+attribute nsBCRelatedAutoload 2.16.840.1.113730.3.1.430 cis
+attribute nsBCRelatedDisabledForDomains 2.16.840.1.113730.3.1.431 cis
+attribute nsBCGoBrowsingEnabled 2.16.840.1.113730.3.1.432 cis
+attribute nsBCOfflineStartupState 2.16.840.1.113730.3.1.433 cis
+attribute nsBCOfflineSendUnsentMessages 2.16.840.1.113730.3.1.434 cis
+attribute nsBCOfflinePromptSynchOnExit 2.16.840.1.113730.3.1.435 cis
+attribute nsBCAlwaysLoadImages 2.16.840.1.113730.3.1.436 cis
+attribute nsBCEnableJava 2.16.840.1.113730.3.1.437 cis
+attribute nsBCEnableJavaScript 2.16.840.1.113730.3.1.438 cis
+attribute nsBCEnableStyleSheets 2.16.840.1.113730.3.1.439 cis
+attribute nsBCEmailAsFtpPassword 2.16.840.1.113730.3.1.440 cis
+attribute nsBCCookieBehavior 2.16.840.1.113730.3.1.441 cis
+attribute nsBCWarnAboutCookies 2.16.840.1.113730.3.1.442 cis
+attribute nsBCMemoryCacheSize 2.16.840.1.113730.3.1.443 cis
+attribute nsBCDiskCacheSize 2.16.840.1.113730.3.1.444 cis
+attribute nsBCCheckDocFrequency 2.16.840.1.113730.3.1.445 cis
+attribute nsBCProxyType 2.16.840.1.113730.3.1.446 cis
+attribute nsBCProxyHttp 2.16.840.1.113730.3.1.447 cis
+attribute nsBCProxySsl 2.16.840.1.113730.3.1.448 cis
+attribute nsBCProxyFtp 2.16.840.1.113730.3.1.449 cis
+attribute nsBCProxySocks 2.16.840.1.113730.3.1.450 cis
+attribute nsBCProxyGopher 2.16.840.1.113730.3.1.451 cis
+attribute nsBCProxyWais 2.16.840.1.113730.3.1.452 cis
+attribute nsBCNoProxiesOn 2.16.840.1.113730.3.1.453 cis
+attribute nsBCProxyAutoConfigUrl 2.16.840.1.113730.3.1.454 cis
+attribute nsBCAutoUpdateEnabled 2.16.840.1.113730.3.1.455 cis
+attribute nsBCAutoUpdateConfirmInstall 2.16.840.1.113730.3.1.456 cis
+
+
+objectclass nsBrowserClient
+ oid 2.16.840.1.113730.3.2.78
+ superior top
+ allows
+ nsBCStartupBrowser,
+ nsBCStartupMail,
+ nsBCStartupEditor,
+ nsBCStartupCalendar,
+ nsBCChromeButtonStyle,
+ nsBCUseDocumentFonts,
+ nsBCForegroundColor,
+ nsBCBackgroundColor,
+ nsBCAnchorColor,
+ nsBCVisitedColor,
+ nsBCUnderlineAnchors,
+ nsBCUseDocumentColors,
+ nsBCStartupPage,
+ nsBCStartupHomePage,
+ nsBCLinkExpiration,
+ nsBCIntlAcceptLanguages,
+ nsBCMimeType,
+ nsBCMimeAllowAdd,
+ nsBCMimeAllowEdit,
+ nsBCMimeAllowRemove,
+ nsBCRelatedEnabled,
+ nsBCRelatedAutoload,
+ nsBCRelatedDisabledForDomains,
+ nsBCGoBrowsingEnabled,
+ nsBCOfflineStartupState,
+ nsBCOfflineSendUnsentMessages,
+ nsBCOfflinePromptSynchOnExit,
+ nsBCAlwaysLoadImages,
+ nsBCEnableJava,
+ nsBCEnableJavaScript,
+ nsBCEnableStyleSheets,
+ nsBCEmailAsFtpPassword,
+ nsBCCookieBehavior,
+ nsBCWarnAboutCookies,
+ nsBCMemoryCacheSize,
+ nsBCDiskCacheSize,
+ nsBCCheckDocFrequency,
+ nsBCProxyType,
+ nsBCProxyHttp,
+ nsBCProxySsl,
+ nsBCProxyFtp,
+ nsBCProxySocks,
+ nsBCProxyGopher,
+ nsBCProxyWais,
+ nsBCNoProxiesOn,
+ nsBCProxyAutoConfigUrl,
+ nsBCAutoUpdateEnabled,
+ nsBCAutoUpdateConfirmInstall
+
+#
+# Netscape Mission Control Desktop browser security schema
+# This schema is used to hold browser security preferences.
+#
+
+attribute nsBSAskForPassword 2.16.840.1.113730.3.1.457 cis
+attribute nsBSPasswordLifetime 2.16.840.1.113730.3.1.458 cis
+attribute nsBSWarnEnteringSecure 2.16.840.1.113730.3.1.459 cis
+attribute nsBSWarnLeavingSecure 2.16.840.1.113730.3.1.460 cis
+attribute nsBSWarnViewingMixed 2.16.840.1.113730.3.1.461 cis
+attribute nsBSWarnSubmitInsecure 2.16.840.1.113730.3.1.462 cis
+attribute nsBSEnableSsl2 2.16.840.1.113730.3.1.463 cis
+attribute nsBSEnableSsl3 2.16.840.1.113730.3.1.464 cis
+attribute nsBSCertmgmtDisableFunctionMsg 2.16.840.1.113730.3.1.465 cis
+attribute nsBSSsl2Rc4128 2.16.840.1.113730.3.1.466 cis
+attribute nsBSSsl2Rc2128 2.16.840.1.113730.3.1.467 cis
+attribute nsBSSsl2DesEd3192 2.16.840.1.113730.3.1.468 cis
+attribute nsBSSsl2Des64 2.16.840.1.113730.3.1.469 cis
+attribute nsBSSsl2Rc440 2.16.840.1.113730.3.1.470 cis
+attribute nsBSSsl2Rc240 2.16.840.1.113730.3.1.471 cis
+attribute nsBSSsl3RsaRc4128Md5 2.16.840.1.113730.3.1.472 cis
+attribute nsBSSsl3FipsDesEd3Sha 2.16.840.1.113730.3.1.473 cis
+attribute nsBSSsl3RsaRc4128Md5 2.16.840.1.113730.3.1.474 cis
+attribute nsBSSsl3RsaFipsDesSha 2.16.840.1.113730.3.1.475 cis
+attribute nsBSSsl3RsaDesSha 2.16.840.1.113730.3.1.476 cis
+attribute nsBSSsl3RsaRc440Md5 2.16.840.1.113730.3.1.477 cis
+attribute nsBSSsl3RsaRc240Md5 2.16.840.1.113730.3.1.478 cis
+attribute nsBSSsl3RsaNullMd5 2.16.840.1.113730.3.1.479 cis
+attribute nsBSSsl3FortezzaFortezzaSha 2.16.840.1.113730.3.1.480 cis
+attribute nsBSSsl3FortezzaRc4Sha 2.16.840.1.113730.3.1.481 cis
+
+
+objectclass nsBrowserSecurity
+ oid 2.16.840.1.113730.3.2.79
+ superior top
+ allows
+ nsBSAskForPassword,
+ nsBSPasswordLifetime,
+ nsBSWarnEnteringSecure,
+ nsBSWarnLeavingSecure,
+ nsBSWarnViewingMixed,
+ nsBSWarnSubmitInsecure,
+ nsBSEnableSsl2,
+ nsBSEnableSsl3,
+ nsBSCertmgmtDisableFunctionMsg,
+ nsBSSsl2Rc4128,
+ nsBSSsl2Rc2128,
+ nsBSSsl2DesEd3192,
+ nsBSSsl2Des64,
+ nsBSSsl2Rc440,
+ nsBSSsl2Rc240,
+ nsBSSsl3RsaRc4128Md5,
+ nsBSSsl3FipsDesEd3Sha,
+ nsBSSsl3RsaRc4128Md5,
+ nsBSSsl3RsaFipsDesSha,
+ nsBSSsl3RsaDesSha,
+ nsBSSsl3RsaRc440Md5,
+ nsBSSsl3RsaRc240Md5,
+ nsBSSsl3RsaNullMd5,
+ nsBSSsl3FortezzaFortezzaSha,
+ nsBSSsl3FortezzaRc4Sha
+
diff --git a/ldap/cm/v4confs/40/ns-mcd-config-schema.conf b/ldap/cm/v4confs/40/ns-mcd-config-schema.conf
new file mode 100644
index 00000000..7076bbc7
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-mcd-config-schema.conf
@@ -0,0 +1,55 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-config-schema.conf
+#
+# Netscape Mission Control Desktop schema
+# This schema is used to set MCD "config()" preferences.
+#
+
+attribute nsMcdUserAgent 2.16.840.1.113730.3.1.482 cis
+attribute nsMcdUseXSender 2.16.840.1.113730.3.1.483 cis
+attribute nsMcdToolbarLogoUrl 2.16.840.1.113730.3.1.484 cis
+attribute nsMcdToolbarLogoWinSmallFile 2.16.840.1.113730.3.1.485 cis
+attribute nsMcdToolbarLogoWinLargeFile 2.16.840.1.113730.3.1.486 cis
+attribute nsMcdToolbarLogoFrames 2.16.840.1.113730.3.1.487 cis
+attribute nsMcdMacAnimationFile 2.16.840.1.113730.3.1.488 cis
+attribute nsMcdXAnimationFile 2.16.840.1.113730.3.1.489 cis
+attribute nsMcdNetSearchUrl 2.16.840.1.113730.3.1.490 cis
+attribute nsMcdMoreInfoPluginUrl 2.16.840.1.113730.3.1.491 cis
+attribute nsMcdAutoAdminConfigUrl 2.16.840.1.113730.3.1.492 cis
+attribute nsMcdAutoAdminAppendEmail 2.16.840.1.113730.3.1.493 cis
+attribute nsMcdAutoAdminRefreshInterval 2.16.840.1.113730.3.1.494 cis
+attribute nsMcdUseGuideButton 2.16.840.1.113730.3.1.495 cis
+attribute nsMcdGuideButtonProperties 2.16.840.1.113730.3.1.496 cis
+attribute nsMcdGuideMenuProperties 2.16.840.1.113730.3.1.497 cis
+attribute nsMcdHelpMenuProperties 2.16.840.1.113730.3.1.498 cis
+
+
+objectclass nsMcdConfig
+ oid 2.16.840.1.113730.3.2.80
+ superior top
+ allows
+ nsMcdUserAgent,
+ nsMcdUseXSender,
+ nsMcdToolbarLogoUrl,
+ nsMcdToolbarLogoWinSmallFile,
+ nsMcdToolbarLogoWinLargeFile,
+ nsMcdToolbarLogoFrames,
+ nsMcdMacAnimationFile,
+ nsMcdXAnimationFile,
+ nsMcdNetSearchUrl,
+ nsMcdMoreInfoPluginUrl,
+ nsMcdAutoAdminConfigUrl,
+ nsMcdAutoAdminAppendEmail,
+ nsMcdAutoAdminRefreshInterval,
+ nsMcdUseGuideButton,
+ nsMcdGuideButtonProperties,
+ nsMcdGuideMenuProperties,
+ nsMcdHelpMenuProperties
+
diff --git a/ldap/cm/v4confs/40/ns-mcd-li-globopt.conf b/ldap/cm/v4confs/40/ns-mcd-li-globopt.conf
new file mode 100644
index 00000000..57a75555
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-mcd-li-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Index required by Mission Control Desktop: Location Independence
+index nsLIProfileName eq
diff --git a/ldap/cm/v4confs/40/ns-mcd-li-schema.conf b/ldap/cm/v4confs/40/ns-mcd-li-schema.conf
new file mode 100644
index 00000000..272d90e2
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-mcd-li-schema.conf
@@ -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
+#
+#
+# ns-mcd-li-schema.conf
+#
+# Netscape Mission Control Desktop Location Independence schema
+#
+
+attribute nsLIPtrURL 2.16.840.1.113730.3.1.399 ces
+attribute nsLIPrefs 2.16.840.1.113730.3.1.400 ces
+attribute nsLIProfileName 2.16.840.1.113730.3.1.401 cis
+attribute nsLIData 2.16.840.1.113730.3.1.402 bin
+attribute nsLIElementType 2.16.840.1.113730.3.1.403 cis
+attribute nsLIServerType 2.16.840.1.113730.3.1.404 cis
+attribute nsLIVersion 2.16.840.1.113730.3.1.405 int
+
+objectclass nsLIPtr
+ oid 2.16.840.1.113730.3.2.74
+ requires
+ objectclass
+ allows
+ nsliptrurl,
+ owner
+
+objectclass nsLIProfile
+ oid 2.16.840.1.113730.3.2.75
+ requires
+ objectclass,
+ nsliprofilename
+ allows
+ nsliprefs,
+ uid,
+ owner
+
+objectclass nsLIProfileElement
+ oid 2.16.840.1.113730.3.2.76
+ requires
+ objectclass,
+ nslielementtype
+ allows
+ owner,
+ nslidata,
+ nsliversion
+
+objectclass nsLIServer
+ oid 2.16.840.1.113730.3.2.77
+ requires
+ objectclass,
+ serverhostname
+ allows
+ description,
+ cn,
+ nsserverport,
+ nsliservertype,
+ serverroot
diff --git a/ldap/cm/v4confs/40/ns-mcd-mail-schema.conf b/ldap/cm/v4confs/40/ns-mcd-mail-schema.conf
new file mode 100644
index 00000000..12d42c0b
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-mcd-mail-schema.conf
@@ -0,0 +1,219 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-mail-schema.conf
+#
+# Netscape Mission Control Desktop mail client schema
+# This schema is used to hold mail client preferences.
+#
+
+attribute nsMCHTMLCompose 2.16.840.1.113730.3.1.331 cis
+attribute nsMCDefaultHTMLAction 2.16.840.1.113730.3.1.332 cis
+attribute nsMCRequestReturnReceipt 2.16.840.1.113730.3.1.333 cis
+attribute nsMCIncorporateReturnReceipt 2.16.840.1.113730.3.1.334 cis
+attribute nsMCMDNReportEnabled 2.16.840.1.113730.3.1.335 cis
+attribute nsMCMDNReportNotInToCC 2.16.840.1.113730.3.1.336 cis
+attribute nsMCMDNReportOutsideDomain 2.16.840.1.113730.3.1.337 cis
+attribute nsMCMDNReportOther 2.16.840.1.113730.3.1.338 cis
+attribute nsMCForwardMessageMode 2.16.840.1.113730.3.1.339 cis
+attribute nsMCAutoQuote 2.16.840.1.113730.3.1.340 cis
+attribute nsMCReplyOnTop 2.16.840.1.113730.3.1.341 cis
+attribute nsMCSpellCheckBeforeSend 2.16.840.1.113730.3.1.342 cis
+attribute nsMCWrapLongLines 2.16.840.1.113730.3.1.343 cis
+attribute nsMCWrapLength 2.16.840.1.113730.3.1.344 cis
+attribute nsMCStrictlyMime 2.16.840.1.113730.3.1.345 cis
+attribute nsMCAutoCompleteUseAddressBooks 2.16.840.1.113730.3.1.346 cis
+attribute nsMCAutoCompleteUseDirectory 2.16.840.1.113730.3.1.347 cis
+attribute nsMCAutoCompleteEnabledServerName 2.16.840.1.113730.3.1.348 cis
+attribute nsMCAutoCompleteShowDlgForMultipleMatches 2.16.840.1.113730.3.1.349 cis
+attribute nsMCSkipDirectoryIfLocalMatchFound 2.16.840.1.113730.3.1.350 cis
+attribute nsMCAddrBookLastnameFirst 2.16.840.1.113730.3.1.351 cis
+attribute nsMCLimitMessageSize 2.16.840.1.113730.3.1.352 cis
+attribute nsMCMaxMessageSize 2.16.840.1.113730.3.1.353 cis
+attribute nsMCPromptPurgeThreshold 2.16.840.1.113730.3.1.354 cis
+attribute nsMCPurgeThreshold 2.16.840.1.113730.3.1.355 cis
+attribute nsMCNewsKeepMethod 2.16.840.1.113730.3.1.356 cis
+attribute nsMCNewsKeepDays 2.16.840.1.113730.3.1.357 cis
+attribute nsMCNewsKeepCount 2.16.840.1.113730.3.1.358 cis
+attribute nsMCNewsKeepOnlyUnread 2.16.840.1.113730.3.1.359 cis
+attribute nsMCNewsRemoveBodiesByAge 2.16.840.1.113730.3.1.360 cis
+attribute nsMCNewsRemoveBodiesDays 2.16.840.1.113730.3.1.361 cis
+attribute nsMCSmtpServer 2.16.840.1.113730.3.1.362 cis
+attribute nsMCSmtpUserName 2.16.840.1.113730.3.1.363 cis
+attribute nsMCSmtpUseSSL 2.16.840.1.113730.3.1.364 cis
+attribute nsMCImapServer 2.16.840.1.113730.3.1.365 cis
+attribute nsMCImapServerProperties 2.16.840.1.113730.3.1.366 cis
+attribute nsMCPopServer 2.16.840.1.113730.3.1.367 cis
+attribute nsMCPopServerProperties 2.16.840.1.113730.3.1.368 cis
+attribute nsMCLdapServer 2.16.840.1.113730.3.1.369 cis
+attribute nsMCLdapServerProperties 2.16.840.1.113730.3.1.370 cis
+attribute nsMCQuotedStyle 2.16.840.1.113730.3.1.371 cis
+attribute nsMCQuotedSize 2.16.840.1.113730.3.1.372 cis
+attribute nsMCCitationColor 2.16.840.1.113730.3.1.373 cis
+attribute nsMCFixedWidthMessages 2.16.840.1.113730.3.1.374 cis
+attribute nsMCPlaySound 2.16.840.1.113730.3.1.375 cis
+attribute nsMCRememberSelectedMessage 2.16.840.1.113730.3.1.376 cis
+attribute nsMCReuseMessageWindow 2.16.840.1.113730.3.1.377 cis
+attribute nsMCConfirmMoveFoldersToTrash 2.16.840.1.113730.3.1.378 cis
+attribute nsMCUseMapiServer 2.16.840.1.113730.3.1.379 cis
+attribute nsMCNewsTimeout 2.16.840.1.113730.3.1.380 cis
+attribute nsMCNavCrossesFolders 2.16.840.1.113730.3.1.381 cis
+attribute nsMCSearchServer 2.16.840.1.113730.3.1.382 cis
+attribute nsMCSearchSubFolders 2.16.840.1.113730.3.1.383 cis
+attribute nsMCEncryptOutgoingMail 2.16.840.1.113730.3.1.384 cis
+attribute nsMCCryptoSignOutgoingMail 2.16.840.1.113730.3.1.385 cis
+attribute nsMCCryptoSignOutgoingNews 2.16.840.1.113730.3.1.386 cis
+attribute nsMCWarnForwardEncrypted 2.16.840.1.113730.3.1.387 cis
+attribute nsMCWarnReplyUnencrypted 2.16.840.1.113730.3.1.388 cis
+attribute nsMCAllowAtSignInUserName 2.16.840.1.113730.3.1.389 cis
+attribute nsMCReceiptRequestHeaderType 2.16.840.1.113730.3.1.390 cis
+attribute nsMCPop3GetsNewMail 2.16.840.1.113730.3.1.391 cis
+attribute nsMCImapAutoSubscribeOnOpen 2.16.840.1.113730.3.1.392 cis
+attribute nsMCImapMimePartsOnDemand 2.16.840.1.113730.3.1.393 cis
+attribute nsMCImapMimePartsOnDemandThreshold 2.16.840.1.113730.3.1.394 cis
+attribute nsMCUseAltMail 2.16.840.1.113730.3.1.395 cis
+attribute nsMCAltMailDll 2.16.840.1.113730.3.1.396 cis
+attribute nsMCUseAltMailForNews 2.16.840.1.113730.3.1.397 cis
+attribute nsPrefMap 2.16.840.1.113730.3.1.398 cis
+attribute nsMCAuthLogin 2.16.840.1.113730.3.1.499 cis
+attribute nsMNCNavCrossesFolders 2.16.840.1.113730.3.1.500 cis
+attribute nsMNCMessageInThreadWindow 2.16.840.1.113730.3.1.501 cis
+attribute nsMCAllowAtSignInUserName 2.16.840.1.113730.3.1.502 cis
+attribute nsMCImapOnlineDraftSent 2.16.840.1.113730.3.1.503 cis
+attribute nsMCCustomHeaders 2.16.840.1.113730.3.1.504 cis
+attribute nsMCHtmlDomains 2.16.840.1.113730.3.1.505 cis
+attribute nsMNCForceAsciiSearch 2.16.840.1.113730.3.1.506 cis
+attribute nsMCAddrBookLdapDisabled 2.16.840.1.113730.3.1.507 cis
+attribute nsMNCReuseThreadWindow 2.16.840.1.113730.3.1.508 cis
+attribute nsMCShowHeaders 2.16.840.1.113730.3.1.509 cis
+attribute nsMCIdentityDefaultdomain 2.16.840.1.113730.3.1.510 cis
+
+
+
+
+objectclass nsMailClient
+ oid 2.16.840.1.113730.3.2.72
+ superior top
+ allows
+ nsMCHTMLCompose,
+ nsMCDefaultHTMLAction,
+ nsMCRequestReturnReceipt,
+ nsMCIncorporateReturnReceipt,
+ nsMCMDNReportEnabled,
+ nsMCMDNReportNotInToCC,
+ nsMCMDNReportOutsideDomain,
+ nsMCMDNReportOther,
+ nsMCForwardMessageMode,
+ nsMCAutoQuote,
+ nsMCReplyOnTop,
+ nsMCSpellCheckBeforeSend,
+ nsMCWrapLongLines,
+ nsMCWrapLength,
+ nsMCStrictlyMime,
+ nsMCAutoCompleteUseAddressBooks,
+ nsMCAutoCompleteUseDirectory,
+ nsMCAutoCompleteEnabledServerName,
+ nsMCAutoCompleteShowDlgForMultipleMatches,
+ nsMCSkipDirectoryIfLocalMatchFound,
+ nsMCAddrBookLastnameFirst,
+ nsMCLimitMessageSize,
+ nsMCMaxMessageSize,
+ nsMCPromptPurgeThreshold,
+ nsMCPurgeThreshold,
+ nsMCNewsKeepMethod,
+ nsMCNewsKeepDays,
+ nsMCNewsKeepCount,
+ nsMCNewsKeepOnlyUnread,
+ nsMCNewsRemoveBodiesByAge,
+ nsMCNewsRemoveBodiesDays,
+ nsMCSmtpServer,
+ nsMCSmtpUserName,
+ nsMCSmtpUseSSL,
+ nsMCImapServer,
+ nsMCImapServerProperties,
+ nsMCPopServer,
+ nsMCPopServerProperties,
+ nsMCLdapServer,
+ nsMCLdapServerProperties,
+ nsMCQuotedStyle,
+ nsMCQuotedSize,
+ nsMCCitationColor,
+ nsMCFixedWidthMessages,
+ nsMCPlaySound,
+ nsMCRememberSelectedMessage,
+ nsMCReuseMessageWindow,
+ nsMCConfirmMoveFoldersToTrash,
+ nsMCUseMapiServer,
+ nsMCNewsTimeout,
+ nsMCNavCrossesFolders,
+ nsMCSearchServer,
+ nsMCSearchSubFolders,
+ nsMCEncryptOutgoingMail,
+ nsMCCryptoSignOutgoingMail,
+ nsMCCryptoSignOutgoingNews,
+ nsMCWarnForwardEncrypted,
+ nsMCWarnReplyUnencrypted,
+ nsMCAllowAtSignInUserName,
+ nsMCReceiptRequestHeaderType,
+ nsMCPop3GetsNewMail,
+ nsMCImapAutoSubscribeOnOpen,
+ nsMCImapMimePartsOnDemand,
+ nsMCImapMimePartsOnDemandThreshold,
+ nsMCUseAltMail,
+ nsMCAltMailDll,
+ nsMCUseAltMailForNews,
+ nsMCAuthLogin,
+ nsMNCNavCrossesFolders,
+ nsMNCMessageInThreadWindow,
+ nsMCAllowAtSignInUserName,
+ nsMCImapOnlineDraftSent,
+ nsMCCustomHeaders,
+ nsMCHtmlDomains,
+ nsMNCForceAsciiSearch,
+ nsMCAddrBookLdapDisabled,
+ nsMNCReuseThreadWindow,
+ nsMCShowHeaders,
+ nsMCIdentityDefaultdomain
+
+
+#
+# Netscape Mission Control Desktop Messenger security schema
+# This schema is used to hold Messenger security preferences.
+#
+
+attribute nsMSEncryptOutgoingMail 2.16.840.1.113730.3.1.511 cis
+attribute nsMSSignOutgoingMail 2.16.840.1.113730.3.1.512 cis
+attribute nsMSSignOutgoingNews 2.16.840.1.113730.3.1.513 cis
+attribute nsMSSmimeDesEde3 2.16.840.1.113730.3.1.514 cis
+attribute nsMSSmimeRc2128 2.16.840.1.113730.3.1.515 cis
+attribute nsMSSmimeDes 2.16.840.1.113730.3.1.516 cis
+attribute nsMSSmimeRc264 2.16.840.1.113730.3.1.517 cis
+attribute nsMSSmimeRc240 2.16.840.1.113730.3.1.518 cis
+attribute nsMSSmimeFortezza 2.16.840.1.113730.3.1.519 cis
+
+objectclass nsMailSecurity
+ oid 2.16.840.1.113730.3.2.81
+ superior top
+ allows
+ nsMSEncryptOutgoingMail,
+ nsMSSignOutgoingMail,
+ nsMSSignOutgoingNews,
+ nsMSSmimeDesEde3,
+ nsMSSmimeRc2128,
+ nsMSSmimeDes,
+ nsMSSmimeRc264,
+ nsMSSmimeRc240,
+ nsMSSmimeFortezza
+
+objectclass netscapePreferenceMap
+ oid 2.16.840.1.113730.3.2.73
+ superior top
+ allows
+ nsPrefMap,
+ uid
+
diff --git a/ldap/cm/v4confs/40/ns-media-globopt.conf b/ldap/cm/v4confs/40/ns-media-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-media-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/40/ns-media-schema.conf b/ldap/cm/v4confs/40/ns-media-schema.conf
new file mode 100644
index 00000000..d4afa271
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-media-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeMediaServer
+ oid 2.16.840.1.113730.3.2.25
+ requires
+ objectclass
+
diff --git a/ldap/cm/v4confs/40/ns-mlm-schema.conf b/ldap/cm/v4confs/40/ns-mlm-schema.conf
new file mode 100644
index 00000000..4aa8fc07
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-mlm-schema.conf
@@ -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
+#
+#
+# LDAP object classes used by MLM
+#
+
+attribute mgmemMemberOfGroup cis
+attribute mgmemRefDN ces single
+attribute mgmemMailUserPassword bin single
+attribute mgmemGroupMemberParam ces
+attribute mgmemGroupServerParam ces
+
+attribute mgmanJoinability ces
+attribute mgmanJoinLocalType cis single
+attribute mgmanMemberVisibility ces
+attribute mgmanIntroText ces single
+attribute mgmanGroupStat ces
+attribute mgmanHidden cis single
+attribute mgmanGroupKey cis single
+attribute mgmanAllowSubscribe cis
+attribute mgmanDenySubscribe cis
+
+attribute mgmanGConfNewGroupParent dn single
+attribute mgmanGConfRemoteUserParent dn single
+attribute mgmanGConfSearchBase dn single
+attribute mgmanGConfGroupCreationUser dn
+attribute mgmanGConfSearchGroupUser dn
+attribute mgmanGConfAdmin dn
+attribute mgmanGConfGroupTemplate dn single
+attribute mgmanGConfDefaultInheritance cis
+attribute mgmanGConfKey cis
+attribute mgmanGConfSearchAttribute cis
+attribute mgmanGConfSearchRelationship cis
+attribute mgmanGConfSearchTreeNode cis
+
+
+objectClass mailGroupMember
+ requires
+ objectClass,
+ mail
+ allows
+ mgmemMemberOfGroup,
+ mgmemRefDN,
+ preferredLanguage,
+ userCertificate,
+ mgmemMailUserPassword,
+ mgmemGroupMemberParam,
+ mgmemGroupServerParam,
+ c,
+ cn,
+ sn,
+ givenName
+
+
+objectClass mailGroupManagement
+ requires
+ objectClass
+ allows
+ description,
+ labeledURL,
+ mgmanAllowSubscribe,
+ mgmanDenySubscribe,
+ mgmanGroupKey,
+ mgmanGroupStat,
+ mgmanHidden,
+ mgmanIntroText,
+ mgmanJoinability,
+ mgmanJoinLocalType,
+ mgmanMemberVisibility,
+ multilineDescription,
+ userCertificate,
+ userPassword
+
+objectClass mailGroupManagement_GlobalConfig
+ requires
+ objectClass
+ allows
+ cn,
+ mgmanGConfAdmin,
+ mgmanGConfDefaultInheritance,
+ mgmanGConfGroupCreationUser,
+ mgmanGConfGroupTemplate,
+ mgmanGConfKey,
+ mgmanGConfNewGroupParent,
+ mgmanGConfRemoteUserParent,
+ mgmanGConfSearchAttribute,
+ mgmanGConfSearchBase,
+ mgmanGConfSearchGroupUser,
+ mgmanGConfSearchRelationship,
+ mgmanGConfSearchTreeNode
diff --git a/ldap/cm/v4confs/40/ns-msg-schema.conf b/ldap/cm/v4confs/40/ns-msg-schema.conf
new file mode 100644
index 00000000..b35df739
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-msg-schema.conf
@@ -0,0 +1,690 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#used by Netscape Messaging Server 4.0
+#
+#
+attribute nsmsgaccounturl cis
+attribute nsmsgadddeliveredto cis
+attribute nsmsgaddheaders cis
+attribute nsmsgadmins cis
+attribute nsmsgalias cis
+attribute nsmsgallowanonymouslogin cis
+attribute nsmsgallowbarelf cis
+attribute nsmsgallowbdat cis
+attribute nsmsgallowehlo cis
+attribute nsmsgallowetrn cis
+attribute nsmsgallowexpn cis
+attribute nsmsgallowhelp cis
+attribute nsmsgallowonex cis
+attribute nsmsgallowsize cis
+attribute nsmsgallowverb cis
+attribute nsmsgallowvrfy cis
+attribute nsmsgaltqueues cis
+attribute nsmsgalwaysqueue cis
+attribute nsmsgauthcachesize cis
+attribute nsmsgauthcachettl cis
+attribute nsmsgauthmaildomain cis
+attribute nsmsgbanner cis
+attribute nsmsgbinarypath cis
+attribute nsmsgbuffersize cis
+attribute nsmsgcheckdeferredqueue cis
+attribute nsmsgcleanupage cis
+attribute nsmsgclearcontrolinterval cis
+attribute nsmsgclearcontrolsafetime cis
+attribute nsmsgcollectiondeltatime cis
+attribute nsmsgconfigversion cis
+attribute nsmsgcontact cis
+attribute nsmsgcounterdeltatime cis
+attribute nsmsgdbcachesize cis
+attribute nsmsgdbtmpdir cis
+attribute nsmsgdefaultacl cis
+attribute nsmsgdefaultdomain cis
+attribute nsmsgdefaultecho cis
+attribute nsmsgdefaultgid cis
+attribute nsmsgdefaultmailboxquota cis
+attribute nsmsgdefaultoverquota cis
+attribute nsmsgdefaultpartition cis
+attribute nsmsgdefaultreply cis
+attribute nsmsgdefaultuid cis
+attribute nsmsgdefaultvacation cis
+attribute nsmsgdeferredperiod cis
+attribute nsmsgdeleteheaders cis
+attribute nsmsgdescription cis
+attribute nsmsgdiskflushinterval cis
+attribute nsmsgdnsresolveclient cis
+attribute nsmsgdocanonicalize cis
+attribute nsmsgdoclientdnslookup cis
+attribute nsmsgdodsn cis
+attribute nsmsgdoetrn cis
+attribute nsmsgdomainallowed cis
+attribute nsmsgdomainlangtable cis
+attribute nsmsgdomainname cis
+attribute nsmsgdomainnotallowed cis
+attribute nsmsgdorewritefromusingauth cis
+attribute nsmsgdorewritesenderusingauth cis
+attribute nsmsgenable cis
+attribute nsmsgenablesslport cis
+attribute nsmsgenveloperewritemethod cis
+attribute nsmsgexclusive cis
+attribute nsmsgexpirestart cis
+attribute nsmsgexpirytime cis
+attribute nsmsgexternalmxserverip cis
+attribute nsmsgfallbacksearchmethod cis
+attribute nsmsgfilemode cis
+attribute nsmsgfilterurl cis
+attribute nsmsgflushinterval cis
+attribute nsmsgfolderpattern cis
+attribute nsmsgfoldersizebytes cis
+attribute nsmsgfolderurl cis
+attribute nsmsgforeignpercentaddr cis
+attribute nsmsgformsigkey cis
+attribute nsmsghidehostname cis
+attribute nsmsghopcountexceedactions cis
+attribute nsmsghostoncommandline cis
+attribute nsmsghostrewrites cis
+attribute nsmsgidletimeout cis
+attribute nsmsginstalledlanguages cis
+attribute nsmsginternalmxserverip cis
+attribute nsmsgldapmemcache cis
+attribute nsmsgldapmemcachesize cis
+attribute nsmsgldapmemcachettl cis
+attribute nsmsgldappoolsize cis
+attribute nsmsgldaputilconfig cis
+attribute nsmsglistenaddr cis
+attribute nsmsglistenq cis
+attribute nsmsglisturl cis
+attribute nsmsglocaldefaultmaxruncount cis
+attribute nsmsglocaldefaultminruncount cis
+attribute nsmsglocalmaildomains cis
+attribute nsmsglocation cis
+attribute nsmsglog cis
+attribute nsmsglogdir cis
+attribute nsmsgloglevel cis
+attribute nsmsglogtype cis
+attribute nsmsgmaildeliveryprogram cis
+attribute nsmsgmasterhost cis
+attribute nsmsgmasterport cis
+attribute nsmsgmaxbadcommands cis
+attribute nsmsgmaxbranches cis
+attribute nsmsgmaxcontrolrecipients cis
+attribute nsmsgmaxcputime cis
+attribute nsmsgmaxerrorobjectsize cis
+attribute nsmsgmaxheaderlines cis
+attribute nsmsgmaxlogfiles cis
+attribute nsmsgmaxlogfilesize cis
+attribute nsmsgmaxlogsize cis
+attribute nsmsgmaxmessagesize cis
+attribute nsmsgmaxmtahops cis
+attribute nsmsgmaxqueuetime cis
+attribute nsmsgmaxruncount cis
+attribute nsmsgmaxruncountdeferred cis
+attribute nsmsgmaxscriptsize cis
+attribute nsmsgmaxsessions cis
+attribute nsmsgmaxstateobjectsize cis
+attribute nsmsgmaxthreads cis
+attribute nsmsgmessagecount cis
+attribute nsmsgmessagedays cis
+attribute nsmsgmessagehostname cis
+attribute nsmsgmessagesize cis
+attribute nsmsgmessagesizedays cis
+attribute nsmsgminfreediskspace cis
+attribute nsmsgminruncount cis
+attribute nsmsgmsgalarmdescription cis
+attribute nsmsgmsgalarmnoticehost cis
+attribute nsmsgmsgalarmnoticeport cis
+attribute nsmsgmsgalarmnoticercpt cis
+attribute nsmsgmsgalarmnoticesender cis
+attribute nsmsgmsgalarmnoticetemplate cis
+attribute nsmsgmsgalarmstatinterval cis
+attribute nsmsgmsgalarmthreshold cis
+attribute nsmsgmsgalarmthresholddirection cis
+attribute nsmsgmsgalarmwarninginterval cis
+attribute nsmsgmtaid cis
+attribute nsmsgmtaname cis
+attribute nsmsgneedsender cis
+attribute nsmsgnegativehostattr cis
+attribute nsmsgnestedgroups cis
+attribute nsmsgnetworkdefaultmaxruncount cis
+attribute nsmsgnetworkdefaultminruncount cis
+attribute nsmsgnewsprefix cis
+attribute nsmsgnewsspool cis
+attribute nsmsgnewuserforms cis
+attribute nsmsgntaccount cis
+attribute nsmsgntpassword cis
+attribute nsmsgntrunoptn cis
+attribute nsmsgnumdays cis
+attribute nsmsgnumenvelopequeuefiles cis
+attribute nsmsgnummessages cis
+attribute nsmsgnumprocesses cis
+attribute nsmsgorganization cis
+attribute nsmsgpartition cis
+attribute nsmsgpath cis
+attribute nsmsgplaintextloginpause cis
+attribute nsmsgplaintextmincipher cis
+attribute nsmsgpopminpoll cis
+attribute nsmsgport cis
+attribute nsmsgpositivehostattr cis
+attribute nsmsgprotocolubeconfig cis
+attribute nsmsgquotaexceededactions cis
+attribute nsmsgquotaexceededmsg cis
+attribute nsmsgquotaexceededmsginterval cis
+attribute nsmsgquotagraceperiod cis
+attribute nsmsgquotawarn cis
+attribute nsmsgreadtimeout cis
+attribute nsmsgrenotifyinterval cis
+attribute nsmsgrequirecrlf cis
+attribute nsmsgreserved0 cis
+attribute nsmsgreserved1 cis
+attribute nsmsgreserved2 cis
+attribute nsmsgreserved3 cis
+attribute nsmsgreserved4 cis
+attribute nsmsgreserved5 cis
+attribute nsmsgreserved6 cis
+attribute nsmsgreserved7 cis
+attribute nsmsgreserved8 cis
+attribute nsmsgreserved9 cis
+attribute nsmsgrewritetocc cis
+attribute nsmsgrolloverdelta cis
+attribute nsmsgrolloversize cis
+attribute nsmsgrollovertime cis
+attribute nsmsgroutingattribute cis
+attribute nsmsgroutstripimapfolders cis
+attribute nsmsgshellpath cis
+attribute nsmsgsitelanguage cis
+attribute nsmsgsmtphost cis
+attribute nsmsgsmtpport cis
+attribute nsmsgsmtprewritestyle cis
+attribute nsmsgsslcachesize cis
+attribute nsmsgsslpasswdfile cis
+attribute nsmsgsslport cis
+attribute nsmsgsslusessl cis
+attribute nsmsgsslusesslrelay cis
+attribute nsmsgstripcr cis
+attribute nsmsgsystemmaildir cis
+attribute nsmsgtimeoutcommand cis
+attribute nsmsgtimeoutdata cis
+attribute nsmsgtimeoutdatadot cis
+attribute nsmsgtimeoutdatasend cis
+attribute nsmsgtimeoutgreet cis
+attribute nsmsgtimeouthelo cis
+attribute nsmsgtimeoutmail cis
+attribute nsmsgtimeoutquit cis
+attribute nsmsgtimeoutrcpt cis
+attribute nsmsgtimeoutrset cis
+attribute nsmsgumask cis
+attribute nsmsgunknownacctsactions cis
+attribute nsmsgusemx cis
+attribute nsmsgverifyrcpts cis
+attribute nsmsgversion cis
+
+objectclass netscapeMessagingServer
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description
+
+objectclass nsmsgcfgcontainer
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfggen
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgaccounturl,
+ nsmsgconfigversion,
+ nsmsgfilterurl,
+ nsmsgfolderurl,
+ nsmsginstalledlanguages,
+ nsmsglisturl,
+ nsmsgnewuserforms,
+ nsmsgsitelanguage
+
+objectclass nsmsgcfgsnmp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgcontact,
+ nsmsgcollectiondeltatime,
+ nsmsgdescription,
+ nsmsgenable,
+ nsmsglocation,
+ nsmsgmtaid,
+ nsmsgmtaname,
+ nsmsgmasterhost,
+ nsmsgmasterport,
+ nsmsgorganization,
+ nsmsgversion
+
+objectclass nsmsgcfgstore
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgadmins,
+ nsmsgcleanupage,
+ nsmsgdbcachesize,
+ nsmsgdbtmpdir,
+ nsmsgdefaultacl,
+ nsmsgdefaultmailboxquota,
+ nsmsgdefaultpartition,
+ nsmsgdiskflushinterval,
+ nsmsgexpirestart,
+ nsmsgquotaexceededmsg,
+ nsmsgquotaexceededmsginterval,
+ nsmsgquotagraceperiod,
+ nsmsgquotawarn,
+ nsmsgumask
+
+objectclass nsmsgcfgexpirerule
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgfolderpattern,
+ nsmsgexclusive,
+ nsmsgfoldersizebytes,
+ nsmsgmessagecount,
+ nsmsgmessagedays,
+ nsmsgmessagesize,
+ nsmsgmessagesizedays
+
+objectclass nsmsgcfgpartition
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgpath
+
+objectclass nsmsgcfguser
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgpublic
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgalias
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgalias
+
+objectclass nsmsgcfglog
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgbuffersize,
+ nsmsgexpirytime,
+ nsmsgflushinterval,
+ nsmsglogdir,
+ nsmsgloglevel,
+ nsmsglogtype,
+ nsmsgmaxlogfiles,
+ nsmsgmaxlogfilesize,
+ nsmsgmaxlogsize,
+ nsmsgminfreediskspace,
+ nsmsgrollovertime
+
+objectclass nsmsgcfgservice
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgauthcachesize,
+ nsmsgauthcachettl,
+ nsmsgdnsresolveclient,
+ nsmsgldapmemcache,
+ nsmsgldapmemcachesize,
+ nsmsgldapmemcachettl,
+ nsmsglistenaddr,
+ nsmsgplaintextloginpause,
+ nsmsgreadtimeout,
+ nsmsgsslpasswdfile
+
+objectclass nsmsgcfgpop
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowanonymouslogin,
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgidletimeout,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgpopminpoll,
+ nsmsgport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgimap
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowanonymouslogin,
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgidletimeout,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgsslcachesize,
+ nsmsgsslport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfghttp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowanonymouslogin,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgidletimeout,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgsmtphost,
+ nsmsgsmtpport,
+ nsmsgsslcachesize,
+ nsmsgsslport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgnntp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgnewsprefix,
+ nsmsgnewsspool,
+ nsmsgpartition,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgsslport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgmta
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgaltqueues,
+ nsmsgauthmaildomain,
+ nsmsgbanner,
+ nsmsgclearcontrolinterval,
+ nsmsgclearcontrolsafetime,
+ nsmsgcounterdeltatime,
+ nsmsgdefaultdomain,
+ nsmsgdeferredperiod,
+ nsmsgdocanonicalize,
+ nsmsgdoclientdnslookup,
+ nsmsgdodsn,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgdomainname,
+ nsmsgdomainlangtable,
+ nsmsgenable,
+ nsmsgforeignpercentaddr,
+ nsmsgldappoolsize,
+ nsmsgldaputilconfig,
+ nsmsglocaldefaultmaxruncount,
+ nsmsglocaldefaultminruncount,
+ nsmsgmaxheaderlines,
+ nsmsgmaxqueuetime,
+ nsmsgmessagehostname,
+ nsmsgnetworkdefaultmaxruncount,
+ nsmsgnetworkdefaultminruncount,
+ nsmsgnumenvelopequeuefiles,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgprotocolubeconfig,
+ nsmsgreserved0,
+ nsmsgreserved1,
+ nsmsgreserved2,
+ nsmsgreserved3,
+ nsmsgreserved4,
+ nsmsgreserved5,
+ nsmsgreserved6,
+ nsmsgreserved7,
+ nsmsgreserved8,
+ nsmsgreserved9,
+ nsmsgrolloverdelta,
+ nsmsgrolloversize,
+ nsmsgroutstripimapfolders,
+ nsmsgsslusessl,
+ nsmsgsslusesslrelay
+
+objectclass nsmsgcfgmtalog
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsglog,
+ nsmsgminruncount,
+ nsmsgmaxruncount,
+ nsmsgmaxruncountdeferred
+
+objectclass nsmsgcfgmtaautoreplyhandler
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultecho,
+ nsmsgdefaultreply,
+ nsmsgdefaultvacation
+
+objectclass nsmsgcfgmtaerrorhandler
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgformsigkey,
+ nsmsghopcountexceedactions,
+ nsmsgquotaexceededactions,
+ nsmsgrenotifyinterval,
+ nsmsgunknownacctsactions
+
+objectclass nsmsgcfgmtamboxdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgmtaprogdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultgid,
+ nsmsgdefaultuid,
+ nsmsgshellpath,
+ nsmsgntrunoptn,
+ nsmsgntaccount,
+ nsmsgntpassword
+
+objectclass nsmsgcfgmtaaccept
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowbdat,
+ nsmsgallowehlo,
+ nsmsgallowetrn,
+ nsmsgallowexpn,
+ nsmsgallowhelp,
+ nsmsgallowonex,
+ nsmsgallowsize,
+ nsmsgallowverb,
+ nsmsgallowvrfy,
+ nsmsghidehostname,
+ nsmsgmaxbadcommands,
+ nsmsgmaxmessagesize,
+ nsmsgminfreediskspace,
+ nsmsgnegativehostattr,
+ nsmsgpositivehostattr,
+ nsmsgrequirecrlf,
+ nsmsgtimeoutcommand,
+ nsmsgtimeoutdata,
+ nsmsgverifyrcpts
+
+objectclass nsmsgcfgmtasmtpdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowbarelf,
+ nsmsgalwaysqueue,
+ nsmsgcheckdeferredqueue,
+ nsmsgdoetrn,
+ nsmsgexternalmxserverip,
+ nsmsginternalmxserverip,
+ nsmsgtimeoutdata,
+ nsmsgtimeoutdatadot,
+ nsmsgtimeoutdatasend,
+ nsmsgtimeoutgreet,
+ nsmsgtimeouthelo,
+ nsmsgtimeoutmail,
+ nsmsgtimeoutquit,
+ nsmsgtimeoutrcpt,
+ nsmsgtimeoutrset,
+ nsmsgusemx
+
+objectclass nsmsgcfgmtarouter
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgadddeliveredto,
+ nsmsgaddheaders,
+ nsmsgdeleteheaders,
+ nsmsgdorewritefromusingauth,
+ nsmsgdorewritesenderusingauth,
+ nsmsgenveloperewritemethod,
+ nsmsgfallbacksearchmethod,
+ nsmsghostrewrites,
+ nsmsglocalmaildomains,
+ nsmsgmaxcontrolrecipients,
+ nsmsgmaxmtahops,
+ nsmsgnestedgroups,
+ nsmsgrewritetocc,
+ nsmsgroutingattribute,
+ nsmsgsmtprewritestyle
+
+objectclass nsmsgcfgmtaunixdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultgid,
+ nsmsgdefaultuid,
+ nsmsgfilemode,
+ nsmsgmaildeliveryprogram,
+ nsmsgneedsender,
+ nsmsgstripcr,
+ nsmsgsystemmaildir
+
+objectclass nsmsgcfgreport
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgalarmcontainer
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgmsgalarmnoticehost,
+ nsmsgmsgalarmnoticeport,
+ nsmsgmsgalarmnoticercpt,
+ nsmsgmsgalarmnoticesender,
+ nsmsgmsgalarmnoticetemplate
+
+objectclass nsmsgcfgalarm
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgmsgalarmdescription,
+ nsmsgmsgalarmstatinterval,
+ nsmsgmsgalarmthreshold,
+ nsmsgmsgalarmthresholddirection,
+ nsmsgmsgalarmwarninginterval
+
+objectclass nsmsgcfgscript
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgenable,
+ nsmsgbinarypath,
+ nsmsgloglevel,
+ nsmsgmaxscriptsize,
+ nsmsgmaxbranches,
+ nsmsgmaxcputime,
+ nsmsgmaxerrorobjectsize,
+ nsmsgmaxstateobjectsize
diff --git a/ldap/cm/v4confs/40/ns-netshare-schema.conf b/ldap/cm/v4confs/40/ns-netshare-schema.conf
new file mode 100644
index 00000000..b1201ef0
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-netshare-schema.conf
@@ -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
+#
+# Used by Netscape Enterprise Server
+attribute netshareHomeURL ces single
+attribute netshareServerType cis single
+attribute netshareHomeTheme cis single
+attribute netsharePrivate cis single
+attribute netshareMemberOf dn
+attribute netshareUIConfig bin single
+
+# added to either users or groups/projects to enable
+# as netshare user accounts or netshare projects
+objectclass netshareAccount
+ requires
+ objectclass,
+ netshareHomeURL
+ allows
+ netshareServerType,
+ netshareHomeTheme,
+ netsharePrivate,
+ netshareMemberOf,
+ netshareUIConfig
+
+
+attribute netsharePMNewProjParent dn single
+attribute netsharePMSearchBase dn single
+attribute netsharePMProjCreationUser dn single
+attribute netsharePMAdmin dn
+
+# this is for the netshare project management utility/CGI
+# that is created under the SIE; this parallels the messaging
+# MLM schema somewhat to enable end-user maintenance/creation
+# of netshare projects
+objectclass netshareProjectManagementGlobalConfig
+ requires
+ objectclass
+ allows
+ netsharePMNewProjParent,
+ netsharePMSearchBase,
+ netsharePMProjCreationUser,
+ netsharePMAdmin,
+ cn
diff --git a/ldap/cm/v4confs/40/ns-news-globopt.conf b/ldap/cm/v4confs/40/ns-news-globopt.conf
new file mode 100644
index 00000000..b35e2a83
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-news-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape News Server
+#index uniquemember,member eq
+
diff --git a/ldap/cm/v4confs/40/ns-news-schema.conf b/ldap/cm/v4confs/40/ns-news-schema.conf
new file mode 100644
index 00000000..777f339a
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-news-schema.conf
@@ -0,0 +1,35 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsnewsACL 2.16.840.1.113730.3.1.191 cis
+attribute nsaclrole 2.16.840.1.113730.3.1.192 cis
+attribute nsprettyname 2.16.840.1.113730.3.1.193 cis
+attribute nsflags 2.16.840.1.113730.3.1.194 cis
+attribute nscreator 2.16.840.1.113730.3.1.195 cis
+attribute ngcomponent 2.16.840.1.113730.3.1.196 dn
+
+objectclass nginfo
+ oid 2.16.840.1.113730.3.2.26
+ requires
+ objectClass,
+ ngcomponent
+ allows
+ nsnewsACL,
+ subtreeACI,
+ description,
+ nsaclrole,
+ nsprettyname,
+ nsflags,
+ nscreator
+
+objectClass netscapeNewsServer
+ oid 2.16.840.1.113730.3.2.27
+ requires
+ objectClass
+
diff --git a/ldap/cm/v4confs/40/ns-proxy-globopt.conf b/ldap/cm/v4confs/40/ns-proxy-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-proxy-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/40/ns-proxy-schema.conf b/ldap/cm/v4confs/40/ns-proxy-schema.conf
new file mode 100644
index 00000000..3d26bacb
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-proxy-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeProxyServer
+ oid 2.16.840.1.113730.3.2.28
+ requires
+ objectclass
+
diff --git a/ldap/cm/v4confs/40/ns-value-schema.conf b/ldap/cm/v4confs/40/ns-value-schema.conf
new file mode 100644
index 00000000..c4b9d3c9
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-value-schema.conf
@@ -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
+#
+# Schema for defining schemaless config for LDAP
+#
+
+attribute nsValueCIS 2.16.840.1.113730.3.1.243 cis
+attribute nsValueCES 2.16.840.1.113730.3.1.244 ces
+attribute nsValueTel 2.16.840.1.113730.3.1.245 tel
+attribute nsValueInt 2.16.840.1.113730.3.1.246 int
+attribute nsValueBin 2.16.840.1.113730.3.1.247 bin
+attribute nsValueDN 2.16.840.1.113730.3.1.248 dn
+attribute nsValueType 2.16.840.1.113730.3.1.249 cis
+attribute nsValueDefault 2.16.840.1.113730.3.1.250 cis
+attribute nsValueFlags 2.16.840.1.113730.3.1.251 cis
+attribute nsValueDescription 2.16.840.1.113730.3.1.252 cis
+attribute nsValueSyntax 2.16.840.1.113730.3.1.253 cis
+attribute nsValueHelpURL 2.16.840.1.113730.3.1.254 ces
+
+objectClass nsValueItem
+ oid 2.16.840.1.113730.3.2.45
+ requires
+ objectClass,
+ cn
+ allows
+ nsValueCIS,
+ nsValueCES,
+ nsValueTel,
+ nsValueInt,
+ nsValueBin,
+ nsValueDN,
+ nsValueType,
+ nsValueSyntax,
+ nsValueDescription,
+ nsValueHelpURL,
+ nsValueFlags,
+ nsValueDefault
+
diff --git a/ldap/cm/v4confs/40/ns-wcal-globopt.conf b/ldap/cm/v4confs/40/ns-wcal-globopt.conf
new file mode 100644
index 00000000..72b108c7
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-wcal-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#used by Netscape Calendar Hosting Server 1.0
+
+index nswcalCALID pres,eq
diff --git a/ldap/cm/v4confs/40/ns-wcal-schema.conf b/ldap/cm/v4confs/40/ns-wcal-schema.conf
new file mode 100644
index 00000000..97a6d12d
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-wcal-schema.conf
@@ -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
+#
+# Used by Netscape Calendar Hosting Server
+
+# Login calendar URI for this user
+attribute nswcalCALID 2.16.840.1.113730.3.1.537 cis single
+
+# Calendar client specific user preferences for this user
+attribute nswcalExtendedUserPrefs 2.16.840.1.113730.3.1.538 cis
+
+# Lists calendar protocols not allowed to be used by this user
+attribute nswcalDisallowAccess 2.16.840.1.113730.3.1.539 cis single
+
+# Calendar host for this user's login calendar
+attribute nswcalHost 2.16.840.1.113730.3.1.540 cis
+
+# Quota associated with this user's calendars
+attribute nswcalQuota 2.16.840.1.113730.3.1.541 cis single
+
+# Used to designate a LDAP entry as representing a Netscape Calendar
+# Hosting Server user account. These first 10 attributes are
+# referenced by Netscape Calendar Hosting Server and the last 3
+# attributes are reserved for future use.
+objectClass nswcalUser
+ oid 2.16.840.1.113730.3.2.83
+ requires
+ objectClass
+ allows
+ cn,
+ givenName,
+ mail,
+ preferredlanguage,
+ sn,
+ uid,
+ userPassword,
+ nswcalCALID,
+ nswcalDisallowAccess,
+ nswcalExtendedUserPrefs,
+ nslicensedfor,
+ nswcalHost,
+ nswcalQuota
+
+# From http://www.imc.org/draft-ietf-calsch-locating
+attribute calCalURI 1.2.840.113556.1.4.478 cis
+attribute calFBURL 1.2.840.113556.1.4.479 cis
+attribute calCAPURI 1.2.840.113556.1.4.480 cis
+attribute calCalAdrURI 1.2.840.113556.1.4.481 cis
+attribute calOtherCalURIs 1.2.840.113556.1.4.482 cis
+attribute calOtherFBURLs 1.2.840.113556.1.4.483 cis
+attribute calOtherCAPURIs 1.2.840.113556.1.4.484 cis
+attribute calOtherCalAdrURIs 1.2.840.113556.1.4.485 cis
+
+# Used to designate a LDAP entry as representing a calendar user.
+objectClass calEntry
+ oid 1.2.840.113556.1.5.87
+ requires
+ objectClass
+ allows
+ calCalURI,
+ calFBURL,
+ calCAPURI,
+ calCalAdrURI,
+ calOtherCalURIs,
+ calOtherFBURLs,
+ calOtherCAPURIs,
+ calOtherCalAdrURIs
diff --git a/ldap/cm/v4confs/40/ns-web-globopt.conf b/ldap/cm/v4confs/40/ns-web-globopt.conf
new file mode 100644
index 00000000..4db72fe2
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-web-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Enterprise Server
+#index uniquemember,member eq
+
diff --git a/ldap/cm/v4confs/40/ns-web-schema.conf b/ldap/cm/v4confs/40/ns-web-schema.conf
new file mode 100644
index 00000000..d5e74ed8
--- /dev/null
+++ b/ldap/cm/v4confs/40/ns-web-schema.conf
@@ -0,0 +1,18 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+objectclass netscapeWebServer
+ oid 2.16.840.1.113730.3.2.29
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description,
+ nsServerPort
+
diff --git a/ldap/cm/v4confs/40/slapd.at.conf b/ldap/cm/v4confs/40/slapd.at.conf
new file mode 100644
index 00000000..0b14ecbe
--- /dev/null
+++ b/ldap/cm/v4confs/40/slapd.at.conf
@@ -0,0 +1,391 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.at.conf for Netscape Directory Server 4.0
+#
+# DO NOT MODIFY!
+#
+# The attributes listed in this file are Standard Attributes and are
+# expected to present in Directory Server 4.0. Editing this file could
+# cause interoperability problems.
+#
+# User Defined Attributes should be added by selecting
+# Schema | Edit or View Attributes from the Admin Server.
+#
+# User Defined Attributes are placed in slapd.user_at.conf.
+#
+# All attributes are viewable over LDAP in the cn=schema entry under
+# attributetypes.
+#
+# The format of this file is:
+#
+# attribute attribute-name [attribute-aliases] [attribute-oid] syntax
+#
+# If no OID is specified, <attribute-name>-oid will be used as the OID
+#
+
+########################################################################
+# X.500(93) User Schema for use with LDAP
+# Taken from <draft-ietf-asid-ldapv3schema-x500-00.txt>
+########################################################################
+
+attribute objectClass 2.5.4.0 cis
+attribute aliasedObjectName 2.5.4.1 dn
+attribute knowledgeInformation 2.5.4.2 cis
+attribute cn commonName 2.5.4.3 cis
+attribute sn surName 2.5.4.4 cis
+attribute serialNumber 2.5.4.5 cis
+attribute c countryName 2.5.4.6 cis
+attribute l locality localityname 2.5.4.7 cis
+attribute st stateOrProvinceName 2.5.4.8 cis
+attribute street streetaddress 2.5.4.9 cis
+attribute o organizationname 2.5.4.10 cis
+attribute ou organizationalUnitName 2.5.4.11 cis
+attribute title 2.5.4.12 cis
+attribute description 2.5.4.13 cis
+attribute searchGuide 2.5.4.14 ces
+attribute businessCategory 2.5.4.15 cis
+attribute postalAddress 2.5.4.16 cis
+attribute postalCode 2.5.4.17 cis
+attribute postOfficeBox 2.5.4.18 cis
+attribute physicalDeliveryOfficeName 2.5.4.19 cis
+attribute telephoneNumber 2.5.4.20 tel
+attribute telexNumber 2.5.4.21 cis
+attribute teletexTerminalIdentifier 2.5.4.22 cis
+attribute facsimileTelephoneNumber fax 2.5.4.23 tel
+attribute x121Address 2.5.4.24 ces
+attribute internationalIsdnNumber 2.5.4.25 ces
+attribute registeredAddress 2.5.4.26 cis
+attribute destinationIndicator 2.5.4.27 cis
+attribute preferredDeliveryMethod 2.5.4.28 cis
+attribute presentationAddress 2.5.4.29 ces
+attribute supportedApplicationContext 2.5.4.30 cis
+attribute member 2.5.4.31 dn
+attribute owner 2.5.4.32 dn
+attribute roleOccupant 2.5.4.33 dn
+attribute seeAlso 2.5.4.34 dn
+attribute userPassword 2.5.4.35 bin
+attribute userCertificate 2.5.4.36 bin
+attribute cACertificate cACertificate 2.5.4.37 bin
+attribute authorityRevocationList authorityRevocationList 2.5.4.38 bin
+attribute certificateRevocationList certificateRevocationList 2.5.4.39 bin
+attribute crossCertificatePair crossCertificatePair 2.5.4.40 bin
+attribute givenName 2.5.4.42 cis
+attribute initials 2.5.4.43 cis
+attribute generationQualifier 2.5.4.44 cis
+attribute x500UniqueIdentifier 2.5.4.45 bin
+attribute dnQualifier 2.5.4.46 cis
+attribute enhancedSearchGuide 2.5.4.47 cis
+attribute protocolInformation 2.5.4.48 cis
+attribute dn distinguishedName 2.5.4.49 dn
+attribute uniqueMember 2.5.4.50 dn
+attribute houseIdentifier 2.5.4.51 cis
+attribute supportedAlgorithms 2.5.4.52 bin
+attribute deltaRevocationList 2.5.4.53 bin
+
+#######################################################################
+# LDAP Attributes #
+# Taken from <draft-ietf-asid-ldapv3-attributes-07.txt> #
+#######################################################################
+
+attribute createTimestamp 2.5.18.1 cis
+attribute modifyTimestamp 2.5.18.2 cis
+attribute creatorsName 2.5.18.3 dn
+attribute modifiersName 2.5.18.4 dn
+attribute subschemaSubentry 2.5.18.10 dn
+attribute attributeTypes 2.5.21.5 cis
+attribute objectClasses 2.5.21.6 cis
+attribute matchingRules 2.5.21.4 cis
+attribute matchingRuleUse 2.5.21.8 cis
+attribute dITStructureRules 2.5.21.1 cis
+attribute dITContentRules 2.5.21.2 cis
+attribute nameForms 2.5.21.7 cis
+
+attribute namingContexts 1.3.6.1.4.1.1466.101.120.5 dn
+attribute altServer 1.3.6.1.4.1.1466.101.120.6 ces
+attribute supportedExtension 1.3.6.1.4.1.1466.101.120.7 cis
+attribute supportedControl 1.3.6.1.4.1.1466.101.120.13 cis
+attribute supportedSASLMechanisms 1.3.6.1.4.1.1466.101.120.14 cis
+attribute supportedLDAPVersion 1.3.6.1.4.1.1466.101.120.15 int
+attribute ldapSyntaxes 1.3.6.1.4.1.1466.101.120.16 cis
+
+#######################################################################
+# Pilot X.500 schema for use in LDAPv3 #
+# Taken from <draft-ietf-asid-schema-pilot-00.txt> #
+#######################################################################
+
+attribute uid 0.9.2342.19200300.100.1.1 cis
+attribute textEncodedORAddress 0.9.2342.19200300.100.1.2 cis
+attribute mail rfc822mailbox 0.9.2342.19200300.100.1.3 cis
+attribute info 0.9.2342.19200300.100.1.4 cis
+attribute drink 0.9.2342.19200300.100.1.5 cis
+attribute roomNumber 0.9.2342.19200300.100.1.6 cis
+attribute userClass 0.9.2342.19200300.100.1.8 cis
+attribute host 0.9.2342.19200300.100.1.9 cis
+attribute manager 0.9.2342.19200300.100.1.10 dn
+attribute documentIdentifier 0.9.2342.19200300.100.1.11 cis
+attribute documentTitle 0.9.2342.19200300.100.1.12 cis
+attribute documentVersion 0.9.2342.19200300.100.1.13 cis
+attribute documentAuthor 0.9.2342.19200300.100.1.14 dn
+attribute documentLocation 0.9.2342.19200300.100.1.15 cis
+attribute homePhone 0.9.2342.19200300.100.1.20 tel
+attribute secretary 0.9.2342.19200300.100.1.21 dn
+attribute otherMailbox 0.9.2342.19200300.100.1.22 cis
+attribute dc domaincomponent 0.9.2342.19200300.100.1.25 cis
+attribute dNSRecord 0.9.2342.19200300.100.1.26 cis
+attribute associatedName 0.9.2342.19200300.100.1.38 dn
+attribute homePostalAddress 0.9.2342.19200300.100.1.39 cis
+attribute personalTitle 0.9.2342.19200300.100.1.40 cis
+attribute mobile mobileTelephoneNumber 0.9.2342.19200300.100.1.41 tel
+attribute pager pagerTelephoneNumber 0.9.2342.19200300.100.1.42 tel
+attribute co friendlycountryname 0.9.2342.19200300.100.1.43 cis
+attribute uniqueIdentifier 0.9.2342.19200300.100.1.44 cis
+attribute organizationalStatus 0.9.2342.19200300.100.1.45 cis
+attribute janetMailbox 0.9.2342.19200300.100.1.46 cis
+attribute mailPreferenceOption 0.9.2342.19200300.100.1.47 int single
+attribute buildingName 0.9.2342.19200300.100.1.48 cis
+attribute dSAQuality 0.9.2342.19200300.100.1.49 cis single
+attribute singleLevelQuality 0.9.2342.19200300.100.1.50 cis single
+attribute subtreeMinimumQuality 0.9.2342.19200300.100.1.51 cis single
+attribute subtreeMaximumQuality 0.9.2342.19200300.100.1.52 cis single
+attribute personalSignature 0.9.2342.19200300.100.1.53 bin
+attribute ditRedirect 0.9.2342.19200300.100.1.54 dn
+attribute audio 0.9.2342.19200300.100.1.55 bin
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis
+attribute jpegPhoto 0.9.2342.19200300.100.1.60 bin
+
+#definitions subsequent to RFC 1274
+
+attribute labeledUri labeledurl 1.3.6.1.4.1.250.1.57 ces
+
+
+############################################################################
+# Netscape Defined Attributes
+#
+# The Netscape base OID is 2.16.840.1.113730
+# The base OID for the Netscape Directory Server is 2.16.840.1.113730.3
+# Netscape defined attributes have base 2.16.840.1.113730.3.1
+#
+# More Netscape defined attributes can be found included in ns-schema.conf
+############################################################################
+
+attribute carLicense 2.16.840.1.113730.3.1.1 cis
+attribute departmentNumber 2.16.840.1.113730.3.1.2 cis
+attribute employeeNumber 2.16.840.1.113730.3.1.3 cis
+attribute employeeType 2.16.840.1.113730.3.1.4 cis
+attribute changeNumber 2.16.840.1.113730.3.1.5 int
+attribute targetDn 2.16.840.1.113730.3.1.6 dn
+attribute changeType 2.16.840.1.113730.3.1.7 cis
+attribute changes 2.16.840.1.113730.3.1.8 bin
+attribute newRdn 2.16.840.1.113730.3.1.9 dn
+attribute deleteOldRdn 2.16.840.1.113730.3.1.10 cis
+attribute newSuperior 2.16.840.1.113730.3.1.11 dn
+attribute ref 2.16.840.1.113730.3.1.34 ces
+attribute nsLicensedFor 2.16.840.1.113730.3.1.36 cis
+attribute nsLicenseStartTime 2.16.840.1.113730.3.1.37 cis
+attribute nsLicenseEndTime 2.16.840.1.113730.3.1.38 cis
+attribute preferredLanguage 2.16.840.1.113730.3.1.39 cis single
+attribute userSMIMECertificate 2.16.840.1.113730.3.1.40 bin
+attribute ntUserDomainId 2.16.840.1.113730.3.1.41 cis single
+attribute ntUserCreateNewAccount 2.16.840.1.113730.3.1.42 cis single
+attribute ntUserDeleteAccount 2.16.840.1.113730.3.1.43 cis single
+attribute ntGroupDomainId 2.16.840.1.113730.3.1.44 cis single
+attribute ntGroupCreateNewGroup 2.16.840.1.113730.3.1.45 cis single
+attribute ntGroupDeleteGroup 2.16.840.1.113730.3.1.46 cis single
+attribute ntGroupType 2.16.840.1.113730.3.1.47 cis single
+attribute replicaPort 2.16.840.1.113730.3.1.48 cis
+attribute replicaUpdateFailedAt 2.16.840.1.113730.3.1.49 cis
+attribute replicaBeginOrc 2.16.840.1.113730.3.1.50 cis
+attribute replicaUpdateReplayed 2.16.840.1.113730.3.1.51 cis
+attribute replicaUpdateSchedule 2.16.840.1.113730.3.1.52 cis
+attribute replicaBindMethod 2.16.840.1.113730.3.1.53 cis
+attribute replicaUseSSL 2.16.840.1.113730.3.1.54 cis
+attribute aci 2.16.840.1.113730.3.1.55 bin
+attribute lastModifiedBy 0.9.2342.19200300.100.1.24 dn
+attribute replicaRoot 2.16.840.1.113730.3.1.57 dn
+attribute replicaBindDn 2.16.840.1.113730.3.1.58 dn
+attribute ntUserPriv 2.16.840.1.113730.3.1.59 bin single
+attribute ntUserAuthFlags 2.16.840.1.113730.3.1.60 bin single
+attribute ntUserUsrComment 2.16.840.1.113730.3.1.61 cis single
+attribute ntUserParms 2.16.840.1.113730.3.1.62 cis single
+attribute ntUserUnitsPerWeek 2.16.840.1.113730.3.1.63 bin single
+attribute ntUserNumLogons 2.16.840.1.113730.3.1.64 bin single
+attribute ntUserLogonServer 2.16.840.1.113730.3.1.65 cis single
+attribute ntUserUniqueId 2.16.840.1.113730.3.1.66 bin single
+attribute ntUserProfile 2.16.840.1.113730.3.1.67 cis single
+attribute ntUserPasswordExpired 2.16.840.1.113730.3.1.68 bin single
+attribute subtreeACI 2.16.840.1.113730.3.1.69 ces
+attribute serverRoot 2.16.840.1.113730.3.1.70 cis
+attribute serverProductName 2.16.840.1.113730.3.1.71 cis
+attribute serverVersionNumber 2.16.840.1.113730.3.1.72 cis
+attribute installationTimeStamp 2.16.840.1.113730.3.1.73 cis
+attribute administratorContactInfo 2.16.840.1.113730.3.1.74 cis
+attribute adminUrl 2.16.840.1.113730.3.1.75 ces
+attribute serverHostName 2.16.840.1.113730.3.1.76 cis
+attribute changeTime 2.16.840.1.113730.3.1.77 cis
+attribute cirReplicaRoot 2.16.840.1.113730.3.1.79 dn
+attribute cirHost 2.16.840.1.113730.3.1.80 cis
+attribute cirPort 2.16.840.1.113730.3.1.81 cis
+attribute cirBindDn 2.16.840.1.113730.3.1.82 dn
+attribute cirUsePersistentSearch 2.16.840.1.113730.3.1.83 cis
+attribute cirUseSsl 2.16.840.1.113730.3.1.84 cis
+attribute cirBindCredentials 2.16.840.1.113730.3.1.85 ces
+attribute cirLastUpdateApplied 2.16.840.1.113730.3.1.86 cis
+attribute cirUpdateSchedule 2.16.840.1.113730.3.1.87 cis
+attribute cirUpdateFailedat 2.16.840.1.113730.3.1.88 cis
+attribute cirSyncInterval 2.16.840.1.113730.3.1.89 cis
+attribute cirBeginORC 2.16.840.1.113730.3.1.90 cis
+attribute passwordExpirationTime 2.16.840.1.113730.3.1.91 cis operational
+attribute passwordExpWarned 2.16.840.1.113730.3.1.92 cis operational
+attribute passwordRetryCount 2.16.840.1.113730.3.1.93 cis operational
+attribute retryCountResetTime 2.16.840.1.113730.3.1.94 cis operational
+attribute accountUnlockTime 2.16.840.1.113730.3.1.95 cis operational
+attribute passwordHistory 2.16.840.1.113730.3.1.96 bin operational
+attribute passwordMaxAge 2.16.840.1.113730.3.1.97 cis
+attribute passwordExp 2.16.840.1.113730.3.1.98 cis
+attribute passwordMinLength 2.16.840.1.113730.3.1.99 cis
+attribute passwordKeepHistory 2.16.840.1.113730.3.1.100 cis
+attribute passwordInHistory 2.16.840.1.113730.3.1.101 cis
+attribute passwordChange 2.16.840.1.113730.3.1.102 cis
+attribute passwordCheckSyntax 2.16.840.1.113730.3.1.103 cis
+attribute passwordWarning 2.16.840.1.113730.3.1.104 cis
+attribute passwordLockout 2.16.840.1.113730.3.1.105 cis
+attribute passwordMaxFailure 2.16.840.1.113730.3.1.106 cis
+attribute passwordResetDuration 2.16.840.1.113730.3.1.107 cis
+attribute passwordUnlock 2.16.840.1.113730.3.1.108 cis
+attribute passwordLockoutDuration 2.16.840.1.113730.3.1.109 cis
+attribute ntGroupId 2.16.840.1.113730.3.1.110 bin single
+attribute replicaHost 2.16.840.1.113730.3.1.197 cis
+attribute memberURL 2.16.840.1.113730.3.1.198 ces
+attribute memberCertificateDescription 2.16.840.1.113730.3.1.199 ces
+attribute replicaCredentials 2.16.840.1.113730.3.1.202 bin
+attribute replicaEntryFilter 2.16.840.1.113730.3.1.203 ces
+attribute replicaNickName 2.16.840.1.113730.3.1.204 cis
+attribute filterInfo 2.16.840.1.113730.3.1.206 cis
+attribute replicaCFUpdated 2.16.840.1.113730.3.1.217 cis
+attribute replicaAbandonedChanges 2.16.840.1.113730.3.1.218 cis
+attribute vlvBase 2.16.840.1.113730.3.1.207 dn
+attribute vlvScope 2.16.840.1.113730.3.1.208 int
+attribute vlvFilter 2.16.840.1.113730.3.1.209 ces
+attribute vlvSort 2.16.840.1.113730.3.1.210 cis
+attribute vlvName 2.16.840.1.113730.3.1.211 ces
+attribute netscapeMDSuffix 2.16.840.1.113730.3.1.212 dn
+attribute vlvEnabled 2.16.840.1.113730.3.1.213 int
+attribute passwordAllowChangeTime 2.16.840.1.113730.3.1.214 cis operational
+attribute oid 2.16.840.1.113730.3.1.215 cis
+attribute userPKCS12 2.16.840.1.113730.3.1.216 bin
+attribute vlvUses 2.16.840.1.113730.3.1.219 int
+attribute passwordMustChange 2.16.840.1.113730.3.1.220 cis
+attribute passwordStorageScheme 2.16.840.1.113730.3.1.121 cis
+attribute passwordMinAge 2.16.840.1.113730.3.1.122 cis
+attribute passwordResetFailureCount 2.16.840.1.113730.3.1.123 cis
+attribute nsslapd-pluginPath 2.16.840.1.113730.3.1.224 cis
+attribute nsslapd-pluginInitfunc 2.16.840.1.113730.3.1.225 cis
+attribute nsslapd-pluginType 2.16.840.1.113730.3.1.226 cis
+attribute nsslapd-pluginId 2.16.840.1.113730.3.1.227 cis
+attribute nsslapd-pluginVersion 2.16.840.1.113730.3.1.228 cis
+attribute nsslapd-pluginVendor 2.16.840.1.113730.3.1.229 cis
+attribute nsslapd-pluginDescription 2.16.840.1.113730.3.1.230 cis
+attribute nsslapd-pluginEnabled 2.16.840.1.113730.3.1.231 cis
+attribute nsSNMPEnabled 2.16.840.1.113730.3.1.232 cis
+attribute nsSNMPOrganization 2.16.840.1.113730.3.1.233 cis
+attribute nsSNMPLocation 2.16.840.1.113730.3.1.234 cis
+attribute nsSNMPContact 2.16.840.1.113730.3.1.235 cis
+attribute nsSNMPDescription 2.16.840.1.113730.3.1.236 cis
+attribute nsSNMPMasterHost 2.16.840.1.113730.3.1.237 cis
+attribute nsSNMPMasterPort 2.16.840.1.113730.3.1.238 cis
+attribute nsslapd-backend 2.16.840.1.113730.3.1.239 cis
+attribute replicatedattributelist 2.16.840.1.113730.3.1.240 cis
+attribute displayName 2.16.840.1.113730.3.1.241 cis
+attribute nsSystemIndex 2.16.840.1.113730.3.1.242 cis
+attribute nsIndexType 2.16.840.1.113730.3.1.327 cis
+attribute nsMatchingRule 2.16.840.1.113730.3.1.328 cis
+attribute nsAddressBookSyncURL 2.16.840.1.113730.3.1.330 ces
+attribute nsSynchUserIDFormat 2.16.840.1.113730.3.1.406 cis
+attribute nsSynchUniqueAttribute 2.16.840.1.113730.3.1.407 cis
+attribute replicaLastRelevantChange 2.16.840.1.113730.3.1.408 int
+
+#
+# Attribute types with OIDs
+#
+
+attribute associatedDomain 0.9.2342.19200300.100.1.37 cis
+attribute ntUserHomeDir 1.2.840.113556.1.4.44 cis single
+attribute ntUserComment 1.2.840.113556.1.4.156 cis single
+attribute ntUserFlags 1.2.840.113556.1.4.38 bin single
+attribute ntUserScriptPath 1.2.840.113556.1.4.62 cis single
+attribute ntUserWorkstations 1.2.840.113556.1.4.86 cis single
+attribute ntUserLastLogon 1.2.840.113556.1.4.52 cis single
+attribute ntUserLastLogoff 1.2.840.113556.1.4.51 cis single
+attribute ntUserAcctExpires 1.2.840.113556.1.4.159 cis single
+attribute ntUserMaxStorage 1.2.840.113556.1.4.76 bin single
+attribute ntUserLogonHours 1.2.840.113556.1.4.64 bin single
+attribute ntUserBadPwCount 1.2.840.113556.1.4.12 bin single
+attribute ntUserCountryCode 1.2.840.113556.1.4.25 cis single
+attribute ntUserCodePage 1.2.840.113556.1.4.16 bin single
+attribute ntUserPrimaryGroupId 1.2.840.113556.1.4.98 bin single
+attribute ntUserHomeDirDrive 1.2.840.113556.1.4.45 cis single
+attribute ntGroupAttributes 1.2.840.113556.1.4.152 bin single
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis single
+
+
+#
+# Attributes which are used by some objectClass, but with unknown OID
+#
+
+attribute abstract abstract-oid cis
+attribute authorCn documentauthorcommonname authorcn-oid cis
+attribute authorSn documentauthorsurname authorsn-oid cis
+attribute changeLog 2.16.840.1.113730.3.1.35 dn
+attribute changeLogMaximumAge 2.16.840.1.113730.3.1.200 cis
+attribute changeLogMaximumSize 2.16.840.1.113730.3.1.201 cis
+attribute documentStore documentStore-oid cis
+attribute keyWords keyWords-oid cis
+attribute lastModifiedTime 0.9.2342.19200300.100.1.23 cis
+attribute multiLineDescription multiLineDescription-oid cis
+attribute subject subject-oid cis
+attribute ttl timeToLive 1.3.6.1.4.1.250.1.60 cis
+attribute photo 0.9.2342.19200300.100.1.7 bin
+attribute generation generation-oid ces
+attribute obsoletedByDocument obsoletedByDocument-oid dn
+attribute obsoletesDocument obsoletesDocument-oid dn
+attribute reciprocalNamingLink reciprocalNaminglink-oid dn
+attribute updatedByDocument updatedByDocument-oid dn
+attribute updatesDocument updatesDocument-oid dn
+
+#
+# Attribute types from RFC 2307
+#
+
+attribute uidNumber 1.3.6.1.1.1.1.0 cis single
+attribute gidNumber 1.3.6.1.1.1.1.1 cis single
+attribute gecos 1.3.6.1.1.1.1.2 cis single
+attribute homeDirectory 1.3.6.1.1.1.1.3 ces single
+attribute loginShell 1.3.6.1.1.1.1.4 ces single
+attribute shadowLastChange 1.3.6.1.1.1.1.5 cis single
+attribute shadowMin 1.3.6.1.1.1.1.6 cis single
+attribute shadowMax 1.3.6.1.1.1.1.7 cis single
+attribute shadowWarning 1.3.6.1.1.1.1.8 cis single
+attribute shadowInactive 1.3.6.1.1.1.1.9 cis single
+attribute shadowExpire 1.3.6.1.1.1.1.10 cis single
+attribute shadowFlag 1.3.6.1.1.1.1.11 cis single
+attribute memberUid 1.3.6.1.1.1.1.12 cis
+attribute memberNisNetgroup 1.3.6.1.1.1.1.13 cis
+attribute nisNetgroupTriple 1.3.6.1.1.1.1.14 cis
+attribute ipServicePort 1.3.6.1.1.1.1.15 cis single
+attribute ipServiceProtocol 1.3.6.1.1.1.1.16 cis
+attribute ipProtocolNumber 1.3.6.1.1.1.1.17 cis single
+attribute oncRpcNumber 1.3.6.1.1.1.1.18 cis single
+attribute ipHostNumber 1.3.6.1.1.1.1.19 cis
+attribute ipNetworkNumber 1.3.6.1.1.1.1.20 cis single
+attribute ipNetmaskNumber 1.3.6.1.1.1.1.21 cis single
+attribute macAddress 1.3.6.1.1.1.1.22 cis
+attribute bootParameter 1.3.6.1.1.1.1.23 ces
+attribute bootFile 1.3.6.1.1.1.1.24 ces
+attribute automountInformation 1.3.6.1.1.1.1.25 ces
+attribute nisMapName 1.3.6.1.1.1.1.26 ces
+attribute nisMapEntry 1.3.6.1.1.1.1.27 ces single
diff --git a/ldap/cm/v4confs/40/slapd.oc.conf b/ldap/cm/v4confs/40/slapd.oc.conf
new file mode 100644
index 00000000..44a95121
--- /dev/null
+++ b/ldap/cm/v4confs/40/slapd.oc.conf
@@ -0,0 +1,1068 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.oc.conf for Netscape Directory Server 4.0
+#
+# DO NOT MODIFY!
+#
+# The ObjectClasses in this file are Standard ObjectClasses and are expected
+# to be present in Directory Server 4.0 unchanged. Modifing this file may
+# cause interoperability problems.
+#
+# User Defined ObjectClasses should be added by selecting
+# Schema | Create ObjectClasses from the Admin Server.
+#
+# User Defined ObjectClasses are saved in slapd.user_oc.conf
+#
+# All ObjectClasses are viewable in the cn=schema entry under objectclasses.
+#
+# The format of this file is:
+#
+# objectclass ObjectClassName
+# [ oid ObjectIdentifier ]
+# [ superior ParentObjectClass ]
+# [ requires <comma separated list of required attributes> ]
+# [ allows <comma separated list of allowed attributes> ]
+#
+
+objectclass top
+ oid 2.5.6.0
+ requires
+ objectClass
+ allows
+ aci
+
+objectclass alias
+ oid 2.5.6.1
+ superior top
+ requires
+ aliasedObjectName
+
+objectclass country
+ oid 2.5.6.2
+ superior top
+ requires
+ c
+ allows
+ searchGuide,
+ description
+
+objectclass locality
+ oid 2.5.6.3
+ superior top
+ allows
+ description,
+ l,
+ searchGuide,
+ seeAlso,
+ st,
+ street
+
+objectclass organization
+ oid 2.5.6.4
+ superior top
+ requires
+ o
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass organizationalUnit
+ oid 2.5.6.5
+ superior top
+ requires
+ ou
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass person
+ oid 2.5.6.6
+ superior top
+ requires
+ sn,
+ cn
+ allows
+ description,
+ seeAlso,
+ telephoneNumber,
+ userPassword
+
+objectclass organizationalPerson
+ oid 2.5.6.7
+ superior person
+ allows
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ title,
+ x121Address
+
+# The certificate attributes include all subtypes, such as ';binary'.
+#
+objectclass inetOrgPerson
+ oid 2.16.840.1.113730.3.2.2
+ superior organizationalPerson
+ allows
+ audio,
+ businessCategory,
+ carLicense,
+ departmentNumber,
+ displayName,
+ employeeType,
+ employeeNumber,
+ givenName,
+ homePhone,
+ homePostalAddress,
+ initials,
+ jpegPhoto,
+ labeledURI,
+ manager,
+ mobile,
+ pager,
+ photo,
+ preferredLanguage,
+ mail,
+ roomNumber,
+ secretary,
+ uid,
+ x500uniqueIdentifier,
+ userCertificate,
+ userSMimeCertificate,
+ userPKCS12
+
+objectclass ntUser
+ oid 2.16.840.1.113730.3.2.8
+ superior top
+ requires
+ ntUserDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntUserPriv,
+ ntUserHomeDir,
+ ntUserComment,
+ ntUserFlags,
+ ntUserScriptPath,
+ ntUserAuthFlags,
+ ntUserUsrComment,
+ ntUserParms,
+ ntUserWorkstations,
+ ntUserLastLogon,
+ ntUserLastLogoff,
+ ntUserAcctExpires,
+ ntUserMaxStorage,
+ ntUserUnitsPerWeek,
+ ntUserLogonHours,
+ ntUserBadPwCount,
+ ntUserNumLogons,
+ ntUserLogonServer,
+ ntUserCountryCode,
+ ntUserCodePage,
+ ntUserUniqueId,
+ ntUserPrimaryGroupId,
+ ntUserProfile,
+ ntUserHomeDirDrive,
+ ntUserPasswordExpired,
+ ntUserCreateNewAccount,
+ ntUserDeleteAccount
+
+objectclass ntGroup
+ oid 2.16.840.1.113730.3.2.9
+ superior top
+ requires
+ ntGroupDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntGroupId,
+ ntGroupAttributes,
+ ntGroupCreateNewGroup,
+ ntGroupDeleteGroup,
+ ntGroupType
+
+objectclass organizationalRole
+ oid 2.5.6.8
+ superior top
+ requires
+ cn
+ allows
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ roleOccupant,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass groupOfNames
+ oid 2.5.6.9
+ superior top
+ requires
+ cn
+ allows
+ member,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfUniqueNames
+ oid 2.5.6.17
+ superior top
+ requires
+ cn
+ allows
+ uniqueMember,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfCertificates
+ oid 2.16.840.1.113730.3.2.31
+ superior top
+ requires
+ cn
+ allows
+ memberCertificateDescription,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfURLs
+ oid 2.16.840.1.113730.3.2.33
+ superior top
+ requires
+ cn
+ allows
+ memberURL,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass residentialPerson
+ oid 2.5.6.10
+ superior person
+ requires
+ l
+ allows
+ businessCategory,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass applicationProcess
+ oid 2.5.6.11
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso
+
+objectclass LDAPServer
+ oid 2.16.840.1.113730.3.2.35
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ generation,
+ changeLogMaximumAge,
+ changeLogMaximumSize
+
+objectclass LDAPReplica
+ oid 2.16.840.1.113730.3.2.36
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ replicaRoot,
+ replicaHost,
+ replicaPort,
+ replicaBindDn,
+ replicaCredentials,
+ replicaBindMethod,
+ replicaUseSSL,
+ replicaUpdateSchedule,
+ replicaUpdateReplayed,
+ replicaUpdateFailedAt,
+ replicaBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList,
+ replicaCFUpdated,
+ replicaAbandonedChanges,
+ replicaLastRelevantChange
+
+objectclass applicationEntity
+ oid 2.5.6.12
+ superior top
+ requires
+ presentationAddress,
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ supportedApplicationContext
+
+objectclass dSA
+ oid 2.5.6.13
+ superior applicationEntity
+ allows
+ knowledgeInformation
+
+objectclass device
+ oid 2.5.6.14
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+objectclass strongAuthenticationUser
+ oid 2.5.6.15
+ superior top
+ requires
+# This certificate attribute includes all subtypes, such as ';binary'.
+ userCertificate
+
+objectclass certificationAuthority
+ oid 2.5.6.16
+ superior top
+ requires
+# These certificate attributes include all subtypes, such as ';binary'.
+ cACertificate
+ allows
+ authorityRevocationList,
+ certificateRevocationList,
+ crossCertificatePair
+
+objectclass pilotObject
+ oid 0.9.2342.19200300.100.4.3
+ superior top
+ allows
+ audio,
+ dITRedirect,
+ info,
+ jpegPhoto,
+ lastModifiedBy,
+ lastModifiedTime,
+ manager,
+ photo,
+ uniqueIdentifier
+
+objectclass newPilotPerson
+ oid 0.9.2342.19200300.100.4.4
+ superior person
+ allows
+ businessCategory,
+ drink,
+ homePhone,
+ homePostalAddress,
+ janetMailbox,
+ mail,
+ mailPreferenceOption,
+ mobile,
+ organizationalStatus,
+ otherMailbox,
+ pager,
+ personalSignature,
+ personalTitle,
+ preferredDeliveryMethod,
+ roomNumber,
+ secretary,
+ textEncodedORAddress,
+ uid,
+ userClass
+
+objectclass account
+ oid 0.9.2342.19200300.100.4.5
+ superior top
+ requires
+ uid
+ allows
+ description,
+ host,
+ l,
+ o,
+ ou,
+ seeAlso
+
+objectclass document
+ oid 0.9.2342.19200300.100.4.6
+ superior pilotObject
+ requires
+ documentIdentifier
+ allows
+ abstract,
+ authorCN,
+ authorSN,
+ cn,
+ description,
+ documentAuthor,
+ documentLocation,
+ documentPublisher,
+ documentStore,
+ documentTitle,
+ documentVersion,
+ keywords,
+ l,
+ o,
+ obsoletedByDocument,
+ obsoletesDocument,
+ ou,
+ seeAlso,
+ subject,
+ updatedByDocument,
+ updatesDocument
+
+objectclass room
+ oid 0.9.2342.19200300.100.4.7
+ superior top
+ requires
+ cn
+ allows
+ description,
+ roomNumber,
+ seeAlso,
+ telephoneNumber
+
+objectclass documentSeries
+ oid 0.9.2342.19200300.100.4.9
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ telephoneNumber
+
+objectclass domain
+ oid 0.9.2342.19200300.100.4.13
+ superior top
+ requires
+ dc
+ allows
+ associatedName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ manager,
+ o,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass RFC822localPart
+ oid 0.9.2342.19200300.100.4.14
+ superior domain
+ allows
+ cn,
+ sn
+
+objectclass DNSDomain
+ oid 0.9.2342.19200300.100.4.15
+ superior domain
+ allows
+ dNSRecord
+
+objectclass domainRelatedObject
+ oid 0.9.2342.19200300.100.4.17
+ superior top
+ requires
+ associatedDomain
+
+objectclass friendlyCountry
+ oid 0.9.2342.19200300.100.4.18
+ superior country
+ requires
+ co
+
+objectclass simpleSecurityObject
+ oid 0.9.2342.19200300.100.4.19
+ superior top
+ requires
+ userPassword
+
+objectclass pilotOrganization
+ oid pilotOrganization-OID
+ superior top
+ requires
+ ou,
+ o
+ allows
+ buildingName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+
+objectclass labeledURIObject
+ oid 1.3.6.1.4.1.250.3.15
+ superior top
+ allows
+ labeledURI
+
+objectclass cacheObject
+ oid 1.3.6.1.4.1.250.3.18
+ superior top
+ allows
+ ttl
+
+# objectclasses below added since Netscape Directory Server 1.01
+
+objectclass netscapeServer
+ oid 2.16.840.1.113730.3.2.10
+ superior top
+ requires
+ cn
+ allows
+ description,
+ serverRoot,
+ serverProductName,
+ serverVersionNumber,
+ installationTimeStamp,
+ administratorContactInfo,
+ userpassword,
+ adminURL,
+ serverHostName
+
+objectclass nsLicenseUser
+ oid 2.16.840.1.113730.3.2.7
+ superior top
+ allows
+ nsLicensedFor,
+ nsLicenseStartTime,
+ nsLicenseEndTime
+
+objectclass changeLogEntry
+ oid 2.16.840.1.113730.3.2.1
+ superior top
+ requires
+ targetdn,
+ changeTime,
+ changenumber,
+ changeType
+ allows
+ changes,
+ newrdn,
+ deleteoldrdn,
+ newsuperior,
+ filterinfo
+
+objectclass cirReplicaSource
+ oid 2.16.840.1.113730.3.2.11
+ requires
+ cn,
+ objectClass
+ allows
+ cirReplicaRoot,
+ cirHost,
+ cirPort,
+ cirBindDN,
+ cirUsePersistentSearch,
+ cirUseSSL,
+ cirBindCredentials,
+ cirLastUpdateApplied,
+ cirUpdateSchedule,
+ cirSyncInterval,
+ cirUpdateFailedAt,
+ cirBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList
+
+objectclass referral
+ superior top
+ oid 2.16.840.1.113730.3.2.6
+ allows
+ ref
+
+objectclass passwordObject
+ oid 2.16.840.1.113730.3.2.12
+ requires
+ objectClass
+ allows
+ passwordExpirationTime,
+ passwordExpWarned,
+ passwordRetryCount,
+ retryCountResetTime,
+ accountUnlockTime,
+ passwordHistory,
+ passwordAllowChangeTime
+
+objectclass passwordPolicy
+ oid 2.16.840.1.113730.3.2.13
+ requires
+ objectClass
+ allows
+ passwordMaxAge,
+ passwordExp,
+ passwordMinLength,
+ passwordKeepHistory,
+ passwordInHistory,
+ passwordChange,
+ passwordWarning,
+ passwordLockout,
+ passwordMaxFailure,
+ passwordResetDuration,
+ passwordUnlock,
+ passwordLockoutDuration,
+ passwordCheckSyntax,
+ passwordMustChange,
+ passwordStorageScheme,
+ passwordMinAge,
+ passwordResetFailureCount
+
+objectclass glue
+ oid 2.16.840.1.113730.3.2.30
+ superior top
+
+objectclass netscapeMachineData
+ oid 2.16.840.1.113730.3.2.32
+ superior top
+
+objectclass dcObject
+ oid 1.3.6.1.4.1.1466.344
+ superior top
+ requires
+ dc
+
+objectclass subschema
+ oid 2.5.20.1
+ superior top
+ allows
+ cn,
+ dITStructureRules,
+ nameForms,
+ dITContentRules,
+ objectClasses,
+ attributeTypes,
+ matchingRules,
+ matchingRuleUse
+
+objectclass vlvSearch
+ oid 2.16.840.1.113730.3.2.38
+ superior top
+ requires
+ cn,
+ vlvBase,
+ vlvScope,
+ vlvFilter
+ allows
+ multiLineDescription
+
+objectclass nsslapdConfig
+ oid 2.16.840.1.113730.3.2.39
+ superior top
+ allows cn
+
+objectclass directoryServerFeature
+ oid 2.16.840.1.113730.3.2.40
+ superior top
+ allows
+ oid,
+ cn,
+ multiLineDescription
+
+objectclass nsslapdPlugin
+ oid 2.16.840.1.113730.3.2.41
+ superior top
+ requires
+ cn,
+ nsslapd-pluginPath,
+ nsslapd-pluginInitFunc,
+ nsslapd-pluginType,
+ nsslapd-pluginId,
+ nsslapd-pluginVersion,
+ nsslapd-pluginVendor,
+ nsslapd-pluginDescription,
+ nsslapd-pluginEnabled,
+ nsslapd-backend
+
+objectclass vlvIndex
+ oid 2.16.840.1.113730.3.2.42
+ superior top
+ requires
+ cn,
+ vlvSort
+ allows
+ vlvEnabled,
+ vlvUses
+
+objectclass nsSNMP
+ OID 2.16.840.1.113730.3.2.43
+ superior top
+ requires
+ cn,
+ nsSNMPEnabled
+ allows
+ nsSNMPOrganization,
+ nsSNMPLocation,
+ nsSNMPContact,
+ nsSNMPDescription,
+ nsSNMPMasterHost,
+ nsSNMPMasterPort
+
+objectclass nsIndex
+ oid 2.16.840.1.113730.3.2.44
+ superior top
+ requires
+ cn,
+ nsSystemIndex
+ allows
+ description,
+ nsIndexType,
+ nsMatchingRule
+
+#
+# ojectclass from rfc2307
+#
+
+# posixAccount is an auxiliary class. You may use account as a structural
+# class.
+objectclass posixAccount
+ oid
+ 1.3.6.1.1.1.2.0
+ superior
+ top
+ requires
+ objectClass,
+ cn,
+ uid,
+ uidNumber,
+ gidNumber,
+ homeDirectory
+ allows
+ userPassword,
+ loginShell,
+ gecos,
+ description
+
+# posixAccount is an auxiliary class. You may use account as a structural
+# class.
+objectclass shadowAccount
+ oid
+ 1.3.6.1.1.1.2.1
+ superior
+ top
+ requires
+ objectClass,
+ uid
+ allows
+ userPassword,
+ shadowLastChange,
+ shadowMin,
+ shadowMax,
+ shadowWarning,
+ shadowInactive,
+ shadowExpire,
+ shadowFlag,
+ description
+
+objectclass posixGroup
+ oid
+ 1.3.6.1.1.1.2.2
+ requires
+ objectClass,
+ cn,
+ gidNumber
+ allows
+ userPassword,
+ memberUid,
+ description
+
+objectclass ipService
+ oid
+ 1.3.6.1.1.1.2.3
+ requires
+ objectClass,
+ cn,
+ ipServicePort,
+ ipServiceProtocol
+ allows
+ description
+
+objectclass ipProtocol
+ oid
+ 1.3.6.1.1.1.2.4
+ requires
+ objectClass,
+ cn,
+ ipProtocolNumber
+ allows
+ description
+
+objectclass oncRpc
+ oid
+ 1.3.6.1.1.1.2.5
+ requires
+ objectClass,
+ cn,
+ oncRpcNumber
+ allows
+ description
+
+# ipHost is a subclass of device
+objectclass ipHost
+ oid
+ 1.3.6.1.1.1.2.6
+ requires
+ objectClass,
+ ipHostNumber,
+ cn
+ allows
+ manager,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+
+objectclass ipNetwork
+ oid
+ 1.3.6.1.1.1.2.7
+ requires
+ objectClass,
+ ipNetworkNumber,
+ cn
+ allows
+ ipNetmaskNumber,
+ manager,
+ l,
+ description
+
+objectclass nisNetgroup
+ oid
+ 1.3.6.1.1.1.2.8
+ requires
+ objectClass,
+ cn
+ allows
+ nisNetgroupTriple,
+ memberNisNetgroup,
+ description
+
+# the automount class is deprecated. Because cn is case insensitive
+# on matches, you may need to use another object class to unique
+# names.
+objectclass automount
+ oid
+ 1.3.6.1.1.1.2.9
+ requires
+ objectClass,
+ cn,
+ automountInformation
+ allows
+ description
+
+# nisObject represents entries in NIS maps.
+objectclass nisObject
+ oid
+ 1.3.6.1.1.1.2.10
+ requires
+ objectClass,
+ cn,
+ nisMapEntry,
+ nisMapName
+ allows
+ description
+
+# ieee802Device is a subclass of device
+objectclass ieee802Device
+ oid
+ 1.3.6.1.1.1.2.11
+ requires
+ objectClass,
+ cn
+ allows
+ macAddress,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# bootableDevice is a subclass of device
+objectclass bootableDevice
+ oid
+ 1.3.6.1.1.1.2.12
+ requires
+ objectClass,
+ cn
+ allows
+ bootFile,
+ bootParameter,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# nisMap is a structural class which may be used as a container
+# for instances of nisObject.
+objectclass nisMap
+ oid
+ 1.3.6.1.1.1.2.13
+ requires
+ objectClass,
+ nisMapName
+ allows
+ description
+
diff --git a/ldap/cm/v4confs/41/java-object-schema.conf b/ldap/cm/v4confs/41/java-object-schema.conf
new file mode 100644
index 00000000..73f6f836
--- /dev/null
+++ b/ldap/cm/v4confs/41/java-object-schema.conf
@@ -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
+#
+# Schema for storing java objects and java object references
+
+attribute javaClassName 1.3.6.1.4.1.42.2.27.4.1.1 ces single
+
+attribute javaCodebase 1.3.6.1.4.1.42.2.27.4.1.6 ces
+
+attribute javaSerializedData 1.3.6.1.4.1.42.2.27.4.1.7 bin single
+
+attribute javaRemoteLocation 1.3.6.1.4.1.42.2.27.4.1.8 ces single
+
+attribute javaFactory 1.3.6.1.4.1.42.2.27.4.1.4 ces single
+
+attribute javaReferenceAddress 1.3.6.1.4.1.42.2.27.4.1.3 ces
+
+objectclass javaContainer
+ oid 1.3.6.1.4.1.42.2.27.4.2.1
+ superior top
+ requires
+ cn
+
+objectclass javaObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.4
+ superior top
+ requires
+ javaClassName
+ allows
+ javaCodebase
+
+objectclass javaSerializedObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.5
+ superior javaObject
+ requires
+ javaSerializedData
+
+objectclass javaRemoteObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.6
+ superior javaObject
+ requires
+ javaRemoteLocation
+
+objectclass javaNamingReference
+ oid 1.3.6.1.4.1.42.2.27.4.2.7
+ superior javaObject
+ requires
+ javaReferenceAddress,
+ javaFactory
diff --git a/ldap/cm/v4confs/41/ns-admin-schema.conf b/ldap/cm/v4confs/41/ns-admin-schema.conf
new file mode 100644
index 00000000..6bd0a9d0
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-admin-schema.conf
@@ -0,0 +1,155 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Netscape Administration Server LDAP Schema configuration file
+#
+# Version: 4.1
+# Description:
+# Administration Server and Mission Control Console attributes
+# and objectclasses.
+#
+
+#############################################################
+# Attributes
+#############################################################
+
+#
+# nsAdminConfig
+#
+attribute nsAdminCgiWaitPid cis
+attribute nsAdminUsers cis
+attribute nsAdminAccessHosts cis
+attribute nsAdminAccessAddresses cis
+attribute nsAdminOneACLDir cis
+attribute nsAdminEnableDSGW cis
+attribute nsAdminEnableEnduser cis
+attribute nsAdminCacheLifetime cis
+
+
+#
+# nsAdminResourceEditorExtension
+#
+attribute nsAdminAccountInfo cis
+attribute nsDeleteclassname cis
+
+#
+# nsAdminGlobalParameters
+#
+attribute nsAdminEndUserHTMLIndex cis
+
+#
+# nsGlobalParameters
+#
+attribute nsUniqueAttribute cis
+attribute nsUserIDFormat cis
+attribute nsUserRDNComponent cis
+attribute nsGroupRDNComponent cis
+attribute nsWellKnownJarfiles cis
+attribute nsNYR cis
+
+#
+# nsDefaultObjectClasses
+#
+attribute nsDefaultObjectClass cis
+
+#
+# nsAdminConsoleUser
+#
+attribute nsPreference cis
+
+#
+# nsCustomView
+#
+attribute nsDisplayName cis
+
+#
+# nsTopologyCustomView
+#
+attribute nsViewConfiguration cis
+
+#############################################################
+# Objectclasses
+#############################################################
+
+objectclass nsAdminServer
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description
+
+objectclass nsAdminConfig
+ superior nsConfig
+ allows
+ nsAdminCgiWaitPid,
+ nsAdminUsers,
+ nsAdminAccessHosts,
+ nsAdminAccessAddresses,
+ nsAdminOneACLDir,
+ nsAdminEnableDSGW,
+ nsAdminEnableEnduser,
+ nsAdminCacheLifetime
+
+objectclass nsAdminResourceEditorExtension
+ superior nsAdminObject
+ requires
+ cn
+ allows
+ nsAdminAccountInfo,
+ nsDeleteclassname
+
+objectclass nsAdminGlobalParameters
+ superior top
+ requires
+ cn
+ allows
+ nsAdminEndUserHTMLIndex,
+ nsNickname
+
+objectclass nsGlobalParameters
+ superior top
+ requires
+ cn
+ allows
+ nsUniqueAttribute,
+ nsUserIDFormat,
+ nsUserRDNComponent,
+ nsGroupRDNComponent,
+ nsWellKnownJarFiles,
+ nsNYR
+
+objectclass nsDefaultObjectClasses
+ superior top
+ requires
+ cn
+ allows
+ nsDefaultObjectClass
+
+objectclass nsAdminConsoleUser
+ superior top
+ requires
+ cn
+ allows
+ nsPreference
+
+objectclass nsCustomView
+ superior nsAdminObject
+ allows
+ nsDisplayName,
+
+objectclass nsTopologyCustomView
+ superior nsCustomView
+ requires
+ cn
+ allows
+ nsViewConfiguration
+
+objectclass nsTopologyPlugin
+ superior nsAdminObject
+ allows
diff --git a/ldap/cm/v4confs/41/ns-calendar-globopt.conf b/ldap/cm/v4confs/41/ns-calendar-globopt.conf
new file mode 100644
index 00000000..0bdb7dd9
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-calendar-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+index nsCalXItemId pres,eq,sub
diff --git a/ldap/cm/v4confs/41/ns-calendar-schema.conf b/ldap/cm/v4confs/41/ns-calendar-schema.conf
new file mode 100644
index 00000000..2a35ae3c
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-calendar-schema.conf
@@ -0,0 +1,148 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsCalAccess 2.16.840.1.113730.3.1.112 cis
+attribute nsCalAccessDomain 2.16.840.1.113730.3.1.113 cis
+attribute nsCalAdmd 2.16.840.1.113730.3.1.114 cis
+attribute nsCalDefaultNoteReminder 2.16.840.1.113730.3.1.115 cis
+attribute nsCalDefaultReminder 2.16.840.1.113730.3.1.116 cis
+attribute nsCalDefaultTaskReminder 2.16.840.1.113730.3.1.117 cis
+attribute nsCalDisplayPrefs 2.16.840.1.113730.3.1.118 cis
+attribute nsCalFlags 2.16.840.1.113730.3.1.119 cis
+attribute nsCalHost 2.16.840.1.113730.3.1.120 cis
+attribute nsCalLanguageId 2.16.840.1.113730.3.1.121 cis
+attribute nsCalNodeAlias 2.16.840.1.113730.3.1.122 cis
+attribute nsCalNotifMechanism 2.16.840.1.113730.3.1.123 cis
+attribute nsCalOperatingPrefs 2.16.840.1.113730.3.1.124 cis
+attribute nsCalOrgUnit2 2.16.840.1.113730.3.1.125 cis
+attribute nsCalOrgUnit3 2.16.840.1.113730.3.1.126 cis
+attribute nsCalOrgUnit4 2.16.840.1.113730.3.1.127 cis
+attribute nsCalPasswordRequired 2.16.840.1.113730.3.1.128 cis
+attribute nsCalPrmd 2.16.840.1.113730.3.1.129 cis
+attribute nsCalRefreshPrefs 2.16.840.1.113730.3.1.130 cis
+attribute nsCalResourceCapacity 2.16.840.1.113730.3.1.131 cis
+attribute nsCalResourceNumber 2.16.840.1.113730.3.1.132 cis
+attribute nsCalServerVersion 2.16.840.1.113730.3.1.133 cis
+attribute nsCalSysopCanWritePassword 2.16.840.1.113730.3.1.134 cis
+attribute nsCalTimezone 2.16.840.1.113730.3.1.135 cis
+attribute nsCalXItemId 2.16.840.1.113730.3.1.136 cis
+
+
+objectclass nsCalUser
+ oid 2.16.840.1.113730.3.2.14
+ requires
+ objectClass
+ allows
+ c,
+ employeeNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ mail,
+ o,
+ ou,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalRefreshPrefs,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass nsCalAdmin
+ oid 2.16.840.1.113730.3.2.15
+ requires
+ objectClass
+ allows
+ c,
+ cn,
+ facsimileTelephoneNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ mail,
+ o,
+ ou,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalXItemId
+
+objectclass nsCalResource
+ oid 2.16.840.1.113730.3.2.16
+ requires
+ objectClass
+ allows
+ cn,
+ facsimileTelephoneNumber,
+ givenName,
+ mail,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalPasswordRequired,
+ nsCalRefreshPrefs,
+ nsCalResourceCapacity,
+ nsCalResourceNumber,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass netscapeCalendarServer
+ oid 2.16.840.1.113730.3.2.17
+ requires
+ objectclass
+
+
+
diff --git a/ldap/cm/v4confs/41/ns-certificate-globopt.conf b/ldap/cm/v4confs/41/ns-certificate-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-certificate-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/41/ns-certificate-schema.conf b/ldap/cm/v4confs/41/ns-certificate-schema.conf
new file mode 100644
index 00000000..a9ef7b9d
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-certificate-schema.conf
@@ -0,0 +1,24 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+attribute nsCertConfig cis
+
+objectclass netscapeCertificateServer
+ oid 2.16.840.1.113730.3.2.18
+ requires
+ objectclass
+
+objectclass nsCertificateServer
+ requires
+ objectclass,
+ nsServerID
+ allows
+ serverHostName,
+ nsServerPort,
+ nsCertConfig
+
+
diff --git a/ldap/cm/v4confs/41/ns-common-schema.conf b/ldap/cm/v4confs/41/ns-common-schema.conf
new file mode 100644
index 00000000..a8d7b00c
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-common-schema.conf
@@ -0,0 +1,246 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Common LDAP schema configuration file
+#
+# Version: 4.1
+# Description:
+# This configuration file contains objectclasses and attributes
+# common to the Mission Control Framework
+#
+
+#############################################################
+# Attributes
+#############################################################
+
+#
+# Common Attributes
+#
+attribute nsServerID cis
+attribute nsBaseDN cis
+attribute nsBindDN cis
+attribute nsBindPassword cis
+attribute nsServerPort cis
+attribute nsServerAddress cis
+attribute nsDirectoryInfoRef dn
+attribute nsDirectoryURL ces
+attribute nsDirectoryFailoverList ces
+#
+# nsAdminDomain
+#
+attribute nsAdminDomainName cis
+
+#
+# nsHost
+#
+attribute nsHostLocation cis
+attribute nsHardwarePlatform cis
+attribute nsOsVersion cis
+
+#
+# nsAdminGroup
+#
+attribute nsAdminGroupName cis
+attribute nsConfigRoot cis
+attribute nsAdminSIEDN dn
+
+#
+# nsApplication
+#
+attribute nsVendor cis
+attribute nsProductName cis
+attribute nsNickName cis
+attribute nsProductVersion cis
+attribute nsBuildNumber cis
+attribute nsRevisionNumber cis
+attribute nsSerialNumber cis
+attribute nsInstalledLocation cis
+attribute nsExpirationDate cis
+attribute nsBuildSecurity cis
+attribute nsServerMigrationClassname cis
+attribute nsServerCreationClassname cis
+attribute nsLdapSchemaVersion cis
+
+#
+# nsConfig
+#
+attribute nsSuiteSpotUser cis
+attribute nsErrorLog cis
+attribute nsPidLog cis
+attribute nsAccessLog cis
+attribute nsDefaultAcceptLanguage cis
+attribute nsServerSecurity cis
+
+#
+# nsEncryptionConfig
+#
+attribute nsCertfile cis
+attribute nsKeyfile cis
+attribute nsSSL2 cis
+attribute nsSSL3 cis
+attribute nsSSLClientAuth cis
+attribute nsSSLSessionTimeout cis
+attribute nsSSL3SessionTimeout cis
+attribute nsSSL2Ciphers cis
+attribute nsSSL3Ciphers cis
+
+#
+# nsEncryptionModule
+#
+attribute nsSSLToken cis
+attribute nsSSLPersonalitySSL cis
+attribute nsSSLActivation cis
+
+#
+# nsTask
+#
+attribute nsTaskLabel cis
+attribute nsHelpRef cis
+attribute nsExecRef cis
+attribute nsLogSuppress cis
+
+#
+# nsAdminObject
+#
+attribute nsJarfilename cis
+attribute nsClassname cis
+
+
+#############################################################
+# Object Classes
+#############################################################
+objectclass nsAdminDomain
+ superior organizationalUnit
+ allows
+ nsAdminDomainName
+
+objectclass nsHost
+ superior top
+ requires
+ cn
+ allows
+ serverHostName,
+ description,
+ l,
+ nsHostLocation,
+ nsHardwarePlatform,
+ nsOsVersion
+
+objectclass nsAdminGroup
+ superior top
+ requires
+ cn
+ allows
+ nsAdminGroupName,
+ description,
+ nsConfigRoot,
+ nsAdminSIEDN
+
+objectclass nsApplication
+ superior top
+ requires
+ cn
+ allows
+ nsVendor,
+ description,
+ nsProductName,
+ nsNickName,
+ nsProductVersion,
+ nsBuildNumber,
+ nsRevisionNumber,
+ nsSerialNumber,
+ nsInstalledLocation,
+ installationTimeStamp,
+ nsExpirationDate,
+ nsBuildSecurity,
+ nsLdapSchemaVersion,
+ nsServerMigrationClassname,
+ nsServerCreationClassname
+
+objectclass nsEncryptionConfig
+ superior top
+ requires
+ cn
+ allows
+ nsCertfile,
+ nsKeyfile,
+ nsSSL2,
+ nsSSL3,
+ nsSSLSessionTimeout,
+ nsSSL3SessionTimeout,
+ nsSSLClientAuth,
+ nsSSL2Ciphers,
+ nsSSL3Ciphers
+
+objectclass nsEncryptionModule
+ superior top
+ requires
+ cn
+ allows
+ nsSSLToken,
+ nsSSLPersonalityssl,
+ nsSSLActivation
+
+
+objectclass nsResourceRef
+ superior top
+ requires
+ cn
+ allows
+ seeAlso
+
+objectclass nsTask
+ superior top
+ requires
+ cn
+ allows
+ nsTaskLabel,
+ nsHelpref,
+ nsExecref,
+ nsLogSuppress
+
+objectclass nsTaskGroup
+ superior top
+ requires
+ cn
+ allows
+ nsTaskLabel
+
+objectclass nsAdminObject
+ superior top
+ requires
+ cn
+ allows
+ nsJarFilename,
+ nsClassName
+
+objectclass nsConfig
+ superior top
+ requires
+ cn
+ allows
+ description,
+ nsServerPort,
+ nsServerAddress,
+ nsSuiteSpotUser,
+ nsErrorLog,
+ nsPidLog,
+ nsAccessLog,
+ nsDefaultAcceptLanguage,
+ nsServerSecurity
+
+objectclass nsDirectoryInfo
+ superior top
+ requires
+ cn
+ allows
+ nsBindDN,
+ nsBindPassword,
+ nsDirectoryURL,
+ nsDirectoryFailoverList,
+ nsDirectoryInfoRef
diff --git a/ldap/cm/v4confs/41/ns-compass-globopt.conf b/ldap/cm/v4confs/41/ns-compass-globopt.conf
new file mode 100644
index 00000000..4d2e1e21
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-compass-globopt.conf
@@ -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
+#
+# Used by Netscape Directory Server
+index pipuid pres,eq,sub
+index pipstatus eq
+
diff --git a/ldap/cm/v4confs/41/ns-compass-schema.conf b/ldap/cm/v4confs/41/ns-compass-schema.conf
new file mode 100644
index 00000000..be13bc44
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-compass-schema.conf
@@ -0,0 +1,173 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+
+# Compass server specific (not currently used)
+
+objectclass netscapeCompassServer
+ oid 2.16.840.1.113730.3.2.19
+ requires
+ objectclass
+
+
+# Attributes for personal interest profile classes
+
+attribute pipuid 2.16.840.1.113730.3.1.137 cis
+attribute pipcompassservers 2.16.840.1.113730.3.1.138 cis
+attribute pipuniqueid 2.16.840.1.113730.3.1.139 cis
+attribute pipstatus 2.16.840.1.113730.3.1.140 cis
+attribute pipusertype 2.16.840.1.113730.3.1.141 cis
+attribute pipfrequency 2.16.840.1.113730.3.1.142 cis
+attribute pipmedium 2.16.840.1.113730.3.1.143 cis
+attribute pipformat 2.16.840.1.113730.3.1.144 cis
+attribute piphour 2.16.840.1.113730.3.1.145 cis
+attribute pipmaxhits 2.16.840.1.113730.3.1.146 cis
+attribute pipresultset 2.16.840.1.113730.3.1.147 cis
+attribute pipsortorder 2.16.840.1.113730.3.1.148 cis
+attribute piptimestamp 2.16.840.1.113730.3.1.149 cis
+attribute pipirlist 2.16.840.1.113730.3.1.150 cis
+attribute pipiroption 2.16.840.1.113730.3.1.151 cis
+attribute pippwp 2.16.840.1.113730.3.1.152 cis
+attribute piplastcount 2.16.840.1.113730.3.1.153 cis
+attribute piptotalcount 2.16.840.1.113730.3.1.154 cis
+attribute piptotalrun 2.16.840.1.113730.3.1.155 cis
+attribute pipnotify 2.16.840.1.113730.3.1.156 cis
+attribute pipprivilege 2.16.840.1.113730.3.1.157 cis
+attribute pipgroup 2.16.840.1.113730.3.1.158 cis
+attribute pipidstcount 2.16.840.1.113730.3.1.159 cis
+attribute pipstid 2.16.840.1.113730.3.1.160 cis
+attribute pipstname 2.16.840.1.113730.3.1.161 cis
+attribute pipstquery 2.16.840.1.113730.3.1.162 cis
+attribute pipsttaxonomy 2.16.840.1.113730.3.1.163 cis
+attribute pipstinterest 2.16.840.1.113730.3.1.164 cis
+attribute pipsttype 2.16.840.1.113730.3.1.165 cis
+attribute pipstprivacy 2.16.840.1.113730.3.1.166 cis
+attribute pipststatus 2.16.840.1.113730.3.1.167 cis
+attribute pipstlastcount 2.16.840.1.113730.3.1.168 cis
+attribute pipsttotalcount 2.16.840.1.113730.3.1.169 cis
+attribute pipsttotalrun 2.16.840.1.113730.3.1.170 cis
+attribute pipstcategory 2.16.840.1.113730.3.1.171 cis
+attribute pipstfrequency 2.16.840.1.113730.3.1.172 cis
+attribute pipstmedium 2.16.840.1.113730.3.1.173 cis
+attribute pipstformat 2.16.840.1.113730.3.1.174 cis
+attribute pipsthour 2.16.840.1.113730.3.1.175 cis
+attribute pipstmaxhits 2.16.840.1.113730.3.1.176 cis
+attribute pipstresultset 2.16.840.1.113730.3.1.177 cis
+attribute pipstsortorder 2.16.840.1.113730.3.1.178 cis
+attribute pipsttimestamp 2.16.840.1.113730.3.1.179 cis
+attribute pipstirlist 2.16.840.1.113730.3.1.180 cis
+attribute pipstiroption 2.16.840.1.113730.3.1.181 cis
+attribute pipreservedcis1 2.16.840.1.113730.3.1.182 cis
+attribute pipreservedcis2 2.16.840.1.113730.3.1.183 cis
+attribute pipreservedcis3 2.16.840.1.113730.3.1.184 cis
+attribute pipreservedcis4 2.16.840.1.113730.3.1.185 cis
+attribute pipreservedcis5 2.16.840.1.113730.3.1.186 cis
+attribute pipreservedcis6 2.16.840.1.113730.3.1.187 cis
+attribute pipreservedces1 2.16.840.1.113730.3.1.188 ces
+attribute pipreservedces2 2.16.840.1.113730.3.1.189 ces
+attribute pipreservedces3 2.16.840.1.113730.3.1.190 ces
+
+
+# Each interest profile is one of these and sits under the compass SIE
+
+objectclass personalInterestProfile
+ oid 2.16.840.1.113730.3.2.20
+ requires
+ objectclass,
+ pipuid
+ allows
+ pipuniqueid,
+ pipstatus,
+ pipusertype,
+ pipfrequency,
+ pipmedium,
+ pipformat,
+ piphour,
+ pipmaxhits,
+ pipresultset,
+ pipsortorder,
+ piptimestamp,
+ pipirlist,
+ pipiroption,
+ pippwp,
+ piplastcount,
+ piptotalcount,
+ piptotalrun,
+ pipnotify,
+ pipprivilege,
+ pipgroup,
+ pipidstcount,
+ pipstid,
+ pipstname,
+ pipstquery,
+ pipsttaxonomy,
+ pipstinterest,
+ pipsttype,
+ pipstprivacy,
+ pipststatus,
+ pipstlastcount,
+ pipsttotalcount,
+ pipsttotalrun,
+ pipstcategory,
+ pipstfrequency,
+ pipstmedium,
+ pipstformat,
+ pipsthour,
+ pipstmaxhits,
+ pipstresultset,
+ pipstsortorder,
+ pipsttimestamp,
+ pipstirlist,
+ pipstiroption,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
+
+# Replication of user info for template users, completeness, etc.
+# (not currently used)
+
+objectclass PIPUserInfo
+ oid 2.16.840.1.113730.3.2.21
+ requires
+ objectclass
+ allows
+ cn,
+ mail,
+ userPassword,
+ description,
+ pipcompassservers,
+ pipuniqueid
+
+
+# Enhancements to a normal user entry (not currently used)
+
+objectclass PIPUser
+ oid 2.16.840.1.113730.3.2.22
+ requires
+ objectclass
+ allows
+ pipuniqueid,
+ pipcompassservers,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
diff --git a/ldap/cm/v4confs/41/ns-cos-schema.conf b/ldap/cm/v4confs/41/ns-cos-schema.conf
new file mode 100644
index 00000000..3d0f9f1a
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-cos-schema.conf
@@ -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
+#
+# Attributes used by Class of Service
+
+attribute cosAttribute 2.16.840.1.113730.3.1.550 cis
+attribute cosSpecifier 2.16.840.1.113730.3.1.551 cis
+attribute cosTargetTree 2.16.840.1.113730.3.1.552 cis
+attribute cosTemplateDn 2.16.840.1.113730.3.1.553 cis
+
+# Object classes used by Class of Service
+
+objectclass cosDefinition
+ oid 2.16.840.1.113730.3.2.84
+ superior top
+ requires
+ objectclass
+ allows
+ aci,
+ cn,
+ uid,
+ costargettree,
+ costemplatedn,
+ cosspecifier,
+ cosattribute
diff --git a/ldap/cm/v4confs/41/ns-delegated-admin-schema.conf b/ldap/cm/v4confs/41/ns-delegated-admin-schema.conf
new file mode 100644
index 00000000..b25c9146
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-delegated-admin-schema.conf
@@ -0,0 +1,62 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Netscape Delegated Administrator LDAP Schema
+#
+# Version: 1.0
+#
+# Attributes and objectclasses for:
+#
+# Netscape Delegated Administrator 1.0
+#
+# DT 9/24/98
+
+#############################################################
+# Delegated User Administration Attributes
+#############################################################
+
+attribute nsNumUsers cis
+attribute nsMaxUsers cis
+attribute nsNumDepts cis
+attribute nsMaxDepts cis
+attribute nsNumDomains cis
+attribute nsDefaultMaxDeptSize cis
+attribute nsSearchFilter cis
+
+#############################################################
+# Delegated User Administration Objectclasses
+#############################################################
+
+objectclass nsManagedISP
+ superior top
+ allows
+ nsNumDomains
+
+objectclass nsManagedDomain
+ superior top
+ allows
+ owner,
+ nsNumUsers,
+ nsMaxUsers,
+ nsNumDepts,
+ nsMaxDepts,
+ nsDefaultMaxDeptSize
+
+objectclass nsManagedDept
+ superior groupofuniquenames
+ allows
+ owner,
+ nsNumUsers,
+ nsMaxUsers
+
+objectclass nsManagedPerson
+ superior top
+ allows
+ owner,
+ nsSearchFilter
+
diff --git a/ldap/cm/v4confs/41/ns-directory-globopt.conf b/ldap/cm/v4confs/41/ns-directory-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-directory-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/41/ns-directory-schema.conf b/ldap/cm/v4confs/41/ns-directory-schema.conf
new file mode 100644
index 00000000..d928081f
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-directory-schema.conf
@@ -0,0 +1,27 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsSecureServerPort cis
+
+objectclass netscapeDirectoryServer
+ oid 2.16.840.1.113730.3.2.23
+ requires
+ objectclass
+
+objectclass nsDirectoryServer
+ requires
+ objectclass,
+ nsServerID
+ allows
+ serverHostName,
+ nsServerPort,
+ nsSecureServerPort,
+ nsBindPassword,
+ nsBindDN,
+ nsBaseDN
diff --git a/ldap/cm/v4confs/41/ns-legacy-schema.conf b/ldap/cm/v4confs/41/ns-legacy-schema.conf
new file mode 100644
index 00000000..4f7c4ac4
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-legacy-schema.conf
@@ -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
+#
+attribute url cis
+
+#use by Netscape Admin Server 4.1 for LegacyServers
+
+objectclass nsLegacyAdminGroup
+ superior
+ nsAdminGroup
+ allows
+ adminUrl
+
+objectclass nsLegacyApplication
+ superior
+ nsApplication
+ allows
+
+objectclass nsLegacyAdminServer
+ superior
+ nsAdminServer
+ allows
+
+objectclass nsLegacyServer
+ superior
+ netscapeServer
+ allows
+ nsServerID,
+ url
diff --git a/ldap/cm/v4confs/41/ns-mail-globopt.conf b/ldap/cm/v4confs/41/ns-mail-globopt.conf
new file mode 100644
index 00000000..2e6cac65
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-mail-globopt.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Messaging Server
+index mailAlternateAddress eq
+index mailHost eq
+#index uid,mail eq
+#index uniquemember,member eq
diff --git a/ldap/cm/v4confs/41/ns-mail-schema.conf b/ldap/cm/v4confs/41/ns-mail-schema.conf
new file mode 100644
index 00000000..ca0fdc5d
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-mail-schema.conf
@@ -0,0 +1,144 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+attribute mailAccessDomain 2.16.840.1.113730.3.1.12 cis
+attribute mailAlternateAddress 2.16.840.1.113730.3.1.13 cis
+attribute mailAutoReplyMode 2.16.840.1.113730.3.1.14 cis
+attribute mailAutoReplyText 2.16.840.1.113730.3.1.15 cis
+attribute mailDeliveryOption 2.16.840.1.113730.3.1.16 cis
+attribute mailForwardingAddress 2.16.840.1.113730.3.1.17 cis
+attribute mailHost 2.16.840.1.113730.3.1.18 cis
+attribute mailQuota 2.16.840.1.113730.3.1.21 cis
+attribute mailRoutingAddress 2.16.840.1.113730.3.1.47 cis
+
+attribute mailMessageStore 2.16.840.1.113730.3.1.19 ces
+attribute mailProgramDeliveryInfo 2.16.840.1.113730.3.1.20 ces
+
+attribute nsmsgDisallowAccess ces
+
+attribute vacationstartdate cis
+attribute vacationenddate cis
+
+# mailRecipient is used to designate an LDAP entry as representing some
+# entity that can receive mail, e.g. a mail user or mail group.
+# Note: attributes 'mailAccessDomain' through 'userPassword' do not
+# belong to mailRecipient, but are included here for backward compatibility.
+objectClass mailRecipient
+ oid 2.16.840.1.113730.3.2.3
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mailAccessDomain,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota,
+ multiLineDescription,
+ uid,
+ userPassword
+
+attribute nswmExtendedUserPrefs 2.16.840.1.113730.3.1.520 cis
+
+# nsMessagingServerUser is used to designate an LDAP entry as representing a
+# Netscape Messaging Server user account. It is used in combination with
+# mailRecipient.
+objectClass nsMessagingServerUser
+ oid 2.16.840.113730.3.2.37
+ requires
+ objectClass
+ allows
+ cn,
+ mailAccessDomain,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota,
+ nsmsgDisallowAccess,
+ nswmExtendedUserPrefs,
+ vacationstartdate,
+ vacationenddate
+
+attribute mgrpAllowedDomain 2.16.840.1.113730.3.1.23 cis
+attribute mgrpMsgRejectAction 2.16.840.1.113730.3.1.28 cis
+attribute mgrpRFC822MailMember 2.16.840.1.113730.3.1.30 cis
+attribute mgrpMsgMaxSize 2.16.840.1.113730.3.1.32 cis single
+attribute mgrpBroadcasterPolicy cis
+attribute mgrpNoDuplicateChecks cis single
+attribute mgrpRemoveHeader cis
+
+attribute mgrpAllowedBroadcaster 2.16.840.1.113730.3.1.22 ces
+attribute mgrpDeliverTo 2.16.840.1.113730.3.1.25 ces
+attribute mgrpErrorsTo 2.16.840.1.113730.3.1.26 ces single
+attribute mgrpModerator 2.16.840.1.113730.3.1.33 ces
+attribute mgrpMsgRejectText 2.16.840.1.113730.3.1.29 ces
+attribute mgrpAddHeader ces
+
+attribute mgrpApprovePassword ces single
+
+# mailGroup is used to designate an LDAP entry as representing a mail group
+# (mailing list). It is used in combination with mailRecipient.
+# Note: attributes 'mail' through 'mailRoutingAddress' belong to mailRecipient,
+# but are also included here for backward compatibility.
+objectClass mailGroup
+ oid 2.16.840.1.113730.3.2.4
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mgrpAddHeader,
+ mgrpAllowedBroadcaster,
+ mgrpAllowedDomain,
+ mgrpApprovePassword,
+ mgrpBroadcasterPolicy,
+ mgrpDeliverTo,
+ mgrpErrorsTo,
+ mgrpModerator,
+ mgrpMsgMaxSize,
+ mgrpMsgRejectAction,
+ mgrpMsgRejectText,
+ mgrpNoDuplicateChecks,
+ mgrpRemoveHeader,
+ mgrpRFC822MailMember,
+ owner
+
+attribute mailEnhancedUniqueMember 2.16.840.1.113730.3.1.31 dn
+
+objectClass groupOfMailEnhancedUniqueNames
+ oid 2.16.840.1.113730.3.2.5
+ requires
+ objectClass,
+ cn
+ allows
+ businessCategory,
+ description,
+ mailEnhancedUniqueMember,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectClass netscapeMailServer
+ oid 2.16.840.1.113730.3.2.24
+ requires
+ objectClass
+
diff --git a/ldap/cm/v4confs/41/ns-mcd-browser-schema.conf b/ldap/cm/v4confs/41/ns-mcd-browser-schema.conf
new file mode 100644
index 00000000..dd2e228f
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-mcd-browser-schema.conf
@@ -0,0 +1,179 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-browser-schema.conf
+#
+# Netscape Mission Control Desktop browser client schema
+# This schema is used to hold browser client preferences.
+#
+
+attribute nsBCStartupBrowser 2.16.840.1.113730.3.1.409 cis
+attribute nsBCStartupMail 2.16.840.1.113730.3.1.410 cis
+attribute nsBCStartupEditor 2.16.840.1.113730.3.1.411 cis
+attribute nsBCStartupCalendar 2.16.840.1.113730.3.1.412 cis
+attribute nsBCChromeButtonStyle 2.16.840.1.113730.3.1.413 cis
+attribute nsBCUseDocumentFonts 2.16.840.1.113730.3.1.414 cis
+attribute nsBCForegroundColor 2.16.840.1.113730.3.1.415 cis
+attribute nsBCBackgroundColor 2.16.840.1.113730.3.1.416 cis
+attribute nsBCAnchorColor 2.16.840.1.113730.3.1.417 cis
+attribute nsBCVisitedColor 2.16.840.1.113730.3.1.418 cis
+attribute nsBCUnderlineAnchors 2.16.840.1.113730.3.1.419 cis
+attribute nsBCUseDocumentColors 2.16.840.1.113730.3.1.420 cis
+attribute nsBCStartupPage 2.16.840.1.113730.3.1.421 cis
+attribute nsBCStartupHomePage 2.16.840.1.113730.3.1.422 cis
+attribute nsBCLinkExpiration 2.16.840.1.113730.3.1.423 cis
+attribute nsBCIntlAcceptLanguages 2.16.840.1.113730.3.1.424 cis
+attribute nsBCMimeType 2.16.840.1.113730.3.1.425 cis
+attribute nsBCMimeAllowAdd 2.16.840.1.113730.3.1.426 cis
+attribute nsBCMimeAllowEdit 2.16.840.1.113730.3.1.427 cis
+attribute nsBCMimeAllowRemove 2.16.840.1.113730.3.1.428 cis
+attribute nsBCRelatedEnabled 2.16.840.1.113730.3.1.429 cis
+attribute nsBCRelatedAutoload 2.16.840.1.113730.3.1.430 cis
+attribute nsBCRelatedDisabledForDomains 2.16.840.1.113730.3.1.431 cis
+attribute nsBCGoBrowsingEnabled 2.16.840.1.113730.3.1.432 cis
+attribute nsBCOfflineStartupState 2.16.840.1.113730.3.1.433 cis
+attribute nsBCOfflineSendUnsentMessages 2.16.840.1.113730.3.1.434 cis
+attribute nsBCOfflinePromptSynchOnExit 2.16.840.1.113730.3.1.435 cis
+attribute nsBCAlwaysLoadImages 2.16.840.1.113730.3.1.436 cis
+attribute nsBCEnableJava 2.16.840.1.113730.3.1.437 cis
+attribute nsBCEnableJavaScript 2.16.840.1.113730.3.1.438 cis
+attribute nsBCEnableStyleSheets 2.16.840.1.113730.3.1.439 cis
+attribute nsBCEmailAsFtpPassword 2.16.840.1.113730.3.1.440 cis
+attribute nsBCCookieBehavior 2.16.840.1.113730.3.1.441 cis
+attribute nsBCWarnAboutCookies 2.16.840.1.113730.3.1.442 cis
+attribute nsBCMemoryCacheSize 2.16.840.1.113730.3.1.443 cis
+attribute nsBCDiskCacheSize 2.16.840.1.113730.3.1.444 cis
+attribute nsBCCheckDocFrequency 2.16.840.1.113730.3.1.445 cis
+attribute nsBCProxyType 2.16.840.1.113730.3.1.446 cis
+attribute nsBCProxyHttp 2.16.840.1.113730.3.1.447 cis
+attribute nsBCProxySsl 2.16.840.1.113730.3.1.448 cis
+attribute nsBCProxyFtp 2.16.840.1.113730.3.1.449 cis
+attribute nsBCProxySocks 2.16.840.1.113730.3.1.450 cis
+attribute nsBCProxyGopher 2.16.840.1.113730.3.1.451 cis
+attribute nsBCProxyWais 2.16.840.1.113730.3.1.452 cis
+attribute nsBCNoProxiesOn 2.16.840.1.113730.3.1.453 cis
+attribute nsBCProxyAutoConfigUrl 2.16.840.1.113730.3.1.454 cis
+attribute nsBCAutoUpdateEnabled 2.16.840.1.113730.3.1.455 cis
+attribute nsBCAutoUpdateConfirmInstall 2.16.840.1.113730.3.1.456 cis
+
+
+objectclass nsBrowserClient
+ oid 2.16.840.1.113730.3.2.78
+ superior top
+ allows
+ nsBCStartupBrowser,
+ nsBCStartupMail,
+ nsBCStartupEditor,
+ nsBCStartupCalendar,
+ nsBCChromeButtonStyle,
+ nsBCUseDocumentFonts,
+ nsBCForegroundColor,
+ nsBCBackgroundColor,
+ nsBCAnchorColor,
+ nsBCVisitedColor,
+ nsBCUnderlineAnchors,
+ nsBCUseDocumentColors,
+ nsBCStartupPage,
+ nsBCStartupHomePage,
+ nsBCLinkExpiration,
+ nsBCIntlAcceptLanguages,
+ nsBCMimeType,
+ nsBCMimeAllowAdd,
+ nsBCMimeAllowEdit,
+ nsBCMimeAllowRemove,
+ nsBCRelatedEnabled,
+ nsBCRelatedAutoload,
+ nsBCRelatedDisabledForDomains,
+ nsBCGoBrowsingEnabled,
+ nsBCOfflineStartupState,
+ nsBCOfflineSendUnsentMessages,
+ nsBCOfflinePromptSynchOnExit,
+ nsBCAlwaysLoadImages,
+ nsBCEnableJava,
+ nsBCEnableJavaScript,
+ nsBCEnableStyleSheets,
+ nsBCEmailAsFtpPassword,
+ nsBCCookieBehavior,
+ nsBCWarnAboutCookies,
+ nsBCMemoryCacheSize,
+ nsBCDiskCacheSize,
+ nsBCCheckDocFrequency,
+ nsBCProxyType,
+ nsBCProxyHttp,
+ nsBCProxySsl,
+ nsBCProxyFtp,
+ nsBCProxySocks,
+ nsBCProxyGopher,
+ nsBCProxyWais,
+ nsBCNoProxiesOn,
+ nsBCProxyAutoConfigUrl,
+ nsBCAutoUpdateEnabled,
+ nsBCAutoUpdateConfirmInstall
+
+#
+# Netscape Mission Control Desktop browser security schema
+# This schema is used to hold browser security preferences.
+#
+
+attribute nsBSAskForPassword 2.16.840.1.113730.3.1.457 cis
+attribute nsBSPasswordLifetime 2.16.840.1.113730.3.1.458 cis
+attribute nsBSWarnEnteringSecure 2.16.840.1.113730.3.1.459 cis
+attribute nsBSWarnLeavingSecure 2.16.840.1.113730.3.1.460 cis
+attribute nsBSWarnViewingMixed 2.16.840.1.113730.3.1.461 cis
+attribute nsBSWarnSubmitInsecure 2.16.840.1.113730.3.1.462 cis
+attribute nsBSEnableSsl2 2.16.840.1.113730.3.1.463 cis
+attribute nsBSEnableSsl3 2.16.840.1.113730.3.1.464 cis
+attribute nsBSCertmgmtDisableFunctionMsg 2.16.840.1.113730.3.1.465 cis
+attribute nsBSSsl2Rc4128 2.16.840.1.113730.3.1.466 cis
+attribute nsBSSsl2Rc2128 2.16.840.1.113730.3.1.467 cis
+attribute nsBSSsl2DesEd3192 2.16.840.1.113730.3.1.468 cis
+attribute nsBSSsl2Des64 2.16.840.1.113730.3.1.469 cis
+attribute nsBSSsl2Rc440 2.16.840.1.113730.3.1.470 cis
+attribute nsBSSsl2Rc240 2.16.840.1.113730.3.1.471 cis
+attribute nsBSSsl3RsaRc4128Md5 2.16.840.1.113730.3.1.472 cis
+attribute nsBSSsl3FipsDesEd3Sha 2.16.840.1.113730.3.1.473 cis
+attribute nsBSSsl3RsaRc4128Md5 2.16.840.1.113730.3.1.474 cis
+attribute nsBSSsl3RsaFipsDesSha 2.16.840.1.113730.3.1.475 cis
+attribute nsBSSsl3RsaDesSha 2.16.840.1.113730.3.1.476 cis
+attribute nsBSSsl3RsaRc440Md5 2.16.840.1.113730.3.1.477 cis
+attribute nsBSSsl3RsaRc240Md5 2.16.840.1.113730.3.1.478 cis
+attribute nsBSSsl3RsaNullMd5 2.16.840.1.113730.3.1.479 cis
+attribute nsBSSsl3FortezzaFortezzaSha 2.16.840.1.113730.3.1.480 cis
+attribute nsBSSsl3FortezzaRc4Sha 2.16.840.1.113730.3.1.481 cis
+
+
+objectclass nsBrowserSecurity
+ oid 2.16.840.1.113730.3.2.79
+ superior top
+ allows
+ nsBSAskForPassword,
+ nsBSPasswordLifetime,
+ nsBSWarnEnteringSecure,
+ nsBSWarnLeavingSecure,
+ nsBSWarnViewingMixed,
+ nsBSWarnSubmitInsecure,
+ nsBSEnableSsl2,
+ nsBSEnableSsl3,
+ nsBSCertmgmtDisableFunctionMsg,
+ nsBSSsl2Rc4128,
+ nsBSSsl2Rc2128,
+ nsBSSsl2DesEd3192,
+ nsBSSsl2Des64,
+ nsBSSsl2Rc440,
+ nsBSSsl2Rc240,
+ nsBSSsl3RsaRc4128Md5,
+ nsBSSsl3FipsDesEd3Sha,
+ nsBSSsl3RsaRc4128Md5,
+ nsBSSsl3RsaFipsDesSha,
+ nsBSSsl3RsaDesSha,
+ nsBSSsl3RsaRc440Md5,
+ nsBSSsl3RsaRc240Md5,
+ nsBSSsl3RsaNullMd5,
+ nsBSSsl3FortezzaFortezzaSha,
+ nsBSSsl3FortezzaRc4Sha
+
diff --git a/ldap/cm/v4confs/41/ns-mcd-config-schema.conf b/ldap/cm/v4confs/41/ns-mcd-config-schema.conf
new file mode 100644
index 00000000..7076bbc7
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-mcd-config-schema.conf
@@ -0,0 +1,55 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-config-schema.conf
+#
+# Netscape Mission Control Desktop schema
+# This schema is used to set MCD "config()" preferences.
+#
+
+attribute nsMcdUserAgent 2.16.840.1.113730.3.1.482 cis
+attribute nsMcdUseXSender 2.16.840.1.113730.3.1.483 cis
+attribute nsMcdToolbarLogoUrl 2.16.840.1.113730.3.1.484 cis
+attribute nsMcdToolbarLogoWinSmallFile 2.16.840.1.113730.3.1.485 cis
+attribute nsMcdToolbarLogoWinLargeFile 2.16.840.1.113730.3.1.486 cis
+attribute nsMcdToolbarLogoFrames 2.16.840.1.113730.3.1.487 cis
+attribute nsMcdMacAnimationFile 2.16.840.1.113730.3.1.488 cis
+attribute nsMcdXAnimationFile 2.16.840.1.113730.3.1.489 cis
+attribute nsMcdNetSearchUrl 2.16.840.1.113730.3.1.490 cis
+attribute nsMcdMoreInfoPluginUrl 2.16.840.1.113730.3.1.491 cis
+attribute nsMcdAutoAdminConfigUrl 2.16.840.1.113730.3.1.492 cis
+attribute nsMcdAutoAdminAppendEmail 2.16.840.1.113730.3.1.493 cis
+attribute nsMcdAutoAdminRefreshInterval 2.16.840.1.113730.3.1.494 cis
+attribute nsMcdUseGuideButton 2.16.840.1.113730.3.1.495 cis
+attribute nsMcdGuideButtonProperties 2.16.840.1.113730.3.1.496 cis
+attribute nsMcdGuideMenuProperties 2.16.840.1.113730.3.1.497 cis
+attribute nsMcdHelpMenuProperties 2.16.840.1.113730.3.1.498 cis
+
+
+objectclass nsMcdConfig
+ oid 2.16.840.1.113730.3.2.80
+ superior top
+ allows
+ nsMcdUserAgent,
+ nsMcdUseXSender,
+ nsMcdToolbarLogoUrl,
+ nsMcdToolbarLogoWinSmallFile,
+ nsMcdToolbarLogoWinLargeFile,
+ nsMcdToolbarLogoFrames,
+ nsMcdMacAnimationFile,
+ nsMcdXAnimationFile,
+ nsMcdNetSearchUrl,
+ nsMcdMoreInfoPluginUrl,
+ nsMcdAutoAdminConfigUrl,
+ nsMcdAutoAdminAppendEmail,
+ nsMcdAutoAdminRefreshInterval,
+ nsMcdUseGuideButton,
+ nsMcdGuideButtonProperties,
+ nsMcdGuideMenuProperties,
+ nsMcdHelpMenuProperties
+
diff --git a/ldap/cm/v4confs/41/ns-mcd-li-globopt.conf b/ldap/cm/v4confs/41/ns-mcd-li-globopt.conf
new file mode 100644
index 00000000..57a75555
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-mcd-li-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Index required by Mission Control Desktop: Location Independence
+index nsLIProfileName eq
diff --git a/ldap/cm/v4confs/41/ns-mcd-li-schema.conf b/ldap/cm/v4confs/41/ns-mcd-li-schema.conf
new file mode 100644
index 00000000..272d90e2
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-mcd-li-schema.conf
@@ -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
+#
+#
+# ns-mcd-li-schema.conf
+#
+# Netscape Mission Control Desktop Location Independence schema
+#
+
+attribute nsLIPtrURL 2.16.840.1.113730.3.1.399 ces
+attribute nsLIPrefs 2.16.840.1.113730.3.1.400 ces
+attribute nsLIProfileName 2.16.840.1.113730.3.1.401 cis
+attribute nsLIData 2.16.840.1.113730.3.1.402 bin
+attribute nsLIElementType 2.16.840.1.113730.3.1.403 cis
+attribute nsLIServerType 2.16.840.1.113730.3.1.404 cis
+attribute nsLIVersion 2.16.840.1.113730.3.1.405 int
+
+objectclass nsLIPtr
+ oid 2.16.840.1.113730.3.2.74
+ requires
+ objectclass
+ allows
+ nsliptrurl,
+ owner
+
+objectclass nsLIProfile
+ oid 2.16.840.1.113730.3.2.75
+ requires
+ objectclass,
+ nsliprofilename
+ allows
+ nsliprefs,
+ uid,
+ owner
+
+objectclass nsLIProfileElement
+ oid 2.16.840.1.113730.3.2.76
+ requires
+ objectclass,
+ nslielementtype
+ allows
+ owner,
+ nslidata,
+ nsliversion
+
+objectclass nsLIServer
+ oid 2.16.840.1.113730.3.2.77
+ requires
+ objectclass,
+ serverhostname
+ allows
+ description,
+ cn,
+ nsserverport,
+ nsliservertype,
+ serverroot
diff --git a/ldap/cm/v4confs/41/ns-mcd-mail-schema.conf b/ldap/cm/v4confs/41/ns-mcd-mail-schema.conf
new file mode 100644
index 00000000..12d42c0b
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-mcd-mail-schema.conf
@@ -0,0 +1,219 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-mail-schema.conf
+#
+# Netscape Mission Control Desktop mail client schema
+# This schema is used to hold mail client preferences.
+#
+
+attribute nsMCHTMLCompose 2.16.840.1.113730.3.1.331 cis
+attribute nsMCDefaultHTMLAction 2.16.840.1.113730.3.1.332 cis
+attribute nsMCRequestReturnReceipt 2.16.840.1.113730.3.1.333 cis
+attribute nsMCIncorporateReturnReceipt 2.16.840.1.113730.3.1.334 cis
+attribute nsMCMDNReportEnabled 2.16.840.1.113730.3.1.335 cis
+attribute nsMCMDNReportNotInToCC 2.16.840.1.113730.3.1.336 cis
+attribute nsMCMDNReportOutsideDomain 2.16.840.1.113730.3.1.337 cis
+attribute nsMCMDNReportOther 2.16.840.1.113730.3.1.338 cis
+attribute nsMCForwardMessageMode 2.16.840.1.113730.3.1.339 cis
+attribute nsMCAutoQuote 2.16.840.1.113730.3.1.340 cis
+attribute nsMCReplyOnTop 2.16.840.1.113730.3.1.341 cis
+attribute nsMCSpellCheckBeforeSend 2.16.840.1.113730.3.1.342 cis
+attribute nsMCWrapLongLines 2.16.840.1.113730.3.1.343 cis
+attribute nsMCWrapLength 2.16.840.1.113730.3.1.344 cis
+attribute nsMCStrictlyMime 2.16.840.1.113730.3.1.345 cis
+attribute nsMCAutoCompleteUseAddressBooks 2.16.840.1.113730.3.1.346 cis
+attribute nsMCAutoCompleteUseDirectory 2.16.840.1.113730.3.1.347 cis
+attribute nsMCAutoCompleteEnabledServerName 2.16.840.1.113730.3.1.348 cis
+attribute nsMCAutoCompleteShowDlgForMultipleMatches 2.16.840.1.113730.3.1.349 cis
+attribute nsMCSkipDirectoryIfLocalMatchFound 2.16.840.1.113730.3.1.350 cis
+attribute nsMCAddrBookLastnameFirst 2.16.840.1.113730.3.1.351 cis
+attribute nsMCLimitMessageSize 2.16.840.1.113730.3.1.352 cis
+attribute nsMCMaxMessageSize 2.16.840.1.113730.3.1.353 cis
+attribute nsMCPromptPurgeThreshold 2.16.840.1.113730.3.1.354 cis
+attribute nsMCPurgeThreshold 2.16.840.1.113730.3.1.355 cis
+attribute nsMCNewsKeepMethod 2.16.840.1.113730.3.1.356 cis
+attribute nsMCNewsKeepDays 2.16.840.1.113730.3.1.357 cis
+attribute nsMCNewsKeepCount 2.16.840.1.113730.3.1.358 cis
+attribute nsMCNewsKeepOnlyUnread 2.16.840.1.113730.3.1.359 cis
+attribute nsMCNewsRemoveBodiesByAge 2.16.840.1.113730.3.1.360 cis
+attribute nsMCNewsRemoveBodiesDays 2.16.840.1.113730.3.1.361 cis
+attribute nsMCSmtpServer 2.16.840.1.113730.3.1.362 cis
+attribute nsMCSmtpUserName 2.16.840.1.113730.3.1.363 cis
+attribute nsMCSmtpUseSSL 2.16.840.1.113730.3.1.364 cis
+attribute nsMCImapServer 2.16.840.1.113730.3.1.365 cis
+attribute nsMCImapServerProperties 2.16.840.1.113730.3.1.366 cis
+attribute nsMCPopServer 2.16.840.1.113730.3.1.367 cis
+attribute nsMCPopServerProperties 2.16.840.1.113730.3.1.368 cis
+attribute nsMCLdapServer 2.16.840.1.113730.3.1.369 cis
+attribute nsMCLdapServerProperties 2.16.840.1.113730.3.1.370 cis
+attribute nsMCQuotedStyle 2.16.840.1.113730.3.1.371 cis
+attribute nsMCQuotedSize 2.16.840.1.113730.3.1.372 cis
+attribute nsMCCitationColor 2.16.840.1.113730.3.1.373 cis
+attribute nsMCFixedWidthMessages 2.16.840.1.113730.3.1.374 cis
+attribute nsMCPlaySound 2.16.840.1.113730.3.1.375 cis
+attribute nsMCRememberSelectedMessage 2.16.840.1.113730.3.1.376 cis
+attribute nsMCReuseMessageWindow 2.16.840.1.113730.3.1.377 cis
+attribute nsMCConfirmMoveFoldersToTrash 2.16.840.1.113730.3.1.378 cis
+attribute nsMCUseMapiServer 2.16.840.1.113730.3.1.379 cis
+attribute nsMCNewsTimeout 2.16.840.1.113730.3.1.380 cis
+attribute nsMCNavCrossesFolders 2.16.840.1.113730.3.1.381 cis
+attribute nsMCSearchServer 2.16.840.1.113730.3.1.382 cis
+attribute nsMCSearchSubFolders 2.16.840.1.113730.3.1.383 cis
+attribute nsMCEncryptOutgoingMail 2.16.840.1.113730.3.1.384 cis
+attribute nsMCCryptoSignOutgoingMail 2.16.840.1.113730.3.1.385 cis
+attribute nsMCCryptoSignOutgoingNews 2.16.840.1.113730.3.1.386 cis
+attribute nsMCWarnForwardEncrypted 2.16.840.1.113730.3.1.387 cis
+attribute nsMCWarnReplyUnencrypted 2.16.840.1.113730.3.1.388 cis
+attribute nsMCAllowAtSignInUserName 2.16.840.1.113730.3.1.389 cis
+attribute nsMCReceiptRequestHeaderType 2.16.840.1.113730.3.1.390 cis
+attribute nsMCPop3GetsNewMail 2.16.840.1.113730.3.1.391 cis
+attribute nsMCImapAutoSubscribeOnOpen 2.16.840.1.113730.3.1.392 cis
+attribute nsMCImapMimePartsOnDemand 2.16.840.1.113730.3.1.393 cis
+attribute nsMCImapMimePartsOnDemandThreshold 2.16.840.1.113730.3.1.394 cis
+attribute nsMCUseAltMail 2.16.840.1.113730.3.1.395 cis
+attribute nsMCAltMailDll 2.16.840.1.113730.3.1.396 cis
+attribute nsMCUseAltMailForNews 2.16.840.1.113730.3.1.397 cis
+attribute nsPrefMap 2.16.840.1.113730.3.1.398 cis
+attribute nsMCAuthLogin 2.16.840.1.113730.3.1.499 cis
+attribute nsMNCNavCrossesFolders 2.16.840.1.113730.3.1.500 cis
+attribute nsMNCMessageInThreadWindow 2.16.840.1.113730.3.1.501 cis
+attribute nsMCAllowAtSignInUserName 2.16.840.1.113730.3.1.502 cis
+attribute nsMCImapOnlineDraftSent 2.16.840.1.113730.3.1.503 cis
+attribute nsMCCustomHeaders 2.16.840.1.113730.3.1.504 cis
+attribute nsMCHtmlDomains 2.16.840.1.113730.3.1.505 cis
+attribute nsMNCForceAsciiSearch 2.16.840.1.113730.3.1.506 cis
+attribute nsMCAddrBookLdapDisabled 2.16.840.1.113730.3.1.507 cis
+attribute nsMNCReuseThreadWindow 2.16.840.1.113730.3.1.508 cis
+attribute nsMCShowHeaders 2.16.840.1.113730.3.1.509 cis
+attribute nsMCIdentityDefaultdomain 2.16.840.1.113730.3.1.510 cis
+
+
+
+
+objectclass nsMailClient
+ oid 2.16.840.1.113730.3.2.72
+ superior top
+ allows
+ nsMCHTMLCompose,
+ nsMCDefaultHTMLAction,
+ nsMCRequestReturnReceipt,
+ nsMCIncorporateReturnReceipt,
+ nsMCMDNReportEnabled,
+ nsMCMDNReportNotInToCC,
+ nsMCMDNReportOutsideDomain,
+ nsMCMDNReportOther,
+ nsMCForwardMessageMode,
+ nsMCAutoQuote,
+ nsMCReplyOnTop,
+ nsMCSpellCheckBeforeSend,
+ nsMCWrapLongLines,
+ nsMCWrapLength,
+ nsMCStrictlyMime,
+ nsMCAutoCompleteUseAddressBooks,
+ nsMCAutoCompleteUseDirectory,
+ nsMCAutoCompleteEnabledServerName,
+ nsMCAutoCompleteShowDlgForMultipleMatches,
+ nsMCSkipDirectoryIfLocalMatchFound,
+ nsMCAddrBookLastnameFirst,
+ nsMCLimitMessageSize,
+ nsMCMaxMessageSize,
+ nsMCPromptPurgeThreshold,
+ nsMCPurgeThreshold,
+ nsMCNewsKeepMethod,
+ nsMCNewsKeepDays,
+ nsMCNewsKeepCount,
+ nsMCNewsKeepOnlyUnread,
+ nsMCNewsRemoveBodiesByAge,
+ nsMCNewsRemoveBodiesDays,
+ nsMCSmtpServer,
+ nsMCSmtpUserName,
+ nsMCSmtpUseSSL,
+ nsMCImapServer,
+ nsMCImapServerProperties,
+ nsMCPopServer,
+ nsMCPopServerProperties,
+ nsMCLdapServer,
+ nsMCLdapServerProperties,
+ nsMCQuotedStyle,
+ nsMCQuotedSize,
+ nsMCCitationColor,
+ nsMCFixedWidthMessages,
+ nsMCPlaySound,
+ nsMCRememberSelectedMessage,
+ nsMCReuseMessageWindow,
+ nsMCConfirmMoveFoldersToTrash,
+ nsMCUseMapiServer,
+ nsMCNewsTimeout,
+ nsMCNavCrossesFolders,
+ nsMCSearchServer,
+ nsMCSearchSubFolders,
+ nsMCEncryptOutgoingMail,
+ nsMCCryptoSignOutgoingMail,
+ nsMCCryptoSignOutgoingNews,
+ nsMCWarnForwardEncrypted,
+ nsMCWarnReplyUnencrypted,
+ nsMCAllowAtSignInUserName,
+ nsMCReceiptRequestHeaderType,
+ nsMCPop3GetsNewMail,
+ nsMCImapAutoSubscribeOnOpen,
+ nsMCImapMimePartsOnDemand,
+ nsMCImapMimePartsOnDemandThreshold,
+ nsMCUseAltMail,
+ nsMCAltMailDll,
+ nsMCUseAltMailForNews,
+ nsMCAuthLogin,
+ nsMNCNavCrossesFolders,
+ nsMNCMessageInThreadWindow,
+ nsMCAllowAtSignInUserName,
+ nsMCImapOnlineDraftSent,
+ nsMCCustomHeaders,
+ nsMCHtmlDomains,
+ nsMNCForceAsciiSearch,
+ nsMCAddrBookLdapDisabled,
+ nsMNCReuseThreadWindow,
+ nsMCShowHeaders,
+ nsMCIdentityDefaultdomain
+
+
+#
+# Netscape Mission Control Desktop Messenger security schema
+# This schema is used to hold Messenger security preferences.
+#
+
+attribute nsMSEncryptOutgoingMail 2.16.840.1.113730.3.1.511 cis
+attribute nsMSSignOutgoingMail 2.16.840.1.113730.3.1.512 cis
+attribute nsMSSignOutgoingNews 2.16.840.1.113730.3.1.513 cis
+attribute nsMSSmimeDesEde3 2.16.840.1.113730.3.1.514 cis
+attribute nsMSSmimeRc2128 2.16.840.1.113730.3.1.515 cis
+attribute nsMSSmimeDes 2.16.840.1.113730.3.1.516 cis
+attribute nsMSSmimeRc264 2.16.840.1.113730.3.1.517 cis
+attribute nsMSSmimeRc240 2.16.840.1.113730.3.1.518 cis
+attribute nsMSSmimeFortezza 2.16.840.1.113730.3.1.519 cis
+
+objectclass nsMailSecurity
+ oid 2.16.840.1.113730.3.2.81
+ superior top
+ allows
+ nsMSEncryptOutgoingMail,
+ nsMSSignOutgoingMail,
+ nsMSSignOutgoingNews,
+ nsMSSmimeDesEde3,
+ nsMSSmimeRc2128,
+ nsMSSmimeDes,
+ nsMSSmimeRc264,
+ nsMSSmimeRc240,
+ nsMSSmimeFortezza
+
+objectclass netscapePreferenceMap
+ oid 2.16.840.1.113730.3.2.73
+ superior top
+ allows
+ nsPrefMap,
+ uid
+
diff --git a/ldap/cm/v4confs/41/ns-media-globopt.conf b/ldap/cm/v4confs/41/ns-media-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-media-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/41/ns-media-schema.conf b/ldap/cm/v4confs/41/ns-media-schema.conf
new file mode 100644
index 00000000..d4afa271
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-media-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeMediaServer
+ oid 2.16.840.1.113730.3.2.25
+ requires
+ objectclass
+
diff --git a/ldap/cm/v4confs/41/ns-mlm-schema.conf b/ldap/cm/v4confs/41/ns-mlm-schema.conf
new file mode 100644
index 00000000..e1c4ef78
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-mlm-schema.conf
@@ -0,0 +1,102 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# LDAP object classes used by MLM
+#
+
+attribute mgmemMemberOfGroup cis
+attribute mgmemRefDN ces single
+attribute mgmemMailUserPassword bin single
+attribute mgmemGroupMemberParam ces
+attribute mgmemGroupServerParam ces
+
+attribute mgmanJoinability ces
+attribute mgmanJoinLocalType cis single
+attribute mgmanMemberVisibility ces
+attribute mgmanIntroText ces single
+attribute mgmanGroupStat ces
+attribute mgmanHidden cis single
+attribute mgmanGroupKey cis single
+attribute mgmanAllowSubscribe cis
+attribute mgmanDenySubscribe cis
+
+attribute mgmanGConfNewGroupParent dn single
+attribute mgmanGConfRemoteUserParent dn single
+attribute mgmanGConfSearchBase dn single
+attribute mgmanGConfGroupCreationUser dn
+attribute mgmanGConfSearchGroupUser dn
+attribute mgmanGConfAdmin dn
+attribute mgmanGConfGroupTemplate dn single
+attribute mgmanGConfDefaultInheritance cis
+attribute mgmanGConfKey cis
+attribute mgmanGConfSearchAttribute cis
+attribute mgmanGConfSearchRelationship cis
+attribute mgmanGConfSearchTreeNode cis
+attribute mgmanGConfSortAttributeDirMembers cis
+attribute mgmanGConfSortAttributeGroupMembers cis
+attribute mgmanGConfGroupDomains dn
+
+
+objectClass mailGroupMember
+ requires
+ objectClass,
+ mail
+ allows
+ mgmemMemberOfGroup,
+ mgmemRefDN,
+ preferredLanguage,
+ userCertificate,
+ mgmemMailUserPassword,
+ mgmemGroupMemberParam,
+ mgmemGroupServerParam,
+ c,
+ cn,
+ sn,
+ givenName
+
+
+objectClass mailGroupManagement
+ requires
+ objectClass
+ allows
+ description,
+ labeledURL,
+ mgmanAllowSubscribe,
+ mgmanDenySubscribe,
+ mgmanGroupKey,
+ mgmanGroupStat,
+ mgmanHidden,
+ mgmanIntroText,
+ mgmanJoinability,
+ mgmanJoinLocalType,
+ mgmanMemberVisibility,
+ multilineDescription,
+ userCertificate,
+ userPassword
+
+objectClass mailGroupManagement_GlobalConfig
+ requires
+ objectClass
+ allows
+ cn,
+ mgmanGConfAdmin,
+ mgmanGConfDefaultInheritance,
+ mgmanGConfGroupCreationUser,
+ mgmanGConfGroupDomains,
+ mgmanGConfGroupTemplate,
+ mgmanGConfKey,
+ mgmanGConfNewGroupParent,
+ mgmanGConfRemoteUserParent,
+ mgmanGConfSearchAttribute,
+ mgmanGConfSearchBase,
+ mgmanGConfSearchGroupUser,
+ mgmanGConfSearchRelationship,
+ mgmanGConfSearchTreeNode,
+ mgmanGConfSortAttributeDirMembers,
+ mgmanGConfSortAttributeGroupMembers
+
diff --git a/ldap/cm/v4confs/41/ns-msg-schema.conf b/ldap/cm/v4confs/41/ns-msg-schema.conf
new file mode 100644
index 00000000..3800edbd
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-msg-schema.conf
@@ -0,0 +1,711 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#used by Netscape Messaging Server 4.0
+#
+#
+attribute nsmsgaccounturl cis
+attribute nsmsgadddeliveredto cis
+attribute nsmsgaddheaders cis
+attribute nsmsgadmins cis
+attribute nsmsgalias cis
+attribute nsmsgallowadminproxy cis
+attribute nsmsgallowanonymouslogin cis
+attribute nsmsgallowbarelf cis
+attribute nsmsgallowbdat cis
+attribute nsmsgallowehlo cis
+attribute nsmsgallowetrn cis
+attribute nsmsgallowexpn cis
+attribute nsmsgallowhelp cis
+attribute nsmsgallowonex cis
+attribute nsmsgallowsize cis
+attribute nsmsgallowverb cis
+attribute nsmsgallowvrfy cis
+attribute nsmsgaltqueues cis
+attribute nsmsgalwaysqueue cis
+attribute nsmsgauthcachesize cis
+attribute nsmsgauthcachettl cis
+attribute nsmsgauthmaildomain cis
+attribute nsmsgbanner cis
+attribute nsmsgbinarypath cis
+attribute nsmsgbuffersize cis
+attribute nsmsgcheckdeferredqueue cis
+attribute nsmsgcleanupage cis
+attribute nsmsgclearcontrolinterval cis
+attribute nsmsgclearcontrolsafetime cis
+attribute nsmsgcollectiondeltatime cis
+attribute nsmsgconfigversion cis
+attribute nsmsgcontact cis
+attribute nsmsgcounterdeltatime cis
+attribute nsmsgdbcachesize cis
+attribute nsmsgdbtmpdir cis
+attribute nsmsgdefaultacl cis
+attribute nsmsgdefaultdomain cis
+attribute nsmsgdefaultecho cis
+attribute nsmsgdefaultgid cis
+attribute nsmsgdefaultmailboxquota cis
+attribute nsmsgdefaultoverquota cis
+attribute nsmsgdefaultpartition cis
+attribute nsmsgdefaultreply cis
+attribute nsmsgdefaultuid cis
+attribute nsmsgdefaultvacation cis
+attribute nsmsgdeferredperiod cis
+attribute nsmsgdeleteheaders cis
+attribute nsmsgdescription cis
+attribute nsmsgdiskflushinterval cis
+attribute nsmsgdnsresolveclient cis
+attribute nsmsgdocanonicalize cis
+attribute nsmsgdoclientdnslookup cis
+attribute nsmsgdodsn cis
+attribute nsmsgdoetrn cis
+attribute nsmsgdomainallowed cis
+attribute nsmsgdomainlangtable cis
+attribute nsmsgdomainname cis
+attribute nsmsgdomainnotallowed cis
+attribute nsmsgdomainsecurity cis
+attribute nsmsgdorewritefromusingauth cis
+attribute nsmsgdorewritesenderusingauth cis
+attribute nsmsgenable cis
+attribute nsmsgenablesslport cis
+attribute nsmsgenveloperewritemethod cis
+attribute nsmsgexclusive cis
+attribute nsmsgexpirestart cis
+attribute nsmsgexpirytime cis
+attribute nsmsgexternalmxserverip cis
+attribute nsmsgfallbacksearchmethod cis
+attribute nsmsgfilemode cis
+attribute nsmsgfilterurl cis
+attribute nsmsgflushinterval cis
+attribute nsmsgfolderpattern cis
+attribute nsmsgfoldersizebytes cis
+attribute nsmsgfolderurl cis
+attribute nsmsgforeignpercentaddr cis
+attribute nsmsgformsigkey cis
+attribute nsmsghidehostname cis
+attribute nsmsghopcountexceedactions cis
+attribute nsmsghostoncommandline cis
+attribute nsmsghostrewrites cis
+attribute nsmsgidletimeout cis
+attribute nsmsgipsecurity cis
+attribute nsmsginstalledlanguages cis
+attribute nsmsginternalmxserverip cis
+attribute nsmsgldapmemcache cis
+attribute nsmsgldapmemcachesize cis
+attribute nsmsgldapmemcachettl cis
+attribute nsmsgldappoolsize cis
+attribute nsmsgldaputilconfig cis
+attribute nsmsglistenaddr cis
+attribute nsmsglistenq cis
+attribute nsmsglisturl cis
+attribute nsmsglocaldefaultmaxruncount cis
+attribute nsmsglocaldefaultminruncount cis
+attribute nsmsglocalmaildomains cis
+attribute nsmsglocation cis
+attribute nsmsglog cis
+attribute nsmsglogdir cis
+attribute nsmsgloglevel cis
+attribute nsmsglogtype cis
+attribute nsmsgmaildeliveryprogram cis
+attribute nsmsgmasterhost cis
+attribute nsmsgmasterport cis
+attribute nsmsgmaxbadcommands cis
+attribute nsmsgmaxbranches cis
+attribute nsmsgmaxcontrolrecipients cis
+attribute nsmsgmaxcputime cis
+attribute nsmsgmaxerrorobjectsize cis
+attribute nsmsgmaxheaderlines cis
+attribute nsmsgmaxlogfiles cis
+attribute nsmsgmaxlogfilesize cis
+attribute nsmsgmaxlogsize cis
+attribute nsmsgmaxmessagesize cis
+attribute nsmsgmaxmtahops cis
+attribute nsmsgmaxpostsize cis
+attribute nsmsgmaxqueuetime cis
+attribute nsmsgmaxruncount cis
+attribute nsmsgmaxruncountdeferred cis
+attribute nsmsgmaxscriptsize cis
+attribute nsmsgmaxsessions cis
+attribute nsmsgmaxstateobjectsize cis
+attribute nsmsgmaxthreads cis
+attribute nsmsgmessagecount cis
+attribute nsmsgmessagedays cis
+attribute nsmsgmessagehostname cis
+attribute nsmsgmessagesize cis
+attribute nsmsgmessagesizedays cis
+attribute nsmsgminfreediskspace cis
+attribute nsmsgminruncount cis
+attribute nsmsgmsgalarmdescription cis
+attribute nsmsgmsgalarmnoticehost cis
+attribute nsmsgmsgalarmnoticeport cis
+attribute nsmsgmsgalarmnoticercpt cis
+attribute nsmsgmsgalarmnoticesender cis
+attribute nsmsgmsgalarmnoticetemplate cis
+attribute nsmsgmsgalarmstatinterval cis
+attribute nsmsgmsgalarmthreshold cis
+attribute nsmsgmsgalarmthresholddirection cis
+attribute nsmsgmsgalarmwarninginterval cis
+attribute nsmsgmtaid cis
+attribute nsmsgmtaname cis
+attribute nsmsgneedsender cis
+attribute nsmsgnegativehostattr cis
+attribute nsmsgnestedgroups cis
+attribute nsmsgnetworkdefaultmaxruncount cis
+attribute nsmsgnetworkdefaultminruncount cis
+attribute nsmsgnewsprefix cis
+attribute nsmsgnewsspool cis
+attribute nsmsgnewuserforms cis
+attribute nsmsgntaccount cis
+attribute nsmsgntpassword cis
+attribute nsmsgntrunoptn cis
+attribute nsmsgnumdays cis
+attribute nsmsgnumenvelopequeuefiles cis
+attribute nsmsgnummessages cis
+attribute nsmsgnumprocesses cis
+attribute nsmsgorganization cis
+attribute nsmsgpartition cis
+attribute nsmsgpath cis
+attribute nsmsgplaintextloginpause cis
+attribute nsmsgplaintextmincipher cis
+attribute nsmsgpopminpoll cis
+attribute nsmsgport cis
+attribute nsmsgpositivehostattr cis
+attribute nsmsgprotocolubeconfig cis
+attribute nsmsgproxydomainallowed cis
+attribute nsmsgquotaexceededactions cis
+attribute nsmsgquotaexceededmsg cis
+attribute nsmsgquotaexceededmsginterval cis
+attribute nsmsgquotagraceperiod cis
+attribute nsmsgquotawarn cis
+attribute nsmsgreadtimeout cis
+attribute nsmsgrenotifyinterval cis
+attribute nsmsgrequirecrlf cis
+attribute nsmsgreserved0 cis
+attribute nsmsgreserved1 cis
+attribute nsmsgreserved2 cis
+attribute nsmsgreserved3 cis
+attribute nsmsgreserved4 cis
+attribute nsmsgreserved5 cis
+attribute nsmsgreserved6 cis
+attribute nsmsgreserved7 cis
+attribute nsmsgreserved8 cis
+attribute nsmsgreserved9 cis
+attribute nsmsgresourcetimeout cis
+attribute nsmsgrewritetocc cis
+attribute nsmsgrolloverdelta cis
+attribute nsmsgrolloversize cis
+attribute nsmsgrollovertime cis
+attribute nsmsgroutingattribute cis
+attribute nsmsgroutstripimapfolders cis
+attribute nsmsgsessiontimeout cis
+attribute nsmsgshellpath cis
+attribute nsmsgsitelanguage cis
+attribute nsmsgsmtphost cis
+attribute nsmsgsmtpport cis
+attribute nsmsgsmtprewritestyle cis
+attribute nsmsgsourceurl cis
+attribute nsmsgspooldir cis
+attribute nsmsgsslcachesize cis
+attribute nsmsgsslpasswdfile cis
+attribute nsmsgsslport cis
+attribute nmmsgsslsourceurl cis
+attribute nsmsgsslusessl cis
+attribute nsmsgsslusesslrelay cis
+attribute nsmsgstripcr cis
+attribute nsmsgsystemmaildir cis
+attribute nsmsgtimeoutcommand cis
+attribute nsmsgtimeoutdata cis
+attribute nsmsgtimeoutdatadot cis
+attribute nsmsgtimeoutdatasend cis
+attribute nsmsgtimeoutgreet cis
+attribute nsmsgtimeouthelo cis
+attribute nsmsgtimeoutmail cis
+attribute nsmsgtimeoutquit cis
+attribute nsmsgtimeoutrcpt cis
+attribute nsmsgtimeoutrset cis
+attribute nsmsgumask cis
+attribute nsmsgunknownacctsactions cis
+attribute nsmsgusemx cis
+attribute nsmsgverifyrcpts cis
+attribute nsmsgversion cis
+
+objectclass netscapeMessagingServer
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description
+
+objectclass nsmsgcfgcontainer
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfggen
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgaccounturl,
+ nsmsgconfigversion,
+ nsmsgfilterurl,
+ nsmsgfolderurl,
+ nsmsginstalledlanguages,
+ nsmsglisturl,
+ nsmsgnewuserforms,
+ nsmsgsitelanguage
+
+objectclass nsmsgcfgsnmp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgcontact,
+ nsmsgcollectiondeltatime,
+ nsmsgdescription,
+ nsmsgenable,
+ nsmsglocation,
+ nsmsgmtaid,
+ nsmsgmtaname,
+ nsmsgmasterhost,
+ nsmsgmasterport,
+ nsmsgorganization,
+ nsmsgversion
+
+objectclass nsmsgcfgstore
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgadmins,
+ nsmsgcleanupage,
+ nsmsgdbcachesize,
+ nsmsgdbtmpdir,
+ nsmsgdefaultacl,
+ nsmsgdefaultmailboxquota,
+ nsmsgdefaultpartition,
+ nsmsgdiskflushinterval,
+ nsmsgexpirestart,
+ nsmsgquotaexceededmsg,
+ nsmsgquotaexceededmsginterval,
+ nsmsgquotagraceperiod,
+ nsmsgquotawarn,
+ nsmsgumask
+
+objectclass nsmsgcfgexpirerule
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgfolderpattern,
+ nsmsgexclusive,
+ nsmsgfoldersizebytes,
+ nsmsgmessagecount,
+ nsmsgmessagedays,
+ nsmsgmessagesize,
+ nsmsgmessagesizedays
+
+objectclass nsmsgcfgpartition
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgpath
+
+objectclass nsmsgcfguser
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgpublic
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgalias
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgalias
+
+objectclass nsmsgcfglog
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgbuffersize,
+ nsmsgexpirytime,
+ nsmsgflushinterval,
+ nsmsglogdir,
+ nsmsgloglevel,
+ nsmsglogtype,
+ nsmsgmaxlogfiles,
+ nsmsgmaxlogfilesize,
+ nsmsgmaxlogsize,
+ nsmsgminfreediskspace,
+ nsmsgrollovertime
+
+objectclass nsmsgcfgservice
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgauthcachesize,
+ nsmsgauthcachettl,
+ nsmsgdnsresolveclient,
+ nsmsgldapmemcache,
+ nsmsgldapmemcachesize,
+ nsmsgldapmemcachettl,
+ nsmsglistenaddr,
+ nsmsgplaintextloginpause,
+ nsmsgreadtimeout,
+ nsmsgsslpasswdfile
+
+objectclass nsmsgcfgpop
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowanonymouslogin,
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgidletimeout,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgpopminpoll,
+ nsmsgport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgimap
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowanonymouslogin,
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgidletimeout,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgsslcachesize,
+ nsmsgsslport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfghttp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowadminproxy,
+ nsmsgallowanonymouslogin,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgdomainsecurity,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgidletimeout,
+ nsmsgipsecurity,
+ nsmsgmaxmessagesize,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgmaxpostsize,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgproxydomainallowed,
+ nsmsgresourcetimeout,
+ nsmsgsessiontimeout,
+ nsmsgsmtphost,
+ nsmsgsmtpport,
+ nsmsgsourceurl,
+ nsmsgspooldir,
+ nsmsgsslcachesize,
+ nsmsgsslport,
+ nsmsgsourceurl,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgnntp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgnewsprefix,
+ nsmsgnewsspool,
+ nsmsgpartition,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgsslport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgmta
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgaltqueues,
+ nsmsgauthmaildomain,
+ nsmsgbanner,
+ nsmsgclearcontrolinterval,
+ nsmsgclearcontrolsafetime,
+ nsmsgcounterdeltatime,
+ nsmsgdefaultdomain,
+ nsmsgdeferredperiod,
+ nsmsgdocanonicalize,
+ nsmsgdoclientdnslookup,
+ nsmsgdodsn,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgdomainname,
+ nsmsgdomainlangtable,
+ nsmsgenable,
+ nsmsgforeignpercentaddr,
+ nsmsgldappoolsize,
+ nsmsgldaputilconfig,
+ nsmsglocaldefaultmaxruncount,
+ nsmsglocaldefaultminruncount,
+ nsmsgmaxheaderlines,
+ nsmsgmaxqueuetime,
+ nsmsgmessagehostname,
+ nsmsgnetworkdefaultmaxruncount,
+ nsmsgnetworkdefaultminruncount,
+ nsmsgnumenvelopequeuefiles,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgprotocolubeconfig,
+ nsmsgreserved0,
+ nsmsgreserved1,
+ nsmsgreserved2,
+ nsmsgreserved3,
+ nsmsgreserved4,
+ nsmsgreserved5,
+ nsmsgreserved6,
+ nsmsgreserved7,
+ nsmsgreserved8,
+ nsmsgreserved9,
+ nsmsgrolloverdelta,
+ nsmsgrolloversize,
+ nsmsgroutstripimapfolders,
+ nsmsgsslusessl,
+ nsmsgsslusesslrelay
+
+objectclass nsmsgcfgmtalog
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsglog,
+ nsmsgminruncount,
+ nsmsgmaxruncount,
+ nsmsgmaxruncountdeferred
+
+objectclass nsmsgcfgmtaautoreplyhandler
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultecho,
+ nsmsgdefaultreply,
+ nsmsgdefaultvacation
+
+objectclass nsmsgcfgmtaerrorhandler
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgformsigkey,
+ nsmsghopcountexceedactions,
+ nsmsgquotaexceededactions,
+ nsmsgrenotifyinterval,
+ nsmsgunknownacctsactions
+
+objectclass nsmsgcfgmtamboxdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgmtaprogdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultgid,
+ nsmsgdefaultuid,
+ nsmsgshellpath,
+ nsmsgntrunoptn,
+ nsmsgntaccount,
+ nsmsgntpassword
+
+objectclass nsmsgcfgmtaaccept
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowbdat,
+ nsmsgallowehlo,
+ nsmsgallowetrn,
+ nsmsgallowexpn,
+ nsmsgallowhelp,
+ nsmsgallowonex,
+ nsmsgallowsize,
+ nsmsgallowverb,
+ nsmsgallowvrfy,
+ nsmsghidehostname,
+ nsmsgmaxbadcommands,
+ nsmsgmaxmessagesize,
+ nsmsgminfreediskspace,
+ nsmsgnegativehostattr,
+ nsmsgpositivehostattr,
+ nsmsgrequirecrlf,
+ nsmsgtimeoutcommand,
+ nsmsgtimeoutdata,
+ nsmsgverifyrcpts
+
+objectclass nsmsgcfgmtasmtpdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowbarelf,
+ nsmsgalwaysqueue,
+ nsmsgcheckdeferredqueue,
+ nsmsgdoetrn,
+ nsmsgexternalmxserverip,
+ nsmsginternalmxserverip,
+ nsmsgtimeoutdata,
+ nsmsgtimeoutdatadot,
+ nsmsgtimeoutdatasend,
+ nsmsgtimeoutgreet,
+ nsmsgtimeouthelo,
+ nsmsgtimeoutmail,
+ nsmsgtimeoutquit,
+ nsmsgtimeoutrcpt,
+ nsmsgtimeoutrset,
+ nsmsgusemx
+
+objectclass nsmsgcfgmtarouter
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgadddeliveredto,
+ nsmsgaddheaders,
+ nsmsgdeleteheaders,
+ nsmsgdorewritefromusingauth,
+ nsmsgdorewritesenderusingauth,
+ nsmsgenveloperewritemethod,
+ nsmsgfallbacksearchmethod,
+ nsmsghostrewrites,
+ nsmsglocalmaildomains,
+ nsmsgmaxcontrolrecipients,
+ nsmsgmaxmtahops,
+ nsmsgnestedgroups,
+ nsmsgrewritetocc,
+ nsmsgroutingattribute,
+ nsmsgsmtprewritestyle
+
+objectclass nsmsgcfgmtaunixdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultgid,
+ nsmsgdefaultuid,
+ nsmsgfilemode,
+ nsmsgmaildeliveryprogram,
+ nsmsgneedsender,
+ nsmsgstripcr,
+ nsmsgsystemmaildir
+
+objectclass nsmsgcfgreport
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgalarmcontainer
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgmsgalarmnoticehost,
+ nsmsgmsgalarmnoticeport,
+ nsmsgmsgalarmnoticercpt,
+ nsmsgmsgalarmnoticesender,
+ nsmsgmsgalarmnoticetemplate
+
+objectclass nsmsgcfgalarm
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgmsgalarmdescription,
+ nsmsgmsgalarmstatinterval,
+ nsmsgmsgalarmthreshold,
+ nsmsgmsgalarmthresholddirection,
+ nsmsgmsgalarmwarninginterval
+
+objectclass nsmsgcfgscript
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgenable,
+ nsmsgbinarypath,
+ nsmsgloglevel,
+ nsmsgmaxscriptsize,
+ nsmsgmaxbranches,
+ nsmsgmaxcputime,
+ nsmsgmaxerrorobjectsize,
+ nsmsgmaxstateobjectsize
diff --git a/ldap/cm/v4confs/41/ns-netshare-schema.conf b/ldap/cm/v4confs/41/ns-netshare-schema.conf
new file mode 100644
index 00000000..b1201ef0
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-netshare-schema.conf
@@ -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
+#
+# Used by Netscape Enterprise Server
+attribute netshareHomeURL ces single
+attribute netshareServerType cis single
+attribute netshareHomeTheme cis single
+attribute netsharePrivate cis single
+attribute netshareMemberOf dn
+attribute netshareUIConfig bin single
+
+# added to either users or groups/projects to enable
+# as netshare user accounts or netshare projects
+objectclass netshareAccount
+ requires
+ objectclass,
+ netshareHomeURL
+ allows
+ netshareServerType,
+ netshareHomeTheme,
+ netsharePrivate,
+ netshareMemberOf,
+ netshareUIConfig
+
+
+attribute netsharePMNewProjParent dn single
+attribute netsharePMSearchBase dn single
+attribute netsharePMProjCreationUser dn single
+attribute netsharePMAdmin dn
+
+# this is for the netshare project management utility/CGI
+# that is created under the SIE; this parallels the messaging
+# MLM schema somewhat to enable end-user maintenance/creation
+# of netshare projects
+objectclass netshareProjectManagementGlobalConfig
+ requires
+ objectclass
+ allows
+ netsharePMNewProjParent,
+ netsharePMSearchBase,
+ netsharePMProjCreationUser,
+ netsharePMAdmin,
+ cn
diff --git a/ldap/cm/v4confs/41/ns-news-globopt.conf b/ldap/cm/v4confs/41/ns-news-globopt.conf
new file mode 100644
index 00000000..b35e2a83
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-news-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape News Server
+#index uniquemember,member eq
+
diff --git a/ldap/cm/v4confs/41/ns-news-schema.conf b/ldap/cm/v4confs/41/ns-news-schema.conf
new file mode 100644
index 00000000..777f339a
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-news-schema.conf
@@ -0,0 +1,35 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsnewsACL 2.16.840.1.113730.3.1.191 cis
+attribute nsaclrole 2.16.840.1.113730.3.1.192 cis
+attribute nsprettyname 2.16.840.1.113730.3.1.193 cis
+attribute nsflags 2.16.840.1.113730.3.1.194 cis
+attribute nscreator 2.16.840.1.113730.3.1.195 cis
+attribute ngcomponent 2.16.840.1.113730.3.1.196 dn
+
+objectclass nginfo
+ oid 2.16.840.1.113730.3.2.26
+ requires
+ objectClass,
+ ngcomponent
+ allows
+ nsnewsACL,
+ subtreeACI,
+ description,
+ nsaclrole,
+ nsprettyname,
+ nsflags,
+ nscreator
+
+objectClass netscapeNewsServer
+ oid 2.16.840.1.113730.3.2.27
+ requires
+ objectClass
+
diff --git a/ldap/cm/v4confs/41/ns-proxy-globopt.conf b/ldap/cm/v4confs/41/ns-proxy-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-proxy-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/41/ns-proxy-schema.conf b/ldap/cm/v4confs/41/ns-proxy-schema.conf
new file mode 100644
index 00000000..3d26bacb
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-proxy-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeProxyServer
+ oid 2.16.840.1.113730.3.2.28
+ requires
+ objectclass
+
diff --git a/ldap/cm/v4confs/41/ns-value-schema.conf b/ldap/cm/v4confs/41/ns-value-schema.conf
new file mode 100644
index 00000000..c4b9d3c9
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-value-schema.conf
@@ -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
+#
+# Schema for defining schemaless config for LDAP
+#
+
+attribute nsValueCIS 2.16.840.1.113730.3.1.243 cis
+attribute nsValueCES 2.16.840.1.113730.3.1.244 ces
+attribute nsValueTel 2.16.840.1.113730.3.1.245 tel
+attribute nsValueInt 2.16.840.1.113730.3.1.246 int
+attribute nsValueBin 2.16.840.1.113730.3.1.247 bin
+attribute nsValueDN 2.16.840.1.113730.3.1.248 dn
+attribute nsValueType 2.16.840.1.113730.3.1.249 cis
+attribute nsValueDefault 2.16.840.1.113730.3.1.250 cis
+attribute nsValueFlags 2.16.840.1.113730.3.1.251 cis
+attribute nsValueDescription 2.16.840.1.113730.3.1.252 cis
+attribute nsValueSyntax 2.16.840.1.113730.3.1.253 cis
+attribute nsValueHelpURL 2.16.840.1.113730.3.1.254 ces
+
+objectClass nsValueItem
+ oid 2.16.840.1.113730.3.2.45
+ requires
+ objectClass,
+ cn
+ allows
+ nsValueCIS,
+ nsValueCES,
+ nsValueTel,
+ nsValueInt,
+ nsValueBin,
+ nsValueDN,
+ nsValueType,
+ nsValueSyntax,
+ nsValueDescription,
+ nsValueHelpURL,
+ nsValueFlags,
+ nsValueDefault
+
diff --git a/ldap/cm/v4confs/41/ns-wcal-globopt.conf b/ldap/cm/v4confs/41/ns-wcal-globopt.conf
new file mode 100644
index 00000000..72b108c7
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-wcal-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#used by Netscape Calendar Hosting Server 1.0
+
+index nswcalCALID pres,eq
diff --git a/ldap/cm/v4confs/41/ns-wcal-schema.conf b/ldap/cm/v4confs/41/ns-wcal-schema.conf
new file mode 100644
index 00000000..97a6d12d
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-wcal-schema.conf
@@ -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
+#
+# Used by Netscape Calendar Hosting Server
+
+# Login calendar URI for this user
+attribute nswcalCALID 2.16.840.1.113730.3.1.537 cis single
+
+# Calendar client specific user preferences for this user
+attribute nswcalExtendedUserPrefs 2.16.840.1.113730.3.1.538 cis
+
+# Lists calendar protocols not allowed to be used by this user
+attribute nswcalDisallowAccess 2.16.840.1.113730.3.1.539 cis single
+
+# Calendar host for this user's login calendar
+attribute nswcalHost 2.16.840.1.113730.3.1.540 cis
+
+# Quota associated with this user's calendars
+attribute nswcalQuota 2.16.840.1.113730.3.1.541 cis single
+
+# Used to designate a LDAP entry as representing a Netscape Calendar
+# Hosting Server user account. These first 10 attributes are
+# referenced by Netscape Calendar Hosting Server and the last 3
+# attributes are reserved for future use.
+objectClass nswcalUser
+ oid 2.16.840.1.113730.3.2.83
+ requires
+ objectClass
+ allows
+ cn,
+ givenName,
+ mail,
+ preferredlanguage,
+ sn,
+ uid,
+ userPassword,
+ nswcalCALID,
+ nswcalDisallowAccess,
+ nswcalExtendedUserPrefs,
+ nslicensedfor,
+ nswcalHost,
+ nswcalQuota
+
+# From http://www.imc.org/draft-ietf-calsch-locating
+attribute calCalURI 1.2.840.113556.1.4.478 cis
+attribute calFBURL 1.2.840.113556.1.4.479 cis
+attribute calCAPURI 1.2.840.113556.1.4.480 cis
+attribute calCalAdrURI 1.2.840.113556.1.4.481 cis
+attribute calOtherCalURIs 1.2.840.113556.1.4.482 cis
+attribute calOtherFBURLs 1.2.840.113556.1.4.483 cis
+attribute calOtherCAPURIs 1.2.840.113556.1.4.484 cis
+attribute calOtherCalAdrURIs 1.2.840.113556.1.4.485 cis
+
+# Used to designate a LDAP entry as representing a calendar user.
+objectClass calEntry
+ oid 1.2.840.113556.1.5.87
+ requires
+ objectClass
+ allows
+ calCalURI,
+ calFBURL,
+ calCAPURI,
+ calCalAdrURI,
+ calOtherCalURIs,
+ calOtherFBURLs,
+ calOtherCAPURIs,
+ calOtherCalAdrURIs
diff --git a/ldap/cm/v4confs/41/ns-web-globopt.conf b/ldap/cm/v4confs/41/ns-web-globopt.conf
new file mode 100644
index 00000000..4db72fe2
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-web-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Enterprise Server
+#index uniquemember,member eq
+
diff --git a/ldap/cm/v4confs/41/ns-web-schema.conf b/ldap/cm/v4confs/41/ns-web-schema.conf
new file mode 100644
index 00000000..d5e74ed8
--- /dev/null
+++ b/ldap/cm/v4confs/41/ns-web-schema.conf
@@ -0,0 +1,18 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+objectclass netscapeWebServer
+ oid 2.16.840.1.113730.3.2.29
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description,
+ nsServerPort
+
diff --git a/ldap/cm/v4confs/41/slapd.at.conf b/ldap/cm/v4confs/41/slapd.at.conf
new file mode 100644
index 00000000..87c3e342
--- /dev/null
+++ b/ldap/cm/v4confs/41/slapd.at.conf
@@ -0,0 +1,391 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.at.conf for Netscape Directory Server 4.1
+#
+# DO NOT MODIFY!
+#
+# The attributes listed in this file are Standard Attributes and are
+# expected to present in Directory Server 4.1. Editing this file could
+# cause interoperability problems.
+#
+# User Defined Attributes should be added by selecting
+# Schema | Edit or View Attributes from the Admin Server.
+#
+# User Defined Attributes are placed in slapd.user_at.conf.
+#
+# All attributes are viewable over LDAP in the cn=schema entry under
+# attributetypes.
+#
+# The format of this file is:
+#
+# attribute attribute-name [attribute-aliases] [attribute-oid] syntax
+#
+# If no OID is specified, <attribute-name>-oid will be used as the OID
+#
+
+########################################################################
+# X.500(93) User Schema for use with LDAP
+# Taken from <draft-ietf-asid-ldapv3schema-x500-00.txt>
+########################################################################
+
+attribute objectClass 2.5.4.0 cis
+attribute aliasedObjectName 2.5.4.1 dn
+attribute knowledgeInformation 2.5.4.2 cis
+attribute cn commonName 2.5.4.3 cis
+attribute sn surName 2.5.4.4 cis
+attribute serialNumber 2.5.4.5 cis
+attribute c countryName 2.5.4.6 cis
+attribute l locality localityname 2.5.4.7 cis
+attribute st stateOrProvinceName 2.5.4.8 cis
+attribute street streetaddress 2.5.4.9 cis
+attribute o organizationname 2.5.4.10 cis
+attribute ou organizationalUnitName 2.5.4.11 cis
+attribute title 2.5.4.12 cis
+attribute description 2.5.4.13 cis
+attribute searchGuide 2.5.4.14 ces
+attribute businessCategory 2.5.4.15 cis
+attribute postalAddress 2.5.4.16 cis
+attribute postalCode 2.5.4.17 cis
+attribute postOfficeBox 2.5.4.18 cis
+attribute physicalDeliveryOfficeName 2.5.4.19 cis
+attribute telephoneNumber 2.5.4.20 tel
+attribute telexNumber 2.5.4.21 cis
+attribute teletexTerminalIdentifier 2.5.4.22 cis
+attribute facsimileTelephoneNumber fax 2.5.4.23 tel
+attribute x121Address 2.5.4.24 ces
+attribute internationalIsdnNumber 2.5.4.25 ces
+attribute registeredAddress 2.5.4.26 cis
+attribute destinationIndicator 2.5.4.27 cis
+attribute preferredDeliveryMethod 2.5.4.28 cis single
+attribute presentationAddress 2.5.4.29 ces
+attribute supportedApplicationContext 2.5.4.30 cis
+attribute member 2.5.4.31 dn
+attribute owner 2.5.4.32 dn
+attribute roleOccupant 2.5.4.33 dn
+attribute seeAlso 2.5.4.34 dn
+attribute userPassword 2.5.4.35 bin
+attribute userCertificate 2.5.4.36 bin
+attribute cACertificate cACertificate 2.5.4.37 bin
+attribute authorityRevocationList authorityRevocationList 2.5.4.38 bin
+attribute certificateRevocationList certificateRevocationList 2.5.4.39 bin
+attribute crossCertificatePair crossCertificatePair 2.5.4.40 bin
+attribute givenName 2.5.4.42 cis
+attribute initials 2.5.4.43 cis
+attribute generationQualifier 2.5.4.44 cis
+attribute x500UniqueIdentifier 2.5.4.45 bin
+attribute dnQualifier 2.5.4.46 cis
+attribute enhancedSearchGuide 2.5.4.47 cis
+attribute protocolInformation 2.5.4.48 cis
+attribute dn distinguishedName 2.5.4.49 dn
+attribute uniqueMember 2.5.4.50 dn
+attribute houseIdentifier 2.5.4.51 cis
+attribute supportedAlgorithms 2.5.4.52 bin
+attribute deltaRevocationList 2.5.4.53 bin
+
+#######################################################################
+# LDAP Attributes #
+# Taken from <draft-ietf-asid-ldapv3-attributes-07.txt> #
+#######################################################################
+
+attribute createTimestamp 2.5.18.1 cis
+attribute modifyTimestamp 2.5.18.2 cis
+attribute creatorsName 2.5.18.3 dn
+attribute modifiersName 2.5.18.4 dn
+attribute subschemaSubentry 2.5.18.10 dn
+attribute attributeTypes 2.5.21.5 cis
+attribute objectClasses 2.5.21.6 cis
+attribute matchingRules 2.5.21.4 cis
+attribute matchingRuleUse 2.5.21.8 cis
+attribute dITStructureRules 2.5.21.1 cis
+attribute dITContentRules 2.5.21.2 cis
+attribute nameForms 2.5.21.7 cis
+
+attribute namingContexts 1.3.6.1.4.1.1466.101.120.5 dn
+attribute altServer 1.3.6.1.4.1.1466.101.120.6 ces
+attribute supportedExtension 1.3.6.1.4.1.1466.101.120.7 cis
+attribute supportedControl 1.3.6.1.4.1.1466.101.120.13 cis
+attribute supportedSASLMechanisms 1.3.6.1.4.1.1466.101.120.14 cis
+attribute supportedLDAPVersion 1.3.6.1.4.1.1466.101.120.15 int
+attribute ldapSyntaxes 1.3.6.1.4.1.1466.101.120.16 cis
+
+#######################################################################
+# Pilot X.500 schema for use in LDAPv3 #
+# Taken from <draft-ietf-asid-schema-pilot-00.txt> #
+#######################################################################
+
+attribute uid 0.9.2342.19200300.100.1.1 cis
+attribute textEncodedORAddress 0.9.2342.19200300.100.1.2 cis
+attribute mail rfc822mailbox 0.9.2342.19200300.100.1.3 cis
+attribute info 0.9.2342.19200300.100.1.4 cis
+attribute drink 0.9.2342.19200300.100.1.5 cis
+attribute roomNumber 0.9.2342.19200300.100.1.6 cis
+attribute userClass 0.9.2342.19200300.100.1.8 cis
+attribute host 0.9.2342.19200300.100.1.9 cis
+attribute manager 0.9.2342.19200300.100.1.10 dn
+attribute documentIdentifier 0.9.2342.19200300.100.1.11 cis
+attribute documentTitle 0.9.2342.19200300.100.1.12 cis
+attribute documentVersion 0.9.2342.19200300.100.1.13 cis
+attribute documentAuthor 0.9.2342.19200300.100.1.14 dn
+attribute documentLocation 0.9.2342.19200300.100.1.15 cis
+attribute homePhone 0.9.2342.19200300.100.1.20 tel
+attribute secretary 0.9.2342.19200300.100.1.21 dn
+attribute otherMailbox 0.9.2342.19200300.100.1.22 cis
+attribute dc domaincomponent 0.9.2342.19200300.100.1.25 cis
+attribute dNSRecord 0.9.2342.19200300.100.1.26 cis
+attribute associatedName 0.9.2342.19200300.100.1.38 dn
+attribute homePostalAddress 0.9.2342.19200300.100.1.39 cis
+attribute personalTitle 0.9.2342.19200300.100.1.40 cis
+attribute mobile mobileTelephoneNumber 0.9.2342.19200300.100.1.41 tel
+attribute pager pagerTelephoneNumber 0.9.2342.19200300.100.1.42 tel
+attribute co friendlycountryname 0.9.2342.19200300.100.1.43 cis
+attribute uniqueIdentifier 0.9.2342.19200300.100.1.44 cis
+attribute organizationalStatus 0.9.2342.19200300.100.1.45 cis
+attribute janetMailbox 0.9.2342.19200300.100.1.46 cis
+attribute mailPreferenceOption 0.9.2342.19200300.100.1.47 int single
+attribute buildingName 0.9.2342.19200300.100.1.48 cis
+attribute dSAQuality 0.9.2342.19200300.100.1.49 cis single
+attribute singleLevelQuality 0.9.2342.19200300.100.1.50 cis single
+attribute subtreeMinimumQuality 0.9.2342.19200300.100.1.51 cis single
+attribute subtreeMaximumQuality 0.9.2342.19200300.100.1.52 cis single
+attribute personalSignature 0.9.2342.19200300.100.1.53 bin
+attribute ditRedirect 0.9.2342.19200300.100.1.54 dn
+attribute audio 0.9.2342.19200300.100.1.55 bin
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis
+attribute jpegPhoto 0.9.2342.19200300.100.1.60 bin
+
+#definitions subsequent to RFC 1274
+
+attribute labeledUri labeledurl 1.3.6.1.4.1.250.1.57 ces
+
+
+############################################################################
+# Netscape Defined Attributes
+#
+# The Netscape base OID is 2.16.840.1.113730
+# The base OID for the Netscape Directory Server is 2.16.840.1.113730.3
+# Netscape defined attributes have base 2.16.840.1.113730.3.1
+#
+# More Netscape defined attributes can be found included in ns-schema.conf
+############################################################################
+
+attribute carLicense 2.16.840.1.113730.3.1.1 cis
+attribute departmentNumber 2.16.840.1.113730.3.1.2 cis
+attribute employeeNumber 2.16.840.1.113730.3.1.3 cis single
+attribute employeeType 2.16.840.1.113730.3.1.4 cis
+attribute changeNumber 2.16.840.1.113730.3.1.5 int
+attribute targetDn 2.16.840.1.113730.3.1.6 dn
+attribute changeType 2.16.840.1.113730.3.1.7 cis
+attribute changes 2.16.840.1.113730.3.1.8 bin
+attribute newRdn 2.16.840.1.113730.3.1.9 dn
+attribute deleteOldRdn 2.16.840.1.113730.3.1.10 cis
+attribute newSuperior 2.16.840.1.113730.3.1.11 dn
+attribute ref 2.16.840.1.113730.3.1.34 ces
+attribute nsLicensedFor 2.16.840.1.113730.3.1.36 cis
+attribute nsLicenseStartTime 2.16.840.1.113730.3.1.37 cis
+attribute nsLicenseEndTime 2.16.840.1.113730.3.1.38 cis
+attribute preferredLanguage 2.16.840.1.113730.3.1.39 cis single
+attribute userSMIMECertificate 2.16.840.1.113730.3.1.40 bin
+attribute ntUserDomainId 2.16.840.1.113730.3.1.41 cis single
+attribute ntUserCreateNewAccount 2.16.840.1.113730.3.1.42 cis single
+attribute ntUserDeleteAccount 2.16.840.1.113730.3.1.43 cis single
+attribute ntGroupDomainId 2.16.840.1.113730.3.1.44 cis single
+attribute ntGroupCreateNewGroup 2.16.840.1.113730.3.1.45 cis single
+attribute ntGroupDeleteGroup 2.16.840.1.113730.3.1.46 cis single
+attribute ntGroupType 2.16.840.1.113730.3.1.47 cis single
+attribute replicaPort 2.16.840.1.113730.3.1.48 cis
+attribute replicaUpdateFailedAt 2.16.840.1.113730.3.1.49 cis
+attribute replicaBeginOrc 2.16.840.1.113730.3.1.50 cis
+attribute replicaUpdateReplayed 2.16.840.1.113730.3.1.51 cis
+attribute replicaUpdateSchedule 2.16.840.1.113730.3.1.52 cis
+attribute replicaBindMethod 2.16.840.1.113730.3.1.53 cis
+attribute replicaUseSSL 2.16.840.1.113730.3.1.54 cis
+attribute aci 2.16.840.1.113730.3.1.55 bin
+attribute lastModifiedBy 0.9.2342.19200300.100.1.24 dn
+attribute replicaRoot 2.16.840.1.113730.3.1.57 dn
+attribute replicaBindDn 2.16.840.1.113730.3.1.58 dn
+attribute ntUserPriv 2.16.840.1.113730.3.1.59 bin single
+attribute ntUserAuthFlags 2.16.840.1.113730.3.1.60 bin single
+attribute ntUserUsrComment 2.16.840.1.113730.3.1.61 cis single
+attribute ntUserParms 2.16.840.1.113730.3.1.62 cis single
+attribute ntUserUnitsPerWeek 2.16.840.1.113730.3.1.63 bin single
+attribute ntUserNumLogons 2.16.840.1.113730.3.1.64 bin single
+attribute ntUserLogonServer 2.16.840.1.113730.3.1.65 cis single
+attribute ntUserUniqueId 2.16.840.1.113730.3.1.66 bin single
+attribute ntUserProfile 2.16.840.1.113730.3.1.67 cis single
+attribute ntUserPasswordExpired 2.16.840.1.113730.3.1.68 bin single
+attribute subtreeACI 2.16.840.1.113730.3.1.69 ces
+attribute serverRoot 2.16.840.1.113730.3.1.70 cis
+attribute serverProductName 2.16.840.1.113730.3.1.71 cis
+attribute serverVersionNumber 2.16.840.1.113730.3.1.72 cis
+attribute installationTimeStamp 2.16.840.1.113730.3.1.73 cis
+attribute administratorContactInfo 2.16.840.1.113730.3.1.74 cis
+attribute adminUrl 2.16.840.1.113730.3.1.75 ces
+attribute serverHostName 2.16.840.1.113730.3.1.76 cis
+attribute changeTime 2.16.840.1.113730.3.1.77 cis
+attribute cirReplicaRoot 2.16.840.1.113730.3.1.79 dn
+attribute cirHost 2.16.840.1.113730.3.1.80 cis
+attribute cirPort 2.16.840.1.113730.3.1.81 cis
+attribute cirBindDn 2.16.840.1.113730.3.1.82 dn
+attribute cirUsePersistentSearch 2.16.840.1.113730.3.1.83 cis
+attribute cirUseSsl 2.16.840.1.113730.3.1.84 cis
+attribute cirBindCredentials 2.16.840.1.113730.3.1.85 ces
+attribute cirLastUpdateApplied 2.16.840.1.113730.3.1.86 cis
+attribute cirUpdateSchedule 2.16.840.1.113730.3.1.87 cis
+attribute cirUpdateFailedat 2.16.840.1.113730.3.1.88 cis
+attribute cirSyncInterval 2.16.840.1.113730.3.1.89 cis
+attribute cirBeginORC 2.16.840.1.113730.3.1.90 cis
+attribute passwordExpirationTime 2.16.840.1.113730.3.1.91 cis operational
+attribute passwordExpWarned 2.16.840.1.113730.3.1.92 cis operational
+attribute passwordRetryCount 2.16.840.1.113730.3.1.93 cis operational
+attribute retryCountResetTime 2.16.840.1.113730.3.1.94 cis operational
+attribute accountUnlockTime 2.16.840.1.113730.3.1.95 cis operational
+attribute passwordHistory 2.16.840.1.113730.3.1.96 bin operational
+attribute passwordMaxAge 2.16.840.1.113730.3.1.97 cis
+attribute passwordExp 2.16.840.1.113730.3.1.98 cis
+attribute passwordMinLength 2.16.840.1.113730.3.1.99 cis
+attribute passwordKeepHistory 2.16.840.1.113730.3.1.100 cis
+attribute passwordInHistory 2.16.840.1.113730.3.1.101 cis
+attribute passwordChange 2.16.840.1.113730.3.1.102 cis
+attribute passwordCheckSyntax 2.16.840.1.113730.3.1.103 cis
+attribute passwordWarning 2.16.840.1.113730.3.1.104 cis
+attribute passwordLockout 2.16.840.1.113730.3.1.105 cis
+attribute passwordMaxFailure 2.16.840.1.113730.3.1.106 cis
+attribute passwordResetDuration 2.16.840.1.113730.3.1.107 cis
+attribute passwordUnlock 2.16.840.1.113730.3.1.108 cis
+attribute passwordLockoutDuration 2.16.840.1.113730.3.1.109 cis
+attribute ntGroupId 2.16.840.1.113730.3.1.110 bin single
+attribute replicaHost 2.16.840.1.113730.3.1.197 cis
+attribute memberURL 2.16.840.1.113730.3.1.198 ces
+attribute memberCertificateDescription 2.16.840.1.113730.3.1.199 ces
+attribute replicaCredentials 2.16.840.1.113730.3.1.202 bin
+attribute replicaEntryFilter 2.16.840.1.113730.3.1.203 ces
+attribute replicaNickName 2.16.840.1.113730.3.1.204 cis
+attribute filterInfo 2.16.840.1.113730.3.1.206 cis
+attribute replicaCFUpdated 2.16.840.1.113730.3.1.217 cis
+attribute replicaAbandonedChanges 2.16.840.1.113730.3.1.218 cis
+attribute vlvBase 2.16.840.1.113730.3.1.207 dn
+attribute vlvScope 2.16.840.1.113730.3.1.208 int
+attribute vlvFilter 2.16.840.1.113730.3.1.209 ces
+attribute vlvSort 2.16.840.1.113730.3.1.210 cis
+attribute vlvName 2.16.840.1.113730.3.1.211 ces
+attribute netscapeMDSuffix 2.16.840.1.113730.3.1.212 dn
+attribute vlvEnabled 2.16.840.1.113730.3.1.213 int
+attribute passwordAllowChangeTime 2.16.840.1.113730.3.1.214 cis operational
+attribute oid 2.16.840.1.113730.3.1.215 cis
+attribute userPKCS12 2.16.840.1.113730.3.1.216 bin
+attribute vlvUses 2.16.840.1.113730.3.1.219 int
+attribute passwordMustChange 2.16.840.1.113730.3.1.220 cis
+attribute passwordStorageScheme 2.16.840.1.113730.3.1.121 cis
+attribute passwordMinAge 2.16.840.1.113730.3.1.122 cis
+attribute passwordResetFailureCount 2.16.840.1.113730.3.1.123 cis
+attribute nsslapd-pluginPath 2.16.840.1.113730.3.1.224 cis
+attribute nsslapd-pluginInitfunc 2.16.840.1.113730.3.1.225 cis
+attribute nsslapd-pluginType 2.16.840.1.113730.3.1.226 cis
+attribute nsslapd-pluginId 2.16.840.1.113730.3.1.227 cis
+attribute nsslapd-pluginVersion 2.16.840.1.113730.3.1.228 cis
+attribute nsslapd-pluginVendor 2.16.840.1.113730.3.1.229 cis
+attribute nsslapd-pluginDescription 2.16.840.1.113730.3.1.230 cis
+attribute nsslapd-pluginEnabled 2.16.840.1.113730.3.1.231 cis
+attribute nsSNMPEnabled 2.16.840.1.113730.3.1.232 cis
+attribute nsSNMPOrganization 2.16.840.1.113730.3.1.233 cis
+attribute nsSNMPLocation 2.16.840.1.113730.3.1.234 cis
+attribute nsSNMPContact 2.16.840.1.113730.3.1.235 cis
+attribute nsSNMPDescription 2.16.840.1.113730.3.1.236 cis
+attribute nsSNMPMasterHost 2.16.840.1.113730.3.1.237 cis
+attribute nsSNMPMasterPort 2.16.840.1.113730.3.1.238 cis
+attribute nsslapd-backend 2.16.840.1.113730.3.1.239 cis
+attribute replicatedattributelist 2.16.840.1.113730.3.1.240 cis
+attribute displayName 2.16.840.1.113730.3.1.241 cis single
+attribute nsSystemIndex 2.16.840.1.113730.3.1.242 cis
+attribute nsIndexType 2.16.840.1.113730.3.1.327 cis
+attribute nsMatchingRule 2.16.840.1.113730.3.1.328 cis
+attribute nsAddressBookSyncURL 2.16.840.1.113730.3.1.330 ces
+attribute nsSynchUserIDFormat 2.16.840.1.113730.3.1.406 cis
+attribute nsSynchUniqueAttribute 2.16.840.1.113730.3.1.407 cis
+attribute replicaLastRelevantChange 2.16.840.1.113730.3.1.408 int
+attribute ntUserHomeDir 2.16.840.1.113730.3.1.521 cis single
+attribute ntUserComment 2.16.840.1.113730.3.1.522 cis single
+attribute ntUserFlags 2.16.840.1.113730.3.1.523 bin single
+attribute ntUserScriptPath 2.16.840.1.113730.3.1.524 cis single
+attribute ntUserWorkstations 2.16.840.1.113730.3.1.525 cis single
+attribute ntUserLastLogon 2.16.840.1.113730.3.1.526 cis single
+attribute ntUserLastLogoff 2.16.840.1.113730.3.1.527 cis single
+attribute ntUserAcctExpires 2.16.840.1.113730.3.1.528 cis single
+attribute ntUserMaxStorage 2.16.840.1.113730.3.1.529 bin single
+attribute ntUserLogonHours 2.16.840.1.113730.3.1.530 bin single
+attribute ntUserBadPwCount 2.16.840.1.113730.3.1.531 bin single
+attribute ntUserCountryCode 2.16.840.1.113730.3.1.532 cis single
+attribute ntUserCodePage 2.16.840.1.113730.3.1.533 bin single
+attribute ntUserPrimaryGroupId 2.16.840.1.113730.3.1.534 bin single
+attribute ntUserHomeDirDrive 2.16.840.1.113730.3.1.535 cis single
+attribute ntGroupAttributes 2.16.840.1.113730.3.1.536 bin single
+
+#
+# Attribute types with OIDs
+#
+
+attribute associatedDomain 0.9.2342.19200300.100.1.37 cis
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis single
+
+
+#
+# Attributes which are used by some objectClass, but with unknown OID
+#
+
+attribute abstract abstract-oid cis
+attribute authorCn documentauthorcommonname authorcn-oid cis
+attribute authorSn documentauthorsurname authorsn-oid cis
+attribute changeLog 2.16.840.1.113730.3.1.35 dn
+attribute changeLogMaximumAge 2.16.840.1.113730.3.1.200 cis
+attribute changeLogMaximumSize 2.16.840.1.113730.3.1.201 cis
+attribute documentStore documentStore-oid cis
+attribute keyWords keyWords-oid cis
+attribute lastModifiedTime 0.9.2342.19200300.100.1.23 cis
+attribute multiLineDescription multiLineDescription-oid cis
+attribute subject subject-oid cis
+attribute ttl timeToLive 1.3.6.1.4.1.250.1.60 cis
+attribute photo 0.9.2342.19200300.100.1.7 bin
+attribute generation generation-oid ces
+attribute obsoletedByDocument obsoletedByDocument-oid dn
+attribute obsoletesDocument obsoletesDocument-oid dn
+attribute reciprocalNamingLink reciprocalNaminglink-oid dn
+attribute updatedByDocument updatedByDocument-oid dn
+attribute updatesDocument updatesDocument-oid dn
+
+#
+# Attribute types from RFC 2307
+#
+
+attribute uidNumber 1.3.6.1.1.1.1.0 int single
+attribute gidNumber 1.3.6.1.1.1.1.1 int single
+attribute gecos 1.3.6.1.1.1.1.2 cis single
+attribute homeDirectory 1.3.6.1.1.1.1.3 ces single
+attribute loginShell 1.3.6.1.1.1.1.4 int single
+attribute shadowLastChange 1.3.6.1.1.1.1.5 int single
+attribute shadowMin 1.3.6.1.1.1.1.6 int single
+attribute shadowMax 1.3.6.1.1.1.1.7 int single
+attribute shadowWarning 1.3.6.1.1.1.1.8 int single
+attribute shadowInactive 1.3.6.1.1.1.1.9 int single
+attribute shadowExpire 1.3.6.1.1.1.1.10 int single
+attribute shadowFlag 1.3.6.1.1.1.1.11 int single
+attribute memberUid 1.3.6.1.1.1.1.12 ces
+attribute memberNisNetgroup 1.3.6.1.1.1.1.13 ces
+attribute nisNetgroupTriple 1.3.6.1.1.1.1.14 ces
+attribute ipServicePort 1.3.6.1.1.1.1.15 int single
+attribute ipServiceProtocol 1.3.6.1.1.1.1.16 cis
+attribute ipProtocolNumber 1.3.6.1.1.1.1.17 int single
+attribute oncRpcNumber 1.3.6.1.1.1.1.18 int single
+attribute ipHostNumber 1.3.6.1.1.1.1.19 cis
+attribute ipNetworkNumber 1.3.6.1.1.1.1.20 cis single
+attribute ipNetmaskNumber 1.3.6.1.1.1.1.21 cis single
+attribute macAddress 1.3.6.1.1.1.1.22 cis
+attribute bootParameter 1.3.6.1.1.1.1.23 ces
+attribute bootFile 1.3.6.1.1.1.1.24 ces
+attribute automountInformation 1.3.6.1.1.1.1.25 ces
+attribute nisMapName 1.3.6.1.1.1.1.26 cis
+attribute nisMapEntry 1.3.6.1.1.1.1.27 ces single
diff --git a/ldap/cm/v4confs/41/slapd.oc.conf b/ldap/cm/v4confs/41/slapd.oc.conf
new file mode 100644
index 00000000..1e8c451b
--- /dev/null
+++ b/ldap/cm/v4confs/41/slapd.oc.conf
@@ -0,0 +1,1069 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.oc.conf for Netscape Directory Server 4.1
+#
+# DO NOT MODIFY!
+#
+# The ObjectClasses in this file are Standard ObjectClasses and are expected
+# to be present in Directory Server 4.1 unchanged. Modifing this file may
+# cause interoperability problems.
+#
+# User Defined ObjectClasses should be added by selecting
+# Schema | Create ObjectClasses from the Admin Server.
+#
+# User Defined ObjectClasses are saved in slapd.user_oc.conf
+#
+# All ObjectClasses are viewable in the cn=schema entry under objectclasses.
+#
+# The format of this file is:
+#
+# objectclass ObjectClassName
+# [ oid ObjectIdentifier ]
+# [ superior ParentObjectClass ]
+# [ requires <comma separated list of required attributes> ]
+# [ allows <comma separated list of allowed attributes> ]
+#
+
+objectclass top
+ oid 2.5.6.0
+ requires
+ objectClass
+ allows
+ aci
+
+objectclass alias
+ oid 2.5.6.1
+ superior top
+ requires
+ aliasedObjectName
+
+objectclass country
+ oid 2.5.6.2
+ superior top
+ requires
+ c
+ allows
+ searchGuide,
+ description
+
+objectclass locality
+ oid 2.5.6.3
+ superior top
+ allows
+ description,
+ l,
+ searchGuide,
+ seeAlso,
+ st,
+ street
+
+objectclass organization
+ oid 2.5.6.4
+ superior top
+ requires
+ o
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass organizationalUnit
+ oid 2.5.6.5
+ superior top
+ requires
+ ou
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass person
+ oid 2.5.6.6
+ superior top
+ requires
+ sn,
+ cn
+ allows
+ description,
+ seeAlso,
+ telephoneNumber,
+ userPassword
+
+objectclass organizationalPerson
+ oid 2.5.6.7
+ superior person
+ allows
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ title,
+ x121Address
+
+# The certificate attributes include all subtypes, such as ';binary'.
+#
+objectclass inetOrgPerson
+ oid 2.16.840.1.113730.3.2.2
+ superior organizationalPerson
+ allows
+ audio,
+ businessCategory,
+ carLicense,
+ departmentNumber,
+ displayName,
+ employeeType,
+ employeeNumber,
+ givenName,
+ homePhone,
+ homePostalAddress,
+ initials,
+ jpegPhoto,
+ labeledURI,
+ manager,
+ mobile,
+ pager,
+ photo,
+ preferredLanguage,
+ mail,
+ o,
+ roomNumber,
+ secretary,
+ uid,
+ x500uniqueIdentifier,
+ userCertificate,
+ userSMimeCertificate,
+ userPKCS12
+
+objectclass ntUser
+ oid 2.16.840.1.113730.3.2.8
+ superior top
+ requires
+ ntUserDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntUserPriv,
+ ntUserHomeDir,
+ ntUserComment,
+ ntUserFlags,
+ ntUserScriptPath,
+ ntUserAuthFlags,
+ ntUserUsrComment,
+ ntUserParms,
+ ntUserWorkstations,
+ ntUserLastLogon,
+ ntUserLastLogoff,
+ ntUserAcctExpires,
+ ntUserMaxStorage,
+ ntUserUnitsPerWeek,
+ ntUserLogonHours,
+ ntUserBadPwCount,
+ ntUserNumLogons,
+ ntUserLogonServer,
+ ntUserCountryCode,
+ ntUserCodePage,
+ ntUserUniqueId,
+ ntUserPrimaryGroupId,
+ ntUserProfile,
+ ntUserHomeDirDrive,
+ ntUserPasswordExpired,
+ ntUserCreateNewAccount,
+ ntUserDeleteAccount
+
+objectclass ntGroup
+ oid 2.16.840.1.113730.3.2.9
+ superior top
+ requires
+ ntGroupDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntGroupId,
+ ntGroupAttributes,
+ ntGroupCreateNewGroup,
+ ntGroupDeleteGroup,
+ ntGroupType
+
+objectclass organizationalRole
+ oid 2.5.6.8
+ superior top
+ requires
+ cn
+ allows
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ roleOccupant,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass groupOfNames
+ oid 2.5.6.9
+ superior top
+ requires
+ cn
+ allows
+ member,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfUniqueNames
+ oid 2.5.6.17
+ superior top
+ requires
+ cn
+ allows
+ uniqueMember,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfCertificates
+ oid 2.16.840.1.113730.3.2.31
+ superior top
+ requires
+ cn
+ allows
+ memberCertificateDescription,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfURLs
+ oid 2.16.840.1.113730.3.2.33
+ superior top
+ requires
+ cn
+ allows
+ memberURL,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass residentialPerson
+ oid 2.5.6.10
+ superior person
+ requires
+ l
+ allows
+ businessCategory,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass applicationProcess
+ oid 2.5.6.11
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso
+
+objectclass LDAPServer
+ oid 2.16.840.1.113730.3.2.35
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ generation,
+ changeLogMaximumAge,
+ changeLogMaximumSize
+
+objectclass LDAPReplica
+ oid 2.16.840.1.113730.3.2.36
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ replicaRoot,
+ replicaHost,
+ replicaPort,
+ replicaBindDn,
+ replicaCredentials,
+ replicaBindMethod,
+ replicaUseSSL,
+ replicaUpdateSchedule,
+ replicaUpdateReplayed,
+ replicaUpdateFailedAt,
+ replicaBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList,
+ replicaCFUpdated,
+ replicaAbandonedChanges,
+ replicaLastRelevantChange
+
+objectclass applicationEntity
+ oid 2.5.6.12
+ superior top
+ requires
+ presentationAddress,
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ supportedApplicationContext
+
+objectclass dSA
+ oid 2.5.6.13
+ superior applicationEntity
+ allows
+ knowledgeInformation
+
+objectclass device
+ oid 2.5.6.14
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# This userCertificate attribute includes all subtypes, such as ';binary'.
+objectclass strongAuthenticationUser
+ oid 2.5.6.15
+ superior top
+ requires
+ userCertificate
+
+# These attributes include all subtypes, such as ';binary'.
+objectclass certificationAuthority
+ oid 2.5.6.16
+ superior top
+ requires
+ cACertificate
+ allows
+ authorityRevocationList,
+ certificateRevocationList,
+ crossCertificatePair
+
+objectclass pilotObject
+ oid 0.9.2342.19200300.100.4.3
+ superior top
+ allows
+ audio,
+ dITRedirect,
+ info,
+ jpegPhoto,
+ lastModifiedBy,
+ lastModifiedTime,
+ manager,
+ photo,
+ uniqueIdentifier
+
+objectclass newPilotPerson
+ oid 0.9.2342.19200300.100.4.4
+ superior person
+ allows
+ businessCategory,
+ drink,
+ homePhone,
+ homePostalAddress,
+ janetMailbox,
+ mail,
+ mailPreferenceOption,
+ mobile,
+ organizationalStatus,
+ otherMailbox,
+ pager,
+ personalSignature,
+ personalTitle,
+ preferredDeliveryMethod,
+ roomNumber,
+ secretary,
+ textEncodedORAddress,
+ uid,
+ userClass
+
+objectclass account
+ oid 0.9.2342.19200300.100.4.5
+ superior top
+ requires
+ uid
+ allows
+ description,
+ host,
+ l,
+ o,
+ ou,
+ seeAlso
+
+objectclass document
+ oid 0.9.2342.19200300.100.4.6
+ superior pilotObject
+ requires
+ documentIdentifier
+ allows
+ abstract,
+ authorCN,
+ authorSN,
+ cn,
+ description,
+ documentAuthor,
+ documentLocation,
+ documentPublisher,
+ documentStore,
+ documentTitle,
+ documentVersion,
+ keywords,
+ l,
+ o,
+ obsoletedByDocument,
+ obsoletesDocument,
+ ou,
+ seeAlso,
+ subject,
+ updatedByDocument,
+ updatesDocument
+
+objectclass room
+ oid 0.9.2342.19200300.100.4.7
+ superior top
+ requires
+ cn
+ allows
+ description,
+ roomNumber,
+ seeAlso,
+ telephoneNumber
+
+objectclass documentSeries
+ oid 0.9.2342.19200300.100.4.9
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ telephoneNumber
+
+objectclass domain
+ oid 0.9.2342.19200300.100.4.13
+ superior top
+ requires
+ dc
+ allows
+ associatedName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ manager,
+ o,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass RFC822localPart
+ oid 0.9.2342.19200300.100.4.14
+ superior domain
+ allows
+ cn,
+ sn
+
+objectclass DNSDomain
+ oid 0.9.2342.19200300.100.4.15
+ superior domain
+ allows
+ dNSRecord
+
+objectclass domainRelatedObject
+ oid 0.9.2342.19200300.100.4.17
+ superior top
+ requires
+ associatedDomain
+
+objectclass friendlyCountry
+ oid 0.9.2342.19200300.100.4.18
+ superior country
+ requires
+ co
+
+objectclass simpleSecurityObject
+ oid 0.9.2342.19200300.100.4.19
+ superior top
+ requires
+ userPassword
+
+objectclass pilotOrganization
+ oid pilotOrganization-OID
+ superior top
+ requires
+ ou,
+ o
+ allows
+ buildingName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+
+objectclass labeledURIObject
+ oid 1.3.6.1.4.1.250.3.15
+ superior top
+ allows
+ labeledURI
+
+objectclass cacheObject
+ oid 1.3.6.1.4.1.250.3.18
+ superior top
+ allows
+ ttl
+
+# objectclasses below added since Netscape Directory Server 1.01
+
+objectclass netscapeServer
+ oid 2.16.840.1.113730.3.2.10
+ superior top
+ requires
+ cn
+ allows
+ description,
+ serverRoot,
+ serverProductName,
+ serverVersionNumber,
+ installationTimeStamp,
+ administratorContactInfo,
+ userpassword,
+ adminURL,
+ serverHostName
+
+objectclass nsLicenseUser
+ oid 2.16.840.1.113730.3.2.7
+ superior top
+ allows
+ nsLicensedFor,
+ nsLicenseStartTime,
+ nsLicenseEndTime
+
+objectclass changeLogEntry
+ oid 2.16.840.1.113730.3.2.1
+ superior top
+ requires
+ targetdn,
+ changeTime,
+ changenumber,
+ changeType
+ allows
+ changes,
+ newrdn,
+ deleteoldrdn,
+ newsuperior,
+ filterinfo
+
+objectclass cirReplicaSource
+ oid 2.16.840.1.113730.3.2.11
+ requires
+ cn,
+ objectClass
+ allows
+ cirReplicaRoot,
+ cirHost,
+ cirPort,
+ cirBindDN,
+ cirUsePersistentSearch,
+ cirUseSSL,
+ cirBindCredentials,
+ cirLastUpdateApplied,
+ cirUpdateSchedule,
+ cirSyncInterval,
+ cirUpdateFailedAt,
+ cirBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList
+
+objectclass referral
+ superior top
+ oid 2.16.840.1.113730.3.2.6
+ allows
+ ref
+
+objectclass passwordObject
+ oid 2.16.840.1.113730.3.2.12
+ requires
+ objectClass
+ allows
+ passwordExpirationTime,
+ passwordExpWarned,
+ passwordRetryCount,
+ retryCountResetTime,
+ accountUnlockTime,
+ passwordHistory,
+ passwordAllowChangeTime
+
+objectclass passwordPolicy
+ oid 2.16.840.1.113730.3.2.13
+ requires
+ objectClass
+ allows
+ passwordMaxAge,
+ passwordExp,
+ passwordMinLength,
+ passwordKeepHistory,
+ passwordInHistory,
+ passwordChange,
+ passwordWarning,
+ passwordLockout,
+ passwordMaxFailure,
+ passwordResetDuration,
+ passwordUnlock,
+ passwordLockoutDuration,
+ passwordCheckSyntax,
+ passwordMustChange,
+ passwordStorageScheme,
+ passwordMinAge,
+ passwordResetFailureCount
+
+objectclass glue
+ oid 2.16.840.1.113730.3.2.30
+ superior top
+
+objectclass netscapeMachineData
+ oid 2.16.840.1.113730.3.2.32
+ superior top
+
+objectclass dcObject
+ oid 1.3.6.1.4.1.1466.344
+ superior top
+ requires
+ dc
+
+objectclass subschema
+ oid 2.5.20.1
+ superior top
+ allows
+ cn,
+ dITStructureRules,
+ nameForms,
+ dITContentRules,
+ objectClasses,
+ attributeTypes,
+ matchingRules,
+ matchingRuleUse
+
+objectclass vlvSearch
+ oid 2.16.840.1.113730.3.2.38
+ superior top
+ requires
+ cn,
+ vlvBase,
+ vlvScope,
+ vlvFilter
+ allows
+ multiLineDescription
+
+objectclass nsslapdConfig
+ oid 2.16.840.1.113730.3.2.39
+ superior top
+ allows cn
+
+objectclass directoryServerFeature
+ oid 2.16.840.1.113730.3.2.40
+ superior top
+ allows
+ oid,
+ cn,
+ multiLineDescription
+
+objectclass nsslapdPlugin
+ oid 2.16.840.1.113730.3.2.41
+ superior top
+ requires
+ cn,
+ nsslapd-pluginPath,
+ nsslapd-pluginInitFunc,
+ nsslapd-pluginType,
+ nsslapd-pluginId,
+ nsslapd-pluginVersion,
+ nsslapd-pluginVendor,
+ nsslapd-pluginDescription,
+ nsslapd-pluginEnabled,
+ nsslapd-backend
+
+objectclass vlvIndex
+ oid 2.16.840.1.113730.3.2.42
+ superior top
+ requires
+ cn,
+ vlvSort
+ allows
+ vlvEnabled,
+ vlvUses
+
+objectclass nsSNMP
+ OID 2.16.840.1.113730.3.2.43
+ superior top
+ requires
+ cn,
+ nsSNMPEnabled
+ allows
+ nsSNMPOrganization,
+ nsSNMPLocation,
+ nsSNMPContact,
+ nsSNMPDescription,
+ nsSNMPMasterHost,
+ nsSNMPMasterPort
+
+objectclass nsIndex
+ oid 2.16.840.1.113730.3.2.44
+ superior top
+ requires
+ cn,
+ nsSystemIndex
+ allows
+ description,
+ nsIndexType,
+ nsMatchingRule
+
+#
+# ojectclass from rfc2307
+#
+
+# posixAccount is an auxiliary class. You may use account as a structural
+# class.
+objectclass posixAccount
+ oid
+ 1.3.6.1.1.1.2.0
+ superior
+ top
+ requires
+ objectClass,
+ cn,
+ uid,
+ uidNumber,
+ gidNumber,
+ homeDirectory
+ allows
+ userPassword,
+ loginShell,
+ gecos,
+ description
+
+# posixAccount is an auxiliary class. You may use account as a structural
+# class.
+objectclass shadowAccount
+ oid
+ 1.3.6.1.1.1.2.1
+ superior
+ top
+ requires
+ objectClass,
+ uid
+ allows
+ userPassword,
+ shadowLastChange,
+ shadowMin,
+ shadowMax,
+ shadowWarning,
+ shadowInactive,
+ shadowExpire,
+ shadowFlag,
+ description
+
+objectclass posixGroup
+ oid
+ 1.3.6.1.1.1.2.2
+ requires
+ objectClass,
+ cn,
+ gidNumber
+ allows
+ userPassword,
+ memberUid,
+ description
+
+objectclass ipService
+ oid
+ 1.3.6.1.1.1.2.3
+ requires
+ objectClass,
+ cn,
+ ipServicePort,
+ ipServiceProtocol
+ allows
+ description
+
+objectclass ipProtocol
+ oid
+ 1.3.6.1.1.1.2.4
+ requires
+ objectClass,
+ cn,
+ ipProtocolNumber
+ allows
+ description
+
+objectclass oncRpc
+ oid
+ 1.3.6.1.1.1.2.5
+ requires
+ objectClass,
+ cn,
+ oncRpcNumber
+ allows
+ description
+
+# ipHost is a subclass of device
+objectclass ipHost
+ oid
+ 1.3.6.1.1.1.2.6
+ requires
+ objectClass,
+ ipHostNumber,
+ cn
+ allows
+ manager,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+
+objectclass ipNetwork
+ oid
+ 1.3.6.1.1.1.2.7
+ requires
+ objectClass,
+ ipNetworkNumber,
+ cn
+ allows
+ ipNetmaskNumber,
+ manager,
+ l,
+ description
+
+objectclass nisNetgroup
+ oid
+ 1.3.6.1.1.1.2.8
+ requires
+ objectClass,
+ cn
+ allows
+ nisNetgroupTriple,
+ memberNisNetgroup,
+ description
+
+# the automount class is deprecated. Because cn is case insensitive
+# on matches, you may need to use another object class to unique
+# names.
+objectclass automount
+ oid
+ 1.3.6.1.1.1.2.9
+ requires
+ objectClass,
+ cn,
+ automountInformation
+ allows
+ description
+
+# nisObject represents entries in NIS maps.
+objectclass nisObject
+ oid
+ 1.3.6.1.1.1.2.10
+ requires
+ objectClass,
+ cn,
+ nisMapEntry,
+ nisMapName
+ allows
+ description
+
+# ieee802Device is a subclass of device
+objectclass ieee802Device
+ oid
+ 1.3.6.1.1.1.2.11
+ requires
+ objectClass,
+ cn
+ allows
+ macAddress,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# bootableDevice is a subclass of device
+objectclass bootableDevice
+ oid
+ 1.3.6.1.1.1.2.12
+ requires
+ objectClass,
+ cn
+ allows
+ bootFile,
+ bootParameter,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# nisMap is a structural class which may be used as a container
+# for instances of nisObject.
+objectclass nisMap
+ oid
+ 1.3.6.1.1.1.2.13
+ requires
+ objectClass,
+ nisMapName
+ allows
+ description
+
diff --git a/ldap/cm/v4confs/411/java-object-schema.conf b/ldap/cm/v4confs/411/java-object-schema.conf
new file mode 100644
index 00000000..1ba36b8c
--- /dev/null
+++ b/ldap/cm/v4confs/411/java-object-schema.conf
@@ -0,0 +1,58 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Schema for storing java objects and java object references
+
+attribute javaClassName 1.3.6.1.4.1.42.2.27.4.1.6 ces single
+
+attribute javaCodebase 1.3.6.1.4.1.42.2.27.4.1.7 ces
+
+attribute javaSerializedData 1.3.6.1.4.1.42.2.27.4.1.8 bin single
+
+attribute javaFactory 1.3.6.1.4.1.42.2.27.4.1.10 ces single
+
+attribute javaReferenceAddress 1.3.6.1.4.1.42.2.27.4.1.11 ces
+
+attribute javaDoc 1.3.6.1.4.1.42.2.27.4.1.12 ces
+
+attribute javaClassNames 1.3.6.1.4.1.42.2.27.4.1.13 ces
+
+objectclass javaContainer
+ oid 1.3.6.1.4.1.42.2.27.4.2.1
+ superior top
+ requires
+ cn
+
+objectclass javaObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.4
+ superior top
+ requires
+ javaClassName
+ allows
+ javaClassNames,
+ javaCodebase,
+ javaDoc,
+ description
+
+objectclass javaSerializedObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.5
+ superior javaObject
+ requires
+ javaSerializedData
+
+objectclass javaNamingReference
+ oid 1.3.6.1.4.1.42.2.27.4.2.7
+ superior javaObject
+ allows
+ javaReferenceAddress,
+ javaFactory
+
+objectclass javaMarshalledObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.8
+ superior javaObject
+ requires
+ javaSerializedData
diff --git a/ldap/cm/v4confs/411/ns-admin-schema.conf b/ldap/cm/v4confs/411/ns-admin-schema.conf
new file mode 100644
index 00000000..6bd0a9d0
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-admin-schema.conf
@@ -0,0 +1,155 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Netscape Administration Server LDAP Schema configuration file
+#
+# Version: 4.1
+# Description:
+# Administration Server and Mission Control Console attributes
+# and objectclasses.
+#
+
+#############################################################
+# Attributes
+#############################################################
+
+#
+# nsAdminConfig
+#
+attribute nsAdminCgiWaitPid cis
+attribute nsAdminUsers cis
+attribute nsAdminAccessHosts cis
+attribute nsAdminAccessAddresses cis
+attribute nsAdminOneACLDir cis
+attribute nsAdminEnableDSGW cis
+attribute nsAdminEnableEnduser cis
+attribute nsAdminCacheLifetime cis
+
+
+#
+# nsAdminResourceEditorExtension
+#
+attribute nsAdminAccountInfo cis
+attribute nsDeleteclassname cis
+
+#
+# nsAdminGlobalParameters
+#
+attribute nsAdminEndUserHTMLIndex cis
+
+#
+# nsGlobalParameters
+#
+attribute nsUniqueAttribute cis
+attribute nsUserIDFormat cis
+attribute nsUserRDNComponent cis
+attribute nsGroupRDNComponent cis
+attribute nsWellKnownJarfiles cis
+attribute nsNYR cis
+
+#
+# nsDefaultObjectClasses
+#
+attribute nsDefaultObjectClass cis
+
+#
+# nsAdminConsoleUser
+#
+attribute nsPreference cis
+
+#
+# nsCustomView
+#
+attribute nsDisplayName cis
+
+#
+# nsTopologyCustomView
+#
+attribute nsViewConfiguration cis
+
+#############################################################
+# Objectclasses
+#############################################################
+
+objectclass nsAdminServer
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description
+
+objectclass nsAdminConfig
+ superior nsConfig
+ allows
+ nsAdminCgiWaitPid,
+ nsAdminUsers,
+ nsAdminAccessHosts,
+ nsAdminAccessAddresses,
+ nsAdminOneACLDir,
+ nsAdminEnableDSGW,
+ nsAdminEnableEnduser,
+ nsAdminCacheLifetime
+
+objectclass nsAdminResourceEditorExtension
+ superior nsAdminObject
+ requires
+ cn
+ allows
+ nsAdminAccountInfo,
+ nsDeleteclassname
+
+objectclass nsAdminGlobalParameters
+ superior top
+ requires
+ cn
+ allows
+ nsAdminEndUserHTMLIndex,
+ nsNickname
+
+objectclass nsGlobalParameters
+ superior top
+ requires
+ cn
+ allows
+ nsUniqueAttribute,
+ nsUserIDFormat,
+ nsUserRDNComponent,
+ nsGroupRDNComponent,
+ nsWellKnownJarFiles,
+ nsNYR
+
+objectclass nsDefaultObjectClasses
+ superior top
+ requires
+ cn
+ allows
+ nsDefaultObjectClass
+
+objectclass nsAdminConsoleUser
+ superior top
+ requires
+ cn
+ allows
+ nsPreference
+
+objectclass nsCustomView
+ superior nsAdminObject
+ allows
+ nsDisplayName,
+
+objectclass nsTopologyCustomView
+ superior nsCustomView
+ requires
+ cn
+ allows
+ nsViewConfiguration
+
+objectclass nsTopologyPlugin
+ superior nsAdminObject
+ allows
diff --git a/ldap/cm/v4confs/411/ns-calendar-globopt.conf b/ldap/cm/v4confs/411/ns-calendar-globopt.conf
new file mode 100644
index 00000000..0bdb7dd9
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-calendar-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+index nsCalXItemId pres,eq,sub
diff --git a/ldap/cm/v4confs/411/ns-calendar-schema.conf b/ldap/cm/v4confs/411/ns-calendar-schema.conf
new file mode 100644
index 00000000..2a35ae3c
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-calendar-schema.conf
@@ -0,0 +1,148 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsCalAccess 2.16.840.1.113730.3.1.112 cis
+attribute nsCalAccessDomain 2.16.840.1.113730.3.1.113 cis
+attribute nsCalAdmd 2.16.840.1.113730.3.1.114 cis
+attribute nsCalDefaultNoteReminder 2.16.840.1.113730.3.1.115 cis
+attribute nsCalDefaultReminder 2.16.840.1.113730.3.1.116 cis
+attribute nsCalDefaultTaskReminder 2.16.840.1.113730.3.1.117 cis
+attribute nsCalDisplayPrefs 2.16.840.1.113730.3.1.118 cis
+attribute nsCalFlags 2.16.840.1.113730.3.1.119 cis
+attribute nsCalHost 2.16.840.1.113730.3.1.120 cis
+attribute nsCalLanguageId 2.16.840.1.113730.3.1.121 cis
+attribute nsCalNodeAlias 2.16.840.1.113730.3.1.122 cis
+attribute nsCalNotifMechanism 2.16.840.1.113730.3.1.123 cis
+attribute nsCalOperatingPrefs 2.16.840.1.113730.3.1.124 cis
+attribute nsCalOrgUnit2 2.16.840.1.113730.3.1.125 cis
+attribute nsCalOrgUnit3 2.16.840.1.113730.3.1.126 cis
+attribute nsCalOrgUnit4 2.16.840.1.113730.3.1.127 cis
+attribute nsCalPasswordRequired 2.16.840.1.113730.3.1.128 cis
+attribute nsCalPrmd 2.16.840.1.113730.3.1.129 cis
+attribute nsCalRefreshPrefs 2.16.840.1.113730.3.1.130 cis
+attribute nsCalResourceCapacity 2.16.840.1.113730.3.1.131 cis
+attribute nsCalResourceNumber 2.16.840.1.113730.3.1.132 cis
+attribute nsCalServerVersion 2.16.840.1.113730.3.1.133 cis
+attribute nsCalSysopCanWritePassword 2.16.840.1.113730.3.1.134 cis
+attribute nsCalTimezone 2.16.840.1.113730.3.1.135 cis
+attribute nsCalXItemId 2.16.840.1.113730.3.1.136 cis
+
+
+objectclass nsCalUser
+ oid 2.16.840.1.113730.3.2.14
+ requires
+ objectClass
+ allows
+ c,
+ employeeNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ mail,
+ o,
+ ou,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalRefreshPrefs,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass nsCalAdmin
+ oid 2.16.840.1.113730.3.2.15
+ requires
+ objectClass
+ allows
+ c,
+ cn,
+ facsimileTelephoneNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ mail,
+ o,
+ ou,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalXItemId
+
+objectclass nsCalResource
+ oid 2.16.840.1.113730.3.2.16
+ requires
+ objectClass
+ allows
+ cn,
+ facsimileTelephoneNumber,
+ givenName,
+ mail,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalPasswordRequired,
+ nsCalRefreshPrefs,
+ nsCalResourceCapacity,
+ nsCalResourceNumber,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass netscapeCalendarServer
+ oid 2.16.840.1.113730.3.2.17
+ requires
+ objectclass
+
+
+
diff --git a/ldap/cm/v4confs/411/ns-certificate-globopt.conf b/ldap/cm/v4confs/411/ns-certificate-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-certificate-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/411/ns-certificate-schema.conf b/ldap/cm/v4confs/411/ns-certificate-schema.conf
new file mode 100644
index 00000000..a9ef7b9d
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-certificate-schema.conf
@@ -0,0 +1,24 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+attribute nsCertConfig cis
+
+objectclass netscapeCertificateServer
+ oid 2.16.840.1.113730.3.2.18
+ requires
+ objectclass
+
+objectclass nsCertificateServer
+ requires
+ objectclass,
+ nsServerID
+ allows
+ serverHostName,
+ nsServerPort,
+ nsCertConfig
+
+
diff --git a/ldap/cm/v4confs/411/ns-common-schema.conf b/ldap/cm/v4confs/411/ns-common-schema.conf
new file mode 100644
index 00000000..a8d7b00c
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-common-schema.conf
@@ -0,0 +1,246 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Common LDAP schema configuration file
+#
+# Version: 4.1
+# Description:
+# This configuration file contains objectclasses and attributes
+# common to the Mission Control Framework
+#
+
+#############################################################
+# Attributes
+#############################################################
+
+#
+# Common Attributes
+#
+attribute nsServerID cis
+attribute nsBaseDN cis
+attribute nsBindDN cis
+attribute nsBindPassword cis
+attribute nsServerPort cis
+attribute nsServerAddress cis
+attribute nsDirectoryInfoRef dn
+attribute nsDirectoryURL ces
+attribute nsDirectoryFailoverList ces
+#
+# nsAdminDomain
+#
+attribute nsAdminDomainName cis
+
+#
+# nsHost
+#
+attribute nsHostLocation cis
+attribute nsHardwarePlatform cis
+attribute nsOsVersion cis
+
+#
+# nsAdminGroup
+#
+attribute nsAdminGroupName cis
+attribute nsConfigRoot cis
+attribute nsAdminSIEDN dn
+
+#
+# nsApplication
+#
+attribute nsVendor cis
+attribute nsProductName cis
+attribute nsNickName cis
+attribute nsProductVersion cis
+attribute nsBuildNumber cis
+attribute nsRevisionNumber cis
+attribute nsSerialNumber cis
+attribute nsInstalledLocation cis
+attribute nsExpirationDate cis
+attribute nsBuildSecurity cis
+attribute nsServerMigrationClassname cis
+attribute nsServerCreationClassname cis
+attribute nsLdapSchemaVersion cis
+
+#
+# nsConfig
+#
+attribute nsSuiteSpotUser cis
+attribute nsErrorLog cis
+attribute nsPidLog cis
+attribute nsAccessLog cis
+attribute nsDefaultAcceptLanguage cis
+attribute nsServerSecurity cis
+
+#
+# nsEncryptionConfig
+#
+attribute nsCertfile cis
+attribute nsKeyfile cis
+attribute nsSSL2 cis
+attribute nsSSL3 cis
+attribute nsSSLClientAuth cis
+attribute nsSSLSessionTimeout cis
+attribute nsSSL3SessionTimeout cis
+attribute nsSSL2Ciphers cis
+attribute nsSSL3Ciphers cis
+
+#
+# nsEncryptionModule
+#
+attribute nsSSLToken cis
+attribute nsSSLPersonalitySSL cis
+attribute nsSSLActivation cis
+
+#
+# nsTask
+#
+attribute nsTaskLabel cis
+attribute nsHelpRef cis
+attribute nsExecRef cis
+attribute nsLogSuppress cis
+
+#
+# nsAdminObject
+#
+attribute nsJarfilename cis
+attribute nsClassname cis
+
+
+#############################################################
+# Object Classes
+#############################################################
+objectclass nsAdminDomain
+ superior organizationalUnit
+ allows
+ nsAdminDomainName
+
+objectclass nsHost
+ superior top
+ requires
+ cn
+ allows
+ serverHostName,
+ description,
+ l,
+ nsHostLocation,
+ nsHardwarePlatform,
+ nsOsVersion
+
+objectclass nsAdminGroup
+ superior top
+ requires
+ cn
+ allows
+ nsAdminGroupName,
+ description,
+ nsConfigRoot,
+ nsAdminSIEDN
+
+objectclass nsApplication
+ superior top
+ requires
+ cn
+ allows
+ nsVendor,
+ description,
+ nsProductName,
+ nsNickName,
+ nsProductVersion,
+ nsBuildNumber,
+ nsRevisionNumber,
+ nsSerialNumber,
+ nsInstalledLocation,
+ installationTimeStamp,
+ nsExpirationDate,
+ nsBuildSecurity,
+ nsLdapSchemaVersion,
+ nsServerMigrationClassname,
+ nsServerCreationClassname
+
+objectclass nsEncryptionConfig
+ superior top
+ requires
+ cn
+ allows
+ nsCertfile,
+ nsKeyfile,
+ nsSSL2,
+ nsSSL3,
+ nsSSLSessionTimeout,
+ nsSSL3SessionTimeout,
+ nsSSLClientAuth,
+ nsSSL2Ciphers,
+ nsSSL3Ciphers
+
+objectclass nsEncryptionModule
+ superior top
+ requires
+ cn
+ allows
+ nsSSLToken,
+ nsSSLPersonalityssl,
+ nsSSLActivation
+
+
+objectclass nsResourceRef
+ superior top
+ requires
+ cn
+ allows
+ seeAlso
+
+objectclass nsTask
+ superior top
+ requires
+ cn
+ allows
+ nsTaskLabel,
+ nsHelpref,
+ nsExecref,
+ nsLogSuppress
+
+objectclass nsTaskGroup
+ superior top
+ requires
+ cn
+ allows
+ nsTaskLabel
+
+objectclass nsAdminObject
+ superior top
+ requires
+ cn
+ allows
+ nsJarFilename,
+ nsClassName
+
+objectclass nsConfig
+ superior top
+ requires
+ cn
+ allows
+ description,
+ nsServerPort,
+ nsServerAddress,
+ nsSuiteSpotUser,
+ nsErrorLog,
+ nsPidLog,
+ nsAccessLog,
+ nsDefaultAcceptLanguage,
+ nsServerSecurity
+
+objectclass nsDirectoryInfo
+ superior top
+ requires
+ cn
+ allows
+ nsBindDN,
+ nsBindPassword,
+ nsDirectoryURL,
+ nsDirectoryFailoverList,
+ nsDirectoryInfoRef
diff --git a/ldap/cm/v4confs/411/ns-compass-globopt.conf b/ldap/cm/v4confs/411/ns-compass-globopt.conf
new file mode 100644
index 00000000..4d2e1e21
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-compass-globopt.conf
@@ -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
+#
+# Used by Netscape Directory Server
+index pipuid pres,eq,sub
+index pipstatus eq
+
diff --git a/ldap/cm/v4confs/411/ns-compass-schema.conf b/ldap/cm/v4confs/411/ns-compass-schema.conf
new file mode 100644
index 00000000..be13bc44
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-compass-schema.conf
@@ -0,0 +1,173 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+
+# Compass server specific (not currently used)
+
+objectclass netscapeCompassServer
+ oid 2.16.840.1.113730.3.2.19
+ requires
+ objectclass
+
+
+# Attributes for personal interest profile classes
+
+attribute pipuid 2.16.840.1.113730.3.1.137 cis
+attribute pipcompassservers 2.16.840.1.113730.3.1.138 cis
+attribute pipuniqueid 2.16.840.1.113730.3.1.139 cis
+attribute pipstatus 2.16.840.1.113730.3.1.140 cis
+attribute pipusertype 2.16.840.1.113730.3.1.141 cis
+attribute pipfrequency 2.16.840.1.113730.3.1.142 cis
+attribute pipmedium 2.16.840.1.113730.3.1.143 cis
+attribute pipformat 2.16.840.1.113730.3.1.144 cis
+attribute piphour 2.16.840.1.113730.3.1.145 cis
+attribute pipmaxhits 2.16.840.1.113730.3.1.146 cis
+attribute pipresultset 2.16.840.1.113730.3.1.147 cis
+attribute pipsortorder 2.16.840.1.113730.3.1.148 cis
+attribute piptimestamp 2.16.840.1.113730.3.1.149 cis
+attribute pipirlist 2.16.840.1.113730.3.1.150 cis
+attribute pipiroption 2.16.840.1.113730.3.1.151 cis
+attribute pippwp 2.16.840.1.113730.3.1.152 cis
+attribute piplastcount 2.16.840.1.113730.3.1.153 cis
+attribute piptotalcount 2.16.840.1.113730.3.1.154 cis
+attribute piptotalrun 2.16.840.1.113730.3.1.155 cis
+attribute pipnotify 2.16.840.1.113730.3.1.156 cis
+attribute pipprivilege 2.16.840.1.113730.3.1.157 cis
+attribute pipgroup 2.16.840.1.113730.3.1.158 cis
+attribute pipidstcount 2.16.840.1.113730.3.1.159 cis
+attribute pipstid 2.16.840.1.113730.3.1.160 cis
+attribute pipstname 2.16.840.1.113730.3.1.161 cis
+attribute pipstquery 2.16.840.1.113730.3.1.162 cis
+attribute pipsttaxonomy 2.16.840.1.113730.3.1.163 cis
+attribute pipstinterest 2.16.840.1.113730.3.1.164 cis
+attribute pipsttype 2.16.840.1.113730.3.1.165 cis
+attribute pipstprivacy 2.16.840.1.113730.3.1.166 cis
+attribute pipststatus 2.16.840.1.113730.3.1.167 cis
+attribute pipstlastcount 2.16.840.1.113730.3.1.168 cis
+attribute pipsttotalcount 2.16.840.1.113730.3.1.169 cis
+attribute pipsttotalrun 2.16.840.1.113730.3.1.170 cis
+attribute pipstcategory 2.16.840.1.113730.3.1.171 cis
+attribute pipstfrequency 2.16.840.1.113730.3.1.172 cis
+attribute pipstmedium 2.16.840.1.113730.3.1.173 cis
+attribute pipstformat 2.16.840.1.113730.3.1.174 cis
+attribute pipsthour 2.16.840.1.113730.3.1.175 cis
+attribute pipstmaxhits 2.16.840.1.113730.3.1.176 cis
+attribute pipstresultset 2.16.840.1.113730.3.1.177 cis
+attribute pipstsortorder 2.16.840.1.113730.3.1.178 cis
+attribute pipsttimestamp 2.16.840.1.113730.3.1.179 cis
+attribute pipstirlist 2.16.840.1.113730.3.1.180 cis
+attribute pipstiroption 2.16.840.1.113730.3.1.181 cis
+attribute pipreservedcis1 2.16.840.1.113730.3.1.182 cis
+attribute pipreservedcis2 2.16.840.1.113730.3.1.183 cis
+attribute pipreservedcis3 2.16.840.1.113730.3.1.184 cis
+attribute pipreservedcis4 2.16.840.1.113730.3.1.185 cis
+attribute pipreservedcis5 2.16.840.1.113730.3.1.186 cis
+attribute pipreservedcis6 2.16.840.1.113730.3.1.187 cis
+attribute pipreservedces1 2.16.840.1.113730.3.1.188 ces
+attribute pipreservedces2 2.16.840.1.113730.3.1.189 ces
+attribute pipreservedces3 2.16.840.1.113730.3.1.190 ces
+
+
+# Each interest profile is one of these and sits under the compass SIE
+
+objectclass personalInterestProfile
+ oid 2.16.840.1.113730.3.2.20
+ requires
+ objectclass,
+ pipuid
+ allows
+ pipuniqueid,
+ pipstatus,
+ pipusertype,
+ pipfrequency,
+ pipmedium,
+ pipformat,
+ piphour,
+ pipmaxhits,
+ pipresultset,
+ pipsortorder,
+ piptimestamp,
+ pipirlist,
+ pipiroption,
+ pippwp,
+ piplastcount,
+ piptotalcount,
+ piptotalrun,
+ pipnotify,
+ pipprivilege,
+ pipgroup,
+ pipidstcount,
+ pipstid,
+ pipstname,
+ pipstquery,
+ pipsttaxonomy,
+ pipstinterest,
+ pipsttype,
+ pipstprivacy,
+ pipststatus,
+ pipstlastcount,
+ pipsttotalcount,
+ pipsttotalrun,
+ pipstcategory,
+ pipstfrequency,
+ pipstmedium,
+ pipstformat,
+ pipsthour,
+ pipstmaxhits,
+ pipstresultset,
+ pipstsortorder,
+ pipsttimestamp,
+ pipstirlist,
+ pipstiroption,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
+
+# Replication of user info for template users, completeness, etc.
+# (not currently used)
+
+objectclass PIPUserInfo
+ oid 2.16.840.1.113730.3.2.21
+ requires
+ objectclass
+ allows
+ cn,
+ mail,
+ userPassword,
+ description,
+ pipcompassservers,
+ pipuniqueid
+
+
+# Enhancements to a normal user entry (not currently used)
+
+objectclass PIPUser
+ oid 2.16.840.1.113730.3.2.22
+ requires
+ objectclass
+ allows
+ pipuniqueid,
+ pipcompassservers,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
diff --git a/ldap/cm/v4confs/411/ns-cos-schema.conf b/ldap/cm/v4confs/411/ns-cos-schema.conf
new file mode 100644
index 00000000..3d0f9f1a
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-cos-schema.conf
@@ -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
+#
+# Attributes used by Class of Service
+
+attribute cosAttribute 2.16.840.1.113730.3.1.550 cis
+attribute cosSpecifier 2.16.840.1.113730.3.1.551 cis
+attribute cosTargetTree 2.16.840.1.113730.3.1.552 cis
+attribute cosTemplateDn 2.16.840.1.113730.3.1.553 cis
+
+# Object classes used by Class of Service
+
+objectclass cosDefinition
+ oid 2.16.840.1.113730.3.2.84
+ superior top
+ requires
+ objectclass
+ allows
+ aci,
+ cn,
+ uid,
+ costargettree,
+ costemplatedn,
+ cosspecifier,
+ cosattribute
diff --git a/ldap/cm/v4confs/411/ns-delegated-admin-schema.conf b/ldap/cm/v4confs/411/ns-delegated-admin-schema.conf
new file mode 100644
index 00000000..773d7069
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-delegated-admin-schema.conf
@@ -0,0 +1,97 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Netscape Delegated Administrator LDAP Schema
+#
+#############################################################
+# Delegated User Administration Attributes
+#############################################################
+
+attribute nsNumUsers 2.16.840.1.113730.3.1.554 cis single
+attribute nsMaxUsers 2.16.840.1.113730.3.1.555 cis single
+attribute nsNumDepts 2.16.840.1.113730.3.1.556 cis single
+attribute nsMaxDepts 2.16.840.1.113730.3.1.557 cis single
+attribute nsNumMailLists 2.16.840.1.113730.3.1.558 cis single
+attribute nsMaxMailLists 2.16.840.1.113730.3.1.559 cis single
+attribute nsNumDomains 2.16.840.1.113730.3.1.560 cis single
+attribute nsMaxDomains 2.16.840.1.113730.3.1.561 cis single
+attribute nsDefaultMaxDeptSize 2.16.840.1.113730.3.1.562 cis single
+attribute nsdaCapability 2.16.840.1.113730.3.1.563 cis
+attribute nsSearchFilter 2.16.840.1.113730.3.1.564 cis single
+attribute nsdaModifiableBy 2.16.840.1.113730.3.1.565 dn
+
+#############################################################
+# Delegated User Administration Objectclasses
+#############################################################
+
+objectclass nsManagedISP
+ oid 2.16.840.1.113730.3.2.85
+ superior top
+ allows
+ nsNumDomains
+
+objectclass nsManagedDomain
+ oid 2.16.840.1.113730.3.2.86
+ superior top
+ allows
+ nsNumUsers,
+ nsMaxUsers,
+ nsNumDepts,
+ nsMaxDepts,
+ nsNumMailLists,
+ nsMaxMailLists,
+ nsNumDomains,
+ nsMaxDomains,
+ nsDefaultMaxDeptSize,
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedOrgUnit
+ oid 2.16.840.1.113730.3.2.87
+ superior top
+ allows
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedDept
+ oid 2.16.840.1.113730.3.2.88
+ superior groupOfUniqueNames
+ allows
+ nsNumUsers,
+ nsMaxUsers,
+ nsNumDepts,
+ nsMaxDepts,
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedFamilyGroup
+ oid 2.16.840.1.113730.3.2.89
+ superior top
+ allows
+ nsNumUsers,
+ nsMaxUsers,
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedMailList
+ oid 2.16.840.1.113730.3.2.90
+ superior top
+ allows
+ nsNumUsers,
+ nsMaxUsers,
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedPerson
+ oid 2.16.840.1.113730.3.2.91
+ superior top
+ allows
+ nsdaCapability,
+ nsSearchFilter,
+ owner,
+ nsdaModifiableBy
diff --git a/ldap/cm/v4confs/411/ns-directory-globopt.conf b/ldap/cm/v4confs/411/ns-directory-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-directory-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/411/ns-directory-schema.conf b/ldap/cm/v4confs/411/ns-directory-schema.conf
new file mode 100644
index 00000000..d928081f
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-directory-schema.conf
@@ -0,0 +1,27 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsSecureServerPort cis
+
+objectclass netscapeDirectoryServer
+ oid 2.16.840.1.113730.3.2.23
+ requires
+ objectclass
+
+objectclass nsDirectoryServer
+ requires
+ objectclass,
+ nsServerID
+ allows
+ serverHostName,
+ nsServerPort,
+ nsSecureServerPort,
+ nsBindPassword,
+ nsBindDN,
+ nsBaseDN
diff --git a/ldap/cm/v4confs/411/ns-legacy-schema.conf b/ldap/cm/v4confs/411/ns-legacy-schema.conf
new file mode 100644
index 00000000..4f7c4ac4
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-legacy-schema.conf
@@ -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
+#
+attribute url cis
+
+#use by Netscape Admin Server 4.1 for LegacyServers
+
+objectclass nsLegacyAdminGroup
+ superior
+ nsAdminGroup
+ allows
+ adminUrl
+
+objectclass nsLegacyApplication
+ superior
+ nsApplication
+ allows
+
+objectclass nsLegacyAdminServer
+ superior
+ nsAdminServer
+ allows
+
+objectclass nsLegacyServer
+ superior
+ netscapeServer
+ allows
+ nsServerID,
+ url
diff --git a/ldap/cm/v4confs/411/ns-mail-globopt.conf b/ldap/cm/v4confs/411/ns-mail-globopt.conf
new file mode 100644
index 00000000..2e6cac65
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-mail-globopt.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Messaging Server
+index mailAlternateAddress eq
+index mailHost eq
+#index uid,mail eq
+#index uniquemember,member eq
diff --git a/ldap/cm/v4confs/411/ns-mail-schema.conf b/ldap/cm/v4confs/411/ns-mail-schema.conf
new file mode 100644
index 00000000..ca0fdc5d
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-mail-schema.conf
@@ -0,0 +1,144 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+attribute mailAccessDomain 2.16.840.1.113730.3.1.12 cis
+attribute mailAlternateAddress 2.16.840.1.113730.3.1.13 cis
+attribute mailAutoReplyMode 2.16.840.1.113730.3.1.14 cis
+attribute mailAutoReplyText 2.16.840.1.113730.3.1.15 cis
+attribute mailDeliveryOption 2.16.840.1.113730.3.1.16 cis
+attribute mailForwardingAddress 2.16.840.1.113730.3.1.17 cis
+attribute mailHost 2.16.840.1.113730.3.1.18 cis
+attribute mailQuota 2.16.840.1.113730.3.1.21 cis
+attribute mailRoutingAddress 2.16.840.1.113730.3.1.47 cis
+
+attribute mailMessageStore 2.16.840.1.113730.3.1.19 ces
+attribute mailProgramDeliveryInfo 2.16.840.1.113730.3.1.20 ces
+
+attribute nsmsgDisallowAccess ces
+
+attribute vacationstartdate cis
+attribute vacationenddate cis
+
+# mailRecipient is used to designate an LDAP entry as representing some
+# entity that can receive mail, e.g. a mail user or mail group.
+# Note: attributes 'mailAccessDomain' through 'userPassword' do not
+# belong to mailRecipient, but are included here for backward compatibility.
+objectClass mailRecipient
+ oid 2.16.840.1.113730.3.2.3
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mailAccessDomain,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota,
+ multiLineDescription,
+ uid,
+ userPassword
+
+attribute nswmExtendedUserPrefs 2.16.840.1.113730.3.1.520 cis
+
+# nsMessagingServerUser is used to designate an LDAP entry as representing a
+# Netscape Messaging Server user account. It is used in combination with
+# mailRecipient.
+objectClass nsMessagingServerUser
+ oid 2.16.840.113730.3.2.37
+ requires
+ objectClass
+ allows
+ cn,
+ mailAccessDomain,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota,
+ nsmsgDisallowAccess,
+ nswmExtendedUserPrefs,
+ vacationstartdate,
+ vacationenddate
+
+attribute mgrpAllowedDomain 2.16.840.1.113730.3.1.23 cis
+attribute mgrpMsgRejectAction 2.16.840.1.113730.3.1.28 cis
+attribute mgrpRFC822MailMember 2.16.840.1.113730.3.1.30 cis
+attribute mgrpMsgMaxSize 2.16.840.1.113730.3.1.32 cis single
+attribute mgrpBroadcasterPolicy cis
+attribute mgrpNoDuplicateChecks cis single
+attribute mgrpRemoveHeader cis
+
+attribute mgrpAllowedBroadcaster 2.16.840.1.113730.3.1.22 ces
+attribute mgrpDeliverTo 2.16.840.1.113730.3.1.25 ces
+attribute mgrpErrorsTo 2.16.840.1.113730.3.1.26 ces single
+attribute mgrpModerator 2.16.840.1.113730.3.1.33 ces
+attribute mgrpMsgRejectText 2.16.840.1.113730.3.1.29 ces
+attribute mgrpAddHeader ces
+
+attribute mgrpApprovePassword ces single
+
+# mailGroup is used to designate an LDAP entry as representing a mail group
+# (mailing list). It is used in combination with mailRecipient.
+# Note: attributes 'mail' through 'mailRoutingAddress' belong to mailRecipient,
+# but are also included here for backward compatibility.
+objectClass mailGroup
+ oid 2.16.840.1.113730.3.2.4
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mgrpAddHeader,
+ mgrpAllowedBroadcaster,
+ mgrpAllowedDomain,
+ mgrpApprovePassword,
+ mgrpBroadcasterPolicy,
+ mgrpDeliverTo,
+ mgrpErrorsTo,
+ mgrpModerator,
+ mgrpMsgMaxSize,
+ mgrpMsgRejectAction,
+ mgrpMsgRejectText,
+ mgrpNoDuplicateChecks,
+ mgrpRemoveHeader,
+ mgrpRFC822MailMember,
+ owner
+
+attribute mailEnhancedUniqueMember 2.16.840.1.113730.3.1.31 dn
+
+objectClass groupOfMailEnhancedUniqueNames
+ oid 2.16.840.1.113730.3.2.5
+ requires
+ objectClass,
+ cn
+ allows
+ businessCategory,
+ description,
+ mailEnhancedUniqueMember,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectClass netscapeMailServer
+ oid 2.16.840.1.113730.3.2.24
+ requires
+ objectClass
+
diff --git a/ldap/cm/v4confs/411/ns-mcd-browser-schema.conf b/ldap/cm/v4confs/411/ns-mcd-browser-schema.conf
new file mode 100644
index 00000000..dd2e228f
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-mcd-browser-schema.conf
@@ -0,0 +1,179 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-browser-schema.conf
+#
+# Netscape Mission Control Desktop browser client schema
+# This schema is used to hold browser client preferences.
+#
+
+attribute nsBCStartupBrowser 2.16.840.1.113730.3.1.409 cis
+attribute nsBCStartupMail 2.16.840.1.113730.3.1.410 cis
+attribute nsBCStartupEditor 2.16.840.1.113730.3.1.411 cis
+attribute nsBCStartupCalendar 2.16.840.1.113730.3.1.412 cis
+attribute nsBCChromeButtonStyle 2.16.840.1.113730.3.1.413 cis
+attribute nsBCUseDocumentFonts 2.16.840.1.113730.3.1.414 cis
+attribute nsBCForegroundColor 2.16.840.1.113730.3.1.415 cis
+attribute nsBCBackgroundColor 2.16.840.1.113730.3.1.416 cis
+attribute nsBCAnchorColor 2.16.840.1.113730.3.1.417 cis
+attribute nsBCVisitedColor 2.16.840.1.113730.3.1.418 cis
+attribute nsBCUnderlineAnchors 2.16.840.1.113730.3.1.419 cis
+attribute nsBCUseDocumentColors 2.16.840.1.113730.3.1.420 cis
+attribute nsBCStartupPage 2.16.840.1.113730.3.1.421 cis
+attribute nsBCStartupHomePage 2.16.840.1.113730.3.1.422 cis
+attribute nsBCLinkExpiration 2.16.840.1.113730.3.1.423 cis
+attribute nsBCIntlAcceptLanguages 2.16.840.1.113730.3.1.424 cis
+attribute nsBCMimeType 2.16.840.1.113730.3.1.425 cis
+attribute nsBCMimeAllowAdd 2.16.840.1.113730.3.1.426 cis
+attribute nsBCMimeAllowEdit 2.16.840.1.113730.3.1.427 cis
+attribute nsBCMimeAllowRemove 2.16.840.1.113730.3.1.428 cis
+attribute nsBCRelatedEnabled 2.16.840.1.113730.3.1.429 cis
+attribute nsBCRelatedAutoload 2.16.840.1.113730.3.1.430 cis
+attribute nsBCRelatedDisabledForDomains 2.16.840.1.113730.3.1.431 cis
+attribute nsBCGoBrowsingEnabled 2.16.840.1.113730.3.1.432 cis
+attribute nsBCOfflineStartupState 2.16.840.1.113730.3.1.433 cis
+attribute nsBCOfflineSendUnsentMessages 2.16.840.1.113730.3.1.434 cis
+attribute nsBCOfflinePromptSynchOnExit 2.16.840.1.113730.3.1.435 cis
+attribute nsBCAlwaysLoadImages 2.16.840.1.113730.3.1.436 cis
+attribute nsBCEnableJava 2.16.840.1.113730.3.1.437 cis
+attribute nsBCEnableJavaScript 2.16.840.1.113730.3.1.438 cis
+attribute nsBCEnableStyleSheets 2.16.840.1.113730.3.1.439 cis
+attribute nsBCEmailAsFtpPassword 2.16.840.1.113730.3.1.440 cis
+attribute nsBCCookieBehavior 2.16.840.1.113730.3.1.441 cis
+attribute nsBCWarnAboutCookies 2.16.840.1.113730.3.1.442 cis
+attribute nsBCMemoryCacheSize 2.16.840.1.113730.3.1.443 cis
+attribute nsBCDiskCacheSize 2.16.840.1.113730.3.1.444 cis
+attribute nsBCCheckDocFrequency 2.16.840.1.113730.3.1.445 cis
+attribute nsBCProxyType 2.16.840.1.113730.3.1.446 cis
+attribute nsBCProxyHttp 2.16.840.1.113730.3.1.447 cis
+attribute nsBCProxySsl 2.16.840.1.113730.3.1.448 cis
+attribute nsBCProxyFtp 2.16.840.1.113730.3.1.449 cis
+attribute nsBCProxySocks 2.16.840.1.113730.3.1.450 cis
+attribute nsBCProxyGopher 2.16.840.1.113730.3.1.451 cis
+attribute nsBCProxyWais 2.16.840.1.113730.3.1.452 cis
+attribute nsBCNoProxiesOn 2.16.840.1.113730.3.1.453 cis
+attribute nsBCProxyAutoConfigUrl 2.16.840.1.113730.3.1.454 cis
+attribute nsBCAutoUpdateEnabled 2.16.840.1.113730.3.1.455 cis
+attribute nsBCAutoUpdateConfirmInstall 2.16.840.1.113730.3.1.456 cis
+
+
+objectclass nsBrowserClient
+ oid 2.16.840.1.113730.3.2.78
+ superior top
+ allows
+ nsBCStartupBrowser,
+ nsBCStartupMail,
+ nsBCStartupEditor,
+ nsBCStartupCalendar,
+ nsBCChromeButtonStyle,
+ nsBCUseDocumentFonts,
+ nsBCForegroundColor,
+ nsBCBackgroundColor,
+ nsBCAnchorColor,
+ nsBCVisitedColor,
+ nsBCUnderlineAnchors,
+ nsBCUseDocumentColors,
+ nsBCStartupPage,
+ nsBCStartupHomePage,
+ nsBCLinkExpiration,
+ nsBCIntlAcceptLanguages,
+ nsBCMimeType,
+ nsBCMimeAllowAdd,
+ nsBCMimeAllowEdit,
+ nsBCMimeAllowRemove,
+ nsBCRelatedEnabled,
+ nsBCRelatedAutoload,
+ nsBCRelatedDisabledForDomains,
+ nsBCGoBrowsingEnabled,
+ nsBCOfflineStartupState,
+ nsBCOfflineSendUnsentMessages,
+ nsBCOfflinePromptSynchOnExit,
+ nsBCAlwaysLoadImages,
+ nsBCEnableJava,
+ nsBCEnableJavaScript,
+ nsBCEnableStyleSheets,
+ nsBCEmailAsFtpPassword,
+ nsBCCookieBehavior,
+ nsBCWarnAboutCookies,
+ nsBCMemoryCacheSize,
+ nsBCDiskCacheSize,
+ nsBCCheckDocFrequency,
+ nsBCProxyType,
+ nsBCProxyHttp,
+ nsBCProxySsl,
+ nsBCProxyFtp,
+ nsBCProxySocks,
+ nsBCProxyGopher,
+ nsBCProxyWais,
+ nsBCNoProxiesOn,
+ nsBCProxyAutoConfigUrl,
+ nsBCAutoUpdateEnabled,
+ nsBCAutoUpdateConfirmInstall
+
+#
+# Netscape Mission Control Desktop browser security schema
+# This schema is used to hold browser security preferences.
+#
+
+attribute nsBSAskForPassword 2.16.840.1.113730.3.1.457 cis
+attribute nsBSPasswordLifetime 2.16.840.1.113730.3.1.458 cis
+attribute nsBSWarnEnteringSecure 2.16.840.1.113730.3.1.459 cis
+attribute nsBSWarnLeavingSecure 2.16.840.1.113730.3.1.460 cis
+attribute nsBSWarnViewingMixed 2.16.840.1.113730.3.1.461 cis
+attribute nsBSWarnSubmitInsecure 2.16.840.1.113730.3.1.462 cis
+attribute nsBSEnableSsl2 2.16.840.1.113730.3.1.463 cis
+attribute nsBSEnableSsl3 2.16.840.1.113730.3.1.464 cis
+attribute nsBSCertmgmtDisableFunctionMsg 2.16.840.1.113730.3.1.465 cis
+attribute nsBSSsl2Rc4128 2.16.840.1.113730.3.1.466 cis
+attribute nsBSSsl2Rc2128 2.16.840.1.113730.3.1.467 cis
+attribute nsBSSsl2DesEd3192 2.16.840.1.113730.3.1.468 cis
+attribute nsBSSsl2Des64 2.16.840.1.113730.3.1.469 cis
+attribute nsBSSsl2Rc440 2.16.840.1.113730.3.1.470 cis
+attribute nsBSSsl2Rc240 2.16.840.1.113730.3.1.471 cis
+attribute nsBSSsl3RsaRc4128Md5 2.16.840.1.113730.3.1.472 cis
+attribute nsBSSsl3FipsDesEd3Sha 2.16.840.1.113730.3.1.473 cis
+attribute nsBSSsl3RsaRc4128Md5 2.16.840.1.113730.3.1.474 cis
+attribute nsBSSsl3RsaFipsDesSha 2.16.840.1.113730.3.1.475 cis
+attribute nsBSSsl3RsaDesSha 2.16.840.1.113730.3.1.476 cis
+attribute nsBSSsl3RsaRc440Md5 2.16.840.1.113730.3.1.477 cis
+attribute nsBSSsl3RsaRc240Md5 2.16.840.1.113730.3.1.478 cis
+attribute nsBSSsl3RsaNullMd5 2.16.840.1.113730.3.1.479 cis
+attribute nsBSSsl3FortezzaFortezzaSha 2.16.840.1.113730.3.1.480 cis
+attribute nsBSSsl3FortezzaRc4Sha 2.16.840.1.113730.3.1.481 cis
+
+
+objectclass nsBrowserSecurity
+ oid 2.16.840.1.113730.3.2.79
+ superior top
+ allows
+ nsBSAskForPassword,
+ nsBSPasswordLifetime,
+ nsBSWarnEnteringSecure,
+ nsBSWarnLeavingSecure,
+ nsBSWarnViewingMixed,
+ nsBSWarnSubmitInsecure,
+ nsBSEnableSsl2,
+ nsBSEnableSsl3,
+ nsBSCertmgmtDisableFunctionMsg,
+ nsBSSsl2Rc4128,
+ nsBSSsl2Rc2128,
+ nsBSSsl2DesEd3192,
+ nsBSSsl2Des64,
+ nsBSSsl2Rc440,
+ nsBSSsl2Rc240,
+ nsBSSsl3RsaRc4128Md5,
+ nsBSSsl3FipsDesEd3Sha,
+ nsBSSsl3RsaRc4128Md5,
+ nsBSSsl3RsaFipsDesSha,
+ nsBSSsl3RsaDesSha,
+ nsBSSsl3RsaRc440Md5,
+ nsBSSsl3RsaRc240Md5,
+ nsBSSsl3RsaNullMd5,
+ nsBSSsl3FortezzaFortezzaSha,
+ nsBSSsl3FortezzaRc4Sha
+
diff --git a/ldap/cm/v4confs/411/ns-mcd-config-schema.conf b/ldap/cm/v4confs/411/ns-mcd-config-schema.conf
new file mode 100644
index 00000000..7076bbc7
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-mcd-config-schema.conf
@@ -0,0 +1,55 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-config-schema.conf
+#
+# Netscape Mission Control Desktop schema
+# This schema is used to set MCD "config()" preferences.
+#
+
+attribute nsMcdUserAgent 2.16.840.1.113730.3.1.482 cis
+attribute nsMcdUseXSender 2.16.840.1.113730.3.1.483 cis
+attribute nsMcdToolbarLogoUrl 2.16.840.1.113730.3.1.484 cis
+attribute nsMcdToolbarLogoWinSmallFile 2.16.840.1.113730.3.1.485 cis
+attribute nsMcdToolbarLogoWinLargeFile 2.16.840.1.113730.3.1.486 cis
+attribute nsMcdToolbarLogoFrames 2.16.840.1.113730.3.1.487 cis
+attribute nsMcdMacAnimationFile 2.16.840.1.113730.3.1.488 cis
+attribute nsMcdXAnimationFile 2.16.840.1.113730.3.1.489 cis
+attribute nsMcdNetSearchUrl 2.16.840.1.113730.3.1.490 cis
+attribute nsMcdMoreInfoPluginUrl 2.16.840.1.113730.3.1.491 cis
+attribute nsMcdAutoAdminConfigUrl 2.16.840.1.113730.3.1.492 cis
+attribute nsMcdAutoAdminAppendEmail 2.16.840.1.113730.3.1.493 cis
+attribute nsMcdAutoAdminRefreshInterval 2.16.840.1.113730.3.1.494 cis
+attribute nsMcdUseGuideButton 2.16.840.1.113730.3.1.495 cis
+attribute nsMcdGuideButtonProperties 2.16.840.1.113730.3.1.496 cis
+attribute nsMcdGuideMenuProperties 2.16.840.1.113730.3.1.497 cis
+attribute nsMcdHelpMenuProperties 2.16.840.1.113730.3.1.498 cis
+
+
+objectclass nsMcdConfig
+ oid 2.16.840.1.113730.3.2.80
+ superior top
+ allows
+ nsMcdUserAgent,
+ nsMcdUseXSender,
+ nsMcdToolbarLogoUrl,
+ nsMcdToolbarLogoWinSmallFile,
+ nsMcdToolbarLogoWinLargeFile,
+ nsMcdToolbarLogoFrames,
+ nsMcdMacAnimationFile,
+ nsMcdXAnimationFile,
+ nsMcdNetSearchUrl,
+ nsMcdMoreInfoPluginUrl,
+ nsMcdAutoAdminConfigUrl,
+ nsMcdAutoAdminAppendEmail,
+ nsMcdAutoAdminRefreshInterval,
+ nsMcdUseGuideButton,
+ nsMcdGuideButtonProperties,
+ nsMcdGuideMenuProperties,
+ nsMcdHelpMenuProperties
+
diff --git a/ldap/cm/v4confs/411/ns-mcd-li-globopt.conf b/ldap/cm/v4confs/411/ns-mcd-li-globopt.conf
new file mode 100644
index 00000000..57a75555
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-mcd-li-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Index required by Mission Control Desktop: Location Independence
+index nsLIProfileName eq
diff --git a/ldap/cm/v4confs/411/ns-mcd-li-schema.conf b/ldap/cm/v4confs/411/ns-mcd-li-schema.conf
new file mode 100644
index 00000000..272d90e2
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-mcd-li-schema.conf
@@ -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
+#
+#
+# ns-mcd-li-schema.conf
+#
+# Netscape Mission Control Desktop Location Independence schema
+#
+
+attribute nsLIPtrURL 2.16.840.1.113730.3.1.399 ces
+attribute nsLIPrefs 2.16.840.1.113730.3.1.400 ces
+attribute nsLIProfileName 2.16.840.1.113730.3.1.401 cis
+attribute nsLIData 2.16.840.1.113730.3.1.402 bin
+attribute nsLIElementType 2.16.840.1.113730.3.1.403 cis
+attribute nsLIServerType 2.16.840.1.113730.3.1.404 cis
+attribute nsLIVersion 2.16.840.1.113730.3.1.405 int
+
+objectclass nsLIPtr
+ oid 2.16.840.1.113730.3.2.74
+ requires
+ objectclass
+ allows
+ nsliptrurl,
+ owner
+
+objectclass nsLIProfile
+ oid 2.16.840.1.113730.3.2.75
+ requires
+ objectclass,
+ nsliprofilename
+ allows
+ nsliprefs,
+ uid,
+ owner
+
+objectclass nsLIProfileElement
+ oid 2.16.840.1.113730.3.2.76
+ requires
+ objectclass,
+ nslielementtype
+ allows
+ owner,
+ nslidata,
+ nsliversion
+
+objectclass nsLIServer
+ oid 2.16.840.1.113730.3.2.77
+ requires
+ objectclass,
+ serverhostname
+ allows
+ description,
+ cn,
+ nsserverport,
+ nsliservertype,
+ serverroot
diff --git a/ldap/cm/v4confs/411/ns-mcd-mail-schema.conf b/ldap/cm/v4confs/411/ns-mcd-mail-schema.conf
new file mode 100644
index 00000000..12d42c0b
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-mcd-mail-schema.conf
@@ -0,0 +1,219 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-mail-schema.conf
+#
+# Netscape Mission Control Desktop mail client schema
+# This schema is used to hold mail client preferences.
+#
+
+attribute nsMCHTMLCompose 2.16.840.1.113730.3.1.331 cis
+attribute nsMCDefaultHTMLAction 2.16.840.1.113730.3.1.332 cis
+attribute nsMCRequestReturnReceipt 2.16.840.1.113730.3.1.333 cis
+attribute nsMCIncorporateReturnReceipt 2.16.840.1.113730.3.1.334 cis
+attribute nsMCMDNReportEnabled 2.16.840.1.113730.3.1.335 cis
+attribute nsMCMDNReportNotInToCC 2.16.840.1.113730.3.1.336 cis
+attribute nsMCMDNReportOutsideDomain 2.16.840.1.113730.3.1.337 cis
+attribute nsMCMDNReportOther 2.16.840.1.113730.3.1.338 cis
+attribute nsMCForwardMessageMode 2.16.840.1.113730.3.1.339 cis
+attribute nsMCAutoQuote 2.16.840.1.113730.3.1.340 cis
+attribute nsMCReplyOnTop 2.16.840.1.113730.3.1.341 cis
+attribute nsMCSpellCheckBeforeSend 2.16.840.1.113730.3.1.342 cis
+attribute nsMCWrapLongLines 2.16.840.1.113730.3.1.343 cis
+attribute nsMCWrapLength 2.16.840.1.113730.3.1.344 cis
+attribute nsMCStrictlyMime 2.16.840.1.113730.3.1.345 cis
+attribute nsMCAutoCompleteUseAddressBooks 2.16.840.1.113730.3.1.346 cis
+attribute nsMCAutoCompleteUseDirectory 2.16.840.1.113730.3.1.347 cis
+attribute nsMCAutoCompleteEnabledServerName 2.16.840.1.113730.3.1.348 cis
+attribute nsMCAutoCompleteShowDlgForMultipleMatches 2.16.840.1.113730.3.1.349 cis
+attribute nsMCSkipDirectoryIfLocalMatchFound 2.16.840.1.113730.3.1.350 cis
+attribute nsMCAddrBookLastnameFirst 2.16.840.1.113730.3.1.351 cis
+attribute nsMCLimitMessageSize 2.16.840.1.113730.3.1.352 cis
+attribute nsMCMaxMessageSize 2.16.840.1.113730.3.1.353 cis
+attribute nsMCPromptPurgeThreshold 2.16.840.1.113730.3.1.354 cis
+attribute nsMCPurgeThreshold 2.16.840.1.113730.3.1.355 cis
+attribute nsMCNewsKeepMethod 2.16.840.1.113730.3.1.356 cis
+attribute nsMCNewsKeepDays 2.16.840.1.113730.3.1.357 cis
+attribute nsMCNewsKeepCount 2.16.840.1.113730.3.1.358 cis
+attribute nsMCNewsKeepOnlyUnread 2.16.840.1.113730.3.1.359 cis
+attribute nsMCNewsRemoveBodiesByAge 2.16.840.1.113730.3.1.360 cis
+attribute nsMCNewsRemoveBodiesDays 2.16.840.1.113730.3.1.361 cis
+attribute nsMCSmtpServer 2.16.840.1.113730.3.1.362 cis
+attribute nsMCSmtpUserName 2.16.840.1.113730.3.1.363 cis
+attribute nsMCSmtpUseSSL 2.16.840.1.113730.3.1.364 cis
+attribute nsMCImapServer 2.16.840.1.113730.3.1.365 cis
+attribute nsMCImapServerProperties 2.16.840.1.113730.3.1.366 cis
+attribute nsMCPopServer 2.16.840.1.113730.3.1.367 cis
+attribute nsMCPopServerProperties 2.16.840.1.113730.3.1.368 cis
+attribute nsMCLdapServer 2.16.840.1.113730.3.1.369 cis
+attribute nsMCLdapServerProperties 2.16.840.1.113730.3.1.370 cis
+attribute nsMCQuotedStyle 2.16.840.1.113730.3.1.371 cis
+attribute nsMCQuotedSize 2.16.840.1.113730.3.1.372 cis
+attribute nsMCCitationColor 2.16.840.1.113730.3.1.373 cis
+attribute nsMCFixedWidthMessages 2.16.840.1.113730.3.1.374 cis
+attribute nsMCPlaySound 2.16.840.1.113730.3.1.375 cis
+attribute nsMCRememberSelectedMessage 2.16.840.1.113730.3.1.376 cis
+attribute nsMCReuseMessageWindow 2.16.840.1.113730.3.1.377 cis
+attribute nsMCConfirmMoveFoldersToTrash 2.16.840.1.113730.3.1.378 cis
+attribute nsMCUseMapiServer 2.16.840.1.113730.3.1.379 cis
+attribute nsMCNewsTimeout 2.16.840.1.113730.3.1.380 cis
+attribute nsMCNavCrossesFolders 2.16.840.1.113730.3.1.381 cis
+attribute nsMCSearchServer 2.16.840.1.113730.3.1.382 cis
+attribute nsMCSearchSubFolders 2.16.840.1.113730.3.1.383 cis
+attribute nsMCEncryptOutgoingMail 2.16.840.1.113730.3.1.384 cis
+attribute nsMCCryptoSignOutgoingMail 2.16.840.1.113730.3.1.385 cis
+attribute nsMCCryptoSignOutgoingNews 2.16.840.1.113730.3.1.386 cis
+attribute nsMCWarnForwardEncrypted 2.16.840.1.113730.3.1.387 cis
+attribute nsMCWarnReplyUnencrypted 2.16.840.1.113730.3.1.388 cis
+attribute nsMCAllowAtSignInUserName 2.16.840.1.113730.3.1.389 cis
+attribute nsMCReceiptRequestHeaderType 2.16.840.1.113730.3.1.390 cis
+attribute nsMCPop3GetsNewMail 2.16.840.1.113730.3.1.391 cis
+attribute nsMCImapAutoSubscribeOnOpen 2.16.840.1.113730.3.1.392 cis
+attribute nsMCImapMimePartsOnDemand 2.16.840.1.113730.3.1.393 cis
+attribute nsMCImapMimePartsOnDemandThreshold 2.16.840.1.113730.3.1.394 cis
+attribute nsMCUseAltMail 2.16.840.1.113730.3.1.395 cis
+attribute nsMCAltMailDll 2.16.840.1.113730.3.1.396 cis
+attribute nsMCUseAltMailForNews 2.16.840.1.113730.3.1.397 cis
+attribute nsPrefMap 2.16.840.1.113730.3.1.398 cis
+attribute nsMCAuthLogin 2.16.840.1.113730.3.1.499 cis
+attribute nsMNCNavCrossesFolders 2.16.840.1.113730.3.1.500 cis
+attribute nsMNCMessageInThreadWindow 2.16.840.1.113730.3.1.501 cis
+attribute nsMCAllowAtSignInUserName 2.16.840.1.113730.3.1.502 cis
+attribute nsMCImapOnlineDraftSent 2.16.840.1.113730.3.1.503 cis
+attribute nsMCCustomHeaders 2.16.840.1.113730.3.1.504 cis
+attribute nsMCHtmlDomains 2.16.840.1.113730.3.1.505 cis
+attribute nsMNCForceAsciiSearch 2.16.840.1.113730.3.1.506 cis
+attribute nsMCAddrBookLdapDisabled 2.16.840.1.113730.3.1.507 cis
+attribute nsMNCReuseThreadWindow 2.16.840.1.113730.3.1.508 cis
+attribute nsMCShowHeaders 2.16.840.1.113730.3.1.509 cis
+attribute nsMCIdentityDefaultdomain 2.16.840.1.113730.3.1.510 cis
+
+
+
+
+objectclass nsMailClient
+ oid 2.16.840.1.113730.3.2.72
+ superior top
+ allows
+ nsMCHTMLCompose,
+ nsMCDefaultHTMLAction,
+ nsMCRequestReturnReceipt,
+ nsMCIncorporateReturnReceipt,
+ nsMCMDNReportEnabled,
+ nsMCMDNReportNotInToCC,
+ nsMCMDNReportOutsideDomain,
+ nsMCMDNReportOther,
+ nsMCForwardMessageMode,
+ nsMCAutoQuote,
+ nsMCReplyOnTop,
+ nsMCSpellCheckBeforeSend,
+ nsMCWrapLongLines,
+ nsMCWrapLength,
+ nsMCStrictlyMime,
+ nsMCAutoCompleteUseAddressBooks,
+ nsMCAutoCompleteUseDirectory,
+ nsMCAutoCompleteEnabledServerName,
+ nsMCAutoCompleteShowDlgForMultipleMatches,
+ nsMCSkipDirectoryIfLocalMatchFound,
+ nsMCAddrBookLastnameFirst,
+ nsMCLimitMessageSize,
+ nsMCMaxMessageSize,
+ nsMCPromptPurgeThreshold,
+ nsMCPurgeThreshold,
+ nsMCNewsKeepMethod,
+ nsMCNewsKeepDays,
+ nsMCNewsKeepCount,
+ nsMCNewsKeepOnlyUnread,
+ nsMCNewsRemoveBodiesByAge,
+ nsMCNewsRemoveBodiesDays,
+ nsMCSmtpServer,
+ nsMCSmtpUserName,
+ nsMCSmtpUseSSL,
+ nsMCImapServer,
+ nsMCImapServerProperties,
+ nsMCPopServer,
+ nsMCPopServerProperties,
+ nsMCLdapServer,
+ nsMCLdapServerProperties,
+ nsMCQuotedStyle,
+ nsMCQuotedSize,
+ nsMCCitationColor,
+ nsMCFixedWidthMessages,
+ nsMCPlaySound,
+ nsMCRememberSelectedMessage,
+ nsMCReuseMessageWindow,
+ nsMCConfirmMoveFoldersToTrash,
+ nsMCUseMapiServer,
+ nsMCNewsTimeout,
+ nsMCNavCrossesFolders,
+ nsMCSearchServer,
+ nsMCSearchSubFolders,
+ nsMCEncryptOutgoingMail,
+ nsMCCryptoSignOutgoingMail,
+ nsMCCryptoSignOutgoingNews,
+ nsMCWarnForwardEncrypted,
+ nsMCWarnReplyUnencrypted,
+ nsMCAllowAtSignInUserName,
+ nsMCReceiptRequestHeaderType,
+ nsMCPop3GetsNewMail,
+ nsMCImapAutoSubscribeOnOpen,
+ nsMCImapMimePartsOnDemand,
+ nsMCImapMimePartsOnDemandThreshold,
+ nsMCUseAltMail,
+ nsMCAltMailDll,
+ nsMCUseAltMailForNews,
+ nsMCAuthLogin,
+ nsMNCNavCrossesFolders,
+ nsMNCMessageInThreadWindow,
+ nsMCAllowAtSignInUserName,
+ nsMCImapOnlineDraftSent,
+ nsMCCustomHeaders,
+ nsMCHtmlDomains,
+ nsMNCForceAsciiSearch,
+ nsMCAddrBookLdapDisabled,
+ nsMNCReuseThreadWindow,
+ nsMCShowHeaders,
+ nsMCIdentityDefaultdomain
+
+
+#
+# Netscape Mission Control Desktop Messenger security schema
+# This schema is used to hold Messenger security preferences.
+#
+
+attribute nsMSEncryptOutgoingMail 2.16.840.1.113730.3.1.511 cis
+attribute nsMSSignOutgoingMail 2.16.840.1.113730.3.1.512 cis
+attribute nsMSSignOutgoingNews 2.16.840.1.113730.3.1.513 cis
+attribute nsMSSmimeDesEde3 2.16.840.1.113730.3.1.514 cis
+attribute nsMSSmimeRc2128 2.16.840.1.113730.3.1.515 cis
+attribute nsMSSmimeDes 2.16.840.1.113730.3.1.516 cis
+attribute nsMSSmimeRc264 2.16.840.1.113730.3.1.517 cis
+attribute nsMSSmimeRc240 2.16.840.1.113730.3.1.518 cis
+attribute nsMSSmimeFortezza 2.16.840.1.113730.3.1.519 cis
+
+objectclass nsMailSecurity
+ oid 2.16.840.1.113730.3.2.81
+ superior top
+ allows
+ nsMSEncryptOutgoingMail,
+ nsMSSignOutgoingMail,
+ nsMSSignOutgoingNews,
+ nsMSSmimeDesEde3,
+ nsMSSmimeRc2128,
+ nsMSSmimeDes,
+ nsMSSmimeRc264,
+ nsMSSmimeRc240,
+ nsMSSmimeFortezza
+
+objectclass netscapePreferenceMap
+ oid 2.16.840.1.113730.3.2.73
+ superior top
+ allows
+ nsPrefMap,
+ uid
+
diff --git a/ldap/cm/v4confs/411/ns-media-globopt.conf b/ldap/cm/v4confs/411/ns-media-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-media-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/411/ns-media-schema.conf b/ldap/cm/v4confs/411/ns-media-schema.conf
new file mode 100644
index 00000000..d4afa271
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-media-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeMediaServer
+ oid 2.16.840.1.113730.3.2.25
+ requires
+ objectclass
+
diff --git a/ldap/cm/v4confs/411/ns-mlm-schema.conf b/ldap/cm/v4confs/411/ns-mlm-schema.conf
new file mode 100644
index 00000000..e1c4ef78
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-mlm-schema.conf
@@ -0,0 +1,102 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# LDAP object classes used by MLM
+#
+
+attribute mgmemMemberOfGroup cis
+attribute mgmemRefDN ces single
+attribute mgmemMailUserPassword bin single
+attribute mgmemGroupMemberParam ces
+attribute mgmemGroupServerParam ces
+
+attribute mgmanJoinability ces
+attribute mgmanJoinLocalType cis single
+attribute mgmanMemberVisibility ces
+attribute mgmanIntroText ces single
+attribute mgmanGroupStat ces
+attribute mgmanHidden cis single
+attribute mgmanGroupKey cis single
+attribute mgmanAllowSubscribe cis
+attribute mgmanDenySubscribe cis
+
+attribute mgmanGConfNewGroupParent dn single
+attribute mgmanGConfRemoteUserParent dn single
+attribute mgmanGConfSearchBase dn single
+attribute mgmanGConfGroupCreationUser dn
+attribute mgmanGConfSearchGroupUser dn
+attribute mgmanGConfAdmin dn
+attribute mgmanGConfGroupTemplate dn single
+attribute mgmanGConfDefaultInheritance cis
+attribute mgmanGConfKey cis
+attribute mgmanGConfSearchAttribute cis
+attribute mgmanGConfSearchRelationship cis
+attribute mgmanGConfSearchTreeNode cis
+attribute mgmanGConfSortAttributeDirMembers cis
+attribute mgmanGConfSortAttributeGroupMembers cis
+attribute mgmanGConfGroupDomains dn
+
+
+objectClass mailGroupMember
+ requires
+ objectClass,
+ mail
+ allows
+ mgmemMemberOfGroup,
+ mgmemRefDN,
+ preferredLanguage,
+ userCertificate,
+ mgmemMailUserPassword,
+ mgmemGroupMemberParam,
+ mgmemGroupServerParam,
+ c,
+ cn,
+ sn,
+ givenName
+
+
+objectClass mailGroupManagement
+ requires
+ objectClass
+ allows
+ description,
+ labeledURL,
+ mgmanAllowSubscribe,
+ mgmanDenySubscribe,
+ mgmanGroupKey,
+ mgmanGroupStat,
+ mgmanHidden,
+ mgmanIntroText,
+ mgmanJoinability,
+ mgmanJoinLocalType,
+ mgmanMemberVisibility,
+ multilineDescription,
+ userCertificate,
+ userPassword
+
+objectClass mailGroupManagement_GlobalConfig
+ requires
+ objectClass
+ allows
+ cn,
+ mgmanGConfAdmin,
+ mgmanGConfDefaultInheritance,
+ mgmanGConfGroupCreationUser,
+ mgmanGConfGroupDomains,
+ mgmanGConfGroupTemplate,
+ mgmanGConfKey,
+ mgmanGConfNewGroupParent,
+ mgmanGConfRemoteUserParent,
+ mgmanGConfSearchAttribute,
+ mgmanGConfSearchBase,
+ mgmanGConfSearchGroupUser,
+ mgmanGConfSearchRelationship,
+ mgmanGConfSearchTreeNode,
+ mgmanGConfSortAttributeDirMembers,
+ mgmanGConfSortAttributeGroupMembers
+
diff --git a/ldap/cm/v4confs/411/ns-msg-schema.conf b/ldap/cm/v4confs/411/ns-msg-schema.conf
new file mode 100644
index 00000000..3800edbd
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-msg-schema.conf
@@ -0,0 +1,711 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#used by Netscape Messaging Server 4.0
+#
+#
+attribute nsmsgaccounturl cis
+attribute nsmsgadddeliveredto cis
+attribute nsmsgaddheaders cis
+attribute nsmsgadmins cis
+attribute nsmsgalias cis
+attribute nsmsgallowadminproxy cis
+attribute nsmsgallowanonymouslogin cis
+attribute nsmsgallowbarelf cis
+attribute nsmsgallowbdat cis
+attribute nsmsgallowehlo cis
+attribute nsmsgallowetrn cis
+attribute nsmsgallowexpn cis
+attribute nsmsgallowhelp cis
+attribute nsmsgallowonex cis
+attribute nsmsgallowsize cis
+attribute nsmsgallowverb cis
+attribute nsmsgallowvrfy cis
+attribute nsmsgaltqueues cis
+attribute nsmsgalwaysqueue cis
+attribute nsmsgauthcachesize cis
+attribute nsmsgauthcachettl cis
+attribute nsmsgauthmaildomain cis
+attribute nsmsgbanner cis
+attribute nsmsgbinarypath cis
+attribute nsmsgbuffersize cis
+attribute nsmsgcheckdeferredqueue cis
+attribute nsmsgcleanupage cis
+attribute nsmsgclearcontrolinterval cis
+attribute nsmsgclearcontrolsafetime cis
+attribute nsmsgcollectiondeltatime cis
+attribute nsmsgconfigversion cis
+attribute nsmsgcontact cis
+attribute nsmsgcounterdeltatime cis
+attribute nsmsgdbcachesize cis
+attribute nsmsgdbtmpdir cis
+attribute nsmsgdefaultacl cis
+attribute nsmsgdefaultdomain cis
+attribute nsmsgdefaultecho cis
+attribute nsmsgdefaultgid cis
+attribute nsmsgdefaultmailboxquota cis
+attribute nsmsgdefaultoverquota cis
+attribute nsmsgdefaultpartition cis
+attribute nsmsgdefaultreply cis
+attribute nsmsgdefaultuid cis
+attribute nsmsgdefaultvacation cis
+attribute nsmsgdeferredperiod cis
+attribute nsmsgdeleteheaders cis
+attribute nsmsgdescription cis
+attribute nsmsgdiskflushinterval cis
+attribute nsmsgdnsresolveclient cis
+attribute nsmsgdocanonicalize cis
+attribute nsmsgdoclientdnslookup cis
+attribute nsmsgdodsn cis
+attribute nsmsgdoetrn cis
+attribute nsmsgdomainallowed cis
+attribute nsmsgdomainlangtable cis
+attribute nsmsgdomainname cis
+attribute nsmsgdomainnotallowed cis
+attribute nsmsgdomainsecurity cis
+attribute nsmsgdorewritefromusingauth cis
+attribute nsmsgdorewritesenderusingauth cis
+attribute nsmsgenable cis
+attribute nsmsgenablesslport cis
+attribute nsmsgenveloperewritemethod cis
+attribute nsmsgexclusive cis
+attribute nsmsgexpirestart cis
+attribute nsmsgexpirytime cis
+attribute nsmsgexternalmxserverip cis
+attribute nsmsgfallbacksearchmethod cis
+attribute nsmsgfilemode cis
+attribute nsmsgfilterurl cis
+attribute nsmsgflushinterval cis
+attribute nsmsgfolderpattern cis
+attribute nsmsgfoldersizebytes cis
+attribute nsmsgfolderurl cis
+attribute nsmsgforeignpercentaddr cis
+attribute nsmsgformsigkey cis
+attribute nsmsghidehostname cis
+attribute nsmsghopcountexceedactions cis
+attribute nsmsghostoncommandline cis
+attribute nsmsghostrewrites cis
+attribute nsmsgidletimeout cis
+attribute nsmsgipsecurity cis
+attribute nsmsginstalledlanguages cis
+attribute nsmsginternalmxserverip cis
+attribute nsmsgldapmemcache cis
+attribute nsmsgldapmemcachesize cis
+attribute nsmsgldapmemcachettl cis
+attribute nsmsgldappoolsize cis
+attribute nsmsgldaputilconfig cis
+attribute nsmsglistenaddr cis
+attribute nsmsglistenq cis
+attribute nsmsglisturl cis
+attribute nsmsglocaldefaultmaxruncount cis
+attribute nsmsglocaldefaultminruncount cis
+attribute nsmsglocalmaildomains cis
+attribute nsmsglocation cis
+attribute nsmsglog cis
+attribute nsmsglogdir cis
+attribute nsmsgloglevel cis
+attribute nsmsglogtype cis
+attribute nsmsgmaildeliveryprogram cis
+attribute nsmsgmasterhost cis
+attribute nsmsgmasterport cis
+attribute nsmsgmaxbadcommands cis
+attribute nsmsgmaxbranches cis
+attribute nsmsgmaxcontrolrecipients cis
+attribute nsmsgmaxcputime cis
+attribute nsmsgmaxerrorobjectsize cis
+attribute nsmsgmaxheaderlines cis
+attribute nsmsgmaxlogfiles cis
+attribute nsmsgmaxlogfilesize cis
+attribute nsmsgmaxlogsize cis
+attribute nsmsgmaxmessagesize cis
+attribute nsmsgmaxmtahops cis
+attribute nsmsgmaxpostsize cis
+attribute nsmsgmaxqueuetime cis
+attribute nsmsgmaxruncount cis
+attribute nsmsgmaxruncountdeferred cis
+attribute nsmsgmaxscriptsize cis
+attribute nsmsgmaxsessions cis
+attribute nsmsgmaxstateobjectsize cis
+attribute nsmsgmaxthreads cis
+attribute nsmsgmessagecount cis
+attribute nsmsgmessagedays cis
+attribute nsmsgmessagehostname cis
+attribute nsmsgmessagesize cis
+attribute nsmsgmessagesizedays cis
+attribute nsmsgminfreediskspace cis
+attribute nsmsgminruncount cis
+attribute nsmsgmsgalarmdescription cis
+attribute nsmsgmsgalarmnoticehost cis
+attribute nsmsgmsgalarmnoticeport cis
+attribute nsmsgmsgalarmnoticercpt cis
+attribute nsmsgmsgalarmnoticesender cis
+attribute nsmsgmsgalarmnoticetemplate cis
+attribute nsmsgmsgalarmstatinterval cis
+attribute nsmsgmsgalarmthreshold cis
+attribute nsmsgmsgalarmthresholddirection cis
+attribute nsmsgmsgalarmwarninginterval cis
+attribute nsmsgmtaid cis
+attribute nsmsgmtaname cis
+attribute nsmsgneedsender cis
+attribute nsmsgnegativehostattr cis
+attribute nsmsgnestedgroups cis
+attribute nsmsgnetworkdefaultmaxruncount cis
+attribute nsmsgnetworkdefaultminruncount cis
+attribute nsmsgnewsprefix cis
+attribute nsmsgnewsspool cis
+attribute nsmsgnewuserforms cis
+attribute nsmsgntaccount cis
+attribute nsmsgntpassword cis
+attribute nsmsgntrunoptn cis
+attribute nsmsgnumdays cis
+attribute nsmsgnumenvelopequeuefiles cis
+attribute nsmsgnummessages cis
+attribute nsmsgnumprocesses cis
+attribute nsmsgorganization cis
+attribute nsmsgpartition cis
+attribute nsmsgpath cis
+attribute nsmsgplaintextloginpause cis
+attribute nsmsgplaintextmincipher cis
+attribute nsmsgpopminpoll cis
+attribute nsmsgport cis
+attribute nsmsgpositivehostattr cis
+attribute nsmsgprotocolubeconfig cis
+attribute nsmsgproxydomainallowed cis
+attribute nsmsgquotaexceededactions cis
+attribute nsmsgquotaexceededmsg cis
+attribute nsmsgquotaexceededmsginterval cis
+attribute nsmsgquotagraceperiod cis
+attribute nsmsgquotawarn cis
+attribute nsmsgreadtimeout cis
+attribute nsmsgrenotifyinterval cis
+attribute nsmsgrequirecrlf cis
+attribute nsmsgreserved0 cis
+attribute nsmsgreserved1 cis
+attribute nsmsgreserved2 cis
+attribute nsmsgreserved3 cis
+attribute nsmsgreserved4 cis
+attribute nsmsgreserved5 cis
+attribute nsmsgreserved6 cis
+attribute nsmsgreserved7 cis
+attribute nsmsgreserved8 cis
+attribute nsmsgreserved9 cis
+attribute nsmsgresourcetimeout cis
+attribute nsmsgrewritetocc cis
+attribute nsmsgrolloverdelta cis
+attribute nsmsgrolloversize cis
+attribute nsmsgrollovertime cis
+attribute nsmsgroutingattribute cis
+attribute nsmsgroutstripimapfolders cis
+attribute nsmsgsessiontimeout cis
+attribute nsmsgshellpath cis
+attribute nsmsgsitelanguage cis
+attribute nsmsgsmtphost cis
+attribute nsmsgsmtpport cis
+attribute nsmsgsmtprewritestyle cis
+attribute nsmsgsourceurl cis
+attribute nsmsgspooldir cis
+attribute nsmsgsslcachesize cis
+attribute nsmsgsslpasswdfile cis
+attribute nsmsgsslport cis
+attribute nmmsgsslsourceurl cis
+attribute nsmsgsslusessl cis
+attribute nsmsgsslusesslrelay cis
+attribute nsmsgstripcr cis
+attribute nsmsgsystemmaildir cis
+attribute nsmsgtimeoutcommand cis
+attribute nsmsgtimeoutdata cis
+attribute nsmsgtimeoutdatadot cis
+attribute nsmsgtimeoutdatasend cis
+attribute nsmsgtimeoutgreet cis
+attribute nsmsgtimeouthelo cis
+attribute nsmsgtimeoutmail cis
+attribute nsmsgtimeoutquit cis
+attribute nsmsgtimeoutrcpt cis
+attribute nsmsgtimeoutrset cis
+attribute nsmsgumask cis
+attribute nsmsgunknownacctsactions cis
+attribute nsmsgusemx cis
+attribute nsmsgverifyrcpts cis
+attribute nsmsgversion cis
+
+objectclass netscapeMessagingServer
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description
+
+objectclass nsmsgcfgcontainer
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfggen
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgaccounturl,
+ nsmsgconfigversion,
+ nsmsgfilterurl,
+ nsmsgfolderurl,
+ nsmsginstalledlanguages,
+ nsmsglisturl,
+ nsmsgnewuserforms,
+ nsmsgsitelanguage
+
+objectclass nsmsgcfgsnmp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgcontact,
+ nsmsgcollectiondeltatime,
+ nsmsgdescription,
+ nsmsgenable,
+ nsmsglocation,
+ nsmsgmtaid,
+ nsmsgmtaname,
+ nsmsgmasterhost,
+ nsmsgmasterport,
+ nsmsgorganization,
+ nsmsgversion
+
+objectclass nsmsgcfgstore
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgadmins,
+ nsmsgcleanupage,
+ nsmsgdbcachesize,
+ nsmsgdbtmpdir,
+ nsmsgdefaultacl,
+ nsmsgdefaultmailboxquota,
+ nsmsgdefaultpartition,
+ nsmsgdiskflushinterval,
+ nsmsgexpirestart,
+ nsmsgquotaexceededmsg,
+ nsmsgquotaexceededmsginterval,
+ nsmsgquotagraceperiod,
+ nsmsgquotawarn,
+ nsmsgumask
+
+objectclass nsmsgcfgexpirerule
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgfolderpattern,
+ nsmsgexclusive,
+ nsmsgfoldersizebytes,
+ nsmsgmessagecount,
+ nsmsgmessagedays,
+ nsmsgmessagesize,
+ nsmsgmessagesizedays
+
+objectclass nsmsgcfgpartition
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgpath
+
+objectclass nsmsgcfguser
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgpublic
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgalias
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgalias
+
+objectclass nsmsgcfglog
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgbuffersize,
+ nsmsgexpirytime,
+ nsmsgflushinterval,
+ nsmsglogdir,
+ nsmsgloglevel,
+ nsmsglogtype,
+ nsmsgmaxlogfiles,
+ nsmsgmaxlogfilesize,
+ nsmsgmaxlogsize,
+ nsmsgminfreediskspace,
+ nsmsgrollovertime
+
+objectclass nsmsgcfgservice
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgauthcachesize,
+ nsmsgauthcachettl,
+ nsmsgdnsresolveclient,
+ nsmsgldapmemcache,
+ nsmsgldapmemcachesize,
+ nsmsgldapmemcachettl,
+ nsmsglistenaddr,
+ nsmsgplaintextloginpause,
+ nsmsgreadtimeout,
+ nsmsgsslpasswdfile
+
+objectclass nsmsgcfgpop
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowanonymouslogin,
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgidletimeout,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgpopminpoll,
+ nsmsgport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgimap
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowanonymouslogin,
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgidletimeout,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgsslcachesize,
+ nsmsgsslport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfghttp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowadminproxy,
+ nsmsgallowanonymouslogin,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgdomainsecurity,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgidletimeout,
+ nsmsgipsecurity,
+ nsmsgmaxmessagesize,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgmaxpostsize,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgproxydomainallowed,
+ nsmsgresourcetimeout,
+ nsmsgsessiontimeout,
+ nsmsgsmtphost,
+ nsmsgsmtpport,
+ nsmsgsourceurl,
+ nsmsgspooldir,
+ nsmsgsslcachesize,
+ nsmsgsslport,
+ nsmsgsourceurl,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgnntp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgnewsprefix,
+ nsmsgnewsspool,
+ nsmsgpartition,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgsslport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgmta
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgaltqueues,
+ nsmsgauthmaildomain,
+ nsmsgbanner,
+ nsmsgclearcontrolinterval,
+ nsmsgclearcontrolsafetime,
+ nsmsgcounterdeltatime,
+ nsmsgdefaultdomain,
+ nsmsgdeferredperiod,
+ nsmsgdocanonicalize,
+ nsmsgdoclientdnslookup,
+ nsmsgdodsn,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgdomainname,
+ nsmsgdomainlangtable,
+ nsmsgenable,
+ nsmsgforeignpercentaddr,
+ nsmsgldappoolsize,
+ nsmsgldaputilconfig,
+ nsmsglocaldefaultmaxruncount,
+ nsmsglocaldefaultminruncount,
+ nsmsgmaxheaderlines,
+ nsmsgmaxqueuetime,
+ nsmsgmessagehostname,
+ nsmsgnetworkdefaultmaxruncount,
+ nsmsgnetworkdefaultminruncount,
+ nsmsgnumenvelopequeuefiles,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgprotocolubeconfig,
+ nsmsgreserved0,
+ nsmsgreserved1,
+ nsmsgreserved2,
+ nsmsgreserved3,
+ nsmsgreserved4,
+ nsmsgreserved5,
+ nsmsgreserved6,
+ nsmsgreserved7,
+ nsmsgreserved8,
+ nsmsgreserved9,
+ nsmsgrolloverdelta,
+ nsmsgrolloversize,
+ nsmsgroutstripimapfolders,
+ nsmsgsslusessl,
+ nsmsgsslusesslrelay
+
+objectclass nsmsgcfgmtalog
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsglog,
+ nsmsgminruncount,
+ nsmsgmaxruncount,
+ nsmsgmaxruncountdeferred
+
+objectclass nsmsgcfgmtaautoreplyhandler
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultecho,
+ nsmsgdefaultreply,
+ nsmsgdefaultvacation
+
+objectclass nsmsgcfgmtaerrorhandler
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgformsigkey,
+ nsmsghopcountexceedactions,
+ nsmsgquotaexceededactions,
+ nsmsgrenotifyinterval,
+ nsmsgunknownacctsactions
+
+objectclass nsmsgcfgmtamboxdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgmtaprogdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultgid,
+ nsmsgdefaultuid,
+ nsmsgshellpath,
+ nsmsgntrunoptn,
+ nsmsgntaccount,
+ nsmsgntpassword
+
+objectclass nsmsgcfgmtaaccept
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowbdat,
+ nsmsgallowehlo,
+ nsmsgallowetrn,
+ nsmsgallowexpn,
+ nsmsgallowhelp,
+ nsmsgallowonex,
+ nsmsgallowsize,
+ nsmsgallowverb,
+ nsmsgallowvrfy,
+ nsmsghidehostname,
+ nsmsgmaxbadcommands,
+ nsmsgmaxmessagesize,
+ nsmsgminfreediskspace,
+ nsmsgnegativehostattr,
+ nsmsgpositivehostattr,
+ nsmsgrequirecrlf,
+ nsmsgtimeoutcommand,
+ nsmsgtimeoutdata,
+ nsmsgverifyrcpts
+
+objectclass nsmsgcfgmtasmtpdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowbarelf,
+ nsmsgalwaysqueue,
+ nsmsgcheckdeferredqueue,
+ nsmsgdoetrn,
+ nsmsgexternalmxserverip,
+ nsmsginternalmxserverip,
+ nsmsgtimeoutdata,
+ nsmsgtimeoutdatadot,
+ nsmsgtimeoutdatasend,
+ nsmsgtimeoutgreet,
+ nsmsgtimeouthelo,
+ nsmsgtimeoutmail,
+ nsmsgtimeoutquit,
+ nsmsgtimeoutrcpt,
+ nsmsgtimeoutrset,
+ nsmsgusemx
+
+objectclass nsmsgcfgmtarouter
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgadddeliveredto,
+ nsmsgaddheaders,
+ nsmsgdeleteheaders,
+ nsmsgdorewritefromusingauth,
+ nsmsgdorewritesenderusingauth,
+ nsmsgenveloperewritemethod,
+ nsmsgfallbacksearchmethod,
+ nsmsghostrewrites,
+ nsmsglocalmaildomains,
+ nsmsgmaxcontrolrecipients,
+ nsmsgmaxmtahops,
+ nsmsgnestedgroups,
+ nsmsgrewritetocc,
+ nsmsgroutingattribute,
+ nsmsgsmtprewritestyle
+
+objectclass nsmsgcfgmtaunixdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultgid,
+ nsmsgdefaultuid,
+ nsmsgfilemode,
+ nsmsgmaildeliveryprogram,
+ nsmsgneedsender,
+ nsmsgstripcr,
+ nsmsgsystemmaildir
+
+objectclass nsmsgcfgreport
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgalarmcontainer
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgmsgalarmnoticehost,
+ nsmsgmsgalarmnoticeport,
+ nsmsgmsgalarmnoticercpt,
+ nsmsgmsgalarmnoticesender,
+ nsmsgmsgalarmnoticetemplate
+
+objectclass nsmsgcfgalarm
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgmsgalarmdescription,
+ nsmsgmsgalarmstatinterval,
+ nsmsgmsgalarmthreshold,
+ nsmsgmsgalarmthresholddirection,
+ nsmsgmsgalarmwarninginterval
+
+objectclass nsmsgcfgscript
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgenable,
+ nsmsgbinarypath,
+ nsmsgloglevel,
+ nsmsgmaxscriptsize,
+ nsmsgmaxbranches,
+ nsmsgmaxcputime,
+ nsmsgmaxerrorobjectsize,
+ nsmsgmaxstateobjectsize
diff --git a/ldap/cm/v4confs/411/ns-netshare-schema.conf b/ldap/cm/v4confs/411/ns-netshare-schema.conf
new file mode 100644
index 00000000..b1201ef0
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-netshare-schema.conf
@@ -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
+#
+# Used by Netscape Enterprise Server
+attribute netshareHomeURL ces single
+attribute netshareServerType cis single
+attribute netshareHomeTheme cis single
+attribute netsharePrivate cis single
+attribute netshareMemberOf dn
+attribute netshareUIConfig bin single
+
+# added to either users or groups/projects to enable
+# as netshare user accounts or netshare projects
+objectclass netshareAccount
+ requires
+ objectclass,
+ netshareHomeURL
+ allows
+ netshareServerType,
+ netshareHomeTheme,
+ netsharePrivate,
+ netshareMemberOf,
+ netshareUIConfig
+
+
+attribute netsharePMNewProjParent dn single
+attribute netsharePMSearchBase dn single
+attribute netsharePMProjCreationUser dn single
+attribute netsharePMAdmin dn
+
+# this is for the netshare project management utility/CGI
+# that is created under the SIE; this parallels the messaging
+# MLM schema somewhat to enable end-user maintenance/creation
+# of netshare projects
+objectclass netshareProjectManagementGlobalConfig
+ requires
+ objectclass
+ allows
+ netsharePMNewProjParent,
+ netsharePMSearchBase,
+ netsharePMProjCreationUser,
+ netsharePMAdmin,
+ cn
diff --git a/ldap/cm/v4confs/411/ns-news-globopt.conf b/ldap/cm/v4confs/411/ns-news-globopt.conf
new file mode 100644
index 00000000..b35e2a83
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-news-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape News Server
+#index uniquemember,member eq
+
diff --git a/ldap/cm/v4confs/411/ns-news-schema.conf b/ldap/cm/v4confs/411/ns-news-schema.conf
new file mode 100644
index 00000000..777f339a
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-news-schema.conf
@@ -0,0 +1,35 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsnewsACL 2.16.840.1.113730.3.1.191 cis
+attribute nsaclrole 2.16.840.1.113730.3.1.192 cis
+attribute nsprettyname 2.16.840.1.113730.3.1.193 cis
+attribute nsflags 2.16.840.1.113730.3.1.194 cis
+attribute nscreator 2.16.840.1.113730.3.1.195 cis
+attribute ngcomponent 2.16.840.1.113730.3.1.196 dn
+
+objectclass nginfo
+ oid 2.16.840.1.113730.3.2.26
+ requires
+ objectClass,
+ ngcomponent
+ allows
+ nsnewsACL,
+ subtreeACI,
+ description,
+ nsaclrole,
+ nsprettyname,
+ nsflags,
+ nscreator
+
+objectClass netscapeNewsServer
+ oid 2.16.840.1.113730.3.2.27
+ requires
+ objectClass
+
diff --git a/ldap/cm/v4confs/411/ns-proxy-globopt.conf b/ldap/cm/v4confs/411/ns-proxy-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-proxy-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/411/ns-proxy-schema.conf b/ldap/cm/v4confs/411/ns-proxy-schema.conf
new file mode 100644
index 00000000..3d26bacb
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-proxy-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeProxyServer
+ oid 2.16.840.1.113730.3.2.28
+ requires
+ objectclass
+
diff --git a/ldap/cm/v4confs/411/ns-value-schema.conf b/ldap/cm/v4confs/411/ns-value-schema.conf
new file mode 100644
index 00000000..c4b9d3c9
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-value-schema.conf
@@ -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
+#
+# Schema for defining schemaless config for LDAP
+#
+
+attribute nsValueCIS 2.16.840.1.113730.3.1.243 cis
+attribute nsValueCES 2.16.840.1.113730.3.1.244 ces
+attribute nsValueTel 2.16.840.1.113730.3.1.245 tel
+attribute nsValueInt 2.16.840.1.113730.3.1.246 int
+attribute nsValueBin 2.16.840.1.113730.3.1.247 bin
+attribute nsValueDN 2.16.840.1.113730.3.1.248 dn
+attribute nsValueType 2.16.840.1.113730.3.1.249 cis
+attribute nsValueDefault 2.16.840.1.113730.3.1.250 cis
+attribute nsValueFlags 2.16.840.1.113730.3.1.251 cis
+attribute nsValueDescription 2.16.840.1.113730.3.1.252 cis
+attribute nsValueSyntax 2.16.840.1.113730.3.1.253 cis
+attribute nsValueHelpURL 2.16.840.1.113730.3.1.254 ces
+
+objectClass nsValueItem
+ oid 2.16.840.1.113730.3.2.45
+ requires
+ objectClass,
+ cn
+ allows
+ nsValueCIS,
+ nsValueCES,
+ nsValueTel,
+ nsValueInt,
+ nsValueBin,
+ nsValueDN,
+ nsValueType,
+ nsValueSyntax,
+ nsValueDescription,
+ nsValueHelpURL,
+ nsValueFlags,
+ nsValueDefault
+
diff --git a/ldap/cm/v4confs/411/ns-wcal-globopt.conf b/ldap/cm/v4confs/411/ns-wcal-globopt.conf
new file mode 100644
index 00000000..72b108c7
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-wcal-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#used by Netscape Calendar Hosting Server 1.0
+
+index nswcalCALID pres,eq
diff --git a/ldap/cm/v4confs/411/ns-wcal-schema.conf b/ldap/cm/v4confs/411/ns-wcal-schema.conf
new file mode 100644
index 00000000..97a6d12d
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-wcal-schema.conf
@@ -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
+#
+# Used by Netscape Calendar Hosting Server
+
+# Login calendar URI for this user
+attribute nswcalCALID 2.16.840.1.113730.3.1.537 cis single
+
+# Calendar client specific user preferences for this user
+attribute nswcalExtendedUserPrefs 2.16.840.1.113730.3.1.538 cis
+
+# Lists calendar protocols not allowed to be used by this user
+attribute nswcalDisallowAccess 2.16.840.1.113730.3.1.539 cis single
+
+# Calendar host for this user's login calendar
+attribute nswcalHost 2.16.840.1.113730.3.1.540 cis
+
+# Quota associated with this user's calendars
+attribute nswcalQuota 2.16.840.1.113730.3.1.541 cis single
+
+# Used to designate a LDAP entry as representing a Netscape Calendar
+# Hosting Server user account. These first 10 attributes are
+# referenced by Netscape Calendar Hosting Server and the last 3
+# attributes are reserved for future use.
+objectClass nswcalUser
+ oid 2.16.840.1.113730.3.2.83
+ requires
+ objectClass
+ allows
+ cn,
+ givenName,
+ mail,
+ preferredlanguage,
+ sn,
+ uid,
+ userPassword,
+ nswcalCALID,
+ nswcalDisallowAccess,
+ nswcalExtendedUserPrefs,
+ nslicensedfor,
+ nswcalHost,
+ nswcalQuota
+
+# From http://www.imc.org/draft-ietf-calsch-locating
+attribute calCalURI 1.2.840.113556.1.4.478 cis
+attribute calFBURL 1.2.840.113556.1.4.479 cis
+attribute calCAPURI 1.2.840.113556.1.4.480 cis
+attribute calCalAdrURI 1.2.840.113556.1.4.481 cis
+attribute calOtherCalURIs 1.2.840.113556.1.4.482 cis
+attribute calOtherFBURLs 1.2.840.113556.1.4.483 cis
+attribute calOtherCAPURIs 1.2.840.113556.1.4.484 cis
+attribute calOtherCalAdrURIs 1.2.840.113556.1.4.485 cis
+
+# Used to designate a LDAP entry as representing a calendar user.
+objectClass calEntry
+ oid 1.2.840.113556.1.5.87
+ requires
+ objectClass
+ allows
+ calCalURI,
+ calFBURL,
+ calCAPURI,
+ calCalAdrURI,
+ calOtherCalURIs,
+ calOtherFBURLs,
+ calOtherCAPURIs,
+ calOtherCalAdrURIs
diff --git a/ldap/cm/v4confs/411/ns-web-globopt.conf b/ldap/cm/v4confs/411/ns-web-globopt.conf
new file mode 100644
index 00000000..4db72fe2
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-web-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Enterprise Server
+#index uniquemember,member eq
+
diff --git a/ldap/cm/v4confs/411/ns-web-schema.conf b/ldap/cm/v4confs/411/ns-web-schema.conf
new file mode 100644
index 00000000..d5e74ed8
--- /dev/null
+++ b/ldap/cm/v4confs/411/ns-web-schema.conf
@@ -0,0 +1,18 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+objectclass netscapeWebServer
+ oid 2.16.840.1.113730.3.2.29
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description,
+ nsServerPort
+
diff --git a/ldap/cm/v4confs/411/slapd.at.conf b/ldap/cm/v4confs/411/slapd.at.conf
new file mode 100644
index 00000000..87c3e342
--- /dev/null
+++ b/ldap/cm/v4confs/411/slapd.at.conf
@@ -0,0 +1,391 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.at.conf for Netscape Directory Server 4.1
+#
+# DO NOT MODIFY!
+#
+# The attributes listed in this file are Standard Attributes and are
+# expected to present in Directory Server 4.1. Editing this file could
+# cause interoperability problems.
+#
+# User Defined Attributes should be added by selecting
+# Schema | Edit or View Attributes from the Admin Server.
+#
+# User Defined Attributes are placed in slapd.user_at.conf.
+#
+# All attributes are viewable over LDAP in the cn=schema entry under
+# attributetypes.
+#
+# The format of this file is:
+#
+# attribute attribute-name [attribute-aliases] [attribute-oid] syntax
+#
+# If no OID is specified, <attribute-name>-oid will be used as the OID
+#
+
+########################################################################
+# X.500(93) User Schema for use with LDAP
+# Taken from <draft-ietf-asid-ldapv3schema-x500-00.txt>
+########################################################################
+
+attribute objectClass 2.5.4.0 cis
+attribute aliasedObjectName 2.5.4.1 dn
+attribute knowledgeInformation 2.5.4.2 cis
+attribute cn commonName 2.5.4.3 cis
+attribute sn surName 2.5.4.4 cis
+attribute serialNumber 2.5.4.5 cis
+attribute c countryName 2.5.4.6 cis
+attribute l locality localityname 2.5.4.7 cis
+attribute st stateOrProvinceName 2.5.4.8 cis
+attribute street streetaddress 2.5.4.9 cis
+attribute o organizationname 2.5.4.10 cis
+attribute ou organizationalUnitName 2.5.4.11 cis
+attribute title 2.5.4.12 cis
+attribute description 2.5.4.13 cis
+attribute searchGuide 2.5.4.14 ces
+attribute businessCategory 2.5.4.15 cis
+attribute postalAddress 2.5.4.16 cis
+attribute postalCode 2.5.4.17 cis
+attribute postOfficeBox 2.5.4.18 cis
+attribute physicalDeliveryOfficeName 2.5.4.19 cis
+attribute telephoneNumber 2.5.4.20 tel
+attribute telexNumber 2.5.4.21 cis
+attribute teletexTerminalIdentifier 2.5.4.22 cis
+attribute facsimileTelephoneNumber fax 2.5.4.23 tel
+attribute x121Address 2.5.4.24 ces
+attribute internationalIsdnNumber 2.5.4.25 ces
+attribute registeredAddress 2.5.4.26 cis
+attribute destinationIndicator 2.5.4.27 cis
+attribute preferredDeliveryMethod 2.5.4.28 cis single
+attribute presentationAddress 2.5.4.29 ces
+attribute supportedApplicationContext 2.5.4.30 cis
+attribute member 2.5.4.31 dn
+attribute owner 2.5.4.32 dn
+attribute roleOccupant 2.5.4.33 dn
+attribute seeAlso 2.5.4.34 dn
+attribute userPassword 2.5.4.35 bin
+attribute userCertificate 2.5.4.36 bin
+attribute cACertificate cACertificate 2.5.4.37 bin
+attribute authorityRevocationList authorityRevocationList 2.5.4.38 bin
+attribute certificateRevocationList certificateRevocationList 2.5.4.39 bin
+attribute crossCertificatePair crossCertificatePair 2.5.4.40 bin
+attribute givenName 2.5.4.42 cis
+attribute initials 2.5.4.43 cis
+attribute generationQualifier 2.5.4.44 cis
+attribute x500UniqueIdentifier 2.5.4.45 bin
+attribute dnQualifier 2.5.4.46 cis
+attribute enhancedSearchGuide 2.5.4.47 cis
+attribute protocolInformation 2.5.4.48 cis
+attribute dn distinguishedName 2.5.4.49 dn
+attribute uniqueMember 2.5.4.50 dn
+attribute houseIdentifier 2.5.4.51 cis
+attribute supportedAlgorithms 2.5.4.52 bin
+attribute deltaRevocationList 2.5.4.53 bin
+
+#######################################################################
+# LDAP Attributes #
+# Taken from <draft-ietf-asid-ldapv3-attributes-07.txt> #
+#######################################################################
+
+attribute createTimestamp 2.5.18.1 cis
+attribute modifyTimestamp 2.5.18.2 cis
+attribute creatorsName 2.5.18.3 dn
+attribute modifiersName 2.5.18.4 dn
+attribute subschemaSubentry 2.5.18.10 dn
+attribute attributeTypes 2.5.21.5 cis
+attribute objectClasses 2.5.21.6 cis
+attribute matchingRules 2.5.21.4 cis
+attribute matchingRuleUse 2.5.21.8 cis
+attribute dITStructureRules 2.5.21.1 cis
+attribute dITContentRules 2.5.21.2 cis
+attribute nameForms 2.5.21.7 cis
+
+attribute namingContexts 1.3.6.1.4.1.1466.101.120.5 dn
+attribute altServer 1.3.6.1.4.1.1466.101.120.6 ces
+attribute supportedExtension 1.3.6.1.4.1.1466.101.120.7 cis
+attribute supportedControl 1.3.6.1.4.1.1466.101.120.13 cis
+attribute supportedSASLMechanisms 1.3.6.1.4.1.1466.101.120.14 cis
+attribute supportedLDAPVersion 1.3.6.1.4.1.1466.101.120.15 int
+attribute ldapSyntaxes 1.3.6.1.4.1.1466.101.120.16 cis
+
+#######################################################################
+# Pilot X.500 schema for use in LDAPv3 #
+# Taken from <draft-ietf-asid-schema-pilot-00.txt> #
+#######################################################################
+
+attribute uid 0.9.2342.19200300.100.1.1 cis
+attribute textEncodedORAddress 0.9.2342.19200300.100.1.2 cis
+attribute mail rfc822mailbox 0.9.2342.19200300.100.1.3 cis
+attribute info 0.9.2342.19200300.100.1.4 cis
+attribute drink 0.9.2342.19200300.100.1.5 cis
+attribute roomNumber 0.9.2342.19200300.100.1.6 cis
+attribute userClass 0.9.2342.19200300.100.1.8 cis
+attribute host 0.9.2342.19200300.100.1.9 cis
+attribute manager 0.9.2342.19200300.100.1.10 dn
+attribute documentIdentifier 0.9.2342.19200300.100.1.11 cis
+attribute documentTitle 0.9.2342.19200300.100.1.12 cis
+attribute documentVersion 0.9.2342.19200300.100.1.13 cis
+attribute documentAuthor 0.9.2342.19200300.100.1.14 dn
+attribute documentLocation 0.9.2342.19200300.100.1.15 cis
+attribute homePhone 0.9.2342.19200300.100.1.20 tel
+attribute secretary 0.9.2342.19200300.100.1.21 dn
+attribute otherMailbox 0.9.2342.19200300.100.1.22 cis
+attribute dc domaincomponent 0.9.2342.19200300.100.1.25 cis
+attribute dNSRecord 0.9.2342.19200300.100.1.26 cis
+attribute associatedName 0.9.2342.19200300.100.1.38 dn
+attribute homePostalAddress 0.9.2342.19200300.100.1.39 cis
+attribute personalTitle 0.9.2342.19200300.100.1.40 cis
+attribute mobile mobileTelephoneNumber 0.9.2342.19200300.100.1.41 tel
+attribute pager pagerTelephoneNumber 0.9.2342.19200300.100.1.42 tel
+attribute co friendlycountryname 0.9.2342.19200300.100.1.43 cis
+attribute uniqueIdentifier 0.9.2342.19200300.100.1.44 cis
+attribute organizationalStatus 0.9.2342.19200300.100.1.45 cis
+attribute janetMailbox 0.9.2342.19200300.100.1.46 cis
+attribute mailPreferenceOption 0.9.2342.19200300.100.1.47 int single
+attribute buildingName 0.9.2342.19200300.100.1.48 cis
+attribute dSAQuality 0.9.2342.19200300.100.1.49 cis single
+attribute singleLevelQuality 0.9.2342.19200300.100.1.50 cis single
+attribute subtreeMinimumQuality 0.9.2342.19200300.100.1.51 cis single
+attribute subtreeMaximumQuality 0.9.2342.19200300.100.1.52 cis single
+attribute personalSignature 0.9.2342.19200300.100.1.53 bin
+attribute ditRedirect 0.9.2342.19200300.100.1.54 dn
+attribute audio 0.9.2342.19200300.100.1.55 bin
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis
+attribute jpegPhoto 0.9.2342.19200300.100.1.60 bin
+
+#definitions subsequent to RFC 1274
+
+attribute labeledUri labeledurl 1.3.6.1.4.1.250.1.57 ces
+
+
+############################################################################
+# Netscape Defined Attributes
+#
+# The Netscape base OID is 2.16.840.1.113730
+# The base OID for the Netscape Directory Server is 2.16.840.1.113730.3
+# Netscape defined attributes have base 2.16.840.1.113730.3.1
+#
+# More Netscape defined attributes can be found included in ns-schema.conf
+############################################################################
+
+attribute carLicense 2.16.840.1.113730.3.1.1 cis
+attribute departmentNumber 2.16.840.1.113730.3.1.2 cis
+attribute employeeNumber 2.16.840.1.113730.3.1.3 cis single
+attribute employeeType 2.16.840.1.113730.3.1.4 cis
+attribute changeNumber 2.16.840.1.113730.3.1.5 int
+attribute targetDn 2.16.840.1.113730.3.1.6 dn
+attribute changeType 2.16.840.1.113730.3.1.7 cis
+attribute changes 2.16.840.1.113730.3.1.8 bin
+attribute newRdn 2.16.840.1.113730.3.1.9 dn
+attribute deleteOldRdn 2.16.840.1.113730.3.1.10 cis
+attribute newSuperior 2.16.840.1.113730.3.1.11 dn
+attribute ref 2.16.840.1.113730.3.1.34 ces
+attribute nsLicensedFor 2.16.840.1.113730.3.1.36 cis
+attribute nsLicenseStartTime 2.16.840.1.113730.3.1.37 cis
+attribute nsLicenseEndTime 2.16.840.1.113730.3.1.38 cis
+attribute preferredLanguage 2.16.840.1.113730.3.1.39 cis single
+attribute userSMIMECertificate 2.16.840.1.113730.3.1.40 bin
+attribute ntUserDomainId 2.16.840.1.113730.3.1.41 cis single
+attribute ntUserCreateNewAccount 2.16.840.1.113730.3.1.42 cis single
+attribute ntUserDeleteAccount 2.16.840.1.113730.3.1.43 cis single
+attribute ntGroupDomainId 2.16.840.1.113730.3.1.44 cis single
+attribute ntGroupCreateNewGroup 2.16.840.1.113730.3.1.45 cis single
+attribute ntGroupDeleteGroup 2.16.840.1.113730.3.1.46 cis single
+attribute ntGroupType 2.16.840.1.113730.3.1.47 cis single
+attribute replicaPort 2.16.840.1.113730.3.1.48 cis
+attribute replicaUpdateFailedAt 2.16.840.1.113730.3.1.49 cis
+attribute replicaBeginOrc 2.16.840.1.113730.3.1.50 cis
+attribute replicaUpdateReplayed 2.16.840.1.113730.3.1.51 cis
+attribute replicaUpdateSchedule 2.16.840.1.113730.3.1.52 cis
+attribute replicaBindMethod 2.16.840.1.113730.3.1.53 cis
+attribute replicaUseSSL 2.16.840.1.113730.3.1.54 cis
+attribute aci 2.16.840.1.113730.3.1.55 bin
+attribute lastModifiedBy 0.9.2342.19200300.100.1.24 dn
+attribute replicaRoot 2.16.840.1.113730.3.1.57 dn
+attribute replicaBindDn 2.16.840.1.113730.3.1.58 dn
+attribute ntUserPriv 2.16.840.1.113730.3.1.59 bin single
+attribute ntUserAuthFlags 2.16.840.1.113730.3.1.60 bin single
+attribute ntUserUsrComment 2.16.840.1.113730.3.1.61 cis single
+attribute ntUserParms 2.16.840.1.113730.3.1.62 cis single
+attribute ntUserUnitsPerWeek 2.16.840.1.113730.3.1.63 bin single
+attribute ntUserNumLogons 2.16.840.1.113730.3.1.64 bin single
+attribute ntUserLogonServer 2.16.840.1.113730.3.1.65 cis single
+attribute ntUserUniqueId 2.16.840.1.113730.3.1.66 bin single
+attribute ntUserProfile 2.16.840.1.113730.3.1.67 cis single
+attribute ntUserPasswordExpired 2.16.840.1.113730.3.1.68 bin single
+attribute subtreeACI 2.16.840.1.113730.3.1.69 ces
+attribute serverRoot 2.16.840.1.113730.3.1.70 cis
+attribute serverProductName 2.16.840.1.113730.3.1.71 cis
+attribute serverVersionNumber 2.16.840.1.113730.3.1.72 cis
+attribute installationTimeStamp 2.16.840.1.113730.3.1.73 cis
+attribute administratorContactInfo 2.16.840.1.113730.3.1.74 cis
+attribute adminUrl 2.16.840.1.113730.3.1.75 ces
+attribute serverHostName 2.16.840.1.113730.3.1.76 cis
+attribute changeTime 2.16.840.1.113730.3.1.77 cis
+attribute cirReplicaRoot 2.16.840.1.113730.3.1.79 dn
+attribute cirHost 2.16.840.1.113730.3.1.80 cis
+attribute cirPort 2.16.840.1.113730.3.1.81 cis
+attribute cirBindDn 2.16.840.1.113730.3.1.82 dn
+attribute cirUsePersistentSearch 2.16.840.1.113730.3.1.83 cis
+attribute cirUseSsl 2.16.840.1.113730.3.1.84 cis
+attribute cirBindCredentials 2.16.840.1.113730.3.1.85 ces
+attribute cirLastUpdateApplied 2.16.840.1.113730.3.1.86 cis
+attribute cirUpdateSchedule 2.16.840.1.113730.3.1.87 cis
+attribute cirUpdateFailedat 2.16.840.1.113730.3.1.88 cis
+attribute cirSyncInterval 2.16.840.1.113730.3.1.89 cis
+attribute cirBeginORC 2.16.840.1.113730.3.1.90 cis
+attribute passwordExpirationTime 2.16.840.1.113730.3.1.91 cis operational
+attribute passwordExpWarned 2.16.840.1.113730.3.1.92 cis operational
+attribute passwordRetryCount 2.16.840.1.113730.3.1.93 cis operational
+attribute retryCountResetTime 2.16.840.1.113730.3.1.94 cis operational
+attribute accountUnlockTime 2.16.840.1.113730.3.1.95 cis operational
+attribute passwordHistory 2.16.840.1.113730.3.1.96 bin operational
+attribute passwordMaxAge 2.16.840.1.113730.3.1.97 cis
+attribute passwordExp 2.16.840.1.113730.3.1.98 cis
+attribute passwordMinLength 2.16.840.1.113730.3.1.99 cis
+attribute passwordKeepHistory 2.16.840.1.113730.3.1.100 cis
+attribute passwordInHistory 2.16.840.1.113730.3.1.101 cis
+attribute passwordChange 2.16.840.1.113730.3.1.102 cis
+attribute passwordCheckSyntax 2.16.840.1.113730.3.1.103 cis
+attribute passwordWarning 2.16.840.1.113730.3.1.104 cis
+attribute passwordLockout 2.16.840.1.113730.3.1.105 cis
+attribute passwordMaxFailure 2.16.840.1.113730.3.1.106 cis
+attribute passwordResetDuration 2.16.840.1.113730.3.1.107 cis
+attribute passwordUnlock 2.16.840.1.113730.3.1.108 cis
+attribute passwordLockoutDuration 2.16.840.1.113730.3.1.109 cis
+attribute ntGroupId 2.16.840.1.113730.3.1.110 bin single
+attribute replicaHost 2.16.840.1.113730.3.1.197 cis
+attribute memberURL 2.16.840.1.113730.3.1.198 ces
+attribute memberCertificateDescription 2.16.840.1.113730.3.1.199 ces
+attribute replicaCredentials 2.16.840.1.113730.3.1.202 bin
+attribute replicaEntryFilter 2.16.840.1.113730.3.1.203 ces
+attribute replicaNickName 2.16.840.1.113730.3.1.204 cis
+attribute filterInfo 2.16.840.1.113730.3.1.206 cis
+attribute replicaCFUpdated 2.16.840.1.113730.3.1.217 cis
+attribute replicaAbandonedChanges 2.16.840.1.113730.3.1.218 cis
+attribute vlvBase 2.16.840.1.113730.3.1.207 dn
+attribute vlvScope 2.16.840.1.113730.3.1.208 int
+attribute vlvFilter 2.16.840.1.113730.3.1.209 ces
+attribute vlvSort 2.16.840.1.113730.3.1.210 cis
+attribute vlvName 2.16.840.1.113730.3.1.211 ces
+attribute netscapeMDSuffix 2.16.840.1.113730.3.1.212 dn
+attribute vlvEnabled 2.16.840.1.113730.3.1.213 int
+attribute passwordAllowChangeTime 2.16.840.1.113730.3.1.214 cis operational
+attribute oid 2.16.840.1.113730.3.1.215 cis
+attribute userPKCS12 2.16.840.1.113730.3.1.216 bin
+attribute vlvUses 2.16.840.1.113730.3.1.219 int
+attribute passwordMustChange 2.16.840.1.113730.3.1.220 cis
+attribute passwordStorageScheme 2.16.840.1.113730.3.1.121 cis
+attribute passwordMinAge 2.16.840.1.113730.3.1.122 cis
+attribute passwordResetFailureCount 2.16.840.1.113730.3.1.123 cis
+attribute nsslapd-pluginPath 2.16.840.1.113730.3.1.224 cis
+attribute nsslapd-pluginInitfunc 2.16.840.1.113730.3.1.225 cis
+attribute nsslapd-pluginType 2.16.840.1.113730.3.1.226 cis
+attribute nsslapd-pluginId 2.16.840.1.113730.3.1.227 cis
+attribute nsslapd-pluginVersion 2.16.840.1.113730.3.1.228 cis
+attribute nsslapd-pluginVendor 2.16.840.1.113730.3.1.229 cis
+attribute nsslapd-pluginDescription 2.16.840.1.113730.3.1.230 cis
+attribute nsslapd-pluginEnabled 2.16.840.1.113730.3.1.231 cis
+attribute nsSNMPEnabled 2.16.840.1.113730.3.1.232 cis
+attribute nsSNMPOrganization 2.16.840.1.113730.3.1.233 cis
+attribute nsSNMPLocation 2.16.840.1.113730.3.1.234 cis
+attribute nsSNMPContact 2.16.840.1.113730.3.1.235 cis
+attribute nsSNMPDescription 2.16.840.1.113730.3.1.236 cis
+attribute nsSNMPMasterHost 2.16.840.1.113730.3.1.237 cis
+attribute nsSNMPMasterPort 2.16.840.1.113730.3.1.238 cis
+attribute nsslapd-backend 2.16.840.1.113730.3.1.239 cis
+attribute replicatedattributelist 2.16.840.1.113730.3.1.240 cis
+attribute displayName 2.16.840.1.113730.3.1.241 cis single
+attribute nsSystemIndex 2.16.840.1.113730.3.1.242 cis
+attribute nsIndexType 2.16.840.1.113730.3.1.327 cis
+attribute nsMatchingRule 2.16.840.1.113730.3.1.328 cis
+attribute nsAddressBookSyncURL 2.16.840.1.113730.3.1.330 ces
+attribute nsSynchUserIDFormat 2.16.840.1.113730.3.1.406 cis
+attribute nsSynchUniqueAttribute 2.16.840.1.113730.3.1.407 cis
+attribute replicaLastRelevantChange 2.16.840.1.113730.3.1.408 int
+attribute ntUserHomeDir 2.16.840.1.113730.3.1.521 cis single
+attribute ntUserComment 2.16.840.1.113730.3.1.522 cis single
+attribute ntUserFlags 2.16.840.1.113730.3.1.523 bin single
+attribute ntUserScriptPath 2.16.840.1.113730.3.1.524 cis single
+attribute ntUserWorkstations 2.16.840.1.113730.3.1.525 cis single
+attribute ntUserLastLogon 2.16.840.1.113730.3.1.526 cis single
+attribute ntUserLastLogoff 2.16.840.1.113730.3.1.527 cis single
+attribute ntUserAcctExpires 2.16.840.1.113730.3.1.528 cis single
+attribute ntUserMaxStorage 2.16.840.1.113730.3.1.529 bin single
+attribute ntUserLogonHours 2.16.840.1.113730.3.1.530 bin single
+attribute ntUserBadPwCount 2.16.840.1.113730.3.1.531 bin single
+attribute ntUserCountryCode 2.16.840.1.113730.3.1.532 cis single
+attribute ntUserCodePage 2.16.840.1.113730.3.1.533 bin single
+attribute ntUserPrimaryGroupId 2.16.840.1.113730.3.1.534 bin single
+attribute ntUserHomeDirDrive 2.16.840.1.113730.3.1.535 cis single
+attribute ntGroupAttributes 2.16.840.1.113730.3.1.536 bin single
+
+#
+# Attribute types with OIDs
+#
+
+attribute associatedDomain 0.9.2342.19200300.100.1.37 cis
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis single
+
+
+#
+# Attributes which are used by some objectClass, but with unknown OID
+#
+
+attribute abstract abstract-oid cis
+attribute authorCn documentauthorcommonname authorcn-oid cis
+attribute authorSn documentauthorsurname authorsn-oid cis
+attribute changeLog 2.16.840.1.113730.3.1.35 dn
+attribute changeLogMaximumAge 2.16.840.1.113730.3.1.200 cis
+attribute changeLogMaximumSize 2.16.840.1.113730.3.1.201 cis
+attribute documentStore documentStore-oid cis
+attribute keyWords keyWords-oid cis
+attribute lastModifiedTime 0.9.2342.19200300.100.1.23 cis
+attribute multiLineDescription multiLineDescription-oid cis
+attribute subject subject-oid cis
+attribute ttl timeToLive 1.3.6.1.4.1.250.1.60 cis
+attribute photo 0.9.2342.19200300.100.1.7 bin
+attribute generation generation-oid ces
+attribute obsoletedByDocument obsoletedByDocument-oid dn
+attribute obsoletesDocument obsoletesDocument-oid dn
+attribute reciprocalNamingLink reciprocalNaminglink-oid dn
+attribute updatedByDocument updatedByDocument-oid dn
+attribute updatesDocument updatesDocument-oid dn
+
+#
+# Attribute types from RFC 2307
+#
+
+attribute uidNumber 1.3.6.1.1.1.1.0 int single
+attribute gidNumber 1.3.6.1.1.1.1.1 int single
+attribute gecos 1.3.6.1.1.1.1.2 cis single
+attribute homeDirectory 1.3.6.1.1.1.1.3 ces single
+attribute loginShell 1.3.6.1.1.1.1.4 int single
+attribute shadowLastChange 1.3.6.1.1.1.1.5 int single
+attribute shadowMin 1.3.6.1.1.1.1.6 int single
+attribute shadowMax 1.3.6.1.1.1.1.7 int single
+attribute shadowWarning 1.3.6.1.1.1.1.8 int single
+attribute shadowInactive 1.3.6.1.1.1.1.9 int single
+attribute shadowExpire 1.3.6.1.1.1.1.10 int single
+attribute shadowFlag 1.3.6.1.1.1.1.11 int single
+attribute memberUid 1.3.6.1.1.1.1.12 ces
+attribute memberNisNetgroup 1.3.6.1.1.1.1.13 ces
+attribute nisNetgroupTriple 1.3.6.1.1.1.1.14 ces
+attribute ipServicePort 1.3.6.1.1.1.1.15 int single
+attribute ipServiceProtocol 1.3.6.1.1.1.1.16 cis
+attribute ipProtocolNumber 1.3.6.1.1.1.1.17 int single
+attribute oncRpcNumber 1.3.6.1.1.1.1.18 int single
+attribute ipHostNumber 1.3.6.1.1.1.1.19 cis
+attribute ipNetworkNumber 1.3.6.1.1.1.1.20 cis single
+attribute ipNetmaskNumber 1.3.6.1.1.1.1.21 cis single
+attribute macAddress 1.3.6.1.1.1.1.22 cis
+attribute bootParameter 1.3.6.1.1.1.1.23 ces
+attribute bootFile 1.3.6.1.1.1.1.24 ces
+attribute automountInformation 1.3.6.1.1.1.1.25 ces
+attribute nisMapName 1.3.6.1.1.1.1.26 cis
+attribute nisMapEntry 1.3.6.1.1.1.1.27 ces single
diff --git a/ldap/cm/v4confs/411/slapd.oc.conf b/ldap/cm/v4confs/411/slapd.oc.conf
new file mode 100644
index 00000000..1e8c451b
--- /dev/null
+++ b/ldap/cm/v4confs/411/slapd.oc.conf
@@ -0,0 +1,1069 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.oc.conf for Netscape Directory Server 4.1
+#
+# DO NOT MODIFY!
+#
+# The ObjectClasses in this file are Standard ObjectClasses and are expected
+# to be present in Directory Server 4.1 unchanged. Modifing this file may
+# cause interoperability problems.
+#
+# User Defined ObjectClasses should be added by selecting
+# Schema | Create ObjectClasses from the Admin Server.
+#
+# User Defined ObjectClasses are saved in slapd.user_oc.conf
+#
+# All ObjectClasses are viewable in the cn=schema entry under objectclasses.
+#
+# The format of this file is:
+#
+# objectclass ObjectClassName
+# [ oid ObjectIdentifier ]
+# [ superior ParentObjectClass ]
+# [ requires <comma separated list of required attributes> ]
+# [ allows <comma separated list of allowed attributes> ]
+#
+
+objectclass top
+ oid 2.5.6.0
+ requires
+ objectClass
+ allows
+ aci
+
+objectclass alias
+ oid 2.5.6.1
+ superior top
+ requires
+ aliasedObjectName
+
+objectclass country
+ oid 2.5.6.2
+ superior top
+ requires
+ c
+ allows
+ searchGuide,
+ description
+
+objectclass locality
+ oid 2.5.6.3
+ superior top
+ allows
+ description,
+ l,
+ searchGuide,
+ seeAlso,
+ st,
+ street
+
+objectclass organization
+ oid 2.5.6.4
+ superior top
+ requires
+ o
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass organizationalUnit
+ oid 2.5.6.5
+ superior top
+ requires
+ ou
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass person
+ oid 2.5.6.6
+ superior top
+ requires
+ sn,
+ cn
+ allows
+ description,
+ seeAlso,
+ telephoneNumber,
+ userPassword
+
+objectclass organizationalPerson
+ oid 2.5.6.7
+ superior person
+ allows
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ title,
+ x121Address
+
+# The certificate attributes include all subtypes, such as ';binary'.
+#
+objectclass inetOrgPerson
+ oid 2.16.840.1.113730.3.2.2
+ superior organizationalPerson
+ allows
+ audio,
+ businessCategory,
+ carLicense,
+ departmentNumber,
+ displayName,
+ employeeType,
+ employeeNumber,
+ givenName,
+ homePhone,
+ homePostalAddress,
+ initials,
+ jpegPhoto,
+ labeledURI,
+ manager,
+ mobile,
+ pager,
+ photo,
+ preferredLanguage,
+ mail,
+ o,
+ roomNumber,
+ secretary,
+ uid,
+ x500uniqueIdentifier,
+ userCertificate,
+ userSMimeCertificate,
+ userPKCS12
+
+objectclass ntUser
+ oid 2.16.840.1.113730.3.2.8
+ superior top
+ requires
+ ntUserDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntUserPriv,
+ ntUserHomeDir,
+ ntUserComment,
+ ntUserFlags,
+ ntUserScriptPath,
+ ntUserAuthFlags,
+ ntUserUsrComment,
+ ntUserParms,
+ ntUserWorkstations,
+ ntUserLastLogon,
+ ntUserLastLogoff,
+ ntUserAcctExpires,
+ ntUserMaxStorage,
+ ntUserUnitsPerWeek,
+ ntUserLogonHours,
+ ntUserBadPwCount,
+ ntUserNumLogons,
+ ntUserLogonServer,
+ ntUserCountryCode,
+ ntUserCodePage,
+ ntUserUniqueId,
+ ntUserPrimaryGroupId,
+ ntUserProfile,
+ ntUserHomeDirDrive,
+ ntUserPasswordExpired,
+ ntUserCreateNewAccount,
+ ntUserDeleteAccount
+
+objectclass ntGroup
+ oid 2.16.840.1.113730.3.2.9
+ superior top
+ requires
+ ntGroupDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntGroupId,
+ ntGroupAttributes,
+ ntGroupCreateNewGroup,
+ ntGroupDeleteGroup,
+ ntGroupType
+
+objectclass organizationalRole
+ oid 2.5.6.8
+ superior top
+ requires
+ cn
+ allows
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ roleOccupant,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass groupOfNames
+ oid 2.5.6.9
+ superior top
+ requires
+ cn
+ allows
+ member,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfUniqueNames
+ oid 2.5.6.17
+ superior top
+ requires
+ cn
+ allows
+ uniqueMember,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfCertificates
+ oid 2.16.840.1.113730.3.2.31
+ superior top
+ requires
+ cn
+ allows
+ memberCertificateDescription,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfURLs
+ oid 2.16.840.1.113730.3.2.33
+ superior top
+ requires
+ cn
+ allows
+ memberURL,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass residentialPerson
+ oid 2.5.6.10
+ superior person
+ requires
+ l
+ allows
+ businessCategory,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass applicationProcess
+ oid 2.5.6.11
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso
+
+objectclass LDAPServer
+ oid 2.16.840.1.113730.3.2.35
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ generation,
+ changeLogMaximumAge,
+ changeLogMaximumSize
+
+objectclass LDAPReplica
+ oid 2.16.840.1.113730.3.2.36
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ replicaRoot,
+ replicaHost,
+ replicaPort,
+ replicaBindDn,
+ replicaCredentials,
+ replicaBindMethod,
+ replicaUseSSL,
+ replicaUpdateSchedule,
+ replicaUpdateReplayed,
+ replicaUpdateFailedAt,
+ replicaBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList,
+ replicaCFUpdated,
+ replicaAbandonedChanges,
+ replicaLastRelevantChange
+
+objectclass applicationEntity
+ oid 2.5.6.12
+ superior top
+ requires
+ presentationAddress,
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ supportedApplicationContext
+
+objectclass dSA
+ oid 2.5.6.13
+ superior applicationEntity
+ allows
+ knowledgeInformation
+
+objectclass device
+ oid 2.5.6.14
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# This userCertificate attribute includes all subtypes, such as ';binary'.
+objectclass strongAuthenticationUser
+ oid 2.5.6.15
+ superior top
+ requires
+ userCertificate
+
+# These attributes include all subtypes, such as ';binary'.
+objectclass certificationAuthority
+ oid 2.5.6.16
+ superior top
+ requires
+ cACertificate
+ allows
+ authorityRevocationList,
+ certificateRevocationList,
+ crossCertificatePair
+
+objectclass pilotObject
+ oid 0.9.2342.19200300.100.4.3
+ superior top
+ allows
+ audio,
+ dITRedirect,
+ info,
+ jpegPhoto,
+ lastModifiedBy,
+ lastModifiedTime,
+ manager,
+ photo,
+ uniqueIdentifier
+
+objectclass newPilotPerson
+ oid 0.9.2342.19200300.100.4.4
+ superior person
+ allows
+ businessCategory,
+ drink,
+ homePhone,
+ homePostalAddress,
+ janetMailbox,
+ mail,
+ mailPreferenceOption,
+ mobile,
+ organizationalStatus,
+ otherMailbox,
+ pager,
+ personalSignature,
+ personalTitle,
+ preferredDeliveryMethod,
+ roomNumber,
+ secretary,
+ textEncodedORAddress,
+ uid,
+ userClass
+
+objectclass account
+ oid 0.9.2342.19200300.100.4.5
+ superior top
+ requires
+ uid
+ allows
+ description,
+ host,
+ l,
+ o,
+ ou,
+ seeAlso
+
+objectclass document
+ oid 0.9.2342.19200300.100.4.6
+ superior pilotObject
+ requires
+ documentIdentifier
+ allows
+ abstract,
+ authorCN,
+ authorSN,
+ cn,
+ description,
+ documentAuthor,
+ documentLocation,
+ documentPublisher,
+ documentStore,
+ documentTitle,
+ documentVersion,
+ keywords,
+ l,
+ o,
+ obsoletedByDocument,
+ obsoletesDocument,
+ ou,
+ seeAlso,
+ subject,
+ updatedByDocument,
+ updatesDocument
+
+objectclass room
+ oid 0.9.2342.19200300.100.4.7
+ superior top
+ requires
+ cn
+ allows
+ description,
+ roomNumber,
+ seeAlso,
+ telephoneNumber
+
+objectclass documentSeries
+ oid 0.9.2342.19200300.100.4.9
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ telephoneNumber
+
+objectclass domain
+ oid 0.9.2342.19200300.100.4.13
+ superior top
+ requires
+ dc
+ allows
+ associatedName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ manager,
+ o,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass RFC822localPart
+ oid 0.9.2342.19200300.100.4.14
+ superior domain
+ allows
+ cn,
+ sn
+
+objectclass DNSDomain
+ oid 0.9.2342.19200300.100.4.15
+ superior domain
+ allows
+ dNSRecord
+
+objectclass domainRelatedObject
+ oid 0.9.2342.19200300.100.4.17
+ superior top
+ requires
+ associatedDomain
+
+objectclass friendlyCountry
+ oid 0.9.2342.19200300.100.4.18
+ superior country
+ requires
+ co
+
+objectclass simpleSecurityObject
+ oid 0.9.2342.19200300.100.4.19
+ superior top
+ requires
+ userPassword
+
+objectclass pilotOrganization
+ oid pilotOrganization-OID
+ superior top
+ requires
+ ou,
+ o
+ allows
+ buildingName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+
+objectclass labeledURIObject
+ oid 1.3.6.1.4.1.250.3.15
+ superior top
+ allows
+ labeledURI
+
+objectclass cacheObject
+ oid 1.3.6.1.4.1.250.3.18
+ superior top
+ allows
+ ttl
+
+# objectclasses below added since Netscape Directory Server 1.01
+
+objectclass netscapeServer
+ oid 2.16.840.1.113730.3.2.10
+ superior top
+ requires
+ cn
+ allows
+ description,
+ serverRoot,
+ serverProductName,
+ serverVersionNumber,
+ installationTimeStamp,
+ administratorContactInfo,
+ userpassword,
+ adminURL,
+ serverHostName
+
+objectclass nsLicenseUser
+ oid 2.16.840.1.113730.3.2.7
+ superior top
+ allows
+ nsLicensedFor,
+ nsLicenseStartTime,
+ nsLicenseEndTime
+
+objectclass changeLogEntry
+ oid 2.16.840.1.113730.3.2.1
+ superior top
+ requires
+ targetdn,
+ changeTime,
+ changenumber,
+ changeType
+ allows
+ changes,
+ newrdn,
+ deleteoldrdn,
+ newsuperior,
+ filterinfo
+
+objectclass cirReplicaSource
+ oid 2.16.840.1.113730.3.2.11
+ requires
+ cn,
+ objectClass
+ allows
+ cirReplicaRoot,
+ cirHost,
+ cirPort,
+ cirBindDN,
+ cirUsePersistentSearch,
+ cirUseSSL,
+ cirBindCredentials,
+ cirLastUpdateApplied,
+ cirUpdateSchedule,
+ cirSyncInterval,
+ cirUpdateFailedAt,
+ cirBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList
+
+objectclass referral
+ superior top
+ oid 2.16.840.1.113730.3.2.6
+ allows
+ ref
+
+objectclass passwordObject
+ oid 2.16.840.1.113730.3.2.12
+ requires
+ objectClass
+ allows
+ passwordExpirationTime,
+ passwordExpWarned,
+ passwordRetryCount,
+ retryCountResetTime,
+ accountUnlockTime,
+ passwordHistory,
+ passwordAllowChangeTime
+
+objectclass passwordPolicy
+ oid 2.16.840.1.113730.3.2.13
+ requires
+ objectClass
+ allows
+ passwordMaxAge,
+ passwordExp,
+ passwordMinLength,
+ passwordKeepHistory,
+ passwordInHistory,
+ passwordChange,
+ passwordWarning,
+ passwordLockout,
+ passwordMaxFailure,
+ passwordResetDuration,
+ passwordUnlock,
+ passwordLockoutDuration,
+ passwordCheckSyntax,
+ passwordMustChange,
+ passwordStorageScheme,
+ passwordMinAge,
+ passwordResetFailureCount
+
+objectclass glue
+ oid 2.16.840.1.113730.3.2.30
+ superior top
+
+objectclass netscapeMachineData
+ oid 2.16.840.1.113730.3.2.32
+ superior top
+
+objectclass dcObject
+ oid 1.3.6.1.4.1.1466.344
+ superior top
+ requires
+ dc
+
+objectclass subschema
+ oid 2.5.20.1
+ superior top
+ allows
+ cn,
+ dITStructureRules,
+ nameForms,
+ dITContentRules,
+ objectClasses,
+ attributeTypes,
+ matchingRules,
+ matchingRuleUse
+
+objectclass vlvSearch
+ oid 2.16.840.1.113730.3.2.38
+ superior top
+ requires
+ cn,
+ vlvBase,
+ vlvScope,
+ vlvFilter
+ allows
+ multiLineDescription
+
+objectclass nsslapdConfig
+ oid 2.16.840.1.113730.3.2.39
+ superior top
+ allows cn
+
+objectclass directoryServerFeature
+ oid 2.16.840.1.113730.3.2.40
+ superior top
+ allows
+ oid,
+ cn,
+ multiLineDescription
+
+objectclass nsslapdPlugin
+ oid 2.16.840.1.113730.3.2.41
+ superior top
+ requires
+ cn,
+ nsslapd-pluginPath,
+ nsslapd-pluginInitFunc,
+ nsslapd-pluginType,
+ nsslapd-pluginId,
+ nsslapd-pluginVersion,
+ nsslapd-pluginVendor,
+ nsslapd-pluginDescription,
+ nsslapd-pluginEnabled,
+ nsslapd-backend
+
+objectclass vlvIndex
+ oid 2.16.840.1.113730.3.2.42
+ superior top
+ requires
+ cn,
+ vlvSort
+ allows
+ vlvEnabled,
+ vlvUses
+
+objectclass nsSNMP
+ OID 2.16.840.1.113730.3.2.43
+ superior top
+ requires
+ cn,
+ nsSNMPEnabled
+ allows
+ nsSNMPOrganization,
+ nsSNMPLocation,
+ nsSNMPContact,
+ nsSNMPDescription,
+ nsSNMPMasterHost,
+ nsSNMPMasterPort
+
+objectclass nsIndex
+ oid 2.16.840.1.113730.3.2.44
+ superior top
+ requires
+ cn,
+ nsSystemIndex
+ allows
+ description,
+ nsIndexType,
+ nsMatchingRule
+
+#
+# ojectclass from rfc2307
+#
+
+# posixAccount is an auxiliary class. You may use account as a structural
+# class.
+objectclass posixAccount
+ oid
+ 1.3.6.1.1.1.2.0
+ superior
+ top
+ requires
+ objectClass,
+ cn,
+ uid,
+ uidNumber,
+ gidNumber,
+ homeDirectory
+ allows
+ userPassword,
+ loginShell,
+ gecos,
+ description
+
+# posixAccount is an auxiliary class. You may use account as a structural
+# class.
+objectclass shadowAccount
+ oid
+ 1.3.6.1.1.1.2.1
+ superior
+ top
+ requires
+ objectClass,
+ uid
+ allows
+ userPassword,
+ shadowLastChange,
+ shadowMin,
+ shadowMax,
+ shadowWarning,
+ shadowInactive,
+ shadowExpire,
+ shadowFlag,
+ description
+
+objectclass posixGroup
+ oid
+ 1.3.6.1.1.1.2.2
+ requires
+ objectClass,
+ cn,
+ gidNumber
+ allows
+ userPassword,
+ memberUid,
+ description
+
+objectclass ipService
+ oid
+ 1.3.6.1.1.1.2.3
+ requires
+ objectClass,
+ cn,
+ ipServicePort,
+ ipServiceProtocol
+ allows
+ description
+
+objectclass ipProtocol
+ oid
+ 1.3.6.1.1.1.2.4
+ requires
+ objectClass,
+ cn,
+ ipProtocolNumber
+ allows
+ description
+
+objectclass oncRpc
+ oid
+ 1.3.6.1.1.1.2.5
+ requires
+ objectClass,
+ cn,
+ oncRpcNumber
+ allows
+ description
+
+# ipHost is a subclass of device
+objectclass ipHost
+ oid
+ 1.3.6.1.1.1.2.6
+ requires
+ objectClass,
+ ipHostNumber,
+ cn
+ allows
+ manager,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+
+objectclass ipNetwork
+ oid
+ 1.3.6.1.1.1.2.7
+ requires
+ objectClass,
+ ipNetworkNumber,
+ cn
+ allows
+ ipNetmaskNumber,
+ manager,
+ l,
+ description
+
+objectclass nisNetgroup
+ oid
+ 1.3.6.1.1.1.2.8
+ requires
+ objectClass,
+ cn
+ allows
+ nisNetgroupTriple,
+ memberNisNetgroup,
+ description
+
+# the automount class is deprecated. Because cn is case insensitive
+# on matches, you may need to use another object class to unique
+# names.
+objectclass automount
+ oid
+ 1.3.6.1.1.1.2.9
+ requires
+ objectClass,
+ cn,
+ automountInformation
+ allows
+ description
+
+# nisObject represents entries in NIS maps.
+objectclass nisObject
+ oid
+ 1.3.6.1.1.1.2.10
+ requires
+ objectClass,
+ cn,
+ nisMapEntry,
+ nisMapName
+ allows
+ description
+
+# ieee802Device is a subclass of device
+objectclass ieee802Device
+ oid
+ 1.3.6.1.1.1.2.11
+ requires
+ objectClass,
+ cn
+ allows
+ macAddress,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# bootableDevice is a subclass of device
+objectclass bootableDevice
+ oid
+ 1.3.6.1.1.1.2.12
+ requires
+ objectClass,
+ cn
+ allows
+ bootFile,
+ bootParameter,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# nisMap is a structural class which may be used as a container
+# for instances of nisObject.
+objectclass nisMap
+ oid
+ 1.3.6.1.1.1.2.13
+ requires
+ objectClass,
+ nisMapName
+ allows
+ description
+
diff --git a/ldap/cm/v4confs/412/java-object-schema.conf b/ldap/cm/v4confs/412/java-object-schema.conf
new file mode 100644
index 00000000..1ba36b8c
--- /dev/null
+++ b/ldap/cm/v4confs/412/java-object-schema.conf
@@ -0,0 +1,58 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Schema for storing java objects and java object references
+
+attribute javaClassName 1.3.6.1.4.1.42.2.27.4.1.6 ces single
+
+attribute javaCodebase 1.3.6.1.4.1.42.2.27.4.1.7 ces
+
+attribute javaSerializedData 1.3.6.1.4.1.42.2.27.4.1.8 bin single
+
+attribute javaFactory 1.3.6.1.4.1.42.2.27.4.1.10 ces single
+
+attribute javaReferenceAddress 1.3.6.1.4.1.42.2.27.4.1.11 ces
+
+attribute javaDoc 1.3.6.1.4.1.42.2.27.4.1.12 ces
+
+attribute javaClassNames 1.3.6.1.4.1.42.2.27.4.1.13 ces
+
+objectclass javaContainer
+ oid 1.3.6.1.4.1.42.2.27.4.2.1
+ superior top
+ requires
+ cn
+
+objectclass javaObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.4
+ superior top
+ requires
+ javaClassName
+ allows
+ javaClassNames,
+ javaCodebase,
+ javaDoc,
+ description
+
+objectclass javaSerializedObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.5
+ superior javaObject
+ requires
+ javaSerializedData
+
+objectclass javaNamingReference
+ oid 1.3.6.1.4.1.42.2.27.4.2.7
+ superior javaObject
+ allows
+ javaReferenceAddress,
+ javaFactory
+
+objectclass javaMarshalledObject
+ oid 1.3.6.1.4.1.42.2.27.4.2.8
+ superior javaObject
+ requires
+ javaSerializedData
diff --git a/ldap/cm/v4confs/412/ns-admin-schema.conf b/ldap/cm/v4confs/412/ns-admin-schema.conf
new file mode 100644
index 00000000..6bd0a9d0
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-admin-schema.conf
@@ -0,0 +1,155 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Netscape Administration Server LDAP Schema configuration file
+#
+# Version: 4.1
+# Description:
+# Administration Server and Mission Control Console attributes
+# and objectclasses.
+#
+
+#############################################################
+# Attributes
+#############################################################
+
+#
+# nsAdminConfig
+#
+attribute nsAdminCgiWaitPid cis
+attribute nsAdminUsers cis
+attribute nsAdminAccessHosts cis
+attribute nsAdminAccessAddresses cis
+attribute nsAdminOneACLDir cis
+attribute nsAdminEnableDSGW cis
+attribute nsAdminEnableEnduser cis
+attribute nsAdminCacheLifetime cis
+
+
+#
+# nsAdminResourceEditorExtension
+#
+attribute nsAdminAccountInfo cis
+attribute nsDeleteclassname cis
+
+#
+# nsAdminGlobalParameters
+#
+attribute nsAdminEndUserHTMLIndex cis
+
+#
+# nsGlobalParameters
+#
+attribute nsUniqueAttribute cis
+attribute nsUserIDFormat cis
+attribute nsUserRDNComponent cis
+attribute nsGroupRDNComponent cis
+attribute nsWellKnownJarfiles cis
+attribute nsNYR cis
+
+#
+# nsDefaultObjectClasses
+#
+attribute nsDefaultObjectClass cis
+
+#
+# nsAdminConsoleUser
+#
+attribute nsPreference cis
+
+#
+# nsCustomView
+#
+attribute nsDisplayName cis
+
+#
+# nsTopologyCustomView
+#
+attribute nsViewConfiguration cis
+
+#############################################################
+# Objectclasses
+#############################################################
+
+objectclass nsAdminServer
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description
+
+objectclass nsAdminConfig
+ superior nsConfig
+ allows
+ nsAdminCgiWaitPid,
+ nsAdminUsers,
+ nsAdminAccessHosts,
+ nsAdminAccessAddresses,
+ nsAdminOneACLDir,
+ nsAdminEnableDSGW,
+ nsAdminEnableEnduser,
+ nsAdminCacheLifetime
+
+objectclass nsAdminResourceEditorExtension
+ superior nsAdminObject
+ requires
+ cn
+ allows
+ nsAdminAccountInfo,
+ nsDeleteclassname
+
+objectclass nsAdminGlobalParameters
+ superior top
+ requires
+ cn
+ allows
+ nsAdminEndUserHTMLIndex,
+ nsNickname
+
+objectclass nsGlobalParameters
+ superior top
+ requires
+ cn
+ allows
+ nsUniqueAttribute,
+ nsUserIDFormat,
+ nsUserRDNComponent,
+ nsGroupRDNComponent,
+ nsWellKnownJarFiles,
+ nsNYR
+
+objectclass nsDefaultObjectClasses
+ superior top
+ requires
+ cn
+ allows
+ nsDefaultObjectClass
+
+objectclass nsAdminConsoleUser
+ superior top
+ requires
+ cn
+ allows
+ nsPreference
+
+objectclass nsCustomView
+ superior nsAdminObject
+ allows
+ nsDisplayName,
+
+objectclass nsTopologyCustomView
+ superior nsCustomView
+ requires
+ cn
+ allows
+ nsViewConfiguration
+
+objectclass nsTopologyPlugin
+ superior nsAdminObject
+ allows
diff --git a/ldap/cm/v4confs/412/ns-calendar-globopt.conf b/ldap/cm/v4confs/412/ns-calendar-globopt.conf
new file mode 100644
index 00000000..0bdb7dd9
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-calendar-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+index nsCalXItemId pres,eq,sub
diff --git a/ldap/cm/v4confs/412/ns-calendar-schema.conf b/ldap/cm/v4confs/412/ns-calendar-schema.conf
new file mode 100644
index 00000000..2a35ae3c
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-calendar-schema.conf
@@ -0,0 +1,148 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsCalAccess 2.16.840.1.113730.3.1.112 cis
+attribute nsCalAccessDomain 2.16.840.1.113730.3.1.113 cis
+attribute nsCalAdmd 2.16.840.1.113730.3.1.114 cis
+attribute nsCalDefaultNoteReminder 2.16.840.1.113730.3.1.115 cis
+attribute nsCalDefaultReminder 2.16.840.1.113730.3.1.116 cis
+attribute nsCalDefaultTaskReminder 2.16.840.1.113730.3.1.117 cis
+attribute nsCalDisplayPrefs 2.16.840.1.113730.3.1.118 cis
+attribute nsCalFlags 2.16.840.1.113730.3.1.119 cis
+attribute nsCalHost 2.16.840.1.113730.3.1.120 cis
+attribute nsCalLanguageId 2.16.840.1.113730.3.1.121 cis
+attribute nsCalNodeAlias 2.16.840.1.113730.3.1.122 cis
+attribute nsCalNotifMechanism 2.16.840.1.113730.3.1.123 cis
+attribute nsCalOperatingPrefs 2.16.840.1.113730.3.1.124 cis
+attribute nsCalOrgUnit2 2.16.840.1.113730.3.1.125 cis
+attribute nsCalOrgUnit3 2.16.840.1.113730.3.1.126 cis
+attribute nsCalOrgUnit4 2.16.840.1.113730.3.1.127 cis
+attribute nsCalPasswordRequired 2.16.840.1.113730.3.1.128 cis
+attribute nsCalPrmd 2.16.840.1.113730.3.1.129 cis
+attribute nsCalRefreshPrefs 2.16.840.1.113730.3.1.130 cis
+attribute nsCalResourceCapacity 2.16.840.1.113730.3.1.131 cis
+attribute nsCalResourceNumber 2.16.840.1.113730.3.1.132 cis
+attribute nsCalServerVersion 2.16.840.1.113730.3.1.133 cis
+attribute nsCalSysopCanWritePassword 2.16.840.1.113730.3.1.134 cis
+attribute nsCalTimezone 2.16.840.1.113730.3.1.135 cis
+attribute nsCalXItemId 2.16.840.1.113730.3.1.136 cis
+
+
+objectclass nsCalUser
+ oid 2.16.840.1.113730.3.2.14
+ requires
+ objectClass
+ allows
+ c,
+ employeeNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ mail,
+ o,
+ ou,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalRefreshPrefs,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass nsCalAdmin
+ oid 2.16.840.1.113730.3.2.15
+ requires
+ objectClass
+ allows
+ c,
+ cn,
+ facsimileTelephoneNumber,
+ generationQualifier,
+ givenName,
+ initials,
+ mail,
+ o,
+ ou,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalAdmd,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalOrgUnit2,
+ nsCalOrgUnit3,
+ nsCalOrgUnit4,
+ nsCalPasswordRequired,
+ nsCalPrmd,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalXItemId
+
+objectclass nsCalResource
+ oid 2.16.840.1.113730.3.2.16
+ requires
+ objectClass
+ allows
+ cn,
+ facsimileTelephoneNumber,
+ givenName,
+ mail,
+ postalAddress,
+ sn,
+ telephoneNumber,
+ userPassword,
+ nsCalAccess,
+ nsCalAccessDomain,
+ nsCalDefaultNoteReminder,
+ nsCalDefaultReminder,
+ nsCalDefaultTaskReminder,
+ nsCalDisplayPrefs,
+ nsCalFlags,
+ nsCalHost,
+ nsCalLanguageId,
+ nsCalNodeAlias,
+ nsCalNotifMechanism,
+ nsCalOperatingPrefs,
+ nsCalPasswordRequired,
+ nsCalRefreshPrefs,
+ nsCalResourceCapacity,
+ nsCalResourceNumber,
+ nsCalServerVersion,
+ nsCalSysopCanWritePassword,
+ nsCalTimezone,
+ nsCalXItemId
+
+objectclass netscapeCalendarServer
+ oid 2.16.840.1.113730.3.2.17
+ requires
+ objectclass
+
+
+
diff --git a/ldap/cm/v4confs/412/ns-certificate-globopt.conf b/ldap/cm/v4confs/412/ns-certificate-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-certificate-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/412/ns-certificate-schema.conf b/ldap/cm/v4confs/412/ns-certificate-schema.conf
new file mode 100644
index 00000000..a9ef7b9d
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-certificate-schema.conf
@@ -0,0 +1,24 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+attribute nsCertConfig cis
+
+objectclass netscapeCertificateServer
+ oid 2.16.840.1.113730.3.2.18
+ requires
+ objectclass
+
+objectclass nsCertificateServer
+ requires
+ objectclass,
+ nsServerID
+ allows
+ serverHostName,
+ nsServerPort,
+ nsCertConfig
+
+
diff --git a/ldap/cm/v4confs/412/ns-common-schema.conf b/ldap/cm/v4confs/412/ns-common-schema.conf
new file mode 100644
index 00000000..a8d7b00c
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-common-schema.conf
@@ -0,0 +1,246 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Common LDAP schema configuration file
+#
+# Version: 4.1
+# Description:
+# This configuration file contains objectclasses and attributes
+# common to the Mission Control Framework
+#
+
+#############################################################
+# Attributes
+#############################################################
+
+#
+# Common Attributes
+#
+attribute nsServerID cis
+attribute nsBaseDN cis
+attribute nsBindDN cis
+attribute nsBindPassword cis
+attribute nsServerPort cis
+attribute nsServerAddress cis
+attribute nsDirectoryInfoRef dn
+attribute nsDirectoryURL ces
+attribute nsDirectoryFailoverList ces
+#
+# nsAdminDomain
+#
+attribute nsAdminDomainName cis
+
+#
+# nsHost
+#
+attribute nsHostLocation cis
+attribute nsHardwarePlatform cis
+attribute nsOsVersion cis
+
+#
+# nsAdminGroup
+#
+attribute nsAdminGroupName cis
+attribute nsConfigRoot cis
+attribute nsAdminSIEDN dn
+
+#
+# nsApplication
+#
+attribute nsVendor cis
+attribute nsProductName cis
+attribute nsNickName cis
+attribute nsProductVersion cis
+attribute nsBuildNumber cis
+attribute nsRevisionNumber cis
+attribute nsSerialNumber cis
+attribute nsInstalledLocation cis
+attribute nsExpirationDate cis
+attribute nsBuildSecurity cis
+attribute nsServerMigrationClassname cis
+attribute nsServerCreationClassname cis
+attribute nsLdapSchemaVersion cis
+
+#
+# nsConfig
+#
+attribute nsSuiteSpotUser cis
+attribute nsErrorLog cis
+attribute nsPidLog cis
+attribute nsAccessLog cis
+attribute nsDefaultAcceptLanguage cis
+attribute nsServerSecurity cis
+
+#
+# nsEncryptionConfig
+#
+attribute nsCertfile cis
+attribute nsKeyfile cis
+attribute nsSSL2 cis
+attribute nsSSL3 cis
+attribute nsSSLClientAuth cis
+attribute nsSSLSessionTimeout cis
+attribute nsSSL3SessionTimeout cis
+attribute nsSSL2Ciphers cis
+attribute nsSSL3Ciphers cis
+
+#
+# nsEncryptionModule
+#
+attribute nsSSLToken cis
+attribute nsSSLPersonalitySSL cis
+attribute nsSSLActivation cis
+
+#
+# nsTask
+#
+attribute nsTaskLabel cis
+attribute nsHelpRef cis
+attribute nsExecRef cis
+attribute nsLogSuppress cis
+
+#
+# nsAdminObject
+#
+attribute nsJarfilename cis
+attribute nsClassname cis
+
+
+#############################################################
+# Object Classes
+#############################################################
+objectclass nsAdminDomain
+ superior organizationalUnit
+ allows
+ nsAdminDomainName
+
+objectclass nsHost
+ superior top
+ requires
+ cn
+ allows
+ serverHostName,
+ description,
+ l,
+ nsHostLocation,
+ nsHardwarePlatform,
+ nsOsVersion
+
+objectclass nsAdminGroup
+ superior top
+ requires
+ cn
+ allows
+ nsAdminGroupName,
+ description,
+ nsConfigRoot,
+ nsAdminSIEDN
+
+objectclass nsApplication
+ superior top
+ requires
+ cn
+ allows
+ nsVendor,
+ description,
+ nsProductName,
+ nsNickName,
+ nsProductVersion,
+ nsBuildNumber,
+ nsRevisionNumber,
+ nsSerialNumber,
+ nsInstalledLocation,
+ installationTimeStamp,
+ nsExpirationDate,
+ nsBuildSecurity,
+ nsLdapSchemaVersion,
+ nsServerMigrationClassname,
+ nsServerCreationClassname
+
+objectclass nsEncryptionConfig
+ superior top
+ requires
+ cn
+ allows
+ nsCertfile,
+ nsKeyfile,
+ nsSSL2,
+ nsSSL3,
+ nsSSLSessionTimeout,
+ nsSSL3SessionTimeout,
+ nsSSLClientAuth,
+ nsSSL2Ciphers,
+ nsSSL3Ciphers
+
+objectclass nsEncryptionModule
+ superior top
+ requires
+ cn
+ allows
+ nsSSLToken,
+ nsSSLPersonalityssl,
+ nsSSLActivation
+
+
+objectclass nsResourceRef
+ superior top
+ requires
+ cn
+ allows
+ seeAlso
+
+objectclass nsTask
+ superior top
+ requires
+ cn
+ allows
+ nsTaskLabel,
+ nsHelpref,
+ nsExecref,
+ nsLogSuppress
+
+objectclass nsTaskGroup
+ superior top
+ requires
+ cn
+ allows
+ nsTaskLabel
+
+objectclass nsAdminObject
+ superior top
+ requires
+ cn
+ allows
+ nsJarFilename,
+ nsClassName
+
+objectclass nsConfig
+ superior top
+ requires
+ cn
+ allows
+ description,
+ nsServerPort,
+ nsServerAddress,
+ nsSuiteSpotUser,
+ nsErrorLog,
+ nsPidLog,
+ nsAccessLog,
+ nsDefaultAcceptLanguage,
+ nsServerSecurity
+
+objectclass nsDirectoryInfo
+ superior top
+ requires
+ cn
+ allows
+ nsBindDN,
+ nsBindPassword,
+ nsDirectoryURL,
+ nsDirectoryFailoverList,
+ nsDirectoryInfoRef
diff --git a/ldap/cm/v4confs/412/ns-compass-globopt.conf b/ldap/cm/v4confs/412/ns-compass-globopt.conf
new file mode 100644
index 00000000..4d2e1e21
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-compass-globopt.conf
@@ -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
+#
+# Used by Netscape Directory Server
+index pipuid pres,eq,sub
+index pipstatus eq
+
diff --git a/ldap/cm/v4confs/412/ns-compass-schema.conf b/ldap/cm/v4confs/412/ns-compass-schema.conf
new file mode 100644
index 00000000..be13bc44
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-compass-schema.conf
@@ -0,0 +1,173 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+
+# Compass server specific (not currently used)
+
+objectclass netscapeCompassServer
+ oid 2.16.840.1.113730.3.2.19
+ requires
+ objectclass
+
+
+# Attributes for personal interest profile classes
+
+attribute pipuid 2.16.840.1.113730.3.1.137 cis
+attribute pipcompassservers 2.16.840.1.113730.3.1.138 cis
+attribute pipuniqueid 2.16.840.1.113730.3.1.139 cis
+attribute pipstatus 2.16.840.1.113730.3.1.140 cis
+attribute pipusertype 2.16.840.1.113730.3.1.141 cis
+attribute pipfrequency 2.16.840.1.113730.3.1.142 cis
+attribute pipmedium 2.16.840.1.113730.3.1.143 cis
+attribute pipformat 2.16.840.1.113730.3.1.144 cis
+attribute piphour 2.16.840.1.113730.3.1.145 cis
+attribute pipmaxhits 2.16.840.1.113730.3.1.146 cis
+attribute pipresultset 2.16.840.1.113730.3.1.147 cis
+attribute pipsortorder 2.16.840.1.113730.3.1.148 cis
+attribute piptimestamp 2.16.840.1.113730.3.1.149 cis
+attribute pipirlist 2.16.840.1.113730.3.1.150 cis
+attribute pipiroption 2.16.840.1.113730.3.1.151 cis
+attribute pippwp 2.16.840.1.113730.3.1.152 cis
+attribute piplastcount 2.16.840.1.113730.3.1.153 cis
+attribute piptotalcount 2.16.840.1.113730.3.1.154 cis
+attribute piptotalrun 2.16.840.1.113730.3.1.155 cis
+attribute pipnotify 2.16.840.1.113730.3.1.156 cis
+attribute pipprivilege 2.16.840.1.113730.3.1.157 cis
+attribute pipgroup 2.16.840.1.113730.3.1.158 cis
+attribute pipidstcount 2.16.840.1.113730.3.1.159 cis
+attribute pipstid 2.16.840.1.113730.3.1.160 cis
+attribute pipstname 2.16.840.1.113730.3.1.161 cis
+attribute pipstquery 2.16.840.1.113730.3.1.162 cis
+attribute pipsttaxonomy 2.16.840.1.113730.3.1.163 cis
+attribute pipstinterest 2.16.840.1.113730.3.1.164 cis
+attribute pipsttype 2.16.840.1.113730.3.1.165 cis
+attribute pipstprivacy 2.16.840.1.113730.3.1.166 cis
+attribute pipststatus 2.16.840.1.113730.3.1.167 cis
+attribute pipstlastcount 2.16.840.1.113730.3.1.168 cis
+attribute pipsttotalcount 2.16.840.1.113730.3.1.169 cis
+attribute pipsttotalrun 2.16.840.1.113730.3.1.170 cis
+attribute pipstcategory 2.16.840.1.113730.3.1.171 cis
+attribute pipstfrequency 2.16.840.1.113730.3.1.172 cis
+attribute pipstmedium 2.16.840.1.113730.3.1.173 cis
+attribute pipstformat 2.16.840.1.113730.3.1.174 cis
+attribute pipsthour 2.16.840.1.113730.3.1.175 cis
+attribute pipstmaxhits 2.16.840.1.113730.3.1.176 cis
+attribute pipstresultset 2.16.840.1.113730.3.1.177 cis
+attribute pipstsortorder 2.16.840.1.113730.3.1.178 cis
+attribute pipsttimestamp 2.16.840.1.113730.3.1.179 cis
+attribute pipstirlist 2.16.840.1.113730.3.1.180 cis
+attribute pipstiroption 2.16.840.1.113730.3.1.181 cis
+attribute pipreservedcis1 2.16.840.1.113730.3.1.182 cis
+attribute pipreservedcis2 2.16.840.1.113730.3.1.183 cis
+attribute pipreservedcis3 2.16.840.1.113730.3.1.184 cis
+attribute pipreservedcis4 2.16.840.1.113730.3.1.185 cis
+attribute pipreservedcis5 2.16.840.1.113730.3.1.186 cis
+attribute pipreservedcis6 2.16.840.1.113730.3.1.187 cis
+attribute pipreservedces1 2.16.840.1.113730.3.1.188 ces
+attribute pipreservedces2 2.16.840.1.113730.3.1.189 ces
+attribute pipreservedces3 2.16.840.1.113730.3.1.190 ces
+
+
+# Each interest profile is one of these and sits under the compass SIE
+
+objectclass personalInterestProfile
+ oid 2.16.840.1.113730.3.2.20
+ requires
+ objectclass,
+ pipuid
+ allows
+ pipuniqueid,
+ pipstatus,
+ pipusertype,
+ pipfrequency,
+ pipmedium,
+ pipformat,
+ piphour,
+ pipmaxhits,
+ pipresultset,
+ pipsortorder,
+ piptimestamp,
+ pipirlist,
+ pipiroption,
+ pippwp,
+ piplastcount,
+ piptotalcount,
+ piptotalrun,
+ pipnotify,
+ pipprivilege,
+ pipgroup,
+ pipidstcount,
+ pipstid,
+ pipstname,
+ pipstquery,
+ pipsttaxonomy,
+ pipstinterest,
+ pipsttype,
+ pipstprivacy,
+ pipststatus,
+ pipstlastcount,
+ pipsttotalcount,
+ pipsttotalrun,
+ pipstcategory,
+ pipstfrequency,
+ pipstmedium,
+ pipstformat,
+ pipsthour,
+ pipstmaxhits,
+ pipstresultset,
+ pipstsortorder,
+ pipsttimestamp,
+ pipstirlist,
+ pipstiroption,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
+
+# Replication of user info for template users, completeness, etc.
+# (not currently used)
+
+objectclass PIPUserInfo
+ oid 2.16.840.1.113730.3.2.21
+ requires
+ objectclass
+ allows
+ cn,
+ mail,
+ userPassword,
+ description,
+ pipcompassservers,
+ pipuniqueid
+
+
+# Enhancements to a normal user entry (not currently used)
+
+objectclass PIPUser
+ oid 2.16.840.1.113730.3.2.22
+ requires
+ objectclass
+ allows
+ pipuniqueid,
+ pipcompassservers,
+ pipreservedcis1,
+ pipreservedcis2,
+ pipreservedcis3,
+ pipreservedcis4,
+ pipreservedcis5,
+ pipreservedcis6,
+ pipreservedces1,
+ pipreservedces2,
+ pipreservedces3
+
diff --git a/ldap/cm/v4confs/412/ns-cos-schema.conf b/ldap/cm/v4confs/412/ns-cos-schema.conf
new file mode 100644
index 00000000..3d0f9f1a
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-cos-schema.conf
@@ -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
+#
+# Attributes used by Class of Service
+
+attribute cosAttribute 2.16.840.1.113730.3.1.550 cis
+attribute cosSpecifier 2.16.840.1.113730.3.1.551 cis
+attribute cosTargetTree 2.16.840.1.113730.3.1.552 cis
+attribute cosTemplateDn 2.16.840.1.113730.3.1.553 cis
+
+# Object classes used by Class of Service
+
+objectclass cosDefinition
+ oid 2.16.840.1.113730.3.2.84
+ superior top
+ requires
+ objectclass
+ allows
+ aci,
+ cn,
+ uid,
+ costargettree,
+ costemplatedn,
+ cosspecifier,
+ cosattribute
diff --git a/ldap/cm/v4confs/412/ns-delegated-admin-schema.conf b/ldap/cm/v4confs/412/ns-delegated-admin-schema.conf
new file mode 100644
index 00000000..788c156f
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-delegated-admin-schema.conf
@@ -0,0 +1,114 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#############################################################
+# Delegated User Administration Attributes
+#############################################################
+
+attribute nsNumUsers 2.16.840.1.113730.3.1.554 int single
+attribute nsMaxUsers 2.16.840.1.113730.3.1.555 int single
+attribute nsNumDepts 2.16.840.1.113730.3.1.556 int single
+attribute nsMaxDepts 2.16.840.1.113730.3.1.557 int single
+attribute nsNumMailLists 2.16.840.1.113730.3.1.558 int single
+attribute nsMaxMailLists 2.16.840.1.113730.3.1.559 int single
+attribute nsNumDomains 2.16.840.1.113730.3.1.560 int single
+attribute nsMaxDomains 2.16.840.1.113730.3.1.561 int single
+attribute nsDefaultMaxDeptSize 2.16.840.1.113730.3.1.562 int single
+attribute nsdaCapability 2.16.840.1.113730.3.1.563 cis
+attribute nsSearchFilter 2.16.840.1.113730.3.1.564 cis single
+attribute nsdaModifiableBy 2.16.840.1.113730.3.1.565 dn
+attribute memberOf 1.2.840.113556.1.2.102 dn
+attribute nsDADomain 2.16.840.1.113730.3.1.600 cis single
+attribute adminRole 2.16.840.1.113730.3.1.601 cis
+
+#############################################################
+# Delegated User Administration Objectclasses
+#############################################################
+
+objectclass nsManagedISP
+ oid 2.16.840.1.113730.3.2.85
+ superior top
+ allows
+ nsNumDomains
+
+objectclass nsManagedDomain
+ oid 2.16.840.1.113730.3.2.86
+ superior top
+ allows
+ nsNumUsers,
+ nsMaxUsers,
+ nsNumDepts,
+ nsMaxDepts,
+ nsNumMailLists,
+ nsMaxMailLists,
+ nsNumDomains,
+ nsMaxDomains,
+ nsDefaultMaxDeptSize,
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedOrgUnit
+ oid 2.16.840.1.113730.3.2.87
+ superior top
+ allows
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedDept
+ oid 2.16.840.1.113730.3.2.88
+ superior groupOfUniqueNames
+ allows
+ nsNumUsers,
+ nsMaxUsers,
+ nsNumDepts,
+ nsMaxDepts,
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedFamilyGroup
+ oid 2.16.840.1.113730.3.2.89
+ superior top
+ allows
+ nsNumUsers,
+ nsMaxUsers,
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedMailList
+ oid 2.16.840.1.113730.3.2.90
+ superior top
+ allows
+ nsNumUsers,
+ nsMaxUsers,
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedPerson
+ oid 2.16.840.1.113730.3.2.91
+ superior top
+ allows
+ memberOf,
+ nsdaDomain,
+ nsdaCapability,
+ nsSearchFilter,
+ owner,
+ nsdaModifiableBy
+
+objectclass nsManagedDeptAdminGroup
+ oid 2.16.840.1.113730.3.2.111
+ superior top
+
+objectclass inetAdmin
+ oid 2.16.840.1.113730.3.2.112
+ superior top
+ allows
+ memberOf,
+ adminRole
+
+objectclass nsUniquenessDomain
+ oid 2.16.840.1.113730.3.2.115
+ superior top
diff --git a/ldap/cm/v4confs/412/ns-directory-globopt.conf b/ldap/cm/v4confs/412/ns-directory-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-directory-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/412/ns-directory-schema.conf b/ldap/cm/v4confs/412/ns-directory-schema.conf
new file mode 100644
index 00000000..d928081f
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-directory-schema.conf
@@ -0,0 +1,27 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsSecureServerPort cis
+
+objectclass netscapeDirectoryServer
+ oid 2.16.840.1.113730.3.2.23
+ requires
+ objectclass
+
+objectclass nsDirectoryServer
+ requires
+ objectclass,
+ nsServerID
+ allows
+ serverHostName,
+ nsServerPort,
+ nsSecureServerPort,
+ nsBindPassword,
+ nsBindDN,
+ nsBaseDN
diff --git a/ldap/cm/v4confs/412/ns-legacy-schema.conf b/ldap/cm/v4confs/412/ns-legacy-schema.conf
new file mode 100644
index 00000000..4f7c4ac4
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-legacy-schema.conf
@@ -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
+#
+attribute url cis
+
+#use by Netscape Admin Server 4.1 for LegacyServers
+
+objectclass nsLegacyAdminGroup
+ superior
+ nsAdminGroup
+ allows
+ adminUrl
+
+objectclass nsLegacyApplication
+ superior
+ nsApplication
+ allows
+
+objectclass nsLegacyAdminServer
+ superior
+ nsAdminServer
+ allows
+
+objectclass nsLegacyServer
+ superior
+ netscapeServer
+ allows
+ nsServerID,
+ url
diff --git a/ldap/cm/v4confs/412/ns-mail-globopt.conf b/ldap/cm/v4confs/412/ns-mail-globopt.conf
new file mode 100644
index 00000000..2e6cac65
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-mail-globopt.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Messaging Server
+index mailAlternateAddress eq
+index mailHost eq
+#index uid,mail eq
+#index uniquemember,member eq
diff --git a/ldap/cm/v4confs/412/ns-mail-schema.conf b/ldap/cm/v4confs/412/ns-mail-schema.conf
new file mode 100644
index 00000000..ca0fdc5d
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-mail-schema.conf
@@ -0,0 +1,144 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+attribute mailAccessDomain 2.16.840.1.113730.3.1.12 cis
+attribute mailAlternateAddress 2.16.840.1.113730.3.1.13 cis
+attribute mailAutoReplyMode 2.16.840.1.113730.3.1.14 cis
+attribute mailAutoReplyText 2.16.840.1.113730.3.1.15 cis
+attribute mailDeliveryOption 2.16.840.1.113730.3.1.16 cis
+attribute mailForwardingAddress 2.16.840.1.113730.3.1.17 cis
+attribute mailHost 2.16.840.1.113730.3.1.18 cis
+attribute mailQuota 2.16.840.1.113730.3.1.21 cis
+attribute mailRoutingAddress 2.16.840.1.113730.3.1.47 cis
+
+attribute mailMessageStore 2.16.840.1.113730.3.1.19 ces
+attribute mailProgramDeliveryInfo 2.16.840.1.113730.3.1.20 ces
+
+attribute nsmsgDisallowAccess ces
+
+attribute vacationstartdate cis
+attribute vacationenddate cis
+
+# mailRecipient is used to designate an LDAP entry as representing some
+# entity that can receive mail, e.g. a mail user or mail group.
+# Note: attributes 'mailAccessDomain' through 'userPassword' do not
+# belong to mailRecipient, but are included here for backward compatibility.
+objectClass mailRecipient
+ oid 2.16.840.1.113730.3.2.3
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mailAccessDomain,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota,
+ multiLineDescription,
+ uid,
+ userPassword
+
+attribute nswmExtendedUserPrefs 2.16.840.1.113730.3.1.520 cis
+
+# nsMessagingServerUser is used to designate an LDAP entry as representing a
+# Netscape Messaging Server user account. It is used in combination with
+# mailRecipient.
+objectClass nsMessagingServerUser
+ oid 2.16.840.113730.3.2.37
+ requires
+ objectClass
+ allows
+ cn,
+ mailAccessDomain,
+ mailAutoReplyMode,
+ mailAutoReplyText,
+ mailDeliveryOption,
+ mailForwardingAddress,
+ mailMessageStore,
+ mailProgramDeliveryInfo,
+ mailQuota,
+ nsmsgDisallowAccess,
+ nswmExtendedUserPrefs,
+ vacationstartdate,
+ vacationenddate
+
+attribute mgrpAllowedDomain 2.16.840.1.113730.3.1.23 cis
+attribute mgrpMsgRejectAction 2.16.840.1.113730.3.1.28 cis
+attribute mgrpRFC822MailMember 2.16.840.1.113730.3.1.30 cis
+attribute mgrpMsgMaxSize 2.16.840.1.113730.3.1.32 cis single
+attribute mgrpBroadcasterPolicy cis
+attribute mgrpNoDuplicateChecks cis single
+attribute mgrpRemoveHeader cis
+
+attribute mgrpAllowedBroadcaster 2.16.840.1.113730.3.1.22 ces
+attribute mgrpDeliverTo 2.16.840.1.113730.3.1.25 ces
+attribute mgrpErrorsTo 2.16.840.1.113730.3.1.26 ces single
+attribute mgrpModerator 2.16.840.1.113730.3.1.33 ces
+attribute mgrpMsgRejectText 2.16.840.1.113730.3.1.29 ces
+attribute mgrpAddHeader ces
+
+attribute mgrpApprovePassword ces single
+
+# mailGroup is used to designate an LDAP entry as representing a mail group
+# (mailing list). It is used in combination with mailRecipient.
+# Note: attributes 'mail' through 'mailRoutingAddress' belong to mailRecipient,
+# but are also included here for backward compatibility.
+objectClass mailGroup
+ oid 2.16.840.1.113730.3.2.4
+ requires
+ objectClass
+ allows
+ cn,
+ mail,
+ mailAlternateAddress,
+ mailHost,
+ mailRoutingAddress,
+ mgrpAddHeader,
+ mgrpAllowedBroadcaster,
+ mgrpAllowedDomain,
+ mgrpApprovePassword,
+ mgrpBroadcasterPolicy,
+ mgrpDeliverTo,
+ mgrpErrorsTo,
+ mgrpModerator,
+ mgrpMsgMaxSize,
+ mgrpMsgRejectAction,
+ mgrpMsgRejectText,
+ mgrpNoDuplicateChecks,
+ mgrpRemoveHeader,
+ mgrpRFC822MailMember,
+ owner
+
+attribute mailEnhancedUniqueMember 2.16.840.1.113730.3.1.31 dn
+
+objectClass groupOfMailEnhancedUniqueNames
+ oid 2.16.840.1.113730.3.2.5
+ requires
+ objectClass,
+ cn
+ allows
+ businessCategory,
+ description,
+ mailEnhancedUniqueMember,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectClass netscapeMailServer
+ oid 2.16.840.1.113730.3.2.24
+ requires
+ objectClass
+
diff --git a/ldap/cm/v4confs/412/ns-mcd-browser-schema.conf b/ldap/cm/v4confs/412/ns-mcd-browser-schema.conf
new file mode 100644
index 00000000..dd2e228f
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-mcd-browser-schema.conf
@@ -0,0 +1,179 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-browser-schema.conf
+#
+# Netscape Mission Control Desktop browser client schema
+# This schema is used to hold browser client preferences.
+#
+
+attribute nsBCStartupBrowser 2.16.840.1.113730.3.1.409 cis
+attribute nsBCStartupMail 2.16.840.1.113730.3.1.410 cis
+attribute nsBCStartupEditor 2.16.840.1.113730.3.1.411 cis
+attribute nsBCStartupCalendar 2.16.840.1.113730.3.1.412 cis
+attribute nsBCChromeButtonStyle 2.16.840.1.113730.3.1.413 cis
+attribute nsBCUseDocumentFonts 2.16.840.1.113730.3.1.414 cis
+attribute nsBCForegroundColor 2.16.840.1.113730.3.1.415 cis
+attribute nsBCBackgroundColor 2.16.840.1.113730.3.1.416 cis
+attribute nsBCAnchorColor 2.16.840.1.113730.3.1.417 cis
+attribute nsBCVisitedColor 2.16.840.1.113730.3.1.418 cis
+attribute nsBCUnderlineAnchors 2.16.840.1.113730.3.1.419 cis
+attribute nsBCUseDocumentColors 2.16.840.1.113730.3.1.420 cis
+attribute nsBCStartupPage 2.16.840.1.113730.3.1.421 cis
+attribute nsBCStartupHomePage 2.16.840.1.113730.3.1.422 cis
+attribute nsBCLinkExpiration 2.16.840.1.113730.3.1.423 cis
+attribute nsBCIntlAcceptLanguages 2.16.840.1.113730.3.1.424 cis
+attribute nsBCMimeType 2.16.840.1.113730.3.1.425 cis
+attribute nsBCMimeAllowAdd 2.16.840.1.113730.3.1.426 cis
+attribute nsBCMimeAllowEdit 2.16.840.1.113730.3.1.427 cis
+attribute nsBCMimeAllowRemove 2.16.840.1.113730.3.1.428 cis
+attribute nsBCRelatedEnabled 2.16.840.1.113730.3.1.429 cis
+attribute nsBCRelatedAutoload 2.16.840.1.113730.3.1.430 cis
+attribute nsBCRelatedDisabledForDomains 2.16.840.1.113730.3.1.431 cis
+attribute nsBCGoBrowsingEnabled 2.16.840.1.113730.3.1.432 cis
+attribute nsBCOfflineStartupState 2.16.840.1.113730.3.1.433 cis
+attribute nsBCOfflineSendUnsentMessages 2.16.840.1.113730.3.1.434 cis
+attribute nsBCOfflinePromptSynchOnExit 2.16.840.1.113730.3.1.435 cis
+attribute nsBCAlwaysLoadImages 2.16.840.1.113730.3.1.436 cis
+attribute nsBCEnableJava 2.16.840.1.113730.3.1.437 cis
+attribute nsBCEnableJavaScript 2.16.840.1.113730.3.1.438 cis
+attribute nsBCEnableStyleSheets 2.16.840.1.113730.3.1.439 cis
+attribute nsBCEmailAsFtpPassword 2.16.840.1.113730.3.1.440 cis
+attribute nsBCCookieBehavior 2.16.840.1.113730.3.1.441 cis
+attribute nsBCWarnAboutCookies 2.16.840.1.113730.3.1.442 cis
+attribute nsBCMemoryCacheSize 2.16.840.1.113730.3.1.443 cis
+attribute nsBCDiskCacheSize 2.16.840.1.113730.3.1.444 cis
+attribute nsBCCheckDocFrequency 2.16.840.1.113730.3.1.445 cis
+attribute nsBCProxyType 2.16.840.1.113730.3.1.446 cis
+attribute nsBCProxyHttp 2.16.840.1.113730.3.1.447 cis
+attribute nsBCProxySsl 2.16.840.1.113730.3.1.448 cis
+attribute nsBCProxyFtp 2.16.840.1.113730.3.1.449 cis
+attribute nsBCProxySocks 2.16.840.1.113730.3.1.450 cis
+attribute nsBCProxyGopher 2.16.840.1.113730.3.1.451 cis
+attribute nsBCProxyWais 2.16.840.1.113730.3.1.452 cis
+attribute nsBCNoProxiesOn 2.16.840.1.113730.3.1.453 cis
+attribute nsBCProxyAutoConfigUrl 2.16.840.1.113730.3.1.454 cis
+attribute nsBCAutoUpdateEnabled 2.16.840.1.113730.3.1.455 cis
+attribute nsBCAutoUpdateConfirmInstall 2.16.840.1.113730.3.1.456 cis
+
+
+objectclass nsBrowserClient
+ oid 2.16.840.1.113730.3.2.78
+ superior top
+ allows
+ nsBCStartupBrowser,
+ nsBCStartupMail,
+ nsBCStartupEditor,
+ nsBCStartupCalendar,
+ nsBCChromeButtonStyle,
+ nsBCUseDocumentFonts,
+ nsBCForegroundColor,
+ nsBCBackgroundColor,
+ nsBCAnchorColor,
+ nsBCVisitedColor,
+ nsBCUnderlineAnchors,
+ nsBCUseDocumentColors,
+ nsBCStartupPage,
+ nsBCStartupHomePage,
+ nsBCLinkExpiration,
+ nsBCIntlAcceptLanguages,
+ nsBCMimeType,
+ nsBCMimeAllowAdd,
+ nsBCMimeAllowEdit,
+ nsBCMimeAllowRemove,
+ nsBCRelatedEnabled,
+ nsBCRelatedAutoload,
+ nsBCRelatedDisabledForDomains,
+ nsBCGoBrowsingEnabled,
+ nsBCOfflineStartupState,
+ nsBCOfflineSendUnsentMessages,
+ nsBCOfflinePromptSynchOnExit,
+ nsBCAlwaysLoadImages,
+ nsBCEnableJava,
+ nsBCEnableJavaScript,
+ nsBCEnableStyleSheets,
+ nsBCEmailAsFtpPassword,
+ nsBCCookieBehavior,
+ nsBCWarnAboutCookies,
+ nsBCMemoryCacheSize,
+ nsBCDiskCacheSize,
+ nsBCCheckDocFrequency,
+ nsBCProxyType,
+ nsBCProxyHttp,
+ nsBCProxySsl,
+ nsBCProxyFtp,
+ nsBCProxySocks,
+ nsBCProxyGopher,
+ nsBCProxyWais,
+ nsBCNoProxiesOn,
+ nsBCProxyAutoConfigUrl,
+ nsBCAutoUpdateEnabled,
+ nsBCAutoUpdateConfirmInstall
+
+#
+# Netscape Mission Control Desktop browser security schema
+# This schema is used to hold browser security preferences.
+#
+
+attribute nsBSAskForPassword 2.16.840.1.113730.3.1.457 cis
+attribute nsBSPasswordLifetime 2.16.840.1.113730.3.1.458 cis
+attribute nsBSWarnEnteringSecure 2.16.840.1.113730.3.1.459 cis
+attribute nsBSWarnLeavingSecure 2.16.840.1.113730.3.1.460 cis
+attribute nsBSWarnViewingMixed 2.16.840.1.113730.3.1.461 cis
+attribute nsBSWarnSubmitInsecure 2.16.840.1.113730.3.1.462 cis
+attribute nsBSEnableSsl2 2.16.840.1.113730.3.1.463 cis
+attribute nsBSEnableSsl3 2.16.840.1.113730.3.1.464 cis
+attribute nsBSCertmgmtDisableFunctionMsg 2.16.840.1.113730.3.1.465 cis
+attribute nsBSSsl2Rc4128 2.16.840.1.113730.3.1.466 cis
+attribute nsBSSsl2Rc2128 2.16.840.1.113730.3.1.467 cis
+attribute nsBSSsl2DesEd3192 2.16.840.1.113730.3.1.468 cis
+attribute nsBSSsl2Des64 2.16.840.1.113730.3.1.469 cis
+attribute nsBSSsl2Rc440 2.16.840.1.113730.3.1.470 cis
+attribute nsBSSsl2Rc240 2.16.840.1.113730.3.1.471 cis
+attribute nsBSSsl3RsaRc4128Md5 2.16.840.1.113730.3.1.472 cis
+attribute nsBSSsl3FipsDesEd3Sha 2.16.840.1.113730.3.1.473 cis
+attribute nsBSSsl3RsaRc4128Md5 2.16.840.1.113730.3.1.474 cis
+attribute nsBSSsl3RsaFipsDesSha 2.16.840.1.113730.3.1.475 cis
+attribute nsBSSsl3RsaDesSha 2.16.840.1.113730.3.1.476 cis
+attribute nsBSSsl3RsaRc440Md5 2.16.840.1.113730.3.1.477 cis
+attribute nsBSSsl3RsaRc240Md5 2.16.840.1.113730.3.1.478 cis
+attribute nsBSSsl3RsaNullMd5 2.16.840.1.113730.3.1.479 cis
+attribute nsBSSsl3FortezzaFortezzaSha 2.16.840.1.113730.3.1.480 cis
+attribute nsBSSsl3FortezzaRc4Sha 2.16.840.1.113730.3.1.481 cis
+
+
+objectclass nsBrowserSecurity
+ oid 2.16.840.1.113730.3.2.79
+ superior top
+ allows
+ nsBSAskForPassword,
+ nsBSPasswordLifetime,
+ nsBSWarnEnteringSecure,
+ nsBSWarnLeavingSecure,
+ nsBSWarnViewingMixed,
+ nsBSWarnSubmitInsecure,
+ nsBSEnableSsl2,
+ nsBSEnableSsl3,
+ nsBSCertmgmtDisableFunctionMsg,
+ nsBSSsl2Rc4128,
+ nsBSSsl2Rc2128,
+ nsBSSsl2DesEd3192,
+ nsBSSsl2Des64,
+ nsBSSsl2Rc440,
+ nsBSSsl2Rc240,
+ nsBSSsl3RsaRc4128Md5,
+ nsBSSsl3FipsDesEd3Sha,
+ nsBSSsl3RsaRc4128Md5,
+ nsBSSsl3RsaFipsDesSha,
+ nsBSSsl3RsaDesSha,
+ nsBSSsl3RsaRc440Md5,
+ nsBSSsl3RsaRc240Md5,
+ nsBSSsl3RsaNullMd5,
+ nsBSSsl3FortezzaFortezzaSha,
+ nsBSSsl3FortezzaRc4Sha
+
diff --git a/ldap/cm/v4confs/412/ns-mcd-config-schema.conf b/ldap/cm/v4confs/412/ns-mcd-config-schema.conf
new file mode 100644
index 00000000..7076bbc7
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-mcd-config-schema.conf
@@ -0,0 +1,55 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-config-schema.conf
+#
+# Netscape Mission Control Desktop schema
+# This schema is used to set MCD "config()" preferences.
+#
+
+attribute nsMcdUserAgent 2.16.840.1.113730.3.1.482 cis
+attribute nsMcdUseXSender 2.16.840.1.113730.3.1.483 cis
+attribute nsMcdToolbarLogoUrl 2.16.840.1.113730.3.1.484 cis
+attribute nsMcdToolbarLogoWinSmallFile 2.16.840.1.113730.3.1.485 cis
+attribute nsMcdToolbarLogoWinLargeFile 2.16.840.1.113730.3.1.486 cis
+attribute nsMcdToolbarLogoFrames 2.16.840.1.113730.3.1.487 cis
+attribute nsMcdMacAnimationFile 2.16.840.1.113730.3.1.488 cis
+attribute nsMcdXAnimationFile 2.16.840.1.113730.3.1.489 cis
+attribute nsMcdNetSearchUrl 2.16.840.1.113730.3.1.490 cis
+attribute nsMcdMoreInfoPluginUrl 2.16.840.1.113730.3.1.491 cis
+attribute nsMcdAutoAdminConfigUrl 2.16.840.1.113730.3.1.492 cis
+attribute nsMcdAutoAdminAppendEmail 2.16.840.1.113730.3.1.493 cis
+attribute nsMcdAutoAdminRefreshInterval 2.16.840.1.113730.3.1.494 cis
+attribute nsMcdUseGuideButton 2.16.840.1.113730.3.1.495 cis
+attribute nsMcdGuideButtonProperties 2.16.840.1.113730.3.1.496 cis
+attribute nsMcdGuideMenuProperties 2.16.840.1.113730.3.1.497 cis
+attribute nsMcdHelpMenuProperties 2.16.840.1.113730.3.1.498 cis
+
+
+objectclass nsMcdConfig
+ oid 2.16.840.1.113730.3.2.80
+ superior top
+ allows
+ nsMcdUserAgent,
+ nsMcdUseXSender,
+ nsMcdToolbarLogoUrl,
+ nsMcdToolbarLogoWinSmallFile,
+ nsMcdToolbarLogoWinLargeFile,
+ nsMcdToolbarLogoFrames,
+ nsMcdMacAnimationFile,
+ nsMcdXAnimationFile,
+ nsMcdNetSearchUrl,
+ nsMcdMoreInfoPluginUrl,
+ nsMcdAutoAdminConfigUrl,
+ nsMcdAutoAdminAppendEmail,
+ nsMcdAutoAdminRefreshInterval,
+ nsMcdUseGuideButton,
+ nsMcdGuideButtonProperties,
+ nsMcdGuideMenuProperties,
+ nsMcdHelpMenuProperties
+
diff --git a/ldap/cm/v4confs/412/ns-mcd-li-globopt.conf b/ldap/cm/v4confs/412/ns-mcd-li-globopt.conf
new file mode 100644
index 00000000..57a75555
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-mcd-li-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Index required by Mission Control Desktop: Location Independence
+index nsLIProfileName eq
diff --git a/ldap/cm/v4confs/412/ns-mcd-li-schema.conf b/ldap/cm/v4confs/412/ns-mcd-li-schema.conf
new file mode 100644
index 00000000..272d90e2
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-mcd-li-schema.conf
@@ -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
+#
+#
+# ns-mcd-li-schema.conf
+#
+# Netscape Mission Control Desktop Location Independence schema
+#
+
+attribute nsLIPtrURL 2.16.840.1.113730.3.1.399 ces
+attribute nsLIPrefs 2.16.840.1.113730.3.1.400 ces
+attribute nsLIProfileName 2.16.840.1.113730.3.1.401 cis
+attribute nsLIData 2.16.840.1.113730.3.1.402 bin
+attribute nsLIElementType 2.16.840.1.113730.3.1.403 cis
+attribute nsLIServerType 2.16.840.1.113730.3.1.404 cis
+attribute nsLIVersion 2.16.840.1.113730.3.1.405 int
+
+objectclass nsLIPtr
+ oid 2.16.840.1.113730.3.2.74
+ requires
+ objectclass
+ allows
+ nsliptrurl,
+ owner
+
+objectclass nsLIProfile
+ oid 2.16.840.1.113730.3.2.75
+ requires
+ objectclass,
+ nsliprofilename
+ allows
+ nsliprefs,
+ uid,
+ owner
+
+objectclass nsLIProfileElement
+ oid 2.16.840.1.113730.3.2.76
+ requires
+ objectclass,
+ nslielementtype
+ allows
+ owner,
+ nslidata,
+ nsliversion
+
+objectclass nsLIServer
+ oid 2.16.840.1.113730.3.2.77
+ requires
+ objectclass,
+ serverhostname
+ allows
+ description,
+ cn,
+ nsserverport,
+ nsliservertype,
+ serverroot
diff --git a/ldap/cm/v4confs/412/ns-mcd-mail-schema.conf b/ldap/cm/v4confs/412/ns-mcd-mail-schema.conf
new file mode 100644
index 00000000..12d42c0b
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-mcd-mail-schema.conf
@@ -0,0 +1,219 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# ns-mcd-mail-schema.conf
+#
+# Netscape Mission Control Desktop mail client schema
+# This schema is used to hold mail client preferences.
+#
+
+attribute nsMCHTMLCompose 2.16.840.1.113730.3.1.331 cis
+attribute nsMCDefaultHTMLAction 2.16.840.1.113730.3.1.332 cis
+attribute nsMCRequestReturnReceipt 2.16.840.1.113730.3.1.333 cis
+attribute nsMCIncorporateReturnReceipt 2.16.840.1.113730.3.1.334 cis
+attribute nsMCMDNReportEnabled 2.16.840.1.113730.3.1.335 cis
+attribute nsMCMDNReportNotInToCC 2.16.840.1.113730.3.1.336 cis
+attribute nsMCMDNReportOutsideDomain 2.16.840.1.113730.3.1.337 cis
+attribute nsMCMDNReportOther 2.16.840.1.113730.3.1.338 cis
+attribute nsMCForwardMessageMode 2.16.840.1.113730.3.1.339 cis
+attribute nsMCAutoQuote 2.16.840.1.113730.3.1.340 cis
+attribute nsMCReplyOnTop 2.16.840.1.113730.3.1.341 cis
+attribute nsMCSpellCheckBeforeSend 2.16.840.1.113730.3.1.342 cis
+attribute nsMCWrapLongLines 2.16.840.1.113730.3.1.343 cis
+attribute nsMCWrapLength 2.16.840.1.113730.3.1.344 cis
+attribute nsMCStrictlyMime 2.16.840.1.113730.3.1.345 cis
+attribute nsMCAutoCompleteUseAddressBooks 2.16.840.1.113730.3.1.346 cis
+attribute nsMCAutoCompleteUseDirectory 2.16.840.1.113730.3.1.347 cis
+attribute nsMCAutoCompleteEnabledServerName 2.16.840.1.113730.3.1.348 cis
+attribute nsMCAutoCompleteShowDlgForMultipleMatches 2.16.840.1.113730.3.1.349 cis
+attribute nsMCSkipDirectoryIfLocalMatchFound 2.16.840.1.113730.3.1.350 cis
+attribute nsMCAddrBookLastnameFirst 2.16.840.1.113730.3.1.351 cis
+attribute nsMCLimitMessageSize 2.16.840.1.113730.3.1.352 cis
+attribute nsMCMaxMessageSize 2.16.840.1.113730.3.1.353 cis
+attribute nsMCPromptPurgeThreshold 2.16.840.1.113730.3.1.354 cis
+attribute nsMCPurgeThreshold 2.16.840.1.113730.3.1.355 cis
+attribute nsMCNewsKeepMethod 2.16.840.1.113730.3.1.356 cis
+attribute nsMCNewsKeepDays 2.16.840.1.113730.3.1.357 cis
+attribute nsMCNewsKeepCount 2.16.840.1.113730.3.1.358 cis
+attribute nsMCNewsKeepOnlyUnread 2.16.840.1.113730.3.1.359 cis
+attribute nsMCNewsRemoveBodiesByAge 2.16.840.1.113730.3.1.360 cis
+attribute nsMCNewsRemoveBodiesDays 2.16.840.1.113730.3.1.361 cis
+attribute nsMCSmtpServer 2.16.840.1.113730.3.1.362 cis
+attribute nsMCSmtpUserName 2.16.840.1.113730.3.1.363 cis
+attribute nsMCSmtpUseSSL 2.16.840.1.113730.3.1.364 cis
+attribute nsMCImapServer 2.16.840.1.113730.3.1.365 cis
+attribute nsMCImapServerProperties 2.16.840.1.113730.3.1.366 cis
+attribute nsMCPopServer 2.16.840.1.113730.3.1.367 cis
+attribute nsMCPopServerProperties 2.16.840.1.113730.3.1.368 cis
+attribute nsMCLdapServer 2.16.840.1.113730.3.1.369 cis
+attribute nsMCLdapServerProperties 2.16.840.1.113730.3.1.370 cis
+attribute nsMCQuotedStyle 2.16.840.1.113730.3.1.371 cis
+attribute nsMCQuotedSize 2.16.840.1.113730.3.1.372 cis
+attribute nsMCCitationColor 2.16.840.1.113730.3.1.373 cis
+attribute nsMCFixedWidthMessages 2.16.840.1.113730.3.1.374 cis
+attribute nsMCPlaySound 2.16.840.1.113730.3.1.375 cis
+attribute nsMCRememberSelectedMessage 2.16.840.1.113730.3.1.376 cis
+attribute nsMCReuseMessageWindow 2.16.840.1.113730.3.1.377 cis
+attribute nsMCConfirmMoveFoldersToTrash 2.16.840.1.113730.3.1.378 cis
+attribute nsMCUseMapiServer 2.16.840.1.113730.3.1.379 cis
+attribute nsMCNewsTimeout 2.16.840.1.113730.3.1.380 cis
+attribute nsMCNavCrossesFolders 2.16.840.1.113730.3.1.381 cis
+attribute nsMCSearchServer 2.16.840.1.113730.3.1.382 cis
+attribute nsMCSearchSubFolders 2.16.840.1.113730.3.1.383 cis
+attribute nsMCEncryptOutgoingMail 2.16.840.1.113730.3.1.384 cis
+attribute nsMCCryptoSignOutgoingMail 2.16.840.1.113730.3.1.385 cis
+attribute nsMCCryptoSignOutgoingNews 2.16.840.1.113730.3.1.386 cis
+attribute nsMCWarnForwardEncrypted 2.16.840.1.113730.3.1.387 cis
+attribute nsMCWarnReplyUnencrypted 2.16.840.1.113730.3.1.388 cis
+attribute nsMCAllowAtSignInUserName 2.16.840.1.113730.3.1.389 cis
+attribute nsMCReceiptRequestHeaderType 2.16.840.1.113730.3.1.390 cis
+attribute nsMCPop3GetsNewMail 2.16.840.1.113730.3.1.391 cis
+attribute nsMCImapAutoSubscribeOnOpen 2.16.840.1.113730.3.1.392 cis
+attribute nsMCImapMimePartsOnDemand 2.16.840.1.113730.3.1.393 cis
+attribute nsMCImapMimePartsOnDemandThreshold 2.16.840.1.113730.3.1.394 cis
+attribute nsMCUseAltMail 2.16.840.1.113730.3.1.395 cis
+attribute nsMCAltMailDll 2.16.840.1.113730.3.1.396 cis
+attribute nsMCUseAltMailForNews 2.16.840.1.113730.3.1.397 cis
+attribute nsPrefMap 2.16.840.1.113730.3.1.398 cis
+attribute nsMCAuthLogin 2.16.840.1.113730.3.1.499 cis
+attribute nsMNCNavCrossesFolders 2.16.840.1.113730.3.1.500 cis
+attribute nsMNCMessageInThreadWindow 2.16.840.1.113730.3.1.501 cis
+attribute nsMCAllowAtSignInUserName 2.16.840.1.113730.3.1.502 cis
+attribute nsMCImapOnlineDraftSent 2.16.840.1.113730.3.1.503 cis
+attribute nsMCCustomHeaders 2.16.840.1.113730.3.1.504 cis
+attribute nsMCHtmlDomains 2.16.840.1.113730.3.1.505 cis
+attribute nsMNCForceAsciiSearch 2.16.840.1.113730.3.1.506 cis
+attribute nsMCAddrBookLdapDisabled 2.16.840.1.113730.3.1.507 cis
+attribute nsMNCReuseThreadWindow 2.16.840.1.113730.3.1.508 cis
+attribute nsMCShowHeaders 2.16.840.1.113730.3.1.509 cis
+attribute nsMCIdentityDefaultdomain 2.16.840.1.113730.3.1.510 cis
+
+
+
+
+objectclass nsMailClient
+ oid 2.16.840.1.113730.3.2.72
+ superior top
+ allows
+ nsMCHTMLCompose,
+ nsMCDefaultHTMLAction,
+ nsMCRequestReturnReceipt,
+ nsMCIncorporateReturnReceipt,
+ nsMCMDNReportEnabled,
+ nsMCMDNReportNotInToCC,
+ nsMCMDNReportOutsideDomain,
+ nsMCMDNReportOther,
+ nsMCForwardMessageMode,
+ nsMCAutoQuote,
+ nsMCReplyOnTop,
+ nsMCSpellCheckBeforeSend,
+ nsMCWrapLongLines,
+ nsMCWrapLength,
+ nsMCStrictlyMime,
+ nsMCAutoCompleteUseAddressBooks,
+ nsMCAutoCompleteUseDirectory,
+ nsMCAutoCompleteEnabledServerName,
+ nsMCAutoCompleteShowDlgForMultipleMatches,
+ nsMCSkipDirectoryIfLocalMatchFound,
+ nsMCAddrBookLastnameFirst,
+ nsMCLimitMessageSize,
+ nsMCMaxMessageSize,
+ nsMCPromptPurgeThreshold,
+ nsMCPurgeThreshold,
+ nsMCNewsKeepMethod,
+ nsMCNewsKeepDays,
+ nsMCNewsKeepCount,
+ nsMCNewsKeepOnlyUnread,
+ nsMCNewsRemoveBodiesByAge,
+ nsMCNewsRemoveBodiesDays,
+ nsMCSmtpServer,
+ nsMCSmtpUserName,
+ nsMCSmtpUseSSL,
+ nsMCImapServer,
+ nsMCImapServerProperties,
+ nsMCPopServer,
+ nsMCPopServerProperties,
+ nsMCLdapServer,
+ nsMCLdapServerProperties,
+ nsMCQuotedStyle,
+ nsMCQuotedSize,
+ nsMCCitationColor,
+ nsMCFixedWidthMessages,
+ nsMCPlaySound,
+ nsMCRememberSelectedMessage,
+ nsMCReuseMessageWindow,
+ nsMCConfirmMoveFoldersToTrash,
+ nsMCUseMapiServer,
+ nsMCNewsTimeout,
+ nsMCNavCrossesFolders,
+ nsMCSearchServer,
+ nsMCSearchSubFolders,
+ nsMCEncryptOutgoingMail,
+ nsMCCryptoSignOutgoingMail,
+ nsMCCryptoSignOutgoingNews,
+ nsMCWarnForwardEncrypted,
+ nsMCWarnReplyUnencrypted,
+ nsMCAllowAtSignInUserName,
+ nsMCReceiptRequestHeaderType,
+ nsMCPop3GetsNewMail,
+ nsMCImapAutoSubscribeOnOpen,
+ nsMCImapMimePartsOnDemand,
+ nsMCImapMimePartsOnDemandThreshold,
+ nsMCUseAltMail,
+ nsMCAltMailDll,
+ nsMCUseAltMailForNews,
+ nsMCAuthLogin,
+ nsMNCNavCrossesFolders,
+ nsMNCMessageInThreadWindow,
+ nsMCAllowAtSignInUserName,
+ nsMCImapOnlineDraftSent,
+ nsMCCustomHeaders,
+ nsMCHtmlDomains,
+ nsMNCForceAsciiSearch,
+ nsMCAddrBookLdapDisabled,
+ nsMNCReuseThreadWindow,
+ nsMCShowHeaders,
+ nsMCIdentityDefaultdomain
+
+
+#
+# Netscape Mission Control Desktop Messenger security schema
+# This schema is used to hold Messenger security preferences.
+#
+
+attribute nsMSEncryptOutgoingMail 2.16.840.1.113730.3.1.511 cis
+attribute nsMSSignOutgoingMail 2.16.840.1.113730.3.1.512 cis
+attribute nsMSSignOutgoingNews 2.16.840.1.113730.3.1.513 cis
+attribute nsMSSmimeDesEde3 2.16.840.1.113730.3.1.514 cis
+attribute nsMSSmimeRc2128 2.16.840.1.113730.3.1.515 cis
+attribute nsMSSmimeDes 2.16.840.1.113730.3.1.516 cis
+attribute nsMSSmimeRc264 2.16.840.1.113730.3.1.517 cis
+attribute nsMSSmimeRc240 2.16.840.1.113730.3.1.518 cis
+attribute nsMSSmimeFortezza 2.16.840.1.113730.3.1.519 cis
+
+objectclass nsMailSecurity
+ oid 2.16.840.1.113730.3.2.81
+ superior top
+ allows
+ nsMSEncryptOutgoingMail,
+ nsMSSignOutgoingMail,
+ nsMSSignOutgoingNews,
+ nsMSSmimeDesEde3,
+ nsMSSmimeRc2128,
+ nsMSSmimeDes,
+ nsMSSmimeRc264,
+ nsMSSmimeRc240,
+ nsMSSmimeFortezza
+
+objectclass netscapePreferenceMap
+ oid 2.16.840.1.113730.3.2.73
+ superior top
+ allows
+ nsPrefMap,
+ uid
+
diff --git a/ldap/cm/v4confs/412/ns-media-globopt.conf b/ldap/cm/v4confs/412/ns-media-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-media-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/412/ns-media-schema.conf b/ldap/cm/v4confs/412/ns-media-schema.conf
new file mode 100644
index 00000000..d4afa271
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-media-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeMediaServer
+ oid 2.16.840.1.113730.3.2.25
+ requires
+ objectclass
+
diff --git a/ldap/cm/v4confs/412/ns-mlm-schema.conf b/ldap/cm/v4confs/412/ns-mlm-schema.conf
new file mode 100644
index 00000000..e1c4ef78
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-mlm-schema.conf
@@ -0,0 +1,102 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# LDAP object classes used by MLM
+#
+
+attribute mgmemMemberOfGroup cis
+attribute mgmemRefDN ces single
+attribute mgmemMailUserPassword bin single
+attribute mgmemGroupMemberParam ces
+attribute mgmemGroupServerParam ces
+
+attribute mgmanJoinability ces
+attribute mgmanJoinLocalType cis single
+attribute mgmanMemberVisibility ces
+attribute mgmanIntroText ces single
+attribute mgmanGroupStat ces
+attribute mgmanHidden cis single
+attribute mgmanGroupKey cis single
+attribute mgmanAllowSubscribe cis
+attribute mgmanDenySubscribe cis
+
+attribute mgmanGConfNewGroupParent dn single
+attribute mgmanGConfRemoteUserParent dn single
+attribute mgmanGConfSearchBase dn single
+attribute mgmanGConfGroupCreationUser dn
+attribute mgmanGConfSearchGroupUser dn
+attribute mgmanGConfAdmin dn
+attribute mgmanGConfGroupTemplate dn single
+attribute mgmanGConfDefaultInheritance cis
+attribute mgmanGConfKey cis
+attribute mgmanGConfSearchAttribute cis
+attribute mgmanGConfSearchRelationship cis
+attribute mgmanGConfSearchTreeNode cis
+attribute mgmanGConfSortAttributeDirMembers cis
+attribute mgmanGConfSortAttributeGroupMembers cis
+attribute mgmanGConfGroupDomains dn
+
+
+objectClass mailGroupMember
+ requires
+ objectClass,
+ mail
+ allows
+ mgmemMemberOfGroup,
+ mgmemRefDN,
+ preferredLanguage,
+ userCertificate,
+ mgmemMailUserPassword,
+ mgmemGroupMemberParam,
+ mgmemGroupServerParam,
+ c,
+ cn,
+ sn,
+ givenName
+
+
+objectClass mailGroupManagement
+ requires
+ objectClass
+ allows
+ description,
+ labeledURL,
+ mgmanAllowSubscribe,
+ mgmanDenySubscribe,
+ mgmanGroupKey,
+ mgmanGroupStat,
+ mgmanHidden,
+ mgmanIntroText,
+ mgmanJoinability,
+ mgmanJoinLocalType,
+ mgmanMemberVisibility,
+ multilineDescription,
+ userCertificate,
+ userPassword
+
+objectClass mailGroupManagement_GlobalConfig
+ requires
+ objectClass
+ allows
+ cn,
+ mgmanGConfAdmin,
+ mgmanGConfDefaultInheritance,
+ mgmanGConfGroupCreationUser,
+ mgmanGConfGroupDomains,
+ mgmanGConfGroupTemplate,
+ mgmanGConfKey,
+ mgmanGConfNewGroupParent,
+ mgmanGConfRemoteUserParent,
+ mgmanGConfSearchAttribute,
+ mgmanGConfSearchBase,
+ mgmanGConfSearchGroupUser,
+ mgmanGConfSearchRelationship,
+ mgmanGConfSearchTreeNode,
+ mgmanGConfSortAttributeDirMembers,
+ mgmanGConfSortAttributeGroupMembers
+
diff --git a/ldap/cm/v4confs/412/ns-msg-schema.conf b/ldap/cm/v4confs/412/ns-msg-schema.conf
new file mode 100644
index 00000000..3800edbd
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-msg-schema.conf
@@ -0,0 +1,711 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#used by Netscape Messaging Server 4.0
+#
+#
+attribute nsmsgaccounturl cis
+attribute nsmsgadddeliveredto cis
+attribute nsmsgaddheaders cis
+attribute nsmsgadmins cis
+attribute nsmsgalias cis
+attribute nsmsgallowadminproxy cis
+attribute nsmsgallowanonymouslogin cis
+attribute nsmsgallowbarelf cis
+attribute nsmsgallowbdat cis
+attribute nsmsgallowehlo cis
+attribute nsmsgallowetrn cis
+attribute nsmsgallowexpn cis
+attribute nsmsgallowhelp cis
+attribute nsmsgallowonex cis
+attribute nsmsgallowsize cis
+attribute nsmsgallowverb cis
+attribute nsmsgallowvrfy cis
+attribute nsmsgaltqueues cis
+attribute nsmsgalwaysqueue cis
+attribute nsmsgauthcachesize cis
+attribute nsmsgauthcachettl cis
+attribute nsmsgauthmaildomain cis
+attribute nsmsgbanner cis
+attribute nsmsgbinarypath cis
+attribute nsmsgbuffersize cis
+attribute nsmsgcheckdeferredqueue cis
+attribute nsmsgcleanupage cis
+attribute nsmsgclearcontrolinterval cis
+attribute nsmsgclearcontrolsafetime cis
+attribute nsmsgcollectiondeltatime cis
+attribute nsmsgconfigversion cis
+attribute nsmsgcontact cis
+attribute nsmsgcounterdeltatime cis
+attribute nsmsgdbcachesize cis
+attribute nsmsgdbtmpdir cis
+attribute nsmsgdefaultacl cis
+attribute nsmsgdefaultdomain cis
+attribute nsmsgdefaultecho cis
+attribute nsmsgdefaultgid cis
+attribute nsmsgdefaultmailboxquota cis
+attribute nsmsgdefaultoverquota cis
+attribute nsmsgdefaultpartition cis
+attribute nsmsgdefaultreply cis
+attribute nsmsgdefaultuid cis
+attribute nsmsgdefaultvacation cis
+attribute nsmsgdeferredperiod cis
+attribute nsmsgdeleteheaders cis
+attribute nsmsgdescription cis
+attribute nsmsgdiskflushinterval cis
+attribute nsmsgdnsresolveclient cis
+attribute nsmsgdocanonicalize cis
+attribute nsmsgdoclientdnslookup cis
+attribute nsmsgdodsn cis
+attribute nsmsgdoetrn cis
+attribute nsmsgdomainallowed cis
+attribute nsmsgdomainlangtable cis
+attribute nsmsgdomainname cis
+attribute nsmsgdomainnotallowed cis
+attribute nsmsgdomainsecurity cis
+attribute nsmsgdorewritefromusingauth cis
+attribute nsmsgdorewritesenderusingauth cis
+attribute nsmsgenable cis
+attribute nsmsgenablesslport cis
+attribute nsmsgenveloperewritemethod cis
+attribute nsmsgexclusive cis
+attribute nsmsgexpirestart cis
+attribute nsmsgexpirytime cis
+attribute nsmsgexternalmxserverip cis
+attribute nsmsgfallbacksearchmethod cis
+attribute nsmsgfilemode cis
+attribute nsmsgfilterurl cis
+attribute nsmsgflushinterval cis
+attribute nsmsgfolderpattern cis
+attribute nsmsgfoldersizebytes cis
+attribute nsmsgfolderurl cis
+attribute nsmsgforeignpercentaddr cis
+attribute nsmsgformsigkey cis
+attribute nsmsghidehostname cis
+attribute nsmsghopcountexceedactions cis
+attribute nsmsghostoncommandline cis
+attribute nsmsghostrewrites cis
+attribute nsmsgidletimeout cis
+attribute nsmsgipsecurity cis
+attribute nsmsginstalledlanguages cis
+attribute nsmsginternalmxserverip cis
+attribute nsmsgldapmemcache cis
+attribute nsmsgldapmemcachesize cis
+attribute nsmsgldapmemcachettl cis
+attribute nsmsgldappoolsize cis
+attribute nsmsgldaputilconfig cis
+attribute nsmsglistenaddr cis
+attribute nsmsglistenq cis
+attribute nsmsglisturl cis
+attribute nsmsglocaldefaultmaxruncount cis
+attribute nsmsglocaldefaultminruncount cis
+attribute nsmsglocalmaildomains cis
+attribute nsmsglocation cis
+attribute nsmsglog cis
+attribute nsmsglogdir cis
+attribute nsmsgloglevel cis
+attribute nsmsglogtype cis
+attribute nsmsgmaildeliveryprogram cis
+attribute nsmsgmasterhost cis
+attribute nsmsgmasterport cis
+attribute nsmsgmaxbadcommands cis
+attribute nsmsgmaxbranches cis
+attribute nsmsgmaxcontrolrecipients cis
+attribute nsmsgmaxcputime cis
+attribute nsmsgmaxerrorobjectsize cis
+attribute nsmsgmaxheaderlines cis
+attribute nsmsgmaxlogfiles cis
+attribute nsmsgmaxlogfilesize cis
+attribute nsmsgmaxlogsize cis
+attribute nsmsgmaxmessagesize cis
+attribute nsmsgmaxmtahops cis
+attribute nsmsgmaxpostsize cis
+attribute nsmsgmaxqueuetime cis
+attribute nsmsgmaxruncount cis
+attribute nsmsgmaxruncountdeferred cis
+attribute nsmsgmaxscriptsize cis
+attribute nsmsgmaxsessions cis
+attribute nsmsgmaxstateobjectsize cis
+attribute nsmsgmaxthreads cis
+attribute nsmsgmessagecount cis
+attribute nsmsgmessagedays cis
+attribute nsmsgmessagehostname cis
+attribute nsmsgmessagesize cis
+attribute nsmsgmessagesizedays cis
+attribute nsmsgminfreediskspace cis
+attribute nsmsgminruncount cis
+attribute nsmsgmsgalarmdescription cis
+attribute nsmsgmsgalarmnoticehost cis
+attribute nsmsgmsgalarmnoticeport cis
+attribute nsmsgmsgalarmnoticercpt cis
+attribute nsmsgmsgalarmnoticesender cis
+attribute nsmsgmsgalarmnoticetemplate cis
+attribute nsmsgmsgalarmstatinterval cis
+attribute nsmsgmsgalarmthreshold cis
+attribute nsmsgmsgalarmthresholddirection cis
+attribute nsmsgmsgalarmwarninginterval cis
+attribute nsmsgmtaid cis
+attribute nsmsgmtaname cis
+attribute nsmsgneedsender cis
+attribute nsmsgnegativehostattr cis
+attribute nsmsgnestedgroups cis
+attribute nsmsgnetworkdefaultmaxruncount cis
+attribute nsmsgnetworkdefaultminruncount cis
+attribute nsmsgnewsprefix cis
+attribute nsmsgnewsspool cis
+attribute nsmsgnewuserforms cis
+attribute nsmsgntaccount cis
+attribute nsmsgntpassword cis
+attribute nsmsgntrunoptn cis
+attribute nsmsgnumdays cis
+attribute nsmsgnumenvelopequeuefiles cis
+attribute nsmsgnummessages cis
+attribute nsmsgnumprocesses cis
+attribute nsmsgorganization cis
+attribute nsmsgpartition cis
+attribute nsmsgpath cis
+attribute nsmsgplaintextloginpause cis
+attribute nsmsgplaintextmincipher cis
+attribute nsmsgpopminpoll cis
+attribute nsmsgport cis
+attribute nsmsgpositivehostattr cis
+attribute nsmsgprotocolubeconfig cis
+attribute nsmsgproxydomainallowed cis
+attribute nsmsgquotaexceededactions cis
+attribute nsmsgquotaexceededmsg cis
+attribute nsmsgquotaexceededmsginterval cis
+attribute nsmsgquotagraceperiod cis
+attribute nsmsgquotawarn cis
+attribute nsmsgreadtimeout cis
+attribute nsmsgrenotifyinterval cis
+attribute nsmsgrequirecrlf cis
+attribute nsmsgreserved0 cis
+attribute nsmsgreserved1 cis
+attribute nsmsgreserved2 cis
+attribute nsmsgreserved3 cis
+attribute nsmsgreserved4 cis
+attribute nsmsgreserved5 cis
+attribute nsmsgreserved6 cis
+attribute nsmsgreserved7 cis
+attribute nsmsgreserved8 cis
+attribute nsmsgreserved9 cis
+attribute nsmsgresourcetimeout cis
+attribute nsmsgrewritetocc cis
+attribute nsmsgrolloverdelta cis
+attribute nsmsgrolloversize cis
+attribute nsmsgrollovertime cis
+attribute nsmsgroutingattribute cis
+attribute nsmsgroutstripimapfolders cis
+attribute nsmsgsessiontimeout cis
+attribute nsmsgshellpath cis
+attribute nsmsgsitelanguage cis
+attribute nsmsgsmtphost cis
+attribute nsmsgsmtpport cis
+attribute nsmsgsmtprewritestyle cis
+attribute nsmsgsourceurl cis
+attribute nsmsgspooldir cis
+attribute nsmsgsslcachesize cis
+attribute nsmsgsslpasswdfile cis
+attribute nsmsgsslport cis
+attribute nmmsgsslsourceurl cis
+attribute nsmsgsslusessl cis
+attribute nsmsgsslusesslrelay cis
+attribute nsmsgstripcr cis
+attribute nsmsgsystemmaildir cis
+attribute nsmsgtimeoutcommand cis
+attribute nsmsgtimeoutdata cis
+attribute nsmsgtimeoutdatadot cis
+attribute nsmsgtimeoutdatasend cis
+attribute nsmsgtimeoutgreet cis
+attribute nsmsgtimeouthelo cis
+attribute nsmsgtimeoutmail cis
+attribute nsmsgtimeoutquit cis
+attribute nsmsgtimeoutrcpt cis
+attribute nsmsgtimeoutrset cis
+attribute nsmsgumask cis
+attribute nsmsgunknownacctsactions cis
+attribute nsmsgusemx cis
+attribute nsmsgverifyrcpts cis
+attribute nsmsgversion cis
+
+objectclass netscapeMessagingServer
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description
+
+objectclass nsmsgcfgcontainer
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfggen
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgaccounturl,
+ nsmsgconfigversion,
+ nsmsgfilterurl,
+ nsmsgfolderurl,
+ nsmsginstalledlanguages,
+ nsmsglisturl,
+ nsmsgnewuserforms,
+ nsmsgsitelanguage
+
+objectclass nsmsgcfgsnmp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgcontact,
+ nsmsgcollectiondeltatime,
+ nsmsgdescription,
+ nsmsgenable,
+ nsmsglocation,
+ nsmsgmtaid,
+ nsmsgmtaname,
+ nsmsgmasterhost,
+ nsmsgmasterport,
+ nsmsgorganization,
+ nsmsgversion
+
+objectclass nsmsgcfgstore
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgadmins,
+ nsmsgcleanupage,
+ nsmsgdbcachesize,
+ nsmsgdbtmpdir,
+ nsmsgdefaultacl,
+ nsmsgdefaultmailboxquota,
+ nsmsgdefaultpartition,
+ nsmsgdiskflushinterval,
+ nsmsgexpirestart,
+ nsmsgquotaexceededmsg,
+ nsmsgquotaexceededmsginterval,
+ nsmsgquotagraceperiod,
+ nsmsgquotawarn,
+ nsmsgumask
+
+objectclass nsmsgcfgexpirerule
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgfolderpattern,
+ nsmsgexclusive,
+ nsmsgfoldersizebytes,
+ nsmsgmessagecount,
+ nsmsgmessagedays,
+ nsmsgmessagesize,
+ nsmsgmessagesizedays
+
+objectclass nsmsgcfgpartition
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgpath
+
+objectclass nsmsgcfguser
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgpublic
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgalias
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgalias
+
+objectclass nsmsgcfglog
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgbuffersize,
+ nsmsgexpirytime,
+ nsmsgflushinterval,
+ nsmsglogdir,
+ nsmsgloglevel,
+ nsmsglogtype,
+ nsmsgmaxlogfiles,
+ nsmsgmaxlogfilesize,
+ nsmsgmaxlogsize,
+ nsmsgminfreediskspace,
+ nsmsgrollovertime
+
+objectclass nsmsgcfgservice
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgauthcachesize,
+ nsmsgauthcachettl,
+ nsmsgdnsresolveclient,
+ nsmsgldapmemcache,
+ nsmsgldapmemcachesize,
+ nsmsgldapmemcachettl,
+ nsmsglistenaddr,
+ nsmsgplaintextloginpause,
+ nsmsgreadtimeout,
+ nsmsgsslpasswdfile
+
+objectclass nsmsgcfgpop
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowanonymouslogin,
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgidletimeout,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgpopminpoll,
+ nsmsgport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgimap
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowanonymouslogin,
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgidletimeout,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgsslcachesize,
+ nsmsgsslport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfghttp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowadminproxy,
+ nsmsgallowanonymouslogin,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgdomainsecurity,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgidletimeout,
+ nsmsgipsecurity,
+ nsmsgmaxmessagesize,
+ nsmsgmaxsessions,
+ nsmsgmaxthreads,
+ nsmsgmaxpostsize,
+ nsmsgnumprocesses,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgproxydomainallowed,
+ nsmsgresourcetimeout,
+ nsmsgsessiontimeout,
+ nsmsgsmtphost,
+ nsmsgsmtpport,
+ nsmsgsourceurl,
+ nsmsgspooldir,
+ nsmsgsslcachesize,
+ nsmsgsslport,
+ nsmsgsourceurl,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgnntp
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgbanner,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgenable,
+ nsmsgenablesslport,
+ nsmsgnewsprefix,
+ nsmsgnewsspool,
+ nsmsgpartition,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgsslport,
+ nsmsgsslusessl
+
+objectclass nsmsgcfgmta
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgaltqueues,
+ nsmsgauthmaildomain,
+ nsmsgbanner,
+ nsmsgclearcontrolinterval,
+ nsmsgclearcontrolsafetime,
+ nsmsgcounterdeltatime,
+ nsmsgdefaultdomain,
+ nsmsgdeferredperiod,
+ nsmsgdocanonicalize,
+ nsmsgdoclientdnslookup,
+ nsmsgdodsn,
+ nsmsgdomainallowed,
+ nsmsgdomainnotallowed,
+ nsmsgdomainname,
+ nsmsgdomainlangtable,
+ nsmsgenable,
+ nsmsgforeignpercentaddr,
+ nsmsgldappoolsize,
+ nsmsgldaputilconfig,
+ nsmsglocaldefaultmaxruncount,
+ nsmsglocaldefaultminruncount,
+ nsmsgmaxheaderlines,
+ nsmsgmaxqueuetime,
+ nsmsgmessagehostname,
+ nsmsgnetworkdefaultmaxruncount,
+ nsmsgnetworkdefaultminruncount,
+ nsmsgnumenvelopequeuefiles,
+ nsmsgplaintextmincipher,
+ nsmsgport,
+ nsmsgprotocolubeconfig,
+ nsmsgreserved0,
+ nsmsgreserved1,
+ nsmsgreserved2,
+ nsmsgreserved3,
+ nsmsgreserved4,
+ nsmsgreserved5,
+ nsmsgreserved6,
+ nsmsgreserved7,
+ nsmsgreserved8,
+ nsmsgreserved9,
+ nsmsgrolloverdelta,
+ nsmsgrolloversize,
+ nsmsgroutstripimapfolders,
+ nsmsgsslusessl,
+ nsmsgsslusesslrelay
+
+objectclass nsmsgcfgmtalog
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsglog,
+ nsmsgminruncount,
+ nsmsgmaxruncount,
+ nsmsgmaxruncountdeferred
+
+objectclass nsmsgcfgmtaautoreplyhandler
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultecho,
+ nsmsgdefaultreply,
+ nsmsgdefaultvacation
+
+objectclass nsmsgcfgmtaerrorhandler
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgformsigkey,
+ nsmsghopcountexceedactions,
+ nsmsgquotaexceededactions,
+ nsmsgrenotifyinterval,
+ nsmsgunknownacctsactions
+
+objectclass nsmsgcfgmtamboxdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgmtaprogdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultgid,
+ nsmsgdefaultuid,
+ nsmsgshellpath,
+ nsmsgntrunoptn,
+ nsmsgntaccount,
+ nsmsgntpassword
+
+objectclass nsmsgcfgmtaaccept
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowbdat,
+ nsmsgallowehlo,
+ nsmsgallowetrn,
+ nsmsgallowexpn,
+ nsmsgallowhelp,
+ nsmsgallowonex,
+ nsmsgallowsize,
+ nsmsgallowverb,
+ nsmsgallowvrfy,
+ nsmsghidehostname,
+ nsmsgmaxbadcommands,
+ nsmsgmaxmessagesize,
+ nsmsgminfreediskspace,
+ nsmsgnegativehostattr,
+ nsmsgpositivehostattr,
+ nsmsgrequirecrlf,
+ nsmsgtimeoutcommand,
+ nsmsgtimeoutdata,
+ nsmsgverifyrcpts
+
+objectclass nsmsgcfgmtasmtpdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgallowbarelf,
+ nsmsgalwaysqueue,
+ nsmsgcheckdeferredqueue,
+ nsmsgdoetrn,
+ nsmsgexternalmxserverip,
+ nsmsginternalmxserverip,
+ nsmsgtimeoutdata,
+ nsmsgtimeoutdatadot,
+ nsmsgtimeoutdatasend,
+ nsmsgtimeoutgreet,
+ nsmsgtimeouthelo,
+ nsmsgtimeoutmail,
+ nsmsgtimeoutquit,
+ nsmsgtimeoutrcpt,
+ nsmsgtimeoutrset,
+ nsmsgusemx
+
+objectclass nsmsgcfgmtarouter
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgadddeliveredto,
+ nsmsgaddheaders,
+ nsmsgdeleteheaders,
+ nsmsgdorewritefromusingauth,
+ nsmsgdorewritesenderusingauth,
+ nsmsgenveloperewritemethod,
+ nsmsgfallbacksearchmethod,
+ nsmsghostrewrites,
+ nsmsglocalmaildomains,
+ nsmsgmaxcontrolrecipients,
+ nsmsgmaxmtahops,
+ nsmsgnestedgroups,
+ nsmsgrewritetocc,
+ nsmsgroutingattribute,
+ nsmsgsmtprewritestyle
+
+objectclass nsmsgcfgmtaunixdeliver
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgdefaultgid,
+ nsmsgdefaultuid,
+ nsmsgfilemode,
+ nsmsgmaildeliveryprogram,
+ nsmsgneedsender,
+ nsmsgstripcr,
+ nsmsgsystemmaildir
+
+objectclass nsmsgcfgreport
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+
+objectclass nsmsgcfgalarmcontainer
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgmsgalarmnoticehost,
+ nsmsgmsgalarmnoticeport,
+ nsmsgmsgalarmnoticercpt,
+ nsmsgmsgalarmnoticesender,
+ nsmsgmsgalarmnoticetemplate
+
+objectclass nsmsgcfgalarm
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgmsgalarmdescription,
+ nsmsgmsgalarmstatinterval,
+ nsmsgmsgalarmthreshold,
+ nsmsgmsgalarmthresholddirection,
+ nsmsgmsgalarmwarninginterval
+
+objectclass nsmsgcfgscript
+ superior top
+ requires
+ objectclass,
+ cn
+ allows
+ nsmsgenable,
+ nsmsgbinarypath,
+ nsmsgloglevel,
+ nsmsgmaxscriptsize,
+ nsmsgmaxbranches,
+ nsmsgmaxcputime,
+ nsmsgmaxerrorobjectsize,
+ nsmsgmaxstateobjectsize
diff --git a/ldap/cm/v4confs/412/ns-netshare-schema.conf b/ldap/cm/v4confs/412/ns-netshare-schema.conf
new file mode 100644
index 00000000..b1201ef0
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-netshare-schema.conf
@@ -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
+#
+# Used by Netscape Enterprise Server
+attribute netshareHomeURL ces single
+attribute netshareServerType cis single
+attribute netshareHomeTheme cis single
+attribute netsharePrivate cis single
+attribute netshareMemberOf dn
+attribute netshareUIConfig bin single
+
+# added to either users or groups/projects to enable
+# as netshare user accounts or netshare projects
+objectclass netshareAccount
+ requires
+ objectclass,
+ netshareHomeURL
+ allows
+ netshareServerType,
+ netshareHomeTheme,
+ netsharePrivate,
+ netshareMemberOf,
+ netshareUIConfig
+
+
+attribute netsharePMNewProjParent dn single
+attribute netsharePMSearchBase dn single
+attribute netsharePMProjCreationUser dn single
+attribute netsharePMAdmin dn
+
+# this is for the netshare project management utility/CGI
+# that is created under the SIE; this parallels the messaging
+# MLM schema somewhat to enable end-user maintenance/creation
+# of netshare projects
+objectclass netshareProjectManagementGlobalConfig
+ requires
+ objectclass
+ allows
+ netsharePMNewProjParent,
+ netsharePMSearchBase,
+ netsharePMProjCreationUser,
+ netsharePMAdmin,
+ cn
diff --git a/ldap/cm/v4confs/412/ns-news-globopt.conf b/ldap/cm/v4confs/412/ns-news-globopt.conf
new file mode 100644
index 00000000..b35e2a83
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-news-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape News Server
+#index uniquemember,member eq
+
diff --git a/ldap/cm/v4confs/412/ns-news-schema.conf b/ldap/cm/v4confs/412/ns-news-schema.conf
new file mode 100644
index 00000000..777f339a
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-news-schema.conf
@@ -0,0 +1,35 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+attribute nsnewsACL 2.16.840.1.113730.3.1.191 cis
+attribute nsaclrole 2.16.840.1.113730.3.1.192 cis
+attribute nsprettyname 2.16.840.1.113730.3.1.193 cis
+attribute nsflags 2.16.840.1.113730.3.1.194 cis
+attribute nscreator 2.16.840.1.113730.3.1.195 cis
+attribute ngcomponent 2.16.840.1.113730.3.1.196 dn
+
+objectclass nginfo
+ oid 2.16.840.1.113730.3.2.26
+ requires
+ objectClass,
+ ngcomponent
+ allows
+ nsnewsACL,
+ subtreeACI,
+ description,
+ nsaclrole,
+ nsprettyname,
+ nsflags,
+ nscreator
+
+objectClass netscapeNewsServer
+ oid 2.16.840.1.113730.3.2.27
+ requires
+ objectClass
+
diff --git a/ldap/cm/v4confs/412/ns-proxy-globopt.conf b/ldap/cm/v4confs/412/ns-proxy-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-proxy-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/cm/v4confs/412/ns-proxy-schema.conf b/ldap/cm/v4confs/412/ns-proxy-schema.conf
new file mode 100644
index 00000000..3d26bacb
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-proxy-schema.conf
@@ -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
+#
+# Used by Netscape Directory Server
+objectclass netscapeProxyServer
+ oid 2.16.840.1.113730.3.2.28
+ requires
+ objectclass
+
diff --git a/ldap/cm/v4confs/412/ns-value-schema.conf b/ldap/cm/v4confs/412/ns-value-schema.conf
new file mode 100644
index 00000000..c4b9d3c9
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-value-schema.conf
@@ -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
+#
+# Schema for defining schemaless config for LDAP
+#
+
+attribute nsValueCIS 2.16.840.1.113730.3.1.243 cis
+attribute nsValueCES 2.16.840.1.113730.3.1.244 ces
+attribute nsValueTel 2.16.840.1.113730.3.1.245 tel
+attribute nsValueInt 2.16.840.1.113730.3.1.246 int
+attribute nsValueBin 2.16.840.1.113730.3.1.247 bin
+attribute nsValueDN 2.16.840.1.113730.3.1.248 dn
+attribute nsValueType 2.16.840.1.113730.3.1.249 cis
+attribute nsValueDefault 2.16.840.1.113730.3.1.250 cis
+attribute nsValueFlags 2.16.840.1.113730.3.1.251 cis
+attribute nsValueDescription 2.16.840.1.113730.3.1.252 cis
+attribute nsValueSyntax 2.16.840.1.113730.3.1.253 cis
+attribute nsValueHelpURL 2.16.840.1.113730.3.1.254 ces
+
+objectClass nsValueItem
+ oid 2.16.840.1.113730.3.2.45
+ requires
+ objectClass,
+ cn
+ allows
+ nsValueCIS,
+ nsValueCES,
+ nsValueTel,
+ nsValueInt,
+ nsValueBin,
+ nsValueDN,
+ nsValueType,
+ nsValueSyntax,
+ nsValueDescription,
+ nsValueHelpURL,
+ nsValueFlags,
+ nsValueDefault
+
diff --git a/ldap/cm/v4confs/412/ns-wcal-globopt.conf b/ldap/cm/v4confs/412/ns-wcal-globopt.conf
new file mode 100644
index 00000000..72b108c7
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-wcal-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#used by Netscape Calendar Hosting Server 1.0
+
+index nswcalCALID pres,eq
diff --git a/ldap/cm/v4confs/412/ns-wcal-schema.conf b/ldap/cm/v4confs/412/ns-wcal-schema.conf
new file mode 100644
index 00000000..97a6d12d
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-wcal-schema.conf
@@ -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
+#
+# Used by Netscape Calendar Hosting Server
+
+# Login calendar URI for this user
+attribute nswcalCALID 2.16.840.1.113730.3.1.537 cis single
+
+# Calendar client specific user preferences for this user
+attribute nswcalExtendedUserPrefs 2.16.840.1.113730.3.1.538 cis
+
+# Lists calendar protocols not allowed to be used by this user
+attribute nswcalDisallowAccess 2.16.840.1.113730.3.1.539 cis single
+
+# Calendar host for this user's login calendar
+attribute nswcalHost 2.16.840.1.113730.3.1.540 cis
+
+# Quota associated with this user's calendars
+attribute nswcalQuota 2.16.840.1.113730.3.1.541 cis single
+
+# Used to designate a LDAP entry as representing a Netscape Calendar
+# Hosting Server user account. These first 10 attributes are
+# referenced by Netscape Calendar Hosting Server and the last 3
+# attributes are reserved for future use.
+objectClass nswcalUser
+ oid 2.16.840.1.113730.3.2.83
+ requires
+ objectClass
+ allows
+ cn,
+ givenName,
+ mail,
+ preferredlanguage,
+ sn,
+ uid,
+ userPassword,
+ nswcalCALID,
+ nswcalDisallowAccess,
+ nswcalExtendedUserPrefs,
+ nslicensedfor,
+ nswcalHost,
+ nswcalQuota
+
+# From http://www.imc.org/draft-ietf-calsch-locating
+attribute calCalURI 1.2.840.113556.1.4.478 cis
+attribute calFBURL 1.2.840.113556.1.4.479 cis
+attribute calCAPURI 1.2.840.113556.1.4.480 cis
+attribute calCalAdrURI 1.2.840.113556.1.4.481 cis
+attribute calOtherCalURIs 1.2.840.113556.1.4.482 cis
+attribute calOtherFBURLs 1.2.840.113556.1.4.483 cis
+attribute calOtherCAPURIs 1.2.840.113556.1.4.484 cis
+attribute calOtherCalAdrURIs 1.2.840.113556.1.4.485 cis
+
+# Used to designate a LDAP entry as representing a calendar user.
+objectClass calEntry
+ oid 1.2.840.113556.1.5.87
+ requires
+ objectClass
+ allows
+ calCalURI,
+ calFBURL,
+ calCAPURI,
+ calCalAdrURI,
+ calOtherCalURIs,
+ calOtherFBURLs,
+ calOtherCAPURIs,
+ calOtherCalAdrURIs
diff --git a/ldap/cm/v4confs/412/ns-web-globopt.conf b/ldap/cm/v4confs/412/ns-web-globopt.conf
new file mode 100644
index 00000000..4db72fe2
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-web-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Enterprise Server
+#index uniquemember,member eq
+
diff --git a/ldap/cm/v4confs/412/ns-web-schema.conf b/ldap/cm/v4confs/412/ns-web-schema.conf
new file mode 100644
index 00000000..d5e74ed8
--- /dev/null
+++ b/ldap/cm/v4confs/412/ns-web-schema.conf
@@ -0,0 +1,18 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+objectclass netscapeWebServer
+ oid 2.16.840.1.113730.3.2.29
+ superior top
+ requires
+ cn,
+ nsServerID
+ allows
+ description,
+ nsServerPort
+
diff --git a/ldap/cm/v4confs/412/slapd.at.conf b/ldap/cm/v4confs/412/slapd.at.conf
new file mode 100644
index 00000000..1772f1fe
--- /dev/null
+++ b/ldap/cm/v4confs/412/slapd.at.conf
@@ -0,0 +1,391 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.at.conf for Netscape Directory Server 4.1
+#
+# DO NOT MODIFY!
+#
+# The attributes listed in this file are Standard Attributes and are
+# expected to present in Directory Server 4.1. Editing this file could
+# cause interoperability problems.
+#
+# User Defined Attributes should be added by selecting
+# Schema | Edit or View Attributes from the Admin Server.
+#
+# User Defined Attributes are placed in slapd.user_at.conf.
+#
+# All attributes are viewable over LDAP in the cn=schema entry under
+# attributetypes.
+#
+# The format of this file is:
+#
+# attribute attribute-name [attribute-aliases] [attribute-oid] syntax
+#
+# If no OID is specified, <attribute-name>-oid will be used as the OID
+#
+
+########################################################################
+# X.500(93) User Schema for use with LDAP
+# Taken from <draft-ietf-asid-ldapv3schema-x500-00.txt>
+########################################################################
+
+attribute objectClass 2.5.4.0 cis
+attribute aliasedObjectName 2.5.4.1 dn
+attribute knowledgeInformation 2.5.4.2 cis
+attribute cn commonName 2.5.4.3 cis
+attribute sn surName 2.5.4.4 cis
+attribute serialNumber 2.5.4.5 cis
+attribute c countryName 2.5.4.6 cis
+attribute l locality localityname 2.5.4.7 cis
+attribute st stateOrProvinceName 2.5.4.8 cis
+attribute street streetaddress 2.5.4.9 cis
+attribute o organizationname 2.5.4.10 cis
+attribute ou organizationalUnitName 2.5.4.11 cis
+attribute title 2.5.4.12 cis
+attribute description 2.5.4.13 cis
+attribute searchGuide 2.5.4.14 ces
+attribute businessCategory 2.5.4.15 cis
+attribute postalAddress 2.5.4.16 cis
+attribute postalCode 2.5.4.17 cis
+attribute postOfficeBox 2.5.4.18 cis
+attribute physicalDeliveryOfficeName 2.5.4.19 cis
+attribute telephoneNumber 2.5.4.20 tel
+attribute telexNumber 2.5.4.21 cis
+attribute teletexTerminalIdentifier 2.5.4.22 cis
+attribute facsimileTelephoneNumber fax 2.5.4.23 tel
+attribute x121Address 2.5.4.24 ces
+attribute internationalIsdnNumber 2.5.4.25 ces
+attribute registeredAddress 2.5.4.26 cis
+attribute destinationIndicator 2.5.4.27 cis
+attribute preferredDeliveryMethod 2.5.4.28 cis single
+attribute presentationAddress 2.5.4.29 ces
+attribute supportedApplicationContext 2.5.4.30 cis
+attribute member 2.5.4.31 dn
+attribute owner 2.5.4.32 dn
+attribute roleOccupant 2.5.4.33 dn
+attribute seeAlso 2.5.4.34 dn
+attribute userPassword 2.5.4.35 bin
+attribute userCertificate 2.5.4.36 bin
+attribute cACertificate cACertificate 2.5.4.37 bin
+attribute authorityRevocationList authorityRevocationList 2.5.4.38 bin
+attribute certificateRevocationList certificateRevocationList 2.5.4.39 bin
+attribute crossCertificatePair crossCertificatePair 2.5.4.40 bin
+attribute givenName 2.5.4.42 cis
+attribute initials 2.5.4.43 cis
+attribute generationQualifier 2.5.4.44 cis
+attribute x500UniqueIdentifier 2.5.4.45 bin
+attribute dnQualifier 2.5.4.46 cis
+attribute enhancedSearchGuide 2.5.4.47 cis
+attribute protocolInformation 2.5.4.48 cis
+attribute dn distinguishedName 2.5.4.49 dn
+attribute uniqueMember 2.5.4.50 dn
+attribute houseIdentifier 2.5.4.51 cis
+attribute supportedAlgorithms 2.5.4.52 bin
+attribute deltaRevocationList 2.5.4.53 bin
+
+#######################################################################
+# LDAP Attributes #
+# Taken from <draft-ietf-asid-ldapv3-attributes-07.txt> #
+#######################################################################
+
+attribute createTimestamp 2.5.18.1 cis
+attribute modifyTimestamp 2.5.18.2 cis
+attribute creatorsName 2.5.18.3 dn
+attribute modifiersName 2.5.18.4 dn
+attribute subschemaSubentry 2.5.18.10 dn
+attribute attributeTypes 2.5.21.5 cis
+attribute objectClasses 2.5.21.6 cis
+attribute matchingRules 2.5.21.4 cis
+attribute matchingRuleUse 2.5.21.8 cis
+attribute dITStructureRules 2.5.21.1 cis
+attribute dITContentRules 2.5.21.2 cis
+attribute nameForms 2.5.21.7 cis
+
+attribute namingContexts 1.3.6.1.4.1.1466.101.120.5 dn
+attribute altServer 1.3.6.1.4.1.1466.101.120.6 ces
+attribute supportedExtension 1.3.6.1.4.1.1466.101.120.7 cis
+attribute supportedControl 1.3.6.1.4.1.1466.101.120.13 cis
+attribute supportedSASLMechanisms 1.3.6.1.4.1.1466.101.120.14 cis
+attribute supportedLDAPVersion 1.3.6.1.4.1.1466.101.120.15 int
+attribute ldapSyntaxes 1.3.6.1.4.1.1466.101.120.16 cis
+
+#######################################################################
+# Pilot X.500 schema for use in LDAPv3 #
+# Taken from <draft-ietf-asid-schema-pilot-00.txt> #
+#######################################################################
+
+attribute uid 0.9.2342.19200300.100.1.1 cis
+attribute textEncodedORAddress 0.9.2342.19200300.100.1.2 cis
+attribute mail rfc822mailbox 0.9.2342.19200300.100.1.3 cis
+attribute info 0.9.2342.19200300.100.1.4 cis
+attribute drink 0.9.2342.19200300.100.1.5 cis
+attribute roomNumber 0.9.2342.19200300.100.1.6 cis
+attribute userClass 0.9.2342.19200300.100.1.8 cis
+attribute host 0.9.2342.19200300.100.1.9 cis
+attribute manager 0.9.2342.19200300.100.1.10 dn
+attribute documentIdentifier 0.9.2342.19200300.100.1.11 cis
+attribute documentTitle 0.9.2342.19200300.100.1.12 cis
+attribute documentVersion 0.9.2342.19200300.100.1.13 cis
+attribute documentAuthor 0.9.2342.19200300.100.1.14 dn
+attribute documentLocation 0.9.2342.19200300.100.1.15 cis
+attribute homePhone 0.9.2342.19200300.100.1.20 tel
+attribute secretary 0.9.2342.19200300.100.1.21 dn
+attribute otherMailbox 0.9.2342.19200300.100.1.22 cis
+attribute dc domaincomponent 0.9.2342.19200300.100.1.25 cis
+attribute dNSRecord 0.9.2342.19200300.100.1.26 cis
+attribute associatedName 0.9.2342.19200300.100.1.38 dn
+attribute homePostalAddress 0.9.2342.19200300.100.1.39 cis
+attribute personalTitle 0.9.2342.19200300.100.1.40 cis
+attribute mobile mobileTelephoneNumber 0.9.2342.19200300.100.1.41 tel
+attribute pager pagerTelephoneNumber 0.9.2342.19200300.100.1.42 tel
+attribute co friendlycountryname 0.9.2342.19200300.100.1.43 cis
+attribute uniqueIdentifier 0.9.2342.19200300.100.1.44 cis
+attribute organizationalStatus 0.9.2342.19200300.100.1.45 cis
+attribute janetMailbox 0.9.2342.19200300.100.1.46 cis
+attribute mailPreferenceOption 0.9.2342.19200300.100.1.47 int single
+attribute buildingName 0.9.2342.19200300.100.1.48 cis
+attribute dSAQuality 0.9.2342.19200300.100.1.49 cis single
+attribute singleLevelQuality 0.9.2342.19200300.100.1.50 cis single
+attribute subtreeMinimumQuality 0.9.2342.19200300.100.1.51 cis single
+attribute subtreeMaximumQuality 0.9.2342.19200300.100.1.52 cis single
+attribute personalSignature 0.9.2342.19200300.100.1.53 bin
+attribute ditRedirect 0.9.2342.19200300.100.1.54 dn
+attribute audio 0.9.2342.19200300.100.1.55 bin
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis
+attribute jpegPhoto 0.9.2342.19200300.100.1.60 bin
+
+#definitions subsequent to RFC 1274
+
+attribute labeledUri labeledurl 1.3.6.1.4.1.250.1.57 ces
+
+
+############################################################################
+# Netscape Defined Attributes
+#
+# The Netscape base OID is 2.16.840.1.113730
+# The base OID for the Netscape Directory Server is 2.16.840.1.113730.3
+# Netscape defined attributes have base 2.16.840.1.113730.3.1
+#
+# More Netscape defined attributes can be found included in ns-schema.conf
+############################################################################
+
+attribute carLicense 2.16.840.1.113730.3.1.1 cis
+attribute departmentNumber 2.16.840.1.113730.3.1.2 cis
+attribute employeeNumber 2.16.840.1.113730.3.1.3 cis single
+attribute employeeType 2.16.840.1.113730.3.1.4 cis
+attribute changeNumber 2.16.840.1.113730.3.1.5 int
+attribute targetDn 2.16.840.1.113730.3.1.6 dn
+attribute changeType 2.16.840.1.113730.3.1.7 cis
+attribute changes 2.16.840.1.113730.3.1.8 bin
+attribute newRdn 2.16.840.1.113730.3.1.9 dn
+attribute deleteOldRdn 2.16.840.1.113730.3.1.10 cis
+attribute newSuperior 2.16.840.1.113730.3.1.11 dn
+attribute ref 2.16.840.1.113730.3.1.34 ces
+attribute nsLicensedFor 2.16.840.1.113730.3.1.36 cis
+attribute nsLicenseStartTime 2.16.840.1.113730.3.1.37 cis
+attribute nsLicenseEndTime 2.16.840.1.113730.3.1.38 cis
+attribute preferredLanguage 2.16.840.1.113730.3.1.39 cis single
+attribute userSMIMECertificate 2.16.840.1.113730.3.1.40 bin
+attribute ntUserDomainId 2.16.840.1.113730.3.1.41 cis single
+attribute ntUserCreateNewAccount 2.16.840.1.113730.3.1.42 cis single
+attribute ntUserDeleteAccount 2.16.840.1.113730.3.1.43 cis single
+attribute ntGroupDomainId 2.16.840.1.113730.3.1.44 cis single
+attribute ntGroupCreateNewGroup 2.16.840.1.113730.3.1.45 cis single
+attribute ntGroupDeleteGroup 2.16.840.1.113730.3.1.46 cis single
+attribute ntGroupType 2.16.840.1.113730.3.1.47 cis single
+attribute replicaPort 2.16.840.1.113730.3.1.48 cis
+attribute replicaUpdateFailedAt 2.16.840.1.113730.3.1.49 cis
+attribute replicaBeginOrc 2.16.840.1.113730.3.1.50 cis
+attribute replicaUpdateReplayed 2.16.840.1.113730.3.1.51 cis
+attribute replicaUpdateSchedule 2.16.840.1.113730.3.1.52 cis
+attribute replicaBindMethod 2.16.840.1.113730.3.1.53 cis
+attribute replicaUseSSL 2.16.840.1.113730.3.1.54 cis
+attribute aci 2.16.840.1.113730.3.1.55 bin
+attribute lastModifiedBy 0.9.2342.19200300.100.1.24 dn
+attribute replicaRoot 2.16.840.1.113730.3.1.57 dn
+attribute replicaBindDn 2.16.840.1.113730.3.1.58 dn
+attribute ntUserPriv 2.16.840.1.113730.3.1.59 bin single
+attribute ntUserAuthFlags 2.16.840.1.113730.3.1.60 bin single
+attribute ntUserUsrComment 2.16.840.1.113730.3.1.61 cis single
+attribute ntUserParms 2.16.840.1.113730.3.1.62 cis single
+attribute ntUserUnitsPerWeek 2.16.840.1.113730.3.1.63 bin single
+attribute ntUserNumLogons 2.16.840.1.113730.3.1.64 bin single
+attribute ntUserLogonServer 2.16.840.1.113730.3.1.65 cis single
+attribute ntUserUniqueId 2.16.840.1.113730.3.1.66 bin single
+attribute ntUserProfile 2.16.840.1.113730.3.1.67 cis single
+attribute ntUserPasswordExpired 2.16.840.1.113730.3.1.68 bin single
+attribute subtreeACI 2.16.840.1.113730.3.1.69 ces
+attribute serverRoot 2.16.840.1.113730.3.1.70 cis
+attribute serverProductName 2.16.840.1.113730.3.1.71 cis
+attribute serverVersionNumber 2.16.840.1.113730.3.1.72 cis
+attribute installationTimeStamp 2.16.840.1.113730.3.1.73 cis
+attribute administratorContactInfo 2.16.840.1.113730.3.1.74 cis
+attribute adminUrl 2.16.840.1.113730.3.1.75 ces
+attribute serverHostName 2.16.840.1.113730.3.1.76 cis
+attribute changeTime 2.16.840.1.113730.3.1.77 cis
+attribute cirReplicaRoot 2.16.840.1.113730.3.1.79 dn
+attribute cirHost 2.16.840.1.113730.3.1.80 cis
+attribute cirPort 2.16.840.1.113730.3.1.81 cis
+attribute cirBindDn 2.16.840.1.113730.3.1.82 dn
+attribute cirUsePersistentSearch 2.16.840.1.113730.3.1.83 cis
+attribute cirUseSsl 2.16.840.1.113730.3.1.84 cis
+attribute cirBindCredentials 2.16.840.1.113730.3.1.85 ces
+attribute cirLastUpdateApplied 2.16.840.1.113730.3.1.86 cis
+attribute cirUpdateSchedule 2.16.840.1.113730.3.1.87 cis
+attribute cirUpdateFailedat 2.16.840.1.113730.3.1.88 cis
+attribute cirSyncInterval 2.16.840.1.113730.3.1.89 cis
+attribute cirBeginORC 2.16.840.1.113730.3.1.90 cis
+attribute passwordExpirationTime 2.16.840.1.113730.3.1.91 cis operational
+attribute passwordExpWarned 2.16.840.1.113730.3.1.92 cis operational
+attribute passwordRetryCount 2.16.840.1.113730.3.1.93 cis operational
+attribute retryCountResetTime 2.16.840.1.113730.3.1.94 cis operational
+attribute accountUnlockTime 2.16.840.1.113730.3.1.95 cis operational
+attribute passwordHistory 2.16.840.1.113730.3.1.96 bin operational
+attribute passwordMaxAge 2.16.840.1.113730.3.1.97 cis
+attribute passwordExp 2.16.840.1.113730.3.1.98 cis
+attribute passwordMinLength 2.16.840.1.113730.3.1.99 cis
+attribute passwordKeepHistory 2.16.840.1.113730.3.1.100 cis
+attribute passwordInHistory 2.16.840.1.113730.3.1.101 cis
+attribute passwordChange 2.16.840.1.113730.3.1.102 cis
+attribute passwordCheckSyntax 2.16.840.1.113730.3.1.103 cis
+attribute passwordWarning 2.16.840.1.113730.3.1.104 cis
+attribute passwordLockout 2.16.840.1.113730.3.1.105 cis
+attribute passwordMaxFailure 2.16.840.1.113730.3.1.106 cis
+attribute passwordResetDuration 2.16.840.1.113730.3.1.107 cis
+attribute passwordUnlock 2.16.840.1.113730.3.1.108 cis
+attribute passwordLockoutDuration 2.16.840.1.113730.3.1.109 cis
+attribute ntGroupId 2.16.840.1.113730.3.1.110 bin single
+attribute replicaHost 2.16.840.1.113730.3.1.197 cis
+attribute memberURL 2.16.840.1.113730.3.1.198 ces
+attribute memberCertificateDescription 2.16.840.1.113730.3.1.199 ces
+attribute replicaCredentials 2.16.840.1.113730.3.1.202 bin
+attribute replicaEntryFilter 2.16.840.1.113730.3.1.203 ces
+attribute replicaNickName 2.16.840.1.113730.3.1.204 cis
+attribute filterInfo 2.16.840.1.113730.3.1.206 cis
+attribute replicaCFUpdated 2.16.840.1.113730.3.1.217 cis
+attribute replicaAbandonedChanges 2.16.840.1.113730.3.1.218 cis
+attribute vlvBase 2.16.840.1.113730.3.1.207 dn
+attribute vlvScope 2.16.840.1.113730.3.1.208 int
+attribute vlvFilter 2.16.840.1.113730.3.1.209 ces
+attribute vlvSort 2.16.840.1.113730.3.1.210 cis
+attribute vlvName 2.16.840.1.113730.3.1.211 ces
+attribute netscapeMDSuffix 2.16.840.1.113730.3.1.212 dn
+attribute vlvEnabled 2.16.840.1.113730.3.1.213 int
+attribute passwordAllowChangeTime 2.16.840.1.113730.3.1.214 cis operational
+attribute oid 2.16.840.1.113730.3.1.215 cis
+attribute userPKCS12 2.16.840.1.113730.3.1.216 bin
+attribute vlvUses 2.16.840.1.113730.3.1.219 int
+attribute passwordMustChange 2.16.840.1.113730.3.1.220 cis
+attribute passwordStorageScheme 2.16.840.1.113730.3.1.121 cis
+attribute passwordMinAge 2.16.840.1.113730.3.1.122 cis
+attribute passwordResetFailureCount 2.16.840.1.113730.3.1.123 cis
+attribute nsslapd-pluginPath 2.16.840.1.113730.3.1.224 cis
+attribute nsslapd-pluginInitfunc 2.16.840.1.113730.3.1.225 cis
+attribute nsslapd-pluginType 2.16.840.1.113730.3.1.226 cis
+attribute nsslapd-pluginId 2.16.840.1.113730.3.1.227 cis
+attribute nsslapd-pluginVersion 2.16.840.1.113730.3.1.228 cis
+attribute nsslapd-pluginVendor 2.16.840.1.113730.3.1.229 cis
+attribute nsslapd-pluginDescription 2.16.840.1.113730.3.1.230 cis
+attribute nsslapd-pluginEnabled 2.16.840.1.113730.3.1.231 cis
+attribute nsSNMPEnabled 2.16.840.1.113730.3.1.232 cis
+attribute nsSNMPOrganization 2.16.840.1.113730.3.1.233 cis
+attribute nsSNMPLocation 2.16.840.1.113730.3.1.234 cis
+attribute nsSNMPContact 2.16.840.1.113730.3.1.235 cis
+attribute nsSNMPDescription 2.16.840.1.113730.3.1.236 cis
+attribute nsSNMPMasterHost 2.16.840.1.113730.3.1.237 cis
+attribute nsSNMPMasterPort 2.16.840.1.113730.3.1.238 cis
+attribute nsslapd-backend 2.16.840.1.113730.3.1.239 cis
+attribute replicatedattributelist 2.16.840.1.113730.3.1.240 cis
+attribute displayName 2.16.840.1.113730.3.1.241 cis single
+attribute nsSystemIndex 2.16.840.1.113730.3.1.242 cis
+attribute nsIndexType 2.16.840.1.113730.3.1.327 cis
+attribute nsMatchingRule 2.16.840.1.113730.3.1.328 cis
+attribute nsAddressBookSyncURL 2.16.840.1.113730.3.1.330 ces
+attribute nsSynchUserIDFormat 2.16.840.1.113730.3.1.406 cis
+attribute nsSynchUniqueAttribute 2.16.840.1.113730.3.1.407 cis
+attribute replicaLastRelevantChange 2.16.840.1.113730.3.1.408 int
+attribute ntUserHomeDir 2.16.840.1.113730.3.1.521 cis single
+attribute ntUserComment 2.16.840.1.113730.3.1.522 cis single
+attribute ntUserFlags 2.16.840.1.113730.3.1.523 bin single
+attribute ntUserScriptPath 2.16.840.1.113730.3.1.524 cis single
+attribute ntUserWorkstations 2.16.840.1.113730.3.1.525 cis single
+attribute ntUserLastLogon 2.16.840.1.113730.3.1.526 cis single
+attribute ntUserLastLogoff 2.16.840.1.113730.3.1.527 cis single
+attribute ntUserAcctExpires 2.16.840.1.113730.3.1.528 cis single
+attribute ntUserMaxStorage 2.16.840.1.113730.3.1.529 bin single
+attribute ntUserLogonHours 2.16.840.1.113730.3.1.530 bin single
+attribute ntUserBadPwCount 2.16.840.1.113730.3.1.531 bin single
+attribute ntUserCountryCode 2.16.840.1.113730.3.1.532 cis single
+attribute ntUserCodePage 2.16.840.1.113730.3.1.533 bin single
+attribute ntUserPrimaryGroupId 2.16.840.1.113730.3.1.534 bin single
+attribute ntUserHomeDirDrive 2.16.840.1.113730.3.1.535 cis single
+attribute ntGroupAttributes 2.16.840.1.113730.3.1.536 bin single
+
+#
+# Attribute types with OIDs
+#
+
+attribute associatedDomain 0.9.2342.19200300.100.1.37 cis
+attribute documentPublisher 0.9.2342.19200300.100.1.56 cis single
+
+
+#
+# Attributes which are used by some objectClass, but with unknown OID
+#
+
+attribute abstract abstract-oid cis
+attribute authorCn documentauthorcommonname authorcn-oid cis
+attribute authorSn documentauthorsurname authorsn-oid cis
+attribute changeLog 2.16.840.1.113730.3.1.35 dn
+attribute changeLogMaximumAge 2.16.840.1.113730.3.1.200 cis
+attribute changeLogMaximumSize 2.16.840.1.113730.3.1.201 cis
+attribute documentStore documentStore-oid cis
+attribute keyWords keyWords-oid cis
+attribute lastModifiedTime 0.9.2342.19200300.100.1.23 cis
+attribute multiLineDescription multiLineDescription-oid cis
+attribute subject subject-oid cis
+attribute ttl timeToLive 1.3.6.1.4.1.250.1.60 cis
+attribute photo 0.9.2342.19200300.100.1.7 bin
+attribute generation generation-oid ces
+attribute obsoletedByDocument obsoletedByDocument-oid dn
+attribute obsoletesDocument obsoletesDocument-oid dn
+attribute reciprocalNamingLink reciprocalNaminglink-oid dn
+attribute updatedByDocument updatedByDocument-oid dn
+attribute updatesDocument updatesDocument-oid dn
+
+#
+# Attribute types from RFC 2307
+#
+
+attribute uidNumber 1.3.6.1.1.1.1.0 int single
+attribute gidNumber 1.3.6.1.1.1.1.1 int single
+attribute gecos 1.3.6.1.1.1.1.2 cis single
+attribute homeDirectory 1.3.6.1.1.1.1.3 ces single
+attribute loginShell 1.3.6.1.1.1.1.4 ces single
+attribute shadowLastChange 1.3.6.1.1.1.1.5 int single
+attribute shadowMin 1.3.6.1.1.1.1.6 int single
+attribute shadowMax 1.3.6.1.1.1.1.7 int single
+attribute shadowWarning 1.3.6.1.1.1.1.8 int single
+attribute shadowInactive 1.3.6.1.1.1.1.9 int single
+attribute shadowExpire 1.3.6.1.1.1.1.10 int single
+attribute shadowFlag 1.3.6.1.1.1.1.11 int single
+attribute memberUid 1.3.6.1.1.1.1.12 ces
+attribute memberNisNetgroup 1.3.6.1.1.1.1.13 ces
+attribute nisNetgroupTriple 1.3.6.1.1.1.1.14 ces
+attribute ipServicePort 1.3.6.1.1.1.1.15 int single
+attribute ipServiceProtocol 1.3.6.1.1.1.1.16 cis
+attribute ipProtocolNumber 1.3.6.1.1.1.1.17 int single
+attribute oncRpcNumber 1.3.6.1.1.1.1.18 int single
+attribute ipHostNumber 1.3.6.1.1.1.1.19 cis
+attribute ipNetworkNumber 1.3.6.1.1.1.1.20 cis single
+attribute ipNetmaskNumber 1.3.6.1.1.1.1.21 cis single
+attribute macAddress 1.3.6.1.1.1.1.22 cis
+attribute bootParameter 1.3.6.1.1.1.1.23 ces
+attribute bootFile 1.3.6.1.1.1.1.24 ces
+attribute automountInformation 1.3.6.1.1.1.1.25 ces
+attribute nisMapName 1.3.6.1.1.1.1.26 cis
+attribute nisMapEntry 1.3.6.1.1.1.1.27 ces single
diff --git a/ldap/cm/v4confs/412/slapd.oc.conf b/ldap/cm/v4confs/412/slapd.oc.conf
new file mode 100644
index 00000000..1e8c451b
--- /dev/null
+++ b/ldap/cm/v4confs/412/slapd.oc.conf
@@ -0,0 +1,1069 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# slapd.oc.conf for Netscape Directory Server 4.1
+#
+# DO NOT MODIFY!
+#
+# The ObjectClasses in this file are Standard ObjectClasses and are expected
+# to be present in Directory Server 4.1 unchanged. Modifing this file may
+# cause interoperability problems.
+#
+# User Defined ObjectClasses should be added by selecting
+# Schema | Create ObjectClasses from the Admin Server.
+#
+# User Defined ObjectClasses are saved in slapd.user_oc.conf
+#
+# All ObjectClasses are viewable in the cn=schema entry under objectclasses.
+#
+# The format of this file is:
+#
+# objectclass ObjectClassName
+# [ oid ObjectIdentifier ]
+# [ superior ParentObjectClass ]
+# [ requires <comma separated list of required attributes> ]
+# [ allows <comma separated list of allowed attributes> ]
+#
+
+objectclass top
+ oid 2.5.6.0
+ requires
+ objectClass
+ allows
+ aci
+
+objectclass alias
+ oid 2.5.6.1
+ superior top
+ requires
+ aliasedObjectName
+
+objectclass country
+ oid 2.5.6.2
+ superior top
+ requires
+ c
+ allows
+ searchGuide,
+ description
+
+objectclass locality
+ oid 2.5.6.3
+ superior top
+ allows
+ description,
+ l,
+ searchGuide,
+ seeAlso,
+ st,
+ street
+
+objectclass organization
+ oid 2.5.6.4
+ superior top
+ requires
+ o
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass organizationalUnit
+ oid 2.5.6.5
+ superior top
+ requires
+ ou
+ allows
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass person
+ oid 2.5.6.6
+ superior top
+ requires
+ sn,
+ cn
+ allows
+ description,
+ seeAlso,
+ telephoneNumber,
+ userPassword
+
+objectclass organizationalPerson
+ oid 2.5.6.7
+ superior person
+ allows
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ title,
+ x121Address
+
+# The certificate attributes include all subtypes, such as ';binary'.
+#
+objectclass inetOrgPerson
+ oid 2.16.840.1.113730.3.2.2
+ superior organizationalPerson
+ allows
+ audio,
+ businessCategory,
+ carLicense,
+ departmentNumber,
+ displayName,
+ employeeType,
+ employeeNumber,
+ givenName,
+ homePhone,
+ homePostalAddress,
+ initials,
+ jpegPhoto,
+ labeledURI,
+ manager,
+ mobile,
+ pager,
+ photo,
+ preferredLanguage,
+ mail,
+ o,
+ roomNumber,
+ secretary,
+ uid,
+ x500uniqueIdentifier,
+ userCertificate,
+ userSMimeCertificate,
+ userPKCS12
+
+objectclass ntUser
+ oid 2.16.840.1.113730.3.2.8
+ superior top
+ requires
+ ntUserDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntUserPriv,
+ ntUserHomeDir,
+ ntUserComment,
+ ntUserFlags,
+ ntUserScriptPath,
+ ntUserAuthFlags,
+ ntUserUsrComment,
+ ntUserParms,
+ ntUserWorkstations,
+ ntUserLastLogon,
+ ntUserLastLogoff,
+ ntUserAcctExpires,
+ ntUserMaxStorage,
+ ntUserUnitsPerWeek,
+ ntUserLogonHours,
+ ntUserBadPwCount,
+ ntUserNumLogons,
+ ntUserLogonServer,
+ ntUserCountryCode,
+ ntUserCodePage,
+ ntUserUniqueId,
+ ntUserPrimaryGroupId,
+ ntUserProfile,
+ ntUserHomeDirDrive,
+ ntUserPasswordExpired,
+ ntUserCreateNewAccount,
+ ntUserDeleteAccount
+
+objectclass ntGroup
+ oid 2.16.840.1.113730.3.2.9
+ superior top
+ requires
+ ntGroupDomainId
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ ntGroupId,
+ ntGroupAttributes,
+ ntGroupCreateNewGroup,
+ ntGroupDeleteGroup,
+ ntGroupType
+
+objectclass organizationalRole
+ oid 2.5.6.8
+ superior top
+ requires
+ cn
+ allows
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ ou,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ roleOccupant,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass groupOfNames
+ oid 2.5.6.9
+ superior top
+ requires
+ cn
+ allows
+ member,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfUniqueNames
+ oid 2.5.6.17
+ superior top
+ requires
+ cn
+ allows
+ uniqueMember,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfCertificates
+ oid 2.16.840.1.113730.3.2.31
+ superior top
+ requires
+ cn
+ allows
+ memberCertificateDescription,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass groupOfURLs
+ oid 2.16.840.1.113730.3.2.33
+ superior top
+ requires
+ cn
+ allows
+ memberURL,
+ businessCategory,
+ description,
+ o,
+ ou,
+ owner,
+ seeAlso
+
+objectclass residentialPerson
+ oid 2.5.6.10
+ superior person
+ requires
+ l
+ allows
+ businessCategory,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ st,
+ street,
+ teletexTerminalIdentifier,
+ telexNumber,
+ x121Address
+
+objectclass applicationProcess
+ oid 2.5.6.11
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso
+
+objectclass LDAPServer
+ oid 2.16.840.1.113730.3.2.35
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ generation,
+ changeLogMaximumAge,
+ changeLogMaximumSize
+
+objectclass LDAPReplica
+ oid 2.16.840.1.113730.3.2.36
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ ou,
+ seeAlso,
+ replicaRoot,
+ replicaHost,
+ replicaPort,
+ replicaBindDn,
+ replicaCredentials,
+ replicaBindMethod,
+ replicaUseSSL,
+ replicaUpdateSchedule,
+ replicaUpdateReplayed,
+ replicaUpdateFailedAt,
+ replicaBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList,
+ replicaCFUpdated,
+ replicaAbandonedChanges,
+ replicaLastRelevantChange
+
+objectclass applicationEntity
+ oid 2.5.6.12
+ superior top
+ requires
+ presentationAddress,
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ supportedApplicationContext
+
+objectclass dSA
+ oid 2.5.6.13
+ superior applicationEntity
+ allows
+ knowledgeInformation
+
+objectclass device
+ oid 2.5.6.14
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# This userCertificate attribute includes all subtypes, such as ';binary'.
+objectclass strongAuthenticationUser
+ oid 2.5.6.15
+ superior top
+ requires
+ userCertificate
+
+# These attributes include all subtypes, such as ';binary'.
+objectclass certificationAuthority
+ oid 2.5.6.16
+ superior top
+ requires
+ cACertificate
+ allows
+ authorityRevocationList,
+ certificateRevocationList,
+ crossCertificatePair
+
+objectclass pilotObject
+ oid 0.9.2342.19200300.100.4.3
+ superior top
+ allows
+ audio,
+ dITRedirect,
+ info,
+ jpegPhoto,
+ lastModifiedBy,
+ lastModifiedTime,
+ manager,
+ photo,
+ uniqueIdentifier
+
+objectclass newPilotPerson
+ oid 0.9.2342.19200300.100.4.4
+ superior person
+ allows
+ businessCategory,
+ drink,
+ homePhone,
+ homePostalAddress,
+ janetMailbox,
+ mail,
+ mailPreferenceOption,
+ mobile,
+ organizationalStatus,
+ otherMailbox,
+ pager,
+ personalSignature,
+ personalTitle,
+ preferredDeliveryMethod,
+ roomNumber,
+ secretary,
+ textEncodedORAddress,
+ uid,
+ userClass
+
+objectclass account
+ oid 0.9.2342.19200300.100.4.5
+ superior top
+ requires
+ uid
+ allows
+ description,
+ host,
+ l,
+ o,
+ ou,
+ seeAlso
+
+objectclass document
+ oid 0.9.2342.19200300.100.4.6
+ superior pilotObject
+ requires
+ documentIdentifier
+ allows
+ abstract,
+ authorCN,
+ authorSN,
+ cn,
+ description,
+ documentAuthor,
+ documentLocation,
+ documentPublisher,
+ documentStore,
+ documentTitle,
+ documentVersion,
+ keywords,
+ l,
+ o,
+ obsoletedByDocument,
+ obsoletesDocument,
+ ou,
+ seeAlso,
+ subject,
+ updatedByDocument,
+ updatesDocument
+
+objectclass room
+ oid 0.9.2342.19200300.100.4.7
+ superior top
+ requires
+ cn
+ allows
+ description,
+ roomNumber,
+ seeAlso,
+ telephoneNumber
+
+objectclass documentSeries
+ oid 0.9.2342.19200300.100.4.9
+ superior top
+ requires
+ cn
+ allows
+ description,
+ l,
+ o,
+ ou,
+ seeAlso,
+ telephoneNumber
+
+objectclass domain
+ oid 0.9.2342.19200300.100.4.13
+ superior top
+ requires
+ dc
+ allows
+ associatedName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ manager,
+ o,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+objectclass RFC822localPart
+ oid 0.9.2342.19200300.100.4.14
+ superior domain
+ allows
+ cn,
+ sn
+
+objectclass DNSDomain
+ oid 0.9.2342.19200300.100.4.15
+ superior domain
+ allows
+ dNSRecord
+
+objectclass domainRelatedObject
+ oid 0.9.2342.19200300.100.4.17
+ superior top
+ requires
+ associatedDomain
+
+objectclass friendlyCountry
+ oid 0.9.2342.19200300.100.4.18
+ superior country
+ requires
+ co
+
+objectclass simpleSecurityObject
+ oid 0.9.2342.19200300.100.4.19
+ superior top
+ requires
+ userPassword
+
+objectclass pilotOrganization
+ oid pilotOrganization-OID
+ superior top
+ requires
+ ou,
+ o
+ allows
+ buildingName,
+ businessCategory,
+ description,
+ destinationIndicator,
+ facsimileTelephoneNumber,
+ internationaliSDNNumber,
+ l,
+ physicalDeliveryOfficeName,
+ postOfficeBox,
+ postalAddress,
+ postalCode,
+ preferredDeliveryMethod,
+ registeredAddress,
+ searchGuide,
+ seeAlso,
+ st,
+ street,
+ telephoneNumber,
+ teletexTerminalIdentifier,
+ telexNumber,
+ userPassword,
+ x121Address
+
+
+objectclass labeledURIObject
+ oid 1.3.6.1.4.1.250.3.15
+ superior top
+ allows
+ labeledURI
+
+objectclass cacheObject
+ oid 1.3.6.1.4.1.250.3.18
+ superior top
+ allows
+ ttl
+
+# objectclasses below added since Netscape Directory Server 1.01
+
+objectclass netscapeServer
+ oid 2.16.840.1.113730.3.2.10
+ superior top
+ requires
+ cn
+ allows
+ description,
+ serverRoot,
+ serverProductName,
+ serverVersionNumber,
+ installationTimeStamp,
+ administratorContactInfo,
+ userpassword,
+ adminURL,
+ serverHostName
+
+objectclass nsLicenseUser
+ oid 2.16.840.1.113730.3.2.7
+ superior top
+ allows
+ nsLicensedFor,
+ nsLicenseStartTime,
+ nsLicenseEndTime
+
+objectclass changeLogEntry
+ oid 2.16.840.1.113730.3.2.1
+ superior top
+ requires
+ targetdn,
+ changeTime,
+ changenumber,
+ changeType
+ allows
+ changes,
+ newrdn,
+ deleteoldrdn,
+ newsuperior,
+ filterinfo
+
+objectclass cirReplicaSource
+ oid 2.16.840.1.113730.3.2.11
+ requires
+ cn,
+ objectClass
+ allows
+ cirReplicaRoot,
+ cirHost,
+ cirPort,
+ cirBindDN,
+ cirUsePersistentSearch,
+ cirUseSSL,
+ cirBindCredentials,
+ cirLastUpdateApplied,
+ cirUpdateSchedule,
+ cirSyncInterval,
+ cirUpdateFailedAt,
+ cirBeginORC,
+ replicaNickname,
+ replicaEntryFilter,
+ replicatedAttributeList
+
+objectclass referral
+ superior top
+ oid 2.16.840.1.113730.3.2.6
+ allows
+ ref
+
+objectclass passwordObject
+ oid 2.16.840.1.113730.3.2.12
+ requires
+ objectClass
+ allows
+ passwordExpirationTime,
+ passwordExpWarned,
+ passwordRetryCount,
+ retryCountResetTime,
+ accountUnlockTime,
+ passwordHistory,
+ passwordAllowChangeTime
+
+objectclass passwordPolicy
+ oid 2.16.840.1.113730.3.2.13
+ requires
+ objectClass
+ allows
+ passwordMaxAge,
+ passwordExp,
+ passwordMinLength,
+ passwordKeepHistory,
+ passwordInHistory,
+ passwordChange,
+ passwordWarning,
+ passwordLockout,
+ passwordMaxFailure,
+ passwordResetDuration,
+ passwordUnlock,
+ passwordLockoutDuration,
+ passwordCheckSyntax,
+ passwordMustChange,
+ passwordStorageScheme,
+ passwordMinAge,
+ passwordResetFailureCount
+
+objectclass glue
+ oid 2.16.840.1.113730.3.2.30
+ superior top
+
+objectclass netscapeMachineData
+ oid 2.16.840.1.113730.3.2.32
+ superior top
+
+objectclass dcObject
+ oid 1.3.6.1.4.1.1466.344
+ superior top
+ requires
+ dc
+
+objectclass subschema
+ oid 2.5.20.1
+ superior top
+ allows
+ cn,
+ dITStructureRules,
+ nameForms,
+ dITContentRules,
+ objectClasses,
+ attributeTypes,
+ matchingRules,
+ matchingRuleUse
+
+objectclass vlvSearch
+ oid 2.16.840.1.113730.3.2.38
+ superior top
+ requires
+ cn,
+ vlvBase,
+ vlvScope,
+ vlvFilter
+ allows
+ multiLineDescription
+
+objectclass nsslapdConfig
+ oid 2.16.840.1.113730.3.2.39
+ superior top
+ allows cn
+
+objectclass directoryServerFeature
+ oid 2.16.840.1.113730.3.2.40
+ superior top
+ allows
+ oid,
+ cn,
+ multiLineDescription
+
+objectclass nsslapdPlugin
+ oid 2.16.840.1.113730.3.2.41
+ superior top
+ requires
+ cn,
+ nsslapd-pluginPath,
+ nsslapd-pluginInitFunc,
+ nsslapd-pluginType,
+ nsslapd-pluginId,
+ nsslapd-pluginVersion,
+ nsslapd-pluginVendor,
+ nsslapd-pluginDescription,
+ nsslapd-pluginEnabled,
+ nsslapd-backend
+
+objectclass vlvIndex
+ oid 2.16.840.1.113730.3.2.42
+ superior top
+ requires
+ cn,
+ vlvSort
+ allows
+ vlvEnabled,
+ vlvUses
+
+objectclass nsSNMP
+ OID 2.16.840.1.113730.3.2.43
+ superior top
+ requires
+ cn,
+ nsSNMPEnabled
+ allows
+ nsSNMPOrganization,
+ nsSNMPLocation,
+ nsSNMPContact,
+ nsSNMPDescription,
+ nsSNMPMasterHost,
+ nsSNMPMasterPort
+
+objectclass nsIndex
+ oid 2.16.840.1.113730.3.2.44
+ superior top
+ requires
+ cn,
+ nsSystemIndex
+ allows
+ description,
+ nsIndexType,
+ nsMatchingRule
+
+#
+# ojectclass from rfc2307
+#
+
+# posixAccount is an auxiliary class. You may use account as a structural
+# class.
+objectclass posixAccount
+ oid
+ 1.3.6.1.1.1.2.0
+ superior
+ top
+ requires
+ objectClass,
+ cn,
+ uid,
+ uidNumber,
+ gidNumber,
+ homeDirectory
+ allows
+ userPassword,
+ loginShell,
+ gecos,
+ description
+
+# posixAccount is an auxiliary class. You may use account as a structural
+# class.
+objectclass shadowAccount
+ oid
+ 1.3.6.1.1.1.2.1
+ superior
+ top
+ requires
+ objectClass,
+ uid
+ allows
+ userPassword,
+ shadowLastChange,
+ shadowMin,
+ shadowMax,
+ shadowWarning,
+ shadowInactive,
+ shadowExpire,
+ shadowFlag,
+ description
+
+objectclass posixGroup
+ oid
+ 1.3.6.1.1.1.2.2
+ requires
+ objectClass,
+ cn,
+ gidNumber
+ allows
+ userPassword,
+ memberUid,
+ description
+
+objectclass ipService
+ oid
+ 1.3.6.1.1.1.2.3
+ requires
+ objectClass,
+ cn,
+ ipServicePort,
+ ipServiceProtocol
+ allows
+ description
+
+objectclass ipProtocol
+ oid
+ 1.3.6.1.1.1.2.4
+ requires
+ objectClass,
+ cn,
+ ipProtocolNumber
+ allows
+ description
+
+objectclass oncRpc
+ oid
+ 1.3.6.1.1.1.2.5
+ requires
+ objectClass,
+ cn,
+ oncRpcNumber
+ allows
+ description
+
+# ipHost is a subclass of device
+objectclass ipHost
+ oid
+ 1.3.6.1.1.1.2.6
+ requires
+ objectClass,
+ ipHostNumber,
+ cn
+ allows
+ manager,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+
+objectclass ipNetwork
+ oid
+ 1.3.6.1.1.1.2.7
+ requires
+ objectClass,
+ ipNetworkNumber,
+ cn
+ allows
+ ipNetmaskNumber,
+ manager,
+ l,
+ description
+
+objectclass nisNetgroup
+ oid
+ 1.3.6.1.1.1.2.8
+ requires
+ objectClass,
+ cn
+ allows
+ nisNetgroupTriple,
+ memberNisNetgroup,
+ description
+
+# the automount class is deprecated. Because cn is case insensitive
+# on matches, you may need to use another object class to unique
+# names.
+objectclass automount
+ oid
+ 1.3.6.1.1.1.2.9
+ requires
+ objectClass,
+ cn,
+ automountInformation
+ allows
+ description
+
+# nisObject represents entries in NIS maps.
+objectclass nisObject
+ oid
+ 1.3.6.1.1.1.2.10
+ requires
+ objectClass,
+ cn,
+ nisMapEntry,
+ nisMapName
+ allows
+ description
+
+# ieee802Device is a subclass of device
+objectclass ieee802Device
+ oid
+ 1.3.6.1.1.1.2.11
+ requires
+ objectClass,
+ cn
+ allows
+ macAddress,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# bootableDevice is a subclass of device
+objectclass bootableDevice
+ oid
+ 1.3.6.1.1.1.2.12
+ requires
+ objectClass,
+ cn
+ allows
+ bootFile,
+ bootParameter,
+ description,
+ l,
+ o,
+ ou,
+ owner,
+ seeAlso,
+ serialNumber
+
+# nisMap is a structural class which may be used as a container
+# for instances of nisObject.
+objectclass nisMap
+ oid
+ 1.3.6.1.1.1.2.13
+ requires
+ objectClass,
+ nisMapName
+ allows
+ description
+
diff --git a/ldap/docs/LICENSE.txt b/ldap/docs/LICENSE.txt
new file mode 100644
index 00000000..974a08ee
--- /dev/null
+++ b/ldap/docs/LICENSE.txt
@@ -0,0 +1,6 @@
+Use of this software product is governed by the license agreement provided
+by Netscape Communications Corporation. By typing "Yes" in agreement to the
+license terms or by installing or using the software, you confirm that your
+organization has agreed to be bound by the license terms and that you and your
+organization will use this product only in accordance with those license terms.
+
diff --git a/ldap/docs/README.txt b/ldap/docs/README.txt
new file mode 100644
index 00000000..be0a799e
--- /dev/null
+++ b/ldap/docs/README.txt
@@ -0,0 +1,19 @@
+=======================================================================
+ Netscape Directory Server 6.2.1 (Unix and Windows)
+=======================================================================
+
+Thank you for purchasing the Netscape Directory 6.2.1 Server. The
+Directory Server is subject to the terms detailed in the license
+agreement file called LICENSE.txt.
+
+For problem reports, please include the machine type and operating
+system along with a specific description of the problem. Due
+to the volume of comments, we cannot personally reply to every comment.
+However, we do read every comment and attempt to incorporate your feedback
+in future releases of the product when appropriate.
+
+For late-breaking news and information on the Directory Server, please see
+the release notes for this release. The release notes are available at
+the following location:
+
+ http://enterprise.netscape.com/docs/directory/
diff --git a/ldap/docs/dirhlp/Makefile b/ldap/docs/dirhlp/Makefile
new file mode 100644
index 00000000..4d478ce9
--- /dev/null
+++ b/ldap/docs/dirhlp/Makefile
@@ -0,0 +1,196 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms.
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2002-2003 Netscape Communications Corporation.
+# All rights reserved.
+#
+#
+# GNU Makefile for Directory Server Console Help
+#
+
+MCOM_ROOT = ../../../..
+LDAP_SRC = ../..
+MODULE=httpdAdminHTML
+
+NOSTDCLEAN=true # don't let nsconfig.mk define target clean
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+HTMLDEST=$(OBJDIR)/manual/slapd
+NEWHTMLDEST=$(OBJDIR)/manual/slapd/help
+COPYRIGHTDEST=$(OBJDIR)/manual/slapd/copyright
+
+NOSTDSTRIP=true
+NOSTDDEPEND=true
+
+HTML= index.map index.htm netscape48.gif pixel.gif
+
+NEWHTMLTOKEN=tokens.map
+NEWHTMLTOPIC=topicindex.htm
+
+COPYRIGHTFILES=copyright.html
+
+NEWHTML = account_mgmt.htm \
+ adv_search.htm \
+ configtab_chaindb.htm \
+ configtab_chaindb2.htm \
+ configtab_chaindb3.htm \
+ configtab_chaindb4.htm \
+ configtab_chaindb5.htm \
+ configtab_chaindb6.htm \
+ configtab_chaindb7.htm \
+ configtab_db.htm \
+ configtab_db10.htm \
+ configtab_db11.htm \
+ configtab_db12.htm \
+ configtab_db13.htm \
+ configtab_db14.htm \
+ configtab_db15.htm \
+ configtab_db2.htm \
+ configtab_db3.htm \
+ configtab_db4.htm \
+ configtab_db5.htm \
+ configtab_db6.htm \
+ configtab_db7.htm \
+ configtab_db8.htm \
+ configtab_db9.htm \
+ configtab_ldbmdb.htm \
+ configtab_logs.htm \
+ configtab_logs2.htm \
+ configtab_logs3.htm \
+ configtab_maptree.htm \
+ configtab_maptree2.htm \
+ configtab_maptree3.htm \
+ configtab_maptree4.htm \
+ configtab_maptree5.htm \
+ configtab_maptree6.htm \
+ configtab_maptree7.htm \
+ configtab_plugins.htm \
+ configtab_replication.htm \
+ configtab_replication2.htm \
+ configtab_replication3.htm \
+ configtab_replication4.htm \
+ configtab_replication5.htm \
+ configtab_replication6.htm \
+ configtab_replication7.htm \
+ configtab_replication8.htm \
+ configtab_rootnode.htm \
+ configtab_rootnode2.htm \
+ configtab_rootnode3.htm \
+ configtab_rootnode4.htm \
+ configtab_rootnode5.htm \
+ configtab_rootnode6.htm \
+ configtab_rootnode7.htm \
+ configtab_rootnode8.htm \
+ configtab_rootnode9.htm \
+ configtab_schema.htm \
+ configtab_schema2.htm \
+ configtab_schema3.htm \
+ configtab_schema4.htm \
+ configtab_schema5.htm \
+ dirtab_cos.htm \
+ dirtab_cos2.htm \
+ dirtab_cos3.htm \
+ dirtab_role.htm \
+ dirtab_role2.htm \
+ dirtab_role3.htm \
+ dirtab_role4.htm \
+ dirtab_role5.htm \
+ dirtab_role6.htm \
+ dirtab_role7.htm \
+ dir_browser.htm \
+ dir_browser2.htm \
+ dir_browser3.htm \
+ dir_browser4.htm \
+ helpmenu.htm \
+ ix.htm \
+ ldapurl.htm \
+ netscape32.gif \
+ new_instance.htm \
+ pixel.gif \
+ property_editor.htm \
+ property_editor2.htm \
+ property_editor3.htm \
+ property_editor4.htm \
+ redir_agtoc.htm \
+ redir_dochome.htm \
+ replication_wizard.htm \
+ replication_wizard2.htm \
+ replication_wizard3.htm \
+ replication_wizard4.htm \
+ replication_wizard5.htm \
+ statustab_general.htm \
+ statustab_logs.htm \
+ statustab_logs2.htm \
+ statustab_logs3.htm \
+ statustab_performance.htm \
+ statustab_performance2.htm \
+ statustab_replication.htm \
+ taskstab_bkup_restore.htm \
+ taskstab_bkup_restore2.htm \
+ topics.htm \
+ sniffer.js
+
+
+BINS=$(addprefix $(HTMLDEST)/,$(HTML))
+
+NEWBINS = $(addprefix $(NEWHTMLDEST)/,$(NEWHTML)) \
+ $(addprefix $(HTMLDEST)/,$(NEWHTMLTOKEN)) \
+ $(addprefix $(HTMLDEST)/,$(NEWHTMLTOPIC))
+
+COPYRIGHTBINS = $(addprefix $(COPYRIGHTDEST)/,$(COPYRIGHTFILES))
+
+all: $(HTMLDEST) $(BINS) $(NEWHTMLDEST) $(NEWBINS) $(COPYRIGHTDEST) $(COPYRIGHTBINS)
+
+$(HTMLDEST):
+ mkdir -p $(HTMLDEST)
+
+$(NEWHTMLDEST):
+ mkdir -p $(NEWHTMLDEST)
+
+$(COPYRIGHTDEST):
+ mkdir -p $(COPYRIGHTDEST)
+
+strip:
+
+depend:
+
+clean:
+
+ -$(RM) -f $(BINS) $(NEWBINS) $(COPYRIGHTBINS)
+
+$(HTMLDEST)/%.js: %.js
+ -$(RM) -f $@
+ cp $< $@
+
+$(HTMLDEST)/%.map: %.map
+ -$(RM) -f $@
+ cp $< $@
+
+$(HTMLDEST)/%.htm: %.htm
+ -$(RM) -f $@
+ cp $< $@
+
+$(HTMLDEST)/%.jpg: %.jpg
+ -$(RM) -f $@
+ cp $< $@
+
+$(NEWHTMLDEST)/%.htm: %.htm
+ -$(RM) -f $@
+ cp $< $@
+
+$(HTMLDEST)/%.gif: %.gif
+ -$(RM) -f $@
+ cp $< $@
+
+$(NEWHTMLDEST)/%.gif: %.gif
+ -$(RM) -f $@
+ cp $< $@
+
+$(COPYRIGHTDEST)/%.html: copyright/%.html
+ -$(RM) -f $@
+ cp $< $@
+
+HTMLDEFS=-DPRODUCT_NAME=$(PRODUCT) -D$(ARCH) -DARCH=$(PRETTY_ARCH)
diff --git a/ldap/docs/dirhlp/dssynchhelp.z b/ldap/docs/dirhlp/dssynchhelp.z
new file mode 100644
index 00000000..1c141cdf
--- /dev/null
+++ b/ldap/docs/dirhlp/dssynchhelp.z
Binary files differ
diff --git a/ldap/docs/dirhlp/help/account_mgmt.htm b/ldap/docs/dirhlp/help/account_mgmt.htm
new file mode 100644
index 00000000..27a5c814
--- /dev/null
+++ b/ldap/docs/dirhlp/help/account_mgmt.htm
@@ -0,0 +1,183 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: User Account</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="26399"> </a>
+<a name="User Account"> </a>
+User Account
+</p>
+
+<p class="text">
+<a name="26446"> </a>
+Use this tab to manage the user account. You can use it to inactivate or activate a user account, as well as set resource limits for a particular user.
+</p>
+<p class="text">
+<a name="26459"> </a>
+<b>Activation. </b>This section provides information about whether the account is active or inactive. If the account is active, you can click the Inactivate button to inactivate it. If the account is inactive, click the Activate button to activate it.
+</p>
+<p class="text">
+<a name="26449"> </a>
+<b>Resource limits.</b> This section lets you set resource limits for a particular user.
+</p>
+<ul>
+
+<li>
+<b>Look through limit. </b>Specifies how many entries can be examined for a search operation.
+<a name="26460"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Size limit. </b>Specifies the maximum number of entries the server returns to a client application in response to a search operation.
+<a name="26450"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Time limit. </b>Specifies the maximum time the server spends processing a search operation.
+<a name="26451"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Idle timeout. </b>Specifies the time a connection to the server can be idle before the connection is dropped.
+<a name="26452"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="h2">
+<a name="26465"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="26447"> </a>
+<a href="../en/slapd/ag/password.htm">User Account Management</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/adv_search.htm b/ldap/docs/dirhlp/help/adv_search.htm
new file mode 100644
index 00000000..a16cb20b
--- /dev/null
+++ b/ldap/docs/dirhlp/help/adv_search.htm
@@ -0,0 +1,142 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: Advanced Search</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="26445"> </a>
+<a name="Advanced Search"> </a>
+Advanced Search
+</p>
+
+<p class="text">
+<a name="16235"> </a>
+Use this dialog box to search the user directory with a search filter.
+</p>
+<p class="text">
+<a name="16224"> </a>
+<b>Search Filter. </b>Enter the search filter you want to use in this text box and then click OK.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_chaindb.htm b/ldap/docs/dirhlp/help/configtab_chaindb.htm
new file mode 100644
index 00000000..42d01b81
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_chaindb.htm
@@ -0,0 +1,189 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Create New Database Link</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28932"> </a>
+<a name="Create New Database Link"> </a>
+Create New Database Link
+</p>
+
+<p class="text">
+<a name="28934"> </a>
+The database link contacts other servers on behalf of a client application and returns the combined results to the client application after finishing the operation. Use the following attributes to configure a new database link:
+</p>
+<p class="text">
+<a name="28935"> </a>
+<b>Database link name.</b> Unique name of the database link.
+</p>
+<p class="text">
+<a name="28936"> </a>
+<b>Bind DN.</b> DN of an administrative user by the database link to bind to the remote server. If this field is left blank, the database link binds as anonymous. Note that the bind DN cannot be the directory manager.
+</p>
+<p class="text">
+<a name="28937"> </a>
+<b>Password.</b> Password for the administrative user, in plain text. If no password is provided, it means that the database link can bind as anonymous.
+</p>
+<p class="text">
+<a name="28938"> </a>
+<b>Remote server(s) information. </b>In this section you provide information about the remote data sources used by the database link.
+</p>
+<p class="text">
+<a name="28939"> </a>
+<b>Use a secure LDAP connection between servers.</b> Selecting this checkbox indicates that the connection between the server and the remote server is secure.
+</p>
+<p class="text">
+<a name="28940"> </a>
+<b>Remote Server.</b> The name of the remote data source.
+</p>
+<p class="text">
+<a name="28941"> </a>
+<b>Remote server port.</b> The port number on the remote data source used by the database link.
+</p>
+<p class="text">
+<a name="28942"> </a>
+<b>Failover Server(s).</b> You can specify optional servers for failover in the event that the primary remote server is unavailable. This field contains the name of an alternative remote server. Click Add to add the name and port number to the list.
+</p>
+<p class="text">
+<a name="28943"> </a>
+<b>Port.</b> Port number of an alternative remote server.
+</p>
+<p class="text">
+<a name="28944"> </a>
+<b>LDAP URL. </b>This field contains a dynamically created LDAP URL that combines the server names and port numbers you specified in the remote server information fields.
+</p>
+<p class="h2">
+<a name="28945"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28948"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#22197">Creating a Maintaining Database Links</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_chaindb2.htm b/ldap/docs/dirhlp/help/configtab_chaindb2.htm
new file mode 100644
index 00000000..f70ed6ca
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_chaindb2.htm
@@ -0,0 +1,191 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Database Link Settings</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28956"> </a>
+<a name="Database Link Settings"> </a>
+Database Link Settings
+</p>
+
+<p class="text">
+<a name="28958"> </a>
+Use the Settings tab to set the default settings for all new database links.
+</p>
+<p class="text">
+<a name="28959"> </a>
+<b>LDAP controls forwarded by database link.</b> This list contains the OIDs of LDAP controls which are allowed to chain. By default, requests made by the following controls are forwarded to the remote server by the database link:
+</p>
+<ul>
+
+<li>
+Virtual list view (VLV) control. This control provides lists of parts of entries rather than returning all entry information. The OID of this control is 2.16.840.1.113730.3.4.9.
+<a name="28960"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Server side sorting control. This control sorts entries according to their attribute values. The OID for this control is 1.2.840.113556.1.4.473.
+<a name="28961"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Managed DSA control. This control returns smart referrals as entries rather than following the referral. This allows you to modify or delete the smart referral itself. The OID for this control is 2.16.840.1.113730.3.4.2.
+<a name="28962"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Loop detection control. This control contains a count that is decremented each time the server tries to chain. When the server receives a count of 0 it determines that a loop has been detected and notifies the client application. The OID for this control is 1.3.6.1.4.1.1466.29539.12.
+<a name="28963"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28964"> </a>
+Click Add to select an LDAP control OID from a list.
+</p>
+<p class="text">
+<a name="28965"> </a>
+<b>Components allowed to chain.</b> A component is any functional unit in the server that uses internal operations. You may need to control the chaining policy of some components so that they can complete their operations successfully. By default, all internal operations are not chained. You can override this default by specifying components in this list.
+</p>
+<p class="text">
+<a name="28966"> </a>
+Click Add and select the component you want to allow to chain from the list.
+</p>
+<p class="h2">
+<a name="28967"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28970"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#21771">Configuring the Chaining Policy</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_chaindb3.htm b/ldap/docs/dirhlp/help/configtab_chaindb3.htm
new file mode 100644
index 00000000..87dc0f89
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_chaindb3.htm
@@ -0,0 +1,325 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Select Controls to Add</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28992"> </a>
+<a name="Select Controls to Add"> </a>
+Select Controls to Add
+</p>
+
+<p class="text">
+<a name="28994"> </a>
+Select an OID from the list and click OK. The following table describes the OIDs listed in the UI by default:
+</p>
+<br />
+<p class="caption">
+<a name="28997"> </a>
+<a name="LDAP Control OIDs &nbsp;"> </a>
+Table 1 &nbsp;&nbsp; LDAP Control OIDs &nbsp;
+
+</p>
+
+<br/>
+<table width="90%" border="1" cellspacing="0" cellpadding="4">
+<tr bgcolor="#CCCCCC" align="left" valign="top">
+<th valign="top" align="left">
+<p class="tablehead">
+<a name="29001"> </a>
+OID
+</p>
+</th>
+<th valign="top" align="left">
+<p class="tablehead">
+<a name="29003"> </a>
+LDAP Control Description
+</p>
+</th>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29005"> </a>
+2.16.840.1.113730.3.4.3
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29007"> </a>
+Persistent search control.
+</p><p class="tabletext">
+<a name="29008"> </a>
+This control is used with a search request to indicate that the server should not complete the request when all the matching entries have been returned. Instead, the server should keep the operation active and send results to the client whenever an entry matching the search filter is added, deleted, or modified.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29010"> </a>
+2.16.840.1.113730.3.4.4
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29012"> </a>
+Password expired notification control.
+</p><p class="tabletext">
+<a name="29013"> </a>
+This control notifies a client application that their password has expired.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29015"> </a>
+2.16.840.1.113730.3.4.5
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29017"> </a>
+Password expiring notification control.
+</p><p class="tabletext">
+<a name="29018"> </a>
+This control notifies a client application that their password will expire in a given amount of time.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29020"> </a>
+2.16.840.1.113730.3.4.16
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29022"> </a>
+Authentication request control.
+</p><p class="tabletext">
+<a name="29023"> </a>
+This control can be provided with a bind request to indicate to the server that an authentication response control is desired with the bind response.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29025"> </a>
+2.16.840.1.113730.3.4.15
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29027"> </a>
+Authentication response control.
+</p><p class="tabletext">
+<a name="29028"> </a>
+This control is returned with the client application bind request to provide LDAP clients with the DN and authentication method used (useful when SASL or certificate is employed).
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29030"> </a>
+2.16.840.1.113730.3.4.17
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29032"> </a>
+Real attribute only request control.
+</p><p class="tabletext">
+<a name="29033"> </a>
+This control requests that the server return only attributes that are truly contained in the entries returned and that the directory does not try to resolve virtual attributes.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29035"> </a>
+2.16.840.1.113730.3.4.14
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29037"> </a>
+Search on specific database control.
+</p><p class="tabletext">
+<a name="29038"> </a>
+This control can be used with search operations to specify that the search must be done on the database which is named in the control.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29040"> </a>
+2.16.840.1.113730.3.4.12
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29042"> </a>
+Proxied authorization control.
+</p><p class="tabletext">
+<a name="29043"> </a>
+This control allows the client to assume the identity of another entry for the duration of a request.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29045"> </a>
+2.16.840.1.113730.3.4.13
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29047"> </a>
+Replication update information control.
+</p><p class="tabletext">
+<a name="29048"> </a>
+This control carries the universally unique identifier (UUID) and change sequence number (CSN) of a replicated operation.
+</p></td>
+
+</tr>
+
+</table>
+
+
+<br />
+<br />
+
+<p class="h2">
+<a name="29050"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="29053"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#21771">Configuring the Chaining Policy</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_chaindb4.htm b/ldap/docs/dirhlp/help/configtab_chaindb4.htm
new file mode 100644
index 00000000..fa9ad0ed
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_chaindb4.htm
@@ -0,0 +1,277 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:03" />
+<title>Netscape Directory Server Help: Select Components to Add</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29064"> </a>
+<a name="Select Components to Add"> </a>
+Select Components to Add
+</p>
+
+<p class="text">
+<a name="29066"> </a>
+Select a component from the list. By default, the list contains the following components:
+</p>
+<br />
+<p class="caption">
+<a name="29072"> </a>
+<a name="Components Available for Chaining &nbsp;"> </a>
+Table 2 &nbsp;&nbsp; Components Available for Chaining &nbsp;
+
+</p>
+
+<br/>
+<table width="90%" border="1" cellspacing="0" cellpadding="4">
+<tr bgcolor="#CCCCCC" align="left" valign="top">
+<th valign="top" align="left">
+<p class="tablehead">
+<a name="29076"> </a>
+Component DN
+</p>
+</th>
+<th valign="top" align="left">
+<p class="tablehead">
+<a name="29078"> </a>
+Description
+</p>
+</th>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29080"> </a>
+cn=resource limits,<br />cn=components, cn=config
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29082"> </a>
+Resource limits plug-in.
+</p><p class="tabletext">
+<a name="29083"> </a>
+Resource limits can be applied to remote users if the resource limit plug-in is allowed to chain.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29085"> </a>
+cn=certificate-based authentication<br />cn=components, cn=config
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29087"> </a>
+Certificate-based authentication plug-in.
+</p><p class="tabletext">
+<a name="29088"> </a>
+This component is used when the SASL-external bind method is used. It retrieves the user certificate from the local remote data source. If you allow this component to chain, certificate-based authentication can work with a database link.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29090"> </a>
+cn=ACL plugin, cn=plugins, cn=config
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29092"> </a>
+ACL plug-in.
+</p><p class="tabletext">
+<a name="29093"> </a>
+Operations used to retrieve and update ACI attributes are not chained because it is not safe to mix local and remote ACI attributes. However, requests used to retrieve user entries may be chained.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29095"> </a>
+cn=old plugin, cn=plugins, cn=config
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29100"> </a>
+Directory Server 4.0 plug-ins.
+</p><p class="tabletext">
+<a name="29104"> </a>
+All Directory Server version 4.0 plug-ins share the same chaining policy, so selecting this option from the list enables them all to chain.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29106"> </a>
+cn=referential integrity postoperation,<br />cn=plugins, cn=config
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29108"> </a>
+Referential integrity plug-in.
+</p><p class="tabletext">
+<a name="29109"> </a>
+This plug-in ensures that updates made to attributes containing DNs are propagated to all entries that contain pointers to the attribute. For example, if you delete an entry that is a member of a group, the entry is automatically removed from the group.
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="29111"> </a>
+cn=attribute uniqueness, cn=plugins,<br />cn=config
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="29113"> </a>
+Attribute uniqueness plug-in.
+</p><p class="tabletext">
+<a name="29114"> </a>
+Confirms that the value of a particular attribute is unique across the local server.
+</p></td>
+
+</tr>
+
+</table>
+
+
+<br />
+<br />
+
+<p class="h2">
+<a name="29116"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="29119"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#21771">Configuring the Chaining Policy</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_chaindb5.htm b/ldap/docs/dirhlp/help/configtab_chaindb5.htm
new file mode 100644
index 00000000..f4a1fe47
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_chaindb5.htm
@@ -0,0 +1,242 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Default Creation Parameters</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29141"> </a>
+<a name="Default Creation Parameters"> </a>
+Default Creation Parameters
+</p>
+
+<p class="text">
+<a name="29143"> </a>
+Use this dialog box to set the default attributes for all of your database links.
+</p>
+<p class="text">
+<a name="29144"> </a>
+<b>Control Client Return.</b> These options help you specify how the database link responds to client application requests.
+</p>
+<ul>
+
+<li>
+<b>Return referral on scoped search.</b> Select this option to return referrals to client applications in response to scoped searches. Choosing to return referrals optimizes directory server performance, as referrals are more efficient than searching for data in remote databases.
+<a name="29145"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Size limit X entries.</b> Specifies the number of entries the database link returns in response to a search request. The default size limit is 2000 entries.
+<a name="29146"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Time limit X seconds.</b> Specifies the search time limit for the database link. The default value is 3600 seconds.
+<a name="29147"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="29148"> </a>
+<b>Cascading Chaining.</b> Use the following options to configure cascading chaining, when one database link points to another database link.
+</p>
+<ul>
+
+<li>
+<b>Check local ACI.</b> Select this checkbox to enable evaluation of local ACIs on all database links involved in a chaining operation.
+<a name="29149"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum hops.</b> Specifies the number of hops, or times one database link contacts another, allowed. When one database link connects to another, this count decrements. Each subsequent database link contacted further decrements the count. If a server receives a count of 0 it determines that a loop has been detected and notifies the client application. The range is 0 to 20.
+<a name="29150"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+ <dl>
+ <dt> <a name="29151"> </a>
+The default maximum hops value is 10.
+<br />&nbsp;</dt> </dl>
+</ul>
+<p class="text">
+<a name="29152"> </a>
+<b>Connection Management.</b> Use these options to configure the pool of connections maintained by the database link with the remote server.
+</p>
+<ul>
+
+<li>
+<b>Maximum TCP connection(s).</b> Maximum number of TCP connections the database link establishes with the remote server. The default value is 3 connections. The range is 1 to 50.
+<a name="29153"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Bind timeout. </b>Amount of time, in seconds, before the bind attempt times out. The default value is 15 seconds. The range is 0 to 3600 seconds.
+<a name="29154"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum binds per connection.</b> Maximum number of outstanding bind operations per TCP connection. The default value is 10 outstanding bind operations. The range is 0 to 25.
+<a name="29155"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Timeout before abandon.</b> The number of seconds that pass before the server checks for abandon operations. The default value is 10 second The range is 0 to 2147483647.
+<a name="29156"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum LDAP connection(s).</b> Maximum number of LDAP connections the database link establishes with the remote server. The default value is 10 connections. The range is 1 to 50.
+<a name="29157"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum bind retries.</b> Number of times a database link attempts to bind with the remote database. A value of zero indicates that the database link will try to bind only once. The default value is 3 attempts. The range of values is 0 to 10.
+<a name="29158"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum operations per connection.</b> Maximum number of outstanding operations per connection. The default value is 10 operations per second. The range is 0 to 50.
+<a name="29159"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Connection life (sec). </b>You can keep connections between the database link and the remote database open for an unspecified time, or you can close them after a specific period. It is faster to keep the connections open, but it uses more resources.
+<a name="29160"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+ <dl>
+ <dt> <a name="29161"> </a>
+A value of 0 indicates that there is no limit. By default, the value is set to 0. The range is 0 to 2147483647 seconds.
+<br />&nbsp;</dt> </dl>
+</ul>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_chaindb6.htm b/ldap/docs/dirhlp/help/configtab_chaindb6.htm
new file mode 100644
index 00000000..1a3f9b81
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_chaindb6.htm
@@ -0,0 +1,249 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Database Link Limits and Controls</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29183"> </a>
+<a name="Database Link Limits and Controls"> </a>
+Database Link Limits and Controls
+</p>
+
+<p class="text">
+<a name="29185"> </a>
+Use the Limits and Controls tab to override the defaults set in Default Creation Parameters tab of the Database link Settings node. You can customize how the database link returns data to client applications and manages connection, and you can configure cascading chaining (in which one database link connects to another).
+</p>
+<p class="text">
+<a name="29186"> </a>
+<b>Control Client Return. </b>These options help you specify how the database link responds to client application requests.
+</p>
+<ul>
+
+<li>
+<b>Return referral on scoped search.</b> Select this option to return referrals to client applications in response to scoped searches. Choosing to return referrals optimizes directory server performance, as referrals are more efficient than searching for data in remote databases.
+<a name="29187"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Size limit X entries.</b> Specifies the number of entries the database link returns in response to a search request. The default size limit is 2000 entries. The range is from -1 (no limit) to 2147483647.
+<a name="29188"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Time limit X seconds.</b> Specifies the search time limit for the database link. After the time limit has passed, the connection is timed out. The default value is 3600 seconds. The value range is -1 (for no limit) to 2147483647.
+<a name="29189"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="29190"> </a>
+<b>Cascading Chaining.</b> Use the following options to configure cascading chaining, when one database link points to another database link.
+</p>
+<ul>
+
+<li>
+<b>Check local ACI.</b> Select this checkbox to enable evaluation of local ACIs on all database links involved in a chaining operation.
+<a name="29191"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum hops.</b> Specifies the number of hops, or times a database link contacts another, allowed. When one database link connects to another, this count decrements. Each subsequent database link contacted further decrements the count. If a server receives a count of 0 it determines that a loop has been detected and notifies the client application.
+<a name="29192"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+ <dl>
+ <dt> <a name="29193"> </a>
+The default maximum hops value is 10. The range of values is 0 to 20.
+<br />&nbsp;</dt> </dl>
+</ul>
+<p class="text">
+<a name="29194"> </a>
+<b>Connection Management.</b> Use these options to configure the pool of connections maintained by the database link with the remote server.
+</p>
+<ul>
+
+<li>
+<b>Maximum TCP connection(s).</b> Maximum number of TCP connections the database link establishes with the remote server. The default value is 3 connections. The value range is 0 to 50.
+<a name="29195"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Bind timeout. </b>Amount of time, in seconds, before the bind attempt times out. The default value is 15 seconds.
+<a name="29196"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum binds per connection.</b> Maximum number of outstanding bind operations per TCP connection. The default value is 10 outstanding bind operations. The range of values is from 1 to 25.
+<a name="29197"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Timeout before abandon.</b> The number of seconds that pass before the server checks for abandon operations. The default value is 10 seconds. The range is 0 to 2147483647.
+<a name="29198"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum LDAP connection(s).</b> Maximum number of LDAP connections the database link establishes with the remote server. The default value is 10 connections. The value range is 1 to 50.
+<a name="29199"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum bind retries.</b> Number of times a database link attempts to bind with the remote database. A value of zero indicates that the database link will try to bind only once. The default value is 3 attempts. The range is from 0 to 10.
+<a name="29200"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Maximum operations per connection.</b> Maximum number of outstanding operations per connection. The default value is 10 operations per second. The range is from 0 to 50.
+<a name="29201"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Connection life (sec).</b> You can keep connections between the database link and the remote database open for an unspecified time, or you can close them after a specific period. It is faster to keep the connections open, but it uses more resources. The range is from 0 (no limit) to 2147483647 seconds.
+<a name="29202"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="h2">
+<a name="29203"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="29205"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#21771">Configuring the Chaining Policy
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_chaindb7.htm b/ldap/docs/dirhlp/help/configtab_chaindb7.htm
new file mode 100644
index 00000000..9b6076b2
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_chaindb7.htm
@@ -0,0 +1,193 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Database Link Authentication</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29213"> </a>
+<a name="Database Link Authentication"> </a>
+Database Link Authentication
+</p>
+
+<p class="text">
+<a name="29215"> </a>
+Use the authentication tab to set the attributes required for your new database link to connect with a remote data source on another server.
+</p>
+<p class="text">
+<a name="29216"> </a>
+<b>Suffix managed by this database link. </b>The suffix of your directory information tree managed by this database link.
+</p>
+<p class="text">
+<a name="29217"> </a>
+<b>Remote server URL. </b>The LDAP URL of the remote server to which this database link connects. The LDAP URL syntax is <br><code>ldap://</code><span class="variable">server</span><code>:[</code><span class="variable">port</span><code>][</code> <span class="variable">server</span><code>[:</code><span class="variable">port</span><code>]]/</code>
+</p>
+<p class="text">
+<a name="29218"> </a>
+<b>Database link bind DN. </b>The DN used by the database link to bind with the remote server. This DN cannot be the directory manager.
+</p>
+<p class="text">
+<a name="29219"> </a>
+<b>Database link password.</b> Password used by the database link to bind with the remote server.
+</p>
+<p class="text">
+<a name="29220"> </a>
+<b>Confirm database link password.</b> Confirm the remote password.
+</p>
+<p class="text">
+<a name="29221"> </a>
+<b>Remote server checklist. </b>Lists what you need to configure on the remote server for database link to successfully chain operations.
+</p>
+<ul>
+
+<li>
+<b>User entry. </b>You need to create an entry in the remote database that corresponds to the DN you specified as the remote server bind DN for the database link.
+<a name="29222"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Suffix. </b>The suffix associated with the database link must be present on the remote server.
+<a name="29223"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>ACI. </b>Provides a sample proxy authorization ACI that need to be added to the naming context on the remote database to which the database link points. This ACI gives the proxy administrative user access only to the data contained within the subtree on which it is specified.
+<a name="29224"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="h2">
+<a name="29225"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="29228"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#21771">Configuring the Chaining Policy</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db.htm b/ldap/docs/dirhlp/help/configtab_db.htm
new file mode 100644
index 00000000..bd37e086
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db.htm
@@ -0,0 +1,207 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Indexes</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28605"> </a>
+<a name="Indexes"> </a>
+Indexes
+</p>
+
+<p class="text">
+<a name="28607"> </a>
+Use the tables contained by this tab to set up the indexes for your database. Browsing indexes are set up on the Directory tab of the Directory Server Console.
+</p>
+<p class="text">
+<a name="28608"> </a>
+This tab displays two sets of indexes, system indexes and additional indexes.
+</p>
+<p class="text">
+<a name="28609"> </a>
+<b>System Indexes (Read-Only).</b> Directory Server creates system indexes by default. They are used internally by the server and cannot be removed.
+</p>
+<p class="text">
+<a name="28610"> </a>
+<b>Additional Indexes</b>. You can specify a standard set of indexes for Directory Server to maintain.
+</p>
+<ul>
+
+<li>
+<b>Attribute name. </b>Contains the name of the attribute to be indexed.
+<a name="28611"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Approximate.</b> Select this checkbox to configure the server to create and maintain an approximate, or "sounds-like," index for the attribute; clear this checkbox to discontinue indexing on this attribute.
+<a name="28612"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Equality.</b> Select this checkbox to configure the server to create and maintain an equality index for the attribute; clear this checkbox to discontinue indexing on this attribute.
+<a name="28613"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Presence.</b> Select this checkbox to configure the server to create and maintain a presence index for the attribute; clear this checkbox to discontinue indexing on this attribute.
+<a name="28614"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Substring.</b> Select this checkbox to configure the server to create and maintain a substring index for the attribute; clear this checkbox to discontinue indexing on this attribute.
+<a name="28615"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Matching rule.</b> Enter the matching rule OID (if any) you want the server to use when client applications search the directory using this attribute.
+<a name="28616"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28617"> </a>
+<b>Add attribute.</b> If the attribute you want to index is not listed in the table, click the "Add Attribute" button. This brings up the Select Attribute dialog box. Select the attribute you want to add and click OK.
+</p>
+<p class="text">
+<a name="28618"> </a>
+<b>Delete attribute.</b> To remove all of the indexes for a particular attribute, select the attribute in the table, click Delete Attribute, and then click Save.
+</p>
+<p class="h2">
+<a name="28619"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28622"> </a>
+<a href="../en/slapd/ag/index1.htm">Managing Indexes</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db10.htm b/ldap/docs/dirhlp/help/configtab_db10.htm
new file mode 100644
index 00000000..5d96f655
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db10.htm
@@ -0,0 +1,161 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Export Single Database</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28833"> </a>
+<a name="Export Single Database"> </a>
+Export Single Database
+</p>
+
+<p class="text">
+<a name="28835"> </a>
+Use this dialog box to export a single database to LDIF.
+</p>
+<p class="text">
+<a name="28836"> </a>
+<b>LDIF file (on remote machine). </b>Enter the full path to the LDIF file. Click Browse to locate it on your machine. By default, if you are running the console locally, the file is stored in the current directory.
+</p>
+<p class="text">
+<a name="28837"> </a>
+When the Browse button is not enabled, by default the file is stored in /<code>usr/netscape/servers/slapd-</code><span class="variable">serverID</span><code>/ldif</code>
+</p>
+<p class="h2">
+<a name="28841"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28844"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1055442">Exporting a Single Database to LDIF Using the Console</a>
+</p>
+<p class="text">
+<a name="28847"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1111210">Exporting Directory Data to LDIF Using the Console</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db11.htm b/ldap/docs/dirhlp/help/configtab_db11.htm
new file mode 100644
index 00000000..abdc0baf
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db11.htm
@@ -0,0 +1,154 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: LDBM Plug-in Settings</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28855"> </a>
+<a name="LDBM Plug-in Settings"> </a>
+LDBM Plug-in Settings
+</p>
+
+<p class="text">
+<a name="28857"> </a>
+Use this tab to configure general database settings.
+</p>
+<p class="text">
+<a name="28858"> </a>
+<b>Maximum cache size.</b> Memory available on disk for all indexes. By default, the value is 10000000 bytes.
+</p>
+<p class="text">
+<a name="28859"> </a>
+<b>Look-through limit. </b>Maximum number of entries the directory checks in response to a search request. The default value is 5000 entries.
+</p>
+<p class="text">
+<a name="28860"> </a>
+<b>Database mode files.</b> Specific permissions applied to the database, in octal.
+</p>
+<p class="text">
+<a name="28861"> </a>
+<b>Import cache size.</b> Memory available on disk for the database to cache information during an import operation, in bytes.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db12.htm b/ldap/docs/dirhlp/help/configtab_db12.htm
new file mode 100644
index 00000000..ba3c1000
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db12.htm
@@ -0,0 +1,170 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Default Indexes</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28871"> </a>
+<a name="Default Indexes"> </a>
+Default Indexes
+</p>
+
+<p class="text">
+<a name="28873"> </a>
+Use this tab to configure the default indexes for your databases.
+</p>
+<p class="text">
+<a name="28874"> </a>
+<b>Attribute name. </b>Contains the name of the attribute to be indexed.
+</p>
+<p class="text">
+<a name="28875"> </a>
+<b>Approximate.</b> Select this checkbox to configure the server to create and maintain an approximate, or "sounds-like," index for the attribute; clear this checkbox to discontinue indexing on this attribute.
+</p>
+<p class="text">
+<a name="28876"> </a>
+<b>Equality.</b> Select this checkbox to configure the server to create and maintain an equality index for the attribute; clear this checkbox to discontinue indexing on this attribute.
+</p>
+<p class="text">
+<a name="28877"> </a>
+<b>Presence.</b> Select this checkbox to configure the server to create and maintain a presence index for the attribute; clear this checkbox to discontinue indexing on this attribute.
+</p>
+<p class="text">
+<a name="28878"> </a>
+<b>Substring.</b> Select this checkbox to configure the server to create and maintain a substring index for the attribute; clear this checkbox to discontinue indexing on this attribute.
+</p>
+<p class="text">
+<a name="28879"> </a>
+<b>Matching rule.</b> Enter the matching rule OID (if any) you want the server to use when client applications search the directory using this attribute.
+</p>
+<p class="text">
+<a name="28880"> </a>
+<b>Add attribute.</b> If the attribute you want to index is not listed in the table, click the "Add Attribute" button. This brings up the Select Attribute dialog box. Select the attribute you want to add and click OK.
+</p>
+<p class="text">
+<a name="28881"> </a>
+<b>Delete attribute.</b> To remove all of the indexes for a particular attribute, select the attribute in the table, click Delete Attribute, and then click Save.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db13.htm b/ldap/docs/dirhlp/help/configtab_db13.htm
new file mode 100644
index 00000000..f7de97d1
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db13.htm
@@ -0,0 +1,112 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+ <meta name="keywords"
+ content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace">
+ <meta name="description"
+ content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software.">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="templatebase"
+ content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6">
+ <meta name="LASTUPDATED" content="04/29/03 15:35:31">
+ <title>Netscape Directory Server Help: Settings Tab</title>
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+ <script type="text/JavaScript" src="help_files/sniffer.js">
+
+ </script>
+
+</head>
+<body style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);"
+ link="#006666" vlink="#006666" alink="#000066">
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent--><!--navigationcontent defines the top row of links and the banner --><!--start navigationcontent-->
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr>
+ <td valign="bottom" width="67"> <img
+ src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0"
+ alt="Netscape logo"></td>
+ <td valign="middle"> <span class="product">Netscape
+Directory Server</span> <span class="booktitle">Console Help</span> </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <hr size="1" noshade="noshade"><span class="navigation"> <a
+ style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+ </a> </span>&nbsp;&nbsp;&nbsp;&nbsp; </td>
+ </tr>
+ </tbody>
+</table>
+<!--end navigationcontent-->
+<!--bookcontent defines the actual content of the file, sans headers and footers --><!--start bookcontent-->
+<blockquote><br>
+ <p class="h1"> <a name="28258"> </a><a name="Settings Tab"> </a>Attribute
+Encryption Tab<br>
+ </p>
+ <p class="text"> <a name="25219"> </a>By configuring attribute
+encryption, or database encryption, it is possible to encrypt highly
+sensitive information as it is stored within the database. The values
+of these attributes are encrypted and can only be read during a secure
+session. Use this tab to select
+attributes to encrypt.<br>
+ </p>
+ <p class="text"><b>Encrypted Attributes.</b> Text box of encrypted
+attributes.<br>
+ </p>
+ <ul>
+ <li><span style="font-weight: bold;">Attribute name.</span> The
+name of the attribute that is encrypted.<br>
+ </li>
+ <li><span style="font-weight: bold;">Encryption Algorithm.</span>
+The encryption cipher used to encrypt that attribute.<br>
+ </li>
+ </ul>
+ <p class="text"> </p>
+ <p class="text"> <a name="25220"> </a><b>Add attribute.</b> Brings
+up a list of all system attributes that can be encrypted.<br>
+ </p>
+ <p class="text"> <a name="25221"> </a><b>Delete attribute.</b>
+Deletes an encrypted attribute. This does not delete the attribute or
+its value; it disables encryption.<br>
+ <br>
+ </p>
+ <p class="text"><big>See also</big><br>
+ <a href="/manual/en/slapd/ag/entry_dist.htm">Configuring Directory
+Databases</a><br>
+ </p>
+</blockquote>
+<br>
+<br>
+<span class="navigation">
+<a style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+</a>
+</span>&nbsp;&nbsp;&nbsp;&nbsp;
+<hr noshade="noshade" size="1">
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright
+1999, 2002-2003 Netscape Communications Corporation. All rights
+reserved.</p>
+<br>
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+<!--end footercontent--><!--end maincontent-->
+</body>
+</html>
diff --git a/ldap/docs/dirhlp/help/configtab_db14.htm b/ldap/docs/dirhlp/help/configtab_db14.htm
new file mode 100644
index 00000000..b80f9eab
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db14.htm
@@ -0,0 +1,87 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+ <meta name="keywords"
+ content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace">
+ <meta name="description"
+ content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software.">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="templatebase"
+ content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6">
+ <meta name="LASTUPDATED" content="04/29/03 15:35:31">
+ <title>Netscape Directory Server Help: Settings Tab</title>
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+ <script type="text/JavaScript" src="help_files/sniffer.js">
+
+ </script>
+
+</head>
+<body style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);"
+ link="#006666" vlink="#006666" alink="#336666">
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent--><!--navigationcontent defines the top row of links and the banner --><!--start navigationcontent-->
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr>
+ <td valign="bottom" width="67"> <img
+ src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0"
+ alt="Netscape logo"></td>
+ <td valign="middle"> <span class="product">Netscape
+Directory Server</span> <span class="booktitle">Console Help</span> </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <hr size="1" noshade="noshade"><span class="navigation"> <a
+ style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+ </a> </span>&nbsp;&nbsp;&nbsp;&nbsp; </td>
+ </tr>
+ </tbody>
+</table>
+<!--end navigationcontent-->
+<!--bookcontent defines the actual content of the file, sans headers and footers --><!--start bookcontent-->
+<blockquote><br>
+ <p class="h1"> <a name="28258"> </a><a name="Settings Tab"> </a>Attribute
+Encryption - Add
+Attribute Button<br>
+ </p>
+ <p class="text"> <a name="25219"> </a>A list of all
+system attributes that can be encrypted, in the "Select Attribute to
+Encrypt" box.<br>
+ </p>
+Select an attribute you wish to encrypt, and click OK. This will bring
+up the "Select Encryption Method" box.</blockquote>
+<br>
+<br>
+<span class="navigation">
+<a style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+</a>
+</span>&nbsp;&nbsp;&nbsp;&nbsp;
+<hr noshade="noshade" size="1">
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright
+1999, 2002-2003 Netscape Communications Corporation. All rights
+reserved.</p>
+<br>
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+<!--end footercontent--><!--end maincontent-->
+</body>
+</html>
diff --git a/ldap/docs/dirhlp/help/configtab_db15.htm b/ldap/docs/dirhlp/help/configtab_db15.htm
new file mode 100644
index 00000000..04d2e7d9
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db15.htm
@@ -0,0 +1,94 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+ <meta name="keywords"
+ content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace">
+ <meta name="description"
+ content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software.">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="templatebase"
+ content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6">
+ <meta name="LASTUPDATED" content="04/29/03 15:35:31">
+ <title>Netscape Directory Server Help: Settings Tab</title>
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+ <script type="text/JavaScript" src="help_files/sniffer.js">
+
+ </script>
+
+</head>
+<body style="background-color: rgb(255, 255, 255); color: rgb(0, 0, 0);"
+ alink="#333366" vlink="#006666" link="#006666">
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent--><!--navigationcontent defines the top row of links and the banner --><!--start navigationcontent-->
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr>
+ <td valign="bottom" width="67"> <img
+ src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0"
+ alt="Netscape logo"></td>
+ <td valign="middle"> <span class="product">Netscape
+Directory Server</span> <span class="booktitle">Console Help</span> </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <hr size="1" noshade="noshade"><span class="navigation"> <a
+ style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+ </a> </span>&nbsp;&nbsp;&nbsp;&nbsp; </td>
+ </tr>
+ </tbody>
+</table>
+<!--end navigationcontent-->
+<!--bookcontent defines the actual content of the file, sans headers and footers --><!--start bookcontent-->
+<blockquote><br>
+ <p class="h1"> <a name="28258"> </a><a name="Settings Tab"> </a>Attribute
+Encryption - Select
+Encryption Method Box<br>
+ </p>
+ <p class="text"><a name="25219"></a>After selecting an
+attribute to encrypt and clicking okay, the "Select Encryption Method"
+box comes up, with a list of encryption ciphers
+available for attribute encryption.<br>
+ </p>
+There are currently two supported ciphers:<br>
+ <ul>
+ <li>AES</li>
+ <li>3DES</li>
+ </ul>
+You may only select one. Click OK to add a cipher and complete the
+encrypted attribute or cancel to close out the selection.<br>
+</blockquote>
+<br>
+<br>
+<span class="navigation">
+<a style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+</a>
+</span>&nbsp;&nbsp;&nbsp;&nbsp;
+<hr noshade="noshade" size="1">
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright
+1999, 2002-2003 Netscape Communications Corporation. All rights
+reserved.</p>
+<br>
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+<!--end footercontent--><!--end maincontent-->
+</body>
+</html>
diff --git a/ldap/docs/dirhlp/help/configtab_db2.htm b/ldap/docs/dirhlp/help/configtab_db2.htm
new file mode 100644
index 00000000..3fbc1485
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db2.htm
@@ -0,0 +1,239 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="07/14/03 13:43:25" />
+<title>Netscape Directory Server Help: Passwords Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28623"> </a>
+<a name="Passwords Tab"> </a>
+Passwords Tab
+</p>
+
+<p class="text">
+<a name="28625"> </a>
+Use this tab to set up a password policy for the directory.
+</p>
+<p class="text">
+<a name="28930"> </a>
+<b>Enable fine-grained password policy. </b>When selected, enables the fine-grained (subtree and user level) password policy.
+</p>
+<p class="text">
+<a name="28626"> </a>
+<b>User must change password after reset. </b>When selected, users must change their passwords when they first log in or after the administrator resets the passwords.
+</p>
+<p class="text">
+<a name="28627"> </a>
+<b>User may change password.</b> When selected, allows users to change their own passwords.
+</p>
+<p class="text">
+<a name="28628"> </a>
+<b>Allow changes in X day(s). </b>Defines how often users can change their password. Use this value in conjunction with "Keep password history" to discourage users from recycling old passwords.
+</p>
+<p class="text">
+<a name="28629"> </a>
+<b>Keep password history.</b> Specifies that the server keep a list of user passwords. Use this in conjunction with "Allow changes in X day(s)" to discourage users from reusing old passwords. If you select this option, enter the number of passwords users must cycle through before they can reuse a password.
+</p>
+<p class="text">
+<a name="28630"> </a>
+<b>Remember X passwords. </b>If the server is keeping a password history, this option specifies how many old passwords the server should store in the history list. The valid value range is from 2 to 24. The default value is 6.
+</p>
+<p class="text">
+<a name="28631"> </a>
+<b>Password never expires.</b> Select this if you do not require users to change their passwords periodically.
+</p>
+<p class="text">
+<a name="28980"> </a>
+<b>Password expires after X days. </b>Select this if you want users to change their passwords periodically. If you select the option, in the text box, you must enter the number of days in which the password will expire.
+</p>
+<p class="text">
+<a name="28981"> </a>
+Note that the maximum value for the password age is derived by subtracting January 18, 2038 from today's date. The value you enter must not be set to the maximum value or too close to the maximum value. If you set the value to the maximum value, Directory Server may fail to start because the number of seconds will go past the epoch date. In such an event, the error log will indicate that the password maximum age is invalid. To resolve this problem, you must correct the <code>paswordMaxAge</code> attribute value in the <code>dse.ldif</code> file.
+</p>
+<p class="text">
+<a name="28985"> </a>
+A common policy is to have passwords expire every 30 to 90 days. By default, the password maximum age is set to 8640000 seconds (100 days).
+</p>
+<p class="text">
+<a name="28633"> </a>
+<b>Send warning X day(s) before password expires.</b> Indicates the number of days before a user's password is due to expire that the user will be sent a warning message. The valid value range is from 1 to 24,855 days. The default value is 1 day.
+</p>
+<p class="text">
+<a name="28998"> </a>
+<b>Allow up to X login attempt(s) after password expires.</b> Indicates the number of grace logins permitted after a user's password has expired. Grace logins are not permitted by default.
+</p>
+<p class="text">
+<a name="28634"> </a>
+<b>Check password syntax.</b> Select this checkbox to enforce password syntax checking. Syntax checking ensures that the password strings conform to the syntax guidelines, such as minimum password length.
+</p>
+<p class="text">
+<a name="28635"> </a>
+<b>Password minimum length. </b>If syntax checking is on, this option specifies the minimum number of characters that must be used in directory server passwords. The valid value range is from 2 to 512 characters. The default value is 6.
+</p>
+<p class="text">
+<a name="28636"> </a>
+<b>Password encryption. </b>Identifies how user passwords are stored in the directory. You can specify one of the following encryption formats:
+</p>
+<ul>
+
+<li>
+Salted Secure Hashing Algorithm (SSHA). This method is recommended as the most secure. SSHA is the default encryption method.
+<a name="28637"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+UNIX crypt algorithm (CRYPT). Provided for compatibility with UNIX passwords.
+<a name="28638"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Secure Hashing Algorithm (SHA). A one-way has algorithm that is the default encryption schema in Directory Server 4.x.
+<a name="28639"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+No encryption (CLEAR). This encryption type indicates that the password will appear in plain text.
+<a name="28640"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28641"> </a>
+Passwords stored using SSHA, CRYPT, or SHA formats cannot be used for secure login through SASL Digest MD5.
+</p>
+<p class="h2">
+<a name="28642"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28645"> </a>
+<a href="../en/slapd/ag/password.htm#1074672">Configuring the Password Policy</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>July 14, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db3.htm b/ldap/docs/dirhlp/help/configtab_db3.htm
new file mode 100644
index 00000000..24626e5a
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db3.htm
@@ -0,0 +1,169 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Account Lockout Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28646"> </a>
+<a name="Account Lockout Tab"> </a>
+Account Lockout Tab
+</p>
+
+<p class="text">
+<a name="28648"> </a>
+You can set up a account lockout policy for the directory using the Account Lockout tab.
+</p>
+<p class="text">
+<a name="28649"> </a>
+<b>Accounts may be locked out. </b>Select this option to enable account lockout because of repeated login failures. Clear this checkbox if you do not want users to be locked out of the directory after a series of failed bind attempts.
+</p>
+<p class="text">
+<a name="28650"> </a>
+<b>Lockout account after X login failures.</b> Specify the number of times a user can fail to bind before they are locked out of the directory. Valid values are 1 to 32,767 attempts. This option is available only if account lockout is enabled.
+</p>
+<p class="text">
+<a name="28651"> </a>
+<b>Reset failure count after X minutes. </b>Indicates the amount of time that must elapse before the failure counter is reset. This option is available only if account lockout is enabled. Valid values are 1 to 35,791,394 minutes.
+</p>
+<p class="text">
+<a name="28652"> </a>
+<b>Lockout forever.</b> Select this option to indicate that user accounts that have been locked must be reset by the administrator before users can access the directory. If you select this option, you cannot set a lockout duration.
+</p>
+<p class="text">
+<a name="28653"> </a>
+<b>Lockout duration X minutes. </b>Select this option to indicate the amount of time a user will be locked out of the directory after a series of failed bind attempts. If you select this option, you must enter a number of minutes in the text box. Valid values are 1 to 35,791,394 minutes. This option is available only if account lockout is enabled.
+</p>
+<p class="h2">
+<a name="28654"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28657"> </a>
+<a href="../en/slapd/ag/password.htm#1086557">Configuring the Account Lockout Policy<a href="">
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db4.htm b/ldap/docs/dirhlp/help/configtab_db4.htm
new file mode 100644
index 00000000..2da71fc1
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db4.htm
@@ -0,0 +1,142 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Select Attribute</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28686"> </a>
+<a name="Select Attribute"> </a>
+Select Attribute
+</p>
+
+<p class="text">
+<a name="28688"> </a>
+Use this dialog box to specify an attribute for which you want the server to maintain an index.
+</p>
+<p class="text">
+<a name="28689"> </a>
+<b>Attributes list.</b> This list contains all of the attributes currently in the directory schema. Select the attribute for which you want to maintain an index and click OK.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db5.htm b/ldap/docs/dirhlp/help/configtab_db5.htm
new file mode 100644
index 00000000..17cc6c07
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db5.htm
@@ -0,0 +1,158 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Database Settings</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28697"> </a>
+<a name="Database Settings"> </a>
+Database Settings
+</p>
+
+<p class="text">
+<a name="28699"> </a>
+Use this tab to configure the settings for a particular database instance. These settings take precedent over the default settings you have described for databases in general.
+</p>
+<p class="text">
+<a name="28700"> </a>
+<b>Suffix</b>. Suffix maintained by this database.
+</p>
+<p class="text">
+<a name="28701"> </a>
+<b>Database location. </b>Full path to the database location on the server.
+</p>
+<p class="text">
+<a name="28702"> </a>
+<b>Maximum entries in cache. </b>Maximum number of entries stored in the database cache for processing client search requests. A value of -1 indicates no limit. For performance tuning purposes.
+</p>
+<p class="text">
+<a name="28703"> </a>
+<b>Memory available for cache.</b> Maximum memory available to the database for storing cached entries, in bytes. For performance tuning purposes.
+</p>
+<p class="text">
+<a name="28704"> </a>
+<b>Database is read-only. </b>Select this checkbox to make the database read-only.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db6.htm b/ldap/docs/dirhlp/help/configtab_db6.htm
new file mode 100644
index 00000000..877ecc2b
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db6.htm
@@ -0,0 +1,168 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:02" />
+<title>Netscape Directory Server Help: Import Database</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28726"> </a>
+<a name="Import Database"> </a>
+Import Database
+</p>
+
+<p class="text">
+<a name="28728"> </a>
+Use this dialog box to append data to all of your databases using LDAP. You can also use this option to modify and delete entries.
+</p>
+<p class="text">
+<a name="28729"> </a>
+<b>LDIF file (on Console's machine). </b>Enter the full path to the LDIF file you want to import. Click Browse to select the file you want to import. By default, the console uses your current path.
+</p>
+
+<p class="text">
+<a name="28731"> </a>
+<b>Add only. </b>The LDIF file may contain modify and delete instructions in addition to the default add instructions. If you want the server to ignore operations other than add, select this checkbox.
+</p>
+
+<p class="text">
+<a name="28732"> </a>
+<b>Continue on error. </b>Select this checkbox if you want the server to continue with the import even if errors occur. For example, use this option if you are importing an LDIF file that contains some entries that already exist in the database in addition to new ones. The server notes existing entries in the rejects file while adding all new entries.
+</p>
+
+<p class="text">
+<a name="28733"> </a>
+<b>File for rejects. </b>Enter the full path to the file in which you want the server to record all entries it cannot import. For example, the server cannot import an entry that already exists in the database or an entry that has no parent object. By default, the server creates the rejects file in the current directory.
+</p>
+<p class="h2">
+<a name="28734"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28737"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1117312">Performing an Import</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db7.htm b/ldap/docs/dirhlp/help/configtab_db7.htm
new file mode 100644
index 00000000..efdfa764
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db7.htm
@@ -0,0 +1,165 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Import</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28745"> </a>
+<a name="Import"> </a>
+Import
+</p>
+
+<p class="text">
+<a name="28747"> </a>
+Use this dialog box to import data to one database or all of your databases. This method overwrites any data contained by the database.
+</p>
+<p class="text">
+<a name="28748"> </a>
+<b>LDIF file. </b>Enter the full path to the LDIF file you want to import. Click Browse to locate the file on your machine.
+</p>
+<p class="text">
+<a name="28749"> </a>
+The following two options apply only if you operate the console from a machine remote to the server containing the LDIF file.
+</p>
+<p class="text">
+<a name="28750"> </a>
+<b>From local machine. </b>Select this radio button to indicate that the LDIF file is located on the local server. By default, the console looks for a file stored in the current directory.
+</p>
+<p class="text">
+<a name="28751"> </a>
+<b>From server machine. </b>Select this radio button to indicate that the LDIF file is located on a remote server. By default, the console looks for the file in the following directory: <code>/usr/netscape/servers/slapd-</code><span class="variable">serverID</span><code>/ldif</code>.
+</p>
+<p class="h2">
+<a name="28755"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28758"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1117312">Performing an Import</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db8.htm b/ldap/docs/dirhlp/help/configtab_db8.htm
new file mode 100644
index 00000000..45c257f0
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db8.htm
@@ -0,0 +1,175 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Initialize Database</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28766"> </a>
+<a name="Initialize Database"> </a>
+Initialize Database
+</p>
+
+<p class="text">
+<a name="28768"> </a>
+Use this dialog box to overwrite any existing data in your database by importing a file from LDIF.
+</p>
+<p class="text">
+<a name="28769"> </a>
+<b>LDIF file. </b>Enter the full path to the LDIF file you want to import. Click Browse to locate it on your machine.
+</p>
+<p class="text">
+<a name="28770"> </a>
+If you are operating the console from a machine remote to the server containing the LDIF file, select one of the following options:
+</p>
+<ul>
+
+<li>
+<b>From local machine. </b>Indicates that the LDIF file is located on the local server. By default, the console looks in the current directory for the LDIF file.
+<a name="28771"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>From server machine. </b>Indicates that the LDIF file is located on a remote server.
+<a name="28772"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="h2">
+<a name="28773"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28776"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1117339">Initializing Database</a>
+</p>
+<p class="text">
+<a name="28779"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1117312">Performing an Import</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_db9.htm b/ldap/docs/dirhlp/help/configtab_db9.htm
new file mode 100644
index 00000000..92d981c5
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_db9.htm
@@ -0,0 +1,177 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Export Databases</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28801"> </a>
+<a name="Export Databases"> </a>
+Export Databases
+</p>
+
+<p class="text">
+<a name="28803"> </a>
+Use this dialog box to export your databases to LDIF.
+</p>
+<p class="text">
+<a name="28804"> </a>
+<b>LDIF File. </b>Enter the name you want the server to use for the LDIF file. If you are running Directory Server Console on the server's host machine, click Browse to select the file to which you want to export.
+</p>
+<p class="text">
+<a name="28808"> </a>
+<b>To Local Machine. </b>Choose this option to export the database to a local file. This option is not visible if you are running Directory Server Console on the directory's host.
+</p>
+<p class="text">
+<a name="28812"> </a>
+<b>To Server Machine. </b>Choose this option to export the database to a file on the server's host machine. If you choose this option, you cannot Browse to select a different file. This option is not visible if you are running Directory Server Console on the directory's host.
+</p>
+<p class="text">
+<a name="28816"> </a>
+<b>All Databases. </b>Select this option to export the all of your databases to LDIF.
+</p>
+<p class="text">
+<a name="28817"> </a>
+<b>Subtree. </b>Select this option if you want the server to export only a portion of the directory to LDIF. If you choose this option, you must also select the subtree you want the server to export.
+</p>
+<p class="text">
+<a name="28818"> </a>
+<b>Subtree text box. </b>If you selected the Subtree radio button, you can enter the subtree you want the server to export to LDIF in this text box. You can also click Browse to browse the directory and select a subtree.
+</p>
+<p class="h2">
+<a name="28819"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28822"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1111210">Exporting Directory Data to LDIF Using the Console</a>
+</p>
+<p class="text">
+<a name="28825"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1055442">Exporting a Single Database to LDIF Using the Console</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_ldbmdb.htm b/ldap/docs/dirhlp/help/configtab_ldbmdb.htm
new file mode 100644
index 00000000..4444682e
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_ldbmdb.htm
@@ -0,0 +1,154 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Create New Database</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28655"> </a>
+<a name="Create New Database"> </a>
+Create New Database
+</p>
+
+<p class="text">
+<a name="28657"> </a>
+Use this dialog box to create a new database.
+</p>
+<p class="text">
+<a name="28658"> </a>
+<b>Suffix Name.</b> This field appears only when you create a new database in an existing suffix. Gives the name of the suffix contained by the database.
+</p>
+<p class="text">
+<a name="28659"> </a>
+<b>Database information.</b> Use these options to specify the database name and location.
+</p>
+<p class="text">
+<a name="28660"> </a>
+<b>Database Name.</b> Enter a unique name for the database. This value cannot contain commas or equals signs (=).
+</p>
+<p class="text">
+<a name="28661"> </a>
+<b>Create database in. </b>Enter the full path to the location on your machine where you want the new database to reside. Click Browse to locate a directory.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_logs.htm b/ldap/docs/dirhlp/help/configtab_logs.htm
new file mode 100644
index 00000000..ead36551
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_logs.htm
@@ -0,0 +1,217 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="10/20/03 15:38:54" />
+<title>Netscape Directory Server Help: Access Log</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28733"> </a>
+<a name="Access Log"> </a>
+Access Log
+</p>
+
+<p class="text">
+<a name="28735"> </a>
+Use this tab to configure various settings for the directory's access log. The access log contains detailed information about client connections to the directory.
+</p>
+<p class="text">
+<a name="28736"> </a>
+<b>Enable logging.</b> Select this checkbox to configure the server to keep an access log; clear this checkbox to disable access logging.
+</p>
+<p class="text">
+<a name="28737"> </a>
+<b>View Log. </b>Click this button to view the access log for the directory.
+</p>
+<p class="text">
+<a name="28738"> </a>
+<b>Log File. </b>Contains the full path and name of the access log file. By default, the value is:
+</p>
+<p class="code">
+<a name="29212"></a>
+<code><span class="variable">serverRoot</span>/slapd-<span class="variable">serverID</span>/logs/access</code>
+</font>
+</p><p class="text">
+<a name="28739"> </a>
+<b>Creation Policy. </b>These options allow you to specify how often the server archives the current access log and starts a new log file.
+</p>
+<p class="text">
+<a name="29128"> </a>
+<b>Access mode. </b>Indicates the access mode or UNIX file permissions with which log files are to be created. The default value is 600.
+</p>
+<p class="text">
+<a name="29129"> </a>
+The valid values are any combination of 000 to 777, as they mirror <em>numbered</em> or <em>absolute</em> UNIX file permissions. That is, the value must be a combination of a 3-digit number, the digits varying from 0 through 7:
+</p>
+<p class="text">
+<a name="29130"> </a>
+0 - None<br />1 - Execute only<br />2 - Write only<br />3 - Write and execute<br />4 - Read only<br />5 - Read and execute<br />6 - Read and write<br />7 - Read, write, and execute
+</p>
+<p class="text">
+<a name="29131"> </a>
+In the 3-digit number, the first digit represents the owner's permissions, the second digit represents the group's permissions, and the third digit represents everyone's permissions. When changing the default value, keep in mind that 000 will not allow access to the logs and allowing <em>write</em> permissions to <em>everyone</em> can result in the logs being overwritten or deleted by anyone.
+</p>
+<p class="text">
+<a name="29182"> </a>
+Note that the newly configured access mode will only affect new logs that are created; the mode will be set when the log rotates to a new file.
+</p>
+<p class="text">
+<a name="28740"> </a>
+<b>Maximum number of logs. </b>The number of logs to archive per directory. When the server exceeds this amount, it deletes old archive logs. The default value is 10.
+</p>
+<p class="text">
+<a name="28741"> </a>
+<b>File size for each log. </b>The maximum file size (in MB) for active access log files. Once a file reaches the size you specify, the server archives the file and starts a new one. To specify no maximum, enter a value of -1.
+</p>
+<p class="text">
+<a name="28742"> </a>
+<b>Create a new log every. </b>How often you want the server to start a new access log. The server archives a log file if the size of the file reaches the maximum file size or the specified time limit has elapsed, whichever comes first.
+</p>
+<p class="text">
+<a name="28743"> </a>
+<b>Deletion Policy. </b>These options allow you to configure the server to delete unneeded archived access log files.
+</p>
+<p class="text">
+<a name="28744"> </a>
+<b>When total log exceeds. </b>The server will delete the oldest archived access log once the total of all the logs reaches this amount. The value is given in MB.
+</p>
+<p class="text">
+<a name="28745"> </a>
+<b>When free disk space is less than. </b>The server will delete the oldest archived access log if the available disk space is less than this amount. The value is given in MB.
+</p>
+<p class="text">
+<a name="28746"> </a>
+<b>When a file is older than. </b>The server will delete an archived access log when the file is older than the age you specify.
+</p>
+<p class="h2">
+<a name="28747"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28750"> </a>
+<a href="../en/slapd/ag/dsstats.htm#1057137">Viewing and Configuring Log Files</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>October 20, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_logs2.htm b/ldap/docs/dirhlp/help/configtab_logs2.htm
new file mode 100644
index 00000000..f8c1d24b
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_logs2.htm
@@ -0,0 +1,221 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="10/20/03 15:42:42" />
+<title>Netscape Directory Server Help: Error Log</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28758"> </a>
+<a name="Error Log"> </a>
+Error Log
+</p>
+
+<p class="text">
+<a name="28760"> </a>
+Use this tab to configure the directory's error log. The error log contains detailed messages about errors and events the server experiences during normal operations.
+</p>
+<p class="text">
+<a name="28761"> </a>
+<b>Enable logging. </b>Select this checkbox to configure the server to keep an error log; clear this checkbox to disable error logging.
+</p>
+<p class="text">
+<a name="28762"> </a>
+<b>View Log. </b>Click this button to view the error log for the directory.
+</p>
+<p class="text">
+<a name="28763"> </a>
+<b>Log File. </b>Contains the full path and filename of the error log. By default, the value is:
+</p>
+<p class="code">
+<a name="29220"></a>
+<span class="variable">serverRoot</span>/slapd-</font><span class="variable">serverID</span>/logs/errors
+</font>
+</p><p class="text">
+<a name="28767"> </a>
+<b>Creation Policy. </b>These options allow you to specify how often the server archives the current error log and starts a new log file.
+</p>
+<p class="text">
+<a name="29100"> </a>
+<b>Access mode. </b>Indicates the access mode or UNIX file permissions with which log files are to be created. The default value is 600.
+</p>
+<p class="text">
+<a name="29101"> </a>
+The valid values are any combination of 000 to 777, as they mirror <em>numbered</em> or <em>absolute</em> UNIX file permissions. That is, the value must be a combination of a 3-digit number, the digits varying from 0 through 7:
+</p>
+<p class="text">
+<a name="29102"> </a>
+0 - None<br />1 - Execute only<br />2 - Write only<br />3 - Write and execute<br />4 - Read only<br />5 - Read and execute<br />6 - Read and write<br />7 - Read, write, and execute
+</p>
+<p class="text">
+<a name="29103"> </a>
+In the 3-digit number, the first digit represents the owner's permissions, the second digit represents the group's permissions, and the third digit represents everyone's permissions. When changing the default value, keep in mind that 000 will not allow access to the logs and allowing <em>write</em> permissions to <em>everyone</em> can result in the logs being overwritten or deleted by anyone.
+</p>
+<p class="text">
+<a name="29194"> </a>
+Note that the newly configured access mode will only affect new logs that are created; the mode will be set when the log rotates to a new file.
+</p>
+<p class="text">
+<a name="28768"> </a>
+<b>Maximum number of logs. </b>The number of logs to archive per directory. The default value is 1 log, meaning that the server does not rotate the log and it grows indefinitely.
+</p>
+<p class="text">
+<a name="28769"> </a>
+<b>File size for each log. </b>The maximum file size (in MB) for active error log files. Once a file reaches the size you specify, the server archives the file and starts a new one.
+</p>
+<p class="text">
+<a name="28770"> </a>
+<b>Create a new log every. </b>How often you want the server to start a new error log. The server archives a log file if the size of the file reaches the maximum file size or the specified time limit has elapsed, whichever comes first.
+</p>
+<p class="text">
+<a name="28771"> </a>
+<b>Deletion Policy. </b>These options allow you to configure the server to delete unneeded archived error log files.
+</p>
+<p class="text">
+<a name="28772"> </a>
+<b>When total log exceeds. </b>The server will delete the oldest archived error log once the total of all the logs reaches this amount.
+</p>
+<p class="text">
+<a name="28773"> </a>
+<b>When free disk space is less than. </b>The server will delete the oldest archived error log if the available disk space is less than this amount.
+</p>
+<p class="text">
+<a name="28774"> </a>
+<b>When a file is older than. </b>The server will delete an archived error log when the file is older than the age you specify.
+</p>
+<p class="text">
+<a name="28775"> </a>
+<b>Log Level. </b>Specifies the kinds of error and event messages the server should store in the error log. By default, no options are selected. Selecting any option will cause the error log to grow very rapidly because additional information is written for every request the server receives. You should not change this option unless told to by <em>Netscape Technical Support</em>.
+</p>
+<p class="h2">
+<a name="28779"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28782"> </a>
+<a href="../en/slapd/ag/dsstats.htm#1057137">Viewing and Configuring Log Files</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>October 20, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_logs3.htm b/ldap/docs/dirhlp/help/configtab_logs3.htm
new file mode 100644
index 00000000..cf9cf20d
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_logs3.htm
@@ -0,0 +1,217 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="10/20/03 15:42:42" />
+<title>Netscape Directory Server Help: Audit Log</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28804"> </a>
+<a name="Audit Log"> </a>
+Audit Log
+</p>
+
+<p class="text">
+<a name="28806"> </a>
+Use this tab to configure the directory's audit log. The audit log contains detailed information about changes made to each database as well as to the overall server configuration.
+</p>
+<p class="text">
+<a name="28807"> </a>
+<b>Enable logging. </b>Select this checkbox to configure the server to keep an audit log; clear this checkbox to disable audit logging.
+</p>
+<p class="text">
+<a name="28808"> </a>
+<b>View Log. </b>Click this button to view the audit log for the directory.
+</p>
+<p class="text">
+<a name="28809"> </a>
+<b>Log File. </b>Contains the full path and name of the audit log. By default, the value is:
+</p>
+<p class="code">
+<a name="29225"></a>
+<span class="variable">serverRoot</span>/slapd-<span class="variable">serverID</span>/logs/audit
+
+</p><p class="text">
+<a name="28810"> </a>
+<b>Creation Policy. </b>These options allow you to specify how often the server archives the current audit log and starts a new log file.
+</p>
+<p class="text">
+<a name="28881"> </a>
+<b>Access mode. </b>Indicates the access mode or UNIX file permissions with which log files are to be created. The default value is 600.
+</p>
+<p class="text">
+<a name="29030"> </a>
+The valid values are any combination of 000 to 777, as they mirror <em>numbered</em> or <em>absolute</em> UNIX file permissions. That is, the value must be a combination of a 3-digit number, the digits varying from 0 through 7:
+</p>
+<p class="text">
+<a name="28958"> </a>
+0 - None<br />1 - Execute only<br />2 - Write only<br />3 - Write and execute<br />4 - Read only<br />5 - Read and execute<br />6 - Read and write<br />7 - Read, write, and execute
+</p>
+<p class="text">
+<a name="29032"> </a>
+In the 3-digit number, the first digit represents the owner's permissions, the second digit represents the group's permissions, and the third digit represents everyone's permissions. When changing the default value, keep in mind that 000 will not allow access to the logs and allowing <em>write</em> permissions to <em>everyone</em> can result in the logs being overwritten or deleted by anyone.
+</p>
+<p class="text">
+<a name="29203"> </a>
+Note that the newly configured access mode will only affect new logs that are created; the mode will be set when the log rotates to a new file.
+</p>
+<p class="text">
+<a name="28811"> </a>
+<b>Maximum number of logs. </b>The number of logs to archive per directory.
+</p>
+<p class="text">
+<a name="28812"> </a>
+<b>File size for each log. </b>The maximum file size (in MB) for active audit log files. Once a file reaches the size you specify, the server archives the file and starts a new one.
+</p>
+<p class="text">
+<a name="28813"> </a>
+<b>Create a new log every. </b>How often you want the server to start a new audit log. The server archives a log file if the size of the file reaches the maximum file size or the specified time limit has elapsed, whichever comes first.
+</p>
+<p class="text">
+<a name="28814"> </a>
+<b>Deletion Policy. </b>These options allow you to configure the server to delete unneeded archived audit log files.
+</p>
+<p class="text">
+<a name="28815"> </a>
+<b>When total log exceeds. </b>The server will delete the oldest archived audit log once the total of all the logs reaches this amount.
+</p>
+<p class="text">
+<a name="28816"> </a>
+<b>When free disk space is less than. </b>The server will delete the oldest archived audit log if the available disk space is less than this amount.
+</p>
+<p class="text">
+<a name="28817"> </a>
+<b>When a file is older than. </b>The server will delete an archived audit log when the file is older than the age you specify.
+</p>
+<p class="h2">
+<a name="28818"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28821"> </a>
+<a href="../en/slapd/ag/dsstats.htm#1057137">Viewing and Configuring Log Files</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>October 20, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_maptree.htm b/ldap/docs/dirhlp/help/configtab_maptree.htm
new file mode 100644
index 00000000..3c18dccf
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_maptree.htm
@@ -0,0 +1,177 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:03" />
+<title>Netscape Directory Server Help: Suffix Settings</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28692"> </a>
+<a name="Suffix Settings"> </a>
+Suffix Settings
+</p>
+
+<p class="text">
+<a name="28694"> </a>
+Use this tab to specify settings for a particular root or sub suffix.
+</p>
+<p class="text">
+<a name="28695"> </a>
+<b>Suffix name. </b>This field gives the name of the suffix. If the suffix is a root suffix, the console states "This is a root suffix." If the suffix is a sub suffix, the root suffix to which it belongs is named in the "Suffix belongs to" field.
+</p>
+<p class="text">
+<a name="28696"> </a>
+<b>Enable this suffix. </b>By default, this checkbox is selected. To disable the suffix (for example, when you take a database down for maintenance), deselect this checkbox.
+</p>
+<p class="text">
+<a name="28697"> </a>
+<b>Suffix request processing. </b>These options help you configure how requests from client applications are managed by this suffix.
+</p>
+<p class="text">
+<a name="28698"> </a>
+<b>Use the Databases. </b>Select this option if you want the databases and database links to be used for processing all requests made by client applications.
+</p>
+<p class="text">
+<a name="28699"> </a>
+<b>Return Referrals for all Operations. </b>Select this option to return a referral in response to all client application requests. For example, you might when a database is taken off line.
+</p>
+<p class="text">
+<a name="28700"> </a>
+<b>Return Referrals for Update Operations. </b>Select this option to return a referral only during update requests. This is useful for redirecting client requests made to read-only databases.
+</p>
+<p class="h2">
+<a name="28701"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28704"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17930">Creating and Maintaining Suffixes</a>
+</p>
+<p class="text">
+<a name="28912"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17763">Using Referrals</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_maptree2.htm b/ldap/docs/dirhlp/help/configtab_maptree2.htm
new file mode 100644
index 00000000..03169594
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_maptree2.htm
@@ -0,0 +1,138 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Database List</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28712"> </a>
+<a name="Database List"> </a>
+Database List
+</p>
+
+<p class="text">
+<a name="28714"> </a>
+This dialog box lists all of the databases in your directory. Select one from the list and click OK. You can highlight multiple databases by holding down the Shift key while you select databases with your mouse.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_maptree3.htm b/ldap/docs/dirhlp/help/configtab_maptree3.htm
new file mode 100644
index 00000000..f84e4e86
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_maptree3.htm
@@ -0,0 +1,175 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Databases</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28722"> </a>
+<a name="Databases"> </a>
+Databases
+</p>
+
+<p class="text">
+<a name="28724"> </a>
+Use this tab to specify the databases for the suffix.
+</p>
+<p class="text">
+<a name="28725"> </a>
+<b>Database information. </b>Enter the database or databases that contain entries for this suffix in this box. Click Add to browse a list of available databases. Click Delete to remove a database from the list.
+</p>
+<p class="text">
+<a name="28726"> </a>
+<b>Distribution Logic for Multiple Databases. </b>Use the options in this section to specify custom distribution logic for your directory. You use distribution logic when you distribute a single suffix across multiple databases. You need to specify the following:
+</p>
+<ul>
+
+<li>
+<b>Distribution library. </b>Enter the name of your distribution library. Click Browse to locate a library in a different directory.
+<a name="28727"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Function name. </b>Enter the name of your distribution function.
+<a name="28728"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28729"> </a>
+For more information about creating customized distribution logic, contact <em>Netscape Professional Services</em>.
+</p>
+<p class="h2">
+<a name="28733"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28736"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17930">Creating and Maintaining Suffixes</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_maptree4.htm b/ldap/docs/dirhlp/help/configtab_maptree4.htm
new file mode 100644
index 00000000..2b1d886d
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_maptree4.htm
@@ -0,0 +1,161 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Referrals</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28744"> </a>
+<a name="Referrals"> </a>
+Referrals
+</p>
+
+<p class="text">
+<a name="28746"> </a>
+Use this tab to configure the referrals returned by the suffix.
+</p>
+<p class="text">
+<a name="28747"> </a>
+<b>Enter a new referral. </b>Enter a referral in LDAP URL format, or click Construct to be guided through the process. Click Add to add the referral to the list.
+</p>
+<p class="text">
+<a name="28748"> </a>
+<b>Current referrals for this suffix. </b>Lists the referrals currently in place for this suffix. The entire list of referrals is returned to client applications in response to a request, when you select Referral or Referral on Update in the Suffix Settings tab. Click Delete to remove a referral from the list.
+</p>
+<p class="h2">
+<a name="28749"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28752"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17921">Creating Suffix Referrals</a>
+</p>
+<p class="text">
+<a name="28755"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17930">Creating and Maintaining Suffixes</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_maptree5.htm b/ldap/docs/dirhlp/help/configtab_maptree5.htm
new file mode 100644
index 00000000..d27e521e
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_maptree5.htm
@@ -0,0 +1,161 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Creating a New Root Suffix</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28777"> </a>
+<a name="Creating a New Root Suffix"> </a>
+Creating a New Root Suffix
+</p>
+
+<p class="text">
+<a name="28779"> </a>
+Use this dialog box to create a new root suffix.
+</p>
+<p class="text">
+<a name="28780"> </a>
+<b>New suffix. </b>Enter a unique name for the new root suffix. The suffix must be named according to dc naming conventions. For example, <code>dc=example,dc=com</code> could be the name of a new root suffix.
+</p>
+<p class="text">
+<a name="28784"> </a>
+<b>Create associated database automatically.</b> Select this checkbox to automatically create a database for the new root suffix.
+</p>
+<p class="text">
+<a name="28785"> </a>
+<b>Database name. </b>If you select the "Create associated database automatically" checkbox, enter the name of the new database in this field.
+</p>
+<p class="h2">
+<a name="28786"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28789"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17930">Creating and Maintaining Suffixes</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_maptree6.htm b/ldap/docs/dirhlp/help/configtab_maptree6.htm
new file mode 100644
index 00000000..fcaf3381
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_maptree6.htm
@@ -0,0 +1,169 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Creating a New Sub Suffix</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28797"> </a>
+<a name="Creating a New Sub Suffix"> </a>
+Creating a New Sub Suffix
+</p>
+
+<p class="text">
+<a name="28799"> </a>
+Use this dialog box to create a new sub suffix under an already existing root suffix.
+</p>
+<p class="text">
+<a name="28800"> </a>
+<b>New suffix. </b>Enter the new sub suffix name in this field. The suffix must be named according to dc naming conventions. For example, <code>o=people</code> could be the name of a new sub suffix.
+</p>
+<p class="text">
+<a name="28801"> </a>
+<b>Suffix belongs to. </b>Indicates the root suffix this sub suffix is beneath.
+</p>
+<p class="text">
+<a name="28802"> </a>
+<b>Complete suffix name. </b>Combines the new suffix name with the root suffix name.
+</p>
+<p class="text">
+<a name="28803"> </a>
+<b>Create associated database automatically.</b> Select this checkbox to automatically create a database for the new sub suffix.
+</p>
+<p class="text">
+<a name="28804"> </a>
+<b>Database name. </b>If you select the "Create associated database automatically" checkbox, enter the name of the new database in this field.
+</p>
+<p class="h2">
+<a name="28805"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28808"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17930">Creating and Maintaining Suffixes</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_maptree7.htm b/ldap/docs/dirhlp/help/configtab_maptree7.htm
new file mode 100644
index 00000000..d50d8c06
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_maptree7.htm
@@ -0,0 +1,157 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Remove Suffix</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28816"> </a>
+<a name="Remove Suffix"> </a>
+Remove Suffix
+</p>
+
+<p class="text">
+<a name="28818"> </a>
+Use this dialog box to delete a suffix and its sub suffixes. Deleting a suffix also deletes the databases and replication agreements of the suffix.
+</p>
+<p class="text">
+<a name="28819"> </a>
+<b>Delete this suffix and all of its sub suffixes. </b>Select this option to delete this suffix and all sub suffixes beneath it. Selecting this option also deletes all databases and replication agreements of this suffix.
+</p>
+<p class="text">
+<a name="28820"> </a>
+<b>Delete this suffix only. </b>Select this option to delete only this suffix, its associated database and replication agreements. Any sub suffixes beneath this suffix will move up a level after the deletion. For example, if you delete a root suffix only, the sub suffix directly beneath becomes a root suffix after the deletion.
+</p>
+<p class="h2">
+<a name="28821"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28824"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17930">Creating and Maintaining Suffixes</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_plugins.htm b/ldap/docs/dirhlp/help/configtab_plugins.htm
new file mode 100644
index 00000000..43549e95
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_plugins.htm
@@ -0,0 +1,174 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Plug-ins</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28742"> </a>
+<a name="Plug-ins"> </a>
+Plug-ins
+</p>
+
+<p class="text">
+<a name="28744"> </a>
+When you select a plug-in, the right pane displays basic information about the plug-in. You cannot modify plug-ins from the Directory Server Console.
+</p>
+<p class="text">
+<a name="28748"> </a>
+<b>Enable plug-in. </b>Select this checkbox to enable the plug-in; clear the checkbox to disable the plug-in. After enabling or disabling a plug-in, you must restart the directory.
+</p>
+<p class="text">
+<a name="28749"> </a>
+<b>Plug-in ID. </b>Gives the name of the plug-in.
+</p>
+<p class="text">
+<a name="28750"> </a>
+<b>Description. </b>Contains descriptive text about the plug-in.
+</p>
+<p class="text">
+<a name="28751"> </a>
+<b>Version. </b>Gives the version number of the plug-in.
+</p>
+<p class="text">
+<a name="28752"> </a>
+<b>Vendor. </b>Identifies the manufacturer of the plug-in.
+</p>
+<p class="text">
+<a name="28753"> </a>
+<b>Plug-in type. </b>Defines the type of plug-in, such as preoperational or postoperational.
+</p>
+<p class="text">
+<a name="28754"> </a>
+<b>Initialization function. </b>Identifies the function that the server calls to initialize the plug-in.
+</p>
+<p class="text">
+<a name="28755"> </a>
+<b>Plug-in module path. </b>Gives the name and path of the shared object or dynamic link library that contains the plug-in.
+</p>
+<p class="text">
+<a name="28756"> </a>
+<b>Arguments. </b>Specifies any additional arguments that are passed to the initialization function.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_replication.htm b/ldap/docs/dirhlp/help/configtab_replication.htm
new file mode 100644
index 00000000..bda4a158
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_replication.htm
@@ -0,0 +1,165 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:04" />
+<title>Netscape Directory Server Help: Legacy Consumer Settings</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28709"> </a>
+<a name="Legacy Consumer Settings"> </a>
+Legacy Consumer Settings
+</p>
+
+<p class="text">
+<a name="28711"> </a>
+Use this tab only when you are using replication agreements established on a 4.0, 4.1, or 4.1x version of Directory Server.
+</p>
+<p class="text">
+<a name="28720"> </a>
+<b>Enable Legacy Consumer. </b>Select this checkbox if you want this (6.2) Directory Server to act as a legacy consumer. This means that this server can accept updates from a 4.0, 4.1, or 4.1x supplier server. You must check this checkbox to activate the other fields in this window.
+</p>
+<p class="text">
+<a name="28722"> </a>
+<b>Supplier DN.</b> Use this field to specify the distinguished name that any supplier server must use to bind to this consumer server to send replication updates. The supplier DN must correspond to an entry that is stored on the consumer server. This entry must not be part of the replicated database.
+</p>
+<p class="text">
+<a name="28723"> </a>
+<b>New supplier password. </b>If a password is specified, the supplier server uses this password to bind to the consumer server.
+</p>
+<p class="text">
+<a name="28724"> </a>
+<b>Confirm new supplier password. </b>Confirms that the password entered in the "New supplier password" field is correct.
+</p>
+<p class="h2">
+<a name="28725"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28728"> </a>
+<a href="../en/slapd/ag/replicat.htm">Managing Replication</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_replication2.htm b/ldap/docs/dirhlp/help/configtab_replication2.htm
new file mode 100644
index 00000000..ff8fa7d5
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_replication2.htm
@@ -0,0 +1,177 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Supplier Settings</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28736"> </a>
+<a name="Supplier Settings"> </a>
+Supplier Settings
+</p>
+
+<p class="text">
+<a name="28738"> </a>
+Use this tab to configure a server as a supplier server. You must specify supplier attributes on any server that holds the master copy of a directory database.
+</p>
+<p class="text">
+<a name="28739"> </a>
+<b>Enable Changelog. </b>Check this box if you want this server to record all update operations in a change log so that these changes can be replayed on a consumer server.
+</p>
+<p class="text">
+<a name="28740"> </a>
+<b>Changelog database directory. </b>The directory in which the supplier server stores the change log.
+</p>
+<p class="text">
+<a name="28741"> </a>
+<b>Browse. </b>If you want the server to display a file selector so that you can select a directory for storing the change log database, click this button.
+</p>
+<p class="text">
+<a name="28742"> </a>
+<b>Use default. </b>If you want the server to suggest a default path name for the change log database, click this button.
+</p>
+<p class="text">
+<a name="28743"> </a>
+<b>Max changelog records.</b> The maximum number of entries recorded in the change log. If you select the Unlimited checkbox, no maximum size is set for the change log.
+</p>
+<p class="text">
+<a name="28744"> </a>
+<b>Max changelog age. </b>When an entry in the change log reaches the age specified here, the server removes the entry from the change log. If you select the Unlimited checkbox, the server does not remove entries from the change log based on age.
+</p>
+<p class="text">
+<a name="28745"> </a>
+To remove a change log database that has grown too big, you must manually delete it.
+</p>
+<p class="h2">
+<a name="28746"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28749"> </a>
+<a href="../en/slapd/ag/replicat.htm">Managing Replication</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_replication3.htm b/ldap/docs/dirhlp/help/configtab_replication3.htm
new file mode 100644
index 00000000..8d034e69
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_replication3.htm
@@ -0,0 +1,193 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:04" />
+<title>Netscape Directory Server Help: Replica Settings</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28757"> </a>
+<a name="Replica Settings"> </a>
+Replica Settings
+</p>
+
+<p class="text">
+<a name="28759"> </a>
+Use this tab to configure replication settings for the database selected in the left navigation tree.
+</p>
+<p class="text">
+<a name="28760"> </a>
+<b>Enable Replica. </b>Select this checkbox to enable replication. You must select this checkbox to activate all other fields in the window.
+</p>
+<p class="text">
+<a name="28764"> </a>
+<b>Single Master. </b>Select this radio button if you want this Directory Server to act as the single supplier server for this database.
+</p>
+<p class="text">
+<a name="28768"> </a>
+<b>Multiple Master. </b>Select this radio button if you want this Directory Server to act as one of the supplier servers that can replicate this database to consumers.
+</p>
+<p class="text">
+<a name="28772"> </a>
+<b>Hub. </b>Select this radio button if you want this Directory Server to accept updates from a supplier server, and replicate changes to consumer servers.
+</p>
+<p class="text">
+<a name="28776"> </a>
+<b>Dedicated Consumer. </b>Select this radio button if you want this Directory Server to accept updates from a supplier server. A dedicated consumer can service search operations but not update operations. Update operations will be referred to a supplier server.
+</p>
+<p class="text">
+<a name="28777"> </a>
+<b>Replica ID. </b>An integer between 1 and 255 that identifies the replica. The replica IDs of the master replicas must be unique. In other words, master replicas involved in the same multi-master configuration must have different replica IDs. However, two master replicas (corresponding to different suffixes) on the same server can have the same replica ID.
+</p>
+<p class="text">
+<a name="28778"> </a>
+If the ID is incorrect, the field labels turn red and the Save button is disabled.
+</p>
+<p class="text">
+<a name="28779"> </a>
+<b>Purge delay.</b> The delay you specify in these fields determines how often the state information stored in the replicated entries is purged. Check the Never checkbox if you want to save this information indefinitely.
+</p>
+<p class="text">
+<a name="28783"> </a>
+<b>Updatable by a 4.x Replica.</b> Check this checkbox if you want this Directory Server to act as a legacy consumer of a 4.0, 4.1, or 4.1x supplier server.
+</p>
+<p class="text">
+<a name="28784"> </a>
+<b>Current Supplier DNs.</b> This field lists the supplier bind DNs that supplier servers must use to update this replica. You can now specify multiple supplier bind DNs per replica, but only one supplier DN per replication agreement. Use the "Enter a new Supplier DN" field to specify a new supplier DN and click Add to add it to this list. If you have configured replication over SSL, specify the DN of the entry that contains the supplier's certificate in the "Enter a new Supplier DN" field and click Add to add it to this list.
+</p>
+<p class="text">
+<a name="28785"> </a>
+<b>Current URLs for referrals (Optional).</b> Directory Server uses the information contained in the replication agreement to create referrals from the consumer server to the appropriate supplier servers. This field lists the URLs you specify in addition to the automatic URLs which will be set up automatically. If you want the consumer to return an <code>ldaps://</code> URL, so that clients will bind to the supplier servers using SSL, enter the URL in the "Enter a new URL" field and click Add to add it to this list of current URLs. In the same way, if you have a cascading replication scenario and you want the referral returned to clients to point to the original supplier instead of the hub supplier, enter the corresponding URL in the "Enter a new URL" field and click Add to add it to this list of current URLs.
+</p>
+<p class="h2">
+<a name="28789"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28792"> </a>
+<a href="../en/slapd/ag/replicat.htm">Managing Replication</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_replication4.htm b/ldap/docs/dirhlp/help/configtab_replication4.htm
new file mode 100644
index 00000000..4d3e08b6
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_replication4.htm
@@ -0,0 +1,170 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Replication Summary</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28816"> </a>
+<a name="Replication Summary"> </a>
+Replication Summary
+</p>
+
+<p class="text">
+<a name="28818"> </a>
+You use the replication agreement Summary tab to view status or change the name of the replication agreement.
+</p>
+<p class="text">
+<a name="28819"> </a>
+<b>Description. </b>Contains the description of the replication agreement.
+</p>
+<p class="text">
+<a name="28820"> </a>
+<b>General. </b>Displays information about:
+</p>
+<ul>
+
+<li>
+Supplier&#151;The name of the supplier server in the agreement.
+<a name="28821"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Consumer&#151;The name of the consumer server in the agreement.
+<a name="28822"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Replicated subtree&#151;The subtree replicated in the agreement.
+<a name="28823"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28824"> </a>
+<b>Status. </b>This area displays information about the replication agreement, including the number of the last change sent to the consumer server, current status of the replication agreement, and the replication history.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_replication5.htm b/ldap/docs/dirhlp/help/configtab_replication5.htm
new file mode 100644
index 00000000..b5d0fef1
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_replication5.htm
@@ -0,0 +1,150 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Replication Schedule</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28832"> </a>
+<a name="Replication Schedule"> </a>
+Replication Schedule
+</p>
+
+<p class="text">
+<a name="28834"> </a>
+Use this tab when you modify a replication agreement to identify the time of day and day of week replication occurs. No new replication processes will be started outside the specified replication interval.
+</p>
+<p class="text">
+<a name="28835"> </a>
+<b>Always Keep Directories in Sync. </b>Select this option if you do not want to set time restrictions on the replication agreement.
+</p>
+<p class="text">
+<a name="28836"> </a>
+<b>Sync on the following days. </b>When selected, you can select the checkbox(es) next to the day(s) of the week when replication can occur. Click All to select every day of the week.
+</p>
+<p class="text">
+<a name="28837"> </a>
+<b>Replication will take place between.</b> Enter the hours during which replication takes place in the boxes provided.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_replication6.htm b/ldap/docs/dirhlp/help/configtab_replication6.htm
new file mode 100644
index 00000000..92b0b62c
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_replication6.htm
@@ -0,0 +1,176 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="07/10/03 13:41:23" />
+<title>Netscape Directory Server Help: Replication Connection</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28845"> </a>
+<a name="Replication Connection"> </a>
+Replication Connection
+</p>
+
+<p class="text">
+<a name="28939"> </a>
+Use the Connection tab to display the type of connection used by your replica during replication. You can use this tab to modify the user bind name and password. You cannot change the connection type. To change the connection type, re-create the replication agreement.
+</p>
+<p class="text">
+<a name="28848"> </a>
+<b>Using Encrypted SSL Connection. </b>When selected, specifies that the supplier and consumer servers use SSL for secure communication.
+</p>
+<p class="text">
+<a name="28849"> </a>
+<b>SSL Client Authentication. </b>When selected, this option specifies that the supplier and consumer servers use certificates for secure communication. SSL client authentication is not used unless the "Using Encrypted SSL Connection" checkbox is selected. The Bind As and Password fields are unavailable with this option because the server will use its security certificate to authenticate to the consumer server.
+</p>
+<p class="text">
+<a name="28850"> </a>
+To select this option, you must first do the following:
+</p>
+<ul>
+
+<li>
+Configure SSL for both your supplier and consumer server.
+<a name="28851"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Configure your consumer server to recognize your supplier server's certificate as the supplier DN.
+<a name="28852"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28853"> </a>
+<b>Simple Authentication. </b>When selected, this option specifies that the supplier and consumer servers use simple authentication during communication.
+</p>
+<p class="text">
+<a name="28854"> </a>
+<b>Bind As. </b>You can update the supplier bind DN in the Bind As text box.
+</p>
+<p class="text">
+<a name="28855"> </a>
+<b>Password. </b>You can update the password corresponding to the supplier bind DN in the Password field.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>July 10, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_replication7.htm b/ldap/docs/dirhlp/help/configtab_replication7.htm
new file mode 100644
index 00000000..c0aacd3e
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_replication7.htm
@@ -0,0 +1,146 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Consumer Server Information</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28877"> </a>
+<a name="Consumer Server Information"> </a>
+Consumer Server Information
+</p>
+
+<p class="text">
+<a name="28879"> </a>
+Use this dialog box to manually enter the host and port number of the consumer server.
+</p>
+<p class="text">
+<a name="28880"> </a>
+<b>Host Name. </b>Enter the host name of the supplier or consumer server as appropriate.
+</p>
+<p class="text">
+<a name="28881"> </a>
+<b>Port Number. </b>Enter the port number of the supplier or consumer server as appropriate.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_replication8.htm b/ldap/docs/dirhlp/help/configtab_replication8.htm
new file mode 100644
index 00000000..537d8033
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_replication8.htm
@@ -0,0 +1,146 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:04" />
+<title>Netscape Directory Server Help: Export Replica</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28889"> </a>
+<a name="Export Replica"> </a>
+Export Replica
+</p>
+
+<p class="text">
+<a name="28891"> </a>
+Use this dialog box to export a replica to LDIF.
+</p>
+<p class="text">
+<a name="28892"> </a>
+<b>LDIF file (on remote machine). </b>Enter the full path to the LDIF file. Click Browse to locate it on your machine. By default, if you are running the console locally, the file is stored in the current directory.
+</p>
+<p class="text">
+<a name="28893"> </a>
+When the Browse button is not enabled, by default the file is stored in the <span class="variable">serverRoot<code>/slapd-</code><span class="variable">serverID</span><code>/ldif</code>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_rootnode.htm b/ldap/docs/dirhlp/help/configtab_rootnode.htm
new file mode 100644
index 00000000..934a87f1
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_rootnode.htm
@@ -0,0 +1,162 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Settings Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28258"> </a>
+<a name="Settings Tab"> </a>
+Settings Tab
+</p>
+
+<p class="text">
+<a name="25219"> </a>
+Use this tab to configure the basic LDAP and network settings for your directory.
+</p>
+<p class="text">
+<a name="25220"> </a>
+<b>Port.</b> Port number used for non-SSL communications. By default, the port number is 389.
+</p>
+<p class="text">
+<a name="25221"> </a>
+<b>Encrypted Port.</b> Port number used for SSL communications. This port number must be different from the port used for non-SSL communications. The default encrypted port number is 636.
+</p>
+<p class="text">
+<a name="25222"> </a>
+<b>Referrals to.</b> LDAP URL of the default referral returned to client applications who submit requests based at a DN not maintained by your directory.
+</p>
+<p class="text">
+<a name="25223"> </a>
+<b>Make entire server read-only.</b> Causes the server to be placed in read-only mode. Selecting this option also places all databases managed by the server into read-only mode, meaning you cannot create, modify, or delete any entries.
+</p>
+<p class="text">
+<a name="25224"> </a>
+<b>Track entry modification times.</b> Specifies whether the directory maintains modification attributes for directory entries. Choosing to track modification times means that new or modified entries will contain the following attributes: <code>modifiersNames</code>, <code>modifyTimestamp</code>, <code>creatorsName</code>, and <code>createTimestamp</code>.
+</p>
+<p class="text">
+<a name="25225"> </a>
+<b>Enable schema checking.</b> Specifies that schema checking is performed when directory entries are created or modified.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_rootnode2.htm b/ldap/docs/dirhlp/help/configtab_rootnode2.htm
new file mode 100644
index 00000000..89a86f5b
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_rootnode2.htm
@@ -0,0 +1,154 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:02" />
+<title>Netscape Directory Server Help: Performance Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="25226"> </a>
+<a name="Performance Tab"> </a>
+Performance Tab
+</p>
+
+<p class="text">
+<a name="25227"> </a>
+Use this tab to tune the performance of your directory.
+</p>
+<p class="text">
+<a name="25228"> </a>
+<b>Size limit. </b>The maximum number of entries the directory returns to a client application in response to a search operation. To set no limit, enter<code> -1</code> in the text box.
+</p>
+<p class="text">
+<a name="25229"> </a>
+<b>Time limit.</b> The maximum amount of time (in seconds) the server spends performing a search request. To set no limit, enter <code>-1 </code>in the text box.
+</p>
+<p class="text">
+<a name="25230"> </a>
+<b>Idle timeout.</b> The time (in seconds) the server maintains an idle connection before terminating the connection. A value of <code>0</code> indicates no limit.
+</p>
+<p class="text">
+<a name="25231"> </a>
+<b>Max number of file descriptors.</b> The maximum number of file descriptors available to the directory. This option is not available for Directory Servers running on Windows.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_rootnode3.htm b/ldap/docs/dirhlp/help/configtab_rootnode3.htm
new file mode 100644
index 00000000..ef6de341
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_rootnode3.htm
@@ -0,0 +1,341 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Encryption Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="25232"> </a>
+<a name="Encryption Tab"> </a>
+Encryption Tab
+</p>
+
+<p class="text">
+<a name="25233"> </a>
+Use this tab to configure SSL for your directory.
+</p>
+<p class="text">
+<a name="25234"> </a>
+<b>Enable SSL for this server.</b> Select this checkbox to enable SSL communications for the directory. Clear the checkbox to disable SSL.
+</p>
+<p class="text">
+<a name="25235"> </a>
+<b>Use this cipher family. </b>Select the checkbox next to the cipher family or families you want the server to use for SSL communications.
+</p>
+<p class="text">
+<a name="25236"> </a>
+<b>Security Device.</b> Select the device you want the server to use.
+</p>
+<p class="text">
+<a name="25237"> </a>
+<b>Certificate.</b> Select the certificate you want the server to use. You must have a certificate set up on your system to use SSL.
+</p>
+<p class="text">
+<a name="25238"> </a>
+<b>Cipher settings. </b>Opens the Encryption Preferences dialog box, where you can select which ciphers you want the server to use from the cipher families you have already selected. By default, Directory Server comes with the following SSL ciphers:
+</p>
+<br />
+
+<br/>
+<table width="90%" border="1" cellspacing="0" cellpadding="4">
+<tr>
+<td valign="top">
+<p class="tablehead">
+<a name="28449"> </a>
+SSL Cipher
+</p></td>
+<td valign="top">
+<p class="tablehead">
+<a name="28451"> </a>
+Description
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="27774"> </a>
+None
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="27776"> </a>
+No encryption, only MD5 message authentication (rsa_null_md5).
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="27778"> </a>
+RC4
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="27780"> </a>
+RC4 cipher with 128-bit encryption and MD5 message authentication (rsa_rc4_128_md5).
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="27782"> </a>
+RC4 (Export)
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="27784"> </a>
+RC4 cipher with 40-bit encryption and MD5 message authentication (rsa_rc4_40_md5).
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="27786"> </a>
+RC2 (Export)
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="27788"> </a>
+RC2 cipher with 40-bit encryption and MD5 message authentication (rsa_rc2_40_md5).
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="27790"> </a>
+DES
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="27792"> </a>
+DES with 56-bit encryption and SHA message authentication (rsa_des_sha).
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="27794"> </a>
+DES (FIPS)
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="27796"> </a>
+FIPS DES with 56-bit encryption and SHA message authentication. This cipher meets the FIPS 140-1 U.S. government standard for implementations of cryptographic modules (rsa_fips_des_sha).
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="27798"> </a>
+Triple-DES
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="27800"> </a>
+Triple DES with 168-bit encryption and SHA message authentication (rsa_3des_sha).
+</p></td>
+
+</tr>
+<tr>
+<td valign="top">
+<p class="tabletext">
+<a name="27802"> </a>
+Triple-DES (FIPS)
+</p></td>
+<td valign="top">
+<p class="tabletext">
+<a name="27804"> </a>
+FIPS Triple DES with 168-bit encryption and SHA message authentication. This cipher meets the FIPS 140-1 U.S. government standard for implementations of cryptographic modules. (rsa_fips_3des_sha)
+</p></td>
+
+</tr>
+
+</table>
+
+
+<br />
+<br />
+
+<p class="text">
+<a name="25239"> </a>
+<b>Do not allow client authentication.</b> Select this option if you want client applications to connect to the server using only simple authentication.
+</p>
+<p class="text">
+<a name="25240"> </a>
+<b>Allow client authentication.</b> Select this option if you want client applications to be able to connect to the server using either simple authentication or client authentication.
+</p>
+<p class="text">
+<a name="25241"> </a>
+If you are using certificate-based authentication with replication, then you must select either "Allow client authentication" or "Require client authentication" on the consumer server.
+</p>
+<p class="text">
+<a name="25242"> </a>
+<b>Require client authentication. </b>Select this option if you want client applications to connect to the server using client authentication only. If you select this option, simple authentication is not allowed.
+</p>
+<p class="text">
+<a name="14859"> </a>
+<b>Use SSL in Netscape Console.</b> Select this checkbox if you want the communication between the Netscape Console and the directory to be secured using SSL.
+</p>
+<p class="text">
+<a name="14866"> </a>
+If you use this option with client authentication, communication between the Netscape Console and the server will take place over a secure channel, but without client authentication.
+</p>
+<p class="text">
+<a name="28333"> </a>
+<b>Check hostname against name in certificate for outbound SSL connections. </b>Select this check box if you want an SSL-enabled Directory Server (with certificate based client authentication turned on) to verify authenticity of a request by matching the hostname against the value assigned to the Common Name (CN) attribute of the subject name in the certificate being presented.
+</p>
+<p class="text">
+<a name="28412"> </a>
+By default, this feature is disabled. If you enable it and if the hostname does not match the CN attribute of the certificate, appropriate error and audit messages are logged. For example, in a replicated environment, messages similar to these are logged in the supplier server's log files if it finds that the peer server's hostname doesn't match the name specified in its certificate:
+</p>
+<p class="text">
+<a name="28356"> </a>
+<code>[DATE] - SSL alert: ldap_sasl_bind("",LDAP_SASL_EXTERNAL) 81 (Netscape runtime error -12276 - Unable to communicate securely with peer: requested domain name does not match the server's certificate.)</code>
+</p>
+<p class="text">
+<a name="28357"> </a>
+<code>[DATE] NSMMReplicationPlugin - agmt="cn=to ultra60 client auth" (ultra60:1924): Replication bind with SSL client authentication failed: LDAP error 81 (Can't contact LDAP server)</code>
+</p>
+<p class="text">
+<a name="28361"> </a>
+It is recommended that you turn this attribute on to protect Directory Server's outbound SSL connections against a Man In The Middle (MITN) attack.
+</p>
+<p class="h2">
+<a name="20476"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="20477"> </a>
+<a href="../en/slapd/ag/ssl.htm">Managing SSL</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_rootnode4.htm b/ldap/docs/dirhlp/help/configtab_rootnode4.htm
new file mode 100644
index 00000000..b2c056d2
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_rootnode4.htm
@@ -0,0 +1,153 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Cipher Settings</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="13688"> </a>
+<a name="Cipher Settings"> </a>
+Cipher Settings
+</p>
+
+<p class="text">
+<a name="14890"> </a>
+Use this dialog box to select specific ciphers to use with SSL. You have to enable SSL to access this dialog box.
+</p>
+<p class="text">
+<a name="14891"> </a>
+Select the checkboxes next to the ciphers you want your server to use. The Netscape Console requires particular ciphers to work with SSL.
+</p>
+<p class="h2">
+<a name="20483"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="20484"> </a>
+<a href="../en/slapd/ag/ssl.htm#1038525">Setting Security Preferences</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_rootnode5.htm b/ldap/docs/dirhlp/help/configtab_rootnode5.htm
new file mode 100644
index 00000000..c1393c27
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_rootnode5.htm
@@ -0,0 +1,181 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:02" />
+<title>Netscape Directory Server Help: SNMP Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="14821"> </a>
+<a name="SNMP Tab"> </a>
+SNMP Tab
+</p>
+
+<p class="text">
+<a name="14938"> </a>
+Use this tab to set up SNMP for the directory.
+</p>
+<p class="text">
+<a name="14939"> </a>
+<b>Enable statistics collection.</b> Select this checkbox to enable SNMP for the directory. Clear this checkbox to disable SNMP.
+</p>
+<p class="text">
+<a name="14941"> </a>
+<b>Master host (UNIX Only).</b> The host name of the machine on which the master subagent is installed. By default, the value is <code>localhost</code>.
+</p>
+<p class="text">
+<a name="14943"> </a>
+<b>Master port (UNIX Only). </b>The port number used to communicate with the master subagent. The default port number is 199.
+</p>
+<p class="text">
+<a name="14945"> </a>
+<b>Description.</b> Describes the directory server instance. This description is presented to clients viewing SNMP statistics.
+</p>
+<p class="text">
+<a name="14947"> </a>
+<b>Organization. </b>Organization name presented to clients viewing SNMP statistics.
+</p>
+<p class="text">
+<a name="14949"> </a>
+<b>Location.</b> The location of the directory. This information is presented to clients viewing the SNMP statistics.
+</p>
+<p class="text">
+<a name="14951"> </a>
+<b>Contact.</b> The email address of the person responsible for maintaining the directory.
+</p>
+<p class="text">
+<a name="14953"> </a>
+<b>Subagent buttons. </b>Allow you to Stop, Start, and Restart the SNMP subagent on UNIX, or the SNMP Service on Windows.
+</p>
+<p class="h2">
+<a name="14959"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="14985"> </a>
+<a href="../en/slapd/ag/snmp.htm">Managing SNMP </a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_rootnode6.htm b/ldap/docs/dirhlp/help/configtab_rootnode6.htm
new file mode 100644
index 00000000..97afd547
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_rootnode6.htm
@@ -0,0 +1,180 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:02" />
+<title>Netscape Directory Server Help: Manager Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="13690"> </a>
+<a name="Manager Tab"> </a>
+Manager Tab
+</p>
+
+<p class="text">
+<a name="14989"> </a>
+Use this tab to configure the directory manager, the privileged database administrator.
+</p>
+<p class="text">
+<a name="14990"> </a>
+<b>Directory Manager DN. </b>Contains the DN for the directory manager. By default, this user is <code>cn=Directory Manager</code>.
+</p>
+<p class="text">
+<a name="14992"> </a>
+<b>Manager password encryption.</b> Defines how the directory stores the directory manager password in the directory. By default, the directory gives you the following encryption options:
+</p>
+<ul>
+
+<li>
+Salted Secure Hashing Algorithm (SSHA). This method is recommended as the most secure. SSHA is the default encryption method.
+<a name="25133"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+UNIX crypt algorithm (CRYPT). Provided for compatibility with UNIX passwords.
+<a name="25134"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Secure Hashing Algorithm (SHA). A one-way has algorithm that is the default encryption schema in Directory Server 4.x.
+<a name="25135"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+No encryption (CLEAR). This encryption type indicates that the password will appear in plain text.
+<a name="25136"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="14994"> </a>
+<b>New password. </b>To change the directory manager password, enter the new password in this text box.
+</p>
+<p class="text">
+<a name="14996"> </a>
+<b>Confirm password.</b> Re-enter the new directory manager password in this text box for verification.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_rootnode7.htm b/ldap/docs/dirhlp/help/configtab_rootnode7.htm
new file mode 100644
index 00000000..6d1da0ff
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_rootnode7.htm
@@ -0,0 +1,118 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+ <meta name="keywords"
+ content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace">
+ <meta name="description"
+ content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software.">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="templatebase"
+ content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6">
+ <meta name="LASTUPDATED" content="04/29/03 15:35:31">
+ <title>Netscape Directory Server Help: Settings Tab</title>
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+ <script type="text/JavaScript" src="help_files/sniffer.js">
+
+ </script>
+
+</head>
+<body style="color: rgb(0, 0, 0); background-color: rgb(255, 255, 255);"
+ link="#006666" vlink="#006666" alink="#333366">
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent--><!--navigationcontent defines the top row of links and the banner --><!--start navigationcontent-->
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr>
+ <td valign="bottom" width="67"> <img
+ src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0"
+ alt="Netscape logo"></td>
+ <td valign="middle"> <span class="product">Netscape
+Directory Server</span> <span class="booktitle">Console Help</span> </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <hr size="1" noshade="noshade"><span class="navigation"> <a
+ style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+ </a> </span>&nbsp;&nbsp;&nbsp;&nbsp; </td>
+ </tr>
+ </tbody>
+</table>
+<!--end navigationcontent-->
+<!--bookcontent defines the actual content of the file, sans headers and footers --><!--start bookcontent-->
+<blockquote><br>
+ <p class="h1"> <a name="28258"> </a><a name="Settings Tab"> </a>SASL
+Mapping Tab </p>
+ <p class="text"> <a name="25219"> </a>SASL uses special identities
+to map a client to an entry or DN in the directory. Use this tab to
+configure
+SASL mapping to use
+SASL for encrypted sessions.</p>
+ <p class="text"><b>label.</b> Text box of SASL identites that have
+been created. Highlight one of these to modify or delete it.<br>
+ </p>
+ <ul>
+ <li><span style="font-weight: bold;">Name.</span> The name of the
+SASL identity.<br>
+ </li>
+ <li><span style="font-weight: bold;">Regular Expression.</span> A
+regular expression that maps the SASL identity.</li>
+ <li><span style="font-weight: bold;">Search Base DN.</span> The
+base DN for the SASL mapping identity search.</li>
+ <li><span style="font-weight: bold;">Search Filter.</span> The
+search filter for the SASL
+mapping identity search.</li>
+ </ul>
+ <p class="text"> <a name="25220"> </a><b>Add.</b> This button will
+bring up the New
+SASL Mapping text box to create a new SASL mapping identity.<br>
+ </p>
+ <p class="text"> <a name="25221"> </a><b>Modify.</b> This will
+bring up the Modify
+SASL Mapping text box, which will allow you to modify the search base
+DN, search filter, and/or regular expression of a SASL mapping
+identity. </p>
+ <p class="text"> <a name="25222"> </a><b>Delete.</b> Deletes a SASL
+mapping identity. <br>
+ </p>
+ <p class="text"><br>
+ <big>See also<br>
+ <a href="/manual/en/slapd/ag/ssl.htm"><small>Managing SSL and SASL</small></a><br>
+ </big> </p>
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date--><!--start footercontent--><br>
+<br>
+<span class="navigation">
+<a style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+</a>
+</span>&nbsp;&nbsp;&nbsp;&nbsp;
+<hr noshade="noshade" size="1">
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright
+1999, 2002-2003 Netscape Communications Corporation. All rights
+reserved.</p>
+<br>
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+<!--end footercontent--><!--end maincontent-->
+</body>
+</html>
diff --git a/ldap/docs/dirhlp/help/configtab_rootnode8.htm b/ldap/docs/dirhlp/help/configtab_rootnode8.htm
new file mode 100644
index 00000000..e22f63d2
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_rootnode8.htm
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+ <meta name="keywords"
+ content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace">
+ <meta name="description"
+ content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software.">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="templatebase"
+ content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6">
+ <meta name="LASTUPDATED" content="04/29/03 15:35:31">
+ <title>Netscape Directory Server Help: Settings Tab</title>
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+ <script type="text/JavaScript" src="help_files/sniffer.js">
+
+ </script>
+
+</head>
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366"
+ bgcolor="#ffffff">
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent--><!--navigationcontent defines the top row of links and the banner --><!--start navigationcontent-->
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr>
+ <td valign="bottom" width="67"> <img
+ src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0"
+ alt="Netscape logo"></td>
+ <td valign="middle"> <span class="product">Netscape
+Directory Server</span> <span class="booktitle">Console Help</span> </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <hr size="1" noshade="noshade"><span class="navigation"> <a
+ style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+ </a> </span>&nbsp;&nbsp;&nbsp;&nbsp; </td>
+ </tr>
+ </tbody>
+</table>
+<!--end navigationcontent-->
+<!--bookcontent defines the actual content of the file, sans headers and footers --><!--start bookcontent-->
+<blockquote><br>
+ <p class="h1"> <a name="28258"> </a><a name="Settings Tab"> </a>SASL
+Mapping - Add Button </p>
+ <p class="text"> <a name="25219"> </a>Use this tab to add a new
+SASL mapping identity. </p>
+ <p class="text"> <a name="25220"> </a><b>Name.</b> The name of the
+new identity.<br>
+ </p>
+ <p class="text"> <a name="25221"> </a><b>Regular Expression.</b> A
+regular expression to map the new identity. </p>
+ <p class="text"> <a name="25222"> </a><b>Search Base DN.</b> The
+base DN for the SASL mapping identity search.<br>
+ </p>
+ <p class="text"><b>Search Filter.</b> The search filter for the SASL
+mapping identity search.<!--end bookcontent--><!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date--><!--start footercontent-->
+ </p>
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date--><!--start footercontent--><br>
+<br>
+<span class="navigation">
+<a style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+</a>
+</span>&nbsp;&nbsp;&nbsp;&nbsp;
+<hr noshade="noshade" size="1">
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright
+1999, 2002-2003 Netscape Communications Corporation. All rights
+reserved.</p>
+<br>
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+<!--end footercontent--><!--end maincontent-->
+</body>
+</html>
diff --git a/ldap/docs/dirhlp/help/configtab_rootnode9.htm b/ldap/docs/dirhlp/help/configtab_rootnode9.htm
new file mode 100644
index 00000000..426ae899
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_rootnode9.htm
@@ -0,0 +1,96 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+ <meta name="keywords"
+ content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace">
+ <meta name="description"
+ content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software.">
+ <meta http-equiv="content-type"
+ content="text/html; charset=ISO-8859-1">
+ <meta name="templatebase"
+ content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6">
+ <meta name="LASTUPDATED" content="04/29/03 15:35:31">
+ <title>Netscape Directory Server Help: Settings Tab</title>
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+ <script type="text/JavaScript" src="help_files/sniffer.js">
+
+ </script>
+
+</head>
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366"
+ bgcolor="#ffffff">
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent--><!--navigationcontent defines the top row of links and the banner --><!--start navigationcontent-->
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+ <tbody>
+ <tr>
+ <td>
+ <table border="0" cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr>
+ <td valign="bottom" width="67"> <img
+ src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0"
+ alt="Netscape logo"></td>
+ <td valign="middle"> <span class="product">Netscape
+Directory Server</span> <span class="booktitle">Console Help</span> </td>
+ </tr>
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <hr size="1" noshade="noshade"><span class="navigation"> <a
+ style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+ </a> </span>&nbsp;&nbsp;&nbsp;&nbsp; </td>
+ </tr>
+ </tbody>
+</table>
+<!--end navigationcontent-->
+<!--bookcontent defines the actual content of the file, sans headers and footers --><!--start bookcontent-->
+<blockquote><br>
+ <p class="h1"> <a name="28258"> </a><a name="Settings Tab"> </a>SASL
+Mapping - Modify Button </p>
+ <p class="text"> <a name="25219"> </a>Use this tab to change a
+SASL mapping identity. </p>
+ <p class="text"> <a name="25220"> </a><b>Name.</b> The name of the
+SASL identity. This field is grayed out, and the name cannot be changed.<br>
+ </p>
+ <p class="text"> <a name="25221"> </a><b>Regular Expression.</b> A
+regular expression to map the new identity; this can be changed. </p>
+ <p class="text"> <a name="25222"> </a><b>Search Base DN.</b> The
+base DN for the SASL mapping identity search; this can be changed.<br>
+ </p>
+ <p class="text"><b>Search Filter.</b> The search filter for the SASL
+mapping identity search; this can be changed.<!--end bookcontent--><!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date--><!--start footercontent-->
+ </p>
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date--><!--start footercontent--><br>
+<br>
+<span class="navigation">
+<a style="text-decoration: none; color: rgb(0, 102, 102);"
+ href="http://whitetail.mtbrook.bozemanpass.com:58464/manual/en/slapd/index.htm">DocHome
+</a>
+</span>&nbsp;&nbsp;&nbsp;&nbsp;
+<hr noshade="noshade" size="1">
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright
+1999, 2002-2003 Netscape Communications Corporation. All rights
+reserved.</p>
+<br>
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+<!--end footercontent--><!--end maincontent-->
+</body>
+</html>
diff --git a/ldap/docs/dirhlp/help/configtab_schema.htm b/ldap/docs/dirhlp/help/configtab_schema.htm
new file mode 100644
index 00000000..ed71a051
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_schema.htm
@@ -0,0 +1,181 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Object Classes</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28692"> </a>
+<a name="Object Classes"> </a>
+Object Classes
+</p>
+
+<p class="text">
+<a name="28694"> </a>
+Use this tab to view information about all object classes that currently exist in your directory schema. You can also delete an object class that you have created using this tab. You cannot edit or delete standard object classes.
+</p>
+<p class="text">
+<a name="28905"> </a>
+<b>Parent. </b>Identifies the object class from which the object class currently selected in the Object Classes list inherits attributes and structure.
+</p>
+<p class="text">
+<a name="28696"> </a>
+<b>OID.</b> Object identifier (OID) for the object class selected in the Object Classes list. An OID is a string, usually of decimal numbers, that uniquely identifies an object, (such as an object class or an attribute) in an object-oriented system. If no OID is assigned, the directory automatically uses <span class="variable">ObjectClass_name</span><code>-oid</code>. For example, if you created the object class <code>division</code> without supplying an OID, the directory automatically uses <code>division-oid</code> as the OID.
+</p>
+<p class="text">
+<a name="28697"> </a>
+<b>Object Classes.</b> Contains a list of all the user-defined and standard object classes that currently exist in the schema.
+</p>
+<p class="text">
+<a name="28698"> </a>
+<b>Required Attributes. </b>Lists the required attributes for the object class selected in the Object Classes list. When you add an entry to the directory using this object class, you must add values for the required attributes to the entry. The list also includes inherited attributes.
+</p>
+<p class="text">
+<a name="28699"> </a>
+<b>Allowed Attributes. </b>Lists the optional attributes for the object class selected in the Object Classes list. When you add an entry to the directory using this object class, you may add values for the allowed attributes to the entry. The list also includes inherited attributes.
+</p>
+<p class="text">
+<a name="28700"> </a>
+<b>Create. </b>Click this button to create a new object class.
+</p>
+<p class="text">
+<a name="28701"> </a>
+<b>Edit. </b>To edit a user-defined object class, select it in the Object Classes list and then click Edit.
+</p>
+<p class="text">
+<a name="28702"> </a>
+<b>Delete. </b>Select a user-defined object class from the Object Classes list and then click Delete to delete it from the schema. You cannot delete the standard object classes that came with the directory.
+</p>
+<p class="h2">
+<a name="28703"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28706"> </a>
+<a href="../en/slapd/ag/scmacfg.htm">Extending the Directory Schema</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_schema2.htm b/ldap/docs/dirhlp/help/configtab_schema2.htm
new file mode 100644
index 00000000..a04519bd
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_schema2.htm
@@ -0,0 +1,177 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Create Object Class</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28714"> </a>
+<a name="Create Object Class"> </a>
+Create Object Class
+</p>
+
+<p class="text">
+<a name="28716"> </a>
+Use this dialog box to create a new or edit an existing object class in your directory. You cannot modify the standard object classes that come with Netscape Directory Server. You can modify only those object classes that you define.
+</p>
+<p class="text">
+<a name="28720"> </a>
+<b>Name.</b> Enter a unique name for the object class.
+</p>
+<p class="text">
+<a name="28721"> </a>
+<b>Parent.</b> Identifies the object class from which the new object class will inherit attributes and structure. You can choose from any existing object class.
+</p>
+<p class="text">
+<a name="28722"> </a>
+<b>OID (Optional).</b> Allows you to change the object identifier (OID) for the object class. An OID is a string, usually of decimal numbers, that uniquely identifies an object (such as an object class or an attribute) in an object-oriented system. This field is optional. If you do not specify an OID, the directory automatically uses <span class="variable">ObjectClass_name</span><code>-oid</code>. For example, if you create the object class <code>division</code> without supplying an OID, the directory automatically creates the OID <code>division-oid</code>.
+</p>
+<p class="text">
+<a name="28723"> </a>
+<b>Available attributes.</b> Lists all of the attributes in the schema not inherited from the parent object class. You can add attributes to a user-defined object class by selecting the attribute in the list and then clicking the Add button to the left of either the Required Attributes or Allowed Attributes list box.
+</p>
+<p class="text">
+<a name="28724"> </a>
+To delete an attribute that you previously added, highlight the attribute in the Required Attributes list or the Allowed Attributes list and then click the corresponding Remove button.
+</p>
+<p class="text">
+<a name="28725"> </a>
+<b>Required attributes. </b>Lists the required attributes for the object class including inherited attributes. To add an attribute to the required attributes list, select it in the Available Attributes list and then click the Add button next to the Required Attributes list box.
+</p>
+<p class="text">
+<a name="28726"> </a>
+<b>Allowed attributes.</b> Lists the allowed attributes for the object class including inherited attributes. To add an attribute to the allowed attributes list, select it in the Available Attributes list and then click the Add button next to the Allowed Attributes list box.
+</p>
+<p class="h2">
+<a name="28727"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28730"> </a>
+<a href="../en/slapd/ag/scmacfg.htm">Extending the Directory Schema</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_schema3.htm b/ldap/docs/dirhlp/help/configtab_schema3.htm
new file mode 100644
index 00000000..cf562976
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_schema3.htm
@@ -0,0 +1,195 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Attributes</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28752"> </a>
+<a name="Attributes"> </a>
+Attributes
+</p>
+
+<p class="text">
+<a name="28754"> </a>
+Use this tab to view information about existing attributes, to create new attributes, or to delete attributes you previously created. For more specific information about the configuration attributes, refer to the <a href="../en/slapd/cli/contents.htm"><em>Netscape Directory Server Configuration, Command, and File Reference</em><em></a></em>.
+</p>
+<p class="text">
+<a name="28760"> </a>
+<b>Standard Attributes (Read-Only). </b>The Standard Attributes table lists all standard attributes along with their OIDs and corresponding attribute syntax. The alphabetical listing of all available attributes helps you determine whether or not you need to create a new attribute. The information in the table is defined below. More specific information is available in the <em>Netscape Schema Reference Guide</em>.
+</p>
+<ul>
+
+<li>
+Name&#151;The unique name of the attribute.
+<a name="28766"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+OID&#151;The object identifier of the attribute.
+<a name="28767"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Syntax&#151;Displays the syntax of the attribute. For example, the syntax type of Case Ignore String indicates that values for this attribute are not case sensitive.
+<a name="28768"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Multi&#151;Defines whether the attribute is multi-valued. If the checkbox in this column is selected, the attribute can be multi-valued. The directory allows more than one instance of a multi-valued attribute per entry.
+<a name="28769"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28770"> </a>
+<b>User Defined Attributes. </b>Table that lists the user-defined attributes in the directory schema. The information displayed for each attribute is the same for user-defined attributes as for standard attributes (see above).
+</p>
+<p class="text">
+<a name="28771"> </a>
+<b>Create. </b>Click this button to create a new attribute.
+</p>
+<p class="text">
+<a name="28772"> </a>
+<b>Edit. </b>Click this button to edit the currently selected attribute in the tables above.
+</p>
+<p class="text">
+<a name="28773"> </a>
+<b>Delete. </b>You can delete user-defined attributes by selecting them from the User Defined Attributes table and then clicking Delete. Make sure that no object classes are using the attribute before you delete it.
+</p>
+<p class="h2">
+<a name="28774"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28777"> </a>
+<a href="../en/slapd/ag/scmacfg.htm">Extending the Directory Schema</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_schema4.htm b/ldap/docs/dirhlp/help/configtab_schema4.htm
new file mode 100644
index 00000000..5604dc6a
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_schema4.htm
@@ -0,0 +1,173 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Create Attribute Dialog Box</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28786"> </a>
+<a name="Create Attribute Dialog Box"> </a>
+Create Attribute Dialog Box
+</p>
+
+<p class="text">
+<a name="28788"> </a>
+This dialog box allows you to create new attributes or edit existing ones.
+</p>
+<p class="text">
+<a name="28789"> </a>
+<b>Attribute name. </b>A unique string that identifies the attribute you are creating.
+</p>
+<p class="text">
+<a name="28790"> </a>
+<b>Attribute OID (optional).</b> The Attribute OID field is an optional field that you can use to supply an object identifier (OID) for the new attribute. If you do not supply an OID, the directory automatically uses <span class="variable">attribute_name</span><code>-oid</code>. For example, if you create a new attribute called <code>birthdate</code>, the default OID is <code>birthdate-oid</code>.
+</p>
+<p class="text">
+<a name="28791"> </a>
+<b>Attribute aliases (optional). </b>You can specify a nickname for the new attribute. For example, <code>cn</code> is an alias for the <code>CommonName</code> attribute.
+</p>
+<p class="text">
+<a name="28792"> </a>
+<b>Attribute description (optional). </b>Enter a short description of the new attribute.
+</p>
+<p class="text">
+<a name="28793"> </a>
+<b>Syntax. </b>Select a syntax that describes the data to be held by the attribute. Available syntaxes are Integer, IA5String, Case Exact String, Case Ignore String, URI, GeneralizedTime, DistinguishedName (DN), TelephoneNumber, Boolean, Binary, DirectoryString, CountryName, PostalAddress, and Octet String. For a description of each syntax, see the<em> </em><em>Netscape Schema Reference Guide</em>. The default value is DirectoryString.
+</p>
+<p class="text">
+<a name="28799"> </a>
+<b>Multi-valued. </b>When selected, this option specifies that the attribute you are creating is multi-valued, meaning an entry may contain more than one instance of this attribute.
+</p>
+<p class="h2">
+<a name="28800"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28803"> </a>
+<a href="../en/slapd/ag/scmacfg.htm">Extending the Directory Schema</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/configtab_schema5.htm b/ldap/docs/dirhlp/help/configtab_schema5.htm
new file mode 100644
index 00000000..d651b387
--- /dev/null
+++ b/ldap/docs/dirhlp/help/configtab_schema5.htm
@@ -0,0 +1,211 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:32" />
+<title>Netscape Directory Server Help: Matching Rules</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28811"> </a>
+<a name="Matching Rules"> </a>
+Matching Rules
+</p>
+
+<p class="text">
+<a name="28813"> </a>
+Use the Matching Rules tab to view all the matching rules used by the directory. The table includes matching rules from plug-ins you have created.You cannot edit the standard matching rules.
+</p>
+<p class="text">
+<a name="28814"> </a>
+Matching rules provide guidelines for how the server compares strings during a search operation. In an international search, the matching rule tells the server what collation order and operator to use. For example, a matching rule in an international search might tell the server to search for attribute values that come at or after llama in the Spanish collation order.
+</p>
+<p class="text">
+<a name="28815"> </a>
+<b>Name. </b>Contains a list of all the user-defined and standard matching rules currently available to the directory. Standard matching rules are named according to the following syntax:
+</p>
+<p class="text">
+<a name="28816"> </a>
+<span class="variable">AttributeSyntax SearchType</span>-<code>Lang</code>
+</p>
+<p class="text">
+<a name="28817"> </a>
+Where <span class="variable">AttributeSyntax</span> is the type of attribute on which this matching rule may be applied, <span class="variable">SearchType</span> is the type of search for which this matching rule may be applied, and <span class="variable">Lang</span> is the abbreviated code for the locale of the matching rule.
+</p>
+<p class="text">
+<a name="28818"> </a>
+The possible name types include:
+</p>
+<ul>
+
+<li>
+caseIgnoreOrderingMatch-(Lang)
+<a name="28819"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+caseExactOrderingMatch-(Lang)
+<a name="28820"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+caseIgnoreSubstringMatch-(Lang)
+<a name="28821"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+caseExactSubstringMatch-(Lang)
+<a name="28822"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28823"> </a>
+<b>OID. </b>The object identifier of the matching rule's locale. Each locale supported by the directory has an associated collation order OID.
+</p>
+<p class="text">
+<a name="28824"> </a>
+<b>Syntax. </b>Displays the syntax of the matching rule's locale. Matching rule syntax is defined as "Directory String" and is used internally by the directory.
+</p>
+<p class="text">
+<a name="28825"> </a>
+<b>Description. </b>Contains the two character language tag of the locale. If necessary to distinguish regional differences in language, the language tag may also contain a country code, which is a two-character uppercase string (as defined in ISO standard 3166). The language code and country code are separated by a hyphen. For example, the language tag used to identify the British English locale is en-GB.
+</p>
+<p class="h2">
+<a name="28826"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28829"> </a>
+<a href="../en/slapd/ag/find.htm#1041100">Matching Rule Filter Syntax</a>
+</p>
+<p class="text">
+<a name="28832"> </a>
+<a href="../en/slapd/ag/i18n.htm">Internationalization Appendix</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dir_browser.htm b/ldap/docs/dirhlp/help/dir_browser.htm
new file mode 100644
index 00000000..19da06c2
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dir_browser.htm
@@ -0,0 +1,138 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: Directory Browser</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="25216"> </a>
+<a name="Directory Browser"> </a>
+Directory Browser
+</p>
+
+<p class="text">
+<a name="25217"> </a>
+Use this dialog box to browse through the contents of the directory and select a subtree to export or replicate.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dir_browser2.htm b/ldap/docs/dirhlp/help/dir_browser2.htm
new file mode 100644
index 00000000..f99eff01
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dir_browser2.htm
@@ -0,0 +1,239 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="07/14/03 14:01:49" />
+<title>Netscape Directory Server Help: Passwords Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28981"> </a>
+<a name="Passwords Tab"> </a>
+Passwords Tab
+</p>
+
+<p class="text">
+<a name="28983"> </a>
+Use this tab to set up a password policy for the currently selected subtree or user.
+</p>
+<p class="text">
+<a name="28984"> </a>
+<b>Create subtree/user level password policy. </b>The caption of this checkbox reflects whether you opted to create a subtree or user level password policy. Selecting the checkbox adds the attributes required for defining the subtree- or user-level password policy. Once the policy is created, the caption changes to reflect that the existing policy can be modified or deleted. To delete the policy, unselect the checkbox.
+</p>
+<p class="text">
+<a name="28985"> </a>
+<b>User must change password after reset. </b>When selected, users must change their passwords when they first log in or after the administrator resets the passwords.
+</p>
+<p class="text">
+<a name="28986"> </a>
+<b>User may change password.</b> When selected, allows users to change their own passwords.
+</p>
+<p class="text">
+<a name="28987"> </a>
+<b>Allow changes in X day(s). </b>Defines how often users can change their password. Use this value in conjunction with "Keep password history" to discourage users from recycling old passwords.
+</p>
+<p class="text">
+<a name="28988"> </a>
+<b>Keep password history.</b> Specifies that the server keep a list of user passwords. Use this in conjunction with "Allow changes in X day(s)" to discourage users from reusing old passwords. If you select this option, enter the number of passwords users must cycle through before they can reuse a password.
+</p>
+<p class="text">
+<a name="28989"> </a>
+<b>Remember X passwords. </b>If the server is keeping a password history, this option specifies how many old passwords the server should store in the history list. The valid value range is from 2 to 24. The default value is 6.
+</p>
+<p class="text">
+<a name="28990"> </a>
+<b>Password never expires.</b> Select this if you do not require users to change their passwords periodically.
+</p>
+<p class="text">
+<a name="28991"> </a>
+<b>Password expires after X days. </b>Select this if you want users to change their passwords periodically. If you select the option, in the text box, you must enter the number of days in which the password will expire.
+</p>
+<p class="text">
+<a name="29169"> </a>
+Note that the maximum value for the password age is derived by subtracting January 18, 2038 from today's date. The value you enter must not be set to the maximum value or too close to the maximum value. If you set the value to the maximum value, Directory Server may fail to start because the number of seconds will go past the epoch date. In such an event, the error log will indicate that the password maximum age is invalid. To resolve this problem, you must correct the <code>paswordMaxAge</code> attribute value in the <code>dse.ldif</code> file.
+</p>
+<p class="text">
+<a name="29183"> </a>
+A common policy is to have passwords expire every 30 to 90 days. By default, the password maximum age is set to 8640000 seconds (100 days).
+</p>
+<p class="text">
+<a name="28992"> </a>
+<b>Send warning X day(s) before password expires.</b> Indicates the number of days before a user's password is due to expire that the user will be sent a warning message. The valid value range is from 1 to 24,855 days. The default value is 1 day.
+</p>
+<p class="text">
+<a name="29051"> </a>
+<b>Allow up to X attempt(s) after password expires.</b> Indicates the number of grace logins permitted after a user's password has expired. Grace logins are not permitted by default.
+</p>
+<p class="text">
+<a name="28993"> </a>
+<b>Check password syntax.</b> Select this checkbox to enforce password syntax checking. Syntax checking ensures that the password strings conform to the syntax guidelines, such as minimum password length.
+</p>
+<p class="text">
+<a name="28994"> </a>
+<b>Password minimum length. </b>If syntax checking is on, this option specifies the minimum number of characters that must be used in directory server passwords. The valid value range is from 2 to 512 characters. The default value is 6.
+</p>
+<p class="text">
+<a name="28995"> </a>
+<b>Password encryption. </b>Identifies how user passwords are stored in the directory. You can specify one of the following encryption formats:
+</p>
+<ul>
+
+<li>
+Salted Secure Hashing Algorithm (SSHA). This method is recommended as the most secure. SSHA is the default encryption method.
+<a name="28996"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+UNIX crypt algorithm (CRYPT). Provided for compatibility with UNIX passwords.
+<a name="28997"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Secure Hashing Algorithm (SHA). A one-way has algorithm that is the default encryption schema in Directory Server 4.x.
+<a name="28998"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+No encryption (CLEAR). This encryption type indicates that the password will appear in plain text.
+<a name="28999"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="29000"> </a>
+Passwords stored using SSHA, CRYPT, or SHA formats cannot be used for secure login through SASL Digest MD5.
+</p>
+<p class="h2">
+<a name="29001"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="29004"> </a>
+<a href="../en/slapd/ag/password.htm#1074672">Configuring the Password Policy</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>July 14, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dir_browser3.htm b/ldap/docs/dirhlp/help/dir_browser3.htm
new file mode 100644
index 00000000..89494a84
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dir_browser3.htm
@@ -0,0 +1,169 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="07/10/03 13:41:25" />
+<title>Netscape Directory Server Help: Account Lockout Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29005"> </a>
+<a name="Account Lockout Tab"> </a>
+Account Lockout Tab
+</p>
+
+<p class="text">
+<a name="29007"> </a>
+You can set up a account lockout policy for the directory using the Account Lockout tab.
+</p>
+<p class="text">
+<a name="29008"> </a>
+<b>Accounts may be locked out. </b>Select this option to enable account lockout because of repeated login failures. Clear this checkbox if you do not want users to be locked out of the directory after a series of failed bind attempts.
+</p>
+<p class="text">
+<a name="29009"> </a>
+<b>Lockout account after X login failures.</b> Specify the number of times a user can fail to bind before they are locked out of the directory. Valid values are 1 to 32,767 attempts. This option is available only if account lockout is enabled.
+</p>
+<p class="text">
+<a name="29010"> </a>
+<b>Reset failure count after X minutes. </b>Indicates the amount of time that must elapse before the failure counter is reset. This option is available only if account lockout is enabled. Valid values are 1 to 35,791,394 minutes.
+</p>
+<p class="text">
+<a name="29011"> </a>
+<b>Lockout forever.</b> Select this option to indicate that user accounts that have been locked must be reset by the administrator before users can access the directory. If you select this option, you cannot set a lockout duration.
+</p>
+<p class="text">
+<a name="29012"> </a>
+<b>Lockout duration X minutes. </b>Select this option to indicate the amount of time a user will be locked out of the directory after a series of failed bind attempts. If you select this option, you must enter a number of minutes in the text box. Valid values are 1 to 35,791,394 minutes. This option is available only if account lockout is enabled.
+</p>
+<p class="h2">
+<a name="29013"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="29016"> </a>
+<a href="../en/slapd/ag/password.htm#1086557">Configuring the Account Lockout Policy<a href="">
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>July 10, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dir_browser4.htm b/ldap/docs/dirhlp/help/dir_browser4.htm
new file mode 100644
index 00000000..338c1cf0
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dir_browser4.htm
@@ -0,0 +1,189 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:05" />
+<title>Netscape Directory Server Help: Edit Smart Referrals</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29223"> </a>
+<a name="Edit Smart Referrals"> </a>
+Edit Smart Referrals
+</p>
+
+<p class="text">
+<a name="29240"> </a>
+Use this tab to configure <em>smart</em> referrals. Smart referrals allow you to map a directory entry or directory tree to a specific LDAP URL. Using smart referrals, you can refer client applications to a specific server or a specific entry on a specific server.
+</p>
+<p class="text">
+<a name="29645"> </a>
+<b>Enable Smart Referrals. </b>Check this option to define smart referrals for the selected entry. Unchecking the option removes all smart referrals from the entry and deletes <code>objectclass: referral</code>.
+</p>
+<p class="text">
+<a name="29267"> </a>
+<b>Smart Referral List. </b>Lists the referrals currently in place for the selected entry. The entire list of referrals is returned to client applications in response to a request, when you select Referral or Referral on Update in the Suffix Settings tab.
+</p>
+<p class="text">
+<a name="29484"> </a>
+To modify the list, click Edit to edit the selected referral or Delete to delete the selected referral.
+</p>
+<p class="text">
+<a name="29357"> </a>
+<b>Enter a new Smart Referral. </b>Enter a referral in the LDAP URL format and then click Add to add the referral to the list. The LDAP URL to which you want to refer client application requests must be in the following format:
+</p>
+<p class="text">
+<a name="29433"> </a>
+<code>ldap://</code><span class="variable">hostname</span><code>:</code><span class="variable">portnumber</span><code>/[</code><span class="variable">optional_dn</span><code>]</code>
+</p>
+<p class="text">
+<a name="29358"> </a>
+where <span class="variable">[optional_dn]</span> is the explicit DN you want the server to return to the requesting client application. For example, you might enter an LDAP URL as follows:
+</p>
+<p class="text">
+<a name="29241"> </a>
+<code>ldap://directory.example.com:389/cn=jdoe,ou=people,dc=example,dc=com</code>
+</p>
+<p class="text">
+<a name="29325"> </a>
+You may also click Construct to be guided through the process of adding a referral.
+</p>
+<p class="text">
+<a name="29495"> </a>
+To allow a referral to be followed with different authentication, click Authentication and specify the appropriate DN and password. Keep in mind that this authentication remains valid only until the console is closed; then, it's reset to the same authentication used to log into the console.
+</p>
+<p class="h2">
+<a name="29243"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="29705"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17763">Using Referrals</a>
+</p>
+<p class="text">
+<a name="29249"> </a>
+<a href="../en/slapd/ag/entry_dist.htm#17930">Creating and Maintaining Suffixes</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_cos.htm b/ldap/docs/dirhlp/help/dirtab_cos.htm
new file mode 100644
index 00000000..432f1dcf
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_cos.htm
@@ -0,0 +1,169 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Attribute</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28794"> </a>
+<a name="Attribute"> </a>
+Attribute
+</p>
+
+<p class="text">
+<a name="28796"> </a>
+This dialog box lists the attributes generated by the class of service.
+</p>
+<p class="text">
+<a name="28797"> </a>
+<b>Attribute Name. </b>Name of the attributes currently generated on the target entries.
+</p>
+<p class="text">
+<a name="28798"> </a>
+<b>Override.</b> Click Override to make the value of the attribute generated by the CoS override the local value.
+</p>
+<p class="text">
+<a name="28799"> </a>
+<b>Operational.</b> Click Operational to make the attribute operational, so that it is not visible to client applications unless explicitly requested.
+</p>
+<p class="text">
+<a name="28800"> </a>
+<b>Add. </b>Click Add to browse the list of possible attributes and add them to the list.
+</p>
+<p class="text">
+<a name="28801"> </a>
+<b>Remove.</b> Click Remove to delete an attribute from the list.
+</p>
+<p class="h2">
+<a name="28802"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28805"> </a>
+<a href="../en/slapd/ag/roles.htm#1115636">About CoS</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_cos2.htm b/ldap/docs/dirhlp/help/dirtab_cos2.htm
new file mode 100644
index 00000000..10c0a989
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_cos2.htm
@@ -0,0 +1,161 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Create New Class of Service</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28813"> </a>
+<a name="Create New Class of Service"> </a>
+Create New Class of Service
+</p>
+
+<p class="text">
+<a name="28815"> </a>
+Use this dialog box to create a new class of service.
+</p>
+<p class="text">
+<a name="28816"> </a>
+<b>Class Name. </b>Enter the name of your new class of service. This field is required.
+</p>
+<p class="text">
+<a name="28817"> </a>
+<b>Description. </b>Enter a description of your class of service.
+</p>
+<p class="h2">
+<a name="28818"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28821"> </a>
+<a href="../en/slapd/ag/roles.htm#1116857">Creating a New Class of Service</a>
+</p>
+<p class="text">
+<a name="28824"> </a>
+<a href="../en/slapd/ag/roles.htm#1115636">About CoS</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_cos3.htm b/ldap/docs/dirhlp/help/dirtab_cos3.htm
new file mode 100644
index 00000000..f34bc63b
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_cos3.htm
@@ -0,0 +1,181 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Template</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28832"> </a>
+<a name="Template"> </a>
+Template
+</p>
+
+<p class="text">
+<a name="28834"> </a>
+Use this tab to configure the CoS template.
+</p>
+<p class="text">
+<a name="28835"> </a>
+<b>Choose how the template entry is identified.</b>
+</p>
+<ul>
+
+<li>
+Explicitly by its DN
+<a name="28836"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Using the value of an attribute from the target entry
+<a name="28837"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Using both a DN and the value of an attribute from the target entry
+<a name="28838"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28839"> </a>
+<b>Template DN. </b>If you choose to have the template entry identified by its DN, enter the DN of the template in this field. Click Browse to locate a template on your local machine.
+</p>
+<p class="text">
+<a name="28840"> </a>
+<b>Attribute Name. </b>If you choose to have the template entry identified by the value of one of the target entry's attributes, enter the attribute name in this field. Be sure to select an attribute which contains DN values.
+</p>
+<p class="h2">
+<a name="28841"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28844"> </a>
+<a href="../en/slapd/ag/roles.htm#1116857">Creating a New CoS</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_role.htm b/ldap/docs/dirhlp/help/dirtab_role.htm
new file mode 100644
index 00000000..5173d462
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_role.htm
@@ -0,0 +1,213 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Add New Filtered Role Member</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28778"> </a>
+<a name="Add New Filtered Role Member"> </a>
+Add New Filtered Role Member
+</p>
+
+<p class="text">
+<a name="28780"> </a>
+Use this dialog box to add members to your new filtered role. Filtered roles allow you to assign entries to the role depending upon an attribute contained by each entry. You do this by specifying an LDAP filter. Entries that match the filter are said to possess the role.
+</p>
+<p class="text">
+<a name="28781"> </a>
+<b>LDAP filter. </b>Enter the filter in this text field or click Construct to be guided through the construction of an LDAP filter. The Construct dialog box contains the following fields:
+</p>
+<ul>
+
+<li>
+<b>Search. </b>Select whether to search for entries within the base DN, one level below the base DN, or the whole subtree beneath the base DN.
+<a name="28782"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>For. </b>Select the types of entries you want to filter from this list. You can choose between users, groups, or both.
+<a name="28783"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Where. </b>Select an attribute from this drop-down list. The two fields following it allow you to refine your search by selecting one of the qualifiers from the drop-down list (such as contains, does not contain, is, is not). Enter an attribute value in the text box.
+<a name="28784"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>More. </b>Click this button to add additional filters.
+<a name="28785"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<b>Fewer. </b>Click this button to remove unnecessary filters.
+<a name="28786"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28787"> </a>
+<b>Test. </b>Click this button to try your filter. The entries matching your filter appear in the table. The following information is displayed:
+</p>
+<ul>
+
+<li>
+Name
+<a name="28788"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+User ID
+<a name="28789"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Email
+<a name="28790"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="h2">
+<a name="28791"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28794"> </a>
+<a href="../en/slapd/ag/roles.htm#1117626">Creating a Filtered Role</a>
+</p>
+<p class="text">
+<a name="28797"> </a>
+<a href="../en/slapd/ag/roles.htm#1115402">Using Roles</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_role2.htm b/ldap/docs/dirhlp/help/dirtab_role2.htm
new file mode 100644
index 00000000..4aec1d96
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_role2.htm
@@ -0,0 +1,161 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Add New Managed Role Member</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28805"> </a>
+<a name="Add New Managed Role Member"> </a>
+Add New Managed Role Member
+</p>
+
+<p class="text">
+<a name="28807"> </a>
+Use this dialog box to add members to your new managed role. Managed roles allow you to create an explicit enumerated list of members.
+</p>
+<p class="text">
+<a name="28808"> </a>
+<b>Click and entry to select it. </b>Select an entry from the list and click OK. This list contains all entries available for adding to the new managed role.
+</p>
+<p class="text">
+<a name="28809"> </a>
+<b>Selected DN. </b>Contains the DN of the selected entry.
+</p>
+<p class="h2">
+<a name="28810"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28813"> </a>
+<a href="../en/slapd/ag/roles.htm#1117626">Creating a Managed Role</a>
+</p>
+<p class="text">
+<a name="28816"> </a>
+<a href="../en/slapd/ag/roles.htm#1115402">Using Roles</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_role3.htm b/ldap/docs/dirhlp/help/dirtab_role3.htm
new file mode 100644
index 00000000..a39cf631
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_role3.htm
@@ -0,0 +1,161 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Add New Nested Role Member</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28824"> </a>
+<a name="Add New Nested Role Member"> </a>
+Add New Nested Role Member
+</p>
+
+<p class="text">
+<a name="28826"> </a>
+Use this dialog box to add members to a new nested role. Nested roles allow you to create roles that contain other roles. Before you can create a nested role, another role must exist.
+</p>
+<p class="text">
+<a name="28827"> </a>
+<b>Add. </b>Click Add to add roles to the list. The members of the nested role are members of other existing roles.
+</p>
+<p class="text">
+<a name="28828"> </a>
+<b>Remove. </b>Click Remove to remove roles from the list.
+</p>
+<p class="h2">
+<a name="28829"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28832"> </a>
+<a href="../en/slapd/ag/roles.htm#1117626">Creating a Nested Role</a>
+</p>
+<p class="text">
+<a name="28835"> </a>
+<a href="../en/slapd/ag/roles.htm#1115402">Using Roles</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_role4.htm b/ldap/docs/dirhlp/help/dirtab_role4.htm
new file mode 100644
index 00000000..0a89f44a
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_role4.htm
@@ -0,0 +1,157 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Role Accounts Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28843"> </a>
+<a name="Role Accounts Tab"> </a>
+Role Accounts Tab
+</p>
+
+<p class="text">
+<a name="28845"> </a>
+Use this tab to activate or inactivate a user or role. Once inactivated, all affected users cannot authenticate.
+</p>
+<p class="text">
+<a name="28846"> </a>
+<b>Inactivate. </b>Click this button to inactivate the user or role. Inactivating a role means that you have inactivated all of the users who are members of the role.
+</p>
+<p class="text">
+<a name="28847"> </a>
+<b>Activate. </b>Click this button to reactive a user or role that has been inactivated.
+</p>
+<p class="h2">
+<a name="28848"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28851"> </a>
+<a href="../en/slapd/ag/password.htm#1085611">Inactivating Accounts Using the Console</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_role5.htm b/ldap/docs/dirhlp/help/dirtab_role5.htm
new file mode 100644
index 00000000..be0c2a12
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_role5.htm
@@ -0,0 +1,161 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: General Tab</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28875"> </a>
+<a name="General Tab"> </a>
+General Tab
+</p>
+
+<p class="text">
+<a name="28877"> </a>
+Use this tab to name and describe your new managed, filtered, or nested role.
+</p>
+<p class="text">
+<a name="28878"> </a>
+<b>Role Name. </b>Enter a unique role name. This field is required.
+</p>
+<p class="text">
+<a name="28879"> </a>
+<b>Description. </b>Enter a brief description of the role in this field.
+</p>
+<p class="h2">
+<a name="28880"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28883"> </a>
+<a href="../en/slapd/ag/roles.htm#1117626">Managing Roles Using the Console</a>
+</p>
+<p class="text">
+<a name="28886"> </a>
+<a href="../en/slapd/ag/roles.htm#1115402">Using Roles</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_role6.htm b/ldap/docs/dirhlp/help/dirtab_role6.htm
new file mode 100644
index 00000000..3b7cff43
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_role6.htm
@@ -0,0 +1,157 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Set Role</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28894"> </a>
+<a name="Set Role"> </a>
+Set Role
+</p>
+
+<p class="text">
+<a name="28896"> </a>
+Use this dialog box to edit a role of an entry.
+</p>
+<p class="text">
+<a name="28897"> </a>
+<b>Managed Roles Tab.</b> This tab displays the managed roles to which this entry belongs. To add a new role, click Add and select an available role from the Role Selector window. To remove a role, select it and click Remove.
+</p>
+<p class="text">
+<a name="28898"> </a>
+<b>Other Roles Tab.</b> This tab displays the filtered and nested roles to which the entry belongs. Click Edit to make changes to the filtered or nested roles of the entry.
+</p>
+<p class="h2">
+<a name="28899"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28902"> </a>
+<a href="../en/slapd/ag/roles.htm">Viewing and Editing an Entry's Roles</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/dirtab_role7.htm b/ldap/docs/dirhlp/help/dirtab_role7.htm
new file mode 100644
index 00000000..a65b0dfb
--- /dev/null
+++ b/ldap/docs/dirhlp/help/dirtab_role7.htm
@@ -0,0 +1,161 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Role Selector</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28910"> </a>
+<a name="Role Selector"> </a>
+Role Selector
+</p>
+
+<p class="text">
+<a name="28912"> </a>
+Use this dialog box to select an existing role to add roles to the listed of nested roles.
+</p>
+<p class="text">
+<a name="28913"> </a>
+<b>Available Roles. </b>This table lists all of the existing roles available for nesting.
+</p>
+<p class="text">
+<a name="28914"> </a>
+<b>Name. </b>Unique role name.
+</p>
+<p class="text">
+<a name="28915"> </a>
+<b>Description. </b>Description of the role.
+</p>
+<p class="h2">
+<a name="28916"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28919"> </a>
+<a href="../en/slapd/ag/roles.htm#1117626">Creating a Nested Role</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/helpmenu.htm b/ldap/docs/dirhlp/help/helpmenu.htm
new file mode 100644
index 00000000..d9ef64cd
--- /dev/null
+++ b/ldap/docs/dirhlp/help/helpmenu.htm
@@ -0,0 +1,204 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: Confirmation Preferences</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29102"> </a>
+<a name="Confirmation Preferences"> </a>
+Confirmation Preferences
+</p>
+
+<p class="text">
+<a name="29107"> </a>
+Use this dialog box to customize whether Directory Server Console requires confirmation on various operations.
+</p>
+<p class="text">
+<a name="29108"> </a>
+Clear the checkbox next to the task(s) for which you do not want the server to require confirmation. The options include:
+</p>
+<ul>
+
+<li>
+Delete object class
+<a name="29109"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Delete attribute
+<a name="29110"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Delete entry
+<a name="29111"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Delete subtree
+<a name="29112"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Delete index
+<a name="29113"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Delete suffix
+<a name="29114"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Delete replication agreement
+<a name="29115"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Remove changelog
+<a name="29116"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Overwrite database (on import)
+<a name="29117"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Stop the server
+<a name="29118"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/ix.htm b/ldap/docs/dirhlp/help/ix.htm
new file mode 100644
index 00000000..92683562
--- /dev/null
+++ b/ldap/docs/dirhlp/help/ix.htm
@@ -0,0 +1,228 @@
+<html>
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="11/07/01 20:19:05" />
+<title>Netscape Directory Server Console Help: </title>
+
+<script type="text/JavaScript">
+
+<!-- Start hiding
+
+window.onerror=null;
+var client=navigator.userAgent.toLowerCase();
+
+var WinStyle = "<STYLE NAME=WINDOWS>\n" +
+"body,p {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 10; margin-top: 0; } \n" +
+"th,tr,td,br,li,dl,dd,ul,ol,li {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; } \n" +
+".booktitle {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: bold; margin-bottom: 0; margin-top: 0; font-size:17pt;} \n" +
+".callout {font-family: verdana,helvetica,arial,sans-serif; font-size: 8pt;} \n" +
+".calloutlarge {font-family: verdana,helvetica,arial,sans-serif; font-size: 9pt;} \n" +
+".calloutlargebold {font-family: verdana,helvetica,arial,sans-serif; font-size: 9pt; font-weight: bold;} \n" +
+".calloutsmall {font-family: verdana,helvetica,arial,sans-serif; font-size: 7pt; font-weight: normal;} \n" +
+".caption {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 5; margin-top: 10; font-size: 10pt;} \n" +
+".caution {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; font-weight: bold; margin-bottom: 0; margin-top: 0; } \n" +
+"code {font-family: courier,couriernew,monospaced; font-size: 10pt; margin-bottom: 0; margin-bottom:0; margin-top: 0;} \n" +
+".code {font-family: courier,couriernew,monospaced; font-size:10pt; margin-bottom: 10; margin-top: 0; } \n" +
+".copy {font-family: verdana,helvetica,arial,sans-serif; font-size:8pt; margin-bottom: 0; margin-top: 0;} \n" +
+".footnote {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; } \n" +
+".gloss {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 10; margin-top: 0; } \n" +
+".grouptitleix {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 20pt; font-size: 14pt;} \n" +
+".h1 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 30; margin-top: 30pt; font-size: 16pt;} \n" +
+".h2 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 30pt; font-size: 14pt;} \n" +
+".h3 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 20pt; font-size: 12pt;} \n" +
+".h4 {font-family: verdana,helvetica,arial,sans-serif; font-style: italic; font-color: black;margin-bottom: 0; margin-top: 16pt; font-size: 11pt;} \n" +
+".h5 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 0; margin-top: 0; font-size: 8pt;} \n" +
+".navigation {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: #006666; margin-bottom: 0; margin-top: 0; font-size:10pt;} \n" +
+".note {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; font-weight: bold; margin-bottom: 0; margin-top: 0; } \n" +
+"pre {font-family: courier,couriernew,monospaced; font-size: 10pt; margin-bottom: 0; } \n" +
+".product {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: bold; margin-bottom: 0; margin-top: 0; font-size:17pt;} \n" +
+".refhead {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 4; margin-top: 15pt; font-size: 11pt;} \n" +
+".tabletext {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 6; margin-top: 0; } \n" +
+".tabletextright {align: right; valign: top; font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 6; margin-top: 0; } \n" +
+".tablehead {text-align: left;font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; font-size:10pt; margin-bottom: 4; margin-top: 0; } \n" +
+".text {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 16; margin-top: 0; } \n" +
+".tip {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; font-weight: bold; margin-bottom: 0; margin-top: 0; } \n" +
+".title {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black;margin-bottom: 30pt; margin-top: 16pt; font-size: 16pt;} \n" +
+".toc1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tocc {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt; font-weight: bold; margin-bottom: 0; margin-top: 7; margin-left: 30;} \n" +
+".tocg {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tochead1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 30;} \n" +
+".tochead2 {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 60;} \n" +
+".tochead3 {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 90;} \n" +
+".tocnontoc {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-left: 0;} \n" +
+".tocpart {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; font-weight: bold; margin-bottom: 0; margin-top: 20;} \n" +
+".update {text-align: right; font-family: verdana,helvetica,arial,sans-serif; font-size:8pt; margin-bottom: 0; margin-top: 0; margin-right: 20pt;} \n" +
+".variable {font-family: palatino, times, serif; font-style: italic;} \n" +
+"</style>";
+
+var OtherStyle = "<style name=NOTWINDOWS>\n" +
+"body,p {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 0; margin-top: 14; } \n" +
+"th,tr,td,br,li,dl,dd,ul,ol,li {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; } \n" +
+".booktitle {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: bold; margin-bottom: 0; margin-top: 0; font-size: 23pt;} \n" +
+".callout {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt;} \n" +
+".calloutlarge {font-family: verdana,helvetica,arial,sans-serif; font-size: 12pt;} \n" +
+".calloutlargebold {font-family: verdana,helvetica,arial,sans-serif; font-size: 12pt; font-weight: bold;} \n" +
+".calloutsmall {font-family: verdana,helvetica,arial,sans-serif; font-size: 9pt; font-weight: normal;} \n" +
+".caption {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 5; margin-top: 16; font-size: 13pt;} \n" +
+".caution {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; font-weight: bold; margin-bottom: 0; margin-top: 14; } \n" +
+"code {font-family: courier,couriernew,monospaced; font-size: 13pt; margin-bottom: 0; margin-bottom:0; margin-top: 0;} \n" +
+".code {font-family: courier,couriernew,monospaced; font-size:13pt; margin-bottom: 0; margin-top: 13; } \n" +
+".copy {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 0; margin-top: 0;} \n" +
+".footnote {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; } \n" +
+".gloss {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 14; margin-top: 14; } \n" +
+".grouptitleix {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 20pt; font-size: 19pt;} \n" +
+".h1 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 30; margin-top: 35pt; font-size: 21pt;} \n" +
+".h2 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 35pt; font-size: 18pt;} \n" +
+".h3 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 25pt; font-size: 14pt;} \n" +
+".h4 {font-family: verdana,helvetica,arial,sans-serif; font-style: italic; font-color: black;margin-bottom: 0; margin-top: 22pt; font-size: 13pt;} \n" +
+".h5 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 0; margin-top: 16; font-size: 13pt;} \n" +
+".navigation {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: #006666; margin-bottom: 0; margin-top: 0; font-size:14pt;} \n" +
+".note {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; font-weight: bold; margin-bottom: 0; margin-top: 14; } \n" +
+"pre {font-family: courier,couriernew,monospaced; font-size: 13pt; margin-bottom: 0; } \n" +
+".product {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: normal; margin-bottom: 0; margin-top: 0; font-size: 23pt;} \n" +
+".refhead {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 4; margin-top: 20pt; font-size: 13pt;} \n" +
+".tabletext {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 4; margin-top: 6; } \n" +
+".tabletextright {align: right; valign: top; font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 4; margin-top: 6; } \n" +
+".tablehead {text-align: left;font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; font-size:13pt; margin-bottom: 4; margin-top: 0; } \n" +
+".text {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 8; margin-top: 14; } \n" +
+".tip {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; font-weight: bold; margin-bottom: 0; margin-top: 14; } \n" +
+".title {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 30pt; margin-top: 16pt; font-size: 21pt;} \n" +
+".toc1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 14pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tocc {font-family: verdana,helvetica,arial,sans-serif; font-size: 14pt; font-weight: bold; margin-bottom: 0; margin-top: 7; margin-left: 30;} \n" +
+".tocg {font-family: verdana,helvetica,arial,sans-serif; font-size: 14pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tochead1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 13pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 30;} \n" +
+".tochead2 {font-family: verdana,helvetica,arial,sans-serif; font-size: 13pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 60;} \n" +
+".tochead3 {font-family: verdana,helvetica,arial,sans-serif; font-size: 13pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 90;} \n" +
+".tocnontoc {font-family: verdana,helvetica,arial,sans-serif; font-size: 13pt; font-weight: normal; text-indent: 0;} \n" +
+".tocpart {font-family: verdana,helvetica,arial,sans-serif; font-size:16pt; font-weight: bold; margin-bottom: 0; margin-top: 20;} \n" +
+".update {text-align: right; font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 0; margin-top: 0; margin-right: 20pt;} \n" +
+".variable {font-family: palatino, times, serif; font-style: italic;} \n" +
+"</style>";
+if ( client.indexOf("win") != -1 ){
+ document.write( WinStyle );
+}else{
+ document.write( OtherStyle );
+}
+
+// End hiding -->
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="../en/slapd/help/topics.htm">
+Topics
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="../en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="title">
+<a name="127"> </a>
+<a name="Index"> </a>
+Index
+</p>
+<br />
+<table border=0 cellpadding=4 cellspacing=0>
+<tr>
+<td><b><a href="#SYMBOLS">Symbols</a></b></td><td><b><a href="#A">A</a></b></td><td><b><a href="#B">B</a></b></td><td><b><a href="#C">C</a></b></td><td><b><a href="#D">D</a></b></td><td><b><a href="#E">E</a></b></td><td><b><a href="#F">F</a></b></td><td><b><a href="#G">G</a></b></td><td><b><a href="#H">H</a></b></td><td><b><a href="#I">I</a></b></td><td><b><a href="#J">J</a></b></td><td><b><a href="#K">K</a></b></td><td><b><a href="#L">L</a></b></td><td><b><a href="#M">M</a></b></td><td><b><a href="#N">N</a></b></td><td><b><a href="#O">O</a></b></td><td><b><a href="#P">P</a></b></td><td><b><a href="#Q">Q</a></b></td><td><b><a href="#R">R</a></b></td><td><b><a href="#S">S</a></b></td><td><b><a href="#T">T</a></b></td><td><b><a href="#U">U</a></b></td><td><b><a href="#V">V</a></b></td><td><b><a href="#W">W</a></b></td><td><b><a href="#X">X</a></b></td><td><b><a href="#Y">Y</a></b></td><td><b><a href="#Z">Z</a></b></td>
+</tr>
+</table>
+<br />
+<br />
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="../en/slapd/help/topics.htm">
+Topics
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="../en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">Copyright © 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>January 31, 2002</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/ldapurl.htm b/ldap/docs/dirhlp/help/ldapurl.htm
new file mode 100644
index 00000000..51a30e1e
--- /dev/null
+++ b/ldap/docs/dirhlp/help/ldapurl.htm
@@ -0,0 +1,154 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: Construct LDAP URL</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28974"> </a>
+<a name="Construct LDAP URL"> </a>
+Construct LDAP URL
+</p>
+
+<p class="text">
+<a name="18752"> </a>
+Use the Construct LDAP URL dialog box to be stepped through the creation of an LDAP URL for a referral.
+</p>
+<p class="text">
+<a name="18753"> </a>
+<b>LDAP Host. </b>Name of the machine containing the data.
+</p>
+<p class="text">
+<a name="18754"> </a>
+<b>LDAP Port. </b>Port number of the machine containing the data.
+</p>
+<p class="text">
+<a name="18755"> </a>
+<b>Target DN. </b>The explicit DN you want the server to return to the client application.
+</p>
+<p class="text">
+<a name="18756"> </a>
+<b>LDAP URL Results. </b>This field displays the automatically created LDAP URL.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/netscape32.gif b/ldap/docs/dirhlp/help/netscape32.gif
new file mode 100644
index 00000000..3dd151d0
--- /dev/null
+++ b/ldap/docs/dirhlp/help/netscape32.gif
Binary files differ
diff --git a/ldap/docs/dirhlp/help/new_instance.htm b/ldap/docs/dirhlp/help/new_instance.htm
new file mode 100644
index 00000000..6fa1a970
--- /dev/null
+++ b/ldap/docs/dirhlp/help/new_instance.htm
@@ -0,0 +1,166 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: New Server Instance</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28957"> </a>
+<a name="New Server Instance"> </a>
+New Server Instance
+</p>
+
+<p class="text">
+<a name="25195"> </a>
+Use this dialog box to create a new instance of an existing directory server.
+</p>
+<p class="text">
+<a name="25196"> </a>
+<b>Server Identifier. </b>Enter a unique identifier for the server. The prefix <code>slapd-</code> will automatically be added to the identifier you enter here. Do not use spaces in the identifier.
+</p>
+<p class="text">
+<a name="25197"> </a>
+<b>Network Port.</b> Type the port number on which you want the directory to listen for incoming requests.
+</p>
+<p class="text">
+<a name="25198"> </a>
+<b>Base Suffix.</b> Enter the user directory suffix. For example, the base suffix for the Example Corporation might be <code>dc=example,dc=com</code>.
+</p>
+<p class="text">
+<a name="25199"> </a>
+<b>Root DN. </b>Enter the distinguished name of the privileged directory user. For example, enter <code>cn=directory manager</code> for the directory manager.
+</p>
+<p class="text">
+<a name="25200"> </a>
+<b>Password for Root DN.</b> Enter the password of the privileged directory user.
+</p>
+<p class="text">
+<a name="25201"> </a>
+<b>Confirm Password.</b> Re-enter the password of the privileged directory user.
+</p>
+<p class="text">
+<a name="25202"> </a>
+<b>Server Runtime (UNIX) User. </b>If you are running the server on a UNIX host, type the name of the runtime user.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/pixel.gif b/ldap/docs/dirhlp/help/pixel.gif
new file mode 100644
index 00000000..3ea701d9
--- /dev/null
+++ b/ldap/docs/dirhlp/help/pixel.gif
Binary files differ
diff --git a/ldap/docs/dirhlp/help/property_editor.htm b/ldap/docs/dirhlp/help/property_editor.htm
new file mode 100644
index 00000000..f7447f70
--- /dev/null
+++ b/ldap/docs/dirhlp/help/property_editor.htm
@@ -0,0 +1,185 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="08/11/03 15:51:42" />
+<title>Netscape Directory Server Help: Property Editor</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28980"> </a>
+<a name="Property Editor"> </a>
+Property Editor
+</p>
+
+<p class="text">
+<a name="28982"> </a>
+Use this dialog box to modify the object classes and attributes contained within an entry.
+</p>
+<p class="text">
+<a name="28983"> </a>
+<b>Show Attribute Names. </b>Select this option if you want the property editor to display the names of the attributes as they appear in the schema. For example, <code>mail</code> instead of <code>Email address</code>.
+</p>
+<p class="text">
+<a name="28984"> </a>
+<b>Show Attribute Descriptions. </b>Select this option if you want the property editor to display the friendly names of the attributes. For example,<code> Email address</code> instead of <code>mail</code>. This option is selected by default.
+</p>
+<p class="text">
+<a name="28985"> </a>
+<b>Show All Allowed Attributes. </b>This checkbox controls the list of attributes shown in the property editor -- the list either includes only the attributes with values currently in the entry or all attributes allowed by schema for the selected object. The checkbox is unselected by default, and the attribute list shows only currently present attributes. Select the checkbox if you want the property editor to display all the attributes allowed by schema for the currently selected object. .
+</p>
+<p class="text">
+<a name="28986"> </a>
+<b>Show DN. </b>Select this checkbox if you want to view the entry's DN.
+</p>
+<p class="text">
+<a name="28987"> </a>
+<b>Add Value. </b>If the currently selected attribute is not the <code>objectclass</code> attribute or a binary attribute, you can use this command to insert a blank text box for the currently selected attribute. Enter the new value in the text box.
+</p>
+<p class="text">
+<a name="28988"> </a>
+If a value already exists for the attribute and the attribute is not multi-valued, you cannot enter additional values. Attempting to do so results in an object class violation.
+</p>
+<p class="text">
+<a name="28989"> </a>
+<b>Delete Value. </b>Use this command to delete the currently selected attribute value. This will not delete the attribute itself.
+</p>
+<p class="text">
+<a name="28990"> </a>
+<b>Add Attribute. </b>Use this command to add an attribute to the entry. When you select this command, the Add Attribute dialog box appears. This dialog box lists only those attributes contained within the object classes already assigned to this entry.
+</p>
+<p class="text">
+<a name="28991"> </a>
+<b>Delete Attribute. </b>Use this command to delete the currently selected attribute from the entry.
+</p>
+<p class="h2">
+<a name="28992"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28998"> </a>
+<a href="../en/slapd/ag/modify.htm#1082152">Managing Entries From the Directory Server Console</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>August 19, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/property_editor2.htm b/ldap/docs/dirhlp/help/property_editor2.htm
new file mode 100644
index 00000000..74e3dff3
--- /dev/null
+++ b/ldap/docs/dirhlp/help/property_editor2.htm
@@ -0,0 +1,142 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: Add Object Class</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29006"> </a>
+<a name="Add Object Class"> </a>
+Add Object Class
+</p>
+
+<p class="text">
+<a name="29008"> </a>
+Use this dialog box to add an object class to an existing entry.
+</p>
+<p class="text">
+<a name="29009"> </a>
+<b>Object Class List. </b>This list contains all of the object classes currently in the directory schema. Select the object class you want to add to the entry and click OK.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/property_editor3.htm b/ldap/docs/dirhlp/help/property_editor3.htm
new file mode 100644
index 00000000..d7353781
--- /dev/null
+++ b/ldap/docs/dirhlp/help/property_editor3.htm
@@ -0,0 +1,188 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: Add Attribute</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29017"> </a>
+<a name="Add Attribute"> </a>
+Add Attribute
+</p>
+
+<p class="text">
+<a name="29019"> </a>
+Use this dialog box to add an attribute to an existing entry. Before you can add an attribute, an object class that allows or requires the attribute must exist in the entry.
+</p>
+<p class="text">
+<a name="29020"> </a>
+<b>Language. </b>Contains a list of languages that can be assigned to the attribute as subtypes.
+</p>
+<p class="text">
+<a name="29021"> </a>
+Sometimes a user's name can be more accurately represented in characters of a language other than the default language. For example, Noriko's name is Japanese, and she has indicated on her hiring forms that she prefers that her name be represented by Japanese characters when possible. You can select Japanese as a language subtype for the <code>givenname</code> attribute so that other users can search for her Japanese name.
+</p>
+<p class="text">
+<a name="29022"> </a>
+If you specify a language subtype for an attribute, the subtype is added to the attribute name as follows:
+</p>
+<p class="text">
+<a name="29023"> </a>
+<span class="variable">attribute</span><code>;lang-</code><span class="variable">subtype</span>
+</p>
+<p class="text">
+<a name="29024"> </a>
+Where <span class="variable">attribute</span> is the attribute you are adding to the entry and <span class="variable">subtype</span> is the two character abbreviation for the language. For example:
+</p>
+<p class="text">
+<a name="29025"> </a>
+<code>givenname;lang-ja</code>
+</p>
+<p class="text">
+<a name="29026"> </a>
+You can assign only one language subtype per instance of an attribute in an entry. To assign multiple language subtypes, add another instance of the attribute to the entry and then assign the new language subtype to the copy.
+</p>
+<p class="text">
+<a name="29027"> </a>
+<b>Subtype.</b> Contains a list of commonly-used subtypes (other than languages) that can be assigned to the attribute as a subtype. The options include:
+</p>
+<ul>
+
+<li>
+Binary&#151;Indicates that the attribute value is binary. For example, <code>userCertificate;binary</code>.
+<a name="29028"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Pronunciation&#151;Indicates that the attribute value is a phonetic representation. The subtype is added to the attribute name as follows: <span class="variable">attribute</span><code>;phonetic</code>. This subtype is commonly used in combination with a language subtype for languages that have more than one alphabet, where one is a phonetic representation. You might want to use this with attributes that are expected to contain user names, such as <code>cn</code> or <code>givenname</code>. For example, <code>givenname;lang-ja;phonetic</code> indicates that the attribute value is the phonetic version of the entry's Japanese name.
+<a name="29029"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="29030"> </a>
+<b>Attributes List. </b>This list contains all of the attributes that are allowed within the object classes currently assigned to the entry. To add an attribute to the entry, select it in the list and then click OK.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/property_editor4.htm b/ldap/docs/dirhlp/help/property_editor4.htm
new file mode 100644
index 00000000..38548c33
--- /dev/null
+++ b/ldap/docs/dirhlp/help/property_editor4.htm
@@ -0,0 +1,186 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: Add New Object</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="29052"> </a>
+<a name="Add New Object"> </a>
+Add New Object
+</p>
+
+<p class="text">
+<a name="29057"> </a>
+Use this dialog box to add new objects to Directory Server.
+</p>
+<p class="text">
+<a name="29058"> </a>
+<b>Show Attribute Names. </b>Select this option if you want the property editor to display the names of the attributes as they appear in the schema. For example, <code>mail</code> instead of <code>Email address</code>.
+</p>
+<p class="text">
+<a name="29059"> </a>
+<b>Show Attribute Descriptions. </b>Select this option if you want the property editor to display the friendly names of the attributes. For example,<code> Email address</code> instead of <code>mail</code>. This option is selected by default.
+</p>
+<p class="text">
+<a name="29060"> </a>
+<b>Show only Attributes with Values. </b>Select this checkbox if you want the property editor to display only those attributes that have values. This option is selected by default.
+</p>
+<p class="text">
+<a name="29061"> </a>
+<b>Show DN. </b>Select this checkbox if you want to view the entry's DN.
+</p>
+<p class="text">
+<a name="29062"> </a>
+<b>Add Value. </b>If the currently selected attribute is not the <code>objectclass</code> attribute or a binary attribute, you can use this command to insert a blank text box for the currently selected attribute. Enter the new value in the text box.
+</p>
+<p class="text">
+<a name="29063"> </a>
+If a value already exists for the attribute and the attribute is not multi-valued, you cannot enter additional values. Attempting to do so results in an object class violation.
+</p>
+<p class="text">
+<a name="29064"> </a>
+<b>Delete Value. </b>Use this command to delete the currently selected attribute value. This will not delete the attribute itself.
+</p>
+<p class="text">
+<a name="29065"> </a>
+<b>Add Attribute. </b>Use this command to add an attribute to the entry. When you select this command, the Add Attribute dialog box appears. This dialog box lists only those attributes contained within the object classes already assigned to this entry.
+</p>
+<p class="text">
+<a name="29066"> </a>
+<b>Delete Attribute. </b>Use this command to delete the currently selected attribute from the entry.
+</p>
+<p class="text">
+<a name="29067"> </a>
+<b>Naming Attribute. </b>Select a naming attribute from the drop-down list. The naming attribute is used to form the DN of the entry.
+</p>
+<p class="text">
+<a name="29068"> </a>
+If the naming attribute you want is not present in the list, click the Add Attribute button and add it to the entry. After adding the new attribute, the naming attribute appears in the list.
+</p>
+<p class="text">
+<a name="29069"> </a>
+<b>Naming Value. </b>Select a value for your naming attribute from the drop-down list.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/redir_agtoc.htm b/ldap/docs/dirhlp/help/redir_agtoc.htm
new file mode 100644
index 00000000..dc6ccb99
--- /dev/null
+++ b/ldap/docs/dirhlp/help/redir_agtoc.htm
@@ -0,0 +1,136 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: </title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="text">
+<a name="28981"> </a>
+
+</p>
+<p class="text">
+<a name="28987"> </a>
+<a href="../en/slapd/ag/contents.htm"><em>Netscape Directory Server Administrator's Guide</em></a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/redir_dochome.htm b/ldap/docs/dirhlp/help/redir_dochome.htm
new file mode 100644
index 00000000..fc3dcb44
--- /dev/null
+++ b/ldap/docs/dirhlp/help/redir_dochome.htm
@@ -0,0 +1,113 @@
+<html>
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: </title>
+
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="text">
+<a name="28992"> </a>
+
+</p>
+<p class="text">
+<a name="28997"> </a>
+<a href="../en/slapd/index.htm">Netscape Directory Server Documentation Home</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/replication_wizard.htm b/ldap/docs/dirhlp/help/replication_wizard.htm
new file mode 100644
index 00000000..a6de6b38
--- /dev/null
+++ b/ldap/docs/dirhlp/help/replication_wizard.htm
@@ -0,0 +1,196 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Source and Destination</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28757"> </a>
+<a name="Source and Destination"> </a>
+Source and Destination
+</p>
+
+<p class="text">
+<a name="28759"> </a>
+Use this dialog box to identify the consumer to which you will replicate directory entries. In addition, this dialog box allows you to define whether or not SSL is used for the connection, and the content you want replicated.
+</p>
+<p class="text">
+<a name="28760"> </a>
+<b>Supplier. </b>This field contains a static display of the name and port number of the supplier server in this agreement.
+</p>
+<p class="text">
+<a name="28761"> </a>
+<b>Consumer. </b>Select the consumer server in the replication agreement from this drop-down menu. To ensure that all servers in your deployment appear in this drop-down menu, you must bind as Administrator. If the consumer server you want still does not appear in the list, click Other to enter the host and port of the consumer.
+</p>
+<p class="text">
+<a name="28762"> </a>
+<b>Other. </b>Click this button to manually enter the host and port of a consumer server
+</p>
+<p class="text">
+<a name="28763"> </a>
+<b>Using Encrypted SSL Connection. </b>If you want the supplier and consumer servers to use SSL for secure communication, select this checkbox. To use this option, you must have first configured your servers to use SSL.
+</p>
+<p class="text">
+<a name="28764"> </a>
+<b>SSL Client Authentication. </b>Select this option if you want the supplier and consumer servers to use certificates for secure communication. You cannot use SSL client authentication unless the "Using Encrypted SSL Connection" checkbox is selected. The "Bind As" and Password fields are unavailable with this option because the servers will use security certificates to authenticate to each other.
+</p>
+<p class="text">
+<a name="28765"> </a>
+To use this option, you must first do the following:
+</p>
+<ul>
+
+<li>
+Configure SSL for both your supplier and consumer servers.
+<a name="28766"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Configure your consumer server to recognize your supplier server's certificate as the supplier DN.
+<a name="28767"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28768"> </a>
+<b>Simple Authentication. </b>Select this option if you want the supplier and consumer servers to use simple authentication during communication. If you select the "Using Encrypted SSL Connection" checkbox and you specify this option, the simple authentication will take place over a secure channel but without certificates.
+</p>
+<p class="text">
+<a name="28769"> </a>
+<b>Bind As. </b>If you are not using SSL, or you are using SSL with simple authentication, enter the supplier bind DN defined on the consumer server in the Bind As text box.
+</p>
+<p class="text">
+<a name="28770"> </a>
+<b>Password. </b>If you are not using SSL, or you are using SSL with simple authentication, enter the Supplier DN password in the Password field.
+</p>
+<p class="text">
+<a name="28771"> </a>
+<b>Subtree. </b>Identifies the content to be replicated.
+</p>
+<p class="text">
+<a name="28772"> </a>
+When you are creating a new replication agreement from the Replication folder, you can choose the subtree you want to replicate. If you are creating a new replication agreement from a database under the Replication folder, the subtree is the same as that contained by the database and cannot be changed.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/replication_wizard2.htm b/ldap/docs/dirhlp/help/replication_wizard2.htm
new file mode 100644
index 00000000..603db59e
--- /dev/null
+++ b/ldap/docs/dirhlp/help/replication_wizard2.htm
@@ -0,0 +1,150 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Schedule Replication</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28780"> </a>
+<a name="Schedule Replication"> </a>
+Schedule Replication
+</p>
+
+<p class="text">
+<a name="28782"> </a>
+Use this dialog box to identify the time of day and day of week when replication can occur. No new replication processes will be started outside the specified replication interval.
+</p>
+<p class="text">
+<a name="28783"> </a>
+<b>Always keep directories in sync. </b>Select this option if you do not want to set time restrictions on the replication agreement.
+</p>
+<p class="text">
+<a name="28784"> </a>
+<b>Sync on the following days. </b>When selected, you can select the checkbox(es) next to the day(s) of the week on which replication can occur. Click All to sync every day.
+</p>
+<p class="text">
+<a name="28785"> </a>
+<b>Replication will take place between. </b>Select specific hours during which replication takes place.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/replication_wizard3.htm b/ldap/docs/dirhlp/help/replication_wizard3.htm
new file mode 100644
index 00000000..aa12dabd
--- /dev/null
+++ b/ldap/docs/dirhlp/help/replication_wizard3.htm
@@ -0,0 +1,169 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Initialize Consumer</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28793"> </a>
+<a name="Initialize Consumer"> </a>
+Initialize Consumer
+</p>
+
+<p class="text">
+<a name="28795"> </a>
+Use this dialog box to determine if you want to initialize the consumer when the server creates the replication agreement.
+</p>
+<p class="text">
+<a name="28796"> </a>
+<b>Do Not Initialize Consumer. </b>Select this radio button if you do not want to initialize the consumer immediately or create an LDIF file. If you are replicating a directory with a large number of entries (&gt;10,000), you should select this option. If you do select this option, you need to initialize the consumer manually before replication can occur.
+</p>
+<p class="text">
+<a name="28797"> </a>
+<b>Initialize Consumer Now. </b>Select this if you want the server to initialize the consumer when you finish creating the replication agreement. This is not recommended for databases larger than 10,000 entries.
+</p>
+<p class="text">
+<a name="28798"> </a>
+<b>Create Consumer Initialization File. </b>Select this option if you want the server to export the replicated tree to an LDIF file so you can manually import it to the consumer.
+</p>
+<p class="text">
+<a name="28799"> </a>
+<b>LDIF Filename. </b>If you choose to generate an LDIF file, supply the LDIF filename in the field provided. Click Browse to locate an LDIF file on your machine.
+</p>
+<p class="h2">
+<a name="28800"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28803"> </a>
+<a href="../en/slapd/ag/replicat.htm#1030615">Online Consumer Creation</a>
+</p>
+<p class="text">
+<a name="28806"> </a>
+<a href="../en/slapd/ag/replicat.htm#1030650">Manual Consumer Creation</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/replication_wizard4.htm b/ldap/docs/dirhlp/help/replication_wizard4.htm
new file mode 100644
index 00000000..d3a25014
--- /dev/null
+++ b/ldap/docs/dirhlp/help/replication_wizard4.htm
@@ -0,0 +1,142 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Summary Dialog</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28828"> </a>
+<a name="Summary Dialog"> </a>
+Summary Dialog
+</p>
+
+<p class="text">
+<a name="28830"> </a>
+This dialog box provides a summary of the information you provided to the replication agreement wizard. Make sure that the information on the summary dialog box is correct. If any information is incorrect, click Back to step back through the wizard and change the information. When you are finished, click Done.
+</p>
+<p class="text">
+<a name="28831"> </a>
+The server creates the replication agreement and dismisses the replication wizard. If you selected "Initialize Consumer Now" in the Initialize Consumer dialog box, the consumer is initialized immediately.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/replication_wizard5.htm b/ldap/docs/dirhlp/help/replication_wizard5.htm
new file mode 100644
index 00000000..f74e1f71
--- /dev/null
+++ b/ldap/docs/dirhlp/help/replication_wizard5.htm
@@ -0,0 +1,146 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Replication Agreement Name</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28839"> </a>
+<a name="Replication Agreement Name"> </a>
+Replication Agreement Name
+</p>
+
+<p class="text">
+<a name="28841"> </a>
+Use this dialog box to name and describe your replication agreement.
+</p>
+<p class="text">
+<a name="28842"> </a>
+<b>Name. </b>Enter a meaningful name for the replication agreement. This field is required.
+</p>
+<p class="text">
+<a name="28843"> </a>
+<b>Description. </b>Enter a brief description of your replication agreement. This field is required.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/sniffer.js b/ldap/docs/dirhlp/help/sniffer.js
new file mode 100755
index 00000000..6e4eb538
--- /dev/null
+++ b/ldap/docs/dirhlp/help/sniffer.js
@@ -0,0 +1,104 @@
+<!-- Start hiding
+
+window.onerror=null;
+var client=navigator.userAgent.toLowerCase();
+
+var WinStyle = "<STYLE NAME=WINDOWS>\n" +
+"body,p {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 10; margin-top: 0; } \n" +
+"th,tr,td,br,li,dl,dd,ul,ol,li {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; } \n" +
+".booktitle {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: bold; margin-bottom: 0; margin-top: 0; font-size:18pt;} \n" +
+".callout {font-family: verdana,helvetica,arial,sans-serif; font-size: 8pt;} \n" +
+".calloutlarge {font-family: verdana,helvetica,arial,sans-serif; font-size: 9pt;} \n" +
+".calloutlargebold {font-family: verdana,helvetica,arial,sans-serif; font-size: 9pt; font-weight: bold;} \n" +
+".calloutsmall {font-family: verdana,helvetica,arial,sans-serif; font-size: 7pt; font-weight: normal;} \n" +
+".caption {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 5; margin-top: 10; font-size: 10pt;} \n" +
+".caution {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; font-weight: bold; margin-bottom: 0; margin-top: 0; } \n" +
+"code {font-family: courier,couriernew,monospaced; font-size: 10pt; margin-bottom: 0; margin-bottom:0; margin-top: 0;} \n" +
+".code {font-family: courier,couriernew,monospaced; font-size:10pt; margin-bottom: 10; margin-top: 0; } \n" +
+".copy {font-family: verdana,helvetica,arial,sans-serif; font-size:8pt; margin-bottom: 0; margin-top: 0;} \n" +
+".footnote {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; } \n" +
+".gloss {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 10; margin-top: 0; } \n" +
+".grouptitleix {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 10; margin-top: 20; font-size: 12pt;} \n" +
+".h1 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 20; margin-top: 10; font-size: 16pt;} \n" +
+".h2 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 30; font-size: 15pt;} \n" +
+".h3 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 20; font-size: 12pt;} \n" +
+".h4 {font-family: verdana,helvetica,arial,sans-serif; font-style: italic; font-color: black;margin-bottom: 0; margin-top: 16; font-size: 11pt;} \n" +
+".h5 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 0; margin-top: 0; font-size: 8pt;} \n" +
+".navigation {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: #006666; margin-bottom: 0; margin-top: 0; font-size:10pt;} \n" +
+".note {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; font-weight: bold; margin-bottom: 0; margin-top: 0; } \n" +
+"pre {font-family: courier,couriernew,monospaced; font-size: 10pt; margin-bottom: 0; } \n" +
+".product {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: normal; margin-bottom: 0; margin-top: 0; font-size:18pt;} \n" +
+".refhead {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 4; margin-top: 15; font-size: 11pt;} \n" +
+".tabletext {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 6; margin-top: 0; } \n" +
+".tabletextright {align: right; valign: top; font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 6; margin-top: 0; } \n" +
+".tablehead {text-align: left;font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; font-size:10pt; margin-bottom: 4; margin-top: 0; } \n" +
+".text {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 16; margin-top: 0; } \n" +
+".tip {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; font-weight: bold; margin-bottom: 0; margin-top: 0; } \n" +
+".title {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black;margin-bottom: 30; margin-top: 16; font-size: 16pt;} \n" +
+".toc1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tocc {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt; font-weight: bold; margin-bottom: 0; margin-top: 7; margin-left: 30;} \n" +
+".tocg {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tochead1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 30;} \n" +
+".tochead2 {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 60;} \n" +
+".tochead3 {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 90;} \n" +
+".tocnontoc {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-left: 0;} \n" +
+".tocpart {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; font-weight: bold; margin-bottom: 0; margin-top: 20;} \n" +
+".update {text-align: right; font-family: verdana,helvetica,arial,sans-serif; font-size:8pt; margin-bottom: 0; margin-top: 0; margin-right: 20pt;} \n" +
+".variable {font-family: palatino, times, serif; font-style: italic;} \n" +
+
+
+"</style>";
+
+var OtherStyle = "<style name=NOTWINDOWS>\n" +
+"body,p {font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; margin-bottom: 0; margin-top: 14; } \n" +
+"th,tr,td,br,li,dl,dd,ul,ol,li {font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; } \n" +
+".booktitle {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: bold; margin-bottom: 0; margin-top: 0; font-size: 23pt;} \n" +
+".callout {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt;} \n" +
+".calloutlarge {font-family: verdana,helvetica,arial,sans-serif; font-size: 12pt;} \n" +
+".calloutlargebold {font-family: verdana,helvetica,arial,sans-serif; font-size: 12pt; font-weight: bold;} \n" +
+".calloutsmall {font-family: verdana,helvetica,arial,sans-serif; font-size: 9pt; font-weight: normal;} \n" +
+".caption {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 5; margin-top: 16; font-size: 15pt;} \n" +
+".caution {font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; font-weight: bold; margin-bottom: 0; margin-top: 14; } \n" +
+"code {font-family: courier,couriernew,monospaced; font-size: 15pt; margin-bottom: 0; margin-bottom:0; margin-top: 0;} \n" +
+".code {font-family: courier,couriernew,monospaced; font-size:15pt; margin-bottom: 0; margin-top: 13; } \n" +
+".copy {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 0; margin-top: 0;} \n" +
+".footnote {font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; } \n" +
+".gloss {font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; margin-bottom: 14; margin-top: 14; } \n" +
+".grouptitleix {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 10; margin-top: 20pt; font-size: 19pt;} \n" +
+".h1 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 20; margin-top: 10; font-size: 24pt;} \n" +
+".h2 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 4; margin-top: 35; font-size: 22pt;} \n" +
+".h3 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 25; font-size: 18pt;} \n" +
+".h4 {font-family: verdana,helvetica,arial,sans-serif; font-style: italic; font-color: black;margin-bottom: 0; margin-top: 22; font-size: 15pt;} \n" +
+".h5 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 0; margin-top: 16; font-size: 15pt;} \n" +
+".navigation {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: #006666; margin-bottom: 0; margin-top: 0; font-size:14pt;} \n" +
+".note {font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; font-weight: bold; margin-bottom: 0; margin-top: 14; } \n" +
+"pre {font-family: courier,couriernew,monospaced; font-size: 15pt; margin-bottom: 0; } \n" +
+".product {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: normal; margin-bottom: 0; margin-top: 0; font-size: 23pt;} \n" +
+".refhead {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 4; margin-top: 20; font-size: 15pt;} \n" +
+".tabletext {font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; margin-bottom: 4; margin-top: 6; } \n" +
+".tabletextright {align: right; valign: top; font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; margin-bottom: 4; margin-top: 6; } \n" +
+".tablehead {text-align: left;font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; font-size:15pt; margin-bottom: 4; margin-top: 0; } \n" +
+".text {font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; margin-bottom: 8; margin-top: 14; } \n" +
+".tip {font-family: verdana,helvetica,arial,sans-serif; font-size:15pt; font-weight: bold; margin-bottom: 0; margin-top: 14; } \n" +
+".title {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 30; margin-top: 16; font-size: 24pt;} \n" +
+".toc1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 16pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tocc {font-family: verdana,helvetica,arial,sans-serif; font-size: 16pt; font-weight: bold; margin-bottom: 0; margin-top: 7; margin-left: 30;} \n" +
+".tocg {font-family: verdana,helvetica,arial,sans-serif; font-size: 16pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tochead1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 15pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 30;} \n" +
+".tochead2 {font-family: verdana,helvetica,arial,sans-serif; font-size: 15pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 60;} \n" +
+".tochead3 {font-family: verdana,helvetica,arial,sans-serif; font-size: 15pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 90;} \n" +
+".tocnontoc {font-family: verdana,helvetica,arial,sans-serif; font-size: 15pt; font-weight: normal; text-indent: 0;} \n" +
+".tocpart {font-family: verdana,helvetica,arial,sans-serif; font-size:18pt; font-weight: bold; margin-bottom: 0; margin-top: 20;} \n" +
+".update {text-align: right; font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 0; margin-top: 0; margin-right: 20pt;} \n" +
+".variable {font-family: palatino, times, serif; font-style: italic;} \n" +
+
+
+"</style>";
+
+if ( client.indexOf("win") != -1 ){
+ document.write( WinStyle );
+}else{
+ document.write( OtherStyle );
+}
+
+// End hiding --> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/statustab_general.htm b/ldap/docs/dirhlp/help/statustab_general.htm
new file mode 100644
index 00000000..b9aff4f1
--- /dev/null
+++ b/ldap/docs/dirhlp/help/statustab_general.htm
@@ -0,0 +1,182 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:34" />
+<title>Netscape Directory Server Help: Directory Server Status</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28922"> </a>
+<a name="Directory Server Status"> </a>
+Directory Server Status
+</p>
+
+<p class="text">
+<a name="28924"> </a>
+Use this panel to view current server information. You cannot use this panel to edit information about the directory.
+</p>
+<p class="text">
+<a name="28925"> </a>
+<b>Server Name. </b>Specifies the name of the server as displayed in the network tree. The server name usually indicates the type of server that is selected. For example, Directory Server.
+</p>
+<p class="text">
+<a name="28931"> </a>
+<b>Description. </b>Contains a brief description of this server. For example, Directory Server for the Eastern region sales force.
+</p>
+<p class="text">
+<a name="28933"> </a>
+<b>Installation date. </b>Indicates date and time the server was installed.
+</p>
+<p class="text">
+<a name="28934"> </a>
+<b>Server root. </b>Indicates the directory where the server binaries are installed.
+</p>
+<p class="text">
+<a name="28935"> </a>
+<b>Product name. </b>Indicates the server's official product name.
+</p>
+<p class="text">
+<a name="28936"> </a>
+<b>Vendor. </b>Indicates the server software maker or provider.
+</p>
+<p class="text">
+<a name="28937"> </a>
+<b>Version. </b>Indicates the server product version number.
+</p>
+<p class="text">
+<a name="28938"> </a>
+<b>Build number. </b>Uniquely identifies a particular release of a server version. Use this as a reference number if you need to contact <em>Netscape Technical Support</em>.
+</p>
+<p class="text">
+<a name="28942"> </a>
+<b>Revision. </b>Indicates whether this server has been upgraded or patched. If no value is present, this is installation has not been patched.
+</p>
+<p class="text">
+<a name="28943"> </a>
+<b>Security level. </b>Indicates whether the server uses domestic (US based, 128-bit ciphers) or export (non-US based, 40-bit ciphers) encryption levels.
+</p>
+<p class="text">
+<a name="28944"> </a>
+<b>Server status. </b>Indicates whether the server is on or off.
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/statustab_logs.htm b/ldap/docs/dirhlp/help/statustab_logs.htm
new file mode 100644
index 00000000..79764651
--- /dev/null
+++ b/ldap/docs/dirhlp/help/statustab_logs.htm
@@ -0,0 +1,189 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Access Log Status</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28880"> </a>
+<a name="Access Log Status"> </a>
+Access Log Status
+</p>
+
+<p class="text">
+<a name="28882"> </a>
+Use this dialog box to view the directory's access log.
+</p>
+<p class="text">
+<a name="28883"> </a>
+<b>Refresh.</b> Refreshes the currently displayed log file.
+</p>
+<p class="text">
+<a name="28884"> </a>
+<b>Continuous refresh.</b> When selected, the server refreshes automatically every 10 seconds.
+</p>
+<p class="text">
+<a name="28885"> </a>
+<b>Select Log. </b>Lets you specify which access log to view from the archive.
+</p>
+<p class="text">
+<a name="28886"> </a>
+<b>Lines to show. </b>Lets you specify the number of messages to view. If you leave this text box blank, the server displays the 25 most recent messages.
+</p>
+<p class="text">
+<a name="28887"> </a>
+<b>Show only lines containing. </b>You can configure the server to display only messages containing a string you specify. Enter the string is this field and click Refresh.
+</p>
+<p class="text">
+<a name="28888"> </a>
+<b>Date.</b> Contains the date the error or event occurred in the format <code>DD/Mon/YYYY</code>. For example, 10/Feb/1998.
+</p>
+<p class="text">
+<a name="28889"> </a>
+<b>Time. </b>Contains the time the access occurred in GMT.
+</p>
+<p class="text">
+<a name="28890"> </a>
+<b>Conn. </b>Connection number.
+</p>
+<p class="text">
+<a name="28891"> </a>
+<b>Op. </b>Operation. The number in this field indicates the number of the operation within a single connection.
+</p>
+<p class="text">
+<a name="28892"> </a>
+<b>Details. </b>Contains specific information about the log entry.
+</p>
+<p class="h2">
+<a name="28893"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28896"> </a>
+<a href="../en/slapd/ag/dsstats.htm#1057137">Viewing and Configuring Log Files</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/statustab_logs2.htm b/ldap/docs/dirhlp/help/statustab_logs2.htm
new file mode 100644
index 00000000..d8ea46dc
--- /dev/null
+++ b/ldap/docs/dirhlp/help/statustab_logs2.htm
@@ -0,0 +1,181 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Error Log Status</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28897"> </a>
+<a name="Error Log Status"> </a>
+Error Log Status
+</p>
+
+<p class="text">
+<a name="28899"> </a>
+Use this dialog box to view the directory's error log.
+</p>
+<p class="text">
+<a name="28900"> </a>
+<b>Refresh. </b>Refreshes the currently displayed log file.
+</p>
+<p class="text">
+<a name="28901"> </a>
+<b>Continuous refresh. </b>When selected, this checkbox specifies that the server continuously update the currently displayed log file.
+</p>
+<p class="text">
+<a name="28902"> </a>
+<b>Select Log. </b>Lets you specify which archived error log to view.
+</p>
+<p class="text">
+<a name="28903"> </a>
+<b>Lines to show. </b>Lets you specify the number of messages to view. If you leave this text box blank, the server displays the 25 most recent messages.
+</p>
+<p class="text">
+<a name="28904"> </a>
+<b>Show only lines containing. </b>You can configure the server to display only messages containing a string you specify. Enter the string is this field and click Refresh.
+</p>
+<p class="text">
+<a name="28905"> </a>
+<b>Date. </b>Contains the date the error or event occurred in the format <code>DD/Mon/YYYY.</code> For example, 10/Feb/1998.
+</p>
+<p class="text">
+<a name="28906"> </a>
+<b>Time. </b>Contains the time the error or event occurred in GMT.
+</p>
+<p class="text">
+<a name="28907"> </a>
+<b>Details. </b>Contains specific information about the error or event.
+</p>
+<p class="h2">
+<a name="28908"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28911"> </a>
+<a href="../en/slapd/ag/dsstats.htm#1057137">Viewing and Configuring Log Files</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/statustab_logs3.htm b/ldap/docs/dirhlp/help/statustab_logs3.htm
new file mode 100644
index 00000000..f1b87827
--- /dev/null
+++ b/ldap/docs/dirhlp/help/statustab_logs3.htm
@@ -0,0 +1,169 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Audit Log Status</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28912"> </a>
+<a name="Audit Log Status"> </a>
+Audit Log Status
+</p>
+
+<p class="text">
+<a name="28914"> </a>
+Use this dialog box to view the directory's audit log. The audit log contains detailed information about changes made to each database as well as to the overall server configuration.
+</p>
+<p class="text">
+<a name="28915"> </a>
+<b>Refresh. </b>Refreshes the currently displayed log file.
+</p>
+<p class="text">
+<a name="28916"> </a>
+<b>Continuous refresh. </b>When selected, this checkbox specifies that the server continuously update the currently displayed log file.
+</p>
+<p class="text">
+<a name="28917"> </a>
+<b>Select log.</b> Select an archived audit log from the drop-down list.
+</p>
+<p class="text">
+<a name="28918"> </a>
+<b>Lines to show. </b>Lets you specify the number of messages to view. If you leave this text box blank, the server displays the 25 most recent messages.
+</p>
+<p class="text">
+<a name="28919"> </a>
+<b>Show only lines containing. </b>You can configure the server to display only messages containing a string you specify. Enter the string is this field and click Refresh.
+</p>
+<p class="h2">
+<a name="28920"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28923"> </a>
+<a href="../en/slapd/ag/dsstats.htm#1057137">Viewing and Configuring Log Files</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/statustab_performance.htm b/ldap/docs/dirhlp/help/statustab_performance.htm
new file mode 100644
index 00000000..2128df1d
--- /dev/null
+++ b/ldap/docs/dirhlp/help/statustab_performance.htm
@@ -0,0 +1,363 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="07/15/03 12:24:17" />
+<title>Netscape Directory Server Help: Server Performance Counters</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28905"> </a>
+<a name="Server Performance Counters"> </a>
+Server Performance Counters
+</p>
+
+<p class="text">
+<a name="28907"> </a>
+Use this tab to monitor your server's current activities. If the server is not running, this tab contains no performance monitoring information.
+</p>
+<p class="text">
+<a name="28908"> </a>
+<b>Server version. </b>Identifies the current server version.
+</p>
+<p class="text">
+<a name="28909"> </a>
+<b>Configuration DN. </b>Identifies the distinguished name you can use to obtain these results using the <code>ldapsearch</code> command-line utility.
+</p>
+<p class="text">
+<a name="28910"> </a>
+<b>Data version. </b>Provides identification information for the server's data area. The information here is relevant if your server supplies replicated data to consumer servers. The information supplied is:
+</p>
+<ul>
+
+<li>
+Server host name,
+<a name="28911"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Server port number,
+<a name="28912"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Database generation number, and
+<a name="28913"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Current change log number.
+<a name="28914"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28915"> </a>
+<b>Startup time on server. </b>Date and time the server started.
+</p>
+<p class="text">
+<a name="28916"> </a>
+<b>Current time on server. </b>Displays the current date and time on the server.
+</p>
+<p class="text">
+<a name="28917"> </a>
+<b>Refresh. </b>Click refresh to update the current display.
+</p>
+<p class="text">
+<a name="28918"> </a>
+<b>Continuous refresh. </b>Select this checkbox to continuously update the information display.
+</p>
+<p class="text">
+<a name="28919"> </a>
+<b>Resource Summary. </b>This table provides the following resource information:
+</p>
+<ul>
+
+<li>
+Connections. Gives the total number of connections to this server since startup and the average number of connections per minute since startup.
+<a name="28920"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Operations Initiated. Gives the total number of operations initiated since server startup and the average number of operations per minute since startup.
+<a name="28921"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Operations Completed. Gives the total number of operations completed by the server since startup and the average number of operations per minute since server startup.
+<a name="28922"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Entries Sent To Clients. Gives the total number of entries sent to client applications since server startup in response to search requests and the average number of entries sent to client application per minute since server startup.
+<a name="28923"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Bytes Sent To Clients. Gives the total number of bytes sent to client applications and the average number of bytes sent to client applications since server startup.
+<a name="28924"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28925"> </a>
+<b>Current Resource Usage. </b>This table provides the following resource usage information:
+</p>
+<ul>
+
+<li>
+Active Threads. Current number of active threads used for handling requests.
+<a name="28926"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Open Connections. Total number of open connections.
+<a name="28927"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Remaining Available Connections. Total number of remaining connections that the server can concurrently open.
+<a name="28928"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Threads Waiting To Read From Client. Provides the current total. This condition occurs when the server starts to receive a request from a client application and then the transmission is halted. This total generally indicates a slow network or client application.
+<a name="28929"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Database In Use. Total number of databases being used by the server.
+<a name="28931"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28932"> </a>
+<b>Connection Status. </b>This table provides information on the amount of resources in use by each currently open connection. The table contains the following information:
+</p>
+<ul>
+
+<li>
+Time opened. Indicates when the connection was opened.
+<a name="28933"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Started. Indicates the number of operations initiated by this connection.
+<a name="28934"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Completed. Indicates the number of operations completed by the server for this connection.
+<a name="28935"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Bound As. Indicates the DN used by the client application to connect to the server.
+<a name="28936"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Read/Write. Indicates whether the server is currently blocked for read or write access by the client application.
+<a name="28937"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28938"> </a>
+<b>Global Database Cache Information.</b>
+</p>
+<ul>
+
+<li>
+Hits. Indicates the number of times the server could process a request by obtaining data from the cache rather than by going to the disk.
+<a name="28939"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Tries. The total number of requests performed on your directory since server startup.
+<a name="28940"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Hit Ratio. The ratio of cache tries to successful cache lookups. The closer this number is to 100% the better.
+<a name="28941"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Pages read in. Indicates the number of pages read from disk into the cache.
+<a name="28942"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Pages written out. Indicates the number of pages written from the cache back to disk.
+<a name="28943"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Read-only page evicts. Indicates the number of read-only pages discarded from the cache to make room for new pages. Pages discarded from the cache have to be written to disk, possibly affecting server performance. The lower the number of page evicts the better.
+<a name="28944"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Read-write page evicts. Indicates the number of read-write pages discarded from the cache to make room for new pages. This value differs from Pages Written Out in that these are discarded read-write pages that have not been modified.
+<a name="28945"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+ <dl>
+ <dt> <a name="28946"> </a>
+Pages discarded from the cache have to be written to disk, possibly affecting server performance. The lower the number of page evicts the better.
+<br />&nbsp;</dt> </dl>
+</ul>
+<p class="h2">
+<a name="28947"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28950"> </a>
+<a href="../en/slapd/ag/dsstats.htm#1079625">Monitoring Your Server from the Console</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>July 15, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/statustab_performance2.htm b/ldap/docs/dirhlp/help/statustab_performance2.htm
new file mode 100644
index 00000000..b4d0713d
--- /dev/null
+++ b/ldap/docs/dirhlp/help/statustab_performance2.htm
@@ -0,0 +1,237 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Database Performance Counter</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28972"> </a>
+<a name="Database Performance Counter"> </a>
+Database Performance Counter
+</p>
+
+<p class="text">
+<a name="28974"> </a>
+Use this tab to monitor the current activities of a particular database or database link.
+</p>
+<p class="text">
+<a name="28975"> </a>
+<b>Database. </b>Identifies the type of database being monitored.
+</p>
+<p class="text">
+<a name="28976"> </a>
+<b>Configuration DN. </b>Identifies the distinguished name you can use to obtain these results using the <code>ldapsearch</code> command-line utility.
+</p>
+<p class="text">
+<a name="28977"> </a>
+<b>Refresh. </b>Click refresh to update the current display.
+</p>
+<p class="text">
+<a name="28978"> </a>
+<b>Continuous refresh. </b>Select this checkbox to continuously update the information display.
+</p>
+<p class="text">
+<a name="28979"> </a>
+<b>Summary Information. </b>This table provides the following information:
+</p>
+<ul>
+
+<li>
+Read-only status. Indicates whether the database is currently in read-only mode.
+<a name="28980"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Entry cache hits. Indicates the number of times the server could process a search request by obtaining data from the cache rather than by going to the disk.
+<a name="28981"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Entry cache tries. The total number of search operations performed against your server since server startup.
+<a name="28982"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Entry cache hit ratio. The ratio of entry cache tries to successful entry cache lookups. The closer this number is to 100% the better.
+<a name="28983"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Current size of entry cache (in bytes). Total number of bytes currently used by the entry cache.
+<a name="28984"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Maximum size of entry cache (in bytes). Maximum number of bytes available to the entry cache.
+<a name="28985"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="28986"> </a>
+<b>Index Information. </b>These tables provide information about the indexes you use for each database. The tables contain the following information:
+</p>
+<ul>
+
+<li>
+Cache hits. Indicates the number of times the server could process a request by obtaining data from the cache rather than by going to the disk.
+<a name="28987"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Cache misses. Number of times the cache does not contain the information being requested by the client application.
+<a name="28988"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Pages read in. Number of pages read from disk into the database cache.
+<a name="28989"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+Pages written out. Number of pages written from the cache back to disk.
+<a name="28990"> </a>
+<img src="/manual/en/slapd/help/pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="h2">
+<a name="28991"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28997"> </a>
+<a href="../en/slapd/ag/dsstats.htm#1028885">Monitoring Database Activity From the Server Console</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/statustab_replication.htm b/ldap/docs/dirhlp/help/statustab_replication.htm
new file mode 100644
index 00000000..4f2ac1de
--- /dev/null
+++ b/ldap/docs/dirhlp/help/statustab_replication.htm
@@ -0,0 +1,213 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:33" />
+<title>Netscape Directory Server Help: Replication Status</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28893"> </a>
+<a name="Replication Status"> </a>
+Replication Status
+</p>
+
+<p class="text">
+<a name="28895"> </a>
+Use this tab to view status about replication agreements configured for the server. You can also use this tab to see the progress of consumer initialization for a particular replication agreement.
+</p>
+<p class="text">
+<a name="28896"> </a>
+<b>Refresh.</b> Refreshes the display.
+</p>
+<p class="text">
+<a name="28897"> </a>
+<b>Continuous refresh. </b>Select this checkbox to provide continuously updated status.
+</p>
+<p class="text">
+<a name="28898"> </a>
+<b>Agreement table. </b>This table contains the name you provided when you set up the replication agreement, the suffix being replicated, and the identity of the consumer server. Select an agreement in the table, and its status is shown in the table below.
+</p>
+<p class="text">
+<a name="28899"> </a>
+<b>Replica suffix.</b> Specifies the subtree contained by this replica.
+</p>
+<p class="text">
+<a name="28900"> </a>
+<b>Consumer. </b>Specifies the consumer server in the agreement.
+</p>
+<p class="text">
+<a name="28901"> </a>
+<b>Supplier.</b> Specifies the supplier server in the agreement.
+</p>
+<p class="text">
+<a name="28902"> </a>
+<b>Number of changes. </b>Indicates the number of successfully replicated changes and the number of changes currently in the changelog. For example: <code>[7] - [10]</code> indicates that seven (7) changes have been successfully replicated and that ten (10) changes are listed in the changelog as needing updating.
+</p>
+<p class="text">
+<a name="28903"> </a>
+"Unknown" indicates that the server has encountered an error and replication cannot continue or the server could not read the last change number from the supplier.
+</p>
+<p class="text">
+<a name="28904"> </a>
+These errors may not indicate a true error condition if no changes have occurred on the supplier or if the consumer has not been initialized.
+</p>
+<p class="text">
+<a name="28905"> </a>
+<b>Last replica update began.</b> Specifies the time at which the last replication operation began.
+</p>
+<p class="text">
+<a name="28906"> </a>
+<b>Last replica update ended.</b> Specifies the time at which the last replication operation ended.
+</p>
+<p class="text">
+<a name="28907"> </a>
+<b>Last update message. </b>Gives the last replication update message received by the server.
+</p>
+<p class="text">
+<a name="28908"> </a>
+<b>Consumer initialization.</b> Indicates whether consumer initialization is in progress.
+</p>
+<p class="text">
+<a name="28909"> </a>
+<b>Last consumer init. update message.</b> Gives the last consumer initialization update message received by the server.
+</p>
+<p class="text">
+<a name="28910"> </a>
+<b>Last consumer initialization began.</b> Specifies the time at which the last consumer initialization operation began.
+</p>
+<p class="text">
+<a name="28911"> </a>
+<b>Last consumer initialization ended. </b>Specifies the time at which the last consumer initialization operation ended.
+</p>
+<p class="h2">
+<a name="28912"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="28915"> </a>
+<a href="../en/slapd/ag/replicat.htm#1032851">Monitoring Replication Status</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/taskstab_bkup_restore.htm b/ldap/docs/dirhlp/help/taskstab_bkup_restore.htm
new file mode 100644
index 00000000..27ad6989
--- /dev/null
+++ b/ldap/docs/dirhlp/help/taskstab_bkup_restore.htm
@@ -0,0 +1,165 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:02" />
+<title>Netscape Directory Server Help: Backup Directory Dialog Box</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="28234"> </a>
+<a name="Backup Directory Dialog Box"> </a>
+Backup Directory Dialog Box
+</p>
+
+<p class="text">
+<a name="15249"> </a>
+Use this dialog box to create a backup of your directory.
+</p>
+<p class="text">
+<a name="15250"> </a>
+<b>Directory.</b> Enter the full path of the directory where you want the server to store the backup file, or click Browse to browse to an existing directory.
+</p>
+<p class="text">
+<a name="15252"> </a>
+<b>Use default.</b> Click this button if you want the server to suggest a path for you. If you choose this option, the server stores the backup file in:
+</p>
+<p class="text">
+<a name="15254"> </a>
+<span class="variable">serverRoot</span><code>/slapd-</code><span class="variable">serverID</span><code>/bak/</code><span class="variable">backup_directory</span>
+</p>
+<p class="text">
+<a name="15255"> </a>
+where <span class="variable">backup_directory</span> specifies a directory using the name of the backup file. By default, the backup name contains the time and date when the backup was created.
+</p>
+<p class="h2">
+<a name="26993"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="26996"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1055147">Backing Up Data</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/taskstab_bkup_restore2.htm b/ldap/docs/dirhlp/help/taskstab_bkup_restore2.htm
new file mode 100644
index 00000000..e2c28fe2
--- /dev/null
+++ b/ldap/docs/dirhlp/help/taskstab_bkup_restore2.htm
@@ -0,0 +1,157 @@
+<html>
+
+
+<!--This html file is XHTML complaint, as set forth in the
+w3c recommendations except for the following:
+Lists work as they do in older versions on HTML and not as
+directed in XHTML.
+The <a name=" "> tags have targets that use spaces. -->
+
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="09/08/03 17:36:02" />
+<title>Netscape Directory Server Help: Restore Directory</title>
+
+
+<!--The following is a javascript which determines whether the client
+is on a Windows machine, or is on another type of operating system. Once
+the operating system is determined, either a windows or other operating
+system cascading style sheet is used. -->
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="h1">
+<a name="26997"> </a>
+<a name="Restore Directory"> </a>
+Restore Directory
+</p>
+
+<p class="text">
+<a name="15275"> </a>
+Use this dialog box to restore your directory from a previously created backup. Directory Server must be shut down before you can restore it from a backup. Restoring your database overwrites any existing database files.
+</p>
+<p class="text">
+<a name="15276"> </a>
+<b>Available backups.</b> The Console lists all backups in the default directory (<span class="variable">serverRoot</span><code>/slapd-</code><span class="variable">serverID</span><code>/bak/</code><span class="variable">backup_directory</span>) in this list box.
+</p>
+<p class="text">
+<a name="15278"> </a>
+<b>Directory.</b> If no backups appear in the Available Backups list, enter the full path to a location containing a valid backup.
+</p>
+<p class="h2">
+<a name="15280"> </a>
+<a name="See also"> </a>
+See also
+</p>
+
+
+<p class="text">
+<a name="15284"> </a>
+<a href="../en/slapd/ag/dbmanage.htm#1055147">Restoring Data</a>
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+
+
+
+
+
+<span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>September 08, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/help/topics.htm b/ldap/docs/dirhlp/help/topics.htm
new file mode 100644
index 00000000..be407999
--- /dev/null
+++ b/ldap/docs/dirhlp/help/topics.htm
@@ -0,0 +1,531 @@
+<html>
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="04/29/03 15:35:31" />
+<title>Netscape Directory Server Help: </title>
+
+<script type="text/JavaScript" src="/manual/en/slapd/help/sniffer.js">
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="/manual/en/slapd/help/netscape32.gif" height="32" width="32" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="product">Netscape Directory Server</span>
+<span class="booktitle">Console Help</span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+
+
+
+ <span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="title">
+<a name="318"> </a>
+<a name="Topics"> </a>
+Topics
+</p>
+<br /><p class="tochead1"><a name="2873"> </a>
+
+<a style="text-decoration: none" href="helpmenu.htm#29102">Confirmation Preferences
+
+</a>
+</p><p class="tochead1"><a name="2875"> </a>
+
+<a style="text-decoration: none" href="taskstab_bkup_restore.htm#28234">Backup Directory Dialog Box
+
+</a>
+</p><p class="tochead1"><a name="2877"> </a>
+
+<a style="text-decoration: none" href="taskstab_bkup_restore2.htm#26997">Restore Directory
+
+</a>
+</p><p class="tochead1"><a name="2879"> </a>
+
+<a style="text-decoration: none" href="configtab_rootnode.htm#28258">Settings Tab
+
+</a>
+</p><p class="tochead1"><a name="2881"> </a>
+
+<a style="text-decoration: none" href="configtab_rootnode2.htm#25226">Performance Tab
+
+</a>
+</p><p class="tochead1"><a name="2883"> </a>
+
+<a style="text-decoration: none" href="configtab_rootnode3.htm#25232">Encryption Tab
+
+</a>
+</p><p class="tochead1"><a name="2885"> </a>
+
+<a style="text-decoration: none" href="configtab_rootnode4.htm#13688">Cipher Settings
+
+</a>
+</p><p class="tochead1"><a name="2887"> </a>
+
+<a style="text-decoration: none" href="configtab_rootnode5.htm#14821">SNMP Tab
+
+</a>
+</p><p class="tochead1"><a name="2889"> </a>
+
+<a style="text-decoration: none" href="configtab_rootnode6.htm#13690">Manager Tab
+
+</a>
+</p><p class="tochead1"><a name="2891"> </a>
+
+<a style="text-decoration: none" href="configtab_db.htm#28605">Indexes
+
+</a>
+</p><p class="tochead1"><a name="2893"> </a>
+
+<a style="text-decoration: none" href="configtab_db2.htm#28623">Passwords Tab
+
+</a>
+</p><p class="tochead1"><a name="2895"> </a>
+
+<a style="text-decoration: none" href="configtab_db3.htm#28646">Account Lockout Tab
+
+</a>
+</p><p class="tochead1"><a name="2897"> </a>
+
+<a style="text-decoration: none" href="configtab_db4.htm#28686">Select Attribute
+
+</a>
+</p><p class="tochead1"><a name="2899"> </a>
+
+<a style="text-decoration: none" href="configtab_db5.htm#28697">Database Settings
+
+</a>
+</p><p class="tochead1"><a name="2901"> </a>
+
+<a style="text-decoration: none" href="configtab_db6.htm#28726">Import Database
+
+</a>
+</p><p class="tochead1"><a name="2903"> </a>
+
+<a style="text-decoration: none" href="configtab_db7.htm#28745">Import
+
+</a>
+</p><p class="tochead1"><a name="2905"> </a>
+
+<a style="text-decoration: none" href="configtab_db8.htm#28766">Initialize Database
+
+</a>
+</p><p class="tochead1"><a name="2907"> </a>
+
+<a style="text-decoration: none" href="configtab_db9.htm#28801">Export Databases
+
+</a>
+</p><p class="tochead1"><a name="2909"> </a>
+
+<a style="text-decoration: none" href="configtab_db10.htm#28833">Export Single Database
+
+</a>
+</p><p class="tochead1"><a name="2911"> </a>
+
+<a style="text-decoration: none" href="configtab_db11.htm#28855">LDBM Plug-in Settings
+
+</a>
+</p><p class="tochead1"><a name="2913"> </a>
+
+<a style="text-decoration: none" href="configtab_db12.htm#28871">Default Indexes
+
+</a>
+</p><p class="tochead1"><a name="2915"> </a>
+
+<a style="text-decoration: none" href="configtab_chaindb.htm#28932">Create New Database Link
+
+</a>
+</p><p class="tochead1"><a name="2917"> </a>
+
+<a style="text-decoration: none" href="configtab_chaindb2.htm#28956">Database Link Settings
+
+</a>
+</p><p class="tochead1"><a name="2919"> </a>
+
+<a style="text-decoration: none" href="configtab_chaindb3.htm#28992">Select Controls to Add
+
+</a>
+</p><p class="tochead1"><a name="2921"> </a>
+
+<a style="text-decoration: none" href="configtab_chaindb4.htm#29064">Select Components to Add
+
+</a>
+</p><p class="tochead1"><a name="2923"> </a>
+
+<a style="text-decoration: none" href="configtab_chaindb5.htm#29141">Default Creation Parameters
+
+</a>
+</p><p class="tochead1"><a name="2925"> </a>
+
+<a style="text-decoration: none" href="configtab_chaindb6.htm#29183">Database Link Limits and Controls
+
+</a>
+</p><p class="tochead1"><a name="2927"> </a>
+
+<a style="text-decoration: none" href="configtab_chaindb7.htm#29213">Database Link Authentication
+
+</a>
+</p><p class="tochead1"><a name="2929"> </a>
+
+<a style="text-decoration: none" href="configtab_ldbmdb.htm#28655">Create New Database
+
+</a>
+</p><p class="tochead1"><a name="2931"> </a>
+
+<a style="text-decoration: none" href="configtab_maptree.htm#28692">Suffix Settings
+
+</a>
+</p><p class="tochead1"><a name="2933"> </a>
+
+<a style="text-decoration: none" href="configtab_maptree2.htm#28712">Database List
+
+</a>
+</p><p class="tochead1"><a name="2935"> </a>
+
+<a style="text-decoration: none" href="configtab_maptree3.htm#28722">Databases
+
+</a>
+</p><p class="tochead1"><a name="2937"> </a>
+
+<a style="text-decoration: none" href="configtab_maptree4.htm#28744">Referrals
+
+</a>
+</p><p class="tochead1"><a name="2939"> </a>
+
+<a style="text-decoration: none" href="configtab_maptree5.htm#28777">Creating a New Root Suffix
+
+</a>
+</p><p class="tochead1"><a name="2941"> </a>
+
+<a style="text-decoration: none" href="configtab_maptree6.htm#28797">Creating a New Sub Suffix
+
+</a>
+</p><p class="tochead1"><a name="2943"> </a>
+
+<a style="text-decoration: none" href="configtab_maptree7.htm#28816">Remove Suffix
+
+</a>
+</p><p class="tochead1"><a name="2945"> </a>
+
+<a style="text-decoration: none" href="configtab_schema.htm#28692">Object Classes
+
+</a>
+</p><p class="tochead1"><a name="2947"> </a>
+
+<a style="text-decoration: none" href="configtab_schema2.htm#28714">Create Object Class
+
+</a>
+</p><p class="tochead1"><a name="2949"> </a>
+
+<a style="text-decoration: none" href="configtab_schema3.htm#28752">Attributes
+
+</a>
+</p><p class="tochead1"><a name="2951"> </a>
+
+<a style="text-decoration: none" href="configtab_schema4.htm#28786">Create Attribute Dialog Box
+
+</a>
+</p><p class="tochead1"><a name="2953"> </a>
+
+<a style="text-decoration: none" href="configtab_schema5.htm#28811">Matching Rules
+
+</a>
+</p><p class="tochead1"><a name="2955"> </a>
+
+<a style="text-decoration: none" href="configtab_replication.htm#28709">Legacy Consumer Settings
+
+</a>
+</p><p class="tochead1"><a name="2957"> </a>
+
+<a style="text-decoration: none" href="configtab_replication2.htm#28736">Supplier Settings
+
+</a>
+</p><p class="tochead1"><a name="2959"> </a>
+
+<a style="text-decoration: none" href="configtab_replication3.htm#28757">Replica Settings
+
+</a>
+</p><p class="tochead1"><a name="2961"> </a>
+
+<a style="text-decoration: none" href="configtab_replication4.htm#28816">Replication Summary
+
+</a>
+</p><p class="tochead1"><a name="2963"> </a>
+
+<a style="text-decoration: none" href="configtab_replication5.htm#28832">Replication Schedule
+
+</a>
+</p><p class="tochead1"><a name="2965"> </a>
+
+<a style="text-decoration: none" href="configtab_replication6.htm#28845">Replication Connection
+
+</a>
+</p><p class="tochead1"><a name="2967"> </a>
+
+<a style="text-decoration: none" href="configtab_replication7.htm#28877">Consumer Server Information
+
+</a>
+</p><p class="tochead1"><a name="2969"> </a>
+
+<a style="text-decoration: none" href="configtab_replication8.htm#28889">Export Replica
+
+</a>
+</p><p class="tochead1"><a name="2971"> </a>
+
+<a style="text-decoration: none" href="configtab_logs.htm#28733">Access Log
+
+</a>
+</p><p class="tochead1"><a name="2973"> </a>
+
+<a style="text-decoration: none" href="configtab_logs2.htm#28758">Error Log
+
+</a>
+</p><p class="tochead1"><a name="2975"> </a>
+
+<a style="text-decoration: none" href="configtab_logs3.htm#28804">Audit Log
+
+</a>
+</p><p class="tochead1"><a name="2977"> </a>
+
+<a style="text-decoration: none" href="configtab_plugins.htm#28742">Plug-ins
+
+</a>
+</p><p class="tochead1"><a name="2979"> </a>
+
+<a style="text-decoration: none" href="replication_wizard.htm#28757">Source and Destination
+
+</a>
+</p><p class="tochead1"><a name="2981"> </a>
+
+<a style="text-decoration: none" href="replication_wizard2.htm#28780">Schedule Replication
+
+</a>
+</p><p class="tochead1"><a name="2983"> </a>
+
+<a style="text-decoration: none" href="replication_wizard3.htm#28793">Initialize Consumer
+
+</a>
+</p><p class="tochead1"><a name="2985"> </a>
+
+<a style="text-decoration: none" href="replication_wizard4.htm#28828">Summary Dialog
+
+</a>
+</p><p class="tochead1"><a name="2987"> </a>
+
+<a style="text-decoration: none" href="replication_wizard5.htm#28839">Replication Agreement Name
+
+</a>
+</p><p class="tochead1"><a name="2989"> </a>
+
+<a style="text-decoration: none" href="dirtab_role.htm#28778">Add New Filtered Role Member
+
+</a>
+</p><p class="tochead1"><a name="2991"> </a>
+
+<a style="text-decoration: none" href="dirtab_role2.htm#28805">Add New Managed Role Member
+
+</a>
+</p><p class="tochead1"><a name="2993"> </a>
+
+<a style="text-decoration: none" href="dirtab_role3.htm#28824">Add New Nested Role Member
+
+</a>
+</p><p class="tochead1"><a name="2995"> </a>
+
+<a style="text-decoration: none" href="dirtab_role4.htm#28843">Role Accounts Tab
+
+</a>
+</p><p class="tochead1"><a name="2997"> </a>
+
+<a style="text-decoration: none" href="dirtab_role5.htm#28875">General Tab
+
+</a>
+</p><p class="tochead1"><a name="2999"> </a>
+
+<a style="text-decoration: none" href="dirtab_role6.htm#28894">Set Role
+
+</a>
+</p><p class="tochead1"><a name="3001"> </a>
+
+<a style="text-decoration: none" href="dirtab_role7.htm#28910">Role Selector
+
+</a>
+</p><p class="tochead1"><a name="3003"> </a>
+
+<a style="text-decoration: none" href="dirtab_cos.htm#28794">Attribute
+
+</a>
+</p><p class="tochead1"><a name="3005"> </a>
+
+<a style="text-decoration: none" href="dirtab_cos2.htm#28813">Create New Class of Service
+
+</a>
+</p><p class="tochead1"><a name="3007"> </a>
+
+<a style="text-decoration: none" href="dirtab_cos3.htm#28832">Template
+
+</a>
+</p><p class="tochead1"><a name="3009"> </a>
+
+<a style="text-decoration: none" href="statustab_replication.htm#28893">Replication Status
+
+</a>
+</p><p class="tochead1"><a name="3011"> </a>
+
+<a style="text-decoration: none" href="statustab_logs.htm#28880">Access Log Status
+
+</a>
+</p><p class="tochead1"><a name="3013"> </a>
+
+<a style="text-decoration: none" href="statustab_logs2.htm#28897">Error Log Status
+
+</a>
+</p><p class="tochead1"><a name="3015"> </a>
+
+<a style="text-decoration: none" href="statustab_logs3.htm#28912">Audit Log Status
+
+</a>
+</p><p class="tochead1"><a name="3017"> </a>
+
+<a style="text-decoration: none" href="statustab_performance.htm#28905">Server Performance Counters
+
+</a>
+</p><p class="tochead1"><a name="3019"> </a>
+
+<a style="text-decoration: none" href="statustab_performance2.htm#28972">Database Performance Counter
+
+</a>
+</p><p class="tochead1"><a name="3021"> </a>
+
+<a style="text-decoration: none" href="statustab_general.htm#28922">Directory Server Status
+
+</a>
+</p><p class="tochead1"><a name="3023"> </a>
+
+<a style="text-decoration: none" href="property_editor.htm#28980">Property Editor
+
+</a>
+</p><p class="tochead1"><a name="3025"> </a>
+
+<a style="text-decoration: none" href="property_editor2.htm#29006">Add Object Class
+
+</a>
+</p><p class="tochead1"><a name="3027"> </a>
+
+<a style="text-decoration: none" href="property_editor3.htm#29017">Add Attribute
+
+</a>
+</p><p class="tochead1"><a name="3029"> </a>
+
+<a style="text-decoration: none" href="property_editor4.htm#29052">Add New Object
+
+</a>
+</p><p class="tochead1"><a name="3031"> </a>
+
+<a style="text-decoration: none" href="ldapurl.htm#28974">Construct LDAP URL
+
+</a>
+</p><p class="tochead1"><a name="3033"> </a>
+
+<a style="text-decoration: none" href="account_mgmt.htm#26399">User Account
+
+</a>
+</p><p class="tochead1"><a name="3035"> </a>
+
+<a style="text-decoration: none" href="adv_search.htm#26445">Advanced Search
+
+</a>
+</p><p class="tochead1"><a name="3037"> </a>
+
+<a style="text-decoration: none" href="new_instance.htm#28957">New Server Instance
+
+</a>
+</p><p class="tochead1"><a name="3039"> </a>
+
+<a style="text-decoration: none" href="dir_browser.htm#25216">Directory Browser
+
+</a>
+</p>
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+
+
+
+ <span class="navigation">
+<a style="text-decoration: none; color:#006666" href="/manual/en/slapd/index.htm">
+DocHome
+</a>
+</span>
+&nbsp;&nbsp;&nbsp;&nbsp;
+
+
+
+
+<hr noshade="noshade" size="1" />
+<p class="copy">&copy; 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2003 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>April 29, 2003</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html> \ No newline at end of file
diff --git a/ldap/docs/dirhlp/index.htm b/ldap/docs/dirhlp/index.htm
new file mode 100644
index 00000000..3c0813d4
--- /dev/null
+++ b/ldap/docs/dirhlp/index.htm
@@ -0,0 +1,297 @@
+<html>
+
+<head>
+<meta name="keywords" content="e-commerce, ecommerce, Netscape, Internet software, e-commerce applications, electronic commerce, ebusiness, e-business, enterprise software, net economy, software, ecommerce solutions, e-commerce services, AOL, America Online, netscape software, netscape solutions, marketplace, digital marketplace" />
+<meta name="description" content="Netscape, an AOL Time Warner Company, produces the world renowned
+Netscape Browser as well as top notch server software." />
+<meta http-equiv="content-type" content="text/html; charset=ISO-8859-1" />
+<meta name="templatebase" content="Authored in FrameMaker. Converted to HTML in WebWorks Publisher. manual wdt 1.6" />
+<meta name="LASTUPDATED" content="02/09/03 00:59:06" />
+<title>Netscape Directory Server Documentation Resources: </title>
+
+<script type="text/JavaScript">
+
+<!-- Start hiding
+
+window.onerror=null;
+var client=navigator.userAgent.toLowerCase();
+
+var WinStyle = "<STYLE NAME=WINDOWS>\n" +
+"body,p {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 10; margin-top: 0; } \n" +
+"th,tr,td,br,li,dl,dd,ul,ol,li {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; } \n" +
+".booktitle {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: bold; margin-bottom: 0; margin-top: 0; font-size:18pt;} \n" +
+".callout {font-family: verdana,helvetica,arial,sans-serif; font-size: 8pt;} \n" +
+".calloutlarge {font-family: verdana,helvetica,arial,sans-serif; font-size: 9pt;} \n" +
+".calloutlargebold {font-family: verdana,helvetica,arial,sans-serif; font-size: 9pt; font-weight: bold;} \n" +
+".calloutsmall {font-family: verdana,helvetica,arial,sans-serif; font-size: 7pt; font-weight: normal;} \n" +
+".caption {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 5; margin-top: 10; font-size: 10pt;} \n" +
+".caution {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; font-weight: bold; margin-bottom: 0; margin-top: 0; } \n" +
+"code {font-family: courier,couriernew,monospaced; font-size: 10pt; margin-bottom: 0; margin-bottom:0; margin-top: 0;} \n" +
+".code {font-family: courier,couriernew,monospaced; font-size:10pt; margin-bottom: 10; margin-top: 0; } \n" +
+".copy {font-family: verdana,helvetica,arial,sans-serif; font-size:8pt; margin-bottom: 0; margin-top: 0;} \n" +
+".footnote {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; } \n" +
+".gloss {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 10; margin-top: 0; } \n" +
+".grouptitleix {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 20pt; font-size: 14pt;} \n" +
+".h1 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 0; margin-top: 30pt; font-size: 16pt;} \n" +
+".h2 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 30pt; font-size: 14pt;} \n" +
+".h3 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 20pt; font-size: 12pt;} \n" +
+".h4 {font-family: verdana,helvetica,arial,sans-serif; font-style: italic; font-color: black;margin-bottom: 0; margin-top: 16pt; font-size: 11pt;} \n" +
+".h5 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 0; margin-top: 0; font-size: 8pt;} \n" +
+".navigation {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: #006666; margin-bottom: 0; margin-top: 0; font-size:10pt;} \n" +
+".note {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; font-weight: bold; margin-bottom: 0; margin-top: 0; } \n" +
+"pre {font-family: courier,couriernew,monospaced; font-size: 10pt; margin-bottom: 0; } \n" +
+".product {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: normal; margin-bottom: 0; margin-top: 0; font-size:18pt;} \n" +
+".refhead {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 4; margin-top: 15pt; font-size: 11pt;} \n" +
+".tabletext {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 6; margin-top: 0; } \n" +
+".tabletextright {align: right; valign: top; font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 6; margin-top: 0; } \n" +
+".tablehead {text-align: left;font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; font-size:10pt; margin-bottom: 4; margin-top: 0; } \n" +
+".text {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 16; margin-top: 0; } \n" +
+".tip {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; font-weight: bold; margin-bottom: 0; margin-top: 0; } \n" +
+".title {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black;margin-bottom: 30pt; margin-top: 16pt; font-size: 16pt;} \n" +
+".toc1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tocc {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt; font-weight: bold; margin-bottom: 0; margin-top: 7; margin-left: 30;} \n" +
+".tocg {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tochead1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 30;} \n" +
+".tochead2 {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 60;} \n" +
+".tochead3 {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 90;} \n" +
+".tocnontoc {font-family: verdana,helvetica,arial,sans-serif; font-size: 10pt; font-weight: normal; margin-left: 0;} \n" +
+".tocpart {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; font-weight: bold; margin-bottom: 0; margin-top: 20;} \n" +
+".update {text-align: right; font-family: verdana,helvetica,arial,sans-serif; font-size:8pt; margin-bottom: 0; margin-top: 0; margin-right: 20pt;} \n" +
+".variable {font-family: palatino, times, serif; font-style: italic;} \n" +
+"</style>";
+
+var OtherStyle = "<style name=NOTWINDOWS>\n" +
+"body,p {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 0; margin-top: 14; } \n" +
+"th,tr,td,br,li,dl,dd,ul,ol,li {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; } \n" +
+".booktitle {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: bold; margin-bottom: 0; margin-top: 0; font-size: 23pt;} \n" +
+".callout {font-family: verdana,helvetica,arial,sans-serif; font-size: 11pt;} \n" +
+".calloutlarge {font-family: verdana,helvetica,arial,sans-serif; font-size: 12pt;} \n" +
+".calloutlargebold {font-family: verdana,helvetica,arial,sans-serif; font-size: 12pt; font-weight: bold;} \n" +
+".calloutsmall {font-family: verdana,helvetica,arial,sans-serif; font-size: 9pt; font-weight: normal;} \n" +
+".caption {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 5; margin-top: 16; font-size: 13pt;} \n" +
+".caution {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; font-weight: bold; margin-bottom: 0; margin-top: 14; } \n" +
+"code {font-family: courier,couriernew,monospaced; font-size: 13pt; margin-bottom: 0; margin-bottom:0; margin-top: 0;} \n" +
+".code {font-family: courier,couriernew,monospaced; font-size:13pt; margin-bottom: 0; margin-top: 13; } \n" +
+".copy {font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 0; margin-top: 0;} \n" +
+".footnote {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; } \n" +
+".gloss {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 14; margin-top: 14; } \n" +
+".grouptitleix {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 20pt; font-size: 19pt;} \n" +
+".h1 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 0; margin-top: 35pt; font-size: 21pt;} \n" +
+".h2 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 35pt; font-size: 18pt;} \n" +
+".h3 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 10; margin-top: 25pt; font-size: 14pt;} \n" +
+".h4 {font-family: verdana,helvetica,arial,sans-serif; font-style: italic; font-color: black;margin-bottom: 0; margin-top: 22pt; font-size: 13pt;} \n" +
+".h5 {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 0; margin-top: 16; font-size: 13pt;} \n" +
+".navigation {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: #006666; margin-bottom: 0; margin-top: 0; font-size:14pt;} \n" +
+".note {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; font-weight: bold; margin-bottom: 0; margin-top: 14; } \n" +
+"pre {font-family: courier,couriernew,monospaced; font-size: 13pt; margin-bottom: 0; } \n" +
+".product {color: #666666; font-family: timesnewroman,times,palatino,serif; font-weight: normal; margin-bottom: 0; margin-top: 0; font-size: 23pt;} \n" +
+".refhead {font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; color: black; margin-bottom: 4; margin-top: 20pt; font-size: 13pt;} \n" +
+".tabletext {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 4; margin-top: 6; } \n" +
+".tabletextright {align: right; valign: top; font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 4; margin-top: 6; } \n" +
+".tablehead {text-align: left;font-family: verdana,helvetica,arial,sans-serif; font-weight: bold; font-size:13pt; margin-bottom: 4; margin-top: 0; } \n" +
+".text {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; margin-bottom: 8; margin-top: 14; } \n" +
+".tip {font-family: verdana,helvetica,arial,sans-serif; font-size:13pt; font-weight: bold; margin-bottom: 0; margin-top: 14; } \n" +
+".title {font-family: verdana,helvetica,arial,sans-serif; font-weight: normal; color: black; margin-bottom: 30pt; margin-top: 16pt; font-size: 21pt;} \n" +
+".toc1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 14pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tocc {font-family: verdana,helvetica,arial,sans-serif; font-size: 14pt; font-weight: bold; margin-bottom: 0; margin-top: 7; margin-left: 30;} \n" +
+".tocg {font-family: verdana,helvetica,arial,sans-serif; font-size: 14pt; font-weight: bold; margin-bottom: 0; margin-top: 30; margin-left: 30;} \n" +
+".tochead1 {font-family: verdana,helvetica,arial,sans-serif; font-size: 13pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 30;} \n" +
+".tochead2 {font-family: verdana,helvetica,arial,sans-serif; font-size: 13pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 60;} \n" +
+".tochead3 {font-family: verdana,helvetica,arial,sans-serif; font-size: 13pt; font-weight: normal; margin-bottom: 0; margin-top: 2; margin-left: 90;} \n" +
+".tocnontoc {font-family: verdana,helvetica,arial,sans-serif; font-size: 13pt; font-weight: normal; text-indent: 0;} \n" +
+".tocpart {font-family: verdana,helvetica,arial,sans-serif; font-size:16pt; font-weight: bold; margin-bottom: 0; margin-top: 20;} \n" +
+".update {text-align: right; font-family: verdana,helvetica,arial,sans-serif; font-size:10pt; margin-bottom: 0; margin-top: 0; margin-right: 20pt;} \n" +
+".variable {font-family: palatino, times, serif; font-style: italic;} \n" +
+"</style>";
+if ( client.indexOf("win") != -1 ){
+ document.write( WinStyle );
+}else{
+ document.write( OtherStyle );
+}
+
+// End hiding -->
+
+</script>
+
+
+</head>
+
+
+
+
+<body text="#000000" link="#006666" vlink="#006666" alink="#333366" bgcolor="#FFFFFF">
+
+
+<!--maincontent defines everything between the body tags -->
+<!--start maincontent-->
+
+<!--navigationcontent defines the top row of links and the banner -->
+<!--start navigationcontent-->
+
+<table border="0" cellspacing="0" cellpadding="0" width="100%">
+<tr>
+<td><table border="0" cellspacing="0" cellpadding="0">
+<tr>
+<td valign="bottom" width="67">
+<img src="netscape48.gif" height="48" width="48" border="0" alt="Netscape logo" />
+</td>
+<td valign="middle">
+<span class="booktitle">Documentation Resources</span><br />
+<span class="product"><i>Netscape Directory Server</i></span>
+</td>
+</tr>
+</table>
+</td>
+</tr>
+
+<tr>
+<td>
+<hr size="1" noshade="noshade" />
+</td>
+</tr>
+</table>
+
+<!--end navigationcontent-->
+
+<!--bookcontent defines the actual content of the file, sans headers and footers -->
+<!--start bookcontent-->
+
+<blockquote>
+<br />
+<p class="text">
+<a name="21251"> </a>
+The list of documentation installed with your Netscape Directory Server (Directory Server) is as follows:
+</p>
+<ul>
+
+<li>
+<a href="index.htm#21483" >Netscape Directory Server Documentation</a>
+<a name="21517"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<a href="index.htm#19516" >Netscape Console Documentation</a>
+<a name="21324"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="21320"> </a>
+From time to time, the documentation for Netscape servers is updated after the server is released. All server documentation that is shipped with the product is posted on the web site; check the Release Notes for this location.
+</p>
+<p class="text">
+<a name="21312"> </a>
+If updates do occur, they will be posted on the web site. Release Notes are updated fairly often, book files are updated every so often.
+</p>
+<p class="h2">
+<a name="21483"> </a>
+<a name="Netscape Directory Server Documentation"> </a>
+Netscape Directory Server Documentation
+</p>
+
+
+<ul>
+
+<li>
+<a href="deploy/contents.htm">Netscape Directory Server Deployment Guide</a>
+<a name="21486"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<a href="install/contents.htm">Netscape Directory Server Installation Guide</a>
+<a name="21489"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<a href="ag/contents.htm">Netscape Directory Server Administrator's Guide</a>
+<a name="21492"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<a href="cli/contents.htm">Netscape Directory Server Configuration, Command, and File Reference</a>
+<a name="21545"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<a href="schema/contents.htm">Netscape Directory Server Schema Reference</a>
+<a name="21571"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+<li>
+<a href="plugin/contents.htm">Netscape Directory Server Plug-in Programmer's Guide</a>
+<a name="21545"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+
+<li>
+<a href="orgchart/orgchart.html">Deploying Netscape Directory Server Org Chart</a>
+<a name="21545"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+
+<li>
+<a href="gwcust/contents.htm">Netscape Directory Server Gateway Customization Guide</a>
+<a name="21545"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+
+
+<li>
+<a href="dsmlgw/dsmlgw.htm">Netscape Directory Server DSML Gateway Guide</a>
+<a name="21545"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+
+
+
+</ul>
+
+
+<p class="h2">
+<a name="19516"> </a>
+<a name="Netscape Console Documentation"> </a>
+Netscape Console Documentation
+</p>
+
+
+<ul>
+
+<li>
+<a href="../admin/ag/contents.htm">Managing Servers with Netscape Console</a>
+<a name="21427"> </a>
+<img src="pixel.gif" align="top" height="22" alt="" />
+</li>
+</ul>
+<p class="text">
+<a name="21362"> </a>
+
+</p>
+
+</blockquote>
+<!--end bookcontent-->
+<!--footercontent defines the bottom navigation and the copyright. It also includes
+the revision date-->
+<!--start footercontent-->
+
+
+<br />
+<br />
+<hr noshade="noshade" size="1" />
+<p class="copy">Copyright © 2001 Sun Microsystems, Inc. Portions copyright 1999, 2002-2004 Netscape Communications Corporation. All rights reserved.</p>
+<br />
+<p class="update">Last Updated <b>October 14, 2004</b></p>
+
+
+<!--end footercontent-->
+<!--end maincontent-->
+</body>
+</html>
diff --git a/ldap/docs/dirhlp/index.map b/ldap/docs/dirhlp/index.map
new file mode 100644
index 00000000..80423185
--- /dev/null
+++ b/ldap/docs/dirhlp/index.map
@@ -0,0 +1,149 @@
+; PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+; license terms. Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+;
+;----------------------------------------------------------------------
+; Last update: 22 October 2001 by Tech Pubs
+;-------------------------------------------MAPPINGS
+; UI Reference Token = help/filename.htm
+;-------------------------------------------PROGRAMS
+;
+;MENU BAR
+;
+;Help Menu from all tabs
+tasks-menubar-help = ag/contents.htm
+preferences-confirmation-help = help/confirmation_preferences.htm
+
+;TASKS TAB
+tasks-backup-help = help/backup.htm
+tasks-restore-help = help/restore.htm
+
+
+;CONFIGURATION TAB
+;Root Node
+configuration-system-settings-help = help/settings.htm
+configuration-system-performance-help = help/performance.htm
+configuration-system-encryption-help = help/encryption.htm
+configuration-system-encryption-preferences-dbox-help = help/encryption_pref.htm
+configuration-system-snmp-help = help/snmp.htm
+configuration-system-manager-help = help/manager.htm
+
+;Database Icon
+configuration-database-indexes-help = help/indexes.htm
+configuration-database-passwords-help = help/passwords.htm
+configuration-database-accountlockout-help = help/account_lockout.htm
+configuration-database-indexes-add-dbox-help = help/index_attribute.htm
+configuration-database-settings-help = help/ldbm_instance_settings.htm
+configuration-database-import-ldap-dbox-help = help/import_ldap.htm
+configuration-database-import-fastwire-dbox-help = help/import_fastwire.htm
+configuration-database-initialize-backend-dbox-help = help/initialize_backend.htm
+configuration-database-export-dbox-help = help/export_general.htm
+configuration-database-export-single-dbox-help = help/export_single.htm
+configuration-database-plugin-setting-help = help/ldbm_plugin_settings.htm
+configuration-database-default-indexes-help = help/default_indexes.htm
+
+;Chaining Database Icon
+configuration-new-chaining-instance-dbox-help = help/new_chaining_be.htm
+configuration-chaining-settings-help = help/chaining_settings.htm
+configuration-chaining-settings-ctrl-chooser-dbox-help = help/chaining_controls.htm
+configuration-chaining-settings-comp-chooser-dbox-help = help/chaining_components.htm
+configuration-chaining-default-help = help/chaining_default.htm
+configuration-chaining-connection-help = help/chaining_connection.htm
+configuration-chaining-authentication-help = help/chaining_authentication.htm
+
+;LDBM Database Instance Icon
+configuration-new-ldbm-instance-dbox-help = help/new_ldbm_instance.htm
+
+;Mapping Tree
+configuration-mapping-settings-help = help/mapping_node_settings.htm
+configuration-mapping-add-backend-dbox-help = help/mapping_backend_add.htm
+configuration-mapping-database-help = help/mapping_database.htm
+configuration-mapping-referral-help = help/mapping_referrals.htm
+configuration-new-mapping-node-dbox-help = help/new_mapping_node.htm
+
+
+;Schema Icon
+configuration-schema-objclass-help = help/object_classes.htm
+configuration-schema-objclass-create-dbox-help = help/create_objclass.htm
+configuration-schema-attr-help = help/attributes.htm
+configuration-schema-attr-create-dbox-help = help/create_attributes.htm
+configuration-schema-mrule-help = help/matching_rules.htm
+
+;Replication Agreements Icon
+configuration-replication-legacyconsumersettings-help = help/legacy_consumer_settings.htm
+configuration-replication-suppliersettings-help = help/supplier_settings.htm
+configuration-replication-replicasettings-help = help/replica_settings.htm
+configuration-replication-summary-help = help/rep_summary.htm
+configuration-replication-schedule-help = help/schedule_rep.htm
+configuration-replication-content-help = help/rep_content.htm
+configuration-replication-host-dbox-help = help/consumer_server_info.htm
+
+;Logs Icon
+configuration-logs-access-help = help/access_log.htm
+configuration-logs-error-help = help/error_log.htm
+configuration-logs-audit-help = help/audit_log.htm
+
+;Plugins Icons
+configuration-plugins-help = help/plugins.htm
+
+
+;REPLICATION AGREEMENT WIZARD
+replication-wizard-content-help = help/rep_source_destination.htm
+replication-wizard-schedule-help = help/schedule_rep_wiz.htm
+replication-wizard-consumerinit-help = help/consumer_init.htm
+replication-wizard-summary-help = help/summary_wiz.htm
+replication-wizard-legacyrmmrname-help = help/rep_agreement_name.htm
+replication-wizard-cirsirselect-help = help/rep_select_wiz.htm
+replication-wizard-cirsirname-help = help/rep_name_wiz.htm
+replication-wizard-attribute-help = help/rep_attributes_wiz.htm
+
+
+;DIRECTORY TAB
+;Role Configuration
+configuration-role-member-filtered-help = help/new_filtered_member.htm
+configuration-role-member-managed-help = help/new_managed_member.htm
+configuration-role-member-nested-help = help/new_nested_member.htm
+configuration-role-account-help = help/role_accounts.htm
+configuration-role-info-help = help/create_new_role.htm
+configuration-set-role = help/set_role.htm
+configuration-choose-role = help/role_selector.htm
+
+;CoS Configuration
+configuration-cos-attributes-help = help/cos_attributes.htm
+configuration-cos-info-help = help/cos_info.htm
+configuration-cos-template-help = help/cos_template.htm
+
+;STATUS TAB
+;Replication Icon
+status-replication-help = help/replication_status.htm
+
+;Logs Icon
+status-logs-access-help = help/access_log_status.htm
+status-logs-error-help = help/error_log_status.htm
+status-logs-audit-help = help/audit_log_status.htm
+
+;Performance Counters Icon
+status-perfcounters-server-help = help/server_performance.htm
+status-perfcounters-database-help = help/database_performance.htm
+
+
+;PROPERTY EDITOR WINDOWS
+property-main-help = help/property_editor.htm
+property-new-objectclass-dbox-help = help/add_new_objclass.htm
+property-new-attribute-dbox-help = help/add_new_attribute.htm
+
+;LDAP URL Construction Dialog
+configuration-construct-new-url-dbox-help = help/construct_ldap_url.htm
+
+;Account Inactivation in Entry Edit Dialog
+configuration-user-account-help = help/
+
+;VERY ADVANCED SEARCH DIALOG BOX
+search-dbox-veryadvanced-help = help/advanced_search.htm
+
+;INSTALL
+menubar-newinstance-dbox-help = help/new_server_instance.htm
+
+; SUBTREE SELECTION DIALOG BOX
+subtree-selection-dbox-help = help/directory_browser.htm
diff --git a/ldap/docs/dirhlp/pixel.gif b/ldap/docs/dirhlp/pixel.gif
new file mode 100644
index 00000000..3ea701d9
--- /dev/null
+++ b/ldap/docs/dirhlp/pixel.gif
Binary files differ
diff --git a/ldap/docs/dirhlp/tokens.map b/ldap/docs/dirhlp/tokens.map
new file mode 100644
index 00000000..a018067f
--- /dev/null
+++ b/ldap/docs/dirhlp/tokens.map
@@ -0,0 +1,166 @@
+;-------------------------------------------------------------------------
+; PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+; license terms. Copyright © 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+;
+;-------------------------------------------------------------------------
+; Last update: 10 July 2003 by Tech Pubs
+;-------------------------------------------MAPPINGS
+; UI Reference Token = help/filename.htm
+;-------------------------------------------PROGRAMS
+;
+;MENU BAR
+;
+;Help Menu from all tabs
+framework-menubar-contents = help/redir_agtoc.htm
+preferences-confirmation-help = help/helpmenu.htm
+framework-menubar-dochome = help/redir_dochome.htm
+
+;TASKS TAB
+tasks-backup-help = help/taskstab_bkup_restore.htm
+tasks-restore-help = help/taskstab_bkup_restore2.htm
+
+
+;CONFIGURATION TAB
+;Root Node
+configuration-system-settings-help = help/configtab_rootnode.htm
+configuration-system-performance-help = help/configtab_rootnode2.htm
+configuration-system-encryption-help = help/configtab_rootnode3.htm
+configuration-system-snmp-help = help/configtab_rootnode5.htm
+configuration-system-manager-help = help/configtab_rootnode6.htm
+configuration-system-sasl-help = help/configtab_rootnode7.htm
+configuration-system-sasl-add-dbox-help = help/configtab_rootnode8.htm
+configuration-system-sasl-mod-dbox-help = help/configtab_rootnode9.htm
+
+;Database Icon
+configuration-database-indexes-help = help/configtab_db.htm
+configuration-database-passwords-help = help/configtab_db2.htm
+configuration-database-accountlockout-help = help/configtab_db3.htm
+configuration-database-indexes-add-dbox-help = help/configtab_db4.htm
+configuration-database-settings-help = help/configtab_db5.htm
+configuration-database-import-ldap-dbox-help = help/configtab_db6.htm
+configuration-database-import-fastwire-dbox-help = help/configtab_db7.htm
+configuration-database-initialize-backend-dbox-help = help/configtab_db8.htm
+configuration-database-export-dbox-help = help/configtab_db9.htm
+configuration-database-export-single-dbox-help = help/configtab_db10.htm
+configuration-database-plugin-setting-help = help/configtab_db11.htm
+configuration-database-default-indexes-help = help/configtab_db12.htm
+configuration-database-attrenc-help = help/configtab_db13.htm
+configuration-database-attrenc-add-dbox-help = help/configtab_db14.htm
+configuration-database-attrenc-method-select-dbox-help = help/configtab_db15.htm
+
+;Chaining Database Icon
+configuration-new-chaining-instance-dbox-help = help/configtab_chaindb.htm
+configuration-chaining-settings-help = help/configtab_chaindb2.htm
+configuration-chaining-settings-ctrl-chooser-dbox-help = help/configtab_chaindb3.htm
+configuration-chaining-settings-comp-chooser-dbox-help = help/configtab_chaindb4.htm
+configuration-chaining-default-help = help/configtab_chaindb5.htm
+configuration-chaining-connection-help = help/configtab_chaindb6.htm
+configuration-chaining-authentication-help = help/configtab_chaindb7.htm
+
+;LDBM Database Instance Icon
+configuration-new-ldbm-instance-dbox-help = help/configtab_ldbmdb.htm
+
+;Mapping Tree/Suffix
+configuration-mapping-setting-help = help/configtab_maptree.htm
+configuration-mapping-add-backend-dbox-help = help/configtab_maptree2.htm
+configuration-mapping-database-help = help/configtab_maptree3.htm
+configuration-mapping-referral-help = help/configtab_maptree4.htm
+configuration-new-mapping-node-dbox-help = help/configtab_maptree5.htm
+configuration-new-mapping-sub-suffix-dbox-help = help/configtab_maptree6.htm
+configuration-confirm-delete-suffix-dbox-help = help/configtab_maptree7.htm
+
+
+;Schema Icon
+configuration-schema-objclass-help = help/configtab_schema.htm
+configuration-schema-objclass-create-dbox-help = help/configtab_schema2.htm
+configuration-schema-attr-help = help/configtab_schema3.htm
+configuration-schema-attr-create-dbox-help = help/configtab_schema4.htm
+configuration-schema-mrule-help = help/configtab_schema5.htm
+
+;Replication Agreements Icon
+configuration-replication-legacyconsumersettings-help = help/configtab_replication.htm
+configuration-replication-suppliersettings-help = help/configtab_replication2.htm
+configuration-replication-replicasettings-help = help/configtab_replication3.htm
+configuration-replication-summary-help = help/configtab_replication4.htm
+configuration-replication-schedule-help = help/configtab_replication5.htm
+configuration-replication-content-help = help/configtab_replication6.htm
+configuration-replication-host-dbox-help = help/configtab_replication7.htm
+configuration-replication-export-help = help/configtab_replication8.htm
+
+;Logs Icon
+configuration-logs-access-help = help/configtab_logs.htm
+configuration-logs-error-help = help/configtab_logs2.htm
+configuration-logs-audit-help = help/configtab_logs3.htm
+
+;Plugins Icons
+configuration-plugins-help = help/configtab_plugins.htm
+
+
+;REPLICATION AGREEMENT WIZARD
+replication-wizard-content-help = help/replication_wizard.htm
+replication-wizard-schedule-help = help/replication_wizard2.htm
+replication-wizard-consumerinit-help = help/replication_wizard3.htm
+replication-wizard-summary-help = help/replication_wizard4.htm
+replication-wizard-legacyrmmrname-help = help/replication_wizard5.htm
+;replication-wizard-cirsirselect-help = help/replication_wizard6.htm
+;replication-wizard-cirsirname-help = help/replication_wizard7.htm
+
+
+;DIRECTORY TAB
+;Role Configuration
+configuration-role-member-filtered-help = help/dirtab_role.htm
+configuration-role-member-managed-help = help/dirtab_role2.htm
+configuration-role-member-nested-help = help/dirtab_role3.htm
+configuration-role-account-help = help/dirtab_role4.htm
+configuration-role-info-help = help/dirtab_role5.htm
+configuration-set-role = help/dirtab_role6.htm
+configuration-choose-role = help/dirtab_role7.htm
+
+;Fine-Grained Password Policy Configuration
+configuration-browser-passwords-help = help/dir_browser2.htm
+configuration-browser-accountlockout-help = help/dir_browser3.htm
+configuration-set-referral = help/dir_browser4.htm
+
+;CoS Configuration
+configuration-cos-attributes-help = help/dirtab_cos.htm
+configuration-cos-info-help = help/dirtab_cos2.htm
+configuration-cos-template-help = help/dirtab_cos3.htm
+
+;STATUS TAB
+;Replication Icon
+status-replication-help = help/statustab_replication.htm
+
+;Logs Icon
+status-logs-access-help = help/statustab_logs.htm
+status-logs-error-help = help/statustab_logs2.htm
+status-logs-audit-help = help/statustab_logs3.htm
+
+;Performance Counters Icon
+status-perfcounters-server-help = help/statustab_performance.htm
+status-perfcounters-database-help = help/statustab_performance2.htm
+
+;General Server Status
+status-server-general-help = help/statustab_general.htm
+
+;PROPERTY EDITOR WINDOWS
+property-main-help = help/property_editor.htm
+property-new-objectclass-dbox-help = help/property_editor2.htm
+property-new-attribute-dbox-help = help/property_editor3.htm
+property-main-create-help = help/property_editor4.htm
+
+;LDAP URL Construction Dialog
+configuration-construct-new-url-dbox-help = help/ldap_url.htm
+
+;Account Management Dialog
+configuration-user-account-help = help/account_mgmt.htm
+
+;VERY ADVANCED SEARCH DIALOG BOX
+search-dbox-veryadvanced-help = help/adv_search.htm
+
+;INSTALL
+menubar-newinstance-dbox-help = help/new_instance.htm
+
+; SUBTREE SELECTION DIALOG BOX
+subtree-selection-dbox-help = help/dir_browser.htm
diff --git a/ldap/docs/dirhlp/topicindex.htm b/ldap/docs/dirhlp/topicindex.htm
new file mode 100644
index 00000000..72f81a77
--- /dev/null
+++ b/ldap/docs/dirhlp/topicindex.htm
@@ -0,0 +1,662 @@
+access control <A HREF="ag/acl.htm#1186545">ACI Placement</A><BR>
+access control <A HREF="ag/acl.htm#1196900">Creating ACIs Manually</A><BR>
+access control <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+access control <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+access control <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+access control <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+access control <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+access control <A HREF="ag/acl.htm#997355">Managing Access Control</A><BR>
+access control <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+access control <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+access control <A HREF="ag/roles.htm#1115584">Using Roles Securely</A><BR>
+access control <A HREF="ag/acl.htm#997696">Defining Access Based on Authentication Method</A><BR>
+access control <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+access control <A HREF="ag/acl.htm#1197484">The ACI Syntax</A><BR>
+access log <A HREF="ag/dsstats.htm#1094317">Access Log</A><BR>
+access log <A HREF="ag/dsstats.htm#1092377">Audit Log</A><BR>
+access log <A HREF="ag/dsstats.htm#1094317">Access Log</A><BR>
+access log <A HREF="ag/dsstats.htm#1094317">Access Log</A><BR>
+access log <A HREF="ag/dsstats.htm#1094317">Access Log</A><BR>
+access log parameter <A HREF="ag/dsstats.htm#1094176">Defining a Log File Deletion Policy</A><BR>
+access-control list (ACL) <A HREF="ag/acl.htm#1013769">Access Control Principles</A><BR>
+account inactivation <A HREF="ag/password.htm#1085613">Inactivating User and Roles Using the Command Line</A><BR>
+account inactivation <A HREF="ag/password.htm#1085611">Inactivating User and Roles Using the Console</A><BR>
+account lockout <A HREF="ag/password.htm#1086557">Configuring the Account Lockout Policy</A><BR>
+account lockout <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+account lockout <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+account lockout <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+account lockout <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+ACI <A HREF="ag/acl.htm#997883">Editing an ACI</A><BR>
+ACI <A HREF="ag/acl.htm#1199793">Creating a New ACI</A><BR>
+ACI attribute <A HREF="ag/index1.htm#1104400">About Default, System, and Standard Indexes</A><BR>
+ACI attribute <A HREF="ag/acl.htm#1186545">ACI Placement</A><BR>
+ACI instruction <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+ACI instruction <A HREF="ag/acl.htm#1197484">The ACI Syntax</A><BR>
+ACI instruction <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+ACI instruction <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+ACI instruction <A HREF="ag/acl.htm#1197484">The ACI Syntax</A><BR>
+ACIs <A HREF="ag/acl.htm#1196838">ACI Evaluation</A><BR>
+ACR <A HREF="ag/acl.htm#997883">Editing an ACI</A><BR>
+activating accounts <A HREF="ag/password.htm#1085796">Activating User and Roles Using the Console</A><BR>
+activating accounts <A HREF="ag/password.htm#1085614">Activating User and Roles Using the Command Line</A><BR>
+Administration Server <A HREF="ag/intro.htm#1043886">Introduction to Netscape Directory Server</A><BR>
+Administration Server <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+agents <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+agents <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+algorithms <A HREF="ag/index1.htm#1095569">Overview of the Searching Algorithm</A><BR>
+algorithms <A HREF="ag/index1.htm#996824">Managing Indexes</A><BR>
+allowed attributes <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+allowed attributes <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+allowed attributes <A HREF="ag/scmacfg.htm#1070760">Editing Object Classes</A><BR>
+anonymous access <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+anonymous access <A HREF="ag/acl.htm#1187588">Access Control Usage Examples</A><BR>
+approximate index <A HREF="ag/index1.htm#1095569">Overview of the Searching Algorithm</A><BR>
+attribute uniqueness plug-in <A HREF="ag/uid.htm#1054798">Configuring Unique Attribute Plug-Ins from the Command Line</A><BR>
+attribute values <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+attribute values <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+attribute values <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+attribute values <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+attribute values <A HREF="ag/scmacfg.htm#1093643">Creating Attributes</A><BR>
+attributes <A HREF="ag/acl.htm#1186545">ACI Placement</A><BR>
+attributes <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+attributes <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+attributes <A HREF="ag/scmacfg.htm#1093575">Viewing Attributes</A><BR>
+attributes <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+attributes <A HREF="ag/scmacfg.htm#1093643">Creating Attributes</A><BR>
+attributes <A HREF="ag/scmacfg.htm#1093643">Creating Attributes</A><BR>
+attributes <A HREF="ag/find.htm#1037676">Search Filter Syntax</A><BR>
+attributes <A HREF="ag/scmacfg.htm#1072236">Overview of Extending Schema</A><BR>
+attributes <A HREF="ag/scmacfg.htm#1093643">Creating Attributes</A><BR>
+attributes <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+attributes <A HREF="ag/scmacfg.htm#1093575">Viewing Attributes</A><BR>
+attributes <A HREF="ag/scmacfg.htm#1093547">Managing Attributes</A><BR>
+audit log <A HREF="ag/dsstats.htm#1092377">Audit Log</A><BR>
+audit log <A HREF="ag/dsstats.htm#1092377">Audit Log</A><BR>
+audit log <A HREF="ag/dsstats.htm#1092377">Audit Log</A><BR>
+audit log <A HREF="ag/dsstats.htm#1092377">Audit Log</A><BR>
+audit log parameter <A HREF="ag/dsstats.htm#1015760">Error Log</A><BR>
+authentication <A HREF="ag/acl.htm#997681">Defining Access at a Specific Time of Day or Day of Week</A><BR>
+authentication <A HREF="ag/ssl.htm#1038525">Setting Security Preferences</A><BR>
+authentication <A HREF="ag/url.htm#2836420">Examples of LDAP URLs</A><BR>
+backing up data <A HREF="ag/dbmanage.htm#1021812">Backing Up All Databases</A><BR>
+backing up data <A HREF="ag/dbmanage.htm#1113690">Backing Up the dse.ldif Configuration File</A><BR>
+bind credentials <A HREF="ag/entry_dist.htm#18376">Creating a New Database Link</A><BR>
+bind DN <A HREF="ag/password.htm#1085603">Setting Resource Limits Based on the Bind DN</A><BR>
+bind rules <A HREF="ag/acl.htm#1198317">Defining Access from a Specific Domain</A><BR>
+bind rules <A HREF="ag/acl.htm#997681">Defining Access at a Specific Time of Day or Day of Week</A><BR>
+bind rules <A HREF="ag/acl.htm#1197484">The ACI Syntax</A><BR>
+bind rules <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+bind rules <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+bind rules <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+bind rules <A HREF="ag/acl.htm#1197654">Bind Rule Syntax</A><BR>
+bind rules <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+bindDN <A HREF="ag/intro.htm#1068452">Binding to the Directory From Netscape Console</A><BR>
+Boolean bind rules <A HREF="ag/acl.htm#997727">Using Boolean Bind Rules</A><BR>
+Boolean bind rules <A HREF="ag/acl.htm#997696">Defining Access Based on Authentication Method</A><BR>
+cache <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+cascading chaining <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+cascading chaining <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+cascading chaining <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+cascading chaining <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+cascading chaining <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+cascading chaining <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+cascading chaining <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+cascading chaining <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+certificate <A HREF="ag/ssl.htm#1080310">Setting up Certificate-Based Authentication</A><BR>
+certificate <A HREF="ag/intro.htm#1068673">Starting the Server with SSL Enabled</A><BR>
+certificate database <A HREF="ag/ssl.htm#1041472">Introduction to SSL in the Directory Server</A><BR>
+chaining <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+chaining <A HREF="ag/entry_dist.htm#22197">Creating and Maintaining Database Links</A><BR>
+chaining <A HREF="ag/entry_dist.htm#25661">Chaining Using SSL</A><BR>
+change log <A HREF="ag/modify.htm#1124276">How Referential Integrity Works</A><BR>
+change operations <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+change operations <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+change operations <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+changetypes <A HREF="ag/modify.htm#1038303">LDIF Update Statements </A><BR>
+changetypes <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+changetypes <A HREF="ag/modify.htm#1042769">Renaming an Entry Using LDIF</A><BR>
+ciphers <A HREF="ag/ssl.htm#1038525">Setting Security Preferences</A><BR>
+ciphers <A HREF="ag/ssl.htm#1038525">Setting Security Preferences</A><BR>
+ciphers <A HREF="ag/ssl.htm#1038525">Setting Security Preferences</A><BR>
+class of service (CoS) <A HREF="ag/roles.htm#1118810">Creating Role-Based Attributes</A><BR>
+class of service (CoS) <A HREF="ag/roles.htm#1115730">Managing CoS From the Command Line</A><BR>
+class of service (CoS) <A HREF="ag/roles.htm#1116857">Managing CoS Using the Console</A><BR>
+class of service (CoS) <A HREF="ag/roles.htm#1116857">Managing CoS Using the Console</A><BR>
+class of service (CoS) <A HREF="ag/roles.htm#1115730">Managing CoS From the Command Line</A><BR>
+classic CoS <A HREF="ag/roles.htm#1115636">About CoS</A><BR>
+classic CoS <A HREF="ag/roles.htm#1115636">About CoS</A><BR>
+client <A HREF="ag/find.htm#1033854">Finding Directory Entries</A><BR>
+collation order <A HREF="ag/index1.htm#1008990">Creating Indexes From the Server Console</A><BR>
+collation order <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+collation order <A HREF="ag/find.htm#1061341">Searching an Internationalized Directory</A><BR>
+command line <A HREF="ag/dsstats.htm#1028885">Monitoring Database Activity From the Server Console</A><BR>
+command line <A HREF="ag/dsstats.htm#1093530">Monitoring Your Server From the Directory Server Console</A><BR>
+command line <A HREF="ag/modify.htm#1069501">Managing Entries From the Command Line</A><BR>
+command-line scripts <A HREF="ag/dbmanage.htm#1021812">Backing Up All Databases</A><BR>
+command-line utilities <A HREF="ag/ssl.htm#1053102">Using Certificate-Based Authentication</A><BR>
+command-line utilities <A HREF="ag/modify.htm#1080582">Adding and Modifying Entries Using ldapmodify</A><BR>
+command-line utilities <A HREF="ag/modify.htm#1057632">Adding Entries Using LDIF</A><BR>
+command-line utilities <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+command-line utilities <A HREF="ag/ldif.htm#1032720">Representing Binary Data</A><BR>
+command-line utilities <A HREF="ag/index1.htm#1051480">Creating Indexes From the Command Line </A><BR>
+command-line utilities <A HREF="ag/intro.htm#1072054">Starting/Stopping the Server From the Command Line</A><BR>
+command-line utilities <A HREF="ag/intro.htm#1072054">Starting/Stopping the Server From the Command Line</A><BR>
+commas, in DNs <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+commas, in DNs <A HREF="ag/ldif.htm#1044482">Specifying Organizational Unit Entries</A><BR>
+commas, in DNs <A HREF="ag/ldif.htm#1044420">Specifying Organization Entries</A><BR>
+commas, in DNs <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+configuration attributes <A HREF="ag/password.htm#1086259">Configuring the Account Lockout Policy</A><BR>
+configuration attributes <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+configuration attributes <A HREF="ag/password.htm#1075248">Configuring the Password Policy</A><BR>
+configuration attributes <A HREF="ag/entry_dist.htm#19406">Creating Suffixes</A><BR>
+connections <A HREF="ag/dsstats.htm#1093530">Monitoring Your Server From the Directory Server Console</A><BR>
+connections <A HREF="ag/dsstats.htm#1093530">Monitoring Your Server From the Directory Server Console</A><BR>
+consumer-initiated replication <A HREF="ag/replicat.htm#1102416">Supplier/Consumer</A><BR>
+continued lines <A HREF="ag/ldif.htm#1045983">Continuing Lines in LDIF</A><BR>
+continued lines <A HREF="ag/modify.htm#1038303">LDIF Update Statements </A><BR>
+CoS definition entry <A HREF="ag/roles.htm#1115730">Managing CoS From the Command Line</A><BR>
+CoS definition entry <A HREF="ag/roles.htm#1115730">Managing CoS From the Command Line</A><BR>
+CoS template entry <A HREF="ag/roles.htm#1115730">Managing CoS From the Command Line</A><BR>
+custom distribution function <A HREF="ag/entry_dist.htm#22523">Creating Databases</A><BR>
+custom distribution logic <A HREF="ag/entry_dist.htm#22523">Creating Databases</A><BR>
+custom distribution logic <A HREF="ag/entry_dist.htm#22523">Creating Databases</A><BR>
+database <A HREF="ag/acl.htm#997355">Managing Access Control</A><BR>
+database <A HREF="ag/ldif.htm#1047767">Specifying Organizational Person Entries</A><BR>
+database <A HREF="ag/scmacfg.htm#1079595">extending the schema </a><BR>
+database <A HREF="ag/dsstats.htm#1028885">Monitoring Database Activity From the Server Console</A><BR>
+database <A HREF="ag/dsstats.htm#1012760">Monitoring Database Activity</A><BR>
+database <A HREF="ag/entry_dist.htm#17926">Creating and Maintaining Databases</A><BR>
+database <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+database <A HREF="ag/scmacfg.htm#1069111">Deleting Object Classes</A><BR>
+database <A HREF="ag/dsstats.htm#1012760">Monitoring Database Activity</A><BR>
+database <A HREF="ag/modify.htm#1125009">Using Special Characters</A><BR>
+database <A HREF="ag/dsstats.htm#1012760">Monitoring Database Activity</A><BR>
+database backups <A HREF="ag/dbmanage.htm#1066683">Backing Up All Databases</A><BR>
+database link <A HREF="ag/entry_dist.htm#21765">Creating a New Database Link</A><BR>
+database links <A HREF="ag/entry_dist.htm#25661">Chaining Using SSL</A><BR>
+database links <A HREF="ag/entry_dist.htm#25659">Maintaining Database Links</A><BR>
+database links <A HREF="ag/entry_dist.htm#22197">Creating and Maintaining Database Links</A><BR>
+database schema <A HREF="ag/scmacfg.htm#1069111">Deleting Object Classes</A><BR>
+database schema <A HREF="ag/scmacfg.htm#1093575">Viewing Attributes</A><BR>
+database schema <A HREF="ag/scmacfg.htm#1076337">Viewing Object Classes</A><BR>
+database schema <A HREF="ag/scmacfg.htm#1093680">Editing Attributes</A><BR>
+database schema <A HREF="ag/scmacfg.htm#1070760">Editing Object Classes</A><BR>
+database schema <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+database schema <A HREF="ag/scmacfg.htm#1079595">extending </a><BR>
+database schema <A HREF="ag/scmacfg.htm#1079595">Extending the Directory Schema</A><BR>
+database schema <A HREF="ag/scmacfg.htm#1093547">Managing Attributes</A><BR>
+database schema <A HREF="ag/scmacfg.htm#1070491">Managing Object Classes</A><BR>
+database server parameters <A HREF="ag/dsmanage.htm#1066342">Changing the Location of the Database Transaction Log</A><BR>
+database server parameters <A HREF="ag/dsmanage.htm#1066356">Changing the Database Checkpoint Interval</A><BR>
+database server parameters <A HREF="ag/dsmanage.htm#1066324">Tuning Transaction Logging</A><BR>
+database server parameters <A HREF="ag/intro.htm#1076196">Configuring the Directory Manager</A><BR>
+database server parameters <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+database server parameters <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+database server parameters <A HREF="ag/dsstats.htm#1028885">Monitoring Database Activity From the Server Console</A><BR>
+database transaction logging <A HREF="ag/dsmanage.htm#1066342">Changing the Location of the Database Transaction Log</A><BR>
+database transaction logging <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+database transaction logging <A HREF="ag/dsmanage.htm#1066356">Changing the Database Checkpoint Interval</A><BR>
+database transaction logging <A HREF="ag/dsmanage.htm#1066324">Tuning Transaction Logging</A><BR>
+databases <A HREF="ag/dbmanage.htm#1055147">Backing Up and Restoring Data</A><BR>
+databases <A HREF="ag/entry_dist.htm#21691">Maintaining Directory Databases</A><BR>
+databases <A HREF="ag/dbmanage.htm#1011783">Exporting Data</A><BR>
+databases <A HREF="ag/dbmanage.htm#1117227">Importing Data</A><BR>
+databases <A HREF="ag/dbmanage.htm#1117339">Initializing a Database From the Console</A><BR>
+databases <A HREF="ag/entry_dist.htm#21691">Maintaining Directory Databases</A><BR>
+databases <A HREF="ag/dbmanage.htm#1111690">Enabling and Disabling Read-Only Mode</A><BR>
+databases <A HREF="ag/dbmanage.htm#1055147">Backing Up and Restoring Data</A><BR>
+default referrals <A HREF="ag/entry_dist.htm#17781">Setting Default Referrals</A><BR>
+defining <A HREF="ag/scmacfg.htm#1093575">Viewing Attributes</A><BR>
+defining <A HREF="ag/scmacfg.htm#1076337">Viewing Object Classes</A><BR>
+deleting <A HREF="ag/acl.htm#997883">Editing an ACI</A><BR>
+deleting <A HREF="ag/acl.htm#997883">Editing an ACI</A><BR>
+deleting <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+deleting <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+deleting <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+deleting <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+deleting <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+deleting <A HREF="ag/scmacfg.htm#1070760">Editing Object Classes</A><BR>
+denying access <A HREF="ag/acl.htm#1196838">ACI Evaluation</A><BR>
+Directory Manager <A HREF="ag/intro.htm#1068751">Starting the Directory Server Console</A><BR>
+Directory Manager <A HREF="ag/intro.htm#1076196">Configuring the Directory Manager</A><BR>
+Directory Manager <A HREF="ag/intro.htm#1068751">Starting the Directory Server Console</A><BR>
+directory server <A HREF="ag/i18n.htm#2836267">Internationalization</A><BR>
+directory server <A HREF="ag/snmp.htm#1100574">SNMP Overview</A><BR>
+directory server <A HREF="ag/dsstats.htm#1005575">Manual Log File Rotation</A><BR>
+directory server <A HREF="ag/dsstats.htm#1004977">Monitoring Server Activity</A><BR>
+directory server <A HREF="ag/dsstats.htm#1005575">Manual Log File Rotation</A><BR>
+directory server <A HREF="ag/snmp.htm#1100574">SNMP Overview</A><BR>
+directory server <A HREF="ag/intro.htm#1068594">Viewing the Current Bind DN From the Console</A><BR>
+directory server <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+directory trees <A HREF="ag/find.htm#1039157">Finding Entries Using the Server Console</A><BR>
+disk space <A HREF="ag/dsstats.htm#1094317">Access Log</A><BR>
+disk space <A HREF="ag/dsstats.htm#1092377">Audit Log</A><BR>
+dse.ldif <A HREF="ag/dbmanage.htm#1113690">Backing Up the dse.ldif Configuration File</A><BR>
+dse.ldif <A HREF="ag/pasthru.htm#1054798">Configuring the PTA Plug-In</A><BR>
+dse.ldif <A HREF="ag/pasthru.htm#1054798">Configuring the PTA Plug-In</A><BR>
+dse.ldif <A HREF="ag/dbmanage.htm#1116135">Restoring the dse.ldif Configuration File</A><BR>
+dynamic groups <A HREF="ag/roles.htm#1115376">Managing Dynamic Groups</A><BR>
+dynamic groups <A HREF="ag/roles.htm#1115376">Managing Dynamic Groups</A><BR>
+Encrypted Port Number parameter <A HREF="ag/intro.htm#1070843">Changing Directory Server Port Numbers</A><BR>
+entries <A HREF="ag/modify.htm#1021458">Providing Input From the Command Line</A><BR>
+entries <A HREF="ag/dsstats.htm#1028885">Monitoring Database Activity From the Server Console</A><BR>
+entries <A HREF="ag/modify.htm#1080582">Adding and Modifying Entries Using ldapmodify</A><BR>
+entries <A HREF="ag/find.htm#1039157">Finding Entries Using the Server Console</A><BR>
+entries <A HREF="ag/modify.htm#1057632">Adding Entries Using LDIF</A><BR>
+entries <A HREF="ag/modify.htm#1042769">Renaming an Entry Using LDIF</A><BR>
+entries <A HREF="ag/modify.htm#1021458">Providing Input From the Command Line</A><BR>
+entries <A HREF="ag/modify.htm#1125336">Deleting Entries Using ldapdelete</A><BR>
+entries <A HREF="ag/modify.htm#1042769">Renaming an Entry Using LDIF</A><BR>
+entries <A HREF="ag/ldif.htm#1044796">Defining Directories Using LDIF</A><BR>
+entries <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+entries <A HREF="ag/modify.htm#996824">working with </a><BR>
+environment variables <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+equality search <A HREF="ag/find.htm#1043150">Search Filter Examples</A><BR>
+equality search <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+error log <A HREF="ag/dsstats.htm#1015760">Error Log</A><BR>
+error log <A HREF="ag/dsstats.htm#1092377">Audit Log</A><BR>
+error log <A HREF="ag/dsstats.htm#1015760">Error Log</A><BR>
+error log <A HREF="ag/dsstats.htm#1015760">Error Log</A><BR>
+error log <A HREF="ag/dsstats.htm#1015760">Error Log</A><BR>
+Error Log parameter <A HREF="ag/dsstats.htm#1015760">Error Log</A><BR>
+example <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+exporting data <A HREF="ag/dbmanage.htm#1112496">Exporting to LDIF From the Command Line</A><BR>
+exporting data <A HREF="ag/dbmanage.htm#1111210">Exporting Directory Data to LDIF Using the Console</A><BR>
+failover servers <A HREF="ag/entry_dist.htm#18376">Creating a New Database Link</A><BR>
+files <A HREF="ag/dsstats.htm#1094317">Access Log</A><BR>
+files <A HREF="ag/dbmanage.htm#1066683">Backing Up All Databases</A><BR>
+files <A HREF="ag/index1.htm#1104400">About Default, System, and Standard Indexes</A><BR>
+files <A HREF="ag/index1.htm#1104400">About Default, System, and Standard Indexes</A><BR>
+files <A HREF="ag/modify.htm#1021458">Providing Input From the Command Line</A><BR>
+files <A HREF="ag/dsstats.htm#1015760">Error Log</A><BR>
+files <A HREF="ag/index1.htm#1104400">About Default, System, and Standard Indexes</A><BR>
+files <A HREF="ag/index1.htm#1104400">About Default, System, and Standard Indexes</A><BR>
+filtered role <A HREF="ag/roles.htm#1117626">Managing Roles Using the Console</A><BR>
+filtered role <A HREF="ag/roles.htm#1115540">Managing Roles Using the Command Line</A><BR>
+finding <A HREF="ag/find.htm#1037676">Search Filter Syntax</A><BR>
+finding <A HREF="ag/find.htm#1039157">Finding Entries Using the Server Console</A><BR>
+general access <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+general access <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+general server parameters <A HREF="ag/dsstats.htm#1015760">Error Log</A><BR>
+general server parameters <A HREF="ag/intro.htm#1070843">Changing Directory Server Port Numbers</A><BR>
+general server parameters <A HREF="ag/dsstats.htm#1015760">Error Log</A><BR>
+general server parameters <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+general server parameters <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+general server parameters <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+general server parameters <A HREF="ag/intro.htm#1070843">Changing Directory Server Port Numbers</A><BR>
+general server parameters <A HREF="ag/scmacfg.htm#1093826">Turning Schema Checking On and Off</A><BR>
+general server parameters <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+general server parameters <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+greater than or equal to search <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+greater than or equal to search <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+groups <A HREF="ag/acl.htm#1197654">Bind Rule Syntax</A><BR>
+groups <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+groups <A HREF="ag/roles.htm#1115348">Managing Static Groups</A><BR>
+groups <A HREF="ag/roles.htm#1115331">Using Groups</A><BR>
+Idle Time Out parameter <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+importing data <A HREF="ag/dbmanage.htm#1117312">Performing an Import From the Console</A><BR>
+importing data <A HREF="ag/dbmanage.htm#1117378">Importing From the Command Line</A><BR>
+importing data <A HREF="ag/dbmanage.htm#1117378">Importing From the Command Line</A><BR>
+importing data <A HREF="ag/dbmanage.htm#1117378">Importing From the Command Line</A><BR>
+indexes <A HREF="ag/index1.htm#1008990">Creating Indexes From the Server Console</A><BR>
+indexes <A HREF="ag/index1.htm#1104400">About Default, System, and Standard Indexes</A><BR>
+indirect CoS <A HREF="ag/roles.htm#1115636">About CoS</A><BR>
+indirect CoS <A HREF="ag/roles.htm#1115636">About CoS</A><BR>
+international indexing <A HREF="ag/index1.htm#1008990">Creating Indexes From the Server Console</A><BR>
+international searches <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+international searches <A HREF="ag/find.htm#1100969">Supported Search Types</A><BR>
+international searches <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+international searches <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+international searches <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+international searches <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+international searches <A HREF="ag/find.htm#1061341">Searching an Internationalized Directory</A><BR>
+international searches <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+international searches <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835992">Identifying Supported Locales</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835992">Identifying Supported Locales</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+internationalization <A HREF="ag/find.htm#1061341">Searching an Internationalized Directory</A><BR>
+internationalization <A HREF="ag/modify.htm#1068089">Modifying an Entry in an Internationalized Directory</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835992">Identifying Supported Locales</A><BR>
+internationalization <A HREF="ag/ldif.htm#1044796">Defining Directories Using LDIF</A><BR>
+internationalization <A HREF="ag/find.htm#1043150">Search Filter Examples</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+internationalization <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+language code <A HREF="ag/ldif.htm#1051434">Storing Information in Multiple Languages</A><BR>
+language code <A HREF="ag/i18n.htm#2835992">Identifying Supported Locales</A><BR>
+language support <A HREF="ag/i18n.htm#2835992">Identifying Supported Locales</A><BR>
+language support <A HREF="ag/find.htm#1043150">Search Filter Examples</A><BR>
+language support <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+language tags <A HREF="ag/i18n.htm#2835992">Identifying Supported Locales</A><BR>
+language tags <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+language tags <A HREF="ag/modify.htm#1068089">Modifying an Entry in an Internationalized Directory</A><BR>
+LDAP clients <A HREF="ag/ssl.htm#1038525">Setting Security Preferences</A><BR>
+LDAP clients <A HREF="ag/scmacfg.htm#1072236">Overview of Extending Schema</A><BR>
+LDAP clients <A HREF="ag/dsstats.htm#1013682">Monitoring Databases From the Command Line</A><BR>
+LDAP clients <A HREF="ag/dsstats.htm#1005738">Monitoring Your Server From the Command Line</A><BR>
+LDAP clients <A HREF="ag/find.htm#1033854">Finding Directory Entries</A><BR>
+LDAP Data Interchange Format (LDIF) <A HREF="ag/ldif.htm#1032720">Representing Binary Data</A><BR>
+LDAP Data Interchange Format (LDIF) <A HREF="ag/ldif.htm#1043905">LDAP Data Interchange Format </A><BR>
+LDAP Data Interchange Format (LDIF) <A HREF="ag/ldif.htm#1044796">Defining Directories Using LDIF</A><BR>
+LDAP Data Interchange Format (LDIF) <A HREF="ag/ldif.htm#1044796">Defining Directories Using LDIF</A><BR>
+LDAP Data Interchange Format (LDIF) <A HREF="ag/ldif.htm#1045983">Continuing Lines in LDIF</A><BR>
+LDAP Data Interchange Format (LDIF) <A HREF="ag/modify.htm#1057632">Adding Entries Using LDIF</A><BR>
+LDAP Data Interchange Format (LDIF) <A HREF="ag/modify.htm#1125009">Using Special Characters</A><BR>
+LDAP Data Interchange Format (LDIF) <A HREF="ag/ldif.htm#1047767">Specifying Organizational Person Entries</A><BR>
+LDAP search filters <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+LDAP search filters <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+LDAP URL <A HREF="ag/entry_dist.htm#18376">Creating a New Database Link</A><BR>
+LDAP URLs <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+LDAP URLs <A HREF="ag/url.htm#2830333">LDAP URLs</A><BR>
+LDAP URLs <A HREF="ag/url.htm#2836420">Examples of LDAP URLs</A><BR>
+LDAP URLs <A HREF="ag/url.htm#2836226">Escaping Unsafe Characters</A><BR>
+LDAP URLs <A HREF="ag/url.htm#2836420">Examples of LDAP URLs</A><BR>
+LDAP URLs <A HREF="ag/url.htm#2831945">Components of an LDAP URL</A><BR>
+ldapdelete utility <A HREF="ag/modify.htm#1080582">Adding and Modifying Entries Using ldapmodify</A><BR>
+ldapdelete utility <A HREF="ag/modify.htm#1125336">Deleting Entries Using ldapdelete</A><BR>
+ldapmodify utility <A HREF="ag/modify.htm#1125336">Deleting Entries Using ldapdelete</A><BR>
+ldapmodify utility <A HREF="ag/modify.htm#1080582">Adding and Modifying Entries Using ldapmodify</A><BR>
+ldapmodify utility <A HREF="ag/modify.htm#1057632">Adding Entries Using LDIF</A><BR>
+ldapmodify utility <A HREF="ag/modify.htm#1080582">Adding and Modifying Entries Using ldapmodify</A><BR>
+ldapmodify utility <A HREF="ag/modify.htm#1068089">Modifying an Entry in an Internationalized Directory</A><BR>
+ldapmodify utility <A HREF="ag/modify.htm#1080582">Adding and Modifying Entries Using ldapmodify</A><BR>
+ldapsearch utility <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+ldapsearch utility <A HREF="ag/find.htm#1100455">Using ldapsearch</A><BR>
+ldapsearch utility <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+ldapsearch utility <A HREF="ag/find.htm#1100459">Using Special Characters</A><BR>
+ldapsearch utility <A HREF="ag/find.htm#1061341">Searching an Internationalized Directory</A><BR>
+ldapsearch utility <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+ldapsearch utility <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+ldapsearch utility <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+ldapsearch utility <A HREF="ag/find.htm#1039157">Finding Entries Using the Server Console</A><BR>
+LDIF entries <A HREF="ag/ldif.htm#1032720">Representing Binary Data</A><BR>
+LDIF entries <A HREF="ag/ldif.htm#1044420">Specifying Organization Entries</A><BR>
+LDIF entries <A HREF="ag/ldif.htm#1032720">Representing Binary Data</A><BR>
+LDIF entries <A HREF="ag/ldif.htm#1044796">Defining Directories Using LDIF</A><BR>
+LDIF files <A HREF="ag/ldif.htm#1045983">Continuing Lines in LDIF</A><BR>
+LDIF files <A HREF="ag/ldif.htm#1047767">Specifying Organizational Person Entries</A><BR>
+LDIF files <A HREF="ag/modify.htm#1057632">Adding Entries Using LDIF</A><BR>
+LDIF files <A HREF="ag/ldif.htm#1044796">Defining Directories Using LDIF</A><BR>
+LDIF files <A HREF="ag/modify.htm#1057632">Adding Entries Using LDIF</A><BR>
+LDIF files <A HREF="ag/ldif.htm#1044796">Defining Directories Using LDIF</A><BR>
+LDIF files <A HREF="ag/acl.htm#998713">Defining Permissions for DNs That Contain a Comma</A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1038303">LDIF Update Statements </A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1038303">LDIF Update Statements </A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1038303">LDIF Update Statements </A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1125009">Using Special Characters</A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+LDIF update statements <A HREF="ag/modify.htm#1042769">Renaming an Entry Using LDIF</A><BR>
+ldif utility <A HREF="ag/ldif.htm#1032720">Representing Binary Data</A><BR>
+ldif2db utility <A HREF="ag/index1.htm#1051480">Creating Indexes From the Command Line </A><BR>
+less than or equal to search <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+less than or equal to search <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+less than search <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+less than search <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+locales <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+locales <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+locales <A HREF="ag/i18n.htm#2835966">About Locales</A><BR>
+log files <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+log files <A HREF="ag/dsstats.htm#1092377">Audit Log</A><BR>
+log files <A HREF="ag/dsstats.htm#1092377">Audit Log</A><BR>
+log files <A HREF="ag/dsstats.htm#996824">Monitoring Server and Database Activity</A><BR>
+Look Through Limit parameter <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+loop detection <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+managed device <A HREF="ag/snmp.htm#1100574">SNMP Overview</A><BR>
+managed device <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+managed role <A HREF="ag/roles.htm#1117626">Managing Roles Using the Console</A><BR>
+managed role <A HREF="ag/roles.htm#1115540">Managing Roles Using the Command Line</A><BR>
+master agent <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+master agent <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+master agent <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+matchingRule format <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+matchingRule format <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+matchingRule format <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+matchingRule format <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+Max File Descriptors parameter <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+Maximum Entries in Cache parameter <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+memory <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+Memory available for cache <A HREF="ag/dsmanage.htm#1066385">Optimizing Search Performance</A><BR>
+MIB <A HREF="ag/snmp.htm#1100574">SNMP Overview</A><BR>
+MIB <A HREF="ag/snmp.htm#1072684">Overview of the Directory Server Management Information Base</A><BR>
+MIB <A HREF="ag/snmp.htm#1072684">Overview of the Directory Server Management Information Base</A><BR>
+modifying <A HREF="ag/modify.htm#1038401">Modifying an Entry Using LDIF</A><BR>
+modifying <A HREF="ag/modify.htm#1042769">Renaming an Entry Using LDIF</A><BR>
+modifying <A HREF="ag/modify.htm#1068089">Modifying an Entry in an Internationalized Directory</A><BR>
+monitoring <A HREF="ag/dsstats.htm#1028885">Monitoring Database Activity From the Server Console</A><BR>
+monitoring <A HREF="ag/dsstats.htm#1012760">Monitoring Database Activity</A><BR>
+monitoring <A HREF="ag/dsstats.htm#1004977">Monitoring Server Activity</A><BR>
+nested role <A HREF="ag/roles.htm#1117626">Managing Roles Using the Console</A><BR>
+nested role <A HREF="ag/roles.htm#1115540">Managing Roles Using the Command Line</A><BR>
+netscape-ldap.mib <A HREF="ag/snmp.htm#1099922">About the Operations Table</A><BR>
+netscape-ldap.mib <A HREF="ag/snmp.htm#1072684">Overview of the Directory Server Management Information Base</A><BR>
+netscape-ldap.mib <A HREF="ag/snmp.htm#1072684">Overview of the Directory Server Management Information Base</A><BR>
+network management station (NMS) <A HREF="ag/snmp.htm#1100574">SNMP Overview</A><BR>
+nsslapd-lookthroughlimit attribute <A HREF="ag/index1.htm#1095569">Overview of the Searching Algorithm</A><BR>
+nsslapd-sizelimit attribute <A HREF="ag/index1.htm#1095569">Overview of the Searching Algorithm</A><BR>
+nsslapd-timelimit attribute <A HREF="ag/index1.htm#1095569">Overview of the Searching Algorithm</A><BR>
+object class <A HREF="ag/scmacfg.htm#1076337">Viewing Object Classes</A><BR>
+object class <A HREF="ag/scmacfg.htm#1070760">Editing Object Classes</A><BR>
+object class <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+object class <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+object class <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+object class <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+object class <A HREF="ag/scmacfg.htm#1072236">Overview of Extending Schema</A><BR>
+object class <A HREF="ag/scmacfg.htm#1070491">Managing Object Classes</A><BR>
+object classes <A HREF="ag/scmacfg.htm#1076337">Viewing Object Classes</A><BR>
+object classes <A HREF="ag/scmacfg.htm#1076337">Viewing Object Classes</A><BR>
+object identifier (OID) <A HREF="ag/scmacfg.htm#1093643">Creating Attributes</A><BR>
+object identifier (OID) <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+object identifier (OID) <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+operators <A HREF="ag/find.htm#1037765">Using Compound Search Filters</A><BR>
+operators <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+operators <A HREF="ag/find.htm#1037683">Using Attributes in Search Filters</A><BR>
+operators <A HREF="ag/find.htm#1100969">Supported Search Types</A><BR>
+optional attributes <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+optional attributes <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+optional attributes <A HREF="ag/scmacfg.htm#1070760">Editing Object Classes</A><BR>
+optional attributes <A HREF="ag/scmacfg.htm#1070760">Editing Object Classes</A><BR>
+password <A HREF="ag/password.htm#1085614">Activating User and Roles Using the Command Line</A><BR>
+password policies <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+password policies <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+password policies <A HREF="ag/password.htm#1085614">Activating User and Roles Using the Command Line</A><BR>
+password policies <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+password policy <A HREF="ag/password.htm#1075248">Configuring the Password Policy</A><BR>
+password policy <A HREF="ag/password.htm#1074672">Configuring the Password Policy</A><BR>
+password policy <A HREF="ag/password.htm#1077081">Managing the Password Policy</A><BR>
+password policy <A HREF="ag/password.htm#1086259">Configuring the Account Lockout Policy</A><BR>
+passwords <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+passwords <A HREF="ag/intro.htm#1068673">Starting the Server with SSL Enabled</A><BR>
+passwords <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+passwords <A HREF="ag/password.htm#1086219">Configuring the Account Lockout Policy</A><BR>
+passwords <A HREF="ag/password.htm#1085614">Activating User and Roles Using the Command Line</A><BR>
+passwords <A HREF="ag/password.htm#1075248">Configuring the Password Policy</A><BR>
+performance counters <A HREF="ag/dsstats.htm#1028885">Monitoring Database Activity From the Server Console</A><BR>
+performance counters <A HREF="ag/dsstats.htm#1005575">Manual Log File Rotation</A><BR>
+performance tuning <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+performance tuning <A HREF="ag/dsmanage.htm#996824">Tuning Directory Server Performance</A><BR>
+permissions <A HREF="ag/acl.htm#1197484">The ACI Syntax</A><BR>
+permissions <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+permissions <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+permissions <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+permissions <A HREF="ag/acl.htm#1196838">ACI Evaluation</A><BR>
+pointer CoS <A HREF="ag/roles.htm#1115636">About CoS</A><BR>
+pointer CoS <A HREF="ag/roles.htm#1115636">About CoS</A><BR>
+Port Number parameter <A HREF="ag/intro.htm#1070843">Changing Directory Server Port Numbers</A><BR>
+presence index <A HREF="ag/index1.htm#1104400">About Default, System, and Standard Indexes</A><BR>
+presence search <A HREF="ag/find.htm#1043150">Search Filter Examples</A><BR>
+presence search <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+proxied authorization <A HREF="ag/acl.htm#998713">Defining Permissions for DNs That Contain a Comma</A><BR>
+proxy authorization control <A HREF="ag/entry_dist.htm#25801">Advanced Feature: Configuring Cascading Chaining</A><BR>
+proxy DN <A HREF="ag/acl.htm#1020466">Proxied Authorization ACI Example</A><BR>
+Proxy rights <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+PTA <A HREF="ag/pasthru.htm#1068035">Using the Pass-Through&nbsp;Authentication&nbsp;Plug-In</A><BR>
+PTA plug-in <A HREF="ag/pasthru.htm#1056152">PTA Plug-In Syntax</A><BR>
+PTA plug-in <A HREF="ag/pasthru.htm#1057316">Configuring the Optional Parameters</A><BR>
+PTA plug-in <A HREF="ag/pasthru.htm#1063372">How Directory Server 5.0 Uses PTA</A><BR>
+read-only mode <A HREF="ag/dbmanage.htm#1111690">Enabling and Disabling Read-Only Mode</A><BR>
+referential integrity <A HREF="ag/modify.htm#1124276">How Referential Integrity Works</A><BR>
+referrals <A HREF="ag/entry_dist.htm#18074">Maintaining Suffixes</A><BR>
+renaming entries <A HREF="ag/modify.htm#1042769">Renaming an Entry Using LDIF</A><BR>
+replication <A HREF="ag/ssl.htm#1038525">Setting Security Preferences</A><BR>
+replication <A HREF="ag/replicat.htm#1102416">Supplier/Consumer</A><BR>
+replication <A HREF="ag/replicat.htm#1027091">Managing Replication</A><BR>
+replication <A HREF="ag/password.htm#1086259">Configuring the Account Lockout Policy</A><BR>
+replication <A HREF="ag/replicat.htm#1102416">Supplier/Consumer</A><BR>
+required attributes <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+required attributes <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+required attributes <A HREF="ag/scmacfg.htm#1070760">Editing Object Classes</A><BR>
+Resource Summary <A HREF="ag/dsstats.htm#1093530">Monitoring Your Server From the Directory Server Console</A><BR>
+restoring data <A HREF="ag/dbmanage.htm#1075653">Restoring All Databases</A><BR>
+restoring data <A HREF="ag/dbmanage.htm#1075653">Restoring All Databases</A><BR>
+restoring data <A HREF="ag/dbmanage.htm#1116135">Restoring the dse.ldif Configuration File</A><BR>
+restoring data <A HREF="ag/dbmanage.htm#1075653">Restoring All Databases</A><BR>
+restoring data <A HREF="ag/dbmanage.htm#1022012">Restoring Databases that Include Replicated Entries</A><BR>
+rights <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+roles <A HREF="ag/roles.htm#1115584">Using Roles Securely</A><BR>
+roles <A HREF="ag/password.htm#1085796">Activating User and Roles Using the Console</A><BR>
+roles <A HREF="ag/roles.htm#1115540">Managing Roles Using the Command Line</A><BR>
+roles <A HREF="ag/roles.htm#1117626">Managing Roles Using the Console</A><BR>
+roles <A HREF="ag/password.htm#1086206">Inactivating Users and Roles</A><BR>
+roles <A HREF="ag/roles.htm#1117626">Managing Roles Using the Console</A><BR>
+roles <A HREF="ag/roles.htm#1115540">Managing Roles Using the Command Line</A><BR>
+roles <A HREF="ag/roles.htm#1117631">About Roles</A><BR>
+root DN <A HREF="ag/intro.htm#1068751">Starting the Directory Server Console</A><BR>
+root suffix <A HREF="ag/entry_dist.htm#19406">Creating Suffixes</A><BR>
+root suffix <A HREF="ag/entry_dist.htm#19406">Creating Suffixes</A><BR>
+schema <A HREF="ag/scmacfg.htm#1069111">Deleting Object Classes</A><BR>
+schema <A HREF="ag/scmacfg.htm#1093575">Viewing Attributes</A><BR>
+schema <A HREF="ag/scmacfg.htm#1076337">Viewing Object Classes</A><BR>
+schema <A HREF="ag/scmacfg.htm#1093680">Editing Attributes</A><BR>
+schema <A HREF="ag/scmacfg.htm#1093065">Creating Object Classes</A><BR>
+schema <A HREF="ag/scmacfg.htm#1079595">extending </a><BR>
+schema <A HREF="ag/scmacfg.htm#1079595">Extending the Directory Schema</A><BR>
+schema <A HREF="ag/scmacfg.htm#1093547">Managing Attributes</A><BR>
+schema <A HREF="ag/scmacfg.htm#1070491">Managing Object Classes</A><BR>
+Schema Check parameter <A HREF="ag/scmacfg.htm#1093826">Turning Schema Checking On and Off</A><BR>
+schema checking <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+schema checking <A HREF="ag/modify.htm#1080582">Adding and Modifying Entries Using ldapmodify</A><BR>
+schema checking <A HREF="ag/scmacfg.htm#1069111">Deleting Object Classes</A><BR>
+schema checking <A HREF="ag/scmacfg.htm#1069111">Deleting Object Classes</A><BR>
+search filters <A HREF="ag/find.htm#1037765">Using Compound Search Filters</A><BR>
+search filters <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+search filters <A HREF="ag/find.htm#1046960">LDAP Search Filters</A><BR>
+search filters <A HREF="ag/find.htm#1061341">Searching an Internationalized Directory</A><BR>
+search filters <A HREF="ag/find.htm#1037683">Using Attributes in Search Filters</A><BR>
+search filters <A HREF="ag/find.htm#1037676">Search Filter Syntax</A><BR>
+search filters <A HREF="ag/find.htm#1046960">LDAP Search Filters</A><BR>
+search filters <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+search filters <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+searches <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+searches <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+searches <A HREF="ag/find.htm#1100542">ldapsearch Examples</A><BR>
+searches <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+searches <A HREF="ag/find.htm#1043150">Search Filter Examples</A><BR>
+searches <A HREF="ag/find.htm#1100969">Supported Search Types</A><BR>
+searches <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+searches <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+searches <A HREF="ag/find.htm#1039157">Finding Entries Using the Server Console</A><BR>
+searches <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+searches <A HREF="ag/index1.htm#1104400">About Default, System, and Standard Indexes</A><BR>
+searches <A HREF="ag/index1.htm#1104400">About Default, System, and Standard Indexes</A><BR>
+searches <A HREF="ag/find.htm#1100481">Commonly Used ldapsearch options</A><BR>
+searches <A HREF="ag/find.htm#1037693">Using Operators in Search Filters</A><BR>
+Secure Sockets Layer (SSL) <A HREF="ag/intro.htm#1068673">Starting the Server with SSL Enabled</A><BR>
+Secure Sockets Layer (SSL) <A HREF="ag/ssl.htm#1039230">Activating SSL</A><BR>
+Secure Sockets Layer (SSL) <A HREF="ag/intro.htm#1070927">Tracking Modifications to Directory Entries</A><BR>
+Secure Sockets Layer (SSL) <A HREF="ag/ssl.htm#1039230">Activating SSL</A><BR>
+security <A HREF="ag/ssl.htm#1038525">Setting Security Preferences</A><BR>
+security <A HREF="ag/url.htm#2836420">Examples of LDAP URLs</A><BR>
+security <A HREF="ag/ssl.htm#1039230">Activating SSL</A><BR>
+self access <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+Selfwrite rights <A HREF="ag/acl.htm#997465">Defining Permissions</A><BR>
+Selfwrite rights <A HREF="ag/acl.htm#1187588">Access Control Usage Examples</A><BR>
+Server Console <A HREF="ag/index1.htm#1102214">Creating Indexes</A><BR>
+Server Console <A HREF="ag/dsstats.htm#1093530">Monitoring Your Server From the Directory Server Console</A><BR>
+Server Console <A HREF="ag/acl.htm#997727">Using Boolean Bind Rules</A><BR>
+server parameters <A HREF="ag/intro.htm#1076196">Configuring the Directory Manager</A><BR>
+SIR <A HREF="ag/replicat.htm#1102572">Cascading Replication</A><BR>
+Size Limit parameter <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+slapd.conf <A HREF="ag/uid.htm#1054798">Configuring Unique Attribute Plug-Ins from the Command Line</A><BR>
+slapd.conf <A HREF="ag/uid.htm#1054798">Configuring Unique Attribute Plug-Ins from the Command Line</A><BR>
+smart referrals <A HREF="ag/entry_dist.htm#17830">Creating Smart Referrals</A><BR>
+smart referrals <A HREF="ag/entry_dist.htm#17796">Creating Smart Referrals</A><BR>
+SNMP <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+SNMP <A HREF="ag/snmp.htm#1072951">Setting Up SNMP on UNIX</A><BR>
+SNMP <A HREF="ag/snmp.htm#1073487">The Entries Table</A><BR>
+SNMP <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+SNMP <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+SNMP <A HREF="ag/snmp.htm#1100574">SNMP Overview</A><BR>
+SNMP <A HREF="ag/snmp.htm#1073255">Monitoring Directory Server Using SNMP</A><BR>
+SNMP <A HREF="ag/snmp.htm#1099211">Starting and Stopping the SNMP Service on Windows NT</A><BR>
+SNMP <A HREF="ag/snmp.htm#1076202">Starting and Stopping the SNMP Subagent on UNIX</A><BR>
+SNMP <A HREF="ag/snmp.htm#1100574">SNMP Overview</A><BR>
+SSL <A HREF="ag/entry_dist.htm#25661">Chaining Using SSL</A><BR>
+standard <A HREF="ag/scmacfg.htm#1072236">Overview of Extending Schema</A><BR>
+standard <A HREF="ag/scmacfg.htm#1079595">Extending the Directory Schema</A><BR>
+standard <A HREF="ag/scmacfg.htm#1072236">Overview of Extending Schema</A><BR>
+static groups <A HREF="ag/roles.htm#1115348">Managing Static Groups</A><BR>
+static groups <A HREF="ag/roles.htm#1115348">Managing Static Groups</A><BR>
+sub suffix <A HREF="ag/entry_dist.htm#19406">Creating Suffixes</A><BR>
+sub suffix <A HREF="ag/entry_dist.htm#19406">Creating Suffixes</A><BR>
+subagent <A HREF="ag/snmp.htm#1099211">Starting and Stopping the SNMP Service on Windows NT</A><BR>
+subagent <A HREF="ag/snmp.htm#1075584">Configuring SNMP for the Directory Server</A><BR>
+subagent <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+subagent <A HREF="ag/snmp.htm#1072972">Configuring the AIX SNMP Daemon</A><BR>
+subagent <A HREF="ag/snmp.htm#1076202">Starting and Stopping the SNMP Subagent on UNIX</A><BR>
+substring search <A HREF="ag/find.htm#1041174">International Search Examples</A><BR>
+suffix <A HREF="ag/entry_dist.htm#19406">Creating Suffixes</A><BR>
+suffix <A HREF="ag/entry_dist.htm#22523">Creating Databases</A><BR>
+suffix referrals <A HREF="ag/entry_dist.htm#17921">Creating Suffix Referrals</A><BR>
+suffixes <A HREF="ag/entry_dist.htm#19406">Creating Suffixes</A><BR>
+suffixes <A HREF="ag/entry_dist.htm#22523">Creating Databases</A><BR>
+suffixes <A HREF="ag/entry_dist.htm#18074">Maintaining Suffixes</A><BR>
+suffixes <A HREF="ag/entry_dist.htm#18074">Maintaining Suffixes</A><BR>
+suffixes <A HREF="ag/entry_dist.htm#18074">Maintaining Suffixes</A><BR>
+supplier-initiated replication <A HREF="ag/replicat.htm#1102572">Cascading Replication</A><BR>
+supplier-initiated replication <A HREF="ag/replicat.htm#1102416">Supplier/Consumer</A><BR>
+syntax <A HREF="ag/acl.htm#997727">Using Boolean Bind Rules</A><BR>
+syntax <A HREF="ag/acl.htm#1196900">Creating ACIs Manually</A><BR>
+syntax <A HREF="ag/scmacfg.htm#1093643">Creating Attributes</A><BR>
+syntax <A HREF="ag/url.htm#2831945">Components of an LDAP URL</A><BR>
+syntax <A HREF="ag/find.htm#1100459">Using Special Characters</A><BR>
+syntax <A HREF="ag/modify.htm#1038303">LDIF Update Statements </A><BR>
+syntax <A HREF="ag/find.htm#1061341">Searching an Internationalized Directory</A><BR>
+syntax <A HREF="ag/find.htm#1046960">LDAP Search Filters</A><BR>
+system connections <A HREF="ag/dsstats.htm#1093530">Monitoring Your Server From the Directory Server Console</A><BR>
+system resources <A HREF="ag/dsstats.htm#1093530">Monitoring Your Server From the Directory Server Console</A><BR>
+tabs <A HREF="ag/intro.htm#1076196">Configuring the Directory Manager</A><BR>
+tabs <A HREF="ag/dsstats.htm#1028885">Monitoring Database Activity From the Server Console</A><BR>
+tabs <A HREF="ag/snmp.htm#1076202">Starting and Stopping the SNMP Subagent on UNIX</A><BR>
+targeting <A HREF="ag/acl.htm#1197484">The ACI Syntax</A><BR>
+targeting <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+targeting <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+targeting <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+targeting <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+targeting <A HREF="ag/acl.htm#1197484">The ACI Syntax</A><BR>
+targeting <A HREF="ag/acl.htm#997404">Defining Targets</A><BR>
+targeting <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+Time Limit parameter <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+tuning performance <A HREF="ag/dsmanage.htm#1006217">Tuning Server Performance</A><BR>
+tuning performance <A HREF="ag/dsmanage.htm#996824">Tuning Directory Server Performance</A><BR>
+Unix <A HREF="ag/snmp.htm#1072951">Setting Up SNMP on UNIX</A><BR>
+Unix <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
+URL <A HREF="ag/url.htm#2836420">Examples of LDAP URLs</A><BR>
+user access <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+user access <A HREF="ag/acl.htm#1187588">Access Control Usage Examples</A><BR>
+user access <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+user access <A HREF="ag/acl.htm#997553">Defining User Access - userdn Keyword</A><BR>
+users <A HREF="ag/password.htm#1085796">Activating User and Roles Using the Console</A><BR>
+users <A HREF="ag/password.htm#1086206">Inactivating Users and Roles</A><BR>
+viewing <A HREF="ag/scmacfg.htm#1093547">Managing Attributes</A><BR>
+wildcards <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+wildcards <A HREF="ag/find.htm#1041100">Matching Rule Filter Syntax</A><BR>
+Windows NT <A HREF="ag/snmp.htm#1092550">About SNMP</A><BR>
diff --git a/ldap/dsml/European.dsml b/ldap/dsml/European.dsml
new file mode 100644
index 00000000..9e088409
--- /dev/null
+++ b/ldap/dsml/European.dsml
@@ -0,0 +1,17598 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- BEGIN COPYRIGHT BLOCK
+ Copyright 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ All rights reserved.
+ END COPYRIGHT BLOCK -->
+<dsml:dsml xmlns:dsml="http://www.dsml.org/DSML">
+ <dsml:directory-entries>
+ <dsml:entry dn="o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organization</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="aci">
+ <dsml:value>(target=ldap:///o=Çéliné Ändrè)(targetattr=*)(version 3.0; acl "acl1"; allow(write) userdn = "ldap:///self";)</dsml:value>
+ <dsml:value>(target=ldap:///o=Çéliné Ändrè)(targetattr=*)(version 3.0; acl "acl2"; allow(write) groupdn = "ldap:///cn=Directory Administrators, o=Çéliné Ändrè";)</dsml:value>
+ <dsml:value>(target=ldap:///o=Çéliné Ändrè)(targetattr=*)(version 3.0; acl "acl3"; allow(read, search, compare) userdn = "ldap:///anyone";)</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="o">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user0, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Babette Ryndérs's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user0@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Ryndérs</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user0</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Babette</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 788-4115</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Babette Ryndérs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Babette Ryndérs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user0</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ryndérs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Babette</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 849-2367</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user1, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>DeCoùrsin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is mÿrty DeCoùrsin's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user1@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>mÿrty DeCoùrsin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>mÿrty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 689-8883</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>mÿrty DeCoùrsin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>DeCoùrsin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>mÿrty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 747-7146</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user2, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Rôw O'Connér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user2@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Rôw O'Connér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Rôw</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 902-8784</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Rôw</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Rôw O'Connér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>O'Connér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>O'Connér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 376-2654</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user3, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kéñnon Fùndérbùrg's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user3@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Kéñnon Fùndérbùrg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user3</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kéñnon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 783-2318</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Kéñnon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kéñnon Fùndérbùrg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user3</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Fùndérbùrg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Fùndérbùrg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 153-3897</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user4, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Theadora Ebérle's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user4@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Theadora</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user4</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Theadora</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 817-4739</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Theadora Ebérle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user4</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Ebérle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ebérle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 627-3928</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Theadora Ebérle</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user5, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Dàsya Cozàrt's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user5@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Cozàrt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user5</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dàsya</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 741-9413</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dàsya Cozàrt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user5</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Dàsya Cozàrt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cozàrt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Dàsya</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 504-4394</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user6, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is mÿrv Callânân's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user6@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>mÿrv Callânân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>mÿrv</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user6</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>mÿrv</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 577-5852</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>mÿrv Callânân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user6</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Callânân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Callânân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 755-9341</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user7, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñäthan Ovâns's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user7@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Ovâns</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user7</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñäthan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 376-1666</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñäthan Ovâns</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user7</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Ñäthan Ovâns</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ovâns</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Ñäthan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 608-3694</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user8, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Takehiko Pröblems's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user8@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Pröblems</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user8</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Takehiko</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 155-3374</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Takehiko Pröblems</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user8</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Takehiko Pröblems</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Pröblems</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Takehiko</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 297-8847</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user9, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Bam Ålï's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user9@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Bam Ålï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user9</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bam</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 213-4553</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bam Ålï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user9</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Bam</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ålï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 273-8511</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Ålï</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user10, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Çándide Rùiz's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user10@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Rùiz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user10</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Çándide</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 774-5666</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Çándide Rùiz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user10</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Çándide Rùiz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rùiz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Çándide</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 281-1317</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user11, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Tàrqùinio</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Rôséñe Tàrqùinio's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user11@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Rôséñe Tàrqùinio</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user11</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Rôséñe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 512-5483</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Rôséñe Tàrqùinio</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user11</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tàrqùinio</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Rôséñe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 619-5503</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user12, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Dànte Petrèe's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user12@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Dànte Petrèe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user12</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dànte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 242-5548</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Dànte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dànte Petrèe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user12</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Petrèe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Petrèe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 386-8197</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user13, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Chuck Geoffrîon's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user13@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Geoffrîon</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user13</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Chuck</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 258-9175</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Chuck Geoffrîon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Chuck Geoffrîon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user13</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Geoffrîon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Chuck</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 158-4210</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user14, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Ållèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Elita Ållèën's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user14@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Elita Ållèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user14</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Elita</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 402-3263</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Elita Ållèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user14</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ållèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Elita</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 898-9817</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user15, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Cloris Binda's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user15@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Cloris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user15</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Cloris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 480-6181</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Cloris Binda</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user15</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Binda</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Binda</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 546-2488</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Cloris Binda</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user16, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Sue Bùschelmân's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user16@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Sue Bùschelmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user16</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 216-1496</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sue Bùschelmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user16</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Sue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bùschelmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 672-9915</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Bùschelmân</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user17, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Lottîë Robértö's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user17@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Robértö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user17</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lottîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 516-2779</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lottîë Robértö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user17</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Lottîë Robértö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Robértö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Lottîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 392-5788</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user18, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Meeks</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Dupuy Meeks's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user18@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Dupuy Meeks</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user18</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dupuy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 677-1437</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dupuy Meeks</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user18</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Meeks</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Dupuy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 733-6498</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user19, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Priscellà Kàrhùniemi's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user19@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Priscellà Kàrhùniemi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user19</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Priscellà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 565-3949</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Priscellà Kàrhùniemi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user19</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Priscellà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kàrhùniemi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 942-2120</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Kàrhùniemi</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user20, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ameliñé Fehr's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user20@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Ameliñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user20</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ameliñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 476-6348</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ameliñé Fehr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user20</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Fehr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Fehr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 214-2625</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Ameliñé Fehr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user21, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Mêrcedes Tùok's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user21@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Mêrcedes Tùok</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user21</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Mêrcedes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 956-7647</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Mêrcedes Tùok</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user21</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Mêrcedes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tùok</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 206-6042</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Tùok</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user22, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Drusîë Dynie's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user22@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Drusîë Dynie</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user22</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Drusîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 520-7607</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Drusîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Drusîë Dynie</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user22</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Dynie</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Dynie</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 594-6193</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user23, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Brigit Grèbil's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user23@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Grèbil</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user23</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Brigit</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 681-1102</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Brigit Grèbil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Brigit Grèbil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user23</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Grèbil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Brigit</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 251-1532</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user24, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Bêrget Càrdèën's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user24@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Bêrget Càrdèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user24</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bêrget</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 718-4689</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bêrget Càrdèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user24</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Bêrget</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Càrdèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 409-8342</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Càrdèën</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user25, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Älka Màrzella's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user25@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Màrzella</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user25</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Älka</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 901-8363</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Älka Màrzella</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Älka Màrzella</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user25</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Màrzella</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Älka</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 639-5063</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user26, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Äléña Newsom's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user26@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Newsom</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user26</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Äléña</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 841-7066</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Äléña Newsom</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user26</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Äléña Newsom</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Newsom</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Äléña</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 901-6553</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user27, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kaitlin Popp's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user27@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Popp</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user27</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kaitlin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 694-8789</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Kaitlin Popp</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kaitlin Popp</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user27</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Popp</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Kaitlin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 926-6751</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user28, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Sanae Wylïe's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user28@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Wylïe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user28</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sanae</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 566-6486</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sanae Wylïe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user28</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Sanae Wylïe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Wylïe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Sanae</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 294-8045</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user29, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kaylil Hàrdérsèën's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user29@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Kaylil Hàrdérsèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Kaylil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user29</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kaylil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 641-9726</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kaylil Hàrdérsèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user29</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hàrdérsèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Hàrdérsèën</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 487-1903</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user30, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Gêrm Scheér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user30@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Gêrm Scheér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user30</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gêrm</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 612-2598</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Gêrm</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gêrm Scheér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user30</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Scheér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Scheér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 748-7557</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user31, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kâty Woodhall's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user31@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Kâty Woodhall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user31</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kâty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 625-3084</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Kâty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kâty Woodhall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user31</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Woodhall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Woodhall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 605-5806</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user32, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Deât Livérmân's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user32@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Deât Livérmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user32</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Deât</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 986-7403</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Deât</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Deât Livérmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user32</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Livérmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Livérmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 281-1121</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user33, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Sivaji</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Sallÿanñé Sivaji's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user33@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Sallÿanñé Sivaji</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user33</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sallÿanñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 235-8018</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sallÿanñé Sivaji</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user33</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Sivaji</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Sallÿanñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 682-3120</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user34, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Jòò-Geok Rùdïåk's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user34@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Jòò-Geok</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user34</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jòò-Geok</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 930-3480</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jòò-Geok Rùdïåk</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user34</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Rùdïåk</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rùdïåk</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 917-2898</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Jòò-Geok Rùdïåk</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user35, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Coxall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Vasan Coxall's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user35@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Vasan Coxall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user35</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Vasan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 750-1454</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Vasan Coxall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user35</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Coxall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Vasan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 703-3700</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user36, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Gêrîïånna Godo's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user36@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Gêrîïånna Godo</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user36</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gêrîïånna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 198-6482</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gêrîïånna Godo</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user36</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Gêrîïånna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Godo</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 838-9697</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Godo</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user37, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Elio Sattlér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user37@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Sattlér</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user37</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Elio</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 900-1660</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Elio Sattlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Elio Sattlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user37</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Sattlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Elio</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 917-3195</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user38, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Doc Stêklasa's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user38@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Doc Stêklasa</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user38</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Doc</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 862-8846</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Doc</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Doc Stêklasa</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user38</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Stêklasa</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Stêklasa</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 916-6247</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user39, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Francisca O'Hàrä's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user39@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>O'Hàrä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user39</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Francisca</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 676-7596</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Francisca O'Hàrä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user39</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Francisca O'Hàrä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>O'Hàrä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Francisca</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 961-2275</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user40, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Wâtwick McCàrrön's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user40@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>McCàrrön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user40</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Wâtwick</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 259-9202</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Wâtwick McCàrrön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user40</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Wâtwick McCàrrön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>McCàrrön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Wâtwick</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 591-9833</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user41, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Dollëy Bùhlér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user41@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Bùhlér</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user41</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dollëy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 884-5242</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Dollëy Bùhlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dollëy Bùhlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user41</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bùhlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Dollëy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 205-8823</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user42, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Emÿd Artzér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user42@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Artzér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user42</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Emÿd</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 382-3440</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Emÿd Artzér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user42</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Emÿd Artzér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Artzér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Emÿd</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 862-4384</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user43, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Watérmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Feâtlëss Watérmân's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user43@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Feâtlëss Watérmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user43</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Feâtlëss</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 117-4653</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Feâtlëss Watérmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user43</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Watérmân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Feâtlëss</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 621-5937</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user44, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Base Frèiwald's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user44@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Base Frèiwald</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user44</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Base</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 946-6912</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Base Frèiwald</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user44</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Base</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Frèiwald</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 182-5600</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Frèiwald</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user45, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Loay Trîpp's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user45@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Loay</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user45</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Loay</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 236-3921</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Loay Trîpp</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user45</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Trîpp</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Trîpp</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 474-8085</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Loay Trîpp</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user46, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Tulip Seàrl's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user46@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Tulip Seàrl</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user46</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tulip</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 496-1732</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Tulip</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tulip Seàrl</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user46</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Seàrl</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Seàrl</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 100-8221</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user47, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Annalise Chrîstiân's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user47@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Annalise Chrîstiân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user47</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Annalise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 448-5803</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Annalise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Annalise Chrîstiân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user47</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Chrîstiân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Chrîstiân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 836-8262</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user48, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Hukam Tsonos's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user48@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Hukam Tsonos</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user48</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Hukam</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 725-4642</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Hukam Tsonos</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user48</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Hukam</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tsonos</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 154-3028</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Tsonos</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user49, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Samÿn Ålthérr's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user49@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Samÿn Ålthérr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Samÿn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user49</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Samÿn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 952-1200</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Samÿn Ålthérr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user49</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ålthérr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Ålthérr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 601-1486</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user50, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Bobette MacLàrèn's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user50@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>MacLàrèn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user50</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bobette</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 548-5417</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bobette MacLàrèn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user50</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Bobette MacLàrèn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>MacLàrèn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Bobette</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 656-3674</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user51, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Grîëtje Nérby's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user51@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Nérby</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user51</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Grîëtje</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 751-9226</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Grîëtje Nérby</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user51</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Grîëtje Nérby</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Nérby</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Grîëtje</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 231-4479</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user52, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Lùrléñe Chrîstie's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user52@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Lùrléñe Chrîstie</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user52</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lùrléñe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 301-7281</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lùrléñe Chrîstie</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user52</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Lùrléñe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Chrîstie</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 971-9928</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Chrîstie</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user53, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Izumi Tzùâng's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user53@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Izumi Tzùâng</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user53</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Izumi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 713-7080</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Izumi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Izumi Tzùâng</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user53</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tzùâng</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Tzùâng</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 687-4878</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user54, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Athât Armes's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user54@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Athât Armes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user54</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Athât</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 821-9285</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Athât Armes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user54</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Athât</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Armes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 232-9437</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Armes</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user55, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Siüôx Cipolla's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user55@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Cipolla</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user55</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Siüôx</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 947-1439</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Siüôx Cipolla</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Siüôx Cipolla</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user55</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cipolla</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Siüôx</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 689-2821</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user56, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Iain Hosking's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user56@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Iain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user56</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Iain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 663-9142</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Iain Hosking</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user56</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Hosking</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hosking</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 688-7595</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Iain Hosking</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user57, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñelîë Backshall's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user57@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Backshall</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user57</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñelîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 915-2589</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ñelîë Backshall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñelîë Backshall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user57</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Backshall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ñelîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 359-6248</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user58, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Jùnkin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Wéñxi Jùnkin's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user58@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Wéñxi Jùnkin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user58</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Wéñxi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 523-1466</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Wéñxi Jùnkin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user58</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jùnkin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Wéñxi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 839-7614</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user59, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Shanon Elsing's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user59@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Elsing</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user59</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Shanon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 318-9017</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Shanon Elsing</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user59</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Shanon Elsing</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Elsing</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Shanon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 878-7761</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user60, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Shellÿ Gräùsso's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user60@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Gräùsso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user60</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Shellÿ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 112-4893</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Shellÿ Gräùsso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user60</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Shellÿ Gräùsso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Gräùsso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Shellÿ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 144-2382</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user61, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñel Hairè's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user61@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Hairè</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user61</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 183-6682</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ñel Hairè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñel Hairè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user61</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hairè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ñel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 123-2391</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user62, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Güôtam Sawchùk's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user62@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Sawchùk</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user62</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Güôtam</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 159-3054</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Güôtam Sawchùk</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Güôtam Sawchùk</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user62</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Sawchùk</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Güôtam</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 660-8227</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user63, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Çárëna Crùickshânk's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user63@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Çárëna Crùickshânk</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user63</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Çárëna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 409-9679</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Çárëna Crùickshânk</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user63</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Çárëna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Crùickshânk</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 917-2113</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Crùickshânk</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user64, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Azàrî</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Wayñé Azàrî's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user64@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Wayñé Azàrî</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user64</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Wayñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 178-3864</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Wayñé Azàrî</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user64</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Azàrî</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Wayñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 402-4145</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user65, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Älëjandra Kräehèënbùehl's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user65@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Älëjandra Kräehèënbùehl</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user65</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Älëjandra</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 366-2521</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Älëjandra Kräehèënbùehl</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user65</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Älëjandra</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kräehèënbùehl</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 346-7450</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Kräehèënbùehl</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user66, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Lujanka Mùllâney's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user66@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Lujanka Mùllâney</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user66</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lujanka</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 191-3099</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Lujanka</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lujanka Mùllâney</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user66</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mùllâney</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Mùllâney</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 664-4612</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user67, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Beehlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Rudîë Beehlér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user67@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Rudîë Beehlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user67</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Rudîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 629-8753</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Rudîë Beehlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user67</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Beehlér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Rudîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 182-9015</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user68, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñicholë Gùpta's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user68@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Ñicholë Gùpta</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user68</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñicholë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 625-2732</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñicholë Gùpta</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user68</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Ñicholë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Gùpta</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 523-3570</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Gùpta</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user69, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Icy Äbräms's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user69@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Icy Äbräms</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Icy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user69</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Icy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 733-2123</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Icy Äbräms</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user69</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Äbräms</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Äbräms</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 576-6333</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user70, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Utillà Coddingtön's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user70@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Utillà Coddingtön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user70</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Utillà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 487-4984</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Utillà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Utillà Coddingtön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user70</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Coddingtön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Coddingtön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 740-8670</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user71, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Phöëbe Kérr's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user71@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Kérr</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user71</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Phöëbe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 931-2018</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Phöëbe Kérr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Phöëbe Kérr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user71</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kérr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Phöëbe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 841-8782</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user72, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Loñée Sampaleânù's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user72@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Loñée Sampaleânù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Loñée</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user72</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Loñée</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 640-6581</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Loñée Sampaleânù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user72</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Sampaleânù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Sampaleânù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 179-2375</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user73, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Euphemîïå Fùqùa's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user73@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Euphemîïå Fùqùa</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user73</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Euphemîïå</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 145-6394</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Euphemîïå Fùqùa</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user73</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Euphemîïå</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Fùqùa</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 102-6009</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Fùqùa</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user74, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Sallÿ Rossi's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user74@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Sallÿ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user74</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sallÿ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 558-4165</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sallÿ Rossi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user74</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Rossi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rossi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 684-4013</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Sallÿ Rossi</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user75, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Ingell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Aùrô Ingell's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user75@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Aùrô Ingell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user75</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Aùrô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 781-4916</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Aùrô Ingell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user75</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ingell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Aùrô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 933-7641</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user76, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Chûng-Cheûng Moghis's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user76@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Chûng-Cheûng</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user76</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Chûng-Cheûng</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 816-8335</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Chûng-Cheûng Moghis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user76</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Moghis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Moghis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 803-6378</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Chûng-Cheûng Moghis</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user77, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Chloris Plmçoop's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user77@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Plmçoop</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user77</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Chloris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 918-4524</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Chloris Plmçoop</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Chloris Plmçoop</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user77</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Plmçoop</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Chloris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 650-4673</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user78, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñiñétte SonHing's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user78@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Ñiñétte SonHing</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user78</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñiñétte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 576-5294</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñiñétte SonHing</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user78</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Ñiñétte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>SonHing</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 617-5968</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>SonHing</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user79, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kaylëy Râçùsch's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user79@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Kaylëy Râçùsch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user79</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kaylëy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 717-4144</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kaylëy Râçùsch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user79</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Kaylëy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Râçùsch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 387-6331</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Râçùsch</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user80, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is mÿry-Jañé Lafòrge's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user80@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Lafòrge</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user80</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>mÿry-Jañé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 517-7562</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>mÿry-Jañé Lafòrge</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user80</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>mÿry-Jañé Lafòrge</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lafòrge</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>mÿry-Jañé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 771-8452</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user81, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Ajérsch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Saba Ajérsch's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user81@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Saba Ajérsch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user81</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Saba</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 878-3769</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Saba Ajérsch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user81</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ajérsch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Saba</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 420-4793</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user82, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Achammÿ Blackweldér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user82@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Blackweldér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user82</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Achammÿ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 491-6719</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Achammÿ Blackweldér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user82</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Achammÿ Blackweldér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Blackweldér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Achammÿ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 839-3470</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user83, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kishor Râçcz's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user83@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Kishor Râçcz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user83</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kishor</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 191-2618</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kishor Râçcz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user83</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Kishor</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Râçcz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 171-3587</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Râçcz</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user84, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Sophi Hallïwill's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user84@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Sophi Hallïwill</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user84</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sophi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 533-5665</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sophi Hallïwill</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user84</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Sophi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hallïwill</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 836-6345</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Hallïwill</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user85, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kätîë Gotch's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user85@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Gotch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user85</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kätîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 597-8603</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kätîë Gotch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user85</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Kätîë Gotch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Gotch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Kätîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 153-7022</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user86, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Rachelë Basco's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user86@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Rachelë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user86</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Rachelë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 824-6348</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Rachelë Basco</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user86</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Basco</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Basco</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 221-7820</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Rachelë Basco</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user87, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Jon Espàrza's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user87@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Jon Espàrza</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user87</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 708-4813</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jon Espàrza</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user87</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Jon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Espàrza</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 884-7493</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Espàrza</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user88, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Rômmel Rembecki's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user88@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Rembecki</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user88</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Rômmel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 220-4436</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Rômmel Rembecki</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user88</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Rômmel Rembecki</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rembecki</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Rômmel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 879-1384</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user89, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is ViDà Lacasse's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user89@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>ViDà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user89</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ViDà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 618-3243</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ViDà Lacasse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user89</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Lacasse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lacasse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 542-2997</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>ViDà Lacasse</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user90, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Fey Dowding's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user90@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Fey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user90</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Fey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 655-1902</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Fey Dowding</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user90</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Dowding</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Dowding</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 340-1322</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Fey Dowding</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user91, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kast Faùlknér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user91@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Faùlknér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user91</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kast</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 737-5478</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kast Faùlknér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user91</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Kast Faùlknér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Faùlknér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Kast</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 781-9716</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user92, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Georßànñé Kùrîo's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user92@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Georßànñé Kùrîo</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user92</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Georßànñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 831-7990</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Georßànñé Kùrîo</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user92</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Georßànñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kùrîo</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 620-5043</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Kùrîo</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user93, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Dolorës Màrkovic's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user93@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Dolorës Màrkovic</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user93</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dolorës</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 374-9555</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Dolorës</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dolorës Màrkovic</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user93</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Màrkovic</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Màrkovic</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 879-3002</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user94, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Pätti Hollïngwòrth's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user94@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Pätti Hollïngwòrth</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user94</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Pätti</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 896-3530</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Pätti Hollïngwòrth</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user94</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Pätti</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hollïngwòrth</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 945-1799</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Hollïngwòrth</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user95, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>McCândless</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Gwéñdolÿn McCândless's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user95@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Gwéñdolÿn McCândless</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user95</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gwéñdolÿn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 426-8725</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gwéñdolÿn McCândless</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user95</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>McCândless</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Gwéñdolÿn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 442-3609</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user96, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Gusellà Rch's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user96@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Gusellà Rch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Gusellà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user96</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gusellà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 633-1074</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gusellà Rch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user96</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Rch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 645-8397</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user97, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Lyndel Whâng's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user97@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Lyndel Whâng</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user97</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lyndel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 581-4327</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lyndel Whâng</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user97</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Lyndel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Whâng</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 738-8516</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Whâng</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user98, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Cordelîïå Fatér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user98@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Cordelîïå</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user98</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Cordelîïå</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 251-4813</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Cordelîïå Fatér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user98</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Fatér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Fatér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 263-8972</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Cordelîïå Fatér</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user99, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Cristöfâto Boivin's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user99@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Boivin</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user99</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Cristöfâto</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 792-5496</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Cristöfâto Boivin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Cristöfâto Boivin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user99</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Boivin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Cristöfâto</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 573-1190</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user100, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Jûnina Khosräviâni's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user100@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Jûnina Khosräviâni</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Jûnina</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user100</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jûnina</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 710-2753</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jûnina Khosräviâni</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user100</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Khosräviâni</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Khosräviâni</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 187-4444</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user101, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Tushât Shackletön's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user101@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Tushât Shackletön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user101</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tushât</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 135-1925</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Tushât</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tushât Shackletön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user101</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Shackletön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Shackletön</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 197-1626</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user102, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Clovis Safah's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user102@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Clovis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user102</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Clovis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 964-2124</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Clovis Safah</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user102</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Safah</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Safah</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 141-3727</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Clovis Safah</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user103, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Xylina Hoyér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user103@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Xylina Hoyér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user103</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Xylina</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 107-8399</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Xylina</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Xylina Hoyér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user103</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hoyér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Hoyér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 145-4003</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user104, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Millâtd Colagrösso's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user104@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Millâtd Colagrösso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user104</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Millâtd</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 756-6465</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Millâtd Colagrösso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user104</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Millâtd</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Colagrösso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 636-9306</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Colagrösso</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user105, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kassandra Rollïns's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user105@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Kassandra Rollïns</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Kassandra</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user105</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kassandra</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 981-5317</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kassandra Rollïns</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user105</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rollïns</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Rollïns</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 398-5322</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user106, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Mêrrîëllë Itö's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user106@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Mêrrîëllë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user106</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Mêrrîëllë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 954-8385</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Mêrrîëllë Itö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user106</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Itö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Itö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 730-9253</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Mêrrîëllë Itö</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user107, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Annâtbor Seay's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user107@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Annâtbor</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user107</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Annâtbor</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 964-8926</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Annâtbor Seay</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user107</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Seay</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Seay</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 275-8841</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Annâtbor Seay</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user108, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Sibellë Clegg's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user108@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Clegg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user108</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sibellë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 153-4454</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sibellë Clegg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user108</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Sibellë Clegg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Clegg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Sibellë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 389-1302</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user109, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Çáthlëéñ Brèedlove's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user109@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Brèedlove</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user109</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Çáthlëéñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 282-5480</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Çáthlëéñ Brèedlove</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Çáthlëéñ Brèedlove</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user109</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Brèedlove</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Çáthlëéñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 841-7668</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user110, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Violëtte Ditko's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user110@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Ditko</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user110</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Violëtte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 239-7182</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Violëtte Ditko</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user110</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Violëtte Ditko</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ditko</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Violëtte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 901-7049</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user111, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Jany Magnùson's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user111@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Magnùson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jany</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 139-1045</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jany Magnùson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Jany Magnùson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Magnùson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Jany</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 338-3357</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user112, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Grîëtje Bïålkèëniùs's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user112@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Grîëtje Bïålkèëniùs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user112</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Grîëtje</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 739-6583</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Grîëtje Bïålkèëniùs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user112</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Grîëtje</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bïålkèëniùs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 836-2896</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Bïålkèëniùs</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user113, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Mozellë Frènch's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user113@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Mozellë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user113</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Mozellë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 469-2172</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Mozellë Frènch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user113</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Frènch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Frènch</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 621-1839</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Mozellë Frènch</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user114, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñonna Yahyapoùr's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user114@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Ñonna Yahyapoùr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user114</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñonna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 948-9261</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Ñonna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñonna Yahyapoùr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user114</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Yahyapoùr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Yahyapoùr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 802-4813</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user115, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Mirände</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Angelîë Mirände's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user115@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Angelîë Mirände</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user115</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Angelîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 832-8156</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Angelîë Mirände</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user115</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mirände</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Angelîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 720-5542</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user116, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is ÇáRôl-jean Sainsbùry's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user116@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>ÇáRôl-jean Sainsbùry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user116</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ÇáRôl-jean</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 462-8515</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>ÇáRôl-jean</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ÇáRôl-jean Sainsbùry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user116</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Sainsbùry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Sainsbùry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 987-8524</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user117, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ting Uffnér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user117@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Uffnér</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user117</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ting</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 276-1089</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ting Uffnér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ting Uffnér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user117</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Uffnér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ting</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 895-7043</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user118, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Lil Sells's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user118@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Lil Sells</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user118</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 914-4404</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lil Sells</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user118</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Lil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Sells</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 250-4206</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Sells</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user119, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñic Românchùck's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user119@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Românchùck</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user119</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñic</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 502-5442</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ñic Românchùck</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñic Românchùck</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user119</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Românchùck</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ñic</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 510-3084</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user120, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Violëtta Reinwald's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user120@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Reinwald</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user120</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Violëtta</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 422-8271</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Violëtta Reinwald</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Violëtta Reinwald</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user120</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Reinwald</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Violëtta</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 532-1292</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user121, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ramiz Systêst's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user121@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Ramiz Systêst</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user121</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ramiz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 972-5388</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Ramiz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ramiz Systêst</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user121</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Systêst</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Systêst</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 497-7314</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user122, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Diblér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Pätching Diblér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user122@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Pätching Diblér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user122</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Pätching</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 666-6668</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Pätching Diblér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user122</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Diblér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Pätching</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 163-3483</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user123, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Celÿñé Baskin's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user123@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Celÿñé Baskin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Celÿñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user123</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Celÿñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 186-7577</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Celÿñé Baskin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user123</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Baskin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Baskin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 929-8591</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user124, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Janîë Pàrdi's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user124@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Janîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user124</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Janîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 999-8165</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Janîë Pàrdi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user124</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Pàrdi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Pàrdi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 539-4548</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Janîë Pàrdi</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user125, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Aùrîë Brîsby's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user125@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Brîsby</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user125</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Aùrîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 769-1594</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Aùrîë Brîsby</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user125</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Aùrîë Brîsby</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Brîsby</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Aùrîë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 880-6179</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user126, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Klùtts</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Livvyy Klùtts's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user126@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Livvyy Klùtts</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user126</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Livvyy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 397-4012</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Livvyy Klùtts</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user126</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Klùtts</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Livvyy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 728-8013</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user127, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Sibillà Millspaùgh's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user127@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Sibillà Millspaùgh</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user127</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sibillà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 204-6815</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Sibillà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sibillà Millspaùgh</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user127</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Millspaùgh</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Millspaùgh</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 990-5705</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user128, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Äléña Milân's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user128@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Milân</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user128</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Äléña</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 303 570-2112</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Äléña Milân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Äléña Milân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user128</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Milân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Äléña</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 896-6336</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user129, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Hêrve McDade's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user129@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>McDade</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user129</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Hêrve</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 829-2873</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Hêrve McDade</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user129</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Hêrve McDade</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>McDade</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Hêrve</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 602-8199</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user130, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is SayeeDà Emesh's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user130@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>SayeeDà Emesh</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user130</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>SayeeDà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 427-1290</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>SayeeDà Emesh</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user130</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>SayeeDà</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Emesh</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 714 808-3656</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Emesh</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user131, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñeelÿ Tynân's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user131@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Tynân</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user131</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñeelÿ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 260-4462</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ñeelÿ Tynân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñeelÿ Tynân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user131</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tynân</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ñeelÿ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 705-2076</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user132, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñaji Flòrès's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user132@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Flòrès</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user132</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñaji</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 417-2310</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ñaji Flòrès</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñaji Flòrès</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user132</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Flòrès</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ñaji</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 818 784-8714</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user133, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is mÿùrise Pùglïå's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user133@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Pùglïå</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user133</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>mÿùrise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 346-5688</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>mÿùrise Pùglïå</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>mÿùrise Pùglïå</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user133</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Pùglïå</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>mÿùrise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 945-8392</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user134, ou=Çéliné Ändrè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Wañéta Vempati's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user134@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Wañéta Vempati</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user134</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Wañéta</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 651-3623</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Wañéta</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Wañéta Vempati</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user134</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Vempati</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Vempati</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 415 382-1034</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user135, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Lañéy Gröna's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user135@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Lañéy Gröna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user135</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lañéy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 317-9705</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Lañéy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lañéy Gröna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user135</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Gröna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Gröna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 125-9224</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user136, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Bayér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Muffin Bayér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user136@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Muffin Bayér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user136</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Muffin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 514-6302</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Muffin Bayér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user136</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bayér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Muffin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 383-3961</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user137, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Lingyan Cottingham's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user137@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>Lingyan Cottingham</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user137</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lingyan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 818 529-3823</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lingyan Cottingham</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user137</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>Lingyan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cottingham</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 177-7520</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Cottingham</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user138, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Corrëna Träsmùndi's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user138@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Träsmùndi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user138</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Corrëna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 774-3146</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Corrëna Träsmùndi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user138</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Corrëna Träsmùndi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Träsmùndi</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Corrëna</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 631-6660</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user139, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ñeil Chérrîér's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user139@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Ñeil Chérrîér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user139</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñeil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 474-5839</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Ñeil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñeil Chérrîér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user139</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Chérrîér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Chérrîér</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 516-3260</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user140, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Älfonso Waltérs's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user140@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Älfonso Waltérs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user140</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Älfonso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 607-3408</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Älfonso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Älfonso Waltérs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user140</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Waltérs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Waltérs</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 233-3644</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user141, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Collëte Wàrfel's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user141@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Wàrfel</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>user141</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Collëte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 360-5788</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Collëte Wàrfel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Collëte Wàrfel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user141</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Wàrfel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Collëte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 749-8263</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user142, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Kishor McAdòrèy's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user142@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Kishor McAdòrèy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Kishor</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user142</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kishor</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 714 433-5127</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kishor McAdòrèy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user142</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>McAdòrèy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>McAdòrèy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 510 752-1955</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user143, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Dûncan Schlïchting's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user143@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="sn;lang-be">
+ <dsml:value>Schlïchting</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user143</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dûncan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 717-9847</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dûncan Schlïchting</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user143</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-be">
+ <dsml:value>Dûncan Schlïchting</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schlïchting</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-be">
+ <dsml:value>Dûncan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 474-1501</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user144, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Valéñtîïå Gräcey's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user144@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Valéñtîïå Gräcey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Valéñtîïå</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user144</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Valéñtîïå</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 206 284-2530</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Valéñtîïå Gräcey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user144</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Gräcey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Gräcey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 206 909-3569</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user145, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Weisèënbérg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Ällëgra Weisèënbérg's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user145@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Ällëgra Weisèënbérg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user145</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ällëgra</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 415 348-1595</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ällëgra Weisèënbérg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user145</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Weisèënbérg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Ällëgra</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 804 623-1255</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user146, ou=Ännheimè, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is LLoyd Majùry's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user146@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-se">
+ <dsml:value>LLoyd Majùry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user146</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>LLoyd</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 213 109-3465</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>LLoyd Majùry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user146</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-se">
+ <dsml:value>LLoyd</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Majùry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ännheimè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 213 515-2132</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-se">
+ <dsml:value>Majùry</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user147, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Ellàdiñé Passin's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user147@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Ellàdiñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user147</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ellàdiñé</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 510 570-9369</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ellàdiñé Passin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user147</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Passin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Passin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 482-2946</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Ellàdiñé Passin</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user148, ou=Sàn Fråncêscô, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>This is Chantallë Secrèst's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user148@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-it">
+ <dsml:value>Chantallë Secrèst</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user148</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Chantallë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 726-9344</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-it">
+ <dsml:value>Chantallë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Chantallë Secrèst</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user148</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Secrèst</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Sàn Fråncêscô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-it">
+ <dsml:value>Secrèst</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 356-1611</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=user149, ou=Çlose Crèkä, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-ie">
+ <dsml:value>Tsitsiòr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>This is Dick Tsitsiòr's description</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="mail">
+ <dsml:value>user149@test.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-ie">
+ <dsml:value>Dick Tsitsiòr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>user149</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dick</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 804 768-4911</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dick Tsitsiòr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>user149</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tsitsiòr</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-ie">
+ <dsml:value>Dick</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Çlose Crèkä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 303 253-4009</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Root for Franch, German, and Spanish letters</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>European Letters</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>ÄÖÜäöüß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>German Letters</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Auf Deutsch</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Spanish Letters</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>á, é, í, ó, ü, ñ, Ã, É, Ã, Ó, Ú, Ãœ, Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>En Español</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>French 8Bit Letters</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>En Français</dsml:value>
+ <dsml:value>lang-fr: àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ä, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ö, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ü, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ß, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ä-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>Ä-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>Ä-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Ä-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ö-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>Ö-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>Ö-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Ö-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ü-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=á, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=é, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=í, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ó, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ü, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ñ, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ã-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=É-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ã-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ó-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ó-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>Ó-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ó-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ú-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ú-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>Ú-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ú-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ü-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ñ-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ñ-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>Ñ-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ñ-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=à, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=â, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ë, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=è, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=é, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ê, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ï, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=î, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ô, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ü, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=ù, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=û, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=À-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>À-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>À-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>À-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Â-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Â-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Â-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Â-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ç-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ç-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Ç-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ç-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ë-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ë-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Ë-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ë-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=È-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>È-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>È-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>È-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=É-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ê-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ê-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Ê-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ê-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ã-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Î-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>ÃŽ-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>ÃŽ-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>ÃŽ-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ô-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ô-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Ô-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ô-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ü-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Ù-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Ù-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Ù-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Ù-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Û-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Û-2</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Û-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Û-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=A, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=B, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=C, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=D, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=E, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=F, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=G, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=H, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=I, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=J, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=K, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=L, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=M, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=N, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=O, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=P, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Q, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=R, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=S, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=T, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=U, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=V, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=W, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=X, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Y, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Z, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="ou;lang-de">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="description">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=A, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=B, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=C, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=D, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=E, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=F, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=G, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=H, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=I, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=J, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=K, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=L, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=M, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=N, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=O, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=P, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Q, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=R, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=S, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=T, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=U, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=V, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=W, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=X, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Y, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Z, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-es">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=A, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=B, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=C, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=D, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=E, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=F, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=G, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=H, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=I, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=J, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=K, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=L, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=M, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=N, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=O, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=P, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Q, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=R, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=S, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=T, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=U, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=V, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=W, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=X, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Y, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Z, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou;lang-fr">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de1, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ä ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>ä ä</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de2 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ö ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>ö ö</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de3 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ü ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de3</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>ü ü</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de4 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ß ß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de4</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>ß ß</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de5 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ä Ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de5</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Ä Ä</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de6 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ö Ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de6</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Ö Ö</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de7 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ü Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de7</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Ü Ü</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es1 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>á á</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>á á</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es2 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>é é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>é é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es3 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>í í</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>í í</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es3</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es4 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ó ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>ó ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es4</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es5 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>ú</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ú ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>ú ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es5</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es6 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ü ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>ü ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es6</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es7 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ã Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ã Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es7</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es8 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>É</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>É É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>É É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es8</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es9 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ã Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ã Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es9</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es10 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Ó</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>Ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ó Ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ó Ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es10</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es11 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Ú</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>Ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ú Ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ú Ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es11</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es12 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ü Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ü Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es12</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es13 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ñ Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ñ Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es13</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es14 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ñ ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>ñ ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es14</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr1, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>à à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>à à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>â â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>â â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr3, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ç ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ç ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr3</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr4, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ë ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ë ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr4</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr5, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>è è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>è è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr5</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr6, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>é é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>é é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr6</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr7, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ê ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ê ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr7</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr8, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ï ï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ï ï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr8</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr9, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>î î</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>î î</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr9</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr10, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ô ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ô ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr10</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr12, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ü ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ü ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr12</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr13, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ù ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ù ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr13</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr14, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>û û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>û û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr14</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr15, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>À À</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>À</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>À</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>À À</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr15</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>À</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>À</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr16, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Â Â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Â Â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr16</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr17, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ç Ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ç Ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr17</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr18, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ë Ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ë Ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr18</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr19, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>È È</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>È</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>È</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>È È</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr19</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>È</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>È</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr20, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>É É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>É É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr20</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>É</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr21, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ê Ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ê Ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr21</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr22, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ã Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ã Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr22</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Ã</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr23, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ÃŽ ÃŽ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>ÃŽ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>ÃŽ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ÃŽ ÃŽ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr23</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>ÃŽ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>ÃŽ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr24, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ô Ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ô Ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr24</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr26, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ü Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ü Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr26</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr27, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ù Ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ù Ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr27</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr28, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Û Û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Û Û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr28</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de100, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>a a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de100</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>a a</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de101 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>b b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de101</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>b b</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de102 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>c c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de102</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>c c</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de103 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>d d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de103</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>d d</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de104, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>e e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de104</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>e e</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de105, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>f f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de105</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>f f</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de106, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>g g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de106</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>g g</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de107, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>h h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de107</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>h h</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de108, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>i i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de108</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>i i</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de109 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>j j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de109</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>j j</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de110 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>k k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de110</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>k k</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de111 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>l l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>l l</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de112, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>m m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de112</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>m m</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de113 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>n n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de113</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>n n</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de114 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>o o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de114</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>o o</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de115, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>p p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de115</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>p p</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de116 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>q q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de116</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>q q</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de117, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>r r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de117</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>r r</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de118 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>s s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de118</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>s s</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de119 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>t t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de119</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>t t</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de120 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>u u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de120</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>u u</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de121, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>v v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de121</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>v v</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de122 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>w w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de122</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>w w</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de123 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>x x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de123</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>x x</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de124, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>y y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de124</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>y y</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de125, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>z z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de125</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>z z</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de126, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>A A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de126</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>A A</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de127, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>B B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de127</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>B B</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de128, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>C C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de128</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>C C</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de129 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>D D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de129</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>D D</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de130 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>E E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de130</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>E E</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de131 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>F F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>F F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de131</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>F F</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de132, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>G G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de132</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>G G</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de133 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>H H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de133</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>H H</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de134 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>I I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de134</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>I I</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de135, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>J J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de135</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>J J</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de136 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>K K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de136</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>K K</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de137, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>L L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de137</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>L L</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de138 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>M M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de138</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>M M</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de139 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>N N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de139</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>N N</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de140 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>O O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de140</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>O O</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de141 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>P P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de141</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>P P</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de142, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Q Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de142</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Q Q</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de143 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>R R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de143</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>R R</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de144 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>S S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de144</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>S S</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de145, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>T T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de145</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>T T</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de146 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>U U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de146</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>U U</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de147, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>V V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de147</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>V V</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de148 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>W W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de148</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>W W</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de149 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>X X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de149</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>X X</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de150 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Y Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de150</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Y Y</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=de151 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname;lang-de">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Z Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>de151</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-de">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>de</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Z Z</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es100, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>a a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>a a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es100</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es101 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>b b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>b b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es101</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es102 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>c c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>c c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es102</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es103 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>d d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>d d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es103</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es104, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>e e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>e e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es104</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es105, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>f f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>f f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es105</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es106, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>g g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>g g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es106</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es107, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>h h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>h h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es107</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es108, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>i i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>i i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es108</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es109 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>j j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>j j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es109</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es110 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>k k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>k k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es110</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es111 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>l l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>l l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es112, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>m m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>m m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es112</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es113 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>n n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>n n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es113</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es114 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>o o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>o o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es114</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es115, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>p p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>p p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es115</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es116 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>q q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>q q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es116</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es117, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>r r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>r r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es117</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es118 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>s s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>s s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es118</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es119 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>t t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>t t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es119</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es120 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>u u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>u u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es120</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es121, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>v v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>v v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es121</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es122 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>w w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>w w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es122</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es123 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>x x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>x x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es123</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es124, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>y y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>y y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es124</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es125, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>z z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>z z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es125</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es126, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>A A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>A A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es126</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es127, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>B B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>B B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es127</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es128, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>C C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>C C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es128</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es129 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>D D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>D D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es129</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es130 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>E E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>E E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es130</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es131 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>F F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>F F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>F F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es131</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es132, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>G G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>G G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es132</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es133 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>H H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>H H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es133</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es134 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>I I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>I I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es134</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es135, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>J J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>J J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es135</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es136 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>K K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>K K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es136</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es137, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>L L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>L L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es137</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es138 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>M M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>M M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es138</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es139 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>N N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>N N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es139</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es140 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>O O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>O O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es140</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es141 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>P P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>P P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es141</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es142, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Q Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Q Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es142</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es143 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>R R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>R R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es143</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es144 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>S S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>S S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es144</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es145, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>T T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>T T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es145</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es146 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>U U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>U U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es146</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es147, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>V V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>V V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es147</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es148 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>W W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>W W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es148</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es149 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>X X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>X X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es149</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es150 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Y Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Y Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es150</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=es151 , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:attr name="sn;lang-es">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="givenname">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Z Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Z Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>es151</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-es">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>es</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr100, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>a a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>a a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr100</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>a</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr101 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>b b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>b b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr101</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>b</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr102 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>c c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>c c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr102</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>c</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr103 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>d d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>d d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr103</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>d</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr104, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>e e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>e e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr104</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>e</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr105, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>f f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>f f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr105</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>f</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr106, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>g g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>g g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr106</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>g</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr107, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>h h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>h h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr107</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>h</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr108, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>i i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>i i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr108</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>i</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr109 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>j j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>j j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr109</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>j</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr110 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>k k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>k k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr110</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>k</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr111 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>l l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>l l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>l</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr112, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>m m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>m m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr112</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>m</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr113 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>n n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>n n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr113</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>n</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr114 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>o o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>o o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr114</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>o</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr115, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>p p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>p p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr115</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>p</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr116 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>q q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>q q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr116</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr117, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>r r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>r r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr117</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>r</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr118 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>s s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>s s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr118</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>s</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr119 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>t t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>t t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr119</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>t</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr120 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>u u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>u u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr120</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>u</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr121, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>v v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>v v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr121</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>v</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr122 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>w w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>w w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr122</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>w</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr123 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>x x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>x x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr123</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>x</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr124, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>y y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>y y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr124</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr125, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>z z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>z z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr125</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr126, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>A A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>A A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr126</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr127, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>B B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>B B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr127</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr128, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>C C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>C C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr128</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr129 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>D D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>D D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr129</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr130 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>E E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>E E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr130</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr131 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>F F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>F F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>F F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr131</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr132, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>G G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>G G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr132</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr133 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>H H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>H H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr133</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr134 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>I I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>I I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr134</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr135, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>J J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>J J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr135</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr136 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>K K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>K K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr136</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr137, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>L L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>L L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr137</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr138 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>M M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>M M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr138</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr139 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>N N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>N N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr139</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr140 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>O O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>O O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr140</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr141 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>P P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>P P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr141</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr142, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Q Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Q Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr142</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr143 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>R R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>R R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr143</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr144 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>S S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>S S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr144</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr145, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>T T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>T T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr145</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr146 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>U U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>U U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr146</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr147, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>V V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>V V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr147</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr148 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>W W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>W W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr148</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr149 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>X X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>X X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr149</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr150 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Y Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Y Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr150</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=fr151 , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Z Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname;lang-fr">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Z Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>fr151</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn;lang-fr">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="preferredlanguage">
+ <dsml:value>fr</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=à , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>à</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr1, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=fr10, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=de7, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=de4, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es2, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es4, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es6, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=â, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>â</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr2, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ç</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr3, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ë, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ë</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr4, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=è, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>è</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr5, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=é, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr6, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ê, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ê</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr7, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ï, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ï</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=î, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>î</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ô, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ô</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ü, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ù, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ù</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=û, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>û</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=À-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>À-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>À-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>À-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Â-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Â-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Â-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Â-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ç-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ç-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ç-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ç-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ë-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ë-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ë-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ë-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=È-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>È-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>È-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>È-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=É-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ê-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ê-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ê-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ê-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ã-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Î-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>ÃŽ-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>ÃŽ-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ÃŽ-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ô-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ô-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ô-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ô-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ü-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ù-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Ù-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ù-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ù-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Û-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Û-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Û-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Û-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ä, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>ä</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ö, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>ö</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ü, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ß , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>ß</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ä-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Ä-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ä-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Ä-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ö-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Ö-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ö-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Ö-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ü-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=á, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>á</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=é, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>é</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=í, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>í</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ó, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ó</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ú , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>ú</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ú</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ü, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ü</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ã-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=É-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>É-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ã-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ã-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ó-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Ó-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ó-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ó-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ú-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Ú-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ú-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ú-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ü-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ü-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Ñ-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Ñ-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Ñ-2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Ñ-2</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=ñ, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>ñ</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=A , ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr111, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=fr106, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=de7, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=de134, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es2, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es4, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es116, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=B, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr2, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=C, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr3, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=D, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr4, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=E, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr5, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=F, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr6, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=G, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr7, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=H, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=I, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=J, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=K, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=L, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=M, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=N, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=O, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=P, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Q, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=R, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=S, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=T, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=U, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=V, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=W, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=X, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Y, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Z, ou=En Français, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-fr">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=A , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr111, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=fr106, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=de7, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=de134, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es2, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es4, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es116, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=B, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=C, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr3, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=D, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr4, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=E, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr5, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=F, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr6, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=G, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr7, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=H, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=I, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=J, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=K, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=L, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=M, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=N, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=O, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=P, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Q, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=R, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=S, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=T, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=U, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=V, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=W, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=X, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Y, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Z, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-de">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=A , ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>A</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr111, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=fr106, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=de7, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=de134, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es2, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es4, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=es116, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=B, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>B</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr2, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=C, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>C</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr3, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=D, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>D</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr4, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=E, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>E</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr5, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=F, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>F</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr6, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=G, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>G</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=fr7, ou=En Español, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=H, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>H</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=I, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>I</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=J, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>J</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=K, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>K</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=L, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>L</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=M, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>M</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=N, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>N</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=O, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>O</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=P, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>P</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Q, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Q</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=R, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>R</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=S, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>S</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=T, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>T</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=U, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>U</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=V, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>V</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=W, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>W</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=X, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>X</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Y, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Y</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Z, ou=En Español, ou=European Letters, o=Çéliné Ändrè">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn;lang-es">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn;lang-en">
+ <dsml:value>Z</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="o=àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>French Organization</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organization</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="businesscategory">
+ <dsml:value>àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="postaladdress">
+ <dsml:value>àâçëèéêï$1234$îôüùû$ÀÂÇËÈÉÊÃÎÔÜÙÛ 123$France 1234</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="seealso">
+ <dsml:value>cn=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=tbird, ou=People, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>ou=Bürger Preußens, ou=Çëû - Europé, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="o">
+ <dsml:value>àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>àâçëèéêïîôüùû$ÀÂÇËÈÉÊÃÎÔÜÙÛ</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="o=á é í ó ü ñ à É à Ó Ú Ü Ñ, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>Spanish Organization</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organization</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="businesscategory">
+ <dsml:value>á é í ó ü ñ à É à Ó Ú Ü Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="postaladdress">
+ <dsml:value>á é í ó ü ñ $1234$à É à Ó Ú Ü Ñ$Spain 54321</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>á é í ó ü ñ à É à Ó Ú Ü Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="seealso">
+ <dsml:value>cn=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>uid=tbird, ou=People, o=Çéliné Ändrè</dsml:value>
+ <dsml:value>ou=Bürger Preußens, ou=Çëû - Europé, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="o">
+ <dsml:value>á é í ó ü ñ à É à Ó Ú Ü Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>á é í ó ü ñ à É à Ó Ú Ü Ñ</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>á é í ó ü ñ à É à Ó Ú Ü Ñ$á é í ó ü ñ à É à Ó Ú Ü Ñ</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="o=ÄÖÜäöüß, o=Çéliné Ändrè">
+ <dsml:attr name="description">
+ <dsml:value>German Organization</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organization</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="businesscategory">
+ <dsml:value>ÄÖÜäöüß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="postaladdress">
+ <dsml:value>ÄÖÜäöüß$1234$ÄÖÜäöüß$Germany 12345</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>ÄÖÜäöüß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="seealso">
+ <dsml:value>cn=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="o">
+ <dsml:value>ÄÖÜäöüß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>ÄÖÜäöüß</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>ÄÖÜäöüß$ÄÖÜäöüß</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ </dsml:directory-entries>
+</dsml:dsml>
diff --git a/ldap/dsml/Example-roles.dsml b/ldap/dsml/Example-roles.dsml
new file mode 100644
index 00000000..dc3abffc
--- /dev/null
+++ b/ldap/dsml/Example-roles.dsml
@@ -0,0 +1,6514 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- BEGIN COPYRIGHT BLOCK
+ Copyright 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ All rights reserved.
+ END COPYRIGHT BLOCK -->
+<dsml:dsml xmlns:dsml="http://www.dsml.org/DSML">
+ <dsml:directory-entries>
+ <dsml:entry dn="dc=example,dc=com">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>domain</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="dc">
+ <dsml:value>example</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="aci">
+ <dsml:value>(target ="ldap:///dc=example,dc=com")(targetattr !="userPassword")(version 3.0;acl "Anonymous read-search access";allow (read, search, compare)(userdn = "ldap:///anyone");)</dsml:value>
+ <dsml:value>(target="ldap:///dc=example,dc=com") (targetattr = "*")(version 3.0; acl "allow all Admin role"; allow(all) roledn = "ldap:///cn=Directory Administrators,dc=example,dc=com";)</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Resource Limits COS,dc=example,dc=com">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>ldapSubEntry</dsml:oc-value>
+ <dsml:oc-value>cosSuperDefinition</dsml:oc-value>
+ <dsml:oc-value>cosClassicDefinition</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="costemplatedn">
+ <dsml:value>cn=Resource Limits COS,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cosspecifier">
+ <dsml:value>nsRole</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cosattribute">
+ <dsml:value>nsLookThroughLimit operational</dsml:value>
+ <dsml:value>nsSizeLimit operational</dsml:value>
+ <dsml:value>nsTimeLimit operational</dsml:value>
+ <dsml:value>nsIdleTimeout operational</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Resource Limits COS</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=&quot;cn=Directory Administrators,dc=example,dc=com&quot;,cn=Resource Limits COS,dc=example,dc=com">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>ldapSubEntry</dsml:oc-value>
+ <dsml:oc-value>cosTemplate</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cospriority">
+ <dsml:value>0</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsidletimeout">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>cn=Directory Administrators,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nstimelimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nslookthroughlimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nssizelimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Directory Administrators,dc=example,dc=com">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>LDAPsubentry</dsml:oc-value>
+ <dsml:oc-value>nsRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsSimpleRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsManagedRoleDefinition</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Directory Administrators</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=People, dc=example,dc=com">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalunit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="aci">
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr ="userpassword || telephonenumber || facsimiletelephonenumber")(version 3.0;acl "Allow self entry modification";allow (write)(userdn = "ldap:///self");)</dsml:value>
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr !="cn || sn || uid")(targetfilter ="(ou=Accounting)")(version 3.0;acl "Accounting Managers Role Permissions";allow (write) (roledn = "ldap:///cn=Accounting Managers,dc=example,dc=com");)</dsml:value>
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr !="cn || sn || uid")(targetfilter ="(ou=Human Resources)")(version 3.0;acl "HR Role Permissions";allow (write)(roledn = "ldap:///cn=HR Managers,dc=example,dc=com");)</dsml:value>
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr !="cn ||sn || uid")(targetfilter ="(ou=Product Testing)")(version 3.0;acl "QA Role Permissions";allow (write)(roledn = "ldap:///cn=QA Managers,dc=example,dc=com");)</dsml:value>
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr !="cn || sn || uid")(targetfilter ="(ou=Product Development)")(version 3.0;acl "Engineering Role Permissions";allow (write)(roledn = "ldap:///cn=PD Managers,dc=example,dc=com");)</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Special Users,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>Special Administrative Accounts</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Special Users</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=scarter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>scarter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sprain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sam</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4798</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sam Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>scarter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4612</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=Accounting Managers,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tmorris, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tmorris@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>irrefutable</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ted</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9187</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ted Morris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tmorris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4117</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Morris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=Accounting Managers,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kvaughan, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kvaughan@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>bribery</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kirsten</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5625</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kirsten Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kvaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2871</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=Directory Administrators,dc=example,dc=com</dsml:value>
+ <dsml:value>cn=HR Managers,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=abergin, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>abergin@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>inflict</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8585</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andy Bergin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>abergin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bergin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=QA Managers,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dmiller, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dmiller@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>gosling</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>David</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9423</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>David Miller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dmiller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4135</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Miller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=gfarmer, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>gfarmer@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>ruling</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gern</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6201</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gern Farmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>gfarmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1269</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Farmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kwinters, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kwinters@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>forsook</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9069</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kelly Winters</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kwinters</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4178</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Winters</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=PD Managers,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=trigden, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>trigden@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sensitive</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9280</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>trigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3584</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=PD Managers,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=cschmith, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>cschmith@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>hypotenuse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Chris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8011</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Chris Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>cschmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0416</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=HR Managers,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jwallace, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jwallace@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>linear</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Judy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0319</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Judy Wallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jwallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1033</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Wallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jwalker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jwalker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>dogleg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>John</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1476</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>John Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jwalker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3915</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=QA Managers,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tclow, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tclow@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>cardreader</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Clow</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tclow</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4376</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Clow</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rdaugherty, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rdaugherty@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>apples</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Robert</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1296</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Robert Daugherty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rdaugherty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0194</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Daugherty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=Directory Administrators,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jreuter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jreuter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>destroy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jayne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1122</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jayne Reuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jreuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2942</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Reuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tmason, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tmason@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>squatted</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1596</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Mason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tmason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1124</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bhall, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bhall@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>oranges</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Benjamin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6067</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Benjamin Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bhall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2511</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=btalbot, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>btalbot@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>trident</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Brad</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Brad Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>btalbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3532</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mward, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mward@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>normal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Marcus</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5688</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Marcus Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1707</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bjablons, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bjablons@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>strawberry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8815</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Jablonski</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bjablons</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0906</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jablonski</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jmcFarla, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jmcFarla@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>walnut</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Judy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2567</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Judy McFarland</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jmcFarla</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2359</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>McFarland</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=llabonte, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>llabonte@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sourdough</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0957</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lee Labonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>llabonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2854</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Labonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jcampaig, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jcampaig@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>grapevine</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jody</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1660</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jody Campaigne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jcampaig</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4385</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Campaigne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bhal2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bhal2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>truths</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4491</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bhal2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2758</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=alutz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>alutz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>northward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6505</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Alexander Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>alutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1327</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=btalbo2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>btalbo2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>corduroy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bjorn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4234</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bjorn Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>btalbo2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1205</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=achassin, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>achassin@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>duopolist</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ashley</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9972</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ashley Chassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>achassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0466</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Chassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=hmiller, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>hmiller@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>hillock</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Harry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9804</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Harry Miller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>hmiller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4304</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Miller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nsroledn">
+ <dsml:value>cn=Directory Administrators,dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jcampai2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jcampai2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>nominee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jeffrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7393</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jeffrey Campaigne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jcampai2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1377</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Campaigne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=lulrich, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>lulrich@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>attribution</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8652</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lee Ulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>lulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0985</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mlangdon, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mlangdon@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>threat</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Marcus</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6249</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Marcus Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mlangdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4471</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=striplet, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>striplet@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>compactify</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Stephen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4519</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Stephen Triplett</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>striplet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3083</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Triplett</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=gtriplet, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>gtriplet@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>placeable</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gern</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2582</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gern Triplett</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>gtriplet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4023</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Triplett</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jfalena, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jfalena@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>nightly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>John</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8133</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>John Falena</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jfalena</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1917</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Falena</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=speterso, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>speterso@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>quinine</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3613</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sue Peterson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>speterso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3073</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Peterson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ejohnson, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ejohnson@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>marketwise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Emanuel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3287</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Emanuel Johnson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ejohnson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3737</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Johnson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=prigden, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>prigden@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>epiphyseal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Peter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5099</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Peter Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>prigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1271</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bwalker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bwalker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>interruptible</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Brad</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5476</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Brad Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bwalker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3529</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>regulatory</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kurt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6127</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kurt Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1944</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mlott, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mlott@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>cognac</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Mike</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2234</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Mike Lott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mlott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0498</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=cwallace, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>cwallace@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>quintus</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Cecil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6438</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Cecil Wallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>cwallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0349</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Wallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tpierce, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tpierce@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>rascal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1531</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias Pierce</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tpierce</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1383</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Pierce</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rbannist, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rbannist@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>demonstrate</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Richard</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1833</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Richard Bannister</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rbannist</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0983</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bannister</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bplante, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bplante@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>tangerine</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Brian</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3550</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Brian Plante</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bplante</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4654</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Plante</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rmills, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rmills@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>condescend</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2072</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Mills</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rmills</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3823</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mills</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bschneid, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bschneid@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>biblical</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Benjamin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1012</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Benjamin Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bschneid</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4471</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=skellehe, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>skellehe@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sweltering</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3480</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sue Kelleher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>skellehe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1608</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kelleher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=brentz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>brentz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>diachronic</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bertram</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5526</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bertram Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>brentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0617</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dsmith, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dsmith@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>quantitative</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Daniel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9519</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Daniel Smith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dsmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0368</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Smith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=scarte2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>scarte2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>scooter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Stephen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6022</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Stephen Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>scarte2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2013</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dthorud, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dthorud@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>fulcrum</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>David</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6185</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>David Thorud</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dthorud</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1128</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Thorud</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ekohler, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ekohler@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>guildhall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Elba</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1926</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Elba Kohler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ekohler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kohler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=lcampbel, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>lcampbel@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>impress</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Laurel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2537</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Laurel Campbell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>lcampbel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2073</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Campbell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tlabonte, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tlabonte@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>express</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tim</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0058</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tim Labonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tlabonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1426</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Labonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=slee, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>slee@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>revertive</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Scott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2335</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Scott Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>slee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1806</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bfree, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bfree@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>etiquette</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bjorn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8588</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bjorn Free</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bfree</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3307</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Free</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tschneid, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tschneid@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>chaperone</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7086</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tschneid</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2292</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=prose, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>prose@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>regatta</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Paula</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9998</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Paula Rose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>prose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0542</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jhunter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jhunter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>nanometer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Janet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7665</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Janet Hunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jhunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4856</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ashelton, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ashelton@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>appointe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1081</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Alexander Shelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ashelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1987</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Shelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mmcinnis, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mmcinnis@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>calcify</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Marcus</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9655</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Marcus Mcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mmcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4818</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=falbers, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>falbers@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>degradation</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Frank</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3094</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Frank Albers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>falbers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1439</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Albers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mschneid, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mschneid@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>motorcycle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Martin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5017</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Martin Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mschneid</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3153</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=pcruse, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>pcruse@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>pauper</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Patricia</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8641</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Patricia Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>pcruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3967</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tkelly, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tkelly@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>risible</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Timothy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4295</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Timothy Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tkelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3107</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ahel, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ahel@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sarsaparilla</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andrew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2666</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andrew Hel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ahel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0572</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jburrell, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jburrell@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>degrease</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>James</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>James Burrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jburrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4926</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Burrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=smason, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>smason@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sensible</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9780</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sue Mason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>smason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4971</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ptyler, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ptyler@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>vinegar</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Pete</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3335</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Pete Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ptyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0327</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=calexand, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>calexand@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>dauphin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Chris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9438</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Chris Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>calexand</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2884</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jcruse, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jcruse@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>bridgework</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jim</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9482</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jim Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jcruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0083</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kcarter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kcarter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>radiosonde</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Karen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4675</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Karen Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kcarter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2320</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rfish, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rfish@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>mailbox</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9865</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Fish</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rfish</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2317</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Fish</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=phunt, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>phunt@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>wastewater</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Philip</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1242</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Philip Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>phunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1183</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rschneid, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rschneid@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>decorous</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Rachel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9908</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Rachel Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rschneid</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4183</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>hifalutin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1862</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Jensen</dsml:value>
+ <dsml:value>Babs Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0209</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jlange, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jlange@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>chastity</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jim</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0488</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jim Lange</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jlange</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3798</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lange</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rulrich, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rulrich@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>twinkle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5311</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Ulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1282</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rfrancis, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rfrancis@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>hacienda</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Richard</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8157</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Richard Francis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rfrancis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3482</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Francis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mwhite, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mwhite@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>staple</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Morgan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9620</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Morgan White</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mwhite</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3088</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>White</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=gjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>gjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>primitive</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gern</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3299</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gern Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>gjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4609</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=awhite, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>awhite@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>placeholder</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Alan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3232</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Alan White</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>awhite</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0142</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>White</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bmaddox, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bmaddox@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>feedback</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7783</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Maddox</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bmaddox</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2207</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Maddox</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mtalbot, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mtalbot@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>currant</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Martin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9228</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Martin Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mtalbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1415</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jbrown, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jbrown@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>militiamen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Judy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6885</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Judy Brown</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jbrown</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4224</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Brown</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>borderland</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jody</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7587</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jody Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4882</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mcarter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mcarter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>mainland</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Mike</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1846</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Mike Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mcarter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3819</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dakers, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dakers@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>integument</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>David</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4812</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>David Akers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dakers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4944</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Akers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=sfarmer, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>sfarmer@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>triumphal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Scott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4228</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Scott Farmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>sfarmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0019</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Farmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dward, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dward@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>armload</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Daniel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5322</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Daniel Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3927</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tward, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tward@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>cedilla</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7202</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2238</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=pshelton, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>pshelton@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>nosedive</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Patricia</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6442</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Patricia Shelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>pshelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2918</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Shelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jrentz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jrentz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>meander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jody</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5829</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jody Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jrentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3025</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=plorig, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>plorig@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>calorimeter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Peter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0624</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Peter Lorig</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>plorig</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1276</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lorig</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ajensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ajensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>coltsfoot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Allison</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7892</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Allison Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ajensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0784</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kschmith, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kschmith@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>purvey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9749</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kelly Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kschmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2221</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=pworrell, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>pworrell@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>solicitous</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Pete</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1637</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Pete Worrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>pworrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2449</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Worrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mreuter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mreuter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>oblivious</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Matthew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6879</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Matthew Reuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mreuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1356</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Reuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=gtyler, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>gtyler@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>typology</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gern</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1020</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gern Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>gtyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0312</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tschmith, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tschmith@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>compost</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9626</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tschmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4607</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bjense2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bjense2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>mortgage</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bjorn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5655</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bjorn Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bjense2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4294</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dswain, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dswain@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>freedom</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dietrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9222</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dietrich Swain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dswain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4396</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Swain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ahall, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ahall@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>slater</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6169</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andy Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ahall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3050</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jmuffly, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jmuffly@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>dictate</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jeff</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5287</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jeff Muffly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jmuffly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0997</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Muffly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>ecosystem</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ted</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8622</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ted Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4717</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ahunter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ahunter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>egregious</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Allison</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7713</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Allison Hunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ahunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1213</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jgoldste, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jgoldste@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>yellow</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5769</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jon Goldstein</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jgoldste</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1454</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Goldstein</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=aworrell, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>aworrell@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>gargoyle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Alan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1591</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Alan Worrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>aworrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3966</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Worrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=wlutz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>wlutz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>bassinet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Wendy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3358</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Wendy Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>wlutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4912</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jlutz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jlutz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>autumn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Janet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4902</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Janet Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jlutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2544</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dlangdon, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dlangdon@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>botulin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7044</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dan Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dlangdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3263</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=aknutson, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>aknutson@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>maltose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ashley</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2169</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ashley Knutson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>aknutson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4736</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Knutson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kmcinnis, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kmcinnis@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>stargaze</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8596</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kelly Mcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kmcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4312</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tcouzens, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tcouzens@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>tambourine</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Trent</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8401</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Trent Couzens</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tcouzens</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3994</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Couzens</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=lstockto, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>lstockto@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>brooklyn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0518</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lee Stockton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>lstockto</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0169</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Stockton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jbourke, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jbourke@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>brainwash</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8541</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jon Bourke</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jbourke</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0034</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bourke</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dlanoway, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dlanoway@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>manhattan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2017</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dan Lanoway</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dlanoway</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3540</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lanoway</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kcope, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kcope@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>forfeiture</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Karl</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2709</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Karl Cope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kcope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3040</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=abarnes, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>abarnes@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>chevron</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Anne-Louise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9445</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Anne-Louise Barnes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>abarnes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2290</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Barnes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>disciplinarian</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Richard</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5957</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Richard Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2631</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=phun2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>phun2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>absorb</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Pete</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0342</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Pete Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>phun2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0087</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mvaughan, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mvaughan@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>submitted</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Matthew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4692</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Matthew Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mvaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4508</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jlut2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jlut2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>shrank</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>James</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9689</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>James Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jlut2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3541</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mjablons, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mjablons@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>minimal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Morgan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0813</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Morgan Jablonski</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mjablons</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3160</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jablonski</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=pchassin, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>pchassin@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>barbital</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Peter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2816</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Peter Chassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>pchassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4524</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Chassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dcope, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dcope@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>snifter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9813</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dan Cope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dcope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1737</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jrent2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jrent2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>tachistoscope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Judy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2523</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Judy Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jrent2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4405</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tcruse, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tcruse@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>flinty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5980</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tcruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4191</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=eward, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>eward@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>episcopal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Eric</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2320</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Eric Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>eward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4874</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ttully, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ttully@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>schooner</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2274</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Tully</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ttully</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3924</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tully</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=charvey, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>charvey@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>journalese</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Cecil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1815</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Cecil Harvey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>charvey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4583</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Harvey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rfisher, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rfisher@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>pomegranate</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1506</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Fisher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rfisher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1579</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Fisher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=alangdon, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>alangdon@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>muzzle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andrew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8289</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andrew Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>alangdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2254</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=drose, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>drose@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>gubernatorial</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>David</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3963</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>David Rose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>drose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4012</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=polfield, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>polfield@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>monologue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Peter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8231</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Peter Olfield</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>polfield</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1376</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Olfield</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=awalker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>awalker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>detonable</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9199</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andy Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>awalker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0061</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=lrentz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>lrentz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>calcium</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lex</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2019</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lex Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>lrentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2203</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jvaughan, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jvaughan@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>appoint</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jeff</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4543</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jeff Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jvaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1734</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bfrancis, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bfrancis@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>holystone</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Francis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bfrancis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3743</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Francis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ewalker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ewalker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>beguile</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Eric</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6387</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Eric Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ewalker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2295</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tjames, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tjames@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>turtle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2458</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias James</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tjames</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0730</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>James</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=brigden, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>brigden@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>purple</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bjorn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5263</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bjorn Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>brigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1643</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ecruse, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ecruse@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>platelet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Eric</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0648</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Eric Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ecruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4233</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rjense2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rjense2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>transpose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9045</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rjense2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1984</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rhunt, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rhunt@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>becloud</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Richard</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0139</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Richard Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rhunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0718</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bparker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bparker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>lenticular</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4647</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barry Parker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bparker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1148</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Parker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ealexand, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ealexand@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>galactose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Erin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5563</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Erin Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ealexand</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2434</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mtyler, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mtyler@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>instantiate</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Matthew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7907</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Matthew Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mtyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2701</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=elott, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>elott@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>holdout</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Emanuel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0932</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Emanuel Lott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>elott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3906</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=cnewport, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>cnewport@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>expertise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Christoph</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0066</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Christoph Newport</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>cnewport</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0056</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Newport</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jvedder, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jvedder@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>befitting</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jeff</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4668</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jeff Vedder</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jvedder</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3445</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Vedder</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Accounting Managers,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>People who can manage accounting entries</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>LDAPsubentry</dsml:oc-value>
+ <dsml:oc-value>nsRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsSimpleRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsManagedRoleDefinition</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Accounting Managers</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=HR Managers,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>People who can manage HR entries</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>LDAPsubentry</dsml:oc-value>
+ <dsml:oc-value>nsRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsSimpleRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsManagedRoleDefinition</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>HR Managers</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=QA Managers,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>People who can manage QA entries</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>LDAPsubentry</dsml:oc-value>
+ <dsml:oc-value>nsRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsSimpleRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsManagedRoleDefinition</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>QA Managers</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=PD Managers,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>People who can manage engineer entries</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>LDAPsubentry</dsml:oc-value>
+ <dsml:oc-value>nsRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsSimpleRoleDefinition</dsml:oc-value>
+ <dsml:oc-value>nsManagedRoleDefinition</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>PD Managers</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Netscape Servers,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>Standard branch for Netscape Server registration</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Netscape Servers</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ </dsml:directory-entries>
+</dsml:dsml>
diff --git a/ldap/dsml/Example.dsml b/ldap/dsml/Example.dsml
new file mode 100644
index 00000000..cb903e00
--- /dev/null
+++ b/ldap/dsml/Example.dsml
@@ -0,0 +1,6501 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!-- BEGIN COPYRIGHT BLOCK
+ Copyright 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ All rights reserved.
+ END COPYRIGHT BLOCK -->
+<dsml:dsml xmlns:dsml="http://www.dsml.org/DSML">
+ <dsml:directory-entries>
+ <dsml:entry dn="dc=example,dc=com">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>domain</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="dc">
+ <dsml:value>example</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="aci">
+ <dsml:value>(target ="ldap:///dc=example,dc=com")(targetattr !="userPassword")(version 3.0;acl "Anonymous read-search access";allow (read, search, compare)(userdn = "ldap:///anyone");)</dsml:value>
+ <dsml:value>(target="ldap:///dc=example,dc=com") (targetattr = "*")(version 3.0; acl "allow all Admin group"; allow(all) groupdn = "ldap:///cn=Directory Administrators,ou=Groups,dc=example,dc=com";)</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Groups, dc=example,dc=com">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalunit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Groups</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Directory Administrators, ou=Groups, dc=example,dc=com">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupofuniquenames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Directory Administrators</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=kvaughan, ou=People, dc=example,dc=com</dsml:value>
+ <dsml:value>uid=rdaugherty, ou=People, dc=example,dc=com</dsml:value>
+ <dsml:value>uid=hmiller, ou=People, dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Groups</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=People, dc=example,dc=com">
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalunit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="aci">
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr ="userpassword || telephonenumber || facsimiletelephonenumber")(version 3.0;acl "Allow self entry modification";allow (write)(userdn = "ldap:///self");)</dsml:value>
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr !="cn || sn || uid")(targetfilter ="(ou=Accounting)")(version 3.0;acl "Accounting Managers Group Permissions";allow (write) (groupdn = "ldap:///cn=Accounting Managers,ou=groups,dc=example,dc=com");)</dsml:value>
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr !="cn || sn || uid")(targetfilter ="(ou=Human Resources)")(version 3.0;acl "HR Group Permissions";allow (write)(groupdn = "ldap:///cn=HR Managers,ou=groups,dc=example,dc=com");)</dsml:value>
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr !="cn ||sn || uid")(targetfilter ="(ou=Product Testing)")(version 3.0;acl "QA Group Permissions";allow (write)(groupdn = "ldap:///cn=QA Managers,ou=groups,dc=example,dc=com");)</dsml:value>
+ <dsml:value>(target ="ldap:///ou=People,dc=example,dc=com")(targetattr !="cn || sn || uid")(targetfilter ="(ou=Product Development)")(version 3.0;acl "Engineering Group Permissions";allow (write)(groupdn = "ldap:///cn=PD Managers,ou=groups,dc=example,dc=com");)</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Special Users,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>Special Administrative Accounts</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Special Users</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=scarter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>scarter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sprain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sam</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4798</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sam Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>scarter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4612</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tmorris, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tmorris@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>irrefutable</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ted</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9187</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ted Morris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tmorris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4117</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Morris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kvaughan, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kvaughan@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="nsidletimeout">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>bribery</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kirsten</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5625</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kirsten Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kvaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2871</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nstimelimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nslookthroughlimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nssizelimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=abergin, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>abergin@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>inflict</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8585</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andy Bergin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>abergin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bergin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dmiller, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dmiller@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>gosling</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>David</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9423</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>David Miller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dmiller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4135</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Miller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=gfarmer, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>gfarmer@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>ruling</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gern</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6201</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gern Farmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>gfarmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1269</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Farmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kwinters, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kwinters@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>forsook</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9069</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kelly Winters</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kwinters</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4178</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Winters</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=trigden, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>trigden@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sensitive</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9280</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>trigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3584</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=cschmith, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>cschmith@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>hypotenuse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Chris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8011</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Chris Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>cschmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0416</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jwallace, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jwallace@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>linear</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Judy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0319</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Judy Wallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jwallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1033</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Wallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jwalker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jwalker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>dogleg</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>John</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1476</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>John Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jwalker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3915</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tclow, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tclow@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>cardreader</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Clow</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tclow</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4376</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Clow</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rdaugherty, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rdaugherty@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="nsidletimeout">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>apples</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Robert</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1296</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Robert Daugherty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rdaugherty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0194</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Daugherty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nstimelimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nslookthroughlimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nssizelimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jreuter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jreuter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>destroy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jayne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1122</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jayne Reuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jreuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2942</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Reuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tmason, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tmason@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>squatted</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1596</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Mason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tmason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1124</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bhall, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bhall@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>oranges</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Benjamin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6067</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Benjamin Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bhall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2511</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=btalbot, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>btalbot@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>trident</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Brad</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Brad Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>btalbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3532</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mward, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mward@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>normal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Marcus</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5688</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Marcus Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1707</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bjablons, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bjablons@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>strawberry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8815</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Jablonski</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bjablons</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0906</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jablonski</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jmcFarla, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jmcFarla@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>walnut</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Judy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2567</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Judy McFarland</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jmcFarla</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2359</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>McFarland</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=llabonte, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>llabonte@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sourdough</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0957</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lee Labonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>llabonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2854</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Labonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jcampaig, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jcampaig@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>grapevine</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jody</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1660</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jody Campaigne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jcampaig</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4385</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Campaigne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bhal2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bhal2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>truths</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4491</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bhal2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2758</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=alutz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>alutz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>northward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6505</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Alexander Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>alutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1327</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=btalbo2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>btalbo2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>corduroy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bjorn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4234</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bjorn Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>btalbo2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1205</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=achassin, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>achassin@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>duopolist</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ashley</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9972</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ashley Chassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>achassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0466</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Chassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=hmiller, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>hmiller@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="nsidletimeout">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="userpassword">
+ <dsml:value>hillock</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Harry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9804</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Harry Miller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>hmiller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4304</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Miller</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nstimelimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nslookthroughlimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="nssizelimit">
+ <dsml:value>-1</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jcampai2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jcampai2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>nominee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jeffrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7393</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jeffrey Campaigne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jcampai2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1377</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Campaigne</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=lulrich, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>lulrich@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>attribution</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8652</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lee Ulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>lulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0985</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mlangdon, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mlangdon@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>threat</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Marcus</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6249</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Marcus Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mlangdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4471</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=striplet, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>striplet@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>compactify</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Stephen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4519</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Stephen Triplett</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>striplet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3083</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Triplett</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=gtriplet, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>gtriplet@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>placeable</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gern</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2582</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gern Triplett</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>gtriplet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4023</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Triplett</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jfalena, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jfalena@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>nightly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>John</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8133</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>John Falena</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jfalena</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1917</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Falena</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=speterso, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>speterso@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>quinine</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3613</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sue Peterson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>speterso</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3073</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Peterson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ejohnson, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ejohnson@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>marketwise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Emanuel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3287</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Emanuel Johnson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ejohnson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3737</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Johnson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=prigden, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>prigden@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>epiphyseal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Peter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5099</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Peter Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>prigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1271</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bwalker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bwalker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>interruptible</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Brad</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5476</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Brad Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bwalker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3529</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>regulatory</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kurt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6127</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kurt Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1944</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mlott, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mlott@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>cognac</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Mike</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2234</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Mike Lott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mlott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0498</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=cwallace, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>cwallace@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>quintus</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Cecil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6438</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Cecil Wallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>cwallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0349</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Wallace</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tpierce, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tpierce@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>rascal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1531</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias Pierce</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tpierce</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1383</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Pierce</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rbannist, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rbannist@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>demonstrate</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Richard</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1833</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Richard Bannister</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rbannist</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0983</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bannister</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bplante, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bplante@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>tangerine</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Brian</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3550</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Brian Plante</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bplante</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4654</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Plante</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rmills, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rmills@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>condescend</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2072</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Mills</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rmills</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3823</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mills</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bschneid, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bschneid@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>biblical</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Benjamin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1012</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Benjamin Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bschneid</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4471</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=skellehe, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>skellehe@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sweltering</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3480</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sue Kelleher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>skellehe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1608</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kelleher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=brentz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>brentz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>diachronic</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bertram</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5526</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bertram Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>brentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0617</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dsmith, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dsmith@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>quantitative</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Daniel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9519</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Daniel Smith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dsmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0368</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Smith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=scarte2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>scarte2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>scooter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Stephen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6022</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Stephen Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>scarte2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2013</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dthorud, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dthorud@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>fulcrum</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>David</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6185</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>David Thorud</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dthorud</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1128</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Thorud</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ekohler, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ekohler@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>guildhall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Elba</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1926</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Elba Kohler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ekohler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kohler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=lcampbel, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>lcampbel@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>impress</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Laurel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2537</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Laurel Campbell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>lcampbel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2073</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Campbell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tlabonte, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tlabonte@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>express</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tim</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0058</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tim Labonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tlabonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1426</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Labonte</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=slee, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>slee@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>revertive</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Scott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2335</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Scott Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>slee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1806</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bfree, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bfree@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>etiquette</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bjorn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8588</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bjorn Free</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bfree</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3307</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Free</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tschneid, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tschneid@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>chaperone</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7086</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tschneid</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2292</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=prose, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>prose@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>regatta</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Paula</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9998</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Paula Rose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>prose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0542</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jhunter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jhunter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>nanometer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Janet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7665</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Janet Hunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jhunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4856</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ashelton, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ashelton@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>appointe</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1081</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Alexander Shelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ashelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1987</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Shelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mmcinnis, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mmcinnis@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>calcify</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Marcus</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9655</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Marcus Mcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mmcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4818</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=falbers, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>falbers@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>degradation</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Frank</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3094</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Frank Albers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>falbers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1439</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Albers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mschneid, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mschneid@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>motorcycle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Martin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5017</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Martin Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mschneid</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3153</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=pcruse, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>pcruse@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>pauper</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Patricia</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8641</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Patricia Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>pcruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3967</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tkelly, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tkelly@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>risible</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Timothy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4295</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Timothy Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tkelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3107</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ahel, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ahel@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sarsaparilla</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andrew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2666</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andrew Hel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ahel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0572</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jburrell, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jburrell@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>degrease</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>James</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>James Burrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jburrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4926</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Burrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=smason, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>smason@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>sensible</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Sue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9780</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Sue Mason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>smason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4971</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mason</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ptyler, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ptyler@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>vinegar</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Pete</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3335</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Pete Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ptyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0327</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=calexand, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>calexand@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>dauphin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Chris</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9438</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Chris Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>calexand</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2884</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jcruse, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jcruse@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>bridgework</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jim</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9482</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jim Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jcruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0083</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kcarter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kcarter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>radiosonde</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Karen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4675</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Karen Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kcarter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2320</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rfish, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rfish@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>mailbox</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9865</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Fish</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rfish</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2317</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Fish</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=phunt, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>phunt@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>wastewater</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Philip</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1242</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Philip Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>phunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1183</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rschneid, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rschneid@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>decorous</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Rachel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9908</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Rachel Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rschneid</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4183</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schneider</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>hifalutin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1862</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Jensen</dsml:value>
+ <dsml:value>Babs Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0209</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jlange, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jlange@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>chastity</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jim</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0488</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jim Lange</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jlange</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3798</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lange</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rulrich, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rulrich@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>twinkle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5311</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Ulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1282</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ulrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rfrancis, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rfrancis@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>hacienda</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Richard</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8157</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Richard Francis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rfrancis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3482</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Francis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mwhite, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mwhite@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>staple</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Morgan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9620</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Morgan White</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mwhite</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3088</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>White</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=gjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>gjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>primitive</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gern</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3299</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gern Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>gjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4609</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=awhite, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>awhite@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>placeholder</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Alan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3232</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Alan White</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>awhite</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0142</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>White</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bmaddox, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bmaddox@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>feedback</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7783</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Maddox</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bmaddox</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2207</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Maddox</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mtalbot, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mtalbot@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>currant</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Martin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9228</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Martin Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mtalbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1415</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Talbot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jbrown, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jbrown@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>militiamen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Judy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6885</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Judy Brown</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jbrown</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4224</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Brown</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>borderland</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jody</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7587</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jody Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4882</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mcarter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mcarter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>mainland</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Mike</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1846</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Mike Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mcarter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3819</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Carter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dakers, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dakers@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>integument</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>David</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4812</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>David Akers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dakers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4944</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Akers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=sfarmer, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>sfarmer@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>triumphal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Scott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4228</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Scott Farmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>sfarmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0019</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Farmer</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dward, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dward@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>armload</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Daniel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5322</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Daniel Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3927</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tward, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tward@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>cedilla</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7202</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2238</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=pshelton, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>pshelton@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>nosedive</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Patricia</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6442</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Patricia Shelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>pshelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2918</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Shelton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jrentz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jrentz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>meander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jody</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5829</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jody Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jrentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3025</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=plorig, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>plorig@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>calorimeter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Peter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0624</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Peter Lorig</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>plorig</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1276</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lorig</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ajensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ajensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>coltsfoot</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Allison</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7892</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Allison Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ajensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0784</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kschmith, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kschmith@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>purvey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9749</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kelly Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kschmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2221</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=pworrell, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>pworrell@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>solicitous</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Pete</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1637</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Pete Worrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>pworrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2449</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Worrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mreuter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mreuter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>oblivious</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Matthew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6879</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Matthew Reuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mreuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1356</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Reuter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=gtyler, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>gtyler@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>typology</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Gern</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1020</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Gern Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>gtyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0312</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tschmith, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tschmith@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>compost</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9626</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tschmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4607</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Schmith</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bjense2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bjense2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>mortgage</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bjorn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5655</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bjorn Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bjense2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4294</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dswain, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dswain@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>freedom</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dietrich</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9222</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dietrich Swain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dswain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4396</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Swain</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ahall, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ahall@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>slater</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6169</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andy Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ahall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3050</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hall</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jmuffly, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jmuffly@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>dictate</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jeff</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5287</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jeff Muffly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jmuffly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0997</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Muffly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>ecosystem</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ted</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8622</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ted Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4717</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ahunter, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ahunter@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>egregious</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Allison</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7713</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Allison Hunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ahunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1213</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jgoldste, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jgoldste@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>yellow</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5769</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jon Goldstein</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jgoldste</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1454</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Goldstein</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=aworrell, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>aworrell@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>gargoyle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Alan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1591</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Alan Worrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>aworrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3966</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Worrell</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=wlutz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>wlutz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>bassinet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Wendy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3358</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Wendy Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>wlutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4912</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jlutz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jlutz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>autumn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Janet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4902</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Janet Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jlutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2544</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dlangdon, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dlangdon@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>botulin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7044</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dan Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dlangdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3263</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=aknutson, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>aknutson@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>maltose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Ashley</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2169</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Ashley Knutson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>aknutson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4736</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Knutson</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kmcinnis, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kmcinnis@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>stargaze</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Kelly</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8596</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Kelly Mcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kmcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4312</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Mcinnis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tcouzens, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tcouzens@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>tambourine</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Trent</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8401</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Trent Couzens</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tcouzens</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3994</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Couzens</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=lstockto, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>lstockto@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>brooklyn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lee</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0518</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lee Stockton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>lstockto</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0169</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Stockton</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jbourke, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jbourke@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>brainwash</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8541</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jon Bourke</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jbourke</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0034</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Bourke</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dlanoway, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dlanoway@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>manhattan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2017</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dan Lanoway</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dlanoway</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3540</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lanoway</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=kcope, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>kcope@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>forfeiture</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Karl</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2709</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Karl Cope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>kcope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3040</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=abarnes, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>abarnes@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>chevron</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Anne-Louise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9445</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Anne-Louise Barnes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>abarnes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2290</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Barnes</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rjensen, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rjensen@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>disciplinarian</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Richard</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5957</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Richard Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rjensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2631</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=phun2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>phun2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>absorb</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Pete</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0342</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Pete Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>phun2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0087</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mvaughan, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mvaughan@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>submitted</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Matthew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4692</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Matthew Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mvaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4508</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jlut2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jlut2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>shrank</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>James</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9689</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>James Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jlut2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3541</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lutz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mjablons, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mjablons@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>minimal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Morgan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0813</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Morgan Jablonski</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mjablons</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3160</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jablonski</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=pchassin, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>pchassin@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>barbital</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Peter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2816</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Peter Chassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>pchassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4524</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Chassin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=dcope, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>dcope@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>snifter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Dan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9813</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Dan Cope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>dcope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1737</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jrent2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jrent2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>tachistoscope</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Judy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2523</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Judy Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jrent2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4405</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tcruse, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tcruse@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>flinty</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5980</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tcruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4191</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4774</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=eward, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>eward@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>episcopal</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Eric</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2320</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Eric Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>eward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4874</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Ward</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 7472</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ttully, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ttully@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>schooner</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Torrey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2274</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Torrey Tully</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ttully</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3924</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tully</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=charvey, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>charvey@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>journalese</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Cecil</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1815</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Cecil Harvey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>charvey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4583</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Harvey</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3825</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rfisher, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rfisher@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>pomegranate</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 1506</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Fisher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rfisher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1579</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Fisher</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=alangdon, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>alangdon@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>muzzle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andrew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8289</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andrew Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>alangdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2254</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Langdon</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=drose, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>drose@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>gubernatorial</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>David</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 3963</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>David Rose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>drose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4012</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=polfield, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>polfield@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>monologue</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Peter</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 8231</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Peter Olfield</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>polfield</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1376</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Olfield</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=awalker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>awalker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>detonable</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Andy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9199</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Andy Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>awalker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0061</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 3372</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=lrentz, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>lrentz@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>calcium</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Lex</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2019</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Lex Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>lrentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2203</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rentz</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jvaughan, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jvaughan@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>appoint</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jeff</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4543</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jeff Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jvaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1734</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Vaughan</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bfrancis, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bfrancis@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>holystone</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barbara</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barbara Francis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bfrancis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3743</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Francis</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ewalker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ewalker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>beguile</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Eric</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 6387</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Eric Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ewalker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2295</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Walker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Payroll</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8721</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=tjames, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>tjames@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>turtle</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Tobias</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 2458</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Tobias James</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>tjames</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0730</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>James</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=brigden, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>brigden@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>purple</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Bjorn</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5263</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Bjorn Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>brigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1643</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Rigden</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ecruse, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ecruse@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>platelet</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Eric</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0648</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Eric Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ecruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>4233</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Cruse</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rjense2, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rjense2@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>transpose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Randy</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 9045</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Randy Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rjense2</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1984</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Jensen</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 1992</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=rhunt, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>rhunt@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>becloud</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Richard</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0139</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Richard Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>rhunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0718</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Hunt</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Accounting</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 8473</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=bparker, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>bparker@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>lenticular</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Barry</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4647</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Barry Parker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>bparker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>1148</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Parker</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=ealexand, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>ealexand@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>galactose</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Erin</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 5563</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Erin Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>ealexand</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2434</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Alexander</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=mtyler, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>mtyler@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>instantiate</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Matthew</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 7907</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Matthew Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>mtyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>2701</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Tyler</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Human Resources</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 4661</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Cupertino</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=elott, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>elott@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>holdout</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Emanuel</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0932</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Emanuel Lott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>elott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3906</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Lott</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Testing</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9751</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=cnewport, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>cnewport@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>expertise</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Christoph</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 0066</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Christoph Newport</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>cnewport</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>0056</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Newport</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 9332</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Sunnyvale</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="uid=jvedder, ou=People, dc=example,dc=com">
+ <dsml:attr name="mail">
+ <dsml:value>jvedder@example.com</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>person</dsml:oc-value>
+ <dsml:oc-value>organizationalPerson</dsml:oc-value>
+ <dsml:oc-value>inetOrgPerson</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="userpassword">
+ <dsml:value>befitting</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="givenname">
+ <dsml:value>Jeff</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="telephonenumber">
+ <dsml:value>+1 408 555 4668</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="cn">
+ <dsml:value>Jeff Vedder</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uid">
+ <dsml:value>jvedder</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="roomnumber">
+ <dsml:value>3445</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="sn">
+ <dsml:value>Vedder</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>Product Development</dsml:value>
+ <dsml:value>People</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="facsimiletelephonenumber">
+ <dsml:value>+1 408 555 0111</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="l">
+ <dsml:value>Santa Clara</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=Accounting Managers,ou=groups,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>People who can manage accounting entries</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>Accounting Managers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=scarter, ou=People, dc=example,dc=com</dsml:value>
+ <dsml:value>uid=tmorris, ou=People, dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>groups</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=HR Managers,ou=groups,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>People who can manage HR entries</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>HR Managers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=kvaughan, ou=People, dc=example,dc=com</dsml:value>
+ <dsml:value>uid=cschmith, ou=People, dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>groups</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=QA Managers,ou=groups,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>People who can manage QA entries</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>QA Managers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=abergin, ou=People, dc=example,dc=com</dsml:value>
+ <dsml:value>uid=jwalker, ou=People, dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>groups</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="cn=PD Managers,ou=groups,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>People who can manage engineer entries</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>groupOfUniqueNames</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="cn">
+ <dsml:value>PD Managers</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="uniquemember">
+ <dsml:value>uid=kwinters, ou=People, dc=example,dc=com</dsml:value>
+ <dsml:value>uid=trigden, ou=People, dc=example,dc=com</dsml:value>
+ </dsml:attr>
+ <dsml:attr name="ou">
+ <dsml:value>groups</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ <dsml:entry dn="ou=Netscape Servers,dc=example,dc=com">
+ <dsml:attr name="description">
+ <dsml:value>Standard branch for Netscape Server registration</dsml:value>
+ </dsml:attr>
+ <dsml:objectclass>
+ <dsml:oc-value>top</dsml:oc-value>
+ <dsml:oc-value>organizationalUnit</dsml:oc-value>
+ </dsml:objectclass>
+ <dsml:attr name="ou">
+ <dsml:value>Netscape Servers</dsml:value>
+ </dsml:attr>
+ </dsml:entry>
+ </dsml:directory-entries>
+</dsml:dsml>
diff --git a/ldap/include/Makefile b/ldap/include/Makefile
new file mode 100644
index 00000000..cbd7c034
--- /dev/null
+++ b/ldap/include/Makefile
@@ -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
+#
+#
+# GNU Makefile for ldap/include
+#
+
+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/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifneq ($(ARCH), WINNT)
+PROT= -m 644
+endif
+
+all: FORCE
+
+$(LDAP_INCLUDEDIR):
+ $(MKDIR) $(LDAP_INCLUDEDIR)
+
+clientSDK: $(LDAP_INCLUDEDIR) all FORCE
+ $(INSTALL) $(INSTALLFLAGS) $(PROT) ldap.h $(LDAP_INCLUDEDIR)
+ $(INSTALL) $(INSTALLFLAGS) $(PROT) lber.h $(LDAP_INCLUDEDIR)
+ifneq ($(LDAP_NO_LIBLCACHE),1)
+ $(INSTALL) $(INSTALLFLAGS) $(PROT) lcache.h $(LDAP_INCLUDEDIR)
+endif
+
+ $(INSTALL) $(INSTALLFLAGS) $(PROT) ldap_ssl.h $(LDAP_INCLUDEDIR)
+
+install: $(LDAP_INCLUDEDIR) clientSDK FORCE
+ $(INSTALL) $(INSTALLFLAGS) $(PROT) disptmpl.h $(LDAP_INCLUDEDIR)
+ $(INSTALL) $(INSTALLFLAGS) $(PROT) srchpref.h $(LDAP_INCLUDEDIR)
+ $(INSTALL) $(INSTALLFLAGS) $(PROT) portable.h $(LDAP_INCLUDEDIR)
+
+depend: FORCE
+
+clean: FORCE
+ -$(RM) db.h sys btree.h extern.h mpool.h
+
+veryclean: clean
+
+FORCE:
diff --git a/ldap/include/Makefile.client b/ldap/include/Makefile.client
new file mode 100644
index 00000000..e2c7ffe4
--- /dev/null
+++ b/ldap/include/Makefile.client
@@ -0,0 +1,54 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+DEPTH = ../../..
+
+CHMOD = chmod
+RM = rm -f
+SED = sed
+
+HEADERS = \
+ disptmpl.h \
+ lber.h \
+ ldap.h \
+ srchpref.h \
+ $(NULL)
+
+include $(DEPTH)/config/rules.mk
+
+GARBAGE += sdkver.h dirver.h
+
+ETCDIR = $(DIST)/etc
+INCLUDEDIR = $(XPDIST)/public/ldap
+
+DIR_VERSION := 2.0
+DIRSDK_VERSION := 1.0
+
+ifeq ($(OS_ARCH), WINNT)
+# Is this correct?
+DIRVER_PATH = $(DEPTH)/netsite/ldap/build
+else
+DIRVER_PATH = $(DIST)/bin
+endif
+
+DIRVER_PROG = $(DIRVER_PATH)/dirver$(BIN_SUFFIX)
+
+###########################################################################
+
+all export:: sdkver.h dirver.h FORCE
+ $(INSTALL) $(INSTALLFLAGS) -m 644 $(HEADERS) $(INCLUDEDIR)
+ $(INSTALL) $(INSTALLFLAGS) -m 644 $(HEADERS) $(DIST)/include
+
+sdkver.h: $(DIRVER_PROG)
+ @$< $(DIRSDK_VERSION) UseSystemDate $@
+
+dirver.h: $(DIRVER_PROG)
+ @$< $(DIR_VERSION) UseSystemDate $@
+
+install:: export
+
+FORCE:
diff --git a/ldap/include/avl.h b/ldap/include/avl.h
new file mode 100644
index 00000000..4b11d5ae
--- /dev/null
+++ b/ldap/include/avl.h
@@ -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 **/
+/* avl.h - avl tree definitions */
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+
+#ifndef _AVL
+#define _AVL
+
+/*
+ * this structure represents a generic avl tree node.
+ */
+
+typedef struct avlnode {
+ caddr_t avl_data;
+ signed char avl_bf;
+ struct avlnode *avl_left;
+ struct avlnode *avl_right;
+} Avlnode;
+
+#define NULLAVL ((Avlnode *) NULL)
+
+/* balance factor values */
+#define LH -1
+#define EH 0
+#define RH 1
+
+/* avl routines */
+#define avl_getone(x) (x == 0 ? 0 : (x)->avl_data)
+#define avl_onenode(x) (x == 0 || ((x)->avl_left == 0 && (x)->avl_right == 0))
+extern int avl_insert();
+extern caddr_t avl_delete();
+extern caddr_t avl_find();
+extern caddr_t avl_getfirst();
+extern caddr_t avl_getnext();
+extern int avl_dup_error();
+extern int avl_apply();
+extern int avl_free();
+
+/* apply traversal types */
+#define AVL_PREORDER 1
+#define AVL_INORDER 2
+#define AVL_POSTORDER 3
+/* what apply returns if it ran out of nodes */
+#define AVL_NOMORE -6
+
+#ifndef _IFP
+#define _IFP
+typedef int (*IFP)();
+#endif
+
+caddr_t avl_find_lin( Avlnode *root, caddr_t data, IFP fcmp );
+
+#endif /* _AVL */
diff --git a/ldap/include/dblayer.h b/ldap/include/dblayer.h
new file mode 100644
index 00000000..92ab5144
--- /dev/null
+++ b/ldap/include/dblayer.h
@@ -0,0 +1,7 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* This file is no longer used */
diff --git a/ldap/include/dirlite_strings.h b/ldap/include/dirlite_strings.h
new file mode 100644
index 00000000..8cc36920
--- /dev/null
+++ b/ldap/include/dirlite_strings.h
@@ -0,0 +1,62 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* dirlite_strings.h - strings used for Directory Lite */
+#ifndef _DIRLITE_STRINGS_H_
+#define _DIRLITE_STRINGS_H_
+
+#define LITE_PRODUCT_NAME "restricted-mode directory"
+#define LITE_UPGRADE_BLURB "To gain access to this feature, you must upgrade to the full verson of the directory."
+
+#define LITE_GENERIC_ERR "cannot be configured in the " LITE_PRODUCT_NAME ". " LITE_UPGRADE_BLURB
+
+
+
+/* Directory Lite: Error Strings related to configuring replication */
+#define LITE_CHANGELOG_DIR_ERR "Error: changelog cannot be configured in DirectoryLite."
+#define LITE_CHANGELOG_SUFFIX_ERR "Error: changelogsuffix cannot be configured in DirectoryLite."
+#define LITE_CHANGELOG_MAXAGE_ERR "Error: changelogmaxage cannot be configured in DirectoryLite."
+#define LITE_CHANGELOG_MAXENTRIES_ERR "Error: changelogmaxentries cannot be configured in DirectoryLite."
+#define LITE_REPLICATIONDN_ERR "Error: replicationdn cannot be configured in DirectoryLite."
+#define LITE_REPLICATIONPW_ERR "Error: replicationpw cannot be configured in DirectoryLite."
+
+
+
+/* Directory Lite: Error Strings related to configurating referrals */
+#define LITE_DEFAULT_REFERRAL_ERR "Error: Referrals are disabled in the " LITE_PRODUCT_NAME ", The defaultreferral " LITE_GENERIC_ERR
+
+#define LITE_REFERRAL_MODE_ERR "Error: Referrals are disabled in the " LITE_PRODUCT_NAME ", The referralmode " LITE_GENERIC_ERR
+
+/* Directory Lite: Error Strings related to configuring password policy */
+#define LITE_PW_EXP_ERR "Error: password policy is disabled in the " LITE_PRODUCT_NAME ", pw_exp " LITE_GENERIC_ERR
+
+/* all plugins which need to be used for Directory Lite must use this as their vendor string */
+#define PLUGIN_MAGIC_VENDOR_STR "Netscape Communications Corp."
+
+/* plugins which contain this substring in their pluginid will not be aprroved in DS Lite */
+#define LITE_NTSYNCH_PLUGIN_ID_SUBSTR "nt-sync"
+
+/*Directory Lite: Error Strings related to configuring nt synch service */
+#define LITE_NTSYNCH_ERR "Error: NT Synch Service " LITE_GENERIC_ERR " nt_synch cannot be enabled."
+
+#define LITE_DISABLED_ATTRS_DN "cn=attributes,cn=options,cn=features,cn=config"
+#define LITE_DISABLED_MODULES_DN "cn=modules,cn=options,cn=features,cn=config"
+
+#define LITE_REPLICA_ERR "Error: Replication is disabled in the " LITE_PRODUCT_NAME ", replica " LITE_GENERIC_ERR
+
+/*Directory Lite: Error Strings related to configuring maxdescriptors */
+#define LITE_MAXDESCRIPTORS_ERR "Warning: The maximum number of concurent connections to the " LITE_PRODUCT_NAME " is 256. Maxdescriptors has a maximum value of 256, setting value for maxdescriptors to 256. To increase the maximum number of concurent connections, you must upgrade to the full version of the directory."
+#define SLAPD_LITE_MAXDESCRIPTORS 256
+
+/* on-line backup and restore */
+#define LITE_BACKUP_ERR "Error: The " LITE_PRODUCT_NAME " server must be in readonly mode before you can do this operation. You must upgrade to the full version of the directory to be able to perform online backup without first putting the server into readonly mode."
+
+/* Directory Lite: Error string related to enabling third party plugins */
+#define LITE_3RD_PARTY_PLUGIN_ERR "Error: Plugins written by third parties are disabled in " LITE_PRODUCT_NAME ". Plugin \"%s\" is disabled. " LITE_UPGRADE_BLURB
+
+#endif /* _DIRLITE_STRINGS_H_ */
+
+
+
diff --git a/ldap/include/disptmpl.h b/ldap/include/disptmpl.h
new file mode 100644
index 00000000..6fdbfc22
--- /dev/null
+++ b/ldap/include/disptmpl.h
@@ -0,0 +1,348 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ *
+ * disptmpl.h: display template library defines
+ * 7 March 1994 by Mark C Smith
+ */
+
+#ifndef _DISPTMPL_H
+#define _DISPTMPL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* calling conventions used by library */
+#ifndef LDAP_CALL
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#define LDAP_C __cdecl
+#ifndef _WIN32
+#define __stdcall _far _pascal
+#define LDAP_CALLBACK _loadds
+#else
+#define LDAP_CALLBACK
+#endif /* _WIN32 */
+#define LDAP_PASCAL __stdcall
+#define LDAP_CALL LDAP_PASCAL
+#else /* _WINDOWS */
+#define LDAP_C
+#define LDAP_CALLBACK
+#define LDAP_PASCAL
+#define LDAP_CALL
+#endif /* _WINDOWS */
+#endif /* LDAP_CALL */
+
+#define LDAP_TEMPLATE_VERSION 1
+
+/*
+ * general types of items (confined to most significant byte)
+ */
+#define LDAP_SYN_TYPE_TEXT 0x01000000L
+#define LDAP_SYN_TYPE_IMAGE 0x02000000L
+#define LDAP_SYN_TYPE_BOOLEAN 0x04000000L
+#define LDAP_SYN_TYPE_BUTTON 0x08000000L
+#define LDAP_SYN_TYPE_ACTION 0x10000000L
+
+
+/*
+ * syntax options (confined to second most significant byte)
+ */
+#define LDAP_SYN_OPT_DEFER 0x00010000L
+
+
+/*
+ * display template item syntax ids (defined by common agreement)
+ * these are the valid values for the ti_syntaxid of the tmplitem
+ * struct (defined below). A general type is encoded in the
+ * most-significant 8 bits, and some options are encoded in the next
+ * 8 bits. The lower 16 bits are reserved for the distinct types.
+ */
+#define LDAP_SYN_CASEIGNORESTR ( 1 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_MULTILINESTR ( 2 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_DN ( 3 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_BOOLEAN ( 4 | LDAP_SYN_TYPE_BOOLEAN )
+#define LDAP_SYN_JPEGIMAGE ( 5 | LDAP_SYN_TYPE_IMAGE )
+#define LDAP_SYN_JPEGBUTTON ( 6 | LDAP_SYN_TYPE_BUTTON | LDAP_SYN_OPT_DEFER )
+#define LDAP_SYN_FAXIMAGE ( 7 | LDAP_SYN_TYPE_IMAGE )
+#define LDAP_SYN_FAXBUTTON ( 8 | LDAP_SYN_TYPE_BUTTON | LDAP_SYN_OPT_DEFER )
+#define LDAP_SYN_AUDIOBUTTON ( 9 | LDAP_SYN_TYPE_BUTTON | LDAP_SYN_OPT_DEFER )
+#define LDAP_SYN_TIME ( 10 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_DATE ( 11 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_LABELEDURL ( 12 | LDAP_SYN_TYPE_TEXT )
+#define LDAP_SYN_SEARCHACTION ( 13 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_LINKACTION ( 14 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_ADDDNACTION ( 15 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_VERIFYDNACTION ( 16 | LDAP_SYN_TYPE_ACTION )
+#define LDAP_SYN_RFC822ADDR ( 17 | LDAP_SYN_TYPE_TEXT )
+
+
+/*
+ * handy macros
+ */
+#define LDAP_GET_SYN_TYPE( syid ) ((syid) & 0xFF000000L )
+#define LDAP_GET_SYN_OPTIONS( syid ) ((syid) & 0x00FF0000L )
+
+
+/*
+ * display options for output routines (used by entry2text and friends)
+ */
+/*
+ * use calculated label width (based on length of longest label in
+ * template) instead of contant width
+ */
+#define LDAP_DISP_OPT_AUTOLABELWIDTH 0x00000001L
+#define LDAP_DISP_OPT_HTMLBODYONLY 0x00000002L
+
+/*
+ * perform search actions (applies to ldap_entry2text_search only)
+ */
+#define LDAP_DISP_OPT_DOSEARCHACTIONS 0x00000002L
+
+/*
+ * include additional info. relevant to "non leaf" entries only
+ * used by ldap_entry2html and ldap_entry2html_search to include "Browse"
+ * and "Move Up" HREFs
+ */
+#define LDAP_DISP_OPT_NONLEAF 0x00000004L
+
+
+/*
+ * display template item options (may not apply to all types)
+ * if this bit is set in ti_options, it applies.
+ */
+#define LDAP_DITEM_OPT_READONLY 0x00000001L
+#define LDAP_DITEM_OPT_SORTVALUES 0x00000002L
+#define LDAP_DITEM_OPT_SINGLEVALUED 0x00000004L
+#define LDAP_DITEM_OPT_HIDEIFEMPTY 0x00000008L
+#define LDAP_DITEM_OPT_VALUEREQUIRED 0x00000010L
+#define LDAP_DITEM_OPT_HIDEIFFALSE 0x00000020L /* booleans only */
+
+
+
+/*
+ * display template item structure
+ */
+struct ldap_tmplitem {
+ unsigned long ti_syntaxid;
+ unsigned long ti_options;
+ char *ti_attrname;
+ char *ti_label;
+ char **ti_args;
+ struct ldap_tmplitem *ti_next_in_row;
+ struct ldap_tmplitem *ti_next_in_col;
+ void *ti_appdata;
+};
+
+
+#define NULLTMPLITEM ((struct ldap_tmplitem *)0)
+
+#define LDAP_SET_TMPLITEM_APPDATA( ti, datap ) \
+ (ti)->ti_appdata = (void *)(datap)
+
+#define LDAP_GET_TMPLITEM_APPDATA( ti, type ) \
+ (type)((ti)->ti_appdata)
+
+#define LDAP_IS_TMPLITEM_OPTION_SET( ti, option ) \
+ (((ti)->ti_options & option ) != 0 )
+
+
+/*
+ * object class array structure
+ */
+struct ldap_oclist {
+ char **oc_objclasses;
+ struct ldap_oclist *oc_next;
+};
+
+#define NULLOCLIST ((struct ldap_oclist *)0)
+
+
+/*
+ * add defaults list
+ */
+struct ldap_adddeflist {
+ int ad_source;
+#define LDAP_ADSRC_CONSTANTVALUE 1
+#define LDAP_ADSRC_ADDERSDN 2
+ char *ad_attrname;
+ char *ad_value;
+ struct ldap_adddeflist *ad_next;
+};
+
+#define NULLADLIST ((struct ldap_adddeflist *)0)
+
+
+/*
+ * display template global options
+ * if this bit is set in dt_options, it applies.
+ */
+/*
+ * users should be allowed to try to add objects of these entries
+ */
+#define LDAP_DTMPL_OPT_ADDABLE 0x00000001L
+
+/*
+ * users should be allowed to do "modify RDN" operation of these entries
+ */
+#define LDAP_DTMPL_OPT_ALLOWMODRDN 0x00000002L
+
+/*
+ * this template is an alternate view, not a primary view
+ */
+#define LDAP_DTMPL_OPT_ALTVIEW 0x00000004L
+
+
+/*
+ * display template structure
+ */
+struct ldap_disptmpl {
+ char *dt_name;
+ char *dt_pluralname;
+ char *dt_iconname;
+ unsigned long dt_options;
+ char *dt_authattrname;
+ char *dt_defrdnattrname;
+ char *dt_defaddlocation;
+ struct ldap_oclist *dt_oclist;
+ struct ldap_adddeflist *dt_adddeflist;
+ struct ldap_tmplitem *dt_items;
+ void *dt_appdata;
+ struct ldap_disptmpl *dt_next;
+};
+
+#define NULLDISPTMPL ((struct ldap_disptmpl *)0)
+
+#define LDAP_SET_DISPTMPL_APPDATA( dt, datap ) \
+ (dt)->dt_appdata = (void *)(datap)
+
+#define LDAP_GET_DISPTMPL_APPDATA( dt, type ) \
+ (type)((dt)->dt_appdata)
+
+#define LDAP_IS_DISPTMPL_OPTION_SET( dt, option ) \
+ (((dt)->dt_options & option ) != 0 )
+
+#define LDAP_TMPL_ERR_VERSION 1
+#define LDAP_TMPL_ERR_MEM 2
+#define LDAP_TMPL_ERR_SYNTAX 3
+#define LDAP_TMPL_ERR_FILE 4
+
+/*
+ * buffer size needed for entry2text and vals2text
+ */
+#define LDAP_DTMPL_BUFSIZ 8192
+
+typedef int (*writeptype)( void *writeparm, char *p, int len );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_init_templates( char *file, struct ldap_disptmpl **tmpllistp );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_init_templates_buf( char *buf, long buflen,
+ struct ldap_disptmpl **tmpllistp );
+
+LDAP_API(void)
+LDAP_CALL
+ldap_free_templates( struct ldap_disptmpl *tmpllist );
+
+LDAP_API(struct ldap_disptmpl *)
+LDAP_CALL
+ldap_first_disptmpl( struct ldap_disptmpl *tmpllist );
+
+LDAP_API(struct ldap_disptmpl *)
+LDAP_CALL
+ldap_next_disptmpl( struct ldap_disptmpl *tmpllist,
+ struct ldap_disptmpl *tmpl );
+
+LDAP_API(struct ldap_disptmpl *)
+LDAP_CALL
+ldap_name2template( char *name, struct ldap_disptmpl *tmpllist );
+
+LDAP_API(struct ldap_disptmpl *)
+LDAP_CALL
+ldap_oc2template( char **oclist, struct ldap_disptmpl *tmpllist );
+
+LDAP_API(char **)
+LDAP_CALL
+ldap_tmplattrs( struct ldap_disptmpl *tmpl, char **includeattrs, int exclude,
+ unsigned long syntaxmask );
+
+LDAP_API(struct ldap_tmplitem *)
+LDAP_CALL
+ldap_first_tmplrow( struct ldap_disptmpl *tmpl );
+
+LDAP_API(struct ldap_tmplitem *)
+LDAP_CALL
+ldap_next_tmplrow( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row );
+
+LDAP_API(struct ldap_tmplitem *)
+LDAP_CALL
+ldap_first_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row );
+
+LDAP_API(struct ldap_tmplitem *)
+LDAP_CALL
+ldap_next_tmplcol( struct ldap_disptmpl *tmpl, struct ldap_tmplitem *row,
+ struct ldap_tmplitem *col );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_entry2text( LDAP *ld, char *buf, LDAPMessage *entry,
+ struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
+ writeptype writeproc, void *writeparm, char *eol, int rdncount,
+ unsigned long opts );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_vals2text( LDAP *ld, char *buf, char **vals, char *label, int labelwidth,
+ unsigned long syntaxid, writeptype writeproc, void *writeparm,
+ char *eol, int rdncount );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_entry2text_search( LDAP *ld, char *dn, char *base, LDAPMessage *entry,
+ struct ldap_disptmpl *tmpllist, char **defattrs, char ***defvals,
+ writeptype writeproc, void *writeparm, char *eol, int rdncount,
+ unsigned long opts );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_entry2html( LDAP *ld, char *buf, LDAPMessage *entry,
+ struct ldap_disptmpl *tmpl, char **defattrs, char ***defvals,
+ writeptype writeproc, void *writeparm, char *eol, int rdncount,
+ unsigned long opts, char *urlprefix, char *base );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_vals2html( LDAP *ld, char *buf, char **vals, char *label, int labelwidth,
+ unsigned long syntaxid, writeptype writeproc, void *writeparm,
+ char *eol, int rdncount, char *urlprefix );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_entry2html_search( LDAP *ld, char *dn, char *base, LDAPMessage *entry,
+ struct ldap_disptmpl *tmpllist, char **defattrs, char ***defvals,
+ writeptype writeproc, void *writeparm, char *eol, int rdncount,
+ unsigned long opts, char *urlprefix );
+
+LDAP_API(char *)
+LDAP_CALL
+ldap_tmplerr2string( int err );
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _DISPTMPL_H */
diff --git a/ldap/include/ldaplog.h b/ldap/include/ldaplog.h
new file mode 100644
index 00000000..3d4a6fb1
--- /dev/null
+++ b/ldap/include/ldaplog.h
@@ -0,0 +1,84 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _LDAPLOG_H
+#define _LDAPLOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDAP_DEBUG_TRACE 0x00001 /* 1 */
+#define LDAP_DEBUG_PACKETS 0x00002 /* 2 */
+#define LDAP_DEBUG_ARGS 0x00004 /* 4 */
+#define LDAP_DEBUG_CONNS 0x00008 /* 8 */
+#define LDAP_DEBUG_BER 0x00010 /* 16 */
+#define LDAP_DEBUG_FILTER 0x00020 /* 32 */
+#define LDAP_DEBUG_CONFIG 0x00040 /* 64 */
+#define LDAP_DEBUG_ACL 0x00080 /* 128 */
+#define LDAP_DEBUG_STATS 0x00100 /* 256 */
+#define LDAP_DEBUG_STATS2 0x00200 /* 512 */
+#define LDAP_DEBUG_SHELL 0x00400 /* 1024 */
+#define LDAP_DEBUG_PARSE 0x00800 /* 2048 */
+#define LDAP_DEBUG_HOUSE 0x01000 /* 4096 */
+#define LDAP_DEBUG_REPL 0x02000 /* 8192 */
+#define LDAP_DEBUG_ANY 0x04000 /* 16384 */
+#define LDAP_DEBUG_CACHE 0x08000 /* 32768 */
+#define LDAP_DEBUG_PLUGIN 0x10000 /* 65536 */
+#define LDAP_DEBUG_TIMING 0x20000 /*131072 */
+#define LDAP_DEBUG_ACLSUMMARY 0x40000 /*262144 */
+
+#define LDAP_DEBUG_ALL_LEVELS 0xFFFFF
+
+/* debugging stuff */
+/* Disable by default */
+#define LDAPDebug( level, fmt, arg1, arg2, arg3 )
+#define LDAPDebugLevelIsSet( level ) (0)
+
+#ifdef LDAP_DEBUG
+# undef LDAPDebug
+# undef LDAPDebugLevelIsSet
+
+/* SLAPD_LOGGING should not be on for WINSOCK (16-bit Windows) */
+# if defined(SLAPD_LOGGING)
+# ifdef _WIN32
+# ifndef DONT_DECLARE_SLAPD_LDAP_DEBUG /* see libglobs.c for info */
+ extern __declspec(dllimport) int slapd_ldap_debug;
+# endif /* DONT_DECLARE_SLAPD_LDAP_DEBUG */
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( *module_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# define LDAPDebugLevelIsSet( level ) (0 != (*module_ldap_debug & level))
+# else /* Not _WIN32 */
+ extern int slapd_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( slapd_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# define LDAPDebugLevelIsSet( level ) (0 != (slapd_ldap_debug & level))
+# endif /* Win32 */
+# else /* no SLAPD_LOGGING */
+ extern void ber_err_print( char * );
+ extern int slapd_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ if ( slapd_ldap_debug & level ) { \
+ char msg[256]; \
+ sprintf( msg, fmt, arg1, arg2, arg3 ); \
+ ber_err_print( msg ); \
+ }
+# define LDAPDebugLevelIsSet( level ) (0 != (slapd_ldap_debug & level))
+# endif /* SLAPD_LOGGING */
+#endif /* LDAP_DEBUG */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAP_H */
diff --git a/ldap/include/ldaprot.h b/ldap/include/ldaprot.h
new file mode 100644
index 00000000..ae4042d4
--- /dev/null
+++ b/ldap/include/ldaprot.h
@@ -0,0 +1,167 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _LDAPROT_H
+#define _LDAPROT_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDAP_VERSION1 1
+#define LDAP_VERSION2 2
+#define LDAP_VERSION3 3
+#define LDAP_VERSION LDAP_VERSION2
+
+#define COMPAT20
+#define COMPAT30
+#if defined(COMPAT20) || defined(COMPAT30)
+#define COMPAT
+#endif
+
+#define LDAP_URL_PREFIX "ldap://"
+#define LDAP_URL_PREFIX_LEN 7
+#define LDAPS_URL_PREFIX "ldaps://"
+#define LDAPS_URL_PREFIX_LEN 8
+#define LDAP_REF_STR "Referral:\n"
+#define LDAP_REF_STR_LEN 10
+
+/*
+ * specific LDAP instantiations of BER types we know about
+ */
+
+/* general stuff */
+#define LDAP_TAG_MESSAGE 0x30L /* tag is 16 + constructed bit */
+#define OLD_LDAP_TAG_MESSAGE 0x10L /* forgot the constructed bit */
+#define LDAP_TAG_MSGID 0x02L /* INTEGER */
+#define LDAP_TAG_LDAPDN 0x04L /* OCTET STRING */
+#define LDAP_TAG_CONTROLS 0xa0L /* context specific + constructed + 0 */
+#define LDAP_TAG_REFERRAL 0xa3L /* context specific + constructed */
+#define LDAP_TAG_NEWSUPERIOR 0x80L /* context specific + primitive */
+#define LDAP_TAG_MRA_OID 0x81L /* context specific + primitive */
+#define LDAP_TAG_MRA_TYPE 0x82L /* context specific + primitive */
+#define LDAP_TAG_MRA_VALUE 0x83L /* context specific + primitive */
+#define LDAP_TAG_MRA_DNATTRS 0x84L /* context specific + primitive */
+#define LDAP_TAG_EXOP_REQ_OID 0x80L /* context specific + primitive */
+#define LDAP_TAG_EXOP_REQ_VALUE 0x81L /* context specific + primitive */
+#define LDAP_TAG_EXOP_RES_OID 0x8aL /* context specific + primitive + 10 */
+#define LDAP_TAG_EXOP_RES_VALUE 0x8bL /* context specific + primitive + 11 */
+#define LDAP_TAG_SK_MATCHRULE 0x80L /* context specific + primitive */
+#define LDAP_TAG_SK_REVERSE 0x81L /* context specific + primitive */
+#define LDAP_TAG_SR_ATTRTYPE 0x80L /* context specific + primitive */
+#define LDAP_TAG_SASL_RES_CREDS 0x87L /* context specific + primitive */
+#define LDAP_TAG_VLV_BY_INDEX 0xa0L /* context specific + constructed + 0 */
+#define LDAP_TAG_VLV_BY_VALUE 0x81L /* context specific + primitive + 1 */
+#define LDAP_TAG_PWP_WARNING 0xA0 /* context specific + constructed + 0 */
+#define LDAP_TAG_PWP_SECSLEFT 0x80L /* context specific + primitive */
+#define LDAP_TAG_PWP_GRCLOGINS 0x81L /* context specific + primitive + 1 */
+#define LDAP_TAG_PWP_ERROR 0x81L /* context specific + primitive + 1 */
+
+/* possible operations a client can invoke */
+#define LDAP_REQ_BIND 0x60L /* application + constructed */
+#define LDAP_REQ_UNBIND 0x42L /* application + primitive */
+#define LDAP_REQ_SEARCH 0x63L /* application + constructed */
+#define LDAP_REQ_MODIFY 0x66L /* application + constructed */
+#define LDAP_REQ_ADD 0x68L /* application + constructed */
+#define LDAP_REQ_DELETE 0x4aL /* application + primitive */
+#define LDAP_REQ_MODRDN 0x6cL /* application + constructed */
+#define LDAP_REQ_MODDN 0x6cL /* application + constructed */
+#define LDAP_REQ_RENAME 0x6cL /* application + constructed */
+#define LDAP_REQ_COMPARE 0x6eL /* application + constructed */
+#define LDAP_REQ_ABANDON 0x50L /* application + primitive */
+#define LDAP_REQ_EXTENDED 0x77L /* application + constructed */
+
+/* version 3.0 compatibility stuff */
+#define LDAP_REQ_UNBIND_30 0x62L
+#define LDAP_REQ_DELETE_30 0x6aL
+#define LDAP_REQ_ABANDON_30 0x70L
+
+/*
+ * old broken stuff for backwards compatibility - forgot application tag
+ * and constructed/primitive bit
+ */
+#define OLD_LDAP_REQ_BIND 0x00L
+#define OLD_LDAP_REQ_UNBIND 0x02L
+#define OLD_LDAP_REQ_SEARCH 0x03L
+#define OLD_LDAP_REQ_MODIFY 0x06L
+#define OLD_LDAP_REQ_ADD 0x08L
+#define OLD_LDAP_REQ_DELETE 0x0aL
+#define OLD_LDAP_REQ_MODRDN 0x0cL
+#define OLD_LDAP_REQ_MODDN 0x0cL
+#define OLD_LDAP_REQ_COMPARE 0x0eL
+#define OLD_LDAP_REQ_ABANDON 0x10L
+
+/* old broken stuff for backwards compatibility */
+#define OLD_LDAP_RES_BIND 0x01L
+#define OLD_LDAP_RES_SEARCH_ENTRY 0x04L
+#define OLD_LDAP_RES_SEARCH_RESULT 0x05L
+#define OLD_LDAP_RES_MODIFY 0x07L
+#define OLD_LDAP_RES_ADD 0x09L
+#define OLD_LDAP_RES_DELETE 0x0bL
+#define OLD_LDAP_RES_MODRDN 0x0dL
+#define OLD_LDAP_RES_MODDN 0x0dL
+#define OLD_LDAP_RES_COMPARE 0x0fL
+
+/* 3.0 compatibility auth methods */
+#define LDAP_AUTH_SIMPLE_30 0xa0L /* context specific + constructed */
+#define LDAP_AUTH_KRBV41_30 0xa1L /* context specific + constructed */
+#define LDAP_AUTH_KRBV42_30 0xa2L /* context specific + constructed */
+
+/* old broken stuff */
+#define OLD_LDAP_AUTH_SIMPLE 0x00L
+#define OLD_LDAP_AUTH_KRBV4 0x01L
+#define OLD_LDAP_AUTH_KRBV42 0x02L
+
+/* 3.0 compatibility filter types */
+#define LDAP_FILTER_PRESENT_30 0xa7L /* context specific + constructed */
+
+/* filter types */
+#define LDAP_FILTER_AND 0xa0L /* context specific + constructed */
+#define LDAP_FILTER_OR 0xa1L /* context specific + constructed */
+#define LDAP_FILTER_NOT 0xa2L /* context specific + constructed */
+#define LDAP_FILTER_EQUALITY 0xa3L /* context specific + constructed */
+#define LDAP_FILTER_SUBSTRINGS 0xa4L /* context specific + constructed */
+#define LDAP_FILTER_GE 0xa5L /* context specific + constructed */
+#define LDAP_FILTER_LE 0xa6L /* context specific + constructed */
+#define LDAP_FILTER_PRESENT 0x87L /* context specific + primitive */
+#define LDAP_FILTER_APPROX 0xa8L /* context specific + constructed */
+#define LDAP_FILTER_EXTENDED 0xa9L /* context specific + constructed */
+
+/* old broken stuff */
+#define OLD_LDAP_FILTER_AND 0x00L
+#define OLD_LDAP_FILTER_OR 0x01L
+#define OLD_LDAP_FILTER_NOT 0x02L
+#define OLD_LDAP_FILTER_EQUALITY 0x03L
+#define OLD_LDAP_FILTER_SUBSTRINGS 0x04L
+#define OLD_LDAP_FILTER_GE 0x05L
+#define OLD_LDAP_FILTER_LE 0x06L
+#define OLD_LDAP_FILTER_PRESENT 0x07L
+#define OLD_LDAP_FILTER_APPROX 0x08L
+
+/* substring filter component types */
+#define LDAP_SUBSTRING_INITIAL 0x80L /* context specific */
+#define LDAP_SUBSTRING_ANY 0x81L /* context specific */
+#define LDAP_SUBSTRING_FINAL 0x82L /* context specific */
+
+/* extended filter component types */
+#define LDAP_FILTER_EXTENDED_OID 0x81L /* context specific */
+#define LDAP_FILTER_EXTENDED_TYPE 0x82L /* context specific */
+#define LDAP_FILTER_EXTENDED_VALUE 0x83L /* context specific */
+#define LDAP_FILTER_EXTENDED_DNATTRS 0x84L /* context specific */
+
+/* 3.0 compatibility substring filter component types */
+#define LDAP_SUBSTRING_INITIAL_30 0xa0L /* context specific */
+#define LDAP_SUBSTRING_ANY_30 0xa1L /* context specific */
+#define LDAP_SUBSTRING_FINAL_30 0xa2L /* context specific */
+
+/* old broken stuff */
+#define OLD_LDAP_SUBSTRING_INITIAL 0x00L
+#define OLD_LDAP_SUBSTRING_ANY 0x01L
+#define OLD_LDAP_SUBSTRING_FINAL 0x02L
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LDAPROT_H */
diff --git a/ldap/include/ldbm.h b/ldap/include/ldbm.h
new file mode 100644
index 00000000..2221071b
--- /dev/null
+++ b/ldap/include/ldbm.h
@@ -0,0 +1,380 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* ldbm.h - ldap dbm compatibility routine header file */
+
+#error "Hmm, shoudn't be here"
+/* Deprecated header, why are you including it ??? */
+
+#if 1
+
+#ifndef _LDBM_H_
+#define _LDBM_H_
+
+/* define LDAP_USE_DB185 to get the old db library, otherwise, use db2.0 */
+#ifndef LDAP_USE_DB185
+#define LDAP_USE_DB20
+#endif
+
+#ifdef LDBM_USE_GDBM
+
+/*****************************************************************
+ * *
+ * use gdbm if possible *
+ * *
+ *****************************************************************/
+
+#include <gdbm.h>
+
+typedef datum Datum;
+
+typedef GDBM_FILE LDBM;
+
+extern gdbm_error gdbm_errno;
+
+/* for ldbm_open */
+#define LDBM_READER GDBM_READER
+#define LDBM_WRITER GDBM_WRITER
+#define LDBM_WRCREAT GDBM_WRCREAT
+#define LDBM_NEWDB GDBM_NEWDB
+#define LDBM_FAST GDBM_FAST
+
+#define LDBM_SUFFIX ".gdbm"
+
+/* for ldbm_insert */
+#define LDBM_INSERT GDBM_INSERT
+#define LDBM_REPLACE GDBM_REPLACE
+#define LDBM_SYNC 0x80000000
+
+#else /* end of gdbm */
+
+#ifdef LDBM_USE_DBHASH
+
+/*****************************************************************
+ * *
+ * use berkeley db hash package *
+ * *
+ *****************************************************************/
+
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <db.h>
+
+typedef DBT Datum;
+#define dsize size
+#define dptr data
+
+typedef DB *LDBM;
+
+#define DB_TYPE DB_HASH
+
+/* for ldbm_open */
+#define LDBM_READER O_RDONLY
+#define LDBM_WRITER O_RDWR
+#define LDBM_WRCREAT (O_RDWR|O_CREAT)
+#define LDBM_NEWDB (O_RDWR|O_TRUNC|O_CREAT)
+#define LDBM_FAST 0
+
+#define LDBM_SUFFIX ".dbh"
+
+/* for ldbm_insert */
+#define LDBM_INSERT R_NOOVERWRITE
+#define LDBM_REPLACE 0
+#define LDBM_SYNC 0x80000000
+
+#else /* end of db hash */
+
+#ifdef LDBM_USE_DBBTREE
+
+/*****************************************************************
+ * *
+ * use berkeley db btree package *
+ * *
+ *****************************************************************/
+
+#ifndef LDAP_USE_DB20 /* old-db needed us to include these system headers first */
+#include <sys/types.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#ifdef HPUX11
+#define __BIT_TYPES_DEFINED__
+typedef unsigned char u_int8_t;
+typedef unsigned int u_int32_t;
+typedef unsigned short u_int16_t;
+#endif
+#include <db.h>
+
+#define DB_TYPE DB_BTREE
+
+#define LDBM_ORDERED 1
+
+#ifdef LDAP_USE_DB20
+
+/* pull in parts of the new interface , this comes from dblayer.h */
+
+typedef struct _tag_dblayer_session{
+ DB_ENV db_env;
+} *dblayer_session, dblayer_session_struct;
+
+
+/* for ldbm_insert */
+#define LDBM_INSERT DB_NOOVERWRITE
+#define LDBM_REPLACE 0 /* Db2.0 default is to replace */
+#define LDBM_SYNC 0x80000000
+
+typedef DBT Datum;
+#define dsize size
+#define dptr data
+
+typedef struct _ldbm {
+ DB *pReal_DB;
+ DBC *pCursor;
+} _ldbmstruct, *LDBM;
+
+/* for ldbm_open */
+#define LDBM_READER DB_RDONLY
+#define LDBM_WRITER 0
+#define LDBM_WRCREAT DB_CREATE
+#define LDBM_NEWDB (DB_TRUNCATE | DB_CREATE)
+#define LDBM_FAST 0
+
+#define LDBM_SUFFIX ".db2"
+#else /* DB 1.85 */
+
+/* for ldbm_insert */
+#define LDBM_INSERT R_NOOVERWRITE
+#define LDBM_REPLACE 0
+#define LDBM_SYNC 0x80000000
+
+typedef DBT Datum;
+#define dsize size
+#define dptr data
+
+typedef DB *LDBM;
+/* for ldbm_open */
+#define LDBM_READER O_RDONLY
+#define LDBM_WRITER O_RDWR
+#define LDBM_WRCREAT (O_RDWR|O_CREAT)
+#define LDBM_NEWDB (O_RDWR|O_TRUNC|O_CREAT)
+#define LDBM_FAST 0
+
+#define LDBM_SUFFIX ".dbb"
+#endif /* LDAP_USE_DB20 */
+
+#else /* end of db btree */
+
+#ifdef LDBM_USE_NDBM
+
+/*****************************************************************
+ * *
+ * if none of the above use ndbm, the standard unix thing *
+ * *
+ *****************************************************************/
+
+#include <ndbm.h>
+#ifndef O_RDONLY
+#include <fcntl.h>
+#endif
+
+typedef datum Datum;
+
+typedef DBM *LDBM;
+
+/* for ldbm_open */
+#define LDBM_READER O_RDONLY
+#define LDBM_WRITER O_WRONLY
+#define LDBM_WRCREAT (O_RDWR|O_CREAT)
+#define LDBM_NEWDB (O_RDWR|O_TRUNC|O_CREAT)
+#define LDBM_FAST 0
+
+#define LDBM_SUFFIX ".ndbm"
+
+/* for ldbm_insert */
+#define LDBM_INSERT DBM_INSERT
+#define LDBM_REPLACE DBM_REPLACE
+#define LDBM_SYNC 0
+
+#else /* end of ndbm */
+
+#ifdef LDBM_USE_CISAM
+
+/*****************************************************************
+ * *
+ * use CISAM db package *
+ * *
+ *****************************************************************/
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include "isam.h"
+
+extern int errno;
+
+struct datum {
+ void *dptr; /* data */
+ size_t dsize; /* data length */
+};
+
+typedef struct datum Datum;
+
+struct ldbm {
+ int fd; /* all callers expect a ptr */
+ int cur_recnum; /* for reading sequentially */
+};
+
+typedef struct ldbm *LDBM;
+
+/* for ldbm_open */
+#define LDBM_READER (ISINPUT | ISVARLEN | ISMANULOCK)
+#define LDBM_WRITER (ISINOUT | ISVARLEN | ISMANULOCK)
+#define LDBM_WRCREAT (ISINOUT | ISVARLEN | ISMANULOCK | ISEXCLLOCK)
+#define LDBM_NEWDB (ISINOUT | ISVARLEN | ISMANULOCK | ISEXCLLOCK)
+#define LDBM_FAST 0
+
+#define LDBM_SUFFIX ""
+#define LDBM_ORDERED 1
+
+/* for ldbm_insert */
+#define LDBM_INSERT 1
+#define LDBM_REPLACE 0
+#define LDBM_SYNC 0x80000000
+
+#else /* end of cisam */
+
+#ifdef LDBM_USE_TRIO
+
+/*****************************************************************
+ * *
+ * use C-Index/II from Trio *
+ * *
+ *****************************************************************/
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <limits.h>
+#include <fcntl.h>
+#include "cndx.h"
+
+#define CRDCREAT 0x100
+
+extern int errno;
+
+struct datum {
+ void *dptr; /* data */
+ size_t dsize; /* data length */
+};
+
+typedef struct datum Datum;
+
+typedef CFILE *LDBM;
+
+/* for ldbm_open */
+#define LDBM_READER (CRDONLY)
+#define LDBM_WRITER (CRDWRITE)
+#define LDBM_WRCREAT (CRDWRITE | CRDCREAT)
+#define LDBM_NEWDB (CRDWRITE | CRDCREAT)
+#define LDBM_FAST 0
+
+#define LDBM_SUFFIX ".c2i"
+#define LDBM_ORDERED 1
+
+/* for ldbm_insert */
+#define LDBM_INSERT 1
+#define LDBM_REPLACE 0
+#define LDBM_SYNC 0x80000000
+
+
+#else /* end of trio */
+
+#ifdef LDBM_USE_CTREE
+
+/*****************************************************************
+ * *
+ * use Faircom Ctree db package *
+ * *
+ *****************************************************************/
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <limits.h>
+#include <fcntl.h>
+
+#include "ctstdr.h"
+#include "ctoptn.h"
+#include "ctaerr.h"
+#include "ctdecl.h"
+#include "cterrc.h"
+
+extern int errno;
+
+struct datum {
+ void *dptr; /* data */
+ size_t dsize; /* data length */
+};
+
+typedef struct datum Datum;
+typedef IFIL *LDBM;
+
+/* for ldbm_open */
+#define LDBM_READER 0
+#define LDBM_WRITER 0
+#define LDBM_WRCREAT 1
+#define LDBM_NEWDB 1
+#define LDBM_FAST 0
+
+#define LDBM_SUFFIX ""
+#define LDBM_ORDERED 1
+
+/* for ldbm_insert */
+#define LDBM_INSERT 1
+#define LDBM_REPLACE 0
+#define LDBM_SYNC 0x80000000
+
+#endif /* ctree */
+#endif /* trio */
+#endif /* cisam */
+#endif /* ndbm */
+#endif /* db hash */
+#endif /* db btree */
+#endif /* gdbm */
+
+/*
+ * name: file name without the suffix
+ * rw: read/write flags
+ * mode: this has the desired permissions mode on the file
+ * dbcachesize: advisory cache size in bytes
+ */
+LDBM ldbm_open( char *name, int rw, int mode, int dbcachesize );
+#ifdef LDAP_USE_DB20
+/* This is a stopgap measure to allow us to associate a session with ldbm_ calls */
+LDBM ldbm_open2( dblayer_session session, char *name, int rw, int mode);
+/* These are stolen from beta2's dblayer.h */
+int dblayer_session_open(char *home_dir, char* log_dir, char* temp_dir, int cachesize, dblayer_session session) ;
+int dblayer_session_terminate(dblayer_session session) ;
+#endif
+int ldbm_close( LDBM ldbm );
+void ldbm_sync( LDBM ldbm );
+void ldbm_datum_free( LDBM ldbm, Datum data );
+Datum ldbm_datum_dup( LDBM ldbm, Datum data );
+Datum ldbm_fetch( LDBM ldbm, Datum key );
+int ldbm_store( LDBM ldbm, Datum key, Datum data, int flags );
+int ldbm_delete( LDBM ldbm, Datum key );
+Datum ldbm_firstkey( LDBM ldbm );
+Datum ldbm_nextkey( LDBM ldbm, Datum key );
+Datum ldbm_prevkey( LDBM ldbm, Datum key );
+Datum ldbm_lastkey( LDBM ldbm );
+Datum ldbm_cursorkey( LDBM ldbm, Datum key );
+int ldbm_errno( LDBM ldbm );
+
+#endif /* _ldbm_h_ */
+
+#endif /* 0 */
diff --git a/ldap/include/ldif.h b/ldap/include/ldif.h
new file mode 100644
index 00000000..5c154749
--- /dev/null
+++ b/ldap/include/ldif.h
@@ -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 **/
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#ifndef _LDIF_H
+#define _LDIF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDIF_VERSION_ONE 1 /* LDIF standard version */
+
+#define LDIF_MAX_LINE_WIDTH 76 /* maximum length of LDIF lines */
+
+/*
+ * Macro to calculate maximum number of bytes that the base64 equivalent
+ * of an item that is "vlen" bytes long will take up. Base64 encoding
+ * uses one byte for every six bits in the value plus up to two pad bytes.
+ */
+#define LDIF_BASE64_LEN(vlen) (((vlen) * 4 / 3 ) + 3)
+
+/*
+ * Macro to calculate maximum size that an LDIF-encoded type (length
+ * tlen) and value (length vlen) will take up: room for type + ":: " +
+ * first newline + base64 value + continued lines. Each continued line
+ * needs room for a newline and a leading space character.
+ */
+#define LDIF_SIZE_NEEDED(tlen,vlen) \
+ ((tlen) + 4 + LDIF_BASE64_LEN(vlen) \
+ + ((LDIF_BASE64_LEN(vlen) + tlen + 3) / LDIF_MAX_LINE_WIDTH * 2 ))
+
+/*
+ * Options for ldif_put_type_and_value_with_options() and
+ * ldif_type_and_value_with_options().
+ */
+#define LDIF_OPT_NOWRAP 0x01UL
+#define LDIF_OPT_VALUE_IS_URL 0x02UL
+#define LDIF_OPT_MINIMAL_ENCODING 0x04UL
+
+int ldif_parse_line( char *line, char **type, char **value, int *vlen, char **errcode);
+char * ldif_getline( char **next );
+void ldif_put_type_and_value( char **out, char *t, char *val, int vlen );
+void ldif_put_type_and_value_nowrap( char **out, char *t, char *val, int vlen );
+void ldif_put_type_and_value_with_options( char **out, char *t, char *val,
+ int vlen, unsigned long options );
+char *ldif_type_and_value( char *type, char *val, int vlen );
+char *ldif_type_and_value_nowrap( char *type, char *val, int vlen );
+char *ldif_type_and_value_with_options( char *type, char *val, int vlen,
+ unsigned long options );
+int ldif_base64_decode( char *src, unsigned char *dst );
+int ldif_base64_encode( unsigned char *src, char *dst, int srclen,
+ int lenused );
+int ldif_base64_encode_nowrap( unsigned char *src, char *dst, int srclen,
+ int lenused );
+char *ldif_get_entry( FILE *fp, int *lineno );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDIF_H */
diff --git a/ldap/include/litekey.h b/ldap/include/litekey.h
new file mode 100644
index 00000000..43dd0f4f
--- /dev/null
+++ b/ldap/include/litekey.h
@@ -0,0 +1,30 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Defines function used to determine the type of DS based on the
+ * key.
+ */
+#ifndef _LITEKEY_H
+#define _LITEKEY_H
+
+#include <dirlite_strings.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define DS_NORMAL_TYPE 0
+#define DS_LITE_TYPE 1
+
+int is_directory_lite ( char *path);
+int generate_directory_key( int type);
+int is_key_validNormalKey ( int key );
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LITEKEY_H */
diff --git a/ldap/include/lthread.h b/ldap/include/lthread.h
new file mode 100644
index 00000000..8f24a08c
--- /dev/null
+++ b/ldap/include/lthread.h
@@ -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 **/
+/* lthread.h - ldap threads header file */
+
+#ifndef _LTHREAD_H
+#define _LTHREAD_H
+
+#if defined( THREAD_SUNOS4_LWP )
+/***********************************
+ * *
+ * thread definitions for sunos4 *
+ * *
+ ***********************************/
+
+#define _THREAD
+
+#include <lwp/lwp.h>
+#include <lwp/stackdep.h>
+
+typedef void *(*VFP)();
+
+/* thread attributes and thread type */
+typedef int pthread_attr_t;
+typedef thread_t pthread_t;
+
+/* default attr states */
+#define pthread_mutexattr_default NULL
+#define pthread_condattr_default NULL
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED 1
+/* thread scope - who is in scheduling pool */
+#define PTHREAD_SCOPE_PROCESS 0
+#define PTHREAD_SCOPE_SYSTEM 1
+
+/* mutex attributes and mutex type */
+typedef int pthread_mutexattr_t;
+typedef mon_t pthread_mutex_t;
+
+/* mutex and condition variable scope - process or system */
+#define PTHREAD_SHARE_PRIVATE 0
+#define PTHREAD_SHARE_PROCESS 1
+
+/* condition variable attributes and condition variable type */
+typedef int pthread_condattr_t;
+typedef struct lwpcv {
+ int lcv_created;
+ cv_t lcv_cv;
+} pthread_cond_t;
+
+#else /* end sunos4 */
+
+#if defined( THREAD_SUNOS5_LWP )
+/***********************************
+ * *
+ * thread definitions for sunos5 *
+ * *
+ ***********************************/
+
+#define _THREAD
+
+#include <thread.h>
+#include <synch.h>
+
+typedef void *(*VFP)();
+
+/* sunos5 threads are preemptive */
+#define PTHREAD_PREEMPTIVE 1
+
+/* thread attributes and thread type */
+typedef int pthread_attr_t;
+typedef thread_t pthread_t;
+
+/* default attr states */
+#define pthread_mutexattr_default NULL
+#define pthread_condattr_default NULL
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED THR_DETACHED
+/* thread scope - who is in scheduling pool */
+#define PTHREAD_SCOPE_PROCESS 0
+#define PTHREAD_SCOPE_SYSTEM THR_BOUND
+
+/* mutex attributes and mutex type */
+typedef int pthread_mutexattr_t;
+typedef mutex_t pthread_mutex_t;
+
+/* mutex and condition variable scope - process or system */
+#define PTHREAD_SHARE_PRIVATE USYNC_THREAD
+#define PTHREAD_SHARE_PROCESS USYNC_PROCESS
+
+/* condition variable attributes and condition variable type */
+typedef int pthread_condattr_t;
+typedef cond_t pthread_cond_t;
+
+#else /* end sunos5 */
+
+#if defined( THREAD_MIT_PTHREADS )
+/***********************************
+ * *
+ * definitions for mit pthreads *
+ * *
+ ***********************************/
+
+#define _THREAD
+
+#include <pthread.h>
+
+#else /* end mit pthreads */
+
+#if defined( THREAD_AIX_PTHREADS )
+/***********************************
+ * *
+ * definitions for aix pthreads *
+ * *
+ ***********************************/
+
+#define _THREAD
+
+#include <pthread.h>
+
+typedef void *(*VFP)(void *);
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE 0
+
+/* default attr states */
+#define pthread_mutexattr_default NULL
+#define pthread_condattr_default NULL
+
+#else /* aix pthreads */
+
+#if defined( THREAD_HP_DCE_PTHREADS )
+/**************************************
+ * *
+ * definitions for HP dce pthreads *
+ * *
+ **************************************/
+
+#define _THREAD
+typedef void *(*VFP)();
+
+#include <pthread.h>
+
+/* dce threads are preemptive */
+#define PTHREAD_PREEMPTIVE 1
+
+/* pthread_kill() is a noop on HP */
+#define PTHREAD_KILL_IS_NOOP 1
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED 1
+
+#define pthread_attr_init( a ) pthread_attr_create( a )
+#define pthread_attr_destroy( a ) pthread_attr_delete( a )
+#define pthread_attr_setdetachstate( a, b ) \
+ pthread_attr_setdetach_np( a, b )
+/*
+ * HP's DCE threads implementation passes a (pthread_attr_t *)
+ * for the second argument. So, we need to fake things a bit.
+ * hpdce_pthread_create_detached() is in thread.c. Note that we
+ * create threads and detach them. If you need to create a joinable
+ * thread, you need to call hpdce_pthread_create_joinable() directly.
+ */
+#define pthread_create( a, b, c, d ) \
+ hpdce_pthread_create_detached( a, b, c, d )
+
+int
+hpdce_pthread_create_joinable( pthread_t *tid, pthread_attr_t *attr,
+ VFP func, void *arg );
+int hpdce_pthread_create_detached( pthread_t *tid, pthread_attr_t *attr,
+ VFP func, void *arg );
+#else /* HP dce pthreads */
+
+#if defined( THREAD_DCE_PTHREADS )
+/***********************************
+ * *
+ * definitions for dce pthreads *
+ * *
+ ***********************************/
+
+#define _THREAD
+typedef void *(*VFP)();
+
+#include <pthread.h>
+
+/* dce threads are preemptive */
+#define PTHREAD_PREEMPTIVE 1
+
+/* thread state - joinable or not */
+#ifndef PTHREAD_CREATE_JOINABLE
+#define PTHREAD_CREATE_JOINABLE 0
+#endif
+#ifndef PTHREAD_CREATE_DETACHED
+#define PTHREAD_CREATE_DETACHED 1
+#endif
+
+#define pthread_attr_init( a ) pthread_attr_create( a )
+#define pthread_attr_destroy( a ) pthread_attr_delete( a )
+#define pthread_attr_setdetachstate( a, b ) \
+ pthread_attr_setdetach_np( a, b )
+#if defined( OSF1 )
+/* pthread_create's second parameter is passed by value, not by reference.
+ * To work around this, call another function instead:
+ */
+#define pthread_create( a, b, c, d ) std_pthread_create( a, b, c, d )
+extern int
+std_pthread_create (pthread_t *tid,
+ pthread_attr_t *attr,
+ pthread_startroutine_t func,
+ pthread_addr_t arg); /* defined in thread.c */
+
+/* OSF1 doesn't support pthread_kill() */
+#define PTHREAD_KILL_IS_NOOP 1
+
+#endif /* OSF1 */
+
+#else /* dce pthreads */
+
+#if defined( THREAD_SGI_SPROC )
+/***********************************
+ * *
+ * thread definitions for sgi irix *
+ * *
+ ***********************************/
+
+#define _THREAD
+
+#include <sys/types.h>
+#include <sys/signal.h>
+#include <sys/procset.h>
+#include <sys/prctl.h>
+#include <ulocks.h>
+
+typedef void *(*VFP)(void *);
+
+/* sgi threads are preemptive */
+#define PTHREAD_PREEMPTIVE 1
+
+/* thread attributes and thread type */
+typedef int pthread_attr_t;
+typedef pid_t pthread_t;
+
+/* default attr states */
+#define pthread_mutexattr_default 0
+#define pthread_condattr_default 0
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED 1
+/* thread scope - who is in scheduling pool */
+#define PTHREAD_SCOPE_PROCESS 0
+#define PTHREAD_SCOPE_SYSTEM 1
+
+/* mutex attributes and mutex type */
+typedef int pthread_mutexattr_t;
+typedef int pthread_mutex_t;
+
+/* mutex and condition variable scope - process or system */
+#define PTHREAD_SHARE_PRIVATE 0
+#define PTHREAD_SHARE_PROCESS 1
+
+/* condition variable attributes and condition variable type */
+typedef int pthread_condattr_t;
+struct irix_cv_waiter {
+ pid_t icvw_pid;
+ struct irix_cv_waiter *icvw_next;
+};
+typedef struct irix_cv {
+ pthread_mutex_t icv_mutex;
+ pthread_mutex_t *icv_waitermutex;
+ struct irix_cv_waiter *icv_waiterq;
+} pthread_cond_t;
+
+#else
+
+#if defined( WIN32_KERNEL_THREADS )
+
+/***********************************
+ * *
+ * thread definitions for Win32 *
+ * *
+ ***********************************/
+
+#define _THREAD
+
+#include <windows.h>
+#include <process.h>
+#include "ldap.h"
+#include "ldaplog.h"
+
+typedef void (*VFP)(void *);
+
+/* Win32 threads are preemptive */
+#define PTHREAD_PREEMPTIVE 1
+
+/* thread attributes and thread type */
+typedef int pthread_attr_t;
+typedef HANDLE pthread_t;
+
+/* default attr states */
+#define pthread_mutexattr_default 0
+#define pthread_condattr_default 0
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED 1
+/* thread scope - who is in scheduling pool */
+#define PTHREAD_SCOPE_PROCESS 0
+#define PTHREAD_SCOPE_SYSTEM 1
+
+/* mutex attributes and mutex type */
+typedef int pthread_mutexattr_t;
+typedef HANDLE pthread_mutex_t;
+
+/* mutex and condition variable scope - process or system */
+#define PTHREAD_SHARE_PRIVATE 0
+#define PTHREAD_SHARE_PROCESS 1
+
+/* condition variable attributes and condition variable type */
+typedef int pthread_condattr_t;
+
+/* simulated condition variable */
+struct win32_cv_waiter {
+ pthread_t icvw_pthread;
+ struct win32_cv_waiter *icvw_next;
+};
+typedef struct win32_cv {
+ pthread_mutex_t icv_mutex;
+ pthread_mutex_t *icv_waitermutex;
+ struct win32_cv_waiter *icv_waiterq;
+} pthread_cond_t;
+
+#endif /* NATIVE_WIN32_THREADS */
+#endif /* sgi sproc */
+#endif /* dce pthreads */
+#endif /* hp dce pthreads */
+#endif /* aix pthreads */
+#endif /* mit pthreads */
+#endif /* sunos5 */
+#endif /* sunos4 */
+
+#ifndef _THREAD
+
+/***********************************
+ * *
+ * thread definitions for no *
+ * underlying library support *
+ * *
+ ***********************************/
+
+typedef void *(*VFP)();
+
+/* thread attributes and thread type */
+typedef int pthread_attr_t;
+typedef int pthread_t;
+
+/* default attr states */
+#define pthread_mutexattr_default NULL
+#define pthread_condattr_default NULL
+
+/* thread state - joinable or not */
+#define PTHREAD_CREATE_JOINABLE 0
+#define PTHREAD_CREATE_DETACHED 0
+/* thread scope - who is in scheduling pool */
+#define PTHREAD_SCOPE_PROCESS 0
+#define PTHREAD_SCOPE_SYSTEM 0
+
+/* mutex attributes and mutex type */
+typedef int pthread_mutexattr_t;
+typedef int pthread_mutex_t;
+
+/* mutex and condition variable scope - process or system */
+#define PTHREAD_SHARE_PRIVATE 0
+#define PTHREAD_SHARE_PROCESS 0
+
+/* condition variable attributes and condition variable type */
+typedef int pthread_condattr_t;
+typedef int pthread_cond_t;
+
+#endif /* no threads support */
+
+/* POSIX standard pthread function declarations: */
+
+int pthread_attr_init( pthread_attr_t *attr );
+int pthread_attr_destroy( pthread_attr_t *attr );
+int pthread_attr_getdetachstate( pthread_attr_t *attr, int *detachstate );
+int pthread_attr_setdetachstate( pthread_attr_t *attr, int detachstate );
+
+int pthread_create( pthread_t *tid, pthread_attr_t *attr, VFP func, void *arg );
+void pthread_yield();
+void pthread_exit();
+int pthread_kill( pthread_t tid, int sig );
+#if defined( hpux ) || defined( OSF1 ) || defined( AIXV4 ) /* <thread.h> declares pthread_join */
+#else
+int pthread_join( pthread_t tid, int *status );
+#endif
+
+#if defined( hpux ) || defined( OSF1 ) /* <thread.h> declares pthread_mutex_init */
+#else
+int pthread_mutex_init( pthread_mutex_t *mp, pthread_mutexattr_t *attr );
+#endif
+int pthread_mutex_destroy( pthread_mutex_t *mp );
+int pthread_mutex_lock( pthread_mutex_t *mp );
+int pthread_mutex_unlock( pthread_mutex_t *mp );
+int pthread_mutex_trylock( pthread_mutex_t *mp );
+
+#if defined( hpux ) || defined( OSF1 ) /* <thread.h> declares pthread_cond_init */
+#else
+int pthread_cond_init( pthread_cond_t *cv, pthread_condattr_t *attr );
+#endif
+int pthread_cond_destroy( pthread_cond_t *cv );
+int pthread_cond_wait( pthread_cond_t *cv, pthread_mutex_t *mp );
+int pthread_cond_signal( pthread_cond_t *cv );
+int pthread_cond_broadcast( pthread_cond_t *cv );
+
+#endif /* _LTHREAD_H */
diff --git a/ldap/include/ntslapdregparms.h b/ldap/include/ntslapdregparms.h
new file mode 100644
index 00000000..ea1ff559
--- /dev/null
+++ b/ldap/include/ntslapdregparms.h
@@ -0,0 +1,41 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/******************************************************
+ *
+ *
+ * ntslapdregparms.h - NT Registry keys for Slapd.
+ *
+ ******************************************************/
+
+#if defined( _WIN32 )
+
+#if !defined( _NTSLAPDREGPARMS_H_ )
+#define _NTSLAPDREGPARMS_H_
+
+#define COMPANY_KEY "SOFTWARE\\Netscape"
+#define COMPANY_NAME "Netscape Communications Corp."
+#define PROGRAM_GROUP_NAME "Netscape"
+#define PRODUCT_NAME "slapd"
+#define PRODUCT_BIN "ns-slapd"
+#define SLAPD_EXE "slapd.exe"
+#define SERVICE_EXE SLAPD_EXE
+#define SLAPD_CONF "slapd.conf"
+#define MAGNUS_CONF SLAPD_CONF
+#define SLAPD_DONGLE_FILE "password.dng"
+#define DONGLE_FILE_NAME SLAPD_DONGLE_FILE
+#define PRODUCT_VERSION "1.0"
+#define EVENTLOG_APPNAME "NetscapeSlapd"
+#define DIRECTORY_SERVICE_PREFIX "Netscape Directory Server "
+#define SERVICE_PREFIX DIRECTORY_SERVICE_PREFIX
+#define CONFIG_PATH_KEY "ConfigurationPath"
+#define EVENTLOG_MESSAGES_KEY "EventMessageFile"
+#define EVENT_LOG_KEY "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application"
+#define ADMIN_REGISTRY_ROOT_KEY "Admin Server"
+#define SLAPD_REGISTRY_ROOT_KEY "Slapd Server"
+#define PRODUCT_KEY SLAPD_REGISTRY_ROOT_KEY
+#endif /* _NTSLAPDREGPARMS_H_ */
+
+#endif /* _WIN32 */
diff --git a/ldap/include/ntwatchdog.h b/ldap/include/ntwatchdog.h
new file mode 100644
index 00000000..ced95daa
--- /dev/null
+++ b/ldap/include/ntwatchdog.h
@@ -0,0 +1,68 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/******************************************************
+ *
+ *
+ * ntwatchdog.h - Defs for NT Watchdog Service.
+ *
+ ******************************************************/
+
+#if defined( _WIN32 )
+
+#if !defined( _NTWATCHDOG_H_ )
+#define _NTWATCHDOG_H_
+
+#define FILE_PATHSEP '/'
+
+#define SLAPD_ROOT "SLAPD_ROOT" // environment variable holding server root path
+#define MORTALITY_KEY "MortalityTimeSecs"
+#define MINRAMFREE_KEY "MinRamFree"
+#define MINRAMTOTAL_KEY "MinRamTotal"
+#define MINRAMPERSERVER_KEY "MinRamPerServer"
+#define DEFAULT_MORTALITY_TIME 60 // seconds after startup up until server will NOT be restarted
+#define DEFAULT_KILL_TIME 600 // seconds to wait for httpd.exe to shutdown
+#define DEFAULT_CRON_TIME 60 // seconds to wait before rechecking cron.conf
+#define DEFAULT_RESTART_TIME 10 // seconds to wait before restarting server
+#define DEFAULT_MINRAMFREE 0 // KB free physical memory remaining
+#define DEFAULT_MINRAMTOTAL (30 * 1024) // KB free physical memory installed
+#define DEFAULT_MINRAMPERSERVER (15 * 1024) // KB free physical memory per server
+
+#define MSG_RESOURCES "Not enough physical memory to start server."
+
+// offsets for extra window bytes, used in Set/GetWindowLong()
+#define GWL_PROCESS_HANDLE (sizeof(LONG) * 0)
+#define GWL_PASSWORD_ADDR (sizeof(LONG) * 1)
+#define GWL_PASSWORD_LENGTH (sizeof(LONG) * 2)
+
+#define MAX_LINE 512
+#define MAX_PASSWORD 256
+#define MAX_TOKENNAME 50
+
+typedef struct PK11_PIN
+{
+ char TokenName[MAX_TOKENNAME];
+ int TokenLength;
+ char Password[MAX_PASSWORD];
+ int PasswordLength;
+}PK11_PIN;
+
+#define CLOSEHANDLE(X) \
+{ \
+ if(X) \
+ { \
+ CloseHandle(X); \
+ X = 0; \
+ } \
+}
+
+// in ntcron.c
+LPTHREAD_START_ROUTINE CRON_ThreadProc(HANDLE hevWatchDogExit);
+
+// in watchdog.c
+BOOL WD_SysLog(WORD fwEventType, DWORD IDEvent, char *szData);
+
+#endif /* _NTWATCHDOG_H_ */
+#endif /* _WIN32 */
diff --git a/ldap/include/portable.h b/ldap/include/portable.h
new file mode 100644
index 00000000..2934db6d
--- /dev/null
+++ b/ldap/include/portable.h
@@ -0,0 +1,380 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#ifndef _PORTABLE_H
+#define _PORTABLE_H
+
+/*
+ * portable.h for LDAP -- this is where we define common stuff to make
+ * life easier on various Unix systems.
+ *
+ * Unless you are porting LDAP to a new platform, you should not need to
+ * edit this file.
+ */
+
+#ifndef SYSV
+#if defined( hpux ) || defined( sunos5 ) || defined ( sgi ) || defined( SVR4 )
+#define SYSV
+#endif
+#endif
+
+/*
+ * under System V, use sysconf() instead of getdtablesize
+ */
+#if !defined( USE_SYSCONF ) && defined( SYSV )
+#define USE_SYSCONF
+#endif
+
+/*
+ * under System V, daemons should use setsid() instead of detaching from their
+ * tty themselves
+ */
+#if !defined( USE_SETSID ) && defined( SYSV )
+#define USE_SETSID
+#endif
+
+/*
+ * System V has socket options in filio.h
+ */
+#if !defined( NEED_FILIO ) && defined( SYSV ) && !defined( hpux ) && !defined( AIX )
+#define NEED_FILIO
+#endif
+
+/*
+ * use lockf() under System V
+ */
+#if !defined( USE_LOCKF ) && ( defined( SYSV ) || defined( aix ))
+#define USE_LOCKF
+#endif
+
+/*
+ * on many systems, we should use waitpid() instead of waitN()
+ */
+#if !defined( USE_WAITPID ) && ( defined( SYSV ) || defined( sunos4 ) || defined( ultrix ) || defined( aix ))
+#define USE_WAITPID
+#endif
+
+/*
+ * define the wait status argument type
+ */
+#if ( defined( SunOS ) && SunOS < 40 ) || defined( nextstep )
+#define WAITSTATUSTYPE union wait
+#else
+#define WAITSTATUSTYPE int
+#endif
+
+/*
+ * define the flags for wait
+ */
+#ifdef sunos5
+#define WAIT_FLAGS ( WNOHANG | WUNTRACED | WCONTINUED )
+#else
+#define WAIT_FLAGS ( WNOHANG | WUNTRACED )
+#endif
+
+/*
+ * defined the options for openlog (syslog)
+ */
+#ifdef ultrix
+#define OPENLOG_OPTIONS LOG_PID
+#else
+#define OPENLOG_OPTIONS ( LOG_PID | LOG_NOWAIT )
+#endif
+
+/*
+ * We use the internal regex on all systems now.
+ */
+#ifndef NEED_BSDREGEX
+#define NEED_BSDREGEX
+#endif
+
+/*
+ * many systems do not have the setpwfile() library routine... we just
+ * enable use for those systems we know have it.
+ */
+#ifndef HAVE_SETPWFILE
+#if defined( sunos4 ) || defined( ultrix ) || defined( OSF1 )
+#define HAVE_SETPWFILE
+#endif
+#endif
+
+/*
+ * Are sys_errlist and sys_nerr declared in stdio.h?
+ */
+#ifndef SYSERRLIST_IN_STDIO
+#if defined( freebsd ) || defined(Linux)
+#define SYSERRLIST_IN_STDIO
+#endif
+#endif
+
+/*
+ * for select()
+ */
+#if !defined(WINSOCK) && !defined(_WINDOWS) && !defined(macintosh)
+#if defined(hpux) || defined(LINUX2_0)
+#include <sys/time.h>
+#else
+#include <sys/select.h>
+#endif
+#if !defined(FD_SET)
+#define NFDBITS 32
+#define FD_SETSIZE 32
+#define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
+#define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
+#define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
+#define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
+#endif /* !FD_SET */
+#endif /* !WINSOCK && !_WINDOWS && !macintosh */
+
+
+/*
+ * for connect() -- must we block signals when calling connect()? This
+ * is necessary on some buggy UNIXes.
+ */
+#if !defined(LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED) && \
+ ( defined(AIX) || defined(IRIX) || defined(HPUX) || defined(SUNOS4))
+#define LDAP_CONNECT_MUST_NOT_BE_INTERRUPTED
+#endif
+
+
+/*
+ * Some DNS resolver implementations, such as the one built into
+ * Solaris <= 8, need to use one or more low numbered file
+ * descriptors internally (probably because they use a deficient
+ * implementation of stdio).
+ */
+#if defined(SOLARIS) || defined(IRIX)
+#define RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
+#endif
+
+
+
+/*
+ * for signal() -- what do signal handling functions return?
+ */
+#ifndef SIG_FN
+#ifdef sunos5
+# define SIG_FN void /* signal-catching functions return void */
+#else /* sunos5 */
+# ifdef BSD
+# if (BSD >= 199006) || defined(NeXT) || defined(OSF1) || defined(sun) || defined(ultrix) || defined(apollo) || defined(POSIX_SIGNALS)
+# define SIG_FN void /* signal-catching functions return void */
+# else
+# define SIG_FN int /* signal-catching functions return int */
+# endif
+# else /* BSD */
+# define SIG_FN void /* signal-catching functions return void */
+# endif /* BSD */
+#endif /* sunos5 */
+#endif /* SIG_FN */
+
+/*
+ * toupper and tolower macros are different under bsd and sys v
+ */
+#if defined( SYSV ) && !defined( hpux )
+#define TOUPPER(c) (isascii(c) && islower(c) ? _toupper(c) : c)
+#define TOLOWER(c) (isascii(c) && isupper(c) ? _tolower(c) : c)
+#else
+#define TOUPPER(c) (isascii(c) && islower(c) ? toupper(c) : c)
+#define TOLOWER(c) (isascii(c) && isupper(c) ? tolower(c) : c)
+#endif
+
+/*
+ * put a cover on the tty-related ioctl calls we need to use
+ */
+#if defined( NeXT ) || (defined(SunOS) && SunOS < 40)
+#define TERMIO_TYPE struct sgttyb
+#define TERMFLAG_TYPE int
+#define GETATTR( fd, tiop ) ioctl((fd), TIOCGETP, (caddr_t)(tiop))
+#define SETATTR( fd, tiop ) ioctl((fd), TIOCSETP, (caddr_t)(tiop))
+#define GETFLAGS( tio ) (tio).sg_flags
+#define SETFLAGS( tio, flags ) (tio).sg_flags = (flags)
+#else
+#define USE_TERMIOS
+#define TERMIO_TYPE struct termios
+#define TERMFLAG_TYPE tcflag_t
+#define GETATTR( fd, tiop ) tcgetattr((fd), (tiop))
+#define SETATTR( fd, tiop ) tcsetattr((fd), TCSANOW /* 0 */, (tiop))
+#define GETFLAGS( tio ) (tio).c_lflag
+#define SETFLAGS( tio, flags ) (tio).c_lflag = (flags)
+#endif
+
+#if ( !defined( HPUX9 )) && ( !defined( sunos4 )) && ( !defined( SNI )) && \
+ ( !defined( HAVE_TIME_R ) )
+#define HAVE_TIME_R
+#endif
+
+#if defined( sunos5 ) || defined( aix )
+#define HAVE_GETPWNAM_R
+#define HAVE_GETGRNAM_R
+#endif
+
+#if defined(SNI) || defined(LINUX1_2)
+int strcasecmp(const char *, const char *);
+#ifdef SNI
+int strncasecmp(const char *, const char *, int);
+#endif /* SNI */
+#ifdef LINUX1_2
+int strncasecmp(const char *, const char *, size_t);
+#endif /* LINUX1_2 */
+#endif /* SNI || LINUX1_2 */
+
+#if defined(_WINDOWS) || defined(macintosh)
+#define GETHOSTBYNAME( n, r, b, l, e ) gethostbyname( n )
+#define CTIME( c, b, l ) ctime( c )
+#define STRTOK( s1, s2, l ) strtok( s1, s2 )
+#else /* UNIX */
+#if defined(sgi) || defined(HPUX9) || defined(LINUX1_2) || defined(SCOOS) || \
+ defined(UNIXWARE) || defined(SUNOS4) || defined(SNI) || defined(BSDI) || \
+ defined(NCR) || defined(OSF1) || defined(NEC) || \
+ ( defined(HPUX10) && !defined(_REENTRANT)) || defined(HPUX11) || \
+ defined(UnixWare) || defined(LINUX2_0)
+#define GETHOSTBYNAME( n, r, b, l, e ) gethostbyname( n )
+#elif defined(AIX)
+#define GETHOSTBYNAME_BUF_T struct hostent_data
+#define GETHOSTBYNAME( n, r, b, l, e ) \
+ (memset (&b, 0, l), gethostbyname_r (n, r, &b) ? NULL : r)
+#elif defined(HPUX10)
+#define GETHOSTBYNAME_BUF_T struct hostent_data
+#define GETHOSTBYNAME( n, r, b, l, e ) nsldapi_compat_gethostbyname_r( n, r, (char *)&b, l, e )
+#else
+#include <stdio.h> /* BUFSIZ */
+typedef char GETHOSTBYNAME_buf_t [BUFSIZ /* XXX might be too small */];
+#define GETHOSTBYNAME_BUF_T GETHOSTBYNAME_buf_t
+#define GETHOSTBYNAME( n, r, b, l, e ) gethostbyname_r( n, r, b, l, e )
+#endif
+
+/*
+ * XXXmcs: GETHOSTBYADDR() is only defined for IRIX/SGI and Solaris for now.
+ */
+#if defined(sgi)
+#define GETHOSTBYADDR( a, al, t, h, b, bl, e ) \
+ gethostbyaddr( a, al, t )
+#elif defined(SOLARIS)
+#include <stdio.h> /* BUFSIZ */
+typedef char GETHOSTBYADDR_buf_t [BUFSIZ];
+#define GETHOSTBYADDR_BUF_T GETHOSTBYADDR_buf_t
+#define GETHOSTBYADDR( a, al, t, h, b, bl, e ) \
+ gethostbyaddr_r( a, al, t, h, b, bl, e )
+#endif
+
+
+#if defined(HPUX9) || defined(LINUX1_2) || defined(SUNOS4) || defined(SNI) || \
+ defined(SCOOS) || defined(BSDI) || defined(NCR) || \
+ defined(NEC) || ( defined(HPUX10) && !defined(_REENTRANT))
+#define CTIME( c, b, l ) ctime( c )
+#elif defined( hpux10 )
+#define CTIME( c, b, l ) nsldapi_compat_ctime_r( c, b, l )
+#elif defined( IRIX ) || defined(UNIXWARE) || defined(LINUX) \
+ || defined(OSF1V4) || defined(AIX) || defined(UnixWare) || defined (HPUX11)
+#define CTIME( c, b, l ) ctime_r( c, b )
+#elif defined( OSF1V3 )
+#define CTIME( c, b, l ) (ctime_r( c, b, l ) ? NULL : b)
+#else
+#define CTIME( c, b, l ) ctime_r( c, b, l )
+#endif
+#if defined(hpux9) || defined(LINUX1_2) || defined(SUNOS4) || defined(SNI) || \
+ defined(SCOOS) || defined(BSDI) || defined(NCR) || \
+ defined(NEC) || defined(LINUX2_0)
+/* strtok() is not MT safe, but it is okay to call here because used in mmt_protocol.xs which
+ has been moved in the tetframewrok */
+#define STRTOK( s1, s2, l ) strtok( s1, s2 )
+#else
+#define HAVE_STRTOK_R
+char *strtok_r(char *, const char *, char **);
+#define STRTOK( s1, s2, l ) (char *)strtok_r( s1, s2, l )
+#endif /* STRTOK */
+#endif /* UNIX */
+
+#if defined( ultrix ) || defined( nextstep )
+extern char *strdup();
+#endif /* ultrix || nextstep */
+
+#if defined( sunos4 ) || defined( OSF1 )
+#define BSD_TIME 1 /* for servers/slapd/log.h */
+#endif /* sunos4 || osf */
+
+#ifdef SOLARIS
+#include <netinet/in.h>
+#include <arpa/inet.h> /* for inet_addr() */
+#endif /* SOLARIS */
+
+#ifdef SUNOS4
+#include <pcfs/pc_dir.h> /* for toupper() */
+int fprintf(FILE *, char *, ...);
+int fseek(FILE *, long, int);
+int fread(char *, int, int, FILE *);
+int fclose(FILE *);
+int fflush(FILE *);
+int rewind(FILE *);
+void *memmove(void *, const void *, size_t);
+int strcasecmp(char *, char *);
+int strncasecmp(char *, char *, int);
+time_t time(time_t *);
+void perror(char *);
+int fputc(char, FILE *);
+int fputs(char *, FILE *);
+int LDAP_CALL re_exec(char *);
+int socket(int, int, int);
+void bzero(char *, int);
+unsigned long inet_addr(char *);
+char * inet_ntoa(struct in_addr);
+int getdtablesize();
+int connect(int, struct sockaddr *, int);
+#endif /* SUNOS4 */
+
+/* #if defined(SUNOS4) || defined(SNI) */
+#if defined(SUNOS4)
+int select(int, fd_set *, fd_set *, fd_set *, struct timeval *);
+#endif /* SUNOS4 || SNI */
+
+/*
+ * SAFEMEMCPY is an overlap-safe copy from s to d of n bytes
+ */
+#ifdef macintosh
+#define SAFEMEMCPY( d, s, n ) BlockMoveData( (Ptr)s, (Ptr)d, n )
+#else /* macintosh */
+#ifdef sunos4
+#define SAFEMEMCPY( d, s, n ) bcopy( s, d, n )
+#else /* sunos4 */
+#define SAFEMEMCPY( d, s, n ) memmove( d, s, n )
+#endif /* sunos4 */
+#endif /* macintosh */
+
+#ifdef _WINDOWS
+
+#undef strcasecmp
+#define strcasecmp strcmpi
+#undef strncasecmp
+#define strncasecmp _strnicmp
+#define bzero(a, b) memset( a, 0, b )
+#define getpid _getpid
+#define ioctl ioctlsocket
+#undef sleep
+#define sleep(a) Sleep( a*1000 )
+
+#define EMSGSIZE WSAEMSGSIZE
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#define EHOSTUNREACH WSAEHOSTUNREACH
+
+#if !defined(MAXPATHLEN)
+#define MAXPATHLEN _MAX_PATH
+#endif
+
+#endif
+
+#endif /* _PORTABLE_H */
diff --git a/ldap/include/proto-ntutil.h b/ldap/include/proto-ntutil.h
new file mode 100644
index 00000000..879387b3
--- /dev/null
+++ b/ldap/include/proto-ntutil.h
@@ -0,0 +1,79 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/******************************************************
+ *
+ *
+ * proto-ntutil.h - Prototypes for utility functions used
+ * throughout slapd on NT.
+ *
+ ******************************************************/
+#if defined( _WINDOWS )
+
+#ifndef _PROTO_NTUTIL
+#define _PROTO_NTUTIL
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ *
+ * ntreg.c
+ *
+ */
+extern int SlapdGetRegSZ( LPTSTR lpszRegKey, LPSTR lpszValueName, LPTSTR lpszValue );
+extern void unixtodospath(char *szText);
+extern void dostounixpath(char *szText);
+
+
+/*
+ *
+ * getopt.c
+ *
+ */
+extern int getopt (int argc, char *const *argv, const char *optstring);
+extern char *optarg;
+/*
+ *
+ * ntevent.c
+ *
+ */
+extern BOOL MultipleInstances();
+extern BOOL SlapdIsAService();
+extern void InitializeSlapdLogging( LPTSTR lpszRegLocation, LPTSTR lpszEventLogName, LPTSTR lpszMessageFile );
+extern void ReportSlapdEvent(WORD wEventType, DWORD dwIdEvent, WORD wNumInsertStrings,
+ char *pszStrings);
+extern BOOL ReportSlapdStatusToSCMgr(
+ SERVICE_STATUS *serviceStatus,
+ SERVICE_STATUS_HANDLE serviceStatusHandle,
+ HANDLE Event,
+ DWORD dwCurrentState,
+ DWORD dwWin32ExitCode,
+ DWORD dwCheckPoint,
+ DWORD dwWaitHint);
+extern void WINAPI SlapdServiceCtrlHandler(DWORD dwOpcode);
+extern BOOL SlapdGetServerNameFromCmdline(char *szServerName, char *szCmdLine, int dirname);
+
+/*
+ *
+ * ntgetpassword.c
+ *
+ */
+#ifdef NET_SSL
+extern char *Slapd_GetPassword();
+#ifdef FORTEZZA
+extern char *Slapd_GetFortezzaPIN();
+#endif
+extern void CenterDialog(HWND hwndParent, HWND hwndDialog);
+#endif /* NET_SSL */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PROTO_NTUTIL */
+
+#endif /* _WINDOWS */
diff --git a/ldap/include/regex.h b/ldap/include/regex.h
new file mode 100644
index 00000000..8d8f1e3c
--- /dev/null
+++ b/ldap/include/regex.h
@@ -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 **/
+#if defined( macintosh ) || defined( DOS ) || defined( _WINDOWS ) || defined( NEED_BSDREGEX )
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+/*
+ * regex.h -- includes for regular expression matching routines
+ * 13 August 1993 Mark C Smith
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ldap.h"
+
+#if !defined( NEEDPROTOS ) && defined( __STDC__ )
+#define NEEDPROTOS
+#endif
+
+#ifdef _SLDAPD_H_ /* server build: no need to use LDAP_CALL stuff */
+#ifdef LDAP_CALL
+#undef LDAP_CALL
+#define LDAP_CALL
+#endif
+#endif
+
+#ifdef NEEDPROTOS
+int slapd_re_init( void );
+void slapd_re_lock( void );
+int slapd_re_unlock( void );
+char * LDAP_CALL slapd_re_comp( char *pat );
+int LDAP_CALL slapd_re_exec( char *lp );
+void LDAP_CALL slapd_re_modw( char *s );
+int LDAP_CALL slapd_re_subs( char *src, char *dst );
+#else /* NEEDPROTOS */
+int slapd_re_init();
+void slapd_re_lock();
+int slapd_re_unlock();
+char * LDAP_CALL slapd_re_comp();
+int LDAP_CALL slapd_re_exec();
+void LDAP_CALL slapd_re_modw();
+int LDAP_CALL slapd_re_subs();
+#endif /* NEEDPROTOS */
+
+#define re_fail( m, p )
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* macintosh or DOS or or _WIN32 or NEED_BSDREGEX */
diff --git a/ldap/include/srchpref.h b/ldap/include/srchpref.h
new file mode 100644
index 00000000..e78f4441
--- /dev/null
+++ b/ldap/include/srchpref.h
@@ -0,0 +1,123 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1993, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ *
+ * searchpref.h: display template library defines
+ * 16 May 1994 by Gordon Good
+ */
+
+
+#ifndef _SRCHPREF_H
+#define _SRCHPREF_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* calling conventions used by library */
+#ifndef LDAP_CALL
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#define LDAP_C __cdecl
+#ifndef _WIN32
+#define __stdcall _far _pascal
+#define LDAP_CALLBACK _loadds
+#else
+#define LDAP_CALLBACK
+#endif /* _WIN32 */
+#define LDAP_PASCAL __stdcall
+#define LDAP_CALL LDAP_PASCAL
+#else /* _WINDOWS */
+#define LDAP_C
+#define LDAP_CALLBACK
+#define LDAP_PASCAL
+#define LDAP_CALL
+#endif /* _WINDOWS */
+#endif /* LDAP_CALL */
+
+struct ldap_searchattr {
+ char *sa_attrlabel;
+ char *sa_attr;
+ /* max 32 matchtypes for now */
+ unsigned long sa_matchtypebitmap;
+ char *sa_selectattr;
+ char *sa_selecttext;
+ struct ldap_searchattr *sa_next;
+};
+
+struct ldap_searchmatch {
+ char *sm_matchprompt;
+ char *sm_filter;
+ struct ldap_searchmatch *sm_next;
+};
+
+struct ldap_searchobj {
+ char *so_objtypeprompt;
+ unsigned long so_options;
+ char *so_prompt;
+ short so_defaultscope;
+ char *so_filterprefix;
+ char *so_filtertag;
+ char *so_defaultselectattr;
+ char *so_defaultselecttext;
+ struct ldap_searchattr *so_salist;
+ struct ldap_searchmatch *so_smlist;
+ struct ldap_searchobj *so_next;
+};
+
+#define NULLSEARCHOBJ ((struct ldap_searchobj *)0)
+
+/*
+ * global search object options
+ */
+#define LDAP_SEARCHOBJ_OPT_INTERNAL 0x00000001
+
+#define LDAP_IS_SEARCHOBJ_OPTION_SET( so, option ) \
+ (((so)->so_options & option ) != 0 )
+
+#define LDAP_SEARCHPREF_VERSION_ZERO 0
+#define LDAP_SEARCHPREF_VERSION 1
+
+#define LDAP_SEARCHPREF_ERR_VERSION 1
+#define LDAP_SEARCHPREF_ERR_MEM 2
+#define LDAP_SEARCHPREF_ERR_SYNTAX 3
+#define LDAP_SEARCHPREF_ERR_FILE 4
+
+
+LDAP_API(int)
+LDAP_CALL
+ldap_init_searchprefs( char *file, struct ldap_searchobj **solistp );
+
+LDAP_API(int)
+LDAP_CALL
+ldap_init_searchprefs_buf( char *buf, long buflen,
+ struct ldap_searchobj **solistp );
+
+LDAP_API(void)
+LDAP_CALL
+ldap_free_searchprefs( struct ldap_searchobj *solist );
+
+LDAP_API(struct ldap_searchobj *)
+LDAP_CALL
+ldap_first_searchobj( struct ldap_searchobj *solist );
+
+LDAP_API(struct ldap_searchobj *)
+LDAP_CALL
+ldap_next_searchobj( struct ldap_searchobj *sollist,
+ struct ldap_searchobj *so );
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _SRCHPREF_H */
diff --git a/ldap/include/sysexits-compat.h b/ldap/include/sysexits-compat.h
new file mode 100644
index 00000000..be6884d5
--- /dev/null
+++ b/ldap/include/sysexits-compat.h
@@ -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 **/
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that the above copyright notice and this paragraph are
+ * duplicated in all such forms and that any documentation,
+ * advertising materials, and other materials related to such
+ * distribution and use acknowledge that the software was developed
+ * by the University of California, Berkeley. The name of the
+ * University may not be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * @(#)sysexits.h 4.5 (Berkeley) 7/6/88
+ */
+
+/*
+** SYSEXITS.H -- Exit status codes for system programs.
+**
+** This include file attempts to categorize possible error
+** exit statuses for system programs, notably delivermail
+** and the Berkeley network.
+**
+** Error numbers begin at EX__BASE to reduce the possibility of
+** clashing with other exit statuses that random programs may
+** already return. The meaning of the codes is approximately
+** as follows:
+**
+** EX_USAGE -- The command was used incorrectly, e.g., with
+** the wrong number of arguments, a bad flag, a bad
+** syntax in a parameter, or whatever.
+** EX_DATAERR -- The input data was incorrect in some way.
+** This should only be used for user's data & not
+** system files.
+** EX_NOINPUT -- An input file (not a system file) did not
+** exist or was not readable. This could also include
+** errors like "No message" to a mailer (if it cared
+** to catch it).
+** EX_NOUSER -- The user specified did not exist. This might
+** be used for mail addresses or remote logins.
+** EX_NOHOST -- The host specified did not exist. This is used
+** in mail addresses or network requests.
+** EX_UNAVAILABLE -- A service is unavailable. This can occur
+** if a support program or file does not exist. This
+** can also be used as a catchall message when something
+** you wanted to do doesn't work, but you don't know
+** why.
+** EX_SOFTWARE -- An internal software error has been detected.
+** This should be limited to non-operating system related
+** errors as possible.
+** EX_OSERR -- An operating system error has been detected.
+** This is intended to be used for such things as "cannot
+** fork", "cannot create pipe", or the like. It includes
+** things like getuid returning a user that does not
+** exist in the passwd file.
+** EX_OSFILE -- Some system file (e.g., /etc/passwd, /etc/utmp,
+** etc.) does not exist, cannot be opened, or has some
+** sort of error (e.g., syntax error).
+** EX_CANTCREAT -- A (user specified) output file cannot be
+** created.
+** EX_IOERR -- An error occurred while doing I/O on some file.
+** EX_TEMPFAIL -- temporary failure, indicating something that
+** is not really an error. In sendmail, this means
+** that a mailer (e.g.) could not create a connection,
+** and the request should be reattempted later.
+** EX_PROTOCOL -- the remote system returned something that
+** was "not possible" during a protocol exchange.
+** EX_NOPERM -- You did not have sufficient permission to
+** perform the operation. This is not intended for
+** file system problems, which should use NOINPUT or
+** CANTCREAT, but rather for higher level permissions.
+** For example, kre uses this to restrict who students
+** can send mail to.
+**
+** Maintained by Eric Allman (eric@berkeley, ucbvax!eric) --
+** please mail changes to me.
+**
+** @(#)sysexits.h 4.5 7/6/88
+*/
+
+# define EX_OK 0 /* successful termination */
+
+# define EX__BASE 64 /* base value for error messages */
+
+# define EX_USAGE 64 /* command line usage error */
+# define EX_DATAERR 65 /* data format error */
+# define EX_NOINPUT 66 /* cannot open input */
+# define EX_NOUSER 67 /* addressee unknown */
+# define EX_NOHOST 68 /* host name unknown */
+# define EX_UNAVAILABLE 69 /* service unavailable */
+# define EX_SOFTWARE 70 /* internal software error */
+# define EX_OSERR 71 /* system error (e.g., can't fork) */
+# define EX_OSFILE 72 /* critical OS file missing */
+# define EX_CANTCREAT 73 /* can't create (user) output file */
+# define EX_IOERR 74 /* input/output error */
+# define EX_TEMPFAIL 75 /* temp failure; user is invited to retry */
+# define EX_PROTOCOL 76 /* remote error in protocol */
+# define EX_NOPERM 77 /* permission denied */
+# define EX_CONFIG 78 /* configuration error */
diff --git a/ldap/javarules.mk b/ldap/javarules.mk
new file mode 100644
index 00000000..8a35ba37
--- /dev/null
+++ b/ldap/javarules.mk
@@ -0,0 +1,118 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# javarules.mk
+#
+# Identify tools, directories, classpath for building the Directory
+# console
+
+# Where the source root is
+JAVA_SRC_DIR=$(ABS_ROOT)/ldapserver/ldap/admin/src/java
+
+# Where the class files go
+JAVA_BUILD_DIR=$(ABS_ROOT)/ldapserver/built/java/$(BUILD_DEBUG)/admin
+JAVA_DEST_DIR=$(MCOM_ROOT)/ldapserver/built/java/$(BUILD_DEBUG)
+CLASS_DIR=$(JAVA_DEST_DIR)/admin
+DSADMIN_DIR=$(CLASS_DIR)/com/netscape/admin
+
+# Where docs go
+DSADMIN_DOC_DIR=$(JAVA_DEST_DIR)/doc
+
+
+# Java setup ##############################################
+
+# disable optimized builds for now until we can figure out why
+# optimized doesn't build . . .
+ifeq ($(BUILD_DEBUG),optimize)
+# JAVAFLAGS=-O
+ JAVAFLAGS=
+else
+ JAVAFLAGS=-g
+endif
+
+PATH_SEP := :
+ifeq ($(OS), Windows_NT)
+ GET_JAVA_FROM_PATH := 1
+ PATH_SEP := ;
+ EXE_SUFFIX := .exe
+endif
+
+# For NT, assume a locally installed JDK
+ifdef GET_JAVA_FROM_PATH
+ # Figure out where the java lib .jar files are, from where javac is
+ JDKCOMP := $(shell which javac)
+ JDKPRELIB := $(subst bin/javac$(EXE_SUFFIX),lib,$(JDKCOMP))
+ JDKLIB := $(addprefix $(JDKPRELIB)/,tools.jar)
+else
+
+# For UNIX, use JDK and JAR files over NFS
+# Use NT classes.zip; doesn't matter that it was compiled on NT
+#
+# Version 1.4.0_01 of the JDK does not seem to run well on RHEL 3.0
+ ifeq ($(ARCH), Linux)
+ JDK_VERSION=1.4.2
+ else
+ ifeq ($(ARCH), HPUX)
+ JDK_VERSION=1.4.1_05
+ else
+ JDK_VERSION=1.4.0_01
+ endif
+ endif
+
+ JDK_VERSDIR=jdk$(JDK_VERSION)
+ JDKLIB=/share/builds/components/jdk/$(JDK_VERSION)/$(PRETTY_ARCH)/lib/tools.jar
+ ifeq ($(NSOS_ARCH), IRIX)
+# Get IRIX compiler from tools directory, currently 1.1.3
+ JAVABINDIR=/tools/ns/bin
+ else
+ ifeq ($(ARCH), AIX)
+# Get AIX compiler from tools directory, currently 1.1.2
+ JAVABINDIR=/tools/ns/bin
+ else
+ ifeq ($(ARCH), OSF1)
+ JAVABINDIR=/share/builds/components/jdk/1.1.6beta/OSF1/bin
+ else
+# Solaris, Linux, HP/UX and any others:
+ JDK_DIR=$(COMPONENTS_DIR)/jdk
+ JAVABINDIR=$(JDK_DIR)/$(JDK_VERSION)/$(PRETTY_ARCH)/bin
+ endif
+ endif
+ endif
+endif
+
+CLASSPATH := $(JAVA_SRC_DIR)$(PATH_SEP)$(NMCLFJARFILE)$(PATH_SEP)$(LDAPJARFILE)$(PATH_SEP)$(MCCJARFILE)$(PATH_SEP)$(JAVASSLJARFILE)$(PATH_SEP)$(BASEJARFILE)$(PATH_SEP)$(JSSJARFILE)
+#CLASSPATH := $(JAVA_SRC_DIR)$(PATH_SEP)$(SWINGJARFILE)$(PATH_SEP)$(NMCLFJARFILE)$(PATH_SEP)$(LDAPJARFILE)$(PATH_SEP)$(MCCJARFILE)$(PATH_SEP)$(JAVASSLJARFILE)$(PATH_SEP)$(BASEJARFILE)
+
+RUNCLASSPATH:=$(JAVA_BUILD_DIR) $(PACKAGE_UNDER_JAVA)
+
+ifndef JAVA
+ ifdef JAVABINDIR
+ JAVA= $(JAVABINDIR)/java
+ else
+ JAVA=java
+ endif
+endif
+
+# Some java compilers run out of memory, so must be run as follows
+JAVAC_PROG=-mx32m sun.tools.javac.Main
+HEAVY_JAVAC=$(JAVA) $(JAVAC_PROG) $(JAVAFLAGS)
+
+ifndef JAVAC
+ ifdef JAVABINDIR
+ JAVAC= $(JAVABINDIR)/javac $(JAVAFLAGS)
+ else
+ JAVAC= javac $(JAVAFLAGS)
+ endif
+endif
+ifndef JAVADOC
+ JAVADOC=$(JAVA) -mx64m sun.tools.javadoc.Main -classpath "$(CLASSPATH)"
+endif
+
+# How to run ant (the Java "make" system)
+ANT = $(JAVA) -Dant.home=$(ANT_HOME) -classpath "$(ANT_CP)$(PATH_SEP)$(JDKLIB)" org.apache.tools.ant.Main
+
+##########################################################
diff --git a/ldap/ldif/Ace.ldif b/ldap/ldif/Ace.ldif
new file mode 100644
index 00000000..187288a2
--- /dev/null
+++ b/ldap/ldif/Ace.ldif
@@ -0,0 +1,2604 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+dn: o=Ace Industry, c=US
+objectclass: top
+objectclass: organization
+o: Ace Industry
+aci: (target ="ldap:///o=Ace Industry, c=US")(targetattr !="userPassword")(version 3.0;acl "anonymous
+ access";allow (read, search, compare)(userdn = "ldap:///anyone");)
+aci: (target="ldap:///o=Ace Industry, c = US") (targetattr = "*")(version 3.0; acl "allow
+ self write"; allow(write) userdn = "ldap:///self";)
+aci: (target="ldap:///o=Ace Industry, c = US") (targetattr = "*")(version 3.0; acl "Allow
+ all admin group"; allow(all) groupdn = "ldap:///cn=Directory Administrators, o=Ace Industry, c=US";)
+
+dn: ou=Accounting, o=Ace Industry, c=US
+objectclass: top
+objectclass: organizationalunit
+ou: Accounting
+
+dn: ou=Product Development, o=Ace Industry, c=US
+objectclass: top
+objectclass: organizationalunit
+ou: Product Development
+
+dn: ou=Product Testing, o=Ace Industry, c=US
+objectclass: top
+objectclass: organizationalunit
+ou: Product Testing
+
+dn: ou=Human Resources, o=Ace Industry, c=US
+objectclass: top
+objectclass: organizationalunit
+ou: Human Resources
+
+dn: ou=Payroll, o=Ace Industry, c=US
+objectclass: top
+objectclass: organizationalunit
+ou: Payroll
+
+dn: cn=Directory Administrators, o=Ace Industry, c=US
+cn: Directory Administrators
+objectclass: top
+objectclass: groupofuniquenames
+uniquemember: cn=Kirsten Vaughan, ou=Human Resources, o=Ace Industry, c=US
+uniquemember: cn=Robert Daugherty, ou=Human Resources, o=Ace Industry, c=US
+uniquemember: cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US
+uniquemember: cn=Barbara Jablonski, ou=Human Resources, o=Ace Industry, c=US
+uniquemember: cn=Philip Hunt, ou=Human Resources, o=Ace Industry, c=US
+uniquemember: cn=Matthew Tyler, ou=Human Resources, o=Ace Industry, c=US
+
+dn: cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US
+cn: Sam Carter
+sn: Carter
+givenname: Sam
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: scarter
+mail: scarter@aceindustry.com
+telephonenumber: +1 408 555 4798
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4612
+userpassword: sprain
+
+dn: cn=Ted Morris, ou=Accounting, o=Ace Industry, c=US
+cn: Ted Morris
+sn: Morris
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: tmorris
+mail: tmorris@aceindustry.com
+telephonenumber: +1 408 555 9187
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4117
+userpassword: irrefutable
+
+dn: cn=Kirsten Vaughan, ou=Human Resources, o=Ace Industry, c=US
+cn: Kirsten Vaughan
+sn: Vaughan
+givenname: Kirsten
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: kvaughan
+mail: kvaughan@aceindustry.com
+telephonenumber: +1 408 555 5625
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2871
+userpassword: bribery
+
+dn: cn=Andy Bergin, ou=Product Testing, o=Ace Industry, c=US
+cn: Andy Bergin
+sn: Bergin
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Cupertino
+uid: abergin
+mail: abergin@aceindustry.com
+telephonenumber: +1 408 555 8585
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3472
+userpassword: inflict
+
+dn: cn=David Miller, ou=Accounting, o=Ace Industry, c=US
+cn: David Miller
+sn: Miller
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: dmiller
+mail: dmiller@aceindustry.com
+telephonenumber: +1 408 555 9423
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4135
+userpassword: gosling
+
+dn: cn=Gern Farmer, ou=Accounting, o=Ace Industry, c=US
+cn: Gern Farmer
+sn: Farmer
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Cupertino
+uid: gfarmer
+mail: gfarmer@aceindustry.com
+telephonenumber: +1 408 555 6201
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1269
+userpassword: ruling
+
+dn: cn=Kelly Winters, ou=Product Development, o=Ace Industry, c=US
+cn: Kelly Winters
+sn: Winters
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: kwinters
+mail: kwinters@aceindustry.com
+telephonenumber: +1 408 555 9069
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4178
+userpassword: forsook
+
+dn: cn=Torrey Rigden, ou=Product Development, o=Ace Industry, c=US
+cn: Torrey Rigden
+sn: Rigden
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: trigden
+mail: trigden@aceindustry.com
+telephonenumber: +1 408 555 9280
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3584
+userpassword: sensitive
+
+dn: cn=Chris Schmith, ou=Human Resources, o=Ace Industry, c=US
+cn: Chris Schmith
+sn: Schmith
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: cschmith
+mail: cschmith@aceindustry.com
+telephonenumber: +1 408 555 8011
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0416
+userpassword: hypotenuse
+
+dn: cn=Judy Wallace, ou=Accounting, o=Ace Industry, c=US
+cn: Judy Wallace
+sn: Wallace
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: jwallace
+mail: jwallace@aceindustry.com
+telephonenumber: +1 408 555 0319
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1033
+userpassword: linear
+
+dn: cn=John Walker, ou=Product Testing, o=Ace Industry, c=US
+cn: John Walker
+sn: Walker
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Cupertino
+uid: jwalker
+mail: jwalker@aceindustry.com
+telephonenumber: +1 408 555 1476
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3915
+userpassword: dogleg
+
+dn: cn=Torrey Clow, ou=Human Resources, o=Ace Industry, c=US
+cn: Torrey Clow
+sn: Clow
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: tclow
+mail: tclow@aceindustry.com
+telephonenumber: +1 408 555 8825
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4376
+userpassword: cardreader
+
+dn: cn=Robert Daugherty, ou=Human Resources, o=Ace Industry, c=US
+cn: Robert Daugherty
+sn: Daugherty
+givenname: Robert
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: rdaugher
+mail: rdaugher@aceindustry.com
+telephonenumber: +1 408 555 1296
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0194
+userpassword: apples
+
+dn: cn=Jayne Reuter, ou=Product Testing, o=Ace Industry, c=US
+cn: Jayne Reuter
+sn: Reuter
+givenname: Jayne
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Cupertino
+uid: jreuter
+mail: jreuter@aceindustry.com
+telephonenumber: +1 408 555 1122
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2942
+userpassword: destroy
+
+dn: cn=Torrey Mason, ou=Human Resources, o=Ace Industry, c=US
+cn: Torrey Mason
+sn: Mason
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: tmason
+mail: tmason@aceindustry.com
+telephonenumber: +1 408 555 1596
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1124
+userpassword: squatted
+
+dn: cn=Benjamin Hall, ou=Product Development, o=Ace Industry, c=US
+cn: Benjamin Hall
+sn: Hall
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: bhall
+mail: bhall@aceindustry.com
+telephonenumber: +1 408 555 6067
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2511
+userpassword: oranges
+
+dn: cn=Brad Talbot, ou=Human Resources, o=Ace Industry, c=US
+cn: Brad Talbot
+sn: Talbot
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: btalbot
+mail: btalbot@aceindustry.com
+telephonenumber: +1 408 555 4992
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3532
+userpassword: trident
+
+dn: cn=Marcus Ward, ou=Accounting, o=Ace Industry, c=US
+cn: Marcus Ward
+sn: Ward
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: mward
+mail: mward@aceindustry.com
+telephonenumber: +1 408 555 5688
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1707
+userpassword: normal
+
+dn: cn=Barbara Jablonski, ou=Human Resources, o=Ace Industry, c=US
+cn: Barbara Jablonski
+sn: Jablonski
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: bjablons
+mail: bjablons@aceindustry.com
+telephonenumber: +1 408 555 8815
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0906
+userpassword: strawberry
+
+dn: cn=Judy McFarland, ou=Accounting, o=Ace Industry, c=US
+cn: Judy McFarland
+sn: McFarland
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: jmcFarla
+mail: jmcFarla@aceindustry.com
+telephonenumber: +1 408 555 2567
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 2359
+userpassword: walnut
+
+dn: cn=Lee Labonte, ou=Product Development, o=Ace Industry, c=US
+cn: Lee Labonte
+sn: Labonte
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: llabonte
+mail: llabonte@aceindustry.com
+telephonenumber: +1 408 555 0957
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2854
+userpassword: sourdough
+
+dn: cn=Jody Campaigne, ou=Product Development, o=Ace Industry, c=US
+cn: Jody Campaigne
+sn: Campaigne
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: jcampaig
+mail: jcampaig@aceindustry.com
+telephonenumber: +1 408 555 1660
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4385
+userpassword: grapevine
+
+dn: cn=Barbara Hall, ou=Accounting, o=Ace Industry, c=US
+cn: Barbara Hall
+sn: Hall
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: bhal2
+mail: bhal2@aceindustry.com
+telephonenumber: +1 408 555 4491
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2758
+userpassword: truths
+
+dn: cn=Alexander Lutz, ou=Product Development, o=Ace Industry, c=US
+cn: Alexander Lutz
+sn: Lutz
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: alutz
+mail: alutz@aceindustry.com
+telephonenumber: +1 408 555 6505
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1327
+userpassword: northward
+
+dn: cn=Bjorn Talbot, ou=Product Development, o=Ace Industry, c=US
+cn: Bjorn Talbot
+sn: Talbot
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: btalbo2
+mail: btalbo2@aceindustry.com
+telephonenumber: +1 408 555 4234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1205
+userpassword: corduroy
+
+dn: cn=Ashley Chassin, ou=Payroll, o=Ace Industry, c=US
+cn: Ashley Chassin
+sn: Chassin
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Santa Clara
+uid: achassin
+mail: achassin@aceindustry.com
+telephonenumber: +1 408 555 9972
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0466
+userpassword: duopolist
+
+dn: cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US
+cn: Harry Miller
+sn: Miller
+givenname: Harry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: hmiller
+mail: hmiller@aceindustry.com
+telephonenumber: +1 408 555 9804
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4304
+userpassword: hillock
+
+dn: cn=Jeffrey Campaigne, ou=Human Resources, o=Ace Industry, c=US
+cn: Jeffrey Campaigne
+sn: Campaigne
+givenname: Jeffrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: jcampai2
+mail: jcampai2@aceindustry.com
+telephonenumber: +1 408 555 7393
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 1377
+userpassword: nominee
+
+dn: cn=Lee Ulrich, ou=Product Testing, o=Ace Industry, c=US
+cn: Lee Ulrich
+sn: Ulrich
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Sunnyvale
+uid: lulrich
+mail: lulrich@aceindustry.com
+telephonenumber: +1 408 555 8652
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0985
+userpassword: attribution
+
+dn: cn=Marcus Langdon, ou=Product Development, o=Ace Industry, c=US
+cn: Marcus Langdon
+sn: Langdon
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: mlangdon
+mail: mlangdon@aceindustry.com
+telephonenumber: +1 408 555 6249
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4471
+userpassword: threat
+
+dn: cn=Stephen Triplett, ou=Human Resources, o=Ace Industry, c=US
+cn: Stephen Triplett
+sn: Triplett
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: striplet
+mail: striplet@aceindustry.com
+telephonenumber: +1 408 555 4519
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3083
+userpassword: compactify
+
+dn: cn=Gern Triplett, ou=Accounting, o=Ace Industry, c=US
+cn: Gern Triplett
+sn: Triplett
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: gtriplet
+mail: gtriplet@aceindustry.com
+telephonenumber: +1 408 555 2582
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4023
+userpassword: placeable
+
+dn: cn=John Falena, ou=Human Resources, o=Ace Industry, c=US
+cn: John Falena
+sn: Falena
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: jfalena
+mail: jfalena@aceindustry.com
+telephonenumber: +1 408 555 8133
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1917
+userpassword: nightly
+
+dn: cn=Sue Peterson, ou=Product Development, o=Ace Industry, c=US
+cn: Sue Peterson
+sn: Peterson
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: speterso
+mail: speterso@aceindustry.com
+telephonenumber: +1 408 555 3613
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3073
+userpassword: quinine
+
+dn: cn=Emanuel Johnson, ou=Accounting, o=Ace Industry, c=US
+cn: Emanuel Johnson
+sn: Johnson
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: ejohnson
+mail: ejohnson@aceindustry.com
+telephonenumber: +1 408 555 3287
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3737
+userpassword: marketwise
+
+dn: cn=Peter Rigden, ou=Human Resources, o=Ace Industry, c=US
+cn: Peter Rigden
+sn: Rigden
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: prigden
+mail: prigden@aceindustry.com
+telephonenumber: +1 408 555 5099
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1271
+userpassword: epiphyseal
+
+dn: cn=Brad Walker, ou=Accounting, o=Ace Industry, c=US
+cn: Brad Walker
+sn: Walker
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: bwalker
+mail: bwalker@aceindustry.com
+telephonenumber: +1 408 555 5476
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3529
+userpassword: interruptible
+
+dn: cn=Kurt Jensen, ou=Product Development, o=Ace Industry, c=US
+cn: Kurt Jensen
+sn: Jensen
+givenname: Kurt
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: kjensen
+mail: kjensen@aceindustry.com
+telephonenumber: +1 408 555 6127
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1944
+userpassword: regulatory
+
+dn: cn=Mike Lott, ou=Human Resources, o=Ace Industry, c=US
+cn: Mike Lott
+sn: Lott
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: mlott
+mail: mlott@aceindustry.com
+telephonenumber: +1 408 555 2234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0498
+userpassword: cognac
+
+dn: cn=Cecil Wallace, ou=Product Development, o=Ace Industry, c=US
+cn: Cecil Wallace
+sn: Wallace
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: cwallace
+mail: cwallace@aceindustry.com
+telephonenumber: +1 408 555 6438
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0349
+userpassword: quintus
+
+dn: cn=Tobias Pierce, ou=Accounting, o=Ace Industry, c=US
+cn: Tobias Pierce
+sn: Pierce
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: tpierce
+mail: tpierce@aceindustry.com
+telephonenumber: +1 408 555 1531
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1383
+userpassword: rascal
+
+dn: cn=Richard Bannister, ou=Human Resources, o=Ace Industry, c=US
+cn: Richard Bannister
+sn: Bannister
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: rbannist
+mail: rbannist@aceindustry.com
+telephonenumber: +1 408 555 1833
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0983
+userpassword: demonstrate
+
+dn: cn=Brian Plante, ou=Human Resources, o=Ace Industry, c=US
+cn: Brian Plante
+sn: Plante
+givenname: Brian
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: bplante
+mail: bplante@aceindustry.com
+telephonenumber: +1 408 555 3550
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4654
+userpassword: tangerine
+
+dn: cn=Randy Mills, ou=Accounting, o=Ace Industry, c=US
+cn: Randy Mills
+sn: Mills
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: rmills
+mail: rmills@aceindustry.com
+telephonenumber: +1 408 555 2072
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3823
+userpassword: condescend
+
+dn: cn=Benjamin Schneider, ou=Product Testing, o=Ace Industry, c=US
+cn: Benjamin Schneider
+sn: Schneider
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Santa Clara
+uid: bschneid
+mail: bschneid@aceindustry.com
+telephonenumber: +1 408 555 1012
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4471
+userpassword: biblical
+
+dn: cn=Sue Kelleher, ou=Payroll, o=Ace Industry, c=US
+cn: Sue Kelleher
+sn: Kelleher
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Santa Clara
+uid: skellehe
+mail: skellehe@aceindustry.com
+telephonenumber: +1 408 555 3480
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1608
+userpassword: sweltering
+
+dn: cn=Bertram Rentz, ou=Product Testing, o=Ace Industry, c=US
+cn: Bertram Rentz
+sn: Rentz
+givenname: Bertram
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Sunnyvale
+uid: brentz
+mail: brentz@aceindustry.com
+telephonenumber: +1 408 555 5526
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0617
+userpassword: diachronic
+
+dn: cn=Daniel Smith, ou=Human Resources, o=Ace Industry, c=US
+cn: Daniel Smith
+sn: Smith
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: dsmith
+mail: dsmith@aceindustry.com
+telephonenumber: +1 408 555 9519
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0368
+userpassword: quantitative
+
+dn: cn=Stephen Carter, ou=Product Development, o=Ace Industry, c=US
+cn: Stephen Carter
+sn: Carter
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: scarte2
+mail: scarte2@aceindustry.com
+telephonenumber: +1 408 555 6022
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2013
+userpassword: scooter
+
+dn: cn=David Thorud, ou=Accounting, o=Ace Industry, c=US
+cn: David Thorud
+sn: Thorud
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Cupertino
+uid: dthorud
+mail: dthorud@aceindustry.com
+telephonenumber: +1 408 555 6185
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1128
+userpassword: fulcrum
+
+dn: cn=Elba Kohler, ou=Accounting, o=Ace Industry, c=US
+cn: Elba Kohler
+sn: Kohler
+givenname: Elba
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: ekohler
+mail: ekohler@aceindustry.com
+telephonenumber: +1 408 555 1926
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2721
+userpassword: guildhall
+
+dn: cn=Laurel Campbell, ou=Accounting, o=Ace Industry, c=US
+cn: Laurel Campbell
+sn: Campbell
+givenname: Laurel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: lcampbel
+mail: lcampbel@aceindustry.com
+telephonenumber: +1 408 555 2537
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 2073
+userpassword: impress
+
+dn: cn=Tim Labonte, ou=Human Resources, o=Ace Industry, c=US
+cn: Tim Labonte
+sn: Labonte
+givenname: Tim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: tlabonte
+mail: tlabonte@aceindustry.com
+telephonenumber: +1 408 555 0058
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1426
+userpassword: express
+
+dn: cn=Scott Lee, ou=Human Resources, o=Ace Industry, c=US
+cn: Scott Lee
+sn: Lee
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: slee
+mail: slee@aceindustry.com
+telephonenumber: +1 408 555 2335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1806
+userpassword: revertive
+
+dn: cn=Bjorn Free, ou=Human Resources, o=Ace Industry, c=US
+cn: Bjorn Free
+sn: Free
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: bfree
+mail: bfree@aceindustry.com
+telephonenumber: +1 408 555 8588
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3307
+userpassword: etiquette
+
+dn: cn=Torrey Schneider, ou=Accounting, o=Ace Industry, c=US
+cn: Torrey Schneider
+sn: Schneider
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: tschneid
+mail: tschneid@aceindustry.com
+telephonenumber: +1 408 555 7086
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2292
+userpassword: chaperone
+
+dn: cn=Paula Rose, ou=Accounting, o=Ace Industry, c=US
+cn: Paula Rose
+sn: Rose
+givenname: Paula
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Cupertino
+uid: prose
+mail: prose@aceindustry.com
+telephonenumber: +1 408 555 9998
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0542
+userpassword: regatta
+
+dn: cn=Janet Hunter, ou=Product Development, o=Ace Industry, c=US
+cn: Janet Hunter
+sn: Hunter
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: jhunter
+mail: jhunter@aceindustry.com
+telephonenumber: +1 408 555 7665
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4856
+userpassword: nanometer
+
+dn: cn=Alexander Shelton, ou=Human Resources, o=Ace Industry, c=US
+cn: Alexander Shelton
+sn: Shelton
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: ashelton
+mail: ashelton@aceindustry.com
+telephonenumber: +1 408 555 1081
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1987
+userpassword: appointe
+
+dn: cn=Marcus Mcinnis, ou=Product Development, o=Ace Industry, c=US
+cn: Marcus Mcinnis
+sn: Mcinnis
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: mmcinnis
+mail: mmcinnis@aceindustry.com
+telephonenumber: +1 408 555 9655
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4818
+userpassword: calcify
+
+dn: cn=Frank Albers, ou=Accounting, o=Ace Industry, c=US
+cn: Frank Albers
+sn: Albers
+givenname: Frank
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: falbers
+mail: falbers@aceindustry.com
+telephonenumber: +1 408 555 3094
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1439
+userpassword: degradation
+
+dn: cn=Martin Schneider, ou=Accounting, o=Ace Industry, c=US
+cn: Martin Schneider
+sn: Schneider
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Cupertino
+uid: mschneid
+mail: mschneid@aceindustry.com
+telephonenumber: +1 408 555 5017
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3153
+userpassword: motorcycle
+
+dn: cn=Patricia Cruse, ou=Product Testing, o=Ace Industry, c=US
+cn: Patricia Cruse
+sn: Cruse
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Santa Clara
+uid: pcruse
+mail: pcruse@aceindustry.com
+telephonenumber: +1 408 555 8641
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3967
+userpassword: pauper
+
+dn: cn=Timothy Kelly, ou=Product Development, o=Ace Industry, c=US
+cn: Timothy Kelly
+sn: Kelly
+givenname: Timothy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: tkelly
+mail: tkelly@aceindustry.com
+telephonenumber: +1 408 555 4295
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3107
+userpassword: risible
+
+dn: cn=Andrew Hel, ou=Accounting, o=Ace Industry, c=US
+cn: Andrew Hel
+sn: Hel
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: ahel
+mail: ahel@aceindustry.com
+telephonenumber: +1 408 555 2666
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0572
+userpassword: sarsaparilla
+
+dn: cn=James Burrell, ou=Human Resources, o=Ace Industry, c=US
+cn: James Burrell
+sn: Burrell
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: jburrell
+mail: jburrell@aceindustry.com
+telephonenumber: +1 408 555 0751
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4926
+userpassword: degrease
+
+dn: cn=Sue Mason, ou=Product Development, o=Ace Industry, c=US
+cn: Sue Mason
+sn: Mason
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: smason
+mail: smason@aceindustry.com
+telephonenumber: +1 408 555 9780
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4971
+userpassword: sensible
+
+dn: cn=Pete Tyler, ou=Accounting, o=Ace Industry, c=US
+cn: Pete Tyler
+sn: Tyler
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: ptyler
+mail: ptyler@aceindustry.com
+telephonenumber: +1 408 555 3335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0327
+userpassword: vinegar
+
+dn: cn=Chris Alexander, ou=Product Development, o=Ace Industry, c=US
+cn: Chris Alexander
+sn: Alexander
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Sunnyvale
+uid: calexand
+mail: calexand@aceindustry.com
+telephonenumber: +1 408 555 9438
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2884
+userpassword: dauphin
+
+dn: cn=Jim Cruse, ou=Payroll, o=Ace Industry, c=US
+cn: Jim Cruse
+sn: Cruse
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Santa Clara
+uid: jcruse
+mail: jcruse@aceindustry.com
+telephonenumber: +1 408 555 9482
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0083
+userpassword: bridgework
+
+dn: cn=Karen Carter, ou=Human Resources, o=Ace Industry, c=US
+cn: Karen Carter
+sn: Carter
+givenname: Karen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: kcarter
+mail: kcarter@aceindustry.com
+telephonenumber: +1 408 555 4675
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2320
+userpassword: radiosonde
+
+dn: cn=Randy Fish, ou=Human Resources, o=Ace Industry, c=US
+cn: Randy Fish
+sn: Fish
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: rfish
+mail: rfish@aceindustry.com
+telephonenumber: +1 408 555 9865
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2317
+userpassword: mailbox
+
+dn: cn=Philip Hunt, ou=Human Resources, o=Ace Industry, c=US
+cn: Philip Hunt
+sn: Hunt
+givenname: Philip
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: phunt
+mail: phunt@aceindustry.com
+telephonenumber: +1 408 555 1242
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1183
+userpassword: wastewater
+
+dn: cn=Rachel Schneider, ou=Human Resources, o=Ace Industry, c=US
+cn: Rachel Schneider
+sn: Schneider
+givenname: Rachel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: rschneid
+mail: rschneid@aceindustry.com
+telephonenumber: +1 408 555 9908
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4183
+userpassword: decorous
+
+dn: cn=Barbara Jensen, ou=Product Development, o=Ace Industry, c=US
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: bjensen
+mail: bjensen@aceindustry.com
+telephonenumber: +1 408 555 1862
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0209
+userpassword: hifalutin
+
+dn: cn=Jim Lange, ou=Product Testing, o=Ace Industry, c=US
+cn: Jim Lange
+sn: Lange
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Santa Clara
+uid: jlange
+mail: jlange@aceindustry.com
+telephonenumber: +1 408 555 0488
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3798
+userpassword: chastity
+
+dn: cn=Randy Ulrich, ou=Accounting, o=Ace Industry, c=US
+cn: Randy Ulrich
+sn: Ulrich
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: rulrich
+mail: rulrich@aceindustry.com
+telephonenumber: +1 408 555 5311
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1282
+userpassword: twinkle
+
+dn: cn=Richard Francis, ou=Accounting, o=Ace Industry, c=US
+cn: Richard Francis
+sn: Francis
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: rfrancis
+mail: rfrancis@aceindustry.com
+telephonenumber: +1 408 555 8157
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3482
+userpassword: hacienda
+
+dn: cn=Morgan White, ou=Accounting, o=Ace Industry, c=US
+cn: Morgan White
+sn: White
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Cupertino
+uid: mwhite
+mail: mwhite@aceindustry.com
+telephonenumber: +1 408 555 9620
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3088
+userpassword: staple
+
+dn: cn=Gern Jensen, ou=Human Resources, o=Ace Industry, c=US
+cn: Gern Jensen
+sn: Jensen
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: gjensen
+mail: gjensen@aceindustry.com
+telephonenumber: +1 408 555 3299
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4609
+userpassword: primitive
+
+dn: cn=Alan White, ou=Product Testing, o=Ace Industry, c=US
+cn: Alan White
+sn: White
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Sunnyvale
+uid: awhite
+mail: awhite@aceindustry.com
+telephonenumber: +1 408 555 3232
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0142
+userpassword: placeholder
+
+dn: cn=Barbara Maddox, ou=Accounting, o=Ace Industry, c=US
+cn: Barbara Maddox
+sn: Maddox
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: bmaddox
+mail: bmaddox@aceindustry.com
+telephonenumber: +1 408 555 7783
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2207
+userpassword: feedback
+
+dn: cn=Martin Talbot, ou=Product Development, o=Ace Industry, c=US
+cn: Martin Talbot
+sn: Talbot
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: mtalbot
+mail: mtalbot@aceindustry.com
+telephonenumber: +1 408 555 9228
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1415
+userpassword: currant
+
+dn: cn=Judy Brown, ou=Payroll, o=Ace Industry, c=US
+cn: Judy Brown
+sn: Brown
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Santa Clara
+uid: jbrown
+mail: jbrown@aceindustry.com
+telephonenumber: +1 408 555 6885
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4224
+userpassword: militiamen
+
+dn: cn=Jody Jensen, ou=Accounting, o=Ace Industry, c=US
+cn: Jody Jensen
+sn: Jensen
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: jjensen
+mail: jjensen@aceindustry.com
+telephonenumber: +1 408 555 7587
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4882
+userpassword: borderland
+
+dn: cn=Mike Carter, ou=Accounting, o=Ace Industry, c=US
+cn: Mike Carter
+sn: Carter
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: mcarter
+mail: mcarter@aceindustry.com
+telephonenumber: +1 408 555 1846
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3819
+userpassword: mainland
+
+dn: cn=David Akers, ou=Human Resources, o=Ace Industry, c=US
+cn: David Akers
+sn: Akers
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: dakers
+mail: dakers@aceindustry.com
+telephonenumber: +1 408 555 4812
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4944
+userpassword: integument
+
+dn: cn=Scott Farmer, ou=Product Development, o=Ace Industry, c=US
+cn: Scott Farmer
+sn: Farmer
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: sfarmer
+mail: sfarmer@aceindustry.com
+telephonenumber: +1 408 555 4228
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0019
+userpassword: triumphal
+
+dn: cn=Daniel Ward, ou=Product Testing, o=Ace Industry, c=US
+cn: Daniel Ward
+sn: Ward
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Sunnyvale
+uid: dward
+mail: dward@aceindustry.com
+telephonenumber: +1 408 555 5322
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3927
+userpassword: armload
+
+dn: cn=Tobias Ward, ou=Human Resources, o=Ace Industry, c=US
+cn: Tobias Ward
+sn: Ward
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: tward
+mail: tward@aceindustry.com
+telephonenumber: +1 408 555 7202
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2238
+userpassword: cedilla
+
+dn: cn=Patricia Shelton, ou=Payroll, o=Ace Industry, c=US
+cn: Patricia Shelton
+sn: Shelton
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Cupertino
+uid: pshelton
+mail: pshelton@aceindustry.com
+telephonenumber: +1 408 555 6442
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2918
+userpassword: nosedive
+
+dn: cn=Jody Rentz, ou=Human Resources, o=Ace Industry, c=US
+cn: Jody Rentz
+sn: Rentz
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: jrentz
+mail: jrentz@aceindustry.com
+telephonenumber: +1 408 555 5829
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3025
+userpassword: meander
+
+dn: cn=Peter Lorig, ou=Human Resources, o=Ace Industry, c=US
+cn: Peter Lorig
+sn: Lorig
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: plorig
+mail: plorig@aceindustry.com
+telephonenumber: +1 408 555 0624
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1276
+userpassword: calorimeter
+
+dn: cn=Allison Jensen, ou=Product Development, o=Ace Industry, c=US
+cn: Allison Jensen
+sn: Jensen
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: ajensen
+mail: ajensen@aceindustry.com
+telephonenumber: +1 408 555 7892
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0784
+userpassword: coltsfoot
+
+dn: cn=Kelly Schmith, ou=Human Resources, o=Ace Industry, c=US
+cn: Kelly Schmith
+sn: Schmith
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: kschmith
+mail: kschmith@aceindustry.com
+telephonenumber: +1 408 555 9749
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2221
+userpassword: purvey
+
+dn: cn=Pete Worrell, ou=Human Resources, o=Ace Industry, c=US
+cn: Pete Worrell
+sn: Worrell
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: pworrell
+mail: pworrell@aceindustry.com
+telephonenumber: +1 408 555 1637
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2449
+userpassword: solicitous
+
+dn: cn=Matthew Reuter, ou=Human Resources, o=Ace Industry, c=US
+cn: Matthew Reuter
+sn: Reuter
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: mreuter
+mail: mreuter@aceindustry.com
+telephonenumber: +1 408 555 6879
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 1356
+userpassword: oblivious
+
+dn: cn=Gern Tyler, ou=Accounting, o=Ace Industry, c=US
+cn: Gern Tyler
+sn: Tyler
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: gtyler
+mail: gtyler@aceindustry.com
+telephonenumber: +1 408 555 1020
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0312
+userpassword: typology
+
+dn: cn=Tobias Schmith, ou=Human Resources, o=Ace Industry, c=US
+cn: Tobias Schmith
+sn: Schmith
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: tschmith
+mail: tschmith@aceindustry.com
+telephonenumber: +1 408 555 9626
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4607
+userpassword: compost
+
+dn: cn=Bjorn Jensen, ou=Accounting, o=Ace Industry, c=US
+cn: Bjorn Jensen
+sn: Jensen
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: bjense2
+mail: bjense2@aceindustry.com
+telephonenumber: +1 408 555 5655
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4294
+userpassword: mortgage
+
+dn: cn=Dietrich Swain, ou=Payroll, o=Ace Industry, c=US
+cn: Dietrich Swain
+sn: Swain
+givenname: Dietrich
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Sunnyvale
+uid: dswain
+mail: dswain@aceindustry.com
+telephonenumber: +1 408 555 9222
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4396
+userpassword: freedom
+
+dn: cn=Andy Hall, ou=Accounting, o=Ace Industry, c=US
+cn: Andy Hall
+sn: Hall
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: ahall
+mail: ahall@aceindustry.com
+telephonenumber: +1 408 555 6169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3050
+userpassword: slater
+
+dn: cn=Jeff Muffly, ou=Product Development, o=Ace Industry, c=US
+cn: Jeff Muffly
+sn: Muffly
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: jmuffly
+mail: jmuffly@aceindustry.com
+telephonenumber: +1 408 555 5287
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0997
+userpassword: dictate
+
+dn: cn=Ted Jensen, ou=Accounting, o=Ace Industry, c=US
+cn: Ted Jensen
+sn: Jensen
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: tjensen
+mail: tjensen@aceindustry.com
+telephonenumber: +1 408 555 8622
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4717
+userpassword: ecosystem
+
+dn: cn=Allison Hunter, ou=Payroll, o=Ace Industry, c=US
+cn: Allison Hunter
+sn: Hunter
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Sunnyvale
+uid: ahunter
+mail: ahunter@aceindustry.com
+telephonenumber: +1 408 555 7713
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1213
+userpassword: egregious
+
+dn: cn=Jon Goldstein, ou=Human Resources, o=Ace Industry, c=US
+cn: Jon Goldstein
+sn: Goldstein
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: jgoldste
+mail: jgoldste@aceindustry.com
+telephonenumber: +1 408 555 5769
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1454
+userpassword: yellow
+
+dn: cn=Alan Worrell, ou=Product Development, o=Ace Industry, c=US
+cn: Alan Worrell
+sn: Worrell
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: aworrell
+mail: aworrell@aceindustry.com
+telephonenumber: +1 408 555 1591
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3966
+userpassword: gargoyle
+
+dn: cn=Wendy Lutz, ou=Accounting, o=Ace Industry, c=US
+cn: Wendy Lutz
+sn: Lutz
+givenname: Wendy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: wlutz
+mail: wlutz@aceindustry.com
+telephonenumber: +1 408 555 3358
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4912
+userpassword: bassinet
+
+dn: cn=Janet Lutz, ou=Human Resources, o=Ace Industry, c=US
+cn: Janet Lutz
+sn: Lutz
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: jlutz
+mail: jlutz@aceindustry.com
+telephonenumber: +1 408 555 4902
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2544
+userpassword: autumn
+
+dn: cn=Dan Langdon, ou=Product Development, o=Ace Industry, c=US
+cn: Dan Langdon
+sn: Langdon
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: dlangdon
+mail: dlangdon@aceindustry.com
+telephonenumber: +1 408 555 7044
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3263
+userpassword: botulin
+
+dn: cn=Ashley Knutson, ou=Product Development, o=Ace Industry, c=US
+cn: Ashley Knutson
+sn: Knutson
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: aknutson
+mail: aknutson@aceindustry.com
+telephonenumber: +1 408 555 2169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4736
+userpassword: maltose
+
+dn: cn=Kelly Mcinnis, ou=Accounting, o=Ace Industry, c=US
+cn: Kelly Mcinnis
+sn: Mcinnis
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: kmcinnis
+mail: kmcinnis@aceindustry.com
+telephonenumber: +1 408 555 8596
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4312
+userpassword: stargaze
+
+dn: cn=Trent Couzens, ou=Accounting, o=Ace Industry, c=US
+cn: Trent Couzens
+sn: Couzens
+givenname: Trent
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Sunnyvale
+uid: tcouzens
+mail: tcouzens@aceindustry.com
+telephonenumber: +1 408 555 8401
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3994
+userpassword: tambourine
+
+dn: cn=Lee Stockton, ou=Product Testing, o=Ace Industry, c=US
+cn: Lee Stockton
+sn: Stockton
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Santa Clara
+uid: lstockto
+mail: lstockto@aceindustry.com
+telephonenumber: +1 408 555 0518
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0169
+userpassword: brooklyn
+
+dn: cn=Jon Bourke, ou=Product Development, o=Ace Industry, c=US
+cn: Jon Bourke
+sn: Bourke
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Cupertino
+uid: jbourke
+mail: jbourke@aceindustry.com
+telephonenumber: +1 408 555 8541
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0034
+userpassword: brainwash
+
+dn: cn=Dan Lanoway, ou=Accounting, o=Ace Industry, c=US
+cn: Dan Lanoway
+sn: Lanoway
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: dlanoway
+mail: dlanoway@aceindustry.com
+telephonenumber: +1 408 555 2017
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3540
+userpassword: manhattan
+
+dn: cn=Karl Cope, ou=Human Resources, o=Ace Industry, c=US
+cn: Karl Cope
+sn: Cope
+givenname: Karl
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: kcope
+mail: kcope@aceindustry.com
+telephonenumber: +1 408 555 2709
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 3040
+userpassword: forfeiture
+
+dn: cn=Anne-Louise Barnes, ou=Payroll, o=Ace Industry, c=US
+cn: Anne-Louise Barnes
+sn: Barnes
+givenname: Anne-Louise
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Santa Clara
+uid: abarnes
+mail: abarnes@aceindustry.com
+telephonenumber: +1 408 555 9445
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2290
+userpassword: chevron
+
+dn: cn=Richard Jensen, ou=Accounting, o=Ace Industry, c=US
+cn: Richard Jensen
+sn: Jensen
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Cupertino
+uid: rjensen
+mail: rjensen@aceindustry.com
+telephonenumber: +1 408 555 5957
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2631
+userpassword: disciplinarian
+
+dn: cn=Pete Hunt, ou=Product Development, o=Ace Industry, c=US
+cn: Pete Hunt
+sn: Hunt
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: phun2
+mail: phun2@aceindustry.com
+telephonenumber: +1 408 555 0342
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0087
+userpassword: absorb
+
+dn: cn=Matthew Vaughan, ou=Product Testing, o=Ace Industry, c=US
+cn: Matthew Vaughan
+sn: Vaughan
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Sunnyvale
+uid: mvaughan
+mail: mvaughan@aceindustry.com
+telephonenumber: +1 408 555 4692
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4508
+userpassword: submitted
+
+dn: cn=James Lutz, ou=Human Resources, o=Ace Industry, c=US
+cn: James Lutz
+sn: Lutz
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: jlut2
+mail: jlut2@aceindustry.com
+telephonenumber: +1 408 555 9689
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3541
+userpassword: shrank
+
+dn: cn=Morgan Jablonski, ou=Accounting, o=Ace Industry, c=US
+cn: Morgan Jablonski
+sn: Jablonski
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Cupertino
+uid: mjablons
+mail: mjablons@aceindustry.com
+telephonenumber: +1 408 555 0813
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3160
+userpassword: minimal
+
+dn: cn=Peter Chassin, ou=Payroll, o=Ace Industry, c=US
+cn: Peter Chassin
+sn: Chassin
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Santa Clara
+uid: pchassin
+mail: pchassin@aceindustry.com
+telephonenumber: +1 408 555 2816
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4524
+userpassword: barbital
+
+dn: cn=Dan Cope, ou=Product Development, o=Ace Industry, c=US
+cn: Dan Cope
+sn: Cope
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Sunnyvale
+uid: dcope
+mail: dcope@aceindustry.com
+telephonenumber: +1 408 555 9813
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1737
+userpassword: snifter
+
+dn: cn=Judy Rentz, ou=Payroll, o=Ace Industry, c=US
+cn: Judy Rentz
+sn: Rentz
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Santa Clara
+uid: jrent2
+mail: jrent2@aceindustry.com
+telephonenumber: +1 408 555 2523
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4405
+userpassword: tachistoscope
+
+dn: cn=Tobias Cruse, ou=Human Resources, o=Ace Industry, c=US
+cn: Tobias Cruse
+sn: Cruse
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: tcruse
+mail: tcruse@aceindustry.com
+telephonenumber: +1 408 555 5980
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4191
+userpassword: flinty
+
+dn: cn=Eric Ward, ou=Human Resources, o=Ace Industry, c=US
+cn: Eric Ward
+sn: Ward
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: eward
+mail: eward@aceindustry.com
+telephonenumber: +1 408 555 2320
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4874
+userpassword: episcopal
+
+dn: cn=Torrey Tully, ou=Human Resources, o=Ace Industry, c=US
+cn: Torrey Tully
+sn: Tully
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: ttully
+mail: ttully@aceindustry.com
+telephonenumber: +1 408 555 2274
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3924
+userpassword: schooner
+
+dn: cn=Cecil Harvey, ou=Product Development, o=Ace Industry, c=US
+cn: Cecil Harvey
+sn: Harvey
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: charvey
+mail: charvey@aceindustry.com
+telephonenumber: +1 408 555 1815
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4583
+userpassword: journalese
+
+dn: cn=Randy Fisher, ou=Human Resources, o=Ace Industry, c=US
+cn: Randy Fisher
+sn: Fisher
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: rfisher
+mail: rfisher@aceindustry.com
+telephonenumber: +1 408 555 1506
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1579
+userpassword: pomegranate
+
+dn: cn=Andrew Langdon, ou=Product Development, o=Ace Industry, c=US
+cn: Andrew Langdon
+sn: Langdon
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: alangdon
+mail: alangdon@aceindustry.com
+telephonenumber: +1 408 555 8289
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2254
+userpassword: muzzle
+
+dn: cn=David Rose, ou=Product Testing, o=Ace Industry, c=US
+cn: David Rose
+sn: Rose
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Sunnyvale
+uid: drose
+mail: drose@aceindustry.com
+telephonenumber: +1 408 555 3963
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4012
+userpassword: gubernatorial
+
+dn: cn=Peter Olfield, ou=Human Resources, o=Ace Industry, c=US
+cn: Peter Olfield
+sn: Olfield
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: polfield
+mail: polfield@aceindustry.com
+telephonenumber: +1 408 555 8231
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1376
+userpassword: monologue
+
+dn: cn=Andy Walker, ou=Accounting, o=Ace Industry, c=US
+cn: Andy Walker
+sn: Walker
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Cupertino
+uid: awalker
+mail: awalker@aceindustry.com
+telephonenumber: +1 408 555 9199
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0061
+userpassword: detonable
+
+dn: cn=Lex Rentz, ou=Human Resources, o=Ace Industry, c=US
+cn: Lex Rentz
+sn: Rentz
+givenname: Lex
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: lrentz
+mail: lrentz@aceindustry.com
+telephonenumber: +1 408 555 2019
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2203
+userpassword: calcium
+
+dn: cn=Jeff Vaughan, ou=Human Resources, o=Ace Industry, c=US
+cn: Jeff Vaughan
+sn: Vaughan
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: jvaughan
+mail: jvaughan@aceindustry.com
+telephonenumber: +1 408 555 4543
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1734
+userpassword: appoint
+
+dn: cn=Barbara Francis, ou=Human Resources, o=Ace Industry, c=US
+cn: Barbara Francis
+sn: Francis
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Santa Clara
+uid: bfrancis
+mail: bfrancis@aceindustry.com
+telephonenumber: +1 408 555 9111
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3743
+userpassword: holystone
+
+dn: cn=Eric Walker, ou=Payroll, o=Ace Industry, c=US
+cn: Eric Walker
+sn: Walker
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+l: Cupertino
+uid: ewalker
+mail: ewalker@aceindustry.com
+telephonenumber: +1 408 555 6387
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2295
+userpassword: beguile
+
+dn: cn=Tobias James, ou=Accounting, o=Ace Industry, c=US
+cn: Tobias James
+sn: James
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: tjames
+mail: tjames@aceindustry.com
+telephonenumber: +1 408 555 2458
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0730
+userpassword: turtle
+
+dn: cn=Bjorn Rigden, ou=Human Resources, o=Ace Industry, c=US
+cn: Bjorn Rigden
+sn: Rigden
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Sunnyvale
+uid: brigden
+mail: brigden@aceindustry.com
+telephonenumber: +1 408 555 5263
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1643
+userpassword: purple
+
+dn: cn=Eric Cruse, ou=Product Testing, o=Ace Industry, c=US
+cn: Eric Cruse
+sn: Cruse
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Santa Clara
+uid: ecruse
+mail: ecruse@aceindustry.com
+telephonenumber: +1 408 555 0648
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4233
+userpassword: platelet
+
+dn: cn=Randy Jensen, ou=Product Testing, o=Ace Industry, c=US
+cn: Randy Jensen
+sn: Jensen
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Sunnyvale
+uid: rjense2
+mail: rjense2@aceindustry.com
+telephonenumber: +1 408 555 9045
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1984
+userpassword: transpose
+
+dn: cn=Richard Hunt, ou=Accounting, o=Ace Industry, c=US
+cn: Richard Hunt
+sn: Hunt
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+l: Santa Clara
+uid: rhunt
+mail: rhunt@aceindustry.com
+telephonenumber: +1 408 555 0139
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 0718
+userpassword: becloud
+
+dn: cn=Barry Parker, ou=Product Development, o=Ace Industry, c=US
+cn: Barry Parker
+sn: Parker
+givenname: Barry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Sunnyvale
+uid: bparker
+mail: bparker@aceindustry.com
+telephonenumber: +1 408 555 4647
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1148
+userpassword: lenticular
+
+dn: cn=Erin Alexander, ou=Product Testing, o=Ace Industry, c=US
+cn: Erin Alexander
+sn: Alexander
+givenname: Erin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Santa Clara
+uid: ealexand
+mail: ealexand@aceindustry.com
+telephonenumber: +1 408 555 5563
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2434
+userpassword: galactose
+
+dn: cn=Matthew Tyler, ou=Human Resources, o=Ace Industry, c=US
+cn: Matthew Tyler
+sn: Tyler
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+l: Cupertino
+uid: mtyler
+mail: mtyler@aceindustry.com
+telephonenumber: +1 408 555 7907
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2701
+userpassword: instantiate
+
+dn: cn=Emanuel Lott, ou=Product Testing, o=Ace Industry, c=US
+cn: Emanuel Lott
+sn: Lott
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+l: Santa Clara
+uid: elott
+mail: elott@aceindustry.com
+telephonenumber: +1 408 555 0932
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3906
+userpassword: holdout
+
+dn: cn=Christoph Newport, ou=Product Development, o=Ace Industry, c=US
+cn: Christoph Newport
+sn: Newport
+givenname: Christoph
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Sunnyvale
+uid: cnewport
+mail: cnewport@aceindustry.com
+telephonenumber: +1 408 555 0066
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0056
+userpassword: expertise
+
+dn: cn=Jeff Vedder, ou=Product Development, o=Ace Industry, c=US
+cn: Jeff Vedder
+sn: Vedder
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: jvedder
+mail: jvedder@aceindustry.com
+telephonenumber: +1 408 555 4668
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3445
+userpassword: befitting
diff --git a/ldap/ldif/European.ldif b/ldap/ldif/European.ldif
new file mode 100644
index 00000000..1908e605
--- /dev/null
+++ b/ldap/ldif/European.ldif
@@ -0,0 +1,7589 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+dn: o=Çéliné Ändrè
+objectClass: top
+objectClass: organization
+o: Çéliné Ändrè
+aci: (target=ldap:///o=Çéliné Ändrè)(targetattr="userpassword || telephonenumber || facsimiletelephonenumber")(version 3.0; acl "acl1"; allow(write) userdn = "ldap:///self";)
+aci: (target=ldap:///o=Çéliné Ändrè)(targetattr=*)(version 3.0; acl "acl2"; allow(write) groupdn = "ldap:///cn=Directory Administrators, o=Çéliné Ändrè";)
+aci: (target=ldap:///o=Çéliné Ändrè)(targetattr=*)(version 3.0; acl "acl3"; allow(read, search, compare) userdn = "ldap:///anyone";)
+
+dn: ou=Çéliné Ändrè, o=Çéliné Ändrè
+objectClass: top
+objectClass: organizationalUnit
+ou: Çéliné Ändrè
+
+dn: ou=Ännheimè, o=Çéliné Ändrè
+objectClass: top
+objectClass: organizationalUnit
+ou: Ännheimè
+
+dn: ou=Çlose Crèkä, o=Çéliné Ändrè
+objectClass: top
+objectClass: organizationalUnit
+ou: Çlose Crèkä
+
+dn: ou=Sàn Fråncêscô, o=Çéliné Ändrè
+objectClass: top
+objectClass: organizationalUnit
+ou: Sàn Fråncêscô
+
+dn: uid=user0, ou=Ännheimè, o=Çéliné Ändrè
+uid: user0
+cn: Babette Ryndérs
+sn: Ryndérs
+givenName: Babette
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Babette Ryndérs's description
+mail: user0@test.com
+telephoneNumber: +1 415 788-4115
+facsimileTelephoneNumber: +1 804 849-2367
+userPassword: user0
+cn;lang-es: Babette Ryndérs
+sn;lang-es: Ryndérs
+givenName;lang-es: Babette
+
+dn: uid=user1, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user1
+cn: mÿrty DeCoùrsin
+sn: DeCoùrsin
+givenName: mÿrty
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is mÿrty DeCoùrsin's description
+mail: user1@test.com
+telephoneNumber: +1 408 689-8883
+facsimileTelephoneNumber: +1 408 747-7146
+userPassword: user1
+cn;lang-ie: mÿrty DeCoùrsin
+sn;lang-ie: DeCoùrsin
+givenName;lang-ie: mÿrty
+
+dn: uid=user2, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user2
+cn: Rôw O'Connér
+sn: O'Connér
+givenName: Rôw
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Rôw O'Connér's description
+mail: user2@test.com
+telephoneNumber: +1 714 902-8784
+facsimileTelephoneNumber: +1 206 376-2654
+userPassword: user2
+cn;lang-it: Rôw O'Connér
+sn;lang-it: O'Connér
+givenName;lang-it: Rôw
+
+dn: uid=user3, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user3
+cn: Kéñnon Fùndérbùrg
+sn: Fùndérbùrg
+givenName: Kéñnon
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kéñnon Fùndérbùrg's description
+mail: user3@test.com
+telephoneNumber: +1 408 783-2318
+facsimileTelephoneNumber: +1 213 153-3897
+userPassword: user3
+cn;lang-it: Kéñnon Fùndérbùrg
+sn;lang-it: Fùndérbùrg
+givenName;lang-it: Kéñnon
+
+dn: uid=user4, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user4
+cn: Theadora Ebérle
+sn: Ebérle
+givenName: Theadora
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Theadora Ebérle's description
+mail: user4@test.com
+telephoneNumber: +1 714 817-4739
+facsimileTelephoneNumber: +1 408 627-3928
+userPassword: user4
+cn;lang-de: Theadora Ebérle
+sn;lang-de: Ebérle
+givenName;lang-de: Theadora
+
+dn: uid=user5, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user5
+cn: Dàsya Cozàrt
+sn: Cozàrt
+givenName: Dàsya
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Dàsya Cozàrt's description
+mail: user5@test.com
+telephoneNumber: +1 303 741-9413
+facsimileTelephoneNumber: +1 818 504-4394
+userPassword: user5
+cn;lang-be: Dàsya Cozàrt
+sn;lang-be: Cozàrt
+givenName;lang-be: Dàsya
+
+dn: uid=user6, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user6
+cn: mÿrv Callânân
+sn: Callânân
+givenName: mÿrv
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is mÿrv Callânân's description
+mail: user6@test.com
+telephoneNumber: +1 510 577-5852
+facsimileTelephoneNumber: +1 213 755-9341
+userPassword: user6
+cn;lang-fr: mÿrv Callânân
+sn;lang-fr: Callânân
+givenName;lang-fr: mÿrv
+
+dn: uid=user7, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user7
+cn: Ñäthan Ovâns
+sn: Ovâns
+givenName: Ñäthan
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñäthan Ovâns's description
+mail: user7@test.com
+telephoneNumber: +1 206 376-1666
+facsimileTelephoneNumber: +1 206 608-3694
+userPassword: user7
+cn;lang-be: Ñäthan Ovâns
+sn;lang-be: Ovâns
+givenName;lang-be: Ñäthan
+
+dn: uid=user8, ou=Ännheimè, o=Çéliné Ändrè
+uid: user8
+cn: Takehiko Pröblems
+sn: Pröblems
+givenName: Takehiko
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Takehiko Pröblems's description
+mail: user8@test.com
+telephoneNumber: +1 213 155-3374
+facsimileTelephoneNumber: +1 510 297-8847
+userPassword: user8
+cn;lang-be: Takehiko Pröblems
+sn;lang-be: Pröblems
+givenName;lang-be: Takehiko
+
+dn: uid=user9, ou=Ännheimè, o=Çéliné Ändrè
+uid: user9
+cn: Bam Ålï
+sn: Ålï
+givenName: Bam
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Bam Ålï's description
+mail: user9@test.com
+telephoneNumber: +1 213 213-4553
+facsimileTelephoneNumber: +1 303 273-8511
+userPassword: user9
+cn;lang-se: Bam Ålï
+sn;lang-se: Ålï
+givenName;lang-se: Bam
+
+dn: uid=user10, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user10
+cn: Çándide Rùiz
+sn: Rùiz
+givenName: Çándide
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Çándide Rùiz's description
+mail: user10@test.com
+telephoneNumber: +1 818 774-5666
+facsimileTelephoneNumber: +1 818 281-1317
+userPassword: user10
+cn;lang-be: Çándide Rùiz
+sn;lang-be: Rùiz
+givenName;lang-be: Çándide
+
+dn: uid=user11, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user11
+cn: Rôséñe Tàrqùinio
+sn: Tàrqùinio
+givenName: Rôséñe
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Rôséñe Tàrqùinio's description
+mail: user11@test.com
+telephoneNumber: +1 818 512-5483
+facsimileTelephoneNumber: +1 415 619-5503
+userPassword: user11
+cn;lang-ie: Rôséñe Tàrqùinio
+sn;lang-ie: Tàrqùinio
+givenName;lang-ie: Rôséñe
+
+dn: uid=user12, ou=Ännheimè, o=Çéliné Ändrè
+uid: user12
+cn: Dànte Petrèe
+sn: Petrèe
+givenName: Dànte
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Dànte Petrèe's description
+mail: user12@test.com
+telephoneNumber: +1 804 242-5548
+facsimileTelephoneNumber: +1 206 386-8197
+userPassword: user12
+cn;lang-it: Dànte Petrèe
+sn;lang-it: Petrèe
+givenName;lang-it: Dànte
+
+dn: uid=user13, ou=Ännheimè, o=Çéliné Ändrè
+uid: user13
+cn: Chuck Geoffrîon
+sn: Geoffrîon
+givenName: Chuck
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Chuck Geoffrîon's description
+mail: user13@test.com
+telephoneNumber: +1 303 258-9175
+facsimileTelephoneNumber: +1 714 158-4210
+userPassword: user13
+cn;lang-es: Chuck Geoffrîon
+sn;lang-es: Geoffrîon
+givenName;lang-es: Chuck
+
+dn: uid=user14, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user14
+cn: Elita Ållèën
+sn: Ållèën
+givenName: Elita
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Elita Ållèën's description
+mail: user14@test.com
+telephoneNumber: +1 303 402-3263
+facsimileTelephoneNumber: +1 818 898-9817
+userPassword: user14
+cn;lang-ie: Elita Ållèën
+sn;lang-ie: Ållèën
+givenName;lang-ie: Elita
+
+dn: uid=user15, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user15
+cn: Cloris Binda
+sn: Binda
+givenName: Cloris
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Cloris Binda's description
+mail: user15@test.com
+telephoneNumber: +1 303 480-6181
+facsimileTelephoneNumber: +1 206 546-2488
+userPassword: user15
+cn;lang-de: Cloris Binda
+sn;lang-de: Binda
+givenName;lang-de: Cloris
+
+dn: uid=user16, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user16
+cn: Sue Bùschelmân
+sn: Bùschelmân
+givenName: Sue
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Sue Bùschelmân's description
+mail: user16@test.com
+telephoneNumber: +1 510 216-1496
+facsimileTelephoneNumber: +1 714 672-9915
+userPassword: user16
+cn;lang-se: Sue Bùschelmân
+sn;lang-se: Bùschelmân
+givenName;lang-se: Sue
+
+dn: uid=user17, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user17
+cn: Lottîë Robértö
+sn: Robértö
+givenName: Lottîë
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Lottîë Robértö's description
+mail: user17@test.com
+telephoneNumber: +1 510 516-2779
+facsimileTelephoneNumber: +1 206 392-5788
+userPassword: user17
+cn;lang-be: Lottîë Robértö
+sn;lang-be: Robértö
+givenName;lang-be: Lottîë
+
+dn: uid=user18, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user18
+cn: Dupuy Meeks
+sn: Meeks
+givenName: Dupuy
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Dupuy Meeks's description
+mail: user18@test.com
+telephoneNumber: +1 415 677-1437
+facsimileTelephoneNumber: +1 804 733-6498
+userPassword: user18
+cn;lang-ie: Dupuy Meeks
+sn;lang-ie: Meeks
+givenName;lang-ie: Dupuy
+
+dn: uid=user19, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user19
+cn: Priscellà Kàrhùniemi
+sn: Kàrhùniemi
+givenName: Priscellà
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Priscellà Kàrhùniemi's description
+mail: user19@test.com
+telephoneNumber: +1 206 565-3949
+facsimileTelephoneNumber: +1 818 942-2120
+userPassword: user19
+cn;lang-se: Priscellà Kàrhùniemi
+sn;lang-se: Kàrhùniemi
+givenName;lang-se: Priscellà
+
+dn: uid=user20, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user20
+cn: Ameliñé Fehr
+sn: Fehr
+givenName: Ameliñé
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ameliñé Fehr's description
+mail: user20@test.com
+telephoneNumber: +1 510 476-6348
+facsimileTelephoneNumber: +1 510 214-2625
+userPassword: user20
+cn;lang-de: Ameliñé Fehr
+sn;lang-de: Fehr
+givenName;lang-de: Ameliñé
+
+dn: uid=user21, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user21
+cn: Mêrcedes Tùok
+sn: Tùok
+givenName: Mêrcedes
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Mêrcedes Tùok's description
+mail: user21@test.com
+telephoneNumber: +1 206 956-7647
+facsimileTelephoneNumber: +1 510 206-6042
+userPassword: user21
+cn;lang-se: Mêrcedes Tùok
+sn;lang-se: Tùok
+givenName;lang-se: Mêrcedes
+
+dn: uid=user22, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user22
+cn: Drusîë Dynie
+sn: Dynie
+givenName: Drusîë
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Drusîë Dynie's description
+mail: user22@test.com
+telephoneNumber: +1 303 520-7607
+facsimileTelephoneNumber: +1 303 594-6193
+userPassword: user22
+cn;lang-it: Drusîë Dynie
+sn;lang-it: Dynie
+givenName;lang-it: Drusîë
+
+dn: uid=user23, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user23
+cn: Brigit Grèbil
+sn: Grèbil
+givenName: Brigit
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Brigit Grèbil's description
+mail: user23@test.com
+telephoneNumber: +1 213 681-1102
+facsimileTelephoneNumber: +1 213 251-1532
+userPassword: user23
+cn;lang-es: Brigit Grèbil
+sn;lang-es: Grèbil
+givenName;lang-es: Brigit
+
+dn: uid=user24, ou=Ännheimè, o=Çéliné Ändrè
+uid: user24
+cn: Bêrget Càrdèën
+sn: Càrdèën
+givenName: Bêrget
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Bêrget Càrdèën's description
+mail: user24@test.com
+telephoneNumber: +1 804 718-4689
+facsimileTelephoneNumber: +1 303 409-8342
+userPassword: user24
+cn;lang-se: Bêrget Càrdèën
+sn;lang-se: Càrdèën
+givenName;lang-se: Bêrget
+
+dn: uid=user25, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user25
+cn: Älka Màrzella
+sn: Màrzella
+givenName: Älka
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Älka Màrzella's description
+mail: user25@test.com
+telephoneNumber: +1 213 901-8363
+facsimileTelephoneNumber: +1 415 639-5063
+userPassword: user25
+cn;lang-es: Älka Màrzella
+sn;lang-es: Màrzella
+givenName;lang-es: Älka
+
+dn: uid=user26, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user26
+cn: Äléña Newsom
+sn: Newsom
+givenName: Äléña
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Äléña Newsom's description
+mail: user26@test.com
+telephoneNumber: +1 714 841-7066
+facsimileTelephoneNumber: +1 714 901-6553
+userPassword: user26
+cn;lang-be: Äléña Newsom
+sn;lang-be: Newsom
+givenName;lang-be: Äléña
+
+dn: uid=user27, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user27
+cn: Kaitlin Popp
+sn: Popp
+givenName: Kaitlin
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kaitlin Popp's description
+mail: user27@test.com
+telephoneNumber: +1 818 694-8789
+facsimileTelephoneNumber: +1 804 926-6751
+userPassword: user27
+cn;lang-es: Kaitlin Popp
+sn;lang-es: Popp
+givenName;lang-es: Kaitlin
+
+dn: uid=user28, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user28
+cn: Sanae Wylïe
+sn: Wylïe
+givenName: Sanae
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Sanae Wylïe's description
+mail: user28@test.com
+telephoneNumber: +1 303 566-6486
+facsimileTelephoneNumber: +1 714 294-8045
+userPassword: user28
+cn;lang-be: Sanae Wylïe
+sn;lang-be: Wylïe
+givenName;lang-be: Sanae
+
+dn: uid=user29, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user29
+cn: Kaylil Hàrdérsèën
+sn: Hàrdérsèën
+givenName: Kaylil
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kaylil Hàrdérsèën's description
+mail: user29@test.com
+telephoneNumber: +1 408 641-9726
+facsimileTelephoneNumber: +1 818 487-1903
+userPassword: user29
+cn;lang-fr: Kaylil Hàrdérsèën
+sn;lang-fr: Hàrdérsèën
+givenName;lang-fr: Kaylil
+
+dn: uid=user30, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user30
+cn: Gêrm Scheér
+sn: Scheér
+givenName: Gêrm
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Gêrm Scheér's description
+mail: user30@test.com
+telephoneNumber: +1 408 612-2598
+facsimileTelephoneNumber: +1 303 748-7557
+userPassword: user30
+cn;lang-it: Gêrm Scheér
+sn;lang-it: Scheér
+givenName;lang-it: Gêrm
+
+dn: uid=user31, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user31
+cn: Kâty Woodhall
+sn: Woodhall
+givenName: Kâty
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kâty Woodhall's description
+mail: user31@test.com
+telephoneNumber: +1 510 625-3084
+facsimileTelephoneNumber: +1 415 605-5806
+userPassword: user31
+cn;lang-it: Kâty Woodhall
+sn;lang-it: Woodhall
+givenName;lang-it: Kâty
+
+dn: uid=user32, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user32
+cn: Deât Livérmân
+sn: Livérmân
+givenName: Deât
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Deât Livérmân's description
+mail: user32@test.com
+telephoneNumber: +1 714 986-7403
+facsimileTelephoneNumber: +1 408 281-1121
+userPassword: user32
+cn;lang-it: Deât Livérmân
+sn;lang-it: Livérmân
+givenName;lang-it: Deât
+
+dn: uid=user33, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user33
+cn: Sallÿanñé Sivaji
+sn: Sivaji
+givenName: Sallÿanñé
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Sallÿanñé Sivaji's description
+mail: user33@test.com
+telephoneNumber: +1 303 235-8018
+facsimileTelephoneNumber: +1 213 682-3120
+userPassword: user33
+cn;lang-ie: Sallÿanñé Sivaji
+sn;lang-ie: Sivaji
+givenName;lang-ie: Sallÿanñé
+
+dn: uid=user34, ou=Ännheimè, o=Çéliné Ändrè
+uid: user34
+cn: Jòò-Geok Rùdïåk
+sn: Rùdïåk
+givenName: Jòò-Geok
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Jòò-Geok Rùdïåk's description
+mail: user34@test.com
+telephoneNumber: +1 510 930-3480
+facsimileTelephoneNumber: +1 510 917-2898
+userPassword: user34
+cn;lang-de: Jòò-Geok Rùdïåk
+sn;lang-de: Rùdïåk
+givenName;lang-de: Jòò-Geok
+
+dn: uid=user35, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user35
+cn: Vasan Coxall
+sn: Coxall
+givenName: Vasan
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Vasan Coxall's description
+mail: user35@test.com
+telephoneNumber: +1 206 750-1454
+facsimileTelephoneNumber: +1 213 703-3700
+userPassword: user35
+cn;lang-ie: Vasan Coxall
+sn;lang-ie: Coxall
+givenName;lang-ie: Vasan
+
+dn: uid=user36, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user36
+cn: Gêrîïånna Godo
+sn: Godo
+givenName: Gêrîïånna
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Gêrîïånna Godo's description
+mail: user36@test.com
+telephoneNumber: +1 804 198-6482
+facsimileTelephoneNumber: +1 408 838-9697
+userPassword: user36
+cn;lang-se: Gêrîïånna Godo
+sn;lang-se: Godo
+givenName;lang-se: Gêrîïånna
+
+dn: uid=user37, ou=Ännheimè, o=Çéliné Ändrè
+uid: user37
+cn: Elio Sattlér
+sn: Sattlér
+givenName: Elio
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Elio Sattlér's description
+mail: user37@test.com
+telephoneNumber: +1 818 900-1660
+facsimileTelephoneNumber: +1 206 917-3195
+userPassword: user37
+cn;lang-es: Elio Sattlér
+sn;lang-es: Sattlér
+givenName;lang-es: Elio
+
+dn: uid=user38, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user38
+cn: Doc Stêklasa
+sn: Stêklasa
+givenName: Doc
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Doc Stêklasa's description
+mail: user38@test.com
+telephoneNumber: +1 303 862-8846
+facsimileTelephoneNumber: +1 213 916-6247
+userPassword: user38
+cn;lang-it: Doc Stêklasa
+sn;lang-it: Stêklasa
+givenName;lang-it: Doc
+
+dn: uid=user39, ou=Ännheimè, o=Çéliné Ändrè
+uid: user39
+cn: Francisca O'Hàrä
+sn: O'Hàrä
+givenName: Francisca
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Francisca O'Hàrä's description
+mail: user39@test.com
+telephoneNumber: +1 415 676-7596
+facsimileTelephoneNumber: +1 213 961-2275
+userPassword: user39
+cn;lang-be: Francisca O'Hàrä
+sn;lang-be: O'Hàrä
+givenName;lang-be: Francisca
+
+dn: uid=user40, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user40
+cn: Wâtwick McCàrrön
+sn: McCàrrön
+givenName: Wâtwick
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Wâtwick McCàrrön's description
+mail: user40@test.com
+telephoneNumber: +1 804 259-9202
+facsimileTelephoneNumber: +1 714 591-9833
+userPassword: user40
+cn;lang-be: Wâtwick McCàrrön
+sn;lang-be: McCàrrön
+givenName;lang-be: Wâtwick
+
+dn: uid=user41, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user41
+cn: Dollëy Bùhlér
+sn: Bùhlér
+givenName: Dollëy
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Dollëy Bùhlér's description
+mail: user41@test.com
+telephoneNumber: +1 714 884-5242
+facsimileTelephoneNumber: +1 818 205-8823
+userPassword: user41
+cn;lang-es: Dollëy Bùhlér
+sn;lang-es: Bùhlér
+givenName;lang-es: Dollëy
+
+dn: uid=user42, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user42
+cn: Emÿd Artzér
+sn: Artzér
+givenName: Emÿd
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Emÿd Artzér's description
+mail: user42@test.com
+telephoneNumber: +1 415 382-3440
+facsimileTelephoneNumber: +1 408 862-4384
+userPassword: user42
+cn;lang-be: Emÿd Artzér
+sn;lang-be: Artzér
+givenName;lang-be: Emÿd
+
+dn: uid=user43, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user43
+cn: Feâtlëss Watérmân
+sn: Watérmân
+givenName: Feâtlëss
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Feâtlëss Watérmân's description
+mail: user43@test.com
+telephoneNumber: +1 415 117-4653
+facsimileTelephoneNumber: +1 408 621-5937
+userPassword: user43
+cn;lang-ie: Feâtlëss Watérmân
+sn;lang-ie: Watérmân
+givenName;lang-ie: Feâtlëss
+
+dn: uid=user44, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user44
+cn: Base Frèiwald
+sn: Frèiwald
+givenName: Base
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Base Frèiwald's description
+mail: user44@test.com
+telephoneNumber: +1 804 946-6912
+facsimileTelephoneNumber: +1 714 182-5600
+userPassword: user44
+cn;lang-se: Base Frèiwald
+sn;lang-se: Frèiwald
+givenName;lang-se: Base
+
+dn: uid=user45, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user45
+cn: Loay Trîpp
+sn: Trîpp
+givenName: Loay
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Loay Trîpp's description
+mail: user45@test.com
+telephoneNumber: +1 818 236-3921
+facsimileTelephoneNumber: +1 303 474-8085
+userPassword: user45
+cn;lang-de: Loay Trîpp
+sn;lang-de: Trîpp
+givenName;lang-de: Loay
+
+dn: uid=user46, ou=Ännheimè, o=Çéliné Ändrè
+uid: user46
+cn: Tulip Seàrl
+sn: Seàrl
+givenName: Tulip
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Tulip Seàrl's description
+mail: user46@test.com
+telephoneNumber: +1 303 496-1732
+facsimileTelephoneNumber: +1 206 100-8221
+userPassword: user46
+cn;lang-it: Tulip Seàrl
+sn;lang-it: Seàrl
+givenName;lang-it: Tulip
+
+dn: uid=user47, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user47
+cn: Annalise Chrîstiân
+sn: Chrîstiân
+givenName: Annalise
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Annalise Chrîstiân's description
+mail: user47@test.com
+telephoneNumber: +1 415 448-5803
+facsimileTelephoneNumber: +1 213 836-8262
+userPassword: user47
+cn;lang-it: Annalise Chrîstiân
+sn;lang-it: Chrîstiân
+givenName;lang-it: Annalise
+
+dn: uid=user48, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user48
+cn: Hukam Tsonos
+sn: Tsonos
+givenName: Hukam
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Hukam Tsonos's description
+mail: user48@test.com
+telephoneNumber: +1 510 725-4642
+facsimileTelephoneNumber: +1 408 154-3028
+userPassword: user48
+cn;lang-se: Hukam Tsonos
+sn;lang-se: Tsonos
+givenName;lang-se: Hukam
+
+dn: uid=user49, ou=Ännheimè, o=Çéliné Ändrè
+uid: user49
+cn: Samÿn Ålthérr
+sn: Ålthérr
+givenName: Samÿn
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Samÿn Ålthérr's description
+mail: user49@test.com
+telephoneNumber: +1 206 952-1200
+facsimileTelephoneNumber: +1 714 601-1486
+userPassword: user49
+cn;lang-fr: Samÿn Ålthérr
+sn;lang-fr: Ålthérr
+givenName;lang-fr: Samÿn
+
+dn: uid=user50, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user50
+cn: Bobette MacLàrèn
+sn: MacLàrèn
+givenName: Bobette
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Bobette MacLàrèn's description
+mail: user50@test.com
+telephoneNumber: +1 804 548-5417
+facsimileTelephoneNumber: +1 415 656-3674
+userPassword: user50
+cn;lang-be: Bobette MacLàrèn
+sn;lang-be: MacLàrèn
+givenName;lang-be: Bobette
+
+dn: uid=user51, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user51
+cn: Grîëtje Nérby
+sn: Nérby
+givenName: Grîëtje
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Grîëtje Nérby's description
+mail: user51@test.com
+telephoneNumber: +1 714 751-9226
+facsimileTelephoneNumber: +1 408 231-4479
+userPassword: user51
+cn;lang-be: Grîëtje Nérby
+sn;lang-be: Nérby
+givenName;lang-be: Grîëtje
+
+dn: uid=user52, ou=Ännheimè, o=Çéliné Ändrè
+uid: user52
+cn: Lùrléñe Chrîstie
+sn: Chrîstie
+givenName: Lùrléñe
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Lùrléñe Chrîstie's description
+mail: user52@test.com
+telephoneNumber: +1 818 301-7281
+facsimileTelephoneNumber: +1 408 971-9928
+userPassword: user52
+cn;lang-se: Lùrléñe Chrîstie
+sn;lang-se: Chrîstie
+givenName;lang-se: Lùrléñe
+
+dn: uid=user53, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user53
+cn: Izumi Tzùâng
+sn: Tzùâng
+givenName: Izumi
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Izumi Tzùâng's description
+mail: user53@test.com
+telephoneNumber: +1 213 713-7080
+facsimileTelephoneNumber: +1 206 687-4878
+userPassword: user53
+cn;lang-it: Izumi Tzùâng
+sn;lang-it: Tzùâng
+givenName;lang-it: Izumi
+
+dn: uid=user54, ou=Ännheimè, o=Çéliné Ändrè
+uid: user54
+cn: Athât Armes
+sn: Armes
+givenName: Athât
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Athât Armes's description
+mail: user54@test.com
+telephoneNumber: +1 206 821-9285
+facsimileTelephoneNumber: +1 510 232-9437
+userPassword: user54
+cn;lang-se: Athât Armes
+sn;lang-se: Armes
+givenName;lang-se: Athât
+
+dn: uid=user55, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user55
+cn: Siüôx Cipolla
+sn: Cipolla
+givenName: Siüôx
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Siüôx Cipolla's description
+mail: user55@test.com
+telephoneNumber: +1 818 947-1439
+facsimileTelephoneNumber: +1 714 689-2821
+userPassword: user55
+cn;lang-es: Siüôx Cipolla
+sn;lang-es: Cipolla
+givenName;lang-es: Siüôx
+
+dn: uid=user56, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user56
+cn: Iain Hosking
+sn: Hosking
+givenName: Iain
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Iain Hosking's description
+mail: user56@test.com
+telephoneNumber: +1 818 663-9142
+facsimileTelephoneNumber: +1 415 688-7595
+userPassword: user56
+cn;lang-de: Iain Hosking
+sn;lang-de: Hosking
+givenName;lang-de: Iain
+
+dn: uid=user57, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user57
+cn: Ñelîë Backshall
+sn: Backshall
+givenName: Ñelîë
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñelîë Backshall's description
+mail: user57@test.com
+telephoneNumber: +1 415 915-2589
+facsimileTelephoneNumber: +1 714 359-6248
+userPassword: user57
+cn;lang-es: Ñelîë Backshall
+sn;lang-es: Backshall
+givenName;lang-es: Ñelîë
+
+dn: uid=user58, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user58
+cn: Wéñxi Jùnkin
+sn: Jùnkin
+givenName: Wéñxi
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Wéñxi Jùnkin's description
+mail: user58@test.com
+telephoneNumber: +1 408 523-1466
+facsimileTelephoneNumber: +1 408 839-7614
+userPassword: user58
+cn;lang-ie: Wéñxi Jùnkin
+sn;lang-ie: Jùnkin
+givenName;lang-ie: Wéñxi
+
+dn: uid=user59, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user59
+cn: Shanon Elsing
+sn: Elsing
+givenName: Shanon
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Shanon Elsing's description
+mail: user59@test.com
+telephoneNumber: +1 408 318-9017
+facsimileTelephoneNumber: +1 714 878-7761
+userPassword: user59
+cn;lang-be: Shanon Elsing
+sn;lang-be: Elsing
+givenName;lang-be: Shanon
+
+dn: uid=user60, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user60
+cn: Shellÿ Gräùsso
+sn: Gräùsso
+givenName: Shellÿ
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Shellÿ Gräùsso's description
+mail: user60@test.com
+telephoneNumber: +1 213 112-4893
+facsimileTelephoneNumber: +1 206 144-2382
+userPassword: user60
+cn;lang-be: Shellÿ Gräùsso
+sn;lang-be: Gräùsso
+givenName;lang-be: Shellÿ
+
+dn: uid=user61, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user61
+cn: Ñel Hairè
+sn: Hairè
+givenName: Ñel
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñel Hairè's description
+mail: user61@test.com
+telephoneNumber: +1 714 183-6682
+facsimileTelephoneNumber: +1 415 123-2391
+userPassword: user61
+cn;lang-es: Ñel Hairè
+sn;lang-es: Hairè
+givenName;lang-es: Ñel
+
+dn: uid=user62, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user62
+cn: Güôtam Sawchùk
+sn: Sawchùk
+givenName: Güôtam
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Güôtam Sawchùk's description
+mail: user62@test.com
+telephoneNumber: +1 804 159-3054
+facsimileTelephoneNumber: +1 714 660-8227
+userPassword: user62
+cn;lang-es: Güôtam Sawchùk
+sn;lang-es: Sawchùk
+givenName;lang-es: Güôtam
+
+dn: uid=user63, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user63
+cn: Çárëna Crùickshânk
+sn: Crùickshânk
+givenName: Çárëna
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Çárëna Crùickshânk's description
+mail: user63@test.com
+telephoneNumber: +1 415 409-9679
+facsimileTelephoneNumber: +1 804 917-2113
+userPassword: user63
+cn;lang-se: Çárëna Crùickshânk
+sn;lang-se: Crùickshânk
+givenName;lang-se: Çárëna
+
+dn: uid=user64, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user64
+cn: Wayñé Azàrî
+sn: Azàrî
+givenName: Wayñé
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Wayñé Azàrî's description
+mail: user64@test.com
+telephoneNumber: +1 303 178-3864
+facsimileTelephoneNumber: +1 213 402-4145
+userPassword: user64
+cn;lang-ie: Wayñé Azàrî
+sn;lang-ie: Azàrî
+givenName;lang-ie: Wayñé
+
+dn: uid=user65, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user65
+cn: Älëjandra Kräehèënbùehl
+sn: Kräehèënbùehl
+givenName: Älëjandra
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Älëjandra Kräehèënbùehl's description
+mail: user65@test.com
+telephoneNumber: +1 818 366-2521
+facsimileTelephoneNumber: +1 213 346-7450
+userPassword: user65
+cn;lang-se: Älëjandra Kräehèënbùehl
+sn;lang-se: Kräehèënbùehl
+givenName;lang-se: Älëjandra
+
+dn: uid=user66, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user66
+cn: Lujanka Mùllâney
+sn: Mùllâney
+givenName: Lujanka
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Lujanka Mùllâney's description
+mail: user66@test.com
+telephoneNumber: +1 804 191-3099
+facsimileTelephoneNumber: +1 804 664-4612
+userPassword: user66
+cn;lang-it: Lujanka Mùllâney
+sn;lang-it: Mùllâney
+givenName;lang-it: Lujanka
+
+dn: uid=user67, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user67
+cn: Rudîë Beehlér
+sn: Beehlér
+givenName: Rudîë
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Rudîë Beehlér's description
+mail: user67@test.com
+telephoneNumber: +1 206 629-8753
+facsimileTelephoneNumber: +1 303 182-9015
+userPassword: user67
+cn;lang-ie: Rudîë Beehlér
+sn;lang-ie: Beehlér
+givenName;lang-ie: Rudîë
+
+dn: uid=user68, ou=Ännheimè, o=Çéliné Ändrè
+uid: user68
+cn: Ñicholë Gùpta
+sn: Gùpta
+givenName: Ñicholë
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñicholë Gùpta's description
+mail: user68@test.com
+telephoneNumber: +1 206 625-2732
+facsimileTelephoneNumber: +1 714 523-3570
+userPassword: user68
+cn;lang-se: Ñicholë Gùpta
+sn;lang-se: Gùpta
+givenName;lang-se: Ñicholë
+
+dn: uid=user69, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user69
+cn: Icy Äbräms
+sn: Äbräms
+givenName: Icy
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Icy Äbräms's description
+mail: user69@test.com
+telephoneNumber: +1 213 733-2123
+facsimileTelephoneNumber: +1 510 576-6333
+userPassword: user69
+cn;lang-fr: Icy Äbräms
+sn;lang-fr: Äbräms
+givenName;lang-fr: Icy
+
+dn: uid=user70, ou=Ännheimè, o=Çéliné Ändrè
+uid: user70
+cn: Utillà Coddingtön
+sn: Coddingtön
+givenName: Utillà
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Utillà Coddingtön's description
+mail: user70@test.com
+telephoneNumber: +1 714 487-4984
+facsimileTelephoneNumber: +1 206 740-8670
+userPassword: user70
+cn;lang-it: Utillà Coddingtön
+sn;lang-it: Coddingtön
+givenName;lang-it: Utillà
+
+dn: uid=user71, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user71
+cn: Phöëbe Kérr
+sn: Kérr
+givenName: Phöëbe
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Phöëbe Kérr's description
+mail: user71@test.com
+telephoneNumber: +1 206 931-2018
+facsimileTelephoneNumber: +1 714 841-8782
+userPassword: user71
+cn;lang-es: Phöëbe Kérr
+sn;lang-es: Kérr
+givenName;lang-es: Phöëbe
+
+dn: uid=user72, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user72
+cn: Loñée Sampaleânù
+sn: Sampaleânù
+givenName: Loñée
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Loñée Sampaleânù's description
+mail: user72@test.com
+telephoneNumber: +1 415 640-6581
+facsimileTelephoneNumber: +1 804 179-2375
+userPassword: user72
+cn;lang-fr: Loñée Sampaleânù
+sn;lang-fr: Sampaleânù
+givenName;lang-fr: Loñée
+
+dn: uid=user73, ou=Ännheimè, o=Çéliné Ändrè
+uid: user73
+cn: Euphemîïå Fùqùa
+sn: Fùqùa
+givenName: Euphemîïå
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Euphemîïå Fùqùa's description
+mail: user73@test.com
+telephoneNumber: +1 714 145-6394
+facsimileTelephoneNumber: +1 714 102-6009
+userPassword: user73
+cn;lang-se: Euphemîïå Fùqùa
+sn;lang-se: Fùqùa
+givenName;lang-se: Euphemîïå
+
+dn: uid=user74, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user74
+cn: Sallÿ Rossi
+sn: Rossi
+givenName: Sallÿ
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Sallÿ Rossi's description
+mail: user74@test.com
+telephoneNumber: +1 714 558-4165
+facsimileTelephoneNumber: +1 510 684-4013
+userPassword: user74
+cn;lang-de: Sallÿ Rossi
+sn;lang-de: Rossi
+givenName;lang-de: Sallÿ
+
+dn: uid=user75, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user75
+cn: Aùrô Ingell
+sn: Ingell
+givenName: Aùrô
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Aùrô Ingell's description
+mail: user75@test.com
+telephoneNumber: +1 213 781-4916
+facsimileTelephoneNumber: +1 818 933-7641
+userPassword: user75
+cn;lang-ie: Aùrô Ingell
+sn;lang-ie: Ingell
+givenName;lang-ie: Aùrô
+
+dn: uid=user76, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user76
+cn: Chûng-Cheûng Moghis
+sn: Moghis
+givenName: Chûng-Cheûng
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Chûng-Cheûng Moghis's description
+mail: user76@test.com
+telephoneNumber: +1 818 816-8335
+facsimileTelephoneNumber: +1 714 803-6378
+userPassword: user76
+cn;lang-de: Chûng-Cheûng Moghis
+sn;lang-de: Moghis
+givenName;lang-de: Chûng-Cheûng
+
+dn: uid=user77, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user77
+cn: Chloris Plmçoop
+sn: Plmçoop
+givenName: Chloris
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Chloris Plmçoop's description
+mail: user77@test.com
+telephoneNumber: +1 408 918-4524
+facsimileTelephoneNumber: +1 303 650-4673
+userPassword: user77
+cn;lang-es: Chloris Plmçoop
+sn;lang-es: Plmçoop
+givenName;lang-es: Chloris
+
+dn: uid=user78, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user78
+cn: Ñiñétte SonHing
+sn: SonHing
+givenName: Ñiñétte
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñiñétte SonHing's description
+mail: user78@test.com
+telephoneNumber: +1 510 576-5294
+facsimileTelephoneNumber: +1 213 617-5968
+userPassword: user78
+cn;lang-se: Ñiñétte SonHing
+sn;lang-se: SonHing
+givenName;lang-se: Ñiñétte
+
+dn: uid=user79, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user79
+cn: Kaylëy Râçùsch
+sn: Râçùsch
+givenName: Kaylëy
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kaylëy Râçùsch's description
+mail: user79@test.com
+telephoneNumber: +1 818 717-4144
+facsimileTelephoneNumber: +1 206 387-6331
+userPassword: user79
+cn;lang-se: Kaylëy Râçùsch
+sn;lang-se: Râçùsch
+givenName;lang-se: Kaylëy
+
+dn: uid=user80, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user80
+cn: mÿry-Jañé Lafòrge
+sn: Lafòrge
+givenName: mÿry-Jañé
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is mÿry-Jañé Lafòrge's description
+mail: user80@test.com
+telephoneNumber: +1 408 517-7562
+facsimileTelephoneNumber: +1 415 771-8452
+userPassword: user80
+cn;lang-be: mÿry-Jañé Lafòrge
+sn;lang-be: Lafòrge
+givenName;lang-be: mÿry-Jañé
+
+dn: uid=user81, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user81
+cn: Saba Ajérsch
+sn: Ajérsch
+givenName: Saba
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Saba Ajérsch's description
+mail: user81@test.com
+telephoneNumber: +1 303 878-3769
+facsimileTelephoneNumber: +1 303 420-4793
+userPassword: user81
+cn;lang-ie: Saba Ajérsch
+sn;lang-ie: Ajérsch
+givenName;lang-ie: Saba
+
+dn: uid=user82, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user82
+cn: Achammÿ Blackweldér
+sn: Blackweldér
+givenName: Achammÿ
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Achammÿ Blackweldér's description
+mail: user82@test.com
+telephoneNumber: +1 714 491-6719
+facsimileTelephoneNumber: +1 206 839-3470
+userPassword: user82
+cn;lang-be: Achammÿ Blackweldér
+sn;lang-be: Blackweldér
+givenName;lang-be: Achammÿ
+
+dn: uid=user83, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user83
+cn: Kishor Râçcz
+sn: Râçcz
+givenName: Kishor
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kishor Râçcz's description
+mail: user83@test.com
+telephoneNumber: +1 415 191-2618
+facsimileTelephoneNumber: +1 818 171-3587
+userPassword: user83
+cn;lang-se: Kishor Râçcz
+sn;lang-se: Râçcz
+givenName;lang-se: Kishor
+
+dn: uid=user84, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user84
+cn: Sophi Hallïwill
+sn: Hallïwill
+givenName: Sophi
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Sophi Hallïwill's description
+mail: user84@test.com
+telephoneNumber: +1 818 533-5665
+facsimileTelephoneNumber: +1 510 836-6345
+userPassword: user84
+cn;lang-se: Sophi Hallïwill
+sn;lang-se: Hallïwill
+givenName;lang-se: Sophi
+
+dn: uid=user85, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user85
+cn: Kätîë Gotch
+sn: Gotch
+givenName: Kätîë
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kätîë Gotch's description
+mail: user85@test.com
+telephoneNumber: +1 818 597-8603
+facsimileTelephoneNumber: +1 213 153-7022
+userPassword: user85
+cn;lang-be: Kätîë Gotch
+sn;lang-be: Gotch
+givenName;lang-be: Kätîë
+
+dn: uid=user86, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user86
+cn: Rachelë Basco
+sn: Basco
+givenName: Rachelë
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Rachelë Basco's description
+mail: user86@test.com
+telephoneNumber: +1 510 824-6348
+facsimileTelephoneNumber: +1 818 221-7820
+userPassword: user86
+cn;lang-de: Rachelë Basco
+sn;lang-de: Basco
+givenName;lang-de: Rachelë
+
+dn: uid=user87, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user87
+cn: Jon Espàrza
+sn: Espàrza
+givenName: Jon
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Jon Espàrza's description
+mail: user87@test.com
+telephoneNumber: +1 510 708-4813
+facsimileTelephoneNumber: +1 206 884-7493
+userPassword: user87
+cn;lang-se: Jon Espàrza
+sn;lang-se: Espàrza
+givenName;lang-se: Jon
+
+dn: uid=user88, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user88
+cn: Rômmel Rembecki
+sn: Rembecki
+givenName: Rômmel
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Rômmel Rembecki's description
+mail: user88@test.com
+telephoneNumber: +1 818 220-4436
+facsimileTelephoneNumber: +1 213 879-1384
+userPassword: user88
+cn;lang-be: Rômmel Rembecki
+sn;lang-be: Rembecki
+givenName;lang-be: Rômmel
+
+dn: uid=user89, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user89
+cn: ViDà Lacasse
+sn: Lacasse
+givenName: ViDà
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is ViDà Lacasse's description
+mail: user89@test.com
+telephoneNumber: +1 415 618-3243
+facsimileTelephoneNumber: +1 303 542-2997
+userPassword: user89
+cn;lang-de: ViDà Lacasse
+sn;lang-de: Lacasse
+givenName;lang-de: ViDà
+
+dn: uid=user90, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user90
+cn: Fey Dowding
+sn: Dowding
+givenName: Fey
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Fey Dowding's description
+mail: user90@test.com
+telephoneNumber: +1 804 655-1902
+facsimileTelephoneNumber: +1 303 340-1322
+userPassword: user90
+cn;lang-de: Fey Dowding
+sn;lang-de: Dowding
+givenName;lang-de: Fey
+
+dn: uid=user91, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user91
+cn: Kast Faùlknér
+sn: Faùlknér
+givenName: Kast
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kast Faùlknér's description
+mail: user91@test.com
+telephoneNumber: +1 804 737-5478
+facsimileTelephoneNumber: +1 303 781-9716
+userPassword: user91
+cn;lang-be: Kast Faùlknér
+sn;lang-be: Faùlknér
+givenName;lang-be: Kast
+
+dn: uid=user92, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user92
+cn: Georßànñé Kùrîo
+sn: Kùrîo
+givenName: Georßànñé
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Georßànñé Kùrîo's description
+mail: user92@test.com
+telephoneNumber: +1 408 831-7990
+facsimileTelephoneNumber: +1 206 620-5043
+userPassword: user92
+cn;lang-se: Georßànñé Kùrîo
+sn;lang-se: Kùrîo
+givenName;lang-se: Georßànñé
+
+dn: uid=user93, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user93
+cn: Dolorës Màrkovic
+sn: Màrkovic
+givenName: Dolorës
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Dolorës Màrkovic's description
+mail: user93@test.com
+telephoneNumber: +1 408 374-9555
+facsimileTelephoneNumber: +1 206 879-3002
+userPassword: user93
+cn;lang-it: Dolorës Màrkovic
+sn;lang-it: Màrkovic
+givenName;lang-it: Dolorës
+
+dn: uid=user94, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user94
+cn: Pätti Hollïngwòrth
+sn: Hollïngwòrth
+givenName: Pätti
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Pätti Hollïngwòrth's description
+mail: user94@test.com
+telephoneNumber: +1 303 896-3530
+facsimileTelephoneNumber: +1 714 945-1799
+userPassword: user94
+cn;lang-se: Pätti Hollïngwòrth
+sn;lang-se: Hollïngwòrth
+givenName;lang-se: Pätti
+
+dn: uid=user95, ou=Ännheimè, o=Çéliné Ändrè
+uid: user95
+cn: Gwéñdolÿn McCândless
+sn: McCândless
+givenName: Gwéñdolÿn
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Gwéñdolÿn McCândless's description
+mail: user95@test.com
+telephoneNumber: +1 303 426-8725
+facsimileTelephoneNumber: +1 818 442-3609
+userPassword: user95
+cn;lang-ie: Gwéñdolÿn McCândless
+sn;lang-ie: McCândless
+givenName;lang-ie: Gwéñdolÿn
+
+dn: uid=user96, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user96
+cn: Gusellà Rch
+sn: Rch
+givenName: Gusellà
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Gusellà Rch's description
+mail: user96@test.com
+telephoneNumber: +1 510 633-1074
+facsimileTelephoneNumber: +1 714 645-8397
+userPassword: user96
+cn;lang-fr: Gusellà Rch
+sn;lang-fr: Rch
+givenName;lang-fr: Gusellà
+
+dn: uid=user97, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user97
+cn: Lyndel Whâng
+sn: Whâng
+givenName: Lyndel
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Lyndel Whâng's description
+mail: user97@test.com
+telephoneNumber: +1 818 581-4327
+facsimileTelephoneNumber: +1 510 738-8516
+userPassword: user97
+cn;lang-se: Lyndel Whâng
+sn;lang-se: Whâng
+givenName;lang-se: Lyndel
+
+dn: uid=user98, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user98
+cn: Cordelîïå Fatér
+sn: Fatér
+givenName: Cordelîïå
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Cordelîïå Fatér's description
+mail: user98@test.com
+telephoneNumber: +1 303 251-4813
+facsimileTelephoneNumber: +1 510 263-8972
+userPassword: user98
+cn;lang-de: Cordelîïå Fatér
+sn;lang-de: Fatér
+givenName;lang-de: Cordelîïå
+
+dn: uid=user99, ou=Ännheimè, o=Çéliné Ändrè
+uid: user99
+cn: Cristöfâto Boivin
+sn: Boivin
+givenName: Cristöfâto
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Cristöfâto Boivin's description
+mail: user99@test.com
+telephoneNumber: +1 804 792-5496
+facsimileTelephoneNumber: +1 206 573-1190
+userPassword: user99
+cn;lang-es: Cristöfâto Boivin
+sn;lang-es: Boivin
+givenName;lang-es: Cristöfâto
+
+dn: uid=user100, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user100
+cn: Jûnina Khosräviâni
+sn: Khosräviâni
+givenName: Jûnina
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Jûnina Khosräviâni's description
+mail: user100@test.com
+telephoneNumber: +1 714 710-2753
+facsimileTelephoneNumber: +1 714 187-4444
+userPassword: user100
+cn;lang-fr: Jûnina Khosräviâni
+sn;lang-fr: Khosräviâni
+givenName;lang-fr: Jûnina
+
+dn: uid=user101, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user101
+cn: Tushât Shackletön
+sn: Shackletön
+givenName: Tushât
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Tushât Shackletön's description
+mail: user101@test.com
+telephoneNumber: +1 206 135-1925
+facsimileTelephoneNumber: +1 206 197-1626
+userPassword: user101
+cn;lang-it: Tushât Shackletön
+sn;lang-it: Shackletön
+givenName;lang-it: Tushât
+
+dn: uid=user102, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user102
+cn: Clovis Safah
+sn: Safah
+givenName: Clovis
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Clovis Safah's description
+mail: user102@test.com
+telephoneNumber: +1 415 964-2124
+facsimileTelephoneNumber: +1 415 141-3727
+userPassword: user102
+cn;lang-de: Clovis Safah
+sn;lang-de: Safah
+givenName;lang-de: Clovis
+
+dn: uid=user103, ou=Ännheimè, o=Çéliné Ändrè
+uid: user103
+cn: Xylina Hoyér
+sn: Hoyér
+givenName: Xylina
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Xylina Hoyér's description
+mail: user103@test.com
+telephoneNumber: +1 303 107-8399
+facsimileTelephoneNumber: +1 804 145-4003
+userPassword: user103
+cn;lang-it: Xylina Hoyér
+sn;lang-it: Hoyér
+givenName;lang-it: Xylina
+
+dn: uid=user104, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user104
+cn: Millâtd Colagrösso
+sn: Colagrösso
+givenName: Millâtd
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Millâtd Colagrösso's description
+mail: user104@test.com
+telephoneNumber: +1 804 756-6465
+facsimileTelephoneNumber: +1 804 636-9306
+userPassword: user104
+cn;lang-se: Millâtd Colagrösso
+sn;lang-se: Colagrösso
+givenName;lang-se: Millâtd
+
+dn: uid=user105, ou=Ännheimè, o=Çéliné Ändrè
+uid: user105
+cn: Kassandra Rollïns
+sn: Rollïns
+givenName: Kassandra
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kassandra Rollïns's description
+mail: user105@test.com
+telephoneNumber: +1 408 981-5317
+facsimileTelephoneNumber: +1 510 398-5322
+userPassword: user105
+cn;lang-fr: Kassandra Rollïns
+sn;lang-fr: Rollïns
+givenName;lang-fr: Kassandra
+
+dn: uid=user106, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user106
+cn: Mêrrîëllë Itö
+sn: Itö
+givenName: Mêrrîëllë
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Mêrrîëllë Itö's description
+mail: user106@test.com
+telephoneNumber: +1 408 954-8385
+facsimileTelephoneNumber: +1 510 730-9253
+userPassword: user106
+cn;lang-de: Mêrrîëllë Itö
+sn;lang-de: Itö
+givenName;lang-de: Mêrrîëllë
+
+dn: uid=user107, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user107
+cn: Annâtbor Seay
+sn: Seay
+givenName: Annâtbor
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Annâtbor Seay's description
+mail: user107@test.com
+telephoneNumber: +1 510 964-8926
+facsimileTelephoneNumber: +1 804 275-8841
+userPassword: user107
+cn;lang-de: Annâtbor Seay
+sn;lang-de: Seay
+givenName;lang-de: Annâtbor
+
+dn: uid=user108, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user108
+cn: Sibellë Clegg
+sn: Clegg
+givenName: Sibellë
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Sibellë Clegg's description
+mail: user108@test.com
+telephoneNumber: +1 714 153-4454
+facsimileTelephoneNumber: +1 213 389-1302
+userPassword: user108
+cn;lang-be: Sibellë Clegg
+sn;lang-be: Clegg
+givenName;lang-be: Sibellë
+
+dn: uid=user109, ou=Ännheimè, o=Çéliné Ändrè
+uid: user109
+cn: Çáthlëéñ Brèedlove
+sn: Brèedlove
+givenName: Çáthlëéñ
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Çáthlëéñ Brèedlove's description
+mail: user109@test.com
+telephoneNumber: +1 818 282-5480
+facsimileTelephoneNumber: +1 213 841-7668
+userPassword: user109
+cn;lang-es: Çáthlëéñ Brèedlove
+sn;lang-es: Brèedlove
+givenName;lang-es: Çáthlëéñ
+
+dn: uid=user110, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user110
+cn: Violëtte Ditko
+sn: Ditko
+givenName: Violëtte
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Violëtte Ditko's description
+mail: user110@test.com
+telephoneNumber: +1 206 239-7182
+facsimileTelephoneNumber: +1 818 901-7049
+userPassword: user110
+cn;lang-be: Violëtte Ditko
+sn;lang-be: Ditko
+givenName;lang-be: Violëtte
+
+dn: uid=user111, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user111
+cn: Jany Magnùson
+sn: Magnùson
+givenName: Jany
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Jany Magnùson's description
+mail: user111@test.com
+telephoneNumber: +1 804 139-1045
+facsimileTelephoneNumber: +1 818 338-3357
+userPassword: user111
+cn;lang-be: Jany Magnùson
+sn;lang-be: Magnùson
+givenName;lang-be: Jany
+
+dn: uid=user112, ou=Ännheimè, o=Çéliné Ändrè
+uid: user112
+cn: Grîëtje Bïålkèëniùs
+sn: Bïålkèëniùs
+givenName: Grîëtje
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Grîëtje Bïålkèëniùs's description
+mail: user112@test.com
+telephoneNumber: +1 510 739-6583
+facsimileTelephoneNumber: +1 818 836-2896
+userPassword: user112
+cn;lang-se: Grîëtje Bïålkèëniùs
+sn;lang-se: Bïålkèëniùs
+givenName;lang-se: Grîëtje
+
+dn: uid=user113, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user113
+cn: Mozellë Frènch
+sn: Frènch
+givenName: Mozellë
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Mozellë Frènch's description
+mail: user113@test.com
+telephoneNumber: +1 415 469-2172
+facsimileTelephoneNumber: +1 303 621-1839
+userPassword: user113
+cn;lang-de: Mozellë Frènch
+sn;lang-de: Frènch
+givenName;lang-de: Mozellë
+
+dn: uid=user114, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user114
+cn: Ñonna Yahyapoùr
+sn: Yahyapoùr
+givenName: Ñonna
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñonna Yahyapoùr's description
+mail: user114@test.com
+telephoneNumber: +1 714 948-9261
+facsimileTelephoneNumber: +1 804 802-4813
+userPassword: user114
+cn;lang-it: Ñonna Yahyapoùr
+sn;lang-it: Yahyapoùr
+givenName;lang-it: Ñonna
+
+dn: uid=user115, ou=Ännheimè, o=Çéliné Ändrè
+uid: user115
+cn: Angelîë Mirände
+sn: Mirände
+givenName: Angelîë
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Angelîë Mirände's description
+mail: user115@test.com
+telephoneNumber: +1 804 832-8156
+facsimileTelephoneNumber: +1 804 720-5542
+userPassword: user115
+cn;lang-ie: Angelîë Mirände
+sn;lang-ie: Mirände
+givenName;lang-ie: Angelîë
+
+dn: uid=user116, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user116
+cn: ÇáRôl-jean Sainsbùry
+sn: Sainsbùry
+givenName: ÇáRôl-jean
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is ÇáRôl-jean Sainsbùry's description
+mail: user116@test.com
+telephoneNumber: +1 804 462-8515
+facsimileTelephoneNumber: +1 408 987-8524
+userPassword: user116
+cn;lang-it: ÇáRôl-jean Sainsbùry
+sn;lang-it: Sainsbùry
+givenName;lang-it: ÇáRôl-jean
+
+dn: uid=user117, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user117
+cn: Ting Uffnér
+sn: Uffnér
+givenName: Ting
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ting Uffnér's description
+mail: user117@test.com
+telephoneNumber: +1 818 276-1089
+facsimileTelephoneNumber: +1 415 895-7043
+userPassword: user117
+cn;lang-es: Ting Uffnér
+sn;lang-es: Uffnér
+givenName;lang-es: Ting
+
+dn: uid=user118, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user118
+cn: Lil Sells
+sn: Sells
+givenName: Lil
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Lil Sells's description
+mail: user118@test.com
+telephoneNumber: +1 213 914-4404
+facsimileTelephoneNumber: +1 818 250-4206
+userPassword: user118
+cn;lang-se: Lil Sells
+sn;lang-se: Sells
+givenName;lang-se: Lil
+
+dn: uid=user119, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user119
+cn: Ñic Românchùck
+sn: Românchùck
+givenName: Ñic
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñic Românchùck's description
+mail: user119@test.com
+telephoneNumber: +1 303 502-5442
+facsimileTelephoneNumber: +1 510 510-3084
+userPassword: user119
+cn;lang-es: Ñic Românchùck
+sn;lang-es: Românchùck
+givenName;lang-es: Ñic
+
+dn: uid=user120, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user120
+cn: Violëtta Reinwald
+sn: Reinwald
+givenName: Violëtta
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Violëtta Reinwald's description
+mail: user120@test.com
+telephoneNumber: +1 206 422-8271
+facsimileTelephoneNumber: +1 408 532-1292
+userPassword: user120
+cn;lang-es: Violëtta Reinwald
+sn;lang-es: Reinwald
+givenName;lang-es: Violëtta
+
+dn: uid=user121, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user121
+cn: Ramiz Systêst
+sn: Systêst
+givenName: Ramiz
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ramiz Systêst's description
+mail: user121@test.com
+telephoneNumber: +1 206 972-5388
+facsimileTelephoneNumber: +1 206 497-7314
+userPassword: user121
+cn;lang-it: Ramiz Systêst
+sn;lang-it: Systêst
+givenName;lang-it: Ramiz
+
+dn: uid=user122, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user122
+cn: Pätching Diblér
+sn: Diblér
+givenName: Pätching
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Pätching Diblér's description
+mail: user122@test.com
+telephoneNumber: +1 415 666-6668
+facsimileTelephoneNumber: +1 213 163-3483
+userPassword: user122
+cn;lang-ie: Pätching Diblér
+sn;lang-ie: Diblér
+givenName;lang-ie: Pätching
+
+dn: uid=user123, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user123
+cn: Celÿñé Baskin
+sn: Baskin
+givenName: Celÿñé
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Celÿñé Baskin's description
+mail: user123@test.com
+telephoneNumber: +1 510 186-7577
+facsimileTelephoneNumber: +1 415 929-8591
+userPassword: user123
+cn;lang-fr: Celÿñé Baskin
+sn;lang-fr: Baskin
+givenName;lang-fr: Celÿñé
+
+dn: uid=user124, ou=Ännheimè, o=Çéliné Ändrè
+uid: user124
+cn: Janîë Pàrdi
+sn: Pàrdi
+givenName: Janîë
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Janîë Pàrdi's description
+mail: user124@test.com
+telephoneNumber: +1 408 999-8165
+facsimileTelephoneNumber: +1 303 539-4548
+userPassword: user124
+cn;lang-de: Janîë Pàrdi
+sn;lang-de: Pàrdi
+givenName;lang-de: Janîë
+
+dn: uid=user125, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user125
+cn: Aùrîë Brîsby
+sn: Brîsby
+givenName: Aùrîë
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Aùrîë Brîsby's description
+mail: user125@test.com
+telephoneNumber: +1 415 769-1594
+facsimileTelephoneNumber: +1 415 880-6179
+userPassword: user125
+cn;lang-be: Aùrîë Brîsby
+sn;lang-be: Brîsby
+givenName;lang-be: Aùrîë
+
+dn: uid=user126, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user126
+cn: Livvyy Klùtts
+sn: Klùtts
+givenName: Livvyy
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Livvyy Klùtts's description
+mail: user126@test.com
+telephoneNumber: +1 818 397-4012
+facsimileTelephoneNumber: +1 408 728-8013
+userPassword: user126
+cn;lang-ie: Livvyy Klùtts
+sn;lang-ie: Klùtts
+givenName;lang-ie: Livvyy
+
+dn: uid=user127, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user127
+cn: Sibillà Millspaùgh
+sn: Millspaùgh
+givenName: Sibillà
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Sibillà Millspaùgh's description
+mail: user127@test.com
+telephoneNumber: +1 818 204-6815
+facsimileTelephoneNumber: +1 714 990-5705
+userPassword: user127
+cn;lang-it: Sibillà Millspaùgh
+sn;lang-it: Millspaùgh
+givenName;lang-it: Sibillà
+
+dn: uid=user128, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user128
+cn: Äléña Milân
+sn: Milân
+givenName: Äléña
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Äléña Milân's description
+mail: user128@test.com
+telephoneNumber: +1 303 570-2112
+facsimileTelephoneNumber: +1 206 896-6336
+userPassword: user128
+cn;lang-es: Äléña Milân
+sn;lang-es: Milân
+givenName;lang-es: Äléña
+
+dn: uid=user129, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user129
+cn: Hêrve McDade
+sn: McDade
+givenName: Hêrve
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Hêrve McDade's description
+mail: user129@test.com
+telephoneNumber: +1 415 829-2873
+facsimileTelephoneNumber: +1 804 602-8199
+userPassword: user129
+cn;lang-be: Hêrve McDade
+sn;lang-be: McDade
+givenName;lang-be: Hêrve
+
+dn: uid=user130, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user130
+cn: SayeeDà Emesh
+sn: Emesh
+givenName: SayeeDà
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is SayeeDà Emesh's description
+mail: user130@test.com
+telephoneNumber: +1 510 427-1290
+facsimileTelephoneNumber: +1 714 808-3656
+userPassword: user130
+cn;lang-se: SayeeDà Emesh
+sn;lang-se: Emesh
+givenName;lang-se: SayeeDà
+
+dn: uid=user131, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user131
+cn: Ñeelÿ Tynân
+sn: Tynân
+givenName: Ñeelÿ
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñeelÿ Tynân's description
+mail: user131@test.com
+telephoneNumber: +1 818 260-4462
+facsimileTelephoneNumber: +1 213 705-2076
+userPassword: user131
+cn;lang-es: Ñeelÿ Tynân
+sn;lang-es: Tynân
+givenName;lang-es: Ñeelÿ
+
+dn: uid=user132, ou=Ännheimè, o=Çéliné Ändrè
+uid: user132
+cn: Ñaji Flòrès
+sn: Flòrès
+givenName: Ñaji
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñaji Flòrès's description
+mail: user132@test.com
+telephoneNumber: +1 818 417-2310
+facsimileTelephoneNumber: +1 818 784-8714
+userPassword: user132
+cn;lang-es: Ñaji Flòrès
+sn;lang-es: Flòrès
+givenName;lang-es: Ñaji
+
+dn: uid=user133, ou=Ännheimè, o=Çéliné Ändrè
+uid: user133
+cn: mÿùrise Pùglïå
+sn: Pùglïå
+givenName: mÿùrise
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is mÿùrise Pùglïå's description
+mail: user133@test.com
+telephoneNumber: +1 415 346-5688
+facsimileTelephoneNumber: +1 415 945-8392
+userPassword: user133
+cn;lang-es: mÿùrise Pùglïå
+sn;lang-es: Pùglïå
+givenName;lang-es: mÿùrise
+
+dn: uid=user134, ou=Çéliné Ändrè, o=Çéliné Ändrè
+uid: user134
+cn: Wañéta Vempati
+sn: Vempati
+givenName: Wañéta
+ou: Çéliné Ändrè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Wañéta Vempati's description
+mail: user134@test.com
+telephoneNumber: +1 510 651-3623
+facsimileTelephoneNumber: +1 415 382-1034
+userPassword: user134
+cn;lang-it: Wañéta Vempati
+sn;lang-it: Vempati
+givenName;lang-it: Wañéta
+
+dn: uid=user135, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user135
+cn: Lañéy Gröna
+sn: Gröna
+givenName: Lañéy
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Lañéy Gröna's description
+mail: user135@test.com
+telephoneNumber: +1 510 317-9705
+facsimileTelephoneNumber: +1 804 125-9224
+userPassword: user135
+cn;lang-it: Lañéy Gröna
+sn;lang-it: Gröna
+givenName;lang-it: Lañéy
+
+dn: uid=user136, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user136
+cn: Muffin Bayér
+sn: Bayér
+givenName: Muffin
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Muffin Bayér's description
+mail: user136@test.com
+telephoneNumber: +1 818 514-6302
+facsimileTelephoneNumber: +1 303 383-3961
+userPassword: user136
+cn;lang-ie: Muffin Bayér
+sn;lang-ie: Bayér
+givenName;lang-ie: Muffin
+
+dn: uid=user137, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user137
+cn: Lingyan Cottingham
+sn: Cottingham
+givenName: Lingyan
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Lingyan Cottingham's description
+mail: user137@test.com
+telephoneNumber: +1 818 529-3823
+facsimileTelephoneNumber: +1 510 177-7520
+userPassword: user137
+cn;lang-se: Lingyan Cottingham
+sn;lang-se: Cottingham
+givenName;lang-se: Lingyan
+
+dn: uid=user138, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user138
+cn: Corrëna Träsmùndi
+sn: Träsmùndi
+givenName: Corrëna
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Corrëna Träsmùndi's description
+mail: user138@test.com
+telephoneNumber: +1 804 774-3146
+facsimileTelephoneNumber: +1 213 631-6660
+userPassword: user138
+cn;lang-be: Corrëna Träsmùndi
+sn;lang-be: Träsmùndi
+givenName;lang-be: Corrëna
+
+dn: uid=user139, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user139
+cn: Ñeil Chérrîér
+sn: Chérrîér
+givenName: Ñeil
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ñeil Chérrîér's description
+mail: user139@test.com
+telephoneNumber: +1 714 474-5839
+facsimileTelephoneNumber: +1 408 516-3260
+userPassword: user139
+cn;lang-it: Ñeil Chérrîér
+sn;lang-it: Chérrîér
+givenName;lang-it: Ñeil
+
+dn: uid=user140, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user140
+cn: Älfonso Waltérs
+sn: Waltérs
+givenName: Älfonso
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Älfonso Waltérs's description
+mail: user140@test.com
+telephoneNumber: +1 714 607-3408
+facsimileTelephoneNumber: +1 408 233-3644
+userPassword: user140
+cn;lang-it: Älfonso Waltérs
+sn;lang-it: Waltérs
+givenName;lang-it: Älfonso
+
+dn: uid=user141, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user141
+cn: Collëte Wàrfel
+sn: Wàrfel
+givenName: Collëte
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Collëte Wàrfel's description
+mail: user141@test.com
+telephoneNumber: +1 804 360-5788
+facsimileTelephoneNumber: +1 804 749-8263
+userPassword: user141
+cn;lang-es: Collëte Wàrfel
+sn;lang-es: Wàrfel
+givenName;lang-es: Collëte
+
+dn: uid=user142, ou=Ännheimè, o=Çéliné Ändrè
+uid: user142
+cn: Kishor McAdòrèy
+sn: McAdòrèy
+givenName: Kishor
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Kishor McAdòrèy's description
+mail: user142@test.com
+telephoneNumber: +1 714 433-5127
+facsimileTelephoneNumber: +1 510 752-1955
+userPassword: user142
+cn;lang-fr: Kishor McAdòrèy
+sn;lang-fr: McAdòrèy
+givenName;lang-fr: Kishor
+
+dn: uid=user143, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user143
+cn: Dûncan Schlïchting
+sn: Schlïchting
+givenName: Dûncan
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Dûncan Schlïchting's description
+mail: user143@test.com
+telephoneNumber: +1 804 717-9847
+facsimileTelephoneNumber: +1 804 474-1501
+userPassword: user143
+cn;lang-be: Dûncan Schlïchting
+sn;lang-be: Schlïchting
+givenName;lang-be: Dûncan
+
+dn: uid=user144, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user144
+cn: Valéñtîïå Gräcey
+sn: Gräcey
+givenName: Valéñtîïå
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Valéñtîïå Gräcey's description
+mail: user144@test.com
+telephoneNumber: +1 206 284-2530
+facsimileTelephoneNumber: +1 206 909-3569
+userPassword: user144
+cn;lang-fr: Valéñtîïå Gräcey
+sn;lang-fr: Gräcey
+givenName;lang-fr: Valéñtîïå
+
+dn: uid=user145, ou=Ännheimè, o=Çéliné Ändrè
+uid: user145
+cn: Ällëgra Weisèënbérg
+sn: Weisèënbérg
+givenName: Ällëgra
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ällëgra Weisèënbérg's description
+mail: user145@test.com
+telephoneNumber: +1 415 348-1595
+facsimileTelephoneNumber: +1 804 623-1255
+userPassword: user145
+cn;lang-ie: Ällëgra Weisèënbérg
+sn;lang-ie: Weisèënbérg
+givenName;lang-ie: Ällëgra
+
+dn: uid=user146, ou=Ännheimè, o=Çéliné Ändrè
+uid: user146
+cn: LLoyd Majùry
+sn: Majùry
+givenName: LLoyd
+ou: Ännheimè
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is LLoyd Majùry's description
+mail: user146@test.com
+telephoneNumber: +1 213 109-3465
+facsimileTelephoneNumber: +1 213 515-2132
+userPassword: user146
+cn;lang-se: LLoyd Majùry
+sn;lang-se: Majùry
+givenName;lang-se: LLoyd
+
+dn: uid=user147, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user147
+cn: Ellàdiñé Passin
+sn: Passin
+givenName: Ellàdiñé
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Ellàdiñé Passin's description
+mail: user147@test.com
+telephoneNumber: +1 510 570-9369
+facsimileTelephoneNumber: +1 408 482-2946
+userPassword: user147
+cn;lang-de: Ellàdiñé Passin
+sn;lang-de: Passin
+givenName;lang-de: Ellàdiñé
+
+dn: uid=user148, ou=Sàn Fråncêscô, o=Çéliné Ändrè
+uid: user148
+cn: Chantallë Secrèst
+sn: Secrèst
+givenName: Chantallë
+ou: Sàn Fråncêscô
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Chantallë Secrèst's description
+mail: user148@test.com
+telephoneNumber: +1 804 726-9344
+facsimileTelephoneNumber: +1 408 356-1611
+userPassword: user148
+cn;lang-it: Chantallë Secrèst
+sn;lang-it: Secrèst
+givenName;lang-it: Chantallë
+
+dn: uid=user149, ou=Çlose Crèkä, o=Çéliné Ändrè
+uid: user149
+cn: Dick Tsitsiòr
+sn: Tsitsiòr
+givenName: Dick
+ou: Çlose Crèkä
+objectClass: top
+objectClass: person
+objectClass: organizationalPerson
+objectClass: inetOrgPerson
+description: This is Dick Tsitsiòr's description
+mail: user149@test.com
+telephoneNumber: +1 804 768-4911
+facsimileTelephoneNumber: +1 303 253-4009
+userPassword: user149
+cn;lang-ie: Dick Tsitsiòr
+sn;lang-ie: Tsitsiòr
+givenName;lang-ie: Dick
+
+dn: ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: European Letters
+description: Root for Franch, German, and Spanish letters
+
+dn: ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Auf Deutsch
+ou;lang-de: ÄÖÜäöüß
+description: German Letters
+
+dn: ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: En Español
+ou;lang-es: á, é, í, ó, ü, ñ, Ã, É, Ã, Ó, Ú, Ãœ, Ñ
+description: Spanish Letters
+
+dn: ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: En Français
+ou:lang-fr: àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ
+description: French 8Bit Letters
+
+dn: ou=ä, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ä
+ou;lang-de: ä
+description: ä
+
+dn: ou=ö, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ö
+ou;lang-de: ö
+description: ö
+
+dn: ou=ü, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ü
+ou;lang-de: ü
+description: ü
+
+dn: ou=ß, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ß
+ou;lang-de: ß
+description: ß
+
+dn: ou=Ä-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ä-2
+ou;lang-de: Ä-2
+description: Ä-2
+
+dn: ou=Ö-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ö-2
+ou;lang-de: Ö-2
+description: Ö-2
+
+dn: ou=Ü-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ü-2
+ou;lang-de: Ü-2
+description: Ü-2
+
+dn: ou=á, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: á
+ou;lang-es: á
+description: á
+
+dn: ou=é, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: é
+ou;lang-es: é
+description: é
+
+dn: ou=í, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: í
+ou;lang-es: í
+description: í
+
+dn: ou=ó, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ó
+ou;lang-es: ó
+description: ó
+
+dn: ou=ü, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ü
+ou;lang-es: ü
+description: ü
+
+dn: ou=ñ, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ñ
+ou;lang-es: ñ
+description: ñ
+
+dn: ou=Ã-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ã-2
+ou;lang-es: Ã-2
+description: Ã-2
+
+dn: ou=É-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: É-2
+ou;lang-es: É-2
+description: É-2
+
+dn: ou=Ã-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ã-2
+ou;lang-es: Ã-2
+description: Ã-2
+
+dn: ou=Ó-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ó-2
+ou;lang-es: Ó-2
+description: Ó-2
+
+dn: ou=Ú-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ú-2
+ou;lang-es: Ú-2
+description: Ú-2
+
+dn: ou=Ü-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ü-2
+ou;lang-es: Ü-2
+description: Ü-2
+
+dn: ou=Ñ-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ñ-2
+ou;lang-es: Ñ-2
+description: Ñ-2
+
+dn: ou=à, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: à
+ou;lang-fr: à
+description: à
+
+dn: ou=â, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: â
+ou;lang-fr: â
+description: â
+
+dn: ou=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ç
+ou;lang-fr: ç
+description: ç
+
+dn: ou=ë, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ë
+ou;lang-fr: ë
+description: ë
+
+dn: ou=è, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: è
+ou;lang-fr: è
+description: è
+
+dn: ou=é, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: é
+ou;lang-fr: é
+description: é
+
+dn: ou=ê, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ê
+ou;lang-fr: ê
+description: ê
+
+dn: ou=ï, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ï
+ou;lang-fr: ï
+description: ï
+
+dn: ou=î, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: î
+ou;lang-fr: î
+description: î
+
+dn: ou=ô, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ô
+ou;lang-fr: ô
+description: ô
+
+dn: ou=ü, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ü
+ou;lang-fr: ü
+description: ü
+
+dn: ou=ù, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ù
+ou;lang-fr: ù
+description: ù
+
+dn: ou=û, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: û
+ou;lang-fr: û
+description: û
+
+dn: ou=À-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: À-2
+ou;lang-fr: À-2
+description: À-2
+
+dn: ou=Â-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Â-2
+ou;lang-fr: Â-2
+description: Â-2
+
+dn: ou=Ç-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ç-2
+ou;lang-fr: Ç-2
+description: Ç-2
+
+dn: ou=Ë-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ë-2
+ou;lang-fr: Ë-2
+description: Ë-2
+
+dn: ou=È-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: È-2
+ou;lang-fr: È-2
+description: È-2
+
+dn: ou=É-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: É-2
+ou;lang-fr: É-2
+description: É-2
+
+dn: ou=Ê-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ê-2
+ou;lang-fr: Ê-2
+description: Ê-2
+
+dn: ou=Ã-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ã-2
+ou;lang-fr: Ã-2
+description: Ã-2
+
+dn: ou=Î-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: ÃŽ-2
+ou;lang-fr: ÃŽ-2
+description: ÃŽ-2
+
+dn: ou=Ô-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ô-2
+ou;lang-fr: Ô-2
+description: Ô-2
+
+dn: ou=Ü-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ü-2
+ou;lang-fr: Ü-2
+description: Ü-2
+
+dn: ou=Ù-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Ù-2
+ou;lang-fr: Ù-2
+description: Ù-2
+
+dn: ou=Û-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Û-2
+ou;lang-fr: Û-2
+description: Û-2
+
+dn: ou=A, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: A
+ou;lang-de: A
+description: A
+
+dn: ou=B, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: B
+ou;lang-de: B
+description: B
+
+dn: ou=C, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: C
+ou;lang-de: C
+description: C
+
+dn: ou=D, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: D
+ou;lang-de: D
+description: D
+
+dn: ou=E, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: E
+ou;lang-de: E
+description: E
+
+dn: ou=F, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: F
+ou;lang-de: F
+description: F
+
+dn: ou=G, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: G
+ou;lang-de: G
+description: G
+
+dn: ou=H, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: H
+ou;lang-de: H
+description: H
+
+dn: ou=I, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: I
+ou;lang-de: I
+description: I
+
+dn: ou=J, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: J
+ou;lang-de: J
+description: J
+
+dn: ou=K, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: K
+ou;lang-de: K
+description: K
+
+dn: ou=L, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: L
+ou;lang-de: L
+description: L
+
+dn: ou=M, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: M
+ou;lang-de: M
+description: M
+
+dn: ou=N, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: N
+ou;lang-de: N
+description: N
+
+dn: ou=O, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: O
+ou;lang-de: O
+description: O
+
+dn: ou=P, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: P
+ou;lang-de: P
+description: P
+
+dn: ou=Q, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Q
+ou;lang-de: Q
+description: Q
+
+dn: ou=R, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: R
+ou;lang-de: R
+description: R
+
+dn: ou=S, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: S
+ou;lang-de: S
+description: S
+
+dn: ou=T, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: T
+ou;lang-de: T
+description: T
+
+dn: ou=U, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: U
+ou;lang-de: U
+description: U
+
+dn: ou=V, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: V
+ou;lang-de: V
+description: V
+
+dn: ou=W, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: W
+ou;lang-de: W
+description: W
+
+dn: ou=X, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: X
+ou;lang-de: X
+description: X
+
+dn: ou=Y, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Y
+ou;lang-de: Y
+description: Y
+
+dn: ou=Z, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Z
+ou;lang-de: Z
+description: Z
+
+dn: ou=A, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: A
+ou;lang-es: A
+description: A
+
+dn: ou=B, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: B
+ou;lang-es: B
+description: B
+
+dn: ou=C, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: C
+ou;lang-es: C
+description: C
+
+dn: ou=D, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: D
+ou;lang-es: D
+description: D
+
+dn: ou=E, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: E
+ou;lang-es: E
+description: E
+
+dn: ou=F, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: F
+ou;lang-es: F
+description: F
+
+dn: ou=G, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: G
+ou;lang-es: G
+description: G
+
+dn: ou=H, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: H
+ou;lang-es: H
+description: H
+
+dn: ou=I, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: I
+ou;lang-es: I
+description: I
+
+dn: ou=J, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: J
+ou;lang-es: J
+description: J
+
+dn: ou=K, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: K
+ou;lang-es: K
+description: K
+
+dn: ou=L, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: L
+ou;lang-es: L
+description: L
+
+dn: ou=M, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: M
+ou;lang-es: M
+description: M
+
+dn: ou=N, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: N
+ou;lang-es: N
+description: N
+
+dn: ou=O, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: O
+ou;lang-es: O
+description: O
+
+dn: ou=P, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: P
+ou;lang-es: P
+description: P
+
+dn: ou=Q, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Q
+ou;lang-es: Q
+description: Q
+
+dn: ou=R, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: R
+ou;lang-es: R
+description: R
+
+dn: ou=S, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: S
+ou;lang-es: S
+description: S
+
+dn: ou=T, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: T
+ou;lang-es: T
+description: T
+
+dn: ou=U, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: U
+ou;lang-es: U
+description: U
+
+dn: ou=V, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: V
+ou;lang-es: V
+description: V
+
+dn: ou=W, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: W
+ou;lang-es: W
+description: W
+
+dn: ou=X, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: X
+ou;lang-es: X
+description: X
+
+dn: ou=Y, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Y
+ou;lang-es: Y
+description: Y
+
+dn: ou=Z, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Z
+ou;lang-es: Z
+description: Z
+
+dn: ou=A, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: A
+ou;lang-fr: A
+description: A
+
+dn: ou=B, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: B
+ou;lang-fr: B
+description: B
+
+dn: ou=C, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: C
+ou;lang-fr: C
+description: C
+
+dn: ou=D, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: D
+ou;lang-fr: D
+description: D
+
+dn: ou=E, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: E
+ou;lang-fr: E
+description: E
+
+dn: ou=F, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: F
+ou;lang-fr: F
+description: F
+
+dn: ou=G, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: G
+ou;lang-fr: G
+description: G
+
+dn: ou=H, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: H
+ou;lang-fr: H
+description: H
+
+dn: ou=I, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: I
+ou;lang-fr: I
+description: I
+
+dn: ou=J, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: J
+ou;lang-fr: J
+description: J
+
+dn: ou=K, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: K
+ou;lang-fr: K
+description: K
+
+dn: ou=L, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: L
+ou;lang-fr: L
+description: L
+
+dn: ou=M, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: M
+ou;lang-fr: M
+description: M
+
+dn: ou=N, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: N
+ou;lang-fr: N
+description: N
+
+dn: ou=O, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: O
+ou;lang-fr: O
+description: O
+
+dn: ou=P, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: P
+ou;lang-fr: P
+description: P
+
+dn: ou=Q, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Q
+ou;lang-fr: Q
+description: Q
+
+dn: ou=R, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: R
+ou;lang-fr: R
+description: R
+
+dn: ou=S, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: S
+ou;lang-fr: S
+description: S
+
+dn: ou=T, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: T
+ou;lang-fr: T
+description: T
+
+dn: ou=U, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: U
+ou;lang-fr: U
+description: U
+
+dn: ou=V, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: V
+ou;lang-fr: V
+description: V
+
+dn: ou=W, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: W
+ou;lang-fr: W
+description: W
+
+dn: ou=X, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: X
+ou;lang-fr: X
+description: X
+
+dn: ou=Y, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Y
+ou;lang-fr: Y
+description: Y
+
+dn: ou=Z, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: organizationalUnit
+ou: Z
+ou;lang-fr: Z
+description: Z
+
+dn: uid=de1, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de1
+givenname;lang-de: ä
+sn;lang-de: ä
+cn;lang-de: ä ä
+preferredlanguage: de
+givenname: ä
+sn: ä
+cn: ä ä
+
+dn: uid=de2 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de2
+givenname;lang-de: ö
+sn;lang-de: ö
+cn;lang-de: ö ö
+preferredlanguage: de
+givenname: ö
+sn: ö
+cn: ö ö
+
+dn: uid=de3 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de3
+givenname;lang-de: ü
+sn;lang-de: ü
+cn;lang-de: ü ü
+preferredlanguage: de
+givenname: ü
+sn: ü
+cn: ü ü
+
+dn: uid=de4 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de4
+givenname;lang-de: ß
+sn;lang-de: ß
+cn;lang-de: ß ß
+preferredlanguage: de
+givenname: ß
+sn: ß
+cn: ß ß
+
+dn: uid=de5 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de5
+givenname;lang-de: Ä
+sn;lang-de: Ä
+cn;lang-de: Ä Ä
+preferredlanguage: de
+givenname: Ä
+sn: Ä
+cn: Ä Ä
+
+dn: uid=de6 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de6
+givenname;lang-de: Ö
+sn;lang-de: Ö
+cn;lang-de: Ö Ö
+preferredlanguage: de
+givenname: Ö
+sn: Ö
+cn: Ö Ö
+
+dn: uid=de7 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de7
+givenname;lang-de: Ü
+sn;lang-de: Ü
+cn;lang-de: Ü Ü
+preferredlanguage: de
+givenname: Ü
+sn: Ü
+cn: Ü Ü
+
+dn: uid=es1 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es1
+givenname;lang-es: á
+sn;lang-es: á
+cn;lang-es: á á
+preferredlanguage: es
+givenname: á
+sn: á
+cn: á á
+
+dn: uid=es2 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es2
+givenname;lang-es: é
+sn;lang-es: é
+cn;lang-es: é é
+preferredlanguage: es
+givenname: é
+sn: é
+cn: é é
+
+dn: uid=es3 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es3
+givenname;lang-es: í
+sn;lang-es: í
+cn;lang-es: í í
+preferredlanguage: es
+givenname: í
+sn: í
+cn: í í
+
+dn: uid=es4 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es4
+givenname;lang-es: ó
+sn;lang-es: ó
+cn;lang-es: ó ó
+preferredlanguage: es
+givenname: ó
+sn: ó
+cn: ó ó
+
+dn: uid=es5 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es5
+givenname;lang-es: ú
+sn;lang-es: ú
+cn;lang-es: ú ú
+preferredlanguage: es
+givenname: ú
+sn: ú
+cn: ú ú
+
+dn: uid=es6 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es6
+givenname;lang-es: ü
+sn;lang-es: ü
+cn;lang-es: ü ü
+preferredlanguage: es
+givenname: ü
+sn: ü
+cn: ü ü
+
+dn: uid=es7 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es7
+givenname;lang-es: Ã
+sn;lang-es: Ã
+cn;lang-es: Ã Ã
+preferredlanguage: es
+givenname: Ã
+sn: Ã
+cn: Ã Ã
+
+dn: uid=es8 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es8
+givenname;lang-es: É
+sn;lang-es: É
+cn;lang-es: É É
+preferredlanguage: es
+givenname: É
+sn: É
+cn: É É
+
+dn: uid=es9 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es9
+givenname;lang-es: Ã
+sn;lang-es: Ã
+cn;lang-es: Ã Ã
+preferredlanguage: es
+givenname: Ã
+sn: Ã
+cn: Ã Ã
+
+dn: uid=es10 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es10
+givenname;lang-es: Ó
+sn;lang-es: Ó
+cn;lang-es: Ó Ó
+preferredlanguage: es
+givenname: Ó
+sn: Ó
+cn: Ó Ó
+
+dn: uid=es11 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es11
+givenname;lang-es: Ú
+sn;lang-es: Ú
+cn;lang-es: Ú Ú
+preferredlanguage: es
+givenname: Ú
+sn: Ú
+cn: Ú Ú
+
+dn: uid=es12 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es12
+givenname;lang-es: Ü
+sn;lang-es: Ü
+cn;lang-es: Ü Ü
+preferredlanguage: es
+givenname: Ü
+sn: Ü
+cn: Ü Ü
+
+dn: uid=es13 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es13
+givenname;lang-es: Ñ
+sn;lang-es: Ñ
+cn;lang-es: Ñ Ñ
+preferredlanguage: es
+givenname: Ñ
+sn: Ñ
+cn: Ñ Ñ
+
+dn: uid=es14 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es14
+givenname;lang-es: ñ
+sn;lang-es: ñ
+cn;lang-es: ñ ñ
+preferredlanguage: es
+givenname: ñ
+sn: ñ
+cn: ñ ñ
+
+dn: uid=fr1, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: à à
+sn: à
+givenname: à
+cn;lang-fr: à à
+sn;lang-fr: à
+givenname;lang-fr: à
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr1
+
+dn: uid=fr2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: â â
+sn: â
+givenname: â
+cn;lang-fr: â â
+sn;lang-fr: â
+givenname;lang-fr: â
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr2
+
+dn: uid=fr3, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ç ç
+sn: ç
+givenname: ç
+cn;lang-fr: ç ç
+sn;lang-fr: ç
+givenname;lang-fr: ç
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr3
+
+dn: uid=fr4, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ë ë
+sn: ë
+givenname: ë
+cn;lang-fr: ë ë
+sn;lang-fr: ë
+givenname;lang-fr: ë
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr4
+
+dn: uid=fr5, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: è è
+sn: è
+givenname: è
+cn;lang-fr: è è
+sn;lang-fr: è
+givenname;lang-fr: è
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr5
+
+dn: uid=fr6, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: é é
+sn: é
+givenname: é
+cn;lang-fr: é é
+sn;lang-fr: é
+givenname;lang-fr: é
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr6
+
+dn: uid=fr7, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ê ê
+sn: ê
+givenname: ê
+cn;lang-fr: ê ê
+sn;lang-fr: ê
+givenname;lang-fr: ê
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr7
+
+dn: uid=fr8, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ï ï
+sn: ï
+givenname: ï
+cn;lang-fr: ï ï
+sn;lang-fr: ï
+givenname;lang-fr: ï
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr8
+
+dn: uid=fr9, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: î î
+sn: î
+givenname: î
+cn;lang-fr: î î
+sn;lang-fr: î
+givenname;lang-fr: î
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr9
+
+dn: uid=fr10, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ô ô
+sn: ô
+givenname: ô
+cn;lang-fr: ô ô
+sn;lang-fr: ô
+givenname;lang-fr: ô
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr10
+
+dn: uid=fr12, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ü ü
+sn: ü
+givenname: ü
+cn;lang-fr: ü ü
+sn;lang-fr: ü
+givenname;lang-fr: ü
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr12
+
+dn: uid=fr13, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ù ù
+sn: ù
+givenname: ù
+cn;lang-fr: ù ù
+sn;lang-fr: ù
+givenname;lang-fr: ù
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr13
+
+dn: uid=fr14, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: û û
+sn: û
+givenname: û
+cn;lang-fr: û û
+sn;lang-fr: û
+givenname;lang-fr: û
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr14
+
+dn: uid=fr15, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: À À
+sn: À
+givenname: À
+cn;lang-fr: À À
+sn;lang-fr: À
+givenname;lang-fr: À
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr15
+
+dn: uid=fr16, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Â Â
+sn: Â
+givenname: Â
+cn;lang-fr: Â Â
+sn;lang-fr: Â
+givenname;lang-fr: Â
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr16
+
+dn: uid=fr17, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ç Ç
+sn: Ç
+givenname: Ç
+cn;lang-fr: Ç Ç
+sn;lang-fr: Ç
+givenname;lang-fr: Ç
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr17
+
+dn: uid=fr18, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ë Ë
+sn: Ë
+givenname: Ë
+cn;lang-fr: Ë Ë
+sn;lang-fr: Ë
+givenname;lang-fr: Ë
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr18
+
+dn: uid=fr19, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: È È
+sn: È
+givenname: È
+cn;lang-fr: È È
+sn;lang-fr: È
+givenname;lang-fr: È
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr19
+
+dn: uid=fr20, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: É É
+sn: É
+givenname: É
+cn;lang-fr: É É
+sn;lang-fr: É
+givenname;lang-fr: É
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr20
+
+dn: uid=fr21, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ê Ê
+sn: Ê
+givenname: Ê
+cn;lang-fr: Ê Ê
+sn;lang-fr: Ê
+givenname;lang-fr: Ê
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr21
+
+dn: uid=fr22, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ã Ã
+sn: Ã
+givenname: Ã
+cn;lang-fr: Ã Ã
+sn;lang-fr: Ã
+givenname;lang-fr: Ã
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr22
+
+dn: uid=fr23, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ÃŽ ÃŽ
+sn: ÃŽ
+givenname: ÃŽ
+cn;lang-fr: ÃŽ ÃŽ
+sn;lang-fr: ÃŽ
+givenname;lang-fr: ÃŽ
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr23
+
+dn: uid=fr24, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ô Ô
+sn: Ô
+givenname: Ô
+cn;lang-fr: Ô Ô
+sn;lang-fr: Ô
+givenname;lang-fr: Ô
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr24
+
+dn: uid=fr26, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ü Ü
+sn: Ü
+givenname: Ü
+cn;lang-fr: Ü Ü
+sn;lang-fr: Ü
+givenname;lang-fr: Ü
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr26
+
+dn: uid=fr27, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ù Ù
+sn: Ù
+givenname: Ù
+cn;lang-fr: Ù Ù
+sn;lang-fr: Ù
+givenname;lang-fr: Ù
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr27
+
+dn: uid=fr28, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Û Û
+sn: Û
+givenname: Û
+cn;lang-fr: Û Û
+sn;lang-fr: Û
+givenname;lang-fr: Û
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+preferredlanguage: fr
+uid: fr28
+
+dn: uid=de100, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de100
+givenname;lang-de: a
+sn;lang-de: a
+cn;lang-de: a a
+preferredlanguage: de
+givenname: a
+sn: a
+cn: a a
+
+dn: uid=de101 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de101
+givenname;lang-de: b
+sn;lang-de: b
+cn;lang-de: b b
+preferredlanguage: de
+givenname: b
+sn: b
+cn: b b
+
+dn: uid=de102 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de102
+givenname;lang-de: c
+sn;lang-de: c
+cn;lang-de: c c
+preferredlanguage: de
+givenname: c
+sn: c
+cn: c c
+
+dn: uid=de103 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de103
+givenname;lang-de: d
+sn;lang-de: d
+cn;lang-de: d d
+preferredlanguage: de
+givenname: d
+sn: d
+cn: d d
+
+dn: uid=de104, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de104
+givenname;lang-de: e
+sn;lang-de: e
+cn;lang-de: e e
+preferredlanguage: de
+givenname: e
+sn: e
+cn: e e
+
+dn: uid=de105, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de105
+givenname;lang-de: f
+sn;lang-de: f
+cn;lang-de: f f
+preferredlanguage: de
+givenname: f
+sn: f
+cn: f f
+
+dn: uid=de106, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de106
+givenname;lang-de: g
+sn;lang-de: g
+cn;lang-de: g g
+preferredlanguage: de
+givenname: g
+sn: g
+cn: g g
+
+dn: uid=de107, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de107
+givenname;lang-de: h
+sn;lang-de: h
+cn;lang-de: h h
+preferredlanguage: de
+givenname: h
+sn: h
+cn: h h
+
+dn: uid=de108, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de108
+givenname;lang-de: i
+sn;lang-de: i
+cn;lang-de: i i
+preferredlanguage: de
+givenname: i
+sn: i
+cn: i i
+
+dn: uid=de109 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de109
+givenname;lang-de: j
+sn;lang-de: j
+cn;lang-de: j j
+preferredlanguage: de
+givenname: j
+sn: j
+cn: j j
+
+dn: uid=de110 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de110
+givenname;lang-de: k
+sn;lang-de: k
+cn;lang-de: k k
+preferredlanguage: de
+givenname: k
+sn: k
+cn: k k
+
+dn: uid=de111 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de111
+givenname;lang-de: l
+sn;lang-de: l
+cn;lang-de: l l
+preferredlanguage: de
+givenname: l
+sn: l
+cn: l l
+
+dn: uid=de112, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de112
+givenname;lang-de: m
+sn;lang-de: m
+cn;lang-de: m m
+preferredlanguage: de
+givenname: m
+sn: m
+cn: m m
+
+dn: uid=de113 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de113
+givenname;lang-de: n
+sn;lang-de: n
+cn;lang-de: n n
+preferredlanguage: de
+givenname: n
+sn: n
+cn: n n
+
+dn: uid=de114 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de114
+givenname;lang-de: o
+sn;lang-de: o
+cn;lang-de: o o
+preferredlanguage: de
+givenname: o
+sn: o
+cn: o o
+
+dn: uid=de115, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de115
+givenname;lang-de: p
+sn;lang-de: p
+cn;lang-de: p p
+preferredlanguage: de
+givenname: p
+sn: p
+cn: p p
+
+dn: uid=de116 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de116
+givenname;lang-de: q
+sn;lang-de: q
+cn;lang-de: q q
+preferredlanguage: de
+givenname: q
+sn: q
+cn: q q
+
+dn: uid=de117, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de117
+givenname;lang-de: r
+sn;lang-de: r
+cn;lang-de: r r
+preferredlanguage: de
+givenname: r
+sn: r
+cn: r r
+
+dn: uid=de118 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de118
+givenname;lang-de: s
+sn;lang-de: s
+cn;lang-de: s s
+preferredlanguage: de
+givenname: s
+sn: s
+cn: s s
+
+dn: uid=de119 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de119
+givenname;lang-de: t
+sn;lang-de: t
+cn;lang-de: t t
+preferredlanguage: de
+givenname: t
+sn: t
+cn: t t
+
+dn: uid=de120 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de120
+givenname;lang-de: u
+sn;lang-de: u
+cn;lang-de: u u
+preferredlanguage: de
+givenname: u
+sn: u
+cn: u u
+
+dn: uid=de121, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de121
+givenname;lang-de: v
+sn;lang-de: v
+cn;lang-de: v v
+preferredlanguage: de
+givenname: v
+sn: v
+cn: v v
+
+dn: uid=de122 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de122
+givenname;lang-de: w
+sn;lang-de: w
+cn;lang-de: w w
+preferredlanguage: de
+givenname: w
+sn: w
+cn: w w
+
+dn: uid=de123 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de123
+givenname;lang-de: x
+sn;lang-de: x
+cn;lang-de: x x
+preferredlanguage: de
+givenname: x
+sn: x
+cn: x x
+
+dn: uid=de124, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de124
+givenname;lang-de: y
+sn;lang-de: y
+cn;lang-de: y y
+preferredlanguage: de
+givenname: y
+sn: y
+cn: y y
+
+dn: uid=de125, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de125
+givenname;lang-de: z
+sn;lang-de: z
+cn;lang-de: z z
+preferredlanguage: de
+givenname: z
+sn: z
+cn: z z
+
+dn: uid=de126, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de126
+givenname;lang-de: A
+sn;lang-de: A
+cn;lang-de: A A
+preferredlanguage: de
+givenname: A
+sn: A
+cn: A A
+
+dn: uid=de127, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de127
+givenname;lang-de: B
+sn;lang-de: B
+cn;lang-de: B B
+preferredlanguage: de
+givenname: B
+sn: B
+cn: B B
+
+dn: uid=de128, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de128
+givenname;lang-de: C
+sn;lang-de: C
+cn;lang-de: C C
+preferredlanguage: de
+givenname: C
+sn: C
+cn: C C
+
+dn: uid=de129 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de129
+givenname;lang-de: D
+sn;lang-de: D
+cn;lang-de: D D
+preferredlanguage: de
+givenname: D
+sn: D
+cn: D D
+
+dn: uid=de130 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de130
+givenname;lang-de: E
+sn;lang-de: E
+cn;lang-de: E E
+preferredlanguage: de
+givenname: E
+sn: E
+cn: E E
+
+dn: uid=de131 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de131
+givenname;lang-de: F
+sn;lang-de: F
+cn;lang-de: F F
+preferredlanguage: de
+givenname: F F
+sn: F
+cn: F F
+
+dn: uid=de132, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de132
+givenname;lang-de: G
+sn;lang-de: G
+cn;lang-de: G G
+preferredlanguage: de
+givenname: G
+sn: G
+cn: G G
+
+dn: uid=de133 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de133
+givenname;lang-de: H
+sn;lang-de: H
+cn;lang-de: H H
+preferredlanguage: de
+givenname: H
+sn: H
+cn: H H
+
+dn: uid=de134 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de134
+givenname;lang-de: I
+sn;lang-de: I
+cn;lang-de: I I
+preferredlanguage: de
+givenname: I
+sn: I
+cn: I I
+
+dn: uid=de135, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de135
+givenname;lang-de: J
+sn;lang-de: J
+cn;lang-de: J J
+preferredlanguage: de
+givenname: J
+sn: J
+cn: J J
+
+dn: uid=de136 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de136
+givenname;lang-de: K
+sn;lang-de: K
+cn;lang-de: K K
+preferredlanguage: de
+givenname: K
+sn: K
+cn: K K
+
+dn: uid=de137, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de137
+givenname;lang-de: L
+sn;lang-de: L
+cn;lang-de: L L
+preferredlanguage: de
+givenname: L
+sn: L
+cn: L L
+
+dn: uid=de138 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de138
+givenname;lang-de: M
+sn;lang-de: M
+cn;lang-de: M M
+preferredlanguage: de
+givenname: M
+sn: M
+cn: M M
+
+dn: uid=de139 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de139
+givenname;lang-de: N
+sn;lang-de: N
+cn;lang-de: N N
+preferredlanguage: de
+givenname: N
+sn: N
+cn: N N
+
+dn: uid=de140 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de140
+givenname;lang-de: O
+sn;lang-de: O
+cn;lang-de: O O
+preferredlanguage: de
+givenname: O
+sn: O
+cn: O O
+
+dn: uid=de141 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de141
+givenname;lang-de: P
+sn;lang-de: P
+cn;lang-de: P P
+preferredlanguage: de
+givenname: P
+sn: P
+cn: P P
+
+dn: uid=de142, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de142
+givenname;lang-de: Q
+sn;lang-de: Q
+cn;lang-de: Q Q
+preferredlanguage: de
+givenname: Q
+sn: Q
+cn: Q Q
+
+dn: uid=de143 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de143
+givenname;lang-de: R
+sn;lang-de: R
+cn;lang-de: R R
+preferredlanguage: de
+givenname: R
+sn: R
+cn: R R
+
+dn: uid=de144 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de144
+givenname;lang-de: S
+sn;lang-de: S
+cn;lang-de: S S
+preferredlanguage: de
+givenname: S
+sn: S
+cn: S S
+
+dn: uid=de145, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de145
+givenname;lang-de: T
+sn;lang-de: T
+cn;lang-de: T T
+preferredlanguage: de
+givenname: T
+sn: T
+cn: T T
+
+dn: uid=de146 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de146
+givenname;lang-de: U
+sn;lang-de: U
+cn;lang-de: U U
+preferredlanguage: de
+givenname: U
+sn: U
+cn: U U
+
+dn: uid=de147, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de147
+givenname;lang-de: V
+sn;lang-de: V
+cn;lang-de: V V
+preferredlanguage: de
+givenname: V
+sn: V
+cn: V V
+
+dn: uid=de148 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de148
+givenname;lang-de: W
+sn;lang-de: W
+cn;lang-de: W W
+preferredlanguage: de
+givenname: W
+sn: W
+cn: W W
+
+dn: uid=de149 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de149
+givenname;lang-de: X
+sn;lang-de: X
+cn;lang-de: X X
+preferredlanguage: de
+givenname: X
+sn: X
+cn: X X
+
+dn: uid=de150 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de150
+givenname;lang-de: Y
+sn;lang-de: Y
+cn;lang-de: Y Y
+preferredlanguage: de
+givenname: Y
+sn: Y
+cn: Y Y
+
+dn: uid=de151 , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: de151
+givenname;lang-de: Z
+sn;lang-de: Z
+cn;lang-de: Z Z
+preferredlanguage: de
+givenname: Z
+sn: Z
+cn: Z Z
+
+dn: uid=es100, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es100
+givenname;lang-es: a
+sn;lang-es: a
+cn;lang-es: a a
+preferredlanguage: es
+givenname: a
+sn: a
+cn: a a
+
+dn: uid=es101 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es101
+givenname;lang-es: b
+sn;lang-es: b
+cn;lang-es: b b
+preferredlanguage: es
+givenname: b
+sn: b
+cn: b b
+
+dn: uid=es102 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es102
+givenname;lang-es: c
+sn;lang-es: c
+cn;lang-es: c c
+preferredlanguage: es
+givenname: c
+sn: c
+cn: c c
+
+dn: uid=es103 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es103
+givenname;lang-es: d
+sn;lang-es: d
+cn;lang-es: d d
+preferredlanguage: es
+givenname: d
+sn: d
+cn: d d
+
+dn: uid=es104, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es104
+givenname;lang-es: e
+sn;lang-es: e
+cn;lang-es: e e
+preferredlanguage: es
+givenname: e
+sn: e
+cn: e e
+
+dn: uid=es105, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es105
+givenname;lang-es: f
+sn;lang-es: f
+cn;lang-es: f f
+preferredlanguage: es
+givenname: f
+sn: f
+cn: f f
+
+dn: uid=es106, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es106
+givenname;lang-es: g
+sn;lang-es: g
+cn;lang-es: g g
+preferredlanguage: es
+givenname: g
+sn: g
+cn: g g
+
+dn: uid=es107, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es107
+givenname;lang-es: h
+sn;lang-es: h
+cn;lang-es: h h
+preferredlanguage: es
+givenname: h
+sn: h
+cn: h h
+
+dn: uid=es108, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es108
+givenname;lang-es: i
+sn;lang-es: i
+cn;lang-es: i i
+preferredlanguage: es
+givenname: i
+sn: i
+cn: i i
+
+dn: uid=es109 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es109
+givenname;lang-es: j
+sn;lang-es: j
+cn;lang-es: j j
+preferredlanguage: es
+givenname: j
+sn: j
+cn: j j
+
+dn: uid=es110 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es110
+givenname;lang-es: k
+sn;lang-es: k
+cn;lang-es: k k
+preferredlanguage: es
+givenname: k
+sn: k
+cn: k k
+
+dn: uid=es111 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es111
+givenname;lang-es: l
+sn;lang-es: l
+cn;lang-es: l l
+preferredlanguage: es
+givenname: l
+sn: l
+cn: l l
+
+dn: uid=es112, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es112
+givenname;lang-es: m
+sn;lang-es: m
+cn;lang-es: m m
+preferredlanguage: es
+givenname: m
+sn: m
+cn: m m
+
+dn: uid=es113 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es113
+givenname;lang-es: n
+sn;lang-es: n
+cn;lang-es: n n
+preferredlanguage: es
+givenname: n
+sn: n
+cn: n n
+
+dn: uid=es114 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es114
+givenname;lang-es: o
+sn;lang-es: o
+cn;lang-es: o o
+preferredlanguage: es
+givenname: o
+sn: o
+cn: o o
+
+dn: uid=es115, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es115
+givenname;lang-es: p
+sn;lang-es: p
+cn;lang-es: p p
+preferredlanguage: es
+givenname: p
+sn: p
+cn: p p
+
+dn: uid=es116 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es116
+givenname;lang-es: q
+sn;lang-es: q
+cn;lang-es: q q
+preferredlanguage: es
+givenname: q
+sn: q
+cn: q q
+
+dn: uid=es117, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es117
+givenname;lang-es: r
+sn;lang-es: r
+cn;lang-es: r r
+preferredlanguage: es
+givenname: r
+sn: r
+cn: r r
+
+dn: uid=es118 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es118
+givenname;lang-es: s
+sn;lang-es: s
+cn;lang-es: s s
+preferredlanguage: es
+givenname: s
+sn: s
+cn: s s
+
+dn: uid=es119 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es119
+givenname;lang-es: t
+sn;lang-es: t
+cn;lang-es: t t
+preferredlanguage: es
+givenname: t
+sn: t
+cn: t t
+
+dn: uid=es120 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es120
+givenname;lang-es: u
+sn;lang-es: u
+cn;lang-es: u u
+preferredlanguage: es
+givenname: u
+sn: u
+cn: u u
+
+dn: uid=es121, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es121
+givenname;lang-es: v
+sn;lang-es: v
+cn;lang-es: v v
+preferredlanguage: es
+givenname: v
+sn: v
+cn: v v
+
+dn: uid=es122 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es122
+givenname;lang-es: w
+sn;lang-es: w
+cn;lang-es: w w
+preferredlanguage: es
+givenname: w
+sn: w
+cn: w w
+
+dn: uid=es123 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es123
+givenname;lang-es: x
+sn;lang-es: x
+cn;lang-es: x x
+preferredlanguage: es
+givenname: x
+sn: x
+cn: x x
+
+dn: uid=es124, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es124
+givenname;lang-es: y
+sn;lang-es: y
+cn;lang-es: y y
+preferredlanguage: es
+givenname: y
+sn: y
+cn: y y
+
+dn: uid=es125, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es125
+givenname;lang-es: z
+sn;lang-es: z
+cn;lang-es: z z
+preferredlanguage: es
+givenname: z
+sn: z
+cn: z z
+
+dn: uid=es126, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es126
+givenname;lang-es: A
+sn;lang-es: A
+cn;lang-es: A A
+preferredlanguage: es
+givenname: A
+sn: A
+cn: A A
+
+dn: uid=es127, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es127
+givenname;lang-es: B
+sn;lang-es: B
+cn;lang-es: B B
+preferredlanguage: es
+givenname: B
+sn: B
+cn: B B
+
+dn: uid=es128, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es128
+givenname;lang-es: C
+sn;lang-es: C
+cn;lang-es: C C
+preferredlanguage: es
+givenname: C
+sn: C
+cn: C C
+
+dn: uid=es129 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es129
+givenname;lang-es: D
+sn;lang-es: D
+cn;lang-es: D D
+preferredlanguage: es
+givenname: D
+sn: D
+cn: D D
+
+dn: uid=es130 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es130
+givenname;lang-es: E
+sn;lang-es: E
+cn;lang-es: E E
+preferredlanguage: es
+givenname: E
+sn: E
+cn: E E
+
+dn: uid=es131 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es131
+givenname;lang-es: F
+sn;lang-es: F
+cn;lang-es: F F
+preferredlanguage: es
+givenname: F F
+sn: F
+cn: F F
+
+dn: uid=es132, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es132
+givenname;lang-es: G
+sn;lang-es: G
+cn;lang-es: G G
+preferredlanguage: es
+givenname: G
+sn: G
+cn: G G
+
+dn: uid=es133 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es133
+givenname;lang-es: H
+sn;lang-es: H
+cn;lang-es: H H
+preferredlanguage: es
+givenname: H
+sn: H
+cn: H H
+
+dn: uid=es134 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es134
+givenname;lang-es: I
+sn;lang-es: I
+cn;lang-es: I I
+preferredlanguage: es
+givenname: I
+sn: I
+cn: I I
+
+dn: uid=es135, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es135
+givenname;lang-es: J
+sn;lang-es: J
+cn;lang-es: J J
+preferredlanguage: es
+givenname: J
+sn: J
+cn: J J
+
+dn: uid=es136 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es136
+givenname;lang-es: K
+sn;lang-es: K
+cn;lang-es: K K
+preferredlanguage: es
+givenname: K
+sn: K
+cn: K K
+
+dn: uid=es137, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es137
+givenname;lang-es: L
+sn;lang-es: L
+cn;lang-es: L L
+preferredlanguage: es
+givenname: L
+sn: L
+cn: L L
+
+dn: uid=es138 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es138
+givenname;lang-es: M
+sn;lang-es: M
+cn;lang-es: M M
+preferredlanguage: es
+givenname: M
+sn: M
+cn: M M
+
+dn: uid=es139 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es139
+givenname;lang-es: N
+sn;lang-es: N
+cn;lang-es: N N
+preferredlanguage: es
+givenname: N
+sn: N
+cn: N N
+
+dn: uid=es140 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es140
+givenname;lang-es: O
+sn;lang-es: O
+cn;lang-es: O O
+preferredlanguage: es
+givenname: O
+sn: O
+cn: O O
+
+dn: uid=es141 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es141
+givenname;lang-es: P
+sn;lang-es: P
+cn;lang-es: P P
+preferredlanguage: es
+givenname: P
+sn: P
+cn: P P
+
+dn: uid=es142, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es142
+givenname;lang-es: Q
+sn;lang-es: Q
+cn;lang-es: Q Q
+preferredlanguage: es
+givenname: Q
+sn: Q
+cn: Q Q
+
+dn: uid=es143 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es143
+givenname;lang-es: R
+sn;lang-es: R
+cn;lang-es: R R
+preferredlanguage: es
+givenname: R
+sn: R
+cn: R R
+
+dn: uid=es144 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es144
+givenname;lang-es: S
+sn;lang-es: S
+cn;lang-es: S S
+preferredlanguage: es
+givenname: S
+sn: S
+cn: S S
+
+dn: uid=es145, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es145
+givenname;lang-es: T
+sn;lang-es: T
+cn;lang-es: T T
+preferredlanguage: es
+givenname: T
+sn: T
+cn: T T
+
+dn: uid=es146 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es146
+givenname;lang-es: U
+sn;lang-es: U
+cn;lang-es: U U
+preferredlanguage: es
+givenname: U
+sn: U
+cn: U U
+
+dn: uid=es147, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es147
+givenname;lang-es: V
+sn;lang-es: V
+cn;lang-es: V V
+preferredlanguage: es
+givenname: V
+sn: V
+cn: V V
+
+dn: uid=es148 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es148
+givenname;lang-es: W
+sn;lang-es: W
+cn;lang-es: W W
+preferredlanguage: es
+givenname: W
+sn: W
+cn: W W
+
+dn: uid=es149 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es149
+givenname;lang-es: X
+sn;lang-es: X
+cn;lang-es: X X
+preferredlanguage: es
+givenname: X
+sn: X
+cn: X X
+
+dn: uid=es150 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es150
+givenname;lang-es: Y
+sn;lang-es: Y
+cn;lang-es: Y Y
+preferredlanguage: es
+givenname: Y
+sn: Y
+cn: Y Y
+
+dn: uid=es151 , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: es151
+givenname;lang-es: Z
+sn;lang-es: Z
+cn;lang-es: Z Z
+preferredlanguage: es
+givenname: Z
+sn: Z
+cn: Z Z
+
+dn: uid=fr100, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr100
+givenname;lang-fr: a
+sn;lang-fr: a
+cn;lang-fr: a a
+preferredlanguage: fr
+givenname: a
+sn: a
+cn: a a
+
+dn: uid=fr101 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr101
+givenname;lang-fr: b
+sn;lang-fr: b
+cn;lang-fr: b b
+preferredlanguage: fr
+givenname: b
+sn: b
+cn: b b
+
+dn: uid=fr102 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr102
+givenname;lang-fr: c
+sn;lang-fr: c
+cn;lang-fr: c c
+preferredlanguage: fr
+givenname: c
+sn: c
+cn: c c
+
+dn: uid=fr103 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr103
+givenname;lang-fr: d
+sn;lang-fr: d
+cn;lang-fr: d d
+preferredlanguage: fr
+givenname: d
+sn: d
+cn: d d
+
+dn: uid=fr104, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr104
+givenname;lang-fr: e
+sn;lang-fr: e
+cn;lang-fr: e e
+preferredlanguage: fr
+givenname: e
+sn: e
+cn: e e
+
+dn: uid=fr105, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr105
+givenname;lang-fr: f
+sn;lang-fr: f
+cn;lang-fr: f f
+preferredlanguage: fr
+givenname: f
+sn: f
+cn: f f
+
+dn: uid=fr106, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr106
+givenname;lang-fr: g
+sn;lang-fr: g
+cn;lang-fr: g g
+preferredlanguage: fr
+givenname: g
+sn: g
+cn: g g
+
+dn: uid=fr107, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr107
+givenname;lang-fr: h
+sn;lang-fr: h
+cn;lang-fr: h h
+preferredlanguage: fr
+givenname: h
+sn: h
+cn: h h
+
+dn: uid=fr108, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr108
+givenname;lang-fr: i
+sn;lang-fr: i
+cn;lang-fr: i i
+preferredlanguage: fr
+givenname: i
+sn: i
+cn: i i
+
+dn: uid=fr109 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr109
+givenname;lang-fr: j
+sn;lang-fr: j
+cn;lang-fr: j j
+preferredlanguage: fr
+givenname: j
+sn: j
+cn: j j
+
+dn: uid=fr110 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr110
+givenname;lang-fr: k
+sn;lang-fr: k
+cn;lang-fr: k k
+preferredlanguage: fr
+givenname: k
+sn: k
+cn: k k
+
+dn: uid=fr111 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr111
+givenname;lang-fr: l
+sn;lang-fr: l
+cn;lang-fr: l l
+preferredlanguage: fr
+givenname: l
+sn: l
+cn: l l
+
+dn: uid=fr112, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr112
+givenname;lang-fr: m
+sn;lang-fr: m
+cn;lang-fr: m m
+preferredlanguage: fr
+givenname: m
+sn: m
+cn: m m
+
+dn: uid=fr113 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr113
+givenname;lang-fr: n
+sn;lang-fr: n
+cn;lang-fr: n n
+preferredlanguage: fr
+givenname: n
+sn: n
+cn: n n
+
+dn: uid=fr114 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr114
+givenname;lang-fr: o
+sn;lang-fr: o
+cn;lang-fr: o o
+preferredlanguage: fr
+givenname: o
+sn: o
+cn: o o
+
+dn: uid=fr115, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr115
+givenname;lang-fr: p
+sn;lang-fr: p
+cn;lang-fr: p p
+preferredlanguage: fr
+givenname: p
+sn: p
+cn: p p
+
+dn: uid=fr116 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr116
+givenname;lang-fr: q
+sn;lang-fr: q
+cn;lang-fr: q q
+preferredlanguage: fr
+givenname: q
+sn: q
+cn: q q
+
+dn: uid=fr117, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr117
+givenname;lang-fr: r
+sn;lang-fr: r
+cn;lang-fr: r r
+preferredlanguage: fr
+givenname: r
+sn: r
+cn: r r
+
+dn: uid=fr118 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr118
+givenname;lang-fr: s
+sn;lang-fr: s
+cn;lang-fr: s s
+preferredlanguage: fr
+givenname: s
+sn: s
+cn: s s
+
+dn: uid=fr119 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr119
+givenname;lang-fr: t
+sn;lang-fr: t
+cn;lang-fr: t t
+preferredlanguage: fr
+givenname: t
+sn: t
+cn: t t
+
+dn: uid=fr120 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr120
+givenname;lang-fr: u
+sn;lang-fr: u
+cn;lang-fr: u u
+preferredlanguage: fr
+givenname: u
+sn: u
+cn: u u
+
+dn: uid=fr121, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr121
+givenname;lang-fr: v
+sn;lang-fr: v
+cn;lang-fr: v v
+preferredlanguage: fr
+givenname: v
+sn: v
+cn: v v
+
+dn: uid=fr122 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr122
+givenname;lang-fr: w
+sn;lang-fr: w
+cn;lang-fr: w w
+preferredlanguage: fr
+givenname: w
+sn: w
+cn: w w
+
+dn: uid=fr123 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr123
+givenname;lang-fr: x
+sn;lang-fr: x
+cn;lang-fr: x x
+preferredlanguage: fr
+givenname: x
+sn: x
+cn: x x
+
+dn: uid=fr124, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr124
+givenname;lang-fr: y
+sn;lang-fr: y
+cn;lang-fr: y y
+preferredlanguage: fr
+givenname: y
+sn: y
+cn: y y
+
+dn: uid=fr125, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr125
+givenname;lang-fr: z
+sn;lang-fr: z
+cn;lang-fr: z z
+preferredlanguage: fr
+givenname: z
+sn: z
+cn: z z
+
+dn: uid=fr126, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr126
+givenname;lang-fr: A
+sn;lang-fr: A
+cn;lang-fr: A A
+preferredlanguage: fr
+givenname: A
+sn: A
+cn: A A
+
+dn: uid=fr127, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr127
+givenname;lang-fr: B
+sn;lang-fr: B
+cn;lang-fr: B B
+preferredlanguage: fr
+givenname: B
+sn: B
+cn: B B
+
+dn: uid=fr128, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr128
+givenname;lang-fr: C
+sn;lang-fr: C
+cn;lang-fr: C C
+preferredlanguage: fr
+givenname: C
+sn: C
+cn: C C
+
+dn: uid=fr129 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr129
+givenname;lang-fr: D
+sn;lang-fr: D
+cn;lang-fr: D D
+preferredlanguage: fr
+givenname: D
+sn: D
+cn: D D
+
+dn: uid=fr130 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr130
+givenname;lang-fr: E
+sn;lang-fr: E
+cn;lang-fr: E E
+preferredlanguage: fr
+givenname: E
+sn: E
+cn: E E
+
+dn: uid=fr131 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr131
+givenname;lang-fr: F
+sn;lang-fr: F
+cn;lang-fr: F F
+preferredlanguage: fr
+givenname: F F
+sn: F
+cn: F F
+
+dn: uid=fr132, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr132
+givenname;lang-fr: G
+sn;lang-fr: G
+cn;lang-fr: G G
+preferredlanguage: fr
+givenname: G
+sn: G
+cn: G G
+
+dn: uid=fr133 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr133
+givenname;lang-fr: H
+sn;lang-fr: H
+cn;lang-fr: H H
+preferredlanguage: fr
+givenname: H
+sn: H
+cn: H H
+
+dn: uid=fr134 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr134
+givenname;lang-fr: I
+sn;lang-fr: I
+cn;lang-fr: I I
+preferredlanguage: fr
+givenname: I
+sn: I
+cn: I I
+
+dn: uid=fr135, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr135
+givenname;lang-fr: J
+sn;lang-fr: J
+cn;lang-fr: J J
+preferredlanguage: fr
+givenname: J
+sn: J
+cn: J J
+
+dn: uid=fr136 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr136
+givenname;lang-fr: K
+sn;lang-fr: K
+cn;lang-fr: K K
+preferredlanguage: fr
+givenname: K
+sn: K
+cn: K K
+
+dn: uid=fr137, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr137
+givenname;lang-fr: L
+sn;lang-fr: L
+cn;lang-fr: L L
+preferredlanguage: fr
+givenname: L
+sn: L
+cn: L L
+
+dn: uid=fr138 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr138
+givenname;lang-fr: M
+sn;lang-fr: M
+cn;lang-fr: M M
+preferredlanguage: fr
+givenname: M
+sn: M
+cn: M M
+
+dn: uid=fr139 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr139
+givenname;lang-fr: N
+sn;lang-fr: N
+cn;lang-fr: N N
+preferredlanguage: fr
+givenname: N
+sn: N
+cn: N N
+
+dn: uid=fr140 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr140
+givenname;lang-fr: O
+sn;lang-fr: O
+cn;lang-fr: O O
+preferredlanguage: fr
+givenname: O
+sn: O
+cn: O O
+
+dn: uid=fr141 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr141
+givenname;lang-fr: P
+sn;lang-fr: P
+cn;lang-fr: P P
+preferredlanguage: fr
+givenname: P
+sn: P
+cn: P P
+
+dn: uid=fr142, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr142
+givenname;lang-fr: Q
+sn;lang-fr: Q
+cn;lang-fr: Q Q
+preferredlanguage: fr
+givenname: Q
+sn: Q
+cn: Q Q
+
+dn: uid=fr143 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr143
+givenname;lang-fr: R
+sn;lang-fr: R
+cn;lang-fr: R R
+preferredlanguage: fr
+givenname: R
+sn: R
+cn: R R
+
+dn: uid=fr144 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr144
+givenname;lang-fr: S
+sn;lang-fr: S
+cn;lang-fr: S S
+preferredlanguage: fr
+givenname: S
+sn: S
+cn: S S
+
+dn: uid=fr145, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr145
+givenname;lang-fr: T
+sn;lang-fr: T
+cn;lang-fr: T T
+preferredlanguage: fr
+givenname: T
+sn: T
+cn: T T
+
+dn: uid=fr146 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr146
+givenname;lang-fr: U
+sn;lang-fr: U
+cn;lang-fr: U U
+preferredlanguage: fr
+givenname: U
+sn: U
+cn: U U
+
+dn: uid=fr147, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr147
+givenname;lang-fr: V
+sn;lang-fr: V
+cn;lang-fr: V V
+preferredlanguage: fr
+givenname: V
+sn: V
+cn: V V
+
+dn: uid=fr148 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr148
+givenname;lang-fr: W
+sn;lang-fr: W
+cn;lang-fr: W W
+preferredlanguage: fr
+givenname: W
+sn: W
+cn: W W
+
+dn: uid=fr149 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr149
+givenname;lang-fr: X
+sn;lang-fr: X
+cn;lang-fr: X X
+preferredlanguage: fr
+givenname: X
+sn: X
+cn: X X
+
+dn: uid=fr150 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr150
+givenname;lang-fr: Y
+sn;lang-fr: Y
+cn;lang-fr: Y Y
+preferredlanguage: fr
+givenname: Y
+sn: Y
+cn: Y Y
+
+dn: uid=fr151 , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+uid: fr151
+givenname;lang-fr: Z
+sn;lang-fr: Z
+cn;lang-fr: Z Z
+preferredlanguage: fr
+givenname: Z
+sn: Z
+cn: Z Z
+
+dn: cn=à , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: à
+cn;lang-fr: à
+cn;lang-en: à
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr1, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=fr10, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=de7, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=de4, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es4, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es6, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=â, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: â
+cn;lang-fr: â
+cn;lang-en: â
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ç
+cn;lang-fr: ç
+cn;lang-en: ç
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr3, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=ë, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ë
+cn;lang-fr: ë
+cn;lang-en: ë
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr4, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=è, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: è
+cn;lang-fr: è
+cn;lang-en: è
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr5, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=é, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: é
+cn;lang-fr: é
+cn;lang-en: é
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr6, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=ê, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ê
+cn;lang-fr: ê
+cn;lang-en: ê
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr7, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=ï, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ï
+cn;lang-fr: ï
+cn;lang-en: ï
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=î, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: î
+cn;lang-fr: î
+cn;lang-en: î
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=ô, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ô
+cn;lang-fr: ô
+cn;lang-en: ô
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=ü, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ü
+cn;lang-fr: ü
+cn;lang-en: ü
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=ù, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ù
+cn;lang-fr: ù
+cn;lang-en: ù
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=û, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: û
+cn;lang-fr: û
+cn;lang-en: û
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=À-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: À-2
+cn;lang-fr: À-2
+cn;lang-en: À-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Â-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Â-2
+cn;lang-fr: Â-2
+cn;lang-en: Â-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Ç-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ç-2
+cn;lang-fr: Ç-2
+cn;lang-en: Ç-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Ë-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ë-2
+cn;lang-fr: Ë-2
+cn;lang-en: Ë-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=È-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: È-2
+cn;lang-fr: È-2
+cn;lang-en: È-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=É-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: É-2
+cn;lang-fr: É-2
+cn;lang-en: É-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Ê-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ê-2
+cn;lang-fr: Ê-2
+cn;lang-en: Ê-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Ã-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ã-2
+cn;lang-fr: Ã-2
+cn;lang-en: Ã-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Î-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: ÃŽ-2
+cn;lang-fr: ÃŽ-2
+cn;lang-en: ÃŽ-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Ô-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ô-2
+cn;lang-fr: Ô-2
+cn;lang-en: Ô-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Ü-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ü-2
+cn;lang-fr: Ü-2
+cn;lang-en: Ü-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Ù-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Ù-2
+cn;lang-fr: Ù-2
+cn;lang-en: Ù-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Û-2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Û-2
+cn;lang-fr: Û-2
+cn;lang-en: Û-2
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=ä, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: ä
+cn;lang-de: ä
+cn: ä
+
+dn: cn=ö, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: ö
+cn;lang-de: ö
+cn: ö
+
+dn: cn=ü, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: ü
+cn;lang-de: ü
+cn: ü
+
+dn: cn=ß , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: ß
+cn;lang-de: ß
+cn: ß
+
+dn: cn=Ä-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: Ä-2
+cn;lang-de: Ä-2
+cn: Ä-2
+
+dn: cn=Ö-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: Ö-2
+cn;lang-de: Ö-2
+cn: Ö-2
+
+dn: cn=Ü-2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: Ü-2
+cn;lang-de: Ü-2
+cn: Ü-2
+
+dn: cn=á, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: á
+cn;lang-es: á
+cn: á
+
+dn: cn=é, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: é
+cn;lang-es: é
+cn: é
+
+dn: cn=í, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: í
+cn;lang-es: í
+cn: í
+
+dn: cn=ó, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: ó
+cn;lang-es: ó
+cn: ó
+
+dn: cn=ú , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: ú
+cn;lang-es: ú
+cn: ú
+
+dn: cn=ü, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: ü
+cn;lang-es: ü
+cn: ü
+
+dn: cn=Ã-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: Ã-2
+cn;lang-es: Ã-2
+cn: Ã-2
+
+dn: cn=É-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: É-2
+cn;lang-es: É-2
+cn: É-2
+
+dn: cn=Ã-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: Ã-2
+cn;lang-es: Ã-2
+cn: Ã-2
+
+dn: cn=Ó-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: Ó-2
+cn;lang-es: Ó-2
+cn: Ó-2
+
+dn: cn=Ú-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: Ú-2
+cn;lang-es: Ú-2
+cn: Ú-2
+
+dn: cn=Ü-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: Ü-2
+cn;lang-es: Ü-2
+cn: Ü-2
+
+dn: cn=Ñ-2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: Ñ-2
+cn;lang-es: Ñ-2
+cn: Ñ-2
+
+dn: cn=ñ, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+objectclass: top
+objectclass: groupOfUniqueNames
+cn;lang-en: ñ
+cn;lang-es: ñ
+cn: ñ
+
+dn: cn=A , ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: A
+cn;lang-fr: A
+cn;lang-en: A
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr111, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=fr106, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=de7, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=de134, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es4, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es116, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=B, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: B
+cn;lang-fr: B
+cn;lang-en: B
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr2, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=C, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: C
+cn;lang-fr: C
+cn;lang-en: C
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr3, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=D, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: D
+cn;lang-fr: D
+cn;lang-en: D
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr4, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=E, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: E
+cn;lang-fr: E
+cn;lang-en: E
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr5, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=F, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: F
+cn;lang-fr: F
+cn;lang-en: F
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr6, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=G, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: G
+cn;lang-fr: G
+cn;lang-en: G
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr7, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=H, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: H
+cn;lang-fr: H
+cn;lang-en: H
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=I, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: I
+cn;lang-fr: I
+cn;lang-en: I
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=J, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: J
+cn;lang-fr: J
+cn;lang-en: J
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=K, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: K
+cn;lang-fr: K
+cn;lang-en: K
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=L, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: L
+cn;lang-fr: L
+cn;lang-en: L
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=M, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: M
+cn;lang-fr: M
+cn;lang-en: M
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=N, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: N
+cn;lang-fr: N
+cn;lang-en: N
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=O, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: O
+cn;lang-fr: O
+cn;lang-en: O
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=P, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: P
+cn;lang-fr: P
+cn;lang-en: P
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Q, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Q
+cn;lang-fr: Q
+cn;lang-en: Q
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=R, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: R
+cn;lang-fr: R
+cn;lang-en: R
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=S, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: S
+cn;lang-fr: S
+cn;lang-en: S
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=T, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: T
+cn;lang-fr: T
+cn;lang-en: T
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=U, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: U
+cn;lang-fr: U
+cn;lang-en: U
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=V, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: V
+cn;lang-fr: V
+cn;lang-en: V
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=W, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: W
+cn;lang-fr: W
+cn;lang-en: W
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=X, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: X
+cn;lang-fr: X
+cn;lang-en: X
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Y, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Y
+cn;lang-fr: Y
+cn;lang-en: Y
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Z, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+cn: Z
+cn;lang-fr: Z
+cn;lang-en: Z
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=A , ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: A
+cn;lang-de: A
+cn;lang-en: A
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr111, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=fr106, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=de7, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=de134, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es4, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es116, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=B, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: B
+cn;lang-de: B
+cn;lang-en: B
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr2, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=C, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: C
+cn;lang-de: C
+cn;lang-en: C
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr3, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=D, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: D
+cn;lang-de: D
+cn;lang-en: D
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr4, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=E, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: E
+cn;lang-de: E
+cn;lang-en: E
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr5, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=F, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: F
+cn;lang-de: F
+cn;lang-en: F
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr6, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=G, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: G
+cn;lang-de: G
+cn;lang-en: G
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr7, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=H, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: H
+cn;lang-de: H
+cn;lang-en: H
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=I, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: I
+cn;lang-de: I
+cn;lang-en: I
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=J, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: J
+cn;lang-de: J
+cn;lang-en: J
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=K, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: K
+cn;lang-de: K
+cn;lang-en: K
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=L, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: L
+cn;lang-de: L
+cn;lang-en: L
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=M, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: M
+cn;lang-de: M
+cn;lang-en: M
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=N, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: N
+cn;lang-de: N
+cn;lang-en: N
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=O, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: O
+cn;lang-de: O
+cn;lang-en: O
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=P, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: P
+cn;lang-de: P
+cn;lang-en: P
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Q, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: Q
+cn;lang-de: Q
+cn;lang-en: Q
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=R, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: R
+cn;lang-de: R
+cn;lang-en: R
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=S, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: S
+cn;lang-de: S
+cn;lang-en: S
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=T, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: T
+cn;lang-de: T
+cn;lang-en: T
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=U, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: U
+cn;lang-de: U
+cn;lang-en: U
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=V, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: V
+cn;lang-de: V
+cn;lang-en: V
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=W, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: W
+cn;lang-de: W
+cn;lang-en: W
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=X, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: X
+cn;lang-de: X
+cn;lang-en: X
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Y, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: Y
+cn;lang-de: Y
+cn;lang-en: Y
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Z, ou=Auf Deutsch, ou=European Letters, o=Çéliné Ändrè
+cn: Z
+cn;lang-de: Z
+cn;lang-en: Z
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=A , ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: A
+cn;lang-es: A
+cn;lang-en: A
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr111, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=fr106, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=de7, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=de134, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es4, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+uniquemember: uid=es116, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=B, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: B
+cn;lang-es: B
+cn;lang-en: B
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr2, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=C, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: C
+cn;lang-es: C
+cn;lang-en: C
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr3, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=D, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: D
+cn;lang-es: D
+cn;lang-en: D
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr4, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=E, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: E
+cn;lang-es: E
+cn;lang-en: E
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr5, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=F, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: F
+cn;lang-es: F
+cn;lang-en: F
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr6, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=G, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: G
+cn;lang-es: G
+cn;lang-en: G
+objectclass: top
+objectclass: groupOfUniqueNames
+uniquemember: uid=fr7, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+
+dn: cn=H, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: H
+cn;lang-es: H
+cn;lang-en: H
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=I, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: I
+cn;lang-es: I
+cn;lang-en: I
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=J, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: J
+cn;lang-es: J
+cn;lang-en: J
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=K, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: K
+cn;lang-es: K
+cn;lang-en: K
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=L, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: L
+cn;lang-es: L
+cn;lang-en: L
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=M, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: M
+cn;lang-es: M
+cn;lang-en: M
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=N, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: N
+cn;lang-es: N
+cn;lang-en: N
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=O, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: O
+cn;lang-es: O
+cn;lang-en: O
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=P, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: P
+cn;lang-es: P
+cn;lang-en: P
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Q, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: Q
+cn;lang-es: Q
+cn;lang-en: Q
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=R, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: R
+cn;lang-es: R
+cn;lang-en: R
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=S, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: S
+cn;lang-es: S
+cn;lang-en: S
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=T, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: T
+cn;lang-es: T
+cn;lang-en: T
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=U, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: U
+cn;lang-es: U
+cn;lang-en: U
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=V, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: V
+cn;lang-es: V
+cn;lang-en: V
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=W, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: W
+cn;lang-es: W
+cn;lang-en: W
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=X, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: X
+cn;lang-es: X
+cn;lang-en: X
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Y, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: Y
+cn;lang-es: Y
+cn;lang-en: Y
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: cn=Z, ou=En Español, ou=European Letters, o=Çéliné Ändrè
+cn: Z
+cn;lang-es: Z
+cn;lang-en: Z
+objectclass: top
+objectclass: groupOfUniqueNames
+
+dn: o=àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ, o=Çéliné Ändrè
+objectclass: top
+objectclass: organization
+o: àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ
+description: French Organization
+telephonenumber: àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ
+businesscategory: àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ
+facsimiletelephonenumber: àâçëèéêïîôüùûÀÂÇËÈÉÊÃÎÔÜÙÛ
+l: àâçëèéêïîôüùû$ÀÂÇËÈÉÊÃÎÔÜÙÛ
+postaladdress: àâçëèéêï$1234$îôüùû$ÀÂÇËÈÉÊÃÎÔÜÙÛ 123$France 1234
+seealso: cn=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+seealso: uid=tbird, ou=People, o=Çéliné Ändrè
+seealso: ou=Bürger Preußens, ou=Çëû - Europé, o=Çéliné Ändrè
+
+dn: o=á é í ó ü ñ à É à Ó Ú Ü Ñ, o=Çéliné Ändrè
+objectclass: top
+objectclass: organization
+o: á é í ó ü ñ à É à Ó Ú Ü Ñ
+description: Spanish Organization
+telephonenumber: á é í ó ü ñ à É à Ó Ú Ü Ñ
+businesscategory: á é í ó ü ñ à É à Ó Ú Ü Ñ
+facsimiletelephonenumber: á é í ó ü ñ à É à Ó Ú Ü Ñ
+l: á é í ó ü ñ à É à Ó Ú Ü Ñ$á é í ó ü ñ à É à Ó Ú Ü Ñ
+postaladdress: á é í ó ü ñ $1234$à É à Ó Ú Ü Ñ$Spain 54321
+seealso: cn=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+seealso: uid=tbird, ou=People, o=Çéliné Ändrè
+seealso: ou=Bürger Preußens, ou=Çëû - Europé, o=Çéliné Ändrè
+
+dn: o=ÄÖÜäöüß, o=Çéliné Ändrè
+objectclass: top
+objectclass: organization
+o: ÄÖÜäöüß
+description: German Organization
+telephonenumber: ÄÖÜäöüß
+businesscategory: ÄÖÜäöüß
+facsimiletelephonenumber: ÄÖÜäöüß
+l: ÄÖÜäöüß$ÄÖÜäöüß
+postaladdress: ÄÖÜäöüß$1234$ÄÖÜäöüß$Germany 12345
+seealso: cn=ç, ou=En Français, ou=European Letters, o=Çéliné Ändrè
+
diff --git a/ldap/ldif/Eurosuffix.ldif b/ldap/ldif/Eurosuffix.ldif
new file mode 100644
index 00000000..6eedb529
--- /dev/null
+++ b/ldap/ldif/Eurosuffix.ldif
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+dn: cn=config,cn=ldbm
+changetype: modify
+add: nsslapd-suffix
+nsslapd-suffix: o=Çéliné Ändrè
+
diff --git a/ldap/ldif/Example-roles.ldif b/ldap/ldif/Example-roles.ldif
new file mode 100644
index 00000000..94f4904a
--- /dev/null
+++ b/ldap/ldif/Example-roles.ldif
@@ -0,0 +1,2995 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Roles-based dc=example,dc=com sample LDIF file
+#
+# Notes:
+# 161 total entries.
+# 1 (objectclass=domain) entry (dc=example,dc=com).
+# 3 (objectclass=organizationalunit) entries.
+# 5 (objectclass=nsManagedRoleDefinition) entries.
+# 1 (objectclass=cosClassicDefinition) entry.
+# 1 (objectclass=cosTemplate) entry.
+# 150 (objectclass=person) entries (all under ou=people,dc=example,dc=com).
+#
+dn: dc=example,dc=com
+objectclass: top
+objectclass: domain
+dc: example
+aci: (target ="ldap:///dc=example,dc=com")(targetattr !=
+ "userPassword")(version 3.0;acl "Anonymous read-search access";
+ allow (read, search, compare)(userdn = "ldap:///anyone");)
+aci: (target="ldap:///dc=example,dc=com") (targetattr =
+ "*")(version 3.0; acl "allow all Admin role"; allow(all) roledn =
+ "ldap:///cn=Directory Administrators,dc=example,dc=com";)
+
+dn: cn=Resource Limits COS,dc=example,dc=com
+objectclass: top
+objectclass: ldapSubEntry
+objectclass: cosSuperDefinition
+objectclass: cosClassicDefinition
+cosTemplateDn: cn=Resource Limits COS,dc=example,dc=com
+cosSpecifier: nsRole
+cosAttribute: nsLookThroughLimit operational
+cosAttribute: nsSizeLimit operational
+cosAttribute: nsTimeLimit operational
+cosAttribute: nsIdleTimeout operational
+cn: Resource Limits COS
+
+dn: cn="cn=Directory Administrators,dc=example,dc=com",cn=Resource Limits COS,dc=example,dc=com
+objectclass: top
+objectclass: ldapSubEntry
+objectclass: cosTemplate
+cn: cn=Directory Administrators,dc=example,dc=com
+cosPriority: 0
+# Directory Administrators are not subject to any resource limits
+nsLookThroughLimit: -1
+nsSizeLimit: -1
+nsTimeLimit: -1
+nsIdleTimeout: -1
+
+dn: cn=Directory Administrators,dc=example,dc=com
+cn: Directory Administrators
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+
+dn: ou=People, dc=example,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: People
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr =
+ "userpassword || telephonenumber || facsimiletelephonenumber")(version 3.0;
+ acl "Allow self entry modification";allow (write)(userdn = "ldap:///self");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn || sn || uid")(targetfilter ="(ou=Accounting)")(version 3.0;
+ acl "Accounting Managers Role Permissions";allow (write) (roledn =
+ "ldap:///cn=Accounting Managers,dc=example,dc=com");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn || sn || uid")(targetfilter ="(ou=Human Resources)")(version 3.0;
+ acl "HR Role Permissions";allow (write)(roledn = "ldap:///cn=HR Managers,
+ dc=example,dc=com
+ ");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn ||sn || uid")(targetfilter ="(ou=Product Testing)")(version 3.0;
+ acl "QA Role Permissions";allow (write)(roledn = "ldap:///cn=QA Managers,
+ dc=example,dc=com");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn || sn || uid")(targetfilter ="(ou=Product Development)")(version 3.0;
+ acl "Engineering Role Permissions";allow (write)(roledn = "ldap:///
+ cn=PD Managers,dc=example,dc=com");)
+
+dn: ou=Special Users,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Special Users
+description: Special Administrative Accounts
+
+dn: uid=scarter, ou=People, dc=example,dc=com
+cn: Sam Carter
+sn: Carter
+givenname: Sam
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: scarter
+mail: scarter@example.com
+telephonenumber: +1 408 555 4798
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4612
+userpassword: sprain
+manager: uid=dmiller, ou=People, dc=example,dc=com
+nsRoleDN: cn=Accounting Managers,dc=example,dc=com
+
+dn: uid=tmorris, ou=People, dc=example,dc=com
+cn: Ted Morris
+sn: Morris
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tmorris
+mail: tmorris@example.com
+telephonenumber: +1 408 555 9187
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4117
+userpassword: irrefutable
+manager: uid=dmiller, ou=People, dc=example,dc=com
+nsRoleDN: cn=Accounting Managers,dc=example,dc=com
+
+dn: uid=kvaughan, ou=People, dc=example,dc=com
+cn: Kirsten Vaughan
+sn: Vaughan
+givenname: Kirsten
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kvaughan
+mail: kvaughan@example.com
+telephonenumber: +1 408 555 5625
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2871
+userpassword: bribery
+manager: uid=jvedder, ou=People, dc=example,dc=com
+nsRoleDN: cn=Directory Administrators,dc=example,dc=com
+nsRoleDN: cn=HR Managers,dc=example,dc=com
+
+dn: uid=abergin, ou=People, dc=example,dc=com
+cn: Andy Bergin
+sn: Bergin
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: abergin
+mail: abergin@example.com
+telephonenumber: +1 408 555 8585
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3472
+userpassword: inflict
+manager: uid=ealexand, ou=People, dc=example,dc=com
+nsRoleDN: cn=QA Managers,dc=example,dc=com
+
+dn: uid=dmiller, ou=People, dc=example,dc=com
+cn: David Miller
+sn: Miller
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: dmiller
+mail: dmiller@example.com
+telephonenumber: +1 408 555 9423
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4135
+userpassword: gosling
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: uid=gfarmer, ou=People, dc=example,dc=com
+cn: Gern Farmer
+sn: Farmer
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: gfarmer
+mail: gfarmer@example.com
+telephonenumber: +1 408 555 6201
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1269
+userpassword: ruling
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=kwinters, ou=People, dc=example,dc=com
+cn: Kelly Winters
+sn: Winters
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kwinters
+mail: kwinters@example.com
+telephonenumber: +1 408 555 9069
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4178
+userpassword: forsook
+manager: uid=cnewport, ou=People, dc=example,dc=com
+nsRoleDN: cn=PD Managers,dc=example,dc=com
+
+dn: uid=trigden, ou=People, dc=example,dc=com
+cn: Torrey Rigden
+sn: Rigden
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: trigden
+mail: trigden@example.com
+telephonenumber: +1 408 555 9280
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3584
+userpassword: sensitive
+manager: uid=cnewport, ou=People, dc=example,dc=com
+nsRoleDN: cn=PD Managers,dc=example,dc=com
+
+dn: uid=cschmith, ou=People, dc=example,dc=com
+cn: Chris Schmith
+sn: Schmith
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: cschmith
+mail: cschmith@example.com
+telephonenumber: +1 408 555 8011
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0416
+userpassword: hypotenuse
+manager: uid=jvedder, ou=People, dc=example,dc=com
+nsRoleDN: cn=HR Managers,dc=example,dc=com
+
+dn: uid=jwallace, ou=People, dc=example,dc=com
+cn: Judy Wallace
+sn: Wallace
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jwallace
+mail: jwallace@example.com
+telephonenumber: +1 408 555 0319
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1033
+userpassword: linear
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=jwalker, ou=People, dc=example,dc=com
+cn: John Walker
+sn: Walker
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jwalker
+mail: jwalker@example.com
+telephonenumber: +1 408 555 1476
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3915
+userpassword: dogleg
+manager: uid=ealexand, ou=People, dc=example,dc=com
+nsRoleDN: cn=QA Managers,dc=example,dc=com
+
+dn: uid=tclow, ou=People, dc=example,dc=com
+cn: Torrey Clow
+sn: Clow
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tclow
+mail: tclow@example.com
+telephonenumber: +1 408 555 8825
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4376
+userpassword: cardreader
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=rdaugherty, ou=People, dc=example,dc=com
+cn: Robert Daugherty
+sn: Daugherty
+givenname: Robert
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: rdaugherty
+mail: rdaugherty@example.com
+telephonenumber: +1 408 555 1296
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0194
+userpassword: apples
+manager: uid=trigden, ou=People, dc=example,dc=com
+nsRoleDN: cn=Directory Administrators,dc=example,dc=com
+
+dn: uid=jreuter, ou=People, dc=example,dc=com
+cn: Jayne Reuter
+sn: Reuter
+givenname: Jayne
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jreuter
+mail: jreuter@example.com
+telephonenumber: +1 408 555 1122
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2942
+userpassword: destroy
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=tmason, ou=People, dc=example,dc=com
+cn: Torrey Mason
+sn: Mason
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: tmason
+mail: tmason@example.com
+telephonenumber: +1 408 555 1596
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1124
+userpassword: squatted
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=bhall, ou=People, dc=example,dc=com
+cn: Benjamin Hall
+sn: Hall
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: bhall
+mail: bhall@example.com
+telephonenumber: +1 408 555 6067
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2511
+userpassword: oranges
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=btalbot, ou=People, dc=example,dc=com
+cn: Brad Talbot
+sn: Talbot
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: btalbot
+mail: btalbot@example.com
+telephonenumber: +1 408 555 4992
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3532
+userpassword: trident
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=mward, ou=People, dc=example,dc=com
+cn: Marcus Ward
+sn: Ward
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mward
+mail: mward@example.com
+telephonenumber: +1 408 555 5688
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1707
+userpassword: normal
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=bjablons, ou=People, dc=example,dc=com
+cn: Barbara Jablonski
+sn: Jablonski
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: bjablons
+mail: bjablons@example.com
+telephonenumber: +1 408 555 8815
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0906
+userpassword: strawberry
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=jmcFarla, ou=People, dc=example,dc=com
+cn: Judy McFarland
+sn: McFarland
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: jmcFarla
+mail: jmcFarla@example.com
+telephonenumber: +1 408 555 2567
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 2359
+userpassword: walnut
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=llabonte, ou=People, dc=example,dc=com
+cn: Lee Labonte
+sn: Labonte
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: llabonte
+mail: llabonte@example.com
+telephonenumber: +1 408 555 0957
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2854
+userpassword: sourdough
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=jcampaig, ou=People, dc=example,dc=com
+cn: Jody Campaigne
+sn: Campaigne
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jcampaig
+mail: jcampaig@example.com
+telephonenumber: +1 408 555 1660
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4385
+userpassword: grapevine
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=bhal2, ou=People, dc=example,dc=com
+cn: Barbara Hall
+sn: Hall
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: bhal2
+mail: bhal2@example.com
+telephonenumber: +1 408 555 4491
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2758
+userpassword: truths
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=alutz, ou=People, dc=example,dc=com
+cn: Alexander Lutz
+sn: Lutz
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alutz
+mail: alutz@example.com
+telephonenumber: +1 408 555 6505
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1327
+userpassword: northward
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=btalbo2, ou=People, dc=example,dc=com
+cn: Bjorn Talbot
+sn: Talbot
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: btalbo2
+mail: btalbo2@example.com
+telephonenumber: +1 408 555 4234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1205
+userpassword: corduroy
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=achassin, ou=People, dc=example,dc=com
+cn: Ashley Chassin
+sn: Chassin
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: achassin
+mail: achassin@example.com
+telephonenumber: +1 408 555 9972
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0466
+userpassword: duopolist
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=hmiller, ou=People, dc=example,dc=com
+cn: Harry Miller
+sn: Miller
+givenname: Harry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: hmiller
+mail: hmiller@example.com
+telephonenumber: +1 408 555 9804
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4304
+userpassword: hillock
+manager: uid=kwinters, ou=People, dc=example,dc=com
+nsRoleDN: cn=Directory Administrators,dc=example,dc=com
+
+dn: uid=jcampai2, ou=People, dc=example,dc=com
+cn: Jeffrey Campaigne
+sn: Campaigne
+givenname: Jeffrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jcampai2
+mail: jcampai2@example.com
+telephonenumber: +1 408 555 7393
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 1377
+userpassword: nominee
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=lulrich, ou=People, dc=example,dc=com
+cn: Lee Ulrich
+sn: Ulrich
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: lulrich
+mail: lulrich@example.com
+telephonenumber: +1 408 555 8652
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0985
+userpassword: attribution
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=mlangdon, ou=People, dc=example,dc=com
+cn: Marcus Langdon
+sn: Langdon
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mlangdon
+mail: mlangdon@example.com
+telephonenumber: +1 408 555 6249
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4471
+userpassword: threat
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=striplet, ou=People, dc=example,dc=com
+cn: Stephen Triplett
+sn: Triplett
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: striplet
+mail: striplet@example.com
+telephonenumber: +1 408 555 4519
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3083
+userpassword: compactify
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=gtriplet, ou=People, dc=example,dc=com
+cn: Gern Triplett
+sn: Triplett
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: gtriplet
+mail: gtriplet@example.com
+telephonenumber: +1 408 555 2582
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4023
+userpassword: placeable
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=jfalena, ou=People, dc=example,dc=com
+cn: John Falena
+sn: Falena
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jfalena
+mail: jfalena@example.com
+telephonenumber: +1 408 555 8133
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1917
+userpassword: nightly
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=speterso, ou=People, dc=example,dc=com
+cn: Sue Peterson
+sn: Peterson
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: speterso
+mail: speterso@example.com
+telephonenumber: +1 408 555 3613
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3073
+userpassword: quinine
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=ejohnson, ou=People, dc=example,dc=com
+cn: Emanuel Johnson
+sn: Johnson
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ejohnson
+mail: ejohnson@example.com
+telephonenumber: +1 408 555 3287
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3737
+userpassword: marketwise
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=prigden, ou=People, dc=example,dc=com
+cn: Peter Rigden
+sn: Rigden
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: prigden
+mail: prigden@example.com
+telephonenumber: +1 408 555 5099
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1271
+userpassword: epiphyseal
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=bwalker, ou=People, dc=example,dc=com
+cn: Brad Walker
+sn: Walker
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bwalker
+mail: bwalker@example.com
+telephonenumber: +1 408 555 5476
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3529
+userpassword: interruptible
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=kjensen, ou=People, dc=example,dc=com
+cn: Kurt Jensen
+sn: Jensen
+givenname: Kurt
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kjensen
+mail: kjensen@example.com
+telephonenumber: +1 408 555 6127
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1944
+userpassword: regulatory
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=mlott, ou=People, dc=example,dc=com
+cn: Mike Lott
+sn: Lott
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mlott
+mail: mlott@example.com
+telephonenumber: +1 408 555 2234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0498
+userpassword: cognac
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=cwallace, ou=People, dc=example,dc=com
+cn: Cecil Wallace
+sn: Wallace
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: cwallace
+mail: cwallace@example.com
+telephonenumber: +1 408 555 6438
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0349
+userpassword: quintus
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=tpierce, ou=People, dc=example,dc=com
+cn: Tobias Pierce
+sn: Pierce
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tpierce
+mail: tpierce@example.com
+telephonenumber: +1 408 555 1531
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1383
+userpassword: rascal
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=rbannist, ou=People, dc=example,dc=com
+cn: Richard Bannister
+sn: Bannister
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rbannist
+mail: rbannist@example.com
+telephonenumber: +1 408 555 1833
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0983
+userpassword: demonstrate
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=bplante, ou=People, dc=example,dc=com
+cn: Brian Plante
+sn: Plante
+givenname: Brian
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: bplante
+mail: bplante@example.com
+telephonenumber: +1 408 555 3550
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4654
+userpassword: tangerine
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=rmills, ou=People, dc=example,dc=com
+cn: Randy Mills
+sn: Mills
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rmills
+mail: rmills@example.com
+telephonenumber: +1 408 555 2072
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3823
+userpassword: condescend
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=bschneid, ou=People, dc=example,dc=com
+cn: Benjamin Schneider
+sn: Schneider
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: bschneid
+mail: bschneid@example.com
+telephonenumber: +1 408 555 1012
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4471
+userpassword: biblical
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=skellehe, ou=People, dc=example,dc=com
+cn: Sue Kelleher
+sn: Kelleher
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: skellehe
+mail: skellehe@example.com
+telephonenumber: +1 408 555 3480
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1608
+userpassword: sweltering
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=brentz, ou=People, dc=example,dc=com
+cn: Bertram Rentz
+sn: Rentz
+givenname: Bertram
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: brentz
+mail: brentz@example.com
+telephonenumber: +1 408 555 5526
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0617
+userpassword: diachronic
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=dsmith, ou=People, dc=example,dc=com
+cn: Daniel Smith
+sn: Smith
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: dsmith
+mail: dsmith@example.com
+telephonenumber: +1 408 555 9519
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0368
+userpassword: quantitative
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=scarte2, ou=People, dc=example,dc=com
+cn: Stephen Carter
+sn: Carter
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: scarte2
+mail: scarte2@example.com
+telephonenumber: +1 408 555 6022
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2013
+userpassword: scooter
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=dthorud, ou=People, dc=example,dc=com
+cn: David Thorud
+sn: Thorud
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: dthorud
+mail: dthorud@example.com
+telephonenumber: +1 408 555 6185
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1128
+userpassword: fulcrum
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=ekohler, ou=People, dc=example,dc=com
+cn: Elba Kohler
+sn: Kohler
+givenname: Elba
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: ekohler
+mail: ekohler@example.com
+telephonenumber: +1 408 555 1926
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2721
+userpassword: guildhall
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=lcampbel, ou=People, dc=example,dc=com
+cn: Laurel Campbell
+sn: Campbell
+givenname: Laurel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: lcampbel
+mail: lcampbel@example.com
+telephonenumber: +1 408 555 2537
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 2073
+userpassword: impress
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=tlabonte, ou=People, dc=example,dc=com
+cn: Tim Labonte
+sn: Labonte
+givenname: Tim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tlabonte
+mail: tlabonte@example.com
+telephonenumber: +1 408 555 0058
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1426
+userpassword: express
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=slee, ou=People, dc=example,dc=com
+cn: Scott Lee
+sn: Lee
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: slee
+mail: slee@example.com
+telephonenumber: +1 408 555 2335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1806
+userpassword: revertive
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=bfree, ou=People, dc=example,dc=com
+cn: Bjorn Free
+sn: Free
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfree
+mail: bfree@example.com
+telephonenumber: +1 408 555 8588
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3307
+userpassword: etiquette
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=tschneid, ou=People, dc=example,dc=com
+cn: Torrey Schneider
+sn: Schneider
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tschneid
+mail: tschneid@example.com
+telephonenumber: +1 408 555 7086
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2292
+userpassword: chaperone
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=prose, ou=People, dc=example,dc=com
+cn: Paula Rose
+sn: Rose
+givenname: Paula
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: prose
+mail: prose@example.com
+telephonenumber: +1 408 555 9998
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0542
+userpassword: regatta
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=jhunter, ou=People, dc=example,dc=com
+cn: Janet Hunter
+sn: Hunter
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jhunter
+mail: jhunter@example.com
+telephonenumber: +1 408 555 7665
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4856
+userpassword: nanometer
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=ashelton, ou=People, dc=example,dc=com
+cn: Alexander Shelton
+sn: Shelton
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: ashelton
+mail: ashelton@example.com
+telephonenumber: +1 408 555 1081
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1987
+userpassword: appointe
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=mmcinnis, ou=People, dc=example,dc=com
+cn: Marcus Mcinnis
+sn: Mcinnis
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: mmcinnis
+mail: mmcinnis@example.com
+telephonenumber: +1 408 555 9655
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4818
+userpassword: calcify
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=falbers, ou=People, dc=example,dc=com
+cn: Frank Albers
+sn: Albers
+givenname: Frank
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: falbers
+mail: falbers@example.com
+telephonenumber: +1 408 555 3094
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1439
+userpassword: degradation
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=mschneid, ou=People, dc=example,dc=com
+cn: Martin Schneider
+sn: Schneider
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mschneid
+mail: mschneid@example.com
+telephonenumber: +1 408 555 5017
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3153
+userpassword: motorcycle
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=pcruse, ou=People, dc=example,dc=com
+cn: Patricia Cruse
+sn: Cruse
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: pcruse
+mail: pcruse@example.com
+telephonenumber: +1 408 555 8641
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3967
+userpassword: pauper
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=tkelly, ou=People, dc=example,dc=com
+cn: Timothy Kelly
+sn: Kelly
+givenname: Timothy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: tkelly
+mail: tkelly@example.com
+telephonenumber: +1 408 555 4295
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3107
+userpassword: risible
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=ahel, ou=People, dc=example,dc=com
+cn: Andrew Hel
+sn: Hel
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahel
+mail: ahel@example.com
+telephonenumber: +1 408 555 2666
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0572
+userpassword: sarsaparilla
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=jburrell, ou=People, dc=example,dc=com
+cn: James Burrell
+sn: Burrell
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jburrell
+mail: jburrell@example.com
+telephonenumber: +1 408 555 0751
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4926
+userpassword: degrease
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=smason, ou=People, dc=example,dc=com
+cn: Sue Mason
+sn: Mason
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: smason
+mail: smason@example.com
+telephonenumber: +1 408 555 9780
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4971
+userpassword: sensible
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=ptyler, ou=People, dc=example,dc=com
+cn: Pete Tyler
+sn: Tyler
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ptyler
+mail: ptyler@example.com
+telephonenumber: +1 408 555 3335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0327
+userpassword: vinegar
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=calexand, ou=People, dc=example,dc=com
+cn: Chris Alexander
+sn: Alexander
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: calexand
+mail: calexand@example.com
+telephonenumber: +1 408 555 9438
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2884
+userpassword: dauphin
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=jcruse, ou=People, dc=example,dc=com
+cn: Jim Cruse
+sn: Cruse
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jcruse
+mail: jcruse@example.com
+telephonenumber: +1 408 555 9482
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0083
+userpassword: bridgework
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=kcarter, ou=People, dc=example,dc=com
+cn: Karen Carter
+sn: Carter
+givenname: Karen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kcarter
+mail: kcarter@example.com
+telephonenumber: +1 408 555 4675
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2320
+userpassword: radiosonde
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rfish, ou=People, dc=example,dc=com
+cn: Randy Fish
+sn: Fish
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rfish
+mail: rfish@example.com
+telephonenumber: +1 408 555 9865
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2317
+userpassword: mailbox
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=phunt, ou=People, dc=example,dc=com
+cn: Philip Hunt
+sn: Hunt
+givenname: Philip
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: phunt
+mail: phunt@example.com
+telephonenumber: +1 408 555 1242
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1183
+userpassword: wastewater
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rschneid, ou=People, dc=example,dc=com
+cn: Rachel Schneider
+sn: Schneider
+givenname: Rachel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rschneid
+mail: rschneid@example.com
+telephonenumber: +1 408 555 9908
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4183
+userpassword: decorous
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=bjensen, ou=People, dc=example,dc=com
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: bjensen
+mail: bjensen@example.com
+telephonenumber: +1 408 555 1862
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0209
+userpassword: hifalutin
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=jlange, ou=People, dc=example,dc=com
+cn: Jim Lange
+sn: Lange
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: jlange
+mail: jlange@example.com
+telephonenumber: +1 408 555 0488
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3798
+userpassword: chastity
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rulrich, ou=People, dc=example,dc=com
+cn: Randy Ulrich
+sn: Ulrich
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: rulrich
+mail: rulrich@example.com
+telephonenumber: +1 408 555 5311
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1282
+userpassword: twinkle
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rfrancis, ou=People, dc=example,dc=com
+cn: Richard Francis
+sn: Francis
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rfrancis
+mail: rfrancis@example.com
+telephonenumber: +1 408 555 8157
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3482
+userpassword: hacienda
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=mwhite, ou=People, dc=example,dc=com
+cn: Morgan White
+sn: White
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mwhite
+mail: mwhite@example.com
+telephonenumber: +1 408 555 9620
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3088
+userpassword: staple
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=gjensen, ou=People, dc=example,dc=com
+cn: Gern Jensen
+sn: Jensen
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: gjensen
+mail: gjensen@example.com
+telephonenumber: +1 408 555 3299
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4609
+userpassword: primitive
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=awhite, ou=People, dc=example,dc=com
+cn: Alan White
+sn: White
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: awhite
+mail: awhite@example.com
+telephonenumber: +1 408 555 3232
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0142
+userpassword: placeholder
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=bmaddox, ou=People, dc=example,dc=com
+cn: Barbara Maddox
+sn: Maddox
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bmaddox
+mail: bmaddox@example.com
+telephonenumber: +1 408 555 7783
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2207
+userpassword: feedback
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=mtalbot, ou=People, dc=example,dc=com
+cn: Martin Talbot
+sn: Talbot
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mtalbot
+mail: mtalbot@example.com
+telephonenumber: +1 408 555 9228
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1415
+userpassword: currant
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=jbrown, ou=People, dc=example,dc=com
+cn: Judy Brown
+sn: Brown
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jbrown
+mail: jbrown@example.com
+telephonenumber: +1 408 555 6885
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4224
+userpassword: militiamen
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=jjensen, ou=People, dc=example,dc=com
+cn: Jody Jensen
+sn: Jensen
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jjensen
+mail: jjensen@example.com
+telephonenumber: +1 408 555 7587
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4882
+userpassword: borderland
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=mcarter, ou=People, dc=example,dc=com
+cn: Mike Carter
+sn: Carter
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mcarter
+mail: mcarter@example.com
+telephonenumber: +1 408 555 1846
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3819
+userpassword: mainland
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=dakers, ou=People, dc=example,dc=com
+cn: David Akers
+sn: Akers
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: dakers
+mail: dakers@example.com
+telephonenumber: +1 408 555 4812
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4944
+userpassword: integument
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=sfarmer, ou=People, dc=example,dc=com
+cn: Scott Farmer
+sn: Farmer
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: sfarmer
+mail: sfarmer@example.com
+telephonenumber: +1 408 555 4228
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0019
+userpassword: triumphal
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=dward, ou=People, dc=example,dc=com
+cn: Daniel Ward
+sn: Ward
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: dward
+mail: dward@example.com
+telephonenumber: +1 408 555 5322
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3927
+userpassword: armload
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=tward, ou=People, dc=example,dc=com
+cn: Tobias Ward
+sn: Ward
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tward
+mail: tward@example.com
+telephonenumber: +1 408 555 7202
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2238
+userpassword: cedilla
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=pshelton, ou=People, dc=example,dc=com
+cn: Patricia Shelton
+sn: Shelton
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: pshelton
+mail: pshelton@example.com
+telephonenumber: +1 408 555 6442
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2918
+userpassword: nosedive
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=jrentz, ou=People, dc=example,dc=com
+cn: Jody Rentz
+sn: Rentz
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jrentz
+mail: jrentz@example.com
+telephonenumber: +1 408 555 5829
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3025
+userpassword: meander
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=plorig, ou=People, dc=example,dc=com
+cn: Peter Lorig
+sn: Lorig
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: plorig
+mail: plorig@example.com
+telephonenumber: +1 408 555 0624
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1276
+userpassword: calorimeter
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=ajensen, ou=People, dc=example,dc=com
+cn: Allison Jensen
+sn: Jensen
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: ajensen
+mail: ajensen@example.com
+telephonenumber: +1 408 555 7892
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0784
+userpassword: coltsfoot
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=kschmith, ou=People, dc=example,dc=com
+cn: Kelly Schmith
+sn: Schmith
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kschmith
+mail: kschmith@example.com
+telephonenumber: +1 408 555 9749
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2221
+userpassword: purvey
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=pworrell, ou=People, dc=example,dc=com
+cn: Pete Worrell
+sn: Worrell
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: pworrell
+mail: pworrell@example.com
+telephonenumber: +1 408 555 1637
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2449
+userpassword: solicitous
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=mreuter, ou=People, dc=example,dc=com
+cn: Matthew Reuter
+sn: Reuter
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mreuter
+mail: mreuter@example.com
+telephonenumber: +1 408 555 6879
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 1356
+userpassword: oblivious
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=gtyler, ou=People, dc=example,dc=com
+cn: Gern Tyler
+sn: Tyler
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: gtyler
+mail: gtyler@example.com
+telephonenumber: +1 408 555 1020
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0312
+userpassword: typology
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=tschmith, ou=People, dc=example,dc=com
+cn: Tobias Schmith
+sn: Schmith
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tschmith
+mail: tschmith@example.com
+telephonenumber: +1 408 555 9626
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4607
+userpassword: compost
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=bjense2, ou=People, dc=example,dc=com
+cn: Bjorn Jensen
+sn: Jensen
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bjense2
+mail: bjense2@example.com
+telephonenumber: +1 408 555 5655
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4294
+userpassword: mortgage
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=dswain, ou=People, dc=example,dc=com
+cn: Dietrich Swain
+sn: Swain
+givenname: Dietrich
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: dswain
+mail: dswain@example.com
+telephonenumber: +1 408 555 9222
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4396
+userpassword: freedom
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=ahall, ou=People, dc=example,dc=com
+cn: Andy Hall
+sn: Hall
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahall
+mail: ahall@example.com
+telephonenumber: +1 408 555 6169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3050
+userpassword: slater
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=jmuffly, ou=People, dc=example,dc=com
+cn: Jeff Muffly
+sn: Muffly
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jmuffly
+mail: jmuffly@example.com
+telephonenumber: +1 408 555 5287
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0997
+userpassword: dictate
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=tjensen, ou=People, dc=example,dc=com
+cn: Ted Jensen
+sn: Jensen
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjensen
+mail: tjensen@example.com
+telephonenumber: +1 408 555 8622
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4717
+userpassword: ecosystem
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=ahunter, ou=People, dc=example,dc=com
+cn: Allison Hunter
+sn: Hunter
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: ahunter
+mail: ahunter@example.com
+telephonenumber: +1 408 555 7713
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1213
+userpassword: egregious
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=jgoldste, ou=People, dc=example,dc=com
+cn: Jon Goldstein
+sn: Goldstein
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jgoldste
+mail: jgoldste@example.com
+telephonenumber: +1 408 555 5769
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1454
+userpassword: yellow
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=aworrell, ou=People, dc=example,dc=com
+cn: Alan Worrell
+sn: Worrell
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aworrell
+mail: aworrell@example.com
+telephonenumber: +1 408 555 1591
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3966
+userpassword: gargoyle
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=wlutz, ou=People, dc=example,dc=com
+cn: Wendy Lutz
+sn: Lutz
+givenname: Wendy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: wlutz
+mail: wlutz@example.com
+telephonenumber: +1 408 555 3358
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4912
+userpassword: bassinet
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=jlutz, ou=People, dc=example,dc=com
+cn: Janet Lutz
+sn: Lutz
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jlutz
+mail: jlutz@example.com
+telephonenumber: +1 408 555 4902
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2544
+userpassword: autumn
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=dlangdon, ou=People, dc=example,dc=com
+cn: Dan Langdon
+sn: Langdon
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: dlangdon
+mail: dlangdon@example.com
+telephonenumber: +1 408 555 7044
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3263
+userpassword: botulin
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=aknutson, ou=People, dc=example,dc=com
+cn: Ashley Knutson
+sn: Knutson
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aknutson
+mail: aknutson@example.com
+telephonenumber: +1 408 555 2169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4736
+userpassword: maltose
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=kmcinnis, ou=People, dc=example,dc=com
+cn: Kelly Mcinnis
+sn: Mcinnis
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: kmcinnis
+mail: kmcinnis@example.com
+telephonenumber: +1 408 555 8596
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4312
+userpassword: stargaze
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=tcouzens, ou=People, dc=example,dc=com
+cn: Trent Couzens
+sn: Couzens
+givenname: Trent
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tcouzens
+mail: tcouzens@example.com
+telephonenumber: +1 408 555 8401
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3994
+userpassword: tambourine
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=lstockto, ou=People, dc=example,dc=com
+cn: Lee Stockton
+sn: Stockton
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: lstockto
+mail: lstockto@example.com
+telephonenumber: +1 408 555 0518
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0169
+userpassword: brooklyn
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=jbourke, ou=People, dc=example,dc=com
+cn: Jon Bourke
+sn: Bourke
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jbourke
+mail: jbourke@example.com
+telephonenumber: +1 408 555 8541
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0034
+userpassword: brainwash
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=dlanoway, ou=People, dc=example,dc=com
+cn: Dan Lanoway
+sn: Lanoway
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: dlanoway
+mail: dlanoway@example.com
+telephonenumber: +1 408 555 2017
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3540
+userpassword: manhattan
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=kcope, ou=People, dc=example,dc=com
+cn: Karl Cope
+sn: Cope
+givenname: Karl
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kcope
+mail: kcope@example.com
+telephonenumber: +1 408 555 2709
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 3040
+userpassword: forfeiture
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=abarnes, ou=People, dc=example,dc=com
+cn: Anne-Louise Barnes
+sn: Barnes
+givenname: Anne-Louise
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: abarnes
+mail: abarnes@example.com
+telephonenumber: +1 408 555 9445
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2290
+userpassword: chevron
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=rjensen, ou=People, dc=example,dc=com
+cn: Richard Jensen
+sn: Jensen
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: rjensen
+mail: rjensen@example.com
+telephonenumber: +1 408 555 5957
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2631
+userpassword: disciplinarian
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=phun2, ou=People, dc=example,dc=com
+cn: Pete Hunt
+sn: Hunt
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: phun2
+mail: phun2@example.com
+telephonenumber: +1 408 555 0342
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0087
+userpassword: absorb
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=mvaughan, ou=People, dc=example,dc=com
+cn: Matthew Vaughan
+sn: Vaughan
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: mvaughan
+mail: mvaughan@example.com
+telephonenumber: +1 408 555 4692
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4508
+userpassword: submitted
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=jlut2, ou=People, dc=example,dc=com
+cn: James Lutz
+sn: Lutz
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jlut2
+mail: jlut2@example.com
+telephonenumber: +1 408 555 9689
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3541
+userpassword: shrank
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=mjablons, ou=People, dc=example,dc=com
+cn: Morgan Jablonski
+sn: Jablonski
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mjablons
+mail: mjablons@example.com
+telephonenumber: +1 408 555 0813
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3160
+userpassword: minimal
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=pchassin, ou=People, dc=example,dc=com
+cn: Peter Chassin
+sn: Chassin
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: pchassin
+mail: pchassin@example.com
+telephonenumber: +1 408 555 2816
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4524
+userpassword: barbital
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=dcope, ou=People, dc=example,dc=com
+cn: Dan Cope
+sn: Cope
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: dcope
+mail: dcope@example.com
+telephonenumber: +1 408 555 9813
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1737
+userpassword: snifter
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=jrent2, ou=People, dc=example,dc=com
+cn: Judy Rentz
+sn: Rentz
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jrent2
+mail: jrent2@example.com
+telephonenumber: +1 408 555 2523
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4405
+userpassword: tachistoscope
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=tcruse, ou=People, dc=example,dc=com
+cn: Tobias Cruse
+sn: Cruse
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tcruse
+mail: tcruse@example.com
+telephonenumber: +1 408 555 5980
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4191
+userpassword: flinty
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=eward, ou=People, dc=example,dc=com
+cn: Eric Ward
+sn: Ward
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: eward
+mail: eward@example.com
+telephonenumber: +1 408 555 2320
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4874
+userpassword: episcopal
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=ttully, ou=People, dc=example,dc=com
+cn: Torrey Tully
+sn: Tully
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: ttully
+mail: ttully@example.com
+telephonenumber: +1 408 555 2274
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3924
+userpassword: schooner
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=charvey, ou=People, dc=example,dc=com
+cn: Cecil Harvey
+sn: Harvey
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: charvey
+mail: charvey@example.com
+telephonenumber: +1 408 555 1815
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4583
+userpassword: journalese
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=rfisher, ou=People, dc=example,dc=com
+cn: Randy Fisher
+sn: Fisher
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: rfisher
+mail: rfisher@example.com
+telephonenumber: +1 408 555 1506
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1579
+userpassword: pomegranate
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=alangdon, ou=People, dc=example,dc=com
+cn: Andrew Langdon
+sn: Langdon
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alangdon
+mail: alangdon@example.com
+telephonenumber: +1 408 555 8289
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2254
+userpassword: muzzle
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=drose, ou=People, dc=example,dc=com
+cn: David Rose
+sn: Rose
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: drose
+mail: drose@example.com
+telephonenumber: +1 408 555 3963
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4012
+userpassword: gubernatorial
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=polfield, ou=People, dc=example,dc=com
+cn: Peter Olfield
+sn: Olfield
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: polfield
+mail: polfield@example.com
+telephonenumber: +1 408 555 8231
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1376
+userpassword: monologue
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=awalker, ou=People, dc=example,dc=com
+cn: Andy Walker
+sn: Walker
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: awalker
+mail: awalker@example.com
+telephonenumber: +1 408 555 9199
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0061
+userpassword: detonable
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=lrentz, ou=People, dc=example,dc=com
+cn: Lex Rentz
+sn: Rentz
+givenname: Lex
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: lrentz
+mail: lrentz@example.com
+telephonenumber: +1 408 555 2019
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2203
+userpassword: calcium
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=jvaughan, ou=People, dc=example,dc=com
+cn: Jeff Vaughan
+sn: Vaughan
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jvaughan
+mail: jvaughan@example.com
+telephonenumber: +1 408 555 4543
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1734
+userpassword: appoint
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=bfrancis, ou=People, dc=example,dc=com
+cn: Barbara Francis
+sn: Francis
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfrancis
+mail: bfrancis@example.com
+telephonenumber: +1 408 555 9111
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3743
+userpassword: holystone
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=ewalker, ou=People, dc=example,dc=com
+cn: Eric Walker
+sn: Walker
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: ewalker
+mail: ewalker@example.com
+telephonenumber: +1 408 555 6387
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2295
+userpassword: beguile
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=tjames, ou=People, dc=example,dc=com
+cn: Tobias James
+sn: James
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjames
+mail: tjames@example.com
+telephonenumber: +1 408 555 2458
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0730
+userpassword: turtle
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=brigden, ou=People, dc=example,dc=com
+cn: Bjorn Rigden
+sn: Rigden
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: brigden
+mail: brigden@example.com
+telephonenumber: +1 408 555 5263
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1643
+userpassword: purple
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=ecruse, ou=People, dc=example,dc=com
+cn: Eric Cruse
+sn: Cruse
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ecruse
+mail: ecruse@example.com
+telephonenumber: +1 408 555 0648
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4233
+userpassword: platelet
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=rjense2, ou=People, dc=example,dc=com
+cn: Randy Jensen
+sn: Jensen
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: rjense2
+mail: rjense2@example.com
+telephonenumber: +1 408 555 9045
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1984
+userpassword: transpose
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=rhunt, ou=People, dc=example,dc=com
+cn: Richard Hunt
+sn: Hunt
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rhunt
+mail: rhunt@example.com
+telephonenumber: +1 408 555 0139
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 0718
+userpassword: becloud
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=bparker, ou=People, dc=example,dc=com
+cn: Barry Parker
+sn: Parker
+givenname: Barry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: bparker
+mail: bparker@example.com
+telephonenumber: +1 408 555 4647
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1148
+userpassword: lenticular
+
+dn: uid=ealexand, ou=People, dc=example,dc=com
+cn: Erin Alexander
+sn: Alexander
+givenname: Erin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ealexand
+mail: ealexand@example.com
+telephonenumber: +1 408 555 5563
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2434
+userpassword: galactose
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: uid=mtyler, ou=People, dc=example,dc=com
+cn: Matthew Tyler
+sn: Tyler
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: mtyler
+mail: mtyler@example.com
+telephonenumber: +1 408 555 7907
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2701
+userpassword: instantiate
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=elott, ou=People, dc=example,dc=com
+cn: Emanuel Lott
+sn: Lott
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: elott
+mail: elott@example.com
+telephonenumber: +1 408 555 0932
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3906
+userpassword: holdout
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=cnewport, ou=People, dc=example,dc=com
+cn: Christoph Newport
+sn: Newport
+givenname: Christoph
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: cnewport
+mail: cnewport@example.com
+telephonenumber: +1 408 555 0066
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0056
+userpassword: expertise
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: uid=jvedder, ou=People, dc=example,dc=com
+cn: Jeff Vedder
+sn: Vedder
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jvedder
+mail: jvedder@example.com
+telephonenumber: +1 408 555 4668
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3445
+userpassword: befitting
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: cn=Accounting Managers,dc=example,dc=com
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+cn: Accounting Managers
+description: People who can manage accounting entries
+
+dn: cn=HR Managers,dc=example,dc=com
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+cn: HR Managers
+description: People who can manage HR entries
+
+dn: cn=QA Managers,dc=example,dc=com
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+cn: QA Managers
+description: People who can manage QA entries
+
+dn: cn=PD Managers,dc=example,dc=com
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+cn: PD Managers
+description: People who can manage engineer entries
+
+dn: ou=Netscape Servers,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Netscape Servers
+description: Standard branch for Netscape Server registration
diff --git a/ldap/ldif/Example-views.ldif b/ldap/ldif/Example-views.ldif
new file mode 100644
index 00000000..57e1c70f
--- /dev/null
+++ b/ldap/ldif/Example-views.ldif
@@ -0,0 +1,3167 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Roles-based dc=example,dc=com sample LDIF file
+#
+# Notes:
+# 161 total entries.
+# 1 (objectclass=domain) entry (dc=example,dc=com).
+# 3 (objectclass=organizationalunit) entries.
+# 5 (objectclass=nsManagedRoleDefinition) entries.
+# 1 (objectclass=cosClassicDefinition) entry.
+# 1 (objectclass=cosTemplate) entry.
+# 150 (objectclass=person) entries (all under ou=people,dc=example,dc=com).
+#
+dn: dc=example,dc=com
+objectclass: top
+objectclass: domain
+dc: example
+aci: (target ="ldap:///dc=example,dc=com")(targetattr !=
+ "userPassword")(version 3.0;acl "Anonymous read-search access";
+ allow (read, search, compare)(userdn = "ldap:///anyone");)
+aci: (target="ldap:///dc=example,dc=com") (targetattr =
+ "*")(version 3.0; acl "allow all Admin role"; allow(all) roledn =
+ "ldap:///cn=Directory Administrators,dc=example,dc=com";)
+
+dn: cn=Resource Limits COS,dc=example,dc=com
+objectclass: top
+objectclass: ldapSubEntry
+objectclass: cosSuperDefinition
+objectclass: cosClassicDefinition
+cosTemplateDn: cn=Resource Limits COS,dc=example,dc=com
+cosSpecifier: nsRole
+cosAttribute: nsLookThroughLimit operational
+cosAttribute: nsSizeLimit operational
+cosAttribute: nsTimeLimit operational
+cosAttribute: nsIdleTimeout operational
+cn: Resource Limits COS
+
+dn: cn="cn=Directory Administrators,dc=example,dc=com",cn=Resource Limits COS,dc=example,dc=com
+objectclass: top
+objectclass: ldapSubEntry
+objectclass: cosTemplate
+cn: cn=Directory Administrators,dc=example,dc=com
+cosPriority: 0
+# Directory Administrators are not subject to any resource limits
+nsLookThroughLimit: -1
+nsSizeLimit: -1
+nsTimeLimit: -1
+nsIdleTimeout: -1
+
+dn: cn=Directory Administrators,dc=example,dc=com
+cn: Directory Administrators
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+
+dn: ou=People, dc=example,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: People
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr =
+ "userpassword || telephonenumber || facsimiletelephonenumber")(version 3.0;
+ acl "Allow self entry modification";allow (write)(userdn = "ldap:///self");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn || sn || uid")(targetfilter ="(ou=Accounting)")(version 3.0;
+ acl "Accounting Managers Role Permissions";allow (write) (roledn =
+ "ldap:///cn=Accounting Managers,dc=example,dc=com");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn || sn || uid")(targetfilter ="(ou=Human Resources)")(version 3.0;
+ acl "HR Role Permissions";allow (write)(roledn = "ldap:///cn=HR Managers,
+ dc=example,dc=com
+ ");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn ||sn || uid")(targetfilter ="(ou=Product Testing)")(version 3.0;
+ acl "QA Role Permissions";allow (write)(roledn = "ldap:///cn=QA Managers,
+ dc=example,dc=com");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn || sn || uid")(targetfilter ="(ou=Product Development)")(version 3.0;
+ acl "Engineering Role Permissions";allow (write)(roledn = "ldap:///
+ cn=PD Managers,dc=example,dc=com");)
+
+dn: ou=Location Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Location Views
+description: views categorized by location
+
+dn: ou=Sunnyvale, ou=Location Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Sunnyvale
+nsViewFilter: (l=Sunnyvale)
+description: views categorized by location
+
+dn: ou=Santa Clara, ou=Location Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Santa Clara
+nsViewFilter: (l=Santa Clara)
+description: views categorized by location
+
+dn: ou=Cupertino, ou=Location Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Cupertino
+nsViewFilter: (l=Cupertino)
+description: views categorized by location
+
+dn: ou=Organization Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Organization Views
+description: views categorized by organizational unit
+
+dn: ou=Functional, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Functional
+description: views categorized by organizational unit
+
+dn: ou=Accounting, ou=Functional, ou=Organization Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Accounting
+nsViewFilter: (ou=Accounting)
+description: views categorized by organizational unit
+
+dn: ou=Payroll, ou=Functional, ou=Organization Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Payroll
+nsViewFilter: (ou=Payroll)
+description: views categorized by organizational unit
+
+dn: ou=Human Resources, ou=Functional, ou=Organization Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Human Resources
+nsViewFilter: (ou=Human Resources)
+description: views categorized by organizational unit
+
+dn: ou=Product Testing, ou=Functional, ou=Organization Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Product Testing
+nsViewFilter: (ou=Product Testing)
+description: views categorized by organizational unit
+
+dn: ou=Product Development, ou=Functional, ou=Organization Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Product Development
+nsViewFilter: (ou=Product Development)
+description: views categorized by organizational unit
+
+dn: ou=People in room 3584, ou=Product Development, ou=Functional, ou=Organization Views,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: People in room 3584
+nsViewFilter: (roomnumber=3584)
+description: views categorized by organizational unit
+
+dn: ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Business Unit
+description: views categorized by organizational unit
+
+dn: ou=Directory, ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Directory
+nsViewFilter: (ou=Directory)
+description: views categorized by organizational unit
+
+dn: ou=Mail, ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: Mail
+nsViewFilter: (ou=Mail)
+description: views categorized by organizational unit
+
+dn: ou=CMS, ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: CMS
+nsViewFilter: (ou=CMS)
+description: views categorized by organizational unit
+
+dn: ou=EHS, ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: EHS
+nsViewFilter: (ou=EHS)
+description: views categorized by organizational unit
+
+dn: ou=EHS Accounting, ou=EHS, ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: EHS Accounting
+nsViewFilter: (ou=Accounting)
+description: views categorized by organizational unit
+
+dn: ou=EHS Payroll, ou=EHS, ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: EHS Payroll
+nsViewFilter: (ou=Payroll)
+description: views categorized by organizational unit
+
+dn: ou=EHS Human Resources, ou=EHS, ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: EHS Human Resources
+nsViewFilter: (ou=Human Resources)
+description: views categorized by organizational unit
+
+dn: ou=EHS Product Testing, ou=EHS, ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: EHS Product Testing
+nsViewFilter: (ou=Product Testing)
+description: views categorized by organizational unit
+
+dn: ou=EHS Product Development, ou=EHS, ou=Business Unit, ou=Organization Views, dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+objectclass: nsView
+ou: EHS Product Development
+nsViewFilter: (ou=Product Development)
+description: views categorized by organizational unit
+
+dn: ou=Special Users,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Special Users
+description: Special Administrative Accounts
+
+dn: uid=scarter, ou=People, dc=example,dc=com
+cn: Sam Carter
+sn: Carter
+givenname: Sam
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: scarter
+mail: scarter@example.com
+telephonenumber: +1 408 555 4798
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4612
+userpassword: sprain
+manager: uid=dmiller, ou=People, dc=example,dc=com
+nsRoleDN: cn=Accounting Managers,dc=example,dc=com
+
+dn: uid=tmorris, ou=People, dc=example,dc=com
+cn: Ted Morris
+sn: Morris
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tmorris
+mail: tmorris@example.com
+telephonenumber: +1 408 555 9187
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4117
+userpassword: irrefutable
+manager: uid=dmiller, ou=People, dc=example,dc=com
+nsRoleDN: cn=Accounting Managers,dc=example,dc=com
+
+dn: uid=kvaughan, ou=People, dc=example,dc=com
+cn: Kirsten Vaughan
+sn: Vaughan
+givenname: Kirsten
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kvaughan
+mail: kvaughan@example.com
+telephonenumber: +1 408 555 5625
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2871
+userpassword: bribery
+manager: uid=jvedder, ou=People, dc=example,dc=com
+nsRoleDN: cn=Directory Administrators,dc=example,dc=com
+nsRoleDN: cn=HR Managers,dc=example,dc=com
+
+dn: uid=abergin, ou=People, dc=example,dc=com
+cn: Andy Bergin
+sn: Bergin
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: abergin
+mail: abergin@example.com
+telephonenumber: +1 408 555 8585
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3472
+userpassword: inflict
+manager: uid=ealexand, ou=People, dc=example,dc=com
+nsRoleDN: cn=QA Managers,dc=example,dc=com
+
+dn: uid=dmiller, ou=People, dc=example,dc=com
+cn: David Miller
+sn: Miller
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: dmiller
+mail: dmiller@example.com
+telephonenumber: +1 408 555 9423
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4135
+userpassword: gosling
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: uid=gfarmer, ou=People, dc=example,dc=com
+cn: Gern Farmer
+sn: Farmer
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: gfarmer
+mail: gfarmer@example.com
+telephonenumber: +1 408 555 6201
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1269
+userpassword: ruling
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=kwinters, ou=People, dc=example,dc=com
+cn: Kelly Winters
+sn: Winters
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kwinters
+mail: kwinters@example.com
+telephonenumber: +1 408 555 9069
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4178
+userpassword: forsook
+manager: uid=cnewport, ou=People, dc=example,dc=com
+nsRoleDN: cn=PD Managers,dc=example,dc=com
+
+dn: uid=trigden, ou=People, dc=example,dc=com
+cn: Torrey Rigden
+sn: Rigden
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: trigden
+mail: trigden@example.com
+telephonenumber: +1 408 555 9280
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3584
+userpassword: sensitive
+manager: uid=cnewport, ou=People, dc=example,dc=com
+nsRoleDN: cn=PD Managers,dc=example,dc=com
+
+dn: uid=cschmith, ou=People, dc=example,dc=com
+cn: Chris Schmith
+sn: Schmith
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: cschmith
+mail: cschmith@example.com
+telephonenumber: +1 408 555 8011
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0416
+userpassword: hypotenuse
+manager: uid=jvedder, ou=People, dc=example,dc=com
+nsRoleDN: cn=HR Managers,dc=example,dc=com
+
+dn: uid=jwallace, ou=People, dc=example,dc=com
+cn: Judy Wallace
+sn: Wallace
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jwallace
+mail: jwallace@example.com
+telephonenumber: +1 408 555 0319
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1033
+userpassword: linear
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=jwalker, ou=People, dc=example,dc=com
+cn: John Walker
+sn: Walker
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jwalker
+mail: jwalker@example.com
+telephonenumber: +1 408 555 1476
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3915
+userpassword: dogleg
+manager: uid=ealexand, ou=People, dc=example,dc=com
+nsRoleDN: cn=QA Managers,dc=example,dc=com
+
+dn: uid=tclow, ou=People, dc=example,dc=com
+cn: Torrey Clow
+sn: Clow
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tclow
+mail: tclow@example.com
+telephonenumber: +1 408 555 8825
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4376
+userpassword: cardreader
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=rdaugherty, ou=People, dc=example,dc=com
+cn: Robert Daugherty
+sn: Daugherty
+givenname: Robert
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: rdaugherty
+mail: rdaugherty@example.com
+telephonenumber: +1 408 555 1296
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0194
+userpassword: apples
+manager: uid=trigden, ou=People, dc=example,dc=com
+nsRoleDN: cn=Directory Administrators,dc=example,dc=com
+
+dn: uid=jreuter, ou=People, dc=example,dc=com
+cn: Jayne Reuter
+sn: Reuter
+givenname: Jayne
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jreuter
+mail: jreuter@example.com
+telephonenumber: +1 408 555 1122
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2942
+userpassword: destroy
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=tmason, ou=People, dc=example,dc=com
+cn: Torrey Mason
+sn: Mason
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: tmason
+mail: tmason@example.com
+telephonenumber: +1 408 555 1596
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1124
+userpassword: squatted
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=bhall, ou=People, dc=example,dc=com
+cn: Benjamin Hall
+sn: Hall
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: bhall
+mail: bhall@example.com
+telephonenumber: +1 408 555 6067
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2511
+userpassword: oranges
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=btalbot, ou=People, dc=example,dc=com
+cn: Brad Talbot
+sn: Talbot
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: btalbot
+mail: btalbot@example.com
+telephonenumber: +1 408 555 4992
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3532
+userpassword: trident
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=mward, ou=People, dc=example,dc=com
+cn: Marcus Ward
+sn: Ward
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mward
+mail: mward@example.com
+telephonenumber: +1 408 555 5688
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1707
+userpassword: normal
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=bjablons, ou=People, dc=example,dc=com
+cn: Barbara Jablonski
+sn: Jablonski
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: bjablons
+mail: bjablons@example.com
+telephonenumber: +1 408 555 8815
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0906
+userpassword: strawberry
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=jmcFarla, ou=People, dc=example,dc=com
+cn: Judy McFarland
+sn: McFarland
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: jmcFarla
+mail: jmcFarla@example.com
+telephonenumber: +1 408 555 2567
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 2359
+userpassword: walnut
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=llabonte, ou=People, dc=example,dc=com
+cn: Lee Labonte
+sn: Labonte
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: llabonte
+mail: llabonte@example.com
+telephonenumber: +1 408 555 0957
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2854
+userpassword: sourdough
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=jcampaig, ou=People, dc=example,dc=com
+cn: Jody Campaigne
+sn: Campaigne
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jcampaig
+mail: jcampaig@example.com
+telephonenumber: +1 408 555 1660
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4385
+userpassword: grapevine
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=bhal2, ou=People, dc=example,dc=com
+cn: Barbara Hall
+sn: Hall
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: bhal2
+mail: bhal2@example.com
+telephonenumber: +1 408 555 4491
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2758
+userpassword: truths
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=alutz, ou=People, dc=example,dc=com
+cn: Alexander Lutz
+sn: Lutz
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alutz
+mail: alutz@example.com
+telephonenumber: +1 408 555 6505
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1327
+userpassword: northward
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=btalbo2, ou=People, dc=example,dc=com
+cn: Bjorn Talbot
+sn: Talbot
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: btalbo2
+mail: btalbo2@example.com
+telephonenumber: +1 408 555 4234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1205
+userpassword: corduroy
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=achassin, ou=People, dc=example,dc=com
+cn: Ashley Chassin
+sn: Chassin
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: achassin
+mail: achassin@example.com
+telephonenumber: +1 408 555 9972
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0466
+userpassword: duopolist
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=hmiller, ou=People, dc=example,dc=com
+cn: Harry Miller
+sn: Miller
+givenname: Harry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: hmiller
+mail: hmiller@example.com
+telephonenumber: +1 408 555 9804
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4304
+userpassword: hillock
+manager: uid=kwinters, ou=People, dc=example,dc=com
+nsRoleDN: cn=Directory Administrators,dc=example,dc=com
+
+dn: uid=jcampai2, ou=People, dc=example,dc=com
+cn: Jeffrey Campaigne
+sn: Campaigne
+givenname: Jeffrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jcampai2
+mail: jcampai2@example.com
+telephonenumber: +1 408 555 7393
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 1377
+userpassword: nominee
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=lulrich, ou=People, dc=example,dc=com
+cn: Lee Ulrich
+sn: Ulrich
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: lulrich
+mail: lulrich@example.com
+telephonenumber: +1 408 555 8652
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0985
+userpassword: attribution
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=mlangdon, ou=People, dc=example,dc=com
+cn: Marcus Langdon
+sn: Langdon
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mlangdon
+mail: mlangdon@example.com
+telephonenumber: +1 408 555 6249
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4471
+userpassword: threat
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=striplet, ou=People, dc=example,dc=com
+cn: Stephen Triplett
+sn: Triplett
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: striplet
+mail: striplet@example.com
+telephonenumber: +1 408 555 4519
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3083
+userpassword: compactify
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=gtriplet, ou=People, dc=example,dc=com
+cn: Gern Triplett
+sn: Triplett
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: gtriplet
+mail: gtriplet@example.com
+telephonenumber: +1 408 555 2582
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4023
+userpassword: placeable
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=jfalena, ou=People, dc=example,dc=com
+cn: John Falena
+sn: Falena
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jfalena
+mail: jfalena@example.com
+telephonenumber: +1 408 555 8133
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1917
+userpassword: nightly
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=speterso, ou=People, dc=example,dc=com
+cn: Sue Peterson
+sn: Peterson
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: speterso
+mail: speterso@example.com
+telephonenumber: +1 408 555 3613
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3073
+userpassword: quinine
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=ejohnson, ou=People, dc=example,dc=com
+cn: Emanuel Johnson
+sn: Johnson
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ejohnson
+mail: ejohnson@example.com
+telephonenumber: +1 408 555 3287
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3737
+userpassword: marketwise
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=prigden, ou=People, dc=example,dc=com
+cn: Peter Rigden
+sn: Rigden
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: prigden
+mail: prigden@example.com
+telephonenumber: +1 408 555 5099
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1271
+userpassword: epiphyseal
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=bwalker, ou=People, dc=example,dc=com
+cn: Brad Walker
+sn: Walker
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bwalker
+mail: bwalker@example.com
+telephonenumber: +1 408 555 5476
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3529
+userpassword: interruptible
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=kjensen, ou=People, dc=example,dc=com
+cn: Kurt Jensen
+sn: Jensen
+givenname: Kurt
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kjensen
+mail: kjensen@example.com
+telephonenumber: +1 408 555 6127
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1944
+userpassword: regulatory
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=mlott, ou=People, dc=example,dc=com
+cn: Mike Lott
+sn: Lott
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mlott
+mail: mlott@example.com
+telephonenumber: +1 408 555 2234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0498
+userpassword: cognac
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=cwallace, ou=People, dc=example,dc=com
+cn: Cecil Wallace
+sn: Wallace
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: cwallace
+mail: cwallace@example.com
+telephonenumber: +1 408 555 6438
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0349
+userpassword: quintus
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=tpierce, ou=People, dc=example,dc=com
+cn: Tobias Pierce
+sn: Pierce
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tpierce
+mail: tpierce@example.com
+telephonenumber: +1 408 555 1531
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1383
+userpassword: rascal
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=rbannist, ou=People, dc=example,dc=com
+cn: Richard Bannister
+sn: Bannister
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rbannist
+mail: rbannist@example.com
+telephonenumber: +1 408 555 1833
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0983
+userpassword: demonstrate
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=bplante, ou=People, dc=example,dc=com
+cn: Brian Plante
+sn: Plante
+givenname: Brian
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: bplante
+mail: bplante@example.com
+telephonenumber: +1 408 555 3550
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4654
+userpassword: tangerine
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=rmills, ou=People, dc=example,dc=com
+cn: Randy Mills
+sn: Mills
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rmills
+mail: rmills@example.com
+telephonenumber: +1 408 555 2072
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3823
+userpassword: condescend
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=bschneid, ou=People, dc=example,dc=com
+cn: Benjamin Schneider
+sn: Schneider
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: bschneid
+mail: bschneid@example.com
+telephonenumber: +1 408 555 1012
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4471
+userpassword: biblical
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=skellehe, ou=People, dc=example,dc=com
+cn: Sue Kelleher
+sn: Kelleher
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: skellehe
+mail: skellehe@example.com
+telephonenumber: +1 408 555 3480
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1608
+userpassword: sweltering
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=brentz, ou=People, dc=example,dc=com
+cn: Bertram Rentz
+sn: Rentz
+givenname: Bertram
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: brentz
+mail: brentz@example.com
+telephonenumber: +1 408 555 5526
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0617
+userpassword: diachronic
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=dsmith, ou=People, dc=example,dc=com
+cn: Daniel Smith
+sn: Smith
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: dsmith
+mail: dsmith@example.com
+telephonenumber: +1 408 555 9519
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0368
+userpassword: quantitative
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=scarte2, ou=People, dc=example,dc=com
+cn: Stephen Carter
+sn: Carter
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: scarte2
+mail: scarte2@example.com
+telephonenumber: +1 408 555 6022
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2013
+userpassword: scooter
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=dthorud, ou=People, dc=example,dc=com
+cn: David Thorud
+sn: Thorud
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: dthorud
+mail: dthorud@example.com
+telephonenumber: +1 408 555 6185
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1128
+userpassword: fulcrum
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=ekohler, ou=People, dc=example,dc=com
+cn: Elba Kohler
+sn: Kohler
+givenname: Elba
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: ekohler
+mail: ekohler@example.com
+telephonenumber: +1 408 555 1926
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2721
+userpassword: guildhall
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=lcampbel, ou=People, dc=example,dc=com
+cn: Laurel Campbell
+sn: Campbell
+givenname: Laurel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: lcampbel
+mail: lcampbel@example.com
+telephonenumber: +1 408 555 2537
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 2073
+userpassword: impress
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=tlabonte, ou=People, dc=example,dc=com
+cn: Tim Labonte
+sn: Labonte
+givenname: Tim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tlabonte
+mail: tlabonte@example.com
+telephonenumber: +1 408 555 0058
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1426
+userpassword: express
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=slee, ou=People, dc=example,dc=com
+cn: Scott Lee
+sn: Lee
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: slee
+mail: slee@example.com
+telephonenumber: +1 408 555 2335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1806
+userpassword: revertive
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=bfree, ou=People, dc=example,dc=com
+cn: Bjorn Free
+sn: Free
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfree
+mail: bfree@example.com
+telephonenumber: +1 408 555 8588
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3307
+userpassword: etiquette
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=tschneid, ou=People, dc=example,dc=com
+cn: Torrey Schneider
+sn: Schneider
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tschneid
+mail: tschneid@example.com
+telephonenumber: +1 408 555 7086
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2292
+userpassword: chaperone
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=prose, ou=People, dc=example,dc=com
+cn: Paula Rose
+sn: Rose
+givenname: Paula
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: prose
+mail: prose@example.com
+telephonenumber: +1 408 555 9998
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0542
+userpassword: regatta
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=jhunter, ou=People, dc=example,dc=com
+cn: Janet Hunter
+sn: Hunter
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jhunter
+mail: jhunter@example.com
+telephonenumber: +1 408 555 7665
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4856
+userpassword: nanometer
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=ashelton, ou=People, dc=example,dc=com
+cn: Alexander Shelton
+sn: Shelton
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: ashelton
+mail: ashelton@example.com
+telephonenumber: +1 408 555 1081
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1987
+userpassword: appointe
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=mmcinnis, ou=People, dc=example,dc=com
+cn: Marcus Mcinnis
+sn: Mcinnis
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: mmcinnis
+mail: mmcinnis@example.com
+telephonenumber: +1 408 555 9655
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4818
+userpassword: calcify
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=falbers, ou=People, dc=example,dc=com
+cn: Frank Albers
+sn: Albers
+givenname: Frank
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: falbers
+mail: falbers@example.com
+telephonenumber: +1 408 555 3094
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1439
+userpassword: degradation
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=mschneid, ou=People, dc=example,dc=com
+cn: Martin Schneider
+sn: Schneider
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mschneid
+mail: mschneid@example.com
+telephonenumber: +1 408 555 5017
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3153
+userpassword: motorcycle
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=pcruse, ou=People, dc=example,dc=com
+cn: Patricia Cruse
+sn: Cruse
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: pcruse
+mail: pcruse@example.com
+telephonenumber: +1 408 555 8641
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3967
+userpassword: pauper
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=tkelly, ou=People, dc=example,dc=com
+cn: Timothy Kelly
+sn: Kelly
+givenname: Timothy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: tkelly
+mail: tkelly@example.com
+telephonenumber: +1 408 555 4295
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3107
+userpassword: risible
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=ahel, ou=People, dc=example,dc=com
+cn: Andrew Hel
+sn: Hel
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahel
+mail: ahel@example.com
+telephonenumber: +1 408 555 2666
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0572
+userpassword: sarsaparilla
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=jburrell, ou=People, dc=example,dc=com
+cn: James Burrell
+sn: Burrell
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jburrell
+mail: jburrell@example.com
+telephonenumber: +1 408 555 0751
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4926
+userpassword: degrease
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=smason, ou=People, dc=example,dc=com
+cn: Sue Mason
+sn: Mason
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: smason
+mail: smason@example.com
+telephonenumber: +1 408 555 9780
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4971
+userpassword: sensible
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=ptyler, ou=People, dc=example,dc=com
+cn: Pete Tyler
+sn: Tyler
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ptyler
+mail: ptyler@example.com
+telephonenumber: +1 408 555 3335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0327
+userpassword: vinegar
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=calexand, ou=People, dc=example,dc=com
+cn: Chris Alexander
+sn: Alexander
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: calexand
+mail: calexand@example.com
+telephonenumber: +1 408 555 9438
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2884
+userpassword: dauphin
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=jcruse, ou=People, dc=example,dc=com
+cn: Jim Cruse
+sn: Cruse
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jcruse
+mail: jcruse@example.com
+telephonenumber: +1 408 555 9482
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0083
+userpassword: bridgework
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=kcarter, ou=People, dc=example,dc=com
+cn: Karen Carter
+sn: Carter
+givenname: Karen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kcarter
+mail: kcarter@example.com
+telephonenumber: +1 408 555 4675
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2320
+userpassword: radiosonde
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rfish, ou=People, dc=example,dc=com
+cn: Randy Fish
+sn: Fish
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rfish
+mail: rfish@example.com
+telephonenumber: +1 408 555 9865
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2317
+userpassword: mailbox
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=phunt, ou=People, dc=example,dc=com
+cn: Philip Hunt
+sn: Hunt
+givenname: Philip
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: phunt
+mail: phunt@example.com
+telephonenumber: +1 408 555 1242
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1183
+userpassword: wastewater
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rschneid, ou=People, dc=example,dc=com
+cn: Rachel Schneider
+sn: Schneider
+givenname: Rachel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rschneid
+mail: rschneid@example.com
+telephonenumber: +1 408 555 9908
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4183
+userpassword: decorous
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=bjensen, ou=People, dc=example,dc=com
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: bjensen
+mail: bjensen@example.com
+telephonenumber: +1 408 555 1862
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0209
+userpassword: hifalutin
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=jlange, ou=People, dc=example,dc=com
+cn: Jim Lange
+sn: Lange
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: jlange
+mail: jlange@example.com
+telephonenumber: +1 408 555 0488
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3798
+userpassword: chastity
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rulrich, ou=People, dc=example,dc=com
+cn: Randy Ulrich
+sn: Ulrich
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: rulrich
+mail: rulrich@example.com
+telephonenumber: +1 408 555 5311
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1282
+userpassword: twinkle
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rfrancis, ou=People, dc=example,dc=com
+cn: Richard Francis
+sn: Francis
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rfrancis
+mail: rfrancis@example.com
+telephonenumber: +1 408 555 8157
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3482
+userpassword: hacienda
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=mwhite, ou=People, dc=example,dc=com
+cn: Morgan White
+sn: White
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mwhite
+mail: mwhite@example.com
+telephonenumber: +1 408 555 9620
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3088
+userpassword: staple
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=gjensen, ou=People, dc=example,dc=com
+cn: Gern Jensen
+sn: Jensen
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: gjensen
+mail: gjensen@example.com
+telephonenumber: +1 408 555 3299
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4609
+userpassword: primitive
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=awhite, ou=People, dc=example,dc=com
+cn: Alan White
+sn: White
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: awhite
+mail: awhite@example.com
+telephonenumber: +1 408 555 3232
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0142
+userpassword: placeholder
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=bmaddox, ou=People, dc=example,dc=com
+cn: Barbara Maddox
+sn: Maddox
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bmaddox
+mail: bmaddox@example.com
+telephonenumber: +1 408 555 7783
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2207
+userpassword: feedback
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=mtalbot, ou=People, dc=example,dc=com
+cn: Martin Talbot
+sn: Talbot
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mtalbot
+mail: mtalbot@example.com
+telephonenumber: +1 408 555 9228
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1415
+userpassword: currant
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=jbrown, ou=People, dc=example,dc=com
+cn: Judy Brown
+sn: Brown
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jbrown
+mail: jbrown@example.com
+telephonenumber: +1 408 555 6885
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4224
+userpassword: militiamen
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=jjensen, ou=People, dc=example,dc=com
+cn: Jody Jensen
+sn: Jensen
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jjensen
+mail: jjensen@example.com
+telephonenumber: +1 408 555 7587
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4882
+userpassword: borderland
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=mcarter, ou=People, dc=example,dc=com
+cn: Mike Carter
+sn: Carter
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mcarter
+mail: mcarter@example.com
+telephonenumber: +1 408 555 1846
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3819
+userpassword: mainland
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=dakers, ou=People, dc=example,dc=com
+cn: David Akers
+sn: Akers
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: dakers
+mail: dakers@example.com
+telephonenumber: +1 408 555 4812
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4944
+userpassword: integument
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=sfarmer, ou=People, dc=example,dc=com
+cn: Scott Farmer
+sn: Farmer
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: sfarmer
+mail: sfarmer@example.com
+telephonenumber: +1 408 555 4228
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0019
+userpassword: triumphal
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=dward, ou=People, dc=example,dc=com
+cn: Daniel Ward
+sn: Ward
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: dward
+mail: dward@example.com
+telephonenumber: +1 408 555 5322
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3927
+userpassword: armload
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=tward, ou=People, dc=example,dc=com
+cn: Tobias Ward
+sn: Ward
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tward
+mail: tward@example.com
+telephonenumber: +1 408 555 7202
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2238
+userpassword: cedilla
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=pshelton, ou=People, dc=example,dc=com
+cn: Patricia Shelton
+sn: Shelton
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: pshelton
+mail: pshelton@example.com
+telephonenumber: +1 408 555 6442
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2918
+userpassword: nosedive
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=jrentz, ou=People, dc=example,dc=com
+cn: Jody Rentz
+sn: Rentz
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jrentz
+mail: jrentz@example.com
+telephonenumber: +1 408 555 5829
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3025
+userpassword: meander
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=plorig, ou=People, dc=example,dc=com
+cn: Peter Lorig
+sn: Lorig
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: plorig
+mail: plorig@example.com
+telephonenumber: +1 408 555 0624
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1276
+userpassword: calorimeter
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=ajensen, ou=People, dc=example,dc=com
+cn: Allison Jensen
+sn: Jensen
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: ajensen
+mail: ajensen@example.com
+telephonenumber: +1 408 555 7892
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0784
+userpassword: coltsfoot
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=kschmith, ou=People, dc=example,dc=com
+cn: Kelly Schmith
+sn: Schmith
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kschmith
+mail: kschmith@example.com
+telephonenumber: +1 408 555 9749
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2221
+userpassword: purvey
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=pworrell, ou=People, dc=example,dc=com
+cn: Pete Worrell
+sn: Worrell
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: pworrell
+mail: pworrell@example.com
+telephonenumber: +1 408 555 1637
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2449
+userpassword: solicitous
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=mreuter, ou=People, dc=example,dc=com
+cn: Matthew Reuter
+sn: Reuter
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mreuter
+mail: mreuter@example.com
+telephonenumber: +1 408 555 6879
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 1356
+userpassword: oblivious
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=gtyler, ou=People, dc=example,dc=com
+cn: Gern Tyler
+sn: Tyler
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: gtyler
+mail: gtyler@example.com
+telephonenumber: +1 408 555 1020
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0312
+userpassword: typology
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=tschmith, ou=People, dc=example,dc=com
+cn: Tobias Schmith
+sn: Schmith
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tschmith
+mail: tschmith@example.com
+telephonenumber: +1 408 555 9626
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4607
+userpassword: compost
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=bjense2, ou=People, dc=example,dc=com
+cn: Bjorn Jensen
+sn: Jensen
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bjense2
+mail: bjense2@example.com
+telephonenumber: +1 408 555 5655
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4294
+userpassword: mortgage
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=dswain, ou=People, dc=example,dc=com
+cn: Dietrich Swain
+sn: Swain
+givenname: Dietrich
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: dswain
+mail: dswain@example.com
+telephonenumber: +1 408 555 9222
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4396
+userpassword: freedom
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=ahall, ou=People, dc=example,dc=com
+cn: Andy Hall
+sn: Hall
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahall
+mail: ahall@example.com
+telephonenumber: +1 408 555 6169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3050
+userpassword: slater
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=jmuffly, ou=People, dc=example,dc=com
+cn: Jeff Muffly
+sn: Muffly
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jmuffly
+mail: jmuffly@example.com
+telephonenumber: +1 408 555 5287
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0997
+userpassword: dictate
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=tjensen, ou=People, dc=example,dc=com
+cn: Ted Jensen
+sn: Jensen
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjensen
+mail: tjensen@example.com
+telephonenumber: +1 408 555 8622
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4717
+userpassword: ecosystem
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=ahunter, ou=People, dc=example,dc=com
+cn: Allison Hunter
+sn: Hunter
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: ahunter
+mail: ahunter@example.com
+telephonenumber: +1 408 555 7713
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1213
+userpassword: egregious
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=jgoldste, ou=People, dc=example,dc=com
+cn: Jon Goldstein
+sn: Goldstein
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jgoldste
+mail: jgoldste@example.com
+telephonenumber: +1 408 555 5769
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1454
+userpassword: yellow
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=aworrell, ou=People, dc=example,dc=com
+cn: Alan Worrell
+sn: Worrell
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aworrell
+mail: aworrell@example.com
+telephonenumber: +1 408 555 1591
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3966
+userpassword: gargoyle
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=wlutz, ou=People, dc=example,dc=com
+cn: Wendy Lutz
+sn: Lutz
+givenname: Wendy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: wlutz
+mail: wlutz@example.com
+telephonenumber: +1 408 555 3358
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4912
+userpassword: bassinet
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=jlutz, ou=People, dc=example,dc=com
+cn: Janet Lutz
+sn: Lutz
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jlutz
+mail: jlutz@example.com
+telephonenumber: +1 408 555 4902
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2544
+userpassword: autumn
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=dlangdon, ou=People, dc=example,dc=com
+cn: Dan Langdon
+sn: Langdon
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: dlangdon
+mail: dlangdon@example.com
+telephonenumber: +1 408 555 7044
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3263
+userpassword: botulin
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=aknutson, ou=People, dc=example,dc=com
+cn: Ashley Knutson
+sn: Knutson
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aknutson
+mail: aknutson@example.com
+telephonenumber: +1 408 555 2169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4736
+userpassword: maltose
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=kmcinnis, ou=People, dc=example,dc=com
+cn: Kelly Mcinnis
+sn: Mcinnis
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: kmcinnis
+mail: kmcinnis@example.com
+telephonenumber: +1 408 555 8596
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4312
+userpassword: stargaze
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=tcouzens, ou=People, dc=example,dc=com
+cn: Trent Couzens
+sn: Couzens
+givenname: Trent
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tcouzens
+mail: tcouzens@example.com
+telephonenumber: +1 408 555 8401
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3994
+userpassword: tambourine
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=lstockto, ou=People, dc=example,dc=com
+cn: Lee Stockton
+sn: Stockton
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: lstockto
+mail: lstockto@example.com
+telephonenumber: +1 408 555 0518
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0169
+userpassword: brooklyn
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=jbourke, ou=People, dc=example,dc=com
+cn: Jon Bourke
+sn: Bourke
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jbourke
+mail: jbourke@example.com
+telephonenumber: +1 408 555 8541
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0034
+userpassword: brainwash
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=dlanoway, ou=People, dc=example,dc=com
+cn: Dan Lanoway
+sn: Lanoway
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: dlanoway
+mail: dlanoway@example.com
+telephonenumber: +1 408 555 2017
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3540
+userpassword: manhattan
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=kcope, ou=People, dc=example,dc=com
+cn: Karl Cope
+sn: Cope
+givenname: Karl
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kcope
+mail: kcope@example.com
+telephonenumber: +1 408 555 2709
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 3040
+userpassword: forfeiture
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=abarnes, ou=People, dc=example,dc=com
+cn: Anne-Louise Barnes
+sn: Barnes
+givenname: Anne-Louise
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: abarnes
+mail: abarnes@example.com
+telephonenumber: +1 408 555 9445
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2290
+userpassword: chevron
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=rjensen, ou=People, dc=example,dc=com
+cn: Richard Jensen
+sn: Jensen
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: rjensen
+mail: rjensen@example.com
+telephonenumber: +1 408 555 5957
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2631
+userpassword: disciplinarian
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=phun2, ou=People, dc=example,dc=com
+cn: Pete Hunt
+sn: Hunt
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: phun2
+mail: phun2@example.com
+telephonenumber: +1 408 555 0342
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0087
+userpassword: absorb
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=mvaughan, ou=People, dc=example,dc=com
+cn: Matthew Vaughan
+sn: Vaughan
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: mvaughan
+mail: mvaughan@example.com
+telephonenumber: +1 408 555 4692
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4508
+userpassword: submitted
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=jlut2, ou=People, dc=example,dc=com
+cn: James Lutz
+sn: Lutz
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jlut2
+mail: jlut2@example.com
+telephonenumber: +1 408 555 9689
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3541
+userpassword: shrank
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=mjablons, ou=People, dc=example,dc=com
+cn: Morgan Jablonski
+sn: Jablonski
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mjablons
+mail: mjablons@example.com
+telephonenumber: +1 408 555 0813
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3160
+userpassword: minimal
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=pchassin, ou=People, dc=example,dc=com
+cn: Peter Chassin
+sn: Chassin
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: pchassin
+mail: pchassin@example.com
+telephonenumber: +1 408 555 2816
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4524
+userpassword: barbital
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=dcope, ou=People, dc=example,dc=com
+cn: Dan Cope
+sn: Cope
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: dcope
+mail: dcope@example.com
+telephonenumber: +1 408 555 9813
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1737
+userpassword: snifter
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=jrent2, ou=People, dc=example,dc=com
+cn: Judy Rentz
+sn: Rentz
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jrent2
+mail: jrent2@example.com
+telephonenumber: +1 408 555 2523
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4405
+userpassword: tachistoscope
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=tcruse, ou=People, dc=example,dc=com
+cn: Tobias Cruse
+sn: Cruse
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tcruse
+mail: tcruse@example.com
+telephonenumber: +1 408 555 5980
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4191
+userpassword: flinty
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=eward, ou=People, dc=example,dc=com
+cn: Eric Ward
+sn: Ward
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: eward
+mail: eward@example.com
+telephonenumber: +1 408 555 2320
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4874
+userpassword: episcopal
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=ttully, ou=People, dc=example,dc=com
+cn: Torrey Tully
+sn: Tully
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: ttully
+mail: ttully@example.com
+telephonenumber: +1 408 555 2274
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3924
+userpassword: schooner
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=charvey, ou=People, dc=example,dc=com
+cn: Cecil Harvey
+sn: Harvey
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: charvey
+mail: charvey@example.com
+telephonenumber: +1 408 555 1815
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4583
+userpassword: journalese
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=rfisher, ou=People, dc=example,dc=com
+cn: Randy Fisher
+sn: Fisher
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: rfisher
+mail: rfisher@example.com
+telephonenumber: +1 408 555 1506
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1579
+userpassword: pomegranate
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=alangdon, ou=People, dc=example,dc=com
+cn: Andrew Langdon
+sn: Langdon
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alangdon
+mail: alangdon@example.com
+telephonenumber: +1 408 555 8289
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2254
+userpassword: muzzle
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=drose, ou=People, dc=example,dc=com
+cn: David Rose
+sn: Rose
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: drose
+mail: drose@example.com
+telephonenumber: +1 408 555 3963
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4012
+userpassword: gubernatorial
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=polfield, ou=People, dc=example,dc=com
+cn: Peter Olfield
+sn: Olfield
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: polfield
+mail: polfield@example.com
+telephonenumber: +1 408 555 8231
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1376
+userpassword: monologue
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=awalker, ou=People, dc=example,dc=com
+cn: Andy Walker
+sn: Walker
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: awalker
+mail: awalker@example.com
+telephonenumber: +1 408 555 9199
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0061
+userpassword: detonable
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=lrentz, ou=People, dc=example,dc=com
+cn: Lex Rentz
+sn: Rentz
+givenname: Lex
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: lrentz
+mail: lrentz@example.com
+telephonenumber: +1 408 555 2019
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2203
+userpassword: calcium
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=jvaughan, ou=People, dc=example,dc=com
+cn: Jeff Vaughan
+sn: Vaughan
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jvaughan
+mail: jvaughan@example.com
+telephonenumber: +1 408 555 4543
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1734
+userpassword: appoint
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=bfrancis, ou=People, dc=example,dc=com
+cn: Barbara Francis
+sn: Francis
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfrancis
+mail: bfrancis@example.com
+telephonenumber: +1 408 555 9111
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3743
+userpassword: holystone
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=ewalker, ou=People, dc=example,dc=com
+cn: Eric Walker
+sn: Walker
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: ewalker
+mail: ewalker@example.com
+telephonenumber: +1 408 555 6387
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2295
+userpassword: beguile
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=tjames, ou=People, dc=example,dc=com
+cn: Tobias James
+sn: James
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjames
+mail: tjames@example.com
+telephonenumber: +1 408 555 2458
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0730
+userpassword: turtle
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=brigden, ou=People, dc=example,dc=com
+cn: Bjorn Rigden
+sn: Rigden
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: brigden
+mail: brigden@example.com
+telephonenumber: +1 408 555 5263
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1643
+userpassword: purple
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=ecruse, ou=People, dc=example,dc=com
+cn: Eric Cruse
+sn: Cruse
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ecruse
+mail: ecruse@example.com
+telephonenumber: +1 408 555 0648
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4233
+userpassword: platelet
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=rjense2, ou=People, dc=example,dc=com
+cn: Randy Jensen
+sn: Jensen
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: rjense2
+mail: rjense2@example.com
+telephonenumber: +1 408 555 9045
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1984
+userpassword: transpose
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=rhunt, ou=People, dc=example,dc=com
+cn: Richard Hunt
+sn: Hunt
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rhunt
+mail: rhunt@example.com
+telephonenumber: +1 408 555 0139
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 0718
+userpassword: becloud
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=bparker, ou=People, dc=example,dc=com
+cn: Barry Parker
+sn: Parker
+givenname: Barry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: bparker
+mail: bparker@example.com
+telephonenumber: +1 408 555 4647
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1148
+userpassword: lenticular
+
+dn: uid=ealexand, ou=People, dc=example,dc=com
+cn: Erin Alexander
+sn: Alexander
+givenname: Erin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ealexand
+mail: ealexand@example.com
+telephonenumber: +1 408 555 5563
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2434
+userpassword: galactose
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: uid=mtyler, ou=People, dc=example,dc=com
+cn: Matthew Tyler
+sn: Tyler
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: mtyler
+mail: mtyler@example.com
+telephonenumber: +1 408 555 7907
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2701
+userpassword: instantiate
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=elott, ou=People, dc=example,dc=com
+cn: Emanuel Lott
+sn: Lott
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: elott
+mail: elott@example.com
+telephonenumber: +1 408 555 0932
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3906
+userpassword: holdout
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=cnewport, ou=People, dc=example,dc=com
+cn: Christoph Newport
+sn: Newport
+givenname: Christoph
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: cnewport
+mail: cnewport@example.com
+telephonenumber: +1 408 555 0066
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0056
+userpassword: expertise
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: uid=jvedder, ou=People, dc=example,dc=com
+cn: Jeff Vedder
+sn: Vedder
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jvedder
+mail: jvedder@example.com
+telephonenumber: +1 408 555 4668
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3445
+userpassword: befitting
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: cn=Accounting Managers,dc=example,dc=com
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+cn: Accounting Managers
+description: People who can manage accounting entries
+
+dn: cn=HR Managers,dc=example,dc=com
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+cn: HR Managers
+description: People who can manage HR entries
+
+dn: cn=QA Managers,dc=example,dc=com
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+cn: QA Managers
+description: People who can manage QA entries
+
+dn: cn=PD Managers,dc=example,dc=com
+objectclass: top
+objectclass: LDAPsubentry
+objectclass: nsRoleDefinition
+objectclass: nsSimpleRoleDefinition
+objectclass: nsManagedRoleDefinition
+cn: PD Managers
+description: People who can manage engineer entries
+
+dn: ou=Netscape Servers,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Netscape Servers
+description: Standard branch for Netscape Server registration
diff --git a/ldap/ldif/Example.ldif b/ldap/ldif/Example.ldif
new file mode 100644
index 00000000..71196a06
--- /dev/null
+++ b/ldap/ldif/Example.ldif
@@ -0,0 +1,2981 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# dc=example,dc=com sample LDIF file
+#
+# Notes:
+# 160 total entries.
+# 1 (objectclass=domain) entry (dc=example,dc=com).
+# 4 (objectclass=organizationalunit) entries.
+# 5 (objectclass=groupofuniquenames) entries.
+# 150 (objectclass=person) entries (all under ou=people,dc=example,dc=com).
+#
+dn: dc=example,dc=com
+objectclass: top
+objectclass: domain
+dc: example
+aci: (target ="ldap:///dc=example,dc=com")(targetattr !=
+ "userPassword")(version 3.0;acl "Anonymous read-search access";
+ allow (read, search, compare)(userdn = "ldap:///anyone");)
+aci: (target="ldap:///dc=example,dc=com") (targetattr =
+ "*")(version 3.0; acl "allow all Admin group"; allow(all) groupdn =
+ "ldap:///cn=Directory Administrators,ou=Groups,dc=example,dc=com";)
+
+dn: ou=Groups, dc=example,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: Groups
+
+dn: cn=Directory Administrators, ou=Groups, dc=example,dc=com
+cn: Directory Administrators
+objectclass: top
+objectclass: groupofuniquenames
+ou: Groups
+uniquemember: uid=kvaughan, ou=People, dc=example,dc=com
+uniquemember: uid=rdaugherty, ou=People, dc=example,dc=com
+uniquemember: uid=hmiller, ou=People, dc=example,dc=com
+
+dn: ou=People, dc=example,dc=com
+objectclass: top
+objectclass: organizationalunit
+ou: People
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr =
+ "userpassword || telephonenumber || facsimiletelephonenumber")(version 3.0;
+ acl "Allow self entry modification";allow (write)(userdn = "ldap:///self");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn || sn || uid")(targetfilter ="(ou=Accounting)")(version 3.0;
+ acl "Accounting Managers Group Permissions";allow (write) (groupdn =
+ "ldap:///cn=Accounting Managers,ou=groups,dc=example,dc=com");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn || sn || uid")(targetfilter ="(ou=Human Resources)")(version 3.0;
+ acl "HR Group Permissions";allow (write)(groupdn = "ldap:///cn=HR Managers,
+ ou=groups,dc=example,dc=com
+ ");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn ||sn || uid")(targetfilter ="(ou=Product Testing)")(version 3.0;
+ acl "QA Group Permissions";allow (write)(groupdn = "ldap:///cn=QA Managers,
+ ou=groups,dc=example,dc=com");)
+aci: (target ="ldap:///ou=People,dc=example,dc=com")(targetattr !=
+ "cn || sn || uid")(targetfilter ="(ou=Product Development)")(version 3.0;
+ acl "Engineering Group Permissions";allow (write)(groupdn = "ldap:///
+ cn=PD Managers,ou=groups,dc=example,dc=com");)
+
+dn: ou=Special Users,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Special Users
+description: Special Administrative Accounts
+
+dn: uid=scarter, ou=People, dc=example,dc=com
+cn: Sam Carter
+sn: Carter
+givenname: Sam
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: scarter
+mail: scarter@example.com
+telephonenumber: +1 408 555 4798
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4612
+userpassword: sprain
+manager: uid=dmiller, ou=People, dc=example,dc=com
+
+dn: uid=tmorris, ou=People, dc=example,dc=com
+cn: Ted Morris
+sn: Morris
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tmorris
+mail: tmorris@example.com
+telephonenumber: +1 408 555 9187
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4117
+userpassword: irrefutable
+manager: uid=dmiller, ou=People, dc=example,dc=com
+
+dn: uid=kvaughan, ou=People, dc=example,dc=com
+cn: Kirsten Vaughan
+sn: Vaughan
+givenname: Kirsten
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kvaughan
+mail: kvaughan@example.com
+telephonenumber: +1 408 555 5625
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2871
+userpassword: bribery
+manager: uid=jvedder, ou=People, dc=example,dc=com
+# Kirsten is a Directory Administrator and therefore should not
+# be subject to any resource limits.
+nsLookThroughLimit: -1
+nsSizeLimit: -1
+nsTimeLimit: -1
+nsIdleTimeout: -1
+
+dn: uid=abergin, ou=People, dc=example,dc=com
+cn: Andy Bergin
+sn: Bergin
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: abergin
+mail: abergin@example.com
+telephonenumber: +1 408 555 8585
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3472
+userpassword: inflict
+manager: uid=ealexand, ou=People, dc=example,dc=com
+
+dn: uid=dmiller, ou=People, dc=example,dc=com
+cn: David Miller
+sn: Miller
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: dmiller
+mail: dmiller@example.com
+telephonenumber: +1 408 555 9423
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4135
+userpassword: gosling
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: uid=gfarmer, ou=People, dc=example,dc=com
+cn: Gern Farmer
+sn: Farmer
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: gfarmer
+mail: gfarmer@example.com
+telephonenumber: +1 408 555 6201
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1269
+userpassword: ruling
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=kwinters, ou=People, dc=example,dc=com
+cn: Kelly Winters
+sn: Winters
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kwinters
+mail: kwinters@example.com
+telephonenumber: +1 408 555 9069
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4178
+userpassword: forsook
+manager: uid=cnewport, ou=People, dc=example,dc=com
+
+dn: uid=trigden, ou=People, dc=example,dc=com
+cn: Torrey Rigden
+sn: Rigden
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: trigden
+mail: trigden@example.com
+telephonenumber: +1 408 555 9280
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3584
+userpassword: sensitive
+manager: uid=cnewport, ou=People, dc=example,dc=com
+
+dn: uid=cschmith, ou=People, dc=example,dc=com
+cn: Chris Schmith
+sn: Schmith
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: cschmith
+mail: cschmith@example.com
+telephonenumber: +1 408 555 8011
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0416
+userpassword: hypotenuse
+manager: uid=jvedder, ou=People, dc=example,dc=com
+
+dn: uid=jwallace, ou=People, dc=example,dc=com
+cn: Judy Wallace
+sn: Wallace
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jwallace
+mail: jwallace@example.com
+telephonenumber: +1 408 555 0319
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1033
+userpassword: linear
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=jwalker, ou=People, dc=example,dc=com
+cn: John Walker
+sn: Walker
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jwalker
+mail: jwalker@example.com
+telephonenumber: +1 408 555 1476
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3915
+userpassword: dogleg
+manager: uid=ealexand, ou=People, dc=example,dc=com
+
+dn: uid=tclow, ou=People, dc=example,dc=com
+cn: Torrey Clow
+sn: Clow
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tclow
+mail: tclow@example.com
+telephonenumber: +1 408 555 8825
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4376
+userpassword: cardreader
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=rdaugherty, ou=People, dc=example,dc=com
+cn: Robert Daugherty
+sn: Daugherty
+givenname: Robert
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: rdaugherty
+mail: rdaugherty@example.com
+telephonenumber: +1 408 555 1296
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0194
+userpassword: apples
+manager: uid=trigden, ou=People, dc=example,dc=com
+# Robert is a Directory Administrator and therefore should not
+# be subject to any resource limits.
+nsLookThroughLimit: -1
+nsSizeLimit: -1
+nsTimeLimit: -1
+nsIdleTimeout: -1
+
+dn: uid=jreuter, ou=People, dc=example,dc=com
+cn: Jayne Reuter
+sn: Reuter
+givenname: Jayne
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Cupertino
+uid: jreuter
+mail: jreuter@example.com
+telephonenumber: +1 408 555 1122
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2942
+userpassword: destroy
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=tmason, ou=People, dc=example,dc=com
+cn: Torrey Mason
+sn: Mason
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: tmason
+mail: tmason@example.com
+telephonenumber: +1 408 555 1596
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1124
+userpassword: squatted
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=bhall, ou=People, dc=example,dc=com
+cn: Benjamin Hall
+sn: Hall
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: bhall
+mail: bhall@example.com
+telephonenumber: +1 408 555 6067
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2511
+userpassword: oranges
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=btalbot, ou=People, dc=example,dc=com
+cn: Brad Talbot
+sn: Talbot
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: btalbot
+mail: btalbot@example.com
+telephonenumber: +1 408 555 4992
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3532
+userpassword: trident
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=mward, ou=People, dc=example,dc=com
+cn: Marcus Ward
+sn: Ward
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mward
+mail: mward@example.com
+telephonenumber: +1 408 555 5688
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1707
+userpassword: normal
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=bjablons, ou=People, dc=example,dc=com
+cn: Barbara Jablonski
+sn: Jablonski
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: bjablons
+mail: bjablons@example.com
+telephonenumber: +1 408 555 8815
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0906
+userpassword: strawberry
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=jmcFarla, ou=People, dc=example,dc=com
+cn: Judy McFarland
+sn: McFarland
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: jmcFarla
+mail: jmcFarla@example.com
+telephonenumber: +1 408 555 2567
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 2359
+userpassword: walnut
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=llabonte, ou=People, dc=example,dc=com
+cn: Lee Labonte
+sn: Labonte
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: llabonte
+mail: llabonte@example.com
+telephonenumber: +1 408 555 0957
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2854
+userpassword: sourdough
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=jcampaig, ou=People, dc=example,dc=com
+cn: Jody Campaigne
+sn: Campaigne
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jcampaig
+mail: jcampaig@example.com
+telephonenumber: +1 408 555 1660
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4385
+userpassword: grapevine
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=bhal2, ou=People, dc=example,dc=com
+cn: Barbara Hall
+sn: Hall
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: bhal2
+mail: bhal2@example.com
+telephonenumber: +1 408 555 4491
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2758
+userpassword: truths
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=alutz, ou=People, dc=example,dc=com
+cn: Alexander Lutz
+sn: Lutz
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alutz
+mail: alutz@example.com
+telephonenumber: +1 408 555 6505
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1327
+userpassword: northward
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=btalbo2, ou=People, dc=example,dc=com
+cn: Bjorn Talbot
+sn: Talbot
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: btalbo2
+mail: btalbo2@example.com
+telephonenumber: +1 408 555 4234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1205
+userpassword: corduroy
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=achassin, ou=People, dc=example,dc=com
+cn: Ashley Chassin
+sn: Chassin
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: achassin
+mail: achassin@example.com
+telephonenumber: +1 408 555 9972
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0466
+userpassword: duopolist
+manager: uid=trigden, ou=People, dc=example,dc=com
+
+dn: uid=hmiller, ou=People, dc=example,dc=com
+cn: Harry Miller
+sn: Miller
+givenname: Harry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: hmiller
+mail: hmiller@example.com
+telephonenumber: +1 408 555 9804
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4304
+userpassword: hillock
+manager: uid=kwinters, ou=People, dc=example,dc=com
+# Harry is a Directory Administrator and therefore should not
+# be subject to any resource limits.
+nsLookThroughLimit: -1
+nsSizeLimit: -1
+nsTimeLimit: -1
+nsIdleTimeout: -1
+
+dn: uid=jcampai2, ou=People, dc=example,dc=com
+cn: Jeffrey Campaigne
+sn: Campaigne
+givenname: Jeffrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jcampai2
+mail: jcampai2@example.com
+telephonenumber: +1 408 555 7393
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 1377
+userpassword: nominee
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=lulrich, ou=People, dc=example,dc=com
+cn: Lee Ulrich
+sn: Ulrich
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: lulrich
+mail: lulrich@example.com
+telephonenumber: +1 408 555 8652
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0985
+userpassword: attribution
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=mlangdon, ou=People, dc=example,dc=com
+cn: Marcus Langdon
+sn: Langdon
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mlangdon
+mail: mlangdon@example.com
+telephonenumber: +1 408 555 6249
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4471
+userpassword: threat
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=striplet, ou=People, dc=example,dc=com
+cn: Stephen Triplett
+sn: Triplett
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: striplet
+mail: striplet@example.com
+telephonenumber: +1 408 555 4519
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3083
+userpassword: compactify
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=gtriplet, ou=People, dc=example,dc=com
+cn: Gern Triplett
+sn: Triplett
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: gtriplet
+mail: gtriplet@example.com
+telephonenumber: +1 408 555 2582
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4023
+userpassword: placeable
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=jfalena, ou=People, dc=example,dc=com
+cn: John Falena
+sn: Falena
+givenname: John
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jfalena
+mail: jfalena@example.com
+telephonenumber: +1 408 555 8133
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1917
+userpassword: nightly
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=speterso, ou=People, dc=example,dc=com
+cn: Sue Peterson
+sn: Peterson
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: speterso
+mail: speterso@example.com
+telephonenumber: +1 408 555 3613
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3073
+userpassword: quinine
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=ejohnson, ou=People, dc=example,dc=com
+cn: Emanuel Johnson
+sn: Johnson
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ejohnson
+mail: ejohnson@example.com
+telephonenumber: +1 408 555 3287
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 3737
+userpassword: marketwise
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=prigden, ou=People, dc=example,dc=com
+cn: Peter Rigden
+sn: Rigden
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: prigden
+mail: prigden@example.com
+telephonenumber: +1 408 555 5099
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1271
+userpassword: epiphyseal
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=bwalker, ou=People, dc=example,dc=com
+cn: Brad Walker
+sn: Walker
+givenname: Brad
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bwalker
+mail: bwalker@example.com
+telephonenumber: +1 408 555 5476
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3529
+userpassword: interruptible
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=kjensen, ou=People, dc=example,dc=com
+cn: Kurt Jensen
+sn: Jensen
+givenname: Kurt
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: kjensen
+mail: kjensen@example.com
+telephonenumber: +1 408 555 6127
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1944
+userpassword: regulatory
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=mlott, ou=People, dc=example,dc=com
+cn: Mike Lott
+sn: Lott
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mlott
+mail: mlott@example.com
+telephonenumber: +1 408 555 2234
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0498
+userpassword: cognac
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=cwallace, ou=People, dc=example,dc=com
+cn: Cecil Wallace
+sn: Wallace
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: cwallace
+mail: cwallace@example.com
+telephonenumber: +1 408 555 6438
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0349
+userpassword: quintus
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=tpierce, ou=People, dc=example,dc=com
+cn: Tobias Pierce
+sn: Pierce
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tpierce
+mail: tpierce@example.com
+telephonenumber: +1 408 555 1531
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1383
+userpassword: rascal
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=rbannist, ou=People, dc=example,dc=com
+cn: Richard Bannister
+sn: Bannister
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rbannist
+mail: rbannist@example.com
+telephonenumber: +1 408 555 1833
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0983
+userpassword: demonstrate
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=bplante, ou=People, dc=example,dc=com
+cn: Brian Plante
+sn: Plante
+givenname: Brian
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: bplante
+mail: bplante@example.com
+telephonenumber: +1 408 555 3550
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4654
+userpassword: tangerine
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=rmills, ou=People, dc=example,dc=com
+cn: Randy Mills
+sn: Mills
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rmills
+mail: rmills@example.com
+telephonenumber: +1 408 555 2072
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3823
+userpassword: condescend
+manager: uid=kwinters, ou=People, dc=example,dc=com
+
+dn: uid=bschneid, ou=People, dc=example,dc=com
+cn: Benjamin Schneider
+sn: Schneider
+givenname: Benjamin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: bschneid
+mail: bschneid@example.com
+telephonenumber: +1 408 555 1012
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4471
+userpassword: biblical
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=skellehe, ou=People, dc=example,dc=com
+cn: Sue Kelleher
+sn: Kelleher
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: skellehe
+mail: skellehe@example.com
+telephonenumber: +1 408 555 3480
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1608
+userpassword: sweltering
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=brentz, ou=People, dc=example,dc=com
+cn: Bertram Rentz
+sn: Rentz
+givenname: Bertram
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: brentz
+mail: brentz@example.com
+telephonenumber: +1 408 555 5526
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0617
+userpassword: diachronic
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=dsmith, ou=People, dc=example,dc=com
+cn: Daniel Smith
+sn: Smith
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: dsmith
+mail: dsmith@example.com
+telephonenumber: +1 408 555 9519
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0368
+userpassword: quantitative
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=scarte2, ou=People, dc=example,dc=com
+cn: Stephen Carter
+sn: Carter
+givenname: Stephen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: scarte2
+mail: scarte2@example.com
+telephonenumber: +1 408 555 6022
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2013
+userpassword: scooter
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=dthorud, ou=People, dc=example,dc=com
+cn: David Thorud
+sn: Thorud
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: dthorud
+mail: dthorud@example.com
+telephonenumber: +1 408 555 6185
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1128
+userpassword: fulcrum
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=ekohler, ou=People, dc=example,dc=com
+cn: Elba Kohler
+sn: Kohler
+givenname: Elba
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: ekohler
+mail: ekohler@example.com
+telephonenumber: +1 408 555 1926
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2721
+userpassword: guildhall
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=lcampbel, ou=People, dc=example,dc=com
+cn: Laurel Campbell
+sn: Campbell
+givenname: Laurel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: lcampbel
+mail: lcampbel@example.com
+telephonenumber: +1 408 555 2537
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 2073
+userpassword: impress
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=tlabonte, ou=People, dc=example,dc=com
+cn: Tim Labonte
+sn: Labonte
+givenname: Tim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tlabonte
+mail: tlabonte@example.com
+telephonenumber: +1 408 555 0058
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1426
+userpassword: express
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=slee, ou=People, dc=example,dc=com
+cn: Scott Lee
+sn: Lee
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: slee
+mail: slee@example.com
+telephonenumber: +1 408 555 2335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 1806
+userpassword: revertive
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=bfree, ou=People, dc=example,dc=com
+cn: Bjorn Free
+sn: Free
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfree
+mail: bfree@example.com
+telephonenumber: +1 408 555 8588
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3307
+userpassword: etiquette
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=tschneid, ou=People, dc=example,dc=com
+cn: Torrey Schneider
+sn: Schneider
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tschneid
+mail: tschneid@example.com
+telephonenumber: +1 408 555 7086
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2292
+userpassword: chaperone
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=prose, ou=People, dc=example,dc=com
+cn: Paula Rose
+sn: Rose
+givenname: Paula
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: prose
+mail: prose@example.com
+telephonenumber: +1 408 555 9998
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 0542
+userpassword: regatta
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=jhunter, ou=People, dc=example,dc=com
+cn: Janet Hunter
+sn: Hunter
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jhunter
+mail: jhunter@example.com
+telephonenumber: +1 408 555 7665
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4856
+userpassword: nanometer
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=ashelton, ou=People, dc=example,dc=com
+cn: Alexander Shelton
+sn: Shelton
+givenname: Alexander
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: ashelton
+mail: ashelton@example.com
+telephonenumber: +1 408 555 1081
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1987
+userpassword: appointe
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=mmcinnis, ou=People, dc=example,dc=com
+cn: Marcus Mcinnis
+sn: Mcinnis
+givenname: Marcus
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: mmcinnis
+mail: mmcinnis@example.com
+telephonenumber: +1 408 555 9655
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4818
+userpassword: calcify
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=falbers, ou=People, dc=example,dc=com
+cn: Frank Albers
+sn: Albers
+givenname: Frank
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: falbers
+mail: falbers@example.com
+telephonenumber: +1 408 555 3094
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1439
+userpassword: degradation
+manager: uid=scarter, ou=People, dc=example,dc=com
+
+dn: uid=mschneid, ou=People, dc=example,dc=com
+cn: Martin Schneider
+sn: Schneider
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mschneid
+mail: mschneid@example.com
+telephonenumber: +1 408 555 5017
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 3153
+userpassword: motorcycle
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=pcruse, ou=People, dc=example,dc=com
+cn: Patricia Cruse
+sn: Cruse
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: pcruse
+mail: pcruse@example.com
+telephonenumber: +1 408 555 8641
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3967
+userpassword: pauper
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=tkelly, ou=People, dc=example,dc=com
+cn: Timothy Kelly
+sn: Kelly
+givenname: Timothy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+l: Santa Clara
+uid: tkelly
+mail: tkelly@example.com
+telephonenumber: +1 408 555 4295
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3107
+userpassword: risible
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=ahel, ou=People, dc=example,dc=com
+cn: Andrew Hel
+sn: Hel
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahel
+mail: ahel@example.com
+telephonenumber: +1 408 555 2666
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0572
+userpassword: sarsaparilla
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=jburrell, ou=People, dc=example,dc=com
+cn: James Burrell
+sn: Burrell
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jburrell
+mail: jburrell@example.com
+telephonenumber: +1 408 555 0751
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4926
+userpassword: degrease
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=smason, ou=People, dc=example,dc=com
+cn: Sue Mason
+sn: Mason
+givenname: Sue
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: smason
+mail: smason@example.com
+telephonenumber: +1 408 555 9780
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4971
+userpassword: sensible
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=ptyler, ou=People, dc=example,dc=com
+cn: Pete Tyler
+sn: Tyler
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ptyler
+mail: ptyler@example.com
+telephonenumber: +1 408 555 3335
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0327
+userpassword: vinegar
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=calexand, ou=People, dc=example,dc=com
+cn: Chris Alexander
+sn: Alexander
+givenname: Chris
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: calexand
+mail: calexand@example.com
+telephonenumber: +1 408 555 9438
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2884
+userpassword: dauphin
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=jcruse, ou=People, dc=example,dc=com
+cn: Jim Cruse
+sn: Cruse
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jcruse
+mail: jcruse@example.com
+telephonenumber: +1 408 555 9482
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0083
+userpassword: bridgework
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=kcarter, ou=People, dc=example,dc=com
+cn: Karen Carter
+sn: Carter
+givenname: Karen
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kcarter
+mail: kcarter@example.com
+telephonenumber: +1 408 555 4675
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 2320
+userpassword: radiosonde
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rfish, ou=People, dc=example,dc=com
+cn: Randy Fish
+sn: Fish
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rfish
+mail: rfish@example.com
+telephonenumber: +1 408 555 9865
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2317
+userpassword: mailbox
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=phunt, ou=People, dc=example,dc=com
+cn: Philip Hunt
+sn: Hunt
+givenname: Philip
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: phunt
+mail: phunt@example.com
+telephonenumber: +1 408 555 1242
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 1183
+userpassword: wastewater
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rschneid, ou=People, dc=example,dc=com
+cn: Rachel Schneider
+sn: Schneider
+givenname: Rachel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: rschneid
+mail: rschneid@example.com
+telephonenumber: +1 408 555 9908
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4183
+userpassword: decorous
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=bjensen, ou=People, dc=example,dc=com
+cn: Barbara Jensen
+cn: Babs Jensen
+sn: Jensen
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: bjensen
+mail: bjensen@example.com
+telephonenumber: +1 408 555 1862
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 0209
+userpassword: hifalutin
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=jlange, ou=People, dc=example,dc=com
+cn: Jim Lange
+sn: Lange
+givenname: Jim
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: jlange
+mail: jlange@example.com
+telephonenumber: +1 408 555 0488
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3798
+userpassword: chastity
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rulrich, ou=People, dc=example,dc=com
+cn: Randy Ulrich
+sn: Ulrich
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: rulrich
+mail: rulrich@example.com
+telephonenumber: +1 408 555 5311
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1282
+userpassword: twinkle
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=rfrancis, ou=People, dc=example,dc=com
+cn: Richard Francis
+sn: Francis
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rfrancis
+mail: rfrancis@example.com
+telephonenumber: +1 408 555 8157
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3482
+userpassword: hacienda
+manager: uid=tmorris, ou=People, dc=example,dc=com
+
+dn: uid=mwhite, ou=People, dc=example,dc=com
+cn: Morgan White
+sn: White
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mwhite
+mail: mwhite@example.com
+telephonenumber: +1 408 555 9620
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3088
+userpassword: staple
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=gjensen, ou=People, dc=example,dc=com
+cn: Gern Jensen
+sn: Jensen
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: gjensen
+mail: gjensen@example.com
+telephonenumber: +1 408 555 3299
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4609
+userpassword: primitive
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=awhite, ou=People, dc=example,dc=com
+cn: Alan White
+sn: White
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: awhite
+mail: awhite@example.com
+telephonenumber: +1 408 555 3232
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 0142
+userpassword: placeholder
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=bmaddox, ou=People, dc=example,dc=com
+cn: Barbara Maddox
+sn: Maddox
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bmaddox
+mail: bmaddox@example.com
+telephonenumber: +1 408 555 7783
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2207
+userpassword: feedback
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=mtalbot, ou=People, dc=example,dc=com
+cn: Martin Talbot
+sn: Talbot
+givenname: Martin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: mtalbot
+mail: mtalbot@example.com
+telephonenumber: +1 408 555 9228
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1415
+userpassword: currant
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=jbrown, ou=People, dc=example,dc=com
+cn: Judy Brown
+sn: Brown
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jbrown
+mail: jbrown@example.com
+telephonenumber: +1 408 555 6885
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4224
+userpassword: militiamen
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=jjensen, ou=People, dc=example,dc=com
+cn: Jody Jensen
+sn: Jensen
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: jjensen
+mail: jjensen@example.com
+telephonenumber: +1 408 555 7587
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4882
+userpassword: borderland
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=mcarter, ou=People, dc=example,dc=com
+cn: Mike Carter
+sn: Carter
+givenname: Mike
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: mcarter
+mail: mcarter@example.com
+telephonenumber: +1 408 555 1846
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3819
+userpassword: mainland
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=dakers, ou=People, dc=example,dc=com
+cn: David Akers
+sn: Akers
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: dakers
+mail: dakers@example.com
+telephonenumber: +1 408 555 4812
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 4944
+userpassword: integument
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=sfarmer, ou=People, dc=example,dc=com
+cn: Scott Farmer
+sn: Farmer
+givenname: Scott
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: sfarmer
+mail: sfarmer@example.com
+telephonenumber: +1 408 555 4228
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0019
+userpassword: triumphal
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=dward, ou=People, dc=example,dc=com
+cn: Daniel Ward
+sn: Ward
+givenname: Daniel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: dward
+mail: dward@example.com
+telephonenumber: +1 408 555 5322
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3927
+userpassword: armload
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=tward, ou=People, dc=example,dc=com
+cn: Tobias Ward
+sn: Ward
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: tward
+mail: tward@example.com
+telephonenumber: +1 408 555 7202
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2238
+userpassword: cedilla
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=pshelton, ou=People, dc=example,dc=com
+cn: Patricia Shelton
+sn: Shelton
+givenname: Patricia
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: pshelton
+mail: pshelton@example.com
+telephonenumber: +1 408 555 6442
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2918
+userpassword: nosedive
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=jrentz, ou=People, dc=example,dc=com
+cn: Jody Rentz
+sn: Rentz
+givenname: Jody
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jrentz
+mail: jrentz@example.com
+telephonenumber: +1 408 555 5829
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 3025
+userpassword: meander
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=plorig, ou=People, dc=example,dc=com
+cn: Peter Lorig
+sn: Lorig
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: plorig
+mail: plorig@example.com
+telephonenumber: +1 408 555 0624
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1276
+userpassword: calorimeter
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=ajensen, ou=People, dc=example,dc=com
+cn: Allison Jensen
+sn: Jensen
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: ajensen
+mail: ajensen@example.com
+telephonenumber: +1 408 555 7892
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 0784
+userpassword: coltsfoot
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=kschmith, ou=People, dc=example,dc=com
+cn: Kelly Schmith
+sn: Schmith
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: kschmith
+mail: kschmith@example.com
+telephonenumber: +1 408 555 9749
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 2221
+userpassword: purvey
+manager: uid=kvaughan, ou=People, dc=example,dc=com
+
+dn: uid=pworrell, ou=People, dc=example,dc=com
+cn: Pete Worrell
+sn: Worrell
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: pworrell
+mail: pworrell@example.com
+telephonenumber: +1 408 555 1637
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 2449
+userpassword: solicitous
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=mreuter, ou=People, dc=example,dc=com
+cn: Matthew Reuter
+sn: Reuter
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: mreuter
+mail: mreuter@example.com
+telephonenumber: +1 408 555 6879
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 1356
+userpassword: oblivious
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=gtyler, ou=People, dc=example,dc=com
+cn: Gern Tyler
+sn: Tyler
+givenname: Gern
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: gtyler
+mail: gtyler@example.com
+telephonenumber: +1 408 555 1020
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0312
+userpassword: typology
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=tschmith, ou=People, dc=example,dc=com
+cn: Tobias Schmith
+sn: Schmith
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tschmith
+mail: tschmith@example.com
+telephonenumber: +1 408 555 9626
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4607
+userpassword: compost
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=bjense2, ou=People, dc=example,dc=com
+cn: Bjorn Jensen
+sn: Jensen
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: bjense2
+mail: bjense2@example.com
+telephonenumber: +1 408 555 5655
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4294
+userpassword: mortgage
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=dswain, ou=People, dc=example,dc=com
+cn: Dietrich Swain
+sn: Swain
+givenname: Dietrich
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: dswain
+mail: dswain@example.com
+telephonenumber: +1 408 555 9222
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 4396
+userpassword: freedom
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=ahall, ou=People, dc=example,dc=com
+cn: Andy Hall
+sn: Hall
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: ahall
+mail: ahall@example.com
+telephonenumber: +1 408 555 6169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 3050
+userpassword: slater
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=jmuffly, ou=People, dc=example,dc=com
+cn: Jeff Muffly
+sn: Muffly
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jmuffly
+mail: jmuffly@example.com
+telephonenumber: +1 408 555 5287
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0997
+userpassword: dictate
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=tjensen, ou=People, dc=example,dc=com
+cn: Ted Jensen
+sn: Jensen
+givenname: Ted
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjensen
+mail: tjensen@example.com
+telephonenumber: +1 408 555 8622
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4717
+userpassword: ecosystem
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=ahunter, ou=People, dc=example,dc=com
+cn: Allison Hunter
+sn: Hunter
+givenname: Allison
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Sunnyvale
+uid: ahunter
+mail: ahunter@example.com
+telephonenumber: +1 408 555 7713
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1213
+userpassword: egregious
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=jgoldste, ou=People, dc=example,dc=com
+cn: Jon Goldstein
+sn: Goldstein
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jgoldste
+mail: jgoldste@example.com
+telephonenumber: +1 408 555 5769
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 1454
+userpassword: yellow
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=aworrell, ou=People, dc=example,dc=com
+cn: Alan Worrell
+sn: Worrell
+givenname: Alan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aworrell
+mail: aworrell@example.com
+telephonenumber: +1 408 555 1591
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3966
+userpassword: gargoyle
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=wlutz, ou=People, dc=example,dc=com
+cn: Wendy Lutz
+sn: Lutz
+givenname: Wendy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: wlutz
+mail: wlutz@example.com
+telephonenumber: +1 408 555 3358
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 4912
+userpassword: bassinet
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=jlutz, ou=People, dc=example,dc=com
+cn: Janet Lutz
+sn: Lutz
+givenname: Janet
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jlutz
+mail: jlutz@example.com
+telephonenumber: +1 408 555 4902
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2544
+userpassword: autumn
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=dlangdon, ou=People, dc=example,dc=com
+cn: Dan Langdon
+sn: Langdon
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: dlangdon
+mail: dlangdon@example.com
+telephonenumber: +1 408 555 7044
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3263
+userpassword: botulin
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=aknutson, ou=People, dc=example,dc=com
+cn: Ashley Knutson
+sn: Knutson
+givenname: Ashley
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: aknutson
+mail: aknutson@example.com
+telephonenumber: +1 408 555 2169
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4736
+userpassword: maltose
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=kmcinnis, ou=People, dc=example,dc=com
+cn: Kelly Mcinnis
+sn: Mcinnis
+givenname: Kelly
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: kmcinnis
+mail: kmcinnis@example.com
+telephonenumber: +1 408 555 8596
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4312
+userpassword: stargaze
+manager: uid=cschmith, ou=People, dc=example,dc=com
+
+dn: uid=tcouzens, ou=People, dc=example,dc=com
+cn: Trent Couzens
+sn: Couzens
+givenname: Trent
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Sunnyvale
+uid: tcouzens
+mail: tcouzens@example.com
+telephonenumber: +1 408 555 8401
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 3994
+userpassword: tambourine
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=lstockto, ou=People, dc=example,dc=com
+cn: Lee Stockton
+sn: Stockton
+givenname: Lee
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: lstockto
+mail: lstockto@example.com
+telephonenumber: +1 408 555 0518
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0169
+userpassword: brooklyn
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=jbourke, ou=People, dc=example,dc=com
+cn: Jon Bourke
+sn: Bourke
+givenname: Jon
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Cupertino
+uid: jbourke
+mail: jbourke@example.com
+telephonenumber: +1 408 555 8541
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 0034
+userpassword: brainwash
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=dlanoway, ou=People, dc=example,dc=com
+cn: Dan Lanoway
+sn: Lanoway
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: dlanoway
+mail: dlanoway@example.com
+telephonenumber: +1 408 555 2017
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 3540
+userpassword: manhattan
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=kcope, ou=People, dc=example,dc=com
+cn: Karl Cope
+sn: Cope
+givenname: Karl
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: kcope
+mail: kcope@example.com
+telephonenumber: +1 408 555 2709
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 3040
+userpassword: forfeiture
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=abarnes, ou=People, dc=example,dc=com
+cn: Anne-Louise Barnes
+sn: Barnes
+givenname: Anne-Louise
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: abarnes
+mail: abarnes@example.com
+telephonenumber: +1 408 555 9445
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2290
+userpassword: chevron
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=rjensen, ou=People, dc=example,dc=com
+cn: Richard Jensen
+sn: Jensen
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: rjensen
+mail: rjensen@example.com
+telephonenumber: +1 408 555 5957
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 2631
+userpassword: disciplinarian
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=phun2, ou=People, dc=example,dc=com
+cn: Pete Hunt
+sn: Hunt
+givenname: Pete
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: phun2
+mail: phun2@example.com
+telephonenumber: +1 408 555 0342
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 0087
+userpassword: absorb
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=mvaughan, ou=People, dc=example,dc=com
+cn: Matthew Vaughan
+sn: Vaughan
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: mvaughan
+mail: mvaughan@example.com
+telephonenumber: +1 408 555 4692
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4508
+userpassword: submitted
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=jlut2, ou=People, dc=example,dc=com
+cn: James Lutz
+sn: Lutz
+givenname: James
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: jlut2
+mail: jlut2@example.com
+telephonenumber: +1 408 555 9689
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 3541
+userpassword: shrank
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=mjablons, ou=People, dc=example,dc=com
+cn: Morgan Jablonski
+sn: Jablonski
+givenname: Morgan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: mjablons
+mail: mjablons@example.com
+telephonenumber: +1 408 555 0813
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 3160
+userpassword: minimal
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=pchassin, ou=People, dc=example,dc=com
+cn: Peter Chassin
+sn: Chassin
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: pchassin
+mail: pchassin@example.com
+telephonenumber: +1 408 555 2816
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 4524
+userpassword: barbital
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=dcope, ou=People, dc=example,dc=com
+cn: Dan Cope
+sn: Cope
+givenname: Dan
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: dcope
+mail: dcope@example.com
+telephonenumber: +1 408 555 9813
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 1737
+userpassword: snifter
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=jrent2, ou=People, dc=example,dc=com
+cn: Judy Rentz
+sn: Rentz
+givenname: Judy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Santa Clara
+uid: jrent2
+mail: jrent2@example.com
+telephonenumber: +1 408 555 2523
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 4405
+userpassword: tachistoscope
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=tcruse, ou=People, dc=example,dc=com
+cn: Tobias Cruse
+sn: Cruse
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: tcruse
+mail: tcruse@example.com
+telephonenumber: +1 408 555 5980
+facsimiletelephonenumber: +1 408 555 4774
+roomnumber: 4191
+userpassword: flinty
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=eward, ou=People, dc=example,dc=com
+cn: Eric Ward
+sn: Ward
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: eward
+mail: eward@example.com
+telephonenumber: +1 408 555 2320
+facsimiletelephonenumber: +1 408 555 7472
+roomnumber: 4874
+userpassword: episcopal
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=ttully, ou=People, dc=example,dc=com
+cn: Torrey Tully
+sn: Tully
+givenname: Torrey
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: ttully
+mail: ttully@example.com
+telephonenumber: +1 408 555 2274
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3924
+userpassword: schooner
+manager: uid=abergin, ou=People, dc=example,dc=com
+
+dn: uid=charvey, ou=People, dc=example,dc=com
+cn: Cecil Harvey
+sn: Harvey
+givenname: Cecil
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: charvey
+mail: charvey@example.com
+telephonenumber: +1 408 555 1815
+facsimiletelephonenumber: +1 408 555 3825
+roomnumber: 4583
+userpassword: journalese
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=rfisher, ou=People, dc=example,dc=com
+cn: Randy Fisher
+sn: Fisher
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: rfisher
+mail: rfisher@example.com
+telephonenumber: +1 408 555 1506
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1579
+userpassword: pomegranate
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=alangdon, ou=People, dc=example,dc=com
+cn: Andrew Langdon
+sn: Langdon
+givenname: Andrew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: alangdon
+mail: alangdon@example.com
+telephonenumber: +1 408 555 8289
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 2254
+userpassword: muzzle
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=drose, ou=People, dc=example,dc=com
+cn: David Rose
+sn: Rose
+givenname: David
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: drose
+mail: drose@example.com
+telephonenumber: +1 408 555 3963
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 4012
+userpassword: gubernatorial
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=polfield, ou=People, dc=example,dc=com
+cn: Peter Olfield
+sn: Olfield
+givenname: Peter
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: polfield
+mail: polfield@example.com
+telephonenumber: +1 408 555 8231
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 1376
+userpassword: monologue
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=awalker, ou=People, dc=example,dc=com
+cn: Andy Walker
+sn: Walker
+givenname: Andy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Cupertino
+uid: awalker
+mail: awalker@example.com
+telephonenumber: +1 408 555 9199
+facsimiletelephonenumber: +1 408 555 3372
+roomnumber: 0061
+userpassword: detonable
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=lrentz, ou=People, dc=example,dc=com
+cn: Lex Rentz
+sn: Rentz
+givenname: Lex
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: lrentz
+mail: lrentz@example.com
+telephonenumber: +1 408 555 2019
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 2203
+userpassword: calcium
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=jvaughan, ou=People, dc=example,dc=com
+cn: Jeff Vaughan
+sn: Vaughan
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: jvaughan
+mail: jvaughan@example.com
+telephonenumber: +1 408 555 4543
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 1734
+userpassword: appoint
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=bfrancis, ou=People, dc=example,dc=com
+cn: Barbara Francis
+sn: Francis
+givenname: Barbara
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Santa Clara
+uid: bfrancis
+mail: bfrancis@example.com
+telephonenumber: +1 408 555 9111
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3743
+userpassword: holystone
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=ewalker, ou=People, dc=example,dc=com
+cn: Eric Walker
+sn: Walker
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Payroll
+ou: People
+l: Cupertino
+uid: ewalker
+mail: ewalker@example.com
+telephonenumber: +1 408 555 6387
+facsimiletelephonenumber: +1 408 555 8721
+roomnumber: 2295
+userpassword: beguile
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=tjames, ou=People, dc=example,dc=com
+cn: Tobias James
+sn: James
+givenname: Tobias
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: tjames
+mail: tjames@example.com
+telephonenumber: +1 408 555 2458
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 0730
+userpassword: turtle
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=brigden, ou=People, dc=example,dc=com
+cn: Bjorn Rigden
+sn: Rigden
+givenname: Bjorn
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Sunnyvale
+uid: brigden
+mail: brigden@example.com
+telephonenumber: +1 408 555 5263
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1643
+userpassword: purple
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=ecruse, ou=People, dc=example,dc=com
+cn: Eric Cruse
+sn: Cruse
+givenname: Eric
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ecruse
+mail: ecruse@example.com
+telephonenumber: +1 408 555 0648
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 4233
+userpassword: platelet
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=rjense2, ou=People, dc=example,dc=com
+cn: Randy Jensen
+sn: Jensen
+givenname: Randy
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Sunnyvale
+uid: rjense2
+mail: rjense2@example.com
+telephonenumber: +1 408 555 9045
+facsimiletelephonenumber: +1 408 555 1992
+roomnumber: 1984
+userpassword: transpose
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=rhunt, ou=People, dc=example,dc=com
+cn: Richard Hunt
+sn: Hunt
+givenname: Richard
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Accounting
+ou: People
+l: Santa Clara
+uid: rhunt
+mail: rhunt@example.com
+telephonenumber: +1 408 555 0139
+facsimiletelephonenumber: +1 408 555 8473
+roomnumber: 0718
+userpassword: becloud
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=bparker, ou=People, dc=example,dc=com
+cn: Barry Parker
+sn: Parker
+givenname: Barry
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: bparker
+mail: bparker@example.com
+telephonenumber: +1 408 555 4647
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 1148
+userpassword: lenticular
+
+dn: uid=ealexand, ou=People, dc=example,dc=com
+cn: Erin Alexander
+sn: Alexander
+givenname: Erin
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: ealexand
+mail: ealexand@example.com
+telephonenumber: +1 408 555 5563
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 2434
+userpassword: galactose
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: uid=mtyler, ou=People, dc=example,dc=com
+cn: Matthew Tyler
+sn: Tyler
+givenname: Matthew
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Human Resources
+ou: People
+l: Cupertino
+uid: mtyler
+mail: mtyler@example.com
+telephonenumber: +1 408 555 7907
+facsimiletelephonenumber: +1 408 555 4661
+roomnumber: 2701
+userpassword: instantiate
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=elott, ou=People, dc=example,dc=com
+cn: Emanuel Lott
+sn: Lott
+givenname: Emanuel
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Testing
+ou: People
+l: Santa Clara
+uid: elott
+mail: elott@example.com
+telephonenumber: +1 408 555 0932
+facsimiletelephonenumber: +1 408 555 9751
+roomnumber: 3906
+userpassword: holdout
+manager: uid=jwalker, ou=People, dc=example,dc=com
+
+dn: uid=cnewport, ou=People, dc=example,dc=com
+cn: Christoph Newport
+sn: Newport
+givenname: Christoph
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Sunnyvale
+uid: cnewport
+mail: cnewport@example.com
+telephonenumber: +1 408 555 0066
+facsimiletelephonenumber: +1 408 555 9332
+roomnumber: 0056
+userpassword: expertise
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: uid=jvedder, ou=People, dc=example,dc=com
+cn: Jeff Vedder
+sn: Vedder
+givenname: Jeff
+objectclass: top
+objectclass: person
+objectclass: organizationalPerson
+objectclass: inetOrgPerson
+ou: Product Development
+ou: People
+l: Santa Clara
+uid: jvedder
+mail: jvedder@example.com
+telephonenumber: +1 408 555 4668
+facsimiletelephonenumber: +1 408 555 0111
+roomnumber: 3445
+userpassword: befitting
+manager: uid=bparker, ou=People, dc=example,dc=com
+
+dn: cn=Accounting Managers,ou=groups,dc=example,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: Accounting Managers
+ou: groups
+uniquemember: uid=scarter, ou=People, dc=example,dc=com
+uniquemember: uid=tmorris, ou=People, dc=example,dc=com
+description: People who can manage accounting entries
+
+dn: cn=HR Managers,ou=groups,dc=example,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: HR Managers
+ou: groups
+uniquemember: uid=kvaughan, ou=People, dc=example,dc=com
+uniquemember: uid=cschmith, ou=People, dc=example,dc=com
+description: People who can manage HR entries
+
+dn: cn=QA Managers,ou=groups,dc=example,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: QA Managers
+ou: groups
+uniquemember: uid=abergin, ou=People, dc=example,dc=com
+uniquemember: uid=jwalker, ou=People, dc=example,dc=com
+description: People who can manage QA entries
+
+dn: cn=PD Managers,ou=groups,dc=example,dc=com
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: PD Managers
+ou: groups
+uniquemember: uid=kwinters, ou=People, dc=example,dc=com
+uniquemember: uid=trigden, ou=People, dc=example,dc=com
+description: People who can manage engineer entries
+
+dn: ou=Netscape Servers,dc=example,dc=com
+objectclass: top
+objectclass: organizationalUnit
+ou: Netscape Servers
+description: Standard branch for Netscape Server registration
diff --git a/ldap/ldif/commonTasks.ldif b/ldap/ldif/commonTasks.ldif
new file mode 100644
index 00000000..0b0d468c
--- /dev/null
+++ b/ldap/ldif/commonTasks.ldif
@@ -0,0 +1,45 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Top level Tasks branch
+#
+dn: cn=Tasks
+objectclass: top
+objectclass: nsResourceRef
+
+#
+# Operation Task Group
+#
+dn: cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nstaskgroup
+nstasklabel: Operation Tasks Group
+
+dn: cn=Migrate, cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: perl?migrateInstance
+
+dn: cn=Create, cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: ds_create
+
+dn: cn=GetConfigInfo, cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: perl?getConfigInfo
+
+dn: cn=MigrateLocalDB, cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: perl?migrateLocalDB
diff --git a/ldap/ldif/roledit.ldif b/ldap/ldif/roledit.ldif
new file mode 100644
index 00000000..0d8051e2
--- /dev/null
+++ b/ldap/ldif/roledit.ldif
@@ -0,0 +1,50 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+dn: ou=Admin, ou=Global Preferences
+objectclass: top
+objectclass: organizationalUnit
+objectclass: extensibleObject
+ou: admin
+nsmerge: ADD_IF_EMPTY
+
+dn: ou=4.0, ou=Admin, ou=Global Preferences
+objectclass: top
+objectclass: organizationalunit
+objectclass: extensibleObject
+ou: 4.0
+nsmerge: ADD_IF_EMPTY
+
+dn: cn=ResourceEditorExtension, ou=4.0, ou=Admin, ou=Global Preferences
+objectclass: top
+objectclass: nsResourceRef
+objectclass: extensibleObject
+cn: ResourceEditorExtension
+nsmerge: ADD_IF_EMPTY
+
+dn: cn=nsroledefinition, cn=ResourceEditorExtension, ou=4.0, ou=Admin, ou=Global Preferences
+cn: nsroledefinition
+objectclass: top
+objectclass: extensibleObject
+objectclass: nsResourceRef
+objectclass: nsAdminResourceEditorExtension
+nsclassname: com.netscape.admin.dirserv.roledit.ResEditorRoleInfo@ds70.jar
+nsclassname: com.netscape.admin.dirserv.roledit.ResEditorRoleMembers@ds70.jar
+nsclassname: com.netscape.admin.dirserv.roledit.ResEditorRoleAccountPage@ds70.jar
+nsmerge: {nsclassname}MULTI_MERGE
+
+dn: cn=cossuperdefinition, cn=ResourceEditorExtension, ou=4.0, ou=Admin, ou=Global Preferences
+cn: cossuperdefinition
+objectclass: top
+objectclass: extensibleObject
+objectclass: nsResourceRef
+objectclass: nsAdminResourceEditorExtension
+nsclassname: com.netscape.admin.dirserv.cosedit.ResEditorCosInfo@ds70.jar
+nsclassname: com.netscape.admin.dirserv.cosedit.ResEditorCosAttributes@ds70.jar
+nsclassname: com.netscape.admin.dirserv.cosedit.ResEditorCosTemplate@ds70.jar
+nsmerge: {nsclassname}MULTI_MERGE
+
diff --git a/ldap/ldif/tasks.ldif b/ldap/ldif/tasks.ldif
new file mode 100644
index 00000000..0c0dd979
--- /dev/null
+++ b/ldap/ldif/tasks.ldif
@@ -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
+#
+#
+# Top level Tasks branch
+#
+dn: cn=Tasks
+objectclass: top
+objectclass: nsResourceRef
+
+#
+# Operation Task Group
+#
+dn: cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nstaskgroup
+nstasklabel: Operation Tasks Group
+
+# Define the order of tasks on the task tab
+dn: cn=task summary, cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nsConfig
+description: start stop restart Backup Restore KeyCert Authenticate CompleteImport CompleteExport
+
+dn: cn=start, cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsClassname: com.netscape.admin.dirserv.task.Start@ds70.jar
+nsexecref: start
+
+dn: cn=stop, cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsClassname: com.netscape.admin.dirserv.task.Stop@ds70.jar
+nsexecref: shutdown
+
+dn: cn=restart, cn=Operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsClassname: com.netscape.admin.dirserv.task.Restart@ds70.jar
+nsexecref: restart
+
+dn: cn=Backup, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsClassname: com.netscape.admin.dirserv.task.Backup@ds70.jar
+nsexecref: ds_db2bak
+
+dn: cn=Restore, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsClassname: com.netscape.admin.dirserv.task.Restore@ds70.jar
+nsexecref: ds_bak2db
+
+dn: cn=KeyCert, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsClassname: com.netscape.admin.dirserv.task.KeyCert@ds70.jar
+
+dn: cn=Authenticate, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsClassname: com.netscape.admin.dirserv.task.Authenticate@ds70.jar
+
+dn: cn=CompleteImport, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsClassname: com.netscape.admin.dirserv.task.CompleteImport@ds70.jar
+
+dn: cn=CompleteExport, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsClassname: com.netscape.admin.dirserv.task.CompleteExport@ds70.jar
+
+dn: cn=Export, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: ds_db2ldif
+
+dn: cn=Import, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: ds_ldif2db
+
+dn: cn=ViewLog, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: perl?ds_viewlog.pl
+
+dn: cn=ListBackups, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: ds_listdb
+
+dn: cn=Remove, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: ds_remove
+
+dn: cn=CreateVLVIndex, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: vlvindex
+
+dn: cn=AddIndex, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: addindex
+
+dn: cn=SNMPCtrl, cn=operation, cn=Tasks
+objectclass: top
+objectclass: nstask
+objectclass: nsAdminObject
+nsexecref: ds_snmpctrl
diff --git a/ldap/ldif/template.ldif b/ldap/ldif/template.ldif
new file mode 100644
index 00000000..7620f2cb
--- /dev/null
+++ b/ldap/ldif/template.ldif
@@ -0,0 +1,83 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+dn: %%%SUFFIX%%%
+objectclass: top
+aci: (targetattr ="*")(version 3.0;
+ acl "Configuration Administrators Group";allow (all) (groupdn = "ldap:///
+ cn=Configuration Administrators, ou=Groups, ou=TopologyManagement, o=NetscapeRoot");)
+aci: (targetattr ="*")(version 3.0;
+ acl "Directory Administrators Group";allow (all) (groupdn = "ldap:///
+ ou=Directory Administrators, %%%SUFFIX%%%");)
+
+dn: cn=Directory Administrators, %%%SUFFIX%%%
+objectClass: top
+objectClass: groupofuniquenames
+cn: Directory Administrators
+
+dn: ou=Groups, %%%SUFFIX%%%
+objectclass: top
+objectclass: organizationalunit
+ou: Groups
+
+dn: ou=People, %%%SUFFIX%%%
+objectclass: top
+objectclass: organizationalunit
+ou: People
+aci: (targetattr ="userpassword || te
+ lephonenumber || facsimiletelephonenumber")(version 3.0;acl "Allow self entry
+ modification";allow (write)(userdn = "ldap:///self");)
+aci: (targetattr !="cn || sn || uid")(t
+ argetfilter ="(ou=Accounting)")(version 3.0;acl "Accounting Managers G
+ roup Permissions";allow (write)(groupdn = "ldap:///cn=Accounting Managers,ou
+ =groups,%%%SUFFIX%%%");)
+aci: (targetattr !="cn || sn || uid")(t
+ argetfilter ="(ou=Human Resources)")(version 3.0;acl "HR Group Permiss
+ ions";allow (write)(groupdn = "ldap:///cn=HR Managers,ou=groups,%%%SUFFIX%%%
+ ");)
+aci: (targetattr !="cn ||sn || uid")(t
+ argetfilter ="(ou=Product Testing)")(version 3.0;acl "QA Group Permiss
+ ions";allow (write)(groupdn = "ldap:///cn=QA Managers,ou=groups,%%%SUFFIX%%%
+ ");)
+aci: (targetattr !="cn || sn || uid")(t
+ argetfilter ="(ou=Product Development)")(version 3.0;acl "Engineering
+ Group Permissions";allow (write)(groupdn = "ldap:///cn=PD Managers,ou=groups
+ ,%%%SUFFIX%%%");)
+
+dn: ou=Special Users,%%%SUFFIX%%%
+objectclass: top
+objectclass: organizationalUnit
+ou: Special Users
+description: Special Administrative Accounts
+
+dn: cn=Accounting Managers,ou=groups,%%%SUFFIX%%%
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: Accounting Managers
+ou: groups
+description: People who can manage accounting entries
+
+dn: cn=HR Managers,ou=groups,%%%SUFFIX%%%
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: HR Managers
+ou: groups
+description: People who can manage HR entries
+
+dn: cn=QA Managers,ou=groups,%%%SUFFIX%%%
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: QA Managers
+ou: groups
+description: People who can manage QA entries
+
+dn: cn=PD Managers,ou=groups,%%%SUFFIX%%%
+objectclass: top
+objectclass: groupOfUniqueNames
+cn: PD Managers
+ou: groups
+description: People who can manage engineer entries
diff --git a/ldap/libraries/Makefile b/ldap/libraries/Makefile
new file mode 100644
index 00000000..d174d131
--- /dev/null
+++ b/ldap/libraries/Makefile
@@ -0,0 +1,370 @@
+#
+# 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 and LDAP SDK libraries
+#
+
+MCOM_ROOT = ../../..
+LDAP_SRC = $(MCOM_ROOT)/ldapserver/ldap
+
+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 = $(OBJDIR)/lib
+LIBDIR = $(LDAP_LIBDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+# the following lines are to make this work for
+# both db1.85 and db2.0
+ifndef LDAP_USE_OLD_DB
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+ldap_db_depend:=$(DB_LIB_DEP)
+CFLAGS+= -I$(DB_INCLUDE)
+else
+ldap_db_depend:=_berkeley_db
+endif
+
+ifeq ($(ARCH), WINNT)
+LDAPRES= $(addprefix $(LIBDIR)/, libldap/*.res)
+LCACHERES= $(addprefix $(LIBDIR)/, liblcache/*.res)
+endif
+
+########## Security #######################
+##########ifneq ($(SECURITY), none)
+
+# Where to find libsec and friends
+SECDIR=$(NSCP_DISTDIR)/lib
+
+ifeq ($(ARCH), WINNT)
+# Used by libsec in Win32
+SEC_SYSLIBS=rpcrt4.lib user32.lib
+# When pulling in libsec/nspr20, WinSock and WinMM must be linked in
+ifdef INCLUDE_SSL
+EXTRA_LIBS=winmm.lib wsock32.lib
+SDK_EXPORT_DEFS=ldapsdk.def
+SDK_EXPORT_DEPS=msdos/winsock/nsldap32.def msdos/winsock/ldapssl.def
+else
+SDK_EXPORT_DEFS=msdos/winsock/nsldap32.def
+endif
+SDK_EXPORT_FLAGS=/DEF:$(SDK_EXPORT_DEFS)
+LCACHE_EXPORT_DEFS=msdos/winsock/nslch32.def
+LCACHE_EXPORT_FLAGS=/DEF:$(LCACHE_EXPORT_DEFS)
+endif
+
+EXPLDAP=libldap
+EXPLCH=liblcache
+EXPLDSSL=libldap_ssl
+
+ifeq ($(ARCH), AIX)
+USE_DLL_EXPORTS_FILE=1
+else
+ifeq ($(ARCH), SOLARIS)
+USE_DLL_EXPORTS_FILE=1
+else
+ifeq ($(ARCH), IRIX)
+USE_DLL_EXPORTS_FILE=1
+endif
+endif
+endif
+
+
+ifeq ($(USE_DLL_EXPORTS_FILE), 1)
+ifdef INCLUDE_SSL
+SDK_EXPORT_DEFS=$(OBJDEST)/$(EXPLDAP).exp $(OBJDEST)/$(EXPLDSSL).exp
+DLL_EXPORT_FLAGS=$(SDK_EXPORT_DEFS)
+else
+SDK_EXPORT_DEFS=$(OBJDEST)/$(EXPLDAP).exp
+endif
+DLL_EXPORT_FLAGS=$(addprefix $(DLLEXPORTS_PREFIX), $(SDK_EXPORT_DEFS))
+LCACHE_EXPORT_DEFS=$(OBJDEST)/$(EXPLCH).exp
+DLL_EXPORT_FLAGS2=$(addprefix $(DLLEXPORTS_PREFIX), $(LCACHE_EXPORT_DEFS))
+endif
+
+
+EXTRA_SECLIBS= $(STATICLIBNSPR) $(LIBSEC) $(LIBXP) $(LIBDB) $(LIBARES) \
+ $(LIBSSLIO) $(SEC_SYSLIBS)
+EXTRA_SECLIBS_DEP += $(STATICLIBNSPR) $(LIBXP_DEP) \
+ $(LIBSSLIO_DEP)
+EXTRA_SECLIBS_DEP += $(LIBSEC_DEP) $(LIBDB_DEP) $(LIBARES_DEP)
+
+ifdef INCLUDE_SSL
+#
+# include security code in the LDAP DLL
+#
+EXTRA_LIBS += $(EXTRA_SECLIBS)
+EXTRA_LIBS_DEP += $(EXTRA_SECLIBS_DEP)
+ifneq ($(ARCH), WINNT)
+DLL_LDFLAGS += -$(LIBPATH)$(SECDIR)
+endif
+
+SSLOBJS= $(addprefix $(LIBDIR)/, libssldap/*.o)
+SSL_DEP= $(LDAPSDK_DEP)
+
+endif
+########## end Security ###################
+
+# The following libraries are built by this Makefile:
+# dynamic LDAP library
+DLIBLDAP= $(addprefix $(LIBDIR)/, $(LIBLDAP_DLL).$(DLL_SUFFIX))
+# static LDAP library
+SLIBLDAP= $(addprefix $(LIBDIR)/, $(LIBLDAP_LIB).$(LIB_SUFFIX))
+# dynamic LCACHE library
+DLIBLCACHE= $(addprefix $(LIBDIR)/, $(LIBLCACHE_DLL).$(DLL_SUFFIX))
+# static LCACHE library
+SLIBLCACHE= $(addprefix $(LIBDIR)/, $(LIBLCACHE_LIB).$(LIB_SUFFIX))
+
+# objects built by libavl/Makefile
+AVLOBJS= $(addprefix $(LIBDIR)/, libavl/*.o)
+# objects built by berkeley_db/Makefile
+# the following lines pull in the new db library with the liblcache dll is built
+# this is a hack, but can't see how to add it easier without a new LINK_DLL2.
+ifndef LDAP_USE_OLD_DB
+DLL_EXPORT_FLAGS2+=$(DB_STATIC_LIB)
+else
+BERKDBOBJS= $(addprefix $(LIBDIR)/, libdb/*.o)
+endif
+# objects built by liblber/Makefile
+LBEROBJS= $(addprefix $(LIBDIR)/, liblber/*.o)
+# objects built by liblcache/Makefile
+LCACHEOBJS= $(addprefix $(LIBDIR)/, liblcache/*.o)
+# objects built by libldap/Makefile
+LDAPOBJS= $(addprefix $(LIBDIR)/, libldap/*.o)
+# one object built by libldap/Makefile
+REGEXOBJ= $(addprefix $(LIBDIR)/, libldap/regex.o)
+# objects built by libldbm/Makefile
+LDBMOBJS= $(addprefix $(LIBDIR)/, libldbm/*.o)
+# objects built by libldif/Makefile
+LDIFOBJS= $(addprefix $(LIBDIR)/, libldif/*.o)
+
+all: $(LDAP_LIBDIR) clientSDK
+
+buildDirectory: $(LDAP_LIBDIR) _libavl _libldif _liblitekey _libutil
+
+ifdef LDAP_USE_OLD_DB
+_berkeley_db:
+ cd berkeley_db; $(MAKE) $(MFLAGS) all
+endif
+
+_libavl:
+ cd libavl; $(MAKE) $(MFLAGS) all
+
+_liblber:
+ cd liblber; $(MAKE) $(MFLAGS) all
+
+_libldbm:
+ cd libldbm; $(MAKE) $(MFLAGS) all
+
+_libldif:
+ cd libldif; $(MAKE) $(MFLAGS) all
+
+_liblitekey:
+ cd liblitekey; $(MAKE) $(MFLAGS) all
+
+_libssldap:
+ cd libssldap; $(MAKE) $(MFLAGS) all
+
+_libutil:
+ifeq ($(ARCH), WINNT)
+ cd libutil; $(MAKE) $(MFLAGS) all
+endif
+
+_libldap:
+ cd libldap; $(MAKE) $(MFLAGS) all
+
+_slapd:
+ cd $(LDAP_SRC)/servers/slapd; $(MAKE) $(MFLAGS) all
+
+_back-ldbm:
+ cd $(LDAP_SRC)/servers/slapd/back-ldbm; $(MAKE) $(MFLAGS) all
+
+_back-ldif:
+ cd $(LDAP_SRC)/servers/slapd/back-ldif; $(MAKE) $(MFLAGS) all
+
+_liblcache:
+ cd liblcache; $(MAKE) $(MFLAGS) clientSDK
+
+ifdef INCLUDE_SSL
+#
+# There is no easy way to include libsec and friends when making static libs
+# (at least on UNIX) so we don't bother making them when INCLUDE_SSL is set.
+# Also if LDAP_NO_LIBLCACHE is 1, we don't build liblcache. Simple, huh?
+#
+ifeq ($(LDAP_NO_LIBLCACHE),1)
+LIBS2BUILD=$(DLIBLDAP)
+else
+LIBS2BUILD=$(DLIBLDAP) $(DLIBLCACHE)
+endif
+else
+ifeq ($(LDAP_NO_LIBLCACHE),1)
+LIBS2BUILD=$(DLIBLDAP) $(SLIBLDAP)
+else
+LIBS2BUILD=$(DLIBLDAP) $(SLIBLDAP) $(DLIBLCACHE) $(SLIBLCACHE)
+endif
+
+endif
+
+clientSDK: $(LDAP_LIBDIR) _libavl _liblber _libldif \
+ _libssldap _libutil $(LIBS2BUILD)
+
+OBJS=$(LBEROBJS) $(LDAPOBJS) $(SSLOBJS) $(LDAPRES)
+
+$(DLIBLDAP): $(LDAP_OUT_DIR) _liblber _libldap $(EXTRA_LIBS_DEP) $(SSL_DEP) \
+ $(SDK_EXPORT_DEFS)
+ $(LINK_DLL) $(SDK_EXPORT_FLAGS) $(EXTRA_LIBS)
+
+$(SLIBLDAP): $(LDAP_OUT_DIR) _liblber _libldap $(EXTRA_LIBS_DEP) $(SSL_DEP)
+ $(LINK_LIB)
+
+OBJS2=$(LCACHEOBJS) $(AVLOBJS) $(LDBMOBJS) $(BERKDBOBJS) $(LDIFOBJS) \
+ $(REGEXOBJ) $(LCACHERES)
+
+ifeq ($(ARCH), WINNT)
+# liblber is included here only to pick up ber_err_print()
+# libsec and libxp are included here only to pick up SHA1_Hash()
+OTHER_SECLIBS= $(LIBSEC) $(LIBXP)
+EXTRA_LCACHE_LIBS=$(LDAP_SDK_LIBLDAP_DLL) $(LDAP_LIBLBER) $(OTHER_SECLIBS)
+EXTRA_LCACHE_LIBS_DEP= $(LDAP_SDK_LIBLDAP_DLL_DEP) $(LDAP_LIBLBER_DEP) \
+ $(EXTRA_SECLIBS_DEP)
+endif
+
+ifeq ($(ARCH), AIX)
+DLL_LDFLAGS += -$(LIBPATH)$(SECDIR)
+# extra libraries are needed on AIX as well
+EXTRA_LCACHE_LIBS=$(LDAP_SDK_LIBLDAP_DLL) $(LDAP_LIBLBER) $(EXTRA_SECLIBS)
+EXTRA_LCACHE_LIBS_DEP= $(LDAP_SDK_LIBLDAP_DLL_DEP) $(LDAP_LIBLBER_DEP) \
+ $(EXTRA_SECLIBS_DEP)
+endif
+
+$(DLIBLCACHE): $(LDAP_OUT_DIR) $(ldap_db_depend) _liblcache _libavl _libldbm \
+ _libldif $(EXTRA_LCACHE_LIBS_DEP) $(LCACHE_EXPORT_DEFS)
+ $(LINK_DLL2) $(LCACHE_EXPORT_FLAGS) $(EXTRA_LCACHE_LIBS) $(EXTRA_LIBS)
+
+$(SLIBLCACHE): $(LDAP_OUT_DIR) $(ldap_db_depend) _liblcache libavl _libldbm \
+ _libldif
+ $(LINK_LIB2)
+
+# Need to add exports if building with SSL in NT
+ifeq ($(ARCH), WINNT)
+ifdef INCLUDE_SSL
+$(SDK_EXPORT_DEFS) : $(SDK_EXPORT_DEPS)
+ cat $(SDK_EXPORT_DEPS) > $(SDK_EXPORT_DEFS)
+endif
+endif
+
+clean: FORCE
+ifdef LDAP_USE_OLD_DB
+ cd berkeley_db; $(MAKE) $(MFLAGS) clean
+endif
+ cd libavl; $(MAKE) $(MFLAGS) clean
+ cd libldif; $(MAKE) $(MFLAGS) clean
+ifeq ($(ARCH), WINNT)
+ cd libutil; $(MAKE) $(MFLAGS) clean
+ -(cd $(LDAP_SRC)/servers/slapd; $(MAKE) $(MFLAGS) clean)
+endif
+ -(cd $(LDAP_SRC)/servers/slapd/back-ldbm; $(MAKE) $(MFLAGS) clean)
+ -(cd $(LDAP_SRC)/servers/slapd/back-ldif; $(MAKE) $(MFLAGS) clean)
+ifeq ($(ARCH), WINNT)
+ -$(RM) $(LIBLDAP_DLL_OBJ)
+endif
+ -$(RM) $(LIBS2BUILD)
+
+veryclean: clean
+
+FORCE:
+
+$(LDAP_OUT_DIR):
+ $(MKDIR) $(LDAP_OUT_DIR)
+
+$(LDAP_LIBDIR):
+ $(MKDIR) $(LDAP_LIBDIR)
+
+
+GENEXPORTS=$(PERL) $(LDAP_SRC)/build/genexports.pl
+# WINDEFDIR is now defined below via a recursive make. This is a
+# bit of a hack to avoid collisions with SDK_EXPORT_DEFS (defined above).
+#WINDEFDIR=msdos/winsock
+MACDEFDIR=macintosh
+GENEXPARGS=$(BUILD_DEBUG) $(DIRSDK_VERSION_DLL_SUFFIX) $(DIRSDK_VERSION)
+
+DEFLDAPW32=$(WINDEFDIR)/nsldap32
+DEFLDAPW16REV=$(WINDEFDIR)/nsldap
+DEFLDAPW16=$(WINDEFDIR)/libldap
+DEFLDAPW32BC=$(WINDEFDIR)/nsldap32bc
+DEFLDSSLW32=$(WINDEFDIR)/ldapssl
+DEFLDSSLW32BC=$(WINDEFDIR)/ldapsslbc
+DEFLCHW32=$(WINDEFDIR)/nslch32
+DEFLCHW32BC=$(WINDEFDIR)/nslch32bc
+DEFLDAPMACPPC=$(MACDEFDIR)/libldap-PPC.u
+DEFLDAPMACCLIENTPPC=$(MACDEFDIR)/LDAPClientPPC.prj
+DEFLDAPMACCLIENT68K=$(MACDEFDIR)/LDAPClient68K.prj
+
+# nsdefs.mk contains version number definitions....
+OTHERDEFDEPS=$(MCOM_ROOT)/ldapserver/nsdefs.mk
+
+exportfiles:
+ $(MAKE) $(MFLAGS) WINDEFDIR=msdos/winsock doExportFiles
+
+doExportFiles: $(DEFLDAPW32).def $(DEFLDAPW16).def $(DEFLDAPW16REV).def \
+ $(DEFLDAPW32BC).def $(DEFLDSSLW32).def $(DEFLDSSLW32BC).def \
+ $(DEFLCHW32).def $(DEFLCHW32BC).def \
+ $(DEFLDAPMACPPC).exp $(DEFLDAPMACCLIENTPPC).exp \
+ $(DEFLDAPMACCLIENT68K).exp
+
+#
+# All the various flavors of Windows:
+#
+$(DEFLDAPW32).def: $(DEFLDAPW32).tdf libldap.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) Win32 $< libldap.ex $(GENEXPARGS) > $@
+
+$(DEFLDAPW16).def: $(DEFLDAPW16).tdf libldap.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) Win16 $< libldap.ex $(GENEXPARGS) > $@
+
+$(DEFLDAPW16REV).def: $(DEFLDAPW16REV).tdf libldap.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) Win16Rev $< libldap.ex $(GENEXPARGS) > $@
+
+$(DEFLDAPW32BC).def: $(DEFLDAPW32BC).tdf libldap.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) WinBC $< libldap.ex $(GENEXPARGS) > $@
+
+$(DEFLDSSLW32).def: $(DEFLDSSLW32).tdf libldap_ssl.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) Win32 $< libldap_ssl.ex $(GENEXPARGS) > $@
+
+$(DEFLDSSLW32BC).def: $(DEFLDSSLW32BC).tdf libldap_ssl.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) WinBC $< libldap_ssl.ex $(GENEXPARGS) > $@
+
+$(DEFLCHW32).def: $(DEFLCHW32).tdf liblcache.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) Win32 $< liblcache.ex $(GENEXPARGS) > $@
+
+$(DEFLCHW32BC).def: $(DEFLCHW32BC).tdf liblcache.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) WinBC $< liblcache.ex $(GENEXPARGS) > $@
+
+#
+# MacOS:
+#
+$(DEFLDAPMACPPC).exp: libldap.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) MacOS Standard $< $(GENEXPARGS) > $@
+
+$(DEFLDAPMACCLIENTPPC).exp: libldap.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) MacOS Standard $< $(GENEXPARGS) > $@
+
+$(DEFLDAPMACCLIENT68K).exp: libldap.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) MacOS Standard $< $(GENEXPARGS) > $@
+
+ifeq ($(USE_DLL_EXPORTS_FILE), 1)
+# generic rules to create standard export/map files
+$(OBJDEST)/$(EXPLDAP).exp: libldap.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) $(ARCH) Standard $< $(GENEXPARGS) > $@
+
+$(OBJDEST)/$(EXPLDSSL).exp: libldap_ssl.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) $(ARCH) Standard $< $(GENEXPARGS) > $@
+
+$(OBJDEST)/$(EXPLCH).exp: liblcache.ex $(OTHERDEFDEPS)
+ $(GENEXPORTS) $(ARCH) Standard $< $(GENEXPARGS) > $@
+endif
diff --git a/ldap/libraries/Makefile.client b/ldap/libraries/Makefile.client
new file mode 100644
index 00000000..5aa0ab20
--- /dev/null
+++ b/ldap/libraries/Makefile.client
@@ -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
+#
+DEPTH = ../../..
+UNIXDIRLIST = liblber libldap
+
+include $(DEPTH)/config/rules.mk
+
+all export:: FORCE
+ @for i in $(UNIXDIRLIST); do \
+ echo " cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) export"; \
+ ( cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) export ); \
+ done
+
+libs install:: FORCE
+ @for i in $(UNIXDIRLIST); do \
+ echo " cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) install"; \
+ ( cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) install ); \
+ done
+
+clean clobber:: FORCE
+ @for i in $(UNIXDIRLIST); do \
+ echo " cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) clean"; \
+ ( cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) clean ); \
+ done
+
+realclean clobber_all:: FORCE
+ @for i in $(UNIXDIRLIST); do \
+ echo " cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) realclean"; \
+ ( cd $$i; $(MAKE) -f Makefile.client $(MFLAGS) realclean ); \
+ done
+
+FORCE:
diff --git a/ldap/libraries/libavl/Makefile b/ldap/libraries/libavl/Makefile
new file mode 100644
index 00000000..28660d4d
--- /dev/null
+++ b/ldap/libraries/libavl/Makefile
@@ -0,0 +1,52 @@
+#
+# 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 libavl
+#
+
+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 = $(OBJDIR)/lib/libavl
+LIBDIR = $(LDAP_LIBDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+CFLAGS += $(SLCFLAGS)
+
+LIBAVL_OBJS= avl.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(LIBAVL_OBJS))
+
+LIBAVL= $(addprefix $(LIBDIR)/, libavl.$(LIB_SUFFIX))
+
+clientSDK: all
+
+all: $(OBJDEST) $(LIBDIR) $(LIBAVL)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
+
+$(LIBAVL): $(OBJS)
+ $(LINK_LIB)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ $(RM) $(LIBAVL)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
diff --git a/ldap/libraries/libavl/avl.c b/ldap/libraries/libavl/avl.c
new file mode 100644
index 00000000..f6fb61ad
--- /dev/null
+++ b/ldap/libraries/libavl/avl.c
@@ -0,0 +1,773 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* avl.c - routines to implement an avl tree */
+/*
+ * Copyright (c) 1993 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#if 0
+static char copyright[] = "@(#) Copyright (c) 1993 Regents of the University of Michigan.\nAll rights reserved.\n";
+static char avl_version[] = "AVL library version 1.0\n";
+#endif
+
+#ifdef _WIN32
+typedef char *caddr_t;
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#endif
+
+#include <sys/types.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "avl.h"
+
+#define ROTATERIGHT(x) { \
+ Avlnode *tmp;\
+ if ( *x == NULL || (*x)->avl_left == NULL ) {\
+ (void) printf("RR error\n"); exit(1); \
+ }\
+ tmp = (*x)->avl_left;\
+ (*x)->avl_left = tmp->avl_right;\
+ tmp->avl_right = *x;\
+ *x = tmp;\
+}
+#define ROTATELEFT(x) { \
+ Avlnode *tmp;\
+ if ( *x == NULL || (*x)->avl_right == NULL ) {\
+ (void) printf("RL error\n"); exit(1); \
+ }\
+ tmp = (*x)->avl_right;\
+ (*x)->avl_right = tmp->avl_left;\
+ tmp->avl_left = *x;\
+ *x = tmp;\
+}
+
+/*
+ * ravl_insert - called from avl_insert() to do a recursive insert into
+ * and balance of an avl tree.
+ */
+
+static int
+ravl_insert(
+ Avlnode **iroot,
+ caddr_t data,
+ int *taller,
+ IFP fcmp, /* comparison function */
+ IFP fdup, /* function to call for duplicates */
+ int depth
+)
+{
+ int rc, cmp, tallersub;
+ Avlnode *l, *r;
+
+ if ( *iroot == 0 ) {
+ if ( (*iroot = (Avlnode *) malloc( sizeof( Avlnode ) ))
+ == NULL ) {
+ return( -1 );
+ }
+ (*iroot)->avl_left = 0;
+ (*iroot)->avl_right = 0;
+ (*iroot)->avl_bf = 0;
+ (*iroot)->avl_data = data;
+ *taller = 1;
+ return( 0 );
+ }
+
+ cmp = (*fcmp)( data, (*iroot)->avl_data );
+
+ /* equal - duplicate name */
+ if ( cmp == 0 ) {
+ *taller = 0;
+ return( (*fdup)( (*iroot)->avl_data, data ) );
+ }
+
+ /* go right */
+ else if ( cmp > 0 ) {
+ rc = ravl_insert( &((*iroot)->avl_right), data, &tallersub,
+ fcmp, fdup, depth );
+ if ( tallersub )
+ switch ( (*iroot)->avl_bf ) {
+ case LH : /* left high - balance is restored */
+ (*iroot)->avl_bf = EH;
+ *taller = 0;
+ break;
+ case EH : /* equal height - now right heavy */
+ (*iroot)->avl_bf = RH;
+ *taller = 1;
+ break;
+ case RH : /* right heavy to start - right balance */
+ r = (*iroot)->avl_right;
+ switch ( r->avl_bf ) {
+ case LH : /* double rotation left */
+ l = r->avl_left;
+ switch ( l->avl_bf ) {
+ case LH : (*iroot)->avl_bf = EH;
+ r->avl_bf = RH;
+ break;
+ case EH : (*iroot)->avl_bf = EH;
+ r->avl_bf = EH;
+ break;
+ case RH : (*iroot)->avl_bf = LH;
+ r->avl_bf = EH;
+ break;
+ }
+ l->avl_bf = EH;
+ ROTATERIGHT( (&r) )
+ (*iroot)->avl_right = r;
+ ROTATELEFT( iroot )
+ *taller = 0;
+ break;
+ case EH : /* This should never happen */
+ break;
+ case RH : /* single rotation left */
+ (*iroot)->avl_bf = EH;
+ r->avl_bf = EH;
+ ROTATELEFT( iroot )
+ *taller = 0;
+ break;
+ }
+ break;
+ }
+ else
+ *taller = 0;
+ }
+
+ /* go left */
+ else {
+ rc = ravl_insert( &((*iroot)->avl_left), data, &tallersub,
+ fcmp, fdup, depth );
+ if ( tallersub )
+ switch ( (*iroot)->avl_bf ) {
+ case LH : /* left high to start - left balance */
+ l = (*iroot)->avl_left;
+ switch ( l->avl_bf ) {
+ case LH : /* single rotation right */
+ (*iroot)->avl_bf = EH;
+ l->avl_bf = EH;
+ ROTATERIGHT( iroot )
+ *taller = 0;
+ break;
+ case EH : /* this should never happen */
+ break;
+ case RH : /* double rotation right */
+ r = l->avl_right;
+ switch ( r->avl_bf ) {
+ case LH : (*iroot)->avl_bf = RH;
+ l->avl_bf = EH;
+ break;
+ case EH : (*iroot)->avl_bf = EH;
+ l->avl_bf = EH;
+ break;
+ case RH : (*iroot)->avl_bf = EH;
+ l->avl_bf = LH;
+ break;
+ }
+ r->avl_bf = EH;
+ ROTATELEFT( (&l) )
+ (*iroot)->avl_left = l;
+ ROTATERIGHT( iroot )
+ *taller = 0;
+ break;
+ }
+ break;
+ case EH : /* equal height - now left heavy */
+ (*iroot)->avl_bf = LH;
+ *taller = 1;
+ break;
+ case RH : /* right high - balance is restored */
+ (*iroot)->avl_bf = EH;
+ *taller = 0;
+ break;
+ }
+ else
+ *taller = 0;
+ }
+
+ return( rc );
+}
+
+/*
+ * avl_insert -- insert a node containing data data into the avl tree
+ * with root root. fcmp is a function to call to compare the data portion
+ * of two nodes. it should take two arguments and return <, >, or == 0,
+ * depending on whether its first argument is <, >, or == its second
+ * argument (like strcmp, e.g.). fdup is a function to call when a duplicate
+ * node is inserted. it should return 0, or -1 and its return value
+ * will be the return value from avl_insert in the case of a duplicate node.
+ * the function will be called with the original node's data as its first
+ * argument and with the incoming duplicate node's data as its second
+ * argument. this could be used, for example, to keep a count with each
+ * node.
+ *
+ * NOTE: this routine may malloc memory
+ */
+
+int
+avl_insert(
+ Avlnode **root,
+ caddr_t data,
+ IFP fcmp,
+ IFP fdup
+)
+{
+ int taller;
+
+ return( ravl_insert( root, data, &taller, fcmp, fdup, 0 ) );
+}
+
+/*
+ * right_balance() - called from delete when root's right subtree has
+ * been shortened because of a deletion.
+ */
+
+static int
+right_balance( Avlnode **root )
+{
+ int shorter= 0;
+ Avlnode *r, *l;
+
+ switch( (*root)->avl_bf ) {
+ case RH: /* was right high - equal now */
+ (*root)->avl_bf = EH;
+ shorter = 1;
+ break;
+ case EH: /* was equal - left high now */
+ (*root)->avl_bf = LH;
+ shorter = 0;
+ break;
+ case LH: /* was right high - balance */
+ l = (*root)->avl_left;
+ switch ( l->avl_bf ) {
+ case RH : /* double rotation left */
+ r = l->avl_right;
+ switch ( r->avl_bf ) {
+ case RH :
+ (*root)->avl_bf = EH;
+ l->avl_bf = LH;
+ break;
+ case EH :
+ (*root)->avl_bf = EH;
+ l->avl_bf = EH;
+ break;
+ case LH :
+ (*root)->avl_bf = RH;
+ l->avl_bf = EH;
+ break;
+ }
+ r->avl_bf = EH;
+ ROTATELEFT( (&l) )
+ (*root)->avl_left = l;
+ ROTATERIGHT( root )
+ shorter = 1;
+ break;
+ case EH : /* right rotation */
+ (*root)->avl_bf = LH;
+ l->avl_bf = RH;
+ ROTATERIGHT( root );
+ shorter = 0;
+ break;
+ case LH : /* single rotation right */
+ (*root)->avl_bf = EH;
+ l->avl_bf = EH;
+ ROTATERIGHT( root )
+ shorter = 1;
+ break;
+ }
+ break;
+ }
+
+ return( shorter );
+}
+
+/*
+ * left_balance() - called from delete when root's left subtree has
+ * been shortened because of a deletion.
+ */
+
+static int
+left_balance( Avlnode **root )
+{
+ int shorter= 0;
+ Avlnode *r, *l;
+
+ switch( (*root)->avl_bf ) {
+ case LH: /* was left high - equal now */
+ (*root)->avl_bf = EH;
+ shorter = 1;
+ break;
+ case EH: /* was equal - right high now */
+ (*root)->avl_bf = RH;
+ shorter = 0;
+ break;
+ case RH: /* was right high - balance */
+ r = (*root)->avl_right;
+ switch ( r->avl_bf ) {
+ case LH : /* double rotation left */
+ l = r->avl_left;
+ switch ( l->avl_bf ) {
+ case LH :
+ (*root)->avl_bf = EH;
+ r->avl_bf = RH;
+ break;
+ case EH :
+ (*root)->avl_bf = EH;
+ r->avl_bf = EH;
+ break;
+ case RH :
+ (*root)->avl_bf = LH;
+ r->avl_bf = EH;
+ break;
+ }
+ l->avl_bf = EH;
+ ROTATERIGHT( (&r) )
+ (*root)->avl_right = r;
+ ROTATELEFT( root )
+ shorter = 1;
+ break;
+ case EH : /* single rotation left */
+ (*root)->avl_bf = RH;
+ r->avl_bf = LH;
+ ROTATELEFT( root );
+ shorter = 0;
+ break;
+ case RH : /* single rotation left */
+ (*root)->avl_bf = EH;
+ r->avl_bf = EH;
+ ROTATELEFT( root )
+ shorter = 1;
+ break;
+ }
+ break;
+ }
+
+ return( shorter );
+}
+
+/*
+ * ravl_delete() - called from avl_delete to do recursive deletion of a
+ * node from an avl tree. It finds the node recursively, deletes it,
+ * and returns shorter if the tree is shorter after the deletion and
+ * rebalancing.
+ */
+
+static caddr_t
+ravl_delete(
+ Avlnode **root,
+ caddr_t data,
+ IFP fcmp,
+ int *shorter
+)
+{
+ int shortersubtree = 0;
+ int cmp;
+ caddr_t savedata;
+ Avlnode *minnode, *savenode;
+
+ if ( *root == NULLAVL )
+ return( 0 );
+
+ cmp = (*fcmp)( data, (*root)->avl_data );
+
+ /* found it! */
+ if ( cmp == 0 ) {
+ savenode = *root;
+ savedata = savenode->avl_data;
+
+ /* simple cases: no left child */
+ if ( (*root)->avl_left == 0 ) {
+ *root = (*root)->avl_right;
+ *shorter = 1;
+ free( (char *) savenode );
+ return( savedata );
+ /* no right child */
+ } else if ( (*root)->avl_right == 0 ) {
+ *root = (*root)->avl_left;
+ *shorter = 1;
+ free( (char *) savenode );
+ return( savedata );
+ }
+
+ /*
+ * avl_getmin will return to us the smallest node greater
+ * than the one we are trying to delete. deleting this node
+ * from the right subtree is guaranteed to end in one of the
+ * simple cases above.
+ */
+
+ minnode = (*root)->avl_right;
+ while ( minnode->avl_left != NULLAVL )
+ minnode = minnode->avl_left;
+
+ /* swap the data */
+ (*root)->avl_data = minnode->avl_data;
+ minnode->avl_data = savedata;
+
+ savedata = ravl_delete( &(*root)->avl_right, data, fcmp,
+ &shortersubtree );
+
+ if ( shortersubtree )
+ *shorter = right_balance( root );
+ else
+ *shorter = 0;
+ /* go left */
+ } else if ( cmp < 0 ) {
+ if ( (savedata = ravl_delete( &(*root)->avl_left, data, fcmp,
+ &shortersubtree )) == 0 ) {
+ *shorter = 0;
+ return( 0 );
+ }
+
+ /* left subtree shorter? */
+ if ( shortersubtree )
+ *shorter = left_balance( root );
+ else
+ *shorter = 0;
+ /* go right */
+ } else {
+ if ( (savedata = ravl_delete( &(*root)->avl_right, data, fcmp,
+ &shortersubtree )) == 0 ) {
+ *shorter = 0;
+ return( 0 );
+ }
+
+ if ( shortersubtree )
+ *shorter = right_balance( root );
+ else
+ *shorter = 0;
+ }
+
+ return( savedata );
+}
+
+/*
+ * avl_delete() - deletes the node containing data (according to fcmp) from
+ * the avl tree rooted at root.
+ */
+
+caddr_t
+avl_delete( Avlnode **root, caddr_t data, IFP fcmp )
+{
+ int shorter;
+
+ return( ravl_delete( root, data, fcmp, &shorter ) );
+}
+
+static int
+avl_inapply( Avlnode *root, IFP fn, caddr_t arg, int stopflag )
+{
+ if ( root == 0 )
+ return( AVL_NOMORE );
+
+ if ( root->avl_left != 0 )
+ if ( avl_inapply( root->avl_left, fn, arg, stopflag )
+ == stopflag )
+ return( stopflag );
+
+ if ( (*fn)( root->avl_data, arg ) == stopflag )
+ return( stopflag );
+
+ if ( root->avl_right == 0 )
+ return( AVL_NOMORE );
+ else
+ return( avl_inapply( root->avl_right, fn, arg, stopflag ) );
+}
+
+static int
+avl_postapply( Avlnode *root, IFP fn, caddr_t arg, int stopflag )
+{
+ if ( root == 0 )
+ return( AVL_NOMORE );
+
+ if ( root->avl_left != 0 )
+ if ( avl_postapply( root->avl_left, fn, arg, stopflag )
+ == stopflag )
+ return( stopflag );
+
+ if ( root->avl_right != 0 )
+ if ( avl_postapply( root->avl_right, fn, arg, stopflag )
+ == stopflag )
+ return( stopflag );
+
+ return( (*fn)( root->avl_data, arg ) );
+}
+
+static int
+avl_preapply( Avlnode *root, IFP fn, caddr_t arg, int stopflag )
+{
+ if ( root == 0 )
+ return( AVL_NOMORE );
+
+ if ( (*fn)( root->avl_data, arg ) == stopflag )
+ return( stopflag );
+
+ if ( root->avl_left != 0 )
+ if ( avl_preapply( root->avl_left, fn, arg, stopflag )
+ == stopflag )
+ return( stopflag );
+
+ if ( root->avl_right == 0 )
+ return( AVL_NOMORE );
+ else
+ return( avl_preapply( root->avl_right, fn, arg, stopflag ) );
+}
+
+/*
+ * avl_apply -- avl tree root is traversed, function fn is called with
+ * arguments arg and the data portion of each node. if fn returns stopflag,
+ * the traversal is cut short, otherwise it continues. Do not use -6 as
+ * a stopflag, as this is what is used to indicate the traversal ran out
+ * of nodes.
+ */
+
+int
+avl_apply(
+ Avlnode *root,
+ IFP fn,
+ caddr_t arg,
+ int stopflag,
+ int type
+)
+{
+ switch ( type ) {
+ case AVL_INORDER:
+ return( avl_inapply( root, fn, arg, stopflag ) );
+ case AVL_PREORDER:
+ return( avl_preapply( root, fn, arg, stopflag ) );
+ case AVL_POSTORDER:
+ return( avl_postapply( root, fn, arg, stopflag ) );
+ default:
+ fprintf( stderr, "Invalid traversal type %d\n", type );
+ return( -1 );
+ }
+
+ /* NOTREACHED */
+}
+
+/*
+ * avl_prefixapply - traverse avl tree root, applying function fprefix
+ * to any nodes that match. fcmp is called with data as its first arg
+ * and the current node's data as its second arg. it should return
+ * 0 if they match, < 0 if data is less, and > 0 if data is greater.
+ * the idea is to efficiently find all nodes that are prefixes of
+ * some key... Like avl_apply, this routine also takes a stopflag
+ * and will return prematurely if fmatch returns this value. Otherwise,
+ * AVL_NOMORE is returned.
+ */
+
+int
+avl_prefixapply(
+ Avlnode *root,
+ caddr_t data,
+ IFP fmatch,
+ caddr_t marg,
+ IFP fcmp,
+ caddr_t carg,
+ int stopflag
+)
+{
+ int cmp;
+
+ if ( root == 0 )
+ return( AVL_NOMORE );
+
+ cmp = (*fcmp)( data, root->avl_data, carg );
+ if ( cmp == 0 ) {
+ if ( (*fmatch)( root->avl_data, marg ) == stopflag )
+ return( stopflag );
+
+ if ( root->avl_left != 0 )
+ if ( avl_prefixapply( root->avl_left, data, fmatch,
+ marg, fcmp, carg, stopflag ) == stopflag )
+ return( stopflag );
+
+ if ( root->avl_right != 0 )
+ return( avl_prefixapply( root->avl_right, data, fmatch,
+ marg, fcmp, carg, stopflag ) );
+ else
+ return( AVL_NOMORE );
+
+ } else if ( cmp < 0 ) {
+ if ( root->avl_left != 0 )
+ return( avl_prefixapply( root->avl_left, data, fmatch,
+ marg, fcmp, carg, stopflag ) );
+ } else {
+ if ( root->avl_right != 0 )
+ return( avl_prefixapply( root->avl_right, data, fmatch,
+ marg, fcmp, carg, stopflag ) );
+ }
+
+ return( AVL_NOMORE );
+}
+
+/*
+ * avl_free -- traverse avltree root, freeing the memory it is using.
+ * the dfree() is called to free the data portion of each node. The
+ * number of items actually freed is returned.
+ */
+
+int
+avl_free( Avlnode *root, IFP dfree )
+{
+ int nleft, nright;
+
+ if ( root == 0 )
+ return( 0 );
+
+ nleft = nright = 0;
+ if ( root->avl_left != 0 )
+ nleft = avl_free( root->avl_left, dfree );
+
+ if ( root->avl_right != 0 )
+ nright = avl_free( root->avl_right, dfree );
+
+ if ( dfree )
+ (*dfree)( root->avl_data );
+
+ free( (char *)root );
+
+ return( nleft + nright + 1 );
+}
+
+/*
+ * avl_find -- search avltree root for a node with data data. the function
+ * cmp is used to compare things. it is called with data as its first arg
+ * and the current node data as its second. it should return 0 if they match,
+ * < 0 if arg1 is less than arg2 and > 0 if arg1 is greater than arg2.
+ */
+
+caddr_t
+avl_find( Avlnode *root, caddr_t data, IFP fcmp )
+{
+ int cmp;
+
+ while ( root != 0 && (cmp = (*fcmp)( data, root->avl_data )) != 0 ) {
+ if ( cmp < 0 )
+ root = root->avl_left;
+ else
+ root = root->avl_right;
+ }
+
+ return( root ? root->avl_data : 0 );
+}
+
+/*
+ * avl_find_lin -- search avltree root linearly for a node with data data.
+ * the function cmp is used to compare things. it is called with data as its
+ * first arg and the current node data as its second. it should return 0 if
+ * they match, non-zero otherwise.
+ */
+
+caddr_t
+avl_find_lin( Avlnode *root, caddr_t data, IFP fcmp )
+{
+ caddr_t res;
+
+ if ( root == 0 )
+ return( NULL );
+
+ if ( (*fcmp)( data, root->avl_data ) == 0 )
+ return( root->avl_data );
+
+ if ( root->avl_left != 0 )
+ if ( (res = avl_find_lin( root->avl_left, data, fcmp ))
+ != NULL )
+ return( res );
+
+ if ( root->avl_right == 0 )
+ return( NULL );
+ else
+ return( avl_find_lin( root->avl_right, data, fcmp ) );
+}
+
+static caddr_t *avl_list = (caddr_t *)0;
+static int avl_maxlist = 0;
+static int avl_nextlist = 0;
+
+#define AVL_GRABSIZE 100
+
+/* ARGSUSED */
+static int
+avl_buildlist( caddr_t data, int arg )
+{
+ static int slots = 0;
+
+ if ( avl_list == (caddr_t *) 0 ) {
+ avl_list = (caddr_t *) malloc(AVL_GRABSIZE * sizeof(caddr_t));
+ slots = AVL_GRABSIZE;
+ avl_maxlist = 0;
+ } else if ( avl_maxlist == slots ) {
+ slots += AVL_GRABSIZE;
+ avl_list = (caddr_t *) realloc( (char *) avl_list,
+ (unsigned) slots * sizeof(caddr_t));
+ }
+
+ avl_list[ avl_maxlist++ ] = data;
+
+ return( 0 );
+}
+
+/*
+ * avl_getfirst() and avl_getnext() are provided as alternate tree
+ * traversal methods, to be used when a single function cannot be
+ * provided to be called with every node in the tree. avl_getfirst()
+ * traverses the tree and builds a linear list of all the nodes,
+ * returning the first node. avl_getnext() returns the next thing
+ * on the list built by avl_getfirst(). This means that avl_getfirst()
+ * can take a while, and that the tree should not be messed with while
+ * being traversed in this way, and that multiple traversals (even of
+ * different trees) cannot be active at once.
+ */
+
+caddr_t
+avl_getfirst( Avlnode *root )
+{
+ if ( avl_list ) {
+ free( (char *) avl_list);
+ avl_list = (caddr_t *) 0;
+ }
+ avl_maxlist = 0;
+ avl_nextlist = 0;
+
+ if ( root == 0 )
+ return( 0 );
+
+ (void) avl_apply( root, avl_buildlist, (caddr_t) 0, -1, AVL_INORDER );
+
+ return( avl_list[ avl_nextlist++ ] );
+}
+
+caddr_t
+avl_getnext()
+{
+ if ( avl_list == 0 )
+ return( 0 );
+
+ if ( avl_nextlist == avl_maxlist ) {
+ free( (caddr_t) avl_list);
+ avl_list = (caddr_t *) 0;
+ return( 0 );
+ }
+
+ return( avl_list[ avl_nextlist++ ] );
+}
+
+int avl_dup_error()
+{
+ return( -1 );
+}
+
+int avl_dup_ok()
+{
+ return( 0 );
+}
diff --git a/ldap/libraries/libavl/testavl.c b/ldap/libraries/libavl/testavl.c
new file mode 100644
index 00000000..6efe8c84
--- /dev/null
+++ b/ldap/libraries/libavl/testavl.c
@@ -0,0 +1,125 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* testavl.c - Test Tim Howes AVL code */
+#ifdef _WIN32
+#include <windows.h>
+#endif
+#include <sys/types.h>
+#include <stdio.h>
+#include "avl.h"
+
+char *strdup( s )
+char *s;
+{
+ char *new;
+
+ if ( (new = (char *) malloc( strlen( s ) + 1 )) == NULL )
+ return( NULL );
+
+ strcpy( new, s );
+
+ return( new );
+}
+
+main( argc, argv )
+int argc;
+char **argv;
+{
+ Avlnode *tree = NULLAVL;
+ char command[ 10 ];
+ char name[ 80 ];
+ char *p;
+ int free(), strcmp();
+
+ printf( "> " );
+ while ( fgets( command, sizeof( command ), stdin ) != NULL ) {
+ switch( *command ) {
+ case 'n': /* new tree */
+ ( void ) avl_free( tree, free );
+ tree = NULLAVL;
+ break;
+ case 'p': /* print */
+ ( void ) myprint( tree );
+ break;
+ case 't': /* traverse with first, next */
+ printf( "***\n" );
+ for ( p = (char * ) avl_getfirst( tree );
+ p != NULL; p = (char *) avl_getnext( tree, p ) )
+ printf( "%s\n", p );
+ printf( "***\n" );
+ break;
+ case 'f': /* find */
+ printf( "data? " );
+ if ( fgets( name, sizeof( name ), stdin ) == NULL )
+ exit( 0 );
+ name[ strlen( name ) - 1 ] = '\0';
+ if ( (p = (char *) avl_find( tree, name, strcmp ))
+ == NULL )
+ printf( "Not found.\n\n" );
+ else
+ printf( "%s\n\n", p );
+ break;
+ case 'i': /* insert */
+ printf( "data? " );
+ if ( fgets( name, sizeof( name ), stdin ) == NULL )
+ exit( 0 );
+ name[ strlen( name ) - 1 ] = '\0';
+ if ( avl_insert( &tree, strdup( name ), strcmp,
+ avl_dup_error ) != OK )
+ printf( "\nNot inserted!\n" );
+ break;
+ case 'd': /* delete */
+ printf( "data? " );
+ if ( fgets( name, sizeof( name ), stdin ) == NULL )
+ exit( 0 );
+ name[ strlen( name ) - 1 ] = '\0';
+ if ( avl_delete( &tree, name, strcmp ) == NULL )
+ printf( "\nNot found!\n" );
+ break;
+ case 'q': /* quit */
+ exit( 0 );
+ break;
+ case '\n':
+ break;
+ default:
+ printf("Commands: insert, delete, print, new, quit\n");
+ }
+
+ printf( "> " );
+ }
+ /* NOTREACHED */
+}
+
+static ravl_print( root, depth )
+Avlnode *root;
+int depth;
+{
+ int i;
+
+ if ( root == 0 )
+ return;
+
+ ravl_print( root->avl_right, depth+1 );
+
+ for ( i = 0; i < depth; i++ )
+ printf( " " );
+ printf( "%s %d\n", root->avl_data, root->avl_bf );
+
+ ravl_print( root->avl_left, depth+1 );
+}
+
+myprint( root )
+Avlnode *root;
+{
+ printf( "********\n" );
+
+ if ( root == 0 )
+ printf( "\tNULL\n" );
+ else
+ ( void ) ravl_print( root, 0 );
+
+ printf( "********\n" );
+}
diff --git a/ldap/libraries/libldif/Makefile b/ldap/libraries/libldif/Makefile
new file mode 100644
index 00000000..5420662c
--- /dev/null
+++ b/ldap/libraries/libldif/Makefile
@@ -0,0 +1,52 @@
+#
+# 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 libldif
+#
+
+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 = $(OBJDIR)/lib/libldif
+LIBDIR = $(LDAP_LIBDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+CFLAGS += $(SLCFLAGS)
+
+LIBLDIF_OBJS= line64.o fileurl.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(LIBLDIF_OBJS))
+
+LIBLDIF= $(addprefix $(LIBDIR)/, libldif.$(LIB_SUFFIX))
+
+clientSDK: all
+
+all: $(OBJDEST) $(LIBDIR) $(OBJS) $(LIBLDIF)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
+
+$(LIBLDIF): $(OBJS)
+ $(LINK_LIB)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ $(RM) $(LIBLDIF)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
diff --git a/ldap/libraries/libldif/fileurl.c b/ldap/libraries/libldif/fileurl.c
new file mode 100644
index 00000000..b8c65aba
--- /dev/null
+++ b/ldap/libraries/libldif/fileurl.c
@@ -0,0 +1,289 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * LDIF tools fileurl.c -- functions for handling file URLs.
+ * Used by ldif_parse_line.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "fileurl.h"
+#include <ctype.h> /* for isalpha() */
+
+static int str_starts_with( char *s, char *prefix );
+static void hex_unescape( char *s );
+static int unhex( char c );
+static void strcpy_escaped_and_convert( char *s1, char *s2 );
+
+/*
+ * Convert a file URL to a local path.
+ *
+ * If successful, LDIF_FILEURL_SUCCESS is returned and *localpathp is
+ * set point to an allocated string. If not, an different LDIF_FILEURL_
+ * error code is returned.
+ *
+ * See RFCs 1738 and 2396 for a specification for file URLs... but
+ * Netscape Navigator seems to be a bit more lenient in what it will
+ * accept, especially on Windows).
+ *
+ * This function parses file URLs of these three forms:
+ *
+ * file:///path
+ * file:/path
+ * file://localhost/path
+ * file://host/path (rejected with a ...NONLOCAL error)
+ *
+ * On Windows, we convert leading drive letters of the form C| to C:
+ * and if a drive letter is present we strip off the slash that precedes
+ * path. Otherwise, the leading slash is returned.
+ *
+ */
+int
+ldif_fileurl2path( char *fileurl, char **localpathp )
+{
+ char *path;
+
+ /*
+ * Make sure this is a file name or URL we can handle.
+ */
+ if ( *fileurl == '/' ||
+ ( isalpha( fileurl[0] ) && ( fileurl[1] == '|' || fileurl[1] == ':' ) ) ) {
+ path = fileurl;
+ goto path_ready;
+ } else if ( !str_starts_with( fileurl, "file:" )) {
+ return( LDIF_FILEURL_NOTAFILEURL );
+ }
+
+ path = fileurl + 5; /* skip past "file:" scheme prefix */
+
+ if ( *path != '/' ) {
+ return( LDIF_FILEURL_MISSINGPATH );
+ }
+
+ ++path; /* skip past '/' at end of "file:/" */
+
+ if ( *path == '/' ) {
+ ++path; /* remainder is now host/path or /path */
+ if ( *path != '/' ) {
+ /*
+ * Make sure it is for the local host.
+ */
+ if ( str_starts_with( path, "localhost/" )) {
+ path += 9;
+ } else {
+ return( LDIF_FILEURL_NONLOCAL );
+ }
+ }
+ } else { /* URL is of the form file:/path */
+ --path;
+ }
+
+ /*
+ * The remainder is now of the form /path. On Windows, skip past the
+ * leading slash if a drive letter is present.
+ */
+#ifdef _WIN32
+ if ( isalpha( path[1] ) && ( path[2] == '|' || path[2] == ':' )) {
+ ++path;
+ }
+#endif /* _WIN32 */
+
+
+ path_ready:
+ /*
+ * Duplicate the path so we can safely alter it.
+ * Unescape any %HH sequences.
+ */
+ if (( path = strdup( path )) == NULL ) {
+ return( LDIF_FILEURL_NOMEMORY );
+ }
+ hex_unescape( path );
+
+#ifdef _WIN32
+ /*
+ * Convert forward slashes to backslashes for Windows. Also,
+ * if we see a drive letter / vertical bar combination (e.g., c|)
+ * at the beginning of the path, replace the '|' with a ':'.
+ */
+ {
+ char *p;
+
+ for ( p = path; *p != '\0'; ++p ) {
+ if ( *p == '/' ) {
+ *p = '\\';
+ }
+ }
+ }
+
+ if ( isalpha( path[0] ) && path[1] == '|' ) {
+ path[1] = ':';
+ }
+#endif /* _WIN32 */
+
+ *localpathp = path;
+ return( LDIF_FILEURL_SUCCESS );
+}
+
+
+/*
+ * Convert a local path to a file URL.
+ *
+ * If successful, LDIF_FILEURL_SUCCESS is returned and *urlp is
+ * set point to an allocated string. If not, an different LDIF_FILEURL_
+ * error code is returned. At present, the only possible error is
+ * LDIF_FILEURL_NOMEMORY.
+ *
+ * This function produces file URLs of the form file:path.
+ *
+ * On Windows, we convert leading drive letters to C|.
+ *
+ */
+int
+ldif_path2fileurl( char *path, char **urlp )
+{
+ char *p, *url, *prefix ="file:";
+
+ if ( NULL == path ) {
+ path = "/";
+ }
+
+ /*
+ * Allocate space for the URL, taking into account that path may
+ * expand during the hex escaping process.
+ */
+ if (( url = malloc( strlen( prefix ) + 3 * strlen( path ) + 1 )) == NULL ) {
+ return( LDIF_FILEURL_NOMEMORY );
+ }
+
+ strcpy( url, prefix );
+ p = url + strlen( prefix );
+
+#ifdef _WIN32
+ /*
+ * On Windows, convert leading drive letters (e.g., C:) to the correct URL
+ * syntax (e.g., C|).
+ */
+ if ( isalpha( path[0] ) && path[1] == ':' ) {
+ *p++ = path[0];
+ *p++ = '|';
+ path += 2;
+ *p = '\0';
+ }
+#endif /* _WIN32 */
+
+ /*
+ * Append the path, encoding any URL-special characters using the %HH
+ * convention.
+ * On Windows, convert backwards slashes in the path to forward ones.
+ */
+ strcpy_escaped_and_convert( p, path );
+
+ *urlp = url;
+ return( LDIF_FILEURL_SUCCESS );
+}
+
+
+/*
+ * Return a non-zero value if the string s begins with prefix and zero if not.
+ */
+static int
+str_starts_with( char *s, char *prefix )
+{
+ size_t prefix_len;
+
+ if ( s == NULL || prefix == NULL ) {
+ return( 0 );
+ }
+
+ prefix_len = strlen( prefix );
+ if ( strlen( s ) < prefix_len ) {
+ return( 0 );
+ }
+
+ return( strncmp( s, prefix, prefix_len ) == 0 );
+}
+
+
+/*
+ * Remove URL hex escapes from s... done in place. The basic concept for
+ * this routine is borrowed from the WWW library HTUnEscape() routine.
+ *
+ */
+static void
+hex_unescape( char *s )
+{
+ char *p;
+
+ for ( p = s; *s != '\0'; ++s ) {
+ if ( *s == '%' ) {
+ if ( *++s != '\0' ) {
+ *p = unhex( *s ) << 4;
+ }
+ if ( *++s != '\0' ) {
+ *p++ += unhex( *s );
+ }
+ } else {
+ *p++ = *s;
+ }
+ }
+
+ *p = '\0';
+}
+
+
+/*
+ * Return the integer equivalent of one hex digit (in c).
+ *
+ */
+static int
+unhex( char c )
+{
+ return( c >= '0' && c <= '9' ? c - '0'
+ : c >= 'A' && c <= 'F' ? c - 'A' + 10
+ : c - 'a' + 10 );
+}
+
+
+#define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \
+ ( c >= '@' && c <= 'Z' ) || \
+ ( c == '_' ) || \
+ ( c >= 'a' && c <= 'z' ))
+
+/*
+ * Like strcat(), except if any URL-special characters are found in s2
+ * they are escaped using the %HH convention and backslash characters are
+ * converted to forward slashes on Windows.
+ *
+ * Maximum space needed in s1 is 3 * strlen( s2 ) + 1.
+ *
+ */
+static void
+strcpy_escaped_and_convert( char *s1, char *s2 )
+{
+ char *p, *q;
+ char *hexdig = "0123456789ABCDEF";
+
+ p = s1 + strlen( s1 );
+ for ( q = s2; *q != '\0'; ++q ) {
+#ifdef _WIN32
+ if ( *q == '\\' ) {
+ *p++ = '/';
+ } else
+#endif /* _WIN32 */
+
+ if ( HREF_CHAR_ACCEPTABLE( *q )) {
+ *p++ = *q;
+ } else {
+ *p++ = '%';
+ *p++ = hexdig[ 0x0F & ((*(unsigned char*)q) >> 4) ];
+ *p++ = hexdig[ 0x0F & *q ];
+ }
+ }
+
+ *p = '\0';
+}
diff --git a/ldap/libraries/libldif/fileurl.h b/ldap/libraries/libldif/fileurl.h
new file mode 100644
index 00000000..727a641c
--- /dev/null
+++ b/ldap/libraries/libldif/fileurl.h
@@ -0,0 +1,40 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * LDIF tools fileurl.h -- defines for file URL functions.
+ * Used by ldif_parse_line.
+ */
+
+/*
+ * ldif_fileurl2path() convert a file URL to a local path.
+ *
+ * If successful, LDIF_FILEURL_SUCCESS is returned and *localpathp is
+ * set point to an allocated string. If not, an differnet LDIF_FILEURL_
+ * error code is returned.
+ */
+int ldif_fileurl2path( char *fileurl, char **localpathp );
+
+
+/*
+ * Convert a local path to a file URL.
+ *
+ * If successful, LDIF_FILEURL_SUCCESS is returned and *urlp is
+ * set point to an allocated string. If not, an different LDIF_FILEURL_
+ * error code is returned. At present, the only possible error is
+ * LDIF_FILEURL_NOMEMORY.
+ *
+ */
+int ldif_path2fileurl( char *path, char **urlp );
+
+
+/*
+ * Possible return codes for ldif_fileurl2path and ldif_path2fileurl.
+ */
+#define LDIF_FILEURL_SUCCESS 0
+#define LDIF_FILEURL_NOTAFILEURL 1
+#define LDIF_FILEURL_MISSINGPATH 2
+#define LDIF_FILEURL_NONLOCAL 3
+#define LDIF_FILEURL_NOMEMORY 4
diff --git a/ldap/libraries/libldif/line64.c b/ldap/libraries/libldif/line64.c
new file mode 100644
index 00000000..ade33a91
--- /dev/null
+++ b/ldap/libraries/libldif/line64.c
@@ -0,0 +1,743 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.0 (the "NPL"); you may not use this file except in
+ * compliance with the NPL. You may obtain a copy of the NPL at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the NPL is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
+ * for the specific language governing rights and limitations under the
+ * NPL.
+ *
+ * The Initial Developer of this code under the NPL is Netscape
+ * Communications Corporation. Portions created by Netscape are
+ * Copyright (C) 1998 Netscape Communications Corporation. All Rights
+ * Reserved.
+ */
+/* line64.c - routines for dealing with the slapd line format */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#ifndef macintosh
+#include <sys/types.h>
+#endif
+#ifdef _WIN32
+#include <windows.h>
+#elif !defined( macintosh )
+#include <sys/socket.h>
+#endif
+#include "ldaplog.h"
+#include "ldif.h"
+#include <errno.h>
+#include "lber.h"
+#include <sys/stat.h>
+#include "fileurl.h"
+
+#ifndef isascii
+#define isascii( c ) (!((c) & ~0177))
+#endif
+
+#define RIGHT2 0x03
+#define RIGHT4 0x0f
+#define CONTINUED_LINE_MARKER '\001'
+
+#define ISBLANK(c) (c == ' ' || c == '\t' || c == '\n') /* not "\r\v\f" */
+
+#define LDIF_OPT_ISSET( value, opt ) (((value) & (opt)) != 0 )
+
+static char nib2b64[0x40] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static unsigned char b642nib[0x80] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
+ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
+ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
+ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
+ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
+ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff
+};
+
+static int ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen,
+ int lenused, int wraplen );
+
+static int ldif_fromfile( char *path, struct berval *bv );
+
+extern int errno;
+/*
+ * ldif_parse_line - takes a line of the form "type:[:] value" and splits it
+ * into components "type" and "value". if a double colon separates type from
+ * value, then value is encoded in base 64, and parse_line un-decodes it
+ * (in place) before returning.
+ * Success return might be 0 (value is returned in place) or 1 (value has
+ * been malloc'ed)
+ */
+
+int
+ldif_parse_line(
+ char *line,
+ char **type,
+ char **value,
+ int *vlen,
+ char **errmsg
+)
+{
+ char *p, *s, *d;
+ int b64;
+ int url = 0;
+ int rc = 0;
+
+ *errmsg = NULL;
+
+ /* skip any leading space */
+ while ( ISBLANK( *line ) ) {
+ line++;
+ }
+ *type = line;
+
+ for ( s = line; *s && *s != ':'; s++ )
+ ; /* NULL */
+ if ( *s == '\0' ) {
+
+ /* Comment-out while we address calling libldif from ns-back-ldbm
+ on NT. 1 of 3 */
+#if defined( _WIN32 )
+ /*
+#endif
+ LDAPDebug( LDAP_DEBUG_PARSE, "ldif_parse_line: missing ':' "
+ "on line \"%s\"\n", line, 0, 0 );
+#if defined( _WIN32 )
+ */
+#endif
+ return( -1 );
+ }
+
+ /* trim any space between type and : */
+ for ( p = s - 1; p > line && ISBLANK( *p ); p-- ) {
+ *p = '\0';
+ }
+ *s++ = '\0';
+
+ /* check for double : - indicates base 64 encoded value */
+ if ( *s == ':' ) {
+ s++;
+ b64 = 1;
+
+ /* single : - normally encoded value */
+ } else {
+ /* check for ":<" - indicates value is actually an url */
+ if (*s == '<') {
+ s++;
+ url = 1;
+ }
+ b64 = 0;
+ }
+
+ /* skip space between : and value */
+ while ( ISBLANK( *s ) ) {
+ s++;
+ }
+
+ /*
+ * If no value is present, return a zero-length string for
+ * *value, with *vlen set to zero.
+ */
+ if ( *s == '\0' ) {
+ *value = s;
+ *vlen = 0;
+ return( 0 );
+ }
+
+ /* check for continued line markers that should be deleted */
+ for ( p = s, d = s; *p; p++ ) {
+ if ( *p != CONTINUED_LINE_MARKER )
+ *d++ = *p;
+ }
+ *d = '\0';
+
+ *value = s;
+ if ( b64 ) {
+ if (( *vlen = ldif_base64_decode( s, (unsigned char *)s ))
+ < 0 ) {
+ /* Comment-out while we address calling libldif from ns-back-ldbm
+ on NT. 3 of 3 */
+#if defined( _WIN32 )
+ /*
+#endif
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ldif_parse_line: invalid base 64 char on line \"%s\"\n",
+ line, 0, 0 );
+#if defined( _WIN32 )
+ */
+#endif
+ return( -1 );
+ }
+ s[ *vlen ] = '\0';
+
+ } else if (url) {
+
+ char *path;
+ struct stat fstats;
+ struct berval bv;
+
+ bv.bv_val = NULL;
+
+ if (( *errmsg = (char *)malloc( strlen(s) + 1024 )) == NULL ) {
+ return (-1);
+ }
+
+ /*
+ * We only support file:// URLs for now.
+ */
+
+ switch( ldif_fileurl2path( s, &path )) {
+ case LDIF_FILEURL_NOTAFILEURL:
+ sprintf(*errmsg,
+ "ldif_parse_line: unsupported URL \"%S\";"
+ " use a file:// URL instead.\n", s);
+ rc = -1;
+ break;
+
+ case LDIF_FILEURL_MISSINGPATH:
+ sprintf(*errmsg,
+ "ldif_parse_line: unable to process URL \"%S\" --"
+ " missing path..\n", s);
+ rc = -1;
+ break;
+
+ case LDIF_FILEURL_NONLOCAL:
+ sprintf(*errmsg,
+ "ldif_parse_line: unable to process URL \"%S\" --"
+ " only local file:// URLs are supported.\n", s);
+ rc = -1;
+ break;
+
+ case LDIF_FILEURL_NOMEMORY:
+ perror( "ldif_fileurl2path" );
+ rc = -1;
+ break;
+
+ case LDIF_FILEURL_SUCCESS:
+ if ( stat( path, &fstats ) != 0 ) {
+ perror( path );
+ rc = -1;
+ } else if ( fstats.st_mode & S_IFDIR ) {
+ sprintf(*errmsg,
+ "ldif_parse_line: %s is a directory, not a file.\n", path);
+ rc = -1;
+ } else if ( ldif_fromfile( path, &bv ) < 0 ) {
+ sprintf(*errmsg,
+ "ldif_parse_line: unable to retrieve information"
+ " from file %s.\n", path);
+ rc = -1;
+ }
+ free( path );
+ break;
+
+ default:
+ sprintf(*errmsg,
+ "ldif_parse_line: unable to process URL \"%S\" --"
+ " unknown error.\n", s);
+ rc = -1;
+ }
+
+
+ if ( rc != 0 ) {
+ if (bv.bv_val)
+ free(bv.bv_val);
+ } else {
+ *value = bv.bv_val;
+ *vlen = bv.bv_len;
+ rc = 1;
+ }
+ } else {
+ *vlen = (int) (d - s);
+ }
+
+ return( rc );
+}
+
+
+/*
+ * ldif_base64_decode - take the BASE64-encoded characters in "src"
+ * (a zero-terminated string) and decode them into the the buffer "dst".
+ * "src" and "dst" can be the same if in-place decoding is desired.
+ * "dst" must be large enough to hold the decoded octets. No more than
+ * 3 * strlen( src ) / 4 bytes will be produced.
+ * "dst" may contain zero octets anywhere within it, but it is not
+ * zero-terminated by this function.
+ *
+ * The number of bytes copied to "dst" is returned if all goes well.
+ * -1 is returned if the BASE64 encoding in "src" is invalid.
+ */
+
+int
+ldif_base64_decode( char *src, unsigned char *dst )
+{
+ char *p, *stop;
+ unsigned char nib, *byte;
+ int i, len;
+
+ stop = strchr( src, '\0' );
+ byte = dst;
+ for ( p = src, len = 0; p < stop; p += 4, len += 3 ) {
+ for ( i = 0; i < 4; i++ ) {
+ if ( p[i] != '=' && (p[i] & 0x80 ||
+ b642nib[ p[i] & 0x7f ] > 0x3f) ) {
+ return( -1 );
+ }
+ }
+
+ /* first digit */
+ nib = b642nib[ p[0] & 0x7f ];
+ byte[0] = nib << 2;
+
+ /* second digit */
+ nib = b642nib[ p[1] & 0x7f ];
+ byte[0] |= nib >> 4;
+
+ /* third digit */
+ if ( p[2] == '=' ) {
+ len += 1;
+ break;
+ }
+ byte[1] = (nib & RIGHT4) << 4;
+ nib = b642nib[ p[2] & 0x7f ];
+ byte[1] |= nib >> 2;
+
+ /* fourth digit */
+ if ( p[3] == '=' ) {
+ len += 2;
+ break;
+ }
+ byte[2] = (nib & RIGHT2) << 6;
+ nib = b642nib[ p[3] & 0x7f ];
+ byte[2] |= nib;
+
+ byte += 3;
+ }
+
+ return( len );
+}
+
+/*
+ * ldif_getline - return the next "line" (minus newline) of input from a
+ * string buffer of lines separated by newlines, terminated by \n\n
+ * or \0. this routine handles continued lines, bundling them into
+ * a single big line before returning. if a line begins with a white
+ * space character, it is a continuation of the previous line. the white
+ * space character (nb: only one char), and preceeding newline are changed
+ * into CONTINUED_LINE_MARKER chars, to be deleted later by the
+ * ldif_parse_line() routine above.
+ *
+ * it takes a pointer to a pointer to the buffer on the first call,
+ * which it updates and must be supplied on subsequent calls.
+ *
+ * XXX need to update this function to also support <CR><LF> as EOL.
+ * XXX supports <CR><LF> as of 07/29/1998 (richm)
+ */
+
+char *
+ldif_getline( char **next )
+{
+ char *l;
+ char c;
+ char *p;
+
+ if ( *next == NULL || **next == '\n' || **next == '\0' ) {
+ return( NULL );
+ }
+
+ while ( **next == '#' ) { /* skip comment lines */
+ if (( *next = strchr( *next, '\n' )) == NULL ) {
+ return( NULL );
+ }
+ (*next)++;
+ }
+
+ l = *next;
+ while ( (*next = strchr( *next, '\n' )) != NULL ) {
+ p = *next - 1; /* pointer to character previous to the newline */
+ c = *(*next + 1); /* character after the newline */
+ if ( ISBLANK( c ) && c != '\n' ) {
+ /* DOS EOL is \r\n, so if the character before */
+ /* the \n is \r, continue it too */
+ if (*p == '\r')
+ *p = CONTINUED_LINE_MARKER;
+ **next = CONTINUED_LINE_MARKER;
+ *(*next+1) = CONTINUED_LINE_MARKER;
+ } else {
+ /* DOS EOL is \r\n, so if the character before */
+ /* the \n is \r, null it too */
+ if (*p == '\r')
+ *p = '\0';
+ *(*next)++ = '\0';
+ break;
+ }
+ (*next)++;
+ }
+
+ return( l );
+}
+
+
+#define LDIF_SAFE_CHAR( c ) ( (c) != '\r' && (c) != '\n' )
+#define LDIF_CONSERVATIVE_CHAR( c ) ( LDIF_SAFE_CHAR(c) && isascii((c)) \
+ && ( isprint((c)) || (c) == '\t' ))
+#define LDIF_SAFE_INITCHAR( c ) ( LDIF_SAFE_CHAR(c) && (c) != ':' \
+ && (c) != ' ' && (c) != '<' )
+#define LDIF_CONSERVATIVE_INITCHAR( c ) ( LDIF_SAFE_INITCHAR( c ) && \
+ ! ( isascii((c)) && isspace((c))))
+#define LDIF_CONSERVATIVE_FINALCHAR( c ) ( (c) != ' ' )
+
+
+void
+ldif_put_type_and_value_with_options( char **out, char *t, char *val,
+ int vlen, unsigned long options )
+{
+ unsigned char *p, *byte, *stop;
+ char *save;
+ int b64, len, savelen, wraplen;
+ len = 0;
+
+ if ( LDIF_OPT_ISSET( options, LDIF_OPT_NOWRAP )) {
+ wraplen = -1;
+ } else {
+ wraplen = LDIF_MAX_LINE_WIDTH;
+ }
+
+ /* put the type + ": " */
+ for ( p = (unsigned char *) t; *p; p++, len++ ) {
+ *(*out)++ = *p;
+ }
+ *(*out)++ = ':';
+ len++;
+ if ( LDIF_OPT_ISSET( options, LDIF_OPT_VALUE_IS_URL )) {
+ *(*out)++ = '<'; /* add '<' for URLs */
+ len++;
+ }
+ save = *out;
+ savelen = len;
+ b64 = 0;
+
+ stop = (unsigned char *)val;
+ if ( val && vlen > 0 ) {
+ *(*out)++ = ' ';
+ stop = (unsigned char *) (val + vlen);
+ if ( LDIF_OPT_ISSET( options, LDIF_OPT_MINIMAL_ENCODING )) {
+ if ( !LDIF_SAFE_INITCHAR( val[0] )) {
+ b64 = 1;
+ }
+ } else {
+ if ( !LDIF_CONSERVATIVE_INITCHAR( val[0] ) ||
+ !LDIF_CONSERVATIVE_FINALCHAR( val[vlen-1] )) {
+ b64 = 1;
+ }
+ }
+ }
+
+ if ( !b64 ) {
+ for ( byte = (unsigned char *) val; byte < stop;
+ byte++, len++ ) {
+ if ( LDIF_OPT_ISSET( options,
+ LDIF_OPT_MINIMAL_ENCODING )) {
+ if ( !LDIF_SAFE_CHAR( *byte )) {
+ b64 = 1;
+ break;
+ }
+ } else if ( !LDIF_CONSERVATIVE_CHAR( *byte )) {
+ b64 = 1;
+ break;
+ }
+
+ if ( wraplen != -1 && len > wraplen ) {
+ *(*out)++ = '\n';
+ *(*out)++ = ' ';
+ len = 1;
+ }
+ *(*out)++ = *byte;
+ }
+ }
+
+ if ( b64 ) {
+ *out = save;
+ *(*out)++ = ':';
+ *(*out)++ = ' ';
+ len = ldif_base64_encode_internal( (unsigned char *)val, *out, vlen,
+ savelen + 2, wraplen );
+ *out += len;
+ }
+
+ *(*out)++ = '\n';
+}
+
+void
+ldif_put_type_and_value( char **out, char *t, char *val, int vlen )
+{
+ ldif_put_type_and_value_with_options( out, t, val, vlen, 0 );
+}
+
+void
+ldif_put_type_and_value_nowrap( char **out, char *t, char *val, int vlen )
+{
+ ldif_put_type_and_value_with_options( out, t, val, vlen, LDIF_OPT_NOWRAP );
+}
+
+/*
+ * ldif_base64_encode_internal - encode "srclen" bytes in "src", place BASE64
+ * encoded bytes in "dst" and return the length of the BASE64
+ * encoded string. "dst" is also zero-terminated by this function.
+ *
+ * If "lenused" >= 0, newlines will be included in "dst" and "lenused" if
+ * appropriate. "lenused" should be a count of characters already used
+ * on the current line. The LDIF lines we create will contain at most
+ * "wraplen" characters on each line, unless "wraplen" is -1, in which
+ * case output line length is unlimited.
+ *
+ * If "lenused" < 0, no newlines will be included, and the LDIF_BASE64_LEN()
+ * macro can be used to determine how many bytes will be placed in "dst."
+ */
+
+static int
+ldif_base64_encode_internal( unsigned char *src, char *dst, int srclen, int lenused, int wraplen )
+{
+ unsigned char *byte, *stop;
+ unsigned char buf[3];
+ char *out;
+ unsigned long bits;
+ int i, pad, len;
+
+ len = 0;
+ out = dst;
+ stop = src + srclen;
+
+ /* convert to base 64 (3 bytes => 4 base 64 digits) */
+ for ( byte = src; byte < stop - 2; byte += 3 ) {
+ bits = (byte[0] & 0xff) << 16;
+ bits |= (byte[1] & 0xff) << 8;
+ bits |= (byte[2] & 0xff);
+
+ for ( i = 0; i < 4; i++, bits <<= 6 ) {
+ if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) {
+ *out++ = '\n';
+ *out++ = ' ';
+ lenused = 2;
+ }
+
+ /* get b64 digit from high order 6 bits */
+ *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
+ }
+ }
+
+ /* add padding if necessary */
+ if ( byte < stop ) {
+ for ( i = 0; byte + i < stop; i++ ) {
+ buf[i] = byte[i];
+ }
+ for ( pad = 0; i < 3; i++, pad++ ) {
+ buf[i] = '\0';
+ }
+ byte = buf;
+ bits = (byte[0] & 0xff) << 16;
+ bits |= (byte[1] & 0xff) << 8;
+ bits |= (byte[2] & 0xff);
+
+ for ( i = 0; i < 4; i++, bits <<= 6 ) {
+ if ( wraplen != -1 && lenused >= 0 && lenused++ > wraplen ) {
+ *out++ = '\n';
+ *out++ = ' ';
+ lenused = 2;
+ }
+
+ if (( i == 3 && pad > 0 ) || ( i == 2 && pad == 2 )) {
+ /* Pad as appropriate */
+ *out++ = '=';
+ } else {
+ /* get b64 digit from low order 6 bits */
+ *out++ = nib2b64[ (bits & 0xfc0000L) >> 18 ];
+ }
+ }
+ }
+
+ *out = '\0';
+
+ return( out - dst );
+}
+
+int
+ldif_base64_encode( unsigned char *src, char *dst, int srclen, int lenused )
+{
+ return ldif_base64_encode_internal( src, dst, srclen, lenused, LDIF_MAX_LINE_WIDTH );
+}
+
+int
+ldif_base64_encode_nowrap( unsigned char *src, char *dst, int srclen, int lenused )
+{
+ return ldif_base64_encode_internal( src, dst, srclen, lenused, -1 );
+}
+
+
+/*
+ * return malloc'd, zero-terminated LDIF line
+ */
+char *
+ldif_type_and_value_with_options( char *type, char *val, int vlen,
+ unsigned long options )
+{
+ char *buf, *p;
+ int tlen;
+
+ tlen = strlen( type );
+ if (( buf = (char *)malloc( LDIF_SIZE_NEEDED( tlen, vlen ) + 1 )) !=
+ NULL ) {
+ p = buf;
+ ldif_put_type_and_value_with_options( &p, type, val, vlen, options );
+ *p = '\0';
+ }
+
+ return( buf );
+}
+
+char *
+ldif_type_and_value( char *type, char *val, int vlen )
+{
+ return ldif_type_and_value_with_options( type, val, vlen, 0 );
+}
+
+char *
+ldif_type_and_value_nowrap( char *type, char *val, int vlen )
+{
+ return ldif_type_and_value_with_options( type, val, vlen, LDIF_OPT_NOWRAP );
+}
+
+/*
+ * ldif_get_entry - read the next ldif entry from the FILE referenced
+ * by fp. return a pointer to a malloc'd, null-terminated buffer. also
+ * returned is the last line number read, in *lineno.
+ */
+char *
+ldif_get_entry( FILE *fp, int *lineno )
+{
+ char line[BUFSIZ];
+ char *buf;
+ int max, cur, len, gotsome;
+
+ buf = NULL;
+ max = cur = gotsome = 0;
+ while ( fgets( line, sizeof(line), fp ) != NULL ) {
+ if ( lineno != NULL ) {
+ (*lineno)++;
+ }
+ /* ldif entries are terminated by a \n on a line by itself */
+ if ( line[0] == '\0' || line[0] == '\n'
+#if !defined( XP_WIN32 )
+ || ( line[0] == '\r' && line[1] == '\n' ) /* DOS format */
+#endif
+ ) {
+ if ( gotsome ) {
+ break;
+ } else {
+ continue;
+ }
+ } else if ( line[0] == '#' ) {
+ continue;
+ }
+ gotsome = 1;
+ len = strlen( line );
+#if !defined( XP_WIN32 )
+ /* DOS format */
+ if ( len > 0 && line[len-1] == '\r' ) {
+ --len;
+ line[len] = '\0';
+ } else if ( len > 1 && line[len-2] == '\r' && line[len-1] == '\n' ) {
+ --len;
+ line[len-1] = line[len];
+ line[len] = '\0';
+ }
+#endif
+ while ( cur + (len + 1) > max ) {
+ if ( buf == NULL ) {
+ max += BUFSIZ;
+ buf = (char *) malloc( max );
+ } else {
+ max *= 2;
+ buf = (char *) realloc( buf, max );
+ }
+ if ( buf == NULL ) {
+ return( NULL );
+ }
+ }
+
+ memcpy( buf + cur, line, len + 1 );
+ cur += len;
+ }
+
+ return( buf );
+}
+
+
+
+static int
+ldif_fromfile( char *path, struct berval *bv )
+{
+ FILE *fp;
+ long rlen;
+ int eof;
+#if defined( XP_WIN32 )
+ char mode[20] = "r+b";
+#else
+ char mode[20] = "r";
+#endif
+
+ if (( fp = fopen( path, mode )) == NULL ) {
+ perror( path );
+ return( -1 );
+ }
+
+ if ( fseek( fp, 0L, SEEK_END ) != 0 ) {
+ perror( path );
+ fclose( fp );
+ return( -1 );
+ }
+
+ bv->bv_len = ftell( fp );
+
+ if (( bv->bv_val = (char *)malloc( bv->bv_len + 1 )) == NULL ) {
+ perror( "malloc" );
+ fclose( fp );
+ return( -1 );
+ }
+
+ if ( fseek( fp, 0L, SEEK_SET ) != 0 ) {
+ perror( path );
+ fclose( fp );
+ return( -1 );
+ }
+
+ rlen = fread( bv->bv_val, 1, bv->bv_len, fp );
+ eof = feof( fp );
+ fclose( fp );
+
+ if ( rlen != (long)bv->bv_len ) {
+ perror( path );
+ free( bv->bv_val );
+ return( -1 );
+ }
+
+ bv->bv_val[ bv->bv_len ] = '\0';
+ return( bv->bv_len );
+}
+
+
diff --git a/ldap/libraries/liblitekey/Makefile b/ldap/libraries/liblitekey/Makefile
new file mode 100644
index 00000000..27e6d942
--- /dev/null
+++ b/ldap/libraries/liblitekey/Makefile
@@ -0,0 +1,50 @@
+#
+# 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 liblitekey
+#
+
+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 = $(OBJDIR)/lib/liblitekey
+LIBDIR = $(LDAP_LIBDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+CFLAGS += $(SLCFLAGS)
+
+LIBLITEKEY_OBJS= keycheck.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(LIBLITEKEY_OBJS))
+
+LIBLITEKEY = $(addprefix $(LIBDIR)/, liblitekey.$(LIB_SUFFIX))
+
+all: $(OBJDEST) $(LIBDIR) $(OBJS) $(LIBLITEKEY)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
+
+$(LIBLITEKEY): $(OBJS)
+ $(LINK_LIB)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ $(RM) $(LIBLITEKEY)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
diff --git a/ldap/libraries/liblitekey/keycheck.c b/ldap/libraries/liblitekey/keycheck.c
new file mode 100644
index 00000000..4f3ee505
--- /dev/null
+++ b/ldap/libraries/liblitekey/keycheck.c
@@ -0,0 +1,137 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * keycheck.c
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <litekey.h>
+
+#define DS_NORMAL_MAGIC_KEY 119
+#define DS_LITE_MAGIC_KEY 326
+#define FILE_PATHSEP '/'
+#define BUFSIZE 800
+
+/*
+ * is_directory_lite
+ *
+ * Checks if the directory server installation is a normal or a
+ * lite. The decision is made based on the key in the key file.
+ *
+ * Input:
+ * char *root; Pathname to install root
+ * Returns:
+ * 1 - yes, it's LITE server
+ * 0 - No; it's fully paid (normal) server.
+ *
+ */
+int is_directory_lite( char *root)
+{
+
+ char buf[40];
+ char *bufp = buf;
+ FILE *fp = NULL;
+ int key =0;
+ char *nsroot;
+ char pathname[BUFSIZE];
+
+ return DS_NORMAL_TYPE; /* richm: no more lite mode in DS 5.0 */
+#if 0 /* no more lite mode */
+ /* There are 3 ways to determine if the server is FULL or LITE.
+ * 1) Use NETSITE_ROOT variable
+ * 2) Use the root path provided
+ * 3) Look at the current directory
+ *
+ * If all of them fails, then it's LITE.
+ */
+ nsroot = getenv("NETSITE_ROOT");
+
+ if ( (NULL == root) && (NULL == nsroot)) {
+ /* case 3 */
+ sprintf ( pathname, "slapd.key" );
+ } else if (NULL == nsroot) {
+ /* case 2 */
+ sprintf ( pathname, "%s%cbin%cslapd%cserver%cslapd.key",
+ root, FILE_PATHSEP,FILE_PATHSEP,
+ FILE_PATHSEP, FILE_PATHSEP);
+ } else {
+ /* case 1 */
+ sprintf ( pathname, "%s%cbin%cslapd%cserver%cslapd.key",
+ nsroot, FILE_PATHSEP,FILE_PATHSEP,
+ FILE_PATHSEP, FILE_PATHSEP);
+ }
+
+
+ /* First read from the key file */
+ if ((fp = fopen ( pathname, "r")) == NULL )
+ return DS_LITE_TYPE;
+
+ if ( fgets(buf, 40, fp) == NULL)
+ return DS_LITE_TYPE;
+
+ fclose (fp );
+
+ /* The key is in the format: "key:123456" */
+ bufp +=4;
+ key = atoi ( (const char *) bufp );
+
+ /* Now we have the key. Determine which one it is */
+ if ( 0 == (key % DS_NORMAL_MAGIC_KEY))
+ return DS_NORMAL_TYPE;
+ else if ( 0 == (key % DS_LITE_MAGIC_KEY) )
+ return DS_LITE_TYPE;
+
+ /* By defualt, it's lite */
+ return DS_LITE_TYPE;
+#endif /* no more lite mode */
+}
+
+/*
+ * generate_lite_key
+ * Generate a key for the product that is being used.
+ *
+ * Input:
+ * type DS_NORMAL_TYPE - Normal
+ * DS_LITE_TYPE - Lite
+ * Returns:
+ * a int key.
+ *
+ */
+int generate_directory_key( int type)
+{
+
+ int key = 0;
+ int val;
+
+ val = rand();
+
+ if (type == DS_NORMAL_TYPE )
+ key = val * DS_NORMAL_MAGIC_KEY;
+ else if (type == DS_LITE_TYPE )
+ key = val * DS_LITE_MAGIC_KEY;
+
+ return key;
+}
+
+/*
+ * is_key_validNormalKey
+ *
+ * Check if the key ia a valid normal key or not.
+ */
+int
+is_key_validNormalKey ( int key )
+{
+
+ if (key <= 0 ) return 0;
+
+ if (0 == ( key % DS_NORMAL_MAGIC_KEY ))
+ return 1;
+
+ return 0;
+}
diff --git a/ldap/libraries/libutil/Makefile b/ldap/libraries/libutil/Makefile
new file mode 100644
index 00000000..6920ec86
--- /dev/null
+++ b/ldap/libraries/libutil/Makefile
@@ -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
+#
+#
+# GNU Makefile for libutil
+#
+
+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 = $(OBJDIR)/lib/libutil
+LIBDIR = $(LDAP_LIBDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+#
+# ntdebug.c currently not used
+#
+LIBUTIL_OBJS= getopt.o ntevent.o \
+ ntreg.o ntstubs.o
+
+ifeq ($(ARCH), WINNT)
+LIBUTIL_OBJS += crypt.o
+endif
+
+OBJS = $(addprefix $(OBJDEST)/, $(LIBUTIL_OBJS))
+
+LIBUTIL= $(addprefix $(LIBDIR)/, libutil.$(LIB_SUFFIX))
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd -I$(OBJDIR)/include
+
+SLAPDMESSAGES_H=$(MCOM_ROOT)/ldapserver/ldap/include/ntslapdmessages.h
+
+ifeq ($(LDAP_NO_LIBLCACHE),1)
+CFLAGS+=-DNO_LIBLCACHE
+endif
+
+clientSDK: all
+
+all: $(OBJDEST) $(SLAPDMESSAGES_H) $(LIBDIR) $(OBJS) $(LIBUTIL)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
+
+$(LIBUTIL): $(OBJS)
+ $(LINK_LIB)
+
+$(SLAPDMESSAGES_H):
+ @echo target: $@
+ cd $(MCOM_ROOT)/ldapserver/ldap/servers/slapd/ntmsgdll; $(MAKE) $(MFLAGS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ $(RM) $(LIBUTIL)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
diff --git a/ldap/libraries/libutil/getopt.c b/ldap/libraries/libutil/getopt.c
new file mode 100644
index 00000000..612d78fe
--- /dev/null
+++ b/ldap/libraries/libutil/getopt.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 1987 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that: (1) source distributions retain this entire copyright
+ * notice and comment, and (2) distributions including binaries display
+ * the following acknowledgement: ``This product includes software
+ * developed by the University of California, Berkeley and its contributors''
+ * in the documentation or other materials provided with the distribution
+ * and in all advertising materials mentioning features or use of this
+ * software. Neither the name of the University nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifdef _WINDOWS
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)getopt.c 4.12 (Berkeley) 6/1/90";
+#endif /* LIBC_SCCS and not lint */
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include "lber.h"
+#define index strchr
+#define rindex strrchr
+
+/*
+ * get option letter from argument vector
+ */
+int opterr = 1, /* if error message should be printed */
+ optind = 1, /* index into parent argv vector */
+ optopt; /* character checked for validity */
+char *optarg; /* argument associated with option */
+
+#define BADCH (int)'?'
+#define EMSG ""
+
+int getopt(int nargc, char *const *nargv, const char *ostr)
+{
+ static char *place = EMSG; /* option letter processing */
+ register char *oli; /* option letter list index */
+ char *p;
+
+ if (!*place) { /* update scanning pointer */
+ if (optind >= nargc || *(place = nargv[optind]) != '-') {
+ place = EMSG;
+ return(EOF);
+ }
+ if (place[1] && *++place == '-') { /* found "--" */
+ ++optind;
+ place = EMSG;
+ return(EOF);
+ }
+ } /* option letter okay? */
+ if ((optopt = (int)*place++) == (int)':' ||
+ !(oli = index(ostr, optopt))) {
+ /*
+ * if the user didn't specify '-' as an option,
+ * assume it means EOF.
+ */
+ if (optopt == (int)'-')
+ return(EOF);
+ if (!*place)
+ ++optind;
+ if (opterr) {
+ if (!(p = rindex(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ (void)fprintf(stderr, "%s: illegal option -- %c\n",
+ p, optopt);
+ }
+ return(BADCH);
+ }
+ if (*++oli != ':') { /* don't need argument */
+ optarg = NULL;
+ if (!*place)
+ ++optind;
+ }
+ else { /* need an argument */
+ if (*place) /* no white space */
+ optarg = place;
+ else if (nargc <= ++optind) { /* no arg */
+ place = EMSG;
+ if (!(p = rindex(*nargv, '/')))
+ p = *nargv;
+ else
+ ++p;
+ if (opterr)
+ (void)fprintf(stderr,
+ "%s: option requires an argument -- %c\n",
+ p, optopt);
+ return(BADCH);
+ }
+ else /* white space */
+ optarg = nargv[optind];
+ place = EMSG;
+ ++optind;
+ }
+ return(optopt); /* dump back option letter */
+}
+
+#endif
diff --git a/ldap/libraries/libutil/ntdebug.c b/ldap/libraries/libutil/ntdebug.c
new file mode 100644
index 00000000..d0347e2d
--- /dev/null
+++ b/ldap/libraries/libutil/ntdebug.c
@@ -0,0 +1,51 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/******************************************************
+ *
+ * ntdebug.c - Sends debug output to window and stdout
+ * on Win32 platforms.
+ *
+ ******************************************************/
+
+#if defined( _WIN32 )
+#include <windows.h>
+#include <time.h>
+#include <stdio.h>
+#if defined( SLAPD_LOGGING )
+#include "slap.h"
+#include "proto-slap.h"
+#else
+#include "ldap.h"
+#include "ldaplog.h"
+#endif
+int slapd_ldap_debug = LDAP_DEBUG_ANY;
+FILE *error_logfp = NULL;
+
+void LDAPDebug( int level, char *fmt, ... )
+{
+ va_list arg_ptr;
+ va_start( arg_ptr, fmt );
+ if ( slapd_ldap_debug & level )
+ {
+ char szFormattedString[512];
+ _vsnprintf( szFormattedString, sizeof( szFormattedString ), fmt, arg_ptr );
+
+#if defined( LDAP_DEBUG )
+ /* Send to debug window ...*/
+ OutputDebugString( szFormattedString );
+
+ /* ... and to stderr */
+ fprintf( stderr, szFormattedString );
+#endif
+#if defined( SLAPD_LOGGING )
+ if ( error_logfp != NULL )
+ slapd_log_error( error_logfp, szFormattedString );
+#endif
+ }
+ va_end( arg_ptr );
+
+}
+#endif
diff --git a/ldap/libraries/libutil/ntevent.c b/ldap/libraries/libutil/ntevent.c
new file mode 100644
index 00000000..2b05dd9d
--- /dev/null
+++ b/ldap/libraries/libutil/ntevent.c
@@ -0,0 +1,183 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include <stdio.h>
+#include "ldap.h"
+#include "regparms.h"
+
+HANDLE hSlapdEventSource;
+LPTSTR pszServerName;
+
+void ReportSlapdEvent(WORD wEventType, DWORD dwIdEvent, WORD wNumInsertStrings,
+ char *pszStrings)
+{
+ LPCTSTR lpszStrings[64];
+ BOOL bSuccess;
+
+ if( hSlapdEventSource )
+ {
+ if( pszServerName )
+ lpszStrings[0] = (LPCTSTR)pszServerName;
+
+ if( pszStrings != NULL)
+ lpszStrings[1] = (LPCTSTR)pszStrings;
+
+ wNumInsertStrings++;
+
+ /* Now report the event, which will add this event to the event log */
+ bSuccess = ReportEvent(hSlapdEventSource, /* event-log handle */
+ wEventType, /* event type */
+ 0, /* category zero */
+ dwIdEvent, /* event ID */
+ NULL, /* no user SID */
+ wNumInsertStrings, /* number of substr */
+ 0, /* no binary data */
+ lpszStrings, /* string array */
+ NULL); /* address of data */
+ }
+
+} /* ReportSlapdEvent */
+
+BOOL ReportSlapdStatusToSCMgr(
+ SERVICE_STATUS *serviceStatus,
+ SERVICE_STATUS_HANDLE serviceStatusHandle,
+ HANDLE Event,
+ DWORD dwCurrentState,
+ DWORD dwWin32ExitCode,
+ DWORD dwCheckPoint,
+ DWORD dwWaitHint)
+{
+ /* Disable control requests until the service is started. */
+ if (dwCurrentState == SERVICE_START_PENDING)
+ serviceStatus->dwControlsAccepted = 0;
+ else
+ serviceStatus->dwControlsAccepted = SERVICE_ACCEPT_STOP |
+ SERVICE_ACCEPT_PAUSE_CONTINUE;
+
+ serviceStatus->dwCurrentState = dwCurrentState;
+ serviceStatus->dwWin32ExitCode = dwWin32ExitCode;
+ serviceStatus->dwCheckPoint = dwCheckPoint;
+
+ serviceStatus->dwWaitHint = dwWaitHint;
+
+ /* Report the status of the service to the service control manager. */
+ return SetServiceStatus( serviceStatusHandle, serviceStatus);
+
+} /* ReportSlapdStatusToSCMgr */
+
+// This is a routine that we use to check for multiple instances of a server with
+// the same id. We cannot use a shared data section to keep count of instances since
+// there will be multiple instances of the server running. MS recommends using a
+// sync object to do this. Thus we attempt to create an object with same NAME
+// but different TYPE as the server "Done" event.We have a small race condition
+// between the check and the creation of the "Done" event.
+
+BOOL
+MultipleInstances()
+{
+ HANDLE hServDoneSemaphore;
+ DWORD result;
+ CHAR ErrMsg[1024];
+ char szDoneEvent[256];
+
+ if( !pszServerName )
+ return FALSE;
+
+ sprintf(szDoneEvent, "NS_%s", pszServerName);
+
+ hServDoneSemaphore = CreateSemaphore(
+ NULL, // security attributes
+ 0, // initial count for semaphore
+ 1, // maximum count for semaphore
+ szDoneEvent);
+
+ if ( hServDoneSemaphore == NULL) {
+
+ result = GetLastError();
+ if (result == ERROR_INVALID_HANDLE) {
+
+ sprintf(ErrMsg, "Netscape Server %s is already"
+ " running. Terminating this instance.", pszServerName);
+
+ MessageBox(GetDesktopWindow(), ErrMsg,
+ "SERVER ALREADY RUNNING", MB_ICONEXCLAMATION | MB_OK);
+ return TRUE;
+
+ } else {
+ /* We aren't too interested in why the creation failed
+ * if it is not because of another instance */
+
+ return FALSE;
+ }
+ } // hServDoneSemaphore == NULL
+
+ CloseHandle(hServDoneSemaphore);
+ return FALSE;
+}
+
+BOOL SlapdIsAService()
+{
+ // May change in V2.0
+ return FALSE;
+}
+
+BOOL SlapdGetServerNameFromCmdline(char *szServerName, char *szCmdLine, int dirname)
+{
+ BOOL bReturn = FALSE;
+ char *szChar = NULL;
+ char szCmdCopy[_MAX_PATH];
+
+ if( szCmdLine )
+ {
+ memset(szCmdCopy, 0, _MAX_PATH );
+ strcpy( szCmdCopy, szCmdLine );
+ }
+ else
+ return(bReturn);
+
+ // szCmdCopy should be something like
+ // c:\navgold\server\slapd-kennedy\config\slapd.conf
+ // unless dirname is TRUE in which case it should be
+ // c:\navgold\server\slapd-kennedy
+ if(szChar = strrchr(szCmdCopy, '\\'))
+ {
+ *szChar = 0;
+ if(dirname)
+ {
+ strcpy(szServerName, szChar+1);
+ bReturn = TRUE;
+ }
+ else if(szChar = strrchr(szCmdCopy, '\\'))
+ {
+ // szCmdCopy should be c:\navgold\server\slapd-kennedy\config
+ *szChar = 0;
+ // szCmdCopy should be c:\navgold\server\slapd-kennedy
+ if(szChar = strrchr(szCmdCopy, '\\'))
+ {
+ szChar++;
+ // szChar should point to slapd-kennedy
+ strcpy(szServerName, szChar);
+ bReturn = TRUE;
+ }
+ }
+ }
+ else
+ {
+ // szCmdCopy should be something like slapd-kennedy
+ strcpy(szServerName, szCmdCopy);
+ bReturn = TRUE;
+ }
+
+ if(strlen(szServerName) == 0)
+ bReturn = FALSE;
+
+ return(bReturn);
+}
+
+#endif _WIN32
diff --git a/ldap/libraries/libutil/ntreg.c b/ldap/libraries/libutil/ntreg.c
new file mode 100644
index 00000000..53313075
--- /dev/null
+++ b/ldap/libraries/libutil/ntreg.c
@@ -0,0 +1,105 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifdef _WIN32
+
+#include <windows.h>
+#include <stdio.h>
+#include "ldap.h"
+
+int SlapdGetRegSZ( LPTSTR lpszRegKey, LPSTR lpszValueName, LPTSTR lpszValue )
+{
+ HKEY hKey;
+ DWORD dwType, dwNumBytes;
+ LONG lResult;
+
+ /* Open the registry, get the required key handle. */
+ lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, lpszRegKey,
+ 0L, KEY_QUERY_VALUE, &hKey );
+ if (lResult == ERROR_SUCCESS)
+ {
+ dwNumBytes = sizeof( DWORD );
+ lResult = RegQueryValueEx( hKey, lpszValueName, 0,
+ &dwType, NULL, &dwNumBytes );
+ if( lResult == ERROR_SUCCESS )
+ {
+ RegQueryValueEx( hKey, lpszValueName, 0, &dwType,
+ (LPBYTE)lpszValue, &dwNumBytes );
+ *(lpszValue+dwNumBytes) = 0;
+
+ /* Close the Registry. */
+ RegCloseKey(hKey);
+ return 0;
+ }
+ else
+ {
+ /* No config file location stored in the Registry. */
+ RegCloseKey(hKey);
+ return 1;
+ }
+ }
+ else
+ {
+ return 1;
+ }
+} /* SlapdGetRegSZ */
+
+
+int SlapdSetRegSZ( LPTSTR lpszKey, LPSTR lpszValueName, LPTSTR lpszValue )
+{
+ HKEY hKey;
+ LONG lResult;
+
+ /* Open the registry, get a handle to the desired key. */
+ lResult = RegOpenKeyEx( HKEY_LOCAL_MACHINE, lpszKey, 0,
+ KEY_ALL_ACCESS, &hKey );
+ if (lResult == ERROR_SUCCESS)
+ {
+ /* Set the value to the value-name at the key location. */
+ RegSetValueEx( hKey, lpszValueName, 0, REG_SZ,
+ (CONST BYTE*)lpszValue, strlen(lpszValue) );
+
+ /* Close the registry */
+ RegCloseKey(hKey);
+ return 0;
+ }
+ else
+ {
+ return 1;
+ }
+} /* SlapdSetRegSZ */
+
+/* converts '/' chars to '\' */
+void
+unixtodospath(char *szText)
+{
+ if(szText)
+ {
+ while(*szText)
+ {
+ if( *szText == '/' )
+ *szText = '\\';
+ szText++;
+ }
+ }
+}
+
+/* converts '\' chars to '/' */
+void
+dostounixpath(char *szText)
+{
+ if(szText)
+ {
+ while(*szText)
+ {
+ if( *szText == '\\' )
+ *szText = '/';
+ szText++;
+ }
+ }
+}
+
+#endif /* _WIN32 */
diff --git a/ldap/libraries/libutil/ntresource.h b/ldap/libraries/libutil/ntresource.h
new file mode 100644
index 00000000..c2e375c5
--- /dev/null
+++ b/ldap/libraries/libutil/ntresource.h
@@ -0,0 +1,31 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+//{{NO_DEPENDENCIES}}
+// Microsoft Developer Studio generated include file.
+// Used by ntslapd.rc
+//
+#define IDD_DATABASE_PASSWORD 101
+#define IDD_FORTEZZA_PIN 102
+#define IDI_KEY 103
+#define IDI_LOGO 105
+#define IDR_MENU 205
+#define IDEDIT 1000
+#define ID_SERVER_RESTART 40001
+#define ID_FILE_EXIT 40003
+#define ID_SERVER_SHUTDOWN 40004
+#define ID_SERVER_SUSPEND 40005
+#define ID_SERVER_RESUME 40006
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 106
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/ldap/libraries/libutil/ntstubs.c b/ldap/libraries/libutil/ntstubs.c
new file mode 100644
index 00000000..5d18ad38
--- /dev/null
+++ b/ldap/libraries/libutil/ntstubs.c
@@ -0,0 +1,40 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/******************************************************
+ *
+ * ntstubs.c - Stubs needed on NT when linking in
+ * the SSL code. If these stubs were not here, the
+ * named functions below would not be located at link
+ * time, because there is no implementation of the
+ * functions for Win32 in cross-platform libraries.
+ *
+ ******************************************************/
+
+#if defined( _WIN32 ) && defined ( NET_SSL )
+
+#include <windows.h>
+#include <nspr.h>
+
+/*
+char* XP_FileName (const char* name, XP_FileType type)
+{
+ return NULL;
+}
+
+XP_File XP_FileOpen(const char* name, XP_FileType type,
+ const XP_FilePerm permissions)
+{
+ return NULL;
+}
+*/
+
+char *
+WH_FileName (const char *name, PRFileType type)
+{
+ return NULL;
+}
+#endif /* WIN32 && NET_SSL */
+
diff --git a/ldap/nsdeps.mk b/ldap/nsdeps.mk
new file mode 100644
index 00000000..3a5f792f
--- /dev/null
+++ b/ldap/nsdeps.mk
@@ -0,0 +1,59 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# build dependency lists if necessary, then make 'build.mk'
+#
+# only build dependency lists on platforms that it works on...
+#
+
+
+ifeq ($(ARCH), WINNT)
+# windows can't make dot-files:
+DEPFILE = ./deps
+$(OBJDIR)/mkdep: $(LDAP_SRC)/servers/slapd/tools/mkdep.c
+ $(CC) /Ox /DWINNT /Fe$(OBJDIR)/mkdep.exe \
+ $(LDAP_SRC)/servers/slapd/tools/mkdep.c
+else
+DEPFILE = ./.deps
+$(OBJDIR)/mkdep: $(LDAP_SRC)/servers/slapd/tools/mkdep.c
+ $(CC) -o $(OBJDIR)/mkdep $(LDAP_SRC)/servers/slapd/tools/mkdep.c
+endif
+
+ifeq ($(RECURSIVE_DEP), yes)
+$(DEPFILE): *.h *.c
+ @echo Cant seem to create $(DEPFILE), time to die.
+ @exit 1
+else
+$(DEPFILE): *.h *.c
+ @echo Rebuilding dependency lists...
+ $(OBJDIR)/mkdep -o $(OBJDEST) *.h *.c >$(DEPFILE)
+ $(MAKE) RECURSIVE_DEP=yes
+endif
+
+#
+# you can override these from the command line
+#
+ifeq ($(ARCH), SOLARIS)
+USE_DEPS = no
+endif
+ifeq ($(ARCH), Linux)
+USE_DEPS = no
+endif
+ifeq ($(ARCH), WINNT)
+USE_DEPS = no
+endif
+
+
+# automatic dependency checking?
+ifeq ($(USE_DEPS), yes)
+ ifeq ($(RECURSIVE_DEP), yes)
+ include $(DEPFILE)
+ else
+ BUILD_DEP = $(OBJDIR)/mkdep $(DEPFILE)
+ endif
+endif
diff --git a/ldap/nsldap.mk b/ldap/nsldap.mk
new file mode 100644
index 00000000..220aca5b
--- /dev/null
+++ b/ldap/nsldap.mk
@@ -0,0 +1,1752 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# nsldap.mk: GNU Makefile for common defs used in Netscape Directory Server
+# and related tools.
+#
+
+#
+# Set the global directory points
+#
+
+# This stuff is for UNIX--we wire in absolute paths
+# because it makes the tar'ing easier.
+# On NT we don't bother with this trick.
+# Note that we're setting MCOM_ROOT again,
+# having set it to a relative path above, so
+# we can find the include files.
+ifneq ($(ARCH), WINNT)
+# This seems useless to check for a path of the form word:word if the arch
+# is neq winnt . . .
+MCOM_TMP = $(subst :, , $(shell cd ../../..;pwd))
+MCOM_WORDS = $(words $(MCOM_TMP))
+# convert MCOM_ROOT from relative path to absolute
+#MCOM_ROOT = $(word $(MCOM_WORDS), $(MCOM_TMP))
+ifneq ($(MCOM_WORDS), 1)
+MCOM_DRIVE = $(word 1, $(MCOM_TMP)):
+endif
+endif
+
+RELTOP=$(MCOM_ROOT)/ldapserver/built/release
+OBJDIR_BASE = $(notdir $(OBJDIR))
+OBJDIR_BASE_32 = $(notdir $(OBJDIR_32))
+# Release directory for Directory Server
+RELDIR = $(MCOM_DRIVE)$(RELTOP)/$(DIR)/$(OBJDIR_BASE)
+RELDIR_32 = $(MCOM_DRIVE)$(RELTOP)/$(DIR)/$(OBJDIR_BASE_32)
+RELDIR_UNSTRIP = $(MCOM_DRIVE)$(RELTOP)/$(DIR)/$(ARCHPROCESSOR)$(NS64TAG)-$(SECURITY)$(SSL_PREFIX)-$(DEBUG)$(RTSUFFIX)-unstripped-$(BUILD_FORTEZZA)$(BUILD_PTHREADS)-$(DIR)
+
+# this is the place libraries and plugins go which are used by other
+# components i.e. not specific to slapd and its programs
+LIB_RELDIR = $(RELDIR)/lib
+# Release path definitions for software components
+# This is the base path for directory server specific components
+LDAP_BASE_RELDIR = $(RELDIR)/bin/slapd
+# This is the base path for the slapd program and other related programs
+LDAP_SERVER_RELDIR = $(LDAP_BASE_RELDIR)/server
+# This is the path for administrative programs, installers, CGIs, etc.
+LDAP_ADMIN_BIN_RELDIR = $(LDAP_BASE_RELDIR)/admin/bin
+# This is the path for other programs, perf counters, etc.
+LDAP_INSTALL_BIN_RELDIR = $(LDAP_BASE_RELDIR)/install/bin
+# This is the base path for directory server specific dlls
+LDAP_LIB_RELDIR = $(LDAP_BASE_RELDIR)/lib
+# This is the primary location for the dsadmin dll
+LDAP_ADMDLLDIR = $(LDAP_LIB_RELDIR)
+# This is the location for the dsadmin export and/or static library,
+# for those platforms which separate them from the dll (like NT :-( )
+ifeq ($(ARCH), WINNT)
+LDAP_ADMLIBDIR = $(LDAP_ADMROOT)/lib
+# This is a list of other files (for NT) the dsadmin dll needs to be
+# copied to
+LDAP_ADMDLL_RELDLLS = $(LDAP_ADMIN_BIN_RELDIR)/libds_admin$(DLL_PRESUF).$(DLL_SUFFIX) $(LDAP_SERVER_RELDIR)/libds_admin$(DLL_PRESUF).$(DLL_SUFFIX)
+LDAP_ADMDLL_RELDIRS = $(LDAP_ADMIN_BIN_RELDIR) $(LDAP_SERVER_RELDIR)
+else # same place as dll
+LDAP_ADMLIBDIR = $(LDAP_ADMDLLDIR)
+endif
+
+LDAP_SRC = $(MCOM_ROOT)/ldapserver/ldap
+
+LDAP_INSTROOT= $(OBJDIR)
+
+LDAP_LIBDIR = $(LDAP_INSTROOT)/lib
+LDAP_OBJDIR = $(LDAP_INSTROOT)/servers/obj
+LDAP_MANDIR = $(LDAP_INSTROOT)/man
+LDAP_BINDIR = $(LDAP_INSTROOT)/bin
+LDAP_INCLUDEDIR = $(LDAP_INSTROOT)/include
+LDAP_ETCDIR = $(LDAP_INSTROOT)/etc
+
+LDAP_ADMROOT = $(LDAP_INSTROOT)/dsadmin
+LDAP_ADMINCDIR = $(LDAP_ADMROOT)/include
+LDAP_ADMOBJDIR = $(LDAP_ADMROOT)/obj
+LDAP_ADMPERLDIR = $(LDAP_ADMROOT)/perl
+
+LDAP_HDIR = $(LDAP_SRC)/include
+
+# set up a target for all directories which are used as dependencies so that the
+# directory will be created if it is needed
+DEPENDENCY_DIRS = $(RELDIR) $(LDAP_SERVER_RELDIR) $(LDAP_ADMIN_BIN_RELDIR) \
+ $(LDAP_LIB_RELDIR) $(LDAP_ADMROOT)/lib $(OBJDIR) $(LDAP_LIBDIR) $(LDAP_OBJDIR) \
+ $(LDAP_MANDIR) $(LDAP_BINDIR) $(LDAP_INCLUDEDIR) $(LDAP_ETCDIR) $(LIB_RELDIR) \
+ $(LDAP_ADMINCDIR) $(LDAP_ADMOBJDIR) $(LDAP_ADMPERLDIR) $(LDAP_INSTALL_BIN_RELDIR)
+
+$(DEPENDENCY_DIRS):
+ $(MKDIR) $@
+
+# On AIX, include _shr in shared library names (Netscape convention). This
+# is done because the suffix .a is used with both static and dynamic libs
+# and we need some way to distinguish the two. You gotta love AIX....
+ifeq ($(ARCH), AIX)
+ifdef OLD_AIX_LINKING
+DLL_PRESUFFIX=_shr
+endif
+else
+DLL_PRESUFFIX=
+endif
+
+# warnings as errors
+# FIXME
+#ifeq ($(ARCH), Linux)
+#CFLAGS += -Werror
+#endif
+#ifeq ($(ARCH), SOLARIS)
+#CFLAGS += -xwe
+#endif
+
+# turn on convidl: new idl upgrade tool
+CFLAGS+=-DUPGRADEDB
+
+#
+# Dynamic library for LDAP Server Admin interface
+#
+ifeq ($(ARCH), WINNT)
+LDAP_ADMLIB_DEP = $(LDAP_ADMDLLDIR)/libds_admin$(DLL_PRESUF).$(DLL_SUFFIX) $(LDAP_ADMLIBDIR)/libds_admin.$(LIB_SUFFIX)
+LDAP_ADMLIB = $(LDAP_ADMLIBDIR)/libds_admin.$(LIB_SUFFIX)
+else
+LDAP_ADMLIB_DEP = $(LDAP_ADMLIBDIR)/libds_admin$(DLL_PRESUF).$(DLL_SUFFIX)
+ifeq ($(ARCH), UnixWare)
+#add (COMMON_OBJDIR) to (LDAP_ADMLIB) so $(LD) can find ns-dshttpd.so
+LDAP_ADMLIB = -L$(COMMON_OBJDIR) -lds_admin$(DLL_PRESUF)
+else
+LDAP_ADMLIB = -L$(LDAP_ADMDLLDIR) -lds_admin$(DLL_PRESUF)
+endif # UnixWare
+endif # WINNT
+
+#
+# Common LDAP static libraries.
+#
+ifdef LDAP_USE_OLD_DB
+ldap_extra_db_lib:=libldbm libdb
+ldap_extra_db_link:=-lldbm -ldb
+else
+ldap_extra_db_lib:=
+ldap_extra_db_link:=
+endif # LDAP_USE_OLD_DB
+LDAP_COMMON_LIBSLIST = libavl $(ldap_extra_db_lib) libldif liblitekey
+ifeq ($(ARCH), WINNT)
+LDAP_COMMON_LIBSLIST += libutil
+else
+LDAP_COMMON_LIBSLIST += libldif
+endif # WINNT
+
+LDAP_COMMON_LIBS_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LDAP_COMMON_LIBSLIST)))
+ifeq ($(ARCH), WINNT)
+LDAP_COMMON_LIBS = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LDAP_COMMON_LIBSLIST)))
+LDAP_COMMON_LINK = /LIBPATH:$(LDAP_LIBDIR) \
+ $(addsuffix .$(LIB_SUFFIX), $(LDAP_COMMON_LIBSLIST))
+else
+LDAP_COMMON_LIBS = -lavl $(ldap_extra_db_link) -lldif
+LDAP_COMMON_LINK = $(LDAP_COMMON_LIBS)
+endif
+
+#
+# Individual LDAP libraries and dependancies
+#
+
+LDAP_LIBAVL_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libavl))
+ifeq ($(ARCH), WINNT)
+LDAP_LIBAVL = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libavl))
+else
+LDAP_LIBAVL = -lavl
+endif
+
+ifdef LDAP_USE_OLD_DB
+LDAP_LIBLDBM_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libldbm))
+ifeq ($(ARCH), WINNT)
+LDAP_LIBLDBM = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libldbm))
+else
+LDAP_LIBLDBM = -lldbm
+endif
+else
+LDAP_LIBLDBM_DEP:=
+LDAP_LIBLDBM:=
+endif
+
+# dboreham: changed for new db regime
+ifdef LDAP_USE_OLD_DB
+LDAP_LIBDB_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libdb))
+ifeq ($(ARCH), WINNT)
+LDAP_LIBDB = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libdb))
+else
+LDAP_LIBDB = -ldb
+endif
+else
+LDAP_LIBDB_DEP:=
+LDAP_LIBDB:=DONT USE THIS ANYMORE
+endif
+
+LDAP_LIBLBER_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, liblber))
+ifeq ($(ARCH), WINNT)
+LDAP_LIBLBER = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, liblber))
+else
+LDAP_LIBLBER = -llber
+endif
+
+LDAP_LIBUTIL_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libutil))
+ifeq ($(ARCH), WINNT)
+LDAP_LIBUTIL = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libutil))
+else
+LDAP_LIBUTIL = -lutil
+endif
+
+LDAP_LIBLDIF_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libldif))
+ifeq ($(ARCH), WINNT)
+LDAP_LIBLDIF = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libldif))
+else
+LDAP_LIBLDIF = -lldif
+endif
+
+LDAP_LIBLITEKEY_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, liblitekey))
+ifeq ($(ARCH), WINNT)
+LDAP_LIBLITEKEY = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, liblitekey))
+else
+LDAP_LIBLITEKEY = -llitekey
+endif
+
+ifneq ($(LDAP_NO_LIBLCACHE),1)
+LDAP_SLIBLCACHE_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LIBLCACHE_LIB)))
+ifeq ($(ARCH), WINNT)
+LDAP_SLIBLCACHE = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LIBLCACHE_LIB)))
+else
+# XXXmcs: on UNIX we actually use the DLL (?)
+LDAP_SLIBLCACHE = $(LDAP_SDK_LIBLCACHE_DLL)
+endif
+endif
+
+# dynamic libs that we ship will be put in <reldir>/lib and
+# static libs that we use to build other ds components will
+# be put in <builddir>/lib; this is mostly for NT and other
+# platforms that separate the static and dynamic code
+ifeq ($(ARCH), WINNT)
+LDAP_LIBBACK_LDBM_LIBDIR = $(LDAP_LIBDIR)
+LDAP_LIBBACK_LDBM_DLLDIR = $(LIB_RELDIR)
+LDAP_LIBBACK_LDBM = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LIBBACK_LDBM_LIB)))
+else
+LDAP_LIBBACK_LDBM = -lback-ldbm
+LDAP_LIBBACK_LDBM_LIBDIR = $(LDAP_LIBDIR)
+LDAP_LIBBACK_LDBM_DLLDIR = $(LIB_RELDIR)
+endif
+LDAP_LIBBACK_LDBM_DEP = $(addsuffix .$(DLL_SUFFIX), \
+ $(addprefix $(LDAP_LIBBACK_LDBM_LIBDIR)/, $(LIBBACK_LDBM_DLL)))
+
+#
+# Libldapu
+#
+LIBLDAPU_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libldapu))
+ifeq ($(ARCH), WINNT)
+LIBLDAPU = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libldapu))
+else
+LIBLDAPU = -lldapu
+endif
+
+#
+# Libadmin
+#
+LIBADMIN_DEP_OLD = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libadmin))
+ifeq ($(ARCH), WINNT)
+LIBADMIN_OLD = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libadmin))
+else
+LIBADMIN_OLD = -ladmin
+endif
+
+LIBADMIN=$(LIBADMIN_OLD)
+LIBADMIN_DEP=$(LIBADMIN_DEP_OLD)
+
+#
+# Shared library for slapd objects---this contains
+# everything prototyped in backendext.h, and
+# in slapd-proto.h The latter routines are not
+# for public consumption, but live in the library
+# used by 3rd party backends.
+# On NT, the libslapd dll is packaged in the same directory as the server
+# On Unix, the libslapd dll is packaged in the <server root>/lib directory
+ifeq ($(ARCH), WINNT)
+LIBSLAPD_DEP = $(addsuffix .$(DLL_SUFFIX), \
+ $(addprefix $(LDAP_SERVER_RELDIR)/, libslapd$(DLL_PRESUFFIX)))
+LIBSLAPD_DLL = $(addsuffix .$(DLL_SUFFIX), \
+ $(addprefix $(LDAP_SERVER_RELDIR)/, libslapd$(DLL_PRESUFFIX)))
+LIBSLAPD = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, libslapd))
+LIBSLAPDLINK = /LIBPATH:$(LDAP_LIBDIR) libslapd.$(LIB_SUFFIX)
+# This is a list of other files (for NT) the dsadmin dll needs to be
+# copied to
+LIBSLAPD_RELDLLS = $(LDAP_SERVER_RELDIR)/libslapd$(DLL_PRESUF).$(DLL_SUFFIX)
+LIBSLAPD_RELDIRS = $(LDAP_SERVER_RELDIR)
+else
+# libslapd is now in $(RELDIR)/bin/slapd/server
+LIBSLAPD_DEP = $(addsuffix .$(DLL_SUFFIX), \
+ $(addprefix $(LDAP_SERVER_RELDIR)/, libslapd$(DLL_PRESUFFIX)))
+LIBSLAPD_DLL = $(LIBSLAPD_DEP)
+LIBSLAPD = -L$(LDAP_SERVER_RELDIR) -lslapd$(DLL_PRESUFFIX)
+LIBSLAPDLINK = $(LIBSLAPD)
+endif
+
+#
+# XP
+#
+LIBXP_DEP = $(NSCP_DISTDIR)/lib/libxp.$(LIB_SUFFIX)
+ifeq ($(ARCH), WINNT)
+LIBXP = $(NSCP_DISTDIR)/lib/libxp.$(LIB_SUFFIX)
+else
+LIBXP = -lxp
+endif
+
+#
+# SSLIO
+#
+LIBSSLIO_DEP = $(NSCP_DISTDIR)/lib/libsslio.$(LIB_SUFFIX)
+ifeq ($(ARCH), WINNT)
+LIBSSLIO = $(NSCP_DISTDIR)/lib/libsslio.$(LIB_SUFFIX)
+else
+LIBSSLIO = -lsslio
+endif
+
+#
+# Libsec
+#
+LIBSEC_DEP = $(NSCP_DISTDIR)/lib/libsec-$(SECURITY_EXTN).$(LIB_SUFFIX)
+LIBSEC = $(NSCP_DISTDIR)/lib/libsec-$(SECURITY_EXTN).$(LIB_SUFFIX)
+ifdef FORTEZZA
+LIBSEC += $(FORTEZZA_DRIVER)
+endif
+
+#
+# Libdb
+#
+LIBDB_DEP = $(NSCP_DISTDIR)/lib/libdbm.$(LIB_SUFFIX)
+ifeq ($(ARCH), WINNT)
+LIBDB = $(NSCP_DISTDIR)/lib/libdbm.$(LIB_SUFFIX)
+else
+LIBDB = -ldbm
+endif
+
+#
+# ACL library, Libaccess
+#
+LIBACCESS_DEP = $(LDAP_LIBDIR)/libaccess.$(LIB_SUFFIX)
+ifeq ($(ARCH), WINNT)
+LIBACCESS = $(LDAP_LIBDIR)/libaccess.lib
+else
+LIBACCESS = -laccess
+endif
+
+#
+# Dynamic libraries and dependancies, LDAP SDK
+#
+ifeq ($(ARCH), WINNT)
+LIBLDAP_DLL = nsldap32v$(DIRSDK_VERSION_DLL_SUFFIX)
+LIBLDAP_LIB = nsldaps32v$(DIRSDK_VERSION_DLL_SUFFIX)
+LIBSSLDAP_LIB = nsldapssl32v$(DIRSDK_VERSION_DLL_SUFFIX)
+LIBLCACHE_DLL = nslch32v$(DIRSDK_VERSION_DLL_SUFFIX)
+LIBLCACHE_LIB = nslchs32v$(DIRSDK_VERSION_DLL_SUFFIX)
+else
+LIBLDAP_DLL = libldap$(DIRSDK_VERSION_DLL_SUFFIX)$(DLL_PRESUFFIX)
+LIBLCACHE_DLL = liblcache$(DIRSDK_VERSION_DLL_SUFFIX)$(DLL_PRESUFFIX)
+LIBLCACHE_LIB = liblcache$(DIRSDK_VERSION_DLL_SUFFIX)
+LIBLDAP_LIB = libldap$(DIRSDK_VERSION_DLL_SUFFIX)
+LIBSSLDAP_LIB = libssldap$(DIRSDK_VERSION_DLL_SUFFIX)
+endif
+
+ifdef PRODUCT_IS_DIRECTORY_SERVER
+# Get headers and libs from components directory
+ LDAP_SDK_LIBLDAP_DLL_DEP = $(addsuffix .$(DLL_SUFFIX), \
+ $(addprefix $(LDAP_LIBPATH)/, $(LIBLDAP_DLL)))
+
+ ifeq ($(ARCH), WINNT)
+ LDAP_SDK_LIBLDAP_DLL = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBPATH)/, $(LIBLDAP_DLL)))
+ else
+ LDAP_SDK_LIBLDAP_DLL = -lldap$(DIRSDK_VERSION_DLL_SUFFIX)$(DLL_PRESUFFIX)
+ endif
+
+ LDAP_SDK_LIBSSLDAP_LIB_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBPATH)/, $(LIBSSLDAP_LIB)))
+
+ LDAP_SDK_LIBSSLDAP_LIB = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBPATH)/, $(LIBSSLDAP_LIB)))
+
+ ifneq ($(LDAP_NO_LIBLCACHE),1)
+ LDAP_SDK_LIBLCACHE_DLL_DEP = $(addsuffix .$(DLL_SUFFIX), \
+ $(addprefix $(LDAP_LIBPATH)/, $(LIBLCACHE_DLL)))
+
+ ifeq ($(ARCH), WINNT)
+ LDAP_SDK_LIBLCACHE_DLL = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBPATH)/, $(LIBLCACHE_DLL)))
+ else
+ LDAP_SDK_LIBLCACHE_DLL = -llcache$(DIRSDK_VERSION_DLL_SUFFIX)$(DLL_PRESUFFIX)
+ endif
+ endif
+else
+# Client SDK
+ LDAP_SDK_LIBLDAP_DLL_DEP = $(addsuffix .$(DLL_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LIBLDAP_DLL)))
+
+ ifeq ($(ARCH), WINNT)
+ LDAP_SDK_LIBLDAP_DLL = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LIBLDAP_DLL)))
+ else
+ LDAP_SDK_LIBLDAP_DLL = -lldap$(DIRSDK_VERSION_DLL_SUFFIX)$(DLL_PRESUFFIX)
+ endif
+
+ LDAP_SDK_LIBSSLDAP_LIB_DEP = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LIBSSLDAP_LIB)))
+
+ LDAP_SDK_LIBSSLDAP_LIB = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LIBSSLDAP_LIB)))
+
+ ifneq ($(LDAP_NO_LIBLCACHE),1)
+ LDAP_SDK_LIBLCACHE_DLL_DEP = $(addsuffix .$(DLL_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LIBLCACHE_DLL)))
+
+ ifeq ($(ARCH), WINNT)
+ LDAP_SDK_LIBLCACHE_DLL = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LIBLCACHE_DLL)))
+ else
+ LDAP_SDK_LIBLCACHE_DLL = -llcache$(DIRSDK_VERSION_DLL_SUFFIX)$(DLL_PRESUFFIX)
+ endif
+ endif
+endif
+
+#dboreham: removed LIBLCACHE from the following lines---everybody was
+#linking with liblcache, which isn't right.
+LDAP_SDK_LIBS_DEP = $(LDAP_SDK_LIBSSLDAP_LIB_DEP) \
+ $(LDAP_SDK_LIBLDAP_DLL_DEP)
+
+LDAP_SDK_LIBS = $(LDAP_SDK_LIBSSLDAP_LIB) $(LDAP_SDK_LIBLDAP_DLL)
+
+#
+# Dynamic and static libraries, BACK-LDBM
+#
+ifeq ($(ARCH), WINNT)
+LIBBACK_LDBM_DLL = libback-ldbm
+LIBBACK_LDBM_LIB = libback-ldbms
+else
+LIBBACK_LDBM_DLL = libback-ldbm$(DLL_PRESUFFIX)
+LIBBACK_LDBM_LIB = libback-ldbm
+endif
+
+#
+# Dynamic library, BACK-LDIF
+#
+#ifeq ($(ARCH), WINNT)
+LIBBACK_LDIF_DLL = libback-ldif
+#else
+LIBBACK_LDIF_DLL = libback-ldif$(DLL_PRESUFFIX)
+#endif
+
+#
+# Dynamic library, REFERINT
+#
+ifeq ($(ARCH), WINNT)
+REFERINT_DLL = referint-plugin
+else
+REFERINT_DLL = referint-plugin$(DLL_PRESUFFIX)
+endif
+
+#
+# Dynamic library, SYNTAX
+#
+ifeq ($(ARCH), WINNT)
+SYNTAX_DLL = syntax-plugin
+else
+SYNTAX_DLL = syntax-plugin$(DLL_PRESUFFIX)
+endif
+
+#
+# Dynamic library, COLLATION
+#
+COLLATION_DLL=liblcoll$(DLL_PRESUFFIX)
+
+#
+# Dynamic library, NT Synchronization Service plugin
+#
+NTSYNCH_DLL=ntsynch-plugin$(DLL_PRESUFFIX)
+
+#
+# Dynamic library, PASS THROUGH AUTHENTICATION PLUGIN
+#
+PASSTHRU_DLL = passthru-plugin$(DLL_PRESUFFIX)
+
+#
+# Dynamic library, UNIQUE UID CHECKING PLUGIN
+#
+UID_DLL = attr-unique-plugin$(DLL_RESUFFIX)
+
+# Dynamic library, Replication Plugin
+#
+REPLICATION_DLL = replication-plugin$(DLL_RESUFFIX)
+
+RETROCL_DLL = retrocl-plugin$(DLL_RESUFFIX)
+
+#
+# Dynamic library, ACL PLUGIN
+#
+ACL_DLL = acl-plugin$(DLL_RESUFFIX)
+
+#
+# Dynamic library, TEST-PLUGINS
+#
+ifeq ($(ARCH), WINNT)
+TEST_PLUGIN_DLL = ns-test-plugin
+else
+TEST_PLUGIN_DLL = libtest-plugin
+endif
+
+#
+# Dynamic library, PWDSTORAGE
+#
+ifeq ($(ARCH), WINNT)
+PWD_DLL = pwdstorage-plugin
+else
+PWD_DLL = pwdstorage-plugin$(DLL_PRESUFFIX)
+endif
+
+#
+# Dynamic library, DISTRIBUTION EXAMPLE
+#
+ifeq ($(ARCH), WINNT)
+DIS_DLL = distrib-plugin
+else
+DIS_DLL = distrib-plugin$(DLL_PRESUFFIX)
+endif
+
+#
+# Chaining backend library, CHAINING DATABASE PLUGIN
+#
+CB_DLL = chainingdb-plugin$(DLL_PRESUFFIX)
+
+#
+# Admin server dynamic library location.
+#
+ifeq ($(ARCH), HPUX)
+ADMSONAME=ns-admin.sl
+else
+ifeq ($(ARCH), SOLARIS)
+ADMSONAME=ns-admin.$(DLL_SUFFIX)
+else
+ifeq ($(ARCH), AIX)
+ADMSONAME=ns-admin$(DLL_PRESUFFIX).$(DLL_SUFFIX)
+else
+ifeq ($(ARCH), WINNT)
+ADMSONAME=ns-admin.$(LIB_SUFFIX)
+endif # WINNT
+endif # AIX
+endif # SOLARIS
+endif # HPUX
+
+ifeq ($(BUILD_MODULE), HTTP_ADMIN)
+ADMININCLUDEDIR = $(MCOM_ROOT)/ldapserver/include
+endif
+
+ifndef ADMSONAME
+ADMSONAME=ns-admin.so
+endif
+
+ifndef ADMSOLIB
+ADMSOLIB = $(BASIC_OBJDIR)-admin/$(ADMSONAME)
+endif
+
+#
+# Library path
+#
+ifeq ($(ARCH), WINNT)
+LIBPATH=LIBPATH:
+else
+LIBPATH=L
+endif
+
+#
+# Web server dynamic library.
+#
+ifeq ($(ARCH), WINNT)
+
+NSHTTPD_DEP = $(COMMON_OBJDIR)/$(BUILD_HTTPDLL_NAME).$(LIB_SUFFIX)
+NSHTTPD = /LIBPATH:$(COMMON_OBJDIR) $(BUILD_HTTPDLL_NAME).$(LIB_SUFFIX)
+DYN_NSHTTPD=$(NSHTTPD)
+NSHTTPD_DLL=$(BUILD_HTTPDLL_NAME)
+
+else
+
+NSHTTPD=$(COMMON_OBJDIR)/$(BUILD_HTTPDLL_NAME).$(DLL_SUFFIX)
+NSHTTPD_DEP = $(NSHTTPD)
+DYN_NSHTTPD=-L$(COMMON_OBJDIR) -l$(LINK_HTTPDLL_NAME)
+NSHTTPD_DLL=$(BUILD_HTTPDLL_NAME)
+
+ifeq ($(ARCH), SOLARIS)
+
+DLLEXPORTS_PREFIX=-Blocal -M
+
+else
+ifeq ($(ARCH), SOLARISx86)
+
+DLLEXPORTS_PREFIX=-Blocal -M
+
+else
+ifeq ($(ARCH), IRIX)
+
+DLLEXPORTS_PREFIX=-exports_file
+
+else
+ifeq ($(ARCH),HPUX)
+
+else
+ifeq ($(ARCH),AIX)
+
+NSHTTPD = $(COMMON_OBJDIR)/$(BUILD_HTTPDLL_NAME)$(DLL_PRESUF).$(DLL_SUFFIX)
+DLLEXPORTS_PREFIX=-bE:
+ifdef OLD_AIX_LINKING
+ DL=-lsvld
+else
+ DL=-ldl
+# flags added to every link
+ PLATFORMLDFLAGS = -brtl
+endif
+
+else
+ifeq ($(ARCH),OSF1)
+
+DL=
+
+else
+ifeq ($(ARCH), Linux)
+
+DL=-ldl
+
+else
+ifeq ($(ARCH),ReliantUNIX)
+
+DYN_NSHTTPD=$(NSHTTPD)
+DL=-ldl
+
+else
+ifeq ($(ARCH),UnixWare)
+
+DYN_NSHTTPD=$(NSHTTPD)
+DL=
+
+else
+#the previous default
+#NSHTTPD=$(NSCP_DISTDIR)/lib/$(BUILD_HTTPDLL_NAME).$(DLL_SUFFIX)
+#DYN_NSHTTPD=$(NSHTTPD)
+#DL=-ldl
+#
+#the new default, which is much better when it comes to porting this product
+NSHTTPD="you need to edit ldapserver/ldap/nsldap.mk for $(ARCH)"
+DYN_NSHTTPD="you need to edit ldapserver/ldap/nsldap.mk for $(ARCH)"
+endif # UnixWare
+endif # ReliantUNIX
+endif # Linux
+endif # OSF1
+endif # AIX
+endif # HPUX
+endif # IRIX
+endif # SOLARISx86
+endif # SOLARIS
+endif # WINNT
+
+
+ADMIN_SECGLUEOBJ=$(BASIC_OBJDIR)-admin/admin-lib/secglue.o
+
+SECGLUEOBJ=$(MCOM_ROOT)/ldapserver/built/$(NS_BUILD_FLAVOR)/httpd-lib/secglue.o
+# XXXggood need to pick up the /share/builds versions of the shared libs
+# because ones we build here don't appear to be compatible with existing
+# shared libs, which are used by admin server.
+#SDKROOT = /share/builds/components/ldapsdk/19961107-bad/$(NC_BUILD_FLAVOR)
+#SDKLDIR = $(SDKROOT)/lib
+#SDKROOT = /share/builds/components/ldapsdk/latest/$(NC_BUILD_FLAVOR)
+#SDKLDIR = $(SDKROOT)/lib
+SDKROOT = $(OBJDIR)
+SDKLDIR = $(SDKROOT)/lib
+SDKHDIR = $(SDKROOT)/include
+LDB_HDIR = $(LDAP_SRC)/libraries/berkeley_db/PORT/include
+
+#
+# Compiler symbol definition
+#
+LDAP_REFERRALS=-DLDAP_REFERRALS
+SLAPD_BACKENDS=-DLDAP_LDBM -DLDAP_LDIF
+LDBMBACKEND=-DLDBM_USE_DBBTREE
+SLAPD_PASSWD_HASH=-DSLAPD_PASSWD_SHA1
+# all debug and server builds are done with LDAP_DEBUG defined.
+# SDK builds pass LDAP_NO_LDAPDEBUG=1 which causes us not to define
+# LDAP_DEBUG in optimized builds.
+ifneq ($(BUILD_DEBUG), optimize)
+LDAP_DEBUG=-DLDAP_DEBUG
+else
+ifneq ($(LDAP_NO_LDAPDEBUG),1)
+LDAP_DEBUG=-DLDAP_DEBUG
+endif
+endif
+NEEDPROTOS=-DNEEDPROTOS
+WINSOCK=-DWINSOCK
+USE_LOCKF=-DUSE_LOCKF
+LDAP_SSLIO_HOOKS=-DLDAP_SSLIO_HOOKS
+DBINTERFACE_PRIVATE=-D__DBINTERFACE_PRIVATE
+NO_DOMAINNAME=-DNO_DOMAINNAME
+
+ifeq ($(LDAP_NO_LIBLCACHE),1)
+NO_LIBLCACHE=-DNO_LIBLCACHE
+endif
+
+ifeq ($(BUILD_MODULE), DIRECTORY)
+NS_DIRECTORY=-DNS_DIRECTORY
+endif
+
+# uncomment this line to use soundex for approximate matches in slapd.
+# the default is to use the metaphone algorithm.
+#PHONETIC=-DSOUNDEX
+
+#
+# uncomment for LDAP over UDP
+#CLDAP=-DCLDAP
+
+#
+# uncomment for Universty of Michigan specific things.
+#UOFM=-DUOFM
+
+#
+# uncomment for elimination of local caching support in Libldap
+#NO_CACHE=-DNO_CACHE
+
+#
+# If you don't want to do auto-translation of character sets, skip this.
+#
+# Otherwise, uncomment this line and set the following options.
+#STR_TRANSLATION=-DSTR_TRANSLATION
+#
+# remove the defines for LDAP client library T.61 character translation
+# you do not need. If you use LDAP_CHARSET_8859, replace the '1' in "88591"
+# with the number of the particular character set you use. E.g., use "88594"
+# if you use the ISO 8859-4 chracter set.
+#LIBLDAP_CHARSETS=-DLDAP_CHARSET_8859="88591"
+#
+# uncomment one these lines to enable automatic T.61 translation by default
+#LIBLDAP_DEF_CHARSET=-DLDAP_DEFAULT_CHARSET=LDAP_CHARSET_8859
+
+#
+# If you are NOT using Kerberos authentication, you can skip this section.
+#
+# Otherwise, to enable kerberos authentication, uncomment KERBEROS (and
+# AFSKERBEROS if you are running the AFS version of kerberos). Also
+# uncomment and change the various KRB* lines to point to where the
+# kerberos libraries and include files are installed at your site.
+#
+#KERBEROS=-DKERBEROS
+#AFSKERBEROS=-DAFSKERBEROS
+#KRBINCLUDEFLAG = -I/usr/local/kerberos/include
+#KRBLIBFLAG = -L/usr/local/kerberos/lib
+#KRBLIBS = -lkrb -ldes
+
+# General non-Windows compiler options
+#
+# Passed to every compile (cc or gcc). This is where you put -O or -g, etc.
+ifneq ($(ARCH), WINNT)
+ifdef BUILD_OPT
+EXTRACFLAGS=-O
+else
+EXTRACFLAGS=-g
+endif
+endif
+
+ifeq ($(ARCH), WINNT)
+ifeq ($(DEBUG), full)
+DSLDDEBUG=/debug
+else
+ifeq ($(DEBUG), purify)
+DSLDDEBUG=/debug
+endif
+endif
+ifndef HEAPAGENT
+PDBOPT=/PDB:NONE
+endif
+endif
+
+#
+# SSL-related definitions
+#
+ifeq ($(SECURITY), export)
+SECURITY_EXTN=export
+endif
+ifeq ($(SECURITY), domestic)
+SECURITY_EXTN=us
+endif
+
+SSL = -DNET_SSL -DUSE_NSPR_MT
+EXTRASSLLIBS = $(LIBARES)
+
+ifeq ($(ARCH), WINNT)
+SSLLIBS = $(EXTRASSLLIBS)
+endif
+
+ifeq ($(ARCH), WINNT)
+LIBNT = $(OBJDIR)/libnt.lib
+LIBNT_DEP = $(LIBNT)
+endif
+
+# If you are certain that an executable will not be using libsec, include
+# the following early in the link command. secglue.o includes "do nothing"
+# shims for most libsec functions. We do this to reduce our size.
+ifeq ($(ARCH), WINNT)
+# MLM
+# SECGLUE= ns-admin.lib
+SECGLUE = $(NSHTTPD) $(OSDEPLIBS) $(LIBNT)
+NOSSLLIBS = $(LDAP_LIBDIR)/libldap.lib \
+ $(SSLLIBS) $(ALIBS)
+else
+# $(ARCH) != WINNT
+ifeq ($(ARCH), Linux)
+# XXXsspitzer: all gcc platforms will have to do this
+SECGLUE= $(SECGLUEOBJS) $(DYN_NSHTTPD)
+# $(LIBARES)
+else # Linux
+SECGLUE= $(SECGLUEOBJS) $(DYN_NSHTTPD)
+# $(LIBARES)
+endif # Linux
+NOSSLLIBS = $(LDAP_SDK_LIBLDAP_DLL) $(LDAP_SDK_LIBLCACHE_DLL)\
+ $(SECGLUE) $(ALIBS)
+endif
+
+ifeq ($(BUILD_DLL), yes)
+STATIC_SECDEPS= $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(COMMON_OBJDIR)/lib/lib, \
+ $(LIBADMIN) $(FRAME) $(LIBACCESS) $(CRYPT))) \
+ $(LIBSEC) $(LIBNSPR)
+
+DYNAMIC_DEPLIBS=$(LDAP_COMMON_LIBS)
+DYNAMIC_DEPLINK=$(DYNAMIC_DEPLIBS)
+else
+STATIC_DEPLIBS=$(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(OBJDIR)/lib/lib, \
+ $(LIBADMIN) $(FRAME) $(LIBACCESS) $(CRYPT))) \
+ $(LIBNSPR)
+
+STATIC_SECDEPS=$(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(OBJDIR)/lib/lib, \
+ $(LIBADMIN) $(FRAME) $(LIBACCESS) $(CRYPT))) \
+ $(LIBSEC) $(LIBNSPR)
+
+DYNAMIC_DEPLIBS=$(LDAP_COMMON_LIBS)
+DYNAMIC_DEPLINK=$(LDAP_COMMON_LIBS)
+endif
+
+ifeq ($(ARCH), WINNT)
+LIBDBM_LIB = $(MCOM_ROOT)/dist/$(NSOBJDIR_NAME)/lib/libdbm.lib
+endif
+
+ifndef DEPLIBS
+DEPLIBS = $(DYNAMIC_DEPLIBS)
+DEPLINK = $(DYNAMIC_DEPLINK)
+ifeq ($(ARCH), WINNT)
+SECDEPS = $(DEPLIBS) $(SECGLUE) $(XP_OBJS)
+else
+SECDEPS = $(STATIC_SECDEPS)
+endif
+SECLINK = $(SECDEPS)
+endif
+
+HTMLDEFS=-DPRODUCT_NAME=$(PRODUCT) -D$(ARCH) -DARCH=$(PRETTY_ARCH)
+
+#
+# Windows NT platform-specifics
+#
+ifeq ($(ARCH), WINNT)
+
+PLATFORM_INCLUDE = -I$(MCOM_ROOT)/ldapserver/include/nt \
+ -I$(LDAP_SRC)/libraries/libutil
+
+SYSERRLIST_IN_STDIO=-DSYSERRLIST_IN_STDIO
+
+endif # WINNT
+
+ifeq ($(ARCH), SOLARIS)
+#
+# SunOS5 platform-specifics
+#
+
+PLATFORM=sunos5
+
+# ranlib not needed under SunOS5
+RANLIB = true
+
+# be explicit about which CC to use
+CC=cc -v
+
+# gie full path to hostname since it may not be in user's path
+HOSTNAME=/usr/ucb/hostname
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+# Flags required to cause compiler to generate code suitable for use in
+# a shared library.
+SLCFLAGS= -KPIC
+
+# Extra linker options needed when creating shared libraries
+DYNALIBS=
+
+# flag to pass to cc when linking to set runtime shared library search path
+# this is used like this, for example: $(RPATHFLAG_PREFIX)../..
+RPATHFLAG_PREFIX=-R
+
+# flag to pass to ld when linking to set runtime shared library search path
+# this is used like this, for example: $(LDRPATHFLAG_PREFIX)../..
+LDRPATHFLAG_PREFIX=-R
+
+# flag to pass to ld to set a shared library's "internal name"
+# this is used like this, for example: $(SONAMEFLAG_PREFIX)libldap.so
+SONAMEFLAG_PREFIX=-h
+
+THREADS= -DTHREAD_SUNOS5_LWP
+PLAT_ADMCFLAGS= -DSVR4 -DSOLARIS
+PLAT_ADMLIBS=
+PLATFORMCFLAGS= -D$(PLATFORM) -D_REENTRANT -DSVR4
+PLATFORMLIBS= -lresolv -lsocket -lnsl -lgen -ldl -lposix4 -lw
+THREADS= -DTHREAD_SUNOS5_LWP
+THREADSLIB=-lthread
+endif # SOLARIS
+
+ifeq ($(ARCH), SOLARISx86)
+#
+# Solaris x86 platform-specifics
+#
+
+PLATFORM=sunos5x86
+
+# ranlib not needed under sunos5x86
+RANLIB = true
+
+# be explicit about which CC to use
+CC=cc
+#CC=gcc
+
+# give full path to hostname since it may not be in user's path
+HOSTNAME=/usr/ucb/hostname
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+# Flags required to cause compiler to generate code suitable for use in
+# a shared library.
+ifeq ($(CC), cc)
+SLCFLAGS= -KPIC
+else
+SLCFLAGS= -fPIC
+endif
+
+# Extra linker options needed when creating shared libraries
+DYNALIBS=
+
+# flag to pass to cc when linking to set runtime shared library search path
+# this is used like this, for example: $(RPATHFLAG_PREFIX)../..
+RPATHFLAG_PREFIX=-R,
+
+# flag to pass to ld when linking to set runtime shared library search path
+# this is used like this, for example: $(LDRPATHFLAG_PREFIX)../..
+LDRPATHFLAG_PREFIX=-R
+
+# flag to pass to ld to set a shared library's "internal name"
+# this is used like this, for example: $(SONAMEFLAG_PREFIX)libldap.so
+SONAMEFLAG_PREFIX=-h
+
+THREADS= -DTHREAD_SUNOS5x86_LWP
+PLAT_ADMCFLAGS= -DSVR4 -DSOLARISx86 -DSOLARIS
+PLAT_ADMLIBS=
+PLATFORMCFLAGS= -D$(PLATFORM) -D_REENTRANT -DSVR4
+PLATFORMLIBS= -lresolv -lsocket -lnsl -lgen -ldl -lposix4 -lw
+THREADS= -DTHREAD_SUNOS5x86_LWP
+THREADSLIB=-lthread
+endif # SOLARISx86
+
+ifeq ($(ARCH), SUNOS4)
+#
+# SunOS 4 platform-specifics
+#
+
+5LINT = /usr/5bin/lint
+
+PLATFORMCFLAGS= -Dsunos4
+THREADS= -DTHREAD_SUNOS4_LWP
+THREADSLIB=-llwp
+
+#
+# the SunOS 4 cc compiler doesn't understand function prototypes, so we
+# need the unproto preprocessor
+#
+NEEDUNPROTO=yes
+UNPROTOCFLAGS=-Qpath $(LDAP_SRC)/build/unproto
+endif # SUNOS4
+
+ifeq ($(ARCH), IRIX)
+#
+# IRIX platform-specifics
+#
+
+PLAT_ADMCFLAGS= -DSVR4 -DIRIX
+PLAT_ADMLIBS=
+
+PLATFORM=irix
+# ranlib not needed under IRIX
+RANLIB = true
+
+# be explicit about which CC to use
+CC=cc
+
+# give full path to hostname since it may not be in user's path
+HOSTNAME=/usr/bsd/hostname
+
+# don't count on a BSD install being present or first in path
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+# flag to pass to cc when linking to set runtime shared library search path
+# this is used like this, for example: $(RPATHFLAG_PREFIX)../..
+RPATHFLAG_PREFIX=-Wl,-rpath,
+
+# flag to pass to ld when linking to set runtime shared library search path
+# this is used like this, for example: $(LDRPATHFLAG_PREFIX)../..
+LDRPATHFLAG_PREFIX=-rpath
+
+# flag to pass to ld to set a shared library's "internal name"
+# this is used like this, for example: $(SONAMEFLAG_PREFIX)libldap.so
+# Note that the definition below includes a trailing space.
+SONAMEFLAG_PREFIX=-soname
+
+PLATFORMCFLAGS=-DUSE_WAITPID -D$(PLATFORM)
+PLATFORMLIBS=
+THREADS= -DTHREAD_SGI_SPROC
+THREADSLIB=
+
+endif # IRIX
+
+ifeq ($(ARCH), OSF1)
+
+#
+# OSF1 platform-specifics
+#
+
+PLATFORM=OSF1
+
+# Even though prototypes are supported by the compiler, OSF's CC doesn't
+# seem to define __STDC__ so we explicitly defined NEEDPROTOS here.
+PLATFORMCFLAGS= -D$(PLATFORM) -DNEEDPROTOS -D_REENTRANT
+PLATFORMLIBS=
+THREADS= -DTHREAD_DCE_PTHREADS
+THREADSLIB= -lpthread
+
+# flag to pass to cc when linking to set runtime shared library search path
+# this is used like this, for example: $(RPATHFLAG_PREFIX)../..
+RPATHFLAG_PREFIX=-Wl,-rpath,
+
+# flag to pass to ld when linking to set runtime shared library search path
+# this is used like this, for example: $(LDRPATHFLAG_PREFIX)../..
+LDRPATHFLAG_PREFIX=-rpath
+
+# flag to pass to ld to set a shared library's "internal name"
+# this is used like this, for example: $(SONAMEFLAG_PREFIX)libldap.so
+# Note that the definition below includes a trailing space.
+SONAMEFLAG_PREFIX=-soname
+
+# the BSD-like install under OSF/1 is called installbsd
+# INSTALL=installbsd
+# use this shell script, instead of installbsd.
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+endif # OSF1
+
+ifeq ($(ARCH), AIX)
+
+#
+# AIX platform-specifics
+#
+
+PLAT_ADMCFLAGS= -DAIX
+PLAT_ADMLIBS=
+
+PLATFORM=aix
+
+# ranlib for aix
+RANLIB=ranlib
+
+# install with BSD semantics
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+# Flags to set runtime shared library search path. For example:
+# $(CC) $(RPATHFLAG_PREFIX)../..$(RPATHFLAG_EXTRAS)
+RPATHFLAG_PREFIX=-blibpath:
+RPATHFLAG_EXTRAS=:/usr/lib:/lib
+
+# flag to pass to ld when linking to set runtime shared library search path
+# this is used like this, for example: $(LDRPATHFLAG_PREFIX)../..
+LDRPATHFLAG_PREFIX=-blibpath:/usr/lib:/lib:
+
+PLATFORMCFLAGS= -D_AIX32_CURSES -DUSE_PTHREADS -DHW_THREADS \
+ -DUSE_REENTRANT_LIBC -Daix -Dunix
+
+PLATFORMLIBS=
+THREADS= -DTHREAD_AIX_PTHREADS
+#SECGLUE= moresecglue.o \
+# $(MCOM_ROOT)/nspr/src/$(NC_BUILD_FLAVOR)/longlong.o \
+# $(MCOM_ROOT)/nspr/src/$(NC_BUILD_FLAVOR)/prprf.o
+
+# JCM - Use -bnoquiet to find out which symbols can't be resolved.
+DLL_LDFLAGS= -bexpall -brtl -bM:SRE -bnoentry \
+ -L.:/usr/lib/threads:/usr/lpp/xlC/lib:/usr/lib:/lib
+DLL_EXTRA_LIBS= -bI:/usr/lib/lowsys.exp -lC_r -lC -lpthreads -lc_r -lm \
+ /usr/lib/libc.a
+
+ifdef OLD_AIX_LINKING
+EXE_EXTRA_LIBS= -bI:/usr/lib/syscalls.exp -lsvld -lpthreads
+else
+EXE_EXTRA_LIBS= -bI:/usr/lib/syscalls.exp -ldl -lpthreads
+endif
+
+endif # AIX
+
+ifeq ($(ARCH), HPUX)
+#
+# HP-UX platform-specifics
+#
+
+CC=cc
+PLATFORM=hpux
+
+# ranlib not needed under HP-UX
+RANLIB = true
+
+# install under HP-UX is not like on BSD systems, so we use our own script
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+# Flags required to cause compiler to generate code suitable for use in
+# a shared library.
+SLCFLAGS=+Z
+
+# we need to link a separate library to get ndbm routines under HP/UX
+LDBMLIB=-lndbm
+
+# flag to pass to cc when linking to set runtime shared library search path
+# this is used like this, for example: $(RPATHFLAG_PREFIX)../..
+RPATHFLAG_PREFIX=-Wl,+s,+b,
+
+# flag to pass to ld when linking to set runtime shared library search path
+# this is used like this, for example: $(LDRPATHFLAG_PREFIX)../..
+LDRPATHFLAG_PREFIX=-Wl,+s,+b,
+
+# flag to pass to ld to set a shared library's "internal name"
+# this is used like this, for example: $(SONAMEFLAG_PREFIX) libldap.so
+SONAMEFLAG_PREFIX=-Wl,+h
+
+# we need to link in the V3 library to get sigset()
+# 07/03/02 - no longer needed - version 6.1
+# PLATFORMLIBS= -lV3
+
+# -Ae means 'enforce ansi BUT allow the use of long-long'. we need this
+# for 64-bit file support.
+PLATFORMCFLAGS= -Dhpux -D$(PLATFORM) -D_HPUX_SOURCE -D_REENTRANT -Ae
+
+#aCC doesn't recognize -Ae so this will be used with aCC
+ACC_PLATFORMCFLAGS= -Dhpux -D$(PLATFORM) -D_HPUX_SOURCE -D_REENTRANT
+
+endif # HPUX
+
+# UNIXWARE || UnixWare
+ifeq ($(subst nix,NIX,$(subst are,ARE,$(ARCH))), UNIXWARE)
+#
+# LDAP SVR4 standard cc Make-platform file
+# Uses the std SVR4 stuff whenever possible.
+# Some references to the BSD compatibility required.
+# "bsdcompat" is an optional package, but we need it installed for other builds
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+# compiler to use, e.g. CC=cc or CC=gcc
+ifndef CC
+CC = cc
+endif
+
+# give full path to hostname since it may not be in user's path
+HOSTNAME=/usr/ucb/hostname
+
+# don't count on /usr/ucb/install being present or first in path
+# INSTALL=$(LDAP_SRC)/build/install.sh
+
+# Flags required to cause compiler to generate code suitable for use in
+# a shared library.
+SLCFLAGS= -Kpic
+
+# Flags required to cause linker to create a shared library
+DYNAFLAGS= -G
+
+# Extra linker options needed then creating shared libraries
+DYNALIBS= -ldl
+
+# Filename extension for shared libraries
+DYNAEXT=so
+
+# ndbm library, needed if not in libc (e.g. LDBMLIB=-lndbm)
+LDBMLIB = -L/usr/ucblib -ldbm
+
+# BSD-like install command; if necessary, you can use a script
+INSTALL = /usr/ucb/install
+
+# command to convert libraries for efficient random access;
+RANLIB = true
+
+# flag to pass to ld to set a shared library's "internal name"
+# this is used like this, for example: $(SONAMEFLAG_PREFIX) libldap.so
+SONAMEFLAG_PREFIX=-h
+
+USE_LD_RUN_PATH=true
+
+# other commands - see the file build/Make-append for a list
+endif #UNIXWARE || UnixWare
+
+ifeq ($(ARCH), UNIXWARE)
+
+PLAT_ADMCFLAGS= -DUNIXWARE -DSVR4 -DSYSV
+
+# flags added to every compile
+PLATFORMCFLAGS= -DUNIXWARE -DSYSV -DSVR4
+
+# flags added to every link
+PLATFORMLDFLAGS =
+
+# extra libraries needed (added to the end of all link commands)
+PLATFORMLIBS = -lsocket -lnsl -lresolv -lgen
+
+# other commands - see the file build/Make-append for a list
+endif #UNIXWARE
+
+ifeq ($(ARCH), UnixWare)
+# Gemini: UnixWare7 (SVR5), or UNIXWARE2.1.x (SVR4) with the UDK
+SYSV_REL := $(shell $(MCOM_ROOT)/ldapserver/nsarch -f | sed 's/UnixWare //')
+ifeq ($(SYSV_REL),5)
+PLAT_ADMCFLAGS= -DUnixWare -DSVR5 -DSYSV
+PLATFORMCFLAGS= -DUnixWare -DSYSV -DSVR5
+else
+PLAT_ADMCFLAGS= -DUNIXWARE -DSVR4 -DSYSV
+PLATFORMCFLAGS= -DUNIXWARE -DSYSV -DSVR4
+endif
+
+# flags added to every link
+PLATFORMLDFLAGS =
+
+# extra libraries needed (added to the end of all link commands)
+PLATFORMLIBS = -lsocket -lnsl -lresolv -lgen
+
+# other commands - see the file build/Make-append for a list
+endif #UnixWare
+
+ifeq ($(ARCH), SCOOS)
+#
+# LDAP SVR4 standard cc Make-platform file
+# Uses the std SVR4 stuff whenever possible.
+# Some references to the BSD compatibility required.
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+# ranlib not needed under SCOOS
+RANLIB = true
+
+USE_LD_RUN_PATH=true
+
+CC= cc -b elf -KPIC -DSCO -DSCOOS
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+# Flags required to cause compiler to generate code suitable for use in
+# a shared library.
+SLCFLAGS= -Kpic
+
+PLATFORMCFLAGS= -DSCO_SV -DSYSV -DHAVE_STRERROR -DSW_THREADS -DSCO_PM -DSCO -Dsco -DSCOOS
+
+PLATFORMLIBS= -lsocket
+
+#-lnsl -ldl -lpmapi -lc -lPW
+
+EXTRA_LIBS= -lsocket
+#-lnsl -ldl -lpmapi -lc -lPW
+
+endif # SCOOS
+
+ifeq ($(ARCH), NCR)
+#
+# LDAP SVR4 standard cc Make-platform file
+# Uses the std SVR4 stuff whenever possible.
+# Some references to the BSD compatibility required.
+#
+
+#
+# add any platform-specific overrides below here
+#
+
+# compiler to use, e.g. CC=cc or CC=gcc
+ifndef CC
+CC = gcc
+endif
+
+# give full path to hostname since it may not be in user's path
+HOSTNAME=/usr/ucb/hostname
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+# Flags required to cause compiler to generate code suitable for use in
+# a shared library.
+SLCFLAGS= -fpic
+
+PLAT_ADMCFLAGS= -DNCR -Di386 -DSVR4 -DSYSV -DHAVE_STRERROR -DSW_THREADS
+
+# flags added to every compile
+PLATFORMCFLAGS= -DNCR -Di386 -DSVR4 -DSYSV -DHAVE_STRERROR -DSW_THREADS
+
+# flags added to every link
+PLATFORMLDFLAGS =
+
+# extra libraries needed (added to the end of all link commands)
+PLATFORMLIBS = -lsocket -lnsl -lgen
+
+EXTRA_LIBS = -lsocket -lnsl -lgen -ldl -lc /usr/ucblib/libucb.a
+
+# Flags required to cause linker to create a shared library
+DYNAFLAGS= -G
+
+# Extra linker options needed then creating shared libraries
+DYNALIBS= -ldl
+
+# Filename extension for shared libraries
+DYNAEXT=so
+
+# ndbm library, needed if not in libc (e.g. LDBMLIB=-lndbm)
+LDBMLIB = -L/usr/ucblib -ldbm
+
+# command to convert libraries for efficient random access;
+RANLIB = true
+
+USE_LD_RUN_PATH=true
+
+# other commands - see the file build/Make-append for a list
+endif #NCR
+
+ifeq ($(ARCH), ReliantUNIX)
+#
+# ReliantUNIX platform-specifics
+#
+PLATFORM=reliantunix
+
+# ranlib not needed under ReliantUNIX
+RANLIB = true
+
+# be explicit about which CC to use
+CC=cc
+
+# gie full path to hostname since it may not be in user's path
+HOSTNAME=/usr/ucb/hostname
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+# Flags required to cause compiler to generate code suitable for use in
+# a shared library.
+SLCFLAGS=
+
+# Extra linker options needed when creating shared libraries
+DYNALIBS=
+
+# flag to pass to cc when linking to set runtime shared library search path
+# this is used like this, for example: $(RPATHFLAG_PREFIX)../..
+RPATHFLAG_PREFIX=-Wl,-R,
+USE_LD_RUN_PATH=true
+
+# flag to pass to ld to set a shared library's "internal name"
+# this is used like this, for example: $(SONAMEFLAG_PREFIX)libldap.so
+SONAMEFLAG_PREFIX=-h
+
+THREADS= -DTHREAD_SUNOS5_LWP
+PLAT_ADMCFLAGS= -DSVR4 -DSNI -DRELIANTUNIX
+PLAT_ADMLIBS=
+PLATFORMCFLAGS= -D$(PLATFORM) -DSVR4 -DSNI -DRELIANTUNIX
+#libc_r.so.1 for strtok_r? talk to ckaiser. maybe libsni_r.a?
+#right now, check out ns/nspr20/pr/include/md/_reliantunix.cfg and
+#ns/nspr20/pr/src/md/unix/reliantunix.c
+PLATFORMLIBS= -lresolv -lsocket -lnsl -lgen -ldl
+THREADS=
+THREADSLIB=
+
+endif # ReliantUNIX
+
+ifeq ($(ARCH), Linux)
+#
+# add any platform-specific overrides below here
+#
+
+# compiler to use, e.g. CC=cc or CC=gcc
+CC=/usr/bin/gcc -fwritable-strings
+
+# give full path to hostname since it may not be in user's path
+HOSTNAME=/bin/hostname
+
+# don't count on /usr/ucb/install being present or first in path
+INSTALL=$(LDAP_SRC)/build/install.sh
+
+# flag to pass to cc when linking to set runtime shared library search path
+# this is used like this, for example: $(RPATHFLAG_PREFIX)../..
+RPATHFLAG_PREFIX=-Wl,-rpath,
+
+# flag to pass to ld when linking to set runtime shared library search path
+# this is used like this, for example: $(LDRPATHFLAG_PREFIX)../..
+# note, there is a trailing space
+LDRPATHFLAG_PREFIX=-rpath
+
+# Flags required to cause compiler to generate code suitable for use in
+# a shared library.
+SLCFLAGS= -fpic
+
+PLAT_ADMCFLAGS= -DLINUX -DLINUX2_0 -DLINUX2_2 -DLinux
+
+# flags added to every compile
+PLATFORMCFLAGS= -DLINUX -DLINUX2_0 -DLINUX2_2 -DLinux
+
+# flags added to every link
+PLATFORMLDFLAGS =
+
+# extra libraries needed (added to the end of all link commands)
+PLATFORMLIBS =
+
+EXTRA_LIBS = -ldl
+
+# Flags required to cause linker to create a shared library
+DYNAFLAGS= -shared
+
+# Extra linker options needed then creating shared libraries
+DYNALIBS= -ldl
+
+# Filename extension for shared libraries
+DYNAEXT=so
+
+# ndbm library, needed if not in libc (e.g. LDBMLIB=-lndbm)
+LDBMLIB = -L/usr/ucblib -ldbm
+
+# command to convert libraries for efficient random access;
+RANLIB = ranlib
+
+# other commands - see the file build/Make-append for a list
+endif # Linux
+
+#
+# DEFS are included in CFLAGS
+#
+DEFS = $(PLATFORMCFLAGS) $(LDAP_DEBUG) $(KERBEROS) $(AFSKERBEROS) \
+ $(UOFM) $(NO_USERINTERFACE) $(CLDAP) $(NO_CACHE) $(DBDEFS) \
+ $(LDAP_REFERRALS) $(LDAP_DNS) $(STR_TRANSLATION) \
+ $(LIBLDAP_CHARSETS) $(LIBLDAP_DEF_CHARSET) \
+ $(SLAPD_BACKENDS) $(LDBMBACKEND) $(LDBMINCLUDE) $(PHONETIC) \
+ $(SLAPD_PASSWD_HASH) $(LDAP_SSLIO_HOOKS) $(DBINTERFACE_PRIVATE) \
+ $(NO_LIBLCACHE) $(SYSERRLIST_IN_STDIO) \
+ $(NS_DIRECTORY)
+
+ifeq ($(ARCH), WINNT)
+DEFS += $(NEEDPROTOS) $(NO_DOMAINNAME)
+endif
+
+# DEFS += $(USE_LOCKF)
+
+# ACFLAGS are added to CFLAGS but not passed to mkdep, lint, etc
+ACFLAGS = $(EXTRACFLAGS) $(UNPROTOCFLAGS)
+
+# ALDFLAGS are always placed near the beginning of all linker (cc -o) commands
+ifneq ($(ARCH), WINNT)
+# Passed to every link (ld). Include -g here if you did in EXTRACFLAGS.
+EXTRALDFLAGS=-$(LIBPATH)$(LDAP_LIBDIR)
+#EXTRALDFLAGS=-$(LIBPATH)$(LDAP_LIBDIR) -$(LIBPATH)$(LDAP_LIBPATH)
+endif
+
+ifeq ($(ARCH), IRIX)
+ ifeq ($(USE_N32), 1)
+ PLATFORMLDFLAGS=-n32 -mips3
+ endif
+endif
+
+ALDFLAGS = $(EXTRALDFLAGS) $(PLATFORMLDFLAGS)
+
+# ALIBS are always placed at the end of all linker (cc -o) commands
+ALIBS = $(PLATFORMLIBS)
+
+INCLUDES += -I$(LDAP_HDIR) $(PLATFORM_INCLUDE) -I$(DIRVERDIR)
+
+CFLAGS += $(DEFS) $(ACFLAGS) $(INCLUDES)
+
+# default definitions for utilities
+
+ifneq ($(ARCH), WINNT)
+SHELL = /bin/sh
+endif
+
+AR = ar cq
+RM = rm -f
+MV = mv -f
+
+CP = cp
+
+CHMOD = chmod
+CAT = cat
+
+ifneq ($(ARCH), WINNT)
+LN = ln -s
+HARDLN = ln
+endif
+
+TAIL = tail.exe
+SED = sed
+LINT = lint
+5LINT = lint
+MKDIR = mkdir -p
+
+ifneq ($(ARCH), WINNT)
+ifndef RANLIB
+RANLIB = ranlib
+endif
+ifndef INSTALL
+INSTALL = install
+endif
+ifndef INSTALLFLAGS
+INSTALLFLAGS = -c
+endif
+ifndef USE_LD_RUN_PATH
+ifndef RPATHFLAG_PREFIX
+RPATHFLAG_PREFIX="XXX Please define a platform-specific RPATHFLAG_PREFIX in nsldap.mk XXX"
+endif
+ifndef LDRPATHFLAG_PREFIX
+LDRPATHFLAG_PREFIX="XXX Please define a platform-specific LDRPATHFLAG_PREFIX in nsldap.mk XXX"
+endif
+endif
+BASENAME= basename
+DIRNAME = dirname
+else
+INSTALL = cp.exe -prv
+RM = rm.exe -rf
+MV = mv.exe -f
+
+CP = cp.exe -prv
+LN = cp.exe -prv
+HARDLN = cp.exe -prv
+
+CHMOD = chmod
+CAT = cat.exe
+MKDIR = mkdir.exe -p
+endif
+
+MKDEP = $(LDAP_SRC)/build/mkdep -s -f Make-template
+PWD = pwd
+DATE = date
+HOSTNAME= hostname
+
+#
+# Compiler output file
+#
+ifeq ($(ARCH), WINNT)
+EXE_SUFFIX=.exe
+RSC=rc
+OFFLAG=/Fo
+else
+OFFLAG=-o
+endif
+
+
+#
+# XXX: does anyone know of a better way to solve the "LINK_LIB2" problem? -mcs
+#
+# Link to produce a console/windows exe on Windows
+#
+ifeq ($(ARCH), WINNT)
+LINK_EXE = link -OUT:"$@" $(USE_MAP) $(ALDFLAGS) $(LDFLAGS) $(ML_DEBUG) \
+ $(LCFLAGS) /NOLOGO $(PDBOPT) /DEBUGTYPE:BOTH /INCREMENTAL:NO \
+ /SUBSYSTEM:$(SUBSYSTEM) $(DEPLIBS) $(EXTRA_LIBS) $(OBJS)
+LINK_EXE_NOLIBSOBJS = link -OUT:"$@" $(USE_MAP) $(ALDFLAGS) $(LDFLAGS) \
+ $(ML_DEBUG) $(LCFLAGS) /NOLOGO $(PDBOPT) /DEBUGTYPE:BOTH /INCREMENTAL:NO \
+ /SUBSYSTEM:$(SUBSYSTEM)
+LINK_LIB = lib -OUT:"$@" $(OBJS)
+LINK_LIB2 = lib -OUT:"$@" $(OBJS2)
+LINK_DLL = link /nologo $(USE_MAP) /DLL $(PDBOPT) /DEBUGTYPE:BOTH \
+ $(ML_DEBUG) /SUBSYSTEM:WINDOWS $(LLFLAGS) $(DLL_LDFLAGS) \
+ $(EXTRA_LIBS) /out:"$@" $(OBJS)
+LINK_DLL2 = link /nologo $(USE_MAP) /DLL $(PDBOPT) /DEBUGTYPE:BOTH \
+ $(ML_DEBUG) /SUBSYSTEM:WINDOWS $(LLFLAGS) $(DLL_LDFLAGS) \
+ $(EXTRA_LIBS) /out:"$@" $(OBJS2)
+else # WINNT
+#
+# UNIX link commands
+#
+LINK_LIB = $(RM) $@; $(AR) $@ $(OBJS); $(RANLIB) $@
+LINK_LIB2 = $(RM) $@; $(AR) $@ $(OBJS2); $(RANLIB) $@
+ifeq ($(ARCH), OSF1)
+DLL_LDFLAGS += $(LDRPATHFLAG_PREFIX) $(RPATHFLAG)$(RPATHFLAG_EXTRAS)
+else
+DLL_LDFLAGS += $(RPATHFLAG_PREFIX)$(RPATHFLAG)$(RPATHFLAG_EXTRAS)
+endif
+ifdef SONAMEFLAG_PREFIX
+LINK_DLL = $(LD) $(ALDFLAGS) $(ARCH_CFLAGS) $(DLL_LDFLAGS) $(DLL_EXPORT_FLAGS) \
+ -o $@ $(SONAMEFLAG_PREFIX)$(notdir $@) $(OBJS)
+LINK_DLL2 = $(LD) $(ALDFLAGS) $(DLL_LDFLAGS) $(DLL_EXPORT_FLAGS2) \
+ -o $@ $(SONAMEFLAG_PREFIX)$(notdir $@) $(OBJS2)
+else # SONAMEFLAG_PREFIX
+LINK_DLL = $(LD) $(ALDFLAGS) $(DLL_LDFLAGS) $(DLL_EXPORT_FLAGS) \
+ -o $@ $(OBJS)
+LINK_DLL2 = $(LD) $(ALDFLAGS) $(DLL_LDFLAGS) $(DLL_EXPORT_FLAGS2) \
+ -o $@ $(OBJS2)
+endif # SONAMEFLAG_PREFIX
+
+ifeq ($(ARCH), HPUX)
+# On HPUX, we need a couple of changes:
+# 1) Use the C++ compiler for linking, which will pass the +eh flag on down to the
+# linker so the correct exception-handling-aware libC gets used (libnshttpd.sl
+# needs this).
+# 2) Add a "-Wl,-E,-N" option so the linker gets a "-E,-N" flag. This makes symbols
+# in an executable visible to shared libraries loaded at runtime and makes ns-slapd
+# 'normal executable' instead of 'shared executable'.
+DS_LINKEXE_EXTRA_FLAGS=-Wl,-E,-N,+k,+vshlibunsats
+LD=$(CXX)
+
+else
+ifeq ($(ARCH), OSF1)
+DS_LINKEXE_EXTRA_FLAGS=-taso
+else
+ifeq ($(ARCH), IRIX)
+DS_LINKEXE_EXTRA_FLAGS=-exceptions
+endif # IRIX
+endif # OSF
+endif # HPUX
+
+# Define an assortment of UNIX LINK_EXE macros.
+DS_LINKEXE_FLAGS=$(DS_LINKEXE_EXTRA_FLAGS) $(ALDFLAGS) $(LDFLAGS)
+ifdef USE_LD_RUN_PATH
+#does RPATH differently. instead we export RPATHFLAG as LD_RUN_PATH
+export LD_RUN_PATH=$(RPATHFLAG)
+else # USE_LD_RUN_PATH
+DS_LINKEXE_FLAGS += $(RPATHFLAG_PREFIX)$(RPATHFLAG)$(RPATHFLAG_EXTRAS)
+endif # USE_LD_RUN_PATH
+
+LINK_EXE = $(CXX) $(DS_LINKEXE_FLAGS) -o $@ \
+ $(OBJS) $(EXTRA_LIBS)
+LINK_EXE_NOLIBSOBJS = $(CXX) $(DS_LINKEXE_FLAGS) -o $@
+endif # WINNT
+
+#
+# Path to platform-specific directory for berkeley db
+#
+ifeq ($(ARCH), SOLARIS)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/sunos.5.2
+else
+ifeq ($(ARCH), IRIX)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/irix.5.3
+else
+ifeq ($(ARCH), AIX)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/aix.4.2
+else
+ifeq ($(ARCH), OSF1)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/osf.2.0
+else
+ifeq ($(ARCH), HPUX)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/hpux.9.01
+else
+ifeq ($(ARCH), WINNT)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/winnt3.51
+else
+# UNIXWARE || UnixWare
+ifeq ($(subst nix,NIX,$(subst are,ARE,$(ARCH))), UNIXWARE)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/unixware.2.1
+else
+ifeq ($(ARCH), SCOOS)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/scoos.5.0
+else
+ifeq ($(ARCH), NCR)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/ncr.3.0
+else
+ifeq ($(ARCH), SOLARISx86)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/sunosx86.5.2
+else
+ifeq ($(ARCH), ReliantUNIX)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/reliantunix.5.4
+else
+ifeq ($(ARCH), Linux)
+LIBDB_MAKEDIR=$(LDAP_SRC)/libraries/berkeley_db/PORT/linux.2.0
+else
+LIBDB_MAKEDIR=XXX_UNDEFINED_XXX
+endif # Linux
+endif # ReliantUNIX
+endif # SOLARISx86
+endif # NCR
+endif # SCOOS
+endif # UnixWare || UNIXWARE
+endif # WINNT
+endif # HPUX
+endif # OSF1
+endif # AIX
+endif # IRIX
+endif # SOLARIS
+
+#
+# Add platform-specific include directory
+#
+# dboreham: this is bogus, take it out
+ifdef LDAP_USE_OLD_DB
+INCLUDES += -I$(LIBDB_MAKEDIR)/include
+endif
+
+#Changes required for ACL
+ACLINC = $(MCOM_ROOT)/ldapserver/include/libaccess
+#ACLDIR = -$(LIBPATH)$(LDAP_LIBDIR)
+ACLLIB = -laccess -lbase -lsi18n
+# end of changes
+
diff --git a/ldap/schema/00core.ldif b/ldap/schema/00core.ldif
new file mode 100644
index 00000000..edc562ce
--- /dev/null
+++ b/ldap/schema/00core.ldif
@@ -0,0 +1,339 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Recommended core schema from the X.500 and LDAP standards (RFCs), and
+# schema used by the Directory Server itself.
+#
+dn: cn=schema
+objectclass: top
+objectclass: ldapSubentry
+objectclass: subschema
+cn: schema
+#
+# aci to ensure that the standard schema attributes are visible to
+# all LDAP clients (anonymous access).
+#
+aci: (target="ldap:///cn=schema")(targetattr !="aci")(version 3.0;acl "anonymous, no acis"; allow (read, search, compare) userdn = "ldap:///anyone";)
+#
+# attribute types:
+#
+attributeTypes: ( 2.5.4.0 NAME 'objectClass' DESC 'Standard LDAP attribute type' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.1 NAME 'aliasedObjectName' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.2 NAME 'knowledgeInformation' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.41 NAME 'name' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{32768} X-ORIGIN 'RFC 2256')
+attributeTypes: ( 2.5.4.49 NAME ( 'dn' 'distinguishedName' ) DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.3 NAME ( 'cn' 'commonName' ) DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.4 NAME ( 'sn' 'surName' ) DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.5 NAME 'serialNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.6 NAME ( 'c' 'countryName' ) DESC 'Standard LDAP attribute type' SUP name SINGLE-VALUE X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.7 NAME ( 'l' 'locality' 'localityname' ) DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.8 NAME ( 'st' 'stateOrProvinceName' ) DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.9 NAME ( 'street' 'streetaddress' ) DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.10 NAME ( 'o' 'organizationname' ) DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.11 NAME ( 'ou' 'organizationalUnitName' ) DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.12 NAME 'title' DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.13 NAME 'description' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.14 NAME 'searchGuide' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.15 NAME 'businessCategory' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.16 NAME 'postalAddress' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.17 NAME 'postalCode' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.18 NAME 'postOfficeBox' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.19 NAME 'physicalDeliveryOfficeName' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.20 NAME 'telephoneNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.21 NAME 'telexNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.22 NAME 'teletexTerminalIdentifier' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.23 NAME ( 'facsimileTelephoneNumber' 'fax' ) DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.24 NAME 'x121Address' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.25 NAME 'internationaliSDNNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.26 NAME 'registeredAddress' DESC 'Standard LDAP attribute type' SUP postalAddress X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.27 NAME 'destinationIndicator' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.28 NAME 'preferredDeliveryMethod' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.29 NAME 'presentationAddress' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.30 NAME 'supportedApplicationContext' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.31 NAME 'member' DESC 'Standard LDAP attribute type' SUP distinguishedName X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.32 NAME 'owner' DESC 'Standard LDAP attribute type' SUP distinguishedName X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.33 NAME 'roleOccupant' DESC 'Standard LDAP attribute type' SUP distinguishedName X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.34 NAME 'seeAlso' DESC 'Standard LDAP attribute type' SUP distinguishedName X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.35 NAME 'userPassword' DESC 'Standard LDAP attribute type' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40{128} X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.36 NAME 'userCertificate' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.37 NAME 'cACertificate' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.38 NAME 'authorityRevocationList' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.39 NAME 'certificateRevocationList' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.40 NAME 'crossCertificatePair' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.42 NAME 'givenName' DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.43 NAME 'initials' DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.44 NAME 'generationQualifier' DESC 'Standard LDAP attribute type' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.45 NAME 'x500UniqueIdentifier' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.46 NAME 'dnQualifier' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.47 NAME 'enhancedSearchGuide' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.48 NAME 'protocolInformation' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.50 NAME 'uniqueMember' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.51 NAME 'houseIdentifier' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.52 NAME 'supportedAlgorithms' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.53 NAME 'deltaRevocationList' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 2.5.4.54 NAME 'dmdName' SUP name X-ORIGIN 'RFC 2256' )
+attributeTypes: ( 0.9.2342.19200300.100.1.1 NAME ( 'uid' 'userid' ) DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.3 NAME ( 'mail' 'rfc822mailbox' ) DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.6 NAME 'roomNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.10 NAME 'manager' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.20 NAME 'homePhone' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.21 NAME 'secretary' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.39 NAME 'homePostalAddress' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.41 NAME ( 'mobile' 'mobileTelephoneNumber' ) DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.42 NAME ( 'pager' 'pagerTelephoneNumber' ) DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.43 NAME ( 'co' 'friendlycountryname' ) DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.55 NAME 'audio' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.60 NAME 'jpegPhoto' DESC 'inetOrgPerson attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.28 X-ORIGIN 'RFC 2798' )
+attributeTypes: ( 1.3.6.1.4.1.250.1.57 NAME ( 'labeledUri' 'labeledurl' ) DESC 'Uniform Resource Identifier with optional label' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2079' )
+attributeTypes: ( 2.16.840.1.113730.3.1.1 NAME 'carLicense' DESC 'inetOrgPerson attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2798' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2 NAME 'departmentNumber' DESC 'inetOrgPerson attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2798' )
+attributeTypes: ( 2.16.840.1.113730.3.1.3 NAME 'employeeNumber' DESC 'inetOrgPerson attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2798' )
+attributeTypes: ( 2.16.840.1.113730.3.1.4 NAME 'employeeType' DESC 'inetOrgPerson attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2798' )
+attributeTypes: ( 2.16.840.1.113730.3.1.5 NAME 'changeNumber' DESC 'Changelog attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'Changelog Internet Draft' )
+attributeTypes: ( 2.16.840.1.113730.3.1.6 NAME 'targetDn' DESC 'Changelog attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Changelog Internet Draft' )
+attributeTypes: ( 2.16.840.1.113730.3.1.7 NAME 'changeType' DESC 'Changelog attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Changelog Internet Draft' )
+attributeTypes: ( 2.16.840.1.113730.3.1.8 NAME 'changes' DESC 'Changelog attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'Changelog Internet Draft' )
+attributeTypes: ( 2.16.840.1.113730.3.1.9 NAME 'newRdn' DESC 'Changelog attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Changelog Internet Draft' )
+attributeTypes: ( 2.16.840.1.113730.3.1.10 NAME 'deleteOldRdn' DESC 'Changelog attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 X-ORIGIN 'Changelog Internet Draft' )
+attributeTypes: ( 2.16.840.1.113730.3.1.11 NAME 'newSuperior' DESC 'Changelog attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Changelog Internet Draft' )
+attributeTypes: ( 2.16.840.1.113730.3.1.34 NAME 'ref' DESC 'LDAP referrals attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'LDAPv3 referrals Internet Draft' )
+attributeTypes: ( 2.5.18.1 NAME 'createTimestamp' DESC 'Standard LDAP attribute type' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.18.2 NAME 'modifyTimestamp' DESC 'Standard LDAP attribute type' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.18.3 NAME 'creatorsName' DESC 'Standard LDAP attribute type' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.18.4 NAME 'modifiersName' DESC 'Standard LDAP attribute type' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.18.10 NAME 'subschemaSubentry' DESC 'Standard LDAP attribute type' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.21.5 NAME 'attributeTypes' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.21.6 NAME 'objectClasses' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.21.4 NAME 'matchingRules' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.21.8 NAME 'matchingRuleUse' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.21.1 NAME 'dITStructureRules' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.21.2 NAME 'dITContentRules' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 2.5.21.7 NAME 'nameForms' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.5 NAME 'namingContexts' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE dSAOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.6 NAME 'altServer' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 USAGE dSAOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.7 NAME 'supportedExtension' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.13 NAME 'supportedControl' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.14 NAME 'supportedSASLMechanisms' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE dSAOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.15 NAME 'supportedLDAPVersion' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 USAGE dSAOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation X-ORIGIN 'RFC 2252' )
+attributeTypes: ( 1.3.6.1.4.1.4203.1.3.5 NAME 'supportedFeatures' DESC 'features supported by the server' EQUALITY objectIdentifierMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.38 USAGE dSAOperation )
+attributeTypes: ( 2.16.840.1.113730.3.1.36 NAME 'nsLicensedFor' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.37 NAME 'nsLicenseStartTime' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.38 NAME 'nsLicenseEndTime' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.39 NAME 'preferredLanguage' DESC 'inetOrgPerson attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2798' )
+attributeTypes: ( 2.16.840.1.113730.3.1.40 NAME 'userSMIMECertificate' DESC 'inetOrgPerson attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2798' )
+attributeTypes: ( 2.16.840.1.113730.3.1.55 NAME 'aci' DESC 'Netscape defined access control information attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.70 NAME 'serverRoot' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.71 NAME 'serverProductName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.72 NAME 'serverVersionNumber' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.73 NAME 'installationTimeStamp' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.74 NAME 'administratorContactInfo' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.75 NAME 'adminUrl' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.76 NAME 'serverHostName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( 2.16.840.1.113730.3.1.77 NAME 'changeTime' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.91 NAME 'passwordExpirationTime' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.92 NAME ( 'passwordExpWarned' 'pwdExpirationWarned' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.93 NAME 'passwordRetryCount' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.94 NAME 'retryCountResetTime' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.95 NAME 'accountUnlockTime' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.96 NAME ( 'passwordHistory' 'pwdHistory' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.97 NAME ( 'passwordMaxAge' 'pwdMaxAge' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.98 NAME 'passwordExp' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.99 NAME ( 'passwordMinLength' 'pwdMinLength' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.100 NAME 'passwordKeepHistory' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.101 NAME ( 'passwordInHistory' 'pwdInHistory' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.102 NAME ( 'passwordChange' 'pwdAllowUserChange' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.103 NAME ( 'passwordCheckSyntax' 'pwdCheckSyntax' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.104 NAME ( 'passwordWarning' 'pwdExpireWarning' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.105 NAME ( 'passwordLockout' 'pwdLockOut' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.106 NAME ( 'passwordMaxFailure' 'pwdMaxFailure' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.107 NAME 'passwordResetDuration' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.108 NAME 'passwordUnlock' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.109 NAME ( 'passwordLockoutDuration' 'pwdLockoutDuration' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.997 NAME 'pwdpolicysubentry' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.998 NAME ( 'passwordGraceUserTime' 'pwdGraceUserTime' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.999 NAME ( 'passwordGraceLimit' 'pwdGraceLoginLimit' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.198 NAME 'memberURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.199 NAME 'memberCertificateDescription' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.207 NAME 'vlvBase' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.208 NAME 'vlvScope' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.209 NAME 'vlvFilter' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.210 NAME 'vlvSort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.213 NAME 'vlvEnabled' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.214 NAME 'passwordAllowChangeTime' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.215 NAME 'oid' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.216 NAME 'userPKCS12' DESC 'inetOrgPerson attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 2798' )
+attributeTypes: ( 2.16.840.1.113730.3.1.219 NAME 'vlvUses' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.220 NAME ( 'passwordMustChange' 'pwdMustChange' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.221 NAME 'passwordStorageScheme' DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.222 NAME ( 'passwordMinAge' 'pwdMinAge' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.223 NAME ( 'passwordResetFailureCount' 'pwdFailureCountInterval' ) DESC 'Netscape defined password policy attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.224 NAME 'nsslapd-pluginPath' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.225 NAME 'nsslapd-pluginInitfunc' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.226 NAME 'nsslapd-pluginType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.227 NAME 'nsslapd-pluginId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.228 NAME 'nsslapd-pluginVersion' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.229 NAME 'nsslapd-pluginVendor' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.230 NAME 'nsslapd-pluginDescription' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.231 NAME 'nsslapd-pluginEnabled' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.232 NAME 'nsSNMPEnabled' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.233 NAME 'nsSNMPOrganization' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.234 NAME 'nsSNMPLocation' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.235 NAME 'nsSNMPContact' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.236 NAME 'nsSNMPDescription' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.237 NAME 'nsSNMPMasterHost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.238 NAME 'nsSNMPMasterPort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.241 NAME 'displayName' DESC 'inetOrgPerson attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2798' )
+attributeTypes: ( 2.16.840.1.113730.3.1.242 NAME 'nsSystemIndex' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.327 NAME 'nsIndexType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.328 NAME 'nsMatchingRule' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.542 NAME 'nsUniqueId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.543 NAME 'nsState' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.544 NAME 'nsParentUniqueId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.545 NAME 'nscpEntryDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.550 NAME 'cosAttribute' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.551 NAME 'cosspecifier' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.552 NAME 'costargettree' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.553 NAME 'costemplatedn' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.35 NAME 'changeLog' DESC 'the distinguished name of the entry which contains the set of entries comprising this servers changelog' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Changelog Internet Draft' )
+attributeTypes: ( 2.16.840.1.113730.3.1.200 NAME 'changeLogMaximumAge' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.201 NAME 'changeLogMaximumSize' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.205 NAME 'changeLogMaximumConcurrentWrites' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 1.3.6.1.4.1.250.1.2 NAME 'multiLineDescription' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 1.3.6.1.4.1.250.1.60 NAME ( 'ttl' 'timeToLive' ) DESC 'time to live in seconds for cached objects' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'LDAP Caching Internet Draft' )
+attributeTypes: ( 0.9.2342.19200300.100.1.7 NAME 'photo' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 2.16.840.1.113730.3.1.612 NAME 'generation' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 1.3.1.1.4.1.453.16.2.103 NAME 'numSubordinates' DESC 'count of immediate subordinates' EQUALITY integerMatch ORDERING integerOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'numSubordinates Internet Draft' )
+attributeTypes: ( 2.5.18.9 NAME 'hasSubordinates' DESC 'if TRUE, subordinate entries may exist' EQUALITY booleanMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'numSubordinates Internet Draft' )
+attributeTypes: ( 2.16.840.1.113730.3.1.569 NAME 'cosPriority' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.570 NAME 'nsLookThroughLimit' DESC 'Binder-based search operation look through limit (candidate entries)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.571 NAME 'nsSizeLimit' DESC 'Binder-based search operation size limit (entries)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.572 NAME 'nsTimeLimit' DESC 'Binder-based search operation time limit (seconds)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.573 NAME 'nsIdleTimeout' DESC 'Binder-based connection idle timeout (seconds)' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.574 NAME 'nsRole' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.575 NAME 'nsRoleDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.576 NAME 'nsRoleFilter' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.577 NAME 'cosIndirectSpecifier' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.578 NAME 'nsDS5ReplicaHost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.579 NAME 'nsDS5ReplicaPort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.580 NAME 'nsDS5ReplicaTransportInfo' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.581 NAME 'nsDS5ReplicaBindDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.582 NAME 'nsDS5ReplicaCredentials' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.583 NAME 'nsDS5ReplicaBindMethod' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.584 NAME 'nsDS5ReplicaRoot' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.585 NAME 'nsDS5ReplicatedAttributeList' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.586 NAME 'nsDS5ReplicaUpdateSchedule' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.587 NAME 'nsds50ruv' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2027 NAME 'nsruvReplicaLastModified' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.588 NAME 'nsDS5ReplicaId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.589 NAME 'nsDS5ReplicaType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.590 NAME 'nsDS5ReplicaName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.591 NAME 'nsDS5ReplicaReferral' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.592 NAME 'nsDS5ReplicaAutoReferral' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.607 NAME 'nsDS5Flags' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.608 NAME 'nsDS5Task' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.609 NAME 'nsds5BeginReplicaRefresh' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.610 NAME 'nsAccountLock' DESC 'Operational attribute for Account Inactivation' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.613 NAME 'copiedFrom' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.614 NAME 'copyingFrom' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.682 NAME 'nsds5ReplicaPurgeDelay' DESC 'Netscape defined attribute type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.684 NAME 'nsds5ReplicaChangeCount' DESC 'Netscape defined attribute type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.683 NAME 'nsds5ReplicaTombstonePurgeInterval' DESC 'Netscape defined attribute type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.685 NAME 'nsds5replicaLastUpdateStart' DESC 'Netscape defined attribute type' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.686 NAME 'nsds5replicaLastUpdateEnd' DESC 'Netscape defined attribute type' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.687 NAME 'nsds5replicaChangesSentSinceStartup' DESC 'Netscape defined attribute type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.688 NAME 'nsds5replicaLastUpdateStatus' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.689 NAME 'nsds5replicaUpdateInProgress' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.802 NAME 'nsds5ReplicaLegacyConsumer' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.803 NAME 'nsBackendSuffix' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.804 NAME 'nsSchemaCSN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.805 NAME 'nsds5replicaTimeout' DESC 'Netscape defined attribute type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.807 NAME 'nsds5replicaLastInitStart' DESC 'Netscape defined attribute type' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.808 NAME 'nsds5replicaLastInitEnd' DESC 'Netscape defined attribute type' EQUALITY generalizedTimeMatch ORDERING generalizedTimeOrderingMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.24 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.809 NAME 'nsds5replicaLastInitStatus' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.1097 NAME 'nsds5replicaBusyWaitTime' DESC 'Netscape defined attribute type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.1098 NAME 'nsds5replicaSessionPauseTime' DESC 'Netscape defined attribute type' EQUALITY integerMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.9999999 NAME 'nsds5debugreplicatimeout' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.973 NAME 'nsds5ReplConflict' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 1.3.6.1.1.4 NAME 'vendorName' EQUALITY 1.3.6.1.4.1.1466.109.114.1 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation X-ORIGIN 'RFC 3045' )
+attributeTypes: ( 1.3.6.1.1.5 NAME 'vendorVersion' EQUALITY 1.3.6.1.4.1.1466.109.114.1 SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE dSAOperation X-ORIGIN 'RFC 3045' )
+attributeTypes: ( 2.16.840.1.113730.3.1.3023 NAME 'nsViewFilter' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2063 NAME 'nsEncryptionAlgorithm' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2064 NAME 'nsSaslMapRegexString' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2065 NAME 'nsSaslMapBaseDNTemplate' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2066 NAME 'nsSaslMapFilterTemplate' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Directory Server' )
+#
+# objectclasses:
+#
+objectClasses: ( 2.5.6.0 NAME 'top' DESC 'Standard LDAP objectclass' ABSTRACT MUST objectClass X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.1 NAME 'alias' DESC 'Standard LDAP objectclass' SUP top ABSTRACT MUST ( aliasedObjectName ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 1.3.6.1.4.1.1466.101.120.111 NAME 'extensibleObject' DESC 'LDAPv3 extensible object' SUP top AUXILIARY X-ORIGIN 'RFC 2252' )
+objectClasses: ( 2.5.6.2 NAME 'country' DESC 'Standard LDAP objectclass' SUP top MUST ( c ) MAY ( searchGuide $ description ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.3 NAME 'locality' DESC 'Standard LDAP attribute type' SUP top MAY ( description $ l $ searchGuide $ seeAlso $ st $ street ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.4 NAME 'organization' DESC 'Standard LDAP objectclass' SUP top MUST ( o ) MAY ( businessCategory $ description $ destinationIndicator $ facsimileTelephoneNumber $ internationaliSDNNumber $ l $ physicalDeliveryOfficeName $ postOfficeBox $ postalAddress $ postalCode $ preferredDeliveryMethod $ registeredAddress $ searchGuide $ seeAlso $ st $ street $ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $ userPassword $ x121Address ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.5 NAME 'organizationalUnit' DESC 'Standard LDAP objectclass' SUP top MUST ( ou ) MAY ( businessCategory $ description $ destinationIndicator $ facsimileTelephoneNumber $ internationaliSDNNumber $ l $ physicalDeliveryOfficeName $ postOfficeBox $ postalAddress $ postalCode $ preferredDeliveryMethod $ registeredAddress $ searchGuide $ seeAlso $ st $ street $ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $ userPassword $ x121Address ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.6 NAME 'person' DESC 'Standard LDAP objectclass' SUP top MUST ( sn $ cn ) MAY ( description $ seeAlso $ telephoneNumber $ userPassword ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.7 NAME 'organizationalPerson' DESC 'Standard LDAP objectclass' SUP person MAY ( destinationIndicator $ facsimileTelephoneNumber $ internationaliSDNNumber $ l $ ou $ physicalDeliveryOfficeName $ postOfficeBox $ postalAddress $ postalCode $ preferredDeliveryMethod $ registeredAddress $ st $ street $ teletexTerminalIdentifier $ telexNumber $ title $ x121Address ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.16.840.1.113730.3.2.2 NAME 'inetOrgPerson' DESC 'Internet extended organizational person objectclass' SUP organizationalPerson MAY ( audio $ businessCategory $ carLicense $ departmentNumber $ displayName $ employeeType $ employeeNumber $ givenName $ homePhone $ homePostalAddress $ initials $ jpegPhoto $ labeledURI $ manager $ mobile $ pager $ photo $ preferredLanguage $ mail $ o $ roomNumber $ secretary $ uid $ x500uniqueIdentifier $ userCertificate $ userSMimeCertificate $ userPKCS12 ) X-ORIGIN 'RFC 2798' )
+objectClasses: ( 2.5.6.8 NAME 'organizationalRole' DESC 'Standard LDAP objectclass' SUP top MUST ( cn ) MAY ( description $ destinationIndicator $ facsimileTelephoneNumber $ internationaliSDNNumber $ l $ ou $ physicalDeliveryOfficeName $ postOfficeBox $ postalAddress $ postalCode $ preferredDeliveryMethod $ registeredAddress $ roleOccupant $ seeAlso $ st $ street $ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $ x121Address ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.9 NAME 'groupOfNames' DESC 'Standard LDAP objectclass' SUP top MUST ( cn ) MAY ( member $ businessCategory $ description $ o $ ou $ owner $ seeAlso ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.17 NAME 'groupOfUniqueNames' DESC 'Standard LDAP objectclass' SUP top MUST ( cn ) MAY ( uniqueMember $ businessCategory $ description $ o $ ou $ owner $ seeAlso ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.16.840.1.113730.3.2.31 NAME 'groupOfCertificates' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( memberCertificateDescription $ businessCategory $ description $ o $ ou $ owner $ seeAlso ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.33 NAME 'groupOfURLs' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( memberURL $ businessCategory $ description $ o $ ou $ owner $ seeAlso ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.5.6.10 NAME 'residentialPerson' DESC 'Standard LDAP objectclass' SUP person MUST ( l ) MAY ( businessCategory $ destinationIndicator $ facsimileTelephoneNumber $ internationaliSDNNumber $ physicalDeliveryOfficeName $ postOfficeBox $ postalAddress $ postalCode $ preferredDeliveryMethod $ registeredAddress $ st $ street $ teletexTerminalIdentifier $ telexNumber $ x121Address ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.11 NAME 'applicationProcess' DESC 'Standard LDAP objectclass' SUP top MUST ( cn ) MAY ( description $ l $ ou $ seeAlso ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.16.840.1.113730.3.2.35 NAME 'LDAPServer' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( description $ l $ ou $ seeAlso $ generation $ changeLogMaximumAge $ changeLogMaximumSize ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.5.6.12 NAME 'applicationEntity' DESC 'Standard LDAP objectclass' SUP top MUST ( presentationAddress $ cn ) MAY ( description $ l $ o $ ou $ seeAlso $ supportedApplicationContext ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.13 NAME 'dSA' DESC 'Standard LDAP objectclass' SUP applicationEntity MAY ( knowledgeInformation ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.14 NAME 'device' DESC 'Standard LDAP objectclass' SUP top MUST ( cn ) MAY ( description $ l $ o $ ou $ owner $ seeAlso $ serialNumber ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.15 NAME 'strongAuthenticationUser' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MUST ( userCertificate ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.16 NAME 'certificationAuthority' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MUST ( authorityRevocationList $ certificateRevocationList $ cACertificate ) MAY crossCertificatePair X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.16.2 NAME 'certificationAuthority-V2' DESC 'Standard LDAP objectclass' SUP certificationAuthority MAY deltaRevocationList X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.18 NAME 'userSecurityInformation' SUP top AUXILIARY MAY ( supportedAlgorithms ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.19 NAME 'cRLDistributionPoint' SUP top STRUCTURAL MUST ( cn ) MAY ( certificateRevocationList $ authorityRevocationList $ deltaRevocationList ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 2.5.6.20 NAME 'dmd' SUP top STRUCTURAL MUST ( dmdName ) MAY ( userPassword $ searchGuide $ seeAlso $ businessCategory $ x121Address $ registeredAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNumber $ teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $ facsimileTelephoneNumber $ street $ postOfficeBox $ postalCode $ postalAddress $ physicalDeliveryOfficeName $ st $ l $ description ) X-ORIGIN 'RFC 2256' )
+objectClasses: ( 1.3.6.1.4.1.250.3.15 NAME 'labeledURIObject' DESC 'object that contains the URI attribute type' SUP top AUXILIARY MAY ( labeledURI ) X-ORIGIN 'RFC 2079' )
+objectClasses: ( 1.3.6.1.4.1.250.3.18 NAME 'cacheObject' DESC 'object that contains the TTL (time to live) attribute type' SUP top MAY ( ttl ) X-ORIGIN 'LDAP Caching Internet Draft' )
+objectClasses: ( 2.5.20.1 NAME 'subschema' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MAY ( dITStructureRules $ nameForms $ dITContentRules $ objectClasses $ attributeTypes $ matchingRules $ matchingRuleUse ) X-ORIGIN 'RFC 2252' )
+objectClasses: ( 2.16.840.1.113730.3.2.10 NAME 'netscapeServer' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( description $ serverRoot $ serverProductName $ serverVersionNumber $ installationTimeStamp $ administratorContactInfo $ userpassword $ adminURL $ serverHostName ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( 2.16.840.1.113730.3.2.7 NAME 'nsLicenseUser' DESC 'Netscape defined objectclass' SUP top MAY ( nsLicensedFor $ nsLicenseStartTime $ nsLicenseEndTime ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( 2.16.840.1.113730.3.2.1 NAME 'changeLogEntry' DESC 'LDAP changelog objectclass' SUP top MUST ( targetdn $ changeTime $ changenumber $ changeType ) MAY ( changes $ newrdn $ deleteoldrdn $ newsuperior ) X-ORIGIN 'Changelog Internet Draft' )
+objectClasses: ( 2.16.840.1.113730.3.2.6 NAME 'referral' DESC 'LDAP referrals objectclass' SUP top MAY ( ref ) X-ORIGIN 'LDAPv3 referrals Internet Draft' )
+objectClasses: ( 2.16.840.1.113730.3.2.12 NAME 'passwordObject' DESC 'Netscape defined password policy objectclass' SUP top MAY ( pwdpolicysubentry $ passwordExpirationTime $ passwordExpWarned $ passwordRetryCount $ retryCountResetTime $ accountUnlockTime $ passwordHistory $ passwordAllowChangeTime $ passwordGraceUserTime ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.13 NAME 'passwordPolicy' DESC 'Netscape defined password policy objectclass' SUP top MAY ( passwordMaxAge $ passwordExp $ passwordMinLength $ passwordKeepHistory $ passwordInHistory $ passwordChange $ passwordWarning $ passwordLockout $ passwordMaxFailure $ passwordResetDuration $ passwordUnlock $ passwordLockoutDuration $ passwordCheckSyntax $ passwordMustChange $ passwordStorageScheme $ passwordMinAge $ passwordResetFailureCount $ passwordGraceLimit ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.30 NAME 'glue' DESC 'Netscape defined objectclass' SUP top X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.32 NAME 'netscapeMachineData' DESC 'Netscape defined objectclass' SUP top X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.38 NAME 'vlvSearch' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ vlvBase $ vlvScope $ vlvFilter ) MAY ( multiLineDescription ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.39 NAME 'nsslapdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.40 NAME 'directoryServerFeature' DESC 'Netscape defined objectclass' SUP top MAY ( oid $ cn $ multiLineDescription ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.41 NAME 'nsslapdPlugin' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsslapd-pluginPath $ nsslapd-pluginInitFunc $ nsslapd-pluginType $ nsslapd-pluginId $ nsslapd-pluginVersion $ nsslapd-pluginVendor $ nsslapd-pluginDescription $ nsslapd-pluginEnabled ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.42 NAME 'vlvIndex' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ vlvSort ) MAY ( vlvEnabled $ vlvUses ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.43 NAME 'nsSNMP' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSNMPEnabled ) MAY ( nsSNMPOrganization $ nsSNMPLocation $ nsSNMPContact $ nsSNMPDescription $ nsSNMPMasterHost $ nsSNMPMasterPort ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.44 NAME 'nsIndex' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSystemIndex ) MAY ( description $ nsIndexType $ nsMatchingRule ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.84 NAME 'cosDefinition' DESC 'Netscape defined objectclass' SUP top MAY ( costargettree $ costemplatedn $ cosspecifier $ cosattribute $ aci $ cn $ uid ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113719.2.142.6.1.1 NAME 'ldapSubEntry' DESC 'LDAP Subentry class, version 1' SUP top STRUCTURAL MAY ( cn ) X-ORIGIN 'LDAP Subentry Internet Draft' )
+objectClasses: ( 2.16.840.1.113730.3.2.93 NAME 'nsRoleDefinition' DESC 'Netscape defined objectclass' SUP ldapSubEntry MAY ( description ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.94 NAME 'nsSimpleRoleDefinition' DESC 'Netscape defined objectclass' SUP nsRoleDefinition X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.95 NAME 'nsComplexRoleDefinition' DESC 'Netscape defined objectclass' SUP nsRoleDefinition X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.96 NAME 'nsManagedRoleDefinition' DESC 'Netscape defined objectclass' SUP nsSimpleRoleDefinition X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.97 NAME 'nsFilteredRoleDefinition' DESC 'Netscape defined objectclass' SUP nsComplexRoleDefinition MUST ( nsRoleFilter ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.98 NAME 'nsNestedRoleDefinition' DESC 'Netscape defined objectclass' SUP nsComplexRoleDefinition MUST ( nsRoleDN ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.99 NAME 'cosSuperDefinition' DESC 'Netscape defined objectclass' SUP ldapSubEntry MUST (cosattribute) MAY ( description ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.100 NAME 'cosClassicDefinition' DESC 'Netscape defined objectclass' SUP cosSuperDefinition MAY ( cosTemplateDn $ cosspecifier ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.101 NAME 'cosPointerDefinition' DESC 'Netscape defined objectclass' SUP cosSuperDefinition MAY ( cosTemplateDn ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.102 NAME 'cosIndirectDefinition' DESC 'Netscape defined objectclass' SUP cosSuperDefinition MAY ( cosIndirectSpecifier ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.103 NAME 'nsDS5ReplicationAgreement' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsDS5ReplicaHost $ nsDS5ReplicaPort $ nsDS5ReplicaTransportInfo $ nsDS5ReplicaBindDN $ nsDS5ReplicaCredentials $ nsDS5ReplicaBindMethod $ nsDS5ReplicaRoot $ nsDS5ReplicatedAttributeList $ nsDS5ReplicaUpdateSchedule $ nsds5BeginReplicaRefresh $ description $ nsds50ruv $ nsruvReplicaLastModified $ nsds5ReplicaTimeout $ nsds5replicaChangesSentSinceStartup $ nsds5replicaLastUpdateEnd $ nsds5replicaLastUpdateStart $ nsds5replicaLastUpdateStatus $ nsds5replicaUpdateInProgress $ nsds5replicaLastInitEnd $ nsds5replicaLastInitStart $ nsds5replicaLastInitStatus $ nsds5debugreplicatimeout $ nsds5replicaBusyWaitTime $ nsds5replicaSessionPauseTime ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.104 NAME 'nsContainer' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.108 NAME 'nsDS5Replica' DESC 'Netscape defined objectclass' SUP top MUST ( nsDS5ReplicaRoot $ nsDS5ReplicaId ) MAY (cn $ nsDS5ReplicaType $ nsDS5ReplicaBindDN $ nsState $ nsDS5ReplicaName $ nsDS5Flags $ nsDS5Task $ nsDS5ReplicaReferral $ nsDS5ReplicaAutoReferral $ nsds5ReplicaPurgeDelay $ nsds5ReplicaTombstonePurgeInterval $ nsds5ReplicaChangeCount $ nsds5ReplicaLegacyConsumer) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.109 NAME 'nsBackendInstance' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.110 NAME 'nsMappingTree' DESC 'Netscape defined objectclass' SUP top MUST ( CN ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.113 NAME 'nsTombstone' DESC 'Netscape defined objectclass' SUP top MAY ( nsParentUniqueId $ nscpEntryDN ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.128 NAME 'costemplate' DESC 'Netscape defined objectclass' SUP top MAY ( cn $ cospriority ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.304 NAME 'nsView' DESC 'Netscape defined objectclass' SUP top AUXILIARY MAY ( nsViewFilter $ description ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.316 NAME 'nsAttributeEncryption' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsEncryptionAlgorithm ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.317 NAME 'nsSaslMapping' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsSaslMapRegexString $ nsSaslMapBaseDNTemplate $ nsSaslMapFilterTemplate ) X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/schema/05rfc2247.ldif b/ldap/schema/05rfc2247.ldif
new file mode 100644
index 00000000..b566cfaa
--- /dev/null
+++ b/ldap/schema/05rfc2247.ldif
@@ -0,0 +1,19 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema from RFC 2247 and related pilot schema
+# "Using Domains in LDAP/X.500 Distinguished Names"
+#
+dn: cn=schema
+attributeTypes: ( 0.9.2342.19200300.100.1.25 NAME ( 'dc' 'domaincomponent' ) DESC 'Standard LDAP attribute type' EQUALITY caseIgnoreIA5Match SUBSTR caseIgnoreIA5SubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2247' )
+attributeTypes: ( 0.9.2342.19200300.100.1.26 NAME 'dNSRecord' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Internet directory pilot' )
+attributeTypes: ( 0.9.2342.19200300.100.1.38 NAME 'associatedName' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'RFC 1274' )
+objectClasses: ( 1.3.6.1.4.1.1466.344 NAME 'dcObject' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MUST dc X-ORIGIN 'RFC 2247' )
+objectClasses: ( 0.9.2342.19200300.100.4.13 NAME 'domain' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST dc MAY ( associatedName $ businessCategory $ description $ destinationIndicator $ facsimileTelephoneNumber $ internationaliSDNNumber $ l $ o $ physicalDeliveryOfficeName $ postOfficeBox $ postalAddress $ postalCode $ preferredDeliveryMethod $ registeredAddress $ searchGuide $ seeAlso $ st $ street $ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $ userPassword $ x121Address ) X-ORIGIN 'RFC 2247' )
+objectClasses: ( 0.9.2342.19200300.100.4.14 NAME 'RFC822localPart' DESC 'Pilot objectclass' SUP domain MAY ( cn $ sn ) X-ORIGIN 'Internet directory pilot' )
+objectClasses: ( 0.9.2342.19200300.100.4.15 NAME 'DNSDomain' DESC 'Pilot objectclass' SUP domain MAY dNSRecord X-ORIGIN 'Internet directory pilot' )
diff --git a/ldap/schema/05rfc2927.ldif b/ldap/schema/05rfc2927.ldif
new file mode 100644
index 00000000..c999890f
--- /dev/null
+++ b/ldap/schema/05rfc2927.ldif
@@ -0,0 +1,19 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema from RFC 2927
+# "MIME Directory Profile for LDAP Schema"
+#
+# DS 6.0 does not yet support the LDAP Schema Definition syntax definition
+# ( 1.3.6.1.4.1.1466.115.121.1.56 DESC 'LDAP Schema Definition' )
+# so in the interim this is replaced by a unstructured string.
+#
+dn: cn=schema
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.17 NAME 'ldapSchemas'
+ SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 USAGE directoryOperation
+ X-ORIGIN 'RFC 2927' )
diff --git a/ldap/schema/10presence.ldif b/ldap/schema/10presence.ldif
new file mode 100644
index 00000000..52aad52d
--- /dev/null
+++ b/ldap/schema/10presence.ldif
@@ -0,0 +1,25 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for representing Instant Messaging presence status
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.2013 NAME 'nsAIMid' DESC 'Netscape defined attribute type' SYNTAX 2.16.840.1.113730.3.7.1 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2014 NAME 'nsICQid' DESC 'Netscape defined attribute type' SYNTAX 2.16.840.1.113730.3.7.1 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2015 NAME 'nsYIMid' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2016 NAME 'nsMSNid' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2017 NAME 'nsAIMStatusText' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2018 NAME 'nsAIMStatusGraphic' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2019 NAME 'nsYIMStatusText' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2020 NAME 'nsYIMStatusGraphic' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2021 NAME 'nsICQStatusText' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2022 NAME 'nsICQStatusGraphic' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE NO-USER-MODIFICATION USAGE directoryOperation X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.300 NAME 'nsAIMpresence' DESC 'Netscape defined objectclass' SUP top AUXILIARY MAY ( nsAIMid $ nsAIMStatusGraphic $ nsAIMStatusText ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.301 NAME 'nsICQpresence' DESC 'Netscape defined objectclass' SUP top AUXILIARY MAY ( nsICQid $ nsICQStatusGraphic $ nsICQStatusText ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.302 NAME 'nsYIMpresence' DESC 'Netscape defined objectclass' SUP top AUXILIARY MAY ( nsYIMid $ nsYIMStatusGraphic $ nsYIMStatusText ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.303 NAME 'nsMSNpresence' DESC 'Netscape defined objectclass' SUP top AUXILIARY MAY ( nsMSNid ) X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/schema/10rfc2307.ldif b/ldap/schema/10rfc2307.ldif
new file mode 100644
index 00000000..9a0dfc2a
--- /dev/null
+++ b/ldap/schema/10rfc2307.ldif
@@ -0,0 +1,54 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema from RFC 2307
+# "An Approach for Using LDAP as a Network Information Service"
+#
+dn: cn=schema
+attributeTypes: ( 1.3.6.1.1.1.1.0 NAME 'uidNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.1 NAME 'gidNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.2 NAME 'gecos' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.3 NAME 'homeDirectory' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.4 NAME 'loginShell' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.5 NAME 'shadowLastChange' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.6 NAME 'shadowMin' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.7 NAME 'shadowMax' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.8 NAME 'shadowWarning' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.9 NAME 'shadowInactive' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.10 NAME 'shadowExpire' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.11 NAME 'shadowFlag' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.12 NAME 'memberUid' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.13 NAME 'memberNisNetgroup' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.14 NAME 'nisNetgroupTriple' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.15 NAME 'ipServicePort' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.16 NAME 'ipServiceProtocol' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.17 NAME 'ipProtocolNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.18 NAME 'oncRpcNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.19 NAME 'ipHostNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.20 NAME 'ipNetworkNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.21 NAME 'ipNetmaskNumber' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.22 NAME 'macAddress' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.23 NAME 'bootParameter' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.24 NAME 'bootFile' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.25 NAME 'automountInformation' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.26 NAME 'nisMapName' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2307' )
+attributeTypes: ( 1.3.6.1.1.1.1.27 NAME 'nisMapEntry' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.0 NAME 'posixAccount' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MUST ( cn $ uid $ uidNumber $ gidNumber $ homeDirectory ) MAY ( userPassword $ loginShell $ gecos $ description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.1 NAME 'shadowAccount' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MUST uid MAY ( userPassword $ shadowLastChange $ shadowMin $ shadowMax $ shadowWarning $ shadowInactive $ shadowExpire $ shadowFlag $ description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.2 NAME 'posixGroup' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST ( cn $ gidNumber ) MAY ( userPassword $ memberUid $ description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.3 NAME 'ipService' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST ( cn $ ipServicePort $ ipServiceProtocol ) MAY ( description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.4 NAME 'ipProtocol' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST ( cn $ ipProtocolNumber ) MAY ( description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.5 NAME 'oncRpc' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST ( cn $ oncRpcNumber ) MAY ( description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.6 NAME 'ipHost' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MUST ( ipHostNumber $ cn ) MAY ( manager $ description $ l $ o $ ou $ owner $ seeAlso $ serialNumber ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.7 NAME 'ipNetwork' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST ( ipNetworkNumber $ cn ) MAY ( ipNetmaskNumber $ manager $ l $ description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.8 NAME 'nisNetgroup' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST cn MAY ( nisNetgroupTriple $ memberNisNetgroup $ description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.9 NAME 'automount' DESC 'Standard LDAP objectclass' SUP top MUST ( cn $ automountInformation ) MAY ( description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.10 NAME 'nisObject' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST ( cn $ nisMapEntry $ nisMapName ) MAY ( description ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.11 NAME 'ieee802Device' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MUST cn MAY ( macAddress $ description $ l $ o $ ou $ owner $ seeAlso $ serialNumber ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.12 NAME 'bootableDevice' DESC 'Standard LDAP objectclass' SUP top AUXILIARY MUST cn MAY ( bootFile $ bootParameter $ description $ l $ o $ ou $ owner $ seeAlso $ serialNumber ) X-ORIGIN 'RFC 2307' )
+objectClasses: ( 1.3.6.1.1.1.2.13 NAME 'nisMap' DESC 'Standard LDAP objectclass' SUP top STRUCTURAL MUST ( nisMapName ) MAY ( description ) X-ORIGIN 'RFC 2307' )
diff --git a/ldap/schema/20subscriber.ldif b/ldap/schema/20subscriber.ldif
new file mode 100644
index 00000000..5c679e3d
--- /dev/null
+++ b/ldap/schema/20subscriber.ldif
@@ -0,0 +1,32 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Common schema elements for Netscape-Nortel subscriber interoperability
+# Last modified September 2000
+#
+# The nsManagedPerson object class is located in the Netscape Delegated
+# Administrator schema file.
+#
+dn: cn=schema
+attributetypes: ( 1.2.840.113556.1.2.102 NAME 'memberOf' DESC 'Group that the entry belongs to' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Delegated Administrator' )
+attributetypes: ( 2.16.840.1.113730.3.1.601 NAME 'adminRole' DESC 'Administrative role' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Delegated Administrator' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.41 NAME 'parentOrganization' EQUALITY distinguishedNameMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.42 NAME 'preferredLocale' DESC 'preferred locale for a person' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape' )
+attributeTypes: ( 1.3.6.1.4.1.1466.101.120.43 NAME 'preferredTimeZone' DESC 'preferred time zone for a person' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreSubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape' )
+attributeTypes: ( 2.16.840.1.113730.3.1.690 NAME 'inetDomainBaseDN' DESC 'Base DN of user subtree for a DNS domain' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape subscriber interoperability' )
+attributeTypes: ( 2.16.840.1.113730.3.1.691 NAME 'inetDomainStatus' DESC '"active", "inactive", or "deleted" status of a domain' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape subscriber interoperability' )
+attributeTypes: ( 2.16.840.1.113730.3.1.692 NAME 'inetUserStatus' DESC '"active", "inactive", or "deleted" status of a user' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape subscriber interoperability' )
+attributeTypes: ( 2.16.840.1.113730.3.1.693 NAME 'inetUserHttpURL' DESC 'A users Web addresses' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape subscriber interoperability' )
+attributeTypes: ( 2.16.840.1.113730.3.1.694 NAME 'inetSubscriberAccountId' DESC 'A unique attribute linking the subscriber to a billing system' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape subscriber interoperability' )
+attributeTypes: ( 2.16.840.1.113730.3.1.695 NAME 'inetSubscriberChallenge' DESC 'Used to confirm subscriberIdentity. This attribute holds the challenge phrase and is used in conjunction with the inetSubscriberResponse' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape subscriber interoperability' )
+attributeTypes: ( 2.16.840.1.113730.3.1.696 NAME 'inetSubscriberResponse' DESC 'Used to confirm subscriberIdentity. This attribute holds the response phrase and is used in conjunction with the inetSubscriberChallenge' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape subscriber interoperability' )
+objectClasses: ( 2.16.840.1.113730.3.2.129 NAME 'inetDomain' DESC 'Auxiliary class for virtual domain nodes' SUP top AUXILIARY MAY ( inetDomainBaseDN $ inetDomainStatus ) X-ORIGIN 'Netscape subscriber interoperability' )
+objectClasses: ( 2.16.840.1.113730.3.2.130 NAME 'inetUser' DESC 'Auxiliary class which must be present in an entry for delivery of subscriber services' SUP top AUXILIARY MAY ( uid $ inetUserStatus $ inetUserHTTPURL $ userPassword $ memberOf ) X-ORIGIN 'Netscape subscriber interoperability' )
+objectClasses: ( 1.3.6.1.4.1.1466.101.120.141 NAME 'NetscapeLinkedOrganization' AUXILIARY MAY parentOrganization X-ORIGIN 'Netscape' )
+objectClasses: ( 1.3.6.1.4.1.1466.101.120.142 NAME 'NetscapePreferences' AUXILIARY MAY ( preferredLanguage $ preferredLocale $ preferredTimeZone ) X-ORIGIN 'Netscape' )
+objectClasses: ( 2.16.840.1.113730.3.2.134 NAME 'inetSubscriber' SUP top AUXILIARY MAY ( inetSubscriberAccountId $ inetSubscriberChallenge $ inetSubscriberResponse ) X-ORIGIN 'Netscape subscriber interoperability' )
+objectclasses: ( 2.16.840.1.113730.3.2.112 NAME 'inetAdmin' DESC 'Marker for an administrative group or user' SUP top AUXILIARY MUST ( objectclass ) MAY ( aci $ memberof $ adminrole ) X-ORIGIN 'Netscape Delegated Administrator' )
diff --git a/ldap/schema/25java-object.ldif b/ldap/schema/25java-object.ldif
new file mode 100644
index 00000000..5ecf2d3d
--- /dev/null
+++ b/ldap/schema/25java-object.ldif
@@ -0,0 +1,24 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema from RFC 2713
+# "Schema for Representing Java(tm) Objects in an LDAP Directory"
+#
+dn: cn=schema
+attributeTypes: ( 1.3.6.1.4.1.42.2.27.4.1.6 NAME 'javaClassName' DESC 'Fully qualified name of distinguished Java class or interface' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2713' )
+attributeTypes: ( 1.3.6.1.4.1.42.2.27.4.1.7 NAME 'javaCodebase' DESC 'URL(s) specifying the location of class definition' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2713' )
+attributeTypes: ( 1.3.6.1.4.1.42.2.27.4.1.8 NAME 'javaSerializedData' DESC 'Serialized form of a Java object' SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 SINGLE-VALUE X-ORIGIN 'RFC 2713' )
+attributeTypes: ( 1.3.6.1.4.1.42.2.27.4.1.10 NAME 'javaFactory' DESC 'Fully qualified Java class name of a JNDI object factory' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 2713' )
+attributeTypes: ( 1.3.6.1.4.1.42.2.27.4.1.11 NAME 'javaReferenceAddress' DESC 'Addresses associated with a JNDI Reference' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2713' )
+attributeTypes: ( 1.3.6.1.4.1.42.2.27.4.1.12 NAME 'javaDoc' DESC 'The Java documentation for the class' EQUALITY caseExactIA5Match SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'RFC 2713' )
+attributeTypes: ( 1.3.6.1.4.1.42.2.27.4.1.13 NAME 'javaClassNames' DESC 'Fully qualified Java class or interface name' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2713' )
+objectClasses: ( 1.3.6.1.4.1.42.2.27.4.2.1 NAME 'javaContainer' DESC 'Container for a Java object' SUP top STRUCTURAL MUST ( cn ) X-ORIGIN 'RFC 2713' )
+objectClasses: ( 1.3.6.1.4.1.42.2.27.4.2.4 NAME 'javaObject' DESC 'Java object representation' SUP top ABSTRACT MUST ( javaClassName ) MAY ( javaClassNames $ javaCodebase $ javaDoc $ description ) X-ORIGIN 'RFC 2713' )
+objectClasses: ( 1.3.6.1.4.1.42.2.27.4.2.5 NAME 'javaSerializedObject' DESC 'Java serialized object' SUP javaObject AUXILIARY MUST ( javaSerializedData ) X-ORIGIN 'RFC 2713' )
+objectClasses: ( 1.3.6.1.4.1.42.2.27.4.2.7 NAME 'javaNamingReference' DESC 'JNDI reference' SUP javaObject AUXILIARY MAY ( javaReferenceAddress $ javaFactory ) X-ORIGIN 'RFC 2713' )
+objectClasses: ( 1.3.6.1.4.1.42.2.27.4.2.8 NAME 'javaMarshalledObject' DESC 'Java marshalled object' SUP javaObject AUXILIARY MUST ( javaSerializedData ) X-ORIGIN 'RFC 2713' )
diff --git a/ldap/schema/28pilot.ldif b/ldap/schema/28pilot.ldif
new file mode 100644
index 00000000..d4dcbf8e
--- /dev/null
+++ b/ldap/schema/28pilot.ldif
@@ -0,0 +1,62 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema from the pilot RFCs, especially RFC 1274, that is no longer
+# recommended by Netscape for use in new deployments. Please be aware
+# that future RFCs that succeed RFC 1274 may deprecate some or all of
+# these attribute types and classes.
+#
+dn: cn=schema
+attributeTypes: ( 0.9.2342.19200300.100.1.48 NAME 'buildingName' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.40 NAME 'personalTitle' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.37 NAME 'associatedDomain' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.22 NAME 'otherMailbox' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.102.1.9 NAME 'abstract' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.102.1.11 NAME ( 'authorCn' 'documentauthorcommonname' ) DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.102.1.12 NAME ( 'authorSn' 'documentauthorsurname' ) DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.100.1.54 NAME 'ditRedirect' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.11 NAME 'documentIdentifier' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.12 NAME 'documentTitle' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.13 NAME 'documentVersion' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.14 NAME 'documentAuthor' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.15 NAME 'documentLocation' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.56 NAME 'documentPublisher' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.102.1.10 NAME 'documentStore' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.100.1.5 NAME ( 'drink' 'favouriteDrink' ) DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.49 NAME 'dSAQuality' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.46 NAME 'janetMailbox' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.102.1.7 NAME 'keyWords' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.100.1.24 NAME 'lastModifiedBy' DESC 'old variant of modifiersName' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.23 NAME 'lastModifiedTime' DESC 'old variant of modifyTimestamp' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.47 NAME 'mailPreferenceOption' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.102.1.4 NAME 'obsoletedByDocument' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.102.1.3 NAME 'obsoletesDocument' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.100.1.45 NAME 'organizationalStatus' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.53 NAME 'personalSignature' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 2.6.6.5.2.4.10 NAME 'reciprocalNamingLink' DESC 'NADF attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'North American Directory Forum (NADF)' )
+attributeTypes: ( 0.9.2342.19200300.100.1.50 NAME 'singleLevelQuality' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.102.1.8 NAME 'subject' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.100.1.51 NAME 'subtreeMinimumQuality' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.52 NAME 'subtreeMaximumQuality' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.2 NAME 'textEncodedORAddress' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.102.1.6 NAME 'updatedByDocument' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.102.1.5 NAME 'updatesDocument' DESC 'Pilot attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Internet White Pages Pilot' )
+attributeTypes: ( 0.9.2342.19200300.100.1.44 NAME 'uniqueIdentifier' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.4 NAME 'info' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.8 NAME 'userClass' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+attributeTypes: ( 0.9.2342.19200300.100.1.9 NAME 'host' DESC 'Standard LDAP attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 1274' )
+objectClasses: ( 0.9.2342.19200300.100.4.3 NAME 'pilotObject' DESC 'Standard LDAP objectclass' SUP top MAY ( audio $ dITRedirect $ info $ jpegPhoto $ lastModifiedBy $ lastModifiedTime $ manager $ photo $ uniqueIdentifier ) X-ORIGIN 'RFC 1274' )
+objectClasses: ( 0.9.2342.19200300.100.4.4 NAME 'newPilotPerson' DESC 'Pilot objectclass' SUP person MAY ( businessCategory $ drink $ homePhone $ homePostalAddress $ janetMailbox $ mail $ mailPreferenceOption $ mobile $ organizationalStatus $ otherMailbox $ pager $ personalSignature $ personalTitle $ preferredDeliveryMethod $ roomNumber $ secretary $ textEncodedORAddress $ uid $ userClass ) X-ORIGIN 'Internet White Pages Pilot' )
+objectClasses: ( 0.9.2342.19200300.100.4.5 NAME 'account' DESC 'Standard LDAP objectclass' SUP top MUST ( uid ) MAY ( description $ host $ l $ o $ ou $ seeAlso ) X-ORIGIN 'RFC 1274' )
+objectClasses: ( 0.9.2342.19200300.100.4.6 NAME 'document' DESC 'Standard LDAP objectclass' SUP pilotObject MUST ( documentIdentifier ) MAY ( abstract $ authorCN $ authorSN $ cn $ description $ documentAuthor $ documentLocation $ documentPublisher $ documentStore $ documentTitle $ documentVersion $ keywords $ l $ o $ obsoletedByDocument $ obsoletesDocument $ ou $ seeAlso $ subject $ updatedByDocument $ updatesDocument ) X-ORIGIN 'RFC 1274' )
+objectClasses: ( 0.9.2342.19200300.100.4.7 NAME 'room' DESC 'Standard LDAP objectclass' SUP top MUST ( cn ) MAY ( description $ roomNumber $ seeAlso $ telephoneNumber ) X-ORIGIN 'RFC 1274' )
+objectClasses: ( 0.9.2342.19200300.100.4.9 NAME 'documentSeries' DESC 'Standard LDAP objectclass' SUP top MUST ( cn ) MAY ( description $ l $ o $ ou $ seeAlso $ telephoneNumber ) X-ORIGIN 'RFC 1274' )
+objectClasses: ( 0.9.2342.19200300.100.4.17 NAME 'domainRelatedObject' DESC 'Standard LDAP objectclass' SUP top MUST ( associatedDomain ) X-ORIGIN 'RFC 1274' )
+objectClasses: ( 0.9.2342.19200300.100.4.18 NAME 'friendlyCountry' DESC 'Standard LDAP objectclass' SUP country MUST ( co ) X-ORIGIN 'RFC 1274' )
+objectClasses: ( 0.9.2342.19200300.100.4.19 NAME 'simpleSecurityObject' DESC 'Standard LDAP objectclass' SUP top MUST ( userPassword ) X-ORIGIN 'RFC 1274' )
+objectClasses: ( 0.9.2342.19200300.100.4.20 NAME 'pilotOrganization' DESC 'Standard LDAP objectclass' SUP top MUST ( ou $ o ) MAY ( buildingName $ businessCategory $ description $ destinationIndicator $ facsimileTelephoneNumber $ internationaliSDNNumber $ l $ physicalDeliveryOfficeName $ postOfficeBox $ postalAddress $ postalCode $ preferredDeliveryMethod $ registeredAddress $ searchGuide $ seeAlso $ st $ street $ telephoneNumber $ teletexTerminalIdentifier $ telexNumber $ userPassword $ x121Address ) X-ORIGIN 'RFC 1274' )
diff --git a/ldap/schema/30ns-common.ldif b/ldap/schema/30ns-common.ldif
new file mode 100644
index 00000000..d480e732
--- /dev/null
+++ b/ldap/schema/30ns-common.ldif
@@ -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
+#
+#
+# Common Netscape schema.
+#
+dn: cn=schema
+attributeTypes: ( nsServerID-oid NAME 'nsServerID' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsBaseDN-oid NAME 'nsBaseDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsBindDN-oid NAME 'nsBindDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsBindPassword-oid NAME 'nsBindPassword' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsServerPort-oid NAME 'nsServerPort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsServerAddress-oid NAME 'nsServerAddress' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsDirectoryInfoRef-oid NAME 'nsDirectoryInfoRef' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsDirectoryURL-oid NAME 'nsDirectoryURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsDirectoryFailoverList-oid NAME 'nsDirectoryFailoverList' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsAdminDomainName-oid NAME 'nsAdminDomainName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsHostLocation-oid NAME 'nsHostLocation' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsHardwarePlatform-oid NAME 'nsHardwarePlatform' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsOsVersion-oid NAME 'nsOsVersion' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsAdminGroupName-oid NAME 'nsAdminGroupName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsConfigRoot-oid NAME 'nsConfigRoot' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsAdminSIEDN-oid NAME 'nsAdminSIEDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsVendor-oid NAME 'nsVendor' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsProductName-oid NAME 'nsProductName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsNickName-oid NAME 'nsNickName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsProductVersion-oid NAME 'nsProductVersion' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsBuildNumber-oid NAME 'nsBuildNumber' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsRevisionNumber-oid NAME 'nsRevisionNumber' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSerialNumber-oid NAME 'nsSerialNumber' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsInstalledLocation-oid NAME 'nsInstalledLocation' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsExpirationDate-oid NAME 'nsExpirationDate' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsBuildSecurity-oid NAME 'nsBuildSecurity' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsServerMigrationClassname-oid NAME 'nsServerMigrationClassname' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsServerCreationClassname-oid NAME 'nsServerCreationClassname' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsLdapSchemaVersion-oid NAME 'nsLdapSchemaVersion' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSuiteSpotUser-oid NAME 'nsSuiteSpotUser' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsErrorLog-oid NAME 'nsErrorLog' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsPidLog-oid NAME 'nsPidLog' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsAccessLog-oid NAME 'nsAccessLog' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsDefaultAcceptLanguage-oid NAME 'nsDefaultAcceptLanguage' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsServerSecurity-oid NAME 'nsServerSecurity' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsCertfile-oid NAME 'nsCertfile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsKeyfile-oid NAME 'nsKeyfile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSL2-oid NAME 'nsSSL2' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSL3-oid NAME 'nsSSL3' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSLClientAuth-oid NAME 'nsSSLClientAuth' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSLSessionTimeout-oid NAME 'nsSSLSessionTimeout' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSL3SessionTimeout-oid NAME 'nsSSL3SessionTimeout' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSL2Ciphers-oid NAME 'nsSSL2Ciphers' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSL3Ciphers-oid NAME 'nsSSL3Ciphers' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSLSupportedCiphers-oid NAME 'nsSSLSupportedCiphers' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSLToken-oid NAME 'nsSSLToken' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSLPersonalitySSL-oid NAME 'nsSSLPersonalitySSL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsSSLActivation-oid NAME 'nsSSLActivation' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsTaskLabel-oid NAME 'nsTaskLabel' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsHelpRef-oid NAME 'nsHelpRef' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsExecRef-oid NAME 'nsExecRef' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsLogSuppress-oid NAME 'nsLogSuppress' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsJarfilename-oid NAME 'nsJarfilename' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+attributeTypes: ( nsClassname-oid NAME 'nsClassname' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape' )
+objectClasses: ( nsAdminDomain-oid NAME 'nsAdminDomain' DESC 'Netscape defined objectclass' SUP organizationalUnit MAY ( nsAdminDomainName ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsHost-oid NAME 'nsHost' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( serverHostName $ description $ l $ nsHostLocation $ nsHardwarePlatform $ nsOsVersion ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsAdminGroup-oid NAME 'nsAdminGroup' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsAdminGroupName $ description $ nsConfigRoot $ nsAdminSIEDN ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsApplication-oid NAME 'nsApplication' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsVendor $ description $ nsProductName $ nsNickName $ nsProductVersion $ nsBuildNumber $ nsRevisionNumber $ nsSerialNumber $ nsInstalledLocation $ installationTimeStamp $ nsExpirationDate $ nsBuildSecurity $ nsLdapSchemaVersion $ nsServerMigrationClassname $ nsServerCreationClassname ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsEncryptionConfig-oid NAME 'nsEncryptionConfig' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsCertfile $ nsKeyfile $ nsSSL2 $ nsSSL3 $ nsSSLSessionTimeout $ nsSSL3SessionTimeout $ nsSSLClientAuth $ nsSSL2Ciphers $ nsSSL3Ciphers $ nsSSLSupportedCiphers) X-ORIGIN 'Netscape' )
+objectClasses: ( nsEncryptionModule-oid NAME 'nsEncryptionModule' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsSSLToken $ nsSSLPersonalityssl $ nsSSLActivation ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsResourceRef-oid NAME 'nsResourceRef' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( seeAlso ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsTask-oid NAME 'nsTask' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsTaskLabel $ nsHelpref $ nsExecref $ nsLogSuppress ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsTaskGroup-oid NAME 'nsTaskGroup' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsTaskLabel ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsAdminObject-oid NAME 'nsAdminObject' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsJarFilename $ nsClassName ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsConfig-oid NAME 'nsConfig' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( description $ nsServerPort $ nsServerAddress $ nsSuiteSpotUser $ nsErrorLog $ nsPidLog $ nsAccessLog $ nsDefaultAcceptLanguage $ nsServerSecurity ) X-ORIGIN 'Netscape' )
+objectClasses: ( nsDirectoryInfo-oid NAME 'nsDirectoryInfo' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsBindDN $ nsBindPassword $ nsDirectoryURL $ nsDirectoryFailoverList $ nsDirectoryInfoRef ) X-ORIGIN 'Netscape' )
diff --git a/ldap/schema/50ns-admin.ldif b/ldap/schema/50ns-admin.ldif
new file mode 100644
index 00000000..3b849709
--- /dev/null
+++ b/ldap/schema/50ns-admin.ldif
@@ -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
+#
+#
+# Schema used by Netscape Administration Services
+#
+dn: cn=schema
+attributeTypes: ( nsAdminCgiWaitPid-oid NAME 'nsAdminCgiWaitPid' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsAdminUsers-oid NAME 'nsAdminUsers' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsAdminAccessHosts-oid NAME 'nsAdminAccessHosts' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsAdminAccessAddresses-oid NAME 'nsAdminAccessAddresses' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsAdminOneACLDir-oid NAME 'nsAdminOneACLDir' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsAdminEnableDSGW-oid NAME 'nsAdminEnableDSGW' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsAdminEnableEnduser-oid NAME 'nsAdminEnableEnduser' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsAdminCacheLifetime-oid NAME 'nsAdminCacheLifetime' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsAdminAccountInfo-oid NAME 'nsAdminAccountInfo' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsDeleteclassname-oid NAME 'nsDeleteclassname' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsAdminEndUserHTMLIndex-oid NAME 'nsAdminEndUserHTMLIndex' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsUniqueAttribute-oid NAME 'nsUniqueAttribute' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsUserIDFormat-oid NAME 'nsUserIDFormat' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsUserRDNComponent-oid NAME 'nsUserRDNComponent' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsGroupRDNComponent-oid NAME 'nsGroupRDNComponent' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsWellKnownJarfiles-oid NAME 'nsWellKnownJarfiles' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsNYR-oid NAME 'nsNYR' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsDefaultObjectClass-oid NAME 'nsDefaultObjectClass' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsPreference-oid NAME 'nsPreference' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsDisplayName-oid NAME 'nsDisplayName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+attributeTypes: ( nsViewConfiguration-oid NAME 'nsViewConfiguration' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsAdminServer-oid NAME 'nsAdminServer' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsServerID ) MAY ( description ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsAdminConfig-oid NAME 'nsAdminConfig' DESC 'Netscape defined objectclass' SUP nsConfig MAY ( nsAdminCgiWaitPid $ nsAdminUsers $ nsAdminAccessHosts $ nsAdminAccessAddresses $ nsAdminOneACLDir $ nsAdminEnableDSGW $ nsAdminEnableEnduser $ nsAdminCacheLifetime ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsAdminResourceEditorExtension-oid NAME 'nsAdminResourceEditorExtension' DESC 'Netscape defined objectclass' SUP nsAdminObject MUST ( cn ) MAY ( nsAdminAccountInfo $ nsDeleteclassname ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsAdminGlobalParameters-oid NAME 'nsAdminGlobalParameters' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsAdminEndUserHTMLIndex $ nsNickname ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsGlobalParameters-oid NAME 'nsGlobalParameters' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsUniqueAttribute $ nsUserIDFormat $ nsUserRDNComponent $ nsGroupRDNComponent $ nsWellKnownJarFiles $ nsNYR ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsDefaultObjectClasses-oid NAME 'nsDefaultObjectClasses' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsDefaultObjectClass ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsAdminConsoleUser-oid NAME 'nsAdminConsoleUser' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( nsPreference ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsCustomView-oid NAME 'nsCustomView' DESC 'Netscape defined objectclass' SUP nsAdminObject MAY ( nsDisplayName ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsTopologyCustomView-oid NAME 'nsTopologyCustomView' DESC 'Netscape defined objectclass' SUP nsCustomView MUST ( cn ) MAY ( nsViewConfiguration ) X-ORIGIN 'Netscape Administration Services' )
+objectClasses: ( nsTopologyPlugin-oid NAME 'nsTopologyPlugin' DESC 'Netscape defined objectclass' SUP nsAdminObject X-ORIGIN 'Netscape Administration Services' )
diff --git a/ldap/schema/50ns-calendar.ldif b/ldap/schema/50ns-calendar.ldif
new file mode 100644
index 00000000..ae579bdd
--- /dev/null
+++ b/ldap/schema/50ns-calendar.ldif
@@ -0,0 +1,40 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Netscape Calendar Server schema.
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.112 NAME 'nsCalAccess' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.113 NAME 'nsCalAccessDomain' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.114 NAME 'nsCalAdmd' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.115 NAME 'nsCalDefaultNoteReminder' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.116 NAME 'nsCalDefaultReminder' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.117 NAME 'nsCalDefaultTaskReminder' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.118 NAME 'nsCalDisplayPrefs' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.119 NAME 'nsCalFlags' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.120 NAME 'nsCalHost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.121 NAME 'nsCalLanguageId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.122 NAME 'nsCalNodeAlias' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.123 NAME 'nsCalNotifMechanism' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.124 NAME 'nsCalOperatingPrefs' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.125 NAME 'nsCalOrgUnit2' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.126 NAME 'nsCalOrgUnit3' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.127 NAME 'nsCalOrgUnit4' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.128 NAME 'nsCalPasswordRequired' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.129 NAME 'nsCalPrmd' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.130 NAME 'nsCalRefreshPrefs' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.131 NAME 'nsCalResourceCapacity' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.132 NAME 'nsCalResourceNumber' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.133 NAME 'nsCalServerVersion' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.134 NAME 'nsCalSysopCanWritePassword' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.135 NAME 'nsCalTimezone' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.136 NAME 'nsCalXItemId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.14 NAME 'nsCalUser' DESC 'Netscape defined objectclass' SUP top MUST ( objectClass ) MAY ( c $ employeeNumber $ generationQualifier $ givenName $ initials $ mail $ o $ ou $ nsCalAccess $ nsCalAccessDomain $ nsCalAdmd $ nsCalDefaultNoteReminder $ nsCalDefaultReminder $ nsCalDefaultTaskReminder $ nsCalDisplayPrefs $ nsCalFlags $ nsCalHost $ nsCalLanguageId $ nsCalNodeAlias $ nsCalNotifMechanism $ nsCalOperatingPrefs $ nsCalOrgUnit2 $ nsCalOrgUnit3 $ nsCalOrgUnit4 $ nsCalPasswordRequired $ nsCalPrmd $ nsCalRefreshPrefs $ nsCalServerVersion $ nsCalSysopCanWritePassword $ nsCalTimezone $ nsCalXItemId ) X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.15 NAME 'nsCalAdmin' DESC 'Netscape defined objectclass' SUP top MUST ( objectClass ) MAY ( c $ cn $ facsimileTelephoneNumber $ generationQualifier $ givenName $ initials $ mail $ o $ ou $ postalAddress $ sn $ telephoneNumber $ userPassword $ nsCalAccess $ nsCalAccessDomain $ nsCalAdmd $ nsCalFlags $ nsCalHost $ nsCalLanguageId $ nsCalNodeAlias $ nsCalOrgUnit2 $ nsCalOrgUnit3 $ nsCalOrgUnit4 $ nsCalPasswordRequired $ nsCalPrmd $ nsCalServerVersion $ nsCalSysopCanWritePassword $ nsCalXItemId ) X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.16 NAME 'nsCalResource' DESC 'Netscape defined objectclass' SUP top MUST ( objectClass ) MAY ( cn $ facsimileTelephoneNumber $ givenName $ mail $ postalAddress $ sn $ telephoneNumber $ userPassword $ nsCalAccess $ nsCalAccessDomain $ nsCalDefaultNoteReminder $ nsCalDefaultReminder $ nsCalDefaultTaskReminder $ nsCalDisplayPrefs $ nsCalFlags $ nsCalHost $ nsCalLanguageId $ nsCalNodeAlias $ nsCalNotifMechanism $ nsCalOperatingPrefs $ nsCalPasswordRequired $ nsCalRefreshPrefs $ nsCalResourceCapacity $ nsCalResourceNumber $ nsCalServerVersion $ nsCalSysopCanWritePassword $ nsCalTimezone $ nsCalXItemId ) X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.17 NAME 'netscapeCalendarServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) X-ORIGIN 'Netscape Calendar Server' )
diff --git a/ldap/schema/50ns-certificate.ldif b/ldap/schema/50ns-certificate.ldif
new file mode 100644
index 00000000..8cb7b595
--- /dev/null
+++ b/ldap/schema/50ns-certificate.ldif
@@ -0,0 +1,14 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for Netscape Certificate Management System
+#
+dn: cn=schema
+attributeTypes: ( nsCertConfig-oid NAME 'nsCertConfig' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Certificate Management System' )
+objectClasses: ( 2.16.840.1.113730.3.2.18 NAME 'netscapeCertificateServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) X-ORIGIN 'Netscape Certificate Management System' )
+objectClasses: ( nsCertificateServer-oid NAME 'nsCertificateServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass $ nsServerID ) MAY ( serverHostName $ nsServerPort $ nsCertConfig ) X-ORIGIN 'Netscape Certificate Management System' )
diff --git a/ldap/schema/50ns-compass.ldif b/ldap/schema/50ns-compass.ldif
new file mode 100644
index 00000000..9b3c17ea
--- /dev/null
+++ b/ldap/schema/50ns-compass.ldif
@@ -0,0 +1,69 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for the Netscape Compass Server
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.137 NAME 'pipuid' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.138 NAME 'pipcompassservers' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.139 NAME 'pipuniqueid' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.140 NAME 'pipstatus' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.141 NAME 'pipusertype' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.142 NAME 'pipfrequency' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.143 NAME 'pipmedium' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.144 NAME 'pipformat' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.145 NAME 'piphour' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.146 NAME 'pipmaxhits' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.147 NAME 'pipresultset' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.148 NAME 'pipsortorder' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.149 NAME 'piptimestamp' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.150 NAME 'pipirlist' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.151 NAME 'pipiroption' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.152 NAME 'pippwp' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.153 NAME 'piplastcount' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.154 NAME 'piptotalcount' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.155 NAME 'piptotalrun' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.156 NAME 'pipnotify' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.157 NAME 'pipprivilege' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.158 NAME 'pipgroup' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.159 NAME 'pipidstcount' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.160 NAME 'pipstid' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.161 NAME 'pipstname' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.162 NAME 'pipstquery' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.163 NAME 'pipsttaxonomy' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.164 NAME 'pipstinterest' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.165 NAME 'pipsttype' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.166 NAME 'pipstprivacy' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.167 NAME 'pipststatus' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.168 NAME 'pipstlastcount' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.169 NAME 'pipsttotalcount' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.170 NAME 'pipsttotalrun' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.171 NAME 'pipstcategory' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.172 NAME 'pipstfrequency' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.173 NAME 'pipstmedium' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.174 NAME 'pipstformat' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.175 NAME 'pipsthour' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.176 NAME 'pipstmaxhits' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.177 NAME 'pipstresultset' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.178 NAME 'pipstsortorder' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.179 NAME 'pipsttimestamp' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.180 NAME 'pipstirlist' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.181 NAME 'pipstiroption' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.182 NAME 'pipreservedcis1' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.183 NAME 'pipreservedcis2' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.184 NAME 'pipreservedcis3' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.185 NAME 'pipreservedcis4' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.186 NAME 'pipreservedcis5' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.187 NAME 'pipreservedcis6' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.188 NAME 'pipreservedces1' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.189 NAME 'pipreservedces2' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Compass Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.190 NAME 'pipreservedces3' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Compass Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.19 NAME 'netscapeCompassServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) X-ORIGIN 'Netscape Compass Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.20 NAME 'personalInterestProfile' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass $ pipuid ) MAY ( pipuniqueid $ pipstatus $ pipusertype $ pipfrequency $ pipmedium $ pipformat $ piphour $ pipmaxhits $ pipresultset $ pipsortorder $ piptimestamp $ pipirlist $ pipiroption $ pippwp $ piplastcount $ piptotalcount $ piptotalrun $ pipnotify $ pipprivilege $ pipgroup $ pipidstcount $ pipstid $ pipstname $ pipstquery $ pipsttaxonomy $ pipstinterest $ pipsttype $ pipstprivacy $ pipststatus $ pipstlastcount $ pipsttotalcount $ pipsttotalrun $ pipstcategory $ pipstfrequency $ pipstmedium $ pipstformat $ pipsthour $ pipstmaxhits $ pipstresultset $ pipstsortorder $ pipsttimestamp $ pipstirlist $ pipstiroption $ pipreservedcis1 $ pipreservedcis2 $ pipreservedcis3 $ pipreservedcis4 $ pipreservedcis5 $ pipreservedcis6 $ pipreservedces1 $ pipreservedces2 $ pipreservedces3 ) X-ORIGIN 'Netscape Compass Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.21 NAME 'PIPUserInfo' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) MAY ( cn $ mail $ userPassword $ description $ pipcompassservers $ pipuniqueid ) X-ORIGIN 'Netscape Compass Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.22 NAME 'PIPUser' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) MAY ( pipuniqueid $ pipcompassservers $ pipreservedcis1 $ pipreservedcis2 $ pipreservedcis3 $ pipreservedcis4 $ pipreservedcis5 $ pipreservedcis6 $ pipreservedces1 $ pipreservedces2 $ pipreservedces3 ) X-ORIGIN 'Netscape Compass Server' )
diff --git a/ldap/schema/50ns-delegated-admin.ldif b/ldap/schema/50ns-delegated-admin.ldif
new file mode 100644
index 00000000..aea5bbe4
--- /dev/null
+++ b/ldap/schema/50ns-delegated-admin.ldif
@@ -0,0 +1,37 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2002 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#############################################################
+# Delegated User Administration Attributes & Objectclasses
+#############################################################
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.556 NAME ( 'nsNumDepts' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.561 NAME ( 'nsMaxDomains' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.558 NAME ( 'nsNumMailLists' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.554 NAME ( 'nsNumUsers' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.562 NAME ( 'nsDefaultMaxDeptSize' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.557 NAME ( 'nsMaxDepts' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.563 NAME ( 'nsdaCapability' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.555 NAME ( 'nsMaxUsers' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.559 NAME ( 'nsMaxMailLists' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2028 NAME ( 'nsMaxMailListsPerUser' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.601 NAME ( 'adminRole' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.560 NAME ( 'nsNumDomains' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 1.2.840.113556.1.2.102 NAME ( 'memberOf' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.565 NAME ( 'nsdaModifiableBy' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.564 NAME ( 'nsSearchFilter' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.600 NAME ( 'nsDADomain' ) DESC 'Netscape Delegated Adminstrator defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Delegated Adminstrator' )
+attributeTypes: ( 2.16.840.1.113730.3.1.712 NAME 'mnggrpStatus' DESC 'Netscape Messaging Server defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Messaging Server' )
+objectclasses: ( 2.16.840.1.113730.3.2.85 NAME 'nsManagedISP' DESC 'Delegated Admin marker for hosted root' SUP top AUXILIARY MAY ( nsNumDomains ) X-ORIGIN 'Netscape Delegated Adminstrator' )
+objectclasses: ( 2.16.840.1.113730.3.2.86 NAME 'nsManagedDomain' DESC 'Delegated Admin marker for managed domain' SUP top AUXILIARY MAY ( nsNumUsers $ nsMaxUsers $ nsNumDepts $ nsMaxDepts $ nsNumMailLists $ nsMaxMailLists $nsMaxMailListsPerUser $ nsNumDomains $ nsMaxDomains $ nsDefaultMaxDeptSize $ owner $ nsdaModifiableBy ) X-ORIGIN 'Netscape Delegated Adminstrator' )
+objectclasses: ( 2.16.840.1.113730.3.2.87 NAME 'nsManagedOrgUnit' DESC 'Delegated Admin marker for managed organizationunit' SUP top AUXILIARY MAY ( owner $ nsdaModifiableBy ) X-ORIGIN 'Netscape Delegated Adminstrator' )
+objectclasses: ( 2.16.840.1.113730.3.2.88 NAME 'nsManagedDept' DESC 'Delegated Admin marker for managed department' SUP groupOfUniqueNames AUXILIARY MAY ( nsNumUsers $ nsMaxUsers $ nsNumDepts $ nsMaxDepts $ owner $ nsdaModifiableBy ) X-ORIGIN 'Netscape Delegated Adminstrator' )
+objectclasses: ( 2.16.840.1.113730.3.2.89 NAME 'nsManagedFamilyGroup' DESC 'Delegated Admin marker for managed familygroup' SUP top AUXILIARY MAY ( nsNumUsers $ nsMaxUsers $ owner $ nsdaModifiableBy ) X-ORIGIN 'Netscape Delegated Adminstrator' )
+objectclasses: ( 2.16.840.1.113730.3.2.90 NAME 'nsManagedMailList' DESC 'Delegated Admin marker for managed mailing list' SUP top AUXILIARY MAY ( nsNumUsers $ nsMaxUsers $ owner $ nsdaModifiableBy ) X-ORIGIN 'Netscape Delegated Adminstrator' )
+objectclasses: ( 2.16.840.1.113730.3.2.91 NAME 'nsManagedPerson' DESC 'Delegated Admin marker for managed person' SUP top AUXILIARY MAY ( memberOf $ nsdaDomain $ nsdaCapability $ nsSearchFilter $ owner $ nsdaModifiableBy ) X-ORIGIN 'Netscape Delegated Adminstrator' )
+objectclasses: ( 2.16.840.1.113730.3.2.111 NAME 'nsManagedDeptAdminGroup' DESC 'Delegated Admin marker for managed department admin group' SUP top AUXILIARY X-ORIGIN 'Netscape Delegated Adminstrator' )
+objectclasses: ( 2.16.840.1.113730.3.2.115 NAME 'nsUniquenessDomain' DESC 'Delegated Admin marker for uniqueness domain' SUP top AUXILIARY X-ORIGIN 'Netscape Delegated Adminstrator' )
+objectclasses: ( 2.16.840.1.113730.3.2.307 NAME 'nsManagedDynamicGroup' DESC 'Delegated Admin marker for dynamic administrative groups' AUXILIARY MAY ( owner $ nsdamodifiableby $ mnggrpstatus ) X-ORIGIN 'Netscape Delegated Adminstrator' )
diff --git a/ldap/schema/50ns-directory.ldif b/ldap/schema/50ns-directory.ldif
new file mode 100644
index 00000000..2e44079d
--- /dev/null
+++ b/ldap/schema/50ns-directory.ldif
@@ -0,0 +1,87 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Additional schema used by Netscape Directory Server 4.x
+#
+dn: cn=schema
+attributeTypes: ( nsSecureServerPort-oid NAME 'nsSecureServerPort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.206 NAME 'filterInfo' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.48 NAME 'replicaPort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.49 NAME 'replicaUpdateFailedAt' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.50 NAME 'replicaBeginOrc' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.51 NAME 'replicaUpdateReplayed' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.52 NAME 'replicaUpdateSchedule' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.53 NAME 'replicaBindMethod' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.79 NAME 'cirReplicaRoot' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.80 NAME 'cirHost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.81 NAME 'cirPort' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.82 NAME 'cirBindDn' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.83 NAME 'cirUsePersistentSearch' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.84 NAME 'cirUseSsl' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.85 NAME 'cirBindCredentials' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.86 NAME 'cirLastUpdateApplied' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.87 NAME 'cirUpdateSchedule' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.88 NAME 'cirUpdateFailedat' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.89 NAME 'cirSyncInterval' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.90 NAME 'cirBeginORC' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.197 NAME 'replicaHost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.202 NAME 'replicaCredentials' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.203 NAME 'replicaEntryFilter' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.204 NAME 'replicaNickName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.406 NAME 'nsSynchUserIDFormat' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.217 NAME 'replicaCFUpdated' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.218 NAME 'replicaAbandonedChanges' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.407 NAME 'nsSynchUniqueAttribute' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.240 NAME 'replicatedattributelist' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.408 NAME 'replicaLastRelevantChange' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.41 NAME 'ntUserDomainId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.42 NAME 'ntUserCreateNewAccount' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.43 NAME 'ntUserDeleteAccount' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.44 NAME 'ntGroupDomainId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.45 NAME 'ntGroupCreateNewGroup' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.46 NAME 'ntGroupDeleteGroup' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.47 NAME 'ntGroupType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.59 NAME 'ntUserPriv' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.60 NAME 'ntUserAuthFlags' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.61 NAME 'ntUserUsrComment' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.62 NAME 'ntUserParms' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.63 NAME 'ntUserUnitsPerWeek' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.64 NAME 'ntUserNumLogons' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.65 NAME 'ntUserLogonServer' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.66 NAME 'ntUserUniqueId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.67 NAME 'ntUserProfile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.68 NAME 'ntUserPasswordExpired' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.110 NAME 'ntGroupId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.521 NAME 'ntUserHomeDir' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.522 NAME 'ntUserComment' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.523 NAME 'ntUserFlags' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.524 NAME 'ntUserScriptPath' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.525 NAME 'ntUserWorkstations' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.526 NAME 'ntUserLastLogon' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.527 NAME 'ntUserLastLogoff' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.528 NAME 'ntUserAcctExpires' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.529 NAME 'ntUserMaxStorage' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.530 NAME 'ntUserLogonHours' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.531 NAME 'ntUserBadPwCount' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.532 NAME 'ntUserCountryCode' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.533 NAME 'ntUserCodePage' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.534 NAME 'ntUserPrimaryGroupId' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.535 NAME 'ntUserHomeDirDrive' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.536 NAME 'ntGroupAttributes' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape NT Synchronization' )
+attributeTypes: ( 2.16.840.1.113730.3.1.54 NAME 'replicaUseSSL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.57 NAME 'replicaRoot' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.58 NAME 'replicaBindDn' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Directory Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.69 NAME 'subtreeACI' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Directory Server 1.0' )
+objectClasses: ( 2.16.840.1.113730.3.2.23 NAME 'netscapeDirectoryServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( nsDirectoryServer-oid NAME 'nsDirectoryServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass $ nsServerID ) MAY ( serverHostName $ nsServerPort $ nsSecureServerPort $ nsBindPassword $ nsBindDN $ nsBaseDN ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.8 NAME 'ntUser' DESC 'Netscape defined objectclass' SUP top MUST ( ntUserDomainId ) MAY ( description $ l $ ou $ seeAlso $ ntUserPriv $ ntUserHomeDir $ ntUserComment $ ntUserFlags $ ntUserScriptPath $ ntUserAuthFlags $ ntUserUsrComment $ ntUserParms $ ntUserWorkstations $ ntUserLastLogon $ ntUserLastLogoff $ ntUserAcctExpires $ ntUserMaxStorage $ ntUserUnitsPerWeek $ ntUserLogonHours $ ntUserBadPwCount $ ntUserNumLogons $ ntUserLogonServer $ ntUserCountryCode $ ntUserCodePage $ ntUserUniqueId $ ntUserPrimaryGroupId $ ntUserProfile $ ntUserHomeDirDrive $ ntUserPasswordExpired $ ntUserCreateNewAccount $ ntUserDeleteAccount ) X-ORIGIN 'Netscape NT Synchronization' )
+objectClasses: ( 2.16.840.1.113730.3.2.9 NAME 'ntGroup' DESC 'Netscape defined objectclass' SUP top MUST ( ntGroupDomainId ) MAY ( description $ l $ ou $ seeAlso $ ntGroupId $ ntGroupAttributes $ ntGroupCreateNewGroup $ ntGroupDeleteGroup $ ntGroupType ) X-ORIGIN 'Netscape NT Synchronization' )
+objectClasses: ( 2.16.840.1.113730.3.2.82 NAME 'nsChangelog4Config' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.114 NAME 'nsConsumer4Config' DESC 'Netscape defined objectclass' SUP top MAY ( cn ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.36 NAME 'LDAPReplica' DESC 'Netscape defined objectclass' SUP top MUST ( cn ) MAY ( description $ l $ ou $ seeAlso $ replicaRoot $ replicaHost $ replicaPort $ replicaBindDn $ replicaCredentials $ replicaBindMethod $ replicaUseSSL $ replicaUpdateSchedule $ replicaUpdateReplayed $ replicaUpdateFailedAt $ replicaBeginORC $ replicaNickname $ replicaEntryFilter $ replicatedAttributeList $ replicaCFUpdated $ replicaAbandonedChanges $ replicaLastRelevantChange ) X-ORIGIN 'Netscape Directory Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.11 NAME 'cirReplicaSource' DESC 'Netscape defined objectclass' SUP top MUST cn MAY ( cirReplicaRoot $ cirHost $ cirPort $ cirBindDN $ cirUsePersistentSearch $ cirUseSSL $ cirBindCredentials $ cirLastUpdateApplied $ cirUpdateSchedule $ cirSyncInterval $ cirUpdateFailedAt $ cirBeginORC $ replicaNickname $ replicaEntryFilter $ replicatedAttributeList ) X-ORIGIN 'Netscape Directory Server' )
diff --git a/ldap/schema/50ns-legacy.ldif b/ldap/schema/50ns-legacy.ldif
new file mode 100644
index 00000000..13116217
--- /dev/null
+++ b/ldap/schema/50ns-legacy.ldif
@@ -0,0 +1,16 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Legacy Netscape Schema
+#
+dn: cn=schema
+attributeTypes: ( url-oid NAME 'url' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Legacy' )
+objectClasses: ( nsLegacyAdminGroup-oid NAME 'nsLegacyAdminGroup' DESC 'Netscape defined objectclass' SUP nsAdminGroup MAY ( adminUrl ) X-ORIGIN 'Netscape Legacy' )
+objectClasses: ( nsLegacyApplication-oid NAME 'nsLegacyApplication' DESC 'Netscape defined objectclass' SUP nsApplication X-ORIGIN 'Netscape Legacy' )
+objectClasses: ( nsLegacyAdminServer-oid NAME 'nsLegacyAdminServer' DESC 'Netscape defined objectclass' SUP nsAdminServer X-ORIGIN 'Netscape Legacy' )
+objectClasses: ( nsLegacyServer-oid NAME 'nsLegacyServer' DESC 'Netscape defined objectclass' SUP netscapeServer MAY ( nsServerID $ url ) X-ORIGIN 'Netscape Legacy' )
diff --git a/ldap/schema/50ns-mail.ldif b/ldap/schema/50ns-mail.ldif
new file mode 100644
index 00000000..ca2d1018
--- /dev/null
+++ b/ldap/schema/50ns-mail.ldif
@@ -0,0 +1,48 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for Netscape Messaging Server 4.x. Some attributes are also
+# used by NMS 5.x
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.16 NAME ( 'mailDeliveryOption' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.707 NAME ( 'vacationstartdate' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.18 NAME ( 'mailHost' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.33 NAME ( 'mgrpModerator' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.25 NAME ( 'mgrpDeliverTo' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( mgrpApprovePassword-oid NAME ( 'mgrpApprovePassword' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.31 NAME ( 'mailEnhancedUniqueMember' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.781 NAME ( 'mgrpAddHeader' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.22 NAME ( 'mgrpAllowedBroadcaster' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.30 NAME ( 'mgrpRFC822MailMember' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( nsmsgNumMsgQuota-oid NAME ( 'nsmsgNumMsgQuota' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.13 NAME ( 'mailAlternateAddress' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.708 NAME ( 'vacationenddate' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.20 NAME ( 'mailProgramDeliveryInfo' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.801 NAME ( 'mgrpRemoveHeader' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.12 NAME ( 'mailAccessDomain' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.14 NAME ( 'mailAutoReplyMode' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.15 NAME ( 'mailAutoReplyText' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.21 NAME ( 'mailQuota' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.788 NAME ( 'mgrpBroadcasterPolicy' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.24 NAME ( 'mailRoutingAddress' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.19 NAME ( 'mailMessageStore' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.520 NAME ( 'nswmExtendedUserPrefs' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.26 NAME ( 'mgrpErrorsTo' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.23 NAME ( 'mgrpAllowedDomain' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.28 NAME ( 'mgrpMsgRejectAction' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( nsmsgDisallowAccess-oid NAME ( 'nsmsgDisallowAccess' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.17 NAME ( 'mailForwardingAddress' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.32 NAME ( 'mgrpMsgMaxSize' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.29 NAME ( 'mgrpMsgRejectText' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Messaging Server 4.x' )
+attributeTypes: ( 2.16.840.1.113730.3.1.789 NAME ( 'mgrpNoDuplicateChecks' ) DESC 'Netscape Messaging Server 4.x defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Messaging Server 4.x' )
+objectclasses: ( 2.16.840.1.113730.3.2.3 NAME 'mailRecipient' DESC '' SUP top AUXILIARY MUST ( objectClass ) MAY ( cn $ mail $ mailAlternateAddress $ mailHost $ mailRoutingAddress $ mailAccessDomain $ mailAutoReplyMode $ mailAutoReplyText $ mailDeliveryOption $ mailForwardingAddress $ mailMessageStore $ mailProgramDeliveryInfo $ mailQuota $ multiLineDescription $ uid $ userPassword ) X-ORIGIN 'Netscape Messaging Server 4.x' )
+objectclasses: ( 2.16.840.113730.3.2.37 NAME 'nsMessagingServerUser' DESC '' SUP top AUXILIARY MUST ( objectClass ) MAY ( cn $ mailAccessDomain $ mailAutoReplyMode $ mailAutoReplyText $ mailDeliveryOption $ mailForwardingAddress $ mailMessageStore $ mailProgramDeliveryInfo $ mailQuota $ nsmsgDisallowAccess $ nsmsgNumMsgQuota $ nswmExtendedUserPrefs $ vacationstartdate $ vacationenddate ) X-ORIGIN 'Netscape Messaging Server 4.x' )
+objectclasses: ( 2.16.840.1.113730.3.2.4 NAME 'mailGroup' DESC '' SUP top AUXILIARY MUST ( objectClass ) MAY ( cn $ mail $ mailAlternateAddress $ mailHost $ mailRoutingAddress $ mgrpAddHeader $ mgrpAllowedBroadcaster $ mgrpAllowedDomain $ mgrpApprovePassword $ mgrpBroadcasterPolicy $ mgrpDeliverTo $ mgrpErrorsTo $ mgrpModerator $ mgrpMsgMaxSize $ mgrpMsgRejectAction $ mgrpMsgRejectText $ mgrpNoDuplicateChecks $ mgrpRemoveHeader $ mgrpRFC822MailMember $ owner ) X-ORIGIN 'Netscape Messaging Server 4.x' )
+objectclasses: ( 2.16.840.1.113730.3.2.5 NAME 'groupOfMailEnhancedUniqueNames' DESC '' SUP top AUXILIARY MUST ( objectClass $ cn ) MAY ( businessCategory $ description $ mailEnhancedUniqueMember $ o $ ou $ owner $ seeAlso ) X-ORIGIN 'Netscape Messaging Server 4.x' )
+objectclasses: ( 2.16.840.1.113730.3.2.24 NAME 'netscapeMailServer' DESC '' SUP top AUXILIARY MUST ( objectClass ) X-ORIGIN 'Netscape Messaging Server 4.x' )
diff --git a/ldap/schema/50ns-mcd-browser.ldif b/ldap/schema/50ns-mcd-browser.ldif
new file mode 100644
index 00000000..20753400
--- /dev/null
+++ b/ldap/schema/50ns-mcd-browser.ldif
@@ -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
+#
+#
+# Schema for Netscape Mission Control Desktop - Browser
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.409 NAME 'nsBCStartupBrowser' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.410 NAME 'nsBCStartupMail' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.411 NAME 'nsBCStartupEditor' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.412 NAME 'nsBCStartupCalendar' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.413 NAME 'nsBCChromeButtonStyle' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.414 NAME 'nsBCUseDocumentFonts' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.415 NAME 'nsBCForegroundColor' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.416 NAME 'nsBCBackgroundColor' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.417 NAME 'nsBCAnchorColor' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.418 NAME 'nsBCVisitedColor' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.419 NAME 'nsBCUnderlineAnchors' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.420 NAME 'nsBCUseDocumentColors' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.421 NAME 'nsBCStartupPage' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.422 NAME 'nsBCStartupHomePage' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.423 NAME 'nsBCLinkExpiration' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.424 NAME 'nsBCIntlAcceptLanguages' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.425 NAME 'nsBCMimeType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.426 NAME 'nsBCMimeAllowAdd' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.427 NAME 'nsBCMimeAllowEdit' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.428 NAME 'nsBCMimeAllowRemove' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.429 NAME 'nsBCRelatedEnabled' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.430 NAME 'nsBCRelatedAutoload' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.431 NAME 'nsBCRelatedDisabledForDomains' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.432 NAME 'nsBCGoBrowsingEnabled' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.433 NAME 'nsBCOfflineStartupState' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.434 NAME 'nsBCOfflineSendUnsentMessages' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.435 NAME 'nsBCOfflinePromptSynchOnExit' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.436 NAME 'nsBCAlwaysLoadImages' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.437 NAME 'nsBCEnableJava' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.438 NAME 'nsBCEnableJavaScript' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.439 NAME 'nsBCEnableStyleSheets' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.440 NAME 'nsBCEmailAsFtpPassword' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.441 NAME 'nsBCCookieBehavior' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.442 NAME 'nsBCWarnAboutCookies' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.443 NAME 'nsBCMemoryCacheSize' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.444 NAME 'nsBCDiskCacheSize' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.445 NAME 'nsBCCheckDocFrequency' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.446 NAME 'nsBCProxyType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.447 NAME 'nsBCProxyHttp' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.448 NAME 'nsBCProxySsl' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.449 NAME 'nsBCProxyFtp' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.450 NAME 'nsBCProxySocks' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.451 NAME 'nsBCProxyGopher' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.452 NAME 'nsBCProxyWais' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.453 NAME 'nsBCNoProxiesOn' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.454 NAME 'nsBCProxyAutoConfigUrl' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.455 NAME 'nsBCAutoUpdateEnabled' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.456 NAME 'nsBCAutoUpdateConfirmInstall' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.457 NAME 'nsBSAskForPassword' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.458 NAME 'nsBSPasswordLifetime' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.459 NAME 'nsBSWarnEnteringSecure' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.460 NAME 'nsBSWarnLeavingSecure' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.461 NAME 'nsBSWarnViewingMixed' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.462 NAME 'nsBSWarnSubmitInsecure' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.463 NAME 'nsBSEnableSsl2' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.464 NAME 'nsBSEnableSsl3' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.465 NAME 'nsBSCertmgmtDisableFunctionMsg' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.466 NAME 'nsBSSsl2Rc4128' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.467 NAME 'nsBSSsl2Rc2128' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.468 NAME 'nsBSSsl2DesEd3192' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.469 NAME 'nsBSSsl2Des64' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.470 NAME 'nsBSSsl2Rc440' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.471 NAME 'nsBSSsl2Rc240' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.472 NAME 'nsBSSsl3RsaRc2128Md5' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.473 NAME 'nsBSSsl3FipsDesEd3Sha' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.474 NAME 'nsBSSsl3RsaRc4128Md5' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.475 NAME 'nsBSSsl3RsaFipsDesSha' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.476 NAME 'nsBSSsl3RsaDesSha' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.477 NAME 'nsBSSsl3RsaRc440Md5' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.478 NAME 'nsBSSsl3RsaRc240Md5' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.479 NAME 'nsBSSsl3RsaNullMd5' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.480 NAME 'nsBSSsl3FortezzaFortezzaSha' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+attributeTypes: ( 2.16.840.1.113730.3.1.481 NAME 'nsBSSsl3FortezzaRc4Sha' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+objectClasses: ( 2.16.840.1.113730.3.2.78 NAME 'nsBrowserClient' DESC 'Netscape defined objectclass' SUP top MAY ( nsBCStartupBrowser $ nsBCStartupMail $ nsBCStartupEditor $ nsBCStartupCalendar $ nsBCChromeButtonStyle $ nsBCUseDocumentFonts $ nsBCForegroundColor $ nsBCBackgroundColor $ nsBCAnchorColor $ nsBCVisitedColor $ nsBCUnderlineAnchors $ nsBCUseDocumentColors $ nsBCStartupPage $ nsBCStartupHomePage $ nsBCLinkExpiration $ nsBCIntlAcceptLanguages $ nsBCMimeType $ nsBCMimeAllowAdd $ nsBCMimeAllowEdit $ nsBCMimeAllowRemove $ nsBCRelatedEnabled $ nsBCRelatedAutoload $ nsBCRelatedDisabledForDomains $ nsBCGoBrowsingEnabled $ nsBCOfflineStartupState $ nsBCOfflineSendUnsentMessages $ nsBCOfflinePromptSynchOnExit $ nsBCAlwaysLoadImages $ nsBCEnableJava $ nsBCEnableJavaScript $ nsBCEnableStyleSheets $ nsBCEmailAsFtpPassword $ nsBCCookieBehavior $ nsBCWarnAboutCookies $ nsBCMemoryCacheSize $ nsBCDiskCacheSize $ nsBCCheckDocFrequency $ nsBCProxyType $ nsBCProxyHttp $ nsBCProxySsl $ nsBCProxyFtp $ nsBCProxySocks $ nsBCProxyGopher $ nsBCProxyWais $ nsBCNoProxiesOn $ nsBCProxyAutoConfigUrl $ nsBCAutoUpdateEnabled $ nsBCAutoUpdateConfirmInstall ) X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
+objectClasses: ( 2.16.840.1.113730.3.2.79 NAME 'nsBrowserSecurity' DESC 'Netscape defined objectclass' SUP top MAY ( nsBSAskForPassword $ nsBSPasswordLifetime $ nsBSWarnEnteringSecure $ nsBSWarnLeavingSecure $ nsBSWarnViewingMixed $ nsBSWarnSubmitInsecure $ nsBSEnableSsl2 $ nsBSEnableSsl3 $ nsBSCertmgmtDisableFunctionMsg $ nsBSSsl2Rc4128 $ nsBSSsl2Rc2128 $ nsBSSsl2DesEd3192 $ nsBSSsl2Des64 $ nsBSSsl2Rc440 $ nsBSSsl2Rc240 $ nsBSSsl3RsaRc4128Md5 $ nsBSSsl3FipsDesEd3Sha $ nsBSSsl3RsaRc4128Md5 $ nsBSSsl3RsaFipsDesSha $ nsBSSsl3RsaDesSha $ nsBSSsl3RsaRc440Md5 $ nsBSSsl3RsaRc240Md5 $ nsBSSsl3RsaNullMd5 $ nsBSSsl3FortezzaFortezzaSha $ nsBSSsl3FortezzaRc4Sha ) X-ORIGIN 'Netscape Mission Control Desktop - Browser' )
diff --git a/ldap/schema/50ns-mcd-config.ldif b/ldap/schema/50ns-mcd-config.ldif
new file mode 100644
index 00000000..6d72272b
--- /dev/null
+++ b/ldap/schema/50ns-mcd-config.ldif
@@ -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
+#
+#
+# Schema for Netscape Mission Control Desktop - Configuration
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.482 NAME 'nsMcdUserAgent' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.483 NAME 'nsMcdUseXSender' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.484 NAME 'nsMcdToolbarLogoUrl' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.485 NAME 'nsMcdToolbarLogoWinSmallFile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.486 NAME 'nsMcdToolbarLogoWinLargeFile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.487 NAME 'nsMcdToolbarLogoFrames' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.488 NAME 'nsMcdMacAnimationFile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.489 NAME 'nsMcdXAnimationFile' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.490 NAME 'nsMcdNetSearchUrl' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.491 NAME 'nsMcdMoreInfoPluginUrl' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.492 NAME 'nsMcdAutoAdminConfigUrl' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.493 NAME 'nsMcdAutoAdminAppendEmail' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.494 NAME 'nsMcdAutoAdminRefreshInterval' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.495 NAME 'nsMcdUseGuideButton' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.496 NAME 'nsMcdGuideButtonProperties' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.497 NAME 'nsMcdGuideMenuProperties' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+attributeTypes: ( 2.16.840.1.113730.3.1.498 NAME 'nsMcdHelpMenuProperties' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
+objectClasses: ( 2.16.840.1.113730.3.2.80 NAME 'nsMcdConfig' DESC 'Netscape defined objectclass' SUP top MAY ( nsMcdUserAgent $ nsMcdUseXSender $ nsMcdToolbarLogoUrl $ nsMcdToolbarLogoWinSmallFile $ nsMcdToolbarLogoWinLargeFile $ nsMcdToolbarLogoFrames $ nsMcdMacAnimationFile $ nsMcdXAnimationFile $ nsMcdNetSearchUrl $ nsMcdMoreInfoPluginUrl $ nsMcdAutoAdminConfigUrl $ nsMcdAutoAdminAppendEmail $ nsMcdAutoAdminRefreshInterval $ nsMcdUseGuideButton $ nsMcdGuideButtonProperties $ nsMcdGuideMenuProperties $ nsMcdHelpMenuProperties ) X-ORIGIN 'Netscape Mission Control Desktop - Configuration' )
diff --git a/ldap/schema/50ns-mcd-li.ldif b/ldap/schema/50ns-mcd-li.ldif
new file mode 100644
index 00000000..12af630f
--- /dev/null
+++ b/ldap/schema/50ns-mcd-li.ldif
@@ -0,0 +1,22 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for Netscape Mission Control Desktop - Location Independence
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.399 NAME 'nsLIPtrURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+attributeTypes: ( 2.16.840.1.113730.3.1.400 NAME 'nsLIPrefs' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+attributeTypes: ( 2.16.840.1.113730.3.1.401 NAME 'nsLIProfileName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+attributeTypes: ( 2.16.840.1.113730.3.1.402 NAME 'nsLIData' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+attributeTypes: ( 2.16.840.1.113730.3.1.403 NAME 'nsLIElementType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+attributeTypes: ( 2.16.840.1.113730.3.1.404 NAME 'nsLIServerType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+attributeTypes: ( 2.16.840.1.113730.3.1.405 NAME 'nsLIVersion' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+objectClasses: ( 2.16.840.1.113730.3.2.74 NAME 'nsLIPtr' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) MAY ( nsliptrurl $ owner ) X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+objectClasses: ( 2.16.840.1.113730.3.2.75 NAME 'nsLIProfile' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass $ nsliprofilename ) MAY ( nsliprefs $ uid $ owner ) X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+objectClasses: ( 2.16.840.1.113730.3.2.76 NAME 'nsLIProfileElement' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass $ nslielementtype ) MAY ( owner $ nslidata $ nsliversion ) X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
+objectClasses: ( 2.16.840.1.113730.3.2.77 NAME 'nsLIServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass $ serverhostname ) MAY ( description $ cn $ nsserverport $ nsliservertype $ serverroot ) X-ORIGIN 'Netscape Mission Control Desktop - Location Independence' )
diff --git a/ldap/schema/50ns-mcd-mail.ldif b/ldap/schema/50ns-mcd-mail.ldif
new file mode 100644
index 00000000..900c1f9b
--- /dev/null
+++ b/ldap/schema/50ns-mcd-mail.ldif
@@ -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
+#
+#
+# Schema for Netscape Mission Control Desktop - Mail
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.331 NAME 'nsMCHTMLCompose' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.332 NAME 'nsMCDefaultHTMLAction' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.333 NAME 'nsMCRequestReturnReceipt' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.334 NAME 'nsMCIncorporateReturnReceipt' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.335 NAME 'nsMCMDNReportEnabled' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.336 NAME 'nsMCMDNReportNotInToCC' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.337 NAME 'nsMCMDNReportOutsideDomain' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.338 NAME 'nsMCMDNReportOther' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.339 NAME 'nsMCForwardMessageMode' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.340 NAME 'nsMCAutoQuote' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.341 NAME 'nsMCReplyOnTop' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.342 NAME 'nsMCSpellCheckBeforeSend' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.343 NAME 'nsMCWrapLongLines' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.344 NAME 'nsMCWrapLength' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.345 NAME 'nsMCStrictlyMime' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.346 NAME 'nsMCAutoCompleteUseAddressBooks' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.347 NAME 'nsMCAutoCompleteUseDirectory' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.348 NAME 'nsMCAutoCompleteEnabledServerName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.349 NAME 'nsMCAutoCompleteShowDlgForMultipleMatches' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.350 NAME 'nsMCSkipDirectoryIfLocalMatchFound' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.351 NAME 'nsMCAddrBookLastnameFirst' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.352 NAME 'nsMCLimitMessageSize' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.353 NAME 'nsMCMaxMessageSize' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.354 NAME 'nsMCPromptPurgeThreshold' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.355 NAME 'nsMCPurgeThreshold' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.356 NAME 'nsMCNewsKeepMethod' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.357 NAME 'nsMCNewsKeepDays' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.358 NAME 'nsMCNewsKeepCount' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.359 NAME 'nsMCNewsKeepOnlyUnread' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.360 NAME 'nsMCNewsRemoveBodiesByAge' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.361 NAME 'nsMCNewsRemoveBodiesDays' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.362 NAME 'nsMCSmtpServer' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.363 NAME 'nsMCSmtpUserName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.364 NAME 'nsMCSmtpUseSSL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.365 NAME 'nsMCImapServer' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.366 NAME 'nsMCImapServerProperties' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.367 NAME 'nsMCPopServer' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.368 NAME 'nsMCPopServerProperties' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.369 NAME 'nsMCLdapServer' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.370 NAME 'nsMCLdapServerProperties' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.371 NAME 'nsMCQuotedStyle' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.372 NAME 'nsMCQuotedSize' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.373 NAME 'nsMCCitationColor' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.374 NAME 'nsMCFixedWidthMessages' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.375 NAME 'nsMCPlaySound' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.376 NAME 'nsMCRememberSelectedMessage' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.377 NAME 'nsMCReuseMessageWindow' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.378 NAME 'nsMCConfirmMoveFoldersToTrash' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.379 NAME 'nsMCUseMapiServer' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.380 NAME 'nsMCNewsTimeout' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.381 NAME 'nsMCNavCrossesFolders' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.382 NAME 'nsMCSearchServer' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.383 NAME 'nsMCSearchSubFolders' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.384 NAME 'nsMCEncryptOutgoingMail' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.385 NAME 'nsMCCryptoSignOutgoingMail' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.386 NAME 'nsMCCryptoSignOutgoingNews' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.387 NAME 'nsMCWarnForwardEncrypted' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.388 NAME 'nsMCWarnReplyUnencrypted' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.389 NAME 'nsMCAllowAtSignInUserName1' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.390 NAME 'nsMCReceiptRequestHeaderType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.391 NAME 'nsMCPop3GetsNewMail' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.392 NAME 'nsMCImapAutoSubscribeOnOpen' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.393 NAME 'nsMCImapMimePartsOnDemand' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.394 NAME 'nsMCImapMimePartsOnDemandThreshold' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.395 NAME 'nsMCUseAltMail' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.396 NAME 'nsMCAltMailDll' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.397 NAME 'nsMCUseAltMailForNews' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.398 NAME 'nsPrefMap' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.499 NAME 'nsMCAuthLogin' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.500 NAME 'nsMNCNavCrossesFolders' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.501 NAME 'nsMNCMessageInThreadWindow' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.502 NAME 'nsMCAllowAtSignInUserName' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.503 NAME 'nsMCImapOnlineDraftSent' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.504 NAME 'nsMCCustomHeaders' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.505 NAME 'nsMCHtmlDomains' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.506 NAME 'nsMNCForceAsciiSearch' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.507 NAME 'nsMCAddrBookLdapDisabled' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.508 NAME 'nsMNCReuseThreadWindow' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.509 NAME 'nsMCShowHeaders' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.510 NAME 'nsMCIdentityDefaultdomain' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.511 NAME 'nsMSEncryptOutgoingMail' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.512 NAME 'nsMSSignOutgoingMail' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.513 NAME 'nsMSSignOutgoingNews' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.514 NAME 'nsMSSmimeDesEde3' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.515 NAME 'nsMSSmimeRc2128' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.516 NAME 'nsMSSmimeDes' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.517 NAME 'nsMSSmimeRc264' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.518 NAME 'nsMSSmimeRc240' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+attributeTypes: ( 2.16.840.1.113730.3.1.519 NAME 'nsMSSmimeFortezza' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+objectClasses: ( 2.16.840.1.113730.3.2.72 NAME 'nsMailClient' DESC 'Netscape defined objectclass' SUP top MAY ( nsMCHTMLCompose $ nsMCDefaultHTMLAction $ nsMCRequestReturnReceipt $ nsMCIncorporateReturnReceipt $ nsMCMDNReportEnabled $ nsMCMDNReportNotInToCC $ nsMCMDNReportOutsideDomain $ nsMCMDNReportOther $ nsMCForwardMessageMode $ nsMCAutoQuote $ nsMCReplyOnTop $ nsMCSpellCheckBeforeSend $ nsMCWrapLongLines $ nsMCWrapLength $ nsMCStrictlyMime $ nsMCAutoCompleteUseAddressBooks $ nsMCAutoCompleteUseDirectory $ nsMCAutoCompleteEnabledServerName $ nsMCAutoCompleteShowDlgForMultipleMatches $ nsMCSkipDirectoryIfLocalMatchFound $ nsMCAddrBookLastnameFirst $ nsMCLimitMessageSize $ nsMCMaxMessageSize $ nsMCPromptPurgeThreshold $ nsMCPurgeThreshold $ nsMCNewsKeepMethod $ nsMCNewsKeepDays $ nsMCNewsKeepCount $ nsMCNewsKeepOnlyUnread $ nsMCNewsRemoveBodiesByAge $ nsMCNewsRemoveBodiesDays $ nsMCSmtpServer $ nsMCSmtpUserName $ nsMCSmtpUseSSL $ nsMCImapServer $ nsMCImapServerProperties $ nsMCPopServer $ nsMCPopServerProperties $ nsMCLdapServer $ nsMCLdapServerProperties $ nsMCQuotedStyle $ nsMCQuotedSize $ nsMCCitationColor $ nsMCFixedWidthMessages $ nsMCPlaySound $ nsMCRememberSelectedMessage $ nsMCReuseMessageWindow $ nsMCConfirmMoveFoldersToTrash $ nsMCUseMapiServer $ nsMCNewsTimeout $ nsMCNavCrossesFolders $ nsMCSearchServer $ nsMCSearchSubFolders $ nsMCEncryptOutgoingMail $ nsMCCryptoSignOutgoingMail $ nsMCCryptoSignOutgoingNews $ nsMCWarnForwardEncrypted $ nsMCWarnReplyUnencrypted $ nsMCAllowAtSignInUserName $ nsMCReceiptRequestHeaderType $ nsMCPop3GetsNewMail $ nsMCImapAutoSubscribeOnOpen $ nsMCImapMimePartsOnDemand $ nsMCImapMimePartsOnDemandThreshold $ nsMCUseAltMail $ nsMCAltMailDll $ nsMCUseAltMailForNews $ nsMCAuthLogin $ nsMNCNavCrossesFolders $ nsMNCMessageInThreadWindow $ nsMCAllowAtSignInUserName $ nsMCImapOnlineDraftSent $ nsMCCustomHeaders $ nsMCHtmlDomains $ nsMNCForceAsciiSearch $ nsMCAddrBookLdapDisabled $ nsMNCReuseThreadWindow $ nsMCShowHeaders $ nsMCIdentityDefaultdomain ) X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+objectClasses: ( 2.16.840.1.113730.3.2.81 NAME 'nsMailSecurity' DESC 'Netscape defined objectclass' SUP top MAY ( nsMSEncryptOutgoingMail $ nsMSSignOutgoingMail $ nsMSSignOutgoingNews $ nsMSSmimeDesEde3 $ nsMSSmimeRc2128 $ nsMSSmimeDes $ nsMSSmimeRc264 $ nsMSSmimeRc240 $ nsMSSmimeFortezza ) X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
+objectClasses: ( 2.16.840.1.113730.3.2.73 NAME 'netscapePreferenceMap' DESC 'Netscape defined objectclass' SUP top MAY ( nsPrefMap $ uid ) X-ORIGIN 'Netscape Mission Control Desktop - Mail' )
diff --git a/ldap/schema/50ns-media.ldif b/ldap/schema/50ns-media.ldif
new file mode 100644
index 00000000..7023f0b9
--- /dev/null
+++ b/ldap/schema/50ns-media.ldif
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for Netscape Media Server
+#
+dn: cn=schema
+objectClasses: ( 2.16.840.1.113730.3.2.25 NAME 'netscapeMediaServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) X-ORIGIN 'Netscape Media Server' )
diff --git a/ldap/schema/50ns-mlm.ldif b/ldap/schema/50ns-mlm.ldif
new file mode 100644
index 00000000..ffc446ba
--- /dev/null
+++ b/ldap/schema/50ns-mlm.ldif
@@ -0,0 +1,43 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for Netscape Mailing List Manager
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.796 NAME ( 'mgmanIntroText' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( 2.16.840.1.113730.3.1.791 NAME ( 'mgmanDenySubscribe' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmemRefDN-oid NAME ( 'mgmemRefDN' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfSortAttributeDirMembers-oid NAME ( 'mgmanGConfSortAttributeDirMembers' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfSearchRelationship-oid NAME ( 'mgmanGConfSearchRelationship' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfKey-oid NAME ( 'mgmanGConfKey' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfGroupTemplate-oid NAME ( 'mgmanGConfGroupTemplate' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfAdmin-oid NAME ( 'mgmanGConfAdmin' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGroupKey-oid NAME ( 'mgmanGroupKey' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfSearchAttribute-oid NAME ( 'mgmanGConfSearchAttribute' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmemMailUserPassword-oid NAME ( 'mgmemMailUserPassword' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmemGroupServerParam-oid NAME ( 'mgmemGroupServerParam' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfSearchTreeNode-oid NAME ( 'mgmanGConfSearchTreeNode' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmemGroupMemberParam-oid NAME ( 'mgmemGroupMemberParam' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfDefaultInheritance-oid NAME ( 'mgmanGConfDefaultInheritance' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmemMemberOfGroup-oid NAME ( 'mgmemMemberOfGroup' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanJoinLocalType-oid NAME ( 'mgmanJoinLocalType' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfSearchBase-oid NAME ( 'mgmanGConfSearchBase' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( 2.16.840.1.113730.3.1.793 NAME ( 'mgmanJoinability' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( 2.16.840.1.113730.3.1.795 NAME ( 'mgmanMemberVisibility' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfSortAttributeGroupMembers-oid NAME ( 'mgmanGConfSortAttributeGroupMembers' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( 2.16.840.1.113730.3.1.790 NAME ( 'mgmanAllowSubscribe' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfRemoteUserParent-oid NAME ( 'mgmanGConfRemoteUserParent' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfGroupDomains-oid NAME ( 'mgmanGConfGroupDomains' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGroupStat-oid NAME ( 'mgmanGroupStat' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( 2.16.840.1.113730.3.1.792 NAME ( 'mgmanHidden' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfNewGroupParent-oid NAME ( 'mgmanGConfNewGroupParent' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfGroupCreationUser-oid NAME ( 'mgmanGConfGroupCreationUser' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Mailing List Manager' )
+attributeTypes: ( mgmanGConfSearchGroupUser-oid NAME ( 'mgmanGConfSearchGroupUser' ) DESC 'Netscape Mailing List Manager defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Mailing List Manager' )
+objectclasses: ( mailGroupMember-oid NAME 'mailGroupMember' DESC 'Netscape defined objectclass' SUP top AUXILIARY MUST ( objectClass $ mail ) MAY ( mgmemMemberOfGroup $ mgmemRefDN $ preferredLanguage $ userCertificate $ mgmemMailUserPassword $ mgmemGroupMemberParam $ mgmemGroupServerParam $ c $ cn $ sn $ givenName ) X-ORIGIN 'Netscape Mailing List Manager' )
+objectclasses: ( mailGroupManagement-oid NAME 'mailGroupManagement' DESC 'Netscape defined objectclass' SUP top AUXILIARY MUST ( objectClass ) MAY ( description $ labeledURL $ mgmanAllowSubscribe $ mgmanDenySubscribe $ mgmanGroupKey $ mgmanGroupStat $ mgmanHidden $ mgmanIntroText $ mgmanJoinability $ mgmanJoinLocalType $ mgmanMemberVisibility $ multilineDescription $ userCertificate $ userPassword ) X-ORIGIN 'Netscape Mailing List Manager' )
+objectclasses: ( mailGroupManagement-GlobalConfig-oid NAME 'mailGroupManagement-GlobalConfig' DESC 'Netscape defined objectclass' SUP top AUXILIARY MUST ( objectClass ) MAY ( cn $ mgmanGConfAdmin $ mgmanGConfDefaultInheritance $ mgmanGConfGroupCreationUser $ mgmanGConfGroupDomains $ mgmanGConfGroupTemplate $ mgmanGConfKey $ mgmanGConfNewGroupParent $ mgmanGConfRemoteUserParent $ mgmanGConfSearchAttribute $ mgmanGConfSearchBase $ mgmanGConfSearchGroupUser $ mgmanGConfSearchRelationship $ mgmanGConfSearchTreeNode $ mgmanGConfSortAttributeDirMembers $ mgmanGConfSortAttributeGroupMembers ) X-ORIGIN 'Netscape Mailing List Manager' )
diff --git a/ldap/schema/50ns-msg.ldif b/ldap/schema/50ns-msg.ldif
new file mode 100644
index 00000000..16256539
--- /dev/null
+++ b/ldap/schema/50ns-msg.ldif
@@ -0,0 +1,297 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Netscape Messaging Server configuration schema
+#
+dn: cn=schema
+attributeTypes: ( nsmsgNtrunoptn-oid NAME ( 'nsmsgNtrunoptn' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgExclusive-oid NAME ( 'nsmsgExclusive' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAltqueues-oid NAME ( 'nsmsgAltqueues' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMinfreediskspace-oid NAME ( 'nsmsgMinfreediskspace' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgEnablesslport-oid NAME ( 'nsmsgEnablesslport' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgExtrauserldapattrs-oid NAME ( 'nsmsgExtrauserldapattrs' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgRolloverdelta-oid NAME ( 'nsmsgRolloverdelta' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLogdir-oid NAME ( 'nsmsgLogdir' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxerrorobjectsize-oid NAME ( 'nsmsgMaxerrorobjectsize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDocanonicalize-oid NAME ( 'nsmsgDocanonicalize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgRollovertime-oid NAME ( 'nsmsgRollovertime' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgProtocolubeconfig-oid NAME ( 'nsmsgProtocolubeconfig' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDeferredperiod-oid NAME ( 'nsmsgDeferredperiod' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgCollectiondeltatime-oid NAME ( 'nsmsgCollectiondeltatime' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAddheaders-oid NAME ( 'nsmsgAddheaders' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNumenvelopequeuefiles-oid NAME ( 'nsmsgNumenvelopequeuefiles' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxmessagesize-oid NAME ( 'nsmsgMaxmessagesize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeoutdatadot-oid NAME ( 'nsmsgTimeoutdatadot' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgListenaddr-oid NAME ( 'nsmsgListenaddr' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeouthelo-oid NAME ( 'nsmsgTimeouthelo' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved0-oid NAME ( 'nsmsgReserved0' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved1-oid NAME ( 'nsmsgReserved1' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgQuotanotification-oid NAME ( 'nsmsgQuotanotification' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNetworkdefaultminruncount-oid NAME ( 'nsmsgNetworkdefaultminruncount' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved2-oid NAME ( 'nsmsgReserved2' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved3-oid NAME ( 'nsmsgReserved3' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNetworkdefaultmaxruncount-oid NAME ( 'nsmsgNetworkdefaultmaxruncount' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved4-oid NAME ( 'nsmsgReserved4' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLdapmemcache-oid NAME ( 'nsmsgLdapmemcache' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved5-oid NAME ( 'nsmsgReserved5' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved6-oid NAME ( 'nsmsgReserved6' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgClearcontrolsafetime-oid NAME ( 'nsmsgClearcontrolsafetime' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved7-oid NAME ( 'nsmsgReserved7' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved8-oid NAME ( 'nsmsgReserved8' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowetrn-oid NAME ( 'nsmsgAllowetrn' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgServiceadmingroupdn-oid NAME ( 'nsmsgServiceadmingroupdn' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSitelanguage-oid NAME ( 'nsmsgSitelanguage' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReserved9-oid NAME ( 'nsmsgReserved9' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLocalmaildomains-oid NAME ( 'nsmsgLocalmaildomains' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxqueuetime-oid NAME ( 'nsmsgMaxqueuetime' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxcontrolrecipients-oid NAME ( 'nsmsgMaxcontrolrecipients' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaildeliveryprogram-oid NAME ( 'nsmsgMaildeliveryprogram' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMessagesize-oid NAME ( 'nsmsgMessagesize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAdddeliveredto-oid NAME ( 'nsmsgAdddeliveredto' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAccounturl-oid NAME ( 'nsmsgAccounturl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowanonymouslogin-oid NAME ( 'nsmsgAllowanonymouslogin' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxmtahops-oid NAME ( 'nsmsgMaxmtahops' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxlogsize-oid NAME ( 'nsmsgMaxlogsize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSslpasswdfile-oid NAME ( 'nsmsgSslpasswdfile' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDnsresolveclient-oid NAME ( 'nsmsgDnsresolveclient' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgFilemode-oid NAME ( 'nsmsgFilemode' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeoutcommand-oid NAME ( 'nsmsgTimeoutcommand' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgFlushinterval-oid NAME ( 'nsmsgFlushinterval' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSmtpport-oid NAME ( 'nsmsgSmtpport' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeoutquit-oid NAME ( 'nsmsgTimeoutquit' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAlias-oid NAME ( 'nsmsgAlias' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgPath-oid NAME ( 'nsmsgPath' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDorewritesenderusingauth-oid NAME ( 'nsmsgDorewritesenderusingauth' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgResourcetimeout-oid NAME ( 'nsmsgResourcetimeout' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMtaid-oid NAME ( 'nsmsgMtaid' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nmmsgsslsourceurl-oid NAME ( 'nmmsgsslsourceurl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDomainsecurity-oid NAME ( 'nsmsgDomainsecurity' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxthreads-oid NAME ( 'nsmsgMaxthreads' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDomainnotallowed-oid NAME ( 'nsmsgDomainnotallowed' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgInternalmxserverip-oid NAME ( 'nsmsgInternalmxserverip' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgOrganization-oid NAME ( 'nsmsgOrganization' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLdaputilconfig-oid NAME ( 'nsmsgLdaputilconfig' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDbtmpdir-oid NAME ( 'nsmsgDbtmpdir' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSmtprewritestyle-oid NAME ( 'nsmsgSmtprewritestyle' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgCounterdeltatime-oid NAME ( 'nsmsgCounterdeltatime' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDomainname-oid NAME ( 'nsmsgDomainname' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLoglevel-oid NAME ( 'nsmsgLoglevel' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultvacation-oid NAME ( 'nsmsgDefaultvacation' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmnoticeport-oid NAME ( 'nsmsgMsgalarmnoticeport' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgRoutingattribute-oid NAME ( 'nsmsgRoutingattribute' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNeedsender-oid NAME ( 'nsmsgNeedsender' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgVerifyrcpts-oid NAME ( 'nsmsgVerifyrcpts' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmthreshold-oid NAME ( 'nsmsgMsgalarmthreshold' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSmtphost-oid NAME ( 'nsmsgSmtphost' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMinruncount-oid NAME ( 'nsmsgMinruncount' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDomainlangtable-oid NAME ( 'nsmsgDomainlangtable' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxruncount-oid NAME ( 'nsmsgMaxruncount' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgCheckdeferredqueue-oid NAME ( 'nsmsgCheckdeferredqueue' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSystemmaildir-oid NAME ( 'nsmsgSystemmaildir' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgStripcr-oid NAME ( 'nsmsgStripcr' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowehlo-oid NAME ( 'nsmsgAllowehlo' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgQuotaexceededmsg-oid NAME ( 'nsmsgQuotaexceededmsg' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNewsspool-oid NAME ( 'nsmsgNewsspool' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowadminproxy-oid NAME ( 'nsmsgAllowadminproxy' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultoverquota-oid NAME ( 'nsmsgDefaultoverquota' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSpooldir-oid NAME ( 'nsmsgSpooldir' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxbranches-oid NAME ( 'nsmsgMaxbranches' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgUnknownacctsactions-oid NAME ( 'nsmsgUnknownacctsactions' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmwarninginterval-oid NAME ( 'nsmsgMsgalarmwarninginterval' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgRolloversize-oid NAME ( 'nsmsgRolloversize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgQuotaexceededactions-oid NAME ( 'nsmsgQuotaexceededactions' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmnoticehost-oid NAME ( 'nsmsgMsgalarmnoticehost' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMessagedays-oid NAME ( 'nsmsgMessagedays' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgBanner-oid NAME ( 'nsmsgBanner' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultmailboxquota-oid NAME ( 'nsmsgDefaultmailboxquota' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultdomain-oid NAME ( 'nsmsgDefaultdomain' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultpartition-oid NAME ( 'nsmsgDefaultpartition' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgListenq-oid NAME ( 'nsmsgListenq' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSslcachesize-oid NAME ( 'nsmsgSslcachesize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgQuotawarn-oid NAME ( 'nsmsgQuotawarn' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgReadtimeout-oid NAME ( 'nsmsgReadtimeout' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNestedgroups-oid NAME ( 'nsmsgNestedgroups' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLogtype-oid NAME ( 'nsmsgLogtype' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDescription-oid NAME ( 'nsmsgDescription' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultuid-oid NAME ( 'nsmsgDefaultuid' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLdapmemcachettl-oid NAME ( 'nsmsgLdapmemcachettl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTcpaccessdeniedtimeout-oid NAME ( 'nsmsgTcpaccessdeniedtimeout' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgContact-oid NAME ( 'nsmsgContact' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDoetrn-oid NAME ( 'nsmsgDoetrn' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgQuotaexceededmsginterval-oid NAME ( 'nsmsgQuotaexceededmsginterval' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLdapmemcachesize-oid NAME ( 'nsmsgLdapmemcachesize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgFullfromheader-oid NAME ( 'nsmsgFullfromheader' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMasterport-oid NAME ( 'nsmsgMasterport' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgIpsecurity-oid NAME ( 'nsmsgIpsecurity' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgUsemx-oid NAME ( 'nsmsgUsemx' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmnoticetemplate-oid NAME ( 'nsmsgMsgalarmnoticetemplate' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgForeignpercentaddr-oid NAME ( 'nsmsgForeignpercentaddr' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgPlaintextmincipher-oid NAME ( 'nsmsgPlaintextmincipher' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAuthcachettl-oid NAME ( 'nsmsgAuthcachettl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxsessions-oid NAME ( 'nsmsgMaxsessions' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgFoldersizebytes-oid NAME ( 'nsmsgFoldersizebytes' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeoutdata-oid NAME ( 'nsmsgTimeoutdata' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgHostoncommandline-oid NAME ( 'nsmsgHostoncommandline' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMtaname-oid NAME ( 'nsmsgMtaname' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgRequirecrlf-oid NAME ( 'nsmsgRequirecrlf' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeoutrset-oid NAME ( 'nsmsgTimeoutrset' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgShellpath-oid NAME ( 'nsmsgShellpath' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgPort-oid NAME ( 'nsmsgPort' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowvrfy-oid NAME ( 'nsmsgAllowvrfy' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeoutmail-oid NAME ( 'nsmsgTimeoutmail' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLoginseparator-oid NAME ( 'nsmsgLoginseparator' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMasterhost-oid NAME ( 'nsmsgMasterhost' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgQuotagraceperiod-oid NAME ( 'nsmsgQuotagraceperiod' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDeleteheaders-oid NAME ( 'nsmsgDeleteheaders' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgExpirytime-oid NAME ( 'nsmsgExpirytime' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultreply-oid NAME ( 'nsmsgDefaultreply' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgRoutstripimapfolders-oid NAME ( 'nsmsgRoutstripimapfolders' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLocaldefaultminruncount-oid NAME ( 'nsmsgLocaldefaultminruncount' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLocaldefaultmaxruncount-oid NAME ( 'nsmsgLocaldefaultmaxruncount' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgRenotifyinterval-oid NAME ( 'nsmsgRenotifyinterval' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNtpassword-oid NAME ( 'nsmsgNtpassword' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultacl-oid NAME ( 'nsmsgDefaultacl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgPartition-oid NAME ( 'nsmsgPartition' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowsize-oid NAME ( 'nsmsgAllowsize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgConfigversion-oid NAME ( 'nsmsgConfigversion' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxbadcommands-oid NAME ( 'nsmsgMaxbadcommands' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgConnLimits-oid NAME ( 'nsmsgConnLimits' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDomainallowed-oid NAME ( 'nsmsgDomainallowed' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgFormsigkey-oid NAME ( 'nsmsgFormsigkey' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgProxydomainallowed-oid NAME ( 'nsmsgProxydomainallowed' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSourceurl-oid NAME ( 'nsmsgSourceurl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultecho-oid NAME ( 'nsmsgDefaultecho' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgVersion-oid NAME ( 'nsmsgVersion' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgEnable-oid NAME ( 'nsmsgEnable' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxpostsize-oid NAME ( 'nsmsgMaxpostsize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowhelp-oid NAME ( 'nsmsgAllowhelp' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgPopminpoll-oid NAME ( 'nsmsgPopminpoll' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgRewritetocc-oid NAME ( 'nsmsgRewritetocc' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNewsprefix-oid NAME ( 'nsmsgNewsprefix' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowbarelf-oid NAME ( 'nsmsgAllowbarelf' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDcroot-oid NAME ( 'nsmsgDcroot' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSslusesslrelay-oid NAME ( 'nsmsgSslusesslrelay' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowverb-oid NAME ( 'nsmsgAllowverb' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMessagecount-oid NAME ( 'nsmsgMessagecount' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmnoticercpt-oid NAME ( 'nsmsgMsgalarmnoticercpt' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNewuserforms-oid NAME ( 'nsmsgNewuserforms' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDoclientdnslookup-oid NAME ( 'nsmsgDoclientdnslookup' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMessagesizedays-oid NAME ( 'nsmsgMessagesizedays' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgBinarypath-oid NAME ( 'nsmsgBinarypath' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmstatinterval-oid NAME ( 'nsmsgMsgalarmstatinterval' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgCleanupage-oid NAME ( 'nsmsgCleanupage' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgBuffersize-oid NAME ( 'nsmsgBuffersize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDbcachesize-oid NAME ( 'nsmsgDbcachesize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSyslogfacility-oid NAME ( 'nsmsgSyslogfacility' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLdappoolsize-oid NAME ( 'nsmsgLdappoolsize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxscriptsize-oid NAME ( 'nsmsgMaxscriptsize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmnoticesender-oid NAME ( 'nsmsgMsgalarmnoticesender' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgExternalmxserverip-oid NAME ( 'nsmsgExternalmxserverip' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmdescription-oid NAME ( 'nsmsgMsgalarmdescription' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowonex-oid NAME ( 'nsmsgAllowonex' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgFilterurl-oid NAME ( 'nsmsgFilterurl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgHidehostname-oid NAME ( 'nsmsgHidehostname' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowbdat-oid NAME ( 'nsmsgAllowbdat' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgFolderpattern-oid NAME ( 'nsmsgFolderpattern' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgExpirestart-oid NAME ( 'nsmsgExpirestart' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAdmins-oid NAME ( 'nsmsgAdmins' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxcputime-oid NAME ( 'nsmsgMaxcputime' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeoutgreet-oid NAME ( 'nsmsgTimeoutgreet' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgQuotaenforcement-oid NAME ( 'nsmsgQuotaenforcement' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNumdays-oid NAME ( 'nsmsgNumdays' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAuthcachesize-oid NAME ( 'nsmsgAuthcachesize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMsgalarmthresholddirection-oid NAME ( 'nsmsgMsgalarmthresholddirection' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxlogfilesize-oid NAME ( 'nsmsgMaxlogfilesize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNummessages-oid NAME ( 'nsmsgNummessages' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxheaderlines-oid NAME ( 'nsmsgMaxheaderlines' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeoutdatasend-oid NAME ( 'nsmsgTimeoutdatasend' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSessiontimeout-oid NAME ( 'nsmsgSessiontimeout' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgPositivehostattr-oid NAME ( 'nsmsgPositivehostattr' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNtaccount-oid NAME ( 'nsmsgNtaccount' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgHopcountexceedactions-oid NAME ( 'nsmsgHopcountexceedactions' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgPlaintextloginpause-oid NAME ( 'nsmsgPlaintextloginpause' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDiskflushinterval-oid NAME ( 'nsmsgDiskflushinterval' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultmessagequota-oid NAME ( 'nsmsgDefaultmessagequota' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgInstalledlanguages-oid NAME ( 'nsmsgInstalledlanguages' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDodsn-oid NAME ( 'nsmsgDodsn' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDefaultgid-oid NAME ( 'nsmsgDefaultgid' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLocation-oid NAME ( 'nsmsgLocation' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxstateobjectsize-oid NAME ( 'nsmsgMaxstateobjectsize' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAllowexpn-oid NAME ( 'nsmsgAllowexpn' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxlogfiles-oid NAME ( 'nsmsgMaxlogfiles' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgTimeoutrcpt-oid NAME ( 'nsmsgTimeoutrcpt' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgUmask-oid NAME ( 'nsmsgUmask' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgDorewritefromusingauth-oid NAME ( 'nsmsgDorewritefromusingauth' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgEnveloperewritemethod-oid NAME ( 'nsmsgEnveloperewritemethod' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgLog-oid NAME ( 'nsmsgLog' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMessagehostname-oid NAME ( 'nsmsgMessagehostname' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgIdletimeout-oid NAME ( 'nsmsgIdletimeout' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgMaxruncountdeferred-oid NAME ( 'nsmsgMaxruncountdeferred' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNumprocesses-oid NAME ( 'nsmsgNumprocesses' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgFallbacksearchmethod-oid NAME ( 'nsmsgFallbacksearchmethod' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgNegativehostattr-oid NAME ( 'nsmsgNegativehostattr' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAuthmaildomain-oid NAME ( 'nsmsgAuthmaildomain' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgClearcontrolinterval-oid NAME ( 'nsmsgClearcontrolinterval' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgFolderurl-oid NAME ( 'nsmsgFolderurl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgListurl-oid NAME ( 'nsmsgListurl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSslusessl-oid NAME ( 'nsmsgSslusessl' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgHostrewrites-oid NAME ( 'nsmsgHostrewrites' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgAlwaysqueue-oid NAME ( 'nsmsgAlwaysqueue' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgSslport-oid NAME ( 'nsmsgSslport' ) DESC 'Netscape Messaging Server configuration defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server configuration' )
+attributeTypes: ( nsmsgPath-oid NAME 'nsmsgPath' DESC 'Netscape Messaging Server defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server' )
+attributeTypes: ( nsmsgPipePerm-oid NAME ( 'nsmsgPipePerm' ) DESC 'Netscape Messaging Server defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server' )
+attributeTypes: ( nsmsgPipeParams-oid NAME ( 'nsmsgPipeParams' ) DESC 'Netscape Messaging Server defined attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Messaging Server' )
+objectclasses: ( netscapeMessagingServer-oid NAME 'netscapeMessagingServer' DESC '' SUP top STRUCTURAL MUST ( cn $ nsServerID ) MAY ( description ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgcontainer-oid NAME 'nsmsgCfgcontainer' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfggen-oid NAME 'nsmsgCfggen' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAccounturl $ nsmsgConfigversion $ nsmsgFilterurl $ nsmsgFolderurl $ nsmsgInstalledlanguages $ nsmsgListurl $ nsmsgNewuserforms $ nsmsgSitelanguage ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgsnmp-oid NAME 'nsmsgCfgsnmp' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgContact $ nsmsgCollectiondeltatime $ nsmsgDescription $ nsmsgEnable $ nsmsgLocation $ nsmsgMtaid $ nsmsgMtaname $ nsmsgMasterhost $ nsmsgMasterport $ nsmsgOrganization $ nsmsgVersion ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgstore-oid NAME 'nsmsgCfgstore' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAdmins $ nsmsgCleanupage $ nsmsgDbcachesize $ nsmsgDbtmpdir $ nsmsgDefaultacl $ nsmsgDefaultmailboxquota $ nsmsgDefaultmessagequota $ nsmsgDefaultpartition $ nsmsgDiskflushinterval $ nsmsgExpirestart $ nsmsgQuotaexceededmsg $ nsmsgQuotaexceededmsginterval $ nsmsgQuotagraceperiod $ nsmsgQuotawarn $ nsmsgQuotaenforcement $ nsmsgQuotanotification $ nsmsgUmask $ nsmsgServiceadmingroupdn ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgexpirerule-oid NAME 'nsmsgCfgexpirerule' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgFolderpattern $ nsmsgExclusive $ nsmsgFoldersizebytes $ nsmsgMessagecount $ nsmsgMessagedays $ nsmsgMessagesize $ nsmsgMessagesizedays ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgpartition-oid NAME 'nsmsgCfgpartition' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgPath ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfguser-oid NAME 'nsmsgCfguser' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgpublic-oid NAME 'nsmsgCfgpublic' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgalias-oid NAME 'nsmsgCfgalias' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAlias ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfglog-oid NAME 'nsmsgCfglog' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgBuffersize $ nsmsgExpirytime $ nsmsgFlushinterval $ nsmsgLogdir $ nsmsgLoglevel $ nsmsgLogtype $ nsmsgMaxlogfiles $ nsmsgMaxlogfilesize $ nsmsgMaxlogsize $ nsmsgMinfreediskspace $ nsmsgRollovertime $ nsmsgSyslogfacility ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgservice-oid NAME 'nsmsgCfgservice' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAuthcachesize $ nsmsgAuthcachettl $ nsmsgDcroot $ nsmsgDefaultdomain $ nsmsgDnsresolveclient $ nsmsgLdapmemcache $ nsmsgLdapmemcachesize $ nsmsgLdapmemcachettl $ nsmsgLdappoolsize $ nsmsgListenaddr $ nsmsgLoginseparator $ nsmsgPlaintextloginpause $ nsmsgReadtimeout $ nsmsgSslpasswdfile ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgpop-oid NAME 'nsmsgCfgpop' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAllowanonymouslogin $ nsmsgBanner $ nsmsgConnLimits $ nsmsgDomainallowed $ nsmsgDomainnotallowed $ nsmsgEnable $ nsmsgIdletimeout $ nsmsgLdappoolsize $ nsmsgMaxsessions $ nsmsgMaxthreads $ nsmsgNumprocesses $ nsmsgPlaintextmincipher $ nsmsgPopminpoll $ nsmsgPort $ nsmsgSslusessl ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgimap-oid NAME 'nsmsgCfgimap' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAllowanonymouslogin $ nsmsgBanner $ nsmsgConnLimits $ nsmsgDomainallowed $ nsmsgDomainnotallowed $ nsmsgEnable $ nsmsgEnablesslport $ nsmsgIdletimeout $ nsmsgLdappoolsize $ nsmsgMaxsessions $ nsmsgMaxthreads $ nsmsgNumprocesses $ nsmsgPlaintextmincipher $ nsmsgPort $ nsmsgSslcachesize $ nsmsgSslport $ nsmsgSslusessl ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfghttp-oid NAME 'nsmsgCfghttp' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAllowadminproxy $ nsmsgAllowanonymouslogin $ nsmsgConnLimits $ nsmsgDomainallowed $ nsmsgDomainnotallowed $ nsmsgDomainsecurity $ nsmsgEnable $ nsmsgEnablesslport $ nsmsgExtrauserldapattrs $ nsmsgFullfromheader $ nsmsgIdletimeout $ nsmsgIpsecurity $ nsmsgLdappoolsize $ nsmsgMaxmessagesize $ nsmsgMaxpostsize $ nsmsgMaxsessions $ nsmsgMaxthreads $ nsmsgNumprocesses $ nsmsgPlaintextmincipher $ nsmsgPort $ nsmsgProxydomainallowed $ nsmsgResourcetimeout $ nsmsgSessiontimeout $ nsmsgSmtphost $ nsmsgSmtpport $ nsmsgSourceurl $ nsmsgSpooldir $ nsmsgSslcachesize $ nsmsgSslport $ nsmsgSourceurl $ nsmsgSslusessl ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmta-oid NAME 'nsmsgCfgmta' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAltqueues $ nsmsgAuthmaildomain $ nsmsgBanner $ nsmsgClearcontrolinterval $ nsmsgClearcontrolsafetime $ nsmsgCounterdeltatime $ nsmsgDefaultdomain $ nsmsgDeferredperiod $ nsmsgDocanonicalize $ nsmsgDoclientdnslookup $ nsmsgDodsn $ nsmsgDomainallowed $ nsmsgDomainnotallowed $ nsmsgDomainname $ nsmsgDomainlangtable $ nsmsgEnable $ nsmsgForeignpercentaddr $ nsmsgLdappoolsize $ nsmsgLdaputilconfig $ nsmsgLocaldefaultmaxruncount $ nsmsgLocaldefaultminruncount $ nsmsgMaxheaderlines $ nsmsgMaxqueuetime $ nsmsgMessagehostname $ nsmsgNetworkdefaultmaxruncount $ nsmsgNetworkdefaultminruncount $ nsmsgNumenvelopequeuefiles $ nsmsgPlaintextmincipher $ nsmsgPort $ nsmsgProtocolubeconfig $ nsmsgReserved0 $ nsmsgReserved1 $ nsmsgReserved2 $ nsmsgReserved3 $ nsmsgReserved4 $ nsmsgReserved5 $ nsmsgReserved6 $ nsmsgReserved7 $ nsmsgReserved8 $ nsmsgReserved9 $ nsmsgRolloverdelta $ nsmsgRolloversize $ nsmsgRoutstripimapfolders $ nsmsgSslusessl $ nsmsgSslusesslrelay ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmtalog-oid NAME 'nsmsgCfgmtalog' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgLog $ nsmsgMinruncount $ nsmsgMaxruncount $ nsmsgMaxruncountdeferred ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmtaautoreplyhandler-oid NAME 'nsmsgCfgmtaautoreplyhandler' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgDefaultecho $ nsmsgDefaultreply $ nsmsgDefaultvacation ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmtaerrorhandler-oid NAME 'nsmsgCfgmtaerrorhandler' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgFormsigkey $ nsmsgHopcountexceedactions $ nsmsgQuotaexceededactions $ nsmsgRenotifyinterval $ nsmsgUnknownacctsactions ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmtamboxdeliver-oid NAME 'nsmsgCfgmtamboxdeliver' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmtaprogdeliver-oid NAME 'nsmsgCfgmtaprogdeliver' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgDefaultgid $ nsmsgDefaultuid $ nsmsgShellpath $ nsmsgNtrunoptn $ nsmsgNtaccount $ nsmsgNtpassword ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmtaaccept-oid NAME 'nsmsgCfgmtaaccept' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAllowbdat $ nsmsgAllowehlo $ nsmsgAllowetrn $ nsmsgAllowexpn $ nsmsgAllowhelp $ nsmsgAllowonex $ nsmsgAllowsize $ nsmsgAllowverb $ nsmsgAllowvrfy $ nsmsgHidehostname $ nsmsgMaxbadcommands $ nsmsgMaxmessagesize $ nsmsgMinfreediskspace $ nsmsgNegativehostattr $ nsmsgPositivehostattr $ nsmsgRequirecrlf $ nsmsgTcpaccessdeniedtimeout $ nsmsgTimeoutcommand $ nsmsgTimeoutdata $ nsmsgVerifyrcpts ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmtasmtpdeliver-oid NAME 'nsmsgCfgmtasmtpdeliver' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAllowbarelf $ nsmsgAlwaysqueue $ nsmsgCheckdeferredqueue $ nsmsgDoetrn $ nsmsgExternalmxserverip $ nsmsgInternalmxserverip $ nsmsgTimeoutdata $ nsmsgTimeoutdatadot $ nsmsgTimeoutdatasend $ nsmsgTimeoutgreet $ nsmsgTimeouthelo $ nsmsgTimeoutmail $ nsmsgTimeoutquit $ nsmsgTimeoutrcpt $ nsmsgTimeoutrset $ nsmsgUsemx ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmtarouter-oid NAME 'nsmsgCfgmtarouter' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgAdddeliveredto $ nsmsgAddheaders $ nsmsgDeleteheaders $ nsmsgDorewritefromusingauth $ nsmsgDorewritesenderusingauth $ nsmsgEnveloperewritemethod $ nsmsgFallbacksearchmethod $ nsmsgHostrewrites $ nsmsgLocalmaildomains $ nsmsgMaxcontrolrecipients $ nsmsgMaxmtahops $ nsmsgNestedgroups $ nsmsgRewritetocc $ nsmsgRoutingattribute $ nsmsgSmtprewritestyle ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgmtaunixdeliver-oid NAME 'nsmsgCfgmtaunixdeliver' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgDefaultgid $ nsmsgDefaultuid $ nsmsgFilemode $ nsmsgMaildeliveryprogram $ nsmsgNeedsender $ nsmsgStripcr $ nsmsgSystemmaildir ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgreport-oid NAME 'nsmsgCfgreport' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgalarmcontainer-oid NAME 'nsmsgCfgalarmcontainer' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgMsgalarmnoticehost $ nsmsgMsgalarmnoticeport $ nsmsgMsgalarmnoticercpt $ nsmsgMsgalarmnoticesender $ nsmsgMsgalarmnoticetemplate ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgalarm-oid NAME 'nsmsgCfgalarm' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgMsgalarmdescription $ nsmsgMsgalarmstatinterval $ nsmsgMsgalarmthreshold $ nsmsgMsgalarmthresholddirection $ nsmsgMsgalarmwarninginterval ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgCfgscript-oid NAME 'nsmsgCfgscript' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn ) MAY ( nsmsgEnable $ nsmsgBinarypath $ nsmsgLoglevel $ nsmsgMaxscriptsize $ nsmsgMaxbranches $ nsmsgMaxcputime $ nsmsgMaxerrorobjectsize $ nsmsgMaxstateobjectsize ) X-ORIGIN 'Netscape Messaging Server configuration' )
+objectclasses: ( nsmsgPipeProgram-oid NAME 'nsmsgPipeProgram' DESC '' SUP top STRUCTURAL MUST ( objectclass $ cn $ nsmsgPath $ nsmsgPipePerm ) MAY ( nsmsgPipeParams ) X-ORIGIN 'Netscape Messaging Server 4.x' )
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ldap/schema/50ns-netshare.ldif b/ldap/schema/50ns-netshare.ldif
new file mode 100644
index 00000000..215a77b5
--- /dev/null
+++ b/ldap/schema/50ns-netshare.ldif
@@ -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
+#
+#
+# Schema for Netscape Netshare
+#
+dn: cn=schema
+attributeTypes: ( netshareHomeURL-oid NAME 'netshareHomeURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Netshare' )
+attributeTypes: ( netshareServerType-oid NAME 'netshareServerType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Netshare' )
+attributeTypes: ( netshareHomeTheme-oid NAME 'netshareHomeTheme' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Netshare' )
+attributeTypes: ( netsharePrivate-oid NAME 'netsharePrivate' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Netshare' )
+attributeTypes: ( netshareMemberOf-oid NAME 'netshareMemberOf' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Netshare' )
+attributeTypes: ( netshareUIConfig-oid NAME 'netshareUIConfig' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 SINGLE-VALUE X-ORIGIN 'Netscape Netshare' )
+attributeTypes: ( netsharePMNewProjParent-oid NAME 'netsharePMNewProjParent' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Netshare' )
+attributeTypes: ( netsharePMSearchBase-oid NAME 'netsharePMSearchBase' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Netshare' )
+attributeTypes: ( netsharePMProjCreationUser-oid NAME 'netsharePMProjCreationUser' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 SINGLE-VALUE X-ORIGIN 'Netscape Netshare' )
+attributeTypes: ( netsharePMAdmin-oid NAME 'netsharePMAdmin' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Netshare' )
+objectClasses: ( netshareAccount-oid NAME 'netshareAccount' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass $ netshareHomeURL ) MAY ( netshareServerType $ netshareHomeTheme $ netsharePrivate $ netshareMemberOf $ netshareUIConfig ) X-ORIGIN 'Netscape Netshare' )
+objectClasses: ( netshareProjectManagementGlobalConfig-oid NAME 'netshareProjectManagementGlobalConfig' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) MAY ( netsharePMNewProjParent $ netsharePMSearchBase $ netsharePMProjCreationUser $ netsharePMAdmin $ cn ) X-ORIGIN 'Netscape Netshare' )
diff --git a/ldap/schema/50ns-news.ldif b/ldap/schema/50ns-news.ldif
new file mode 100644
index 00000000..806b7a8d
--- /dev/null
+++ b/ldap/schema/50ns-news.ldif
@@ -0,0 +1,19 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for Netscape Collabra Server
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.191 NAME 'nsnewsACL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Collabra Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.192 NAME 'nsaclrole' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Collabra Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.193 NAME 'nsprettyname' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Collabra Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.194 NAME 'nsflags' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Collabra Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.195 NAME 'nscreator' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Collabra Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.196 NAME 'ngcomponent' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape Collabra Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.26 NAME 'nginfo' DESC 'Netscape defined objectclass' SUP top MUST ( objectClass $ ngcomponent ) MAY ( nsnewsACL $ subtreeACI $ description $ nsaclrole $ nsprettyname $ nsflags $ nscreator ) X-ORIGIN 'Netscape Collabra Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.27 NAME 'netscapeNewsServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectClass ) X-ORIGIN 'Netscape Collabra Server' )
diff --git a/ldap/schema/50ns-proxy.ldif b/ldap/schema/50ns-proxy.ldif
new file mode 100644
index 00000000..d9bc6d7e
--- /dev/null
+++ b/ldap/schema/50ns-proxy.ldif
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for Netscape Proxy Server
+#
+dn: cn=schema
+objectClasses: ( 2.16.840.1.113730.3.2.28 NAME 'netscapeProxyServer' DESC 'Netscape defined objectclass' SUP top MUST ( objectclass ) X-ORIGIN 'Netscape Proxy Server' )
diff --git a/ldap/schema/50ns-value.ldif b/ldap/schema/50ns-value.ldif
new file mode 100644
index 00000000..36aea5d3
--- /dev/null
+++ b/ldap/schema/50ns-value.ldif
@@ -0,0 +1,24 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Netscape servers "value item" schema
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.243 NAME 'nsValueCIS' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.244 NAME 'nsValueCES' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.245 NAME 'nsValueTel' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.50 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.246 NAME 'nsValueInt' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.247 NAME 'nsValueBin' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.5 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.248 NAME 'nsValueDN' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.12 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.249 NAME 'nsValueType' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.250 NAME 'nsValueDefault' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.251 NAME 'nsValueFlags' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.252 NAME 'nsValueDescription' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.253 NAME 'nsValueSyntax' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape servers - value item' )
+attributeTypes: ( 2.16.840.1.113730.3.1.254 NAME 'nsValueHelpURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape servers - value item' )
+objectClasses: ( 2.16.840.1.113730.3.2.45 NAME 'nsValueItem' DESC 'Netscape defined objectclass' SUP top MUST ( objectClass $ cn ) MAY ( nsValueCIS $ nsValueCES $ nsValueTel $ nsValueInt $ nsValueBin $ nsValueDN $ nsValueType $ nsValueSyntax $ nsValueDescription $ nsValueHelpURL $ nsValueFlags $ nsValueDefault ) X-ORIGIN 'Netscape servers - value item' )
diff --git a/ldap/schema/50ns-wcal.ldif b/ldap/schema/50ns-wcal.ldif
new file mode 100644
index 00000000..40dacb3e
--- /dev/null
+++ b/ldap/schema/50ns-wcal.ldif
@@ -0,0 +1,26 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for Netscape Web Calendaring
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.537 NAME 'nswcalCALID' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 2.16.840.1.113730.3.1.538 NAME 'nswcalExtendedUserPrefs' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 2.16.840.1.113730.3.1.539 NAME 'nswcalDisallowAccess' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 2.16.840.1.113730.3.1.540 NAME 'nswcalHost' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 2.16.840.1.113730.3.1.541 NAME 'nswcalQuota' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 1.2.840.113556.1.4.478 NAME 'calCalURI' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 1.2.840.113556.1.4.479 NAME 'calFBURL' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 1.2.840.113556.1.4.480 NAME 'calCAPURI' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 1.2.840.113556.1.4.481 NAME 'calCalAdrURI' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 1.2.840.113556.1.4.482 NAME 'calOtherCalURIs' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 1.2.840.113556.1.4.483 NAME 'calOtherFBURLs' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 1.2.840.113556.1.4.484 NAME 'calOtherCAPURIs' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+attributeTypes: ( 1.2.840.113556.1.4.485 NAME 'calOtherCalAdrURIs' DESC 'Netscape defined attribute type' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Web Calendaring' )
+objectClasses: ( 2.16.840.1.113730.3.2.83 NAME 'nswcalUser' DESC 'Netscape defined objectclass' SUP top MUST ( objectClass ) MAY ( cn $ givenName $ mail $ preferredlanguage $ sn $ uid $ userPassword $ nswcalCALID $ nswcalDisallowAccess $ nswcalExtendedUserPrefs $ nslicensedfor $ nswcalHost $ nswcalQuota ) X-ORIGIN 'Netscape Web Calendaring' )
+objectClasses: ( 1.2.840.113556.1.5.87 NAME 'calEntry' DESC 'Netscape defined objectclass' SUP top MUST ( objectClass ) MAY ( calCalURI $ calFBURL $ calCAPURI $ calCalAdrURI $ calOtherCalURIs $ calOtherFBURLs $ calOtherCAPURIs $ calOtherCalAdrURIs ) X-ORIGIN 'Netscape Web Calendaring' )
diff --git a/ldap/schema/50ns-web.ldif b/ldap/schema/50ns-web.ldif
new file mode 100644
index 00000000..33a80db7
--- /dev/null
+++ b/ldap/schema/50ns-web.ldif
@@ -0,0 +1,14 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Schema for Netscape Web Server
+#
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.812 NAME 'netscapeReversiblePassword' DESC 'password for HTTP Digest/MD5 authentication' EQUALITY octetStringMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.40 X-ORIGIN 'Netscape Web Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.29 NAME 'netscapeWebServer' DESC 'Netscape defined objectclass' SUP top MUST ( cn $ nsServerID ) MAY ( description $ nsServerPort ) X-ORIGIN 'Netscape Web Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.154 NAME 'netscapeReversiblePasswordObject' DESC 'object that contains an netscapeReversiblePassword' AUXILIARY MAY netscapeReversiblePassword X-ORIGIN 'Netscape Web Server' )
diff --git a/ldap/schema/51ns-calendar.ldif b/ldap/schema/51ns-calendar.ldif
new file mode 100644
index 00000000..63bd4217
--- /dev/null
+++ b/ldap/schema/51ns-calendar.ldif
@@ -0,0 +1,69 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Last modified March 2001
+#
+# This file contains the DS 4.x schema converted to DS5.x format using the migrateSchemaTo5
+# script.
+#
+# THESE SCHEMA DEFINITIONS HAVE NOT BEEN CHECKED TO SEE IF THEY EXIST IN THE NEW DS 5.x DIRECTORY
+# BEFORE LOADING THIS SCHEMA YOU SHOULD CHECK THE SCHEMA IN DS 5.x FOR THE EXISTANCE OF ANY ATTRIBUTES
+# OR OBJECTCLASSES IN THIS FILE. IF THEY ALREADY EXIST THEY SHOULD BE REMOVED FROM THIS FILE.
+#
+# In addition if this file has the X-ORIGIN setting for all attributes and objectclasses set to 'user defined'
+# these definitions will be editable via the console and could potentially be re-saved to the 99user.ldif file.
+# If you want to modify these definitions using the console or LDAP, you should cut and paste these
+# definitions into the 99user.ldif file. See the Deployment Guide for more information.
+#
+# SCHEMA FILE 51ns-calendar.ldif Created on Wed Jan 30 17:30:35 2002
+dn: cn=schema
+attributeTypes: ( 2.16.840.1.113730.3.1.798 NAME ( 'icsAnonymousLogin' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.755 NAME ( 'icsStatus' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.744 NAME ( 'icsFreeBusy' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.750 NAME ( 'icsRecurrenceBound' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2029 NAME ( 'icsDWPHost' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.747 NAME ( 'icsMandatoryView' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.725 NAME ( 'icsAlias' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.757 NAME ( 'icsTimezone' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2031 NAME ( 'icsDomainNames' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.753 NAME ( 'icsSet' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.751 NAME ( 'icsRecurrenceDate' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.733 NAME ( 'icsContact' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.800 NAME ( 'icsCapacity' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.742 NAME ( 'icsExtendedUserPrefs' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.735 NAME ( 'icsDefaultSet' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.738 NAME ( 'icsExtended' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.728 NAME ( 'icsAnonymousAllowWrite' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.746 NAME ( 'icsMandatorySubscribed' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.732 NAME ( 'icsAnonymousSet' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.724 NAME ( 'icsAdminRole' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.740 NAME ( 'icsExtendedGroupPrefs' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.736 NAME ( 'icsDomainAllowed' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.729 NAME ( 'icsAnonymousCalendar' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.756 NAME ( 'icsSubscribed' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.743 NAME ( 'icsFirstDay' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.754 NAME ( 'icsSourceHtml' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.739 NAME ( 'icsExtendedDomainPrefs' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.748 NAME ( 'icsQuota' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.726 NAME ( 'icsAllowedServiceAccess' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.752 NAME ( 'icsSessionTimeout' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.727 NAME ( 'icsAllowRights' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.737 NAME ( 'icsDomainNotAllowed' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2032 NAME ( 'icsRegularExpressions' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.734 NAME ( 'icsDefaultAccess' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.741 NAME ( 'icsExtendedResourcePrefs' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.2033 NAME ( 'icsPartition' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.731 NAME ( 'icsCalendar' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.730 NAME ( 'icsAnonymousDefaultSet' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.745 NAME ( 'icsGeo' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.758 NAME ( 'inetResourceStatus' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+attributeTypes: ( 2.16.840.1.113730.3.1.749 NAME ( 'icsPreferredHost' ) DESC 'Netscape Calendar Server Attribute' SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 SINGLE-VALUE X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.141 NAME 'icsCalendarUser' DESC 'Netscape Calendar Server Schema' SUP top STRUCTURAL MUST ( ) MAY ( cn $ givenName $ mail $ preferredlanguage $ sn $ uid $ userPassword $ icsAllowedServiceAccess $ icsCalendar $ icsDefaultSet $ icsDWPHost $ icsExtended $ icsExtendedUserPrefs $ icsFirstDay $ icsFreeBusy $ icsGeo $ icsPreferredHost $ icsQuota $ icsSet $ icsStatus $ icsSubscribed $ icsTimezone $ nswcalDisallowAccess ) X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.142 NAME 'inetResource' DESC 'Netscape Calendar Server Schema' SUP top STRUCTURAL MUST ( cn ) MAY ( telephoneNumber $ facsimileTelephoneNumber $ mail $ postalAddress $ inetResourceStatus ) X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.143 NAME 'icsCalendarResource' DESC 'Netscape Calendar Server Schema' SUP top STRUCTURAL MUST ( ) MAY ( cn $ uid $ icsAlias $ icsCalendar $ icsCapacity $ icsContact $ icsDWPHost $ icsExtended $ icsExtendedResourcePrefs $ icsGeo $ icsPreferredHost $ icsQuota $ icsStatus $ icsTimezone ) X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.144 NAME 'icsCalendarDomain' DESC 'Netscape Calendar Server Schema' SUP top STRUCTURAL MUST ( ) MAY ( icsAllowedServiceAccess $ icsAllowRights $ icsAnonymousAllowWrite $ icsAnonymousCalendar $ icsAnonymousDefaultSet $ icsAnonymousLogin $ icsAnonymousSet $ icsExtended $ icsExtendedDomainPrefs $ icsDefaultAccess $ icsDomainAllowed $ icsDomainNotAllowed $ icsDWPHost $ icsMandatorySubscribed $ icsMandatoryView $ icsPreferredHost $ icsQuota $ icsRecurrenceBound $ icsRecurrenceDate $ icsSessionTimeout $ icsSourceHtml $ icsStatus $ icsTimezone ) X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.145 NAME 'icsAdministrator' DESC 'Netscape Calendar Server Schema' SUP top STRUCTURAL MUST ( ) MAY ( icsAdminRole $ icsExtended $ icsExtendedGroupPrefs ) X-ORIGIN 'Netscape Calendar Server' )
+objectClasses: ( 2.16.840.1.113730.3.2.306 NAME 'icsCalendarDWPServer' DESC 'Netscape Calendar Server Schema' SUP top STRUCTURAL MUST ( ) MAY ( icsDWPHost $ icsRegularExpressions $ icsExtended $ icsDomainNames ) X-ORIGIN 'Netscape Calendar Server' )
diff --git a/ldap/schema/99user.ldif b/ldap/schema/99user.ldif
new file mode 100644
index 00000000..f3abb9d3
--- /dev/null
+++ b/ldap/schema/99user.ldif
@@ -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
+#
+#
+# User-defined schema
+#
+dn: cn=schema
diff --git a/ldap/schema/ns-calendar-globopt.conf b/ldap/schema/ns-calendar-globopt.conf
new file mode 100644
index 00000000..0bdb7dd9
--- /dev/null
+++ b/ldap/schema/ns-calendar-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
+index nsCalXItemId pres,eq,sub
diff --git a/ldap/schema/ns-certificate-globopt.conf b/ldap/schema/ns-certificate-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/schema/ns-certificate-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/schema/ns-compass-globopt.conf b/ldap/schema/ns-compass-globopt.conf
new file mode 100644
index 00000000..4d2e1e21
--- /dev/null
+++ b/ldap/schema/ns-compass-globopt.conf
@@ -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
+#
+# Used by Netscape Directory Server
+index pipuid pres,eq,sub
+index pipstatus eq
+
diff --git a/ldap/schema/ns-directory-globopt.conf b/ldap/schema/ns-directory-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/schema/ns-directory-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/schema/ns-mail-globopt.conf b/ldap/schema/ns-mail-globopt.conf
new file mode 100644
index 00000000..2e6cac65
--- /dev/null
+++ b/ldap/schema/ns-mail-globopt.conf
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Messaging Server
+index mailAlternateAddress eq
+index mailHost eq
+#index uid,mail eq
+#index uniquemember,member eq
diff --git a/ldap/schema/ns-mcd-li-globopt.conf b/ldap/schema/ns-mcd-li-globopt.conf
new file mode 100644
index 00000000..57a75555
--- /dev/null
+++ b/ldap/schema/ns-mcd-li-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Index required by Mission Control Desktop: Location Independence
+index nsLIProfileName eq
diff --git a/ldap/schema/ns-media-globopt.conf b/ldap/schema/ns-media-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/schema/ns-media-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/schema/ns-news-globopt.conf b/ldap/schema/ns-news-globopt.conf
new file mode 100644
index 00000000..b21de8c4
--- /dev/null
+++ b/ldap/schema/ns-news-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Collabra Server
+#index uniquemember,member eq
+
diff --git a/ldap/schema/ns-proxy-globopt.conf b/ldap/schema/ns-proxy-globopt.conf
new file mode 100644
index 00000000..65ba5064
--- /dev/null
+++ b/ldap/schema/ns-proxy-globopt.conf
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Directory Server
+
diff --git a/ldap/schema/ns-wcal-globopt.conf b/ldap/schema/ns-wcal-globopt.conf
new file mode 100644
index 00000000..57a3183e
--- /dev/null
+++ b/ldap/schema/ns-wcal-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#used by Netscape Calendar Hosting Server
+
+index nswcalCALID pres,eq
diff --git a/ldap/schema/ns-web-globopt.conf b/ldap/schema/ns-web-globopt.conf
new file mode 100644
index 00000000..6c18733f
--- /dev/null
+++ b/ldap/schema/ns-web-globopt.conf
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Used by Netscape Web Server
+#index uniquemember,member eq
+
diff --git a/ldap/schema/slapd-collations.conf b/ldap/schema/slapd-collations.conf
new file mode 100644
index 00000000..7cfcb22f
--- /dev/null
+++ b/ldap/schema/slapd-collations.conf
@@ -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
+#
+# Used by Netscape Directory Server
+#######################################################################
+# Collations
+#######################################################################
+# collation language country variant strength decomposition oid oid ...
+
+collation "" "" "" 1 3 2.16.840.1.113730.3.3.2.0.1 default
+collation ar "" "" 1 3 2.16.840.1.113730.3.3.2.1.1 ar
+collation be "" "" 1 3 2.16.840.1.113730.3.3.2.2.1 be
+collation bg "" "" 1 3 2.16.840.1.113730.3.3.2.3.1 bg
+collation ca "" "" 1 3 2.16.840.1.113730.3.3.2.4.1 ca
+collation cs "" "" 1 3 2.16.840.1.113730.3.3.2.5.1 cs
+collation da "" "" 1 3 2.16.840.1.113730.3.3.2.6.1 da
+collation de "" "" 1 3 2.16.840.1.113730.3.3.2.7.1 de
+collation de AT "" 1 3 2.16.840.1.113730.3.3.2.8.1 de-AT
+collation de CH "" 1 3 2.16.840.1.113730.3.3.2.9.1 de-CH
+collation el "" "" 1 3 2.16.840.1.113730.3.3.2.10.1 el
+collation en "" "" 1 3 2.16.840.1.113730.3.3.2.11.1 en en-US
+collation en CA "" 1 3 2.16.840.1.113730.3.3.2.12.1 en-CA
+collation en GB "" 1 3 2.16.840.1.113730.3.3.2.13.1 en-GB
+collation en IE "" 1 3 2.16.840.1.113730.3.3.2.14.1 en-IE
+collation es "" "" 1 3 2.16.840.1.113730.3.3.2.15.1 es es-ES
+collation et "" "" 1 3 2.16.840.1.113730.3.3.2.16.1 et
+collation fi "" "" 1 3 2.16.840.1.113730.3.3.2.17.1 fi
+collation fr "" "" 1 3 2.16.840.1.113730.3.3.2.18.1 fr fr-FR
+collation fr BE "" 1 3 2.16.840.1.113730.3.3.2.19.1 fr-BE
+collation fr CA "" 1 3 2.16.840.1.113730.3.3.2.20.1 fr-CA
+collation fr CH "" 1 3 2.16.840.1.113730.3.3.2.21.1 fr-CH
+collation hr "" "" 1 3 2.16.840.1.113730.3.3.2.22.1 hr
+collation hu "" "" 1 3 2.16.840.1.113730.3.3.2.23.1 hu
+collation is "" "" 1 3 2.16.840.1.113730.3.3.2.24.1 is
+collation it "" "" 1 3 2.16.840.1.113730.3.3.2.25.1 it
+collation it CH "" 1 3 2.16.840.1.113730.3.3.2.26.1 it-CH
+collation iw "" "" 1 3 2.16.840.1.113730.3.3.2.27.1 iw
+collation ja "" "" 1 3 2.16.840.1.113730.3.3.2.28.1 ja
+collation ko "" "" 1 3 2.16.840.1.113730.3.3.2.29.1 ko
+collation lt "" "" 1 3 2.16.840.1.113730.3.3.2.30.1 lt
+collation lv "" "" 1 3 2.16.840.1.113730.3.3.2.31.1 lv
+collation mk "" "" 1 3 2.16.840.1.113730.3.3.2.32.1 mk
+collation nl "" "" 1 3 2.16.840.1.113730.3.3.2.33.1 nl
+collation nl BE "" 1 3 2.16.840.1.113730.3.3.2.34.1 nl-BE
+collation no "" "" 1 3 2.16.840.1.113730.3.3.2.35.1 no
+collation no NO B 1 3 2.16.840.1.113730.3.3.2.36.1 no-NO-B
+collation no NO NY 1 3 2.16.840.1.113730.3.3.2.37.1 no-NO-NY
+collation pl "" "" 1 3 2.16.840.1.113730.3.3.2.38.1 pl
+collation ro "" "" 1 3 2.16.840.1.113730.3.3.2.39.1 ro
+collation ru "" "" 1 3 2.16.840.1.113730.3.3.2.40.1 ru
+collation sh "" "" 1 3 2.16.840.1.113730.3.3.2.41.1 sh
+collation sk "" "" 1 3 2.16.840.1.113730.3.3.2.42.1 sk
+collation sl "" "" 1 3 2.16.840.1.113730.3.3.2.43.1 sl
+collation sq "" "" 1 3 2.16.840.1.113730.3.3.2.44.1 sq
+collation sr "" "" 1 3 2.16.840.1.113730.3.3.2.45.1 sr
+collation sv "" "" 1 3 2.16.840.1.113730.3.3.2.46.1 sv
+collation tr "" "" 1 3 2.16.840.1.113730.3.3.2.47.1 tr
+collation uk "" "" 1 3 2.16.840.1.113730.3.3.2.48.1 uk
+collation zh "" "" 1 3 2.16.840.1.113730.3.3.2.49.1 zh
+collation zh TW "" 1 3 2.16.840.1.113730.3.3.2.50.1 zh-TW
+
+collation "" "" "" 3 3 2.16.840.1.113730.3.3.2.0.3
+collation en "" "" 3 3 2.16.840.1.113730.3.3.2.11.3
diff --git a/ldap/servers/Makefile b/ldap/servers/Makefile
new file mode 100644
index 00000000..a02d82c8
--- /dev/null
+++ b/ldap/servers/Makefile
@@ -0,0 +1,90 @@
+#
+# 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 ldap/servers
+#
+
+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
+
+ifeq ($(ARCH), WINNT)
+PRE_SLAPD_EXTRAS=_ntmsgdll
+POST_SLAPD_EXTRAS=_ntwdog _ntperfdll
+endif
+
+ifeq ($(ARCH), SOLARIS)
+PRE_SLAPD_EXTRAS=_libsh_stub
+endif
+
+all: $(PRE_SLAPD_EXTRAS) _slapd $(POST_SLAPD_EXTRAS) _backends _plugins _snmp _slapdtools
+
+
+ifeq ($(ARCH), HPUX)
+# slapd depends on liblcoll.sl on HPUX....
+_slapd: _collation_plugin
+ cd slapd; $(MAKE) $(MFLAGS) all
+else
+_slapd:
+ cd slapd; $(MAKE) $(MFLAGS) all
+endif
+
+_collation_plugin:
+ cd plugins/collation; $(MAKE) $(MFLAGS) all
+
+_backends:
+ cd slapd/back-ldbm; $(MAKE) $(MFLAGS) all
+# we aren't using back-ldif yet
+# cd slapd/back-ldif; $(MAKE) $(MFLAGS) all
+
+_plugins:
+ cd plugins; $(MAKE) $(MFLAGS) all
+
+_snmp:
+ cd snmp; $(MAKE) $(MFLAGS) all
+
+_slapdtools:
+ cd slapd/tools; $(MAKE) $(MFLAGS) all
+
+ifeq ($(ARCH), WINNT)
+_ntmsgdll:
+ cd slapd/ntmsgdll; $(MAKE) $(MFLAGS) all
+
+_ntwdog:
+ cd slapd/ntwdog; $(MAKE) $(MFLAGS) all
+
+_ntperfdll:
+ cd slapd/ntperfdll; $(MAKE) $(MFLAGS) all
+endif
+
+ifeq ($(ARCH), SOLARIS)
+_libsh_stub:
+ cd slapd/libsh_stub; $(MAKE) $(MFLAGS) all
+endif
+
+
+clean:
+ cd slapd; $(MAKE) $(MFLAGS) clean
+ifeq ($(ARCH), WINNT)
+ cd slapd/ntmsgdll; $(MAKE) $(MFLAGS) clean
+ cd slapd/ntwdog; $(MAKE) $(MFLAGS) clean
+ cd slapd/ntperfdll; $(MAKE) $(MFLAGS) clean
+endif
+ifeq ($(ARCH), SOLARIS)
+ cd slapd/libsh_stub; $(MAKE) $(MFLAGS) clean
+endif
+ cd slapd/back-ldbm; $(MAKE) $(MFLAGS) clean
+ cd slapd/back-ldif; $(MAKE) $(MFLAGS) clean
+ cd plugins; $(MAKE) $(MFLAGS) clean
+ cd slapd/tools; $(MAKE) $(MFLAGS) clean
diff --git a/ldap/servers/plugins/Makefile b/ldap/servers/plugins/Makefile
new file mode 100644
index 00000000..051f3b70
--- /dev/null
+++ b/ldap/servers/plugins/Makefile
@@ -0,0 +1,101 @@
+#
+# 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 and LDAP SDK libraries
+#
+
+MCOM_ROOT = ../../../..
+LDAP_SRC = $(MCOM_ROOT)/ldapserver/ldap
+
+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
+
+all: _referint _collation _syntaxes _passthru _utils _uiduniq _roles _acl _replication _cos _pwdstorage _rever _chainingdb _distrib _retrocl _statechange _http _presence _views
+
+_utils:
+ cd shared; $(MAKE) $(MFLAGS) all
+_rever:
+ cd rever; $(MAKE) $(MFLAGS) all
+
+_chainingdb:
+ cd chainingdb; $(MAKE) $(MFLAGS) all
+
+_referint:
+ cd referint; $(MAKE) $(MFLAGS) all
+
+_collation:
+ cd collation; $(MAKE) $(MFLAGS) all
+
+_syntaxes:
+ cd syntaxes; $(MAKE) $(MFLAGS) all
+
+_passthru:
+ cd passthru; $(MAKE) $(MFLAGS) all
+
+_uiduniq:
+ cd uiduniq; $(MAKE) $(MFLAGS) all
+
+_replication:
+ cd replication; $(MAKE) $(MFLAGS) all
+
+_acl:
+ cd acl; $(MAKE) $(MFLAGS) all
+
+_pwdstorage:
+ cd pwdstorage; $(MAKE) $(MFLAGS) all
+
+_distrib:
+ cd distrib; $(MAKE) $(MFLAGS) all
+
+_roles:
+ cd roles; $(MAKE) $(MFLAGS) all
+
+_cos:
+ cd cos; $(MAKE) $(MFLAGS) all
+
+_statechange:
+ cd statechange; $(MAKE) $(MFLAGS) all
+
+_retrocl:
+ cd retrocl; $(MAKE) $(MFLAGS) all
+
+_http:
+ cd http; $(MAKE) $(MFLAGS) all
+
+_presence:
+ cd presence; $(MAKE) $(MFLAGS) all
+
+_views:
+ cd views; $(MAKE) $(MFLAGS) all
+
+clean:
+ cd rever; $(MAKE) $(MFLAGS) clean
+ cd referint; $(MAKE) $(MFLAGS) clean
+ cd collation; $(MAKE) $(MFLAGS) clean
+ cd syntaxes; $(MAKE) $(MFLAGS) clean
+ cd passthru; $(MAKE) $(MFLAGS) clean
+ cd shared; $(MAKE) $(MFLAGS) clean
+ cd uiduniq; $(MAKE) $(MFLAGS) clean
+ cd replication; $(MAKE) $(MFLAGS) clean
+ cd acl; $(MAKE) $(MFLAGS) clean
+ cd cos; $(MAKE) $(MFLAGS) clean
+ cd pwdstorage; $(MAKE) $(MFLAGS) clean
+ cd roles; $(MAKE) $(MFLAGS) clean
+ cd chainingdb; $(MAKE) $(MFLAGS) clean
+ cd distrib; $(MAKE) $(MFLAGS) clean
+ cd retrocl; $(MAKE) $(MFLAGS) clean
+ cd statechange; $(MAKE) $(MFLAGS) clean
+ cd presence; $(MAKE) $(MFLAGS) clean
+ cd http; $(MAKE) $(MFLAGS) clean
+ cd views; $(MAKE) $(MFLAGS) clean
+
+veryclean: clean
diff --git a/ldap/servers/plugins/acl/ACL-Notes b/ldap/servers/plugins/acl/ACL-Notes
new file mode 100644
index 00000000..e275c967
--- /dev/null
+++ b/ldap/servers/plugins/acl/ACL-Notes
@@ -0,0 +1,215 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+
+Date What ?
+===================================
+10/15/98 - Created the ACL plugin
+ - Created a new file aclplugin.c and split the old
+ acl.c to acl.c & aclparse.c files.
+ - Merged changes made upt 4.0B2
+10/21/98 - Added USERATTR rule.
+
+
+02/01/99 - Cleanup needed to be done in 5.0 to make it a real plugin
+=====================================================================================
+1. Do not use slap.h but use slapi-plugin.h. This will require
+ some work. Work involves
+ 1) Making the ACLCB an extensible object of CONN struct
+ 2) Remove reference of Connection & operation struct
+ 3) Need slapi plugin apis to get the IP and DNS so that
+ we can evaluate it in the LASes.
+ 4) Need new option to get values of conn , op & pb stuct like
+ cert, authtype,
+
+2. Make ACLPB hang from the Operation struct instead of the PBlock.
+3. Make ACLCB an extensible object of CONN struct and remove any reference
+ about acl private info.
+
+4. I implemented the Userattr rule before even deciding if we need in 5.0
+ or not. I think it is useful. The documents those were based on are
+ in http://jazz/users/prasanta/acl_manage_filter
+
+5. Move acllas_dn_parent to the libslapd. This is duplicated code and is
+ BAAAD.
+
+6. Use the new normalized dn code so that we don't have to it over and over again.
+ We have to very careful ins slapi_access_allowed() as we keep the dn around and
+ free it later ( we can use dn by ref ).
+
+7. Merge from DS4.1 ( proxy auth) to DS 5.0.
+
+8. Miscs
+ a) can we use the SDK URL parsing code ?
+ b) Merge teh printing routines ( it's all over ).
+
+My estimate for doing the above cleanup will require anywhere between 5 to 8 days.
+Run the ACL tests after all the changes -- that is a MUST.
+===============================
+04/28/99
+
+ -- All the work descibed above is done.
+ -- Also
+ a) Created a Pool pf ACLPB one of which is grabed at the init time.
+ b) Created a global lockarary which takes care of the concurreny issue between
+ aclpb & aclcb
+ c) Fixed plugin init.
+
+
+I think the userattr rule should be made generic
+
+ useAttr = "attrName#Type"
+
+ <Type> :== DN | GROUP | ROLE | URL | <value>
+ <value> :== < any printable String>
+
+Example:
+ userAttr = "manager#DN" --- similar to userdnattr
+ userAttr = "owner#GROUP" --- similar to groupdnattr
+ userAttr = "attr#ROLE" --- The value of attr contains a role definition
+ userAttr = "myattr#URL" --- The value contains a URL or filter
+ userAttr = "OU#Directory Server"
+ --- In this case the client's OU and the
+ resource entry's OU must have
+ "Directory Server" value.
+
+ This way we can get rid of userdnattr and groupdnattr and accomplish a
+ lot with a single rule.
+
+At this point, we are done with the changes and waiting for what needs to be
+done in 5.0.
+=================================
+06/01/1999
+ -- Split the code into smaller modules
+ ( aclanom, aclgroup, aclinit, ...)
+ --- The ACLs are read and kept in a AVL tree.
+ --- Few bugs fixed in the acl_scan_match code.
+
+================================================
+07/02/99
+
+ -- Added support for parameterized bind rules.
+ -- Added support for caching of ATTR rules using recompute.S
+
+ What's left for 5.0
+ -------------------
+ 1. Support for roles
+ 2. Re-architect user/group cache
+ 3. startup in multiple threads ( low priority)
+ 4. look at add/delete/modrdn operations.
+ 5. cleanup:
+ - revist all the debug statements
+ - new tests etc.
+ 6. UI work
+
+============
+commit:14/12/99 rbyrne
+
+. Added targattrfilters keyword for value based acls.
+ Required also slapi_filter_apply(), slapi_get_attribute_type()
+ and slapi_attr_syntax_normalize() in slapd (filter.c and attrsyntax.c).
+. Memory leak fix in acl.c for PListInit() call--see comments in code.
+. made access an int on it's own to give room for expansion
+ (see aci_access and aclpb_access)
+. files: ACL-Notes, acl.c acl.h acl-ext.c aclanom.c acllas.c acllist.c aclparse.c aclutil.c slapd/attrsyntax.c slapd/slapi-plugin.h slapd/filter.c slapd/libslapd.def
+
+===
+commit: Mon 20th Dec 199
+. aclparse.c: add proxy back to acl_access2str
+. filter.c: get_filter() does not recurse anymore--get_fitler_internal(), get_filter_list()
+do the recursion...this way testing for ldapsubentry works.
+. aclinit.c: now have filter (|(aci=*)(objectclass=ldapsubentry)) in
+aclinit_search_and_insert_aci(). This means that when slapi_search_internal_callback()
+stops returning subentries by default, we will still get them as we have the correct filter.
+
+===
+commit: 12/01/2000:
+. aclplugin.c: fix for proxyauth bug in aclplugin_preop_search() and
+acl_plugin_preop_modify()--the proxy_dn and dn were swapped.
+. acl_ext.c: Also, when we PListAssignValue() on DS_ATTR_USERDN in acl_init_aclpb(),
+we should pass it a dn from aclpb_sdn, NOT the dn passed into acl_init_aclpb() which
+gets freed after the call to acl_init_acpb(). JAlso here need to be careful thatif dn contains NULL that we indicate this in aclpb_sdn by setting dn to a non-NULL empty string ("") which the code takes to be anon.
+. checked that none of the PList objects (DS_PROP_ACLPB, DS_ATTR_USERDN, DS_ATTR_ENTRY) have mem leak problems.
+. acl.c, acllas.c, aclproxy.c: removed some #ifdef 0 and comments--tidy up but
+no code changes.
+. acl_ext.c: in acl__done_aclpb() we need to PListDleteProp() on ACL_ATTR_IP
+and ACL_ATTR_DNS. This is because if LASIpEval/ACL_GetAttribute() and
+LASDnsEval/ACL_GetAttribute() see that these properties exist, they do
+not bother calling the respective Getter() function. So, everytime
+the aclpb is reused and ip or dns eval is required, the old value is used (
+or whatever hjappens to be in the memory.). Tested--works fine now with ip and dns keywords. ALso tested that when the same user tries an a non-allowed machine he is not allowed by accident (as he was before).
+. in schema.c/oc_find(): normalize the objectclass name before looking for it. Otherwise
+if there's a trailing space in the oc name, you won't dfind it.
+
+===
+commit:
+
+. aclparse.c: fix for syntax.ksh tp6 test: if there is no "version" in an aci item, reject it.
+. acllas.c: in DS_UserDnEval() now call slapi_normalize_dn() when comparing param strings and
+ ordinary dns.
+. acl_ext.c: when seeting DS_USER_DN_ATTR, get the ndn, the normalized form.
+
+====
+commit: 7/02/2000
+anom profile and groupdn != don't work together! Bug 381830 in 4.X
+. acl.h: new bit in aci_type to mark as below.
+. aclparse.c: mark an aci if it's like deny() groupdn != blah
+. aclanom.c: if marked like that cancel anom profile (just like userdn !=)
+==
+. removed these for the mo...
+commit:
+. acllas.c: now get the vattrs via slapi_vattr_merge_copy() when testing the client entry.
+. vattr.c: assign i the length of the list:i = type_context.list_length;
+. entry.c: slapi_entry_add_valueset()
+
+==
+
+commit: 03/03/2000
+. support for roledn in acis.
+===
+. acllist: in slapi_sdn_free(&aciListHead->acic_sdn); gbeelato's mem leak fix.
+commited
+
+=====
+
+committed: 17/008/00
+. support for $dn: aclutil.c, aclparse.c, acllist.c, acllas.c, acl.c, acl.h
+. acl_ext.c:Make sure aclpb_search_base is initialized to NULL in aclpb__malloc()
+. acl.c: set_result_status: wrong bit masks were being used in a_eval->attrEval_s_astatus etc.
+ acl__attr_cached_result(): in the attr==NULL case, need to test for potential
+"recompute" case of attribute--this happens if it's a param or attr style aci.
+
+========
+commited
+Support for dynamic backends:
+. acllist.c, aclinit.c, libslapd.def, control.c, slapi-plugin.h:
+ acl_be_state_change_fnc(), slapi_build_control_from_berval() etc.
+. aclanom.c: logical error in aclanom_match_profile() was causing misctest4 to fail.
+. acl_ext.c:fix mem leak by calling acl_clean_aclEval_control() in acl_ext_conn_desctructor()
+.
+===
+committed:24 Aug 2000
+now SLAPI_ACL_ALL (allow(all)) does NOT include proxy right
+
+==
+committed: 30 Aug 2000
+. acl.c: new print_access_control_Summary() routine to display final acl status. Gets the proxy
+ stuff right too.
+ in acl__resource_match_aci() always test the TARGET_FILTER case, the old cod ethere was wrong.
+==
+. add support for macros to userdn ldapurl keyword.
+
+
+==
+Committed:
+. Sep 07 2000: Support for $attr in macros.
+. Sep 15 2000: Support for aci macros in targetfilter keyword.
+. Sep 18 2000: improve ret code handling in __aclinit_handler--stops spurious error message.
+
+
+--eof
diff --git a/ldap/servers/plugins/acl/Makefile b/ldap/servers/plugins/acl/Makefile
new file mode 100644
index 00000000..bdfe2dc0
--- /dev/null
+++ b/ldap/servers/plugins/acl/Makefile
@@ -0,0 +1,96 @@
+#
+# 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 acl-plugin.so acl plugins
+#
+
+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 = $(OBJDIR)/lib/libacl
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+# ACL plugin depends on libadminutil
+MCC_INCLUDE += $(ADMINUTIL_INCLUDE)
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./libacl.def
+endif
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd -I$(ACLINC)
+
+ACL_OBJS= acl.o acllas.o aclutil.o aclplugin.o aclparse.o acl_ext.o aclproxy.o \
+ aclinit.o aclgroup.o aclanom.o acllist.o acleffectiverights.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(ACL_OBJS))
+
+ifeq ($(ARCH), WINNT)
+LIBACL_DLL_OBJ = $(addprefix $(OBJDEST)/, acldllmain.o)
+endif
+
+LIBACL= $(addprefix $(LIBDIR)/, $(ACL_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(NSPRLINK) $(LDAP_LIBAVL) $(LDAP_SDK_LIBLDAP_DLL)
+endif
+
+# ACL plugin depends on libadminutil (through libns-httpd)
+EXTRA_LIBS_DEP += $(NSHTTPD_DEP) $(ADMINUTIL_DEP) $(DBM_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(DBMLINK)
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBACCESS_DEP)
+EXTRA_LIBS += $(LIBACCESS)
+endif
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libacl.def"
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPDLINK) $(NSPRLINK) $(LDAP_LIBAVL) $(LDAP_SDK_LIBLDAP_DLL)
+EXTRA_LIBS += $(DLL_EXTRA_LIBS)
+LD=ld
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBACL)
+
+$(LIBACL): $(OBJS) $(LIBACL_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBACL_DLL_OBJ) $(PLATFORMLIBS) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBACL_DLL_OBJ)
+endif
+ $(RM) $(LIBACL)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
diff --git a/ldap/servers/plugins/acl/acl.c b/ldap/servers/plugins/acl/acl.c
new file mode 100644
index 00000000..8dfbd52a
--- /dev/null
+++ b/ldap/servers/plugins/acl/acl.c
@@ -0,0 +1,4118 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "acl.h"
+
+/****************************************************************************
+*
+* acl.c
+*
+*
+* This file contains the functions related to Access Control List (ACL)
+* checking. The ACL checking is based on the ONE ACL design implemented
+* in the Web server 2.0. For more information on the ACL design look
+* into the barracuda home page.
+*
+*
+******************************************************************************/
+
+
+/****************************************************************************/
+/* Globals. Must be protected by Mutex. */
+/****************************************************************************/
+/* Signatures to see if things have changed */
+static short acl_signature = 0;
+
+/****************************************************************************/
+/* Defines, Constants, ande Declarations */
+/****************************************************************************/
+static char *ds_map_generic[2] = { NULL, NULL };
+
+/****************************************************************************/
+/* prototypes */
+/****************************************************************************/
+static int acl__resource_match_aci(struct acl_pblock *aclpb, aci_t *aci ,
+ int skip_attrEval, int *a_matched);
+static acl__TestRights(Acl_PBlock *aclpb,int access, char **right,
+ char ** map_generic, aclResultReason_t *result_reason);
+static int acl__scan_for_acis(struct acl_pblock *aclpb, int *err);
+static void acl__reset_cached_result (struct acl_pblock *aclpb );
+static int acl__scan_match_handles ( struct acl_pblock *aclpb, int type);
+static int acl__attr_cached_result (struct acl_pblock *aclpb, char *attr, int access );
+static int acl__match_handlesFromCache (struct acl_pblock *aclpb, char *attr, int access);
+static int acl__get_attrEval ( struct acl_pblock *aclpb, char *attr );
+static int acl__config_get_readonly ();
+static int acl__recompute_acl (Acl_PBlock *aclpb, AclAttrEval *a_eval,
+ int access, int aciIndex);
+static void __acl_set_aclIndex_inResult ( Acl_PBlock *aclpb,
+ int access, int index );
+static int acl__make_filter_test_entry ( Slapi_Entry **entry,
+ char *attr_type, struct berval *attr_val);
+static int acl__test_filter ( Slapi_Entry *entry, struct slapi_filter *f,
+ int filter_sense);
+static void print_access_control_summary( char * source,
+ int ret_val, char *clientDn,
+ struct acl_pblock *aclpb,
+ char *right,
+ char *attr,
+ const char *edn,
+ aclResultReason_t *acl_reason);
+static int check_rdn_access( Slapi_PBlock *pb,Slapi_Entry *e, char * newrdn,
+ int access);
+
+
+/*
+ * Check the rdn permissions for this entry:
+ * require: write access to the entry, write (add) access to the new
+ * naming attribute, write (del) access to the old naming attribute if
+ * deleteoldrdn set.
+ *
+ * Valid only for the modrdn operation.
+*/
+int
+acl_access_allowed_modrdn(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e, /* The Slapi_Entry */
+ char *attr, /* Attribute of the entry */
+ struct berval *val, /* value of attr. NOT USED */
+ int access /* requested access rights */
+ )
+{
+ int retCode ;
+ char *newrdn, *oldrdn;
+ int deleteoldrdn = 0;
+
+ /*
+ * First check write permission on the entry--this is actually
+ * specially for modrdn.
+ */
+ retCode = acl_access_allowed ( pb, e, NULL /* attr */, NULL /* val */,
+ SLAPI_ACL_WRITE);
+
+ if ( retCode != LDAP_SUCCESS ) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "modrdn:write permission to entry not allowed\n");
+ return(retCode);
+ }
+
+ /* Now get the new rdn attribute name and value */
+
+ slapi_pblock_get( pb, SLAPI_MODRDN_TARGET, &oldrdn );
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn );
+
+ /* Check can add the new naming attribute */
+ retCode = check_rdn_access( pb, e, newrdn, ACLPB_SLAPI_ACL_WRITE_ADD) ;
+ if ( retCode != LDAP_SUCCESS ) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "modrdn:write permission to add new naming attribute not allowed\n");
+ return(retCode);
+ }
+
+ /* Check can delete the new naming attribute--if required */
+ slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &deleteoldrdn );
+ if ( deleteoldrdn ) {
+ retCode = check_rdn_access( pb, e, oldrdn, ACLPB_SLAPI_ACL_WRITE_DEL) ;
+ if ( retCode != LDAP_SUCCESS ) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "modrdn:write permission to delete old naming attribute not allowed\n");
+ return(retCode);
+ }
+ }
+
+ return(retCode);
+
+}
+/*
+ * Test if have access to make the first rdn of dn in entry e.
+*/
+
+static int check_rdn_access( Slapi_PBlock *pb, Slapi_Entry *e, char *dn,
+ int access) {
+
+ char **dns;
+ char **rdns;
+ int retCode = LDAP_INSUFFICIENT_ACCESS;
+ int i;
+
+ if ( (dns = ldap_explode_dn( dn, 0 )) != NULL ) {
+
+ if ( (rdns = ldap_explode_rdn( dns[0], 0 )) != NULL ) {
+
+ for ( i = 0; rdns[i] != NULL; i++ ) {
+ char *type;
+ struct berval bv;
+
+ if ( slapi_rdn2typeval( rdns[i], &type, &bv ) != 0 ) {
+ char ebuf[ BUFSIZ ];
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "modrdn: rdn2typeval (%s) failed\n",
+ escape_string( rdns[i], ebuf ));
+ retCode = LDAP_INSUFFICIENT_ACCESS;
+ break;
+ } else {
+ if ( (retCode = acl_access_allowed ( pb, e, type /* attr */,
+ &bv /* val */,
+ access)) != LDAP_SUCCESS) {
+ break;
+ }
+ }
+ }
+ ldap_value_free( rdns );
+ }
+ ldap_value_free( dns );
+ }
+
+ return(retCode);
+}
+
+/***************************************************************************
+*
+* acl_access_allowed
+* Determines if access to the resource is allowed or not.
+*
+* Input:
+* 
+*
+* Returns:
+*
+* Returns success/Denied/error condition
+*
+* LDAP_SUCCESS -- access allowed
+* LDAP_INSUFFICIENT_ACCESS -- access denied
+*
+* Errors returned:
+*
+* Some of the definition of the return values used copied from
+* "ldap.h" for convienience.
+* LDAP_OPERATIONS_ERROR
+* LDAP_PROTOCOL_ERROR
+* LDAP_UNWILLING_TO_PERFORM
+*
+*
+* Error Handling:
+* Returned error code.
+**************************************************************************/
+int
+acl_access_allowed(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e, /* The Slapi_Entry */
+ char *attr, /* Attribute of the entry */
+ struct berval *val, /* value of attr. NOT USED */
+ int access /* requested access rights */
+ )
+{
+ char *n_edn; /* Normalized DN of the entry */
+ int rv;
+ int err;
+ int ret_val;
+ char *right;
+ int num_handle;
+ struct acl_pblock *aclpb = NULL;
+ AclAttrEval *c_attrEval = NULL;
+ int got_reader_locked = 0;
+ int deallocate_attrEval = 0;
+ char ebuf [ BUFSIZ ];
+ char *clientDn;
+ Slapi_DN *e_sdn;
+ Slapi_Operation *op = NULL;
+ aclResultReason_t decision_reason;
+ int loglevel;
+
+ loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op); /* for logging */
+
+ TNF_PROBE_1_DEBUG(acl_access_allowed_start,"ACL","",
+ tnf_int,access,access);
+
+ decision_reason.deciding_aci = NULL;
+ decision_reason.reason = ACL_REASON_NONE;
+
+ /**
+ * First, if the acl private write/delete on attribute right
+ * is requested, turn this into SLAPI_ACL_WRITE
+ * and record the original value.
+ * Need to make sure that these rights do not clash with the SLAPI
+ * public rights. This should be easy as the requested rights
+ * in the aclpb are stored in the bottom byte of aclpb_res_type,
+ * so if we keep the ACL private bits here too we make sure
+ * not to clash.
+ *
+ */
+
+ if ( access & (ACLPB_SLAPI_ACL_WRITE_ADD | ACLPB_SLAPI_ACL_WRITE_DEL) ) {
+ access |= SLAPI_ACL_WRITE;
+ }
+
+ n_edn = slapi_entry_get_ndn ( e );
+ e_sdn = slapi_entry_get_sdn ( e );
+
+ /* Check if this is a write operation and the database is readonly */
+ /* No one, even the rootdn should be allowed to write to the database */
+ /* jcm: ReadOnly only applies to the public backends, the private ones */
+ /* (the DSEs) should still be writable for configuration. */
+ if ( access & ( SLAPI_ACL_WRITE | SLAPI_ACL_ADD | SLAPI_ACL_DELETE )) {
+ int be_readonly, privateBackend;
+ Slapi_Backend *be;
+
+ slapi_pblock_get ( pb, SLAPI_BE_READONLY, &be_readonly );
+ slapi_pblock_get ( pb, SLAPI_BACKEND, &be );
+ privateBackend = slapi_be_private ( be );
+
+ if ( !privateBackend && (be_readonly || slapi_config_get_readonly () )){
+ slapi_log_error (loglevel, plugin_name,
+ "conn=%d op=%d (main): Deny %s on entry(%s)"
+ ": readonly backend\n",
+ op->o_connid, op->o_opid,
+ acl_access2str(access),
+ escape_string_with_punctuation(n_edn,ebuf));
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ }
+
+ /* Check for things we need to skip */
+ TNF_PROBE_0_DEBUG(acl_skipaccess_start,"ACL","");
+ if ( acl_skip_access_check ( pb, e )) {
+ slapi_log_error (loglevel, plugin_name,
+ "conn=%d op=%d (main): Allow %s on entry(%s)"
+ ": root user\n",
+ op->o_connid, op->o_opid,
+ acl_access2str(access),
+ escape_string_with_punctuation(n_edn,ebuf));
+ return(LDAP_SUCCESS);
+ }
+ TNF_PROBE_0_DEBUG(acl_skipaccess_end,"ACL","");
+
+
+ /* Get the bindDN */
+ slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &clientDn );
+
+ /* get the right acl pblock to work with */
+ if ( access & SLAPI_ACL_PROXY )
+ aclpb = acl_get_aclpb ( pb, ACLPB_PROXYDN_PBLOCK );
+ else
+ aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
+
+ if ( !aclpb ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Missing aclpb 1 \n" );
+ ret_val = LDAP_OPERATIONS_ERROR;
+ goto cleanup_and_ret;
+ }
+
+ /* check if aclpb is initialized or not */
+ TNF_PROBE_0_DEBUG(acl_aclpbinit_start,"ACL","");
+ acl_init_aclpb ( pb, aclpb, clientDn, 0 );
+ TNF_PROBE_0_DEBUG(acl_aclpbinit_end,"ACL","");
+
+
+ /* Here we mean if "I am trying to add/delete "myself" ? " */
+ if (val && (access & SLAPI_ACL_WRITE) && (val->bv_len > 0) ) {
+ /* should use slapi_sdn_compare() but that'a an extra malloc/free */
+
+ char *dn_val_to_write =
+ slapi_dn_normalize(slapi_ch_strdup(val->bv_val));
+
+ if ( aclpb->aclpb_authorization_sdn &&
+ slapi_utf8casecmp((ACLUCHP)dn_val_to_write, (ACLUCHP)
+ slapi_sdn_get_ndn(aclpb->aclpb_authorization_sdn)) == 0) {
+ access |= SLAPI_ACL_SELF;
+ }
+
+ slapi_ch_free( (void **)&dn_val_to_write);
+ }
+
+ /* Convert access to string of rights eg SLAPI_ACL_ADD->"add". */
+ if ((right= acl_access2str(access)) == NULL) {
+ /* ERROR: unknown rights */
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "acl_access_allowed unknown rights:%d\n", access);
+
+ ret_val = LDAP_OPERATIONS_ERROR;
+ goto cleanup_and_ret;
+ }
+
+
+ /*
+ * Am I a anonymous dude ? then we can use our anonymous profile
+ * We don't require the aclpb to have been initialized for anom stuff
+ *
+ */
+ TNF_PROBE_0_DEBUG(acl_anon_test_start,"ACL","");
+ if ( (access & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ )) &&
+ (clientDn && *clientDn == '\0')) {
+ aclanom_get_suffix_info(e, aclpb);
+ ret_val = aclanom_match_profile ( pb, aclpb, e, attr, access );
+ if (ret_val != -1 ) {
+ if (ret_val == LDAP_SUCCESS ) {
+ decision_reason.reason = ACL_REASON_ANON_ALLOWED;
+ } else if (ret_val == LDAP_INSUFFICIENT_ACCESS) {
+ decision_reason.reason = ACL_REASON_ANON_DENIED;
+ }
+ goto cleanup_and_ret;
+ }
+ }
+ TNF_PROBE_0_DEBUG(acl_anon_test_end,"ACL","");
+
+ /* copy the value into the aclpb for later checking by the value acl code */
+
+ aclpb->aclpb_curr_attrVal = val;
+
+ if (!(aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) &&
+ (access & SLAPI_ACL_SEARCH)) {
+ /* We are evaluating SEARCH right for the entry. After that
+ ** we will eval the READ right. We need to refresh the
+ ** list of acls selected for evaluation for the entry.
+ ** Initialize the array so that we indicate nothing has been
+ ** selected.
+ */
+ aclpb->aclpb_handles_index[0] = -1;
+ /* access is not allowed on entry for search -- it's for
+ ** read only.
+ */
+ aclpb->aclpb_state &= ~ACLPB_ACCESS_ALLOWED_ON_ENTRY;
+ }
+
+ /* set that this is a new entry */
+ aclpb->aclpb_res_type |= ACLPB_NEW_ENTRY;
+ aclpb->aclpb_access = 0;
+ aclpb->aclpb_access |= access;
+
+ /*
+ * stub the Slapi_Entry info first time and only it has changed
+ * or if the pblock is a psearch pblock--in this case the lifetime
+ * of entries associated with psearches is such that we cannot cache
+ * pointers to them--we must always start afresh (see psearch.c).
+ */
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op);
+ if ( operation_is_flag_set(op, OP_FLAG_PS) ||
+ (aclpb->aclpb_curr_entry_sdn == NULL) ||
+ (slapi_sdn_compare ( aclpb->aclpb_curr_entry_sdn, e_sdn) != 0)) {
+
+ TNF_PROBE_0_DEBUG(acl_entry_first_touch_start,"ACL","");
+
+ slapi_log_error(loglevel, plugin_name,
+ "#### conn=%d op=%d binddn=\"%s\"\n",
+ op->o_connid, op->o_opid, clientDn);
+ aclpb->aclpb_stat_total_entries++;
+
+ if (!(access & SLAPI_ACL_PROXY) &&
+ !( aclpb->aclpb_state & ACLPB_DONOT_EVALUATE_PROXY )) {
+ Acl_PBlock *proxy_pb;
+
+ proxy_pb = acl_get_aclpb( pb, ACLPB_PROXYDN_PBLOCK );
+ if (proxy_pb) {
+ TNF_PROBE_0_DEBUG(acl_access_allowed_proxy_start,"ACL","");
+ ret_val = acl_access_allowed( pb, e, attr, val, SLAPI_ACL_PROXY );
+ TNF_PROBE_0_DEBUG(acl_access_allowed_proxy_end,"ACL","");
+
+ if (ret_val != LDAP_SUCCESS) goto cleanup_and_ret;
+ }
+ }
+ if ( access & SLAPI_ACL_SEARCH) {
+ aclpb->aclpb_num_entries++;
+
+ if ( aclpb->aclpb_num_entries == 1) {
+ aclpb->aclpb_state |= ACLPB_COPY_EVALCONTEXT;
+ } else if ( aclpb->aclpb_state & ACLPB_COPY_EVALCONTEXT ) {
+ /* We need to copy the evalContext */
+ acl_copyEval_context ( aclpb, &aclpb->aclpb_curr_entryEval_context,
+ &aclpb->aclpb_prev_entryEval_context, 0 );
+ aclpb->aclpb_state &= ~ACLPB_COPY_EVALCONTEXT;
+ }
+ acl_clean_aclEval_context ( &aclpb->aclpb_curr_entryEval_context, 1 /*scrub */);
+ }
+
+ /* reset the cached result based on the scope */
+ acl__reset_cached_result (aclpb );
+
+ /* Find all the candidate aci's that apply by scanning up the DIT tree from edn. */
+
+ TNF_PROBE_0_DEBUG(acl_aciscan_start,"ACL","");
+ slapi_sdn_done ( aclpb->aclpb_curr_entry_sdn );
+ slapi_sdn_set_dn_byval ( aclpb->aclpb_curr_entry_sdn, n_edn );
+ acllist_aciscan_update_scan ( aclpb, n_edn );
+ TNF_PROBE_0_DEBUG(acl_aciscan_end,"ACL","");
+
+ /* Keep the ptr to the current entry */
+ aclpb->aclpb_curr_entry = (Slapi_Entry *) e;
+
+ /* Get the attr info */
+ deallocate_attrEval = acl__get_attrEval ( aclpb, attr );
+
+ aclutil_print_resource ( aclpb, right, attr, clientDn );
+
+ /*
+ * Used to be PListInitProp(aclpb->aclpb_proplist, 0,
+ * DS_ATTR_ENTRY, e, 0);
+ *
+ * The difference is that PListInitProp() allocates a new property
+ * every time it's called, overwriting the old name in the PList hash
+ * table, but not freeing the original property.
+ * Now, we just create the property at aclpb_malloc() time and
+ * Assign a new value each time.
+ */
+
+ rv = PListAssignValue(aclpb->aclpb_proplist,
+ DS_ATTR_ENTRY, e, 0);
+
+ if (rv < 0) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Unable to set the Slapi_Entry in the Plist\n",0,0,0);
+ ret_val = LDAP_OPERATIONS_ERROR;
+ goto cleanup_and_ret;
+ }
+
+ TNF_PROBE_0_DEBUG(acl_entry_first_touch_end,"ACL","");
+
+ } else {
+ /* we are processing the same entry but for a different
+ ** attribute. If access is already allowed on that, entry, then
+ ** it's not a new entry anymore. It's the same old one.
+ */
+
+ TNF_PROBE_0_DEBUG(acl_entry_subs_touch_start,"ACL","");
+
+ aclpb->aclpb_res_type &= ~ACLPB_NEW_ENTRY;
+
+ /* Get the attr info */
+ deallocate_attrEval = acl__get_attrEval ( aclpb, attr );
+
+ TNF_PROBE_0_DEBUG(acl_entry_subs_touch_end,"ACL","");
+
+ }
+
+ /* get a lock for the reader */
+ acllist_acicache_READ_LOCK();
+ got_reader_locked = 1;
+
+ /*
+ ** Check if we can use any cached information to determine
+ ** access to this resource
+ */
+ if ( (access & SLAPI_ACL_SEARCH) &&
+ (ret_val = acl__match_handlesFromCache ( aclpb , attr, access)) != -1) {
+ /* means got a result: allowed or not*/
+
+ if (ret_val == LDAP_SUCCESS ) {
+ decision_reason.reason = ACL_REASON_EVALCONTEXT_CACHED_ALLOW;
+ } else if (ret_val == LDAP_INSUFFICIENT_ACCESS) {
+ decision_reason.reason =
+ ACL_REASON_EVALCONTEXT_CACHED_NOT_ALLOWED;
+ }
+ goto cleanup_and_ret;
+ }
+
+ /*
+ ** Now we have all the information about the resource. Now we need to
+ ** figure out if there are any ACLs which can be applied.
+ ** If no ACLs are there, then it's a DENY as default.
+ */
+ if (!(num_handle = acl__scan_for_acis(aclpb, &err))) {
+
+ /* We might have accessed the ACL first time which could
+ ** have caused syntax error.
+ */
+ if ( err == ACL_ONEACL_TEXT_ERR)
+ ret_val = LDAP_INVALID_SYNTAX;
+ else {
+ ret_val = LDAP_INSUFFICIENT_ACCESS;
+ decision_reason.reason = ACL_REASON_NO_MATCHED_RESOURCE_ALLOWS;
+ }
+ goto cleanup_and_ret;
+ }
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Processed attr:%s for entry:%s\n", attr ? attr : "NULL",
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION ( n_edn, ebuf), 0);
+
+ /*
+ ** Now evaluate the rights.
+ ** This is what we have been waiting for.
+ ** The return value should be ACL_RES_DENY or ACL_RES_ALLOW.
+ */
+ rv = acl__TestRights(aclpb, access, &right, ds_map_generic,
+ &decision_reason);
+ if ( rv != ACL_RES_ALLOW && (0 == strcasecmp ( right, "selfwrite") ) ) {
+ /* If I am adding myself to a group, we don't need selfwrite always,
+ ** write priv is good enough. Since libaccess doesn't provide me a nice
+ ** way to evaluate OR rights, I have to try again with wite priv.
+ ** bug: 339051
+ */
+ right = access_str_write;
+ rv = acl__TestRights(aclpb, access, &right, ds_map_generic,
+ &decision_reason);
+ }
+
+ if (rv == ACL_RES_ALLOW) {
+ ret_val = LDAP_SUCCESS;
+ } else {
+ ret_val = LDAP_INSUFFICIENT_ACCESS;
+ }
+
+cleanup_and_ret:
+
+ TNF_PROBE_0_DEBUG(acl_cleanup_start,"ACL","");
+
+ /* I am ready to get out. */
+ if ( got_reader_locked ) acllist_acicache_READ_UNLOCK();
+
+ /* Store the status of the evaluation for this attr */
+ if ( aclpb && (c_attrEval = aclpb->aclpb_curr_attrEval )) {
+ if ( deallocate_attrEval ) {
+ /* In this case we are not caching the result as
+ ** we have too many attrs. we have malloced space.
+ ** Get rid of it.
+ */
+ slapi_ch_free ( (void **) &c_attrEval->attrEval_name );
+ slapi_ch_free ( (void **) &c_attrEval );
+ } else if (ret_val == LDAP_SUCCESS ) {
+ if ( access & SLAPI_ACL_SEARCH )
+ c_attrEval->attrEval_s_status |= ACL_ATTREVAL_SUCCESS;
+ else if ( access & SLAPI_ACL_READ )
+ c_attrEval->attrEval_r_status |= ACL_ATTREVAL_SUCCESS;
+ else
+ c_attrEval->attrEval_r_status |= ACL_ATTREVAL_INVALID;
+ } else {
+ if ( access & SLAPI_ACL_SEARCH )
+ c_attrEval->attrEval_s_status |= ACL_ATTREVAL_FAIL;
+ else if ( access & SLAPI_ACL_READ )
+ c_attrEval->attrEval_r_status |= ACL_ATTREVAL_FAIL;
+ else
+ c_attrEval->attrEval_r_status |= ACL_ATTREVAL_INVALID;
+ }
+ }
+
+ if ( aclpb ) aclpb->aclpb_curr_attrEval = NULL;
+
+ print_access_control_summary( "main", ret_val, clientDn, aclpb, right,
+ (attr ? attr : "NULL"),
+ escape_string_with_punctuation (n_edn, ebuf),
+ &decision_reason);
+ TNF_PROBE_0_DEBUG(acl_cleanup_end,"ACL","");
+
+ TNF_PROBE_0_DEBUG(acl_access_allowed_end,"ACL","");
+
+ return(ret_val);
+
+}
+
+static void print_access_control_summary( char *source, int ret_val, char *clientDn,
+ struct acl_pblock *aclpb,
+ char *right,
+ char *attr,
+ const char *edn,
+ aclResultReason_t *acl_reason)
+{
+ struct codebook {
+ int code;
+ char *text;
+ };
+
+ static struct codebook reasonbook[] = {
+ {ACL_REASON_NO_ALLOWS, "no allow acis"},
+ {ACL_REASON_RESULT_CACHED_DENY, "cached deny"},
+ {ACL_REASON_RESULT_CACHED_ALLOW, "cached allow"},
+ {ACL_REASON_EVALUATED_ALLOW, "allowed"},
+ {ACL_REASON_EVALUATED_DENY, "denied"},
+ {ACL_REASON_NO_MATCHED_RESOURCE_ALLOWS, "no aci matched the resource"},
+ {ACL_REASON_NO_MATCHED_SUBJECT_ALLOWS, "no aci matched the subject"},
+ {ACL_REASON_ANON_ALLOWED, "allow anyone aci matched anon user"},
+ {ACL_REASON_ANON_DENIED, "no matching anyone aci for anon user"},
+ {ACL_REASON_EVALCONTEXT_CACHED_ALLOW, "cached context/parent allow"},
+ {ACL_REASON_EVALCONTEXT_CACHED_NOT_ALLOWED, "cached context/parent deny"},
+ {ACL_REASON_EVALCONTEXT_CACHED_ATTR_STAR_ALLOW, "cached context/parent allow any attr"},
+ {ACL_REASON_NONE, "error occurred"},
+ };
+
+ char *anon = "anonymous";
+ char *null_user = "NULL"; /* bizare case */
+ char *real_user = NULL;
+ char *proxy_user = NULL;
+ char *access_allowed_string = "Allow";
+ char *access_not_allowed_string = "Deny";
+ char *access_error_string = "access_error";
+ char *access_status = NULL;
+ char *access_reason_none = "no reason available";
+ char *access_reason = access_reason_none;
+ char acl_info[ BUFSIZ ];
+ Slapi_Operation *op = NULL;
+ int loglevel;
+ int i;
+
+ loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
+
+ if ( !slapi_is_loglevel_set(loglevel) ) {
+ return;
+ }
+
+ slapi_pblock_get(aclpb->aclpb_pblock, SLAPI_OPERATION, &op); /* for logging */
+
+ if (ret_val == LDAP_INSUFFICIENT_ACCESS) {
+ access_status = access_not_allowed_string;
+ } else if ( ret_val == LDAP_SUCCESS) {
+ access_status = access_allowed_string;
+ } else { /* some kind of error */
+ access_status = access_error_string;
+ }
+
+ /* decode the reason */
+ for (i = 0; i < sizeof(reasonbook) / sizeof(struct codebook); i++) {
+ if ( acl_reason->reason == reasonbook[i].code ) {
+ access_reason = reasonbook[i].text;
+ break;
+ }
+ }
+
+ /* get the acl */
+ acl_info[0] = '\0';
+ if (acl_reason->deciding_aci) {
+ if (acl_reason->reason == ACL_REASON_RESULT_CACHED_DENY ||
+ acl_reason->reason == ACL_REASON_RESULT_CACHED_ALLOW) {
+ /* acl is in cache. Its detail must have been printed before.
+ * So no need to print out acl detail this time.
+ */
+ PR_snprintf( &acl_info[0], BUFSIZ, "%s by aci(%d)",
+ access_reason,
+ acl_reason->deciding_aci->aci_index);
+ }
+ else {
+ PR_snprintf( &acl_info[0], BUFSIZ, "%s by aci(%d): aciname=%s, acidn=\"%s\"",
+ access_reason,
+ acl_reason->deciding_aci->aci_index,
+ acl_reason->deciding_aci->aclName,
+ slapi_sdn_get_ndn (acl_reason->deciding_aci->aci_sdn) );
+ }
+ }
+
+ /* Say who was denied access */
+
+ if (clientDn) {
+ if (clientDn[0] == '\0') {
+ /* anon */
+ real_user = anon;
+ } else {
+ real_user = clientDn;
+ }
+ } else {
+ real_user = null_user;
+ }
+
+ /* Is there a proxy */
+
+ if ( aclpb != NULL && aclpb->aclpb_proxy != NULL) {
+
+ if ( aclpb->aclpb_authorization_sdn != NULL ) {
+
+ proxy_user = (char *)(aclpb->aclpb_authorization_sdn->ndn ?
+ aclpb->aclpb_authorization_sdn->ndn:
+ null_user);
+
+ slapi_log_error(loglevel, plugin_name,
+ "conn=%d op=%d (%s): %s %s on entry(%s).attr(%s) to proxy (%s)"
+ ": %s\n",
+ op->o_connid, op->o_opid,
+ source,
+ access_status,
+ right,
+ edn,
+ attr ? attr: "NULL",
+ proxy_user,
+ acl_info[0] ? acl_info : access_reason);
+ } else {
+ proxy_user = null_user;
+ slapi_log_error(loglevel, plugin_name,
+ "conn=%d op=%d (%s): %s %s on entry(%s).attr(%s) to proxy (%s)"
+ ": %s\n",
+ op->o_connid, op->o_opid,
+ source,
+ access_status,
+ right,
+ edn,
+ attr ? attr: "NULL",
+ proxy_user,
+ acl_info[0] ? acl_info : access_reason);
+ }
+ } else{
+ slapi_log_error(loglevel, plugin_name,
+ "conn=%d op=%d (%s): %s %s on entry(%s).attr(%s)"
+ ": %s\n",
+ op->o_connid, op->o_opid,
+ source,
+ access_status,
+ right,
+ edn,
+ attr ? attr: "NULL",
+ acl_info[0] ? acl_info : access_reason);
+ }
+
+
+}
+/***************************************************************************
+*
+* acl_read_access_allowed_on_entry
+* check read access control on the given entry.
+*
+* Only used during seearch to test for read access on the entry.
+* (Could be generalized).
+*
+* attrs is the list of requested attributes passed with the search.
+* If the entry has no attributes (weird case) then the routine survives.
+*
+* Input:
+*
+*
+* Returns:
+* LDAP_SUCCESS - access allowed
+* LDAP_INSUFFICIENT_ACCESS - access denied
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+acl_read_access_allowed_on_entry (
+ Slapi_PBlock *pb,
+ Slapi_Entry *e, /* The Slapi_Entry */
+ char **attrs,
+ int access /* access rights */
+ )
+{
+
+ struct acl_pblock *aclpb;
+ Slapi_Attr *currAttr;
+ Slapi_Attr *nextAttr;
+ int len;
+ int attr_index = -1;
+ char *attr_type = NULL;
+ int rv, isRoot;
+ char *clientDn;
+ unsigned long flags;
+ aclResultReason_t decision_reason;
+ int loglevel;
+
+ loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
+
+ TNF_PROBE_0_DEBUG(acl_read_access_allowed_on_entry_start ,"ACL","");
+
+ decision_reason.deciding_aci = NULL;
+ decision_reason.reason = ACL_REASON_NONE;
+
+ slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );
+
+ /*
+ ** If it's the root, or acl is off or the entry is a rootdse,
+ ** Then you have the privilege to read it.
+ */
+ if ( acl_skip_access_check ( pb, e ) ) {
+ char *n_edn = slapi_entry_get_ndn ( e );
+ char ebuf [ BUFSIZ ];
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "Root access (%s) allowed on entry(%s)\n",
+ acl_access2str(access),
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION (n_edn, ebuf));
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","",
+ tnf_string,skip_access,"");
+ return LDAP_SUCCESS;
+ }
+
+ aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
+ if ( !aclpb ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Missing aclpb 2 \n" );
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","",
+ tnf_string,end,"aclpb error");
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /*
+ * Am I a anonymous dude ? then we can use our anonympous profile
+ * We don't require the aclpb to have been initialized for anom stuff
+ *
+ */
+ slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &clientDn );
+ if ( clientDn && *clientDn == '\0' ) {
+ int ret_val;
+ ret_val = aclanom_match_profile ( pb, aclpb, e, NULL, SLAPI_ACL_READ );
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","",
+ tnf_string,end,"anon");
+
+ if (ret_val != -1 ) return ret_val;
+ }
+
+ aclpb->aclpb_state &= ~ACLPB_RESET_MASK;
+ if (aclpb->aclpb_state & ACLPB_MATCHES_ALL_ACLS ) {
+ int ret_val;
+ ret_val = acl__attr_cached_result (aclpb, NULL, SLAPI_ACL_READ);
+ if (ret_val != -1 ) {
+ /* print summary if loglevel set */
+ if ( slapi_is_loglevel_set(loglevel) ) {
+ char *n_edn;
+ n_edn = slapi_entry_get_ndn ( e );
+ if ( ret_val == LDAP_SUCCESS) {
+ decision_reason.reason =
+ ACL_REASON_EVALCONTEXT_CACHED_ALLOW;
+ } else {
+ decision_reason.reason =
+ ACL_REASON_EVALCONTEXT_CACHED_NOT_ALLOWED;
+ }
+ /*
+ * pass NULL as the attr as this routine is concerned with
+ * access at the entry level.
+ */
+ print_access_control_summary( "on entry",
+ ret_val, clientDn, aclpb,
+ acl_access2str(SLAPI_ACL_READ),
+ NULL, n_edn,
+ &decision_reason);
+ }
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","",
+ tnf_string,eval_context_cached,"");
+
+ return ret_val;
+ }
+ }
+
+ /*
+ * Currently do not use this code--it results in confusing
+ * behaviour..see 529905
+ */
+#ifdef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
+
+ /* Do we have access to the entry by virtue of
+ ** having access to an attr. Before that, let's find out which attrs
+ ** the user want. If the user has specified certain attributes, then
+ ** we check aginst that set of attributes.
+ */
+ if (!((aclpb->aclpb_state & ACLPB_USER_WANTS_ALL_ATTRS) ||
+ (aclpb->aclpb_state & ACLPB_USER_SPECIFIED_ATTARS))) {
+ int i;
+ if (attrs == NULL) {
+ aclpb->aclpb_state |= ACLPB_USER_WANTS_ALL_ATTRS;
+ } else {
+ for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
+ if ( strcmp( LDAP_ALL_USER_ATTRS, attrs[i] ) == 0 ) {
+ aclpb->aclpb_state |= ACLPB_USER_WANTS_ALL_ATTRS;
+ break;
+ }
+ }
+ }
+
+ if (!(aclpb->aclpb_state & ACLPB_USER_WANTS_ALL_ATTRS)) {
+ for (i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
+ if ( !slapi_entry_attr_find ( e, attrs[i], &currAttr ) ) {
+ aclpb->aclpb_state |= ACLPB_USER_SPECIFIED_ATTARS;
+ break;
+ }
+ }
+ }
+ } /* end of all user test*/
+
+
+ /*
+ ** If user has specified a list of attrs, might as well use it
+ ** to determine access control.
+ */
+ currAttr = NULL;
+ attr_index = -1;
+ if ( aclpb->aclpb_state & ACLPB_USER_SPECIFIED_ATTARS) {
+ attr_index = 0;
+ attr_type = attrs[attr_index++];
+ } else {
+ /* Skip the operational attributes -- if there are any in the front */
+ slapi_entry_first_attr ( e, &currAttr );
+ if (currAttr != NULL) {
+ slapi_attr_get_flags ( currAttr, &flags );
+ while ( flags & SLAPI_ATTR_FLAG_OPATTR ) {
+ flags = 0;
+ rv = slapi_entry_next_attr ( e, currAttr, &nextAttr );
+ if ( !rv ) slapi_attr_get_flags ( nextAttr, &flags );
+ currAttr = nextAttr;
+ }
+
+ /* Get the attr type */
+ if ( currAttr ) slapi_attr_get_type ( currAttr , &attr_type );
+ }
+ }
+
+#endif /*DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES*/
+
+#ifndef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
+
+ /*
+ * Here look at each attribute in the entry and see if
+ * we have read access to it--if we do
+ * and we are not denied access to the entry then this
+ * is taken as implying access to the entry.
+ */
+ slapi_entry_first_attr ( e, &currAttr );
+ if (currAttr != NULL) {
+ slapi_attr_get_type ( currAttr , &attr_type );
+ }
+#endif
+ aclpb->aclpb_state |= ACLPB_EVALUATING_FIRST_ATTR;
+
+ while (attr_type) {
+ if (acl_access_allowed (pb, e,attr_type, NULL,
+ SLAPI_ACL_READ) == LDAP_SUCCESS) {
+ /*
+ ** We found a rule which requires us to test access
+ ** to the entry.
+ */
+ if ( aclpb->aclpb_state & ACLPB_FOUND_A_ENTRY_TEST_RULE){
+ /* Do I have access on the entry itself */
+ if (acl_access_allowed (pb, e, NULL,
+ NULL, access) != LDAP_SUCCESS) {
+ /* How was I denied ?
+ ** I could be denied on a DENY rule or because
+ ** there is no allow rule. If it's a DENY from
+ ** a DENY rule, then we don't have access to
+ ** the entry ( nice trick to get in )
+ */
+ if ( aclpb->aclpb_state &
+ ACLPB_EXECUTING_DENY_HANDLES)
+ return LDAP_INSUFFICIENT_ACCESS;
+
+ /* The other case is I don't have an
+ ** explicit allow rule -- which is fine.
+ ** Since, I am already here, it means that I have
+ ** an implicit allow to the entry.
+ */
+ }
+ }
+ aclpb->aclpb_state &= ~ACLPB_EVALUATING_FIRST_ATTR;
+
+ /*
+ ** If we are not sending all the attrs, then we must
+ ** make sure that we have right on a attr that we are
+ ** sending
+ */
+ len = strlen(attr_type);
+ if ( len > ACLPB_MAX_ATTR_LEN) {
+ slapi_ch_free ( (void **) &aclpb->aclpb_Evalattr);
+ aclpb->aclpb_Evalattr = slapi_ch_malloc(len);
+ }
+ strncpy (aclpb->aclpb_Evalattr, attr_type, len);
+ aclpb->aclpb_Evalattr[len] = '\0';
+ if ( attr_index >= 0 ) {
+ /*
+ * access was granted to one of the user specified attributes
+ * which was found in the entry and that attribute is
+ * now in aclpb_Evalattr
+ */
+ aclpb->aclpb_state |=
+ ACLPB_ACCESS_ALLOWED_USERATTR;
+ } else {
+ /*
+ * Access was granted to _an_ attribute in the entry and that
+ * attribute is now in aclpb_Evalattr
+ */
+ aclpb->aclpb_state |=
+ ACLPB_ACCESS_ALLOWED_ON_A_ATTR;
+ }
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_entry_end , "ACL","",
+ tnf_string,called_access_allowed,"");
+
+ return LDAP_SUCCESS;
+ } else {
+ /* try the next one */
+ attr_type = NULL;
+ if (attr_index >= 0) {
+ attr_type = attrs[attr_index++];
+ } else {
+ rv = slapi_entry_next_attr ( e, currAttr, &nextAttr );
+ if ( rv != 0 ) break;
+ currAttr = nextAttr;
+ slapi_attr_get_flags ( currAttr, &flags );
+ while ( flags & SLAPI_ATTR_FLAG_OPATTR ) {
+ flags = 0;
+ rv = slapi_entry_next_attr ( e, currAttr, &nextAttr );
+ if ( !rv ) slapi_attr_get_flags ( nextAttr, &flags );
+ currAttr = nextAttr;
+ }
+ /* Get the attr type */
+ if ( currAttr ) slapi_attr_get_type ( currAttr , &attr_type );
+ }
+ }
+ }
+
+ /*
+ ** That means. we have searched thru all the attrs and found
+ ** access is denied on all attrs.
+ **
+ ** If there were no attributes in the entry at all (can have
+ ** such entries thrown up by the b/e, then we do
+ ** not have such an implied access.
+ */
+ aclpb->aclpb_state |= ACLPB_ACCESS_DENIED_ON_ALL_ATTRS;
+ aclpb->aclpb_state &= ~ACLPB_EVALUATING_FIRST_ATTR;
+ TNF_PROBE_0_DEBUG(acl_read_access_allowed_on_entry_end ,"ACL","");
+
+ return LDAP_INSUFFICIENT_ACCESS;
+}
+
+/***************************************************************************
+*
+* acl_read_access_allowed_on_attr
+* check access control on the given attr.
+*
+* Only used during search to test for read access to an attr.
+* (Could be generalized)
+*
+* Input:
+*
+*
+* Returns:
+* LDAP_SUCCESS - access allowed
+* LDAP_INSUFFICIENT_ACCESS - access denied
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+acl_read_access_allowed_on_attr (
+ Slapi_PBlock *pb,
+ Slapi_Entry *e, /* The Slapi_Entry */
+ char *attr, /* Attribute of the entry */
+ struct berval *val, /* value of attr. NOT USED */
+ int access /* access rights */
+ )
+{
+
+ struct acl_pblock *aclpb = NULL;
+ char ebuf [ BUFSIZ ];
+ char *clientDn = NULL;
+ char *n_edn;
+ aclResultReason_t decision_reason;
+ int ret_val = -1;
+ int loglevel;
+
+ loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
+
+ TNF_PROBE_0_DEBUG(acl_read_access_allowed_on_attr_start ,"ACL","");
+
+ decision_reason.deciding_aci = NULL;
+ decision_reason.reason = ACL_REASON_NONE;
+
+ /* I am here, because I have access to the entry */
+
+ n_edn = slapi_entry_get_ndn ( e );
+
+ /* If it's the root or acl is off or rootdse, he has all the priv */
+ if ( acl_skip_access_check ( pb, e ) ) {
+ char ebuf [ BUFSIZ ];
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "Root access (%s) allowed on entry(%s)\n",
+ acl_access2str(access),
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION (n_edn, ebuf), 0);
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
+ tnf_string,skip_aclcheck,"");
+
+ return LDAP_SUCCESS;
+ }
+
+ aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
+ if ( !aclpb ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Missing aclpb 3 \n" );
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
+ tnf_string,aclpb_error,"");
+
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /*
+ * Am I a anonymous dude ? then we can use our anonympous profile
+ * We don't require the aclpb to have been initialized for anom stuff
+ *
+ */
+ slapi_pblock_get (pb, SLAPI_REQUESTOR_DN ,&clientDn );
+ if ( clientDn && *clientDn == '\0' ) {
+ ret_val = aclanom_match_profile ( pb, aclpb, e, attr,
+ SLAPI_ACL_READ );
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
+ tnf_string,anon_decision,"");
+ if (ret_val != -1 ) return ret_val;
+ }
+
+ /* Then I must have a access to the entry. */
+ aclpb->aclpb_state |= ACLPB_ACCESS_ALLOWED_ON_ENTRY;
+
+ if ( aclpb->aclpb_state & ACLPB_MATCHES_ALL_ACLS ) {
+
+ ret_val = acl__attr_cached_result (aclpb, attr, SLAPI_ACL_READ);
+ if (ret_val != -1 ) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "MATCHED HANDLE:dn:%s attr: %s val:%d\n",
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION (n_edn, ebuf), attr,
+ ret_val );
+ if ( ret_val == LDAP_SUCCESS) {
+ decision_reason.reason =
+ ACL_REASON_EVALCONTEXT_CACHED_ALLOW;
+ } else {
+ decision_reason.reason =
+ ACL_REASON_EVALCONTEXT_CACHED_NOT_ALLOWED;
+ }
+ goto acl_access_allowed_on_attr_Exit;
+ } else {
+ aclpb->aclpb_state |= ACLPB_COPY_EVALCONTEXT;
+ }
+ }
+
+ if (aclpb->aclpb_state & ACLPB_ACCESS_DENIED_ON_ALL_ATTRS) {
+ /* access is denied on all the attributes */
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
+ tnf_string,deny_all_attrs,"");
+
+ return LDAP_INSUFFICIENT_ACCESS;
+ }
+
+ /* do I have access to all the entries by virtue of having aci
+ ** rules with targetattr ="*". If yes, then allow access to
+ ** rest of the attributes.
+ */
+ if (aclpb->aclpb_state & ACLPB_ATTR_STAR_MATCHED) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "STAR Access allowed on attr:%s; entry:%s \n",
+ attr, ACL_ESCAPE_STRING_WITH_PUNCTUATION (n_edn, ebuf), 0);
+ decision_reason.reason =
+ ACL_REASON_EVALCONTEXT_CACHED_ATTR_STAR_ALLOW;
+ ret_val = LDAP_SUCCESS;
+ goto acl_access_allowed_on_attr_Exit;
+
+ }
+
+ if (aclpb->aclpb_state & ACLPB_ACCESS_ALLOWED_ON_A_ATTR) {
+
+ /* access is allowed on that attr.
+ ** for example: Slapi_Entry: cn, sn. phone, uid, passwd, address
+ ** We found that access is allowed on phone. That means the
+ ** -- access is denied on cn, sn
+ ** -- access is allowed on phone
+ ** -- Don't know about the rest. Need to evaluate.
+ */
+
+ if ( slapi_attr_type_cmp (attr, aclpb->aclpb_Evalattr, 1) == 0) {
+ /* from now on we need to evaluate access on
+ ** rest of the attrs.
+ */
+ aclpb->aclpb_state &= ~ACLPB_ACCESS_ALLOWED_ON_A_ATTR;
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
+ tnf_string,aclp_Evalattr1,"");
+
+ return LDAP_SUCCESS;
+ } else {
+ /*
+ * Here, the attr that implied access to the entry (aclpb_Evalattr),
+ * is not
+ * the one we currently want evaluated--so
+ * we need to evaluate access to attr--so fall through.
+ */
+ }
+
+ } else if (aclpb->aclpb_state & ACLPB_ACCESS_ALLOWED_USERATTR) {
+ /* Only skip evaluation on the user attr on which we have
+ ** evaluated before.
+ */
+ if ( slapi_attr_type_cmp (attr, aclpb->aclpb_Evalattr, 1) == 0) {
+ aclpb->aclpb_state &= ~ACLPB_ACCESS_ALLOWED_USERATTR;
+ TNF_PROBE_1_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","",
+ tnf_string,aclp_Evalattr2,"");
+ return LDAP_SUCCESS;
+ }
+ }
+
+ /* we need to evaluate the access on this attr */
+ return ( acl_access_allowed(pb, e, attr, val, access) );
+
+ /* This exit point prints a summary and returns ret_val */
+acl_access_allowed_on_attr_Exit:
+
+ /* print summary if loglevel set */
+ if ( slapi_is_loglevel_set(loglevel) ) {
+
+ print_access_control_summary( "on attr",
+ ret_val, clientDn, aclpb,
+ acl_access2str(SLAPI_ACL_READ),
+ attr, n_edn, &decision_reason);
+ }
+ TNF_PROBE_0_DEBUG(acl_read_access_allowed_on_attr_end ,"ACL","");
+
+ return(ret_val);
+}
+/***************************************************************************
+*
+* acl_check_mods
+* check access control on the given entry to see if
+* it allows the given modifications by the user associated with op.
+*
+*
+* Input:
+*
+*
+* Returns:
+* LDAP_SUCCESS - mods allowed ok
+* <err> - same return value as acl_access_allowed()
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+acl_check_mods(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ LDAPMod **mods,
+ char **errbuf
+)
+{
+ int i;
+ int rv, accessCheckDisabled;
+ int lastmod = 0;
+ Slapi_Attr *attr = NULL;
+ char *n_edn;
+ Slapi_Backend *be = NULL;
+ Slapi_DN *e_sdn;
+ Acl_PBlock *aclpb = acl_get_aclpb ( pb, ACLPB_PROXYDN_PBLOCK );
+ LDAPMod *mod;
+ Slapi_Mods smods;
+
+ rv = slapi_pblock_get ( pb, SLAPI_PLUGIN_DB_NO_ACL, &accessCheckDisabled );
+ if ( rv != -1 && accessCheckDisabled ) return LDAP_SUCCESS;
+
+ if ( NULL == aclpb )
+ aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
+
+ n_edn = slapi_entry_get_ndn ( e );
+ e_sdn = slapi_entry_get_sdn ( e );
+
+ slapi_mods_init_byref(&smods,mods);
+
+ for (mod = slapi_mods_get_first_mod(&smods);
+ mod != NULL;
+ mod = slapi_mods_get_next_mod(&smods)) {
+ switch (mod->mod_op & ~LDAP_MOD_BVALUES ) {
+
+ case LDAP_MOD_DELETE:
+ if (mod->mod_bvalues != NULL ) {
+ break;
+ }
+
+ /*
+ * Here, check that we have the right to delete all
+ * the values of the attribute in the entry.
+ */
+
+ case LDAP_MOD_REPLACE:
+ if ( !lastmod ) {
+ if (be == NULL) {
+ if (slapi_pblock_get( pb, SLAPI_BACKEND, &be )) {
+ be = NULL;
+ }
+ }
+ if (be != NULL)
+ slapi_pblock_get ( pb, SLAPI_BE_LASTMOD, &lastmod );
+ }
+ if (lastmod &&
+ (strcmp (mod->mod_type, "modifiersname")== 0 ||
+ strcmp (mod->mod_type, "modifytimestamp")== 0)) {
+ continue;
+ }
+
+ slapi_entry_attr_find (e, mod->mod_type, &attr);
+ if ( attr != NULL) {
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal=NULL;
+ int k= slapi_attr_first_value(attr,&sval);
+ while(k != -1) {
+ attrVal = slapi_value_get_berval(sval);
+ rv = slapi_access_allowed (pb, e,
+ mod->mod_type,
+ (struct berval *)attrVal, /* XXXggood had to cast away const - BAD */
+ ACLPB_SLAPI_ACL_WRITE_DEL); /* was SLAPI_ACL_WRITE */
+ if ( rv != LDAP_SUCCESS) {
+ acl_gen_err_msg (
+ SLAPI_ACL_WRITE,
+ n_edn,
+ mod->mod_type,
+ errbuf);
+ /* Cleanup */
+ slapi_mods_done(&smods);
+ return(rv);
+ }
+ k= slapi_attr_next_value(attr, k, &sval);
+ }
+ }
+ else {
+ rv = slapi_access_allowed (pb, e,
+ mod->mod_type,
+ NULL,
+ ACLPB_SLAPI_ACL_WRITE_DEL); /* was SLAPI_ACL_WRITE */
+ if ( rv != LDAP_SUCCESS) {
+ acl_gen_err_msg (
+ SLAPI_ACL_WRITE,
+ n_edn,
+ mod->mod_type,
+ errbuf);
+ /* Cleanup */
+ slapi_mods_done(&smods);
+ return(rv);
+ }
+ }
+ break;
+
+ default:
+ break;
+ } /* switch */
+
+ /*
+ * Check that we have add/delete writes on the specific values
+ * we are trying to add.
+ */
+
+ if ( aclpb && aclpb->aclpb_curr_entry_sdn )
+ slapi_sdn_done ( aclpb->aclpb_curr_entry_sdn );
+
+ if ( mod->mod_bvalues != NULL ) {
+
+ /*
+ * Here, there are specific values specified.
+ * For add and replace--we need add rights for these values.
+ * For delete we need delete rights for these values.
+ */
+
+ for ( i = 0; mod->mod_bvalues[i] != NULL; i++ ) {
+
+ if ( ((mod->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) ||
+ ((mod->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_REPLACE)) {
+
+ rv = acl_access_allowed (pb,e,
+ mod->mod_type,
+ mod->mod_bvalues[i],
+ ACLPB_SLAPI_ACL_WRITE_ADD); /*was SLAPI_ACL_WRITE*/
+ } else if ((mod->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ rv = acl_access_allowed (pb,e,
+ mod->mod_type,
+ mod->mod_bvalues[i],
+ ACLPB_SLAPI_ACL_WRITE_DEL); /*was SLAPI_ACL_WRITE*/
+ } else {
+ rv = LDAP_INSUFFICIENT_ACCESS;
+ }
+
+ if ( rv != LDAP_SUCCESS ) {
+ acl_gen_err_msg (
+ SLAPI_ACL_WRITE,
+ n_edn,
+ mod->mod_type,
+ errbuf);
+ /* Cleanup */
+ slapi_mods_done(&smods);
+ return rv;
+ }
+ /* Need to check for all the values because
+ ** we may be modifying a "self<right>" value.
+ */
+
+ /* Are we adding/replacing a aci attribute
+ ** value. In that case, we need to make
+ ** sure that the new value has thr right
+ ** syntax
+ */
+ if (strcmp(mod->mod_type,
+ aci_attr_type) == 0) {
+ if ( 0 != (rv = acl_verify_syntax( e_sdn,
+ mod->mod_bvalues[i]))) {
+ aclutil_print_err(rv, e_sdn,
+ mod->mod_bvalues[i],
+ errbuf);
+ /* Cleanup */
+ slapi_mods_done(&smods);
+ return LDAP_INVALID_SYNTAX;
+ }
+ }
+ } /* for */
+ }
+ } /* end of big for */
+ /* Cleanup */
+ slapi_mods_done(&smods);
+ return( LDAP_SUCCESS );
+}
+/***************************************************************************
+*
+* acl_modified
+* Modifies ( removed, add, changes) the ACI LIST.
+*
+* Input:
+* int *optype - op code
+* char *dn - DN of the entry
+* void *change - The change struct which contais the
+* - change value
+*
+* Returns:
+* None.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+extern void
+acl_modified (Slapi_PBlock *pb, int optype, char *n_dn, void *change)
+{
+ struct berval **bvalue;
+ char **value;
+ int rv=0; /* returned value */
+ char* new_RDN;
+ char* parent_DN;
+ char* new_DN;
+ LDAPMod **mods;
+ struct berval b;
+ int j;
+ Slapi_Attr *attr = NULL;
+ Slapi_Entry *e = NULL;
+ char ebuf [ BUFSIZ];
+ Slapi_DN *e_sdn;
+ aclUserGroup *ugroup = NULL;
+
+ e_sdn = slapi_sdn_new_ndn_byval ( n_dn );
+ /* Before we proceed, Let's first check if we are changing any groups.
+ ** If we are, then we need to change the signature
+ */
+ switch ( optype ) {
+ case SLAPI_OPERATION_MODIFY:
+ case SLAPI_OPERATION_DELETE:
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, (void*)&e);
+ break;
+ case SLAPI_OPERATION_ADD:
+ e = (Slapi_Entry *)change;
+ break;
+ }
+
+ /* e can be null for RDN */
+ if ( e ) slapi_entry_attr_find( e, "objectclass", &attr);
+
+ if ( attr ) {
+ int group_change = 0;
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+ int i;
+
+ i= slapi_attr_first_value ( attr,&sval );
+ while(i != -1) {
+ attrVal = slapi_value_get_berval ( sval );
+ if ( (strcasecmp (attrVal->bv_val, "groupOfNames") == 0 ) ||
+ (strcasecmp (attrVal->bv_val, "groupOfUniqueNames") == 0 ) ||
+ (strcasecmp (attrVal->bv_val, "groupOfCertificates") == 0 ) ||
+ (strcasecmp (attrVal->bv_val, "groupOfURLs") == 0 ) ) {
+ group_change= 1;
+ if ( optype == SLAPI_OPERATION_MODIFY ) {
+ Slapi_Attr *a = NULL;
+ int rv;
+ rv = slapi_entry_attr_find ( e, "uniqueMember", &a);
+ if ( rv != 0 ) break;
+ rv = slapi_entry_attr_find ( e, "Member", &a );
+ if ( rv != 0 ) break;
+ rv = slapi_entry_attr_find ( e, "MemberURL", &a );
+ if ( rv != 0 ) break;
+ /* That means we are not changing the member
+ ** list, so it's okay to let go this
+ ** change
+ */
+ group_change = 0;
+ }
+ break;
+ }
+ i= slapi_attr_next_value ( attr, i, &sval );
+ }
+
+ /*
+ ** We can do better here XXX, i.e invalidate the cache for users who
+ ** use this group. for now just do the whole thing.
+ */
+ if ( group_change ) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Group Change: Invalidating entire UserGroup Cache\n",
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION(n_dn, ebuf));
+ aclg_regen_group_signature();
+ if ( (optype == SLAPI_OPERATION_MODIFY) || (optype == SLAPI_OPERATION_DELETE ) ) {
+ /* Then we need to invalidate the acl signature also */
+ acl_signature = aclutil_gen_signature ( acl_signature );
+ }
+ }
+ }
+
+ /*
+ * Here if the target entry is in the group cache
+ * as a user then, as it's being changed it may move out of any dynamic
+ * groups it belongs to.
+ * Just remove it for now--can do better XXX by checking to see if
+ * it really needs to be removed by testing to see if he's
+ * still in th group after the change--but this requires keeping
+ * the memberURL of the group which we don't currently do.
+ * Also, if we keep
+ * the attributes that are being used in dynamic
+ * groups then we could only remove the user if a sensitive
+ * attribute was being modified (rather than scanning the whole user cache
+ * all the time). Also could do a hash lookup.
+ *
+ * aclg_find_userGroup() incs a refcnt so we can still refer to ugroup.
+ * aclg_markUgroupForRemoval() decs it and marks it for removal
+ * , so after that you cannot refer to ugroup.
+ *
+ */
+
+ if ( (ugroup = aclg_find_userGroup(n_dn)) != NULL) {
+ /*
+ * Mark this for deletion next time round--try to impact
+ * this mainline code as little as possible.
+ */
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Marking entry %s for removal from ACL user Group Cache\n",
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION(n_dn, ebuf));
+ aclg_markUgroupForRemoval (ugroup);
+ }
+
+ /*
+ * Take the write lock around all the mods--so that
+ * other operations will see the acicache either before the whole mod
+ * or after but not, as it was before, during the mod.
+ * This is in line with the LDAP concept of the operation
+ * on the whole entry being the atomic unit.
+ *
+ */
+
+ switch(optype) {
+ case SLAPI_OPERATION_DELETE:
+ /* In this case we have already checked if the user has
+ ** right to delete the entry. Part of delete of entry is
+ ** remove all the ACLs also.
+ */
+
+ acllist_acicache_WRITE_LOCK();
+ rv = acllist_remove_aci_needsLock(e_sdn, NULL);
+ acllist_acicache_WRITE_UNLOCK();
+
+ break;
+ case SLAPI_OPERATION_ADD:
+ slapi_entry_attr_find ( (Slapi_Entry *) change, aci_attr_type, &attr );
+
+ if ( attr ) {
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+ int i;
+
+ acllist_acicache_WRITE_LOCK();
+ i= slapi_attr_first_value ( attr,&sval );
+ while ( i != -1 ) {
+ attrVal = slapi_value_get_berval(sval);
+ rv= acllist_insert_aci_needsLock(e_sdn, attrVal );
+ if (rv <= ACL_ERR)
+ aclutil_print_err(rv, e_sdn, attrVal, NULL);
+ /* Print the aci list */
+ i= slapi_attr_next_value ( attr, i, &sval );
+ }
+ acllist_acicache_WRITE_UNLOCK();
+ }
+ break;
+
+ case SLAPI_OPERATION_MODIFY:
+ {
+ int got_write_lock = 0;
+
+ mods = (LDAPMod **) change;
+
+ for (j=0; mods[j] != NULL; j++) {
+ if (strcasecmp(mods[j]->mod_type, aci_attr_type) == 0) {
+
+ /* Got an aci to mod in this list of mods, so
+ * take the acicache lock for the whole list of mods,
+ * remembering to free it below.
+ */
+ if ( !got_write_lock) {
+ acllist_acicache_WRITE_LOCK();
+ got_write_lock = 1;
+ }
+
+ switch (mods[j]->mod_op & ~LDAP_MOD_BVALUES) {
+ case LDAP_MOD_REPLACE:
+ /* First remove the item */
+ rv = acllist_remove_aci_needsLock(e_sdn, NULL);
+
+ /* now fall thru to add the new one */
+ case LDAP_MOD_ADD:
+ /* Add the new aci */
+ if (mods[j]->mod_op & LDAP_MOD_BVALUES) {
+ bvalue = mods[j]->mod_bvalues;
+ if (bvalue == NULL)
+ break;
+ for (; *bvalue != NULL; ++bvalue) {
+ rv=acllist_insert_aci_needsLock( e_sdn, *bvalue);
+ if (rv <= ACL_ERR) {
+ aclutil_print_err(rv, e_sdn,
+ *bvalue, NULL);
+ }
+ }
+ } else {
+ value = mods[j]->mod_values;
+ if (value == NULL)
+ break;
+ for (; *value != NULL; ++value) {
+ b.bv_len = strlen (*value);
+ b.bv_val = *value;
+ rv=acllist_insert_aci_needsLock( e_sdn, &b);
+ if (rv <= ACL_ERR) {
+ aclutil_print_err(rv, e_sdn,
+ &b, NULL);
+ }
+ }
+ }
+ break;
+ case LDAP_MOD_DELETE:
+ if (mods[j]->mod_op & LDAP_MOD_BVALUES) {
+ bvalue = mods[j]->mod_bvalues;
+ if (bvalue == NULL || *bvalue == NULL) {
+ rv = acllist_remove_aci_needsLock( e_sdn, NULL);
+ } else {
+ for (; *bvalue != NULL; ++bvalue)
+ acllist_remove_aci_needsLock( e_sdn, *bvalue);
+ }
+ } else {
+ value = mods[j]->mod_values;
+ if (value == NULL || *value == NULL) {
+ acllist_remove_aci_needsLock( e_sdn,NULL);
+ } else {
+ for (; *value != NULL; ++value) {
+ b.bv_len = strlen (*value);
+ b.bv_val = *value;
+ acllist_remove_aci_needsLock( e_sdn, &b);
+ }
+ }
+
+ }
+ break;
+
+ default:
+ break;
+ }/* modtype switch */
+ }/* attrtype is aci */
+ } /* end of for */
+ if ( got_write_lock ) {
+ acllist_acicache_WRITE_UNLOCK();
+ got_write_lock = 0;
+ }
+
+ break;
+ }/* case op is modify*/
+
+ case SLAPI_OPERATION_MODRDN:
+
+ new_RDN = (char*) change;
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "acl_modified (MODRDN %s => \"%s\"\n",
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION (n_dn, ebuf), new_RDN, 0);
+
+ /* compute new_DN: */
+ parent_DN = slapi_dn_parent (n_dn);
+ if (parent_DN == NULL) {
+ new_DN = new_RDN;
+ } else {
+ new_DN = (char*) slapi_ch_malloc (strlen (new_RDN) + 3
+ + strlen (parent_DN));
+ strcpy (new_DN, new_RDN);
+ strcat (new_DN, ",");
+ strcat (new_DN, parent_DN);
+ slapi_dn_normalize (new_DN);
+ }
+
+ /* Change the acls */
+ acllist_acicache_WRITE_LOCK();
+ acllist_moddn_aci_needsLock ( e_sdn, new_DN );
+ acllist_acicache_WRITE_UNLOCK();
+
+ /* deallocat the parent_DN */
+ if (parent_DN != NULL) {
+ slapi_ch_free ( (void **) &new_DN );
+ slapi_ch_free ( (void **) &parent_DN );
+ }
+ break;
+
+ default:
+ /* print ERROR */
+ break;
+ } /*optype switch */
+
+ slapi_sdn_free ( &e_sdn );
+
+}
+/***************************************************************************
+*
+* acl__scan_for_acis
+* Scan the list and picup the correct acls for evaluation.
+*
+* Input:
+* Acl_PBlock *aclpb - Main ACL pblock
+* int *err; - Any error status
+* Returns:
+* num_handles - Number of handles matched to the
+* - resource + 1.
+* Error Handling:
+* None.
+*
+**************************************************************************/
+static int
+acl__scan_for_acis(Acl_PBlock *aclpb, int *err)
+{
+ aci_t *aci;
+ NSErr_t errp;
+ int attr_matched;
+ int deny_handle;
+ int allow_handle;
+ int gen_allow_handle = ACI_MAX_ELEVEL+1;
+ int gen_deny_handle = ACI_MAX_ELEVEL+1;
+ int i;
+ PRUint32 cookie;
+
+ TNF_PROBE_0_DEBUG(acl__scan_for_acis_start,"ACL","");
+
+ /*
+ ** Determine if we are traversing via the list Vs. we have our own
+ ** generated list
+ */
+ if ( aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST ||
+ aclpb->aclpb_handles_index[0] != -1 ) {
+ int kk = 0;
+ while ( kk < ACLPB_MAX_SELECTED_ACLS && aclpb->aclpb_handles_index[kk] != -1 ) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name, "Using ACL Cointainer:%d for evaluation\n", kk);
+ kk++;
+ }
+ }
+
+ memset (&errp, 0, sizeof(NSErr_t));
+ *err = ACL_FALSE;
+ aclpb->aclpb_num_deny_handles = -1;
+ aclpb->aclpb_num_allow_handles = -1;
+ for (i=0; i <= ACI_MAX_ELEVEL; i++) {
+ aclpb->aclpb_deny_handles [i] = NULL;
+ aclpb->aclpb_allow_handles [i] = NULL;
+ }
+
+ /* Check the signature. If it has changed, start fresh */
+ if ( aclpb->aclpb_signature != acl_signature ) {
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "Restart the scan -- due to acl changes\n");
+ acllist_init_scan ( aclpb->aclpb_pblock, LDAP_SCOPE_BASE, NULL );
+ }
+
+ attr_matched = ACL_FALSE;
+ deny_handle = 0;
+ allow_handle = 0;
+ i = 0;
+
+ aclpb->aclpb_stat_acllist_scanned++;
+ aci = acllist_get_first_aci ( aclpb, &cookie );
+
+ while( aci ) {
+ if (acl__resource_match_aci(aclpb, aci, 0, &attr_matched)) {
+ /* Generate the ACL list handle */
+ if (aci->aci_handle == NULL) {
+ aci = acllist_get_next_aci ( aclpb, aci, &cookie );
+ continue;
+ }
+ aclutil_print_aci (aci, acl_access2str (aclpb->aclpb_access));
+
+ if (aci->aci_type & ACI_HAS_DENY_RULE) {
+ if (aclpb->aclpb_deny_handles[aci->aci_elevel] == NULL ) {
+ aclpb->aclpb_deny_handles[aci->aci_elevel] = aci;
+ } else {
+ if ((gen_deny_handle + ACI_DEFAULT_ELEVEL + 1) ==
+ aclpb->aclpb_deny_handles_size ) {
+ int num = ACLPB_INCR_LIST_HANDLES +
+ aclpb->aclpb_deny_handles_size;
+ /* allocate more space */
+ aclpb->aclpb_deny_handles =
+ (aci_t **)
+ slapi_ch_realloc (
+ (void *) aclpb->aclpb_deny_handles,
+ num * sizeof (aci_t *));
+ aclpb->aclpb_deny_handles_size = num;
+ }
+ aclpb->aclpb_deny_handles [gen_deny_handle] = aci;
+ gen_deny_handle++;
+ }
+ deny_handle++;
+ }
+ /*
+ ** It's possible that a single acl is in both the camps i.e
+ ** It has a allow and a deny rule
+ ** In that case we keep the same acl in both the camps.
+ */
+ if (aci->aci_type & ACI_HAS_ALLOW_RULE) {
+ if (aclpb->aclpb_allow_handles[aci->aci_elevel] == NULL ) {
+ aclpb->aclpb_allow_handles[aci->aci_elevel] = aci;
+ } else {
+ if ((gen_allow_handle + ACI_DEFAULT_ELEVEL + 1) ==
+ aclpb->aclpb_allow_handles_size) {
+ /* allocate more space */
+ int num = ACLPB_INCR_LIST_HANDLES +
+ aclpb->aclpb_allow_handles_size;
+
+ aclpb->aclpb_allow_handles =
+ (aci_t **)
+ slapi_ch_realloc (
+ (void *) aclpb->aclpb_allow_handles,
+ num * sizeof (aci_t *));
+ aclpb->aclpb_allow_handles_size = num;
+ }
+ aclpb->aclpb_allow_handles [gen_allow_handle] = aci;
+ gen_allow_handle++;
+ }
+ allow_handle++;
+ }
+ }
+ aci = acllist_get_next_aci ( aclpb, aci, &cookie );
+ } /* end of while */
+
+ /* make the last one a null */
+ aclpb->aclpb_deny_handles [gen_deny_handle] = NULL;
+ aclpb->aclpb_allow_handles [gen_allow_handle] = NULL;
+
+ /* specify how many we found */
+ aclpb->aclpb_num_deny_handles = deny_handle;
+ aclpb->aclpb_num_allow_handles = allow_handle;
+
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name, "Num of ALLOW Handles:%d, DENY handles:%d\n",
+ aclpb->aclpb_num_allow_handles, aclpb->aclpb_num_deny_handles, 0);
+
+ TNF_PROBE_0_DEBUG(acl__scan_for_acis_end,"ACL","");
+
+ return(allow_handle + deny_handle);
+}
+
+/***************************************************************************
+*
+* acl__resource_match_aci
+*
+* This compares the ACI for the given resource and determines if
+* the ACL applies to the resource or not.
+*
+* For read/search operation, we collect all the possible acls which
+* will apply, We will be using this list for future acl evaluation
+* for that entry.
+*
+* Input:
+* struct acl_pblock *aclpb - Main acl private block
+* aci_t *aci - The ACI item
+* int skip_attrEval - DOn't check for attrs
+* int *a_matched - Attribute matched
+*
+* Returns:
+*
+* ACL_TRUE - Yep, This ACL is applicable to the
+* - the resource.
+* ACL_FALSE - No it is not.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+#define ACL_RIGHTS_TARGETATTR_NOT_NEEDED ( SLAPI_ACL_ADD | SLAPI_ACL_DELETE | SLAPI_ACL_PROXY)
+static int
+acl__resource_match_aci( Acl_PBlock *aclpb, aci_t *aci, int skip_attrEval, int *a_matched)
+{
+
+ struct slapi_filter *f; /* filter */
+ int rv; /* return value */
+ int matches;
+ int attr_matched;
+ int attr_matched_in_targetattrfilters = 0;
+ int dn_matched;
+ char *res_attr;
+ int aci_right = 0;
+ int res_right = 0;
+ int star_matched = ACL_FALSE;
+ int num_attrs = 0;
+ AclAttrEval *c_attrEval = NULL;
+ const char *res_ndn = NULL;
+ const char *aci_ndn = NULL;
+ char *matched_val = NULL;
+ int add_matched_val_to_ht = 0;
+ char res_right_str[128];
+
+ TNF_PROBE_0_DEBUG(acl__resource_match_aci_start,"ACL","");
+
+ aclpb->aclpb_stat_aclres_matched++;
+
+ /* Assume that resource matches */
+ matches = ACL_TRUE;
+
+ /* Figure out if the acl has the correct rights or not */
+ aci_right = aci->aci_access;
+ res_right = aclpb->aclpb_access;
+ if (!(aci_right & res_right)) {
+ /* If we are looking for read/search and the acl has read/search
+ ** then go further because if targets match we may keep that
+ ** acl in the entry cache list.
+ */
+ if (!((res_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) &&
+ (aci_right & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ))))
+ matches = ACL_FALSE;
+ goto acl__resource_match_aci_EXIT;
+ }
+
+
+ /* first Let's see if the entry is under the subtree where the
+ ** ACL resides. We can't let somebody affect a target beyond the
+ ** scope of where the ACL resides
+ ** Example: ACL is located in "ou=engineering, o=ace industry, c=us
+ ** but if the target is "o=ace industry, c=us", then we are in trouble.
+ **
+ ** If the aci is in the rootdse and the entry is not, then we do not
+ ** match--ie. acis in the rootdse do NOT apply below...for the moment.
+ **
+ */
+ res_ndn = slapi_sdn_get_ndn ( aclpb->aclpb_curr_entry_sdn );
+ aci_ndn = slapi_sdn_get_ndn ( aci->aci_sdn );
+ if (!slapi_sdn_issuffix(aclpb->aclpb_curr_entry_sdn, aci->aci_sdn)
+ || (!slapi_is_rootdse(res_ndn) && slapi_is_rootdse(aci_ndn)) ) {
+
+ /* cant' poke around */
+ matches = ACL_FALSE;
+ goto acl__resource_match_aci_EXIT;
+ }
+
+ /*
+ ** We have a single ACI which we need to find if it applies to
+ ** the resource or not.
+ */
+ if ((aci->aci_type & ACI_TARGET_DN) &&
+ (aclpb->aclpb_curr_entry_sdn)) {
+ char *avaType;
+ struct berval *avaValue;
+
+ f = aci->target;
+ dn_matched = ACL_TRUE;
+ slapi_filter_get_ava ( f, &avaType, &avaValue );
+
+ if (!slapi_dn_issuffix( res_ndn, avaValue->bv_val)) {
+ dn_matched = ACL_FALSE;
+ }
+ if (aci->aci_type & ACI_TARGET_NOT) {
+ matches = (dn_matched ? ACL_FALSE : ACL_TRUE);
+ } else {
+ matches = (dn_matched ? ACL_TRUE: ACL_FALSE);
+ }
+ }
+
+ /* No need to look further */
+ if (matches == ACL_FALSE) {
+ goto acl__resource_match_aci_EXIT;
+ }
+
+ if (aci->aci_type & ACI_TARGET_PATTERN) {
+
+ f = aci->target;
+ dn_matched = ACL_TRUE;
+
+ if ((rv = acl_match_substring(f, (char *)res_ndn, 0 /* match suffux */)) != ACL_TRUE) {
+ dn_matched = ACL_FALSE;
+ if(rv == ACL_ERR) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "acl__resource_match_aci:pattern err\n",
+ 0,0,0);
+ matches = ACL_FALSE;
+ goto acl__resource_match_aci_EXIT;
+ }
+ }
+ if (aci->aci_type & ACI_TARGET_NOT) {
+ matches = (dn_matched ? ACL_FALSE : ACL_TRUE);
+ } else {
+ matches = (dn_matched ? ACL_TRUE: ACL_FALSE);
+ }
+ }
+
+ /* No need to look further */
+ if (matches == ACL_FALSE) {
+ goto acl__resource_match_aci_EXIT;
+ }
+
+ /*
+ * Is it a (target="ldap://cn=*,($dn),o=sun.com") kind of thing.
+ */
+ if (aci->aci_type & ACI_TARGET_MACRO_DN) {
+ /*
+ * See if the ($dn) component matches the string and
+ * retrieve the matched substring for later use
+ * in the userdn.
+ * The macro string is a function of the dn only, so if the
+ * entry is the same one don't recalculate it--
+ * this flag only works for search right now, could
+ * also optimise for mods by making it work for mods.
+ */
+
+ if ( (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY) == 0 ) {
+ /*
+ * Here same entry so just look up the matched value,
+ * calculated from the targetdn and stored judiciously there
+ */
+ matched_val = (char *)acl_ht_lookup( aclpb->aclpb_macro_ht,
+ (PLHashNumber)aci->aci_index);
+ }
+ if ( matched_val == NULL &&
+ (aclpb->aclpb_res_type & (ACLPB_NEW_ENTRY | ACLPB_EFFECTIVE_RIGHTS))) {
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "Evaluating macro aci(%d)%s for resource %s\n",
+ aci->aci_index, aci->aclName,
+ aclutil__access_str(res_right, res_right_str));
+ matched_val = acl_match_macro_in_target( res_ndn,
+ aci->aci_macro->match_this,
+ aci->aci_macro->macro_ptr);
+ add_matched_val_to_ht = 1; /* may need to add matched value to ht */
+ }
+ if (matched_val == NULL) {
+ dn_matched = ACL_FALSE;
+ } else {
+ dn_matched = ACL_TRUE;
+ }
+
+ if (aci->aci_type & ACI_TARGET_NOT) {
+ matches = (dn_matched ? ACL_FALSE : ACL_TRUE);
+ } else {
+ matches = (dn_matched ? ACL_TRUE: ACL_FALSE);
+ }
+
+ if ( add_matched_val_to_ht ) {
+ if ( matches == ACL_TRUE && matched_val ) {
+ /*
+ * matched_val may be needed later for matching on
+ * other targets or on the subject--so optimistically
+ * put it in the hash table.
+ * If, at the end of this routine, we
+ * find that after all the resource did not match then
+ * that's ok--the value is freed at aclpb cleanup time.
+ * If there is already an entry for this aci in this
+ * aclpb then remove it--it's an old value for a
+ * different entry.
+ */
+
+ acl_ht_add_and_freeOld(aclpb->aclpb_macro_ht,
+ (PLHashNumber)aci->aci_index,
+ matched_val);
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "-- Added aci(%d) and matched value (%s) to macro ht\n",
+ aci->aci_index, matched_val);
+ acl_ht_display_ht(aclpb->aclpb_macro_ht);
+ } else {
+ slapi_ch_free((void **)&matched_val);
+ if (matches == ACL_FALSE) {
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "Evaluated ACL_FALSE\n");
+ }
+ }
+ }
+ } /* MACRO_DN */
+
+ /* No need to look further */
+ if (matches == ACL_FALSE) {
+ goto acl__resource_match_aci_EXIT;
+ }
+
+ /*
+ ** Here, if there's a targetfilter field, see if it matches.
+ **
+ ** The commented out code below was an erroneous attempt to skip
+ ** this test. It is wrong because: 1. you need to store
+ ** whether the last test matched or not (you cannot just assume it did)
+ ** and 2. It may not be the same aci, so the previous matched
+ ** value is a function of the aci.
+ ** May be interesting to build such a cache...but no evidence for
+ ** for that right now. See Bug 383424.
+ **
+ **
+ ** && ((aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_LIST) ||
+ ** (aclpb->aclpb_res_type & ACLPB_NEW_ENTRY))
+ */
+ if (aci->aci_type & ACI_TARGET_FILTER ) {
+ int filter_matched = ACL_TRUE;
+
+ /*
+ * Check for macros.
+ * For targetfilter we need to fake the lasinfo structure--it's
+ * created "naturally" for subjects but not targets.
+ */
+
+
+ if ( aci->aci_type & ACI_TARGET_FILTER_MACRO_DN) {
+
+ lasInfo *lasinfo = NULL;
+
+ lasinfo = (lasInfo*) slapi_ch_malloc( sizeof(lasInfo) );
+
+ lasinfo->aclpb = aclpb;
+ lasinfo->resourceEntry = aclpb->aclpb_curr_entry;
+ aclpb->aclpb_curr_aci = aci;
+ filter_matched = aclutil_evaluate_macro( aci->targetFilterStr,
+ lasinfo,
+ ACL_EVAL_TARGET_FILTER);
+ slapi_ch_free((void**)&lasinfo);
+ } else {
+
+
+ if (slapi_vattr_filter_test(NULL, aclpb->aclpb_curr_entry,
+ aci->targetFilter,
+ 0 /*don't do acess chk*/)!= 0) {
+ filter_matched = ACL_FALSE;
+ }
+
+ }
+
+ /* If it's a logical value we can do logic on it...otherwise we do not match */
+ if ( filter_matched == ACL_TRUE || filter_matched == ACL_FALSE) {
+ if (aci->aci_type & ACI_TARGET_FILTER_NOT) {
+ matches = (filter_matched == ACL_TRUE ? ACL_FALSE : ACL_TRUE);
+ } else {
+ matches = (filter_matched == ACL_TRUE ? ACL_TRUE: ACL_FALSE);
+ }
+ } else {
+ matches = ACL_FALSE;
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Returning UNDEFINED for targetfilter evaluation.\n");
+ }
+
+ if (matches == ACL_FALSE) {
+ goto acl__resource_match_aci_EXIT;
+ }
+ }
+
+ /*
+ * Check to see if we need to evaluate any targetattrfilters.
+ * They look as follows:
+ * (targetattrfilters="add=sn:(sn=rob) && gn:(gn!=byrne),
+ * del=sn:(sn=rob) && gn:(gn=byrne)")
+ *
+ * For ADD/DELETE:
+ * If theres's a targetattrfilter then each add/del filter
+ * that applies to an attribute in the entry, must be satisfied
+ * by each value of the attribute in the entry.
+ *
+ * For MODIFY:
+ * If there's a targetattrfilter then the add/del filter
+ * must be satisfied by the attribute to be added/deleted.
+ * (MODIFY acl is evaluated one value at a time).
+ *
+ *
+ */
+
+ if ((aclpb->aclpb_access & SLAPI_ACL_ADD &&
+ aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS )||
+ (aclpb->aclpb_access & SLAPI_ACL_DELETE &&
+ aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS ) ) {
+
+ Targetattrfilter **attrFilterArray;
+
+ Targetattrfilter *attrFilter = NULL;
+
+ int found_applicable = 0;
+ Slapi_Attr *attr_ptr = NULL;
+ Slapi_Value *sval;
+ const struct berval *attrVal;
+ int k;
+ int done;
+
+
+ if (aclpb->aclpb_access & SLAPI_ACL_ADD &&
+ aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) {
+
+ attrFilterArray = aci->targetAttrAddFilters;
+
+ } else if (aclpb->aclpb_access & SLAPI_ACL_DELETE &&
+ aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS) {
+
+ attrFilterArray = aci->targetAttrDelFilters;
+
+ }
+
+ attr_matched = ACL_TRUE;
+ num_attrs = 0;
+
+ while (attrFilterArray[num_attrs] && attr_matched) {
+ attrFilter = attrFilterArray[num_attrs];
+
+ /*
+ * If this filter applies to an attribute in the entry,
+ * apply it to the entry.
+ * Otherwise just ignore it.
+ *
+ */
+
+ if (slapi_entry_attr_find ( aclpb->aclpb_curr_entry,
+ attrFilter->attr_str,
+ &attr_ptr) == 0) {
+
+ /*
+ * This is an applicable filter.
+ * The filter is to be appplied to the entry being added
+ * or deleted.
+ * The filter needs to be satisfied by _each_ occurence
+ * of the attribute in the entry--otherwise you
+ * could satisfy the filter and then put loads of other
+ * values in on the back of it.
+ */
+
+ found_applicable = 1;
+
+ sval=NULL;
+ attrVal=NULL;
+ k= slapi_attr_first_value(attr_ptr,&sval);
+ done = 0;
+ while(k != -1 && !done) {
+ attrVal = slapi_value_get_berval(sval);
+
+ if ( acl__make_filter_test_entry(
+ &aclpb->aclpb_filter_test_entry,
+ attrFilter->attr_str,
+ (struct berval *)attrVal) == LDAP_SUCCESS ) {
+
+ attr_matched= acl__test_filter(
+ aclpb->aclpb_filter_test_entry,
+ attrFilter->filter,
+ 1 /* Do filter sense evaluation below */
+ );
+ done = !attr_matched;
+ slapi_entry_free( aclpb->aclpb_filter_test_entry );
+ }
+
+ k= slapi_attr_next_value(attr_ptr, k, &sval);
+ }/* while */
+
+ /*
+ * Here, we applied an applicable filter to the entry.
+ * So if attr_matched is ACL_TRUE then every value
+ * of the attribute in the entry satisfied the filter.
+ * Otherwise, attr_matched is ACL_FALSE and not every
+ * value satisfied the filter, so we will teminate the
+ * scan of the filter list.
+ */
+
+ }
+
+ num_attrs++;
+ } /* while */
+
+ /*
+ * Here, we've applied all the applicable filters to the entry.
+ * Each one must have been satisfied by all the values of the attribute.
+ * The result of this is stored in attr_matched.
+ */
+
+#if 0
+ /*
+ * Don't support a notion of "add != " or "del != "
+ * at the moment.
+ * To do this, need to test whether it's an add test or del test
+ * then if it's add and ACI_TARGET_ATTR_ADD_FILTERS_NOT then
+ * flip the bit. Same for del.
+ */
+
+ if (aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS_NOT) {
+ matches = (matches ? ACL_FALSE : ACL_TRUE);
+ } else {
+ matches = (matches ? ACL_TRUE: ACL_FALSE);
+ }
+#endif
+
+ /* No need to look further */
+ if (attr_matched == ACL_FALSE) {
+ matches = ACL_FALSE;
+ goto acl__resource_match_aci_EXIT;
+ }
+
+ } else if ( (aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD &&
+ aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) ||
+ (aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL &&
+ aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS ) ) {
+
+
+ /*
+ * Here, it's a modify add/del and we have attr filters.
+ * So, we need to scan the add/del filter list to find the filter
+ * that applies to the current attribute.
+ * Then the (attribute,value) pair being added/deleted better
+ * match that filter.
+ *
+ *
+ */
+
+ Targetattrfilter **attrFilterArray = NULL;
+ Targetattrfilter *attrFilter;
+ int found = 0;
+
+ if (aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_ADD &&
+ aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) {
+
+ attrFilterArray = aci->targetAttrAddFilters;
+
+ } else if (aclpb->aclpb_access & ACLPB_SLAPI_ACL_WRITE_DEL &&
+ aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS) {
+
+ attrFilterArray = aci->targetAttrDelFilters;
+
+ }
+
+
+ /*
+ * Scan this filter list for an applicable filter.
+ */
+
+ found = 0;
+ num_attrs = 0;
+
+ while (attrFilterArray[num_attrs] && !found) {
+ attrFilter = attrFilterArray[num_attrs];
+
+ /* If this filter applies to the attribute, stop. */
+ if ((aclpb->aclpb_curr_attrEval) &&
+ slapi_attr_type_cmp ( aclpb->aclpb_curr_attrEval->attrEval_name,
+ attrFilter->attr_str, 1) == 0) {
+ found = 1;
+ }
+ num_attrs++;
+ }
+
+ /*
+ * Here, if found an applicable filter, then apply the filter to the
+ * (attr,val) pair.
+ * Otherwise, ignore the targetattrfilters.
+ */
+
+ if (found) {
+
+ if ( acl__make_filter_test_entry(
+ &aclpb->aclpb_filter_test_entry,
+ aclpb->aclpb_curr_attrEval->attrEval_name,
+ aclpb->aclpb_curr_attrVal) == LDAP_SUCCESS ) {
+
+ attr_matched= acl__test_filter(aclpb->aclpb_filter_test_entry,
+ attrFilter->filter,
+ 1 /* Do filter sense evaluation below */
+ );
+ slapi_entry_free( aclpb->aclpb_filter_test_entry );
+ }
+
+ /* No need to look further */
+ if (attr_matched == ACL_FALSE) {
+ matches = attr_matched;
+ goto acl__resource_match_aci_EXIT;
+ }
+
+ /*
+ * Here this attribute appeared and was matched in a
+ * targetattrfilters list, so record this fact so we do
+ * not have to scan the targetattr list for the attribute.
+ */
+
+ attr_matched_in_targetattrfilters = 1;
+
+
+ }
+ } /* targetvaluefilters */
+
+
+ /* There are 3 cases by which acis are selected.
+ ** 1) By scanning the whole list and picking based on the resource.
+ ** 2) By picking a subset of the list which will be used for the whole
+ ** acl evaluation.
+ ** 3) A finer granularity, i.e, a selected list of acls which will be
+ ** used for only that entry's evaluation.
+ */
+ if ( !(skip_attrEval) && (aclpb->aclpb_state & ACLPB_SEARCH_BASED_ON_ENTRY_LIST) &&
+ (res_right & SLAPI_ACL_SEARCH) &&
+ ((aci->aci_access & SLAPI_ACL_READ) || (aci->aci_access & SLAPI_ACL_SEARCH))) {
+ int kk=0;
+
+ while ( kk < ACLPB_MAX_SELECTED_ACLS && aclpb->aclpb_handles_index[kk] >=0 ) kk++;
+ if (kk >= ACLPB_MAX_SELECTED_ACLS) {
+ aclpb->aclpb_state &= ~ACLPB_SEARCH_BASED_ON_ENTRY_LIST;
+ } else {
+ aclpb->aclpb_handles_index[kk++] = aci->aci_index;
+ aclpb->aclpb_handles_index[kk] = -1;
+ }
+ }
+
+
+ /* If we are suppose to skip attr eval, then let's skip it */
+ if ( (aclpb->aclpb_access & SLAPI_ACL_SEARCH ) && ( ! skip_attrEval ) &&
+ ( aclpb->aclpb_res_type & ACLPB_NEW_ENTRY )) {
+ aclEvalContext *c_evalContext = &aclpb->aclpb_curr_entryEval_context;
+ int nhandle = c_evalContext->acle_numof_tmatched_handles;
+
+ if ( nhandle < ACLPB_MAX_SELECTED_ACLS) {
+ c_evalContext->acle_handles_matched_target[nhandle] = aci->aci_index;
+ c_evalContext->acle_numof_tmatched_handles++;
+ }
+ }
+
+ if ( skip_attrEval ) {
+ goto acl__resource_match_aci_EXIT;
+ }
+
+ /* We need to check again because we don't want to select this handle
+ ** if the right doesn't match for now.
+ */
+ if (!(aci_right & res_right)) {
+ matches = ACL_FALSE;
+ goto acl__resource_match_aci_EXIT;
+ }
+
+ /*
+ * Here if the request is one that requires matching
+ * on a targetattr then do it here.
+ * If we have already matched an attribute in the targetattrfitlers list
+ * then we do not require a match in the targetattr so we can skip it.
+ * The operations that require targetattr are SLAPI_ACL_COMPARE,
+ * SLAPI_ACL_SEARCH, SLAPI_ACL_READ and SLAPI_ACL_WRITE, as long as
+ * c_attrEval is non-null (otherwise it's a modrdn op which
+ * does not require the targetattr list).
+ *
+ * rbyrneXXX if we had a proper permission for modrdn eg SLAPI_ACL_MODRDN
+ * then we would not need this crappy way of telling it was a MODRDN
+ * request ie. SLAPI_ACL_WRITE && !(c_attrEval).
+ */
+
+ c_attrEval = aclpb->aclpb_curr_attrEval;
+
+ /*
+ * If we've already matched on targattrfilter then do not
+ * bother to look at the attrlist.
+ */
+
+ if (!attr_matched_in_targetattrfilters) {
+
+ /* match target attr */
+ if ((c_attrEval) &&
+ (aci->aci_type & ACI_TARGET_ATTR)) {
+ /* there is a target ATTR */
+ Targetattr **attrArray = aci->targetAttr;
+ Targetattr *attr = NULL;
+
+ res_attr = c_attrEval->attrEval_name;
+ attr_matched = ACL_FALSE;
+ star_matched = ACL_FALSE;
+ num_attrs = 0;
+
+ while (attrArray[num_attrs] && !attr_matched) {
+ attr = attrArray[num_attrs];
+ if (attr->attr_type & ACL_ATTR_STRING) {
+ if (slapi_attr_type_cmp ( res_attr,
+ attr->u.attr_str, 1) == 0) {
+ attr_matched = ACL_TRUE;
+ *a_matched = ACL_TRUE;
+ }
+ } else if (attr->attr_type & ACL_ATTR_FILTER) {
+ if (ACL_TRUE == acl_match_substring (
+ attr->u.attr_filter,
+ res_attr, 1)) {
+ attr_matched = ACL_TRUE;
+ *a_matched = ACL_TRUE;
+ }
+ } else if (attr->attr_type & ACL_ATTR_STAR) {
+ attr_matched = ACL_TRUE;
+ *a_matched = ACL_TRUE;
+ star_matched = ACL_TRUE;
+ }
+ num_attrs++;
+ }
+
+ if (aci->aci_type & ACI_TARGET_ATTR_NOT) {
+ matches = (attr_matched ? ACL_FALSE : ACL_TRUE);
+ } else {
+ matches = (attr_matched ? ACL_TRUE: ACL_FALSE);
+ }
+
+
+ aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
+ /* figure out how it matched, i.e star matched */
+ if (matches && star_matched && num_attrs == 1 &&
+ !(aclpb->aclpb_state & ACLPB_FOUND_ATTR_RULE))
+ aclpb->aclpb_state |= ACLPB_ATTR_STAR_MATCHED;
+ else {
+ /* we are here means that there is a specific
+ ** attr in the rule for this resource.
+ ** We need to avoid this case
+ ** Rule 1: (targetattr = "uid")
+ ** Rule 2: (targetattr = "*")
+ ** we cannot use STAR optimization
+ */
+ aclpb->aclpb_state |= ACLPB_FOUND_ATTR_RULE;
+ aclpb->aclpb_state &= ~ACLPB_ATTR_STAR_MATCHED;
+ }
+ } else if ( (c_attrEval) ||
+ (aci->aci_type & ACI_TARGET_ATTR)) {
+ if ((aci_right & ACL_RIGHTS_TARGETATTR_NOT_NEEDED) &&
+ (aclpb->aclpb_access & ACL_RIGHTS_TARGETATTR_NOT_NEEDED)) {
+ /*
+ ** Targetattr rule doesn't make any sense
+ ** in this case. So select this rule
+ ** default: matches = ACL_TRUE;
+ */
+ ;
+ } else if (aci_right & SLAPI_ACL_WRITE &&
+ (aci->aci_type & ACI_TARGET_ATTR) &&
+ !(c_attrEval)) {
+ /* We need to handle modrdn operation. Modrdn doesn't
+ ** change any attrs but changes the RDN and so (attr=NULL).
+ ** Here we found an acl which has a targetattr but
+ ** the resource doesn't need one. In that case, we should
+ ** consider this acl.
+ ** default: matches = ACL_TRUE;
+ */
+ ;
+ } else {
+ matches = ACL_FALSE;
+ }
+ }
+ }/* !attr_matched_in_targetattrfilters */
+
+ /*
+ ** Here we are testing if we find a entry test rule (which should
+ ** be rare). In that case, just remember it. An entry test rule
+ ** doesn't have "(targetattr)".
+ */
+ if (aclpb && (aclpb->aclpb_state & ACLPB_EVALUATING_FIRST_ATTR) &&
+ (!(aci->aci_type & ACI_TARGET_ATTR))) {
+ aclpb->aclpb_state |= ACLPB_FOUND_A_ENTRY_TEST_RULE;
+ }
+
+ /*
+ * Generic exit point for this routine:
+ * matches is ACL_TRUE if the aci matches the target of the resource,
+ * ACL_FALSE othrewise.
+ * Apologies for the goto--this is a retro-fitted exit point.
+ */
+acl__resource_match_aci_EXIT:
+
+ /*
+ * For macro acis, there may be a partial macro string
+ * placed in the aclpb_macro_ht
+ * even if the aci did not finally match.
+ * All the partial strings will be freed at aclpb
+ * cleanup time.
+ */
+
+ TNF_PROBE_0_DEBUG(acl__resource_match_aci_end,"ACL","");
+
+ return (matches);
+}
+/* Macro to determine if the cached result is valid or not. */
+#define ACL_CACHED_RESULT_VALID( result) \
+ (((result & ACLPB_CACHE_READ_RES_ALLOW) && \
+ (result & ACLPB_CACHE_READ_RES_SKIP)) || \
+ ((result & ACLPB_CACHE_SEARCH_RES_ALLOW) && \
+ (result & ACLPB_CACHE_SEARCH_RES_SKIP))) ? 0 : 1
+/***************************************************************************
+*
+* acl__TestRights
+*
+* Test the rights and find out if access is allowed or not.
+*
+* Processing Alogorithm:
+*
+* First, process the DENY rules one by one. If the user is not explicitly
+* denied, then check if the user is allowed by processing the ALLOW handles
+* one by one.
+* The result of the evaluation is cached. Exceptions are
+* -- If an acl happens to be in both DENY and ALLOW camp.
+* -- Only interested for READ/SEARCH right.
+*
+* Input:
+* struct acl_pblock *aclpb - main acl private block
+* int access - The access bits
+* char **right - The right we are looking for
+* char ** generic - Generic rights
+*
+* Returns:
+*
+* ACL_RES_ALLOW - Access allowed
+* ACL_RES_DENY - Access denied
+* err - error condition
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+static int
+acl__TestRights(Acl_PBlock *aclpb,int access, char **right, char ** map_generic,
+ aclResultReason_t *result_reason)
+{
+ ACLEvalHandle_t *acleval;
+ int rights_rv = ACL_RES_DENY;
+ int rv, i,j, k;
+ int index;
+ char *deny = NULL;
+ char *deny_generic = NULL;
+ char *acl_tag;
+ int expr_num;
+ char *testRights[2];
+ aci_t *aci;
+ int numHandles = 0;
+ aclEvalContext *c_evalContext = NULL;
+
+ TNF_PROBE_0_DEBUG(acl__TestRights_start,"ACL","");
+
+ c_evalContext = &aclpb->aclpb_curr_entryEval_context;
+
+ /* record the aci and reason for access decision */
+ result_reason->deciding_aci = NULL;
+ result_reason->reason = ACL_REASON_NONE;
+
+ /* If we don't have any ALLLOW handles, it's DENY by default */
+ if (aclpb->aclpb_num_allow_handles <= 0) {
+ result_reason->deciding_aci = NULL;
+ result_reason->reason = ACL_REASON_NO_MATCHED_RESOURCE_ALLOWS;
+
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,no_allows,"");
+
+ return ACL_RES_DENY;
+ }
+
+ /* Get the ACL evaluation Context */
+ acleval = aclpb->aclpb_acleval;
+
+ testRights[0] = *right;
+ testRights[1] = '\0';
+
+ /*
+ ** START PROCESSING DENY HANDLES
+ ** Process each handle at a time. Do not concatenate the handles or else
+ ** all the context information will be build again and we will pay a
+ ** lot of penalty. The context is built the first time the handle is
+ ** processed.
+ **
+ ** First we set the default to INVALID so that if rules are not matched, then
+ ** we get INVALID and if a rule matched, the we get DENY.
+ */
+ aclpb->aclpb_state &= ~ACLPB_EXECUTING_ALLOW_HANDLES;
+ aclpb->aclpb_state |= ACLPB_EXECUTING_DENY_HANDLES;
+ ACL_SetDefaultResult (NULL, acleval, ACL_RES_INVALID);
+
+ numHandles = ACI_MAX_ELEVEL + aclpb->aclpb_num_deny_handles;
+ for (i=0, k=0; i < numHandles && k < aclpb->aclpb_num_deny_handles ; ++i) {
+ int skip_eval = 0;
+
+ /*
+ ** If the handle has been evaluated before, we can
+ ** cache the result.
+ */
+ if (((aci = aclpb->aclpb_deny_handles[i]) == NULL) && (i <= ACI_MAX_ELEVEL))
+ continue;
+ k++;
+ index = aci->aci_index;
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Evaluating DENY aci(%d) \"%s\"\n", index, aci->aclName);
+
+ if (access & ( SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) {
+
+ /*
+ * aclpb->aclpb_cache_result[0..aclpb->aclpb_last_cache_result] is
+ * a cache of info about whether applicable acis
+ * allowed, did_not_allow or denied access
+ */
+ for (j =0; j < aclpb->aclpb_last_cache_result; j++) {
+ if (index == aclpb->aclpb_cache_result[j].aci_index) {
+ short result;
+
+ result = aclpb->aclpb_cache_result[j].result;
+ if ( result <= 0) break;
+ if (!ACL_CACHED_RESULT_VALID(result)) {
+ /* something is wrong. Need to evaluate */
+ aclpb->aclpb_cache_result[j].result = -1;
+ break;
+ }
+ /*
+ ** We have a valid cached result. Let's see if we
+ ** have what we need.
+ */
+ if (access & SLAPI_ACL_SEARCH) {
+ if ( result & ACLPB_CACHE_SEARCH_RES_DENY){
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "DENY:Found SEARCH DENY in cache\n",0,0,0);
+ __acl_set_aclIndex_inResult ( aclpb, access, index );
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_RESULT_CACHED_DENY;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,cached_deny,"");
+ return ACL_RES_DENY;
+ } else if ((result & ACLPB_CACHE_SEARCH_RES_SKIP) ||
+ (result & ACLPB_CACHE_SEARCH_RES_ALLOW)) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "DENY:Found SEARCH SKIP in cache\n",0,0,0);
+ skip_eval = 1;
+ break;
+ } else {
+ break;
+ }
+ } else { /* must be READ */
+ if (result & ACLPB_CACHE_READ_RES_DENY) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "DENY:Found READ DENY in cache\n",0,0,0);
+ __acl_set_aclIndex_inResult ( aclpb, access, index );
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_RESULT_CACHED_DENY;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,cached_deny,"");
+ return ACL_RES_DENY;
+ } else if ( result & ACLPB_CACHE_READ_RES_SKIP) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "DENY:Found READ SKIP in cache\n",0,0,0);
+ skip_eval = 1;
+ break;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if (skip_eval) {
+ skip_eval = 0;
+ continue;
+ }
+
+ rv = ACL_EvalSetACL(NULL, acleval, aci->aci_handle);
+ if ( rv < 0) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "acl__TestRights:Unable to set the DENY acllist\n",
+ 0,0,0);
+ continue;
+ }
+ /*
+ ** Now we have all the information we need. We need to call
+ ** the ONE ACL to test the rights.
+ ** return value: ACL_RES_DENY, ACL_RES_ALLOW, error codes
+ */
+ aclpb->aclpb_curr_aci = aci;
+ rights_rv = ACL_EvalTestRights (NULL, acleval, testRights,
+ map_generic, &deny,
+ &deny_generic,
+ &acl_tag, &expr_num);
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Processed:%d DENY handles Result:%d\n",index, rights_rv,0);
+
+ if (rights_rv == ACL_RES_FAIL) {
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_NONE;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,evaled_deny,"");
+ return ACL_RES_DENY;
+ }
+
+ /* have we executed an ATTR RULE */
+ if ( aci->aci_ruleType & ACI_ATTR_RULES )
+ aclpb->aclpb_state |= ACLPB_ATTR_RULE_EVALUATED;
+
+ if (access & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) {
+
+ for (j=0; j <aclpb->aclpb_last_cache_result; ++j) {
+ if (index == aclpb->aclpb_cache_result[j].aci_index) {
+ break;
+ }
+ }
+
+ if ( j < aclpb->aclpb_last_cache_result) {
+ /* already in cache */
+ } else if ( j < ACLPB_MAX_CACHE_RESULTS ) {
+ /* j == aclpb->aclpb_last_cache_result &&
+ j < ACLPB_MAX_CACHE_RESULTS */
+ aclpb->aclpb_last_cache_result++;
+ aclpb->aclpb_cache_result[j].aci_index = index;
+ aclpb->aclpb_cache_result[j].aci_ruleType = aci->aci_ruleType;
+
+ } else { /* cache overflow */
+ if ( rights_rv == ACL_RES_DENY) {
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_EVALUATED_DENY;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,evaled_deny,"");
+ return ACL_RES_DENY;
+ } else {
+ continue;
+ }
+ }
+
+ __acl_set_aclIndex_inResult ( aclpb, access, index );
+ if (rights_rv == ACL_RES_DENY) {
+ if (access & SLAPI_ACL_SEARCH) {
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_SEARCH_RES_DENY;
+ } else { /* MUST BE READ */
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_READ_RES_DENY;
+ }
+ /* We are done -- return */
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_EVALUATED_DENY;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,evaled_deny,"");
+ return ACL_RES_DENY;
+ } else if (rights_rv == ACL_RES_ALLOW) {
+ /* This will happen, of we have an acl with both deny and allow
+ ** Since we may not have finished all the deny acl, go thru all
+ ** of them. We will use this cached result when we evaluate this
+ ** handle in the context of allow handles.
+ */
+ if (access & SLAPI_ACL_SEARCH) {
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_SEARCH_RES_ALLOW;
+ } else {
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_READ_RES_ALLOW;
+ }
+
+ } else {
+ if (access & SLAPI_ACL_SEARCH) {
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_SEARCH_RES_SKIP;
+ } else {
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_READ_RES_SKIP;
+ }
+ continue;
+ }
+ } else {
+ if ( rights_rv == ACL_RES_DENY ) {
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_EVALUATED_DENY;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,evaled_deny,"");
+ return ACL_RES_DENY;
+ }
+ }
+ }
+
+
+ /*
+ ** START PROCESSING ALLOW HANDLES.
+ ** Process each handle at a time. Do not concatenate the handles or else
+ ** all the context information will be build again and we will pay a
+ ** lot of penalty. The context is built the first time the handle is
+ ** processed.
+ **
+ ** First we set the default to INVALID so that if rules are not matched, then
+ ** we get INVALID and if a rule matched, the we get ALLOW.
+ */
+ aclpb->aclpb_state &= ~ACLPB_EXECUTING_DENY_HANDLES;
+ aclpb->aclpb_state |= ACLPB_EXECUTING_ALLOW_HANDLES;
+ ACL_SetDefaultResult (NULL, acleval, ACL_RES_INVALID);
+ numHandles = ACI_MAX_ELEVEL + aclpb->aclpb_num_allow_handles;
+ for (i=0, k=0; i < numHandles && k < aclpb->aclpb_num_allow_handles ; ++i) {
+ int skip_eval = 0;
+ /*
+ ** If the handle has been evaluated before, we can
+ ** cache the result.
+ */
+ aci = aclpb->aclpb_allow_handles[i];
+ if (((aci = aclpb->aclpb_allow_handles[i]) == NULL) && (i <= ACI_MAX_ELEVEL))
+ continue;
+ k++;
+ index = aci->aci_index;
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "%d. Evaluating ALLOW aci(%d) \"%s\"\n", k, index, aci->aclName);
+
+ if (access & ( SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) {
+
+ /*
+ * aclpb->aclpb_cache_result[0..aclpb->aclpb_last_cache_result] is
+ * a cache of info about whether applicable acis
+ * allowed, did_not_allow or denied access
+ */
+
+ for (j =0; j < aclpb->aclpb_last_cache_result; j++) {
+ if (index == aclpb->aclpb_cache_result[j].aci_index) {
+ short result;
+ result = aclpb->aclpb_cache_result[j].result;
+ if ( result <= 0) break;
+
+ if (!ACL_CACHED_RESULT_VALID(result)) {
+ /* something is wrong. Need to evaluate */
+ aclpb->aclpb_cache_result[j].result = -1;
+ break;
+ }
+
+ /*
+ ** We have a valid cached result. Let's see if we
+ ** have what we need.
+ */
+ if (access & SLAPI_ACL_SEARCH) {
+ if (result & ACLPB_CACHE_SEARCH_RES_ALLOW) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Found SEARCH ALLOW in cache\n");
+ __acl_set_aclIndex_inResult ( aclpb, access, index );
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_RESULT_CACHED_ALLOW;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,cached_allow,"");
+ return ACL_RES_ALLOW;
+ } else if ( result & ACLPB_CACHE_SEARCH_RES_SKIP) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Found SEARCH SKIP in cache\n",0,0,0);
+ skip_eval = 1;
+ break;
+ } else {
+ /* need to evaluate */
+ break;
+ }
+ } else {
+ if ( result & ACLPB_CACHE_READ_RES_ALLOW) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Found READ ALLOW in cache\n",0,0,0);
+ __acl_set_aclIndex_inResult ( aclpb, access, index );
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_RESULT_CACHED_ALLOW;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,cached_allow,"");
+ return ACL_RES_ALLOW;
+ } else if ( result & ACLPB_CACHE_READ_RES_SKIP) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Found READ SKIP in cache\n",0,0,0);
+ skip_eval = 1;
+ break;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ }
+ if ( skip_eval) {
+ skip_eval = 0;
+ continue;
+ }
+
+ TNF_PROBE_0_DEBUG(acl__libaccess_start,"ACL","");
+ rv = ACL_EvalSetACL(NULL, acleval, aci->aci_handle);
+ if ( rv < 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "acl__TestRights:Unable to set the acllist\n",
+ 0,0,0);
+ continue;
+ }
+ /*
+ ** Now we have all the information we need. We need to call
+ ** the ONE ACL to test the rights.
+ ** return value: ACL_RES_DENY, ACL_RES_ALLOW, error codes
+ */
+ aclpb->aclpb_curr_aci = aci;
+ rights_rv = ACL_EvalTestRights (NULL, acleval, testRights,
+ map_generic, &deny,
+ &deny_generic,
+ &acl_tag, &expr_num);
+ TNF_PROBE_0_DEBUG(acl__libaccess_end,"ACL","");
+
+ if (aci->aci_ruleType & ACI_ATTR_RULES)
+ aclpb->aclpb_state |= ACLPB_ATTR_RULE_EVALUATED;
+
+ if (access & (SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) {
+
+ for (j=0; j <aclpb->aclpb_last_cache_result; ++j) {
+ if (index == aclpb->aclpb_cache_result[j].aci_index) {
+ break;
+ }
+ }
+
+ if ( j < aclpb->aclpb_last_cache_result) {
+ /* already in cache */
+ } else if ( j < ACLPB_MAX_CACHE_RESULTS ) {
+ /* j == aclpb->aclpb_last_cache_result &&
+ j < ACLPB_MAX_CACHE_RESULTS */
+ aclpb->aclpb_last_cache_result++;
+ aclpb->aclpb_cache_result[j].aci_index = index;
+ aclpb->aclpb_cache_result[j].aci_ruleType = aci->aci_ruleType;
+ } else { /* cache overflow */
+ slapi_log_error (SLAPI_LOG_FATAL, "acl__TestRights", "cache overflown\n");
+ if ( rights_rv == ACL_RES_ALLOW) {
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_EVALUATED_ALLOW;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,evaled_allow,"");
+ return ACL_RES_ALLOW;
+ } else {
+ continue;
+ }
+ }
+
+ __acl_set_aclIndex_inResult ( aclpb, access, index );
+ if (rights_rv == ACL_RES_ALLOW) {
+ if (access & SLAPI_ACL_SEARCH) {
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_SEARCH_RES_ALLOW;
+ } else { /* must be READ */
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_READ_RES_ALLOW;
+ }
+
+ /* We are done -- return */
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_EVALUATED_ALLOW;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,evaled_allow,"");
+ return ACL_RES_ALLOW;
+
+ } else {
+ if (access & SLAPI_ACL_SEARCH) {
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_SEARCH_RES_SKIP;
+ } else {
+ aclpb->aclpb_cache_result[j].result |=
+ ACLPB_CACHE_READ_RES_SKIP;
+ }
+ continue;
+ }
+ } else {
+ if ( rights_rv == ACL_RES_ALLOW ) {
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_EVALUATED_ALLOW;
+ TNF_PROBE_1_DEBUG(acl__TestRights_end,"ACL","",
+ tnf_string,evaled_allow,"");
+ return ACL_RES_ALLOW;
+ }
+ }
+ }/* for */
+ result_reason->deciding_aci = aci;
+ result_reason->reason = ACL_REASON_NO_MATCHED_SUBJECT_ALLOWS;
+
+ TNF_PROBE_0_DEBUG(acl__TestRights_end,"ACL","");
+
+ return (ACL_RES_DENY);
+}
+/***************************************************************************
+*
+* acl_match_substring
+*
+* Compare the input string to the patteren in the filter
+*
+* Input:
+* struct slapi_filter *f - Filter which has the patteren
+* char *str - String to compare
+* int exact_match - 1; match the pattern exactly
+* - 0; match the pattern as a suffix
+*
+* Returns:
+* ACL_TRUE - The sting matches with the patteren
+* ACL_FALSE - No it doesn't
+* ACL_ERR - Error
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+acl_match_substring ( Slapi_Filter *f, char *str, int exact_match)
+{
+ int i, rc, len;
+ char *p;
+ char *end, *realval, *tmp;
+ char pat[BUFSIZ];
+ char buf[BUFSIZ];
+ char *type, *initial, *final;
+ char **any;
+
+ if ( 0 != slapi_filter_get_subfilt ( f, &type, &initial, &any, &final ) ) {
+ return (ACL_FALSE);
+ }
+
+ /* convert the input to lower. */
+ for (p = str; *p; p++)
+ *p = TOLOWER ( *p );
+
+ /* construct a regular expression corresponding to the filter: */
+ pat[0] = '\0';
+ p = pat;
+ end = pat + sizeof(pat) - 2; /* leave room for null */
+
+
+ if ( initial != NULL) {
+ strcpy (p, "^");
+ p = strchr (p, '\0');
+
+ /* 2 * in case every char is special */
+ if (p + 2 * strlen ( initial ) > end) {
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "not enough pattern space\n", 0, 0, 0);
+
+ return (ACL_ERR);
+ }
+
+ if (!exact_match) {
+ strcpy (p, ".*");
+ p = strchr (p, '\0');
+ }
+ acl_strcpy_special (p, initial);
+ p = strchr (p, '\0');
+ }
+
+ if ( any != NULL) {
+ for (i = 0; any && any[i] != NULL; i++) {
+ /* ".*" + value */
+ if (p + 2 * strlen ( any[i]) + 2 > end) {
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "not enough pattern space\n", 0, 0, 0);
+ return (ACL_ERR);
+ }
+
+ strcpy (p, ".*");
+ p = strchr (p, '\0');
+ acl_strcpy_special (p, any[i]);
+ p = strchr (p, '\0');
+ }
+ }
+
+
+ if ( final != NULL) {
+ /* ".*" + value */
+ if (p + 2 * strlen ( final ) + 2 > end) {
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "not enough pattern space\n", 0, 0, 0);
+ return (ACL_ERR);
+ }
+
+ strcpy (p, ".*");
+ p = strchr (p, '\0');
+ acl_strcpy_special (p, final);
+ p = strchr (p, '\0');
+ strcpy (p, "$");
+ }
+
+ /* see if regex matches with the input string */
+ tmp = NULL;
+ len = strlen(str);
+
+ if (len < sizeof(buf)) {
+ strcpy (buf, str);
+ realval = buf;
+ } else {
+ tmp = (char*) slapi_ch_malloc (len + 1);
+ strcpy (tmp, str);
+ realval = tmp;
+ }
+
+ slapi_dn_normalize (realval);
+
+
+ /* What we have built is a regular pattaren expression.
+ ** Now we will compile the pattern and compare wth the string to
+ ** see if the input string matches with the patteren or not.
+ */
+ slapd_re_lock();
+ if ((p = slapd_re_comp (pat)) != 0) {
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "acl_match_substring:re_comp failed (%s)\n", p, 0, 0);
+ slapd_re_unlock();
+ return (ACL_ERR);
+ }
+
+ /* re_exec() returns 1 if the string p1 matches the last compiled
+ ** regular expression, 0 if the string p1 failed to match
+ ** (see man pages)
+ **
+ ** IMPORTANT NOTE: If I use compile() and step() to do the patteren
+ ** matching, it seems that step() is leaking 1036 bytes/search
+ ** I couldn't figure out why it's leaking.
+ */
+ rc = slapd_re_exec( realval );
+
+ slapd_re_unlock();
+
+ if (tmp != NULL) {
+ slapi_ch_free ( (void **) &tmp );
+ }
+
+ if (rc == 1) {
+ return ACL_TRUE;
+ } else {
+ return ACL_FALSE;
+ }
+}
+/***************************************************************************
+*
+* acl__reset_cached_result
+*
+* Go thru the cached result and invlalidate the cached evaluation results for
+* rules which can only be cached based on the scope.
+* If we have scope ACI_CACHE_RESULT_PER_ENTRY, then we need to invalidate the
+* cacched reult whenever we hit a new entry.
+*
+* Returns:
+* Null
+*
+**************************************************************************/
+static void
+acl__reset_cached_result (struct acl_pblock *aclpb )
+{
+
+ int j;
+
+ for (j =0; j < aclpb->aclpb_last_cache_result; j++) {
+ /* Unless we have to clear the result, move on */
+ if (!( aclpb->aclpb_cache_result[j].aci_ruleType & ACI_CACHE_RESULT_PER_ENTRY))
+ continue;
+ aclpb->aclpb_cache_result[j].result = 0;
+ }
+}
+/*
+ * acl_access_allowed_disjoint_resource
+ *
+ * This is an internal module which can be used to verify
+ * access to a resource which may not be inside the search scope.
+ *
+ * Returns:
+ * - Same return val as acl_access_allowed().
+ */
+int
+acl_access_allowed_disjoint_resource(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e, /* The Slapi_Entry */
+ char *attr, /* Attribute of the entry */
+ struct berval *val, /* value of attr. NOT USED */
+ int access /* access rights */
+ )
+{
+
+ int rv;
+ struct acl_pblock *aclpb = NULL;
+
+ aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
+ /*
+ ** It's possible that we already have a context of ACLs.
+ ** However once in a while, we need to test
+ ** access to a resource which (like vlv, schema) which falls
+ ** outside the search base. In that case, we need to go
+ ** thru all the ACLs and not depend upon the acls which we have
+ ** gathered.
+ */
+
+ /* If you have the right to use the resource, then we don't need to check for
+ ** proxy right on that resource.
+ */
+ if (aclpb)
+ aclpb->aclpb_state |= ( ACLPB_DONOT_USE_CONTEXT_ACLS| ACLPB_DONOT_EVALUATE_PROXY );
+
+ rv = acl_access_allowed(pb, e, attr, val, access);
+
+ if (aclpb) aclpb->aclpb_state &= ~ACLPB_DONOT_USE_CONTEXT_ACLS;
+ if (aclpb ) aclpb->aclpb_state &= ~ACLPB_DONOT_EVALUATE_PROXY;
+
+ return rv;
+}
+
+/*
+ * acl__attr_cached_result
+ * Loops thru the cached result and determines if we can use the cached value.
+ *
+ * Inputs:
+ * Slapi_pblock *aclpb - acl private block
+ * char *attr - attribute name
+ * int access - access type
+ * Returns:
+ * LDAP_SUCCESS: - access is granted
+ * LDAP_INSUFFICIENT_ACCESS - access denied
+ * ACL_ERR - no cached info about this attr.
+ * - or the attr had multiple result and so
+ * - we can't determine the outcome.
+ *
+ */
+static int
+acl__attr_cached_result (struct acl_pblock *aclpb, char *attr, int access )
+{
+
+ int i, rc;
+ aclEvalContext *c_evalContext;
+
+ if ( !(access & ( SLAPI_ACL_SEARCH | SLAPI_ACL_READ) ))
+ return ACL_ERR;
+
+ if (aclpb->aclpb_state & ACLPB_HAS_ACLCB_EVALCONTEXT ) {
+ c_evalContext = &aclpb->aclpb_prev_opEval_context;
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "acl__attr_cached_result:Using Context: ACLPB_ACLCB\n", 0,0,0 );
+ } else {
+ c_evalContext = &aclpb->aclpb_prev_entryEval_context;
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "acl__attr_cached_result:Using Context: ACLPB_PREV\n", 0,0,0 );
+ }
+
+ if ( attr == NULL ) {
+ int eval_read = 0;
+ /*
+ ** Do I have access to at least one attribute, then I have
+ ** access to the entry.
+ */
+ for (i=0; i < c_evalContext->acle_numof_attrs; i++ ) {
+ AclAttrEval *a_eval = &c_evalContext->acle_attrEval[i];
+
+ if ( (access & SLAPI_ACL_READ ) && a_eval->attrEval_r_status &&
+ a_eval->attrEval_r_status < ACL_ATTREVAL_DETERMINISTIC ) {
+ eval_read++;
+ if ( a_eval->attrEval_r_status & ACL_ATTREVAL_SUCCESS)
+ return LDAP_SUCCESS;
+ /* rbyrne: recompute if we have to.
+ * How does this cached result get turned off for
+ * attr style acis which acannot be cached becuase entry
+ * can result in a diff value.
+ */
+ else if ( a_eval->attrEval_r_status & ACL_ATTREVAL_RECOMPUTE ) {
+ rc = acl__recompute_acl ( aclpb, a_eval, access,
+ a_eval->attrEval_r_aciIndex);
+ if ( rc != ACL_ERR ) {
+ acl_copyEval_context ( aclpb, c_evalContext,
+ &aclpb->aclpb_curr_entryEval_context, 1);
+ }
+ if ( rc == LDAP_SUCCESS) {
+ return LDAP_SUCCESS;
+ }
+ }
+ }
+ }/* for */
+ /*
+ * If we have scanned the whole list without success then
+ * we are not granting access to this entry through access
+ * to an attribute in the list--however this does not mean
+ * that we do not have access to the entry via another attribute
+ * not already in the list, so return -1 meaning
+ * "don't know".
+ */
+ return(ACL_ERR);
+#if 0
+ if ( eval_read )
+ return LDAP_INSUFFICIENT_ACCESS;
+ else
+ return ACL_ERR;
+#endif
+ }
+
+ for (i=0; i < c_evalContext->acle_numof_attrs; i++ ) {
+ AclAttrEval *a_eval = &c_evalContext->acle_attrEval[i];
+
+ if ( a_eval == NULL ) continue;
+
+ if (strcasecmp ( attr, a_eval->attrEval_name ) == 0 ) {
+ if ( access & SLAPI_ACL_SEARCH ) {
+ if (a_eval->attrEval_s_status < ACL_ATTREVAL_DETERMINISTIC ) {
+ if ( a_eval->attrEval_s_status & ACL_ATTREVAL_SUCCESS)
+ return LDAP_SUCCESS;
+ else if ( a_eval->attrEval_s_status & ACL_ATTREVAL_FAIL)
+ return LDAP_INSUFFICIENT_ACCESS;
+ else if ( a_eval->attrEval_s_status & ACL_ATTREVAL_RECOMPUTE ) {
+ rc = acl__recompute_acl ( aclpb, a_eval, access,
+ a_eval->attrEval_s_aciIndex);
+ if ( rc != ACL_ERR ) {
+ acl_copyEval_context ( aclpb, c_evalContext,
+ &aclpb->aclpb_curr_entryEval_context, 1);
+ }
+ } else
+ return ACL_ERR;
+ } else {
+ /* This means that for the same attribute and same type of
+ ** access, we had different results at different time.
+ ** Since we are not caching per object, we can't
+ ** determine exactly. So, can't touch this
+ */
+ return ACL_ERR;
+ }
+ } else {
+ if (a_eval->attrEval_r_status < ACL_ATTREVAL_DETERMINISTIC ) {
+ if ( a_eval->attrEval_r_status & ACL_ATTREVAL_SUCCESS)
+ return LDAP_SUCCESS;
+ else if ( a_eval->attrEval_r_status & ACL_ATTREVAL_FAIL)
+ return LDAP_INSUFFICIENT_ACCESS;
+ else if ( a_eval->attrEval_r_status & ACL_ATTREVAL_RECOMPUTE ) {
+ rc = acl__recompute_acl ( aclpb, a_eval, access,
+ a_eval->attrEval_r_aciIndex);
+ if ( rc != ACL_ERR ) {
+ acl_copyEval_context ( aclpb, c_evalContext,
+ &aclpb->aclpb_curr_entryEval_context, 1);
+ }
+ } else
+ return ACL_ERR;
+ } else {
+ /* Look above for explanation */
+ return ACL_ERR;
+ }
+ }
+ }
+ }
+ return ACL_ERR;
+}
+
+/*
+ * Had to do this juggling of casting to make
+ * both Nt & unix compiler happy.
+ */
+static int
+acl__cmp(const void *a, const void *b)
+{
+ short *i = (short *) a;
+ short *j = (short *) b;
+
+ if ( (short) *i > (short) *j )
+ return (1);
+ if ( (short)*i < (short) *j)
+ return (-1);
+ return (0);
+}
+
+/*
+ * acl__scan_match_handles
+ * Go thru the ACL list and determine if the list of acls selected matches
+ * what we have in the cache.
+ *
+ * Inputs:
+ * Acl_PBlock *pb - Main pblock ( blacvk hole)
+ * int type - Which context to look on
+ *
+ * Returns:
+ * 0 - matches all the acl handles
+ * ACL_ERR - sorry; no match
+ *
+ * ASSUMPTION: A READER LOCK ON ACL LIST
+ */
+static int
+acl__scan_match_handles ( Acl_PBlock *aclpb, int type)
+{
+
+
+ int matched = 0;
+ aci_t *aci = NULL;
+ int index;
+ PRUint32 cookie;
+ aclEvalContext *c_evalContext = NULL;
+
+ if (type == ACLPB_EVALCONTEXT_PREV ) {
+ c_evalContext = &aclpb->aclpb_prev_entryEval_context;
+ } else if ( type == ACLPB_EVALCONTEXT_ACLCB ){
+ c_evalContext = &aclpb->aclpb_prev_opEval_context;
+ } else {
+ return ACL_ERR;
+ }
+
+
+ if ( !c_evalContext->acle_numof_tmatched_handles )
+ return ACL_ERR;
+
+ aclpb->aclpb_stat_acllist_scanned++;
+ aci = acllist_get_first_aci ( aclpb, &cookie );
+
+ while ( aci ) {
+ index = aci->aci_index;
+ if (acl__resource_match_aci(aclpb, aci, 1 /* skip attr matching */, NULL )) {
+ int j;
+ int s_matched = matched;
+
+ /* We have a sorted list of handles that matched the target */
+
+ for (j=0; j < c_evalContext->acle_numof_tmatched_handles ; j++ ) {
+ if ( c_evalContext->acle_handles_matched_target[j] > index )
+
+ break;
+ else if ( index == c_evalContext->acle_handles_matched_target[j] ) {
+ int jj;
+ matched++;
+
+ /* See if this is a ATTR rule that matched -- in that case we have
+ ** to nullify the cached result
+ */
+ if ( aci->aci_ruleType & ACI_ATTR_RULES ) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Found an attr Rule [Name:%s Index:%d\n", aci->aclName,
+ aci->aci_index );
+ for ( jj =0; jj < c_evalContext->acle_numof_attrs; jj++ ) {
+ AclAttrEval *a_eval = &c_evalContext->acle_attrEval[jj];
+ if ( a_eval->attrEval_r_aciIndex == aci->aci_index )
+ a_eval->attrEval_r_status = ACL_ATTREVAL_RECOMPUTE;
+ if ( a_eval->attrEval_s_aciIndex == aci->aci_index )
+ a_eval->attrEval_s_status = ACL_ATTREVAL_RECOMPUTE;
+ }
+ }
+ break;
+ }
+ }
+ if ( s_matched == matched ) return ACL_ERR;
+ }
+ aci = acllist_get_next_aci ( aclpb, aci, &cookie );
+ }
+ if ( matched == c_evalContext->acle_numof_tmatched_handles )
+ return 0;
+
+ return ACL_ERR;
+}
+/*
+ * acl_copyEval_context
+ * Copy the context info which include attr info and handles.
+ *
+ * Inputs
+ * struct acl_pblock *aclpb - acl private main block
+ * aclEvalContext *src - src context
+ * aclEvalContext *dest - dest context
+ * Returns:
+ * None.
+ *
+ */
+void
+acl_copyEval_context ( struct acl_pblock *aclpb, aclEvalContext *src,
+ aclEvalContext *dest , int copy_attr_only )
+{
+
+ int d_slot, i;
+
+ /* Do a CLEAN copy we have nothing or else do an incremental copy.*/
+ if ( src->acle_numof_attrs < 1 )
+ return;
+
+ /* Copy the attr info */
+ if ( dest->acle_numof_attrs < 1 )
+ acl_clean_aclEval_context ( dest, 0 /*clean */ );
+
+ d_slot = dest->acle_numof_attrs;
+ for (i=0; i < src->acle_numof_attrs; i++ ) {
+ int j;
+ int attr_exists = 0;
+ int dd_slot = d_slot;
+
+ if ( aclpb && (i == 0) ) aclpb->aclpb_stat_num_copycontext++;
+
+ if ( src->acle_attrEval[i].attrEval_r_status == 0 &&
+ src->acle_attrEval[i].attrEval_s_status == 0 )
+ continue;
+
+ for ( j = 0; j < dest->acle_numof_attrs; j++ ) {
+ if ( strcasecmp ( src->acle_attrEval[i].attrEval_name,
+ dest->acle_attrEval[j].attrEval_name ) == 0 ) {
+ /* We have it. skip it. */
+ attr_exists = 1;
+ dd_slot = j;
+ break;
+ }
+ }
+ if ( !attr_exists ) {
+ if ( dd_slot >= ACLPB_MAX_ATTRS -1 )
+ break;
+
+ if ( aclpb) aclpb->aclpb_stat_num_copy_attrs++;
+
+ if ( dest->acle_attrEval[dd_slot].attrEval_name )
+ slapi_ch_free ( (void **) &dest->acle_attrEval[dd_slot].attrEval_name );
+
+ dest->acle_attrEval[dd_slot].attrEval_name =
+ slapi_ch_strdup ( src->acle_attrEval[i].attrEval_name );
+ }
+ /* Copy the result status and the aci index */
+ dest->acle_attrEval[dd_slot].attrEval_r_status =
+ src->acle_attrEval[i].attrEval_r_status;
+ dest->acle_attrEval[dd_slot].attrEval_r_aciIndex =
+ src->acle_attrEval[i].attrEval_r_aciIndex;
+ dest->acle_attrEval[dd_slot].attrEval_s_status =
+ src->acle_attrEval[i].attrEval_s_status;
+ dest->acle_attrEval[dd_slot].attrEval_s_aciIndex =
+ src->acle_attrEval[i].attrEval_s_aciIndex;
+
+ if (!attr_exists ) d_slot++;
+ }
+
+ dest->acle_numof_attrs = d_slot;
+ dest->acle_attrEval[d_slot].attrEval_name = NULL;
+
+ if ( copy_attr_only )
+ return;
+
+ /* First sort the arrays which keeps the acl index numbers */
+ qsort ( (char *) src->acle_handles_matched_target,
+ (size_t)src->acle_numof_tmatched_handles, sizeof( int ), acl__cmp );
+
+ for (i=0; i < src->acle_numof_tmatched_handles; i++ ) {
+ dest->acle_handles_matched_target[i] =
+ src->acle_handles_matched_target[i];
+ }
+
+ if ( src->acle_numof_tmatched_handles ) {
+ dest->acle_numof_tmatched_handles = src->acle_numof_tmatched_handles;
+ if ( aclpb) aclpb->aclpb_stat_num_tmatched_acls = src->acle_numof_tmatched_handles;
+ }
+}
+
+/*
+ * acl_clean_aclEval_context
+ * Clean the eval context
+ *
+ * Inputs:
+ * aclEvalContext *clean_me - COntext to be cleaned
+ * int clean_type - 0: clean, 1 scrub
+ *
+ */
+
+void
+acl_clean_aclEval_context ( aclEvalContext *clean_me, int scrub_only )
+{
+ int i;
+
+ /* Copy the attr info */
+ for (i=0; i < clean_me->acle_numof_attrs; i++ ) {
+
+ char *a_name = clean_me->acle_attrEval[i].attrEval_name;
+ if ( a_name && !scrub_only) {
+ slapi_ch_free ( (void **) &a_name );
+ clean_me->acle_attrEval[i].attrEval_name = NULL;
+ }
+ clean_me->acle_attrEval[i].attrEval_r_status = 0;
+ clean_me->acle_attrEval[i].attrEval_s_status = 0;
+ clean_me->acle_attrEval[i].attrEval_r_aciIndex = 0;
+ clean_me->acle_attrEval[i].attrEval_s_aciIndex = 0;
+ }
+
+ if ( !scrub_only ) clean_me->acle_numof_attrs = 0;
+ clean_me->acle_numof_tmatched_handles = 0;
+}
+/*
+ * acl__match_handlesFromCache
+ *
+ * We have 2 cacheed information
+ * 1) cached info from the previous operation
+ * 2) cached info from the prev entry evaluation
+ *
+ * What we are doing here is going thru all the acls and see if the same
+ * set of acls apply to this resource or not. If it does, then do we have
+ * a cached info for the attr. If we don't for both of the cases then we need
+ * to evaluate all over again.
+ *
+ * Inputs:
+ * struct acl_pblock - ACL private block;
+ * char *attr - Attribute name
+ * int access - acces type
+ *
+ * returns:
+ * LDAP_SUCCESS (0) - The same acls apply and we have
+ * access ALLOWED on the attr
+ * LDAP_INSUFFICIENT_ACCESS - The same acls apply and we have
+ * access DENIED on the attr
+ * -1 - Acls doesn't match or we don't have
+ * cached info for this attr.
+ *
+ * ASSUMPTIONS: A reader lock has been obtained for the acl list.
+ */
+static int
+acl__match_handlesFromCache ( Acl_PBlock *aclpb, char *attr, int access)
+{
+
+ aclEvalContext *c_evalContext = NULL;
+ int context_type = 0;
+ int ret_val = -1; /* it doen't match by default */
+
+ /* Before we proceed, find out if we have evaluated any ATTR RULE. If we have
+ ** then we can't use any caching mechanism
+ */
+
+ if ( aclpb->aclpb_state & ACLPB_HAS_ACLCB_EVALCONTEXT ) {
+ context_type = ACLPB_EVALCONTEXT_ACLCB;
+ c_evalContext = &aclpb->aclpb_prev_opEval_context;
+ } else {
+ context_type = ACLPB_EVALCONTEXT_PREV;
+ c_evalContext = &aclpb->aclpb_prev_entryEval_context;
+ }
+
+
+ if ( aclpb->aclpb_res_type & (ACLPB_NEW_ENTRY | ACLPB_EFFECTIVE_RIGHTS) ) {
+ aclpb->aclpb_state |= ACLPB_MATCHES_ALL_ACLS;
+ ret_val = acl__scan_match_handles ( aclpb, context_type );
+ if ( -1 == ret_val ) {
+ aclpb->aclpb_state &= ~ACLPB_MATCHES_ALL_ACLS;
+ aclpb->aclpb_state |= ACLPB_UPD_ACLCB_CACHE;
+ /* Did not match */
+ if ( context_type == ACLPB_HAS_ACLCB_EVALCONTEXT ) {
+ aclpb->aclpb_state &= ~ACLPB_HAS_ACLCB_EVALCONTEXT;
+ } else {
+ aclpb->aclpb_state |= ACLPB_COPY_EVALCONTEXT;
+ c_evalContext->acle_numof_tmatched_handles = 0;
+ }
+ }
+ }
+ if ( aclpb->aclpb_state & ACLPB_MATCHES_ALL_ACLS ) {
+ /* See if we have a cached result for this attr */
+ ret_val = acl__attr_cached_result (aclpb, attr, access);
+
+ /* It's not in the ACLCB context but we might have it in the
+ ** current/prev context. Take a look at it. we might have evaluated
+ ** this attribute already.
+ */
+ if ( (-1 == ret_val ) &&
+ ( aclpb->aclpb_state & ACLPB_HAS_ACLCB_EVALCONTEXT )) {
+ aclpb->aclpb_state &= ~ACLPB_HAS_ACLCB_EVALCONTEXT ;
+ ret_val = acl__attr_cached_result (aclpb, attr, access);
+ aclpb->aclpb_state |= ACLPB_HAS_ACLCB_EVALCONTEXT ;
+
+ /* We need to do an incremental update */
+ if ( !ret_val ) aclpb->aclpb_state |= ACLPB_INCR_ACLCB_CACHE;
+ }
+ }
+ return ret_val;
+}
+/*
+ * acl__get_attrEval
+ * Get the atteval from the current context and hold the ptr in aclpb.
+ * If we have too many attrs, then allocate a new one. In that case
+ * we let the caller know about that so that it will be deallocated.
+ *
+ * Returns:
+ * int - 0: The context was indexed. So, no allocations.
+ * - 1; context was allocated - deallocate it.
+ */
+static int
+acl__get_attrEval ( struct acl_pblock *aclpb, char *attr )
+{
+
+ int j;
+ aclEvalContext *c_ContextEval = &aclpb->aclpb_curr_entryEval_context;
+ int deallocate_attrEval = 0;
+ AclAttrEval *c_attrEval = NULL;
+
+ if ( !attr ) return deallocate_attrEval;
+
+ aclpb->aclpb_curr_attrEval = NULL;
+
+ /* Go thru and see if we have the attr already */
+ for (j=0; j < c_ContextEval->acle_numof_attrs; j++) {
+ c_attrEval = &c_ContextEval->acle_attrEval[j];
+
+ if ( c_attrEval &&
+ slapi_attr_type_cmp ( c_attrEval->attrEval_name, attr, 1) == 0 ) {
+ aclpb->aclpb_curr_attrEval = c_attrEval;
+ break;
+ }
+ }
+
+ if ( !aclpb->aclpb_curr_attrEval) {
+ if ( c_ContextEval->acle_numof_attrs == ACLPB_MAX_ATTRS -1 ) {
+ /* Too many attrs. create a temp one */
+ c_attrEval = (AclAttrEval * ) slapi_ch_calloc ( 1, sizeof ( AclAttrEval ) );
+ deallocate_attrEval =1;
+ } else {
+ c_attrEval = &c_ContextEval->acle_attrEval[c_ContextEval->acle_numof_attrs++];
+ c_attrEval->attrEval_r_status = 0;
+ c_attrEval->attrEval_s_status = 0;
+ c_attrEval->attrEval_r_aciIndex = 0;
+ c_attrEval->attrEval_s_aciIndex = 0;
+ }
+ /* clean it before use */
+ c_attrEval->attrEval_name = slapi_ch_strdup ( attr );
+ aclpb->aclpb_curr_attrEval = c_attrEval;
+ }
+ return deallocate_attrEval;
+}
+/*
+ * acl_skip_access_check
+ *
+ * See if we need to go thru the ACL check or not. We don't need to if I am root
+ * or internal operation or ...
+ *
+ * returns:
+ * ACL_TRUE - Yes; skip the ACL check
+ * ACL_FALSE - No; you have to go thru ACL check
+ *
+ */
+int
+acl_skip_access_check ( Slapi_PBlock *pb, Slapi_Entry *e )
+{
+ int rv, isRoot, accessCheckDisabled;
+ void *conn = NULL;
+ Slapi_Backend *be;
+
+ slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );
+ if ( isRoot ) return ACL_TRUE;
+
+ /* See if this is local request */
+ slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn);
+
+ if ( NULL == conn ) return ACL_TRUE;
+
+ /*
+ * Turn on access checking in the rootdse--this code used
+ * to skip the access check.
+ *
+ * check if the entry is the RootDSE entry
+ if ( e ) {
+ char * edn = slapi_entry_get_ndn ( e );
+ if ( slapi_is_rootdse ( edn ) ) return ACL_TRUE;
+ }
+ */
+
+ /* GB : when referrals are directly set in the mappin tree
+ * we can reach this code without a backend in the pblock
+ * in such a case, allow access for now
+ * we may want to reconsider this is NULL DSE implementation happens
+ */
+ rv = slapi_pblock_get ( pb, SLAPI_BACKEND, &be );
+ if (be == NULL)
+ return ACL_TRUE;
+
+ rv = slapi_pblock_get ( pb, SLAPI_PLUGIN_DB_NO_ACL, &accessCheckDisabled );
+ if ( rv != -1 && accessCheckDisabled ) return ACL_TRUE;
+
+ return ACL_FALSE;
+}
+short
+acl_get_aclsignature ()
+{
+ return acl_signature;
+}
+void
+acl_set_aclsignature ( short value)
+{
+ acl_signature = value;
+}
+void
+acl_regen_aclsignature ()
+{
+ acl_signature = aclutil_gen_signature ( acl_signature );
+}
+
+
+
+static int
+acl__handle_config_entry (Slapi_Entry *e, void *callback_data )
+{
+
+ int *value = (int *) callback_data;
+
+ *value = slapi_entry_attr_get_int( e, "nsslapd-readonly");
+
+ return 0;
+}
+
+static int
+acl__config_get_readonly ()
+{
+
+ int readonly = 0;
+
+ slapi_search_internal_callback( "cn=config", LDAP_SCOPE_BASE, "(objectclass=*)",
+ NULL, 0 /* attrsonly */,
+ &readonly/* callback_data */,
+ NULL /* controls */,
+ NULL /* result_callback */,
+ acl__handle_config_entry,
+ NULL /* referral_callback */);
+
+ return readonly;
+}
+/*
+*
+* Assumptions:
+* 1) Called for read/search right.
+*/
+static int
+acl__recompute_acl ( Acl_PBlock *aclpb,
+ AclAttrEval *a_eval,
+ int access,
+ int aciIndex
+ )
+{
+
+
+ char *unused_str1, *unused_str2;
+ char *acl_tag, *testRight[2];
+ int j, expr_num;
+ int result_status, rv, cache_result;
+ PRUint32 cookie;
+ aci_t *aci;
+
+
+ PR_ASSERT ( aciIndex >= 0 );
+ PR_ASSERT ( a_eval != NULL );
+ PR_ASSERT (aclpb != NULL );
+
+
+ /* We might have evaluated this acl just now, check it there first */
+
+ for ( j =0; j < aclpb->aclpb_last_cache_result; j++) {
+ if (aciIndex == aclpb->aclpb_cache_result[j].aci_index) {
+ short result;
+ result_status =ACL_RES_INVALID;
+
+ result = aclpb->aclpb_cache_result[j].result;
+ if ( result <= 0) break;
+ if (!ACL_CACHED_RESULT_VALID(result)) {
+ /* something is wrong. Need to evaluate */
+ aclpb->aclpb_cache_result[j].result = -1;
+ break;
+ }
+
+
+ /*
+ ** We have a valid cached result. Let's see if we
+ ** have what we need.
+ */
+ if ((result & ACLPB_CACHE_SEARCH_RES_ALLOW) ||
+ (result & ACLPB_CACHE_READ_RES_ALLOW) )
+ result_status = ACL_RES_ALLOW;
+ else if ((result & ACLPB_CACHE_SEARCH_RES_DENY) ||
+ (result & ACLPB_CACHE_READ_RES_DENY) )
+ result_status = ACL_RES_DENY;
+
+ }
+ } /* end of for */
+
+ if ( result_status != ACL_RES_INVALID ) {
+ goto set_result_status;
+ }
+
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Recomputing the ACL Index:%d for entry:%s\n",
+ aciIndex, slapi_entry_get_ndn ( aclpb->aclpb_curr_entry) );
+
+ /* First find this one ACL and then evaluate it. */
+
+
+ aci = acllist_get_first_aci ( aclpb, &cookie );
+ while ( aci && aci->aci_index != aciIndex ) {
+ aci = acllist_get_next_aci ( aclpb, aci, &cookie );
+ }
+
+ if (NULL == aci)
+ return -1;
+
+
+ ACL_SetDefaultResult (NULL, aclpb->aclpb_acleval, ACL_RES_INVALID);
+ rv = ACL_EvalSetACL(NULL, aclpb->aclpb_acleval, aci->aci_handle);
+
+ testRight[0] = acl_access2str ( access );
+ testRight[1] = '\0';
+ aclpb->aclpb_curr_aci = aci;
+ result_status = ACL_EvalTestRights (NULL, aclpb->aclpb_acleval, testRight,
+ ds_map_generic, &unused_str1,
+ &unused_str2,
+ &acl_tag, &expr_num);
+
+ cache_result = 0;
+ if ( result_status == ACL_RES_DENY && aci->aci_type & ACI_HAS_DENY_RULE ) {
+ if ( access & SLAPI_ACL_SEARCH)
+ cache_result = ACLPB_CACHE_SEARCH_RES_DENY;
+ else
+ cache_result = ACLPB_CACHE_READ_RES_DENY;
+ } else if ( result_status == ACL_RES_ALLOW && aci->aci_type & ACI_HAS_ALLOW_RULE ) {
+ if ( access & SLAPI_ACL_SEARCH)
+ cache_result = ACLPB_CACHE_SEARCH_RES_ALLOW;
+ else
+ cache_result = ACLPB_CACHE_READ_RES_ALLOW;
+
+ } else {
+ result_status = -1;
+ }
+
+ /* Now we need to put the cached result in the aclpb */
+
+ for (j=0; j <aclpb->aclpb_last_cache_result; ++j) {
+ if (aciIndex == aclpb->aclpb_cache_result[j].aci_index) {
+ break;
+ }
+ }
+
+ if ( j < aclpb->aclpb_last_cache_result) {
+ /* already in cache */
+ } else if ( j < ACLPB_MAX_CACHE_RESULTS-1) {
+ /* rbyrneXXX: make this same as other last_cache_result code! */
+ j = ++aclpb->aclpb_last_cache_result;
+ aclpb->aclpb_cache_result[j].aci_index = aci->aci_index;
+ aclpb->aclpb_cache_result[j].aci_ruleType = aci->aci_ruleType;
+
+ } else { /* No more space */
+ goto set_result_status;
+ }
+
+ /* Add the cached result status */
+ aclpb->aclpb_cache_result[j].result |= cache_result;
+
+
+
+set_result_status:
+ if (result_status == ACL_RES_ALLOW) {
+ if (access & SLAPI_ACL_SEARCH)
+ /*wrong bit maskes were being used here--
+ a_eval->attrEval_s_status = ACLPB_CACHE_SEARCH_RES_ALLOW;*/
+ a_eval->attrEval_s_status = ACL_ATTREVAL_SUCCESS;
+ else
+ a_eval->attrEval_r_status = ACL_ATTREVAL_SUCCESS;
+
+ } else if ( result_status == ACL_RES_DENY) {
+ if (access & SLAPI_ACL_SEARCH)
+ a_eval->attrEval_s_status = ACL_ATTREVAL_FAIL;
+ else
+ a_eval->attrEval_r_status = ACL_ATTREVAL_FAIL;
+ } else {
+ /* Here, set it to recompute--try again later */
+ if (access & SLAPI_ACL_SEARCH)
+ a_eval->attrEval_s_status = ACL_ATTREVAL_RECOMPUTE;
+ else
+ a_eval->attrEval_r_status = ACL_ATTREVAL_RECOMPUTE;
+ result_status = -1;
+ }
+
+ return result_status;
+}
+
+static void
+__acl_set_aclIndex_inResult ( Acl_PBlock *aclpb, int access, int index )
+{
+ AclAttrEval *c_attrEval = aclpb->aclpb_curr_attrEval;
+
+ if ( c_attrEval ) {
+ if ( access & SLAPI_ACL_SEARCH )
+ c_attrEval->attrEval_s_aciIndex = index;
+ else if ( access & SLAPI_ACL_READ )
+ c_attrEval->attrEval_r_aciIndex = index;
+ }
+}
+
+/*
+ * If filter_sense is true then return (entry satisfies f).
+ * Otherwise, return !(entry satisfies f)
+*/
+
+static int
+acl__test_filter ( Slapi_Entry *entry, struct slapi_filter *f, int filter_sense) {
+ int filter_matched;
+
+ /* slapi_vattr_filter_test() returns 0 for match */
+
+ filter_matched = !slapi_vattr_filter_test(NULL, entry,
+ f,
+ 0 /*don't do acess chk*/);
+
+ if (filter_sense) {
+ return(filter_matched ? ACL_TRUE : ACL_FALSE);
+ } else {
+ return(filter_matched ? ACL_FALSE: ACL_TRUE);
+ }
+}
+
+/*
+ * Make an entry consisting of attr_type and attr_val and put
+ * a pointer to it in *entry.
+ * We will use this afterwards to test for against a filter.
+*/
+
+static int
+acl__make_filter_test_entry ( Slapi_Entry **entry, char *attr_type,
+ struct berval *attr_val) {
+
+ struct berval *vals_array[2];
+
+ vals_array[0] = attr_val;
+ vals_array[1] = NULL;
+
+ *entry = slapi_entry_alloc();
+ slapi_entry_init(*entry, NULL, NULL);
+
+ return (slapi_entry_add_values( *entry, (const char *)attr_type,
+ (struct berval**)&vals_array[0] ));
+
+}
+
+/*********************************************************************************/
+/* E N D */
+/*********************************************************************************/
diff --git a/ldap/servers/plugins/acl/acl.h b/ldap/servers/plugins/acl/acl.h
new file mode 100644
index 00000000..5e16a0bd
--- /dev/null
+++ b/ldap/servers/plugins/acl/acl.h
@@ -0,0 +1,867 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*****************************************************************************
+* acl.h
+*
+* Header file for ACL processing
+*
+*****************************************************************************/
+#ifndef _ACL_H_
+#define _ACL_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#include <ldap.h>
+#include <las.h>
+#include <aclproto.h>
+#include <aclerror.h>
+#include "prcvar.h"
+#include "slapi-plugin.h"
+#include "slap.h"
+#include "slapi-private.h"
+#include "portable.h"
+#include "prrwlock.h"
+#include "avl.h"
+
+#include "cert.h"
+
+#include <plhash.h>
+
+#ifdef SOLARIS
+ #include <tnf/probe.h>
+#else
+ #define TNF_PROBE_0_DEBUG(a,b,c)
+ #define TNF_PROBE_1_DEBUG(a,b,c,d,e,f)
+#endif
+
+#define ACL_PLUGIN_NAME "NSACLPlugin"
+extern char *plugin_name;
+
+/*
+ * Define the OID for version 2 of the proxied authorization control if
+ * it is not already defined (it is in recent copies of ldap.h).
+ */
+#ifndef LDAP_CONTROL_PROXIEDAUTH
+#define LDAP_CONTROL_PROXIEDAUTH "2.16.840.1.113730.3.4.18"
+#endif
+
+#define ACLUCHP unsigned char *
+
+static char* const aci_attr_type = "aci";
+static char* const filter_string = "aci=*";
+static char* const aci_targetdn = "target";
+static char* const aci_targetattr = "targetattr";
+static char* const aci_targetattrfilters = "targattrfilters";
+static char* const aci_targetfilter = "targetfilter";
+
+static char* const LDAP_URL_prefix = "ldap:///";
+
+static char* const access_str_compare = "compare";
+static char* const access_str_search = "search";
+static char* const access_str_read = "read";
+static char* const access_str_write = "write";
+static char* const access_str_delete = "delete";
+static char* const access_str_add = "add";
+static char* const access_str_selfwrite = "selfwrite";
+static char* const access_str_proxy = "proxy";
+
+#define ACL_INIT_ATTR_ARRAY 5
+
+/* define the method */
+#define DS_METHOD "ds_method"
+
+#define ACL_ESCAPE_STRING_WITH_PUNCTUATION(x,y) (slapi_is_loglevel_set(SLAPI_LOG_ACL) ? escape_string_with_punctuation(x,y) : "")
+
+/* Lases */
+#define DS_LAS_USER "user"
+#define DS_LAS_GROUP "group"
+#define DS_LAS_USERDN "userdn"
+#define DS_LAS_GROUPDN "groupdn"
+#define DS_LAS_USERDNATTR "userdnattr"
+#define DS_LAS_AUTHMETHOD "authmethod"
+#define DS_LAS_GROUPDNATTR "groupdnattr"
+#define DS_LAS_USERATTR "userattr"
+#define DS_LAS_ROLEDN "roledn"
+#define DS_LAS_ROLEDNATTR "rolednattr"
+
+
+/* These define the things that aclutil_evaluate_macro() supports */
+typedef enum
+{
+ ACL_EVAL_USER,
+ ACL_EVAL_GROUP,
+ ACL_EVAL_ROLE,
+ ACL_EVAL_GROUPDNATTR,
+ ACL_EVAL_TARGET_FILTER
+}acl_eval_types;
+
+typedef enum
+{
+ ACL_RULE_MACRO_DN_TYPE,
+ ACL_RULE_MACRO_DN_LEVELS_TYPE
+}acl_rule_macro_types;
+
+#define ACL_TARGET_MACRO_DN_KEY "($dn)"
+#define ACL_RULE_MACRO_DN_KEY "($dn)"
+#define ACL_RULE_MACRO_DN_LEVELS_KEY "[$dn]"
+#define ACL_RULE_MACRO_ATTR_KEY "($attr."
+
+#define ACL_EVAL_USER 0
+#define ACL_EVAL_GROUP 1
+#define ACL_EVAL_ROLE 2
+
+/* The LASes are implemented in the libaccess library */
+#define DS_LAS_TIMEOFDAY "timeofday"
+#define DS_LAS_DAYOFWEEK "dayofweek"
+
+
+/* ACL function return codes */
+#define ACL_TRUE 1 /* evaluation results to TRUE */
+#define ACL_OK ACL_TRUE
+#define ACL_FALSE 0 /* evaluation results to FALSE */
+#define ACL_ERR -1 /* generic error */
+#define ACL_TARGET_FILTER_ERR -2 /* Target filter not set properly */
+#define ACL_TARGETATTR_FILTER_ERR -3 /* TargetAttr filter not set properly */
+#define ACL_TARGETFILTER_ERR -4 /* Target filter not set properly */
+#define ACL_SYNTAX_ERR -5 /* Syntax error */
+#define ACL_ONEACL_TEXT_ERR -6 /* ONE ACL text error */
+#define ACL_ERR_CONCAT_HANDLES -7 /* unable to concat the handles */
+#define ACL_INVALID_TARGET -8 /* invalid target */
+#define ACL_INVALID_AUTHMETHOD -9 /* multiple client auth */
+#define ACL_INVALID_AUTHORIZATION -10 /* no authorization */
+#define ACL_INCORRECT_ACI_VERSION -11 /* incorrect version # */
+#define ACL_DONT_KNOW -12 /* the world is an uncertain place */
+
+/* supported by the DS */
+#define DS_PROP_CONNECTION "connection"
+#define DS_ATTR_USERDN "userdn"
+#define DS_ATTR_ENTRY "entry"
+#define DS_PROP_ACLPB "aclblock"
+#define DS_ATTR_AUTHTYPE "authtype"
+#define DS_ATTR_CERT "clientcert"
+
+#define ACL_ANOM_MAX_ACL 40
+struct scoped_entry_anominfo {
+ short anom_e_targetInfo[ACL_ANOM_MAX_ACL];
+ short anom_e_nummatched;
+ short anom_e_isrootds;
+};
+
+typedef struct targetattr {
+ int attr_type;
+#define ACL_ATTR_FILTER 0x01
+#define ACL_ATTR_STRING 0x02
+#define ACL_ATTR_STAR 0x04 /* attr is * only */
+
+ union {
+ char *attr_str;
+ struct slapi_filter *attr_filter;
+ }u;
+}Targetattr;
+
+typedef struct targetattrfilter {
+ char *attr_str;
+ char *filterStr;
+ struct slapi_filter *filter; /* value filter */
+
+}Targetattrfilter;
+
+typedef struct Aci_Macro {
+ char *match_this;
+ char *macro_ptr; /* ptr into match_this */
+}aciMacro;
+
+typedef PLHashTable acl_ht_t;
+
+/* Access Control Item (aci): Stores information about a particular ACL */
+typedef struct aci {
+ int aci_type; /* Type of resurce */
+
+/* THE FIRST BYTE WAS USED TO KEEP THE RIGHTS. ITS BEEN MOVED TO
+** aci_access and is now free.
+**
+**
+**
+*/
+
+#define ACI_TARGET_MACRO_DN (int)0x000001
+#define ACI_TARGET_FILTER_MACRO_DN (int)0x000002
+#define ACI_TARGET_DN (int)0x000100 /* target has DN */
+#define ACI_TARGET_ATTR (int)0x000200 /* target is an attr */
+#define ACI_TARGET_PATTERN (int)0x000400 /* target has some patt */
+#define ACI_TARGET_FILTER (int)0x000800 /* target has a filter */
+#define ACI_ACLTXT (int)0x001000 /* ACI has text only */
+#define ACI_TARGET_NOT (int)0x002000 /* it's a != */
+#define ACI_TARGET_ATTR_NOT (int)0x004000 /* It's a != manager */
+#define ACI_TARGET_FILTER_NOT (int)0x008000 /* It's a != filter */
+#define ACI_UNUSED2 (int)0x010000 /* Unused */
+#define ACI_HAS_ALLOW_RULE (int)0x020000 /* allow (...) */
+#define ACI_HAS_DENY_RULE (int)0x040000 /* deny (...) */
+#define ACI_CONTAIN_NOT_USERDN (int)0x080000 /* userdn != blah */
+#define ACI_TARGET_ATTR_ADD_FILTERS (int)0x100000
+#define ACI_TARGET_ATTR_DEL_FILTERS (int)0x200000
+#define ACI_CONTAIN_NOT_GROUPDN (int)0x400000 /* groupdn != blah */
+#define ACI_CONTAIN_NOT_ROLEDN (int)0x800000
+
+ int aci_access;
+
+/*
+ * See also aclpb_access which is used to store rights too.
+*/
+
+ short aci_ruleType; /* kinds of rules in the ACL */
+
+#define ACI_USERDN_RULE (short) 0x0001
+#define ACI_USERDNATTR_RULE (short) 0x0002
+#define ACI_GROUPDN_RULE (short) 0x0004
+#define ACI_GROUPDNATTR_RULE (short) 0x0008
+#define ACI_AUTHMETHOD_RULE (short) 0x0010
+#define ACI_IP_RULE (short) 0x0020
+#define ACI_DNS_RULE (short) 0x0040
+#define ACI_TIMEOFDAY_RULE (short) 0x0080
+#define ACI_DAYOFWEEK_RULE (short) 0x0010
+#define ACI_USERATTR_RULE (short) 0x0200
+/*
+ * These are extension of USERDN/GROUPDN rule. However since the
+ * semantics are quite different, we classify them as different rules.
+ * ex: groupdn = "ldap:///cn=helpdesk, ou=$attr.dept, o=$dn.o, o=isp"
+ */
+#define ACI_PARAM_DNRULE (short) 0x0400
+#define ACI_PARAM_ATTRRULE (short) 0x0800
+#define ACI_USERDN_SELFRULE (short) 0x1000
+#define ACI_ROLEDN_RULE (short) 0x2000
+
+
+
+#define ACI_ATTR_RULES ( ACI_USERDNATTR_RULE | ACI_GROUPDNATTR_RULE | ACI_USERATTR_RULE | ACI_PARAM_DNRULE | ACI_PARAM_ATTRRULE | ACI_USERDN_SELFRULE)
+#define ACI_CACHE_RESULT_PER_ENTRY ACI_ATTR_RULES
+
+ short aci_elevel; /* Based on the aci type some idea about the
+ ** execution flow
+ */
+ int aci_index; /* index # */
+ Slapi_DN *aci_sdn; /* location */
+ Slapi_Filter *target; /* Target is a DN */
+ Targetattr **targetAttr;
+ char *targetFilterStr;
+ struct slapi_filter *targetFilter; /* Target has a filter */
+ Targetattrfilter **targetAttrAddFilters;
+ Targetattrfilter **targetAttrDelFilters;
+ char *aclName; /* ACL name */
+ struct ACLListHandle *aci_handle; /*handle of the ACL */
+ aciMacro *aci_macro;
+ struct aci *aci_next; /* next one */
+}aci_t;
+
+/* Aci excution level
+** The idea is that for each handle types, we can prioritize which one to evaluate first.
+** Evaluating the user before the group is better.
+*/
+#define ACI_ELEVEL_USERDN_ANYONE 0
+#define ACI_ELEVEL_USERDN_ALL 1
+#define ACI_ELEVEL_USERDN 2
+#define ACI_ELEVEL_USERDNATTR 3
+#define ACI_ELEVEL_GROUPDNATTR_URL 4
+#define ACI_ELEVEL_GROUPDNATTR 5
+#define ACI_ELEVEL_GROUPDN 6
+#define ACI_MAX_ELEVEL ACI_ELEVEL_GROUPDN +1
+#define ACI_DEFAULT_ELEVEL ACI_MAX_ELEVEL
+
+
+#define ACLPB_MAX_SELECTED_ACLS 200
+
+typedef struct result_cache {
+ int aci_index;
+ short aci_ruleType;
+ short result;
+#define ACLPB_CACHE_READ_RES_ALLOW (short)0x0001 /* used for ALLOW handles only */
+#define ACLPB_CACHE_READ_RES_DENY (short)0x0002 /* used for DENY handles only */
+#define ACLPB_CACHE_SEARCH_RES_ALLOW (short)0x0004 /* used for ALLOW handles only */
+#define ACLPB_CACHE_SEARCH_RES_DENY (short)0x0008 /* used for DENY handles only */
+#define ACLPB_CACHE_SEARCH_RES_SKIP (short)0x0010 /* used for both types */
+#define ACLPB_CACHE_READ_RES_SKIP (short)0x0020 /* used for both types */
+}r_cache_t;
+#define ACLPB_MAX_CACHE_RESULTS ACLPB_MAX_SELECTED_ACLS
+
+/*
+ * This is use to keep the result of the evaluation of the attr.
+ * We are only intrested in read/searc only.
+ */
+struct acl_attrEval {
+ char *attrEval_name; /* Attribute Name */
+ short attrEval_r_status; /* status of read evaluation */
+ short attrEval_s_status; /* status of search evaluation */
+ int attrEval_r_aciIndex; /* Index of the ACL which grants access*/
+ int attrEval_s_aciIndex; /* Index of the ACL which grants access*/
+
+#define ACL_ATTREVAL_SUCCESS 0x1
+#define ACL_ATTREVAL_FAIL 0x2
+#define ACL_ATTREVAL_RECOMPUTE 0x4
+#define ACL_ATTREVAL_DETERMINISTIC 7
+#define ACL_ATTREVAL_INVALID 0x8
+
+};
+typedef struct acl_attrEval AclAttrEval;
+
+
+/*
+ * Struct to keep the evaluation context information. This struct is
+ * used in multiple places ( different instance ) to keep the context for
+ * current entry evaluation, previous entry evaluation or previous operation
+ * evaluation status.
+ */
+#define ACLPB_MAX_ATTR_LEN 100
+#define ACLPB_MAX_ATTRS 100
+struct acleval_context {
+
+ /* Information about the attrs */
+ AclAttrEval acle_attrEval[ACLPB_MAX_ATTRS];
+ short acle_numof_attrs;
+
+ /* Handles information */
+ short acle_numof_tmatched_handles;
+ int acle_handles_matched_target[ACLPB_MAX_SELECTED_ACLS];
+};
+typedef struct acleval_context aclEvalContext;
+
+
+struct acl_usergroup {
+ short aclug_signature;
+/*
+ * To modify refcnt you need either the write lock on the whole cache or
+ * the reader lock on the whole cache plus this refcnt mutex
+*/
+ short aclug_refcnt;
+ PRLock *aclug_refcnt_mutex;
+
+
+ char *aclug_ndn; /* Client's normalized DN */
+
+ char **aclug_member_groups;
+ short aclug_member_group_size;
+ short aclug_numof_member_group;
+
+ char **aclug_notmember_groups;
+ short aclug_notmember_group_size;
+ short aclug_numof_notmember_group;
+ struct acl_usergroup *aclug_next;
+ struct acl_usergroup *aclug_prev;
+
+};
+typedef struct acl_usergroup aclUserGroup;
+
+#define ACLUG_INCR_GROUPS_LIST 20
+
+struct aci_container {
+ Slapi_DN *acic_sdn; /* node DN */
+ aci_t *acic_list; /* List of the ACLs for that node */
+ int acic_index; /* index to the container array */
+};
+typedef struct aci_container AciContainer;
+
+struct acl_pblock {
+ int aclpb_state;
+
+#define ACLPB_ACCESS_ALLOWED_ON_A_ATTR 0x000001
+#define ACLPB_ACCESS_DENIED_ON_ALL_ATTRS 0x000002
+#define ACLPB_ACCESS_ALLOWED_ON_ENTRY 0x000004
+#define ACLPB_ATTR_STAR_MATCHED 0x000008
+#define ACLPB_FOUND_ATTR_RULE 0x000010
+#define ACLPB_SEARCH_BASED_ON_LIST 0x000020
+#define ACLPB_EXECUTING_DENY_HANDLES 0x000040
+#define ACLPB_EXECUTING_ALLOW_HANDLES 0x000080
+#define ACLPB_ACCESS_ALLOWED_USERATTR 0x000100
+#ifdef DETERMINE_ACCESS_BASED_ON_REQUESTED_ATTRIBUTES
+ #define ACLPB_USER_SPECIFIED_ATTARS 0x000200
+ #define ACLPB_USER_WANTS_ALL_ATTRS 0x000400
+#endif
+#define ACLPB_EVALUATING_FIRST_ATTR 0x000800
+#define ACLPB_FOUND_A_ENTRY_TEST_RULE 0x001000
+#define ACLPB_SEARCH_BASED_ON_ENTRY_LIST 0x002000
+#define ACLPB_DONOT_USE_CONTEXT_ACLS 0x004000
+#define ACLPB_HAS_ACLCB_EVALCONTEXT 0x008000
+#define ACLPB_COPY_EVALCONTEXT 0x010000
+#define ACLPB_MATCHES_ALL_ACLS 0x020000
+#define ACLPB_INITIALIZED 0x040000
+#define ACLPB_INCR_ACLCB_CACHE 0x080000
+#define ACLPB_UPD_ACLCB_CACHE 0x100000
+#define ACLPB_ATTR_RULE_EVALUATED 0x200000
+#define ACLPB_DONOT_EVALUATE_PROXY 0x400000
+
+
+#define ACLPB_RESET_MASK ( ACLPB_ACCESS_ALLOWED_ON_A_ATTR | ACLPB_ACCESS_DENIED_ON_ALL_ATTRS | \
+ ACLPB_ACCESS_ALLOWED_ON_ENTRY | ACLPB_ATTR_STAR_MATCHED | \
+ ACLPB_FOUND_ATTR_RULE | ACLPB_EVALUATING_FIRST_ATTR | \
+ ACLPB_FOUND_A_ENTRY_TEST_RULE )
+#define ACLPB_STATE_ALL 0x3fffff
+
+ int aclpb_res_type;
+
+ #define ACLPB_NEW_ENTRY 0x100
+ #define ACLPB_EFFECTIVE_RIGHTS 0x200
+ #define ACLPB_RESTYPE_ALL 0x7ff
+
+ /*
+ * The bottom bye used to be for rights. It's free now as they have
+ * been moved to aclpb_access.
+ */
+
+ int aclpb_access;
+
+#define ACLPB_SLAPI_ACL_WRITE_ADD 0x200
+#define ACLPB_SLAPI_ACL_WRITE_DEL 0x400
+
+ /* stores the requested access during an operation */
+
+ short aclpb_signature;
+ short aclpb_type;
+#define ACLPB_TYPE_MAIN 1
+#define ACLPB_TYPE_MAIN_STR "Main Block"
+#define ACLPB_TYPE_PROXY 2
+#define ACLPB_TYPE_PROXY_STR "Proxy Block"
+
+ Slapi_Entry *aclpb_client_entry; /* A copy of client's entry */
+ Slapi_PBlock *aclpb_pblock; /* back to LDAP PBlock */
+ int aclpb_optype; /* current optype from pb */
+
+ /* Current entry/dn/attr evaluation info */
+ Slapi_Entry *aclpb_curr_entry; /* current Entry being processed */
+ int aclpb_num_entries;
+ Slapi_DN *aclpb_curr_entry_sdn; /* Entry's SDN */
+ Slapi_DN *aclpb_authorization_sdn; /* dn used for authorization */
+
+ AclAttrEval *aclpb_curr_attrEval; /* Current attr being evaluated */
+ struct berval *aclpb_curr_attrVal; /* Value of Current attr */
+ Slapi_Entry *aclpb_filter_test_entry; /* Scratch entry */
+ aci_t *aclpb_curr_aci;
+ char *aclpb_Evalattr; /* The last attr evaluated */
+
+ /* Plist and eval info */
+ ACLEvalHandle_t *aclpb_acleval; /* acleval handle for evaluation */
+ struct PListStruct_s *aclpb_proplist;/* All the needed property */
+
+ /* DENY ACI HANDLES */
+ aci_t **aclpb_deny_handles;
+ int aclpb_deny_handles_size;
+ int aclpb_num_deny_handles;
+
+ /* ALLOW ACI HANDLES */
+ aci_t **aclpb_allow_handles;
+ int aclpb_allow_handles_size;
+ int aclpb_num_allow_handles;
+
+ /* This is used in the groupdnattr="URL" rule
+ ** Keep a list of base where searched has been done
+ */
+ char **aclpb_grpsearchbase;
+ int aclpb_grpsearchbase_size;
+ int aclpb_numof_bases;
+
+ aclUserGroup *aclpb_groupinfo;
+
+ /* Keep the Group nesting level */
+ int aclpb_max_nesting_level;
+ int aclpb_max_member_sizelimit;
+
+
+ /* To keep the results in the cache */
+
+ int aclpb_last_cache_result;
+ struct result_cache aclpb_cache_result[ACLPB_MAX_CACHE_RESULTS];
+
+ /* Index numbers of ACLs selected based on a locality search*/
+ char *aclpb_search_base;
+ int aclpb_base_handles_index[ACLPB_MAX_SELECTED_ACLS];
+ int aclpb_handles_index[ACLPB_MAX_SELECTED_ACLS];
+
+ /* Evaluation context info
+ ** 1) Context cached from aclcb ( from connection struct )
+ ** 2) Context cached from previous entry evaluation
+ ** 3) current entry evaluation info
+ */
+ aclEvalContext aclpb_curr_entryEval_context;
+ aclEvalContext aclpb_prev_entryEval_context;
+ aclEvalContext aclpb_prev_opEval_context;
+
+ /* Currentry anom profile sumamry */
+ struct scoped_entry_anominfo aclpb_scoped_entry_anominfo;
+
+ /* Some Statistics gathering */
+ PRUint16 aclpb_stat_acllist_scanned;
+ PRUint16 aclpb_stat_aclres_matched;
+ PRUint16 aclpb_stat_total_entries;
+ PRUint16 aclpb_stat_anom_list_scanned;
+ PRUint16 aclpb_stat_num_copycontext;
+ PRUint16 aclpb_stat_num_copy_attrs;
+ PRUint16 aclpb_stat_num_tmatched_acls;
+ PRUint16 aclpb_stat_unused;
+ CERTCertificate *aclpb_clientcert;
+ AciContainer *aclpb_aclContainer;
+ struct acl_pblock *aclpb_proxy; /* Child proxy block */
+ acl_ht_t *aclpb_macro_ht; /* ht for partial macro strs */
+
+ struct acl_pblock *aclpb_prev; /* Previpous in the chain */
+ struct acl_pblock *aclpb_next; /* Next in the chain */
+};
+typedef struct acl_pblock Acl_PBlock;
+
+/* PBLCOK TYPES */
+typedef enum
+{
+ ACLPB_BINDDN_PBLOCK,
+ ACLPB_PROXYDN_PBLOCK,
+ ACLPB_ALL_PBLOCK
+}aclpb_types;
+
+
+#define ACLPB_EVALCONTEXT_CURR 1
+#define ACLPB_EVALCONTEXT_PREV 2
+#define ACLPB_EVALCONTEXT_ACLCB 3
+
+
+
+/* Cleaning/ deallocating/ ... acl_freeBlock() */
+#define ACL_CLEAN_ACLPB 1
+#define ACL_COPY_ACLCB 2
+#define ACL_CLEAN_ACLCB 3
+
+/* used to differentiate acl plugins sharing the same lib */
+#define ACL_PLUGIN_IDENTITY 1
+#define ACL_PREOP_PLUGIN_IDENTITY 2
+
+
+/* start with 50 and then add 50 more as required
+ * The first ACI_MAX_ELEVEL slots are predefined.
+ */
+#define ACLPB_INCR_LIST_HANDLES ACI_MAX_ELEVEL + 43
+
+#define ACLPB_INCR_BASES 5
+
+/*
+ * acl private block which hangs from connection structure.
+ * This is allocated the first time an operation is done and freed when the
+ * connection are cleaned.
+ *
+ */
+struct acl_cblock {
+
+ short aclcb_aclsignature;
+ short aclcb_state;
+#define ACLCB_HAS_CACHED_EVALCONTEXT 0x1
+
+ Slapi_DN *aclcb_sdn; /* Contains bind SDN */
+ aclEvalContext aclcb_eval_context;
+ PRLock *aclcb_lock; /* shared lock */
+};
+
+struct acl_groupcache {
+ short aclg_state; /* status information */
+ short aclg_signature;
+ int aclg_num_userGroups;
+ aclUserGroup *aclg_first;
+ aclUserGroup *aclg_last;
+ PRRWLock *aclg_rwlock; /* lock to monitor the group cache */
+};
+typedef struct acl_groupcache aclGroupCache;
+
+
+/* Type of extensions that can be registered */
+typedef enum
+{
+ ACL_EXT_OPERATION, /* extension for Operation object */
+ ACL_EXT_CONNECTION, /* extension for Connection object */
+ ACL_EXT_ALL
+}ext_type;
+
+/* Used to pass data around in acllas.c */
+
+typedef struct {
+ char *clientDn;
+ char *authType;
+ int anomUser;
+ Acl_PBlock *aclpb;
+ Slapi_Entry *resourceEntry;
+
+}lasInfo;
+
+
+/* reasons why the subject allowed/denied access--good for logs */
+
+typedef enum{
+ACL_REASON_NO_ALLOWS,
+ACL_REASON_RESULT_CACHED_DENY,
+ACL_REASON_EVALUATED_DENY, /* evaluated deny */
+ACL_REASON_RESULT_CACHED_ALLOW, /* cached allow */
+ACL_REASON_EVALUATED_ALLOW, /* evalauted allow */
+ACL_REASON_NO_MATCHED_RESOURCE_ALLOWS, /* were allows/denies, but none matched */
+ACL_REASON_NONE, /* no reason available */
+ACL_REASON_ANON_ALLOWED,
+ACL_REASON_ANON_DENIED,
+ACL_REASON_NO_MATCHED_SUBJECT_ALLOWS,
+ACL_REASON_EVALCONTEXT_CACHED_ALLOW,
+ACL_REASON_EVALCONTEXT_CACHED_NOT_ALLOWED,
+ACL_REASON_EVALCONTEXT_CACHED_ATTR_STAR_ALLOW
+}aclReasonCode_t;
+
+typedef struct{
+ aci_t *deciding_aci;
+ aclReasonCode_t reason;
+}aclResultReason_t;
+#define ACL_NO_DECIDING_ACI_INDEX -10
+
+
+/* Extern declaration for backend state change fnc: acllist.c and aclinit.c */
+
+void acl_be_state_change_fnc ( void *handle, char *be_name, int old_state,
+ int new_state);
+
+
+/* Extern declaration for ATTRs */
+
+extern int
+DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
+ auth_info, PList_t global_auth, void *arg);
+extern int
+DS_LASDnsGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
+ auth_info, PList_t global_auth, void *arg);
+extern int
+DS_LASUserDnGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
+ auth_info, PList_t global_auth, void *arg);
+extern int
+DS_LASGroupDnGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
+ auth_info, PList_t global_auth, void *arg);
+extern int
+DS_LASEntryGetter(NSErr_t *errp, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth, void *arg);
+
+extern int
+DS_LASCertGetter(NSErr_t *errp, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth, void *arg);
+
+/* function declartion for LAses supported by DS */
+
+extern int DS_LASUserEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern int DS_LASGroupEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern int DS_LASUserDnEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern int DS_LASGroupDnEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern int DS_LASRoleDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern int DS_LASUserDnAttrEval(NSErr_t *errp, char *attribute,
+ CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern int DS_LASAuthMethodEval(NSErr_t *errp, char *attribute,
+ CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern int DS_LASGroupDnAttrEval(NSErr_t *errp, char *attribute,
+ CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern int DS_LASRoleDnAttrEval(NSErr_t *errp, char *attribute,
+ CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern int DS_LASUserAttrEval(NSErr_t *errp, char *attribute,
+ CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+/* other function declaration */
+int aclinit_main();
+int acl_match_substring (struct slapi_filter *f, char *str, int match);
+void acl_print_acllib_err(NSErr_t *errp, char * str);
+void acl_initBlock ( Slapi_PBlock *pb );
+void acl_freeBlock ( Slapi_PBlock *pb, int state );
+int acl_read_access_allowed_on_entry ( Slapi_PBlock *pb, Slapi_Entry *e,
+ char **attrs, int access);
+int acl_access_allowed_modrdn ( Slapi_PBlock *pb, Slapi_Entry *e, char *attr,
+ struct berval *val, int access);
+int acl_read_access_allowed_on_attr ( Slapi_PBlock *pb, Slapi_Entry *e, char *attr,
+ struct berval *val, int access);
+void acl_set_acllist (Slapi_PBlock *pb, int scope, char *base);
+void acl_gen_err_msg(int access, char *edn, char *attr, char **errbuf);
+void acl_modified ( Slapi_PBlock *pb, int optype, char *dn, void *change);
+int acl_access_allowed_disjoint_resource( Slapi_PBlock *pb, Slapi_Entry *e,
+ char *attr, struct berval *val, int access );
+int acl_access_allowed_main ( Slapi_PBlock *pb, Slapi_Entry *e, char **attrs,
+ struct berval *val, int access , int flags, char **errbuf);
+int acl_access_allowed( Slapi_PBlock *pb, Slapi_Entry *e, char *attr,
+ struct berval *val, int access );
+int acl_verify_syntax(const Slapi_DN *e_sdn, const struct berval *bval);
+aclUserGroup * acl_get_usersGroup ( struct acl_pblock *aclpb , char *n_dn);
+void acl_print_acllib_err (NSErr_t *errp , char * str);
+int acl_check_mods( Slapi_PBlock *pb, Slapi_Entry *e, LDAPMod **mods, char **errbuf );
+int acl_verify_aci_syntax (Slapi_Entry *e, char **errbuf);
+char * acl__access2str(int access);
+void acl_strcpy_special (char *d, char *s);
+int acl_parse(char * str, aci_t *aci_item);
+char * acl_access2str ( int access );
+int acl_init_ext ();
+void * acl_get_ext (ext_type type, void *object);
+void acl_set_ext (ext_type type, void *object, void *data);
+void acl_reset_ext_status (ext_type type, void *object);
+void acl_init_op_ext ( Slapi_PBlock *pb , int type, char *dn, int copy);
+void * acl_operation_ext_constructor (void *object, void *parent );
+void acl_operation_ext_destructor ( void *ext, void *object, void *parent );
+void * acl_conn_ext_constructor (void *object, void *parent );
+void acl_conn_ext_destructor ( void *ext, void *object, void *parent );
+void acl_clean_aclEval_context ( aclEvalContext *clean_me, int scrub_only );
+void acl_copyEval_context ( struct acl_pblock *aclpb, aclEvalContext *src,
+ aclEvalContext *dest , int copy_attr_only );
+struct acl_pblock * acl_get_aclpb ( Slapi_PBlock *pb, int type );
+int acl_client_anonymous ( Slapi_PBlock *pb );
+short acl_get_aclsignature();
+void acl_set_aclsignature( short value);
+void acl_regen_aclsignature();
+struct acl_pblock * acl_new_proxy_aclpb( Slapi_PBlock *pb );
+void acl_set_authorization_dn( Slapi_PBlock *pb, char *dn, int type );
+int acl_get_proxyauth_dn( Slapi_PBlock *pb, char **proxydnp,
+ char **errtextp );
+void acl_init_aclpb ( Slapi_PBlock *pb , Acl_PBlock *aclpb,
+ const char *dn, int copy_from_aclcb);
+int acl_create_aclpb_pool ();
+int acl_skip_access_check ( Slapi_PBlock *pb, Slapi_Entry *e );
+
+int aclext_alloc_lockarray ();
+
+int aclutil_str_appened(char **str1, const char *str2);
+void aclutil_print_err (int rv , const Slapi_DN *sdn,
+ const struct berval* val, char **errbuf);
+void aclutil_print_aci (aci_t *aci_item, char *type);
+short aclutil_gen_signature ( short c_signature );
+void aclutil_print_resource( struct acl_pblock *aclpb, char *right , char *attr, char *clientdn );
+char * aclutil_expand_paramString ( char *str, Slapi_Entry *e );
+
+
+void acllist_init_scan (Slapi_PBlock *pb, int scope, char *base);
+aci_t * acllist_get_first_aci (Acl_PBlock *aclpb, PRUint32 *cookie );
+aci_t * acllist_get_next_aci ( Acl_PBlock *aclpb, aci_t *curraci, PRUint32 *cookie );
+aci_t * acllist_get_aci_new ();
+void acllist_free_aci (aci_t *item);
+void acllist_acicache_READ_UNLOCK(void);
+void acllist_acicache_READ_LOCK(void);
+void acllist_acicache_WRITE_UNLOCK(void);
+void acllist_acicache_WRITE_LOCK(void);
+void acllist_aciscan_update_scan ( Acl_PBlock *aclpb, char *edn );
+int acllist_remove_aci_needsLock( const Slapi_DN *sdn, const struct berval *attr );
+int acllist_insert_aci_needsLock( const Slapi_DN *e_sdn, const struct berval* aci_attr);
+int acllist_init ();
+int acllist_moddn_aci_needsLock ( Slapi_DN *oldsdn, char *newdn );
+void acllist_print_tree ( Avlnode *root, int *depth, char *start, char *side);
+AciContainer *acllist_get_aciContainer_new ( );
+void acllist_done_aciContainer ( AciContainer *);
+
+aclUserGroup* aclg_find_userGroup (char *n_dn);
+void aclg_regen_ugroup_signature( aclUserGroup *ugroup);
+void aclg_markUgroupForRemoval ( aclUserGroup *u_group );
+void aclg_reader_incr_ugroup_refcnt(aclUserGroup* u_group);
+int aclg_numof_usergroups(void);
+int aclgroup_init ();
+void aclg_regen_group_signature ();
+void aclg_reset_userGroup ( struct acl_pblock *aclpb );
+void aclg_init_userGroup ( struct acl_pblock *aclpb, const char *dn , int got_lock);
+aclUserGroup * aclg_get_usersGroup ( struct acl_pblock *aclpb , char *n_dn);
+
+void aclg_lock_groupCache (int type );
+void aclg_unlock_groupCache (int type );
+
+int aclanom_init();
+int aclanom_match_profile (Slapi_PBlock *pb, struct acl_pblock *aclpb,
+ Slapi_Entry *e, char *attr, int access);
+void aclanom_get_suffix_info(Slapi_Entry *e, struct acl_pblock *aclpb );
+void aclanom_invalidateProfile();
+typedef enum{
+ DONT_TAKE_ACLCACHE_READLOCK,
+ DO_TAKE_ACLCACHE_READLOCK,
+ DONT_TAKE_ACLCACHE_WRITELOCK,
+ DO_TAKE_ACLCACHE_WRITELOCK
+}acl_lock_flag_t;
+void aclanom_gen_anomProfile (acl_lock_flag_t lock_flag);
+int aclanom_is_client_anonymous ( Slapi_PBlock *pb );
+int aclinit_main ();
+typedef struct aclinit_handler_callback_data {
+#define ACL_ADD_ACIS 1
+#define ACL_REMOVE_ACIS 0
+ int op;
+ int retCode;
+ acl_lock_flag_t lock_flag;
+}aclinit_handler_callback_data_t;
+int
+aclinit_search_and_update_aci ( int thisbeonly, const Slapi_DN *base,
+ char *be_name, int scope, int op,
+ acl_lock_flag_t lock_flag);
+void *aclplugin_get_identity(int plug);
+int
+acl_dn_component_match( const char *ndn, char *match_this, int component_number);
+char *
+acl_match_macro_in_target( const char *ndn, char *match_this,
+ char *macro_ptr);
+char* get_next_component(char *dn, int *index);
+int acl_match_prefix( char *macro_prefix, const char *ndn,
+ int *exact_match);
+char *
+get_this_component(char *dn, int *index);
+int
+acl_find_comp_end( char * s);
+char *
+acl_replace_str(char * s, char *substr, char* replace_with);
+int acl_strstr(char * s, char *substr);
+int aclutil_evaluate_macro( char * rule, lasInfo *lasinfo,
+ acl_eval_types evalType );
+
+/* acl hash table functions */
+void acl_ht_add_and_freeOld(acl_ht_t * acl_ht, PLHashNumber key,char *value);
+acl_ht_t *acl_ht_new(void);
+void acl_ht_free_all_entries_and_values( acl_ht_t *acl_ht);
+void acl_ht_remove( acl_ht_t *acl_ht, PLHashNumber key);
+void *acl_ht_lookup( acl_ht_t *acl_ht, PLHashNumber key);
+void acl_ht_display_ht( acl_ht_t *acl_ht);
+
+/* acl get effective rights */
+int
+acl_get_effective_rights ( Slapi_PBlock *pb, Slapi_Entry *e,
+ char **attrs, struct berval *val, int access, char **errbuf );
+
+char* aclutil__access_str (int type , char str[]);
+
+#endif /* _ACL_H_ */
diff --git a/ldap/servers/plugins/acl/acl_ext.c b/ldap/servers/plugins/acl/acl_ext.c
new file mode 100644
index 00000000..28a9ce18
--- /dev/null
+++ b/ldap/servers/plugins/acl/acl_ext.c
@@ -0,0 +1,968 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "acl.h"
+
+static void acl__done_aclpb ( struct acl_pblock *aclpb );
+static void acl__dump_stats ( struct acl_pblock *aclpb , const char *block_type);
+static Acl_PBlock * acl__get_aclpb_from_pool ( );
+static int acl__put_aclpb_back_to_pool ( Acl_PBlock *aclpb );
+static Acl_PBlock * acl__malloc_aclpb ( );
+static char * acl__get_aclpb_type ( Acl_PBlock *aclpb );
+static PRLock *aclext_get_lock ();
+
+
+struct acl_pbqueue {
+ Acl_PBlock *aclq_free;
+ Acl_PBlock *aclq_busy;
+ short aclq_nfree;
+ short aclq_nbusy;
+ PRLock *aclq_lock;
+};
+typedef struct acl_pbqueue Acl_PBqueue;
+
+static Acl_PBqueue *aclQueue;
+
+/* structure with information for each extension */
+typedef struct acl_ext
+{
+ char *object_name; /* name of the object extended */
+ int object_type; /* handle to the extended object */
+ int handle; /* extension handle */
+} acl_ext;
+
+static acl_ext acl_ext_list [ACL_EXT_ALL];
+
+/*
+ * EXTENSION INITIALIZATION, CONSTRUCTION, & DESTRUCTION
+ *
+ */
+int
+acl_init_ext ()
+{
+ int rc;
+
+ acl_ext_list[ACL_EXT_OPERATION].object_name = SLAPI_EXT_OPERATION;
+
+ rc = slapi_register_object_extension(plugin_name, SLAPI_EXT_OPERATION,
+ acl_operation_ext_constructor,
+ acl_operation_ext_destructor,
+ &acl_ext_list[ACL_EXT_OPERATION].object_type,
+ &acl_ext_list[ACL_EXT_OPERATION].handle);
+
+ if ( rc != 0 ) return rc;
+
+ acl_ext_list[ACL_EXT_CONNECTION].object_name = SLAPI_EXT_CONNECTION;
+ rc = slapi_register_object_extension(plugin_name, SLAPI_EXT_CONNECTION,
+ acl_conn_ext_constructor,
+ acl_conn_ext_destructor,
+ &acl_ext_list[ACL_EXT_CONNECTION].object_type,
+ &acl_ext_list[ACL_EXT_CONNECTION].handle);
+
+ return rc;
+
+}
+
+/* Interface to get the extensions */
+void *
+acl_get_ext (ext_type type, void *object)
+{
+ struct acl_ext ext;
+ void *data;
+
+ if ( type >= ACL_EXT_ALL ) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Invalid extension type:%d\n", type );
+ return NULL;
+ }
+
+ /* find the requested extension */
+ ext = acl_ext_list [type];
+ data = slapi_get_object_extension(ext.object_type, object, ext.handle);
+
+ return data;
+}
+
+void
+acl_set_ext (ext_type type, void *object, void *data)
+{
+ if ( type >= 0 && type < ACL_EXT_ALL )
+ {
+ struct acl_ext ext = acl_ext_list [type];
+ slapi_set_object_extension ( ext.object_type, object, ext.handle, data );
+ }
+}
+
+/****************************************************************************
+ * Global lock array so that private extension between connection and operation
+ * co-exist
+ *
+ ******************************************************************************/
+struct ext_lockArray {
+ PRLock **lockArray;
+ int numlocks;
+};
+
+static struct ext_lockArray extLockArray;
+
+/* PKBxxx: make this a configurable. Start with 2 * maxThreads */
+#define ACLEXT_MAX_LOCKS 40
+
+int
+aclext_alloc_lockarray ( )
+{
+
+ int i;
+ PRLock *lock;
+
+ extLockArray.lockArray =
+ (PRLock **) slapi_ch_calloc ( ACLEXT_MAX_LOCKS, sizeof ( PRLock *) );
+
+ for ( i =0; i < ACLEXT_MAX_LOCKS; i++) {
+ if (NULL == (lock = PR_NewLock()) ) {
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to allocate locks used for private extension\n");
+ return 1;
+ }
+ extLockArray.lockArray[i] = lock;
+ }
+ extLockArray.numlocks = ACLEXT_MAX_LOCKS;
+ return 0;
+}
+static PRUint32 slot_id =0;
+static PRLock *
+aclext_get_lock ()
+{
+
+ PRUint16 slot = slot_id % ACLEXT_MAX_LOCKS;
+ slot_id++;
+ return ( extLockArray.lockArray[slot] );
+
+}
+/****************************************************************************/
+/* CONNECTION EXTENSION SPECIFIC */
+/****************************************************************************/
+void *
+acl_conn_ext_constructor ( void *object, void *parent )
+{
+ struct acl_cblock *ext = NULL;
+
+ ext = (struct acl_cblock * ) slapi_ch_calloc (1, sizeof (struct acl_cblock ) );
+ if (( ext->aclcb_lock = aclext_get_lock () ) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to get Read/Write lock for CONNECTION extension\n");
+ slapi_ch_free ( (void **) &ext );
+ return NULL;
+ }
+ ext->aclcb_sdn = slapi_sdn_new ();
+ /* store the signatures */
+ ext->aclcb_aclsignature = acl_get_aclsignature();
+ ext->aclcb_state = -1;
+ return ext;
+
+
+}
+
+void
+acl_conn_ext_destructor ( void *ext, void *object, void *parent )
+{
+ struct acl_cblock *aclcb = ext;
+ PRLock *shared_lock;
+
+ if ( NULL == aclcb ) return;
+ PR_Lock ( aclcb->aclcb_lock );
+ shared_lock = aclcb->aclcb_lock;
+ acl_clean_aclEval_context ( &aclcb->aclcb_eval_context, 0 /* clean*/ );
+ slapi_sdn_free ( &aclcb->aclcb_sdn );
+ aclcb->aclcb_lock = NULL;
+ slapi_ch_free ( (void **) &aclcb );
+
+ PR_Unlock ( shared_lock );
+}
+
+/****************************************************************************/
+/* OPERATION EXTENSION SPECIFIC */
+/****************************************************************************/
+void *
+acl_operation_ext_constructor ( void *object, void *parent )
+{
+ Acl_PBlock *aclpb = NULL;
+
+ TNF_PROBE_0_DEBUG(acl_operation_ext_constructor_start ,"ACL","");
+
+ /* This means internal operations */
+ if ( NULL == parent) {
+
+ TNF_PROBE_1_DEBUG(acl_operation_ext_constructor_end ,"ACL","",
+ tnf_string,internal_op,"");
+
+ return NULL;
+ }
+
+ aclpb = acl__get_aclpb_from_pool();
+ if ( NULL == aclpb ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Operation extension allocation Failed\n");
+ }
+
+ TNF_PROBE_0_DEBUG(acl_operation_ext_constructor_end ,"ACL","");
+
+ return aclpb;
+
+}
+
+void
+acl_operation_ext_destructor ( void *ext, void *object, void *parent )
+{
+
+ struct acl_cblock *aclcb = NULL;
+ struct acl_pblock *aclpb = NULL;
+
+ TNF_PROBE_0_DEBUG(acl_operation_ext_destructor_start ,"ACL","");
+
+ if ( (NULL == parent ) || (NULL == ext)) {
+ TNF_PROBE_1_DEBUG(acl_operation_ext_destructor_end ,"ACL","",
+ tnf_string,internal_op,"");
+
+ return;
+ }
+
+ aclpb = (Acl_PBlock *) ext;
+
+ if ( (NULL == aclpb) ||
+ (NULL == aclpb->aclpb_pblock) ||
+ (!(aclpb->aclpb_state & ACLPB_INITIALIZED)))
+ goto clean_aclpb;
+
+ /* get the connection extension */
+ aclcb = (struct acl_cblock *) acl_get_ext ( ACL_EXT_CONNECTION, parent );
+
+ /* We are about to get out of this connection. Move all the
+ ** cached information to the acl private block which hangs
+ ** from the connection struct.
+ */
+ if ( aclcb && aclcb->aclcb_lock &&
+ ( (aclpb->aclpb_state & ACLPB_UPD_ACLCB_CACHE ) ||
+ (aclpb->aclpb_state & ACLPB_INCR_ACLCB_CACHE ) ) ) {
+
+ aclEvalContext *c_evalContext;
+ int attr_only = 0;
+ PRLock *shared_lock = aclcb->aclcb_lock;
+
+ if (aclcb->aclcb_lock ) PR_Lock ( shared_lock );
+ else {
+ goto clean_aclpb;
+ }
+ if ( !aclcb->aclcb_lock ) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "aclcb lock released! aclcb cache can't be refreshed\n");
+ PR_Unlock ( shared_lock );
+ goto clean_aclpb;
+ }
+
+ /* We need to refresh the aclcb cache */
+ if ( aclpb->aclpb_state & ACLPB_UPD_ACLCB_CACHE )
+ acl_clean_aclEval_context ( &aclcb->aclcb_eval_context, 0 /* clean*/ );
+ if ( aclpb->aclpb_prev_entryEval_context.acle_numof_attrs ) {
+ c_evalContext = &aclpb->aclpb_prev_entryEval_context;
+ } else {
+ c_evalContext = &aclpb->aclpb_curr_entryEval_context;
+ }
+
+ if (( aclpb->aclpb_state & ACLPB_INCR_ACLCB_CACHE ) &&
+ ! ( aclpb->aclpb_state & ACLPB_UPD_ACLCB_CACHE ))
+ attr_only = 1;
+
+ acl_copyEval_context ( NULL, c_evalContext, &aclcb->aclcb_eval_context, attr_only );
+
+ aclcb->aclcb_aclsignature = aclpb->aclpb_signature;
+ if ( aclcb->aclcb_sdn && aclpb->aclpb_authorization_sdn &&
+ (0 != slapi_sdn_compare ( aclcb->aclcb_sdn,
+ aclpb->aclpb_authorization_sdn ) ) ) {
+ slapi_sdn_set_ndn_byval( aclcb->aclcb_sdn,
+ slapi_sdn_get_ndn ( aclpb->aclpb_authorization_sdn ) );
+ }
+ aclcb->aclcb_state = 0;
+ aclcb->aclcb_state |= ACLCB_HAS_CACHED_EVALCONTEXT;
+
+ PR_Unlock ( shared_lock );
+ }
+
+clean_aclpb:
+ if ( aclpb ) {
+
+ if ( aclpb->aclpb_proxy ) {
+ TNF_PROBE_0_DEBUG(acl_proxy_aclpbdoneback_start ,"ACL","");
+
+ acl__done_aclpb( aclpb->aclpb_proxy );
+
+ /* Put back to the Pool */
+ acl__put_aclpb_back_to_pool ( aclpb->aclpb_proxy );
+ aclpb->aclpb_proxy = NULL;
+ TNF_PROBE_0_DEBUG(acl_proxy_aclpbdoneback_end ,"ACL","");
+
+ }
+
+ TNF_PROBE_0_DEBUG(acl_aclpbdoneback_start ,"ACL","");
+
+ acl__done_aclpb( aclpb);
+ acl__put_aclpb_back_to_pool ( aclpb );
+
+ TNF_PROBE_0_DEBUG(acl_aclpbdoneback_end ,"ACL","");
+
+ }
+
+ TNF_PROBE_0_DEBUG(acl_operation_ext_destructor_end ,"ACL","");
+
+}
+
+/****************************************************************************/
+/* FUNCTIONS TO MANAGE THE ACLPB POOL */
+/****************************************************************************/
+
+/*
+ * Get the right acl pblock
+ */
+struct acl_pblock *
+acl_get_aclpb ( Slapi_PBlock *pb, int type )
+{
+ Acl_PBlock *aclpb = NULL;
+ void *op = NULL;
+
+ slapi_pblock_get ( pb, SLAPI_OPERATION, &op );
+ aclpb = (Acl_PBlock *) acl_get_ext ( ACL_EXT_OPERATION, op );
+ if (NULL == aclpb ) return NULL;
+
+ if ( type == ACLPB_BINDDN_PBLOCK )
+ return aclpb;
+ else if ( type == ACLPB_PROXYDN_PBLOCK )
+ return aclpb->aclpb_proxy;
+ else
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "acl_get_aclpb: Invalid aclpb type %d\n", type );
+ return NULL;
+}
+/*
+ * Create a new proxy acl pblock
+ *
+ */
+struct acl_pblock *
+acl_new_proxy_aclpb( Slapi_PBlock *pb )
+{
+ void *op;
+ Acl_PBlock *aclpb = NULL;
+ Acl_PBlock *proxy_aclpb = NULL;
+
+ slapi_pblock_get ( pb, SLAPI_OPERATION, &op );
+ aclpb = (Acl_PBlock *) acl_get_ext ( ACL_EXT_OPERATION, op );
+ if (NULL == aclpb ) return NULL;
+
+ proxy_aclpb = acl__get_aclpb_from_pool();
+ if (NULL == proxy_aclpb) return NULL;
+ proxy_aclpb->aclpb_type = ACLPB_TYPE_PROXY;
+
+ aclpb->aclpb_proxy = proxy_aclpb;
+
+ return proxy_aclpb;
+
+}
+static int
+acl__handle_config_entry (Slapi_Entry *e, void *callback_data )
+{
+ *(int * )callback_data = slapi_entry_attr_get_int( e, "nsslapd-threadnumber");
+
+ return 0;
+}
+
+/*
+ * Create a pool of acl pblock. Created during the ACL plugin
+ * initialization.
+ */
+int
+acl_create_aclpb_pool ()
+{
+
+ Acl_PBlock *aclpb;
+ Acl_PBlock *prev_aclpb;
+ Acl_PBlock *first_aclpb;
+ int i;
+ int maxThreads= 0;
+
+ slapi_search_internal_callback( "cn=config", LDAP_SCOPE_BASE, "(objectclass=*)",
+ NULL, 0 /* attrsonly */,
+ &maxThreads/* callback_data */,
+ NULL /* controls */,
+ NULL /* result_callback */,
+ acl__handle_config_entry,
+ NULL /* referral_callback */);
+
+ /* Create a pool pf aclpb */
+ maxThreads = 2 * maxThreads;
+
+ aclQueue = ( Acl_PBqueue *) slapi_ch_calloc ( 1, sizeof (Acl_PBqueue) );
+ aclQueue->aclq_lock = PR_NewLock();
+
+ if ( NULL == aclQueue->aclq_lock ) {
+ /* ERROR */
+ return 1;
+ }
+
+ prev_aclpb = NULL;
+ first_aclpb = NULL;
+ for ( i = 0; i < maxThreads; i++ ) {
+ aclpb = acl__malloc_aclpb ();
+ if ( 0 == i) first_aclpb = aclpb;
+
+ aclpb->aclpb_prev = prev_aclpb;
+ if ( prev_aclpb ) prev_aclpb->aclpb_next = aclpb;
+ prev_aclpb = aclpb;
+ }
+
+ /* Since this is the begining, everybody is in free list */
+ aclQueue->aclq_free = first_aclpb;
+
+ aclQueue->aclq_nfree = maxThreads;
+ return 0;
+}
+
+/*
+ * Get a FREE acl pblock from the pool.
+ *
+ */
+static Acl_PBlock *
+acl__get_aclpb_from_pool ( )
+{
+ Acl_PBlock *aclpb = NULL;
+ Acl_PBlock *t_aclpb = NULL;
+
+
+ PR_Lock (aclQueue->aclq_lock );
+
+ /* Get the first aclpb from the FREE List */
+ aclpb = aclQueue->aclq_free;
+ if ( aclpb ) {
+ t_aclpb = aclpb->aclpb_next;
+ if ( t_aclpb ) t_aclpb->aclpb_prev = NULL;
+ aclQueue->aclq_free = t_aclpb;
+
+ /* make the this an orphon */
+ aclpb->aclpb_prev = aclpb->aclpb_next = NULL;
+
+ aclQueue->aclq_nfree--;
+ } else {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Unable to find a free aclpb\n");
+ aclpb = acl__malloc_aclpb ();
+ }
+
+
+ /* Now move it to the FRONT of busy list */
+ t_aclpb = aclQueue->aclq_busy;
+ aclpb->aclpb_next = t_aclpb;
+ if ( t_aclpb ) t_aclpb->aclpb_prev = aclpb;
+ aclQueue->aclq_busy = aclpb;
+ aclQueue->aclq_nbusy++;
+
+ PR_Unlock (aclQueue->aclq_lock );
+
+ return aclpb;
+}
+/*
+ * Put the acl pblock into the FREE pool.
+ *
+ */
+static int
+acl__put_aclpb_back_to_pool ( Acl_PBlock *aclpb )
+{
+
+ Acl_PBlock *p_aclpb, *n_aclpb;
+
+ PR_Lock (aclQueue->aclq_lock );
+
+ /* Remove it from the busy list */
+ n_aclpb = aclpb->aclpb_next;
+ p_aclpb = aclpb->aclpb_prev;
+
+ if ( p_aclpb ) {
+ p_aclpb->aclpb_next = n_aclpb;
+ if ( n_aclpb ) n_aclpb->aclpb_prev = p_aclpb;
+ } else {
+ aclQueue->aclq_busy = n_aclpb;
+ if ( n_aclpb ) n_aclpb->aclpb_prev = NULL;
+ }
+ aclQueue->aclq_nbusy--;
+
+
+ /* Put back to the FREE list */
+ aclpb->aclpb_prev = NULL;
+ n_aclpb = aclQueue->aclq_free;
+ aclpb->aclpb_next = n_aclpb;
+ if ( n_aclpb ) n_aclpb->aclpb_prev = aclpb;
+ aclQueue->aclq_free = aclpb;
+ aclQueue->aclq_nfree++;
+
+ PR_Unlock (aclQueue->aclq_lock );
+
+ return 0;
+}
+
+/*
+ * Allocate the basic acl pb
+ *
+ */
+static Acl_PBlock *
+acl__malloc_aclpb ( )
+{
+ Acl_PBlock *aclpb = NULL;
+
+
+ aclpb = ( Acl_PBlock *) slapi_ch_calloc ( 1, sizeof ( Acl_PBlock) );
+
+ /* Now set the propert we need for ACL evaluations */
+ if ((aclpb->aclpb_proplist = PListNew(NULL)) == NULL) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to allocate the aclprop PList\n");
+ return NULL;
+ }
+
+ if (PListInitProp(aclpb->aclpb_proplist, 0, DS_PROP_ACLPB, aclpb, 0) < 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to set the ACL PBLOCK in the Plist\n");
+ return NULL;
+ }
+ if (PListInitProp(aclpb->aclpb_proplist, 0, DS_ATTR_USERDN, aclpb, 0) < 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to set the USER DN in the Plist\n");
+ return NULL;
+ }
+ if (PListInitProp(aclpb->aclpb_proplist, 0, DS_ATTR_AUTHTYPE, aclpb, 0) < 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to set the AUTH TYPE in the Plist\n");
+ return NULL;
+ }
+ if (PListInitProp(aclpb->aclpb_proplist, 0, DS_ATTR_ENTRY, aclpb, 0) < 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to set the ENTRY TYPE in the Plist\n");
+ return NULL;
+ }
+
+ /*
+ * ACL_ATTR_IP and ACL_ATTR_DNS are initialized lazily in the
+ * IpGetter and DnsGetter functions.
+ * They are removed from the aclpb property list at acl__aclpb_done()
+ * time.
+ */
+
+ /* allocate the acleval struct */
+ aclpb->aclpb_acleval = (ACLEvalHandle_t *) ACL_EvalNew(NULL, NULL);
+ if (aclpb->aclpb_acleval == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to allocate the acleval block\n");
+ return NULL;
+ }
+ /*
+ * This is a libaccess routine.
+ * Need to setup subject and resource property information
+ */
+
+ ACL_EvalSetSubject(NULL, aclpb->aclpb_acleval, aclpb->aclpb_proplist);
+
+ /* allocate some space for attr name */
+ aclpb->aclpb_Evalattr = (char *) slapi_ch_malloc (ACLPB_MAX_ATTR_LEN);
+
+ aclpb->aclpb_deny_handles = (aci_t **) slapi_ch_calloc (1,
+ ACLPB_INCR_LIST_HANDLES * sizeof (aci_t *));
+
+ aclpb->aclpb_allow_handles = (aci_t **) slapi_ch_calloc (1,
+ ACLPB_INCR_LIST_HANDLES * sizeof (aci_t *));
+
+ aclpb->aclpb_deny_handles_size = ACLPB_INCR_LIST_HANDLES;
+ aclpb->aclpb_allow_handles_size = ACLPB_INCR_LIST_HANDLES;
+
+ /* allocate the array for bases */
+ aclpb->aclpb_grpsearchbase = (char **)
+ slapi_ch_malloc (ACLPB_INCR_BASES * sizeof(char *));
+ aclpb->aclpb_grpsearchbase_size = ACLPB_INCR_BASES;
+ aclpb->aclpb_numof_bases = 0;
+
+ /* Make sure aclpb_search_base is initialized to NULL..tested elsewhere! */
+ aclpb->aclpb_search_base = NULL;
+
+ aclpb->aclpb_authorization_sdn = slapi_sdn_new ();
+ aclpb->aclpb_curr_entry_sdn = slapi_sdn_new();
+
+ aclpb->aclpb_aclContainer = acllist_get_aciContainer_new ();
+
+ /* hash table to store macro matched values from targets */
+ aclpb->aclpb_macro_ht = acl_ht_new();
+
+ return aclpb;
+
+}
+
+/* Initializes the aclpb */
+void
+acl_init_aclpb ( Slapi_PBlock *pb , Acl_PBlock *aclpb, const char *dn, int copy_from_aclcb)
+{
+ struct acl_cblock *aclcb = NULL;
+ char *authType;
+ void *conn;
+ unsigned long op_type;
+
+
+ if ( NULL == aclpb ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "acl_init_aclpb:No ACLPB\n");
+ return;
+ }
+
+ /* See if we have initialized already */
+ if (aclpb->aclpb_state & ACLPB_INITIALIZED) return;
+
+ slapi_pblock_get ( pb, SLAPI_OPERATION_TYPE, &op_type );
+ if ( op_type == SLAPI_OPERATION_BIND || op_type == SLAPI_OPERATION_UNBIND )
+ return;
+
+ /* We indicate the initialize here becuase, if something goes wrong, it's cleaned up
+ ** properly.
+ */
+ aclpb->aclpb_state = ACLPB_INITIALIZED;
+
+ /* We make an anonymous user a non null dn which is empty */
+ if (dn && *dn != '\0' )
+ slapi_sdn_set_ndn_byval ( aclpb->aclpb_authorization_sdn, dn );
+ else
+ slapi_sdn_set_ndn_byval ( aclpb->aclpb_authorization_sdn, "" );
+
+ /* reset scoped entry cache to be empty */
+ aclpb->aclpb_scoped_entry_anominfo.anom_e_nummatched = 0;
+
+ if (PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_USERDN,
+ slapi_sdn_get_ndn(aclpb->aclpb_authorization_sdn), 0) < 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to set the USER DN in the Plist\n");
+ return;
+ }
+ slapi_pblock_get ( pb, SLAPI_OPERATION_AUTHTYPE, &authType );
+ if (PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_AUTHTYPE, authType, 0) < 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to set the AUTH TYPE in the Plist\n");
+ return;
+ }
+ /* PKBxxx: We should be getting it from the OP struct */
+ slapi_pblock_get ( pb, SLAPI_CONN_CERT, &aclpb->aclpb_clientcert );
+
+ /* See if the we have already a cached info about user's group */
+ aclg_init_userGroup ( aclpb, dn, 0 /* get lock */ );
+
+ slapi_pblock_get( pb, SLAPI_BE_MAXNESTLEVEL, &aclpb->aclpb_max_nesting_level );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &aclpb->aclpb_max_member_sizelimit );
+ if ( aclpb->aclpb_max_member_sizelimit == 0 ) {
+ aclpb->aclpb_max_member_sizelimit = SLAPD_DEFAULT_LOOKTHROUGHLIMIT;
+ }
+ slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &aclpb->aclpb_optype );
+
+ aclpb->aclpb_signature = acl_get_aclsignature();
+ aclpb->aclpb_last_cache_result = 0;
+ aclpb->aclpb_pblock = pb;
+ PR_ASSERT ( aclpb->aclpb_pblock != NULL );
+
+ /* get the connection */
+ slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn);
+ aclcb = (struct acl_cblock *) acl_get_ext ( ACL_EXT_CONNECTION, conn );
+
+ if (NULL == aclcb || NULL == aclcb->aclcb_lock) {
+ /* This could happen if the client is dead and we are in
+ ** process of abondoning this operation
+ */
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "No CONNECTION extension\n");
+
+ } else if ( aclcb->aclcb_state == -1 ) {
+ /* indicate that we need to update the cache */
+ aclpb->aclpb_state |= ACLPB_UPD_ACLCB_CACHE;
+ aclcb->aclcb_state = 0; /* Nore this is ACLCB and not ACLPB */
+
+ } else if ( copy_from_aclcb ){
+ char *cdn;
+ Slapi_DN *c_sdn; /* client SDN */
+
+ /* check if the operation is abandoned or not.*/
+ if ( slapi_op_abandoned ( pb ) ) {
+ return;
+ }
+
+ slapi_pblock_get ( pb, SLAPI_CONN_DN, &cdn ); /* We *must* free cdn! */
+ c_sdn = slapi_sdn_new_dn_passin( cdn );
+ PR_Lock ( aclcb->aclcb_lock );
+ /*
+ * since PR_Lock is taken,
+ * we can mark the connection extension ok to be destroyed.
+ */
+ if ( (aclcb->aclcb_aclsignature != acl_get_aclsignature()) ||
+ ( (NULL == cdn) && aclcb->aclcb_sdn ) ||
+ (cdn && (NULL == aclcb->aclcb_sdn )) ||
+ (cdn && aclcb->aclcb_sdn && ( 0 != slapi_sdn_compare ( c_sdn, aclcb->aclcb_sdn ) ))) {
+
+ /* cleanup the aclcb cache */
+ acl_clean_aclEval_context ( &aclcb->aclcb_eval_context, 0 /*clean*/ );
+ aclcb->aclcb_state = 0;
+ aclcb->aclcb_aclsignature = 0;
+ slapi_sdn_done ( aclcb->aclcb_sdn );
+ }
+ slapi_sdn_free ( &c_sdn );
+
+ /* COPY the cached information from ACLCB --> ACLPB */
+ if ( aclcb->aclcb_state & ACLCB_HAS_CACHED_EVALCONTEXT) {
+ acl_copyEval_context ( aclpb, &aclcb->aclcb_eval_context ,
+ &aclpb->aclpb_prev_opEval_context, 0 );
+ aclpb->aclpb_state |= ACLPB_HAS_ACLCB_EVALCONTEXT;
+ }
+ PR_Unlock ( aclcb->aclcb_lock );
+ }
+
+}
+
+/* Cleans up the aclpb */
+static void
+acl__done_aclpb ( struct acl_pblock *aclpb )
+{
+
+ int i;
+ int dump_aclpb_info = 0;
+ char *ds_attr_userdn=NULL; /* for finding userdn for freeing */
+ int rc=-1;
+ char *tmp_ptr=NULL;
+
+ /*
+ ** First, let's do some sanity checks to see if we have everything what
+ ** it should be.
+ */
+
+ /* Nothing needs to be cleaned up in this case */
+ if ( !aclpb->aclpb_state & ACLPB_INITIALIZED)
+ return;
+
+ /* Check the state */
+ if (aclpb->aclpb_state & ~ACLPB_STATE_ALL) {
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
+ "The aclpb.state value (%d) is incorrect. Exceeded the limit (%d)\n",
+ aclpb->aclpb_state, ACLPB_STATE_ALL);
+ dump_aclpb_info = 1;
+
+ }
+
+ /* acl__dump_stats ( aclpb, acl__get_aclpb_type(aclpb)); */
+
+ /* reset the usergroup cache */
+ aclg_reset_userGroup ( aclpb );
+
+ if ( aclpb->aclpb_res_type & ~ACLPB_RESTYPE_ALL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
+ "The aclpb res_type value (%d) has exceeded. Limit is (%d)\n",
+ aclpb->aclpb_res_type, ACLPB_RESTYPE_ALL, 0 );
+ dump_aclpb_info = 1;
+ }
+
+ if ( dump_aclpb_info ) {
+ const char *ndn;
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "ACLPB value is:%p\n", aclpb, 0,0 );
+
+ ndn = slapi_sdn_get_ndn ( aclpb->aclpb_curr_entry_sdn );
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "curr_entry:%p num_entries:%d curr_dn:%p\n",
+ aclpb->aclpb_curr_entry ? (char *) aclpb->aclpb_curr_entry : "NULL",
+ aclpb->aclpb_num_entries,
+ ndn ? ndn : "NULL");
+
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Last attr:%p, Plist:%p acleval: %p\n",
+ aclpb->aclpb_Evalattr ? aclpb->aclpb_Evalattr : "NULL",
+ aclpb->aclpb_proplist ? (char *) aclpb->aclpb_proplist : "NULL",
+ aclpb->aclpb_acleval ? (char *) aclpb->aclpb_acleval : "NULL" );
+ }
+
+ /* Now Free the contents or clean it */
+ slapi_sdn_done ( aclpb->aclpb_curr_entry_sdn );
+ if (aclpb->aclpb_Evalattr)
+ aclpb->aclpb_Evalattr[0] = '\0';
+
+ /* deallocate the contents of the base array */
+ for (i=0; i < aclpb->aclpb_numof_bases; i++) {
+ if (aclpb->aclpb_grpsearchbase[i])
+ slapi_ch_free ( (void **)&aclpb->aclpb_grpsearchbase[i] );
+ }
+ aclpb->aclpb_numof_bases = 0;
+
+ acl_clean_aclEval_context ( &aclpb->aclpb_prev_opEval_context, 0 /*claen*/ );
+ acl_clean_aclEval_context ( &aclpb->aclpb_prev_entryEval_context, 0 /*clean*/ );
+ acl_clean_aclEval_context ( &aclpb->aclpb_curr_entryEval_context, 0/*clean*/ );
+
+ if ( aclpb->aclpb_client_entry ) slapi_entry_free ( aclpb->aclpb_client_entry );
+ aclpb->aclpb_client_entry = NULL;
+
+ slapi_sdn_done ( aclpb->aclpb_authorization_sdn );
+ aclpb->aclpb_pblock = NULL;
+
+ if ( aclpb->aclpb_search_base )
+ slapi_ch_free ( (void **) &aclpb->aclpb_search_base );
+ for ( i=0; i < aclpb->aclpb_num_deny_handles; i++ )
+ aclpb->aclpb_deny_handles[i] = NULL;
+ aclpb->aclpb_num_deny_handles = 0;
+
+ for ( i=0; i < aclpb->aclpb_num_allow_handles; i++ )
+ aclpb->aclpb_allow_handles[i] = NULL;
+ aclpb->aclpb_num_allow_handles = 0;
+
+ /* clear results cache */
+ memset((char*)aclpb->aclpb_cache_result, 0,
+ sizeof(struct result_cache)*aclpb->aclpb_last_cache_result);
+ aclpb->aclpb_last_cache_result = 0;
+ aclpb->aclpb_handles_index[0] = -1;
+ aclpb->aclpb_base_handles_index[0] = -1;
+
+ aclpb->aclpb_stat_acllist_scanned = 0;
+ aclpb->aclpb_stat_aclres_matched = 0;
+ aclpb->aclpb_stat_total_entries = 0;
+ aclpb->aclpb_stat_anom_list_scanned = 0;
+ aclpb->aclpb_stat_num_copycontext = 0;
+ aclpb->aclpb_stat_num_copy_attrs = 0;
+ aclpb->aclpb_stat_num_tmatched_acls = 0;
+
+ aclpb->aclpb_clientcert = NULL;
+ aclpb->aclpb_proxy = NULL;
+
+ acllist_done_aciContainer ( aclpb->aclpb_aclContainer );
+
+ /*
+ * Here, decide which things need to be freed/removed/whatever from the
+ * aclpb_proplist.
+ */
+
+ /*
+ * The DS_ATTR_DNS property contains the name of the client machine.
+ *
+ * The value pointed to by this property is stored in the pblock--it
+ * points to the SLAPI_CLIENT_DNS object. So, that memory will
+ * be freed elsewhere.
+ *
+ * It's removed here from the aclpb_proplist as it would be an error to
+ * allow it to persist in the aclpb which is an operation time thing.
+ * If we leave it here the next time this aclpb gets used, the DnsGetter
+ * is not called by LASDnsEval/ACL_GetAttribute() as it thinks the
+ * ACL_ATTR_DNS has already been initialized.
+ *
+ */
+
+ if ((rc = PListFindValue(aclpb->aclpb_proplist, ACL_ATTR_DNS,
+ (void **)&tmp_ptr, NULL)) > 0) {
+
+ PListDeleteProp(aclpb->aclpb_proplist, rc, NULL);
+ }
+
+ /*
+ * Remove the DS_ATTR_IP property from the property list.
+ * The value of this property is just the property pointer
+ * (an unsigned long) so that gets freed too when we delete the
+ * property.
+ * It's removed here from the aclpb_proplist as it would be an error to
+ * allow it to persist in the aclpb which is an operation time thing.
+ * If we leave it here the next time this aclpb gets used, the DnsGetter
+ * is not called by LASIpEval/ACL_GetAttribute() as it thinks the
+ * ACL_ATTR_IP has already been initialized.
+ */
+
+ if ((rc = PListFindValue(aclpb->aclpb_proplist, ACL_ATTR_IP,
+ (void **)&tmp_ptr, NULL)) > 0) {
+
+ PListDeleteProp(aclpb->aclpb_proplist, rc, NULL);
+ }
+
+ /*
+ * The DS_ATTR_USERDN value comes from aclpb_authorization_sdn.
+ * This memory
+ * is freed above using aclpb_authorization_sdn so we don't need to free it here
+ * before overwriting the old value.
+ */
+ PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_USERDN, NULL, 0);
+
+ /*
+ * The DS_ATTR_AUTHTYPE value is a pointer into the pblock, so
+ * we do not need to free that memory before overwriting the value.
+ */
+ PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_AUTHTYPE, NULL, 0);
+
+ /*
+ * DO NOT overwrite the aclpb pointer--it is initialized at malloc_aclpb
+ * time and is kept within the aclpb.
+ *
+ * PListAssignValue(aclpb->aclpb_proplist, DS_PROP_ACLPB, NULL, 0);
+ */
+
+ /*
+ * The DS_ATTR_ENTRY value was a pointer to the entry being evaluated
+ * by the ACL code. That entry comes from outside the context of
+ * the acl code and so is dealt with out there. Ergo, here we can just
+ * lose the pointer to that entry.
+ */
+ PListAssignValue(aclpb->aclpb_proplist, DS_ATTR_ENTRY, NULL, 0);
+
+ aclpb->aclpb_signature = 0;
+
+ /* reset scoped entry cache to be empty */
+ aclpb->aclpb_scoped_entry_anominfo.anom_e_nummatched = 0;
+
+ /* Free up any of the string values left in the macro ht and remove
+ * the entries.*/
+ acl_ht_free_all_entries_and_values(aclpb->aclpb_macro_ht);
+
+ /* Finally, set it to the no use state */
+ aclpb->aclpb_state = 0;
+
+}
+
+static char *
+acl__get_aclpb_type ( Acl_PBlock *aclpb )
+{
+
+ if (aclpb->aclpb_state & ACLPB_TYPE_PROXY)
+ return ACLPB_TYPE_PROXY_STR;
+
+ return ACLPB_TYPE_MAIN_STR;
+}
+static void
+acl__dump_stats ( struct acl_pblock *aclpb , const char *block_type)
+{
+ int connid = 0;
+ int opid = 0;
+ Slapi_PBlock *pb = NULL;
+
+ pb = aclpb->aclpb_pblock;
+ if ( pb ) {
+ slapi_pblock_get ( pb, SLAPI_CONN_ID, &connid );
+ slapi_pblock_get ( pb, SLAPI_OPERATION_ID, &opid );
+ }
+
+ /* DUMP STAT INFO */
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "**** ACL OPERATION STAT BEGIN ( aclpb:%p Block type: %s): Conn:%d Operation:%d *******\n",
+ aclpb, block_type, connid, opid );
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of entries scanned: %d\n",
+ aclpb->aclpb_stat_total_entries);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times ACL List scanned: %d\n",
+ aclpb->aclpb_stat_acllist_scanned);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of ACLs with target matched:%d\n",
+ aclpb->aclpb_stat_num_tmatched_acls);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times acl resource matched:%d\n",
+ aclpb->aclpb_stat_aclres_matched);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times ANOM list scanned:%d\n",
+ aclpb->aclpb_stat_anom_list_scanned);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times Context was copied:%d\n",
+ aclpb->aclpb_stat_num_copycontext);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "\tNumber of times Attrs was copied:%d\n",
+ aclpb->aclpb_stat_num_copy_attrs);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, " **** ACL OPERATION STAT END *******\n");
+}
+/****************************************************************************/
+/* E N D */
+/****************************************************************************/
+
diff --git a/ldap/servers/plugins/acl/aclanom.c b/ldap/servers/plugins/acl/aclanom.c
new file mode 100644
index 00000000..71b0c68a
--- /dev/null
+++ b/ldap/servers/plugins/acl/aclanom.c
@@ -0,0 +1,536 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "acl.h"
+
+/************************************************************************
+Anonymous profile
+**************************************************************************/
+
+struct anom_targetacl {
+ int anom_type; /* defines for anom types same as aci_type */
+ int anom_access;
+ Slapi_DN *anom_target; /* target of the ACL */
+ Slapi_Filter *anom_filter; /* targetfilter part */
+ char **anom_targetAttrs; /* list of attrs */
+};
+
+
+struct anom_profile {
+ short anom_signature;
+ short anom_numacls;
+ struct anom_targetacl anom_targetinfo[ACL_ANOM_MAX_ACL];
+};
+
+static struct anom_profile *acl_anom_profile = NULL;
+
+static PRRWLock *anom_rwlock = NULL;
+#define ANOM_LOCK_READ() PR_RWLock_Rlock (anom_rwlock )
+#define ANOM_UNLOCK_READ() PR_RWLock_Unlock (anom_rwlock )
+#define ANOM_LOCK_WRITE() PR_RWLock_Wlock (anom_rwlock )
+#define ANOM_UNLOCK_WRITE() PR_RWLock_Unlock (anom_rwlock )
+
+
+static void __aclanom__del_profile ();
+
+/*
+ * aclanom_init ();
+ * Generate a profile for the anonymous user. We can use this profile
+ * later to determine what resources the client is allowed to.
+ *
+ * Dependency:
+ * Before calling this, it is assumed that all the ACLs have been read
+ * and parsed.
+ *
+ * We will go thru all the ACL and pick the ANYONE ACL and generate the anom
+ * profile.
+ *
+ */
+int
+aclanom_init ()
+{
+
+ acl_anom_profile = (struct anom_profile * )
+ slapi_ch_calloc (1, sizeof ( struct anom_profile ) );
+
+ if (( anom_rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,"ANOM LOCK") ) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
+ "Failed in getting the ANOM rwlock\n" );
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Depending on the context, this routine may need to take the
+ * acicache read lock.
+*/
+void
+aclanom_gen_anomProfile (acl_lock_flag_t lock_flag)
+{
+ aci_t *aci = NULL;
+ int i;
+ Targetattr **srcattrArray;
+ Targetattr *attr;
+ struct anom_profile *a_profile;
+ PRUint32 cookie;
+
+ PR_ASSERT( lock_flag == DO_TAKE_ACLCACHE_READLOCK ||
+ lock_flag == DONT_TAKE_ACLCACHE_READLOCK);
+
+ /*
+ * This routine requires two locks:
+ * the one for the global cache in acllist_acicache_READ_LOCK() and
+ * the one for the anom profile.
+ * They _must_ be taken in the order presented here or there
+ * is a deadlock scenario with acllist_remove_aci_needsLock() which
+ * takes them is this order.
+ */
+
+ if ( lock_flag == DO_TAKE_ACLCACHE_READLOCK ) {
+ acllist_acicache_READ_LOCK();
+ }
+ ANOM_LOCK_WRITE ();
+ a_profile = acl_anom_profile;
+
+ if ( (!acl_get_aclsignature()) || ( !a_profile) ||
+ (a_profile->anom_signature == acl_get_aclsignature()) ) {
+ ANOM_UNLOCK_WRITE ();
+ if ( lock_flag == DO_TAKE_ACLCACHE_READLOCK ) {
+ acllist_acicache_READ_UNLOCK();
+ }
+ return;
+ }
+
+ /* D0 we have one already. If we do, then clean it up */
+ __aclanom__del_profile();
+
+ /* We have a new signature now */
+ a_profile->anom_signature = acl_get_aclsignature();
+
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name, "GENERATING ANOM USER PROFILE\n", 0,0,0);
+ /*
+ ** Go thru the ACL list and find all the ACLs which apply to the
+ ** anonymous user i.e anyone. we can generate a profile for that.
+ ** We will llok at the simple case i.e it matches
+ ** cases not handled:
+ ** 1) When there is a mix if rule types ( allows & denies )
+ **
+ */
+
+ aci = acllist_get_first_aci ( NULL, &cookie );
+ while ( aci ) {
+ int a_numacl;
+ struct slapi_filter *f;
+ char **destattrArray;
+
+
+ /*
+ * We must not have a rule like: deny ( all ) userdn != "xyz"
+ * or groupdn !=
+ */
+ if ( (aci->aci_type & ACI_HAS_DENY_RULE) &&
+ ( (aci->aci_type & ACI_CONTAIN_NOT_USERDN ) ||
+ (aci->aci_type & ACI_CONTAIN_NOT_GROUPDN) ||
+ (aci->aci_type & ACI_CONTAIN_NOT_ROLEDN)) ){
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "CANCELLING ANOM USER PROFILE BECAUSE OF DENY RULE\n", 0,0,0);
+ goto cleanup;
+ }
+
+ /* Must be a anyone rule */
+ if ( aci->aci_elevel != ACI_ELEVEL_USERDN_ANYONE ) {
+ aci = acllist_get_next_aci ( NULL, aci, &cookie);
+ continue;
+ }
+ if (! (aci->aci_access & ( SLAPI_ACL_READ | SLAPI_ACL_SEARCH)) ) {
+ aci = acllist_get_next_aci ( NULL, aci, &cookie);
+ continue;
+ }
+ /* If the rule has anything other than userdn = "ldap:///anyone"
+ ** let's not consider complex rules - let's make this lean.
+ */
+ if ( aci->aci_ruleType & ~ACI_USERDN_RULE ){
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "CANCELLING ANOM USER PROFILE BECAUSE OF COMPLEX RULE\n", 0,0,0);
+ goto cleanup;
+ }
+
+ /* Must not be a or have a
+ ** 1 ) DENY RULE 2) targetfilter
+ ** 3) no target pattern ( skip monitor acl )
+ */
+ if ( aci->aci_type & ( ACI_HAS_DENY_RULE | ACI_TARGET_PATTERN |
+ ACI_TARGET_NOT | ACI_TARGET_FILTER_NOT )) {
+ const char *dn = slapi_sdn_get_dn ( aci->aci_sdn );
+
+ /* see if this is a monitor acl */
+ if (( strcasecmp ( dn, "cn=monitor") == 0 ) ||
+ ( strcasecmp ( dn, "cn=monitor,cn=ldbm") == 0 )) {
+ aci = acllist_get_next_aci ( NULL, aci, &cookie);
+ continue;
+ } else {
+ /* clean up before leaving */
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "CANCELLING ANOM USER PROFILE 1\n", 0,0,0);
+ goto cleanup;
+ }
+
+ }
+
+ /* Now we have an ALLOW ACL which applies to anyone */
+ a_numacl = a_profile->anom_numacls++;
+
+ if ( a_profile->anom_numacls == ACL_ANOM_MAX_ACL ) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name, "CANCELLING ANOM USER PROFILE 2\n", 0,0,0);
+ goto cleanup;
+ }
+
+ if ( (f = aci->target) != NULL ) {
+ char *avaType;
+ struct berval *avaValue;
+ slapi_filter_get_ava ( f, &avaType, &avaValue );
+
+ a_profile->anom_targetinfo[a_numacl].anom_target =
+ slapi_sdn_new_dn_byval ( avaValue->bv_val );
+ } else {
+ a_profile->anom_targetinfo[a_numacl].anom_target =
+ slapi_sdn_dup ( aci->aci_sdn );
+ }
+
+ a_profile->anom_targetinfo[a_numacl].anom_filter = NULL;
+ if ( aci->targetFilterStr )
+ a_profile->anom_targetinfo[a_numacl].anom_filter = slapi_str2filter ( aci->targetFilterStr );
+
+ i = 0;
+ srcattrArray = aci->targetAttr;
+ while ( srcattrArray[i])
+ i++;
+
+ a_profile->anom_targetinfo[a_numacl].anom_targetAttrs =
+ (char **) slapi_ch_calloc ( 1, (i+1) * sizeof(char *));
+
+ srcattrArray = aci->targetAttr;
+ destattrArray = a_profile->anom_targetinfo[a_numacl].anom_targetAttrs;
+
+ i = 0;
+ while ( srcattrArray[i] ) {
+ attr = srcattrArray[i];
+ if ( attr->attr_type & ACL_ATTR_FILTER ) {
+ /* Do'nt want to support these kind now */
+ destattrArray[i] = NULL;
+ /* clean up before leaving */
+ __aclanom__del_profile ();
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "CANCELLING ANOM USER PROFILE 3\n", 0,0,0);
+ goto cleanup;
+ }
+
+ destattrArray[i] = slapi_ch_strdup ( attr->u.attr_str );
+ i++;
+ }
+
+ destattrArray[i] = NULL;
+
+ aclutil_print_aci ( aci, "anom" );
+ /* Here we are storing att the info from the acls. However
+ ** we are only interested in a few things like ACI_TARGETATTR_NOT.
+ */
+ a_profile->anom_targetinfo[a_numacl].anom_type = aci->aci_type;
+ a_profile->anom_targetinfo[a_numacl].anom_access = aci->aci_access;
+
+ aci = acllist_get_next_aci ( NULL, aci, &cookie);
+ }
+
+ ANOM_UNLOCK_WRITE ();
+ if ( lock_flag == DO_TAKE_ACLCACHE_READLOCK ) {
+ acllist_acicache_READ_UNLOCK();
+ }
+ return;
+
+cleanup:
+ __aclanom__del_profile ();
+ ANOM_UNLOCK_WRITE ();
+ if ( lock_flag == DO_TAKE_ACLCACHE_READLOCK ) {
+ acllist_acicache_READ_UNLOCK();
+ }
+}
+
+
+void
+aclanom_invalidateProfile ()
+{
+ ANOM_LOCK_WRITE();
+ if ( acl_anom_profile && acl_anom_profile->anom_numacls )
+ acl_anom_profile->anom_signature = 0;
+ ANOM_UNLOCK_WRITE();
+
+
+}
+
+/*
+ * __aclanom_del_profile
+ *
+ * Cleanup the anonymous user's profile we have.
+ *
+ * ASSUMPTION: A WRITE LOCK HAS BEEN OBTAINED
+ *
+ */
+static void
+__aclanom__del_profile (void)
+{
+ int i;
+ struct anom_profile *a_profile;
+
+
+ if ( (a_profile = acl_anom_profile) == NULL ) {
+ return;
+ }
+
+ for ( i=0; i < a_profile->anom_numacls; i++ ) {
+ int j = 0;
+ char **destArray = a_profile->anom_targetinfo[i].anom_targetAttrs;
+
+ /* Deallocate target */
+ slapi_sdn_free ( &a_profile->anom_targetinfo[i].anom_target );
+
+ /* Deallocate filter */
+ if ( a_profile->anom_targetinfo[i].anom_filter )
+ slapi_filter_free ( a_profile->anom_targetinfo[i].anom_filter, 1 );
+
+ /* Deallocate attrs */
+ if ( destArray ) {
+ while ( destArray[j] ) {
+ slapi_ch_free ( (void **) &destArray[j] );
+ j++;
+ }
+ slapi_ch_free ( (void **) &destArray );
+ }
+ a_profile->anom_targetinfo[i].anom_targetAttrs = NULL;
+ a_profile->anom_targetinfo[i].anom_type = 0;
+ a_profile->anom_targetinfo[i].anom_access = 0;
+ }
+ a_profile->anom_numacls = 0;
+
+ /* Don't clean the signatue */
+}
+
+/*
+ * This routine sets up a "context" for evaluation of access control
+ * on a given entry for an anonymous user.
+ * It just factors out the scope and targetfilter info into a list
+ * of indices of the global anom profile list, that apply to this
+ * entry, and stores them in the aclpb.
+ * It's use relies on the way that access control is checked in the mailine search
+ * code in the core server, namely: check filter, check entry, then check each
+ * attribute. So, we call this in acl_access_allowed() before calling
+ * aclanom_match_profile()--therafter, aclanom_match_profile() uses the
+ * context to evaluate access to the entry and attributes.
+ *
+ * If there are no anom profiles, or the anom profiles get cancelled
+ * due to complex anon acis, then that's OK, aclanom_match_profile()
+ * returns -1 and the mainline acl code kicks in.
+ *
+ * The lifetime of this context info is the time it takes to check
+ * access control for all parts of this entry (filter, entry, attributes).
+ * So, if for an example an entry changes and a given anom profile entry
+ * no longer applies, we will not notice until the next round of access
+ * control checking on the entry--this is acceptable.
+ *
+ * The gain on doing this factoring in the following type of search
+ * was approx 6%:
+ * anon bind, 20 threads, exact match, ~20 attributes returned,
+ * (searchrate & DirectoryMark).
+ *
+*/
+void
+aclanom_get_suffix_info(Slapi_Entry *e,
+ struct acl_pblock *aclpb ) {
+ int i;
+ char *ndn = NULL;
+ Slapi_DN *e_sdn;
+ const char *aci_ndn;
+ int populate = 0;
+ struct scoped_entry_anominfo *s_e_anominfo =
+ &aclpb->aclpb_scoped_entry_anominfo;
+
+ ANOM_LOCK_READ ();
+
+ s_e_anominfo->anom_e_nummatched=0;
+
+ ndn = slapi_entry_get_ndn ( e ) ;
+ e_sdn= slapi_entry_get_sdn ( e ) ;
+ for (i=acl_anom_profile->anom_numacls-1; i >= 0; i-- ) {
+ aci_ndn = slapi_sdn_get_ndn (acl_anom_profile->anom_targetinfo[i].anom_target);
+ if (!slapi_sdn_issuffix(e_sdn,acl_anom_profile->anom_targetinfo[i].anom_target)
+ || (!slapi_is_rootdse(ndn) && slapi_is_rootdse(aci_ndn)))
+ continue;
+ if ( acl_anom_profile->anom_targetinfo[i].anom_filter ) {
+ if ( slapi_vattr_filter_test( aclpb->aclpb_pblock, e,
+ acl_anom_profile->anom_targetinfo[i].anom_filter,
+ 0 /*don't do acess chk*/) != 0)
+ continue;
+ }
+ s_e_anominfo->anom_e_targetInfo[s_e_anominfo->anom_e_nummatched]=i;
+ s_e_anominfo->anom_e_nummatched++;
+ }
+ ANOM_UNLOCK_READ ();
+}
+
+
+/*
+ * aclanom_match_profile
+ * Look at the anonymous profile and see if we can use it or not.
+ *
+ *
+ * Inputs:
+ * Slapi_Pblock - The Pblock
+ * Slapi_Entry *e - The entry for which we are asking permission.
+ * char *attr - Attribute name
+ * int access - access type
+ *
+ * Return:
+ * LDAP_SUCCESS ( 0 ) - acess is allowed.
+ * LDAP_INSUFFICIENT_ACCESS (50 ) - access denied.
+ * -1 - didn't match the targets
+ *
+ * Assumptions:
+ * The caller of this module has to make sure that the client is
+ * an anonymous client.
+ */
+int
+aclanom_match_profile (Slapi_PBlock *pb, struct acl_pblock *aclpb, Slapi_Entry *e,
+ char *attr, int access )
+{
+
+ struct anom_profile *a_profile;
+ int result, i, k;
+ char **destArray;
+ int tmatched = 0;
+ char ebuf[ BUFSIZ ];
+ int loglevel;
+ struct scoped_entry_anominfo *s_e_anominfo =
+ &aclpb->aclpb_scoped_entry_anominfo;
+
+ loglevel = slapi_is_loglevel_set(SLAPI_LOG_ACL) ? SLAPI_LOG_ACL : SLAPI_LOG_ACLSUMMARY;
+
+ /* WE are only interested for READ/SEARCH */
+ if ( !(access & ( SLAPI_ACL_SEARCH | SLAPI_ACL_READ)) )
+ return -1;
+
+ /* If we are here means, the client is doing a anonymous read/search */
+ if ((a_profile = acl_anom_profile) == NULL ) {
+ return -1;
+ }
+
+ ANOM_LOCK_READ ();
+ /* Check the signature first */
+ if ( a_profile->anom_signature != acl_get_aclsignature () ) {
+ /* Need to regenrate the signature.
+ * Need a WRITE lock to generate the anom profile -
+ * which is obtained in acl__gen_anom_user_profile (). Since
+ * I don't have upgrade lock -- I have to do this way.
+ */
+ ANOM_UNLOCK_READ ();
+ aclanom_gen_anomProfile (DO_TAKE_ACLCACHE_READLOCK);
+ aclanom_get_suffix_info(e, aclpb );
+ ANOM_LOCK_READ ();
+ }
+
+ /* doing this early saves use a malloc/free/normalize cost */
+ if ( !a_profile->anom_numacls ) {
+ ANOM_UNLOCK_READ ();
+ return -1;
+ }
+
+ result = LDAP_INSUFFICIENT_ACCESS;
+
+ for ( k=0; k<s_e_anominfo->anom_e_nummatched; k++ ) {
+ short matched = 0;
+ short j = 0;
+
+ i = s_e_anominfo->anom_e_targetInfo[k];
+
+ /* Check for right */
+ if ( !(a_profile->anom_targetinfo[i].anom_access & access) )
+ continue;
+
+ /*
+ * XXX rbyrne Don't really understand the role of this
+ * but not causing any obvious bugs...get back to it.
+ */
+ tmatched++;
+
+ if ( attr == NULL ) {
+ result = LDAP_SUCCESS;
+ break;
+ }
+
+ destArray = a_profile->anom_targetinfo[i].anom_targetAttrs;
+ while ( destArray[j] ) {
+ if ( strcasecmp ( destArray[j], "*") == 0 ||
+ slapi_attr_type_cmp ( attr, destArray[j], 1 ) == 0 ) {
+ matched = 1;
+ break;
+ }
+ j++;
+ }
+
+ if ( a_profile->anom_targetinfo[i].anom_type & ACI_TARGET_ATTR_NOT )
+ result = matched ? LDAP_INSUFFICIENT_ACCESS : LDAP_SUCCESS;
+ else
+ result = matched ? LDAP_SUCCESS : LDAP_INSUFFICIENT_ACCESS;
+
+ if ( result == LDAP_SUCCESS )
+ break;
+ } /* for */
+
+ if ( slapi_is_loglevel_set(loglevel) ) {
+ char *ndn = NULL;
+ Slapi_Operation *op = NULL;
+
+ ndn = slapi_entry_get_ndn ( e ) ;
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+
+ if ( result == LDAP_SUCCESS) {
+ const char *aci_ndn;
+ aci_ndn = slapi_sdn_get_ndn (acl_anom_profile->anom_targetinfo[i].anom_target);
+
+ slapi_log_error(loglevel, plugin_name,
+ "conn=%d op=%d: Allow access on entry(%s).attr(%s) to anonymous: acidn=\"%s\"\n",
+ op->o_connid, op->o_opid,
+ escape_string_with_punctuation(ndn, ebuf),
+ attr ? attr:"NULL",
+ escape_string_with_punctuation(aci_ndn, ebuf));
+ } else {
+ slapi_log_error(loglevel, plugin_name,
+ "conn=%d op=%d: Deny access on entry(%s).attr(%s) to anonymous\n",
+ op->o_connid, op->o_opid,
+ escape_string_with_punctuation(ndn, ebuf), attr ? attr:"NULL" );
+ }
+ }
+
+ ANOM_UNLOCK_READ ();
+ if ( tmatched == 0)
+ return -1;
+ else
+ return result;
+
+}
+int
+aclanom_is_client_anonymous ( Slapi_PBlock *pb )
+{
+ char *clientDn;
+
+
+ slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &clientDn );
+ if (acl_anom_profile->anom_numacls &&
+ acl_anom_profile->anom_signature &&
+ (( NULL == clientDn) || (clientDn && *clientDn == '\0')) )
+ return 1;
+
+ return 0;
+}
+
diff --git a/ldap/servers/plugins/acl/acldllmain.c b/ldap/servers/plugins/acl/acldllmain.c
new file mode 100644
index 00000000..21ab60c4
--- /dev/null
+++ b/ldap/servers/plugins/acl/acldllmain.c
@@ -0,0 +1,128 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "acl.h"
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
+
+#ifdef LDAP_DEBUG
+#ifndef _WIN32
+#include <stdarg.h>
+#include <stdio.h>
+
+void LDAPDebug( int level, char* fmt, ... )
+{
+ static char debugBuf[1024];
+
+ if (module_ldap_debug && (*module_ldap_debug & level))
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ _snprintf (debugBuf, sizeof(debugBuf), fmt, ap);
+ va_end (ap);
+
+ OutputDebugString (debugBuf);
+ }
+}
+#endif
+#endif
+
+#ifndef _WIN32
+
+/* The 16-bit version of the RTL does not implement perror() */
+
+#include <stdio.h>
+
+void perror( const char *msg )
+{
+ char buf[128];
+ wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ;
+ OutputDebugString( buf );
+}
+
+#endif
diff --git a/ldap/servers/plugins/acl/acleffectiverights.c b/ldap/servers/plugins/acl/acleffectiverights.c
new file mode 100644
index 00000000..1e250e96
--- /dev/null
+++ b/ldap/servers/plugins/acl/acleffectiverights.c
@@ -0,0 +1,674 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2004 Netscape Communications Corporation
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "acl.h"
+
+static int
+_ger_g_permission_granted ( Slapi_PBlock *pb, Slapi_Entry *e, char **errbuf )
+{
+ char *proxydn = NULL;
+ Slapi_DN *requestor_sdn, *entry_sdn;
+ char *errtext = NULL;
+ int isroot;
+ int rc;
+
+ /*
+ * Theorically, we should check if the entry has "g"
+ * permission granted to the requestor. If granted,
+ * allows the effective rights on that entry and its
+ * attributes within the entry to be returned for
+ * ANY subject.
+ *
+ * "G" permission granting has not been implemented yet,
+ * the current release assumes that "g" permission be
+ * granted to root and owner of any entry.
+ */
+
+ /*
+ * The requestor may be either the bind dn or a proxy dn
+ */
+ acl_get_proxyauth_dn ( pb, &proxydn, &errtext );
+ if ( proxydn != NULL )
+ {
+ requestor_sdn = slapi_sdn_new_dn_passin ( proxydn );
+ }
+ else
+ {
+ requestor_sdn = &(pb->pb_op->o_sdn);
+ }
+ if ( slapi_sdn_get_dn (requestor_sdn) == NULL )
+ {
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_g_permission_granted: anonymous has no g permission\n" );
+ rc = LDAP_INSUFFICIENT_ACCESS;
+ goto bailout;
+ }
+ isroot = slapi_dn_isroot ( slapi_sdn_get_dn (requestor_sdn) );
+ if ( isroot )
+ {
+ /* Root has "g" permission on any entry */
+ rc = LDAP_SUCCESS;
+ goto bailout;
+ }
+
+ entry_sdn = slapi_entry_get_sdn ( e );
+ if ( entry_sdn == NULL || slapi_sdn_get_dn (entry_sdn) == NULL )
+ {
+ rc = LDAP_SUCCESS;
+ goto bailout;
+ }
+
+ if ( slapi_sdn_compare ( requestor_sdn, entry_sdn ) == 0 )
+ {
+ /* Owner has "g" permission on his own entry */
+ rc = LDAP_SUCCESS;
+ goto bailout;
+ }
+
+ aclutil_str_appened ( errbuf, "get-effective-rights: requestor has no g permission on the entry" );
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_g_permission_granted: %s\n", *errbuf);
+ rc = LDAP_INSUFFICIENT_ACCESS;
+
+bailout:
+ if ( proxydn )
+ {
+ /* The ownership of proxydn has passed to requestor_sdn */
+ slapi_sdn_free ( &requestor_sdn );
+ }
+ return rc;
+}
+
+static int
+_ger_parse_control ( Slapi_PBlock *pb, char **subjectndn, int *iscritical, char **errbuf )
+{
+ LDAPControl **requestcontrols;
+ struct berval *subjectber;
+ BerElement *ber;
+
+ if (NULL == subjectndn)
+ {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ *subjectndn = NULL;
+
+ /*
+ * Get the control
+ */
+ slapi_pblock_get ( pb, SLAPI_REQCONTROLS, (void *) &requestcontrols );
+ slapi_control_present ( requestcontrols,
+ LDAP_CONTROL_GET_EFFECTIVE_RIGHTS,
+ &subjectber,
+ iscritical );
+ if ( subjectber == NULL || subjectber->bv_val == NULL ||
+ subjectber->bv_len == 0 )
+ {
+ aclutil_str_appened ( errbuf, "get-effective-rights: missing subject" );
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ if ( strncasecmp ( "dn:", subjectber->bv_val, 3 ) == 0 )
+ {
+ /*
+ * This is a non-standard support to allow the subject being a plain
+ * or base64 encoding string. Hence users using -J option in
+ * ldapsearch don't have to do BER encoding for the subject.
+ */
+ *subjectndn = slapi_ch_malloc ( subjectber->bv_len + 1 );
+ strncpy ( *subjectndn, subjectber->bv_val, subjectber->bv_len );
+ *(*subjectndn + subjectber->bv_len) = '\0';
+ }
+ else
+ {
+ ber = ber_init (subjectber);
+ if ( ber == NULL )
+ {
+ aclutil_str_appened ( errbuf, "get-effective-rights: ber_init failed for the subject" );
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf );
+ return LDAP_OPERATIONS_ERROR;
+ }
+ /* "a" means to allocate storage as needed for octet string */
+ if ( ber_scanf (ber, "a", subjectndn) == LBER_ERROR )
+ {
+ aclutil_str_appened ( errbuf, "get-effective-rights: invalid ber tag in the subject" );
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf );
+ ber_free ( ber, 1 );
+ return LDAP_INVALID_SYNTAX;
+ }
+ ber_free ( ber, 1 );
+ }
+
+ /*
+ * The current implementation limits the subject to authorization ID
+ * (see section 9 of RFC 2829) only. It also only supports the "dnAuthzId"
+ * flavor, which looks like "dn:<DN>" where null <DN> is for anonymous.
+ */
+ if ( NULL == *subjectndn || strlen (*subjectndn) < 3 ||
+ strncasecmp ( "dn:", *subjectndn, 3 ) != 0 )
+ {
+ aclutil_str_appened ( errbuf, "get-effective-rights: subject is not dnAuthzId" );
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name, "%s\n", *errbuf );
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ strcpy ( *subjectndn, *subjectndn + 3 );
+ slapi_dn_normalize ( *subjectndn );
+ return LDAP_SUCCESS;
+}
+
+static void
+_ger_release_gerpb (
+ Slapi_PBlock **gerpb,
+ void **aclcb, /* original aclcb */
+ Slapi_PBlock *pb /* original pb */
+ )
+{
+ if ( *gerpb )
+ {
+ /* Return conn to pb */
+ slapi_pblock_set ( *gerpb, SLAPI_CONNECTION, NULL );
+ slapi_pblock_destroy ( *gerpb );
+ *gerpb = NULL;
+ }
+
+ /* Put the original aclcb back to pb */
+ if ( *aclcb )
+ {
+ Connection *conn = NULL;
+ slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn );
+ if (conn)
+ {
+ struct aclcb *geraclcb;
+ geraclcb = (struct aclcb *) acl_get_ext ( ACL_EXT_CONNECTION, conn );
+ acl_conn_ext_destructor ( geraclcb, NULL, NULL );
+ acl_set_ext ( ACL_EXT_CONNECTION, conn, *aclcb );
+ *aclcb = NULL;
+ }
+ }
+}
+
+static int
+_ger_new_gerpb (
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ const char *subjectndn,
+ Slapi_PBlock **gerpb,
+ void **aclcb, /* original aclcb */
+ char **errbuf
+ )
+{
+ Connection *conn;
+ struct acl_cblock *geraclcb;
+ Acl_PBlock *aclpb, *geraclpb;
+ Operation *op, *gerop;
+ int rc = LDAP_SUCCESS;
+
+ *aclcb = NULL;
+ *gerpb = slapi_pblock_new ();
+ if ( *gerpb == NULL )
+ {
+ rc = LDAP_NO_MEMORY;
+ goto bailout;
+ }
+
+ {
+ /* aclpb initialization needs the backend */
+ Slapi_Backend *be;
+ slapi_pblock_get ( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_set ( *gerpb, SLAPI_BACKEND, be );
+ }
+
+ {
+ int isroot = slapi_dn_isroot ( subjectndn );
+ slapi_pblock_set ( *gerpb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ }
+
+ /* Save requestor's aclcb and set subjectdn's one */
+ {
+ slapi_pblock_get ( pb, SLAPI_CONNECTION, &conn );
+ slapi_pblock_set ( *gerpb, SLAPI_CONNECTION, conn );
+
+ /* Can't share the conn->aclcb because of different context */
+ geraclcb = (struct acl_cblock *) acl_conn_ext_constructor ( NULL, NULL);
+ if ( geraclcb == NULL )
+ {
+ rc = LDAP_NO_MEMORY;
+ goto bailout;
+ }
+ slapi_sdn_set_ndn_byval ( geraclcb->aclcb_sdn, subjectndn );
+ *aclcb = acl_get_ext ( ACL_EXT_CONNECTION, conn );
+ acl_set_ext ( ACL_EXT_CONNECTION, conn, (void *) geraclcb );
+ }
+
+ {
+ gerop = operation_new ( OP_FLAG_INTERNAL );
+ if ( gerop == NULL )
+ {
+ rc = LDAP_NO_MEMORY;
+ goto bailout;
+ }
+ /*
+ * conn is a no-use parameter in the functions
+ * chained down from factory_create_extension
+ */
+ gerop->o_extension = factory_create_extension ( get_operation_object_type(), (void *)gerop, (void *)conn );
+ slapi_pblock_set ( *gerpb, SLAPI_OPERATION, gerop );
+ slapi_sdn_set_dn_byval ( &gerop->o_sdn, subjectndn );
+ geraclpb = acl_get_ext ( ACL_EXT_OPERATION, (void *)gerop);
+ acl_init_aclpb ( *gerpb, geraclpb, subjectndn, 0 );
+ geraclpb->aclpb_res_type |= ACLPB_EFFECTIVE_RIGHTS;
+ }
+
+
+bailout:
+ if ( rc != LDAP_SUCCESS )
+ {
+ _ger_release_gerpb ( gerpb, aclcb, pb );
+ }
+
+ return rc;
+}
+
+/*
+ * Callers should have already allocated *gerstr to hold at least
+ * "entryLevelRights: adnvxxx\n".
+ */
+unsigned long
+_ger_get_entry_rights (
+ Slapi_PBlock *gerpb,
+ Slapi_Entry *e,
+ const char *subjectndn,
+ char *gerstr,
+ char **errbuf
+ )
+{
+ unsigned long entryrights = 0;
+ Slapi_RDN *rdn = NULL;
+ const char *rdnstr = NULL;
+ char *equalsign = NULL;
+ char *rdntype = NULL;
+
+ strcpy ( gerstr, "entryLevelRights: " );
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_entry_rights: SLAPI_ACL_READ\n" );
+ if (acl_access_allowed(gerpb, e, "*", NULL, SLAPI_ACL_READ) == LDAP_SUCCESS)
+ {
+ /* v - view e */
+ entryrights |= SLAPI_ACL_READ;
+ strcat (gerstr, "v");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_entry_rights: SLAPI_ACL_ADD\n" );
+ if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_ADD) == LDAP_SUCCESS)
+ {
+ /* a - add child entry below e */
+ entryrights |= SLAPI_ACL_ADD;
+ strcat (gerstr, "a");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_entry_rights: SLAPI_ACL_DELETE\n" );
+ if (acl_access_allowed(gerpb, e, NULL, NULL, SLAPI_ACL_DELETE) == LDAP_SUCCESS)
+ {
+ /* d - delete e */
+ entryrights |= SLAPI_ACL_DELETE;
+ strcat (gerstr, "d");
+ }
+ /*
+ * Some limitation/simplification applied here:
+ * - The modrdn right requires the rights to delete the old rdn and
+ * the new one. However we have no knowledge of what the new rdn
+ * is going to be.
+ * - In multi-valued RDN case, we check the right on
+ * the first rdn type only for now.
+ */
+ rdn = slapi_rdn_new_dn ( slapi_entry_get_ndn (e) );
+ rdnstr = slapi_rdn_get_rdn ( rdn );
+ if ( NULL != (equalsign = strchr ( rdnstr, '=' )) )
+ {
+ rdntype = slapi_ch_malloc ( equalsign-rdnstr+1 );
+ strncpy ( rdntype, rdnstr, equalsign-rdnstr );
+ rdntype [ equalsign-rdnstr ] = '\0';
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_entry_rights: SLAPI_ACL_WRITE_DEL & _ADD %s\n", rdntype );
+ if (acl_access_allowed(gerpb, e, rdntype, NULL,
+ ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS &&
+ acl_access_allowed(gerpb, e, rdntype, NULL,
+ ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS)
+ {
+ /* n - rename e */
+ entryrights |= SLAPI_ACL_WRITE;
+ strcat (gerstr, "n");
+ }
+ slapi_ch_free ( (void**) &rdntype );
+ }
+ slapi_rdn_free ( &rdn );
+
+done:
+ if ( entryrights == 0 )
+ {
+ strcat (gerstr, "none");
+ }
+
+ strcat (gerstr, "\n");
+
+ return entryrights;
+}
+
+/*
+ * *gerstr should point to a heap buffer since it may need
+ * to expand dynamically.
+ */
+unsigned long
+_ger_get_attr_rights (
+ Slapi_PBlock *gerpb,
+ Slapi_Entry *e,
+ const char *subjectndn,
+ char *type,
+ char **gerstr,
+ int *gerstrsize,
+ int isfirstattr,
+ char **errbuf
+ )
+{
+ unsigned long attrrights = 0;
+
+ /* Enough space for " $type:rwoscxx" ? */
+ if ( (*gerstrsize - strlen(*gerstr)) < (strlen(type) + 16) )
+ {
+ /* slapi_ch_realloc() exits if realloc() failed */
+ *gerstrsize += 256;
+ *gerstr = slapi_ch_realloc ( *gerstr, *gerstrsize );
+ }
+ if (!isfirstattr)
+ {
+ strcat ( *gerstr, ", " );
+ }
+ sprintf ( *gerstr + strlen(*gerstr), "%s:", type );
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_READ %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_READ) == LDAP_SUCCESS)
+ {
+ /* r - read the values of type */
+ attrrights |= SLAPI_ACL_READ;
+ strcat (*gerstr, "r");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_SEARCH %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_SEARCH) == LDAP_SUCCESS)
+ {
+ /* s - search the values of type */
+ attrrights |= SLAPI_ACL_SEARCH;
+ strcat (*gerstr, "s");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_COMPARE %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, SLAPI_ACL_COMPARE) == LDAP_SUCCESS)
+ {
+ /* c - compare the values of type */
+ attrrights |= SLAPI_ACL_COMPARE;
+ strcat (*gerstr, "c");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_WRITE_ADD %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS)
+ {
+ /* w - add the values of type */
+ attrrights |= ACLPB_SLAPI_ACL_WRITE_ADD;
+ strcat (*gerstr, "w");
+ }
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "_ger_get_attr_rights: SLAPI_ACL_WRITE_DEL %s\n", type );
+ if (acl_access_allowed(gerpb, e, type, NULL, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS)
+ {
+ /* o - delete the values of type */
+ attrrights |= ACLPB_SLAPI_ACL_WRITE_DEL;
+ strcat (*gerstr, "o");
+ }
+ /* If subjectdn has no general write right, check for self write */
+ if ( 0 == (attrrights & (ACLPB_SLAPI_ACL_WRITE_DEL | ACLPB_SLAPI_ACL_WRITE_ADD)) )
+ {
+ struct berval val;
+
+ val.bv_val = (char *)subjectndn;
+ val.bv_len = strlen (subjectndn);
+
+ if (acl_access_allowed(gerpb, e, type, &val, ACLPB_SLAPI_ACL_WRITE_ADD) == LDAP_SUCCESS)
+ {
+ /* W - add self to the attribute */
+ attrrights |= ACLPB_SLAPI_ACL_WRITE_ADD;
+ strcat (*gerstr, "W");
+ }
+ if (acl_access_allowed(gerpb, e, type, &val, ACLPB_SLAPI_ACL_WRITE_DEL) == LDAP_SUCCESS)
+ {
+ /* O - delete self from the attribute */
+ attrrights |= ACLPB_SLAPI_ACL_WRITE_DEL;
+ strcat (*gerstr, "O");
+ }
+ }
+
+ if ( attrrights == 0 )
+ {
+ strcat (*gerstr, "none");
+ }
+
+ return attrrights;
+}
+
+void
+_ger_get_attrs_rights (
+ Slapi_PBlock *gerpb,
+ Slapi_Entry *e,
+ const char *subjectndn,
+ char **attrs,
+ char **gerstr,
+ int *gerstrsize,
+ char **errbuf
+ )
+{
+ int isfirstattr = 1;
+
+ /* gerstr was initially allocated with enough space for one more line */
+ strcat ( *gerstr, "attributeLevelRights: " );
+
+ if (attrs && *attrs)
+ {
+ int i;
+ for ( i = 0; attrs[i]; i++ )
+ {
+ _ger_get_attr_rights ( gerpb, e, subjectndn, attrs[i], gerstr, gerstrsize, isfirstattr, errbuf );
+ isfirstattr = 0;
+ }
+ }
+ else
+ {
+ Slapi_Attr *prevattr = NULL, *attr;
+ char *type;
+
+ while ( slapi_entry_next_attr ( e, prevattr, &attr ) == 0 )
+ {
+ if ( ! slapi_attr_flag_is_set (attr, SLAPI_ATTR_FLAG_OPATTR) )
+ {
+ slapi_attr_get_type ( attr, &type );
+ _ger_get_attr_rights ( gerpb, e, subjectndn, type, gerstr, gerstrsize, isfirstattr, errbuf );
+ isfirstattr = 0;
+ }
+ prevattr = attr;
+ }
+ }
+
+ if ( isfirstattr )
+ {
+ /* not a single attribute was retrived or specified */
+ strcat ( *gerstr, "*:none" );
+ }
+ return;
+}
+
+/*
+ * controlType = LDAP_CONTROL_GET_EFFECTIVE_RIGHTS;
+ * criticality = n/a;
+ * controlValue = OCTET STRING of BER encoding of the SEQUENCE of
+ * ENUMERATED LDAP code
+ */
+void
+_ger_set_response_control (
+ Slapi_PBlock *pb,
+ int iscritical,
+ int rc
+ )
+{
+ LDAPControl **resultctrls = NULL;
+ LDAPControl gerrespctrl;
+ BerElement *ber = NULL;
+ struct berval *berval = NULL;
+ int found = 0;
+ int i;
+
+ if ( (ber = der_alloc ()) == NULL )
+ {
+ goto bailout;
+ }
+
+ /* begin sequence, enumeration, end sequence */
+ ber_printf ( ber, "{e}", rc );
+ if ( ber_flatten ( ber, &berval ) != LDAP_SUCCESS )
+ {
+ goto bailout;
+ }
+ gerrespctrl.ldctl_oid = LDAP_CONTROL_GET_EFFECTIVE_RIGHTS;
+ gerrespctrl.ldctl_iscritical = iscritical;
+ gerrespctrl.ldctl_value.bv_val = berval->bv_val;
+ gerrespctrl.ldctl_value.bv_len = berval->bv_len;
+
+ slapi_pblock_get ( pb, SLAPI_RESCONTROLS, &resultctrls );
+ for (i = 0; resultctrls && resultctrls[i]; i++)
+ {
+ if (strcmp(resultctrls[i]->ldctl_oid, LDAP_CONTROL_GET_EFFECTIVE_RIGHTS) == 0)
+ {
+ /*
+ * We get here if search returns more than one entry
+ * and this is not the first entry.
+ */
+ ldap_control_free ( resultctrls[i] );
+ resultctrls[i] = slapi_dup_control (&gerrespctrl);
+ found = 1;
+ break;
+ }
+ }
+
+ if ( !found )
+ {
+ /* slapi_pblock_set() will dup the control */
+ slapi_pblock_set ( pb, SLAPI_ADD_RESCONTROL, &gerrespctrl );
+ }
+
+bailout:
+ ber_free ( ber, 1 ); /* ber_free() checks for NULL param */
+ ber_bvfree ( berval ); /* ber_bvfree() checks for NULL param */
+}
+
+int
+acl_get_effective_rights (
+ Slapi_PBlock *pb,
+ Slapi_Entry *e, /* target entry */
+ char **attrs, /* Attribute of the entry */
+ struct berval *val, /* value of attr. NOT USED */
+ int access, /* requested access rights */
+ char **errbuf
+ )
+{
+ Slapi_PBlock *gerpb = NULL;
+ void *aclcb = NULL;
+ char *subjectndn = NULL;
+ char *gerstr = NULL;
+ int gerstrsize = 1024;
+ unsigned long entryrights;
+ int iscritical = 1;
+ int rc;
+
+ *errbuf = '\0';
+ gerstr = slapi_ch_malloc ( gerstrsize );
+
+ /*
+ * Get the subject
+ */
+ rc = _ger_parse_control (pb, &subjectndn, &iscritical, errbuf );
+ if ( rc != LDAP_SUCCESS )
+ {
+ goto bailout;
+ }
+
+ /*
+ * The requestor should have g permission on the entry
+ * to get the effective rights.
+ */
+ rc = _ger_g_permission_granted (pb, e, errbuf);
+ if ( rc != LDAP_SUCCESS )
+ {
+ goto bailout;
+ }
+
+ /*
+ * Construct a new pb
+ */
+ rc = _ger_new_gerpb ( pb, e, subjectndn, &gerpb, &aclcb, errbuf );
+ if ( rc != LDAP_SUCCESS )
+ {
+ goto bailout;
+ }
+
+ /* Get entry level effective rights */
+ entryrights = _ger_get_entry_rights ( gerpb, e, subjectndn, gerstr, errbuf );
+
+ /*
+ * Attribute level effective rights may not be NULL
+ * even if entry level's is.
+ */
+ _ger_get_attrs_rights ( gerpb, e, subjectndn, attrs, &gerstr, &gerstrsize, errbuf );
+
+bailout:
+ /*
+ * Now construct the response control
+ */
+ _ger_set_response_control ( pb, iscritical, rc );
+
+ if ( rc != LDAP_SUCCESS )
+ {
+ sprintf ( gerstr, "entryLevelRights: %d\nattributeLevelRights: *:%d", rc, rc );
+ }
+
+ slapi_log_error (SLAPI_LOG_ACLSUMMARY, plugin_name,
+ "###### Effective Rights on Entry (%s) for Subject (%s) ######\n",
+ slapi_entry_get_ndn (e), subjectndn);
+ slapi_log_error (SLAPI_LOG_ACLSUMMARY, plugin_name, "%s\n", gerstr);
+
+ /* Restore pb */
+ _ger_release_gerpb ( &gerpb, &aclcb, pb );
+
+ /*
+ * General plugin uses SLAPI_RESULT_TEXT for error text. Here
+ * SLAPI_PB_RESULT_TEXT is exclusively shared with add, dse and schema.
+ * slapi_pblock_set() will free any previous data, and
+ * pblock_done() will free SLAPI_PB_RESULT_TEXT.
+ */
+ slapi_pblock_set (pb, SLAPI_PB_RESULT_TEXT, gerstr);
+
+ if ( !iscritical )
+ {
+ /*
+ * If return code is not LDAP_SUCCESS, the server would
+ * abort sending the data of the entry to the client.
+ */
+ rc = LDAP_SUCCESS;
+ }
+
+ slapi_ch_free ( (void **) &subjectndn );
+ slapi_ch_free ( (void **) &gerstr );
+ return rc;
+}
diff --git a/ldap/servers/plugins/acl/aclgroup.c b/ldap/servers/plugins/acl/aclgroup.c
new file mode 100644
index 00000000..4cd7039f
--- /dev/null
+++ b/ldap/servers/plugins/acl/aclgroup.c
@@ -0,0 +1,442 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "acl.h"
+
+/***************************************************************************
+ *
+ * This module deals with the global user group cache.
+ *
+ * A LRU queue mechanism is used to maintain the groups the user currently in.
+ * At this moment the QUEUE is invalidated if there is a group change. A better
+ * way would have been to invalidate only the one which are effected.
+ * However to accomplish that will require quite a bit of work which may not be
+ * cost-efftive.
+ **************************************************************************/
+static aclGroupCache *aclUserGroups;
+#define ACL_MAXCACHE_USERGROUPS 200
+
+#define ACLG_LOCK_GROUPCACHE_READ() PR_RWLock_Rlock ( aclUserGroups->aclg_rwlock )
+#define ACLG_LOCK_GROUPCACHE_WRITE() PR_RWLock_Wlock ( aclUserGroups->aclg_rwlock )
+#define ACLG_ULOCK_GROUPCACHE_WRITE() PR_RWLock_Unlock ( aclUserGroups->aclg_rwlock )
+#define ACLG_ULOCK_GROUPCACHE_READ() PR_RWLock_Unlock ( aclUserGroups->aclg_rwlock )
+
+
+static void __aclg__delete_userGroup ( aclUserGroup *u_group );
+
+
+int
+aclgroup_init ()
+{
+
+ aclUserGroups = ( aclGroupCache * ) slapi_ch_calloc (1, sizeof ( aclGroupCache ) );
+ if ( NULL == (aclUserGroups->aclg_rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,"Group LOCK"))) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name, "Unable to allocate RWLOCK for group cache\n");
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * aclg_init_userGroup
+ *
+ * Go thru the Global Group CACHE and see if we have group information for
+ * the user. The user's group cache is invalidated when a group is modified
+ * (in which case ALL usergroups are invalidated) or when the user's entry
+ * is modified in which case just his is invalidated.
+ *
+ * We need to scan the whole cache looking for a valid entry that matches
+ * this user. If we find invalid entries along the way.
+ *
+ * If we don't have anything it's fine. we will allocate a space when we
+ * need it i.e during the group evaluation.
+ *
+ * Inputs:
+ * struct acl_pblock - ACL private block
+ * char *dn - the client's dn
+ * int got_lock - 1: already obtained WRITE Lock
+ * - 0: Nope; get one
+ * Returns:
+ * None.
+ */
+
+void
+aclg_init_userGroup ( struct acl_pblock *aclpb, const char *n_dn , int got_lock )
+{
+ aclUserGroup *u_group = NULL;
+ aclUserGroup *next_ugroup = NULL;
+ aclUserGroup *p_group, *n_group;
+ int found = 0;
+
+ /* Check for Anonymous user */
+ if ( n_dn && *n_dn == '\0') return;
+
+ if ( !got_lock ) ACLG_LOCK_GROUPCACHE_WRITE ();
+ u_group = aclUserGroups->aclg_first;
+ aclpb->aclpb_groupinfo = NULL;
+
+ while ( u_group != NULL ) {
+ next_ugroup = u_group->aclug_next;
+ if ( aclUserGroups->aclg_signature != u_group->aclug_signature) {
+ /*
+ * This means that this usergroup is no longer valid and
+ * this operation so delete this one if no one is using it.
+ */
+
+ if ( !u_group->aclug_refcnt ) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "In traversal group deallocation\n", 0,0,0 );
+ __aclg__delete_userGroup (u_group);
+ }
+ } else {
+
+ /*
+ * Here, u_group is valid--if it matches then take it.
+ */
+ if ( slapi_utf8casecmp((ACLUCHP)u_group->aclug_ndn,
+ (ACLUCHP)n_dn ) == 0 ) {
+ u_group->aclug_refcnt++;
+ aclpb->aclpb_groupinfo = u_group;
+ found = 1;
+ break;
+ }
+ }
+ u_group = next_ugroup;
+ }
+
+ /* Move the new one to the top of the queue */
+ if ( found ) {
+ p_group = u_group->aclug_prev;
+ n_group = u_group->aclug_next;
+
+ if ( p_group ) {
+ aclUserGroup *t_group = NULL;
+
+ p_group->aclug_next = n_group;
+ if ( n_group ) n_group->aclug_prev = p_group;
+
+ t_group = aclUserGroups->aclg_first;
+ if ( t_group ) t_group->aclug_prev = u_group;
+
+ u_group->aclug_prev = NULL;
+ u_group->aclug_next = t_group;
+ aclUserGroups->aclg_first = u_group;
+
+ if ( u_group == aclUserGroups->aclg_last )
+ aclUserGroups->aclg_last = p_group;
+ }
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name, "acl_init_userGroup: found in cache for dn:%s\n", n_dn,0,0);
+ }
+ if (!got_lock ) ACLG_ULOCK_GROUPCACHE_WRITE ();
+}
+
+
+/*
+ *
+ * aclg_reset_userGroup
+ * Reset the reference count to the user's group.
+ *
+ * Inputs:
+ * struct acl_pblock -- The acl private block.
+ * Returns:
+ * None.
+ *
+ * Note: A WRITE Lock on the GroupCache is obtained during the change:
+ */
+void
+aclg_reset_userGroup ( struct acl_pblock *aclpb )
+{
+
+ aclUserGroup *u_group;
+
+ ACLG_LOCK_GROUPCACHE_WRITE();
+
+ if ( (u_group = aclpb->aclpb_groupinfo) != NULL ) {
+ u_group->aclug_refcnt--;
+
+ /* If I am the last one but I was using an invalid group cache
+ ** in the meantime, it is time now to get rid of it so that we will
+ ** not have duplicate cache.
+ */
+ if ( !u_group->aclug_refcnt &&
+ ( aclUserGroups->aclg_signature != u_group->aclug_signature )) {
+ __aclg__delete_userGroup ( u_group );
+ }
+ }
+ ACLG_ULOCK_GROUPCACHE_WRITE();
+ aclpb->aclpb_groupinfo = NULL;
+}
+
+/*
+ * Find a user group in the global cache, returning a pointer to it,
+ * ensuring that the refcnt has been bumped to stop
+ * another thread freeing it underneath us.
+*/
+
+aclUserGroup*
+aclg_find_userGroup(char *n_dn)
+{
+ aclUserGroup *u_group = NULL;
+ int i;
+
+ /* Check for Anonymous user */
+ if ( n_dn && *n_dn == '\0') return (NULL) ;
+
+ ACLG_LOCK_GROUPCACHE_READ ();
+ u_group = aclUserGroups->aclg_first;
+
+ for ( i=0; i < aclUserGroups->aclg_num_userGroups; i++ ) {
+ if ( aclUserGroups->aclg_signature == u_group->aclug_signature &&
+ slapi_utf8casecmp((ACLUCHP)u_group->aclug_ndn,
+ (ACLUCHP)n_dn ) == 0 ) {
+ aclg_reader_incr_ugroup_refcnt(u_group);
+ break;
+ }
+ u_group = u_group->aclug_next;
+ }
+
+ ACLG_ULOCK_GROUPCACHE_READ ();
+ return(u_group);
+}
+
+/*
+ * Mark a usergroup for removal from the usergroup cache.
+ * It will be removed by the first operation traversing the cache
+ * that finds it.
+*/
+void
+aclg_markUgroupForRemoval ( aclUserGroup* u_group) {
+
+ ACLG_LOCK_GROUPCACHE_WRITE ();
+ aclg_regen_ugroup_signature(u_group);
+ u_group->aclug_refcnt--;
+ ACLG_ULOCK_GROUPCACHE_WRITE ();
+}
+
+/*
+ *
+ * aclg_get_usersGroup
+ *
+ * If we already have a the group info then we are done. If we
+ * don't, then allocate a new one and attach it.
+ *
+ * Inputs:
+ * struct acl_pblock -- The acl private block.
+ * char *n_dn - normalized client's DN
+ *
+ * Returns:
+ * aclUserGroup - The Group info block.
+ *
+ */
+aclUserGroup *
+aclg_get_usersGroup ( struct acl_pblock *aclpb , char *n_dn)
+{
+
+ aclUserGroup *u_group, *f_group;
+
+ if ( aclpb && aclpb->aclpb_groupinfo )
+ return aclpb->aclpb_groupinfo;
+
+ ACLG_LOCK_GROUPCACHE_WRITE();
+
+ /* try it one more time. We might have one in the meantime */
+ aclg_init_userGroup (aclpb, n_dn , 1 /* got the lock */);
+ if ( aclpb && aclpb->aclpb_groupinfo ) {
+ ACLG_ULOCK_GROUPCACHE_WRITE();
+ return aclpb->aclpb_groupinfo;
+ }
+
+ /*
+ * It is possible at this point that we already have a group cache for the user
+ * but is is invalid. We can't use it anayway. So, we march along and allocate a new one.
+ * That's fine as the invalid one will be deallocated when done.
+ */
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "ALLOCATING GROUP FOR:%s\n", n_dn,0,0 );
+ u_group = ( aclUserGroup * ) slapi_ch_calloc ( 1, sizeof ( aclUserGroup ) );
+
+ u_group->aclug_refcnt = 1;
+ if ( (u_group->aclug_refcnt_mutex = PR_NewLock()) == NULL ) {
+ slapi_ch_free((void **)&u_group);
+ ACLG_ULOCK_GROUPCACHE_WRITE();
+ return(NULL);
+ }
+
+ u_group->aclug_member_groups = (char **)
+ slapi_ch_calloc ( 1,
+ (ACLUG_INCR_GROUPS_LIST * sizeof (char *)));
+ u_group->aclug_member_group_size = ACLUG_INCR_GROUPS_LIST;
+ u_group->aclug_numof_member_group = 0;
+
+ u_group->aclug_notmember_groups = (char **)
+ slapi_ch_calloc ( 1,
+ (ACLUG_INCR_GROUPS_LIST * sizeof (char *)));
+ u_group->aclug_notmember_group_size = ACLUG_INCR_GROUPS_LIST;
+ u_group->aclug_numof_notmember_group = 0;
+
+ u_group->aclug_ndn = slapi_ch_strdup ( n_dn ) ;
+
+ u_group->aclug_signature = aclUserGroups->aclg_signature;
+
+ /* Do we have alreday the max number. If we have then delete the last one */
+ if ( aclUserGroups->aclg_num_userGroups >= ACL_MAXCACHE_USERGROUPS - 5 ) {
+ aclUserGroup *d_group;
+
+ /* We need to traverse thru backwards and delete the one with a refcnt = 0 */
+ d_group = aclUserGroups->aclg_last;
+ while ( d_group ) {
+ if ( !d_group->aclug_refcnt ) {
+ __aclg__delete_userGroup ( d_group );
+ break;
+ } else {
+ d_group = d_group->aclug_prev;
+ }
+ }
+
+ /* If we didn't find any, which should be never,
+ ** we have 5 more tries to do it.
+ */
+ }
+ f_group = aclUserGroups->aclg_first;
+ u_group->aclug_next = f_group;
+ if ( f_group ) f_group->aclug_prev = u_group;
+
+ aclUserGroups->aclg_first = u_group;
+ if ( aclUserGroups->aclg_last == NULL )
+ aclUserGroups->aclg_last = u_group;
+
+ aclUserGroups->aclg_num_userGroups++;
+
+ /* Put it in the queue */
+ ACLG_ULOCK_GROUPCACHE_WRITE();
+
+ /* Now hang on to it */
+ aclpb->aclpb_groupinfo = u_group;
+ return u_group;
+}
+
+/*
+ *
+ * __aclg__delete_userGroup
+ *
+ * Delete the User's Group cache.
+ *
+ * Inputs:
+ * aclUserGroup - remove this one
+ * Returns:
+ * None.
+ *
+ * Note: A WRITE Lock on the GroupCache is obtained by the caller
+ */
+static void
+__aclg__delete_userGroup ( aclUserGroup *u_group )
+{
+
+ aclUserGroup *next_group, *prev_group;
+ int i;
+
+ if ( !u_group ) return;
+
+ prev_group = u_group->aclug_prev;
+ next_group = u_group->aclug_next;
+
+ /*
+ * At this point we must have a 0 refcnt or else we are in a bad shape.
+ * If we don't have one then at least remove the user's dn so that it will
+ * be in a condemned state and later deleted.
+ */
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "DEALLOCATING GROUP FOR:%s\n", u_group->aclug_ndn,0,0 );
+
+ slapi_ch_free ( (void **) &u_group->aclug_ndn );
+
+ PR_DestroyLock(u_group->aclug_refcnt_mutex);
+
+ /* Remove the member GROUPS */
+ for (i=0; i < u_group->aclug_numof_member_group; i++ )
+ slapi_ch_free ( (void **) &u_group->aclug_member_groups[i] );
+ slapi_ch_free ( (void **) &u_group->aclug_member_groups );
+
+ /* Remove the NOT member GROUPS */
+ for (i=0; i < u_group->aclug_numof_notmember_group; i++ )
+ slapi_ch_free ( (void **) &u_group->aclug_notmember_groups[i] );
+ slapi_ch_free ( (void **) &u_group->aclug_notmember_groups );
+
+ slapi_ch_free ( (void **) &u_group );
+
+ if ( prev_group == NULL && next_group == NULL ) {
+ aclUserGroups->aclg_first = NULL;
+ aclUserGroups->aclg_last = NULL;
+ } else if ( prev_group == NULL ) {
+ next_group->aclug_prev = NULL;
+ aclUserGroups->aclg_first = next_group;
+ } else {
+ prev_group->aclug_next = next_group;
+ if ( next_group )
+ next_group->aclug_prev = prev_group;
+ else
+ aclUserGroups->aclg_last = prev_group;
+ }
+ aclUserGroups->aclg_num_userGroups--;
+}
+
+void
+aclg_regen_group_signature( )
+{
+ aclUserGroups->aclg_signature = aclutil_gen_signature ( aclUserGroups->aclg_signature );
+}
+
+void
+aclg_regen_ugroup_signature( aclUserGroup *ugroup)
+{
+ ugroup->aclug_signature =
+ aclutil_gen_signature ( ugroup->aclug_signature );
+}
+
+void
+aclg_lock_groupCache ( int type /* 1 for reader and 2 for writer */)
+{
+
+ if (type == 1 )
+ ACLG_LOCK_GROUPCACHE_READ();
+ else
+ ACLG_LOCK_GROUPCACHE_WRITE();
+}
+
+void
+aclg_unlock_groupCache ( int type /* 1 for reader and 2 for writer */)
+{
+
+ if (type == 1 )
+ ACLG_ULOCK_GROUPCACHE_READ();
+ else
+ ACLG_ULOCK_GROUPCACHE_WRITE();
+}
+
+
+/*
+ * If you have the write lock on the group cache, you can
+ * increment the refcnt without taking the mutex.
+ * If you just have the reader lock on the refcnt then you need to
+ * take the mutex on the refcnt to increment it--which is what this routine is
+ * for.
+ *
+*/
+
+void
+aclg_reader_incr_ugroup_refcnt(aclUserGroup* u_group) {
+
+ PR_Lock(u_group->aclug_refcnt_mutex);
+ u_group->aclug_refcnt++;
+ PR_Unlock(u_group->aclug_refcnt_mutex);
+}
+
+/* You need the usergroups read lock to call this routine*/
+int
+aclg_numof_usergroups(void) {
+
+ return(aclUserGroups->aclg_num_userGroups);
+}
+
diff --git a/ldap/servers/plugins/acl/aclinit.c b/ldap/servers/plugins/acl/aclinit.c
new file mode 100644
index 00000000..21e54337
--- /dev/null
+++ b/ldap/servers/plugins/acl/aclinit.c
@@ -0,0 +1,537 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "acl.h"
+
+static int __aclinit__RegisterLases(void);
+static int __aclinit__RegisterAttributes(void);
+static int __aclinit_handler(Slapi_Entry *e, void *callback_data);
+
+/***************************************************************************
+*
+* aclinit_main()
+* Main routine which is called at the server boot up time.
+*
+* 1) Reads all the ACI entries from the database and creates
+* the ACL list.
+* 2) Registers all the LASes and the GetAttrs supported by the DS.
+* 3) Generates anonymous profiles.
+* 4) Registers proxy control
+* 5) Creates aclpb pool
+*
+* Input:
+* None.
+*
+* Returns:
+* 0 -- no error
+* 1 -- Error
+*
+* Error Handling:
+* If any error found during the ACL generation, error is logged.
+*
+**************************************************************************/
+static int acl_initialized = 0;
+int
+aclinit_main()
+{
+ char *cookie = NULL;
+ Slapi_PBlock *pb;
+ int rv;
+ Slapi_DN *sdn;
+ void *node;
+
+ if (acl_initialized) {
+ /* There is no need to do anything more */
+ return 0;
+ }
+
+ /* Initialize the LIBACCESS ACL library */
+ if (ACL_Init() != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "ACL Library Initialization failed\n",0,0,0);
+ return 1;
+ }
+
+ /* register all the LASes supported by the DS */
+ if (ACL_ERR == __aclinit__RegisterLases()) {
+ /* Error is already logged */
+ return 1;
+ }
+
+ /* Register all the Attrs */
+ if (ACL_ERR == __aclinit__RegisterAttributes()) {
+ /* Error is already logged */
+ return 1;
+ }
+
+ /*
+ * Register to get backend state changes so we can add/remove
+ * acis from backends that come up and go down.
+ */
+
+ slapi_register_backend_state_change((void *) NULL, acl_be_state_change_fnc);
+
+
+ /* register the extensions */
+ /* ONREPL Moved to the acl_init function because extensions
+ need to be registered before any operations are issued
+ if ( 0 != acl_init_ext() ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to initialize the extensions\n");
+ return 1;
+ } */
+
+ /* create the mutex array */
+ if ( 0 != aclext_alloc_lockarray ( ) ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to create the mutext array\n");
+ return 1;
+ }
+
+ /* Allocate the pool */
+ if ( 0 != acl_create_aclpb_pool () ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to create the acl private pool\n");
+ return 1;
+ }
+
+ /*
+ * Now read all the ACLs from all the backends and put it
+ * in a list
+ */
+ /* initialize the ACLLIST sub-system */
+ if ( 0 != (rv = acllist_init ( ))) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to initialize the plugin:%d\n", rv );
+ return 1;
+ }
+
+ /* Initialize the anonymous profile i.e., generate it */
+ rv = aclanom_init ();
+
+ pb = slapi_pblock_new();
+
+ /*
+ * search for the aci_attr_type attributes of all entries.
+ *
+ * slapi_get_fist_suffix() and slapi_get_next_suffix() do not return the
+ * rootdse entry so we search for acis in there explicitly here.
+ */
+
+ sdn = slapi_sdn_new_dn_byval("");
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Searching for all acis(scope base) at suffix ''\n");
+ aclinit_search_and_update_aci ( 0, /* thisbeonly */
+ sdn, /* base */
+ NULL, /* be name*/
+ LDAP_SCOPE_BASE, ACL_ADD_ACIS,
+ DO_TAKE_ACLCACHE_WRITELOCK);
+ slapi_sdn_free(&sdn);
+
+ sdn = slapi_get_first_suffix( &node, 1 );
+ while (sdn)
+ {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Searching for all acis(scope subtree) at suffix '%s'\n",
+ slapi_sdn_get_dn(sdn) );
+ aclinit_search_and_update_aci ( 0, /* thisbeonly */
+ sdn, /* base */
+ NULL, /* be name*/
+ LDAP_SCOPE_SUBTREE, ACL_ADD_ACIS,
+ DO_TAKE_ACLCACHE_WRITELOCK);
+ sdn = slapi_get_next_suffix( &node, 1 );
+ }
+
+ /* Initialize it. */
+ acl_initialized = 1;
+
+ /* generate the signatures */
+ acl_set_aclsignature ( aclutil_gen_signature ( 100 ) );
+
+ /* Initialize the user-group cache */
+ rv = aclgroup_init ( );
+
+ aclanom_gen_anomProfile (DO_TAKE_ACLCACHE_READLOCK);
+
+ /* Register both of the proxied authorization controls (version 1 and 2) */
+ slapi_register_supported_control( LDAP_CONTROL_PROXYAUTH,
+ SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE
+ | SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE
+ | SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN
+ | SLAPI_OPERATION_EXTENDED );
+ slapi_register_supported_control( LDAP_CONTROL_PROXIEDAUTH,
+ SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE
+ | SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE
+ | SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN
+ | SLAPI_OPERATION_EXTENDED );
+
+ slapi_pblock_destroy ( pb );
+ return 0;
+}
+/*
+ * This routine is the one that scans for acis and either adds them
+ * to the internal cache (op==ACL_ADD_ACIS) or deletes them
+ * (op==ACL_REMOVE_ACIS).
+ *
+ * If thisbeonly is 0 the search
+ * is conducted on the base with the specifed scope and be_name is ignored.
+ * This is used at startup time where we iterate over all suffixes, searching
+ * for all the acis in the DIT to load the ACL cache.
+ *
+ * If thisbeonly is 1 then then a be_name must be specified.
+ * In this case we will search in that backend ONLY.
+ * This is used in the case where a backend is turned on and off--in this
+ * case we only want to add/remove the acis in that particular backend and
+ * not for example in any backends below that one.
+*/
+
+int
+aclinit_search_and_update_aci ( int thisbeonly, const Slapi_DN *base,
+ char *be_name, int scope, int op,
+ acl_lock_flag_t lock_flag )
+{
+ char *attrs[2] = { "aci", NULL };
+ /* Tell __aclinit_handler whether it's an add or a delete */
+ int any_error = op;
+ Slapi_PBlock *aPb;
+ LDAPControl **ctrls=NULL;
+ int retval;
+ struct berval *bval;
+ aclinit_handler_callback_data_t call_back_data;
+
+ PR_ASSERT( lock_flag == DONT_TAKE_ACLCACHE_WRITELOCK ||
+ lock_flag == DO_TAKE_ACLCACHE_WRITELOCK);
+
+ if ( thisbeonly && be_name == NULL) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Error: This be_name must be specified.\n", 0, 0, 0);
+ return -1;
+ }
+
+
+ /*
+ * We need to explicitly request (objectclass=ldapsubentry)
+ * in order to get all the subentry acis too.
+ * Note that subentries can be added under subentries (although its not
+ * recommended) so that
+ * there may be non-trivial acis under a subentry.
+ */
+
+ /* Use new search internal API */
+ /* and never retrieve aci from a remote server */
+ aPb = slapi_pblock_new ();
+
+ /*
+ * Set up the control to say "Only get acis from this Backend--
+ * there may be more backends under this one.
+ */
+
+ if ( thisbeonly ) {
+
+ bval = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
+ bval->bv_len = strlen(be_name) + 1;
+ bval->bv_val = slapi_ch_strdup(be_name);
+
+ ctrls = (LDAPControl **)slapi_ch_calloc( 2, sizeof(LDAPControl *));
+ ctrls[0] = NULL;
+ ctrls[1] = NULL;
+
+ retval = slapi_build_control_from_berval(
+ MTN_CONTROL_USE_ONE_BACKEND_OID,
+ bval,
+ 1 /* is critical */,
+ ctrls);
+
+ }
+
+ slapi_search_internal_set_pb ( aPb,
+ slapi_sdn_get_dn(base),
+ scope,
+ "(|(aci=*)(objectclass=ldapsubentry))",
+ attrs,
+ 0 /* attrsonly */,
+ ctrls /* controls: SLAPI_ARGCONTROLS */,
+ NULL /* uniqueid */,
+ aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
+ SLAPI_OP_FLAG_NEVER_CHAIN /* actions : get local aci only */);
+
+ if (thisbeonly) {
+ slapi_pblock_set(aPb, SLAPI_REQCONTROLS, ctrls);
+ }
+
+ call_back_data.op = op;
+ call_back_data.retCode = 0;
+ call_back_data.lock_flag = lock_flag;
+
+ slapi_search_internal_callback_pb(aPb,
+ &call_back_data /* callback_data */,
+ NULL/* result_callback */,
+ __aclinit_handler,
+ NULL /* referral_callback */);
+
+ if (thisbeonly) {
+ slapi_ch_free((void **)&bval);
+ }
+
+ /*
+ * This frees the control oid, the bv_val and the control itself and the
+ * ctrls array mem by caling ldap_controls_free()--so we
+ * don't need to do it ourselves.
+ */
+ slapi_pblock_destroy (aPb);
+
+ return call_back_data.retCode;
+
+}
+
+/***************************************************************************
+*
+* __aclinit_handler
+*
+* For each entry, finds if there is any ACL in thet entry. If there is
+* then the ACL is processed and stored in the ACL LIST.
+*
+*
+* Input:
+*
+*
+* Returns:
+* None.
+*
+* Error Handling:
+* If any error found during the ACL generation, the ACL is
+* logged. Also, set in the callback_data so that caller can act upon it.
+*
+**************************************************************************/
+static int
+__aclinit_handler ( Slapi_Entry *e, void *callback_data)
+{
+ Slapi_Attr *attr;
+ aclinit_handler_callback_data_t *call_back_data =
+ (aclinit_handler_callback_data_t*)callback_data;
+ Slapi_DN *e_sdn;
+ int rv;
+ Slapi_Value *sval=NULL;
+
+ call_back_data->retCode = 0; /* assume success--if there's an error we overwrite it */
+ if (e != NULL) {
+
+ e_sdn = slapi_entry_get_sdn ( e );
+
+ /*
+ * Take the write lock around all the mods--so that
+ * other operations will see the acicache either before the whole mod
+ * or after but not, as it was before, during the mod.
+ * This is in line with the LDAP concept of the operation
+ * on the whole entry being the atomic unit.
+ *
+ */
+
+ if ( call_back_data->op == ACL_ADD_ACIS ) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Adding acis for entry '%s'\n", slapi_sdn_get_dn(e_sdn));
+ slapi_entry_attr_find ( e, aci_attr_type, &attr );
+
+ if ( attr ) {
+
+ const struct berval *attrValue;
+
+ int i;
+ if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
+ acllist_acicache_WRITE_LOCK();
+ }
+ i= slapi_attr_first_value ( attr, &sval );
+ while(i != -1) {
+ attrValue = slapi_value_get_berval(sval);
+
+ if ( 0 != (rv=acllist_insert_aci_needsLock (e_sdn, attrValue))) {
+ aclutil_print_err(rv, e_sdn, attrValue, NULL);
+
+ /* We got an error; Log it and then march along */
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Error: This (%s) ACL will not be considered for evaluation"
+ " because of syntax errors.\n",
+ attrValue->bv_val ? attrValue->bv_val: "NULL", 0, 0);
+ call_back_data->retCode = rv;
+ }
+ i= slapi_attr_next_value( attr, i, &sval );
+ }/* while */
+ if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
+ acllist_acicache_WRITE_UNLOCK();
+ }
+ }
+ } else if (call_back_data->op == ACL_REMOVE_ACIS) {
+
+ /* Here we are deleting the acis. */
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "Removing acis\n");
+ if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
+ acllist_acicache_WRITE_LOCK();
+ }
+ if ( 0 != (rv=acllist_remove_aci_needsLock(e_sdn, NULL))) {
+ aclutil_print_err(rv, e_sdn, NULL, NULL);
+
+ /* We got an error; Log it and then march along */
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Error: ACls not deleted from %s\n",
+ e_sdn, 0, 0);
+ call_back_data->retCode = rv;
+ }
+ if ( call_back_data->lock_flag == DO_TAKE_ACLCACHE_WRITELOCK) {
+ acllist_acicache_WRITE_UNLOCK();
+ }
+ }
+
+ }
+
+ /*
+ * If we get here it's success.
+ * The call_back_data->error is the error code that counts as it's the
+ * one that the original caller will see--this routine is called off a callbacl.
+ */
+
+ return ACL_FALSE; /* "local" error code--it's 0 */
+}
+/***************************************************************************
+*
+* __acl__RegisterAttributes
+*
+* Register all the attributes supported by the DS.
+*
+* Input:
+* None.
+*
+* Returns:
+* ACL_OK - No error
+* ACL_ERR - in case of errror
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+static int
+__aclinit__RegisterAttributes(void)
+{
+
+ ACLMethod_t methodinfo;
+ NSErr_t errp;
+ int rv;
+
+ memset (&errp, 0, sizeof(NSErr_t));
+
+ rv = ACL_MethodRegister(&errp, DS_METHOD, &methodinfo);
+ if (rv < 0) {
+ acl_print_acllib_err(&errp, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to Register the methods\n", 0,0,0);
+ return ACL_ERR;
+ }
+ rv = ACL_MethodSetDefault (&errp, methodinfo);
+ if (rv < 0) {
+ acl_print_acllib_err(&errp, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to Set the default method\n", 0,0,0);
+ return ACL_ERR;
+ }
+ rv = ACL_AttrGetterRegister(&errp, ACL_ATTR_IP, DS_LASIpGetter,
+ methodinfo, ACL_DBTYPE_ANY, ACL_AT_FRONT, NULL);
+ if (rv < 0) {
+ acl_print_acllib_err(&errp, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to Register Attr ip\n", 0,0,0);
+ return ACL_ERR;
+ }
+ rv = ACL_AttrGetterRegister(&errp, ACL_ATTR_DNS, DS_LASDnsGetter,
+ methodinfo, ACL_DBTYPE_ANY, ACL_AT_FRONT, NULL);
+ if (rv < 0) {
+ acl_print_acllib_err(&errp, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Unable to Register Attr dns\n", 0,0,0);
+ return ACL_ERR;
+ }
+ return ACL_OK;
+}
+
+/***************************************************************************
+*
+* __acl__RegisterLases
+* Register all the LASes supported by the DS.
+*
+* The DS doesnot support user/group. We have defined our own LAS
+* so that we can display/print an error when the LAS is invoked.
+* Input:
+* None.
+*
+* Returns:
+* ACL_OK - No error
+* ACL_ERR - in case of errror
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+static int
+__aclinit__RegisterLases(void)
+{
+
+ if (ACL_LasRegister(NULL, DS_LAS_USER, (LASEvalFunc_t) DS_LASUserEval,
+ (LASFlushFunc_t) NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register USER Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_GROUP, (LASEvalFunc_t) DS_LASGroupEval,
+ (LASFlushFunc_t) NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register GROUP Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_GROUPDN, (LASEvalFunc_t)DS_LASGroupDnEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register GROUPDN Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_ROLEDN, (LASEvalFunc_t)DS_LASRoleDnEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register ROLEDN Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_USERDN, (LASEvalFunc_t)DS_LASUserDnEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register USERDN Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_USERDNATTR,
+ (LASEvalFunc_t)DS_LASUserDnAttrEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register USERDNATTR Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_AUTHMETHOD,
+ (LASEvalFunc_t)DS_LASAuthMethodEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register CLIENTAUTHTYPE Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_GROUPDNATTR,
+ (LASEvalFunc_t)DS_LASGroupDnAttrEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register GROUPDNATTR Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ if (ACL_LasRegister(NULL, DS_LAS_USERATTR,
+ (LASEvalFunc_t)DS_LASUserAttrEval,
+ (LASFlushFunc_t)NULL) < 0) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "Unable to register USERATTR Las\n",0,0,0);
+ return ACL_ERR;
+ }
+ return ACL_OK;
+}
diff --git a/ldap/servers/plugins/acl/acllas.c b/ldap/servers/plugins/acl/acllas.c
new file mode 100644
index 00000000..0179b0e6
--- /dev/null
+++ b/ldap/servers/plugins/acl/acllas.c
@@ -0,0 +1,3848 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <ipfstruct.h>
+#include "acl.h"
+
+/*
+ A word on this file:
+
+ The various routines here implement each component of the subject of an aci
+ eg. "groupdn", "userdn","roledn", "userattr" etc.
+ They are responsible for evaluating each individual keyword not for doing
+ the boolean combination of these keywords, nor for combining multiple
+ allow()/deny() statements--that's libaccess's job.
+ For example, for "groupdn", DS_LASGroupDnEval might have to evaluate
+ something like this:
+
+ "groupdn = "ldap:///cn=G1,o=sun.com || ldap:///cn=G2,o=sun.com"
+
+ The "=" here may be "!=" as well and these routines take care of the
+ comparator.
+
+ These rotuines get called via acl__TestRights(), which calls
+ ACL_EvalTestRights() a libaccess routine (the immediately calling routine is
+ ACLEvalAce() in oneeval.cpp).
+
+ They should return LAS_EVAL_TRUE, if that keyword component evaluates to
+ TRUE, LAS_EVAL_FALSE if it evaluates to FALSE and LAS_EVAL_FAIL if an
+ error occurrs during evaluation. Note that once any component of a subject
+ returns LAS_EVAL_FAIL, the evaluation in libaccess stops and the whole
+ subject does not match and that aci is not applied.
+*/
+
+/*
+
+ A word on three-valued logic:
+
+ In general when you do boolean combination of terms some of which
+ may evaluate to UNDEFINED then you need to define what the combination
+ means.
+ So, for example libaccess implements a scheme which once UNDEFINED
+ is returned for a term, it bales out of the
+ evaluation and the whole expression evaluates to UNDEFINED.
+ In this case the aci will not apply.
+ On the other hand LDAP filters (cf. rfc2251 4.5.1) say that for OR,
+ an expression will
+ evaluate to TRUE if any term is TRUE, even if some terms are UNDEFINED.
+ Other off the cuff options might be to redefine UNDEFINED to be FALSE,
+ or TRUE.
+
+ Which is best ?
+
+ Well it probably depends on exactly what is to decided based on the
+ evaluation of the logical expression. However, the final suggestion is
+ almost certainly
+ bad--you are unlikely to want to take an action based on an undefined
+ result and
+ defining UNDEFINED to be either TRUE or FALSE may result in the overall
+ expression
+ returning TRUE--a security hole. The only case this might work is if you
+ are dealing with restricted
+ expressions eg. terms may only be AND'ed togther--in this case defining
+ UNDEFINED to be FALSE would guarantee a result of FALSE.
+
+ The libaccess approach of returning UNDEFINED once an UNDEFINED is
+ encountered during
+ evaluation is not too bad--at least it guarantees that no aci will apply
+ based on an
+ undefined value. However, with an aci like this "...allow(all) A or B"
+ where A returned UNDEFINED, you might be disappointed not to receive the
+ rights if it was B that
+ was granting you the rights and evaluation of A, which has nothing to do
+ with you, returns UNDEFINED. In the case of an aci like
+ "...deny(all) A or B" then the same
+ situation is arguably a security hole. Note that this scheme also makes
+ the final result
+ dependent on the evaluation order and so if the evaluation engine does
+ anything fancy internally (eg. reordering the terms in an OR so that fast
+ to evaluate ones came first) then
+ this would need to be documented so that a user (or a tool) could look at
+ the external syntax and figure out the result of the evaluation.
+ Also it breaks commutivity and De Morgans law.
+
+ The LDAP filter scheme is starting to look good--it solves the problems of
+ the
+ libaccess approach, makes the final result of an expression independent of
+ the evaluation order and
+ gives you back commutivity of OR and AND. De Morgans is still broken, but
+ that's because of the asymmetry of behaviour of UNDEFINED with OR and AND.
+
+ So...?
+
+ For acis, in general it can look like this:
+
+ "...allow(rights)(LogicalCombinationofBindRule);
+ deny(LogicalCombinationOfBindRule)...."
+
+ A BindRule is one of the "userdn", "groupdn" or "userattr" things and it
+ can look like this:
+
+ "groupdn = "ldap:///cn=G1,o=sun.com || ldap:///cn=G2,o=sun.com"
+
+ The "=" here may be "!=" as well and these routines take care of the
+ comparator.
+
+ For "userattr" keywords a mutilvalued attribute amounts a logical OR of the
+ individual values. There is also a logical OR over the different levels
+ as specified by the "parent" keyword.
+
+ In fact there are three levels of logical combination:
+
+ 1. In the aclplugin:
+ The "||" and "!=" combinator for BindRule keywords like userdn and
+ groupdn.
+ The fact that for the "userattr" keyword, a mutilvalued attribute is
+ evaluated as "||". Same for the different levels.
+ 2. In libaccess:
+ The logical combination of BindRules.
+ 3. In libaccess:
+ The evaluation of multiple BindRules seperated by ";", which means OR.
+
+ The LDAP filter three-valued logic SHOULD be applied to each level but
+ here's the way it works right now:
+
+ 1. At this level it depends....
+
+ DS_LASIpGetter - get attr for IP -
+ returns ip address or LAS_EVAL_FAIL for error.
+ no logical combination.
+ DS_LASDnsGetter - get attr for DNS-
+ returns dns name or LAS_EVAL_FAIL for error
+ no logical combination.
+ DS_LASUserDnEval - LAS Evaluation for USERDN -
+ three-valued logic
+ logical combination: || and !=
+ DS_LASGroupDnEval - LAS Evaluation for GROUPDN -
+ three-valued logic
+ logical combination: || and !=
+ DS_LASRoleDnEval - LAS Evaluation for ROLEDN -
+ three-valued logic
+ logical combination: || and !=
+ DS_LASUserDnAttrEval - LAS Evaluation for USERDNATTR -
+ three-valued logic
+ logical combination || (over specified attribute values and
+ parent keyword levels), !=
+ DS_LASAuthMethodEval - LAS Evaluation for AUTHMETHOD -
+ three-valued logic ( logical combinations: !=)
+ DS_LASGroupDnAttrEval - LAS Evaluation for GROUPDNATTR -
+ three-valued logic
+ logical combination || (over specified attribute values and
+ parent keyword levels), !=
+ DS_LASUserAttrEval - LAS Evaluation for USERATTR -
+ USER, GROUPDN and ROLEDN as above.
+ LDAPURL -- three-valued logic (logical combinations: || over
+ specified attribute vales, !=)
+ attrname#attrvalue -- three-valued logic, logical combination:!=
+
+ 2. The libaccess scheme applies at this level.
+ 3. The LDAP filter three-valued logic applies at this level.
+
+ Example of realistic, non-bizarre things that cause evaluation of a
+ BindRule to be undefined are exceeding some resource limits (nesting level,
+ lookthrough limit) in group membership evaluation, or trying to get ADD
+ permission from the "userattr" keyword at "parent" level 0.
+ Note that not everything that might be construed as an error needs to be
+ taken as UNDEFINED. For example, things like not finding a user or an
+ attribute in an entry can be defined away as TRUE or FALSE. eg. in an
+ LDAP filter (cn=rob) applied to an entry where cn is not present is FALSE,
+ not UNDEFINED. Similarly, if the number of levels in a parent keyword
+ exceeds the allowed limit, we just ignore the rest--though this
+ is a syntax error which should be detected at parse time.
+
+
+*/
+
+/* To get around warning: declared in ldapserver/lib/ldaputil/ldaputili.h */
+extern int ldapu_member_certificate_match (void* cert, const char* desc);
+
+/****************************************************************************/
+/* Defines, Constants, ande Declarations */
+/****************************************************************************/
+static char* const type_objectClass = "objectclass";
+static char* const filter_groups = "(|(objectclass=groupOfNames) (objectclass=groupOfUniqueNames)(objectclass=groupOfCertificates)(objectclass=groupOfURLs))";
+static char* const type_member = "member";
+static char* const type_uniquemember = "uniquemember";
+static char* const type_memberURL = "memberURL";
+static char* const type_memberCert = "memberCertificateDescription";
+
+/* cache strategy for groups */
+#define ACLLAS_CACHE_MEMBER_GROUPS 0x1
+#define ACLLAS_CACHE_NOT_MEMBER_GROUPS 0x2
+#define ACLLAS_CACHE_ALL_GROUPS 0x3
+
+/****************************************************************************/
+/* prototypes */
+/****************************************************************************/
+static int acllas__handle_group_entry(Slapi_Entry *, void *);
+static int acllas__user_ismember_of_group(struct acl_pblock *aclpb,
+ char* groupDN,
+ char* clientDN,
+ int cache_status,
+ CERTCertificate *clientCert);
+static int acllas__user_has_role( struct acl_pblock *aclpb,
+ Slapi_DN *roleDN, Slapi_DN *clientDn);
+static int acllas__add_allgroups (Slapi_Entry* e, void *callback_data);
+static int acllas__eval_memberGroupDnAttr (char *attrName,
+ Slapi_Entry *e,
+ char *n_clientdn,
+ struct acl_pblock *aclpb);
+static int acllas__verify_client (Slapi_Entry* e, void *callback_data);
+static char* acllas__dn_parent( char *dn, int level);
+static int acllas__get_members (Slapi_Entry* e, void *callback_data);
+static int acllas__client_match_URL (struct acl_pblock *aclpb,
+ char *n_dn, char *url );
+static int acllas__handle_client_search (Slapi_Entry *e, void *callback_data);
+static int __acllas_setup ( NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth, char *lasType, char *lasName, lasInfo *linfo);
+int
+aclutil_evaluate_macro( char * user, lasInfo *lasinfo,
+ acl_eval_types evalType );
+static int
+acllas_eval_one_user( struct acl_pblock *aclpb,
+ char * clientDN, char *userKeyword);
+static int
+acllas_eval_one_group(char *group, lasInfo *lasinfo);
+static int
+acllas_eval_one_role(char *role, lasInfo *lasinfo);
+static char **
+acllas_replace_dn_macro( char *rule, char *matched_val, lasInfo *lasinfo);
+static char **
+acllas_replace_attr_macro( char *rule, lasInfo *lasinfo);
+static int
+acllas_eval_one_target_filter( char * str, Slapi_Entry *e);
+
+/****************************************************************************/
+
+int
+DS_LASIpGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
+ auth_info, PList_t global_auth, void *arg)
+{
+
+ struct acl_pblock *aclpb = NULL;
+ IPAddr_t ip=0;
+ PRNetAddr client_praddr;
+ struct in_addr client_addr;
+ int rv;
+
+
+ rv = ACL_GetAttribute(errp, DS_PROP_ACLPB, (void **)&aclpb,
+ subject, resource, auth_info, global_auth);
+ if ( rv != LAS_EVAL_TRUE || ( NULL == aclpb )) {
+ acl_print_acllib_err(errp, NULL);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASIpGetter:Unable to get the ACLPB(%d)\n", rv,0,0);
+ return LAS_EVAL_FAIL;
+ }
+
+ if ( slapi_pblock_get( aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR,
+ &client_praddr ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Could not get client IP.\n" );
+ return( LAS_EVAL_FAIL );
+ }
+
+ if ( !PR_IsNetAddrType(&client_praddr, PR_IpAddrV4Mapped) ) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Client address is IPv6. ACLs only support IPv4 addresses so far.\n");
+ return( LAS_EVAL_FAIL );
+ }
+
+ client_addr.s_addr = client_praddr.ipv6.ip.pr_s6_addr32[3];
+
+ ip = (IPAddr_t) ntohl( client_addr.s_addr );
+ rv = PListInitProp(subject, 0, ACL_ATTR_IP, (void *)ip, NULL);
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Returning client ip address '%s'\n",
+ (slapi_is_loglevel_set(SLAPI_LOG_ACL) ? inet_ntoa(client_addr) : ""));
+
+ return LAS_EVAL_TRUE;
+
+}
+
+/*
+ * This is called from the libaccess code when it needs to find a dns name.
+ * It's called from ACL_GetAttribute() when it finds that ACL_ATTR_DNS is
+ * not already part of the proplist.
+ *
+*/
+
+int
+DS_LASDnsGetter(NSErr_t *errp, PList_t subject, PList_t resource, PList_t
+ auth_info, PList_t global_auth, void *arg)
+{
+ struct acl_pblock *aclpb = NULL;
+ PRNetAddr client_praddr;
+ PRHostEnt *hp;
+ char *dnsName = NULL;
+ int rv;
+ struct berval **clientDns;
+
+
+ rv = ACL_GetAttribute(errp, DS_PROP_ACLPB, (void **)&aclpb,
+ subject, resource, auth_info, global_auth);
+ if ( rv != LAS_EVAL_TRUE || ( NULL == aclpb )) {
+ acl_print_acllib_err(errp, NULL);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASDnsGetter:Unable to get the ACLPB(%d)\n", rv,0,0);
+ return LAS_EVAL_FAIL;
+ }
+
+ if ( slapi_pblock_get( aclpb->aclpb_pblock, SLAPI_CLIENT_DNS, &clientDns ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Could not get client IP.\n" );
+ return( LAS_EVAL_FAIL );
+ }
+
+ /*
+ * If the client hostname has already been put into the pblock then
+ * use that. Otherwise we work it out and add it ourselves.
+ * This info is connection-lifetime so with multiple operaitons on the same
+ * connection we will only do the calculation once.
+ *
+ * rbyrneXXX surely this code would be better in connection.c so
+ * the name would be just there waiting for us, and everyone else.
+ *
+ */
+
+ if ( clientDns && clientDns[0] != NULL && clientDns[0]->bv_val ) {
+ dnsName = clientDns[0]->bv_val;
+ } else {
+ struct berval **dnsList;
+ char buf[PR_NETDB_BUF_SIZE];
+
+ if ( slapi_pblock_get( aclpb->aclpb_pblock, SLAPI_CONN_CLIENTNETADDR, &client_praddr ) != 0 ) {
+
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "Could not get client IP.\n" );
+ return( LAS_EVAL_FAIL );
+ }
+ hp = (PRHostEnt *)slapi_ch_malloc( sizeof(PRHostEnt) );
+ if ( PR_GetHostByAddr( &(client_praddr), (char *)buf, sizeof(buf), hp ) == PR_SUCCESS ) {
+ if ( hp->h_name != NULL ) {
+ dnsList = (struct berval**)
+ slapi_ch_calloc (1, sizeof(struct berval*) * (1 + 1));
+ *dnsList = (struct berval*)
+ slapi_ch_calloc ( 1, sizeof(struct berval));
+ dnsName = (*dnsList)->bv_val = slapi_ch_strdup( hp->h_name );
+ (*dnsList)->bv_len = strlen ( (*dnsList)->bv_val );
+ slapi_pblock_set( aclpb->aclpb_pblock, SLAPI_CLIENT_DNS, &dnsList );
+ }
+ }
+ slapi_ch_free( (void **)&hp );
+ }
+
+ if ( NULL == dnsName ) return LAS_EVAL_FAIL;
+
+ rv = PListInitProp(subject, 0, ACL_ATTR_DNS, dnsName, NULL);
+ if (rv < 0) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASDnsGetter:Couldn't set the DNS property(%d)\n", rv );
+ return LAS_EVAL_FAIL;
+ }
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "DNS name: %s\n", dnsName );
+ return LAS_EVAL_TRUE;
+
+}
+/***************************************************************************/
+/* New LASes */
+/* */
+/* 1. user, groups. -- stubs to report errors. Not supported. */
+/* 2. userdn */
+/* 3. groupdn */
+/* 4. userdnattr */
+/* 5. authmethod */
+/* 6. groupdnattr */
+/* 7. roledn */
+/* */
+/* */
+/***************************************************************************/
+int
+DS_LASUserEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "User LAS is not supported in the ACL\n",0,0,0);
+
+ return LAS_EVAL_INVALID;
+}
+
+int
+DS_LASGroupEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Group LAS is not supported in the ACL\n",0,0,0);
+
+ return LAS_EVAL_INVALID;
+}
+
+/***************************************************************************
+*
+* DS_LASUserDnEval
+* Evaluate the "userdn" LAS. See if the user has rights.
+*
+* Input:
+* attr_name The string "userdn" - in lower case.
+* comparator CMP_OP_EQ or CMP_OP_NE only
+* attr_pattern A comma-separated list of users
+* cachable Always set to FALSE.
+* subject Subject property list
+* resource Resource property list
+* auth_info Authentication info, if any
+*
+* Returns:
+* retcode The usual LAS return codes.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+DS_LASUserDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+
+ char *users = NULL;
+ char *s_user, *user = NULL;
+ char *ptr = NULL;
+ char *end_dn = NULL;
+ char *n_edn = NULL;
+ char *parent_dn = NULL;
+ int matched;
+ int rc;
+ short len;
+ char *s = NULL;
+ const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix);
+ lasInfo lasinfo;
+ int got_undefined = 0;
+
+ if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
+ attr_pattern,cachable,LAS_cookie,
+ subject, resource, auth_info,global_auth,
+ DS_LAS_USERDN, "DS_LASUserDnEval", &lasinfo )) ) {
+ return LAS_EVAL_FAIL;
+ }
+
+ users = slapi_ch_strdup(attr_pattern);
+ user = users;
+ matched = ACL_FALSE;
+
+ /* check if the clientdn is one of the users */
+ while(user != 0 && *user != 0 && matched != ACL_TRUE ) {
+
+ /* ignore leading whitespace */
+ while(ldap_utf8isspace(user))
+ LDAP_UTF8INC(user);
+
+ /* Now we must see the userdn in the following
+ ** formats:
+ **
+ ** The following formats are supported:
+ **
+ ** 1. The DN itself:
+ ** allow (read) userdn = "ldap:///cn=prasanta, ..."
+ **
+ ** 2. keyword SELF:
+ ** allow (write)
+ ** userdn = "ldap:///self"
+ **
+ ** 3. Pattern:
+ ** deny (read) userdn = "ldap:///cn=*, o=netscape, c = us";
+ **
+ ** 4. Anonymous user
+ ** deny (read, write) userdn = "ldap:///anyone"
+ **
+ ** 5. All users (All authenticated users)
+ ** allow (search) ** userdn = "ldap:///all"
+ ** 6. parent "ldap:///parent"
+ ** 7. Synamic users using the URL
+ **
+ **
+ ** DNs must be separated by "||". Ex:
+ ** allow (read)
+ ** userdn = "ldap:///DN1 || ldap:///DN2"
+ */
+
+
+ /* The DN is now "ldap:///DN"
+ ** remove the "ldap:///" part
+ */
+ if (strncasecmp (user, LDAP_URL_prefix,
+ LDAP_URL_prefix_len) == 0) {
+ s_user = user;
+ user += LDAP_URL_prefix_len;
+
+ } else {
+ char ebuf[ BUFSIZ ];
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "DS_LASUserDnEval:Syntax error(%s)\n",
+ escape_string_with_punctuation( user, ebuf ), 0,0);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Now we have the starting point of the "userdn" */
+ if ((end_dn = strstr(user, "||")) != NULL) {
+ auto char *t = end_dn;
+ LDAP_UTF8INC(end_dn);
+ LDAP_UTF8INC(end_dn);
+ *t = 0;
+ }
+
+ /* Now user is a null terminated string */
+
+ if (*user) {
+ while(ldap_utf8isspace(user))
+ LDAP_UTF8INC(user);
+ /* ignore trailing whitespace */
+ len = strlen(user);
+ ptr = user+len-1;
+ while(ldap_utf8isspace(ptr)){ *ptr = '\0'; LDAP_UTF8DEC(ptr); }
+ }
+
+ /*
+ ** Check , if the user is a anonymous user. In that case
+ ** We must find the rule "ldap:///anyone"
+ */
+ if (lasinfo.anomUser) {
+ if (strcasecmp(user, "anyone") == 0 ) {
+ /* matches -- anonymous user */
+ matched = ACL_TRUE;
+ break;
+ }
+ } else {
+ /* URL format */
+
+ if ((s = strstr (user, ACL_RULE_MACRO_DN_KEY)) != NULL ||
+ (s = strstr (user, ACL_RULE_MACRO_DN_LEVELS_KEY)) != NULL ||
+ (s = strstr (user, ACL_RULE_MACRO_ATTR_KEY)) != NULL) {
+
+ matched = aclutil_evaluate_macro( s_user, &lasinfo,
+ ACL_EVAL_USER);
+ if (matched == ACL_TRUE) {
+ break;
+ }
+
+ } else if ((s = strchr (user, '?'))!= NULL) {
+ /* URL format */
+ if (acllas__client_match_URL ( lasinfo.aclpb, lasinfo.clientDn,
+ s_user) == ACL_TRUE) {
+ matched = ACL_TRUE;
+ break;
+ }
+ } else if (strcasecmp(user, "anyone") == 0 ) {
+ /* Anyone means anyone in the world */
+ matched = ACL_TRUE;
+ break;
+ } else if (strcasecmp(user, "self") == 0) {
+ if (n_edn == NULL) {
+ n_edn = slapi_entry_get_ndn ( lasinfo.resourceEntry );
+ }
+ if (slapi_utf8casecmp((ACLUCHP)lasinfo.clientDn, (ACLUCHP)n_edn) == 0)
+ matched = ACL_TRUE;
+ break;
+ } else if (strcasecmp(user, "parent") == 0) {
+ if (n_edn == NULL) {
+ n_edn = slapi_entry_get_ndn ( lasinfo.resourceEntry );
+ }
+ /* get the parent */
+ parent_dn = slapi_dn_parent(n_edn);
+ if (parent_dn &&
+ slapi_utf8casecmp ((ACLUCHP)lasinfo.clientDn, (ACLUCHP)parent_dn) == 0)
+ matched = ACL_TRUE;
+
+ if (parent_dn) slapi_ch_free ( (void **) &parent_dn );
+ break;
+ } else if (strcasecmp(user, "all") == 0) {
+ /* matches -- */
+ matched = ACL_TRUE;
+ break;
+ } else if (strchr(user, '*')) {
+ char line[200];
+ char *lineptr = &line[0];
+ char *newline = NULL;
+ int lenu = 0;
+ Slapi_Filter *f = NULL;
+ char *tt;
+ int filterChoice;
+
+ /*
+ ** what we are doing is faking the str2simple()
+ ** function with a "userdn = "user")
+ */
+ for (tt = user; *tt; tt++)
+ *tt = TOLOWER ( *tt );
+
+ if ((lenu = strlen(user)) > 190) { /* 200 - 9 for "(userdn=%s)" */
+ newline = slapi_ch_malloc(lenu + 10);
+ lineptr = newline;
+ }
+
+ sprintf (lineptr, "(userdn=%s)", user);
+ if ((f = slapi_str2filter (lineptr)) == NULL) {
+ if (newline) slapi_ch_free((void **) &newline);
+ /* try the next one */
+ break;
+ }
+ if (newline) slapi_ch_free((void **) &newline);
+ filterChoice = slapi_filter_get_choice ( f );
+
+ if (( filterChoice != LDAP_FILTER_SUBSTRINGS) &&
+ ( filterChoice != LDAP_FILTER_PRESENT)) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASUserDnEval:Error in gen. filter(%s)\n", user);
+ }
+ if ((rc = acl_match_substring( f,
+ lasinfo.clientDn,
+ 1 /*exact match */)
+ ) == ACL_TRUE) {
+ matched = ACL_TRUE;
+ slapi_filter_free(f,1);
+ break;
+ }
+ if (rc == ACL_ERR) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASUserDnEval:Error in matching patteren(%s)\n",
+ user,0,0);
+ }
+ slapi_filter_free(f,1);
+ } else {
+ /* Must be a simple dn then */
+ if (slapi_utf8casecmp((ACLUCHP)lasinfo.clientDn,
+ (ACLUCHP)slapi_dn_normalize(user)) == 0) {
+ matched = ACL_TRUE;
+ break;
+ }
+ }
+ }
+
+ if ( matched == ACL_DONT_KNOW ) {
+ /* record this but keep going--maybe another user will evaluate to TRUE */
+ got_undefined = 1;
+ }
+ /* Nothing matched -- try the next DN */
+ user = end_dn;
+ } /* end of while */
+
+ slapi_ch_free ( (void **) &users);
+
+ /*
+ * If no terms were undefined, then evaluate as normal.
+ * If there was an undefined term, but another one was TRUE, then we also evaluate
+ * as normal. Otherwise, the whole expression is UNDEFINED.
+ */
+ if ( matched == ACL_TRUE || !got_undefined ) {
+ if (comparator == CMP_OP_EQ) {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ } else {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ } else {
+ rc = LAS_EVAL_FAIL;
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Returning UNDEFINED for userdn evaluation.\n");
+ }
+
+ return rc;
+}
+
+/***************************************************************************
+*
+* DS_LASGroupDnEval
+*
+*
+* Input:
+* attr_name The string "userdn" - in lower case.
+* comparator CMP_OP_EQ or CMP_OP_NE only
+* attr_pattern A comma-separated list of users
+* cachable Always set to FALSE.
+* subject Subject property list
+* resource Resource property list
+* auth_info Authentication info, if any
+*
+* Returns:
+* retcode The usual LAS return code
+* If the client is in any of the groups mentioned this groupdn keywrod
+* then returns LAS_EVAL_TRUE, if he's not in any LAS_EVAL_FALSE.
+* If any of the membership evaluations fail, then it goes on to evaluate the
+* others.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+DS_LASGroupDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+
+ char *groups;
+ char *groupName;
+ char *ptr;
+ char *end_dn;
+ int matched;
+ int rc;
+ int len;
+ const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix);
+ int any_group = 0;
+ lasInfo lasinfo;
+ int got_undefined = 0;
+
+ /* the setup should not fail under normal operation */
+ if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
+ attr_pattern,cachable,LAS_cookie,
+ subject, resource, auth_info,global_auth,
+ DS_LAS_GROUPDN, "DS_LASGroupDnEval", &lasinfo )) ) {
+ return LAS_EVAL_FAIL;
+ }
+
+ groups = slapi_ch_strdup(attr_pattern);
+ groupName = groups;
+ matched = ACL_FALSE;
+
+ /* check if the groupdn is one of the users */
+ while(groupName != 0 && *groupName != 0 && matched != ACL_TRUE) {
+
+ /* ignore leading whitespace */
+ while(ldap_utf8isspace(groupName))
+ LDAP_UTF8INC(groupName);
+
+ /*
+ ** The syntax allowed for the groupdn is
+ **
+ ** Example:
+ ** groupdn = "ldap:///dn1 || ldap:///dn2";
+ **
+ */
+
+ if (strncasecmp (groupName, LDAP_URL_prefix,
+ LDAP_URL_prefix_len) == 0) {
+ groupName += LDAP_URL_prefix_len;
+ } else {
+ char ebuf[ BUFSIZ ];
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "DS_LASGroupDnEval:Syntax error(%s)\n",
+ escape_string_with_punctuation( groupName, ebuf ),0,0);
+ }
+
+ /* Now we have the starting point of the "groupdn" */
+ if ((end_dn = strstr(groupName, "||")) != NULL) {
+ auto char *t = end_dn;
+ LDAP_UTF8INC(end_dn);
+ LDAP_UTF8INC(end_dn);
+ *t = 0;
+ }
+
+ if (*groupName) {
+ while(ldap_utf8isspace(groupName))
+ LDAP_UTF8INC(groupName);
+ /* ignore trailing whitespace */
+ len = strlen(groupName);
+ ptr = groupName+len-1;
+ while(ldap_utf8isspace(ptr)) { *ptr = '\0'; LDAP_UTF8DEC(ptr); }
+ }
+
+ /*
+ ** Now we have the DN of the group. Evaluate the "clientdn"
+ ** and see if the user is a member of the group.
+ */
+ if (0 == (strcasecmp(groupName, "anyone"))) {
+ any_group = 1;
+ }
+
+ if (any_group) {
+ /* anyone in the world */
+ matched = ACL_TRUE;
+ break;
+ } else if ( lasinfo.anomUser &&
+ (lasinfo.aclpb->aclpb_clientcert == NULL) && (!any_group)) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Group not evaluated(%s)\n", groupName);
+ break;
+ } else {
+ char *s;
+
+ if ((s = strstr (groupName, ACL_RULE_MACRO_DN_KEY)) != NULL ||
+ (s = strstr (groupName, ACL_RULE_MACRO_DN_LEVELS_KEY)) != NULL ||
+ (s = strstr (groupName, ACL_RULE_MACRO_ATTR_KEY)) != NULL) {
+
+ matched = aclutil_evaluate_macro( groupName, &lasinfo,
+ ACL_EVAL_GROUP);
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASGroupDnEval: Param group name:%s\n",
+ groupName);
+ } else {/* normal evaluation */
+
+ matched = acllas_eval_one_group( groupName, &lasinfo);
+
+ }
+
+ if ( matched == ACL_TRUE ) {
+ break;
+ } else if ( matched == ACL_DONT_KNOW ) {
+ /* record this but keep going--maybe another group will evaluate to TRUE */
+ got_undefined = 1;
+ }
+ }
+ /* Nothing matched -- try the next DN */
+ groupName = end_dn;
+
+ } /* end of while */
+
+ /*
+ * If no terms were undefined, then evaluate as normal.
+ * If there was an undefined term, but another one was TRUE, then we also evaluate
+ * as normal. Otherwise, the whole expression is UNDEFINED.
+ */
+ if ( matched == ACL_TRUE || !got_undefined ) {
+ if (comparator == CMP_OP_EQ) {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ } else {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ } else {
+ rc = LAS_EVAL_FAIL;
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Returning UNDEFINED for groupdn evaluation.\n");
+ }
+
+ slapi_ch_free ((void**) &groups);
+ return rc;
+}
+/***************************************************************************
+*
+* DS_LASRoleDnEval
+*
+*
+* Input:
+* attr_name The string "roledn" - in lower case.
+* comparator CMP_OP_EQ or CMP_OP_NE only
+* attr_pattern A "||" sperated list of roles
+* cachable Always set to FALSE.
+* subject Subject property list
+* resource Resource property list
+* auth_info Authentication info, if any
+*
+* Returns:
+* retcode The usual LAS return codes.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+DS_LASRoleDnEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+
+ char *roles;
+ char *role;
+ char *ptr;
+ char *end_dn;
+ int matched;
+ int rc;
+ int len;
+ const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix);
+ int any_role = 0;
+ lasInfo lasinfo;
+ int got_undefined = 0;
+
+ if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
+ attr_pattern,cachable,LAS_cookie,
+ subject, resource, auth_info,global_auth,
+ DS_LAS_ROLEDN, "DS_LASRoleDnEval",
+ &lasinfo )) ) {
+ return LAS_EVAL_FALSE;
+ }
+
+
+ roles = slapi_ch_strdup(attr_pattern);
+ role = roles;
+ matched = ACL_FALSE;
+
+ /* check if the roledn is one of the users */
+ while(role != 0 && *role != 0 && matched != ACL_TRUE) {
+
+ /* ignore leading whitespace */
+ while(ldap_utf8isspace(role))
+ LDAP_UTF8INC(role);
+
+ /*
+ ** The syntax allowed for the roledn is
+ **
+ ** Example:
+ ** roledn = "ldap:///roledn1 || ldap:///roledn2";
+ **
+ */
+
+ if (strncasecmp (role, LDAP_URL_prefix,
+ LDAP_URL_prefix_len) == 0) {
+ role += LDAP_URL_prefix_len;
+ } else {
+ char ebuf[ BUFSIZ ];
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "DS_LASRoleDnEval:Syntax error(%s)\n",
+ escape_string_with_punctuation( role, ebuf ),0,0);
+ }
+
+ /* Now we have the starting point of the "roledn" */
+ if ((end_dn = strstr(role, "||")) != NULL) {
+ auto char *t = end_dn;
+ LDAP_UTF8INC(end_dn);
+ LDAP_UTF8INC(end_dn);
+ *t = 0;
+ }
+
+
+ if (*role) {
+ while(ldap_utf8isspace(role))
+ LDAP_UTF8INC(role);
+ /* ignore trailing whitespace */
+ len = strlen(role);
+ ptr = role+len-1;
+ while(ldap_utf8isspace(ptr)) { *ptr = '\0'; LDAP_UTF8DEC(ptr); }
+ }
+
+ /*
+ ** Now we have the DN of the role. Evaluate the "clientdn"
+ ** and see if the user has this role.
+ */
+ if (0 == (strcasecmp(role, "anyone"))) {
+ any_role = 1;
+ }
+
+ if (any_role) {
+ /* anyone in the world */
+ matched = ACL_TRUE;
+ break;
+ } else if ( lasinfo.anomUser &&
+ (lasinfo.aclpb->aclpb_clientcert == NULL) && (!any_role)) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Role not evaluated(%s) for anon user\n", role);
+ break;
+ } else {
+
+ /* Take care of param strings */
+
+ char *s;
+
+ if ((s = strstr (role, ACL_RULE_MACRO_DN_KEY)) != NULL ||
+ (s = strstr (role, ACL_RULE_MACRO_DN_LEVELS_KEY)) != NULL ||
+ (s = strstr (role, ACL_RULE_MACRO_ATTR_KEY)) != NULL) {
+
+ matched = aclutil_evaluate_macro( role, &lasinfo,
+ ACL_EVAL_ROLE);
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASRoleDnEval: Param role name:%s\n",
+ role);
+ } else {/* normal evaluation */
+
+ matched = acllas_eval_one_role( role, &lasinfo);
+
+ }
+
+ if ( matched == ACL_TRUE ) {
+ break;
+ } else if ( matched == ACL_DONT_KNOW ) {
+ /* record this but keep going--maybe another role will evaluate to TRUE */
+ got_undefined = 1;
+ }
+ }
+ /* Nothing matched -- try the next DN */
+ role = end_dn;
+
+ } /* end of while */
+
+ /*
+ * If no terms were undefined, then evaluate as normal.
+ * If there was an undefined term, but another one was TRUE, then we also evaluate
+ * as normal. Otherwise, the whole expression is UNDEFINED.
+ */
+ if ( matched == ACL_TRUE || !got_undefined ) {
+ if (comparator == CMP_OP_EQ) {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ } else {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ } else {
+ rc = LAS_EVAL_FAIL;
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Returning UNDEFINED for roledn evaluation.\n");
+ }
+
+ slapi_ch_free ((void**) &roles);
+ return rc;
+}
+/***************************************************************************
+*
+* DS_LASUserDnAttrEval
+*
+*
+* Input:
+* attr_name The string "userdn" - in lower case.
+* comparator CMP_OP_EQ or CMP_OP_NE only
+* attr_pattern A comma-separated list of users
+* cachable Always set to FALSE.
+* subject Subject property list
+* resource Resource property list
+* auth_info Authentication info, if any
+*
+* Returns:
+* retcode The usual LAS return codes.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+struct userdnattr_info {
+ char *attr;
+ int result;
+ char *clientdn;
+};
+#define ACLLAS_MAX_LEVELS 10
+int
+DS_LASUserDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+
+ char *n_currEntryDn = NULL;
+ char *s_attrName, *attrName;
+ char *ptr;
+ int matched;
+ int rc, len, i;
+ char *val;
+ Slapi_Attr *a;
+ int levels[ACLLAS_MAX_LEVELS];
+ int numOflevels =0;
+ struct userdnattr_info info;
+ char *attrs[2] = { LDAP_ALL_USER_ATTRS, NULL };
+ lasInfo lasinfo;
+ int got_undefined = 0;
+
+ if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
+ attr_pattern,cachable,LAS_cookie,
+ subject, resource, auth_info,global_auth,
+ DS_LAS_USERDNATTR, "DS_LASUserDnAttrEval",
+ &lasinfo )) ) {
+ return LAS_EVAL_FAIL;
+ }
+
+ /*
+ ** The userdnAttr syntax is
+ ** userdnattr = <attribute> or
+ ** userdnattr = parent[0,2,4].attribute"
+ ** Ex:
+ ** userdnattr = manager; or
+ ** userdnattr = "parent[0,2,4].manager";
+ **
+ ** Here 0 means current level, 2 means grandfather and
+ ** 4 (great great grandfather)
+ **
+ ** The function of this LAS is to compare the value of the
+ ** attribute in the Slapi_Entry with the "userdn".
+ **
+ ** Ex: userdn: "cn=prasanta, o= netscape, c= us"
+ ** and in the Slapi_Entry the manager attribute has
+ ** manager = <value>. Compare the userdn with manager.value to
+ ** determine the result.
+ **
+ */
+ s_attrName = attrName = slapi_ch_strdup (attr_pattern);
+
+ /* ignore leading/trailing whitespace */
+ while(ldap_utf8isspace(attrName)) LDAP_UTF8INC(attrName);
+ len = strlen(attrName);
+ ptr = attrName+len-1;
+ while(ldap_utf8isspace(ptr)) { *ptr = '\0'; LDAP_UTF8DEC(ptr); }
+
+
+ /* See if we have a parent[2].attr" rule */
+ if ( (ptr = strstr(attrName, "parent[")) != NULL) {
+ char *word, *str, *next;
+
+ numOflevels = 0;
+ n_currEntryDn = slapi_entry_get_ndn ( lasinfo.resourceEntry );
+ str = attrName;
+
+ word = ldap_utf8strtok_r(str, "[],. ",&next);
+ /* The first word is "parent[" and so it's not important */
+
+ while ((word= ldap_utf8strtok_r(NULL, "[],.", &next)) != NULL) {
+ if (ldap_utf8isdigit(word)) {
+ while (word && ldap_utf8isspace(word)) LDAP_UTF8INC(word);
+ if (numOflevels < ACLLAS_MAX_LEVELS)
+ levels[numOflevels++] = atoi (word);
+ else {
+ /*
+ * Here, ignore the extra levels..it's really
+ * a syntax error which should have been ruled out at parse time
+ */
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
+ "DS_LASUserDnattr: Exceeded the ATTR LIMIT:%d: Ignoring extra levels\n",
+ ACLLAS_MAX_LEVELS);
+ }
+ } else {
+ /* Must be the attr name. We can goof of by
+ ** having parent[1,2,a] but then you have to be
+ ** stupid to do that.
+ */
+ char *p = word;
+ if (*--p == '.') {
+ attrName = word;
+ break;
+ }
+ }
+ }
+ info.attr = attrName;
+ info.clientdn = lasinfo.clientDn;
+ info.result = 0;
+ } else {
+ levels[0] = 0;
+ numOflevels = 1;
+
+ }
+
+ /* No attribute name specified--it's a syntax error and so undefined */
+ if (attrName == NULL ) {
+ slapi_ch_free ( (void**) &s_attrName);
+ return LAS_EVAL_FAIL;
+ }
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,"Attr:%s\n" , attrName, 0,0);
+ matched = ACL_FALSE;
+ for (i=0; i < numOflevels; i++) {
+ if ( levels[i] == 0 ) {
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+ int j;
+
+ /*
+ * For the add operation, the resource itself (level 0)
+ * must never be allowed to grant access--
+ * This is because access would be granted based on a value
+ * of an attribute in the new entry--security hole.
+ *
+ */
+
+ if ( lasinfo.aclpb->aclpb_optype == SLAPI_OPERATION_ADD) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "ACL info: userdnAttr does not allow ADD permission at level 0.\n");
+ got_undefined = 1;
+ continue;
+ }
+ slapi_entry_attr_find( lasinfo.resourceEntry, attrName, &a);
+ if ( NULL == a ) continue;
+ j= slapi_attr_first_value ( a,&sval );
+ while ( j != -1 ) {
+ attrVal = slapi_value_get_berval ( sval );
+ /* Here if atleast 1 value matches then we are done.*/
+ val = slapi_dn_normalize (
+ slapi_ch_strdup( attrVal->bv_val));
+
+ if (slapi_utf8casecmp((ACLUCHP)val, (ACLUCHP)lasinfo.clientDn ) == 0) {
+ char ebuf [ BUFSIZ ];
+ /* Wow it matches */
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "userdnAttr matches(%s, %s) level (%d)\n",
+ val,
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION (lasinfo.clientDn, ebuf),
+ 0);
+ matched = ACL_TRUE;
+ slapi_ch_free ( (void **) &val);
+ break;
+ }
+ slapi_ch_free ( (void**) &val);
+ j = slapi_attr_next_value ( a, j, &sval );
+ }
+ } else {
+ char *p_dn; /* parent dn */
+
+ p_dn = acllas__dn_parent (n_currEntryDn, levels[i]);
+ if (p_dn == NULL) continue;
+
+ /* use new search internal API */
+ {
+ Slapi_PBlock *aPb = slapi_pblock_new ();
+
+ /*
+ * This search may be chained if chaining for ACL is
+ * is enabled in the backend and the entry is in
+ * a chained backend.
+ */
+ slapi_search_internal_set_pb ( aPb,
+ p_dn,
+ LDAP_SCOPE_BASE,
+ "objectclass=*",
+ &attrs[0],
+ 0,
+ NULL /* controls */,
+ NULL /* uniqueid */,
+ aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
+ 0 /* actions */);
+
+ slapi_search_internal_callback_pb(aPb,
+ &info /* callback_data */,
+ NULL/* result_callback */,
+ acllas__verify_client,
+ NULL /* referral_callback */);
+ slapi_pblock_destroy(aPb);
+ }
+
+ /*
+ * Currently info.result is boolean so
+ * we do not need to check for ACL_DONT_KNOW
+ */
+ if (info.result) {
+ matched = ACL_TRUE;
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "userdnAttr matches at level (%d)\n", levels[i]);
+ }
+ }
+ if (matched == ACL_TRUE) {
+ break;
+ }
+ }
+
+ slapi_ch_free ( (void **) &s_attrName);
+
+ /*
+ * If no terms were undefined, then evaluate as normal.
+ * If there was an undefined term, but another one was TRUE, then we also evaluate
+ * as normal. Otherwise, the whole expression is UNDEFINED.
+ */
+ if ( matched == ACL_TRUE || !got_undefined ) {
+ if (comparator == CMP_OP_EQ) {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ } else {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ } else {
+ rc = LAS_EVAL_FAIL;
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Returning UNDEFINED for userdnattr evaluation.\n");
+ }
+
+ return rc;
+}
+/***************************************************************************
+*
+* DS_LASAuthMethodEval
+*
+*
+* Input:
+* attr_name The string "authmethod" - in lower case.
+* comparator CMP_OP_EQ or CMP_OP_NE only
+* attr_pattern A comma-separated list of users
+* cachable Always set to FALSE.
+* subject Subject property list
+* resource Resource property list
+* auth_info Authentication info, if any
+*
+* Returns:
+* retcode The usual LAS return codes.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+DS_LASAuthMethodEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+
+ char *attr;
+ char *ptr;
+ int len;
+ int matched;
+ int rc;
+ char *s = NULL;
+ lasInfo lasinfo;
+
+ if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
+ attr_pattern,cachable,LAS_cookie,
+ subject, resource, auth_info,global_auth,
+ DS_LAS_AUTHMETHOD, "DS_LASAuthMethodEval",
+ &lasinfo )) ) {
+ return LAS_EVAL_FAIL;
+ }
+
+ attr = attr_pattern;
+
+ matched = ACL_FALSE;
+ /* ignore leading whitespace */
+ s = strstr (attr, SLAPD_AUTH_SASL);
+ if ( s) {
+ s +=4;
+ attr = s;
+ }
+
+ while(ldap_utf8isspace(attr)) LDAP_UTF8INC(attr);
+ len = strlen(attr);
+ ptr = attr+len-1;
+ while(ldap_utf8isspace(ptr)) { *ptr = '\0'; LDAP_UTF8DEC(ptr); }
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASAuthMethodEval:authtype:%s authmethod:%s\n",
+ lasinfo.authType, attr);
+
+ /* None method means, we don't care -- otherwise we care */
+ if ((strcasecmp(attr, "none") == 0) ||
+ (strcasecmp(attr, lasinfo.authType) == 0)) {
+ matched = ACL_TRUE;
+ }
+
+ if ( matched == ACL_TRUE || matched == ACL_FALSE) {
+ if (comparator == CMP_OP_EQ) {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ } else {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ } else {
+ rc = LAS_EVAL_FAIL;
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Returning UNDEFINED for authmethod evaluation.\n");
+ }
+
+ return rc;
+}
+
+/****************************************************************************
+* Struct to evaluate and keep the current members being evaluated
+*
+* 0 1 2 3 4 5
+* member: [a,b,c,d,e,f]
+* c_idx may point to 2 i.e to "c" if "c" is being evaluated to
+* see if any of "c" members is the clientDN.
+* lu_idx points to the last used spot i.e 5.
+* lu_idx++ is the next free spot.
+*
+* We allocate ACLLAS_MAX_GRP_MEMBER ptr first and then we add if it
+* is required.
+*
+***************************************************************************/
+#define ACLLAS_MAX_GRP_MEMBER 50
+struct member_info
+{
+ char *member; /* member DN */
+ struct member_info *parent; /* parent of this member */
+} member_info;
+
+struct eval_info
+{
+ int result; /* result status */
+ char *userDN; /* client's normalized DN */
+ int c_idx; /* Index to the current member being processed */
+ int lu_idx; /* Index to the slot where the last member is stored */
+ char **member; /* mmebers list */
+ struct member_info **memberInfo;/* array of memberInfo */
+ CERTCertificate *clientCert; /* ptr to cert */
+ struct acl_pblock *aclpb; /*aclpblock */
+} eval_info;
+
+static void
+dump_member_info ( struct member_info *minfo, char *buf )
+{
+ if ( minfo )
+ {
+ if ( minfo->parent )
+ {
+ dump_member_info ( minfo->parent, buf );
+ }
+ else
+ {
+ strcat ( buf, "<nil>" );
+ }
+ strcat ( buf, "->" );
+ strcat ( buf, minfo->member );
+ }
+}
+
+static void
+dump_eval_info (char *caller, struct eval_info *info, int idx)
+{
+ char buf[1024];
+ int len;
+ int i;
+
+ if ( idx < 0 )
+ {
+ sprintf ( buf, "\nuserDN=\"%s\"\nmember=", info->userDN);
+ if (info->member)
+ {
+ len = strlen (buf);
+ sprintf ( &(buf[len]), "\"%s\"", info->member );
+ }
+ len = strlen (buf);
+ sprintf ( &(buf[len]), "\nmemberinfo[%d]-[%d]:", info->c_idx, info->lu_idx );
+ if ( info->memberInfo )
+ for (i = 0; i <= info->lu_idx; i++)
+ {
+ len = strlen(buf);
+ sprintf ( &buf[len], "\n [%d]: ", i );
+ dump_member_info ( info->memberInfo[i], buf );
+ }
+ slapi_log_error ( SLAPI_LOG_FATAL, NULL, "\n======== candidate member info in eval_info ========%s\n\n", buf );
+ }
+ else
+ {
+ sprintf (buf, "evaluated candidate [%d]=", idx);
+ switch (info->result)
+ {
+ case ACL_TRUE:
+ strcat (buf, "ACL_TRUE\n");
+ break;
+ case ACL_FALSE:
+ strcat (buf, "ACL_FALSE\n");
+ break;
+ case ACL_DONT_KNOW:
+ strcat (buf, "ACL_DONT_KNOW\n");
+ break;
+ default:
+ len = strlen (buf);
+ sprintf ( &(buf[len]), "%d\n", info->result );
+ break;
+ }
+ dump_member_info ( info->memberInfo[idx], buf );
+ slapi_log_error ( SLAPI_LOG_FATAL, NULL, "%s\n", buf );
+ }
+}
+
+
+/***************************************************************************
+*
+* acllas__user_ismember_of_group
+*
+* Check if the user is a member of the group and nested groups..
+*
+* Input:
+* char *groupdn - DN of the group
+* char *clientDN - Dn of the client
+*
+* Returns:
+* ACL_TRUE - the user is a member of the group.
+* ACL_FALSE - Not a member
+* ACL_DONT_KNOW - Any errors eg. resource limits exceeded and we could
+* not compelte the evaluation.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+static int
+acllas__user_ismember_of_group( struct acl_pblock *aclpb,
+ char* groupDN,
+ char* clientDN,
+ int cache_status,
+ CERTCertificate *clientCert)
+{
+
+
+ char *attrs[5];
+ char *currDN;
+ int i,j;
+ int result = ACL_FALSE;
+ struct eval_info info;
+ int nesting_level;
+ int numOfMembersAtCurrentLevel;
+ int numOfMembersVisited;
+ int totalMembersVisited;
+ int numOfMembers;
+ int max_nestlevel;
+ int max_memberlimit;
+ aclUserGroup *u_group;
+ char ebuf [ BUFSIZ ];
+ struct member_info *groupMember = NULL;
+ struct member_info *parentGroup = NULL;
+
+ /*
+ ** First, Let's look thru the cached list and determine if the client is
+ ** a member of the cached list of groups.
+ */
+ if ( (u_group = aclg_get_usersGroup ( aclpb , clientDN )) == NULL) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Failed to find/allocate a usergroup--aborting evaluation\n", 0, 0);
+ return(ACL_DONT_KNOW);
+ }
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluating user %s in group %s?\n",
+ clientDN, groupDN );
+
+ /* Before I start using, get a reader lock on the group cache */
+ aclg_lock_groupCache ( 1 /* reader */ );
+ for ( i= 0; i < u_group->aclug_numof_member_group; i++) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "-- In %s\n",
+ u_group->aclug_member_groups[i] );
+ if ( slapi_utf8casecmp((ACLUCHP)groupDN, (ACLUCHP)u_group->aclug_member_groups[i]) == 0){
+ aclg_unlock_groupCache ( 1 /* reader */ );
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluated ACL_TRUE\n");
+ return ACL_TRUE;
+ }
+ }
+
+ /* see if we know the client is not a member of a group. */
+ for ( i= 0; i < u_group->aclug_numof_notmember_group; i++) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "-- Not in %s\n",
+ u_group->aclug_notmember_groups[i] );
+ if ( slapi_utf8casecmp((ACLUCHP)groupDN, (ACLUCHP)u_group->aclug_notmember_groups[i]) == 0){
+ aclg_unlock_groupCache ( 1 /* reader */ );
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluated ACL_FALSE\n");
+ return ACL_FALSE;
+ }
+ }
+
+ /*
+ ** That means we didn't find the the group in the cache. -- we have to add it
+ ** so no need for READ lock - need to get a WRITE lock. We will get it just before
+ ** modifying it.
+ */
+ aclg_unlock_groupCache ( 1 /* reader */ );
+
+ /* Indicate the initialization handler -- this module will be
+ ** called by the backend to evaluate the entry.
+ */
+ info.result = ACL_FALSE;
+ if (clientDN && *clientDN != '\0')
+ info.userDN = clientDN;
+ else
+ info.userDN = NULL;
+
+ info.c_idx = 0;
+ info.memberInfo = (struct member_info **) slapi_ch_malloc (ACLLAS_MAX_GRP_MEMBER * sizeof(struct member_info *));
+ groupMember = (struct member_info *) slapi_ch_malloc ( sizeof (struct member_info) );
+ groupMember->member = slapi_ch_strdup(groupDN);
+ groupMember->parent = NULL;
+ info.memberInfo[0] = groupMember;
+ info.lu_idx = 0;
+
+ attrs[0] = type_member;
+ attrs[1] = type_uniquemember;
+ attrs[2] = type_memberURL;
+ attrs[3] = type_memberCert;
+ attrs[4] = NULL;
+
+ currDN = groupMember->member;
+
+ /* nesting level is 0 to begin with */
+ nesting_level = 0;
+ numOfMembersVisited = 0;
+ totalMembersVisited = 0;
+ numOfMembersAtCurrentLevel = 1;
+
+ if (clientCert)
+ info.clientCert = clientCert;
+ else
+ info.clientCert = NULL;
+ info.aclpb = aclpb;
+
+ max_memberlimit = aclpb->aclpb_max_member_sizelimit;
+ max_nestlevel = aclpb->aclpb_max_nesting_level;
+
+ /* dump_eval_info ( "acllas__user_ismember_of_group", &info, -1 ); */
+
+eval_another_member:
+
+ numOfMembers = info.lu_idx - info.c_idx;
+
+ /* Use new search internal API */
+ {
+ Slapi_PBlock * aPb = slapi_pblock_new ();
+
+ /*
+ * This search may NOT be chained--we demand that group
+ * definition be local.
+ */
+ slapi_search_internal_set_pb ( aPb,
+ currDN,
+ LDAP_SCOPE_BASE,
+ filter_groups,
+ &attrs[0],
+ 0,
+ NULL /* controls */,
+ NULL /* uniqueid */,
+ aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
+ SLAPI_OP_FLAG_NEVER_CHAIN /* actions */);
+ slapi_search_internal_callback_pb(aPb,
+ &info /* callback_data */,
+ NULL/* result_callback */,
+ acllas__handle_group_entry,
+ NULL /* referral_callback */);
+
+ if ( info.result == ACL_TRUE )
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,"-- In %s\n", info.memberInfo[info.c_idx]->member );
+ else if ( info.result == ACL_FALSE )
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,"-- Not in %s\n", info.memberInfo[info.c_idx]->member );
+
+ slapi_pblock_destroy (aPb);
+ }
+
+ if (info.result == ACL_TRUE) {
+ /*
+ ** that means the client is a member of the
+ ** group or one of the nested groups. We are done.
+ */
+ result = ACL_TRUE;
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluated ACL_TRUE\n");
+ goto free_and_return;
+ }
+ numOfMembersVisited++;
+
+ if (numOfMembersVisited == numOfMembersAtCurrentLevel) {
+ /* This means we have looked at all the members for this level */
+ numOfMembersVisited = 0;
+
+ /* Now we are ready to look at the next level */
+ nesting_level++;
+
+ /* So, far we have visited ... */
+ totalMembersVisited += numOfMembersAtCurrentLevel;
+
+ /* How many members in the next level ? */
+ numOfMembersAtCurrentLevel =
+ info.lu_idx - totalMembersVisited +1;
+ }
+
+ if ((nesting_level > max_nestlevel)) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "GroupEval:Member not found within the allowed nesting level (Allowed:%d Looked at:%d)\n",
+ max_nestlevel, nesting_level, 0);
+
+ result = ACL_DONT_KNOW; /* don't try to cache info based on this result */
+ goto free_and_return;
+ }
+
+ /* limit of -1 means "no limit */
+ if (info.c_idx > max_memberlimit &&
+ max_memberlimit != -1 ) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "GroupEval:Looked at too many entries:(%d, %d)\n",
+ info.c_idx, info.lu_idx,0);
+ result = ACL_DONT_KNOW; /* don't try to cache info based on this result */
+ goto free_and_return;
+ }
+ if (info.lu_idx > info.c_idx) {
+ if (numOfMembers == (info.lu_idx - info.c_idx)) {
+ /* That means it's not a GROUP. It is just another
+ ** useless member which doesn't match. Remove the BAD dude.
+ */
+ groupMember = info.memberInfo[info.c_idx];
+
+ if (groupMember ) {
+ if ( groupMember->member ) slapi_ch_free ( (void **) &groupMember->member );
+ slapi_ch_free ( (void **) &groupMember );
+ info.memberInfo[info.c_idx] = NULL;
+ }
+ }
+ info.c_idx++;
+
+ /* Go thru the stack and see if we have already
+ ** evaluated this group. If we have, then skip it.
+ */
+ while (1) {
+ int evalNext=0;
+ int j;
+ if (info.c_idx > info.lu_idx) {
+ /* That means we have crossed the limit. We
+ ** may end of in this situation if we
+ ** have circular groups
+ */
+ info.c_idx = info.lu_idx;
+ goto free_and_return;
+ }
+
+ /* Break out of the loop if we have searched to the end */
+ groupMember = info.memberInfo[info.c_idx];
+ if ( (NULL == groupMember) || ((currDN = groupMember->member)!= NULL))
+ break;
+
+ for (j = 0; j < info.c_idx; j++) {
+ groupMember = info.memberInfo[j];
+ if (groupMember->member &&
+ (slapi_utf8casecmp((ACLUCHP)currDN, (ACLUCHP)groupMember->member) == 0)) {
+ /* Don't need the duplicate */
+ groupMember = info.memberInfo[info.c_idx];
+ slapi_ch_free ( (void **) &groupMember->member );
+ slapi_ch_free ( (void **) &groupMember );
+ info.memberInfo[info.c_idx] = NULL;
+ info.c_idx++;
+ evalNext=1;
+ break;
+ }
+ }
+ if (!evalNext) break;
+ }
+ /* Make sure that we have a valid DN to chug along */
+ groupMember = info.memberInfo[info.c_idx];
+ if ((info.c_idx <= info.lu_idx) && ((currDN = groupMember->member) != NULL))
+ goto eval_another_member;
+ }
+
+free_and_return:
+ /* Remove the unnecessary members from the list which
+ ** we might have accumulated during the last execution
+ ** and we don't need to look at them.
+ */
+ i = info.c_idx;
+ i++;
+ while (i <= info.lu_idx) {
+ groupMember = info.memberInfo[i];
+ slapi_ch_free ( (void **) &groupMember->member );
+ slapi_ch_free ( (void **) &groupMember );
+ info.memberInfo[i] = NULL;
+ i++;
+ }
+
+ /*
+ ** Now we have a list which has all the groups
+ ** which we need to cache
+ */
+ info.lu_idx = info.c_idx;
+
+ /* since we are updating the groupcache, get a write lock */
+ aclg_lock_groupCache ( 2 /* writer */ );
+
+ /*
+ ** Keep the result of the evaluation in the cache.
+ ** We have 2 lists: member_of and not_member_of. We can use this
+ ** cached information next time we evaluate groups.
+ */
+ if (result == ACL_TRUE &&
+ (cache_status & ACLLAS_CACHE_MEMBER_GROUPS)) {
+ int ngr = 0;
+
+ /* get the last group which the user is a member of */
+ groupMember = info.memberInfo[info.c_idx];
+
+ while ( groupMember ) {
+ int already_cached = 0;
+
+ parentGroup = groupMember->parent;
+ for (j=0; j < u_group->aclug_numof_member_group;j++){
+ if (slapi_utf8casecmp( (ACLUCHP)groupMember->member,
+ (ACLUCHP)u_group->aclug_member_groups[j]) == 0) {
+ already_cached = 1;
+ break;
+ }
+ }
+ if (already_cached) {
+ groupMember = parentGroup;
+ parentGroup = NULL;
+ continue;
+ }
+
+ ngr = u_group->aclug_numof_member_group++;
+ if (u_group->aclug_numof_member_group >=
+ u_group->aclug_member_group_size){
+ u_group->aclug_member_groups =
+ (char **) slapi_ch_realloc (
+ (void *) u_group->aclug_member_groups,
+ (u_group->aclug_member_group_size +
+ ACLUG_INCR_GROUPS_LIST) *
+ sizeof (char *));
+ u_group->aclug_member_group_size +=
+ ACLUG_INCR_GROUPS_LIST;
+ }
+ u_group->aclug_member_groups[ngr] = slapi_ch_strdup ( groupMember->member );
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Adding Group (%s) ParentGroup (%s) to the IN GROUP List\n",
+ groupMember->member , parentGroup ? parentGroup->member: "NULL");
+
+ groupMember = parentGroup;
+ parentGroup = NULL;
+ }
+ } else if (result == ACL_FALSE &&
+ (cache_status & ACLLAS_CACHE_NOT_MEMBER_GROUPS)) {
+ int ngr = 0;
+
+ /* NOT IN THE GROUP LIST */
+ /* get the last group which the user is a member of */
+ groupMember = info.memberInfo[info.c_idx];
+
+ while ( groupMember ) {
+ int already_cached = 0;
+
+ parentGroup = groupMember->parent;
+ for (j=0; j < u_group->aclug_numof_notmember_group;j++){
+ if (slapi_utf8casecmp( (ACLUCHP)groupMember->member,
+ (ACLUCHP)u_group->aclug_notmember_groups[j]) == 0) {
+ already_cached = 1;
+ break;
+ }
+ }
+ if (already_cached) {
+ groupMember = parentGroup;
+ parentGroup = NULL;
+ continue;
+ }
+
+ ngr = u_group->aclug_numof_notmember_group++;
+ if (u_group->aclug_numof_notmember_group >=
+ u_group->aclug_notmember_group_size){
+ u_group->aclug_notmember_groups =
+ (char **) slapi_ch_realloc (
+ (void *) u_group->aclug_notmember_groups,
+ (u_group->aclug_notmember_group_size +
+ ACLUG_INCR_GROUPS_LIST) *
+ sizeof (char *));
+ u_group->aclug_notmember_group_size +=
+ ACLUG_INCR_GROUPS_LIST;
+ }
+ u_group->aclug_notmember_groups[ngr] = slapi_ch_strdup ( groupMember->member );
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Adding Group (%s) ParentGroup (%s) to the NOT IN GROUP List\n",
+ groupMember->member , parentGroup ? parentGroup->member: "NULL");
+
+ groupMember = parentGroup;
+ parentGroup = NULL;
+ }
+ } else if ( result == ACL_DONT_KNOW ) {
+
+ /*
+ * We terminated the search without reaching a conclusion--so
+ * don't cache any info based on this evaluation.
+ */
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "Evaluated ACL_DONT_KNOW\n");
+ }
+
+ /* Unlock the group cache, we are done with updating */
+ aclg_unlock_groupCache ( 2 /* writer */ );
+
+ for (i=0; i <= info.lu_idx; i++) {
+ groupMember = info.memberInfo[i];
+ if ( NULL == groupMember ) continue;
+
+ slapi_ch_free ( (void **) &groupMember->member );
+ slapi_ch_free ( (void **) &groupMember );
+ }
+
+ /* free the pointer array.*/
+ slapi_ch_free ( (void **) &info.memberInfo);
+ return result;
+}
+
+/***************************************************************************
+*
+* acllas__handle_group_entry
+*
+* handler called. Compares the userdn value and determines if it's
+* a member of not.
+*
+* Input:
+*
+*
+* Returns:
+*
+* Error Handling:
+*
+**************************************************************************/
+static int
+acllas__handle_group_entry (Slapi_Entry* e, void *callback_data)
+{
+ struct eval_info *info;
+ Slapi_Attr *currAttr, *nextAttr;
+ char *n_dn, *attrType;
+ short n;
+ int i;
+
+ info = (struct eval_info *) callback_data;
+ info->result = ACL_FALSE;
+
+ if (e == NULL) {
+ return 0;
+ }
+
+ slapi_entry_first_attr ( e, &currAttr);
+ if ( NULL == currAttr ) return 0;
+
+ slapi_attr_get_type ( currAttr, &attrType );
+ if (NULL == attrType ) return 0;
+
+ do {
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+
+ if ((strcasecmp (attrType, type_member) == 0) ||
+ (strcasecmp (attrType, type_uniquemember) == 0 )) {
+
+ i = slapi_attr_first_value ( currAttr,&sval );
+ while ( i != -1 ) {
+ struct member_info *groupMember = NULL;
+ attrVal = slapi_value_get_berval ( sval );
+ n_dn = slapi_dn_normalize ( slapi_ch_strdup( attrVal->bv_val));
+ info->lu_idx++;
+ n = info->lu_idx;
+ if (!(n % ACLLAS_MAX_GRP_MEMBER)) {
+ info->memberInfo = (struct member_info **) slapi_ch_realloc(
+ (void *) info->memberInfo,
+ (n+ACLLAS_MAX_GRP_MEMBER) *
+ sizeof(struct eval_info *));
+ }
+
+ /* allocate the space for the member and attch it to the list */
+ groupMember = (struct member_info *) slapi_ch_malloc ( sizeof ( struct member_info ) );
+ groupMember->member = n_dn;
+ groupMember->parent = info->memberInfo[info->c_idx];
+ info->memberInfo[n] = groupMember;
+
+ if (info->userDN &&
+ slapi_utf8casecmp((ACLUCHP)n_dn, (ACLUCHP)info->userDN) == 0) {
+ info->result = ACL_TRUE;
+ return 0;
+ }
+ i = slapi_attr_next_value ( currAttr, i, &sval );
+ }
+ /* Evaluate Dynamic groups */
+ } else if (strcasecmp ( attrType, type_memberURL) == 0) {
+ char *memberURL, *savURL;
+
+ if (!info->userDN) continue;
+
+ i= slapi_attr_first_value ( currAttr,&sval );
+ while ( i != -1 ) {
+ attrVal = slapi_value_get_berval ( sval );
+ /*
+ * memberURL may start with "ldap:///" or "ldap://host:port"
+ * ldap://localhost:11000/o=ace industry,c=us??
+ * or
+ * ldap:///o=ace industry,c=us??
+ */
+ if (strncasecmp( attrVal->bv_val, "ldap://",7) == 0 ||
+ strncasecmp( attrVal->bv_val, "ldaps://",8) == 0) {
+ savURL = memberURL = slapi_ch_strdup ( attrVal->bv_val);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "ACL Group Eval:MemberURL:%s\n", memberURL);
+ info->result = acllas__client_match_URL (
+ info->aclpb,
+ info->userDN,
+ memberURL);
+ slapi_ch_free ( (void**) &savURL);
+ if (info->result == ACL_TRUE)
+ return 0;
+ } else {
+ /* This means that the URL is ill-formed */
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "ACL Group Eval:Badly Formed MemberURL:%s\n", attrVal->bv_val);
+ }
+ i = slapi_attr_next_value ( currAttr, i, &sval );
+ }
+ /* Evaluate Fortezza groups */
+ } else if ((strcasecmp (attrType, type_memberCert) == 0) ) {
+ /* Do we have the certificate around */
+ if (!info->clientCert) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ " acllas__handle_group_entry:Client Cert missing\n" );
+ continue;
+ }
+ i = slapi_attr_first_value ( currAttr,&sval );
+ while ( i != -1 ) {
+ attrVal = slapi_value_get_berval ( sval );
+ if (ldapu_member_certificate_match (
+ info->clientCert,
+ attrVal->bv_val) == LDAP_SUCCESS) {
+ info->result = ACL_TRUE;
+ return 0;
+ }
+ i = slapi_attr_next_value ( currAttr, i, &sval );
+ }
+ }
+
+ attrType = NULL;
+ /* get the next attr */
+ slapi_entry_next_attr ( e, currAttr, &nextAttr );
+ if ( NULL == nextAttr ) break;
+
+ currAttr = nextAttr;
+ slapi_attr_get_type ( currAttr, &attrType );
+
+ } while ( NULL != attrType );
+
+ return 0;
+}
+/***************************************************************************
+*
+* DS_LASGroupDnAttrEval
+*
+*
+* Input:
+* attr_name The string "groupdnattr" - in lower case.
+* comparator CMP_OP_EQ or CMP_OP_NE only
+* attr_pattern A comma-separated list of users
+* cachable Always set to FALSE.
+* subject Subject property list
+* resource Resource property list
+* auth_info Authentication info, if any
+*
+* Returns:
+* retcode The usual LAS return codes.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+struct groupdnattr_info
+{
+ char *attrName; /* name of the attribute */
+ int numofGroups; /* number of groups */
+ char **member;
+};
+int
+DS_LASGroupDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+
+ char *s_attrName = NULL;
+ char *attrName;
+ char *ptr;
+ int matched;
+ int rc;
+ int len;
+ Slapi_Attr *attr;
+ int levels[ACLLAS_MAX_LEVELS];
+ int numOflevels = 0;
+ char *n_currEntryDn = NULL;
+ lasInfo lasinfo;
+ int got_undefined = 0;
+
+ if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
+ attr_pattern,cachable,LAS_cookie,
+ subject, resource, auth_info,global_auth,
+ DS_LAS_GROUPDNATTR, "DS_LASGroupDnAttrEval",
+ &lasinfo )) ) {
+ return LAS_EVAL_FAIL;
+ }
+
+ /* For anonymous client, the answer is XXX come back to this */
+ if ( lasinfo.anomUser )
+ return LAS_EVAL_FALSE;
+
+ /*
+ ** The groupdnAttr syntax is
+ ** groupdnattr = <attribute>
+ ** Ex:
+ ** groupdnattr = SIEmanager;
+ **
+ ** The function of this LAS is to find out if the client belongs
+ ** to any group that is specified in the attr.
+ */
+ attrName = attr_pattern;
+ if (strstr(attrName, LDAP_URL_prefix)) {
+ char *s;
+
+
+ /* In this case "grppupdnattr="ldap:///base??attr" */
+
+ if ((s = strstr (attrName, ACL_RULE_MACRO_DN_KEY)) != NULL ||
+ (s = strstr (attrName, ACL_RULE_MACRO_DN_LEVELS_KEY)) != NULL ||
+ (s = strstr (attrName, ACL_RULE_MACRO_ATTR_KEY)) != NULL) {
+
+ matched = aclutil_evaluate_macro( attrName, &lasinfo,
+ ACL_EVAL_GROUPDNATTR);
+ } else{
+
+ matched = acllas__eval_memberGroupDnAttr(attrName,
+ lasinfo.resourceEntry,
+ lasinfo.clientDn,
+ lasinfo.aclpb);
+ }
+ if ( matched == ACL_DONT_KNOW) {
+ got_undefined = 1;
+ }
+ } else {
+ int i;
+ char *n_groupdn;
+
+ /* ignore leading/trailing whitespace */
+ while(ldap_utf8isspace(attrName)) LDAP_UTF8INC(attrName);
+ len = strlen(attrName);
+ ptr = attrName+len-1;
+ while(ldap_utf8isspace(ptr)) { *ptr = '\0'; LDAP_UTF8DEC(ptr); }
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,"Attr:%s\n" , attrName, 0,0);
+
+ /* See if we have a parent[2].attr" rule */
+ if ( (ptr = strstr(attrName, "parent[")) != NULL) {
+ char *word, *str, *next;
+
+ numOflevels = 0;
+ n_currEntryDn = slapi_entry_get_ndn ( lasinfo.resourceEntry ) ;
+ s_attrName = attrName = slapi_ch_strdup ( attr_pattern );
+ str = attrName;
+
+ word = ldap_utf8strtok_r(str, "[],. ",&next);
+ /* The first word is "parent[" and so it's not important */
+
+ while ((word= ldap_utf8strtok_r(NULL, "[],.", &next)) != NULL) {
+ if (ldap_utf8isdigit(word)) {
+ while (word && ldap_utf8isspace(word)) LDAP_UTF8INC(word);
+ if (numOflevels < ACLLAS_MAX_LEVELS)
+ levels[numOflevels++] = atoi (word);
+ else {
+ /*
+ * Here, ignore the extra levels..it's really
+ * a syntax error which should have been ruled out at parse time
+ */
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
+ "DS_LASGroupDnattr: Exceeded the ATTR LIMIT:%d: Ignoring extra levels\n",
+ ACLLAS_MAX_LEVELS,0,0);
+ }
+ } else {
+ /* Must be the attr name. We can goof of by
+ ** having parent[1,2,a] but then you have to be
+ ** stupid to do that.
+ */
+ char *p = word;
+ if (*--p == '.') {
+ attrName = word;
+ break;
+ }
+ }
+ }
+ } else {
+ levels[0] = 0;
+ numOflevels = 1;
+ }
+
+ matched = ACL_FALSE;
+ for (i=0; i < numOflevels; i++) {
+ if ( levels[i] == 0 ) {
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+ int attr_i;
+
+ /*
+ * For the add operation, the resource itself (level 0)
+ * must never be allowed to grant access--
+ * This is because access would be granted based on a value
+ * of an attribute in the new entry--security hole.
+ * XXX is this therefore FALSE or DONT_KNOW ?
+ */
+
+ if ( lasinfo.aclpb->aclpb_optype == SLAPI_OPERATION_ADD) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "ACL info: groupdnAttr does not allow ADD permission at level 0.\n");
+ got_undefined = 1;
+ continue;
+ }
+ slapi_entry_attr_find ( lasinfo.resourceEntry, attrName, &attr);
+ if ( !attr) continue;
+ attr_i= slapi_attr_first_value ( attr,&sval );
+ while ( attr_i != -1 ) {
+ attrVal = slapi_value_get_berval ( sval );
+ n_groupdn = slapi_dn_normalize(
+ slapi_ch_strdup( attrVal->bv_val));
+ matched = acllas__user_ismember_of_group (
+ lasinfo.aclpb, n_groupdn, lasinfo.clientDn,
+ ACLLAS_CACHE_MEMBER_GROUPS,
+ lasinfo.aclpb->aclpb_clientcert);
+ slapi_ch_free ( (void **) &n_groupdn);
+ if (matched == ACL_TRUE ) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "groupdnattr matches at level (%d)\n", levels[i]);
+ break;
+ } else if ( matched == ACL_DONT_KNOW ) {
+ /* record this but keep going--maybe another group will evaluate to TRUE */
+ got_undefined = 1;
+ }
+ attr_i= slapi_attr_next_value ( attr, attr_i, &sval );
+ }
+ } else {
+ char *p_dn;
+ struct groupdnattr_info info;
+ char *attrs[2];
+ int j;
+
+ info.numofGroups = 0;
+ attrs[0] = info.attrName = attrName;
+ attrs[1] = NULL;
+
+ p_dn = acllas__dn_parent (n_currEntryDn, levels[i]);
+
+ if (p_dn == NULL) continue;
+
+ /* Use new search internal API */
+ {
+
+ Slapi_PBlock *aPb = slapi_pblock_new ();
+ /*
+ * This search may NOT be chained--if the user's definition is
+ * remote and the group is dynamic and the user entry
+ * changes then we would not notice--so don't go
+ * find the user entry in the first place.
+ */
+ slapi_search_internal_set_pb ( aPb,
+ p_dn,
+ LDAP_SCOPE_BASE,
+ "objectclass=*",
+ &attrs[0],
+ 0,
+ NULL /* controls */,
+ NULL /* uniqueid */,
+ aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
+ SLAPI_OP_FLAG_NEVER_CHAIN /* actions */);
+ slapi_search_internal_callback_pb(aPb,
+ &info /* callback_data */,
+ NULL/* result_callback */,
+ acllas__get_members,
+ NULL /* referral_callback */);
+ slapi_pblock_destroy (aPb);
+ }
+
+ if (info.numofGroups <= 0) {
+ continue;
+ }
+ for (j=0; j <info.numofGroups; j++) {
+ if (slapi_utf8casecmp((ACLUCHP)info.member[j],
+ (ACLUCHP)lasinfo.clientDn) == 0) {
+ matched = ACL_TRUE;
+ break;
+ }
+ matched = acllas__user_ismember_of_group (
+ lasinfo.aclpb, info.member[j],
+ lasinfo.clientDn, ACLLAS_CACHE_ALL_GROUPS,
+ lasinfo.aclpb->aclpb_clientcert);
+ if (matched == ACL_TRUE) {
+ break;
+ } else if ( matched == ACL_DONT_KNOW ) {
+ /* record this but keep going--maybe another group will evaluate to TRUE */
+ got_undefined = 1;
+ }
+ }
+ /* Deallocate the member array and the member struct */
+ for (j=0; j < info.numofGroups; j++)
+ slapi_ch_free ((void **) &info.member[j]);
+ slapi_ch_free ((void **) &info.member);
+ }
+ if (matched == ACL_TRUE) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "groupdnattr matches at level (%d)\n", levels[i]);
+ break;
+ } else if ( matched == ACL_DONT_KNOW ) {
+ /* record this but keep going--maybe another group at another level
+ * will evaluate to TRUE.
+ */
+ got_undefined = 1;
+ }
+
+ } /* NumofLevels */
+ }
+ if (s_attrName) slapi_ch_free ((void**) &s_attrName );
+
+ /*
+ * If no terms were undefined, then evaluate as normal.
+ * If there was an undefined term, but another one was TRUE, then we also evaluate
+ * as normal. Otherwise, the whole expression is UNDEFINED.
+ */
+ if ( matched == ACL_TRUE || !got_undefined ) {
+ if (comparator == CMP_OP_EQ) {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ } else {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ } else {
+ rc = LAS_EVAL_FAIL;
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Returning UNDEFINED for groupdnattr evaluation.\n");
+ }
+
+ return rc;
+}
+
+/*
+ * acllas__eval_memberGroupDnAttr
+ *
+ * return ACL_TRUE, ACL_FALSE or ACL_DONT_KNOW
+ *
+ * Inverse group evaluation. Find all the groups that the user is a
+ * member of. Find all teh groups that contain those groups. Do an
+ * upward nested level search. By the end of it, we will know all the
+ * groups that the clinet is a member of under that search scope.
+ *
+ * This model seems to be very fast if we have few groups at the
+ * leaf level.
+ *
+ */
+static int
+acllas__eval_memberGroupDnAttr (char *attrName, Slapi_Entry *e,
+ char *n_clientdn, struct acl_pblock *aclpb)
+{
+
+ Slapi_Attr *attr;
+ char *s, *p;
+ char *str, *s_str, *base, *groupattr;
+ int i,j,k,matched, enumerate_groups;
+ aclUserGroup *u_group;
+ char ebuf [ BUFSIZ ];
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+
+ /* Parse the URL -- We can't use the ldap_url_parse()
+ ** we don't follow thw complete url naming scheme
+ */
+ s_str = str = slapi_ch_strdup(attrName);
+ while (str && ldap_utf8isspace(str)) LDAP_UTF8INC( str );
+ str +=8;
+ s = strchr (str, '?');
+ if (s) {
+ p = s;
+ p++;
+ *s = '\0';
+ base = str;
+ s = strchr (p, '?');
+ if (s) *s = '\0';
+
+ groupattr = p;
+ } else {
+ slapi_ch_free ( (void **)&s_str );
+ return ACL_FALSE;
+ }
+
+ if ( (u_group = aclg_get_usersGroup ( aclpb , n_clientdn )) == NULL) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "Failed to find/allocate a usergroup--aborting evaluation\n", 0, 0);
+ slapi_ch_free ( (void **)&s_str );
+ return(ACL_DONT_KNOW);
+ }
+
+ /*
+ ** First find out if we have already searched this base or
+ ** if we are searching a subtree to an already enumerated base.
+ */
+ enumerate_groups = 1;
+ for (j=0; j < aclpb->aclpb_numof_bases; j++) {
+ if (slapi_dn_issuffix(aclpb->aclpb_grpsearchbase[j], base)) {
+ enumerate_groups = 0;
+ break;
+ }
+ }
+
+
+ /* See if we have already enumerated all the groups which the
+ ** client is a member of.
+ */
+ if (enumerate_groups) {
+ char filter_str[BUFSIZ];
+ char *attrs[3];
+ struct eval_info info;
+ char *curMemberDn;
+ int Done = 0;
+ int ngr, tt;
+
+ /* Add the scope to the list of scopes */
+ if (aclpb->aclpb_numof_bases >= (aclpb->aclpb_grpsearchbase_size-1)) {
+ aclpb->aclpb_grpsearchbase = (char **)
+ slapi_ch_realloc (
+ (void *) aclpb->aclpb_grpsearchbase,
+ (aclpb->aclpb_grpsearchbase_size +
+ ACLPB_INCR_BASES) *
+ sizeof (char *));
+ aclpb->aclpb_grpsearchbase_size += ACLPB_INCR_BASES;
+ }
+ aclpb->aclpb_grpsearchbase[aclpb->aclpb_numof_bases++] =
+ slapi_dn_normalize(slapi_ch_strdup(base));
+
+ /* Set up info to do a search */
+ attrs[0] = type_member;
+ attrs[1] = type_uniquemember;
+ attrs[2] = NULL;
+
+ info.c_idx = info.lu_idx = 0;
+ info.member =
+ (char **) slapi_ch_malloc (ACLLAS_MAX_GRP_MEMBER * sizeof(char *));
+ curMemberDn = n_clientdn;
+
+ while (!Done) {
+ char *filter_str_ptr = &filter_str[0];
+ char *new_filter_str = NULL;
+ int lenf = strlen(curMemberDn)<<1;
+
+ if (lenf > (BUFSIZ - 28)) { /* 28 for "(|(uniquemember=%s)(member=%s))" */
+ new_filter_str = slapi_ch_malloc(lenf + 28);
+ filter_str_ptr = new_filter_str;
+ }
+
+ /*
+ ** Search the db for groups that the client is a member of.
+ ** Once found cache it. cache only unique groups.
+ */
+ tt = info.lu_idx;
+ sprintf (filter_str_ptr,"(|(uniquemember=%s)(member=%s))",
+ curMemberDn, curMemberDn);
+
+ /* Use new search internal API */
+ {
+ Slapi_PBlock *aPb = slapi_pblock_new ();
+ /*
+ * This search may NOT be chained--we demand that group
+ * definition be local.
+ */
+ slapi_search_internal_set_pb ( aPb,
+ base,
+ LDAP_SCOPE_SUBTREE,
+ filter_str_ptr,
+ &attrs[0],
+ 0,
+ NULL /* controls */,
+ NULL /* uniqueid */,
+ aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
+ SLAPI_OP_FLAG_NEVER_CHAIN /* actions */);
+ slapi_search_internal_callback_pb(aPb,
+ &info /* callback_data */,
+ NULL/* result_callback */,
+ acllas__add_allgroups,
+ NULL /* referral_callback */);
+ slapi_pblock_destroy (aPb);
+ }
+
+ if (new_filter_str) slapi_ch_free((void **) &new_filter_str);
+
+ if (tt == info.lu_idx) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name, "currDn:(%s) \n\tNO MEMBER ADDED\n",
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION (curMemberDn, ebuf) , 0,0);
+ } else {
+ for (i=tt; i < info.lu_idx; i++)
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "currDn:(%s) \n\tADDED MEMBER[%d]=%s\n",
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION (curMemberDn, ebuf), i, info.member[i]);
+ }
+
+ if (info.c_idx >= info.lu_idx) {
+ for (i=0; i < info.lu_idx; i++) {
+ int already_cached = 0;
+ for (j=0; j < u_group->aclug_numof_member_group;
+ j++){
+ if (slapi_utf8casecmp(
+ (ACLUCHP)info.member[i],
+ (ACLUCHP)u_group->aclug_member_groups[j]) == 0) {
+ slapi_ch_free ((void **) &info.member[i] );
+ info.member[i] = NULL;
+ already_cached = 1;
+ break;
+ }
+
+ }
+
+ if (already_cached) continue;
+
+ ngr = u_group->aclug_numof_member_group++;
+ if (u_group->aclug_numof_member_group >=
+ u_group->aclug_member_group_size){
+ u_group->aclug_member_groups =
+ (char **) slapi_ch_realloc (
+ (void *) u_group->aclug_member_groups,
+ (u_group->aclug_member_group_size +
+ ACLUG_INCR_GROUPS_LIST) * sizeof(char *));
+
+ u_group->aclug_member_group_size +=
+ ACLUG_INCR_GROUPS_LIST;
+ }
+ u_group->aclug_member_groups[ngr] = info.member[i];
+ info.member[i] = NULL;
+ }
+ slapi_ch_free ((void **) &info.member);
+ Done = 1;
+ } else {
+ curMemberDn = info.member[info.c_idx];
+ info.c_idx++;
+ }
+ }
+ }
+
+ for (j=0; j < u_group->aclug_numof_member_group; j++)
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "acllas__eval_memberGroupDnAttr:GROUP[%d] IN CACHE:%s\n",
+ j, ACL_ESCAPE_STRING_WITH_PUNCTUATION (u_group->aclug_member_groups[j], ebuf),0);
+
+ matched = ACL_FALSE;
+ slapi_entry_attr_find( e, groupattr, &attr);
+ if (attr == NULL) {
+ slapi_ch_free ( (void **)&s_str );
+ return ACL_FALSE;
+ }
+ {
+ k = slapi_attr_first_value ( attr,&sval );
+ while ( k != -1 ) {
+ char *n_attrval;
+ attrVal = slapi_value_get_berval ( sval );
+ n_attrval = slapi_ch_strdup( attrVal->bv_val);
+ n_attrval = slapi_dn_normalize (n_attrval);
+
+ /* We support: The attribute value can be a USER or a GROUP.
+ ** Let's compare with the client, thi might be just an user. If it is not
+ ** then we test it against the list of groups.
+ */
+ if (slapi_utf8casecmp ((ACLUCHP)n_attrval, (ACLUCHP)n_clientdn) == 0 ) {
+ matched = ACL_TRUE;
+ slapi_ch_free ( (void **)&n_attrval );
+ break;
+ }
+ for (j=0; j <u_group->aclug_numof_member_group; j++) {
+ if ( slapi_utf8casecmp((ACLUCHP)n_attrval,
+ (ACLUCHP)u_group->aclug_member_groups[j]) == 0) {
+ matched = ACL_TRUE;
+ break;
+ }
+ }
+ slapi_ch_free ( (void **)&n_attrval );
+ if (matched == ACL_TRUE) break;
+ k= slapi_attr_next_value ( attr, k, &sval );
+ }
+ }
+ slapi_ch_free ( (void **)&s_str );
+ return matched;
+}
+
+static int
+acllas__add_allgroups (Slapi_Entry* e, void *callback_data)
+{
+ int i, n, m;
+ struct eval_info *info;
+ char *n_dn;
+
+ info = (struct eval_info *) callback_data;
+
+ /*
+ ** Once we are here means this is a valid group. First see
+ ** If we have already seen this group. If not, add it to the
+ ** member list.
+ */
+ n_dn = slapi_ch_strdup ( slapi_entry_get_ndn ( e ) );
+ for (i=0; i < info->lu_idx; i++) {
+ if (slapi_utf8casecmp((ACLUCHP)n_dn, (ACLUCHP)info->member[i]) == 0) {
+ slapi_ch_free ( (void **) &n_dn);
+ return 0;
+ }
+ }
+
+ m = info->lu_idx;
+ n = info->lu_idx++;
+ if (!(n % ACLLAS_MAX_GRP_MEMBER)) {
+ info->member = (char **) slapi_ch_realloc (
+ (void *) info->member,
+ (n+ACLLAS_MAX_GRP_MEMBER) * sizeof(char *));
+ }
+ info->member[m] = n_dn;
+ return 0;
+}
+/*
+ *
+ * acllas__dn_parent
+ *
+ * This code should belong to dn.c. However this is specific to acl and I had
+ * 2 choices 1) create a new API or 2) reuse the slapi_dN_parent
+ *
+ * Returns a ptr to the parent based on the level.
+ *
+ */
+#define DNSEPARATOR(c) (c == ',' || c == ';')
+static char*
+acllas__dn_parent( char *dn, int level)
+{
+ char *s, *dnstr;
+ int inquote;
+ int curLevel;
+ int lastLoop = 0;
+
+ if ( dn == NULL || *dn == '\0' ) {
+ return( NULL );
+ }
+
+ /* An X.500-style name, which looks like foo=bar,sha=baz,... */
+ /* Do we have any dn seprator or not */
+ if ((strchr(dn,',') == NULL) && (strchr(dn,';') == NULL))
+ return (NULL);
+
+ inquote = 0;
+ curLevel = 1;
+ dnstr = dn;
+ while ( curLevel <= level) {
+ if (lastLoop) break;
+ if (curLevel == level) lastLoop = 1;
+ for ( s = dnstr; *s; s++ ) {
+ if ( *s == '\\' ) {
+ if ( *(s + 1) )
+ s++;
+ continue;
+ }
+ if ( inquote ) {
+ if ( *s == '"' )
+ inquote = 0;
+ } else {
+ if ( *s == '"' )
+ inquote = 1;
+ else if ( DNSEPARATOR( *s ) ) {
+ if (curLevel == level)
+ return( s + 1 );
+ dnstr = s + 1;
+ curLevel++;
+ break;
+ }
+ }
+ }
+ if ( *s == '\0') {
+ /* Got to the end of the string without reaching level,
+ * so return NULL.
+ */
+ return(NULL);
+ }
+ }
+
+ return( NULL );
+}
+/*
+ * acllas__verify_client
+ *
+ * returns 1 if the attribute exists in the entry and
+ * it's value is equal to the client Dn.
+ * If the attribute is not in the entry, or it is and the
+ * value differs from the clientDn then returns FALSE.
+ *
+ * Verify if client's DN is stored in the attrbute or not.
+ * This is a handler from a search being done at
+ * DS_LASUserDnAttrEval().
+ *
+ */
+static int
+acllas__verify_client (Slapi_Entry* e, void *callback_data)
+{
+
+ Slapi_Attr *attr;
+ char *val;
+ struct userdnattr_info *info;
+ Slapi_Value *sval;
+ const struct berval *attrVal;
+ int i;
+
+ info = (struct userdnattr_info *) callback_data;
+
+ slapi_entry_attr_find( e, info->attr, &attr);
+ if (attr == NULL) return 0;
+
+ i = slapi_attr_first_value ( attr,&sval );
+ while ( i != -1 ) {
+ attrVal = slapi_value_get_berval ( sval );
+ val = slapi_dn_normalize (
+ slapi_ch_strdup(attrVal->bv_val));
+
+ if (slapi_utf8casecmp((ACLUCHP)val, (ACLUCHP)info->clientdn ) == 0) {
+ info->result = 1;
+ slapi_ch_free ( (void **) &val);
+ return 0;
+ }
+ slapi_ch_free ( (void **) &val);
+ i = slapi_attr_next_value ( attr, i, &sval );
+ }
+ return 0;
+}
+/*
+ *
+ * acllas__get_members
+ *
+ * Collects all the values of the specified attribute which should be group names.
+ */
+static int
+acllas__get_members (Slapi_Entry* e, void *callback_data)
+{
+
+ Slapi_Attr *attr;
+ struct groupdnattr_info *info;
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+ int i;
+
+ info = (struct groupdnattr_info *) callback_data;
+ slapi_entry_attr_find (e, info->attrName, &attr);
+ if ( !attr ) return 0;
+
+ slapi_attr_get_numvalues ( attr, &info->numofGroups );
+
+ info->member = (char **) slapi_ch_malloc (info->numofGroups * sizeof(char *));
+ i = slapi_attr_first_value ( attr,&sval );
+ while ( i != -1 ) {
+ attrVal =slapi_value_get_berval ( sval );
+ info->member[i] = slapi_dn_normalize ( slapi_ch_strdup(attrVal->bv_val));
+ i = slapi_attr_next_value ( attr, i, &sval );
+ }
+ return 0;
+}
+
+/*
+ * DS_LASUserAttrEval
+ * LAS to evaluate the userattr rule
+ *
+ * userAttr = "attrName#Type"
+ *
+ * <Type> ::= "USERDN" | "GROUPDN" | "ROLEDN" | "LDAPURL" | <value>
+ * <value>::== <any printable String>
+ *
+ * Example:
+ * userAttr = "manager#USERDN" --- same as userdnattr
+ * userAttr = "owner#GROUPDN" --- same as groupdnattr
+ * = "ldap:///o=sun.com?owner#GROUPDN
+ * userAttr = "attr#ROLEDN" --- The value of attr contains a roledn
+ * userAttr = "myattr#LDAPURL" --- The value contains a LDAP URL
+ * which can have scope and filter
+ * bits.
+ * userAttr = "OU#Directory Server"
+ * --- In this case the client's OU and the
+ * resource entry's OU must have
+ * "Directory Server" value.
+ *
+ * Returns:
+ * retcode The usual LAS return codes.
+ */
+int
+DS_LASUserAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+
+ char *attrName;
+ char *attrValue = NULL;
+ int rc;
+ int matched = ACL_FALSE;
+ char *p;
+ int URLAttrRule = 0;
+ lasInfo lasinfo;
+ int got_undefined = 0;
+
+ if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
+ attr_pattern,cachable,LAS_cookie,
+ subject, resource, auth_info,global_auth,
+ DS_LAS_USERATTR, "DS_LASUserAttrEval",
+ &lasinfo )) ) {
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Which rule are we evaluating ? */
+ attrName = slapi_ch_strdup (attr_pattern );
+ if ( NULL == (p = strchr ( attrName, '#' ))) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASUserAttrEval:Invalid value(%s)\n", attr_pattern);
+ slapi_ch_free ( (void **) &attrName );
+ return LAS_EVAL_FAIL;
+ }
+ attrValue = p;
+ attrValue++; /* skip the # */
+ *p = '\0'; /* null terminate the attr name */
+
+ if ( 0 == strncasecmp ( attrValue, "USERDN", 6)) {
+ matched = DS_LASUserDnAttrEval (errp,DS_LAS_USERDNATTR, comparator,
+ attrName, cachable, LAS_cookie,
+ subject, resource, auth_info, global_auth);
+ goto done_las;
+ } else if ( 0 == strncasecmp ( attrValue, "GROUPDN", 7)) {
+ matched = DS_LASGroupDnAttrEval (errp,DS_LAS_GROUPDNATTR, comparator,
+ attrName, cachable, LAS_cookie,
+ subject, resource, auth_info, global_auth);
+ goto done_las;
+ } else if ( 0 == strncasecmp ( attrValue, "LDAPURL", 7) ) {
+ URLAttrRule = 1;
+ } else if ( 0 == strncasecmp ( attrValue, "ROLEDN", 6)) {
+ matched = DS_LASRoleDnAttrEval (errp,DS_LAS_ROLEDN, comparator,
+ attrName, cachable, LAS_cookie,
+ subject, resource, auth_info, global_auth);
+ goto done_las;
+ }
+
+ if ( lasinfo.aclpb && ( NULL == lasinfo.aclpb->aclpb_client_entry )) {
+ /* SD 00/16/03 pass NULL in case the req is chained */
+ char **attrs=NULL;
+
+
+ /* Use new search internal API */
+ Slapi_PBlock *aPb = slapi_pblock_new ();
+ /*
+ * This search may be chained if chaining for ACL is
+ * is enabled in the backend and the entry is in
+ * a chained backend.
+ */
+ slapi_search_internal_set_pb ( aPb,
+ lasinfo.clientDn,
+ LDAP_SCOPE_BASE,
+ "objectclass=*",
+ attrs,
+ 0,
+ NULL /* controls */,
+ NULL /* uniqueid */,
+ aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
+ 0 /* actions */);
+ slapi_search_internal_callback_pb(aPb,
+ lasinfo.aclpb /* callback_data */,
+ NULL/* result_callback */,
+ acllas__handle_client_search,
+ NULL /* referral_callback */);
+ slapi_pblock_destroy (aPb);
+
+ }
+
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASUserAttrEval: AttrName:%s, attrVal:%s\n", attrName, attrValue );
+
+ if ( URLAttrRule ) {
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+ Slapi_Attr *attrs;
+ int i;
+
+ /* Get the attr from the resouce entry */
+ if ( 0 == slapi_entry_attr_find (lasinfo.resourceEntry, attrName, &attrs) ) {
+ i= slapi_attr_first_value ( attrs, &sval );
+ if ( i==-1 ) {
+ matched = ACL_FALSE; /* Attr val not there so it's value cannot equal other one */
+ goto done_acl;
+ }
+ } else {
+ matched = ACL_FALSE; /* Not there so it cannot equal another one */
+ goto done_acl;
+ }
+
+ while( matched != ACL_TRUE && (sval != NULL)) {
+ attrVal = slapi_value_get_berval ( sval );
+ matched = acllas__client_match_URL ( lasinfo.aclpb,
+ lasinfo.clientDn,
+ attrVal->bv_val);
+ if ( matched != ACL_TRUE )
+ i = slapi_attr_next_value ( attrs, i, &sval );
+ if ( matched == ACL_DONT_KNOW ) {
+ got_undefined = 1;
+ }
+ }/* while */
+ } else {
+ /*
+ * Here it's the userAttr = "OU#Directory Server" case.
+ * Allocate the Slapi_Value on the stack and init it by reference
+ * to avoid having to malloc and free memory.
+ */
+ Slapi_Value v;
+
+ slapi_value_init_string_passin(&v, attrValue);
+ rc = slapi_entry_attr_has_syntax_value ( lasinfo.resourceEntry, attrName,
+ &v );
+ if (rc) {
+ rc = slapi_entry_attr_has_syntax_value (
+ lasinfo.aclpb->aclpb_client_entry,
+ attrName, &v );
+ if (rc) matched = ACL_TRUE;
+ }
+ /* Nothing to free--cool */
+ }
+
+ /*
+ * Find out what the result is, in
+ * this case matched is one of ACL_TRUE, ACL_FALSE or ACL_DONT_KNOW
+ * and got_undefined says whether a logical term evaluated to ACL_DONT_KNOW.
+ *
+ */
+done_acl:
+ if ( matched == ACL_TRUE || !got_undefined) {
+ if (comparator == CMP_OP_EQ) {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ } else {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ } else {
+ rc = LAS_EVAL_FAIL;
+ }
+
+ slapi_ch_free ( (void **) &attrName );
+ return rc;
+
+done_las:
+ /*
+ * In this case matched is already LAS_EVAL_TRUE or LAS_EVAL_FALSE or
+ * LAS_EVAL_FAIL.
+ */
+ if ( matched != LAS_EVAL_FAIL ) {
+ if (comparator == CMP_OP_EQ) {
+ rc = matched;
+ } else {
+ rc = (matched == LAS_EVAL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ }
+
+ slapi_ch_free ( (void **) &attrName );
+ return rc;
+}
+
+/*
+ * acllas__client_match_URL
+ * Match a client to a URL.
+ *
+ * Returns:
+ * ACL_TRUE - matched the URL
+ * ACL_FALSE - Sorry; no match
+ *
+ */
+static int
+acllas__client_match_URL (struct acl_pblock *aclpb, char *n_clientdn, char *url )
+{
+
+ LDAPURLDesc *ludp;
+ int rc;
+ Slapi_Filter *f = NULL;
+
+
+ /* Get the client's entry if we don't have already */
+ if ( aclpb && ( NULL == aclpb->aclpb_client_entry )) {
+ /* SD 00/16/03 Get every attr in case req chained */
+ char **attrs=NULL;
+
+ /* Use new search internal API */
+ Slapi_PBlock * aPb = slapi_pblock_new ();
+ /*
+ * This search may be chained if chaining for ACL is
+ * is enabled in the backend and the entry is in
+ * a chained backend.
+ */
+ slapi_search_internal_set_pb ( aPb,
+ n_clientdn,
+ LDAP_SCOPE_BASE,
+ "objectclass=*",
+ attrs,
+ 0,
+ NULL /* controls */,
+ NULL /* uniqueid */,
+ aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
+ 0 /* actions */);
+ slapi_search_internal_callback_pb(aPb,
+ aclpb /* callback_data */,
+ NULL/* result_callback */,
+ acllas__handle_client_search,
+ NULL /* referral_callback */);
+ slapi_pblock_destroy (aPb);
+ }
+
+ if ( NULL == aclpb->aclpb_client_entry ) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "DS_LASUserAttrEval: Unable to get client's entry\n",0,0,0);
+ return ACL_FALSE;
+ }
+
+ if (( rc = ldap_url_parse( url, &ludp)) != 0 ) {
+ return ACL_FALSE;
+
+ }
+ if ( ( NULL == ludp->lud_dn) || ( NULL == ludp->lud_filter) ) {
+ ldap_free_urldesc( ludp );
+ return ACL_FALSE;
+ }
+
+ /* Normalize in place the dn */
+ slapi_dn_normalize ( ludp->lud_dn );
+
+ /* Check the scope */
+ if ( ludp->lud_scope == LDAP_SCOPE_SUBTREE ) {
+ if (!slapi_dn_issuffix(n_clientdn, ludp->lud_dn)) {
+ ldap_free_urldesc( ludp );
+ return ACL_FALSE;
+ }
+ } else if ( ludp->lud_scope == LDAP_SCOPE_ONELEVEL ) {
+ char *parent = slapi_dn_parent (n_clientdn);
+
+ if (slapi_utf8casecmp ((ACLUCHP)parent, (ACLUCHP)ludp->lud_dn) != 0 ) {
+ slapi_ch_free ( (void **) &parent);
+ ldap_free_urldesc( ludp );
+ return ACL_FALSE;
+ }
+ slapi_ch_free ( (void **) &parent);
+ } else { /* default */
+ if (slapi_utf8casecmp ( (ACLUCHP)n_clientdn, (ACLUCHP)ludp->lud_dn) != 0 ) {
+ ldap_free_urldesc( ludp );
+ return ACL_FALSE;
+ }
+
+ }
+
+
+ /* Convert the filter string */
+ f = slapi_str2filter ( ludp->lud_filter );
+
+ rc = ACL_TRUE;
+ if (0 != slapi_vattr_filter_test ( aclpb->aclpb_pblock,
+ aclpb->aclpb_client_entry, f, 0 /* no acces chk */ ))
+ rc = ACL_FALSE;
+
+ ldap_free_urldesc( ludp );
+ slapi_filter_free ( f, 1 ) ;
+
+ return rc;
+}
+static int
+acllas__handle_client_search ( Slapi_Entry *e, void *callback_data )
+{
+ struct acl_pblock *aclpb = (struct acl_pblock *) callback_data;
+
+ /* If we are here means we have found the entry */
+ if ( NULL == aclpb-> aclpb_client_entry)
+ aclpb->aclpb_client_entry = slapi_entry_dup ( e );
+ return 0;
+}
+/*
+*
+* Do all the necessary setup for all the
+* LASes.
+* It will only fail if it's passed garbage (which should not happen) or
+* if the data it needs to stock the lasinfo is not available, which
+* also should not happen.
+*
+*
+* Return value: 0 or one of these
+* #define LAS_EVAL_TRUE -1
+* #define LAS_EVAL_FALSE -2
+* #define LAS_EVAL_DECLINE -3
+* #define LAS_EVAL_FAIL -4
+* #define LAS_EVAL_INVALID -5
+*/
+
+static int
+__acllas_setup ( NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth, char *lasType, char*lasName, lasInfo *linfo)
+{
+
+ int rc;
+ memset ( linfo, 0, sizeof ( lasInfo) );
+
+ *cachable = 0;
+ *LAS_cookie = (void *)0;
+
+ if (strcmp(attr_name, lasType) != 0) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "%s:Invalid LAS(%s)\n", lasName, attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "%s:Invalid comparator(%d)\n", lasName, (int)comparator);
+ return LAS_EVAL_INVALID;
+ }
+
+
+ /* Get the client DN */
+ rc = ACL_GetAttribute(errp, DS_ATTR_USERDN, (void **)&linfo->clientDn,
+ subject, resource, auth_info, global_auth);
+
+ if ( rc != LAS_EVAL_TRUE ) {
+ acl_print_acllib_err(errp, NULL);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "%s:Unable to get the clientdn attribute(%d)\n",lasName, rc);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Check if we have a user or not */
+ if (linfo->clientDn) {
+ /* See if it's a anonymous user */
+ if (*(linfo->clientDn) == '\0')
+ linfo->anomUser = ACL_TRUE;
+ } else {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "%s: No user\n",lasName);
+ return LAS_EVAL_FAIL;
+ }
+
+ if ((rc = PListFindValue(subject, DS_ATTR_ENTRY,
+ (void **)&linfo->resourceEntry, NULL)) < 0) {
+ acl_print_acllib_err(errp, NULL);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "%s:Unable to get the Slapi_Entry attr(%d)\n",lasName, rc);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Get ACLPB */
+ rc = ACL_GetAttribute(errp, DS_PROP_ACLPB, (void **)&linfo->aclpb,
+ subject, resource, auth_info, global_auth);
+ if ( rc != LAS_EVAL_TRUE ) {
+ acl_print_acllib_err(errp, NULL);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "%s:Unable to get the ACLPB(%d)\n", lasName, rc);
+ return LAS_EVAL_FAIL;
+ }
+ if (NULL == attr_pattern ) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "%s:No rule value in the ACL\n", lasName);
+
+ return LAS_EVAL_FAIL;
+ }
+ /* get the authentication type */
+ if ((rc = PListFindValue(subject, DS_ATTR_AUTHTYPE,
+ (void **)&linfo->authType, NULL)) < 0) {
+ acl_print_acllib_err(errp, NULL);
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "%s:Unable to get the auth type(%d)\n", rc);
+ return LAS_EVAL_FAIL;
+ }
+ return 0;
+}
+
+/*
+ * See if clientDN has role roleDN.
+ * Here we know the user is not anon and that the role
+ * is not the anyone role ie. it's actually worth invoking the roles code.
+*/
+
+static int acllas__user_has_role( struct acl_pblock *aclpb,
+ Slapi_DN *roleDN, Slapi_DN *clientDn) {
+
+ int present = 0;
+ int rc = 0;
+
+ /* Get the client's entry if we don't have already */
+ if ( aclpb && ( NULL == aclpb->aclpb_client_entry )) {
+ /* SD 00/16/03 Get every attr in case req chained */
+ char **attrs=NULL;
+
+ /* Use new search internal API */
+ Slapi_PBlock * aPb = slapi_pblock_new ();
+ /*
+ * This search may NOT be chained--the user and the role definition
+ * must be co-located (chaining is not supported for the roles
+ * plugin in 5.0
+ */
+ slapi_search_internal_set_pb ( aPb,
+ slapi_sdn_get_ndn(clientDn),
+ LDAP_SCOPE_BASE,
+ "objectclass=*",
+ attrs,
+ 0,
+ NULL /* controls */,
+ NULL /* uniqueid */,
+ aclplugin_get_identity (ACL_PLUGIN_IDENTITY),
+ SLAPI_OP_FLAG_NEVER_CHAIN /* actions */);
+ slapi_search_internal_callback_pb(aPb,
+ aclpb /* callback_data */,
+ NULL/* result_callback */,
+ acllas__handle_client_search,
+ NULL /* referral_callback */);
+ slapi_pblock_destroy (aPb);
+ }
+
+ if ( NULL == aclpb->aclpb_client_entry ) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "acllas__user_has_role: Unable to get client's entry\n",0,0,0);
+ return ACL_FALSE;
+ }
+
+ /* If the client has the role then it's a match, otherwise no */
+
+ rc = slapi_role_check( aclpb->aclpb_client_entry, roleDN, &present);
+ if ( present ) {
+ return(ACL_TRUE);
+ }
+
+ return(ACL_FALSE);
+}
+
+int
+DS_LASRoleDnAttrEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, int *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+
+ char *s_attrName = NULL;
+ char *attrName;
+ int matched;
+ int rc;
+ Slapi_Attr *attr;
+ int numOflevels = 0;
+ char *n_currEntryDn = NULL;
+ lasInfo lasinfo;
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+ int k=0;
+ int got_undefined = 0;
+
+ if ( 0 != (rc = __acllas_setup (errp, attr_name, comparator,
+ attr_pattern,cachable,LAS_cookie,
+ subject, resource, auth_info,global_auth,
+ DS_LAS_ROLEDN, "DS_LASRoleDnAttrEval",
+ &lasinfo )) ) {
+ return LAS_EVAL_FAIL;
+ }
+
+ /* For anonymous client, they have no roles so the match is false. */
+ if ( lasinfo.anomUser )
+ return LAS_EVAL_FALSE;
+
+ /*
+ **
+ ** The function of this LAS is to find out if the client has
+ ** the role specified in the attr.
+ ** attr_pattern looks like: "ROLEDN cn=role1,o=sun.com"
+ */
+ attrName = attr_pattern;
+
+ matched = ACL_FALSE;
+ slapi_entry_attr_find( lasinfo.resourceEntry, attrName, &attr);
+ if (attr == NULL) {
+ /*
+ * Here the entry does not contain the attribute so the user
+ * cannot have this "null" role
+ */
+ return LAS_EVAL_FALSE;
+ }
+
+ if (lasinfo.aclpb->aclpb_optype == SLAPI_OPERATION_ADD) {
+ /*
+ * Here the entry does not contain the attribute so the user
+ * cannot have this "null" role or
+ * For the add operation, the resource itself
+ * must never be allowed to grant access--
+ * This is because access would be granted based on a value
+ * of an attribute in the new entry--security hole.
+ * XXX is this therefore FALSE or DONT_KNOW ?
+ *
+ *
+ */
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "ACL info: userattr=XXX#ROLEDN does not allow ADD permission.\n");
+ got_undefined = 1;
+ } else {
+
+ /*
+ * Got the first value.
+ * Test all the values of this attribute--if the client has _any_
+ * of the roles then it's a match.
+ */
+ k = slapi_attr_first_value ( attr,&sval );
+ while ( k != -1 ) {
+ char *n_attrval;
+ Slapi_DN *roleDN;
+
+ attrVal = slapi_value_get_berval ( sval );
+ n_attrval = slapi_ch_strdup( attrVal->bv_val);
+ n_attrval = slapi_dn_normalize (n_attrval);
+ roleDN = slapi_sdn_new_dn_byval(n_attrval);
+
+ /* We support: The attribute value can be a USER or a GROUP.
+ ** Let's compare with the client, thi might be just an user. If it is not
+ ** then we test it against the list of groups.
+ */
+ if ((matched = acllas__user_has_role(
+ lasinfo.aclpb,
+ roleDN,
+ lasinfo.aclpb->aclpb_authorization_sdn)) == ACL_TRUE){
+ slapi_ch_free ( (void **)&n_attrval );
+ slapi_sdn_free(&roleDN );
+ break;
+ }
+ slapi_ch_free ( (void **)&n_attrval );
+ slapi_sdn_free(&roleDN );
+ if (matched == ACL_TRUE) {
+ break;
+ } else if ( matched == ACL_DONT_KNOW ) {
+ /* record this but keep going--maybe another group will evaluate to TRUE */
+ got_undefined = 1;
+ }
+ k= slapi_attr_next_value ( attr, k, &sval );
+ }/* while */
+ }
+
+ /*
+ * If no terms were undefined, then evaluate as normal.
+ * If there was an undefined term, but another one was TRUE, then we also evaluate
+ * as normal. Otherwise, the whole expression is UNDEFINED.
+ */
+ if ( matched == ACL_TRUE || !got_undefined ) {
+ if (comparator == CMP_OP_EQ) {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ } else {
+ rc = (matched == ACL_TRUE ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+ } else {
+ rc = LAS_EVAL_FAIL;
+ }
+ return (rc);
+}
+
+/*
+ * Here, determine if lasinfo->clientDn matches user (which contains
+ * a ($dn) or a $attr component or both.) As defined in the aci
+ * lasinfo->aclpb->aclpb_curr_aci,
+ * which is the current aci being evaluated.
+ *
+ * returns: ACL_TRUE for matched,
+ * ACL_FALSE for matched.
+ * ACL_DONT_KNOW otherwise.
+ *
+ *
+*/
+
+int
+aclutil_evaluate_macro( char * rule, lasInfo *lasinfo,
+ acl_eval_types evalType ) {
+
+ int matched = 0;
+ aci_t *aci;
+ char *matched_val = NULL;
+ char **candidate_list = NULL;
+ char **inner_list = NULL;
+ char **sptr = NULL;
+ char **tptr = NULL;
+ char *t = NULL;
+ char *s = NULL;
+ char *target_dn = NULL;
+ struct acl_pblock *aclpb = lasinfo->aclpb;
+ int found_matched_val_in_ht = 0;
+
+ aci = lasinfo->aclpb->aclpb_curr_aci;
+ /* Get a pointer to the ndn in the resouirce */
+ target_dn = slapi_entry_get_ndn ( lasinfo->resourceEntry );
+
+ /*
+ * First, get the matched value from the target resource.
+ * We have alredy done this matching once beofer at tasrget match time.
+ */
+
+ LDAPDebug ( LDAP_DEBUG_ACL, "aclutil_evaluate_macro for aci '%s'"
+ "index '%d'\n",
+ aci->aclName, aci->aci_index,0);
+
+ if ( aci->aci_macro == NULL ) {
+ /* No $dn in the target, it's a $attr type subject rule */
+ matched_val = NULL;
+ } else {
+
+ /*
+ * Look up the matched_val value calculated
+ * from the target and stored judiciously there for us.
+ */
+
+ if ( (matched_val = (char *)acl_ht_lookup( aclpb->aclpb_macro_ht,
+ (PLHashNumber)aci->aci_index)) == NULL) {
+ LDAPDebug( LDAP_DEBUG_ACL,
+ "ACL info: failed to locate the calculated target"
+ "macro for aci '%s' index '%d'\n",
+ aci->aclName, aci->aci_index,0);
+ return(ACL_FALSE); /* Not a match */
+ } else {
+ LDAPDebug( LDAP_DEBUG_ACL,
+ "ACL info: found matched_val (%s) for aci index %d"
+ "in macro ht\n",
+ aci->aclName, aci->aci_index,0);
+
+ found_matched_val_in_ht = 1;
+ }
+ }
+
+ /*
+ * Now, make a candidate
+ * list of strings to match against the client.
+ * This involves replacing ($dn) or [$dn] by either the matched
+ * value, or all the suffix substrings of matched_val.
+ * If there is no $dn then the candidate list is just
+ * user itself.
+ *
+ */
+
+ candidate_list = acllas_replace_dn_macro( rule, matched_val, lasinfo);
+
+ sptr= candidate_list;
+ while( *sptr != NULL && !matched) {
+
+ s = *sptr;
+
+ /*
+ * Now s may contain some $attr macros.
+ * So, make a candidate list, got by replacing each occurence
+ * of $attr with all the values that attribute has in
+ * the resource entry.
+ */
+
+ inner_list = acllas_replace_attr_macro( s, lasinfo);
+
+ tptr = inner_list;
+ while( *tptr != NULL && (matched != ACL_TRUE) ){
+
+ t = *tptr;
+
+ /*
+ * Now, at last t is a candidate string we can
+ * match agains the client.
+ *
+ * $dn and $attr can appear in userdn, graoupdn and roledn
+ * rules, so we we need to decide which type we
+ * currently evaluating and evaluate that.
+ *
+ * If the string generated was undefined, eg it contained
+ * ($attr.ou) and the entry did not have an ou attribute,then
+ * the empty string is returned for this. So it we find
+ * an empty string in the list, skip it--it does not match.
+ */
+
+ if ( *t != '\0') {
+ if ( evalType == ACL_EVAL_USER ) {
+
+ matched = acllas_eval_one_user( lasinfo->aclpb,
+ lasinfo->clientDn, t);
+ } else if (evalType == ACL_EVAL_GROUP) {
+
+ matched = acllas_eval_one_group(t, lasinfo);
+ } else if (evalType == ACL_EVAL_ROLE) {
+ matched = acllas_eval_one_role(t, lasinfo);
+ } else if (evalType == ACL_EVAL_GROUPDNATTR) {
+ matched = acllas__eval_memberGroupDnAttr(t,
+ lasinfo->resourceEntry,
+ lasinfo->clientDn,
+ lasinfo->aclpb);
+ } else if ( evalType == ACL_EVAL_TARGET_FILTER) {
+
+ matched = acllas_eval_one_target_filter(t,
+ lasinfo->resourceEntry);
+
+ }
+ }
+
+ tptr++;
+
+ }/*inner while*/
+ charray_free(inner_list);
+
+ sptr++;
+ }/* outer while */
+
+ charray_free(candidate_list);
+
+ return(matched);
+
+}
+
+/*
+ * Here, replace the first occurrence of $(dn) with matched_val.
+ * replace any occurrence of $[dn] with each of the suffix substrings
+ * of matched_val.
+ * Each of these strings is returned in a NULL terminated list of strings.
+ *
+ * If there is no $dn thing then the returned list just contains rule itself.
+ *
+ * eg. rule: cn=fred,ou=*, ($dn), o=sun.com
+ * matched_val: ou=People,o=icnc
+ *
+ * Then we return the list
+ * cn=fred,ou=*,ou=People,o=icnc,o=sun.com NULL
+ *
+ * eg. rule: cn=fred,ou=*,[$dn], o=sun.com
+ * matched_val: ou=People,o=icnc
+ *
+ * Then we return the list
+ * cn=fred,ou=*,ou=People,o=icnc,o=sun.com
+ * cn=fred,ou=*,o=icnc,o=sun.com
+ * NULL
+ *
+ *
+*/
+
+static char **
+acllas_replace_dn_macro( char *rule, char *matched_val, lasInfo *lasinfo) {
+
+ char **a = NULL;
+ char *str = NULL;
+ char *patched_rule = NULL;
+ char *rule_to_use = NULL;
+ char *new_patched_rule = NULL;
+ char *rule_prefix = NULL;
+ char *rule_suffix = NULL;
+ int rule_suffix_len = 0;
+ char *comp = NULL;
+ int matched_val_len = 0;
+ int macro_len = 0;
+ int j = 0;
+ int has_macro_dn = 0;
+ int has_macro_levels = 0;
+
+ /* Determine what the rule's got once */
+ if ( strstr(rule, ACL_RULE_MACRO_DN_KEY) != NULL) {
+ has_macro_dn = 1;
+ }
+
+ if ( strstr(rule, ACL_RULE_MACRO_DN_LEVELS_KEY) != NULL) {
+ has_macro_levels = 1;
+ }
+
+ if ( !has_macro_dn && !has_macro_levels ) {
+
+ /*
+ * No $dn thing, just return a list with two elements, rule and NULL.
+ * charray_add will create the list and null terminate it.
+ */
+
+ charray_add( &a, slapi_ch_strdup(rule));
+ return(a);
+ } else {
+
+ /*
+ * Have an occurrence of the macro rules
+ *
+ * First, replace all occurrencers of ($dn) with the matched_val
+ */
+
+ if ( has_macro_dn) {
+ patched_rule =
+ acl_replace_str(rule, ACL_RULE_MACRO_DN_KEY, matched_val);
+ }
+
+ /* If there are no [$dn] we're done */
+
+ if ( !has_macro_levels ) {
+ charray_add( &a, patched_rule);
+ return(a);
+ } else {
+
+ /*
+ * It's a [$dn] type, so walk matched_val, splicing in all
+ * the suffix substrings and adding each such string to
+ * to the returned list.
+ * get_next_component() does not return the commas--the
+ * prefix and suffix should come with their commas.
+ *
+ * All occurrences of each [$dn] are replaced with each level.
+ *
+ * If has_macro_dn then patched_rule is the rule to strart with,
+ * and this needs to be freed at the end, otherwise
+ * just use rule.
+ */
+
+ if (patched_rule) {
+ rule_to_use = patched_rule;
+ } else {
+ rule_to_use = rule;
+ }
+
+ matched_val_len = strlen(matched_val);
+ j = 0;
+
+ while( j < matched_val_len) {
+
+ new_patched_rule =
+ acl_replace_str(rule_to_use, ACL_RULE_MACRO_DN_LEVELS_KEY,
+ &matched_val[j]);
+ charray_add( &a, new_patched_rule);
+
+ j += acl_find_comp_end(&matched_val[j]);
+ }
+
+ if (patched_rule) {
+ slapi_ch_free((void**)&patched_rule);
+ }
+
+ return(a);
+ }
+ }
+}
+
+/*
+ * Here, replace any occurrence of $attr.attrname with the
+ * value of attrname from lasinfo->resourceEntry.
+ *
+ *
+ * If there is no $attr thing then the returned list just contains rule
+ * itself.
+ *
+ * eg. rule: cn=fred,ou=*,ou=$attr.ou,o=sun.com
+ * ou: People
+ * ou: icnc
+ *
+ * Then we return the list
+ * cn=fred,ou=*,ou=People,o=sun.com
+ * cn=fred,ou=*,ou=icnc,o=sun.com
+ *
+*/
+
+static char **
+acllas_replace_attr_macro( char *rule, lasInfo *lasinfo) {
+
+ char **a = NULL;
+ char **working_list = NULL;
+ Slapi_Entry *e = lasinfo->resourceEntry;
+ char *str, *working_rule;
+ char *macro_str, *macro_attr_name;
+ int l;
+ Slapi_Attr *attr = NULL;
+
+ str = strstr(rule, ACL_RULE_MACRO_ATTR_KEY);
+ if ( str == NULL ) {
+
+ charray_add(&a, slapi_ch_strdup(rule));
+ return(a);
+
+ } else {
+
+ working_rule = slapi_ch_strdup(rule);
+ str = strstr(working_rule, ACL_RULE_MACRO_ATTR_KEY);
+ charray_add(&working_list, working_rule );
+
+ while( str != NULL) {
+
+ /*
+ * working_rule is the first member of working_list.
+ * str points to the next $attr.attrName in working_rule.
+ * each member of working_list needs to have each occurence of
+ * $attr.atrName replaced with the value of attrName in e.
+ * If attrName is multi valued then this generates another
+ * list which replaces the old one.
+ */
+
+ l = acl_strstr(&str[0], ")");
+ macro_str = slapi_ch_malloc(l+2);
+ strncpy( macro_str, &str[0], l+1);
+ macro_str[l+1] = '\0';
+
+ str = strstr(macro_str, ".");
+ str++; /* skip the . */
+ l = acl_strstr(&str[0], ")");
+ macro_attr_name = slapi_ch_malloc(l+1);
+ strncpy( macro_attr_name, &str[0], l);
+ macro_attr_name[l] = '\0';
+
+ slapi_entry_attr_find ( e, macro_attr_name, &attr );
+ if ( NULL == attr ) {
+
+ /*
+ * Here, if a $attr.attrName is such that the attrName
+ * does not occur in the entry then return a ""--
+ * this will go back to the matching code in
+ * aclutil_evaluate_macro() where "" will
+ * be taken as the candidate.
+ */
+
+ slapi_ch_free((void **)&macro_str);
+ slapi_ch_free((void **)&macro_attr_name);
+
+ charray_free(working_list);
+ charray_add(&a, slapi_ch_strdup(""));
+ return(a);
+
+ } else{
+
+ const struct berval *attrValue;
+ Slapi_Value *sval;
+ int i, j;
+ char *patched_rule;
+
+ a = NULL;
+ i= slapi_attr_first_value ( attr, &sval );
+ while(i != -1) {
+ attrValue = slapi_value_get_berval(sval);
+
+ j = 0;
+ while( working_list[j] != NULL) {
+
+ patched_rule =
+ acl_replace_str(working_list[j],
+ macro_str, attrValue->bv_val);
+ charray_add(&a, patched_rule);
+ j++;
+ }
+
+ i= slapi_attr_next_value( attr, i, &sval );
+ }/* while */
+
+ /*
+ * Here, a is working_list, where each member has had
+ * macro_str replaced with attrVal.
+ */
+
+ charray_free(working_list);
+ working_list = a;
+ working_rule = a[0];
+ }
+ slapi_ch_free((void **)&macro_str);
+ slapi_ch_free((void **)&macro_attr_name);
+
+ str = strstr(working_rule, ACL_RULE_MACRO_ATTR_KEY);
+
+ }/* while */
+
+ return(working_list);
+ }
+
+
+}
+
+/*
+ * returns ACL_TRUE, ACL_FALSE or ACL_DONT_KNOW.
+ *
+ * user is a string from the userdn keyword which may contain
+ * * components. This routine does the compare component by component, so
+ * that * behaves differently to "normal".
+ * Any ($dn) or $attr must have been removed from user before this is called.
+*/
+static int
+acllas_eval_one_user( struct acl_pblock *aclpb, char * clientDN, char *rule) {
+
+ int exact_match = 0;
+ int ret_code = 0;
+ const size_t LDAP_URL_prefix_len = strlen(LDAP_URL_prefix);
+ char *s = NULL;
+
+
+
+ /* URL format */
+ if ((s = strchr (rule, '?'))!= NULL) {
+ /* URL format */
+ if (acllas__client_match_URL ( aclpb, clientDN,
+ rule) == ACL_TRUE) {
+ exact_match = 1;
+ }
+ } else if ( strstr(rule, "=*") == NULL ) {
+ /* Just a straight compare */
+ /* skip the ldap:/// part */
+ rule += LDAP_URL_prefix_len;
+ exact_match = !slapi_utf8casecmp((ACLUCHP)clientDN,
+ (ACLUCHP)rule);
+ } else{
+ /* Here, contains a =*, so need to match comp by comp */
+ /* skip the ldap:/// part */
+ rule += LDAP_URL_prefix_len;
+ ret_code = acl_match_prefix( rule, clientDN, &exact_match);
+ }
+ if ( exact_match) {
+ return( ACL_TRUE);
+ } else {
+ return(ACL_FALSE);
+ }
+}
+
+/*
+ * returns ACL_TRUE, ACL_FALSE and ACL_DONT_KNOW.
+ *
+ * The user string has had all ($dn) and $attr replaced
+ * so the only dodgy thing left is a *.
+ *
+ * If * appears in such a user string, then it matches only that
+ * component, not .*, like it would otherwise.
+ *
+*/
+static int
+acllas_eval_one_group(char *groupbuf, lasInfo *lasinfo) {
+
+ if (groupbuf) {
+ return( acllas__user_ismember_of_group (
+ lasinfo->aclpb,
+ groupbuf,
+ lasinfo->clientDn,
+ ACLLAS_CACHE_ALL_GROUPS,
+ lasinfo->aclpb->aclpb_clientcert
+ ));
+ } else {
+ return(ACL_FALSE); /* not in the empty group */
+ }
+}
+
+/*
+ * returns ACL_TRUE for match, ACL_FALSE for not a match, ACL_DONT_KNOW otherwise.
+*/
+static int
+acllas_eval_one_role(char *role, lasInfo *lasinfo) {
+
+ Slapi_DN *roleDN = NULL;
+ int rc = ACL_FALSE;
+ char ebuf [ BUFSIZ ];
+
+ /*
+ * See if lasinfo.clientDn has role rolebuf.
+ * Here we know it's not an anom user nor
+ * a an anyone user--the client dn must be matched against
+ * a real role.
+ */
+
+ roleDN = slapi_sdn_new_dn_byval(role);
+ if (role) {
+ rc = acllas__user_has_role(
+ lasinfo->aclpb,
+ roleDN,
+ lasinfo->aclpb->aclpb_authorization_sdn);
+ } else { /* The user does not have the empty role */
+ rc = ACL_FALSE;
+ }
+ slapi_sdn_free(&roleDN );
+
+ /* Some useful logging */
+ if (rc == ACL_TRUE ) {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "role evaluation: user '%s' does have role '%s'\n",
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION (lasinfo->clientDn, ebuf),
+ role);
+ } else {
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "role evaluation: user '%s' does NOT have role '%s'\n",
+ ACL_ESCAPE_STRING_WITH_PUNCTUATION (lasinfo->clientDn, ebuf),
+ role);
+ }
+ return(rc);
+}
+
+/*
+ * returns ACL_TRUE if e matches the filter str, ACL_FALSE if not,
+ * ACL_DONT_KNOW otherwise.
+*/
+static int acllas_eval_one_target_filter( char * str, Slapi_Entry *e) {
+
+ int rc = ACL_FALSE;
+ Slapi_Filter *f = NULL;
+
+ if ((f = slapi_str2filter(str)) == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "Warning: Bad targetfilter(%s) in aci: does not match\n", str);
+ return(ACL_DONT_KNOW);
+ }
+
+ if (slapi_vattr_filter_test(NULL, e, f, 0 /*don't do acess chk*/)!= 0) {
+ rc = ACL_FALSE; /* Filter does not match */
+ } else {
+ rc = ACL_TRUE; /* filter does match */
+ }
+ slapi_filter_free(f, 1);
+
+ return(rc);
+
+}
+
+
+
+
+
+/***************************************************************************/
+/* E N D */
+/***************************************************************************/
diff --git a/ldap/servers/plugins/acl/acllist.c b/ldap/servers/plugins/acl/acllist.c
new file mode 100644
index 00000000..0147626d
--- /dev/null
+++ b/ldap/servers/plugins/acl/acllist.c
@@ -0,0 +1,940 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/************************************************************************
+ *
+ * ACLLIST
+ *
+ * All the ACLs are read when the server is started. The ACLs are
+ * parsed and kept in an AVL tree. All the ACL List management are
+ * in this file.
+ *
+ * The locking on the aci cache is implemented using the acllist_acicache*()
+ * routines--a read/write lock.
+ *
+ * The granularity of the view of the cache is the entry level--ie.
+ * when an entry is being modified (mod,add,delete,modrdn) and the mod
+ * involves the aci attribute, then other operations will see the acl cache
+ * before the whole change or after the whole change, but not during the change.
+ * cf. acl.c:acl_modified()
+ *
+ * The only tricky issue is that there is also locking
+ * implemented for the anonymous profile and sometimes we need to take both
+ * locks cf. aclanom_anom_genProfile(). The rule is
+ * always take the acicache lock first, followed by the anon lock--following
+ * this rule will ensure no dead lock scenarios can arise.
+ *
+ * Some routines are called in different places with different lock
+ * contexts--for these routines acl_lock_flag_t is used to
+ * pass the context.
+ *
+ */
+#include "acl.h"
+
+static PRRWLock *aci_rwlock = NULL;
+#define ACILIST_LOCK_READ() PR_RWLock_Rlock (aci_rwlock )
+#define ACILIST_UNLOCK_READ() PR_RWLock_Unlock (aci_rwlock )
+#define ACILIST_LOCK_WRITE() PR_RWLock_Wlock (aci_rwlock )
+#define ACILIST_UNLOCK_WRITE() PR_RWLock_Unlock (aci_rwlock )
+
+
+/* Root of the TREE */
+static Avlnode *acllistRoot = NULL;
+
+#define CONTAINER_INCR 2000
+
+/* The container array */
+static AciContainer **aciContainerArray;
+static PRUint32 currContainerIndex =0;
+static PRUint32 maxContainerIndex = 0;
+static int curAciIndex = 1;
+
+/* PROTOTYPES */
+static int __acllist_add_aci ( aci_t *aci );
+static int __acllist_aciContainer_node_cmp ( caddr_t d1, caddr_t d2 );
+static int __acllist_aciContainer_node_dup ( caddr_t d1, caddr_t d2 );
+static void __acllist_free_aciContainer ( AciContainer **container);
+static void free_targetattrfilters( Targetattrfilter ***input_attrFilterArray);
+
+void my_print( Avlnode *root );
+
+
+int
+acllist_init ()
+{
+
+ if (( aci_rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,"ACLLIST LOCK") ) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name,
+ "acllist_init:failed in getting the rwlock\n" );
+ return 1;
+ }
+
+ aciContainerArray = (AciContainer **) slapi_ch_calloc ( 1,
+ CONTAINER_INCR * sizeof ( AciContainer * ) );
+ maxContainerIndex = CONTAINER_INCR;
+ currContainerIndex = 0;
+
+ return 0;
+}
+
+/*
+ * This is the callback for backend state changes.
+ * It needs to add/remove acis as backends come up and go down.
+ *
+ * The strategy is simple:
+ * When a backend moves to the SLAPI_BE_STATE_ON then we go get all the acis
+ * add them to the cache.
+ * When a backend moves out of the SLAPI_BE_STATE_ON then we remove them all.
+ *
+*/
+
+void acl_be_state_change_fnc ( void *handle, char *be_name, int old_state,
+ int new_state) {
+ Slapi_Backend *be=NULL;
+ const Slapi_DN *sdn;
+
+
+ if ( old_state == SLAPI_BE_STATE_ON && new_state != SLAPI_BE_STATE_ON) {
+
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Backend %s is no longer STARTED--deactivating it's acis\n",
+ be_name);
+
+ if ( (be = slapi_be_select_by_instance_name( be_name )) == NULL) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Failed to retreive backend--NOT activating it's acis\n");
+ return;
+ }
+
+ /*
+ * Just get the first suffix--if there are multiple XXX ?
+ */
+
+ if ( (sdn = slapi_be_getsuffix( be, 0)) == NULL ) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Failed to retreive backend--NOT activating it's acis\n");
+ return;
+ }
+
+ aclinit_search_and_update_aci ( 1, /* thisbeonly */
+ sdn, /* base */
+ be_name,/* be name */
+ LDAP_SCOPE_SUBTREE,
+ ACL_REMOVE_ACIS,
+ DO_TAKE_ACLCACHE_WRITELOCK);
+
+ } else if ( old_state != SLAPI_BE_STATE_ON && new_state == SLAPI_BE_STATE_ON) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Backend %s is now STARTED--activating it's acis\n", be_name);
+
+ if ( (be = slapi_be_select_by_instance_name( be_name )) == NULL) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Failed to retreive backend--NOT activating it's acis\n");
+ return;
+ }
+
+ /*
+ * In fact there can onlt be one sufffix here.
+ */
+
+ if ( (sdn = slapi_be_getsuffix( be, 0)) == NULL ) {
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Failed to retreive backend--NOT activating it's acis\n");
+ return;
+ }
+
+ aclinit_search_and_update_aci ( 1, /* thisbeonly */
+ sdn,
+ be_name, /* be name */
+ LDAP_SCOPE_SUBTREE,
+ ACL_ADD_ACIS,
+ DO_TAKE_ACLCACHE_WRITELOCK);
+ }
+
+}
+
+/* This routine must be called with the acicache write lock taken */
+int
+acllist_insert_aci_needsLock( const Slapi_DN *e_sdn, const struct berval* aci_attr)
+{
+
+ aci_t *aci;
+ char *acl_str;
+ int rv =0;
+
+ if (aci_attr->bv_len <= 0)
+ return 0;
+
+ aci = acllist_get_aci_new ();
+ slapi_sdn_set_ndn_byval ( aci->aci_sdn, slapi_sdn_get_ndn ( e_sdn ) );
+
+ acl_str = slapi_ch_strdup(aci_attr->bv_val);
+ /* Parse the ACL TEXT */
+ if ( 0 != (rv = acl_parse ( acl_str, aci )) ) {
+ slapi_log_error (SLAPI_LOG_FATAL, plugin_name,
+ "ACL PARSE ERR(rv=%d): %s\n", rv, acl_str );
+ slapi_ch_free ( (void **) &acl_str );
+ acllist_free_aci ( aci );
+
+ return 1;
+ }
+
+ /* Now add it to the list */
+ if ( 0 != (rv =__acllist_add_aci ( aci ))) {
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "ACL ADD ACI ERR(rv=%d): %s\n", rv, acl_str );
+ slapi_ch_free ( (void **) &acl_str );
+ acllist_free_aci ( aci );
+ return 1;
+ }
+
+ slapi_ch_free ( (void **) &acl_str );
+ acl_regen_aclsignature ();
+ if ( aci->aci_elevel == ACI_ELEVEL_USERDN_ANYONE)
+ aclanom_invalidateProfile ();
+ return 0;
+}
+
+/* This routine must be called with the acicache write lock taken */
+static int
+__acllist_add_aci ( aci_t *aci )
+{
+
+ int rv = 0; /* OK */
+ AciContainer *aciListHead;
+ AciContainer *head;
+ PRUint32 i;
+
+ aciListHead = acllist_get_aciContainer_new ( );
+ slapi_sdn_set_ndn_byval ( aciListHead->acic_sdn, slapi_sdn_get_ndn ( aci->aci_sdn ) );
+
+ /* insert the aci */
+ switch (avl_insert ( &acllistRoot, aciListHead, __acllist_aciContainer_node_cmp,
+ __acllist_aciContainer_node_dup ) ) {
+
+ case 1: /* duplicate ACL on the same entry */
+
+ /* Find the node that contains the acl. */
+ if ( NULL == (head = (AciContainer *) avl_find( acllistRoot, aciListHead,
+ (IFP) __acllist_aciContainer_node_cmp ) ) ) {
+ slapi_log_error ( SLAPI_PLUGIN_ACL, plugin_name,
+ "Can't insert the acl in the tree\n");
+ rv = 1;
+ } else {
+ aci_t *t_aci;;
+
+ /* Attach the list */
+ t_aci = head->acic_list;;
+ while ( t_aci && t_aci->aci_next )
+ t_aci = t_aci->aci_next;
+
+ /* Now add the new one to the end of the list */
+ t_aci->aci_next = aci;
+ }
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "Added the ACL:%s to existing container:[%d]%s\n",
+ aci->aclName, head->acic_index, slapi_sdn_get_ndn( head->acic_sdn ));
+
+ /* now free the tmp container */
+ aciListHead->acic_list = NULL;
+ __acllist_free_aciContainer ( &aciListHead );
+
+ break;
+ default:
+ /* The container is inserted. Now hook up the aci and setup the
+ * container index. Donot free the "aciListHead" here.
+ */
+ aciListHead->acic_list = aci;
+
+ /*
+ * First, see if we have an open slot or not - -if we have reuse it
+ */
+ i = 0;
+ while ( (i < currContainerIndex) && aciContainerArray[i] )
+ i++;
+
+ if ( currContainerIndex >= (maxContainerIndex - 2)) {
+ maxContainerIndex += CONTAINER_INCR;
+ aciContainerArray = (AciContainer **) slapi_ch_realloc ( (char *) aciContainerArray,
+ maxContainerIndex * sizeof ( AciContainer * ) );
+ }
+ aciListHead->acic_index = i;
+ /* If i < currContainerIndex, we are just re-using an old slot. */
+ /* We don't need to increase currContainerIndex if we just re-use an old one. */
+ if (i == currContainerIndex)
+ currContainerIndex++;
+
+ aciContainerArray[ aciListHead->acic_index ] = aciListHead;
+
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name, "Added %s to container:%d\n",
+ slapi_sdn_get_ndn( aciListHead->acic_sdn ), aciListHead->acic_index );
+ break;
+ }
+
+ return rv;
+}
+
+
+
+static int
+__acllist_aciContainer_node_cmp ( caddr_t d1, caddr_t d2 )
+{
+
+ int rc =0;
+ AciContainer *c1 = (AciContainer *) d1;
+ AciContainer *c2 = (AciContainer *) d2;
+
+
+ rc = slapi_sdn_compare ( c1->acic_sdn, c2->acic_sdn );
+ return rc;
+}
+
+static int
+__acllist_aciContainer_node_dup ( caddr_t d1, caddr_t d2 )
+{
+
+ /* we allow duplicates -- they are not exactly duplicates
+ ** but multiple aci value on the same node
+ */
+ return 1;
+
+}
+
+
+/*
+ * Remove the ACL
+ *
+ * This routine must be called with the aclcache write lock taken.
+ * It takes in addition the one for the anom profile taken in
+ * aclanom_invalidateProfile().
+ * They _must_ be taken in this order or there
+ * is a deadlock scenario with aclanom_gen_anomProfile() which
+ * also takes them is this order.
+*/
+
+int
+acllist_remove_aci_needsLock( const Slapi_DN *sdn, const struct berval *attr )
+{
+
+ aci_t *head, *next;
+ int rv = 0;
+ AciContainer *aciListHead, *root;
+ AciContainer *dContainer;
+ int removed_anom_acl = 0;
+
+ /* we used to delete the ACL by value but we don't do that anymore.
+ * rather we delete all the acls in that entry and then repopulate it if
+ * there are any more acls.
+ */
+
+ aciListHead = acllist_get_aciContainer_new ( );
+ slapi_sdn_set_ndn_byval ( aciListHead->acic_sdn, slapi_sdn_get_ndn ( sdn ) );
+
+ /* now find it */
+ if ( NULL == (root = (AciContainer *) avl_find( acllistRoot, aciListHead,
+ (IFP) __acllist_aciContainer_node_cmp ))) {
+ /* In that case we don't have any acl for this entry. cool !!! */
+
+ __acllist_free_aciContainer ( &aciListHead );
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "No acis to remove in this entry\n" );
+ return 0;
+ }
+
+ head = root->acic_list;
+ if ( head)
+ next = head->aci_next;
+ while ( head ) {
+ if ( head->aci_elevel == ACI_ELEVEL_USERDN_ANYONE)
+ removed_anom_acl = 1;
+
+ /* Free the acl */
+ acllist_free_aci ( head );
+
+ head = next;
+ next = NULL;
+ if ( head && head->aci_next )
+ next = head->aci_next;
+ }
+ root->acic_list = NULL;
+
+ /* remove the container from the slot */
+ aciContainerArray[root->acic_index] = NULL;
+
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Removing container[%d]=%s\n", root->acic_index,
+ slapi_sdn_get_ndn ( root->acic_sdn) );
+ dContainer = (AciContainer *) avl_delete ( &acllistRoot, aciListHead,
+ __acllist_aciContainer_node_cmp );
+ __acllist_free_aciContainer ( &dContainer );
+
+ acl_regen_aclsignature ();
+ if ( removed_anom_acl )
+ aclanom_invalidateProfile ();
+
+ /*
+ * Now read back the entry and repopulate ACLs for that entry, but
+ * only if a specific aci was deleted, otherwise, we do a
+ * "When Harry met Sally" and nail 'em all.
+ */
+
+ if ( attr != NULL) {
+
+ if (0 != (rv = aclinit_search_and_update_aci ( 0, /* thisbeonly */
+ sdn, /* base */
+ NULL, /* be name */
+ LDAP_SCOPE_BASE,
+ ACL_ADD_ACIS,
+ DONT_TAKE_ACLCACHE_WRITELOCK))) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ " Can't add the rest of the acls for entry:%s after delete\n",
+ slapi_sdn_get_dn ( sdn ) );
+ }
+ }
+
+ /* Now free the tmp container we used */
+ __acllist_free_aciContainer ( &aciListHead );
+
+ /*
+ * regenerate the anonymous profile if we have deleted
+ * anyone acls.
+ * We don't need the aclcache readlock because the context of
+ * this routine is we have the write lock already.
+ */
+ if ( removed_anom_acl )
+ aclanom_gen_anomProfile(DONT_TAKE_ACLCACHE_READLOCK);
+
+ return rv;
+}
+
+AciContainer *
+acllist_get_aciContainer_new ( )
+{
+
+ AciContainer *head;
+
+ head = (AciContainer * ) slapi_ch_calloc ( 1, sizeof ( AciContainer ) );
+ head->acic_sdn = slapi_sdn_new ( );
+ head->acic_index = -1;
+
+ return head;
+}
+static void
+__acllist_free_aciContainer ( AciContainer **container)
+{
+
+ PR_ASSERT ( container != NULL );
+
+ if ( (*container)->acic_index >= 0 )
+ aciContainerArray[ (*container)->acic_index] = NULL;
+ if ( (*container)->acic_sdn )
+ slapi_sdn_free ( &(*container)->acic_sdn );
+ slapi_ch_free ( (void **) container );
+
+}
+
+void
+acllist_done_aciContainer ( AciContainer *head )
+{
+
+ PR_ASSERT ( head != NULL );
+
+ slapi_sdn_done ( head->acic_sdn );
+ head->acic_index = -1;
+
+ /* The caller is responsible for taking care of list */
+ head->acic_list = NULL;
+}
+
+
+aci_t *
+acllist_get_aci_new ()
+{
+ aci_t *aci_item;
+
+ aci_item = (aci_t *) slapi_ch_calloc (1, sizeof (aci_t));
+ aci_item->aci_sdn = slapi_sdn_new ();
+ aci_item->aci_index = curAciIndex++;
+ aci_item->aci_elevel = ACI_DEFAULT_ELEVEL; /* by default it's a complex */
+ aci_item->targetAttr = (Targetattr **) slapi_ch_calloc (
+ ACL_INIT_ATTR_ARRAY,
+ sizeof (Targetattr *));
+ return aci_item;
+}
+
+void
+acllist_free_aci(aci_t *item)
+{
+
+ Targetattr **attrArray;
+
+ /* The caller is responsible for taking
+ ** care of list issue
+ */
+ if (item == NULL) return;
+
+ slapi_sdn_free ( &item->aci_sdn );
+ slapi_filter_free (item->target, 1);
+
+ /* slapi_filter_free(item->targetAttr, 1); */
+ attrArray = item->targetAttr;
+ if (attrArray) {
+ int i = 0;
+ Targetattr *attr;
+
+ while (attrArray[i] != NULL) {
+ attr = attrArray[i];
+ if (attr->attr_type & ACL_ATTR_FILTER) {
+ slapi_filter_free(attr->u.attr_filter, 1);
+ } else {
+ slapi_ch_free ( (void **) &attr->u.attr_str );
+ }
+ slapi_ch_free ( (void **) &attr );
+ i++;
+ }
+ /* Now free the array */
+ slapi_ch_free ( (void **) &attrArray );
+ }
+
+ /* Now free any targetattrfilters in this aci item */
+
+ if ( item->targetAttrAddFilters ) {
+ free_targetattrfilters(&item->targetAttrAddFilters);
+ }
+
+ if ( item->targetAttrDelFilters ) {
+ free_targetattrfilters(&item->targetAttrDelFilters);
+ }
+
+ if (item->targetFilterStr) slapi_ch_free ( (void **) &item->targetFilterStr );
+ slapi_filter_free(item->targetFilter, 1);
+
+ /* free the handle */
+ if (item->aci_handle) ACL_ListDestroy(NULL, item->aci_handle);
+
+ /* Free the name */
+ if (item->aclName) slapi_ch_free((void **) &item->aclName);
+
+ /* Free any macro info*/
+ if (item->aci_macro) {
+ slapi_ch_free((void **) &item->aci_macro->match_this);
+ slapi_ch_free((void **) &item->aci_macro);
+ }
+
+ /* free at last -- free at last */
+ slapi_ch_free ( (void **) &item );
+}
+
+static void free_targetattrfilters( Targetattrfilter ***attrFilterArray) {
+
+ if (*attrFilterArray) {
+ int i = 0;
+ Targetattrfilter *attrfilter;
+
+ while ((*attrFilterArray)[i] != NULL) {
+ attrfilter = (*attrFilterArray)[i];
+
+ if ( attrfilter->attr_str != NULL) {
+ slapi_ch_free ( (void **) &attrfilter->attr_str );
+ }
+
+ if (attrfilter->filter != NULL) {
+ slapi_filter_free(attrfilter->filter, 1);
+ }
+
+ if( attrfilter->filterStr != NULL) {
+ slapi_ch_free ( (void **) &attrfilter->filterStr );
+ }
+
+ slapi_ch_free ( (void **) &attrfilter );
+ i++;
+ }
+ /* Now free the array */
+ slapi_ch_free ( (void **) attrFilterArray );
+ }
+
+}
+
+/* SEARCH */
+void
+acllist_init_scan (Slapi_PBlock *pb, int scope, char *base)
+{
+ Acl_PBlock *aclpb;
+ int i;
+ AciContainer *root;
+ char *basedn = NULL;
+ int index;
+
+ if ( acl_skip_access_check ( pb, NULL ) ) {
+ return;
+ }
+
+ /*acllist_print_tree ( acllistRoot, &depth, "top", "top") ; */
+ /* my_print ( acllistRoot );*/
+ /* If we have an anonymous profile and I am an anom dude - let's skip it */
+ if ( aclanom_is_client_anonymous ( pb )) {
+ return;
+ }
+ aclpb = acl_get_aclpb (pb, ACLPB_BINDDN_PBLOCK );
+ if ( !aclpb ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name, "Missing aclpb 4 \n" );
+ return;
+ }
+
+ aclpb->aclpb_handles_index[0] = -1;
+
+ /* If base is NULL - it means we are going to go thru all the ACLs
+ * This is needed when we do anonymous profile generation.
+ */
+ if ( NULL == base ) {
+ return;
+ }
+
+ aclpb->aclpb_state |= ACLPB_SEARCH_BASED_ON_LIST ;
+
+ acllist_acicache_READ_LOCK();
+
+ basedn = slapi_ch_strdup (base);
+ index = 0;
+ aclpb->aclpb_search_base = slapi_ch_strdup ( base );
+
+ while (basedn ) {
+ char *tmp = NULL;
+
+ slapi_sdn_set_ndn_byref ( aclpb->aclpb_aclContainer->acic_sdn, basedn );
+
+ root = (AciContainer *) avl_find( acllistRoot,
+ (caddr_t) aclpb->aclpb_aclContainer,
+ (IFP) __acllist_aciContainer_node_cmp);
+ if ( index >= ACLPB_MAX_SELECTED_ACLS -2 ) {
+ aclpb->aclpb_handles_index[0] = -1;
+ slapi_ch_free ( (void **) &basedn);
+ break;
+ } else if ( NULL != root ) {
+ aclpb->aclpb_base_handles_index[index++] = root->acic_index;
+ aclpb->aclpb_base_handles_index[index] = -1;
+ }
+ tmp = slapi_dn_parent ( basedn );
+ slapi_ch_free ( (void **) &basedn);
+ basedn = tmp;
+ }
+
+ acllist_done_aciContainer ( aclpb->aclpb_aclContainer);
+
+ if ( aclpb->aclpb_base_handles_index[0] == -1 )
+ aclpb->aclpb_state &= ~ACLPB_SEARCH_BASED_ON_LIST ;
+
+ acllist_acicache_READ_UNLOCK();
+
+ i = 0;
+ while ( i < ACLPB_MAX_SELECTED_ACLS && aclpb->aclpb_base_handles_index[i] != -1 ) {
+ i++;
+ }
+}
+
+/*
+ * Initialize aclpb_handles_index[] (sentinel -1) to
+ * contain a list of all aci items at and above edn in the DIT tree.
+ * This list will be subsequestly scanned to find applicable aci's for
+ * the given operation.
+*/
+
+void
+acllist_aciscan_update_scan ( Acl_PBlock *aclpb, char *edn )
+{
+
+ int i, index = 0;
+ char *basedn = NULL;
+ AciContainer *root;
+ int is_not_search_base = 1;
+
+
+ /* First copy the containers indx from the base to the one which is
+ * going to be used.
+ * The base handles get done in acllist_init_scan().
+ * This stuff is only used if it's a search operation.
+ */
+ if ( aclpb && aclpb->aclpb_search_base ) {
+ while ( aclpb->aclpb_base_handles_index[index] != -1 &&
+ index < ACLPB_MAX_SELECTED_ACLS -2 ) {
+ aclpb->aclpb_handles_index[index] =
+ aclpb->aclpb_base_handles_index[index];
+ index++;
+ }
+ if ( strcasecmp ( edn, aclpb->aclpb_search_base) == 0) {
+ is_not_search_base = 0;
+ }
+ }
+ aclpb->aclpb_handles_index[index] = -1;
+
+ /*
+ * Here, make a list of all the aci's that will apply
+ * to edn ie. all aci's at and above edn in the DIT tree.
+ *
+ * Do this by walking up edn, looking at corresponding
+ * points in the acllistRoot aci tree.
+ *
+ * If is_not_search_base is true, then we need to iterate on edn, otherwise
+ * we've already got all the base handles above.
+ *
+ */
+
+ if (is_not_search_base) {
+
+ basedn = slapi_ch_strdup ( edn );
+
+ while (basedn ) {
+ char *tmp = NULL;
+
+ slapi_sdn_set_ndn_byref ( aclpb->aclpb_aclContainer->acic_sdn, basedn );
+
+ root = (AciContainer *) avl_find( acllistRoot,
+ (caddr_t) aclpb->aclpb_aclContainer,
+ (IFP) __acllist_aciContainer_node_cmp);
+
+ slapi_log_error ( SLAPI_LOG_ACL, plugin_name,
+ "Searching AVL tree for update:%s: container:%d\n", basedn ,
+ root ? root->acic_index: -1);
+ if ( index >= ACLPB_MAX_SELECTED_ACLS -2 ) {
+ aclpb->aclpb_handles_index[0] = -1;
+ slapi_ch_free ( (void **) &basedn);
+ break;
+ } else if ( NULL != root ) {
+ aclpb->aclpb_handles_index[index++] = root->acic_index;
+ aclpb->aclpb_handles_index[index] = -1;
+ }
+ tmp = slapi_dn_parent ( basedn );
+ slapi_ch_free ( (void **) &basedn);
+ basedn = tmp;
+ if ( aclpb->aclpb_search_base && tmp &&
+ ( 0 == strcasecmp ( tmp, aclpb->aclpb_search_base))) {
+ slapi_ch_free ( (void **) &basedn);
+ tmp = NULL;
+ }
+ } /* while */
+ }
+
+ acllist_done_aciContainer ( aclpb->aclpb_aclContainer );
+ i = 0;
+ while ( i < ACLPB_MAX_SELECTED_ACLS && aclpb->aclpb_handles_index[i] != -1 ) {
+ i++;
+ }
+
+}
+
+aci_t *
+acllist_get_first_aci (Acl_PBlock *aclpb, PRUint32 *cookie )
+{
+
+ int val;
+
+ *cookie = val = 0;
+ if ( aclpb && aclpb->aclpb_handles_index[0] != -1 ) {
+ val = aclpb->aclpb_handles_index[*cookie];
+ }
+ if ( NULL == aciContainerArray[val]) {
+ return ( acllist_get_next_aci ( aclpb, NULL, cookie ) );
+ }
+
+ return (aciContainerArray[val]->acic_list );
+}
+/*
+ * acllist_get_next_aci
+ * Return the next aci in the list
+ *
+ * Inputs
+ * Acl_PBlock *aclpb -- acl Main block; if aclpb= NULL,
+ * -- then we scan thru the whole list.
+ * -- which is used by anom profile code.
+ * aci_t *curaci -- the current aci
+ * PRUint32 *cookie -- cookie -- to maintain a state (what's next)
+ *
+ */
+
+aci_t *
+acllist_get_next_aci ( Acl_PBlock *aclpb, aci_t *curaci, PRUint32 *cookie )
+{
+ PRUint32 val;
+ int scan_entire_list;
+
+ /*
+ Here, if we're passed a curaci and there's another aci in the same node,
+ return that one.
+ */
+
+ if ( curaci && curaci->aci_next )
+ return ( curaci->aci_next );
+
+ /*
+ Determine if we need to scan the entire list of acis.
+ We do if the aclpb==NULL or if the first handle index is -1.
+ That means that we want to go through
+ the entire aciContainerArray up to the currContainerIndex to get
+ acis; the -1 in the first position is a special keyword which tells
+ us that the acis have changed, so we need to go through all of them.
+ */
+
+ scan_entire_list = (aclpb == NULL || aclpb->aclpb_handles_index[0] == -1);
+
+start:
+ (*cookie)++;
+ val = *cookie;
+
+ /* if we are not scanning the entire aciContainerArray list, we only want to
+ look at the indexes specified in the handles index */
+ if ( !scan_entire_list )
+ val = aclpb->aclpb_handles_index[*cookie];
+
+ /* the hard max end */
+ if ( val >= maxContainerIndex)
+ return NULL;
+
+ /* reached the end of the array */
+ if ((!scan_entire_list && (*cookie >= (ACLPB_MAX_SELECTED_ACLS-1))) ||
+ (*cookie >= currContainerIndex)) {
+ return NULL;
+ }
+
+ /* if we're only using the handles list for our aciContainerArray
+ indexes, the -1 value marks the end of that list */
+ if ( !scan_entire_list && (aclpb->aclpb_handles_index[*cookie] == -1) ) {
+ return NULL;
+ }
+
+ /* if we're scanning the entire list, and we hit a null value in the
+ middle of the list, just try the next one; this can happen if
+ an aci was deleted - it can leave "holes" in the array */
+ if ( scan_entire_list && ( NULL == aciContainerArray[val])) {
+ goto start;
+ }
+
+ if ( aciContainerArray[val] )
+ return (aciContainerArray[val]->acic_list );
+ else
+ return NULL;
+}
+
+void
+acllist_acicache_READ_UNLOCK( )
+{
+ ACILIST_UNLOCK_READ ();
+
+}
+
+void
+acllist_acicache_READ_LOCK()
+{
+ /* get a reader lock */
+ ACILIST_LOCK_READ ();
+
+}
+
+void
+acllist_acicache_WRITE_UNLOCK( )
+{
+ ACILIST_UNLOCK_WRITE ();
+
+}
+
+void
+acllist_acicache_WRITE_LOCK( )
+{
+ ACILIST_LOCK_WRITE ();
+
+}
+
+/* This routine must be called with the acicache write lock taken */
+int
+acllist_moddn_aci_needsLock ( Slapi_DN *oldsdn, char *newdn )
+{
+
+
+ AciContainer *aciListHead;
+ AciContainer *head;
+
+ /* first get the container */
+
+ aciListHead = acllist_get_aciContainer_new ( );
+ slapi_sdn_free(&aciListHead->acic_sdn);
+ aciListHead->acic_sdn = oldsdn;
+
+
+ if ( NULL == (head = (AciContainer *) avl_find( acllistRoot, aciListHead,
+ (IFP) __acllist_aciContainer_node_cmp ) ) ) {
+
+ slapi_log_error ( SLAPI_PLUGIN_ACL, plugin_name,
+ "Can't find the acl in the tree for moddn operation:olddn%s\n",
+ slapi_sdn_get_ndn ( oldsdn ));
+ aciListHead->acic_sdn = NULL;
+ __acllist_free_aciContainer ( &aciListHead );
+ return 1;
+ }
+
+
+ /* Now set the new DN */
+ slapi_sdn_done ( head->acic_sdn );
+ slapi_sdn_set_ndn_byval ( head->acic_sdn, newdn );
+
+ aciListHead->acic_sdn = NULL;
+ __acllist_free_aciContainer ( &aciListHead );
+
+ return 0;
+}
+
+void
+acllist_print_tree ( Avlnode *root, int *depth, char *start, char *side)
+{
+
+ AciContainer *aciHeadList;
+
+ if ( NULL == root ) {
+ return;
+ }
+ aciHeadList = (AciContainer *) root->avl_data;
+ slapi_log_error ( SLAPI_LOG_ACL, "plugin_name",
+ "Container[ Depth=%d%s-%s]: %s\n", *depth, start, side,
+ slapi_sdn_get_ndn ( aciHeadList->acic_sdn ) );
+
+ (*depth)++;
+
+ acllist_print_tree ( root->avl_left, depth, side, "L" );
+ acllist_print_tree ( root->avl_right, depth, side, "R" );
+
+ (*depth)--;
+
+}
+
+static
+void
+ravl_print( Avlnode *root, int depth )
+{
+ int i;
+
+ AciContainer *aciHeadList;
+ if ( root == 0 )
+ return;
+
+ ravl_print( root->avl_right, depth+1 );
+
+ for ( i = 0; i < depth; i++ )
+ printf( " " );
+ aciHeadList = (AciContainer *) root->avl_data;
+ printf( "%s\n", slapi_sdn_get_ndn ( aciHeadList->acic_sdn ) );
+
+ ravl_print( root->avl_left, depth+1 );
+}
+
+void
+my_print( Avlnode *root )
+{
+ printf( "********\n" );
+
+ if ( root == 0 )
+ printf( "\tNULL\n" );
+ else
+ ( void ) ravl_print( root, 0 );
+
+ printf( "********\n" );
+}
diff --git a/ldap/servers/plugins/acl/aclparse.c b/ldap/servers/plugins/acl/aclparse.c
new file mode 100644
index 00000000..2247471a
--- /dev/null
+++ b/ldap/servers/plugins/acl/aclparse.c
@@ -0,0 +1,1928 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "acl.h"
+
+/****************************************************************************/
+/* prototypes */
+/****************************************************************************/
+static int __aclp__parse_aci(char *str, aci_t *aci_item);
+static int __aclp__sanity_check_acltxt(aci_t *aci_item, char *str);
+static char * __aclp__normalize_acltxt (aci_t *aci_item, char *str);
+static char * __aclp__getNextLASRule(aci_t *aci_item, char *str,
+ char **endOfCurrRule);
+static char * __aclp__dn_normalize( char *dn , char *end);
+static int __aclp__get_aci_right ( char *str);
+static int __aclp__init_targetattr (aci_t *aci, char *attr_val);
+static int __acl__init_targetattrfilters( aci_t *aci_item, char *str);
+static int process_filter_list( Targetattrfilter ***attrfilterarray,
+ char * str);
+static int __acl_init_targetattrfilter( Targetattrfilter *attrfilter, char *str );
+static void __aclp_chk_paramRules ( aci_t *aci_item, char *start,
+ char *end);
+static void __acl_strip_trailing_space( char *str);
+static void __acl_strip_leading_space( char **str);
+static char * __acl_trim_filterstr( char * str );
+static int acl_verify_exactly_one_attribute( char *attr_name, Slapi_Filter *f);
+static int type_compare( Slapi_Filter *f, void *arg);
+static int acl_check_for_target_macro( aci_t *aci_item, char *value);
+static int get_acl_rights_as_int( char * strValue);
+
+/***************************************************************************
+*
+* acl_parse
+*
+* Parses the input string and copies the information into the
+* correct place in the aci.
+*
+*
+* Input:
+* char *str - Input string which has the ACL
+* This is a duped copy, so here we have
+* the right to stich '\0' characters into str for
+* processing purposes. If you want to keep
+* a piece of str, you'll need to dup it
+* as it gets freed outside the scope of acl_parse.
+* aci_t *item - the aci item where the ACL info will be
+* - stored.
+*
+* Returns:
+* 0 -- Parsed okay
+* < 0 -- error codes
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+acl_parse(char * str, aci_t *aci_item)
+{
+
+ int rv=0;
+ char *next;
+ char *save;
+
+ while(*str) {
+ __acl_strip_leading_space( &str );
+ if (*str == '\0') break;
+
+ if (*str == '(') {
+ if ((next = slapi_find_matching_paren(str)) == NULL) {
+ return(ACL_SYNTAX_ERR);
+ }
+ } else {
+ /* then we have done all the processing */
+ return 0;
+ }
+ LDAP_UTF8INC(str); /* skip the "(" */
+ save = next;
+ LDAP_UTF8INC(next);
+ *save = '\0';
+
+ /* Now we have a "str)" */
+ if ( 0 != (rv = __aclp__parse_aci(str, aci_item))) {
+ return(rv);
+ }
+
+ /* Move to the next */
+ str = next;
+ }
+
+ /* check if have a ACLTXT or not */
+ if (!(aci_item->aci_type & ACI_ACLTXT))
+ return ACL_SYNTAX_ERR;
+
+ if (aci_item->target) {
+ Slapi_Filter *f;
+
+ /* Make sure that the target is a valid target.
+ ** Example: ACL is located in
+ ** "ou=engineering, o=ace industry, c=us
+ ** but if the target is "o=ace industry, c=us",
+ ** then it's an ERROR.
+ */
+ f = aci_item->target;
+ if (aci_item->aci_type & ACI_TARGET_DN) {
+ char *avaType;
+ struct berval *avaValue;
+ const char *dn;
+
+ dn = slapi_sdn_get_ndn ( aci_item->aci_sdn );
+ slapi_filter_get_ava ( f, &avaType, &avaValue );
+
+ if (!slapi_dn_issuffix( avaValue->bv_val, dn))
+ return ACL_INVALID_TARGET;
+ }
+ }
+
+ /*
+ ** We need to keep the taregetFilterStr for anyone ACL only.
+ ** same for targetValueFilterStr.
+ ** We need to keep it for macros too as it needs to be expnaded at eval time.
+ **
+ */
+ if ( (aci_item->aci_elevel != ACI_ELEVEL_USERDN_ANYONE) &&
+ !(aci_item->aci_type & ACI_TARGET_MACRO_DN) ) {
+ slapi_ch_free ( (void **) & aci_item->targetFilterStr );
+ }
+
+ /*
+ * If we parsed the aci and there was a ($dn) on the user side
+ * but none in hte taget then that's an error as the user side
+ * value is derived from the target side value.
+ */
+
+ if (!(aci_item->aci_type & ACI_TARGET_MACRO_DN) &&
+ (aci_item->aci_ruleType & ACI_PARAM_DNRULE)) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "acl_parse: A macro in a subject ($dn) must have a macro in the target.\n");
+ return(ACL_INVALID_TARGET);
+ }
+
+ return 0;
+}
+
+/***************************************************************************
+*
+* __aclp__parse_aci
+*
+* Parses Each individual subset of information/
+*
+* Input:
+* char *str - Input string which has the ACL like "str)"
+* aci_t *item - the aci item where the ACL info will be
+* - stored.
+*
+* Returns:
+* 0 -- Parsed okay
+* < 0 -- error codes
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+static int
+__aclp__parse_aci (char *str, aci_t *aci_item)
+{
+
+ int len;
+ int rv;
+ int type;
+ char *tmpstr;
+ char *s = NULL;
+ char *value = NULL;
+ Slapi_Filter *f = NULL;
+ int targetattrlen = strlen(aci_targetattr);
+ int targetdnlen = strlen (aci_targetdn);
+ int tfilterlen = strlen(aci_targetfilter);
+ int targetattrfilterslen = strlen(aci_targetattrfilters);
+
+ __acl_strip_leading_space( &str );
+
+ if (*str == '\0') {
+ return(ACL_SYNTAX_ERR);
+ }
+
+ /* The first letter should tell us something */
+ switch(*str) {
+ case 'v':
+ type = ACI_ACLTXT;
+
+ if ( 0 != (rv= __aclp__sanity_check_acltxt(aci_item, str ) ) ) {
+
+ return rv;
+ }
+ break;
+
+ case 't':
+ if (strncmp(str, aci_targetattrfilters,targetattrfilterslen ) == 0) {
+ type = ACI_TARGET_ATTR;
+
+
+ /*
+ * The targetattrfilters bit looks like this:
+ * (targetattrfilters="add= attr1:F1 && attr2:F2 ... && attrn:Fn,
+ * del= attr1:F1 && attr2:F2... && attrn:Fn")
+ */
+ if ( 0 != (rv= __acl__init_targetattrfilters(
+ aci_item, str))) {
+ return rv;
+ }
+ } else if (strncmp(str, aci_targetattr,targetattrlen ) == 0) {
+ type = ACI_TARGET_ATTR;
+
+ if ( (s = strstr( str, "!=" )) != NULL ) {
+ type |= ACI_TARGET_ATTR_NOT;
+ strncpy(s, " ", 1);
+ }
+ /* Get individual components of the targetattr.
+ * (targetattr = "cn || u* || phone ||tel:add:(tel=1234)
+ * || sn:del:(gn=5678)")
+ * If it contains a value filter, the type will also be
+ * ACI_TARGET_VALUE_ATTR.
+ */
+ if ( 0 != (rv= __aclp__init_targetattr(
+ aci_item, str))) {
+ return rv;
+ }
+ } else if (strncmp(str, aci_targetfilter,tfilterlen ) == 0) {
+ if ( aci_item->targetFilter)
+ return ACL_SYNTAX_ERR;
+
+ type = ACI_TARGET_FILTER;
+ /* we need to remove the targetfilter stuff*/
+ if ( (s = strstr( str, "!=" )) != NULL ) {
+ type |= ACI_TARGET_FILTER_NOT;
+ }
+
+ /*
+ * If it's got a macro in the targetfilter then it must
+ * have a target and it must have a macro.
+ */
+
+ if ((s = strstr (str, ACL_RULE_MACRO_DN_KEY)) != NULL ||
+ ((s = strstr(str, ACL_RULE_MACRO_DN_LEVELS_KEY)) != NULL)) {
+
+ /* Must have a targetmacro */
+ if ( !(aci_item->aci_type & ACI_TARGET_MACRO_DN)) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "acl_parse: A macro in a targetfilter ($dn) must have a macro in the target.\n");
+ return(ACL_SYNTAX_ERR);
+ }
+
+ type|= ACI_TARGET_FILTER_MACRO_DN;
+ }
+
+ tmpstr = strchr(str, '=');
+ tmpstr++;
+ __acl_strip_leading_space(&tmpstr);
+
+ /*
+ * Trim off enclosing quotes and enclosing
+ * superfluous brackets.
+ * The result has been duped so it can be kept.
+ */
+
+ tmpstr = __acl_trim_filterstr( tmpstr );
+
+ f = slapi_str2filter(tmpstr);
+
+ /* save the filter string */
+ aci_item->targetFilterStr = tmpstr;
+
+ } else if (strncmp(str, aci_targetdn, targetdnlen) == 0) {
+ char *tstr = NULL;
+ const size_t LDAP_URL_prefix_len = strlen (LDAP_URL_prefix);
+ char *tt;
+ type = ACI_TARGET_DN;
+ /* Keep a copy of the target attr */
+ if (aci_item->target) {
+ return (ACL_SYNTAX_ERR);
+ }
+ if ( (s = strstr( str, "!=" )) != NULL ) {
+ type |= ACI_TARGET_NOT;
+ strncpy(s, " ", 1);
+ }
+
+ /* Convert it to lower as slapi_dn_normalize() does not */
+ for (tt = str; *tt; tt++) *tt = TOLOWER ( *tt );
+
+ if ( (s = strchr( str, '=' )) != NULL ) {
+ value = s + 1;
+ slapi_dn_normalize(value);
+ len = strlen ( value );
+ if (*value == '"' && value[len-1] == '"'){
+ value[len-1] = '\0';
+ value++;
+ }
+ __acl_strip_leading_space(&value);
+ } else {
+ return ( ACL_SYNTAX_ERR );
+ }
+
+ if ( strncasecmp ( value, LDAP_URL_prefix , LDAP_URL_prefix_len) )
+ return ( ACL_SYNTAX_ERR );
+
+ value += LDAP_URL_prefix_len;
+ len = strlen ( value );
+ tstr = (char *) slapi_ch_malloc ( targetdnlen + len + 4 );
+ sprintf ( tstr, "(target=%s)", value);
+ if ( (rv = acl_check_for_target_macro( aci_item, value)) == -1) {
+ slapi_ch_free ( (void **) &tstr );
+ return(ACL_SYNTAX_ERR);
+ } else if ( rv > 0) {
+ /* is present, so the type is now ACL_TARGET_MACRO_DN */
+ type = ACI_TARGET_MACRO_DN;
+ } else {
+ /* it's a normal target with no macros inside */
+ f = slapi_str2filter ( tstr );
+ }
+ slapi_ch_free ( (void **) &tstr );
+ } else {
+ /* did start with a 't' but was not a recognsied keyword */
+ return(ACL_SYNTAX_ERR);
+ }
+
+ /*
+ * Here, it was a recognised keyword that started with 't'.
+ * Check that the filter associated with ACI_TARGET_DN and
+ * ACI_TARGET_FILTER are OK.
+ */
+ if (f == NULL) {
+ /* The following types require a filter to have been created */
+ if (type & ACI_TARGET_DN)
+ return ACL_TARGET_FILTER_ERR;
+ else if (type & ACI_TARGET_FILTER)
+ return ACL_TARGETFILTER_ERR;
+ } else {
+ int filterChoice;
+
+ filterChoice = slapi_filter_get_choice ( f );
+ if ( (type & ACI_TARGET_DN) &&
+ ( filterChoice == LDAP_FILTER_PRESENT)) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "acl__parse_aci: Unsupported filter type:%d\n", filterChoice);
+ return(ACL_SYNTAX_ERR);
+ } else if (( filterChoice == LDAP_FILTER_SUBSTRINGS) &&
+ (type & ACI_TARGET_DN)) {
+ type &= ~ACI_TARGET_DN;
+ type |= ACI_TARGET_PATTERN;
+ }
+ }
+
+ if ((type & ACI_TARGET_DN) ||
+ (type & ACI_TARGET_PATTERN)) {
+ if (aci_item->target) {
+ /* There is something already. ERROR */
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Multiple targets in the ACL syntax\n",
+ 0,0,0);
+ slapi_filter_free(f, 1);
+ return(ACL_SYNTAX_ERR);
+ } else {
+ aci_item->target = f;
+ }
+ } else if ( type & ACI_TARGET_FILTER) {
+ if (aci_item->targetFilter) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Multiple target Filters in the ACL Syntax\n",
+ 0,0,0);
+ slapi_filter_free(f, 1);
+ return(ACL_SYNTAX_ERR);
+ } else {
+ aci_item->targetFilter = f;
+ }
+ }
+ break; /* 't' */
+ default:
+ /* Here the keyword did not start with 'v' ot 't' so error */
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Unknown keyword at \"%s\"\n Expecting"
+ " \"target\", \"targetattr\", \"targetfilter\", \"targattrfilters\""
+ " or \"version\"\n", str, 0, 0);
+ return(ACL_SYNTAX_ERR);
+ }/* switch() */
+
+ /* Store the type info */
+ aci_item->aci_type |= type;
+
+ return 0;
+}
+
+/***************************************************************************
+* acl__sanity_check_acltxt
+*
+* Check the input ACL text. Reports any errors. Also forgivs if certain
+* things are missing.
+*
+* Input:
+* char *str - String containg the acl text
+* int *err - error status
+*
+* Returns:
+* 0 --- good status
+* <0 --- error
+*
+* Error Handling:
+* None.
+*
+*
+**************************************************************************/
+static int
+__aclp__sanity_check_acltxt (aci_t *aci_item, char *str)
+{
+ NSErr_t errp;
+ char *s;
+ ACLListHandle_t *handle = NULL;
+ char *newstr = NULL;
+ char *word;
+ char *next;
+
+ memset (&errp, 0, sizeof(NSErr_t));
+ newstr = str;
+
+ while ((s = strstr(newstr, "authenticate")) != NULL) {
+ char *next;
+ next = s + 12;
+ s--;
+ while (s != str && ldap_utf8isspace(s)) LDAP_UTF8DEC(s);
+ if (s && *s == ';') {
+ /* We don't support authenticate stuff */
+ return ACL_INVALID_AUTHORIZATION;
+
+ } else {
+ newstr = next;
+ }
+ }
+
+ newstr = slapi_ch_strdup (str);
+ word = ldap_utf8strtok_r(newstr, " ", &next);
+ if (strcasecmp (word, "version") == 0) {
+ word = ldap_utf8strtok_r(NULL, " ", &next);
+ if (atoi(word) != 3) {
+ slapi_ch_free ( (void **) &newstr );
+ return ACL_INCORRECT_ACI_VERSION;
+ }
+ }
+ slapi_ch_free ( (void **) &newstr );
+
+ /* We need to normalize the DNs in the userdn and group dn
+ ** so that, it's only done once.
+ */
+ if ((newstr = __aclp__normalize_acltxt (aci_item, str )) == NULL) {
+ return ACL_SYNTAX_ERR;
+ }
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name, "Normalized String:%s\n", newstr, 0,0);
+
+ /* check for acl syntax error */
+ if ((handle = (ACLListHandle_t *) ACL_ParseString(&errp,
+ newstr)) == NULL) {
+ acl_print_acllib_err(&errp, str);
+ slapi_ch_free ( (void **) &newstr );
+ return ACL_SYNTAX_ERR;
+ } else {
+ /* get the rights and the aci type */
+ aci_item->aci_handle = handle;
+ nserrDispose(&errp);
+ slapi_ch_free ( (void **) &newstr );
+
+ return 0;
+ }
+}
+/******************************************************************************
+*
+* acl__normalize_acltxt
+*
+*
+* XXXrbyrne this routine should be re-written when someone eventually
+* gets sick enough of it. Same for getNextLAS() below.
+*
+* Normalize the acltxt i.e normalize all the DNs specified in the
+* Userdn and Groupdn rule so that we normalize once here and not
+* over and over again at the runtime in the LASes. We have to normalize
+* before we generate the handle otherwise it's of no use.
+* Also convert deny to deny absolute
+*
+* The string that comes in is something like:
+* version 3.0; acl "Dept domain administration"; allow (all)
+* groupdn = "ldap:///cn=Domain Administrators, o=$dn.o, o=ISP"; )
+*
+* Returns NULL on error.
+*
+******************************************************************************/
+static char *
+__aclp__normalize_acltxt ( aci_t * aci_item, char * str )
+{
+
+ char *s, *p;
+ char *end;
+ char *aclstr, *s_aclstr;
+ char *ret_str = NULL;
+ int len;
+ char *ptr, *aclName;
+ char *nextACE;
+ char *tmp_str = NULL;
+ char *acestr = NULL;
+ char *s_acestr = NULL;
+ int aci_rights_val = 0; /* bug 389975 */
+
+ /* make a copy first */
+ s_aclstr = aclstr = slapi_ch_strdup ( str );
+
+ /* The rules are like this version 3.0; acl "xyz"; rule1; rule2; */
+ s = strchr (aclstr, ';');
+ if ( NULL == s) {
+ slapi_ch_free ( (void **) &s_aclstr );
+ return NULL;
+ }
+ aclstr = ++s;
+
+ /* From DS 4.0, we support both aci (or aci) "name" -- we have to change to acl
+ ** as libaccess will not like it
+ */
+ s = aclstr;
+ while (s && ldap_utf8isspace(s)) LDAP_UTF8INC(s);
+ *(s+2 ) = 'l';
+
+ aclName = s+3;
+
+ s = strchr (aclstr, ';');
+ if ( NULL == s) {
+ slapi_ch_free ( (void **) &s_aclstr );
+ return NULL;
+ }
+
+ aclstr = s;
+ LDAP_UTF8INC(aclstr);
+ *s = '\0';
+
+ /* Here aclName is the acl description string */
+ aci_item->aclName = slapi_ch_strdup ( aclName );
+
+ aclutil_str_appened (&ret_str, s_aclstr);
+ aclutil_str_appened (&ret_str, ";");
+
+ /* start with the string */
+ acestr = aclstr;
+
+ /*
+ * Here acestr is something like:
+ *
+ * " allow (all) groupdn = "ldap:///cn=Domain Administrators, o=$dn.o, o=ISP";)"
+ *
+ *
+ */
+
+normalize_nextACERule:
+
+ /* now we are in the rule part */
+ tmp_str = acestr;
+ s = strchr (tmp_str, ';');
+ if ( s == NULL) {
+ if (ret_str) slapi_ch_free ( (void **) &ret_str );
+ slapi_ch_free ( (void **) &s_aclstr );
+ return NULL;
+ }
+ nextACE = s;
+ LDAP_UTF8INC(nextACE);
+ *s = '\0';
+
+ /* acestr now will hold copy of the ACE. Also add
+ ** some more space in case we need to add "absolute"
+ ** for deny rule. We will never need more 2 times
+ ** the len.
+ */
+ len = strlen (tmp_str);
+ s_acestr = acestr = slapi_ch_calloc ( 1, 2 * len);
+
+ __acl_strip_leading_space(&tmp_str);
+
+ /*
+ * Now it's something like:
+ * allow (all) groupdn = "ldap:///cn=Domain Administrators, o=$dn.o, o=ISP";
+ */
+ if (strncasecmp(tmp_str, "allow", 5) == 0) {
+ memcpy(acestr, tmp_str, len);
+ tmp_str += 5;
+ /* gather the rights */
+ aci_rights_val = __aclp__get_aci_right (tmp_str);/* bug 389975 */
+ aci_item->aci_type |= ACI_HAS_ALLOW_RULE;
+
+ } else if (strncasecmp(tmp_str, "deny", 4) == 0) {
+ char *d_rule ="deny absolute";
+ /* Then we have to add "absolute" to the deny rule
+ ** What we are doing here is to tackle this situation.
+ **
+ ** allow -- deny -- allow
+ ** deny -- allow
+ **
+ ** by using deny absolute we force the precedence rule
+ ** i.e deny has a precedence over allow. Since there doesn't
+ ** seem to be an easy to detect the mix, forcing this
+ ** to all the deny rules will do the job.
+ */
+ __acl_strip_leading_space(&tmp_str);
+ tmp_str += 4;
+
+ /* We might have an absolute there already */
+ if ((s = strstr (tmp_str, "absolute")) != NULL) {
+ tmp_str = s;
+ tmp_str += 8;
+ }
+ /* gather the rights */
+ aci_rights_val = __aclp__get_aci_right (tmp_str);/* bug 389975 */
+ aci_item->aci_type |= ACI_HAS_DENY_RULE;
+
+ len = strlen ( d_rule );
+ memcpy (acestr, d_rule, len );
+ memcpy (acestr+len, tmp_str, strlen (tmp_str) );
+ } else {
+ /* wrong syntax */
+ aci_rights_val = -1 ;
+ }
+ if (aci_rights_val == -1 )
+ {
+ /* wrong syntax */
+ slapi_ch_free ( (void **) &ret_str );
+ slapi_ch_free ( (void **) &s_acestr );
+ slapi_ch_free ( (void **) &s_aclstr );
+ return NULL;
+ } else
+ aci_item->aci_access |= aci_rights_val;
+
+
+ /* Normalize all the DNs in the userdn rule */
+
+ /*
+ *
+ * Here acestr starts like this:
+ * " allow (all) groupdn = "ldap:///cn=Domain Administrators, o=$dn.o, o=ISP"
+ */
+
+ s = __aclp__getNextLASRule(aci_item, acestr, &end);
+ while ( s ) {
+ if ( 0 == strncmp ( s, DS_LAS_USERDNATTR, 10) ||
+ ( 0 == strncmp ( s, DS_LAS_USERATTR, 8))) {
+ /*
+ ** For userdnattr/userattr rule, the resources changes and hence
+ ** we cannot cache the result. See above for more comments.
+ */
+ aci_item->aci_elevel = ACI_ELEVEL_USERDNATTR;
+ } else if ( 0== strncmp ( s, DS_LAS_USERDN, 6)) {
+ p = strstr ( s, "=");
+ p--;
+ if ( strncmp (p, "!=", 2) == 0)
+ aci_item->aci_type |= ACI_CONTAIN_NOT_USERDN;
+
+ /* XXXrbyrne
+ * Here we need to scan for more ldap:/// within
+ * this userdn rule type:
+ * eg. userdn = "ldap:///cn=joe,o=sun.com || ldap:///self"
+ * This is handled correctly in DS_LASUserDnEval
+ * but the bug here is not setting ACI_USERDN_SELFRULE
+ * which would ensure that acl info is not cached from
+ * one resource entry to the next. (bug 558519)
+ */
+ p = strstr ( p, "ldap");
+ if (p == NULL) {
+ /* must start with ldap */
+ if (s_acestr) slapi_ch_free ( (void **) &s_acestr );
+ if (ret_str) slapi_ch_free ( (void **) &ret_str );
+ slapi_ch_free ( (void **) &s_aclstr );
+ return (NULL);
+ }
+ p += 8; /* for ldap:/// */
+ if( __aclp__dn_normalize (p, end) == NULL) {
+ if (s_acestr) slapi_ch_free ( (void **) &s_acestr );
+ if (ret_str) slapi_ch_free ( (void **) &ret_str );
+ slapi_ch_free ( (void **) &s_aclstr );
+ return (NULL);
+ }
+
+ /* we have a rule like userdn = "ldap:///blah". s points to blah now.
+ ** let's find if we have a SELF rule like userdn = "ldap:///self".
+ ** Since the resource changes on entry basis, we can't cache the
+ ** evalation of handle for all time. The cache result is valid
+ ** within the evaluation of that resource.
+ */
+ if (strncasecmp(p, "self", 4) == 0) {
+ aci_item->aci_ruleType |= ACI_USERDN_SELFRULE;
+ } else if ( strncasecmp(p, "anyone", 6) == 0 ) {
+ aci_item->aci_elevel = ACI_ELEVEL_USERDN_ANYONE;
+
+ } else if ( strncasecmp(p, "all", 3) == 0 ) {
+ if ( aci_item->aci_elevel > ACI_ELEVEL_USERDN_ALL )
+ aci_item->aci_elevel = ACI_ELEVEL_USERDN_ALL;
+
+ } else {
+ if ( aci_item->aci_elevel > ACI_ELEVEL_USERDN )
+ aci_item->aci_elevel = ACI_ELEVEL_USERDN;
+ }
+
+ /* See if we have a parameterized rule */
+ __aclp_chk_paramRules ( aci_item, p, end );
+ } else if ( 0 == strncmp ( s, DS_LAS_GROUPDNATTR, 11)) {
+ /*
+ ** For groupdnattr rule, the resources changes and hence
+ ** we cannot cache the result. See above for more comments.
+ */
+ /* Find out if we have a URL type of rule */
+ if ((p= strstr (s, "ldap")) != NULL) {
+ if ( aci_item->aci_elevel > ACI_ELEVEL_GROUPDNATTR_URL )
+ aci_item->aci_elevel = ACI_ELEVEL_GROUPDNATTR_URL;
+ } else if ( aci_item->aci_elevel > ACI_ELEVEL_GROUPDNATTR ) {
+ aci_item->aci_elevel = ACI_ELEVEL_GROUPDNATTR;
+ }
+ aci_item->aci_ruleType |= ACI_GROUPDNATTR_RULE;
+ } else if ( 0 == strncmp ( s, DS_LAS_GROUPDN, 7)) {
+
+ p = strstr ( s, "=");
+ p--;
+ if ( strncmp (p, "!=", 2) == 0)
+ aci_item->aci_type |= ACI_CONTAIN_NOT_GROUPDN;
+
+ p = strstr ( s, "ldap");
+ if (p == NULL) {
+ /* must start with ldap */
+ if (s_acestr) slapi_ch_free ( (void **) &s_acestr );
+ if (ret_str) slapi_ch_free ( (void **) &ret_str );
+ slapi_ch_free ( (void **) &s_aclstr );
+ return (NULL);
+ }
+ p += 8;
+ if (__aclp__dn_normalize (p, end) == NULL) {
+ if (s_acestr) slapi_ch_free ( (void **) &s_acestr );
+ if (ret_str) slapi_ch_free ( (void **) &ret_str );
+ slapi_ch_free ( (void **) &s_aclstr );
+ return (NULL);
+ }
+ /* check for param rules */
+ __aclp_chk_paramRules ( aci_item, p, end );
+
+ if ( aci_item->aci_elevel > ACI_ELEVEL_GROUPDN )
+ aci_item->aci_elevel = ACI_ELEVEL_GROUPDN;
+ aci_item->aci_ruleType |= ACI_GROUPDN_RULE;
+
+ } else if ( 0 == strncmp ( s, DS_LAS_ROLEDN, 6)) {
+
+ p = strstr ( s, "=");
+ p--;
+ if ( strncmp (p, "!=", 2) == 0)
+ aci_item->aci_type |= ACI_CONTAIN_NOT_ROLEDN;
+
+ p = strstr ( s, "ldap");
+ if (p == NULL) {
+ /* must start with ldap */
+ if (s_acestr) slapi_ch_free ( (void **) &s_acestr );
+ if (ret_str) slapi_ch_free ( (void **) &ret_str );
+ slapi_ch_free ( (void **) &s_aclstr );
+ return (NULL);
+ }
+ p += 8;
+ if (__aclp__dn_normalize (p, end) == NULL) {
+ if (s_acestr) slapi_ch_free ( (void **) &s_acestr );
+ if (ret_str) slapi_ch_free ( (void **) &ret_str );
+ slapi_ch_free ( (void **) &s_aclstr );
+ return (NULL);
+ }
+ /* check for param rules */
+ __aclp_chk_paramRules ( aci_item, p, end );
+
+ /* XXX need this for roledn ?
+ if ( aci_item->aci_elevel > ACI_ELEVEL_GROUPDN )
+ aci_item->aci_elevel = ACI_ELEVEL_GROUPDN;*/
+ aci_item->aci_ruleType |= ACI_ROLEDN_RULE;
+ }
+ s = ++end;
+ s = __aclp__getNextLASRule(aci_item, s, &end);
+ }/* while */
+
+ /* get the head of the string */
+ acestr = s_acestr;
+ len = strlen( acestr);
+ ptr = acestr +len-1;
+ while (*ptr && *ptr != '\"' && *ptr != ')' ) *ptr-- = ' ';
+ ptr++;
+ *ptr = ';';
+
+ aclutil_str_appened (&ret_str, acestr);
+ if (s_acestr) {
+ slapi_ch_free ( (void **) &s_acestr );
+ }
+ s_acestr = NULL;
+
+ if (nextACE) {
+ s = strstr (nextACE, "allow");
+ if (s == NULL) s = strstr (nextACE, "deny");
+ if (s == NULL) {
+ if (nextACE && *nextACE != '\0')
+ aclutil_str_appened (&ret_str, nextACE);
+ slapi_ch_free ( (void **) &s_aclstr );
+ return (ret_str);
+ }
+ acestr = nextACE;
+ goto normalize_nextACERule;
+ }
+
+ slapi_ch_free ( (void **) &s_aclstr );
+ return (ret_str);
+}
+/*
+ *
+ * acl__getNextLASRule
+ * Find the next rule.
+ *
+ * Returns:
+ * endOfCurrRule - end of current rule
+ * nextRule - start of next rule
+ */
+static char *
+__aclp__getNextLASRule (aci_t *aci_item, char *original_str , char **endOfCurrRule)
+{
+ char *newstr, *word, *next, *start, *end;
+ char *ruleStart = NULL;
+ int len, ruleLen;
+ int in_dn_expr = 0;
+
+ *endOfCurrRule = NULL;
+ end = start = NULL;
+
+ newstr = slapi_ch_strdup (original_str);
+
+ if ( (strncasecmp(newstr, "allow", 5) == 0) ||
+ (strncasecmp(newstr, "deny", 4) == 0) ) {
+ word = ldap_utf8strtok_r(newstr, ")", &next);
+ }
+ else {
+ word = ldap_utf8strtok_r(newstr, " ", &next);
+ }
+
+ /*
+ * The first word is of no interest -- skip it
+ * it's allow or deny followed by the rights (<rights>),
+ * so skip over the rights as well or it's 'and', 'or',....
+ */
+
+ while ( (word = ldap_utf8strtok_r(NULL, " ", &next)) != NULL) {
+ int got_rule = 0;
+ int ruleType = 0;
+ /*
+ ** The next word must be one of these to be considered
+ ** a valid rule.
+ ** This is making me crazy. We might have a case like
+ ** "((userdn=". strtok is returning me that word.
+ */
+ len = strlen ( word );
+ word [len] = '\0';
+
+ if ( (ruleStart= strstr(word, DS_LAS_USERDNATTR)) != NULL) {
+ ruleType |= ACI_USERDNATTR_RULE;
+ ruleLen = strlen ( DS_LAS_USERDNATTR) ;
+ } else if ( (ruleStart = strstr(word, DS_LAS_USERDN)) != NULL) {
+ ruleType = ACI_USERDN_RULE;
+ ruleLen = strlen ( DS_LAS_USERDN);
+ in_dn_expr = 1;
+ } else if ( (ruleStart = strstr(word, DS_LAS_GROUPDNATTR)) != NULL) {
+ ruleType = ACI_GROUPDNATTR_RULE;
+ ruleLen = strlen ( DS_LAS_GROUPDNATTR) ;
+ } else if ((ruleStart= strstr(word, DS_LAS_GROUPDN)) != NULL) {
+ ruleType = ACI_GROUPDN_RULE;
+ ruleLen = strlen ( DS_LAS_GROUPDN) ;
+ in_dn_expr = 1;
+ } else if ((ruleStart = strstr(word, DS_LAS_USERATTR)) != NULL) {
+ ruleType = ACI_USERATTR_RULE;
+ ruleLen = strlen ( DS_LAS_USERATTR) ;
+ } else if ((ruleStart= strstr(word, DS_LAS_ROLEDN)) != NULL) {
+ ruleType = ACI_ROLEDN_RULE;
+ ruleLen = strlen ( DS_LAS_ROLEDN);
+ in_dn_expr = 1;
+ } else if ((ruleStart= strstr(word, DS_LAS_AUTHMETHOD)) != NULL) {
+ ruleType = ACI_AUTHMETHOD_RULE;
+ ruleLen = strlen ( DS_LAS_AUTHMETHOD);
+ } else if ((ruleStart = strstr(word, ACL_ATTR_IP)) != NULL) {
+ ruleType = ACI_IP_RULE;
+ ruleLen = strlen ( ACL_ATTR_IP) ;
+ } else if ((ruleStart = strstr(word, DS_LAS_TIMEOFDAY)) != NULL) {
+ ruleType = ACI_TIMEOFDAY_RULE;
+ ruleLen = strlen ( DS_LAS_TIMEOFDAY) ;
+ } else if ((ruleStart = strstr(word, DS_LAS_DAYOFWEEK)) != NULL) {
+ ruleType = ACI_DAYOFWEEK_RULE;
+ ruleLen = strlen ( DS_LAS_DAYOFWEEK) ;
+ } else if ((ruleStart = strstr(word, ACL_ATTR_DNS)) != NULL) {
+ ruleType = ACI_DNS_RULE;
+ ruleLen = strlen ( ACL_ATTR_DNS) ;
+ }
+ /* Here, we've found a space...if we were in in_dn_expr mode
+ * and we'vve found a closure for that ie.a '"' or a ')'
+ * eg. "'ldap:///all"' or 'ldap:///all")' then exit in_dn_expr mode.
+ */
+ if ( in_dn_expr && (word[len-1] == '"' ||
+ len>1 && word[len-2] == '"' ||
+ len>2 && word[len-3] == '"')) {
+ in_dn_expr = 0;
+ }
+
+ /*
+ * ruleStart may be NULL as word could be (all) for example.
+ * this word will just be skipped--we're really waiting for
+ * userdn or groupdn or...
+ */
+
+ if ( ruleStart && ruleType ) {
+ /* Look in the current word for "=" or else look into
+ ** the next word -- if none of them are true, then this
+ ** is not the start of the rule
+ */
+ char *tmpStr = ruleStart + ruleLen;
+ if ( strchr ( tmpStr, '=') ||
+ ((word = ldap_utf8strtok_r(NULL, " ", &next) ) &&
+ word && ((strncmp ( word, "=", 1) == 0 ) ||
+ (strncmp ( word, "!=",2) ==0) ||
+ (strncmp ( word, ">", 1) == 0 ) ||
+ (strncmp ( word, "<", 1) == 0 ) ||
+ (strncmp ( word, "<", 1) == 0 ) ||
+ (strncmp ( word, "<=",2) ==0 ) ||
+ (strncmp ( word, ">=",2) ==0) ||
+ (strncmp ( word, "=>",2) ==0) ||
+ (strncmp ( word, "=<",2) ==0))
+ ) ){
+ aci_item->aci_ruleType |= ruleType;
+ got_rule = 1;
+ }
+ }
+ if ( NULL == start && got_rule ) {
+ /*
+ * We've just found a rule start--keep going though because
+ * we need to return the end of this rule too.
+ */
+ start= ruleStart;
+ got_rule = 0;
+ } else {
+ /*
+ * Here, we have a candidate for the end of the rule we've found
+ * (the start of which is currently in start).
+ * But we need to be sure it really is the end and not a
+ * "fake end" due to a keyword bbeing embeded in a dn.
+ */
+ if (word && !in_dn_expr &&
+ ((strcasecmp(word, "and") == 0) ||
+ (strcasecmp(word, "or") == 0) ||
+ (strcasecmp(word, "not") == 0) ||
+ (strcasecmp(word, ";") == 0))) {
+ /* If we have start, then it really is the end */
+ word--;
+ if (start) {
+ end = word;
+ break;
+ } else {
+ /* We found a fake end, but we've no start so keep going */
+ }
+ }
+ }
+ } /* while */
+
+
+ if ( end ) {
+ /* Found an end to the rule and it's not the last rule */
+ len = end - newstr;
+ end = original_str +len;
+ while ( (end != original_str) && *end != '\"') end--;
+ *endOfCurrRule = end;
+ len = start - newstr;
+ ruleStart = original_str + len;
+ } else {
+ /* Walked off the end of the string so it's the last rule */
+ end = original_str + strlen(original_str)-1;
+ while ( (end != original_str) && *end != '\"') end--;
+ *endOfCurrRule = end;
+ }
+ if ( start ) {
+ /* Got a rule, fixup the pointer */
+ len = start - newstr;
+ ruleStart = original_str + len;
+ }
+ slapi_ch_free ( (void **) &newstr );
+
+ /*
+ * Here, ruleStart points to the start of the next rule in original_str.
+ * end points to the end of this rule.
+ */
+
+ return ( ruleStart );
+}
+/******************************************************************************
+*
+* __aclp__dn_normalize
+*
+* Normalize the DN INPLACE. This routine is similar to slapi_dn_normalize()
+* except various small stuff at the end.
+* Normalize until the "end" and not to the end of string.
+*
+******************************************************************************/
+static char *
+__aclp__dn_normalize( char *dn , char *end)
+{
+ char *d;
+
+ if ((end - dn) < 0) {
+ return(NULL);
+ }
+
+ d = slapi_dn_normalize_to_end ( dn, end );
+
+ /* Do I have the quotes already */
+ if (*d != '\"' ) {
+ /*
+ ** We are taking care of this situation
+ ** " ") ". We need to remove the space
+ ** infront and tack it after the quote like this.
+ ** "" ) ".
+ */
+
+ *d = '\"';
+ d++;
+ while (*d && *d != '\"') *d++ = ' ';
+ *d = ' ';
+ }
+
+ return( dn );
+}
+/***************************************************************************
+* acl__get_aci_right
+*
+* Go thru the one acl text str and figure our the rights declared.
+*
+*****************************************************************************/
+static int
+__aclp__get_aci_right (char *str)
+{
+
+ char *sav_str = slapi_ch_strdup(str);
+ char *t, *tt;
+ int type = 0;
+ char *delimiter = ",";
+ char *val = NULL;
+ int aclval = 0;
+
+ t = sav_str;
+ __acl_strip_leading_space( &t );
+
+ if (*t == '(' ) {
+ if ((tt = slapi_find_matching_paren(t)) == NULL) {
+ slapi_ch_free ( (void **) &sav_str );
+ return -1;
+ } else {
+ t++; /* skip the first character which is ( */
+ *tt = '\0';
+ }
+ } else {
+ slapi_ch_free ( (void **) &sav_str );
+ return -1;
+ }
+ /* get the tokens separated by "," */
+ val = ldap_utf8strtok_r(t,delimiter, &tt);
+ if (val == NULL )
+ {
+ slapi_ch_free ( (void **) &sav_str );
+ return -1;
+ }
+ while (val != NULL)
+ {
+ /* get the corresponding integer value */
+ aclval = get_acl_rights_as_int(val);
+ if (aclval == -1 )
+ {
+ type = -1;
+ break;
+ }
+ type |= aclval;
+ val = ldap_utf8strtok_r(NULL,delimiter, &tt); /* get the next token */
+ }
+
+ slapi_ch_free ( (void **) &sav_str );
+ return type;
+
+}
+
+static int get_acl_rights_as_int( char * strValue)
+{
+
+ if (strValue == NULL )
+ return -1;
+ /* First strip out the leading and trailing spaces */
+ __acl_strip_leading_space( &strValue );
+ __acl_strip_trailing_space( strValue );
+
+ /* We have to do a strcasecmp (case insensitive cmp) becuase we should return
+ only if it is exact match. */
+
+ if (strcasecmp (strValue, "read") == 0 )
+ return SLAPI_ACL_READ;
+ else if (strcasecmp (strValue, "write") == 0 )
+ return SLAPI_ACL_WRITE;
+ else if (strcasecmp (strValue, "search") == 0 )
+ return SLAPI_ACL_SEARCH;
+ else if (strcasecmp (strValue, "compare") == 0 )
+ return SLAPI_ACL_COMPARE;
+ else if (strcasecmp (strValue, "add") == 0 )
+ return SLAPI_ACL_ADD;
+ else if (strcasecmp (strValue, "delete") == 0 )
+ return SLAPI_ACL_DELETE;
+ else if (strcasecmp (strValue, "proxy") == 0 )
+ return SLAPI_ACL_PROXY;
+ else if (strcasecmp (strValue, "selfwrite") == 0 )
+ return (SLAPI_ACL_SELF | SLAPI_ACL_WRITE);
+ else if (strcasecmp (strValue, "all") == 0 )
+ return SLAPI_ACL_ALL;
+ else
+ return -1; /* error */
+}
+/***************************************************************************
+*
+* acl_access2str
+*
+* Convert the access bits into character strings.
+* Example: "read, self read"
+*
+* Input:
+*
+* int access - The access in bits
+* char **rights - rights in chars
+*
+* Returns:
+* NULL - No rights to start with
+* right - rights converted.
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+char *
+acl_access2str(int access)
+{
+
+ if ( access & SLAPI_ACL_COMPARE ) {
+ return access_str_compare;
+ } else if ( access & SLAPI_ACL_SEARCH ) {
+ return access_str_search;
+ } else if ( access & SLAPI_ACL_READ ) {
+ return access_str_read;
+ } else if ( access & SLAPI_ACL_DELETE) {
+ return access_str_delete;
+ } else if ( access & SLAPI_ACL_ADD) {
+ return access_str_add;
+ } else if ( (access & SLAPI_ACL_WRITE ) && (access & SLAPI_ACL_SELF)) {
+ return access_str_selfwrite;
+ } else if (access & SLAPI_ACL_WRITE ) {
+ return access_str_write;
+ } else if (access & SLAPI_ACL_PROXY ) {
+ return access_str_proxy;
+ }
+
+ return NULL;
+}
+/***************************************************************************
+*
+* __aclp__init_targetattr
+*
+* Parse the targetattr string and create a array of attrs. This will
+* help us to do evaluation at run time little faster.
+* entry.
+* Here, also extract any target value filters.
+*
+* Input:
+* aci_t *aci -- The aci item
+* char *str -- the targetattr string
+*
+* Returns:
+* ACL_OK - everything ok
+* ACL_SYNTAX_ERROR - in case of error.
+*
+*
+***************************************************************************/
+static int
+__aclp__init_targetattr (aci_t *aci, char *attr_val)
+{
+
+ int numattr=0;
+ Targetattr **attrArray;
+ char *s, *end_attr, *str;
+ int len;
+ Targetattr *attr = NULL;
+
+ s = strchr (attr_val, '=');
+ s++;
+ __acl_strip_leading_space(&s);
+ len = strlen(s);
+ if (*s == '"' && s[len-1] == '"') {
+ s[len-1] = '\0';
+ s++;
+ }
+
+ str = s;
+ attrArray = aci->targetAttr;
+
+ if (attrArray[0] != NULL) {
+ /*
+ ** That means we are visiting more than once.
+ ** Syntax error. We have a case like: (targetattr) (targetattr)
+ */
+ return ACL_SYNTAX_ERR;
+ }
+
+ while (str != 0 && *str != 0) {
+
+ __acl_strip_leading_space(&str);
+
+ if ((end_attr = strstr(str, "||")) != NULL) {
+ /* skip the two '|' chars */
+ auto char *t = end_attr;
+ LDAP_UTF8INC(end_attr);
+ LDAP_UTF8INC(end_attr);
+ *t = 0;
+ }
+ __acl_strip_trailing_space(str);
+
+ /*
+ * Here:
+ * end_attr points to the next attribute thing.
+ *
+ * str points to the current one to be processed and it looks like this:
+ * rbyrneXXX Watchout is it OK to use : as the speperator ?
+ * cn
+ * c*n*
+ * *
+ * The attribute goes in the attrTarget list.
+ *
+ */
+
+
+ attr = (Targetattr *) slapi_ch_malloc (sizeof (Targetattr));
+ memset (attr, 0, sizeof(Targetattr));
+
+ if (strchr(str, '*')) {
+
+ /* It contains a * so it's something like * or cn* */
+ if (strcmp(str, "*" ) != 0) {
+ char line[100];
+ char *lineptr = &line[0];
+ char *newline = NULL;
+ int lenstr = 0;
+ struct slapi_filter *f = NULL;
+
+ if ((lenstr = strlen(str)) > 91) { /* 100 - 8 for "(attr =%s)" */
+ newline = slapi_ch_malloc(lenstr + 9);
+ lineptr = newline;
+ }
+
+ attr->attr_type = ACL_ATTR_FILTER;
+ sprintf (lineptr, "(attr =%s)", str);
+ f = slapi_str2filter (lineptr);
+
+ if (f == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, plugin_name,
+ "__aclp__init_targetattr:Unable to generate filter (%s)\n", lineptr,0,0);
+ } else {
+ attr->u.attr_filter = f;
+ }
+
+ if (newline) slapi_ch_free((void **) &newline);
+ } else {
+ attr->attr_type = ACL_ATTR_STAR;
+ attr->u.attr_str = slapi_ch_strdup (str);
+ }
+
+ } else {
+ attr->u.attr_str = slapi_ch_strdup (str);
+ attr->attr_type = ACL_ATTR_STRING;
+ }
+
+
+ /*
+ * Add the attr to the targetAttr list
+ */
+
+ attrArray[numattr] = attr;
+ numattr++;
+ if (!(numattr % ACL_INIT_ATTR_ARRAY)) {
+ aci->targetAttr = (Targetattr **) slapi_ch_realloc (
+ (void *) aci->targetAttr,
+ (numattr+ACL_INIT_ATTR_ARRAY) *
+ sizeof(Targetattr *));
+ attrArray = aci->targetAttr;
+ }
+
+
+ /* Move on to the next attribute in the list */
+ str = end_attr;
+
+ } /* while */
+
+ /* NULL teminate the list */
+ attrArray[numattr] = NULL;
+ return 0;
+}
+
+void
+acl_strcpy_special (char *d, char *s)
+{
+ for (; *s; LDAP_UTF8INC(s)) {
+ switch (*s) {
+ case '.':
+ case '\\':
+ case '[':
+ case ']':
+ case '*':
+ case '+':
+ case '^':
+ case '$':
+ *d = '\\';
+ LDAP_UTF8INC(d);
+ /* FALL */
+ default:
+ d += LDAP_UTF8COPY(d, s);
+ }
+ }
+ *d = '\0';
+}
+/***************************************************************************
+*
+* acl_verify_aci_syntax
+* verify if the aci's being added for the entry has a valid syntax or not.
+*
+* Input:
+* Slapi_Entry *e - The Slapi_Entry itself
+* char **errbuf; -- error message
+*
+* Returns:
+* -1 (ACL_ERR) - Syntax error
+* 0 - No error
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+acl_verify_aci_syntax (Slapi_Entry *e, char **errbuf)
+{
+
+ if (e != NULL) {
+ Slapi_DN *e_sdn;
+ int rv;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval=NULL;
+ const struct berval *attrVal;
+ int i;
+
+ e_sdn = slapi_entry_get_sdn ( e );
+
+ slapi_entry_attr_find (e, aci_attr_type, &attr);
+ if (! attr ) return 0;
+
+ i= slapi_attr_first_value ( attr,&sval );
+ while ( i != -1 ) {
+ attrVal = slapi_value_get_berval ( sval );
+ rv=acl_verify_syntax ( e_sdn, attrVal);
+ if ( 0 != rv ) {
+ aclutil_print_err(rv, e_sdn, attrVal, errbuf);
+ return ACL_ERR;
+ }
+ i = slapi_attr_next_value ( attr, i, &sval );
+ }
+ }
+ return(0);
+}
+/***************************************************************************
+*
+* acl__verify_syntax
+* Called from slapi_acl_check_mods() to verify if the new aci being
+* added/replaced has the right syntax or not.
+*
+* Input:
+* Slapi_DN *e_sdn - sdn of the entry
+* berval *bval - The berval containg the aci value
+*
+* Returns:
+* return values from acl__parse_aci()
+*
+* Error Handling:
+* None.
+*
+**************************************************************************/
+int
+acl_verify_syntax(const Slapi_DN *e_sdn, const struct berval *bval)
+{
+ aci_t *aci_item;
+ int rv = 0;
+ char *str;
+ aci_item = acllist_get_aci_new ();
+ slapi_sdn_set_ndn_byval ( aci_item->aci_sdn, slapi_sdn_get_ndn ( e_sdn ) );
+
+ /* make a copy the the string */
+ str = slapi_ch_strdup(bval->bv_val);
+ rv = acl_parse(str, aci_item);
+
+ /* cleanup before you leave ... */
+ acllist_free_aci (aci_item);
+ slapi_ch_free ( (void **) &str );
+ return(rv);
+}
+static void
+__aclp_chk_paramRules ( aci_t *aci_item, char *start, char *end)
+{
+
+ size_t len;
+ char *str;
+ char *p, *s;
+
+
+ len = end - start;
+
+ s = str = (char *) slapi_ch_calloc(1, len + 1);
+ memcpy ( str, start, len);
+ while ( (p= strchr ( s, '$')) != NULL) {
+ p++; /* skip the $ */
+ if ( 0 == strncasecmp ( p, "dn", 2))
+ aci_item->aci_ruleType |= ACI_PARAM_DNRULE;
+ else if ( 0 == strncasecmp ( p, "attr", 4))
+ aci_item->aci_ruleType |= ACI_PARAM_ATTRRULE;
+
+ s = p;
+ }
+ slapi_ch_free ( (void **) &str );
+}
+
+/*
+ * Check for an ocurrence of a macro aci in the target.
+ * value is the normalized target string.
+ *
+ * this is something like:
+ * (target="ldap:///cn=*,ou=people,($dn),o=sun.com")
+ *
+ *
+ * returns 1 if there is a $dn present.
+ * returns 0 if not.
+ * returns -1 is syntax error.
+ * If succes then:
+ * ACI_TARGET_MACRO_DN is the type.
+ * type can also include, ACI_TARGET_PATTERN, ACI_TARGET_NOT.
+ * Also aci_item->aci_macro->match_this is set to be
+ * cn=*,ou=people,($dn),o=sun.com, to be used later.
+ *
+ * . we allow at most one ($dn) in a target.
+ * . if a "*" accurs with it, it must be the first component and at most
+ * once.
+ * . it's ok for ($dn) to occur on it's own in a target, but if it appears in
+ * a user rule, then it must be in the target.
+ *
+ *
+ *
+*/
+
+static int
+acl_check_for_target_macro( aci_t *aci_item, char *value)
+{
+
+ char *str = NULL;
+
+ str = strstr( value, ACL_TARGET_MACRO_DN_KEY);
+
+ if (str != NULL) {
+ aci_item->aci_type &= ~ACI_TARGET_DN;
+ aci_item->aci_type |= ACI_TARGET_MACRO_DN;
+ aci_item->aci_macro = (aciMacro *)slapi_ch_malloc(sizeof(aciMacro));
+ aci_item->aci_macro->match_this = slapi_ch_strdup(value);
+ aci_item->aci_macro->macro_ptr = strstr( aci_item->aci_macro->match_this,
+ ACL_TARGET_MACRO_DN_KEY);
+ return(1);
+ }
+
+ return(0);
+}
+
+/* Strip trailing spaces from str by writing '\0' into them */
+
+static void
+__acl_strip_trailing_space( char *str) {
+
+ char *ptr = NULL;
+ int len = 0;
+
+ if (*str) {
+ /* ignore trailing whitespace */
+ len = strlen(str);
+ ptr = str+len-1;
+ while(ldap_utf8isspace(ptr)){ *ptr = '\0'; LDAP_UTF8DEC(ptr); }
+ }
+}
+
+/*
+ * Strip leading spaces by resetting str to point to the first
+ * non-space charater.
+*/
+
+static void
+__acl_strip_leading_space( char **str) {
+
+ char *tmp_ptr = NULL;
+
+ tmp_ptr = *str;
+ while ( *tmp_ptr && ldap_utf8isspace( tmp_ptr ) ) LDAP_UTF8INC(tmp_ptr);
+ *str = tmp_ptr;
+}
+
+
+/*
+ * str is a string containing an LDAP filter.
+ * Trim off enclosing quotes and enclosing
+ * superfluous brackets.
+ * The result is duped so it can be kept.
+*/
+
+static char *
+__acl_trim_filterstr( char * str ) {
+
+ char *tmpstr;
+ int len;
+ char *end;
+
+ tmpstr = str;
+
+ /* If the last char is a "," take it out */
+
+ len = strlen (tmpstr);
+ if (len>0 && (tmpstr[len-1] == ',')) {
+ tmpstr [len-1] = '\0';
+ }
+
+
+ /* Does it have quotes around it */
+ len = strlen (tmpstr);
+ if (*tmpstr == '"' && tmpstr[len-1] == '"') {
+ tmpstr [len-1] = '\0';
+ tmpstr++;
+ }
+
+ str = tmpstr;
+
+ /* If we have a filter like
+ ** (((&(...) (...)))), we need to get rid of the
+ ** multiple parens or slapi_str2filter will not
+ ** evaluate properly. Need to package like
+ ** (filter ). probably I should fix str2filter
+ ** code.
+ */
+
+ while (*tmpstr++ == '(' && *tmpstr == '(') {
+ if ((end = slapi_find_matching_paren( str )) != NULL) {
+ *end = '\0';
+ str++;
+ }
+ }
+
+ return( slapi_ch_strdup(str));
+}
+
+/*
+ * Here str points to a targetattrfilters thing which looks tlike this:
+ *
+ * targetattrfilters="add=attr1:F1 && attr2:F2 ... && attrn:Fn,
+ * del=attr1:F1 && attr2:F2... && attrn:Fn")
+ *
+ *
+ */
+
+static int __acl__init_targetattrfilters( aci_t *aci, char *input_str) {
+
+ int numattr=0;
+ char *s, *str;
+ int len;
+ char *addlistptr = NULL;
+ char *dellistptr = NULL;
+
+ if (aci->targetAttrAddFilters != NULL ||
+ aci->targetAttrDelFilters != NULL) {
+
+ /*
+ ** That means we are visiting more than once.
+ ** Syntax error.
+ ** We have a case like: (targetattrfilters) (targetattrfilters)
+ */
+
+ return ACL_SYNTAX_ERR;
+ }
+
+ /* First, skip the "targetattrfilters" */
+
+ s = strchr (input_str, '=');
+ s++; /* skip the = */
+ __acl_strip_leading_space(&s); /* skip to next significant character */
+ len = strlen(s); /* Knock off the " and trailing ) */
+ if (*s == '"' && s[len-1] == '"') {
+ s[len-1] = '\0';
+ s++; /* skip the first " */
+ } else { /* No matching quotes */
+
+ return (ACL_SYNTAX_ERR);
+ }
+
+ str = s;
+
+ /*
+ * Here str looks like add=attr1:F1...attrn:Fn,
+ * del=attr1:F1...attrn:Fn
+ *
+ * extract the add and del filter lists and process each one
+ * in turn.
+ */
+
+ s = strchr (str, '=');
+ *s = '\0';
+ s++; /* skip the = */
+ __acl_strip_leading_space(&s); /* start of the first filter list */
+
+
+ /*
+ * Now str is add or del
+ * s points to the first filter list.
+ */
+
+ if (strcmp(str, "add") == 0) {
+ aci->aci_type |= ACI_TARGET_ATTR_ADD_FILTERS;
+ addlistptr = s;
+
+ /* Now isolate the first filter list. */
+ if ((str = strstr(s , "del=")) || ((str = strstr(s , "del ="))) ) {
+ str--;
+ *str = '\0';
+ *str++;
+ }
+
+
+ } else if (strcmp(str, "del") == 0) {
+ aci->aci_type |= ACI_TARGET_ATTR_DEL_FILTERS;
+ dellistptr = s;
+
+ /* Now isolate the first filter list. */
+ if ((str = strstr(s , "add=")) || ((str = strstr(s , "add ="))) ) {
+ str--;
+ *str = '\0';
+ *str++;
+ }
+ } else {
+ return(ACL_SYNTAX_ERR);
+ }
+
+ __acl_strip_trailing_space(s);
+
+ /*
+ * Here, we have isolated the first filter list.
+ * There may be a second one.
+ * Now, str points to the start of the
+ * string that contains the second filter list.
+ * If there is none then str is NULL.
+ */
+
+ if (str != NULL ){
+
+ __acl_strip_leading_space(&str);
+ s = strchr (str, '=');
+ *s = '\0';
+ s++;
+ __acl_strip_trailing_space(str);
+ __acl_strip_leading_space(&s);
+
+
+ /*
+ * s points to the start of the second filter list.
+ * str is add or del
+ */
+
+ if (aci->aci_type & ACI_TARGET_ATTR_ADD_FILTERS) {
+
+ if (strcmp(str, "del") == 0) {
+ aci->aci_type |= ACI_TARGET_ATTR_DEL_FILTERS;
+ dellistptr = s;
+ } else {
+ return(ACL_SYNTAX_ERR);
+ }
+ } else if ( aci->aci_type & ACI_TARGET_ATTR_DEL_FILTERS ) {
+ if (strcmp(str, "add") == 0) {
+ aci->aci_type |= ACI_TARGET_ATTR_ADD_FILTERS;
+ addlistptr = s;
+ } else {
+ return(ACL_SYNTAX_ERR);
+ }
+ }
+ }
+
+ /*
+ * addlistptr points to the add filter list.
+ * dellistptr points to the del filter list.
+ * In both cases the strings have been leading and trailing space
+ * stripped.
+ * Either may be NULL.
+ */
+
+ if (process_filter_list( &aci->targetAttrAddFilters, addlistptr)
+ == ACL_SYNTAX_ERR) {
+ return( ACL_SYNTAX_ERR);
+ }
+
+ if (process_filter_list( &aci->targetAttrDelFilters, dellistptr)
+ == ACL_SYNTAX_ERR) {
+ return( ACL_SYNTAX_ERR);
+ }
+
+ return(0);
+
+}
+
+/*
+ * We have a list of filters that looks like this:
+ * attr1:F1 &&....attrn:Fn
+ *
+ * We need to put each component into a targetattrfilter component of
+ * the array.
+ *
+*/
+
+static int process_filter_list( Targetattrfilter ***input_attrFilterArray,
+ char * input_str) {
+
+ char *str, *end_attr, *tmp_attr;
+ Targetattrfilter *attrfilter = NULL;
+ int numattr=0;
+ Targetattrfilter **attrFilterArray = NULL;
+
+ str = input_str;
+
+ while (str != 0 && *str != 0) {
+
+ if ((end_attr = strstr(str, "&&")) != NULL) {
+ /* skip the two '|' chars */
+ auto char *t = end_attr;
+ LDAP_UTF8INC(end_attr);
+ LDAP_UTF8INC(end_attr);
+ *t = 0;
+ }
+ __acl_strip_trailing_space(str);
+ __acl_strip_leading_space(&str);
+
+ /*
+ * Here:
+ * end_attr points to the next attribute thing.
+ *
+ * str points to the current one to be processed and it looks like
+ * this:
+ *
+ * attr1:F1
+ *
+ */
+
+ attrfilter = (Targetattrfilter *) slapi_ch_malloc (sizeof (Targetattrfilter));
+ memset (attrfilter, 0, sizeof(Targetattrfilter));
+
+ if ((tmp_attr = strstr( str,":")) != NULL) {
+
+ if ( __acl_init_targetattrfilter( attrfilter, str ) != 0 ) {
+ slapi_ch_free((void**)&attrfilter);
+ return(ACL_SYNTAX_ERR);
+ }
+ } else {
+ slapi_ch_free((void**)&attrfilter);
+ return(ACL_SYNTAX_ERR);
+ }
+
+
+ /*
+ * Add the attrfilte to the targetAttrFilter list
+ */
+
+
+ attrFilterArray = (Targetattrfilter **) slapi_ch_realloc (
+ (void *) attrFilterArray,
+ ((numattr+1)*sizeof(Targetattrfilter *)) );
+ attrFilterArray[numattr] = attrfilter;
+ numattr++;
+
+ /* Move on to the next attribute in the list */
+ str = end_attr;
+
+ }/* while */
+
+ /* NULL terminate the list */
+
+ attrFilterArray = (Targetattrfilter **) slapi_ch_realloc (
+ (void *) attrFilterArray,
+ ((numattr+1)*sizeof(Targetattrfilter *)) );
+ attrFilterArray[numattr] = NULL;
+
+ *input_attrFilterArray = attrFilterArray;
+ return 0;
+
+}
+
+/*
+ * Take str and put it into the attrfilter component.
+ *
+ * str looks as follows: attr1:F1
+ *
+ * It has had leading and trailing space stripped.
+*/
+
+static int __acl_init_targetattrfilter( Targetattrfilter *attrfilter,
+ char *str ) {
+
+ char *tmp_ptr, *s, *filter_ptr;
+ Slapi_Filter *f = NULL;
+
+ s = str;
+
+ /* First grab the attribute name */
+
+ if ( (tmp_ptr = strstr( str, ":")) == NULL ) {
+ /* No :, syntax error */
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Bad targetattrfilter %s:%s\n",
+ str,"Expecting \":\"",0);
+
+ return(ACL_SYNTAX_ERR);
+ }
+ *tmp_ptr = '\0';
+ LDAP_UTF8INC(tmp_ptr);
+
+ __acl_strip_trailing_space(s);
+
+ /* s should be the attribute name-make sure it's non-empty. */
+
+ if ( *s == '\0' ) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "No attribute name in targattrfilters\n",
+ 0,0);
+ return(ACL_SYNTAX_ERR);
+ }
+
+ attrfilter->attr_str = slapi_ch_strdup (s);
+
+ /* Now grab the filter */
+
+ filter_ptr = tmp_ptr;
+ __acl_strip_leading_space(&filter_ptr);
+ __acl_strip_trailing_space(filter_ptr);
+
+ /* trim dups the string, so we need to free it later if it's not kept. */
+ tmp_ptr = __acl_trim_filterstr(filter_ptr);
+
+ if ((f = slapi_str2filter(tmp_ptr)) == NULL) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Bad targetattr filter for attribute %s:%s\n",
+ attrfilter->attr_str,tmp_ptr,0);
+ slapi_ch_free( (void **) &attrfilter->attr_str);
+ slapi_ch_free( (void **) &tmp_ptr);
+ return(ACL_SYNTAX_ERR);
+ }
+
+ /*
+ * Here verify that the named attribute is the only one
+ * that appears in the filter.
+ */
+
+ if (acl_verify_exactly_one_attribute( attrfilter->attr_str, f) !=
+ SLAPI_FILTER_SCAN_NOMORE) {
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,
+ "Exactly one attribute type per filter allowed in targattrfilters (%s)\n",
+ attrfilter->attr_str, 0);
+ slapi_ch_free( (void **) &attrfilter->attr_str);
+ slapi_ch_free( (void **) &tmp_ptr);
+ slapi_filter_free( f, 1 );
+ return(ACL_SYNTAX_ERR);
+ }
+
+ /* free the tmp_ptr */
+ slapi_ch_free( (void **) &tmp_ptr);
+ attrfilter->filterStr = slapi_ch_strdup (filter_ptr);
+ attrfilter->filter = f;
+
+ return(LDAP_SUCCESS);
+}
+
+/*
+ * Returns 0 if attr_name is the only attribute name to
+ * appear in original_filter AND it appears at least once.
+ * Otherwise returns STOP_FILTER_SCAN.
+*/
+
+static int acl_verify_exactly_one_attribute( char *attr_name,
+ Slapi_Filter *original_filter) {
+ int error_code;
+
+ return( slapi_filter_apply( original_filter, type_compare,
+ (void *)attr_name, &error_code));
+
+}
+
+static int type_compare( Slapi_Filter *f, void *arg) {
+
+ /* Compare only the base names: eg cn and cn;lang-eb will be the same. */
+
+ char *t = (char *)arg;
+ char *filter_type;
+ int rc = SLAPI_FILTER_SCAN_STOP;
+
+ if (slapi_filter_get_attribute_type( f, &filter_type) == 0) {
+ t = slapi_attr_syntax_normalize(t);
+ filter_type = slapi_attr_syntax_normalize(filter_type);
+
+ if (slapi_attr_type_cmp(filter_type, t, 1) == 0) {
+ rc = SLAPI_FILTER_SCAN_CONTINUE;
+ }
+
+ slapi_ch_free( (void **)&t );
+ slapi_ch_free( (void **)&filter_type );
+ }
+
+ return rc;
+}
diff --git a/ldap/servers/plugins/acl/aclplugin.c b/ldap/servers/plugins/acl/aclplugin.c
new file mode 100644
index 00000000..a39ef3cd
--- /dev/null
+++ b/ldap/servers/plugins/acl/aclplugin.c
@@ -0,0 +1,355 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * There are 3 ACL PLUGIN points
+ * PREOP, POSTOP and ACL plugin
+ *
+ */
+#include "acl.h"
+#include "dirver.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+
+static Slapi_PluginDesc pdesc = { "acl", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "acl access check plugin" };
+char *plugin_name = ACL_PLUGIN_NAME;
+
+/* Prototypes */
+
+static int aclplugin_preop_search ( Slapi_PBlock *pb );
+static int aclplugin_preop_modify ( Slapi_PBlock *pb );
+static int aclplugin_preop_common ( Slapi_PBlock *pb );
+
+/*******************************************************************************
+ * ACL PLUGIN Architecture
+ *
+ * There are 3 registered plugins:
+ *
+ * 1) PREOP ACL Plugin
+ * The preop plugin does all the initialization. It allocate the ACL
+ * PBlock and copies stuff from the connection if it needs to.
+ *
+ * 2) POSTOP ACL Plugin
+ * The Postop plugin cleans up the ACL PBlock. It copies Back to the
+ * connection struct. The Postop bind & Unbind cleans up the
+ * ACL CBlock ( struct hanging from conn struct ).
+ *
+ * 3) ACCESSCONTROL Plugin
+ * Main module which does the access check. There are 5 entry point
+ * from this plugin
+ * a) Initilize the ACL system i.e read all the ACLs and generate the
+ * the ACL List.
+ * b) Check for ACI syntax.
+ * c) Check for normal access.
+ * d) Check for access to a mod request.
+ * e) Update the in-memory ACL List.
+ *
+ *******************************************************************************/
+
+/*******************************************************************************
+ * PREOP
+ *******************************************************************************/
+
+/* Plugin identity is passed by the server in the plugin init function and must
+ be supplied by the plugin to all internal operations it initiates
+ */
+void* g_acl_preop_plugin_identity;
+
+int
+acl_preopInit (Slapi_PBlock *pb)
+{
+ int rc = 0;
+
+ /* save plugin identity to later pass to internal operations */
+ rc = slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &g_acl_preop_plugin_identity);
+
+ /* Declare plugin version */
+ rc = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01);
+
+ /* Provide descriptive information */
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION, (void*)&pdesc);
+
+ /* Register functions */
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void*)aclplugin_preop_search);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_COMPARE_FN, (void*)aclplugin_preop_search);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN, (void*)aclplugin_preop_modify);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void*)aclplugin_preop_modify);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN, (void*)aclplugin_preop_modify);
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_DELETE_FN, (void*)aclplugin_preop_modify);
+
+#if 0
+ /*
+ * XXXmcs: In order to support access control checking from
+ * extended operations, we need a SLAPI_PLUGIN_PRE_EXTENDED_FN hook.
+ * But today no such entry point exists.
+ */
+ rc |= slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_EXTENDED_FN, (void*)aclplugin_preop_modify);
+#endif
+
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= acl_preop_Init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+/* For preop search we do two things:
+ * 1) based on the search base, we preselect the acls.
+ * 2) also get hold of a acl_pblock for use
+ */
+static int
+aclplugin_preop_search ( Slapi_PBlock *pb )
+{
+ int scope;
+ char *base = NULL;
+ int optype;
+ int isRoot;
+ int rc = 0;
+
+ TNF_PROBE_0_DEBUG(aclplugin_preop_search_start ,"ACL","");
+
+ slapi_pblock_get ( pb, SLAPI_OPERATION_TYPE, &optype );
+ slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot );
+
+ if ( isRoot ) {
+ TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
+ tnf_string,isroot,"");
+ return rc;
+ }
+
+ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base );
+ /* For anonymous client doing search nothing needs to be set up */
+ if ( optype == SLAPI_OPERATION_SEARCH && aclanom_is_client_anonymous ( pb ) &&
+ ! slapi_dn_issuffix( base, "cn=monitor") ) {
+ TNF_PROBE_1_DEBUG(aclplugin_preop_search_end ,"ACL","",
+ tnf_string,anon,"");
+ return rc;
+ }
+
+ if ( 0 == ( rc = aclplugin_preop_common( pb ))) {
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
+ acllist_init_scan ( pb, scope, base );
+ }
+
+ TNF_PROBE_0_DEBUG(aclplugin_preop_search_end ,"ACL","");
+
+ return rc;
+}
+
+/*
+ * For rest of the opertion type, we get a hold of the acl
+ * private Block.
+ */
+static int
+aclplugin_preop_modify ( Slapi_PBlock *pb )
+{
+ /*
+ * Note: since we don't keep the anom profile for modifies, we have to go
+ * through the regular process to check the access.
+ */
+ return aclplugin_preop_common( pb );
+}
+
+/*
+ * Common function that is called by aclplugin_preop_search() and
+ * aclplugin_preop_modify().
+ *
+ * Return values:
+ * 0 - all is well; proceed.
+ * 1 - fatal error; result has been sent to client.
+ */
+static int
+aclplugin_preop_common( Slapi_PBlock *pb )
+{
+ char *proxy_dn; /* id being assumed */
+ char *dn; /* proxy master */
+ char *errtext = NULL;
+ int lderr;
+ Acl_PBlock *aclpb;
+
+ TNF_PROBE_0_DEBUG(aclplugin_preop_common_start ,"ACL","");
+
+ aclpb = acl_get_aclpb ( pb, ACLPB_BINDDN_PBLOCK );
+
+ /*
+ * The following mallocs memory for proxy_dn, but not the dn.
+ * The proxy_dn is the id being assumed, while dn
+ * is the "proxy master".
+ */
+ proxy_dn = NULL;
+ if ( LDAP_SUCCESS != ( lderr = acl_get_proxyauth_dn( pb, &proxy_dn,
+ &errtext ))) {
+ /*
+ * Fatal error -- send a result to the client and arrange to skip
+ * any further processing.
+ */
+ slapi_send_ldap_result( pb, lderr, NULL, errtext, 0, NULL );
+ TNF_PROBE_1_DEBUG(aclplugin_preop_common_end ,"ACL","",
+ tnf_string,proxid_error,"");
+
+ return 1; /* skip any further processing */
+ }
+ slapi_pblock_get ( pb, SLAPI_REQUESTOR_DN, &dn );
+
+
+ /*
+ * The dn is copied into the aclpb during initialization.
+ */
+ if ( proxy_dn) {
+ TNF_PROBE_0_DEBUG(proxyacpb_init_start,"ACL","");
+
+ slapi_log_error( SLAPI_LOG_ACL, plugin_name,
+ "proxied authorization dn is (%s)\n", proxy_dn );
+ acl_init_aclpb ( pb, aclpb, proxy_dn, 1 );
+ aclpb = acl_new_proxy_aclpb (pb );
+ acl_init_aclpb ( pb, aclpb, dn, 0 );
+ slapi_ch_free ( (void **) &proxy_dn );
+
+ TNF_PROBE_0_DEBUG(proxyacpb_init_end,"ACL","");
+
+ } else {
+ TNF_PROBE_0_DEBUG(aclpb_init_start,"ACL","");
+ acl_init_aclpb ( pb, aclpb, dn, 1 );
+ TNF_PROBE_0_DEBUG(aclpb_init_end,"ACL","");
+
+ }
+
+ TNF_PROBE_0_DEBUG(aclplugin_preop_common_end ,"ACL","");
+
+ return 0;
+}
+
+/*******************************************************************************
+ * POSTOP
+ *******************************************************************************/
+
+/*******************************************************************************
+ * ACCESSCONTROL PLUGIN
+ *******************************************************************************/
+
+void* g_acl_plugin_identity;
+
+/* For now, the acl component is implemented as 2 different plugins */
+/* Return the right plugin identity */
+void * aclplugin_get_identity(int plug) {
+ if (plug == ACL_PLUGIN_IDENTITY)
+ return g_acl_plugin_identity;
+ if (plug == ACL_PREOP_PLUGIN_IDENTITY)
+ return g_acl_preop_plugin_identity;
+ return NULL;
+}
+
+int
+aclplugin_init (Slapi_PBlock *pb )
+{
+
+ int rc = 0; /* OK */
+ rc = aclinit_main ( pb );
+
+ return rc;
+
+}
+int
+aclplugin_stop ( Slapi_PBlock *pb )
+{
+ int rc = 0; /* OK */
+
+ /* nothing to be done now */
+ return rc;
+}
+
+int
+acl_init( Slapi_PBlock *pb )
+{
+ int rc =0;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "=> acl_init\n", 0, 0, 0 );
+
+ if ( 0 != acl_init_ext() ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, plugin_name,
+ "Unable to initialize the extensions\n");
+ return 1;
+ }
+
+ /* save plugin identity to later pass to internal operations */
+ rc = slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &g_acl_plugin_identity);
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc );
+
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) aclplugin_init );
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) aclplugin_stop );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_SYNTAX_CHECK,
+ (void *) acl_verify_aci_syntax );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_ALLOW_ACCESS,
+ (void *) acl_access_allowed_main );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_MODS_ALLOWED,
+ (void *) acl_check_mods );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_ACL_MODS_UPDATE,
+ (void *) acl_modified );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= acl_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+/*
+ *
+ * acl_access_allowed_main
+ * Main interface to the plugin. Calls different access check functions
+ * based on the flag.
+ *
+ *
+ * Returns:
+ * LDAP_SUCCESS -- access is granted
+ * LDAP_INSUFFICIENT_ACCESS -- access denied
+ * <other ldap error> -- ex: opererations error
+ *
+ */
+int
+acl_access_allowed_main ( Slapi_PBlock *pb, Slapi_Entry *e, char **attrs,
+ struct berval *val, int access , int flags, char **errbuf)
+{
+ int rc =0;
+ char *attr = NULL;
+
+ TNF_PROBE_0_DEBUG(acl_access_allowed_main_start,"ACL","");
+
+ if (attrs && *attrs) attr = attrs[0];
+
+ if (ACLPLUGIN_ACCESS_READ_ON_ENTRY == flags)
+ rc = acl_read_access_allowed_on_entry ( pb, e, attrs, access);
+ else if ( ACLPLUGIN_ACCESS_READ_ON_ATTR == flags)
+ rc = acl_read_access_allowed_on_attr ( pb, e, attr, val, access);
+ else if ( ACLPLUGIN_ACCESS_READ_ON_VLV == flags)
+ rc = acl_access_allowed_disjoint_resource ( pb, e, attr, val, access);
+ else if ( ACLPLUGIN_ACCESS_MODRDN == flags)
+ rc = acl_access_allowed_modrdn ( pb, e, attr, val, access);
+ else if ( ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS == flags)
+ rc = acl_get_effective_rights ( pb, e, attrs, val, access, errbuf );
+ else
+ rc = acl_access_allowed ( pb, e, attr, val, access);
+
+ /* generate the appropriate error message */
+ if ( ( rc != LDAP_SUCCESS ) && errbuf &&
+ ( ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS != flags ) &&
+ ( access & ( SLAPI_ACL_WRITE | SLAPI_ACL_ADD | SLAPI_ACL_DELETE ))) {
+
+ char *edn = slapi_entry_get_dn ( e );
+
+ acl_gen_err_msg(access, edn, attr, errbuf);
+ }
+
+ TNF_PROBE_0_DEBUG(acl_access_allowed_main_end,"ACL","");
+
+ return rc;
+}
+#ifdef _WIN32
+
+int *module_ldap_debug = 0;
+void plugin_init_debug_level ( int *level_ptr )
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
diff --git a/ldap/servers/plugins/acl/aclproxy.c b/ldap/servers/plugins/acl/aclproxy.c
new file mode 100644
index 00000000..9065bddc
--- /dev/null
+++ b/ldap/servers/plugins/acl/aclproxy.c
@@ -0,0 +1,195 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "acl.h"
+
+#define BEGIN do {
+#define END } while(0);
+
+/* ------------------------------------------------------------
+ * LDAPProxyAuth
+ *
+ * ProxyAuthControl ::= SEQUENCE {
+ * authorizationDN LDAPDN
+ * }
+ */
+struct LDAPProxyAuth
+{
+ char *auth_dn;
+};
+typedef struct LDAPProxyAuth LDAPProxyAuth;
+
+/*
+ * delete_LDAPProxyAuth
+ */
+static void
+delete_LDAPProxyAuth(LDAPProxyAuth *spec)
+{
+ if (!spec) return;
+
+ slapi_ch_free((void**)&spec->auth_dn);
+ slapi_ch_free((void**)&spec);
+}
+
+/*
+ * parse_LDAPProxyAuth
+ *
+ * Parse a BER encoded value into the compoents of the LDAP ProxyAuth control.
+ * The 'version' parameter should be 1 or 2.
+ *
+ * Returns an LDAP error code (LDAP_SUCCESS if all goes well) and sets
+ * *errtextp if appropriate.
+ */
+static int
+parse_LDAPProxyAuth(struct berval *spec_ber, int version, char **errtextp,
+ LDAPProxyAuth **out)
+{
+ int lderr = LDAP_OPERATIONS_ERROR; /* pessimistic */
+ LDAPProxyAuth *spec = NULL;
+ BerElement *ber = NULL;
+ char *errstring = "unable to parse proxied authorization control";
+
+
+ BEGIN
+ unsigned long tag;
+
+ if ( version != 1 && version != 2 ) {
+ break;
+ }
+
+ /* create_LDAPProxyAuth */
+ spec = (LDAPProxyAuth*)slapi_ch_calloc(1,sizeof (LDAPProxyAuth));
+ if (!spec) {
+ break;
+ }
+
+ ber = ber_init(spec_ber);
+ if (!ber) {
+ break;
+ }
+
+ if ( version == 1 ) {
+ tag = ber_scanf(ber, "{a}", &spec->auth_dn);
+ } else {
+ tag = ber_scanf(ber, "a", &spec->auth_dn);
+ }
+ if (tag == LBER_ERROR) {
+ lderr = LDAP_PROTOCOL_ERROR;
+ break;
+ }
+
+ /*
+ * In version 2 of the control, the control value is actually an
+ * authorization ID (see section 9 of RFC 2829). We only support
+ * the "dnAuthzId" flavor, which looks like "dn:<DN>" where <DN> is
+ * an actual DN, e.g., "dn:uid=bjensen,dc=example,dc=com". So we
+ * need to strip off the dn: if present and reject the operation if
+ * not.
+ */
+ if (2 == version) {
+ if ( NULL == spec->auth_dn || strlen( spec->auth_dn ) < 3 ||
+ strncmp( "dn:", spec->auth_dn, 3 ) != 0 ) {
+ lderr = LDAP_INSUFFICIENT_ACCESS; /* per Proxied Auth. I-D */
+ errstring = "proxied authorization id must be a DN (dn:...)";
+ break;
+ }
+ strcpy( spec->auth_dn, spec->auth_dn + 3 );
+ }
+
+ slapi_dn_normalize(spec->auth_dn);
+ lderr = LDAP_SUCCESS; /* got it! */
+ END
+
+ /* Cleanup */
+ if (ber) ber_free(ber, 0);
+
+ if ( LDAP_SUCCESS != lderr)
+ {
+ if (spec) delete_LDAPProxyAuth(spec);
+ spec = 0;
+ if ( NULL != errtextp ) {
+ *errtextp = errstring;
+ }
+ }
+
+ *out = spec;
+
+ return lderr;
+}
+
+/*
+ * proxyauth_dn - find the users DN in the proxyauth control if it is
+ * present. The return value has been malloced for you.
+ *
+ * Returns an LDAP error code. If anything than LDAP_SUCCESS is returned,
+ * the error should be returned to the client. LDAP_SUCCESS is always
+ * returned if the proxy auth control is not present or not critical.
+ */
+int
+acl_get_proxyauth_dn( Slapi_PBlock *pb, char **proxydnp, char **errtextp )
+{
+ char *dn = 0;
+ LDAPProxyAuth *spec = 0;
+ int rv, lderr = LDAP_SUCCESS; /* optimistic */
+
+ BEGIN
+ struct berval *spec_ber;
+ LDAPControl **controls;
+ int present;
+ int critical;
+ int version = 1;
+
+ rv = slapi_pblock_get( pb, SLAPI_REQCONTROLS, &controls );
+ if (rv) break;
+
+ present = slapi_control_present( controls, LDAP_CONTROL_PROXYAUTH,
+ &spec_ber, &critical );
+ if (!present) {
+ present = slapi_control_present( controls, LDAP_CONTROL_PROXIEDAUTH,
+ &spec_ber, &critical );
+ if (!present) break;
+ version = 2;
+ /*
+ * Note the according to the Proxied Authorization I-D, the
+ * control is always supposed to be marked critical by the
+ * client. If it is not, we return a protocolError.
+ */
+ if ( !critical ) {
+ lderr = LDAP_PROTOCOL_ERROR;
+ if ( NULL != errtextp ) {
+ *errtextp = "proxy control must be marked critical";
+ }
+ break;
+ }
+ }
+
+ rv = parse_LDAPProxyAuth(spec_ber, version, errtextp, &spec);
+ if (LDAP_SUCCESS != rv) {
+ if ( critical ) {
+ lderr = rv;
+ }
+ break;
+ }
+
+ dn = slapi_ch_strdup(spec->auth_dn);
+ if (slapi_dn_isroot(dn) ) {
+ lderr = LDAP_UNWILLING_TO_PERFORM;
+ *errtextp = "Proxy dn should not be rootdn";
+ break;
+
+ }
+ END
+
+ if (spec) delete_LDAPProxyAuth(spec);
+
+ if ( NULL != proxydnp ) {
+ *proxydnp = dn;
+ } else {
+ slapi_ch_free( (void **)&dn );
+ }
+
+ return lderr;
+}
+
diff --git a/ldap/servers/plugins/acl/aclutil.c b/ldap/servers/plugins/acl/aclutil.c
new file mode 100644
index 00000000..168ca482
--- /dev/null
+++ b/ldap/servers/plugins/acl/aclutil.c
@@ -0,0 +1,1475 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "acl.h"
+
+/**************************************************************************
+* Defines and usefuls stuff
+****************************************************************************/
+
+/*************************************************************************
+* Prototypes
+*************************************************************************/
+static void aclutil__typestr (int type , char str[]);
+static void aclutil__Ruletypestr (int type , char str[]);
+static char* __aclutil_extract_dn_component ( char **e_dns, int position,
+ char *attrName );
+static char* acl_get_final_component(char *macro_prefix) ;
+static char* acl_match_component( char *start, char *component);
+static int aclutil_compare_components( char * comp1, char *comp2);
+static int acl_find_comp_start(char * s, int pos );
+static PRIntn acl_ht_free_entry_and_value(PLHashEntry *he, PRIntn i,
+ void *arg);
+static PLHashNumber acl_ht_hash( const void *key);
+static PRIntn acl_ht_display_entry(PLHashEntry *he, PRIntn i, void *arg);
+
+/***************************************************************************/
+/* UTILITY FUNCTIONS */
+/***************************************************************************/
+int
+aclutil_str_appened(char **str1, const char *str2)
+{
+ int new_len;
+
+ if ( str1 == NULL || str2 == NULL )
+ return(0);
+
+ if ( *str1 == NULL ) {
+ new_len = strlen(str2) + 1;
+ *str1 = (char *)slapi_ch_malloc(new_len);
+ *str1[0] = 0;
+ } else {
+ new_len = strlen(*str1) + strlen(str2) + 1;
+ *str1 = (char *)slapi_ch_realloc(*str1, new_len);
+ }
+ if ( *str1 == NULL )
+ return(-1);
+
+ strcat(*str1, str2);
+ return(0);
+}
+
+/***************************************************************************/
+/* Print routines */
+/***************************************************************************/
+
+/* print eroror message returned from the ACL Library */
+#define ACLUTIL_ACLLIB_MSGBUF_LEN 200
+void
+acl_print_acllib_err (NSErr_t *errp , char * str)
+{
+ char msgbuf[ ACLUTIL_ACLLIB_MSGBUF_LEN ];
+
+ if ((NULL == errp ) || !slapi_is_loglevel_set ( SLAPI_LOG_ACL ) )
+ return;
+
+ aclErrorFmt(errp, msgbuf, ACLUTIL_ACLLIB_MSGBUF_LEN, 1);
+ msgbuf[ACLUTIL_ACLLIB_MSGBUF_LEN-1] = '\0';
+
+ if (msgbuf)
+ slapi_log_error(SLAPI_LOG_ACL, plugin_name,"ACL LIB ERR:(%s)(%s)\n",
+ msgbuf, str ? str: "NULL",0);
+}
+void
+aclutil_print_aci (aci_t *aci_item, char *type)
+{
+ char str[BUFSIZ];
+ const char *dn;
+
+ if ( ! slapi_is_loglevel_set ( SLAPI_LOG_ACL ) )
+ return;
+
+ if (!aci_item) {
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "acl__print_aci: Null item\n",0,0,0);
+ return;
+ }
+
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "***BEGIN ACL INFO[ Name:%s]***\n", aci_item->aclName);
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "ACL Index:%d ACL_ELEVEL:%d\n", aci_item->aci_index, aci_item->aci_elevel );
+ aclutil__access_str (aci_item->aci_access, str);
+ aclutil__typestr (aci_item->aci_type, &str[strlen(str)]);
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "ACI type:(%s)\n", str);
+
+ aclutil__Ruletypestr (aci_item->aci_ruleType, str);
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "ACI RULE type:(%s)\n",str);
+
+ dn = slapi_sdn_get_dn ( aci_item->aci_sdn );
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "Slapi_Entry DN:%s\n", escape_string_with_punctuation (dn, str));
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name,
+ "***END ACL INFO*****************************\n");
+
+}
+void
+aclutil_print_err (int rv , const Slapi_DN *sdn, const struct berval* val,
+ char **errbuf)
+{
+ char ebuf [BUFSIZ];
+ /*
+ * The maximum size of line is ebuf_size + the log message
+ * itself (less than 200 characters for all but potentially ACL_INVALID_TARGET)
+ */
+ char line [BUFSIZ + 200];
+ char str [1024];
+ const char *dn;
+ char *lineptr = line;
+ char *newline = NULL;
+
+ if ( rv >= 0)
+ return;
+
+ if (val->bv_len > 0 && val->bv_val != NULL) {
+ sprintf (str, "%.1023s", val->bv_val);
+ } else {
+ str[0] = '\0';
+ }
+
+ dn = slapi_sdn_get_dn ( sdn );
+ if (dn && (rv == ACL_INVALID_TARGET) && ((strlen(dn) + strlen(str)) > BUFSIZ)) {
+ /*
+ * if (str_length + dn_length + 200 char message) > (BUFSIZ + 200) line
+ * we have to make space for a bigger line...
+ */
+ newline = slapi_ch_malloc(strlen(dn) + strlen(str) + 200);
+ lineptr = newline;
+ }
+
+ switch (rv) {
+ case ACL_TARGET_FILTER_ERR:
+ sprintf (line, "ACL Internal Error(%d): "
+ "Error in generating the target filter for the ACL(%s)\n",
+ rv, escape_string_with_punctuation (str, ebuf));
+ break;
+ case ACL_TARGETATTR_FILTER_ERR:
+ sprintf (line, "ACL Internal Error(%d): "
+ "Error in generating the targetattr filter for the ACL(%s)\n",
+ rv, escape_string_with_punctuation (str, ebuf));
+ break;
+ case ACL_TARGETFILTER_ERR:
+ sprintf (line, "ACL Internal Error(%d): "
+ "Error in generating the targetfilter filter for the ACL(%s)\n",
+ rv, escape_string_with_punctuation (str, ebuf));
+ break;
+ case ACL_SYNTAX_ERR:
+ sprintf (line, "ACL Syntax Error(%d):%s\n",
+ rv, escape_string_with_punctuation (str, ebuf));
+ break;
+ case ACL_ONEACL_TEXT_ERR:
+ sprintf (line, "ACL Syntax Error in the Bind Rules(%d):%s\n",
+ rv, escape_string_with_punctuation (str, ebuf));
+ break;
+ case ACL_ERR_CONCAT_HANDLES:
+ sprintf (line, "ACL Internal Error(%d): "
+ "Error in Concatenating List handles\n",
+ rv);
+ break;
+ case ACL_INVALID_TARGET:
+ sprintf (lineptr, "ACL Invalid Target Error(%d): "
+ "Target is beyond the scope of the ACL(SCOPE:%s)",
+ rv, dn ? escape_string_with_punctuation (dn, ebuf) : "NULL");
+ sprintf (lineptr + strlen(lineptr), " %s\n", escape_string_with_punctuation (str, ebuf));
+ break;
+ case ACL_INVALID_AUTHMETHOD:
+ sprintf (line, "ACL Multiple auth method Error(%d):"
+ "Multiple Authentication Metod in the ACL(%s)\n",
+ rv, escape_string_with_punctuation (str, ebuf));
+ break;
+ case ACL_INVALID_AUTHORIZATION:
+ sprintf (line, "ACL Syntax Error(%d):"
+ "Invalid Authorization statement in the ACL(%s)\n",
+ rv, escape_string_with_punctuation (str, ebuf));
+ break;
+ case ACL_INCORRECT_ACI_VERSION:
+ sprintf (line, "ACL Syntax Error(%d):"
+ "Incorrect version Number in the ACL(%s)\n",
+ rv, escape_string_with_punctuation (str, ebuf));
+ break;
+ default:
+ sprintf (line, "ACL Internal Error(%d):"
+ "ACL generic error (%s)\n",
+ rv, escape_string_with_punctuation (str, ebuf));
+ break;
+ }
+
+ if (errbuf) {
+ /* If a buffer is provided, then copy the error */
+ aclutil_str_appened(errbuf, lineptr );
+ }
+
+ slapi_log_error( SLAPI_LOG_FATAL, plugin_name, "%s", lineptr);
+ if (newline) slapi_ch_free((void **) &newline);
+}
+
+/***************************************************************************
+* Convert access to str
+***************************************************************************/
+char*
+aclutil__access_str (int type , char str[])
+{
+ char *p;
+
+ str[0] = '\0';
+ p = str;
+
+ if (type & SLAPI_ACL_COMPARE) {
+ strcpy (p, "compare ");
+ p = strchr (p, '\0');
+ }
+ if (type & SLAPI_ACL_SEARCH) {
+ strcpy (p, "search ");
+ p = strchr (p, '\0');
+ }
+ if (type & SLAPI_ACL_READ) {
+ strcpy (p, "read ");
+ p = strchr (p, '\0');
+ }
+ if (type & SLAPI_ACL_WRITE) {
+ strcpy (p, "write ");
+ p = strchr (p, '\0');
+ }
+ if (type & SLAPI_ACL_DELETE) {
+ strcpy (p, "delete ");
+ p = strchr (p, '\0');
+ }
+ if (type & SLAPI_ACL_ADD) {
+ strcpy (p, "add ");
+ p = strchr (p, '\0');
+ }
+ if (type & SLAPI_ACL_SELF) {
+ strcpy (p, "self ");
+ p = strchr (p, '\0');
+ }
+ if (type & SLAPI_ACL_PROXY) {
+ strcpy (p, "proxy ");
+ }
+ return str;
+}
+
+/***************************************************************************
+* Convert type to str
+***************************************************************************/
+static void
+aclutil__typestr (int type , char str[])
+{
+ char *p;
+
+ /* Start copying in at whatever location is passed in */
+
+ p = str;
+
+ if (type & ACI_TARGET_DN) {
+ strcpy (p, "target_DN ");
+ p = strchr (p, '\0');
+ }
+ if (type & ACI_TARGET_ATTR) {
+ strcpy (p, "target_attr ");
+ p = strchr (p, '\0');
+ }
+ if (type & ACI_TARGET_PATTERN) {
+ strcpy (p, "target_patt ");
+ p = strchr (p, '\0');
+ }
+ if ((type & ACI_TARGET_ATTR_ADD_FILTERS) | (type & ACI_TARGET_ATTR_DEL_FILTERS)) {
+ strcpy (p, "targetattrfilters ");
+ p = strchr (p, '\0');
+ }
+ if (type & ACI_TARGET_FILTER) {
+ strcpy (p, "target_filter ");
+ p = strchr (p, '\0');
+ }
+ if (type & ACI_ACLTXT) {
+ strcpy (p, "acltxt ");
+ p = strchr (p, '\0');
+ }
+ if (type & ACI_TARGET_NOT) {
+ strcpy (p, "target_not ");
+ p = strchr (p, '\0');
+ }
+ if (type & ACI_TARGET_ATTR_NOT) {
+ strcpy (p, "target_attr_not ");
+ p = strchr (p, '\0');
+ }
+ if (type & ACI_TARGET_FILTER_NOT) {
+ strcpy (p, "target_filter_not ");
+ p = strchr (p, '\0');
+ }
+
+ if (type & ACI_HAS_ALLOW_RULE) {
+ strcpy (p, "allow_rule ");
+ p = strchr (p, '\0');
+ }
+ if (type & ACI_HAS_DENY_RULE) {
+ strcpy (p, "deny_rule ");
+ p = strchr (p, '\0');
+ }
+}
+static void
+aclutil__Ruletypestr (int type , char str[])
+{
+ char *p;
+
+ str[0] = '\0';
+ p = str;
+ if ( type & ACI_USERDN_RULE) {
+ strcpy (p, "userdn ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_USERDNATTR_RULE) {
+ strcpy (p, "userdnattr ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_USERATTR_RULE) {
+ strcpy (p, "userattr ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_GROUPDN_RULE) {
+ strcpy (p, "groupdn ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_GROUPDNATTR_RULE) {
+ strcpy (p, "groupdnattr ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_ROLEDN_RULE) {
+ strcpy (p, "roledn ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_IP_RULE) {
+ strcpy (p, "ip ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_DNS_RULE) {
+ strcpy (p, "dns ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_TIMEOFDAY_RULE) {
+ strcpy (p, "timeofday ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_DAYOFWEEK_RULE) {
+ strcpy (p, "dayofweek ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_AUTHMETHOD_RULE) {
+ strcpy (p, "authmethod ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_PARAM_DNRULE) {
+ strcpy (p, "paramdn ");
+ p = strchr (p, '\0');
+ }
+ if ( type & ACI_PARAM_ATTRRULE) {
+ strcpy (p, "paramAttr ");
+ p = strchr (p, '\0');
+ }
+}
+/*
+** acl_gen_err_msg
+** This function is called by backend to generate the error message
+** if access is denied.
+*/
+void
+acl_gen_err_msg(int access, char *edn, char *attr, char **errbuf)
+{
+ char *line = NULL;
+
+ if (access & SLAPI_ACL_WRITE) {
+ line = PR_smprintf(
+ "Insufficient 'write' privilege to the '%s' attribute of entry '%s'.\n",
+ attr ? attr: "NULL", edn);
+ } else if ( access & SLAPI_ACL_ADD ) {
+ line = PR_smprintf(
+ "Insufficient 'add' privilege to add the entry '%s'.\n",edn);
+
+ } else if ( access & SLAPI_ACL_DELETE ) {
+ line = PR_smprintf(
+ "Insufficient 'delete' privilege to delete the entry '%s'.\n",edn);
+ }
+ aclutil_str_appened(errbuf, line );
+
+ if (line) {
+ PR_smprintf_free(line);
+ line = NULL;
+ }
+}
+short
+aclutil_gen_signature ( short c_signature )
+{
+ short o_signature;
+ o_signature = c_signature ^ (slapi_rand() % 32768);
+ if (!o_signature)
+ o_signature = c_signature ^ (slapi_rand() % 32768);
+
+ return o_signature;
+}
+
+void
+aclutil_print_resource( struct acl_pblock *aclpb, char *right , char *attr, char *clientdn )
+{
+
+ char str[BUFSIZ];
+ const char *dn;
+
+
+ if ( aclpb == NULL) return;
+
+ if ( ! slapi_is_loglevel_set ( SLAPI_LOG_ACL ) )
+ return;
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name, " ************ RESOURCE INFO STARTS *********\n",0,0,0);
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name, " Client DN: %s\n",
+ clientdn ? escape_string_with_punctuation (clientdn, str) : "NULL", 0,0);
+ aclutil__access_str (aclpb->aclpb_access, str);
+ aclutil__typestr (aclpb->aclpb_res_type, &str[strlen(str)]);
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name, " resource type:%d(%s)\n",
+ aclpb->aclpb_res_type, str, 0);
+
+ dn = slapi_sdn_get_dn ( aclpb->aclpb_curr_entry_sdn );
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name, " Slapi_Entry DN: %s\n",
+ dn ? escape_string_with_punctuation ( dn , str) : "NULL",0,0);
+
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name, " ATTR: %s\n", attr ? attr : "NULL",0,0);
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name, " rights:%s\n", right ? right: "NULL",0,0);
+ slapi_log_error (SLAPI_LOG_ACL, plugin_name, " ************ RESOURCE INFO ENDS *********\n",0,0,0);
+}
+/*
+ * The input string contains a rule like
+ * "cn=helpdesk, ou=$attr.deptName, o=$dn.o, o=ISP"
+ *
+ * Where $attr -- means look into the attribute list for values
+ * $dn -- means look into the entry's dn
+ *
+ * We extract the values from the entry and returned a string
+ * with the values added.
+ * For "$attr" rule - if we find multiple values then it is
+ * the pattern is not expanded.
+ * For "$dn" rule, if we find multiple of them, we use the relative
+ * position.
+ * NOTE: The caller is responsible in freeing the memory.
+ */
+char *
+aclutil_expand_paramString ( char *str, Slapi_Entry *e )
+{
+
+ char **e_dns;
+ char **a_dns;
+ char *attrName;
+ char *s, *p;
+ char *attrVal;
+ int i, len;
+ int ncomponents, type;
+ int rc = -1;
+ char *buf = NULL;
+
+
+ e_dns = ldap_explode_dn ( slapi_entry_get_ndn ( e ), 0 );
+ a_dns = ldap_explode_dn ( str, 0 );
+
+ i = 0;
+ ncomponents = 0;
+ while ( a_dns[ncomponents] )
+ ncomponents++;
+
+
+ for (i=0; i < ncomponents; i++ ) {
+
+ /* Look for"$" char */
+ if ( (s = strchr ( a_dns[i], '$') ) != NULL) {
+ p = s;
+ s++;
+ if ( strncasecmp (s, "dn", 2) == 0 )
+ type = 1;
+ else if ( strncasecmp (s, "attr", 4) == 0 )
+ type = 2;
+ else {
+ /* error */
+ goto cleanup;
+ }
+ *p = '\0';
+ aclutil_str_appened ( &buf,a_dns[i]);
+
+ if ( type == 1 ) {
+ /* xyz = $dn.o */
+ s +=3;
+ attrName = s;
+
+ attrVal = __aclutil_extract_dn_component (e_dns,
+ ncomponents-i, attrName);
+ if ( NULL == attrVal ) /*error*/
+ goto cleanup;
+
+ } else {
+ Slapi_Attr *attr;
+ const struct berval *attrValue;
+ int kk;
+ Slapi_Value *sval, *t_sval;
+
+
+ /* The pattern is x=$attr.o" */
+ s +=5;
+ attrName = s;
+
+ slapi_entry_attr_find ( e, attrName, &attr );
+ if ( NULL == attr )
+ goto cleanup;
+
+ kk= slapi_attr_first_value ( attr, &sval );
+ if ( kk != -1 ) {
+ t_sval = sval;
+ kk= slapi_attr_next_value( attr, kk, &sval );
+ if ( kk != -1 ) /* can't handle multiple --error */
+ goto cleanup;
+ }
+ attrValue = slapi_value_get_berval ( t_sval );
+ attrVal = attrValue->bv_val;
+ }
+ } else {
+ attrVal = a_dns[i];
+ }
+ aclutil_str_appened ( &buf, attrVal);
+ aclutil_str_appened ( &buf, ",");
+ }
+ rc = 0; /* everything is okay*/
+ /* remove the last comma */
+ len = strlen ( buf);
+ buf[len-1] = '\0';
+
+cleanup:
+
+ ldap_value_free ( a_dns );
+ ldap_value_free ( e_dns );
+ if ( 0 != rc ) /* error */ {
+ slapi_ch_free ( (void **) &buf );
+ buf = NULL;
+ }
+
+ return buf;
+}
+static char *
+__aclutil_extract_dn_component ( char **e_dns, int position, char *attrName )
+{
+
+ int i, matched, len;
+ char *s;
+ int matchedPosition;
+
+ len = strlen ( attrName );
+
+ /* First check if there thare are multiple of these */
+ i = matched = 0;
+ while ( e_dns[i] ) {
+ if (0 == strncasecmp (e_dns[i], attrName, len) ) {
+ matched++;
+ matchedPosition = i;
+ }
+ i++;
+ }
+
+ if (!matched )
+ return NULL;
+
+ if ( matched > 1 ) {
+ matchedPosition = i - position;
+ }
+
+ if ( NULL == e_dns[matchedPosition])
+ return NULL;
+
+ s = strstr ( e_dns[matchedPosition], "=");
+ if ( NULL == s)
+ return NULL;
+ else
+ return s+1;
+}
+
+/*
+ * Does the first component of ndn match the first component of match_this ?
+*/
+
+int
+acl_dn_component_match( const char *ndn, char *match_this, int component_number) {
+
+ return(1);
+}
+
+/*
+ * Here, ndn is a resource dn and match_this is a dn, containing a macro, ($dn).
+ *
+ * eg. ndn is cn=fred,ou=groups,ou=people,ou=icnc,o=ISP and
+ * match_this is "ou=Groups,($dn),o=ISP" or
+ * "cn=*,ou=Groups,($dn),o=ISP".
+ *
+ * They match if:
+ * match_this is a suffix of ndn
+ *
+ * It returns NULL, if they do not match.
+ * Otherwise it returns a copy of the substring of ndn that matches the ($dn).
+ *
+ * eg. in the above example, "ou=people,ou=icnc"
+*/
+
+char *
+acl_match_macro_in_target( const char *ndn, char * match_this,
+ char *macro_ptr) {
+
+ char *macro_prefix = NULL;
+ int macro_prefix_len = 0;
+ char *macro_suffix = NULL;
+ char *tmp_ptr = NULL;
+ char *matched_val = NULL;
+ char *ndn_suffix_start = NULL;
+ char *macro_prefix_final_component = NULL;
+ char *ret_val = NULL;
+ int ndn_len = 0;
+ int macro_suffix_len = 0;
+ int ndn_prefix_len = 0;
+ int ndn_prefix_end = 0;
+ int matched_val_len = 0;
+
+ /*
+ * First, grab the macro_suffix--the bit after the ($dn)
+ *
+ */
+
+ if (strlen(macro_ptr) == strlen(ACL_TARGET_MACRO_DN_KEY)) {
+ macro_suffix = NULL; /* just ($dn) */
+ } else {
+ if ( macro_ptr[strlen(ACL_TARGET_MACRO_DN_KEY)] == ',') {
+ macro_suffix = &macro_ptr[strlen(ACL_TARGET_MACRO_DN_KEY) + 1];
+ } else {
+ macro_suffix = &macro_ptr[strlen(ACL_TARGET_MACRO_DN_KEY)];
+ }
+ }
+
+ /*
+ * First ensure that the suffix of match_this is
+ * a suffix of ndn.
+ */
+
+ ndn_len = strlen(ndn);
+ if ( macro_suffix != NULL) {
+ macro_suffix_len = strlen(macro_suffix);
+ if( macro_suffix_len >= ndn_len ) {
+
+ /*
+ * eg ndn: o=icnc,o=sun.com
+ * match_this: ($dn),o=icnc,o=sun.com
+ */
+ return(NULL); /* ($dn) must match something. */
+ } else {
+ /*
+ * eg ndn: ou=People,o=icnc,o=sun.com
+ * match_this: ($dn),o=icnc,o=sun.com
+ *
+ * we can do a direct strncmp() because we know that
+ * there can be no "*" after the ($dn)...by definition.
+ */
+ if (strncasecmp( macro_suffix, &ndn[ndn_len-macro_suffix_len],
+ macro_suffix_len) != 0) {
+ return(NULL); /* suffix must match */
+ }
+ }
+ }
+
+ /* Start of the suffix in ndn...and it matched. */
+ ndn_suffix_start = (char*)&ndn[ndn_len-macro_suffix_len];
+
+ /* Here, macro_suffix is a suffix of ndn.
+ *
+ *
+ * Now, look at macro_prefix, if it is NULL, then ($dn) matches
+ * ndn[0..ndn_len-macro_suffix_len].
+ * (eg, ndn: cn=fred,ou=People,o=sun.com
+ * match_this: ($dn),o=sun.com.
+ *
+ */
+
+ macro_prefix = slapi_ch_strdup(match_this);
+
+ /* we know it's got a $(dn) */
+ tmp_ptr = strstr(macro_prefix, ACL_TARGET_MACRO_DN_KEY);
+ *tmp_ptr = '\0';
+ /* There may be a NULL prefix eg. match_this: ($dn),o=sun.com */
+ macro_prefix_len = strlen(macro_prefix);
+ if (macro_prefix_len == 0) {
+ slapi_ch_free((void **) &macro_prefix);
+ macro_prefix = NULL;
+ }
+
+ if (macro_prefix == NULL ) {
+ /*
+ * ($dn) matches ndn[0..ndn_len-macro_suffix_len]
+ */
+ int matched_val_len = 0;
+
+ matched_val_len = ndn_len-macro_suffix_len;
+
+ matched_val = (char *)slapi_ch_malloc(matched_val_len + 1);
+ strncpy(matched_val, ndn, ndn_len-macro_suffix_len);
+ /*
+ * Null terminate matched_val, removing trailing "," if there is
+ * one.
+ */
+ if (matched_val_len > 1) {
+ if (matched_val[matched_val_len-1] == ',' ) {
+ matched_val[matched_val_len-1] = '\0';
+ } else {
+ matched_val[matched_val_len] = '\0';
+ }
+ }
+ ret_val = matched_val;
+ } else {
+
+
+ /*
+ * If it is not NULL, then if macro_prefix contains a * then
+ * it needs to be an exact prefix of ndn (modulo the * component
+ * which matches anything) becuase that's the semantics
+ * of target patterns containing *'s, except that we just
+ * make it match one component.
+ * If it is such a prefix then ($dn) matches that portion of ndn
+ * from the end of the prefix, &ndn[ndn_prefix_end] to
+ * ndn_suffix_start.
+ * If ndn_prefix_len > ndn_len-macro_suffix_len then return(NULL),
+ * otherwise $(dn) matches ndn[ndn_prefix_len..ndn_len-macro_suffix_len].
+ *
+ *
+ * eg. ndn: cn=fred,ou=P,o=sun.com
+ * match_this: cn=*,($dn),o=sun.com
+ */
+
+ if ( strstr(macro_prefix, "=*") != NULL ) {
+ int exact_match = 0;
+
+ ndn_prefix_len = acl_match_prefix( macro_prefix, ndn, &exact_match);
+ if ( ndn_prefix_len != -1 ) {
+
+ /*
+ * ndn[0..ndn_prefix_len] is the prefix in ndn.
+ * ndn[ndn_prefix_len..ndn_len-macro_suffix_len] is the
+ * matched string.
+ */
+ if (ndn_prefix_len >= ndn_len-macro_suffix_len) {
+
+ /*
+ * eg ndn: cn=fred,ou=People,o=icnc,o=sun.com
+ * cn=*,ou=People,o=icnc,($dn),o=icnc,o=sun.com
+ */
+
+ ret_val = NULL; /* matched string is empty */
+ } else {
+
+ /*
+ * eg ndn: cn=fred,ou=People,o=icnc,o=sun.com
+ * cn=*,ou=People,($dn),o=sun.com
+ */
+
+ matched_val_len = ndn_len-macro_suffix_len-ndn_prefix_len;
+ matched_val = (char *)slapi_ch_malloc(matched_val_len + 1);
+ strncpy(matched_val, &ndn[ndn_prefix_len], matched_val_len);
+ if (matched_val_len > 1) {
+ if (matched_val[matched_val_len-1] == ',' ) {
+ matched_val[matched_val_len-1] = '\0';
+ } else {
+ matched_val[matched_val_len] = '\0';
+ }
+ }
+ matched_val[matched_val_len] = '\0';
+ ret_val = matched_val;
+ }
+ } else {
+ /* Was not a prefix so not a match */
+ ret_val = NULL;
+ }
+ } else {
+
+ /*
+ *
+ * If macro_prefix is not NULL and it does not
+ * contain a =* then
+ * we need to ensure that macro_prefix is a substring
+ * ndn.
+ * If it is and the position of the character after it's end in
+ * ndn is
+ * ndn_prefix_end then ($dn) matches
+ * ndn[ndn_prefix_end..ndn_len-macro_suffix_len].
+ *
+ *
+ * One important principal is that ($dn) matches a maximal
+ * chunk--this way it will serve to make the link
+ * between resources and users at each level of the structure.
+ *
+ * eg. ndn: ou=Groups,ou=Groups,ou=Groups,c=fr
+ * macro_prefix: ou=Groups,($dn),c=fr
+ *
+ * then ($dn) matches ou=Groups,ou=Groups.
+ *
+ *
+ *
+ * If it is not a substring, then there is no match.
+ * If it is a substring and
+ * ndn[ndn_prefix_end..ndn_len-macro_suffix_len] is empty then
+ * it's also not a match as we demand that ($dn) match a non-empty
+ * string.
+ *
+ *
+ *
+ * (eg. ndn: cn=fred,o=icnc,ou=People,o=sun.com
+ * match_this: o=icnc,($dn),o=sun.com.)
+ *
+ *
+ * (eg. ndn: cn=fred,o=menlo park,ou=People,o=icnc,o=sun.com
+ * match_this: o=menlo park,ou=People,($dn),o=sun.com
+ *
+ */
+
+ ndn_prefix_end = acl_strstr((char *)ndn, macro_prefix);
+ if ( ndn_prefix_end == -1) {
+ ret_val = NULL;
+ } else {
+ /* Is a substring */
+
+ ndn_prefix_end += macro_prefix_len;
+
+ /*
+ * make sure the matching part is non-empty:
+ *
+ * ndn[ndn_prefix_end..mndn_len-macro_suffix_len].
+ */
+
+ if ( ndn_prefix_end >= ndn_len-macro_suffix_len) {
+ ret_val = NULL;
+ } else {
+ /*
+ * ($dn) matches the non-empty string segment
+ * ndn[ndn_prefix_end..mndn_len-macro_suffix_len]
+ * the -1 is because macro_suffix_eln does not include
+ * the coma before the suffix.
+ */
+
+ matched_val_len = ndn_len-macro_suffix_len-
+ ndn_prefix_end - 1;
+
+ matched_val = (char *)slapi_ch_malloc(matched_val_len + 1);
+ strncpy(matched_val, &ndn[ndn_prefix_end],
+ matched_val_len);
+ matched_val[matched_val_len] = '\0';
+
+ ret_val = matched_val;
+ }
+ }
+ }/* contains an =* */
+ slapi_ch_free((void **) &macro_prefix);
+ }/* macro_prefix != NULL */
+
+ return(ret_val);
+}
+
+/*
+ * Checks to see if macro_prefix is an exact prefix of ndn.
+ * macro_prefix may contain a * component.
+ *
+ * The length of the matched prefix in ndn is returned.
+ * If it was not a match, a negative int is returned.
+ * Also, if the string matched exactly,
+ * exact_match is set to 1, other wise it was a proper prefix.
+ *
+*/
+
+int
+acl_match_prefix( char *macro_prefix, const char *ndn, int *exact_match) {
+
+ int macro_index = 0;
+ int ndn_index = 0;
+ int ret_code = -1;
+ char *curr_macro_component = NULL;
+ char *curr_ndn_component = NULL;
+ int matched = 0;
+ int macro_prefix_len = 0;
+ int ndn_len = 0;
+ int i = 0;
+ int j = 0;
+ int done = 0;
+ int t = 0;
+ char * tmp_str = NULL;
+ int k,l = 0;
+
+ *exact_match = 0; /* default to not an exact match */
+
+ /* The NULL prefix matches everthing*/
+ if (macro_prefix == NULL) {
+ if ( ndn == NULL ) {
+ *exact_match = 1;
+ }
+ return(0);
+ } else {
+ /* macro_prefix is not null, so if ndn is NULL, it's not a match. */
+ if ( ndn == NULL) {
+ return(-1);
+ }
+ }
+ /*
+ * Here, neither macro_prefix nor ndn are NULL.
+ *
+ * eg. macro_prefix: cn=*,ou=people,o=sun.com
+ * ndn : cn=fred,ou=people,o=sun.com
+ */
+
+
+ /*
+ * Here, there is a component with a * (eg. cn=* ) so
+ * we need to step through the macro_prefix, and where there is
+ * such a * match on that component,
+ * when we run out of * componenets, jsut do a straight match.
+ *
+ * Out of interest, the following extended regular expression
+ * will match just one ou rdn value from a string:
+ * "^uid=admin,ou=\([^,]*\\\,\)*[^,]*,o=sun.com$"
+ *
+ *
+ * eg. cn=fred,ou=People,o=sun.com
+ *
+ *
+ * s points to the = of the component.
+ */
+
+ macro_prefix_len = strlen(macro_prefix);
+ ndn_len = strlen(ndn);
+ i = 0;
+ j = 0;
+ done = 0;
+ while ( !done ) {
+
+ /* Here ndn[0..i] has matched macro_prefix[0..j] && j<= i
+ * i<=ndn_len j<=macro_prefix_len */
+
+ if ( (t = acl_strstr(&macro_prefix[j], "=*")) < 0 ) {
+ /*
+ * No more *'s, do a straight match on
+ * macro_prefix[j..macro_prefix_len] and
+ * ndn[i..macro_prefix_len]
+ */
+
+ if( macro_prefix_len-j > ndn_len-i) {
+ /* Not a prefix, nor a match */
+ *exact_match = 0;
+ ret_code = -1;
+ done = 1;
+ } else {
+ /*
+ * ndn_len-i >= macro_prefix_len - j
+ * if macro_prefix_len-j is 0, then
+ * it's a null prefix, so it matches.
+ * If in addition ndn_len-i is 0 then it's
+ * an exact match.
+ * Otherwise, do the cmp.
+ */
+
+ if ( macro_prefix_len-j == 0) {
+ done = 1;
+ ret_code = i;
+ if ( ndn_len-i == 0) {
+ *exact_match = 1;
+ }
+ }else {
+
+ if (strncasecmp(&macro_prefix[j], &ndn[i],
+ macro_prefix_len-j) == 0) {
+ *exact_match = (macro_prefix_len-j == ndn_len-i);
+ ret_code = i + macro_prefix_len -j;
+ done = 1;
+ } else {
+ /* not a prefix not a match */
+ *exact_match = 0;
+ ret_code = -1;
+ done = 1;
+ }
+ }
+ }
+ }else {
+ /*
+ * Is another * component, so:
+ * 1. match that component in macro_prefix (at pos k say)
+ * with the corresponding compoent (at pos l say ) in ndn
+ *
+ * 2. match the intervening string ndn[i..l] and
+ * macro_prefix[j..k].
+ */
+
+ /* First, find the start of the component in macro_prefix. */
+
+ t++; /* move to the--this way we will look for "ou=" in ndn */
+ k = acl_find_comp_start(macro_prefix, t);
+
+ /* Now identify that component in ndn--if it's not there no match */
+ tmp_str = slapi_ch_malloc(t-k+1);
+ strncpy(tmp_str, &macro_prefix[k], t-k);
+ tmp_str[t-k] = '\0';
+ l = acl_strstr((char*)&ndn[i], tmp_str);
+ if (l == -1) {
+ *exact_match = 0;
+ ret_code = -1;
+ done = 1;
+ } else {
+ /*
+ * Found the comp in ndn, so the comp matches.
+ * Now test the intervening string segments:
+ * ndn[i..l] and macro_prefix[j..k]
+ */
+
+ if ( k-j != l-i ) {
+ *exact_match = 0;
+ ret_code = -1;
+ done = 1;
+ } else{
+ if (strncasecmp(&macro_prefix[j], &ndn[i], k-j) != 0) {
+ *exact_match = 0;
+ ret_code = -1;
+ done = 1;
+ } else {
+ /* Matched, so bump i and j and keep going.*/
+ i += acl_find_comp_end((char*)&ndn[l]);
+ j += acl_find_comp_end((char*)&macro_prefix[k]);
+ }
+ }
+ }
+ slapi_ch_free((void **)&tmp_str);
+ }
+ }/* while */
+
+ return(ret_code);
+
+}
+
+/*
+ * returns the index in s of where the component at position
+ * s[pos] starts.
+ * This is the index of the character after the first unescaped comma
+ * moving backwards in s from pos.
+ * If this is not found then return 0, ie. the start of the string.
+ * If the index returned is > strlen(s) then could not find it.
+ * only such case is if you pass ",", in which case there is no component start.
+*/
+
+static int
+acl_find_comp_start(char * s, int pos ) {
+
+ int i =0;
+ int comp_start = 0;
+
+ i = pos;
+ while( i > 0 && (s[i] != ',' ||
+ s[i-1] == '\\')) {
+ i--;
+ }
+ /*
+ * i == 0 || (s[i] == ',' && s[i-1] != '\\')
+ */
+ if (i==0) {
+ /* Got all the way with no unescaped comma */
+ if (s[i] == ',') {
+ comp_start = i+1;
+ } else {
+ comp_start = i;
+ }
+ } else { /* Found an unescaped comma */
+ comp_start = i + 1;
+ }
+
+ return( comp_start);
+}
+
+/*
+ * returns the index in s of the first character after the
+ * first unescaped comma.
+ * If ther is no such character, returns strlen(s);
+*/
+
+int
+acl_find_comp_end( char * s) {
+
+ int i = 0;
+ int s_len = 0;
+
+ s_len = strlen(s);
+
+ if ( s_len == 0 || s_len == 1) {
+ return(s_len);
+ }
+
+ /* inv: i+1<s_len && (s[i] == '\\' || s[i+1] != ',')*/
+
+ i = 0;
+ while( i+1 < s_len && (s[i] == '\\' ||
+ s[i+1] != ',')) {
+ i++;
+ }
+ if ( i + 1 == s_len) {
+ return(s_len);
+ } else {
+ return(i+2);
+ }
+}
+
+/*
+ * return the index in s where substr occurs, if none
+ * returns -1.
+*/
+
+int
+acl_strstr(char * s, char *substr) {
+
+ char *t = NULL;
+ char *tmp_str = NULL;
+
+ tmp_str = slapi_ch_strdup(s);
+
+ if ( (t = strstr(tmp_str, substr)) == NULL ) {
+ slapi_ch_free((void **)&tmp_str);
+ return(-1);
+ } else {
+ int l = 0;
+ *t = '\0';
+ l = strlen(tmp_str);
+ slapi_ch_free((void **)&tmp_str);
+ return(l);
+ }
+}
+
+/*
+ * replace all occurences of substr in s with replace_str.
+ *
+ * returns a malloced version of the patched string.
+*/
+
+char *
+acl_replace_str(char * s, char *substr, char* replace_with_str) {
+
+ char *str = NULL;
+ char *working_s, *suffix, *prefix, *patched;
+ int replace_with_len, substr_len, prefix_len, suffix_len;
+
+ if ( (str = strstr(s, substr)) == NULL) {
+ return(slapi_ch_strdup(s));
+ } else {
+
+
+ replace_with_len = strlen(replace_with_str);
+ substr_len = strlen(substr);
+
+ working_s = slapi_ch_strdup(s);
+ prefix = working_s;
+ str = strstr(prefix, substr);
+
+ while (str != NULL) {
+
+ /*
+ * working_s is a copy of the string to be patched
+ * str points to a substr to be patched
+ * prefix points to working_s
+ */
+
+ *str = '\0';
+
+ suffix = &str[substr_len];
+ prefix_len = strlen(prefix);
+ suffix_len = strlen(suffix);
+
+ patched = (char *)slapi_ch_malloc(prefix_len +
+ replace_with_len +
+ suffix_len +1 );
+ strcpy(patched, prefix);
+ strcat(patched, replace_with_str);
+ strcat(patched, suffix);
+
+ slapi_ch_free((void **)&working_s);
+
+ working_s = patched;
+ prefix = working_s;
+ str = strstr(prefix, substr);
+
+ }
+
+ return(working_s);
+ }
+
+}
+
+
+/*
+ * Start at index and return a malloced string that is the
+ * next component in dn (eg. "ou=People"),
+ * or NULL if couldn't find the next one.
+*/
+
+char *
+get_next_component(char *dn, int *index) {
+
+ int dn_len = strlen(dn);
+ int start_next = -1;
+ int i = 0;
+ char *ret_comp;
+
+ if (*index>= dn_len) {
+ return(NULL);
+ }
+
+ start_next = acl_find_comp_end( &dn[*index]);
+
+ if ( start_next >= dn_len ) {
+ *index = start_next;
+ return(NULL); /* no next comp */
+ }
+
+ /*
+ *Here, start_next should be the start of the next
+ * component--so far have not run off the end.
+ */
+
+ i = acl_find_comp_end( &dn[start_next]);
+
+ /*
+ * Here, the matched string is all from start_next to i.
+ */
+
+ ret_comp = (char *)slapi_ch_malloc(i - start_next +1);
+ memcpy( ret_comp, &dn[start_next], i-start_next);
+ ret_comp[i-start_next] = '\0';
+
+ return(ret_comp);
+}
+
+char *
+get_this_component(char *dn, int *index) {
+
+ int dn_len = strlen(dn);
+ int i = 0;
+ char *ret_comp;
+
+ if (*index>= dn_len) {
+ return(NULL);
+ }
+
+ if (dn_len == *index + 1) {
+ /* Just return a copy of the string. */
+ return(slapi_ch_strdup(dn));
+ }else {
+ /* *index + 1 < dn_len */
+ i = *index+1;
+ while( (dn[i] != '\0') && dn[i] != ',' && dn[i-1] != '\\') {
+ i += 1;
+ }
+
+ /*
+ * Here, the matched string is all from *index to i.
+ */
+
+ ret_comp = (char *)slapi_ch_malloc(i - *index +1);
+ memcpy( ret_comp, &dn[*index], i - *index);
+ ret_comp[i-*index] = '\0';
+
+ if (i < dn_len) {
+ /* Found a comma before the end */
+ *index = i + 1; /* skip it */
+ }
+
+ return(ret_comp);
+ }
+
+}
+
+/*
+ * return 1 if comp1==comp2,
+ * return 0 otherwise.
+ *
+ * the components might have *'s.
+ *
+ * eg: comp1: cn=*
+ * comp2: cn=fred
+ *
+ *
+*/
+
+static int
+aclutil_compare_components( char * comp1, char *comp2) {
+
+ char *tmp_str = NULL;
+
+ tmp_str = strstr( comp1, "=*");
+ if ( tmp_str == NULL) {
+
+ /* Just a straight cmp */
+
+ if (slapi_utf8casecmp((ACLUCHP)comp1, (ACLUCHP)comp2) == 0) {
+ return(1);
+ } else {
+ return(0);
+ }
+ } else {
+
+ char *tmp_comp1= NULL;
+ char *tmp_comp2 = NULL;
+ int ret_code = 0;
+
+ /* Here, just compare the bit before the = */
+
+ tmp_comp1 = slapi_ch_strdup(comp1);
+ tmp_comp2 = slapi_ch_strdup(comp2);
+
+ /*
+ * Probably need to verify it's not escaped--see code for looking for
+ * unescaped commas.
+ */
+
+ tmp_str = strstr(tmp_comp1, "=");
+ *tmp_str = '\0';
+
+ tmp_str = strstr(tmp_comp2, "=");
+ if ( tmp_str == NULL) {
+ ret_code = 0;
+ } else{
+
+ *tmp_str = '\0';
+
+ if (slapi_utf8casecmp((ACLUCHP)comp1, (ACLUCHP)comp2) == 0) {
+ ret_code = 1;
+ } else {
+ ret_code = 0;
+ }
+
+ slapi_ch_free((void **)&tmp_comp1);
+ slapi_ch_free((void **)&tmp_comp2);
+
+ return(ret_code);
+
+ }
+
+ }
+}
+
+/*
+ * return a pointer to the final component of macro_prefix.
+*/
+
+static char *
+acl_get_final_component(char *macro_prefix) {
+
+ return(NULL);
+}
+
+/*
+ *
+ *
+*/
+
+static char *
+acl_match_component( char *start, char *component) {
+
+
+ return(NULL);
+}
+
+/* acl hash table funcs */
+
+/*
+ * Add the key adn value to the ht.
+ * If it already exists then remove the old one and free
+ * the value.
+*/
+void acl_ht_add_and_freeOld(acl_ht_t * acl_ht,
+ PLHashNumber key,
+ char *value){
+ char *old_value = NULL;
+
+ if ( (old_value = (char *)acl_ht_lookup( acl_ht, key)) != NULL ) {
+ acl_ht_remove( acl_ht, key);
+ slapi_ch_free((void **)&old_value);
+ }
+
+ PL_HashTableAdd( acl_ht, (const void *)key, value);
+}
+
+/*
+ * Return a new acl_ht_t *
+*/
+acl_ht_t *acl_ht_new(void) {
+
+ return(PL_NewHashTable(30, acl_ht_hash, /* key hasher */
+ PL_CompareValues, /* keyCompare */
+ PL_CompareStrings, 0, 0)); /* value compare */
+}
+
+static PLHashNumber acl_ht_hash( const void *key) {
+
+ return( (PLHashNumber)key );
+}
+
+/* Free all the values in the ht */
+void acl_ht_free_all_entries_and_values( acl_ht_t *acl_ht) {
+
+ PL_HashTableEnumerateEntries( acl_ht, acl_ht_free_entry_and_value,
+ NULL);
+}
+
+static PRIntn
+acl_ht_free_entry_and_value(PLHashEntry *he, PRIntn i, void *arg)
+{
+
+ slapi_ch_free((void **)&he->value); /* free value */
+
+ /* Free this entry anfd go on to next one */
+ return ( HT_ENUMERATE_NEXT | HT_ENUMERATE_REMOVE);
+}
+
+/* Free all the values in the ht */
+void acl_ht_display_ht( acl_ht_t *acl_ht) {
+
+#ifdef DEBUG
+ PL_HashTableEnumerateEntries( acl_ht, acl_ht_display_entry, NULL);
+#endif
+}
+
+static PRIntn
+acl_ht_display_entry(PLHashEntry *he, PRIntn i, void *arg)
+{
+ PLHashNumber aci_index = (PLHashNumber)he->key;
+ char *matched_val = (char *)he->value;
+
+ LDAPDebug(LDAP_DEBUG_ACL,"macro ht entry: key='%d' matched_val='%s'"
+ "keyhash='%d'\n",
+ aci_index, (matched_val ? matched_val: "NULL"),
+ (PLHashNumber)he->keyHash);
+
+ return HT_ENUMERATE_NEXT;
+
+}
+
+/* remove this entry from the ht--doesn't free the value.*/
+void acl_ht_remove( acl_ht_t *acl_ht, PLHashNumber key) {
+
+ PL_HashTableRemove( acl_ht, (const void *)key);
+}
+
+/* Retrieve a pointer to the value of the entry with key */
+void *acl_ht_lookup( acl_ht_t *acl_ht,
+ PLHashNumber key) {
+
+ return( PL_HashTableLookup( acl_ht, (const void *)key) );
+}
+
+
+/***************************************************************************/
+/* E N D */
+/***************************************************************************/
+
diff --git a/ldap/servers/plugins/acl/libacl.def b/ldap/servers/plugins/acl/libacl.def
new file mode 100644
index 00000000..947638cd
--- /dev/null
+++ b/ldap/servers/plugins/acl/libacl.def
@@ -0,0 +1,16 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+;
+;
+DESCRIPTION 'Netscape Directory Server 7.0 ACL Plugin'
+;CODE SHARED READ EXECUTE
+;DATA SHARED READ WRITE
+EXPORTS
+ acl_preopInit @1
+; unused @2
+ acl_init @3
+ plugin_init_debug_level @4
diff --git a/ldap/servers/plugins/chainingdb/Makefile b/ldap/servers/plugins/chainingdb/Makefile
new file mode 100644
index 00000000..4f47e480
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/Makefile
@@ -0,0 +1,93 @@
+#
+# 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 "Chaining Backend" plugin
+#
+
+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 = $(OBJDIR)/lib/libcb
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./libcb.def
+endif
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd
+
+CB_OBJS= cb_temp.o cb_init.o cb_config.o cb_instance.o cb_start.o cb_search.o cb_utils.o cb_add.o cb_delete.o cb_schema.o \
+cb_acl.o cb_modify.o cb_compare.o cb_modrdn.o cb_abandon.o cb_conn_stateless.o cb_bind.o cb_unbind.o cb_monitor.o \
+cb_controls.o cb_size.o cb_test.o cb_close.o cb_cleanup.o cb_debug.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(CB_OBJS))
+
+ifeq ($(ARCH), WINNT)
+LIBCB_DLL_OBJ = $(addprefix $(OBJDEST)/, cbdllmain.o)
+endif
+
+LIBCB= $(addprefix $(LIBDIR)/, $(CB_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAP_LIBUTIL_DEP) $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(SECURITY_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL) $(LDAP_LIBUTIL) $(LDAP_COMMON_LIBS) $(SECURITYLINK) $(NSPRLINK)
+
+endif
+
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libcb.def"
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAP_LIBUTIL_DEP) $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(SECURITY_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL) $(LIBUTIL) $(LDAP_COMMON_LIBS) $(SECURITYLINK) $(NSPRLINK)
+EXTRA_LIBS += $(DLL_EXTRA_LIBS)
+LD=ld
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBCB)
+
+$(LIBCB): $(OBJS) $(LIBCB_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBCB_DLL_OBJ) $(PLATFORMLIBS) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBCB_DLL_OBJ)
+endif
+ $(RM) $(LIBCB)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+#
+# header file dependencies (incomplete)
+#
+$(OBJS): cb.h
diff --git a/ldap/servers/plugins/chainingdb/cb.h b/ldap/servers/plugins/chainingdb/cb.h
new file mode 100644
index 00000000..8aed412c
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb.h
@@ -0,0 +1,461 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef CBHFILE
+#define CBHFILE
+
+/*** #define CB_YIELD ***/
+
+#include <stdio.h>
+#include <string.h>
+#include <prlock.h>
+#include <prcvar.h>
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+#include "portable.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+
+/* Constants */
+
+#define CB_DIRECTORY_MANAGER_DN "cn=directory manager"
+#define CB_CHAINING_BACKEND_TYPE "chaining database"
+#define CB_PLUGIN_NAME "chaining database"
+#define CB_PLUGIN_SUBSYSTEM "chaining database"
+#define CB_PLUGIN_DESCRIPTION "LDAP chaining backend database plugin"
+
+#define CB_LDAP_SECURE_PORT 636
+#define CB_BUFSIZE 2048
+
+
+/* Macros */
+
+#define CB_LDAP_CONN_ERROR( err ) ( (err) == LDAP_SERVER_DOWN || \
+ (err) == LDAP_CONNECT_ERROR )
+#define CB_ASSERT( expr ) PR_ASSERT( expr )
+
+/* Innosoft chaining extension for loop detection */
+
+#define CB_LDAP_CONTROL_CHAIN_SERVER "1.3.6.1.4.1.1466.29539.12"
+
+/* Chaining backend configuration attributes */
+
+/* Monitor entry */
+#define CB_MONITOR_EXTENSIBLEOCL "extensibleObject"
+#define CB_MONITOR_INSTNAME "cn"
+#define CB_MONITOR_ADDCOUNT "nsAddCount"
+#define CB_MONITOR_DELETECOUNT "nsDeleteCount"
+#define CB_MONITOR_MODIFYCOUNT "nsModifyCount"
+#define CB_MONITOR_MODRDNCOUNT "nsRenameCount"
+#define CB_MONITOR_SEARCHBASECOUNT "nsSearchBaseCount"
+#define CB_MONITOR_SEARCHONELEVELCOUNT "nsSearchOneLevelCount"
+#define CB_MONITOR_SEARCHSUBTREECOUNT "nsSearchSubtreeCount"
+#define CB_MONITOR_ABANDONCOUNT "nsAbandonCount"
+#define CB_MONITOR_BINDCOUNT "nsBindCount"
+#define CB_MONITOR_UNBINDCOUNT "nsUnbindCount"
+#define CB_MONITOR_COMPARECOUNT "nsCompareCount"
+#define CB_MONITOR_OUTGOINGCONN "nsOpenOpConnectionCount"
+#define CB_MONITOR_OUTGOINGBINDCOUNT "nsOpenBindConnectionCount"
+
+/* Global configuration */
+#define CB_CONFIG_GLOBAL_FORWARD_CTRLS "nsTransmittedControls"
+#define CB_CONFIG_GLOBAL_CHAINING_COMPONENTS "nsActiveChainingComponents"
+#define CB_CONFIG_GLOBAL_CHAINABLE_COMPONENTS "nsPossibleChainingComponents"
+/* not documented */
+#define CB_CONFIG_GLOBAL_DEBUG "nsDebug"
+
+
+/* Instance-specific configuration */
+#define CB_CONFIG_CHAINING_COMPONENTS CB_CONFIG_GLOBAL_CHAINING_COMPONENTS
+#define CB_CONFIG_EXTENSIBLEOCL "extensibleObject"
+/* XXXSD to be changed */
+#define CB_CONFIG_INSTANCE_FILTER "(objectclass=nsBackendInstance)"
+#define CB_CONFIG_INSTNAME "cn"
+#define CB_CONFIG_SUFFIX "nsslapd-suffix"
+#define CB_CONFIG_SIZELIMIT "nsslapd-sizelimit"
+#define CB_CONFIG_TIMELIMIT "nsslapd-timelimit"
+#define CB_CONFIG_HOSTURL "nsFarmServerURL"
+
+#define CB_CONFIG_BINDUSER "nsMultiplexorBindDn"
+#define CB_CONFIG_USERPASSWORD "nsMultiplexorCredentials"
+#define CB_CONFIG_MAXBINDCONNECTIONS "nsBindConnectionsLimit"
+#define CB_CONFIG_MAXCONNECTIONS "nsOperationConnectionsLimit"
+#define CB_CONFIG_MAXCONCURRENCY "nsConcurrentOperationsLimit"
+#define CB_CONFIG_MAXBINDCONCURRENCY "nsConcurrentBindLimit"
+
+#define CB_CONFIG_IMPERSONATION "nsProxiedAuthorization"
+
+#define CB_CONFIG_BINDTIMEOUT "nsBindTimeout"
+#define CB_CONFIG_TIMEOUT "nsOperationTimeout"
+#define CB_CONFIG_MAX_IDLE_TIME "nsMaxResponseDelay"
+#define CB_CONFIG_MAX_TEST_TIME "nsMaxTestResponseDelay"
+
+#define CB_CONFIG_REFERRAL "nsReferralOnScopedSearch"
+
+#define CB_CONFIG_CONNLIFETIME "nsConnectionLife"
+#define CB_CONFIG_ABANDONTIMEOUT "nsAbandonedSearchCheckInterval "
+#define CB_CONFIG_BINDRETRY "nsBindRetryLimit"
+#define CB_CONFIG_LOCALACL "nsCheckLocalACI"
+#define CB_CONFIG_HOPLIMIT "nsHopLimit"
+
+/* not documented */
+#define CB_CONFIG_ILLEGAL_ATTRS "nsServerDefinedAttributes"
+
+/* Default configuration values (as string) */
+
+/*
+ * CB_DEF_MAXCONNECTIONS and CB_DEF_MAXCONCURRENCY used to be 10.
+ * Reduced CB_DEF_MAXCONCURRENCY to 2 to workaround bug 623793 -
+ * err=1 in accesslogs and ber parsing errors in errors logs.
+ */
+#define CB_DEF_MAXCONNECTIONS "20" /* CB_CONFIG_MAXCONNECTIONS */
+#define CB_DEF_MAXCONCURRENCY "2" /* CB_CONFIG_MAXCONCURRENCY */
+#define CB_DEF_BIND_MAXCONNECTIONS "3" /* CB_CONFIG_MAXBINDCONNECTIONS */
+#define CB_DEF_BIND_MAXCONCURRENCY "10" /* CB_CONFIG_MAXBINDCONCURRENCY */
+#define CB_DEF_BINDTIMEOUT "15" /* CB_CONFIG_BINDTIMEOUT */
+#define CB_DEF_CONNLIFETIME "0" /* CB_CONFIG_CONNLIFETIME */
+#define CB_DEF_IMPERSONATION "on" /* CB_CONFIG_IMPERSONATION */
+#define CB_DEF_SEARCHREFERRAL "off" /* CB_CONFIG_REFERRAL */
+#define CB_DEF_ABANDON_TIMEOUT "1" /* CB_CONFIG_ABANDONTIMEOUT */
+#define CB_DEF_BINDRETRY "3" /* CB_CONFIG_BINDRETRY */
+#define CB_DEF_LOCALACL "off" /* CB_CONFIG_LOCALACL */
+#define CB_DEF_TIMELIMIT "3600"
+#define CB_DEF_SIZELIMIT "2000"
+#define CB_DEF_HOPLIMIT "10" /* CB_CONFIG_HOPLIMIT */
+#define CB_DEF_MAX_IDLE_TIME "60" /* CB_CONFIG_MAX_IDLE_TIME */
+#define CB_DEF_MAX_TEST_TIME "15" /* CB_CONFIG_MAX_TEST_TIME */
+
+typedef void *cb_config_get_fn_t(void *arg);
+typedef int cb_config_set_fn_t(void *arg, void *value, char *errorbuf, int phase, int apply);
+typedef struct _cb_instance_config_info {
+ char *config_name;
+ int config_type;
+ char *config_default_value;
+ cb_config_get_fn_t *config_get_fn;
+ cb_config_set_fn_t *config_set_fn;
+ int config_flags;
+} cb_instance_config_info;
+
+#define CB_CONFIG_TYPE_ONOFF 1 /* val = (int) value */
+#define CB_CONFIG_TYPE_STRING 2 /* val = (char *) value - The get functions
+ * for this type must return alloced memory
+ * that should be freed by the caller. */
+#define CB_CONFIG_TYPE_INT 3 /* val = (int) value */
+#define CB_CONFIG_TYPE_LONG 4 /* val = (long) value */
+#define CB_CONFIG_TYPE_INT_OCTAL 5 /* Same as CONFIG_TYPE_INT, but shown in octal*/
+#define CB_PREVIOUSLY_SET 1
+#define CB_ALWAYS_SHOW 2
+#define CB_CONFIG_PHASE_INITIALIZATION 1
+#define CB_CONFIG_PHASE_STARTUP 2
+#define CB_CONFIG_PHASE_RUNNING 3
+#define CB_CONFIG_PHASE_INTERNAL 4
+
+/*jarnou: default amount of time in seconds during wich the chaining backend will be unavailable */
+#define CB_UNAVAILABLE_PERIOD 30 /* CB_CONFIG_UNAVAILABLE_PERIOD */
+#define CB_INFINITE_TIME 360000 /* must be enough ... */
+/*jarnou: default number of connections failed from which the farm is declared unavailable */
+#define CB_NUM_CONN_BEFORE_UNAVAILABILITY 1
+#define FARMSERVER_UNAVAILABLE 1
+#define FARMSERVER_AVAILABLE 0
+
+/* Internal data structures */
+
+/* cb_backend represents the chaining backend type. */
+/* Only one instance is created when the plugin is */
+/* loaded. Contain global conf */
+typedef struct _cb_backend {
+
+ /*
+ ** keep track of plugin identity.
+ ** Used for internal operations
+ */
+
+ void *identity;
+ char * pluginDN;
+ char * configDN;
+
+ /*
+ ** There are times when we need a pointer to the chaining database
+ ** plugin, so we will store a pointer to it here. Examples of
+ ** when we need it are when we create a new instance and when
+ ** we need the name of the plugin to do internal ops.
+ */
+
+ struct slapdplugin *plugin;
+
+ /*
+ ** Global config. shared by all chaining db instances
+ */
+
+ struct {
+ char ** forward_ctrls; /* List of forwardable controls */
+ char ** chaining_components; /* List of plugins that chains */
+ char ** chainable_components; /* List of plugins allowed to chain*/
+ /* internal operations. */
+ PRRWLock *rwl_config_lock; /* Protect the global config */
+ } config;
+
+ int started; /* TRUE when started */
+
+} cb_backend;
+
+
+/* Connection management */
+
+/* states */
+#define CB_CONNSTATUS_OK 1 /* Open */
+#define CB_CONNSTATUS_DOWN 2 /* Down */
+#define CB_CONNSTATUS_STALE 3
+
+#define ENABLE_MULTITHREAD_PER_CONN 1 /* to allow multiple threads to perform LDAP operations on a connection */
+#define DISABLE_MULTITHREAD_PER_CONN 0 /* to allow only one thread to perform LDAP operations on a connection */
+
+/************** WARNING: Be careful if you want to change this constant. It is used in hexadecimal in cb_conn_stateless.c in the function PR_ThreadSelf() ************/
+#define MAX_CONN_ARRAY 2048 /* we suppose the number of threads in the server not to exceed this limit*/
+/**********************************************************************************************************/
+typedef struct _cb_outgoing_conn{
+ LDAP *ld;
+ unsigned long refcount;
+ struct _cb_outgoing_conn *next;
+ time_t opentime;
+ int status;
+ int ThreadId ; /* usefull to identify the thread when SSL is enabled */
+} cb_outgoing_conn;
+
+typedef struct {
+ char *hostname; /* Farm server name */
+ char *url;
+ unsigned int port;
+ int secure;
+ char *binddn; /* normalized */
+ char *binddn2; /* not normalized, value returned to the client */
+ char *password;
+ int bindit; /* If true, open AND bind */
+ char ** waste_basket; /* stale char * */
+
+ struct {
+ unsigned int maxconnections;
+ unsigned int maxconcurrency;
+ unsigned int connlifetime;
+ struct timeval op_timeout;
+ struct timeval bind_timeout;
+
+ Slapi_Mutex *conn_list_mutex;
+ Slapi_CondVar *conn_list_cv;
+ cb_outgoing_conn *conn_list;
+ unsigned int conn_list_count;
+
+ } conn;
+
+ cb_outgoing_conn *connarray[MAX_CONN_ARRAY]; /* array of secure connections */
+
+ /* To protect the config set by LDAP */
+ PRRWLock * rwl_config_lock;
+} cb_conn_pool;
+
+
+/* _cb_backend_instance represents a instance of the chaining */
+/* backend. */
+
+typedef struct _cb_backend_instance {
+
+ char *inst_name; /* Unique name */
+ Slapi_Backend *inst_be; /* Slapi_Bakedn associated with it */
+ cb_backend *backend_type; /* pointer to the backend type */
+
+ /* configuration */
+
+ PRRWLock *rwl_config_lock; /* protect the config */
+ char *configDn; /* config entry dn */
+ char *monitorDn; /* monitor entry dn */
+ int local_acl; /* True if local acl evaluation */
+ /* sometimes a chaining backend may be associated with a local backend
+ 1) The chaining backend is the backend of a sub suffix, and the
+ parent suffix has a local backend
+ 2) Entry distribution is being used to distribute write operations to
+ a chaining backend and other operations to a local backend
+ (e.g. a replication hub or consumer)
+ If the associated local backend is being initialized (import), it will be
+ disabled, and it will be impossible to evaluate local acls. In this case,
+ we still want to be able to chain operations to a farm server or another
+ database chain. But the current code will not allow cascading without
+ local acl evaluation (cb_controls.c). The following variable allows us to relax that
+ restriction while the associated backend is disabled
+ */
+ int associated_be_is_disabled; /* true if associated backend is disabled */
+ int isconfigured; /* True when valid config entry */
+ int impersonate; /* TRUE to impersonate users */
+ int searchreferral; /* TRUE to return referral for scoped searches */
+ int bind_retry;
+ struct timeval abandon_timeout; /* check for abandoned op periodically */
+ struct timeval op_timeout;
+ char **url_array; /* list of urls to farm servers */
+ char **chaining_components; /* List of plugins using chaining */
+ char **illegal_attributes; /* Attributes not forwarded */
+ char **every_attribute; /* attr list to get every attr, including op attrs */
+ int sizelimit;
+ int timelimit;
+ int hoplimit;
+ int max_idle_time; /* how long we wait before pinging the farm server */
+ int max_test_time; /* how long we wait during ping */
+
+ cb_conn_pool *pool; /* Operation cnx pool */
+ cb_conn_pool *bind_pool; /* Bind cnx pool */
+
+ Slapi_Eq_Context eq_ctx; /* Use to identify the function put in the queue */
+
+ /* Monitoring */
+
+ struct {
+ Slapi_Mutex *mutex;
+ unsigned long addcount;
+ unsigned long deletecount;
+ unsigned long modifycount;
+ unsigned long modrdncount;
+ unsigned long searchbasecount;
+ unsigned long searchonelevelcount;
+ unsigned long searchsubtreecount;
+ unsigned long abandoncount;
+ unsigned long bindcount;
+ unsigned long unbindcount;
+ unsigned long comparecount;
+ } monitor;
+
+ /* Monitoring the chaining BE availability */
+ /* Principle: as soon as we detect an abnormal pb with an ldap operation, and we close the connection
+ or if we can't open a connection, we increment a counter (cpt). This counter represents the number of
+ continuously pbs we can notice. Before forwarding an LDAP operation, wether the farmserver is available or not,
+ through the value of the counter. If the farmserver is not available, we just return an error msg to the client */
+
+ struct {
+ int unavailable_period ; /* how long we wait as soon as the farm is declared unavailable */
+ int max_num_conn_failed ; /* max number of consecutive failed/aborted connections before we declared the farm as unreachable */
+ time_t unavailableTimeLimit ; /* time from which the chaining BE becomes available */
+ int farmserver_state ; /* FARMSERVER_AVAILABLE if the chaining is available, FARMSERVER_UNAVAILABLE else */
+ int cpt ; /* count the number of consecutive failed/aborted connexions */
+ Slapi_Mutex *cpt_lock ; /* lock to protect the counter cpt */
+ Slapi_Mutex *lock_timeLimit ; /* lock to protect the unavailableTimeLimit variable*/
+ } monitor_availability;
+
+
+} cb_backend_instance;
+
+/* Data structure for the search operation to carry candidates */
+
+#define CB_SEARCHCONTEXT_ENTRY 2
+
+typedef struct _cb_searchContext {
+ int type;
+ void *data;
+ int msgid;
+ LDAP *ld;
+ cb_outgoing_conn *cnx;
+ Slapi_Entry *tobefreed;
+ LDAPMessage *pending_result;
+ int pending_result_type;
+} cb_searchContext;
+
+#define CB_REOPEN_CONN -1968 /* Different from any LDAP_XXX errors */
+
+/* Forward declarations */
+
+/* for ctrl_flags on cb_update_controls */
+#define CB_UPDATE_CONTROLS_ADDAUTH 1
+#define CB_UPDATE_CONTROLS_ISABANDON 2
+
+
+int cb_get_connection(cb_conn_pool * pool, LDAP ** ld, cb_outgoing_conn ** cnx, struct timeval * tmax, char **errmsg);
+int cb_config(cb_backend_instance * cb, int argc, char ** argv );
+int cb_update_controls( Slapi_PBlock *pb, LDAP * ld, LDAPControl *** controls, int ctrl_flags);
+int cb_is_control_forwardable(cb_backend * cb, char *controloid);
+int cb_access_allowed (Slapi_PBlock *pb,Slapi_Entry *e,char *type,struct berval * bval, int op, char ** buf);
+int cb_forward_operation(Slapi_PBlock * op);
+int cb_parse_instance_config_entry(cb_backend * cb, Slapi_Entry * e);
+int cb_abandon_connection(cb_backend_instance * cb, Slapi_PBlock * pb, LDAP ** ld);
+int cb_atoi(char *str);
+int cb_check_forward_abandon(cb_backend_instance * cb,Slapi_PBlock * pb, LDAP * ld, int msgid );
+int cb_search_monitor_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *e2, int *ret, char *t,void *a);
+int cb_config_load_dse_info(Slapi_PBlock * pb);
+int cb_config_add_dse_entries(cb_backend *cb, char **entries, char *string1, char *string2, char *string3);
+int cb_add_suffix(cb_backend_instance *inst, struct berval **bvals, int apply_mod, char *returntext);
+int cb_create_default_backend_instance_config(cb_backend * cb);
+int cb_build_backend_instance_config(cb_backend_instance *inst, Slapi_Entry * conf,int apply);
+int cb_instance_delete_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg);
+int cb_instance_search_config_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg);
+int cb_instance_add_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg);
+int cb_instance_modify_config_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg);
+int cb_dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg);
+int cb_config_search_callback(Slapi_PBlock *pb, Slapi_Entry* e1, Slapi_Entry* e2, int *returncode,
+ char *returntext, void *arg);
+int cb_config_add_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int cb_config_delete_instance_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int cb_config_modify_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int cb_config_add_instance_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int cb_delete_monitor_callback(Slapi_PBlock * pb, Slapi_Entry * e, Slapi_Entry * entryAfter, int * returnCode, char * returnText, void * arg);
+int cb_config_add_check_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2, int *returncode,
+ char *returntext, void *arg);
+int cb_instance_add_config_check_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg);
+int cb_config_modify_check_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode,
+ char *returntext, void *arg);
+
+void cb_eliminate_illegal_attributes(cb_backend_instance * inst, Slapi_Entry * e);
+void cb_release_op_connection(cb_conn_pool * pool, LDAP *ldd, int dispose);
+void cb_register_supported_control( cb_backend * cb, char *controloid, unsigned long controlops );
+void cb_unregister_all_supported_control( cb_backend * cb );
+void cb_register_supported_control( cb_backend * cb, char *controloid, unsigned long controlops );
+void cb_unregister_supported_control( cb_backend * cb, char *controloid, unsigned long controlops );
+void cb_set_acl_policy(Slapi_PBlock *pb);
+void cb_close_conn_pool(cb_conn_pool * pool);
+void cb_update_monitor_info(Slapi_PBlock * pb, cb_backend_instance * inst,int op);
+void cb_send_ldap_result(Slapi_PBlock *pb, int err, char *m,char *t, int ne, struct berval **urls );
+void cb_stale_all_connections( cb_backend_instance * be);
+int
+cb_config_add_instance_check_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg);
+
+
+int chaining_back_add ( Slapi_PBlock *pb );
+int chaining_back_delete ( Slapi_PBlock *pb );
+int chaining_back_compare ( Slapi_PBlock *pb );
+int chaining_back_modify ( Slapi_PBlock *pb );
+int chaining_back_modrdn ( Slapi_PBlock *pb );
+int chaining_back_abandon ( Slapi_PBlock *pb );
+int chaining_back_entry_release ( Slapi_PBlock *pb );
+int chainingdb_next_search_entry( Slapi_PBlock *pb );
+int chainingdb_build_candidate_list ( Slapi_PBlock *pb );
+int chainingdb_start (Slapi_PBlock *pb );
+int chainingdb_bind (Slapi_PBlock *pb );
+int cb_db_size (Slapi_PBlock *pb );
+int cb_back_close (Slapi_PBlock *pb );
+int cb_back_cleanup (Slapi_PBlock *pb );
+
+long cb_atol(char *str);
+
+Slapi_Entry * cb_LDAPMessage2Entry(LDAP * ctx, LDAPMessage * msg, int attrsonly);
+char * cb_urlparse_err2string( int err );
+char * cb_get_rootdn();
+struct berval ** referrals2berval(char ** referrals);
+cb_backend_instance * cb_get_instance(Slapi_Backend * be);
+cb_backend * cb_get_backend_type();
+int cb_debug_on();
+void cb_set_debug(int on);
+int cb_ping_farm(cb_backend_instance *cb,cb_outgoing_conn * cnx,time_t end);
+void cb_update_failed_conn_cpt ( cb_backend_instance *cb ) ;
+void cb_reset_conn_cpt( cb_backend_instance *cb ) ;
+int cb_check_availability( cb_backend_instance *cb, Slapi_PBlock *pb ) ;
+
+time_t current_time();
+char* get_localhost_DNS();
+
+/* this function is called when state of a backend changes */
+void cb_be_state_change (void *handle, char *be_name, int old_be_state, int new_be_state);
+
+#endif
diff --git a/ldap/servers/plugins/chainingdb/cb_abandon.c b/ldap/servers/plugins/chainingdb/cb_abandon.c
new file mode 100644
index 00000000..ca0cfc09
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_abandon.c
@@ -0,0 +1,50 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+ * Perform an abandon operation
+ *
+ * Returns:
+ * 0 - success
+ * <0 - fail
+ *
+ */
+
+int
+chaining_back_abandon ( Slapi_PBlock *pb )
+{
+ /*
+ * Abandon forwarded to the farm server for scoped
+ * searches only. Done in cb_search.c
+ */
+ return 0;
+}
+
+int cb_check_forward_abandon(cb_backend_instance * cb,Slapi_PBlock * pb, LDAP * ld, int msgid ) {
+
+ int rc;
+ LDAPControl ** ctrls=NULL;
+
+ if (slapi_op_abandoned( pb )) {
+
+ if ((rc=cb_forward_operation(pb)) != LDAP_SUCCESS ) {
+ return 0;
+ }
+
+ if ((rc = cb_update_controls( pb,ld,&ctrls,CB_UPDATE_CONTROLS_ISABANDON )) != LDAP_SUCCESS ) {
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ return 0;
+ }
+ rc = ldap_abandon_ext(ld, msgid, ctrls, NULL );
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ return 1;
+ }
+ return 0;
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_acl.c b/ldap/servers/plugins/chainingdb/cb_acl.c
new file mode 100644
index 00000000..ce0a6793
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_acl.c
@@ -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 **/
+#include "cb.h"
+
+/*
+** generic function to send back results
+** Turn off acl eval on front-end when needed
+*/
+
+void cb_set_acl_policy(Slapi_PBlock *pb) {
+
+ Slapi_Backend *be;
+ cb_backend_instance *cb;
+ int noacl;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ /* disable acl checking if the local_acl flag is not set
+ or if the associated backend is disabled */
+ noacl=!(cb->local_acl) || cb->associated_be_is_disabled;
+
+ if (noacl) {
+ slapi_pblock_set(pb, SLAPI_PLUGIN_DB_NO_ACL, &noacl);
+ } else {
+ /* Be very conservative about acl evaluation */
+ slapi_pblock_set(pb, SLAPI_PLUGIN_DB_NO_ACL, &noacl);
+ }
+}
+
+int cb_access_allowed(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e, /* The Slapi_Entry */
+ char *attr, /* Attribute of the entry */
+ struct berval *val, /* value of attr. NOT USED */
+ int access, /* access rights */
+ char **errbuf
+ )
+
+{
+
+switch (access) {
+
+ case SLAPI_ACL_ADD:
+ case SLAPI_ACL_DELETE:
+ case SLAPI_ACL_COMPARE:
+ case SLAPI_ACL_WRITE:
+ case SLAPI_ACL_PROXY:
+
+ /* Keep in mind some entries are NOT */
+ /* available for acl evaluation */
+
+ return slapi_access_allowed(pb,e,attr,val,access);
+ default:
+ return LDAP_INSUFFICIENT_ACCESS;
+}
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_add.c b/ldap/servers/plugins/chainingdb/cb_add.c
new file mode 100644
index 00000000..e0b49f7c
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_add.c
@@ -0,0 +1,227 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+ * Perform an add operation
+ *
+ * Returns:
+ * 0 - success
+ * <0 - fail
+ *
+ */
+
+int
+chaining_back_add ( Slapi_PBlock *pb )
+{
+
+ Slapi_Backend *be;
+ Slapi_Entry *e;
+ cb_backend_instance *cb;
+ LDAPControl **serverctrls=NULL;
+ LDAPControl **ctrls=NULL;
+ int rc,parse_rc,msgid,i;
+ LDAP *ld=NULL;
+ char **referrals=NULL;
+ LDAPMod ** mods;
+ LDAPMessage * res;
+ char *dn,* matched_msg, *error_msg;
+ char *cnxerrbuf=NULL;
+ time_t endtime;
+ cb_outgoing_conn *cnx;
+
+ if ( (rc=cb_forward_operation(pb)) != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL, "Remote data access disabled", 0, NULL );
+ return -1;
+ }
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ /* Update monitor info */
+ cb_update_monitor_info(pb,cb,SLAPI_OPERATION_ADD);
+
+ /* Check wether the chaining BE is available or not */
+ if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){
+ return -1;
+ }
+
+
+ slapi_pblock_get( pb, SLAPI_ADD_TARGET, &dn );
+ slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e );
+
+ /* Check local access controls */
+ if (cb->local_acl && !cb->associated_be_is_disabled) {
+ char * errbuf=NULL;
+ rc = cb_access_allowed (pb, e, NULL, NULL, SLAPI_ACL_ADD, &errbuf);
+ if ( rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL, errbuf, 0, NULL );
+ slapi_ch_free((void **)&errbuf);
+ return -1;
+ }
+ }
+
+ /* Build LDAPMod from the SLapi_Entry */
+ cb_eliminate_illegal_attributes(cb,e);
+
+ if ((rc = slapi_entry2mods ((const Slapi_Entry *)e, NULL, &mods)) != LDAP_SUCCESS) {
+ cb_send_ldap_result( pb, rc,NULL,NULL, 0, NULL);
+ return -1;
+ }
+
+ /* Grab a connection handle */
+ if ((rc = cb_get_connection(cb->pool,&ld,&cnx,NULL,&cnxerrbuf)) != LDAP_SUCCESS) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR,NULL,cnxerrbuf, 0, NULL);
+ ldap_mods_free(mods,1);
+ slapi_ch_free((void **)&cnxerrbuf);
+ /* ping the farm. If the farm is unreachable, we increment the counter */
+ cb_ping_farm(cb,NULL,0);
+
+ return -1;
+ }
+
+ /* Control management */
+ if ( (rc = cb_update_controls( pb,ld,&ctrls,CB_UPDATE_CONTROLS_ADDAUTH)) != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL,NULL, 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ ldap_mods_free(mods,1);
+ return -1;
+ }
+
+ if ( slapi_op_abandoned( pb )) {
+ cb_release_op_connection(cb->pool,ld,0);
+ ldap_mods_free(mods,1);
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ return -1;
+ }
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ /* Send LDAP operation to the remote host */
+ rc = ldap_add_ext( ld, dn, mods, ctrls, NULL, &msgid );
+
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+
+ if ( rc != LDAP_SUCCESS ) {
+
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ ldap_mods_free(mods,1);
+ return -1;
+ }
+
+ /*
+ * Poll the server for the results of the add operation.
+ * Check for abandoned operation regularly.
+ */
+
+ while ( 1 ) {
+
+ if (cb_check_forward_abandon(cb,pb,ld,msgid)) {
+ /* connection handle released in cb_check_forward_abandon() */
+ ldap_mods_free(mods,1);
+ return -1;
+ }
+
+ rc = ldap_result( ld, msgid, 0, &cb->abandon_timeout, &res );
+ switch ( rc ) {
+ case -1:
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ ldap_mods_free(mods,1);
+ if (res)
+ ldap_msgfree(res);
+ return -1;
+ case 0:
+
+ if ((rc=cb_ping_farm(cb,cnx,endtime)) != LDAP_SUCCESS) {
+
+ /* does not respond. give up and return a*/
+ /* error to the client. */
+
+ /*cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);*/
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL, "FARM SERVER TEMPORARY UNAVAILABLE", 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ ldap_mods_free(mods,1);
+ if (res)
+ ldap_msgfree(res);
+ return -1;
+ }
+#ifdef CB_YIELD
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+#endif
+ break;
+ default:
+ serverctrls=NULL;
+ matched_msg=error_msg=NULL;
+ referrals=NULL;
+
+ parse_rc = ldap_parse_result( ld, res, &rc, &matched_msg,
+ &error_msg, &referrals, &serverctrls, 1 );
+
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(parse_rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(parse_rc));
+ ldap_mods_free(mods,1);
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free referrals */
+ if (referrals)
+ charray_free(referrals);
+ return -1;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ struct berval ** refs = referrals2berval(referrals);
+ cb_send_ldap_result( pb, rc, matched_msg, error_msg, 0, refs);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ ldap_mods_free(mods,1);
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (refs)
+ ber_bvecfree(refs);
+ if (referrals)
+ charray_free(referrals);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ return -1;
+ }
+
+ ldap_mods_free(mods,1 );
+ cb_release_op_connection(cb->pool,ld,0);
+
+ /* Add control response sent by the farm server */
+
+ for (i=0; serverctrls && serverctrls[i];i++)
+ slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, serverctrls[i]);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free matched_msg, error_msg, and referrals if necessary */
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (referrals)
+ charray_free(referrals);
+ cb_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+
+ slapi_entry_free(e);
+ slapi_pblock_set( pb, SLAPI_ADD_ENTRY, NULL );
+
+ return 0;
+ }
+ }
+
+ /* Never reached */
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_bind.c b/ldap/servers/plugins/chainingdb/cb_bind.c
new file mode 100644
index 00000000..495b672f
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_bind.c
@@ -0,0 +1,290 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+static void
+cb_free_bervals( struct berval **bvs );
+
+
+static int
+cb_sasl_bind_once_s( cb_conn_pool *pool, char *dn, int method, char * mechanism,
+ struct berval *creds, LDAPControl **reqctrls,
+ char **matcheddnp, char **errmsgp, struct berval ***refurlsp,
+ LDAPControl ***resctrlsp , int * status);
+
+/*
+ * Attempt to chain a bind request off to "srvr." We return an LDAP error
+ * code that indicates whether we successfully got a response from the
+ * other server or not. If we succeed, we return LDAP_SUCCESS and *lderrnop
+ * is set to the result code from the remote server.
+ *
+ * Note that in the face of "ldap server down" or "ldap connect failed" errors
+ * we make up to "tries" attempts to bind to the remote server. Since we
+ * are only interested in recovering silently when the remote server is up
+ * but decided to close our connection, we retry without pausing between
+ * attempts.
+ */
+
+static int
+cb_sasl_bind_s(Slapi_PBlock * pb, cb_conn_pool *pool, int tries,
+ char *dn, int method,char * mechanism, struct berval *creds, LDAPControl **reqctrls,
+ char **matcheddnp, char **errmsgp, struct berval ***refurlsp,
+ LDAPControl ***resctrlsp ,int *status) {
+
+ int rc;
+
+ do {
+ /* check to see if operation has been abandoned...*/
+
+ if (LDAP_AUTH_SIMPLE!=method)
+ return LDAP_AUTH_METHOD_NOT_SUPPORTED;
+
+ if ( slapi_op_abandoned( pb )) {
+ rc = LDAP_USER_CANCELLED;
+ } else {
+ rc = cb_sasl_bind_once_s( pool, dn, method,mechanism, creds, reqctrls,
+ matcheddnp, errmsgp, refurlsp, resctrlsp ,status);
+ }
+ } while ( CB_LDAP_CONN_ERROR( rc ) && --tries > 0 );
+
+ return( rc );
+}
+
+static int
+cb_sasl_bind_once_s( cb_conn_pool *pool, char *dn, int method, char * mechanism,
+ struct berval *creds, LDAPControl **reqctrls,
+ char **matcheddnp, char **errmsgp, struct berval ***refurlsp,
+ LDAPControl ***resctrlsp , int * status) {
+
+ int rc, msgid;
+ char **referrals;
+ struct timeval timeout_copy, *timeout;
+ LDAPMessage *result=NULL;
+ LDAP *ld=NULL;
+ char *cnxerrbuf=NULL;
+ cb_outgoing_conn *cnx;
+ int version=LDAP_VERSION3;
+
+ /* Grab an LDAP connection to use for this bind. */
+
+ PR_RWLock_Rlock(pool->rwl_config_lock);
+ timeout_copy.tv_sec = pool->conn.bind_timeout.tv_sec;
+ timeout_copy.tv_usec = pool->conn.bind_timeout.tv_usec;
+ PR_RWLock_Unlock(pool->rwl_config_lock);
+
+ if (( rc = cb_get_connection( pool, &ld ,&cnx, NULL, &cnxerrbuf)) != LDAP_SUCCESS ) {
+ *errmsgp=cnxerrbuf;
+ goto release_and_return;
+ }
+
+ /* Send the bind operation (need to retry on LDAP_SERVER_DOWN) */
+
+ ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
+
+ if (( rc = ldap_sasl_bind( ld, dn, LDAP_SASL_SIMPLE, creds, reqctrls,
+ NULL, &msgid )) != LDAP_SUCCESS ) {
+ goto release_and_return;
+ }
+
+ /* XXXSD what is the exact semantics of bind_to ? it is used to get a
+ connection handle and later to bind ==> bind op may last 2*bind_to
+ from the user point of view
+ confusion comes from teh fact that bind to is used 2for 3 differnt thinks,
+ */
+
+ /*
+ * determine timeout value (how long we will wait for a response)
+ * if timeout is zero'd, we wait indefinitely.
+ */
+ if ( timeout_copy.tv_sec == 0 && timeout_copy.tv_usec == 0 ) {
+ timeout = NULL;
+ } else {
+ timeout = &timeout_copy;
+ }
+
+ /*
+ * Wait for a result.
+ */
+ rc = ldap_result( ld, msgid, 1, timeout, &result );
+
+ /*
+ * Interpret the result.
+ */
+
+ if ( rc == 0 ) { /* timeout */
+ /*
+ * Timed out waiting for a reply from the server.
+ */
+ rc = LDAP_TIMEOUT;
+ } else if ( rc < 0 ) {
+
+ /* Some other error occurred (no result received). */
+ char * matcheddnp2, * errmsgp2;
+ matcheddnp2=errmsgp2=NULL;
+
+ rc = ldap_get_lderrno( ld, &matcheddnp2, &errmsgp2 );
+
+ /* Need to allocate errmsgs */
+ if (matcheddnp2)
+ *matcheddnp=slapi_ch_strdup(matcheddnp2);
+ if (errmsgp2)
+ *errmsgp=slapi_ch_strdup(errmsgp2);
+
+ if ( LDAP_SUCCESS != rc ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_sasl_bind_once_s failed (%s)\n",ldap_err2string(rc));
+ }
+ } else {
+
+ /* Got a result from remote server -- parse it.*/
+
+ char * matcheddnp2, * errmsgp2;
+ matcheddnp2=errmsgp2=NULL;
+ *resctrlsp=NULL;
+ rc = ldap_parse_result( ld, result, status, matcheddnp, errmsgp,
+ &referrals, resctrlsp, 1 );
+ if ( referrals != NULL ) {
+ *refurlsp = referrals2berval( referrals );
+ ldap_value_free( referrals );
+ }
+ /* realloc matcheddn & errmsg because the mem alloc model */
+ /* may differ from malloc */
+ if (matcheddnp2) {
+ *matcheddnp=slapi_ch_strdup(matcheddnp2);
+ ldap_memfree(matcheddnp2);
+ }
+ if (errmsgp2) {
+ *errmsgp=slapi_ch_strdup(errmsgp2);
+ ldap_memfree(errmsgp2);
+ }
+
+ }
+
+release_and_return:
+ if ( ld != NULL ) {
+ cb_release_op_connection( pool, ld, CB_LDAP_CONN_ERROR( rc ));
+ }
+
+ return( rc );
+}
+
+int
+chainingdb_bind( Slapi_PBlock *pb ) {
+
+ int status=LDAP_SUCCESS;
+ int allocated_errmsg;
+ int rc=LDAP_SUCCESS;
+ cb_backend_instance *cb;
+ Slapi_Backend *be;
+ char *dn;
+ int method;
+ struct berval *creds, **urls;
+ char *matcheddn,*errmsg;
+ LDAPControl **reqctrls, **resctrls, **ctrls;
+ char * mechanism;
+ int freectrls=1;
+ int bind_retry;
+
+ if ( LDAP_SUCCESS != (rc = cb_forward_operation(pb) )) {
+ cb_send_ldap_result( pb, rc, NULL, "Chaining forbidden", 0, NULL );
+ return SLAPI_BIND_FAIL;
+ }
+
+ ctrls=NULL;
+ /* don't add proxy auth control. use this call to check for supported */
+ /* controls only. */
+ if ( LDAP_SUCCESS != ( rc = cb_update_controls( pb, NULL, &ctrls, 0 )) ) {
+ cb_send_ldap_result( pb, rc, NULL, NULL, 0, NULL );
+ if (ctrls)
+ ldap_controls_free(ctrls);
+ return SLAPI_BIND_FAIL;
+ }
+ if (ctrls)
+ ldap_controls_free(ctrls);
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_get( pb, SLAPI_BIND_TARGET, &dn );
+ slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method );
+ slapi_pblock_get( pb, SLAPI_BIND_SASLMECHANISM, &mechanism);
+ slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &creds );
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &reqctrls );
+ cb = cb_get_instance(be);
+
+ if ( NULL == dn )
+ dn="";
+
+ /* always allow noauth simple binds */
+ if (( method == LDAP_AUTH_SIMPLE) && creds->bv_len == 0 ) {
+ return( SLAPI_BIND_ANONYMOUS );
+ }
+
+ cb_update_monitor_info(pb,cb,SLAPI_OPERATION_BIND);
+
+ matcheddn=errmsg=NULL;
+ allocated_errmsg = 0;
+ resctrls=NULL;
+ urls=NULL;
+
+ /* Check wether the chaining BE is available or not */
+ if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){
+ return -1;
+ }
+
+ PR_RWLock_Rlock(cb->rwl_config_lock);
+ bind_retry=cb->bind_retry;
+ PR_RWLock_Unlock(cb->rwl_config_lock);
+
+ if ( LDAP_SUCCESS == (rc = cb_sasl_bind_s(pb, cb->bind_pool, bind_retry, dn,method,mechanism,
+ creds,reqctrls,&matcheddn,&errmsg,&urls,&resctrls, &status))) {
+ rc = status;
+ allocated_errmsg = 1;
+ } else
+ if ( LDAP_USER_CANCELLED != rc ) {
+ errmsg = ldap_err2string( rc );
+ if (rc == LDAP_TIMEOUT) {
+ cb_ping_farm(cb,NULL,NULL);
+ }
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( rc != LDAP_USER_CANCELLED ) { /* not abandoned */
+ if ( resctrls != NULL ) {
+ slapi_pblock_set( pb, SLAPI_RESCONTROLS, resctrls );
+ freectrls=0;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, matcheddn, errmsg, 0, urls );
+ }
+ }
+
+ if ( urls != NULL ) {
+ cb_free_bervals( urls );
+ }
+ if ( freectrls && ( resctrls != NULL )) {
+ ldap_controls_free( resctrls );
+ }
+ slapi_ch_free((void **)& matcheddn );
+ if ( allocated_errmsg && errmsg != NULL ) {
+ slapi_ch_free((void **)& errmsg );
+ }
+
+ return ((rc == LDAP_SUCCESS ) ? SLAPI_BIND_SUCCESS : SLAPI_BIND_FAIL );
+}
+
+static void
+cb_free_bervals( struct berval **bvs )
+{
+ int i;
+
+ if ( bvs != NULL ) {
+ for ( i = 0; bvs[ i ] != NULL; ++i ) {
+ slapi_ch_free( (void **)&bvs[ i ] );
+ }
+ }
+ slapi_ch_free( (void **)&bvs );
+}
+
diff --git a/ldap/servers/plugins/chainingdb/cb_cleanup.c b/ldap/servers/plugins/chainingdb/cb_cleanup.c
new file mode 100644
index 00000000..b034b0a1
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_cleanup.c
@@ -0,0 +1,22 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+** cLeanup a chaining backend instance
+*/
+
+int cb_back_cleanup( Slapi_PBlock *pb )
+{
+
+ /*
+ ** Connections have been closed in cb_back_close()
+ ** For now, don't do more
+ */
+
+ return 0;
+}
+
diff --git a/ldap/servers/plugins/chainingdb/cb_close.c b/ldap/servers/plugins/chainingdb/cb_close.c
new file mode 100644
index 00000000..3ef52e32
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_close.c
@@ -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 **/
+#include "cb.h"
+
+/*
+** Close a chaining backend instance
+** Should be followed by a cleanup
+*/
+
+int cb_back_close( Slapi_PBlock *pb )
+{
+ Slapi_Backend * be;
+ cb_backend_instance * inst;
+ int rc;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ if (be == NULL) {
+
+ cb_backend * cb = cb_get_backend_type();
+ CB_ASSERT(cb!=NULL);
+
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, cb->configDN, LDAP_SCOPE_BASE,
+ "(objectclass=*)",cb_config_modify_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, cb->configDN, LDAP_SCOPE_BASE,
+ "(objectclass=*)",cb_config_modify_check_callback);
+
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_POSTOP, cb->configDN, LDAP_SCOPE_BASE,
+ "(objectclass=*)",cb_config_add_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, cb->configDN, LDAP_SCOPE_BASE,
+ "(objectclass=*)",cb_config_add_check_callback);
+
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, cb->configDN, LDAP_SCOPE_BASE,
+ "(objectclass=*)",cb_config_search_callback);
+
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_POSTOP, cb->pluginDN,
+ LDAP_SCOPE_SUBTREE, CB_CONFIG_INSTANCE_FILTER, cb_config_add_instance_callback);
+
+ return 0;
+ }
+
+ /* XXXSD: temp fix . Sometimes, this functions */
+ /* gets called with a ldbm backend instance... */
+
+ {
+ const char * betype = slapi_be_gettype(be);
+ if (!betype || strcasecmp(betype,CB_CHAINING_BACKEND_TYPE)) {
+
+ slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "Wrong database type.\n");
+ return 0;
+ }
+ }
+
+ inst = cb_get_instance(be);
+ CB_ASSERT( inst!=NULL );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,"Stopping chaining database instance %s\n",
+ inst->configDn);
+ /* emulate a backend instance deletion */
+ /* to clean up everything */
+ cb_instance_delete_config_callback(NULL, NULL,NULL, &rc, NULL, inst);
+
+ return 0;
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_compare.c b/ldap/servers/plugins/chainingdb/cb_compare.c
new file mode 100644
index 00000000..ebce1645
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_compare.c
@@ -0,0 +1,217 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+ * Perform a compare operation
+ *
+ * Returns:
+ * 0 - success
+ * <0 - fail
+ *
+ */
+
+int
+chaining_back_compare ( Slapi_PBlock *pb )
+{
+
+ Slapi_Backend * be;
+ cb_backend_instance *cb=NULL;
+ struct berval *bval=NULL;
+ LDAPControl **ctrls, **serverctrls;
+ int rc,parse_rc,msgid,i,checkacl;
+ LDAP *ld=NULL;
+ char **referrals=NULL;
+ LDAPMessage * res;
+ char *type,*dn,* matched_msg, *error_msg;
+ char *cnxerrbuf=NULL;
+ time_t endtime;
+ cb_outgoing_conn *cnx;
+
+ if ( LDAP_SUCCESS != (rc=cb_forward_operation(pb) )) {
+ cb_send_ldap_result( pb, rc, NULL, "Chaining forbidden", 0, NULL );
+ return -1;
+ }
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ cb_update_monitor_info(pb,cb,SLAPI_OPERATION_COMPARE);
+
+ /* Check wether the chaining BE is available or not */
+ if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){
+ return -1;
+ }
+
+ slapi_pblock_get( pb, SLAPI_COMPARE_TARGET, &dn );
+ slapi_pblock_get( pb, SLAPI_COMPARE_TYPE, &type );
+ slapi_pblock_get( pb, SLAPI_COMPARE_VALUE, &bval );
+
+ /*
+ * Check local acls
+ * No need to lock the config to access cb->local_acl
+ */
+
+ checkacl=cb->local_acl && !cb->associated_be_is_disabled;
+
+ if (checkacl) {
+ char * errbuf=NULL;
+ Slapi_Entry *te = slapi_entry_alloc();
+ slapi_entry_set_dn(te,slapi_ch_strdup(dn));
+ rc = cb_access_allowed (pb, te, type, bval, SLAPI_ACL_COMPARE,&errbuf);
+ slapi_entry_free(te);
+
+ if ( rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL, errbuf, 0, NULL );
+ slapi_ch_free((void **) &errbuf);
+ return 1;
+ }
+ }
+
+ /*
+ * Grab a connection handle
+ */
+
+ if ((rc = cb_get_connection(cb->pool,&ld,&cnx,NULL,&cnxerrbuf)) != LDAP_SUCCESS) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, cnxerrbuf, 0, NULL);
+ slapi_ch_free((void **)&cnxerrbuf);
+ /* ping the farm. If the farm is unreachable, we increment the counter */
+ cb_ping_farm(cb,NULL,0);
+ return 1;
+ }
+
+ /*
+ * Control management
+ */
+
+ if ( (rc = cb_update_controls( pb,ld,&ctrls,CB_UPDATE_CONTROLS_ADDAUTH )) != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL,NULL, 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ return 1;
+ }
+
+ if ( slapi_op_abandoned( pb )) {
+ cb_release_op_connection(cb->pool,ld,0);
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ return -1;
+ }
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ /*
+ * Send LDAP operation to the remote host
+ */
+
+ rc = ldap_compare_ext( ld, dn, type, bval, ctrls, NULL, &msgid );
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+
+ if ( rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ return 1;
+ }
+
+ while ( 1 ) {
+
+ if (cb_check_forward_abandon(cb,pb,ld,msgid)) {
+ return -1;
+ }
+
+ /* No need to lock the config to access cb->abandon_timeout */
+ rc = ldap_result( ld, msgid, 0, &cb->abandon_timeout, &res );
+ switch ( rc ) {
+ case -1:
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ return 1;
+ case 0:
+ if ((rc=cb_ping_farm(cb,cnx,endtime)) != LDAP_SUCCESS) {
+
+ /* does not respond. give up and return a*/
+ /* error to the client. */
+
+ /*cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);*/
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL, "FARM SERVER TEMPORARY UNAVAILABLE", 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ return 1;
+ }
+#ifdef CB_YIELD
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+#endif
+ break;
+ default:
+ matched_msg=error_msg=NULL;
+ parse_rc = ldap_parse_result( ld, res, &rc, &matched_msg,
+ &error_msg, &referrals, &serverctrls, 1 );
+ if ( parse_rc != LDAP_SUCCESS ) {
+
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(parse_rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(parse_rc));
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free referrals */
+ if (referrals)
+ charray_free(referrals);
+ return 1;
+ }
+
+ switch ( rc ) {
+
+ case LDAP_COMPARE_TRUE:
+ case LDAP_COMPARE_FALSE:
+ break;
+ default: {
+ struct berval ** refs = referrals2berval(referrals);
+
+ cb_send_ldap_result( pb, rc, matched_msg, error_msg, 0, refs);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (refs)
+ ber_bvecfree(refs);
+ if (referrals)
+ charray_free(referrals);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ return 1;
+ }
+ }
+
+ /* Add control response sent by the farm server */
+
+ for (i=0; serverctrls && serverctrls[i];i++)
+ slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, serverctrls[i]);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free matched_msg, error_msg, and referrals if necessary */
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (referrals)
+ charray_free(referrals);
+
+ cb_send_ldap_result( pb, rc , NULL, NULL, 0, NULL );
+ cb_release_op_connection(cb->pool,ld,0);
+ return 0;
+ }
+ }
+
+ /* Never reached */
+ /* return 0; */
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_config.c b/ldap/servers/plugins/chainingdb/cb_config.c
new file mode 100644
index 00000000..13dd7b22
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_config.c
@@ -0,0 +1,600 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+#include <errno.h>
+
+/* Forward declarations */
+
+static int cb_parse_config_entry(cb_backend * cb, Slapi_Entry *e);
+
+/* body starts here */
+
+/* Used to add an array of entries, like the one above and
+** cb_instance_skeleton_entries to the dse.
+** Returns 0 on success.
+*/
+
+
+
+int cb_config_add_dse_entries(cb_backend *cb, char **entries, char *string1, char *string2, char *string3)
+{
+ int x;
+ Slapi_Entry *e;
+ Slapi_PBlock *util_pb = NULL;
+ int res, rc = 0;
+ char entry_string[CB_BUFSIZE];
+
+ for(x = 0; strlen(entries[x]) > 0; x++) {
+ util_pb = slapi_pblock_new();
+ sprintf(entry_string, entries[x], string1, string2, string3);
+ e = slapi_str2entry(entry_string, 0);
+ slapi_add_entry_internal_set_pb(util_pb, e, NULL, cb->identity, 0);
+ slapi_add_internal_pb(util_pb);
+ slapi_pblock_get(util_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ if ( LDAP_SUCCESS != res && LDAP_ALREADY_EXISTS != res ) {
+ char ebuf[ BUFSIZ ];
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Unable to add config entry (%s) to the DSE: %s\n",
+ escape_string(slapi_entry_get_dn(e), ebuf),
+ ldap_err2string(res));
+ rc = res;
+ slapi_pblock_destroy(util_pb);
+ break;
+ }
+ slapi_pblock_destroy(util_pb);
+ }
+ return rc;
+}
+
+/*
+** Try to read the entry cn=config,cn=chaining database,cn=plugins,cn=config
+** If the entry is there, then process the configuration information it stores.
+** If it is missing, create it with default configuration.
+** The default configuration is taken from the default entry if it exists
+*/
+
+int cb_config_load_dse_info(Slapi_PBlock * pb) {
+
+ Slapi_PBlock *search_pb,*default_pb;
+ Slapi_Entry **entries = NULL;
+ Slapi_Entry *configEntry=NULL;
+ int res,default_res,i;
+ char defaultDn[CB_BUFSIZE];
+ cb_backend *cb;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &cb );
+
+ /* Get global configuration entry */
+ search_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(search_pb, cb->configDN, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL, cb->identity, 0);
+ slapi_search_internal_pb (search_pb);
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if ( LDAP_SUCCESS == res ) {
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || entries[0] == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Error accessing entry <%s>\n",cb->configDN);
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+ return 1;
+ }
+ configEntry=entries[0];
+ } else
+ if ( LDAP_NO_SUCH_OBJECT == res ) {
+ /* Don't do anything. The default conf is used */
+ configEntry=NULL;
+ } else {
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Error accessing entry <%s> (%s)\n",cb->configDN,ldap_err2string(res));
+ return 1;
+ }
+
+ /* Parse the configuration entry */
+ /* Default config if configEntry is NULL*/
+
+ cb_parse_config_entry(cb, configEntry);
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+
+ /*
+ ** Parse the chaining backend instances
+ ** Immediate subordinates of cn=<plugin name>,cn=plugins,cn=config
+ */
+
+ search_pb = slapi_pblock_new();
+
+ slapi_search_internal_set_pb(search_pb, cb->pluginDN, LDAP_SCOPE_ONELEVEL,
+ CB_CONFIG_INSTANCE_FILTER,NULL,0,NULL,NULL,cb->identity, 0);
+ slapi_search_internal_pb (search_pb);
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ if (res != LDAP_SUCCESS) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Error accessing the config DSE (%s)\n",ldap_err2string(res));
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+ return 1;
+ }
+
+ /* Get the default instance value entry if it exists */
+ /* else create it */
+
+ sprintf(defaultDn,"cn=default instance config,%s",cb->pluginDN);
+
+ default_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(default_pb, defaultDn, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL, cb->identity, 0);
+ slapi_search_internal_pb (default_pb);
+ slapi_pblock_get(default_pb, SLAPI_PLUGIN_INTOP_RESULT, &default_res);
+ if (LDAP_SUCCESS != default_res) {
+ cb_create_default_backend_instance_config(cb);
+ }
+
+ slapi_free_search_results_internal(default_pb);
+ slapi_pblock_destroy(default_pb);
+
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ for (i=0; entries && entries[i]; i++) {
+ int retcode;
+ char * aDn=slapi_entry_get_dn(entries[i]);
+ slapi_dn_normalize(aDn);
+
+ cb_instance_add_config_callback(pb,entries[i],NULL,&retcode,NULL,cb);
+ }
+
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+
+
+ /* Add callbacks */
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, cb->configDN,
+ LDAP_SCOPE_BASE, "(objectclass=*)",cb_config_modify_check_callback, (void *) cb);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, cb->configDN,
+ LDAP_SCOPE_BASE, "(objectclass=*)",cb_config_modify_callback, (void *) cb);
+
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, cb->configDN,
+ LDAP_SCOPE_BASE, "(objectclass=*)",cb_config_add_check_callback, (void *) cb);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_POSTOP, cb->configDN,
+ LDAP_SCOPE_BASE, "(objectclass=*)",cb_config_add_callback, (void *) cb);
+
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, cb->configDN,
+ LDAP_SCOPE_BASE, "(objectclass=*)",cb_config_search_callback, (void *) cb);
+
+ /* instance creation */
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, cb->pluginDN,
+ LDAP_SCOPE_SUBTREE, CB_CONFIG_INSTANCE_FILTER, cb_config_add_instance_check_callback, (void *) cb);
+
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_POSTOP, cb->pluginDN,
+ LDAP_SCOPE_SUBTREE, CB_CONFIG_INSTANCE_FILTER, cb_config_add_instance_callback, (void *) cb);
+
+ return 0;
+}
+
+/* Check validity of the modification */
+
+int cb_config_add_check_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2, int *returncode,
+ char *returntext, void *arg)
+{
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ struct berval * bval;
+ int i;
+ cb_backend *cb = (cb_backend *) arg;
+
+ CB_ASSERT (cb!=NULL);
+
+ for (slapi_entry_first_attr(e, &attr); attr; slapi_entry_next_attr(e, attr, &attr)) {
+ char * attr_name=NULL;
+ slapi_attr_get_type(attr, &attr_name);
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_FORWARD_CTRLS )) {
+ /* First, parse the values to make sure they are valid */
+ i = slapi_attr_first_value(attr, &sval);
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ if (!cb_is_control_forwardable(cb,bval->bv_val)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,CB_PLUGIN_SUBSYSTEM,
+ "control %s can't be forwarded.\n",bval->bv_val);
+ *returncode=LDAP_CONSTRAINT_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ }
+ }
+ *returncode=LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/*
+** Global config is beeing added
+** Take the new values into account
+*/
+
+int
+cb_config_add_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2, int *returncode,
+ char *returntext, void *arg)
+{
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ struct berval * bval;
+ int i;
+ cb_backend *cb = (cb_backend *) arg;
+
+ CB_ASSERT (cb!=NULL);
+
+ for (slapi_entry_first_attr(e, &attr); attr; slapi_entry_next_attr(e, attr, &attr)) {
+ char * attr_name=NULL;
+ slapi_attr_get_type(attr, &attr_name);
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_FORWARD_CTRLS )) {
+ /* First, parse the values to make sure they are valid */
+ i = slapi_attr_first_value(attr, &sval);
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ if (!cb_is_control_forwardable(cb,bval->bv_val)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,CB_PLUGIN_SUBSYSTEM,
+ "control %s can't be forwarded.\n",bval->bv_val);
+ *returncode=LDAP_CONSTRAINT_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ /* second pass. apply changes */
+ cb_unregister_all_supported_control(cb);
+ i = slapi_attr_first_value(attr, &sval);
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ cb_register_supported_control(cb,bval->bv_val,0);
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ }
+ }
+ *returncode=LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+int
+cb_config_search_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2, int *returncode,
+ char *returntext, void *arg) {
+
+ cb_backend *cb = (cb_backend *) arg;
+ struct berval val;
+ struct berval *vals[2];
+ int i = 0;
+
+ CB_ASSERT (cb!=NULL);
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* naming attribute */
+ val.bv_val = "config";
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "cn", (struct berval **)vals );
+
+ /* objectclass attribute */
+ val.bv_val = "top";
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "objectclass", (struct berval **)vals );
+ val.bv_val = CB_CONFIG_EXTENSIBLEOCL;
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_merge( e, "objectclass", (struct berval **)vals );
+
+ /* other attributes */
+
+ PR_RWLock_Rlock(cb->config.rwl_config_lock);
+
+ for (i=0; cb->config.forward_ctrls && cb->config.forward_ctrls[i] ; i++) {
+ val.bv_val=cb->config.forward_ctrls[i];
+ val.bv_len = strlen( val.bv_val );
+ if (i==0)
+ slapi_entry_attr_replace( e, CB_CONFIG_GLOBAL_FORWARD_CTRLS, (struct berval **)vals );
+ else
+ slapi_entry_attr_merge( e, CB_CONFIG_GLOBAL_FORWARD_CTRLS, (struct berval **)vals );
+ }
+
+ for (i=0;cb->config.chaining_components && cb->config.chaining_components[i];i++) {
+ val.bv_val=cb->config.chaining_components[i];
+ val.bv_len = strlen( val.bv_val );
+ if (i==0)
+ slapi_entry_attr_replace( e, CB_CONFIG_GLOBAL_CHAINING_COMPONENTS,
+ (struct berval **)vals );
+ else
+ slapi_entry_attr_merge( e, CB_CONFIG_GLOBAL_CHAINING_COMPONENTS,
+ (struct berval **)vals );
+ }
+
+ for (i=0; cb->config.chainable_components && cb->config.chainable_components[i]; i++) {
+ val.bv_val=cb->config.chainable_components[i];
+ val.bv_len = strlen( val.bv_val );
+ if (i==0)
+ slapi_entry_attr_replace( e, CB_CONFIG_GLOBAL_CHAINABLE_COMPONENTS,
+ (struct berval **)vals );
+ else
+ slapi_entry_attr_merge( e, CB_CONFIG_GLOBAL_CHAINABLE_COMPONENTS,
+ (struct berval **)vals );
+ }
+
+
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* Check validity of the modification */
+
+int
+cb_config_modify_check_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode,
+ char *returntext, void *arg)
+{
+ LDAPMod **mods;
+ char *attr_name;
+ int i,j;
+ cb_backend *cb = (cb_backend *) arg;
+
+ CB_ASSERT (cb!=NULL);
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ for (i = 0; mods[i] ; i++) {
+ attr_name = mods[i]->mod_type;
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_FORWARD_CTRLS )) {
+ char * config_attr_value;
+ for (j = 0; mods[i]->mod_bvalues && mods[i]->mod_bvalues[j]; j++) {
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+ if (!cb_is_control_forwardable(cb,config_attr_value)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,CB_PLUGIN_SUBSYSTEM,
+ "control %s can't be forwarded.\n",config_attr_value);
+ *returncode=LDAP_CONSTRAINT_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ }
+ }
+ *returncode=LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+int
+cb_config_modify_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode,
+ char *returntext, void *arg)
+{
+ LDAPMod **mods;
+ char *attr_name;
+ int i,j;
+ cb_backend *cb = (cb_backend *) arg;
+
+ CB_ASSERT (cb!=NULL);
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ for (i = 0; mods[i] ; i++) {
+ attr_name = mods[i]->mod_type;
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_FORWARD_CTRLS )) {
+ char * config_attr_value;
+ int done=0;
+ for (j = 0; mods[i]->mod_bvalues && mods[i]->mod_bvalues[j]; j++) {
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+ if (!cb_is_control_forwardable(cb,config_attr_value)) {
+ slapi_log_error(SLAPI_LOG_PLUGIN,CB_PLUGIN_SUBSYSTEM,
+ "control %s can't be forwarded.\n",config_attr_value);
+ *returncode=LDAP_CONSTRAINT_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ if ( mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ if (!done) {
+ cb_unregister_all_supported_control(cb);
+ done=1;
+ }
+ cb_register_supported_control(cb,config_attr_value,0);
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ cb_register_supported_control(cb,config_attr_value,0);
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ cb_unregister_supported_control(cb,config_attr_value,0);
+ }
+ }
+ if (NULL == mods[i]->mod_bvalues)
+ cb_unregister_all_supported_control(cb);
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_DEBUG )) {
+ /* assume single-valued */
+ if (mods[i]->mod_op & LDAP_MOD_DELETE)
+ cb_set_debug(0);
+ else if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD)
+ cb_set_debug(1);
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_CHAINING_COMPONENTS )) {
+ char * config_attr_value;
+ int done=0;
+
+ PR_RWLock_Wlock(cb->config.rwl_config_lock);
+
+ for (j = 0; mods[i]->mod_bvalues && mods[i]->mod_bvalues[j]; j++) {
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+ if ( mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ if (!done) {
+ charray_free(cb->config.chaining_components);
+ cb->config.chaining_components=NULL;
+ done=1;
+ }
+ /* XXXSD assume dn. Normalize it */
+ charray_add(&cb->config.chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ charray_add(&cb->config.chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ charray_remove(cb->config.chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)));
+ }
+ }
+ if (NULL == mods[i]->mod_bvalues) {
+ charray_free(cb->config.chaining_components);
+ cb->config.chaining_components=NULL;
+ }
+
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_CHAINABLE_COMPONENTS )) {
+ char * config_attr_value;
+ int done=0;
+
+ PR_RWLock_Wlock(cb->config.rwl_config_lock);
+
+ for (j = 0; mods[i]->mod_bvalues && mods[i]->mod_bvalues[j]; j++) {
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+ if ( mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ if (!done) {
+ charray_free(cb->config.chainable_components);
+ cb->config.chainable_components=NULL;
+ done=1;
+ }
+ charray_add(&cb->config.chainable_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)
+));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ charray_add(&cb->config.chainable_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)
+));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ charray_remove(cb->config.chainable_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)
+));
+ }
+ }
+ if (NULL == mods[i]->mod_bvalues) {
+ charray_free(cb->config.chainable_components);
+ cb->config.chainable_components=NULL;
+ }
+
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+ }
+
+
+ }
+ *returncode=LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/*
+** Creation of a new backend instance
+*/
+
+int
+cb_config_add_instance_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode,
+ char *returntext, void *arg)
+{
+ cb_backend *cb=(cb_backend *)arg;
+ CB_ASSERT(cb!=NULL);
+ cb_instance_add_config_callback(pb,entryBefore,NULL,returncode,returntext,cb);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+int
+cb_config_add_instance_check_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode,
+ char *returntext, void *arg)
+{
+ cb_backend *cb=(cb_backend *)arg;
+ CB_ASSERT(cb!=NULL);
+ return cb_instance_add_config_check_callback(pb,entryBefore,NULL,returncode,returntext,cb);
+}
+
+/*
+** Parse the global chaining backend configuration
+*/
+
+static int cb_parse_config_entry(cb_backend * cb, Slapi_Entry *e)
+{
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ struct berval *bval;
+ int i;
+
+ if (e == NULL)
+ return LDAP_SUCCESS;
+
+ cb_set_debug(0);
+
+ for (slapi_entry_first_attr(e, &attr); attr; slapi_entry_next_attr(e, attr, &attr)) {
+ char * attr_name=NULL;
+ slapi_attr_get_type(attr, &attr_name);
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_FORWARD_CTRLS )) {
+ i = slapi_attr_first_value(attr, &sval);
+
+ PR_RWLock_Wlock(cb->config.rwl_config_lock);
+ if (cb->config.forward_ctrls) {
+ charray_free(cb->config.forward_ctrls);
+ cb->config.forward_ctrls=NULL;
+ }
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ /* For now, don't support operation type */
+ cb_register_supported_control(cb,bval->bv_val,
+ SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE |
+ SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE |
+ SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN);
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_CHAINING_COMPONENTS )) {
+ i = slapi_attr_first_value(attr, &sval);
+ PR_RWLock_Wlock(cb->config.rwl_config_lock);
+ if (cb->config.chaining_components) {
+ charray_free(cb->config.chaining_components);
+ cb->config.chaining_components=NULL;
+ }
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ /* XXXSD assume dn. Normalize it */
+ charray_add( &cb->config.chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(bval->bv_val)));
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_CHAINABLE_COMPONENTS )) {
+ i = slapi_attr_first_value(attr, &sval);
+ PR_RWLock_Wlock(cb->config.rwl_config_lock);
+ if (cb->config.chainable_components) {
+ charray_free(cb->config.chainable_components);
+ cb->config.chainable_components=NULL;
+ }
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ charray_add( &cb->config.chainable_components,
+ slapi_dn_normalize(slapi_ch_strdup(bval->bv_val)));
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_GLOBAL_DEBUG )) {
+ i = slapi_attr_first_value(attr, &sval);
+ if (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ /* any value */
+ cb_set_debug(1);
+ }
+ }
+ }
+ return LDAP_SUCCESS;
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_conn_stateless.c b/ldap/servers/plugins/chainingdb/cb_conn_stateless.c
new file mode 100644
index 00000000..d97f947e
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_conn_stateless.c
@@ -0,0 +1,1132 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+ * Most of the complicated connection-related code lives in this file. Some
+ * general notes about how we manage our connections to "remote" LDAP servers:
+ *
+ * 1) Each farm server we have a relationship with is managed independently.
+ *
+ * 2) We may simultaneously issue multiple requests on a single LDAP
+ * connection. Each server has a "maxconcurrency" configuration
+ * parameter associated with it that caps the number of outstanding operations
+ * per connection. For each connection we maintain a "usecount"
+ * which is used to track the number of threads using the connection.
+ *
+ * 3) IMPORTANT NOTE: This connexion management is stateless i.e there is no garanty that
+ * operation from the same incoming client connections are sent to the same
+ * outgoing connection to the farm server. Today, this is not a problem because
+ * all controls we support are stateless. The implementation of the abandon
+ * operation takes this limitation into account.
+ *
+ * 4) We may open more than one connection to a server. Each farm server
+ * has a "maxconnections" configuration parameter associated with it
+ * that caps the number of connections.
+ *
+ * 5) If no connection is available to service a request , threads
+ * go to sleep on a condition variable and one is woken up each time
+ * a connection's "usecount" is decremented.
+ *
+ * 6) If we see an LDAP_CONNECT_ERROR or LDAP_SERVER_DOWN error on a
+ * session handle, we mark its status as CB_LDAP_STATUS_DOWN and
+ * close it as soon as all threads using it release it. Connections
+ * marked as "down" are not counted against the "maxconnections" limit.
+ *
+ * 7) We close and reopen connections that have been open for more than
+ * the server's configured connection lifetime. This is done to ensure
+ * that we reconnect to a primary server after failover occurs. If no
+ * lifetime is configured or it is set to 0, we never close and reopen
+ * connections.
+ */
+
+static void cb_close_and_dispose_connection ( cb_outgoing_conn * conn );
+static void cb_check_for_stale_connections(cb_conn_pool * pool);
+
+PRUint32 PR_GetThreadID(PRThread *thread);
+
+/* returns the threadId of the current thread modulo MAX_CONN_ARRAY
+=> gives the position of the thread in the array of secure connections */
+static int PR_ThreadSelf() {
+ PRThread *thr = PR_GetCurrentThread();
+ PRUint32 myself = PR_GetThreadID(thr);
+ myself &= 0x000007FF ;
+ return myself;
+}
+
+static int PR_MyThreadId() {
+ PRThread *thr = PR_GetCurrentThread();
+ PRUint32 myself = PR_GetThreadID(thr);
+ return myself;
+}
+
+/*
+** Close outgoing connections
+*/
+
+void cb_close_conn_pool(cb_conn_pool * pool) {
+
+ cb_outgoing_conn *conn, *nextconn;
+ int secure = pool->secure;
+ int i = 0;
+
+ slapi_lock_mutex( pool->conn.conn_list_mutex );
+
+ if (secure) {
+ for (i=0; i< MAX_CONN_ARRAY; i++) {
+ for (conn = pool->connarray[i]; conn != NULL; conn = nextconn) {
+ if ( conn->status != CB_CONNSTATUS_OK ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_close_conn_pool: unexpected connection state (%d)\n",conn->status);
+ }
+ nextconn=conn->next;
+ cb_close_and_dispose_connection(conn);
+ }
+ }
+ }
+ else {
+ for ( conn = pool->conn.conn_list; conn != NULL; conn = nextconn ) {
+ if ( conn->status != CB_CONNSTATUS_OK ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_close_conn_pool: unexpected connection state (%d)\n",conn->status);
+ }
+ nextconn=conn->next;
+ cb_close_and_dispose_connection(conn);
+ }
+ }
+
+ pool->conn.conn_list=NULL;
+ pool->conn.conn_list_count=0;
+
+ slapi_unlock_mutex( pool->conn.conn_list_mutex );
+}
+
+/*
+ * Get an LDAP session handle for communicating with the farm servers.
+ *
+ * Returns an LDAP eror code, typically:
+ * LDAP_SUCCESS
+ * LDAP_TIMELIMIT_EXCEEDED
+ * LDAP_CONNECT_ERROR
+ * NOTE : if maxtime NULL, use operation timeout
+ */
+
+int cb_get_connection(cb_conn_pool * pool, LDAP ** lld, cb_outgoing_conn ** cc,struct timeval * maxtime, char **errmsg) {
+
+ int rc=LDAP_SUCCESS; /* optimistic */
+ cb_outgoing_conn *conn=NULL;
+ cb_outgoing_conn *connprev=NULL;
+ LDAP *ld=NULL;
+ time_t endbefore=0;
+ int checktime=0;
+ struct timeval bind_to, op_to;
+ unsigned int maxconcurrency,maxconnections;
+ char *password,*binddn,*hostname;
+ unsigned int port;
+ int secure;
+ static char *error1="Can't contact remote server : %s";
+ static char *error2="Can't bind to remote server : %s";
+ int isMultiThread = ENABLE_MULTITHREAD_PER_CONN ; /* by default, we enable multiple operations per connection */
+
+ /*
+ ** return an error if we can't get a connection
+ ** before the operation timeout has expired
+ ** bind_timeout: timeout for the bind operation (if bind needed)
+ ** ( checked in ldap_result )
+ ** op_timeout: timeout for the op that needs a connection
+ ** ( checked in the loop )
+ */
+ *cc=NULL;
+
+ PR_RWLock_Rlock(pool->rwl_config_lock);
+ maxconcurrency=pool->conn.maxconcurrency;
+ maxconnections=pool->conn.maxconnections;
+ bind_to.tv_sec = pool->conn.bind_timeout.tv_sec;
+ bind_to.tv_usec = pool->conn.bind_timeout.tv_usec;
+ op_to.tv_sec = pool->conn.op_timeout.tv_sec;
+ op_to.tv_usec = pool->conn.op_timeout.tv_usec;
+
+ /* SD 02/10/2000 temp fix */
+ /* allow dynamic update of the binddn & password */
+ /* host, port and security mode */
+ /* previous values are NOT freed when changed */
+ /* won't likely to be changed often */
+ /* pointers put in the waste basket fields and */
+ /* freed when the backend is stopped. */
+
+ password=pool->password;
+ binddn=pool->binddn;
+ hostname=pool->hostname;
+ port=pool->port;
+ secure=pool->secure;
+
+ PR_RWLock_Unlock(pool->rwl_config_lock);
+
+ if (secure) {
+ isMultiThread = DISABLE_MULTITHREAD_PER_CONN ;
+ }
+
+ /* For stupid admins */
+ if (maxconnections <=0) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "<== cb_get_connection error (no connection available)\n");
+ if ( errmsg ) {
+ *errmsg = slapi_ch_malloc(CB_BUFSIZE);
+ sprintf(*errmsg,error1,"no connection available");
+ }
+ return LDAP_CONNECT_ERROR;
+ }
+
+ if (maxtime) {
+ if (maxtime->tv_sec != 0) {
+ checktime=1;
+ endbefore = current_time() + maxtime->tv_sec;
+
+ /* make sure bind to <= operation timeout */
+ if ((bind_to.tv_sec==0) || (bind_to.tv_sec > maxtime->tv_sec))
+ bind_to.tv_sec=maxtime->tv_sec;
+ }
+ } else {
+ if (op_to.tv_sec != 0) {
+ checktime=1;
+ endbefore = current_time() + op_to.tv_sec;
+
+ /* make sure bind to <= operation timeout */
+ if ((bind_to.tv_sec==0) || (bind_to.tv_sec > op_to.tv_sec))
+ bind_to.tv_sec=op_to.tv_sec;
+ }
+ }
+
+ /*
+ * Close (or mark to be closed) any connections for this farm server that have
+ * exceeded the maximum connection lifetime.
+ */
+
+ cb_check_for_stale_connections(pool);
+
+ /*
+ * Look for an available, already open connection
+ */
+
+ slapi_lock_mutex( pool->conn.conn_list_mutex );
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "==> cb_get_connection server %s conns: %d maxconns: %d\n",
+ hostname, pool->conn.conn_list_count, maxconnections );
+ }
+
+ for (;;) {
+
+ /* time limit mgmt */
+ if (checktime) {
+ if (current_time() > endbefore ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_get_connection server %s expired.\n", hostname );
+ if ( errmsg ) {
+ *errmsg = slapi_ch_malloc(CB_BUFSIZE);
+ sprintf(*errmsg,error1,"timelimit exceeded");
+ }
+ rc=LDAP_TIMELIMIT_EXCEEDED;
+ conn=NULL;
+ ld=NULL;
+ goto unlock_and_return;
+ }
+ }
+
+ /*
+ * First, look for an available, already open/bound connection
+ */
+
+ if (secure) {
+ for (conn = pool->connarray[PR_ThreadSelf()]; conn != NULL; conn = conn->next) {
+ if ((conn->ThreadId == PR_MyThreadId()) && (conn->status == CB_CONNSTATUS_OK &&
+ conn->refcount < maxconcurrency)){
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "<= cb_get_connection server found conn 0x%x to use)\n", conn );
+ }
+ goto unlock_and_return; /* found one */
+ }
+ }
+ }
+ else {
+ connprev = NULL;
+ for ( conn = pool->conn.conn_list; conn != NULL; conn = conn->next ) {
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "list: conn 0x%x status %d refcount %d\n", conn,
+ conn->status, conn->refcount );
+ }
+
+ if ( conn->status == CB_CONNSTATUS_OK
+ && conn->refcount < maxconcurrency ) {
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "<= cb_get_connection server found conn 0x%x to use)\n", conn );
+ }
+ goto unlock_and_return; /* found one */
+ }
+ connprev = conn;
+ }
+ }
+
+ if ( secure || pool->conn.conn_list_count <maxconnections) {
+
+ int version=LDAP_VERSION3;
+
+ /* check wether the security libraries are correctly initialized */
+ if (secure && slapd_security_library_is_initialized() != 1) {
+ slapi_log_error(
+ SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "SSL Not Initialized, Chaining Backend over SSL FAILED\n");
+ rc = LDAP_CONNECT_ERROR;
+ goto unlock_and_return;
+ }
+
+ /*
+ * we have not exceeded the maximum number of connections allowed,
+ * so we initialize a new one and add it to the end of our list.
+ */
+
+ /* No need to lock. url can't be changed dynamically */
+ if ((ld=slapi_ldap_init(hostname,port,secure,isMultiThread))== NULL) {
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Can't contact server <%s> port <%d>.\n", hostname, port);
+ }
+ if ( errmsg ) {
+ *errmsg = slapi_ch_malloc(CB_BUFSIZE);
+ sprintf(*errmsg,error1,"unknown reason");
+ }
+ rc = LDAP_CONNECT_ERROR;
+ goto unlock_and_return;
+ }
+
+ ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
+ /* Don't chase referrals */
+ ldap_set_option( ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF );
+
+ /* no controls and simple bind only */
+ /* For now, bind even if no user to detect error */
+ /* earlier */
+ if (pool->bindit) {
+ int msgid;
+ LDAPMessage *res=NULL;
+ int parse_rc;
+ PRErrorCode prerr = 0;
+ LDAPControl **serverctrls=NULL;
+ char **referrals=NULL;
+
+ char *plain = NULL;
+ int ret = -1;
+
+ rc=LDAP_SUCCESS;
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Bind to to server <%s> port <%d> as <%s>\n",
+ hostname, port, binddn);
+ }
+
+ ret = pw_rever_decode(password, &plain, CB_CONFIG_USERPASSWORD);
+
+ /* Pb occured in decryption: stop now, binding will fail */
+ if ( ret == -1 )
+ {
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Internal credentials decoding error\n.",
+ 0, 0, 0);
+ }
+ rc = LDAP_LOCAL_ERROR;
+ goto unlock_and_return;
+ }
+
+ /* Password-based client authentication */
+
+ if (( msgid = ldap_simple_bind( ld, binddn, plain)) <0) {
+ rc=ldap_get_lderrno( ld, NULL, NULL );
+ prerr=PR_GetError();
+ }
+ if ( ret == 0 ) free(plain); /* free plain only if it has been duplicated */
+
+ if ( rc != LDAP_SUCCESS ) {
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Can't bind to server <%s> port <%d>. "
+ "(LDAP error %d - %s; "
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)\n",
+ hostname, port, rc,
+ ldap_err2string(rc),
+ prerr, slapd_pr_strerror(prerr));
+ }
+ if ( errmsg ) {
+ *errmsg = slapi_ch_malloc(CB_BUFSIZE);
+ sprintf(*errmsg,error2, ldap_err2string(rc));
+ }
+ rc = LDAP_CONNECT_ERROR;
+ goto unlock_and_return;
+ }
+
+ rc = ldap_result( ld, msgid, 0, &bind_to, &res );
+ switch (rc) {
+ case -1:
+ rc = ldap_get_lderrno( ld, NULL, NULL );
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Can't bind to server <%s> port <%d>. "
+ "(LDAP error %d - %s; "
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)\n",
+ hostname, port, rc,
+ ldap_err2string(rc),
+ prerr, slapd_pr_strerror(prerr));
+ }
+ if ( errmsg ) {
+ *errmsg = slapi_ch_malloc(CB_BUFSIZE);
+ sprintf(*errmsg,error2,ldap_err2string(rc));
+ }
+ rc = LDAP_CONNECT_ERROR;
+ goto unlock_and_return;
+ case 0:
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Can't bind to server <%s> port <%d>. (%s)\n",
+ hostname, port, "time-out expired");
+ }
+ rc = LDAP_CONNECT_ERROR;
+ goto unlock_and_return;
+ default:
+
+ parse_rc = ldap_parse_result( ld, res, &rc, NULL,
+ NULL, &referrals, &serverctrls, 1 );
+
+ if ( parse_rc != LDAP_SUCCESS ) {
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Can't bind to server <%s> port <%d>. (%s)\n",
+ hostname, port, ldap_err2string(parse_rc));
+ }
+ if ( errmsg ) {
+ *errmsg = slapi_ch_malloc(CB_BUFSIZE);
+ sprintf(*errmsg,error2,ldap_err2string(parse_rc));
+ }
+ rc = parse_rc;
+ goto unlock_and_return;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Can't bind to server <%s> port <%d>. (%s)\n",
+ hostname, port, ldap_err2string(rc));
+ }
+ if ( errmsg ) {
+ *errmsg = slapi_ch_malloc(CB_BUFSIZE);
+ sprintf(*errmsg,error2, ldap_err2string(rc));
+ }
+ goto unlock_and_return;
+ }
+
+ if ( serverctrls )
+ {
+ int i;
+ for( i = 0; serverctrls[ i ] != NULL; ++i )
+ {
+ if ( !(strcmp( serverctrls[ i ]->ldctl_oid, LDAP_CONTROL_PWEXPIRED)) )
+ {
+ /* Bind is successful but password has expired */
+ slapi_log_error(SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "Succesfully bound as %s to remote server %s:%d, "
+ "but password has expired.\n",
+ binddn, hostname, port);
+ }
+ else if ( !(strcmp( serverctrls[ i ]->ldctl_oid, LDAP_CONTROL_PWEXPIRING)) )
+ {
+ /* The password is expiring in n seconds */
+ if ( (serverctrls[ i ]->ldctl_value.bv_val != NULL) &&
+ (serverctrls[ i ]->ldctl_value.bv_len > 0) )
+ {
+ int password_expiring = atoi( serverctrls[ i ]->ldctl_value.bv_val );
+ slapi_log_error(SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "Succesfully bound as %s to remote server %s:%d, "
+ "but password is expiring in %d seconds.\n",
+ binddn, hostname, port, password_expiring);
+ }
+ }
+ }
+ ldap_controls_free(serverctrls);
+ }
+
+ if (referrals)
+ charray_free(referrals);
+ }
+ }
+
+ conn = (cb_outgoing_conn *) slapi_ch_malloc(sizeof(cb_outgoing_conn));
+ conn->ld=ld;
+ conn->status=CB_CONNSTATUS_OK;
+ conn->refcount=0; /* incremented below */
+ conn->opentime=current_time();
+ conn->ThreadId=PR_MyThreadId(); /* store the thread id */
+ conn->next=NULL;
+ if (secure) {
+ if (pool->connarray[PR_ThreadSelf()] == NULL) {
+ pool->connarray[PR_ThreadSelf()] = conn;
+ }
+ else {
+ conn->next = pool->connarray[PR_ThreadSelf()];
+ pool->connarray[PR_ThreadSelf()] = conn ;
+ }
+ }
+ else {
+ if ( NULL == connprev ) {
+ pool->conn.conn_list = conn;
+ } else {
+ connprev->next=conn;
+ }
+ }
+
+ ++pool->conn.conn_list_count;
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "<= cb_get_connection added new conn 0x%x, "
+ "conn count now %d\n", conn->ld, pool->conn.conn_list_count );
+ }
+ goto unlock_and_return; /* got a new one */
+ }
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "... cb_get_connection waiting for conn to free up\n" );
+ }
+
+ if (!secure) slapi_wait_condvar( pool->conn.conn_list_cv, NULL );
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "... cb_get_connection awake again\n" );
+ }
+ }
+
+unlock_and_return:
+ if ( conn != NULL ) {
+ ++conn->refcount;
+ *lld=conn->ld;
+ *cc=conn;
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "<== cb_get_connection ld=0x%x (concurrency now %d)\n",*lld, conn->refcount );
+ }
+
+ } else {
+ if ( NULL != ld ) {
+ slapi_ldap_unbind( ld );
+ }
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "<== cb_get_connection error %d\n", rc );
+ }
+ }
+
+ slapi_unlock_mutex(pool->conn.conn_list_mutex);
+ return( rc );
+}
+
+/*
+ * We are done with the connection handle because the
+ * LDAP operation has completed.
+ */
+
+void cb_release_op_connection(cb_conn_pool* pool, LDAP *lld, int dispose) {
+
+ cb_outgoing_conn *conn;
+ cb_outgoing_conn *connprev = NULL;
+ int secure = pool->secure;
+ int myself = 0;
+
+ slapi_lock_mutex(pool->conn.conn_list_mutex);
+ /*
+ * find the connection structure this ld is part of
+ */
+
+ if (secure) {
+ myself = PR_ThreadSelf();
+ for (conn = pool->connarray[myself]; conn != NULL; conn = conn->next ) {
+ if ( lld == conn->ld )
+ break;
+ connprev = conn;
+ }
+ }
+ else {
+ for ( conn = pool->conn.conn_list; conn != NULL; conn = conn->next ){
+ if ( lld == conn->ld )
+ break;
+ connprev = conn;
+ }
+ }
+
+ if ( conn == NULL ) { /* ld not found -- unexpected */
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "==> cb_release_op_connection ld=0x%x not found\n", lld );
+ } else {
+
+ --conn->refcount;
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "release conn 0x%x status %d refcount after release %d\n", conn,
+ conn->status, conn->refcount );
+ }
+
+ if ( dispose ) {
+ conn->status = CB_CONNSTATUS_DOWN;
+ }
+
+ if ( conn->status != CB_CONNSTATUS_OK && conn->refcount == 0 ) {
+
+ /*
+ * remove from server's connection list
+ */
+
+ if (!secure) {
+ if ( connprev == NULL ) {
+ pool->conn.conn_list = conn->next;
+ } else {
+ connprev->next = conn->next;
+ }
+ }
+ else {
+ if ( connprev == NULL ) {
+ pool->connarray[myself] = conn->next;
+ } else {
+ connprev->next = conn->next;
+ }
+ }
+
+ --pool->conn.conn_list_count;
+
+ /*
+ * close connection and free memory
+ */
+ cb_close_and_dispose_connection( conn );
+ }
+ }
+
+ /*
+ * wake up a thread that is waiting for a connection
+ */
+
+ if (!secure) slapi_notify_condvar( pool->conn.conn_list_cv, 0 );
+
+ slapi_unlock_mutex( pool->conn.conn_list_mutex );
+}
+
+
+static void
+cb_close_and_dispose_connection( cb_outgoing_conn *conn )
+{
+ slapi_ldap_unbind( conn->ld );
+ conn->ld = NULL;
+ slapi_ch_free( (void **)&conn );
+}
+
+static void cb_check_for_stale_connections(cb_conn_pool * pool) {
+
+ cb_outgoing_conn * connprev, *conn, *conn_next;
+ time_t curtime;
+ int connlifetime;
+ int myself;
+
+ PR_RWLock_Rlock(pool->rwl_config_lock);
+ connlifetime=pool->conn.connlifetime;
+ PR_RWLock_Unlock(pool->rwl_config_lock);
+
+ connprev = NULL;
+ conn_next = NULL;
+
+ slapi_lock_mutex(pool->conn.conn_list_mutex);
+
+ if (connlifetime > 0)
+ curtime=current_time();
+
+ if (pool->secure) {
+ myself = PR_ThreadSelf();
+ for (conn = pool->connarray[myself]; conn != NULL; conn = conn_next){
+ if ((conn->status == CB_CONNSTATUS_STALE) ||
+ (( connlifetime > 0) && (curtime - conn->opentime > connlifetime))) {
+ if ( conn->refcount == 0 ) {
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_check_for_stale_connections: conn 0x%x idle and stale\n",conn);
+ }
+ --pool->conn.conn_list_count;
+ if (connprev == NULL) {
+ pool->connarray[myself] = conn->next ;
+ }
+ else {
+ connprev->next = conn->next ;
+ }
+ conn_next = conn->next ;
+ cb_close_and_dispose_connection( conn );
+ continue;
+ }
+ /* Connection is stale but in use */
+ /* Mark to be disposed later but let it in the backend list */
+ /* so that it is counted as a valid connection */
+ else {
+ conn->status = CB_CONNSTATUS_STALE;
+ }
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_check_for_stale_connections: conn 0x%x stale\n",conn);
+ }
+ }
+ connprev = conn ;
+ conn_next = conn->next;
+ }
+ slapi_unlock_mutex(pool->conn.conn_list_mutex);
+ return;
+ }
+
+ for ( conn = pool->conn.conn_list; conn != NULL; conn=conn_next ) {
+ if ((conn->status == CB_CONNSTATUS_STALE) ||
+ (( connlifetime > 0) && (curtime - conn->opentime > connlifetime))) {
+ if ( conn->refcount == 0 ) {
+
+ /* Connection idle & stale. Remove and free. */
+
+ if ( NULL == connprev )
+ pool->conn.conn_list = conn->next;
+ else
+ connprev->next=conn->next;
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_check_for_stale_connections: conn 0x%x idle and stale\n",conn);
+ }
+ --pool->conn.conn_list_count;
+ conn_next=conn->next;
+ cb_close_and_dispose_connection( conn );
+ continue;
+ }
+
+ /* Connection is stale but in use */
+ /* Mark to be disposed later but let it in the backend list */
+ /* so that it is counted as a valid connection */
+ else {
+ conn->status = CB_CONNSTATUS_STALE;
+ }
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_check_for_stale_connections: conn 0x%x stale\n",conn);
+ }
+ }
+ connprev = conn;
+ conn_next=conn->next;
+ }
+
+ /* Generate an event to wake up threads waiting */
+ /* for a conn to be released. Useful to detect */
+ /* exceeded time limit. May be expensive */
+
+ slapi_notify_condvar( pool->conn.conn_list_cv, 0 );
+
+ slapi_unlock_mutex(pool->conn.conn_list_mutex);
+}
+
+/*
+ * close all open connections in preparation for server shutdown, etc.
+ * WARNING: Don't wait for current operations to complete
+ */
+
+void
+cb_close_all_connections( Slapi_Backend * be )
+{
+
+ cb_outgoing_conn *conn, *next_conn;
+ cb_backend_instance * cb= cb_get_instance(be);
+ int i;
+
+ slapi_lock_mutex(cb->pool->conn.conn_list_mutex);
+ if (cb->pool->secure) {
+ for (i=0; i< MAX_CONN_ARRAY; i++) {
+ for (conn = cb->pool->connarray[i]; conn != NULL; conn = next_conn ){
+ next_conn = conn->next;
+ cb_close_and_dispose_connection(conn);
+ }
+ }
+ } else {
+ for ( conn = cb->pool->conn.conn_list; conn != NULL; conn = next_conn ) {
+ next_conn=conn->next;
+ cb_close_and_dispose_connection(conn);
+ }
+ }
+ slapi_unlock_mutex(cb->pool->conn.conn_list_mutex);
+
+ slapi_lock_mutex(cb->bind_pool->conn.conn_list_mutex);
+ if (cb->bind_pool->secure) {
+ for (i=0; i< MAX_CONN_ARRAY; i++) {
+ for (conn = cb->bind_pool->connarray[i]; conn != NULL; conn = next_conn ){
+ next_conn=conn->next;
+ cb_close_and_dispose_connection(conn);
+ }
+ }
+ } else {
+ for ( conn = cb->bind_pool->conn.conn_list; conn != NULL; conn = next_conn ) {
+ next_conn=conn->next;
+ cb_close_and_dispose_connection(conn);
+ }
+ }
+ slapi_unlock_mutex(cb->bind_pool->conn.conn_list_mutex);
+}
+
+/* Mark used connections as stale and close unsued connections */
+/* Called when the target farm url has changed */
+
+void cb_stale_all_connections( cb_backend_instance * cb)
+{
+ cb_outgoing_conn *conn, *next_conn, *prev_conn;
+ int notify=0;
+ int i, j;
+ cb_conn_pool *pools[3];
+
+ pools[0]=cb->pool;
+ pools[1]=cb->bind_pool;
+ pools[2]=NULL;
+
+ for (i=0; pools[i]; i++) {
+ slapi_lock_mutex(pools[i]->conn.conn_list_mutex);
+ for (j=0; j< MAX_CONN_ARRAY; j++) {
+ prev_conn=NULL;
+ for (conn = pools[i]->connarray[j]; conn != NULL; conn=next_conn) {
+ next_conn=conn->next;
+ if (conn->refcount > 0) {
+ /*
+ ** Connection is stale but in use
+ ** Mark to be disposed later but let it in the backend list
+ ** so that it is counted as a valid connection
+ */
+ conn->status = CB_CONNSTATUS_STALE;
+ prev_conn=conn;
+ } else {
+ if (prev_conn == NULL) {
+ pools[i]->connarray[j]=next_conn;
+ } else {
+ prev_conn->next=next_conn;
+ }
+ cb_close_and_dispose_connection(conn);
+ pools[i]->conn.conn_list_count--;
+ }
+ }
+ }
+ prev_conn = NULL ;
+ for ( conn = pools[i]->conn.conn_list; conn != NULL; conn = next_conn ) {
+ next_conn=conn->next;
+ if (conn->refcount > 0) {
+ /*
+ ** Connection is stale but in use
+ ** Mark to be disposed later but let it in the backend list
+ ** so that it is counted as a valid connection
+ */
+ conn->status = CB_CONNSTATUS_STALE;
+ prev_conn=conn;
+ }
+ else {
+ if (conn==pools[i]->conn.conn_list) {
+ pools[i]->conn.conn_list=next_conn;
+ } else {
+ prev_conn->next=next_conn;
+ }
+ cb_close_and_dispose_connection(conn);
+ pools[i]->conn.conn_list_count--;
+ notify=1;
+ }
+ }
+ if (notify && (! pools[i]->secure)) {
+ slapi_notify_condvar( pools[i]->conn.conn_list_cv, 0 );
+ }
+ slapi_unlock_mutex(pools[i]->conn.conn_list_mutex);
+ }
+}
+
+
+
+/**************************************************************************/
+/* Need to use our own connect function until we've switched to C-SDK 4.1 */
+/* to have a timeout in the connect system call. */
+/**************************************************************************/
+
+static int global_connect_to;
+
+#if 0
+
+/* Taken from C-SDK 4.1 */
+#include <fcntl.h>
+#include <errno.h>
+#define LDAP_X_IO_TIMEOUT_NO_TIMEOUT (-1)
+
+static int
+nsldapi_os_connect_with_to(LBER_SOCKET sockfd, struct sockaddr *saptr,
+ int salen)
+{
+#ifndef _WIN32
+ int flags;
+#endif /* _WIN32 */
+ int n, error;
+ int len;
+ fd_set rset, wset;
+ struct timeval tval;
+#ifdef _WIN32
+ int nonblock = 1;
+ int block = 0;
+ fd_set eset;
+#endif /* _WIN32 */
+
+ int msec=global_connect_to; /* global */
+
+#ifdef _WIN32
+ ioctlsocket(sockfd, FIONBIO, &nonblock);
+#else
+ flags = fcntl(sockfd, F_GETFL, 0);
+ fcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+#endif /* _WIN32 */
+
+ error = 0;
+ if ((n = connect(sockfd, saptr, salen)) < 0)
+#ifdef _WIN32
+ if ((n != SOCKET_ERROR) && (WSAGetLastError() != WSAEWOULDBLOCK)) {
+#else
+ if (errno != EINPROGRESS) {
+#endif /* _WIN32 */
+ return (-1);
+ }
+
+ /* success */
+ if (n == 0)
+ goto done;
+
+ FD_ZERO(&rset);
+ FD_SET(sockfd, &rset);
+ wset = rset;
+
+#ifdef _WIN32
+ eset = rset;
+#endif /* _WIN32 */
+
+ if (msec < 0 && msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) {
+ msec = LDAP_X_IO_TIMEOUT_NO_TIMEOUT;
+ } else {
+ if (msec != 0)
+ tval.tv_sec = msec / 1000;
+ else
+ tval.tv_sec = 0;
+ tval.tv_usec = 0;
+ }
+
+ /* if timeval structure == NULL, select will block indefinitely */
+ /* != NULL, and value == 0, select will */
+ /* not block */
+ /* Windows is a bit quirky on how it behaves w.r.t nonblocking */
+ /* connects. If the connect fails, the exception fd, eset, is */
+ /* set to show the failure. The first argument in select is */
+ /* ignored */
+
+#ifdef _WIN32
+ if ((n = select(sockfd +1, &rset, &wset, &eset,
+ (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
+ errno = WSAETIMEDOUT;
+ return (-1);
+ }
+ /* if wset is set, the connect worked */
+ if (FD_ISSET(sockfd, &wset) || FD_ISSET(sockfd, &rset)) {
+ len = sizeof(error);
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
+ < 0)
+ return (-1);
+ goto done;
+ }
+
+ /* if eset is set, the connect failed */
+ if (FD_ISSET(sockfd, &eset)) {
+ return (-1);
+ }
+
+ /* failure on select call */
+ if (n == SOCKET_ERROR) {
+ return (-1);
+ }
+#else
+ if ((n = select(sockfd +1, &rset, &wset, NULL,
+ (msec != LDAP_X_IO_TIMEOUT_NO_TIMEOUT) ? &tval : NULL)) == 0) {
+ errno = ETIMEDOUT;
+ return (-1);
+ }
+ if (FD_ISSET(sockfd, &rset) || FD_ISSET(sockfd, &wset)) {
+ len = sizeof(error);
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (char *)&error, &len)
+ < 0)
+ return (-1);
+ }
+#endif /* _WIN32 */
+done:
+#ifdef _WIN32
+ ioctlsocket(sockfd, FIONBIO, &block);
+#else
+ fcntl(sockfd, F_SETFL, flags);
+#endif /* _WIN32 */
+
+ if (error) {
+ errno = error;
+ return (-1);
+ }
+
+ return (0);
+}
+
+#endif
+
+/* Try to figure out if a farm server is still alive */
+
+int cb_ping_farm(cb_backend_instance *cb, cb_outgoing_conn * cnx,time_t end_time) {
+
+ char *attrs[] ={"1.1",NULL};
+ int rc;
+ struct timeval timeout;
+ LDAP *ld;
+ LDAPMessage *result;
+#if 0
+ struct ldap_io_fns iof;
+#endif
+ time_t now;
+ if (cb->max_idle_time <=0) /* Heart-beat disabled */
+ return LDAP_SUCCESS;
+
+ if (cnx && (cnx->status != CB_CONNSTATUS_OK )) /* Known problem */
+ return LDAP_SERVER_DOWN;
+
+ now = current_time();
+ if (end_time && ((now <= end_time) || (end_time <0))) return LDAP_SUCCESS;
+
+ ld=slapi_ldap_init(cb->pool->hostname,cb->pool->port,cb->pool->secure,0);
+ if (NULL == ld) {
+ cb_update_failed_conn_cpt( cb );
+ return LDAP_SERVER_DOWN;
+ }
+
+#if 0
+ memset(&iof,0,sizeof(struct ldap_io_fns));
+ if (LDAP_SUCCESS !=ldap_get_option(ld,LDAP_OPT_IO_FN_PTRS,&iof)) {
+ slapi_ldap_unbind( ld );
+ cb_update_failed_conn_cpt( cb );
+ return LDAP_SERVER_DOWN;
+ }
+
+ iof.liof_connect = nsldapi_os_connect_with_to;
+ if (LDAP_SUCCESS !=ldap_set_option(ld,LDAP_OPT_IO_FN_PTRS,&iof)) {
+ slapi_ldap_unbind( ld );
+ cb_update_failed_conn_cpt( cb );
+ return LDAP_SERVER_DOWN;
+ }
+
+#endif
+
+ timeout.tv_sec=cb->max_test_time;
+ timeout.tv_usec=0;
+
+ global_connect_to=cb->max_test_time * 1000; /* Reuse the same for the connect */
+ rc=ldap_search_ext_s(ld ,NULL,LDAP_SCOPE_BASE,"objectclass=*",attrs,1,NULL,
+ NULL, &timeout, 1,&result);
+ if ( LDAP_SUCCESS != rc ) {
+ slapi_ldap_unbind( ld );
+ cb_update_failed_conn_cpt( cb );
+ return LDAP_SERVER_DOWN;
+ }
+
+ ldap_msgfree(result);
+ slapi_ldap_unbind( ld );
+ cb_reset_conn_cpt( cb );
+ return LDAP_SUCCESS;
+}
+
+
+
+void cb_update_failed_conn_cpt ( cb_backend_instance *cb ) {
+ /* if the chaining BE is already unavailable, we do nothing*/
+ time_t now;
+ if (cb->monitor_availability.farmserver_state == FARMSERVER_AVAILABLE) {
+ slapi_lock_mutex(cb->monitor_availability.cpt_lock);
+ cb->monitor_availability.cpt ++;
+ slapi_unlock_mutex(cb->monitor_availability.cpt_lock);
+ if (cb->monitor_availability.cpt >= CB_NUM_CONN_BEFORE_UNAVAILABILITY ) {
+ /* we reach the limit of authorized failed connections => we setup the chaining BE state to unavailable */
+ now = current_time();
+ slapi_lock_mutex(cb->monitor_availability.lock_timeLimit);
+ cb->monitor_availability.unavailableTimeLimit = now + CB_UNAVAILABLE_PERIOD ;
+ slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
+ cb->monitor_availability.farmserver_state = FARMSERVER_UNAVAILABLE ;
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_update_failed_conn_cpt: Farm server unavailable");
+ }
+
+ }
+}
+
+void cb_reset_conn_cpt( cb_backend_instance *cb ) {
+ if (cb->monitor_availability.cpt > 0) {
+ slapi_lock_mutex(cb->monitor_availability.cpt_lock);
+ cb->monitor_availability.cpt = 0 ;
+ if (cb->monitor_availability.farmserver_state == FARMSERVER_UNAVAILABLE) {
+ cb->monitor_availability.farmserver_state = FARMSERVER_AVAILABLE ;
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_reset_conn_cpt: Farm server is back");
+ }
+ slapi_unlock_mutex(cb->monitor_availability.cpt_lock);
+ }
+}
+
+int cb_check_availability( cb_backend_instance *cb, Slapi_PBlock *pb ) {
+ /* check wether the farmserver is available or not */
+ int rc ;
+ time_t now ;
+ if ( cb->monitor_availability.farmserver_state == FARMSERVER_UNAVAILABLE ){
+ slapi_lock_mutex(cb->monitor_availability.lock_timeLimit);
+ now = current_time();
+ if (now >= cb->monitor_availability.unavailableTimeLimit) {
+ cb->monitor_availability.unavailableTimeLimit = now + CB_INFINITE_TIME ; /* to be sure only one thread can do the test */
+ slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
+ }
+ else {
+ slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, "FARM SERVER TEMPORARY UNAVAILABLE", 0, NULL) ;
+ return FARMSERVER_UNAVAILABLE ;
+ }
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_check_availability: ping the farm server and check if it's still unavailable");
+ if ((rc = cb_ping_farm(cb, NULL, 0)) != LDAP_SUCCESS) { /* farm still unavailable... Just change the timelimit */
+ slapi_lock_mutex(cb->monitor_availability.lock_timeLimit);
+ now = current_time();
+ cb->monitor_availability.unavailableTimeLimit = now + CB_UNAVAILABLE_PERIOD ;
+ slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, "FARM SERVER TEMPORARY UNAVAILABLE", 0, NULL) ;
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_check_availability: Farm server still unavailable");
+ return FARMSERVER_UNAVAILABLE ;
+ }
+ else {
+ /* farm is back !*/
+ slapi_lock_mutex(cb->monitor_availability.lock_timeLimit);
+ now = current_time();
+ cb->monitor_availability.unavailableTimeLimit = now ; /* the unavailable period is finished */
+ slapi_unlock_mutex(cb->monitor_availability.lock_timeLimit);
+ /* The farmer server state backs to FARMSERVER_AVAILABLE, but this already done in cb_ping_farm, and also the reset of cpt*/
+ return FARMSERVER_AVAILABLE ;
+ }
+ }
+ return FARMSERVER_AVAILABLE ;
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_controls.c b/ldap/servers/plugins/chainingdb/cb_controls.c
new file mode 100644
index 00000000..ab612099
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_controls.c
@@ -0,0 +1,289 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+** Controls that can't be forwarded due to the current implementation
+*/
+
+static char * unsupported_ctrls[] = {LDAP_CONTROL_PERSISTENTSEARCH,NULL};
+
+int cb_is_control_forwardable(cb_backend * cb, char *controloid) {
+ return (!(charray_inlist(unsupported_ctrls,controloid)));
+}
+
+void
+cb_register_supported_control( cb_backend * cb, char *controloid, unsigned long controlops )
+{
+ /* For now, ignore controlops */
+ if ( controloid != NULL ) {
+ PR_RWLock_Wlock(cb->config.rwl_config_lock);
+ charray_add( &cb->config.forward_ctrls,slapi_ch_strdup( controloid ));
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+ }
+}
+
+
+void
+cb_unregister_all_supported_control( cb_backend * cb ) {
+
+ PR_RWLock_Wlock(cb->config.rwl_config_lock);
+ charray_free(cb->config.forward_ctrls);
+ cb->config.forward_ctrls=NULL;
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+}
+
+void
+cb_unregister_supported_control( cb_backend * cb, char *controloid, unsigned long controlops )
+{
+
+ /* For now, ignore controlops */
+ if ( controloid != NULL ) {
+ int i;
+ PR_RWLock_Wlock(cb->config.rwl_config_lock);
+ for ( i = 0; cb->config.forward_ctrls != NULL && cb->config.forward_ctrls[i] != NULL; ++i ) {
+ if ( strcmp( cb->config.forward_ctrls[i], controloid ) == 0 ) {
+ break;
+ }
+ }
+ if ( cb->config.forward_ctrls == NULL || cb->config.forward_ctrls[i] == NULL) {
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+ return;
+ }
+ if ( controlops == 0 ) {
+ charray_remove(cb->config.forward_ctrls,controloid);
+ }
+ PR_RWLock_Unlock(cb->config.rwl_config_lock);
+ }
+}
+
+int cb_create_loop_control (
+ const int hops,
+ LDAPControl **ctrlp)
+
+{
+ BerElement *ber;
+ int rc;
+
+ if ((ber = ber_alloc()) == NULL)
+ return -1;
+
+ if ( ber_printf( ber, "i", hops ) < 0) {
+ ber_free(ber,1);
+ return -1;
+ }
+
+ rc = slapi_build_control( CB_LDAP_CONTROL_CHAIN_SERVER, ber, 0, ctrlp);
+
+ ber_free(ber,1);
+
+ return rc;
+}
+
+/*
+** Return the controls to be passed to the remote
+** farm server and the LDAP error to return.
+**
+** Add the Proxied Authorization control when impersonation
+** is enabled. Other controls present in the request are added
+** to the control list
+**
+** #622885 .abandon should not inherit the to-be-abandoned-operation's controls
+** .controls attached to abandon should not be critical
+*/
+
+int cb_update_controls( Slapi_PBlock * pb,
+ LDAP * ld,
+ LDAPControl *** controls,
+ int ctrl_flags
+ )
+{
+
+ int cCount=0;
+ int dCount=0;
+ int i;
+ char * proxyDN=NULL;
+ LDAPControl ** reqControls = NULL;
+ LDAPControl ** ctrls = NULL;
+ cb_backend_instance * cb;
+ cb_backend * cbb;
+ Slapi_Backend * be;
+ int rc=LDAP_SUCCESS;
+ int hops=0;
+ int useloop=0;
+ int addauth = (ctrl_flags & CB_UPDATE_CONTROLS_ADDAUTH);
+ int isabandon = (ctrl_flags & CB_UPDATE_CONTROLS_ISABANDON);
+ int op_type = 0;
+
+ *controls = NULL;
+ slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
+ if (!isabandon || op_type == SLAPI_OPERATION_ABANDON) {
+ /* if not abandon or abandon sent by client */
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &reqControls );
+ }
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &cbb );
+ cb = cb_get_instance(be);
+
+ /*****************************************/
+ /* First, check for unsupported controls */
+ /* Return an error if critical control */
+ /* else remove it from the control list */
+ /*****************************************/
+
+ for ( cCount=0; reqControls && reqControls[cCount]; cCount++ );
+ ctrls = (LDAPControl **)slapi_ch_calloc(1,sizeof(LDAPControl *) * (cCount +3));
+
+ PR_RWLock_Rlock(cbb->config.rwl_config_lock);
+
+ for ( cCount=0; reqControls && reqControls[cCount]; cCount++ ) {
+
+ /* XXXSD CASCADING */
+ /* For now, allow PROXY_AUTH control forwarding only when */
+ /* local acl evaluation to prevent unauthorized access */
+
+ if (!strcmp(reqControls[cCount]->ldctl_oid,LDAP_CONTROL_PROXYAUTH)) {
+
+ /* we have to force remote acl checking if the associated backend to this
+ chaining backend is disabled - disabled == no acl check possible */
+ if (!cb->local_acl && !cb->associated_be_is_disabled) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,CB_PLUGIN_SUBSYSTEM,
+ "local aci check required to handle proxied auth control. Deny access.\n");
+ rc= LDAP_INSUFFICIENT_ACCESS;
+ break;
+ }
+
+ /* XXXSD Not safe to use proxied authorization with Directory Manager */
+ /* checked earlier when impersonation is on */
+
+ if (!cb->impersonate) {
+ char * requestor,*rootdn;
+ char * requestorCopy=NULL;
+
+ rootdn=cb_get_rootdn();
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_DN, &requestor );
+ requestorCopy=slapi_ch_strdup(requestor);
+ slapi_dn_normalize_case(requestorCopy);
+
+ if (!strcmp( requestorCopy, rootdn )) { /* UTF8- aware */
+ slapi_log_error( SLAPI_LOG_PLUGIN,CB_PLUGIN_SUBSYSTEM,
+ "Use of user <%s> incompatible with proxied auth. control\n",rootdn);
+ rc=LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ slapi_ch_free((void **)&requestorCopy);
+ break;
+ }
+ slapi_ch_free((void **)&rootdn);
+ slapi_ch_free((void **)&requestorCopy);
+ }
+
+ addauth=0;
+ ctrls[dCount]=slapi_dup_control(reqControls[cCount]);
+ dCount++;
+
+ } else
+ if (!strcmp(reqControls[cCount]->ldctl_oid,CB_LDAP_CONTROL_CHAIN_SERVER)) {
+
+ /* Max hop count reached ? */
+ /* Checked realier by a call to cb_forward_operation() */
+
+ BerElement *ber = NULL;
+
+ ber = ber_init(&(reqControls[cCount]->ldctl_value));
+ ber_scanf(ber,"i",&hops);
+ ber_free(ber,1);
+ useloop=1;
+
+ /* Add to the control list later */
+
+ } else {
+
+ int i;
+ for ( i = 0; cbb->config.forward_ctrls != NULL
+ && cbb->config.forward_ctrls[i] != NULL; ++i ) {
+ if ( strcmp( cbb->config.forward_ctrls[i], reqControls[cCount]->ldctl_oid ) == 0 ) {
+ break;
+ }
+ }
+ /* For now, ignore optype */
+ if ( cbb->config.forward_ctrls == NULL || cbb->config.forward_ctrls[i] == NULL) {
+ if (reqControls[cCount]->ldctl_iscritical) {
+ rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ break;
+ }
+ /* Skip it */
+ } else {
+ ctrls[dCount]=slapi_dup_control(reqControls[cCount]);
+ dCount++;
+ }
+ }
+ }
+
+ PR_RWLock_Unlock(cbb->config.rwl_config_lock);
+
+ if (LDAP_SUCCESS != rc) {
+ ldap_controls_free(ctrls);
+ return rc;
+ }
+
+ /***************************************/
+ /* add impersonation control if needed */
+ /***************************************/
+
+ if ( !(cb->impersonate) ) {
+
+ /* don't add proxy control */
+ addauth=0;
+ }
+
+ if (addauth) {
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_DN, &proxyDN );
+
+ if ( ldap_create_proxyauth_control(ld, proxyDN, isabandon?0:1, &ctrls[dCount] )) {
+ ldap_controls_free(ctrls);
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "LDAP_CONTROL_PROXYAUTH control encoding failed.\n");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ dCount++;
+ }
+
+ /***********************************************************/
+ /* add loop control if needed */
+ /* Don't add it if not in the list of forwardable controls */
+ /***********************************************************/
+
+ if (!useloop) {
+ for ( i = 0; cbb->config.forward_ctrls != NULL
+ && cbb->config.forward_ctrls[i] != NULL; ++i ) {
+ if ( strcmp( cbb->config.forward_ctrls[i],
+ CB_LDAP_CONTROL_CHAIN_SERVER) == 0 ) {
+ break;
+ }
+ }
+ }
+ if ( useloop || (cbb->config.forward_ctrls !=NULL && cbb->config.forward_ctrls[i] !=NULL)){
+
+ if (hops > 0) {
+ hops--;
+ } else {
+ hops = cb->hoplimit;
+ }
+
+ /* loop control's critical flag is 0;
+ * no special treatment is needed for abandon */
+ cb_create_loop_control(hops,&ctrls[dCount]);
+ dCount++;
+ }
+
+ if (dCount==0) {
+ ldap_controls_free(ctrls);
+ } else {
+ *controls = ctrls;
+ }
+
+ return LDAP_SUCCESS;
+
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_debug.c b/ldap/servers/plugins/chainingdb/cb_debug.c
new file mode 100644
index 00000000..8a33e440
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_debug.c
@@ -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 **/
+/*
+ * cb_debug.c - debugging-related code for Chaining backend
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "cb.h"
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
diff --git a/ldap/servers/plugins/chainingdb/cb_delete.c b/ldap/servers/plugins/chainingdb/cb_delete.c
new file mode 100644
index 00000000..f7eb77f6
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_delete.c
@@ -0,0 +1,203 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+ * Perform an delete operation
+ *
+ * Returns:
+ * 0 - success
+ * <0 - fail
+ *
+ */
+
+int
+chaining_back_delete ( Slapi_PBlock *pb )
+{
+
+ Slapi_Backend * be;
+ cb_backend_instance *cb;
+ LDAPControl **ctrls, **serverctrls;
+ int rc,parse_rc,msgid,i;
+ LDAP *ld=NULL;
+ char **referrals=NULL;
+ LDAPMessage * res;
+ char *dn,* matched_msg, *error_msg;
+ char *cnxerrbuf=NULL;
+ time_t endtime;
+ cb_outgoing_conn *cnx;
+
+ if ( LDAP_SUCCESS != (rc=cb_forward_operation(pb) )) {
+ cb_send_ldap_result( pb, rc, NULL, "Chaining forbidden", 0, NULL );
+ return -1;
+ }
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ cb_update_monitor_info(pb,cb,SLAPI_OPERATION_DELETE);
+
+ /* Check wether the chaining BE is available or not */
+ if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){
+ return -1;
+ }
+
+ slapi_pblock_get( pb, SLAPI_DELETE_TARGET, &dn );
+
+ /*
+ * Check local acls
+ */
+
+ if (cb->local_acl && !cb->associated_be_is_disabled) {
+ char * errbuf=NULL;
+ Slapi_Entry *te = slapi_entry_alloc();
+ slapi_entry_set_dn(te,slapi_ch_strdup(dn));
+ rc = cb_access_allowed (pb, te, NULL, NULL, SLAPI_ACL_DELETE,&errbuf);
+ slapi_entry_free(te);
+
+ if ( rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL, errbuf, 0, NULL );
+ slapi_ch_free((void **)&errbuf);
+ return -1;
+ }
+ }
+
+ /*
+ * Grab a connection handle
+ */
+
+ if ((rc = cb_get_connection(cb->pool,&ld,&cnx,NULL,&cnxerrbuf)) != LDAP_SUCCESS) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, cnxerrbuf, 0, NULL);
+ slapi_ch_free((void **)&cnxerrbuf);
+ /* ping the farm. If the farm is unreachable, we increment the counter */
+ cb_ping_farm(cb,NULL,0);
+ return -1;
+ }
+
+ /*
+ * Control management
+ */
+
+ if ( (rc = cb_update_controls( pb,ld,&ctrls,CB_UPDATE_CONTROLS_ADDAUTH )) != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL,NULL, 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ return -1;
+ }
+
+ if ( slapi_op_abandoned( pb )) {
+ cb_release_op_connection(cb->pool,ld,0);
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ return -1;
+ }
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ /*
+ * Send LDAP operation to the remote host
+ */
+
+ rc = ldap_delete_ext( ld, dn, ctrls, NULL, &msgid );
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ if ( rc != LDAP_SUCCESS ) {
+
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ return -1;
+ }
+
+ while ( 1 ) {
+
+ if (cb_check_forward_abandon(cb,pb,ld,msgid)) {
+ return -1;
+ }
+
+ rc = ldap_result( ld, msgid, 0, &cb->abandon_timeout, &res );
+ switch ( rc ) {
+ case -1:
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ return -1;
+ case 0:
+ if ((rc=cb_ping_farm(cb,cnx,endtime)) != LDAP_SUCCESS) {
+
+ /* does not respond. give up and return a*/
+ /* error to the client. */
+
+ /*cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);*/
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL, "FARM SERVER TEMPORARY UNAVAILABLE", 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ return -1;
+ }
+#ifdef CB_YIELD
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+#endif
+ break;
+ default:
+ matched_msg=error_msg=NULL;
+ parse_rc = ldap_parse_result( ld, res, &rc, &matched_msg,
+ &error_msg, &referrals, &serverctrls, 1 );
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(parse_rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(parse_rc));
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free referrals */
+ if (referrals)
+ charray_free(referrals);
+ return -1;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ struct berval ** refs = referrals2berval(referrals);
+
+ cb_send_ldap_result( pb, rc, matched_msg, error_msg, 0, refs);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (refs)
+ ber_bvecfree(refs);
+ if (referrals)
+ charray_free(referrals);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ return -1;
+ }
+
+ cb_release_op_connection(cb->pool,ld,0);
+
+ /* Add control response sent by the farm server */
+
+ for (i=0; serverctrls && serverctrls[i];i++)
+ slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, serverctrls[i]);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free matched_msg, error_msg, and referrals if necessary */
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (referrals)
+ charray_free(referrals);
+ cb_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ return 0;
+ }
+ }
+
+ /* Never reached */
+ /* return 0; */
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_init.c b/ldap/servers/plugins/chainingdb/cb_init.c
new file mode 100644
index 00000000..70af3d42
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_init.c
@@ -0,0 +1,120 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+Slapi_PluginDesc chainingdbdesc = { CB_PLUGIN_NAME,
+ PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT,
+ CB_PLUGIN_DESCRIPTION };
+
+
+static cb_backend * cb_backend_type=NULL;
+
+cb_backend * cb_get_backend_type() {
+ return cb_backend_type;
+}
+
+static void cb_set_backend_type(cb_backend * cb) {
+ cb_backend_type=cb;
+}
+
+/* Initialization function */
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+
+int
+chaining_back_init( Slapi_PBlock *pb )
+{
+
+ int rc=0;
+ cb_backend *cb;
+ struct slapdplugin *p;
+
+ cb = (cb_backend *) slapi_ch_calloc( 1, sizeof(cb_backend));
+
+ /* Record the identity of the chaining plugin. used during internal ops.*/
+ slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &(cb->identity));
+
+ /* keep a pointer back to the plugin */
+ slapi_pblock_get(pb, SLAPI_PLUGIN, &p);
+ cb->plugin = p;
+
+ /* Initialize misc. fields */
+ cb->config.rwl_config_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "chaining_db");
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_PRIVATE, (void *) cb );
+ cb->pluginDN=slapi_ch_calloc( 1,strlen(PLUGIN_BASE_DN)+strlen(CB_PLUGIN_NAME)+5);
+ sprintf(cb->pluginDN,"cn=%s,%s",CB_PLUGIN_NAME,PLUGIN_BASE_DN);
+
+ cb->configDN=slapi_ch_calloc( 1,strlen(cb->pluginDN)+11);
+ sprintf(cb->configDN,"cn=config,%s",cb->pluginDN);
+
+ /* Set backend callback functions */
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_03 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&chainingdbdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_SEARCH_FN,
+ (void *) chainingdb_build_candidate_list );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN,
+ (void *) chainingdb_next_search_entry );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN,
+ (void *) chainingdb_start ) ;
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_BIND_FN,
+ (void *) chainingdb_bind ) ;
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ADD_FN,
+ (void *) chaining_back_add );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_DELETE_FN,
+ (void *) chaining_back_delete );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_COMPARE_FN,
+ (void *) chaining_back_compare );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_MODIFY_FN,
+ (void *) chaining_back_modify );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_MODRDN_FN,
+ (void *) chaining_back_modrdn );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ABANDON_FN,
+ (void *) chaining_back_abandon );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_SIZE_FN,
+ (void *) cb_db_size );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) cb_back_close );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_CLEANUP_FN,
+ (void *) cb_back_cleanup );
+
+/****
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ENTRY_RELEASE_FN,
+ (void *) chaining_back_entry_release );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_INIT_INSTANCE_FN,
+ (void *) chaining_back_init);
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_TEST_FN,
+ (void *) cb_back_test );
+****/
+
+ /*
+ ** The following callbacks are not implemented
+ ** by the chaining backend
+ ** - SLAPI_PLUGIN_DB_FLUSH_FN
+ ** - SLAPI_PLUGIN_DB_SEQ_FN
+ ** - SLAPI_PLUGIN_DB_RMDB_FN
+ ** - SLAPI_PLUGIN_DB_DB2INDEX_FN
+ ** - SLAPI_PLUGIN_DB_LDIF2DB_FN
+ ** - SLAPI_PLUGIN_DB_DB2LDIF_FN
+ ** - SLAPI_PLUGIN_DB_ARCHIVE2DB_FN
+ ** - SLAPI_PLUGIN_DB_DB2ARCHIVE_FN
+ ** - SLAPI_PLUGIN_DB_BEGIN_FN
+ ** - SLAPI_PLUGIN_DB_COMMIT_FN
+ ** - SLAPI_PLUGIN_DB_ABORT_FN
+ ** - SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN
+ */
+
+ if ( rc != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM, "chaining_back_init failed\n");
+ return( -1 );
+ }
+
+ cb_set_backend_type(cb);
+
+ return (0);
+}
+
diff --git a/ldap/servers/plugins/chainingdb/cb_instance.c b/ldap/servers/plugins/chainingdb/cb_instance.c
new file mode 100644
index 00000000..60af726f
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_instance.c
@@ -0,0 +1,1871 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+** 1 set/get function for each parameter of a backend instance
+** NOTE: Some parameters won't be taken into account until the server has restarted
+** In such cases, the internal conf is not updated but the new value is stored in the
+** dse.ldif file.
+**/
+
+/* Get functions */
+
+static void *cb_instance_hosturl_get(void *arg);
+static void *cb_instance_binduser_get(void *arg);
+static void *cb_instance_userpassword_get(void *arg);
+static void *cb_instance_maxbconn_get(void *arg);
+static void *cb_instance_maxconn_get(void *arg);
+static void *cb_instance_abandonto_get(void *arg);
+static void *cb_instance_maxbconc_get(void *arg);
+static void *cb_instance_maxconc_get(void *arg);
+static void *cb_instance_imperson_get(void *arg);
+static void *cb_instance_connlife_get(void *arg);
+static void *cb_instance_bindto_get(void *arg);
+static void *cb_instance_opto_get(void *arg);
+static void *cb_instance_ref_get(void *arg);
+static void *cb_instance_acl_get(void *arg);
+static void *cb_instance_bindretry_get(void *arg);
+static void *cb_instance_sizelimit_get(void *arg);
+static void *cb_instance_timelimit_get(void *arg);
+static void *cb_instance_hoplimit_get(void *arg);
+static void *cb_instance_max_idle_get(void *arg);
+static void *cb_instance_max_test_get(void *arg);
+
+
+/* Set functions */
+
+static int cb_instance_hosturl_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_binduser_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_userpassword_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_maxbconn_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_maxconn_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_abandonto_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_maxbconc_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_maxconc_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_imperson_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_connlife_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_bindto_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_opto_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_ref_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_acl_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_bindretry_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_sizelimit_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_timelimit_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_hoplimit_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_max_idle_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+static int cb_instance_max_test_set(void *arg, void *value, char *errorbuf, int phase, int apply);
+
+/* Default hardwired values */
+
+cb_instance_config_info cb_the_instance_config[] = {
+{CB_CONFIG_HOSTURL,CB_CONFIG_TYPE_STRING,"",&cb_instance_hosturl_get,&cb_instance_hosturl_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_BINDUSER, CB_CONFIG_TYPE_STRING, "", &cb_instance_binduser_get, &cb_instance_binduser_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_USERPASSWORD,CB_CONFIG_TYPE_STRING,"",&cb_instance_userpassword_get,&cb_instance_userpassword_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAXBINDCONNECTIONS,CB_CONFIG_TYPE_INT,CB_DEF_BIND_MAXCONNECTIONS,&cb_instance_maxbconn_get, &cb_instance_maxbconn_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAXCONNECTIONS,CB_CONFIG_TYPE_INT,CB_DEF_MAXCONNECTIONS,&cb_instance_maxconn_get, &cb_instance_maxconn_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_ABANDONTIMEOUT,CB_CONFIG_TYPE_INT,CB_DEF_ABANDON_TIMEOUT,&cb_instance_abandonto_get, &cb_instance_abandonto_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAXBINDCONCURRENCY,CB_CONFIG_TYPE_INT,CB_DEF_BIND_MAXCONCURRENCY,&cb_instance_maxbconc_get, &cb_instance_maxbconc_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAXCONCURRENCY,CB_CONFIG_TYPE_INT,CB_DEF_MAXCONCURRENCY,&cb_instance_maxconc_get, &cb_instance_maxconc_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_IMPERSONATION,CB_CONFIG_TYPE_ONOFF,CB_DEF_IMPERSONATION,&cb_instance_imperson_get, &cb_instance_imperson_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_CONNLIFETIME,CB_CONFIG_TYPE_INT,CB_DEF_CONNLIFETIME,&cb_instance_connlife_get, &cb_instance_connlife_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_BINDTIMEOUT,CB_CONFIG_TYPE_INT,CB_DEF_BINDTIMEOUT,&cb_instance_bindto_get, &cb_instance_bindto_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_TIMEOUT,CB_CONFIG_TYPE_INT,"0",&cb_instance_opto_get, &cb_instance_opto_set,0},
+{CB_CONFIG_REFERRAL,CB_CONFIG_TYPE_ONOFF,CB_DEF_SEARCHREFERRAL,&cb_instance_ref_get, &cb_instance_ref_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_LOCALACL,CB_CONFIG_TYPE_ONOFF,CB_DEF_LOCALACL,&cb_instance_acl_get, &cb_instance_acl_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_BINDRETRY,CB_CONFIG_TYPE_INT,CB_DEF_BINDRETRY,&cb_instance_bindretry_get, &cb_instance_bindretry_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_SIZELIMIT,CB_CONFIG_TYPE_INT,CB_DEF_SIZELIMIT,&cb_instance_sizelimit_get, &cb_instance_sizelimit_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_TIMELIMIT,CB_CONFIG_TYPE_INT,CB_DEF_TIMELIMIT,&cb_instance_timelimit_get, &cb_instance_timelimit_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_HOPLIMIT,CB_CONFIG_TYPE_INT,CB_DEF_HOPLIMIT,&cb_instance_hoplimit_get, &cb_instance_hoplimit_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAX_IDLE_TIME,CB_CONFIG_TYPE_INT,CB_DEF_MAX_IDLE_TIME,&cb_instance_max_idle_get, &cb_instance_max_idle_set,CB_ALWAYS_SHOW},
+{CB_CONFIG_MAX_TEST_TIME,CB_CONFIG_TYPE_INT,CB_DEF_MAX_TEST_TIME,&cb_instance_max_test_get, &cb_instance_max_test_set,CB_ALWAYS_SHOW},
+{NULL, 0, NULL, NULL, NULL, 0}
+};
+
+/* Others forward declarations */
+
+int cb_instance_delete_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg);
+int cb_instance_search_config_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg);
+int cb_instance_add_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg);
+static int
+cb_instance_config_set(void *arg, char *attr_name, cb_instance_config_info *config_array,
+struct berval *bval, char *err_buf, int phase, int apply_mod);
+
+
+int
+cb_dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg)
+{
+ *returncode=LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+static char *cb_skeleton_entries[] =
+{
+
+ "dn:cn=monitor, cn=%s, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:monitor\n",
+
+ ""
+};
+
+/*
+** Initialize a backend instance with a default configuration
+*/
+
+static void cb_instance_config_set_default(cb_backend_instance *inst)
+{
+ cb_instance_config_info *config;
+ char err_buf[CB_BUFSIZE];
+
+ for (config = cb_the_instance_config; config->config_name != NULL; config++) {
+ cb_instance_config_set((void *)inst,
+ config->config_name, cb_the_instance_config, NULL /* use default */, err_buf,
+ CB_CONFIG_PHASE_INITIALIZATION, 1 /* apply */);
+ }
+
+ /* Set backend instance flags */
+ if (inst->inst_be)
+ slapi_be_set_flag(inst->inst_be,SLAPI_BE_FLAG_REMOTE_DATA);
+}
+
+/*
+** Allocate a new chaining backend instance. Internal structure
+*/
+
+static cb_backend_instance * cb_instance_alloc(cb_backend * cb, char * name, char * basedn) {
+
+ int i;
+
+ cb_backend_instance * inst =
+ (cb_backend_instance *)slapi_ch_calloc(1, sizeof(cb_backend_instance));
+
+ /* associated_be_is_disabled defaults to 0 - this may be a problem if the associated
+ be is disabled at instance creation time
+ */
+ inst->inst_name = slapi_ch_strdup(name);
+ inst->monitor.mutex = slapi_new_mutex();
+ inst->monitor_availability.cpt_lock = slapi_new_mutex();
+ inst->monitor_availability.lock_timeLimit = slapi_new_mutex();
+ inst->pool= (cb_conn_pool *) slapi_ch_calloc(1,sizeof(cb_conn_pool));
+ inst->pool->conn.conn_list_mutex = slapi_new_mutex();
+ inst->pool->conn.conn_list_cv = slapi_new_condvar(inst->pool->conn.conn_list_mutex);
+ inst->pool->bindit=1;
+
+ inst->bind_pool= (cb_conn_pool *) slapi_ch_calloc(1,sizeof(cb_conn_pool));
+ inst->bind_pool->conn.conn_list_mutex = slapi_new_mutex();
+ inst->bind_pool->conn.conn_list_cv = slapi_new_condvar(inst->bind_pool->conn.conn_list_mutex);
+
+ inst->backend_type=cb;
+ /* initialize monitor_availability */
+ inst->monitor_availability.farmserver_state = FARMSERVER_AVAILABLE ; /* we expect the farm to be available */
+ inst->monitor_availability.cpt = 0 ; /* set up the failed conn counter to 0 */
+
+ /* create RW lock to protect the config */
+ inst->rwl_config_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, slapi_ch_strdup(name));
+
+ /* quick hack */
+ /* put a ref to the config lock in the pool */
+ /* so that the connection mgmt module can */
+ /* access the config safely */
+
+ inst->pool->rwl_config_lock = inst->rwl_config_lock;
+ inst->bind_pool->rwl_config_lock = inst->rwl_config_lock;
+
+ for (i=0; i < MAX_CONN_ARRAY; i++) {
+ inst->pool->connarray[i] = NULL;
+ inst->bind_pool->connarray[i] = NULL;
+ }
+
+ /* Config is now merged with the backend entry */
+ inst->configDn=slapi_ch_strdup(basedn);
+
+ inst->monitorDn=(char *) slapi_ch_calloc(1,strlen(basedn)+15);
+ sprintf(inst->monitorDn,"cn=monitor,%s",basedn);
+
+ inst->eq_ctx = NULL;
+
+ return inst;
+}
+
+void cb_instance_free(cb_backend_instance * inst) {
+
+ if (inst) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+
+ if ( inst->eq_ctx != NULL )
+ {
+ slapi_eq_cancel(inst->eq_ctx);
+ inst->eq_ctx = NULL;
+ }
+
+ if (inst->bind_pool)
+ cb_close_conn_pool(inst->bind_pool);
+ if (inst->pool)
+ cb_close_conn_pool(inst->pool);
+
+ slapi_destroy_condvar(inst->bind_pool->conn.conn_list_cv);
+ slapi_destroy_condvar(inst->pool->conn.conn_list_cv);
+ slapi_destroy_mutex(inst->monitor.mutex);
+ slapi_destroy_mutex(inst->bind_pool->conn.conn_list_mutex);
+ slapi_destroy_mutex(inst->pool->conn.conn_list_mutex);
+ slapi_destroy_mutex(inst->monitor_availability.cpt_lock);
+ slapi_destroy_mutex(inst->monitor_availability.lock_timeLimit);
+ slapi_ch_free((void **) &inst->configDn);
+ slapi_ch_free((void **) &inst->monitorDn);
+ slapi_ch_free((void **) &inst->inst_name);
+ charray_free(inst->every_attribute);
+
+ slapi_ch_free((void **) &inst->bind_pool);
+ slapi_ch_free((void **) &inst->pool);
+
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+
+ PR_DestroyRWLock(inst->rwl_config_lock);
+
+ slapi_ch_free((void **) &inst);
+ }
+/* XXXSD */
+}
+
+/*
+** Check the change the configuration of an existing chaining
+** backend instance.
+*/
+
+int cb_instance_modify_config_check_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg) {
+
+ cb_backend_instance * inst = (cb_backend_instance *) arg;
+ LDAPMod **mods;
+ int rc = LDAP_SUCCESS;
+ int i;
+ char * attr_name;
+ returntext[0] = '\0';
+
+ CB_ASSERT(inst!=NULL);
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ /* First pass to validate input */
+ for (i = 0; mods[i] && LDAP_SUCCESS == rc; i++) {
+ attr_name = mods[i]->mod_type;
+
+ /* specific processing for multi-valued attributes */
+ if ( !strcasecmp ( attr_name, CB_CONFIG_SUFFIX )) {
+ sprintf(returntext, "suffix modification not allowed\n");
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_ILLEGAL_ATTRS )) {
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_CHAINING_COMPONENTS )) {
+ continue;
+ } else
+
+ /* CB_CONFIG_BINDUSER & CB_CONFIG_USERPASSWORD may be added */
+ /* or deleted */
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_USERPASSWORD )) {
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_BINDUSER )) {
+
+ /* Make sure value is not forbidden */
+ if ((mods[i]->mod_op & LDAP_MOD_REPLACE) ||
+ ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD)) {
+
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, mods[i]->mod_bvalues[0], returntext,
+ CB_CONFIG_PHASE_RUNNING, 0);
+ continue;
+ }
+ }
+
+ if ((mods[i]->mod_op & LDAP_MOD_DELETE) ||
+ ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD)) {
+ rc= LDAP_UNWILLING_TO_PERFORM;
+ sprintf(returntext, "%s attributes is not allowed",
+ (mods[i]->mod_op & LDAP_MOD_DELETE) ? "Deleting" : "Adding");
+ } else if (mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ /* This assumes there is only one bval for this mod. */
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, mods[i]->mod_bvalues[0], returntext,
+ CB_CONFIG_PHASE_RUNNING, 0);
+ }
+ }
+ *returncode= rc;
+ return ((LDAP_SUCCESS == rc) ? 1:-1);
+}
+
+
+/*
+** Change the configuration of an existing chaining
+** backend instance.
+*/
+
+int cb_instance_modify_config_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg) {
+
+ cb_backend_instance * inst = (cb_backend_instance *) arg;
+ LDAPMod **mods;
+ int rc = LDAP_SUCCESS;
+ int i;
+ int reopen_conn=0;
+ char * attr_name;
+ returntext[0] = '\0';
+
+ CB_ASSERT(inst!=NULL);
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ /* input checked in the preop modify callback */
+
+ for (i = 0; mods[i] && LDAP_SUCCESS == rc; i++) {
+ attr_name = mods[i]->mod_type;
+
+ /* specific processing for multi-valued attributes */
+ if ( !strcasecmp ( attr_name, CB_CONFIG_ILLEGAL_ATTRS )) {
+ char * config_attr_value;
+ int done=0;
+ int j;
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ for (j = 0; mods[i]->mod_bvalues && mods[i]->mod_bvalues[j]; j++) {
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+ if ( mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ if (!done) {
+ charray_free(inst->illegal_attributes);
+ inst->illegal_attributes=NULL;
+ done=1;
+ }
+ charray_add(&inst->illegal_attributes,
+ slapi_ch_strdup(config_attr_value));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ charray_add(&inst->illegal_attributes,
+ slapi_ch_strdup(config_attr_value));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ charray_remove(inst->illegal_attributes,
+ slapi_ch_strdup(config_attr_value));
+ }
+ }
+ if (NULL == mods[i]->mod_bvalues) {
+ charray_free(inst->illegal_attributes);
+ inst->illegal_attributes=NULL;
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ continue;
+ }
+ if ( !strcasecmp ( attr_name, CB_CONFIG_CHAINING_COMPONENTS )) {
+ char * config_attr_value;
+ int done=0;
+ int j;
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ for (j = 0; mods[i]->mod_bvalues && mods[i]->mod_bvalues[j]; j++) {
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+ if ( mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ if (!done) {
+ charray_free(inst->chaining_components);
+ inst->chaining_components=NULL;
+ done=1;
+ }
+ /* XXXSD assume dns */
+ charray_add(&inst->chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ charray_add(&inst->chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)));
+ } else
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ charray_remove(inst->chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(config_attr_value)));
+ }
+ }
+ if (NULL == mods[i]->mod_bvalues) {
+ charray_free(inst->chaining_components);
+ inst->chaining_components=NULL;
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ continue;
+ }
+
+
+
+ if ((mods[i]->mod_op & LDAP_MOD_DELETE) ||
+ ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD)) {
+
+ /* Special processing for binddn & password */
+ /* because they are optional */
+
+ if (( !strcasecmp ( attr_name, CB_CONFIG_BINDUSER )) ||
+ ( !strcasecmp ( attr_name, CB_CONFIG_USERPASSWORD ))) {
+
+ if (mods[i]->mod_op & LDAP_MOD_DELETE) {
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, NULL, returntext,
+ CB_CONFIG_PHASE_RUNNING, 1); }
+ else {
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, mods[i]->mod_bvalues[0], returntext,
+ CB_CONFIG_PHASE_RUNNING, 1);
+ }
+ if (rc==CB_REOPEN_CONN) {
+ reopen_conn=1;
+ rc=LDAP_SUCCESS;
+ }
+ continue;
+ }
+
+ rc= LDAP_UNWILLING_TO_PERFORM;
+ sprintf(returntext, "%s attributes is not allowed",
+ (mods[i]->mod_op & LDAP_MOD_DELETE) ? "Deleting" : "Adding");
+ } else if (mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ /* This assumes there is only one bval for this mod. */
+ rc = cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, mods[i]->mod_bvalues[0], returntext,
+ CB_CONFIG_PHASE_RUNNING, 1);
+
+ /* Update requires to reopen connections */
+ /* Expensive operation so do it only once */
+ if (rc==CB_REOPEN_CONN) {
+ reopen_conn=1;
+ rc=LDAP_SUCCESS;
+ }
+ }
+ }
+
+ *returncode= rc;
+
+ if (reopen_conn) {
+ cb_stale_all_connections(inst);
+ }
+
+ return ((LDAP_SUCCESS == rc) ? SLAPI_DSE_CALLBACK_OK:SLAPI_DSE_CALLBACK_ERROR);
+}
+
+/*
+** Parse and instantiate backend instances
+*/
+
+int
+cb_parse_instance_config_entry(cb_backend * cb, Slapi_Entry * e) {
+
+ int rc =LDAP_SUCCESS;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ const struct berval *attrValue;
+ cb_backend_instance *inst=NULL;
+ char *instname;
+ Slapi_PBlock *search_pb=NULL;
+ char retmsg[CB_BUFSIZE];
+
+ CB_ASSERT(e!=NULL);
+
+ /*
+ ** Retrieve the instance name and make sure it is not
+ ** already declared.
+ */
+
+ if ( 0 == slapi_entry_attr_find( e, CB_CONFIG_INSTNAME, &attr )) {
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ instname=attrValue->bv_val;
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Malformed backend instance (<%s> missing)>\n", CB_CONFIG_INSTNAME);
+ return LDAP_LOCAL_ERROR;
+ }
+
+ /* Allocate a new backend internal data structure */
+ inst = cb_instance_alloc(cb,instname,slapi_entry_get_dn(e));
+
+ /* Emulate a add config entry to configure */
+ /* this backend instance. */
+
+ cb_instance_add_config_callback(NULL,e,NULL,&rc,retmsg,inst);
+ if ( rc != LDAP_SUCCESS ) {
+ cb_instance_free(inst);
+ }
+ return rc;
+}
+
+/*
+** Update the instance configuration
+*/
+
+static int
+cb_instance_config_initialize(cb_backend_instance * inst, Slapi_Entry * e , int phase, int apply) {
+
+ int rc =LDAP_SUCCESS;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ struct berval * bval;
+ int using_def_connlifetime,i;
+ char err_buf[CB_BUFSIZE];
+ int urlfound=0;
+ char *rootdn;
+
+ using_def_connlifetime=1;
+
+ for (slapi_entry_first_attr(e, &attr); attr; slapi_entry_next_attr(e, attr, &attr)) {
+ char * attr_name=NULL;
+ slapi_attr_get_type(attr, &attr_name);
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_SUFFIX )) {
+ if (apply && ( inst->inst_be != NULL )) {
+ Slapi_DN *suffix;
+ suffix = slapi_sdn_new();
+ i = slapi_attr_first_value(attr, &sval);
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ slapi_sdn_init_dn_byref(suffix, bval->bv_val);
+
+ if (!slapi_be_issuffix(inst->inst_be, suffix)) {
+ slapi_be_addsuffix(inst->inst_be, suffix);
+ }
+ slapi_sdn_done(suffix);
+ slapi_sdn_free(&suffix);
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ }
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_CHAINING_COMPONENTS )) {
+
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ i = slapi_attr_first_value(attr, &sval);
+ charray_free(inst->chaining_components);
+ inst->chaining_components=NULL;
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ charray_add(&inst->chaining_components,
+ slapi_dn_normalize(slapi_ch_strdup(bval->bv_val)));
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ continue;
+ } else
+ if ( !strcasecmp ( attr_name, CB_CONFIG_ILLEGAL_ATTRS )) {
+
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ i = slapi_attr_first_value(attr, &sval);
+ charray_free(inst->illegal_attributes);
+ inst->illegal_attributes=NULL;
+ while (i != -1 ) {
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ charray_add(&inst->illegal_attributes,
+ slapi_ch_strdup(bval->bv_val));
+ i = slapi_attr_next_value(attr, i, &sval);
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ continue;
+ }
+
+
+ if ( !strcasecmp ( attr_name, CB_CONFIG_HOSTURL )) {
+ urlfound=1;
+ }
+
+
+ /* We are assuming that each of these attributes are to have
+ * only one value. If they have more than one value, like
+ * the nsslapd-suffix attribute, then they need to be
+ * handled differently. */
+
+ slapi_attr_first_value(attr, &sval);
+ bval = (struct berval *) slapi_value_get_berval(sval);
+
+ if (cb_instance_config_set((void *) inst, attr_name,
+ cb_the_instance_config, bval, err_buf, phase, apply ) != LDAP_SUCCESS) {
+ slapi_log_error( SLAPI_LOG_FATAL,
+ CB_PLUGIN_SUBSYSTEM,"Error with config attribute %s : %s\n",
+ attr_name, err_buf);
+ rc=LDAP_LOCAL_ERROR;
+ break;
+ }
+ if ( !strcasecmp ( attr_name, CB_CONFIG_CONNLIFETIME )) {
+ using_def_connlifetime=0;
+ }
+ }
+
+
+ /*
+ ** Check for mandatory attributes
+ ** Post-Processing
+ */
+
+ if (LDAP_SUCCESS == rc) {
+ if (!urlfound) {
+ slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "Malformed backend instance entry. Mandatory attr <%s> missing\n",
+ CB_CONFIG_HOSTURL);
+ rc= LDAP_LOCAL_ERROR;
+ }
+
+ if (apply ) {
+ if ( using_def_connlifetime &&
+ strchr( inst->pool->hostname, ' ' ) != NULL ) {
+
+ cb_instance_config_set((void *)inst, CB_CONFIG_CONNLIFETIME,
+ cb_the_instance_config, NULL /* use default */, err_buf,
+ CB_CONFIG_PHASE_INITIALIZATION, 1 );
+ }
+ }
+ }
+
+ /*
+ ** Additional checks
+ ** It is forbidden to use directory manager as proxy user
+ ** due to a bug in the acl check
+ */
+
+ rootdn=cb_get_rootdn();
+
+ if (inst->impersonate && inst->pool && inst->pool->binddn &&
+ !strcmp(inst->pool->binddn,rootdn)) { /* UTF8 aware */
+ slapi_log_error( SLAPI_LOG_FATAL,
+ CB_PLUGIN_SUBSYSTEM,"Error with config attribute %s (%s: forbidden value)\n",
+ CB_CONFIG_BINDUSER, rootdn);
+ rc=LDAP_LOCAL_ERROR;
+ }
+ slapi_ch_free((void **)&rootdn);
+
+ return rc;
+}
+
+/********************************************************
+** Get and set functions for chaining backend instances *
+*********************************************************
+*/
+
+static void *cb_instance_hosturl_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ char * data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = slapi_ch_strdup(inst->pool->url);
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return data;
+}
+
+static int cb_instance_hosturl_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance *inst=(cb_backend_instance *) arg;
+ char *url = (char *) value;
+ LDAPURLDesc *ludp=NULL;
+ int rc=LDAP_SUCCESS;
+
+ if (( rc = ldap_url_parse( url, &ludp )) != 0 ) {
+ strcpy(errorbuf,cb_urlparse_err2string( rc ));
+ if (CB_CONFIG_PHASE_INITIALIZATION == phase)
+ inst->pool->url=slapi_ch_strdup("");
+ return(LDAP_INVALID_SYNTAX);
+ }
+
+ if (apply) {
+
+ char * ptr;
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modification */
+ /* Don't free char * pointer now */
+ /* STore them in a waste basket */
+ /* Will be relesase when the backend stops */
+
+ if (inst->pool->hostname)
+ charray_add(&inst->pool->waste_basket,inst->pool->hostname);
+ if (inst->pool->url)
+ charray_add(&inst->pool->waste_basket,inst->pool->url);
+
+ if (inst->bind_pool->hostname)
+ charray_add(&inst->bind_pool->waste_basket,inst->bind_pool->hostname);
+ if (inst->bind_pool->url)
+ charray_add(&inst->bind_pool->waste_basket,inst->bind_pool->url);
+
+ /* Require connection cleanup */
+ rc=CB_REOPEN_CONN;
+ }
+
+ /* Normal case. Extract useful data from */
+ /* the url and update the configuration */
+
+ if ((ludp->lud_host==NULL) || (strlen(ludp->lud_host)==0)) {
+ inst->pool->hostname=(char *)slapi_ch_strdup((char *)get_localhost_DNS());
+ } else {
+ inst->pool->hostname = slapi_ch_strdup( ludp->lud_host );
+ }
+ inst->pool->url = slapi_ch_strdup( url);
+ inst->pool->secure = (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 );
+
+ if ((ludp->lud_port==0) && inst->pool->secure)
+ inst->pool->port=CB_LDAP_SECURE_PORT;
+ else
+ inst->pool->port = ludp->lud_port;
+
+ /* Build a charray of <host>:<port> */
+ /* hostname is of the form <host>[:port] <host>[:port] */
+
+ { char * aBufCopy, * aHostName;
+ char * iter = NULL;
+ aBufCopy= aBufCopy=slapi_ch_strdup(inst->pool->hostname);
+
+ aHostName=ldap_utf8strtok_r(aBufCopy," ", &iter);
+ charray_free(inst->url_array);
+ inst->url_array=NULL;
+ while (aHostName) {
+
+ char * aHostPort = slapi_ch_calloc(1,strlen(aHostName)+30);
+ if ( NULL == ( ptr=strstr(aHostName,":")))
+ sprintf(aHostPort,"%s://%s:%d/",
+ inst->pool->secure ? "ldaps" : "ldap",
+ aHostName,inst->pool->port);
+ else
+ sprintf(aHostPort,"%s://%s/",
+ inst->pool->secure ? "ldaps" : "ldap",
+ aHostName);
+
+ charray_add(&inst->url_array,aHostPort);
+ aHostName=ldap_utf8strtok_r(NULL," ", &iter);
+ }
+
+ slapi_ch_free((void **) &aBufCopy);
+ }
+
+ inst->bind_pool->port=inst->pool->port;
+ inst->bind_pool->secure=inst->pool->secure;
+ inst->bind_pool->hostname=slapi_ch_strdup(inst->pool->hostname);
+
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+
+ if ( ludp != NULL ) {
+ ldap_free_urldesc( ludp );
+ }
+ return rc;
+}
+
+static void *cb_instance_binduser_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ char * data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = slapi_ch_strdup(inst->pool->binddn2); /* not normalized */
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return data;
+}
+
+static int cb_instance_binduser_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int rc=LDAP_SUCCESS;
+
+ if (apply) {
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modif */
+ /* Free user later */
+
+ charray_add(&inst->pool->waste_basket,inst->pool->binddn);
+ charray_add(&inst->pool->waste_basket,inst->pool->binddn2);
+ rc=CB_REOPEN_CONN;
+ }
+
+ inst->pool->binddn=slapi_ch_strdup((char *) value);
+ inst->pool->binddn2=slapi_ch_strdup((char *) value);
+ slapi_dn_normalize_case(inst->pool->binddn);
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ } else {
+
+ /* Security check */
+ /* directory manager of the farm server should not be used as */
+ /* proxing user. This is hard to check, so assume same directory */
+ /* manager across servers. */
+
+ char * rootdn = cb_get_rootdn();
+ char * theValueCopy = NULL;
+
+ if (value) {
+ theValueCopy=slapi_ch_strdup((char *) value);
+ slapi_dn_normalize_case(theValueCopy);
+ }
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ if (inst->impersonate && theValueCopy &&
+ !strcmp(theValueCopy,rootdn)) { /* UTF8-aware. See cb_get_dn() */
+ rc=LDAP_UNWILLING_TO_PERFORM;
+ if (errorbuf) {
+ sprintf(errorbuf,"value %s not allowed",rootdn);
+ }
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+
+ slapi_ch_free((void **)&theValueCopy);
+ slapi_ch_free((void **)&rootdn);
+ }
+
+ return rc;
+}
+
+
+static void *cb_instance_userpassword_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ char * data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = slapi_ch_strdup(inst->pool->password);
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return data;
+}
+
+static int cb_instance_userpassword_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int rc=LDAP_SUCCESS;
+
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modif */
+ charray_add(&inst->pool->waste_basket,inst->pool->password);
+ rc=CB_REOPEN_CONN;
+ }
+
+ inst->pool->password=slapi_ch_strdup((char *) value);
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return rc;
+}
+
+static void *cb_instance_sizelimit_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->sizelimit;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_sizelimit_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->sizelimit=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ if (inst->inst_be)
+ be_set_sizelimit(inst->inst_be, (int) value);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_timelimit_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->timelimit;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_timelimit_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->timelimit=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ if (inst->inst_be)
+ be_set_timelimit(inst->inst_be, (int) value);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_max_test_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->max_test_time;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_max_test_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->max_test_time=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_max_idle_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->max_idle_time;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_max_idle_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->max_idle_time=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+
+static void *cb_instance_hoplimit_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->hoplimit;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_hoplimit_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->hoplimit=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_maxbconn_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->bind_pool->conn.maxconnections;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_maxbconn_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->bind_pool->conn.maxconnections=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_maxconn_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->pool->conn.maxconnections;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_maxconn_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->pool->conn.maxconnections=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_abandonto_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->abandon_timeout.tv_sec;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_abandonto_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+
+ if (apply) {
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modif not supported */
+ /* Stored in ldif only */
+ return LDAP_SUCCESS;
+ }
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->abandon_timeout.tv_sec=(int) value;
+ inst->abandon_timeout.tv_usec=0;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_maxbconc_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->bind_pool->conn.maxconcurrency;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_maxbconc_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->bind_pool->conn.maxconcurrency=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_maxconc_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->pool->conn.maxconcurrency;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_maxconc_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->pool->conn.maxconcurrency=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_imperson_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data = inst->impersonate;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_imperson_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int rc=LDAP_SUCCESS;
+
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->impersonate=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ } else {
+ /* Security check: Make sure the proxing user is */
+ /* not the directory manager. */
+
+ char * rootdn=cb_get_rootdn();
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ if (((int) value) && inst->pool && inst->pool->binddn &&
+ !strcmp(inst->pool->binddn,rootdn)) { /* UTF-8 aware */
+ rc=LDAP_UNWILLING_TO_PERFORM;
+ if (errorbuf)
+ sprintf(errorbuf,"Proxy mode incompatible with %s value (%s not allowed)",
+ CB_CONFIG_BINDUSER,rootdn);
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ slapi_ch_free((void **)&rootdn);
+ }
+
+ return rc;
+}
+
+static void *cb_instance_connlife_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->pool->conn.connlifetime;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_connlife_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->pool->conn.connlifetime=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_bindto_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->bind_pool->conn.op_timeout.tv_sec;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_bindto_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->bind_pool->conn.op_timeout.tv_sec=(int) value;
+ inst->bind_pool->conn.op_timeout.tv_usec=0;
+ inst->bind_pool->conn.bind_timeout.tv_sec=(int) value;
+ inst->bind_pool->conn.bind_timeout.tv_usec=0;
+ /* Used to bind to the farm server */
+ inst->pool->conn.bind_timeout.tv_sec=(int) value;
+ inst->pool->conn.bind_timeout.tv_usec=0;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_opto_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->pool->conn.op_timeout.tv_sec;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_opto_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->pool->conn.op_timeout.tv_sec=(int) value;
+ inst->pool->conn.op_timeout.tv_usec=0;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_ref_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->searchreferral;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_ref_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->searchreferral=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_acl_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->local_acl;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_acl_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+
+ if (apply) {
+ if (( phase != CB_CONFIG_PHASE_INITIALIZATION ) &&
+ ( phase != CB_CONFIG_PHASE_STARTUP )) {
+
+ /* Dynamic modif not supported */
+ /* Stored in ldif only */
+ return LDAP_SUCCESS;
+ }
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->local_acl=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *cb_instance_bindretry_get(void *arg)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ int data;
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ data=inst->bind_retry;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return (void *) data;
+}
+
+static int cb_instance_bindretry_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ cb_backend_instance * inst=(cb_backend_instance *) arg;
+ if (apply) {
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+ inst->bind_retry=(int) value;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+ return LDAP_SUCCESS;
+}
+
+
+
+
+/* Finds an entry in a config_info array with the given name. Returns
+ * the entry on success and NULL when not found.
+ */
+static cb_instance_config_info *cb_get_config_info(cb_instance_config_info *config_array, char *attr_name)
+{
+ int x;
+
+ for(x = 0; config_array[x].config_name != NULL; x++) {
+ if (!strcasecmp(config_array[x].config_name, attr_name)) {
+ return &(config_array[x]);
+ }
+ }
+ return NULL;
+}
+
+/*
+** Update an attribute value
+** For now, unknown attributes are ignored
+** Return a LDAP error code OR CB_REOPEN_CONN when the
+** update requires to close open connections.
+*/
+
+static int
+cb_instance_config_set(void *arg, char *attr_name, cb_instance_config_info *config_array,
+struct berval *bval, char *err_buf, int phase, int apply_mod)
+{
+ cb_instance_config_info *config;
+ int use_default;
+ int int_val;
+ long long_val;
+ int retval=LDAP_LOCAL_ERROR;
+
+ config = cb_get_config_info(config_array, attr_name);
+ if (NULL == config) {
+ /* Ignore unknown attributes */
+ return LDAP_SUCCESS;
+ }
+
+ /* If the config phase is initialization or if bval is NULL, we will use
+ * the default value for the attribute. */
+ if (CB_CONFIG_PHASE_INITIALIZATION == phase || NULL == bval) {
+ use_default = 1;
+ } else {
+ use_default = 0;
+ /* Since we are setting the value for the config attribute, we
+ * need to turn on the CB_PREVIOUSLY_SET flag to make
+ * sure this attribute is shown. */
+ config->config_flags |= CB_PREVIOUSLY_SET;
+ }
+
+ switch(config->config_type) {
+ case CB_CONFIG_TYPE_INT:
+ if (use_default) {
+ int_val = cb_atoi(config->config_default_value);
+ } else {
+ int_val = cb_atoi((char *)bval->bv_val);
+ }
+ retval = config->config_set_fn(arg, (void *) int_val, err_buf, phase, apply_mod);
+ break;
+ case CB_CONFIG_TYPE_INT_OCTAL:
+ if (use_default) {
+ int_val = (int) strtol(config->config_default_value, NULL, 8);
+ } else {
+ int_val = (int) strtol((char *)bval->bv_val, NULL, 8);
+ }
+ retval = config->config_set_fn(arg, (void *) int_val, err_buf, phase, apply_mod);
+ break;
+ case CB_CONFIG_TYPE_LONG:
+ if (use_default) {
+ long_val = cb_atol(config->config_default_value);
+ } else {
+ long_val = cb_atol((char *)bval->bv_val);
+ }
+ retval = config->config_set_fn(arg, (void *) long_val, err_buf, phase, apply_mod);
+ break;
+ case CB_CONFIG_TYPE_STRING:
+ if (use_default) {
+ retval = config->config_set_fn(arg, config->config_default_value, err_buf, phase, apply_mod);
+ } else {
+ retval = config->config_set_fn(arg, bval->bv_val, err_buf, phase, apply_mod);
+ }
+ break;
+ case CB_CONFIG_TYPE_ONOFF:
+ if (use_default) {
+ int_val = !strcasecmp(config->config_default_value, "on");
+ } else {
+ int_val = !strcasecmp((char *) bval->bv_val, "on");
+ }
+ retval = config->config_set_fn(arg, (void *) int_val, err_buf, phase, apply_mod);
+ break;
+ }
+ return retval;
+}
+
+/* Utility function used in creating config entries. Using the
+ * config_info, this function gets info and formats in the correct
+ * way.
+ */
+void cb_instance_config_get(void *arg, cb_instance_config_info *config, char *buf)
+{
+ char *tmp_string;
+
+ if (config == NULL) {
+ buf[0] = '\0';
+ }
+
+ switch(config->config_type) {
+ case CB_CONFIG_TYPE_INT:
+ sprintf(buf, "%d", (int) config->config_get_fn(arg));
+ break;
+ case CB_CONFIG_TYPE_INT_OCTAL:
+ sprintf(buf, "%o", (int) config->config_get_fn(arg));
+ break;
+ case CB_CONFIG_TYPE_LONG:
+ sprintf(buf, "%d", (long) config->config_get_fn(arg));
+ break;
+ case CB_CONFIG_TYPE_STRING:
+ /* Remember the get function for strings returns memory
+ * that must be freed. */
+ tmp_string = (char *) config->config_get_fn(arg);
+ sprintf(buf, "%s", (char *) tmp_string);
+ slapi_ch_free((void **)&tmp_string);
+ break;
+ case CB_CONFIG_TYPE_ONOFF:
+ if ((int) config->config_get_fn(arg)) {
+ sprintf(buf,"%s","on");
+ } else {
+ sprintf(buf,"%s","off");
+ }
+ break;
+ default:
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Invalid attribute syntax.\n");
+
+ }
+}
+
+/*
+** Search for instance config entry
+** Always return 'active' values because some configuration changes
+** won't be taken into account until the server restarts
+*/
+
+int cb_instance_search_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
+ int *returncode, char *returntext, void *arg) {
+
+ char buf[CB_BUFSIZE];
+ struct berval val;
+ struct berval *vals[2];
+ int i = 0;
+ cb_backend_instance *inst = (cb_backend_instance *)arg;
+ cb_instance_config_info * config;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* suffixes */
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+
+ {
+ const Slapi_DN *aSuffix;
+ i=0;
+ if (inst->inst_be) {
+ while ((aSuffix=slapi_be_getsuffix(inst->inst_be,i))) {
+ val.bv_val = (char *)slapi_sdn_get_dn(aSuffix);
+ val.bv_len = strlen( val.bv_val );
+ if (val.bv_len) {
+ if (i==0)
+ slapi_entry_attr_replace(e,CB_CONFIG_SUFFIX,(struct berval **)vals );
+ else
+ slapi_entry_attr_merge(e,CB_CONFIG_SUFFIX,(struct berval **)vals );
+ }
+ i++;
+ }
+ }
+ }
+
+ for (i=0; inst->chaining_components && inst->chaining_components[i]; i++) {
+ val.bv_val = inst->chaining_components[i];
+ val.bv_len = strlen( val.bv_val );
+ if (val.bv_len) {
+ if (i==0)
+ slapi_entry_attr_replace(e,CB_CONFIG_CHAINING_COMPONENTS,(struct berval **)vals );
+ else
+ slapi_entry_attr_merge(e,CB_CONFIG_CHAINING_COMPONENTS,(struct berval **)vals );
+ }
+ }
+
+ for (i=0; inst->illegal_attributes && inst->illegal_attributes[i]; i++) {
+ val.bv_val = inst->illegal_attributes[i];
+ val.bv_len = strlen( val.bv_val );
+ if (val.bv_len) {
+ if (i==0)
+ slapi_entry_attr_replace(e,CB_CONFIG_ILLEGAL_ATTRS,(struct berval **)vals );
+ else
+ slapi_entry_attr_merge(e,CB_CONFIG_ILLEGAL_ATTRS,(struct berval **)vals );
+ }
+ }
+
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+
+ /* standard attributes */
+ for(config = cb_the_instance_config; config->config_name != NULL; config++) {
+ if (!(config->config_flags & (CB_ALWAYS_SHOW | CB_PREVIOUSLY_SET))) {
+ /* This config option shouldn't be shown */
+ continue;
+ }
+
+ cb_instance_config_get((void *) inst, config, buf);
+
+ val.bv_val = buf;
+ val.bv_len = strlen(buf);
+ if (val.bv_len)
+ slapi_entry_attr_replace(e, config->config_name, vals);
+ }
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/*
+** Ooops!!! The backend instance is beeing deleted
+*/
+
+int cb_instance_delete_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg) {
+
+ cb_backend_instance * inst = (cb_backend_instance *) arg;
+ int rc;
+ Slapi_Entry * anEntry=NULL;
+ Slapi_DN * aDn;
+
+ CB_ASSERT( inst!=NULL );
+
+ /* notify the front-end */
+ slapi_mtn_be_stopping(inst->inst_be);
+
+ /* Now it is safe to stop */
+ /* No pending op */
+
+
+ /* unregister callbacks */
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, inst->configDn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", cb_instance_search_config_callback);
+
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_POSTOP, inst->configDn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", cb_instance_delete_config_callback);
+
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, inst->configDn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", cb_instance_modify_config_check_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, inst->configDn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", cb_instance_modify_config_callback);
+
+ /* At this point, the monitor entry should have been removed */
+ /* If not, manually call delete callback */
+
+ aDn = slapi_sdn_new_dn_byref(inst->monitorDn);
+ if ( LDAP_SUCCESS==(slapi_search_internal_get_entry(aDn,NULL, &anEntry,inst->backend_type->identity))) {
+ cb_delete_monitor_callback( NULL, anEntry, NULL, &rc , NULL, inst );
+ if (anEntry)
+ slapi_entry_free(anEntry);
+ }
+ slapi_sdn_done(aDn);
+ slapi_sdn_free(&aDn);
+
+ /* free resources */
+ cb_close_conn_pool(inst->bind_pool);
+ cb_close_conn_pool(inst->pool);
+ slapi_be_free(&(inst->inst_be));
+ cb_instance_free(inst);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static void cb_instance_add_monitor_later(time_t when, void *arg) {
+
+ cb_backend_instance * inst = (cb_backend_instance *) arg;
+
+ if ( inst != NULL )
+ {
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+
+ /* create the monitor entry if it is not there yet */
+ if (LDAP_SUCCESS == cb_config_add_dse_entries(inst->backend_type, cb_skeleton_entries,
+ inst->inst_name,CB_PLUGIN_NAME, NULL))
+ {
+
+ /* add monitor callbacks */
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, inst->monitorDn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", cb_search_monitor_callback, (void *) inst);
+
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, inst->monitorDn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", cb_dont_allow_that, (void *) NULL);
+
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP , inst->monitorDn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", cb_delete_monitor_callback, (void *) inst);
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+}
+
+
+int cb_instance_add_config_check_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg) {
+
+ int rc=LDAP_SUCCESS;
+ cb_backend_instance *inst;
+ cb_backend *cb=(cb_backend *) arg;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ const struct berval *attrValue;
+ char *instname=NULL;
+
+ if (returntext)
+ returntext[0]='\0';
+
+ /* Basic entry check */
+ if ( 0 == slapi_entry_attr_find( e, CB_CONFIG_INSTNAME, &attr )) {
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ instname=attrValue->bv_val;
+ }
+ if ( instname == NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Malformed backend instance (<%s> missing)>\n", CB_CONFIG_INSTNAME);
+ *returncode = LDAP_LOCAL_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* Allocate a new backend internal data structure */
+ inst = cb_instance_alloc(cb,instname,slapi_entry_get_dn(e));
+
+ /* build the backend instance from the default hardcoded conf, */
+ /* the default instance config and the specific entry specified */
+ if ((rc=cb_build_backend_instance_config(inst,e,0))
+ != LDAP_SUCCESS) {
+ slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "Can't instantiate chaining backend instance %s.\n",inst->inst_name);
+ *returncode=rc;
+ cb_instance_free(inst);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* Free the dummy instance */
+ *returncode=rc;
+ cb_instance_free(inst);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+/* Create the default instance config from hard-coded values */
+/*
+** Initialize the backend instance with the config entry
+** passed in arguments.
+** <arg> : (cb_backend *)
+*/
+
+int cb_instance_add_config_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* e2,
+ int *returncode, char *returntext, void *arg) {
+
+ int rc=LDAP_SUCCESS;
+ cb_backend_instance *inst;
+ cb_backend *cb=(cb_backend *) arg;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval;
+ const struct berval *attrValue;
+ char *instname=NULL;
+
+ if (returntext)
+ returntext[0]='\0';
+
+ /* Basic entry check */
+ if ( 0 == slapi_entry_attr_find( e, CB_CONFIG_INSTNAME, &attr )) {
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ instname=attrValue->bv_val;
+ }
+ if ( instname == NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Malformed backend instance (<%s> missing)>\n", CB_CONFIG_INSTNAME);
+ *returncode = LDAP_LOCAL_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* Allocate a new backend internal data structure */
+ inst = cb_instance_alloc(cb,instname,slapi_entry_get_dn(e));
+
+ /* build the backend instance from the default hardcoded conf, */
+ /* the default instance config and the specific entry specified */
+ if ((rc=cb_build_backend_instance_config(inst,e,0))
+ != LDAP_SUCCESS) {
+ slapi_log_error( SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "Can't instantiate chaining backend instance %s.\n",inst->inst_name);
+ *returncode=rc;
+ cb_instance_free(inst);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* Instantiate a Slapi_Backend if necessary */
+ if (!inst->isconfigured) {
+
+ Slapi_PBlock *aPb=NULL;
+
+ inst->inst_be = slapi_be_new(CB_CHAINING_BACKEND_TYPE,slapi_ch_strdup(inst->inst_name),0,0);
+ aPb=slapi_pblock_new();
+ slapi_pblock_set(aPb, SLAPI_PLUGIN, inst->backend_type->plugin);
+ slapi_be_setentrypoint(inst->inst_be,0,(void *)NULL,aPb);
+ slapi_be_set_instance_info(inst->inst_be,inst);
+ slapi_pblock_set(aPb, SLAPI_PLUGIN, NULL);
+ slapi_pblock_destroy(aPb);
+ }
+
+ cb_build_backend_instance_config(inst,e,1);
+
+ /* kexcoff: the order of the following calls is very important to prevent the deletion of the
+ instance to happen before the creation of the monitor part of the config.
+ However, not sure it solves all the situations, but at least it is worth to maintain
+ this order. */
+
+ if (!inst->isconfigured)
+ {
+ /* Add monitor entry and callback on it
+ * called from an add...
+ * we can't call recursively into the DSE to do more adds, they'll
+ * silently fail. instead, schedule the adds to happen in 1 second.
+ */
+ inst->eq_ctx = slapi_eq_once(cb_instance_add_monitor_later, (void *)inst, time(NULL)+1);
+ }
+
+ /* Get the list of operational attrs defined in the schema */
+ /* see cb_search file for a reason for that */
+
+ inst->every_attribute=slapi_schema_list_attribute_names(SLAPI_ATTR_FLAG_OPATTR);
+ charray_add(&inst->every_attribute,slapi_ch_strdup(LDAP_ALL_USER_ATTRS));
+
+ if (!inst->isconfigured)
+ {
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, inst->configDn,
+ LDAP_SCOPE_BASE,"(objectclass=*)",cb_instance_modify_config_check_callback, (void *) inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, inst->configDn,
+ LDAP_SCOPE_BASE,"(objectclass=*)",cb_instance_modify_config_callback, (void *) inst);
+
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, inst->configDn,
+ LDAP_SCOPE_BASE,"(objectclass=*)", cb_instance_search_config_callback, (void *) inst);
+
+ /* allow deletion otherwise impossible to remote a backend instance */
+ /* dynamically... */
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_POSTOP, inst->configDn,
+ LDAP_SCOPE_BASE,"(objectclass=*)", cb_instance_delete_config_callback, (void *) inst);
+ }
+
+ /* Notify the front-end */
+ /* After the call below, we can receive ops */
+ slapi_mtn_be_started(inst->inst_be);
+
+ inst->isconfigured=1;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+/* Create the default instance config from hard-coded values */
+
+int cb_create_default_backend_instance_config(cb_backend * cb) {
+
+
+ int rc;
+ cb_backend_instance *dummy;
+ Slapi_Entry *e=slapi_entry_alloc();
+ char defaultDn[CB_BUFSIZE];
+ char *olddn;
+ struct berval val;
+ struct berval *vals[2];
+ Slapi_PBlock *pb;
+
+ dummy = cb_instance_alloc(cb, "dummy", "o=dummy");
+ cb_instance_config_set_default(dummy);
+ cb_instance_search_config_callback(NULL,e,NULL, &rc, NULL,(void *) dummy);
+
+
+ /* set right dn and objectclass */
+
+ sprintf(defaultDn,"cn=default instance config,%s",cb->pluginDN);
+ olddn = slapi_entry_get_dn(e);
+ slapi_ch_free((void **) &olddn);
+
+ slapi_entry_set_dn(e,slapi_ch_strdup(defaultDn));
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ val.bv_val = "top";
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "objectclass", (struct berval **)vals );
+ val.bv_val = CB_CONFIG_EXTENSIBLEOCL;
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_merge( e, "objectclass", (struct berval **)vals );
+ val.bv_val = "default instance config";
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "cn", (struct berval **)vals );
+
+ /* create entry */
+ pb = slapi_pblock_new();
+ slapi_add_entry_internal_set_pb(pb, e, NULL, cb->identity, 0);
+ slapi_add_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if ( LDAP_SUCCESS != rc ) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Add %s failed (%s)\n",defaultDn,ldap_err2string(rc));
+ }
+
+ slapi_pblock_destroy(pb);
+ /* cleanup */
+ cb_instance_free(dummy);
+ /* BEWARE: entry is consummed */
+ return rc;
+}
+
+/* Extract backend instance configuration from the LDAP entry */
+
+int cb_build_backend_instance_config(cb_backend_instance *inst, Slapi_Entry * conf, int apply) {
+
+ cb_backend *cb = inst->backend_type;
+ Slapi_PBlock *default_pb;
+ Slapi_Entry **default_entries = NULL;
+ Slapi_Entry *default_conf=NULL;
+ int default_res, rc;
+ char defaultDn[CB_BUFSIZE];
+ cb_backend_instance * current_inst;
+
+ rc=LDAP_SUCCESS;
+
+ if (apply)
+ current_inst=inst;
+ else
+ current_inst=cb_instance_alloc(cb,inst->inst_name,"cn=dummy");
+
+ /* set default configuration */
+ cb_instance_config_set_default(current_inst);
+
+ /* 2: Overwrite values present in the default instance config */
+
+ sprintf(defaultDn,"cn=default instance config,%s",cb->pluginDN);
+
+ default_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(default_pb, defaultDn, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL, cb->identity, 0);
+ slapi_search_internal_pb (default_pb);
+ slapi_pblock_get(default_pb, SLAPI_PLUGIN_INTOP_RESULT, &default_res);
+ if ( LDAP_SUCCESS == default_res ) {
+ slapi_pblock_get(default_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &default_entries);
+ if (default_entries && default_entries[0] ) {
+
+ struct berval val;
+ struct berval *vals[2];
+ vals[0] = &val;
+ vals[1] = NULL;
+ default_conf=default_entries[0];
+
+ /* hack: add a dummy url (mandatory) to avoid error */
+ /* will be overwritten by the one in conf entry */
+ val.bv_val = "ldap://localhost/";
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( default_conf, CB_CONFIG_HOSTURL, (struct berval **)vals );
+
+ rc=cb_instance_config_initialize(current_inst,default_conf,CB_CONFIG_PHASE_STARTUP,1);
+ }
+ }
+ slapi_free_search_results_internal(default_pb);
+ slapi_pblock_destroy(default_pb);
+
+ if (rc == LDAP_SUCCESS)
+ rc=cb_instance_config_initialize(current_inst,conf,CB_CONFIG_PHASE_STARTUP,1);
+
+ if (!apply)
+ cb_instance_free(current_inst);
+
+ return rc;
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_modify.c b/ldap/servers/plugins/chainingdb/cb_modify.c
new file mode 100644
index 00000000..51aed6a3
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_modify.c
@@ -0,0 +1,244 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+static void cb_remove_illegal_mods(cb_backend_instance * inst, LDAPMod **mods);
+
+/*
+ * Perform a modify operation
+ *
+ * Returns:
+ * 0 - success
+ * <0 - fail
+ *
+ */
+
+int
+chaining_back_modify ( Slapi_PBlock *pb )
+{
+
+ Slapi_Backend *be;
+ cb_backend_instance *cb;
+ LDAPControl **ctrls, **serverctrls;
+ int rc,parse_rc,msgid,i;
+ LDAP *ld=NULL;
+ char **referrals=NULL;
+ LDAPMod ** mods;
+ LDAPMessage * res;
+ char *dn,* matched_msg, *error_msg;
+ char *cnxerrbuf=NULL;
+ time_t endtime;
+ cb_outgoing_conn *cnx;
+
+ if ( LDAP_SUCCESS != (rc=cb_forward_operation(pb) )) {
+ cb_send_ldap_result( pb, rc, NULL, "Chaining forbidden", 0, NULL );
+ return -1;
+ }
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ cb_update_monitor_info(pb,cb,SLAPI_OPERATION_MODIFY);
+
+ /* Check wether the chaining BE is available or not */
+ if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){
+ return -1;
+ }
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_TARGET, &dn );
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,"modify: target:<%s>\n",dn);
+ }
+
+
+ ctrls=serverctrls=NULL;
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &ctrls );
+
+ /* Check acls */
+
+ if ( cb->local_acl && !cb->associated_be_is_disabled ) {
+ char * errbuf=NULL;
+ Slapi_Entry *te = slapi_entry_alloc();
+ slapi_entry_set_dn(te,slapi_ch_strdup(dn));
+ rc = slapi_acl_check_mods( pb, te, mods, &errbuf);
+ slapi_entry_free(te);
+
+ if ( rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL, errbuf, 0, NULL );
+ slapi_ch_free((void **)&errbuf);
+ return -1;
+ }
+ }
+
+
+ /* Grab a connection handle */
+ if ((rc = cb_get_connection(cb->pool,&ld,&cnx,NULL,&cnxerrbuf)) != LDAP_SUCCESS) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, cnxerrbuf, 0, NULL);
+ slapi_ch_free((void **)&cnxerrbuf);
+ /* ping the farm. If the farm is unreachable, we increment the counter */
+ cb_ping_farm(cb,NULL,0);
+ return -1;
+ }
+
+ /* Control management */
+ if ( (rc = cb_update_controls( pb,ld,&ctrls,CB_UPDATE_CONTROLS_ADDAUTH )) != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL,NULL, 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ /* Don't free mods here: are freed at the do_modify level */
+ return -1;
+ }
+
+ if ( slapi_op_abandoned( pb )) {
+ cb_release_op_connection(cb->pool,ld,0);
+ /* Don't free mods here: are freed at the do_modify level */
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ return -1;
+ }
+
+ /* Remove illegal attributes from the mods */
+ cb_remove_illegal_mods(cb,mods);
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ /* Send LDAP operation to the remote host */
+ rc = ldap_modify_ext( ld, dn, mods, ctrls, NULL, &msgid );
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+
+ if ( rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ return -1;
+ }
+
+ while ( 1 ) {
+
+ if (cb_check_forward_abandon(cb,pb,ld,msgid)) {
+ /* connection handle released */
+ return -1;
+ }
+
+ rc = ldap_result( ld, msgid, 0, &cb->abandon_timeout, &res );
+ switch ( rc ) {
+ case -1:
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ return -1;
+ case 0:
+ if ((rc=cb_ping_farm(cb,cnx,endtime)) != LDAP_SUCCESS) {
+
+ /* does not respond. give up and return a*/
+ /* error to the client. */
+
+ /*cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);*/
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL, "FARM SERVER TEMPORARY UNAVAILABLE", 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ return -1;
+ }
+#ifdef CB_YIELD
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+#endif
+ break;
+ default:
+
+ matched_msg=error_msg=NULL;
+ serverctrls=NULL;
+ parse_rc = ldap_parse_result( ld, res, &rc, &matched_msg,
+ &error_msg, &referrals, &serverctrls, 1 );
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(parse_rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(parse_rc));
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free referrals */
+ if (referrals)
+ charray_free(referrals);
+ return -1;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ struct berval ** refs = referrals2berval(referrals);
+ cb_send_ldap_result( pb, rc, matched_msg, error_msg, 0, refs);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (refs)
+ ber_bvecfree(refs);
+ if (referrals)
+ charray_free(referrals);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ return -1;
+ }
+
+ cb_release_op_connection(cb->pool,ld,0);
+
+ /* Add control response sent by the farm server */
+
+ for (i=0; serverctrls && serverctrls[i];i++)
+ slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, serverctrls[i]);
+ /* SLAPI_ADD_RESCONTROL dups controls */
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free matched_msg, error_msg, and referrals if necessary */
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (referrals)
+ charray_free(referrals);
+ cb_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ return 0;
+ }
+ }
+
+ /* Never reached */
+ /* return 0; */
+}
+
+/* Function removes mods which are not allowed over-the-wire */
+static void
+cb_remove_illegal_mods(cb_backend_instance *inst, LDAPMod **mods)
+{
+ int i, j;
+ LDAPMod *tmp;
+
+ if ( inst->illegal_attributes != NULL ) { /* Unlikely to happen */
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+
+ for (j=0; inst->illegal_attributes[j]; j++) {
+ for ( i = 0; mods[i] != NULL; i++ ) {
+ if (slapi_attr_types_equivalent(inst->illegal_attributes[j],mods[i]->mod_type)) {
+ tmp = mods[i];
+ for ( j = i; mods[j] != NULL; j++ ) {
+ mods[j] = mods[j + 1];
+ }
+ slapi_ch_free( (void**)&(tmp->mod_type) );
+ if ( tmp->mod_bvalues != NULL ) {
+ ber_bvecfree( tmp->mod_bvalues );
+ }
+ slapi_ch_free( (void**)&tmp );
+ i--;
+ }
+ }
+ }
+
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_modrdn.c b/ldap/servers/plugins/chainingdb/cb_modrdn.c
new file mode 100644
index 00000000..e6b5dadb
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_modrdn.c
@@ -0,0 +1,239 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+ * Perform a modrdn operation
+ *
+ * Returns:
+ * 0 - success
+ * <0 - fail
+ *
+ */
+
+int
+chaining_back_modrdn ( Slapi_PBlock *pb )
+{
+
+ Slapi_Backend * be;
+ cb_backend_instance *cb;
+ LDAPControl **ctrls, **serverctrls;
+ int rc,parse_rc,msgid,i;
+ LDAP *ld=NULL;
+ char **referrals=NULL;
+ LDAPMessage * res;
+ char * matched_msg, *error_msg,* pdn, *newdn, *dn;
+ int deleteoldrdn=0;
+ char * newsuperior, *newrdn;
+ char * cnxerrbuf=NULL;
+ time_t endtime;
+ cb_outgoing_conn * cnx;
+
+ if ( LDAP_SUCCESS != (rc=cb_forward_operation(pb) )) {
+ cb_send_ldap_result( pb, rc, NULL, "Chaining forbidden", 0, NULL );
+ return -1;
+ }
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ cb_update_monitor_info(pb,cb,SLAPI_OPERATION_MODRDN);
+
+ /* Check wether the chaining BE is available or not */
+ if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){
+ return -1;
+ }
+
+ newsuperior=newdn=newrdn=dn=NULL;
+ slapi_pblock_get( pb, SLAPI_MODRDN_TARGET, &dn );
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn );
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperior );
+ slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &deleteoldrdn );
+
+ /*
+ * Construct the new dn
+ */
+
+ dn = slapi_dn_normalize_case(dn);
+ if ( (pdn = slapi_dn_parent( dn )) != NULL ) {
+ /* parent + rdn + separator(s) + null */
+ newdn = (char *) slapi_ch_malloc( strlen( pdn ) + strlen( newrdn ) + 3 );
+ strcpy( newdn, newrdn );
+ strcat( newdn, "," );
+ strcat( newdn, pdn );
+
+ slapi_ch_free((void **)&pdn );
+
+ } else {
+ newdn = slapi_ch_strdup( newrdn );
+ }
+
+ /*
+ * Make sure the current backend is managing
+ * the new dn. We won't support moving entries
+ * across backend this way.
+ * Done in the front-end.
+ */
+
+ slapi_ch_free((void **)&newdn);
+
+ if (cb->local_acl && !cb->associated_be_is_disabled) {
+ /*
+ * Check local acls
+ * Keep in mind We don't have the entry for acl evaluation
+ */
+
+ char * errbuf=NULL;
+ Slapi_Entry *te = slapi_entry_alloc();
+ slapi_entry_set_dn(te,slapi_ch_strdup(dn));
+ rc = cb_access_allowed (pb, te, NULL, NULL, SLAPI_ACL_WRITE,&errbuf);
+ slapi_entry_free(te);
+
+ if ( rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL, errbuf, 0, NULL );
+ slapi_ch_free((void **)&errbuf);
+ return -1;
+ }
+ }
+
+ /*
+ * Grab a connection handle
+ */
+
+ if ((rc = cb_get_connection(cb->pool,&ld,&cnx,NULL,&cnxerrbuf)) != LDAP_SUCCESS) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, cnxerrbuf, 0, NULL);
+ slapi_ch_free((void **)&cnxerrbuf);
+ /* ping the farm. If the farm is unreachable, we increment the counter */
+ cb_ping_farm(cb,NULL,0);
+ return -1;
+ }
+
+ /*
+ * Control management
+ */
+
+ if ( (rc = cb_update_controls( pb,ld,&ctrls,CB_UPDATE_CONTROLS_ADDAUTH )) != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, rc, NULL,NULL, 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ return -1;
+ }
+
+
+ if ( slapi_op_abandoned( pb )) {
+ cb_release_op_connection(cb->pool,ld,0);
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ return -1;
+ }
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ /*
+ * Send LDAP operation to the remote host
+ */
+
+ rc = ldap_rename ( ld,dn,newrdn,newsuperior,deleteoldrdn,ctrls,NULL,&msgid);
+
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ if ( rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ return -1;
+ }
+
+ while ( 1 ) {
+
+ if (cb_check_forward_abandon(cb,pb,ld,msgid)) {
+ return -1;
+ }
+
+ rc = ldap_result( ld, msgid, 0, &cb->abandon_timeout, &res );
+ switch ( rc ) {
+ case -1:
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ return -1;
+ case 0:
+ if ((rc=cb_ping_farm(cb,cnx,endtime)) != LDAP_SUCCESS) {
+
+ /* does not respond. give up and return a*/
+ /* error to the client. */
+
+ /*cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);*/
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL, "FARM SERVER TEMPORARY UNAVAILABLE", 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ return -1;
+ }
+#ifdef CB_YIELD
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+#endif
+ break;
+ default:
+ matched_msg=error_msg=NULL;
+ parse_rc = ldap_parse_result( ld, res, &rc, &matched_msg,
+ &error_msg, &referrals, &serverctrls, 1 );
+
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(parse_rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(parse_rc));
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free referrals */
+ if (referrals)
+ charray_free(referrals);
+ return -1;
+ }
+
+ if ( rc != LDAP_SUCCESS ) {
+ struct berval ** refs = referrals2berval(referrals);
+
+ cb_send_ldap_result( pb, rc, matched_msg, error_msg, 0, refs);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (refs)
+ ber_bvecfree(refs);
+ if (referrals)
+ charray_free(referrals);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ return -1;
+ }
+
+ cb_release_op_connection(cb->pool,ld,0);
+
+ /* Add control response sent by the farm server */
+
+ for (i=0; serverctrls && serverctrls[i];i++)
+ slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, serverctrls[i]);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ /* jarnou: free matched_msg, error_msg, and referrals if necessary */
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (referrals)
+ charray_free(referrals);
+ cb_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ return 0;
+ }
+ }
+
+ /* Never reached */
+ /* return 0; */
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_monitor.c b/ldap/servers/plugins/chainingdb/cb_monitor.c
new file mode 100644
index 00000000..11ef3bda
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_monitor.c
@@ -0,0 +1,228 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+extern cb_instance_config_info cb_the_instance_config[];
+/*
+** Chaining backend instance monitor function
+** This function wraps up backend specific monitoring information
+** and return it to the client as an LDAP entry.
+** This function is usually called upon receipt of the monitor
+** dn for this backend
+**
+** Monitor information:
+**
+** Database misc
+** database
+**
+** Number of hits for each operation
+** addopcount
+** modifyopcount
+** deleteopcount
+** modrdnopcount
+** compareopcount
+** searchsubtreeopcount
+** searchonelevelopcount
+** searchbaseopcount
+** bindopcount
+** unbindopcount
+** abandonopcount
+**
+** Outgoing connections
+** outgoingopconnections
+** outgoingbindconnections
+**
+*/
+
+int
+cb_search_monitor_callback(Slapi_PBlock * pb, Slapi_Entry * e, Slapi_Entry * entryAfter, int * returnCode, char * returnText, void * arg)
+{
+
+ char buf[CB_BUFSIZE];
+ struct berval val;
+ struct berval *vals[2];
+ int deletecount,addcount,modifycount,modrdncount,searchbasecount,searchonelevelcount;
+ int searchsubtreecount,abandoncount,bindcount,unbindcount,comparecount;
+ int outgoingconn, outgoingbindconn;
+ cb_backend_instance *inst = (cb_backend_instance *)arg;
+
+ /* First make sure the backend instance is configured */
+ /* If not, don't return anything */
+
+ PR_RWLock_Rlock(inst->rwl_config_lock);
+ if (!inst->isconfigured) {
+ *returnCode= LDAP_NO_SUCH_OBJECT;
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ slapi_lock_mutex(inst->monitor.mutex);
+
+ addcount =inst->monitor.addcount;
+ deletecount =inst->monitor.deletecount;
+ modifycount =inst->monitor.modifycount;
+ modrdncount =inst->monitor.modrdncount;
+ searchbasecount =inst->monitor.searchbasecount;
+ searchonelevelcount =inst->monitor.searchonelevelcount;
+ searchsubtreecount =inst->monitor.searchsubtreecount;
+ abandoncount =inst->monitor.abandoncount;
+ bindcount =inst->monitor.bindcount;
+ unbindcount =inst->monitor.unbindcount;
+ comparecount =inst->monitor.comparecount;
+
+ slapi_unlock_mutex(inst->monitor.mutex);
+
+ /*
+ ** Get connection information
+ */
+
+ slapi_lock_mutex(inst->pool->conn.conn_list_mutex);
+ outgoingconn= inst->pool->conn.conn_list_count;
+ slapi_unlock_mutex(inst->pool->conn.conn_list_mutex);
+
+ slapi_lock_mutex(inst->bind_pool->conn.conn_list_mutex);
+ outgoingbindconn= inst->bind_pool->conn.conn_list_count;
+ slapi_unlock_mutex(inst->bind_pool->conn.conn_list_mutex);
+
+ sprintf( buf, "%lu", addcount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_ADDCOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", deletecount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_DELETECOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", modifycount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_MODIFYCOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", modrdncount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_MODRDNCOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", searchbasecount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_SEARCHBASECOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", searchonelevelcount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_SEARCHONELEVELCOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", searchsubtreecount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_SEARCHSUBTREECOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", abandoncount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_ABANDONCOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", bindcount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_BINDCOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", unbindcount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_UNBINDCOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%lu", comparecount );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_COMPARECOUNT, ( struct berval **)vals );
+
+ sprintf( buf, "%d", outgoingconn );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_OUTGOINGCONN, ( struct berval **)vals );
+
+ sprintf( buf, "%d", outgoingbindconn );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, CB_MONITOR_OUTGOINGBINDCOUNT, ( struct berval **)vals );
+
+ *returnCode= LDAP_SUCCESS;
+ return(SLAPI_DSE_CALLBACK_OK);
+}
+
+void
+cb_update_monitor_info(Slapi_PBlock * pb, cb_backend_instance * inst,int op)
+{
+
+ int scope;
+
+ slapi_lock_mutex(inst->monitor.mutex);
+ switch (op) {
+ case SLAPI_OPERATION_ADD:
+ inst->monitor.addcount++;
+ break;
+ case SLAPI_OPERATION_MODIFY:
+ inst->monitor.modifycount++;
+ break;
+ case SLAPI_OPERATION_DELETE:
+ inst->monitor.deletecount++;
+ break;
+ case SLAPI_OPERATION_MODRDN:
+/** case SLAPI_OPERATION_MODDN: **/
+ inst->monitor.modrdncount++;
+ break;
+ case SLAPI_OPERATION_COMPARE:
+ inst->monitor.comparecount++;
+ break;
+ case SLAPI_OPERATION_ABANDON:
+ inst->monitor.abandoncount++;
+ break;
+ case SLAPI_OPERATION_BIND:
+ inst->monitor.bindcount++;
+ break;
+ case SLAPI_OPERATION_UNBIND:
+ inst->monitor.unbindcount++;
+ break;
+ case SLAPI_OPERATION_SEARCH:
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
+ if ( LDAP_SCOPE_BASE == scope )
+ inst->monitor.searchbasecount++;
+ else
+ if ( LDAP_SCOPE_ONELEVEL == scope )
+ inst->monitor.searchonelevelcount++;
+ else
+ inst->monitor.searchsubtreecount++;
+ break;
+ default:
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,"cb_update_monitor_info: invalid op type <%d>\n",op);
+ }
+ slapi_unlock_mutex(inst->monitor.mutex);
+}
+
+
+int
+cb_delete_monitor_callback(Slapi_PBlock * pb, Slapi_Entry * e, Slapi_Entry * entryAfter, int * returnCode, char * returnText, void * arg)
+{
+
+ cb_backend_instance *inst = (cb_backend_instance *)arg;
+
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, inst->monitorDn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", cb_search_monitor_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, inst->monitorDn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", cb_dont_allow_that);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, inst->monitorDn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", cb_delete_monitor_callback);
+
+ *returnCode= LDAP_SUCCESS;
+ return(SLAPI_DSE_CALLBACK_OK);
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_schema.c b/ldap/servers/plugins/chainingdb/cb_schema.c
new file mode 100644
index 00000000..2337b977
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_schema.c
@@ -0,0 +1,45 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+void cb_eliminate_illegal_attributes(cb_backend_instance * inst, Slapi_Entry * e) {
+
+ /* get rid of illegal attributes before sending op to the */
+ /* farm server. (Add) */
+
+ int rc,j;
+ Slapi_Attr *attr=NULL;
+ char *tobefreed=NULL;
+
+ if (inst->illegal_attributes != NULL ) { /* Unlikely to happen */
+
+ PR_RWLock_Wlock(inst->rwl_config_lock);
+
+ for (j=0; inst->illegal_attributes[j]; j++) {
+ char * aType=NULL;
+ rc=slapi_entry_first_attr(e,&attr);
+ while (rc==0) {
+ if (tobefreed) {
+ slapi_entry_attr_delete( e, tobefreed);
+ tobefreed=NULL;
+ }
+ slapi_attr_get_type(attr,&aType);
+ if (aType && slapi_attr_types_equivalent(inst->illegal_attributes[j],aType)) {
+ tobefreed=aType;
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "attribute <%s> not forwarded.\n",aType);
+ }
+ rc = slapi_entry_next_attr(e, attr, &attr);
+ }
+ if (tobefreed) {
+ slapi_entry_attr_delete( e, tobefreed);
+ tobefreed=NULL;
+ }
+ }
+
+ PR_RWLock_Unlock(inst->rwl_config_lock);
+ }
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_search.c b/ldap/servers/plugins/chainingdb/cb_search.c
new file mode 100644
index 00000000..d9cf6ef7
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_search.c
@@ -0,0 +1,698 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+ * Build a candidate list for this backentry and scope.
+ * Could be a BASE, ONELEVEL, or SUBTREE search.
+ *
+ * Returns:
+ * 0 - success
+ * <0 - fail
+ *
+ */
+
+int
+chainingdb_build_candidate_list ( Slapi_PBlock *pb )
+{
+
+ Slapi_Backend * be;
+ Slapi_Operation * op;
+ char *target, *filter;
+ int scope,attrsonly,sizelimit,timelimit,rc,searchreferral;
+ char **attrs=NULL;
+ LDAPControl **controls=NULL;
+ LDAPControl **ctrls=NULL;
+ LDAP *ld=NULL;
+ cb_backend_instance *cb = NULL;
+ cb_searchContext *ctx=NULL;
+ struct timeval timeout;
+ time_t optime;
+ int doit,parse_rc;
+ LDAPMessage *res=NULL;
+ char *matched_msg,*error_msg;
+ LDAPControl **serverctrls=NULL;
+ char **referrals=NULL;
+ char *cnxerrbuf=NULL;
+ time_t endbefore=0;
+ time_t endtime;
+ cb_outgoing_conn *cnx;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op );
+ slapi_pblock_get( pb, SLAPI_SEARCH_STRFILTER, &filter );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
+ slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &target );
+
+ if ( LDAP_SUCCESS != (parse_rc=cb_forward_operation(pb) )) {
+
+ /* Don't return errors */
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "local search: base:<%s> scope:<%s> filter:<%s>\n",target,
+ scope==LDAP_SCOPE_SUBTREE?"SUBTREE":scope==LDAP_SCOPE_ONELEVEL ? "ONE-LEVEL" : "BASE" , filter);
+ }
+
+ ctx = (cb_searchContext *)slapi_ch_calloc(1,sizeof(cb_searchContext));
+ ctx->type = CB_SEARCHCONTEXT_ENTRY;
+ ctx->data=NULL;
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ return 0;
+ }
+
+ cb_update_monitor_info(pb,cb,SLAPI_OPERATION_SEARCH);
+
+ /* Check wether the chaining BE is available or not */
+ if ( cb_check_availability( cb, pb ) == FARMSERVER_UNAVAILABLE ){
+ return -1;
+ }
+
+ if (cb_debug_on()) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "chained search: base:<%s> scope:<%s> filter:<%s>\n",target,
+ scope==LDAP_SCOPE_SUBTREE?"SUBTREE":scope==LDAP_SCOPE_ONELEVEL ? "ONE-LEVEL" : "BASE" , filter);
+ }
+
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs );
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &controls );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+
+
+ if ((scope != LDAP_SCOPE_BASE) && (scope != LDAP_SCOPE_ONELEVEL) && (scope != LDAP_SCOPE_SUBTREE)) {
+ cb_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "Bad scope", 0, NULL );
+ return 1;
+ }
+
+ searchreferral=cb->searchreferral;
+
+ if (( scope != LDAP_SCOPE_BASE ) && ( searchreferral )) {
+
+ int i;
+ struct berval bv,*bvals[2];
+ Slapi_Entry ** aciArray=(Slapi_Entry **) slapi_ch_malloc(2*sizeof(Slapi_Entry *));
+ Slapi_Entry *anEntry = slapi_entry_alloc();
+
+ slapi_entry_set_dn(anEntry,slapi_ch_strdup(target));
+
+ bvals[1]=NULL;
+ bvals[0]=&bv;
+ bv.bv_val="referral";
+ bv.bv_len=strlen(bv.bv_val);
+ slapi_entry_add_values( anEntry, "objectclass", bvals);
+
+ PR_RWLock_Rlock(cb->rwl_config_lock);
+ for (i=0; cb->url_array && cb->url_array[i]; i++) {
+ char * anUrl= slapi_ch_calloc(1,strlen(cb->url_array[i])+strlen(target)+1);
+ sprintf(anUrl,"%s%s",cb->url_array[i],target);
+ bv.bv_val=anUrl;
+ bv.bv_len=strlen(bv.bv_val);
+ slapi_entry_attr_merge( anEntry, "ref", bvals);
+ slapi_ch_free((void **)&anUrl);
+ }
+ PR_RWLock_Unlock(cb->rwl_config_lock);
+
+ aciArray[0]=anEntry;
+ aciArray[1]=NULL;
+
+ ctx = (cb_searchContext *)slapi_ch_calloc(1,sizeof(cb_searchContext));
+ ctx->type = CB_SEARCHCONTEXT_ENTRY;
+ ctx->data=aciArray;
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ return 0;
+ }
+
+ /*
+ ** Time limit management.
+ ** Make sure the operation has not expired
+ */
+
+ if ( timelimit == -1 ) {
+ timeout.tv_sec = timeout.tv_usec = 0;
+ } else {
+ time_t now=current_time();
+ endbefore=optime + timelimit;
+ if (now >= endbefore) {
+ cb_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL,NULL, 0, NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
+ return 1;
+ }
+ timeout.tv_sec=timelimit-(now-optime);
+ timeout.tv_usec=0;
+ }
+
+ /* Operational attribute support for internal searches: */
+ /* The front-end relies on the fact that operational attributes */
+ /* are returned along with standard attrs when the attr list is */
+ /* NULL. To make it work, we need to explicitly request for all*/
+ /* possible operational attrs. Too bad. */
+
+ if ( (attrs == NULL) && operation_is_flag_set(op, OP_FLAG_INTERNAL) ) {
+ attrs = cb->every_attribute;
+
+ }
+ else
+ {
+ int i;
+ if ( attrs != NULL )
+ {
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ if ( strcasecmp( "nsrole", attrs[i] ) == 0 )
+ {
+ attrs = cb->every_attribute;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Grab a connection handle */
+
+ if ( LDAP_SUCCESS != (rc = cb_get_connection(cb->pool,&ld,&cnx,&timeout,&cnxerrbuf))) {
+ if (rc == LDAP_TIMELIMIT_EXCEEDED)
+ cb_send_ldap_result( pb, rc, NULL,cnxerrbuf, 0, NULL);
+ else
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,cnxerrbuf, 0, NULL);
+
+ slapi_ch_free((void **)&cnxerrbuf);
+ /* ping the farm. If the farm is unreachable, we increment the counter */
+ cb_ping_farm(cb,NULL,0);
+ return 1;
+ }
+
+ /*
+ * Control management
+ */
+
+ if ( LDAP_SUCCESS != (rc = cb_update_controls( pb,ld,&ctrls,CB_UPDATE_CONTROLS_ADDAUTH ))) {
+ cb_send_ldap_result( pb, rc, NULL,NULL, 0, NULL);
+ cb_release_op_connection(cb->pool,ld,0);
+ return 1;
+ }
+
+ if ( slapi_op_abandoned( pb )) {
+ cb_release_op_connection(cb->pool,ld,0);
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+ return 1;
+ }
+
+ ctx = (cb_searchContext *) slapi_ch_calloc(1,sizeof(cb_searchContext));
+
+ /*
+ ** We need to store the connection handle in the search context
+ ** to make sure we reuse it in the next_entry iteration
+ ** Indeed, if another thread on this connection detects a problem
+ ** on this connection, it may reallocate a new connection and
+ ** a call to get_connection may return a new cnx. Too bad.
+ */
+
+ ctx->ld=ld;
+ ctx->cnx=cnx;
+
+ /* for some reasons, it is an error to pass in a zero'd timeval */
+ /* to ldap_search_ext() */
+ if ((timeout.tv_sec==0) && (timeout.tv_usec==0))
+ timeout.tv_sec=timeout.tv_usec=-1;
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ rc=ldap_search_ext(ld ,target,scope,filter,attrs,attrsonly,
+ ctrls, NULL, &timeout,sizelimit, &(ctx->msgid) );
+
+ if ( NULL != ctrls)
+ ldap_controls_free(ctrls);
+
+ if ( LDAP_SUCCESS != rc ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **) &ctx);
+ return 1;
+ }
+
+ /*
+ ** Need to get the very first result to handle
+ ** errors properly, especially no search base.
+ */
+
+ doit=1;
+ while (doit) {
+
+ if (cb_check_forward_abandon(cb,pb,ctx->ld,ctx->msgid)) {
+ slapi_ch_free((void **) &ctx);
+ return 1;
+ }
+
+ rc=ldap_result(ld,ctx->msgid,LDAP_MSG_ONE,&cb->abandon_timeout,&res);
+ switch ( rc ) {
+ case -1:
+ /* An error occurred. return now */
+ rc = ldap_get_lderrno(ld,NULL,NULL);
+ /* tuck away some errors in a OPERATION_ERROR */
+ if (CB_LDAP_CONN_ERROR(rc)) {
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string( rc ), 0, NULL);
+ } else {
+ cb_send_ldap_result(pb,rc, NULL, NULL,0,NULL);
+ }
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ slapi_ch_free((void **)&ctx);
+ return 1;
+ case 0:
+
+ /* Local timeout management */
+ if (timelimit != -1) {
+ if (current_time() > endbefore) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Local timeout expiration\n");
+
+ cb_send_ldap_result(pb,LDAP_TIMELIMIT_EXCEEDED,
+ NULL,NULL, 0, NULL);
+ /* Force connection close */
+ cb_release_op_connection(cb->pool,ld,1);
+ if (res)
+ ldap_msgfree(res);
+ slapi_ch_free((void **)&ctx);
+ return 1;
+ }
+ }
+ /* heart-beat management */
+ if ((rc=cb_ping_farm(cb,cnx,endtime)) != LDAP_SUCCESS) {
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+ cb_release_op_connection(cb->pool,ld,CB_LDAP_CONN_ERROR(rc));
+ if (res)
+ ldap_msgfree(res);
+ slapi_ch_free((void **)&ctx);
+ return 1;
+ }
+
+#ifdef CB_YIELD
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+#endif
+ break;
+ case LDAP_RES_SEARCH_ENTRY:
+ case LDAP_RES_SEARCH_REFERENCE:
+ /* Some results received */
+ /* don't parse result here */
+ ctx->pending_result=res;
+ ctx->pending_result_type=rc;
+ doit=0;
+ break;
+ case LDAP_RES_SEARCH_RESULT:
+ matched_msg=NULL;
+ error_msg=NULL;
+ referrals=NULL;
+ serverctrls=NULL;
+ parse_rc=ldap_parse_result(ld,res,&rc,&matched_msg,
+ &error_msg,&referrals, &serverctrls, 0 );
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result(pb,parse_rc,
+ matched_msg,error_msg,0,NULL);
+ rc=-1;
+ } else
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_get_lderrno( ctx->ld, &matched_msg, &error_msg );
+ cb_send_ldap_result( pb, rc, matched_msg,
+ error_msg,0,NULL);
+ /* BEWARE: matched_msg and error_msg points */
+ /* to ld fields. */
+ matched_msg=NULL;
+ error_msg=NULL;
+ rc=-1;
+ }
+
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ if (referrals)
+ charray_free(referrals);
+
+ if (rc!=LDAP_SUCCESS) {
+ cb_release_op_connection(cb->pool,ld,
+ CB_LDAP_CONN_ERROR(rc));
+ ldap_msgfree(res);
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ }
+
+ /* Store the msg in the ctx */
+ /* Parsed in iterate. */
+
+ ctx->pending_result=res;
+ ctx->pending_result_type=LDAP_RES_SEARCH_RESULT;
+ doit=0;
+ }
+ }
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ return 0;
+}
+
+/*
+ * Return the next entry in the result set. The entry is returned
+ * in the pblock.
+ * Returns 0 normally. If -1 is returned, it means that some
+ * exceptional condition, e.g. timelimit exceeded has occurred,
+ * and this routine has sent a result to the client. If zero
+ * is returned and no entry is available in the PBlock, then
+ * we've iterated through all the entries.
+ */
+
+int
+chainingdb_next_search_entry ( Slapi_PBlock *pb )
+{
+
+ char *target;
+ int sizelimit,timelimit, rc, parse_rc, optime,i,retcode, attrsonly;
+ LDAPMessage *res=NULL;
+ char *matched_msg,*error_msg;
+ cb_searchContext *ctx=NULL;
+ Slapi_Entry *entry;
+ LDAPControl **serverctrls=NULL;
+ char **referrals=NULL;
+ cb_backend_instance * cb=NULL;
+ Slapi_Backend * be;
+ time_t endtime;
+
+ matched_msg=error_msg=NULL;
+
+ slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &ctx );
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &target );
+ slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
+
+ cb = cb_get_instance(be);
+
+ if ( NULL == ctx ) {
+ /* End of local search */
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Unexpected NULL ctx in chainingdb_next_search_entry\n");
+ return 0;
+ }
+
+ if ( NULL != ctx->tobefreed ) {
+ slapi_entry_free(ctx->tobefreed);
+ ctx->tobefreed=NULL;
+ }
+
+ if ( ctx->type == CB_SEARCHCONTEXT_ENTRY ) {
+
+ int n;
+ Slapi_Entry ** ptr;
+ if ( (timelimit != -1) && (timelimit != 0)) {
+ time_t now=current_time();
+
+ if (now > (optime + timelimit)) {
+ cb_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL,NULL, 0, NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ for ( n = 0, ptr=(Slapi_Entry **)ctx->data; ptr != NULL && ptr[n] != NULL; n++ ) {
+ slapi_entry_free(ptr[n]);
+ }
+ if (ctx->data)
+ slapi_ch_free((void **)&ctx->data);
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ }
+ }
+
+ /*
+ ** Return the Slapi_Entry of the result set one
+ ** by one
+ */
+
+ for ( n = 0, ptr=(Slapi_Entry **)ctx->data; ptr != NULL && ptr[n] != NULL; n++ );
+ if ( n != 0) {
+ Slapi_Entry * anEntry=ptr[n-1];
+ ptr[n-1]=NULL;
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,anEntry);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ cb_set_acl_policy(pb);
+ ctx->tobefreed=anEntry;
+ } else {
+ slapi_ch_free((void **) &ctx);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+ }
+ return 0;
+ }
+
+ /*
+ * Grab a connection handle. Should be the same as the one
+ * used in the build_candidate list. To be certain of that, grab it from
+ * the context.
+ */
+
+ /* Poll the server for the results of the search operation.
+ * Passing LDAP_MSG_ONE indicates that you want to receive
+ * the entries one at a time, as they come in. If the next
+ * entry that you retrieve is NULL, there are no more entries.
+ */
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ while (1) {
+
+ if (cb_check_forward_abandon(cb,pb,ctx->ld,ctx->msgid)) {
+ /* cnx handle released */
+ if (ctx->pending_result)
+ ldap_msgfree(ctx->pending_result);
+ slapi_ch_free((void **) &ctx);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+ return -1;
+ }
+
+ /* Check for time limit done by the remote farm server */
+ /* Check for size limit done by the remote farm server */
+
+ /* Use pending msg if one is available */
+ if (ctx->pending_result) {
+ res=ctx->pending_result;
+ rc=ctx->pending_result_type;
+ ctx->pending_result=NULL;
+ } else {
+
+
+ rc=ldap_result(ctx->ld,ctx->msgid,
+ LDAP_MSG_ONE, &cb->abandon_timeout, &res );
+ }
+
+ /* The server can return three types of results back to the client,
+ * and the return value of ldap_result() indicates the result type:
+ * LDAP_RES_SEARCH_ENTRY identifies an entry found by the search,
+ * LDAP_RES_SEARCH_REFERENCE identifies a search reference returned
+ * by the server, and LDAP_RES_SEARCH_RESULT is the last result
+ * sent from the server to the client after the operation completes.
+ * We need to check for each of these types of results.
+ */
+
+ switch ( rc ) {
+ case -1:
+
+ /* An error occurred. */
+ rc = ldap_get_lderrno( ctx->ld, NULL, NULL );
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, ldap_err2string( rc ), 0, NULL);
+
+ if (res)
+ ldap_msgfree(res);
+ cb_release_op_connection(cb->pool,ctx->ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ case 0:
+ /* heart-beat management */
+ if ((rc=cb_ping_farm(cb,ctx->cnx,endtime)) != LDAP_SUCCESS) {
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ cb_send_ldap_result(pb,LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string(rc), 0, NULL);
+
+ if (res)
+ ldap_msgfree(res);
+ cb_release_op_connection(cb->pool,ctx->ld,CB_LDAP_CONN_ERROR(rc));
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ }
+#ifdef CB_YIELD
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+#endif
+ break;
+
+ case LDAP_RES_SEARCH_ENTRY:
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ /* The server sent one of the entries found by the search */
+ if ((entry = cb_LDAPMessage2Entry(ctx->ld,res,attrsonly)) == NULL) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,"Invalid entry received.\n");
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL , 0, NULL);
+
+ ldap_msgfree(res);
+ cb_release_op_connection(cb->pool,ctx->ld,0);
+ slapi_ch_free((void **)&ctx);
+ return -1;
+ }
+
+ ctx->tobefreed=entry;
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,entry);
+ cb_set_acl_policy(pb);
+ ldap_msgfree(res);
+ return 0;
+
+ case LDAP_RES_SEARCH_REFERENCE:
+
+ /* The server sent a search reference encountered during the
+ * search operation.
+ */
+
+ /* heart-beat management */
+ if (cb->max_idle_time>0)
+ endtime=current_time() + cb->max_idle_time;
+
+ parse_rc = ldap_parse_reference( ctx->ld, res, &referrals, NULL, 1 );
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ ldap_err2string( parse_rc ), 0, NULL);
+ cb_release_op_connection(cb->pool,ctx->ld,CB_LDAP_CONN_ERROR(parse_rc));
+ slapi_ch_free((void **)&ctx);
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+ return -1;
+ }
+
+ /*
+ ** build a dummy entry on the fly with a ref attribute
+ */
+
+ {
+
+ struct berval bv;
+ int i;
+ struct berval *bvals[2];
+ Slapi_Entry *anEntry = slapi_entry_alloc();
+ slapi_entry_set_dn(anEntry,slapi_ch_strdup(target));
+
+ bvals[1]=NULL;
+ bvals[0]=&bv;
+
+ bv.bv_val="referral";
+ bv.bv_len=strlen(bv.bv_val);
+ slapi_entry_add_values( anEntry, "objectclass", bvals);
+
+ for (i=0;referrals[i] != NULL; i++) {
+ bv.bv_val=referrals[i];
+ bv.bv_len=strlen(bv.bv_val);
+ slapi_entry_add_values( anEntry, "ref", bvals);
+ }
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,ctx);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,anEntry);
+ cb_set_acl_policy(pb);
+ }
+
+ if (referrals != NULL) {
+ ldap_value_free( referrals );
+ }
+
+ return 0;
+
+ case LDAP_RES_SEARCH_RESULT:
+
+ /* Parse the final result received from the server. Note the last
+ * argument is a non-zero value, which indicates that the
+ * LDAPMessage structure will be freed when done.
+ */
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET,NULL);
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY,NULL);
+
+ parse_rc = ldap_parse_result( ctx->ld, res,
+ &rc,&matched_msg,&error_msg, &referrals, &serverctrls, 1 );
+ if ( parse_rc != LDAP_SUCCESS ) {
+ cb_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, matched_msg,
+ ldap_err2string( parse_rc ), 0, NULL);
+
+ retcode=-1;
+ } else
+ if ( rc != LDAP_SUCCESS ) {
+ ldap_get_lderrno( ctx->ld, &matched_msg, &error_msg );
+ cb_send_ldap_result( pb, rc, matched_msg, NULL, 0, NULL);
+
+ /* BEWARE: Don't free matched_msg && error_msg */
+ /* Points to the ld fields */
+ matched_msg=NULL;
+ error_msg=NULL;
+ retcode=-1;
+ } else {
+ /* Add control response sent by the farm server */
+ for (i=0; serverctrls && serverctrls[i];i++)
+ slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, serverctrls[i]);
+ retcode=0;
+ }
+
+ if (serverctrls)
+ ldap_controls_free(serverctrls);
+ slapi_ch_free((void **)&matched_msg);
+ slapi_ch_free((void **)&error_msg);
+ if (referrals)
+ charray_free(referrals);
+
+ cb_release_op_connection(cb->pool,ctx->ld,0);
+ slapi_ch_free((void **)&ctx);
+ return retcode;
+
+ default:
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "chainingdb_next_search_entry:default case.\n");
+
+ }
+ }
+
+ /* Not reached */
+ /* return 0; */
+}
+
+int
+chaining_back_entry_release ( Slapi_PBlock *pb ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM, "chaining_back_entry_release\n");
+ return 0;
+}
+
diff --git a/ldap/servers/plugins/chainingdb/cb_size.c b/ldap/servers/plugins/chainingdb/cb_size.c
new file mode 100644
index 00000000..a6f1fb20
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_size.c
@@ -0,0 +1,22 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+int
+cb_db_size( Slapi_PBlock *pb )
+{
+
+ /*
+ ** Return the size in byte of the local database storage
+ ** Size is 0 for a chaining backend
+ */
+
+ unsigned int size=0;
+
+ slapi_pblock_set( pb, SLAPI_DBSIZE, &size );
+ return 0;
+}
+
diff --git a/ldap/servers/plugins/chainingdb/cb_start.c b/ldap/servers/plugins/chainingdb/cb_start.c
new file mode 100644
index 00000000..c4a4538b
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_start.c
@@ -0,0 +1,43 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+int
+chainingdb_start ( Slapi_PBlock *pb ) {
+
+ cb_backend * cb;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &cb );
+
+ if (cb->started) {
+ /* We may be called multiple times due to */
+ /* plugin dependency resolution */
+ return 0;
+ }
+
+ /*
+ ** Reads in any configuration information held in the dse for the
+ ** chaining plugin. Create dse entries used to configure the
+ ** chaining plugin if they don't exist. Registers plugins to maintain
+ ** those dse entries.
+ */
+
+ cb_config_load_dse_info(pb);
+
+ /* Register new LDAPv3 controls supported by the chaining backend */
+
+ slapi_register_supported_control( CB_LDAP_CONTROL_CHAIN_SERVER,
+ SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE
+ | SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE
+ | SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN );
+
+ /* register to be notified when backend state changes */
+ slapi_register_backend_state_change((void *)cb_be_state_change,
+ cb_be_state_change);
+
+ cb->started=1;
+ return 0;
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_temp.c b/ldap/servers/plugins/chainingdb/cb_temp.c
new file mode 100644
index 00000000..fc5407ff
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_temp.c
@@ -0,0 +1,15 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/*
+** Temp wrappers until the appropriate functions
+** are implemented in the slapi interface
+*/
+
+cb_backend_instance * cb_get_instance(Slapi_Backend * be) {
+ return (cb_backend_instance *)slapi_be_get_instance_info(be);
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_test.c b/ldap/servers/plugins/chainingdb/cb_test.c
new file mode 100644
index 00000000..cb075664
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_test.c
@@ -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 **/
+#include "cb.h"
+
+int cb_back_test( Slapi_PBlock *pb )
+{
+
+ Slapi_Backend * be;
+ cb_backend * cb;
+ cb_backend_instance * inst;
+ Slapi_PBlock * apb;
+ int res;
+ int rc=0;
+ const Slapi_DN *aSuffix=NULL;
+ const char * aSuffixString;
+ char * theTarget;
+
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &cb );
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ inst = cb_get_instance(be);
+ apb = slapi_pblock_new();
+
+ /*
+ ** Try to open a connection to the farm server
+ ** Try to get a dummy entry BELOW the suffix managed
+ ** by the chaining backend, in case the local root is shared
+ ** across different backend
+ */
+
+ printf("Begin test instance %s.\n",inst->inst_name);
+
+ aSuffix = slapi_be_getsuffix(be,0);
+ aSuffixString=slapi_sdn_get_dn(aSuffix);
+ /* Remove leading white spaces */
+ for (aSuffixString; *aSuffixString==' ';aSuffixString++) {}
+ theTarget=slapi_ch_calloc(1,strlen(aSuffixString)+20);
+ sprintf(theTarget,"cn=test,%s",aSuffixString);
+
+ /* XXXSD make sure chaining allowed for this plugin... */
+ slapi_search_internal_set_pb (apb, theTarget, LDAP_SCOPE_BASE, "objectclass=*", NULL, 0, NULL, NULL,
+ cb->identity,0 );
+ slapi_search_internal_pb (apb);
+
+ slapi_ch_free((void **)&theTarget);
+
+ if ( NULL == apb ) {
+ printf("Can't contact farm server. (Internal error).\n");
+ rc=-1;
+ goto the_end;
+ }
+
+ slapi_pblock_get(apb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ /* OPERATIONS ERRORS also returned when bind failed */
+ if (CB_LDAP_CONN_ERROR(res) || (res==LDAP_OPERATIONS_ERROR ))
+ {
+ printf("Can't contact the remote farm server %s. (%s).\n",inst->pool->hostname,ldap_err2string(res));
+ rc=-1;
+ goto the_end;
+ } else {
+ printf("Connection established with the remote farm server %s.\n",inst->pool->hostname);
+ }
+
+the_end:
+ if (apb)
+ {
+ slapi_free_search_results_internal(apb);
+ slapi_pblock_destroy (apb);
+ }
+
+ return rc;
+}
+
diff --git a/ldap/servers/plugins/chainingdb/cb_unbind.c b/ldap/servers/plugins/chainingdb/cb_unbind.c
new file mode 100644
index 00000000..1400ae1f
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_unbind.c
@@ -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 **/
+#include "cb.h"
+
+int
+chainingdb_unbind( Slapi_PBlock *pb ) {
+
+ /* Nothing to do because connection mgmt is stateless*/
+
+ Slapi_Backend * be;
+ cb_backend_instance * cb;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ cb_update_monitor_info(pb,cb,SLAPI_OPERATION_UNBIND);
+
+ cb_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ return SLAPI_BIND_SUCCESS;
+}
diff --git a/ldap/servers/plugins/chainingdb/cb_utils.c b/ldap/servers/plugins/chainingdb/cb_utils.c
new file mode 100644
index 00000000..b73effd0
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cb_utils.c
@@ -0,0 +1,375 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+/* return the rootdn configured in the server */
+
+char * cb_get_rootdn() {
+
+ char * ret=slapi_get_rootdn();
+ if (ret == NULL)
+ ret = slapi_ch_strdup(CB_DIRECTORY_MANAGER_DN);
+ if (ret)
+ slapi_dn_normalize_case(ret); /* UTF8-aware */
+ return ret;
+}
+
+void
+cb_send_ldap_result(Slapi_PBlock *pb, int err, char *matched,char *text, int nentries, struct berval **urls )
+{
+ cb_set_acl_policy(pb);
+ slapi_send_ldap_result( pb, err, matched, text, nentries ,urls);
+}
+
+Slapi_Entry * cb_LDAPMessage2Entry(LDAP * ld, LDAPMessage * msg, int attrsonly) {
+
+ Slapi_Entry * e = slapi_entry_alloc();
+ char * a=NULL;
+ BerElement * ber=NULL;
+
+ if ( e == NULL ) return NULL;
+ if (msg == NULL) {
+ slapi_entry_free(e);
+ return NULL;
+ }
+
+ /*
+ * dn not allocated by slapi
+ * attribute type and values ARE allocated
+ */
+
+ slapi_entry_set_dn( e, ldap_get_dn( ld, msg ) );
+
+ for ( a = ldap_first_attribute( ld, msg, &ber ); a!=NULL;
+ a=ldap_next_attribute( ld, msg, ber ) ) {
+ if(attrsonly) {
+ slapi_entry_add_value(e, a, (Slapi_Value *)NULL);
+ ldap_memfree(a);
+ } else {
+ struct berval ** aVal = ldap_get_values_len( ld, msg, a);
+ slapi_entry_add_values( e, a, aVal);
+
+ ldap_memfree(a);
+ ldap_value_free_len(aVal);
+ }
+ }
+ if ( NULL != ber )
+ ldap_ber_free( ber, 0 );
+
+ return e;
+}
+
+struct berval ** referrals2berval(char ** referrals) {
+
+ int i;
+ struct berval ** val=NULL;
+
+ if (referrals == NULL)
+ return NULL;
+
+ for (i=0;referrals[i];i++) {}
+
+ val = (struct berval **) slapi_ch_calloc(1,(i+1)*sizeof(struct berval *));
+
+ for (i=0;referrals[i];i++) {
+
+ val[i]=(struct berval *) slapi_ch_malloc(sizeof(struct berval));
+ val[i]->bv_len= strlen(referrals[i]);
+ val[i]->bv_val = slapi_ch_strdup(referrals[i]);
+ }
+
+ return val;
+}
+
+char *
+cb_urlparse_err2string( int err )
+{
+ char *s="internal error";
+
+ switch( err ) {
+ case 0:
+ s = "no error";
+ break;
+ case LDAP_URL_ERR_NOTLDAP:
+ s = "missing ldap:// or ldaps://";
+ break;
+ case LDAP_URL_ERR_NODN:
+ s = "missing suffix";
+ break;
+ case LDAP_URL_ERR_BADSCOPE:
+ s = "invalid search scope";
+ break;
+ case LDAP_URL_ERR_MEM:
+ s = "unable to allocate memory";
+ break;
+ case LDAP_URL_ERR_PARAM:
+ s = "bad parameter to an LDAP URL function";
+ break;
+ }
+
+ return( s );
+}
+
+/*
+** Return LDAP_SUCCESS if an internal operation needs to be forwarded to
+** the farm server. We check chaining policy for internal operations
+** We also check max hop count for loop detection for both internal
+** and external operations
+*/
+
+int cb_forward_operation(Slapi_PBlock * pb ) {
+
+ Slapi_Operation *op=NULL;
+ Slapi_Backend *be;
+ struct slapi_componentid *cid = NULL;
+ char *pname;
+ cb_backend_instance *cb;
+ int retcode;
+ LDAPControl **ctrls=NULL;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &op);
+
+ /* Loop detection */
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &ctrls );
+
+ if ( NULL != ctrls ) {
+ struct berval *ctl_value=NULL;
+ int iscritical=0;
+
+ if (slapi_control_present(ctrls,CB_LDAP_CONTROL_CHAIN_SERVER,&ctl_value,&iscritical)) {
+
+ /* Decode control data */
+ /* hop INTEGER (0 .. maxInt) */
+
+ int hops = 0;
+ int rc;
+ BerElement *ber = NULL;
+
+ if ((ber = ber_init(ctl_value)) == NULL) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "cb_forward_operation: ber_init: Memory allocation failed");
+ return LDAP_NO_MEMORY;
+ }
+ rc = ber_scanf(ber,"i",&hops);
+ if (LBER_ERROR == rc) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Loop detection control badly encoded.");
+ ber_free(ber,1);
+ return LDAP_LOOP_DETECT;
+ }
+
+ if (hops <=0) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "Max hop count exceeded. Loop detected.\n");
+ ber_free(ber,1);
+ return LDAP_LOOP_DETECT;
+ }
+ ber_free(ber,1);
+ }
+ }
+
+ if ( !operation_is_flag_set(op, OP_FLAG_INTERNAL))
+ return LDAP_SUCCESS;
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &cid);
+ if ( cid == NULL ) {
+ /* programming error in the front-end */
+ slapi_log_error(SLAPI_LOG_FATAL, CB_PLUGIN_SUBSYSTEM,
+ "NULL component identity in an internal operation.");
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ pname=cid->sci_component_name;
+
+ if (cb_debug_on()) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, CB_PLUGIN_SUBSYSTEM,
+ "internal op received from %s component \n",pname ? pname : "NULL");
+ }
+
+ /* First, make sure chaining is not denied */
+ if (operation_is_flag_set(op, SLAPI_OP_FLAG_NEVER_CHAIN))
+ return LDAP_UNWILLING_TO_PERFORM;
+
+ /* unidentified caller. should not happen */
+ if (pname == NULL)
+ return LDAP_UNWILLING_TO_PERFORM;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ cb = cb_get_instance(be);
+
+ /* Local policy */
+ PR_RWLock_Rlock(cb->rwl_config_lock);
+ if ( cb->chaining_components != NULL ) {
+ retcode=charray_inlist(cb->chaining_components,pname);
+ PR_RWLock_Unlock(cb->rwl_config_lock);
+ if ( retcode )
+ retcode=LDAP_SUCCESS;
+ else
+ retcode=LDAP_UNWILLING_TO_PERFORM;
+ return retcode;
+ }
+ PR_RWLock_Unlock(cb->rwl_config_lock);
+
+ /* Global policy */
+ PR_RWLock_Rlock(cb->backend_type->config.rwl_config_lock);
+ retcode=charray_inlist(cb->backend_type->config.chaining_components,pname);
+ PR_RWLock_Unlock(cb->backend_type->config.rwl_config_lock);
+
+ if ( retcode )
+ retcode=LDAP_SUCCESS;
+ else
+ retcode=LDAP_UNWILLING_TO_PERFORM;
+ return retcode;
+}
+
+/* better atol -- it understands a trailing multiplier k/m/g
+ * for example, "32k" will be returned as 32768
+ */
+long cb_atol(char *str)
+{
+ long multiplier = 1;
+ char *x = str;
+
+ /* find possible trailing k/m/g */
+ while ((*x >= '0') && (*x <= '9')) x++;
+ switch (*x) {
+ case 'g':
+ case 'G':
+ multiplier *= 1024;
+ case 'm':
+ case 'M':
+ multiplier *= 1024;
+ case 'k':
+ case 'K':
+ multiplier *= 1024;
+ }
+ return (atol(str) * multiplier);
+}
+
+int cb_atoi(char *str)
+{
+ return (int)cb_atol(str);
+}
+
+
+/* This function is used by the instance modify callback to add a new
+ * suffix. It return LDAP_SUCCESS on success.
+ */
+int cb_add_suffix(cb_backend_instance *inst, struct berval **bvals, int apply_mod, char *returntext)
+{
+ Slapi_DN *suffix;
+ int x;
+
+ returntext[0] = '\0';
+ for (x = 0; bvals[x]; x++) {
+ suffix=slapi_sdn_new_dn_byval(bvals[x]->bv_val);
+ if (!slapi_be_issuffix(inst->inst_be, suffix) && apply_mod) {
+ slapi_be_addsuffix(inst->inst_be, suffix);
+ }
+ slapi_sdn_free(&suffix);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int debug_on=0;
+
+int cb_debug_on()
+{
+ return debug_on;
+}
+
+void cb_set_debug(int on) {
+ debug_on=on;
+}
+
+/* this function is called when state of a backend changes */
+/* The purpose of this function is to handle the associated_be_is_disabled
+ flag in the cb instance structure. The associated database is used to
+ perform local acl evaluations. The associated database can be
+ 1) The chaining backend is the backend of a sub suffix, and the
+ parent suffix has a local backend
+ 2) Entry distribution is being used to distribute write operations to
+ a chaining backend and other operations to a local backend
+ (e.g. a replication hub or consumer)
+ If the associated local backend is being initialized (import), it will be
+ disabled, and it will be impossible to evaluate local acls. In this case,
+ we still want to be able to chain operations to a farm server or another
+ database chain. But the current code will not allow cascading without
+ local acl evaluation (cb_controls.c). associated_be_is_disabled allows
+ us to relax that restriction while the associated backend is disabled
+*/
+/*
+ The first thing we need to do is to determine what our associated backends
+ are. An associated backend is defined as a backend used by the same
+ suffix which uses this cb instance or a backend used by any
+ parent suffix of the suffix which uses this cb instance
+
+ We first see if the be_name is for a local database. If not, then just return.
+ So for the given be_name, we find the suffix which uses it, then the mapping tree
+ entry for that suffix. Then
+ get cb instances used by the suffix and set associated_be_is_disabled
+ get cb instances used by sub suffixes of this suffix and
+ set associated_be_is_disabled
+*/
+void
+cb_be_state_change (void *handle, char *be_name, int old_be_state, int new_be_state)
+{
+ const Slapi_DN *tmpsdn;
+ Slapi_DN *the_be_suffix;
+ char *cookie = NULL;
+ Slapi_Backend *chainbe;
+ Slapi_Backend *the_be = slapi_be_select_by_instance_name(be_name);
+
+ /* no backend? */
+ if (!the_be) {
+ return;
+ }
+
+ /* ignore chaining backends - associated backends must be local */
+ if (slapi_be_is_flag_set(the_be, SLAPI_BE_FLAG_REMOTE_DATA)) {
+ return;
+ }
+
+ /* get the suffix for the local backend */
+ tmpsdn = slapi_be_getsuffix(the_be, 0);
+ if (!tmpsdn) {
+ return;
+ } else {
+ the_be_suffix = slapi_sdn_dup(tmpsdn);
+ }
+
+ /* now, iterate through the chaining backends */
+ for (chainbe = slapi_get_first_backend(&cookie);
+ chainbe; chainbe = slapi_get_next_backend(cookie)) {
+ /* only look at chaining backends */
+ if (slapi_be_is_flag_set(chainbe, SLAPI_BE_FLAG_REMOTE_DATA)) {
+ /* get the suffix */
+ const Slapi_DN *tmpcbsuf = slapi_be_getsuffix(chainbe, 0);
+ if (tmpcbsuf) {
+ /* make a copy - to be safe */
+ Slapi_DN *cbsuffix = slapi_sdn_dup(tmpcbsuf);
+ /* if the suffixes are equal, or the_be_suffix is a suffix
+ of cbsuffix, apply the flag */
+ if (!slapi_sdn_compare(cbsuffix, the_be_suffix) ||
+ slapi_sdn_issuffix(cbsuffix, the_be_suffix)) {
+ cb_backend_instance *cbinst = cb_get_instance(chainbe);
+ if (cbinst) {
+ /* the backend is disabled if the state is not ON */
+ cbinst->associated_be_is_disabled = (new_be_state != SLAPI_BE_STATE_ON);
+ slapi_log_error(SLAPI_LOG_PLUGIN, "chainbe", "cb_be_state_change: set the "
+ "state of chainbe for %s to %d\n",
+ slapi_sdn_get_dn(cbsuffix), (new_be_state != SLAPI_BE_STATE_ON));
+ }
+ }
+ slapi_sdn_free(&cbsuffix);
+ }
+ }
+ }
+
+ /* clean up */
+ slapi_sdn_free(&the_be_suffix);
+ slapi_ch_free_string(&cookie);
+}
diff --git a/ldap/servers/plugins/chainingdb/cbdllmain.c b/ldap/servers/plugins/chainingdb/cbdllmain.c
new file mode 100644
index 00000000..cacf9cb5
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/cbdllmain.c
@@ -0,0 +1,128 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "cb.h"
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
+
+#ifdef LDAP_DEBUG
+#ifndef _WIN32
+#include <stdarg.h>
+#include <stdio.h>
+
+void LDAPDebug( int level, char* fmt, ... )
+{
+ static char debugBuf[1024];
+
+ if (module_ldap_debug && (*module_ldap_debug & level))
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ _snprintf (debugBuf, sizeof(debugBuf), fmt, ap);
+ va_end (ap);
+
+ OutputDebugString (debugBuf);
+ }
+}
+#endif
+#endif
+
+#ifndef _WIN32
+
+/* The 16-bit version of the RTL does not implement perror() */
+
+#include <stdio.h>
+
+void perror( const char *msg )
+{
+ char buf[128];
+ wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ;
+ OutputDebugString( buf );
+}
+
+#endif
diff --git a/ldap/servers/plugins/chainingdb/libcb.def b/ldap/servers/plugins/chainingdb/libcb.def
new file mode 100644
index 00000000..71fe8482
--- /dev/null
+++ b/ldap/servers/plugins/chainingdb/libcb.def
@@ -0,0 +1,15 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+;
+;
+DESCRIPTION 'Netscape Directory Server 7 Chaining Database Plugin'
+;CODE SHARED READ EXECUTE
+;DATA SHARED READ WRITE
+EXPORTS
+ chaining_back_init @1
+ plugin_init_debug_level @2
+ cb_be_state_change @3
diff --git a/ldap/servers/plugins/collation/Makefile b/ldap/servers/plugins/collation/Makefile
new file mode 100644
index 00000000..14619af7
--- /dev/null
+++ b/ldap/servers/plugins/collation/Makefile
@@ -0,0 +1,99 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+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= $(OBJDIR)/lib/liblcoll
+LIBDIR= $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+INCLUDES+= -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+COLLATION_OBJS= collate.o config.o orfilter.o
+
+ifeq ($(ARCH), WINNT)
+COLLATION_OBJS+= debug.o
+COLLATION_DLL_OBJ=$(addprefix $(OBJDEST)/, dllmain.o)
+DEF_FILE:=./collation.def
+EXTRA_LIBS+= $(NSPRLINK) $(LDAP_SDK_LIBLDAP_DLL) $(LIBSLAPD)
+EXTRA_LIBS_DEP+= $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP+=$(LDAPSDK_DEP)
+endif
+
+# INCLUDES+= -I. -I$(ACLINC) -I$(MCOM_ROOT)/ldapserver/lib
+
+# ICU stuff
+INCLUDES+= $(ICU_INCLUDE)
+EXTRA_LIBS+=$(ICULINK)
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS+= $(LIBSLAPDLINK) $(NSPRLINK) $(LDAPLINK)
+EXTRA_LIBS_DEP+= $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP+=$(LDAPSDK_DEP)
+LD=ld
+endif
+
+OBJS= $(addprefix $(OBJDEST)/, $(COLLATION_OBJS))
+COLLATION= $(addprefix $(LIBDIR)/, $(COLLATION_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(COLLATION)
+ifeq (0, 1)
+# Where the heck did the compiler options come from?
+ @echo ARCH=$(ARCH)
+ @echo DEBUG=$(DEBUG)
+ @echo BUILD_OPT=$(BUILD_OPT)
+ @echo CFLAGS=$(CFLAGS)
+ @echo " MCC_DEBUG="$(MCC_DEBUG)
+ @echo " PLATFORMCFLAGS="$(PLATFORMCFLAGS)
+ @echo " ACFLAGS="$(ACFLAGS)
+ @echo " EXTRACFLAGS="$(EXTRACFLAGS)
+ @echo " UNPROTOCFLAGS="$(UNPROTOCFLAGS)
+ @echo " SLCFLAGS="$(SLCFLAGS)
+ @echo "ALDFLAGS="$(ALDFLAGS)
+ @echo "DLL_LDFLAGS="$(DLL_LDFLAGS)
+ @echo "DLL_EXPORT_FLAGS="$(DLL_EXPORT_FLAGS)
+endif
+
+ifeq ($(ARCH), WINNT)
+$(COLLATION): $(OBJS) $(COLLATION_DLL_OBJ) $(EXTRA_LIBS_DEP) $(DEF_FILE)
+ $(LINK_DLL) $(COLLATION_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+ifeq ($(ARCH), AIX)
+$(COLLATION): $(OBJS) $(COLLATION_DLL_OBJ) $(EXTRA_LIBS_DEP)
+ $(LINK_DLL) $(COLLATION_DLL_OBJ) $(EXTRA_LIBS)
+else
+$(COLLATION): $(OBJS) $(EXTRA_LIBS_DEP)
+ $(LINK_DLL) $(EXTRA_LIBS)
+endif
+endif
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(COLLATION_DLL_OBJ)
+endif
+ $(RM) $(COLLATION)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
diff --git a/ldap/servers/plugins/collation/collate.c b/ldap/servers/plugins/collation/collate.c
new file mode 100644
index 00000000..603caf53
--- /dev/null
+++ b/ldap/servers/plugins/collation/collate.c
@@ -0,0 +1,454 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* collate.c - implementation of indexing, using a Collation */
+
+#include "collate.h"
+#include <string.h> /* memcpy */
+
+#include <unicode/ucol.h> /* Collation */
+#include <unicode/ucnv.h> /* Conversion */
+#include <unicode/ustring.h> /* UTF8 conversion */
+
+#include <ldap.h> /* LDAP_UTF8LEN */
+#include <slap.h> /* for strcasecmp on non-UNIX platforms and correct debug macro */
+
+void
+collation_init( char *configpath )
+ /* Called once per process, to initialize globals. */
+{
+ /* ICU needs no initialization? */
+}
+
+typedef struct coll_profile_t { /* Collator characteristics */
+ const char* language;
+ const char* country;
+ const char* variant;
+ UColAttributeValue strength; /* one of UCOL_PRIMARY = 0, UCOL_SECONDARY = 1, UCOL_TERTIARY = 2, UCOL_QUATERNARY = 3, UCOL_IDENTICAL = 4 */
+ UColAttributeValue decomposition; /* one of UCOL_OFF = 0, UCOL_DEFAULT = 1, UCOL_ON = 2 */
+} coll_profile_t;
+
+typedef struct coll_id_t { /* associates an OID with a coll_profile_t */
+ char* oid;
+ coll_profile_t* profile;
+} coll_id_t;
+
+/* A list of all OIDs that identify collator profiles: */
+static const coll_id_t** collation_id = NULL;
+static size_t collation_ids = 0;
+
+int
+collation_config (size_t cargc, char** cargv,
+ const char* fname, size_t lineno)
+ /* Process one line from a configuration file.
+ Return 0 if it's OK, -1 if it's not recognized.
+ Any other return value is a process exit code.
+ */
+{
+ if (cargc <= 0) { /* Bizarre. Oh, well... */
+ } else if (!strcasecmp (cargv[0], "NLS")) {
+ /* ignore - not needed anymore with ICU - was used to get path for NLS_Initialize */
+ } else if (!strcasecmp (cargv[0], "collation")) {
+ if ( cargc < 7 ) {
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "%s: line %lu ignored: only %lu arguments (expected "
+ "collation language country variant strength decomposition oid ...)\n",
+ fname, (unsigned long)lineno, (unsigned long)cargc );
+ } else {
+ auto size_t arg;
+ auto coll_profile_t* profile = (coll_profile_t*) slapi_ch_calloc (1, sizeof (coll_profile_t));
+ if (*cargv[1]) profile->language = slapi_ch_strdup (cargv[1]);
+ if (*cargv[2]) profile->country = slapi_ch_strdup (cargv[2]);
+ if (*cargv[3]) profile->variant = slapi_ch_strdup (cargv[3]);
+ switch (atoi(cargv[4])) {
+ case 1: profile->strength = UCOL_PRIMARY; break;
+ case 2: profile->strength = UCOL_SECONDARY; /* no break here? fall through? wtf? */
+ case 3: profile->strength = UCOL_TERTIARY; break;
+ case 4: profile->strength = UCOL_IDENTICAL; break;
+ default: profile->strength = UCOL_SECONDARY;
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "%s: line %lu: strength \"%s\" not supported (will use 2)\n",
+ fname, (unsigned long)lineno, cargv[4]);
+ break;
+ }
+ switch (atoi(cargv[5])) {
+ case 1: profile->decomposition = UCOL_OFF; break;
+ case 2: profile->decomposition = UCOL_DEFAULT; /* no break here? fall through? wtf? */
+ case 3: profile->decomposition = UCOL_ON; break;
+ default: profile->decomposition = UCOL_DEFAULT;
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "%s: line %lu: decomposition \"%s\" not supported (will use 2)\n",
+ fname, (unsigned long)lineno, cargv[5]);
+ break;
+ }
+
+ {
+ char descStr[256];
+ char nameOrder[256];
+ char nameSubstring[256];
+ char oidString[256];
+ char *tmpStr=NULL;
+ Slapi_MatchingRuleEntry *mrentry=slapi_matchingrule_new();
+
+ if(UCOL_PRIMARY == profile->strength) {
+ strcpy(nameOrder,"caseIgnoreOrderingMatch");
+ strcpy(nameSubstring,"caseIgnoreSubstringMatch");
+ }
+ else {
+ strcpy(nameOrder,"caseExactOrderingMatch");
+ strcpy(nameSubstring,"caseExactSubstringMatch");
+ }
+
+ if(cargc > 7) {
+ strcat(nameOrder,"-");
+ strcat(nameOrder,cargv[7]);
+ strcat(nameSubstring,"-");
+ strcat(nameSubstring,cargv[7]);
+ slapi_matchingrule_set(mrentry,SLAPI_MATCHINGRULE_NAME,
+ (void *)slapi_ch_strdup(nameOrder));
+ }
+ else {
+ if(0 != cargv[1][0]) {
+ strcat(nameOrder,"-");
+ strcat(nameSubstring,"-");
+ }
+ strcat(nameOrder,cargv[1]);
+ strcat(nameSubstring,cargv[1]);
+ slapi_matchingrule_set(mrentry,SLAPI_MATCHINGRULE_NAME,
+ (void *)slapi_ch_strdup(nameOrder));
+ }
+ strcpy(oidString,cargv[6]);
+ slapi_matchingrule_set(mrentry,SLAPI_MATCHINGRULE_OID,
+ (void *)slapi_ch_strdup(oidString));
+ if(0 != cargv[2][0]) {
+ sprintf(descStr,"%s-%s",cargv[1],cargv[2]);
+ }
+ else {
+ strcpy(descStr,cargv[1]);
+ }
+ slapi_matchingrule_set(mrentry,SLAPI_MATCHINGRULE_DESC,
+ (void *)slapi_ch_strdup(descStr));
+ slapi_matchingrule_set(mrentry,SLAPI_MATCHINGRULE_SYNTAX,
+ (void *)slapi_ch_strdup(DIRSTRING_SYNTAX_OID));
+ slapi_matchingrule_register(mrentry);
+ slapi_matchingrule_get(mrentry,SLAPI_MATCHINGRULE_NAME,
+ (void *)&tmpStr);
+ slapi_ch_free((void **)&tmpStr);
+ slapi_matchingrule_get(mrentry,SLAPI_MATCHINGRULE_OID,
+ (void *)&tmpStr);
+ slapi_ch_free((void **)&tmpStr);
+ slapi_matchingrule_set(mrentry,SLAPI_MATCHINGRULE_NAME,
+ (void *)slapi_ch_strdup(nameSubstring));
+ strcat(oidString,".6");
+ slapi_matchingrule_set(mrentry,SLAPI_MATCHINGRULE_OID,
+ (void *)slapi_ch_strdup(oidString));
+ slapi_matchingrule_register(mrentry);
+ slapi_matchingrule_free(&mrentry,1);
+ }
+
+
+ for (arg = 6; arg < cargc; ++arg) {
+ auto coll_id_t* id = (coll_id_t*) slapi_ch_malloc (sizeof (coll_id_t));
+ id->oid = slapi_ch_strdup (cargv[arg]);
+ id->profile = profile;
+ if (collation_ids <= 0) {
+ collation_id = (const coll_id_t**) slapi_ch_malloc (2 * sizeof (coll_id_t*));
+ } else {
+ collation_id = (const coll_id_t**) slapi_ch_realloc
+ ((void*)collation_id, (collation_ids + 2) * sizeof (coll_id_t*));
+ }
+ collation_id [collation_ids++] = id;
+ collation_id [collation_ids] = NULL;
+ }
+ }
+ } else {
+ return -1; /* unrecognized */
+ }
+ return 0; /* success */
+}
+
+typedef struct collation_indexer_t
+ /* A kind of indexer, implemented using an ICU Collator */
+{
+ UCollator* collator;
+ UConverter* converter;
+ struct berval** ix_keys;
+ int is_default_collator;
+} collation_indexer_t;
+
+/*
+ Caller must ensure that U == NULL and Ulen == 0 the first time called
+*/
+static UErrorCode
+SetUnicodeStringFromUTF_8 (UChar** U, int32_t* Ulen, int *isAlloced, const struct berval* bv)
+ /* Copy the UTF-8 string bv into the UnicodeString U,
+ but remove leading and trailing whitespace, and
+ convert consecutive whitespaces into a single space.
+ Ulen is set to the number of UChars in the array (not necessarily the number of bytes!)
+ */
+{
+ size_t n;
+ int32_t len = 0; /* length of non-space string */
+ int32_t needLen = 0; /* number of bytes needed for string */
+ UErrorCode err = U_ZERO_ERROR;
+ const char* s = bv->bv_val;
+ const char* begin = NULL; /* will point to beginning of non-space in val */
+ const char* end = NULL; /* will point to the first space after the last non-space char in val */
+ int32_t nUchars = 0;
+
+ if (!bv->bv_len) { /* no value? */
+ return U_INVALID_FORMAT_ERROR; /* don't know what else to use here */
+ }
+
+ /* first, set s to the first non-space char in bv->bv_val */
+ for (n = 0; (n < bv->bv_len) && ldap_utf8isspace((char *)s); ) { /* cast away const */
+ const char *next = LDAP_UTF8NEXT((char *)s); /* cast away const */
+ n += (next - s); /* count bytes, not chars */
+ s = next;
+ }
+ begin = s; /* begin points to first non-space char in val */
+
+ if (n >= bv->bv_len) { /* value is all spaces? */
+ return U_INVALID_FORMAT_ERROR; /* don't know what else to use here */
+ }
+
+ s = bv->bv_val + (bv->bv_len-1); /* move s to last char of bv_val */
+ end = s; /* end points at last char of bv_val - may change below */
+ /* find the last non-null and non-space char of val */
+ for (n = bv->bv_len; (n > 0) && (!*s || ldap_utf8isspace((char *)s));) {
+ const char *prev = LDAP_UTF8PREV((char *)s);
+ end = prev;
+ n -= (s - prev); /* count bytes, not chars */
+ s = prev;
+ }
+
+ /* end now points at last non-null/non-space of val */
+ if (n < 0) { /* bogus */
+ return U_INVALID_FORMAT_ERROR; /* don't know what else to use here */
+ }
+
+ len = LDAP_UTF8NEXT((char *)end) - begin;
+
+ u_strFromUTF8(*U, *Ulen, &nUchars, begin, len, &err);
+ if (nUchars > *Ulen) { /* need more space */
+ if (*isAlloced) { /* realloc space */
+ *U = (UChar *)slapi_ch_realloc((char *)*U, sizeof(UChar) * nUchars);
+ } else { /* must use malloc */
+ *U = (UChar *)slapi_ch_malloc(sizeof(UChar) * nUchars);
+ *isAlloced = 1; /* no longer using fixed buffer */
+ }
+ *Ulen = nUchars;
+ err = U_ZERO_ERROR; /* reset */
+ u_strFromUTF8(*U, *Ulen, NULL, begin, len, &err);
+ } else {
+ *Ulen = nUchars;
+ }
+
+ return err;
+}
+
+static struct berval**
+collation_index (indexer_t* ix, struct berval** bvec, struct berval** prefixes)
+{
+ collation_indexer_t* etc = (collation_indexer_t*) ix->ix_etc;
+ struct berval** keys = NULL;
+ if (bvec) {
+ char keyBuffer[128]; /* try to use static space buffer to avoid malloc */
+ int32_t keyLen = sizeof(keyBuffer);
+ char* key = keyBuffer; /* but key can grow if necessary */
+ size_t keyn = 0;
+ struct berval** bv;
+ UChar charBuffer[128]; /* try to use static space buffer */
+ int32_t nChars = sizeof(charBuffer)/sizeof(UChar); /* but grow if necessary */
+ UChar *chars = charBuffer; /* try to reuse this */
+ int isAlloced = 0; /* using fixed buffer */
+
+ for (bv = bvec; *bv; ++bv) {
+ /* if chars is allocated, nChars will be the capacity and the number of chars in chars */
+ /* otherwise, nChars will be the number of chars, which may be less than the capacity */
+ if (!isAlloced) {
+ nChars = sizeof(charBuffer)/sizeof(UChar); /* reset */
+ }
+ if (U_ZERO_ERROR == SetUnicodeStringFromUTF_8 (&chars, &nChars, &isAlloced, *bv)) {
+ /* nChars is now the number of UChar in chars, which may be less than the
+ capacity of charBuffer if not allocated */
+ struct berval* prefix = prefixes ? prefixes[bv-bvec] : NULL;
+ const size_t prefixLen = prefix ? prefix->bv_len : 0;
+ struct berval* bk = NULL;
+ int32_t realLen; /* real length of key, not keyLen which is buffer size */
+
+ /* try to get the sort key using key and keyLen; only grow key
+ if we need to */
+ /* can use -1 for char len since the conversion from UTF8
+ null terminates the string */
+ realLen = ucol_getSortKey(etc->collator, chars, nChars, (uint8_t *)key, keyLen);
+ if (realLen > keyLen) { /* need more space */
+ if (key == keyBuffer) {
+ key = (char*)slapi_ch_malloc(sizeof(char) * realLen);
+ } else {
+ key = (char*)slapi_ch_realloc(key, sizeof(char) * realLen);
+ }
+ keyLen = ucol_getSortKey(etc->collator, chars, nChars, (uint8_t *)key, realLen);
+ }
+ if (realLen > 0) {
+ bk = (struct berval*) slapi_ch_malloc (sizeof(struct berval));
+
+ bk->bv_len = prefixLen + realLen;
+ bk->bv_val = slapi_ch_malloc (bk->bv_len + 1);
+ if (prefixLen) {
+ memcpy(bk->bv_val, prefix->bv_val, prefixLen);
+ }
+ memcpy(bk->bv_val + prefixLen, key, realLen);
+ bk->bv_val[bk->bv_len] = '\0';
+ LDAPDebug (LDAP_DEBUG_FILTER, "collation_index(%.*s) %lu bytes\n",
+ bk->bv_len, bk->bv_val, (unsigned long)bk->bv_len);
+ keys = (struct berval**)
+ slapi_ch_realloc ((void*)keys, sizeof(struct berval*) * (keyn + 2));
+ keys[keyn++] = bk;
+ keys[keyn] = NULL;
+ }
+ }
+ }
+ if (chars != charBuffer) { /* realloc'ed, need to free */
+ slapi_ch_free((void **)&chars);
+ }
+ if (key != keyBuffer) { /* realloc'ed, need to free */
+ slapi_ch_free_string(&key);
+ }
+ }
+ if (etc->ix_keys != NULL) ber_bvecfree (etc->ix_keys);
+ etc->ix_keys = keys;
+ return keys;
+}
+
+static void
+collation_indexer_destroy (indexer_t* ix)
+ /* The destructor function for a collation-based indexer. */
+{
+ collation_indexer_t* etc = (collation_indexer_t*) ix->ix_etc;
+ if (etc->converter) {
+ ucnv_close(etc->converter);
+ etc->converter = NULL;
+ }
+ if (!etc->is_default_collator) {
+ /* Don't delete the default collation - it seems to cause problems */
+ ucol_close(etc->collator);
+ etc->collator = NULL;
+ }
+ if (etc->ix_keys != NULL) {
+ ber_bvecfree (etc->ix_keys);
+ etc->ix_keys = NULL;
+ }
+ slapi_ch_free((void**)&ix->ix_etc);
+ ix->ix_etc = NULL; /* just for hygiene */
+}
+
+static UErrorCode
+s_newNamedLocaleFromComponents(char **locale, const char *lang, const char *country, const char *variant)
+{
+ UErrorCode err = U_ZERO_ERROR;
+ int hasLang = (lang && *lang);
+ int hasC = (country && *country);
+ int hasVar = (variant && *variant);
+
+ *locale = NULL;
+ if (hasLang) {
+ *locale = PR_smprintf("%s%s%s%s%s", lang, (hasC ? "_" : ""), (hasC ? country : ""),
+ (hasVar ? "_" : ""), (hasVar ? variant : ""));
+ } else {
+ err = U_INVALID_FORMAT_ERROR; /* don't know what else to use here */
+ }
+
+ return err;
+}
+
+indexer_t*
+collation_indexer_create (const char* oid)
+ /* Return a new indexer, based on the collation identified by oid.
+ Return NULL if this can't be done.
+ */
+{
+ indexer_t* ix = NULL;
+ const coll_id_t** id = collation_id;
+ char* locale = NULL; /* NULL == default locale */
+ if (id) for (; *id; ++id) {
+ if (!strcasecmp (oid, (*id)->oid)) {
+ const coll_profile_t* profile = (*id)->profile;
+ const int is_default = (profile->language == NULL &&
+ profile->country == NULL &&
+ profile->variant == NULL);
+ UErrorCode err = U_ZERO_ERROR;
+ if ( ! is_default) {
+ if (locale) {
+ PR_smprintf_free(locale);
+ locale = NULL;
+ }
+ err = s_newNamedLocaleFromComponents(&locale,
+ profile->language,
+ profile->country,
+ profile->variant);
+ }
+ if (err == U_ZERO_ERROR) {
+ UCollator* coll = ucol_open(locale, &err);
+ /*
+ * If we found exactly the right collator for this locale,
+ * or if we found a fallback one, or if we are happy with
+ * the default, use it.
+ */
+ if (err == U_ZERO_ERROR || err == U_USING_FALLBACK_WARNING ||
+ (err == U_USING_DEFAULT_WARNING && is_default)) {
+ collation_indexer_t* etc = (collation_indexer_t*)
+ slapi_ch_calloc (1, sizeof (collation_indexer_t));
+ ix = (indexer_t*) slapi_ch_calloc (1, sizeof (indexer_t));
+ ucol_setAttribute (coll, UCOL_STRENGTH, profile->strength, &err);
+ if (err != U_ZERO_ERROR) {
+ LDAPDebug (LDAP_DEBUG_ANY, "collation_indexer_create: could not "
+ "set the collator strength for oid %s to %d: err %d\n",
+ oid, profile->strength, err);
+ }
+ ucol_setAttribute (coll, UCOL_DECOMPOSITION_MODE, profile->decomposition, &err);
+ if (err != U_ZERO_ERROR) {
+ LDAPDebug (LDAP_DEBUG_ANY, "collation_indexer_create: could not "
+ "set the collator decomposition mode for oid %s to %d: err %d\n",
+ oid, profile->decomposition, err);
+ }
+ etc->collator = coll;
+ etc->is_default_collator = is_default;
+ for (id = collation_id; *id; ++id) {
+ if ((*id)->profile == profile) {
+ break; /* found the 'official' id */
+ }
+ }
+ ix->ix_etc = etc;
+ ix->ix_oid = (*id)->oid;
+ ix->ix_index = collation_index;
+ ix->ix_destroy = collation_indexer_destroy;
+ break; /* return */
+ /* free (etc); */
+ /* free (ix); */
+ } else if (err == U_USING_DEFAULT_WARNING) {
+ LDAPDebug (LDAP_DEBUG_FILTER, "collation_indexer_create: could not "
+ "create an indexer for OID %s for locale %s and could not "
+ "use default locale\n",
+ oid, (locale ? locale : "(default)"), NULL);
+ } else { /* error */
+ LDAPDebug (LDAP_DEBUG_FILTER, "collation_indexer_create: could not "
+ "create an indexer for OID %s for locale %s: err = %d\n",
+ oid, (locale ? locale : "(default)"), err);
+ }
+ if (coll) {
+ ucol_close (coll);
+ coll = NULL;
+ }
+ }
+ break; /* failed to create the specified collator */
+ }
+ }
+ if (locale) {
+ PR_smprintf_free(locale);
+ locale = NULL;
+ }
+ return ix;
+}
diff --git a/ldap/servers/plugins/collation/collate.h b/ldap/servers/plugins/collation/collate.h
new file mode 100644
index 00000000..29e51022
--- /dev/null
+++ b/ldap/servers/plugins/collation/collate.h
@@ -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 **/
+
+#ifndef _COLLATE_H_
+#define _COLLATE_H_
+
+#include <stddef.h> /* size_t */
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+
+struct indexer_t;
+
+typedef void (*ix_destroy_t) (struct indexer_t*);
+typedef struct berval** (*ix_index_t) (struct indexer_t*, struct berval** values,
+ struct berval** prefixes /* inserted into each key */);
+
+typedef struct indexer_t
+{
+ char* ix_oid;
+ ix_index_t ix_index; /* map values to index keys */
+ ix_destroy_t ix_destroy;
+ void* ix_etc; /* whatever state the implementation needs */
+} indexer_t;
+
+extern void
+collation_init( char *configpath );
+
+extern int
+collation_config (size_t argc, char** argv, const char* fname, size_t lineno);
+
+extern indexer_t*
+collation_indexer_create (const char* oid);
+
+#endif
diff --git a/ldap/servers/plugins/collation/collation.def b/ldap/servers/plugins/collation/collation.def
new file mode 100644
index 00000000..bd5d531b
--- /dev/null
+++ b/ldap/servers/plugins/collation/collation.def
@@ -0,0 +1,10 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 7 Collation Plugin'
+EXPORTS
+ orderingRule_init @2
+ plugin_init_debug_level @3
diff --git a/ldap/servers/plugins/collation/config.c b/ldap/servers/plugins/collation/config.c
new file mode 100644
index 00000000..ef3e66cf
--- /dev/null
+++ b/ldap/servers/plugins/collation/config.c
@@ -0,0 +1,178 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "collate.h"
+#include "config.h"
+#include <stdio.h>
+#include <string.h>
+#include "slap.h"
+
+#define MAXARGS 16
+
+static char *
+strtok_quote( char *line, char *sep )
+{
+ int inquote;
+ char *tmp, *d;
+ static char *next;
+
+ if ( line != NULL ) {
+ next = line;
+ }
+ while ( *next && strchr( sep, *next ) ) {
+ next++;
+ }
+
+ if ( *next == '\0' ) {
+ next = NULL;
+ return( NULL );
+ }
+
+ d = tmp = next;
+ for ( inquote = 0; *next; next++ ) {
+ switch ( *next ) {
+ case '"':
+ if ( inquote ) {
+ inquote = 0;
+ } else {
+ inquote = 1;
+ }
+ break;
+
+#ifndef _WIN32
+ case '\\':
+ *d++ = *++next;
+ break;
+#endif
+
+ default:
+ if ( ! inquote ) {
+ if ( strchr( sep, *next ) != NULL ) {
+ *d++ = '\0';
+ next++;
+ return( tmp );
+ }
+ }
+ *d++ = *next;
+ break;
+ }
+ }
+ *d = '\0';
+
+ return( tmp );
+}
+
+static void
+fp_parse_line(
+ char *line,
+ int *argcp,
+ char **argv
+)
+{
+ char * token;
+
+ *argcp = 0;
+ for ( token = strtok_quote( line, " \t" ); token != NULL;
+ token = strtok_quote( NULL, " \t" ) ) {
+ if ( *argcp == MAXARGS ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Too many tokens (max %d)\n",
+ MAXARGS, 0, 0 );
+ exit( 1 );
+ }
+ argv[(*argcp)++] = token;
+ }
+ argv[*argcp] = NULL;
+}
+
+static char buf[BUFSIZ];
+static char *line;
+static int lmax, lcur;
+
+static void
+fp_getline_init( int *lineno )
+{
+ *lineno = -1;
+ buf[0] = '\0';
+}
+
+#define CATLINE( buf ) { \
+ int len; \
+ len = strlen( buf ); \
+ while ( lcur + len + 1 > lmax ) { \
+ lmax += BUFSIZ; \
+ line = (char *) slapi_ch_realloc( line, lmax ); \
+ } \
+ strcpy( line + lcur, buf ); \
+ lcur += len; \
+}
+
+static char *
+fp_getline( FILE *fp, int *lineno )
+{
+ char *p;
+
+ lcur = 0;
+ CATLINE( buf );
+ (*lineno)++;
+
+ /* hack attack - keeps us from having to keep a stack of bufs... */
+ if ( strncasecmp( line, "include", 7 ) == 0 ) {
+ buf[0] = '\0';
+ return( line );
+ }
+
+ while ( fgets( buf, sizeof(buf), fp ) != NULL ) {
+ if ( (p = strchr( buf, '\n' )) != NULL ) {
+ *p = '\0';
+ }
+ if ( ! isspace( buf[0] ) ) {
+ return( line );
+ }
+
+ CATLINE( buf );
+ (*lineno)++;
+ }
+ buf[0] = '\0';
+
+ return( line[0] ? line : NULL );
+}
+
+void
+collation_read_config( char *fname )
+{
+ FILE* fp;
+ char* line;
+ int cargc;
+ char* cargv[MAXARGS];
+ int lineno;
+
+ fp = fopen( fname, "r" );
+ if ( fp == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "could not open config file \"%s\" - absolute path?\n",
+ fname, 0, 0 );
+ return; /* Do not exit */
+ }
+
+ LDAPDebug( LDAP_DEBUG_CONFIG, "reading config file %s\n", fname, 0, 0 );
+
+ fp_getline_init( &lineno );
+ while ( (line = fp_getline( fp, &lineno )) != NULL ) {
+ /* skip comments and blank lines */
+ if ( line[0] == '#' || line[0] == '\0' ) {
+ continue;
+ }
+ LDAPDebug( LDAP_DEBUG_CONFIG, "line %d: %s\n", lineno, line, 0 );
+ fp_parse_line( line, &cargc, cargv );
+ if ( cargc < 1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "%s: line %d: bad config line (ignored)\n",
+ fname, lineno, 0 );
+ continue;
+ }
+ collation_config (cargc, cargv, fname, lineno);
+ }
+ fclose(fp);
+}
diff --git a/ldap/servers/plugins/collation/config.h b/ldap/servers/plugins/collation/config.h
new file mode 100644
index 00000000..1a4aef66
--- /dev/null
+++ b/ldap/servers/plugins/collation/config.h
@@ -0,0 +1,12 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _COLL_CONFIG_H_
+#define _COLL_CONFIG_H_
+
+extern void
+collation_read_config( char *fname );
+
+#endif
diff --git a/ldap/servers/plugins/collation/debug.c b/ldap/servers/plugins/collation/debug.c
new file mode 100644
index 00000000..99266a33
--- /dev/null
+++ b/ldap/servers/plugins/collation/debug.c
@@ -0,0 +1,14 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void
+plugin_init_debug_level (int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
diff --git a/ldap/servers/plugins/collation/dllmain.c b/ldap/servers/plugins/collation/dllmain.c
new file mode 100644
index 00000000..fa158500
--- /dev/null
+++ b/ldap/servers/plugins/collation/dllmain.c
@@ -0,0 +1,129 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for collation DLL
+ */
+#include "ldap.h"
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
+
+#ifdef LDAP_DEBUG
+#ifndef _WIN32
+#include <stdarg.h>
+#include <stdio.h>
+
+void LDAPDebug( int level, char* fmt, ... )
+{
+ static char debugBuf[1024];
+
+ if (module_ldap_debug && (*module_ldap_debug & level))
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ _snprintf (debugBuf, sizeof(debugBuf), fmt, ap);
+ va_end (ap);
+
+ OutputDebugString (debugBuf);
+ }
+}
+#endif
+#endif
+
+#ifndef _WIN32
+/* The 16-bit version of the RTL does not implement perror() */
+#include <stdio.h>
+
+void perror( const char *msg )
+{
+ char buf[128];
+ wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ;
+ OutputDebugString( buf );
+}
+
+#endif
diff --git a/ldap/servers/plugins/collation/orfilter.c b/ldap/servers/plugins/collation/orfilter.c
new file mode 100644
index 00000000..65222baa
--- /dev/null
+++ b/ldap/servers/plugins/collation/orfilter.c
@@ -0,0 +1,984 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* orfilter.c - implementation of ordering rule filter */
+
+#include <ldap.h> /* LDAP_UTF8INC */
+#include <slap.h> /* for debug macros */
+#include <slapi-plugin.h> /* slapi_berval_cmp, SLAPI_BERVAL_EQ */
+#include "collate.h" /* indexer_t, collation_xxx */
+#include "config.h" /* collation_read_config */
+#include "orfilter.h"
+
+#ifdef HPUX11
+#include <dl.h>
+#endif /* HPUX11 */
+
+static indexer_t*
+indexer_create (const char* oid)
+{
+ return collation_indexer_create (oid);
+}
+
+static void
+indexer_free (indexer_t* ix)
+{
+ if (ix->ix_destroy != NULL) {
+ ix->ix_destroy (ix);
+ }
+ slapi_ch_free((void**)&ix);
+}
+
+typedef struct or_filter_t {
+ /* implements a filter, using an indexer */
+ char* or_type;
+ int or_op; /* LDAPI_OP_xxx */
+ char* or_oid;
+ struct berval** or_values;
+ struct berval** or_match_keys;
+ struct berval** or_index_keys;
+ indexer_t* or_indexer; /* used to construct or_match_keys and or_index_keys */
+} or_filter_t;
+
+static or_filter_t*
+or_filter_get (Slapi_PBlock* pb)
+{
+ auto void* obj = NULL;
+ if ( ! slapi_pblock_get (pb, SLAPI_PLUGIN_OBJECT, &obj)) {
+ return (or_filter_t*)obj;
+ }
+ return NULL;
+}
+
+static int
+or_filter_destroy (Slapi_PBlock* pb)
+{
+ auto or_filter_t* or = or_filter_get (pb);
+ LDAPDebug (LDAP_DEBUG_FILTER, "or_filter_destroy(%p)\n", (void*)or, 0, 0);
+ if (or != NULL) {
+ slapi_ch_free((void**)&or->or_type);
+ slapi_ch_free((void**)&or->or_oid);
+ if (or->or_values != NULL) {
+ ber_bvecfree (or->or_values);
+ or->or_values = NULL;
+ }
+ if (or->or_match_keys != NULL) {
+ ber_bvecfree (or->or_match_keys);
+ or->or_match_keys = NULL;
+ }
+ if (or->or_index_keys != NULL) {
+ ber_bvecfree (or->or_index_keys);
+ or->or_index_keys = NULL;
+ }
+ if (or->or_indexer != NULL) {
+ indexer_free (or->or_indexer);
+ or->or_indexer = NULL;
+ }
+ slapi_ch_free((void**)&or);
+ }
+ return 0;
+}
+
+#define MAX_CHAR_COMBINING 3
+/* The maximum number of Unicode characters that may combine
+ to form a single collation element.
+*/
+
+static int
+ss_match (struct berval* value,
+ const struct berval* key0,
+ indexer_t* ix)
+/* returns: 0 a prefix of value matched key
+ * 1 a subsequent substring might match; try again
+ * -1 nothing in value will match; give up
+ */
+{
+ auto struct berval* vals[2];
+ auto struct berval val;
+ auto struct berval key;
+ auto size_t attempts = MAX_CHAR_COMBINING;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+ val.bv_val = value->bv_val;
+ val.bv_len = 0;
+ key.bv_val = key0->bv_val;
+ key.bv_len = key0->bv_len - 1;
+ while (1) {
+ auto struct berval** vkeys = ix->ix_index (ix, vals, NULL);
+ if (vkeys && vkeys[0]) {
+ auto const struct berval* vkey = vkeys[0];
+ if (vkey->bv_len > key.bv_len) {
+ if (--attempts <= 0) {
+ break; /* No match at this starting point */
+ } /* else Try looking at another character;
+ it may combine, and produce a shorter key.
+ */
+ } else if (SLAPI_BERVAL_EQ (vkey, &key)) {
+ value->bv_len -= val.bv_len;
+ value->bv_val += val.bv_len;
+ return 0;
+ }
+ }
+ if (val.bv_len >= value->bv_len) {
+ break;
+ }
+ val.bv_len += LDAP_UTF8LEN (val.bv_val + val.bv_len);
+ }
+ if (value->bv_len > 0) {
+ auto size_t one = LDAP_UTF8LEN (value->bv_val);
+ value->bv_len -= one;
+ value->bv_val += one;
+ return 1;
+ }
+ return -1;
+}
+
+static int
+ss_filter_match (or_filter_t* or, struct berval** vals)
+/* returns: 0 filter matched
+ * -1 filter did not match
+ * >0 an LDAP error code
+ */
+{
+ auto int rc = -1; /* no match */
+ auto indexer_t* ix = or->or_indexer;
+ if (vals != NULL) for (; *vals; ++vals) {
+ auto struct berval v;
+ auto struct berval** k = or->or_match_keys;
+ if (k == NULL || *k == NULL) {
+ rc = 0; /* present */
+ break;
+ }
+ v.bv_len = (*vals)->bv_len;
+ v.bv_val = (*vals)->bv_val;
+ if ((*k)->bv_len > 0 && ss_match (&v, *k, ix) != 0) {
+ break; /* initial failed */
+ }
+ rc = 0; /* so far, so good */
+ while (*++k) {
+ if ((*k)->bv_len <= 0) {
+ rc = 0;
+ } else if (k[1]) { /* middle */
+ do {
+ rc = ss_match (&v, *k, ix);
+ } while (rc > 0);
+ if (rc < 0) {
+ break;
+ }
+ } else { /* final */
+ auto size_t attempts = MAX_CHAR_COMBINING;
+ auto char* limit = v.bv_val;
+ auto struct berval** vkeys;
+ auto struct berval* vals[2];
+ auto struct berval key;
+ rc = -1;
+ vals[0] = &v;
+ vals[1] = NULL;
+ key.bv_val = (*k)->bv_val;
+ key.bv_len = (*k)->bv_len - 1;
+ v.bv_val = (*vals)->bv_val + (*vals)->bv_len;
+ while(1) {
+ v.bv_len = (*vals)->bv_len - (v.bv_val - (*vals)->bv_val);
+ vkeys = ix->ix_index (ix, vals, NULL);
+ if (vkeys && vkeys[0]) {
+ auto const struct berval* vkey = vkeys[0];
+ if (vkey->bv_len > key.bv_len) {
+ if (--attempts <= 0) {
+ break;
+ } /* else Try looking at another character;
+ it may combine, and produce a shorter key.
+ */
+ } else if (SLAPI_BERVAL_EQ (vkey, &key)) {
+ rc = 0;
+ break;
+ }
+ }
+ if (v.bv_val <= limit) break;
+ LDAP_UTF8DEC (v.bv_val);
+ }
+ break;
+ }
+ }
+ if (rc != -1) break;
+ }
+ return rc;
+}
+
+static int
+op_filter_match (or_filter_t* or, struct berval** vals)
+{
+ auto indexer_t* ix = or->or_indexer;
+ auto struct berval** v = ix->ix_index (ix, vals, NULL);
+ if (v != NULL) for (; *v; ++v) {
+ auto struct berval** k = or->or_match_keys;
+ if (k != NULL) for (; *k; ++k) {
+ switch (or->or_op) {
+ case SLAPI_OP_LESS:
+ if (slapi_berval_cmp (*v, *k) < 0) return 0; break;
+ case SLAPI_OP_LESS_OR_EQUAL:
+ if (slapi_berval_cmp (*v, *k) <= 0) return 0; break;
+ case SLAPI_OP_EQUAL:
+ if (SLAPI_BERVAL_EQ (*v, *k)) return 0; break;
+ case SLAPI_OP_GREATER_OR_EQUAL:
+ if (slapi_berval_cmp (*v, *k) >= 0) return 0; break;
+ case SLAPI_OP_GREATER:
+ if (slapi_berval_cmp (*v, *k) > 0) return 0; break;
+ default:
+ break;
+ }
+ }
+ }
+ return -1;
+}
+
+static int
+or_filter_match (void* obj, Slapi_Entry* entry, Slapi_Attr* attr)
+/* returns: 0 filter matched
+ * -1 filter did not match
+ * >0 an LDAP error code
+ */
+{
+ auto int rc = -1; /* no match */
+ auto or_filter_t* or = (or_filter_t*)obj;
+ for (; attr != NULL; slapi_entry_next_attr (entry, attr, &attr)) {
+ auto char* type = NULL;
+ auto struct berval** vals = NULL;
+
+/*
+ * XXXmcs 1-March-2001: This code would perform better if it did not make
+ * a copy of the values here, but that would require re-writing the code
+ * in this file to use Slapi_ValueSet's instead of struct berval **'s
+ * (and that is not a small project).
+ */
+ if (!slapi_attr_get_type (attr, &type) && type != NULL &&
+ !slapi_attr_type_cmp (or->or_type, type, 2/*match subtypes*/) &&
+ !slapi_attr_get_bervals_copy(attr, &vals) && vals != NULL) {
+
+ if (or->or_op == SLAPI_OP_SUBSTRING) {
+ rc = ss_filter_match (or, vals);
+ } else {
+ rc = op_filter_match (or, vals);
+ }
+
+ ber_bvecfree( vals );
+ vals = NULL;
+ if (rc >= 0) break;
+ }
+ }
+ return rc;
+}
+
+#define WILDCARD '*'
+/* If you want a filter value to contain a non-wildcard '*' or '\'
+ you write "\2a" or "\5c" (the ASCII codes, in hexadecimal).
+ For example, "4\2a4*flim\5cflam"
+ matches a value that begins with "4*4" and ends with "flim\flam"
+ (except that all the "\" should be doubled in C string literals).
+ This conforms to <draft-ietf-asid-ldapv3-attributes-08> section 8.3.
+*/
+
+static void
+ss_unescape (struct berval* val)
+{
+ char* s = val->bv_val;
+ char* t = s;
+ char* limit = s + val->bv_len;
+ while (s < limit) {
+ if (!memcmp (s, "\\2a", 3) ||
+ !memcmp (s, "\\2A", 3)) {
+ *t++ = WILDCARD;
+ s += 3;
+ } else if (!memcmp (s, "\\5c", 3) ||
+ !memcmp (s, "\\5C", 3)) {
+ *t++ = '\\';
+ s += 3;
+ } else {
+ if (t == s) LDAP_UTF8INC (t);
+ else t += LDAP_UTF8COPY (t, s);
+ LDAP_UTF8INC (s);
+ }
+ }
+ val->bv_len = t - val->bv_val;
+}
+
+static struct berval*
+slapi_ch_bvdup0 (struct berval* val)
+ /* Return a copy of val, with a 0 byte following the end. */
+{
+ auto struct berval* result = (struct berval*)
+ slapi_ch_malloc (sizeof (struct berval));
+ result->bv_len = val->bv_len;
+ result->bv_val = slapi_ch_malloc (result->bv_len + 1);
+ if (result->bv_len > 0) {
+ memcpy (result->bv_val, val->bv_val, result->bv_len);
+ }
+ result->bv_val[result->bv_len] = '\0';
+ return result;
+}
+
+static struct berval*
+ss_filter_value (const char* s, const size_t len, struct berval* val)
+{
+ val->bv_len = len;
+ if (len > 0) memcpy (val->bv_val, s, len);
+ ss_unescape (val);
+ return slapi_ch_bvdup0 (val);
+}
+
+static struct berval**
+ss_filter_values (struct berval* pattern, int* query_op)
+ /* Split the pattern into its substrings and return them. */
+{
+ auto struct berval** result;
+ auto struct berval val;
+ auto size_t n;
+ auto char* s;
+ auto char* p;
+ auto char* plimit = pattern->bv_val + pattern->bv_len;
+
+ /* Compute the length of the result array, and
+ the maximum bv_len of any of its elements. */
+ val.bv_len = 0;
+ n = 2; /* one key, plus NULL terminator */
+ s = pattern->bv_val;
+ for (p = s; p < plimit; LDAP_UTF8INC(p)) {
+ switch (*p) {
+ case WILDCARD:
+ ++n;
+ {
+ auto const size_t len = (p - s);
+ if (val.bv_len < len)
+ val.bv_len = len;
+ }
+ while (++p != plimit && *p == WILDCARD);
+ s = p;
+ break;
+ default: break;
+ }
+ }
+ if (n == 2) { /* no wildcards in pattern */
+ auto struct berval** pvec = (struct berval**) slapi_ch_malloc (sizeof (struct berval*) * 2);
+ auto struct berval* pv = (struct berval*) slapi_ch_malloc (sizeof (struct berval));
+ pvec[0] = pv;
+ pvec[1] = NULL;
+ pv->bv_len = pattern->bv_len;
+ pv->bv_val = slapi_ch_malloc (pv->bv_len);
+ memcpy (pv->bv_val, pattern->bv_val, pv->bv_len);
+ ss_unescape (pv);
+ *query_op = SLAPI_OP_EQUAL;
+ return pvec;
+ } else if (n == 3 && pattern->bv_len <= 1) { /* entire pattern is one wildcard */
+ return NULL; /* presence */
+ }
+ {
+ auto const size_t len = (p - s);
+ if (val.bv_len < len)
+ val.bv_len = len;
+ }
+ result = (struct berval**) slapi_ch_malloc (n * sizeof (struct berval*));
+ val.bv_val = slapi_ch_malloc (val.bv_len);
+ n = 0;
+ s = pattern->bv_val;
+ for (p = s; p < plimit; LDAP_UTF8INC(p)) {
+ switch (*p) {
+ case WILDCARD:
+ result[n++] = ss_filter_value (s, p-s, &val);
+ while (++p != plimit && *p == WILDCARD);
+ s = p;
+ break;
+ default: break;
+ }
+ }
+ if (p != s || s == plimit) {
+ result[n++] = ss_filter_value (s, p-s, &val);
+ }
+ result[n] = NULL;
+ slapi_ch_free((void**)&val.bv_val);
+ return result;
+}
+
+static struct berval*
+ss_filter_key (indexer_t* ix, struct berval* val)
+{
+ struct berval* key = (struct berval*) slapi_ch_calloc (1, sizeof(struct berval));
+ if (val->bv_len > 0) {
+ struct berval** keys = NULL;
+ auto struct berval* vals[2];
+ vals[0] = val;
+ vals[1] = NULL;
+ keys = ix->ix_index (ix, vals, NULL);
+ if (keys && keys[0]) {
+ key->bv_len = keys[0]->bv_len + 1;
+ key->bv_val = slapi_ch_malloc (key->bv_len);
+ memcpy (key->bv_val, keys[0]->bv_val, keys[0]->bv_len);
+ key->bv_val[key->bv_len-1] = '\0';
+ }
+ }
+ return key;
+}
+
+static struct berval**
+ss_filter_keys (indexer_t* ix, struct berval** values)
+ /* Index the substrings and return the key values,
+ with an extra byte appended to each key, so that
+ an empty key definitely implies an absent value.
+ */
+{
+ auto struct berval** keys = NULL;
+ if (values != NULL) {
+ auto size_t n; /* how many substring values */
+ auto struct berval** val;
+ for (n=0,val=values; *val != NULL; ++n,++val);
+ keys = (struct berval**) slapi_ch_malloc ((n+1) * sizeof (struct berval*));
+ for (n=0,val=values; *val != NULL; ++n,++val) {
+ keys[n] = ss_filter_key (ix, *val);
+ }
+ keys[n] = NULL;
+ }
+ return keys;
+}
+
+static int or_filter_index (Slapi_PBlock* pb);
+
+static int
+or_filter_create (Slapi_PBlock* pb)
+{
+ auto int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* failed to initialize */
+ auto char* mrOID = NULL;
+ auto char* mrTYPE = NULL;
+ auto struct berval* mrVALUE = NULL;
+ auto or_filter_t* or = NULL;
+
+ if (!slapi_pblock_get (pb, SLAPI_PLUGIN_MR_OID, &mrOID) && mrOID != NULL &&
+ !slapi_pblock_get (pb, SLAPI_PLUGIN_MR_TYPE, &mrTYPE) && mrTYPE != NULL &&
+ !slapi_pblock_get (pb, SLAPI_PLUGIN_MR_VALUE, &mrVALUE) && mrVALUE != NULL) {
+ auto size_t len = mrVALUE->bv_len;
+ auto indexer_t* ix = NULL;
+ auto int op = SLAPI_OP_EQUAL;
+ auto struct berval bv;
+ auto int reusable = MRF_ANY_TYPE;
+
+ LDAPDebug (LDAP_DEBUG_FILTER, "=> or_filter_create(oid %s; type %s)\n",
+ mrOID, mrTYPE, 0);
+ if (len > 1 && (ix = indexer_create (mrOID)) != NULL) {
+ auto char* val = mrVALUE->bv_val;
+ switch (val[0]) {
+ case '=': break;
+ case '<': op = (val[1] == '=') ?
+ SLAPI_OP_LESS_OR_EQUAL : SLAPI_OP_LESS; break;
+ case '>': op = (val[1] == '=') ?
+ SLAPI_OP_GREATER_OR_EQUAL : SLAPI_OP_GREATER; break;
+ case WILDCARD: op = SLAPI_OP_SUBSTRING; break;
+ default:
+ break;
+ }
+ for (; len > 0 && *val != ' '; ++val, --len);
+ if (len > 0) ++val, --len; /* skip the space */
+ bv.bv_len = len;
+ bv.bv_val = (len > 0) ? val : NULL;
+ } else { /* mrOID does not identify an ordering rule. */
+ /* Is it an ordering rule OID with a relational operator suffix? */
+ auto size_t oidlen = strlen (mrOID);
+ if (oidlen > 2 && mrOID[oidlen-2] == '.') {
+ op = atoi (mrOID + oidlen - 1);
+ switch (op) {
+ case SLAPI_OP_LESS:
+ case SLAPI_OP_LESS_OR_EQUAL:
+ case SLAPI_OP_EQUAL:
+ case SLAPI_OP_GREATER_OR_EQUAL:
+ case SLAPI_OP_GREATER:
+ case SLAPI_OP_SUBSTRING:
+ {
+ auto char* or_oid = slapi_ch_strdup (mrOID);
+ or_oid [oidlen-2] = '\0';
+ ix = indexer_create (or_oid);
+ if (ix != NULL) {
+ memcpy (&bv, mrVALUE, sizeof(struct berval));
+ reusable |= MRF_ANY_VALUE;
+ }
+ slapi_ch_free((void**)&or_oid);
+ }
+ break;
+ default: /* not a relational operator */
+ break;
+ }
+ }
+ }
+ if (ix != NULL) {
+ or = (or_filter_t*) slapi_ch_calloc (1, sizeof (or_filter_t));
+ or->or_type = slapi_ch_strdup (mrTYPE);
+ or->or_indexer = ix;
+ or->or_op = op;
+ if (op == SLAPI_OP_SUBSTRING) {
+ or->or_values = ss_filter_values (&bv, &(or->or_op));
+ } else {
+ or->or_values = (struct berval**)
+ slapi_ch_malloc (2 * sizeof (struct berval*));
+ or->or_values[0] = slapi_ch_bvdup0 (&bv);
+ or->or_values[1] = NULL;
+ }
+ {
+ auto struct berval** val = or->or_values;
+ if (val) for (; *val; ++val) {
+ LDAPDebug (LDAP_DEBUG_FILTER, "value \"%s\"\n", (*val)->bv_val, 0, 0);
+ }
+ }
+ if (or->or_op == SLAPI_OP_SUBSTRING) {
+ or->or_match_keys = ss_filter_keys (ix, or->or_values);
+ } else {
+ or->or_match_keys = slapi_ch_bvecdup (
+ ix->ix_index (ix, or->or_values, NULL));
+ }
+ slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, or);
+ slapi_pblock_set (pb, SLAPI_PLUGIN_DESTROY_FN, (void*)or_filter_destroy);
+ slapi_pblock_set (pb, SLAPI_PLUGIN_MR_FILTER_MATCH_FN, (void*)or_filter_match);
+ slapi_pblock_set (pb, SLAPI_PLUGIN_MR_FILTER_INDEX_FN, (void*)or_filter_index);
+/* slapi_pblock_set (pb, SLAPI_PLUGIN_MR_FILTER_REUSABLE, &reusable); */
+/* slapi_pblock_set (pb, SLAPI_PLUGIN_MR_FILTER_RESET_FN, ?); to be implemented */
+ rc = LDAP_SUCCESS;
+ }
+ } else {
+ LDAPDebug (LDAP_DEBUG_FILTER, "=> or_filter_create missing parameter(s)\n", 0, 0, 0);
+ }
+ LDAPDebug (LDAP_DEBUG_FILTER, "<= or_filter_create(%p) %i\n", (void*)or, rc, 0);
+ return rc;
+}
+
+static indexer_t*
+op_indexer_get (Slapi_PBlock* pb)
+{
+ auto void* obj = NULL;
+ if ( ! slapi_pblock_get (pb, SLAPI_PLUGIN_OBJECT, &obj)) {
+ return (indexer_t*)obj;
+ }
+ return NULL;
+}
+
+static int
+op_indexer_destroy (Slapi_PBlock* pb)
+{
+ auto indexer_t* ix = op_indexer_get (pb);
+ LDAPDebug (LDAP_DEBUG_FILTER, "op_indexer_destroy(%p)\n", (void*)ix, 0, 0);
+ if (ix != NULL) {
+ indexer_free (ix);
+ }
+ return 0;
+}
+
+static int
+op_index_entry (Slapi_PBlock* pb)
+ /* Compute collation keys (when writing an entry). */
+{
+ auto indexer_t* ix = op_indexer_get (pb);
+ auto int rc;
+ struct berval** values;
+ if (ix != NULL && ix->ix_index != NULL &&
+ !slapi_pblock_get (pb, SLAPI_PLUGIN_MR_VALUES, &values) &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_MR_KEYS, ix->ix_index (ix, values, NULL))) {
+ rc = 0;
+ } else {
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+ LDAPDebug (LDAP_DEBUG_FILTER, "op_index_entry(%p) %i\n", (void*)ix, rc, 0);
+ return rc;
+}
+
+static int
+op_index_search (Slapi_PBlock* pb)
+ /* Compute collation keys (when searching for entries). */
+{
+ auto or_filter_t* or = or_filter_get (pb);
+ auto int rc = LDAP_OPERATIONS_ERROR;
+ if (or != NULL) {
+ auto indexer_t* ix = or->or_indexer;
+ struct berval** values;
+ if (or->or_index_keys == NULL && ix != NULL && ix->ix_index != NULL &&
+ !slapi_pblock_get (pb, SLAPI_PLUGIN_MR_VALUES, &values)) {
+ or->or_index_keys = slapi_ch_bvecdup (
+ ix->ix_index (ix, values, NULL));
+ }
+ if (or->or_index_keys) {
+ rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_KEYS, or->or_index_keys);
+ }
+ }
+ LDAPDebug (LDAP_DEBUG_FILTER, "op_index_search(%p) %i\n", (void*)or, rc, 0);
+ return rc;
+}
+
+typedef struct ss_indexer_t {
+ char* ss_oid; /* ss_indexer->ix_oid && ".6" */
+ indexer_t* ss_indexer;
+} ss_indexer_t;
+
+static void
+ss_indexer_free (ss_indexer_t* ss)
+{
+ slapi_ch_free((void**)&ss->ss_oid);
+ if (ss->ss_indexer != NULL) {
+ indexer_free (ss->ss_indexer);
+ ss->ss_indexer = NULL;
+ }
+ slapi_ch_free((void**)&ss);
+}
+
+static ss_indexer_t*
+ss_indexer_get (Slapi_PBlock* pb)
+{
+ auto void* obj = NULL;
+ if ( ! slapi_pblock_get (pb, SLAPI_PLUGIN_OBJECT, &obj)) {
+ return (ss_indexer_t*)obj;
+ }
+ return NULL;
+}
+
+static void
+ss_indexer_destroy (Slapi_PBlock* pb)
+{
+ auto ss_indexer_t* ss = ss_indexer_get (pb);
+ LDAPDebug (LDAP_DEBUG_FILTER, "ss_indexer_destroy(%p)\n", (void*)ss, 0, 0);
+ if (ss) {
+ ss_indexer_free (ss);
+ }
+}
+
+#define SS_INDEX_LENGTH 3 /* characters */
+
+static char ss_prefixI = '[';
+static char ss_prefixM = '|';
+static char ss_prefixF = '}';
+
+static struct berval ss_index_initial = {1, &ss_prefixI};
+static struct berval ss_index_middle = {1, &ss_prefixM};
+static struct berval ss_index_final = {1, &ss_prefixF};
+
+static int
+long_enough (struct berval* bval, size_t enough)
+{
+ if (bval) {
+ auto size_t len = 0;
+ auto char* next = bval->bv_val;
+ auto char* last = next + bval->bv_len;
+ while (next < last) {
+ LDAP_UTF8INC (next);
+ if (++len >= enough) {
+ if (next > last) next = last;
+ bval->bv_len = next - bval->bv_val;
+ return 1;
+ }
+ }
+ }
+ return !enough;
+}
+
+static int
+ss_index_entry (Slapi_PBlock* pb)
+ /* Compute substring index keys (when writing an entry). */
+{
+ auto int rc = LDAP_OPERATIONS_ERROR;
+ auto size_t substringsLen = 0;
+ struct berval** values;
+ auto ss_indexer_t* ss = ss_indexer_get (pb);
+ auto indexer_t* ix = ss ? ss->ss_indexer : NULL;
+ if (ix != NULL && ix->ix_index != NULL &&
+ !slapi_pblock_get (pb, SLAPI_PLUGIN_MR_VALUES, &values)) {
+ auto struct berval* substrings = NULL;
+ auto struct berval** prefixes = NULL;
+ auto struct berval** value;
+ for (value = values; *value != NULL; ++value) {
+ auto struct berval substring;
+ substring.bv_val = (*value)->bv_val;
+ substring.bv_len = (*value)->bv_len;
+ if (long_enough (&substring, SS_INDEX_LENGTH-1)) {
+ auto struct berval* prefix = &ss_index_initial;
+ auto size_t offset;
+ for (offset = 0; 1; ++offset) {
+ ++substringsLen;
+ substrings = (struct berval*)
+ slapi_ch_realloc ((void*)substrings, substringsLen * sizeof(struct berval));
+ memcpy (&(substrings[substringsLen-1]), &substring, sizeof (struct berval));
+ prefixes = (struct berval**)
+ slapi_ch_realloc ((void*)prefixes, substringsLen * sizeof(struct berval*));
+ prefixes[substringsLen-1] = prefix;
+
+ if (offset != 0) LDAP_UTF8INC (substring.bv_val);
+ substring.bv_len = (*value)->bv_len - (substring.bv_val - (*value)->bv_val);
+ if (long_enough (&substring, SS_INDEX_LENGTH)) {
+ prefix = &ss_index_middle;
+ } else if (long_enough (&substring, SS_INDEX_LENGTH-1)) {
+ prefix = &ss_index_final;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ if (substrings != NULL) {
+ auto struct berval** vector = (struct berval**)
+ slapi_ch_malloc ((substringsLen+1) * sizeof(struct berval*));
+ auto size_t i;
+ for (i = 0; i < substringsLen; ++i) vector[i] = &(substrings[i]);
+ vector[substringsLen] = NULL;
+ rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_KEYS, ix->ix_index (ix, vector, prefixes));
+ slapi_ch_free((void**)&vector);
+ slapi_ch_free((void**)&substrings);
+ slapi_ch_free((void**)&prefixes);
+ }
+ }
+ LDAPDebug (LDAP_DEBUG_FILTER, "ss_index_entry(%p) %i %lu substrings\n",
+ (void*)ss, rc, (unsigned long)substringsLen);
+ return rc;
+}
+
+static int
+ss_index_search (Slapi_PBlock* pb)
+ /* Compute substring search keys (when searching for entries). */
+{
+ auto int rc = LDAP_OPERATIONS_ERROR;
+ auto or_filter_t* or = or_filter_get (pb);
+ if (or) {
+ if (or->or_index_keys == NULL /* not yet computed */ &&
+ or->or_values && or->or_indexer && or->or_indexer->ix_index) {
+ auto size_t substringsLen = 0;
+ auto struct berval* substrings = NULL;
+ auto struct berval** prefixes = NULL;
+ auto struct berval** value;
+ for (value = or->or_values; *value != NULL; ++value) {
+ auto size_t offset;
+ auto struct berval substring;
+ substring.bv_val = (*value)->bv_val;
+ for (offset = 0; 1; ++offset, LDAP_UTF8INC (substring.bv_val)) {
+ auto struct berval* prefix = NULL;
+ substring.bv_len = (*value)->bv_len - (substring.bv_val - (*value)->bv_val);
+ if (offset == 0 && value == or->or_values) {
+ if (long_enough (&substring, SS_INDEX_LENGTH - 1)) {
+ prefix = &ss_index_initial;
+ }
+ } else if (value[1] != NULL) {
+ if (long_enough (&substring, SS_INDEX_LENGTH)) {
+ prefix = &ss_index_middle;
+ }
+ } else if (long_enough (&substring, SS_INDEX_LENGTH)) {
+ prefix = &ss_index_middle;
+ } else if (long_enough (&substring, SS_INDEX_LENGTH-1)) {
+ prefix = &ss_index_final;
+ }
+ if (prefix == NULL) break;
+ ++substringsLen;
+ substrings = (struct berval*)
+ slapi_ch_realloc ((void*)substrings, substringsLen * sizeof(struct berval));
+ memcpy (&(substrings[substringsLen-1]), &substring, sizeof (struct berval));
+ prefixes = (struct berval**)
+ slapi_ch_realloc ((void*)prefixes, substringsLen * sizeof(struct berval*));
+ prefixes[substringsLen-1] = prefix;
+ }
+ }
+ if (substrings != NULL) {
+ auto indexer_t* ix = or->or_indexer;
+ auto struct berval** vector = (struct berval**)
+ slapi_ch_malloc ((substringsLen+1) * sizeof(struct berval*));
+ auto size_t i;
+ for (i = 0; i < substringsLen; ++i) vector[i] = &(substrings[i]);
+ vector[substringsLen] = NULL;
+ or->or_index_keys = slapi_ch_bvecdup (
+ ix->ix_index (ix, vector, prefixes));
+ slapi_ch_free((void**)&vector);
+ slapi_ch_free((void**)&substrings);
+ slapi_ch_free((void**)&prefixes);
+ }
+ }
+ if (or->or_index_keys) {
+ rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_KEYS, or->or_index_keys);
+ }
+ }
+ LDAPDebug (LDAP_DEBUG_FILTER, "ss_index_search(%p) %i\n", (void*)or, rc, 0);
+ return rc;
+}
+
+static int
+ss_indexable (struct berval** values)
+ /* at least one of the values is long enough to index */
+{
+ auto struct berval** val = values;
+ if (val) for (; *val; ++val) {
+ auto struct berval value;
+ value.bv_val = (*val)->bv_val;
+ value.bv_len = (*val)->bv_len;
+ if (val == values) { /* initial */
+ if (long_enough (&value, SS_INDEX_LENGTH-1)) return 1;
+ } else if (val[1]) { /* middle */
+ if (long_enough (&value, SS_INDEX_LENGTH)) return 1;
+ } else { /* final */
+ if (long_enough (&value, SS_INDEX_LENGTH-1)) return 1;
+ }
+ }
+ return 0;
+}
+
+static struct berval ss_one_berval = {0,0};
+static struct berval* ss_one_value[2] = {&ss_one_berval, NULL};
+
+static int
+or_filter_index (Slapi_PBlock* pb)
+ /* Return an indexer and values that accelerate the given filter. */
+{
+ auto or_filter_t* or = or_filter_get (pb);
+ auto int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ auto IFP mrINDEX_FN = NULL;
+ auto struct berval** mrVALUES = NULL;
+ auto char* mrOID = NULL;
+ auto int mrQUERY_OPERATOR;
+ if (or && or->or_indexer && or->or_indexer->ix_index) {
+ switch (or->or_op) {
+ case SLAPI_OP_LESS:
+ case SLAPI_OP_LESS_OR_EQUAL:
+ case SLAPI_OP_EQUAL:
+ case SLAPI_OP_GREATER_OR_EQUAL:
+ case SLAPI_OP_GREATER:
+ mrINDEX_FN = op_index_search;
+ mrVALUES = or->or_values;
+ mrOID = or->or_indexer->ix_oid;
+ mrQUERY_OPERATOR = or->or_op;
+ break;
+ case SLAPI_OP_SUBSTRING:
+ if (ss_indexable (or->or_values)) {
+ if (or->or_oid == NULL) {
+ auto const size_t len = strlen (or->or_indexer->ix_oid);
+ or->or_oid = slapi_ch_malloc (len + 3);
+ memcpy (or->or_oid, or->or_indexer->ix_oid, len);
+ sprintf (or->or_oid + len, ".%1i", SLAPI_OP_SUBSTRING);
+ }
+ mrINDEX_FN = ss_index_search;
+ mrVALUES = ss_one_value;
+ mrOID = or->or_oid;
+ mrQUERY_OPERATOR = SLAPI_OP_EQUAL;
+ }
+ break;
+ default: /* unsupported operator */
+ break;
+ }
+ }
+ if (mrINDEX_FN != NULL &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, or)) &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_TYPE, or->or_type)) &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_INDEX_FN, (void*)mrINDEX_FN)) &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUES, mrVALUES)) &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, mrOID))) {
+ rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_QUERY_OPERATOR, &mrQUERY_OPERATOR);
+ }
+ LDAPDebug (LDAP_DEBUG_FILTER, "or_filter_index(%p) %i\n",
+ (void*)(or ? or->or_indexer : NULL), rc, 0);
+ return rc;
+}
+
+static int
+or_indexer_create (Slapi_PBlock* pb)
+{
+ auto int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION; /* failed to initialize */
+ auto char* mrOID = NULL;
+ auto void* mrOBJECT = NULL;
+ if (slapi_pblock_get (pb, SLAPI_PLUGIN_MR_OID, &mrOID) || mrOID == NULL) {
+ LDAPDebug (LDAP_DEBUG_FILTER, "=> or_indexer_create: no OID parameter\n", 0, 0, 0);
+ } else {
+ auto indexer_t* ix = indexer_create (mrOID);
+ auto char* mrTYPE = NULL;
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_TYPE, &mrTYPE);
+ LDAPDebug (LDAP_DEBUG_FILTER, "=> or_indexer_create(oid %s; type %s)\n",
+ mrOID, mrTYPE ? mrTYPE : "<NULL>", 0);
+ if (ix != NULL) {
+ if (ix->ix_index != NULL &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, ix) &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, ix->ix_oid) &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_MR_INDEX_FN, (void*)op_index_entry) &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_DESTROY_FN, (void*)op_indexer_destroy)) {
+ mrOBJECT = ix;
+ rc = 0; /* success */
+ } else {
+ indexer_free (ix);
+ }
+ } else { /* mrOID does not identify an ordering rule. */
+ /* Is it an ordering rule OID with the substring suffix? */
+ auto size_t oidlen = strlen (mrOID);
+ if (oidlen > 2 && mrOID[oidlen-2] == '.' &&
+ atoi (mrOID + oidlen - 1) == SLAPI_OP_SUBSTRING) {
+ auto char* or_oid = slapi_ch_strdup (mrOID);
+ or_oid [oidlen-2] = '\0';
+ ix = indexer_create (or_oid);
+ if (ix != NULL) {
+ auto ss_indexer_t* ss = (ss_indexer_t*) slapi_ch_malloc (sizeof (ss_indexer_t));
+ ss->ss_indexer = ix;
+ oidlen = strlen (ix->ix_oid);
+ ss->ss_oid = slapi_ch_malloc (oidlen + 3);
+ memcpy (ss->ss_oid, ix->ix_oid, oidlen);
+ sprintf (ss->ss_oid + oidlen, ".%1i", SLAPI_OP_SUBSTRING);
+ if (ix->ix_index != NULL &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, ss) &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, ss->ss_oid) &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_MR_INDEX_FN, (void*)ss_index_entry) &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_DESTROY_FN, (void*)ss_indexer_destroy)) {
+ mrOBJECT = ss;
+ rc = 0; /* success */
+ } else {
+ ss_indexer_free (ss);
+ }
+ }
+ slapi_ch_free((void**)&or_oid);
+ }
+ }
+ }
+ LDAPDebug (LDAP_DEBUG_FILTER, "<= or_indexer_create(%p) %i\n", mrOBJECT, rc, 0);
+ return rc;
+}
+
+static Slapi_PluginDesc pdesc = { "orderingrule", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "internationalized ordering rule plugin" };
+
+#define SLAPI_ORPLUGIN_NAME pdesc.spd_description
+
+int /* LDAP error code */
+orderingRule_init (Slapi_PBlock* pb)
+{
+ int rc;
+ int argc;
+ char** argv;
+ char* cfgpath;
+
+/* if (!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_PRIVATE, ...)) &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_CLOSE_FN, ...)))
+*/
+
+#ifdef USE_HPUX_CC
+ /* not needed with ICU
+ shl_load ( "../lib/libnsbrk30.sl", BIND_IMMEDIATE, 0L );
+ shl_load ( "../lib/libnscnv30.sl", BIND_IMMEDIATE, 0L );
+ shl_load ( "../lib/libnscol30.sl", BIND_IMMEDIATE, 0L );
+ shl_load ( "../lib/libnsfmt30.sl", BIND_IMMEDIATE, 0L );
+ shl_load ( "../lib/libnsres30.sl", BIND_IMMEDIATE, 0L );
+ shl_load ( "../lib/libnsuni30.sl", BIND_IMMEDIATE, 0L );
+ */
+#endif
+
+ if ( slapi_pblock_get( pb, SLAPI_CONFIG_DIRECTORY, &cfgpath ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_ORPLUGIN_NAME,
+ "Unable to retrieve slapd configuration pathname; using default\n" );
+ cfgpath = NULL;
+ }
+
+ collation_init( cfgpath );
+ if (!slapi_pblock_get (pb, SLAPI_PLUGIN_ARGC, &argc) &&
+ !slapi_pblock_get (pb, SLAPI_PLUGIN_ARGV, &argv) &&
+ argc > 0) {
+ collation_read_config (argv[0]);
+ }
+ {
+ slapi_pblock_set (pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, (void*)or_indexer_create);
+ rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, (void*)or_filter_create);
+ }
+ if ( rc == 0 ) {
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&pdesc );
+ }
+ LDAPDebug (LDAP_DEBUG_FILTER, "orderingRule_init %i\n", rc, 0, 0);
+ return rc;
+}
diff --git a/ldap/servers/plugins/collation/orfilter.h b/ldap/servers/plugins/collation/orfilter.h
new file mode 100644
index 00000000..85a32592
--- /dev/null
+++ b/ldap/servers/plugins/collation/orfilter.h
@@ -0,0 +1,10 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _ORFILTER_H_
+#define _ORFILTER_H_
+
+#endif
diff --git a/ldap/servers/plugins/cos/Makefile b/ldap/servers/plugins/cos/Makefile
new file mode 100644
index 00000000..de540f5a
--- /dev/null
+++ b/ldap/servers/plugins/cos/Makefile
@@ -0,0 +1,79 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+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 = $(OBJDIR)/lib/libcos
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./cos.def
+endif
+
+COS_OBJS = cos.o cos_cache.o
+OBJS = $(addprefix $(OBJDEST)/, $(COS_OBJS))
+
+COS_DLL = cos-plugin
+
+INCLUDES += -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
+EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL)
+COS_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
+EXTRA_LIBS += $(LIBSLAPDLINK) $(NSPRLINK) $(LDAP_SDK_LIBLDAP_DLL)
+LD=ld
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+COS= $(addprefix $(LIBDIR)/, $(COS_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(COS)
+
+ifeq ($(ARCH), WINNT)
+$(COS): $(OBJS) $(COS_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(COS_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(COS): $(OBJS) $(COS_DLL_OBJ)
+ $(LINK_DLL) $(COS_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(COS_DLL_OBJ)
+endif
+ $(RM) $(COS)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
diff --git a/ldap/servers/plugins/cos/cos.c b/ldap/servers/plugins/cos/cos.c
new file mode 100644
index 00000000..5a077646
--- /dev/null
+++ b/ldap/servers/plugins/cos/cos.c
@@ -0,0 +1,266 @@
+/** 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 <string.h>
+#include "portable.h"
+#include "nspr.h"
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+#include "cos_cache.h"
+#include "vattr_spi.h"
+
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+/*** secret slapd stuff ***/
+
+/*
+ these are required here because they are not available
+ in any public header. They must exactly match their
+ counterparts in the server or they will fail to work
+ correctly.
+*/
+
+/*** from proto-slap.h ***/
+
+int slapd_log_error_proc( char *subsystem, char *fmt, ... );
+
+/*** from ldaplog.h ***/
+
+/* edited ldaplog.h for LDAPDebug()*/
+#ifndef _LDAPLOG_H
+#define _LDAPLOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDAP_DEBUG_TRACE 0x00001 /* 1 */
+#define LDAP_DEBUG_ANY 0x04000 /* 16384 */
+#define LDAP_DEBUG_PLUGIN 0x10000 /* 65536 */
+
+/* debugging stuff */
+# ifdef _WIN32
+ extern int *module_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( *module_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# else /* _WIN32 */
+ extern int slapd_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( slapd_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# endif /* Win32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAP_H */
+
+/*** end secrets ***/
+
+#define COS_PLUGIN_SUBSYSTEM "cos-plugin" /* used for logging */
+
+/* subrelease in the following version info is for odd-ball cos releases
+ * which do not fit into a general release, this can be used for beta releases
+ * and other (this version stuff is really to help outside applications which
+ * may wish to update cos decide whether the cos version they want to update to
+ * is a higher release than the installed plugin)
+ *
+ * note: release origin is 00 for directory server
+ * sub-release should be:
+ * 50 for initial RTM products
+ * from 0 increasing for alpha/beta releases
+ * from 51 increasing for patch releases
+ */
+#define COS_VERSION 0x00050050 /* version format: 0x release origin 00 major 05 minor 00 sub-release 00 */
+
+/* other function prototypes */
+int cos_init( Slapi_PBlock *pb );
+int cos_compute(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_compute_output_t outputfn);
+int cos_start( Slapi_PBlock *pb );
+int cos_close( Slapi_PBlock *pb );
+int cos_post_op( Slapi_PBlock *pb );
+
+
+static Slapi_PluginDesc pdesc = { "cos", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "class of service plugin" };
+
+static void * cos_plugin_identity = NULL;
+
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+/*
+** Plugin identity mgmt
+*/
+
+void cos_set_plugin_identity(void * identity)
+{
+ cos_plugin_identity=identity;
+}
+
+void * cos_get_plugin_identity()
+{
+ return cos_plugin_identity;
+}
+
+int cos_version()
+{
+ return COS_VERSION;
+}
+
+/*
+ cos_init
+ --------
+ adds our callbacks to the list
+*/
+int cos_init( Slapi_PBlock *pb )
+{
+ int ret = 0;
+ void * plugin_identity=NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_init\n",0,0,0);
+
+ /*
+ ** Store the plugin identity for later use.
+ ** Used for internal operations
+ */
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
+ PR_ASSERT (plugin_identity);
+ cos_set_plugin_identity(plugin_identity);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) cos_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
+ (void *) cos_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN,
+ (void *) cos_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
+ (void *) cos_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
+ (void *) cos_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) cos_close ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, COS_PLUGIN_SUBSYSTEM,
+ "cos_init: failed to register plugin\n" );
+ ret = -1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_init\n",0,0,0);
+ return ret;
+}
+
+
+/*
+ cos_start
+ ---------
+ This function registers the computed attribute evaluator
+ and inits the cos cache.
+ It is called after cos_init.
+*/
+int cos_start( Slapi_PBlock *pb )
+{
+ int ret = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_start\n",0,0,0);
+
+ if( !cos_cache_init() )
+ {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos: ready for service\n",0,0,0);
+ }
+ else
+ {
+ /* problems we are hosed */
+ cos_cache_stop();
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_start: failed to initialise\n",0,0,0);
+ ret = -1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_start\n",0,0,0);
+ return ret;
+}
+
+/*
+ cos_close
+ ---------
+ closes down the cache
+*/
+int cos_close( Slapi_PBlock *pb )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_close\n",0,0,0);
+
+ cos_cache_stop();
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_close\n",0,0,0);
+
+ return 0;
+}
+
+/*
+ cos_compute
+ -----------
+ called when evaluating named attributes in a search
+ and attributes remain unfound in the entry,
+ this function checks the attribute for a match with
+ those in the class of service definitions, and if a
+ match is found, adds the attribute and value to the
+ output list
+
+ returns
+ 0 on success
+ 1 on outright failure
+ -1 when doesn't know about attribute
+*/
+int cos_compute(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_compute_output_t outputfn)
+{
+ int ret = -1;
+
+ return ret;
+}
+
+
+/*
+ cos_post_op
+ -----------
+ Catch all for all post operations that change entries
+ in some way - this simply notifies the cache of a
+ change - the cache decides if action is necessary
+*/
+int cos_post_op( Slapi_PBlock *pb )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_post_op\n",0,0,0);
+
+ cos_cache_change_notify(pb);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_post_op\n",0,0,0);
+ return 0; /* always succeed */
+}
+
diff --git a/ldap/servers/plugins/cos/cos.def b/ldap/servers/plugins/cos/cos.def
new file mode 100644
index 00000000..484d9c6a
--- /dev/null
+++ b/ldap/servers/plugins/cos/cos.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
+;
+DESCRIPTION 'Netscape Directory Server 7 Class Of Service Plugin'
+EXPORTS
+ cos_init @2
+ plugin_init_debug_level @3
+ cos_version @4
diff --git a/ldap/servers/plugins/cos/cos_cache.c b/ldap/servers/plugins/cos/cos_cache.c
new file mode 100644
index 00000000..165f47d1
--- /dev/null
+++ b/ldap/servers/plugins/cos/cos_cache.c
@@ -0,0 +1,3566 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ The cos cache keeps in memory all of
+ the data related to cos. This allows
+ very fast lookups at the expense of RAM.
+ All meta data is indexed, allowing fast
+ binary search lookups.
+ The cache is not dynamic, in the sense
+ that it does not iteratively modify
+ itself as changes are made to the cos
+ meta-data. Rather, it is designed to
+ be fast to read, with non-locking
+ multiple thread access to the cache,
+ at the expense of modification speed.
+ This means that when changes do occur,
+ the cache must be rebuilt from scratch.
+ However, this is achieved in such a way,
+ so as to allow cache queries during the
+ building of the new cache - so once a
+ cache has been built, there is no down
+ time.
+ Of course, the configuration of the cos meta
+ data is likely to be a thing which does not
+ happen often. Any other use, is probably a
+ mis-use of the mechanism, and certainly will
+ suffer from performance problems.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include "portable.h"
+#include "slapi-plugin.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+
+/* this is naughty, but the api for backend state change is currently here */
+#include "slapi-private.h"
+
+/* include NSPR header files */
+#include "prthread.h"
+#include "prlock.h"
+#include "prerror.h"
+#include "prcvar.h"
+#include "prio.h"
+#include "vattr_spi.h"
+
+#include "cos_cache.h"
+
+#include "views.h"
+static void **views_api;
+
+/*** secret functions and structs in slapd ***/
+
+/*
+ these are required here because they are not available
+ in any public header. They must exactly match their
+ counterparts in the server or they will fail to work
+ correctly.
+*/
+
+/*** from slap.h ***/
+
+struct objclass {
+ char *oc_name; /* NAME */
+ char *oc_desc; /* DESC */
+ char *oc_oid; /* object identifier */
+ char *oc_superior; /* SUP -- XXXmcs: should be an array */
+ PRUint8 oc_kind; /* ABSTRACT/STRUCTURAL/AUXILIARY */
+ PRUint8 oc_flags; /* misc. flags, e.g., OBSOLETE */
+ char **oc_required;
+ char **oc_allowed;
+ char **oc_orig_required; /* MUST */
+ char **oc_orig_allowed; /* MAY */
+ char **oc_origin; /* X-ORIGIN extension */
+ struct objclass *oc_next;
+};
+
+/*** from proto-slap.h ***/
+
+int config_get_schemacheck();
+void oc_lock_read( void );
+void oc_unlock( void );
+struct objclass* g_get_global_oc_nolock();
+int slapd_log_error_proc( char *subsystem, char *fmt, ... );
+
+/*** from ldaplog.h ***/
+
+/* edited ldaplog.h for LDAPDebug()*/
+#ifndef _LDAPLOG_H
+#define _LDAPLOG_H
+
+/* defined in cos.c */
+void * cos_get_plugin_identity();
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDAP_DEBUG_TRACE 0x00001 /* 1 */
+#define LDAP_DEBUG_ANY 0x04000 /* 16384 */
+#define LDAP_DEBUG_PLUGIN 0x10000 /* 65536 */
+
+/* debugging stuff */
+# ifdef _WIN32
+ extern int *module_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( *module_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# else /* _WIN32 */
+ extern int slapd_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( slapd_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# endif /* Win32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAP_H */
+
+/*** end secrets ***/
+
+#define COS_PLUGIN_SUBSYSTEM "cos-plugin" /* used for logging */
+
+#define COSTYPE_BADTYPE 0
+#define COSTYPE_CLASSIC 1
+#define COSTYPE_POINTER 2
+#define COSTYPE_INDIRECT 3
+#define COS_DEF_ERROR_NO_TEMPLATES -2
+
+/* the global plugin handle */
+static volatile vattr_sp_handle *vattr_handle = NULL;
+
+static cos_cache_notify_flag = 0;
+
+/* service definition cache structs */
+
+/* cosIndexedLinkedList: provides an object oriented type interface to
+ link lists where each element contains an index for the entire
+ list. All structures that contain this one must specify this one
+ as the first member otherwise the supporting functions will not work.
+
+ {PARPAR} The indexing ability is not currently used since the
+ fastest lookup is achieved via a cache level index of all attributes,
+ however this mechanism may prove useful in the future
+*/
+struct _cosIndexedLinkedList
+{
+ void *pNext;
+ void **index;
+};
+typedef struct _cosIndexedLinkedList cosIndexedLinkedList;
+
+struct _cosAttrValue
+{
+ cosIndexedLinkedList list;
+ char *val;
+};
+typedef struct _cosAttrValue cosAttrValue;
+
+struct _cosAttribute
+{
+ cosIndexedLinkedList list;
+ char *pAttrName;
+ cosAttrValue *pAttrValue;
+ cosAttrValue *pObjectclasses;
+ int attr_override;
+ int attr_operational;
+ int attr_operational_default;
+ int attr_cos_merge;
+ void *pParent;
+};
+typedef struct _cosAttribute cosAttributes;
+
+struct _cosTemplate
+{
+ cosIndexedLinkedList list;
+ cosAttrValue *pDn;
+ cosAttrValue *pObjectclasses;
+ cosAttributes *pAttrs;
+ char *cosGrade;
+ int template_default;
+ void *pParent;
+ unsigned long cosPriority;
+};
+
+typedef struct _cosTemplate cosTemplates;
+
+struct _cosDefinition
+{
+ cosIndexedLinkedList list;
+ int cosType;
+ cosAttrValue *pDn;
+ cosAttrValue *pCosTargetTree;
+ cosAttrValue *pCosTemplateDn;
+ cosAttrValue *pCosSpecifier;
+ cosAttrValue *pCosAttrs;
+ cosAttrValue *pCosOverrides;
+ cosAttrValue *pCosOperational;
+ cosAttrValue *pCosOpDefault;
+ cosAttrValue *pCosMerge;
+ cosTemplates *pCosTmps;
+};
+typedef struct _cosDefinition cosDefinitions;
+
+struct _cos_cache
+{
+ cosDefinitions *pDefs;
+ cosAttributes **ppAttrIndex;
+ int attrCount;
+ char **ppTemplateList;
+ int templateCount;
+ int refCount;
+ int vattr_cacheable;
+};
+typedef struct _cos_cache cosCache;
+
+/* cache manipulation function prototypes*/
+static cosCache *pCache; /* always the current global cache, only use getref to get */
+
+/* the place to start if you want a new cache */
+static int cos_cache_create();
+
+/* cache index related functions */
+static int cos_cache_index_all(cosCache *pCache);
+static int cos_cache_attr_compare(const void *e1, const void *e2);
+static int cos_cache_template_index_compare(const void *e1, const void *e2);
+static int cos_cache_string_compare(const void *e1, const void *e2);
+static int cos_cache_template_index_bsearch(const char *dn);
+static int cos_cache_attr_index_bsearch( const cosCache *pCache, const cosAttributes *key, int lower, int upper );
+
+/* the multi purpose list creation function, pass it something and it links it */
+static void cos_cache_add_ll_entry(void **attrval, void *theVal, int ( *compare )(const void *elem1, const void *elem2 ));
+
+/* cosAttrValue manipulation */
+static int cos_cache_add_attrval(cosAttrValue **attrval, char *val);
+static void cos_cache_del_attrval_list(cosAttrValue **pVal);
+static int cos_cache_attrval_count(cosAttrValue *pVal);
+static int cos_cache_attrval_exists(cosAttrValue *pAttrs, const char *val);
+
+/* cosAttributes manipulation */
+static int cos_cache_add_attr(cosAttributes **pAttrs, char *name, cosAttrValue *val);
+static void cos_cache_del_attr_list(cosAttributes **pAttrs);
+static int cos_cache_find_attr(cosCache *pCache, char *type);
+static int cos_cache_total_attr_count(cosCache *pCache);
+static int cos_cache_cos_2_slapi_valueset(cosAttributes *pAttr, Slapi_ValueSet **out_vs);
+static int cos_cache_cmp_attr(cosAttributes *pAttr, Slapi_Value *test_this, int *result);
+
+/* cosTemplates manipulation */
+static int cos_cache_add_dn_tmpls(char *dn, cosAttrValue *pCosSpecifier, cosAttrValue *pAttrs, cosTemplates **pTmpls);
+static int cos_cache_add_tmpl(cosTemplates **pTemplates, cosAttrValue *dn, cosAttrValue *objclasses, cosAttrValue *pCosSpecifier, cosAttributes *pAttrs,cosAttrValue *cosPriority);
+#if 0
+static int cos_cache_del_tmpl(cosTemplates *pTemplates, char *dn);
+#endif
+
+/* cosDefinitions manipulation */
+static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_cacheable);
+static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_cacheable);
+static int cos_cache_add_defn(cosDefinitions **pDefs, cosAttrValue **dn, int cosType, cosAttrValue **tree, cosAttrValue **tmpDn, cosAttrValue **spec, cosAttrValue **pAttrs, cosAttrValue **pOverrides, cosAttrValue **pOperational, cosAttrValue **pCosMerge, cosAttrValue **pCosOpDefault);
+static int cos_cache_entry_is_cos_related( Slapi_Entry *e);
+#if 0
+static int cos_cache_del_defn(cosDefinitions *pDefs, char *dn);
+#endif
+
+/* schema checking */
+static int cos_cache_schema_check(cosCache *pCache, int cache_attr_index, Slapi_Attr *pObjclasses);
+static int cos_cache_schema_build(cosCache *pCache);
+static void cos_cache_del_schema(cosCache *pCache);
+
+/* special cos scheme implimentations (special = other than cos classic) */
+static int cos_cache_follow_pointer( vattr_context *context, const char *dn, char *type, Slapi_ValueSet **out_vs, Slapi_Value *test_this, int *result, int flags );
+
+
+/* this dude is the thread function which performs dynamic config of the cache */
+static void cos_cache_wait_on_change(void *arg);
+
+/* this gets called when a backend changes state */
+void cos_cache_backend_state_change(void *handle, char *be_name,
+ int old_be_state, int new_be_state);
+
+/* operation callbacks for vattr service */
+static int cos_cache_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *free_flags, void *hint);
+static int cos_cache_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result, int flags, void *hint);
+static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags);
+static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *ops);
+static void cos_cache_query_attr_free(struct berval ***vals); /* deprecated */
+
+
+/*
+ compares s2 to s1 starting from end of string until the beginning of either
+ matches result in the s2 value being clipped from s1 with a NULL char
+ and 1 being returned as opposed to 0
+*/
+static int cos_cache_backwards_stricmp_and_clip(char*s1,char*s2);
+
+/* module level thread control stuff */
+
+static PRThread *cos_tid = NULL;
+static int keeprunning = 0;
+static int started = 0;
+
+static Slapi_Mutex *cache_lock;
+static Slapi_Mutex *change_lock;
+static Slapi_Mutex *start_lock;
+static Slapi_Mutex *stop_lock;
+static Slapi_CondVar *something_changed = NULL;
+static Slapi_CondVar *start_cond = NULL;
+
+
+/*
+ cos_cache_init
+ --------------
+ starts up the thread which waits for changes and
+ fires off the cache re-creation when one is detected
+ also registers vattr callbacks
+*/
+int cos_cache_init()
+{
+ int ret = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_init\n",0,0,0);
+
+ slapi_vattrcache_cache_none();
+ cache_lock = slapi_new_mutex();
+ change_lock = slapi_new_mutex();
+ stop_lock = slapi_new_mutex();
+ something_changed = slapi_new_condvar(change_lock);
+ keeprunning =1;
+ start_lock = slapi_new_mutex();
+ start_cond = slapi_new_condvar(start_lock);
+ started = 0;
+
+ if ( stop_lock == NULL ||
+ change_lock == NULL ||
+ cache_lock == NULL ||
+ stop_lock == NULL ||
+ start_lock == NULL ||
+ start_cond == NULL ||
+ something_changed == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, COS_PLUGIN_SUBSYSTEM,
+ "cos_cache_init: cannot create mutexes\n" );
+ ret = -1;
+ goto out;
+ }
+
+ /* grab the views interface */
+ if(slapi_apib_get_interface(Views_v1_0_GUID, &views_api))
+ {
+ /* lets be tolerant if views is disabled */
+ views_api = 0;
+ }
+
+ if (slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
+ cos_cache_vattr_get,
+ cos_cache_vattr_compare,
+ cos_cache_vattr_types) != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, COS_PLUGIN_SUBSYSTEM,
+ "cos_cache_init: cannot register as service provider\n" );
+ ret = -1;
+ goto out;
+ }
+
+ if ((cos_tid = PR_CreateThread (PR_USER_THREAD,
+ cos_cache_wait_on_change,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, COS_PLUGIN_SUBSYSTEM,
+ "cos_cache_init: PR_CreateThread failed\n" );
+ ret = -1;
+ goto out;
+ }
+
+ /* wait for that thread to get started */
+ if (ret == 0) {
+ slapi_lock_mutex(start_lock);
+ while (!started) {
+ while (slapi_wait_condvar(start_cond, NULL) == 0);
+ }
+ slapi_unlock_mutex(start_lock);
+ }
+
+
+out:
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_init\n",0,0,0);
+ return ret;
+}
+
+/*
+ cos_cache_wait_on_change
+ ------------------------
+ sit around waiting on a notification that something has
+ changed, then fires off the cache re-creation
+
+ The way this stuff is written, we can look for the
+ template for a definiton, before the template has been added--I think
+ that's OK--we'll see it when it arrives--get this error message:
+ "skipping cos definition cn=cosPointerGenerateSt,ou=People,o=cosAll--no templates found"
+
+*/
+static void cos_cache_wait_on_change(void *arg)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_wait_on_change thread\n",0,0,0);
+
+ slapi_lock_mutex(stop_lock);
+ slapi_lock_mutex(change_lock);
+
+ /* first register our backend state change func (we'll use func pointer as handle) */
+ slapi_register_backend_state_change((void *)cos_cache_backend_state_change, cos_cache_backend_state_change);
+
+ pCache = 0;
+
+ /* create initial cache */
+ cos_cache_create();
+
+ slapi_lock_mutex(start_lock);
+ started = 1;
+ slapi_notify_condvar(start_cond, 1);
+ slapi_unlock_mutex(start_lock);
+
+ while(keeprunning)
+ {
+ slapi_unlock_mutex(change_lock);
+ slapi_lock_mutex(change_lock);
+ if ( !cos_cache_notify_flag && keeprunning) {
+ /*
+ * Nothing to do right now, so go to sleep--as
+ * we have the mutex, we are sure to wait before any modify
+ * thread notifies our condvar, and so we will not miss any
+ * notifications, including the shutdown notification.
+ */
+ slapi_wait_condvar( something_changed, NULL );
+ } else {
+ /* Something to do...do it below */
+ }
+ /*
+ * We're here because:
+ * 1. we were asleep and got a signal, on our condvar OR
+ * 2. we were about to wait on the condvar and noticed that a modfiy
+ * thread
+ * had passed, setting the cos_cache_notify_flag and notifying us--
+ * we did not wait in that case as we would have missed the notify
+ * (notify when noone is waiting == no-op).
+ * before we go running off doing lots of stuff lets check if we should stop
+ */
+ if(keeprunning) {
+ cos_cache_create();
+ }
+ cos_cache_notify_flag = 0; /* Dealt with it */
+ }/* while */
+
+ /* shut down the cache */
+ slapi_unlock_mutex(change_lock);
+ slapi_unlock_mutex(stop_lock);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_wait_on_change thread exit\n",0,0,0);
+}
+
+/*
+ cos_cache_create
+ ---------------------
+ Walks the definitions in the DIT and creates the cache.
+ Once created, it swaps the new cache for the old one,
+ releasing its refcount to the old cache and allowing it
+ to be destroyed.
+*/
+static int cos_cache_create()
+{
+ int ret = -1;
+ cosCache *pNewCache;
+ static int firstTime = 1;
+ int cache_built = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_create\n",0,0,0);
+
+ pNewCache = (cosCache*)slapi_ch_malloc(sizeof(cosCache));
+ if(pNewCache)
+ {
+ pNewCache->pDefs = 0;
+ pNewCache->refCount = 1; /* 1 is for us */
+ pNewCache->vattr_cacheable = 0; /* default is not cacheable */
+
+ ret = cos_cache_build_definition_list(&(pNewCache->pDefs), &(pNewCache->vattr_cacheable));
+ if(!ret)
+ {
+ /* OK, we have a cache, lets add indexing for
+ that faster than slow feeling */
+
+ ret = cos_cache_index_all(pNewCache);
+ if(ret == 0)
+ {
+ /* right, indexed cache, lets do our duty for the schema */
+
+ ret = cos_cache_schema_build(pNewCache);
+ if(ret == 0)
+ {
+ /* now to swap the new cache for the old cache */
+ cosCache *pOldCache;
+
+ slapi_lock_mutex(cache_lock);
+
+ /* turn off caching until the old cache is done */
+ if(pCache)
+ {
+ slapi_vattrcache_cache_none();
+
+ /*
+ * be sure not to uncache other stuff
+ * like roles if there is no change in
+ * state
+ */
+ if(pCache->vattr_cacheable)
+ slapi_entrycache_vattrcache_watermark_invalidate();
+ }
+ else
+ {
+ if(pNewCache && pNewCache->vattr_cacheable)
+ {
+ slapi_vattrcache_cache_all();
+ }
+ }
+
+ pOldCache = pCache;
+ pCache = pNewCache;
+
+ slapi_unlock_mutex(cache_lock);
+
+ if(pOldCache)
+ cos_cache_release(pOldCache);
+
+ cache_built = 1;
+ }
+ else
+ {
+ /* we should not go on without proper schema checking */
+ cos_cache_release(pNewCache);
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_create: failed to cache the schema\n",0,0,0);
+ }
+ }
+ else
+ {
+ /* currently we cannot go on without the indexes */
+ cos_cache_release(pNewCache);
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_create: failed to index cache\n",0,0,0);
+ }
+ }
+ else
+ {
+ if(firstTime)
+ {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_create: cos disabled\n",0,0,0);
+ firstTime = 0;
+ }
+
+ slapi_ch_free((void**)&pNewCache);
+ }
+ }
+ else
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_create: memory allocation failure\n",0,0,0);
+
+
+ /* make sure we have a new cache */
+ if(!cache_built)
+ {
+ /* we do not have a new cache, must make sure the old cache is destroyed */
+
+ cosCache *pOldCache;
+
+ slapi_lock_mutex(cache_lock);
+
+ slapi_vattrcache_cache_none();
+
+ /*
+ * be sure not to uncache other stuff
+ * like roles if there is no change in
+ * state
+ */
+ if(pCache && pCache->vattr_cacheable)
+ slapi_entrycache_vattrcache_watermark_invalidate();
+
+ pOldCache = pCache;
+ pCache = NULL;
+
+ slapi_unlock_mutex(cache_lock);
+
+ if(pOldCache)
+ cos_cache_release(pOldCache); /* release our reference to the old cache */
+
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_create\n",0,0,0);
+ return ret;
+}
+
+
+/*
+ cos_cache_build_definition_list
+ -------------------------------
+ builds the list of cos definitions by searching for them throughout the DIT
+*/
+static int cos_cache_build_definition_list(cosDefinitions **pDefs, int *vattr_cacheable)
+{
+ int ret = 0;
+ Slapi_PBlock *pSuffixSearch = 0;
+ Slapi_Entry **pSuffixList = 0;
+ Slapi_Attr *suffixAttr;
+ struct berval **suffixVals;
+ char *attrType = 0;
+ char *attrs[2];
+ int suffixIndex = 0;
+ int valIndex = 0;
+ int cos_def_available = 0;
+ static int firstTime = 1;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_build_definition_list\n",0,0,0);
+
+ /*
+ the class of service definitions may be anywhere in the DIT,
+ so our first task is to find them.
+ */
+
+ attrs[0] = "namingcontexts";
+ attrs[1] = 0;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos: Building class of service cache after status change.\n",0,0,0);
+
+ /*
+ * XXXrbyrne: this looks really ineficient--should be using
+ * slapi_get_next_suffix(), rather than searching for namingcontexts.
+ */
+
+ pSuffixSearch = slapi_search_internal("",LDAP_SCOPE_BASE,"(objectclass=*)",NULL,attrs,0);
+ if(pSuffixSearch)
+ slapi_pblock_get( pSuffixSearch, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+
+ if(pSuffixSearch && ret == LDAP_SUCCESS)
+ {
+ /* iterate through the suffixes and search for cos definitions */
+ slapi_pblock_get( pSuffixSearch, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &pSuffixList);
+ if(pSuffixList)
+ {
+ while(pSuffixList[suffixIndex])
+ {
+ if(!slapi_entry_first_attr(pSuffixList[suffixIndex], &suffixAttr))
+ {
+ do
+ {
+ attrType = 0;
+ slapi_attr_get_type(suffixAttr, &attrType);
+ if(attrType && !slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"namingcontexts"))
+ {
+ if(!slapi_attr_get_bervals_copy(suffixAttr, &suffixVals))
+ {
+ valIndex = 0;
+
+ if(suffixVals)
+ {
+ while(suffixVals[valIndex])
+ {
+ /* here's a suffix, lets search it... */
+ if(suffixVals[valIndex]->bv_val)
+ if(!cos_cache_add_dn_defs(suffixVals[valIndex]->bv_val ,pDefs, vattr_cacheable))
+ cos_def_available = 1;
+
+ valIndex++;
+ }
+
+
+ ber_bvecfree( suffixVals );
+ suffixVals = NULL;
+ }
+ }
+ }
+
+ } while(!slapi_entry_next_attr(pSuffixList[suffixIndex], suffixAttr, &suffixAttr));
+ }
+ suffixIndex++;
+ }
+ }
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_build_definition_list: failed to find suffixes\n",0,0,0);
+ ret = -1;
+ }
+
+ if(cos_def_available == 0)
+ {
+ if(firstTime)
+ {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_build_definition_list: Found no cos definitions, cos disabled while waiting for updates\n",0,0,0);
+ firstTime = 0;
+ }
+
+ ret = -1;
+ }
+ else
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos: Class of service cache built.\n",0,0,0);
+
+ /* clean up */
+ if(pSuffixSearch)
+ {
+ slapi_free_search_results_internal(pSuffixSearch);
+ slapi_pblock_destroy(pSuffixSearch);
+ }
+
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_build_definition_list\n",0,0,0);
+ return ret;
+}
+
+
+/* struct to support search callback API */
+struct dn_defs_info {
+ cosDefinitions **pDefs;
+ int vattr_cacheable;
+ int ret;
+};
+
+/*
+ * Currently, always returns 0 to continue the search for definitions, even
+ * if a particular attempt to add a definition fails: info.ret gets set to
+ * zero only if we succed to add a def.
+*/
+static int cos_dn_defs_cb (Slapi_Entry* e, void *callback_data) {
+ struct dn_defs_info *info;
+ cosAttrValue **pSneakyVal = 0;
+ cosAttrValue *pObjectclass = 0;
+ cosAttrValue *pCosTargetTree = 0;
+ cosAttrValue *pCosTemplateDn = 0;
+ cosAttrValue *pCosSpecifier = 0;
+ cosAttrValue *pCosAttribute = 0;
+ cosAttrValue *pCosOverrides = 0;
+ cosAttrValue *pCosOperational = 0;
+ cosAttrValue *pCosOpDefault = 0;
+ cosAttrValue *pCosMerge = 0;
+ cosAttrValue *pDn = 0;
+ struct berval **dnVals;
+ int cosType = 0;
+ int valIndex = 0;
+ Slapi_Attr *dnAttr;
+ char *attrType = 0;
+ char *attrs[7];
+
+ attrs[0] = "objectclass";
+ attrs[1] = "cosTargetTree";
+ attrs[2] = "cosTemplateDn";
+ attrs[3] = "cosSpecifier";
+ attrs[4] = "cosAttribute";
+ attrs[5] = 0;
+ info=(struct dn_defs_info *)callback_data;
+
+
+ /* assume cacheable */
+ info->vattr_cacheable = -1;
+
+ cos_cache_add_attrval(&pDn, slapi_entry_get_dn(e));
+ if(!slapi_entry_first_attr(e, &dnAttr))
+ {
+ do
+ {
+ attrType = 0;
+ /* we need to fill in the details of the definition now */
+ slapi_attr_get_type(dnAttr, &attrType);
+ if(attrType)
+ {
+ pSneakyVal = 0;
+ if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"objectclass"))
+ pSneakyVal = &pObjectclass;
+ else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosTargetTree"))
+ pSneakyVal = &pCosTargetTree;
+ else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosTemplateDn"))
+ pSneakyVal = &pCosTemplateDn;
+ else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosSpecifier"))
+ pSneakyVal = &pCosSpecifier;
+ else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosAttribute"))
+ pSneakyVal = &pCosAttribute;
+ else if(!slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"cosIndirectSpecifier"))
+ pSneakyVal = &pCosSpecifier;
+ if(pSneakyVal)
+ {
+ /* It's a type we're interested in */
+ if(!slapi_attr_get_bervals_copy(dnAttr, &dnVals))
+ {
+ valIndex = 0;
+ if(dnVals)
+ {
+ while(dnVals[valIndex])
+ {
+ if(dnVals[valIndex]->bv_val)
+ {
+ /*
+ parse any overide or default values
+ and deal with them
+ */
+ if(pSneakyVal == &pCosAttribute)
+ {
+ cosAttrValue *pTmpTargetTree = 0;
+ int qualifier_hit = 0;
+ int op_qualifier_hit = 0;
+ int merge_schemes_qualifier_hit = 0;
+ int override_qualifier_hit =0;
+ int default_qualifier_hit = 0;
+ int operational_default_qualifier_hit = 0;
+ do
+ {
+ qualifier_hit = 0;
+
+ if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " operational"))
+ {
+ /* matched */
+ op_qualifier_hit = 1;
+ qualifier_hit = 1;
+ }
+
+ if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " merge-schemes"))
+ {
+ /* matched */
+ merge_schemes_qualifier_hit = 1;
+ qualifier_hit = 1;
+ }
+
+ if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " override"))
+ {
+ /* matched */
+ override_qualifier_hit = 1;
+ qualifier_hit = 1;
+ }
+
+ if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " default")) {
+ default_qualifier_hit = 1;
+ qualifier_hit = 1;
+ }
+
+ if(cos_cache_backwards_stricmp_and_clip(dnVals[valIndex]->bv_val, " operational-default")) {
+ operational_default_qualifier_hit = 1;
+ qualifier_hit = 1;
+ }
+ }
+ while(qualifier_hit == 1);
+
+ /*
+ * At this point, dnVals[valIndex]->bv_val
+ * is the value of cosAttribute, stripped of
+ * any qualifiers, so add this pure attribute type to
+ * the appropriate lists.
+ */
+
+ if ( op_qualifier_hit ) {
+ cos_cache_add_attrval(&pCosOperational,
+ dnVals[valIndex]->bv_val);
+ }
+ if ( merge_schemes_qualifier_hit ) {
+ cos_cache_add_attrval(&pCosMerge,
+ dnVals[valIndex]->bv_val);
+ }
+ if ( override_qualifier_hit ) {
+ cos_cache_add_attrval(&pCosOverrides,
+ dnVals[valIndex]->bv_val);
+ }
+ if ( default_qualifier_hit ) {
+ /* attr is added below in pSneakyVal, in any case */
+ }
+
+ if ( operational_default_qualifier_hit ) {
+ cos_cache_add_attrval(&pCosOpDefault,
+ dnVals[valIndex]->bv_val);
+ }
+
+ if(!pCosTargetTree)
+ {
+ /* get the parent of the definition */
+
+ char *parent = slapi_dn_parent(pDn->val);
+ slapi_dn_normalize( parent );
+
+ cos_cache_add_attrval(&pCosTargetTree, parent);
+ if(!pCosTemplateDn)
+ cos_cache_add_attrval(&pCosTemplateDn, parent);
+
+ slapi_ch_free((void**)&parent);
+ }
+
+ pTmpTargetTree = pCosTargetTree;
+
+ slapi_vattrspi_regattr((vattr_sp_handle *)vattr_handle, dnVals[valIndex]->bv_val, NULL, NULL);
+ } /* if(attrType is cosAttribute) */
+
+ /*
+ * Add the attributetype to the appropriate
+ * list.
+ */
+ cos_cache_add_attrval(pSneakyVal,
+ dnVals[valIndex]->bv_val);
+ }/*if(dnVals[valIndex]->bv_val)*/
+
+ valIndex++;
+ }/* while(dnVals[valIndex]) */
+
+ ber_bvecfree( dnVals );
+ dnVals = NULL;
+ }/*if(dnVals)*/
+ }
+ }/*if(pSneakyVal)*/
+ }/*if(attrType)*/
+
+ } while(!slapi_entry_next_attr(e, dnAttr, &dnAttr));
+
+ /*
+ determine the type of class of service scheme
+ */
+
+ if(pObjectclass)
+ {
+ if(cos_cache_attrval_exists(pObjectclass, "cosDefinition"))
+ {
+ cosType = COSTYPE_CLASSIC;
+ }
+ else if(cos_cache_attrval_exists(pObjectclass, "cosClassicDefinition"))
+ {
+ cosType = COSTYPE_CLASSIC;
+
+ }
+ else if(cos_cache_attrval_exists(pObjectclass, "cosPointerDefinition"))
+ {
+ cosType = COSTYPE_POINTER;
+
+ }
+ else if(cos_cache_attrval_exists(pObjectclass, "cosIndirectDefinition"))
+ {
+ cosType = COSTYPE_INDIRECT;
+
+ }
+ else
+ cosType = COSTYPE_BADTYPE;
+ }
+
+ /*
+ we should now have a full definition,
+ do some sanity checks because we don't
+ want bogus entries in the cache
+ then ship it
+ */
+
+ /* these must exist */
+ if( pDn &&
+ pObjectclass &&
+
+ (
+ (cosType == COSTYPE_CLASSIC &&
+ pCosTemplateDn &&
+ pCosSpecifier &&
+ pCosAttribute )
+ ||
+ (cosType == COSTYPE_POINTER &&
+ pCosTemplateDn &&
+ pCosAttribute )
+ ||
+ (cosType == COSTYPE_INDIRECT &&
+ pCosSpecifier &&
+ pCosAttribute )
+ )
+ )
+ {
+ int rc = 0;
+ /*
+ we'll leave the referential integrity stuff
+ up to the referint plug-in and assume all
+ is good - if it's not then we just have a
+ useless definition and we'll nag copiously later.
+ */
+ char *pTmpDn = slapi_ch_strdup(pDn->val); /* because dn gets hosed on error */
+ char ebuf[ BUFSIZ ];
+
+ if(!(rc = cos_cache_add_defn(info->pDefs, &pDn, cosType,
+ &pCosTargetTree, &pCosTemplateDn,
+ &pCosSpecifier, &pCosAttribute,
+ &pCosOverrides, &pCosOperational,
+ &pCosMerge, &pCosOpDefault))) {
+ info->ret = 0; /* we have succeeded to add the defn*/
+ } else {
+ /*
+ * Failed but we will continue the search for other defs
+ * Don't reset info->ret....it keeps track of any success
+ */
+ if ( rc == COS_DEF_ERROR_NO_TEMPLATES) {
+ LDAPDebug(LDAP_DEBUG_ANY, "skipping cos definition %s"
+ "--no templates found\n",
+ escape_string(pTmpDn, ebuf),0,0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "skipping cos definition %s\n"
+ ,escape_string(pTmpDn, ebuf),0,0);
+ }
+ }
+
+ slapi_ch_free_string(&pTmpDn);
+ }
+ else
+ {
+ /*
+ this definition is brain dead - bail
+ if we have a dn use it to report, if not then *really* bad
+ things are going on
+ */
+ if(pDn)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_add_dn_defs: incomplete cos definition detected in %s, discarding from cache.\n",pDn->val,0,0);
+ }
+ else
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_add_dn_defs: incomplete cos definition detected, no DN to report, discarding from cache.\n",0,0,0);
+
+ if(pCosTargetTree)
+ cos_cache_del_attrval_list(&pCosTargetTree);
+ if(pCosTemplateDn)
+ cos_cache_del_attrval_list(&pCosTemplateDn);
+ if(pCosSpecifier)
+ cos_cache_del_attrval_list(&pCosSpecifier);
+ if(pCosAttribute)
+ cos_cache_del_attrval_list(&pCosAttribute);
+ if(pDn)
+ cos_cache_del_attrval_list(&pDn);
+ }
+ }/*if(!slapi_entry_first_attr(e, &dnAttr))*/
+ /* we don't keep the objectclasses, so lets free them */
+ if(pObjectclass) {
+ cos_cache_del_attrval_list(&pObjectclass);
+ }
+ /* This particular definition may not have yielded anything
+ * worth caching (eg. no template was found for it) but
+ * that should not cause us to abort the search for other more well behaved
+ * definitions.
+ * return info->ret;
+ */
+ return (0);
+
+}
+
+/*
+ cos_cache_add_dn_defs
+ -------------------------
+ takes a dn as argument and searches the dn for cos definitions,
+ adding any found to the definition list. Change to use search callback API.
+
+ Returns: 0: found at least one definition entry that got added to the
+ cache successfully.
+ non-zero: added no cos defs to the cache.
+*/
+
+#define DN_DEF_FILTER "(&(|(objectclass=cosSuperDefinition)(objectclass=cosDefinition))(objectclass=ldapsubentry))"
+
+static int cos_cache_add_dn_defs(char *dn, cosDefinitions **pDefs, int *vattr_cacheable)
+{
+ Slapi_PBlock *pDnSearch = 0;
+ struct dn_defs_info info;
+ pDnSearch = slapi_pblock_new();
+ if (pDnSearch) {
+ info.ret=-1; /* assume no good defs */
+ info.pDefs=pDefs;
+ info.vattr_cacheable = 0; /* assume not cacheable */
+ slapi_search_internal_set_pb(pDnSearch, dn, LDAP_SCOPE_SUBTREE,
+ DN_DEF_FILTER,NULL,0,
+ NULL,NULL,cos_get_plugin_identity(),0);
+ slapi_search_internal_callback_pb(pDnSearch,
+ &info /* callback_data */,
+ NULL/* result_callback */,
+ cos_dn_defs_cb,
+ NULL /* referral_callback */);
+ slapi_pblock_destroy (pDnSearch);
+ }
+
+ *vattr_cacheable = info.vattr_cacheable;
+
+ return info.ret;
+}
+
+
+
+/* struct to support call back API */
+
+struct tmpl_info {
+ cosAttrValue *pCosSpecifier;
+ cosAttrValue *pAttrs;
+ cosTemplates **pTmpls;
+ int ret;
+};
+
+
+/*
+ * Currently, always returns 0 to continue the search for templates, even
+ * if a particular attempt to add a template fails: info.ret gets set to
+ * zero only if we succed to add at least one tmpl.
+*/
+static int cos_dn_tmpl_entries_cb (Slapi_Entry* e, void *callback_data) {
+ cosAttrValue *pDn = 0;
+ cosAttrValue *pCosPriority = 0;
+ cosAttributes *pAttributes = 0;
+ cosAttrValue *pObjectclass = 0;
+ cosAttrValue *pCosAttribute = 0;
+ Slapi_Attr *dnAttr;
+ struct berval **dnVals;
+ int itsAnAttr = 0;
+ int valIndex = 0;
+ cosAttrValue **pSneakyVal = 0;
+ char *attrType = 0;
+ struct tmpl_info *info;
+ info = (struct tmpl_info *)callback_data;
+
+ pDn = 0;
+ cos_cache_add_attrval(&pDn, slapi_entry_get_dn(e));
+ pAttributes = 0;
+ pObjectclass = 0;
+ pCosPriority = 0;
+
+ if(!slapi_entry_first_attr(e, &dnAttr))
+ {
+ int attrs_present = 0;
+
+ do
+ {
+ attrType = 0;
+ pCosAttribute = 0;
+
+ /* we need to fill in the details of the template now */
+ slapi_attr_get_type(dnAttr, &attrType);
+
+ if(attrType)
+ {
+ itsAnAttr = 0;
+ pSneakyVal = 0;
+
+ if(!slapi_utf8casecmp((unsigned char*)attrType,
+ (unsigned char*)"objectclass"))
+ pSneakyVal = &pObjectclass;
+
+ if(!slapi_utf8casecmp((unsigned char*)attrType,
+ (unsigned char*)"cosPriority"))
+ pSneakyVal = &pCosPriority;
+
+ if(pSneakyVal == NULL)
+ {
+ /* look for the atrribute in the dynamic attributes */
+ if(cos_cache_attrval_exists(info->pAttrs, attrType))
+ {
+ pSneakyVal = &pCosAttribute;
+ itsAnAttr = 1;
+ attrs_present = 1;
+ }
+ }
+
+ if(pSneakyVal)
+ {
+ if(!slapi_attr_get_bervals_copy(dnAttr, &dnVals))
+ {
+ valIndex = 0;
+
+ if(dnVals)
+ {
+ while(dnVals[valIndex])
+ {
+ if(dnVals[valIndex]->bv_val)
+ cos_cache_add_attrval(pSneakyVal,
+ dnVals[valIndex]->bv_val);
+
+ valIndex++;
+ }
+
+ if(itsAnAttr)
+ {
+ /* got all vals, add this attribute to the attribute list */
+ cos_cache_add_attr(&pAttributes, attrType,
+ *pSneakyVal);
+ }
+
+ ber_bvecfree( dnVals );
+ dnVals = NULL;
+ }
+ }
+ }
+ }
+
+ } while(!slapi_entry_next_attr(e, dnAttr, &dnAttr));
+
+ /*
+ we should now have a full template,
+ do some sanity checks because we don't
+ want bogus entries in the cache if we can help it
+ - then ship it
+ */
+
+ /* these must exist */
+ if(
+ attrs_present &&
+ pObjectclass &&
+ pAttributes &&
+ pDn
+ )
+ {
+ /*
+ we'll leave the referential integrity stuff
+ up to the referint plug-in if set up and assume all
+ is good - if it's not then we just have a
+ useless definition and we'll nag copiously later.
+ */
+
+ if(!cos_cache_add_tmpl(info->pTmpls, pDn, pObjectclass,
+ info->pCosSpecifier, pAttributes,pCosPriority)){
+ info->ret = 0; /* we have succeed to add the tmpl */
+ } else {
+ /* Don't reset info->ret....it keeps track of any success */
+ LDAPDebug(LDAP_DEBUG_ANY, "cos_cache_add_dn_tmpls:"
+ "could not cache cos template %s\n",pDn,0,0);
+ }
+ }
+ else
+ {
+ /*
+ this template is brain dead - bail
+ if we have a dn use it to report, if not then *really* bad
+ things are going on
+ - of course it might not be a template, so lets
+ not tell the world unless the world wants to know,
+ we'll make it a plugin level message
+ */
+ if(pDn)
+ {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_add_dn_tmpls: incomplete cos template detected in %s, discarding from cache.\n",pDn->val,0,0);
+ }
+ else
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_add_dn_tmpls: incomplete cos template detected, no DN to report, discarding from cache.\n",0,0,0);
+
+ if(pObjectclass)
+ cos_cache_del_attrval_list(&pObjectclass);
+ if(pCosAttribute)
+ cos_cache_del_attrval_list(&pCosAttribute);
+ if(pDn)
+ cos_cache_del_attrval_list(&pDn);
+ if(pAttributes)
+ cos_cache_del_attr_list(&pAttributes);
+ }
+ }
+ /*
+ * Always contine the search even if a particular attempt
+ * to add a template failed.
+ */
+ return 0;
+}
+
+/*
+ cos_cache_add_dn_tmpls
+ -------------------------
+ takes a dn as argument and searches the dn for cos templates,
+ adding any found to the template list
+ This is the new version using call back search API
+
+ Returns: zero for success--found at least one good tmpl for this def.
+ non-zero: failed to add any templs for this def.
+*/
+
+#define TMPL_FILTER "(&(objectclass=costemplate)(|(objectclass=costemplate)(objectclass=ldapsubentry)))"
+
+static int cos_cache_add_dn_tmpls(char *dn, cosAttrValue *pCosSpecifier, cosAttrValue *pAttrs, cosTemplates **pTmpls)
+{
+ void *plugin_id;
+ int scope;
+ struct tmpl_info info;
+ Slapi_PBlock *pDnSearch = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_add_dn_tmpls\n",0,0,0);
+
+ /* no cos specifier means this is an indirect scheme */
+ if(pCosSpecifier)
+ scope = LDAP_SCOPE_ONELEVEL;
+ else
+ scope = LDAP_SCOPE_BASE;
+
+ /* Use new internal operation API */
+ pDnSearch = slapi_pblock_new();
+ plugin_id=cos_get_plugin_identity();
+ if (pDnSearch) {
+ info.pAttrs=pAttrs;
+ info.pTmpls=pTmpls;
+ info.pCosSpecifier=pCosSpecifier;
+ info.ret=-1; /* assume no good tmpls */
+ slapi_search_internal_set_pb(pDnSearch, dn, scope,
+ TMPL_FILTER,NULL,0,
+ NULL,NULL,plugin_id,0);
+ slapi_search_internal_callback_pb(pDnSearch,
+ &info /* callback_data */,
+ NULL/* result_callback */,
+ cos_dn_tmpl_entries_cb,
+ NULL /* referral_callback */);
+ slapi_pblock_destroy (pDnSearch);
+ }
+ /*
+ * info.ret comes out zero only if we succeed to add at least one
+ * tmpl to the cache.
+ */
+ return (info.ret);
+}
+
+/*
+ cos_cache_add_defn
+ ------------------
+ Add a cos definition to the list and create the template
+ cache for this definition
+ returns: 0: successfully added the definition to the cache
+ non-zero: failed to add the definition to the cache (eg. because
+ there was no template for it.)
+ ret==COS_DEF_ERROR_NO_TEMPLATES then no templs were found
+ for thsi def. We make a special case of this and pass the
+ back the error so we can roll two messages into one--this
+ is to reduce the number of error messages at cos definiton
+ load time--it is common to see the defs before the tmpls
+ arrive.
+
+*/
+static int cos_cache_add_defn(
+ cosDefinitions **pDefs,
+ cosAttrValue **dn,
+ int cosType,
+ cosAttrValue **tree,
+ cosAttrValue **tmpDn,
+ cosAttrValue **spec,
+ cosAttrValue **pAttrs,
+ cosAttrValue **pOverrides,
+ cosAttrValue **pOperational,
+ cosAttrValue **pCosMerge,
+ cosAttrValue **pCosOpDefault
+ )
+{
+ int ret = 0;
+ int tmplCount = 0;
+ cosDefinitions *theDef = 0;
+ cosAttrValue *pTmpTmplDn = *tmpDn;
+ cosAttrValue *pDummyAttrVal = 0;
+ cosAttrValue *pAttrsIter = 0;
+ cosAttributes *pDummyAttributes = 0;
+ cosAttrValue *pSpecsIter = *spec;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_add_defn\n",0,0,0);
+
+ /* we don't want cosspecifiers that can be supplied by the same scheme */
+ while( pSpecsIter )
+ {
+ if( cos_cache_attrval_exists(*pAttrs, pSpecsIter->val ) )
+ {
+ /* no, this is not sane, lets reject the whole darn scheme in disgust */
+ LDAPDebug( LDAP_DEBUG_ANY, "cos definition %s supplies its own cosspecifier, rejecting scheme\n",(*dn)->val,0,0);
+ ret = -1;
+ }
+
+ pSpecsIter = pSpecsIter->list.pNext;
+ }
+
+ /* create the definition */
+ if(0 == ret)
+ {
+ theDef = (cosDefinitions*) slapi_ch_malloc(sizeof(cosDefinitions));
+ if(theDef)
+ {
+ theDef->pCosTmps = NULL;
+
+ /* process each template in turn */
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "Processing cosDefinition %s\n",(*dn)->val,0,0);
+
+ while(pTmpTmplDn && cosType != COSTYPE_INDIRECT)
+ {
+ /* create the template */
+ if(!cos_cache_add_dn_tmpls(pTmpTmplDn->val, *spec, *pAttrs, &(theDef->pCosTmps)))
+ tmplCount++;
+
+ pTmpTmplDn = pTmpTmplDn->list.pNext;
+ }
+
+ if(tmplCount == 0 && cosType != COSTYPE_INDIRECT)
+ {
+ /* without our golden templates we are nothing
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_add_defn:"
+ "no templates for cos definition at %s.\n",(*dn)->val,0,0);*/
+ ret = COS_DEF_ERROR_NO_TEMPLATES;
+ }
+ else
+ {
+ if(cosType == COSTYPE_INDIRECT)
+ {
+ /*
+ Indirect cos schemes have no templates,
+ however, in order to take advantage of existing code
+ which is optimized to do a binary search on attributes
+ which are found through their templates, we add a dummy
+ template and dummy attributes. The value of the attributes
+ will be ignored when later assessing a query.
+ */
+ pAttrsIter = *pAttrs;
+
+ while(pAttrsIter)
+ {
+ pDummyAttrVal = NULL;
+ cos_cache_add_attrval(&pDummyAttrVal, "not used");
+ cos_cache_add_attr(&pDummyAttributes, pAttrsIter->val, pDummyAttrVal);
+
+ pAttrsIter = pAttrsIter->list.pNext;
+ }
+
+ cos_cache_add_attrval(tmpDn, "cn=dummy,");
+
+ cos_cache_add_tmpl(&(theDef->pCosTmps), *tmpDn, NULL, *spec, pDummyAttributes,NULL);
+ *tmpDn = 0;
+ }
+
+ theDef->pDn = *dn;
+ theDef->cosType = cosType;
+ theDef->pCosTargetTree = *tree;
+ theDef->pCosTemplateDn = *tmpDn;
+ theDef->pCosSpecifier = *spec;
+ theDef->pCosAttrs = *pAttrs;
+ theDef->pCosOverrides = *pOverrides;
+ theDef->pCosOperational = *pOperational;
+ theDef->pCosMerge = *pCosMerge;
+ theDef->pCosOpDefault = *pCosOpDefault;
+
+ cos_cache_add_ll_entry((void**)pDefs, theDef, NULL);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "Added cosDefinition %s\n",(*dn)->val,0,0);
+ }
+ }
+ else
+ {
+ ret = -1;
+ }
+ }
+
+ if(ret == -1)
+ {
+ if(dn)
+ cos_cache_del_attrval_list(dn);
+ if(tree)
+ cos_cache_del_attrval_list(tree);
+ if(tmpDn)
+ cos_cache_del_attrval_list(tmpDn);
+ if(spec)
+ cos_cache_del_attrval_list(spec);
+ if(pAttrs)
+ cos_cache_del_attrval_list(pAttrs);
+ if(theDef)
+ slapi_ch_free((void**)&theDef);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_add_defn\n",0,0,0);
+ return ret;
+}
+
+/*
+ cos_cache_del_attrval_list
+ --------------------------
+ walks the list deleting as it goes
+*/
+static void cos_cache_del_attrval_list(cosAttrValue **pVal)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_del_attrval_list\n",0,0,0);
+
+ while(*pVal)
+ {
+ cosAttrValue *pTmp = (*pVal)->list.pNext;
+
+ slapi_ch_free((void**)&((*pVal)->val));
+ slapi_ch_free((void**)&(*pVal));
+ *pVal = pTmp;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_del_attrval_list\n",0,0,0);
+}
+
+
+/*
+ cos_cache_add_attrval
+ ---------------------
+ adds a value to an attribute value list
+*/
+static int cos_cache_add_attrval(cosAttrValue **attrval, char *val)
+{
+ int ret = 0;
+ cosAttrValue *theVal;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_add_attrval\n",0,0,0);
+
+ /* create the attrvalue */
+ theVal = (cosAttrValue*) slapi_ch_malloc(sizeof(cosAttrValue));
+ if(theVal)
+ {
+ theVal->val = slapi_ch_strdup(val);
+ if(theVal->val)
+ {
+ cos_cache_add_ll_entry((void**)attrval, theVal, NULL);
+ }
+ else
+ {
+ slapi_ch_free((void**)&theVal);
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_add_attrval: failed to allocate memory\n",0,0,0);
+ ret = -1;
+ }
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_add_attrval: failed to allocate memory\n",0,0,0);
+ ret = -1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_add_attrval\n",0,0,0);
+ return ret;
+}
+
+/*
+ cos_cache_add_ll_entry - RECURSIVE for sorted lists
+ ---------------------------------------------------
+ if a compare function is passed as argument, the element
+ is added to the linked list in the sorted order according
+ to that compare functions algorithm. This prepares the list
+ for ultra fast indexing - requiring only to walk the list once
+ to build the index.
+ if no compare function is passed, the element is added
+ to the head of the linked list
+ the index is created after the linked list is complete,
+ and so is always null until explicitly indexed
+
+ *NOTE* this function assumes and *requires* that the structures
+ passed to it in "attrval" and "theVal" have a cosIndexedLinkedList
+ member, and it is the *first* member of the structure. This
+ is safe because this is a module level function, and all functions
+ which call this one are part of the same sub-system.
+
+ The compare function will also make a similar assumption, but
+ likely one that recognizes the full structure or type, it is
+ the responsibility of the caller to match input structures with
+ the appropriate compare function.
+
+ WARNING: current recursive sorting code never used, never tested
+*/
+static void cos_cache_add_ll_entry(void** attrval, void *theVal, int ( *compare )(const void *elem1, const void *elem2 ))
+{
+ static cosIndexedLinkedList *pLastList = 0;
+ static cosIndexedLinkedList *first_element;
+ static int call_count = 0;
+
+ call_count++;
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_add_ll_entry - recursion level %d\n",call_count,0,0);
+
+
+ /*
+ need to save the first element of the list
+ we update this first element whenever an entry
+ is added to the start of the list, this way
+ we can ensure that the head of the list is always
+ *attrval - callers pass us the head of the list
+ and can expect that what they get back is also
+ the head of the list
+ */
+ if(call_count == 1)
+ first_element = *attrval;
+
+ if(*attrval)
+ {
+ if(compare == NULL)
+ {
+ /* we dont want this list sorted */
+ /* push this to the start of the list (because its quick) */
+ ((cosIndexedLinkedList*)theVal)->pNext = *attrval;
+ ((cosIndexedLinkedList*)theVal)->index = NULL;
+ *attrval = theVal;
+ }
+ else
+ {
+ /* insert this in the list in sorted order
+ (because its quicker for building indexes later) */
+ int comp_ret = 0;
+
+ comp_ret = compare(*attrval, theVal);
+ if(comp_ret == 0 || comp_ret > 0)
+ {
+ /* insert prior to this element */
+ if(pLastList)
+ pLastList->pNext = theVal;
+ else
+ first_element = theVal;
+
+ ((cosIndexedLinkedList*)theVal)->pNext = *attrval;
+ ((cosIndexedLinkedList*)theVal)->index = NULL;
+ }
+ else
+ {
+ /* still looking - recurse on next element */
+ pLastList = (cosIndexedLinkedList*)attrval;
+ cos_cache_add_ll_entry(&(((cosIndexedLinkedList*)attrval)->pNext), theVal, compare);
+ }
+
+ if(call_count == 1)
+ *attrval = first_element;
+ }
+ }
+ else
+ {
+ /* new or end of list */
+ ((cosIndexedLinkedList*)theVal)->pNext = NULL;
+ ((cosIndexedLinkedList*)theVal)->index = NULL;
+ if(call_count == 1) /* if new list */
+ *attrval = theVal;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_add_ll_entry - recursion level %d\n",call_count,0,0);
+ call_count--;
+}
+
+
+/*
+ cos_cache_getref
+ ----------------
+ retrieves a reference to the current cache and adds to the cache reference count
+*/
+int cos_cache_getref(cos_cache **pptheCache)
+{
+ int ret = -1;
+ static int first_time = 1;
+ cosCache **ppCache = (cosCache**)pptheCache;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_getref\n",0,0,0);
+
+ if(first_time)
+ {
+ first_time = 0;
+ /* first customer, create the cache */
+ slapi_lock_mutex(change_lock);
+ if(pCache == NULL)
+ {
+ if(cos_cache_create())
+ {
+ /* there was a problem or no COS definitions were found */
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_getref: no cos cache created\n",0,0,0);
+ }
+ }
+ slapi_unlock_mutex(change_lock);
+ }
+
+ slapi_lock_mutex(cache_lock);
+
+ *ppCache = pCache;
+
+ if(pCache)
+ ret = ++((*ppCache)->refCount);
+
+ slapi_unlock_mutex(cache_lock);
+
+
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_getref\n",0,0,0);
+ return ret;
+}
+
+/*
+ cos_cache_addref
+ ----------------
+ adds 1 to the cache reference count
+*/
+int cos_cache_addref(cos_cache *ptheCache)
+{
+ int ret;
+ cosCache *pCache = (cosCache*)ptheCache;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_addref\n",0,0,0);
+
+ slapi_lock_mutex(cache_lock);
+
+ if(pCache)
+ ret = ++(pCache->refCount);
+
+ slapi_unlock_mutex(cache_lock);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_addref\n",0,0,0);
+
+ return ret;
+}
+
+
+/*
+ cos_cache_release
+ -----------------
+ subtracts 1 from the cache reference count, if the count falls
+ below 1, the cache is destroyed.
+*/
+int cos_cache_release(cos_cache *ptheCache)
+{
+ int ret = 0;
+ int destroy = 0;
+ cosCache *pOldCache = (cosCache*)ptheCache;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_release\n",0,0,0);
+
+ slapi_lock_mutex(cache_lock);
+
+ if(pOldCache)
+ {
+ ret = --(pOldCache->refCount);
+ if(ret == 0)
+ destroy = 1;
+ }
+
+ slapi_unlock_mutex(cache_lock);
+
+ if(destroy)
+ {
+ cosDefinitions *pDef = pOldCache->pDefs;
+
+ /* now is the first time it is
+ * safe to assess whether
+ * vattr caching can be turned on
+ */
+ if(pCache && pCache->vattr_cacheable)
+ {
+ slapi_vattrcache_cache_all();
+ }
+
+ /* destroy the cache here - no locking required, no references outstanding */
+
+ if(pDef)
+ cos_cache_del_schema(pOldCache);
+
+ while(pDef)
+ {
+ cosDefinitions *pTmpD = pDef;
+ cosTemplates *pCosTmps = pDef->pCosTmps;
+
+ while(pCosTmps)
+ {
+ cosTemplates *pTmpT = pCosTmps;
+
+ pCosTmps = pCosTmps->list.pNext;
+
+ cos_cache_del_attr_list(&(pTmpT->pAttrs));
+ cos_cache_del_attrval_list(&(pTmpT->pObjectclasses));
+ cos_cache_del_attrval_list(&(pTmpT->pDn));
+ slapi_ch_free((void**)&(pTmpT->cosGrade));
+ slapi_ch_free((void**)&pTmpT);
+ }
+
+ pDef = pDef->list.pNext;
+
+ cos_cache_del_attrval_list(&(pTmpD->pDn));
+ cos_cache_del_attrval_list(&(pTmpD->pCosTargetTree));
+ cos_cache_del_attrval_list(&(pTmpD->pCosTemplateDn));
+ cos_cache_del_attrval_list(&(pTmpD->pCosSpecifier));
+ cos_cache_del_attrval_list(&(pTmpD->pCosAttrs));
+ cos_cache_del_attrval_list(&(pTmpD->pCosOverrides));
+ cos_cache_del_attrval_list(&(pTmpD->pCosOperational));
+ cos_cache_del_attrval_list(&(pTmpD->pCosMerge));
+ cos_cache_del_attrval_list(&(pTmpD->pCosOpDefault));
+ slapi_ch_free((void**)&pTmpD);
+ }
+
+ if(pOldCache->ppAttrIndex)
+ slapi_ch_free((void**)&(pOldCache->ppAttrIndex));
+ if(pOldCache->ppTemplateList)
+ slapi_ch_free((void**)&(pOldCache->ppTemplateList));
+ slapi_ch_free((void**)&pOldCache);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_release\n",0,0,0);
+
+ return ret;
+}
+
+/*
+ cos_cache_attrval_count
+ -----------------------
+ counts the number of values in the list
+*/
+
+static int cos_cache_attrval_count(cosAttrValue *pVal)
+{
+ int ret = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_attrval_count\n",0,0,0);
+
+ while(pVal)
+ {
+ ret++;
+ pVal = pVal->list.pNext;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_attrval_count\n",0,0,0);
+ return ret;
+}
+
+/*
+ cos_cache_del_attr_list
+ -----------------------
+ walk the list deleting as we go
+*/
+static void cos_cache_del_attr_list(cosAttributes **pAttrs)
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_del_attr_list\n",0,0,0);
+
+ while(*pAttrs)
+ {
+ cosAttributes *pTmp = (*pAttrs)->list.pNext;
+
+ cos_cache_del_attrval_list(&((*pAttrs)->pAttrValue));
+ slapi_ch_free((void**)&((*pAttrs)->pAttrName));
+ slapi_ch_free((void**)&(*pAttrs));
+ *pAttrs = pTmp;
+ }
+
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_del_attr_list\n",0,0,0);
+}
+
+
+/*
+ cos_cache_del_schema
+ --------------------
+ delete the object class lists used for schema checking
+*/
+static void cos_cache_del_schema(cosCache *pCache)
+{
+ char *pLastName = 0;
+ cosAttrValue *pLastRef = 0;
+ int attr_index = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_del_schema\n",0,0,0);
+
+ if(pCache && pCache->attrCount && pCache->ppAttrIndex)
+ {
+ pLastName = pCache->ppAttrIndex[0]->pAttrName;
+ pLastRef = pCache->ppAttrIndex[0]->pObjectclasses;
+
+ for(attr_index=1; attr_index<pCache->attrCount; attr_index++)
+ {
+ if(slapi_utf8casecmp((unsigned char*)pCache->ppAttrIndex[attr_index]->pAttrName, (unsigned char*)pLastName))
+ {
+ /* remember what went before */
+ pLastName = pCache->ppAttrIndex[attr_index]->pAttrName;
+
+ /* then blow it away */
+ cos_cache_del_attrval_list(&(pCache->ppAttrIndex[attr_index]->pObjectclasses));
+ }
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_del_schema\n",0,0,0);
+}
+
+
+/*
+ cos_cache_add_attr
+ ------------------
+ Adds an attribute to the list
+*/
+static int cos_cache_add_attr(cosAttributes **pAttrs, char *name, cosAttrValue *val)
+{
+ int ret =0;
+ cosAttributes *theAttr;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_add_attr\n",0,0,0);
+
+ /* create the attribute */
+ theAttr = (cosAttributes*) slapi_ch_malloc(sizeof(cosAttributes));
+ if(theAttr)
+ {
+ theAttr->pAttrValue = val;
+ theAttr->pObjectclasses = 0; /* schema issues come later */
+ theAttr->pAttrName = slapi_ch_strdup(name);
+ if(theAttr->pAttrName)
+ {
+ cos_cache_add_ll_entry((void**)pAttrs, theAttr, NULL);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_add_attr: Added attribute %s\n",name,0,0);
+ }
+ else
+ {
+ slapi_ch_free((void**)&theAttr);
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_add_attr: failed to allocate memory\n",0,0,0);
+ ret = -1;
+ }
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_add_attr: failed to allocate memory\n",0,0,0);
+ ret = -1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_add_attr\n",0,0,0);
+ return ret;
+}
+
+
+/*
+ cos_cache_add_tmpl
+ ------------------
+ Adds a template to the list
+*/
+static int cos_cache_add_tmpl(cosTemplates **pTemplates, cosAttrValue *dn, cosAttrValue *objclasses, cosAttrValue *pCosSpecifier, cosAttributes *pAttrs,cosAttrValue *cosPriority)
+{
+ int ret =0;
+ cosTemplates *theTemp;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_add_tmpl\n",0,0,0);
+
+ /* create the attribute */
+ theTemp = (cosTemplates*) slapi_ch_malloc(sizeof(cosTemplates));
+ if(theTemp)
+ {
+ char *grade = (char*)slapi_ch_malloc(strlen(dn->val)+1);
+ int grade_index = 0;
+ int index = 0;
+ int template_default = 0;
+
+ slapi_dn_normalize(dn->val);
+
+ /* extract the cos grade */
+ while(dn->val[index] != '=' && dn->val[index] != '\0')
+ index++;
+
+ if(dn->val[index] == '=')
+ {
+ int quotes = 0;
+
+ index++;
+
+ /* copy the grade (supports one level of quote nesting in rdn) */
+ while(dn->val[index] != ',' || dn->val[index-1] == '\\' || quotes == 1)
+ {
+ if(dn->val[index] == '"')
+ {
+ if(quotes == 0)
+ quotes = 1;
+ else
+ quotes = 0;
+ }
+ else
+ {
+ if(dn->val[index] != '\\') /* skip escape chars */
+ {
+ grade[grade_index] = dn->val[index];
+ grade_index++;
+ }
+ }
+
+ index++;
+ }
+
+ grade[grade_index] = '\0';
+
+ /* ok, grade copied, is it the default template? */
+
+ if(pCosSpecifier) /* some schemes don't have one */
+ {
+ char tmpGrade[BUFSIZ];
+
+ if (strlen(pCosSpecifier->val) < (BUFSIZ - 9)) { /* 9 for "-default" */
+ strcpy(tmpGrade, pCosSpecifier->val);
+ strcat(tmpGrade, "-default");
+ if(!slapi_utf8casecmp((unsigned char*)grade, (unsigned char*)tmpGrade))
+ template_default = 1;
+ }
+ else
+ {
+ /*
+ * We shouldn't pass ever through this code as we expect
+ * pCosSpecifier values to be reasonably smaller than BUFSIZ
+ *
+ * only 2 lines of code -> no need to set an indirect char *
+ * duplicate the lines of code for clearness instead
+ */
+ char * newTmpGrade = (char*) slapi_ch_malloc(
+ strlen((pCosSpecifier->val) + 9));
+ strcpy(newTmpGrade, pCosSpecifier->val);
+ strcat(newTmpGrade, "-default");
+ if(!slapi_utf8casecmp((unsigned char*)grade, (unsigned char*)newTmpGrade))
+ template_default = 1;
+ slapi_ch_free((void**)&newTmpGrade);
+ }
+ }
+
+ }
+ else
+ {
+ /* mmm, should never get here, it means the dn is whacky */
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_add_tmpl: malformed dn detected: %s\n",dn,0,0);
+ grade[0] = '\0';
+ }
+
+ /* now fill in the blanks */
+ theTemp->pDn = dn;
+ theTemp->pObjectclasses = objclasses;
+ theTemp->pAttrs = pAttrs;
+ theTemp->cosGrade = slapi_ch_strdup(grade);
+ theTemp->template_default = template_default;
+ theTemp->cosPriority = (unsigned long)-1;
+
+ if(cosPriority)
+ {
+ theTemp->cosPriority = atol(cosPriority->val);
+ cos_cache_del_attrval_list(&cosPriority);
+ }
+
+ cos_cache_add_ll_entry((void**)pTemplates, theTemp, NULL);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_add_tmpl: Added template %s\n",dn->val,0,0);
+
+ slapi_ch_free((void**)&grade);
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_add_tmpl: failed to allocate memory\n",0,0,0);
+ ret = -1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_add_tmpl\n",0,0,0);
+ return ret;
+}
+
+/*
+ cos_cache_attrval_exists
+ ------------------------
+ performs linear search on the list for a
+ cosAttrValue that matches val
+ however, if the "index" member of cosAttrValue
+ is non-null then a binary search is performed
+ on the index {PARPAR: TO BE DONE}
+
+ return 1 on found, 0 otherwise
+*/
+static int cos_cache_attrval_exists(cosAttrValue *pAttrs, const char *val)
+{
+ int ret = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_attrval_exists\n",0,0,0);
+
+ while(pAttrs)
+ {
+ if(!slapi_utf8casecmp((unsigned char*)pAttrs->val,(unsigned char*)val))
+ {
+ ret = 1;
+ break;
+ }
+
+ pAttrs = pAttrs->list.pNext;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_attrval_exists\n",0,0,0);
+ return ret;
+}
+
+
+
+static int cos_cache_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *free_flags, void *hint)
+{
+ int ret = -1;
+ cos_cache *pCache = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_vattr_get\n",0,0,0);
+
+ if(cos_cache_getref(&pCache) < 1)
+ {
+ /* problems we are hosed */
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_vattr_get: failed to get class of service reference\n",0,0,0);
+ goto bail;
+ }
+
+ ret = cos_cache_query_attr(pCache, c, e, type, results, NULL, NULL, NULL);
+ if(ret == 0)
+ {
+ *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
+ *actual_type_name = slapi_ch_strdup(type);
+ *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ }
+ cos_cache_release(pCache);
+
+bail:
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_vattr_get\n",0,0,0);
+ return ret;
+}
+
+
+static int cos_cache_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result, int flags, void *hint)
+{
+ int ret = -1;
+ cos_cache *pCache = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_vattr_compare\n",0,0,0);
+
+ if(cos_cache_getref(&pCache) < 1)
+ {
+ /* problems we are hosed */
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_vattr_compare: failed to get class of service reference\n",0,0,0);
+ goto bail;
+ }
+
+ ret = cos_cache_query_attr(pCache, c, e, type, NULL, test_this, result, NULL);
+
+ cos_cache_release(pCache);
+
+bail:
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_vattr_compare\n",0,0,0);
+ return ret;
+}
+
+/*
+ * this imp is damn slow
+ *
+ */
+static int cos_cache_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,
+ vattr_type_list_context *type_context,int flags)
+{
+ int ret = 0;
+ int index = 0;
+ cosCache *pCache;
+ char *lastattr = "thisisfakeforcos";
+ int props = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_vattr_types\n",0,0,0);
+
+ if(cos_cache_getref((cos_cache **)&pCache) < 1)
+ {
+ /* problems we are hosed */
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_vattr_types: failed to get class of service reference\n",0,0,0);
+ goto bail;
+ }
+
+ while(index < pCache->attrCount )
+ {
+ if(slapi_utf8casecmp(
+ (unsigned char *)pCache->ppAttrIndex[index]->pAttrName,
+ (unsigned char *)lastattr))
+ {
+ lastattr = pCache->ppAttrIndex[index]->pAttrName;
+
+ if(1 == cos_cache_query_attr(pCache, NULL, e, lastattr, NULL, NULL,
+ NULL, &props))
+ {
+ /* entry contains this attr */
+ vattr_type_thang thang = {0};
+
+ thang.type_name = lastattr;
+ thang.type_flags = props;
+
+ slapi_vattrspi_add_type(type_context,&thang,0);
+ }
+
+ }
+
+ index++;
+ }
+
+ cos_cache_release(pCache);
+
+bail:
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_vattr_types\n",0,0,0);
+ return ret;
+}
+
+
+/*
+ cos_cache_query_attr
+ --------------------
+ queries the cache to determine if this entry
+ should have an attribute of "type", and if so,
+ returns the attribute values in "vals" - which
+ should be subsequently freed by a call to
+ cos_cache_query_attr_free()
+
+ returns
+ 0 on success, we added a computed attribute
+ 1 on outright failure
+ -1 when doesn't know about attribute
+
+ {PARPAR} must also check the attribute does not exist if we are not
+ overriding and allow the DS logic to pick it up by denying knowledge
+ of attribute
+*/
+static int cos_cache_query_attr(cos_cache *ptheCache, vattr_context *context, Slapi_Entry *e, char *type, Slapi_ValueSet **out_attr, Slapi_Value *test_this, int *result, int *props)
+{
+ int ret = -1;
+ cosCache *pCache = (cosCache*)ptheCache;
+ char *pDn = 0;
+ Slapi_Attr *pObjclasses = 0;
+ int attr_index = 0; /* for looping through attributes */
+ int attr_matched_index = 0; /* for identifying the matched attribute */
+ int hit = 0;
+ cosAttributes *pDefAttr = 0;
+ Slapi_ValueSet* results = 0;
+ Slapi_Value *val;
+/* int type_name_disposition;
+ char *actual_type_name;
+ int flags = 0;
+ int free_flags;*/
+ Slapi_Attr *pTmpVals;
+ int using_default = 0;
+ int entry_has_value = 0;
+ int merge_mode = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_query_attr\n",0,0,0);
+
+
+ if(out_attr)
+ *out_attr = 0;
+
+ /*
+ to perform this operation we need to know:
+
+ * if we know about the attribute, if not just exit
+ --
+ * dn,to determine its relevancy to any cos definition,
+ it must be a child of cosTargetTree
+ --
+ * objectclasses,to determine if the cos attribute will
+ violate schema (only when schema checking is on)
+ --
+ * class of service specifier, for matching definitions
+ - cosSpecifier is the attribute name and is used to
+ determine the cosDefinition to use, its value determines
+ the template to use
+ --
+ * the cosAttribute(s) (from the cosDefinition(s)) that match
+ the attribute name.
+ ($$)If these have a postfix of "default", then it is the same
+ as no postfix i.e. this acts as the default value. If it has
+ a postfix of "override", then the value in the matching template
+ is used regardless of any value stored in the entry. This has
+ been worked out previously so we can use a bool indicator in
+ the cosDefinition structure to determine what to do.
+ --
+ * the value of the attribute in the entry -
+ if present it overrides any default template value (see $$)
+
+ Also this ordering ensures least work done to fail (in this
+ implementation)
+ */
+
+ /** attribute **/
+ /*
+ lets be sure we need to do something
+ most of the time we probably don't
+ */
+ attr_index = cos_cache_find_attr(pCache, type);
+ if(attr_index == -1)
+ {
+ /* we don't know about this attribute */
+ goto bail;
+ }
+
+ /*
+ if there is a value in the entry the outcome
+ of the cos attribute resolution may be different
+ */
+ slapi_entry_attr_find(e, type, &pTmpVals);
+ if(pTmpVals)
+ entry_has_value = 1;
+
+ /** dn **/
+ pDn = slapi_entry_get_dn(e);
+
+ if(pDn == 0)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_query_attr: failed to get entry dn\n",0,0,0);
+ ret = 1;
+ goto bail;
+ }
+
+ slapi_dn_normalize( pDn );
+
+ /** objectclasses **/
+ if(pCache->ppAttrIndex[attr_index]->attr_operational == 0 && config_get_schemacheck() &&
+ pCache->ppAttrIndex[attr_index]->attr_operational_default == 0)
+ {
+ /* does this entry violate schema? */
+
+ if(slapi_entry_attr_find( e, "objectclass", &pObjclasses ))
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_query_attr: failed to get objectclass from %s\n",pDn,0,0);
+ goto bail;
+ }
+
+ if(!cos_cache_schema_check(pCache, attr_index, pObjclasses))
+ {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_query_attr: cos attribute %s failed schema check on dn: %s\n",type,pDn,0);
+ goto bail;
+ }
+ }
+
+ /** class of service specifier **/
+ /*
+ now we need to iterate through the attributes to discover
+ if one fits all the criteria, we'll take the first that does
+ and blow off the rest
+ */
+ do
+ {
+ /* for convenience, define some pointers */
+ cosAttributes *pAttr = pCache->ppAttrIndex[attr_index];
+ cosTemplates *pTemplate = (cosTemplates*)pAttr->pParent;
+ cosDefinitions *pDef = (cosDefinitions*)pTemplate->pParent;
+ cosAttrValue *pTargetTree = pDef->pCosTargetTree;
+
+ /* now for the tests */
+
+ /* would we be allowed to supply this attribute if we had one? */
+ if(entry_has_value && pAttr->attr_override == 0 && pAttr->attr_operational == 0)
+ {
+ /* answer: no, move on to the next attribute */
+ attr_index++;
+ continue;
+ }
+
+ /* if we are in merge_mode, can the attribute be merged? */
+ if(merge_mode && pAttr->attr_cos_merge == 0)
+ {
+ /* answer: no, move on to the next attribute */
+ attr_index++;
+ continue;
+ }
+
+ /* is this entry a child of the target tree(s)? */
+ do
+ {
+ if(pTargetTree)
+ slapi_dn_normalize( pTargetTree->val );
+
+ if( pTargetTree->val == 0 ||
+ slapi_dn_issuffix(pDn, pTargetTree->val) != 0 ||
+ (views_api && views_entry_exists(views_api, pTargetTree->val, e)) /* might be in a view */
+ )
+ {
+ cosAttrValue *pSpec = pDef->pCosSpecifier;
+ Slapi_ValueSet *pAttrSpecs = 0;
+
+
+ /* Does this entry have a correct cosSpecifier? */
+ do
+ {
+ Slapi_ValueSet *results = 0;
+ int type_name_disposition = 0;
+ char *actual_type_name = 0;
+ int free_flags = 0;
+
+ if(pSpec && pSpec->val) {
+ slapi_vattr_values_get_sp(context, e, pSpec->val, &pAttrSpecs, &type_name_disposition, &actual_type_name, 0, &free_flags);
+ /* MAB: We need to free actual_type_name here !!!
+ XXX BAD--should use slapi_vattr_values_free() */
+ slapi_ch_free((void **) &actual_type_name);
+ }
+
+ if(pAttrSpecs || pDef->cosType == COSTYPE_POINTER)
+ {
+ int index = 0;
+
+ /* does the cosSpecifier value correspond to this template? */
+ if(pDef->cosType == COSTYPE_INDIRECT)
+ {
+ /*
+ it always does correspond for indirect schemes (it's a dummy value)
+ now we must follow the dn of our pointer and retrieve a value to
+ return
+ Note: we support one dn only, the result of multiple pointers is undefined
+ */
+ Slapi_Value *indirectdn;
+ int pointer_flags = 0;
+
+ slapi_valueset_first_value( pAttrSpecs, &indirectdn );
+
+ if(props)
+ pointer_flags = *props;
+
+ if( indirectdn != NULL &&
+ !cos_cache_follow_pointer( context, (char*)slapi_value_get_string(indirectdn), type, out_attr, test_this, result, pointer_flags))
+ hit = 1;
+ }
+ else
+ {
+ if(pDef->cosType != COSTYPE_POINTER)
+ index = slapi_valueset_first_value( pAttrSpecs, &val );
+
+ while(pDef->cosType == COSTYPE_POINTER || val)
+ {
+ if(pDef->cosType == COSTYPE_POINTER || !slapi_utf8casecmp((unsigned char*)pTemplate->cosGrade, (unsigned char*)slapi_value_get_string(val)))
+ {
+ /* we have a hit */
+
+
+ if(out_attr)
+ {
+ if(cos_cache_cos_2_slapi_valueset(pAttr, out_attr) == 0)
+ hit = 1;
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_query_attr: could not create values to return\n",0,0,0);
+ goto bail;
+ }
+
+ if(pAttr->attr_cos_merge)
+ {
+ merge_mode = 1;
+ attr_matched_index = attr_index;
+ }
+ }
+ else
+ {
+ if(test_this && result)
+ {
+ /* compare op */
+ if(cos_cache_cmp_attr(pAttr, test_this, result))
+ {
+ hit = 1;
+ }
+ }
+ else
+ {
+ /* well, this must be a request for type only */
+ hit = 1;
+ }
+ }
+
+ break;
+ }
+
+ if(pDef->cosType != COSTYPE_POINTER)
+ index = slapi_valueset_next_value( pAttrSpecs, index, &val );
+ }
+ }
+ }
+
+ if(pSpec)
+ pSpec = pSpec->list.pNext;
+
+ } while(hit == 0 && pSpec);
+
+ /* MAB: We need to free pAttrSpecs here !!!
+ XXX BAD--should use slapi_vattr_values_free()*/
+ slapi_valueset_free(pAttrSpecs);
+
+ /* is the cosTemplate the default template? */
+ if(hit == 0 && pTemplate->template_default && !pDefAttr)
+ {
+ /* then lets save the attr in case we need it later */
+ pDefAttr = pAttr;
+ }
+ }
+
+ pTargetTree = pTargetTree->list.pNext;
+
+ } while(hit == 0 && pTargetTree);
+
+
+ if(hit==0 || merge_mode)
+ attr_index++;
+
+ } while(
+ (hit == 0 || merge_mode) &&
+ pCache->attrCount > attr_index &&
+ !slapi_utf8casecmp((unsigned char*)type, (unsigned char*)pCache->ppAttrIndex[attr_index]->pAttrName)
+ );
+
+ if(!merge_mode)
+ attr_matched_index = attr_index;
+
+ /* should we use a default value? */
+ if(hit == 0 && pDefAttr)
+ {
+ /* we have a hit */
+
+ using_default = 1;
+
+ if(out_attr)
+ {
+ if(cos_cache_cos_2_slapi_valueset(pDefAttr, out_attr) == 0)
+ hit = 1;
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_query_attr: could not create values to return\n",0,0,0);
+ goto bail;
+ }
+ }
+ else
+ {
+ if(test_this && result)
+ {
+ /* compare op */
+ if(cos_cache_cmp_attr(pDefAttr, test_this, result))
+ hit = 1;
+ }
+ else
+ {
+ /* well, this must be a request for type only and the entry gets default template value */
+ hit = 1;
+ }
+ }
+ }
+
+ if(hit == 1 && out_attr == NULL && test_this == NULL)
+ ret = 1;
+ else if(hit == 1)
+ ret = 0;
+
+ if(props)
+ *props = 0;
+
+ if(hit == 1 && props && pDefAttr) {
+ if (
+ ((using_default && pDefAttr->attr_operational == 1) ||
+ (!using_default && pCache->ppAttrIndex[attr_matched_index]->attr_operational == 1)) ||
+ ((using_default && pDefAttr->attr_operational_default == 1) ||
+ (!using_default && pCache->ppAttrIndex[attr_matched_index]->attr_operational_default == 1)) )
+ {
+ /* this is an operational attribute, lets mark it so */
+ *props |= SLAPI_ATTR_FLAG_OPATTR;
+ }
+ }
+
+bail:
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_query_attr\n",0,0,0);
+ return ret;
+}
+
+/*
+ cos_cache_query_attr_free
+ -------------------------
+ frees the memory allocated for the data returned
+ by cos_cache_query_attr
+*/
+static void cos_cache_query_attr_free(struct berval ***vals)
+{
+ int index = 0;
+
+ while((*vals)[index])
+ {
+ slapi_ch_free((void**)&((*vals)[index]));
+ index++;
+ }
+
+ slapi_ch_free((void**)*vals);
+}
+
+/*
+ cos_cache_find_attr
+ -------------------
+ searches for the attribute "type", and if found returns the index
+ of the first occurrance of the attribute in the cache top level
+ indexed attribute list.
+*/
+static int cos_cache_find_attr(cosCache *pCache, char *type)
+{
+ int ret = -1; /* assume failure */
+ cosAttributes attr;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_find_attr\n",0,0,0);
+
+ attr.pAttrName = type;
+
+ if(pCache->attrCount-1 != 0)
+ ret = cos_cache_attr_index_bsearch(pCache, &attr, 0, pCache->attrCount-1);
+ else
+ {
+ /* only one attribute (that will fool our bsearch) lets check it here */
+ if(!slapi_utf8casecmp((unsigned char*)type, (unsigned char*)(pCache->ppAttrIndex)[0]->pAttrName))
+ {
+ ret = 0;
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_find_attr\n",0,0,0);
+ return ret;
+}
+
+
+/*
+ cos_cache_schema_check
+ ----------------------
+ check those object classes which match in the input list and the
+ cached set for allowed attribute types
+
+ return non-null for schema matches, zero otherwise
+*/
+static int cos_cache_schema_check(cosCache *pCache, int attr_index, Slapi_Attr *pObjclasses)
+{
+ int ret = 0; /* assume failure */
+ Slapi_Value *val;
+ int hint;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_schema_check\n",0,0,0);
+
+ hint = slapi_attr_first_value( pObjclasses, &val );
+ while(hint != -1)
+ {
+ ret = cos_cache_attrval_exists(pCache->ppAttrIndex[attr_index]->pObjectclasses, (char*) slapi_value_get_string(val));
+ if(ret)
+ break;
+
+ hint = slapi_attr_next_value( pObjclasses, hint, &val );
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_schema_check\n",0,0,0);
+ return ret;
+}
+
+/*
+ cos_cache_schema_build
+ ----------------------
+ For each attribute in our global cache add the objectclasses which allow it.
+ This may be referred to later to check schema is not being violated.
+*/
+static int cos_cache_schema_build(cosCache *pCache)
+{
+ int ret = 0; /* we assume success, with operational attributes not supplied in schema we might fail otherwise */
+ struct objclass *oc;
+ char *pLastName = 0;
+ cosAttrValue *pLastRef = 0;
+ int attr_index = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_schema_build\n",0,0,0);
+
+ if(!config_get_schemacheck())
+ ret = 0;
+
+ /*
+ it is expected that in all but the most hard core cases, the number of
+ objectclasses will out number the attributes we look after - so we make
+ the objectclasses the outside loop. However, even if they are not, we
+ perform binary searches on the attribute list anyway, so it should be
+ considerably faster to search than the linked list of objectclasses (even
+ with the string comparisons going on)
+ */
+ oc_lock_read();
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next )
+ {
+ char **pppAttrs[2];
+ int index;
+ int attrType = 0;
+
+ pppAttrs[0] = oc->oc_required;
+ pppAttrs[1] = oc->oc_allowed;
+
+ /* we need to check both required and allowed attributes I think */
+ while(attrType < 2)
+ {
+ if(pppAttrs[attrType])
+ {
+ index = 0;
+
+ while(pppAttrs[attrType][index])
+ {
+ attr_index = cos_cache_find_attr(pCache, pppAttrs[attrType][index]);
+ if(attr_index != -1)
+ {
+ /*
+ this attribute is one of ours, add this
+ objectclass to the objectclass list
+ note the index refers to the first
+ occurrence of this attribute in the list,
+ later we will copy over references to this
+ list to all the other attribute duplicates.
+ */
+
+ cos_cache_add_attrval(&(pCache->ppAttrIndex[attr_index]->pObjectclasses), oc->oc_name);
+ ret = 0;
+ }
+ index++;
+ }
+ }
+
+ attrType++;
+ }
+ }
+ oc_unlock();
+
+ /*
+ OK, now we need to add references to the real
+ lists to the duplicate attribute entries.
+ (this allows the schema check to be a little
+ less complex and just a little quicker)
+ */
+ pLastName = pCache->ppAttrIndex[0]->pAttrName;
+ pLastRef = pCache->ppAttrIndex[0]->pObjectclasses;
+
+ for(attr_index=1; attr_index<pCache->attrCount; attr_index++)
+ {
+ if(!slapi_utf8casecmp((unsigned char*)pCache->ppAttrIndex[attr_index]->pAttrName, (unsigned char*)pLastName))
+ {
+ /* copy over reference */
+ pCache->ppAttrIndex[attr_index]->pObjectclasses = pLastRef;
+ }
+ else
+ {
+ /* remember what went before */
+ pLastName = pCache->ppAttrIndex[attr_index]->pAttrName;
+ pLastRef = pCache->ppAttrIndex[attr_index]->pObjectclasses;
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_schema_build\n",0,0,0);
+ return ret;
+}
+
+
+/*
+ cos_cache_index_all
+ -------------------
+ Indexes every attribute in the cache for fast binary lookup
+ on attributes from the top level of the cache.
+ Also fixes up all parent pointers so that a single attribute
+ lookup will allow access to all information regarding that attribute.
+ Attributes that appear more than once in the cache will also
+ be indexed more than once - this means that a pure binary
+ search is not possible, but it is possible to make use of a
+ duplicate entry aware binary search function - which are rare beasts,
+ so we'll need to provide cos_cache_attr_bsearch()
+
+ This is also a handy time to mark the attributes as overides if
+ necessary
+*/
+
+static int cos_cache_index_all(cosCache *pCache)
+{
+ int ret = -1;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_index_all\n",0,0,0);
+
+ /*
+ first fixup the index array so we can use qsort()
+ also fixup the parent pointers
+ */
+
+ pCache->ppTemplateList = 0;
+ pCache->templateCount = 0;
+ pCache->ppAttrIndex = 0;
+
+ pCache->attrCount = cos_cache_total_attr_count(pCache);
+ if(pCache->attrCount && pCache->templateCount)
+ {
+ int tmpindex = 0;
+ int cmpindex = 0;
+ int actualCount = 0;
+
+ pCache->ppAttrIndex = (cosAttributes**)slapi_ch_malloc(sizeof(cosAttributes*) * pCache->attrCount);
+ pCache->ppTemplateList = (char**)slapi_ch_calloc((pCache->templateCount + 1) * 2, sizeof(char*));
+ if(pCache->ppAttrIndex && pCache->ppTemplateList)
+ {
+ int attrcount = 0;
+ cosDefinitions *pDef = pCache->pDefs;
+ cosAttrValue *pAttrVal = 0;
+
+ while(pDef)
+ {
+ cosTemplates *pCosTmps = pDef->pCosTmps;
+
+ while(pCosTmps)
+ {
+ cosAttributes *pAttrs = pCosTmps->pAttrs;
+
+ pCosTmps->pParent = pDef;
+
+ while(pAttrs)
+ {
+ pAttrs->pParent = pCosTmps;
+ (pCache->ppAttrIndex)[attrcount] = pAttrs;
+
+ if(cos_cache_attrval_exists(pDef->pCosOverrides, pAttrs->pAttrName))
+ pAttrs->attr_override = 1;
+ else
+ pAttrs->attr_override = 0;
+
+ if(cos_cache_attrval_exists(pDef->pCosOperational, pAttrs->pAttrName))
+ pAttrs->attr_operational = 1;
+ else
+ pAttrs->attr_operational = 0;
+
+ if(cos_cache_attrval_exists(pDef->pCosMerge, pAttrs->pAttrName))
+ pAttrs->attr_cos_merge = 1;
+ else
+ pAttrs->attr_cos_merge = 0;
+
+ if(cos_cache_attrval_exists(pDef->pCosOpDefault, pAttrs->pAttrName))
+ pAttrs->attr_operational_default = 1;
+ else
+ pAttrs->attr_operational_default = 0;
+
+ attrcount++;
+
+ pAttrs = pAttrs->list.pNext;
+ }
+
+ pCosTmps = pCosTmps->list.pNext;
+ }
+
+ /*
+ we need to build the template dn list too,
+ we are going to take care that we do not
+ add duplicate dns or dns that have
+ ancestors elsewhere in the list since this
+ list will be binary searched (with a special
+ BS alg) to find an ancestor tree for a target
+ that has been modified - that comes later in
+ this function however - right now we'll just
+ slap them in the list
+ */
+ pAttrVal = pDef->pCosTemplateDn;
+
+ while(pAttrVal)
+ {
+ slapi_dn_normalize(pAttrVal->val);
+ pCache->ppTemplateList[tmpindex] = pAttrVal->val;
+
+ tmpindex++;
+ pAttrVal = pAttrVal->list.pNext;
+ }
+
+ pDef = pDef->list.pNext;
+ }
+
+ /* now sort the index array */
+ qsort(pCache->ppAttrIndex, attrcount, sizeof(cosAttributes*), cos_cache_attr_compare);
+ qsort(pCache->ppTemplateList, tmpindex, sizeof(char*), cos_cache_string_compare);
+
+ /*
+ now we have the sorted template dn list, we can get rid of
+ duplicates and entries that have an ancestor elsewhere in
+ the list - all this in the name of faster searches
+ */
+
+ /* first go through zapping the useless PARPAR - THIS DOES NOT WORK */
+ tmpindex = 1;
+ cmpindex = 0;
+ actualCount = pCache->templateCount;
+
+ while(tmpindex < pCache->templateCount)
+ {
+ if(
+ !slapi_utf8casecmp((unsigned char*)pCache->ppTemplateList[tmpindex],(unsigned char*)pCache->ppTemplateList[cmpindex]) ||
+ slapi_dn_issuffix(pCache->ppTemplateList[tmpindex], pCache->ppTemplateList[cmpindex])
+ )
+ {
+ /* this guy is a waste of space */
+ pCache->ppTemplateList[tmpindex] = 0;
+ actualCount--;
+ }
+ else
+ cmpindex = tmpindex;
+
+ tmpindex++;
+ }
+
+ /* now shuffle everything up to the front to cover the bald spots */
+ tmpindex = 1;
+ cmpindex = 0;
+
+ while(tmpindex < pCache->templateCount)
+ {
+ if(pCache->ppTemplateList[tmpindex] != 0)
+ {
+ if(cmpindex)
+ {
+ pCache->ppTemplateList[cmpindex] = pCache->ppTemplateList[tmpindex];
+ pCache->ppTemplateList[tmpindex] = 0;
+ cmpindex++;
+ }
+ }
+ else
+ {
+ if(cmpindex == 0)
+ cmpindex = tmpindex;
+ }
+
+ tmpindex++;
+ }
+
+ pCache->templateCount = actualCount;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos: cos cache index built\n",0,0,0);
+
+ ret = 0;
+ }
+ else
+ {
+ if(pCache->ppAttrIndex)
+ slapi_ch_free((void**)(&pCache->ppAttrIndex));
+
+ if(pCache->ppTemplateList)
+ slapi_ch_free((void**)(&pCache->ppTemplateList));
+
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_index_all: failed to allocate index memory\n",0,0,0);
+ }
+ }
+ else
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_index_all: no attributes to index\n",0,0,0);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_index_all\n",0,0,0);
+ return ret;
+}
+
+
+/*
+ cos_cache_total_attr_count
+ --------------------------
+ walks the entire cache counting all attributes
+ note: this is coded so that it may be called
+ prior to the cache indexing of attributes - in
+ fact it is called by the code that creates the
+ index. Once indexing has been performed, it is
+ *much* *much* faster to get the count from the
+ cache object itself - cosCache::attrCount.
+
+ Additionally - a side effect is that the template
+ target trees are counted and placed in the cache level
+ target tree count - probably should be renamed,
+ but lets let it slide for now
+
+ returns the number of attributes counted
+*/
+static int cos_cache_total_attr_count(cosCache *pCache)
+{
+ int count = 0;
+ cosDefinitions *pDef = pCache->pDefs;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_total_attr_count\n",0,0,0);
+
+ pCache->templateCount = 0;
+
+ while(pDef)
+ {
+ cosTemplates *pCosTmps = pDef->pCosTmps;
+
+ while(pCosTmps)
+ {
+ cosAttributes *pAttrs = pCosTmps->pAttrs;
+
+ while(pAttrs)
+ {
+ count++;
+ pAttrs = pAttrs->list.pNext;
+ }
+
+ pCache->templateCount++;
+ pCosTmps = pCosTmps->list.pNext;
+ }
+
+ pDef = pDef->list.pNext;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_total_attr_count\n",0,0,0);
+ return count;
+}
+
+
+/*
+ cos_cache_XXX_compare
+ ---------------------
+ this set of functions are passed to sorting and searching
+ functions to provide an ordering comparison between to structures
+*/
+#if 0
+int cos_cache_attrval_compare(const void *e1, const void *e2)
+{
+ return slapi_utf8casecmp((unsigned char*)(*(cosAttrValue**)e1)->val,(unsigned char*)(*(cosAttrValue**)e2)->val);
+}
+#endif
+
+static int cos_cache_attr_compare(const void *e1, const void *e2)
+{
+ int com_Result;
+ cosAttributes *pAttr = (*(cosAttributes**)e1);
+ cosTemplates *pTemplate = (cosTemplates*)pAttr->pParent;
+ cosDefinitions *pDef = (cosDefinitions*)pTemplate->pParent;
+ cosAttrValue *pcostt = pDef->pCosTargetTree;
+ cosAttributes *pAttr1 = (*(cosAttributes**)e2);
+ cosTemplates *pTemplate1 = (cosTemplates*)pAttr1->pParent;
+ cosDefinitions *pDef1 = (cosDefinitions*)pTemplate1->pParent;
+ cosAttrValue *pcostt1 = pDef1->pCosTargetTree;
+
+ /* Now compare the names of the attributes */
+ com_Result = slapi_utf8casecmp((unsigned char*)(*(cosAttributes**)e1)->pAttrName,(unsigned char*)(*(cosAttributes**)e2)->pAttrName);
+ if(0 == com_Result)
+ /* Now compare the definition Dn parents */
+ com_Result = slapi_utf8casecmp((unsigned char*)pcostt1->val,(unsigned char*)pcostt->val);
+ if(0 == com_Result)
+ /* Now compare the cosPririoties */
+ com_Result = pTemplate->cosPriority - pTemplate1->cosPriority;
+ /* Now compare the prirority */
+ if(0 == com_Result)
+ return -1;
+ return com_Result;
+}
+
+#if 0
+int cos_cache_tmpl_compare(const void *e1, const void *e2)
+{
+ return slapi_utf8casecmp((unsigned char*)(*(cosTemplates**)e1)->cosGrade,(unsigned char*)(*(cosTemplates**)e2)->cosGrade);
+}
+#endif
+
+static int cos_cache_string_compare(const void *e1, const void *e2)
+{
+ return slapi_utf8casecmp((*(unsigned char**)e1),(*(unsigned char**)e2));
+}
+
+static int cos_cache_template_index_compare(const void *e1, const void *e2)
+{
+ int ret = 0;
+
+ if(0 == slapi_dn_issuffix((const char*)e1,*(const char**)e2))
+ ret = slapi_utf8casecmp(*(unsigned char**)e2,(unsigned char*)e1);
+ else
+ ret = 0;
+
+ return ret;
+}
+
+/*
+ cos_cache_template_index_bsearch
+ --------------------------------
+ searches the template dn index for a match
+*/
+static int cos_cache_template_index_bsearch(const char *dn)
+{
+ int ret = 0;
+ cosCache *pCache;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_template_index_bsearch\n",0,0,0);
+
+ if(-1 != cos_cache_getref((cos_cache**)&pCache))
+ {
+ if(bsearch(dn, pCache->ppTemplateList, pCache->templateCount, sizeof(char*), cos_cache_template_index_compare))
+ ret = 1;
+
+ cos_cache_release((cos_cache*)pCache);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_template_index_bsearch\n",0,0,0);
+
+ return ret;
+}
+
+/*
+ cos_cache_attr_index_bsearch - RECURSIVE
+ ----------------------------------------
+ performs a binary search on the cache attribute index
+ return -1 if key is not found
+ the index into attribute index array of the first occurrance
+ of that attribute type otherwise
+*/
+static int cos_cache_attr_index_bsearch( const cosCache *pCache, const cosAttributes *key, int lower, int upper )
+{
+ int ret = -1;
+ int index = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_attr_index_bsearch\n",0,0,0);
+
+ if(upper >= lower)
+ {
+ if(upper != 0)
+ index = ((upper-lower)/2) + lower;
+ else
+ index = 0;
+
+ ret = slapi_utf8casecmp((unsigned char*)key->pAttrName, (unsigned char*)(pCache->ppAttrIndex)[index]->pAttrName);
+ if(ret == 0)
+ {
+ /*
+ we have a match, backtrack to the
+ first occurrance of this attribute
+ type
+ */
+ do
+ {
+ index--;
+ if(index >= 0)
+ ret = slapi_utf8casecmp((unsigned char*)key->pAttrName, (unsigned char*)(pCache->ppAttrIndex)[index]->pAttrName);
+ } while(index >= 0 && ret == 0);
+
+ index++;
+ }
+ else
+ {
+ /* seek elsewhere */
+ if(ret < 0)
+ {
+ /* take the low road */
+ index = cos_cache_attr_index_bsearch(pCache, key, lower, index-1);
+ }
+ else
+ {
+ /* go high */
+ index = cos_cache_attr_index_bsearch(pCache, key, index+1, upper);
+ }
+ }
+ }
+ else
+ index = -1;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_attr_index_bsearch\n",0,0,0);
+ return index;
+}
+
+
+static int cos_cache_cmp_attr(cosAttributes *pAttr, Slapi_Value *test_this, int *result)
+{
+ int ret = 0;
+ int index = 0;
+ cosAttrValue *pAttrVal = pAttr->pAttrValue;
+ char *the_cmp = (char *)slapi_value_get_string(test_this);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_cmp_attr\n",0,0,0);
+
+ *result = 0;
+
+ while( pAttrVal )
+ {
+ if(!slapi_utf8casecmp((unsigned char*)the_cmp, (unsigned char*)pAttrVal->val))
+ {
+ /* compare match */
+ *result = 1;
+ break;
+ }
+
+ pAttrVal = pAttrVal->list.pNext;
+ index++;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_cmp_attr\n",0,0,0);
+ return ret;
+}
+
+
+/*
+ cos_cache_cos_2_slapi_attr
+ ----------------------
+ converts a cosAttributes structure to a Slapi_Attribute
+*/
+static int cos_cache_cos_2_slapi_valueset(cosAttributes *pAttr, Slapi_ValueSet **out_vs)
+{
+ int ret = 0;
+ int index = 0;
+ cosAttrValue *pAttrVal = pAttr->pAttrValue;
+ int add_mode = 0;
+ static Slapi_Attr *attr = 0; /* allocated once, never freed */
+ static done_once = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_cos_2_slapi_attr\n",0,0,0);
+
+ /* test out_vs for existing values */
+ if(*out_vs)
+ {
+ add_mode = 1;
+ if(!done_once)
+ {
+ attr = slapi_attr_new(); /* lord knows why this is needed by slapi_valueset_find*/
+ slapi_attr_init(attr, "cos-bogus");
+ done_once = 1;
+ }
+ }
+ else
+ *out_vs = slapi_valueset_new();
+
+ if(*out_vs)
+ {
+ if(!add_mode)
+ slapi_valueset_init(*out_vs);
+
+ while( pAttrVal )
+ {
+ Slapi_Value *val = slapi_value_new_string(pAttrVal->val);
+ if(val) {
+ if(!add_mode || !slapi_valueset_find(attr, *out_vs, val)) {
+ slapi_valueset_add_value_ext(*out_vs, val, SLAPI_VALUE_FLAG_PASSIN);
+ }
+ else {
+ slapi_value_free(&val);
+ }
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_cos_2_slapi_attr: memory allocation error\n",0,0,0);
+ ret = -1;
+ goto bail;
+ }
+
+ pAttrVal = pAttrVal->list.pNext;
+ index++;
+ }
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_cos_2_slapi_attr: memory allocation error\n",0,0,0);
+ ret = -1;
+ }
+
+bail:
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_cos_2_slapi_attr\n",0,0,0);
+ return ret;
+}
+
+
+/*
+ cos_cache_change_notify
+ -----------------------
+ determines if the change effects the cache and if so
+ signals a rebuild.
+
+ XXXrbyrne This whole mechanism needs to be revisited--it means that
+ the modifying client gets his LDAP response, and an unspecified and
+ variable
+ period of time later, his mods get taken into account in the cos cache.
+ This makes it hard to program reliable admin tools for COS--DSAME
+ has already indicated this is an issue for them.
+ Additionally, it regenerates the _whole_ cache even for eeny weeny mods--
+ does it really neeed to ? Additionally, in order to ensure we
+ do not miss any mods, we may tend to regen the cache, even if we've already
+ taken a mod into account in an earlier regeneration--currently there is no
+ way to know we've already dealt with the mod.
+ The right thing is something like: figure out what's being changed
+ and change only that in the cos cache and do it _before_ the response
+ goes to the client....or do a task that he can poll.
+*/
+void cos_cache_change_notify(Slapi_PBlock *pb)
+{
+ char *dn;
+ Slapi_Attr *pObjclasses = 0;
+ int index = 0;
+ int do_update = 0;
+ struct slapi_entry *e;
+ Slapi_Backend *be=NULL;
+ int rc = 0;
+ int optype = -1;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_change_notify\n",0,0,0);
+
+ /* Don't update local cache when remote entries */
+ /* are updated. */
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ if ( ( be!=NULL ) && (slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
+ goto bail;
+
+ /* need to work out if a cache rebuild is necessary */
+ if(slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn ))
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_change_notify: failed to get dn of changed entry",0,0,0);
+ goto bail;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ if (0 != rc) {
+ /* The operation did not succeed. As far as the cos cache is concerned, no need to update anything */
+ goto bail;
+ }
+
+ /*
+ * For DELETE, MODIFY, MODRDN: see if the pre-op entry was cos significant.
+ * For ADD, MODIFY, MODRDN: see if the post-op was cos significant.
+ * Touching a cos significant entry triggers the update
+ * of the whole cache.
+ */
+ slapi_pblock_get ( pb, SLAPI_OPERATION_TYPE, &optype );
+ if ( optype == SLAPI_OPERATION_DELETE ||
+ optype == SLAPI_OPERATION_MODIFY ||
+ optype == SLAPI_OPERATION_MODRDN ) {
+
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
+ if ( cos_cache_entry_is_cos_related(e)) {
+ do_update = 1;
+ }
+ }
+ if ( !do_update &&
+ (optype == SLAPI_OPERATION_ADD ||
+ optype == SLAPI_OPERATION_MODIFY ||
+ optype == SLAPI_OPERATION_MODRDN )) {
+
+ /* Adds have null pre-op entries */
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
+ if ( cos_cache_entry_is_cos_related(e)) {
+ do_update = 1;
+ }
+ }
+
+ /*
+ * Check if this was an entry in a template tree (dn contains
+ * the old dn value).
+ * It's only relevant for indirect templates, which will
+ * not usually contain the "objectclass: costemplate" pair
+ * and so will not get detected by the above code.
+ * In fact, everything would still work fine if
+ * we just ignored a mod of one of these indirect templates,
+ * as we do not cache values from them, but the advantage of
+ * triggering an update here is that
+ * we can maintain the invariant that we only ever cache
+ * definitions that have _valid_ templates--the active cache
+ * stays lean in the face of errors.
+ */
+ if( !do_update && cos_cache_template_index_bsearch(dn)) {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "cos_cache_change_notify:"
+ "updating due to indirect template change(%s)\n",
+ dn,0,0);
+ do_update = 1;
+ }
+
+ /* Do the update if required */
+ if(do_update)
+ {
+ slapi_lock_mutex(change_lock);
+ slapi_notify_condvar( something_changed, 1 );
+ cos_cache_notify_flag = 1;
+ slapi_unlock_mutex(change_lock);
+ }
+
+bail:
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_change_notify\n",0,0,0);
+}
+
+/*
+ cos_cache_stop
+ --------------
+ notifies the cache thread we are stopping
+*/
+void cos_cache_stop()
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_stop\n",0,0,0);
+
+ /* first deregister our state change func */
+ slapi_unregister_backend_state_change((void *)cos_cache_backend_state_change);
+
+ slapi_lock_mutex(change_lock);
+ keeprunning = 0;
+ slapi_notify_condvar( something_changed, 1 );
+ slapi_unlock_mutex(change_lock);
+
+ /* wait on shutdown */
+ slapi_lock_mutex(stop_lock);
+
+ /* release the caches reference to the cache */
+ cos_cache_release(pCache);
+
+ slapi_destroy_mutex(cache_lock);
+ slapi_destroy_mutex(change_lock);
+ slapi_destroy_condvar(something_changed);
+
+ slapi_unlock_mutex(stop_lock);
+ slapi_destroy_mutex(stop_lock);
+ slapi_destroy_condvar(start_cond);
+ slapi_destroy_mutex(start_lock);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_stop\n",0,0,0);
+}
+
+/*
+ cos_cache_backwards_stricmp_and_clip
+ ------------------------------------
+ compares s2 to s1 starting from end of the strings until the beginning of
+ either matches result in the s2 value being clipped from s1 with a NULL char
+ and 1 being returned as opposed to 0
+
+*/
+static int cos_cache_backwards_stricmp_and_clip(char*s1,char*s2)
+{
+ int ret = 0;
+ int s1len = 0;
+ int s2len = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> cos_cache_backwards_stricmp_and_clip\n",0,0,0);
+
+ s1len = strlen(s1);
+ s2len = strlen(s2);
+
+ if(s1len > s2len && s2len > 0)
+ {
+ while(s1len > -1 && s2len > -1)
+ {
+ s1len--;
+ s2len--;
+
+ if(s1[s1len] != s2[s2len])
+ break;
+ else
+ {
+ if(s2len == 0)
+ {
+ /* hit! now clip */
+ ret = 1;
+ s1[s1len] = '\0';
+ }
+ }
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- cos_cache_backwards_stricmp_and_clip\n",0,0,0);
+ return ret;
+}
+
+
+static int cos_cache_follow_pointer( vattr_context *c, const char *dn, char *type, Slapi_ValueSet **out_vs, Slapi_Value *test_this, int *result, int flags)
+{
+ int ret = -1; /* assume failure */
+ Slapi_PBlock *pDnSearch = 0;
+ Slapi_Entry **pEntryList = 0;
+ char *attrs[2];
+ int entryIndex = 0;
+ int op = 0;
+ int type_test = 0;
+ int type_name_disposition = 0;
+ char *actual_type_name = 0;
+ int free_flags = 0;
+ Slapi_ValueSet *tmp_vs = 0;
+
+ attrs[0] = type;
+ attrs[1] = 0;
+
+ /* Use new internal operation API */
+ pDnSearch = slapi_pblock_new();
+ if (pDnSearch) {
+ slapi_search_internal_set_pb(pDnSearch, dn, LDAP_SCOPE_BASE,"(|(objectclass=*)(objectclass=ldapsubentry))",attrs,
+ 0,NULL,NULL,cos_get_plugin_identity(),0);
+ slapi_search_internal_pb(pDnSearch);
+ slapi_pblock_get( pDnSearch, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ }
+
+ if(pDnSearch && (ret == LDAP_SUCCESS))
+ {
+ ret = -1;
+
+ slapi_pblock_get( pDnSearch, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &pEntryList);
+ if(pEntryList)
+ {
+ if(out_vs) /* if this set, a value is required */
+ op = 1;
+ else if(test_this && result) /* compare op */
+ op = 2;
+ else
+ {
+ /* requires only type present */
+ op = 1;
+ type_test = 1;
+ }
+
+ switch(op)
+ {
+ case 1:
+ /* straight value return or type test */
+ if(type_test)
+ out_vs = &tmp_vs;
+
+ ret = slapi_vattr_values_get_sp(c, pEntryList[0], type, out_vs,&type_name_disposition, &actual_type_name, flags, &free_flags);
+
+ if(actual_type_name)
+ slapi_ch_free((void **) &actual_type_name);
+
+ if(type_test && free_flags == SLAPI_VIRTUALATTRS_RETURNED_COPIES)
+ slapi_valueset_free(*out_vs);
+
+ break;
+
+ case 2:
+ /* this must be a compare op */
+ ret = slapi_vattr_value_compare_sp(c, pEntryList[0],type, test_this, result, flags);
+ break;
+
+ default:
+ goto bail;
+ }
+ }
+ }
+
+bail:
+ /* clean up */
+ if(pDnSearch)
+ {
+ slapi_free_search_results_internal(pDnSearch);
+ slapi_pblock_destroy(pDnSearch);
+ }
+
+ return ret;
+}
+
+
+/*
+ * cos_cache_backend_state_change()
+ * --------------------------------
+ * This is called when a backend changes state
+ * We simply signal to rebuild the cos cache in this case
+ *
+ */
+void cos_cache_backend_state_change(void *handle, char *be_name,
+ int old_be_state, int new_be_state)
+{
+ slapi_lock_mutex(change_lock);
+ slapi_notify_condvar( something_changed, 1 );
+ slapi_unlock_mutex(change_lock);
+}
+
+/*
+ * returns non-zero: entry is cos significant (note does not detect indirect
+ * template entries).
+ * 0 : entry is not cos significant.
+*/
+static int cos_cache_entry_is_cos_related( Slapi_Entry *e) {
+
+ int rc = 0;
+ Slapi_Attr *pObjclasses = NULL;
+
+ if ( e == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_change_notify:"
+ "modified entry is NULL--updating cache just in case!",
+ 0,0,0);
+ rc = 1;
+ } else {
+
+ if(slapi_entry_attr_find( e, "objectclass", &pObjclasses ))
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cos_cache_change_notify:"
+ " failed to get objectclass from %s",
+ slapi_entry_get_dn(e),0,0);
+ rc = 0;
+ } else {
+
+ Slapi_Value *val = NULL;
+ int index = 0;
+ char *pObj;
+
+ /* check out the object classes to see if this was a cosDefinition */
+
+ index = slapi_attr_first_value( pObjclasses, &val );
+ while(!rc && val)
+ {
+ pObj = (char*)slapi_value_get_string(val);
+
+ /*
+ * objectclasses are ascii--maybe strcasecmp() is faster than
+ * slapi_utf8casecmp()
+ */
+ if( !strcasecmp(pObj, "cosdefinition") ||
+ !strcasecmp(pObj, "cossuperdefinition") ||
+ !strcasecmp(pObj, "costemplate")
+ )
+ {
+ rc = 1;
+ }
+
+ index = slapi_attr_next_value( pObjclasses, index, &val );
+ }
+ }
+ }
+ return(rc);
+}
diff --git a/ldap/servers/plugins/cos/cos_cache.h b/ldap/servers/plugins/cos/cos_cache.h
new file mode 100644
index 00000000..ef47a9ab
--- /dev/null
+++ b/ldap/servers/plugins/cos/cos_cache.h
@@ -0,0 +1,19 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#if !defined( _COS_CACHE_H )
+#define _COS_CACHE_H
+
+typedef void cos_cache;
+
+int cos_cache_init();
+void cos_cache_stop();
+int cos_cache_getref(cos_cache **ppCache);
+int cos_cache_addref(cos_cache *pCache);
+int cos_cache_release(cos_cache *pCache);
+void cos_cache_change_notify(Slapi_PBlock *pb);
+
+#endif /* _COS_CACHE_H */
diff --git a/ldap/servers/plugins/cos/dllmain.c b/ldap/servers/plugins/cos/dllmain.c
new file mode 100644
index 00000000..fabf8677
--- /dev/null
+++ b/ldap/servers/plugins/cos/dllmain.c
@@ -0,0 +1,96 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/distrib/Makefile b/ldap/servers/plugins/distrib/Makefile
new file mode 100644
index 00000000..3144e8cb
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile
@@ -0,0 +1,109 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# GNU Makefile for Directory Server distribution plugin
+#
+
+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 = $(OBJDIR)/lib/libdistrib
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./libdistrib.def
+endif
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd
+
+DIS_OBJS= \
+ distrib.o
+
+
+OBJS = $(addprefix $(OBJDEST)/, $(DIS_OBJS))
+
+ifeq ($(ARCH), WINNT)
+LIBDIS_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+# The sample distribution plugin is not part of DS.
+# So we generate the shared library outside of $(LIBDIR)
+# so that it's not retreived by the packaging makefiles.
+#LIBDIS = $(addprefix $(LIBDIR)/, $(DIS_DLL).$(DLL_SUFFIX))
+LIBDIS = $(addprefix $(OBJDEST)/, $(DIS_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += \
+ $(LIBSLAPD_DEP) \
+ $(LDAP_LIBUTIL_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP) \
+ $(SECURITY_DEP)
+EXTRA_LIBS += \
+ $(LIBSLAPD) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LIBUTIL) \
+ $(NSPRLINK) \
+ $(LDAP_COMMON_LIBS)
+endif
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += \
+ $(LIBSLAPD_DEP) \
+ $(LDAP_LIBUTIL_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP)
+EXTRA_LIBS += \
+ $(LIBSLAPDLINK) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LIBUTIL) \
+ $(NSPRLINK) \
+ $(LDAP_COMMON_LIBS)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libdistrib.def"
+CFLAGS+= /WX
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+LD=ld
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBDIS)
+
+$(LIBDIS): $(OBJS) $(LIBDIS_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBDIS_DLL_OBJ) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBDIS_DLL_OBJ)
+endif
+ $(RM) $(LIBDIS)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
diff --git a/ldap/servers/plugins/distrib/Makefile.AIX b/ldap/servers/plugins/distrib/Makefile.AIX
new file mode 100644
index 00000000..d155626d
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.AIX
@@ -0,0 +1,44 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# AIX Makefile for Directory Server plug-in examples
+# NOTE: Make sure to set the DSLIB variable to the path
+# to the libslapd_shr.a file (for example,
+# DSLIB = /usr/netscape/suitespot/lib/libslapd_shr.a
+
+CC = xlC_r
+LD = ld
+
+# Set this to the path to the libslapd_shr.a file
+DSLIB =
+
+INCLUDE_FLAGS= -I../../include
+CFLAGS= $(INCLUDE_FLAGS) -qarch=com
+LIBPATH=/usr/lib/threads:/usr/lpp/xlC/lib:/usr/lib:/lib:..:../../../../lib
+EXTRA_LIBS= -bI:/usr/lib/lowsys.exp -lC_r -lC -lpthreads -lc_r -lm \
+ /usr/lib/libc.a $(DSLIB)
+LDFLAGS= -bE:libtest-plugin_shr.exp -bM:SRE -bnoentry -blibpath:$(LIBPATH) \
+ $(EXTRA_LIBS)
+
+OBJS = distrib
+
+all: libtest-plugin_shr.a
+
+
+libtest-plugin_shr.a: $(OBJS)
+ rm -f libtest-plugin_shr.exp
+ echo "#!" > libtest-plugin_shr.exp
+ nm -B -C -g $(OBJS) | \
+ awk '/ [B,T,D] / {print $$3}' | \
+ sed -e 's/^\.//' | sort -u >> libtest-plugin_shr.exp
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin_shr.a
+
diff --git a/ldap/servers/plugins/distrib/Makefile.BSDI b/ldap/servers/plugins/distrib/Makefile.BSDI
new file mode 100644
index 00000000..c8016c9e
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.BSDI
@@ -0,0 +1,30 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.HPUX b/ldap/servers/plugins/distrib/Makefile.HPUX
new file mode 100644
index 00000000..34c24521
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.HPUX
@@ -0,0 +1,27 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# HPUX Makefile for Directory Server plug-in examples
+
+CC = cc
+LD = ld
+
+INCLUDE = -I../../include
+CFLAGS=$(INCLUDE) -D_HPUX_SOURCE -Aa +DA1.0 +z
+LDFLAGS = -b
+
+OBJS = distrib.o
+
+all: libtest-plugin.sl
+
+libtest-plugin.sl: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.sl
diff --git a/ldap/servers/plugins/distrib/Makefile.HPUX64 b/ldap/servers/plugins/distrib/Makefile.HPUX64
new file mode 100644
index 00000000..d6a09339
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.HPUX64
@@ -0,0 +1,27 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# HPUX Makefile for Directory Server plug-in examples
+
+CC = cc
+LD = ld
+
+INCLUDE = -I../../include
+CFLAGS=$(INCLUDE) -D_HPUX_SOURCE -Aa +DA2.0W +z
+LDFLAGS = -b
+
+OBJS = distrib.o
+
+all: libtest-plugin.sl
+
+libtest-plugin.sl: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.sl
diff --git a/ldap/servers/plugins/distrib/Makefile.IRIX b/ldap/servers/plugins/distrib/Makefile.IRIX
new file mode 100644
index 00000000..f2ffc0c7
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.IRIX
@@ -0,0 +1,30 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# IRIX Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../../include
+CFLAGS = $(INCLUDE_FLAGS) -D_SGI_MP_SOURCE -fullwarn
+LDFLAGS = -32 -shared
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.Linux b/ldap/servers/plugins/distrib/Makefile.Linux
new file mode 100644
index 00000000..b5fe839f
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.Linux
@@ -0,0 +1,30 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = gcc
+LD = ld
+
+INCLUDE_FLAGS = -I../../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.OSF1 b/ldap/servers/plugins/distrib/Makefile.OSF1
new file mode 100644
index 00000000..2c2c4660
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.OSF1
@@ -0,0 +1,29 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# OSF1 Makefile for Directory Server plug-in examples
+
+CC = cc
+LD = ld
+
+INCLUDE = -I../../include
+CFLAGS = $(INCLUDE) -DIS_64 -ieee_with_inexact -pthread -DOSF1
+LDFLAGS = -shared -all -expect_unresolved "*" -taso
+
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.ReliantUNIX b/ldap/servers/plugins/distrib/Makefile.ReliantUNIX
new file mode 100644
index 00000000..c8016c9e
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.ReliantUNIX
@@ -0,0 +1,30 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.SOLARIS b/ldap/servers/plugins/distrib/Makefile.SOLARIS
new file mode 100644
index 00000000..c8016c9e
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.SOLARIS
@@ -0,0 +1,30 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.SOLARIS64 b/ldap/servers/plugins/distrib/Makefile.SOLARIS64
new file mode 100644
index 00000000..170d2b47
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.SOLARIS64
@@ -0,0 +1,30 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC -xarch=v9
+LDFLAGS = -G -xarch=v9
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.SOLARISx86 b/ldap/servers/plugins/distrib/Makefile.SOLARISx86
new file mode 100644
index 00000000..c8016c9e
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.SOLARISx86
@@ -0,0 +1,30 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.UnixWare b/ldap/servers/plugins/distrib/Makefile.UnixWare
new file mode 100644
index 00000000..c8016c9e
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.UnixWare
@@ -0,0 +1,30 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.UnixWareUDK b/ldap/servers/plugins/distrib/Makefile.UnixWareUDK
new file mode 100644
index 00000000..c8016c9e
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.UnixWareUDK
@@ -0,0 +1,30 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = distrib.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/plugins/distrib/Makefile.WINNT b/ldap/servers/plugins/distrib/Makefile.WINNT
new file mode 100644
index 00000000..ddb02e29
--- /dev/null
+++ b/ldap/servers/plugins/distrib/Makefile.WINNT
@@ -0,0 +1,38 @@
+# Makefile for Directory Server plug-in
+#
+
+CC = cl
+LD = link
+
+
+TARGET=libdistrib
+
+OBJS=distrib.obj
+
+
+INC = ..\..\include
+CFLAGS = /nologo -I $(INC) /c
+LDFLAGS = /dll /nologo
+LIBS=/DEFAULTLIB:kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib ..\..\lib\libslapd.lib ..\..\lib\libnspr4.lib
+
+
+all: \
+ init \
+ $(TARGET).dll
+
+init:
+ "c:\program files\microsoft visual studio\vc98\bin\vcvars32.bat"
+
+
+$(TARGET).dll: $(OBJS)
+ $(LD) $(LDFLAGS) /def:$(TARGET).def /out:$(TARGET).dll $(LIBS) $(OBJS)
+ -rm -f $(OBJS2) *~
+
+.c.obj:
+ $(CC) $(CFLAGS) $<
+
+clean:
+ del -f $(OBJS) $(TARGET).dll *~
+
+
+
diff --git a/ldap/servers/plugins/distrib/README b/ldap/servers/plugins/distrib/README
new file mode 100644
index 00000000..3ee6ff88
--- /dev/null
+++ b/ldap/servers/plugins/distrib/README
@@ -0,0 +1,23 @@
+ ----------------------------
+ Sample pluggable distribution logic
+ for Netscape Directory Server
+ ----------------------------
+
+This directory contains code for some sample server plug-ins intended for
+use with the Netscape Directory Server 7.
+
+ NOTE: Before you compile and run these examples, make sure
+ to change any server-specific data in the examples to
+ values applicable to your Directory Server.
+
+distrib.c
+----------
+This is an example of a distribution function that can be used
+to distribute a flat namespace into several backends
+
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
diff --git a/ldap/servers/plugins/distrib/distrib.c b/ldap/servers/plugins/distrib/distrib.c
new file mode 100644
index 00000000..fd8ea5b6
--- /dev/null
+++ b/ldap/servers/plugins/distrib/distrib.c
@@ -0,0 +1,222 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+#include <ctype.h>
+#include <string.h>
+#include "slapi-plugin.h"
+
+/*
+ * These are examples of distribution function as declared in mapping tree node
+ * This function will be called for every operations
+ * reaching this node, including subtree search operations that are started
+ * above this node
+ *
+ * Parameters :
+ * . pb is the pblock of the operation
+ * . target_dn is the target DN of the operation
+ * . mtn_be_names is the list of names of backends declared for this node
+ * . be_count is the number of backends declared
+ * . node_dn is the node where the distribution function is set
+ *
+ * The return value of the functions should be the indice of the backend
+ * in the mtn_be_names table
+ * For search operation, the value SLAPI_BE_ALL_BACKENDS can be used to
+ * specify that all backends must be searched
+ * The use of value SLAPI_BE_ALL_BACKENDS for operation other than search
+ * is not supported and may give random results
+ *
+ */
+
+/*
+ * Distribute the entries based on the first letter of their rdn
+ *
+ * . Entries starting with anything other that a-z or A-Z will always
+ * go in backend 0
+ * . Entries starting with letter (a-z or A-Z) will be shared between
+ * the backends depending following the alphabetic order
+ * Example : if 3 backends are used, entries starting with A-I will go
+ * in backend 0, entries starting with J-R will go in backend 1, entries
+ * starting with S-Z will go in backend 2
+ *
+ * Of course this won't work for all locales...
+ *
+ * This example only works for a flat namespace below the node DN
+ */
+int alpha_distribution(Slapi_PBlock *pb, Slapi_DN * target_dn,
+ char **mtn_be_names, int be_count, Slapi_DN * node_dn)
+{
+ unsigned long op_type;
+ Slapi_Operation *op;
+ char *rdn_type;
+ char *rdn_value;
+ Slapi_RDN *rdn = NULL;
+ char c;
+
+ /* first check the operation type
+ * searches at node level or above it should go in all backends
+ * searches below node level should go in only one backend
+ */
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op_type = slapi_op_get_type(op);
+ if ((op_type == SLAPI_OPERATION_SEARCH) &&
+ slapi_sdn_issuffix(node_dn, target_dn))
+ return SLAPI_BE_ALL_BACKENDS;
+
+ /* now choose the backend
+ * anything starting with a char different from a-z or A-Z will
+ * go in backend 0
+ */
+
+ /* get the first char of first value of rdn */
+ rdn = slapi_rdn_new();
+ slapi_sdn_get_rdn(target_dn, rdn);
+ slapi_rdn_get_first(rdn, &rdn_type, &rdn_value);
+ c = rdn_value[0];
+
+ if (!(((c >= 'a') && (c <= 'z')) ||
+ ((c >= 'A') && (c <= 'Z')) ))
+ {
+ return 0;
+ }
+
+ slapi_rdn_free(&rdn);
+
+ /* for entries with rdn starting with alphabetic characters
+ * use the formula : (c - 'A') * be_count/26
+ * to calculate the backend number
+ */
+ return (toupper(c) - 'A') * be_count/26;
+}
+
+/*
+ * Distribute the entries based on a simple hash algorithme
+ */
+int hash_distribution(Slapi_PBlock *pb, Slapi_DN * target_dn,
+ char **mtn_be_names, int be_count, Slapi_DN * node_dn)
+{
+ unsigned long op_type;
+ Slapi_Operation *op;
+ char *rdn_type;
+ char *rdn_value;
+ Slapi_RDN *rdn = NULL;
+ int hash_value;
+
+ /* first check the operation type
+ * searches at node level or above it should go in all backends
+ * searches below node level should go in only one backend
+ */
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op_type = slapi_op_get_type(op);
+ if ((op_type == SLAPI_OPERATION_SEARCH) &&
+ slapi_sdn_issuffix(node_dn, target_dn))
+ return SLAPI_BE_ALL_BACKENDS;
+
+ /* now choose the backend
+ */
+
+ /* get the rdn and hash it to compute the backend number
+ * use a simple hash for this example
+ */
+ rdn = slapi_rdn_new();
+ slapi_sdn_get_rdn(target_dn, rdn);
+ slapi_rdn_get_first(rdn, &rdn_type, &rdn_value);
+
+ /* compute the hash value */
+ hash_value = 0;
+ while (*rdn_value)
+ {
+ hash_value += *rdn_value;
+ rdn_value++;
+ }
+ hash_value = hash_value % be_count;
+
+ slapi_rdn_free(&rdn);
+
+ /* use the hash_value as the returned backend number */
+ return hash_value;
+}
+
+/*
+ * This plugin allows to use a local backend in conjonction with
+ * a chaining backend
+ * The ldbm backend is considered a read-only replica of the data
+ * The chaining backend point to a red-write replica of the data
+ * This distribution logic forward the update request to the chaining
+ * backend, and send the search request to the local dbm database
+ *
+ * The mechanism for updating the local read-only replica is not
+ * taken into account by this plugin
+ *
+ * To be able to use it one must define one ldbm backend and one chaining
+ * backend in the mapping tree node
+ *
+ */
+int chaining_distribution(Slapi_PBlock *pb, Slapi_DN * target_dn,
+ char **mtn_be_names, int be_count, Slapi_DN * node_dn)
+{
+ char * requestor_dn;
+ unsigned long op_type;
+ Slapi_Operation *op;
+ int repl_op = 0;
+ int local_backend = -1;
+ int chaining_backend = -1;
+ int i;
+ char * name;
+
+ /* first, we have to decide which backend is the local backend
+ * and which is the chaining one
+ * For the purpose of this example use the backend name :
+ * the backend with name starting with ldbm is local
+ * the bakend with name starting with chaining is remote
+ */
+ local_backend = -1;
+ chaining_backend = -1;
+ for (i=0; i<be_count; i++)
+ {
+ name = mtn_be_names[i];
+ if ((0 == strncmp(name, "ldbm", 4)) ||
+ (0 == strncmp(name, "user", 4)))
+ local_backend = i;
+ else if (0 == strncmp(name, "chaining", 8))
+ chaining_backend = i;
+ }
+
+ /* Check the operation type
+ * read-only operation will go to the local backend
+ * updates operation will go to the chaining backend
+ */
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op_type = slapi_op_get_type(op);
+ if ((op_type == SLAPI_OPERATION_SEARCH) ||
+ (op_type == SLAPI_OPERATION_BIND) ||
+ (op_type == SLAPI_OPERATION_UNBIND) ||
+ (op_type == SLAPI_OPERATION_COMPARE))
+ return local_backend;
+
+ /* if the operation is done by directory manager
+ * use local database even for updates because it is an administrative
+ * operation
+ * remarks : one could also use an update DN in the same way
+ * to let update operation go to the local backend when they are done
+ * by specific administrator user but let all the other user
+ * go to the read-write replica
+ */
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_DN, &requestor_dn );
+ if (slapi_dn_isroot(requestor_dn))
+ return local_backend;
+
+ /* if the operation is a replicated operation
+ * use local database even for updates to avoid infinite loops
+ */
+ slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ if (repl_op)
+ return local_backend;
+
+ /* all other case (update while not directory manager) :
+ * use the chaining backend
+ */
+ return chaining_backend;
+}
diff --git a/ldap/servers/plugins/distrib/distrib.dsp b/ldap/servers/plugins/distrib/distrib.dsp
new file mode 100644
index 00000000..ebf11f1e
--- /dev/null
+++ b/ldap/servers/plugins/distrib/distrib.dsp
@@ -0,0 +1,116 @@
+# Microsoft Developer Studio Project File - Name="distrib" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=distrib - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "distrib.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "distrib.mak" CFG="distrib - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "distrib - Win32 Release" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "distrib - Win32 Debug" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "distrib - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib ..\..\lib\libslapd.lib /nologo /subsystem:windows /dll /machine:I386
+
+!ELSEIF "$(CFG)" == "distrib - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug"
+# PROP Intermediate_Dir ".\Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MD /W3 /Gm /GX /Zi /Od /I "..\..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WIN32" /YX /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib ..\..\lib\libslapd.lib /nologo /subsystem:windows /dll /debug /machine:I386
+
+!ENDIF
+
+# Begin Target
+
+# Name "distrib - Win32 Release"
+# Name "distrib - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\dllmain.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\distrib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\libdistrib.def
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/ldap/servers/plugins/distrib/dllmain.c b/ldap/servers/plugins/distrib/dllmain.c
new file mode 100644
index 00000000..bce5eed7
--- /dev/null
+++ b/ldap/servers/plugins/distrib/dllmain.c
@@ -0,0 +1,101 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * Copyright (C) 2000 Sun Microsystems Inc.
+ *
+ * Use of this Source Code is subject to the terms of the applicable license
+ * agreement from Sun Microsystems Inc.
+ *
+ * The copyright notice(s) in this Source Code does not indicate actual or
+ * intended publication of this Source Code.
+ */
+
+ /*
+ * Microsoft Windows specifics
+ */
+#include "ldap.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; /* successful DLL_PROCESS_ATTACH */
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/distrib/libdistrib.def b/ldap/servers/plugins/distrib/libdistrib.def
new file mode 100644
index 00000000..baef2027
--- /dev/null
+++ b/ldap/servers/plugins/distrib/libdistrib.def
@@ -0,0 +1,10 @@
+;-------------------------------------------------------------------------
+; PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+; license terms. Copyright 2001 Sun Microsystems, Inc.
+; Some preexisting portions Copyright 2001 Netscape Communications Corp.
+; All rights reserved.
+;-------------------------------------------------------------------------
+DESCRIPTION 'Netscape Directory Server 7 distribution logic example'
+EXPORTS
+ alpha_distribution @1
+ hash_distribution @2
diff --git a/ldap/servers/plugins/http/Makefile b/ldap/servers/plugins/http/Makefile
new file mode 100644
index 00000000..d23c26a5
--- /dev/null
+++ b/ldap/servers/plugins/http/Makefile
@@ -0,0 +1,80 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+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 = $(OBJDIR)/lib/libhttpclient
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./http.def
+endif
+
+HTTP_OBJS = http_client.o http_impl.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(HTTP_OBJS))
+
+HTTP_DLL = http-client-plugin
+
+INCLUDES += -I../../slapd -I../../../include
+
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+ifeq ($(ARCH), WINNT)
+CFLAGS+=-D_WIN32 -DXP_WIN -DXP_WIN32
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD) $(SECURITYLINK)
+HTTP_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), AIX)
+LD=ld
+EXTRA_LIBS += $(LIBSLAPD)
+endif
+
+HTTP= $(addprefix $(LIBDIR)/, $(HTTP_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(HTTP)
+
+ifeq ($(ARCH), WINNT)
+$(HTTP): $(OBJS) $(HTTP_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(HTTP_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(HTTP): $(OBJS) $(HTTP_DLL_OBJ)
+ $(LINK_DLL) $(HTTP_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(HTTP_DLL_OBJ)
+endif
+ $(RM) $(HTTP)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
diff --git a/ldap/servers/plugins/http/dllmain.c b/ldap/servers/plugins/http/dllmain.c
new file mode 100644
index 00000000..ef1f637a
--- /dev/null
+++ b/ldap/servers/plugins/http/dllmain.c
@@ -0,0 +1,98 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+#ifdef _WIN32
+
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; /* successful DLL_PROCESS_ATTACH */
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/http/http.def b/ldap/servers/plugins/http/http.def
new file mode 100644
index 00000000..ac2f3e05
--- /dev/null
+++ b/ldap/servers/plugins/http/http.def
@@ -0,0 +1,13 @@
+;-------------------------------------------------------------------------
+; PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+; license terms. Copyright 2001 Sun Microsystems, Inc.
+; Some preexisting portions Copyright 2001 Netscape Communications Corp.
+; All rights reserved.
+;-------------------------------------------------------------------------
+DESCRIPTION 'Netscape Directory Server Http Client'
+EXPORTS
+ http_client_init @2
+ plugin_init_debug_level @3
+ http_client_version @4
+
+
diff --git a/ldap/servers/plugins/http/http_client.c b/ldap/servers/plugins/http/http_client.c
new file mode 100644
index 00000000..2fbbdd52
--- /dev/null
+++ b/ldap/servers/plugins/http/http_client.c
@@ -0,0 +1,290 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+/**
+ * Simple Http Client API broker plugin
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "portable.h"
+#include "nspr.h"
+
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+#include "dirlite_strings.h"
+#include "dirver.h"
+
+#include "http_client.h"
+#include "http_impl.h"
+
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+/*** from proto-slap.h ***/
+
+int slapd_log_error_proc( char *subsystem, char *fmt, ... );
+
+/*** from ldaplog.h ***/
+
+/* edited ldaplog.h for LDAPDebug()*/
+#ifndef _LDAPLOG_H
+#define _LDAPLOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDAP_DEBUG_TRACE 0x00001 /* 1 */
+#define LDAP_DEBUG_ANY 0x04000 /* 16384 */
+#define LDAP_DEBUG_PLUGIN 0x10000 /* 65536 */
+
+/* debugging stuff */
+# ifdef _WIN32
+ extern int *module_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( *module_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# else /* _WIN32 */
+ extern int slapd_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( slapd_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# endif /* Win32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAP_H */
+
+#define HTTP_PLUGIN_SUBSYSTEM "http-client-plugin" /* used for logging */
+#define HTTP_PLUGIN_VERSION 0x00050050
+
+#define HTTP_SUCCESS 0
+#define HTTP_FAILURE -1
+
+/**
+ * Implementation functions
+ */
+static void *api[7];
+
+/**
+ * Plugin identifiers
+ */
+static Slapi_PluginDesc pdesc = { "http-client",
+ PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT,
+ "HTTP Client plugin" };
+
+static Slapi_ComponentId *plugin_id = NULL;
+
+/**
+ **
+ ** Http plug-in management functions
+ **
+ **/
+int http_client_init(Slapi_PBlock *pb);
+static int http_client_start(Slapi_PBlock *pb);
+static int http_client_close(Slapi_PBlock *pb);
+
+/**
+ * our functions
+ */
+static void _http_init(Slapi_ComponentId *plugin_id);
+static int _http_get_text(char *url, char **data, int *bytesRead);
+static int _http_get_binary(char *url, char **data, int *bytesRead);
+static int _http_get_redirected_uri(char *url, char **data, int *bytesRead);
+static int _http_post(char *url, httpheader **httpheaderArray, char *body, char **data, int *bytesRead);
+static void _http_shutdown( void );
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+/**
+ *
+ * Get the presence plug-in version
+ *
+ */
+int http_client_version()
+{
+ return HTTP_PLUGIN_VERSION;
+}
+
+int http_client_init(Slapi_PBlock *pb)
+{
+ int status = HTTP_SUCCESS;
+ PRUint32 nssFlags = 0;
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> http_client_init -- BEGIN\n",0,0,0);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) http_client_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) http_client_close ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "http_client_init: failed to register plugin\n" );
+ status = HTTP_FAILURE;
+ }
+
+ /* Retrieve and save the plugin identity to later pass to
+ internal operations */
+ if (slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &plugin_id) != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "http_client_init: Failed to retrieve SLAPI_PLUGIN_IDENTITY\n");
+ return HTTP_FAILURE;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- http_client_init -- END\n",0,0,0);
+ return status;
+}
+
+static int http_client_start(Slapi_PBlock *pb)
+{
+ int status = HTTP_SUCCESS;
+ /**
+ * do some init work here
+ */
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> http_client_start -- BEGIN\n",0,0,0);
+
+ api[0] = 0; /* reserved for api broker use, must be zero */
+ api[1] = (void *)_http_init;
+ api[2] = (void *)_http_get_text;
+ api[3] = (void *)_http_get_binary;
+ api[4] = (void *)_http_get_redirected_uri;
+ api[5] = (void *)_http_shutdown;
+ api[6] = (void *)_http_post;
+
+ if( slapi_apib_register(HTTP_v1_0_GUID, api) ) {
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "http_client_start: failed to register functions\n" );
+ status = HTTP_FAILURE;
+ }
+
+ _http_init(plugin_id);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- http_client_start -- END\n",0,0,0);
+ return status;
+}
+
+static int http_client_close(Slapi_PBlock *pb)
+{
+ int status = HTTP_SUCCESS;
+ /**
+ * do cleanup
+ */
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> http_client_close -- BEGIN\n",0,0,0);
+
+ slapi_apib_unregister(HTTP_v1_0_GUID);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- http_client_close -- END\n",0,0,0);
+
+ return status;
+}
+
+/**
+ * perform http initialization here
+ */
+static void _http_init(Slapi_ComponentId *plugin_id)
+{
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> _http_init -- BEGIN\n",0,0,0);
+
+ http_impl_init(plugin_id);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- _http_init -- END\n",0,0,0);
+}
+
+/**
+ * This method gets the data in a text format based on the
+ * URL send.
+ */
+static int _http_get_text(char *url, char **data, int *bytesRead)
+{
+ int status = HTTP_SUCCESS;
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> _http_get_text -- BEGIN\n",0,0,0);
+
+ status = http_impl_get_text(url, data, bytesRead);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- _http_get_text -- END\n",0,0,0);
+ return status;
+}
+
+/**
+ * This method gets the data in a binary format based on the
+ * URL send.
+ */
+static int _http_get_binary(char *url, char **data, int *bytesRead)
+{
+ int status = HTTP_SUCCESS;
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> _http_get_binary -- BEGIN\n",0,0,0);
+
+ status = http_impl_get_binary(url, data, bytesRead);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- _http_get_binary -- END\n",0,0,0);
+ return status;
+}
+
+/**
+ * This method intercepts the redirected URI and returns the location
+ * information.
+ */
+static int _http_get_redirected_uri(char *url, char **data, int *bytesRead)
+{
+ int status = HTTP_SUCCESS;
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> _http_get_redirected_uri -- BEGIN\n",0,0,0);
+
+ status = http_impl_get_redirected_uri(url, data, bytesRead);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- _http_get_redirected_uri -- END\n",0,0,0);
+ return status;
+}
+
+/**
+ * This method posts the data based on the URL send.
+ */
+static int _http_post(char *url, httpheader ** httpheaderArray, char *body, char **data, int *bytesRead)
+{
+ int status = HTTP_SUCCESS;
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> _http_post -- BEGIN\n",0,0,0);
+
+ status = http_impl_post(url, httpheaderArray, body, data, bytesRead);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- _http_post -- END\n",0,0,0);
+ return status;
+}
+
+/**
+ * perform http shutdown here
+ */
+static void _http_shutdown( void )
+{
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> _http_shutdown -- BEGIN\n",0,0,0);
+
+ http_impl_shutdown();
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- _http_shutdown -- END\n",0,0,0);
+}
+
diff --git a/ldap/servers/plugins/http/http_client.h b/ldap/servers/plugins/http/http_client.h
new file mode 100644
index 00000000..d849e18d
--- /dev/null
+++ b/ldap/servers/plugins/http/http_client.h
@@ -0,0 +1,64 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#ifndef _HTTP_CLIENT_H_
+#define _HTTP_CLIENT_H_
+
+/* Error codes */
+#define HTTP_CLIENT_ERROR_BAD_URL -1
+#define HTTP_CLIENT_ERROR_NET_ADDR -2
+#define HTTP_CLIENT_ERROR_SOCKET_CREATE -3
+#define HTTP_CLIENT_ERROR_CONNECT_FAILED -4
+#define HTTP_CLIENT_ERROR_SEND_REQ -5
+#define HTTP_CLIENT_ERROR_BAD_RESPONSE -6
+#define HTTP_CLIENT_ERROR_SSLSOCKET_CREATE -7
+ #define HTTP_CLIENT_ERROR_NSS_INITIALIZE -8
+
+/*Structure to store HTTP Headers */
+typedef struct {
+ char *name;
+ char *value;
+} httpheader;
+
+
+/* mechanics */
+
+
+typedef void (*api_http_init)(Slapi_ComponentId *plugin_id);
+typedef int (*api_http_get_text)(char *url, char **data, int *bytesRead);
+typedef int (*api_http_get_binary)(char *url, char **data, int *bytesRead);
+typedef int (*api_http_get_redirected_uri)(char *url, char **data, int *bytesRead);
+typedef void (*api_http_shutdown)();
+typedef int (*api_http_post)(char *url, httpheader **httpheaderArray, char *body, char **data, int *bytesRead);
+
+/* API ID for http_apib_get_interface */
+
+#define HTTP_v1_0_GUID "811c5ea2-fef4-4f1c-9ab4-fcf746cd6efc"
+
+/* API */
+
+/* the api broker reserves api[0] for its use */
+
+#define http_init(api) \
+ ((api_http_init*)(api))[1](Slapi_ComponentId *plugin_id)
+
+#define http_get_text(api, url, data, bytesRead) \
+ ((api_http_get_text*)(api))[2]( url, data, bytesRead)
+
+#define http_get_binary(api, url, data, bytesRead) \
+ ((api_http_get_binary*)(api))[3](url, data, bytesRead)
+
+#define http_get_redirected_uri(api, url, data, bytesRead) \
+ ((api_http_get_redirected_uri*)(api))[4](url, data, bytesRead)
+
+#define http_shutdown(api) \
+ ((api_http_shutdown*)(api))[5]()
+
+#define http_post(api, url, httpheaderArray, body, data, bytesRead) \
+ ((api_http_post*)(api))[6](url, httpheaderArray, body, data, bytesRead)
+
+#endif /*_HTTP_CLIENT_H_*/
diff --git a/ldap/servers/plugins/http/http_impl.c b/ldap/servers/plugins/http/http_impl.c
new file mode 100644
index 00000000..bad8315c
--- /dev/null
+++ b/ldap/servers/plugins/http/http_impl.c
@@ -0,0 +1,1479 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+/**
+ * Implementation of a Simple HTTP Client
+ */
+#include <stdio.h>
+#include <string.h>
+
+#include "nspr.h"
+#include "nss.h"
+#include "pk11func.h"
+#include "ssl.h"
+#include "prprf.h"
+#include "plstr.h"
+#include "slapi-plugin.h"
+#include "http_client.h"
+#include "secerr.h"
+#include "sslerr.h"
+#include "slapi-private.h"
+#include "slapi-plugin-compat4.h"
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+/*** from proto-slap.h ***/
+
+int slapd_log_error_proc( char *subsystem, char *fmt, ... );
+char *config_get_instancedir();
+
+/*** from ldaplog.h ***/
+
+/* edited ldaplog.h for LDAPDebug()*/
+#ifndef _LDAPLOG_H
+#define _LDAPLOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef BUILD_STANDALONE
+#define slapi_log_error(a,b,c,d) printf((c),(d))
+#define stricmp strcasecmp
+#endif
+
+#define LDAP_DEBUG_TRACE 0x00001 /* 1 */
+#define LDAP_DEBUG_ANY 0x04000 /* 16384 */
+#define LDAP_DEBUG_PLUGIN 0x10000 /* 65536 */
+
+/* debugging stuff */
+# ifdef _WIN32
+ extern int *module_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( *module_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# else /* _WIN32 */
+ extern int slapd_ldap_debug;
+# define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( slapd_ldap_debug & level ) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+# endif /* Win32 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAP_H */
+
+#define HTTP_PLUGIN_SUBSYSTEM "http-client-plugin" /* used for logging */
+
+#define HTTP_IMPL_SUCCESS 0
+#define HTTP_IMPL_FAILURE -1
+
+#define HTTP_REQ_TYPE_GET 1
+#define HTTP_REQ_TYPE_REDIRECT 2
+#define HTTP_REQ_TYPE_POST 3
+
+#define HTTP_GET "GET"
+#define HTTP_POST "POST"
+#define HTTP_PROTOCOL "HTTP/1.0"
+#define HTTP_CONTENT_LENGTH "Content-length:"
+#define HTTP_CONTENT_TYPE_URL_ENCODED "Content-type: application/x-www-form-urlencoded"
+#define HTTP_GET_STD_LEN 18
+#define HTTP_POST_STD_LEN 85
+#define HTTP_DEFAULT_BUFFER_SIZE 4096
+#define HTTP_RESPONSE_REDIRECT (retcode == 302 || retcode == 301)
+
+/**
+ * Error strings used for logging error messages
+ */
+#define HTTP_ERROR_BAD_URL " Badly formatted URL"
+#define HTTP_ERROR_NET_ADDR " NetAddr initialization failed"
+#define HTTP_ERROR_SOCKET_CREATE " Creation of socket failed"
+#define HTTP_ERROR_SSLSOCKET_CREATE " Creation of SSL socket failed"
+#define HTTP_ERROR_CONNECT_FAILED " Couldn't connect to remote host"
+#define HTTP_ERROR_SEND_REQ " Send request failed"
+#define HTTP_ERROR_BAD_RESPONSE " Invalid response from remote host"
+
+#define HTTP_PLUGIN_DN "cn=HTTP Client,cn=plugins,cn=config"
+#define CONFIG_DN "cn=config"
+#define ATTR_CONNECTION_TIME_OUT "nsHTTPConnectionTimeOut"
+#define ATTR_READ_TIME_OUT "nsHTTPReadTimeOut"
+#define ATTR_RETRY_COUNT "nsHTTPRetryCount"
+#define ATTR_DS_SECURITY "nsslapd-security"
+#define ATTR_INSTANCE_PATH "nsslapd-errorlog"
+
+/*static Slapi_ComponentId *plugin_id = NULL;*/
+
+typedef struct {
+ int retryCount;
+ int connectionTimeOut;
+ int readTimeOut;
+ int nssInitialized;
+ char *DS_sslOn;
+} httpPluginConfig;
+
+httpPluginConfig *httpConfig;
+
+/**
+ * Public functions
+ */
+int http_impl_init(Slapi_ComponentId *plugin_id);
+int http_impl_get_text(char *url, char **data, int *bytesRead);
+int http_impl_get_binary(char *url, char **data, int *bytesRead);
+int http_impl_get_redirected_uri(char *url, char **data, int *bytesRead);
+int http_impl_post(char *url, httpheader **httpheaderArray, char *body, char **data, int *bytesRead);
+void http_impl_shutdown();
+
+/**
+ * Http handling functions
+ */
+static int doRequest(const char *url, httpheader **httpheaderArray, char *body, char **buf, int *bytesRead, int reqType);
+static int doRequestRetry(const char *url, httpheader **httpheaderArray, char *body, char **buf, int *bytesRead, int reqType);
+static void setTCPNoDelay(PRFileDesc* fd);
+static PRStatus sendGetReq(PRFileDesc *fd, const char *path);
+static PRStatus sendPostReq(PRFileDesc *fd, const char *path, httpheader **httpheaderArray, char *body);
+static PRStatus processResponse(PRFileDesc *fd, char **resBUF, int *bytesRead, int reqType);
+static PRStatus getChar(PRFileDesc *fd, char *buf);
+static PRInt32 http_read(PRFileDesc *fd, char *buf, int size);
+static PRStatus getBody(PRFileDesc *fd, char **buf, int *actualBytesRead);
+static PRBool isWhiteSpace(char ch);
+static PRStatus sendFullData( PRFileDesc *fd, char *buf, int timeOut);
+
+/**
+ * Helper functions to parse URL
+ */
+static PRStatus parseURI(const char *url, char **host, PRInt32 *port, char **path, int *sslOn);
+static void toLowerCase(char* str);
+static PRStatus parseAtPort(const char* url, PRInt32 *port, char **path);
+static PRStatus parseAtPath(const char *url, char **path);
+static PRInt32 getPort(const char* src);
+static PRBool isAsciiSpace(char aChar);
+static PRBool isAsciiDigit(char aChar);
+static char * isHttpReq(const char *url, int *sslOn);
+
+/*To get config from entry*/
+static int readConfigLDAPurl(Slapi_ComponentId *plugin_id, char *plugindn);
+static int parseHTTPConfigEntry(Slapi_Entry *e);
+static int parseConfigEntry(Slapi_Entry *e);
+
+static int nssReinitializationRequired();
+
+/*SSL functions */
+PRFileDesc* setupSSLSocket(PRFileDesc* fd);
+
+/*SSL callback functions */
+SECStatus badCertHandler(void *arg, PRFileDesc *socket);
+SECStatus authCertificate(void *arg, PRFileDesc *socket, PRBool checksig, PRBool isServer);
+SECStatus getClientAuthData(void *arg, PRFileDesc *socket,struct CERTDistNamesStr *caNames, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey);
+SECStatus handshakeCallback(PRFileDesc *socket, void *arg);
+
+static int doRequestRetry(const char *url, httpheader **httpheaderArray, char *body, char **buf, int *bytesRead, int reqType)
+{
+ int status = HTTP_IMPL_SUCCESS;
+ int retrycnt = 0;
+ int i = 1;
+
+ retrycnt = httpConfig->retryCount;
+
+ if (retrycnt == 0) {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "doRequestRetry: Retry Count cannot be read. Setting to default value of 3 \n", 0,0,0);
+ retrycnt = 3;
+ }
+ status = doRequest(url, httpheaderArray, body, buf, bytesRead, reqType);
+ if (status != HTTP_IMPL_SUCCESS) {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "doRequestRetry: Failed to perform http request \n", 0,0,0);
+ while (retrycnt > 0) {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "doRequestRetry: Retrying http request %d.\n", i,0,0);
+ status = doRequest(url, httpheaderArray, body, buf, bytesRead, reqType);
+ if (status == HTTP_IMPL_SUCCESS) {
+ break;
+ }
+ retrycnt--;
+ i++;
+ }
+ if (status != HTTP_IMPL_SUCCESS) {
+ LDAPDebug( LDAP_DEBUG_ANY, "doRequestRetry: Failed to perform http request after %d attempts.\n", i,0,0);
+ LDAPDebug( LDAP_DEBUG_ANY, "doRequestRetry: Verify plugin URI configuration and contact Directory Administrator.\n",0,0,0);
+ }
+
+ }
+ return status;
+}
+
+static int doRequest(const char *url, httpheader **httpheaderArray, char *body, char **buf, int *bytesRead, int reqType)
+{
+ PRStatus status = PR_SUCCESS;
+
+ char *host = NULL;
+ char *path = NULL;
+ char *val = NULL;
+ char *defaultprefix = NULL;
+ PRFileDesc *fd = NULL;
+ PRNetAddr addr;
+ PRInt32 port;
+ PRInt32 errcode = 0;
+ PRInt32 http_connection_time_out = 0;
+ PRInt32 sslOn;
+ PRInt32 nssStatus;
+ PRUint32 nssFlags = 0;
+ char certDir[1024];
+ char certPref[1024];
+ char keyPref[1024];
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> doRequest -- BEGIN\n",0,0,0);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> url=[%s] \n",url,0,0);
+
+ /* Parse the URL and initialize the host, port, path */
+ if (parseURI(url, &host, &port, &path, &sslOn) == PR_FAILURE) {
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest: %s \n", HTTP_ERROR_BAD_URL);
+ status = PR_FAILURE;
+ goto bail;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> host=[%s] port[%d] path[%s] \n",host,port,path);
+
+ /* Initialize the Net Addr */
+ if (PR_StringToNetAddr(host, &addr) == PR_FAILURE) {
+ char buf[PR_NETDB_BUF_SIZE];
+ PRHostEnt ent;
+
+ status = PR_GetIPNodeByName(host, PR_AF_INET, PR_AI_DEFAULT, buf, sizeof(buf), &ent);
+ if (status == PR_SUCCESS) {
+ PR_EnumerateHostEnt(0, &ent, (PRUint16)port, &addr);
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest: %s\n", HTTP_ERROR_NET_ADDR);
+ status = HTTP_CLIENT_ERROR_NET_ADDR;
+ goto bail;
+ }
+ } else {
+ addr.inet.port = (PRUint16)port;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully created NetAddr \n",0,0,0);
+
+ /* open a TCP connection to the server */
+ fd = PR_NewTCPSocket();
+ if (!fd) {
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest: %s\n", HTTP_ERROR_SOCKET_CREATE);
+ status = HTTP_CLIENT_ERROR_SOCKET_CREATE;
+ goto bail;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully created New TCP Socket \n",0,0,0);
+
+ /* immediately send the response */
+ setTCPNoDelay(fd);
+
+ if (sslOn) {
+
+ /* Have to reinitialize NSS is the DS security is set to off.
+ This is because the HTTPS required the cert dbs to be created.
+ The default prefixes are used as per DS norm */
+
+ if (PL_strcasecmp(httpConfig->DS_sslOn, "off") == 0) {
+ if (!httpConfig->nssInitialized) {
+ if (nssReinitializationRequired())
+ {
+ NSS_Shutdown();
+ nssFlags &= (~NSS_INIT_READONLY);
+ val = config_get_instancedir();
+ strcpy(certDir, val);
+ defaultprefix = strrchr(certDir, '/');
+ if (!defaultprefix)
+ defaultprefix = strrchr(certDir, '\\');
+ if (!defaultprefix) /* still could not find it . . . */
+ goto bail; /* . . . can't do anything */
+ defaultprefix++;
+ sprintf(certPref, "%s-",defaultprefix);
+ strcpy(keyPref, certPref);
+ *defaultprefix= '\0';
+ sprintf(certDir, "%salias", certDir);
+ nssStatus = NSS_Initialize(certDir, certPref, keyPref, "secmod.db", nssFlags);
+ slapi_ch_free((void **)&val);
+
+ if (nssStatus != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest: Unable to initialize NSS Cert/Key Database\n");
+ status = HTTP_CLIENT_ERROR_NSS_INITIALIZE;
+ goto bail;
+ }
+ }
+ httpConfig->nssInitialized = 1;
+ }
+ }
+
+ NSS_SetDomesticPolicy();
+
+ fd = setupSSLSocket(fd);
+ if (fd == NULL) {
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest: %s\n", HTTP_ERROR_SSLSOCKET_CREATE);
+ status = HTTP_CLIENT_ERROR_SSLSOCKET_CREATE;
+ goto bail;
+ }
+
+ if (SSL_SetURL(fd, host) != 0) {
+ errcode = PR_GetError();
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest: SSL_SetURL -> NSPR Error code (%d) \n", errcode);
+ status = HTTP_CLIENT_ERROR_SSLSOCKET_CREATE;
+ goto bail;
+ }
+
+ }
+
+ http_connection_time_out = httpConfig->connectionTimeOut;
+ /* connect to the host */
+ if (PR_Connect(fd, &addr, PR_MillisecondsToInterval(http_connection_time_out)) == PR_FAILURE) {
+ errcode = PR_GetError();
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest: %s (%s:%d) -> NSPR Error code (%d)\n",
+ HTTP_ERROR_CONNECT_FAILED, host, addr.inet.port, errcode);
+ status = HTTP_CLIENT_ERROR_CONNECT_FAILED;
+ goto bail;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully connected to host [%s] \n",host,0,0);
+
+ /* send the request to the server */
+ if (reqType == HTTP_REQ_TYPE_POST) {
+ if (sendPostReq(fd, path, httpheaderArray, body) == PR_FAILURE) {
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest-sendPostReq: %s (%s)\n", HTTP_ERROR_SEND_REQ, path);
+ status = HTTP_CLIENT_ERROR_SEND_REQ;
+ goto bail;
+ }
+ }
+ else {
+ if (sendGetReq(fd, path) == PR_FAILURE) {
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest-sendGetReq: %s (%s)\n", HTTP_ERROR_SEND_REQ, path);
+ status = HTTP_CLIENT_ERROR_SEND_REQ;
+ goto bail;
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully sent the request [%s] \n",path,0,0);
+
+ /* read the response */
+ if (processResponse(fd, buf, bytesRead, reqType) == PR_FAILURE) {
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "doRequest: %s (%s)\n", HTTP_ERROR_BAD_RESPONSE, url);
+ status = HTTP_CLIENT_ERROR_BAD_RESPONSE;
+ goto bail;
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Successfully read the response\n",0,0,0);
+bail:
+ if (host) {
+ PR_Free(host);
+ }
+ if (path) {
+ PR_Free(path);
+ }
+ if (fd) {
+ PR_Close(fd);
+ fd = NULL;
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- doRequest -- END\n",0,0,0);
+ return status;
+}
+
+static PRStatus processResponse(PRFileDesc *fd, char **resBUF, int *bytesRead, int reqType)
+{
+ PRStatus status = PR_SUCCESS;
+ char *location = NULL;
+ char *protocol = NULL;
+ char *statusNum = NULL;
+ char *statusString = NULL;
+ char *headers = NULL;
+
+ char tmp[HTTP_DEFAULT_BUFFER_SIZE];
+ int pos=0;
+ char ch;
+ int index;
+ int retcode;
+
+ PRBool doneParsing = PR_FALSE;
+ PRBool isRedirect = PR_FALSE;
+ char name[HTTP_DEFAULT_BUFFER_SIZE];
+ char value[HTTP_DEFAULT_BUFFER_SIZE];
+ PRBool atEOL = PR_FALSE;
+ PRBool inName = PR_TRUE;
+
+ /* PKBxxx: If we are getting a redirect and the response is more the
+ * the HTTP_DEFAULT_BUFFER_SIZE, it will cause the server to crash. A 4k
+ * buffer should be good enough.
+ */
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> processResponse -- BEGIN\n",0,0,0);
+
+ headers = (char *)PR_Calloc(1, 4 * HTTP_DEFAULT_BUFFER_SIZE);
+ /* Get protocol string */
+ index = 0;
+ while (1) {
+ status = getChar(fd, headers+pos);
+ if (status == PR_FAILURE) {
+ /* Error : */
+ goto bail;
+ }
+ ch = (char)headers[pos];
+ pos++;
+ if (!isWhiteSpace(ch)) {
+ tmp[index++] = ch;
+ } else {
+ break;
+ }
+ }
+ tmp[index] = '\0';
+ protocol = PL_strdup(tmp);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> protocol=[%s] \n",protocol,0,0);
+
+ /* Get status num */
+ index = 0;
+ while (1) {
+ status = getChar(fd, headers+pos);
+ if (status == PR_FAILURE) {
+ /* Error : */
+ goto bail;
+ }
+ ch = (char)headers[pos];
+ pos++;
+ if (!isWhiteSpace(ch)) {
+ tmp[index++] = ch;
+ } else {
+ break;
+ }
+ }
+ tmp[index] = '\0';
+ statusNum = PL_strdup(tmp);
+ retcode=atoi(tmp);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> statusNum=[%s] \n",statusNum,0,0);
+
+ if (HTTP_RESPONSE_REDIRECT && (reqType == HTTP_REQ_TYPE_REDIRECT)) {
+ isRedirect = PR_TRUE;
+ }
+ /* Get status string */
+ if (ch != '\r')
+ {
+ index = 0;
+ while (ch != '\r') {
+ status = getChar(fd, headers+pos);
+ if (status == PR_FAILURE) {
+ /* Error : */
+ goto bail;
+ }
+ ch = (char)headers[pos];
+ pos++;
+ tmp[index++] = ch;
+ }
+ tmp[index] = '\0';
+ statusString = PL_strdup(tmp);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> statusString [%s] \n",statusString,0,0);
+ }
+
+ /**
+ * Skip CRLF
+ */
+ status = getChar(fd, headers+pos);
+ if (status == PR_FAILURE) {
+ /* Error : */
+ goto bail;
+ }
+ ch = (char)headers[pos];
+ pos++;
+
+ /**
+ * loop over response headers
+ */
+ index = 0;
+ while (!doneParsing) {
+ status = getChar(fd, headers+pos);
+ if (status == PR_FAILURE) {
+ /* Error : */
+ goto bail;
+ }
+ ch = (char)headers[pos];
+ pos++;
+ switch(ch)
+ {
+ case ':':
+ if (inName) {
+ name[index] = '\0';
+ index = 0;
+ inName = PR_FALSE;
+
+ /* skip whitespace */
+ ch = ' ';
+
+ /* status = getChar(fd, headers+pos);
+ if (status == PR_FAILURE) {
+ goto bail;
+ }
+ ch = (char)headers[pos];
+ pos++; */
+
+ while(isWhiteSpace(ch)) {
+ status = getChar(fd, headers+pos);
+ if (status == PR_FAILURE) {
+ /* Error : */
+ goto bail;
+ }
+ ch = (char)headers[pos];
+ pos++;
+ }
+ value[index++] = ch;
+ } else {
+ value[index++] = ch;
+ }
+ break;
+ case '\r':
+ if (inName && !atEOL) {
+ return PR_FALSE;
+ }
+ break;
+ case '\n':
+ if (atEOL) {
+ doneParsing = PR_TRUE;
+ break;
+ }
+ if (inName) {
+ return PR_FALSE;
+ }
+ value[index] = '\0';
+ index = 0;
+ inName = PR_TRUE;
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> name=[%s] value=[%s]\n",name,value,0);
+ if (isRedirect && !PL_strcasecmp(name,"location")) {
+ location = PL_strdup(value);
+ }
+ atEOL = PR_TRUE;
+ break;
+ default:
+ atEOL = PR_FALSE;
+ if (inName) {
+ name[index++] = ch;
+ } else {
+ value[index++] = ch;
+ }
+ break;
+ }
+ }
+
+ if (!isRedirect) {
+ getBody(fd, resBUF, bytesRead);
+ } else {
+ *resBUF = PL_strdup(location);
+ *bytesRead = strlen(location);
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Response Buffer=[%s] bytesRead=[%d] \n",*resBUF,*bytesRead,0);
+
+bail:
+
+ if (headers) {
+ PR_Free(headers);
+ }
+ if (protocol) {
+ PL_strfree(protocol);
+ }
+ if (statusNum) {
+ PL_strfree(statusNum);
+ }
+ if (statusString) {
+ PL_strfree(statusString);
+ }
+ if (location) {
+ PL_strfree(location);
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- processResponse -- END\n",0,0,0);
+ return status;
+}
+
+static int nssReinitializationRequired()
+{
+ int nssReinitializationRequired = 0;
+ int err = 0;
+ int str_len = 0;
+ float version = 0;
+ const float DSVERSION = 6.1;
+ char *str = NULL;
+ char *value = NULL;
+ char *ver_value = NULL;
+ Slapi_Entry **entry = NULL;
+ Slapi_PBlock *resultpb= NULL;
+
+ resultpb= slapi_search_internal( "", LDAP_SCOPE_BASE, "objectclass=*", NULL, NULL, 0);
+ slapi_pblock_get( resultpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry );
+ slapi_pblock_get( resultpb, SLAPI_PLUGIN_INTOP_RESULT, &err);
+ if ( err == LDAP_SUCCESS && entry!=NULL && entry[0]!=NULL)
+ {
+ value = slapi_entry_attr_get_charptr(entry[0], "vendorVersion");
+ if (value == NULL || strncmp(value, "Netscape", strlen("Netscape")))
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "nssReinitializationRequired: vendor is not Netscape \n");
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "or version is earlier than 6.0\n", value);
+ nssReinitializationRequired = 1;
+ slapi_free_search_results_internal(resultpb);
+ slapi_pblock_destroy(resultpb);
+ slapi_ch_free((void **)&value);
+ return nssReinitializationRequired;
+ }
+
+ if ( (str = strstr(value,"/")) != NULL )
+ {
+ str++;
+ version = atof(str);
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "nssReinitializationRequired: version is %f. \n", version);
+ }
+
+
+ if (str == NULL || version < DSVERSION)
+ {
+ nssReinitializationRequired = 1;
+ }
+ slapi_ch_free((void **)&value);
+
+ }
+ slapi_free_search_results_internal(resultpb);
+ slapi_pblock_destroy(resultpb);
+ return nssReinitializationRequired;
+
+}
+
+static PRStatus sendGetReq(PRFileDesc *fd, const char *path)
+{
+ PRStatus status = PR_SUCCESS;
+ char *reqBUF = NULL;
+ PRInt32 http_connection_time_out = 0;
+ int buflen = (HTTP_GET_STD_LEN + strlen(path));
+
+ reqBUF = (char *)PR_Calloc(1, buflen);
+
+ strcpy(reqBUF, HTTP_GET);
+ strcat(reqBUF, " ");
+ strcat(reqBUF, path);
+ strcat(reqBUF, " ");
+ strcat(reqBUF, HTTP_PROTOCOL);
+ strcat(reqBUF, "\r\n\r\n\0");
+
+ http_connection_time_out = httpConfig->connectionTimeOut;
+ status = sendFullData( fd, reqBUF, http_connection_time_out);
+
+bail:
+ if (reqBUF) {
+ PR_Free(reqBUF);
+ reqBUF = 0;
+ }
+ return status;
+}
+
+static PRStatus sendFullData( PRFileDesc *fd, char *buf, int timeOut)
+{
+ int dataSent = 0;
+ int bufLen = strlen(buf);
+ int retVal = 0;
+ PRInt32 errcode = 0;
+ while (dataSent < bufLen)
+ {
+ retVal = PR_Send(fd, buf+dataSent, bufLen-dataSent, 0, PR_MillisecondsToInterval(timeOut));
+ if (retVal == -1 )
+ break;
+ dataSent += retVal;
+ }
+ if (dataSent == bufLen )
+ return PR_SUCCESS;
+ else
+ {
+ errcode = PR_GetError();
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "sendFullData: dataSent=%d bufLen=%d -> NSPR Error code (%d)\n",
+ dataSent, bufLen, errcode);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "---------->NSPR Error code (%d) \n", errcode,0,0);
+ return PR_FAILURE;
+ }
+}
+
+static PRStatus sendPostReq(PRFileDesc *fd, const char *path, httpheader **httpheaderArray, char *body)
+{
+ PRStatus status = PR_SUCCESS;
+ char body_len_str[20];
+ char *reqBUF = NULL;
+ PRInt32 http_connection_time_out = 0;
+ int i = 0;
+ int body_len, buflen = 0;
+
+ body_len = strlen(body);
+ PR_snprintf(body_len_str, sizeof(body_len_str), "%d", body_len);
+
+ buflen = (HTTP_POST_STD_LEN + strlen(path) + body_len + strlen(body_len_str));
+
+ for (i = 0; httpheaderArray[i] != NULL; i++) {
+
+ if (httpheaderArray[i]->name != NULL)
+ {
+ buflen += strlen(httpheaderArray[i]->name) + 2;
+ if (httpheaderArray[i]->value != NULL)
+ buflen += strlen(httpheaderArray[i]->value) + 2;
+ }
+
+ }
+
+ reqBUF = (char *)PR_Calloc(1, buflen);
+
+ strcpy(reqBUF, HTTP_POST);
+ strcat(reqBUF, " ");
+ strcat(reqBUF, path);
+ strcat(reqBUF, " ");
+ strcat(reqBUF, HTTP_PROTOCOL);
+ strcat(reqBUF, "\r\n");
+ strcat(reqBUF, HTTP_CONTENT_LENGTH);
+ strcat(reqBUF, " ");
+ strcat(reqBUF, body_len_str);
+ strcat(reqBUF, "\r\n");
+ strcat(reqBUF, HTTP_CONTENT_TYPE_URL_ENCODED);
+ strcat(reqBUF, "\r\n");
+
+ for (i = 0; httpheaderArray[i] != NULL; i++) {
+
+ if (httpheaderArray[i]->name != NULL)
+ strcat(reqBUF, httpheaderArray[i]->name);
+ strcat(reqBUF, ": ");
+ if (httpheaderArray[i]->value != NULL)
+ strcat(reqBUF, httpheaderArray[i]->value);
+ strcat(reqBUF, "\r\n");
+
+ }
+
+ strcat(reqBUF, "\r\n");
+ strcat(reqBUF, body);
+ strcat(reqBUF, "\0");
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "---------->reqBUF is %s \n",reqBUF,0,0);
+ http_connection_time_out = httpConfig->connectionTimeOut;
+
+ status = sendFullData( fd, reqBUF, http_connection_time_out);
+
+bail:
+ if (reqBUF) {
+ PR_Free(reqBUF);
+ reqBUF = 0;
+ }
+ return status;
+}
+
+
+static PRStatus getChar(PRFileDesc *fd, char *buf)
+{
+ PRInt32 bytesRead = http_read(fd, buf, 1);
+ if (bytesRead <=0) {
+ PRInt32 errcode = PR_GetError();
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "getChar: NSPR Error code (%d)\n", errcode);
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+}
+
+static PRStatus getBody(PRFileDesc *fd, char **buf, int *actualBytesRead)
+{
+ int totalBytesRead = 0;
+ int size = 4 * HTTP_DEFAULT_BUFFER_SIZE;
+ int bytesRead = size;
+ char *data = (char *) PR_Calloc(1, size);
+ while (bytesRead == size) {
+ bytesRead = http_read(fd, (data+totalBytesRead), size);
+ if (bytesRead <= 0) {
+ /* Read error */
+ return PR_FAILURE;
+ }
+ if (bytesRead == size) {
+ /* more data to be read so increase the buffer */
+ size = size * 2 ;
+ data = (char *) PR_Realloc(data, size);
+ }
+ totalBytesRead += bytesRead;
+ }
+ *buf = data;
+ *actualBytesRead = totalBytesRead;
+
+ return PR_SUCCESS;
+}
+
+static PRInt32 http_read(PRFileDesc *fd, char *buf, int size)
+{
+ PRInt32 http_read_time_out = 0;
+ http_read_time_out = httpConfig->readTimeOut;
+ return PR_Recv(fd, buf, size, 0, PR_MillisecondsToInterval(http_read_time_out));
+}
+
+static PRBool isWhiteSpace(char ch)
+{
+ PRBool b = PR_FALSE;
+ if (ch == ' ') {
+ b = PR_TRUE;
+ }
+ return b;
+}
+
+static PRStatus parseURI(const char *urlstr, char **host, PRInt32 *port, char **path, int *sslOn)
+{
+ PRStatus status = PR_SUCCESS;
+ char *brk;
+ int len;
+ static const char delimiters[] = ":/?#";
+ char *url = isHttpReq(urlstr, sslOn);
+
+ if (*sslOn) {
+ *port = 443;
+ }
+ else {
+ *port = 80;
+ }
+ if (url == NULL) {
+ /* Error : */
+ status = PR_FAILURE;
+ goto bail;
+ }
+ len = PL_strlen(url);
+ /* Currently we do not support Ipv6 addresses */
+ brk = PL_strpbrk(url, delimiters);
+ if (!brk) {
+ *host = PL_strndup(url, len);
+ toLowerCase(*host);
+ goto bail;
+ }
+ switch (*brk)
+ {
+ case '/' :
+ case '?' :
+ case '#' :
+ /* Get the Host, the rest is Path */
+ *host = PL_strndup(url, (brk - url));
+ toLowerCase(*host);
+ status = parseAtPath(brk, path);
+ break;
+ case ':' :
+ /* Get the Host and process port, path */
+ *host = PL_strndup(url, (brk - url));
+ toLowerCase(*host);
+ status = parseAtPort(brk+1, port, path);
+ break;
+ default:
+ /* Error : HTTP_BAD_URL */
+ break;
+ }
+
+bail:
+ if (url) {
+ PR_Free(url);
+ }
+ return status;
+}
+
+static PRStatus parseAtPort(const char* url, PRInt32 *port, char **path)
+{
+ PRStatus status = PR_SUCCESS;
+ static const char delimiters[] = "/?#";
+ char* brk = PL_strpbrk(url, delimiters);
+ if (!brk) /* everything is a Port */
+ {
+ *port = getPort(url);
+ if (*port <= 0) {
+ /* Error : HTTP_BAD_URL */
+ return PR_FAILURE;
+ } else {
+ return status;
+ }
+ }
+
+ switch (*brk)
+ {
+ case '/' :
+ case '?' :
+ case '#' :
+ /* Get the Port, the rest is Path */
+ *port = getPort(url);
+ if (*port <= 0) {
+ /* Error : HTTP_BAD_URL */
+ return PR_FAILURE;
+ }
+ status = parseAtPath(brk, path);
+ break;
+ default:
+ /* Error : HTTP_BAD_URL */
+ break;
+ }
+ return status;
+}
+
+static PRStatus parseAtPath(const char *url, char **path)
+{
+ PRStatus status = PR_SUCCESS;
+ char *dir = "%s%s";
+ *path = (char *)PR_Calloc(1, (strlen(dir) + 1024));
+
+ /* Just write the path and check for a starting / */
+ if ('/' != *url) {
+ PR_sscanf(*path, dir, "/", url);
+ } else {
+ strcpy(*path, url);
+ }
+ if (!*path) {
+ /* Error : HTTP_BAD_URL */
+ status = PR_FAILURE;
+ }
+ return status;
+}
+
+static void toLowerCase(char* str)
+{
+ if (str) {
+ char* lstr = str;
+ PRInt8 shift = 'a' - 'A';
+ for(; (*lstr != '\0'); ++lstr) {
+ if ((*(lstr) <= 'Z') && (*(lstr) >= 'A')) {
+ *(lstr) = *(lstr) + shift;
+ }
+ }
+ }
+}
+
+static PRInt32 getPort(const char* src)
+{
+ /* search for digits up to a slash or the string ends */
+ const char* port = src;
+ PRInt32 returnValue = -1;
+ char c;
+
+ /* skip leading white space */
+ while (isAsciiSpace(*port))
+ port++;
+
+ while ((c = *port++) != '\0') {
+ /* stop if slash or ? or # reached */
+ if (c == '/' || c == '?' || c == '#')
+ break;
+ else if (!isAsciiDigit(c))
+ return returnValue;
+ }
+ return (0 < PR_sscanf(src, "%d", &returnValue)) ? returnValue : -1;
+}
+
+
+static PRBool isAsciiSpace(char aChar)
+{
+ if ((aChar == ' ') || (aChar == '\r') || (aChar == '\n') || (aChar == '\t')) {
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+static PRBool isAsciiDigit(char aChar)
+{
+ if ((aChar >= '0') && (aChar <= '9')) {
+ return PR_TRUE;
+ }
+ return PR_FALSE;
+}
+
+static void setTCPNoDelay(PRFileDesc* fd)
+{
+ PRStatus status = PR_SUCCESS;
+ PRSocketOptionData opt;
+
+ opt.option = PR_SockOpt_NoDelay;
+ opt.value.no_delay = PR_FALSE;
+
+ status = PR_GetSocketOption(fd, &opt);
+ if (status == PR_FAILURE) {
+ return;
+ }
+
+ opt.option = PR_SockOpt_NoDelay;
+ opt.value.no_delay = PR_TRUE;
+ status = PR_SetSocketOption(fd, &opt);
+ if (status == PR_FAILURE) {
+ return;
+ }
+ return;
+}
+
+static char * isHttpReq(const char *url, int *sslOn)
+{
+ static const char http_protopol_header[] = "http://";
+ static const char https_protopol_header[] = "https://";
+ char *newstr = NULL;
+ /* skip leading white space */
+ while (isAsciiSpace(*url))
+ url++;
+
+ if (strncmp(url, http_protopol_header, strlen(http_protopol_header)) == 0) {
+ newstr = (char *)PR_Calloc(1, (strlen(url)-strlen(http_protopol_header) + 1));
+ strcpy(newstr, url+7);
+ strcat(newstr,"\0");
+ *sslOn = 0;
+ }
+ else if (strncmp(url, https_protopol_header, strlen(https_protopol_header)) == 0) {
+ newstr = (char *)PR_Calloc(1, (strlen(url)-strlen(https_protopol_header) + 1));
+ strcpy(newstr, url+8);
+ strcat(newstr,"\0");
+ *sslOn = 1;
+ }
+
+ return newstr;
+}
+
+PRFileDesc* setupSSLSocket(PRFileDesc* fd)
+{
+ SECStatus secStatus;
+ PRFileDesc* sslSocket;
+ PRSocketOptionData socketOption;
+ char *certNickname = NULL;
+
+ socketOption.option = PR_SockOpt_Nonblocking;
+ socketOption.value.non_blocking = PR_FALSE;
+ if( PR_SetSocketOption(fd, &socketOption) != 0) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "Cannot set socket option NSS \n");
+ return NULL;
+ }
+
+ sslSocket = SSL_ImportFD(NULL, fd);
+ if (!sslSocket) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "setupSSLSocket: Cannot import to SSL Socket\n" );
+ goto sslbail;
+ }
+
+ slapi_log_error( SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "setupSSLSocket: setupssl socket created\n" );
+
+ secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, 1);
+ if (SECSuccess != secStatus) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "setupSSLSocket: Cannot set SSL_SECURITY option\n");
+ goto sslbail;
+ }
+
+ secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, 1);
+ if (SECSuccess != secStatus) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "setupSSLSocket: CAnnot set SSL_HANDSHAKE_AS_CLIENT option\n");
+ goto sslbail;
+ }
+
+ /* Set SSL callback routines. */
+
+ secStatus = SSL_GetClientAuthDataHook(sslSocket,
+ (SSLGetClientAuthData) getClientAuthData,
+ (void *)certNickname);
+ if (secStatus != SECSuccess) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "setupSSLSocket: SSL_GetClientAuthDataHook Failed\n");
+ goto sslbail;
+ }
+
+ secStatus = SSL_AuthCertificateHook(sslSocket,
+ (SSLAuthCertificate) authCertificate,
+ (void *)CERT_GetDefaultCertDB());
+ if (secStatus != SECSuccess) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "setupSSLSocket: SSL_AuthCertificateHook Failed\n");
+ goto sslbail;
+ }
+
+ secStatus = SSL_BadCertHook(sslSocket,
+ (SSLBadCertHandler) badCertHandler, NULL);
+ if (secStatus != SECSuccess) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "setupSSLSocket: SSL_BadCertHook Failed\n");
+ goto sslbail;
+ }
+
+ secStatus = SSL_HandshakeCallback(sslSocket,
+ (SSLHandshakeCallback) handshakeCallback, NULL);
+ if (secStatus != SECSuccess) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "setupSSLSocket: SSL_HandshakeCallback Failed\n");
+ goto sslbail;
+ }
+
+ return sslSocket;
+
+sslbail:
+ PR_Close(fd);
+ return NULL;
+}
+
+SECStatus
+ authCertificate(void *arg, PRFileDesc *socket,
+ PRBool checksig, PRBool isServer)
+{
+
+ SECCertUsage certUsage;
+ CERTCertificate * cert;
+ void * pinArg;
+ char * hostName;
+ SECStatus secStatus;
+
+ if (!arg || !socket) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ " authCertificate: Faulty socket in callback function \n");
+ return SECFailure;
+ }
+
+ /* Define how the cert is being used based upon the isServer flag. */
+
+ certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
+
+ cert = SSL_PeerCertificate(socket);
+
+ pinArg = SSL_RevealPinArg(socket);
+
+ secStatus = CERT_VerifyCertNow((CERTCertDBHandle *)arg,
+ cert,
+ checksig,
+ certUsage,
+ pinArg);
+
+ /* If this is a server, we're finished. */
+ if (isServer || secStatus != SECSuccess) {
+ return secStatus;
+ }
+
+ hostName = SSL_RevealURL(socket);
+
+ if (hostName && hostName[0]) {
+ secStatus = CERT_VerifyCertName(cert, hostName);
+ } else {
+ PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0);
+ secStatus = SECFailure;
+ }
+
+ if (hostName)
+ PR_Free(hostName);
+
+ return secStatus;
+}
+
+SECStatus
+ badCertHandler(void *arg, PRFileDesc *socket)
+{
+
+ SECStatus secStatus = SECFailure;
+ PRErrorCode err;
+
+ /* log invalid cert here */
+
+ if (!arg) {
+ return secStatus;
+ }
+
+ *(PRErrorCode *)arg = err = PORT_GetError();
+ switch (err) {
+ case SEC_ERROR_INVALID_AVA:
+ case SEC_ERROR_INVALID_TIME:
+ case SEC_ERROR_BAD_SIGNATURE:
+ case SEC_ERROR_EXPIRED_CERTIFICATE:
+ case SEC_ERROR_UNKNOWN_ISSUER:
+ case SEC_ERROR_UNTRUSTED_CERT:
+ case SEC_ERROR_CERT_VALID:
+ case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+ case SEC_ERROR_CRL_EXPIRED:
+ case SEC_ERROR_CRL_BAD_SIGNATURE:
+ case SEC_ERROR_EXTENSION_VALUE_INVALID:
+ case SEC_ERROR_CA_CERT_INVALID:
+ case SEC_ERROR_CERT_USAGES_INVALID:
+ case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
+ secStatus = SECSuccess;
+ break;
+ default:
+ secStatus = SECFailure;
+ break;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "Bad certificate: %d\n", err);
+
+ return secStatus;
+}
+
+SECStatus
+ getClientAuthData(void *arg,
+ PRFileDesc *socket,
+ struct CERTDistNamesStr *caNames,
+ struct CERTCertificateStr **pRetCert,
+ struct SECKEYPrivateKeyStr **pRetKey)
+{
+ CERTCertificate * cert;
+ SECKEYPrivateKey * privKey;
+ char * chosenNickName = (char *)arg;
+ void * proto_win = NULL;
+ SECStatus secStatus = SECFailure;
+ proto_win = SSL_RevealPinArg(socket);
+
+ if (chosenNickName) {
+ cert = PK11_FindCertFromNickname(chosenNickName, proto_win);
+ if (cert) {
+ privKey = PK11_FindKeyByAnyCert(cert, proto_win);
+ if (privKey) {
+ secStatus = SECSuccess;
+ } else {
+ CERT_DestroyCertificate(cert);
+ }
+ }
+ } else { /* no nickname given, automatically find the right cert */
+ CERTCertNicknames *names;
+ int i;
+
+ names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(),
+ SEC_CERT_NICKNAMES_USER, proto_win);
+
+ if (names != NULL) {
+ for(i = 0; i < names->numnicknames; i++ ) {
+
+ cert = PK11_FindCertFromNickname(names->nicknames[i],
+ proto_win);
+ if (!cert) {
+ continue;
+ }
+
+ /* Only check unexpired certs */
+ if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE)
+ != secCertTimeValid ) {
+ CERT_DestroyCertificate(cert);
+ continue;
+ }
+
+ secStatus = NSS_CmpCertChainWCANames(cert, caNames);
+ if (secStatus == SECSuccess) {
+ privKey = PK11_FindKeyByAnyCert(cert, proto_win);
+ if (privKey) {
+ break;
+ }
+ secStatus = SECFailure;
+ break;
+ }
+ CERT_FreeNicknames(names);
+ } /* for loop */
+ }
+ }
+
+ if (secStatus == SECSuccess) {
+ *pRetCert = cert;
+ *pRetKey = privKey;
+ }
+
+ return secStatus;
+}
+
+SECStatus
+ handshakeCallback(PRFileDesc *socket, void *arg)
+{
+ slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "----------> Handshake has completed, ready to send data securely.\n");
+ return SECSuccess;
+}
+
+
+/**
+ * PUBLIC FUNCTIONS IMPLEMENTATION
+ */
+int http_impl_init(Slapi_ComponentId *plugin_id)
+{
+ int status = HTTP_IMPL_SUCCESS;
+ slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "-> http_impl_init \n");
+ httpConfig = NULL;
+
+ httpConfig = (httpPluginConfig *) slapi_ch_calloc(1, sizeof(httpPluginConfig));
+
+ status = readConfigLDAPurl(plugin_id, HTTP_PLUGIN_DN);
+ if (status != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "http_impl_start: Unable to get HTTP config information \n");
+ return HTTP_IMPL_FAILURE;
+ }
+
+ status = readConfigLDAPurl(plugin_id, CONFIG_DN);
+ if (status != 0) {
+ slapi_log_error(SLAPI_LOG_FATAL, HTTP_PLUGIN_SUBSYSTEM,
+ "http_impl_start: Unable to get config information \n");
+ return HTTP_IMPL_FAILURE;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "<- http_impl_init \n");
+
+ return status;
+
+}
+
+
+int http_impl_get_text(char *url, char **data, int *bytesRead)
+{
+ int status = HTTP_IMPL_SUCCESS;
+ status = doRequestRetry(url, NULL, NULL, data, bytesRead, HTTP_REQ_TYPE_GET);
+ return status;
+}
+
+int http_impl_get_binary(char *url, char **data, int *bytesRead)
+{
+ int status = HTTP_IMPL_SUCCESS;
+ status = doRequestRetry(url, NULL, NULL, data, bytesRead, HTTP_REQ_TYPE_GET);
+ return status;
+}
+
+int http_impl_get_redirected_uri(char *url, char **data, int *bytesRead)
+{
+ int status = HTTP_IMPL_SUCCESS;
+ status = doRequestRetry(url, NULL, NULL, data, bytesRead, HTTP_REQ_TYPE_REDIRECT);
+ return status;
+}
+
+int http_impl_post(char *url, httpheader **httpheaderArray, char *body, char **data, int *bytesRead)
+{
+ int status = HTTP_IMPL_SUCCESS;
+ status = doRequestRetry(url, httpheaderArray, body, data, bytesRead, HTTP_REQ_TYPE_POST);
+ return status;
+}
+
+void http_impl_shutdown()
+{
+ int status = HTTP_IMPL_SUCCESS;
+ /**
+ * Put cleanup code here
+ */
+}
+
+static int readConfigLDAPurl(Slapi_ComponentId *plugin_id, char *plugindn) {
+
+ int rc = LDAP_SUCCESS;
+ Slapi_DN *sdn = NULL;
+ int status = HTTP_IMPL_SUCCESS;
+ Slapi_Entry *entry = NULL;
+
+ sdn = slapi_sdn_new_dn_byref(plugindn);
+ rc = slapi_search_internal_get_entry(sdn, NULL, &entry, plugin_id);
+ slapi_sdn_free(&sdn);
+ if (rc != LDAP_SUCCESS) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "readConfigLDAPurl: Could not find entry %s (error %d)\n", plugindn, rc);
+ status = HTTP_IMPL_FAILURE;
+ return status;
+ }
+ if (NULL == entry)
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, HTTP_PLUGIN_SUBSYSTEM,
+ "readConfigLDAPurl: No entries found for <%s>\n", plugindn);
+
+ status = HTTP_IMPL_FAILURE;
+ return status;
+ }
+
+ if ((PL_strcasecmp(plugindn, HTTP_PLUGIN_DN) == 0))
+ status = parseHTTPConfigEntry(entry);
+ else
+ status = parseConfigEntry(entry);
+
+ slapi_entry_free(entry);
+ return status;
+
+}
+
+/* Retrieves the plugin configuration info */
+
+/* Retrieves security info as well as the path info required for the SSL
+config dir */
+static int parseConfigEntry(Slapi_Entry *e)
+{
+ char *value = NULL;
+
+ value = slapi_entry_attr_get_charptr(e, ATTR_DS_SECURITY);
+ if (value) {
+ httpConfig->DS_sslOn = value;
+ }
+
+ return HTTP_IMPL_SUCCESS;
+
+}
+
+
+static int parseHTTPConfigEntry(Slapi_Entry *e)
+{
+ int value = 0;
+
+
+ value = slapi_entry_attr_get_int(e, ATTR_RETRY_COUNT);
+ if (value) {
+ httpConfig->retryCount = value;
+ }
+
+ value = slapi_entry_attr_get_int(e, ATTR_CONNECTION_TIME_OUT);
+ if (value) {
+ httpConfig->connectionTimeOut = value;
+ }
+ else {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "parseHTTPConfigEntry: HTTP Connection Time Out cannot be read. Setting to default value of 5000 ms \n", 0,0,0);
+ httpConfig->connectionTimeOut = 5000;
+ }
+
+
+ value = slapi_entry_attr_get_int(e, ATTR_READ_TIME_OUT);
+ if (value) {
+ httpConfig->readTimeOut = value;
+ }
+ else {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "parseHTTPConfigEntry: HTTP Read Time Out cannot be read. Setting to default value of 5000 ms \n", 0,0,0);
+ httpConfig->readTimeOut = 5000;
+ }
+
+ httpConfig->nssInitialized = 0;
+
+ return HTTP_IMPL_SUCCESS;
+
+}
+
+/**
+ * Self Testing
+ */
+#ifdef BUILD_STANDALONE
+int main(int argc, char **argv)
+{
+ PRStatus status = PR_SUCCESS;
+ char *buf;
+ int bytes;
+ char *host;
+ PRInt32 port;
+ char *path;
+ if (argc < 2) {
+ printf("URL missing\n");
+ return -1;
+ }
+ PR_Init(PR_USER_THREAD,PR_PRIORITY_NORMAL, 0);
+ doRequest(argv[1], &buf, &bytes, 2);
+ printf( "%s\n", buf );
+ return -1;
+}
+#endif
+
diff --git a/ldap/servers/plugins/http/http_impl.h b/ldap/servers/plugins/http/http_impl.h
new file mode 100644
index 00000000..0bca3ca2
--- /dev/null
+++ b/ldap/servers/plugins/http/http_impl.h
@@ -0,0 +1,25 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+#ifndef HTTP_IMPL_H__
+#define HTTP_IMPL_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int http_impl_init(Slapi_ComponentId *plugin_id);
+int http_impl_get_text(char *url, char **data, int *bytesRead);
+int http_impl_get_binary(char *url, char **data, int *bytesRead);
+int http_impl_get_redirected_uri(char *url, char **data, int *bytesRead);
+int http_impl_post(char *url, httpheader **httpheaderArray, char *body, char **data, int *bytesRead);
+void http_impl_shutdown();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ldap/servers/plugins/passthru/Makefile b/ldap/servers/plugins/passthru/Makefile
new file mode 100644
index 00000000..11540915
--- /dev/null
+++ b/ldap/servers/plugins/passthru/Makefile
@@ -0,0 +1,90 @@
+#
+# 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 "Pass Through Authentication" plugin
+#
+#
+
+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 = $(OBJDIR)/lib/libpassthru
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./libpassthru.def
+endif
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd
+
+PASSTHRU_OBJS= ptbind.o ptconfig.o ptconn.o ptdebug.o ptpreop.o ptutil.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(PASSTHRU_OBJS))
+
+ifeq ($(ARCH), WINNT)
+LIBPASSTHRU_DLL_OBJ = $(addprefix $(OBJDEST)/, ptdllmain.o)
+endif
+
+LIBPASSTHRU= $(addprefix $(LIBDIR)/, $(PASSTHRU_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL) $(NSPRLINK)
+endif
+
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libpassthru.def"
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPDLINK) $(LDAP_SDK_LIBLDAP_DLL) $(NSPRLINK)
+EXTRA_LIBS += $(DLL_EXTRA_LIBS)
+LD=ld
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBPASSTHRU)
+
+$(LIBPASSTHRU): $(OBJS) $(LIBPASSTHRU_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBPASSTHRU_DLL_OBJ) $(PLATFORMLIBS) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBPASSTHRU_DLL_OBJ)
+endif
+ $(RM) $(LIBPASSTHRU)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+#
+# header file dependencies (incomplete)
+#
+$(OBJS): passthru.h
diff --git a/ldap/servers/plugins/passthru/PT-Notes b/ldap/servers/plugins/passthru/PT-Notes
new file mode 100644
index 00000000..2e3cea10
--- /dev/null
+++ b/ldap/servers/plugins/passthru/PT-Notes
@@ -0,0 +1,30 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+ Pass Through Authentication Plugin Notes
+
+Key
+ r required feature
+ n nice-to-have
+ ? undecided whether this is a good idea or not
+
+Missing features:
+n U/I for configuration.
+
+Loose ends:
+n Resolve any remaining code that is marked with XXX.
+n Put some thought into cases we do not handle (SASL, no DN, no passwd) and
+ make sure we do the right thing in terms of errors, letting server's
+ standard mechanism handle the bind, etc.
+? Protect against server connecting back to itself recursively.
+
+Testing:
+r Basic tests (all platforms: NT,Sol,IRIX,AIX,HP/UX,OSF/1).
+r Controls (both coming (e.g., ?) and going (e.g., password policy).
+r SSL connections to remote servers.
+r LDAPv2/v3 compatiblity
+r Stress tests.
diff --git a/ldap/servers/plugins/passthru/libpassthru.def b/ldap/servers/plugins/passthru/libpassthru.def
new file mode 100644
index 00000000..b08d907a
--- /dev/null
+++ b/ldap/servers/plugins/passthru/libpassthru.def
@@ -0,0 +1,14 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+;
+;
+DESCRIPTION 'Netscape Directory Server 7 Pass Through Authentication Plugin'
+;CODE SHARED READ EXECUTE
+;DATA SHARED READ WRITE
+EXPORTS
+ passthruauth_init @1
+ plugin_init_debug_level @2
diff --git a/ldap/servers/plugins/passthru/passthru.h b/ldap/servers/plugins/passthru/passthru.h
new file mode 100644
index 00000000..fdf30d65
--- /dev/null
+++ b/ldap/servers/plugins/passthru/passthru.h
@@ -0,0 +1,131 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * passthru.h - Pass Through Authentication shared definitions
+ *
+ */
+
+#ifndef _PASSTHRU_H_
+#define _PASSTHRU_H_
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include "portable.h"
+#include "slapi-plugin.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+#include <nspr.h>
+
+/* Private API: to get slapd_pr_strerror() and SLAPI_COMPONENT_NAME_NSPR */
+#include "slapi-private.h"
+
+/*
+ * macros
+ */
+#define PASSTHRU_PLUGIN_SUBSYSTEM "passthru-plugin" /* for logging */
+
+#define PASSTHRU_ASSERT( expr ) PR_ASSERT( expr )
+
+#define PASSTHRU_LDAP_CONN_ERROR( err ) ( (err) == LDAP_SERVER_DOWN || \
+ (err) == LDAP_CONNECT_ERROR )
+
+#define PASSTHRU_OP_NOT_HANDLED 0
+#define PASSTHRU_OP_HANDLED 1
+
+#define PASSTHRU_CONN_TRIES 2
+
+/* #define PASSTHRU_VERBOSE_LOGGING */
+
+/* defaults */
+#define PASSTHRU_DEF_SRVR_MAXCONNECTIONS 3
+#define PASSTHRU_DEF_SRVR_MAXCONCURRENCY 5
+#define PASSTHRU_DEF_SRVR_TIMEOUT 300 /* seconds */
+#define PASSTHRU_DEF_SRVR_PROTOCOL_VERSION LDAP_VERSION3
+#define PASSTHRU_DEF_SRVR_CONNLIFETIME 0 /* seconds */
+#define PASSTHRU_DEF_SRVR_FAILOVERCONNLIFETIME 300 /* seconds */
+
+/*
+ * structs
+ */
+typedef struct passthrusuffix {
+ int ptsuffix_len;
+ char *ptsuffix_normsuffix; /* not case normalized */
+ struct passthrusuffix *ptsuffix_next;
+} PassThruSuffix;
+
+typedef struct passthruconnection {
+ LDAP *ptconn_ld;
+ int ptconn_ldapversion;
+ int ptconn_usecount;
+#define PASSTHRU_CONNSTATUS_OK 0
+#define PASSTHRU_CONNSTATUS_DOWN 1
+#define PASSTHRU_CONNSTATUS_STALE 2
+ int ptconn_status;
+ time_t ptconn_opentime;
+ struct passthruconnection *ptconn_prev;
+ struct passthruconnection *ptconn_next;
+} PassThruConnection;
+
+typedef struct passthruserver {
+ char *ptsrvr_url; /* copy from argv[i] */
+ char *ptsrvr_hostname;
+ int ptsrvr_port;
+ int ptsrvr_secure; /* use SSL? */
+ int ptsrvr_ldapversion;
+ int ptsrvr_maxconnections;
+ int ptsrvr_maxconcurrency;
+ int ptsrvr_connlifetime; /* in seconds */
+ struct timeval *ptsrvr_timeout; /* for ldap_result() */
+ PassThruSuffix *ptsrvr_suffixes;
+ Slapi_CondVar *ptsrvr_connlist_cv;
+ Slapi_Mutex *ptsrvr_connlist_mutex; /* protects connlist */
+ int ptsrvr_connlist_count;
+ PassThruConnection *ptsrvr_connlist;
+ struct passthruserver *ptsrvr_next;
+} PassThruServer;
+
+typedef struct passthruconfig {
+ PassThruServer *ptconfig_serverlist;
+} PassThruConfig;
+
+
+/*
+ * public functions
+ */
+/*
+ * ptbind.c:
+ */
+int passthru_simple_bind_s( Slapi_PBlock *pb, PassThruServer *srvr, int tries,
+ char *dn, struct berval *creds, LDAPControl **reqctrls, int *lderrnop,
+ char **matcheddnp, char **errmsgp, struct berval ***refurlsp,
+ LDAPControl ***resctrlsp );
+
+/*
+ * ptconfig.c:
+ */
+int passthru_config( int argc, char **argv );
+PassThruConfig *passthru_get_config( void );
+
+/*
+ * ptconn.c:
+ */
+int passthru_dn2server( PassThruConfig *cfg, char *normdn,
+ PassThruServer **srvrp );
+int passthru_get_connection( PassThruServer *srvr, LDAP **ldp );
+void passthru_release_connection( PassThruServer *srvr, LDAP *ld, int dispose );
+void passthru_close_all_connections( PassThruConfig *cfg );
+
+/*
+ * ptutil.c:
+ */
+struct berval **passthru_strs2bervals( char **ss );
+char ** passthru_bervals2strs( struct berval **bvs );
+void passthru_free_bervals( struct berval **bvs );
+char *passthru_urlparse_err2string( int err );
+
+#endif /* _PASSTHRU_H_ */
diff --git a/ldap/servers/plugins/passthru/ptbind.c b/ldap/servers/plugins/passthru/ptbind.c
new file mode 100644
index 00000000..f9da57a1
--- /dev/null
+++ b/ldap/servers/plugins/passthru/ptbind.c
@@ -0,0 +1,144 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * ptbind.c - LDAP bind-related code for Pass Through Authentication
+ *
+ */
+
+#include "passthru.h"
+
+static int
+passthru_simple_bind_once_s( PassThruServer *srvr, char *dn,
+ struct berval *creds, LDAPControl **reqctrls, int *lderrnop,
+ char **matcheddnp, char **errmsgp, struct berval ***refurlsp,
+ LDAPControl ***resctrlsp );
+
+
+/*
+ * Attempt to chain a bind request off to "srvr." We return an LDAP error
+ * code that indicates whether we successfully got a response from the
+ * other server or not. If we succeed, we return LDAP_SUCCESS and *lderrnop
+ * is set to the result code from the remote server.
+ *
+ * Note that in the face of "ldap server down" or "ldap connect failed" errors
+ * we make up to "tries" attempts to bind to the remote server. Since we
+ * are only interested in recovering silently when the remote server is up
+ * but decided to close our connection, we retry without pausing between
+ * attempts.
+ */
+int
+passthru_simple_bind_s( Slapi_PBlock *pb, PassThruServer *srvr, int tries,
+ char *dn, struct berval *creds, LDAPControl **reqctrls, int *lderrnop,
+ char **matcheddnp, char **errmsgp, struct berval ***refurlsp,
+ LDAPControl ***resctrlsp )
+{
+ int rc;
+
+ PASSTHRU_ASSERT( srvr != NULL );
+ PASSTHRU_ASSERT( tries > 0 );
+ PASSTHRU_ASSERT( creds != NULL );
+ PASSTHRU_ASSERT( lderrnop != NULL );
+ PASSTHRU_ASSERT( refurlsp != NULL );
+
+ do {
+ /*
+ * check to see if operation has been abandoned...
+ */
+ if ( slapi_op_abandoned( pb )) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "operation abandoned\n" );
+ rc = LDAP_USER_CANCELLED;
+ } else {
+ rc = passthru_simple_bind_once_s( srvr, dn, creds, reqctrls,
+ lderrnop, matcheddnp, errmsgp, refurlsp, resctrlsp );
+ }
+ } while ( PASSTHRU_LDAP_CONN_ERROR( rc ) && --tries > 0 );
+
+ return( rc );
+}
+
+
+/*
+ * like passthru_simple_bind_s() but only makes one attempt.
+ */
+static int
+passthru_simple_bind_once_s( PassThruServer *srvr, char *dn,
+ struct berval *creds, LDAPControl **reqctrls, int *lderrnop,
+ char **matcheddnp, char **errmsgp, struct berval ***refurlsp,
+ LDAPControl ***resctrlsp )
+{
+ int rc, msgid;
+ char **referrals;
+ struct timeval tv, *timeout;
+ LDAPMessage *result;
+ LDAP *ld;
+
+ /*
+ * Grab an LDAP connection to use for this bind.
+ */
+ ld = NULL;
+ if (( rc = passthru_get_connection( srvr, &ld )) != LDAP_SUCCESS ) {
+ goto release_and_return;
+ }
+
+ /*
+ * Send the bind operation (need to retry on LDAP_SERVER_DOWN)
+ */
+ if (( rc = ldap_sasl_bind( ld, dn, LDAP_SASL_SIMPLE, creds, reqctrls,
+ NULL, &msgid )) != LDAP_SUCCESS ) {
+ goto release_and_return;
+ }
+
+ /*
+ * determine timeout value (how long we will wait for a response)
+ * if timeout is NULL or zero'd, we wait indefinitely.
+ */
+ if ( srvr->ptsrvr_timeout == NULL || ( srvr->ptsrvr_timeout->tv_sec == 0
+ && srvr->ptsrvr_timeout->tv_usec == 0 )) {
+ timeout = NULL;
+ } else {
+ tv = *srvr->ptsrvr_timeout; /* struct copy */
+ timeout = &tv;
+ }
+
+ /*
+ * Wait for a result.
+ */
+ rc = ldap_result( ld, msgid, 1, timeout, &result );
+
+ /*
+ * Interpret the result.
+ */
+ if ( rc == 0 ) { /* timeout */
+ /*
+ * Timed out waiting for a reply from the server.
+ */
+ rc = LDAP_TIMEOUT;
+ } else if ( rc < 0 ) {
+ /*
+ * Some other error occurred (no result received).
+ */
+ rc = ldap_get_lderrno( ld, matcheddnp, errmsgp );
+ } else {
+ /*
+ * Got a result from remote server -- parse it.
+ */
+ rc = ldap_parse_result( ld, result, lderrnop, matcheddnp, errmsgp,
+ &referrals, resctrlsp, 1 );
+ if ( referrals != NULL ) {
+ *refurlsp = passthru_strs2bervals( referrals );
+ ldap_value_free( referrals );
+ }
+ }
+
+
+release_and_return:
+ if ( ld != NULL ) {
+ passthru_release_connection( srvr, ld, PASSTHRU_LDAP_CONN_ERROR( rc ));
+ }
+
+ return( rc );
+}
diff --git a/ldap/servers/plugins/passthru/ptconfig.c b/ldap/servers/plugins/passthru/ptconfig.c
new file mode 100644
index 00000000..c3653f66
--- /dev/null
+++ b/ldap/servers/plugins/passthru/ptconfig.c
@@ -0,0 +1,301 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * ptconfig.c - configuration-related code for Pass Through Authentication
+ *
+ */
+
+#include "passthru.h"
+
+/*
+ * Configuration is a bit complicated to fit into a single slapd config file
+ * line, but for now that's how it works. The format is:
+ *
+ * plugin preoperation on PTA NSHOME/passthru-plugin.so passthruauth_init ARGS
+ *
+ * where each ARGS provides configuration for one host. Each ARG should
+ * be of the form:
+ *
+ * "ldap://hosts/suffixes maxconns,maxconcurrency,timeout,ldver,connlifetime"
+ * OR
+ * "ldaps://hosts/suffixes maxconns,maxconcurrency,timeout,ldver,connlifetime"
+ *
+ * where:
+ * hosts is a space-separated list of remote servers (with optional port
+ * numbers) to be used. Each one is tried in order when opening an
+ * LDAP connection.
+ * suffixes is a semicolon separated list of DNs (if a DN contains a
+ * semicolon it must be represented \3B),
+ * maxconns is a limit on how many connections will be made,
+ * maxconcurrency is a limit on how many operations can share a connection,
+ * timeout is a time limit in seconds for bind operations to complete (use
+ * 0 to specify an infinite limit).
+ * ldver is the LDAP protocol version to use to talk to the server (2 or 3)
+ * connlifetime is a time limit time in seconds for a connection to be
+ * used before it is closed and reopened (use 0 to specify an infinite
+ * limit). connlifetime can be omitted in which case a default value
+ * is used; this is for compatibility with DS 4.0 which did not support
+ * connlifetime.
+ */
+
+
+/*
+ * function prototypes
+ */
+static char **get_backend_suffixes( void );
+static int is_underneath_backend_suffix( char *normdn, char **besuffixes );
+
+/*
+ * static variables
+ */
+/* for now, there is only one configuration and it is global to the plugin */
+static PassThruConfig theConfig;
+static int inited = 0;
+
+
+/*
+ * Read configuration and create a configuration data structure.
+ * This is called after the server has configured itself so we can check
+ * for things like collisions between our suffixes and backend's suffixes.
+ * Returns an LDAP error code (LDAP_SUCCESS if all goes well).
+ * XXXmcs: this function leaks memory if any errors occur.
+ */
+int
+passthru_config( int argc, char **argv )
+{
+ int i, j, rc, tosecs, using_def_connlifetime;
+ char *p, **suffixarray;
+ PassThruServer *prevsrvr, *srvr;
+ PassThruSuffix *suffix, *prevsuffix;
+ LDAPURLDesc *ludp;
+
+ if ( inited ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "only one pass through plugin instance can be used\n" );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ inited = 1;
+
+ /*
+ * It doesn't make sense to configure a pass through plugin without
+ * providing at least one remote server. Return an error if attempted.
+ */
+ if ( argc < 1 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "no pass through servers found in configuration"
+ " (at least one must be listed)\n" );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ /*
+ * Parse argv[] values.
+ */
+ prevsrvr = NULL;
+ for ( i = 0; i < argc; ++i ) {
+ srvr = (PassThruServer *)slapi_ch_calloc( 1, sizeof( PassThruServer ));
+ srvr->ptsrvr_url = slapi_ch_strdup( argv[i] );
+
+ if (( p = strchr( srvr->ptsrvr_url, ' ' )) == NULL ) {
+ /*
+ * use defaults for maxconnections, maxconcurrency, timeout,
+ * LDAP version, and connlifetime.
+ */
+ srvr->ptsrvr_maxconnections = PASSTHRU_DEF_SRVR_MAXCONNECTIONS;
+ srvr->ptsrvr_maxconcurrency = PASSTHRU_DEF_SRVR_MAXCONCURRENCY;
+ srvr->ptsrvr_timeout = (struct timeval *)slapi_ch_calloc( 1,
+ sizeof( struct timeval ));
+ srvr->ptsrvr_timeout->tv_sec = PASSTHRU_DEF_SRVR_TIMEOUT;
+ srvr->ptsrvr_ldapversion = PASSTHRU_DEF_SRVR_PROTOCOL_VERSION;
+ using_def_connlifetime = 1;
+ } else {
+ /*
+ * parse parameters. format is:
+ * maxconnections,maxconcurrency,timeout,ldapversion
+ * OR maxconnections,maxconcurrency,timeout,ldapversion,lifetime
+ */
+ *p++ = '\0';
+ rc = sscanf( p, "%d,%d,%d,%d,%d", &srvr->ptsrvr_maxconnections,
+ &srvr->ptsrvr_maxconcurrency, &tosecs,
+ &srvr->ptsrvr_ldapversion, &srvr->ptsrvr_connlifetime );
+ if ( rc < 4 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "server parameters should be in the form "
+ "\"maxconnections,maxconcurrency,timeout,ldapversion,"
+ "connlifetime\" (got \"%s\")\n", p );
+ return( LDAP_PARAM_ERROR );
+ } else if ( rc < 5 ) {
+ using_def_connlifetime = 1;
+ srvr->ptsrvr_connlifetime = PASSTHRU_DEF_SRVR_CONNLIFETIME;
+ } else {
+ using_def_connlifetime = 0;
+ }
+
+ if ( srvr->ptsrvr_ldapversion != LDAP_VERSION2
+ && srvr->ptsrvr_ldapversion != LDAP_VERSION3 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "LDAP protocol version should be %d or %d (got %d)\n",
+ LDAP_VERSION2, LDAP_VERSION3,
+ srvr->ptsrvr_ldapversion );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( srvr->ptsrvr_maxconnections <= 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "maximum connections must be greater than "
+ "zero (got %d)\n", srvr->ptsrvr_maxconnections );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( srvr->ptsrvr_maxconcurrency <= 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "maximum concurrency must be greater than "
+ "zero (got %d)\n", srvr->ptsrvr_maxconcurrency );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( tosecs <= 0 ) {
+ srvr->ptsrvr_timeout = NULL;
+ } else {
+ srvr->ptsrvr_timeout = (struct timeval *)slapi_ch_calloc( 1,
+ sizeof( struct timeval ));
+ srvr->ptsrvr_timeout->tv_sec = tosecs;
+ }
+ }
+
+ /*
+ * parse the LDAP URL
+ */
+ if (( rc = ldap_url_parse( srvr->ptsrvr_url, &ludp )) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "unable to parse LDAP URL \"%s\" (%s)\n",
+ srvr->ptsrvr_url, passthru_urlparse_err2string( rc ));
+ return( LDAP_PARAM_ERROR );
+ }
+
+ if ( ludp->lud_dn == NULL || *ludp->lud_dn == '\0' ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "missing suffix in LDAP URL \"%s\"\n",
+ srvr->ptsrvr_url );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ srvr->ptsrvr_hostname = slapi_ch_strdup( ludp->lud_host );
+ srvr->ptsrvr_port = ludp->lud_port;
+ srvr->ptsrvr_secure =
+ (( ludp->lud_options & LDAP_URL_OPT_SECURE ) != 0 );
+
+ /*
+ * If a space-separated list of hosts is configured for failover,
+ * use a different (non infinite) default for connection lifetime.
+ */
+ if ( using_def_connlifetime &&
+ strchr( srvr->ptsrvr_hostname, ' ' ) != NULL ) {
+ srvr->ptsrvr_connlifetime =
+ PASSTHRU_DEF_SRVR_FAILOVERCONNLIFETIME;
+ }
+
+ /*
+ * split the DN into multiple suffixes (separated by ';')
+ */
+ if (( suffixarray = ldap_str2charray( ludp->lud_dn, ";" )) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "unable to parse suffix string \"%s\" within \"%s\"\n",
+ ludp->lud_dn, srvr->ptsrvr_url );
+ return( LDAP_PARAM_ERROR );
+ }
+
+ /*
+ * free our LDAP URL descriptor
+ */
+ ldap_free_urldesc( ludp );
+ ludp = NULL;
+
+ /*
+ * reorganize the suffixes into a linked list and normalize them
+ */
+ prevsuffix = NULL;
+ for ( j = 0; suffixarray[ j ] != NULL; ++j ) {
+
+ /*
+ * allocate a new PassThruSuffix structure and fill it in.
+ */
+ suffix = (PassThruSuffix *)slapi_ch_malloc(
+ sizeof( PassThruSuffix ));
+ suffix->ptsuffix_normsuffix =
+ slapi_dn_normalize( suffixarray[ j ] );
+ suffixarray[ j ] = NULL;
+ suffix->ptsuffix_len = strlen( suffix->ptsuffix_normsuffix );
+ suffix->ptsuffix_next = NULL;
+
+ /*
+ * add to end of list
+ */
+ if ( prevsuffix == NULL ) {
+ srvr->ptsrvr_suffixes = suffix;
+ } else {
+ prevsuffix->ptsuffix_next = suffix;
+ }
+ prevsuffix = suffix;
+ }
+ ldap_memfree( suffixarray );
+
+ /*
+ * create mutexes and condition variables for this server
+ */
+ if (( srvr->ptsrvr_connlist_mutex = slapi_new_mutex()) == NULL ||
+ ( srvr->ptsrvr_connlist_cv = slapi_new_condvar(
+ srvr->ptsrvr_connlist_mutex )) == NULL ) {
+ return( LDAP_LOCAL_ERROR );
+ }
+
+ /*
+ * add this server to the end of our list
+ */
+ if ( prevsrvr == NULL ) {
+ theConfig.ptconfig_serverlist = srvr;
+ } else {
+ prevsrvr->ptsrvr_next = srvr;
+ }
+ prevsrvr = srvr;
+
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ /*
+ * log configuration for debugging purposes
+ */
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "PTA server host: \"%s\", port: %d, secure: %d,"
+ " maxconnections: %d, maxconcurrency: %d, timeout: %d,"
+ " ldversion: %d, connlifetime: %d\n",
+ srvr->ptsrvr_hostname, srvr->ptsrvr_port,
+ srvr->ptsrvr_secure, srvr->ptsrvr_maxconnections,
+ srvr->ptsrvr_maxconcurrency,
+ srvr->ptsrvr_timeout == NULL ? -1
+ : srvr->ptsrvr_timeout->tv_sec, srvr->ptsrvr_ldapversion,
+ srvr->ptsrvr_connlifetime );
+ for ( prevsuffix = srvr->ptsrvr_suffixes; prevsuffix != NULL;
+ prevsuffix = prevsuffix->ptsuffix_next ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ " normalized suffix: \"%s\"\n",
+ prevsuffix->ptsuffix_normsuffix );
+ }
+#endif
+
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+
+/*
+ * Get the pass though configuration data. For now, there is only one
+ * configuration and it is global to the plugin.
+ */
+PassThruConfig *
+passthru_get_config( void )
+{
+ return( &theConfig );
+}
diff --git a/ldap/servers/plugins/passthru/ptconn.c b/ldap/servers/plugins/passthru/ptconn.c
new file mode 100644
index 00000000..56e2e0cc
--- /dev/null
+++ b/ldap/servers/plugins/passthru/ptconn.c
@@ -0,0 +1,420 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * ptconn.c - LDAP connection-related code for Pass Through Authentication
+ *
+ */
+
+#include "passthru.h"
+
+/*
+ * function prototypes
+ */
+static int dn_is_underneath_suffix( PassThruSuffix *suffix, char *normdn,
+ int dnlen );
+static void close_and_dispose_connection( PassThruConnection *conn );
+static void check_for_stale_connections( PassThruServer *srvr );
+
+
+/*
+ * Most of the complicated connection-related code lives in this file. Some
+ * general notes about how we manage our connections to "remote" LDAP servers:
+ *
+ * 1) Each server we have a relationship with is managed independently.
+ *
+ * 2) We may simultaneously issue multiple bind requests on a single LDAP
+ * connection. Each server has a "maxconcurrency" configuration
+ * parameter associated with it that caps the number of outstanding
+ * binds per connection. For each connection we maintain a "usecount"
+ * which is used to track the number of threads using the connection.
+ *
+ * 3) We may open more than one connection to a server. This is only done
+ * when "maxconcurrency" is exceeded for all the connections we already
+ * have open. Each server has a "maxconnections" configuration
+ * parameter associated with it that caps the number of connections.
+ * We also maintain a "connlist_count" for each server so we know when
+ * we have reached the maximum number of open connections allowed.
+ *
+ * 4) If no connection is available to service a request (and we have
+ * reached the limit of how many we are supposed to open), threads
+ * go to sleep on a condition variable and one is woken up each time
+ * a connection's "usecount" is decremented.
+ *
+ * 5) If we see an LDAP_CONNECT_ERROR or LDAP_SERVER_DOWN error on a
+ * session handle, we mark its status as PASSTHRU_CONNSTATUS_DOWN and
+ * close it as soon as all threads using it release it. Connections
+ * marked as "down" are not counted against the "maxconnections" limit.
+ *
+ * 6) We close and reopen connections that have been open for more than
+ * the server's configured connection lifetime. This is done to ensure
+ * that we reconnect to a primary server after failover occurs. If no
+ * lifetime is configured or it is set to 0, we never close and reopen
+ * connections.
+ */
+
+
+/*
+ * Given a normalized target dn, see if it we should "pass through"
+ * authentication to another LDAP server. The answer is "yes" if the
+ * target dn resides under one of the suffixes we have that is associated
+ * with an LDAP server we know about.
+ *
+ * This function assumes that normdn is normalized and the the suffixes in the
+ * cfg structure have also been normalized.
+ *
+ * Returns an LDAP error code, typically:
+ * LDAP_SUCCESS should pass though; *srvrp set.
+ * LDAP_NO_SUCH_OBJECT let this server handle the bind.
+ */
+int
+passthru_dn2server( PassThruConfig *cfg, char *normdn, PassThruServer **srvrp )
+{
+ PassThruServer *ptsrvr;
+ PassThruSuffix *ptsuffix;
+ int dnlen;
+
+ PASSTHRU_ASSERT( cfg != NULL );
+ PASSTHRU_ASSERT( normdn != NULL );
+ PASSTHRU_ASSERT( srvrp != NULL );
+
+ dnlen = strlen( normdn );
+
+ for ( ptsrvr = cfg->ptconfig_serverlist; ptsrvr != NULL;
+ ptsrvr = ptsrvr->ptsrvr_next ) {
+ for ( ptsuffix = ptsrvr->ptsrvr_suffixes; ptsuffix != NULL;
+ ptsuffix = ptsuffix->ptsuffix_next ) {
+ if ( dn_is_underneath_suffix( ptsuffix, normdn, dnlen )) {
+ *srvrp = ptsrvr;
+ return( LDAP_SUCCESS ); /* got it */
+ }
+ }
+ }
+
+ *srvrp = NULL;
+ return( LDAP_NO_SUCH_OBJECT ); /* no match */
+}
+
+
+/*
+ * Get an LDAP session handle for communicating with srvr.
+ *
+ * Returns an LDAP eror code, typically:
+ * LDAP_SUCCESS
+ * other
+ */
+int
+passthru_get_connection( PassThruServer *srvr, LDAP **ldp )
+{
+ int rc;
+ PassThruConnection *conn, *connprev;
+ LDAP *ld;
+
+ PASSTHRU_ASSERT( srvr != NULL );
+ PASSTHRU_ASSERT( ldp != NULL );
+
+ check_for_stale_connections( srvr );
+
+ slapi_lock_mutex( srvr->ptsrvr_connlist_mutex );
+ rc = LDAP_SUCCESS; /* optimistic */
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "=> passthru_get_connection server %s:%d conns: %d maxconns: %d\n",
+ srvr->ptsrvr_hostname, srvr->ptsrvr_port, srvr->ptsrvr_connlist_count,
+ srvr->ptsrvr_maxconnections );
+
+ for ( ;; ) {
+ /*
+ * look for an available, already open connection
+ */
+ connprev = NULL;
+ for ( conn = srvr->ptsrvr_connlist; conn != NULL;
+ conn = conn->ptconn_next ) {
+ if ( conn->ptconn_status == PASSTHRU_CONNSTATUS_OK
+ && conn->ptconn_usecount < srvr->ptsrvr_maxconcurrency ) {
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= passthru_get_connection server found "
+ "conn 0x%x to use)\n", conn->ptconn_ld );
+#endif
+ goto unlock_and_return; /* found one */
+ }
+ connprev = conn;
+ }
+
+ if ( srvr->ptsrvr_connlist_count < srvr->ptsrvr_maxconnections ) {
+ /*
+ * we have not exceeded the maximum number of connections allowed,
+ * so we initialize a new one and add it to the end of our list.
+ */
+ if (( ld = slapi_ldap_init( srvr->ptsrvr_hostname,
+ srvr->ptsrvr_port, srvr->ptsrvr_secure, 1 )) == NULL ) {
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= passthru_get_connection slapi_ldap_init failed\n" );
+#endif
+ rc = LDAP_LOCAL_ERROR;
+ goto unlock_and_return;
+ }
+
+ /*
+ * set protocol version to correct value for this server
+ */
+ if ( ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION,
+ &srvr->ptsrvr_ldapversion ) != 0 ) {
+ slapi_ldap_unbind( ld );
+ }
+
+ conn = (PassThruConnection *)slapi_ch_malloc(
+ sizeof( PassThruConnection ));
+ conn->ptconn_ld = ld;
+ conn->ptconn_status = PASSTHRU_CONNSTATUS_OK;
+ time( &conn->ptconn_opentime );
+ conn->ptconn_ldapversion = srvr->ptsrvr_ldapversion;
+ conn->ptconn_usecount = 0;
+ conn->ptconn_next = NULL;
+ conn->ptconn_prev = connprev;
+ if ( connprev == NULL ) {
+ srvr->ptsrvr_connlist = conn;
+ conn->ptconn_prev = NULL;
+ } else {
+ connprev->ptconn_next = conn;
+ conn->ptconn_prev = connprev;
+ }
+
+ ++srvr->ptsrvr_connlist_count;
+
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= passthru_get_connection added new conn 0x%x, "
+ "conn count now %d\n", ld, srvr->ptsrvr_connlist_count );
+#endif
+ goto unlock_and_return; /* got a new one */
+ }
+
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "... passthru_get_connection waiting for conn to free up\n" );
+#endif
+ slapi_wait_condvar( srvr->ptsrvr_connlist_cv, NULL );
+
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "... passthru_get_connection awake again\n" );
+#endif
+ }
+
+unlock_and_return:
+ if ( conn != NULL ) {
+ ++conn->ptconn_usecount;
+ *ldp = conn->ptconn_ld;
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= passthru_get_connection ld=0x%x (concurrency now %d)\n",
+ *ldp, conn->ptconn_usecount );
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= passthru_get_connection error %d\n", rc );
+ }
+
+ slapi_unlock_mutex( srvr->ptsrvr_connlist_mutex );
+ return( rc );
+}
+
+
+/*
+ * Mark the connection ld is associated with as free to be used again.
+ * If dispose is non-zero, we mark the connection as "bad" and dispose
+ * of it and its ld once the use count becomes zero.
+ */
+void
+passthru_release_connection( PassThruServer *srvr, LDAP *ld, int dispose )
+{
+ PassThruConnection *conn, *connprev;
+
+ PASSTHRU_ASSERT( srvr != NULL );
+ PASSTHRU_ASSERT( ld != NULL );
+
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "=> passthru_release_connection ld=0x%x%s\n", ld,
+ dispose ? " (disposing)" : "" );
+#endif
+
+ slapi_lock_mutex( srvr->ptsrvr_connlist_mutex );
+
+ /*
+ * find the connection structure this ld is part of
+ */
+ connprev = NULL;
+ for ( conn = srvr->ptsrvr_connlist; conn != NULL;
+ conn = conn->ptconn_next ) {
+ if ( ld == conn->ptconn_ld ) {
+ break;
+ }
+ connprev = conn;
+ }
+
+ if ( conn == NULL ) { /* ld not found -- unexpected */
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "=> passthru_release_connection ld=0x%x not found\n", ld );
+ } else {
+ PASSTHRU_ASSERT( conn->ptconn_usecount > 0 );
+ --conn->ptconn_usecount;
+ if ( dispose ) {
+ conn->ptconn_status = PASSTHRU_CONNSTATUS_DOWN;
+ }
+
+ if ( conn->ptconn_status != PASSTHRU_CONNSTATUS_OK
+ && conn->ptconn_usecount == 0 ) {
+ /*
+ * remove from server's connection list
+ */
+ if ( connprev == NULL ) {
+ srvr->ptsrvr_connlist = conn->ptconn_next;
+ } else {
+ connprev->ptconn_next = conn->ptconn_next;
+ }
+ --srvr->ptsrvr_connlist_count;
+
+ /*
+ * close connection and free memory
+ */
+ close_and_dispose_connection( conn );
+ }
+ }
+
+ /*
+ * wake up a thread that is waiting for a connection (there may not be
+ * any but the slapi_notify_condvar() call should be cheap in any event).
+ */
+ slapi_notify_condvar( srvr->ptsrvr_connlist_cv, 0 );
+
+ /*
+ * unlock and return
+ */
+ slapi_unlock_mutex( srvr->ptsrvr_connlist_mutex );
+}
+
+
+/*
+ * close all open connections in preparation for server shutdown, etc.
+ */
+void
+passthru_close_all_connections( PassThruConfig *cfg )
+{
+ PassThruServer *srvr;
+ PassThruConnection *conn, *nextconn;
+
+ PASSTHRU_ASSERT( cfg != NULL );
+
+ for ( srvr = cfg->ptconfig_serverlist; srvr != NULL;
+ srvr = srvr->ptsrvr_next ) {
+ for ( conn = srvr->ptsrvr_connlist; conn != NULL; conn = nextconn ) {
+ nextconn = conn->ptconn_next;
+ close_and_dispose_connection( conn );
+ }
+ }
+}
+
+
+/*
+ * return non-zero value if normdn falls underneath a suffix
+ */
+static int
+dn_is_underneath_suffix( PassThruSuffix *suffix, char *normdn, int dnlen )
+{
+ PASSTHRU_ASSERT( suffix != NULL );
+ PASSTHRU_ASSERT( normdn != NULL );
+ PASSTHRU_ASSERT( dnlen >= 0 );
+
+ return ( suffix->ptsuffix_len <= dnlen &&
+ slapi_UTF8CASECMP( suffix->ptsuffix_normsuffix,
+ normdn + ( dnlen - suffix->ptsuffix_len )) == 0 );
+}
+
+
+/*
+ * Unbind from server and dispose of a connection.
+ */
+static void
+close_and_dispose_connection( PassThruConnection *conn )
+{
+ PASSTHRU_ASSERT( conn != NULL );
+ PASSTHRU_ASSERT( conn->ptconn_ld != NULL );
+
+ slapi_ldap_unbind( conn->ptconn_ld );
+ conn->ptconn_ld = NULL;
+ slapi_ch_free( (void **)&conn );
+}
+
+
+/*
+ * Close (or mark to be closed) any connections for this srvr that have
+ * exceeded the maximum connection lifetime.
+ */
+static void
+check_for_stale_connections( PassThruServer *srvr )
+{
+ PassThruConnection *conn, *prevconn, *nextconn;
+ time_t curtime;
+
+ PASSTHRU_ASSERT( srvr != NULL );
+
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "check_for_stale_connections: server %s (lifetime %d secs)\n",
+ srvr->ptsrvr_url, srvr->ptsrvr_connlifetime );
+#endif
+
+
+ if ( srvr->ptsrvr_connlifetime <= 0 ) {
+ return;
+ }
+
+ time( &curtime );
+
+ slapi_lock_mutex( srvr->ptsrvr_connlist_mutex );
+
+ prevconn = NULL;
+ for ( conn = srvr->ptsrvr_connlist; conn != NULL; conn = nextconn ) {
+ nextconn = conn->ptconn_next;
+
+ if ( curtime - conn->ptconn_opentime > srvr->ptsrvr_connlifetime ) {
+ if ( conn->ptconn_usecount == 0 ) {
+ /*
+ * connection is idle and stale -- remove from server's list
+ */
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "check_for_stale_connections: discarding idle, "
+ "stale connection 0x%x\n", conn->ptconn_ld );
+#endif
+ if ( prevconn == NULL ) {
+ srvr->ptsrvr_connlist = nextconn;
+ } else {
+ prevconn->ptconn_next = nextconn;
+ }
+ --srvr->ptsrvr_connlist_count;
+ close_and_dispose_connection( conn );
+ } else {
+ /*
+ * connection is stale but in use -- mark to be disposed later
+ */
+#ifdef PASSTHRU_VERBOSE_LOGGING
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "check_for_stale_connections: marking connection 0x%x "
+ "stale (use count %d)\n", conn->ptconn_ld,
+ conn->ptconn_usecount );
+#endif
+ conn->ptconn_status = PASSTHRU_CONNSTATUS_STALE;
+ prevconn = conn;
+ }
+ } else {
+ prevconn = conn;
+ }
+ }
+
+ slapi_unlock_mutex( srvr->ptsrvr_connlist_mutex );
+}
diff --git a/ldap/servers/plugins/passthru/ptdebug.c b/ldap/servers/plugins/passthru/ptdebug.c
new file mode 100644
index 00000000..0f01c4a7
--- /dev/null
+++ b/ldap/servers/plugins/passthru/ptdebug.c
@@ -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 **/
+/*
+ * ptdebug.c - debugging-related code for Pass Through Authentication
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "passthru.h"
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
diff --git a/ldap/servers/plugins/passthru/ptdllmain.c b/ldap/servers/plugins/passthru/ptdllmain.c
new file mode 100644
index 00000000..0e9eaccf
--- /dev/null
+++ b/ldap/servers/plugins/passthru/ptdllmain.c
@@ -0,0 +1,131 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "ldap.h"
+#include "lber.h"
+#include "passthru.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
+
+#ifdef LDAP_DEBUG
+#ifndef _WIN32
+#include <stdarg.h>
+#include <stdio.h>
+
+void LDAPDebug( int level, char* fmt, ... )
+{
+ static char debugBuf[1024];
+
+ if (module_ldap_debug && (*module_ldap_debug & level))
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ _snprintf (debugBuf, sizeof(debugBuf), fmt, ap);
+ va_end (ap);
+
+ OutputDebugString (debugBuf);
+ }
+}
+#endif
+#endif
+
+#ifndef _WIN32
+
+/* The 16-bit version of the RTL does not implement perror() */
+
+#include <stdio.h>
+
+void perror( const char *msg )
+{
+ char buf[128];
+ wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ;
+ OutputDebugString( buf );
+}
+
+#endif
diff --git a/ldap/servers/plugins/passthru/ptpreop.c b/ldap/servers/plugins/passthru/ptpreop.c
new file mode 100644
index 00000000..aaad0621
--- /dev/null
+++ b/ldap/servers/plugins/passthru/ptpreop.c
@@ -0,0 +1,252 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * ptpreop.c - bind pre-operation plugin for Pass Through Authentication
+ *
+ */
+
+#include "passthru.h"
+
+static Slapi_PluginDesc pdesc = { "passthruauth", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "pass through authentication plugin" };
+
+/*
+ * function prototypes
+ */
+static int passthru_bindpreop( Slapi_PBlock *pb );
+static int passthru_bindpreop_start( Slapi_PBlock *pb );
+static int passthru_bindpreop_close( Slapi_PBlock *pb );
+
+
+/*
+ * Plugin initialization function (which must be listed in the appropriate
+ * slapd config file).
+ */
+int
+passthruauth_init( Slapi_PBlock *pb )
+{
+ PASSTHRU_ASSERT( pb != NULL );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "=> passthruauth_init\n" );
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *)SLAPI_PLUGIN_VERSION_01 ) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN,
+ (void *)passthru_bindpreop_start ) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN,
+ (void *)passthru_bindpreop ) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *)passthru_bindpreop_close ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "passthruauth_init failed\n" );
+ return( -1 );
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= passthruauth_init succeeded\n" );
+
+ return( 0 );
+}
+
+
+/*
+ * passthru_bindpreop_start() is called before the directory server
+ * is fully up. We parse our configuration and initialize any mutexes, etc.
+ */
+static int
+passthru_bindpreop_start( Slapi_PBlock *pb )
+{
+ int argc, rc;
+ char **argv;
+
+ PASSTHRU_ASSERT( pb != NULL );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "=> passthru_bindpreop_start\n" );
+
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "unable to get arguments\n" );
+ return( -1 );
+ }
+
+ if (( rc = passthru_config( argc, argv )) != LDAP_SUCCESS ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "configuration failed (%s)\n", ldap_err2string( rc ));
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * Called right before the Directory Server shuts down.
+ */
+static int
+passthru_bindpreop_close( Slapi_PBlock *pb )
+{
+ PASSTHRU_ASSERT( pb != NULL );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "=> passthru_bindpreop_close\n" );
+
+ /*
+ * close all our open connections.
+ * XXXmcs: free any memory, mutexes, etc.
+ */
+ passthru_close_all_connections( passthru_get_config() );
+
+ return( 0 );
+}
+
+
+static int
+passthru_bindpreop( Slapi_PBlock *pb )
+{
+ int rc, method;
+ char *normbinddn, *matcheddn;
+ char *libldap_errmsg, *pr_errmsg, *errmsg;
+ PassThruConfig *cfg;
+ PassThruServer *srvr;
+ struct berval *creds, **urls;
+ LDAPControl **reqctrls, **resctrls;
+
+ PASSTHRU_ASSERT( pb != NULL );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "=> passthru_bindpreop\n" );
+
+ /*
+ * retrieve parameters for bind operation
+ */
+ if ( slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_TARGET, &normbinddn ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &creds ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= not handled (unable to retrieve bind parameters)\n" );
+ return( PASSTHRU_OP_NOT_HANDLED );
+ }
+ if ( normbinddn == NULL ) {
+ normbinddn = "";
+ }
+
+ /*
+ * We only handle simple bind requests that include non-NULL binddn and
+ * credentials. Let the Directory Server itself handle everything else.
+ */
+ if ( method != LDAP_AUTH_SIMPLE || *normbinddn == '\0'
+ || creds->bv_len == 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= not handled (not simple bind or NULL dn/credentials)\n" );
+ return( PASSTHRU_OP_NOT_HANDLED );
+ }
+
+ /*
+ * Get pass through authentication configuration.
+ */
+ cfg = passthru_get_config();
+
+ /*
+ * Check to see if the target DN is one we should "pass through" to
+ * another server.
+ */
+ if ( passthru_dn2server( cfg, normbinddn, &srvr ) != LDAP_SUCCESS ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= not handled (not one of our suffixes)\n" );
+ return( PASSTHRU_OP_NOT_HANDLED );
+ }
+
+ /*
+ * We are now committed to handling this bind request.
+ * Chain it off to another server.
+ */
+ matcheddn = errmsg = libldap_errmsg = pr_errmsg = NULL;
+ urls = NULL;
+ resctrls = NULL;
+ if ( slapi_pblock_get( pb, SLAPI_REQCONTROLS, &reqctrls ) != 0 ) {
+ rc = LDAP_OPERATIONS_ERROR;
+ errmsg = "unable to retrieve bind controls";
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM, "%s\n",
+ errmsg );
+ } else {
+ int lderrno;
+
+ if (( rc = passthru_simple_bind_s( pb, srvr, PASSTHRU_CONN_TRIES,
+ normbinddn, creds, reqctrls, &lderrno, &matcheddn,
+ &libldap_errmsg, &urls, &resctrls )) == LDAP_SUCCESS ) {
+ rc = lderrno;
+ errmsg = libldap_errmsg;
+ } else if ( rc != LDAP_USER_CANCELLED ) { /* not abandoned */
+ PRErrorCode prerr = PR_GetError();
+ pr_errmsg = PR_smprintf( "error %d - %s %s ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ rc, ldap_err2string( rc ), srvr->ptsrvr_url,
+ prerr, slapd_pr_strerror(prerr));
+ if ( NULL != pr_errmsg ) {
+ errmsg = pr_errmsg;
+ } else {
+ errmsg = ldap_err2string( rc );
+ }
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+ }
+
+ /*
+ * If bind succeeded, change authentication information associated
+ * with this connection.
+ */
+ if ( rc == LDAP_SUCCESS ) {
+ char *ndn = slapi_ch_strdup( normbinddn );
+ if (slapi_pblock_set(pb, SLAPI_CONN_DN, ndn) != 0 ||
+ slapi_pblock_set(pb, SLAPI_CONN_AUTHMETHOD,
+ SLAPD_AUTH_SIMPLE) != 0) {
+ slapi_ch_free((void **)&ndn);
+ rc = LDAP_OPERATIONS_ERROR;
+ errmsg = "unable to set connection DN or AUTHTYPE";
+ slapi_log_error( SLAPI_LOG_FATAL, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "%s\n", errmsg );
+ }
+ }
+
+ if ( rc != LDAP_USER_CANCELLED ) { /* not abandoned */
+ /*
+ * Send a result to our client.
+ */
+ if ( resctrls != NULL ) {
+ (void)slapi_pblock_set( pb, SLAPI_RESCONTROLS, &resctrls );
+ }
+ slapi_send_ldap_result( pb, rc, matcheddn, errmsg, 0, urls );
+ }
+
+ /*
+ * Clean up -- free allocated memory, etc.
+ */
+ if ( urls != NULL ) {
+ passthru_free_bervals( urls );
+ }
+ if ( libldap_errmsg != NULL ) {
+ ldap_memfree( errmsg );
+ }
+ if ( pr_errmsg != NULL ) {
+ PR_smprintf_free( pr_errmsg );
+ }
+ if ( resctrls != NULL ) {
+ ldap_controls_free( resctrls );
+ }
+ if ( matcheddn != NULL ) {
+ ldap_memfree( matcheddn );
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, PASSTHRU_PLUGIN_SUBSYSTEM,
+ "<= handled (error %d - %s)\n", rc, ldap_err2string( rc ));
+
+ return( PASSTHRU_OP_HANDLED );
+}
diff --git a/ldap/servers/plugins/passthru/ptutil.c b/ldap/servers/plugins/passthru/ptutil.c
new file mode 100644
index 00000000..4a1b307b
--- /dev/null
+++ b/ldap/servers/plugins/passthru/ptutil.c
@@ -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 **/
+/*
+ * ptutil.c - utility functions for Pass Through Authentication
+ *
+ */
+
+#include "passthru.h"
+
+
+/*
+ * Convert a char * array into a struct berval * array.
+ * Always succeeds.
+ */
+struct berval **
+passthru_strs2bervals( char **ss )
+{
+ int i;
+ struct berval **bvs;
+
+ if ( ss == NULL || ss[0] == NULL ) {
+ return( NULL );
+ }
+
+ for ( i = 0; ss[i] != NULL; ++i ) {
+ ;
+ }
+
+ bvs = (struct berval **)slapi_ch_calloc( i + 1, sizeof( struct berval * ));
+ for ( i = 0; ss[i] != NULL; ++i ) {
+ bvs[i] = (struct berval *)slapi_ch_malloc( sizeof( struct berval ));
+ bvs[i]->bv_val = slapi_ch_strdup( ss[i] );
+ bvs[i]->bv_len = strlen( ss[i] );
+ }
+
+ return( bvs );
+}
+
+
+/*
+ * Convert a struct berval * array into a char * array.
+ * Always succeeds.
+ */
+char **
+passthru_bervals2strs( struct berval **bvs )
+{
+ int i;
+ char **strs;
+
+ if ( bvs == NULL || bvs[0] == NULL ) {
+ return( NULL );
+ }
+
+ for ( i = 0; bvs[i] != NULL; ++i ) {
+ ;
+ }
+
+ strs = (char **)slapi_ch_calloc( i + 1, sizeof( char * ));
+ for ( i = 0; bvs[i] != NULL; ++i ) {
+ strs[i] = slapi_ch_strdup( bvs[i]->bv_val );
+ }
+
+ return( strs );
+}
+
+
+void
+passthru_free_bervals( struct berval **bvs )
+{
+ int i;
+
+ if ( bvs != NULL ) {
+ for ( i = 0; bvs[ i ] != NULL; ++i ) {
+ slapi_ch_free( (void **)&bvs[ i ] );
+ }
+ }
+ slapi_ch_free( (void **)&bvs );
+}
+
+
+char *
+passthru_urlparse_err2string( int err )
+{
+ char *s;
+
+ switch( err ) {
+ case 0:
+ s = "no error";
+ break;
+ case LDAP_URL_ERR_NOTLDAP:
+ s = "missing ldap:// or ldaps://";
+ break;
+ case LDAP_URL_ERR_NODN:
+ s = "missing suffix";
+ break;
+ case LDAP_URL_ERR_BADSCOPE:
+ s = "invalid search scope";
+ break;
+ case LDAP_URL_ERR_MEM:
+ s = "unable to allocate memory";
+ break;
+ case LDAP_URL_ERR_PARAM:
+ s = "bad parameter to an LDAP URL function";
+ break;
+ }
+
+ return( s );
+}
diff --git a/ldap/servers/plugins/presence/Makefile b/ldap/servers/plugins/presence/Makefile
new file mode 100644
index 00000000..9b15bc96
--- /dev/null
+++ b/ldap/servers/plugins/presence/Makefile
@@ -0,0 +1,85 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+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 = $(OBJDIR)/lib/libpresence
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./presence.def
+endif
+
+PRESENCE_OBJS = presence.o
+OBJS = $(addprefix $(OBJDEST)/, $(PRESENCE_OBJS))
+
+PRESENCE_DLL = presence-plugin
+
+INCLUDES += -I../http -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
+EXTRA_LIBS_DEP += $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL)
+EXTRA_LIBS += $(LDAP_COMMON_LIBS)
+PRESENCE_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
+EXTRA_LIBS_DEP += $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS += $(LIBSLAPDLINK) $(NSPRLINK) $(LDAP_SDK_LIBLDAP_DLL)
+EXTRA_LIBS += $(LDAP_COMMON_LIBS)
+LD=ld
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS_DEP += $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+EXTRA_LIBS += $(LDAP_COMMON_LIBS)
+endif
+
+PRESENCE= $(addprefix $(LIBDIR)/, $(PRESENCE_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(PRESENCE)
+
+ifeq ($(ARCH), WINNT)
+$(PRESENCE): $(OBJS) $(PRESENCE_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(PRESENCE_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(PRESENCE): $(OBJS) $(PRESENCE_DLL_OBJ)
+ $(LINK_DLL) $(PRESENCE_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(PRESENCE_DLL_OBJ)
+endif
+ $(RM) $(PRESENCE)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
diff --git a/ldap/servers/plugins/presence/dllmain.c b/ldap/servers/plugins/presence/dllmain.c
new file mode 100644
index 00000000..fabf8677
--- /dev/null
+++ b/ldap/servers/plugins/presence/dllmain.c
@@ -0,0 +1,96 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/presence/images/aim-offline.gif b/ldap/servers/plugins/presence/images/aim-offline.gif
new file mode 100644
index 00000000..7403ea29
--- /dev/null
+++ b/ldap/servers/plugins/presence/images/aim-offline.gif
Binary files differ
diff --git a/ldap/servers/plugins/presence/images/aim-online.gif b/ldap/servers/plugins/presence/images/aim-online.gif
new file mode 100644
index 00000000..d90c2910
--- /dev/null
+++ b/ldap/servers/plugins/presence/images/aim-online.gif
Binary files differ
diff --git a/ldap/servers/plugins/presence/images/icq-disabled.gif b/ldap/servers/plugins/presence/images/icq-disabled.gif
new file mode 100644
index 00000000..78b748cd
--- /dev/null
+++ b/ldap/servers/plugins/presence/images/icq-disabled.gif
Binary files differ
diff --git a/ldap/servers/plugins/presence/images/icq-offline.gif b/ldap/servers/plugins/presence/images/icq-offline.gif
new file mode 100644
index 00000000..40b35c16
--- /dev/null
+++ b/ldap/servers/plugins/presence/images/icq-offline.gif
Binary files differ
diff --git a/ldap/servers/plugins/presence/images/icq-online.gif b/ldap/servers/plugins/presence/images/icq-online.gif
new file mode 100644
index 00000000..bd5452c1
--- /dev/null
+++ b/ldap/servers/plugins/presence/images/icq-online.gif
Binary files differ
diff --git a/ldap/servers/plugins/presence/images/yahoo-offline.gif b/ldap/servers/plugins/presence/images/yahoo-offline.gif
new file mode 100644
index 00000000..315a2261
--- /dev/null
+++ b/ldap/servers/plugins/presence/images/yahoo-offline.gif
Binary files differ
diff --git a/ldap/servers/plugins/presence/images/yahoo-online.gif b/ldap/servers/plugins/presence/images/yahoo-online.gif
new file mode 100644
index 00000000..1c2b16d8
--- /dev/null
+++ b/ldap/servers/plugins/presence/images/yahoo-online.gif
Binary files differ
diff --git a/ldap/servers/plugins/presence/presence.c b/ldap/servers/plugins/presence/presence.c
new file mode 100644
index 00000000..6c75e745
--- /dev/null
+++ b/ldap/servers/plugins/presence/presence.c
@@ -0,0 +1,1204 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/**
+ * IM Presence plug-in
+ */
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include "portable.h"
+#include "nspr.h"
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+#include "dirlite_strings.h"
+#include "dirver.h"
+#include "vattr_spi.h"
+#include "plhash.h"
+#include "ldif.h"
+
+#include "http_client.h"
+
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+/*** from proto-slap.h ***/
+
+int slapd_log_error_proc( char *subsystem, char *fmt, ... );
+
+/*** from ldaplog.h ***/
+
+/* edited ldaplog.h for LDAPDebug()*/
+#ifndef _LDAPLOG_H
+#define _LDAPLOG_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define LDAP_DEBUG_TRACE 0x00001 /* 1 */
+#define LDAP_DEBUG_ANY 0x04000 /* 16384 */
+#define LDAP_DEBUG_PLUGIN 0x10000 /* 65536 */
+
+/* debugging stuff */
+# ifdef _WIN32
+ extern int *module_ldap_debug;
+# define LDAPDebugLevelIsSet( level ) ( *module_ldap_debug & level )
+# else /* _WIN32 */
+ extern int slapd_ldap_debug;
+# define LDAPDebugLevelIsSet( level ) ( slapd_ldap_debug & level )
+# endif /* Win32 */
+
+#define LDAPDebug( level, fmt, arg1, arg2, arg3 ) \
+ { \
+ if ( LDAPDebugLevelIsSet( level )) { \
+ slapd_log_error_proc( NULL, fmt, arg1, arg2, arg3 ); \
+ } \
+ }
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LDAP_H */
+
+#define PRESENCE_PLUGIN_SUBSYSTEM "presence-plugin"
+#define PRESENCE_PLUGIN_VERSION 0x00050050
+
+/**
+ * this may become unnecessary when we are able to get
+ * the plug-in DN dynamically (pete?)
+ */
+#define PRESENCE_DN "cn=Presence,cn=plugins,cn=config" /* temporary */
+
+#define PRESENCE_SUCCESS 0
+#define PRESENCE_FAILURE -1
+
+/**
+ * Presence vendor specific config parameters
+ */
+
+#define NS_IM_ID "nsIM-ID"
+
+#define NS_IM_URL_TEXT "nsIM-URLText"
+#define NS_IM_URL_GRAPHIC "nsIM-URLGraphic"
+
+#define NS_IM_ON_VALUE_MAP_TEXT "nsIM-OnValueMapText"
+#define NS_IM_OFF_VALUE_MAP_TEXT "nsIM-OffValueMapText"
+
+#define NS_IM_ON_VALUE_MAP_GRAPHIC "nsIM-OnValueMapGraphic"
+#define NS_IM_OFF_VALUE_MAP_GRAPHIC "nsIM-OffValueMapGraphic"
+#define NS_IM_DISABLED_VALUE_MAP_GRAPHIC "nsIM-disabledValueMapGraphic"
+
+#define NS_IM_REQUEST_METHOD "nsIM-RequestMethod"
+
+#define NS_IM_URL_TEXT_RETURN_TYPE "nsIM-URLTextReturnType"
+#define NS_IM_URL_GRAPHIC_RETURN_TYPE "nsIM-URLGraphicReturnType"
+
+#define NS_IM_STATUS_TEXT "nsIM-StatusText"
+#define NS_IM_STATUS_GRAPHIC "nsIM-StatusGraphic"
+
+#define PRESENCE_STRING 1
+#define PRESENCE_BINARY 2
+
+#define PRESENCE_TEXT_RETURN_TYPE "TEXT"
+#define PRESENCE_BINARY_RETURN_TYPE "BINARY"
+
+#define PRESENCE_REQUEST_METHOD_GET "GET"
+#define PRESENCE_REQUEST_METHOD_REDIRECT "REDIRECT"
+
+#define PRESENCE_RETURNED_ON_TEXT "ONLINE"
+#define PRESENCE_RETURNED_OFF_TEXT "OFFLINE"
+#define PRESENCE_RETURNED_ERROR_TEXT "ERROR"
+
+static Slapi_PluginDesc pdesc = { "IM Presence",
+ PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT,
+ "presence plugin" };
+
+/**
+ * struct used to pass the argument to PL_Enumerator Callback
+ */
+struct _vattrtypes
+{
+ Slapi_Entry *entry;
+ vattr_type_list_context *context;
+};
+
+/**
+ * This structure holds the mapping between the virtual attributes and
+ * the IM IDs. This information is used to find out whether this plugin
+ * should service the attributes it was asked to. Also, it stores the
+ * syntax of the attribute. 1 is String and 2 is binary.
+ */
+struct _vattrmap {
+ char *imID;
+ int syntax;
+};
+typedef struct _vattrmap _Vmap;
+
+/**
+ * struct to store the config values for each presence vendor
+ */
+struct _defs {
+ char *textURL;
+ char *graphicURL;
+ char *onTextMap;
+ char *offTextMap;
+ Slapi_Attr *onGraphicMap;
+ Slapi_Attr *offGraphicMap;
+ Slapi_Attr *disabledGraphicMap;
+ char *requestMethod;
+ char *textReturnType;
+ char *graphicReturnType;
+};
+typedef struct _defs _ConfigEntry;
+
+static vattr_sp_handle *_VattrHandle = NULL;
+static void *_PluginID = NULL;
+static void *_PluginDN = NULL;
+static PLHashTable *_IdVattrMapTable = NULL;
+static PLHashTable *_IdConfigMapTable = NULL;
+static void **_HttpAPI = NULL;
+
+/**
+ *
+ * Presence plug-in management functions
+ *
+ */
+int presence_init(Slapi_PBlock *pb);
+int presence_start(Slapi_PBlock *pb);
+int presence_close(Slapi_PBlock *pb);
+
+/**
+ *
+ * Vattr operation callbacks functions
+ *
+ */
+static int presence_vattr_get(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *free_flags, void *hint);
+static int presence_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result, int flags, void *hint);
+static int presence_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags);
+
+/**
+ *
+ * Local operation functions
+ *
+ */
+static int loadPluginConfig();
+static int parseConfigEntry(Slapi_Entry *e);
+static int imIDExists(Slapi_Entry *e, char *type, char **value, _Vmap **map, _ConfigEntry **entry);
+static int makeHttpRequest(char *id, _Vmap *map, _ConfigEntry *info, char **buf, int *size);
+static char * replaceIdWithValue(char *str, char *id, char *value);
+static int setIMStatus(char *id, _Vmap *map, _ConfigEntry *info, char *returnedBUF, int size, Slapi_ValueSet **results);
+static int setTypes(PLHashEntry *he, PRIntn i, void *arg);
+
+static void deleteMapTables();
+static PRIntn destroyHashEntry(PLHashEntry *he, PRIntn index, void *arg);
+static void logGraphicAttributeValue( Slapi_Attr *attr, const char *attrname );
+static void toLowerCase(char* str);
+
+/**
+ * utility function
+ */
+void printMapTable();
+PRIntn printIdVattrMapTable(PLHashEntry *he, PRIntn i, void *arg);
+PRIntn printIdConfigMapTable(PLHashEntry *he, PRIntn i, void *arg);
+
+/**
+ * set the debug level
+ */
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+/**
+ *
+ * Get the presence plug-in version
+ *
+ */
+int presence_version()
+{
+ return PRESENCE_PLUGIN_VERSION;
+}
+
+/**
+ * Plugin identity mgmt
+ */
+void setPluginID(void * pluginID)
+{
+ _PluginID=pluginID;
+}
+
+void * getPluginID()
+{
+ return _PluginID;
+}
+
+void setPluginDN(void *pluginDN)
+{
+ _PluginDN = pluginDN;
+}
+
+void * getPluginDN()
+{
+ return _PluginDN;
+}
+
+/*
+ presence_init
+ -------------
+ adds our callbacks to the list
+*/
+int presence_init( Slapi_PBlock *pb )
+{
+ int status = PRESENCE_SUCCESS;
+ char * plugin_identity=NULL;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> presence_init -- BEGIN\n",0,0,0);
+
+ /**
+ * Store the plugin identity for later use.
+ * Used for internal operations
+ */
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
+ PR_ASSERT (plugin_identity);
+ setPluginID(plugin_identity);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) presence_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) presence_close ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, PRESENCE_PLUGIN_SUBSYSTEM,
+ "presence_init: failed to register plugin\n" );
+ status = PRESENCE_FAILURE;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- presence_init -- END\n",0,0,0);
+ return status;
+}
+
+/*
+ presence_start
+ --------------
+ This function registers the computed attribute evaluator
+ and loads the configuration parameters in the local cache.
+ It is called after presence_init.
+*/
+int presence_start( Slapi_PBlock *pb )
+{
+ char * plugindn = NULL;
+ char * httpRootDir = NULL;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> presence_start -- begin\n",0,0,0);
+
+ if(slapi_apib_get_interface(HTTP_v1_0_GUID, &_HttpAPI))
+ {
+ /**
+ * error cannot proceeed
+ */
+ return PRESENCE_FAILURE;
+ }
+
+ /**
+ * register our vattr callbacks
+ */
+ if (slapi_vattrspi_register((vattr_sp_handle **)&_VattrHandle,
+ presence_vattr_get,
+ presence_vattr_compare,
+ presence_vattr_types) != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, PRESENCE_PLUGIN_SUBSYSTEM,
+ "presence_start: cannot register as service provider\n" );
+ return PRESENCE_FAILURE;
+ }
+
+ /**
+ * Get the plug-in target dn from the system
+ * and store it for future use. This should avoid
+ * hardcoding of DN's in the code.
+ */
+ slapi_pblock_get(pb, SLAPI_TARGET_DN, &plugindn);
+ if (plugindn == NULL || strlen(plugindn) == 0)
+ {
+ /**
+ * This is not required as the above statement
+ * should work and give you a valid DN for this
+ * plugin. ??? remove it later
+ */
+ plugindn = PRESENCE_DN;
+ }
+ setPluginDN(plugindn);
+
+ /**
+ * Load the config info for our plug-in in memory
+ * In the 6.0 release this information will be stored
+ * statically and if any change is done to this info a server
+ * restart is necessary :-(. Probably if time permits then
+ * state change plug-in would be used to notify the state
+ * change. We also register the virtual attributes we are
+ * interested in here.
+ */
+ if (loadPluginConfig() != PRESENCE_SUCCESS)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, PRESENCE_PLUGIN_SUBSYSTEM,
+ "presence_start: unable to load plug-in configuration\n" );
+ return PRESENCE_FAILURE;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "presence: ready for service\n",0,0,0);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- presence_start -- end\n",0,0,0);
+
+ return PRESENCE_SUCCESS;
+}
+
+/*
+ presence_close
+ --------------
+ closes down the cache
+*/
+int presence_close( Slapi_PBlock *pb )
+{
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> presence_close\n",0,0,0);
+
+ deleteMapTables();
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- presence_close\n",0,0,0);
+
+ return PRESENCE_SUCCESS;
+}
+
+static int presence_vattr_get(vattr_sp_handle *handle,
+ vattr_context *c,
+ Slapi_Entry *e,
+ char *type,
+ Slapi_ValueSet** results,
+ int *type_name_disposition,
+ char** actual_type_name,
+ int flags,
+ int *free_flags,
+ void *hint)
+{
+
+ int status = PRESENCE_SUCCESS;
+ char *id = NULL;
+ char *returnedBUF = NULL;
+ int size = 0;
+ _Vmap *map = NULL;
+ _ConfigEntry *info = NULL;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> presence_vattr_get \n",0,0,0);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Type=[%s] \n",type,0,0);
+
+ if (imIDExists(e, type, &id, &map, &info) != PRESENCE_SUCCESS)
+ {
+ /**
+ * we didn't find any valid matching nsimid in this
+ * entry so since we cannot process a request without
+ * a valid nsimid we just return.
+ */
+ status = PRESENCE_FAILURE;
+ goto cleanup;
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> ID=[%s] \n",id,0,0);
+
+ /**
+ * Now since we got a valid id we do a quick schema check
+ * if schema checking is on to make sure that there is no
+ * schema violation ?
+ */
+ /* do_schema_check() */
+
+ /**
+ * At this stage we have a valid attribute and we have to
+ * get its value from the IM Server. so make an Http request
+ * depending on whether it is a request for Text or Graphic
+ */
+
+ status = makeHttpRequest(id, map, info, &returnedBUF, &size);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> size=[%d] \n",size,0,0);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> buffer=[%s]\n",(returnedBUF) ? returnedBUF : "NULL",0,0);
+
+
+ if(status == PRESENCE_SUCCESS)
+ {
+ status = setIMStatus(id, map, info, returnedBUF, size, results);
+ }
+ else
+ {
+ /**
+ * Report all HTTP failures as a single predefined value of the
+ * attribute
+ */
+ Slapi_Value *value =
+ slapi_value_new_string(PRESENCE_RETURNED_ERROR_TEXT);
+ if (!*results) {
+ *results = slapi_valueset_new();
+ }
+ slapi_valueset_add_value(*results, value);
+ slapi_value_free(&value); /* slapi_valueset_add_value copies value */
+ /**
+ * It's a success only in the sense that we are returning a value
+ */
+ status = PRESENCE_SUCCESS;
+ }
+ if(status == PRESENCE_SUCCESS)
+ {
+ *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
+ *actual_type_name = slapi_ch_strdup(type);
+ *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ }
+
+cleanup:
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Processed ID=[%s] \n",id,0,0);
+ if (id != NULL ) {
+ slapi_ch_free((void **)&id);
+ }
+ if (returnedBUF != NULL ) {
+ PR_Free(returnedBUF);
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- presence_vattr_get \n",0,0,0);
+ return status;
+}
+
+
+static int presence_vattr_compare(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result, int flags, void *hint)
+{
+ int status = PRESENCE_SUCCESS;
+ /**
+ * not yet implemented ???
+ */
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> presence_vattr_compare \n",0,0,0);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- presence_vattr_compare \n",0,0,0);
+
+ return status;
+}
+
+static int presence_vattr_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags)
+{
+ int status = PRESENCE_SUCCESS;
+ struct _vattrtypes args;
+ args.entry = e;
+ args.context = type_context;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> presence_vattr_types\n",0,0,0);
+
+ PL_HashTableEnumerateEntries(_IdVattrMapTable, setTypes, &args);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- presence_vattr_types\n",0,0,0);
+ return status;
+}
+
+static int loadPluginConfig()
+{
+ int status = PRESENCE_SUCCESS;
+ int result;
+ int i;
+ Slapi_PBlock *search_pb;
+ Slapi_Entry **entries = NULL;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> loadPluginConfig\n",0,0,0);
+
+ search_pb = slapi_pblock_new();
+
+ slapi_search_internal_set_pb(search_pb, PRESENCE_DN, LDAP_SCOPE_ONELEVEL,
+ "objectclass=*", NULL, 0, NULL, NULL, getPluginID(), 0);
+ slapi_search_internal_pb(search_pb);
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &result);
+
+ if (status != PRESENCE_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, PRESENCE_PLUGIN_SUBSYSTEM,
+ "Error getting level1 presence configurations<%s>\n", getPluginDN());
+ status = PRESENCE_FAILURE;
+ goto cleanup;
+ }
+
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || entries[0] == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, PRESENCE_PLUGIN_SUBSYSTEM,
+ "No entries found for <%s>\n", getPluginDN());
+
+ status = PRESENCE_FAILURE;
+ goto cleanup;
+ }
+
+ _IdVattrMapTable = PL_NewHashTable( 0,
+ PL_HashString,
+ PL_CompareStrings,
+ PL_CompareValues,
+ NULL,
+ NULL
+ );
+
+ _IdConfigMapTable = PL_NewHashTable(0,
+ PL_HashString,
+ PL_CompareStrings,
+ PL_CompareValues,
+ NULL,
+ NULL
+ );
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> parseConfigEntry \n",0,0,0);
+
+ for (i = 0; (entries[i] != NULL); i++)
+ {
+ status = parseConfigEntry(entries[i]);
+ if (status != PRESENCE_SUCCESS)
+ {
+ deleteMapTables();
+ goto cleanup;
+ }
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- parseConfigEntry \n",0,0,0);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- loadPluginConfig\n",0,0,0);
+
+cleanup:
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+ return status;
+}
+
+static int parseConfigEntry(Slapi_Entry *e)
+{
+ char *key = NULL;
+ char *value = NULL;
+ _ConfigEntry *entry = NULL;
+ _Vmap *map = NULL;
+ Slapi_Attr *attr = NULL;
+
+ key = slapi_entry_attr_get_charptr(e, NS_IM_ID);
+ if (!key) {
+ /**
+ * IM Id not defined in the config, unfortunately
+ * cannot do anything without it so better not to
+ * load the plug-in.
+ */
+ return PRESENCE_FAILURE;
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> key [%s] \n",key,0,0);
+ /**
+ * Now create the config entry which will hold all the
+ * attributes of a presence vendor
+ */
+ entry = (_ConfigEntry*) slapi_ch_calloc(1, sizeof(_ConfigEntry));
+
+ /**
+ * Next 2 are the virtual attributes for which this plug-in
+ * is responsible. Register them with the vattr system so
+ * that the system can call us whenever their
+ * values are requested. Also update these entries in the
+ * map table for later access.
+ */
+ value = slapi_entry_attr_get_charptr(e, NS_IM_STATUS_TEXT);
+ if (value) {
+ slapi_vattrspi_regattr(_VattrHandle, value, "", NULL);
+ map = (_Vmap*) slapi_ch_calloc(1, sizeof(_Vmap));
+ map->imID = key;
+ map->syntax = PRESENCE_STRING;
+ toLowerCase(value);
+ PL_HashTableAdd(_IdVattrMapTable, value, map);
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> nsIMStatusText [%s] \n",value,0,0);
+
+ value = slapi_entry_attr_get_charptr(e, NS_IM_STATUS_GRAPHIC);
+ if (value) {
+ slapi_vattrspi_regattr(_VattrHandle, value, "", NULL);
+ map = (_Vmap*) slapi_ch_calloc(1, sizeof(_Vmap));
+ map->imID = key;
+ map->syntax = PRESENCE_BINARY;
+ toLowerCase(value);
+ PL_HashTableAdd(_IdVattrMapTable, value, map);
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> nsIMStatusGraphic [%s] \n",value,0,0);
+
+ value = slapi_entry_attr_get_charptr(e, NS_IM_URL_TEXT);
+ if (value) {
+ entry->textURL = value;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> nsIMURLText [%s] \n",value,0,0);
+
+ value = slapi_entry_attr_get_charptr(e, NS_IM_URL_GRAPHIC);
+ if (value) {
+ entry->graphicURL = value;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> nsIMStatusGraphic [%s] \n",value,0,0);
+
+ value = slapi_entry_attr_get_charptr(e, NS_IM_ON_VALUE_MAP_TEXT);
+ if (value) {
+ entry->onTextMap = value;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> nsIMOnValueMapText [%s] \n",value,0,0);
+
+ value = slapi_entry_attr_get_charptr(e, NS_IM_OFF_VALUE_MAP_TEXT);
+ if (value) {
+ entry->offTextMap = value;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> nsIMOffValueMapText [%s] \n",value,0,0);
+
+ /**
+ * Next 3 are binary syntax types so needs special handling
+ */
+ slapi_entry_attr_find(e, NS_IM_ON_VALUE_MAP_GRAPHIC, &attr);
+ if (attr) {
+ entry->onGraphicMap = slapi_attr_dup(attr);
+ logGraphicAttributeValue(attr,NS_IM_ON_VALUE_MAP_GRAPHIC);
+ }
+
+ slapi_entry_attr_find(e, NS_IM_OFF_VALUE_MAP_GRAPHIC, &attr);
+ if (attr) {
+ entry->offGraphicMap = slapi_attr_dup(attr);
+ logGraphicAttributeValue(attr,NS_IM_OFF_VALUE_MAP_GRAPHIC);
+ }
+
+ slapi_entry_attr_find(e, NS_IM_DISABLED_VALUE_MAP_GRAPHIC, &attr);
+ if (attr) {
+ entry->disabledGraphicMap = slapi_attr_dup(attr);
+ logGraphicAttributeValue(attr,NS_IM_DISABLED_VALUE_MAP_GRAPHIC);
+ }
+
+ value = slapi_entry_attr_get_charptr(e, NS_IM_REQUEST_METHOD);
+ if (value) {
+ entry->requestMethod = value;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> nsIMRequestMethod [%s] \n",value,0,0);
+
+ value = slapi_entry_attr_get_charptr(e, NS_IM_URL_TEXT_RETURN_TYPE);
+ if (value) {
+ entry->textReturnType = value;
+ }
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> nsIMURLTextReturnType [%s] \n",value,0,0);
+
+ value = slapi_entry_attr_get_charptr(e, NS_IM_URL_GRAPHIC_RETURN_TYPE);
+ if (value) {
+ entry->graphicReturnType = value;
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> nsIMURLGraphicReturnType [%s] \n",value,0,0);
+
+ /**
+ * Finally add the entry to the map table
+ */
+ PL_HashTableAdd(_IdConfigMapTable, key, entry);
+
+ return PRESENCE_SUCCESS;
+}
+
+/**
+ * this function goes thru the valid stored ids
+ * and return the correct one for which we have to
+ * do further processing
+ */
+static int imIDExists(Slapi_Entry *e, char *type, char **value, _Vmap **map, _ConfigEntry **entry)
+{
+ int status = PRESENCE_SUCCESS;
+ char *tValue = NULL;
+ _ConfigEntry *tEntry = NULL;
+ _Vmap *tMap = NULL;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> imIDExists \n",0,0,0);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Type [%s] \n",type,0,0);
+
+ /**
+ * The public function PL_HashTableLookup modifies the
+ * the table while reading. so using this private function
+ * which just does a lookup and doesn't modifies the
+ * hashtable
+ */
+ toLowerCase(type);
+ tMap = PL_HashTableLookupConst(_IdVattrMapTable, type);
+ if (!tMap)
+ {
+ /**
+ * this should not happen but no harm we just return
+ */
+ status = PRESENCE_FAILURE;
+ slapi_log_error(SLAPI_LOG_FATAL, PRESENCE_PLUGIN_SUBSYSTEM,
+ "No hashtable for vattr types\n");
+ goto bail;
+ }
+ /**
+ * We found a matching id in the map table
+ * now see if that id exists in the Slapi_Entry
+ */
+ tValue = slapi_entry_attr_get_charptr(e, tMap->imID);
+ if (!tValue)
+ {
+ /**
+ * we don't do anything here but just return
+ */
+ status = PRESENCE_FAILURE;
+ goto bail;
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Value [%s] \n",tValue,0,0);
+
+ tEntry = PL_HashTableLookupConst(_IdConfigMapTable, tMap->imID);
+ *value = tValue;
+ *entry = tEntry;
+ *map = tMap;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- imIDExists \n",0,0,0);
+
+bail:
+ return status;
+}
+
+static int makeHttpRequest(char *id, _Vmap *map, _ConfigEntry *info, char **BUF, int *size)
+{
+ int status = PRESENCE_SUCCESS;
+ char *buf = NULL;
+ char *url = NULL;
+ char *urltosend = NULL;
+ int bytesRead;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> makeHttpRequest:: \n",0,0,0);
+
+ if (map->syntax == PRESENCE_STRING) {
+ url = info->textURL;
+ } else {
+ url = info->graphicURL;
+ }
+ if (url == NULL) {
+ status = PRESENCE_FAILURE;
+ goto bail;
+ }
+ urltosend = replaceIdWithValue(url, map->imID, id);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> URL [%s] \n",urltosend,0,0);
+ /**
+ * make an actual HTTP call now
+ */
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> RequestMethod [%s] \n", info->requestMethod,0,0);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Syntax [%d] \n", map->syntax,0,0);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> TextReturnType [%s] \n", info->textReturnType,0,0);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> GraphicReturnType [%s] \n", info->graphicReturnType,0,0);
+ if (!strcasecmp(info->requestMethod, PRESENCE_REQUEST_METHOD_GET)) {
+ if (map->syntax == PRESENCE_STRING) {
+ if (!strcasecmp(info->textReturnType, PRESENCE_TEXT_RETURN_TYPE)) {
+ status = http_get_text(_HttpAPI, urltosend, &buf, &bytesRead);
+ } else {
+ status = http_get_binary(_HttpAPI, urltosend, &buf, &bytesRead);
+ }
+ } else {
+ if (!strcasecmp(info->graphicReturnType, PRESENCE_TEXT_RETURN_TYPE)) {
+ status = http_get_text(_HttpAPI, urltosend, &buf, &bytesRead);
+ } else {
+ status = http_get_binary(_HttpAPI, urltosend, &buf, &bytesRead);
+ }
+ }
+ } else if (!strcasecmp(info->requestMethod, PRESENCE_REQUEST_METHOD_REDIRECT)) {
+ status = http_get_redirected_uri(_HttpAPI, urltosend, &buf, &bytesRead);
+ } else {
+ /**
+ * error : unknown method
+ * probably we should check at the time of loading
+ * of the plugin itself that the config values are
+ * properly checked and throw warning/errors in case
+ * of any invalid entry
+ */
+ slapi_log_error(SLAPI_LOG_FATAL, PRESENCE_PLUGIN_SUBSYSTEM,
+ "Unknown request type <%s>\n", info->requestMethod);
+ status = PRESENCE_FAILURE;
+ goto bail;
+ }
+ if (buf && status == PRESENCE_SUCCESS)
+ {
+ *BUF = buf;
+ *size = bytesRead;
+ }
+
+bail:
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- makeHttpRequest:: <%d>\n",status,0,0);
+
+ slapi_ch_free((void**)&urltosend);
+ return status;
+}
+
+/**
+ * This function replaces the occurrence of $ns[<vendor>]imid with its
+ * actual value
+ * e.g.
+ * URL : http://opi.yahoo.com/online?u=$nsyimid
+ * after replacing
+ * newURL : http://opi.yahoo.com/online?u=srajam
+ */
+static char * replaceIdWithValue(char *str, char *id, char *value)
+{
+ int i=0;
+ int k=0;
+ char *newstr = NULL;
+ char c;
+ if (!str || !id || !value)
+ {
+ return NULL;
+ }
+ /* extra space for userids */
+ newstr = (char *)slapi_ch_malloc(strlen(str) + strlen(value));
+ while ((c=str[i]) != '\0')
+ {
+ if (c == '$')
+ {
+ int j = 0;
+ i++; /*skip one char */
+ /**
+ * we found the begining of the string to be
+ * substituted. Now skip the chars we want to replace
+ */
+ while (str[i] != '\0' && id[j] != '\0' &&
+ (toupper(str[i]) == toupper(id[j])))
+ {
+ i++;
+ j++;
+ }
+ j=0;
+ while (value[j] != '\0')
+ {
+ newstr[k++] = value[j++];
+ }
+ }
+ else
+ {
+ newstr[k++]=c;
+ i++;
+ }
+ }
+
+ newstr[k] = '\0';
+ return newstr;
+}
+
+static int setIMStatus(char *id, _Vmap *map, _ConfigEntry *info,
+ char *returnedBUF, int size, Slapi_ValueSet **results)
+{
+ int status = PRESENCE_SUCCESS;
+ char *ontxtmap = NULL;
+ char *offtxtmap = NULL;
+ Slapi_Value *value = NULL;
+ Slapi_Value *value1 = NULL;
+ Slapi_Value *value2 = NULL;
+ struct berval bval;
+ Slapi_Attr *attr = NULL;
+ const struct berval *tmp = NULL;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> setIMStatus \n", 0,0,0);
+ /**
+ * we got some data back so lets try to map it to
+ * the existing set of on/off data
+ *
+ * first we need to take a look at the
+ * returned type and depending upon that parse
+ * the data
+ */
+
+ if (map->syntax == PRESENCE_STRING) {
+ /**
+ * we had send a request for text
+ * but chances are we might end up
+ * getting an image back. So we need
+ * to compare it to existing set of
+ * images that we have in store ???
+ */
+ if (!strcasecmp(info->textReturnType, PRESENCE_TEXT_RETURN_TYPE)) {
+ /* return value is in text format */
+ ontxtmap = replaceIdWithValue(info->onTextMap, map->imID, id);
+ offtxtmap = replaceIdWithValue(info->offTextMap, map->imID, id);
+ if (!strcasecmp(ontxtmap, returnedBUF)) {
+ /**
+ * set the on value
+ */
+ value = slapi_value_new_string(PRESENCE_RETURNED_ON_TEXT);
+ } else if (!strcasecmp(offtxtmap, returnedBUF)) {
+ /**
+ * set the off value
+ */
+ value = slapi_value_new_string(PRESENCE_RETURNED_OFF_TEXT);
+ } else {
+ value = slapi_value_new_string(PRESENCE_RETURNED_ERROR_TEXT);
+ }
+ } else if (!strcasecmp(info->textReturnType, PRESENCE_BINARY_RETURN_TYPE)) {
+ /**
+ * call binary compare method
+ */
+ bval.bv_len = size;
+ bval.bv_val = returnedBUF;
+ value1 = slapi_value_new_berval(&bval);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> returned size [%d] \n", bval.bv_len,0,0);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> returned value [%s] \n", bval.bv_val,0,0);
+
+ attr = info->onGraphicMap;
+ if (attr) {
+ slapi_attr_first_value(attr, &value2);
+ tmp = slapi_value_get_berval(value2);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Stored size [%d] \n", tmp->bv_len,0,0);
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> Stored value [%s] \n", tmp->bv_val,0,0);
+ if (!slapi_value_compare(attr, value1, value2)) {
+ value = slapi_value_new_string(PRESENCE_RETURNED_ON_TEXT);
+ }
+ }
+ if (!value) {
+ attr = info->offGraphicMap;
+ if (attr) {
+ slapi_attr_first_value(attr, &value2);
+ if (!slapi_value_compare(attr, value1, value2)) {
+ value = slapi_value_new_string(PRESENCE_RETURNED_OFF_TEXT);
+ }
+ }
+ }
+ if (!value) {
+ attr = info->disabledGraphicMap;
+ if (attr) {
+ slapi_attr_first_value(attr, &value2);
+ if (!slapi_value_compare(attr, value1, value2)) {
+ value = slapi_value_new_string(PRESENCE_RETURNED_OFF_TEXT);
+ }
+ }
+ }
+ if (!value) {
+ /* some error */
+ value = slapi_value_new_string(PRESENCE_RETURNED_ERROR_TEXT);
+ }
+ } else {
+ /**
+ * set the error condition
+ */
+ value = slapi_value_new_string(PRESENCE_RETURNED_ERROR_TEXT);
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> value [%s] \n", returnedBUF,0,0);
+ } else {
+ /**
+ * we had send a request for image
+ * so whatever we get back we just
+ * return instead of analyzing it
+ */
+ if (!strcasecmp(info->graphicReturnType, PRESENCE_TEXT_RETURN_TYPE)) {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> value [%s] \n", returnedBUF,0,0);
+ if (!strcasecmp(info->requestMethod, PRESENCE_REQUEST_METHOD_REDIRECT)) {
+ /**
+ * a redirect case in which we should probably have a
+ * gif in store so return that value
+ *
+ * for now
+ */
+
+ ontxtmap = replaceIdWithValue(info->onTextMap, map->imID, id);
+ offtxtmap = replaceIdWithValue(info->offTextMap, map->imID, id);
+ if (!strcasecmp(ontxtmap, returnedBUF)) {
+ /**
+ * set the on value
+ */
+ attr = info->onGraphicMap;
+ } else if (!strcasecmp(offtxtmap, returnedBUF)) {
+ /**
+ * set the off value
+ */
+ attr = info->offGraphicMap;
+ } else {
+ attr = info->disabledGraphicMap;
+ }
+ if (attr) {
+ slapi_attr_first_value(attr, &value);
+ }
+ } else {
+ /**
+ * for now just set the returned value
+ * should not happen in our case
+ * ERROR
+ */
+ }
+ } else {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> value [%s] \n", returnedBUF,0,0);
+ bval.bv_len = size;
+ bval.bv_val = returnedBUF;
+ value = slapi_value_new_berval(&bval);
+ }
+ }
+ if (!*results) {
+ *results = slapi_valueset_new();
+ }
+
+ slapi_valueset_add_value(*results, value);
+
+ if (ontxtmap) {
+ slapi_ch_free((void **)&ontxtmap);
+ }
+ if (offtxtmap) {
+ slapi_ch_free((void **)&offtxtmap);
+ }
+ if (value && map->syntax == PRESENCE_STRING) {
+ slapi_value_free(&value);
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- setIMStatus \n", 0,0,0);
+
+ return status;
+}
+
+static int setTypes(PLHashEntry *he, PRIntn i, void *arg)
+{
+ int status;
+ int props = SLAPI_ATTR_FLAG_OPATTR;
+ Slapi_Attr *attr = NULL;
+ Slapi_ValueSet *results = NULL;
+ int type_name_disposition = 0;
+ char *actual_type_name = 0;
+ int free_flags = 0;
+
+ struct _vattrtypes *args = arg;
+ char *type = (char *)he->key;
+ _Vmap *map = (_Vmap *)he->value;
+ char *id = map->imID;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "--> setTypes \n", 0,0,0);
+
+ status = slapi_vattr_values_get_sp(NULL, args->entry, id, &results, &type_name_disposition, &actual_type_name, 0, &free_flags);
+ if(status == PRESENCE_SUCCESS)
+ {
+ /* entry contains this attr */
+ vattr_type_thang thang = {0};
+
+ thang.type_name = type;
+ thang.type_flags = props;
+
+ slapi_vattrspi_add_type(args->context,&thang,0);
+
+ slapi_vattr_values_free(&results, &actual_type_name, free_flags);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> ID [%s] Type[%s]\n", actual_type_name,type,0);
+ }
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<-- setTypes \n", 0,0,0);
+
+ return HT_ENUMERATE_NEXT;
+}
+
+
+static void
+logGraphicAttributeValue( Slapi_Attr *attr, const char *attrname )
+{
+ Slapi_Value *val = NULL;
+ const struct berval *v = NULL;
+
+ if ( LDAPDebugLevelIsSet( LDAP_DEBUG_PLUGIN )) {
+ slapi_attr_first_value(attr, &val);
+ v = slapi_value_get_berval(val);
+ if (v) {
+ char *ldifvalue;
+ size_t attrnamelen = strlen( attrname );
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> %s size [%d] \n",
+ attrname,v->bv_len,0);
+
+ ldifvalue = ldif_type_and_value_with_options(
+ (char *)attrname, /* XXX: had to cast away const */
+ v->bv_val, v->bv_len, 0 );
+ if ( NULL != ldifvalue ) {
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "----------> %s value [\n%s]\n",
+ attrname,ldifvalue,0);
+ slapi_ch_free_string( &ldifvalue );
+ }
+ }
+ }
+}
+
+
+static void deleteMapTables()
+{
+ PL_HashTableEnumerateEntries(_IdConfigMapTable, destroyHashEntry, 0);
+ if (_IdConfigMapTable)
+ {
+ PL_HashTableDestroy(_IdConfigMapTable);
+ }
+
+ PL_HashTableEnumerateEntries(_IdVattrMapTable, destroyHashEntry, 0);
+ if (_IdVattrMapTable)
+ {
+ PL_HashTableDestroy(_IdVattrMapTable);
+ }
+ return;
+}
+
+static PRIntn destroyHashEntry(PLHashEntry *he, PRIntn index, void *arg)
+{
+ void *value = NULL;
+ if (he == NULL)
+ {
+ return HT_ENUMERATE_NEXT;
+ }
+ value = he->value;
+ if (value)
+ {
+ slapi_ch_free(&value);
+ }
+ return HT_ENUMERATE_REMOVE;
+}
+
+static void toLowerCase(char* str)
+{
+ if (str) {
+ char* lstr = str;
+ for(; (*lstr != '\0'); ++lstr) {
+ *lstr = tolower(*lstr);
+ }
+ }
+}
+
+
+/**
+ * utility function to print the array
+ */
+void printMapTable()
+{
+ PL_HashTableEnumerateEntries(_IdVattrMapTable, printIdVattrMapTable, 0);
+ PL_HashTableEnumerateEntries(_IdConfigMapTable, printIdConfigMapTable, 0);
+}
+
+PRIntn printIdVattrMapTable(PLHashEntry *he, PRIntn i, void *arg)
+{
+ char *key = (char *)he->key;
+ _Vmap *map = (_Vmap *)he->value;
+ printf("<---- Key -------> %s\n", key);
+ printf("<---- ImId ------> %s\n", map->imID);
+ printf("<---- syntax ----> %d\n", map->syntax);
+ return HT_ENUMERATE_NEXT;
+}
+
+PRIntn printIdConfigMapTable(PLHashEntry *he, PRIntn i, void *arg)
+{
+ char *key = (char *)he->key;
+ _ConfigEntry *value = (_ConfigEntry *)he->value;
+ printf("<- Key ---------------------> %s\n", key);
+ printf("<---- text_url -------------> %s\n", value->textURL);
+ printf("<---- graphic_url ----------> %s\n", value->graphicURL);
+ printf("<---- on_text_map ----------> %s\n", value->onTextMap);
+ printf("<---- off_text_map ---------> %s\n", value->offTextMap);
+ printf("<---- request_method -------> %s\n", value->requestMethod);
+ printf("<---- text_return_type -----> %s\n", value->textReturnType);
+ printf("<---- graphic_return_type --> %s\n", value->graphicReturnType);
+
+ return HT_ENUMERATE_NEXT;
+}
+
diff --git a/ldap/servers/plugins/presence/presence.def b/ldap/servers/plugins/presence/presence.def
new file mode 100644
index 00000000..4d083d26
--- /dev/null
+++ b/ldap/servers/plugins/presence/presence.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
+;
+DESCRIPTION 'Netscape Directory Server 6.2.1 Presence Plugin'
+EXPORTS
+ presence_init @2
+ plugin_init_debug_level @3
+ presence_version @4
diff --git a/ldap/servers/plugins/presence/presence.ldif b/ldap/servers/plugins/presence/presence.ldif
new file mode 100644
index 00000000..67bb977b
--- /dev/null
+++ b/ldap/servers/plugins/presence/presence.ldif
@@ -0,0 +1,44 @@
+dn:cn=ICQ Presence,cn=Presence,cn=plugins,cn=config
+changeType:modify
+replace:nsim-onvaluemapgraphic
+nsim-onvaluemapgraphic: D:/dev/ds60cvs/ldapserver/ldap/servers/plugins/presence/icq-online.gif
+
+dn:cn=ICQ Presence,cn=Presence,cn=plugins,cn=config
+changeType:modify
+replace:nsim-offvaluemapgraphic
+nsim-offvaluemapgraphic: D:/dev/ds60cvs/ldapserver/ldap/servers/plugins/presence/icq-offline.gif
+
+dn:cn=ICQ Presence,cn=Presence,cn=plugins,cn=config
+changeType:modify
+replace:nsim-disabledvaluemapgraphic
+nsim-disabledvaluemapgraphic: D:/dev/ds60cvs/ldapserver/ldap/servers/plugins/presence/icq-disabled.gif
+
+dn:cn=AIM Presence,cn=Presence,cn=plugins,cn=config
+changeType:modify
+replace:nsim-onvaluemapgraphic
+nsim-onvaluemapgraphic: D:/dev/ds60cvs/ldapserver/ldap/servers/plugins/presence/aim-online.gif
+
+dn:cn=AIM Presence,cn=Presence,cn=plugins,cn=config
+changeType:modify
+replace:nsim-offvaluemapgraphic
+nsim-offvaluemapgraphic: D:/dev/ds60cvs/ldapserver/ldap/servers/plugins/presence/aim-offline.gif
+
+dn:cn=ICQ Presence,cn=Presence,cn=plugins,cn=config
+changeType:modify
+replace:nsim-disabledvaluemapgraphic
+nsim-disabledvaluemapgraphic: D:/dev/ds60cvs/ldapserver/ldap/servers/plugins/presence/aim-offline.gif
+
+dn:cn=Yahoo Presence,cn=Presence,cn=plugins,cn=config
+changeType:modify
+replace:nsim-offvaluemapgraphic
+nsim-offvaluemapgraphic: D:/dev/ds60cvs/ldapserver/ldap/servers/plugins/presence/yahoo-offline.gif
+
+dn:cn=Yahoo Presence,cn=Presence,cn=plugins,cn=config
+changeType:modify
+replace:nsim-onvaluemapgraphic
+nsim-onvaluemapgraphic: D:/dev/ds60cvs/ldapserver/ldap/servers/plugins/presence/yahoo-online.gif
+
+dn:cn=Yahoo Presence,cn=Presence,cn=plugins,cn=config
+changeType:modify
+replace:nsim-disabledvaluemapgraphic
+nsim-disabledvaluemapgraphic: D:/dev/ds60cvs/ldapserver/ldap/servers/plugins/presence/yahoo-offline.gif
diff --git a/ldap/servers/plugins/pwdstorage/Makefile b/ldap/servers/plugins/pwdstorage/Makefile
new file mode 100644
index 00000000..efad0788
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/Makefile
@@ -0,0 +1,115 @@
+#
+# 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 password_storaged-plugin.so password storage scheme plugins
+#
+
+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 = $(OBJDIR)/lib/libpwdstorage
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./libpwdstorage.def
+endif
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd
+
+PWD_OBJS= \
+ pwd_init.o \
+ clear_pwd.o \
+ crypt_pwd.o \
+ ns-mta-md5_pwd.o \
+ sha_pwd.o \
+ ssha_pwd.o \
+ md5c.o
+
+
+OBJS = $(addprefix $(OBJDEST)/, $(PWD_OBJS))
+
+ifeq ($(ARCH), WINNT)
+LIBPWD_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+LIBPWD = $(addprefix $(LIBDIR)/, $(PWD_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += \
+ $(LIBSLAPD_DEP) \
+ $(LDAP_LIBUTIL_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP) \
+ $(SECURITY_DEP)
+EXTRA_LIBS += \
+ $(LIBSLAPD) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LIBUTIL) \
+ $(NSPRLINK) \
+ $(LDAP_COMMON_LIBS) \
+ $(SECURITYLINK)
+endif
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += \
+ $(LIBSLAPD_DEP) \
+ $(LDAP_LIBUTIL_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP) \
+ $(SECURITY_DEP)
+EXTRA_LIBS += \
+ $(LIBSLAPDLINK) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LIBUTIL) \
+ $(NSPRLINK) \
+ $(LDAP_COMMON_LIBS) \
+ $(SECURITYLINK)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libpwdstorage.def"
+CFLAGS+= /WX
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+LD=ld
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBPWD)
+
+$(LIBPWD): $(OBJS) $(LIBPWD_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBPWD_DLL_OBJ) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBPWD_DLL_OBJ)
+endif
+ $(RM) $(LIBPWD)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
diff --git a/ldap/servers/plugins/pwdstorage/clear_pwd.c b/ldap/servers/plugins/pwdstorage/clear_pwd.c
new file mode 100644
index 00000000..4b2a3ca5
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/clear_pwd.c
@@ -0,0 +1,27 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * slapd hashed password routines
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "pwdstorage.h"
+
+int
+clear_pw_cmp( char *userpwd, char *dbpwd )
+{
+ return( strcmp( userpwd, dbpwd ));
+}
+
+char *
+clear_pw_enc( char *pwd )
+{
+ return( slapi_ch_strdup( pwd ));
+}
diff --git a/ldap/servers/plugins/pwdstorage/crypt_pwd.c b/ldap/servers/plugins/pwdstorage/crypt_pwd.c
new file mode 100644
index 00000000..df179ef6
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/crypt_pwd.c
@@ -0,0 +1,91 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * slapd hashed password routines
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifdef _WIN32
+char *crypt(char *key, char *salt);
+#else
+#include <sys/socket.h>
+#if defined( hpux ) || defined ( AIX ) || defined (LINUX) || defined (OSF1)
+#define __USE_XOPEN /* linux */
+#include <unistd.h>
+#else /* hpux */
+#include <crypt.h>
+#endif /* hpux */
+#endif /* _WIN32 */
+
+#include "pwdstorage.h"
+
+static PRLock *cryptlock; /* Some implementations of crypt are not thread safe. ie. ours & Irix */
+
+/* characters used in crypt encoding */
+static unsigned char itoa64[] = /* 0 ... 63 => ascii - 64 */
+ "./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+
+
+
+void
+crypt_init()
+{
+ cryptlock = PR_NewLock();
+}
+
+int
+crypt_pw_cmp( char *userpwd, char *dbpwd )
+{
+ int rc;
+ char *cp;
+ PR_Lock(cryptlock);
+ /* we use salt (first 2 chars) of encoded password in call to crypt() */
+ cp = crypt( userpwd, dbpwd );
+ if (cp) {
+ rc= strcmp( dbpwd, cp);
+ } else {
+ rc = -1;
+ }
+ PR_Unlock(cryptlock);
+ return rc;
+}
+
+char *
+crypt_pw_enc( char *pwd )
+{
+ char *cry, salt[3];
+ char *enc= NULL;
+ long v;
+ static unsigned int seed = 0;
+
+ if ( seed == 0)
+ {
+ seed = (unsigned int)slapi_rand();
+ }
+ v = slapi_rand_r(&seed);
+
+ salt[0] = itoa64[v & 0x3f];
+ v >>= 6;
+ salt[1] = itoa64[v & 0x3f];
+ salt[2] = '\0';
+
+ PR_Lock(cryptlock);
+ cry = crypt( pwd, salt );
+ if ( cry != NULL )
+ {
+ enc = slapi_ch_malloc( 3 + CRYPT_NAME_LEN + strlen( cry ));
+ if ( enc != NULL )
+ {
+ sprintf( enc, "%c%s%c%s", PWD_HASH_PREFIX_START, CRYPT_SCHEME_NAME, PWD_HASH_PREFIX_END, cry );
+ }
+ }
+ PR_Unlock(cryptlock);
+ return( enc );
+}
+
diff --git a/ldap/servers/plugins/pwdstorage/dllmain.c b/ldap/servers/plugins/pwdstorage/dllmain.c
new file mode 100644
index 00000000..71530805
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/dllmain.c
@@ -0,0 +1,91 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+ /*
+ * Microsoft Windows specifics for LIBPWDSTORAGE DLL
+ */
+#include "ldap.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; /* successful DLL_PROCESS_ATTACH */
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/pwdstorage/libpwdstorage.def b/ldap/servers/plugins/pwdstorage/libpwdstorage.def
new file mode 100644
index 00000000..e19305d5
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/libpwdstorage.def
@@ -0,0 +1,24 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 7 password storage scheme Plugin'
+EXPORTS
+ sha_pwd_storage_scheme_init @2
+ ssha_pwd_storage_scheme_init @3
+ crypt_pwd_storage_scheme_init @4
+ clear_pwd_storage_scheme_init @5
+ ns_mta_md5_pwd_storage_scheme_init @6
+ clear_pw_cmp @7
+ crypt_pw_cmp @8
+ ns_mta_md5_pw_cmp @9
+ sha1_pw_cmp @10
+ sha1_pw_enc @11
+ salted_sha1_pw_enc @12
+ crypt_pw_enc @13
+ clear_pw_enc @14
+ mta_MD5Init @15
+ mta_MD5Update @16
+ mta_MD5Final @17
diff --git a/ldap/servers/plugins/pwdstorage/md5.h b/ldap/servers/plugins/pwdstorage/md5.h
new file mode 100644
index 00000000..6f7ec036
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/md5.h
@@ -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 **/
+/*
+ * MD5 algorithm used by Netscape Mail Server
+ */
+
+/* MD5 code taken from reference implementation published in RFC 1321 */
+
+#ifndef _RFC1321_MD5_H_
+#define _RFC1321_MD5_H_
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ rights reserved.
+
+ License to copy and use this software is granted provided that it
+ is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ License is also granted to make and use derivative works provided
+ that such works are identified as "derived from the RSA Data
+ Security, Inc. MD5 Message-Digest Algorithm" in all material
+ mentioning or referencing the derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include "nspr.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+typedef unsigned char * POINTER;
+typedef PRUint16 UINT2;
+typedef PRUint32 UINT4;
+
+/* MD5 context. */
+typedef struct {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} mta_MD5_CTX;
+
+void mta_MD5Init (mta_MD5_CTX *);
+void mta_MD5Update (mta_MD5_CTX *, const unsigned char *, unsigned int);
+void mta_MD5Final (unsigned char [16], mta_MD5_CTX *);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* end of _RFC1321_MD5_H_ */
+
diff --git a/ldap/servers/plugins/pwdstorage/md5c.c b/ldap/servers/plugins/pwdstorage/md5c.c
new file mode 100644
index 00000000..d78b772c
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/md5c.c
@@ -0,0 +1,337 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* MD5 code taken from reference implementation published in RFC 1321 */
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ rights reserved.
+
+ License to copy and use this software is granted provided that it
+ is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ License is also granted to make and use derivative works provided
+ that such works are identified as "derived from the RSA Data
+ Security, Inc. MD5 Message-Digest Algorithm" in all material
+ mentioning or referencing the derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include "md5.h"
+
+/* Constants for MD5Transform routine. */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform (UINT4 [4], const unsigned char [64]);
+static void Encode (unsigned char *, const UINT4 *, unsigned int);
+static void Decode (UINT4 *, const unsigned char *, unsigned int);
+static void MD5_memcpy (POINTER, const POINTER, unsigned int);
+static void MD5_memset (POINTER, int, unsigned int);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~(z))))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~(z))))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void mta_MD5Init (context)
+mta_MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void mta_MD5Update (context, input, inputLen)
+mta_MD5_CTX *context; /* context */
+const unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void mta_MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+mta_MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ mta_MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ mta_MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+const unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+const UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+const unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+const POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
diff --git a/ldap/servers/plugins/pwdstorage/ns-mta-md5_pwd.bu b/ldap/servers/plugins/pwdstorage/ns-mta-md5_pwd.bu
new file mode 100644
index 00000000..7cdd74b3
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/ns-mta-md5_pwd.bu
@@ -0,0 +1,405 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * slapd hashed password routines
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "pwd.h"
+
+
+/*
+ * Netscape Mail Server MD5 support (compare-only; no support for encoding)
+ */
+
+static char * ns_mta_hextab = "0123456789abcdef";
+
+static void
+ns_mta_hexify(char *buffer, char *str, int len)
+{
+ char *pch = str;
+ char ch;
+ int i;
+
+ for(i = 0;i < len; i ++) {
+ ch = pch[i];
+ buffer[2*i] = ns_mta_hextab[(ch>>4)&15];
+ buffer[2*i+1] = ns_mta_hextab[ch&15];
+ }
+
+ return;
+}
+
+static char *
+ns_mta_hash_alg(char *buffer, char *salt, char *passwd)
+{
+ mta_MD5_CTX context;
+ char saltstr[2048];
+ unsigned char digest[16];
+
+ sprintf(saltstr,"%s%c%s%c%s",salt,89,passwd,247,salt);
+
+ mta_MD5Init(&context);
+ mta_MD5Update(&context,(unsigned char *)saltstr,strlen(saltstr));
+ mta_MD5Final(digest,&context);
+ ns_mta_hexify(buffer,(char*)digest,16);
+ buffer[32] = '\0';
+ return(buffer);
+
+}
+
+int
+ns_mta_md5_pw_cmp(char * clear, char *mangled)
+{
+ char mta_hash[33];
+ char mta_salt[33];
+ char buffer[65];
+
+ strncpy(mta_hash,mangled,32);
+ strncpy(mta_salt,&mangled[32],32);
+
+ mta_hash[32] = mta_salt[32] = 0;
+
+ return( strcmp(mta_hash,ns_mta_hash_alg(buffer,mta_salt,clear)));
+}
+
+
+/* MD5 code taken from reference implementation published in RFC 1321 */
+
+/* MD5C.C - RSA Data Security, Inc., MD5 message-digest algorithm */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+ rights reserved.
+
+ License to copy and use this software is granted provided that it
+ is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ License is also granted to make and use derivative works provided
+ that such works are identified as "derived from the RSA Data
+ Security, Inc. MD5 Message-Digest Algorithm" in all material
+ mentioning or referencing the derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include "pw.h"
+
+/* Constants for MD5Transform routine. */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform (UINT4 [4], const unsigned char [64]);
+static void Encode (unsigned char *, const UINT4 *, unsigned int);
+static void Decode (UINT4 *, const unsigned char *, unsigned int);
+static void MD5_memcpy (POINTER, const POINTER, unsigned int);
+static void MD5_memset (POINTER, int, unsigned int);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~(x)) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~(z))))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~(z))))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+void mta_MD5Init (context)
+mta_MD5_CTX *context; /* context */
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants.
+*/
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+void mta_MD5Update (context, input, inputLen)
+mta_MD5_CTX *context; /* context */
+const unsigned char *input; /* input block */
+unsigned int inputLen; /* length of input block */
+{
+ unsigned int i, index, partLen;
+
+ /* Compute number of bytes mod 64 */
+ index = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if ((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - index;
+
+ /* Transform as many times as possible.
+*/
+ if (inputLen >= partLen) {
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)input, partLen);
+ MD5Transform (context->state, context->buffer);
+
+ for (i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform (context->state, &input[i]);
+
+ index = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ MD5_memcpy
+ ((POINTER)&context->buffer[index], (POINTER)&input[i],
+ inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+void mta_MD5Final (digest, context)
+unsigned char digest[16]; /* message digest */
+mta_MD5_CTX *context; /* context */
+{
+ unsigned char bits[8];
+ unsigned int index, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+*/
+ index = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (index < 56) ? (56 - index) : (120 - index);
+ mta_MD5Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ mta_MD5Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block.
+ */
+static void MD5Transform (state, block)
+UINT4 state[4];
+const unsigned char block[64];
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+*/
+ MD5_memset ((POINTER)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (output, input, len)
+unsigned char *output;
+const UINT4 *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (output, input, len)
+UINT4 *output;
+const unsigned char *input;
+unsigned int len;
+{
+ unsigned int i, j;
+
+ for (i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+/* Note: Replace "for loop" with standard memcpy if possible.
+ */
+
+static void MD5_memcpy (output, input, len)
+POINTER output;
+const POINTER input;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ output[i] = input[i];
+}
+
+/* Note: Replace "for loop" with standard memset if possible.
+ */
+static void MD5_memset (output, value, len)
+POINTER output;
+int value;
+unsigned int len;
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++)
+ ((char *)output)[i] = (char)value;
+}
+
diff --git a/ldap/servers/plugins/pwdstorage/ns-mta-md5_pwd.c b/ldap/servers/plugins/pwdstorage/ns-mta-md5_pwd.c
new file mode 100644
index 00000000..f3c11a10
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/ns-mta-md5_pwd.c
@@ -0,0 +1,81 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * slapd hashed password routines
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "pwdstorage.h"
+
+#include "md5.h" /* JCM - This is a core server header... These functions could be made part of the slapi API. */
+
+
+/*
+ * Netscape Mail Server MD5 support (compare-only; no support for encoding)
+ */
+
+static char * ns_mta_hextab = "0123456789abcdef";
+
+static void
+ns_mta_hexify(char *buffer, char *str, int len)
+{
+ char *pch = str;
+ char ch;
+ int i;
+
+ for(i = 0;i < len; i ++) {
+ ch = pch[i];
+ buffer[2*i] = ns_mta_hextab[(ch>>4)&15];
+ buffer[2*i+1] = ns_mta_hextab[ch&15];
+ }
+
+ return;
+}
+
+static char *
+ns_mta_hash_alg(char *buffer, char *salt, char *passwd)
+{
+ mta_MD5_CTX context;
+ char *saltstr;
+ unsigned char digest[16];
+
+
+ if ( (saltstr = slapi_ch_malloc(strlen(salt)*2 + strlen(passwd) + 3))
+ == NULL ) {
+ return( NULL );
+ }
+
+ sprintf(saltstr,"%s%c%s%c%s",salt,89,passwd,247,salt);
+
+ mta_MD5Init(&context);
+ mta_MD5Update(&context,(unsigned char *)saltstr,strlen(saltstr));
+ mta_MD5Final(digest,&context);
+ ns_mta_hexify(buffer,(char*)digest,16);
+ buffer[32] = '\0';
+ slapi_ch_free((void**)&saltstr);
+ return(buffer);
+
+}
+
+int
+ns_mta_md5_pw_cmp(char * clear, char *mangled)
+{
+ char mta_hash[33];
+ char mta_salt[33];
+ char buffer[65];
+
+ strncpy(mta_hash,mangled,32);
+ strncpy(mta_salt,&mangled[32],32);
+
+ mta_hash[32] = mta_salt[32] = 0;
+
+ return( strcmp(mta_hash,ns_mta_hash_alg(buffer,mta_salt,clear)));
+}
+
diff --git a/ldap/servers/plugins/pwdstorage/pwd_init.c b/ldap/servers/plugins/pwdstorage/pwd_init.c
new file mode 100644
index 00000000..4ee5138b
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/pwd_init.c
@@ -0,0 +1,146 @@
+/** 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 <string.h>
+#include <sys/types.h>
+
+#include "pwdstorage.h"
+#include "dirver.h"
+
+static Slapi_PluginDesc sha_pdesc = { "sha-password-storage-scheme", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Secure Hashing Algorithm (SHA)" };
+
+static Slapi_PluginDesc ssha_pdesc = { "ssha-password-storage-scheme", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Salted Secure Hashing Algorithm (SSHA)" };
+
+static Slapi_PluginDesc crypt_pdesc = { "crypt-password-storage-scheme", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Unix crypt algorithm (CRYPT)" };
+
+static Slapi_PluginDesc clear_pdesc = { "clear-password-storage-scheme", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "No encryption (CLEAR)" };
+
+static Slapi_PluginDesc ns_mta_md5_pdesc = { "NS-MTA-MD5-password-storage-scheme", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Netscape MD5 (NS-MTA-MD5)" };
+
+static char *plugin_name = "NSPwdStoragePlugin";
+
+int
+sha_pwd_storage_scheme_init( Slapi_PBlock *pb )
+{
+ int rc;
+ char *name;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "=> sha_pwd_storage_scheme_init\n" );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&sha_pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
+ (void *) sha1_pw_enc);
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
+ (void *) sha1_pw_cmp );
+ name = slapi_ch_strdup("SHA");
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME,
+ name );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= sha_pwd_storage_scheme_init %d\n\n", rc );
+
+ return( rc );
+}
+
+int
+ssha_pwd_storage_scheme_init( Slapi_PBlock *pb )
+{
+ int rc;
+ char *name;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "=> ssha_pwd_storage_scheme_init\n" );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&ssha_pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
+ (void *) salted_sha1_pw_enc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
+ (void *) sha1_pw_cmp );
+ name = slapi_ch_strdup("SSHA");
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME,
+ name );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= ssha_pwd_storage_scheme_init %d\n\n", rc );
+ return( rc );
+}
+
+int
+crypt_pwd_storage_scheme_init( Slapi_PBlock *pb )
+{
+ int rc;
+ char *name;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "=> crypt_pwd_storage_scheme_init\n" );
+
+ crypt_init();
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&crypt_pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
+ (void *) crypt_pw_enc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
+ (void *) crypt_pw_cmp );
+ name = slapi_ch_strdup("CRYPT");
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME,
+ name );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= crypt_pwd_storage_scheme_init %d\n\n", rc );
+ return( rc );
+}
+
+int
+clear_pwd_storage_scheme_init( Slapi_PBlock *pb )
+{
+ int rc;
+ char *name;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "=> clear_pwd_storage_scheme_init\n" );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&clear_pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
+ (void *) clear_pw_enc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
+ (void *) clear_pw_cmp );
+ name = slapi_ch_strdup("CLEAR");
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME,
+ name );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= clear_pwd_storage_scheme_init %d\n\n", rc );
+ return( rc );
+}
+
+int
+ns_mta_md5_pwd_storage_scheme_init( Slapi_PBlock *pb )
+{
+ int rc;
+ char *name;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "=> ns_mta_md5_pwd_storage_scheme_init\n" );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&ns_mta_md5_pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
+ (void *) NULL );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
+ (void *) ns_mta_md5_pw_cmp );
+ name = slapi_ch_strdup("NS-MTA-MD5");
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME,
+ name );
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= ns_mta_md5_pwd_storage_scheme_init %d\n\n", rc );
+ return( rc );
+}
diff --git a/ldap/servers/plugins/pwdstorage/pwdstorage.h b/ldap/servers/plugins/pwdstorage/pwdstorage.h
new file mode 100644
index 00000000..0e938cb9
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/pwdstorage.h
@@ -0,0 +1,99 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _PWDSTORAGE_H
+#define _PWDSTORAGE_H
+
+#include "slapi-plugin.h"
+#include <ssl.h>
+#include "nspr.h"
+#include "ldif.h"
+#include "md5.h"
+
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+
+#define PWD_HASH_PREFIX_START '{'
+#define PWD_HASH_PREFIX_END '}'
+
+#define SHA1_SCHEME_NAME "SHA"
+#define SHA1_NAME_LEN 3
+#define SALTED_SHA1_SCHEME_NAME "SSHA"
+#define SALTED_SHA1_NAME_LEN 4
+#define CRYPT_SCHEME_NAME "crypt"
+#define CRYPT_NAME_LEN 5
+#define NS_MTA_MD5_SCHEME_NAME "NS-MTA-MD5"
+#define NS_MTA_MD5_NAME_LEN 10
+#define CLEARTEXT_SCHEME_NAME "clear"
+#define CLEARTEXT_NAME_LEN 5
+
+SECStatus sha1_salted_hash(unsigned char *hash_out, char *pwd, struct berval *salt);
+int sha1_pw_cmp( char *userpwd, char *dbpwd );
+char * sha1_pw_enc( char *pwd );
+char * salted_sha1_pw_enc( char *pwd );
+int clear_pw_cmp( char *userpwd, char *dbpwd );
+char *clear_pw_enc( char *pwd );
+void crypt_init();
+int crypt_pw_cmp( char *userpwd, char *dbpwd );
+char *crypt_pw_enc( char *pwd );
+int ns_mta_md5_pw_cmp( char *userpwd, char *dbpwd );
+
+
+#if !defined(NET_SSL)
+/******************************************/
+/*
+ * Some of the stuff below depends on a definition for uint32, so
+ * we include one here. Other definitions appear in nspr/prtypes.h,
+ * at least. All the platforms we support use 32-bit ints.
+ */
+typedef unsigned int uint32;
+
+
+/******************************************/
+/*
+ * The following is from ds.h, which the libsec sec.h stuff depends on (see
+ * comment below).
+ */
+/*
+** A status code. Status's are used by procedures that return status
+** values. Again the motivation is so that a compiler can generate
+** warnings when return values are wrong. Correct testing of status codes:
+**
+** DSStatus rv;
+** rv = some_function (some_argument);
+** if (rv != DSSuccess)
+** do_an_error_thing();
+**
+*/
+typedef enum DSStatusEnum {
+ DSWouldBlock = -2,
+ DSFailure = -1,
+ DSSuccess = 0
+} DSStatus;
+
+
+/******************************************/
+/*
+ * All of the SHA1-related defines are from libsec's "sec.h" -- including
+ * it directly pulls in way too much stuff that we conflict with. Ugh.
+ */
+
+/*
+ * Number of bytes each hash algorithm produces
+ */
+#define SHA1_LENGTH 20
+
+/******************************************/
+/*
+** SHA-1 secure hash function
+*/
+
+/*
+** Hash a null terminated string "src" into "dest" using SHA-1
+*/
+DSStatus SHA1_Hash(unsigned char *dest, char *src);
+
+#endif /* !defined(NET_SSL) */
+
+#endif /* _PWDSTORAGE_H */
diff --git a/ldap/servers/plugins/pwdstorage/sha_pwd.c b/ldap/servers/plugins/pwdstorage/sha_pwd.c
new file mode 100644
index 00000000..c8cf435d
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/sha_pwd.c
@@ -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 **/
+/*
+ * slapd hashed password routines
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "pwdstorage.h"
+
+#if defined(NET_SSL)
+#include <sechash.h>
+#endif /* NET_SSL */
+
+#define SHA1_SALT_LENGTH 8 /* number of bytes of data in salt */
+#define NOT_FIRST_TIME (time_t)1 /* not the first logon */
+
+static char *hasherrmsg = "pw_cmp: %s userPassword \"%s\" is the wrong length or is not properly encoded BASE64\n";
+
+static char *plugin_name = "NSPwdStoragePlugin";
+
+#define DS40B1_SALTED_SHA_LENGTH 18
+/* Directory Server 4.0 Beta 1 implemented a scheme that stored
+ * 8 bytes of salt plus the first 10 bytes of the SHA-1 digest.
+ * It's obsolescent now, but we still handle such stored values.
+ */
+
+int
+sha1_pw_cmp (char *userpwd, char *dbpwd )
+{
+ /*
+ * SHA1 passwords are stored in the database as SHA1_LENGTH bytes of
+ * hash, followed by zero or more bytes of salt, all BASE64 encoded.
+ */
+ int result = 1; /* failure */
+ unsigned char userhash[SHA1_LENGTH];
+ unsigned char quick_dbhash[SHA1_LENGTH + SHA1_SALT_LENGTH + 3];
+ unsigned char *dbhash = quick_dbhash;
+ struct berval salt;
+ int hash_len; /* must be a signed valued -- see below */
+
+ /*
+ * Decode hash stored in database.
+ *
+ * Note that ldif_base64_decode() returns a value less than zero to
+ * indicate that a decoding error occurred, so it is critical that
+ * hash_len be a signed value.
+ */
+ hash_len = (((strlen(dbpwd) + 3) / 4) * 3); /* maybe less */
+ if ( hash_len > sizeof(quick_dbhash) ) { /* get more space: */
+ dbhash = (unsigned char*) slapi_ch_malloc( hash_len );
+ if ( dbhash == NULL ) goto loser;
+ }
+ hash_len = ldif_base64_decode( dbpwd, dbhash );
+ if ( hash_len >= SHA1_LENGTH ) {
+ salt.bv_val = (void*)(dbhash + SHA1_LENGTH);
+ salt.bv_len = hash_len - SHA1_LENGTH;
+ } else if ( hash_len == DS40B1_SALTED_SHA_LENGTH ) {
+ salt.bv_val = (void*)dbhash;
+ salt.bv_len = 8;
+ } else { /* unsupported, invalid BASE64 (hash_len < 0), or similar */
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, hasherrmsg, SHA1_SCHEME_NAME, dbpwd );
+ goto loser;
+ }
+
+ /* SHA1 hash the user's key */
+ if ( sha1_salted_hash( userhash, userpwd, &salt ) != SECSuccess ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "sha1_pw_cmp: SHA1_Hash() failed\n");
+ goto loser;
+ }
+
+ /* the proof is in the comparison... */
+ result = ( hash_len == DS40B1_SALTED_SHA_LENGTH ) ?
+ ( memcmp( userhash, dbhash + 8, hash_len - 8 )) :
+ ( memcmp( userhash, dbhash, SHA1_LENGTH ));
+
+ loser:
+ if ( dbhash && dbhash != quick_dbhash ) slapi_ch_free( (void**)&dbhash );
+ return result;
+}
+
+
+char *
+sha1_pw_enc( char *pwd )
+{
+ unsigned char hash[ SHA1_LENGTH ];
+ char *enc;
+
+ /* SHA1 hash the user's key */
+ if ( sha1_salted_hash( hash, pwd, NULL ) != SECSuccess ) {
+ return( NULL );
+ }
+
+ if (( enc = slapi_ch_malloc( 3 + SHA1_NAME_LEN +
+ LDIF_BASE64_LEN( SHA1_LENGTH ))) == NULL ) {
+ return( NULL );
+ }
+
+ sprintf( enc, "%c%s%c", PWD_HASH_PREFIX_START, SHA1_SCHEME_NAME,
+ PWD_HASH_PREFIX_END );
+ (void)ldif_base64_encode( hash, enc + 2 + SHA1_NAME_LEN,
+ SHA1_LENGTH, -1 );
+
+ return( enc );
+}
diff --git a/ldap/servers/plugins/pwdstorage/ssha_pwd.c b/ldap/servers/plugins/pwdstorage/ssha_pwd.c
new file mode 100644
index 00000000..b3c82d6d
--- /dev/null
+++ b/ldap/servers/plugins/pwdstorage/ssha_pwd.c
@@ -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 **/
+/*
+ * slapd hashed password routines
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+#include "pwdstorage.h"
+#include "prtime.h"
+#include "prlong.h"
+
+#if defined(NET_SSL)
+#include <pk11func.h>
+#include <pk11pqg.h>
+#endif /* NET_SSL */
+
+#define SHA1_SALT_LENGTH 8 /* number of bytes of data in salt */
+
+static void ssha_rand_array(void *randx, size_t len);
+
+
+/* ***************************************************
+ Identical function to slapi_rand_array in util.c, but can't use
+ that here since this module is included in libds_admin, which doesn't
+ link to libslapd.
+ *************************************************** */
+static void
+ssha_rand_array(void *randx, size_t len)
+{
+ PK11_RandomUpdate(randx, len);
+ PK11_GenerateRandom((unsigned char *)randx, (int)len);
+}
+
+/*
+ * A salted SHA1 hash
+ * if salt is null, no salt is used (this is for backward compatibility)
+*/
+SECStatus
+sha1_salted_hash(unsigned char *hash_out, char *pwd, struct berval *salt)
+{
+ PK11Context *ctx;
+ unsigned int outLen;
+ SECStatus rc;
+
+ if (salt && salt->bv_len) {
+ ctx = PK11_CreateDigestContext(SEC_OID_SHA1);
+ if (ctx == NULL) {
+ rc = SECFailure;
+ }
+ else {
+ PK11_DigestBegin(ctx);
+ PK11_DigestOp(ctx, (unsigned char*)pwd, strlen(pwd));
+ PK11_DigestOp(ctx, (unsigned char*)(salt->bv_val), salt->bv_len);
+ PK11_DigestFinal(ctx, hash_out, &outLen, SHA1_LENGTH);
+ PK11_DestroyContext(ctx, 1);
+ if (outLen == SHA1_LENGTH)
+ rc = SECSuccess;
+ else
+ rc = SECFailure;
+ }
+ }
+ else {
+ /*backward compatibility*/
+ rc = PK11_HashBuf(SEC_OID_SHA1, hash_out, (unsigned char *)pwd, strlen(pwd));
+ }
+
+ return rc;
+}
+
+char *
+salted_sha1_pw_enc( char *pwd )
+{
+ unsigned char hash[ SHA1_LENGTH + SHA1_SALT_LENGTH ];
+ unsigned char *salt = hash + SHA1_LENGTH;
+ struct berval saltval;
+ char *enc;
+
+ saltval.bv_val = (void*)salt;
+ saltval.bv_len = SHA1_SALT_LENGTH;
+
+ /* generate a new random salt */
+ /* Note: the uninitialized salt array provides a little extra entropy
+ * to the random array generation, but it is not really needed since
+ * PK11_GenerateRandom takes care of seeding. In any case, it doesn't
+ * hurt. */
+ ssha_rand_array( salt, SHA1_SALT_LENGTH );
+
+ /* SHA1 hash the user's key */
+ if ( sha1_salted_hash( hash, pwd, &saltval ) != SECSuccess ) {
+ return( NULL );
+ }
+
+ if (( enc = PR_Malloc( 3 + SALTED_SHA1_NAME_LEN +
+ LDIF_BASE64_LEN(sizeof(hash)))) == NULL ) {
+ return( NULL );
+ }
+
+ sprintf( enc, "%c%s%c", PWD_HASH_PREFIX_START, SALTED_SHA1_SCHEME_NAME,
+ PWD_HASH_PREFIX_END );
+ (void)ldif_base64_encode( hash, enc + 2 + SALTED_SHA1_NAME_LEN,
+ sizeof(hash), -1 );
+
+ return( enc );
+}
+
diff --git a/ldap/servers/plugins/referint/Makefile b/ldap/servers/plugins/referint/Makefile
new file mode 100644
index 00000000..acf09c42
--- /dev/null
+++ b/ldap/servers/plugins/referint/Makefile
@@ -0,0 +1,72 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+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 = $(OBJDIR)/lib/referint-plugin
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./referint.def
+endif
+
+REFERINT_OBJS = referint.o
+OBJS = $(addprefix $(OBJDEST)/, $(REFERINT_OBJS))
+
+INCLUDES += -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPLINK_DEP) $(NSPRLINK_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAPLINK) $(NSPRLINK)
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(SECURITY_DEP)
+EXTRA_LIBS += $(SECURITYLINK)
+endif
+
+ifeq ($(ARCH), WINNT)
+REFERINT_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), AIX)
+LD=ld
+endif
+
+REFERINT= $(addprefix $(LIBDIR)/, $(REFERINT_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(REFERINT)
+
+ifeq ($(ARCH), WINNT)
+$(REFERINT): $(OBJS) $(REFERINT_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(REFERINT_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(REFERINT): $(OBJS) $(REFERINT_DLL_OBJ)
+ $(LINK_DLL) $(REFERINT_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(REFERINT_DLL_OBJ)
+endif
+ $(RM) $(REFERINT)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
diff --git a/ldap/servers/plugins/referint/dllmain.c b/ldap/servers/plugins/referint/dllmain.c
new file mode 100644
index 00000000..96bfcbb0
--- /dev/null
+++ b/ldap/servers/plugins/referint/dllmain.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 **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/referint/referint.c b/ldap/servers/plugins/referint/referint.c
new file mode 100644
index 00000000..e0ad15fd
--- /dev/null
+++ b/ldap/servers/plugins/referint/referint.c
@@ -0,0 +1,808 @@
+/** 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 <string.h>
+#include "portable.h"
+#include "slapi-plugin.h"
+#include "slap.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+
+/* include NSPR header files */
+#include "prthread.h"
+#include "prlock.h"
+#include "prerror.h"
+#include "prcvar.h"
+#include "prio.h"
+
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+#define REFERINT_PLUGIN_SUBSYSTEM "referint-plugin" /* used for logging */
+
+#ifdef _WIN32
+#define REFERINT_DEFAULT_FILE_MODE 0
+#else
+#define REFERINT_DEFAULT_FILE_MODE S_IRUSR | S_IWUSR
+#endif
+
+
+#define MAX_LINE 2048
+#define READ_BUFSIZE 4096
+#define MY_EOF 0
+
+/* function prototypes */
+int referint_postop_init( Slapi_PBlock *pb );
+int referint_postop_del( Slapi_PBlock *pb );
+int referint_postop_modrdn( Slapi_PBlock *pb );
+int referint_postop_start( Slapi_PBlock *pb);
+int referint_postop_close( Slapi_PBlock *pb);
+int update_integrity(char **argv, char *origDN, char *newrDN, int logChanges);
+void referint_thread_func(void *arg);
+int GetNextLine(char *dest, int size_dest, PRFileDesc *stream);
+void writeintegritylog(char *logfilename, char *dn, char *newrdn);
+int my_fgetc(PRFileDesc *stream);
+
+/* global thread control stuff */
+
+static PRLock *referint_mutex = NULL;
+static PRThread *referint_tid = NULL;
+int keeprunning = 0;
+
+static PRLock *keeprunning_mutex = NULL;
+static PRCondVar *keeprunning_cv = NULL;
+
+static Slapi_PluginDesc pdesc = { "referint", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "referential integrity plugin" };
+
+static void* referint_plugin_identity = NULL;
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+int
+referint_postop_init( Slapi_PBlock *pb )
+{
+
+ /*
+ * Get plugin identity and stored it for later use
+ * Used for internal operations
+ */
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &referint_plugin_identity);
+ PR_ASSERT (referint_plugin_identity);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_DELETE_FN,
+ (void *) referint_postop_del ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODRDN_FN,
+ (void *) referint_postop_modrdn ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) referint_postop_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) referint_postop_close ) != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_init failed\n" );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+int
+referint_postop_del( Slapi_PBlock *pb )
+{
+ char *dn;
+ int rc;
+ int oprc;
+ char **argv;
+ int argc;
+ int delay;
+ int logChanges=0;
+ int isrepop = 0;
+
+ if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_DELETE_TARGET, &dn ) != 0 ||
+ slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_del: could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* this plugin should only execute if the delete was successful
+ and this is not a replicated op
+ */
+ if(oprc != 0 || isrepop)
+ {
+ return( 0 );
+ }
+ /* get args */
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argc\n" );
+ return( -1 );
+ }
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+
+ if(argv == NULL){
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_modrdn, args are NULL\n" );
+ return( -1 );
+ }
+
+ if (argc >= 3) {
+ /* argv[0] will be the delay */
+ delay = atoi(argv[0]);
+
+ /* argv[2] will be wether or not to log changes */
+ logChanges = atoi(argv[2]);
+
+ if(delay == -1){
+ /* integrity updating is off */
+ rc = 0;
+ }else if(delay == 0){
+ /* no delay */
+ /* call function to update references to entry */
+ rc = update_integrity(argv, dn, NULL, logChanges);
+ }else{
+ /* write the entry to integrity log */
+ writeintegritylog(argv[1],dn, NULL);
+ rc = 0;
+ }
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop insufficient arguments supplied\n" );
+ return( -1 );
+ }
+
+ return( rc );
+
+}
+
+int
+referint_postop_modrdn( Slapi_PBlock *pb )
+{
+ char *dn;
+ char *newrdn;
+ int oprc;
+ int rc;
+ char **argv;
+ int argc = 0;
+ int delay;
+ int logChanges=0;
+ int isrepop = 0;
+
+ if ( slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &isrepop ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_MODRDN_TARGET, &dn ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn ) != 0 ||
+ slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &oprc) != 0 ){
+
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_modrdn: could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* this plugin should only execute if the delete was successful
+ and this is not a replicated op
+ */
+ if(oprc != 0 || isrepop){
+ return( 0 );
+ }
+ /* get args */
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+
+ if(argv == NULL){
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_modrdn, args are NULL\n" );
+ return( -1 );
+ }
+
+ if (argc >= 3) {
+ /* argv[0] will always be the delay */
+ delay = atoi(argv[0]);
+
+ /* argv[2] will be wether or not to log changes */
+ logChanges = atoi(argv[2]);
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_modrdn insufficient arguments supplied\n" );
+ return( -1 );
+ }
+
+ if(delay == -1){
+ /* integrity updating is off */
+ rc = 0;
+ }else if(delay == 0){
+ /* no delay */
+ /* call function to update references to entry */
+ rc = update_integrity(argv, dn, newrdn, logChanges);
+ }else{
+ /* write the entry to integrity log */
+ writeintegritylog(argv[1],dn, newrdn);
+ rc = 0;
+ }
+
+ return( rc );
+}
+
+int isFatalSearchError(int search_result)
+{
+
+ /* Make sure search result is fatal
+ * Some conditions that happen quite often are not fatal
+ * for example if you have two suffixes and one is null, you will always
+ * get no such object, howerever this is not a fatal error.
+ * Add other conditions to the if statement as they are found
+ */
+
+ /* NPCTE fix for bugid 531225, esc 0. <P.R> <30-May-2001> */
+ switch(search_result) {
+ case LDAP_REFERRAL:
+ case LDAP_NO_SUCH_OBJECT: return 0 ;
+ }
+ return 1;
+ /* end of NPCTE fix for bugid 531225 */
+
+}
+
+int update_integrity(char **argv, char *origDN, char *newrDN, int logChanges){
+
+ Slapi_PBlock *search_result_pb = NULL;
+ Slapi_PBlock *mod_result_pb = NULL;
+ Slapi_Entry **search_entries = NULL;
+ int search_result;
+ Slapi_DN *sdn = NULL;
+ void *node = NULL;
+ LDAPMod attribute1, attribute2;
+ const LDAPMod *list_of_mods[3];
+ char *values_del[2];
+ char *values_add[2];
+ char *filter = NULL;
+ int i, j;
+ const char *search_base = NULL;
+ char *newDN=NULL;
+ char **dnParts=NULL;
+ int dnsize;
+ int x;
+ int rc;
+ int valcount = 0;
+
+ if ( argv == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop required config file arguments missing\n" );
+ rc = -1;
+ goto free_and_return;
+ }
+
+ /* for now, just putting attributes to keep integrity on in conf file,
+ until resolve the other timing mode issue */
+
+ /* Search each namingContext in turn */
+ for ( sdn = slapi_get_first_suffix( &node, 0 ); sdn != NULL;
+ sdn = slapi_get_next_suffix( &node, 0 ))
+ {
+ search_base = slapi_sdn_get_dn( sdn );
+
+
+ for(i=3; argv[i] != NULL; i++)
+ {
+ unsigned long filtlen = strlen(argv[i]) + (strlen(origDN) * 3 ) + 4;
+ filter = (char *)slapi_ch_calloc( filtlen, sizeof(char ));
+ if (( search_result = ldap_create_filter( filter, filtlen, "(%a=%e)",
+ NULL, NULL, argv[i], origDN, NULL )) == LDAP_SUCCESS ) {
+
+ /* Don't need any attribute */
+ char * attrs[2];
+ attrs[0]="1.1";
+ attrs[1]=NULL;
+
+ /* Use new search API */
+ search_result_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(search_result_pb, search_base, LDAP_SCOPE_SUBTREE,
+ filter, attrs, 0 /* attrs only */, NULL,NULL,referint_plugin_identity,0);
+ slapi_search_internal_pb(search_result_pb);
+
+ slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
+ }
+
+
+ /* if search successfull then do integrity update */
+ if(search_result == 0)
+ {
+ slapi_pblock_get( search_result_pb,SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+ &search_entries);
+
+ for(j=0; search_entries[j] != NULL; j++)
+ {
+ /* no matter what mode in always going to delete old dn so set that up */
+ values_del[0]= origDN;
+ values_del[1]= NULL;
+ attribute1.mod_type = argv[i];
+ attribute1.mod_op = LDAP_MOD_DELETE;
+ attribute1.mod_values = values_del;
+ list_of_mods[0] = &attribute1;
+
+ if(newrDN == NULL){
+ /* in delete mode so terminate list of mods cause this is the only one */
+ list_of_mods[1] = NULL;
+ }else if(newrDN != NULL){
+ /* in modrdn mode */
+
+ /* need to put together rdn into a dn */
+ dnParts = ldap_explode_dn( origDN, 0 );
+
+ /* skip original rdn so start at 1*/
+ dnsize = 0;
+ for(x=1; dnParts[x] != NULL; x++)
+ {
+ /* +2 for space and comma adding later */
+ dnsize += strlen(dnParts[x]) + 2;
+ }
+ /* add the newrDN length */
+ dnsize += strlen(newrDN) + 1;
+
+ newDN = slapi_ch_calloc(dnsize, sizeof(char));
+ strcat(newDN, newrDN);
+ for(x=1; dnParts[x] != NULL; x++)
+ {
+ strcat(newDN, ", ");
+ strcat(newDN, dnParts[x]);
+ }
+
+ values_add[0]=newDN;
+ values_add[1]=NULL;
+ attribute2.mod_type = argv[i];
+ attribute2.mod_op = LDAP_MOD_ADD;
+ attribute2.mod_values = values_add;
+
+ /* add the new dn to list of mods and terminate list of mods */
+ list_of_mods[1] = &attribute2;
+ list_of_mods[2] = NULL;
+
+ }
+
+ /* try to cleanup entry */
+
+ /* Use new internal operation API */
+ mod_result_pb=slapi_pblock_new();
+ slapi_modify_internal_set_pb(mod_result_pb,slapi_entry_get_dn(search_entries[j]),
+ (LDAPMod **)list_of_mods,NULL,NULL,referint_plugin_identity,0);
+ slapi_modify_internal_pb(mod_result_pb);
+
+ /* could check the result code here if want to log it or something later
+ for now, continue no matter what result is */
+
+ slapi_pblock_destroy(mod_result_pb);
+
+ /* cleanup memory allocated for dnParts and newDN */
+ if(dnParts != NULL){
+ for(x=0; dnParts[x] != NULL; x++)
+ {
+ free(dnParts[x]);
+ }
+ free(dnParts);
+ }
+ if(newDN != NULL){
+ slapi_ch_free((void**)&newDN);
+ }
+
+ }
+
+
+
+ }else{
+ if(isFatalSearchError(search_result))
+ {
+ /* NPCTE fix for bugid 531225, esc 0. <P.R> <30-May-2001> */
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop search (base=%s filter=%s) returned error %d\n", search_base,filter,search_result );
+ /* end of NPCTE fix for bugid 531225 */
+ rc = -1;
+ goto free_and_return;
+ }
+
+ }
+
+ slapi_ch_free((void**)&filter);
+
+ if(search_result_pb != NULL){
+ slapi_free_search_results_internal(search_result_pb);
+ slapi_pblock_destroy(search_result_pb);
+ search_result_pb= NULL;
+ }
+
+ }
+ }
+ /* if got here, then everything good rc = 0 */
+ rc = 0;
+
+free_and_return:
+
+ /* free filter and search_results_pb */
+ if(filter != NULL)
+ {
+ free(filter);
+ }
+
+ if(search_result_pb != NULL)
+ {
+ slapi_free_search_results_internal(search_result_pb);
+ free(search_result_pb);
+ }
+
+ return(rc);
+}
+
+int referint_postop_start( Slapi_PBlock *pb)
+{
+
+ char **argv;
+ int argc = 0;
+
+ /* get args */
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGC, &argc ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop failed to get argv\n" );
+ return( -1 );
+ }
+
+ if(argv == NULL){
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "args were null in referint_postop_start\n" );
+ return( -1 );
+ }
+
+ /* only bother to start the thread if you are in delay mode.
+ 0 = no delay,
+ -1 = integrity off */
+
+ if (argc >= 1) {
+ if(atoi(argv[0]) > 0){
+
+ /* initialize cv and lock */
+
+ referint_mutex = PR_NewLock();
+ keeprunning_mutex = PR_NewLock();
+ keeprunning_cv = PR_NewCondVar(keeprunning_mutex);
+ keeprunning =1;
+
+ if (( referint_tid = PR_CreateThread (PR_USER_THREAD,
+ referint_thread_func,
+ (void *)argv,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_start PR_CreateThread failed\n" );
+ exit( 1 );
+ }
+ }
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_start insufficient arguments supplied\n" );
+ return( -1 );
+ }
+
+ return(0);
+
+}
+
+int referint_postop_close( Slapi_PBlock *pb)
+{
+
+ /* signal the thread to exit */
+ if (NULL != keeprunning_mutex) {
+ PR_Lock(keeprunning_mutex);
+ keeprunning=0;
+ if (NULL != keeprunning_cv) {
+ PR_NotifyCondVar(keeprunning_cv);
+ }
+ PR_Unlock(keeprunning_mutex);
+ }
+
+ return(0);
+}
+
+void referint_thread_func(void *arg){
+
+ char **plugin_argv = (char **)arg;
+ PRFileDesc *prfd;
+ char *logfilename;
+ char thisline[MAX_LINE];
+ int delay;
+ int no_changes;
+ char delimiter[]="\t\n";
+ char *ptoken;
+ char *tmpdn, *tmprdn;
+ int logChanges=0;
+ char * iter = NULL;
+
+ if(plugin_argv == NULL){
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_thread_func not get args \n" );
+ return;
+ }
+
+
+ delay = atoi(plugin_argv[0]);
+ logfilename = plugin_argv[1];
+ logChanges = atoi(plugin_argv[2]);
+
+ /* keep running this thread until plugin is signalled to close */
+
+ while(1){
+
+ no_changes=1;
+
+ while(no_changes){
+
+ PR_Lock(keeprunning_mutex);
+ if(keeprunning == 0){
+ PR_Unlock(keeprunning_mutex);
+ break;
+ }
+ PR_Unlock(keeprunning_mutex);
+
+
+ PR_Lock(referint_mutex);
+ if (( prfd = PR_Open( logfilename, PR_RDONLY,
+ REFERINT_DEFAULT_FILE_MODE )) == NULL )
+ {
+ PR_Unlock(referint_mutex);
+ /* go back to sleep and wait for this file */
+ PR_Lock(keeprunning_mutex);
+ PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
+ PR_Unlock(keeprunning_mutex);
+ }else{
+ no_changes = 0;
+ }
+ }
+
+ /* check keep running here, because after break out of no
+ * changes loop on shutdown, also need to break out of this
+ * loop before trying to do the changes. The server
+ * will pick them up on next startup as file still exists
+ */
+ PR_Lock(keeprunning_mutex);
+ if(keeprunning == 0){
+ PR_Unlock(keeprunning_mutex);
+ break;
+ }
+ PR_Unlock(keeprunning_mutex);
+
+
+ while( GetNextLine(thisline, MAX_LINE, prfd) ){
+ ptoken = ldap_utf8strtok_r(thisline, delimiter, &iter);
+ tmpdn = slapi_ch_calloc(strlen(ptoken) + 1, sizeof(char));
+ strcpy(tmpdn, ptoken);
+
+ ptoken = ldap_utf8strtok_r (NULL, delimiter, &iter);
+ if(!strcasecmp(ptoken, "NULL")){
+ tmprdn = NULL;
+ }else{
+ tmprdn = slapi_ch_calloc(strlen(ptoken) + 1, sizeof(char));
+ strcpy(tmprdn, ptoken);
+ }
+
+
+ update_integrity(plugin_argv, tmpdn, tmprdn, logChanges);
+
+ slapi_ch_free((void **) &tmpdn);
+ slapi_ch_free((void **) &tmprdn);
+ }
+
+ PR_Close(prfd);
+
+ /* remove the original file */
+ if( PR_SUCCESS != PR_Delete(logfilename) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop_close could not delete \"%s\"\n",
+ logfilename );
+ }
+
+ /* unlock and let other writers back at the file */
+ PR_Unlock(referint_mutex);
+
+ /* wait on condition here */
+ PR_Lock(keeprunning_mutex);
+ PR_WaitCondVar(keeprunning_cv, PR_SecondsToInterval(delay));
+ PR_Unlock(keeprunning_mutex);
+ }
+
+ /* cleanup resources allocated in start */
+ if (NULL != keeprunning_mutex) {
+ PR_DestroyLock(keeprunning_mutex);
+ }
+ if (NULL != referint_mutex) {
+ PR_DestroyLock(referint_mutex);
+ }
+ if (NULL != keeprunning_cv) {
+ PR_DestroyCondVar(keeprunning_cv);
+ }
+
+
+}
+
+int my_fgetc(PRFileDesc *stream)
+{
+ static char buf[READ_BUFSIZE] = "\0";
+ static int position = READ_BUFSIZE;
+ int retval;
+ int err;
+
+ /* check if we need to load the buffer */
+
+ if( READ_BUFSIZE == position )
+ {
+ memset(buf, '\0', READ_BUFSIZE);
+ if( ( err = PR_Read(stream, buf, READ_BUFSIZE) ) >= 0)
+ {
+ /* it read some data */;
+ position = 0;
+ }else{
+ /* an error occurred */
+ return err;
+ }
+ }
+
+ /* try to read some data */
+ if( '\0' == buf[position])
+ {
+ /* out of data, return eof */
+ retval = MY_EOF;
+ position = READ_BUFSIZE;
+ }else{
+ retval = buf[position];
+ position++;
+ }
+
+ return retval;
+
+}
+
+int
+GetNextLine(char *dest, int size_dest, PRFileDesc *stream) {
+
+ char nextchar ='\0';
+ int done = 0;
+ int i = 0;
+
+ while(!done)
+ {
+ if( ( nextchar = my_fgetc(stream) ) != 0)
+ {
+ if( i < (size_dest - 1) )
+ {
+ dest[i] = nextchar;
+ i++;
+
+ if(nextchar == '\n')
+ {
+ /* end of line reached */
+ done = 1;
+ }
+
+ }else{
+ /* no more room in buffer */
+ done = 1;
+ }
+
+ }else{
+ /* error or end of file */
+ done = 1;
+ }
+ }
+
+ dest[i] = '\0';
+
+ /* return size of string read */
+ return i;
+}
+
+void writeintegritylog(char *logfilename, char *dn, char *newrdn){
+ PRFileDesc *prfd;
+ char buffer[MAX_LINE];
+ int len_to_write = 0;
+ int rc;
+ /* write this record to the file */
+
+ /* use this lock to protect file data when update integrity is occuring */
+ /* should hopefully not be a big issue on concurrency */
+
+ PR_Lock(referint_mutex);
+ if (( prfd = PR_Open( logfilename, PR_WRONLY | PR_CREATE_FILE | PR_APPEND,
+ REFERINT_DEFAULT_FILE_MODE )) == NULL )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop could not write integrity log \"%s\" "
+ SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
+ logfilename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
+
+ PR_Unlock(referint_mutex);
+ return;
+ }
+
+ /* make sure we have enough room in our buffer
+ before trying to write it
+ */
+
+ /* add length of dn + 4(two tabs, a newline, and terminating \0) */
+ len_to_write = strlen(dn) + 4;
+
+ if(newrdn == NULL)
+ {
+ /* add the length of "NULL" */
+ len_to_write += 4;
+ }else{
+ /* add the length of the newrdn */
+ len_to_write += strlen(newrdn);
+ }
+
+ if(len_to_write > MAX_LINE )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, REFERINT_PLUGIN_SUBSYSTEM,
+ "referint_postop could not write integrity log:"
+ " line length exceeded. It will not be able"
+ " to update references to this entry.\n");
+ }else{
+ PRInt32 rv;
+ sprintf(buffer, "%s\t%s\t\n",
+ dn,
+ (newrdn != NULL) ? newrdn : "NULL");
+ if ((rv = PR_Write(prfd,buffer,strlen(buffer))) < 0){
+ slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
+ " writeintegritylog: PR_Write failed : The disk"
+ " may be full or the file is unwritable :: NSPR error - %d\n",
+ PR_GetError());
+ }
+ }
+
+ /* If file descriptor is closed successfully, PR_SUCCESS */
+
+ rc = PR_Close(prfd);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL,REFERINT_PLUGIN_SUBSYSTEM,
+ " writeintegritylog: failed to close the file"
+ " descriptor prfd; NSPR error - %d\n",
+ PR_GetError());
+ }
+ PR_Unlock(referint_mutex);
+ }
diff --git a/ldap/servers/plugins/referint/referint.def b/ldap/servers/plugins/referint/referint.def
new file mode 100644
index 00000000..75861791
--- /dev/null
+++ b/ldap/servers/plugins/referint/referint.def
@@ -0,0 +1,12 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 7 Referint Plugin'
+CODE SHARED READ EXECUTE
+DATA SHARED READ WRITE
+EXPORTS
+ referint_postop_init @2
+ plugin_init_debug_level @3
diff --git a/ldap/servers/plugins/replication/Makefile b/ldap/servers/plugins/replication/Makefile
new file mode 100644
index 00000000..6f5341e8
--- /dev/null
+++ b/ldap/servers/plugins/replication/Makefile
@@ -0,0 +1,152 @@
+#
+# 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 "Replication" plugin
+#
+#
+
+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 = $(OBJDIR)/lib/replication-plugin
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./replication.def
+endif
+
+CFLAGS += $(SLCFLAGS) -DSLAPD_LOGGING
+
+ifeq ($(ARCH), WINNT)
+CFLAGS += /WX
+endif
+
+ifdef TEST_CL5
+CFLAGS += -DTEST_CL5
+endif
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd -I$(DB_INCLUDE)
+
+LOCAL_OBJS= \
+ cl5_api.o \
+ cl5_clcache.o \
+ cl5_config.o \
+ cl5_init.o \
+ csnpl.o\
+ legacy_consumer.o \
+ llist.o\
+ repl5_agmt.o \
+ repl5_agmtlist.o \
+ repl5_backoff.o \
+ repl5_connection.o \
+ repl5_inc_protocol.o \
+ repl5_init.o\
+ repl5_protocol.o \
+ repl5_protocol_util.o \
+ repl5_replica.o\
+ repl5_replica_config.o\
+ repl5_ruv.o\
+ repl5_schedule.o \
+ repl5_tot_protocol.o \
+ repl5_total.o\
+ repl5_mtnode_ext.o\
+ repl5_plugins.o \
+ repl_add.o \
+ repl_bind.o \
+ repl_compare.o \
+ repl_connext.o \
+ repl_controls.o \
+ repl_delete.o \
+ repl_entry.o \
+ repl_ext.o \
+ repl_extop.o \
+ repl_globals.o \
+ repl_init.o \
+ repl_modify.o \
+ repl_modrdn.o \
+ repl_monitor.o \
+ repl_objset.o \
+ repl_opext.o \
+ repl_ops.o \
+ repl_rootdse.o \
+ repl_search.o \
+ replutil.o \
+ urp.o \
+ urp_glue.o \
+ urp_tombstone.o \
+ repl5_replica_hash.o\
+ repl5_replica_dnhash.o\
+ repl5_updatedn_list.o\
+
+LIBREPLICATION_OBJS = $(addprefix $(OBJDEST)/, $(LOCAL_OBJS))
+
+ifeq ($(ARCH), WINNT)
+REPLICATION_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+LIBREPLICATION= $(addprefix $(LIBDIR)/, $(REPLICATION_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(DB_LIB_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAPLINK) $(DB_LIB)
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(DB_LIB_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL) $(DB_LIB)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./replication.def"
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS += $(DLL_EXTRA_LIBS)
+LD=ld
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBREPLICATION)
+
+$(LIBREPLICATION): $(LIBREPLICATION_OBJS) $(REPLICATION_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBREPLICATION_OBJS) $(REPLICATION_DLL_OBJ) $(PLATFORMLIBS) $(EXTRA_LIBS) $(LDAP_LIBLDIF) $(NSPRLINK)
+
+tests: $(TEST_PROGS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(LIBREPLICATION_OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(REPLICATION_DLL_OBJ)
+endif
+ $(RM) $(LIBREPLICATION)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+#
+# header file dependencies (incomplete)
+#
+$(LIBREPLICATION_OBJS):
diff --git a/ldap/servers/plugins/replication/cl4.h b/ldap/servers/plugins/replication/cl4.h
new file mode 100644
index 00000000..0dbcece2
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl4.h
@@ -0,0 +1,65 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cl4.h - global declarations used by the 4.0 style changelog module
+ */
+
+#ifndef CL4_H
+#define CL4_H
+
+#include "slapi-private.h"
+#include "portable.h" /* GGOODREPL - is this cheating? */
+
+#define CONFIG_CHANGELOG_SUFFIX_ATTRIBUTE "nsslapd-changelogsuffix"
+
+/* A place to store changelog config info */
+typedef struct _chglog4Info chglog4Info;
+
+/* in cl4.c */
+chglog4Info* changelog4_new (Slapi_Entry *e, char *errorbuf);
+void changelog4_free (chglog4Info** cl4);
+void changelog4_lock (Object *obj, PRBool write);
+void changelog4_unlock (Object *obj);
+const char * changelog4_get_dir (const chglog4Info* cl4);
+const char * changelog4_get_suffix (const chglog4Info* cl4);
+time_t changelog4_get_maxage (const chglog4Info* cl4);
+unsigned long changelog4_get_maxentries (const chglog4Info* cl4);
+void changelog4_set_dir (chglog4Info* cl4, const char *dir);
+void changelog4_set_suffix (chglog4Info* cl4, const char *suffix);
+void changelog4_set_maxage (chglog4Info* cl4, const char *maxage);
+void changelog4_set_maxentries (chglog4Info* cl4, const char* maxentries);
+
+/* In cl4_suffix.c */
+char *get_changelog_dataversion(const chglog4Info* cl4);
+void set_changelog_dataversion(chglog4Info* cl4, const char *dataversion);
+
+/* In cl4_config.c */
+int changelog4_config_init();
+void changelog4_config_destroy();
+
+/*
+ * backend configuration information
+ * Previously, these two typedefs were in ../../slapd/slapi-plugin.h but
+ * the CL4 code is the only remaining code that references these definitions.
+ */
+typedef struct config_directive
+{
+ char *file_name; /* file from which to read directive */
+ int lineno; /* line to read */
+ int argc; /* number of argvs */
+ char **argv; /* directive in agrv format */
+} slapi_config_directive;
+
+typedef struct be_config
+{
+ char *type; /* type of the backend */
+ char *suffix; /* suffix of the backend */
+ int is_private; /* 1 - private, 0 -not */
+ int log_change; /* 1 - write change to the changelog; 0 - don't */
+ slapi_config_directive *directives;/* configuration directives */
+ int dir_count; /* number of directives */
+} slapi_be_config;
+
+#endif
diff --git a/ldap/servers/plugins/replication/cl4_api.c b/ldap/servers/plugins/replication/cl4_api.c
new file mode 100644
index 00000000..135b4a5b
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl4_api.c
@@ -0,0 +1,797 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cl4_api.h - implementation of the minimal interface to 4.0 changelog necessary to
+ link 4.0 changelog to 5.0 replication
+ */
+
+#include "repl.h"
+#include "cl4_api.h"
+#include "csnpl.h"
+#include "cl4.h"
+
+/*** Data Structures ***/
+
+/* changelog internal data */
+typedef struct cl4priv
+{
+ CSNPL *csnPL; /* csn pending list */
+ int regID; /* csn function registration id */
+}CL4Private;
+
+/* callback data to get result of internal operations */
+typedef struct cl4ret
+{
+ int err; /* error code */
+ Slapi_Entry *e; /* target entry */
+}CL4Ret;
+
+/* Global Data */
+static CL4Private s_cl4Desc; /* represents changelog state */
+
+/*** Helper functions forward declarations ***/
+static int _cl4WriteOperation (const slapi_operation_parameters *op);
+static void _cl4AssignCSNCallback (const CSN *csn, void *data);
+static void _cl4AbortCSNCallback (const CSN *csn, void *data);
+static char* _cl4MakeCSNDN (const CSN* csn);
+static int _cl4GetEntry (const CSN *csn, Slapi_Entry **entry);
+static void _cl4ResultCallback (int err, void *callback_data);
+static int _cl4EntryCallback (Slapi_Entry *e, void *callback_data);
+static PRBool _cl4CanAssignChangeNumber (const CSN *csn);
+static int _cl4ResolveTargetDN (Slapi_Entry *entry, Slapi_DN **newTargetDN);
+static int _cl4GetTargetEntry (Slapi_DN *targetDN, const char *uniqueid, Slapi_Entry **entry);
+static int _cl4FindTargetDN (const CSN *csn, const char *uniqueid,
+ const Slapi_DN *targetSDN, Slapi_DN **newTargetDN);
+static int _cl4AssignChangeNumber (changeNumber *cnum);
+static int _cl4UpdateEntry (const CSN *csn, const char *changeType, const Slapi_DN *newTargetDN, changeNumber cnum);
+
+/*** API ***/
+int cl4Init ()
+{
+ s_cl4Desc.csnPL = csnplNew ();
+ if (s_cl4Desc.csnPL == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4Init: failed to create CSN pending list\n");
+ return CL4_CSNPL_ERROR;
+ }
+
+ s_cl4Desc.regID = csnRegisterNewCSNCb(_cl4AssignCSNCallback, NULL,
+ _cl4AbortCSNCallback, NULL);
+
+ return CL4_SUCCESS;
+}
+
+void cl4Cleanup ()
+{
+ if (s_cl4Desc.regID >= 0)
+ {
+ csnRemoveNewCSNCb(s_cl4Desc.regID);
+ s_cl4Desc.regID = -1;
+ }
+
+ if (s_cl4Desc.csnPL == NULL)
+ csnplFree (&s_cl4Desc.csnPL);
+}
+
+int cl4WriteOperation (const slapi_operation_parameters *op)
+{
+ int rc;
+ ReplicaId rd;
+
+ if (op == NULL || !IsValidOperation (op))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4WriteEntry: invalid entry\n");
+ return CL4_BAD_DATA;
+ }
+
+ rc = _cl4WriteOperation (op);
+ if (rc != CL4_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4WriteEntry: failed to write changelog entry\n");
+ return rc;
+ }
+
+ /* the entry is generated by this server - remove the entry from the pending list */
+ rd= csn_get_replicaid(op->csn);
+ if (rd == slapi_get_replicaid ())
+ {
+ rc = csnplRemove (s_cl4Desc.csnPL, op->csn);
+
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "cl4WriteEntry: failed to remove CSN from the pending list\n");
+ rc = CL4_CSNPL_ERROR;
+ }
+ }
+
+ return rc;
+}
+
+int cl4ChangeTargetDN (const CSN *csn, const char *newDN)
+{
+ Slapi_PBlock *pb;
+ char *changeEntryDN;
+ Slapi_Mods smods;
+ int res;
+
+ if (csn == NULL || newDN == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4ChangeTargetDN: invalid argument\n");
+ return CL4_BAD_DATA;
+ }
+
+ /* construct dn of the change entry */
+ changeEntryDN = _cl4MakeCSNDN (csn);
+ if (changeEntryDN == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "cl4ChangeTargetDN: failed to construct change entry dn\n");
+ return CL4_MEMORY_ERROR;
+ }
+
+ pb = slapi_pblock_new ();
+
+ slapi_mods_init(&smods, 1);
+ slapi_mods_add(&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, attr_targetdn,
+ strlen (newDN), newDN);
+ slapi_modify_internal_set_pb(pb, changeEntryDN, slapi_mods_get_ldapmods_byref(&smods),
+ NULL, NULL, repl_get_plugin_identity(PLUGIN_LEGACY_REPLICATION), 0);
+ slapi_modify_internal_pb (pb);
+
+ slapi_mods_done(&smods);
+ slapi_ch_free ((void**)&changeEntryDN);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ slapi_pblock_destroy(pb);
+
+ if (res != LDAP_SUCCESS)
+ {
+ char s[CSN_STRSIZE];
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "cl4ChangeTargetDN: an error occured while modifying change entry with csn %s: %s. "
+ "Logging of changes is disabled.\n", csn_as_string(csn,PR_FALSE,s), ldap_err2string(res));
+ /* GGOODREPL g_set_repl_backend( NULL ); */
+ return CL4_LDAP_ERROR;
+ }
+
+ return CL4_SUCCESS;
+}
+
+void cl4AssignChangeNumbers (time_t when, void *arg)
+{
+ int rc = CL4_SUCCESS;
+ Slapi_Entry *entry;
+ CSN *csn = NULL;
+ Slapi_DN *newTargetDN;
+ changeNumber cnum;
+ char *changetype;
+
+ /* we are looping though the entries ready to be commited updating there target dn
+ and assigning change numbers */
+ while (_cl4GetEntry (csn, &entry) == CL4_SUCCESS)
+ {
+ /* ONREPL - I think we need to free previous csn */
+ csn = csn_new_by_string(slapi_entry_attr_get_charptr (entry, attr_csn));
+ /* all conflicts involving this entry have been resolved */
+ if (_cl4CanAssignChangeNumber (csn))
+ {
+ /* figure out the name of the target entry that corresponds to change csn */
+ rc = _cl4ResolveTargetDN (entry, &newTargetDN);
+ slapi_entry_free (entry);
+ if (rc != CL4_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "cl4AssignChangeNumbers: failed to resolve target dn\n");
+ break;
+ }
+
+ _cl4AssignChangeNumber (&cnum);
+
+ changetype = slapi_entry_attr_get_charptr (entry, attr_changetype);
+
+ /* update change entry: write change number and remove csn attribute.
+ Note that we leave uniqueid in the entry to avoid an extra update.
+ This is ok since uniqueid is an operational attribute not returned
+ to the client by default. */
+ rc = _cl4UpdateEntry (csn, changetype, newTargetDN, cnum);
+ if (newTargetDN)
+ {
+ slapi_sdn_free (&newTargetDN);
+ }
+
+ slapi_ch_free ((void**)&changetype);
+
+ if (rc != CL4_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "cl4AssignChangeNumbers: failed to update changelog entry\n");
+ break;
+ }
+ }
+ else /* went too far */
+ {
+ slapi_entry_free (entry);
+ break;
+ }
+ }
+}
+
+
+/*** Helper Functions ***/
+
+/* adds new change record to 4.0 changelog */
+static int _cl4WriteOperation (const slapi_operation_parameters *op)
+{
+ int rc = CL4_SUCCESS, res;
+ char *changeEntryDN, *timeStr;
+ Slapi_Entry *e;
+ Slapi_PBlock *pb = NULL;
+ Slapi_Value *values[3];
+ char s[CSN_STRSIZE];
+
+ slapi_log_error (SLAPI_LOG_PLUGIN, repl_plugin_name,
+ "_cl4WriteEntry: writing change record with csn %s for dn: \"%s\"\n",
+ csn_as_string(op->csn,PR_FALSE,s), op->target_address.dn);
+
+ /* create change entry dn */
+ changeEntryDN = _cl4MakeCSNDN (op->csn);
+ if (changeEntryDN == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_cl4WriteEntry: failed to create entry dn\n");
+ return CL4_MEMORY_ERROR;
+ }
+
+ /*
+ * Create the entry struct, and fill in fields common to all types
+ * of change records.
+ */
+ e = slapi_entry_alloc();
+ if (e == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_cl4WriteEntry: failed to allocate change entry\n");
+ return CL4_MEMORY_ERROR;
+ }
+
+ slapi_entry_set_dn(e, slapi_ch_strdup (changeEntryDN));
+
+ /* Set the objectclass attribute */
+ values [0] = slapi_value_new (NULL);
+ values [1] = slapi_value_new (NULL);
+ values [2] = NULL;
+ slapi_value_set_string(values[0], "top");
+ slapi_value_set_string(values[1], "changelogentry");
+ slapi_entry_add_values_sv (e, "objectclass", values);
+
+ /* ONREPL - for now we have to free Slapi_Values since api makes copy;
+ this will change when a new set of api is added */
+ slapi_value_free (&(values[0]));
+ slapi_value_free (&(values[1]));
+
+ /* Set the changeNumber attribute */
+ /* Need to set this because it is required by schema */
+ slapi_entry_attr_set_charptr (e, attr_changenumber, "0");
+
+ /* Set the targetentrydn attribute */
+ if (op->operation_type == SLAPI_OPERATION_ADD) /* use raw dn */
+ slapi_entry_attr_set_charptr (e, attr_targetdn, slapi_entry_get_dn (op->p.p_add.target_entry));
+ else /* use normolized dn */
+ slapi_entry_attr_set_charptr (e, attr_targetdn, op->target_address.dn);
+
+ /* ONREPL - set dbid attribute */
+
+ /* Set the changeTime attribute */
+ timeStr = format_localTime (current_time());
+ slapi_entry_attr_set_charptr (e, attr_changetime, timeStr);
+ slapi_ch_free((void**)&timeStr);
+
+ /*
+ * Finish constructing the entry. How to do it depends on the type
+ * of modification being logged.
+ */
+ switch (op->operation_type)
+ {
+ case SLAPI_OPERATION_ADD: if (entry2reple(e, op->p.p_add.target_entry) != 0 )
+ {
+ rc = CL4_INTERNAL_ERROR;
+ goto done;
+ }
+
+ break;
+
+ case SLAPI_OPERATION_MODIFY: if (mods2reple(e, op->p.p_modify.modify_mods) != 0)
+ {
+ rc = CL4_INTERNAL_ERROR;
+ goto done;
+ }
+
+ break;
+
+ case SLAPI_OPERATION_MODDN: if (modrdn2reple(e, op->p.p_modrdn.modrdn_newrdn,
+ op->p.p_modrdn.modrdn_deloldrdn, op->p.p_modrdn.modrdn_mods) != 0)
+ {
+ rc = CL4_INTERNAL_ERROR;
+ goto done;
+ }
+
+ break;
+
+ case SLAPI_OPERATION_DELETE: /* Set the changetype attribute */
+ slapi_entry_attr_set_charptr (e, attr_changetype, "delete");
+ break;
+ }
+
+ pb = slapi_pblock_new (pb);
+ slapi_add_entry_internal_set_pb (pb, e, NULL, repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0);
+ slapi_add_internal_pb (pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ slapi_pblock_destroy(pb);
+
+ if (res != LDAP_SUCCESS)
+ {
+ char s[CSN_STRSIZE];
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "_cl4WriteEntry: an error occured while adding change entry with csn %s, dn = %s: %s. "
+ "Logging of changes is disabled.\n", csn_as_string(op->csn,PR_FALSE,s), op->target_address.dn,
+ ldap_err2string(res));
+ /* GGOODREPL g_set_repl_backend( NULL ); */
+ rc = CL4_LDAP_ERROR;
+ }
+
+done:
+ if (changeEntryDN)
+ slapi_ch_free((void **) &changeEntryDN);
+
+ return rc;
+}
+
+static void _cl4AssignCSNCallback (const CSN *csn, void *data)
+{
+ int rc;
+
+ if (csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4AssignCSNCallback: null csn\n");
+ return;
+ }
+
+ rc = csnplInsert (s_cl4Desc.csnPL, csn);
+
+ if (rc == -1)
+ {
+ char s[CSN_STRSIZE];
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_cl4AssignCSNCallback: failed to insert csn %s to the pending list\n",
+ csn_as_string(csn,PR_FALSE,s));
+ }
+}
+
+static void _cl4AbortCSNCallback (const CSN *csn, void *data)
+{
+ int rc;
+
+ if (csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4AbortCSNCallback: null csn\n");
+ return;
+ }
+
+ rc = csnplRemove (s_cl4Desc.csnPL, csn);
+ if (rc == -1)
+ {
+ char s[CSN_STRSIZE];
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_cl4AbortCSNCallback: failed to remove csn %s from the pending list\n",
+ csn_as_string(csn,PR_FALSE,s));
+ }
+}
+
+/* initial dn format: csn=<csn>,<changelog suffix>. For instance, csn=013744022939465,cn=changelog4 */
+static char* _cl4MakeCSNDN (const CSN* csn)
+{
+ char *pat, *edn;
+ char *suffix = changelog4_get_suffix ();
+ char s[CSN_STRSIZE];
+
+ if (suffix == NULL)
+ return NULL;
+
+ /* Construct the dn of this change record */
+ pat = "%s=%s,%s";
+ edn = slapi_ch_malloc(strlen(pat) + strlen(attr_csn) + strlen(suffix) + CSN_STRSIZE + 1);
+ if (edn)
+ sprintf(edn, pat, attr_csn, csn_as_string(csn,PR_FALSE,s), suffix);
+ slapi_ch_free ((void **)&suffix);
+
+ return edn;
+}
+
+static int _cl4GetEntry (const CSN *csn, Slapi_Entry **entry)
+{
+ int rc;
+ char *suffix = changelog4_get_suffix ();
+ int type;
+ const char *value;
+ CL4Ret ret;
+ char s[CSN_STRSIZE];
+
+ if (csn == NULL) /* entry with smallest csn */
+ {
+ type = SLAPI_SEQ_FIRST;
+ value = NULL;
+ }
+ else /* entry with next csn */
+ {
+ type = SLAPI_SEQ_NEXT;
+ value = csn_as_string(csn,PR_FALSE,s);
+ }
+
+ rc = slapi_seq_callback(suffix, type, attr_csn, (char*)value, NULL, 0, &ret, NULL,
+ _cl4ResultCallback, _cl4EntryCallback, NULL);
+ slapi_ch_free ((void**)&suffix);
+
+ if (rc != 0 || ret.err != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4GetEntry: failed to get next changelog entry\n");
+ return CL4_INTERNAL_ERROR;
+ }
+
+ *entry = ret.e;
+ return CL4_SUCCESS;
+}
+
+static void _cl4ResultCallback (int err, void *callback_data)
+{
+ CL4Ret *ret = (CL4Ret *)callback_data;
+
+ if (ret)
+ {
+ ret->err = err;
+ }
+}
+
+static int _cl4EntryCallback (Slapi_Entry *e, void *callback_data)
+{
+ CL4Ret *ret = (CL4Ret *)callback_data;
+
+ if (ret)
+ {
+ ret->e = slapi_entry_dup (e);
+ }
+
+ return 0;
+}
+
+static PRBool _cl4CanAssignChangeNumber (const CSN *csn)
+{
+ CSN *commitCSN = NULL;
+
+ /* th CSN is withtin region that can be commited */
+ if (csn && csn_compare(csn, commitCSN) < 0)
+ return PR_TRUE;
+
+ return PR_FALSE;
+}
+
+/* ONREPL - describe algorithm */
+static int _cl4ResolveTargetDN (Slapi_Entry *entry, Slapi_DN **newTargetDN)
+{
+ int rc;
+ char *csnStr = slapi_entry_attr_get_charptr (entry, attr_csn);
+ char *targetdn = slapi_entry_attr_get_charptr (entry, attr_targetdn);
+ const char *uniqueid = slapi_entry_get_uniqueid (entry);
+ char *changetype = slapi_entry_attr_get_charptr (entry, attr_changetype);
+ CSN *csn = csn_new_by_string (csnStr);
+ Slapi_Entry *targetEntry = NULL;
+ const Slapi_DN *teSDN;
+ Slapi_DN *targetSDN;
+ const CSN *teDNCSN = NULL;
+
+ *newTargetDN = NULL;
+
+ targetSDN = slapi_sdn_new();
+ if (strcasecmp (changetype, "add") == 0) /* this is add operation - we have rawdn */
+ slapi_sdn_set_dn_byref (targetSDN, targetdn);
+ else
+ slapi_sdn_set_ndn_byref (targetSDN, targetdn);
+
+ /* read the entry to which the change was applied */
+ rc = _cl4GetTargetEntry (targetSDN, uniqueid, &targetEntry);
+ if (rc != CL4_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4ResolveTargetDN: failed to get target entry\n");
+ goto done;
+ }
+
+ teDNCSN = entry_get_dncsn(targetEntry);
+ if (teDNCSN == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4ResolveTargetDN: failed to get target entry dn\n");
+ rc = CL4_BAD_FORMAT;
+ goto done;
+ }
+
+ if (csn_compare(teDNCSN, csn) <= 0)
+ {
+ /* the change entry target dn should be the same as target entry dn */
+ teSDN = slapi_entry_get_sdn_const(targetEntry);
+
+ /* target dn of change entry is not the same as dn of the target entry - update */
+ if (slapi_sdn_compare (teSDN, targetSDN) != 0)
+ {
+ *newTargetDN = slapi_sdn_dup (targetSDN);
+ }
+ }
+ else /* the target entry was renamed since this change occur - find the right target dn */
+ {
+ rc = _cl4FindTargetDN (csn, uniqueid, targetSDN, newTargetDN);
+ }
+
+done:;
+ if (csnStr)
+ slapi_ch_free ((void**)&csnStr);
+
+ if (targetdn)
+ slapi_ch_free ((void**)&targetdn);
+
+ if (uniqueid)
+ slapi_ch_free ((void**)&uniqueid);
+
+ if (changetype)
+ slapi_ch_free ((void**)&changetype);
+
+ if (targetEntry)
+ slapi_entry_free (targetEntry);
+
+ if (targetSDN)
+ slapi_sdn_free (&targetSDN);
+
+ return rc;
+}
+
+static int _cl4GetTargetEntry (Slapi_DN *sdn, const char *uniqueid, Slapi_Entry **entry)
+{
+ Slapi_PBlock *pb;
+ char filter [128];
+ int res, rc = CL4_SUCCESS;
+ Slapi_Entry **entries = NULL;
+
+ /* read corresponding database entry based on its uniqueid */
+ sprintf (filter, "uniqueid=%s", uniqueid);
+ pb = slapi_pblock_new ();
+ slapi_search_internal_set_pb (pb, (char*)slapi_sdn_get_ndn(sdn), LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL,
+ repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0);
+ slapi_search_internal_pb (pb);
+
+ if (pb == NULL)
+ {
+ rc = CL4_LDAP_ERROR;
+ goto done;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ if (res == LDAP_NO_SUCH_OBJECT) /* entry not found */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4GetTargetEntry: entry (%s) not found\n",
+ slapi_sdn_get_ndn(sdn));
+ rc = CL4_NOT_FOUND;
+ goto done;
+ }
+
+ if (res != LDAP_SUCCESS)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "_cl4ResolveTargetDN: an error occured while searching for directory entry with uniqueid %s: %s. "
+ "Logging of changes is disabled.\n", uniqueid, ldap_err2string(res));
+ /* GGOODREPL g_set_repl_backend( NULL ); */
+ rc = CL4_LDAP_ERROR;
+ goto done;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (entries == NULL || entries [0] == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4GetTargetEntry: entry (%s) not found\n",
+ slapi_sdn_get_ndn(sdn));
+ rc = CL4_NOT_FOUND;
+ goto done;
+ }
+
+ *entry = slapi_entry_dup (entries[0]);
+
+done:
+ if (pb)
+ {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy (pb);
+ }
+
+ return rc;
+}
+
+static int _cl4FindTargetDN (const CSN *csn, const char *uniqueid,
+ const Slapi_DN *targetSDN, Slapi_DN **newTargetDN)
+{
+ int rc = CL4_SUCCESS;
+ int res, i;
+ Slapi_PBlock *pb;
+ char *suffix = changelog4_get_suffix ();
+ char filter [128];
+ Slapi_Entry **entries;
+ int minIndex = 0;
+ CSN *minCSN = NULL, *curCSN;
+ char *curType;
+ const Slapi_DN *sdn;
+ char s[CSN_STRSIZE];
+
+ *newTargetDN = NULL;
+
+ /* Look for all modifications to the target entry with csn larger than
+ this csn. We are only interested in rename operations, but change type
+ is currently not indexed */
+ sprintf (filter, "&(uniqueid=%s)(csn>%s)", uniqueid, csn_as_string(csn,PR_FALSE,s));
+ pb = slapi_pblock_new ();
+ slapi_search_internal_set_pb (pb, suffix, LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL,
+ repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0);
+ slapi_search_internal_pb (pb);
+ slapi_ch_free ((void**)&suffix);
+ if (pb == NULL)
+ {
+ rc = CL4_LDAP_ERROR;
+ goto done;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ if (res == LDAP_NO_SUCH_OBJECT) /* entry not found */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4FindTargetDN: no entries much filter (%s)\n",
+ filter);
+ rc = CL4_NOT_FOUND;
+ goto done;
+ }
+
+ if (res != LDAP_SUCCESS)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "_cl4ResolveTargetDN: an error occured while searching change entries matching filter %s: %s. "
+ "Logging of changes is disabled.\n", filter, ldap_err2string(res));
+ /* GGOODREPL g_set_repl_backend( NULL ); */
+ rc = CL4_LDAP_ERROR;
+ goto done;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (entries == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4FindTargetDN: no entries much filter (%s)\n",
+ filter);
+ rc = CL4_NOT_FOUND;
+ goto done;
+ }
+
+ i = 0;
+
+ /* find rename operation with smallest csn - its target dn should be the name
+ of our change entry */
+ while (entries[i])
+ {
+ curType = slapi_entry_attr_get_charptr (entries[i], attr_changetype);
+ if (curType && strcasecmp (curType, "modrdn") == 0)
+ {
+ curCSN = csn_new_by_string (slapi_entry_attr_get_charptr (entries[i], attr_csn));
+ if (minCSN == NULL || csn_compare (curCSN, minCSN) < 0)
+ {
+ minCSN = curCSN;
+ minIndex = i;
+ }
+ }
+
+ if (curType)
+ slapi_ch_free ((void**)&curType);
+
+ i ++;
+ }
+
+ if (curCSN == NULL)
+ {
+ rc = CL4_NOT_FOUND;
+ goto done;
+ }
+
+ /* update targetDN of our entry if necessary */
+ sdn = slapi_entry_get_sdn_const(entries[minIndex]);
+
+ /* target dn does not match to renaming operation - rename change entry */
+ if (slapi_sdn_compare (sdn, targetSDN) != 0)
+ *newTargetDN = slapi_sdn_dup (sdn);
+
+done:
+ if (pb)
+ {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy (pb);
+ }
+
+ return rc;
+}
+
+static int _cl4AssignChangeNumber (changeNumber *cnum)
+{
+ *cnum = ldapi_assign_changenumber();
+ return CL4_SUCCESS;
+}
+
+static int _cl4UpdateEntry (const CSN *csn, const char *changeType,
+ const Slapi_DN *newDN, changeNumber cnum)
+{
+ Slapi_PBlock *pb;
+ char *dn;
+ const char *dnTemp;
+ int res;
+ Slapi_Mods smods;
+ char cnumbuf[32];
+
+ if (csn == NULL || changeType == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4UpdateEntry: invalid argument\n");
+ return CL4_BAD_DATA;
+ }
+
+ dn = _cl4MakeCSNDN (csn);
+ if (dn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_cl4UpdateEntry: failed to create entry dn\n");
+ return CL4_MEMORY_ERROR;
+ }
+
+ slapi_mods_init(&smods, 2);
+ if (newDN)
+ {
+ if (strcasecmp (changeType, "add") == 0)
+ dnTemp = slapi_sdn_get_dn (newDN);
+ else
+ dnTemp = slapi_sdn_get_ndn (newDN);
+
+ slapi_mods_add(&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, attr_targetdn,
+ strlen (dnTemp), dnTemp);
+ }
+ /* Set the changeNumber attribute */
+ sprintf(cnumbuf, "%lu", cnum);
+ slapi_mods_add (&smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, attr_changenumber,
+ strlen (cnumbuf), cnumbuf);
+ pb = slapi_pblock_new ();
+ slapi_modify_internal_set_pb (pb, dn, slapi_mods_get_ldapmods_byref(&smods), NULL, NULL,
+ repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION), 0);
+ slapi_modify_internal_pb (pb);
+ slapi_mods_done(&smods);
+ slapi_ch_free ((void**)&dn);
+
+ if (pb == NULL)
+ {
+ return CL4_LDAP_ERROR;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ slapi_pblock_destroy(pb);
+ if (res != LDAP_SUCCESS)
+ {
+ char s[CSN_STRSIZE];
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "cl4ChangeTargetDN: an error occured while modifying change entry with csn %s: %s. "
+ "Logging of changes is disabled.\n", csn_as_string(csn,PR_FALSE,s), ldap_err2string(res));
+ /* GGOODREPL g_set_repl_backend( NULL ); */
+ return CL4_LDAP_ERROR;
+ }
+
+ if ( ldapi_get_first_changenumber() == (changeNumber) 0L )
+ {
+ ldapi_set_first_changenumber( cnum );
+ }
+
+ ldapi_commit_changenumber(cnum);
+ return CL4_SUCCESS;
+}
diff --git a/ldap/servers/plugins/replication/cl4_api.h b/ldap/servers/plugins/replication/cl4_api.h
new file mode 100644
index 00000000..c0b20e57
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl4_api.h
@@ -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 **/
+/* cl4_api.h - minimal interface to 4.0 changelog necessary to link 4.0 changelog
+ to 5.0 replication
+ */
+
+#ifndef CL4_API_H
+#define CL4_API_H
+
+#include "repl.h"
+
+/*** Error Codes ***/
+enum
+{
+ CL4_SUCCESS,
+ CL4_BAD_DATA,
+ CL4_BAD_FORMAT,
+ CL4_NOT_FOUND,
+ CL4_MEMORY_ERROR,
+ CL4_CSNPL_ERROR,
+ CL4_LDAP_ERROR,
+ CL4_INTERNAL_ERROR
+};
+
+/*** APIs ***/
+/* Name: cl4Init
+ Description: initializes 4.0 changelog subsystem
+ Parameters: none
+ Return: ????
+ */
+int cl4Init ();
+
+/* Name: cl4WriteOperation
+ Description: logs operation to 4.0 changelog; operation must go through CD&R engine first
+ Parameters: op - operation to be logged
+
+ Return: ????
+ */
+int cl4WriteOperation (const slapi_operation_parameters *op);
+
+/* Name: cl4ChangeTargetDN
+ Description: modifies change entry target dn; should be called for conflicts due to naming collisions;
+ raw dn should be passed for add operations; normolized dn otherwise.
+ Parameters: csn - csn of the change entry to be modified
+ newDN - new target dn of the entry
+ Return: ????
+ */
+int cl4ChangeTargetDN (const CSN* csn, const char *newDN);
+
+/* Name: cl4AssignChangeNumbers
+ Description: this function should be called periodically to assign change numbers to changelog
+ entries. Intended for use with event queue
+ Parameters: parameters are not currently used
+ Return: none
+ */
+void cl4AssignChangeNumbers (time_t when, void *arg);
+
+/* Name: cl4Cleanup
+ Description: frees memory held by 4.0 changelog subsystem
+ Parameters: none
+ Return: none
+ */
+void cl4Clean ();
+#endif
diff --git a/ldap/servers/plugins/replication/cl4_init.c b/ldap/servers/plugins/replication/cl4_init.c
new file mode 100644
index 00000000..6c12f0b0
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl4_init.c
@@ -0,0 +1,349 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* cl4_init.c - implments initialization/cleanup functions for
+ 4.0 style changelog
+ */
+
+#include <string.h>
+
+#include "slapi-plugin.h"
+#include "cl4.h"
+#include "repl.h"
+
+/* forward declarations */
+static int changelog4_create_be();
+static int changelog4_start_be ();
+static int changelog4_close();
+static int changelog4_remove();
+
+/*
+ * Initialise the 4.0 Changelog
+ */
+int changelog4_init ()
+{
+ int rc= 0; /* OK */
+ Slapi_Backend *rbe;
+ changeNumber first_change = 0UL, last_change = 0UL;
+ int lderr;
+
+ if (changelog4_create_be() < 0 )
+ {
+ rc= -1;
+ }
+ else
+ {
+ rc = changelog4_start_be ();
+ }
+
+ if(rc == 0)
+ {
+ rbe = get_repl_backend();
+ if(rbe!=NULL)
+ {
+ /* We have a Change Log. Check it's valid. */
+ /* changelog has to be started before its
+ data version can be read */
+ const char *sdv= get_server_dataversion();
+ const char *cdv= get_changelog_dataversion();
+ char *suffix = changelog4_get_suffix ();
+ if(!cdv || strcmp(sdv,cdv)!=0)
+ {
+
+ /* The SDV and CDV are not the same. The Change Log is invalid.
+ It must be removed. */
+ /* ONREPL - currently we go through this code when the changelog
+ is first created because we can't tell new backend from the
+ existing one.*/
+ rc = changelog4_close();
+ rc = changelog4_remove();
+
+ /* now restart the changelog */
+ changelog4_start_be ();
+
+ create_entity( suffix, "extensibleobject");
+ /* Write the Server Data Version onto the changelog suffix entry */
+ /* JCMREPL - And the changelog database version number */
+ set_changelog_dataversion(sdv);
+ slapi_ch_free ((void **)&suffix);
+
+ }
+ }
+ }
+
+ if(rc != 0)
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name,
+ "An error occurred configuring the changelog database\n" );
+ }
+
+ first_change = replog_get_firstchangenum( &lderr );
+ last_change = replog_get_lastchangenum( &lderr );
+ ldapi_initialize_changenumbers( first_change, last_change );
+
+ return rc;
+}
+
+static int
+
+changelog4_close()
+{
+ int rc= 0 /* OK */;
+ Slapi_Backend *rbe= get_repl_backend();
+ Slapi_PBlock *pb = slapi_pblock_new ();
+ IFP closefn = NULL;
+
+ rc = slapi_be_getentrypoint (rbe, SLAPI_PLUGIN_CLOSE_FN, (void**)&closefn, pb);
+ if (rc != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Error: backend close entry point is missing. "
+ "Replication subsystem disabled.\n");
+ slapi_pblock_destroy (pb);
+ set_repl_backend( NULL );
+ return -1;
+ }
+
+ rc = closefn (pb);
+
+ if (rc != 0)
+ {
+
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Error: the changelog database could "
+ "not be closed. Replication subsystem disabled.\n");
+ set_repl_backend( NULL );
+ rc = -1;
+ }
+
+ slapi_pblock_destroy (pb);
+ return rc;
+
+}
+
+static int
+changelog4_remove()
+{
+ int rc= 0 /* OK */;
+ Slapi_Backend *rbe= get_repl_backend();
+ Slapi_PBlock *pb = slapi_pblock_new ();
+ IFP rmdbfn = NULL;
+
+ rc = slapi_be_getentrypoint (rbe, SLAPI_PLUGIN_DB_RMDB_FN, (void**)&rmdbfn, pb);
+ if (rc != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Error: backend rmdb entry point is missing. "
+ "Replication subsystem disabled.\n");
+ slapi_pblock_destroy (pb);
+ set_repl_backend( NULL );
+ return -1;
+ }
+
+ rc = rmdbfn (pb);
+
+ if (rc != 0)
+ {
+
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name, "Error: the changelog database could "
+ "not be removed. Replication subsystem disabled.\n");
+ rc = -1;
+ }
+ else
+ {
+ slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name, "New database generation computed. "
+ "Changelog database removed.\n");
+ }
+
+ slapi_pblock_destroy (pb);
+ return rc;
+}
+
+static Slapi_Backend *repl_backend = NULL;
+
+Slapi_Backend
+*get_repl_backend()
+{
+ return repl_backend;
+}
+
+void
+set_repl_backend(Slapi_Backend *be)
+{
+ repl_backend = be;
+}
+
+
+int changelog4_shutdown ()
+{
+ /* ONREPL - will shutdown the backend */
+ int rc = 1;
+
+ return rc;
+}
+
+static void changelog4_init_trimming ()
+{
+ char *cl_maxage = changelog4_get_maxage ();
+ unsigned long cl_maxentries = changelog4_get_maxentries ();
+ time_t ageval = age_str2time (cl_maxage);
+
+ slapi_ch_free ((void **)&cl_maxage);
+
+ init_changelog_trimming(cl_maxentries, ageval );
+}
+
+
+
+/*
+ * Function: changelog4_create_be
+ * Arguments: none
+ * Returns: 0 on success, non-0 on error
+ * Description: configures changelog backend instance.
+ */
+
+static int
+changelog4_create_be()
+{
+ int i, dir_count = 5;
+ Slapi_Backend *rbe;
+ slapi_be_config config;
+ char *cl_dir = changelog4_get_dir ();
+ char *cl_suffix;
+
+ if ( cl_dir == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Error: no directory specified for changelog database.\n");
+ return -1;
+ }
+
+ cl_suffix = changelog4_get_suffix ();
+
+ if ( cl_suffix == NULL ) {
+ slapi_ch_free ((void **)&cl_dir);
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Error: no suffix specified for changelog database.\n");
+ return -1;
+ }
+
+ /* setup configuration parameters for backend initialization */
+ config.type = CHANGELOG_LDBM_TYPE;
+ config.suffix = cl_suffix;
+ config.is_private = 1; /* yes */
+ config.log_change = 0; /* no */
+ config.directives = (slapi_config_directive*)slapi_ch_calloc(
+ dir_count, sizeof(slapi_config_directive));
+ config.dir_count = dir_count;
+
+ for (i = 0; i < dir_count; i++)
+ {
+ config.directives[i].file_name = "(internal)";
+ config.directives[i].lineno = 0;
+ }
+
+ /* setup indexes */
+ config.directives[0].argv = NULL;
+ config.directives[0].argc = 3;
+ charray_add( &(config.directives[0].argv), slapi_ch_strdup( "index" ));
+ charray_add( &(config.directives[0].argv), slapi_ch_strdup( attr_changenumber ));
+ charray_add( &(config.directives[0].argv), slapi_ch_strdup( "eq" ));
+
+ /* Set up the database directory */
+ config.directives[1].argv = NULL;
+ config.directives[1].argc = 2;
+ charray_add( &(config.directives[1].argv), slapi_ch_strdup( "directory" ));
+ charray_add( &(config.directives[1].argv), slapi_ch_strdup( cl_dir ));
+
+ /* Override the entry cache size */
+ config.directives[2].argv = NULL;
+ config.directives[2].argc = 2;
+ charray_add( &(config.directives[2].argv), slapi_ch_strdup( "cachesize" ));
+ charray_add( &(config.directives[2].argv), slapi_ch_strdup( "10" ));
+
+ /* Override the database cache size */
+ config.directives[3].argv = NULL;
+ config.directives[3].argc = 2;
+ charray_add( &(config.directives[3].argv), slapi_ch_strdup( "dbcachesize" ));
+ charray_add( &(config.directives[3].argv), slapi_ch_strdup( "1000000" ));
+
+ /* Override the allids threshold */
+ config.directives[4].argv = NULL;
+ config.directives[4].argc = 2;
+ charray_add( &(config.directives[4].argv), slapi_ch_strdup( "allidsthreshold" ));
+ /* assumes sizeof(int) >= 32 bits */
+ charray_add( &(config.directives[4].argv), slapi_ch_strdup( "2147483647" ));
+
+ /* rbe = slapi_be_create_instance(&config, LDBM_TYPE); */
+ rbe= NULL;
+
+ /* free memory allocated to argv */
+ for (i = 0; i < dir_count; i++)
+ {
+ charray_free (config.directives[i].argv);
+ }
+
+ slapi_ch_free ((void **)&config.directives);
+ slapi_ch_free ((void **)&cl_dir);
+ slapi_ch_free ((void **)&cl_suffix);
+
+ if (rbe == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Error: failed to create changelog backend. "
+ "Replication disabled.\n");
+ return -1;
+ }
+
+ set_repl_backend (rbe);
+
+ changelog4_init_trimming ();
+
+ return 0;
+}
+
+/* Name: changelog4_start_be
+ * Parameters: none
+ * Return: 0 if successful, non 0 otherwise
+ * Description: starts the changelog backend; backend must be configured
+ * first via call to changelog4_create_be
+ */
+static int
+changelog4_start_be ()
+{
+ int rc;
+ IFP startfn = NULL;
+ Slapi_PBlock *pb;
+ Slapi_Backend *rbe = get_repl_backend ();
+
+ if (rbe)
+ {
+ pb = slapi_pblock_new();
+ rc = slapi_be_getentrypoint(rbe, SLAPI_PLUGIN_START_FN, (void**)&startfn, pb);
+ if (rc != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Error: backend start entry point is missing. "
+ "Replication subsystem disabled.\n");
+ slapi_pblock_destroy (pb);
+ set_repl_backend( NULL );
+ return -1;
+ }
+
+ rc = startfn (pb);
+ slapi_pblock_destroy (pb);
+
+ if (rc != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Error: Failed to start changelog backend. "
+ "Replication subsystem disabled.\n");
+ set_repl_backend( NULL );
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
diff --git a/ldap/servers/plugins/replication/cl5.h b/ldap/servers/plugins/replication/cl5.h
new file mode 100644
index 00000000..a80c666b
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl5.h
@@ -0,0 +1,38 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cl5.h - changelog related function */
+
+#ifndef CL5_H
+#define CL5_H
+
+#include "cl5_api.h" /* changelog access APIs */
+
+typedef struct changelog5Config
+{
+ char *dir;
+/* These 2 parameters are needed for changelog trimming. Already present in 5.0 */
+ char *maxAge;
+ int maxEntries;
+/* the changelog DB configuration parameters are defined as CL5DBConfig in cl5_api.h */
+ CL5DBConfig dbconfig;
+}changelog5Config;
+
+/* initializes changelog*/
+int changelog5_init();
+/* cleanups changelog data */
+void changelog5_cleanup();
+/* initializes changelog configurationd */
+int changelog5_config_init();
+/* cleanups config data */
+void changelog5_config_cleanup();
+/* reads changelog configuration */
+int changelog5_read_config (changelog5Config *config);
+/* cleanups the content of the config structure */
+void changelog5_config_done (changelog5Config *config);
+/* frees the content and the config structure */
+void changelog5_config_free (changelog5Config **config);
+
+#endif
diff --git a/ldap/servers/plugins/replication/cl5_api.c b/ldap/servers/plugins/replication/cl5_api.c
new file mode 100644
index 00000000..792d3646
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl5_api.c
@@ -0,0 +1,6512 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* cl5_api.c - implementation of 5.0 style changelog API */
+
+#include <errno.h>
+#include <sys/stat.h>
+#if defined( OS_solaris ) || defined( hpux )
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#endif
+#if defined( linux )
+#include <sys/vfs.h>
+#endif
+
+
+#include "cl5_api.h"
+#include "plhash.h"
+
+#include "db.h"
+#include "cl5_clcache.h" /* To use the Changelog Cache */
+#include "repl5.h" /* for agmt_get_consumer_rid() */
+
+#define CL5_TYPE "Changelog5" /* changelog type */
+#define VERSION_SIZE 127 /* size of the buffer to hold changelog version */
+#define GUARDIAN_FILE "guardian" /* name of the guardian file */
+#define VERSION_FILE "DBVERSION" /* name of the version file */
+#define MAX_TRIALS 50 /* number of retries on db operations */
+#define V_5 5 /* changelog entry version */
+#define CHUNK_SIZE 64*1024
+#define DBID_SIZE 64
+#define FILE_SEP "_" /* separates parts of the db file name */
+
+#define T_CSNSTR "csn"
+#define T_UNIQUEIDSTR "nsuniqueid"
+#define T_PARENTIDSTR "parentuniqueid"
+#define T_NEWSUPERIORDNSTR "newsuperiordn"
+#define T_NEWSUPERIORIDSTR "newsuperioruniqueid"
+#define T_REPLGEN "replgen"
+
+#define ENTRY_COUNT_TIME 111 /* this time is used to construct csn
+ used to store/retrieve entry count */
+#define PURGE_RUV_TIME 222 /* this time is used to construct csn
+ used to store purge RUV vector */
+#define MAX_RUV_TIME 333 /* this time is used to construct csn
+ used to store upper boundary RUV vector */
+
+#define DB_EXTENSION_DB3 "db3"
+#define DB_EXTENSION "db4"
+
+#define HASH_BACKETS_COUNT 16 /* number of buckets in a hash table */
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4100
+#define DEFAULT_DB_OP_FLAGS DB_AUTO_COMMIT
+#define DB_OPEN(oflags, db, txnid, file, database, type, flags, mode, rval) \
+{ \
+ if (((oflags) & DB_INIT_TXN) && ((oflags) & DB_INIT_LOG)) \
+ { \
+ (rval) = (db)->open((db), (txnid), (file), (database), (type), (flags)|DB_AUTO_COMMIT, (mode)); \
+ } \
+ else \
+ { \
+ (rval) = (db)->open((db), (txnid), (file), (database), (type), (flags), (mode)); \
+ } \
+}
+#else /* older then db 41 */
+#define DEFAULT_DB_OP_FLAGS 0
+#define DB_OPEN(oflags, db, txnid, file, database, type, flags, mode, rval) \
+ (rval) = (db)->open((db), (file), (database), (type), (flags), (mode))
+#endif
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4000
+#define DB_ENV_SET_REGION_INIT(env) (env)->set_flags((env), DB_REGION_INIT, 1)
+#define DB_ENV_SET_TAS_SPINS(env, tas_spins) \
+ (env)->set_tas_spins((env), (tas_spins))
+#define TXN_BEGIN(env, parent_txn, tid, flags) \
+ (env)->txn_begin((env), (parent_txn), (tid), (flags))
+#define TXN_COMMIT(txn, flags) (txn)->commit((txn), (flags))
+#define TXN_ABORT(txn) (txn)->abort(txn)
+#define TXN_CHECKPOINT(env, kbyte, min, flags) \
+ (env)->txn_checkpoint((env), (kbyte), (min), (flags))
+#define MEMP_STAT(env, gsp, fsp, flags, malloc) \
+ (env)->memp_stat((env), (gsp), (fsp), (flags))
+#define MEMP_TRICKLE(env, pct, nwrotep) \
+ (env)->memp_trickle((env), (pct), (nwrotep))
+#define LOG_ARCHIVE(env, listp, flags, malloc) \
+ (env)->log_archive((env), (listp), (flags))
+#define LOG_FLUSH(env, lsn) (env)->log_flush((env), (lsn))
+#define LOCK_DETECT(env, flags, atype, aborted) \
+ (env)->lock_detect((env), (flags), (atype), (aborted))
+
+#else /* older than db 4.0 */
+#define DB_ENV_SET_REGION_INIT(env) db_env_set_region_init(1)
+#define DB_ENV_SET_TAS_SPINS(env, tas_spins) \
+ db_env_set_tas_spins((tas_spins))
+#define TXN_BEGIN(env, parent_txn, tid, flags) \
+ txn_begin((env), (parent_txn), (tid), (flags))
+#define TXN_COMMIT(txn, flags) txn_commit((txn), (flags))
+#define TXN_ABORT(txn) txn_abort((txn))
+#define TXN_CHECKPOINT(env, kbyte, min, flags) \
+ txn_checkpoint((env), (kbyte), (min), (flags))
+#define MEMP_TRICKLE(env, pct, nwrotep) memp_trickle((env), (pct), (nwrotep))
+#define LOG_FLUSH(env, lsn) log_flush((env), (lsn))
+#define LOCK_DETECT(env, flags, atype, aborted) \
+ lock_detect((env), (flags), (atype), (aborted))
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3300
+#define MEMP_STAT(env, gsp, fsp, flags, malloc) memp_stat((env), (gsp), (fsp))
+#define LOG_ARCHIVE(env, listp, flags, malloc) \
+ log_archive((env), (listp), (flags))
+
+#else /* older than db 3.3 */
+#define MEMP_STAT(env, gsp, fsp, flags, malloc) \
+ memp_stat((env), (gsp), (fsp), (malloc))
+#define LOG_ARCHIVE(env, listp, flags, malloc) \
+ log_archive((env), (listp), (flags), (malloc))
+#endif
+#endif
+/*
+ * The defult thread stacksize for nspr21 is 64k. For OSF, we require
+ * a larger stacksize as actual storage allocation is higher i.e
+ * pointers are allocated 8 bytes but lower 4 bytes are used.
+ * The value 0 means use the default stacksize.
+ */
+#if defined (OSF1) || defined (__LP64__) || defined (_LP64) /* 64-bit architectures need bigger stacks */
+#define DEFAULT_THREAD_STACKSIZE 131072L
+#else
+#define DEFAULT_THREAD_STACKSIZE 0
+#endif
+
+#ifdef _WIN32
+#define FILE_CREATE_MODE S_IREAD | S_IWRITE
+#define DIR_CREATE_MODE 0755
+#else /* _WIN32 */
+#define FILE_CREATE_MODE S_IRUSR | S_IWUSR
+#define DIR_CREATE_MODE 0755
+#endif
+
+#define NO_DISK_SPACE 1024
+#define MIN_DISK_SPACE 10485760 /* 10 MB */
+
+/***** Data Definitions *****/
+
+/* possible changelog open modes */
+typedef enum
+{
+ CL5_OPEN_NONE, /* nothing specified */
+ CL5_OPEN_NORMAL, /* open for normal read/write use */
+ CL5_OPEN_RESTORE_RECOVER, /* restore from archive and recover */
+ CL5_OPEN_RESTORE, /* restore, but no recovery */
+ CL5_OPEN_LDIF2CL, /* open as part of ldif2cl: no locking,
+ recovery, checkpointing */
+ CL5_OPEN_CLEAN_RECOVER /* remove env after recover open (upgrade) */
+} CL5OpenMode;
+
+#define DB_FILE_DELETED 0x1
+#define DB_FILE_INIT 0x2
+/* this structure represents one changelog file, Each changelog file contains
+ changes applied to a single backend. Files are named by the database id */
+typedef struct cl5dbfile
+{
+ char *name; /* file name (with the extension) */
+ char *replGen; /* replica generation of the data */
+ char *replName; /* replica name */
+ DB *db; /* db handle to the changelog file*/
+ int entryCount; /* number of entries in the file */
+ int flags; /* currently used to mark the file as deleted
+ * or as initialized */
+ RUV *purgeRUV; /* ruv to which the file has been purged */
+ RUV *maxRUV; /* ruv that marks the upper boundary of the data */
+ char *semaName; /* semaphore name */
+ PRSem *sema; /* semaphore for max concurrent cl writes */
+}CL5DBFile;
+
+/* structure that allows to iterate through entries to be sent to a consumer
+ that originated on a particular supplier. */
+struct cl5replayiterator
+{
+ Object *fileObj;
+ CLC_Buffer *clcache; /* changelog cache */
+ ReplicaId consumerRID; /* consumer's RID */
+ const RUV *consumerRuv; /* consumer's update vector */
+ Object *supplierRuvObj;/* supplier's update vector object */
+};
+
+typedef struct cl5iterator
+{
+ DBC *cursor; /* current position in the db file */
+ Object *file; /* handle to release db file object */
+}CL5Iterator;
+
+/* changelog trimming configuration */
+typedef struct cl5trim
+{
+ time_t maxAge; /* maximum entry age in seconds */
+ int maxEntries; /* maximum number of entries across all changelog files */
+ PRLock* lock; /* controls access to trimming configuration */
+} CL5Trim;
+
+/* this structure defines 5.0 changelog internals */
+typedef struct cl5desc
+{
+ char *dbDir; /* absolute path to changelog directory */
+ DB_ENV *dbEnv; /* db environment shared by all db files */
+ int dbEnvOpenFlags;/* openflag used for env->open */
+ Objset *dbFiles; /* ref counted set of changelog files (CL5DBFile) */
+ PRLock *fileLock; /* ensures that changelog file is not added twice */
+ CL5OpenMode dbOpenMode; /* how we open db */
+ CL5DBConfig dbConfig; /* database configuration params */
+ CL5Trim dbTrim; /* trimming parameters */
+ CL5State dbState; /* changelog current state */
+ PRRWLock *stLock; /* lock that controls access to the changelog state */
+ PRBool dbRmOnClose;/* indicates whether changelog should be removed when
+ it is closed */
+ PRBool fatalError; /* bad stuff happened like out of disk space; don't
+ write guardian file on close - UnUsed so far */
+ int threadCount;/* threads that globally access changelog like
+ deadlock detection, etc. */
+ PRLock *clLock; /* Lock associated to clVar, used to notify threads on close */
+ PRCondVar *clCvar; /* Condition Variable used to notify threads on close */
+} CL5Desc;
+
+typedef void (*VFP)(void *);
+
+int g_get_shutdown(); /* declared in proto-slap.h */
+
+/***** Global Variables *****/
+static CL5Desc s_cl5Desc;
+
+/***** Forward Declarations *****/
+
+/* changelog initialization and cleanup */
+static int _cl5Open (const char *dir, const CL5DBConfig *config, CL5OpenMode openMode);
+static int _cl5AppInit (PRBool *didRecovery);
+static int _cl5DBOpen ();
+static void _cl5SetDefaultDBConfig ();
+static void _cl5SetDBConfig (const CL5DBConfig *config);
+static void _cl5InitDBEnv(DB_ENV *dbEnv);
+static int _cl5CheckDBVersion ();
+static int _cl5ReadDBVersion (const char *dir, char *clVersion);
+static int _cl5WriteDBVersion ();
+static int _cl5CheckGuardian ();
+static int _cl5ReadGuardian (char *buff);
+static int _cl5WriteGuardian ();
+static int _cl5RemoveGuardian ();
+static void _cl5Close ();
+static int _cl5Delete (const char *dir, PRBool rmDir);
+static void _cl5DBClose ();
+
+/* thread management */
+static int _cl5DispatchDBThreads ();
+static int _cl5AddThread ();
+static void _cl5RemoveThread ();
+static int _cl5DeadlockMain (void *param);
+static int _cl5CheckpointMain (void *param);
+static int _cl5TrickleMain (void *param);
+
+/* functions that work with individual changelog files */
+static int _cl5NewDBFile (const char *replName, const char *replGen, CL5DBFile** dbFile);
+static int _cl5DBOpenFile (Object *replica, Object **obj, PRBool checkDups);
+static int _cl5DBOpenFileByReplicaName (const char *replName, const char *replGen,
+ Object **obj, PRBool checkDups);
+static void _cl5DBCloseFile (void **data);
+static void _cl5DBDeleteFile (Object *obj);
+static void _cl5DBFileInitialized (Object *obj);
+static int _cl5GetDBFile (Object *replica, Object **obj);
+static int _cl5GetDBFileByReplicaName (const char *replName, const char *replGen,
+ Object **obj);
+static int _cl5AddDBFile (CL5DBFile *file, Object **obj);
+static int _cl5CompareDBFile (Object *el1, const void *el2);
+static int _cl5CopyDBFiles (const char *srcDir, const char *distDir, Object **replicas);
+static char* _cl5Replica2FileName (Object *replica);
+static char* _cl5MakeFileName (const char *replName, const char *replGen);
+static PRBool _cl5FileName2Replica (const char *fileName, Object **replica);
+static int _cl5ExportFile (PRFileDesc *prFile, Object *obj);
+static PRBool _cl5ReplicaInList (Object *replica, Object **replicas);
+
+/* data storage and retrieval */
+static int _cl5Entry2DBData (const CL5Entry *entry, char **data, PRUint32 *len);
+static int _cl5WriteOperation(const char *replName, const char *replGen,
+ const slapi_operation_parameters *op, PRBool local);
+static int _cl5GetFirstEntry (Object *obj, CL5Entry *entry, void **iterator, DB_TXN *txnid);
+static int _cl5GetNextEntry (CL5Entry *entry, void *iterator);
+static int _cl5CurrentDeleteEntry (void *iterator);
+static PRBool _cl5IsValidIterator (const CL5Iterator *iterator);
+static int _cl5GetOperation (Object *replica, slapi_operation_parameters *op);
+static const char* _cl5OperationType2Str (int type);
+static int _cl5Str2OperationType (const char *str);
+static void _cl5WriteString (const char *str, char **buff);
+static void _cl5ReadString (char **str, char **buff);
+static void _cl5WriteMods (LDAPMod **mods, char **buff);
+static void _cl5WriteMod (LDAPMod *mod, char **buff);
+static int _cl5ReadMods (LDAPMod ***mods, char **buff);
+static int _cl5ReadMod (Slapi_Mod *mod, char **buff);
+static int _cl5GetModsSize (LDAPMod **mods);
+static int _cl5GetModSize (LDAPMod *mod);
+static void _cl5ReadBerval (struct berval *bv, char** buff);
+static void _cl5WriteBerval (struct berval *bv, char** buff);
+static int _cl5ReadBervals (struct berval ***bv, char** buff, unsigned int size);
+static int _cl5WriteBervals (struct berval **bv, char** buff, unsigned int *size);
+
+/* replay iteration */
+static PRBool _cl5ValidReplayIterator (const CL5ReplayIterator *iterator);
+static int _cl5PositionCursorForReplay (ReplicaId consumerRID, const RUV *consumerRuv,
+ Object *replica, Object *fileObject, CL5ReplayIterator **iterator);
+static int _cl5CheckMissingCSN (const CSN *minCsn, const RUV *supplierRUV, CL5DBFile *file);
+
+/* changelog trimming */
+static int _cl5TrimInit ();
+static void _cl5TrimCleanup ();
+static int _cl5TrimMain (void *param);
+static void _cl5DoTrimming ();
+static void _cl5TrimFile (Object *obj, long *numToTrim);
+static PRBool _cl5CanTrim (time_t time, long *numToTrim);
+static int _cl5ReadRUV (const char *replGen, Object *obj, PRBool purge);
+static int _cl5WriteRUV (CL5DBFile *file, PRBool purge);
+static int _cl5ConstructRUV (const char *replGen, Object *obj, PRBool purge);
+static int _cl5UpdateRUV (Object *obj, CSN *csn, PRBool newReplica, PRBool purge);
+static int _cl5GetRUV2Purge2 (Object *fileObj, RUV **ruv);
+
+/* db error processing */
+static void _cl5DBLogPrint(const char* prefix, char *buffer);
+
+/* bakup/recovery, import/export */
+static PRBool _cl5IsLogFile (const char *name);
+static int _cl5Recover (int open_flags, DB_ENV *dbEnv);
+static int _cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op,
+ char **replGen);
+static int _cl5Operation2LDIF (const slapi_operation_parameters *op, const char *replGen,
+ char **ldifEntry, PRInt32 *lenLDIF);
+
+/* entry count */
+static int _cl5GetEntryCount (CL5DBFile *file);
+static int _cl5WriteEntryCount (CL5DBFile *file);
+
+/* misc */
+static char* _cl5GetHelperEntryKey (int type, char *csnStr);
+static Object* _cl5GetReplica (const slapi_operation_parameters *op, const char* replGen);
+static int _cl5FileEndsWith(const char *filename, const char *ext);
+
+/* Callback function for libdb to spit error info into our log */
+static void dblayer_log_print(const char* prefix, char *buffer)
+{
+ /* We ignore the prefix since we know who we are anyway */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "libdb: %s\n", buffer);
+}
+
+static PRLock *cl5_diskfull_lock = NULL;
+static int cl5_diskfull_flag = 0;
+
+static void cl5_set_diskfull();
+static void cl5_set_no_diskfull();
+
+/***** Module APIs *****/
+
+/* Name: cl5Init
+ Description: initializes changelog module; must be called by a single thread
+ before any other changelog function.
+ Parameters: none
+ Return: CL5_SUCCESS if function is successful;
+ CL5_SYSTEM_ERROR error if NSPR call fails.
+ */
+int cl5Init ()
+{
+ s_cl5Desc.stLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "state_lock");
+ if (s_cl5Desc.stLock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Init: failed to create state lock; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+ if ((s_cl5Desc.clLock = PR_NewLock()) == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Init: failed to create on close lock; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+
+ }
+ if ((s_cl5Desc.clCvar = PR_NewCondVar(s_cl5Desc.clLock)) == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Init: failed to create on close cvar; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ if (( clcache_init (&s_cl5Desc.dbEnv) != 0 )) {
+ return CL5_SYSTEM_ERROR;
+ }
+
+ s_cl5Desc.dbState = CL5_STATE_CLOSED;
+ s_cl5Desc.fatalError = PR_FALSE;
+ s_cl5Desc.dbRmOnClose = PR_FALSE;
+ s_cl5Desc.threadCount = 0;
+
+ if (NULL == cl5_diskfull_lock)
+ {
+ cl5_diskfull_lock = PR_NewLock ();
+ }
+
+ return CL5_SUCCESS;
+}
+
+/* Name: cl5Cleanup
+ Description: performs cleanup of the changelog module; must be called by a single
+ thread; it closes changelog if it is still open.
+ Parameters: none
+ Return: none
+ */
+void cl5Cleanup ()
+{
+ /* close db if it is still open */
+ if (s_cl5Desc.dbState == CL5_STATE_OPEN)
+ {
+ cl5Close ();
+ }
+
+ if (s_cl5Desc.stLock)
+ PR_DestroyRWLock (s_cl5Desc.stLock);
+ s_cl5Desc.stLock = NULL;
+
+ if (cl5_diskfull_lock)
+ {
+ PR_DestroyLock (cl5_diskfull_lock);
+ cl5_diskfull_lock = NULL;
+ }
+
+ memset (&s_cl5Desc, 0, sizeof (s_cl5Desc));
+}
+
+/* Name: cl5Open
+ Description: opens changelog; must be called after changelog is
+ initialized using cl5Init. It is thread safe and the second
+ call is ignored.
+ Parameters: dir - changelog dir
+ config - db configuration parameters; currently not used
+ Return: CL5_SUCCESS if successfull;
+ CL5_BAD_DATA if invalid directory is passed;
+ CL5_BAD_STATE if changelog is not initialized;
+ CL5_BAD_DBVERSION if dbversion file is missing or has unexpected data
+ CL5_SYSTEM_ERROR if NSPR error occured (during db directory creation);
+ CL5_MEMORY_ERROR if memory allocation fails;
+ CL5_DB_ERROR if db initialization fails.
+ */
+int cl5Open (const char *dir, const CL5DBConfig *config)
+{
+ int rc;
+
+ if (dir == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "cl5Open: null directory\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Open: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* prevent state from changing */
+ PR_RWLock_Wlock (s_cl5Desc.stLock);
+
+ /* already open - ignore */
+ if (s_cl5Desc.dbState == CL5_STATE_OPEN)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "cl5Open: changelog already opened; request ignored\n");
+ rc = CL5_SUCCESS;
+ goto done;
+ }
+ else if (s_cl5Desc.dbState != CL5_STATE_CLOSED)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Open: invalid state - %d\n", s_cl5Desc.dbState);
+ rc = CL5_BAD_STATE;
+ goto done;
+ }
+
+ rc = _cl5Open (dir, config, CL5_OPEN_NORMAL);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Open: failed to open changelog\n");
+ goto done;
+ }
+
+ /* dispatch global threads like deadlock detection, trimming, etc */
+ rc = _cl5DispatchDBThreads ();
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Open: failed to start database monitoring threads\n");
+
+ _cl5Close ();
+ }
+ else
+ {
+ s_cl5Desc.dbState = CL5_STATE_OPEN;
+ }
+
+done:;
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+
+ return rc;
+}
+
+/* Name: cl5Close
+ Description: closes changelog; waits until all threads are done using changelog;
+ call is ignored if changelog is already closed.
+ Parameters: none
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if db is not in the open or closed state;
+ CL5_SYSTEM_ERROR if NSPR call fails;
+ CL5_DB_ERROR if db shutdown fails
+ */
+int cl5Close ()
+{
+ int rc = CL5_SUCCESS;
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5Close: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ PR_RWLock_Wlock (s_cl5Desc.stLock);
+
+ /* already closed - ignore */
+ if (s_cl5Desc.dbState == CL5_STATE_CLOSED)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "cl5Close: changelog closed; request ignored\n");
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+ return CL5_SUCCESS;
+ }
+ else if (s_cl5Desc.dbState != CL5_STATE_OPEN)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5Close: invalid state - %d\n", s_cl5Desc.dbState);
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+ return CL5_BAD_STATE;
+ }
+
+ /* signal changelog closing to all threads */
+ s_cl5Desc.dbState = CL5_STATE_CLOSING;
+
+ PR_Lock(s_cl5Desc.clLock);
+ PR_NotifyCondVar(s_cl5Desc.clCvar);
+ PR_Unlock(s_cl5Desc.clLock);
+
+ _cl5Close ();
+
+ s_cl5Desc.dbState = CL5_STATE_CLOSED;
+
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+
+ return rc;
+}
+
+/* Name: cl5Delete
+ Description: removes changelog; changelog must be in the closed state.
+ Parameters: dir - changelog directory
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if the changelog is not in closed state;
+ CL5_BAD_DATA if invalid directory supplied
+ CL5_SYSTEM_ERROR if NSPR call fails
+ */
+int cl5Delete (const char *dir)
+{
+ int rc;
+
+ if (dir == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl, "cl5Delete: null directory\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5Delete: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ PR_RWLock_Wlock (s_cl5Desc.stLock);
+
+ if (s_cl5Desc.dbState != CL5_STATE_CLOSED)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5Delete: invalid state - %d\n", s_cl5Desc.dbState);
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+ return CL5_BAD_STATE;
+ }
+
+ rc = _cl5Delete (dir, PR_TRUE /* remove changelog dir */);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5Delete: failed to remove changelog\n");
+ }
+
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+ return rc;
+}
+
+/* Name: cl5OpenDB
+ Description: opens changelog file for specified file
+ Parameters: replica - replica whose file we wish to open
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if the changelog is not initialized;
+ CL5_BAD_DATA - if NULL id is supplied
+ */
+int cl5OpenDB (Object *replica)
+{
+ int rc;
+
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "cl5OpenDB: null replica\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5OpenDB: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog stays open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ rc = _cl5DBOpenFile (replica, NULL /* file object */, PR_TRUE /* check for duplicates */);
+
+ _cl5RemoveThread ();
+
+ return rc;
+}
+
+/* Name: cl5CloseDB
+ Description: closes changelog file for the specified replica
+ Parameters: replica - replica whose file we wish to close
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if the changelog is not initialized;
+ CL5_BAD_DATA - if NULL id is supplied
+ CL5_NOTFOUND - nothing is known about specified database
+ */
+int cl5CloseDB (Object *replica)
+{
+ int rc;
+ Object *obj;
+
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "cl5CloseDB: null replica\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5CloseDB: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog is open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ rc = _cl5GetDBFile (replica, &obj);
+ if (rc == CL5_SUCCESS)
+ {
+ rc = objset_remove_obj(s_cl5Desc.dbFiles, obj);
+ object_release (obj);
+ }
+ else
+ {
+ Replica *r;
+
+ r = (Replica*)object_get_data (replica);
+ PR_ASSERT (r);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5CloseDB: failed to close file for replica at (%s)\n",
+ slapi_sdn_get_dn (replica_get_root (r)));
+ }
+
+ _cl5RemoveThread ();
+ return rc;
+}
+
+/* Name: cl5DeleteDB
+ Description: asynchronously removes changelog file for the specified replica.
+ The file is physically removed when it is no longer in use.
+ This function is called when a backend is removed or reloaded.
+ Parameters: replica - replica whose file we wish to delete
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if the changelog is not initialized;
+ CL5_BAD_DATA - if NULL id is supplied
+ CL5_NOTFOUND - nothing is known about specified database
+ */
+int cl5DeleteDB (Object *replica)
+{
+ Object *obj;
+ int rc;
+
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5DeleteDB: invalid database id\n");
+ return CL5_BAD_DATA;
+ }
+
+ /* changelog is not initialized */
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "cl5DeleteDB: "
+ "changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog stays open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ rc = _cl5GetDBFile (replica, &obj);
+ if (rc == CL5_SUCCESS)
+ {
+ _cl5DBDeleteFile (obj);
+ }
+ else
+ {
+ Replica *r = (Replica*)object_get_data (replica);
+ PR_ASSERT (r);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "cl5DeleteDB: "
+ "file for replica at (%s) not found\n",
+ slapi_sdn_get_dn (replica_get_root (r)));
+ }
+
+ _cl5RemoveThread ();
+ return rc;
+}
+
+/* Name: cl5DeleteDBSync
+ Description: The same as cl5DeleteDB except the function does not return
+ until the file is removed.
+*/
+int cl5DeleteDBSync (Object *replica)
+{
+ Object *obj;
+ int rc;
+ CL5DBFile *file;
+ char fName [MAXPATHLEN + 1];
+
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5DeleteDBSync: invalid database id\n");
+ return CL5_BAD_DATA;
+ }
+
+ /* changelog is not initialized */
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "cl5DeleteDBSync: "
+ "changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog stays open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ rc = _cl5GetDBFile (replica, &obj);
+ if (rc == CL5_SUCCESS)
+ {
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+
+ PR_snprintf (fName, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, file->name);
+
+ _cl5DBDeleteFile (obj);
+
+ /* wait until the file is gone */
+ while (PR_Access (fName, PR_ACCESS_EXISTS) == PR_SUCCESS)
+ {
+ DS_Sleep (PR_MillisecondsToInterval(100));
+ }
+
+ }
+ else
+ {
+ Replica *r = (Replica*)object_get_data (replica);
+ PR_ASSERT (r);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "cl5DeleteDBSync: "
+ "file for replica at (%s) not found\n",
+ slapi_sdn_get_dn (replica_get_root (r)));
+ }
+
+ _cl5RemoveThread ();
+ return rc;
+}
+
+/* Name: cl5GetUpperBoundRUV
+ Description: retrieves vector for that represnts the upper bound of the changes for a replica.
+ Parameters: r - replica for which the purge vector is requested
+ ruv - contains a copy of the purge ruv if function is successful;
+ unchanged otherwise. It is responsobility pf the caller to free
+ the ruv when it is no longer is in use
+ Return: CL5_SUCCESS if function is successfull
+ CL5_BAD_STATE if the changelog is not initialized;
+ CL5_BAD_DATA - if NULL id is supplied
+ CL5_NOTFOUND, if changelog file for replica is not found
+ */
+int cl5GetUpperBoundRUV (Replica *r, RUV **ruv)
+{
+ int rc;
+ Object *r_obj, *file_obj;
+ CL5DBFile *file;
+
+ if (r == NULL || ruv == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5GetUpperBoundRUV: invalid parameters\n");
+ return CL5_BAD_DATA;
+ }
+
+ /* changelog is not initialized */
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "cl5GetUpperBoundRUV: "
+ "changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog stays open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ /* create a temporary replica object because of the interface we have */
+ r_obj = object_new (r, NULL);
+
+ rc = _cl5GetDBFile (r_obj, &file_obj);
+ if (rc == CL5_SUCCESS)
+ {
+ file = (CL5DBFile*)object_get_data (file_obj);
+ PR_ASSERT (file && file->maxRUV);
+
+ *ruv = ruv_dup (file->maxRUV);
+
+ object_release (file_obj);
+ }
+
+ object_release (r_obj);
+
+ _cl5RemoveThread ();
+ return rc;
+}
+
+/* Name: cl5Backup
+ Description: makes a backup of the changelog including *.db2,
+ log files, and dbversion. Can be called with the changelog in either open or
+ closed state.
+ Parameters: bkDir - directory to which the data is backed up;
+ created if it does not exist
+ replicas - optional list of replicas whose changes should be backed up;
+ if the list is NULL, entire changelog is backed up.
+ Return: CL5_SUCCESS if function is successful;
+ CL5_BAD_DATA if invalid directory is passed;
+ CL5_BAD_STATE if changelog has not been initialized;
+ CL5_DB_ERROR if db call fails;
+ CL5_SYSTEM_ERROR if NSPR call or file copy failes.
+ */
+int cl5Backup (const char *bkDir, Object **replicas)
+{
+ int rc;
+ char **list = NULL;
+ char **logFile;
+ char srcFile [MAXPATHLEN + 1];
+ char destFile[MAXPATHLEN + 1];
+ DB_TXN *txn = NULL;
+
+ if (bkDir == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "cl5Backup: null backup directory\n");
+ return CL5_BAD_DATA;
+ }
+
+ /* changelog must be initialized */
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Backup: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog stays open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ /* create backup directory if necessary */
+ rc = cl5CreateDirIfNeeded (bkDir);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Backup: failed to create backup directory\n");
+ goto done;
+ }
+
+ /* start transaction to tempararily prevent transaction log
+ from being trimmed
+ */
+ rc = TXN_BEGIN(s_cl5Desc.dbEnv, NULL /*pid*/, &txn, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Backup: failed to begin transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "cl5Backup: starting changelog backup from %s to %s ...\n", s_cl5Desc.dbDir, bkDir);
+
+ /* The following files are backed up: *.<dbext>, log files, dbversion file */
+
+ /* copy db file */
+ /* ONREPL currently, list of replicas is ignored because db code can't handle
+ discrepancy between transaction log and present files; should be fixed before 5.0 ships */
+ rc = _cl5CopyDBFiles (s_cl5Desc.dbDir, bkDir, replicas);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Backup : failed to copy database files from %s to %s\n", s_cl5Desc.dbDir, bkDir);
+ goto done;
+ }
+
+ /* copy db log files */
+ rc = LOG_ARCHIVE(s_cl5Desc.dbEnv, &list, DB_ARCH_LOG, malloc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Backup: failed to get list of log files; db error - %d %s\n",
+ rc, db_strerror(rc));
+ rc = CL5_SYSTEM_ERROR;
+ goto done;
+ }
+
+ if (list)
+ {
+ logFile = list;
+ while (*logFile)
+ {
+ PR_snprintf(srcFile, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, *logFile);
+ PR_snprintf(destFile, MAXPATHLEN, "%s/%s", bkDir, *logFile);
+ rc = copyfile(srcFile, destFile, 0, FILE_CREATE_MODE);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Backup: failed to copy %s\n", *logFile);
+ rc = CL5_SYSTEM_ERROR;
+ goto done;
+ }
+
+ logFile ++;
+ }
+
+ free(list);
+ }
+
+ /* now, copy the version file */
+ PR_snprintf(srcFile, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, VERSION_FILE);
+ PR_snprintf(destFile, MAXPATHLEN, "%s/%s", bkDir, VERSION_FILE);
+ rc = copyfile(srcFile, destFile, 0, FILE_CREATE_MODE);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Backup: failed to copy %s\n", VERSION_FILE);
+ rc = CL5_SYSTEM_ERROR;
+ goto done;
+ }
+
+ rc = CL5_SUCCESS;
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "cl5Backup: changelog backup is finished \n");
+done:;
+ if (txn && TXN_ABORT (txn) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Backup: failed to abort transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ }
+
+ _cl5RemoveThread ();
+
+ return rc;
+}
+
+/* Name: cl5Restore
+ Description: restores changelog from the backed up copy. Changelog must be ibnitalized and closed.
+ Parameters: clDir - changelog dir
+ bkDir - directory that contains the backup
+ replicas - optional list of replicas whose changes should be recovered;
+ if the list is NULL, entire changelog is recovered.
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_BAD_STATE if changelog is open or not initialized;
+ CL5_DB_ERROR if db call fails;
+ CL5_SYSTEM_ERROR if NSPR call of file copy fails
+ */
+int cl5Restore (const char *clDir, const char *bkDir, Object **replicas)
+{
+ int rc;
+ char srcFile[MAXPATHLEN + 1];
+ char destFile[MAXPATHLEN + 1];
+ PRDir *prDir;
+ PRDirEntry *prDirEntry;
+ int seenLog = 0; /* Tells us if we restored any logfiles */
+
+ if (clDir == NULL || bkDir == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "cl5Restore: null parameter\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Restore: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* prevent state change while recovery is in progress */
+ PR_RWLock_Wlock (s_cl5Desc.stLock);
+
+ if (s_cl5Desc.dbState != CL5_STATE_CLOSED)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Restore: changelog must be closed\n");
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+ return CL5_BAD_STATE;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "cl5Restore: starting changelog recovery from %s to %s ...\n", bkDir, clDir);
+
+ /* delete current changelog content */
+ rc = _cl5Delete (clDir, PR_FALSE);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Restore: failed to remove changelog\n");
+ goto done;
+ }
+
+ /* We copy the files over from the staging area */
+ prDir = PR_OpenDir(bkDir);
+ if (prDir == NULL)
+ {
+ rc = CL5_SYSTEM_ERROR;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Restore: unable to access backup directory %s; NSPR error - %d\n",
+ bkDir, PR_GetError ());
+ goto done;
+ }
+
+ while (NULL != (prDirEntry = PR_ReadDir(prDir, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == prDirEntry->name) /* NSPR doesn't behave like the docs say it should */
+ {
+ break;
+ }
+
+ /* Log files have names of the form "log.xxxxx". We detect these by looking for
+ the prefix "log." and the lack of the ".<dbext>" suffix */
+ seenLog |= _cl5IsLogFile(prDirEntry->name);
+
+ /* ONREPL currently, list of replicas is ignored because db code can't handle discrepancy
+ between transaction log and present files; this should change before 5.0 ships */
+ PR_snprintf(destFile, MAXPATHLEN, "%s/%s", clDir, prDirEntry->name);
+ PR_snprintf(srcFile, MAXPATHLEN, "%s/%s", bkDir, prDirEntry->name);
+ rc = copyfile(srcFile, destFile, 0, FILE_CREATE_MODE);
+ if (rc != 0)
+ {
+ rc = CL5_SYSTEM_ERROR;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Restore: failed to copy %s\n", prDirEntry->name);
+ PR_CloseDir(prDir);
+ goto done;
+ }
+ }
+
+ PR_CloseDir(prDir);
+
+ /* now open and close changelog to create all necessary files */
+ if (seenLog)
+ rc = _cl5Open (clDir, NULL, CL5_OPEN_RESTORE_RECOVER);
+ else
+ rc = _cl5Open (clDir, NULL, CL5_OPEN_RESTORE);
+
+ if (rc == CL5_SUCCESS)
+ {
+ _cl5Close ();
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "cl5Restore: changelog recovery is finished \n");
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5Restore: failed open changelog after recovery\n");
+ }
+
+done:;
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+ return rc;
+}
+
+/* Name: cl5ExportLDIF
+ Description: dumps changelog to an LDIF file; changelog can be open or closed.
+ Parameters: clDir - changelog dir
+ ldifFile - full path to ldif file to write
+ replicas - optional list of replicas whose changes should be exported;
+ if the list is NULL, entire changelog is exported.
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_BAD_STATE if changelog is not initialized;
+ CL5_DB_ERROR if db api fails;
+ CL5_SYSTEM_ERROR if NSPR call fails;
+ CL5_MEMORY_ERROR if memory allocation fials.
+ */
+int cl5ExportLDIF (const char *ldifFile, Object **replicas)
+{
+ int i;
+ int rc;
+ PRFileDesc *prFile = NULL;
+ Object *obj;
+
+ if (ldifFile == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ExportLDIF: null ldif file name\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ExportLDIF: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog is open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ prFile = PR_Open (ldifFile, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0600);
+ if (prFile == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ExportLDIF: failed to open (%s) file; NSPR error - %d\n",
+ ldifFile, PR_GetError ());
+ rc = CL5_SYSTEM_ERROR;
+ goto done;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "cl5ExportLDIF: starting changelog export to (%s) ...\n", ldifFile);
+
+ if (replicas) /* export only selected files */
+ {
+ for (i = 0; replicas[i]; i++)
+ {
+ rc = _cl5GetDBFile (replicas[i], &obj);
+ if (rc == CL5_SUCCESS)
+ {
+ rc = _cl5ExportFile (prFile, obj);
+ object_release (obj);
+ }
+ else
+ {
+ Replica *r = (Replica*)object_get_data (replicas[i]);
+
+ PR_ASSERT (r);
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "cl5ExportLDIF: "
+ "failed to locate changelog file for replica at (%s)\n",
+ slapi_sdn_get_dn (replica_get_root (r)));
+ }
+ }
+ }
+ else /* export all files */
+ {
+ for (obj = objset_first_obj(s_cl5Desc.dbFiles); obj;
+ obj = objset_next_obj(s_cl5Desc.dbFiles, obj))
+ {
+ rc = _cl5ExportFile (prFile, obj);
+ object_release (obj);
+ }
+ }
+
+ rc = CL5_SUCCESS;
+done:;
+
+ _cl5RemoveThread ();
+
+ if (rc == CL5_SUCCESS)
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "cl5ExportLDIF: changelog export is finished.\n");
+
+ if (prFile)
+ PR_Close (prFile);
+
+ return rc;
+}
+
+/* Name: cl5ImportLDIF
+ Description: imports ldif file into changelog; changelog must be in the closed state
+ Parameters: clDir - changelog dir
+ ldifFile - absolute path to the ldif file to import
+ replicas - optional list of replicas whose data should be imported;
+ if the list is NULL, all data in the file is imported.
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_BAD_STATE if changelog is open or not inititalized;
+ CL5_DB_ERROR if db api fails;
+ CL5_SYSTEM_ERROR if NSPR call fails;
+ CL5_MEMORY_ERROR if memory allocation fials.
+ */
+int cl5ImportLDIF (const char *clDir, const char *ldifFile, Object **replicas)
+{
+ FILE *file;
+ int rc;
+ char *buff;
+ int lineno = 0;
+ slapi_operation_parameters op;
+ Object *replica = NULL;
+ char *replGen = NULL;
+
+ /* validate params */
+ if (ldifFile == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ImportLDIF: null ldif file name\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ImportLDIF: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that nobody change changelog state while import is in progress */
+ PR_RWLock_Wlock (s_cl5Desc.stLock);
+
+ /* make sure changelog is closed */
+ if (s_cl5Desc.dbState != CL5_STATE_CLOSED)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ImportLDIF: invalid state - %d \n", s_cl5Desc.dbState);
+
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+ return CL5_BAD_STATE;
+ }
+
+ /* open LDIF file */
+ file = fopen (ldifFile, "r"); /* XXXggood Does fopen reliably work if > 255 files open? */
+ if (file == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ImportLDIF: failed to open (%s) ldif file; system error - %d\n",
+ ldifFile, errno);
+ rc = CL5_SYSTEM_ERROR;
+ goto done;
+ }
+
+ /* remove changelog */
+ rc = _cl5Delete (clDir, PR_FALSE);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ImportLDIF: failed to remove changelog\n");
+ goto done;
+ }
+
+ /* open changelog */
+ rc = _cl5Open (clDir, NULL, CL5_OPEN_LDIF2CL);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ImportLDIF: failed to open changelog\n");
+ goto done;
+ }
+
+ /* read entries and write them to changelog */
+ while ((buff = ldif_get_entry( file, &lineno )) != NULL)
+ {
+ rc = _cl5LDIF2Operation (buff, &op, &replGen);
+ slapi_ch_free ((void**)&buff);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ImportLDIF: failed to convert LDIF fragment to LDAP operation; "
+ "end of fragment line number - %d\n", lineno);
+ goto done;
+ }
+
+ /* if we perform selective import, check if the operation should be wriiten to changelog */
+ replica = _cl5GetReplica (&op, replGen);
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ImportLDIF: failed to locate replica for target dn (%s) and "
+ "replica generation %s\n", op.target_address.dn, replGen);
+
+ slapi_ch_free ((void**)&replGen);
+ operation_parameters_done (&op);
+ goto done;
+ }
+
+ if (!replicas || _cl5ReplicaInList (replica, replicas))
+ {
+ /* write operation creates the file if it does not exist */
+ rc = _cl5WriteOperation (replica_get_name ((Replica*)object_get_data(replica)),
+ replGen, &op, 1);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ImportLDIF: failed to write operation to the changelog\n");
+ object_release (replica);
+ slapi_ch_free ((void**)&replGen);
+ operation_parameters_done (&op);
+ goto done;
+ }
+ }
+
+ object_release (replica);
+ slapi_ch_free ((void**)&replGen);
+ operation_parameters_done (&op);
+ }
+
+done:;
+ _cl5Close ();
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+ return rc;
+}
+
+/* Name: cl5GetState
+ Description: returns database state
+ Parameters: none
+ Return: changelog state
+ */
+int cl5GetState ()
+{
+ return s_cl5Desc.dbState;
+}
+
+/* Name: cl5ConfigTrimming
+ Description: sets changelog trimming parameters; changelog must be open.
+ Parameters: maxEntries - maximum number of entries in the chnagelog (in all files);
+ maxAge - maximum entry age;
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if changelog is not open
+ */
+int cl5ConfigTrimming (int maxEntries, const char *maxAge)
+{
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5ConfigTrimming: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure changelog is not closed while trimming configuration
+ is updated.*/
+ _cl5AddThread ();
+
+ PR_Lock (s_cl5Desc.dbTrim.lock);
+
+ if (maxAge)
+ {
+ /* don't ignore this argument */
+ if (strcmp (maxAge, CL5_STR_IGNORE) != 0)
+ {
+ s_cl5Desc.dbTrim.maxAge = age_str2time (maxAge);
+ }
+ }
+ else
+ {
+ /* unlimited */
+ s_cl5Desc.dbTrim.maxAge = 0;
+ }
+
+ if (maxEntries != CL5_NUM_IGNORE)
+ {
+ s_cl5Desc.dbTrim.maxEntries = maxEntries;
+ }
+
+ PR_Unlock (s_cl5Desc.dbTrim.lock);
+
+ _cl5RemoveThread ();
+
+ return CL5_SUCCESS;
+}
+
+/* Name: cl5GetOperation
+ Description: retireves operation specified by its csn and databaseid
+ Parameters: op - must contain csn and databaseid; the rest of data is
+ filled if function is successfull
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid op is passed;
+ CL5_BAD_STATE if db has not been initialized;
+ CL5_NOTFOUND if entry was not found;
+ CL5_DB_ERROR if any other db error occured;
+ CL5_BADFORMAT if db data format does not match entry format.
+ */
+int cl5GetOperation (Object *replica, slapi_operation_parameters *op)
+{
+ int rc;
+ char *agmt_name;
+
+ agmt_name = get_thread_private_agmtname();
+
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "cl5GetOperation: NULL replica\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (op == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "cl5GetOperation: NULL operation\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (op->csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "%s: cl5GetOperation: operation contains no CSN\n", agmt_name);
+ return CL5_BAD_DATA;
+ }
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "%s: cl5GetOperation: changelog is not initialized\n", agmt_name);
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog is open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ rc = _cl5GetOperation (replica, op);
+
+ _cl5RemoveThread ();
+
+ return rc;
+}
+
+/* Name: cl5GetFirstOperation
+ Description: retrieves first operation for a particular database
+ replica - replica for which the operation should be retrieved.
+ Parameters: op - buffer to store the operation;
+ iterator - to be passed to the call to cl5GetNextOperation
+ Return: CL5_SUCCESS, if successful
+ CL5_BADDATA, if operation is NULL
+ CL5_BAD_STATE, if changelog is not open
+ CL5_DB_ERROR, if db call fails
+ */
+int cl5GetFirstOperation (Object *replica, slapi_operation_parameters *op, void **iterator)
+{
+ int rc;
+ CL5Entry entry;
+ Object *obj;
+ char *agmt_name;
+
+ if (replica == NULL || op == NULL || iterator == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5GetFirstOperation: invalid argument\n");
+ return CL5_BAD_DATA;
+ }
+
+ *iterator = NULL;
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ agmt_name = get_thread_private_agmtname();
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "%s: cl5GetFirstOperation: changelog is not initialized\n", agmt_name);
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog stays open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ rc = _cl5GetDBFile (replica, &obj);
+ if (rc != CL5_SUCCESS)
+ {
+ _cl5RemoveThread ();
+ return rc;
+ }
+
+ entry.op = op;
+ /* Callers of this function should cl5_operation_parameters_done(op) */
+ rc = _cl5GetFirstEntry (obj, &entry, iterator, NULL);
+ object_release (obj);
+
+ _cl5RemoveThread ();
+
+ return rc;
+}
+
+/* Name: cl5GetNextOperation
+ Description: retrieves the next op from the changelog as defined by the iterator;
+ changelog must be open.
+ Parameters: op - returned operation, if function is successful
+ iterator - in: identifies op to retrieve; out: identifies next op
+ Return: CL5_SUCCESS, if successful
+ CL5_BADDATA, if op is NULL
+ CL5_BAD_STATE, if changelog is not open
+ CL5_NOTFOUND, empty changelog
+ CL5_DB_ERROR, if db call fails
+ */
+int cl5GetNextOperation (slapi_operation_parameters *op, void *iterator)
+{
+ CL5Entry entry;
+
+ if (op == NULL || iterator == NULL || !_cl5IsValidIterator (iterator))
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5GetNextOperation: invalid argument\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (s_cl5Desc.dbState != CL5_STATE_OPEN)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5GetNextOperation: changelog is not open\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* we don't need to increment thread count since cl5GetFirstOperation
+ locked the file through which we are iterating */
+ entry.op = op;
+ /* Callers of this function should cl5_operation_parameters_done(op) */
+ return _cl5GetNextEntry (&entry, iterator);
+}
+
+/* Name: cl5DestroyIterator
+ Description: destroys iterator once iteration through changelog is done
+ Parameters: iterator - iterator to destroy
+ Return: none
+ */
+void cl5DestroyIterator (void *iterator)
+{
+ CL5Iterator *it = (CL5Iterator*)iterator;
+
+ if (it == NULL)
+ return;
+
+ /* close cursor */
+ if (it->cursor)
+ it->cursor->c_close (it->cursor);
+
+ if (it->file)
+ object_release (it->file);
+
+ slapi_ch_free ((void**)&it);
+}
+
+/* Name: cl5WriteOperation
+ Description: writes operation to changelog
+ Parameters: replName - name of the replica to which operation applies
+ replGen - replica generation for the operation
+ !!!Note that we pass name and generation rather than
+ replica object since generation can change while operation
+ is in progress (if the data is reloaded). !!!
+ op - operation to write
+ local - this is a non-replicated operation
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid op is passed;
+ CL5_BAD_STATE if db has not been initialized;
+ CL5_MEMORY_ERROR if memory allocation failed;
+ CL5_DB_ERROR if any other db error occured;
+ */
+int cl5WriteOperation(const char *replName, const char *replGen,
+ const slapi_operation_parameters *op, PRBool local)
+{
+ int rc;
+
+ if (op == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5WriteOperation: NULL operation passed\n");
+ return CL5_BAD_DATA;
+ }
+
+ if (!IsValidOperation (op))
+ {
+ return CL5_BAD_DATA;
+ }
+
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5WriteOperation: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog is open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ rc = _cl5WriteOperation(replName, replGen, op, local);
+
+ /* update the upper bound ruv vector */
+ if (rc == CL5_SUCCESS)
+ {
+ Object *file_obj = NULL;
+
+ if ( _cl5GetDBFileByReplicaName (replName, replGen, &file_obj) == CL5_SUCCESS) {
+ rc = _cl5UpdateRUV (file_obj, op->csn, PR_FALSE, PR_FALSE);
+ object_release (file_obj);
+ }
+
+ }
+
+ _cl5RemoveThread ();
+
+ return rc;
+}
+
+/* Name: cl5CreateReplayIterator
+ Description: creates an iterator that allows to retireve changes that should
+ to be sent to the consumer identified by ruv. The iteration is peformed by
+ repeated calls to cl5GetNextOperationToReplay.
+ Parameters: replica - replica whose data we wish to iterate;
+ ruv - consumer ruv;
+ iterator - iterator to be passed to cl5GetNextOperationToReplay call
+ Return: CL5_SUCCESS, if function is successfull;
+ CL5_MISSING_DATA, if data that should be in the changelog is missing
+ CL5_PURGED_DATA, if some data that consumer needs has been purged.
+ Note that the iterator can be non null if the supplier contains
+ some data that needs to be sent to the consumer
+ CL5_NOTFOUND if the consumer is up to data with respect to the supplier
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_BAD_STATE if db has not been open;
+ CL5_DB_ERROR if any other db error occured;
+ CL5_MEMORY_ERROR if memory allocation fails.
+ Algorithm: Build a list of csns from consumer's and supplier's ruv. For each element
+ of the consumer's ruv put max csn into the csn list. For each element
+ of the supplier's ruv not in the consumer's ruv put min csn from the
+ supplier's ruv into the list. The list contains, for each known replica,
+ the starting point for changes to be sent to the consumer.
+ Sort the list in accending order.
+ Build a hash which contains, for each known replica, whether the
+ supplier can bring the consumer up to data with respect to that replica.
+ The hash is used to decide whether a change can be sent to the consumer
+ Find the replica with the smallest csn in the list for which
+ we can bring the consumer up to date.
+ Position the db cursor on the change entry that corresponds to this csn.
+ Hash entries are created for each replica traversed so far. sendChanges
+ flag is set to FALSE for all repolicas except the last traversed.
+
+ */
+int cl5CreateReplayIterator (Private_Repl_Protocol *prp, const RUV *consumerRuv,
+ CL5ReplayIterator **iterator)
+{
+ int rc;
+ Object *replica;
+ Object *obj = NULL;
+
+ replica = prp->replica_object;
+ if (replica == NULL || consumerRuv == NULL || iterator == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5CreateReplayIterator: invalid parameter\n");
+ return CL5_BAD_DATA;
+ }
+
+ *iterator = NULL;
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5CreateReplayIterator: changelog is not initialized\n");
+ return CL5_BAD_STATE;
+ }
+
+ /* make sure that changelog is open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS ) return rc;
+
+
+ rc = _cl5GetDBFile (replica, &obj);
+ if (rc == CL5_SUCCESS)
+ {
+ /* iterate through the ruv in csn order to find first master for which
+ we can replay changes */
+ ReplicaId consumerRID = agmt_get_consumer_rid ( prp->agmt, prp->conn );
+ rc = _cl5PositionCursorForReplay (consumerRID, consumerRuv, replica, obj, iterator);
+ if (rc != CL5_SUCCESS)
+ {
+ if (obj)
+ object_release (obj);
+ }
+ }
+
+ _cl5RemoveThread ();
+
+ return rc;
+}
+
+/* Name: cl5GetNextOperationToReplay
+ Description: retrieves next operation to be sent to a particular consumer and
+ that was created on a particular master. Consumer and master info
+ is encoded in the iterator parameter that must be created by call
+ to cl5CreateReplayIterator.
+ Parameters: iterator - iterator that identifies next entry to retrieve;
+ op - operation retrieved if function is successful
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_NOTFOUND if end of iteration list is reached
+ CL5_DB_ERROR if any other db error occured;
+ CL5_BADFORMAT if data in db is of unrecognized format;
+ CL5_MEMORY_ERROR if memory allocation fails.
+ Algorithm: Iterate through changelog entries until a change is found that
+ originated at the replica for which we are sending changes
+ (based on the information in the iteration hash) and
+ whose csn is larger than the csn already seen by the consumer
+ If change originated at the replica not in the hash,
+ determine whether we should send changes originated at the replica
+ and add replica entry into the hash. We can send the changes for
+ the replica if the current csn is smaller or equal to the csn
+ in the consumer's ruv (if present) or if it is equal to the min
+ csn in the supplier's ruv.
+ */
+int
+cl5GetNextOperationToReplay (CL5ReplayIterator *iterator, CL5Entry *entry)
+{
+ CSN *csn;
+ char *key, *data;
+ size_t keylen, datalen;
+ char *agmt_name;
+ int rc = 0;
+
+ agmt_name = get_thread_private_agmtname();
+
+ if (entry == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "%s: cl5GetNextOperationToReplay: invalid parameter passed\n", agmt_name);
+ return CL5_BAD_DATA;
+ }
+
+ rc = clcache_get_next_change (iterator->clcache, (void **)&key, &keylen, (void **)&data, &datalen, &csn);
+
+ if (rc == DB_NOTFOUND)
+ {
+ /*
+ * Abort means we've figured out that we've passed the replica Min CSN,
+ * so we should stop looping through the changelog
+ */
+ return CL5_NOTFOUND;
+ }
+
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "%s: cl5GetNextOperationToReplay: "
+ "failed to read next entry; DB error %d\n", agmt_name, rc);
+ return CL5_DB_ERROR;
+ }
+
+ /* there is an entry we should return */
+ /* Callers of this function should cl5_operation_parameters_done(op) */
+ if ( 0 != cl5DBData2Entry ( data, datalen, entry ) )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "%s: cl5GetNextOperationToReplay: failed to format entry rc=%d\n", agmt_name, rc);
+ return rc;
+ }
+
+ return CL5_SUCCESS;
+}
+
+/* Name: cl5DestroyReplayIterator
+ Description: destorys iterator
+ Parameters: iterator - iterator to destory
+ Return: none
+ */
+void cl5DestroyReplayIterator (CL5ReplayIterator **iterator)
+{
+ if (iterator == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5DestroyReplayIterator: invalid iterartor passed\n");
+ return;
+ }
+
+ clcache_return_buffer ( &(*iterator)->clcache );
+
+ if ((*iterator)->fileObj)
+ object_release ((*iterator)->fileObj);
+
+ /* release supplier's ruv */
+ if ((*iterator)->supplierRuvObj)
+ object_release ((*iterator)->supplierRuvObj);
+
+ slapi_ch_free ((void **)iterator);
+}
+
+/* Name: cl5DeleteOnClose
+ Description: marks changelog for deletion when it is closed
+ Parameters: flag; if flag = 1 then delete else don't
+ Return: none
+ */
+void cl5DeleteOnClose (PRBool rm)
+{
+ s_cl5Desc.dbRmOnClose = rm;
+}
+
+/* Name: cl5GetDir
+ Description: returns changelog directory
+ Parameters: none
+ Return: copy of the directory; caller needs to free the string
+ */
+ char *cl5GetDir ()
+{
+ if (s_cl5Desc.dbDir == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ return slapi_ch_strdup (s_cl5Desc.dbDir);
+ }
+}
+
+/* Name: cl5Exist
+ Description: checks if a changelog exists in the specified directory;
+ We consider changelog to exist if it contains the dbversion file.
+ Parameters: clDir - directory to check
+ Return: 1 - if changelog exists; 0 - otherwise
+ */
+PRBool cl5Exist (const char *clDir)
+{
+ char fName [MAXPATHLEN + 1];
+ int rc;
+
+ PR_snprintf (fName, MAXPATHLEN, "%s/%s", clDir, VERSION_FILE);
+ rc = PR_Access (fName, PR_ACCESS_EXISTS);
+
+ return (rc == PR_SUCCESS);
+}
+
+/* Name: cl5GetOperationCount
+ Description: returns number of entries in the changelog. The changelog must be
+ open for the value to be meaningful.
+ Parameters: replica - optional parameter that specifies the replica whose operations
+ we wish to count; if NULL all changelog entries are counted
+ Return: number of entries in the changelog
+ */
+
+int cl5GetOperationCount (Object *replica)
+{
+ Object *obj;
+ CL5DBFile *file;
+ int count = 0;
+ int rc;
+
+ if (s_cl5Desc.dbState == CL5_STATE_NONE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5GetOperationCount: changelog is not initialized\n");
+ return -1;
+ }
+
+ /* make sure that changelog is open while operation is in progress */
+ rc = _cl5AddThread ();
+ if (rc != CL5_SUCCESS)
+ return -1;
+
+ if (replica == NULL) /* compute total entry count */
+ {
+ obj = objset_first_obj (s_cl5Desc.dbFiles);
+ while (obj)
+ {
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+ count += file->entryCount;
+ obj = objset_next_obj (s_cl5Desc.dbFiles, obj);
+ }
+ }
+ else /* return count for particular db */
+ {
+ /* select correct db file */
+ rc = _cl5GetDBFile (replica, &obj);
+ if (rc == CL5_SUCCESS)
+ {
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+
+ count = file->entryCount;
+ object_release (obj);
+ }
+ else
+ {
+ count = 0;
+ }
+ }
+
+ _cl5RemoveThread ();
+ return count;
+}
+
+/***** Helper Functions *****/
+
+/* this call happens under state lock */
+static int _cl5Open (const char *dir, const CL5DBConfig *config, CL5OpenMode openMode)
+{
+ int rc;
+ PRBool didRecovery;
+
+ PR_ASSERT (dir);
+
+ /* setup db configuration parameters */
+ if (config)
+ {
+ _cl5SetDBConfig (config);
+ }
+ else
+ {
+ _cl5SetDefaultDBConfig ();
+ }
+
+ /* initialize trimming */
+ rc = _cl5TrimInit ();
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Open: failed to initialize trimming\n");
+ goto done;
+ }
+
+ /* create the changelog directory if it does not exist */
+ rc = cl5CreateDirIfNeeded (dir);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Open: failed to create changelog directory (%s)\n", dir);
+ goto done;
+ }
+
+ s_cl5Desc.dbDir = slapi_ch_strdup (dir);
+
+ /* check database version */
+ rc = _cl5CheckDBVersion ();
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5Open: invalid db version\n");
+ goto done;
+ }
+
+ s_cl5Desc.dbOpenMode = openMode;
+
+ /* initialize db environment */
+ rc = _cl5AppInit (&didRecovery);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Open: failed to initialize db environment\n");
+ goto done;
+ }
+
+ /* open database files */
+ rc = _cl5DBOpen (!didRecovery);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Open: failed to open changelog database\n");
+
+ goto done;
+ }
+
+done:;
+
+ if (rc != CL5_SUCCESS)
+ {
+ _cl5Close ();
+ }
+
+ return rc;
+}
+
+int cl5CreateDirIfNeeded (const char *dirName)
+{
+ int rc;
+ char buff [MAXPATHLEN + 1];
+ char *t;
+
+ PR_ASSERT (dirName);
+
+ rc = PR_Access(dirName, PR_ACCESS_EXISTS);
+ if (rc == PR_SUCCESS)
+ {
+ return CL5_SUCCESS;
+ }
+
+ /* directory does not exist - try to create */
+ strncpy (buff, dirName, MAXPATHLEN);
+ t = strchr (buff, '/');
+
+ /* skip first slash */
+ if (t)
+ {
+ t = strchr (t+1, '/');
+ }
+
+ while (t)
+ {
+ *t = '\0';
+ if (PR_Access (buff, PR_ACCESS_EXISTS) != PR_SUCCESS)
+ {
+ rc = PR_MkDir (buff, DIR_CREATE_MODE);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5CreateDirIfNeeded: failed to create dir (%s); NSPR error - %d\n",
+ dirName, PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+ }
+
+ *t++ = FILE_PATHSEP;
+
+ t = strchr (t, '/');
+ }
+
+ /* last piece */
+ rc = PR_MkDir (buff, DIR_CREATE_MODE);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5CreateDirIfNeeded: failed to create dir; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5RemoveEnv ()
+{
+ DB_ENV *dbEnv = NULL;
+ int rc = 0;
+
+ if ((rc = db_env_create(&dbEnv, 0)) != 0)
+ dbEnv = NULL;
+
+ if (dbEnv == NULL)
+ {
+ char *errstr = db_strerror(rc);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5RemoveEnv: failed to allocate db environment; "
+ "db error - %d %s\n", rc, errstr ? errstr : "unknown");
+ return CL5_MEMORY_ERROR;
+ }
+ rc = dbEnv->remove(dbEnv, s_cl5Desc.dbDir, DB_FORCE);
+ if (0 != rc)
+ {
+ char *errstr = db_strerror(rc);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5AppInit: failed to remove db environment; "
+ "db error - %d %s\n", rc, errstr ? errstr : "unknown");
+ return CL5_DB_ERROR;
+ }
+ return CL5_SUCCESS;
+}
+
+static int _cl5AppInit (PRBool *didRecovery)
+{
+ int rc;
+ unsigned int flags = DB_CREATE | DB_INIT_MPOOL | DB_THREAD;
+ DB_ENV *dbEnv;
+ if ((rc = db_env_create(&dbEnv, 0)) != 0)
+ dbEnv = NULL;
+
+ if (dbEnv == NULL)
+ {
+ char *errstr = db_strerror(rc);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5AppInit: failed to allocate db environment; db error - %d (%s)\n",
+ rc, errstr ? errstr : "unknown");
+ return CL5_MEMORY_ERROR;
+ }
+
+ _cl5InitDBEnv (dbEnv);
+
+ if (didRecovery)
+ *didRecovery = PR_FALSE;
+
+ /* decide how two open based on the mode in which db is open */
+ switch (s_cl5Desc.dbOpenMode)
+ {
+ case CL5_OPEN_NORMAL:
+ flags |= DB_INIT_LOCK | DB_INIT_TXN | DB_INIT_LOG;
+ /* check if need to initiate recovery */
+ rc = _cl5CheckGuardian ();
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5AppInit: recovering changelog after disorderly shutdown\n");
+ flags |= DB_RECOVER;
+ }
+ break;
+
+ case CL5_OPEN_RESTORE:
+ flags |= DB_INIT_LOCK | DB_INIT_TXN | DB_INIT_LOG;
+ break;
+
+ case CL5_OPEN_CLEAN_RECOVER:
+ flags |= DB_INIT_LOCK | DB_INIT_TXN | DB_INIT_LOG | DB_RECOVER;
+ break;
+
+ case CL5_OPEN_RESTORE_RECOVER:
+ flags |= DB_INIT_LOCK | DB_INIT_TXN | DB_INIT_LOG | DB_RECOVER_FATAL;
+ break;
+
+ case CL5_OPEN_LDIF2CL:
+ /* ONREPL - don't think we need any extra flags here */
+ break;
+ default:
+ /* fixme? CL5_OPEN_NONE */
+ break;
+ }
+
+ if (!s_cl5Desc.dbConfig.durableTrans)
+ {
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3200
+ dbEnv->set_flags(dbEnv, DB_TXN_NOSYNC, 1);
+#else
+ flags |= DB_TXN_NOSYNC;
+#endif
+ }
+
+ dbEnv->set_errcall(dbEnv, dblayer_log_print);
+
+ /* do recovery if necessary */
+ if ((flags & DB_RECOVER) || (flags & DB_RECOVER_FATAL))
+ {
+ if (CL5_OPEN_CLEAN_RECOVER == s_cl5Desc.dbOpenMode)
+ _cl5RemoveEnv();
+
+ rc = _cl5Recover (flags, dbEnv);
+ if (rc != CL5_SUCCESS)
+ {
+ char *errstr = db_strerror(rc);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5AppInit: failed to recover changelog; db error - %d %s\n",
+ rc, errstr ? errstr : "unknown");
+
+ slapi_ch_free ((void **)&dbEnv);
+
+ return rc;
+ }
+
+ if (didRecovery)
+ *didRecovery = PR_TRUE;
+ flags &= ~(DB_RECOVER | DB_RECOVER_FATAL);
+ /* Need to reset the env */
+ /* Does this leak the dbEnv? */
+ if ((rc = db_env_create(&dbEnv, 0)) != 0)
+ dbEnv = NULL;
+
+ if (dbEnv == NULL)
+ {
+ char *errstr = db_strerror(rc);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5AppInit: failed to allocate db environment after recovery; "
+ "db error - %d %s\n", rc, errstr ? errstr : "unknown");
+ return CL5_MEMORY_ERROR;
+ }
+ _cl5InitDBEnv (dbEnv);
+ }
+
+ rc = dbEnv->open(dbEnv, s_cl5Desc.dbDir, flags,
+ s_cl5Desc.dbConfig.fileMode);
+ if (rc == 0)
+ {
+ s_cl5Desc.dbEnv = dbEnv;
+ s_cl5Desc.dbEnvOpenFlags = flags;
+ return CL5_SUCCESS;
+ }
+ else
+ {
+ char *errstr = db_strerror(rc);
+ char flagstr[20];
+
+ flagstr[0] = 0;
+ /* EINVAL return means bad flags - let's see what the flags are */
+ if (rc == EINVAL)
+ {
+ sprintf(flagstr, "%u", flags);
+ }
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5AppInit: db environment open failed; db error - %d %s %s\n",
+ rc, errstr ? errstr : "unknown", flagstr);
+ slapi_ch_free ((void **)&dbEnv);
+ return CL5_DB_ERROR;
+ }
+}
+
+static int _cl5DBOpen ()
+{
+ PRBool dbFile;
+ PRDir *dir;
+ PRDirEntry *entry = NULL;
+ int rc;
+ Object *replica;
+
+ /* create lock that guarantees that each file is only added once to the list */
+ s_cl5Desc.fileLock = PR_NewLock ();
+
+ /* loop over all db files and open them; file name format is cl5_<dbid>.<dbext> */
+ dir = PR_OpenDir(s_cl5Desc.dbDir);
+ if (dir == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5DBOpen: failed to open changelog dir; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+
+ }
+
+ /* initialize set of db file objects */
+ s_cl5Desc.dbFiles = objset_new(NULL);
+ while (NULL != (entry = PR_ReadDir(dir, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == entry->name)
+ {
+ break;
+ }
+
+ dbFile = _cl5FileName2Replica (entry->name, &replica);
+ if (dbFile) /* this is db file, not a log or dbversion; those are just skipped */
+ {
+ /* we only open files for existing replicas */
+ if (replica)
+ {
+ rc = _cl5DBOpenFile (replica, NULL /* file object */,
+ PR_FALSE /* check for duplicates */);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5DBOpen: "
+ "Error opening file %s\n",
+ entry->name);
+ return rc;
+ }
+
+ object_release (replica);
+ }
+ else /* there is no matching replica for the file - remove */
+ {
+ char fullpathname[MAXPATHLEN];
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5DBOpen: "
+ "file %s has no matching replica; removing\n", entry->name);
+
+ PR_snprintf(fullpathname, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, entry->name);
+ if (PR_Delete(fullpathname) != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5DBOpen: "
+ "failed to remove (%s) file; NSPR error - %d\n",
+ entry->name, PR_GetError ());
+
+ }
+ }
+ }
+ }
+
+ PR_CloseDir(dir);
+
+ return CL5_SUCCESS;
+}
+
+/* this function assumes that the entry was validated
+ using IsValidOperation
+
+ Data in db format:
+ ------------------
+ <1 byte version><1 byte change_type><sizeof time_t time><null terminated csn>
+ <null terminated uniqueid><null terminated targetdn>
+ [<null terminated newrdn><1 byte deleteoldrdn>][<4 byte mod count><mod1><mod2>....]
+
+ mod format:
+ -----------
+ <1 byte modop><null terminated attr name><4 byte value count>
+ <4 byte value size><value1><4 byte value size><value2>
+*/
+static int _cl5Entry2DBData (const CL5Entry *entry, char **data, PRUint32 *len)
+{
+ int size = 1 /* version */ + 1 /* operation type */ + sizeof (time_t);
+ char *pos;
+ PRUint32 t;
+ slapi_operation_parameters *op;
+ LDAPMod **add_mods = NULL;
+ char *rawDN = NULL;
+ char s[CSN_STRSIZE];
+
+ PR_ASSERT (entry && entry->op && data && len);
+
+ op = entry->op;
+
+ /* compute size of the buffer needed to hold the data */
+ size += CSN_STRSIZE;
+ size += strlen (op->target_address.uniqueid) + 1;
+
+ switch (op->operation_type)
+ {
+ case SLAPI_OPERATION_ADD: if (op->p.p_add.parentuniqueid)
+ size += strlen (op->p.p_add.parentuniqueid) + 1;
+ else
+ size ++; /* we just store NULL char */
+ slapi_entry2mods (op->p.p_add.target_entry, &rawDN/* dn */, &add_mods);
+ size += strlen (rawDN) + 1;
+ size += _cl5GetModsSize (add_mods);
+ break;
+
+ case SLAPI_OPERATION_MODIFY: size += strlen (op->target_address.dn) + 1;
+ size += _cl5GetModsSize (op->p.p_modify.modify_mods);
+ break;
+
+ case SLAPI_OPERATION_MODRDN: size += strlen (op->target_address.dn) + 1;
+ /* 1 for deleteoldrdn */
+ size += strlen (op->p.p_modrdn.modrdn_newrdn) + 2;
+ if (op->p.p_modrdn.modrdn_newsuperior_address.dn)
+ size += strlen (op->p.p_modrdn.modrdn_newsuperior_address.dn) + 1;
+ else
+ size ++; /* for NULL char */
+ if (op->p.p_modrdn.modrdn_newsuperior_address.uniqueid)
+ size += strlen (op->p.p_modrdn.modrdn_newsuperior_address.uniqueid) + 1;
+ else
+ size ++; /* for NULL char */
+ size += _cl5GetModsSize (op->p.p_modrdn.modrdn_mods);
+ break;
+
+ case SLAPI_OPERATION_DELETE: size += strlen (op->target_address.dn) + 1;
+ break;
+ }
+
+ /* allocate data buffer */
+ (*data) = (char *) slapi_ch_malloc (size);
+ if ((*data) == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5Entry2DBData: failed to allocate data buffer\n");
+ return CL5_MEMORY_ERROR;
+ }
+
+ /* fill in the data buffer */
+ pos = *data;
+ /* write a byte of version */
+ (*pos) = V_5;
+ pos ++;
+ /* write change type */
+ (*pos) = (unsigned char)op->operation_type;
+ pos ++;
+ /* write time */
+ t = PR_htonl((PRUint32)entry->time);
+ memcpy (pos, &t, sizeof (t));
+ pos += sizeof (t);
+ /* write csn */
+ _cl5WriteString (csn_as_string(op->csn,PR_FALSE,s), &pos);
+ /* write UniqueID */
+ _cl5WriteString (op->target_address.uniqueid, &pos);
+
+ /* figure out what else we need to write depending on the operation type */
+ switch (op->operation_type)
+ {
+ case SLAPI_OPERATION_ADD: _cl5WriteString (op->p.p_add.parentuniqueid, &pos);
+ _cl5WriteString (rawDN, &pos);
+ _cl5WriteMods (add_mods, &pos);
+ slapi_ch_free ((void**)&rawDN);
+ ldap_mods_free (add_mods, 1);
+ break;
+
+ case SLAPI_OPERATION_MODIFY: _cl5WriteString (op->target_address.dn, &pos);
+ _cl5WriteMods (op->p.p_modify.modify_mods, &pos);
+ break;
+
+ case SLAPI_OPERATION_MODRDN: _cl5WriteString (op->target_address.dn, &pos);
+ _cl5WriteString (op->p.p_modrdn.modrdn_newrdn, &pos);
+ *pos = (PRUint8)op->p.p_modrdn.modrdn_deloldrdn;
+ pos ++;
+ _cl5WriteString (op->p.p_modrdn.modrdn_newsuperior_address.dn, &pos);
+ _cl5WriteString (op->p.p_modrdn.modrdn_newsuperior_address.uniqueid, &pos);
+ _cl5WriteMods (op->p.p_modrdn.modrdn_mods, &pos);
+ break;
+
+ case SLAPI_OPERATION_DELETE: _cl5WriteString (op->target_address.dn, &pos);
+ break;
+ }
+
+ (*len) = size;
+
+ return CL5_SUCCESS;
+}
+
+/*
+ Data in db format:
+ ------------------
+ <1 byte version><1 byte change_type><sizeof time_t time><null terminated dbid>
+ <null terminated csn><null terminated uniqueid><null terminated targetdn>
+ [<null terminated newrdn><1 byte deleteoldrdn>][<4 byte mod count><mod1><mod2>....]
+
+ mod format:
+ -----------
+ <1 byte modop><null terminated attr name><4 byte value count>
+ <4 byte value size><value1><4 byte value size><value2>
+*/
+
+
+int
+cl5DBData2Entry (const char *data, PRUint32 len, CL5Entry *entry)
+{
+ int rc;
+ PRUint8 version;
+ char *pos = (char *)data;
+ char *strCSN;
+ PRUint32 thetime;
+ slapi_operation_parameters *op;
+ LDAPMod **add_mods;
+ char *rawDN;
+ char s[CSN_STRSIZE];
+
+ PR_ASSERT (data && entry && entry->op);
+
+ /* ONREPL - check that we do not go beyond the end of the buffer */
+
+ /* read byte of version */
+ version = (PRUint8)(*pos);
+ if (version != V_5)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5DBData2Entry: invalid data version\n");
+ return CL5_BAD_FORMAT;
+ }
+
+ op = entry->op;
+
+ pos += sizeof(version);
+
+ /* read change type */
+ op->operation_type = (PRUint8)(*pos);
+ pos ++;
+
+ /* need to do the copy first, to skirt around alignment problems on
+ certain architectures */
+ memcpy((char *)&thetime,pos,sizeof(thetime));
+ entry->time = (time_t)PR_ntohl(thetime);
+ pos += sizeof (thetime);
+
+ /* read csn */
+ _cl5ReadString (&strCSN, &pos);
+ if (op->csn == NULL || strcmp (strCSN, csn_as_string(op->csn,PR_FALSE,s)) != 0)
+ {
+ op->csn = csn_new_by_string (strCSN);
+ }
+ slapi_ch_free ((void**)&strCSN);
+
+ /* read UniqueID */
+ _cl5ReadString (&op->target_address.uniqueid, &pos);
+
+ /* figure out what else we need to read depending on the operation type */
+ switch (op->operation_type)
+ {
+ case SLAPI_OPERATION_ADD: _cl5ReadString (&op->p.p_add.parentuniqueid, &pos);
+ /* richm: need to free parentuniqueid */
+ _cl5ReadString (&rawDN, &pos);
+ op->target_address.dn = rawDN;
+ /* convert mods to entry */
+ rc = _cl5ReadMods (&add_mods, &pos);
+ slapi_mods2entry (&(op->p.p_add.target_entry), rawDN, add_mods);
+ ldap_mods_free (add_mods, 1);
+ break;
+
+ case SLAPI_OPERATION_MODIFY: _cl5ReadString (&op->target_address.dn, &pos);
+ rc = _cl5ReadMods (&op->p.p_modify.modify_mods, &pos);
+ break;
+
+ case SLAPI_OPERATION_MODRDN: _cl5ReadString (&op->target_address.dn, &pos);
+ _cl5ReadString (&op->p.p_modrdn.modrdn_newrdn, &pos);
+ op->p.p_modrdn.modrdn_deloldrdn = *pos;
+ pos ++;
+ _cl5ReadString (&op->p.p_modrdn.modrdn_newsuperior_address.dn, &pos);
+ _cl5ReadString (&op->p.p_modrdn.modrdn_newsuperior_address.uniqueid, &pos);
+ rc = _cl5ReadMods (&op->p.p_modrdn.modrdn_mods, &pos);
+ break;
+
+ case SLAPI_OPERATION_DELETE: _cl5ReadString (&op->target_address.dn, &pos);
+ rc = CL5_SUCCESS;
+ break;
+
+ default: rc = CL5_BAD_FORMAT;
+ slapi_log_error(SLAPI_LOG_FATAL,
+ repl_plugin_name_cl,
+ "cl5DBData2Entry: failed to format entry\n");
+ break;
+ }
+
+ return rc;
+}
+
+/* thread management functions */
+static int _cl5DispatchDBThreads ()
+{
+ if (NULL == PR_CreateThread (PR_USER_THREAD, (VFP)(void *)_cl5DeadlockMain,
+ NULL, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, DEFAULT_THREAD_STACKSIZE))
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5DispatchDBThreads: failed to create deadlock thread; "
+ "NSPR error - %d\n", PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ if (NULL == PR_CreateThread (PR_USER_THREAD, (VFP)(void *)_cl5CheckpointMain,
+ NULL, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, DEFAULT_THREAD_STACKSIZE))
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5DispatchDBThreads: failed to create checkpoint thread; "
+ "NSPR error - %d\n", PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ if (NULL == PR_CreateThread (PR_USER_THREAD, (VFP)(void *)_cl5TrickleMain,
+ NULL, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, DEFAULT_THREAD_STACKSIZE) )
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5DispatchDBThreads: failed to create trickle thread; "
+ "NSPR error - %d\n", PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ if (NULL == PR_CreateThread (PR_USER_THREAD, (VFP)(void*)_cl5TrimMain,
+ NULL, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, DEFAULT_THREAD_STACKSIZE) )
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5DispatchDBThreads: failed to create trimming thread; "
+ "NSPR error - %d\n", PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5AddThread ()
+{
+ /* lock the state lock so that nobody can change the state
+ while backup is in progress
+ */
+ PR_RWLock_Rlock (s_cl5Desc.stLock);
+
+ /* open changelog if it is not already open */
+ if (s_cl5Desc.dbState != CL5_STATE_OPEN)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5AddThread: invalid changelog state - %d\n", s_cl5Desc.dbState);
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+ return CL5_BAD_STATE;
+ }
+
+ /* increment global thread count to make sure that changelog does not close while
+ backup is in progress */
+ PR_AtomicIncrement (&s_cl5Desc.threadCount);
+
+ PR_RWLock_Unlock (s_cl5Desc.stLock);
+
+ return CL5_SUCCESS;
+}
+
+static void _cl5RemoveThread ()
+{
+ PR_ASSERT (s_cl5Desc.threadCount > 0);
+ PR_AtomicDecrement (&s_cl5Desc.threadCount);
+}
+
+/* data conversion functions */
+static void _cl5WriteString (const char *str, char **buff)
+{
+ if (str)
+ {
+ strcpy (*buff, str);
+ (*buff) += strlen (str) + 1;
+ }
+ else /* just write NULL char */
+ {
+ (**buff) = '\0';
+ (*buff) ++;
+ }
+}
+
+static void _cl5ReadString (char **str, char **buff)
+{
+ if (str)
+ {
+ int len = strlen (*buff);
+
+ if (len)
+ {
+ *str = slapi_ch_strdup (*buff);
+ (*buff) += len + 1;
+ }
+ else /* just null char - skip it */
+ {
+ *str = NULL;
+ (*buff) ++;
+ }
+ }
+ else /* just skip this string */
+ {
+ (*buff) += strlen (*buff) + 1;
+ }
+}
+
+/* mods format:
+ -----------
+ <4 byte mods count><mod1><mod2>...
+
+ mod format:
+ -----------
+ <1 byte modop><null terminated attr name><4 byte count>
+ <4 byte size><value1><4 byte size><value2>...
+ */
+static void _cl5WriteMods (LDAPMod **mods, char **buff)
+{
+ PRInt32 i;
+ char *mod_start;
+ PRInt32 count;
+
+ if (mods == NULL)
+ return;
+
+ /* skip mods count */
+ mod_start = (*buff) + sizeof (count);
+
+ /* write mods*/
+ for (i=0; mods[i]; i++)
+ {
+ _cl5WriteMod (mods[i], &mod_start);
+ }
+
+ count = PR_htonl(i);
+ memcpy (*buff, &count, sizeof (count));
+
+ (*buff) = mod_start;
+}
+
+static void _cl5WriteMod (LDAPMod *mod, char **buff)
+{
+ char *pos;
+ PRInt32 count;
+ struct berval *bv;
+ Slapi_Mod smod;
+
+ slapi_mod_init_byref(&smod, mod);
+
+ pos = *buff;
+ /* write mod op */
+ *pos = (PRUint8)slapi_mod_get_operation (&smod);
+ pos ++;
+ /* write attribute name */
+ _cl5WriteString (slapi_mod_get_type (&smod), &pos);
+
+ /* write value count */
+ count = PR_htonl(slapi_mod_get_num_values(&smod));
+ memcpy (pos, &count, sizeof (count));
+ pos += sizeof (PRInt32);
+
+ bv = slapi_mod_get_first_value (&smod);
+ while (bv)
+ {
+ _cl5WriteBerval (bv, &pos);
+ bv = slapi_mod_get_next_value (&smod);
+ }
+
+ (*buff) = pos;
+
+ slapi_mod_done (&smod);
+}
+
+/* mods format:
+ -----------
+ <4 byte mods count><mod1><mod2>...
+
+ mod format:
+ -----------
+ <1 byte modop><null terminated attr name><4 byte count>
+ {<4 byte size><value1><4 byte size><value2>... ||
+ <null terminated str1> <null terminated str2>...}
+ */
+
+static int _cl5ReadMods (LDAPMod ***mods, char **buff)
+{
+ char *pos = *buff;
+ int i;
+ int rc;
+ PRInt32 mod_count;
+ Slapi_Mods smods;
+ Slapi_Mod smod;
+
+ /* need to copy first, to skirt around alignment problems on certain
+ architectures */
+ memcpy((char *)&mod_count,*buff,sizeof(mod_count));
+ mod_count = PR_ntohl(mod_count);
+ pos += sizeof (mod_count);
+
+ slapi_mods_init (&smods , mod_count);
+
+ for (i = 0; i < mod_count; i++)
+ {
+ rc = _cl5ReadMod (&smod, &pos);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_mods_done(&smods);
+ return rc;
+ }
+
+ slapi_mods_add_smod(&smods, &smod);
+ }
+
+ *buff = pos;
+
+ *mods = slapi_mods_get_ldapmods_passout (&smods);
+ slapi_mods_done(&smods);
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5ReadMod (Slapi_Mod *smod, char **buff)
+{
+ char *pos = *buff;
+ int i;
+ PRInt32 val_count;
+ char *type;
+ int op;
+ struct berval bv;
+
+ op = (*pos) & 0x000000FF;
+ pos ++;
+ _cl5ReadString (&type, &pos);
+
+ /* need to do the copy first, to skirt around alignment problems on
+ certain architectures */
+ memcpy((char *)&val_count,pos,sizeof(val_count));
+ val_count = PR_ntohl(val_count);
+ pos += sizeof (PRInt32);
+
+ slapi_mod_init(smod, val_count);
+ slapi_mod_set_operation (smod, op|LDAP_MOD_BVALUES);
+ slapi_mod_set_type (smod, type);
+ slapi_ch_free ((void**)&type);
+
+ for (i = 0; i < val_count; i++)
+ {
+ _cl5ReadBerval (&bv, &pos);
+ slapi_mod_add_value (smod, &bv);
+ slapi_ch_free((void **) &bv.bv_val);
+ }
+
+ (*buff) = pos;
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5GetModsSize (LDAPMod **mods)
+{
+ int size;
+ int i;
+
+ if (mods == NULL)
+ return 0;
+
+ size = sizeof (PRInt32);
+ for (i=0; mods[i]; i++)
+ {
+ size += _cl5GetModSize (mods[i]);
+ }
+
+ return size;
+}
+
+static int _cl5GetModSize (LDAPMod *mod)
+{
+ int size;
+ int i;
+
+ size = 1 + strlen (mod->mod_type) + 1 + sizeof (mod->mod_op);
+ i = 0;
+ if (mod->mod_op & LDAP_MOD_BVALUES) /* values are in binary form */
+ {
+ while (mod->mod_bvalues != NULL && mod->mod_bvalues[i] != NULL)
+ {
+ size += mod->mod_bvalues[i]->bv_len + sizeof (mod->mod_bvalues[i]->bv_len);
+ i++;
+ }
+ }
+ else /* string data */
+ {
+ PR_ASSERT(0); /* ggood string values should never be used in the server */
+ }
+
+ return size;
+}
+
+static void _cl5ReadBerval (struct berval *bv, char** buff)
+{
+ PRUint32 length = 0;
+ PRUint32 net_length = 0;
+
+ PR_ASSERT (bv && buff);
+
+ /***PINAKI need to do the copy first, to skirt around alignment problems on
+ certain architectures */
+ /* DBDB : struct berval.bv_len is defined as unsigned long
+ * But code here expects it to be 32-bits in size.
+ * On 64-bit machines, this is not the case.
+ * I changed the code to consistently use 32-bit (4-byte)
+ * values on the encoded side. This means that it's
+ * possible to generate a huge berval that will not
+ * be encoded properly. However, this seems unlikely
+ * to happen in reality, and I felt that retaining the
+ * old on-disk format for the changely in the 64-bit
+ * version of the server was important.
+ */
+
+ memcpy((char *)&net_length, *buff, sizeof(net_length));
+ length = PR_ntohl(net_length);
+ *buff += sizeof(net_length);
+ bv->bv_len = length;
+
+ if (bv->bv_len > 0) {
+ bv->bv_val = (char*)slapi_ch_malloc (bv->bv_len);
+ memcpy (bv->bv_val, *buff, bv->bv_len);
+ *buff += bv->bv_len;
+ }
+ else {
+ bv->bv_val = NULL;
+ }
+}
+
+static void _cl5WriteBerval (struct berval *bv, char** buff)
+{
+ PRUint32 length = 0;
+ PRUint32 net_length = 0;
+
+ length = (PRUint32) bv->bv_len;
+ net_length = PR_htonl(length);
+
+ memcpy(*buff, &net_length, sizeof (net_length));
+ *buff += sizeof (net_length);
+ memcpy (*buff, bv->bv_val, length);
+ *buff += length;
+}
+
+/* data format: <value count> <value size> <value> <value size> <value> ..... */
+static int _cl5ReadBervals (struct berval ***bv, char** buff, unsigned int size)
+{
+ PRInt32 count;
+ int i;
+ char *pos;
+
+ PR_ASSERT (bv && buff);
+
+ /* ONREPL - need to check that we don't go beyond the end of the buffer */
+
+ pos = *buff;
+ memcpy((char *)&count, pos, sizeof(count));
+ count = PR_htonl (count);
+ pos += sizeof(count);
+
+ /* allocate bervals */
+ *bv = (struct berval **)slapi_ch_malloc ((count + 1) * sizeof (struct berval*));
+ if (*bv == NULL)
+ {
+ return CL5_MEMORY_ERROR;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ (*bv)[i] = (struct berval *)slapi_ch_malloc (sizeof (struct berval));
+ if ((*bv)[i] == NULL)
+ {
+ ber_bvecfree(*bv);
+ return CL5_MEMORY_ERROR;
+ }
+
+ _cl5ReadBerval ((*bv)[i], &pos);
+ }
+
+ (*bv)[count] = NULL;
+ *buff = pos;
+
+ return CL5_SUCCESS;
+}
+
+/* data format: <value count> <value size> <value> <value size> <value> ..... */
+static int _cl5WriteBervals (struct berval **bv, char** buff, unsigned int *size)
+{
+ PRInt32 count, net_count;
+ char *pos;
+ int i;
+
+ PR_ASSERT (bv && buff && size);
+
+ /* compute number of values and size of the buffer to hold them */
+ *size = sizeof (count);
+ for (count = 0; bv[count]; count ++)
+ {
+ *size += sizeof (bv[count]->bv_len) + bv[count]->bv_len;
+ }
+
+ /* allocate buffer */
+ *buff = (char*) slapi_ch_malloc (*size);
+ if (*buff == NULL)
+ {
+ *size = 0;
+ return CL5_MEMORY_ERROR;
+ }
+
+ /* fill the buffer */
+ pos = *buff;
+ net_count = PR_htonl(count);
+ memcpy (pos, &net_count, sizeof (net_count));
+ pos += sizeof (net_count);
+ for (i = 0; i < count; i ++)
+ {
+ _cl5WriteBerval (bv[i], &pos);
+ }
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5DeadlockMain (void *param)
+{
+ PRIntervalTime interval;
+ int rc;
+
+ PR_AtomicIncrement (&s_cl5Desc.threadCount);
+ interval = PR_MillisecondsToInterval(100);
+ while (s_cl5Desc.dbState != CL5_STATE_CLOSING)
+ {
+ int aborted;
+ if ((rc = LOCK_DETECT(s_cl5Desc.dbEnv, 0, DB_LOCK_YOUNGEST, &aborted)) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5DeadlockMain: lock_detect failed (%d transaction%s aborted); db error - %d %s\n",
+ aborted, (aborted == 1)? "":"s", rc, db_strerror(rc));
+ }
+ else if (aborted)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5DeadlockMain: lock_detect succeeded, but %d transaction%s ha%s been aborted\n",
+ aborted, (aborted == 1)? "":"s", (aborted == 1)? "s":"ve");
+ }
+
+ DS_Sleep(interval);
+ }
+
+ PR_AtomicDecrement (&s_cl5Desc.threadCount);
+ return 0;
+}
+
+static int _cl5CheckpointMain (void *param)
+{
+ time_t lastCheckpointCompletion = 0;
+ PRIntervalTime interval;
+ int rc = -1;
+
+ PR_AtomicIncrement (&s_cl5Desc.threadCount);
+
+ interval = PR_MillisecondsToInterval(1000);
+ lastCheckpointCompletion = current_time();
+
+ while (s_cl5Desc.dbState != CL5_STATE_CLOSING)
+ {
+ /* Check to see if the checkpoint interval has elapsed */
+ if (current_time() - lastCheckpointCompletion > s_cl5Desc.dbConfig.checkpointInterval)
+ {
+ rc = TXN_CHECKPOINT(s_cl5Desc.dbEnv, 0, 0, 0);
+ if (rc == 0)
+ {
+ lastCheckpointCompletion = current_time();
+ }
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ else if (rc != DB_INCOMPLETE) /* real error happened */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5CheckpointMain: checkpoint failed, db error - %d %s\n",
+ rc, db_strerror(rc));
+ }
+#endif
+
+ /* According to dboreham, we are doing checkpoint twice
+ to reduce the number of transaction log files which need
+ to be retained at any time. */
+ rc = TXN_CHECKPOINT(s_cl5Desc.dbEnv, 0, 0, 0);
+ if (rc == 0)
+ {
+ lastCheckpointCompletion = current_time();
+ }
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ else if (rc != DB_INCOMPLETE) /* real error happened */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5CheckpointMain: checkpoint failed, db error - %d %s\n",
+ rc, db_strerror(rc));
+ }
+#endif
+
+ /* check if we should truncate logs */
+ if (s_cl5Desc.dbConfig.circularLogging)
+ {
+ char **list = NULL;
+ char **listp = NULL;
+ int rc = -1;
+ char filename[MAXPATHLEN + 1];
+
+ /* find out which log files don't contain active txns */
+ rc = LOG_ARCHIVE(s_cl5Desc.dbEnv, &list, 0, malloc);
+ if (0 == rc && NULL != list)
+ {
+ /* zap 'em ! */
+ for (listp = list; *listp != NULL; ++listp)
+ {
+ PR_snprintf(filename, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir,*listp);
+ PR_Delete (filename);
+ }
+ slapi_ch_free((void **)&list);
+ }
+ }
+ }
+
+ /* sleep for a while */
+ /* why aren't we sleeping exactly the right amount of time ? */
+ /* answer---because the interval might be changed after the server starts up */
+ DS_Sleep(interval);
+ }
+
+ PR_AtomicDecrement (&s_cl5Desc.threadCount);
+ return 0;
+}
+
+static int _cl5TrickleMain (void *param)
+{
+ PRIntervalTime interval;
+ int pages_written;
+ int rc;
+
+ PR_AtomicIncrement (&s_cl5Desc.threadCount);
+ interval = PR_MillisecondsToInterval(1000);
+ while (s_cl5Desc.dbState != CL5_STATE_CLOSING)
+ {
+ if ((rc = MEMP_TRICKLE(s_cl5Desc.dbEnv,
+ s_cl5Desc.dbConfig.tricklePercentage, &pages_written)) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5TrickleMain: memp_trickle failed; db error - %d %s\n",
+ rc, db_strerror(rc));
+ }
+
+ DS_Sleep(interval);
+ }
+
+ PR_AtomicDecrement (&s_cl5Desc.threadCount);
+
+ return 0;
+}
+
+/* upgrade from db33 to db41
+ * 1. Run recovery on the database environment using the DB_ENV->open method
+ * 2. Remove any Berkeley DB environment using the DB_ENV->remove method
+ * 3. extention .db3 -> .db4 ### koko kara !!!
+ */
+static int _cl5Upgrade3_4(char *fromVersion, char *toVersion)
+{
+ PRDir *dir = NULL;
+ PRDirEntry *entry = NULL;
+ DB *thisdb = NULL;
+ CL5OpenMode backup;
+ int rc = 0;
+
+ backup = s_cl5Desc.dbOpenMode;
+ s_cl5Desc.dbOpenMode = CL5_OPEN_CLEAN_RECOVER;
+ /* CL5_OPEN_CLEAN_RECOVER does 1 and 2 */
+ rc = _cl5AppInit (NULL);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5Upgrade3_4: failed to open the db env\n");
+ return rc;
+ }
+
+ dir = PR_OpenDir(s_cl5Desc.dbDir);
+ if (dir == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5Upgrade3_4: failed to open changelog dir %s; NSPR error - %d\n",
+ s_cl5Desc.dbDir, PR_GetError ());
+ goto out;
+ }
+
+ while (NULL != (entry = PR_ReadDir(dir, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == entry->name)
+ {
+ break;
+ }
+ if (_cl5FileEndsWith(entry->name, DB_EXTENSION_DB3))
+ {
+ char oName [MAXPATHLEN + 1];
+ char nName [MAXPATHLEN + 1];
+ char *p = NULL;
+ char c;
+ int baselen = 0;
+ PR_snprintf(oName, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, entry->name);
+ p = strstr(oName, DB_EXTENSION_DB3);
+ if (NULL == p)
+ {
+ continue;
+ }
+ /* db->rename closes DB; need to create every time */
+ rc = db_create(&thisdb, s_cl5Desc.dbEnv, 0);
+ if (0 != rc) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5Upgrade3_4: failed to get db handle\n");
+ goto out;
+ }
+
+ baselen = p - oName;
+ c = *p;
+ *p = '\0';
+ PR_snprintf(nName, MAXPATHLEN+1, "%s", oName);
+ PR_snprintf(nName + baselen, MAXPATHLEN+1-baselen, "%s", DB_EXTENSION);
+ *p = c;
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Upgrade3_4: renaming %s to %s\n", oName, nName);
+ rc = thisdb->rename(thisdb, (const char *)oName, NULL /* subdb */,
+ (const char *)nName, 0);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Upgrade3_4: failed to rename file (%s -> %s); "
+ "db error - %d %s\n", oName, nName, rc, db_strerror(rc));
+ break;
+ }
+ }
+ }
+ /* update the version file */
+ _cl5WriteDBVersion ();
+
+ /* update the guardian file */
+ _cl5WriteGuardian ();
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Upgrading from %s to %s is successfully done (%s)\n",
+ fromVersion, toVersion, s_cl5Desc.dbDir);
+out:
+ if (NULL != dir)
+ {
+ PR_CloseDir(dir);
+ }
+ if (s_cl5Desc.dbEnv)
+ {
+ DB_ENV *dbEnv = s_cl5Desc.dbEnv;
+ dbEnv->close(dbEnv, 0);
+ s_cl5Desc.dbEnv = NULL;
+ }
+ return rc;
+}
+
+static int _cl5CheckDBVersion ()
+{
+ char clVersion [VERSION_SIZE + 1];
+ char dbVersion [VERSION_SIZE + 1];
+ int rc;
+
+ if (!cl5Exist (s_cl5Desc.dbDir))
+ {
+ /* this is new changelog - write DB version and guardian file */
+ rc = _cl5WriteDBVersion ();
+ if (rc == CL5_SUCCESS) {
+ rc = _cl5WriteGuardian();
+ }
+ }
+ else
+ {
+ PR_snprintf (clVersion, VERSION_SIZE, "%s/%s/%s", CL5_TYPE, REPL_PLUGIN_NAME,
+ CHANGELOG_DB_VERSION);
+ rc = _cl5ReadDBVersion (s_cl5Desc.dbDir, dbVersion);
+
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5CheckDBVersion: invalid dbversion\n");
+ rc = CL5_BAD_DBVERSION;
+ }
+ else if (strcasecmp (clVersion, dbVersion) != 0)
+ {
+ char prevClVersion [VERSION_SIZE + 1];
+ PR_snprintf (prevClVersion, VERSION_SIZE, "%s/%s/%s",
+ CL5_TYPE, REPL_PLUGIN_NAME, CHANGELOG_DB_VERSION_PREV);
+ if (strcasecmp (prevClVersion, dbVersion) == 0)
+ {
+ /* upgrade */
+ rc = _cl5Upgrade3_4(prevClVersion, clVersion);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5CheckDBVersion: upgrade %s -> %s failed\n",
+ CHANGELOG_DB_VERSION_PREV, CHANGELOG_DB_VERSION);
+ rc = CL5_BAD_DBVERSION;
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5CheckDBVersion: invalid dbversion\n");
+ rc = CL5_BAD_DBVERSION;
+ }
+ }
+
+ }
+
+ return rc;
+}
+
+static int _cl5ReadDBVersion (const char *dir, char *clVersion)
+{
+ int rc;
+ PRFileDesc *file;
+ char fName [MAXPATHLEN + 1];
+ char buff [BUFSIZ];
+ PRInt32 size;
+ char *tok;
+ char * iter = NULL;
+
+ if (clVersion)
+ {
+ clVersion [0] = '\0';
+ }
+
+ PR_snprintf (fName, MAXPATHLEN, "%s/%s", dir, VERSION_FILE);
+
+ file = PR_Open (fName, PR_RDONLY, 777);
+ if (file == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5ReadDBVersion: failed to open DBVERSION; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ size = slapi_read_buffer (file, buff, BUFSIZ);
+ if (size < 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5ReadDBVersion: failed to read DBVERSION; NSPR error - %d\n",
+ PR_GetError ());
+ PR_Close (file);
+ return CL5_SYSTEM_ERROR;
+ }
+
+ /* parse the data */
+ buff[size]= '\0';
+ tok = ldap_utf8strtok_r (buff, "\n", &iter);
+ if (tok)
+ {
+ if (clVersion)
+ {
+ strcpy(clVersion, tok);
+ }
+ }
+
+ rc = PR_Close (file);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5ReadDBVersion: failed to close DBVERSION; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5WriteDBVersion ()
+{
+ int rc;
+ PRFileDesc *file;
+ char fName [MAXPATHLEN + 1];
+ char clVersion [VERSION_SIZE + 1];
+ PRInt32 len, size;
+
+ PR_snprintf (fName, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, VERSION_FILE);
+
+ file = PR_Open (fName, PR_WRONLY | PR_CREATE_FILE, s_cl5Desc.dbConfig.fileMode);
+ if (file == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5WriteDBVersion: failed to open DBVERSION; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ /* write changelog version */
+ PR_snprintf (clVersion, VERSION_SIZE, "%s/%s/%s\n", CL5_TYPE, REPL_PLUGIN_NAME,
+ CHANGELOG_DB_VERSION);
+
+ len = strlen (clVersion);
+ size = slapi_write_buffer (file, clVersion, len);
+ if (size != len)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5WriteDBVersion: failed to write DBVERSION; NSPR error - %d\n",
+ PR_GetError ());
+ PR_Close (file);
+ return CL5_SYSTEM_ERROR;
+ }
+
+ rc = PR_Close (file);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5WriteDBVersion: failed to close DBVERSION; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ return CL5_SUCCESS;
+}
+
+/* for now guardian file is just like dbversion file */
+static int _cl5CheckGuardian ()
+{
+ char plVersion [VERSION_SIZE + 1];
+ char dbVersion [VERSION_SIZE + 1];
+ int rc;
+
+ /* new changelog - no guardian file */
+ if (!cl5Exist(s_cl5Desc.dbDir))
+ {
+ return CL5_SUCCESS;
+ }
+ else
+ {
+ PR_snprintf (plVersion, VERSION_SIZE, "%s/%s/%s", CL5_TYPE, REPL_PLUGIN_NAME,
+ CHANGELOG_DB_VERSION);
+ rc = _cl5ReadGuardian (dbVersion);
+
+ if (rc != CL5_SUCCESS || strcasecmp (plVersion, dbVersion) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5CheckGuardian: missing or invalid guardian file\n");
+ return (CL5_BAD_FORMAT);
+ }
+
+ /* remove guardian file */
+ rc = _cl5RemoveGuardian ();
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5CheckGuardian: failed to remove guardian file\n");
+ }
+ }
+
+ return rc;
+}
+
+static int _cl5WriteGuardian ()
+{
+ int rc;
+ PRFileDesc *file;
+ char fName [MAXPATHLEN + 1];
+ char version [VERSION_SIZE];
+ PRInt32 len, size;
+
+ PR_snprintf (fName, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, GUARDIAN_FILE);
+
+ file = PR_Open (fName, PR_WRONLY | PR_CREATE_FILE, s_cl5Desc.dbConfig.fileMode);
+ if (file == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5WriteGuardian: failed to open guardian file; NSPR error - %d\n",
+ PR_GetError());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ PR_snprintf (version, VERSION_SIZE, "%s/%s/%s\n", CL5_TYPE, REPL_PLUGIN_NAME,
+ CHANGELOG_DB_VERSION);
+
+ len = strlen (version);
+ size = slapi_write_buffer (file, version, len);
+ if (size != len)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteGuardian: failed to write guardian file; NSPR error - %d\n",
+ PR_GetError());
+ PR_Close (file);
+ return CL5_SYSTEM_ERROR;
+ }
+
+ rc = PR_Close (file);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5WriteGuardian: failed to close guardian file; NSPR error - %d\n",
+ PR_GetError());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5ReadGuardian (char *buff)
+{
+ int rc;
+ PRFileDesc *file;
+ char fName [MAXPATHLEN + 1];
+ PRInt32 size;
+
+ PR_snprintf (fName, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, GUARDIAN_FILE);
+
+ file = PR_Open (fName, PR_RDONLY, 0);
+ if (file == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5ReadGuardian: failed to open guardian file; NSPR error - %d\n",
+ PR_GetError());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ size = slapi_read_buffer (file, buff, VERSION_SIZE);
+ if (size <= 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5ReadGuardian: failed to read guardian file; NSPR error - %d\n",
+ PR_GetError());
+ PR_Close (file);
+ return CL5_SYSTEM_ERROR;
+ }
+
+ buff [size-1] = '\0';
+
+ rc = PR_Close (file);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5ReadGuardian: failed to close guardian file; NSPR error - %d\n",
+ PR_GetError());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5RemoveGuardian ()
+{
+ char fName [MAXPATHLEN + 1];
+ int rc;
+
+ PR_snprintf (fName, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, GUARDIAN_FILE);
+
+ rc = PR_Delete (fName);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5RemoveGuardian: failed to remove guardian file; NSPR error - %d\n",
+ PR_GetError());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ return CL5_SUCCESS;
+}
+
+/* must be called under the state lock */
+static void _cl5Close ()
+{
+ int rc2 = 0;
+ PRIntervalTime interval;
+
+ if (s_cl5Desc.dbState != CL5_STATE_CLOSED) /* Don't try to close twice */
+ {
+
+ /* close db files */
+ _cl5DBClose ();
+
+ /* stop global threads */
+ interval = PR_MillisecondsToInterval(100);
+ while (s_cl5Desc.threadCount > 0)
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "_cl5Close: waiting for threads to exit: %d thread(s) still active\n",
+ s_cl5Desc.threadCount);
+ DS_Sleep(interval);
+ }
+
+ /* cleanup trimming */
+ _cl5TrimCleanup ();
+
+ /* shutdown db environment */
+ if (s_cl5Desc.dbEnv)
+ {
+ DB_ENV *dbEnv = s_cl5Desc.dbEnv;
+ rc2 = dbEnv->close(dbEnv, 0);
+ s_cl5Desc.dbEnv = NULL;
+ }
+
+ /* record successful close by writing guardian file;
+ we do it in all case accept incomplete open due to an error */
+ if (s_cl5Desc.dbState == CL5_STATE_CLOSING || s_cl5Desc.dbOpenMode != CL5_OPEN_NORMAL)
+ {
+ _cl5WriteGuardian ();
+ }
+
+ /* remove changelog if requested */
+ if (s_cl5Desc.dbRmOnClose)
+ {
+
+ if (_cl5Delete (s_cl5Desc.dbDir, 1) != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5Close: failed to remove changelog\n");
+ }
+ s_cl5Desc.dbRmOnClose = PR_FALSE;
+ }
+
+ slapi_ch_free ((void **)&s_cl5Desc.dbDir);
+ memset (&s_cl5Desc.dbConfig, 0, sizeof (s_cl5Desc.dbConfig));
+ s_cl5Desc.fatalError = PR_FALSE;
+ s_cl5Desc.threadCount = 0;
+ s_cl5Desc.dbOpenMode = CL5_OPEN_NONE;
+ }
+}
+
+static void _cl5DBClose ()
+{
+ if (NULL != s_cl5Desc.dbFiles)
+ {
+ objset_delete (&s_cl5Desc.dbFiles);
+ }
+ if (NULL != s_cl5Desc.fileLock)
+ {
+ PR_DestroyLock (s_cl5Desc.fileLock);
+ }
+}
+
+/* state lock must be locked */
+static int _cl5Delete (const char *clDir, int rmDir)
+{
+ PRDir *dir;
+ char filename[MAXPATHLEN + 1];
+ PRDirEntry *entry = NULL;
+ int rc;
+
+ /* remove all files in the directory and the directory */
+ dir = PR_OpenDir(clDir);
+ if (dir == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Delete: failed to open changelog dir; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+
+ }
+
+ while (NULL != (entry = PR_ReadDir(dir, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == entry->name)
+ {
+ break;
+ }
+ PR_snprintf(filename, MAXPATHLEN, "%s/%s", clDir, entry->name);
+ rc = PR_Delete(filename);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Delete: failed to remove (%s) file; NSPR error - %d\n",
+ filename, PR_GetError ());
+ }
+ }
+
+ rc = PR_CloseDir(dir);
+ if (rc != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Delete: failed to close changelog dir (%s); NSPR error - %d\n",
+ clDir, PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+
+ if (rmDir)
+ {
+ rc = PR_RmDir (clDir);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5Delete: failed to remove changelog dir (%s); errno = %d\n",
+ clDir, errno);
+ return CL5_SYSTEM_ERROR;
+ }
+ }
+
+ return CL5_SUCCESS;
+}
+
+static void _cl5SetDefaultDBConfig ()
+{
+ s_cl5Desc.dbConfig.cacheSize = CL5_DEFAULT_CONFIG_DB_DBCACHESIZE;
+ s_cl5Desc.dbConfig.durableTrans = CL5_DEFAULT_CONFIG_DB_DURABLE_TRANSACTIONS;
+ s_cl5Desc.dbConfig.checkpointInterval = CL5_DEFAULT_CONFIG_DB_CHECKPOINT_INTERVAL;
+ s_cl5Desc.dbConfig.circularLogging = CL5_DEFAULT_CONFIG_DB_CIRCULAR_LOGGING;
+ s_cl5Desc.dbConfig.pageSize = CL5_DEFAULT_CONFIG_DB_PAGE_SIZE;
+ s_cl5Desc.dbConfig.logfileSize = CL5_DEFAULT_CONFIG_DB_LOGFILE_SIZE;
+ s_cl5Desc.dbConfig.maxTxnSize = CL5_DEFAULT_CONFIG_DB_TXN_MAX;
+ s_cl5Desc.dbConfig.verbose = CL5_DEFAULT_CONFIG_DB_VERBOSE;
+ s_cl5Desc.dbConfig.debug = CL5_DEFAULT_CONFIG_DB_DEBUG;
+ s_cl5Desc.dbConfig.tricklePercentage = CL5_DEFAULT_CONFIG_DB_TRICKLE_PERCENTAGE;
+ s_cl5Desc.dbConfig.spinCount = CL5_DEFAULT_CONFIG_DB_SPINCOUNT;
+ s_cl5Desc.dbConfig.nb_lock_config = CL5_DEFAULT_CONFIG_NB_LOCK;
+ s_cl5Desc.dbConfig.fileMode = FILE_CREATE_MODE;
+}
+
+static void _cl5SetDBConfig (const CL5DBConfig *config)
+{
+ /* through CL5DBConfig, we have access to all the LDAP configurable Changelog DB parameters */
+ s_cl5Desc.dbConfig.cacheSize = config->cacheSize;
+ s_cl5Desc.dbConfig.durableTrans = config->durableTrans;
+ s_cl5Desc.dbConfig.checkpointInterval = config->checkpointInterval;
+ s_cl5Desc.dbConfig.circularLogging = config->circularLogging;
+ s_cl5Desc.dbConfig.pageSize = config->pageSize;
+ s_cl5Desc.dbConfig.logfileSize = config->logfileSize;
+ s_cl5Desc.dbConfig.maxTxnSize = config->maxTxnSize;
+ s_cl5Desc.dbConfig.verbose = config->verbose;
+ s_cl5Desc.dbConfig.debug = config->debug;
+ s_cl5Desc.dbConfig.tricklePercentage = config->tricklePercentage;
+ s_cl5Desc.dbConfig.spinCount = config->spinCount;
+ s_cl5Desc.dbConfig.nb_lock_config = config->nb_lock_config;
+ s_cl5Desc.dbConfig.maxConcurrentWrites = config->maxConcurrentWrites;
+
+ if (config->spinCount != 0)
+ {
+ DB_ENV_SET_TAS_SPINS(s_cl5Desc.dbEnv, config->spinCount);
+ }
+
+ /* Some other configuration parameters are hardcoded... */
+ s_cl5Desc.dbConfig.fileMode = FILE_CREATE_MODE;
+}
+
+#define ONEG 1073741824 /* one giga bytes */
+static void _cl5InitDBEnv(DB_ENV *dbEnv)
+{
+ dbEnv->set_errpfx(dbEnv, "ns-slapd");
+ dbEnv->set_lg_max(dbEnv, s_cl5Desc.dbConfig.logfileSize);
+ dbEnv->set_tx_max(dbEnv, s_cl5Desc.dbConfig.maxTxnSize);
+ dbEnv->set_cachesize(dbEnv, s_cl5Desc.dbConfig.cacheSize/ONEG,
+ s_cl5Desc.dbConfig.cacheSize%ONEG,
+ 0);
+ /* Set default number of locks */
+ dbEnv->set_lk_max_locks(dbEnv, s_cl5Desc.dbConfig.nb_lock_config);
+
+ if (s_cl5Desc.dbConfig.verbose)
+ {
+ int on = 1;
+ dbEnv->set_verbose(dbEnv, DB_VERB_CHKPOINT, on);
+ dbEnv->set_verbose(dbEnv, DB_VERB_DEADLOCK, on);
+ dbEnv->set_verbose(dbEnv, DB_VERB_RECOVERY, on);
+ dbEnv->set_verbose(dbEnv, DB_VERB_WAITSFOR, on);
+ }
+ if (s_cl5Desc.dbConfig.debug)
+ {
+ dbEnv->set_errcall(dbEnv, _cl5DBLogPrint);
+ }
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3300
+ dbEnv->set_alloc(dbEnv, malloc, realloc, free);
+#endif
+}
+
+static void _cl5DBLogPrint(const char* prefix, char *buffer)
+{
+ /* We ignore the prefix since we know who we are anyway */
+ slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name_cl, "cl5: %s\n", buffer);
+}
+
+static PRBool _cl5IsLogFile (const char *path)
+{
+ int rc;
+
+ /* Is the filename at least 4 characters long ? */
+ if (strlen(path) < 4)
+ {
+ return PR_FALSE; /* Not a log file then */
+ }
+
+ /* Are the first 4 characters "log." ? */
+ rc = strncmp(path,"log.",4);
+ if (0 == rc)
+ {
+ /* Now, are the last 4 characters _not_ .db# ? */
+ const char *piece = path + (strlen(path) - 4);
+ rc = strcmp(piece, DB_EXTENSION);
+ if (0 != rc)
+ {
+ /* Is */
+ return PR_TRUE;
+ }
+ }
+ return PR_FALSE; /* Is not */
+}
+
+static int _cl5Recover (int open_flags, DB_ENV *dbEnv)
+{
+ /* If we're doing recovery, we MUST open the env single-threaded ! */
+ int recover_flags = open_flags & ~DB_THREAD;
+ int rc;
+
+ rc = dbEnv->open(dbEnv, s_cl5Desc.dbDir, recover_flags, s_cl5Desc.dbConfig.fileMode);
+
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5Recover: appinit failed; db error - %d %s\n",
+ rc, db_strerror(rc));
+ return CL5_DB_ERROR;
+ }
+
+ /* Now close it so we can re-open it again... */
+ dbEnv->close(dbEnv, 0);
+
+ return CL5_SUCCESS;
+}
+
+/* Trimming helper functions */
+static int _cl5TrimInit ()
+{
+ /* just create the lock while we are singlethreaded */
+ s_cl5Desc.dbTrim.lock = PR_NewLock();
+
+ if (s_cl5Desc.dbTrim.lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5InitTrimming: failed to create lock; NSPR error - %d\n",
+ PR_GetError ());
+ return CL5_SYSTEM_ERROR;
+ }
+ else
+ {
+ return CL5_SUCCESS;
+ }
+}
+
+static void _cl5TrimCleanup ()
+{
+ if (s_cl5Desc.dbTrim.lock)
+ PR_DestroyLock (s_cl5Desc.dbTrim.lock);
+
+ memset (&s_cl5Desc.dbTrim, 0, sizeof (s_cl5Desc.dbTrim));
+}
+
+static int _cl5TrimMain (void *param)
+{
+ PRIntervalTime interval;
+ time_t timePrev = current_time ();
+ time_t timeNow;
+
+ PR_AtomicIncrement (&s_cl5Desc.threadCount);
+ interval = PR_SecondsToInterval(CHANGELOGDB_TRIM_INTERVAL);
+
+ while (s_cl5Desc.dbState != CL5_STATE_CLOSING)
+ {
+ timeNow = current_time ();
+ if (timeNow - timePrev >= CHANGELOGDB_TRIM_INTERVAL)
+ {
+ /* time to trim */
+ timePrev = timeNow;
+ _cl5DoTrimming ();
+ }
+ if (NULL == s_cl5Desc.clLock)
+ {
+ /* most likely, emergency */
+ break;
+ }
+
+ PR_Lock(s_cl5Desc.clLock);
+ PR_WaitCondVar(s_cl5Desc.clCvar, interval);
+ PR_Unlock(s_cl5Desc.clLock);
+ }
+
+ PR_AtomicDecrement (&s_cl5Desc.threadCount);
+
+ return 0;
+}
+
+/* We remove an entry if it has been replayed to all consumers and
+ and the number of entries in the changelog is larger than maxEntries
+ or age of the entry is larger than maxAge.
+ Also we can't purge entries which correspond to max csns in the
+ supplier's ruv. Here is a example where we can get into trouble:
+ The server is setup with time based trimming and no consumer's
+ At some point all the entries are trimmed from the changelog.
+ At a later point a consumer is added and initialized online
+ Then a change is made on the supplier.
+ To update the consumer, the supplier would attempt to locate
+ the last change sent to the consumer in the changelog and will
+ fail because the change was removed.
+
+ */
+
+static void _cl5DoTrimming ()
+{
+ Object *obj;
+ long numToTrim;
+
+ PR_Lock (s_cl5Desc.dbTrim.lock);
+
+ /* ONREPL We trim file by file which means that some files will be
+ trimmed more often than other. We might have to fix that by, for
+ example, randomizing starting point */
+ obj = objset_first_obj (s_cl5Desc.dbFiles);
+ while (obj && _cl5CanTrim ((time_t)0, &numToTrim))
+ {
+ _cl5TrimFile (obj, &numToTrim);
+ obj = objset_next_obj (s_cl5Desc.dbFiles, obj);
+ }
+
+ if (obj)
+ object_release (obj);
+
+ PR_Unlock (s_cl5Desc.dbTrim.lock);
+
+ return;
+}
+
+/* Note that each file contains changes for a single replicated area.
+ trimming algorithm:
+*/
+#define CL5_TRIM_MAX_PER_TRANSACTION 10
+
+static void _cl5TrimFile (Object *obj, long *numToTrim)
+{
+ DB_TXN *txnid;
+ RUV *ruv = NULL;
+ CL5Entry entry;
+ slapi_operation_parameters op = {0};
+ void *it;
+ int finished = 0, totalTrimmed = 0, count;
+ PRBool abort;
+ char strCSN[CSN_STRSIZE];
+ int rc;
+
+ PR_ASSERT (obj);
+
+ /* construct the ruv up to which we can purge */
+ rc = _cl5GetRUV2Purge2 (obj, &ruv);
+ if (rc != CL5_SUCCESS || ruv == NULL)
+ {
+ return;
+ }
+
+ entry.op = &op;
+
+ while ( !finished && !g_get_shutdown() )
+ {
+ it = NULL;
+ count = 0;
+ txnid = NULL;
+ abort = PR_FALSE;
+
+ /* DB txn lock accessed pages until the end of the transaction. */
+
+ rc = TXN_BEGIN(s_cl5Desc.dbEnv, NULL, &txnid, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5TrimFile: failed to begin transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ finished = PR_TRUE;
+ break;
+ }
+
+ finished = _cl5GetFirstEntry (obj, &entry, &it, txnid);
+ while ( !finished )
+ {
+ /*
+ * This change can be trimmed if it exceeds purge
+ * parameters and has been seen by all consumers.
+ */
+ if ( (*numToTrim > 0 || _cl5CanTrim (entry.time, numToTrim)) &&
+ ruv_covers_csn_strict (ruv, op.csn) )
+ {
+ rc = _cl5CurrentDeleteEntry (it);
+ if ( rc == CL5_SUCCESS )
+ {
+ /* update purge vector */
+ rc = _cl5UpdateRUV (obj, op.csn, PR_FALSE, PR_TRUE);
+ }
+ if ( rc == CL5_SUCCESS)
+ {
+ if (*numToTrim > 0) (*numToTrim)--;
+ count++;
+ }
+ else
+ {
+ /* The above two functions have logged the error */
+ abort = PR_TRUE;
+ }
+
+ }
+ else
+ {
+ /* The changelog DB is time ordered. If we can not trim
+ * a CSN, we will not be allowed to trim the rest of the
+ * CSNs generally. However, the maxcsn of each replica ID
+ * is always kept in the changelog as an anchor for
+ * replaying future changes. We have to skip those anchor
+ * CSNs, otherwise a non-active replica ID could block
+ * the trim forever.
+ */
+ CSN *maxcsn = NULL;
+ ReplicaId rid;
+
+ rid = csn_get_replicaid (op.csn);
+ ruv_get_largest_csn_for_replica (ruv, rid, &maxcsn);
+ if ( csn_compare (op.csn, maxcsn) != 0 )
+ {
+ /* op.csn is not anchor CSN */
+ finished = 1;
+ }
+ else
+ {
+ slapi_log_error (SLAPI_LOG_REPL, NULL,
+ "Changelog purge skipped anchor csn %s\n",
+ csn_as_string (maxcsn, PR_FALSE, strCSN));
+
+ /* extra read to skip the current record */
+ cl5_operation_parameters_done (&op);
+ finished =_cl5GetNextEntry (&entry, it);
+ }
+ if (maxcsn) csn_free (&maxcsn);
+ }
+ cl5_operation_parameters_done (&op);
+ if (finished || abort || count >= CL5_TRIM_MAX_PER_TRANSACTION)
+ {
+ /* If we reach CL5_TRIM_MAX_PER_TRANSACTION,
+ * we close the cursor,
+ * commit the transaction and restart a new transaction
+ */
+ break;
+ }
+ finished = _cl5GetNextEntry (&entry, it);
+ }
+
+ /* MAB: We need to close the cursor BEFORE the txn commits/aborts.
+ * If we don't respect this order, we'll screw up the database,
+ * placing it in DB_RUNRECOVERY mode
+ */
+ cl5DestroyIterator (it);
+
+ if (abort)
+ {
+ finished = 1;
+ rc = TXN_ABORT (txnid);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5TrimFile: failed to abort transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ }
+ }
+ else
+ {
+ rc = TXN_COMMIT (txnid, 0);
+ if (rc != 0)
+ {
+ finished = 1;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5TrimFile: failed to commit transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ }
+ else
+ {
+ totalTrimmed += count;
+ }
+ }
+
+ } /* While (!finished) */
+
+ if (ruv)
+ ruv_destroy (&ruv);
+
+ if (totalTrimmed)
+ {
+ slapi_log_error (SLAPI_LOG_REPL, NULL, "Trimmed %d changes from the changelog\n", totalTrimmed);
+ }
+}
+
+static PRBool _cl5CanTrim (time_t time, long *numToTrim)
+{
+ *numToTrim = 0;
+
+ if (s_cl5Desc.dbTrim.maxAge == 0 && s_cl5Desc.dbTrim.maxEntries == 0)
+ return PR_FALSE;
+
+ if (s_cl5Desc.dbTrim.maxAge == 0)
+ {
+ *numToTrim = cl5GetOperationCount (NULL) - s_cl5Desc.dbTrim.maxEntries;
+ return ( *numToTrim > 0 );
+ }
+
+ if (s_cl5Desc.dbTrim.maxEntries > 0 &&
+ (*numToTrim = cl5GetOperationCount (NULL) - s_cl5Desc.dbTrim.maxEntries) > 0)
+ return PR_TRUE;
+
+ if (time)
+ return (current_time () - time > s_cl5Desc.dbTrim.maxAge);
+ else
+ return PR_TRUE;
+}
+
+static int _cl5ReadRUV (const char *replGen, Object *obj, PRBool purge)
+{
+ int rc;
+ char csnStr [CSN_STRSIZE];
+ DBT key={0}, data={0};
+ struct berval **vals;
+ CL5DBFile *file;
+ char *pos;
+ char *agmt_name;
+
+
+ PR_ASSERT (replGen && obj);
+
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+
+ agmt_name = get_thread_private_agmtname();
+
+ if (purge) /* read purge vector entry */
+ key.data = _cl5GetHelperEntryKey (PURGE_RUV_TIME, csnStr);
+ else /* read upper bound vector */
+ key.data = _cl5GetHelperEntryKey (MAX_RUV_TIME, csnStr);
+
+ key.size = CSN_STRSIZE;
+
+ data.flags = DB_DBT_MALLOC;
+
+ rc = file->db->get(file->db, NULL/*txn*/, &key, &data, 0);
+ switch (rc)
+ {
+ case 0: pos = data.data;
+ rc = _cl5ReadBervals (&vals, &pos, data.size);
+ free (data.data);
+ if (rc != CL5_SUCCESS)
+ return rc;
+
+ if (purge)
+ rc = ruv_init_from_bervals(vals, &file->purgeRUV);
+ else
+ rc = ruv_init_from_bervals(vals, &file->maxRUV);
+
+ if (rc != RUV_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "%s: _cl5ReadRUV: failed to initialize %s ruv; "
+ "RUV error %d\n", agmt_name, purge? "purge" : "upper bound", rc);
+
+ return CL5_RUV_ERROR;
+ }
+
+ ber_bvecfree(vals);
+
+ /* delete the entry; it is re-added when file
+ is successfully closed */
+ file->db->del (file->db, NULL, &key, DEFAULT_DB_OP_FLAGS);
+
+ return CL5_SUCCESS;
+
+ case DB_NOTFOUND: /* RUV is lost - need to construct */
+ rc = _cl5ConstructRUV (replGen, obj, purge);
+ return rc;
+
+ default: slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "%s: _cl5ReadRUV: failed to get purge RUV; "
+ "db error - %d %s\n", agmt_name, rc, db_strerror(rc));
+ return CL5_DB_ERROR;
+ }
+}
+
+static int _cl5WriteRUV (CL5DBFile *file, PRBool purge)
+{
+ int rc;
+ DBT key={0}, data={0};
+ char csnStr [CSN_STRSIZE];
+ struct berval **vals;
+ DB_TXN *txnid = NULL;
+
+ if ((purge && file->purgeRUV == NULL) || (!purge && file->maxRUV == NULL))
+ return CL5_SUCCESS;
+
+ if (purge)
+ {
+ key.data = _cl5GetHelperEntryKey (PURGE_RUV_TIME, csnStr);
+ rc = ruv_to_bervals(file->purgeRUV, &vals);
+ }
+ else
+ {
+ key.data = _cl5GetHelperEntryKey (MAX_RUV_TIME, csnStr);
+ rc = ruv_to_bervals(file->maxRUV, &vals);
+ }
+
+ key.size = CSN_STRSIZE;
+
+ rc = _cl5WriteBervals (vals, (char**)&data.data, &data.size);
+ ber_bvecfree(vals);
+ if (rc != CL5_SUCCESS)
+ {
+ return rc;
+ }
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ rc = txn_begin(s_cl5Desc.dbEnv, NULL, &txnid, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteRUV: failed to begin transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ return CL5_DB_ERROR;
+ }
+#endif
+ rc = file->db->put(file->db, txnid, &key, &data, DEFAULT_DB_OP_FLAGS);
+
+ slapi_ch_free ((void**)&data.data);
+ if ( rc == 0 )
+ {
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ rc = txn_commit (txnid, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteRUV: failed to commit transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ return CL5_DB_ERROR;
+ }
+#endif
+ return CL5_SUCCESS;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteRUV: failed to write %s RUV for file %s; db error - %d\n",
+ purge? "purge" : "upper bound", file->name, rc);
+
+ if (CL5_OS_ERR_IS_DISKFULL(rc))
+ {
+ cl5_set_diskfull();
+ return CL5_DB_ERROR;
+ }
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ rc = txn_abort (txnid);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteRUV: failed to abort transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ }
+#endif
+ return CL5_DB_ERROR;
+ }
+}
+
+/* This is a very slow process since we have to read every changelog entry.
+ Hopefully, this function is not called too often */
+static int _cl5ConstructRUV (const char *replGen, Object *obj, PRBool purge)
+{
+ int rc;
+ CL5Entry entry;
+ void *iterator = NULL;
+ slapi_operation_parameters op = {0};
+ CL5DBFile *file;
+
+ PR_ASSERT (replGen && obj);
+
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+
+ /* construct the RUV */
+ if (purge)
+ rc = ruv_init_new (replGen, 0, NULL, &file->purgeRUV);
+ else
+ rc = ruv_init_new (replGen, 0, NULL, &file->maxRUV);
+ if (rc != RUV_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5ConstructRUV: "
+ "failed to initialize %s RUV for file %s; ruv error - %d\n",
+ purge? "purge" : "upper bound", file->name, rc);
+ return CL5_RUV_ERROR;
+ }
+
+ entry.op = &op;
+ rc = _cl5GetFirstEntry (obj, &entry, &iterator, NULL);
+ while (rc == CL5_SUCCESS)
+ {
+ if (purge)
+ rc = ruv_set_csns_keep_smallest(file->purgeRUV, op.csn);
+ else
+ rc = ruv_set_csns (file->maxRUV, op.csn, NULL);
+
+ cl5_operation_parameters_done (&op);
+ if (rc != RUV_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5ConstructRUV: "
+ "failed to updated %s RUV for file %s; ruv error - %d\n",
+ purge ? "purge" : "upper bound", file->name, rc);
+ rc = CL5_RUV_ERROR;
+ continue;
+ }
+
+ rc = _cl5GetNextEntry (&entry, iterator);
+ }
+
+ cl5_operation_parameters_done (&op);
+
+ if (iterator)
+ cl5DestroyIterator (iterator);
+
+ if (rc == CL5_NOTFOUND)
+ {
+ rc = CL5_SUCCESS;
+ }
+ else
+ {
+ if (purge)
+ ruv_destroy (&file->purgeRUV);
+ else
+ ruv_destroy (&file->maxRUV);
+ }
+
+ return rc;
+}
+
+static int _cl5UpdateRUV (Object *obj, CSN *csn, PRBool newReplica, PRBool purge)
+{
+ ReplicaId rid;
+ int rc = RUV_SUCCESS; /* initialize rc to avoid erroneous logs */
+ CL5DBFile *file;
+
+ PR_ASSERT (obj && csn);
+
+ file = (CL5DBFile*)object_get_data (obj);
+
+ /* if purge is TRUE, file->purgeRUV must be set;
+ if purge is FALSE, maxRUV must be set */
+ PR_ASSERT (file && ((purge && file->purgeRUV) || (!purge && file->maxRUV)));
+
+ /* update vector only if this replica is not yet part of RUV */
+ if (purge && newReplica)
+ {
+ rid = csn_get_replicaid(csn);
+ if (ruv_contains_replica (file->purgeRUV, rid))
+ return CL5_SUCCESS;
+ else
+ {
+ /* if the replica is not part of the purgeRUV yet, add it */
+ ruv_add_replica (file->purgeRUV, rid, multimaster_get_local_purl());
+ }
+ }
+ else
+ {
+ if (purge)
+ rc = ruv_set_csns(file->purgeRUV, csn, NULL);
+ else
+ rc = ruv_set_csns(file->maxRUV, csn, NULL);
+ }
+
+ if (rc != RUV_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5UpdatePurgeRUV: "
+ "failed to update %s RUV for file %s; ruv error - %d\n",
+ purge ? "purge" : "upper bound", file->name, rc);
+ return CL5_RUV_ERROR;
+ }
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5EnumConsumerRUV (const ruv_enum_data *element, void *arg)
+{
+ int rc;
+ RUV *ruv;
+ CSN *csn = NULL;
+
+ PR_ASSERT (element && element->csn && arg);
+
+ ruv = (RUV*)arg;
+
+ rc = ruv_get_largest_csn_for_replica(ruv, csn_get_replicaid (element->csn), &csn);
+ if (rc != RUV_SUCCESS || csn == NULL || csn_compare (element->csn, csn) < 0)
+ {
+ ruv_set_max_csn(ruv, element->csn, NULL);
+ }
+
+ if (csn)
+ csn_free (&csn);
+
+ return 0;
+}
+
+static int _cl5GetRUV2Purge2 (Object *fileObj, RUV **ruv)
+{
+ int rc = CL5_SUCCESS;
+ CL5DBFile *dbFile;
+ Object *rObj = NULL;
+ Replica *r = NULL;
+ Object *agmtObj = NULL;
+ Repl_Agmt *agmt;
+ Object *consRUVObj, *supRUVObj;
+ RUV *consRUV, *supRUV;
+ CSN *csn;
+
+ PR_ASSERT (fileObj && ruv);
+
+ dbFile = (CL5DBFile*)object_get_data (fileObj);
+ PR_ASSERT (dbFile);
+
+ rObj = replica_get_by_name (dbFile->replName);
+ PR_ASSERT (rObj);
+ r = (Replica*)object_get_data (rObj);
+ PR_ASSERT (r);
+
+ /* We start with this replica's RUV. See note in _cl5DoTrimming */
+ supRUVObj = replica_get_ruv (r);
+ PR_ASSERT (supRUVObj);
+
+ supRUV = (RUV*)object_get_data (supRUVObj);
+ PR_ASSERT (supRUV);
+
+ *ruv = ruv_dup (supRUV);
+
+ object_release (supRUVObj);
+
+ agmtObj = agmtlist_get_first_agreement_for_replica (r);
+ while (agmtObj)
+ {
+ agmt = (Repl_Agmt*)object_get_data (agmtObj);
+ PR_ASSERT (agmt);
+
+ consRUVObj = agmt_get_consumer_ruv (agmt);
+ if (consRUVObj)
+ {
+ consRUV = (RUV*)object_get_data (consRUVObj);
+ rc = ruv_enumerate_elements (consRUV, _cl5EnumConsumerRUV, *ruv);
+ if (rc != RUV_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5GetRUV2Purge2: "
+ "failed to construct ruv; ruv error - %d\n", rc);
+ rc = CL5_RUV_ERROR;
+ object_release (consRUVObj);
+ object_release (agmtObj);
+ break;
+ }
+
+ object_release (consRUVObj);
+ }
+
+ agmtObj = agmtlist_get_next_agreement_for_replica (r, agmtObj);
+ }
+
+ /* check if there is any data in the constructed ruv - otherwise get rid of it */
+ if (ruv_get_max_csn(*ruv, &csn) != RUV_SUCCESS || csn == NULL)
+ {
+ ruv_destroy (ruv);
+ }
+ else
+ {
+ csn_free (&csn);
+ }
+
+ if (rObj)
+ object_release (rObj);
+
+ if (rc != CL5_SUCCESS && ruv)
+ ruv_destroy (ruv);
+
+ return rc;
+}
+
+static int _cl5GetEntryCount (CL5DBFile *file)
+{
+ int rc;
+ char csnStr [CSN_STRSIZE];
+ DBT key={0}, data={0};
+ DB_BTREE_STAT *stats = NULL;
+
+ PR_ASSERT (file);
+
+ /* read entry count. if the entry is there - the file was successfully closed
+ last time it was used */
+ key.data = _cl5GetHelperEntryKey (ENTRY_COUNT_TIME, csnStr);
+ key.size = CSN_STRSIZE;
+
+ data.flags = DB_DBT_MALLOC;
+
+ rc = file->db->get(file->db, NULL/*txn*/, &key, &data, 0);
+ switch (rc)
+ {
+ case 0: file->entryCount = *(int*)data.data;
+ free (data.data);
+
+ /* delete the entry. the entry is re-added when file
+ is successfully closed */
+ file->db->del (file->db, NULL, &key, DEFAULT_DB_OP_FLAGS);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5GetEntryCount: %d changes for replica %s\n",
+ file->entryCount, file->replName);
+ return CL5_SUCCESS;
+
+ case DB_NOTFOUND: file->entryCount = 0;
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3300
+ rc = file->db->stat(file->db, (void*)&stats, 0);
+#else
+ rc = file->db->stat(file->db, (void*)&stats, malloc, 0);
+#endif
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5GetEntryCount: failed to get changelog statistics; "
+ "db error - %d %s\n", rc, db_strerror(rc));
+ return CL5_DB_ERROR;
+ }
+
+#ifdef DB30
+ file->entryCount = stats->bt_nrecs;
+#else /* DB31 */
+ file->entryCount = stats->bt_ndata;
+#endif
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5GetEntryCount: %d changes for replica %s\n",
+ file->entryCount, file->replName);
+
+ free (stats);
+ return CL5_SUCCESS;
+
+ default: slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5GetEntryCount: failed to get count entry; "
+ "db error - %d %s\n", rc, db_strerror(rc));
+ return CL5_DB_ERROR;
+ }
+}
+
+static int _cl5WriteEntryCount (CL5DBFile *file)
+{
+ int rc;
+ DBT key={0}, data={0};
+ char csnStr [CSN_STRSIZE];
+ DB_TXN *txnid = NULL;
+
+ key.data = _cl5GetHelperEntryKey (ENTRY_COUNT_TIME, csnStr);
+ key.size = CSN_STRSIZE;
+ data.data = (void*)&file->entryCount;
+ data.size = sizeof (file->entryCount);
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ rc = txn_begin(s_cl5Desc.dbEnv, NULL, &txnid, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteEntryCount: failed to begin transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ return CL5_DB_ERROR;
+ }
+#endif
+ rc = file->db->put(file->db, txnid, &key, &data, DEFAULT_DB_OP_FLAGS);
+ if (rc == 0)
+ {
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ rc = txn_commit (txnid, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteEntryCount: failed to commit transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ return CL5_DB_ERROR;
+ }
+#endif
+ return CL5_SUCCESS;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteEntryCount: "
+ "failed to write count entry for file %s; db error - %d %s\n",
+ file->name, rc, db_strerror(rc));
+ if (CL5_OS_ERR_IS_DISKFULL(rc))
+ {
+ cl5_set_diskfull();
+ return CL5_DB_ERROR;
+ }
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ rc = txn_abort (txnid);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteEntryCount: failed to abort transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ }
+#endif
+ return CL5_DB_ERROR;
+ }
+}
+
+static const char* _cl5OperationType2Str (int type)
+{
+ switch (type)
+ {
+ case SLAPI_OPERATION_ADD: return T_ADDCTSTR;
+ case SLAPI_OPERATION_MODIFY: return T_MODIFYCTSTR;
+ case SLAPI_OPERATION_MODRDN: return T_MODRDNCTSTR;
+ case SLAPI_OPERATION_DELETE: return T_DELETECTSTR;
+ default: return NULL;
+ }
+}
+
+static int _cl5Str2OperationType (const char *str)
+{
+ if (strcasecmp (str, T_ADDCTSTR) == 0)
+ return SLAPI_OPERATION_ADD;
+
+ if (strcasecmp (str, T_MODIFYCTSTR) == 0)
+ return SLAPI_OPERATION_MODIFY;
+
+ if (strcasecmp (str, T_MODRDNCTSTR) == 0)
+ return SLAPI_OPERATION_MODRDN;
+
+ if (strcasecmp (str, T_DELETECTSTR) == 0)
+ return SLAPI_OPERATION_DELETE;
+
+ return -1;
+}
+
+static int _cl5Operation2LDIF (const slapi_operation_parameters *op, const char *replGen,
+ char **ldifEntry, PRInt32 *lenLDIF)
+{
+ int len = 2;
+ lenstr *l = NULL;
+ const char *strType;
+ char *strDeleteOldRDN;
+ char *buff, *start;
+ LDAPMod **add_mods;
+ char *rawDN;
+ char strCSN[CSN_STRSIZE];
+
+ PR_ASSERT (op && replGen && ldifEntry && IsValidOperation (op));
+
+ strType = _cl5OperationType2Str (op->operation_type);
+ csn_as_string(op->csn,PR_FALSE,strCSN);
+
+ /* find length of the buffer */
+ len += LDIF_SIZE_NEEDED(strlen (T_CHANGETYPESTR), strlen (strType));
+ len += LDIF_SIZE_NEEDED(strlen (T_REPLGEN), strlen (replGen));
+ len += LDIF_SIZE_NEEDED(strlen (T_CSNSTR), strlen (strCSN));
+ len += LDIF_SIZE_NEEDED(strlen (T_UNIQUEIDSTR), strlen (op->target_address.uniqueid));
+
+ switch (op->operation_type)
+ {
+ case SLAPI_OPERATION_ADD: if (op->p.p_add.parentuniqueid)
+ len += LDIF_SIZE_NEEDED(strlen (T_PARENTIDSTR),
+ strlen (op->p.p_add.parentuniqueid));
+ slapi_entry2mods (op->p.p_add.target_entry, &rawDN, &add_mods);
+ len += LDIF_SIZE_NEEDED(strlen (T_DNSTR), strlen (rawDN));
+ l = make_changes_string(add_mods, NULL);
+ len += LDIF_SIZE_NEEDED(strlen (T_CHANGESTR), l->ls_len);
+ ldap_mods_free (add_mods, 1);
+ break;
+
+ case SLAPI_OPERATION_MODIFY: len += LDIF_SIZE_NEEDED(strlen (T_DNSTR), strlen (op->target_address.dn));
+ l = make_changes_string(op->p.p_modify.modify_mods, NULL);
+ len += LDIF_SIZE_NEEDED(strlen (T_CHANGESTR), l->ls_len);
+ break;
+
+ case SLAPI_OPERATION_MODRDN: len += LDIF_SIZE_NEEDED(strlen (T_DNSTR), strlen (op->target_address.dn));
+ len += LDIF_SIZE_NEEDED(strlen (T_NEWRDNSTR),
+ strlen (op->p.p_modrdn.modrdn_newrdn));
+ strDeleteOldRDN = (op->p.p_modrdn.modrdn_deloldrdn ? "true" : "false");
+ len += LDIF_SIZE_NEEDED(strlen (T_DRDNFLAGSTR),
+ strlen (strDeleteOldRDN));
+ if (op->p.p_modrdn.modrdn_newsuperior_address.dn)
+ len += LDIF_SIZE_NEEDED(strlen (T_NEWSUPERIORDNSTR),
+ strlen (op->p.p_modrdn.modrdn_newsuperior_address.dn));
+ if (op->p.p_modrdn.modrdn_newsuperior_address.uniqueid)
+ len += LDIF_SIZE_NEEDED(strlen (T_NEWSUPERIORIDSTR),
+ strlen (op->p.p_modrdn.modrdn_newsuperior_address.uniqueid));
+ l = make_changes_string(op->p.p_modrdn.modrdn_mods, NULL);
+ len += LDIF_SIZE_NEEDED(strlen (T_CHANGESTR), l->ls_len);
+ break;
+
+ case SLAPI_OPERATION_DELETE: len += LDIF_SIZE_NEEDED(strlen (T_DNSTR), strlen (op->target_address.dn));
+ break;
+
+ default: slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5Operation2LDIF: invalid operation type - %d\n", op->operation_type);
+
+ return CL5_BAD_FORMAT;
+ }
+
+ /* allocate buffer */
+ buff = (char*)slapi_ch_malloc (len);
+ start = buff;
+ if (buff == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5Operation2LDIF: memory allocation failed\n");
+ return CL5_MEMORY_ERROR;
+ }
+
+ /* fill buffer */
+ ldif_put_type_and_value(&buff, T_CHANGETYPESTR, (char*)strType, strlen (strType));
+ ldif_put_type_and_value(&buff, T_REPLGEN, (char*)replGen, strlen (replGen));
+ ldif_put_type_and_value(&buff, T_CSNSTR, (char*)strCSN, strlen (strCSN));
+ ldif_put_type_and_value(&buff, T_UNIQUEIDSTR, op->target_address.uniqueid,
+ strlen (op->target_address.uniqueid));
+
+ switch (op->operation_type)
+ {
+ case SLAPI_OPERATION_ADD: if (op->p.p_add.parentuniqueid)
+ ldif_put_type_and_value(&buff, T_PARENTIDSTR,
+ op->p.p_add.parentuniqueid, strlen (op->p.p_add.parentuniqueid));
+ ldif_put_type_and_value(&buff, T_DNSTR, rawDN, strlen (rawDN));
+ ldif_put_type_and_value(&buff, T_CHANGESTR, l->ls_buf, l->ls_len);
+ slapi_ch_free ((void**)&rawDN);
+ break;
+
+ case SLAPI_OPERATION_MODIFY: ldif_put_type_and_value(&buff, T_DNSTR, op->target_address.dn,
+ strlen (op->target_address.dn));
+ ldif_put_type_and_value(&buff, T_CHANGESTR, l->ls_buf, l->ls_len);
+ break;
+
+ case SLAPI_OPERATION_MODRDN: ldif_put_type_and_value(&buff, T_DNSTR, op->target_address.dn,
+ strlen (op->target_address.dn));
+ ldif_put_type_and_value(&buff, T_NEWRDNSTR, op->p.p_modrdn.modrdn_newrdn,
+ strlen (op->p.p_modrdn.modrdn_newrdn));
+ ldif_put_type_and_value(&buff, T_DRDNFLAGSTR, strDeleteOldRDN,
+ strlen (strDeleteOldRDN));
+ if (op->p.p_modrdn.modrdn_newsuperior_address.dn)
+ ldif_put_type_and_value(&buff, T_NEWSUPERIORDNSTR,
+ op->p.p_modrdn.modrdn_newsuperior_address.dn,
+ strlen (op->p.p_modrdn.modrdn_newsuperior_address.dn));
+ if (op->p.p_modrdn.modrdn_newsuperior_address.uniqueid)
+ ldif_put_type_and_value(&buff, T_NEWSUPERIORIDSTR,
+ op->p.p_modrdn.modrdn_newsuperior_address.uniqueid,
+ strlen (op->p.p_modrdn.modrdn_newsuperior_address.uniqueid));
+ ldif_put_type_and_value(&buff, T_CHANGESTR, l->ls_buf, l->ls_len);
+ break;
+
+ case SLAPI_OPERATION_DELETE: ldif_put_type_and_value(&buff, T_DNSTR, op->target_address.dn,
+ strlen (op->target_address.dn));
+ break;
+ }
+
+ *buff = '\n';
+ buff ++;
+ *buff = '\0';
+
+ *ldifEntry = start;
+ *lenLDIF = buff - start;
+
+ if (l)
+ lenstr_free(&l);
+
+ return CL5_SUCCESS;
+}
+
+static int
+_cl5LDIF2Operation (char *ldifEntry, slapi_operation_parameters *op, char **replGen)
+{
+ int rc;
+ int vlen;
+ char *next, *line;
+ char *type, *value;
+ Slapi_Mods *mods;
+ char *rawDN;
+
+ PR_ASSERT (op && ldifEntry && replGen);
+
+ memset (op, 0, sizeof (*op));
+
+ next = ldifEntry;
+ while ((line = ldif_getline(&next)) != NULL)
+ {
+ char *errmsg = NULL;
+
+ if ( *line == '\n' || *line == '\0' )
+ {
+ break;
+ }
+
+ /* this call modifies ldifEntry */
+ rc = ldif_parse_line(line, &type, &value, &vlen, &errmsg);
+ if (rc != 0)
+ {
+ if ( errmsg != NULL ) {
+ slapi_log_error(SLAPI_LOG_PARSE, repl_plugin_name_cl, "%s", errmsg);
+ slapi_ch_free( (void**)&errmsg );
+ }
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5LDIF2Operation: warning - failed to parse ldif line\n");
+ continue;
+ }
+
+ if (strcasecmp (type, T_CHANGETYPESTR) == 0)
+ {
+ op->operation_type = _cl5Str2OperationType (value);
+ }
+ else if (strcasecmp (type, T_REPLGEN) == 0)
+ {
+ *replGen = slapi_ch_strdup (value);
+ }
+ else if (strcasecmp (type, T_CSNSTR) == 0)
+ {
+ op->csn = csn_new_by_string(value);
+ }
+ else if (strcasecmp (type, T_UNIQUEIDSTR) == 0)
+ {
+ op->target_address.uniqueid = slapi_ch_strdup (value);
+ }
+ else if (strcasecmp (type, T_DNSTR) == 0)
+ {
+ PR_ASSERT (op->operation_type);
+
+ if (op->operation_type == SLAPI_OPERATION_ADD)
+ {
+ rawDN = slapi_ch_strdup (value);
+ op->target_address.dn = slapi_ch_strdup(rawDN);
+ }
+ else
+ op->target_address.dn = slapi_ch_strdup (value);
+ }
+ else if (strcasecmp (type, T_PARENTIDSTR) == 0)
+ {
+ op->p.p_add.parentuniqueid = slapi_ch_strdup (value);
+ }
+ else if (strcasecmp (type, T_NEWRDNSTR) == 0)
+ {
+ op->p.p_modrdn.modrdn_newrdn = slapi_ch_strdup (value);
+ }
+ else if (strcasecmp (type, T_DRDNFLAGSTR) == 0)
+ {
+ op->p.p_modrdn.modrdn_deloldrdn = (strcasecmp (value, "true") ? PR_FALSE : PR_TRUE);
+ }
+ else if (strcasecmp (type, T_NEWSUPERIORDNSTR) == 0)
+ {
+ op->p.p_modrdn.modrdn_newsuperior_address.dn = slapi_ch_strdup (value);
+ }
+ else if (strcasecmp (type, T_NEWSUPERIORIDSTR) == 0)
+ {
+ op->p.p_modrdn.modrdn_newsuperior_address.uniqueid = slapi_ch_strdup (value);
+ }
+ else if (strcasecmp (type, T_CHANGESTR) == 0)
+ {
+ PR_ASSERT (op->operation_type);
+
+ switch (op->operation_type)
+ {
+ case SLAPI_OPERATION_ADD: mods = parse_changes_string(value);
+ slapi_mods2entry (&(op->p.p_add.target_entry), rawDN,
+ slapi_mods_get_ldapmods_byref(mods));
+ slapi_ch_free ((void**)&rawDN);
+ slapi_mods_free (&mods);
+ break;
+
+ case SLAPI_OPERATION_MODIFY: mods = parse_changes_string(value);
+ PR_ASSERT (mods);
+ op->p.p_modify.modify_mods = slapi_mods_get_ldapmods_passout (mods);
+ slapi_mods_free (&mods);
+ break;
+
+ case SLAPI_OPERATION_MODRDN: mods = parse_changes_string(value);
+ PR_ASSERT (mods);
+ op->p.p_modrdn.modrdn_mods = slapi_mods_get_ldapmods_passout (mods);
+ slapi_mods_free (&mods);
+ break;
+
+ default: slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5LDIF2Operation: invalid operation type - %d\n",
+ op->operation_type);
+ return CL5_BAD_FORMAT;
+ }
+ }
+ }
+
+ if (IsValidOperation (op))
+ return CL5_SUCCESS;
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5LDIF2Operation: invalid data format\n");
+ return CL5_BAD_FORMAT;
+}
+
+static int _cl5WriteOperation(const char *replName, const char *replGen,
+ const slapi_operation_parameters *op, PRBool local)
+{
+ int rc;
+ int cnt;
+ DBT key={0};
+ DBT * data=NULL;
+ char csnStr [CSN_STRSIZE];
+ PRIntervalTime interval;
+ CL5Entry entry;
+ CL5DBFile *file = NULL;
+ Object *file_obj = NULL;
+ DB_TXN *txnid = NULL;
+
+ rc = _cl5GetDBFileByReplicaName (replName, replGen, &file_obj);
+ if (rc == CL5_NOTFOUND)
+ {
+ rc = _cl5DBOpenFileByReplicaName (replName, replGen, &file_obj,
+ PR_TRUE /* check for duplicates */);
+ if (rc != CL5_SUCCESS)
+ {
+ return rc;
+ }
+ }
+ else if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "_cl5WriteOperation: failed to get db file for target dn (%s)",
+ op->target_address.dn);
+ return CL5_OBJSET_ERROR;
+ }
+
+ /* assign entry time - used for trimming */
+ entry.time = current_time ();
+ entry.op = (slapi_operation_parameters *)op;
+
+ /* construct the key */
+ key.data = csn_as_string(op->csn, PR_FALSE, csnStr);
+ key.size = CSN_STRSIZE;
+
+ /* construct the data */
+ data = (DBT *) slapi_ch_calloc(1, sizeof(DBT));
+ rc = _cl5Entry2DBData (&entry, (char**)&data->data, &data->size);
+ if (rc != CL5_SUCCESS)
+ {
+ char s[CSN_STRSIZE];
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5WriteOperation: failed to convert entry with csn (%s) "
+ "to db format\n", csn_as_string(op->csn,PR_FALSE,s));
+ goto done;
+ }
+
+ file = (CL5DBFile*)object_get_data (file_obj);
+ PR_ASSERT (file);
+
+ /* if this is part of ldif2cl - just write the entry without transaction */
+ if (s_cl5Desc.dbOpenMode == CL5_OPEN_LDIF2CL)
+ {
+ rc = file->db->put(file->db, NULL, &key, data, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteOperation: failed to write entry; db error - %d %s\n",
+ rc, db_strerror(rc));
+ if (CL5_OS_ERR_IS_DISKFULL(rc))
+ {
+ cl5_set_diskfull();
+ }
+ rc = CL5_DB_ERROR;
+ }
+ goto done;
+ }
+
+ /* write the entry */
+ rc = EAGAIN;
+ cnt = 0;
+
+ while ((rc == EAGAIN || rc == DB_LOCK_DEADLOCK) && cnt < MAX_TRIALS)
+ {
+ if (cnt != 0)
+ {
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ /* abort previous transaction */
+ rc = txn_abort (txnid);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteOperation: failed to abort transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+#endif
+ /* back off */
+ interval = PR_MillisecondsToInterval(slapi_rand() % 100);
+ DS_Sleep(interval);
+ }
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ /* begin transaction */
+ rc = txn_begin(s_cl5Desc.dbEnv, NULL /*pid*/, &txnid, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteOperation: failed to start transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+#endif
+
+ if ( file->sema )
+ {
+ PR_WaitSemaphore(file->sema);
+ }
+ rc = file->db->put(file->db, txnid, &key, data, DEFAULT_DB_OP_FLAGS);
+ if ( file->sema )
+ {
+ PR_PostSemaphore(file->sema);
+ }
+ if (CL5_OS_ERR_IS_DISKFULL(rc))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteOperation: changelog (%s) DISK FULL; db error - %d %s\n",
+ s_cl5Desc.dbDir, rc, db_strerror(rc));
+ cl5_set_diskfull();
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+ if (cnt != 0)
+ {
+ if (rc == 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "_cl5WriteOperation: retry (%d) the transaction (csn=%s) succeeded\n", cnt, (char*)key.data);
+ }
+ else if ((cnt + 1) >= MAX_TRIALS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "_cl5WriteOperation: retry (%d) the transaction (csn=%s) failed (rc=%d)\n", cnt, (char*)key.data, rc);
+ }
+ }
+ cnt ++;
+ }
+
+ if (rc == 0) /* we successfully added entry */
+ {
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ rc = txn_commit (txnid, 0);
+#endif
+ }
+ else
+ {
+ char s[CSN_STRSIZE];
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteOperation: failed to write entry with csn (%s); "
+ "db error - %d %s\n", csn_as_string(op->csn,PR_FALSE,s),
+ rc, db_strerror(rc));
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ rc = txn_abort (txnid);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5WriteOperation: failed to abort transaction; db error - %d %s\n",
+ rc, db_strerror(rc));
+ }
+#endif
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+
+ /* update entry count - we assume that all entries are new */
+ PR_AtomicIncrement (&file->entryCount);
+
+ /* update purge vector if we have not seen any changes from this replica before */
+ _cl5UpdateRUV (file_obj, op->csn, PR_TRUE, PR_TRUE);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "cl5WriteOperation: successfully written entry with csn (%s)\n", csnStr);
+ rc = CL5_SUCCESS;
+done:
+ if (data->data)
+ slapi_ch_free ((void**)&data->data);
+ slapi_ch_free((void**) &data);
+
+ if (file_obj)
+ object_release (file_obj);
+
+ return rc;
+}
+
+static int _cl5GetFirstEntry (Object *obj, CL5Entry *entry, void **iterator, DB_TXN *txnid)
+{
+ int rc;
+ DBC *cursor = NULL;
+ DBT key={0}, data={0};
+ CL5Iterator *it;
+ CL5DBFile *file;
+
+ PR_ASSERT (obj && entry && iterator);
+
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+ /* create cursor */
+ rc = file->db->cursor(file->db, txnid, &cursor, 0);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5GetFirstEntry: failed to create cursor; db error - %d %s\n", rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+
+ key.flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ while ((rc = cursor->c_get(cursor, &key, &data, DB_NEXT)) == 0)
+ {
+ /* skip service entries */
+ if (cl5HelperEntry ((char*)key.data, NULL))
+ {
+ free (key.data);
+ free (data.data);
+ continue;
+ }
+
+ /* format entry */
+ free (key.data);
+ rc = cl5DBData2Entry (data.data, data.size, entry);
+ free (data.data);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5GetFirstOperation: failed to format entry\n", rc);
+ goto done;
+ }
+
+ it = (CL5Iterator*)slapi_ch_malloc (sizeof (CL5Iterator));
+ it->cursor = cursor;
+ object_acquire (obj);
+ it->file = obj;
+ *(CL5Iterator**)iterator = it;
+
+ return CL5_SUCCESS;
+ }
+
+ /* walked of the end of the file */
+ if (rc == DB_NOTFOUND)
+ {
+ rc = CL5_NOTFOUND;
+ goto done;
+ }
+
+ /* db error occured while iterating */
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5GetFirstEntry: failed to get entry; db error - %d %s\n", rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+
+ /* successfully retrieved next entry but it was out of range */
+ if (rc == CL5_SUCCESS)
+ {
+ free (key.data);
+ free (data.data);
+ rc = CL5_NOTFOUND;
+ goto done;
+ }
+
+done:;
+ /* error occured */
+ /* We didn't success in assigning this cursor to the iterator,
+ * so we need to free the cursor here */
+ if (cursor)
+ cursor->c_close(cursor);
+
+ return rc;
+}
+
+static int _cl5GetNextEntry (CL5Entry *entry, void *iterator)
+{
+ int rc;
+ CL5Iterator *it;
+ DBT key={0}, data={0};
+
+ PR_ASSERT (entry && iterator);
+
+ it = (CL5Iterator*) iterator;
+
+ key.flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ while ((rc = it->cursor->c_get(it->cursor, &key, &data, DB_NEXT)) == 0)
+ {
+ if (cl5HelperEntry ((char*)key.data, NULL))
+ {
+ free (key.data);
+ free (data.data);
+ continue;
+ }
+
+ free (key.data);
+ /* format entry */
+ rc = cl5DBData2Entry (data.data, data.size, entry);
+ free (data.data);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5GetNextEntry: failed to format entry\n", rc);
+ }
+
+ return rc;
+ }
+
+ /* walked of the end of the file or entry is out of range */
+ if (rc == 0 || rc == DB_NOTFOUND)
+ {
+ return CL5_NOTFOUND;
+ }
+
+ /* cursor operation failed */
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5GetNextEntry: failed to get entry; db error - %d %s\n", rc, db_strerror(rc));
+
+ return CL5_DB_ERROR;
+ }
+
+ return rc;
+}
+
+static int _cl5CurrentDeleteEntry (void *iterator)
+{
+ int rc;
+ CL5Iterator *it;
+ CL5DBFile *file;
+
+ PR_ASSERT (iterator);
+
+ it = (CL5Iterator*)iterator;
+
+ rc = it->cursor->c_del (it->cursor, 0);
+
+ if (rc == 0) {
+ /* decrement entry count */
+ file = (CL5DBFile*)object_get_data (it->file);
+ PR_AtomicDecrement (&file->entryCount);
+ return CL5_SUCCESS;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5CurrentDeleteEntry failed, err=%d %s\n",
+ rc, db_strerror(rc));
+ /* We don't free(close) the cursor here, as the caller will free it by a call to cl5DestroyIterator */
+ /* Freeing it here is a potential bug, as the cursor can't be referenced later once freed */
+ return CL5_DB_ERROR;
+ }
+}
+
+static PRBool _cl5IsValidIterator (const CL5Iterator *iterator)
+{
+ return (iterator && iterator->cursor && iterator->file);
+}
+
+static int _cl5GetOperation (Object *replica, slapi_operation_parameters *op)
+{
+ int rc;
+ DBT key={0}, data={0};
+ CL5DBFile *file;
+ CL5Entry entry;
+ Object *obj = NULL;
+ char csnStr[CSN_STRSIZE];
+
+ rc = _cl5GetDBFile (replica, &obj);
+ if (rc != CL5_SUCCESS)
+ {
+ return rc;
+ }
+
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+
+ /* construct the key */
+ key.data = csn_as_string(op->csn, PR_FALSE, csnStr);
+ key.size = CSN_STRSIZE;
+
+ data.flags = DB_DBT_MALLOC;
+
+ rc = file->db->get(file->db, NULL/*txn*/, &key, &data, 0);
+ switch (rc)
+ {
+ case 0: entry.op = op;
+ /* Callers of this function should cl5_operation_parameters_done(op) */
+ rc = cl5DBData2Entry (data.data, data.size, &entry);
+ if (rc == CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "_cl5GetOperation: successfully retrieved operation with csn (%s)\n",
+ csnStr);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5GetOperation: failed to convert db data to operation;"
+ " csn - %s\n", csnStr);
+ }
+ goto done;
+
+ case DB_NOTFOUND: slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5GetOperation: operation for csn (%s) is not found in db that should contain dn (%s)\n",
+ csnStr, op->target_address.dn);
+ rc = CL5_NOTFOUND;
+ goto done;
+
+ default: slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5GetOperation: failed to get entry for csn (%s); "
+ "db error - %d %s\n", csnStr, rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+
+done:;
+ if (obj)
+ object_release (obj);
+
+ if (data.data)
+ free (data.data);
+
+ return rc;
+}
+
+PRBool cl5HelperEntry (const char *csnstr, CSN *csnp)
+{
+ CSN *csn;
+ time_t csnTime;
+ PRBool retval = PR_FALSE;
+
+ if (csnp)
+ {
+ csn = csnp;
+ }
+ else
+ {
+ csn= csn_new_by_string(csnstr);
+ }
+ if (csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "cl5HelperEntry: failed to get csn time; csn error\n");
+ return PR_FALSE;
+ }
+ csnTime= csn_get_time(csn);
+
+ if (csnTime == ENTRY_COUNT_TIME || csnTime == PURGE_RUV_TIME)
+ {
+ retval = PR_TRUE;
+ }
+
+ if (NULL == csnp)
+ csn_free(&csn);
+ return retval;
+}
+
+/* Replay iteration helper functions */
+static PRBool _cl5ValidReplayIterator (const CL5ReplayIterator *iterator)
+{
+ if (iterator == NULL ||
+ iterator->consumerRuv == NULL || iterator->supplierRuvObj == NULL ||
+ iterator->fileObj == NULL)
+ return PR_FALSE;
+
+ return PR_TRUE;
+}
+
+/* Algorithm: ONREPL!!!
+ */
+struct replica_hash_entry
+{
+ ReplicaId rid; /* replica id */
+ PRBool sendChanges; /* indicates whether changes should be sent for this replica */
+};
+
+
+static int _cl5PositionCursorForReplay (ReplicaId consumerRID, const RUV *consumerRuv,
+ Object *replica, Object *fileObj, CL5ReplayIterator **iterator)
+{
+ CLC_Buffer *clcache = NULL;
+ CL5DBFile *file;
+ int i;
+ CSN **csns = NULL;
+ CSN *startCSN = NULL;
+ char csnStr [CSN_STRSIZE];
+ int rc = CL5_SUCCESS;
+ Object *supplierRuvObj = NULL;
+ RUV *supplierRuv = NULL;
+ ReplicaId supplierRID;
+ PRBool newReplica;
+ PRBool haveChanges = PR_FALSE;
+ char *agmt_name;
+ ReplicaId rid;
+
+ PR_ASSERT (consumerRuv && replica && fileObj && iterator);
+ csnStr[0] = '\0';
+
+ file = (CL5DBFile*)object_get_data (fileObj);
+ supplierRID = replica_get_rid((Replica*)object_get_data(replica));
+
+ /* get supplier's RUV */
+ supplierRuvObj = replica_get_ruv((Replica*)object_get_data(replica));
+ PR_ASSERT (supplierRuvObj);
+ supplierRuv = (RUV*)object_get_data (supplierRuvObj);
+ PR_ASSERT (supplierRuv);
+
+ agmt_name = get_thread_private_agmtname();
+ slapi_log_error(SLAPI_LOG_REPL, NULL, "_cl5PositionCursorForReplay (%s): Consumer RUV:\n", agmt_name);
+ ruv_dump (consumerRuv, agmt_name, NULL);
+ slapi_log_error(SLAPI_LOG_REPL, NULL, "_cl5PositionCursorForReplay (%s): Supplier RUV:\n", agmt_name);
+ ruv_dump (supplierRuv, agmt_name, NULL);
+
+ /*
+ * get the sorted list of SupplierMinCSN (if no ConsumerMaxCSN)
+ * and ConsumerMaxCSN for those RIDs where consumer is not
+ * up-to-date.
+ */
+ csns = cl5BuildCSNList (consumerRuv, supplierRuv);
+ if (csns == NULL)
+ {
+ rc = CL5_NOTFOUND;
+ goto done;
+ }
+
+ /* iterate over elements of consumer's (and/or supplier's) ruv */
+ for (i = 0; csns[i]; i++)
+ {
+ CSN *consumerMaxCSN = NULL;
+
+ rid = csn_get_replicaid(csns[i]);
+
+ /*
+ * Skip CSN that is originated from the consumer.
+ * If RID==65535, the CSN is originated from a
+ * legacy consumer. In this case the supplier
+ * and the consumer may have the same RID.
+ */
+ if (rid == consumerRID && rid != MAX_REPLICA_ID)
+ continue;
+
+ startCSN = csns[i];
+ csn_as_string(startCSN, PR_FALSE, csnStr);
+
+ rc = clcache_get_buffer ( &clcache, file->db, consumerRID, consumerRuv, supplierRuv );
+ if ( rc != 0 ) goto done;
+
+ /* This is the first loading of this iteration. For replicas
+ * already known to the consumer, we exclude the last entry
+ * sent to the consumer by using DB_NEXT. However, for
+ * replicas new to the consumer, we include the first change
+ * ever generated by that replica.
+ */
+ newReplica = ruv_get_largest_csn_for_replica (consumerRuv, rid, &consumerMaxCSN);
+ csn_free(&consumerMaxCSN);
+ rc = clcache_load_buffer (clcache, startCSN, (newReplica ? DB_SET : DB_NEXT));
+
+ /* there is a special case which can occur just after migration - in this case,
+ the consumer RUV will contain the last state of the supplier before migration,
+ but the supplier will have an empty changelog, or the supplier changelog will
+ not contain any entries within the consumer min and max CSN - also, since
+ the purge RUV contains no CSNs, the changelog has never been purged
+ ASSUMPTIONS - it is assumed that the supplier had no pending changes to send
+ to any consumers; that is, we can assume that no changes were lost due to
+ either changelog purging or database reload - bug# 603061 - richm@netscape.com
+ */
+ if (rc == 0 || (rc == DB_NOTFOUND && !ruv_has_csns(file->purgeRUV)))
+ {
+ haveChanges = PR_TRUE;
+ rc = CL5_SUCCESS;
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "%s: CSN %s found, position set for replay\n", agmt_name, csnStr);
+ break;
+ }
+ else if (rc == DB_NOTFOUND) /* entry not found */
+ {
+ /* check whether this csn should be present */
+ rc = _cl5CheckMissingCSN (startCSN, supplierRuv, file);
+ if (rc == CL5_MISSING_DATA) /* we should have had the change but we don't */
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "%s: CSN %s not found, seems to be missing\n", agmt_name, csnStr);
+ break;
+ }
+ else /* we are not as up to date or we purged */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "%s: CSN %s not found, we aren't as up to date, or we purged\n",
+ agmt_name, csnStr);
+ continue;
+ }
+ }
+ else
+ {
+
+ /* db error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "%s: Failed to retrieve change with CSN %s; db error - %d %s\n",
+ agmt_name, csnStr, rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ break;
+ }
+
+ } /* end for */
+
+ /* setup the iterator */
+ if (haveChanges)
+ {
+ *iterator = (CL5ReplayIterator*) slapi_ch_calloc (1, sizeof (CL5ReplayIterator));
+
+ if (*iterator == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "%s: _cl5PositionCursorForReplay: failed to allocate iterator\n", agmt_name);
+ rc = CL5_MEMORY_ERROR;
+ goto done;
+ }
+
+ /* ONREPL - should we make a copy of both RUVs here ?*/
+ (*iterator)->fileObj = fileObj;
+ (*iterator)->clcache = clcache; clcache = NULL;
+ (*iterator)->consumerRID = consumerRID;
+ (*iterator)->consumerRuv = consumerRuv;
+ (*iterator)->supplierRuvObj = supplierRuvObj;
+ }
+ else if (rc == CL5_SUCCESS)
+ {
+ /* we have no changes to send */
+ rc = CL5_NOTFOUND;
+ }
+
+done:
+ if ( clcache )
+ clcache_return_buffer ( &clcache );
+
+ if (csns)
+ cl5DestroyCSNList (&csns);
+
+ if (rc != CL5_SUCCESS)
+ {
+ if (supplierRuvObj)
+ object_release (supplierRuvObj);
+ }
+
+ return rc;
+}
+
+struct ruv_it
+{
+ CSN **csns; /* csn list */
+ int alloc; /* allocated size */
+ int pos; /* position in the list */
+};
+
+static int ruv_consumer_iterator (const ruv_enum_data *enum_data, void *arg)
+{
+ struct ruv_it *data = (struct ruv_it*)arg;
+
+ PR_ASSERT (data);
+
+ /* check if we have space for one more element */
+ if (data->pos >= data->alloc - 2)
+ {
+ data->alloc += 4;
+ data->csns = (CSN**) slapi_ch_realloc ((void*)data->csns, data->alloc * sizeof (CSN*));
+ }
+
+ data->csns [data->pos] = csn_dup (enum_data->csn);
+ data->pos ++;
+
+ return 0;
+}
+
+
+static int ruv_supplier_iterator (const ruv_enum_data *enum_data, void *arg)
+{
+ int i;
+ PRBool found = PR_FALSE;
+ ReplicaId rid;
+ struct ruv_it *data = (struct ruv_it*)arg;
+
+ PR_ASSERT (data);
+
+ rid = csn_get_replicaid (enum_data->min_csn);
+ /* check if the replica that generated the csn is already in the list */
+ for (i = 0; i < data->pos; i++)
+ {
+ if (rid == csn_get_replicaid (data->csns[i]))
+ {
+ found = PR_TRUE;
+
+ /* remove datacsn[i] if it is greater or equal to the supplier's maxcsn */
+ if ( csn_compare ( data->csns[i], enum_data->csn ) >= 0 )
+ {
+ int j;
+
+ csn_free ( & data->csns[i] );
+ for (j = i+1; j < data->pos; j++)
+ {
+ data->csns [j-1] = data->csns [j];
+ }
+ data->pos --;
+ }
+ break;
+ }
+ }
+
+ if (!found)
+ {
+ /* check if we have space for one more element */
+ if (data->pos >= data->alloc - 2)
+ {
+ data->alloc += 4;
+ data->csns = (CSN**)slapi_ch_realloc ((void*)data->csns,
+ data->alloc * sizeof (CSN*));
+ }
+
+ data->csns [data->pos] = csn_dup (enum_data->min_csn);
+ data->pos ++;
+ }
+ return 0;
+}
+
+
+
+static int
+my_csn_compare(const void *arg1, const void *arg2)
+{
+ return(csn_compare(*((CSN **)arg1), *((CSN **)arg2)));
+}
+
+
+
+/* builds CSN ordered list of all csns in the RUV */
+CSN** cl5BuildCSNList (const RUV *consRuv, const RUV *supRuv)
+{
+ struct ruv_it data;
+ int count, rc;
+ CSN **csns;
+
+ PR_ASSERT (consRuv);
+
+ count = ruv_replica_count (consRuv);
+ csns = (CSN**)slapi_ch_calloc (count + 1, sizeof (CSN*));
+
+ data.csns = csns;
+ data.alloc = count + 1;
+ data.pos = 0;
+
+ /* add consumer elements to the list */
+ rc = ruv_enumerate_elements (consRuv, ruv_consumer_iterator, &data);
+ if (rc == 0 && supRuv)
+ {
+ /* add supplier elements to the list */
+ rc = ruv_enumerate_elements (supRuv, ruv_supplier_iterator, &data);
+ }
+
+ /* we have no csns */
+ if (data.csns[0] == NULL)
+ {
+ /* csns might have been realloced in ruv_supplier_iterator() */
+ slapi_ch_free ((void**)&data.csns);
+ csns = NULL;
+ }
+ else
+ {
+ csns = data.csns;
+ data.csns [data.pos] = NULL;
+ if (rc == 0)
+ {
+ qsort (csns, data.pos, sizeof (CSN*), my_csn_compare);
+ }
+ else
+ {
+ cl5DestroyCSNList (&csns);
+ }
+ }
+
+ return csns;
+}
+
+void cl5DestroyCSNList (CSN*** csns)
+{
+ if (csns && *csns)
+ {
+ int i;
+
+ for (i = 0; (*csns)[i]; i++)
+ {
+ csn_free (&(*csns)[i]);
+ }
+
+ slapi_ch_free ((void**)csns);
+ }
+}
+
+/* A csn should be in the changelog if it is larger than purge vector csn for the same
+ replica and is smaller than the csn in supplier's ruv for the same replica.
+ The functions returns
+ CL5_PURGED if data was purged from the changelog or was never logged
+ because it was loaded as part of replica initialization
+ CL5_MISSING if the data erouneously missing
+ CL5_SUCCESS if that has not and should not been seen by the server
+ */
+static int _cl5CheckMissingCSN (const CSN *csn, const RUV *supplierRuv, CL5DBFile *file)
+{
+ ReplicaId rid;
+ CSN *supplierCsn = NULL;
+ CSN *purgeCsn = NULL;
+ int rc = CL5_SUCCESS;
+ char csnStr [CSN_STRSIZE];
+
+ PR_ASSERT (csn && supplierRuv && file);
+
+ rid = csn_get_replicaid (csn);
+ ruv_get_largest_csn_for_replica (supplierRuv, rid, &supplierCsn);
+ if (supplierCsn == NULL)
+ {
+ /* we have not seen any changes from this replica so it is
+ ok not to have this csn */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5CheckMissingCSN: "
+ "can't locate %s csn: we have not seen any changes for replica %d\n",
+ csn_as_string (csn, PR_FALSE, csnStr), rid);
+ return CL5_SUCCESS;
+ }
+
+ ruv_get_largest_csn_for_replica (file->purgeRUV, rid, &purgeCsn);
+ if (purgeCsn == NULL)
+ {
+ /* changelog never contained any changes for this replica */
+ if (csn_compare (csn, supplierCsn) <= 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5CheckMissingCSN: "
+ "the change with %s csn was never logged because it was imported "
+ "during replica initialization\n", csn_as_string (csn, PR_FALSE, csnStr));
+ rc = CL5_PURGED_DATA; /* XXXggood is that the correct return value? */
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5CheckMissingCSN: "
+ "change with %s csn has not yet been seen by this server; "
+ " last csn seen from that replica is %s\n",
+ csn_as_string (csn, PR_FALSE, csnStr),
+ csn_as_string (supplierCsn, PR_FALSE, csnStr));
+ rc = CL5_SUCCESS;
+ }
+ }
+ else /* we have both purge and supplier csn */
+ {
+ if (csn_compare (csn, purgeCsn) < 0) /* the csn is below the purge point */
+ {
+ rc = CL5_PURGED_DATA;
+ }
+ else
+ {
+ if (csn_compare (csn, supplierCsn) <= 0) /* we should have the data but we don't */
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5CheckMissingCSN: "
+ "change with %s csn has been purged by this server; "
+ "the current purge point for that replica is %s\n",
+ csn_as_string (csn, PR_FALSE, csnStr),
+ csn_as_string (purgeCsn, PR_FALSE, csnStr));
+ rc = CL5_MISSING_DATA;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5CheckMissingCSN: "
+ "change with %s csn has not yet been seen by this server; "
+ " last csn seen from that replica is %s\n",
+ csn_as_string (csn, PR_FALSE, csnStr),
+ csn_as_string (supplierCsn, PR_FALSE, csnStr));
+ rc = CL5_SUCCESS;
+ }
+ }
+ }
+
+ if (supplierCsn)
+ csn_free (&supplierCsn);
+
+ if (purgeCsn)
+ csn_free (&purgeCsn);
+
+ return rc;
+}
+
+/* Helper functions that work with individual changelog files */
+
+/* file name format : <replica name>_<replica generation>db{2,3} */
+static PRBool _cl5FileName2Replica (const char *file_name, Object **replica)
+{
+ Replica *r;
+ char *repl_name, *file_gen, *repl_gen;
+ int len;
+
+ PR_ASSERT (file_name && replica);
+
+ *replica = NULL;
+
+ /* this is database file */
+ if (_cl5FileEndsWith (file_name, DB_EXTENSION) ||
+ _cl5FileEndsWith (file_name, DB_EXTENSION_DB3) )
+ {
+ repl_name = slapi_ch_strdup (file_name);
+ file_gen = strstr(repl_name, FILE_SEP);
+ if (file_gen)
+ {
+ int extlen = strlen(DB_EXTENSION);
+ *file_gen = '\0';
+ file_gen += strlen (FILE_SEP);
+ len = strlen (file_gen);
+ if (len <= extlen + 1)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5FileName2Replica "
+ "invalid file name (%s)\n", file_name);
+ }
+ else
+ {
+ /* get rid of the file extension */
+ file_gen [len - extlen - 1] = '\0';
+ *replica = replica_get_by_name (repl_name);
+ if (*replica)
+ {
+ /* check that generation matches the one in replica object */
+ r = (Replica*)object_get_data (*replica);
+ repl_gen = replica_get_generation (r);
+ PR_ASSERT (repl_gen);
+ if (strcmp (file_gen, repl_gen) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5FileName2Replica "
+ "replica generation mismatch for replica at (%s), "
+ "file generation %s, new replica generation %s\n",
+ slapi_sdn_get_dn (replica_get_root (r)), file_gen, repl_gen);
+
+ object_release (*replica);
+ *replica = NULL;
+ }
+ slapi_ch_free ((void**)&repl_gen);
+ }
+ }
+ slapi_ch_free ((void**)&repl_name);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5FileName2Replica "
+ "malformed file name - %s\n", file_name);
+ }
+
+ return PR_TRUE;
+ }
+ else
+ return PR_FALSE;
+}
+
+/* file name format : <replica name>_<replica generation>db{2,3} */
+static char* _cl5Replica2FileName (Object *replica)
+{
+ const char *replName;
+ char *replGen, *fileName;
+ Replica *r;
+
+ PR_ASSERT (replica);
+
+ r = (Replica*)object_get_data (replica);
+ PR_ASSERT (r);
+
+ replName = replica_get_name (r);
+ replGen = replica_get_generation (r);
+
+ fileName = _cl5MakeFileName (replName, replGen) ;
+
+ slapi_ch_free ((void**)&replGen);
+
+ return fileName;
+}
+
+static char* _cl5MakeFileName (const char *replName, const char *replGen)
+{
+ char *fileName;
+ fileName = slapi_ch_malloc (strlen (replName) + strlen (replGen) +
+ strlen (DB_EXTENSION) + 3/* '_' + '.' + '\0' */);
+ sprintf (fileName, "%s%s%s.%s", replName, FILE_SEP, replGen, DB_EXTENSION);
+
+ return fileName;
+}
+
+/* open file that corresponds to a particular database */
+static int _cl5DBOpenFile (Object *replica, Object **obj, PRBool checkDups)
+{
+ int rc;
+ const char *replName;
+ char *replGen;
+ Replica *r;
+
+ PR_ASSERT (replica);
+
+ r = (Replica*)object_get_data (replica);
+ replName = replica_get_name (r);
+ PR_ASSERT (replName);
+ replGen = replica_get_generation (r);
+ PR_ASSERT (replGen);
+
+ rc = _cl5DBOpenFileByReplicaName (replName, replGen, obj, checkDups);
+
+ slapi_ch_free ((void**)&replGen);
+
+ return rc;
+}
+
+static int _cl5DBOpenFileByReplicaName (const char *replName, const char *replGen,
+ Object **obj, PRBool checkDups)
+{
+ int rc = CL5_SUCCESS;
+ Object *tmpObj;
+ CL5DBFile *file;
+ char *file_name;
+
+ PR_ASSERT (replName && replGen);
+
+ if (checkDups)
+ {
+ PR_Lock (s_cl5Desc.fileLock);
+ file_name = _cl5MakeFileName (replName, replGen);
+ tmpObj = objset_find (s_cl5Desc.dbFiles, _cl5CompareDBFile, file_name);
+ slapi_ch_free((void **)&file_name);
+ file_name = NULL;
+ if (tmpObj) /* this file already exist */
+ {
+ /* if we were asked for file handle - keep the handle */
+ if (obj)
+ {
+ *obj = tmpObj;
+ }
+ else
+ {
+ object_release (tmpObj);
+ }
+
+ rc = CL5_SUCCESS;
+ goto done;
+ }
+ }
+
+ rc = _cl5NewDBFile (replName, replGen, &file);
+ if (rc == CL5_SUCCESS)
+ {
+ /* This creates the file but doesn't set the init flag
+ * The flag is set later when the purge and max ruvs are set.
+ * This is to prevent some thread to get file access before the
+ * structure is fully initialized */
+ rc = _cl5AddDBFile (file, &tmpObj);
+ if (rc == CL5_SUCCESS)
+ {
+ /* read purge RUV - done here because it needs file object rather than file pointer */
+ rc = _cl5ReadRUV (replGen, tmpObj, PR_TRUE);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5DBOpenFileByReplicaName: failed to get purge RUV\n");
+ goto done;
+ }
+
+ /* read ruv that represents the upper bound of the changes stored in the file */
+ rc = _cl5ReadRUV (replGen, tmpObj, PR_FALSE);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5DBOpenFileByReplicaName: failed to get upper bound RUV\n");
+ goto done;
+ }
+
+ /* Mark the DB File initialize */
+ _cl5DBFileInitialized(tmpObj);
+
+ if (obj)
+ {
+ *obj = tmpObj;
+ }
+ else
+ {
+ object_release (tmpObj);
+ }
+ }
+ }
+
+done:;
+ if (rc != CL5_SUCCESS)
+ {
+ if (file)
+ _cl5DBCloseFile ((void**)&file);
+ }
+
+ if (checkDups)
+ {
+ PR_Unlock (s_cl5Desc.fileLock);
+ }
+
+ return rc;
+}
+
+/* adds file to the db file list */
+static int _cl5AddDBFile (CL5DBFile *file, Object **obj)
+{
+ int rc;
+ Object *tmpObj;
+
+ PR_ASSERT (file);
+
+ tmpObj = object_new (file, _cl5DBCloseFile);
+ rc = objset_add_obj(s_cl5Desc.dbFiles, tmpObj);
+ if (rc != OBJSET_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5AddDBFile: failed to add db file to the list; "
+ "repl_objset error - %d\n", rc);
+ object_release (tmpObj);
+ return CL5_OBJSET_ERROR;
+ }
+
+ if (obj)
+ {
+ *obj = tmpObj;
+ }
+ else
+ object_release (tmpObj);
+
+ return CL5_SUCCESS;
+}
+
+static int _cl5NewDBFile (const char *replName, const char *replGen, CL5DBFile** dbFile)
+{
+ int rc;
+ DB *db = NULL;
+ char *name;
+ char *semadir;
+#ifdef HPUX
+ char cwd [PATH_MAX+1];
+#endif
+
+ PR_ASSERT (replName && replGen && dbFile);
+
+ (*dbFile) = (CL5DBFile *)slapi_ch_calloc (1, sizeof (CL5DBFile));
+ if (*dbFile == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5NewDBFile: memory allocation failed\n");
+ return CL5_MEMORY_ERROR;
+ }
+
+ name = _cl5MakeFileName (replName, replGen);
+ {
+ /* The subname argument allows applications to have
+ * subdatabases, i.e., multiple databases inside of a single
+ * physical file. This is useful when the logical databases
+ * are both numerous and reasonably small, in order to
+ * avoid creating a large number of underlying files.
+ */
+ char *subname = NULL;
+ DB_ENV *dbEnv = s_cl5Desc.dbEnv;
+
+ rc = db_create(&db, dbEnv, 0);
+ if (0 != rc) {
+ goto out;
+ }
+
+ rc = db->set_pagesize(
+ db,
+ s_cl5Desc.dbConfig.pageSize);
+
+ if (0 != rc) {
+ goto out;
+ }
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 3300
+ rc = db->set_malloc(db, malloc);
+ if (0 != rc) {
+ goto out;
+ }
+#endif
+
+ DB_OPEN(s_cl5Desc.dbEnvOpenFlags,
+ db, NULL /* txnid */, name, subname, DB_BTREE,
+ DB_CREATE | DB_THREAD, s_cl5Desc.dbConfig.fileMode, rc);
+ }
+out:
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5NewDBFile: db_open failed; db error - %d %s\n",
+ rc, db_strerror(rc));
+ rc = CL5_DB_ERROR;
+ goto done;
+ }
+
+ (*dbFile)->db = db;
+ (*dbFile)->name = name;
+ (*dbFile)->replName = slapi_ch_strdup (replName);
+ (*dbFile)->replGen = slapi_ch_strdup (replGen);
+
+ /*
+ * Considerations for setting up cl semaphore:
+ * (1) The NT version of SleepyCat uses test-and-set mutexes
+ * at the DB page level instead of blocking mutexes. That has
+ * proven to be a killer for the changelog DB, as this DB is
+ * accessed by multiple a reader threads (the repl thread) and
+ * writer threads (the server ops threads) usually at the last
+ * pages of the DB, due to the sequential nature of the changelog
+ * keys. To avoid the test-and-set mutexes, we could use semaphore
+ * to serialize the writers and avoid the high mutex contention
+ * that SleepyCat is unable to avoid.
+ * (2) [610948] Linux master hangs for 2 hours
+ * [611239] _cl5DeadlockMain: lock_detect succeeded
+ * (3) DS 6.2 introduced the semaphore on all platforms (replaced
+ * the serial lock used on Windows and Linux described above).
+ * The number of the concurrent writes now is configurable by
+ * nsslapd-changelogmaxconcurrentwrites (the server needs to
+ * be restarted).
+ */
+
+ semadir = s_cl5Desc.dbDir;
+#ifdef HPUX
+ /*
+ * HP sem_open() does not allow pathname component "./" or "../"
+ * in the semaphore name. For simplicity and to avoid doing
+ * chdir() in multi-thread environment, current working dir
+ * (log dir) is used to replace the original semaphore dir
+ * if it contains "./".
+ */
+ if ( strstr ( semadir, "./" ) != NULL && getcwd ( cwd, PATH_MAX+1 ) != NULL )
+ {
+ semadir = cwd;
+ }
+#endif
+
+ if ( semadir != NULL )
+ {
+ (*dbFile)->semaName = slapi_ch_malloc (strlen(semadir) + strlen(replName) + strlen(".sema") + 10);
+ sprintf ((*dbFile)->semaName, "%s/%s.sema", semadir, replName);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5NewDBFile: semaphore %s\n", (*dbFile)->semaName);
+ (*dbFile)->sema = PR_OpenSemaphore((*dbFile)->semaName, PR_SEM_CREATE, 0666, s_cl5Desc.dbConfig.maxConcurrentWrites );
+ slapi_log_error (SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5NewDBFile: maxConcurrentWrites=%d\n", s_cl5Desc.dbConfig.maxConcurrentWrites );
+ }
+
+ if ((*dbFile)->sema == NULL )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5NewDBFile: failed to create semaphore %s; NSPR error - %d\n",
+ (*dbFile)->semaName ? (*dbFile)->semaName : "(nil)", PR_GetError ());
+ rc = CL5_SYSTEM_ERROR;
+ goto done;
+ }
+
+ /* compute number of entries in the file */
+ /* ONREPL - to improve performance, we keep entry count in memory
+ and write it down during shutdown. Problem: this will not
+ work with multiple processes. Do we have to worry about that?
+ */
+ if (s_cl5Desc.dbOpenMode == CL5_OPEN_NORMAL)
+ {
+ rc = _cl5GetEntryCount (*dbFile);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl,
+ "_cl5NewDBFile: failed to get entry count\n");
+ goto done;
+ }
+ }
+
+done:
+ if (rc != CL5_SUCCESS)
+ {
+ if (dbFile)
+ _cl5DBCloseFile ((void**)dbFile);
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void**)&name);
+
+ slapi_ch_free ((void**)dbFile);
+ }
+
+ return rc;
+}
+
+static void _cl5DBCloseFile (void **data)
+{
+ CL5DBFile *file;
+ char fullpathname[MAXPATHLEN];
+
+ PR_ASSERT (data);
+
+ file = *(CL5DBFile**)data;
+
+ /* close the file */
+ /* if this is normal close or close after import, update entry count */
+ if ((s_cl5Desc.dbOpenMode == CL5_OPEN_NORMAL && s_cl5Desc.dbState == CL5_STATE_CLOSING) ||
+ s_cl5Desc.dbOpenMode == CL5_OPEN_LDIF2CL)
+ {
+ _cl5WriteEntryCount (file);
+ _cl5WriteRUV (file, PR_TRUE);
+ _cl5WriteRUV (file, PR_FALSE);
+ }
+
+ /* close file */
+ if (file->db)
+ file->db->close(file->db, 0);
+
+ if (file->flags & DB_FILE_DELETED)
+ {
+ PR_snprintf(fullpathname, MAXPATHLEN, "%s/%s", s_cl5Desc.dbDir, file->name);
+ if (PR_Delete(fullpathname) != PR_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name_cl, "_cl5DBCloseFile: "
+ "failed to remove (%s) file; NSPR error - %d\n", file->name, PR_GetError ());
+
+ }
+ }
+
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void**)&file->name);
+ slapi_ch_free ((void**)&file->replName);
+ slapi_ch_free ((void**)&file->replGen);
+ if (file->sema) {
+ PR_CloseSemaphore (file->sema);
+ PR_DeleteSemaphore (file->semaName);
+ file->sema = NULL;
+ }
+ slapi_ch_free ((void**)&file->semaName);
+
+ slapi_ch_free (data);
+}
+
+static int _cl5GetDBFile (Object *replica, Object **obj)
+{
+ char *fileName;
+
+ PR_ASSERT (replica && obj);
+
+ fileName = _cl5Replica2FileName (replica);
+
+ *obj = objset_find(s_cl5Desc.dbFiles, _cl5CompareDBFile, fileName);
+ slapi_ch_free ((void**)&fileName);
+ if (*obj)
+ {
+ return CL5_SUCCESS;
+ }
+ else
+ {
+ return CL5_NOTFOUND;
+ }
+}
+
+static int _cl5GetDBFileByReplicaName (const char *replName, const char *replGen,
+ Object **obj)
+{
+ char *fileName;
+
+ PR_ASSERT (replName && replGen && obj);
+
+ fileName = _cl5MakeFileName (replName, replGen);
+
+ *obj = objset_find(s_cl5Desc.dbFiles, _cl5CompareDBFile, fileName);
+ slapi_ch_free ((void**)&fileName);
+ if (*obj)
+ {
+ return CL5_SUCCESS;
+ }
+ else
+ {
+ return CL5_NOTFOUND;
+ }
+}
+
+static void _cl5DBDeleteFile (Object *obj)
+{
+ CL5DBFile *file;
+
+ PR_ASSERT (obj);
+
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+ file->flags |= DB_FILE_DELETED;
+ objset_remove_obj(s_cl5Desc.dbFiles, obj);
+ object_release (obj);
+}
+
+static void _cl5DBFileInitialized (Object *obj)
+{
+ CL5DBFile *file;
+
+ PR_ASSERT (obj);
+
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+ file->flags |= DB_FILE_INIT;
+}
+
+static int _cl5CompareDBFile (Object *el1, const void *el2)
+{
+ CL5DBFile *file;
+ const char *name;
+
+ PR_ASSERT (el1 && el2);
+
+ file = (CL5DBFile*) object_get_data (el1);
+ name = (const char*) el2;
+ return ((file->flags & DB_FILE_INIT) ? strcmp (file->name, name) : 1);
+}
+
+static int _cl5CopyDBFiles (const char *srcDir, const char *destDir, Object **replicas)
+{
+ char srcFile [MAXPATHLEN + 1];
+ char destFile[MAXPATHLEN + 1];
+ int rc;
+ Object *obj;
+ CL5DBFile *file;
+
+ /* ONREPL currently, dbidlist is ignored because db code can't handle discrepancy between
+ transaction log and present files; this should change before 5.0 ships */
+ obj = objset_first_obj (s_cl5Desc.dbFiles);
+ while (obj)
+ {
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+
+ PR_snprintf(srcFile, MAXPATHLEN, "%s/%s", srcDir, file->name);
+ PR_snprintf(destFile, MAXPATHLEN, "%s/%s", destDir, file->name);
+ rc = copyfile(srcFile, destFile, 0, FILE_CREATE_MODE);
+ if (rc != 0)
+ {
+ object_release (obj);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5CopyDBFiles: failed to copy %s from %s to %s\n",
+ file, srcDir, destDir);
+ return CL5_SYSTEM_ERROR;
+ }
+
+ obj = objset_next_obj (s_cl5Desc.dbFiles, obj);
+ }
+
+ return CL5_SUCCESS;
+}
+
+/*
+ * return 1: true (the "filename" ends with "ext")
+ * return 0: false
+ */
+static int _cl5FileEndsWith(const char *filename, const char *ext)
+{
+ char *p = NULL;
+ int flen = strlen(filename);
+ int elen = strlen(ext);
+ if (0 == flen || 0 == elen)
+ {
+ return 0;
+ }
+ p = strstr(filename, ext);
+ if (NULL == p)
+ {
+ return 0;
+ }
+ if (p - filename + elen == flen)
+ {
+ return 1;
+ }
+ return 0;
+}
+
+static int _cl5ExportFile (PRFileDesc *prFile, Object *obj)
+{
+ int rc;
+ void *iterator = NULL;
+ slapi_operation_parameters op = {0};
+ char *buff;
+ PRInt32 len, wlen;
+ CL5Entry entry;
+ CL5DBFile *file;
+
+ PR_ASSERT (prFile && obj);
+
+ file = (CL5DBFile*)object_get_data (obj);
+ PR_ASSERT (file);
+
+ ruv_dump (file->purgeRUV, "clpurgeruv", prFile);
+ ruv_dump (file->maxRUV, "clmaxruv", prFile);
+ slapi_write_buffer (prFile, "\n", strlen("\n"));
+
+ entry.op = &op;
+ rc = _cl5GetFirstEntry (obj, &entry, &iterator, NULL);
+ while (rc == CL5_SUCCESS)
+ {
+ rc = _cl5Operation2LDIF (&op, file->replGen, &buff, &len);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5ExportLDIF: failed to convert operation to ldif\n");
+ operation_parameters_done (&op);
+ break;
+ }
+
+ wlen = slapi_write_buffer (prFile, buff, len);
+ slapi_ch_free((void **)&buff);
+ if (wlen < len)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5ExportLDIF: failed to write to ldif file\n");
+ rc = CL5_SYSTEM_ERROR;
+ operation_parameters_done (&op);
+ break;
+ }
+
+ cl5_operation_parameters_done (&op);
+
+ rc = _cl5GetNextEntry (&entry, iterator);
+ }
+
+ cl5_operation_parameters_done (&op);
+
+ if (iterator)
+ cl5DestroyIterator (iterator);
+
+ if (rc != CL5_NOTFOUND)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "_cl5ExportLDIF: failed to retrieve changelog entry\n");
+ }
+ else
+ {
+ rc = CL5_SUCCESS;
+ }
+
+ return rc;
+}
+
+static PRBool _cl5ReplicaInList (Object *replica, Object **replicas)
+{
+ int i;
+
+ PR_ASSERT (replica && replicas);
+
+ /* ONREPL I think it should be sufficient to just compare replica pointers */
+ for (i=0; replicas[i]; i++)
+ {
+ if (replica == replicas[i])
+ return PR_TRUE;
+ }
+
+ return PR_FALSE;
+}
+
+static char* _cl5GetHelperEntryKey (int type, char *csnStr)
+{
+ CSN *csn= csn_new();
+ char *rt;
+
+ csn_set_time(csn, type);
+ csn_set_replicaid(csn, 0);
+
+ rt = csn_as_string(csn, PR_FALSE, csnStr);
+ csn_free(&csn);
+
+ return rt;
+}
+
+static Object* _cl5GetReplica (const slapi_operation_parameters *op, const char* replGen)
+{
+ Slapi_DN *sdn;
+ Object *replObj;
+ Replica *replica;
+ char *newGen;
+
+ PR_ASSERT (op && replGen);
+
+ sdn = slapi_sdn_new_dn_byref(op->target_address.dn);
+
+ replObj = replica_get_replica_from_dn (sdn);
+ if (replObj)
+ {
+ /* check to see if replica generation has not change */
+ replica = (Replica*)object_get_data (replObj);
+ PR_ASSERT (replica);
+ newGen = replica_get_generation (replica);
+ PR_ASSERT (newGen);
+ if (strcmp (replGen, newGen) != 0)
+ {
+ object_release (replObj);
+ replObj = NULL;
+ }
+
+ slapi_ch_free ((void**)&replGen);
+ }
+
+ slapi_sdn_free (&sdn);
+
+ return replObj;
+}
+
+int
+cl5_is_diskfull()
+{
+ int rc;
+ PR_Lock(cl5_diskfull_lock);
+ rc = cl5_diskfull_flag;
+ PR_Unlock(cl5_diskfull_lock);
+ return rc;
+}
+
+static void
+cl5_set_diskfull()
+{
+ PR_Lock(cl5_diskfull_lock);
+ cl5_diskfull_flag = 1;
+ PR_Unlock(cl5_diskfull_lock);
+}
+
+static void
+cl5_set_no_diskfull()
+{
+ PR_Lock(cl5_diskfull_lock);
+ cl5_diskfull_flag = 0;
+ PR_Unlock(cl5_diskfull_lock);
+}
+
+int
+cl5_diskspace_is_available()
+{
+ int rval = 1;
+
+#if defined( OS_solaris ) || defined( hpux )
+ struct statvfs fsbuf;
+ if (statvfs(s_cl5Desc.dbDir, &fsbuf) < 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5_diskspace_is_available: Cannot get file system info\n");
+ rval = 0;
+ }
+ else
+ {
+ unsigned long fsiz = fsbuf.f_bavail * fsbuf.f_frsize;
+ if (fsiz < NO_DISK_SPACE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5_diskspace_is_available: No enough diskspace for changelog: (%u bytes free)\n", fsiz);
+ rval = 0;
+ }
+ else if (fsiz > MIN_DISK_SPACE)
+ {
+ /* assume recovered */
+ cl5_set_no_diskfull();
+ }
+ }
+#endif
+#if defined( linux )
+ struct statfs fsbuf;
+ if (statfs(s_cl5Desc.dbDir, &fsbuf) < 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5_diskspace_is_available: Cannot get file system info\n");
+ rval = 0;
+ }
+ else
+ {
+ unsigned long fsiz = fsbuf.f_bavail * fsbuf.f_bsize;
+ if (fsiz < NO_DISK_SPACE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "cl5_diskspace_is_available: No enough diskspace for changelog: (%u bytes free)\n", fsiz);
+ rval = 0;
+ }
+ else if (fsiz > MIN_DISK_SPACE)
+ {
+ /* assume recovered */
+ cl5_set_no_diskfull();
+ }
+ }
+#endif
+ return rval;
+}
diff --git a/ldap/servers/plugins/replication/cl5_api.h b/ldap/servers/plugins/replication/cl5_api.h
new file mode 100644
index 00000000..49296df2
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl5_api.h
@@ -0,0 +1,478 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cl5_api.h - interface to 5.0 changelog */
+
+#ifndef CL5_API_H
+#define CL5_API_H
+
+#include "repl5.h"
+#include "repl5_prot_private.h"
+
+#define CL5_TYPE "Changelog5" /* changelog type */
+#define VERSION_SIZE 127 /* size of the buffer to hold changelog version */
+#define CL5_DEFAULT_CONFIG -1 /* value that indicates to changelog to use default */
+#define CL5_STR_IGNORE "-1" /* tels function to ignore this parameter */
+#define CL5_NUM_IGNORE -1 /* tels function to ignore this parameter */
+#define CL5_STR_UNLIMITED "0" /* represent unlimited value (trimming ) */
+#define CL5_NUM_UNLIMITED 0 /* represent unlimited value (trimming ) */
+
+#define CL5_OS_ERR_IS_DISKFULL(err) ((err)==ENOSPC || (err)==EFBIG)
+
+/***** Data Structures *****/
+
+/* changelog configuration structure */
+typedef struct cl5dbconfig
+{
+ size_t cacheSize; /* cache size in bytes */
+ PRBool durableTrans; /* flag that tells not to sync log when trans commits */
+ PRInt32 checkpointInterval; /* checkpoint interval in seconds */
+ PRBool circularLogging; /* flag to archive and trancate log */
+ size_t pageSize; /* page size in bytes */
+ size_t logfileSize; /* maximum log size in bytes */
+ size_t maxTxnSize; /* maximum txn table size in count*/
+ PRInt32 fileMode; /* file mode */
+ PRBool verbose; /* Get libdb to exhale debugging info */
+ PRBool debug; /* Will libdb emit debugging info into our log ? */
+ PRInt32 tricklePercentage; /* guaranteed percentage of clean cache pages; 0 - 100 */
+ PRInt32 spinCount; /* DB Mutex spin count */
+ PRUint32 nb_lock_config; /* Number of locks in the DB lock table. New in 5.1 */
+/* The next 2 parameters are needed for configuring the changelog cache. New in 5.1 */
+ PRUint32 maxChCacheEntries;
+ PRUint32 maxChCacheSize;
+ PRUint32 maxConcurrentWrites; /* 6.2 max number of concurrent cl writes */
+} CL5DBConfig;
+
+/* changelog entry format */
+typedef struct cl5entry
+{
+ slapi_operation_parameters *op; /* operation applied to the server */
+ time_t time; /* time added to the cl; used for trimming */
+} CL5Entry;
+
+/* default values for the changelog configuration structure above */
+/*
+ * For historical reasons, dbcachesize refers to number of bytes at the DB level,
+ * whereas cachesize refers to number of entries at the changelog cache level (cachememsize is the
+ * one refering to number of bytes at the changelog cache level)
+ */
+#define CL5_DEFAULT_CONFIG_DB_DBCACHESIZE 10485760 /* 10M bytes */
+#define CL5_DEFAULT_CONFIG_DB_DURABLE_TRANSACTIONS 1
+#define CL5_DEFAULT_CONFIG_DB_CHECKPOINT_INTERVAL 60
+#define CL5_DEFAULT_CONFIG_DB_CIRCULAR_LOGGING 1
+#define CL5_DEFAULT_CONFIG_DB_PAGE_SIZE 8*1024
+#define CL5_DEFAULT_CONFIG_DB_LOGFILE_SIZE 0
+#define CL5_DEFAULT_CONFIG_DB_VERBOSE 0
+#define CL5_DEFAULT_CONFIG_DB_DEBUG 0
+#define CL5_DEFAULT_CONFIG_DB_TRICKLE_PERCENTAGE 40
+#define CL5_DEFAULT_CONFIG_DB_SPINCOUNT 0
+#define CL5_DEFAULT_CONFIG_DB_TXN_MAX 200
+#define CL5_DEFAULT_CONFIG_CACHESIZE 3000 /* number of entries */
+#define CL5_DEFAULT_CONFIG_CACHEMEMSIZE 1048576 /* 1 M bytes */
+#define CL5_DEFAULT_CONFIG_NB_LOCK 1000 /* Number of locks in the lock table of the DB */
+
+/*
+ * Small number of concurrent writes degradate the throughput.
+ * Large one increases deadlock.
+ */
+#ifdef SOLARIS
+#define CL5_DEFAULT_CONFIG_MAX_CONCURRENT_WRITES 10
+#else
+#define CL5_DEFAULT_CONFIG_MAX_CONCURRENT_WRITES 2
+#endif
+
+
+#define CL5_MIN_DB_DBCACHESIZE 524288 /* min 500K bytes */
+#define CL5_MIN_CACHESIZE 500 /* min number of entries */
+#define CL5_MIN_CACHEMEMSIZE 262144 /* min 250K bytes */
+#define CL5_MIN_NB_LOCK 1000 /* The minimal number of locks in the DB (Same as default) */
+
+/* data structure that allows iteration through changelog */
+typedef struct cl5replayiterator CL5ReplayIterator;
+
+/* changelog state */
+typedef enum
+{
+ CL5_STATE_NONE, /* changelog has not been initialized */
+ CL5_STATE_CLOSING, /* changelog is about to close; all threads must exit */
+ CL5_STATE_CLOSED, /* changelog has been initialized, but not opened, or open and then closed */
+ CL5_STATE_OPEN /* changelog is opened */
+} CL5State;
+
+/* error codes */
+enum
+{
+ CL5_SUCCESS, /* successful operation */
+ CL5_BAD_DATA, /* invalid parameter passed to the function */
+ CL5_BAD_FORMAT, /* db data has unexpected format */
+ CL5_BAD_STATE, /* changelog is in an incorrect state for attempted operation */
+ CL5_BAD_DBVERSION, /* changelog has invalid dbversion */
+ CL5_DB_ERROR, /* database error */
+ CL5_NOTFOUND, /* requested entry or value was not found */
+ CL5_MEMORY_ERROR, /* memory allocation failed */
+ CL5_SYSTEM_ERROR, /* NSPR error occured, use PR_Error for furhter info */
+ CL5_CSN_ERROR, /* CSN API failed */
+ CL5_RUV_ERROR, /* RUV API failed */
+ CL5_OBJSET_ERROR, /* namedobjset api failed */
+ CL5_PURGED_DATA, /* requested data has been purged */
+ CL5_MISSING_DATA, /* data should be in the changelog, but is missing */
+ CL5_UNKNOWN_ERROR /* unclassified error */
+};
+
+/***** Module APIs *****/
+
+/* Name: cl5Init
+ Description: initializes changelog module; must be called by a single thread
+ before any function of the module.
+ Parameters: none
+ Return: CL5_SUCCESS if function is successful;
+ CL5_BAD_DATA if invalid directory is passed;
+ CL5_SYSTEM error if NSPR call fails.
+ */
+int cl5Init ();
+
+/* Name: cl5Cleanup
+ Description: performs cleanup of the changelog module. Must be called by a single
+ thread. It will closed db if it is still open.
+ Parameters: none
+ Return: none
+ */
+void cl5Cleanup ();
+
+/* Name: cl5Open
+ Description: opens changelog ; must be called after changelog is
+ initialized using cl5Init. It is thread safe and the second
+ call is ignored.
+ Parameters: dir - changelog dir
+ config - db configuration parameters; currently not used
+ openMode - open mode
+ Return: CL5_SUCCESS if successfull;
+ CL5_BAD_DATA if invalid directory is passed;
+ CL5_BAD_DBVERSION if dbversion file is missing or has unexpected data
+ CL5_SYSTEM_ERROR if NSPR error occured (during db directory creation);
+ CL5_MEMORY_ERROR if memory allocation fails;
+ CL5_DB_ERROR if db initialization or open fails.
+ */
+int cl5Open (const char *dir, const CL5DBConfig *config);
+
+/* Name: cl5Close
+ Description: closes changelog and cleanups changelog module; waits until
+ all threads are done using changelog
+ Parameters: none
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if db is not in the open state;
+ CL5_SYSTEM_ERROR if NSPR call fails
+ */
+int cl5Close ();
+
+/* Name: cl5Delete
+ Description: removes changelog
+ Parameters: dir - changelog directory
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if the changelog is not in closed state;
+ CL5_BAD_DATA if invalid directory supplied
+ CL5_SYSTEM_ERROR if NSPR call fails
+ */
+int cl5Delete (const char *dir);
+
+/* Name: cl5OpenDB
+ Description: opens changelog file for specified file
+ Parameters: replica - replica whose file we wish to open
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if the changelog is not initialized;
+ CL5_BAD_DATA - if NULL id is supplied
+ */
+int cl5OpenDB (Object *replica);
+
+/* Name: cl5CloseDB
+ Description: closes changelog file for the specified replica
+ Parameters: replica - replica whose file we wish to close
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if the changelog is not initialized;
+ CL5_BAD_DATA - if NULL id is supplied
+ CL5_NOTFOUND - nothing is known about specified database
+ */
+int cl5CloseDB (Object *replica);
+
+/* Name: cl5DeleteDB
+ Description: asynchronously removes changelog file for the specified replica.
+ The file is physically removed when it is no longer in use.
+ This function is called when a backend is removed or reloaded.
+ Parameters: replica - replica whose file we wish to delete
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if the changelog is not initialized;
+ CL5_BAD_DATA - if NULL id is supplied
+ CL5_NOTFOUND - nothing is known about specified database
+ */
+int cl5DeleteDB (Object *replica);
+
+/* Name: cl5DeleteDBSync
+ Description: The same as cl5DeleteDB except the function does not return
+ until the file is removed.
+*/
+int cl5DeleteDBSync (Object *replica);
+
+/* Name: cl5GetUpperBoundRUV
+ Description: retrieves vector that represent the upper bound of changes
+ stored in the changelog for the replica.
+ Parameters: r - replica for which the vector is requested
+ ruv - contains a copy of the upper bound ruv if function is successful;
+ unchanged otherwise. It is responsobility pf the caller to free
+ the ruv when it is no longer is in use
+ Return: CL5_SUCCESS if function is successfull
+ CL5_BAD_STATE if the changelog is not initialized;
+ CL5_BAD_DATA - if NULL id is supplied
+ CL5_NOTFOUND, if changelog file for replica is not found
+ */
+int cl5GetUpperBoundRUV (Replica *r, RUV **ruv);
+
+/* Name: cl5Backup
+ Description: makes a backup of the changelog including *.db2,
+ log files, and dbversion. Can be called with the changelog in either open or
+ closed state.
+ Parameters: bkDir - directory to which the data is backed up;
+ created if it does not exist
+ replicas - optional list of replicas whose changes should be backed up;
+ if the list is NULL, entire changelog is backed up.
+ Return: CL5_SUCCESS if function is successful;
+ CL5_BAD_DATA if invalid directory is passed;
+ CL5_BAD_STATE if changelog has not been initialized;
+ CL5_DB_ERROR if db call fails;
+ CL5_SYSTEM_ERROR if NSPR call or file copy failes.
+ */
+int cl5Backup (const char *bkDir, Object **replicas);
+
+/* Name: cl5Restore
+ Description: restores changelog from the backed up copy. Changelog must be ibnitalized and closed.
+ Parameters: clDir - changelog dir
+ bkDir - directory that contains the backup
+ replicas - optional list of replicas whose changes should be recovered;
+ if the list is NULL, entire changelog is recovered.
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_BAD_STATE if changelog is open or not initialized;
+ CL5_DB_ERROR if db call fails;
+ CL5_SYSTEM_ERROR if NSPR call of file copy fails
+ */
+int cl5Restore (const char *clDir, const char *bkDir, Object **replicas);
+
+/* Name: cl5ExportLDIF
+ Description: dumps changelog to an LDIF file; changelog can be open or closed.
+ Parameters: clDir - changelog dir
+ ldifFile - full path to ldif file to write
+ replicas - optional list of replicas whose changes should be exported;
+ if the list is NULL, entire changelog is exported.
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_BAD_STATE if changelog is not initialized;
+ CL5_DB_ERROR if db api fails;
+ CL5_SYSTEM_ERROR if NSPR call fails;
+ CL5_MEMORY_ERROR if memory allocation fials.
+ */
+int cl5ExportLDIF (const char *ldifFile, Object **replicas);
+
+/* Name: cl5ImportLDIF
+ Description: imports ldif file into changelog; changelog must be in the closed state
+ Parameters: clDir - changelog dir
+ ldifFile - absolute path to the ldif file to import
+ replicas - optional list of replicas whose data should be imported;
+ if the list is NULL, all data in the file is imported.
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_BAD_STATE if changelog is open or not inititalized;
+ CL5_DB_ERROR if db api fails;
+ CL5_SYSTEM_ERROR if NSPR call fails;
+ CL5_MEMORY_ERROR if memory allocation fials.
+ */
+int cl5ImportLDIF (const char *clDir, const char *ldifFile, Object **replicas);
+
+/* Name: cl5GetState
+ Description: returns database state
+ Parameters: none
+ Return: changelog state
+ */
+
+int cl5GetState ();
+
+/* Name: cl5ConfigTrimming
+ Description: sets changelog trimming parameters
+ Parameters: maxEntries - maximum number of entries in the log;
+ maxAge - maximum entry age;
+ Return: CL5_SUCCESS if successful;
+ CL5_BAD_STATE if changelog has not been open
+ */
+int cl5ConfigTrimming (int maxEntries, const char *maxAge);
+
+/* Name: cl5GetOperation
+ Description: retireves operation specified by its csn and databaseid
+ Parameters: op - must contain csn and databaseid; the rest of data is
+ filled if function is successfull
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid op is passed;
+ CL5_BAD_STATE if db has not been initialized;
+ CL5_NOTFOUND if entry was not found;
+ CL5_DB_ERROR if any other db error occured;
+ CL5_BADFORMAT if db data format does not match entry format.
+ */
+int cl5GetOperation (Object *replica, slapi_operation_parameters *op);
+
+/* Name: cl5GetFirstOperation
+ Description: retrieves first operation for a particular database
+ replica - replica for which the operation should be retrieved.
+ Parameters: op - buffer to store the operation;
+ iterator - to be passed to the call to cl5GetNextOperation
+ Return: CL5_SUCCESS, if successful
+ CL5_BADDATA, if operation is NULL
+ CL5_BAD_STATE, if changelog is not open
+ CL5_DB_ERROR, if db call fails
+ */
+int cl5GetFirstOperation (Object *replica, slapi_operation_parameters *op, void **iterator);
+
+/* Name: cl5GetNextOperation
+ Description: retrieves the next op from the changelog as defined by the iterator
+ Parameters: replica - replica for which the operation should be retrieved.
+ op - returned operation, if function is successful
+ iterator - in: identifies op to retrieve; out: identifies next op
+ Return: CL5_SUCCESS, if successful
+ CL5_BADDATA, if invalid parameter is supplied
+ CL5_BAD_STATE, if changelog is not open
+ CL5_NOTFOUND, empty changelog
+ CL5_DB_ERROR, if db call fails
+ */
+int cl5GetNextOperation (slapi_operation_parameters *op, void *iterator);
+
+/* Name: cl5DestroyIterator
+ Description: destroys iterator once iteration through changelog is done
+ Parameters: iterator - iterator to destroy
+ Return: CL5_SUCCESS, if successful
+ CL5_BADDATA, if invalid parameters is supplied
+ CL5_BAD_STATE, if changelog is not open
+ CL5_DB_ERROR, if db call fails
+ */
+void cl5DestroyIterator (void *iterator);
+
+/* Name: cl5WriteOperation
+ Description: writes operation to changelog
+ Parameters: repl_name - name of the replica to which operation applies
+ repl_gen - replica generation for the operation
+ !!!Note that we pass name and generation rather than
+ replica object since generation can change while operation
+ is in progress (if the data is reloaded). !!!
+ op - operation to write
+ local - this is a non-replicated operation
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid op is passed;
+ CL5_BAD_STATE if db has not been initialized;
+ CL5_MEMORY_ERROR if memory allocation failed;
+ CL5_DB_ERROR if any other db error occured;
+ */
+int cl5WriteOperation(const char *repl_name, const char *repl_gen,
+ const slapi_operation_parameters *op, PRBool local);
+
+/* Name: cl5CreateReplayIterator
+ Description: creates an iterator that allows to retireve changes that should
+ to be sent to the consumer identified by ruv The iteration is peformed by
+ repeated calls to cl5GetNextOperationToReplay.
+ Parameters: replica - replica whose data we wish to iterate;
+ ruv - consumer ruv;
+ iterator - iterator to be passed to cl5GetNextOperationToReplay call
+ Return: CL5_SUCCESS, if function is successfull;
+ CL5_MISSING_DATA, if data that should be in the changelog is missing
+ CL5_PURGED_DATA, if some data that consumer needs has been purged.
+ Note that the iterator can be non null if the supplier contains
+ some data that needs to be sent to the consumer
+ CL5_NOTFOUND if the consumer is up to data with respect to the supplier
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_BAD_STATE if db has not been open;
+ CL5_DB_ERROR if any other db error occured;
+ CL5_MEMORY_ERROR if memory allocation fails.
+ */
+int cl5CreateReplayIterator (Private_Repl_Protocol *prp, const RUV *ruv,
+ CL5ReplayIterator **iterator);
+
+/* Name: cl5GetNextOperationToReplay
+ Description: retrieves next operation to be sent to the consumer and
+ that was created on a particular master. Consumer and master info
+ is encoded in the iterator parameter that must be created by calling
+ to cl5CreateIterator.
+ Parameters: iterator - iterator that identifies next entry to retrieve;
+ op - operation retireved if function is successful
+ Return: CL5_SUCCESS if function is successfull;
+ CL5_BAD_DATA if invalid parameter is passed;
+ CL5_NOTFOUND if end of iteration list is reached
+ CL5_DB_ERROR if any other db error occured;
+ CL5_BADFORMAT if data in db is of unrecognized format;
+ CL5_MEMORY_ERROR if memory allocation fails.
+ */
+int cl5GetNextOperationToReplay (CL5ReplayIterator *iterator,
+ CL5Entry *entry);
+
+/* Name: cl5DestroyReplayIterator
+ Description: destorys iterator
+ Parameters: iterator - iterator to destory
+ Return: none
+ */
+void cl5DestroyReplayIterator (CL5ReplayIterator **iterator);
+
+/* Name: cl5DeleteOnClose
+ Description: marks changelog for deletion when it is closed
+ Parameters: flag; if flag = 1 then delete else don't
+ Return: none
+ */
+
+void cl5DeleteOnClose (PRBool rm);
+
+/* Name: cl5GetDir
+ Description: returns changelog directory; must be freed by the caller;
+ Parameters: none
+ Return: copy of the directory; caller needs to free the string
+ */
+
+char *cl5GetDir ();
+
+/* Name: cl5Exist
+ Description: checks if a changelog exists in the specified directory
+ Parameters: clDir - directory to check;
+ Return: 1 - if changelog exists; 0 - otherwise
+ */
+
+PRBool cl5Exist (const char *clDir);
+
+/* Name: cl5GetOperationCount
+ Description: returns number of entries in the changelog. The changelog must be
+ open for the value to be meaningful.
+ Parameters: replica - optional parameter that specifies the replica whose operations
+ we wish to count; if NULL all changelog entries are counted
+ Return: number of entries in the changelog
+ */
+
+int cl5GetOperationCount (Object *replica);
+
+/* Name: cl5_operation_parameters_done
+ Description: frees all parameters that are not freed by operation_parameters_done
+ function in the server.
+
+ */
+
+void cl5_operation_parameters_done (struct slapi_operation_parameters *sop);
+
+/* Name: cl5CreateDirIfNeeded
+ Description: Create the directory if it doesn't exist yet
+ Parameters: dir - Contains the name of the directory to create. Must not be NULL
+ Return: CL5_SUCCESS if succeeded or existed,
+ CL5_SYSTEM_ERROR if failed.
+*/
+
+int cl5CreateDirIfNeeded (const char *dir);
+int cl5DBData2Entry (const char *data, PRUint32 len, CL5Entry *entry);
+
+PRBool cl5HelperEntry (const char *csnstr, CSN *csn);
+CSN** cl5BuildCSNList (const RUV *consRuv, const RUV *supRuv);
+void cl5DestroyCSNList (CSN*** csns);
+
+int cl5_is_diskfull();
+int cl5_diskspace_is_available();
+
+#endif
diff --git a/ldap/servers/plugins/replication/cl5_clcache.c b/ldap/servers/plugins/replication/cl5_clcache.c
new file mode 100644
index 00000000..585a7266
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl5_clcache.c
@@ -0,0 +1,910 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2003 Netscape Communications Corporation
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "errno.h" /* ENOMEM, EVAL used by Berkeley DB */
+#include "db.h" /* Berkeley DB */
+#include "cl5.h" /* changelog5Config */
+#include "cl5_clcache.h"
+
+/*
+ * Constants for the buffer pool:
+ *
+ * DEFAULT_CLC_BUFFER_PAGE_COUNT
+ * Little performance boost if it is too small.
+ *
+ * DEFAULT_CLC_BUFFER_PAGE_SIZE
+ * Its value is determined based on the DB requirement that
+ * the buffer size should be the multiple of 1024.
+ */
+#define DEFAULT_CLC_BUFFER_COUNT_MIN 10
+#define DEFAULT_CLC_BUFFER_COUNT_MAX 0
+#define DEFAULT_CLC_BUFFER_PAGE_COUNT 32
+#define DEFAULT_CLC_BUFFER_PAGE_SIZE 1024
+
+static enum {
+ CLC_STATE_READY = 0, /* ready to iterate */
+ CLC_STATE_UP_TO_DATE, /* remote RUV already covers the CSN */
+ CLC_STATE_CSN_GT_RUV, /* local RUV doesn't conver the CSN */
+ CLC_STATE_NEW_RID, /* unknown RID to local RUVs */
+ CLC_STATE_UNSAFE_RUV_CHANGE,/* (RUV1 < maxcsn-in-buffer) && (RUV1 < RUV1') */
+ CLC_STATE_DONE, /* no more change */
+ CLC_STATE_ABORTING /* abort replication session */
+};
+
+typedef struct clc_busy_list CLC_Busy_List;
+
+struct csn_seq_ctrl_block {
+ ReplicaId rid; /* RID this block serves */
+ CSN *consumer_maxcsn; /* Don't send CSN <= this */
+ CSN *local_maxcsn; /* Don't send CSN > this */
+ CSN *prev_local_maxcsn; /* */
+ int state; /* CLC_STATE_* */
+};
+
+/*
+ * Each cl5replayiterator acquires a buffer from the buffer pool
+ * at the beginning of a replication session, and returns it back
+ * at the end.
+ */
+struct clc_buffer {
+ char *buf_agmt_name; /* agreement acquired this buffer */
+ ReplicaId buf_consumer_rid; /* help checking threshold csn */
+ const RUV *buf_consumer_ruv; /* used to skip change */
+ const RUV *buf_local_ruv; /* used to refresh local_maxcsn */
+
+ /*
+ * fields for retriving data from DB
+ */
+ int buf_state;
+ CSN *buf_current_csn;
+ int buf_load_flag; /* db flag DB_MULTIPLE_KEY, DB_SET, DB_NEXT */
+ DBC *buf_cursor;
+ DBT buf_key; /* current csn string */
+ DBT buf_data; /* data retrived from db */
+ void *buf_record_ptr; /* ptr to the current record in data */
+ CSN *buf_missing_csn; /* used to detect persistent missing of CSN */
+
+ /* fields for control the CSN sequence sent to the consumer */
+ struct csn_seq_ctrl_block *buf_cscbs [MAX_NUM_OF_MASTERS];
+ int buf_num_cscbs; /* number of csn sequence ctrl blocks */
+
+ /* fields for debugging stat */
+ int buf_load_cnt; /* number of loads for session */
+ int buf_record_cnt; /* number of changes for session */
+ int buf_record_skipped; /* number of changes skipped */
+
+ /*
+ * fields that should be accessed via bl_lock or pl_lock
+ */
+ CLC_Buffer *buf_next; /* next buffer in the same list */
+ CLC_Busy_List *buf_busy_list; /* which busy list I'm in */
+};
+
+/*
+ * Each changelog has a busy buffer list
+ */
+struct clc_busy_list {
+ PRLock *bl_lock;
+ DB *bl_db; /* changelog db handle */
+ CLC_Buffer *bl_buffers; /* busy buffers of this list */
+ CLC_Busy_List *bl_next; /* next busy list in the pool */
+};
+
+/*
+ * Each process has a buffer pool
+ */
+struct clc_pool {
+ PRRWLock *pl_lock; /* cl writer and agreements */
+ DB_ENV **pl_dbenv; /* pointer to DB_ENV for all the changelog files */
+ CLC_Busy_List *pl_busy_lists; /* busy buffer lists, one list per changelog file */
+ int pl_buffer_cnt_now; /* total number of buffers */
+ int pl_buffer_cnt_min; /* free a newly returned buffer if _now > _min */
+ int pl_buffer_cnt_max; /* no use */
+ int pl_buffer_default_pages; /* num of pages in a new buffer */
+};
+
+/* static variables */
+static struct clc_pool *_pool = NULL; /* process's buffer pool */
+
+/* static prototypes */
+static int clcache_adjust_anchorcsn ( CLC_Buffer *buf );
+static void clcache_refresh_consumer_maxcsns ( CLC_Buffer *buf );
+static int clcache_refresh_local_maxcsns ( CLC_Buffer *buf );
+static int clcache_skip_change ( CLC_Buffer *buf );
+static int clcache_load_buffer_bulk ( CLC_Buffer *buf, int flag );
+static int clcache_open_cursor ( DB_TXN *txn, CLC_Buffer *buf, DBC **cursor );
+static int clcache_cursor_get ( DBC *cursor, CLC_Buffer *buf, int flag );
+static struct csn_seq_ctrl_block *clcache_new_cscb ();
+static void clcache_free_cscb ( struct csn_seq_ctrl_block ** cscb );
+static CLC_Buffer *clcache_new_buffer ( ReplicaId consumer_rid );
+static void clcache_delete_buffer ( CLC_Buffer **buf );
+static CLC_Busy_List *clcache_new_busy_list ();
+static void clcache_delete_busy_list ( CLC_Busy_List **bl );
+static int clcache_enqueue_busy_list( DB *db, CLC_Buffer *buf );
+static void csn_dup_or_init_by_csn ( CSN **csn1, CSN *csn2 );
+
+/*
+ * Initiates the process buffer pool. This should be done
+ * once and only once when process starts.
+ */
+int
+clcache_init ( DB_ENV **dbenv )
+{
+ _pool = (struct clc_pool*) slapi_ch_calloc ( 1, sizeof ( struct clc_pool ));
+ _pool->pl_dbenv = dbenv;
+ _pool->pl_buffer_cnt_min = DEFAULT_CLC_BUFFER_COUNT_MIN;
+ _pool->pl_buffer_cnt_max = DEFAULT_CLC_BUFFER_COUNT_MAX;
+ _pool->pl_buffer_default_pages = DEFAULT_CLC_BUFFER_COUNT_MAX;
+ _pool->pl_lock = PR_NewRWLock (PR_RWLOCK_RANK_NONE, "clcache_pl_lock");
+ return 0;
+}
+
+/*
+ * This is part of a callback function when changelog configuration
+ * is read or updated.
+ */
+void
+clcache_set_config ( CL5DBConfig *config )
+{
+ if ( config == NULL ) return;
+
+ PR_RWLock_Wlock ( _pool->pl_lock );
+
+ _pool->pl_buffer_cnt_max = config->maxChCacheEntries;
+
+ /*
+ * According to http://www.sleepycat.com/docs/api_c/dbc_get.html,
+ * data buffer should be a multiple of 1024 bytes in size
+ * for DB_MULTIPLE_KEY operation.
+ */
+ _pool->pl_buffer_default_pages = config->maxChCacheSize / DEFAULT_CLC_BUFFER_PAGE_SIZE + 1;
+ _pool->pl_buffer_default_pages = DEFAULT_CLC_BUFFER_PAGE_COUNT;
+ if ( _pool->pl_buffer_default_pages <= 0 ) {
+ _pool->pl_buffer_default_pages = DEFAULT_CLC_BUFFER_PAGE_COUNT;
+ }
+
+ PR_RWLock_Unlock ( _pool->pl_lock );
+}
+
+/*
+ * Gets the pointer to a thread dedicated buffer, or allocates
+ * a new buffer if there is no buffer allocated yet for this thread.
+ *
+ * This is called when a cl5replayiterator is created for
+ * a replication session.
+ */
+int
+clcache_get_buffer ( CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV *consumer_ruv, const RUV *local_ruv )
+{
+ int rc = 0;
+
+ if ( buf == NULL ) return CL5_BAD_DATA;
+
+ *buf = NULL;
+
+ if ( NULL != ( *buf = (CLC_Buffer*) get_thread_private_cache()) ) {
+ (*buf)->buf_state = CLC_STATE_READY;
+ (*buf)->buf_load_cnt = 0;
+ (*buf)->buf_record_cnt = 0;
+ (*buf)->buf_record_skipped = 0;
+ (*buf)->buf_cursor = NULL;
+ (*buf)->buf_num_cscbs = 0;
+ }
+ else {
+ *buf = clcache_new_buffer ( consumer_rid );
+ if ( *buf ) {
+ if ( 0 == clcache_enqueue_busy_list ( db, *buf ) ) {
+ set_thread_private_cache ( (void*) (*buf) );
+ }
+ else {
+ clcache_delete_buffer ( buf );
+ }
+ }
+ }
+
+ if ( NULL != *buf ) {
+ (*buf)->buf_consumer_ruv = consumer_ruv;
+ (*buf)->buf_local_ruv = local_ruv;
+ }
+ else {
+ slapi_log_error ( SLAPI_LOG_FATAL, get_thread_private_agmtname(),
+ "clcache_get_buffer: can't allocate new buffer\n" );
+ rc = ENOMEM;
+ }
+
+ return rc;
+}
+
+/*
+ * Returns a buffer back to the buffer pool.
+ */
+void
+clcache_return_buffer ( CLC_Buffer **buf )
+{
+ int i;
+
+ slapi_log_error ( SLAPI_LOG_REPL, (*buf)->buf_agmt_name,
+ "session end: state=%d load=%d sent=%d skipped=%d\n",
+ (*buf)->buf_state,
+ (*buf)->buf_load_cnt,
+ (*buf)->buf_record_cnt - (*buf)->buf_record_skipped,
+ (*buf)->buf_record_skipped );
+
+ for ( i = 0; i < (*buf)->buf_num_cscbs; i++ ) {
+ clcache_free_cscb ( &(*buf)->buf_cscbs[i] );
+ }
+ (*buf)->buf_num_cscbs = 0;
+
+ if ( (*buf)->buf_cursor ) {
+
+ (*buf)->buf_cursor->c_close ( (*buf)->buf_cursor );
+ (*buf)->buf_cursor = NULL;
+ }
+}
+
+/*
+ * Loads a buffer from DB.
+ *
+ * anchorcsn - passed in for the first load of a replication session;
+ * flag - DB_SET to load in the key CSN record.
+ * DB_NEXT to load in the records greater than key CSN.
+ * return - DB error code instead of cl5 one because of the
+ * historic reason.
+ */
+int
+clcache_load_buffer ( CLC_Buffer *buf, CSN *anchorcsn, int flag )
+{
+ int rc = 0;
+
+ clcache_refresh_local_maxcsns ( buf );
+
+ /* Set the loading key */
+ if ( anchorcsn ) {
+ clcache_refresh_consumer_maxcsns ( buf );
+ buf->buf_load_flag = DB_MULTIPLE_KEY;
+ csn_as_string ( anchorcsn, 0, (char*)buf->buf_key.data );
+ slapi_log_error ( SLAPI_LOG_REPL, buf->buf_agmt_name,
+ "session start: anchorcsn=%s\n", (char*)buf->buf_key.data );
+ }
+ else if ( csn_get_time(buf->buf_current_csn) == 0 ) {
+ /* time == 0 means this csn has never been set */
+ rc = DB_NOTFOUND;
+ }
+ else if ( clcache_adjust_anchorcsn ( buf ) != 0 ) {
+ rc = DB_NOTFOUND;
+ }
+ else {
+ csn_as_string ( buf->buf_current_csn, 0, (char*)buf->buf_key.data );
+ slapi_log_error ( SLAPI_LOG_REPL, buf->buf_agmt_name,
+ "load next: anchorcsn=%s\n", (char*)buf->buf_key.data );
+ }
+
+ if ( rc == 0 ) {
+
+ buf->buf_state = CLC_STATE_READY;
+ rc = clcache_load_buffer_bulk ( buf, flag );
+
+ /* Reset some flag variables */
+ if ( rc == 0 ) {
+ int i;
+ for ( i = 0; i < buf->buf_num_cscbs; i++ ) {
+ buf->buf_cscbs[i]->state = CLC_STATE_READY;
+ }
+ }
+ else if ( anchorcsn ) {
+ /* Report error only when the missing is persistent */
+ if ( buf->buf_missing_csn && csn_compare (buf->buf_missing_csn, anchorcsn) == 0 ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, buf->buf_agmt_name,
+ "Can't locate CSN %s in the changelog (DB rc=%d). The consumer may need to be reinitialized.\n",
+ (char*)buf->buf_key.data, rc );
+ }
+ else {
+ csn_dup_or_init_by_csn (&buf->buf_missing_csn, anchorcsn);
+ }
+ }
+ }
+ if ( rc != 0 ) {
+ slapi_log_error ( SLAPI_LOG_REPL, buf->buf_agmt_name,
+ "clcache_load_buffer: rc=%d\n", rc );
+ }
+
+ return rc;
+}
+
+static int
+clcache_load_buffer_bulk ( CLC_Buffer *buf, int flag )
+{
+ DB_TXN *txn = NULL;
+ DBC *cursor = NULL;
+ int rc;
+
+ /* txn control seems not improving anything so turn it off */
+ /*
+ if ( *(_pool->pl_dbenv) ) {
+ txn_begin( *(_pool->pl_dbenv), NULL, &txn, 0 );
+ }
+ */
+
+ PR_Lock ( buf->buf_busy_list->bl_lock );
+ if ( 0 == ( rc = clcache_open_cursor ( txn, buf, &cursor )) ) {
+
+ if ( flag == DB_NEXT ) {
+ /* For bulk read, position the cursor before read the next block */
+ rc = cursor->c_get ( cursor,
+ & buf->buf_key,
+ & buf->buf_data,
+ DB_SET );
+ }
+
+ /*
+ * Continue if the error is no-mem since we don't need to
+ * load in the key record anyway with DB_SET.
+ */
+ if ( 0 == rc || ENOMEM == rc )
+ rc = clcache_cursor_get ( cursor, buf, flag );
+
+ }
+
+ /*
+ * Don't keep a cursor open across the whole replication session.
+ * That had caused noticable DB resource contention.
+ */
+ if ( cursor ) {
+ cursor->c_close ( cursor );
+ }
+
+ if ( txn ) {
+ txn->commit ( txn, DB_TXN_NOSYNC );
+ }
+
+ PR_Unlock ( buf->buf_busy_list->bl_lock );
+
+ buf->buf_record_ptr = NULL;
+ if ( 0 == rc ) {
+ DB_MULTIPLE_INIT ( buf->buf_record_ptr, &buf->buf_data );
+ if ( NULL == buf->buf_record_ptr )
+ rc = DB_NOTFOUND;
+ else
+ buf->buf_load_cnt++;
+ }
+
+ return rc;
+}
+
+/*
+ * Gets the next change from the buffer.
+ * *key : output - key of the next change, or NULL if no more change
+ * *data: output - data of the next change, or NULL if no more change
+ */
+int
+clcache_get_next_change ( CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn )
+{
+ int skip = 1;
+ int rc = 0;
+
+ do {
+ *key = *data = NULL;
+ *keylen = *datalen = 0;
+
+ if ( buf->buf_record_ptr ) {
+ DB_MULTIPLE_KEY_NEXT ( buf->buf_record_ptr, &buf->buf_data,
+ *key, *keylen, *data, *datalen );
+ }
+
+ /*
+ * We're done with the current buffer. Now load the next chunk.
+ */
+ if ( NULL == *key && CLC_STATE_READY == buf->buf_state ) {
+ rc = clcache_load_buffer ( buf, NULL, DB_NEXT );
+ if ( 0 == rc && buf->buf_record_ptr ) {
+ DB_MULTIPLE_KEY_NEXT ( buf->buf_record_ptr, &buf->buf_data,
+ *key, *keylen, *data, *datalen );
+ }
+ }
+
+ /* Compare the new change to the local and remote RUVs */
+ if ( NULL != *key ) {
+ buf->buf_record_cnt++;
+ csn_init_by_string ( buf->buf_current_csn, (char*)*key );
+ skip = clcache_skip_change ( buf );
+ if (skip) buf->buf_record_skipped++;
+ }
+ }
+ while ( rc == 0 && *key && skip );
+
+ if ( NULL == *key ) {
+ *key = NULL;
+ *csn = NULL;
+ rc = DB_NOTFOUND;
+ }
+ else {
+ *csn = buf->buf_current_csn;
+ slapi_log_error ( SLAPI_LOG_REPL, buf->buf_agmt_name,
+ "load=%d rec=%d csn=%s\n",
+ buf->buf_load_cnt, buf->buf_record_cnt, (char*)*key );
+ }
+
+ return rc;
+}
+
+static void
+clcache_refresh_consumer_maxcsns ( CLC_Buffer *buf )
+{
+ int i;
+
+ for ( i = 0; i < buf->buf_num_cscbs; i++ ) {
+ ruv_get_largest_csn_for_replica (
+ buf->buf_consumer_ruv,
+ buf->buf_cscbs[i]->rid,
+ &buf->buf_cscbs[i]->consumer_maxcsn );
+ }
+}
+
+static int
+clcache_refresh_local_maxcsn ( const ruv_enum_data *rid_data, void *data )
+{
+ CLC_Buffer *buf = (CLC_Buffer*) data;
+ ReplicaId rid;
+ int rc = 0;
+ int i;
+
+ rid = csn_get_replicaid ( rid_data->csn );
+
+ /*
+ * No need to create cscb for consumer's RID.
+ * If RID==65535, the CSN is originated from a
+ * legacy consumer. In this case the supplier
+ * and the consumer may have the same RID.
+ */
+ if ( rid == buf->buf_consumer_rid && rid != MAX_REPLICA_ID )
+ return rc;
+
+ for ( i = 0; i < buf->buf_num_cscbs; i++ ) {
+ if ( buf->buf_cscbs[i]->rid == rid )
+ break;
+ }
+ if ( i >= buf->buf_num_cscbs ) {
+ buf->buf_cscbs[i] = clcache_new_cscb ();
+ if ( buf->buf_cscbs[i] == NULL ) {
+ return -1;
+ }
+ buf->buf_cscbs[i]->rid = rid;
+ buf->buf_num_cscbs++;
+ }
+
+ csn_dup_or_init_by_csn ( &buf->buf_cscbs[i]->local_maxcsn, rid_data->csn );
+
+ if ( buf->buf_cscbs[i]->consumer_maxcsn &&
+ csn_compare (buf->buf_cscbs[i]->consumer_maxcsn, rid_data->csn) >= 0 ) {
+ /* No change need to be sent for this RID */
+ buf->buf_cscbs[i]->state = CLC_STATE_UP_TO_DATE;
+ }
+
+ return rc;
+}
+
+static int
+clcache_refresh_local_maxcsns ( CLC_Buffer *buf )
+{
+ int i;
+
+ for ( i = 0; i < buf->buf_num_cscbs; i++ ) {
+ csn_dup_or_init_by_csn ( &buf->buf_cscbs[i]->prev_local_maxcsn,
+ buf->buf_cscbs[i]->local_maxcsn );
+ }
+ return ruv_enumerate_elements ( buf->buf_local_ruv, clcache_refresh_local_maxcsn, buf );
+}
+
+/*
+ * Algorithm:
+ *
+ * 1. Snapshot local RUVs;
+ * 2. Load buffer;
+ * 3. Send to the consumer only those CSNs that are covered
+ * by the RUVs snapshot taken in the first step;
+ * All CSNs that are covered by the RUVs snapshot taken in the
+ * first step are guaranteed in consecutive order for the respected
+ * RIDs because of the the CSN pending list control;
+ * A CSN that is not covered by the RUVs snapshot may be out of order
+ * since it is possible that a smaller CSN might not have committed
+ * yet by the time the buffer was loaded.
+ * 4. Determine anchorcsn for each RID:
+ *
+ * Case| Local vs. Buffer | New Local | Next
+ * | MaxCSN MaxCSN | MaxCSN | Anchor-CSN
+ * ----+-------------------+-----------+----------------
+ * 1 | Cl >= Cb | * | Cb
+ * 2 | Cl < Cb | Cl | Cb
+ * 3 | Cl < Cb | Cl2 | Cl
+ *
+ * 5. Determine anchorcsn for next load:
+ * Anchor-CSN = min { all Next-Anchor-CSN, Buffer-MaxCSN }
+ */
+static int
+clcache_adjust_anchorcsn ( CLC_Buffer *buf )
+{
+ PRBool hasChange = PR_FALSE;
+ struct csn_seq_ctrl_block *cscb;
+ int rc = 0;
+ int i;
+
+ if ( buf->buf_state == CLC_STATE_READY ) {
+ for ( i = 0; i < buf->buf_num_cscbs; i++ ) {
+ cscb = buf->buf_cscbs[i];
+
+ if ( cscb->state == CLC_STATE_UP_TO_DATE )
+ continue;
+
+ /*
+ * Case 3 unsafe ruv change: next buffer load should start
+ * from where the maxcsn in the old ruv was. Since each
+ * cscb has remembered the maxcsn sent to the consumer,
+ * CSNs that may be loaded again could easily be skipped.
+ */
+ if ( cscb->prev_local_maxcsn &&
+ csn_compare (cscb->prev_local_maxcsn, buf->buf_current_csn) < 0 &&
+ csn_compare (cscb->local_maxcsn, cscb->prev_local_maxcsn) != 0 ) {
+ hasChange = PR_TRUE;
+ cscb->state = CLC_STATE_READY;
+ csn_init_by_csn ( buf->buf_current_csn, cscb->prev_local_maxcsn );
+ csn_as_string ( cscb->prev_local_maxcsn, 0, (char*)buf->buf_key.data );
+ slapi_log_error ( SLAPI_LOG_REPL, buf->buf_agmt_name,
+ "adjust anchor csn upon %s\n",
+ ( cscb->state == CLC_STATE_CSN_GT_RUV ? "out of sequence csn" : "unsafe ruv change") );
+ continue;
+ }
+
+ /*
+ * check if there are still changes to send for this RID
+ * Assume we had compared the local maxcsn and the consumer
+ * max csn before this function was called and hence the
+ * cscb->state had been set accordingly.
+ */
+ if ( hasChange == PR_FALSE &&
+ csn_compare (cscb->local_maxcsn, buf->buf_current_csn) > 0 ) {
+ hasChange = PR_TRUE;
+ }
+ }
+ }
+
+ if ( !hasChange ) {
+ buf->buf_state = CLC_STATE_DONE;
+ }
+
+ return buf->buf_state;
+}
+
+static int
+clcache_skip_change ( CLC_Buffer *buf )
+{
+ struct csn_seq_ctrl_block *cscb = NULL;
+ ReplicaId rid;
+ int skip = 1;
+ int i;
+
+ do {
+
+ rid = csn_get_replicaid ( buf->buf_current_csn );
+
+ /*
+ * Skip CSN that is originated from the consumer.
+ * If RID==65535, the CSN is originated from a
+ * legacy consumer. In this case the supplier
+ * and the consumer may have the same RID.
+ */
+ if (rid == buf->buf_consumer_rid && rid != MAX_REPLICA_ID)
+ break;
+
+ /* Skip helper entry (ENTRY_COUNT, PURGE_RUV and so on) */
+ if ( cl5HelperEntry ( NULL, buf->buf_current_csn ) == PR_TRUE ) {
+ slapi_log_error ( SLAPI_LOG_REPL, buf->buf_agmt_name,
+ "Skip helper entry type=%d\n", csn_get_time( buf->buf_current_csn ));
+ break;
+ }
+
+ /* Find csn sequence control block for the current rid */
+ for (i = 0; i < buf->buf_num_cscbs && buf->buf_cscbs[i]->rid != rid; i++);
+
+ /* Skip CSN whose RID is unknown to the local RUV snapshot */
+ if ( i >= buf->buf_num_cscbs ) {
+ buf->buf_state = CLC_STATE_NEW_RID;
+ break;
+ }
+
+ cscb = buf->buf_cscbs[i];
+
+ /* Skip if the consumer is already up-to-date for the RID */
+ if ( cscb->state == CLC_STATE_UP_TO_DATE ) {
+ break;
+ }
+
+ /* Skip CSN whose preceedents are not covered by local RUV snapshot */
+ if ( cscb->state == CLC_STATE_CSN_GT_RUV ) {
+ break;
+ }
+
+ /* Skip CSNs already covered by consumer RUV */
+ if ( cscb->consumer_maxcsn &&
+ csn_compare ( buf->buf_current_csn, cscb->consumer_maxcsn ) <= 0 ) {
+ break;
+ }
+
+ /* Send CSNs that are covered by the local RUV snapshot */
+ if ( csn_compare ( buf->buf_current_csn, cscb->local_maxcsn ) <= 0 ) {
+ skip = 0;
+ csn_dup_or_init_by_csn ( &cscb->consumer_maxcsn, buf->buf_current_csn );
+ break;
+ }
+
+ /*
+ * Promote the local maxcsn to its next neighbor
+ * to keep the current session going. Skip if we
+ * are not sure if current_csn is the neighbor.
+ */
+ if ( csn_time_difference(buf->buf_current_csn, cscb->local_maxcsn) == 0 &&
+ (csn_get_seqnum(buf->buf_current_csn) ==
+ csn_get_seqnum(cscb->local_maxcsn) + 1) ) {
+ csn_init_by_csn ( cscb->local_maxcsn, buf->buf_current_csn );
+ csn_init_by_csn ( cscb->consumer_maxcsn, buf->buf_current_csn );
+ skip = 0;
+ break;
+ }
+
+ /* Skip CSNs not covered by local RUV snapshot */
+ cscb->state = CLC_STATE_CSN_GT_RUV;
+
+ } while (0);
+
+#ifdef DEBUG
+ if (skip && cscb) {
+ char consumer[24] = {'\0'};
+ char local[24] = {'\0'};
+ char current[24] = {'\0'};
+
+ if ( cscb->consumer_maxcsn )
+ csn_as_string ( cscb->consumer_maxcsn, PR_FALSE, consumer );
+ if ( cscb->local_maxcsn )
+ csn_as_string ( cscb->local_maxcsn, PR_FALSE, local );
+ csn_as_string ( buf->buf_current_csn, PR_FALSE, current );
+ slapi_log_error ( SLAPI_LOG_REPL, buf->buf_agmt_name,
+ "Skip %s consumer=%s local=%s\n", current, consumer, local );
+ }
+#endif
+
+ return skip;
+}
+
+static struct csn_seq_ctrl_block *
+clcache_new_cscb ()
+{
+ struct csn_seq_ctrl_block *cscb;
+
+ cscb = (struct csn_seq_ctrl_block *) slapi_ch_calloc ( 1, sizeof (struct csn_seq_ctrl_block) );
+ if (cscb == NULL) {
+ slapi_log_error ( SLAPI_LOG_FATAL, NULL, "clcache: malloc failure\n" );
+ }
+ return cscb;
+}
+
+static void
+clcache_free_cscb ( struct csn_seq_ctrl_block ** cscb )
+{
+ csn_free ( & (*cscb)->consumer_maxcsn );
+ csn_free ( & (*cscb)->local_maxcsn );
+ csn_free ( & (*cscb)->prev_local_maxcsn );
+ slapi_ch_free ( (void **) cscb );
+}
+
+/*
+ * Allocate and initialize a new buffer
+ * It is called when there is a request for a buffer while
+ * buffer free list is empty.
+ */
+static CLC_Buffer *
+clcache_new_buffer ( ReplicaId consumer_rid )
+{
+ CLC_Buffer *buf = NULL;
+ int page_count = 0;
+ int welldone = 0;
+ int rc = 0;
+
+ do {
+
+ buf = (CLC_Buffer*) slapi_ch_calloc (1, sizeof(CLC_Buffer));
+ if ( NULL == buf )
+ break;
+
+ buf->buf_key.flags = DB_DBT_USERMEM;
+ buf->buf_key.ulen = CSN_STRSIZE + 1;
+ buf->buf_key.size = CSN_STRSIZE;
+ buf->buf_key.data = slapi_ch_calloc( 1, buf->buf_key.ulen );
+ if ( NULL == buf->buf_key.data )
+ break;
+
+ buf->buf_data.flags = DB_DBT_USERMEM;
+ buf->buf_data.ulen = _pool->pl_buffer_default_pages * DEFAULT_CLC_BUFFER_PAGE_SIZE;
+ buf->buf_data.data = slapi_ch_malloc( buf->buf_data.ulen );
+ if ( NULL == buf->buf_data.data )
+ break;
+
+ if ( NULL == ( buf->buf_current_csn = csn_new()) )
+ break;
+
+ buf->buf_state = CLC_STATE_READY;
+ buf->buf_agmt_name = get_thread_private_agmtname();
+ buf->buf_consumer_rid = consumer_rid;
+ buf->buf_num_cscbs = 0;
+
+ welldone = 1;
+
+ } while (0);
+
+ if ( !welldone ) {
+ clcache_delete_buffer ( &buf );
+ }
+
+ return buf;
+}
+
+/*
+ * Deallocates a buffer.
+ * It is called when a buffer is returned to the buffer pool
+ * and the pool size is over the limit.
+ */
+static void
+clcache_delete_buffer ( CLC_Buffer **buf )
+{
+ if ( buf && *buf ) {
+ slapi_ch_free (&( (*buf)->buf_key.data ));
+ slapi_ch_free (&( (*buf)->buf_data.data ));
+ csn_free (&( (*buf)->buf_current_csn ));
+ csn_free (&( (*buf)->buf_missing_csn ));
+ slapi_ch_free ( (void **) buf );
+ }
+}
+
+static CLC_Busy_List *
+clcache_new_busy_list ()
+{
+ CLC_Busy_List *bl;
+ int welldone = 0;
+
+ do {
+ if ( NULL == (bl = ( CLC_Busy_List* ) slapi_ch_calloc (1, sizeof(CLC_Busy_List)) ))
+ break;
+
+ if ( NULL == (bl->bl_lock = PR_NewLock ()) )
+ break;
+
+ /*
+ if ( NULL == (bl->bl_max_csn = csn_new ()) )
+ break;
+ */
+
+ welldone = 1;
+ }
+ while (0);
+
+ if ( !welldone ) {
+ clcache_delete_busy_list ( &bl );
+ }
+
+ return bl;
+}
+
+static void
+clcache_delete_busy_list ( CLC_Busy_List **bl )
+{
+ if ( bl && *bl ) {
+ if ( (*bl)->bl_lock ) {
+ PR_DestroyLock ( (*bl)->bl_lock );
+ }
+ /* csn_free (&( (*bl)->bl_max_csn )); */
+ slapi_ch_free ( (void **) bl );
+ }
+}
+
+static int
+clcache_enqueue_busy_list ( DB *db, CLC_Buffer *buf )
+{
+ CLC_Busy_List *bl;
+ int rc = 0;
+
+ PR_RWLock_Rlock ( _pool->pl_lock );
+ for ( bl = _pool->pl_busy_lists; bl && bl->bl_db != db; bl = bl->bl_next );
+ PR_RWLock_Unlock ( _pool->pl_lock );
+
+ if ( NULL == bl ) {
+ if ( NULL == ( bl = clcache_new_busy_list ()) ) {
+ rc = ENOMEM;
+ }
+ else {
+ PR_RWLock_Wlock ( _pool->pl_lock );
+ bl->bl_db = db;
+ bl->bl_next = _pool->pl_busy_lists;
+ _pool->pl_busy_lists = bl;
+ PR_RWLock_Unlock ( _pool->pl_lock );
+ }
+ }
+
+ if ( NULL != bl ) {
+ PR_Lock ( bl->bl_lock );
+ buf->buf_busy_list = bl;
+ buf->buf_next = bl->bl_buffers;
+ bl->bl_buffers = buf;
+ PR_Unlock ( bl->bl_lock );
+ }
+
+ return rc;
+}
+
+static int
+clcache_open_cursor ( DB_TXN *txn, CLC_Buffer *buf, DBC **cursor )
+{
+ int rc;
+
+ rc = buf->buf_busy_list->bl_db->cursor ( buf->buf_busy_list->bl_db, txn, cursor, 0 );
+ if ( rc != 0 ) {
+ slapi_log_error ( SLAPI_LOG_FATAL, get_thread_private_agmtname(),
+ "clcache: failed to open cursor; db error - %d %s\n",
+ rc, db_strerror(rc));
+ }
+
+ return rc;
+}
+
+static int
+clcache_cursor_get ( DBC *cursor, CLC_Buffer *buf, int flag )
+{
+ int rc;
+
+ rc = cursor->c_get ( cursor,
+ & buf->buf_key,
+ & buf->buf_data,
+ buf->buf_load_flag | flag );
+ if ( ENOMEM == rc ) {
+ /*
+ * The record takes more space than the current size of the
+ * buffer. Fortunately, buf->buf_data.size has been set by
+ * c_get() to the actual data size needed. So we can
+ * reallocate the data buffer and try to read again.
+ */
+ buf->buf_data.ulen = ( buf->buf_data.size / DEFAULT_CLC_BUFFER_PAGE_SIZE + 1 ) * DEFAULT_CLC_BUFFER_PAGE_SIZE;
+ buf->buf_data.data = slapi_ch_realloc ( buf->buf_data.data, buf->buf_data.ulen );
+ if ( buf->buf_data.data != NULL ) {
+ rc = cursor->c_get ( cursor,
+ &( buf->buf_key ),
+ &( buf->buf_data ),
+ buf->buf_load_flag | flag );
+ slapi_log_error ( SLAPI_LOG_REPL, buf->buf_agmt_name,
+ "clcache: (%d | %d) %s reallocated and retry returns %d\n", buf->buf_load_flag, flag, buf->buf_key.data, rc );
+ }
+ }
+
+ switch ( rc ) {
+ case EINVAL:
+ slapi_log_error ( SLAPI_LOG_FATAL, buf->buf_agmt_name,
+ "clcache_cursor_get: invalid parameter\n" );
+ break;
+
+ case ENOMEM:
+ slapi_log_error ( SLAPI_LOG_FATAL, buf->buf_agmt_name,
+ "clcache_cursor_get: cann't allocate %u bytes\n", buf->buf_data.ulen );
+ break;
+
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+static void
+csn_dup_or_init_by_csn ( CSN **csn1, CSN *csn2 )
+{
+ if ( *csn1 == NULL )
+ *csn1 = csn_new();
+ csn_init_by_csn ( *csn1, csn2 );
+}
diff --git a/ldap/servers/plugins/replication/cl5_clcache.h b/ldap/servers/plugins/replication/cl5_clcache.h
new file mode 100644
index 00000000..93024d1e
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl5_clcache.h
@@ -0,0 +1,22 @@
+#ifndef CL5_CLCACHE_H
+#define CL5_CLCACHE_H
+
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "db.h"
+#include "slapi-private.h"
+
+typedef struct clc_buffer CLC_Buffer;
+
+int clcache_init ( DB_ENV **dbenv );
+void clcache_set_config ( CL5DBConfig * config );
+int clcache_get_buffer ( CLC_Buffer **buf, DB *db, ReplicaId consumer_rid, const RUV *consumer_ruv, const RUV *local_ruv );
+int clcache_load_buffer ( CLC_Buffer *buf, CSN *startCSN, int flag );
+void clcache_return_buffer ( CLC_Buffer **buf );
+int clcache_get_next_change ( CLC_Buffer *buf, void **key, size_t *keylen, void **data, size_t *datalen, CSN **csn );
+
+#endif
diff --git a/ldap/servers/plugins/replication/cl5_config.c b/ldap/servers/plugins/replication/cl5_config.c
new file mode 100644
index 00000000..58c79dc1
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl5_config.c
@@ -0,0 +1,868 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cl5_config.c - functions to process changelog configuration
+ */
+
+#include <string.h>
+#include <prio.h>
+#include "repl5.h"
+#include "cl5.h"
+#include "cl5_clcache.h" /* To configure the Changelog Cache */
+#include "intrinsics.h" /* JCMREPL - Is this bad? */
+#ifdef TEST_CL5
+#include "cl5_test.h"
+#endif
+
+#define CONFIG_BASE "cn=changelog5,cn=config" /*"cn=changelog,cn=supplier,cn=replication5.0,cn=replication,cn=config"*/
+#define CONFIG_FILTER "(objectclass=*)"
+
+static PRRWLock *s_configLock; /* guarantees that only on thread at a time
+ modifies changelog configuration */
+
+/* Forward Declartions */
+static int changelog5_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int changelog5_config_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int changelog5_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+
+static void changelog5_extract_config(Slapi_Entry* entry, changelog5Config *config);
+static changelog5Config * changelog5_dup_config(changelog5Config *config);
+static void replace_bslash (char *dir);
+static int notify_replica (Replica *r, void *arg);
+static int _is_absolutepath (char *dir);
+
+int changelog5_config_init()
+{
+ /* The FE DSE *must* be initialised before we get here */
+
+ /* create the configuration lock */
+ s_configLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "config_lock");
+ if (s_configLock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_init: failed to create configurationlock; "
+ "NSPR error - %d\n",PR_GetError ());
+ return 1;
+ }
+
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
+ CONFIG_FILTER, changelog5_config_add, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
+ CONFIG_FILTER, changelog5_config_modify, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
+ CONFIG_FILTER, dont_allow_that, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
+ CONFIG_FILTER, changelog5_config_delete, NULL);
+
+ return 0;
+}
+
+void changelog5_config_cleanup()
+{
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
+ CONFIG_FILTER, changelog5_config_add);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
+ CONFIG_FILTER, changelog5_config_modify);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
+ CONFIG_FILTER, dont_allow_that);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_BASE,
+ CONFIG_FILTER, changelog5_config_delete);
+
+ if (s_configLock)
+ {
+ PR_DestroyRWLock (s_configLock);
+ s_configLock = NULL;
+ }
+}
+
+int changelog5_read_config (changelog5Config *config)
+{
+ int rc = LDAP_SUCCESS;
+ Slapi_PBlock *pb;
+
+ pb = slapi_pblock_new ();
+ slapi_search_internal_set_pb (pb, CONFIG_BASE, LDAP_SCOPE_BASE, CONFIG_FILTER, NULL, 0, NULL,
+ NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_search_internal_pb (pb);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
+ if ( LDAP_SUCCESS == rc )
+ {
+ Slapi_Entry **entries = NULL;
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries );
+ if ( NULL != entries && NULL != entries[0])
+ {
+ /* Extract the config info from the changelog entry */
+ changelog5_extract_config(entries[0], config);
+ }
+ }
+ else
+ {
+ memset (config, 0, sizeof (*config));
+ rc = LDAP_SUCCESS;
+ }
+
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+
+ return rc;
+}
+
+void changelog5_config_done (changelog5Config *config)
+{
+ if (config) {
+ /* slapi_ch_free_string accepts NULL pointer */
+ slapi_ch_free_string (&config->maxAge);
+ slapi_ch_free_string (&config->dir);
+ }
+}
+
+void changelog5_config_free (changelog5Config **config)
+{
+ changelog5_config_done(*config);
+ slapi_ch_free((void **)config);
+}
+
+static int
+changelog5_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
+ int *returncode, char *returntext, void *arg)
+{
+ int rc;
+ changelog5Config config;
+
+ *returncode = LDAP_SUCCESS;
+
+ PR_RWLock_Wlock (s_configLock);
+
+ /* we already have a configured changelog - don't need to do anything
+ since add operation will fail */
+ if (cl5GetState () == CL5_STATE_OPEN)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ strcpy (returntext, "attempt to add changelog when it already exists");
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_add: changelog already exist; "
+ "request ignored\n");
+ goto done;
+ }
+
+ changelog5_extract_config(e, &config);
+ if (config.dir == NULL)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ sprintf (returntext, "NULL changelog directory");
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_add: NULL changelog directory\n");
+ goto done;
+ }
+
+ /* start the changelog */
+ rc = cl5Open (config.dir, &config.dbconfig);
+ if (rc != CL5_SUCCESS)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ sprintf (returntext, "failed to start changelog; error - %d", rc);
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_add: failed to start changelog\n");
+ goto done;
+ }
+
+ /* set trimming parameters */
+ rc = cl5ConfigTrimming (config.maxEntries, config.maxAge);
+ if (rc != CL5_SUCCESS)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ sprintf (returntext, "failed to configure changelog trimming; error - %d", rc);
+ }
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_add: failed to configure changelog trimming\n");
+ goto done;
+ }
+
+ /* notify all the replicas that the changelog is configured
+ so that the can log dummy changes if necessary. */
+ replica_enumerate_replicas (notify_replica, NULL);
+
+#ifdef TEST_CL5
+ testChangelog (TEST_ITERATION);
+#endif
+
+done:;
+ PR_RWLock_Unlock (s_configLock);
+ changelog5_config_done (&config);
+ if (*returncode == LDAP_SUCCESS)
+ {
+ if (returntext)
+ {
+ returntext[0] = '\0';
+ }
+
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+static int
+changelog5_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg)
+{
+ int rc= 0;
+ LDAPMod **mods;
+ int i;
+ changelog5Config config;
+ changelog5Config * originalConfig = NULL;
+ char *currentDir = NULL;
+
+ *returncode = LDAP_SUCCESS;
+
+ /* changelog must be open before its parameters can be modified */
+ if (cl5GetState() != CL5_STATE_OPEN)
+ {
+ if (returntext)
+ {
+ strcpy (returntext, "changelog is not configured");
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_modify: changelog is not configured\n");
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ PR_RWLock_Wlock (s_configLock);
+
+ /* changelog must be open before its parameters can be modified */
+ if (cl5GetState() != CL5_STATE_OPEN)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ strcpy (returntext, "changelog is not configured");
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_modify: changelog is not configured\n");
+ goto done;
+ }
+
+ /*
+ * Extract all the original configuration: This is needed to ensure that the configuration
+ * is trully reloaded. This was not needed before 091401 because the changelog configuration
+ * was always hardcoded (NULL was being passed to cl5Open). Now we need to ensure we pass to
+ * cl5Open the proper configuration...
+ */
+ changelog5_extract_config(e, &config);
+ originalConfig = changelog5_dup_config(&config);
+
+ /* Reset all the attributes that have been potentially modified by the current MODIFY operation */
+ slapi_ch_free_string(&config.dir);
+ config.dir = NULL;
+ config.maxEntries = CL5_NUM_IGNORE;
+ slapi_ch_free_string(&config.maxAge);
+ config.maxAge = slapi_ch_strdup(CL5_STR_IGNORE);
+ config.dbconfig.maxChCacheEntries = 0;
+ config.dbconfig.maxChCacheSize = CL5_NUM_IGNORE;
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ for (i = 0; mods[i] != NULL; i++)
+ {
+ if (mods[i]->mod_op & LDAP_MOD_DELETE)
+ {
+ /* We don't support deleting changelog attributes */
+ }
+ else
+ {
+ int j;
+ for (j = 0; ((mods[i]->mod_values[j]) && (LDAP_SUCCESS == rc)); j++)
+ {
+ char *config_attr, *config_attr_value;
+ config_attr = (char *) mods[i]->mod_type;
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+
+#define ATTR_MODIFIERSNAME "modifiersname"
+#define ATTR_MODIFYTIMESTAMP "modifytimestamp"
+
+ if ( strcasecmp ( config_attr, ATTR_MODIFIERSNAME ) == 0 ) {
+ continue;
+ }
+ if ( strcasecmp ( config_attr, ATTR_MODIFYTIMESTAMP ) == 0 ) {
+ continue;
+ }
+ /* replace existing value */
+ if ( strcasecmp (config_attr, CONFIG_CHANGELOG_DIR_ATTRIBUTE ) == 0 )
+ {
+ if (config_attr_value && config_attr_value[0] != '\0')
+ {
+ slapi_ch_free_string(&config.dir);
+ config.dir = slapi_ch_strdup(config_attr_value);
+ replace_bslash (config.dir);
+ }
+ else
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ strcpy (returntext, "null changelog directory");
+ }
+ goto done;
+ }
+ }
+ else if ( strcasecmp ( config_attr, CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE ) == 0 )
+ {
+ if (config_attr_value && config_attr_value[0] != '\0')
+ {
+ config.maxEntries = atoi (config_attr_value);
+ }
+ else
+ {
+ config.maxEntries = 0;
+ }
+ }
+ else if ( strcasecmp ( config_attr, CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE ) == 0 )
+ {
+ slapi_ch_free_string(&config.maxAge);
+ config.maxAge = slapi_ch_strdup(config_attr_value);
+ }
+ else if ( strcasecmp ( config_attr, CONFIG_CHANGELOG_CACHESIZE ) == 0 )
+ { /* The Changelog Cache Size parameters can be modified online without a need for restart */
+ if (config_attr_value && config_attr_value[0] != '\0')
+ {
+ config.dbconfig.maxChCacheEntries = atoi (config_attr_value);
+ }
+ else
+ {
+ config.dbconfig.maxChCacheEntries = 0;
+ }
+ }
+ else if ( strcasecmp ( config_attr, CONFIG_CHANGELOG_CACHEMEMSIZE ) == 0 )
+ { /* The Changelog Cache Size parameters can be modified online without a need for restart */
+ if (config_attr_value && config_attr_value[0] != '\0')
+ {
+ config.dbconfig.maxChCacheSize = atoi (config_attr_value);
+ }
+ else
+ {
+ config.dbconfig.maxChCacheSize = 0;
+ }
+ }
+ else
+ {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ if (returntext)
+ {
+ sprintf (returntext, "Unwilling to apply %s mods while the server is running", config_attr);
+ }
+ goto done;
+ }
+ }
+ }
+ }
+ /* Undo the reset above for all the modifiable attributes that were not modified
+ * except config.dir */
+ if (config.maxEntries == CL5_NUM_IGNORE)
+ config.maxEntries = originalConfig->maxEntries;
+ if (strcmp (config.maxAge, CL5_STR_IGNORE) == 0) {
+ slapi_ch_free_string(&config.maxAge);
+ if (originalConfig->maxAge)
+ config.maxAge = slapi_ch_strdup(originalConfig->maxAge);
+ }
+ if (config.dbconfig.maxChCacheEntries == 0)
+ config.dbconfig.maxChCacheEntries = originalConfig->dbconfig.maxChCacheEntries;
+ if (config.dbconfig.maxChCacheSize == CL5_NUM_IGNORE)
+ config.dbconfig.maxChCacheSize = originalConfig->dbconfig.maxChCacheSize;
+
+
+ /* attempt to change chagelog dir */
+ if (config.dir)
+ {
+ currentDir = cl5GetDir ();
+ if (currentDir == NULL)
+ {
+ /* something is wrong: we should never be here */
+ *returncode = 1;
+ if (returntext)
+ {
+ strcpy (returntext, "internal failure");
+ }
+
+ goto done;
+ }
+
+#ifdef _WIN32
+ if (strcasecmp (currentDir, config.dir) != 0)
+#else /* On Unix, path are case sensitive */
+ if (strcmp (currentDir, config.dir) != 0)
+#endif
+ {
+ if (!_is_absolutepath(config.dir) || (CL5_SUCCESS != cl5CreateDirIfNeeded(config.dir)))
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ strcpy (returntext, "invalid changelog directory or insufficient access");
+ }
+
+ goto done;
+ }
+
+ /* changelog directory changed - need to remove the
+ previous changelog and create new one */
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name_cl,
+ "changelog5_config_modify: changelog directory changed; "
+ "old dir - %s, new dir - %s; recreating changelog.\n",
+ currentDir, config.dir);
+
+ /* this call will block until all threads using changelog
+ release changelog by calling cl5RemoveThread () */
+ rc = cl5Close ();
+ if (rc != CL5_SUCCESS)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ sprintf (returntext, "failed to close changelog; error - %d", rc);
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_modify: failed to close changelog\n");
+ goto done;
+ }
+
+ rc = cl5Delete (currentDir);
+ if (rc != CL5_SUCCESS)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ sprintf (returntext, "failed to remove changelog; error - %d", rc);
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_modify: failed to remove changelog\n");
+ goto done;
+ }
+
+ rc = cl5Open (config.dir, &config.dbconfig);
+ if (rc != CL5_SUCCESS)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ sprintf (returntext, "failed to restart changelog; error - %d", rc);
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_modify: failed to restart changelog\n");
+ /* before finishing, let's try to do some error recovery */
+ if (CL5_SUCCESS != cl5Open(currentDir, &config.dbconfig)) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_modify: failed to restore previous changelog\n");
+ }
+ goto done;
+ }
+ }
+ }
+
+ /* one of the changelog parameters is modified */
+ if (config.maxEntries != CL5_NUM_IGNORE ||
+ strcmp (config.maxAge, CL5_STR_IGNORE) != 0)
+ {
+ rc = cl5ConfigTrimming (config.maxEntries, config.maxAge);
+ if (rc != CL5_SUCCESS)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ sprintf (returntext, "failed to configure changelog trimming; error - %d", rc);
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_modify: failed to configure changelog trimming\n");
+ goto done;
+ }
+ }
+
+ if (config.dbconfig.maxChCacheEntries != 0 || config.dbconfig.maxChCacheSize != CL5_NUM_IGNORE)
+ clcache_set_config(&config.dbconfig);
+
+done:;
+ PR_RWLock_Unlock (s_configLock);
+
+ changelog5_config_done (&config);
+ changelog5_config_free (&originalConfig);
+
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void**)&currentDir);
+
+ if (*returncode == LDAP_SUCCESS)
+ {
+
+ if (returntext)
+ {
+ returntext[0] = '\0';
+ }
+
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+static int
+changelog5_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
+ int *returncode, char *returntext, void *arg)
+{
+ int rc;
+ char *currentDir = NULL;
+ *returncode = LDAP_SUCCESS;
+
+ /* changelog must be open before it can be deleted */
+ if (cl5GetState () != CL5_STATE_OPEN)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ strcpy (returntext, "changelog is not configured");
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_delete: chagelog is not configured\n");
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ PR_RWLock_Wlock (s_configLock);
+
+ /* changelog must be open before it can be deleted */
+ if (cl5GetState () != CL5_STATE_OPEN)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ strcpy (returntext, "changelog is not configured");
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_delete: chagelog is not configured\n");
+ goto done;
+ }
+
+ currentDir = cl5GetDir ();
+
+ if (currentDir == NULL)
+ {
+ /* something is wrong: we should never be here */
+ *returncode = 1;
+ if (returntext)
+ {
+ strcpy (returntext, "internal failure");
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_delete: NULL directory\n");
+ goto done;
+ }
+
+ /* this call will block until all threads using changelog
+ release changelog by calling cl5RemoveThread () */
+ rc = cl5Close ();
+ if (rc != CL5_SUCCESS)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ sprintf (returntext, "failed to close changelog; error - %d", rc);
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_delete: failed to close changelog\n");
+ goto done;
+ }
+
+ rc = cl5Delete (currentDir);
+ if (rc != CL5_SUCCESS)
+ {
+ *returncode = 1;
+ if (returntext)
+ {
+ sprintf (returntext, "failed to remove changelog; error - %d", rc);
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_config_delete: failed to remove changelog\n");
+ goto done;
+ }
+
+done:;
+ PR_RWLock_Unlock (s_configLock);
+
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void**)&currentDir);
+
+ if (*returncode == LDAP_SUCCESS)
+ {
+ if (returntext)
+ {
+ returntext[0] = '\0';
+ }
+
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+static int dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg)
+{
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+static changelog5Config * changelog5_dup_config(changelog5Config *config)
+{
+ changelog5Config *dup = (changelog5Config *) slapi_ch_calloc(1, sizeof(changelog5Config));
+
+ if (config->dir)
+ dup->dir = slapi_ch_strdup(config->dir);
+ if (config->maxAge)
+ dup->maxAge = slapi_ch_strdup(config->maxAge);
+
+ dup->maxEntries = config->maxEntries;
+
+ /*memcpy((void *) &dup->dbconfig, (const void *) &config->dbconfig, sizeof(CL5DBConfig));*/
+ dup->dbconfig.cacheSize = config->dbconfig.cacheSize;
+ dup->dbconfig.durableTrans = config->dbconfig.durableTrans;
+ dup->dbconfig.checkpointInterval = config->dbconfig.checkpointInterval;
+ dup->dbconfig.circularLogging = config->dbconfig.circularLogging;
+ dup->dbconfig.pageSize = config->dbconfig.pageSize;
+ dup->dbconfig.logfileSize = config->dbconfig.logfileSize;
+ dup->dbconfig.maxTxnSize = config->dbconfig.maxTxnSize;
+ dup->dbconfig.fileMode = config->dbconfig.fileMode;
+ dup->dbconfig.verbose = config->dbconfig.verbose;
+ dup->dbconfig.debug = config->dbconfig.debug;
+ dup->dbconfig.tricklePercentage = config->dbconfig.tricklePercentage;
+ dup->dbconfig.spinCount = config->dbconfig.spinCount;
+ dup->dbconfig.maxChCacheEntries = config->dbconfig.maxChCacheEntries;
+ dup->dbconfig.maxChCacheSize = config->dbconfig.maxChCacheSize;
+ dup->dbconfig.nb_lock_config = config->dbconfig.nb_lock_config;
+
+ return dup;
+}
+
+
+/*
+ * Given the changelog configuration entry, extract the configuration directives.
+ */
+static void changelog5_extract_config(Slapi_Entry* entry, changelog5Config *config)
+{
+ char *arg;
+
+ memset (config, 0, sizeof (*config));
+ config->dir = slapi_entry_attr_get_charptr(entry,CONFIG_CHANGELOG_DIR_ATTRIBUTE);
+ replace_bslash (config->dir);
+
+ arg= slapi_entry_attr_get_charptr(entry,CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE);
+ if (arg)
+ {
+ config->maxEntries = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+
+ config->maxAge = slapi_entry_attr_get_charptr(entry,CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE);
+
+ /*
+ * Read the Changelog Internal Configuration Parameters for the Changelog DB
+ * (db cache size, db settings...)
+ */
+
+ /* Set configuration default values first... */
+ config->dbconfig.cacheSize = CL5_DEFAULT_CONFIG_DB_DBCACHESIZE;
+ config->dbconfig.durableTrans = CL5_DEFAULT_CONFIG_DB_DURABLE_TRANSACTIONS;
+ config->dbconfig.checkpointInterval = CL5_DEFAULT_CONFIG_DB_CHECKPOINT_INTERVAL;
+ config->dbconfig.circularLogging = CL5_DEFAULT_CONFIG_DB_CIRCULAR_LOGGING;
+ config->dbconfig.pageSize = CL5_DEFAULT_CONFIG_DB_PAGE_SIZE;
+ config->dbconfig.logfileSize = CL5_DEFAULT_CONFIG_DB_LOGFILE_SIZE;
+ config->dbconfig.maxTxnSize = CL5_DEFAULT_CONFIG_DB_TXN_MAX;
+ config->dbconfig.verbose = CL5_DEFAULT_CONFIG_DB_VERBOSE;
+ config->dbconfig.debug = CL5_DEFAULT_CONFIG_DB_DEBUG;
+ config->dbconfig.tricklePercentage = CL5_DEFAULT_CONFIG_DB_TRICKLE_PERCENTAGE;
+ config->dbconfig.spinCount = CL5_DEFAULT_CONFIG_DB_SPINCOUNT;
+ config->dbconfig.nb_lock_config = CL5_DEFAULT_CONFIG_NB_LOCK;
+
+ /* Now read from the entry to override default values if needed */
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_DBCACHESIZE);
+ if (arg)
+ {
+ size_t theSize = atoi (arg);
+ if (theSize > CL5_MIN_DB_DBCACHESIZE)
+ config->dbconfig.cacheSize = theSize;
+ else {
+ config->dbconfig.cacheSize = CL5_MIN_DB_DBCACHESIZE;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Warning: Changelog dbcache size too small. "
+ "Increasing the Memory Size to %d bytes\n",
+ CL5_MIN_DB_DBCACHESIZE);
+ }
+ slapi_ch_free_string(&arg);
+ }
+
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_DURABLE_TRANSACTIONS);
+ if (arg)
+ {
+ config->dbconfig.durableTrans = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_CHECKPOINT_INTERVAL);
+ if (arg)
+ {
+ config->dbconfig.checkpointInterval = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_CIRCULAR_LOGGING);
+ if (arg)
+ {
+ config->dbconfig.circularLogging = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_PAGE_SIZE);
+ if (arg)
+ {
+ config->dbconfig.pageSize = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_LOGFILE_SIZE);
+ if (arg)
+ {
+ config->dbconfig.logfileSize = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_MAXTXN_SIZE);
+ if (arg)
+ {
+ config->dbconfig.maxTxnSize = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_VERBOSE);
+ if (arg)
+ {
+ config->dbconfig.verbose = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_DEBUG);
+ if (arg)
+ {
+ config->dbconfig.debug = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_TRICKLE_PERCENTAGE);
+ if (arg)
+ {
+ config->dbconfig.tricklePercentage = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_DB_SPINCOUNT);
+ if (arg)
+ {
+ config->dbconfig.spinCount = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_MAX_CONCURRENT_WRITES);
+ if (arg)
+ {
+ config->dbconfig.maxConcurrentWrites = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ if ( config->dbconfig.maxConcurrentWrites <= 0 )
+ {
+ config->dbconfig.maxConcurrentWrites = CL5_DEFAULT_CONFIG_MAX_CONCURRENT_WRITES;
+ }
+
+ /*
+ * Read the Changelog Internal Configuration Parameters for the Changelog Cache
+ */
+
+ /* Set configuration default values first... */
+ config->dbconfig.maxChCacheEntries = CL5_DEFAULT_CONFIG_CACHESIZE;
+ config->dbconfig.maxChCacheSize = CL5_DEFAULT_CONFIG_CACHEMEMSIZE;
+
+ /* Now read from the entry to override default values if needed */
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_CACHESIZE);
+ if (arg)
+ {
+ config->dbconfig.maxChCacheEntries = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg= slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_CACHEMEMSIZE);
+ if (arg)
+ {
+ config->dbconfig.maxChCacheSize = atoi (arg);
+ slapi_ch_free_string(&arg);
+ }
+ arg = slapi_entry_attr_get_charptr(entry, CONFIG_CHANGELOG_NB_LOCK);
+ if (arg)
+ {
+ size_t theSize = atoi(arg);
+ if (theSize < CL5_MIN_NB_LOCK)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Warning: Changelog %s value is too low (%d). Set to minimal value instead (%d)\n",
+ CONFIG_CHANGELOG_NB_LOCK, theSize, CL5_MIN_NB_LOCK);
+ config->dbconfig.nb_lock_config = CL5_MIN_NB_LOCK;
+ }
+ else
+ {
+ config->dbconfig.nb_lock_config = theSize;
+ }
+ slapi_ch_free_string(&arg);
+ }
+
+ clcache_set_config(&config->dbconfig);
+}
+
+static void replace_bslash (char *dir)
+{
+ char *bslash;
+
+ if (dir == NULL)
+ return;
+
+ bslash = strchr (dir, '\\');
+ while (bslash)
+ {
+ *bslash = '/';
+ bslash = strchr (bslash, '\\');
+ }
+}
+
+static int notify_replica (Replica *r, void *arg)
+{
+ return replica_log_ruv_elements (r);
+}
+
+static int _is_absolutepath (char * dir)
+{
+ if (dir[0] == '/')
+ return 1;
+#if defined(_WIN32)
+ if (dir[2] == '/' && dir[1] == ':')
+ return 1;
+#endif
+ return 0;
+}
diff --git a/ldap/servers/plugins/replication/cl5_init.c b/ldap/servers/plugins/replication/cl5_init.c
new file mode 100644
index 00000000..435299c0
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl5_init.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 **/
+
+/* cl5_init.c - implments initialization/cleanup functions for
+ 4.0 style changelog
+ */
+
+#include "slapi-plugin.h"
+#include "cl5.h"
+#include "repl5.h"
+
+/* initializes changelog*/
+int changelog5_init()
+{
+ int rc;
+ changelog5Config config;
+
+ rc = cl5Init ();
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_init: failed to initialize changelog\n");
+ return 1;
+ }
+
+ /* read changelog configuration */
+ changelog5_config_init ();
+ changelog5_read_config (&config);
+
+ if (config.dir == NULL)
+ {
+ /* changelog is not configured - bail out */
+ rc = 0; /* OK */
+ goto done;
+ }
+
+ /* start changelog */
+ rc = cl5Open (config.dir, &config.dbconfig);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_init: failed to start changelog at %s\n",
+ config.dir);
+ rc = 1;
+ goto done;
+ }
+
+ /* set trimming parameters */
+ rc = cl5ConfigTrimming (config.maxEntries, config.maxAge);
+ if (rc != CL5_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "changelog5_init: failed to configure changelog trimming\n");
+ rc = 1;
+ goto done;
+ }
+
+ rc = 0;
+
+done:
+ changelog5_config_done (&config);
+ return rc;
+}
+
+/* cleanups changelog data */
+void changelog5_cleanup()
+{
+ /* close changelog */
+ cl5Close ();
+ cl5Cleanup ();
+
+ /* cleanup config */
+ changelog5_config_cleanup ();
+}
diff --git a/ldap/servers/plugins/replication/cl5_test.c b/ldap/servers/plugins/replication/cl5_test.c
new file mode 100644
index 00000000..b64a60f5
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl5_test.c
@@ -0,0 +1,830 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cl5_test.c - changelog test cases */
+#include "cl5_test.h"
+#include "slapi-plugin.h"
+#include "cl5.h"
+
+#define REPLICA_ROOT "dc=example,dc=com" /* replica root */
+#define OP_COUNT 4 /* number of ops generated at a time */
+#define MOD_COUNT 5
+#define VALUE_COUNT 5
+#define ENTRY_COUNT 50
+#define CL_DN "cn=changelog5,cn=config"
+#define INSTANCE_ATTR "nsslapd-instancedir"
+#define REPLICA_OC "nsds5Replica"
+#define REPLICA_RDN "cn=replica"
+
+static void testBasic ();
+static void testBackupRestore ();
+static void testIteration ();
+static void testTrimming ();
+static void testPerformance ();
+static void testPerformanceMT ();
+static void testLDIF ();
+static void testAll ();
+static int configureChangelog ();
+static int configureReplica ();
+static int populateChangelogOp ();
+static int populateChangelog (int entryCount, CSN ***csnList);
+static int processEntries (int entryCount, CSN **csnList);
+static void clearCSNList (CSN ***csnList, int count);
+static void threadMain (void *data);
+static char* getBaseDir (const char *dir);
+static LDAPMod **buildMods ();
+
+void testChangelog (TestType type)
+{
+ switch (type)
+ {
+ case TEST_BASIC: testBasic ();
+ break;
+ case TEST_BACKUP_RESTORE: testBackupRestore ();
+ break;
+ case TEST_ITERATION: testIteration ();
+ break;
+ case TEST_TRIMMING: testTrimming ();
+ break;
+ case TEST_PERFORMANCE: testPerformance ();
+ break;
+ case TEST_PERFORMANCE_MT: testPerformanceMT ();
+ break;
+ case TEST_LDIF: testLDIF ();
+ break;
+ case TEST_ALL: testAll ();
+ break;
+ default: printf ("Taste case %d is not supported\n", type);
+ }
+}
+
+/* tests Open/Close, normal recovery, read/write/remove
+ of an entry */
+static void testBasic ()
+{
+ int rc = 0;
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Starting basic test ...\n");
+
+ /* ONREPL - we can't run the tests from the startup code because
+ operations can't be issued until all plugins are started. So,
+ instead, we do it when changelog is created
+ rc = configureChangelog (); */
+ if (rc == 0)
+ {
+ rc = configureReplica ();
+ if (rc == 0)
+ {
+ rc = populateChangelogOp ();
+ }
+ }
+
+ if (rc == 0)
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Basic test completed successfully\n");
+ else
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Basic test failed\n");
+}
+
+static void testBackupRestore ()
+{
+ char *dir;
+ int rc = -1;
+ char *baseDir;
+ char bkDir [MAXPATHLEN + 1];
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Starting backup and recovery test ...\n");
+
+ dir = cl5GetDir ();
+
+ if (dir)
+ {
+ baseDir = getBaseDir (dir);
+ sprintf (bkDir, "%s/clbackup", baseDir);
+ slapi_ch_free ((void**)&baseDir);
+ rc = cl5Backup (bkDir, NULL);
+
+ if (rc == CL5_SUCCESS)
+ {
+ cl5Close ();
+ rc = cl5Restore (dir, bkDir, NULL);
+ if (rc == CL5_SUCCESS)
+ rc = cl5Open (dir, NULL);
+
+ /* PR_RmDir (bkDir);*/
+ }
+ }
+
+ if (rc == CL5_SUCCESS)
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Backup and Restore test completed successfully\n");
+ else
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Backup and Restore test failed\n");
+}
+
+static void testIteration ()
+{
+ Object *r_obj;
+ Slapi_DN *r_root;
+ Replica *r;
+ char *replGen;
+ RUV *ruv;
+ CL5ReplayIterator *it = NULL;
+ slapi_operation_parameters op;
+ int rc;
+ int i;
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Starting iteration test ...\n");
+
+ /* get replica object */
+ r_root = slapi_sdn_new_dn_byval(REPLICA_ROOT);
+ r_obj = replica_get_replica_from_dn (r_root);
+ slapi_sdn_free (&r_root);
+ if (r_obj == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "replica is not configured for (%s)\n",
+ REPLICA_ROOT);
+ return;
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Starting first iteration pass ...\n");
+
+ /* configure empty consumer ruv */
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r);
+ replGen = replica_get_generation (r);
+ ruv_init_new (replGen, 0, NULL, &ruv);
+
+ /* create replay iterator */
+ rc = cl5CreateReplayIterator (r_obj, ruv, &it);
+ if (it)
+ {
+ i = 0;
+ while ((rc = cl5GetNextOperationToReplay (it, &op)) == CL5_SUCCESS)
+ {
+ ruv_set_csns (ruv, op.csn, NULL);
+ operation_parameters_done (&op);
+ i ++;
+ }
+ }
+
+ if (it)
+ cl5DestroyReplayIterator (&it);
+
+ if (rc == CL5_NOTFOUND)
+ {
+ if (i == 0) /* success */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "First iteration pass completed "
+ "successfully: no changes to replay\n");
+ else /* incorrect number of entries traversed */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "First iteration pass failed: "
+ "traversed %d entries; expected none\n", i);
+ }
+ else /* general error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "First iteration pass failed\n");
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Starting second iteration pass ...\n");
+
+ /* add some entries */
+ populateChangelogOp ();
+
+ /* create replay iterator */
+ rc = cl5CreateReplayIterator (r_obj, ruv, &it);
+ if (it)
+ {
+ i = 0;
+ while ((rc = cl5GetNextOperationToReplay (it, &op)) == CL5_SUCCESS)
+ {
+ ruv_set_csns (ruv, op.csn, NULL);
+ operation_parameters_done (&op);
+ i ++;
+ }
+ }
+
+ if (it)
+ cl5DestroyReplayIterator (&it);
+
+ if (rc == CL5_NOTFOUND)
+ {
+ if (i == OP_COUNT) /* success */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Second iteration pass completed "
+ "successfully: %d entries traversed\n", i);
+ else /* incorrect number of entries traversed */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Second iteration pass failed: "
+ "traversed %d entries; expected %d\n", i, OP_COUNT);
+ }
+ else /* general error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Second iteration pass failed\n");
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Starting third iteration pass ...\n");
+ /* add more entries */
+ populateChangelogOp ();
+
+ /* create replay iterator */
+ rc = cl5CreateReplayIterator (r_obj, ruv, &it);
+ if (it)
+ {
+ i = 0;
+ while ((rc = cl5GetNextOperationToReplay (it, &op)) == CL5_SUCCESS)
+ {
+ ruv_set_csns (ruv, op.csn, NULL);
+ operation_parameters_done (&op);
+ i ++;
+ }
+ }
+
+ if (it)
+ cl5DestroyReplayIterator (&it);
+
+ if (rc == CL5_NOTFOUND)
+ {
+ if (i == OP_COUNT) /* success */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Third iteration pass completed "
+ "successfully: %d entries traversed\n", i);
+ else /* incorrect number of entries traversed */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Third iteration pass failed: "
+ "traversed %d entries; expected %d\n", i, OP_COUNT);
+ }
+ else /* general error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Second iteration pass failed\n");
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Iteration test is complete\n");
+
+ ruv_destroy (&ruv);
+ object_release (r_obj);
+ slapi_ch_free ((void**)&replGen);
+}
+
+static void testTrimming ()
+{
+ PRIntervalTime interval;
+ int count;
+ int rc;
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Starting trimming test ...\n");
+
+ rc = populateChangelog (200, NULL);
+
+ if (rc == 0)
+ {
+ interval = PR_SecondsToInterval(2);
+ DS_Sleep (interval);
+
+ rc = populateChangelog (300, NULL);
+
+ if (rc == 0)
+ rc = cl5ConfigTrimming (300, "1d");
+
+ interval = PR_SecondsToInterval(300); /* 5 min is default trimming interval */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Trimming test: sleeping for 5 minutes until trimming kicks in\n");
+ DS_Sleep (interval);
+
+ count = cl5GetOperationCount (NULL);
+ }
+
+ if (rc == 0 && count == 300)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Trimming test completed successfully: changelog contains 300 entries\n");
+ }
+ else if (rc == 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Trimming test failed: changelog contains %d entries; expected - 300\n",
+ count);
+ }
+ else /* general failure */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Trimming test failed\n");
+}
+
+static void testPerformance ()
+{
+ PRTime starttime, endtime, totaltime;
+ int entryCount = 5000;
+ CSN **csnList = NULL;
+ int rc;
+
+ starttime = PR_Now();
+
+ rc = populateChangelog (entryCount, &csnList);
+
+ endtime = PR_Now();
+
+ totaltime = (endtime - starttime) / 1000; /* ms */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Write performance:\n"
+ "entry count - %d, total time - %ldms\n"
+ "latency = %d msec\nthroughput = %d entry/sec\n",
+ entryCount, totaltime,
+ totaltime / entryCount, entryCount * 1000 / totaltime);
+
+
+ starttime = endtime;
+
+ rc = processEntries (entryCount, csnList);
+
+ endtime = PR_Now();
+
+ totaltime = (endtime - starttime) / 1000; /* ms */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Read performance:\n"
+ "entry count - %d, total time - %ld\n"
+ "latency = %d msec\nthroughput = %d entry/sec\n",
+ entryCount, totaltime,
+ totaltime / entryCount, entryCount * 1000 / totaltime);
+
+ clearCSNList (&csnList, entryCount);
+}
+
+static int threadsLeft;
+static void testPerformanceMT ()
+{
+ PRTime starttime, endtime, totaltime;
+ int entryCount = 200;
+ int threadCount = 10;
+ int entryTotal;
+ int i;
+ PRIntervalTime interval;
+
+ interval = PR_MillisecondsToInterval(100);
+ threadsLeft = threadCount * 2;
+ entryTotal = threadCount * entryCount;
+ starttime = PR_Now();
+
+ for (i = 0; i < threadCount; i++)
+ {
+ PR_CreateThread(PR_USER_THREAD, threadMain, (void*)&entryCount,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, 0);
+ }
+
+ while (threadsLeft > 5)
+ DS_Sleep (interval);
+
+ endtime = PR_Now();
+
+ totaltime = (endtime - starttime) / 1000; /* ms */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Write performance:\n"
+ "entry count - %d, total time - %ld\n"
+ "latency = %d msec per entry\nthroughput = %d entry/sec\n",
+ entryCount, totaltime,
+ totaltime / entryTotal, entryTotal * 1000 / totaltime);
+
+
+ starttime = endtime;
+
+ while (threadsLeft != 0)
+ DS_Sleep (interval);
+
+ endtime = PR_Now();
+
+ totaltime = (endtime - starttime) / 1000; /* ms */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Read performance:\n"
+ "entry count - %d, total time - %ld\n"
+ "latency = %d msec per entry\nthroughput = %d entry/sec\n",
+ entryCount, totaltime,
+ totaltime / entryTotal, entryTotal * 1000 / totaltime);
+}
+
+static void testLDIF ()
+{
+ char *clDir = cl5GetDir ();
+ int rc;
+ char *baseDir;
+ char ldifFile [MAXPATHLEN + 1];
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "Starting LDIF test ...\n");
+
+ baseDir = getBaseDir (clDir);
+ sprintf (ldifFile, "%s/cl5.ldif", baseDir);
+ slapi_ch_free ((void**)&baseDir);
+ rc = populateChangelog (ENTRY_COUNT, NULL);
+
+ if (rc == CL5_SUCCESS)
+ {
+ rc = cl5ExportLDIF (ldifFile, NULL);
+ if (rc == CL5_SUCCESS)
+ {
+ cl5Close();
+ rc = cl5ImportLDIF (clDir, ldifFile, NULL);
+ if (rc == CL5_SUCCESS)
+ cl5Open(clDir, NULL);
+ }
+ }
+
+ PR_Delete (ldifFile);
+
+ if (rc == CL5_SUCCESS)
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "LDIF test completed successfully\n");
+ else
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "LDIF test failed\n");
+}
+
+static void testAll ()
+{
+ testBasic ();
+
+ testIteration ();
+
+ testBackupRestore ();
+
+ testLDIF ();
+
+ /* testTrimming ();*/
+
+#if 0
+ /* xxxPINAKI */
+ /* these tests are not working correctly...the call to db->put() */
+ /* just hangs forever */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Starting single threaded performance measurement ...\n");
+ testPerformance ();
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Starting multi threaded performance measurement ...\n");
+ testPerformanceMT ();
+#endif
+
+}
+
+static int populateChangelog (int entryCount, CSN ***csnList)
+{
+ CSN *csn;
+ int i;
+ slapi_operation_parameters op;
+ int rc;
+ char *uniqueid;
+
+ if (csnList)
+ {
+ (*csnList) = (CSN**)slapi_ch_calloc (entryCount, sizeof (CSN*));
+ }
+
+ /* generate entries */
+ for (i = 0; i < entryCount; i++)
+ {
+ /* ONREPL need to get replica object
+ rc = csnGetNewCSNForRepl (&csn);
+ if (rc != CL5_SUCCESS) */
+ return -1;
+
+ if (csnList)
+ (*csnList) [i] = csn_dup (csn);
+ memset (&op, 0, sizeof (op));
+ op.csn = csn;
+ slapi_uniqueIDGenerateString(&uniqueid);
+ op.target_address.uniqueid = uniqueid;
+ op.target_address.dn = slapi_ch_strdup ("cn=entry,dc=example,dc=com");
+ if (i % 5 == 0)
+ {
+ op.operation_type = SLAPI_OPERATION_MODRDN;
+ op.p.p_modrdn.modrdn_deloldrdn = 1;
+ op.p.p_modrdn.modrdn_newrdn = slapi_ch_strdup("cn=entry2,dc=example,dc=com");
+ op.p.p_modrdn.modrdn_newsuperior_address.dn = NULL;
+ op.p.p_modrdn.modrdn_newsuperior_address.uniqueid = NULL;
+ op.p.p_modrdn.modrdn_mods = buildMods ();
+ }
+ else if (i % 4 == 0)
+ {
+ op.operation_type = SLAPI_OPERATION_DELETE;
+ }
+ else if (i % 3 == 0)
+ {
+
+ op.operation_type = SLAPI_OPERATION_ADD;
+ op.p.p_add.target_entry = slapi_entry_alloc ();
+ slapi_entry_set_dn (op.p.p_add.target_entry, slapi_ch_strdup(op.target_address.dn));
+ slapi_entry_set_uniqueid (op.p.p_add.target_entry, slapi_ch_strdup(op.target_address.uniqueid));
+ slapi_entry_attr_set_charptr(op.p.p_add.target_entry, "objectclass", "top");
+ slapi_entry_attr_set_charptr(op.p.p_add.target_entry, "cn", "entry");
+ }
+ else
+ {
+ op.operation_type = SLAPI_OPERATION_MODIFY;
+ op.p.p_modify.modify_mods = buildMods ();
+ }
+
+ /* ONREPL rc = cl5WriteOperation (&op, 1);*/
+ operation_parameters_done (&op);
+
+ if (rc != CL5_SUCCESS)
+ return -1;
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Successfully populated changelog with %d entries\n", entryCount);
+ return 0;
+}
+
+static int processEntries (int entryCount, CSN **csnList)
+{
+ int i;
+ int rc = 0;
+ slapi_operation_parameters op;
+
+ for (i = 0; i < entryCount; i++)
+ {
+ memset (&op, 0, sizeof (op));
+
+ op.csn = csn_dup (csnList [i]);
+
+ /* rc = cl5GetOperation (&op);*/
+ if (rc != CL5_SUCCESS)
+ return -1;
+
+ operation_parameters_done (&op);
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl,
+ "Successfully read %d entries from the changelog\n", entryCount);
+ return 0;
+}
+
+void clearCSNList (CSN ***csnList, int count)
+{
+ int i;
+
+ for (i = 0; i < count; i++)
+ {
+ csn_free (&((*csnList)[i]));
+ }
+
+ slapi_ch_free ((void**)csnList);
+}
+
+static void threadMain (void *data)
+{
+ int entryCount = *(int*)data;
+ CSN **csnList;
+
+ populateChangelog (entryCount, &csnList);
+ PR_AtomicDecrement (&threadsLeft);
+
+ processEntries (entryCount, csnList);
+ PR_AtomicDecrement (&threadsLeft);
+
+ clearCSNList (&csnList, entryCount);
+}
+
+static char* getBaseDir (const char *dir)
+{
+ char *baseDir = slapi_ch_strdup (dir);
+ char *ch;
+
+ ch = &(baseDir [strlen (dir) - 2]);
+
+ while (ch >= baseDir && *ch != '\\' && *ch != '/')
+ ch --;
+
+ if (ch >= baseDir)
+ {
+ *ch = '\0';
+ }
+
+ return baseDir;
+}
+
+static LDAPMod **buildMods ()
+{
+ Slapi_Mods smods;
+ Slapi_Mod smod;
+ LDAPMod **mods;
+ struct berval bv;
+ int j, k;
+
+ slapi_mods_init (&smods, MOD_COUNT);
+
+ for (j = 0; j < MOD_COUNT; j++)
+ {
+ slapi_mod_init (&smod, VALUE_COUNT);
+ slapi_mod_set_operation (&smod, LDAP_MOD_ADD | LDAP_MOD_BVALUES);
+ slapi_mod_set_type (&smod, "attr");
+
+ for (k = 0; k < VALUE_COUNT; k++)
+ {
+ bv.bv_val = "bvalue";
+ bv.bv_len = strlen (bv.bv_val) + 1;
+ slapi_mod_add_value (&smod, &bv);
+ }
+
+ slapi_mods_add_smod (&smods, &smod);
+ /* ONREPL slapi_mod_done (&smod); */
+ }
+
+ mods = slapi_mods_get_ldapmods_passout (&smods);
+ slapi_mods_done (&smods);
+ return mods;
+}
+
+/* Format:
+ dn: cn=changelog5,cn=config
+ objectclass: top
+ objectclass: extensibleObject
+ cn: changelog5
+ nsslapd-changelogDir: d:/netscape/server4/slapd-elf/cl5 */
+static int configureChangelog ()
+{
+ Slapi_PBlock *pb = slapi_pblock_new ();
+ Slapi_Entry *e = slapi_entry_alloc ();
+ int rc;
+ char *attrs[] = {INSTANCE_ATTR, NULL};
+ Slapi_Entry **entries;
+ char cl_dir [256];
+ char *str = NULL;
+
+ /* set changelog dn */
+ slapi_entry_set_dn (e, slapi_ch_strdup (CL_DN));
+
+ /* set object classes */
+ slapi_entry_add_string(e, "objectclass", "top");
+ slapi_entry_add_string(e, "objectclass", "extensibleObject");
+
+ /* get directory instance dir */
+ slapi_search_internal_set_pb (pb, "cn=config", LDAP_SCOPE_BASE, "objectclass=*",
+ attrs, 0, NULL, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_search_internal_pb (pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "failed to get server instance "
+ "directory; LDAP error - %d\n", rc);
+ rc = -1;
+ goto done;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ str = slapi_entry_attr_get_charptr(entries[0], INSTANCE_ATTR);
+ sprintf (cl_dir, "%s/%s", str, "cl5db");
+ slapi_ch_free((void **)&str);
+ slapi_entry_add_string (e, CONFIG_CHANGELOG_DIR_ATTRIBUTE, cl_dir);
+
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy (pb);
+
+ pb = slapi_pblock_new ();
+
+ slapi_add_entry_internal_set_pb (pb, e, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+
+ slapi_add_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "failed to add changelog "
+ "configuration entry; LDAP error - %d\n", rc);
+ rc = -1;
+ }
+ else
+ rc = 0;
+
+done:
+ slapi_pblock_destroy (pb);
+
+ return rc;
+}
+
+/* Format:
+ dn: cn=replica,cn="o=NetscapeRoot",cn= mapping tree,cn=config
+ objectclass: top
+ objectclass: nsds5Replica
+ objectclass: extensibleObject
+ nsds5ReplicaRoot: o=NetscapeRoot
+ nsds5ReplicaId: 2
+ nsds5flags: 1
+ cn: replica
+ */
+static int configureReplica ()
+{
+ Slapi_PBlock *pb = slapi_pblock_new ();
+ Slapi_Entry *e = slapi_entry_alloc ();
+ int rc;
+ char dn [128];
+
+ /* set changelog dn */
+ sprintf (dn, "%s,cn=\"%s\",%s", REPLICA_RDN, REPLICA_ROOT,
+ slapi_get_mapping_tree_config_root ());
+ slapi_entry_set_dn (e, slapi_ch_strdup (dn));
+
+ /* set object classes */
+ slapi_entry_add_string(e, "objectclass", "top");
+ slapi_entry_add_string(e, "objectclass", REPLICA_OC);
+ slapi_entry_add_string(e, "objectclass", "extensibleObject");
+
+ /* set other attributes */
+ slapi_entry_add_string (e, attr_replicaRoot, REPLICA_ROOT);
+ slapi_entry_add_string (e, attr_replicaId, "1");
+ slapi_entry_add_string (e, attr_flags, "1");
+
+ slapi_add_entry_internal_set_pb (pb, e, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+
+ slapi_add_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "failed to add replica for (%s) "
+ "configuration entry; LDAP error - %d\n", REPLICA_ROOT, rc);
+ rc = -1;
+ }
+ else
+ rc = 0;
+
+ slapi_pblock_destroy (pb);
+
+ return rc;
+}
+
+/* generates one of each ldap operations */
+static int populateChangelogOp ()
+{
+ Slapi_PBlock *pb = slapi_pblock_new ();
+ Slapi_Entry *e = slapi_entry_alloc ();
+ int rc;
+ char dn [128], newrdn [64];
+ LDAPMod *mods[2];
+ Slapi_Mod smod;
+ struct berval bv;
+ time_t cur_time;
+
+ /* add entry */
+ cur_time = time(NULL);
+ sprintf (dn, "cn=%s,%s", ctime(&cur_time), REPLICA_ROOT);
+ slapi_entry_set_dn (e, slapi_ch_strdup (dn));
+ slapi_entry_add_string(e, "objectclass", "top");
+ slapi_entry_add_string(e, "objectclass", "extensibleObject");
+ slapi_entry_add_string (e, "mail", "jsmith@netscape.com");
+
+ slapi_add_entry_internal_set_pb (pb, e, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_add_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ slapi_pblock_destroy (pb);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "failed to add entry (%s); "
+ "LDAP error - %d\n", dn, rc);
+ return -1;
+ }
+
+ /* modify entry */
+ pb = slapi_pblock_new ();
+ slapi_mod_init (&smod, 1);
+ slapi_mod_set_type (&smod, "mail");
+ slapi_mod_set_operation (&smod, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
+ bv.bv_val = "jsmith@aol.com";
+ bv.bv_len = strlen (bv.bv_val);
+ slapi_mod_add_value(&smod, &bv);
+ mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod);
+ mods[1] = NULL;
+ slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_modify_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ slapi_mod_done (&smod);
+ slapi_pblock_destroy (pb);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "failed to modify entry (%s); "
+ "LDAP error - %d\n", dn, rc);
+ return -1;
+ }
+
+ /* rename entry */
+ pb = slapi_pblock_new ();
+ cur_time = time (NULL);
+ sprintf (newrdn, "cn=renamed%s", ctime(&cur_time));
+ slapi_rename_internal_set_pb (pb, dn, newrdn, NULL, 1, NULL, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_modrdn_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ slapi_pblock_destroy (pb);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "failed to rename entry (%s); "
+ "LDAP error - %d\n", dn, rc);
+ return -1;
+ }
+
+ /* delete the entry */
+ pb = slapi_pblock_new ();
+ sprintf (dn, "%s,%s", newrdn, REPLICA_ROOT);
+ slapi_delete_internal_set_pb (pb, dn, NULL, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_delete_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ slapi_pblock_destroy (pb);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name_cl, "failed to delete entry (%s); "
+ "LDAP error - %d\n", dn, rc);
+ return -1;
+ }
+
+ return 0;
+}
diff --git a/ldap/servers/plugins/replication/cl5_test.h b/ldap/servers/plugins/replication/cl5_test.h
new file mode 100644
index 00000000..57d8435c
--- /dev/null
+++ b/ldap/servers/plugins/replication/cl5_test.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cl5_test.h - changelog test cases */
+
+typedef enum
+{
+ TEST_BASIC, /* open-close-delete, read-write-delete */
+ TEST_BACKUP_RESTORE,/* test backup and recovery */
+ TEST_ITERATION, /* similar to iteration used by replica upsate protocol */
+ TEST_TRIMMING, /* test changelog trimming */
+ TEST_PERFORMANCE, /* test read/write performance */
+ TEST_PERFORMANCE_MT,/* test multithreaded performance */
+ TEST_LDIF, /* test cl2ldif and ldif2cl */
+ TEST_ALL /* collective test */
+} TestType;
+
+void testChangelog (TestType type);
+
diff --git a/ldap/servers/plugins/replication/csnpl.c b/ldap/servers/plugins/replication/csnpl.c
new file mode 100644
index 00000000..7180af67
--- /dev/null
+++ b/ldap/servers/plugins/replication/csnpl.c
@@ -0,0 +1,328 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "csnpl.h"
+#include "llist.h"
+#include "repl_shared.h"
+
+struct csnpl
+{
+ LList* csnList; /* pending list */
+ PRRWLock* csnLock; /* lock to serialize access to PL */
+};
+
+typedef struct _csnpldata
+{
+ PRBool committed; /* True if CSN committed */
+ CSN *csn; /* The actual CSN */
+} csnpldata;
+
+/* forward declarations */
+#ifdef DEBUG
+static void _csnplDumpContentNoLock(CSNPL *csnpl, const char *caller);
+#endif
+
+CSNPL* csnplNew ()
+{
+ CSNPL *csnpl;
+
+ csnpl = (CSNPL *)slapi_ch_malloc (sizeof (CSNPL));
+ if (csnpl == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "csnplNew: failed to allocate pending list\n");
+ return NULL;
+ }
+
+ csnpl->csnList = llistNew ();
+ if (csnpl->csnList == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "csnplNew: failed to allocate pending list\n");
+ slapi_ch_free ((void**)&csnpl);
+ return NULL;
+ }
+
+ /* ONREPL: do locks need different names */
+ csnpl->csnLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "pl_lock");
+
+ if (csnpl->csnLock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "csnplNew: failed to create lock; NSPR error - %d\n",
+ PR_GetError ());
+ slapi_ch_free ((void**)&(csnpl->csnList));
+ slapi_ch_free ((void**)&csnpl);
+ return NULL;
+ }
+
+ return csnpl;
+}
+
+
+void
+csnpldata_free(void **data)
+{
+ csnpldata **data_to_free = (csnpldata **)data;
+ if (NULL != data_to_free)
+ {
+ if (NULL != (*data_to_free)->csn)
+ {
+ csn_free(&(*data_to_free)->csn);
+ }
+ slapi_ch_free((void **)data_to_free);
+ }
+}
+
+void csnplFree (CSNPL **csnpl)
+{
+ if ((csnpl == NULL) || (*csnpl == NULL))
+ return;
+
+ /* free all remaining nodes */
+ llistDestroy (&((*csnpl)->csnList), (FNFree)csnpldata_free);
+
+ if ((*csnpl)->csnLock);
+ PR_DestroyRWLock ((*csnpl)->csnLock);
+
+ slapi_ch_free ((void**)csnpl);
+}
+
+/* This function isnerts a CSN into the pending list
+ * Returns: 0 if the csn was successfully inserted
+ * 1 if the csn has already been seen
+ * -1 for any other kind of errors
+ */
+int csnplInsert (CSNPL *csnpl, const CSN *csn)
+{
+ int rc;
+ csnpldata *csnplnode;
+ char csn_str[CSN_STRSIZE];
+
+ if (csnpl == NULL || csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "csnplInsert: invalid argument\n");
+ return -1;
+ }
+
+ PR_RWLock_Wlock (csnpl->csnLock);
+
+ /* check to see if this csn is larger than the last csn in the
+ pending list. It has to be if we have not seen it since
+ the csns are always added in the accending order. */
+ csnplnode = llistGetTail (csnpl->csnList);
+ if (csnplnode && csn_compare (csnplnode->csn, csn) >= 0)
+ {
+ PR_RWLock_Unlock (csnpl->csnLock);
+ return 1;
+ }
+
+ csnplnode = (csnpldata *)slapi_ch_malloc(sizeof(csnpldata));
+ csnplnode->committed = PR_FALSE;
+ csnplnode->csn = csn_dup(csn);
+ csn_as_string(csn, PR_FALSE, csn_str);
+ rc = llistInsertTail (csnpl->csnList, csn_str, csnplnode);
+
+#ifdef DEBUG
+ _csnplDumpContentNoLock(csnpl, "csnplInsert");
+#endif
+
+ PR_RWLock_Unlock (csnpl->csnLock);
+ if (rc != 0)
+ {
+ char s[CSN_STRSIZE];
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "csnplInsert: failed to insert csn (%s) into pending list\n", csn_as_string(csn,PR_FALSE,s));
+ return -1;
+ }
+
+ return 0;
+}
+
+int csnplRemove (CSNPL *csnpl, const CSN *csn)
+{
+ csnpldata *data;
+ char csn_str[CSN_STRSIZE];
+
+ if (csnpl == NULL || csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "csnplRemove: invalid argument\n");
+ return -1;
+ }
+
+ csn_as_string(csn, PR_FALSE, csn_str);
+ PR_RWLock_Wlock (csnpl->csnLock);
+
+ data = (csnpldata *)llistRemove (csnpl->csnList, csn_str);
+ if (data == NULL)
+ {
+ PR_RWLock_Unlock (csnpl->csnLock);
+ return -1;
+ }
+
+#ifdef DEBUG
+ _csnplDumpContentNoLock(csnpl, "csnplRemove");
+#endif
+
+ csn_free(&data->csn);
+ slapi_ch_free((void **)&data);
+
+ PR_RWLock_Unlock (csnpl->csnLock);
+
+ return 0;
+}
+
+int csnplCommit (CSNPL *csnpl, const CSN *csn)
+{
+ csnpldata *data;
+ char csn_str[CSN_STRSIZE];
+
+ if (csnpl == NULL || csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "csnplCommit: invalid argument\n");
+ return -1;
+ }
+ csn_as_string(csn, PR_FALSE, csn_str);
+
+ PR_RWLock_Wlock (csnpl->csnLock);
+
+#ifdef DEBUG
+ _csnplDumpContentNoLock(csnpl, "csnplCommit");
+#endif
+
+ data = (csnpldata*)llistGet (csnpl->csnList, csn_str);
+ if (data == NULL)
+ {
+ /*
+ * In the scenario "4.x master -> 6.x legacy-consumer -> 6.x consumer"
+ * csn will have rid=65535. Hence 6.x consumer will get here trying
+ * to commit r->min_csn_pl because its rid matches that in the csn.
+ * However, r->min_csn_pl is always empty for a dedicated consumer.
+ * Exclude READ-ONLY replica ID here from error logging.
+ */
+ ReplicaId rid = csn_get_replicaid (csn);
+ if (rid < MAX_REPLICA_ID)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "csnplCommit: can't find csn %s\n", csn_str);
+ }
+ PR_RWLock_Unlock (csnpl->csnLock);
+ return -1;
+ }
+ else
+ {
+ data->committed = PR_TRUE;
+ }
+
+ PR_RWLock_Unlock (csnpl->csnLock);
+
+ return 0;
+}
+
+
+
+CSN* csnplGetMinCSN (CSNPL *csnpl, PRBool *committed)
+{
+ csnpldata *data;
+ CSN *csn = NULL;
+ PR_RWLock_Rlock (csnpl->csnLock);
+ if ((data = (csnpldata*)llistGetHead (csnpl->csnList)) != NULL)
+ {
+ csn = csn_dup(data->csn);
+ if (NULL != committed)
+ {
+ *committed = data->committed;
+ }
+ }
+ PR_RWLock_Unlock (csnpl->csnLock);
+
+ return csn;
+}
+
+
+/*
+ * Roll up the list of pending CSNs, removing all of the CSNs at the
+ * head of the the list that are committed and contiguous. Returns
+ * the largest committed CSN, or NULL if no contiguous block of
+ * committed CSNs appears at the beginning of the list. The caller
+ * is responsible for freeing the CSN returned.
+ */
+CSN *
+csnplRollUp(CSNPL *csnpl, CSN **first_commited)
+{
+ CSN *largest_committed_csn = NULL;
+ csnpldata *data;
+ PRBool freeit = PR_TRUE;
+
+ PR_RWLock_Wlock (csnpl->csnLock);
+ if (first_commited) {
+ /* Avoid non-initialization issues due to careless callers */
+ *first_commited = NULL;
+ }
+ data = (csnpldata *)llistGetHead(csnpl->csnList);
+ while (NULL != data && data->committed)
+ {
+ if (NULL != largest_committed_csn && freeit)
+ {
+ csn_free(&largest_committed_csn);
+ }
+ freeit = PR_TRUE;
+ largest_committed_csn = data->csn; /* Save it */
+ if (first_commited && (*first_commited == NULL)) {
+ *first_commited = data->csn;
+ freeit = PR_FALSE;
+ }
+ data = (csnpldata*)llistRemoveHead (csnpl->csnList);
+ slapi_ch_free((void **)&data);
+ data = (csnpldata *)llistGetHead(csnpl->csnList);
+ }
+
+#ifdef DEBUG
+ _csnplDumpContentNoLock(csnpl, "csnplRollUp");
+#endif
+
+ PR_RWLock_Unlock (csnpl->csnLock);
+ return largest_committed_csn;
+}
+
+#ifdef DEBUG
+/* Dump current content of the list - for debugging */
+void
+csnplDumpContent(CSNPL *csnpl, const char *caller)
+{
+ if (csnpl)
+ {
+ PR_RWLock_Rlock (csnpl->csnLock);
+ _csnplDumpContentNoLock (csnpl, caller);
+ PR_RWLock_Unlock (csnpl->csnLock);
+ }
+}
+
+/* helper function */
+static void _csnplDumpContentNoLock(CSNPL *csnpl, const char *caller)
+{
+ csnpldata *data;
+ void *iterator;
+ char csn_str[CSN_STRSIZE];
+
+ data = (csnpldata *)llistGetFirst(csnpl->csnList, &iterator);
+ if (data) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s: CSN Pending list content:\n",
+ caller ? caller : "");
+ }
+ while (data)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s, %s\n",
+ csn_as_string(data->csn, PR_FALSE, csn_str),
+ data->committed ? "committed" : "not committed");
+ data = (csnpldata *)llistGetNext (csnpl->csnList, &iterator);
+ }
+}
+#endif
+
diff --git a/ldap/servers/plugins/replication/csnpl.h b/ldap/servers/plugins/replication/csnpl.h
new file mode 100644
index 00000000..ae1b4c85
--- /dev/null
+++ b/ldap/servers/plugins/replication/csnpl.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 **/
+/* csnpl.h - interface for csn pending list */
+
+#ifndef CSNPL_H
+#define CSNPL_H
+
+#include "slapi-private.h"
+
+typedef struct csnpl CSNPL;
+
+CSNPL* csnplNew ();
+void csnplFree (CSNPL **csnpl);
+int csnplInsert (CSNPL *csnpl, const CSN *csn);
+int csnplRemove (CSNPL *csnpl, const CSN *csn);
+CSN* csnplGetMinCSN (CSNPL *csnpl, PRBool *committed);
+int csnplCommit (CSNPL *csnpl, const CSN *csn);
+CSN *csnplRollUp(CSNPL *csnpl, CSN ** first);
+void csnplDumpContent(CSNPL *csnpl, const char *caller);
+#endif
diff --git a/ldap/servers/plugins/replication/dllmain.c b/ldap/servers/plugins/replication/dllmain.c
new file mode 100644
index 00000000..3f17b14c
--- /dev/null
+++ b/ldap/servers/plugins/replication/dllmain.c
@@ -0,0 +1,91 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+ /*
+ * Microsoft Windows specifics for LIBREPLICATION DLL
+ */
+#include "ldap.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; /* successful DLL_PROCESS_ATTACH */
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/replication/legacy_consumer.c b/ldap/servers/plugins/replication/legacy_consumer.c
new file mode 100644
index 00000000..8bf45ee1
--- /dev/null
+++ b/ldap/servers/plugins/replication/legacy_consumer.c
@@ -0,0 +1,707 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * repl_legacy_consumer.c - support for legacy replication (consumer-side)
+ *
+ * Support for legacy replication involves correctly dealing with
+ * the addition and removal of attribute types "copiedFrom" and
+ * "copyingFrom". The behavior is:
+ * 1) If a copiedFrom appears in an entry, and that entry is the root
+ * of a replicated area, then put the backend into "refer on update"
+ * mode and install a referral corresponding to the URL contained
+ * in the copiedFrom attribute. This referral overrides the mode
+ * of the replica, e.g. if it was previously an updateable replica,
+ * it now becomes read-only except for the updatedn.
+ * 2) If a copiedFrom disappears from an entry, or the entry containing
+ * the copiedFrom is removed, restore the backend to the state
+ * determined by the DS 5.0 replica configuration.
+ * 3) If a "copyingFrom" referral appears in an entry, and that entry
+ * is the root of a replicated area, then put the backend into
+ * "refer all operations" mode and install a referral corresponding
+ * to the URL contained in the copyingFrom attribute. This referral
+ * overrides the mode of the replica, e.g if it was previously an
+ * updateable replica, it now becomes read-only and refers all
+ * operations except for the updatedn.
+ * 4) If a copyingFrom disappears from an entry, or the entry containing
+ * the copyingFrom is removed, restore the backend to the state
+ * determined by the DS 5.0 replica configuration.
+ */
+
+
+#include "repl5.h"
+#include "repl.h"
+
+/* Forward Declarations */
+static int legacy_consumer_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int legacy_consumer_config_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int legacy_consumer_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+
+static int legacy_consumer_extract_config(Slapi_Entry* entry, char *returntext);
+static int legacy_consumer_read_config ();
+static void legacy_consumer_encode_pw (Slapi_Entry *e);
+static void set_legacy_purl (Slapi_PBlock *pb, const char *purl);
+static int get_legacy_referral (Slapi_Entry *e, char **referral, char **state);
+
+#define LEGACY_CONSUMER_CONFIG_DN "cn=legacy consumer," REPL_CONFIG_TOP
+#define LEGACY_CONSUMER_FILTER "(objectclass=*)"
+
+/* Configuration parameters local to this module */
+static Slapi_DN *legacy_consumer_replicationdn = NULL;
+static char *legacy_consumer_replicationpw = NULL;
+/* Lock which protects the above config parameters */
+PRRWLock *legacy_consumer_config_lock = NULL;
+
+static PRBool
+target_is_a_replica_root(Slapi_PBlock *pb, const Slapi_DN **root)
+{
+ char *dn;
+ Slapi_DN *sdn;
+ PRBool return_value;
+ Object *repl_obj;
+
+ slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
+ sdn = slapi_sdn_new_dn_byref(dn);
+ repl_obj = replica_get_replica_from_dn(sdn);
+ if (NULL != repl_obj)
+ {
+ Replica *r = object_get_data(repl_obj);
+ *root = replica_get_root(r);
+ return_value = PR_TRUE;
+ object_release(repl_obj);
+ }
+ else
+ {
+ *root = NULL;
+ return_value = PR_FALSE;
+ }
+ slapi_sdn_free(&sdn);
+ return return_value;
+}
+
+
+
+static int
+parse_cfstring(const char *cfstring, char **referral, char **generation, char **lastreplayed)
+{
+ int return_value = -1;
+ char *ref, *gen, *lastplayed;
+
+ if (cfstring != NULL)
+ {
+ char *tmp;
+ char *cfcopy = slapi_ch_strdup(cfstring);
+ ref = cfcopy;
+ tmp = strchr(cfcopy, ' ');
+ if (NULL != tmp)
+ {
+ *tmp++ = '\0';
+ while ('\0' != *tmp && ' ' == *tmp) tmp++;
+ gen = tmp;
+ tmp = strchr(gen, ' ');
+ if (NULL != tmp)
+ {
+ *tmp++ = '\0';
+ while ('\0' != *tmp && ' ' == *tmp) tmp++;
+ lastplayed = tmp;
+ return_value = 0;
+ }
+ }
+
+ if (return_value == 0)
+ {
+ if (referral)
+ *referral = slapi_ch_strdup(ref);
+ if (generation)
+ *generation = slapi_ch_strdup(gen);
+ if (lastreplayed)
+ *lastreplayed = slapi_ch_strdup(lastplayed);
+ }
+ slapi_ch_free((void **)&cfcopy);
+ }
+ return return_value;
+}
+
+
+
+/*
+ * This is called from the consumer post-op plugin point.
+ * It's called if:
+ * 1) The operation is an add or modify operation, and a
+ * copiedfrom/copyingfrom was found in the entry/mods, or
+ * 2) the operation is a delete operation, or
+ * 3) the operation is a moddn operation.
+ */
+
+void
+process_legacy_cf(Slapi_PBlock *pb)
+{
+ consumer_operation_extension *opext;
+ Slapi_Operation *op;
+ char *referral_array[2] = {0};
+ char *referral;
+ char *state;
+ int rc;
+ const Slapi_DN *replica_root_sdn = NULL;
+ Slapi_Entry *e;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ opext = (consumer_operation_extension*) repl_con_get_ext (REPL_CON_EXT_OP, op);
+
+ if (opext->has_cf)
+ {
+ PR_ASSERT (operation_get_type (op) == SLAPI_OPERATION_ADD ||
+ operation_get_type (op) == SLAPI_OPERATION_MODIFY);
+
+ if ((PR_FALSE == target_is_a_replica_root(pb, &replica_root_sdn)) ||
+ (NULL == replica_root_sdn)){
+ return;
+ }
+
+ slapi_pblock_get (pb, SLAPI_ENTRY_POST_OP, &e);
+ PR_ASSERT (e);
+
+ if (NULL == e)
+ return;
+
+ rc = get_legacy_referral (e, &referral, &state);
+ if (rc == 0)
+ {
+ referral_array[0] = referral;
+ referral_array[1] = NULL;
+ repl_set_mtn_state_and_referrals(replica_root_sdn, state, NULL, NULL,
+ referral_array);
+ /* set partial url in the replica_object */
+ set_legacy_purl (pb, referral);
+
+ slapi_ch_free((void **)&referral);
+ }
+
+ }
+}
+
+void legacy_consumer_be_state_change (void *handle, char *be_name,
+ int old_be_state, int new_be_state)
+{
+ Object *r_obj;
+ Replica *r;
+
+ /* we only interested when a backend is coming online */
+ if (new_be_state == SLAPI_BE_STATE_ON)
+ {
+ r_obj = replica_get_for_backend (be_name);
+ if (r_obj)
+ {
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r);
+
+ if (replica_is_legacy_consumer (r))
+ legacy_consumer_init_referrals (r);
+
+ object_release (r_obj);
+ }
+ }
+}
+
+
+static int
+dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+int
+legacy_consumer_config_init()
+{
+ /* The FE DSE *must* be initialised before we get here */
+ int rc;
+
+ if ((legacy_consumer_config_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "legacy_consumer_config_lock")) == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Failed to create legacy_consumer config read-write lock\n");
+ exit(1);
+ }
+
+ rc = legacy_consumer_read_config ();
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Failed to initialize legacy replication configuration\n");
+ return 1;
+ }
+
+ slapi_config_register_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,LEGACY_CONSUMER_CONFIG_DN,LDAP_SCOPE_SUBTREE,LEGACY_CONSUMER_FILTER,legacy_consumer_config_add,NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,LEGACY_CONSUMER_CONFIG_DN,LDAP_SCOPE_SUBTREE,LEGACY_CONSUMER_FILTER,legacy_consumer_config_modify,NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,LEGACY_CONSUMER_CONFIG_DN,LDAP_SCOPE_SUBTREE,LEGACY_CONSUMER_FILTER,dont_allow_that,NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,LEGACY_CONSUMER_CONFIG_DN,LDAP_SCOPE_SUBTREE,LEGACY_CONSUMER_FILTER,legacy_consumer_config_delete,NULL);
+
+ return 0;
+}
+
+static int
+legacy_consumer_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ int rc;
+
+ rc = legacy_consumer_extract_config(e, returntext);
+ if (rc != LDAP_SUCCESS)
+ {
+ *returncode = rc;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Failed to configure legacy replication\n");
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ /* make sure that the password is encoded */
+ legacy_consumer_encode_pw(e);
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "legacy_consumer_config_add: "
+ "successfully configured legacy consumer credentials\n");
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+#define config_copy_strval( s ) s ? slapi_ch_strdup (s) : NULL;
+
+static int
+legacy_consumer_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ int rc= 0;
+ LDAPMod **mods;
+ int not_allowed = 0;
+ int i;
+
+ if (returntext)
+ {
+ returntext[0] = '\0';
+ }
+ *returncode = LDAP_SUCCESS;
+
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ PR_RWLock_Wlock (legacy_consumer_config_lock);
+
+ for (i = 0; (mods[i] && (!not_allowed)); i++)
+ {
+ if (mods[i]->mod_op & LDAP_MOD_DELETE)
+ {
+ /* We don't support deleting an attribute from cn=config */
+ }
+ else
+ {
+ int j;
+ for (j = 0; ((mods[i]->mod_values[j]) && (LDAP_SUCCESS == rc)); j++)
+ {
+ char *config_attr, *config_attr_value;
+ int mod_type;
+ config_attr = (char *) mods[i]->mod_type;
+ config_attr_value = (char *) mods[i]->mod_bvalues[j]->bv_val;
+ /* replace existing value */
+ mod_type = mods[i]->mod_op & ~LDAP_MOD_BVALUES;
+ if ( strcasecmp (config_attr, CONFIG_LEGACY_REPLICATIONDN_ATTRIBUTE ) == 0 )
+ {
+ if (legacy_consumer_replicationdn)
+ slapi_sdn_free (&legacy_consumer_replicationdn);
+
+ if (mod_type == LDAP_MOD_REPLACE)
+ {
+ if (config_attr_value)
+ legacy_consumer_replicationdn = slapi_sdn_new_dn_byval (config_attr_value);
+ }
+ else if (mod_type == LDAP_MOD_DELETE)
+ {
+ legacy_consumer_replicationdn = NULL;
+ }
+ else if (mod_type == LDAP_MOD_ADD)
+ {
+ if (legacy_consumer_replicationdn != NULL)
+ {
+ not_allowed = 1;
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Multiple replicationdns not permitted." );
+ }
+ else
+ {
+ if (config_attr_value)
+ legacy_consumer_replicationdn = slapi_sdn_new_dn_byval (config_attr_value);
+ }
+ }
+ }
+ else if ( strcasecmp ( config_attr, CONFIG_LEGACY_REPLICATIONPW_ATTRIBUTE ) == 0 )
+ {
+ if (mod_type == LDAP_MOD_REPLACE)
+ {
+ legacy_consumer_replicationpw = config_copy_strval(config_attr_value);
+ }
+ else if (mod_type == LDAP_MOD_DELETE)
+ {
+ legacy_consumer_replicationpw = NULL;
+ }
+ else if (mod_type == LDAP_MOD_ADD)
+ {
+ if (legacy_consumer_replicationpw != NULL)
+ {
+ not_allowed = 1;
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Multiple replicationpws not permitted." );
+ }
+ else
+ {
+ legacy_consumer_replicationpw = config_copy_strval(config_attr_value);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ PR_RWLock_Unlock (legacy_consumer_config_lock);
+
+
+ if (not_allowed)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "Failed to modify legacy replication configuration\n" );
+ *returncode= LDAP_CONSTRAINT_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* make sure that the password is encoded */
+ legacy_consumer_encode_pw (e);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static int
+legacy_consumer_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+
+ PR_RWLock_Wlock (legacy_consumer_config_lock);
+ if (legacy_consumer_replicationdn)
+ slapi_sdn_free (&legacy_consumer_replicationdn);
+ if (legacy_consumer_replicationpw)
+ slapi_ch_free ((void**)&legacy_consumer_replicationpw);
+
+ legacy_consumer_replicationdn = NULL;
+ legacy_consumer_replicationpw = NULL;
+ PR_RWLock_Unlock (legacy_consumer_config_lock);
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/*
+ * Given the changelog configuration entry, extract the configuration directives.
+ */
+static int
+legacy_consumer_extract_config(Slapi_Entry* entry, char *returntext)
+{
+ int rc = LDAP_SUCCESS; /* OK */
+ char *arg;
+
+ PR_RWLock_Wlock (legacy_consumer_config_lock);
+
+ arg= slapi_entry_attr_get_charptr(entry,CONFIG_LEGACY_REPLICATIONDN_ATTRIBUTE);
+ if (arg)
+ legacy_consumer_replicationdn = slapi_sdn_new_dn_passin (arg);
+
+ arg= slapi_entry_attr_get_charptr(entry,CONFIG_LEGACY_REPLICATIONPW_ATTRIBUTE);
+ legacy_consumer_replicationpw = arg;
+
+ PR_RWLock_Unlock (legacy_consumer_config_lock);
+
+ return rc;
+}
+
+
+
+
+static int
+legacy_consumer_read_config ()
+{
+ int rc = LDAP_SUCCESS;
+ int scope= LDAP_SCOPE_BASE;
+ Slapi_PBlock *pb;
+
+ pb = slapi_pblock_new ();
+ slapi_search_internal_set_pb (pb, LEGACY_CONSUMER_CONFIG_DN, scope,
+ "(objectclass=*)", NULL /*attrs*/, 0 /* attrs only */,
+ NULL /* controls */, NULL /* uniqueid */,
+ repl_get_plugin_identity(PLUGIN_LEGACY_REPLICATION), 0 /* actions */);
+ slapi_search_internal_pb (pb);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
+ if ( LDAP_SUCCESS == rc )
+ {
+ Slapi_Entry **entries = NULL;
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries );
+ if ( NULL != entries && NULL != entries[0])
+ {
+ /* Extract the config info from the changelog entry */
+ rc = legacy_consumer_extract_config(entries[0], NULL);
+ }
+ }
+ else
+ {
+ rc = LDAP_SUCCESS;
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+
+ return rc;
+}
+
+
+int
+legacy_consumer_is_replicationdn(char *dn)
+{
+ int return_value = 0; /* Assume not */
+
+ if (NULL != dn && '\0' != dn[0])
+ {
+ if (NULL != legacy_consumer_replicationdn)
+ {
+ Slapi_DN *sdn = slapi_sdn_new_dn_byref (dn);
+
+ if (slapi_sdn_compare (legacy_consumer_replicationdn, sdn) == 0) {
+ return_value = 1;
+ }
+
+ slapi_sdn_free (&sdn);
+ }
+ }
+ return return_value;
+}
+
+
+int
+legacy_consumer_is_replicationpw(struct berval *pwval)
+{
+ int return_value = 0; /* Assume not */
+
+ if (NULL != pwval && NULL != pwval->bv_val)
+ {
+ if (NULL != legacy_consumer_replicationpw &&
+ '\0' != legacy_consumer_replicationpw[0]) {
+ struct berval *pwvals[2];
+ struct berval config_pw;
+
+ config_pw.bv_val = legacy_consumer_replicationpw;
+ config_pw.bv_len = strlen(legacy_consumer_replicationpw);
+ pwvals[0] = &config_pw;
+ pwvals[1] = NULL;
+
+ return_value = slapi_pw_find(pwvals, pwval) == 0;
+ }
+ }
+ return return_value;
+}
+
+static void
+legacy_consumer_free_config ()
+{
+ if (NULL != legacy_consumer_replicationdn) {
+ slapi_sdn_free(&legacy_consumer_replicationdn);
+ }
+ if (NULL != legacy_consumer_replicationpw) {
+ slapi_ch_free((void **) &legacy_consumer_replicationpw);
+ }
+}
+
+
+
+static void
+legacy_consumer_encode_pw (Slapi_Entry *e)
+{
+ char *updatepw = slapi_entry_attr_get_charptr(e,
+ CONFIG_LEGACY_REPLICATIONPW_ATTRIBUTE);
+ int is_encoded;
+ char *encoded_value = NULL;
+
+ if (updatepw != NULL)
+ {
+ is_encoded = slapi_is_encoded (updatepw);
+
+ if (!is_encoded)
+ {
+ encoded_value = slapi_encode (updatepw, "SHA");
+ }
+
+ if (encoded_value)
+ {
+ slapi_entry_attr_set_charptr(e,
+ CONFIG_LEGACY_REPLICATIONPW_ATTRIBUTE, encoded_value);
+ }
+ }
+}
+
+static void
+set_legacy_purl (Slapi_PBlock *pb, const char *purl)
+{
+ Object *r_obj;
+ Replica *r;
+
+ r_obj = replica_get_replica_for_op (pb);
+ PR_ASSERT (r_obj);
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r && replica_is_legacy_consumer(r));
+
+ replica_set_legacy_purl (r, purl);
+
+ object_release (r_obj);
+}
+
+/* this function get referrals from an entry.
+ Returns 0 if successful
+ 1 if no referrals are present
+ -1 in case of error
+ */
+static int
+get_legacy_referral (Slapi_Entry *e, char **referral, char **state)
+{
+ char* pat = "ldap://%s";
+ const char *val = NULL;
+ char *hostport;
+ int rc = 1;
+ Slapi_Attr *attr;
+ const Slapi_Value *sval;
+
+ PR_ASSERT (e && referral && state);
+
+ /* Find any copiedFrom/copyingFrom attributes -
+ copyingFrom has priority */
+ if (slapi_entry_attr_find(e, type_copyingFrom, &attr) == 0)
+ {
+ slapi_attr_first_value(attr, (Slapi_Value **)&sval);
+ val = slapi_value_get_string(sval);
+ *state = STATE_REFERRAL;
+ }
+ else if (slapi_entry_attr_find(e, type_copiedFrom, &attr) == 0)
+ {
+ slapi_attr_first_value(attr, (Slapi_Value **)&sval);
+ val = slapi_value_get_string(sval);
+ *state = STATE_UPDATE_REFERRAL;
+ }
+
+ if (val)
+ {
+ rc = parse_cfstring(val, &hostport, NULL, NULL);
+ if (rc != 0)
+ {
+ const char *target_dn = slapi_entry_get_dn_const(e);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Warning: a copiedFrom "
+ "or copyingFrom attribute was added to or removed from an "
+ "entry that is not the root of a replicated area. It is possible "
+ "that a legacy replication supplier is incorrectly configured "
+ "to supply updates to the subtree rooted at %s\n",
+ target_dn == NULL ? "null" : target_dn);
+ }
+ else
+ {
+ *referral = slapi_ch_malloc (strlen (pat) + strlen (hostport));
+
+ sprintf (*referral, pat, hostport);
+
+ slapi_ch_free ((void**)&hostport);
+ }
+ }
+ else
+ {
+ rc = 1; /* no copiedFrom or copyingFrom int the entry */
+ }
+
+ return rc;
+}
+
+/* this function is called during server startup or when replica's data
+ is reloaded. It sets up referrals in the mapping tree based on the
+ copiedFrom and copyingFrom attributes. It also sets up partial url in
+ the replica object used to update RUV.
+ Returns 0 if successful and -1 otherwise
+
+ */
+int
+legacy_consumer_init_referrals (Replica *r)
+{
+ Slapi_PBlock *pb;
+ const Slapi_DN *root_sdn;
+ const char *root_dn;
+ char *attrs[] = {"copiedFrom", "copyingFrom"};
+ int rc;
+ Slapi_Entry **entries = NULL;
+ char *referral = NULL;
+ char *referral_array[2];
+ char *state = NULL;
+
+ PR_ASSERT (r);
+
+ pb = slapi_pblock_new ();
+ PR_ASSERT (pb);
+
+ root_sdn = replica_get_root(r);
+ PR_ASSERT (root_sdn);
+
+ root_dn = slapi_sdn_get_ndn(root_sdn);
+ PR_ASSERT (root_dn);
+
+ slapi_search_internal_set_pb (pb, root_dn, LDAP_SCOPE_BASE, "objectclass=*",attrs,
+ 0 /* attrsonly */, NULL /* controls */,
+ NULL /* uniqueid */,
+ repl_get_plugin_identity (PLUGIN_LEGACY_REPLICATION),
+ 0 /* flags */);
+
+ slapi_search_internal_pb (pb);
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ if (rc == LDAP_REFERRAL)
+ {
+ /* We are in referral mode, probably because ORC failed */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "legacy_consumer_init_referrals "
+ "data for replica %s is in referral mode due to failed "
+ "initialization. Replica need to be reinitialized\n",
+ root_dn);
+ rc = 0;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "legacy_consumer_init_referrals "
+ "failed to obtain root entry for replica %s; LDAP error - %d\n",
+ root_dn, rc);
+ rc = -1;
+ }
+
+ goto done;
+ }
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+
+ PR_ASSERT (entries && entries[0]);
+
+ rc = get_legacy_referral (entries[0], &referral, &state);
+ if (rc == 0)
+ {
+ referral_array[0] = referral;
+ referral_array[1] = NULL;
+ repl_set_mtn_state_and_referrals(root_sdn, state, NULL, NULL, referral_array);
+
+ /* set purtial url in the replica_object */
+ replica_set_legacy_purl (r, referral);
+
+ slapi_ch_free((void **)&referral);
+ }
+ else if (rc == 1) /* no referrals - treat as success */
+ {
+ rc = 0;
+ }
+
+ slapi_free_search_results_internal (pb);
+
+done:
+
+ slapi_pblock_destroy (pb);
+ return rc;
+}
+
diff --git a/ldap/servers/plugins/replication/llist.c b/ldap/servers/plugins/replication/llist.c
new file mode 100644
index 00000000..175ea48f
--- /dev/null
+++ b/ldap/servers/plugins/replication/llist.c
@@ -0,0 +1,336 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* llist.c - single link list implementation */
+
+#include <string.h>
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+#include "llist.h"
+#include "repl_shared.h"
+
+/* data structures */
+
+/* link list node */
+typedef struct lnode
+{
+ char *key;
+ void *data;
+ struct lnode *next;
+} LNode;
+
+/* This structure defines a one-way linked list with head and tail pointers.
+ The list contains a "dummy" head node which makes sure that every node
+ has a previous node. This allows to remove a node during iteration without
+ breaking the list */
+struct llist
+{
+ LNode *head;
+ LNode *tail;
+};
+
+/* forward declarations */
+static LNode* _llistNewNode (const char *key, void *data);
+static void _llistDestroyNode (LNode **node, FNFree fnFree);
+
+LList* llistNew ()
+{
+ LList *list = (LList*) slapi_ch_calloc (1, sizeof (LList));
+
+ /* allocate a special head node - it contains no data but just
+ fulfills the requirement that every node has a previous one.
+ This is used during iteration with removal */
+ if (list)
+ {
+ list->head = (LNode*)slapi_ch_calloc (1, sizeof (LNode));
+ if (list->head == NULL)
+ {
+ slapi_ch_free ((void**)&list);
+ }
+ }
+
+ return list;
+}
+
+void llistDestroy (LList **list, FNFree fnFree)
+{
+ LNode *node = NULL, *prev_node;
+
+ if (list == NULL || *list == NULL)
+ return;
+
+ if ((*list)->head)
+ node = (*list)->head->next;
+
+ while (node)
+ {
+ prev_node = node;
+ node = node->next;
+ _llistDestroyNode (&prev_node, fnFree);
+ }
+
+ slapi_ch_free ((void**)&((*list)->head));
+ slapi_ch_free ((void**)list);
+}
+
+void* llistGetFirst(LList *list, void **iterator)
+{
+ if (list == NULL || iterator == NULL || list->head == NULL || list->head->next == NULL)
+ {
+ /* empty list or error */
+ return NULL;
+ }
+
+ /* Iterator points to the previous element (so that we can remove current element
+ and still keep the list in tact. In case of the first element, iterator points
+ to the dummy head element */
+ (*iterator) = list->head;
+ return list->head->next->data;
+}
+
+void* llistGetNext (LList *list, void **iterator)
+{
+ LNode *node;
+
+ if (list == NULL || list->head == NULL || iterator == NULL || *iterator == NULL)
+ {
+ /* end of the list or error */
+ return NULL;
+ }
+
+ /* Iterator points to the previous element (so that we can
+ remove current element and still keep list in tact. */
+ node = *(LNode **)iterator;
+ node = node->next;
+
+ (*iterator) = node;
+
+ if (node && node->next)
+ return node->next->data;
+ else
+ return NULL;
+}
+
+void* llistRemoveCurrentAndGetNext (LList *list, void **iterator)
+{
+ LNode *prevNode, *node;
+
+ /* end of the list is reached or error occured */
+ if (list == NULL || iterator == NULL || *iterator == NULL)
+ return NULL;
+
+ /* Iterator points to the previous element (so that we can
+ remove current element and still keep list in tact. */
+ prevNode = *(LNode **)iterator;
+ node = prevNode->next;
+ if (node)
+ {
+ prevNode->next = node->next;
+ _llistDestroyNode (&node, NULL);
+ node = prevNode->next;
+ if (node)
+ return node->data;
+ else
+ return NULL;
+ }
+ else
+ return NULL;
+}
+
+void* llistGetHead (LList *list)
+{
+ if (list == NULL || list->head == NULL || list->head->next == NULL)
+ {
+ /* empty list or error */
+ return NULL;
+ }
+
+ return list->head->next->data;
+}
+
+void* llistGetTail (LList *list)
+{
+ if (list == NULL || list->tail == NULL)
+ {
+ /* empty list or error */
+ return NULL;
+ }
+
+ return list->tail->data;
+}
+
+void* llistGet (LList *list, const char* key)
+{
+ LNode *node;
+
+ /* empty list or invalid input */
+ if (list == NULL || list->head == NULL || list->head->next == NULL || key == NULL)
+ return NULL;
+
+ node = list->head->next;
+ while (node)
+ {
+ if (node->key && strcmp (key, node->key) == 0)
+ {
+ return node->data;
+ }
+
+ node = node->next;
+ }
+
+ /* node with specified key is not found */
+ return NULL;
+}
+
+int llistInsertHead (LList *list, const char *key, void *data)
+{
+ LNode *node;
+ if (list == NULL || list->head == NULL || data == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name, "llistInsertHead: invalid argument\n");
+ return -1;
+ }
+
+ node = _llistNewNode (key, data);
+ if (node == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name, "llistInsertHead: failed to allocate list node\n");
+ return -1;
+ }
+
+ if (list->head->next == NULL) /* empty list */
+ {
+ list->head->next = node;
+ list->tail = node;
+ }
+ else
+ {
+ node->next = list->head->next;
+ list->head->next = node;
+ }
+
+ return 0;
+}
+
+int llistInsertTail (LList *list, const char *key, void *data)
+{
+ LNode *node;
+ if (list == NULL || list->head == NULL || data == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name, "llistInsertHead: invalid argument\n");
+ return -1;
+ }
+
+ node = _llistNewNode (key, data);
+ if (node == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, repl_plugin_name, "llistInsertHead: failed to allocate list node\n");
+ return -1;
+ }
+
+ if (list->head->next == NULL) /* empty list */
+ {
+ list->head->next = node;
+ list->tail = node;
+ }
+ else
+ {
+ list->tail->next = node;
+ list->tail = node;
+ }
+
+ return 0;
+}
+
+void* llistRemoveHead (LList *list)
+{
+ LNode *node;
+ void *data;
+
+ if (list == NULL || list->head == NULL || list->head->next == NULL)
+ return NULL;
+
+ node = list->head->next;
+ data = node->data;
+
+ list->head->next = node->next;
+
+ /* last element removed */
+ if (list->head->next == NULL)
+ list->tail = NULL;
+
+ _llistDestroyNode (&node, NULL);
+
+ return data;
+}
+
+void* llistRemove (LList *list, const char *key)
+{
+ LNode *node, *prev_node;
+ void *data;
+
+ if (list == NULL || list->head == NULL || list->head->next == NULL || key == NULL)
+ return NULL;
+
+ node = list->head->next;
+ prev_node = list->head;
+ while (node)
+ {
+ if (node->key && strcmp (key, node->key) == 0)
+ {
+ prev_node->next = node->next;
+ /* last element removed */
+ if (node->next == NULL)
+ {
+ /* no more elements in the list */
+ if (list->head->next == NULL)
+ {
+ list->tail = NULL;
+ }
+ else
+ {
+ list->tail = prev_node;
+ }
+ }
+
+ data = node->data;
+ _llistDestroyNode (&node, NULL);
+ return data;
+ }
+
+ prev_node = node;
+ node = node->next;
+ }
+
+ /* node with specified key is not found */
+ return NULL;
+}
+
+static LNode* _llistNewNode (const char *key, void *data)
+{
+ LNode *node = (LNode*) slapi_ch_malloc (sizeof (LNode));
+ if (node == NULL)
+ return NULL;
+
+ if (key)
+ node->key = slapi_ch_strdup (key);
+ else
+ node->key = NULL;
+
+ node->data = data;
+ node->next = NULL;
+
+ return node;
+}
+
+static void _llistDestroyNode (LNode **node, FNFree fnFree)
+{
+ if ((*node)->data && fnFree)
+ fnFree (&(*node)->data);
+ if ((*node)->key)
+ slapi_ch_free ((void**)&((*node)->key));
+
+ slapi_ch_free ((void**)node);
+}
diff --git a/ldap/servers/plugins/replication/llist.h b/ldap/servers/plugins/replication/llist.h
new file mode 100644
index 00000000..3b196ef8
--- /dev/null
+++ b/ldap/servers/plugins/replication/llist.h
@@ -0,0 +1,26 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* llist.h - single link list interface */
+
+#ifndef LLIST_H
+#define LLIST_H
+typedef struct llist LList;
+
+LList* llistNew ();
+void llistDestroy (LList **list, FNFree fnFree);
+void* llistGetFirst(LList *list, void **iterator);
+void* llistGetNext (LList *list, void **iterator);
+void* llistRemoveCurrentAndGetNext (LList *list, void **iterator);
+void* llistGetHead (LList *list);
+void* llistGetTail (LList *list);
+void* llistGet (LList *list, const char* key);
+int llistInsertHead (LList *list, const char *key, void *data);
+int llistInsertTail (LList *list, const char *key, void *data);
+void* llistRemoveHead (LList *list);
+void* llistRemove (LList *list, const char *key);
+
+#endif
+
diff --git a/ldap/servers/plugins/replication/profile.c b/ldap/servers/plugins/replication/profile.c
new file mode 100644
index 00000000..0a7de374
--- /dev/null
+++ b/ldap/servers/plugins/replication/profile.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 **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+
+
+/* module: provide an interface to the profile file */
+
+static FILE *profile_fd=NULL;
+
+/* JCMREPL - Could build up in an AVL tree and dump out to disk at the end... */
+
+void profile_log(char *file,int line)
+{
+ if (profile_fd==NULL)
+ slapi_log_error(,"profile_log: profile file not open.");
+ else
+ {
+ /* JCMREPL - Probably need a lock around here */
+ fprintf(profile_fd,"%s %d\n",file,line);
+ }
+}
+
+void profile_open()
+{
+ char filename[MAX_FILENAME];
+ strncpy(filename,CFG_rootpath,MAX_FILENAME);
+ strcat(filename,CFG_profilefile);
+ profile_fd= textfile_open(filename,"a");
+}
+
+void profile_close()
+{
+ if (profile_fd==NULL)
+ slapi_log_error(,"profile_close: profile file not open.");
+ else
+ textfile_close(profile_fd);
+}
diff --git a/ldap/servers/plugins/replication/repl.h b/ldap/servers/plugins/replication/repl.h
new file mode 100644
index 00000000..8e502816
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl.h
@@ -0,0 +1,366 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _REPL_H_
+#define _REPL_H_
+
+#include <limits.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32
+#include <sys/param.h>
+#endif /* _WIN32 */
+
+#include "portable.h" /* GGOODREPL - is this cheating? */
+#include "ldaplog.h"
+#include "repl_shared.h"
+#include "cl4.h"
+
+typedef struct schedule_item
+{
+ unsigned long sch_start; /* seconds after midnight */
+ unsigned long sch_length; /* sec */
+ unsigned int sch_weekdays; /* bit mask; LSB = Sunday */
+ struct schedule_item* sch_next;
+} schedule_item;
+
+/* XXXggood - copied from slap.h - bad */
+#if defined( XP_WIN32 )
+#define NO_TIME (time_t)0 /* cannot be -1, NT's localtime( -1 ) returns NULL */
+#else
+#define NO_TIME (time_t)-1 /* a value that time() does not return */
+#endif
+
+/*
+ * A status message contains a time, the textual message,
+ * and a count of the number of times the message occured.
+ */
+typedef struct _status_message {
+ time_t sm_time;
+ char *sm_message;
+ int sm_occurances;
+} status_message;
+
+/*
+ * A status_message_list is a circular array of status messages.
+ * Old messages roll off the end and are discarded.
+ */
+typedef struct _status_message_list {
+ int sml_size; /* number of slots in array */
+ int sml_tail; /* next slot to be written */
+ status_message *sml_messages; /* array of messages */
+} sm_list;
+#define NUM_REPL_MESSAGES 20 /* max # of messages to save */
+
+/* Selective attribute Inclusion states. ORDERING IS SIGNIFICANT */
+#define IMPLICITLY_INCLUDED 1
+#define IMPLICITLY_EXCLUDED 2
+#define EXPLICITLY_EXCLUDED 3
+#define EXPLICITLY_INCLUDED 4
+
+#if defined(__JCMREPL_FILTER__)
+/*
+ * Structure used to implement selective attribute filtering.
+ * sa_filter nodes are arranged in a linked list.
+ */
+typedef struct _sa_filter {
+ Slapi_Filter *sa_filter; /* Filter to apply */
+ int sa_isexclude; /* non-zero if list is exclude list */
+ char **sa_attrlist; /* array - attrs to replicate */
+ struct _sa_filter *sa_next; /* Link to next struct */
+} sa_filter;
+#endif
+
+typedef unsigned long changeNumber;
+#define a2changeNumber( a ) strtoul(( a ), (char **)NULL, 10 )
+
+#define AUTH_SIMPLE 1
+#define AUTH_KERBEROS 2
+
+typedef struct modinfo {
+ char *type;
+ char *value;
+ int len;
+} modinfo;
+
+/*
+ * Representation of one change entry from the replog file.
+ */
+typedef struct repl {
+ char *time; /* time of modification */
+ changeNumber change; /* number of this change */
+ char *dn; /* dn of entry being modified - normalized */
+ char *raw_dn; /* dn of entry - not normalized */
+ int changetype; /* type of change */
+ modinfo *mods; /* modifications to make */
+ char *newrdn; /* new rdn for modrdn */
+ int deleteoldrdn; /* flag for modrdn */
+
+} repl;
+
+#define BIND_OK 0
+#define BIND_ERR_BADLDP 1
+#define BIND_ERR_OPEN 2
+#define BIND_ERR_BAD_ATYPE 3
+#define BIND_ERR_SIMPLE_FAILED 4
+#define BIND_ERR_KERBEROS_FAILED 5
+#define BIND_ERR_SSL_INIT_FAILED 6
+#define BIND_ERR_RACE 7
+
+#define MAX_CHANGENUMBER ULONG_MAX
+
+#define REPLICATION_SUBSYSTEM "replication"
+#define REPL_LDAP_TIMEOUT 30L /* Wait 30 seconds for responses */
+
+/* Update the copiedFrom attribute every <n> updates */
+#define UPDATE_COPIEDFROM_INTERVAL 10
+#define REPL_ERROR_REPL_HALTED "REPLICATION HALTED"
+#define ATTR_NETSCAPEMDSUFFIX "netscapemdsuffix"
+
+#define CONFIG_LEGACY_REPLICATIONDN_ATTRIBUTE "nsslapd-legacy-updatedn"
+#define CONFIG_LEGACY_REPLICATIONPW_ATTRIBUTE "nsslapd-legacy-updatepw"
+
+#define LDAP_CONTROL_REPL_MODRDN_EXTRAMODS "2.16.840.1.113730.3.4.999"
+
+/* Operation types */
+#define OP_MODIFY 1
+#define OP_ADD 2
+#define OP_DELETE 3
+#define OP_MODDN 4
+#define OP_SEARCH 5
+#define OP_COMPARE 6
+
+/* 4.0-style housekeeping interval */
+#define REPLICATION_HOUSEKEEPING_INTERVAL (30 * 1000) /* 30 seconds */
+
+/* Top of tree for replication configuration information */
+#define REPL_CONFIG_TOP "cn=replication,cn=config"
+
+/* Functions */
+
+/* repl_rootdse.c */
+int repl_rootdse_init();
+
+/* In repl.c */
+Slapi_Entry *get_changerecord(const chglog4Info *cl4, changeNumber cnum, int *err);
+changeNumber replog_get_firstchangenum(const chglog4Info *cl4, int *err);
+changeNumber replog_get_lastchangenum(const chglog4Info *cl4, int *err);
+void changelog_housekeeping(time_t cur_time );
+
+/* In repl_config.c */
+int repl_config_init ();
+
+/* Legacy Plugin Functions */
+
+int legacy_preop_bind( Slapi_PBlock *pb );
+int legacy_bepreop_bind( Slapi_PBlock *pb );
+int legacy_postop_bind( Slapi_PBlock *pb );
+int legacy_preop_add( Slapi_PBlock *pb );
+int legacy_bepreop_add( Slapi_PBlock *pb );
+int legacy_postop_add( Slapi_PBlock *pb );
+int legacy_preop_modify( Slapi_PBlock *pb );
+int legacy_bepreop_modify( Slapi_PBlock *pb );
+int legacy_postop_modify( Slapi_PBlock *pb );
+int legacy_preop_modrdn( Slapi_PBlock *pb );
+int legacy_bepreop_modrdn( Slapi_PBlock *pb );
+int legacy_postop_modrdn( Slapi_PBlock *pb );
+int legacy_preop_delete( Slapi_PBlock *pb );
+int legacy_bepreop_delete( Slapi_PBlock *pb );
+int legacy_postop_delete( Slapi_PBlock *pb );
+int legacy_preop_search( Slapi_PBlock *pb );
+int legacy_preop_compare( Slapi_PBlock *pb );
+int legacy_pre_entry( Slapi_PBlock *pb );
+int legacy_bepostop_assignchangenum( Slapi_PBlock *pb );
+
+int replication_plugin_start( Slapi_PBlock *pb );
+int replication_plugin_poststart( Slapi_PBlock *pb );
+int replication_plugin_stop( Slapi_PBlock *pb );
+
+/* In repl.c */
+void replog( Slapi_PBlock *pb, int optype );
+void init_changelog_trimming( changeNumber max_changes, time_t max_age );
+
+/* From repl_globals.c */
+
+extern char *attr_changenumber;
+extern char *attr_targetdn;
+extern char *attr_changetype;
+extern char *attr_newrdn;
+extern char *attr_deleteoldrdn;
+extern char *attr_changes;
+extern char *attr_newsuperior;
+extern char *attr_changetime;
+extern char *attr_dataversion;
+extern char *attr_csn;
+
+extern char *changetype_add;
+extern char *changetype_delete;
+extern char *changetype_modify;
+extern char *changetype_modrdn;
+extern char *changetype_moddn;
+
+extern char *type_copyingFrom;
+extern char *type_copiedFrom;
+extern char *filter_copyingFrom;
+extern char *filter_copiedFrom;
+extern char *filter_objectclass;
+
+extern char *type_cn;
+extern char *type_objectclass;
+
+/* JCMREPL - IFP should be defined centrally */
+
+#ifndef _IFP
+#define _IFP
+typedef int (*IFP)();
+#endif
+
+/* In cl4.c */
+
+changeNumber ldapi_assign_changenumber(chglog4Info *cl4);
+changeNumber ldapi_get_last_changenumber(chglog4Info *cl4);
+changeNumber ldapi_get_first_changenumber(chglog4Info *cl4);
+void ldapi_commit_changenumber(chglog4Info *cl4, changeNumber cnum);
+void ldapi_set_first_changenumber(chglog4Info *cl4, changeNumber cnum);
+void ldapi_set_last_changenumber(chglog4Info *cl4, changeNumber cnum);
+void ldapi_initialize_changenumbers(chglog4Info *cl4, changeNumber first, changeNumber last);
+
+#define LDBM_TYPE "ldbm"
+#define CHANGELOG_LDBM_TYPE "changelog-ldbm"
+
+#define MAX_RETRY_INTERVAL 3600 /* sec = 1 hour */
+
+#define REPL_PROTOCOL_UNKNOWN 0
+#define REPL_PROTOCOL_40 1
+#define REPL_PROTOCOL_50_INCREMENTAL 2
+#define REPL_PROTOCOL_50_TOTALUPDATE 3
+
+/* In repl_globals.c */
+int decrement_repl_active_threads();
+int increment_repl_active_threads();
+
+/* operation extensions */
+
+/* Type of extensions that can be registered */
+typedef enum
+{
+ REPL_SUP_EXT_OP, /* extension for Operation object, replication supplier */
+ REPL_SUP_EXT_CONN, /* extension for Connection object, replication supplier */
+ REPL_CON_EXT_OP, /* extension for Operation object, replication consumer */
+ REPL_CON_EXT_CONN, /* extension for Connection object, replication consumer */
+ REPL_CON_EXT_MTNODE,/* extension for mapping_tree_node object, replication consumer */
+ REPL_EXT_ALL
+} ext_type;
+
+/* general extension functions - repl_ext.c */
+void repl_sup_init_ext (); /* initializes registrations - must be called first */
+void repl_con_init_ext (); /* initializes registrations - must be called first */
+int repl_sup_register_ext (ext_type type); /* registers an extension of the specified type */
+int repl_con_register_ext (ext_type type); /* registers an extension of the specified type */
+void* repl_sup_get_ext (ext_type type, void *object); /* retireves the extension from the object */
+void* repl_con_get_ext (ext_type type, void *object); /* retireves the extension from the object */
+
+/* Operation extension functions - supplier_operation_extension.c */
+
+/* --- supplier operation extension --- */
+typedef struct supplier_operation_extension
+{
+ int prevent_recursive_call;
+ struct slapi_operation_parameters *operation_parameters;
+ char *repl_gen;
+} supplier_operation_extension;
+
+/* extension construct/destructor */
+void* supplier_operation_extension_constructor (void *object, void *parent);
+void supplier_operation_extension_destructor (void* ext,void *object, void *parent);
+
+/* --- consumer operation extension --- */
+typedef struct consumer_operation_extension
+{
+ int has_cf; /* non-zero if the operation contains a copiedFrom/copyingFrom attr */
+ void *search_referrals;
+} consumer_operation_extension;
+
+/* extension construct/destructor */
+void* consumer_operation_extension_constructor (void *object, void *parent);
+void consumer_operation_extension_destructor (void* ext,void *object, void *parent);
+
+/* Connection extension functions - repl_connext.c */
+
+/* --- connection extension --- */
+/* ONREPL - some pointers are void* because they represent 5.0 data structures
+ not known in this header. Fix */
+typedef struct consumer_connection_extension
+{
+ int is_legacy_replication_dn;
+ int repl_protocol_version; /* the replication protocol version number the supplier is talking. */
+ void *replica_acquired; /* Object* for replica */
+ void *supplier_ruv; /* RUV* */
+ int isreplicationsession;
+ Slapi_Connection *connection;
+} consumer_connection_extension;
+
+/* extension construct/destructor */
+void* consumer_connection_extension_constructor (void *object,void *parent);
+void consumer_connection_extension_destructor (void* ext,void *object,void *parent);
+
+/* mapping tree extension - stores replica object */
+typedef struct multimaster_mtnode_extension
+{
+ Object *replica;
+} multimaster_mtnode_extension;
+void* multimaster_mtnode_extension_constructor (void *object,void *parent);
+void multimaster_mtnode_extension_destructor (void* ext,void *object,void *parent);
+
+/* In repl_init.c */
+
+int get_legacy_stop();
+
+/* In repl_entry.c */
+void repl_entry_init(int argc, char** argv);
+
+/* In repl_ops.c */
+int legacy_preop( Slapi_PBlock *pb, const char* caller, int operation_type);
+int legacy_postop( Slapi_PBlock *pb, const char* caller, int operation_type);
+
+/* In profile.c */
+
+#ifdef PROFILE
+#define PROFILE_POINT if (CFG_profile) profile_log(__FILE__,__LINE__) /* JCMREPL - Where is the profiling flag stored? */
+#else
+#define PROFILE_POINT ((void)0)
+#endif
+
+void profile_log(char *file,int line);
+void profile_open();
+void profile_close();
+
+/* in repl_controls.c */
+void add_repl_control_mods( Slapi_PBlock *pb, Slapi_Mods *smods );
+
+/* ... */
+void create_entity (char* DN, const char* oclass);
+
+void write_replog_db( int optype, char *dn, void *change, int flag, changeNumber changenum, time_t curtime, LDAPMod **modrdn_mods );
+int entry2reple( Slapi_Entry *e, Slapi_Entry *oe );
+int mods2reple( Slapi_Entry *e, LDAPMod **ldm );
+int modrdn2reple( Slapi_Entry *e, char *newrdn, int deloldrdn, LDAPMod **ldm );
+
+/* In legacy_consumer.c */
+void process_legacy_cf(Slapi_PBlock *pb);
+int legacy_consumer_is_replicationdn(char *dn);
+int legacy_consumer_is_replicationpw(struct berval *creds);
+int legacy_consumer_config_init();
+
+/* function that gets called when a backend state is changed */
+void legacy_consumer_be_state_change (void *handle, char *be_name,
+ int old_be_state, int new_be_state);
+
+#endif /* _REPL_H_ */
+
+
+
diff --git a/ldap/servers/plugins/replication/repl5.h b/ldap/servers/plugins/replication/repl5.h
new file mode 100644
index 00000000..d936cbea
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5.h
@@ -0,0 +1,480 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5.h - 5.0 replication header */
+
+#ifndef _REPL5_H_
+#define _REPL5_H_
+
+#include <limits.h>
+#include <time.h>
+#include <stdio.h>
+#include <string.h>
+#ifndef _WIN32
+#include <sys/param.h>
+#endif /* _WIN32 */
+
+#include "portable.h" /* GGOODREPL - is this cheating? */
+#include "repl_shared.h"
+#include "llist.h"
+#include "repl5_ruv.h"
+#include "cl4.h"
+
+/* DS 5.0 replication protocol OIDs */
+#define REPL_START_NSDS50_REPLICATION_REQUEST_OID "2.16.840.1.113730.3.5.3"
+#define REPL_END_NSDS50_REPLICATION_REQUEST_OID "2.16.840.1.113730.3.5.5"
+#define REPL_NSDS50_REPLICATION_ENTRY_REQUEST_OID "2.16.840.1.113730.3.5.6"
+#define REPL_NSDS50_REPLICATION_RESPONSE_OID "2.16.840.1.113730.3.5.4"
+#define REPL_NSDS50_UPDATE_INFO_CONTROL_OID "2.16.840.1.113730.3.4.13"
+#define REPL_NSDS50_INCREMENTAL_PROTOCOL_OID "2.16.840.1.113730.3.6.1"
+#define REPL_NSDS50_TOTAL_PROTOCOL_OID "2.16.840.1.113730.3.6.2"
+
+/* DS 5.0 replication protocol error codes */
+#define NSDS50_REPL_REPLICA_READY 0x00 /* Replica ready, go ahead */
+#define NSDS50_REPL_REPLICA_BUSY 0x01 /* Replica busy, try later */
+#define NSDS50_REPL_EXCESSIVE_CLOCK_SKEW 0x02 /* Supplier clock too far ahead */
+#define NSDS50_REPL_PERMISSION_DENIED 0x03 /* Bind DN not allowed to send updates */
+#define NSDS50_REPL_DECODING_ERROR 0x04 /* Consumer couldn't decode extended operation */
+#define NSDS50_REPL_UNKNOWN_UPDATE_PROTOCOL 0x05 /* Consumer doesn't understand suplier's update protocol */
+#define NSDS50_REPL_NO_SUCH_REPLICA 0x06 /* Consumer holds no such replica */
+#define NSDS50_REPL_BELOW_PURGEPOINT 0x07 /* Supplier provided a CSN below the consumer's purge point */
+#define NSDS50_REPL_INTERNAL_ERROR 0x08 /* Something bad happened on consumer */
+#define NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED 0x09 /* Replica released successfully */
+#define NSDS50_REPL_LEGACY_CONSUMER 0x0A /* replica is a legacy consumer */
+#define NSDS50_REPL_REPLICAID_ERROR 0x0B /* replicaID doesn't seem to be unique */
+#define NSDS50_REPL_DISABLED 0x0C /* replica suffix is disabled */
+#define NSDS50_REPL_UPTODATE 0x0D /* replica is uptodate */
+#define NSDS50_REPL_REPLICA_NO_RESPONSE 0xff /* No response received */
+
+/* Protocol status */
+#define PROTOCOL_STATUS_UNKNOWN 701
+#define PROTOCOL_STATUS_INCREMENTAL_AWAITING_CHANGES 702
+#define PROTOCOL_STATUS_INCREMENTAL_ACQUIRING_REPLICA 703
+#define PROTOCOL_STATUS_INCREMENTAL_RELEASING_REPLICA 704
+#define PROTOCOL_STATUS_INCREMENTAL_SENDING_UPDATES 705
+#define PROTOCOL_STATUS_INCREMENTAL_BACKING_OFF 706
+#define PROTOCOL_STATUS_INCREMENTAL_NEEDS_TOTAL_UPDATE 707
+#define PROTOCOL_STATUS_INCREMENTAL_FATAL_ERROR 708
+#define PROTOCOL_STATUS_TOTAL_ACQUIRING_REPLICA 709
+#define PROTOCOL_STATUS_TOTAL_RELEASING_REPLICA 710
+#define PROTOCOL_STATUS_TOTAL_SENDING_DATA 711
+
+/* To Allow Consumer Initialisation when adding an agreement - */
+#define STATE_PERFORMING_TOTAL_UPDATE 501
+#define STATE_PERFORMING_INCREMENTAL_UPDATE 502
+
+#define MAX_NUM_OF_MASTERS 64
+#define REPL_SESSION_ID_SIZE 64
+
+/* Attribute names for replication agreement attributes */
+extern const char *type_nsds5ReplicaHost;
+extern const char *type_nsds5ReplicaPort;
+extern const char *type_nsds5TransportInfo;
+extern const char *type_nsds5ReplicaBindDN;
+extern const char *type_nsds5ReplicaCredentials;
+extern const char *type_nsds5ReplicaBindMethod;
+extern const char *type_nsds5ReplicaRoot;
+extern const char *type_nsds5ReplicatedAttributeList;
+extern const char *type_nsds5ReplicaUpdateSchedule;
+extern const char *type_nsds5ReplicaInitialize;
+extern const char *type_nsds5ReplicaTimeout;
+extern const char *type_nsds5ReplicaBusyWaitTime;
+extern const char *type_nsds5ReplicaSessionPauseTime;
+
+/* To Allow Consumer Initialisation when adding an agreement - */
+extern const char *type_nsds5BeginReplicaRefresh;
+
+/* replica related attributes */
+extern const char *attr_replicaId;
+extern const char *attr_replicaRoot;
+extern const char *attr_replicaType;
+extern const char *attr_replicaBindDn;
+extern const char *attr_state;
+extern const char *attr_flags;
+extern const char *attr_replicaName;
+extern const char *attr_replicaReferral;
+extern const char *type_ruvElement;
+extern const char *type_replicaPurgeDelay;
+extern const char *type_replicaChangeCount;
+extern const char *type_replicaTombstonePurgeInterval;
+extern const char *type_replicaLegacyConsumer;
+extern const char *type_ruvElementUpdatetime;
+
+/* multimaster plugin points */
+int multimaster_preop_bind (Slapi_PBlock *pb);
+int multimaster_preop_add (Slapi_PBlock *pb);
+int multimaster_preop_delete (Slapi_PBlock *pb);
+int multimaster_preop_modify (Slapi_PBlock *pb);
+int multimaster_preop_modrdn (Slapi_PBlock *pb);
+int multimaster_preop_search (Slapi_PBlock *pb);
+int multimaster_preop_compare (Slapi_PBlock *pb);
+int multimaster_bepreop_add (Slapi_PBlock *pb);
+int multimaster_bepreop_delete (Slapi_PBlock *pb);
+int multimaster_bepreop_modify (Slapi_PBlock *pb);
+int multimaster_bepreop_modrdn (Slapi_PBlock *pb);
+int multimaster_bepostop_modrdn (Slapi_PBlock *pb);
+int multimaster_bepostop_delete (Slapi_PBlock *pb);
+int multimaster_postop_bind (Slapi_PBlock *pb);
+int multimaster_postop_add (Slapi_PBlock *pb);
+int multimaster_postop_delete (Slapi_PBlock *pb);
+int multimaster_postop_modify (Slapi_PBlock *pb);
+int multimaster_postop_modrdn (Slapi_PBlock *pb);
+
+/* In repl5_init.c */
+char* get_thread_private_agmtname ();
+void set_thread_private_agmtname (const char *agmtname);
+void* get_thread_private_cache ();
+void set_thread_private_cache (void *buf);
+char* get_repl_session_id (Slapi_PBlock *pb, char *id, CSN **opcsn);
+
+/* In repl_extop.c */
+int multimaster_extop_StartNSDS50ReplicationRequest(Slapi_PBlock *pb);
+int multimaster_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb);
+int extop_noop(Slapi_PBlock *pb);
+struct berval *NSDS50StartReplicationRequest_new(const char *protocol_oid,
+ const char *repl_root, char **extra_referrals, CSN *csn);
+struct berval *NSDS50EndReplicationRequest_new(char *repl_root);
+int decode_repl_ext_response(struct berval *data, int *response_code,
+ struct berval ***ruv_bervals);
+
+/* In repl5_total.c */
+int multimaster_extop_NSDS50ReplicationEntry(Slapi_PBlock *pb);
+
+/* In repl_controls.c */
+int create_NSDS50ReplUpdateInfoControl(const char *uuid,
+ const char *superior_uuid, const CSN *csn,
+ LDAPMod **modify_mods, LDAPControl **ctrlp);
+void destroy_NSDS50ReplUpdateInfoControl(LDAPControl **ctrlp);
+int decode_NSDS50ReplUpdateInfoControl(LDAPControl **controlsp,
+ char **uuid, char **newsuperior_uuid, CSN **csn, LDAPMod ***modrdn_mods);
+
+/* In repl5_replsupplier.c */
+typedef struct repl_supplier Repl_Supplier;
+Repl_Supplier *replsupplier_init(Slapi_Entry *e);
+void replsupplier_configure(Repl_Supplier *rs, Slapi_PBlock *pb);
+void replsupplier_start(Repl_Supplier *rs);
+void replsupplier_stop(Repl_Supplier *rs);
+void replsupplier_destroy(Repl_Supplier **rs);
+void replsupplier_notify(Repl_Supplier *rs, PRUint32 eventmask);
+PRUint32 replsupplier_get_status(Repl_Supplier *rs);
+
+/* In repl5_plugins.c */
+int multimaster_set_local_purl();
+const char *multimaster_get_local_purl();
+PRBool multimaster_started();
+
+/* In repl5_schedule.c */
+typedef struct schedule Schedule;
+typedef void (*window_state_change_callback)(void *arg, PRBool opened);
+Schedule *schedule_new(window_state_change_callback callback_fn, void *callback_arg, const char *session_id);
+void schedule_destroy(Schedule *s);
+int schedule_set(Schedule *sch, Slapi_Attr *attr);
+char **schedule_get(Schedule *sch);
+int schedule_in_window_now(Schedule *sch);
+PRTime schedule_next(Schedule *sch);
+int schedule_notify(Schedule *sch, Slapi_PBlock *pb);
+void schedule_set_priority_attributes(Schedule *sch, char **prio_attrs, int override_schedule);
+void schedule_set_startup_delay(Schedule *sch, size_t startup_delay);
+void schedule_set_maximum_backlog(Schedule *sch, size_t max_backlog);
+void schedule_notify_session(Schedule *sch, PRTime session_end_time, unsigned int flags);
+#define REPLICATION_SESSION_SUCCESS 0
+
+/* In repl5_bos.c */
+typedef struct repl_bos Repl_Bos;
+
+/* In repl5_agmt.c */
+typedef struct repl5agmt Repl_Agmt;
+#define TRANSPORT_FLAG_SSL 1
+#define TRANSPORT_FLAG_TLS 2
+#define BINDMETHOD_SIMPLE_AUTH 1
+#define BINDMETHOD_SSL_CLIENTAUTH 2
+Repl_Agmt *agmt_new_from_entry(Slapi_Entry *e);
+Repl_Agmt *agmt_new_from_pblock(Slapi_PBlock *pb);
+void agmt_delete(void **ra);
+const Slapi_DN *agmt_get_dn_byref(const Repl_Agmt *ra);
+int agmt_get_auto_initialize(const Repl_Agmt *ra);
+long agmt_get_timeout(const Repl_Agmt *ra);
+long agmt_get_busywaittime(const Repl_Agmt *ra);
+long agmt_get_pausetime(const Repl_Agmt *ra);
+int agmt_start(Repl_Agmt *ra);
+int agmt_stop(Repl_Agmt *ra);
+int agmt_replicate_now(Repl_Agmt *ra);
+char *agmt_get_hostname(const Repl_Agmt *ra);
+int agmt_get_port(const Repl_Agmt *ra);
+PRUint32 agmt_get_transport_flags(const Repl_Agmt *ra);
+char *agmt_get_binddn(const Repl_Agmt *ra);
+struct berval *agmt_get_credentials(const Repl_Agmt *ra);
+int agmt_get_bindmethod(const Repl_Agmt *ra);
+Slapi_DN *agmt_get_replarea(const Repl_Agmt *ra);
+int agmt_is_fractional(const Repl_Agmt *ra);
+int agmt_is_fractional_attr(const Repl_Agmt *ra, const char *attrname);
+int agmt_is_50_mm_protocol(const Repl_Agmt *ra);
+int agmt_matches_name(const Repl_Agmt *ra, const Slapi_DN *name);
+int agmt_replarea_matches(const Repl_Agmt *ra, const Slapi_DN *name);
+int agmt_schedule_in_window_now(const Repl_Agmt *ra);
+int agmt_set_schedule_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
+int agmt_set_timeout_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
+int agmt_set_busywaittime_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
+int agmt_set_pausetime_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
+int agmt_set_credentials_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
+int agmt_set_binddn_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
+int agmt_set_bind_method_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
+int agmt_set_transportinfo_from_entry( Repl_Agmt *ra, const Slapi_Entry *e );
+const char *agmt_get_long_name(const Repl_Agmt *ra);
+int agmt_initialize_replica(const Repl_Agmt *agmt);
+void agmt_replica_init_done (const Repl_Agmt *agmt);
+void agmt_notify_change(Repl_Agmt *ra, Slapi_PBlock *pb);
+Object* agmt_get_consumer_ruv (Repl_Agmt *ra);
+ReplicaId agmt_get_consumer_rid ( Repl_Agmt *ra, void *conn );
+int agmt_set_consumer_ruv (Repl_Agmt *ra, RUV *ruv);
+void agmt_update_consumer_ruv (Repl_Agmt *ra);
+CSN* agmt_get_consumer_schema_csn (Repl_Agmt *ra);
+void agmt_set_consumer_schema_csn (Repl_Agmt *ra, CSN *csn);
+void agmt_set_last_update_in_progress (Repl_Agmt *ra, PRBool in_progress);
+void agmt_set_last_update_start (Repl_Agmt *ra, time_t start_time);
+void agmt_set_last_update_end (Repl_Agmt *ra, time_t end_time);
+void agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *msg);
+void agmt_set_update_in_progress (Repl_Agmt *ra, PRBool in_progress);
+void agmt_set_last_init_start (Repl_Agmt *ra, time_t start_time);
+void agmt_set_last_init_end (Repl_Agmt *ra, time_t end_time);
+void agmt_set_last_init_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *msg);
+void agmt_inc_last_update_changecount (Repl_Agmt *ra, ReplicaId rid, int skipped);
+void agmt_get_changecount_string (Repl_Agmt *ra, char *buf, int bufsize);
+
+typedef struct replica Replica;
+
+/* In repl5_agmtlist.c */
+int agmtlist_config_init();
+void agmtlist_shutdown();
+void agmtlist_notify_all(Slapi_PBlock *pb);
+Object* agmtlist_get_first_agreement_for_replica (Replica *r);
+Object* agmtlist_get_next_agreement_for_replica (Replica *r, Object *prev);
+
+
+/* In repl5_backoff.c */
+typedef struct backoff_timer Backoff_Timer;
+#define BACKOFF_FIXED 1
+#define BACKOFF_EXPONENTIAL 2
+#define BACKOFF_RANDOM 3
+Backoff_Timer *backoff_new(int timer_type, int initial_interval, int max_interval);
+time_t backoff_reset(Backoff_Timer *bt, slapi_eq_fn_t callback, void *callback_data);
+time_t backoff_step(Backoff_Timer *bt);
+int backoff_expired(Backoff_Timer *bt, int margin);
+void backoff_delete(Backoff_Timer **btp);
+
+/* In repl5_connection.c */
+typedef struct repl_connection Repl_Connection;
+typedef enum
+{
+ CONN_OPERATION_SUCCESS,
+ CONN_OPERATION_FAILED,
+ CONN_NOT_CONNECTED,
+ CONN_SUPPORTS_DS5_REPL,
+ CONN_DOES_NOT_SUPPORT_DS5_REPL,
+ CONN_SCHEMA_UPDATED,
+ CONN_SCHEMA_NO_UPDATE_NEEDED,
+ CONN_LOCAL_ERROR,
+ CONN_BUSY,
+ CONN_SSL_NOT_ENABLED,
+ CONN_TIMEOUT
+} ConnResult;
+Repl_Connection *conn_new(Repl_Agmt *agmt);
+ConnResult conn_connect(Repl_Connection *conn);
+void conn_disconnect(Repl_Connection *conn);
+void conn_delete(Repl_Connection *conn);
+void conn_get_error(Repl_Connection *conn, int *operation, int *error);
+ConnResult conn_send_add(Repl_Connection *conn, const char *dn, LDAPMod **attrs,
+ LDAPControl *update_control, LDAPControl ***returned_controls);
+ConnResult conn_send_delete(Repl_Connection *conn, const char *dn,
+ LDAPControl *update_control, LDAPControl ***returned_controls);
+ConnResult conn_send_modify(Repl_Connection *conn, const char *dn, LDAPMod **mods,
+ LDAPControl *update_control, LDAPControl ***returned_controls);
+ConnResult conn_send_rename(Repl_Connection *conn, const char *dn,
+ const char *newrdn, const char *newparent, int deleteoldrdn,
+ LDAPControl *update_control, LDAPControl ***returned_controls);
+ConnResult conn_send_extended_operation(Repl_Connection *conn, const char *extop_oid,
+ struct berval *payload, char **retoidp, struct berval **retdatap,
+ LDAPControl *update_control, LDAPControl ***returned_controls);
+const char *conn_get_status(Repl_Connection *conn);
+void conn_start_linger(Repl_Connection *conn);
+void conn_cancel_linger(Repl_Connection *conn);
+ConnResult conn_replica_supports_ds5_repl(Repl_Connection *conn);
+ConnResult conn_read_entry_attribute(Repl_Connection *conn, const char *dn, char *type,
+ struct berval ***returned_bvals);
+ConnResult conn_push_schema(Repl_Connection *conn, CSN **remotecsn);
+void conn_set_timeout(Repl_Connection *conn, long timeout);
+void conn_set_agmt_changed(Repl_Connection *conn);
+
+/* In repl5_protocol.c */
+typedef struct repl_protocol Repl_Protocol;
+Repl_Protocol *prot_new(Repl_Agmt *agmt, int protocol_state);
+void prot_start(Repl_Protocol *rp);
+Repl_Agmt *prot_get_agreement(Repl_Protocol *rp);
+/* initiate total protocol */
+void prot_initialize_replica(Repl_Protocol *rp);
+/* stop protocol session in progress */
+void prot_stop(Repl_Protocol *rp);
+void prot_delete(Repl_Protocol **rpp);
+void prot_free(Repl_Protocol **rpp);
+PRBool prot_set_active_protocol (Repl_Protocol *rp, PRBool total);
+void prot_clear_active_protocol (Repl_Protocol *rp);
+Repl_Connection *prot_get_connection(Repl_Protocol *rp);
+void prot_resume(Repl_Protocol *rp, int wakeup_action);
+void prot_notify_update(Repl_Protocol *rp);
+void prot_notify_agmt_changed(Repl_Protocol *rp, char * agmt_name);
+void prot_notify_window_opened (Repl_Protocol *rp);
+void prot_notify_window_closed (Repl_Protocol *rp);
+Object *prot_get_replica_object(Repl_Protocol *rp);
+void prot_replicate_now(Repl_Protocol *rp);
+
+/* In repl5_replica.c */
+typedef enum
+{
+ REPLICA_TYPE_UNKNOWN,
+ REPLICA_TYPE_PRIMARY,
+ REPLICA_TYPE_READONLY,
+ REPLICA_TYPE_UPDATABLE,
+ REPLICA_TYPE_END
+} ReplicaType;
+
+#define RUV_STORAGE_ENTRY_UNIQUEID "ffffffff-ffffffff-ffffffff-ffffffff"
+#define START_ITERATION_ENTRY_UNIQUEID "00000000-00000000-00000000-00000000"
+#define START_ITERATION_ENTRY_DN "cn=start iteration"
+
+typedef int (*FNEnumReplica) (Replica *r, void *arg);
+
+/* this function should be called to construct the replica object
+ from the data already in the DIT */
+Replica *replica_new(const Slapi_DN *root);
+/* this function should be called to construct the replica object
+ during addition of the replica over LDAP */
+Replica *replica_new_from_entry (Slapi_Entry *e, char *errortext, PRBool is_add_operation);
+void replica_destroy(void **arg);
+PRBool replica_get_exclusive_access(Replica *r, PRBool *isInc, int connid, int opid,
+ const char *locking_purl,
+ char **current_purl);
+void replica_relinquish_exclusive_access(Replica *r, int connid, int opid);
+PRBool replica_get_tombstone_reap_active(const Replica *r);
+const Slapi_DN *replica_get_root(const Replica *r);
+const char *replica_get_name(const Replica *r);
+ReplicaId replica_get_rid (const Replica *r);
+void replica_set_rid (Replica *r, ReplicaId rid);
+PRBool replica_is_initialized (const Replica *r);
+Object *replica_get_ruv (const Replica *r);
+/* replica now owns the RUV */
+void replica_set_ruv (Replica *r, RUV *ruv);
+Object *replica_get_csngen (const Replica *r);
+ReplicaType replica_get_type (const Replica *r);
+void replica_set_type (Replica *r, ReplicaType type);
+PRBool replica_is_legacy_consumer (const Replica *r);
+void replica_set_legacy_consumer (Replica *r, PRBool legacy);
+char *replica_get_legacy_purl (const Replica *r);
+void replica_set_legacy_purl (Replica *r, const char *purl);
+PRBool replica_is_updatedn (const Replica *r, const Slapi_DN *sdn);
+void replica_set_updatedn (Replica *r, const Slapi_ValueSet *vs, int mod_op);
+char *replica_get_generation (const Replica *r);
+/* currently supported flags */
+#define REPLICA_LOG_CHANGES 0x1 /* enable change logging */
+PRBool replica_is_flag_set (const Replica *r, PRUint32 flag);
+void replica_set_flag (Replica *r, PRUint32 flag, PRBool clear);
+void replica_replace_flags (Replica *r, PRUint32 flags);
+void replica_dump(Replica *r);
+void replica_set_enabled (Replica *r, PRBool enable);
+Object *replica_get_replica_from_dn (const Slapi_DN *dn);
+void replica_update_ruv(Replica *replica, const CSN *csn, const char *replica_purl);
+Object *replica_get_replica_for_op (Slapi_PBlock *pb);
+/* the functions below manipulate replica hash */
+int replica_init_name_hash ();
+void replica_destroy_name_hash ();
+int replica_add_by_name (const char *name, Object *replica);
+int replica_delete_by_name (const char *name);
+Object* replica_get_by_name (const char *name);
+void replica_flush(Replica *r);
+void replica_get_referrals(const Replica *r, char ***referrals);
+void replica_set_referrals(Replica *r,const Slapi_ValueSet *vs);
+int replica_update_csngen_state (Replica *r, const RUV *ruv);
+CSN *replica_get_purge_csn(const Replica *r);
+int replica_log_ruv_elements (const Replica *r);
+void replica_enumerate_replicas (FNEnumReplica fn, void *arg);
+int replica_reload_ruv (Replica *r);
+int replica_check_for_data_reload (Replica *r, void *arg);
+/* the functions below manipulate replica dn hash */
+int replica_init_dn_hash ();
+void replica_destroy_dn_hash ();
+int replica_add_by_dn (const char *dn);
+int replica_delete_by_dn (const char *dn);
+int replica_is_being_configured (const char *dn);
+const CSN * _get_deletion_csn(Slapi_Entry *e);
+int legacy_consumer_init_referrals (Replica *r);
+void consumer5_set_mapping_tree_state_for_replica(const Replica *r, RUV *supplierRuv);
+Object *replica_get_for_backend (const char *be_name);
+void replica_set_purge_delay (Replica *r, PRUint32 purge_delay);
+void replica_set_tombstone_reap_interval (Replica *r, long interval);
+void replica_update_ruv_consumer (Replica *r, RUV *supplier_ruv);
+void replica_set_ruv_dirty (Replica *r);
+void replica_write_ruv (Replica *r);
+/* The functions below handles the state flag */
+/* Current internal state flags */
+/* The replica can be busy and not other flag,
+ * it means that the protocol has ended, but the work is not done yet.
+ * It happens on total protocol, the end protocol has been received,
+ * and the thread waits for import to finish
+ */
+#define REPLICA_IN_USE 1 /* The replica is busy */
+#define REPLICA_INCREMENTAL_IN_PROGRESS 2 /* Set only between start and stop inc */
+#define REPLICA_TOTAL_IN_PROGRESS 4 /* Set only between start and stop total */
+#define REPLICA_AGREEMENTS_DISABLED 8 /* Replica is offline */
+PRBool replica_is_state_flag_set(Replica *r, PRInt32 flag);
+void replica_set_state_flag (Replica *r, PRUint32 flag, PRBool clear);
+void replica_enable_replication (Replica *r);
+void replica_disable_replication (Replica *r, Object *r_obj);
+int replica_start_agreement(Replica *r, Repl_Agmt *ra);
+
+CSN* replica_generate_next_csn ( Slapi_PBlock *pb, const CSN *basecsn );
+int replica_get_attr ( Slapi_PBlock *pb, const char *type, void *value );
+
+/* mapping tree extensions manipulation */
+void multimaster_mtnode_extension_init ();
+void multimaster_mtnode_extension_destroy ();
+void multimaster_mtnode_construct_replicas ();
+
+void multimaster_be_state_change (void *handle, char *be_name, int old_be_state, int new_be_state);
+
+/* In repl5_replica_config.c */
+int replica_config_init();
+void replica_config_destroy ();
+
+/* replutil.c */
+LDAPControl* create_managedsait_control ();
+LDAPControl* create_backend_control(Slapi_DN *sdn);
+void repl_set_mtn_state_and_referrals(const Slapi_DN *sdn, const char *mtn_state,
+ const RUV *ruv, char **ruv_referrals,
+ char **other_referrals);
+void repl_set_repl_plugin_path(const char *path);
+
+/* repl5_updatedn_list.c */
+typedef void *ReplicaUpdateDNList;
+typedef int (*FNEnumDN)(Slapi_DN *dn, void *arg);
+ReplicaUpdateDNList replica_updatedn_list_new(const Slapi_Entry *entry);
+void replica_updatedn_list_free(ReplicaUpdateDNList list);
+void replica_updatedn_list_replace(ReplicaUpdateDNList list, const Slapi_ValueSet *vs);
+void replica_updatedn_list_delete(ReplicaUpdateDNList list, const Slapi_ValueSet *vs);
+void replica_updatedn_list_add(ReplicaUpdateDNList list, const Slapi_ValueSet *vs);
+PRBool replica_updatedn_list_ismember(ReplicaUpdateDNList list, const Slapi_DN *dn);
+char *replica_updatedn_list_to_string(ReplicaUpdateDNList list, const char *delimiter);
+void replica_updatedn_list_enumerate(ReplicaUpdateDNList list, FNEnumDN fn, void *arg);
+
+/* enabling developper traces for MMR to understand the total/inc protocol state machines */
+#ifdef DEV_DEBUG
+#define SLAPI_LOG_DEV_DEBUG SLAPI_LOG_FATAL
+#define dev_debug(a) slapi_log_error(SLAPI_LOG_DEV_DEBUG, "DEV_DEBUG", "%s\n", a)
+#else
+#define dev_debug(a)
+#endif
+
+void repl5_set_debug_timeout(const char *val);
+
+#endif /* _REPL5_H_ */
diff --git a/ldap/servers/plugins/replication/repl5_agmt.c b/ldap/servers/plugins/replication/repl5_agmt.c
new file mode 100644
index 00000000..2992fc11
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_agmt.c
@@ -0,0 +1,1766 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl5_agmt.c */
+/*
+
+ Support for 5.0-style replication agreements.
+
+ Directory Server 5.0 replication agreements contain information about
+ replication consumers that we are supplying.
+
+ This module encapsulates the methods available for adding, deleting,
+ modifying, and firing replication agreements.
+
+ Methods:
+
+ agmt_new - Create a new replication agreement, in response to a new
+ replication agreement being added over LDAP.
+ agmt_delete - Destroy an agreement. It is an error to destroy an
+ agreement that has not been stopped.
+ agmt_getstatus - get the status of this replication agreement.
+ agmt_replicate_now - initiate a replication session asap, even if the
+ schedule says we shouldn't.
+ agmt_start - start replicating, according to schedule. Starts a new
+ thread to handle replication.
+ agmt_stop - stop replicating asap and end replication thread.
+ agmt_notify_change - notify the replication agreement about a change that
+ has been logged. The replication agreement will
+ decide if it needs to take some action, e.g. start a
+ replication session.
+ agmt_initialize_replica - start a complete replica refresh.
+ agmt_set_schedule_from_entry - (re)set the schedule associated with this
+ replication agreement based on a RA entry's contents.
+ agmt_set_credentials_from_entry - (re)set the credentials used to bind
+ to the remote replica.
+ agmt_set_binddn_from_entry - (re)set the DN used to bind
+ to the remote replica.
+ agmt_set_bind_method_from_entry - (re)set the bind method used to bind
+ to the remote replica (SIMPLE or SSLCLIENTAUTH).
+ agmt_set_transportinfo_from_entry - (re)set the transport used to bind
+ to the remote replica (SSL or not)
+
+*/
+
+#include "repl5.h"
+#include "repl5_prot_private.h"
+#include "cl5_api.h"
+
+#define DEFAULT_TIMEOUT 600 /* (seconds) default outbound LDAP connection */
+#define TRANSPORT_FLAG_SSL 1
+#define STATUS_LEN 1024
+
+struct changecounter {
+ ReplicaId rid;
+ PRUint32 num_replayed;
+ PRUint32 num_skipped;
+};
+
+typedef struct repl5agmt {
+ char *hostname; /* remote hostname */
+ int port; /* port of remote server */
+ PRUint32 transport_flags; /* SSL, TLS, etc. */
+ char *binddn; /* DN to bind as */
+ struct berval *creds; /* Password, or certificate */
+ int bindmethod; /* Bind method - simple, SSL */
+ Slapi_DN *replarea; /* DN of replicated area */
+ char **frac_attrs; /* list of fractional attributes to be replicated */
+ Schedule *schedule; /* Scheduling information */
+ int auto_initialize; /* 1 = automatically re-initialize replica */
+ const Slapi_DN *dn; /* DN of replication agreement entry */
+ const Slapi_RDN *rdn; /* RDN of replication agreement entry */
+ char *long_name; /* Long name (rdn + host, port) of entry, for logging */
+ Repl_Protocol *protocol; /* Protocol object - manages protocol */
+ struct changecounter *changecounters[MAX_NUM_OF_MASTERS]; /* changes sent/skipped since server start up */
+ int num_changecounters;
+ time_t last_update_start_time; /* Local start time of last update session */
+ time_t last_update_end_time; /* Local end time of last update session */
+ char last_update_status[STATUS_LEN]; /* Status of last update. Format = numeric code <space> textual description */
+ PRBool update_in_progress;
+ time_t last_init_start_time; /* Local start time of last total init */
+ time_t last_init_end_time; /* Local end time of last total init */
+ char last_init_status[STATUS_LEN]; /* Status of last total init. Format = numeric code <space> textual description */
+ PRLock *lock;
+ Object *consumerRUV; /* last RUV received from the consumer - used for changelog purging */
+ CSN *consumerSchemaCSN; /* last schema CSN received from the consumer */
+ ReplicaId consumerRID; /* indicates if the consumer is the originator of a CSN */
+ long timeout; /* timeout (in seconds) for outbound LDAP connections to remote server */
+ PRBool stop_in_progress; /* set by agmt_stop when shutting down */
+ long busywaittime; /* time in seconds to wait after getting a REPLICA BUSY from the consumer -
+ to allow another supplier to finish sending its updates -
+ if set to 0, this means to use the default value if we get a busy
+ signal from the consumer */
+ long pausetime; /* time in seconds to pause after sending updates -
+ to allow another supplier to send its updates -
+ should be greater than busywaittime -
+ if set to 0, this means do not pause */
+} repl5agmt;
+
+/* Forward declarations */
+void agmt_delete(void **rap);
+static void update_window_state_change_callback (void *arg, PRBool opened);
+static int get_agmt_status(Slapi_PBlock *pb, Slapi_Entry* e,
+ Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int agmt_set_bind_method_no_lock(Repl_Agmt *ra, const Slapi_Entry *e);
+static int agmt_set_transportinfo_no_lock(Repl_Agmt *ra, const Slapi_Entry *e);
+
+/*
+Schema for replication agreement:
+
+cn
+nsds5ReplicaHost - hostname
+nsds5ReplicaPort - port number
+nsds5ReplicaTransportInfo - "SSL", "startTLS", or may be absent;
+nsds5ReplicaBindDN
+nsds5ReplicaCredentials
+nsds5ReplicaBindMethod - "SIMPLE" or "SSLCLIENTAUTH".
+nsds5ReplicaRoot - Replicated suffix
+nsds5ReplicatedAttributeList - Unused so far (meant for fractional repl).
+nsds5ReplicaUpdateSchedule
+nsds5ReplicaTimeout - Outbound repl operations timeout
+nsds50ruv - consumer's RUV
+nsds5ReplicaBusyWaitTime - time to wait after getting a REPLICA BUSY from the consumer
+nsds5ReplicaSessionPauseTime - time to pause after sending updates to allow another supplier to send
+*/
+
+
+/*
+ * Validate an agreement, making sure that it's valid.
+ * Return 1 if the agreement is valid, 0 otherwise.
+ */
+static int
+agmt_is_valid(Repl_Agmt *ra)
+{
+ int return_value = 1; /* assume valid, initially */
+ PR_ASSERT(NULL != ra);
+ PR_ASSERT(NULL != ra->dn);
+
+ if (NULL == ra->hostname)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
+ "is malformed: missing host name.\n", slapi_sdn_get_dn(ra->dn));
+ return_value = 0;
+ }
+ if (ra->port <= 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
+ "is malformed: invalid port number %d.\n", slapi_sdn_get_dn(ra->dn), ra->port);
+ return_value = 0;
+ }
+ if (ra->timeout < 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
+ "is malformed: invalid timeout %d.\n", slapi_sdn_get_dn(ra->dn), ra->timeout);
+ return_value = 0;
+ }
+ if (ra->busywaittime < 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
+ "is malformed: invalid busy wait time %d.\n", slapi_sdn_get_dn(ra->dn), ra->busywaittime);
+ return_value = 0;
+ }
+ if (ra->pausetime < 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Replication agreement \"%s\" "
+ "is malformed: invalid pausetime %d.\n", slapi_sdn_get_dn(ra->dn), ra->pausetime);
+ return_value = 0;
+ }
+ return return_value;
+}
+
+
+Repl_Agmt *
+agmt_new_from_entry(Slapi_Entry *e)
+{
+ Repl_Agmt *ra;
+ char *tmpstr;
+ Slapi_Attr *sattr;
+
+ char *auto_initialize = NULL;
+ char *val_nsds5BeginReplicaRefresh = "start";
+
+ ra = (Repl_Agmt *)slapi_ch_calloc(1, sizeof(repl5agmt));
+ if ((ra->lock = PR_NewLock()) == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Unable to create new lock "
+ "for replication agreement \"%s\" - agreement ignored.\n",
+ slapi_entry_get_dn_const(e));
+ goto loser;
+ }
+
+ /* Find all the stuff we need for the agreement */
+
+ /* To Allow Consumer Initialisation when adding an agreement: */
+
+ /*
+ Using 'auto_initialize' member of 'repl5agmt' structure to
+ store the effect of 'nsds5BeginReplicaRefresh' attribute's value
+ in it.
+ */
+ auto_initialize = slapi_entry_attr_get_charptr(e, type_nsds5BeginReplicaRefresh);
+ if ((auto_initialize != NULL) && (strcasecmp(auto_initialize, val_nsds5BeginReplicaRefresh) == 0))
+ {
+ ra->auto_initialize = STATE_PERFORMING_TOTAL_UPDATE;
+ }
+ else
+ {
+ ra->auto_initialize = STATE_PERFORMING_INCREMENTAL_UPDATE;
+ }
+
+ if (auto_initialize)
+ {
+ slapi_ch_free_string (&auto_initialize);
+ }
+
+ /* Host name of remote replica */
+ ra->hostname = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaHost);
+ /* Port number for remote replica instance */
+ ra->port = slapi_entry_attr_get_int(e, type_nsds5ReplicaPort);
+ /* SSL, TLS, or other transport stuff */
+ ra->transport_flags = 0;
+ agmt_set_transportinfo_no_lock(ra, e);
+
+ /* DN to use when binding. May be empty if cert-based auth is to be used. */
+ ra->binddn = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaBindDN);
+ if (NULL == ra->binddn)
+ {
+ ra->binddn = slapi_ch_strdup("");
+ }
+ /* Credentials to use when binding. */
+ ra->creds = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
+ ra->creds->bv_val = NULL;
+ ra->creds->bv_len = 0;
+ if (slapi_entry_attr_find(e, type_nsds5ReplicaCredentials, &sattr) == 0)
+ {
+ Slapi_Value *sval;
+ if (slapi_attr_first_value(sattr, &sval) == 0)
+ {
+ const struct berval *bv = slapi_value_get_berval(sval);
+ if (NULL != bv)
+ {
+ ra->creds->bv_val = slapi_ch_malloc(bv->bv_len + 1);
+ memcpy(ra->creds->bv_val, bv->bv_val, bv->bv_len);
+ ra->creds->bv_len = bv->bv_len;
+ ra->creds->bv_val[bv->bv_len] = '\0'; /* be safe */
+ }
+ }
+ }
+ /* How to bind */
+ (void)agmt_set_bind_method_no_lock(ra, e);
+
+ /* timeout. */
+ ra->timeout = DEFAULT_TIMEOUT;
+ if (slapi_entry_attr_find(e, type_nsds5ReplicaTimeout, &sattr) == 0)
+ {
+ Slapi_Value *sval;
+ if (slapi_attr_first_value(sattr, &sval) == 0)
+ {
+ ra->timeout = slapi_value_get_long(sval);
+ }
+ }
+
+ /* DN of entry at root of replicated area */
+ tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaRoot);
+ if (NULL != tmpstr)
+ {
+ ra->replarea = slapi_sdn_new_dn_passin(tmpstr);
+ }
+ /* XXXggood get fractional attribute include/exclude lists here */
+ /* Replication schedule */
+ ra->schedule = schedule_new(update_window_state_change_callback, ra, agmt_get_long_name(ra));
+ if (slapi_entry_attr_find(e, type_nsds5ReplicaUpdateSchedule, &sattr) == 0)
+ {
+ schedule_set(ra->schedule, sattr);
+ }
+
+ /* busy wait time - time to wait after getting REPLICA BUSY from consumer */
+ ra->busywaittime = slapi_entry_attr_get_long(e, type_nsds5ReplicaBusyWaitTime);
+
+ /* pause time - time to pause after a session has ended */
+ ra->pausetime = slapi_entry_attr_get_long(e, type_nsds5ReplicaSessionPauseTime);
+
+ /* consumer's RUV */
+ if (slapi_entry_attr_find(e, type_ruvElement, &sattr) == 0)
+ {
+ RUV *ruv;
+
+ if (ruv_init_from_slapi_attr(sattr, &ruv) == 0)
+ {
+ ra->consumerRUV = object_new (ruv, (FNFree)ruv_destroy);
+ }
+ }
+
+ ra->consumerRID = 0;
+
+ /* DN and RDN of the replication agreement entry itself */
+ ra->dn = slapi_sdn_dup(slapi_entry_get_sdn((Slapi_Entry *)e));
+ ra->rdn = slapi_rdn_new_sdn(ra->dn);
+
+ /* Compute long name */
+ {
+ const char *agmtname = slapi_rdn_get_rdn(ra->rdn);
+ char hostname[128];
+ char *dot;
+
+ strncpy(hostname, ra->hostname ? ra->hostname : "(unknown)", sizeof(hostname));
+ hostname[sizeof(hostname)-1] = '\0';
+ dot = strchr(hostname, '.');
+ if (dot) {
+ *dot = '\0';
+ }
+ ra->long_name = slapi_ch_malloc(strlen(agmtname) +
+ strlen(hostname) + 25);
+ sprintf(ra->long_name, "agmt=\"%s\" (%s:%d)", agmtname, hostname, ra->port);
+ }
+
+ /* Initialize status information */
+ ra->last_update_start_time = 0UL;
+ ra->last_update_end_time = 0UL;
+ ra->num_changecounters = 0;
+ ra->last_update_status[0] = '\0';
+ ra->update_in_progress = PR_FALSE;
+ ra->stop_in_progress = PR_FALSE;
+ ra->last_init_end_time = 0UL;
+ ra->last_init_start_time = 0UL;
+ ra->last_init_status[0] = '\0';
+
+ if (!agmt_is_valid(ra))
+ {
+ goto loser;
+ }
+
+ /* Now that the agreement is done, just check if changelog is configured */
+ if (cl5GetState() != CL5_STATE_OPEN) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "WARNING: "
+ "Replication agreement added but there is no changelog configured. "
+ "No change will be replicated until a changelog is configured.\n");
+ }
+
+ /*
+ * Establish a callback for this agreement's entry, so we can
+ * adorn it with status information when read.
+ */
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, slapi_sdn_get_ndn(ra->dn),
+ LDAP_SCOPE_BASE, "(objectclass=*)", get_agmt_status, ra);
+
+ return ra;
+loser:
+ agmt_delete((void **)&ra);
+ return NULL;
+}
+
+
+
+Repl_Agmt *
+agmt_new_from_pblock(Slapi_PBlock *pb)
+{
+ Slapi_Entry *e;
+
+ slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
+ return agmt_new_from_entry(e);
+}
+
+
+/*
+ This should never be called directly - only should be called
+ as a destructor. XXXggood this is not finished
+ */
+void
+agmt_delete(void **rap)
+{
+ Repl_Agmt *ra;
+ PR_ASSERT(NULL != rap);
+ PR_ASSERT(NULL != *rap);
+
+ ra = (Repl_Agmt *)*rap;
+
+ /* do prot_delete first - we may be doing some processing using this
+ replication agreement, and prot_delete will make sure the
+ processing is complete - then it should be safe to clean up the
+ other fields below
+ */
+ prot_delete(&ra->protocol);
+
+ /*
+ * Remove the callback for this agreement's entry
+ */
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP,
+ slapi_sdn_get_ndn(ra->dn),
+ LDAP_SCOPE_BASE, "(objectclass=*)",
+ get_agmt_status);
+
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free((void **)&(ra->hostname));
+ slapi_ch_free((void **)&(ra->binddn));
+
+ if (NULL != ra->creds)
+ {
+ /* XXX free berval */
+ }
+ if (NULL != ra->replarea)
+ {
+ slapi_sdn_free(&ra->replarea);
+ }
+
+ if (NULL != ra->consumerRUV)
+ {
+ object_release (ra->consumerRUV);
+ }
+
+ csn_free (&ra->consumerSchemaCSN);
+ while ( --(ra->num_changecounters) >= 0 )
+ {
+ slapi_ch_free((void **)&ra->changecounters[ra->num_changecounters]);
+ }
+
+ schedule_destroy(ra->schedule);
+ slapi_ch_free((void **)&ra->long_name);
+ slapi_ch_free((void **)rap);
+}
+
+
+/*
+ * Allow replication for this replica to begin. Replication will
+ * occur at the next scheduled time. Returns 0 on success, -1 on
+ * failure.
+ */
+int
+agmt_start(Repl_Agmt *ra)
+{
+ Repl_Protocol *prot = NULL;
+
+ int protocol_state;
+
+ /* To Allow Consumer Initialisation when adding an agreement: */
+ if (ra->auto_initialize == STATE_PERFORMING_TOTAL_UPDATE)
+ {
+ protocol_state = STATE_PERFORMING_TOTAL_UPDATE;
+ }
+ else
+ {
+ protocol_state = STATE_PERFORMING_INCREMENTAL_UPDATE;
+ }
+
+ /* First, create a new protocol object */
+ if ((prot = prot_new(ra, protocol_state)) == NULL) {
+ return -1;
+ }
+
+ /* Now it is safe to own the agreement lock */
+ PR_Lock(ra->lock);
+
+ /* Check that replication is not already started */
+ if (ra->protocol != NULL) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replication already started for agreement \"%s\"\n", agmt_get_long_name(ra));
+ PR_Unlock(ra->lock);
+ prot_free(&prot);
+ return 0;
+ }
+
+ ra->protocol = prot;
+
+ /* Start the protocol thread */
+ prot_start(ra->protocol);
+
+ PR_Unlock(ra->lock);
+ return 0;
+}
+
+/*
+Cease replicating to this replica as soon as possible.
+*/
+int
+agmt_stop(Repl_Agmt *ra)
+{
+ int return_value = 0;
+ Repl_Protocol *rp = NULL;
+
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress)
+ {
+ PR_Unlock(ra->lock);
+ return return_value;
+ }
+ ra->stop_in_progress = PR_TRUE;
+ rp = ra->protocol;
+ PR_Unlock(ra->lock);
+ if (NULL != rp) /* we use this pointer outside the lock - dangerous? */
+ {
+ prot_stop(rp);
+ }
+ PR_Lock(ra->lock);
+ ra->stop_in_progress = PR_FALSE;
+ /* we do not reuse the protocol object so free it */
+ prot_free(&ra->protocol);
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+/*
+Send any pending updates as soon as possible, ignoring any replication
+schedules.
+*/
+int
+agmt_replicate_now(Repl_Agmt *ra)
+{
+ int return_value = 0;
+
+ return return_value;
+}
+
+/*
+ * Return a copy of the remote replica's hostname.
+ */
+char *
+agmt_get_hostname(const Repl_Agmt *ra)
+{
+ char *return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = slapi_ch_strdup(ra->hostname);
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+/*
+ * Return the port number of the remote replica's instance.
+ */
+int
+agmt_get_port(const Repl_Agmt *ra)
+{
+ int return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->port;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+/*
+ * Return the transport flags for this agreement.
+ */
+PRUint32
+agmt_get_transport_flags(const Repl_Agmt *ra)
+{
+ unsigned int return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->transport_flags;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+/*
+ * Return a copy of the bind dn to be used with this
+ * agreement (may return NULL if no binddn is required,
+ * e.g. SSL client auth.
+ */
+char *
+agmt_get_binddn(const Repl_Agmt *ra)
+{
+ char *return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->binddn == NULL ? NULL : slapi_ch_strdup(ra->binddn);
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+/*
+ * Return a copy of the credentials.
+ */
+struct berval *
+agmt_get_credentials(const Repl_Agmt *ra)
+{
+ struct berval *return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
+ return_value->bv_val = (char *)slapi_ch_malloc(ra->creds->bv_len + 1);
+ return_value->bv_len = ra->creds->bv_len;
+ memcpy(return_value->bv_val, ra->creds->bv_val, ra->creds->bv_len);
+ return_value->bv_val[return_value->bv_len] = '\0'; /* just in case */
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+int
+agmt_get_bindmethod(const Repl_Agmt *ra)
+{
+ int return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->bindmethod;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+/*
+ * Return a copy of the dn at the top of the replicated area.
+ */
+Slapi_DN *
+agmt_get_replarea(const Repl_Agmt *ra)
+{
+ Slapi_DN *return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = slapi_sdn_new();
+ slapi_sdn_copy(ra->replarea, return_value);
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+int
+agmt_is_fractional(const Repl_Agmt *ra)
+{
+ int return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->frac_attrs != NULL;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+int
+agmt_is_fractional_attr(const Repl_Agmt *ra, const char *attrname)
+{
+ int return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = 1; /* XXXggood finish this */
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+int
+agmt_get_auto_initialize(const Repl_Agmt *ra)
+{
+ int return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->auto_initialize;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+long
+agmt_get_timeout(const Repl_Agmt *ra)
+{
+ long return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->timeout;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+long
+agmt_get_busywaittime(const Repl_Agmt *ra)
+{
+ long return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->busywaittime;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+long
+agmt_get_pausetime(const Repl_Agmt *ra)
+{
+ long return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ return_value = ra->pausetime;
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+/*
+ * Warning - reference to the long name of the agreement is returned.
+ * The long name of an agreement is the DN of the agreement entry,
+ * followed by the host/port for the replica.
+ */
+const char *
+agmt_get_long_name(const Repl_Agmt *ra)
+{
+ char *return_value = NULL;
+
+ return_value = ra ? ra->long_name : "";
+ return return_value;
+}
+
+/*
+ * Warning - reference to dn is returned. However, since the dn of
+ * the replication agreement is its name, it won't change during the
+ * lifetime of the replication agreement object.
+ */
+const Slapi_DN *
+agmt_get_dn_byref(const Repl_Agmt *ra)
+{
+ const Slapi_DN *return_value = NULL;
+
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ return_value = ra->dn;
+ }
+ return return_value;
+}
+
+/* Return 1 if name matches the replication Dn, 0 otherwise */
+int
+agmt_matches_name(const Repl_Agmt *ra, const Slapi_DN *name)
+{
+ int return_value = 0;
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ PR_Lock(ra->lock);
+ if (slapi_sdn_compare(name, ra->dn) == 0)
+ {
+ return_value = 1;
+ }
+ PR_Unlock(ra->lock);
+ }
+ return return_value;
+}
+
+/* Return 1 if name matches the replication area, 0 otherwise */
+int
+agmt_replarea_matches(const Repl_Agmt *ra, const Slapi_DN *name)
+{
+ int return_value = 0;
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ PR_Lock(ra->lock);
+ if (slapi_sdn_compare(name, ra->replarea) == 0)
+ {
+ return_value = 1;
+ }
+ PR_Unlock(ra->lock);
+ }
+ return return_value;
+}
+
+
+int
+agmt_schedule_in_window_now(const Repl_Agmt *ra)
+{
+ int return_value;
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ if (NULL != ra->schedule && schedule_in_window_now(ra->schedule))
+ {
+ return_value = 1;
+ }
+ else
+ {
+ return_value = 0;
+ }
+ PR_Unlock(ra->lock);
+ return return_value;
+}
+
+
+/*
+ * Set or reset the credentials used to bind to the remote replica.
+ *
+ * Returns 0 if credentials set, or -1 if an error occurred.
+ */
+int
+agmt_set_credentials_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ Slapi_Attr *sattr = NULL;
+ int return_value = 0;
+
+ PR_ASSERT(NULL != ra);
+ slapi_entry_attr_find(e, type_nsds5ReplicaCredentials, &sattr);
+ PR_Lock(ra->lock);
+ slapi_ch_free((void **)&ra->creds->bv_val);
+ ra->creds->bv_len = 0;
+ if (NULL != sattr)
+ {
+ Slapi_Value *sval = NULL;
+ slapi_attr_first_value(sattr, &sval);
+ if (NULL != sval)
+ {
+ const struct berval *bv = slapi_value_get_berval(sval);
+ ra->creds->bv_val = slapi_ch_calloc(1, bv->bv_len + 1);
+ memcpy(ra->creds->bv_val, bv->bv_val, bv->bv_len);
+ ra->creds->bv_len = bv->bv_len;
+ }
+ }
+ /* If no credentials set, set to zero-length string */
+ ra->creds->bv_val = NULL == ra->creds->bv_val ? slapi_ch_strdup("") : ra->creds->bv_val;
+ PR_Unlock(ra->lock);
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+ return return_value;
+}
+
+/*
+ * Set or reset the DN used to bind to the remote replica.
+ *
+ * Returns 0 if DN set, or -1 if an error occurred.
+ */
+int
+agmt_set_binddn_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ Slapi_Attr *sattr = NULL;
+ int return_value = 0;
+
+ PR_ASSERT(NULL != ra);
+ slapi_entry_attr_find(e, type_nsds5ReplicaBindDN, &sattr);
+ PR_Lock(ra->lock);
+ slapi_ch_free((void **)&ra->binddn);
+ ra->binddn = NULL;
+ if (NULL != sattr)
+ {
+ Slapi_Value *sval = NULL;
+ slapi_attr_first_value(sattr, &sval);
+ if (NULL != sval)
+ {
+ const char *val = slapi_value_get_string(sval);
+ ra->binddn = strdup(val);
+ }
+ }
+ /* If no BindDN set, set to zero-length string */
+ if (ra->binddn == NULL) {
+ ra->binddn = strdup("");
+ }
+ PR_Unlock(ra->lock);
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+ return return_value;
+}
+
+/*
+ * Set or reset the bind method used to bind to the remote replica.
+ *
+ * Returns 0 if bind method set, or -1 if an error occurred.
+ */
+static int
+agmt_set_bind_method_no_lock(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ char *tmpstr = NULL;
+ int return_value = 0;
+
+ PR_ASSERT(NULL != ra);
+ tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5ReplicaBindMethod);
+
+ if (NULL == tmpstr || strcasecmp(tmpstr, "SIMPLE") == 0)
+ {
+ ra->bindmethod = BINDMETHOD_SIMPLE_AUTH;
+ }
+ else if (strcasecmp(tmpstr, "SSLCLIENTAUTH") == 0)
+ {
+ ra->bindmethod = BINDMETHOD_SSL_CLIENTAUTH;
+ }
+ else
+ {
+ ra->bindmethod = BINDMETHOD_SIMPLE_AUTH;
+ }
+ slapi_ch_free((void **)&tmpstr);
+ return return_value;
+}
+
+int
+agmt_set_bind_method_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ char *tmpstr = NULL;
+ int return_value = 0;
+
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress)
+ {
+ PR_Unlock(ra->lock);
+ return return_value;
+ }
+ return_value = agmt_set_bind_method_no_lock(ra, e);
+ PR_Unlock(ra->lock);
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+ return return_value;
+}
+
+/*
+ * Set or reset the transport used to bind to the remote replica.
+ *
+ * Returns 0 if transport set, or -1 if an error occurred.
+ */
+static int
+agmt_set_transportinfo_no_lock(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ char *tmpstr;
+ int rc = 0;
+
+ tmpstr = slapi_entry_attr_get_charptr(e, type_nsds5TransportInfo);
+ if (NULL != tmpstr && strcasecmp(tmpstr, "SSL") == 0)
+ {
+ ra->transport_flags |= TRANSPORT_FLAG_SSL;
+ } else {
+ ra->transport_flags &= ~TRANSPORT_FLAG_SSL;
+ }
+
+ slapi_ch_free((void **)&tmpstr);
+ return (rc);
+}
+
+int
+agmt_set_transportinfo_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ int return_value = 0;
+
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress)
+ {
+ PR_Unlock(ra->lock);
+ return return_value;
+ }
+ return_value = agmt_set_transportinfo_no_lock(ra, e);
+ PR_Unlock(ra->lock);
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+
+ return return_value;
+}
+
+
+/*
+ * Set or reset the replication schedule. Notify the protocol handler
+ * that a change has been made.
+ *
+ * Returns 0 if schedule was set or -1 if an error occurred.
+ */
+int
+agmt_set_schedule_from_entry( Repl_Agmt *ra, const Slapi_Entry *e )
+{
+ Slapi_Attr *sattr;
+ int return_value = 0;
+
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress)
+ {
+ PR_Unlock(ra->lock);
+ return return_value;
+ }
+ PR_Unlock(ra->lock);
+
+ if (slapi_entry_attr_find(e, type_nsds5ReplicaUpdateSchedule, &sattr) != 0)
+ {
+ sattr = NULL; /* no schedule ==> delete any existing one */
+ }
+
+ /* make it so */
+ return_value = schedule_set(ra->schedule, sattr);
+
+ if ( 0 == return_value ) {
+ /* schedule set OK -- spread the news */
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+ }
+
+ return return_value;
+}
+
+/*
+ * Set or reset the timeout used to bind to the remote replica.
+ *
+ * Returns 0 if timeout set, or -1 if an error occurred.
+ */
+int
+agmt_set_timeout_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ Slapi_Attr *sattr = NULL;
+ int return_value = -1;
+
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress)
+ {
+ PR_Unlock(ra->lock);
+ return return_value;
+ }
+
+ slapi_entry_attr_find(e, type_nsds5ReplicaTimeout, &sattr);
+ if (NULL != sattr)
+ {
+ Slapi_Value *sval = NULL;
+ slapi_attr_first_value(sattr, &sval);
+ if (NULL != sval)
+ {
+ long tmpval = slapi_value_get_long(sval);
+ if (tmpval >= 0) {
+ ra->timeout = tmpval;
+ return_value = 0; /* success! */
+ }
+ }
+ }
+ PR_Unlock(ra->lock);
+ if (return_value == 0)
+ {
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+ }
+ return return_value;
+}
+
+/*
+ * Set or reset the busywaittime
+ *
+ * Returns 0 if busywaittime set, or -1 if an error occurred.
+ */
+int
+agmt_set_busywaittime_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ Slapi_Attr *sattr = NULL;
+ int return_value = -1;
+
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress)
+ {
+ PR_Unlock(ra->lock);
+ return return_value;
+ }
+
+ slapi_entry_attr_find(e, type_nsds5ReplicaBusyWaitTime, &sattr);
+ if (NULL != sattr)
+ {
+ Slapi_Value *sval = NULL;
+ slapi_attr_first_value(sattr, &sval);
+ if (NULL != sval)
+ {
+ long tmpval = slapi_value_get_long(sval);
+ if (tmpval >= 0) {
+ ra->busywaittime = tmpval;
+ return_value = 0; /* success! */
+ }
+ }
+ }
+ PR_Unlock(ra->lock);
+ if (return_value == 0)
+ {
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+ }
+ return return_value;
+}
+
+/*
+ * Set or reset the pausetime
+ *
+ * Returns 0 if pausetime set, or -1 if an error occurred.
+ */
+int
+agmt_set_pausetime_from_entry(Repl_Agmt *ra, const Slapi_Entry *e)
+{
+ Slapi_Attr *sattr = NULL;
+ int return_value = -1;
+
+ PR_ASSERT(NULL != ra);
+ PR_Lock(ra->lock);
+ if (ra->stop_in_progress)
+ {
+ PR_Unlock(ra->lock);
+ return return_value;
+ }
+
+ slapi_entry_attr_find(e, type_nsds5ReplicaSessionPauseTime, &sattr);
+ if (NULL != sattr)
+ {
+ Slapi_Value *sval = NULL;
+ slapi_attr_first_value(sattr, &sval);
+ if (NULL != sval)
+ {
+ long tmpval = slapi_value_get_long(sval);
+ if (tmpval >= 0) {
+ ra->pausetime = tmpval;
+ return_value = 0; /* success! */
+ }
+ }
+ }
+ PR_Unlock(ra->lock);
+ if (return_value == 0)
+ {
+ prot_notify_agmt_changed(ra->protocol, ra->long_name);
+ }
+ return return_value;
+}
+
+/* XXXggood - also make this pass an arg that tells if there was
+ * an update to a priority attribute */
+void
+agmt_notify_change(Repl_Agmt *agmt, Slapi_PBlock *pb)
+{
+ if (NULL != pb)
+ {
+ /* Is the entry within our replicated area? */
+ char *target_dn;
+ Slapi_DN *target_sdn;
+ int change_is_relevant = 0;
+
+ PR_ASSERT(NULL != agmt);
+ PR_Lock(agmt->lock);
+ if (agmt->stop_in_progress)
+ {
+ PR_Unlock(agmt->lock);
+ return;
+ }
+
+ slapi_pblock_get(pb, SLAPI_TARGET_DN, &target_dn);
+ target_sdn = slapi_sdn_new_dn_byref(target_dn); /* XXX see if you can avoid allocating this */
+
+ if (slapi_sdn_issuffix(target_sdn, agmt->replarea))
+ {
+ /*
+ * Yep, it's in our replicated area. Is this a fractional
+ * replication agreement?
+ */
+ if (NULL != agmt->frac_attrs)
+ {
+ /*
+ * Yep, it's fractional. See if the change should be
+ * tossed because it doesn't affect any of the replicated
+ * attributes.
+ */
+ int optype;
+ int affects_fractional_attribute = 0;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &optype);
+ if (SLAPI_OPERATION_MODIFY == optype)
+ {
+ LDAPMod **mods;
+ int i, j;
+
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ for (i = 0; !affects_fractional_attribute && NULL != agmt->frac_attrs[i]; i++)
+ {
+ for (j = 0; !affects_fractional_attribute && NULL != mods[j]; j++)
+ {
+ if (slapi_attr_types_equivalent(agmt->frac_attrs[i],
+ mods[i]->mod_type))
+ {
+ affects_fractional_attribute = 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ /*
+ * Add, delete, and modrdn always cause some sort of
+ * operation replay, even if agreement is fractional.
+ */
+ affects_fractional_attribute = 1;
+ }
+ if (affects_fractional_attribute)
+ {
+ change_is_relevant = 1;
+ }
+ }
+ else
+ {
+ /* Not a fractional agreement */
+ change_is_relevant = 1;
+ }
+ }
+ PR_Unlock(agmt->lock);
+ slapi_sdn_free(&target_sdn);
+ if (change_is_relevant)
+ {
+ /* Notify the protocol that a change has occurred */
+ prot_notify_update(agmt->protocol);
+ }
+ }
+}
+
+
+
+int
+agmt_is_50_mm_protocol(const Repl_Agmt *agmt)
+{
+ return 1; /* XXXggood could support > 1 protocol */
+}
+
+
+
+int
+agmt_initialize_replica(const Repl_Agmt *agmt)
+{
+ PR_ASSERT(NULL != agmt);
+ PR_Lock(agmt->lock);
+ if (agmt->stop_in_progress)
+ {
+ PR_Unlock(agmt->lock);
+ return 0;
+ }
+ PR_Unlock(agmt->lock);
+ /* Call prot_initialize_replica only if the suffix is enabled (agmt->protocol != NULL) */
+ if (NULL != agmt->protocol) {
+ prot_initialize_replica(agmt->protocol);
+ }
+ else {
+ /* agmt->protocol == NULL --> Suffix is disabled */
+ return -1;
+ }
+ return 0;
+}
+
+/* delete nsds5BeginReplicaRefresh attribute to indicate to the clients
+ that replica initialization have completed */
+void
+agmt_replica_init_done (const Repl_Agmt *agmt)
+{
+ int rc;
+ Slapi_PBlock *pb = slapi_pblock_new ();
+ LDAPMod *mods [2];
+ LDAPMod mod;
+
+ mods[0] = &mod;
+ mods[1] = NULL;
+ mod.mod_op = LDAP_MOD_DELETE | LDAP_MOD_BVALUES;
+ mod.mod_type = (char*)type_nsds5ReplicaInitialize;
+ mod.mod_bvalues = NULL;
+
+ slapi_modify_internal_set_pb(pb, slapi_sdn_get_dn (agmt->dn), mods, NULL/* controls */,
+ NULL/* uniqueid */, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0/* flags */);
+ slapi_modify_internal_pb (pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_replica_init_done: "
+ "failed to remove (%s) attribute from (%s) entry; LDAP error - %d\n",
+ type_nsds5ReplicaInitialize, slapi_sdn_get_ndn (agmt->dn), rc);
+ }
+
+ slapi_pblock_destroy (pb);
+}
+
+/* Agreement object is acquired on behalf of the caller.
+ The caller is responsible for releasing the object
+ when it is no longer used */
+
+Object*
+agmt_get_consumer_ruv (Repl_Agmt *ra)
+{
+ Object *rt = NULL;
+
+ PR_ASSERT(NULL != ra);
+
+ PR_Lock(ra->lock);
+ if (ra->consumerRUV)
+ {
+ object_acquire (ra->consumerRUV);
+ rt = ra->consumerRUV;
+ }
+
+ PR_Unlock(ra->lock);
+
+ return rt;
+}
+
+int
+agmt_set_consumer_ruv (Repl_Agmt *ra, RUV *ruv)
+{
+ if (ra == NULL || ruv == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmt_set_consumer_ruv: invalid argument"
+ " agmt - %p, ruv - %p\n", ra, ruv);
+ return -1;
+ }
+
+ PR_Lock(ra->lock);
+
+ if (ra->consumerRUV)
+ {
+ object_release (ra->consumerRUV);
+ }
+
+ ra->consumerRUV = object_new (ruv_dup (ruv), (FNFree)ruv_destroy);
+
+ PR_Unlock(ra->lock);
+
+ return 0;
+}
+
+void
+agmt_update_consumer_ruv (Repl_Agmt *ra)
+{
+ int rc;
+ RUV *ruv;
+ Slapi_Mod smod;
+ Slapi_Mod smod_last_modified;
+ Slapi_PBlock *pb;
+ LDAPMod *mods[3];
+
+ PR_ASSERT (ra);
+ PR_Lock(ra->lock);
+
+ if (ra->consumerRUV)
+ {
+ ruv = (RUV*) object_get_data (ra->consumerRUV);
+ PR_ASSERT (ruv);
+
+ ruv_to_smod(ruv, &smod);
+ ruv_last_modified_to_smod(ruv, &smod_last_modified);
+
+ /* it is ok to release the lock here because we are done with the agreement data.
+ we have to do it before issuing the modify operation because it causes
+ agmtlist_notify_all to be called which uses the same lock - hence the deadlock */
+ PR_Unlock(ra->lock);
+
+ pb = slapi_pblock_new ();
+ mods[0] = (LDAPMod *)slapi_mod_get_ldapmod_byref(&smod);
+ mods[1] = (LDAPMod *)slapi_mod_get_ldapmod_byref(&smod_last_modified);
+ mods[2] = NULL;
+
+ slapi_modify_internal_set_pb (pb, (char*)slapi_sdn_get_dn(ra->dn), mods, NULL, NULL,
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_modify_internal_pb (pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS && rc != LDAP_NO_SUCH_ATTRIBUTE)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s: agmt_update_consumer_ruv: "
+ "failed to update consumer's RUV; LDAP error - %d\n",
+ ra->long_name, rc);
+ }
+
+ slapi_mod_done (&smod);
+ slapi_mod_done (&smod_last_modified);
+ slapi_pblock_destroy (pb);
+ }
+ else
+ PR_Unlock(ra->lock);
+}
+
+CSN*
+agmt_get_consumer_schema_csn (Repl_Agmt *ra)
+{
+ CSN *rt;
+
+ PR_ASSERT(NULL != ra);
+
+ PR_Lock(ra->lock);
+ rt = ra->consumerSchemaCSN;
+ PR_Unlock(ra->lock);
+
+ return rt;
+}
+
+void
+agmt_set_consumer_schema_csn (Repl_Agmt *ra, CSN *csn)
+{
+ PR_ASSERT(NULL != ra);
+
+ PR_Lock(ra->lock);
+ csn_free(&ra->consumerSchemaCSN);
+ ra->consumerSchemaCSN = csn;
+ PR_Unlock(ra->lock);
+}
+
+void
+agmt_set_last_update_start (Repl_Agmt *ra, time_t start_time)
+{
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ ra->last_update_start_time = start_time;
+ ra->last_update_end_time = 0UL;
+ }
+}
+
+
+void
+agmt_set_last_update_end (Repl_Agmt *ra, time_t end_time)
+{
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ ra->last_update_end_time = end_time;
+ }
+}
+
+void
+agmt_set_last_init_start (Repl_Agmt *ra, time_t start_time)
+{
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ ra->last_init_start_time = start_time;
+ ra->last_init_end_time = 0UL;
+ }
+}
+
+
+void
+agmt_set_last_init_end (Repl_Agmt *ra, time_t end_time)
+{
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ ra->last_init_end_time = end_time;
+ }
+}
+
+void
+agmt_set_last_update_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *message)
+{
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ if (replrc == NSDS50_REPL_UPTODATE)
+ {
+ /* no session started, no status update */
+ }
+ else if (ldaprc != LDAP_SUCCESS)
+ {
+ char *replmsg = NULL;
+ if ( replrc ) {
+ replmsg = protocol_response2string(replrc);
+ /* Do not mix the unknown replication error with the known ldap one */
+ if ( strcasecmp(replmsg, "unknown error") == 0 ) {
+ replmsg = NULL;
+ }
+ }
+ if (ldaprc > 0) {
+ PR_snprintf(ra->last_update_status, STATUS_LEN,
+ "%d %s%sLDAP error: %s%s%s",
+ ldaprc,
+ message?message:"",message?"":" - ",
+ ldap_err2string(ldaprc),
+ replmsg ? " - " : "", replmsg ? replmsg : "");
+ } else { /* ldaprc is < 0 */
+ PR_snprintf(ra->last_update_status, STATUS_LEN,
+ "%d %s%sSystem error%s%s",
+ ldaprc,message?message:"",message?"":" - ",
+ replmsg ? " - " : "", replmsg ? replmsg : "");
+ }
+ }
+ else if (replrc != 0)
+ {
+ if (replrc == NSDS50_REPL_REPLICA_READY)
+ {
+ PR_snprintf(ra->last_update_status, STATUS_LEN, "%d %s",
+ ldaprc, "Replica acquired successfully");
+ }
+ else if (replrc == NSDS50_REPL_REPLICA_BUSY)
+ {
+ PR_snprintf(ra->last_update_status, STATUS_LEN,
+ "%d Can't acquire busy replica", replrc );
+ }
+ else if (replrc == NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED)
+ {
+ PR_snprintf(ra->last_update_status, STATUS_LEN, "%d %s",
+ ldaprc, "Replication session successful");
+ }
+ else if (replrc == NSDS50_REPL_DISABLED)
+ {
+ PR_snprintf(ra->last_update_status, STATUS_LEN, "%d Total update aborted: "
+ "Replication agreement for %s\n can not be updated while the replica is disabled.\n"
+ "(If the suffix is disabled you must enable it then restart the server for replication to take place).",
+ replrc, ra->long_name ? ra->long_name : "a replica");
+ /* Log into the errors log, as "ra->long_name" is not accessible from the caller */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Total update aborted: Replication agreement for \"%s\" "
+ "can not be updated while the replica is disabled\n", ra->long_name ? ra->long_name : "a replica");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "(If the suffix is disabled you must enable it then restart the server for replication to take place).\n");
+ }
+ else
+ {
+ PR_snprintf(ra->last_update_status, STATUS_LEN,
+ "%d Replication error acquiring replica: %s%s%s",
+ replrc, protocol_response2string(replrc),
+ message?" - ":"",message?message:"");
+ }
+ }
+ else if (message != NULL)
+ {
+ PR_snprintf(ra->last_update_status, STATUS_LEN, "%d %s", ldaprc, message);
+ }
+ else { /* agmt_set_last_update_status(0,0,NULL) to reset agmt */
+ PR_snprintf(ra->last_update_status, STATUS_LEN, "%d", ldaprc);
+ }
+ }
+}
+
+void
+agmt_set_last_init_status (Repl_Agmt *ra, int ldaprc, int replrc, const char *message)
+{
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ if (ldaprc != LDAP_SUCCESS)
+ {
+ char *replmsg = NULL;
+ if ( replrc ) {
+ replmsg = protocol_response2string(replrc);
+ /* Do not mix the unknown replication error with the known ldap one */
+ if ( strcasecmp(replmsg, "unknown error") == 0 ) {
+ replmsg = NULL;
+ }
+ }
+ if (ldaprc > 0) {
+ PR_snprintf(ra->last_init_status, STATUS_LEN,
+ "%d %s%sLDAP error: %s%s%s",
+ ldaprc,
+ message?message:"",message?"":" - ",
+ ldap_err2string(ldaprc),
+ replmsg ? " - " : "", replmsg ? replmsg : "");
+ } else { /* ldaprc is < 0 */
+ PR_snprintf(ra->last_init_status, STATUS_LEN,
+ "%d %s%sSystem error%s%s",
+ ldaprc,message?message:"",message?"":" - ",
+ replmsg ? " - " : "", replmsg ? replmsg : "");
+ }
+ }
+ else if (replrc != 0)
+ {
+ if (replrc == NSDS50_REPL_REPLICA_READY)
+ {
+ PR_snprintf(ra->last_init_status, STATUS_LEN, "%d %s",
+ ldaprc, "Replica acquired successfully");
+ }
+ else if (replrc == NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED)
+ {
+ PR_snprintf(ra->last_init_status, STATUS_LEN, "%d %s",
+ ldaprc, "Replication session successful");
+ }
+ else if (replrc == NSDS50_REPL_DISABLED)
+ {
+ PR_snprintf(ra->last_init_status, STATUS_LEN, "%d Total update aborted: "
+ "Replication agreement for %s\n can not be updated while the replica is disabled.\n"
+ "(If the suffix is disabled you must enable it then restart the server for replication to take place).",
+ replrc, ra->long_name ? ra->long_name : "a replica");
+ /* Log into the errors log, as "ra->long_name" is not accessible from the caller */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Total update aborted: Replication agreement for \"%s\" "
+ "can not be updated while the replica is disabled\n", ra->long_name ? ra->long_name : "a replica");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "(If the suffix is disabled you must enable it then restart the server for replication to take place).\n");
+ }
+ else
+ {
+ PR_snprintf(ra->last_init_status, STATUS_LEN,
+ "%d Replication error acquiring replica: %s%s%s",
+ replrc, protocol_response2string(replrc),
+ message?" - ":"",message?message:"");
+ }
+ }
+ else if (message != NULL)
+ {
+ PR_snprintf(ra->last_init_status, STATUS_LEN, "%d %s", ldaprc, message);
+ }
+ else { /* agmt_set_last_init_status(0,0,NULL) to reset agmt */
+ PR_snprintf(ra->last_init_status, STATUS_LEN, "%d", ldaprc);
+ }
+ }
+}
+
+
+void
+agmt_set_update_in_progress (Repl_Agmt *ra, PRBool in_progress)
+{
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ ra->update_in_progress = in_progress;
+ }
+}
+
+void
+agmt_inc_last_update_changecount (Repl_Agmt *ra, ReplicaId rid, int skipped)
+{
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ int i;
+
+ for ( i = 0; i < ra->num_changecounters; i++ )
+ {
+ if ( ra->changecounters[i]->rid == rid )
+ break;
+ }
+
+ if ( i < ra->num_changecounters )
+ {
+ if ( skipped )
+ ra->changecounters[i]->num_skipped ++;
+ else
+ ra->changecounters[i]->num_replayed ++;
+ }
+ else
+ {
+ ra->num_changecounters ++;
+ ra->changecounters[i] = (struct changecounter*) slapi_ch_calloc(1, sizeof(struct changecounter));
+ ra->changecounters[i]->rid = rid;
+ if ( skipped )
+ ra->changecounters[i]->num_skipped = 1;
+ else
+ ra->changecounters[i]->num_replayed = 1;
+ }
+ }
+}
+
+void
+agmt_get_changecount_string (Repl_Agmt *ra, char *buf, int bufsize)
+{
+ char tmp_buf[32]; /* 5 digit RID, 10 digit each replayed and skipped */
+ int i;
+ int buflen = 0;
+
+ *buf = '\0';
+ if (NULL != ra)
+ {
+ for ( i = 0; i < ra->num_changecounters; i++ )
+ {
+ PR_snprintf (tmp_buf, sizeof(tmp_buf), "%u:%u/%u ",
+ ra->changecounters[i]->rid,
+ ra->changecounters[i]->num_replayed,
+ ra->changecounters[i]->num_skipped);
+ PR_snprintf (buf+buflen, bufsize-buflen, "%s", tmp_buf);
+ buflen += strlen (tmp_buf);
+ }
+ }
+}
+
+static int
+get_agmt_status(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
+ int *returncode, char *returntext, void *arg)
+{
+ char *time_tmp = NULL;
+ char changecount_string[BUFSIZ];
+ Repl_Agmt *ra = (Repl_Agmt *)arg;
+
+ PR_ASSERT(NULL != ra);
+ if (NULL != ra)
+ {
+ PRBool reapActive = PR_FALSE;
+ Slapi_DN *replarea_sdn = NULL;
+ Object *repl_obj = NULL;
+
+ replarea_sdn = agmt_get_replarea(ra);
+ repl_obj = replica_get_replica_from_dn(replarea_sdn);
+ slapi_sdn_free(&replarea_sdn);
+ if (repl_obj) {
+ Replica *replica = (Replica*)object_get_data (repl_obj);
+ reapActive = replica_get_tombstone_reap_active(replica);
+ object_release(repl_obj);
+ }
+ slapi_entry_attr_set_int(e, "nsds5replicaReapActive", (int)reapActive);
+
+ /* these values persist in the dse.ldif file, so we delete them
+ here to avoid multi valued attributes */
+ slapi_entry_attr_delete(e, "nsds5replicaLastUpdateStart");
+ slapi_entry_attr_delete(e, "nsds5replicaLastUpdateEnd");
+ slapi_entry_attr_delete(e, "nsds5replicaChangesSentSinceStartup");
+ slapi_entry_attr_delete(e, "nsds5replicaLastUpdateStatus");
+ slapi_entry_attr_delete(e, "nsds5replicaUpdateInProgress");
+ slapi_entry_attr_delete(e, "nsds5replicaLastInitStart");
+ slapi_entry_attr_delete(e, "nsds5replicaLastInitStatus");
+ slapi_entry_attr_delete(e, "nsds5replicaLastInitEnd");
+
+ /* now, add the real values (singly) */
+ if (ra->last_update_start_time == 0)
+ {
+ slapi_entry_add_string(e, "nsds5replicaLastUpdateStart", "0");
+ }
+ else
+ {
+ time_tmp = format_genTime(ra->last_update_start_time);
+ slapi_entry_add_string(e, "nsds5replicaLastUpdateStart", time_tmp);
+ slapi_ch_free((void **)&time_tmp);
+ }
+ if (ra->last_update_end_time == 0)
+ {
+ slapi_entry_add_string(e, "nsds5replicaLastUpdateEnd", "0");
+ }
+ else
+ {
+ time_tmp = format_genTime(ra->last_update_end_time);
+ slapi_entry_add_string(e, "nsds5replicaLastUpdateEnd", time_tmp);
+ slapi_ch_free((void **)&time_tmp);
+ }
+ agmt_get_changecount_string (ra, changecount_string, sizeof (changecount_string) );
+ slapi_entry_add_string(e, "nsds5replicaChangesSentSinceStartup", changecount_string);
+ if (ra->last_update_status[0] == '\0')
+ {
+ slapi_entry_add_string(e, "nsds5replicaLastUpdateStatus", "0 No replication sessions started since server startup");
+ }
+ else
+ {
+ slapi_entry_add_string(e, "nsds5replicaLastUpdateStatus", ra->last_update_status);
+ }
+ slapi_entry_add_string(e, "nsds5replicaUpdateInProgress", ra->update_in_progress ? "TRUE" : "FALSE");
+ if (ra->last_init_start_time == 0)
+ {
+ slapi_entry_add_string(e, "nsds5replicaLastInitStart", "0");
+ }
+ else
+ {
+ time_tmp = format_genTime(ra->last_init_start_time);
+ slapi_entry_add_string(e, "nsds5replicaLastInitStart", time_tmp);
+ slapi_ch_free((void **)&time_tmp);
+ }
+ if (ra->last_init_end_time == 0)
+ {
+ slapi_entry_add_string(e, "nsds5replicaLastInitEnd", "0");
+ }
+ else
+ {
+ time_tmp = format_genTime(ra->last_init_end_time);
+ slapi_entry_add_string(e, "nsds5replicaLastInitEnd", time_tmp);
+ slapi_ch_free((void **)&time_tmp);
+ }
+ if (ra->last_init_status[0] != '\0')
+ {
+ slapi_entry_add_string(e, "nsds5replicaLastInitStatus", ra->last_init_status);
+ }
+ }
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static void
+update_window_state_change_callback (void *arg, PRBool opened)
+{
+ Repl_Agmt *agmt = (Repl_Agmt*)arg;
+
+ PR_ASSERT (agmt);
+
+ if (opened)
+ {
+ prot_notify_window_opened (agmt->protocol);
+ }
+ else
+ {
+ prot_notify_window_closed (agmt->protocol);
+ }
+}
+
+ReplicaId
+agmt_get_consumer_rid ( Repl_Agmt *agmt, void *conn )
+{
+ if ( agmt->consumerRID <= 0 ) {
+
+ char mapping_tree_node[512];
+ struct berval **bvals = NULL;
+
+ PR_snprintf ( mapping_tree_node,
+ sizeof (mapping_tree_node),
+ "cn=replica,cn=\"%s\",cn=mapping tree,cn=config",
+ slapi_sdn_get_dn (agmt->replarea) );
+ conn_read_entry_attribute ( conn, mapping_tree_node, "nsDS5ReplicaID", &bvals );
+ if ( NULL != bvals && NULL != bvals[0] ) {
+ char *ridstr = slapi_ch_malloc( bvals[0]->bv_len + 1 );
+ memcpy ( ridstr, bvals[0]->bv_val, bvals[0]->bv_len );
+ ridstr[bvals[0]->bv_len] = '\0';
+ agmt->consumerRID = atoi (ridstr);
+ slapi_ch_free ( (void**) &ridstr );
+ ber_bvecfree ( bvals );
+ }
+ }
+
+ return agmt->consumerRID;
+}
diff --git a/ldap/servers/plugins/replication/repl5_agmtlist.c b/ldap/servers/plugins/replication/repl5_agmtlist.c
new file mode 100644
index 00000000..5c7213a6
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_agmtlist.c
@@ -0,0 +1,618 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl5_agmtlist.c */
+/*
+
+ Replication agreements are held in object set (objset.c).
+
+*/
+
+#include "repl5.h"
+
+#define AGMT_CONFIG_BASE "cn=mapping tree, cn=config"
+#define CONFIG_FILTER "(objectclass=nsds5replicationagreement)"
+
+PRCallOnceType once = {0};
+static Objset *agmt_set = NULL; /* The set of replication agreements */
+
+typedef struct agmt_wrapper {
+ Repl_Agmt *agmt;
+ void *handle;
+} agmt_wrapper;
+
+
+
+/*
+ * Find the replication agreement whose entry DN matches the given DN.
+ * Object is returned referenced, so be sure to release it when
+ * finished.
+ */
+Repl_Agmt *
+agmtlist_get_by_agmt_name(const Slapi_DN *agmt_name)
+{
+ Repl_Agmt *ra;
+ Object *ro;
+
+ for (ro = objset_first_obj(agmt_set); NULL != ro;
+ ro = objset_next_obj(agmt_set, ro))
+ {
+ ra = (Repl_Agmt *)object_get_data(ro);
+ if (agmt_matches_name(ra, agmt_name))
+ {
+ break;
+ }
+ }
+ return ra;
+}
+
+
+static int
+agmt_ptr_cmp(Object *ro, const void *arg)
+{
+ Repl_Agmt *ra;
+ Repl_Agmt *provided_ra = (Repl_Agmt *)arg;
+
+ ra = object_get_data(ro);
+
+ if (ra == provided_ra)
+ return 0;
+ else
+ return 1;
+}
+
+
+
+static int
+agmt_dn_cmp(Object *ro, const void *arg)
+{
+ Repl_Agmt *ra;
+ Slapi_DN *sdn = (Slapi_DN *)arg;
+
+ ra = object_get_data(ro);
+ return(slapi_sdn_compare(sdn, agmt_get_dn_byref(ra)));
+}
+
+void
+agmtlist_release_agmt(Repl_Agmt *ra)
+{
+ Object *ro;
+
+ PR_ASSERT(NULL != agmt_set);
+ PR_ASSERT(NULL != ra);
+
+ ro = objset_find(agmt_set, agmt_ptr_cmp, (const void *)ra);
+ if (NULL != ro)
+ {
+ /*
+ * Release twice - once for the reference we got when finding
+ * it, and once for the reference we got when we called
+ * agmtlist_get_*().
+ */
+ object_release(ro);
+ object_release(ro);
+ }
+}
+
+
+/*
+ * Note: when we add the new object, we have a reference to it. We hold
+ * on to this reference until the agreement is deleted (or until the
+ * server is shut down).
+ */
+static int
+add_new_agreement(Slapi_Entry *e)
+{
+ int rc = 0;
+ Repl_Agmt *ra = agmt_new_from_entry(e);
+ Slapi_DN *replarea_sdn = NULL;
+ Replica *replica = NULL;
+ Object *repl_obj = NULL;
+ Object *ro = NULL;
+
+ if (ra == NULL) return 0;
+
+ ro = object_new((void *)ra, agmt_delete);
+ objset_add_obj(agmt_set, ro);
+ object_release(ro); /* Object now owned by objset */
+
+ /* get the replica for this agreement */
+ replarea_sdn = agmt_get_replarea(ra);
+ repl_obj = replica_get_replica_from_dn(replarea_sdn);
+ slapi_sdn_free(&replarea_sdn);
+ if (repl_obj) {
+ replica = (Replica*)object_get_data (repl_obj);
+ }
+
+ rc = replica_start_agreement(replica, ra);
+
+ if (repl_obj) object_release(repl_obj);
+
+ return rc;
+}
+
+static int
+agmtlist_add_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter,
+ int *returncode, char *returntext, void *arg)
+{
+ int rc;
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmt_add: begin\n");
+
+ rc = add_new_agreement(e);
+ if (0 != rc) {
+ char *dn;
+ slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmtlist_add_callback: "
+ "Can't start agreement \"%s\"\n", dn);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static int
+agmtlist_modify_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *e,
+ int *returncode, char *returntext, void *arg)
+{
+ int i;
+ char *dn;
+ Slapi_DN *sdn = NULL;
+ int start_initialize = 0, stop_initialize = 0, cancel_initialize = 0;
+ int update_the_schedule = 0; /* do we need to update the repl sched? */
+ Repl_Agmt *agmt = NULL;
+ LDAPMod **mods;
+ char buff [BUFSIZ];
+ char *errortext = returntext ? returntext : buff;
+ int rc = SLAPI_DSE_CALLBACK_OK;
+ Slapi_Operation *op;
+ void *identity;
+
+ *returncode = LDAP_SUCCESS;
+
+ /* just let internal operations originated from replication plugin to go through */
+ slapi_pblock_get (pb, SLAPI_OPERATION, &op);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
+
+ if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
+ (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
+ {
+ goto done;
+ }
+
+ slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
+ sdn= slapi_sdn_new_dn_byref(dn);
+ agmt = agmtlist_get_by_agmt_name(sdn);
+ if (NULL == agmt)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmtlist_modify_callback: received "
+ "a modification for unknown replication agreement \"%s\"\n", dn);
+ goto done;
+ }
+
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ for (i = 0; NULL != mods && NULL != mods[i]; i++)
+ {
+ if (slapi_attr_types_equivalent(mods[i]->mod_type, type_nsds5ReplicaInitialize))
+ {
+ /* we don't allow delete attribute operations unless it was issued by
+ the replication plugin - handled above */
+ if (mods[i]->mod_op & LDAP_MOD_DELETE)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "deletion of %s attribute is not allowed\n", type_nsds5ReplicaInitialize);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ break;
+ }
+ else
+ {
+ char *val;
+
+ if (mods[i]->mod_bvalues && mods[i]->mod_bvalues[0])
+ val = slapi_berval_get_string_copy (mods[i]->mod_bvalues[0]);
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "no value provided for %s attribute\n", type_nsds5ReplicaInitialize);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ break;
+ }
+
+ /* Start replica initialization */
+ if (val == NULL)
+ {
+ sprintf (errortext, "No value supplied for attr (%s)", mods[i]->mod_type);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: %s\n",
+ errortext);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ break;
+ }
+
+ if (strcasecmp (val, "start") == 0)
+ {
+ start_initialize = 1;
+ }
+ else if (strcasecmp (val, "stop") == 0)
+ {
+ stop_initialize = 1;
+ }
+ else if (strcasecmp (val, "cancel") == 0)
+ {
+ cancel_initialize = 1;
+ }
+ else
+ {
+ sprintf (errortext, "Invalid value (%s) value supplied for attr (%s)",
+ val, mods[i]->mod_type);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: %s\n",
+ errortext);
+ }
+
+ slapi_ch_free ((void**)&val);
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5ReplicaUpdateSchedule))
+ {
+ /*
+ * Request to update the replication schedule. Set a flag so
+ * we know to update the schedule later.
+ */
+ update_the_schedule = 1;
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5ReplicaCredentials))
+ {
+ /* New replica credentials */
+ if (agmt_set_credentials_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update credentials for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5ReplicaTimeout))
+ {
+ /* New replica timeout */
+ if (agmt_set_timeout_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update timeout for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5ReplicaBusyWaitTime))
+ {
+ /* New replica busywaittime */
+ if (agmt_set_busywaittime_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update busy wait time for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5ReplicaSessionPauseTime))
+ {
+ /* New replica pausetime */
+ if (agmt_set_pausetime_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update session pause time for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5ReplicaBindDN))
+ {
+ /* New replica Bind DN */
+ if (agmt_set_binddn_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update bind DN for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5TransportInfo))
+ {
+ /* New Transport info */
+ if (agmt_set_transportinfo_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update transport info for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ type_nsds5ReplicaBindMethod))
+ {
+ /* New replica bind method */
+ if (agmt_set_bind_method_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update bind method for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if (slapi_attr_types_equivalent(mods[i]->mod_type,
+ "nsds5debugreplicatimeout"))
+ {
+ char *val = slapi_entry_attr_get_charptr(e, "nsds5debugreplicatimeout");
+ repl5_set_debug_timeout(val);
+ slapi_ch_free_string(&val);
+ }
+ else if (strcasecmp (mods[i]->mod_type, "modifytimestamp") == 0 ||
+ strcasecmp (mods[i]->mod_type, "modifiersname") == 0 ||
+ strcasecmp (mods[i]->mod_type, "description") == 0)
+ {
+ /* ignore modifier's name and timestamp attributes and the description. */
+ continue;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "modification of %s attribute is not allowed\n", mods[i]->mod_type);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ break;
+ }
+ }
+
+ if (stop_initialize)
+ {
+ agmt_stop (agmt);
+ }
+ else if (start_initialize)
+ {
+ if (agmt_initialize_replica(agmt) != 0) {
+ /* The suffix is disabled */
+ agmt_set_last_init_status(agmt, 0, NSDS50_REPL_DISABLED, NULL);
+ }
+ }
+ else if (cancel_initialize)
+ {
+ agmt_replica_init_done(agmt);
+ }
+
+ if (update_the_schedule)
+ {
+ if (agmt_set_schedule_from_entry(agmt, e) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_modify_callback: "
+ "failed to update replication schedule for agreement %s\n",
+ agmt_get_long_name(agmt));
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+
+done:
+ if (NULL != agmt)
+ {
+ agmtlist_release_agmt(agmt);
+ }
+
+ if (sdn)
+ slapi_sdn_free(&sdn);
+ return rc;
+}
+
+static int
+agmtlist_delete_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter,
+ int *returncode, char *returntext, void *arg)
+{
+ Repl_Agmt *ra;
+ Object *ro;
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_delete: begin\n");
+ ro = objset_find(agmt_set, agmt_dn_cmp, (const void *)slapi_entry_get_sdn_const(e));
+ ra = (NULL == ro) ? NULL : (Repl_Agmt *)object_get_data(ro);
+ if (NULL == ra)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmtlist_delete: "
+ "Tried to delete replication agreement \"%s\", but no such "
+ "agreement was configured.\n", slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)));
+ }
+ else
+ {
+ agmt_stop(ra);
+ object_release(ro); /* Release ref acquired in objset_find */
+ objset_remove_obj(agmt_set, ro); /* Releases a reference (should be final reference */
+ }
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static int
+agmtlist_rename_callback(Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *e,
+ int *returncode, char *returntext, void *arg)
+{
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "agmt_rename: begin\n");
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+static int
+handle_agmt_search(Slapi_Entry *e, void *callback_data)
+{
+ int *agmtcount = (int *)callback_data;
+ int rc;
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Found replication agreement named \"%s\".\n",
+ slapi_sdn_get_dn(slapi_entry_get_sdn(e)));
+ rc = add_new_agreement(e);
+ if (0 == rc)
+ {
+ (*agmtcount)++;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "The replication "
+ "agreement named \"%s\" could not be correctly parsed. No "
+ "replication will occur with this replica.\n",
+ slapi_sdn_get_dn(slapi_entry_get_sdn(e)));
+ }
+
+ return rc;
+}
+
+
+static void
+agmtlist_objset_destructor(void **o)
+{
+ /* XXXggood Nothing to do, I think. */
+}
+
+
+int
+agmtlist_config_init()
+{
+ Slapi_PBlock *pb;
+ int agmtcount = 0;
+
+ agmt_set = objset_new(agmtlist_objset_destructor);
+
+ /* Register callbacks so we're informed about updates */
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, AGMT_CONFIG_BASE,
+ LDAP_SCOPE_SUBTREE, CONFIG_FILTER, agmtlist_add_callback, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, AGMT_CONFIG_BASE,
+ LDAP_SCOPE_SUBTREE, CONFIG_FILTER, agmtlist_modify_callback, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, AGMT_CONFIG_BASE,
+ LDAP_SCOPE_SUBTREE, CONFIG_FILTER, agmtlist_delete_callback, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, AGMT_CONFIG_BASE,
+ LDAP_SCOPE_SUBTREE, CONFIG_FILTER, agmtlist_rename_callback, NULL);
+
+ /* Search the DIT and find all the replication agreements */
+ pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(pb, AGMT_CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, NULL /* attrs */, 0 /* attrsonly */,
+ NULL, /* controls */ NULL /* uniqueid */,
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0 /* actions */);
+ slapi_search_internal_callback_pb(pb,
+ (void *)&agmtcount /* callback data */,
+ NULL /* result_callback */,
+ handle_agmt_search /* search entry cb */,
+ NULL /* referral callback */);
+ slapi_pblock_destroy(pb);
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "agmtlist_config_init: found %d replication agreements in DIT\n", agmtcount);
+
+ return 0;
+}
+
+
+
+void
+agmtlist_shutdown()
+{
+ Repl_Agmt *ra;
+ Object *ro;
+ Object *next_ro;
+
+ ro = objset_first_obj(agmt_set);
+ while (NULL != ro)
+ {
+ next_ro = objset_next_obj(agmt_set, ro);
+ ra = (Repl_Agmt *)object_get_data(ro);
+ agmt_stop(ra);
+ agmt_update_consumer_ruv (ra);
+ objset_remove_obj(agmt_set, ro);
+ ro = next_ro;
+ }
+ objset_delete(&agmt_set);
+ agmt_set = NULL;
+}
+
+
+
+/*
+ * Notify each replication agreement about an update.
+ */
+void
+agmtlist_notify_all(Slapi_PBlock *pb)
+{
+ Repl_Agmt *ra;
+ Object *ro;
+
+ if (NULL != agmt_set)
+ {
+ ro = objset_first_obj(agmt_set);
+ while (NULL != ro)
+ {
+ ra = (Repl_Agmt *)object_get_data(ro);
+ agmt_notify_change(ra, pb);
+ ro = objset_next_obj(agmt_set, ro);
+ }
+ }
+}
+
+Object* agmtlist_get_first_agreement_for_replica (Replica *r)
+{
+ return agmtlist_get_next_agreement_for_replica (r, NULL) ;
+}
+
+Object* agmtlist_get_next_agreement_for_replica (Replica *r, Object *prev)
+{
+ const Slapi_DN *replica_root;
+ Slapi_DN *agmt_root;
+ Object *obj;
+ Repl_Agmt *agmt;
+
+ if (r == NULL)
+ {
+ /* ONREPL - log error */
+ return NULL;
+ }
+
+ replica_root = replica_get_root(r);
+
+ if (prev)
+ obj = objset_next_obj(agmt_set, prev);
+ else
+ obj = objset_first_obj(agmt_set);
+
+ while (obj)
+ {
+ agmt = (Repl_Agmt*)object_get_data (obj);
+ PR_ASSERT (agmt);
+
+ agmt_root = agmt_get_replarea(agmt);
+ PR_ASSERT (agmt_root);
+
+ if (slapi_sdn_compare (replica_root, agmt_root) == 0)
+ {
+ slapi_sdn_free (&agmt_root);
+ return obj;
+ }
+
+ slapi_sdn_free (&agmt_root);
+ obj = objset_next_obj(agmt_set, obj);
+ }
+
+ return NULL;
+}
diff --git a/ldap/servers/plugins/replication/repl5_backoff.c b/ldap/servers/plugins/replication/repl5_backoff.c
new file mode 100644
index 00000000..d0a90878
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_backoff.c
@@ -0,0 +1,232 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl5_backoff.c */
+/*
+
+ The backoff object implements a backoff timer. The timer can operate
+ with a fixed interval, an expontially increasing interval, or a
+ random interval.
+
+ The caller creates a new backoff timer, specifying the backoff behavior
+ desired (fixed, exponential, or random), the initial backoff value,
+ and the maximum backoff interval. This does not start the timer - the
+ backoff_reset() function must be used to actually start the timer.
+
+ The backoff_reset() function takes an optional function that
+ will be called when the backoff time has expired, and a void *
+ that can be used to pass arguments into the callback function.
+
+ When the time expires, the callback function will be called. If no
+ callback function has been provided, the timer simply expires.
+ A timer does not recompute the next interval and begin timing until
+ the backoff_step() function is called. Therefore, callers that
+ do not install a callback function may use the timer by polling.
+ When a callback function is provided, the timer is typically reset
+ inside the callback function.
+
+*/
+
+#include "repl5.h"
+
+
+typedef struct backoff_timer {
+ int type;
+ int running;
+ slapi_eq_fn_t callback;
+ void *callback_arg;
+ time_t initial_interval;
+ time_t next_interval;
+ time_t max_interval;
+ time_t last_fire_time;
+ Slapi_Eq_Context pending_event;
+ PRLock *lock;
+
+} backoff_timer;
+
+/* Forward declarations */
+static PRIntervalTime random_interval_in_range(time_t lower_bound, time_t upper_bound);
+
+
+/*
+ Create a new backoff timer. The timer is initialized, but is not
+ started.
+ */
+Backoff_Timer *
+backoff_new(int timer_type, int initial_interval, int max_interval)
+{
+ Backoff_Timer *bt;
+
+ bt = (Backoff_Timer *)slapi_ch_calloc(1, sizeof(struct backoff_timer));
+ bt->type = timer_type;
+ bt->initial_interval = initial_interval;
+ bt->next_interval = bt->initial_interval;
+ bt->max_interval = max_interval;
+ bt->running = 0;
+ if ((bt->lock = PR_NewLock()) == NULL)
+ {
+ slapi_ch_free((void **)&bt);
+ }
+ return bt;
+}
+
+
+/*
+ * Reset and start the timer. Returns the time (as a time_t) when the
+ * time will next expire.
+ */
+time_t
+backoff_reset(Backoff_Timer *bt, slapi_eq_fn_t callback, void *callback_data)
+{
+ time_t return_value = 0UL;
+
+ PR_ASSERT(NULL != bt);
+ PR_ASSERT(NULL != callback);
+
+ PR_Lock(bt->lock);
+ bt->running = 1;
+ bt->callback = callback;
+ bt->callback_arg = callback_data;
+ /* Cancel any pending events in the event queue */
+ if (NULL != bt->pending_event)
+ {
+ slapi_eq_cancel(bt->pending_event);
+ bt->pending_event = NULL;
+ }
+ /* Compute the first fire time */
+ if (BACKOFF_RANDOM == bt->type)
+ {
+ bt->next_interval = random_interval_in_range(bt->initial_interval,
+ bt->max_interval);
+ }
+ else
+ {
+ bt->next_interval = bt->initial_interval;
+ }
+ /* Schedule the callback */
+ time(&bt->last_fire_time);
+ return_value = bt->last_fire_time + bt->next_interval;
+ bt->pending_event = slapi_eq_once(bt->callback, bt->callback_arg,
+ return_value);
+ PR_Unlock(bt->lock);
+ return return_value;
+}
+
+
+/*
+ Step the timer - compute the new backoff interval and start
+ counting. Note that the next expiration time is based on the
+ last timer expiration time, *not* the current time.
+
+ Returns the time (as a time_t) when the timer will next expire.
+ */
+time_t
+backoff_step(Backoff_Timer *bt)
+{
+ time_t return_value = 0UL;
+
+ PR_ASSERT(NULL != bt);
+
+ /* If the timer has never been reset, then return 0 */
+ PR_Lock(bt->lock);
+ if (bt->running)
+ {
+ time_t previous_interval = bt->next_interval;
+ switch (bt->type) {
+ case BACKOFF_FIXED:
+ /* Interval stays the same */
+ break;
+ case BACKOFF_EXPONENTIAL:
+ /* Interval doubles, up to a maximum */
+ if (bt->next_interval < bt->max_interval)
+ {
+ bt->next_interval *= 2;
+ if (bt->next_interval > bt->max_interval)
+ {
+ bt->next_interval = bt->max_interval;
+ }
+ }
+ break;
+ case BACKOFF_RANDOM:
+ /* Compute the new random interval time */
+ bt->next_interval = random_interval_in_range(bt->initial_interval,
+ bt->max_interval);
+ break;
+ }
+ /* Schedule the callback, if any */
+ bt->last_fire_time += previous_interval;
+ return_value = bt->last_fire_time + bt->next_interval;
+ bt->pending_event = slapi_eq_once(bt->callback, bt->callback_arg,
+ return_value);
+ }
+ PR_Unlock(bt->lock);
+ return return_value;
+}
+
+
+/*
+ * Return 1 if the backoff timer has expired, 0 otherwise.
+ */
+int
+backoff_expired(Backoff_Timer *bt, int margin)
+{
+ int return_value = 0;
+
+ PR_ASSERT(NULL != bt);
+ PR_Lock(bt->lock);
+ return_value = (current_time() >= (bt->last_fire_time + bt->next_interval + margin));
+ PR_Unlock(bt->lock);
+ return return_value;
+}
+
+
+/*
+ Destroy and deallocate a timer object
+ */
+void
+backoff_delete(Backoff_Timer **btp)
+{
+ Backoff_Timer *bt;
+
+ PR_ASSERT(NULL != btp && NULL != *btp);
+ bt = *btp;
+ PR_Lock(bt->lock);
+ /* Cancel any pending events in the event queue */
+ if (NULL != bt->pending_event)
+ {
+ slapi_eq_cancel(bt->pending_event);
+ }
+ PR_Unlock(bt->lock);
+ PR_DestroyLock(bt->lock);
+ slapi_ch_free((void **)btp);
+}
+
+
+/*
+ * Return the next fire time for the timer.
+ */
+time_t
+backoff_get_next_fire_time(Backoff_Timer *bt)
+{
+ time_t return_value;
+
+ PR_ASSERT(NULL != bt);
+ PR_Lock(bt->lock);
+ return_value = bt->last_fire_time + bt->next_interval;
+ PR_Unlock(bt->lock);
+ return return_value;
+}
+
+static PRIntervalTime
+random_interval_in_range(time_t lower_bound, time_t upper_bound)
+{
+ /*
+ * slapi_rand() provides some entropy from two or three system timer
+ * calls (depending on the platform) down in NSS. If more entropy is
+ * required, slapi_rand_r(unsigned int *seed) can be called instead.
+ */
+ return(lower_bound + (slapi_rand() % (upper_bound - lower_bound)));
+}
+
diff --git a/ldap/servers/plugins/replication/repl5_connection.c b/ldap/servers/plugins/replication/repl5_connection.c
new file mode 100644
index 00000000..a50c163a
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_connection.c
@@ -0,0 +1,1493 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_connection.c */
+/*
+
+ The connection object manages a connection to a single replication
+ consumer.
+
+XXXggood what to do on timeout? If we close connection, then we won't leave a
+replica locked. Seems like right thing to do.
+*/
+
+#include "repl5.h"
+#include "ldappr.h"
+
+typedef struct repl_connection
+{
+ char *hostname;
+ int port;
+ char *binddn;
+ int bindmethod;
+ int state;
+ int last_operation;
+ int last_ldap_error;
+ const char *status;
+ char *last_ldap_errmsg;
+ PRUint32 transport_flags;
+ LDAP *ld;
+ int supports_ldapv3; /* 1 if does, 0 if doesn't, -1 if not determined */
+ int supports_ds50_repl; /* 1 if does, 0 if doesn't, -1 if not determined */
+ int supports_ds40_repl; /* 1 if does, 0 if doesn't, -1 if not determined */
+ int linger_time; /* time in seconds to leave an idle connection open */
+ PRBool linger_active;
+ Slapi_Eq_Context *linger_event;
+ PRBool delete_after_linger;
+ int refcnt;
+ const Repl_Agmt *agmt;
+ PRLock *lock;
+ struct timeval timeout;
+ int flag_agmt_changed;
+ char *plain;
+} repl_connection;
+
+/* #define DEFAULT_LINGER_TIME (5 * 60) */ /* 5 minutes */
+#define DEFAULT_LINGER_TIME (60)
+
+/* Controls we add on every outbound operation */
+
+static LDAPControl manageDSAITControl = {LDAP_CONTROL_MANAGEDSAIT, {0, ""}, '\0'};
+static int attribute_string_value_present(LDAP *ld, LDAPMessage *entry,
+ const char *type, const char *value);
+static int bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password);
+static int do_simple_bind (Repl_Connection *conn, LDAP *ld, char * binddn, char *password);
+
+static int s_debug_timeout = 0;
+static int s_debug_level = 0;
+static Slapi_Eq_Context repl5_start_debug_timeout(int *setlevel);
+static void repl5_stop_debug_timeout(Slapi_Eq_Context eqctx, int *setlevel);
+static void repl5_debug_timeout_callback(time_t when, void *arg);
+#ifndef DSE_RETURNTEXT_SIZE
+#define SLAPI_DSE_RETURNTEXT_SIZE 512
+#endif
+
+#define STATE_CONNECTED 600
+#define STATE_DISCONNECTED 601
+
+#define STATUS_DISCONNECTED "disconnected"
+#define STATUS_CONNECTED "connected"
+#define STATUS_PROCESSING_ADD "processing add operation"
+#define STATUS_PROCESSING_DELETE "processing delete operation"
+#define STATUS_PROCESSING_MODIFY "processing modify operation"
+#define STATUS_PROCESSING_RENAME "processing rename operation"
+#define STATUS_PROCESSING_EXTENDED_OPERATION "processing extended operation"
+#define STATUS_LINGERING "lingering"
+#define STATUS_SHUTTING_DOWN "shutting down"
+#define STATUS_BINDING "connecting and binding"
+#define STATUS_SEARCHING "processing search operation"
+
+#define CONN_NO_OPERATION 0
+#define CONN_ADD 1
+#define CONN_DELETE 2
+#define CONN_MODIFY 3
+#define CONN_RENAME 4
+#define CONN_EXTENDED_OPERATION 5
+#define CONN_BIND 6
+#define CONN_INIT 7
+
+/* These are errors returned from ldap operations which should cause us to disconnect and
+ retry the connection later */
+#define IS_DISCONNECT_ERROR(rc) (rc == LDAP_SERVER_DOWN || rc == LDAP_CONNECT_ERROR || rc == LDAP_INVALID_CREDENTIALS || rc == LDAP_INAPPROPRIATE_AUTH || rc == LDAP_LOCAL_ERROR)
+
+/* Forward declarations */
+static void close_connection_internal(Repl_Connection *conn);
+
+/*
+ * Create a new conenction object. Returns a pointer to the object, or
+ * NULL if an error occurs.
+ */
+Repl_Connection *
+conn_new(Repl_Agmt *agmt)
+{
+ Repl_Connection *rpc;
+
+ rpc = (Repl_Connection *)slapi_ch_malloc(sizeof(repl_connection));
+ if ((rpc->lock = PR_NewLock()) == NULL)
+ {
+ goto loser;
+ }
+ rpc->hostname = agmt_get_hostname(agmt);
+ rpc->port = agmt_get_port(agmt);
+ rpc->binddn = agmt_get_binddn(agmt);
+ rpc->bindmethod = agmt_get_bindmethod(agmt);
+ rpc->transport_flags = agmt_get_transport_flags(agmt);
+ rpc->ld = NULL;
+ rpc->state = STATE_DISCONNECTED;
+ rpc->last_operation = CONN_NO_OPERATION;
+ rpc->last_ldap_error = LDAP_SUCCESS;
+ rpc->last_ldap_errmsg = NULL;
+ rpc->supports_ldapv3 = -1;
+ rpc->supports_ds40_repl = -1;
+ rpc->supports_ds50_repl = -1;
+ rpc->linger_active = PR_FALSE;
+ rpc->delete_after_linger = PR_FALSE;
+ rpc->linger_event = NULL;
+ rpc->linger_time = DEFAULT_LINGER_TIME;
+ rpc->status = STATUS_DISCONNECTED;
+ rpc->agmt = agmt;
+ rpc->refcnt = 1;
+ rpc->timeout.tv_sec = agmt_get_timeout(agmt);
+ rpc->timeout.tv_usec = 0;
+ rpc->flag_agmt_changed = 0;
+ rpc->plain = NULL;
+ return rpc;
+loser:
+ conn_delete(rpc);
+ return NULL;
+}
+
+
+/*
+ * Return PR_TRUE if the connection is in the connected state
+ */
+static PRBool
+conn_connected(Repl_Connection *conn)
+{
+ PRBool return_value;
+ PR_Lock(conn->lock);
+ return_value = STATE_CONNECTED == conn->state;
+ PR_Unlock(conn->lock);
+ return return_value;
+}
+
+
+/*
+ * Destroy a connection object.
+ */
+static void
+conn_delete_internal(Repl_Connection *conn)
+{
+ PR_ASSERT(NULL != conn);
+ close_connection_internal(conn);
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free((void **)&conn->hostname);
+ slapi_ch_free((void **)&conn->binddn);
+ slapi_ch_free((void **)&conn->plain);
+}
+
+/*
+ * Destroy a connection. It is an error to use the connection object
+ * after conn_delete() has been called.
+ */
+void
+conn_delete(Repl_Connection *conn)
+{
+ PRBool destroy_it = PR_FALSE;
+
+ PR_ASSERT(NULL != conn);
+ PR_Lock(conn->lock);
+ if (conn->linger_active)
+ {
+ if (slapi_eq_cancel(conn->linger_event) == 1)
+ {
+ /* Event was found and cancelled. Destroy the connection object. */
+ PR_Unlock(conn->lock);
+ destroy_it = PR_TRUE;
+ }
+ else
+ {
+ /*
+ * The event wasn't found, but we think it's still active.
+ * That means an event is in the process of being fired
+ * off, so arrange for the event to destroy the object .
+ */
+ conn->delete_after_linger = PR_TRUE;
+ PR_Unlock(conn->lock);
+ }
+ }
+ if (destroy_it)
+ {
+ conn_delete_internal(conn);
+ }
+}
+
+
+/*
+ * Return the last operation type processed by the connection
+ * object, and the LDAP error encountered.
+ */
+void
+conn_get_error(Repl_Connection *conn, int *operation, int *error)
+{
+ PR_Lock(conn->lock);
+ *operation = conn->last_operation;
+ *error = conn->last_ldap_error;
+ PR_Unlock(conn->lock);
+}
+
+
+/*
+ * Common code to send an LDAPv3 operation and collect the result.
+ * Return values:
+ * CONN_OPERATION_SUCCESS - the operation succeeded
+ * CONN_OPERATION_FAILED - the operation was sent to the consumer
+ * and failed. Use conn_get_error() to determine the LDAP error
+ * code.
+ * CONN_NOT_CONNECTED - no connection is active. The caller should
+ * use conn_connect() to connect to the replica and bind, then should
+ * reacquire the replica (if needed).
+ * CONN_BUSY - the server is busy with previous requests, must wait for a while
+ * before retrying
+ */
+static ConnResult
+perform_operation(Repl_Connection *conn, int optype, const char *dn,
+ LDAPMod **attrs, const char *newrdn, const char *newparent,
+ int deleteoldrdn, LDAPControl *update_control,
+ const char *extop_oid, struct berval *extop_payload, char **retoidp,
+ struct berval **retdatap, LDAPControl ***returned_controls)
+{
+ int rc;
+ ConnResult return_value;
+ LDAPControl *server_controls[3];
+ LDAPControl **loc_returned_controls;
+ const char *op_string = NULL;
+ const char *extra_op_string = NULL;
+
+ server_controls[0] = &manageDSAITControl;
+ server_controls[1] = update_control;
+ server_controls[2] = NULL;
+
+ if (conn_connected(conn))
+ {
+ int msgid;
+
+ conn->last_operation = optype;
+ switch (optype)
+ {
+ case CONN_ADD:
+ conn->status = STATUS_PROCESSING_ADD;
+ op_string = "add";
+ rc = ldap_add_ext(conn->ld, dn, attrs, server_controls,
+ NULL /* clientctls */, &msgid);
+ break;
+ case CONN_MODIFY:
+ conn->status = STATUS_PROCESSING_MODIFY;
+ op_string = "modify";
+ rc = ldap_modify_ext(conn->ld, dn, attrs, server_controls,
+ NULL /* clientctls */, &msgid);
+ break;
+ case CONN_DELETE:
+ conn->status = STATUS_PROCESSING_DELETE;
+ op_string = "delete";
+ rc = ldap_delete_ext(conn->ld, dn, server_controls,
+ NULL /* clientctls */, &msgid);
+ break;
+ case CONN_RENAME:
+ conn->status = STATUS_PROCESSING_RENAME;
+ op_string = "rename";
+ rc = ldap_rename(conn->ld, dn, newrdn, newparent, deleteoldrdn,
+ server_controls, NULL /* clientctls */, &msgid);
+ break;
+ case CONN_EXTENDED_OPERATION:
+ conn->status = STATUS_PROCESSING_EXTENDED_OPERATION;
+ op_string = "extended";
+ extra_op_string = extop_oid;
+ rc = ldap_extended_operation(conn->ld, extop_oid, extop_payload,
+ server_controls, NULL /* clientctls */, &msgid);
+ }
+ if (LDAP_SUCCESS == rc)
+ {
+ LDAPMessage *res = NULL;
+ int setlevel = 0;
+ Slapi_Eq_Context eqctx = repl5_start_debug_timeout(&setlevel);
+
+ rc = ldap_result(conn->ld, msgid, 1, &conn->timeout, &res);
+ repl5_stop_debug_timeout(eqctx, &setlevel);
+ if (0 == rc)
+ {
+ /* Timeout */
+ rc = ldap_get_lderrno(conn->ld, NULL, NULL);
+ conn->last_ldap_error = LDAP_TIMEOUT;
+ return_value = CONN_TIMEOUT;
+ }
+ else if (-1 == rc)
+ {
+ /* Error */
+ char *s = NULL;
+
+ rc = ldap_get_lderrno(conn->ld, NULL, &s);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Received error %d: %s for %s operation\n",
+ agmt_get_long_name(conn->agmt),
+ rc, s ? s : "NULL",
+ op_string ? op_string : "NULL");
+ conn->last_ldap_error = rc;
+ /* some errors will require a disconnect and retry the connection
+ later */
+ if (IS_DISCONNECT_ERROR(rc))
+ {
+ conn_disconnect(conn);
+ return_value = CONN_NOT_CONNECTED;
+ }
+ else
+ {
+ conn->status = STATUS_CONNECTED;
+ return_value = CONN_OPERATION_FAILED;
+ }
+ }
+ else
+ {
+ int err;
+ char *errmsg = NULL;
+ char **referrals = NULL;
+ char *matched = NULL;
+
+ rc = ldap_parse_result(conn->ld, res, &err, &matched,
+ &errmsg, &referrals, &loc_returned_controls,
+ 0 /* Don't free the result */);
+ if (IS_DISCONNECT_ERROR(rc))
+ {
+ conn->last_ldap_error = rc;
+ conn_disconnect(conn);
+ return_value = CONN_NOT_CONNECTED;
+ }
+ else if (IS_DISCONNECT_ERROR(err))
+ {
+ conn->last_ldap_error = err;
+ conn_disconnect(conn);
+ return_value = CONN_NOT_CONNECTED;
+ }
+ /* Got a result */
+ else if (CONN_EXTENDED_OPERATION == optype)
+ {
+ if ((rc == LDAP_SUCCESS) && (err == LDAP_BUSY))
+ return_value = CONN_BUSY;
+ else {
+ if (rc == LDAP_SUCCESS) {
+ rc = ldap_parse_extended_result(conn->ld, res, retoidp,
+ retdatap, 0 /* Don't Free it */);
+ }
+ conn->last_ldap_error = rc;
+ return_value = (LDAP_SUCCESS == conn->last_ldap_error ?
+ CONN_OPERATION_SUCCESS : CONN_OPERATION_FAILED);
+ }
+ }
+ else /* regular operation, result returned */
+ {
+ if (NULL != returned_controls)
+ {
+ *returned_controls = loc_returned_controls;
+ }
+ if (LDAP_SUCCESS != rc)
+ {
+ conn->last_ldap_error = rc;
+ }
+ else
+ {
+ conn->last_ldap_error = err;
+ }
+ return_value = LDAP_SUCCESS == conn->last_ldap_error ? CONN_OPERATION_SUCCESS : CONN_OPERATION_FAILED;
+ }
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Received result code %d for %s operation %s%s\n",
+ agmt_get_long_name(conn->agmt),
+ conn->last_ldap_error,
+ op_string == NULL ? "" : op_string,
+ extra_op_string == NULL ? "" : extra_op_string,
+ extra_op_string == NULL ? "" : " ");
+ /*
+ * XXXggood do I need to free matched, referrals,
+ * anything else? Or can I pass NULL for the args
+ * I'm not interested in?
+ */
+ /* Good question! Meanwhile, as RTM aproaches, let's free them... */
+ slapi_ch_free((void **) &errmsg);
+ slapi_ch_free((void **) &matched);
+ charray_free(referrals);
+ conn->status = STATUS_CONNECTED;
+ }
+ if (res) ldap_msgfree(res);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Failed to send %s operation: LDAP error %d (%s)\n",
+ agmt_get_long_name(conn->agmt),
+ op_string ? op_string : "NULL", rc, ldap_err2string(rc));
+ conn->last_ldap_error = rc;
+ if (IS_DISCONNECT_ERROR(rc))
+ {
+ conn_disconnect(conn);
+ return_value = CONN_NOT_CONNECTED;
+ }
+ else
+ {
+ conn->status = STATUS_CONNECTED;
+ return_value = CONN_OPERATION_FAILED;
+ }
+ }
+ }
+ else
+ {
+ /* conn->last_ldap_error has been set to a more specific value
+ * in conn_connected()
+ * conn->last_ldap_error = LDAP_SERVER_DOWN;
+ */
+ return_value = CONN_NOT_CONNECTED;
+ }
+ return return_value;
+}
+
+/*
+ * Send an LDAP add operation.
+ */
+ConnResult
+conn_send_add(Repl_Connection *conn, const char *dn, LDAPMod **attrs,
+ LDAPControl *update_control, LDAPControl ***returned_controls)
+{
+ return perform_operation(conn, CONN_ADD, dn, attrs, NULL /* newrdn */,
+ NULL /* newparent */, 0 /* deleteoldrdn */, update_control,
+ NULL /* extop OID */, NULL /* extop payload */, NULL /* retoidp */,
+ NULL /* retdatap */, returned_controls);
+}
+
+
+/*
+ * Send an LDAP delete operation.
+ */
+ConnResult
+conn_send_delete(Repl_Connection *conn, const char *dn,
+ LDAPControl *update_control, LDAPControl ***returned_controls)
+{
+ return perform_operation(conn, CONN_DELETE, dn, NULL /* attrs */,
+ NULL /* newrdn */, NULL /* newparent */, 0 /* deleteoldrdn */,
+ update_control, NULL /* extop OID */, NULL /* extop payload */,
+ NULL /* retoidp */, NULL /* retdatap */, returned_controls);
+}
+
+
+/*
+ * Send an LDAP modify operation.
+ */
+ConnResult
+conn_send_modify(Repl_Connection *conn, const char *dn, LDAPMod **mods,
+ LDAPControl *update_control, LDAPControl ***returned_controls)
+{
+ return perform_operation(conn, CONN_MODIFY, dn, mods, NULL /* newrdn */,
+ NULL /* newparent */, 0 /* deleteoldrdn */, update_control,
+ NULL /* extop OID */, NULL /* extop payload */, NULL /* retoidp */,
+ NULL /* retdatap */, returned_controls);
+}
+
+/*
+ * Send an LDAP moddn operation.
+ */
+ConnResult
+conn_send_rename(Repl_Connection *conn, const char *dn,
+ const char *newrdn, const char *newparent, int deleteoldrdn,
+ LDAPControl *update_control, LDAPControl ***returned_controls)
+{
+ return perform_operation(conn, CONN_RENAME, dn, NULL /* attrs */,
+ newrdn, newparent, deleteoldrdn, update_control,
+ NULL /* extop OID */, NULL /* extop payload */, NULL /* retoidp */,
+ NULL /* retdatap */, returned_controls);
+}
+
+
+/*
+ * Send an LDAP extended operation.
+ */
+ConnResult
+conn_send_extended_operation(Repl_Connection *conn, const char *extop_oid,
+ struct berval *payload, char **retoidp, struct berval **retdatap,
+ LDAPControl *update_control, LDAPControl ***returned_controls)
+{
+ return perform_operation(conn, CONN_EXTENDED_OPERATION, NULL /* dn */, NULL /* attrs */,
+ NULL /* newrdn */, NULL /* newparent */, 0 /* deleteoldrdn */,
+ update_control, extop_oid, payload, retoidp, retdatap,
+ returned_controls);
+}
+
+
+/*
+ * Synchronously read an entry and return a specific attribute's values.
+ * Returns CONN_OPERATION_SUCCESS if successful. Returns
+ * CONN_OPERATION_FAILED if the operation was sent but an LDAP error
+ * occurred (conn->last_ldap_error is set in this case), and
+ * CONN_NOT_CONNECTED if no connection was active.
+ *
+ * The caller must free the returned_bvals.
+ */
+ConnResult
+conn_read_entry_attribute(Repl_Connection *conn, const char *dn,
+ char *type, struct berval ***returned_bvals)
+{
+ ConnResult return_value;
+ int ldap_rc;
+ LDAPControl *server_controls[2];
+ LDAPMessage *res = NULL;
+ char *attrs[2];
+
+ PR_ASSERT(NULL != type);
+ if (conn_connected(conn))
+ {
+ server_controls[0] = &manageDSAITControl;
+ server_controls[1] = NULL;
+ attrs[0] = type;
+ attrs[1] = NULL;
+ ldap_rc = ldap_search_ext_s(conn->ld, dn, LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, 0 /* attrsonly */,
+ server_controls, NULL /* client controls */,
+ &conn->timeout, 0 /* sizelimit */, &res);
+ if (LDAP_SUCCESS == ldap_rc)
+ {
+ LDAPMessage *entry = ldap_first_entry(conn->ld, res);
+ if (NULL != entry)
+ {
+ *returned_bvals = ldap_get_values_len(conn->ld, entry, type);
+ }
+ return_value = CONN_OPERATION_SUCCESS;
+ }
+ else if (IS_DISCONNECT_ERROR(ldap_rc))
+ {
+ conn_disconnect(conn);
+ return_value = CONN_NOT_CONNECTED;
+ }
+ else
+ {
+ return_value = CONN_OPERATION_FAILED;
+ }
+ conn->last_ldap_error = ldap_rc;
+ if (NULL != res)
+ {
+ ldap_msgfree(res);
+ res = NULL;
+ }
+ }
+ else
+ {
+ return_value = CONN_NOT_CONNECTED;
+ }
+ return return_value;
+}
+
+
+/*
+ * Return an pointer to a string describing the connection's status.
+*/
+
+const char *
+conn_get_status(Repl_Connection *conn)
+{
+ return conn->status;
+}
+
+
+
+/*
+ * Cancel any outstanding linger timer. Should be called when
+ * a replication session is beginning.
+ */
+void
+conn_cancel_linger(Repl_Connection *conn)
+{
+ PR_ASSERT(NULL != conn);
+ PR_Lock(conn->lock);
+ if (conn->linger_active)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Cancelling linger on the connection\n",
+ agmt_get_long_name(conn->agmt));
+ conn->linger_active = PR_FALSE;
+ if (slapi_eq_cancel(conn->linger_event) == 1)
+ {
+ conn->refcnt--;
+ }
+ conn->linger_event = NULL;
+ conn->status = STATUS_CONNECTED;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: No linger to cancel on the connection\n",
+ agmt_get_long_name(conn->agmt));
+ }
+ PR_Unlock(conn->lock);
+}
+
+
+/*
+ * Called when our linger timeout timer expires. This means
+ * we should check to see if perhaps the connection's become
+ * active again, in which case we do nothing. Otherwise,
+ * we close the connection.
+ */
+static void
+linger_timeout(time_t event_time, void *arg)
+{
+ PRBool delete_now;
+ Repl_Connection *conn = (Repl_Connection *)arg;
+
+ PR_ASSERT(NULL != conn);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Linger timeout has expired on the connection\n",
+ agmt_get_long_name(conn->agmt));
+ PR_Lock(conn->lock);
+ if (conn->linger_active)
+ {
+ conn->linger_active = PR_FALSE;
+ conn->linger_event = NULL;
+ close_connection_internal(conn);
+ }
+ delete_now = conn->delete_after_linger;
+ PR_Unlock(conn->lock);
+ if (delete_now)
+ {
+ conn_delete_internal(conn);
+ }
+}
+
+
+/*
+ * Indicate that a session is ending. The linger timer starts when
+ * this function is called.
+ */
+void
+conn_start_linger(Repl_Connection *conn)
+{
+ time_t now;
+
+ PR_ASSERT(NULL != conn);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Beginning linger on the connection\n",
+ agmt_get_long_name(conn->agmt));
+ if (!conn_connected(conn))
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: No linger on the closed conn\n",
+ agmt_get_long_name(conn->agmt));
+ return;
+ }
+ time(&now);
+ PR_Lock(conn->lock);
+ if (conn->linger_active)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Linger already active on the connection\n",
+ agmt_get_long_name(conn->agmt));
+ }
+ else
+ {
+ conn->linger_active = PR_TRUE;
+ conn->linger_event = slapi_eq_once(linger_timeout, conn, now + conn->linger_time);
+ conn->status = STATUS_LINGERING;
+ }
+ PR_Unlock(conn->lock);
+}
+
+
+
+/*
+ * If no connection is currently active, opens a connection and binds to
+ * the remote server. If a connection is open (e.g. lingering) then
+ * this is a no-op.
+ *
+ * Returns CONN_OPERATION_SUCCESS on success, or CONN_OPERATION_FAILED
+ * on failure. Sets conn->last_ldap_error and conn->last_operation;
+ */
+ConnResult
+conn_connect(Repl_Connection *conn)
+{
+ int ldap_rc;
+ int optdata;
+ int secure = 0;
+ char* binddn = NULL;
+ struct berval *creds;
+ ConnResult return_value = CONN_OPERATION_SUCCESS;
+ int pw_ret = 1;
+
+ /** Connection already open just return SUCCESS **/
+ if(conn->state == STATE_CONNECTED) return return_value;
+
+ PR_Lock(conn->lock);
+ if (conn->flag_agmt_changed) {
+ /* So far we cannot change Hostname and Port */
+ /* slapi_ch_free((void **)&conn->hostname); */
+ /* conn->hostname = agmt_get_hostname(conn->agmt); */
+ /* conn->port = agmt_get_port(conn->agmt); */
+ slapi_ch_free((void **)&conn->binddn);
+ conn->binddn = agmt_get_binddn(conn->agmt);
+ conn->bindmethod = agmt_get_bindmethod(conn->agmt);
+ conn->transport_flags = agmt_get_transport_flags(conn->agmt);
+ conn->timeout.tv_sec = agmt_get_timeout(conn->agmt);
+ conn->flag_agmt_changed = 0;
+ slapi_ch_free((void **)&conn->plain);
+ }
+ PR_Unlock(conn->lock);
+
+ creds = agmt_get_credentials(conn->agmt);
+
+ if (conn->plain == NULL) {
+
+ char *plain = NULL;
+
+ /* kexcoff: for reversible encryption */
+ /* We need to test the return code of pw_rever_decode in order to decide
+ * if a free for plain will be needed (pw_ret == 0) or not (pw_ret != 0) */
+ pw_ret = pw_rever_decode(creds->bv_val, &plain, type_nsds5ReplicaCredentials);
+ /* Pb occured in decryption: stop now, binding will fail */
+ if ( pw_ret == -1 )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Decoding of the credentials failed.\n",
+ agmt_get_long_name(conn->agmt));
+
+ return_value = CONN_OPERATION_FAILED;
+ conn->last_ldap_error = LDAP_INVALID_CREDENTIALS;
+ conn->state = STATE_DISCONNECTED;
+ return (return_value);
+ } /* Else, does not mean that the plain is correct, only means the we had no internal
+ decoding pb */
+ conn->plain = slapi_ch_strdup (plain);
+ if (!pw_ret) slapi_ch_free((void**)&plain);
+ }
+
+
+ /* ugaston: if SSL has been selected in the replication agreement, SSL client
+ * initialisation should be done before ever trying to open any connection at all.
+ */
+ if (conn->transport_flags == TRANSPORT_FLAG_TLS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Replication secured by StartTLS not currently supported\n",
+ agmt_get_long_name(conn->agmt));
+
+ return_value = CONN_OPERATION_FAILED;
+ conn->last_ldap_error = LDAP_STRONG_AUTH_NOT_SUPPORTED;
+ conn->state = STATE_DISCONNECTED;
+ } else if(conn->transport_flags == TRANSPORT_FLAG_SSL)
+ {
+
+ /** Make sure the SSL Library has been initialized before anything else **/
+ if(slapd_security_library_is_initialized() != 1)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: SSL Not Initialized, Replication over SSL FAILED\n",
+ agmt_get_long_name(conn->agmt));
+ conn->last_ldap_error = LDAP_INAPPROPRIATE_AUTH;
+ conn->last_operation = CONN_INIT;
+ ber_bvfree(creds);
+ creds = NULL;
+ return CONN_SSL_NOT_ENABLED;
+ } else
+ {
+ secure = 1;
+ }
+ }
+
+ if (return_value == CONN_OPERATION_SUCCESS) {
+ int io_timeout_ms;
+ /* Now we initialize the LDAP Structure and set options */
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Trying %s slapi_ldap_init\n",
+ agmt_get_long_name(conn->agmt),
+ secure ? "secure" : "non-secure");
+
+ conn->ld = slapi_ldap_init(conn->hostname, conn->port, secure, 0);
+ if (NULL == conn->ld)
+ {
+ return_value = CONN_OPERATION_FAILED;
+ conn->state = STATE_DISCONNECTED;
+ conn->last_operation = CONN_INIT;
+ conn->last_ldap_error = LDAP_LOCAL_ERROR;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Failed to establish %sconnection to the consumer\n",
+ agmt_get_long_name(conn->agmt),
+ secure ? "secure " : "");
+ ber_bvfree(creds);
+ creds = NULL;
+ return return_value;
+ }
+
+ /* slapi_ch_strdup is OK with NULL strings */
+ binddn = slapi_ch_strdup(conn->binddn);
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: binddn = %s, passwd = %s\n",
+ agmt_get_long_name(conn->agmt),
+ binddn?binddn:"NULL", creds->bv_val?creds->bv_val:"NULL");
+
+ /* Set some options for the connection. */
+ optdata = LDAP_DEREF_NEVER; /* Don't dereference aliases */
+ ldap_set_option(conn->ld, LDAP_OPT_DEREF, &optdata);
+
+ optdata = LDAP_VERSION3; /* We need LDAP version 3 */
+ ldap_set_option(conn->ld, LDAP_OPT_PROTOCOL_VERSION, &optdata);
+
+ /* Don't chase any referrals (although we shouldn't get any) */
+ ldap_set_option(conn->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
+
+ /* override the default timeout with the specified timeout */
+ io_timeout_ms = conn->timeout.tv_sec * 1000 + conn->timeout.tv_usec / 1000;
+ prldap_set_session_option(conn->ld, NULL, PRLDAP_OPT_IO_MAX_TIMEOUT,
+ io_timeout_ms);
+
+ /* We've got an ld. Now bind to the server. */
+ conn->last_operation = CONN_BIND;
+
+ }
+
+ if ( bind_and_check_pwp(conn, binddn, conn->plain) == CONN_OPERATION_FAILED )
+ {
+ conn->last_ldap_error = ldap_get_lderrno (conn->ld, NULL, NULL);
+ conn->state = STATE_DISCONNECTED;
+ return_value = CONN_OPERATION_FAILED;
+ }
+ else
+ {
+ conn->last_ldap_error = ldap_rc = LDAP_SUCCESS;
+ conn->state = STATE_CONNECTED;
+ return_value = CONN_OPERATION_SUCCESS;
+ }
+
+
+ ber_bvfree(creds);
+ creds = NULL;
+
+ slapi_ch_free((void**)&binddn);
+
+ if(return_value == CONN_OPERATION_FAILED)
+ {
+ close_connection_internal(conn);
+ } else
+ {
+ conn->last_ldap_error = ldap_rc = LDAP_SUCCESS;
+ conn->state = STATE_CONNECTED;
+ }
+
+ return return_value;
+}
+
+
+static void
+close_connection_internal(Repl_Connection *conn)
+{
+ if (NULL != conn->ld)
+ {
+ /* Since we call slapi_ldap_init,
+ we must call slapi_ldap_unbind */
+ slapi_ldap_unbind(conn->ld);
+ }
+ conn->ld = NULL;
+ conn->state = STATE_DISCONNECTED;
+ conn->status = STATUS_DISCONNECTED;
+ conn->supports_ds50_repl = -1;
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Disconnected from the consumer\n", agmt_get_long_name(conn->agmt));
+}
+
+void
+conn_disconnect(Repl_Connection *conn)
+{
+ PR_ASSERT(NULL != conn);
+ PR_Lock(conn->lock);
+ close_connection_internal(conn);
+ PR_Unlock(conn->lock);
+}
+
+
+/*
+ * Determine if the remote replica supports DS 5.0 replication.
+ * Return codes:
+ * CONN_SUPPORTS_DS5_REPL - the remote replica suport DS5 replication
+ * CONN_DOES_NOT_SUPPORT_DS5_REPL - the remote replica does not
+ * support DS5 replication.
+ * CONN_OPERATION_FAILED - it could not be determined if the remote
+ * replica supports DS5 replication.
+ * CONN_NOT_CONNECTED - no connection was active.
+ */
+ConnResult
+conn_replica_supports_ds5_repl(Repl_Connection *conn)
+{
+ ConnResult return_value;
+ int ldap_rc;
+
+ if (conn_connected(conn))
+ {
+ if (conn->supports_ds50_repl == -1) {
+ LDAPMessage *res = NULL;
+ LDAPMessage *entry = NULL;
+ char *attrs[] = {"supportedcontrol", "supportedextension", NULL};
+
+ conn->status = STATUS_SEARCHING;
+ ldap_rc = ldap_search_ext_s(conn->ld, "", LDAP_SCOPE_BASE,
+ "(objectclass=*)", attrs, 0 /* attrsonly */,
+ NULL /* server controls */, NULL /* client controls */,
+ &conn->timeout, LDAP_NO_LIMIT, &res);
+ if (LDAP_SUCCESS == ldap_rc)
+ {
+ conn->supports_ds50_repl = 0;
+ entry = ldap_first_entry(conn->ld, res);
+ if (!attribute_string_value_present(conn->ld, entry, "supportedcontrol", REPL_NSDS50_UPDATE_INFO_CONTROL_OID))
+ {
+ return_value = CONN_DOES_NOT_SUPPORT_DS5_REPL;
+ }
+ else if (!attribute_string_value_present(conn->ld, entry, "supportedextension", REPL_START_NSDS50_REPLICATION_REQUEST_OID))
+ {
+ return_value = CONN_DOES_NOT_SUPPORT_DS5_REPL;
+ }
+ else if (!attribute_string_value_present(conn->ld, entry, "supportedextension", REPL_END_NSDS50_REPLICATION_REQUEST_OID))
+ {
+ return_value = CONN_DOES_NOT_SUPPORT_DS5_REPL;
+ }
+ else if (!attribute_string_value_present(conn->ld, entry, "supportedextension", REPL_NSDS50_REPLICATION_ENTRY_REQUEST_OID))
+ {
+ return_value = CONN_DOES_NOT_SUPPORT_DS5_REPL;
+ }
+ else if (!attribute_string_value_present(conn->ld, entry, "supportedextension", REPL_NSDS50_REPLICATION_RESPONSE_OID))
+ {
+ return_value = CONN_DOES_NOT_SUPPORT_DS5_REPL;
+ }
+ else
+ {
+ conn->supports_ds50_repl = 1;
+ return_value = CONN_SUPPORTS_DS5_REPL;
+ }
+ }
+ else
+ {
+ if (IS_DISCONNECT_ERROR(ldap_rc))
+ {
+ conn->last_ldap_error = ldap_rc; /* specific reason */
+ conn_disconnect(conn);
+ return_value = CONN_NOT_CONNECTED;
+ }
+ else
+ {
+ return_value = CONN_OPERATION_FAILED;
+ }
+ }
+ if (NULL != res)
+ ldap_msgfree(res);
+ }
+ else {
+ return_value = conn->supports_ds50_repl ? CONN_SUPPORTS_DS5_REPL : CONN_DOES_NOT_SUPPORT_DS5_REPL;
+ }
+ }
+ else
+ {
+ /* Not connected */
+ return_value = CONN_NOT_CONNECTED;
+ }
+ return return_value;
+}
+
+
+
+
+
+/*
+ * Return 1 if "value" is a value of attribute type "type" in entry "entry".
+ * Otherwise, return 0.
+ */
+static int
+attribute_string_value_present(LDAP *ld, LDAPMessage *entry, const char *type,
+ const char *value)
+{
+ int return_value = 0;
+
+ if (NULL != entry)
+ {
+ char *atype = NULL;
+ BerElement *ber = NULL;
+
+ atype = ldap_first_attribute(ld, entry, &ber);
+ while (NULL != atype && 0 == return_value)
+ {
+ if (strcasecmp(atype, type) == 0)
+ {
+ char **strvals = ldap_get_values(ld, entry, atype);
+ int i;
+ for (i = 0; return_value == 0 && NULL != strvals && NULL != strvals[i]; i++)
+ {
+ if (strcmp(strvals[i], value) == 0)
+ {
+ return_value = 1;
+ }
+ }
+ if (NULL != strvals)
+ {
+ ldap_value_free(strvals);
+ }
+ }
+ ldap_memfree(atype);
+ atype = ldap_next_attribute(ld, entry, ber);
+ }
+ if (NULL != ber)
+ ldap_ber_free(ber, 0);
+ /* The last atype has not been freed yet */
+ if (NULL != atype)
+ ldap_memfree(atype);
+ }
+ return return_value;
+}
+
+
+
+
+/*
+ * Read the remote server's schema entry, then read the local schema entry,
+ * and compare the nsschemacsn attribute. If the local csn is newer, or
+ * the remote csn is absent, push the schema down to the consumer.
+ * Return codes:
+ * CONN_SCHEMA_UPDATED if the schema was pushed successfully
+ * CONN_SCHEMA_NO_UPDATE_NEEDED if the schema was as new or newer than
+ * the local server's schema
+ * CONN_OPERATION_FAILED if an error occurred
+ * CONN_NOT_CONNECTED if no connection was active
+ * NOTE: Should only be called when a replication session has been
+ * established by sending a startReplication extended operation.
+ */
+ConnResult
+conn_push_schema(Repl_Connection *conn, CSN **remotecsn)
+{
+ ConnResult return_value = CONN_OPERATION_SUCCESS;
+ char *nsschemacsn = "nsschemacsn";
+ Slapi_Entry **entries = NULL;
+ Slapi_Entry *schema_entry = NULL;
+ int push_schema = 1; /* Assume we need to push for now */
+ int local_error = 0; /* No local error encountered yet */
+ int remote_error = 0; /* No remote error encountered yet */
+ CSN *localcsn = NULL;
+ Slapi_PBlock *spb = NULL;
+ char localcsnstr[CSN_STRSIZE + 1] = {0};
+
+ if (!conn_connected(conn))
+ {
+ return_value = CONN_NOT_CONNECTED;
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Schema replication update failed: not connected to consumer\n",
+ agmt_get_long_name(conn->agmt));
+ }
+ else
+ {
+ localcsn = dup_global_schema_csn();
+ if (NULL == localcsn)
+ {
+ /* Local server has epoch CSN, so don't push schema */
+ return_value = CONN_SCHEMA_NO_UPDATE_NEEDED;
+ }
+ else if ( remotecsn && *remotecsn && csn_compare(localcsn, *remotecsn) <= 0 )
+ {
+ /* Local server schema is not newer than the remote one */
+ return_value = CONN_SCHEMA_NO_UPDATE_NEEDED;
+ }
+ else
+ {
+ struct berval **remote_schema_csn_bervals = NULL;
+ /* Get remote server's schema */
+ return_value = conn_read_entry_attribute(conn, "cn=schema", nsschemacsn,
+ &remote_schema_csn_bervals);
+ if (CONN_OPERATION_SUCCESS == return_value)
+ {
+ if (NULL != remote_schema_csn_bervals && NULL != remote_schema_csn_bervals[0])
+ {
+ char remotecsnstr[CSN_STRSIZE + 1] = {0};
+ memcpy(remotecsnstr, remote_schema_csn_bervals[0]->bv_val,
+ remote_schema_csn_bervals[0]->bv_len);
+ remotecsnstr[remote_schema_csn_bervals[0]->bv_len] = '\0';
+ *remotecsn = csn_new_by_string(remotecsnstr);
+ if (NULL != remotecsn && (csn_compare(localcsn, *remotecsn) <= 0))
+ {
+ return_value = CONN_SCHEMA_NO_UPDATE_NEEDED;
+ }
+ /* Need to free the remote_schema_csn_bervals */
+ ber_bvecfree(remote_schema_csn_bervals);
+ }
+ }
+ }
+ }
+ if (CONN_OPERATION_SUCCESS == return_value)
+ {
+ /* We know we need to push the schema out. */
+ LDAPMod ocmod = {0};
+ LDAPMod atmod = {0};
+ LDAPMod csnmod = {0};
+ LDAPMod *attrs[4] = {0};
+ int numvalues = 0;
+ Slapi_Attr *attr = NULL;
+ char *csnvalues[2];
+
+ ocmod.mod_type = "objectclasses";
+ ocmod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
+ ocmod.mod_bvalues = NULL;
+ atmod.mod_type = "attributetypes";
+ atmod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
+ atmod.mod_bvalues = NULL;
+ csnmod.mod_type = nsschemacsn;
+ csnmod.mod_op = LDAP_MOD_REPLACE;
+ csn_as_string (localcsn, PR_FALSE, localcsnstr);
+ csnvalues[0] = localcsnstr;
+ csnvalues[1] = NULL;
+ csnmod.mod_values = csnvalues;
+ attrs[0] = &ocmod;
+ attrs[1] = &atmod;
+ attrs[2] = &csnmod;
+ attrs[3] = NULL;
+
+ return_value = CONN_OPERATION_FAILED; /* assume failure */
+
+ /* Get local schema */
+ spb = slapi_search_internal("cn=schema", LDAP_SCOPE_BASE, "(objectclass=*)",
+ NULL /* controls */, NULL /* schema_csn_attrs */, 0 /* attrsonly */);
+ slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0])
+ {
+ /* Whoops - couldn't read our own schema! */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Error: unable to read local schema definitions.\n",
+ agmt_get_long_name(conn->agmt));
+ return_value = CONN_OPERATION_FAILED;
+ }
+ else
+ {
+ schema_entry = entries[0];
+ if (slapi_entry_attr_find(schema_entry, "objectclasses", &attr) != -1)
+ {
+ int i, ind;
+ Slapi_Value *value;
+ slapi_attr_get_numvalues(attr, &numvalues);
+ ocmod.mod_bvalues = (struct berval **)slapi_ch_malloc((numvalues + 1) *
+ sizeof(struct berval *));
+ for (i = 0, ind = slapi_attr_first_value(attr, &value);
+ ind != -1; ind = slapi_attr_next_value(attr, ind, &value), i++)
+ {
+ /* XXXggood had to cast away const below */
+ ocmod.mod_bvalues[i] = (struct berval *)slapi_value_get_berval(value);
+ }
+ ocmod.mod_bvalues[numvalues] = NULL;
+ if (slapi_entry_attr_find(schema_entry, "attributetypes", &attr) != -1)
+ {
+ ConnResult result;
+ slapi_attr_get_numvalues(attr, &numvalues);
+ atmod.mod_bvalues = (struct berval **)slapi_ch_malloc((numvalues + 1) *
+ sizeof(struct berval *));
+ for (i = 0, ind = slapi_attr_first_value(attr, &value);
+ ind != -1; ind = slapi_attr_next_value(attr, ind, &value), i++)
+ {
+ /* XXXggood had to cast away const below */
+ atmod.mod_bvalues[i] = (struct berval *)slapi_value_get_berval(value);
+ }
+ atmod.mod_bvalues[numvalues] = NULL;
+
+ result = conn_send_modify(conn, "cn=schema", attrs, NULL, NULL);
+ switch (result)
+ {
+ case CONN_OPERATION_FAILED:
+ {
+ int ldaperr = -1, optype = -1;
+ conn_get_error(conn, &optype, &ldaperr);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Schema replication update failed: %s\n",
+ agmt_get_long_name(conn->agmt),
+ ldaperr == -1 ? "Unknown Error" : ldap_err2string(ldaperr));
+ }
+ case CONN_NOT_CONNECTED:
+ return_value = CONN_NOT_CONNECTED;
+ break;
+ case CONN_OPERATION_SUCCESS:
+ return_value = CONN_SCHEMA_UPDATED;
+ break;
+ }
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Schema replication update failed: "
+ "unable to prepare schema entry for transmission.\n",
+ agmt_get_long_name(conn->agmt));
+ }
+ }
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free((void **)&ocmod.mod_bvalues);
+ slapi_ch_free((void **)&atmod.mod_bvalues);
+ }
+ if (NULL != spb)
+ {
+ slapi_free_search_results_internal(spb);
+ slapi_pblock_destroy(spb);
+ spb = NULL;
+ }
+ if (NULL != localcsn)
+ {
+ csn_free(&localcsn);
+ }
+ return return_value;
+}
+
+void
+conn_set_timeout(Repl_Connection *conn, long timeout)
+{
+ PR_ASSERT(NULL != conn);
+ PR_ASSERT(timeout >= 0);
+ PR_Lock(conn->lock);
+ conn->timeout.tv_sec = timeout;
+ PR_Unlock(conn->lock);
+}
+
+void conn_set_agmt_changed(Repl_Connection *conn)
+{
+ PR_ASSERT(NULL != conn);
+ PR_Lock(conn->lock);
+ if (NULL != conn->agmt)
+ conn->flag_agmt_changed = 1;
+ PR_Unlock(conn->lock);
+}
+
+/*
+ * Check the result of an ldap_simple_bind operation to see we it
+ * contains the expiration controls
+ * return: -1 error, not bound
+ * 0, OK bind has succeeded
+ */
+static int
+bind_and_check_pwp(Repl_Connection *conn, char * binddn, char *password)
+{
+
+ LDAPControl **ctrls = NULL;
+ LDAPMessage *res = NULL;
+ char *errmsg = NULL;
+ LDAP *ld = conn->ld;
+ int msgid;
+ int *msgidAdr = &msgid;
+ int rc;
+
+ char * optype; /* ldap_simple_bind or slapd_SSL_client_bind */
+
+ if ( conn->transport_flags == TRANSPORT_FLAG_SSL )
+ {
+ char *auth;
+ optype = "ldap_sasl_bind";
+
+ if ( conn->bindmethod == BINDMETHOD_SSL_CLIENTAUTH )
+ {
+ rc = slapd_sasl_ext_client_bind(conn->ld, &msgidAdr);
+ auth = "SSL client authentication";
+
+ if ( rc == LDAP_SUCCESS )
+ {
+ if (conn->last_ldap_error != rc)
+ {
+ conn->last_ldap_error = rc;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Replication bind with %s resumed\n",
+ agmt_get_long_name(conn->agmt), auth);
+ }
+ }
+ else
+ {
+ /* Do not report the same error over and over again */
+ if (conn->last_ldap_error != rc)
+ {
+ conn->last_ldap_error = rc;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Replication bind with %s failed: LDAP error %d (%s)\n",
+ agmt_get_long_name(conn->agmt), auth, rc,
+ ldap_err2string(rc));
+ }
+
+ return (CONN_OPERATION_FAILED);
+ }
+ }
+ else
+ {
+ if( ( msgid = do_simple_bind( conn, ld, binddn, password ) ) == -1 )
+ {
+ return (CONN_OPERATION_FAILED);
+ }
+ }
+ }
+ else
+ {
+ optype = "ldap_simple_bind";
+ if( ( msgid = do_simple_bind( conn, ld, binddn, password ) ) == -1 )
+ {
+ return (CONN_OPERATION_FAILED);
+ }
+ }
+
+ /* Wait for the result */
+ if ( ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &res ) == -1 )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Received error from consumer for %s operation\n",
+ agmt_get_long_name(conn->agmt), optype);
+
+ return (CONN_OPERATION_FAILED);
+ }
+ /* Don't check ldap_result against 0 because, no timeout is specified */
+
+ /* Free res as we won't use it any longer */
+ if ( ldap_parse_result( ld, res, &rc, NULL, NULL, NULL, &ctrls, 1 /* Free res */)
+ != LDAP_SUCCESS )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Received error from consumer for %s operation\n",
+ agmt_get_long_name(conn->agmt), optype);
+
+ return (CONN_OPERATION_FAILED);
+ }
+
+ if ( rc == LDAP_SUCCESS )
+ {
+ if ( ctrls )
+ {
+ int i;
+ for( i = 0; ctrls[ i ] != NULL; ++i )
+ {
+ if ( !(strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_PWEXPIRED)) )
+ {
+ /* Bind is successfull but password has expired */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Succesfully bound %s to consumer, "
+ "but password has expired on consumer.\n",
+ agmt_get_long_name(conn->agmt), binddn);
+ }
+ else if ( !(strcmp( ctrls[ i ]->ldctl_oid, LDAP_CONTROL_PWEXPIRING)) )
+ {
+ /* The password is expiring in n seconds */
+ if ( (ctrls[ i ]->ldctl_value.bv_val != NULL) &&
+ (ctrls[ i ]->ldctl_value.bv_len > 0) )
+ {
+ int password_expiring = atoi( ctrls[ i ]->ldctl_value.bv_val );
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Succesfully bound %s to consumer, "
+ "but password is expiring on consumer in %d seconds.\n",
+ agmt_get_long_name(conn->agmt), binddn, password_expiring);
+ }
+ }
+ }
+ ldap_controls_free( ctrls );
+ }
+
+ return (CONN_OPERATION_SUCCESS);
+ }
+ else
+ {
+ /* errmsg is a pointer directly into the ld structure - do not free */
+ rc = ldap_get_lderrno( ld, NULL, &errmsg );
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Replication bind to %s on consumer failed: %d (%s)\n",
+ agmt_get_long_name(conn->agmt), binddn, rc, errmsg);
+
+ conn->last_ldap_error = rc; /* specific error */
+ return (CONN_OPERATION_FAILED);
+ }
+}
+
+static int
+do_simple_bind (Repl_Connection *conn, LDAP *ld, char * binddn, char *password)
+{
+ int msgid;
+
+ if( ( msgid = ldap_simple_bind( ld, binddn, password ) ) == -1 )
+ {
+ char *ldaperrtext = NULL;
+ int ldaperr;
+ int prerr = PR_GetError();
+
+ ldaperr = ldap_get_lderrno( ld, NULL, &ldaperrtext );
+ /* Do not report the same error over and over again */
+ if (conn->last_ldap_error != ldaperr)
+ {
+ conn->last_ldap_error = ldaperr;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Simple bind failed, "
+ SLAPI_COMPONENT_NAME_LDAPSDK " error %d (%s), "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ agmt_get_long_name(conn->agmt),
+ ldaperr, ldaperrtext ? ldaperrtext : ldap_err2string(ldaperr),
+ prerr, slapd_pr_strerror(prerr));
+ }
+ }
+ else if (conn->last_ldap_error != LDAP_SUCCESS)
+ {
+ conn->last_ldap_error = LDAP_SUCCESS;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Simple bind resumed\n",
+ agmt_get_long_name(conn->agmt));
+ }
+ return msgid;
+}
+
+void
+repl5_set_debug_timeout(const char *val)
+{
+ /* val looks like this: seconds[:debuglevel] */
+ /* seconds is the number of seconds to wait until turning on the debug level */
+ /* this should be less than the ldap connection timeout (default 10 minutes) */
+ /* the optional debug level is the error log debugging level to use (default repl) */
+ if (val) {
+ const char *p = strchr(val, ':');
+ s_debug_timeout = atoi(val);
+ if (p) {
+ s_debug_level = atoi(p+1);
+ } else {
+ s_debug_level = 8192;
+ }
+ }
+}
+
+static time_t
+PRTime2time_t (PRTime tm)
+{
+ PRInt64 rt;
+
+ PR_ASSERT (tm);
+
+ LL_DIV(rt, tm, PR_USEC_PER_SEC);
+
+ return (time_t)rt;
+}
+
+static Slapi_Eq_Context
+repl5_start_debug_timeout(int *setlevel)
+{
+ Slapi_Eq_Context eqctx = 0;
+ if (s_debug_timeout && s_debug_level) {
+ time_t now = time(NULL);
+ eqctx = slapi_eq_once(repl5_debug_timeout_callback, setlevel,
+ s_debug_timeout + now);
+ }
+ return eqctx;
+}
+
+static void
+repl5_stop_debug_timeout(Slapi_Eq_Context eqctx, int *setlevel)
+{
+ char buf[20];
+ char msg[SLAPI_DSE_RETURNTEXT_SIZE];
+
+ if (eqctx && !*setlevel) {
+ int found = slapi_eq_cancel(eqctx);
+ }
+
+ if (s_debug_timeout && s_debug_level && *setlevel) {
+ void config_set_errorlog_level(const char *type, char *buf, char *msg, int apply);
+ sprintf(buf, "%d", 0);
+ config_set_errorlog_level("nsslapd-errorlog-level", buf, msg, 1);
+ }
+}
+
+static void
+repl5_debug_timeout_callback(time_t when, void *arg)
+{
+ int *setlevel = (int *)arg;
+ void config_set_errorlog_level(const char *type, char *buf, char *msg, int apply);
+ char buf[20];
+ char msg[SLAPI_DSE_RETURNTEXT_SIZE];
+
+ *setlevel = 1;
+ sprintf(buf, "%d", s_debug_level);
+ config_set_errorlog_level("nsslapd-errorlog-level", buf, msg, 1);
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "repl5_debug_timeout_callback: set debug level to %d at %d\n",
+ s_debug_level, when);
+}
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
new file mode 100644
index 00000000..a9905a34
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -0,0 +1,1759 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_inc_protocol.c */
+/*
+
+ The Prot_Incremental object implements the DS 5.0 multi-master incremental
+ replication protocol.
+
+
+Stuff to do:
+
+- Need to figure out how asynchronous events end up in here. They are:
+ - entry updated in replicated area.
+ - backoff timeout
+ - enter/leave.
+
+Perhaps these events should be properties of the main protocol.
+*/
+
+#include "repl.h"
+#include "repl5.h"
+#include "repl5_ruv.h"
+#include "repl5_prot_private.h"
+#include "cl5_api.h"
+
+extern int slapi_log_urp;
+
+/*** from proto-slap.h ***/
+void ava_done(struct ava *ava);
+
+typedef struct repl5_inc_private
+{
+ char *ruv; /* RUV on remote replica (use diff type for this? - ggood */
+ Backoff_Timer *backoff;
+ Repl_Protocol *rp;
+ PRLock *lock;
+ PRUint32 eventbits;
+} repl5_inc_private;
+
+
+/* Various states the incremental protocol can pass through */
+#define STATE_START 0 /* ONREPL - should we rename this - we don't use it just to start up? */
+#define STATE_WAIT_WINDOW_OPEN 1
+#define STATE_WAIT_CHANGES 2
+#define STATE_READY_TO_ACQUIRE 3
+#define STATE_BACKOFF_START 4 /* ONREPL - can we combine BACKOFF_START and BACKOFF states? */
+#define STATE_BACKOFF 5
+#define STATE_SENDING_UPDATES 6
+#define STATE_STOP_FATAL_ERROR 7
+#define STATE_STOP_FATAL_ERROR_PART2 8
+#define STATE_STOP_NORMAL_TERMINATION 9
+
+/* Events (synchronous and asynchronous; these are bits) */
+#define EVENT_WINDOW_OPENED 1
+#define EVENT_WINDOW_CLOSED 2
+#define EVENT_TRIGGERING_CRITERIA_MET 4 /* ONREPL - should we rename this to EVENT_CHANGE_AVAILABLE */
+#define EVENT_BACKOFF_EXPIRED 8
+#define EVENT_REPLICATE_NOW 16
+#define EVENT_PROTOCOL_SHUTDOWN 32
+#define EVENT_AGMT_CHANGED 64
+
+#define UPDATE_NO_MORE_UPDATES 201
+#define UPDATE_TRANSIENT_ERROR 202
+#define UPDATE_FATAL_ERROR 203
+#define UPDATE_SCHEDULE_WINDOW_CLOSED 204
+#define UPDATE_CONNECTION_LOST 205
+#define UPDATE_TIMEOUT 206
+#define UPDATE_YIELD 207
+
+/* Return codes from examine_update_vector */
+#define EXAMINE_RUV_PRISTINE_REPLICA 401
+#define EXAMINE_RUV_GENERATION_MISMATCH 402
+#define EXAMINE_RUV_REPLICA_TOO_OLD 403
+#define EXAMINE_RUV_OK 404
+#define EXAMINE_RUV_PARAM_ERROR 405
+
+#define MAX_CHANGES_PER_SESSION 10000
+/*
+ * Maximum time to wait between replication sessions. If we
+ * don't see any updates for a period equal to this interval,
+ * we go ahead and start a replication session, just to be safe
+ */
+#define MAX_WAIT_BETWEEN_SESSIONS PR_SecondsToInterval(60 * 5) /* 5 minutes */
+
+/*
+ * tests if the protocol has been shutdown and we need to quit
+ * event_occurred resets the bits in the bit flag, so whoever tests for shutdown
+ * resets the flags, so the next one who tests for shutdown won't get it, so we
+ * also look at the terminate flag
+ */
+#define PROTOCOL_IS_SHUTDOWN(prp) (event_occurred(prp, EVENT_PROTOCOL_SHUTDOWN) || prp->terminate)
+
+/* Forward declarations */
+static PRUint32 event_occurred(Private_Repl_Protocol *prp, PRUint32 event);
+static void reset_events (Private_Repl_Protocol *prp);
+static void protocol_sleep(Private_Repl_Protocol *prp, PRIntervalTime duration);
+static int send_updates(Private_Repl_Protocol *prp, RUV *ruv, PRUint32 *num_changes_sent);
+static void repl5_inc_backoff_expired(time_t timer_fire_time, void *arg);
+static int examine_update_vector(Private_Repl_Protocol *prp, RUV *ruv);
+static PRBool ignore_error_and_keep_going(int error);
+static const char* state2name (int state);
+static const char* event2name (int event);
+static const char* op2string (int op);
+
+/*
+ * It's specifically ok to delete a protocol instance that
+ * is currently running. The instance will be shut down, and
+ * then resources will be freed. Since a graceful shutdown is
+ * attempted, this function may take some time to complete.
+ */
+static void
+repl5_inc_delete(Private_Repl_Protocol **prpp)
+{
+ /* First, stop the protocol if it isn't already stopped */
+ /* Then, delete all resources used by the protocol */
+}
+
+/* helper function */
+void
+set_pause_and_busy_time(long *pausetime, long *busywaittime)
+{
+ /* If neither are set, set busy time to its default */
+ if (!*pausetime && !*busywaittime)
+ {
+ *busywaittime = PROTOCOL_BUSY_BACKOFF_MINIMUM;
+ }
+ /* pause time must be at least 1 more than the busy backoff time */
+ if (*pausetime && !*busywaittime)
+ {
+ /*
+ * user specified a pause time but no busy wait time - must
+ * set busy wait time to 1 less than pause time - if pause
+ * time is 1, we must set it to 2
+ */
+ if (*pausetime < 2)
+ {
+ *pausetime = 2;
+ }
+ *busywaittime = *pausetime - 1;
+ }
+ else if (!*pausetime && *busywaittime)
+ {
+ /*
+ * user specified a busy wait time but no pause time - must
+ * set pause time to 1 more than busy wait time
+ */
+ *pausetime = *busywaittime + 1;
+ }
+ else if (*pausetime && *busywaittime && *pausetime <= *busywaittime)
+ {
+ /*
+ * user specified both pause and busy wait times, but the pause
+ * time was <= busy wait time - pause time must be at least
+ * 1 more than the busy wait time
+ */
+ *pausetime = *busywaittime + 1;
+ }
+}
+
+/*
+ * Do the incremental protocol.
+ *
+ * What's going on here? This thing is a state machine. It has the
+ * following states:
+ *
+ * State transition table:
+ *
+ * Curr State Condition/Event Next State
+ * ---------- ------------ -----------
+ * START schedule window is open ACQUIRE_REPLICA
+ * schedule window is closed WAIT_WINDOW_OPEN
+ * WAIT_WINDOW_OPEN schedule change START
+ * replicate now ACQUIRE_REPLICA
+ * schedule window opens ACQUIRE_REPLICA
+ * ACQUIRE_REPLICA acquired replica SEND_CHANGES
+ * failed to acquire - transient error START_BACKOFF
+ * failed to acquire - fatal error STOP_FATAL_ERROR
+ * SEND_CHANGES can't update CONSUMER_NEEDS_REINIT
+ * no changes to send WAIT_CHANGES
+ * can't send - thransient error START_BACKOF
+ * can't send - window closed WAIT_WINDOW_OPEN
+ * can'r send - fatal error STOP_FATAL_ERROR
+ * START_BACKOF replicate now ACQUIRE_REPLICA
+ * schedule changes START
+ * schedule window closes WAIT_WINDOW_OPEN
+ * backoff expires & can acquire SEND_CHANGES
+ * backoff expires & can't acquire-trans BACKOFF
+ * backoff expires & can't acquire-fatal STOP_FATAL_ERROR
+ * BACKOF replicate now ACQUIRE_REPLICA
+ * schedule changes START
+ * schedule window closes WAIT_WINDOW_OPEN
+ * backoff expires & can acquire SEND_CHANGES
+ * backoff expires & can't acquire-trans BACKOFF
+ * backoff expires & can't acquire-fatal STOP_FATAL_ERROR
+ * WAIT_CHANGES schedule window closes WAIT_WINDOW_OPEN
+ * replicate_now ACQUIRE_REPLICA
+ * change available ACQUIRE_REPLICA
+ * schedule_change START
+ */
+
+/*
+ * Main state machine for the incremental protocol. This routine will,
+ * under normal circumstances, not return until the protocol is shut
+ * down.
+ */
+static void
+repl5_inc_run(Private_Repl_Protocol *prp)
+{
+ int current_state = STATE_START;
+ int next_state = STATE_START;
+ repl5_inc_private *prp_priv = (repl5_inc_private *)prp->private;
+ int done;
+ int e1;
+ RUV *ruv = NULL;
+ CSN *cons_schema_csn;
+ Replica *replica;
+ int wait_change_timer_set = 0;
+ time_t last_start_time;
+ PRUint32 num_changes_sent;
+ char *hostname = NULL;
+ int portnum = 0;
+ /* use a different backoff timer strategy for ACQUIRE_REPLICA_BUSY errors */
+ PRBool use_busy_backoff_timer = PR_FALSE;
+ long pausetime = 0;
+ long busywaittime = 0;
+
+ prp->stopped = 0;
+ prp->terminate = 0;
+ hostname = agmt_get_hostname(prp->agmt);
+ portnum = agmt_get_port(prp->agmt);
+
+ /* establish_protocol_callbacks(prp); */
+ done = 0;
+ do {
+ int rc;
+
+ /* Take action, based on current state, and compute new state. */
+ switch (current_state)
+ {
+ case STATE_START:
+
+ dev_debug("repl5_inc_run(STATE_START)");
+ if (PROTOCOL_IS_SHUTDOWN(prp))
+ {
+ done = 1;
+ break;
+ }
+
+ /*
+ * Our initial state. See if we're in a schedule window. If
+ * so, then we're ready to acquire the replica and see if it
+ * needs any updates from us. If not, then wait for the window
+ * to open.
+ */
+ if (agmt_schedule_in_window_now(prp->agmt))
+ {
+ next_state = STATE_READY_TO_ACQUIRE;
+ }
+ else
+ {
+ next_state = STATE_WAIT_WINDOW_OPEN;
+ }
+
+ /* we can get here from other states because some events happened and were
+ not cleared. For instance when we wake up in STATE_WAIT_CHANGES state.
+ Since this is a fresh start state, we should clear all events */
+ /* ONREPL - this does not feel right - we should take another look
+ at this state machine */
+ reset_events (prp);
+
+ /* Cancel any linger timer that might be in effect... */
+ conn_cancel_linger(prp->conn);
+ /* ... and disconnect, if currently connected */
+ conn_disconnect(prp->conn);
+ /* get the new pause time, if any */
+ pausetime = agmt_get_pausetime(prp->agmt);
+ /* get the new busy wait time, if any */
+ busywaittime = agmt_get_busywaittime(prp->agmt);
+ if (pausetime || busywaittime)
+ {
+ /* helper function to make sure they are set correctly */
+ set_pause_and_busy_time(&pausetime, &busywaittime);
+ }
+ break;
+ case STATE_WAIT_WINDOW_OPEN:
+ /*
+ * We're waiting for a schedule window to open. If one did,
+ * or we receive a "replicate now" event, then start a protocol
+ * session immediately. If the replication schedule changed, go
+ * back to start. Otherwise, go back to sleep.
+ */
+ dev_debug("repl5_inc_run(STATE_WAIT_WINDOW_OPEN)");
+ if (PROTOCOL_IS_SHUTDOWN(prp))
+ {
+ done = 1;
+ break;
+ }
+ else if (event_occurred(prp, EVENT_WINDOW_OPENED))
+ {
+ next_state = STATE_READY_TO_ACQUIRE;
+ }
+ else if (event_occurred(prp, EVENT_REPLICATE_NOW))
+ {
+ next_state = STATE_READY_TO_ACQUIRE;
+ }
+ else if (event_occurred(prp, EVENT_AGMT_CHANGED))
+ {
+ next_state = STATE_START;
+ conn_set_agmt_changed(prp->conn);
+ }
+ else if (event_occurred(prp, EVENT_TRIGGERING_CRITERIA_MET)) /* change available */
+ {
+ /* just ignore it and go to sleep */
+ protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT);
+ }
+ else if (e1 = event_occurred(prp, EVENT_WINDOW_CLOSED) ||
+ event_occurred(prp, EVENT_BACKOFF_EXPIRED))
+ {
+ /* this events - should not occur - log a warning and go to sleep */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Incremental protocol: "
+ "event %s should not occur in state %s; going to sleep\n",
+ agmt_get_long_name(prp->agmt),
+ e1 ? event2name(EVENT_WINDOW_CLOSED) : event2name(EVENT_BACKOFF_EXPIRED),
+ state2name(current_state));
+ protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT);
+ }
+ else
+ {
+ /* wait until window opens or an event occurs */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Incremental protocol: "
+ "waiting for update window to open\n", agmt_get_long_name(prp->agmt));
+ protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT);
+ }
+ break;
+ case STATE_WAIT_CHANGES:
+ /*
+ * We're in a replication window, but we're waiting for more
+ * changes to accumulate before we actually hook up and send
+ * them.
+ */
+ dev_debug("repl5_inc_run(STATE_WAIT_CHANGES)");
+ if (PROTOCOL_IS_SHUTDOWN(prp))
+ {
+ dev_debug("repl5_inc_run(STATE_WAIT_CHANGES): PROTOCOL_IS_SHUTING_DOWN -> end repl5_inc_run\n");
+ done = 1;
+ break;
+ }
+ else if (event_occurred(prp, EVENT_REPLICATE_NOW))
+ {
+ dev_debug("repl5_inc_run(STATE_WAIT_CHANGES): EVENT_REPLICATE_NOW received -> STATE_READY_TO_ACQUIRE\n");
+ next_state = STATE_READY_TO_ACQUIRE;
+ wait_change_timer_set = 0;
+ }
+ else if (event_occurred(prp, EVENT_AGMT_CHANGED))
+ {
+ dev_debug("repl5_inc_run(STATE_WAIT_CHANGES): EVENT_AGMT_CHANGED received -> STATE_START\n");
+ next_state = STATE_START;
+ conn_set_agmt_changed(prp->conn);
+ wait_change_timer_set = 0;
+ }
+ else if (event_occurred(prp, EVENT_WINDOW_CLOSED))
+ {
+ dev_debug("repl5_inc_run(STATE_WAIT_CHANGES): EVENT_WINDOW_CLOSED received -> STATE_WAIT_WINDOW_OPEN\n");
+ next_state = STATE_WAIT_WINDOW_OPEN;
+ wait_change_timer_set = 0;
+ }
+ else if (event_occurred(prp, EVENT_TRIGGERING_CRITERIA_MET))
+ {
+ dev_debug("repl5_inc_run(STATE_WAIT_CHANGES): EVENT_TRIGGERING_CRITERIA_MET received -> STATE_READY_TO_ACQUIRE\n");
+ next_state = STATE_READY_TO_ACQUIRE;
+ wait_change_timer_set = 0;
+ }
+ else if (e1 = event_occurred(prp, EVENT_WINDOW_OPENED) ||
+ event_occurred(prp, EVENT_BACKOFF_EXPIRED))
+ {
+ /* this events - should not occur - log a warning and clear the event */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s: Incremental protocol: "
+ "event %s should not occur in state %s\n",
+ agmt_get_long_name(prp->agmt),
+ e1 ? event2name(EVENT_WINDOW_OPENED) : event2name(EVENT_BACKOFF_EXPIRED),
+ state2name(current_state));
+ wait_change_timer_set = 0;
+ }
+ else
+ {
+ if (wait_change_timer_set)
+ {
+ /* We are here because our timer expired */
+ dev_debug("repl5_inc_run(STATE_WAIT_CHANGES): wait_change_timer_set expired -> STATE_START\n");
+ next_state = STATE_START;
+ wait_change_timer_set = 0;
+ }
+ else
+ {
+ /* We are here because the last replication session
+ * finished or aborted.
+ */
+ wait_change_timer_set = 1;
+ protocol_sleep(prp, MAX_WAIT_BETWEEN_SESSIONS);
+ }
+ }
+ break;
+ case STATE_READY_TO_ACQUIRE:
+
+ dev_debug("repl5_inc_run(STATE_READY_TO_ACQUIRE)");
+ if (PROTOCOL_IS_SHUTDOWN(prp))
+ {
+ done = 1;
+ break;
+ }
+
+ /* ONREPL - at this state we unconditionally acquire the replica
+ ignoring all events. Not sure if this is good */
+ object_acquire(prp->replica_object);
+ replica = object_get_data(prp->replica_object);
+
+ rc = acquire_replica(prp, REPL_NSDS50_INCREMENTAL_PROTOCOL_OID, &ruv);
+ use_busy_backoff_timer = PR_FALSE; /* default */
+ if (rc == ACQUIRE_SUCCESS)
+ {
+ next_state = STATE_SENDING_UPDATES;
+ }
+ else if (rc == ACQUIRE_REPLICA_BUSY)
+ {
+ next_state = STATE_BACKOFF_START;
+ use_busy_backoff_timer = PR_TRUE;
+ }
+ else if (rc == ACQUIRE_CONSUMER_WAS_UPTODATE)
+ {
+ next_state = STATE_WAIT_CHANGES;
+ }
+ else if (rc == ACQUIRE_TRANSIENT_ERROR)
+ {
+ next_state = STATE_BACKOFF_START;
+ }
+ else if (rc == ACQUIRE_FATAL_ERROR)
+ {
+ next_state = STATE_STOP_FATAL_ERROR;
+ }
+ if (rc != ACQUIRE_SUCCESS)
+ {
+ int optype, ldaprc;
+ conn_get_error(prp->conn, &optype, &ldaprc);
+ agmt_set_last_update_status(prp->agmt, ldaprc,
+ prp->last_acquire_response_code, NULL);
+ }
+
+ object_release(prp->replica_object); replica = NULL;
+ break;
+ case STATE_BACKOFF_START:
+ dev_debug("repl5_inc_run(STATE_BACKOFF_START)");
+ if (PROTOCOL_IS_SHUTDOWN(prp))
+ {
+ done = 1;
+ break;
+ }
+ if (event_occurred(prp, EVENT_REPLICATE_NOW))
+ {
+ next_state = STATE_READY_TO_ACQUIRE;
+ }
+ else if (event_occurred(prp, EVENT_AGMT_CHANGED))
+ {
+ next_state = STATE_START;
+ conn_set_agmt_changed(prp->conn);
+ }
+ else if (event_occurred (prp, EVENT_WINDOW_CLOSED))
+ {
+ next_state = STATE_WAIT_WINDOW_OPEN;
+ }
+ else if (event_occurred (prp, EVENT_TRIGGERING_CRITERIA_MET))
+ {
+ /* consume and ignore */
+ }
+ else if (e1 = event_occurred (prp, EVENT_WINDOW_OPENED) ||
+ event_occurred (prp, EVENT_BACKOFF_EXPIRED))
+ {
+ /* This should never happen */
+ /* this events - should not occur - log a warning and go to sleep */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Incremental protocol: event %s should not occur in state %s\n",
+ agmt_get_long_name(prp->agmt),
+ e1 ? event2name(EVENT_WINDOW_OPENED) : event2name(EVENT_BACKOFF_EXPIRED),
+ state2name(current_state));
+ }
+ else
+ {
+ /* Set up the backoff timer to wake us up at the appropriate time */
+ if (use_busy_backoff_timer)
+ {
+ /* we received a busy signal from the consumer, wait for a while */
+ if (!busywaittime)
+ {
+ busywaittime = PROTOCOL_BUSY_BACKOFF_MINIMUM;
+ }
+ prp_priv->backoff = backoff_new(BACKOFF_FIXED, busywaittime,
+ busywaittime);
+ }
+ else
+ {
+ prp_priv->backoff = backoff_new(BACKOFF_EXPONENTIAL, PROTOCOL_BACKOFF_MINIMUM,
+ PROTOCOL_BACKOFF_MAXIMUM);
+ }
+ next_state = STATE_BACKOFF;
+ backoff_reset(prp_priv->backoff, repl5_inc_backoff_expired, (void *)prp);
+ protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT);
+ use_busy_backoff_timer = PR_FALSE;
+ }
+ break;
+ case STATE_BACKOFF:
+ /*
+ * We're in a backoff state.
+ */
+ dev_debug("repl5_inc_run(STATE_BACKOFF)");
+ if (PROTOCOL_IS_SHUTDOWN(prp))
+ {
+ if (prp_priv->backoff)
+ backoff_delete(&prp_priv->backoff);
+ done = 1;
+ break;
+ }
+ else if (event_occurred(prp, EVENT_REPLICATE_NOW))
+ {
+ next_state = STATE_READY_TO_ACQUIRE;
+ }
+ else if (event_occurred(prp, EVENT_AGMT_CHANGED))
+ {
+ next_state = STATE_START;
+
+ conn_set_agmt_changed(prp->conn);
+ /* Destroy the backoff timer, since we won't need it anymore */
+ if (prp_priv->backoff)
+ backoff_delete(&prp_priv->backoff);
+ }
+ else if (event_occurred(prp, EVENT_WINDOW_CLOSED))
+ {
+ next_state = STATE_WAIT_WINDOW_OPEN;
+ /* Destroy the backoff timer, since we won't need it anymore */
+ if (prp_priv->backoff)
+ backoff_delete(&prp_priv->backoff);
+ }
+ else if (event_occurred(prp, EVENT_BACKOFF_EXPIRED))
+ {
+ rc = acquire_replica(prp, REPL_NSDS50_INCREMENTAL_PROTOCOL_OID, &ruv);
+ use_busy_backoff_timer = PR_FALSE;
+ if (rc == ACQUIRE_SUCCESS)
+ {
+ next_state = STATE_SENDING_UPDATES;
+ }
+ else if (rc == ACQUIRE_REPLICA_BUSY)
+ {
+ next_state = STATE_BACKOFF;
+ use_busy_backoff_timer = PR_TRUE;
+ }
+ else if (rc == ACQUIRE_CONSUMER_WAS_UPTODATE)
+ {
+ next_state = STATE_WAIT_CHANGES;
+ }
+ else if (rc == ACQUIRE_TRANSIENT_ERROR)
+ {
+ next_state = STATE_BACKOFF;
+ }
+ else if (rc == ACQUIRE_FATAL_ERROR)
+ {
+ next_state = STATE_STOP_FATAL_ERROR;
+ }
+ if (rc != ACQUIRE_SUCCESS)
+ {
+ int optype, ldaprc;
+ conn_get_error(prp->conn, &optype, &ldaprc);
+ agmt_set_last_update_status(prp->agmt, ldaprc,
+ prp->last_acquire_response_code, NULL);
+ }
+ /*
+ * We either need to step the backoff timer, or
+ * destroy it if we don't need it anymore.
+ */
+ if (STATE_BACKOFF == next_state)
+ {
+ time_t next_fire_time;
+ time_t now;
+ /* Step the backoff timer */
+ time(&now);
+ next_fire_time = backoff_step(prp_priv->backoff);
+ /* And go back to sleep */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Replication session backing off for %d seconds\n",
+ agmt_get_long_name(prp->agmt),
+ next_fire_time - now);
+
+ protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT);
+ }
+ else
+ {
+ /* Destroy the backoff timer, since we won't need it anymore */
+ backoff_delete(&prp_priv->backoff);
+ }
+ use_busy_backoff_timer = PR_FALSE;
+ }
+ else if (event_occurred(prp, EVENT_TRIGGERING_CRITERIA_MET))
+ {
+ /* changes are available */
+ if ( prp_priv->backoff == NULL || backoff_expired (prp_priv->backoff, 60) )
+ {
+ /*
+ * Have seen cases that the agmt stuck here forever since
+ * somehow the backoff timer was not in event queue anymore.
+ * If the backoff timer has expired more than 60 seconds,
+ * destroy it.
+ */
+ if ( prp_priv->backoff )
+ backoff_delete(&prp_priv->backoff);
+ next_state = STATE_READY_TO_ACQUIRE;
+ }
+ else
+ {
+ /* ignore changes and go to sleep */
+ protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT);
+ }
+ }
+ else if (event_occurred(prp, EVENT_WINDOW_OPENED))
+ {
+ /* this should never happen - log an error and go to sleep */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s: Incremental protocol: "
+ "event %s should not occur in state %s; going to sleep\n",
+ agmt_get_long_name(prp->agmt),
+ event2name(EVENT_WINDOW_OPENED), state2name(current_state));
+ protocol_sleep(prp, PR_INTERVAL_NO_TIMEOUT);
+ }
+ break;
+ case STATE_SENDING_UPDATES:
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES)");
+ agmt_set_update_in_progress(prp->agmt, PR_TRUE);
+ num_changes_sent = 0;
+ last_start_time = current_time();
+ agmt_set_last_update_start(prp->agmt, last_start_time);
+ /*
+ * We've acquired the replica, and are ready to send any
+ * needed updates.
+ */
+ if (PROTOCOL_IS_SHUTDOWN(prp))
+ {
+ release_replica (prp);
+ done = 1;
+ agmt_set_update_in_progress(prp->agmt, PR_FALSE);
+ agmt_set_last_update_end(prp->agmt, current_time());
+ /* MAB: I don't find the following status correct. How do we know it has
+ been stopped by an admin and not by a total update request, for instance?
+ In any case, how is this protocol shutdown situation different from all the
+ other ones that are present in this state machine? */
+ /* richm: We at least need to let monitors know that the protocol has been
+ shutdown - maybe they can figure out why */
+ agmt_set_last_update_status(prp->agmt, 0, 0, "Protocol stopped");
+ break;
+ }
+
+ agmt_set_last_update_status(prp->agmt, 0, 0, "Incremental update started");
+
+ /* ONREPL - in this state we send changes no matter what other events occur.
+ This is because we can get because of the REPLICATE_NOW event which
+ has high priority. Is this ok? */
+ /* First, push new schema to the consumer if needed */
+ /* ONREPL - should we push schema after we examine the RUV? */
+ /*
+ * GGOOREPL - I don't see why we should wait until we've
+ * examined the RUV. The schema entry has its own CSN that is
+ * used to decide if the remote schema needs to be updated.
+ */
+ cons_schema_csn = agmt_get_consumer_schema_csn ( prp->agmt );
+ rc = conn_push_schema(prp->conn, &cons_schema_csn);
+ if ( cons_schema_csn != agmt_get_consumer_schema_csn ( prp->agmt ))
+ {
+ agmt_set_consumer_schema_csn ( prp->agmt, cons_schema_csn );
+ }
+ if (CONN_SCHEMA_UPDATED != rc && CONN_SCHEMA_NO_UPDATE_NEEDED != rc)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Warning: unable to replicate schema: rc=%d\n",
+ agmt_get_long_name(prp->agmt), rc);
+ /* But keep going */
+ }
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> examine_update_vector");
+ rc = examine_update_vector(prp, ruv);
+ /*
+ * Decide what to do next - proceed with incremental,
+ * backoff, or total update
+ */
+ switch (rc)
+ {
+ case EXAMINE_RUV_PARAM_ERROR:
+ /* this is really bad - we have NULL prp! */
+ next_state = STATE_STOP_FATAL_ERROR;
+ break;
+ case EXAMINE_RUV_PRISTINE_REPLICA:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Replica has no update vector. It has never been initialized.\n",
+ agmt_get_long_name(prp->agmt));
+ next_state = STATE_BACKOFF_START;
+ break;
+ case EXAMINE_RUV_GENERATION_MISMATCH:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Replica has a different generation ID than the local data.\n",
+ agmt_get_long_name(prp->agmt));
+ next_state = STATE_BACKOFF_START;
+ break;
+ case EXAMINE_RUV_REPLICA_TOO_OLD:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Replica update vector is too out of date to bring "
+ "into sync using the incremental protocol. The replica "
+ "must be reinitialized.\n", agmt_get_long_name(prp->agmt));
+ next_state = STATE_BACKOFF_START;
+ break;
+ case EXAMINE_RUV_OK:
+ /* update our csn generator state with the consumer's ruv data */
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> examine_update_vector OK");
+ object_acquire(prp->replica_object);
+ replica = object_get_data(prp->replica_object);
+ rc = replica_update_csngen_state (replica, ruv);
+ object_release (prp->replica_object);
+ replica = NULL;
+ if (rc != 0) /* too much skew */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Incremental protocol: fatal error - too much time skew between replicas!\n",
+ agmt_get_long_name(prp->agmt));
+ next_state = STATE_STOP_FATAL_ERROR;
+ }
+ else
+ {
+ rc = send_updates(prp, ruv, &num_changes_sent);
+ if (rc == UPDATE_NO_MORE_UPDATES)
+ {
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_NO_MORE_UPDATES -> STATE_WAIT_CHANGES");
+ agmt_set_last_update_status(prp->agmt, 0, 0, "Incremental update succeeded");
+ next_state = STATE_WAIT_CHANGES;
+ }
+ else if (rc == UPDATE_YIELD)
+ {
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_YIELD -> STATE_BACKOFF_START");
+ agmt_set_last_update_status(prp->agmt, 0, 0, "Incremental update succeeded and yielded");
+ next_state = STATE_BACKOFF_START;
+ }
+ else if (rc == UPDATE_TRANSIENT_ERROR)
+ {
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_TRANSIENT_ERROR -> STATE_BACKOFF_START");
+ next_state = STATE_BACKOFF_START;
+ }
+ else if (rc == UPDATE_FATAL_ERROR)
+ {
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_FATAL_ERROR -> STATE_STOP_FATAL_ERROR");
+ next_state = STATE_STOP_FATAL_ERROR;
+ }
+ else if (rc == UPDATE_SCHEDULE_WINDOW_CLOSED)
+ {
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_SCHEDULE_WINDOW_CLOSED -> STATE_WAIT_WINDOW_OPEN");
+ /* ONREPL - I don't think we should check this. We might be
+ here because of replicate_now event - so we don't care
+ about the schedule */
+ next_state = STATE_WAIT_WINDOW_OPEN;
+ /* ONREPL - do we need to release the replica here ? */
+ conn_disconnect (prp->conn);
+ }
+ else if (rc == UPDATE_CONNECTION_LOST)
+ {
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_CONNECTION_LOST -> STATE_BACKOFF_START");
+ next_state = STATE_BACKOFF_START;
+ }
+ else if (rc == UPDATE_TIMEOUT)
+ {
+ dev_debug("repl5_inc_run(STATE_SENDING_UPDATES) -> send_updates = UPDATE_TIMEOUT -> STATE_BACKOFF_START");
+ next_state = STATE_BACKOFF_START;
+ }
+ }
+ last_start_time = 0UL;
+ break;
+ }
+ if (NULL != ruv)
+ {
+ ruv_destroy(&ruv); ruv = NULL;
+ }
+ agmt_set_last_update_end(prp->agmt, current_time());
+ agmt_set_update_in_progress(prp->agmt, PR_FALSE);
+ /* If timed out, close the connection after released the replica */
+ release_replica(prp);
+ if (rc == UPDATE_TIMEOUT) {
+ conn_disconnect(prp->conn);
+ }
+ if (rc == UPDATE_NO_MORE_UPDATES && num_changes_sent > 0)
+ {
+ if (pausetime > 0)
+ {
+ /* richm - 20020219 - If we have acquired the consumer, and another master has gone
+ into backoff waiting for us to release it, we may acquire the replica sooner
+ than the other master has a chance to, and the other master may not be able
+ to acquire the consumer for a long time (hours, days?) if this server is
+ under a heavy load (see reliab06 et. al. system tests)
+ So, this sleep gives the other master(s) a chance to acquire the consumer
+ replica */
+ long loops = pausetime;
+ /* the while loop is so that we don't just sleep and sleep if an
+ event comes in that we should handle immediately (like shutdown) */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Pausing updates for %ld seconds to allow other suppliers to update consumer\n",
+ agmt_get_long_name(prp->agmt), pausetime);
+ while (loops-- && !(PROTOCOL_IS_SHUTDOWN(prp)))
+ {
+ DS_Sleep(PR_SecondsToInterval(1));
+ }
+ }
+ else if (num_changes_sent > 10)
+ {
+ /* wait for consumer to write its ruv if the replication was busy */
+ /* When asked, consumer sends its ruv in cache to the supplier. */
+ /* DS_Sleep ( PR_SecondsToInterval(1) ); */
+ }
+ }
+ break;
+ case STATE_STOP_FATAL_ERROR:
+ /*
+ * We encountered some sort of a fatal error. Suspend.
+ */
+ /* XXXggood update state in replica */
+ agmt_set_last_update_status(prp->agmt, -1, 0, "Incremental update has failed and requires administrator action");
+ dev_debug("repl5_inc_run(STATE_STOP_FATAL_ERROR)");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Incremental update failed and requires administrator action\n",
+ agmt_get_long_name(prp->agmt));
+ next_state = STATE_STOP_FATAL_ERROR_PART2;
+ break;
+ case STATE_STOP_FATAL_ERROR_PART2:
+ if (PROTOCOL_IS_SHUTDOWN(prp))
+ {
+ done = 1;
+ break;
+ }
+
+ /* MAB: This state is the FATAL state where we are supposed to get
+ as a result of a FATAL error on send_updates. But, as bug
+ states, send_updates was always returning TRANSIENT errors and never
+ FATAL... In other words, this code has never been tested before...
+
+ As of 01/16/01, this piece of code was in a very dangerous state. In particular,
+ 1) it does not catch any events
+ 2) it is a terminal state (once reached it never transitions to a different state)
+
+ Both things combined make this state to become a consuming infinite loop
+ that is useless after all (we are in a fatal place requiring manual admin jobs */
+
+ /* MAB: The following lines fix problem number 1 above... When the code gets
+ into this state, it should only get a chance to get out of it by an
+ EVENT_AGMT_CHANGED event... All other events should be ignored */
+ else if (event_occurred(prp, EVENT_AGMT_CHANGED))
+ {
+ dev_debug("repl5_inc_run(STATE_STOP_FATAL_ERROR): EVENT_AGMT_CHANGED received\n");
+ /* Chance to recover for the EVENT_AGMT_CHANGED event.
+ This is not mandatory, but fixes problem 2 above */
+ next_state = STATE_STOP_NORMAL_TERMINATION;
+ }
+ else
+ {
+ dev_debug("repl5_inc_run(STATE_STOP_FATAL_ERROR): Event received. Clearing it\n");
+ reset_events (prp);
+ }
+
+ protocol_sleep (prp, PR_INTERVAL_NO_TIMEOUT);
+ break;
+
+ case STATE_STOP_NORMAL_TERMINATION:
+ /*
+ * We encountered some sort of a fatal error. Return.
+ */
+ /* XXXggood update state in replica */
+ dev_debug("repl5_inc_run(STATE_STOP_NORMAL_TERMINATION)");
+ done = 1;
+ break;
+ }
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: State: %s -> %s\n",
+ agmt_get_long_name(prp->agmt),
+ state2name(current_state), state2name(next_state));
+
+ current_state = next_state;
+ } while (!done);
+ slapi_ch_free((void**)&hostname);
+ /* remove_protocol_callbacks(prp); */
+ prp->stopped = 1;
+ /* Cancel any linger timer that might be in effect... */
+ conn_cancel_linger(prp->conn);
+ /* ... and disconnect, if currently connected */
+ conn_disconnect(prp->conn);
+}
+
+
+
+/*
+ * Go to sleep until awakened.
+ */
+static void
+protocol_sleep(Private_Repl_Protocol *prp, PRIntervalTime duration)
+{
+ PR_ASSERT(NULL != prp);
+ PR_Lock(prp->lock);
+ /* we should not go to sleep if there are events available to be processed.
+ Otherwise, we can miss the event that suppose to wake us up */
+ if (prp->eventbits == 0)
+ PR_WaitCondVar(prp->cvar, duration);
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Incremental protocol: can't go to sleep: event bits - %x\n",
+ agmt_get_long_name(prp->agmt), prp->eventbits);
+ }
+ PR_Unlock(prp->lock);
+}
+
+
+/*
+ * Notify the protocol about some event. Signal the condition
+ * variable in case the protocol is sleeping. Multiple occurences
+ * of a single event type are not remembered (e.g. no stack
+ * of events is maintained).
+ */
+static void
+event_notify(Private_Repl_Protocol *prp, PRUint32 event)
+{
+ PR_ASSERT(NULL != prp);
+ PR_Lock(prp->lock);
+ prp->eventbits |= event;
+ PR_NotifyCondVar(prp->cvar);
+ PR_Unlock(prp->lock);
+}
+
+
+/*
+ * Test to see if an event occurred. The event is cleared when
+ * read.
+ */
+static PRUint32
+event_occurred(Private_Repl_Protocol *prp, PRUint32 event)
+{
+ PRUint32 return_value;
+ PR_ASSERT(NULL != prp);
+ PR_Lock(prp->lock);
+ return_value = (prp->eventbits & event);
+ prp->eventbits &= ~event; /* Clear event */
+ PR_Unlock(prp->lock);
+ return return_value;
+}
+
+static void
+reset_events (Private_Repl_Protocol *prp)
+{
+ PR_ASSERT(NULL != prp);
+ PR_Lock(prp->lock);
+ prp->eventbits = 0;
+ PR_Unlock(prp->lock);
+}
+
+
+/*
+ * Replay the actual update to the consumer. Construct an appropriate LDAP
+ * operation, attach the baggage LDAPv3 control that contains the CSN, etc.,
+ * and send the operation to the consumer.
+ */
+ConnResult
+replay_update(Private_Repl_Protocol *prp, slapi_operation_parameters *op)
+{
+ ConnResult return_value;
+ LDAPControl *update_control;
+ char *parentuniqueid;
+ LDAPMod **modrdn_mods = NULL;
+ char csn_str[CSN_STRSIZE]; /* For logging only */
+
+ csn_as_string(op->csn, PR_FALSE, csn_str);
+
+ /* Construct the replication info control that accompanies the operation */
+ if (SLAPI_OPERATION_ADD == op->operation_type)
+ {
+ parentuniqueid = op->p.p_add.parentuniqueid;
+ }
+ else if (SLAPI_OPERATION_MODRDN == op->operation_type)
+ {
+ /*
+ * For modrdn operations, we need to send along modified attributes, e.g.
+ * modifytimestamp.
+ * And the superior_uniqueid !
+ */
+ modrdn_mods = op->p.p_modrdn.modrdn_mods;
+ parentuniqueid = op->p.p_modrdn.modrdn_newsuperior_address.uniqueid;
+ }
+ else
+ {
+ parentuniqueid = NULL;
+ }
+ if (create_NSDS50ReplUpdateInfoControl(op->target_address.uniqueid,
+ parentuniqueid, op->csn, modrdn_mods, &update_control) != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: replay_update: Unable to create NSDS50ReplUpdateInfoControl "
+ "for operation with csn %s. Skipping update.\n",
+ agmt_get_long_name(prp->agmt), csn_str);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: replay_update: Sending %s operation (dn=\"%s\" csn=%s)\n",
+ agmt_get_long_name(prp->agmt),
+ op2string(op->operation_type), op->target_address.dn, csn_str);
+ /* What type of operation is it? */
+ switch (op->operation_type)
+ {
+ case SLAPI_OPERATION_ADD:
+ {
+ LDAPMod **entryattrs;
+ /* Convert entry to mods */
+ (void)slapi_entry2mods (op->p.p_add.target_entry,
+ NULL /* &entrydn : We don't need it */,
+ &entryattrs);
+ if (NULL == entryattrs)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: replay_update: Cannot convert entry to LDAPMods.\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = CONN_LOCAL_ERROR;
+ }
+ else
+ {
+ return_value = conn_send_add(prp->conn, op->target_address.dn,
+ entryattrs, update_control, NULL /* returned controls */);
+ ldap_mods_free(entryattrs, 1);
+ }
+ break;
+ }
+ case SLAPI_OPERATION_MODIFY:
+ return_value = conn_send_modify(prp->conn, op->target_address.dn,
+ op->p.p_modify.modify_mods, update_control,
+ NULL /* returned controls */);
+ break;
+ case SLAPI_OPERATION_DELETE:
+ return_value = conn_send_delete(prp->conn, op->target_address.dn,
+ update_control, NULL /* returned controls */);
+ break;
+ case SLAPI_OPERATION_MODRDN:
+ /* XXXggood need to pass modrdn mods in update control! */
+ return_value = conn_send_rename(prp->conn, op->target_address.dn,
+ op->p.p_modrdn.modrdn_newrdn,
+ op->p.p_modrdn.modrdn_newsuperior_address.dn,
+ op->p.p_modrdn.modrdn_deloldrdn,
+ update_control, NULL /* returned controls */);
+ break;
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s: replay_update: Unknown "
+ "operation type %d found in changelog - skipping change.\n",
+ agmt_get_long_name(prp->agmt), op->operation_type);
+ }
+
+ destroy_NSDS50ReplUpdateInfoControl(&update_control);
+ }
+
+ if (CONN_OPERATION_SUCCESS == return_value)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: replay_update: Consumer successfully replayed operation with csn %s\n",
+ agmt_get_long_name(prp->agmt), csn_str);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: replay_update: Consumer could not replay operation with csn %s\n",
+ agmt_get_long_name(prp->agmt), csn_str);
+ }
+ return return_value;
+}
+
+static PRBool
+is_dummy_operation (const slapi_operation_parameters *op)
+{
+ return (strcmp (op->target_address.uniqueid, START_ITERATION_ENTRY_UNIQUEID) == 0);
+}
+
+
+
+void
+cl5_operation_parameters_done (struct slapi_operation_parameters *sop)
+{
+ if(sop!=NULL) {
+ switch(sop->operation_type)
+ {
+ case SLAPI_OPERATION_BIND:
+ slapi_ch_free((void **)&(sop->p.p_bind.bind_saslmechanism));
+ if (sop->p.p_bind.bind_creds)
+ ber_bvecfree((struct berval**)&(sop->p.p_bind.bind_creds));
+ if (sop->p.p_bind.bind_ret_saslcreds)
+ ber_bvecfree((struct berval**)&(sop->p.p_bind.bind_ret_saslcreds));
+ sop->p.p_bind.bind_creds = NULL;
+ sop->p.p_bind.bind_ret_saslcreds = NULL;
+ break;
+ case SLAPI_OPERATION_COMPARE:
+ ava_done((struct ava *)&(sop->p.p_compare.compare_ava));
+ break;
+ case SLAPI_OPERATION_SEARCH:
+ slapi_ch_free((void **)&(sop->p.p_search.search_strfilter));
+ charray_free(sop->p.p_search.search_attrs);
+ slapi_filter_free(sop->p.p_search.search_filter,1);
+ break;
+ case SLAPI_OPERATION_MODRDN:
+ sop->p.p_modrdn.modrdn_deloldrdn = 0;
+ break;
+ case SLAPI_OPERATION_EXTENDED:
+ slapi_ch_free((void **)&(sop->p.p_extended.exop_oid));
+ if (sop->p.p_extended.exop_value)
+ ber_bvecfree((struct berval**)&(sop->p.p_extended.exop_value));
+ sop->p.p_extended.exop_value = NULL;
+ break;
+ default:
+ break;
+ }
+ }
+ operation_parameters_done(sop);
+
+}
+
+
+
+/*
+ * Send a set of updates to the replica. Assumes that (1) the replica
+ * has already been acquired, (2) that the consumer's update vector has
+ * been checked and (3) that it's ok to send incremental updates.
+ * Returns:
+ * UPDATE_NO_MORE_UPDATES - all updates were sent succussfully
+ * UPDATE_TRANSIENT_ERROR - some non-permanent error occurred. Try again later.
+ * UPDATE_FATAL_ERROR - some bad, permanent error occurred.
+ * UPDATE_SCHEDULE_WINDOW_CLOSED - the schedule window closed on us.
+ */
+static int
+send_updates(Private_Repl_Protocol *prp, RUV *remote_update_vector, PRUint32 *num_changes_sent)
+{
+ CL5Entry entry;
+ slapi_operation_parameters op;
+ int return_value;
+ int rc;
+ CL5ReplayIterator *changelog_iterator;
+
+ *num_changes_sent = 0;
+ /*
+ * Iterate over the changelog. Retrieve each update,
+ * construct an appropriate LDAP operation,
+ * attaching the CSN, and send the change.
+ */
+
+ rc = cl5CreateReplayIterator(prp, remote_update_vector, &changelog_iterator);
+ if (CL5_SUCCESS != rc)
+ {
+ switch (rc)
+ {
+ case CL5_BAD_DATA: /* invalid parameter passed to the function */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Invalid parameter passed to cl5CreateReplayIterator\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ break;
+ case CL5_BAD_FORMAT: /* db data has unexpected format */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unexpected format encountered in changelog database\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ break;
+ case CL5_BAD_STATE: /* changelog is in an incorrect state for attempted operation */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Changelog database was in an incorrect state\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ break;
+ case CL5_BAD_DBVERSION: /* changelog has invalid dbversion */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Incorrect dbversion found in changelog database\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ break;
+ case CL5_DB_ERROR: /* database error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: A changelog database error was encountered\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ break;
+ case CL5_NOTFOUND: /* we have no changes to send */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: No changes to send\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_NO_MORE_UPDATES;
+ break;
+ case CL5_MEMORY_ERROR: /* memory allocation failed */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Memory allocation error occurred\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ break;
+ case CL5_SYSTEM_ERROR: /* NSPR error occurred: use PR_GetError for furhter info */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: An NSPR error (%d) occurred\n",
+ agmt_get_long_name(prp->agmt), PR_GetError());
+ return_value = UPDATE_TRANSIENT_ERROR;
+ break;
+ case CL5_CSN_ERROR: /* CSN API failed */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: A CSN API failure was encountered\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_TRANSIENT_ERROR;
+ break;
+ case CL5_RUV_ERROR: /* RUV API failed */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: An RUV API failure occurred\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_TRANSIENT_ERROR;
+ break;
+ case CL5_OBJSET_ERROR: /* namedobjset api failed */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: A namedobject API failure occurred\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_TRANSIENT_ERROR;
+ break;
+ case CL5_PURGED_DATA: /* requested data has been purged */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Data required to update replica has been purged. "
+ "The replica must be reinitialized.\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ break;
+ case CL5_MISSING_DATA: /* data should be in the changelog, but is missing */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Missing data encountered\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ break;
+ case CL5_UNKNOWN_ERROR: /* unclassified error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: An unknown error was ecountered\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_TRANSIENT_ERROR;
+ break;
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: An unknown error (%d) occurred "
+ "(cl5CreateReplayIterator)\n",
+ agmt_get_long_name(prp->agmt), rc);
+ return_value = UPDATE_TRANSIENT_ERROR;
+ }
+ }
+ else
+ {
+ int finished = 0;
+ ConnResult replay_crc;
+ char csn_str[CSN_STRSIZE];
+
+ memset ( (void*)&op, 0, sizeof (op) );
+ entry.op = &op;
+ do {
+ cl5_operation_parameters_done ( entry.op );
+ memset ( (void*)entry.op, 0, sizeof (op) );
+ rc = cl5GetNextOperationToReplay(changelog_iterator, &entry);
+ switch (rc)
+ {
+ case CL5_SUCCESS:
+ /* check that we don't return dummy entries */
+ if (is_dummy_operation (entry.op))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: changelog iteration code returned a dummy entry with csn %s, "
+ "skipping ...\n",
+ agmt_get_long_name(prp->agmt), csn_as_string(entry.op->csn, PR_FALSE, csn_str));
+ continue;
+ }
+ replay_crc = replay_update(prp, entry.op);
+ if (CONN_OPERATION_SUCCESS != replay_crc)
+ {
+ int operation, error;
+ conn_get_error(prp->conn, &operation, &error);
+ csn_as_string(entry.op->csn, PR_FALSE, csn_str);
+ /* Figure out what to do next */
+ if (CONN_OPERATION_FAILED == replay_crc)
+ {
+ /* Map ldap error code to return value */
+ if (!ignore_error_and_keep_going(error))
+ {
+ return_value = UPDATE_TRANSIENT_ERROR;
+ finished = 1;
+ }
+ else
+ {
+ agmt_inc_last_update_changecount (prp->agmt, csn_get_replicaid(entry.op->csn), 1 /*skipped*/);
+ }
+ slapi_log_error(finished ? SLAPI_LOG_FATAL : slapi_log_urp, repl_plugin_name,
+ "%s: Consumer failed to replay change (uniqueid %s, CSN %s): %s. %s.\n",
+ agmt_get_long_name(prp->agmt),
+ entry.op->target_address.uniqueid, csn_str,
+ ldap_err2string(error),
+ finished ? "Will retry later" : "Skipping");
+ }
+ else if (CONN_NOT_CONNECTED == replay_crc)
+ {
+ /* We lost the connection - enter backoff state */
+
+ return_value = UPDATE_TRANSIENT_ERROR;
+ finished = 1;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Consumer failed to replay change (uniqueid %s, CSN %s): "
+ "%s. Will retry later.\n",
+ agmt_get_long_name(prp->agmt),
+ entry.op->target_address.uniqueid, csn_str,
+ error ? ldap_err2string(error) : "Connection lost");
+ }
+ else if (CONN_TIMEOUT == replay_crc)
+ {
+ return_value = UPDATE_TIMEOUT;
+ finished = 1;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Consumer timed out to replay change (uniqueid %s, CSN %s): "
+ "%s.\n",
+ agmt_get_long_name(prp->agmt),
+ entry.op->target_address.uniqueid, csn_str,
+ error ? ldap_err2string(error) : "Timeout");
+ }
+ else if (CONN_LOCAL_ERROR == replay_crc)
+ {
+ /*
+ * Something bad happened on the local server - enter
+ * backoff state.
+ */
+ return_value = UPDATE_TRANSIENT_ERROR;
+ finished = 1;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Failed to replay change (uniqueid %s, CSN %s): "
+ "Local error. Will retry later.\n",
+ agmt_get_long_name(prp->agmt),
+ entry.op->target_address.uniqueid, csn_str);
+ }
+
+ }
+ else
+ {
+ /* Positive response received */
+ (*num_changes_sent)++;
+ agmt_inc_last_update_changecount (prp->agmt, csn_get_replicaid(entry.op->csn), 0 /*replayed*/);
+ }
+ break;
+ case CL5_BAD_DATA:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Invalid parameter passed to cl5GetNextOperationToReplay\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ finished = 1;
+ break;
+ case CL5_NOTFOUND:
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: No more updates to send (cl5GetNextOperationToReplay)\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_NO_MORE_UPDATES;
+ finished = 1;
+ break;
+ case CL5_DB_ERROR:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: A database error occurred (cl5GetNextOperationToReplay)\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ finished = 1;
+ break;
+ case CL5_BAD_FORMAT:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: A malformed changelog entry was encountered (cl5GetNextOperationToReplay)\n",
+ agmt_get_long_name(prp->agmt));
+ break;
+ case CL5_MEMORY_ERROR:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: A memory allocation error occurred (cl5GetNextOperationToRepla)\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = UPDATE_FATAL_ERROR;
+ break;
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unknown error code (%d) returned from cl5GetNextOperationToReplay\n",
+ agmt_get_long_name(prp->agmt), rc);
+ return_value = UPDATE_TRANSIENT_ERROR;
+ break;
+ }
+ /* Check for protocol shutdown */
+ if (prp->terminate)
+ {
+ return_value = UPDATE_NO_MORE_UPDATES;
+ finished = 1;
+ }
+ if (*num_changes_sent >= MAX_CHANGES_PER_SESSION)
+ {
+ return_value = UPDATE_YIELD;
+ finished = 1;
+ }
+ } while (!finished);
+ cl5_operation_parameters_done ( entry.op );
+ cl5DestroyReplayIterator(&changelog_iterator);
+ }
+ return return_value;
+}
+
+
+
+/*
+ * XXXggood this should probably be in the superclass, since the full update
+ * protocol is going to need it too.
+ */
+static int
+repl5_inc_stop(Private_Repl_Protocol *prp)
+{
+ int return_value;
+ PRIntervalTime start, maxwait, now;
+ int seconds = 1200;
+
+ maxwait = PR_SecondsToInterval(seconds);
+ prp->terminate = 1;
+ event_notify(prp, EVENT_PROTOCOL_SHUTDOWN);
+ start = PR_IntervalNow();
+ now = start;
+ while (!prp->stopped && ((now - start) < maxwait))
+ {
+ DS_Sleep(PR_SecondsToInterval(1));
+ now = PR_IntervalNow();
+ }
+ if (!prp->stopped)
+ {
+ /* Isn't listening. Do something drastic. */
+ return_value = -1;
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: protocol does not stop after %d seconds\n",
+ agmt_get_long_name(prp->agmt), seconds);
+ }
+ else
+ {
+ return_value = 0;
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: protocol stopped after %d seconds\n",
+ agmt_get_long_name(prp->agmt),
+ PR_IntervalToSeconds(now-start));
+ }
+ return return_value;
+}
+
+
+
+static int
+repl5_inc_status(Private_Repl_Protocol *prp)
+{
+ int return_value = 0;
+
+ return return_value;
+}
+
+
+
+static void
+repl5_inc_notify_update(Private_Repl_Protocol *prp)
+{
+ event_notify(prp, EVENT_TRIGGERING_CRITERIA_MET);
+}
+
+
+static void
+repl5_inc_update_now(Private_Repl_Protocol *prp)
+{
+ event_notify(prp, EVENT_REPLICATE_NOW);
+}
+
+
+static void
+repl5_inc_notify_agmt_changed(Private_Repl_Protocol *prp)
+{
+ event_notify(prp, EVENT_AGMT_CHANGED);
+}
+
+static void
+repl5_inc_notify_window_opened (Private_Repl_Protocol *prp)
+{
+ event_notify(prp, EVENT_WINDOW_OPENED);
+}
+
+static void
+repl5_inc_notify_window_closed (Private_Repl_Protocol *prp)
+{
+ event_notify(prp, EVENT_WINDOW_CLOSED);
+}
+
+Private_Repl_Protocol *
+Repl_5_Inc_Protocol_new(Repl_Protocol *rp)
+{
+ repl5_inc_private *rip = NULL;
+ Private_Repl_Protocol *prp = (Private_Repl_Protocol *)slapi_ch_malloc(sizeof(Private_Repl_Protocol));
+ prp->delete = repl5_inc_delete;
+ prp->run = repl5_inc_run;
+ prp->stop = repl5_inc_stop;
+ prp->status = repl5_inc_status;
+ prp->notify_update = repl5_inc_notify_update;
+ prp->notify_agmt_changed = repl5_inc_notify_agmt_changed;
+ prp->notify_window_opened = repl5_inc_notify_window_opened;
+ prp->notify_window_closed = repl5_inc_notify_window_closed;
+ prp->update_now = repl5_inc_update_now;
+ prp->replica_object = prot_get_replica_object(rp);
+ if ((prp->lock = PR_NewLock()) == NULL)
+ {
+ goto loser;
+ }
+ if ((prp->cvar = PR_NewCondVar(prp->lock)) == NULL)
+ {
+ goto loser;
+ }
+ prp->stopped = 0;
+ prp->terminate = 0;
+ prp->eventbits = 0;
+ prp->conn = prot_get_connection(rp);
+ prp->agmt = prot_get_agreement(rp);
+ prp->last_acquire_response_code = NSDS50_REPL_REPLICA_READY;
+ rip = (void *)slapi_ch_malloc(sizeof(repl5_inc_private));
+ rip->ruv = NULL;
+ rip->backoff = NULL;
+ rip->rp = rp;
+ prp->private = (void *)rip;
+ prp->replica_acquired = PR_FALSE;
+ return prp;
+loser:
+ repl5_inc_delete(&prp);
+ return NULL;
+}
+
+
+
+
+static void
+repl5_inc_backoff_expired(time_t timer_fire_time, void *arg)
+{
+ Private_Repl_Protocol *prp = (Private_Repl_Protocol *)arg;
+ PR_ASSERT(NULL != prp);
+ event_notify(prp, EVENT_BACKOFF_EXPIRED);
+}
+
+
+
+/*
+ * Examine the update vector and determine our course of action.
+ * There are 3 different possibilities, plus a catch-all error:
+ * 1 - no update vector (ruv is NULL). The consumer's replica is
+ * pristine, so it needs to be initialized. Return
+ * EXAMINE_RUV_PRISTINE_REPLICA.
+ * 2 - ruv is present, but its database generation ID doesn't
+ * match the local generation ID. This means that either
+ * the local replica must be reinitialized from the remote
+ * replica or vice-versa. Return
+ * EXAMINE_RUV_GENERATION_MISMATCH.
+ * 3 - ruv is present, and we have all updates needed to bring
+ * the replica up to date using the incremental protocol.
+ * return EXAMINE_RUV_OK.
+ * 4 - parameter error. Return EXAMINE_RUV_PARAM_ERROR
+ */
+static int
+examine_update_vector(Private_Repl_Protocol *prp, RUV *remote_ruv)
+{
+ int return_value;
+
+ PR_ASSERT(NULL != prp);
+ if (NULL == prp)
+ {
+ return_value = EXAMINE_RUV_PARAM_ERROR;
+ }
+ else if (NULL == remote_ruv)
+ {
+ return_value = EXAMINE_RUV_PRISTINE_REPLICA;
+ }
+ else
+ {
+ char *local_gen = NULL;
+ char *remote_gen = ruv_get_replica_generation(remote_ruv);
+ Object *local_ruv_obj;
+ RUV *local_ruv;
+ Replica *replica;
+
+ PR_ASSERT(NULL != prp->replica_object);
+ replica = object_get_data(prp->replica_object);
+ PR_ASSERT(NULL != replica);
+ local_ruv_obj = replica_get_ruv (replica);
+ if (NULL != local_ruv_obj)
+ {
+ local_ruv = (RUV*)object_get_data (local_ruv_obj);
+ PR_ASSERT (local_ruv);
+ local_gen = ruv_get_replica_generation(local_ruv);
+ object_release (local_ruv_obj);
+ }
+ if (NULL == remote_gen || NULL == local_gen || strcmp(remote_gen, local_gen) != 0)
+ {
+ return_value = EXAMINE_RUV_GENERATION_MISMATCH;
+ }
+ else
+ {
+ return_value = EXAMINE_RUV_OK;
+ }
+ slapi_ch_free((void**)&remote_gen);
+ slapi_ch_free((void**)&local_gen);
+ }
+ return return_value;
+}
+
+
+/*
+ * When we get an error from an LDAP operation, we call this
+ * function to decide if we should just keep replaying
+ * updates, or if we should stop, back off, and try again
+ * later.
+ * Returns PR_TRUE if we shoould keep going, PR_FALSE if
+ * we should back off and try again later.
+ *
+ * In general, we keep going if the return code is consistent
+ * with some sort of bug in URP that causes the consumer to
+ * emit an error code that it shouldn't have, e.g. LDAP_ALREADY_EXISTS.
+ *
+ * We stop if there's some indication that the server just completely
+ * failed to process the operation, e.g. LDAP_OPERATIONS_ERROR.
+ */
+static PRBool
+ignore_error_and_keep_going(int error)
+{
+ int return_value;
+
+ switch (error)
+ {
+ /* Cases where we keep going */
+ case LDAP_SUCCESS:
+ case LDAP_NO_SUCH_ATTRIBUTE:
+ case LDAP_UNDEFINED_TYPE:
+ case LDAP_CONSTRAINT_VIOLATION:
+ case LDAP_TYPE_OR_VALUE_EXISTS:
+ case LDAP_INVALID_SYNTAX:
+ case LDAP_NO_SUCH_OBJECT:
+ case LDAP_INVALID_DN_SYNTAX:
+ case LDAP_IS_LEAF:
+ case LDAP_INSUFFICIENT_ACCESS:
+ case LDAP_NAMING_VIOLATION:
+ case LDAP_OBJECT_CLASS_VIOLATION:
+ case LDAP_NOT_ALLOWED_ON_NONLEAF:
+ case LDAP_NOT_ALLOWED_ON_RDN:
+ case LDAP_ALREADY_EXISTS:
+ case LDAP_NO_OBJECT_CLASS_MODS:
+ return_value = PR_TRUE;
+ break;
+
+ /* Cases where we stop and retry */
+ case LDAP_OPERATIONS_ERROR:
+ case LDAP_PROTOCOL_ERROR:
+ case LDAP_TIMELIMIT_EXCEEDED:
+ case LDAP_SIZELIMIT_EXCEEDED:
+ case LDAP_STRONG_AUTH_NOT_SUPPORTED:
+ case LDAP_STRONG_AUTH_REQUIRED:
+ case LDAP_PARTIAL_RESULTS:
+ case LDAP_REFERRAL:
+ case LDAP_ADMINLIMIT_EXCEEDED:
+ case LDAP_UNAVAILABLE_CRITICAL_EXTENSION:
+ case LDAP_CONFIDENTIALITY_REQUIRED:
+ case LDAP_SASL_BIND_IN_PROGRESS:
+ case LDAP_INAPPROPRIATE_MATCHING:
+ case LDAP_ALIAS_PROBLEM:
+ case LDAP_ALIAS_DEREF_PROBLEM:
+ case LDAP_INAPPROPRIATE_AUTH:
+ case LDAP_INVALID_CREDENTIALS:
+ case LDAP_BUSY:
+ case LDAP_UNAVAILABLE:
+ case LDAP_UNWILLING_TO_PERFORM:
+ case LDAP_LOOP_DETECT:
+ case LDAP_SORT_CONTROL_MISSING:
+ case LDAP_INDEX_RANGE_ERROR:
+ case LDAP_RESULTS_TOO_LARGE:
+ case LDAP_AFFECTS_MULTIPLE_DSAS:
+ case LDAP_OTHER:
+ case LDAP_SERVER_DOWN:
+ case LDAP_LOCAL_ERROR:
+ case LDAP_ENCODING_ERROR:
+ case LDAP_DECODING_ERROR:
+ case LDAP_TIMEOUT:
+ case LDAP_AUTH_UNKNOWN:
+ case LDAP_FILTER_ERROR:
+ case LDAP_USER_CANCELLED:
+ case LDAP_PARAM_ERROR:
+ case LDAP_NO_MEMORY:
+ case LDAP_CONNECT_ERROR:
+ case LDAP_NOT_SUPPORTED:
+ case LDAP_CONTROL_NOT_FOUND:
+ case LDAP_NO_RESULTS_RETURNED:
+ case LDAP_MORE_RESULTS_TO_RETURN:
+ case LDAP_CLIENT_LOOP:
+ case LDAP_REFERRAL_LIMIT_EXCEEDED:
+ return_value = PR_FALSE;
+ break;
+ }
+ return return_value;
+}
+
+/* this function converts a state to its name - for debug output */
+static const char*
+state2name (int state)
+{
+ switch (state)
+ {
+ case STATE_START: return "start";
+ case STATE_WAIT_WINDOW_OPEN: return "wait_for_window_to_open";
+ case STATE_WAIT_CHANGES: return "wait_for_changes";
+ case STATE_READY_TO_ACQUIRE: return "ready_to_acquire_replica";
+ case STATE_BACKOFF_START: return "start_backoff";
+ case STATE_BACKOFF: return "backoff";
+ case STATE_SENDING_UPDATES: return "sending_updates";
+ case STATE_STOP_FATAL_ERROR: return "stop_fatal_error";
+ case STATE_STOP_FATAL_ERROR_PART2: return "stop_fatal_error";
+ case STATE_STOP_NORMAL_TERMINATION: return "stop_normal_termination";
+ default: return "invalid_state";
+ }
+}
+
+/* this function convert s an event to its name - for debug output */
+static const char*
+event2name (int event)
+{
+ switch (event)
+ {
+ case EVENT_WINDOW_OPENED: return "update_window_opened";
+ case EVENT_WINDOW_CLOSED: return "update_window_closed";
+ case EVENT_TRIGGERING_CRITERIA_MET: return "data_modified";
+ case EVENT_BACKOFF_EXPIRED: return "backoff_timer_expired";
+ case EVENT_REPLICATE_NOW: return "replicate_now";
+ case EVENT_PROTOCOL_SHUTDOWN: return "protocol_shutdown";
+ case EVENT_AGMT_CHANGED: return "agreement_changed";
+ default: return "invalid_event";
+ }
+}
+
+static const char*
+op2string(int op)
+{
+ switch (op) {
+ case SLAPI_OPERATION_ADD:
+ return "add";
+ case SLAPI_OPERATION_MODIFY:
+ return "modify";
+ case SLAPI_OPERATION_DELETE:
+ return "delete";
+ case SLAPI_OPERATION_MODRDN:
+ return "rename";
+ case SLAPI_OPERATION_EXTENDED:
+ return "extended";
+ }
+
+ return "unknown";
+}
diff --git a/ldap/servers/plugins/replication/repl5_init.c b/ldap/servers/plugins/replication/repl5_init.c
new file mode 100644
index 00000000..eae3b238
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_init.c
@@ -0,0 +1,572 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ repl5_init.c - plugin initialization functions
+*/
+
+/*
+ * Add an entry like the following to dse.ldif to enable this plugin:
+
+dn: cn=Multi-Master Replication Plugin,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Legacy Replication Plugin
+nsslapd-pluginpath: /export2/servers/Hydra-supplier/lib/replication-plugin.so
+nsslapd-plugininitfunc: replication_multimaster_plugin_init
+nsslapd-plugintype: object
+nsslapd-pluginenabled: on
+nsslapd-plugin-depends-on-type: database
+nsslapd-plugin-depends-on-named: Class of Service
+nsslapd-pluginid: replication-multimaster
+nsslapd-pluginversion: 5.0b1
+nsslapd-pluginvendor: Netscape Communications
+nsslapd-plugindescription: Multi-Master Replication Plugin
+
+*/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+#include "repl5.h"
+#include "cl5.h" /* changelog interface */
+#include "dirver.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+
+/* #ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif*/
+
+#define NSDS_REPL_NAME_PREFIX "Netscape Replication"
+
+static char *start_oid_list[] = {
+ REPL_START_NSDS50_REPLICATION_REQUEST_OID,
+ NULL
+};
+static char *start_name_list[] = {
+ NSDS_REPL_NAME_PREFIX " Start Session",
+ NULL
+};
+static char *end_oid_list[] = {
+ REPL_END_NSDS50_REPLICATION_REQUEST_OID,
+ NULL
+};
+static char *end_name_list[] = {
+ NSDS_REPL_NAME_PREFIX " End Session",
+ NULL
+};
+static char *total_oid_list[] = {
+ REPL_NSDS50_REPLICATION_ENTRY_REQUEST_OID,
+ NULL
+};
+static char *total_name_list[] = {
+ NSDS_REPL_NAME_PREFIX " Total Update Entry",
+ NULL
+};
+static char *response_oid_list[] = {
+ REPL_NSDS50_REPLICATION_RESPONSE_OID,
+ NULL
+};
+static char *response_name_list[] = {
+ NSDS_REPL_NAME_PREFIX " Response",
+ NULL
+};
+
+/* List of plugin identities for every plugin registered. Plugin identity
+ is passed by the server in the plugin init function and must be supplied
+ by the plugin to all internal operations it initiates
+ */
+
+/* ----------------------------- Multi-Master Replication Plugin */
+
+static Slapi_PluginDesc multimasterdesc = {"replication-multimaster", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Multi-master Replication Plugin"};
+static Slapi_PluginDesc multimasterpreopdesc = {"replication-multimaster-preop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Multi-master replication pre-operation plugin"};
+static Slapi_PluginDesc multimasterpostopdesc = {"replication-multimaster-postop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Multi-master replication post-operation plugin"};
+static Slapi_PluginDesc multimasterinternalpreopdesc = {"replication-multimaster-internalpreop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Multi-master replication internal pre-operation plugin"};
+static Slapi_PluginDesc multimasterinternalpostopdesc = {"replication-multimaster-internalpostop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Multimaster replication internal post-operation plugin"};
+static Slapi_PluginDesc multimasterbepreopdesc = {"replication-multimaster-bepreop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Multimaster replication bepre-operation plugin"};
+static Slapi_PluginDesc multimasterbepostopdesc = {"replication-multimaster-bepostop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Multimaster replication bepost-operation plugin"};
+static Slapi_PluginDesc multimasterextopdesc = { "replication-multimaster-extop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Multimaster replication extended-operation plugin" };
+
+static int multimaster_stopped_flag; /* A flag which is set when all the plugin threads are to stop */
+static int multimaster_started_flag = 0;
+
+/* Thread private data and interface */
+static PRUintn thread_private_agmtname; /* thread private index for logging*/
+static PRUintn thread_private_cache;
+
+char*
+get_thread_private_agmtname()
+{
+ char *agmtname = NULL;
+ if (thread_private_agmtname)
+ agmtname = PR_GetThreadPrivate(thread_private_agmtname);
+ return (agmtname ? agmtname : "");
+}
+
+void
+set_thread_private_agmtname(const char *agmtname)
+{
+ if (thread_private_agmtname)
+ PR_SetThreadPrivate(thread_private_agmtname, (void *)agmtname);
+}
+
+void*
+get_thread_private_cache ()
+{
+ void *buf = NULL;
+ if ( thread_private_cache )
+ buf = PR_GetThreadPrivate ( thread_private_cache );
+ return buf;
+}
+
+void
+set_thread_private_cache ( void *buf )
+{
+ if ( thread_private_cache )
+ PR_SetThreadPrivate ( thread_private_cache, buf );
+}
+
+char*
+get_repl_session_id (Slapi_PBlock *pb, char *idstr, CSN **csn)
+{
+ int connid=-1, opid=-1;
+ CSN *opcsn;
+ char opcsnstr[CSN_STRSIZE];
+
+ *idstr = '\0';
+ opcsn = NULL;
+ opcsnstr[0] = '\0';
+
+ if (pb) {
+ Slapi_Operation *op;
+ slapi_pblock_get (pb, SLAPI_OPERATION_ID, &opid);
+ /* Avoid "Connection is NULL and hence cannot access SLAPI_CONN_ID" */
+ if (opid) {
+ slapi_pblock_get (pb, SLAPI_CONN_ID, &connid);
+ sprintf (idstr, "conn=%d op=%d", connid, opid);
+ }
+
+ slapi_pblock_get ( pb, SLAPI_OPERATION, &op );
+ opcsn = operation_get_csn (op);
+ if (opcsn) {
+ csn_as_string (opcsn, PR_FALSE, opcsnstr);
+ strcat (idstr, " csn=");
+ strcat (idstr, opcsnstr);
+ }
+ }
+ if (csn) {
+ *csn = opcsn;
+ }
+ return idstr;
+}
+
+
+int
+multimaster_preop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterpreopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN, (void *) multimaster_preop_bind ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_ADD_FN, (void *) multimaster_preop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_DELETE_FN, (void *) multimaster_preop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void *) multimaster_preop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_MODRDN_FN, (void *) multimaster_preop_modrdn ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void *) multimaster_preop_search ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_COMPARE_FN, (void *) multimaster_preop_compare ) != 0)
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_preop_init failed\n" );
+ rc= -1;
+ }
+ return rc;
+}
+
+int
+multimaster_postop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterpostopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_BIND_FN, (void *) multimaster_postop_bind ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_ADD_FN, (void *) multimaster_postop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *) multimaster_postop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *) multimaster_postop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *) multimaster_postop_modrdn ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_postop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+int
+multimaster_internalpreop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterinternalpreopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN, (void *) multimaster_preop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN, (void *) multimaster_preop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN, (void *) multimaster_preop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN, (void *) multimaster_preop_modrdn ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_internalpreop_init failed\n" );
+ rc= -1;
+ }
+ return rc;
+}
+
+int
+multimaster_internalpostop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterinternalpostopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *) multimaster_postop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *) multimaster_postop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *) multimaster_postop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *) multimaster_postop_modrdn ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_internalpostop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+int
+multimaster_bepreop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterbepreopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_BE_PRE_ADD_FN, (void *) multimaster_bepreop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN, (void *) multimaster_bepreop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN, (void *) multimaster_bepreop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_BE_PRE_MODRDN_FN, (void *) multimaster_bepreop_modrdn ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_bepreop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+int
+multimaster_bepostop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterbepostopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_BE_POST_MODRDN_FN, (void *) multimaster_bepostop_modrdn ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_BE_POST_DELETE_FN, (void *) multimaster_bepostop_delete ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_bepostop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+int
+multimaster_start_extop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterextopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)start_oid_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)start_name_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)multimaster_extop_StartNSDS50ReplicationRequest ))
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_start_extop_init (StartNSDS50ReplicationRequest) failed\n" );
+ rc= -1;
+ }
+
+
+ return rc;
+}
+
+
+int
+multimaster_end_extop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterextopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)end_oid_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)end_name_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)multimaster_extop_EndNSDS50ReplicationRequest ))
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_end_extop_init (EndNSDS50ReplicationRequest) failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+
+int
+multimaster_total_extop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+ void *identity = NULL;
+
+ /* get plugin identity and store it to pass to internal operations */
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
+ PR_ASSERT (identity);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterextopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)total_oid_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)total_name_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)multimaster_extop_NSDS50ReplicationEntry ))
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_start_extop_init (NSDS50ReplicationEntry failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+int
+multimaster_response_extop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+ void *identity = NULL;
+
+ /* get plugin identity and store it to pass to internal operations */
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
+ PR_ASSERT (identity);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterextopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, (void *)response_oid_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, (void *)response_name_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *)extop_noop ))
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "multimaster_start_extop_init (NSDS50ReplicationResponse failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+
+static PRBool
+check_for_ldif_dump(Slapi_PBlock *pb)
+{
+ int i;
+ int argc;
+ char **argv;
+ PRBool return_value = PR_FALSE;
+
+ slapi_pblock_get( pb, SLAPI_ARGC, &argc);
+ slapi_pblock_get( pb, SLAPI_ARGV, &argv);
+
+ for (i = 1; i < argc && !return_value; i++)
+ {
+ if (strcmp(argv[i], "db2ldif") == 0)
+ {
+ return_value = PR_TRUE;
+ }
+ }
+ return return_value;
+}
+
+
+static PRBool is_ldif_dump = PR_FALSE;
+
+int
+multimaster_start( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if (!multimaster_started_flag)
+ {
+ /* Initialize thread private data for logging. Ignore if fails */
+ PR_NewThreadPrivateIndex (&thread_private_agmtname, NULL);
+ PR_NewThreadPrivateIndex (&thread_private_cache, NULL);
+
+ /* Decode the command line args to see if we're dumping to LDIF */
+ is_ldif_dump = check_for_ldif_dump(pb);
+
+ /* allow online replica configuration */
+ rc = replica_config_init ();
+ if (rc != 0)
+ goto out;
+
+ slapi_register_supported_control(REPL_NSDS50_UPDATE_INFO_CONTROL_OID,
+ SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE |
+ SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN);
+
+ /* Stash away our partial URL, used in RUVs */
+ rc = multimaster_set_local_purl();
+ if (rc != 0)
+ goto out;
+
+ /* Initialise support for cn=monitor */
+ rc = repl_monitor_init();
+ if (rc != 0)
+ goto out;
+
+ /* initialize name hash */
+ rc = replica_init_name_hash ();
+ if (rc != 0)
+ goto out;
+
+ /* initialize dn hash */
+ rc = replica_init_dn_hash ();
+ if (rc != 0)
+ goto out;
+
+ /* create replicas */
+ multimaster_mtnode_construct_replicas ();
+
+ /* Initialise the 5.0 Changelog */
+ rc = changelog5_init();
+ if (rc != 0)
+ goto out;
+
+ /* Initialize the replication agreements, unless we're dumping LDIF */
+ if (!is_ldif_dump)
+ {
+ rc = agmtlist_config_init();
+ if (rc != 0)
+ goto out;
+ }
+
+ /* check if the replica's data was reloaded offline and we need
+ to reinitialize replica's changelog. This should be done
+ after the changelog is initialized */
+
+ replica_enumerate_replicas (replica_check_for_data_reload, NULL);
+
+ /* register to be notified when backend state changes */
+ slapi_register_backend_state_change((void *)multimaster_be_state_change,
+ multimaster_be_state_change);
+
+ multimaster_started_flag = 1;
+ multimaster_stopped_flag = 0;
+ }
+out:
+ return rc;
+}
+
+int
+multimaster_stop( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if (!multimaster_stopped_flag)
+ {
+ if (!is_ldif_dump)
+ {
+ agmtlist_shutdown(); /* Shut down replication agreements */
+ }
+
+ /* unregister backend state change notification */
+ slapi_unregister_backend_state_change((void *)multimaster_be_state_change);
+
+ changelog5_cleanup(); /* Shut down the changelog */
+ multimaster_mtnode_extension_destroy(); /* Destroy mapping tree node exts */
+ replica_destroy_name_hash(); /* destroy the hash and its remaining content */
+ replica_config_destroy (); /* Destroy replica config info */
+ multimaster_stopped_flag = 1;
+ /* JCMREPL - Wait for all our threads to stop */
+ /* JCMREPL - Shut down the replication plugin */
+ /* JCMREPL - Mark all the replication plugin interfaces at not enabled. */
+ }
+ return rc;
+}
+
+
+PRBool
+multimaster_started()
+{
+ return(multimaster_started_flag != 0);
+}
+
+
+/*
+ * Initialize the multimaster replication plugin.
+ */
+int replication_multimaster_plugin_init(Slapi_PBlock *pb)
+{
+ static int multimaster_initialised= 0;
+ int rc= 0; /* OK */
+ void *identity = NULL;
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
+ PR_ASSERT (identity);
+ repl_set_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION, identity);
+
+ /* need the repl plugin path for the chain on update function */
+/* slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &entry);
+ PR_ASSERT(entry);
+ path = slapi_entry_attr_get_charptr(entry, "nsslapd-pluginpath");
+ repl_set_repl_plugin_path(path);
+ slapi_ch_free_string(&path);
+*/
+ multimaster_mtnode_extension_init ();
+
+ if(config_is_slapd_lite())
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "replication plugin not approved for restricted"
+ " mode Directory Server.\n" );
+ rc= -1;
+ }
+ if(rc==0 && !multimaster_initialised)
+ {
+ /* initialize replica hash - has to be done before mapping tree is
+ initialized so we can't do it in the start function */
+
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "replication_multimaster_plugin_init: failed to initialize replica hash\n");
+ return -1;
+ }
+
+ /* Initialize extensions */
+ repl_con_init_ext();
+ repl_sup_init_ext();
+
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&multimasterdesc );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) multimaster_start );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) multimaster_stop );
+
+ /* Register the plugin interfaces we implement */
+ rc= slapi_register_plugin("preoperation", 1 /* Enabled */, "multimaster_preop_init", multimaster_preop_init, "Multimaster replication preoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("postoperation", 1 /* Enabled */, "multimaster_postop_init", multimaster_postop_init, "Multimaster replication postoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("bepreoperation", 1 /* Enabled */, "multimaster_bepreop_init", multimaster_bepreop_init, "Multimaster replication bepreoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("bepostoperation", 1 /* Enabled */, "multimaster_bepostop_init", multimaster_bepostop_init, "Multimaster replication bepostoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("internalpreoperation", 1 /* Enabled */, "multimaster_internalpreop_init", multimaster_internalpreop_init, "Multimaster replication internal preoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("internalpostoperation", 1 /* Enabled */, "multimaster_internalpostop_init", multimaster_internalpostop_init, "Multimaster replication internal postoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_start_extop_init", multimaster_start_extop_init, "Multimaster replication start extended operation plugin", NULL, identity);
+ rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_end_extop_init", multimaster_end_extop_init, "Multimaster replication end extended operation plugin", NULL, identity);
+ rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_total_extop_init", multimaster_total_extop_init, "Multimaster replication total update extended operation plugin", NULL, identity);
+ rc= slapi_register_plugin("extendedop", 1 /* Enabled */, "multimaster_response_extop_init", multimaster_response_extop_init, "Multimaster replication extended response plugin", NULL, identity);
+ }
+ return rc;
+}
diff --git a/ldap/servers/plugins/replication/repl5_mtnode_ext.c b/ldap/servers/plugins/replication/repl5_mtnode_ext.c
new file mode 100644
index 00000000..e677927c
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_mtnode_ext.c
@@ -0,0 +1,194 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_replica.c */
+
+#include "repl.h" /* ONREPL - this is bad */
+#include "repl5.h"
+#include "cl5_api.h"
+
+/* global data */
+static DataList *root_list;
+
+/*
+ * Mapping tree node extension management. Node stores replica object
+ */
+
+void
+multimaster_mtnode_extension_init ()
+{
+ /* Initialize list that store node roots. It is used during
+ plugin startup to create replica objects */
+ root_list = dl_new ();
+ dl_init (root_list, 0);
+}
+
+void
+multimaster_mtnode_extension_destroy ()
+{
+ dl_cleanup (root_list, (FREEFN)slapi_sdn_free);
+ dl_free (&root_list);
+}
+
+/* This function loops over the list of node roots, constructing replica objects
+ where exist */
+void
+multimaster_mtnode_construct_replicas ()
+{
+ Slapi_DN *root;
+ int cookie;
+ Replica *r;
+ mapping_tree_node *mtnode;
+ multimaster_mtnode_extension *ext;
+
+ for (root = dl_get_first (root_list, &cookie); root;
+ root = dl_get_next (root_list, &cookie))
+ {
+ r = replica_new(root);
+ if (r)
+ {
+
+ mtnode = slapi_get_mapping_tree_node_by_dn(root);
+ if (mtnode == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "multimaster_mtnode_construct_replicas: "
+ "failed to locate mapping tree node for %s\n",
+ slapi_sdn_get_dn (root));
+ continue;
+ }
+
+ ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);
+ if (ext == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "multimaster_mtnode_construct_replicas: "
+ "failed to locate replication extension of mapping tree node for %s\n",
+ slapi_sdn_get_dn (root));
+ continue;
+ }
+
+ ext->replica = object_new(r, replica_destroy);
+ if (replica_add_by_name (replica_get_name (r), ext->replica) != 0)
+ {
+ object_release (ext->replica);
+ ext->replica = NULL;
+ }
+ }
+ }
+}
+
+void *
+multimaster_mtnode_extension_constructor (void *object, void *parent)
+{
+ mapping_tree_node *node;
+ const Slapi_DN *root;
+ multimaster_mtnode_extension *ext;
+
+ ext = (multimaster_mtnode_extension *)slapi_ch_calloc (1, sizeof (multimaster_mtnode_extension));
+
+ node = (mapping_tree_node *)object;
+
+ /* replica can be attached only to local public data */
+ if (slapi_mapping_tree_node_is_set (node, SLAPI_MTN_LOCAL) &&
+ !slapi_mapping_tree_node_is_set (node, SLAPI_MTN_PRIVATE))
+ {
+ root = slapi_get_mapping_tree_node_root (node);
+ /* ONREPL - we don't create replica object here because
+ we can't fully initialize replica here since backends
+ are not yet started. Instead, replica objects are created
+ during replication plugin startup */
+ if (root)
+ {
+ /* for now just store node root in the root list */
+ dl_add (root_list, slapi_sdn_dup (root));
+ }
+ }
+
+ return ext;
+}
+
+void
+multimaster_mtnode_extension_destructor (void* ext, void *object, void *parent)
+{
+ if (ext)
+ {
+ multimaster_mtnode_extension *mtnode_ext = (multimaster_mtnode_extension *)ext;
+ if (mtnode_ext->replica)
+ {
+ object_release (mtnode_ext->replica);
+ mtnode_ext->replica = NULL;
+ }
+ }
+}
+
+Object *
+replica_get_replica_from_dn (const Slapi_DN *dn)
+{
+ mapping_tree_node *mtnode;
+ multimaster_mtnode_extension *ext;
+
+ if (dn == NULL)
+ return NULL;
+
+ mtnode = slapi_get_mapping_tree_node_by_dn(dn);
+ if (mtnode == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_get_replica_from_dn: "
+ "failed to locate mapping tree node for %s\n",
+ slapi_sdn_get_dn (dn));
+ return NULL;
+ }
+
+ ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);
+ if (ext == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_get_replica_from_dn: "
+ "failed to locate replication extension of mapping tree node for %s\n",
+ slapi_sdn_get_dn (dn));
+ return NULL;
+ }
+
+ if (ext->replica)
+ object_acquire (ext->replica);
+
+ return ext->replica;
+}
+
+Object *replica_get_replica_for_op (Slapi_PBlock *pb)
+{
+ char *dn;
+ Slapi_DN *sdn;
+ Object *repl_obj = NULL;
+
+ if (pb)
+ {
+ /* get replica generation for this operation */
+ slapi_pblock_get (pb, SLAPI_TARGET_DN, &dn);
+ sdn = slapi_sdn_new_dn_byref(dn);
+ repl_obj = replica_get_replica_from_dn (sdn);
+
+ slapi_sdn_free (&sdn);
+ }
+
+ return repl_obj;
+}
+
+Object *replica_get_for_backend (const char *be_name)
+{
+ Slapi_Backend *be;
+ const Slapi_DN *suffix;
+ Object *r_obj;
+
+ be = slapi_be_select_by_instance_name(be_name);
+ if (NULL == be)
+ return NULL;
+
+ suffix = slapi_be_getsuffix(be, 0);
+
+ r_obj = replica_get_replica_from_dn (suffix);
+
+ return r_obj;
+}
diff --git a/ldap/servers/plugins/replication/repl5_plugins.c b/ldap/servers/plugins/replication/repl5_plugins.c
new file mode 100644
index 00000000..afee321a
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_plugins.c
@@ -0,0 +1,1416 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * repl5_consumer.c - consumer plugin functions
+ */
+
+/*
+ * LDAP Data Model Constraints...
+ *
+ * 1) Parent entry must exist.
+ * 2) RDN must be unique.
+ * 3) RDN components must be attribute values.
+ * 4) Must conform to the schema constraints - Single Valued Attributes.
+ * 5) Must conform to the schema constraints - Required Attributes.
+ * 6) Must conform to the schema constraints - No Extra Attributes.
+ * 7) Duplicate attribute values are not permited.
+ * 8) Cycle in the ancestry graph not permitted.
+ *
+ * Update Resolution Procedures...
+ * 1) ...
+ * 2) Add the UniqueID to the RDN.
+ * 3) Remove the not present RDN component.
+ * Use the UniqueID if the RDN becomes empty.
+ * 4) Keep the most recent value.
+ * 5) Ignore.
+ * 6) Ignore.
+ * 7) Keep the largest CSN for the duplicate value.
+ * 8) Don't check for this.
+ */
+
+#include "repl5.h"
+#include "repl.h"
+#include "cl5_api.h"
+#include "urp.h"
+
+static char *local_purl = NULL;
+static char *purl_attrs[] = {"nsslapd-localhost", "nsslapd-port", "nsslapd-secureport", NULL};
+
+/* Forward declarations */
+static void copy_operation_parameters(Slapi_PBlock *pb);
+static int write_changelog_and_ruv(Slapi_PBlock *pb);
+static int process_postop (Slapi_PBlock *pb);
+static int cancel_opcsn (Slapi_PBlock *pb);
+static int ruv_tombstone_op (Slapi_PBlock *pb);
+static PRBool process_operation (Slapi_PBlock *pb, const CSN *csn);
+static PRBool is_mmr_replica (Slapi_PBlock *pb);
+static const char *replica_get_purl_for_op (const Replica *r, Slapi_PBlock *pb, const CSN *opcsn);
+static void strip_legacy_info (slapi_operation_parameters *op_params);
+static void close_changelog_for_replica (Object *r_obj);
+static void process_new_ruv_for_replica (Replica *r);
+
+/*
+ * XXXggood - what to do if both ssl and non-ssl ports available? How
+ * do you know which to use? Offer a choice in replication config?
+ */
+int
+multimaster_set_local_purl()
+{
+ int rc = 0;
+ Slapi_Entry **entries;
+ Slapi_PBlock *pb = NULL;
+
+ pb = slapi_pblock_new ();
+
+ slapi_search_internal_set_pb (pb, "cn=config", LDAP_SCOPE_BASE,
+ "objectclass=*", purl_attrs, 0, NULL, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_search_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_set_local_purl: "
+ "unable to read server configuration: error %d\n", rc);
+ }
+ else
+ {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0])
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_set_local_purl: "
+ "server configuration missing\n");
+ rc = -1;
+ }
+ else
+ {
+ char *host = slapi_entry_attr_get_charptr(entries[0], "nsslapd-localhost");
+ char *port = slapi_entry_attr_get_charptr(entries[0], "nsslapd-port");
+ char *sslport = slapi_entry_attr_get_charptr(entries[0], "nsslapd-secureport");
+ if (host == NULL || ((port == NULL && sslport == NULL)))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "multimaster_set_local_purl: invalid server "
+ "configuration\n");
+ }
+ else
+ {
+ int len = 0;
+ char *patt = "ldap://%s:%s";
+ len += strlen(host);
+ len += strlen(port);
+ len += strlen(patt);
+ len++; /* for \0 */
+ local_purl = slapi_ch_malloc(len);
+ sprintf(local_purl, patt, host, port);
+ }
+
+ /* slapi_ch_free acceptS NULL pointer */
+ slapi_ch_free ((void**)&host);
+ slapi_ch_free ((void**)&port);
+ slapi_ch_free ((void**)&sslport);
+ }
+ }
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy (pb);
+
+ return rc;
+}
+
+
+const char *
+multimaster_get_local_purl()
+{
+ return local_purl;
+}
+
+
+/* ================= Multimaster Pre-Op Plugin Points ================== */
+
+
+int
+multimaster_preop_bind (Slapi_PBlock *pb)
+{
+ return 0;
+}
+
+int
+multimaster_preop_add (Slapi_PBlock *pb)
+{
+ Slapi_Operation *op;
+ int is_replicated_operation;
+ int is_fixup_operation;
+ int is_legacy_operation;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+
+ /* If there is no replica or it is a legacy consumer - we don't need to continue.
+ Legacy plugin is handling 4.0 consumer code */
+ /* but if it is legacy, csngen_handler needs to be assigned here */
+ is_legacy_operation =
+ operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
+ if (is_legacy_operation)
+ {
+ copy_operation_parameters(pb);
+ slapi_operation_set_csngen_handler(op,
+ (void*)replica_generate_next_csn);
+ return 0;
+ }
+
+ if (!is_mmr_replica (pb))
+ {
+ copy_operation_parameters(pb);
+ return 0;
+ }
+
+ is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
+ is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
+
+ if(is_replicated_operation)
+ {
+ if(!is_fixup_operation)
+ {
+ LDAPControl **ctrlp;
+ char sessionid[REPL_SESSION_ID_SIZE];
+ get_repl_session_id (pb, sessionid, NULL);
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
+ if (NULL != ctrlp)
+ {
+ CSN *csn = NULL;
+ char *target_uuid = NULL;
+ char *superior_uuid= NULL;
+ int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, &superior_uuid, &csn, NULL /* modrdn_mods */);
+ if (-1 == drc)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
+ "%s An error occurred while decoding the replication update "
+ "control - Add\n", sessionid);
+ }
+ else if (1 == drc)
+ {
+ /*
+ * For add operations, we just set the operation csn. The entry's
+ * uniqueid should already be an attribute of the replicated entry.
+ */
+ struct slapi_operation_parameters *op_params;
+
+ /* we don't want to process replicated operations with csn smaller
+ than the corresponding csn in the consumer's ruv */
+ if (!process_operation (pb, csn))
+ {
+ slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
+ "replication operation not processed, replica unavailable "
+ "or csn ignored", 0, 0);
+ csn_free (&csn);
+ slapi_ch_free ((void**)&target_uuid);
+ slapi_ch_free ((void**)&superior_uuid);
+
+ return -1;
+ }
+
+ operation_set_csn(op, csn);
+ slapi_pblock_set( pb, SLAPI_TARGET_UNIQUEID, target_uuid);
+ slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
+ /* JCMREPL - Complain if there's no superior uuid */
+ op_params->p.p_add.parentuniqueid= superior_uuid; /* JCMREPL - Not very elegant */
+ /* JCMREPL - When do these things get free'd? */
+ if(target_uuid!=NULL)
+ {
+ /*
+ * Make sure that the Unique Identifier in the Control is the
+ * same as the one in the entry.
+ */
+ Slapi_Entry *addentry;
+ char *entry_uuid;
+ slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &addentry );
+ entry_uuid= slapi_entry_attr_get_charptr( addentry, SLAPI_ATTR_UNIQUEID);
+ if(entry_uuid==NULL)
+ {
+ /* Odd that the entry doesn't have a Unique Identifier. But, we can fix it. */
+ slapi_entry_set_uniqueid(addentry, slapi_ch_strdup(target_uuid)); /* JCMREPL - strdup EVIL! There should be a uuid dup function. */
+ }
+ else
+ {
+ if(strcasecmp(entry_uuid,target_uuid)!=0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
+ "%s Replicated Add received with Control_UUID=%s and Entry_UUID=%s.\n",
+ sessionid, target_uuid,entry_uuid);
+ }
+
+ slapi_ch_free ((void**)&entry_uuid);
+ }
+ }
+ }
+ }
+ else
+ {
+ PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
+ }
+ }
+ else
+ {
+ /* Replicated & Fixup Operation */
+ }
+ }
+ else
+ {
+ slapi_operation_set_csngen_handler ( op, (void*)replica_generate_next_csn );
+ }
+
+ copy_operation_parameters(pb);
+
+ return 0;
+}
+
+int
+multimaster_preop_delete (Slapi_PBlock *pb)
+{
+ Slapi_Operation *op;
+ int is_replicated_operation;
+ int is_fixup_operation;
+ int is_legacy_operation;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+
+ /* If there is no replica or it is a legacy consumer - we don't need to continue.
+ Legacy plugin is handling 4.0 consumer code */
+ /* but if it is legacy, csngen_handler needs to be assigned here */
+ is_legacy_operation =
+ operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
+ if (is_legacy_operation)
+ {
+ copy_operation_parameters(pb);
+ slapi_operation_set_replica_attr_handler ( op, (void*)replica_get_attr );
+ slapi_operation_set_csngen_handler(op,
+ (void*)replica_generate_next_csn);
+ return 0;
+ }
+
+ if (!is_mmr_replica (pb))
+ {
+ copy_operation_parameters(pb);
+ return 0;
+ }
+
+ is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
+ is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
+
+ if(is_replicated_operation)
+ {
+ if(!is_fixup_operation)
+ {
+ LDAPControl **ctrlp;
+ char sessionid[REPL_SESSION_ID_SIZE];
+ get_repl_session_id (pb, sessionid, NULL);
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
+ if (NULL != ctrlp)
+ {
+ CSN *csn = NULL;
+ char *target_uuid = NULL;
+ int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, NULL, &csn, NULL /* modrdn_mods */);
+ if (-1 == drc)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
+ "%s An error occurred while decoding the replication update "
+ "control - Delete\n", sessionid);
+ }
+ else if (1 == drc)
+ {
+ /* we don't want to process replicated operations with csn smaller
+ than the corresponding csn in the consumer's ruv */
+ if (!process_operation (pb, csn))
+ {
+ slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
+ "replication operation not processed, replica unavailable "
+ "or csn ignored", 0, 0);
+ slapi_log_error(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
+ "%s replication operation not processed, replica unavailable "
+ "or csn ignored\n", sessionid);
+ csn_free (&csn);
+ slapi_ch_free ((void**)&target_uuid);
+
+ return -1;
+ }
+
+ /*
+ * For delete operations, we pass the uniqueid of the deleted entry
+ * to the backend and let it sort out which entry to really delete.
+ * We also set the operation csn.
+ */
+ operation_set_csn(op, csn);
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
+ }
+ }
+ else
+ {
+ PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
+ }
+ }
+ else
+ {
+ /* Replicated & Fixup Operation */
+ }
+ }
+ else
+ {
+ slapi_operation_set_csngen_handler ( op, (void*)replica_generate_next_csn );
+ }
+
+ copy_operation_parameters(pb);
+ slapi_operation_set_replica_attr_handler ( op, (void*)replica_get_attr );
+
+ return 0;
+}
+
+int
+multimaster_preop_modify (Slapi_PBlock *pb)
+{
+ Slapi_Operation *op;
+ int is_replicated_operation;
+ int is_fixup_operation;
+ int is_legacy_operation;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+
+ /* If there is no replica or it is a legacy consumer - we don't need to continue.
+ Legacy plugin is handling 4.0 consumer code */
+ /* but if it is legacy, csngen_handler needs to be assigned here */
+ is_legacy_operation =
+ operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
+ if (is_legacy_operation)
+ {
+ copy_operation_parameters(pb);
+ slapi_operation_set_csngen_handler(op,
+ (void*)replica_generate_next_csn);
+ return 0;
+ }
+
+ if (!is_mmr_replica (pb))
+ {
+ copy_operation_parameters(pb);
+ return 0;
+ }
+
+ is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
+ is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
+
+ if(is_replicated_operation)
+ {
+ if(!is_fixup_operation)
+ {
+ LDAPControl **ctrlp;
+ char sessionid[REPL_SESSION_ID_SIZE];
+ get_repl_session_id (pb, sessionid, NULL);
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
+ if (NULL != ctrlp)
+ {
+ CSN *csn = NULL;
+ char *target_uuid = NULL;
+ int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, NULL, &csn, NULL /* modrdn_mods */);
+ if (-1 == drc)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
+ "%s An error occurred while decoding the replication update "
+ "control- Modify\n", sessionid);
+ }
+ else if (1 == drc)
+ {
+ /* we don't want to process replicated operations with csn smaller
+ than the corresponding csn in the consumer's ruv */
+ if (!process_operation (pb, csn))
+ {
+ slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
+ "replication operation not processed, replica unavailable "
+ "or csn ignored", 0, 0);
+ slapi_log_error(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM,
+ "%s replication operation not processed, replica unavailable "
+ "or csn ignored\n", sessionid);
+ csn_free (&csn);
+ slapi_ch_free ((void**)&target_uuid);
+
+ return -1;
+ }
+
+ /*
+ * For modify operations, we pass the uniqueid of the modified entry
+ * to the backend and let it sort out which entry to really modify.
+ * We also set the operation csn.
+ */
+ operation_set_csn(op, csn);
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
+ }
+ }
+ else
+ {
+ PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
+ }
+ }
+ else
+ {
+ /* Replicated & Fixup Operation */
+ }
+ }
+ else
+ {
+ slapi_operation_set_csngen_handler ( op, (void*)replica_generate_next_csn );
+ }
+
+ copy_operation_parameters(pb);
+ return 0;
+}
+
+int
+multimaster_preop_modrdn (Slapi_PBlock *pb)
+{
+ Slapi_Operation *op;
+ int is_replicated_operation;
+ int is_fixup_operation;
+ int is_legacy_operation;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+
+ /* If there is no replica or it is a legacy consumer - we don't need to continue.
+ Legacy plugin is handling 4.0 consumer code */
+ /* but if it is legacy, csngen_handler needs to be assigned here */
+ is_legacy_operation =
+ operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
+ if (is_legacy_operation)
+ {
+ copy_operation_parameters(pb);
+ slapi_operation_set_csngen_handler(op,
+ (void*)replica_generate_next_csn);
+ return 0;
+ }
+
+ if (!is_mmr_replica (pb))
+ {
+ copy_operation_parameters(pb);
+ return 0;
+ }
+
+ is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
+ is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
+
+ if(is_replicated_operation)
+ {
+ if(!is_fixup_operation)
+ {
+ LDAPControl **ctrlp;
+ char sessionid[REPL_SESSION_ID_SIZE];
+ get_repl_session_id (pb, sessionid, NULL);
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
+ if (NULL != ctrlp)
+ {
+ CSN *csn = NULL;
+ char *target_uuid = NULL;
+ char *newsuperior_uuid = NULL;
+ LDAPMod **modrdn_mods = NULL;
+ int drc = decode_NSDS50ReplUpdateInfoControl(ctrlp, &target_uuid, &newsuperior_uuid,
+ &csn, &modrdn_mods);
+ if (-1 == drc)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, REPLICATION_SUBSYSTEM,
+ "%s An error occurred while decoding the replication update "
+ "control - ModRDN\n", sessionid);
+ }
+ else if (1 == drc)
+ {
+ /*
+ * For modrdn operations, we pass the uniqueid of the entry being
+ * renamed to the backend and let it sort out which entry to really
+ * rename. We also set the operation csn, and if the newsuperior_uuid
+ * was sent, we decode that as well.
+ */
+ struct slapi_operation_parameters *op_params;
+
+ /* we don't want to process replicated operations with csn smaller
+ than the corresponding csn in the consumer's ruv */
+ if (!process_operation (pb, csn))
+ {
+ slapi_send_ldap_result(pb, LDAP_SUCCESS, 0,
+ "replication operation not processed, replica unavailable "
+ "or csn ignored", 0, 0);
+ csn_free (&csn);
+ slapi_ch_free ((void**)&target_uuid);
+ slapi_ch_free ((void**)&newsuperior_uuid);
+ ldap_mods_free (modrdn_mods, 1);
+
+ return -1;
+ }
+
+ operation_set_csn(op, csn);
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, target_uuid);
+ slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
+ op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid= newsuperior_uuid; /* JCMREPL - Not very elegant */
+ }
+
+ /*
+ * The replicated modrdn operation may also contain a sequence
+ * that contains side effects of the modrdn operation, e.g. the
+ * modifiersname and modifytimestamp are updated.
+ */
+ if (NULL != modrdn_mods)
+ {
+ LDAPMod **mods;
+ Slapi_Mods smods;
+ int i;
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ slapi_mods_init_passin(&smods, mods);
+ for (i = 0; NULL != modrdn_mods[i]; i++)
+ {
+ slapi_mods_add_ldapmod(&smods, modrdn_mods[i]); /* Does not copy mod */
+ }
+ mods = slapi_mods_get_ldapmods_passout(&smods);
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods);
+ slapi_mods_done(&smods);
+ slapi_ch_free((void **)&modrdn_mods); /* Free container only - contents are referred to by array "mods" */
+ }
+ }
+ else
+ {
+ PR_ASSERT(0); /* JCMREPL - A Replicated Operation with no Repl Baggage control... What does that mean? */
+ }
+ }
+ else
+ {
+ /* Replicated & Fixup Operation */
+ }
+ }
+ else
+ {
+ slapi_operation_set_csngen_handler ( op, (void*)replica_generate_next_csn );
+ }
+
+ copy_operation_parameters(pb);
+
+ return 0;
+}
+
+int
+multimaster_preop_search (Slapi_PBlock *pb)
+{
+ return 0;
+}
+
+int
+multimaster_preop_compare (Slapi_PBlock *pb)
+{
+ return 0;
+}
+
+static void
+purge_entry_state_information (Slapi_PBlock *pb)
+{
+ CSN *purge_csn;
+ Object *repl_obj;
+ Replica *replica;
+
+ /* we don't want to trim RUV tombstone because we will
+ deadlock with ourself */
+ if (ruv_tombstone_op (pb))
+ return;
+
+ repl_obj = replica_get_replica_for_op(pb);
+ if (NULL != repl_obj)
+ {
+ replica = object_get_data(repl_obj);
+ if (NULL != replica)
+ {
+ purge_csn = replica_get_purge_csn(replica);
+ }
+ if (NULL != purge_csn)
+ {
+ Slapi_Entry *e;
+ int optype;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &optype);
+ switch (optype)
+ {
+ case SLAPI_OPERATION_MODIFY:
+ slapi_pblock_get(pb, SLAPI_MODIFY_EXISTING_ENTRY, &e);
+ break;
+ case SLAPI_OPERATION_MODRDN:
+ /* XXXggood - the following always gives a NULL entry - why? */
+ slapi_pblock_get(pb, SLAPI_MODRDN_EXISTING_ENTRY, &e);
+ break;
+ case SLAPI_OPERATION_DELETE:
+ slapi_pblock_get(pb, SLAPI_DELETE_EXISTING_ENTRY, &e);
+ break;
+ default:
+ e = NULL; /* Don't purge on ADD - not needed */
+ break;
+ }
+ if (NULL != e)
+ {
+ char csn_str[CSN_STRSIZE];
+ entry_purge_state_information(e, purge_csn);
+ /* conntion is always null */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Purged state information from entry %s up to "
+ "CSN %s\n", slapi_entry_get_dn(e),
+ csn_as_string(purge_csn, PR_FALSE, csn_str));
+ }
+ csn_free(&purge_csn);
+ }
+ object_release(repl_obj);
+ }
+}
+
+int
+multimaster_bepreop_add (Slapi_PBlock *pb)
+{
+ int rc= 0;
+ Slapi_Operation *op;
+ int is_replicated_operation;
+ int is_fixup_operation;
+ int is_legacy_operation;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
+ is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
+ is_legacy_operation= operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
+
+ /* For replicated operations, apply URP algorithm */
+ if (is_replicated_operation && !is_fixup_operation)
+ {
+ rc = urp_add_operation(pb);
+ }
+
+ return rc;
+}
+
+int
+multimaster_bepreop_delete (Slapi_PBlock *pb)
+{
+ int rc= 0;
+ Slapi_Operation *op;
+ int is_replicated_operation;
+ int is_fixup_operation;
+ int is_legacy_operation;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
+ is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
+ is_legacy_operation= operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
+
+ /* For replicated operations, apply URP algorithm */
+ if(is_replicated_operation && !is_fixup_operation)
+ {
+ rc = urp_delete_operation(pb);
+ }
+
+ return rc;
+}
+
+int
+multimaster_bepreop_modify (Slapi_PBlock *pb)
+{
+ int rc= 0;
+ Slapi_Operation *op;
+ int is_replicated_operation;
+ int is_fixup_operation;
+ int is_legacy_operation;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
+ is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
+ is_legacy_operation= operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
+
+ /* For replicated operations, apply URP algorithm */
+ if(is_replicated_operation && !is_fixup_operation)
+ {
+ rc = urp_modify_operation(pb);
+ }
+
+ /* Clean up old state information */
+ purge_entry_state_information(pb);
+
+ return rc;
+}
+
+int
+multimaster_bepreop_modrdn (Slapi_PBlock *pb)
+{
+ int rc= 0;
+ Slapi_Operation *op;
+ int is_replicated_operation;
+ int is_fixup_operation;
+ int is_legacy_operation;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
+ is_fixup_operation= operation_is_flag_set(op,OP_FLAG_REPL_FIXUP);
+ is_legacy_operation= operation_is_flag_set(op,OP_FLAG_LEGACY_REPLICATION_DN);
+
+ /* For replicated operations, apply URP algorithm */
+ if(is_replicated_operation && !is_fixup_operation)
+ {
+ rc = urp_modrdn_operation(pb);
+ }
+
+ /* Clean up old state information */
+ purge_entry_state_information(pb);
+
+ return rc;
+}
+
+int
+multimaster_bepostop_modrdn (Slapi_PBlock *pb)
+{
+ return 0;
+}
+
+int
+multimaster_bepostop_delete (Slapi_PBlock *pb)
+{
+ return 0;
+}
+
+/* postop - write to changelog */
+int
+multimaster_postop_bind (Slapi_PBlock *pb)
+{
+ return 0;
+}
+
+int
+multimaster_postop_add (Slapi_PBlock *pb)
+{
+ return process_postop(pb);
+}
+
+int
+multimaster_postop_delete (Slapi_PBlock *pb)
+{
+ int rc;
+ Slapi_Operation *op;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ if ( ! operation_is_flag_set (op, OP_FLAG_REPL_FIXUP) )
+ {
+ urp_post_delete_operation (pb);
+ }
+ rc = process_postop(pb);
+ return rc;
+}
+
+int
+multimaster_postop_modify (Slapi_PBlock *pb)
+{
+ return process_postop(pb);
+}
+
+int
+multimaster_postop_modrdn (Slapi_PBlock *pb)
+{
+ int rc;
+ Slapi_Operation *op;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ if ( ! operation_is_flag_set (op, OP_FLAG_REPL_FIXUP) )
+ {
+ urp_post_modrdn_operation (pb);
+ }
+ rc = process_postop(pb);
+ return rc;
+}
+
+
+/* Helper functions */
+
+/*
+ * This function makes a copy of the operation parameters
+ * and stashes them in the consumer operation extension.
+ * This is where the 5.0 Change Log will get the operation
+ * details from.
+ */
+static void
+copy_operation_parameters(Slapi_PBlock *pb)
+{
+ Slapi_Operation *op = NULL;
+ struct slapi_operation_parameters *op_params;
+ supplier_operation_extension *opext;
+ Object *repl_obj;
+ Replica *replica;
+
+ repl_obj = replica_get_replica_for_op (pb);
+
+ /* we are only interested in the updates to replicas */
+ if (repl_obj)
+ {
+ /* we only save the original operation parameters for replicated operations
+ since client operations don't go through urp engine and pblock data can be logged */
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op );
+ PR_ASSERT (op);
+
+ replica = (Replica*)object_get_data (repl_obj);
+ PR_ASSERT (replica);
+
+ opext = (supplier_operation_extension*) repl_sup_get_ext (REPL_SUP_EXT_OP, op);
+ if (operation_is_flag_set(op,OP_FLAG_REPLICATED) &&
+ !operation_is_flag_set(op, OP_FLAG_REPL_FIXUP))
+ {
+ slapi_pblock_get (pb, SLAPI_OPERATION_PARAMETERS, &op_params);
+ opext->operation_parameters= operation_parameters_dup(op_params);
+ }
+
+ /* this condition is needed to avoid re-entering lock when
+ ruv state is updated */
+ if (!operation_is_flag_set(op, OP_FLAG_REPL_FIXUP))
+ {
+ /* save replica generation in case it changes */
+ opext->repl_gen = replica_get_generation (replica);
+ }
+
+ object_release (repl_obj);
+ }
+}
+
+/*
+ * Helper function: update the RUV so that it reflects the
+ * locally-processed update. This is called for both replicated
+ * and non-replicated operations.
+ */
+static void
+update_ruv_component(Replica *replica, CSN *opcsn, Slapi_PBlock *pb)
+{
+ PRBool legacy;
+ char *purl;
+
+ if (!replica || !opcsn)
+ return;
+
+ /* Replica configured, so update its ruv */
+ legacy = replica_is_legacy_consumer (replica);
+ if (legacy)
+ purl = replica_get_legacy_purl (replica);
+ else
+ purl = (char*)replica_get_purl_for_op (replica, pb, opcsn);
+
+ replica_update_ruv(replica, opcsn, purl);
+
+ if (legacy)
+ {
+ slapi_ch_free ((void**)&purl);
+ }
+}
+
+/*
+ * Write the changelog. Note: it is an error to call write_changelog_and_ruv() for fixup
+ * operations. The caller should avoid calling this function if the operation is
+ * a fixup op.
+ * Also update the ruv - we need to do this while we have the replica lock acquired
+ * so that the csn is written to the changelog and the ruv is updated with the csn
+ * in one atomic operation - if there is no changelog, we still need to update
+ * the ruv (e.g. for consumers)
+ */
+static int
+write_changelog_and_ruv (Slapi_PBlock *pb)
+{
+ int rc;
+ slapi_operation_parameters *op_params = NULL;
+ Object *repl_obj;
+ int return_value = 0;
+ Replica *r;
+
+ /* we only log changes for operations applied to a replica */
+ repl_obj = replica_get_replica_for_op (pb);
+ if (repl_obj == NULL)
+ return 0;
+
+ r = (Replica*)object_get_data (repl_obj);
+ PR_ASSERT (r);
+
+ if (replica_is_flag_set (r, REPLICA_LOG_CHANGES) &&
+ (cl5GetState () == CL5_STATE_OPEN))
+ {
+ supplier_operation_extension *opext = NULL;
+ const char *repl_name;
+ char *repl_gen;
+ Slapi_Operation *op;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ opext = (supplier_operation_extension*) repl_sup_get_ext (REPL_SUP_EXT_OP, op);
+ PR_ASSERT (opext);
+
+ /* get replica generation and replica name to pass to the write function */
+ repl_name = replica_get_name (r);
+ repl_gen = opext->repl_gen;
+ PR_ASSERT (repl_name && repl_gen);
+
+ /* for replicated operations, we log the original, non-urp data which is
+ saved in the operation extension */
+ if (operation_is_flag_set(op,OP_FLAG_REPLICATED))
+ {
+ PR_ASSERT (opext->operation_parameters);
+ op_params = opext->operation_parameters;
+ }
+ else /* since client operations don't go through urp, we log the operation data in pblock */
+ {
+ Slapi_Entry *e = NULL;
+ const char *uniqueid = NULL;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION_PARAMETERS, &op_params);
+ PR_ASSERT (op_params);
+
+ /* need to set uniqueid operation parameter */
+ /* we try to use the appropriate entry (pre op or post op)
+ depending on the type of operation (add, delete, modify)
+ However, in some cases, the backend operation may fail in
+ a non fatal way (e.g. attempt to remove an attribute value
+ that does not exist) but we still need to log the change.
+ So, the POST_OP entry may not have been set in the FE modify
+ code. In that case, we use the PRE_OP entry.
+ */
+ slapi_pblock_get (pb, SLAPI_ENTRY_POST_OP, &e);
+ if ((e == NULL) ||
+ (op_params->operation_type == SLAPI_OPERATION_DELETE))
+ {
+ slapi_pblock_get (pb, SLAPI_ENTRY_PRE_OP, &e);
+ }
+
+ PR_ASSERT (e);
+
+ uniqueid = slapi_entry_get_uniqueid (e);
+ PR_ASSERT (uniqueid);
+
+ op_params->target_address.uniqueid = slapi_ch_strdup (uniqueid);
+ }
+
+ /* we might have stripped all the mods - in that case we do not
+ log the operation */
+ if (op_params->operation_type != SLAPI_OPERATION_MODIFY ||
+ op_params->p.p_modify.modify_mods != NULL)
+ {
+ if (cl5_is_diskfull() && !cl5_diskspace_is_available())
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "write_changelog_and_ruv: Skipped due to DISKFULL\n");
+ return 0;
+ }
+ rc = cl5WriteOperation(repl_name, repl_gen, op_params,
+ !operation_is_flag_set(op, OP_FLAG_REPLICATED));
+ if (rc != CL5_SUCCESS)
+ {
+ char csn_str[CSN_STRSIZE];
+ /* ONREPL - log error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "write_changelog_and_ruv: can't add a change for "
+ "%s (uniqid: %s, optype: %u) to changelog csn %s\n",
+ op_params->target_address.dn,
+ op_params->target_address.uniqueid,
+ op_params->operation_type,
+ csn_as_string(op_params->csn, PR_FALSE, csn_str));
+ return_value = 1;
+ }
+ }
+
+ if (!operation_is_flag_set(op,OP_FLAG_REPLICATED))
+ {
+ slapi_ch_free((void**)&op_params->target_address.uniqueid);
+ }
+ }
+
+ /*
+ This was moved because we need to write the changelog and update
+ the ruv in one atomic operation - I have seen cases where the inc
+ protocol thread interrupts this thread between the time the changelog
+ is written and the ruv is updated - this causes confusion in several
+ places, especially in _cl5SkipReplayEntry since it cannot find the csn it
+ just read from the changelog in either the supplier or consumer ruv
+ */
+ if (0 == return_value) {
+ Slapi_Operation *op;
+ CSN *opcsn;
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op );
+ opcsn = operation_get_csn(op);
+ update_ruv_component(r, opcsn, pb);
+ }
+
+ object_release (repl_obj);
+ return return_value;
+}
+
+/*
+ * Postop processing - write the changelog if the operation resulted in
+ * an LDAP_SUCCESS result code, update the RUV, and notify the replication
+ * agreements about the change.
+ * If the result code is not LDAP_SUCCESS, then cancel the operation CSN.
+ */
+static int
+process_postop (Slapi_PBlock *pb)
+{
+ int rc = LDAP_SUCCESS;
+ Slapi_Operation *op;
+ Slapi_Backend *be;
+ int is_replicated_operation = 0;
+ CSN *opcsn = NULL;
+ char sessionid[REPL_SESSION_ID_SIZE];
+
+ /* we just let fixup operations through */
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op );
+ if ((operation_is_flag_set(op, OP_FLAG_REPL_FIXUP)) ||
+ (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY)))
+ {
+ return 0;
+ }
+
+ /* ignore operations intended for chaining backends - they will be
+ replicated back to us or should be ignored anyway
+ replicated operations should be processed normally, as they should
+ be going to a local backend */
+ is_replicated_operation= operation_is_flag_set(op,OP_FLAG_REPLICATED);
+ slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+ if (!is_replicated_operation &&
+ slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA))
+ {
+ return 0;
+ }
+
+ get_repl_session_id (pb, sessionid, &opcsn);
+
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc);
+ /*
+ * Don't abandon writing changelog since we'd do everything
+ * possible to keep the changelog in sync with the backend
+ * db which was committed before this function was called.
+ *
+ * if (rc == LDAP_SUCCESS && !slapi_op_abandoned(pb))
+ */
+ if (rc == LDAP_SUCCESS)
+ {
+ rc = write_changelog_and_ruv(pb);
+ if (rc == 0)
+ {
+ agmtlist_notify_all(pb);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s process postop: error writing changelog and ruv\n", sessionid);
+ }
+ }
+ else if (opcsn)
+ {
+ rc = cancel_opcsn (pb);
+
+ /* Don't try to get session id since conn is always null */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s process postop: canceling operation csn\n", sessionid);
+ }
+
+ /* the target unique id is set in the modify_preop above, so
+ we need to free it */
+ /* The following bunch of frees code does not belong to this place
+ * but rather to operation_free who should be responsible for calling
+ * operation_parameters_free and it doesn't. I guess this is like this
+ * because several crashes happened in the past regarding some opparams
+ * that were getting individually freed before they should. Whatever
+ * the case, this is not the place and we should make sure that this
+ * code gets removed for 5.next and substituted by the strategy (operation_free).
+ * For 5.0, such change is too risky, so this will be done here */
+ if (is_replicated_operation)
+ {
+ slapi_operation_parameters *op_params = NULL;
+ int optype = 0;
+ /* target uid and csn are set for all repl operations. Free them */
+ char *target_uuid = NULL;
+ slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &optype);
+ slapi_pblock_get(pb, SLAPI_TARGET_UNIQUEID, &target_uuid);
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, NULL);
+ slapi_ch_free((void**)&target_uuid);
+ if (optype == SLAPI_OPERATION_ADD) {
+ slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
+ slapi_ch_free((void **) &op_params->p.p_add.parentuniqueid);
+ }
+ if (optype == SLAPI_OPERATION_MODRDN) {
+ slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
+ slapi_ch_free((void **) &op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid);
+ }
+ }
+ if (NULL == opcsn)
+ opcsn = operation_get_csn(op);
+ if (opcsn)
+ csn_free(&opcsn);
+
+ return rc;
+}
+
+
+/*
+ * Cancel an operation CSN. This removes it from any CSN pending lists.
+ * This function is called when a previously-generated CSN will not
+ * be needed, e.g. if the update operation produced an error.
+ */
+static int
+cancel_opcsn (Slapi_PBlock *pb)
+{
+ Object *repl_obj;
+ Slapi_Operation *op = NULL;
+
+ PR_ASSERT (pb);
+
+ repl_obj = replica_get_replica_for_op (pb);
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ PR_ASSERT (op);
+ if (repl_obj)
+ {
+ Replica *r;
+ Object *gen_obj;
+ CSNGen *gen;
+ CSN *opcsn;
+
+ r = (Replica*)object_get_data (repl_obj);
+ PR_ASSERT (r);
+ opcsn = operation_get_csn(op);
+
+ if (!operation_is_flag_set(op,OP_FLAG_REPLICATED))
+ {
+ /* get csn generator for the replica */
+ gen_obj = replica_get_csngen (r);
+ PR_ASSERT (gen_obj);
+ gen = (CSNGen*)object_get_data (gen_obj);
+
+ if (NULL != opcsn)
+ {
+ csngen_abort_csn (gen, operation_get_csn(op));
+ }
+
+ object_release (gen_obj);
+ }
+ else if (!operation_is_flag_set(op,OP_FLAG_REPL_FIXUP))
+ {
+ Object *ruv_obj;
+
+ ruv_obj = replica_get_ruv (r);
+ PR_ASSERT (ruv_obj);
+ ruv_cancel_csn_inprogress ((RUV*)object_get_data (ruv_obj), opcsn);
+ object_release (ruv_obj);
+ }
+
+ object_release (repl_obj);
+ }
+
+ return 0;
+}
+
+
+
+/*
+ * Return non-zero if the target entry DN is the DN of the RUV tombstone
+ * entry.
+ * The entry has rdn of nsuniqueid = ffffffff-ffffffff-ffffffff-ffffffff
+ */
+static int
+ruv_tombstone_op (Slapi_PBlock *pb)
+{
+ char *uniqueid;
+ int rc;
+
+ slapi_pblock_get (pb, SLAPI_TARGET_UNIQUEID, &uniqueid);
+
+ rc = uniqueid && strcasecmp (uniqueid, RUV_STORAGE_ENTRY_UNIQUEID) == 0;
+
+ return rc;
+}
+
+/* we don't want to process replicated operations with csn smaller
+ than the corresponding csn in the consumer's ruv */
+static PRBool
+process_operation (Slapi_PBlock *pb, const CSN *csn)
+{
+ Object *r_obj;
+ Replica *r;
+ Object *ruv_obj;
+ RUV *ruv;
+ int rc;
+
+ r_obj = replica_get_replica_for_op(pb);
+ if (r_obj == NULL)
+ {
+ char sessionid[REPL_SESSION_ID_SIZE];
+ get_repl_session_id (pb, sessionid, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s process_operation: "
+ "can't locate replica for the replicated operation\n",
+ sessionid );
+ return PR_FALSE;
+ }
+
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r);
+
+ ruv_obj = replica_get_ruv (r);
+ PR_ASSERT (ruv_obj);
+
+ ruv = (RUV*)object_get_data (ruv_obj);
+ PR_ASSERT (ruv);
+
+ rc = ruv_add_csn_inprogress (ruv, csn);
+
+ object_release (ruv_obj);
+ object_release (r_obj);
+
+ return (rc == RUV_SUCCESS);
+}
+
+static PRBool
+is_mmr_replica (Slapi_PBlock *pb)
+{
+ Object *r_obj;
+ Replica *r;
+ PRBool mmr;
+
+ r_obj = replica_get_replica_for_op(pb);
+ if (r_obj == NULL)
+ {
+ return PR_FALSE;
+ }
+
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r);
+
+ mmr = !replica_is_legacy_consumer (r);
+
+ object_release (r_obj);
+
+ return mmr;
+}
+
+static const char *replica_get_purl_for_op (const Replica *r, Slapi_PBlock *pb, const CSN *opcsn)
+{
+ int is_replicated_op;
+ const char *purl;
+
+ slapi_pblock_get(pb, SLAPI_IS_MMR_REPLICATED_OPERATION, &is_replicated_op);
+
+ if (!is_replicated_op)
+ {
+ purl = multimaster_get_local_purl();
+ }
+ else
+ {
+ /* Get the appropriate partial URL from the supplier RUV */
+ Slapi_Connection *conn;
+ consumer_connection_extension *connext;
+ slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
+ connext = (consumer_connection_extension *)repl_con_get_ext(
+ REPL_CON_EXT_CONN, conn);
+ if (NULL == connext || NULL == connext->supplier_ruv)
+ {
+ char sessionid[REPL_SESSION_ID_SIZE];
+ get_repl_session_id (pb, sessionid, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "%s replica_get_purl_for_op: "
+ "cannot obtain consumer connection extension or supplier_ruv.\n",
+ sessionid);
+ }
+ else
+ {
+ purl = ruv_get_purl_for_replica(connext->supplier_ruv,
+ csn_get_replicaid(opcsn));
+ }
+ }
+
+ return purl;
+}
+
+/* ONREPL at the moment, I decided not to trim copiedFrom and copyingFrom
+ attributes when sending operation to replicas. This is because, each
+ operation results in a state information stored in the database and
+ if we don't replay all operations we will endup with state inconsistency.
+
+ Keeping the function just in case
+ */
+static void strip_legacy_info (slapi_operation_parameters *op_params)
+{
+ switch (op_params->operation_type)
+ {
+ case SLAPI_OPERATION_ADD:
+ slapi_entry_delete_values_sv(op_params->p.p_add.target_entry,
+ type_copiedFrom, NULL);
+ slapi_entry_delete_values_sv(op_params->p.p_add.target_entry,
+ type_copyingFrom, NULL);
+ break;
+ case SLAPI_OPERATION_MODIFY:
+ {
+ Slapi_Mods smods;
+ LDAPMod *mod;
+
+ slapi_mods_init_byref(&smods, op_params->p.p_modify.modify_mods);
+ mod = slapi_mods_get_first_mod(&smods);
+ while (mod)
+ {
+ /* modify just to update copiedFrom or copyingFrom attribute
+ does not contain modifiersname or modifytime - so we don't
+ have to strip them */
+ if (strcasecmp (mod->mod_type, type_copiedFrom) == 0 ||
+ strcasecmp (mod->mod_type, type_copyingFrom) == 0)
+ slapi_mods_remove(&smods);
+ mod = slapi_mods_get_next_mod(&smods);
+ }
+
+ op_params->p.p_modify.modify_mods = slapi_mods_get_ldapmods_passout (&smods);
+ slapi_mods_done (&smods);
+
+ break;
+ }
+
+ default: break;
+ }
+}
+
+/* this function is called when state of a backend changes */
+void
+multimaster_be_state_change (void *handle, char *be_name, int old_be_state, int new_be_state)
+{
+ Object *r_obj;
+ Replica *r;
+
+ /* check if we have replica associated with the backend */
+ r_obj = replica_get_for_backend (be_name);
+ if (r_obj == NULL)
+ return;
+
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r);
+
+ if (new_be_state == SLAPI_BE_STATE_ON)
+ {
+ /* backend came back online - restart replication */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_be_state_change: "
+ "replica %s is coming online; enabling replication\n",
+ slapi_sdn_get_ndn (replica_get_root (r)));
+ replica_enable_replication (r);
+ }
+ else if (new_be_state == SLAPI_BE_STATE_OFFLINE)
+ {
+ /* backend is about to be taken down - disable replication */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_be_state_change: "
+ "replica %s is going offline; disabling replication\n",
+ slapi_sdn_get_ndn (replica_get_root (r)));
+ replica_disable_replication (r, r_obj);
+ }
+ else if (new_be_state == SLAPI_BE_STATE_DELETE)
+ {
+ /* backend is about to be removed - disable replication */
+ if (old_be_state == SLAPI_BE_STATE_ON)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "multimaster_be_state_change: "
+ "replica %s is about to be deleted; disabling replication\n",
+ slapi_sdn_get_ndn (replica_get_root (r)));
+ replica_disable_replication (r, r_obj);
+ }
+ }
+
+ object_release (r_obj);
+}
+
+static void
+close_changelog_for_replica (Object *r_obj)
+{
+ if (cl5GetState () == CL5_STATE_OPEN)
+ cl5CloseDB (r_obj);
+}
diff --git a/ldap/servers/plugins/replication/repl5_prot_private.h b/ldap/servers/plugins/replication/repl5_prot_private.h
new file mode 100644
index 00000000..fbaf96e4
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_prot_private.h
@@ -0,0 +1,66 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _REPL5_PROT_PRIVATE_H_
+#define _REPL5_PROT_PRIVATE_H_
+
+#define ACQUIRE_SUCCESS 101
+#define ACQUIRE_REPLICA_BUSY 102
+#define ACQUIRE_FATAL_ERROR 103
+#define ACQUIRE_CONSUMER_WAS_UPTODATE 104
+#define ACQUIRE_TRANSIENT_ERROR 105
+
+typedef struct private_repl_protocol
+{
+ void (*delete)(struct private_repl_protocol **);
+ void (*run)(struct private_repl_protocol *);
+ int (*stop)(struct private_repl_protocol *);
+ int (*status)(struct private_repl_protocol *);
+ void (*notify_update)(struct private_repl_protocol *);
+ void (*notify_agmt_changed)(struct private_repl_protocol *);
+ void (*notify_window_opened)(struct private_repl_protocol *);
+ void (*notify_window_closed)(struct private_repl_protocol *);
+ void (*update_now)(struct private_repl_protocol *);
+ PRLock *lock;
+ PRCondVar *cvar;
+ int stopped;
+ int terminate;
+ PRUint32 eventbits;
+ Repl_Connection *conn;
+ int last_acquire_response_code;
+ Repl_Agmt *agmt;
+ Object *replica_object;
+ void *private;
+ PRBool replica_acquired;
+} Private_Repl_Protocol;
+
+extern Private_Repl_Protocol *Repl_5_Inc_Protocol_new();
+extern Private_Repl_Protocol *Repl_5_Tot_Protocol_new();
+
+#define PROTOCOL_TERMINATION_NORMAL 301
+#define PROTOCOL_TERMINATION_ABNORMAL 302
+#define PROTOCOL_TERMINATION_NEEDS_TOTAL_UPDATE 303
+
+#define RESUME_DO_TOTAL_UPDATE 401
+#define RESUME_DO_INCREMENTAL_UPDATE 402
+#define RESUME_TERMINATE 403
+#define RESUME_SUSPEND 404
+
+/* Backoff timer settings for reconnect */
+#define PROTOCOL_BACKOFF_MINIMUM 3 /* 3 seconds */
+#define PROTOCOL_BACKOFF_MAXIMUM (60 * 5) /* 5 minutes */
+/* Backoff timer settings for replica busy reconnect */
+#define PROTOCOL_BUSY_BACKOFF_MINIMUM PROTOCOL_BACKOFF_MINIMUM
+#define PROTOCOL_BUSY_BACKOFF_MAXIMUM PROTOCOL_BUSY_BACKOFF_MINIMUM
+
+/* protocol related functions */
+void release_replica(Private_Repl_Protocol *prp);
+int acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv);
+BerElement *entry2bere(const Slapi_Entry *e);
+CSN *get_current_csn(Slapi_DN *replarea_sdn);
+char* protocol_response2string (int response);
+
+#endif /* _REPL5_PROT_PRIVATE_H_ */
diff --git a/ldap/servers/plugins/replication/repl5_protocol.c b/ldap/servers/plugins/replication/repl5_protocol.c
new file mode 100644
index 00000000..725bf3f2
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_protocol.c
@@ -0,0 +1,502 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_protocol.c */
+/*
+
+ The replication protocol object manages the replication protocol for
+ a given replica. It determines which protocol(s) are appropriate to
+ use when updating a given replica. It also knows how to arbitrate
+ incremental and total update protocols for a given replica.
+
+*/
+
+#include "repl5.h"
+#include "repl5_prot_private.h"
+
+#define PROTOCOL_5_INCREMENTAL 1
+#define PROTOCOL_5_TOTAL 2
+#define PROTOCOL_4_INCREMENTAL 3
+#define PROTOCOL_4_TOTAL 4
+
+typedef struct repl_protocol
+{
+ Private_Repl_Protocol *prp_incremental; /* inc protocol to use */
+ Private_Repl_Protocol *prp_total; /* total protocol to use */
+ Private_Repl_Protocol *prp_active_protocol; /* Pointer to active protocol */
+ Repl_Agmt *agmt; /* The replication agreement we're servicing */
+ Repl_Connection *conn; /* Connection to remote server */
+ Object *replica_object; /* Local replica. If non-NULL, replica object is acquired */
+ int state;
+ int next_state;
+ PRLock *lock;
+} repl_protocol;
+
+
+/* States */
+#define STATE_FINISHED 503
+#define STATE_BAD_STATE_SHOULD_NEVER_HAPPEN 599
+
+/* Forward declarations */
+static Private_Repl_Protocol *private_protocol_factory(Repl_Protocol *rp, int type);
+
+
+
+
+/*
+ * Create a new protocol instance.
+ */
+Repl_Protocol *
+prot_new(Repl_Agmt *agmt, int protocol_state)
+{
+ Slapi_DN *replarea_sdn = NULL;
+ Repl_Protocol *rp = (Repl_Protocol *)slapi_ch_malloc(sizeof(Repl_Protocol));
+
+ rp->prp_incremental = rp->prp_total = rp->prp_active_protocol = NULL;
+ if (protocol_state == STATE_PERFORMING_TOTAL_UPDATE)
+ {
+ rp->state = STATE_PERFORMING_TOTAL_UPDATE;
+ }
+ else
+ {
+ rp->state = STATE_PERFORMING_INCREMENTAL_UPDATE;
+ }
+ rp->next_state = STATE_PERFORMING_INCREMENTAL_UPDATE;
+ if ((rp->lock = PR_NewLock()) == NULL)
+ {
+ goto loser;
+ }
+ rp->agmt = agmt;
+ if ((rp->conn = conn_new(agmt)) == NULL)
+ {
+ goto loser;
+ }
+ /* Acquire the local replica object */
+ replarea_sdn = agmt_get_replarea(agmt);
+ rp->replica_object = replica_get_replica_from_dn(replarea_sdn);
+ if (NULL == rp->replica_object)
+ {
+ /* Whoa, no local replica!?!? */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to locate replica object for local replica %s\n",
+ agmt_get_long_name(agmt),
+ slapi_sdn_get_dn(replarea_sdn));
+ goto loser;
+ }
+ rp->prp_incremental = private_protocol_factory(rp, PROTOCOL_5_INCREMENTAL);
+ rp->prp_total = private_protocol_factory(rp, PROTOCOL_5_TOTAL);
+ /* XXXggood register callback handlers for entries updated, and
+ schedule window enter/leave. */
+ slapi_sdn_free(&replarea_sdn);
+
+ return rp;
+loser:
+ prot_delete(&rp);
+ return NULL;
+}
+
+
+
+
+
+Object *
+prot_get_replica_object(Repl_Protocol *rp)
+{
+ PR_ASSERT(NULL != rp);
+ return rp->replica_object;
+}
+
+
+
+
+
+Repl_Agmt *
+prot_get_agreement(Repl_Protocol *rp)
+{
+ /* MAB: rp might be NULL for disabled suffixes. Don't ASSERT on it */
+ if (NULL == rp) return NULL;
+ return rp->agmt;
+}
+
+
+
+
+void
+prot_free(Repl_Protocol **rpp)
+{
+ Repl_Protocol *rp = NULL;
+
+ if (rpp == NULL || *rpp == NULL) return;
+
+ rp = *rpp;
+
+ PR_Lock(rp->lock);
+ if (NULL != rp->prp_incremental)
+ {
+ rp->prp_incremental->delete(&rp->prp_incremental);
+ }
+ if (NULL != rp->prp_total)
+ {
+ rp->prp_total->delete(&rp->prp_total);
+ }
+ if (NULL != rp->replica_object)
+ {
+ object_release(rp->replica_object);
+ }
+ if (NULL != rp->conn)
+ {
+ conn_delete(rp->conn);
+ }
+ rp->prp_active_protocol = NULL;
+ PR_Unlock(rp->lock);
+ slapi_ch_free((void **)rpp);
+}
+
+/*
+ * Destroy a protocol instance XXXggood not complete
+ */
+void
+prot_delete(Repl_Protocol **rpp)
+{
+ Repl_Protocol *rp;
+
+ PR_ASSERT(NULL != rpp);
+ rp = *rpp;
+ /* MAB: rp might be NULL for disabled suffixes. Don't ASSERT on it */
+ if (NULL != rp)
+ {
+ prot_stop(rp);
+ prot_free(rpp);
+ }
+}
+
+
+
+
+
+/*
+ * Get the connection object.
+ */
+Repl_Connection *
+prot_get_connection(Repl_Protocol *rp)
+{
+ Repl_Connection *return_value;
+
+ PR_ASSERT(NULL != rp);
+ PR_Lock(rp->lock);
+ return_value = rp->conn;
+ PR_Unlock(rp->lock);
+ return return_value;
+}
+
+
+
+
+/*
+ * This function causes the total protocol to start.
+ * This is accomplished by registering a state transition
+ * to a new state, and then signaling the incremental
+ * protocol to stop.
+ */
+void
+prot_initialize_replica(Repl_Protocol *rp)
+{
+ PR_ASSERT(NULL != rp);
+
+ PR_Lock(rp->lock);
+ /* check that total protocol is not running */
+ rp->next_state = STATE_PERFORMING_TOTAL_UPDATE;
+ /* Stop the incremental protocol, if running */
+ rp->prp_incremental->stop(rp->prp_incremental);
+ if (rp->prp_total) agmt_set_last_init_status(rp->prp_total->agmt, 0, 0, NULL);
+ PR_Unlock(rp->lock);
+}
+
+
+
+
+
+/*
+ * Main thread for protocol manager.
+
+This is a simple state machine. State transition table:
+
+Initial state: incremental update
+
+STATE EVENT NEXT STATE
+----- ----- ----------
+incremental update shutdown finished
+incremental update total update requested total update
+total update shutdown finished
+total update update complete incremental update
+finished (any) finished
+
+*/
+
+static void
+prot_thread_main(void *arg)
+{
+ Repl_Protocol *rp = (Repl_Protocol *)arg;
+ int done;
+
+ PR_ASSERT(NULL != rp);
+
+ if (rp->agmt) {
+ set_thread_private_agmtname (agmt_get_long_name(rp->agmt));
+ }
+
+ done = 0;
+
+ while (!done)
+ {
+ switch (rp->state)
+ {
+ case STATE_PERFORMING_INCREMENTAL_UPDATE:
+ /* Run the incremental update protocol */
+ PR_Lock(rp->lock);
+ dev_debug("prot_thread_main(STATE_PERFORMING_INCREMENTAL_UPDATE): begin");
+ rp->prp_active_protocol = rp->prp_incremental;
+ PR_Unlock(rp->lock);
+ rp->prp_incremental->run(rp->prp_incremental);
+ dev_debug("prot_thread_main(STATE_PERFORMING_INCREMENTAL_UPDATE): end");
+ break;
+ case STATE_PERFORMING_TOTAL_UPDATE:
+ PR_Lock(rp->lock);
+
+ /* stop incremental protocol if running */
+ rp->prp_active_protocol = rp->prp_total;
+ /* After total protocol finished, return to incremental */
+ rp->next_state = STATE_PERFORMING_INCREMENTAL_UPDATE;
+ PR_Unlock(rp->lock);
+ /* Run the total update protocol */
+ dev_debug("prot_thread_main(STATE_PERFORMING_TOTAL_UPDATE): begin");
+ rp->prp_total->run(rp->prp_total);
+ dev_debug("prot_thread_main(STATE_PERFORMING_TOTAL_UPDATE): end");
+ /* update the agreement entry to notify clients that
+ replica initialization is completed. */
+ agmt_replica_init_done (rp->agmt);
+
+ break;
+ case STATE_FINISHED:
+ dev_debug("prot_thread_main(STATE_FINISHED): exiting prot_thread_main");
+ done = 1;
+ break;
+ }
+ rp->state = rp->next_state;
+ }
+}
+
+
+/*
+ * Start a thread to handle the replication protocol.
+ */
+void
+prot_start(Repl_Protocol *rp)
+{
+ PR_ASSERT(NULL != rp);
+ if (NULL != rp)
+ {
+ if (PR_CreateThread(PR_USER_THREAD, prot_thread_main, (void *)rp,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE) == NULL)
+ {
+ PRErrorCode prerr = PR_GetError();
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to create protocol thread; NSPR error - %d, %s\n",
+ agmt_get_long_name(rp->agmt),
+ prerr, slapd_pr_strerror(prerr));
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Unable to start "
+ "protocol object - NULL protocol object passed to prot_start.\n");
+ }
+}
+
+
+
+
+
+/*
+ * Stop a protocol instance.
+ */
+void
+prot_stop(Repl_Protocol *rp)
+{
+ PR_ASSERT(NULL != rp);
+ if (NULL != rp)
+ {
+ PR_Lock(rp->lock);
+ rp->next_state = STATE_FINISHED;
+ if (NULL != rp->prp_incremental)
+ {
+ if (rp->prp_incremental->stop(rp->prp_incremental) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Warning: incremental protocol for replica \"%s\" "
+ "did not shut down properly.\n",
+ agmt_get_long_name(rp->agmt));
+ }
+ }
+ if (NULL != rp->prp_total)
+ {
+ if (rp->prp_total->stop(rp->prp_total) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Warning: total protocol for replica \"%s\" "
+ "did not shut down properly.\n",
+ agmt_get_long_name(rp->agmt));
+ }
+ }
+ PR_Unlock(rp->lock);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Error: prot_stop() "
+ " called on NULL protocol instance.\n");
+ }
+}
+
+
+
+
+
+/*
+ * Call the notify_update method of the incremental or total update
+ * protocol, is either is active.
+ */
+void
+prot_notify_update(Repl_Protocol *rp)
+{
+ /* MAB: rp might be NULL for disabled suffixes. Don't ASSERT on it */
+ if (NULL == rp) return;
+
+ PR_Lock(rp->lock);
+ if (NULL != rp->prp_active_protocol)
+ {
+ rp->prp_active_protocol->notify_update(rp->prp_active_protocol);
+ }
+ PR_Unlock(rp->lock);
+}
+
+
+/*
+ * Call the notify_agmt_changed method of the incremental or total update
+ * protocol, is either is active.
+ */
+void
+prot_notify_agmt_changed(Repl_Protocol *rp, char * agmt_name)
+{
+ /* MAB: rp might be NULL for disabled suffixes. Don't ASSERT on it */
+ if (NULL == rp) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Replication agreement for %s could not be updated. "
+ "For replication to take place, please enable the suffix "
+ "and restart the server\n", agmt_name);
+ return;
+ }
+
+ PR_Lock(rp->lock);
+ if (NULL != rp->prp_active_protocol)
+ {
+ rp->prp_active_protocol->notify_agmt_changed(rp->prp_active_protocol);
+ }
+ PR_Unlock(rp->lock);
+}
+
+
+void
+prot_notify_window_opened (Repl_Protocol *rp)
+{
+ /* MAB: rp might be NULL for disabled suffixes. Don't ASSERT on it */
+ if (NULL == rp) return;
+
+ PR_Lock(rp->lock);
+ if (NULL != rp->prp_active_protocol)
+ {
+ rp->prp_active_protocol->notify_window_opened(rp->prp_active_protocol);
+ }
+ PR_Unlock(rp->lock);
+}
+
+
+void
+prot_notify_window_closed (Repl_Protocol *rp)
+{
+ /* MAB: rp might be NULL for disabled suffixes. Don't ASSERT on it */
+ if (NULL == rp) return;
+
+ PR_Lock(rp->lock);
+ if (NULL != rp->prp_active_protocol)
+ {
+ rp->prp_active_protocol->notify_window_closed(rp->prp_active_protocol);
+ }
+ PR_Unlock(rp->lock);
+}
+
+
+int
+prot_status(Repl_Protocol *rp)
+{
+ int return_status = PROTOCOL_STATUS_UNKNOWN;
+
+ /* MAB: rp might be NULL for disabled suffixes. Don't ASSERT on it */
+ if (NULL != rp)
+ {
+ PR_Lock(rp->lock);
+ if (NULL != rp->prp_active_protocol)
+ {
+ return_status = rp->prp_active_protocol->status(rp->prp_active_protocol);
+ }
+ PR_Unlock(rp->lock);
+ }
+ return return_status;
+}
+
+
+/*
+ * Start an incremental protocol session, even if we're not
+ * currently in a schedule window.
+ * If the total protocol is active, do nothing.
+ * Otherwise, notify the incremental protocol that it should
+ * run once.
+ */
+void
+prot_replicate_now(Repl_Protocol *rp)
+{
+ /* MAB: rp might be NULL for disabled suffixes. Don't ASSERT on it */
+
+ if (NULL != rp)
+ {
+ PR_Lock(rp->lock);
+ if (rp->prp_incremental == rp->prp_active_protocol)
+ {
+ rp->prp_active_protocol->update_now(rp->prp_active_protocol);
+ }
+ PR_Unlock(rp->lock);
+ }
+}
+
+/*
+ * A little factory function to create a protocol
+ * instance of the correct type.
+ */
+static Private_Repl_Protocol *
+private_protocol_factory(Repl_Protocol *rp, int type)
+{
+ Private_Repl_Protocol *prp;
+ switch (type)
+ {
+ case PROTOCOL_5_INCREMENTAL:
+ prp = Repl_5_Inc_Protocol_new(rp);
+ break;
+ case PROTOCOL_5_TOTAL:
+ prp = Repl_5_Tot_Protocol_new(rp);
+ break;
+ }
+ return prp;
+}
diff --git a/ldap/servers/plugins/replication/repl5_protocol_util.c b/ldap/servers/plugins/replication/repl5_protocol_util.c
new file mode 100644
index 00000000..16f65485
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_protocol_util.c
@@ -0,0 +1,468 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_protocol_util.c */
+/*
+
+Code common to both incremental and total protocols.
+
+*/
+
+#include "repl5.h"
+#include "repl5_prot_private.h"
+
+
+/*
+ * Obtain a current CSN (e.g. one that would have been
+ * generated for an operation occurring at this time)
+ * for a given replica.
+ */
+CSN *
+get_current_csn(Slapi_DN *replarea_sdn)
+{
+ Object *replica_obj;
+ Replica *replica;
+ Object *gen_obj;
+ CSNGen *gen;
+ CSN *current_csn = NULL;
+
+ if (NULL != replarea_sdn)
+ {
+ replica_obj = replica_get_replica_from_dn(replarea_sdn);
+ if (NULL != replica_obj)
+ {
+ replica = object_get_data(replica_obj);
+ if (NULL != replica)
+ {
+ gen_obj = replica_get_csngen(replica);
+ if (NULL != gen_obj)
+ {
+ gen = (CSNGen *)object_get_data(gen_obj);
+ if (NULL != gen)
+ {
+ if (csngen_new_csn(gen, &current_csn,
+ PR_FALSE /* notify */) != CSN_SUCCESS)
+ {
+ current_csn = NULL;
+
+ }
+ object_release(gen_obj);
+ }
+ }
+ }
+ }
+ }
+ return current_csn;
+}
+
+
+/*
+ * Acquire exclusive access to a replica. Send a start replication extended
+ * operation to the replica. The response will contain a success code, and
+ * optionally the replica's update vector if acquisition is successful.
+ * This function returns one of the following:
+ * ACQUIRE_SUCCESS - the replica was acquired, and we have exclusive update access
+ * ACQUIRE_REPLICA_BUSY - another master was updating the replica
+ * ACQUIRE_FATAL_ERROR - something bad happened, and it's not likely to improve
+ * if we wait.
+ * ACQUIRE_TRANSIENT_ERROR - something bad happened, but it's probably worth
+ * another try after waiting a while.
+ * If ACQUIRE_SUCCESS is returned, then ruv will point to the replica's update
+ * vector. It's possible that the replica does something goofy and doesn't
+ * return us an update vector, so be prepared for ruv to be NULL (but this is
+ * an error).
+ */
+int
+acquire_replica(Private_Repl_Protocol *prp, char *prot_oid, RUV **ruv)
+{
+ int return_value;
+ ConnResult crc;
+ Repl_Connection *conn;
+
+ PR_ASSERT(prp && prot_oid);
+
+ if (prp->replica_acquired) /* we already acquire replica */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Remote replica already acquired\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = ACQUIRE_FATAL_ERROR;
+ return ACQUIRE_SUCCESS;
+ }
+
+ if (NULL != ruv)
+ {
+ ruv_destroy ( ruv );
+ }
+
+ if (strcmp(prot_oid, REPL_NSDS50_INCREMENTAL_PROTOCOL_OID) == 0)
+ {
+ Replica *replica;
+ Object *supl_ruv_obj, *cons_ruv_obj;
+ PRBool is_newer = PR_FALSE;
+
+ object_acquire(prp->replica_object);
+ replica = object_get_data(prp->replica_object);
+ supl_ruv_obj = replica_get_ruv ( replica );
+ cons_ruv_obj = agmt_get_consumer_ruv ( prp->agmt );
+ is_newer = ruv_is_newer ( supl_ruv_obj, cons_ruv_obj );
+ if ( supl_ruv_obj ) object_release ( supl_ruv_obj );
+ if ( cons_ruv_obj ) object_release ( cons_ruv_obj );
+ object_release (prp->replica_object);
+ replica = NULL;
+
+ if (is_newer == PR_FALSE) {
+ prp->last_acquire_response_code = NSDS50_REPL_UPTODATE;
+ return ACQUIRE_CONSUMER_WAS_UPTODATE;
+ }
+ }
+
+ prp->last_acquire_response_code = NSDS50_REPL_REPLICA_NO_RESPONSE;
+
+ /* Get the connection */
+ conn = prp->conn;
+
+ crc = conn_connect(conn);
+ if (CONN_OPERATION_FAILED == crc)
+ {
+ return_value = ACQUIRE_TRANSIENT_ERROR;
+ }
+ else if (CONN_SSL_NOT_ENABLED == crc)
+ {
+ return_value = ACQUIRE_FATAL_ERROR;
+ }
+ else
+ {
+ /* we don't want the timer to go off in the middle of an operation */
+ conn_cancel_linger(conn);
+ /* Does the remote replica support the 5.0 protocol? */
+ crc = conn_replica_supports_ds5_repl(conn);
+ if (CONN_DOES_NOT_SUPPORT_DS5_REPL == crc)
+ {
+ return_value = ACQUIRE_FATAL_ERROR;
+ }
+ else if (CONN_NOT_CONNECTED == crc || CONN_OPERATION_FAILED == crc)
+ {
+ /* We don't know anything about the remote replica. Try again later. */
+ return_value = ACQUIRE_TRANSIENT_ERROR;
+ }
+ else
+ {
+ /* Good to go. Start the protocol. */
+ CSN *current_csn = NULL;
+ struct berval *retdata = NULL;
+ char *retoid = NULL;
+ Slapi_DN *replarea_sdn;
+
+ /* Obtain a current CSN */
+ replarea_sdn = agmt_get_replarea(prp->agmt);
+ current_csn = get_current_csn(replarea_sdn);
+ if (NULL != current_csn)
+ {
+ struct berval *payload = NSDS50StartReplicationRequest_new(
+ prot_oid, slapi_sdn_get_ndn(replarea_sdn),
+ NULL /* XXXggood need to provide referral(s) */, current_csn);
+ /* JCMREPL - Need to extract the referrals from the RUV */
+ csn_free(&current_csn);
+ current_csn = NULL;
+ crc = conn_send_extended_operation(conn,
+ REPL_START_NSDS50_REPLICATION_REQUEST_OID, payload, &retoid,
+ &retdata, NULL /* update control */, NULL /* returned controls */);
+ ber_bvfree(payload);
+ payload = NULL;
+ /* Look at the response we got. */
+ if (CONN_OPERATION_SUCCESS == crc)
+ {
+ /*
+ * Extop was processed. Look at extop response to see if we're
+ * permitted to go ahead.
+ */
+ struct berval **ruv_bervals = NULL;
+ int extop_result;
+ int extop_rc = decode_repl_ext_response(retdata, &extop_result,
+ &ruv_bervals);
+ if (0 == extop_rc)
+ {
+ prp->last_acquire_response_code = extop_result;
+ switch (extop_result)
+ {
+ /* XXXggood handle other error codes here */
+ case NSDS50_REPL_INTERNAL_ERROR:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to acquire replica: "
+ "an internal error occurred on the remote replica. "
+ "Replication is aborting.\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = ACQUIRE_FATAL_ERROR;
+ break;
+ case NSDS50_REPL_PERMISSION_DENIED:
+ /* Not allowed to send updates */
+ {
+ char *repl_binddn = agmt_get_binddn(prp->agmt);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to acquire replica: permission denied. "
+ "The bind dn \"%s\" does not have permission to "
+ "supply replication updates to the replica. "
+ "Will retry later.\n",
+ agmt_get_long_name(prp->agmt), repl_binddn);
+ slapi_ch_free((void **)&repl_binddn);
+ return_value = ACQUIRE_TRANSIENT_ERROR;
+ break;
+ }
+ case NSDS50_REPL_NO_SUCH_REPLICA:
+ /* There is no such replica on the consumer */
+ {
+ Slapi_DN *repl_root = agmt_get_replarea(prp->agmt);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to acquire replica: there is no "
+ "replicated area \"%s\" on the consumer server. "
+ "Replication is aborting.\n",
+ agmt_get_long_name(prp->agmt),
+ slapi_sdn_get_dn(repl_root));
+ slapi_sdn_free(&repl_root);
+ return_value = ACQUIRE_FATAL_ERROR;
+ break;
+ }
+ case NSDS50_REPL_EXCESSIVE_CLOCK_SKEW:
+ /* Large clock skew between the consumer and the supplier */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to acquire replica: "
+ "Excessive clock skew between the supplier and "
+ "the consumer. Replication is aborting.\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = ACQUIRE_FATAL_ERROR;
+ break;
+ case NSDS50_REPL_DECODING_ERROR:
+ /* We sent something the replica couldn't understand. */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to acquire replica: "
+ "the consumer was unable to decode the "
+ "startReplicationRequest extended operation sent by the "
+ "supplier. Replication is aborting.\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = ACQUIRE_FATAL_ERROR;
+ break;
+ case NSDS50_REPL_REPLICA_BUSY:
+ /* Someone else is updating the replica. Try later. */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Unable to acquire replica: "
+ "the replica is currently being updated"
+ "by another supplier. Will try later\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = ACQUIRE_REPLICA_BUSY;
+ break;
+ case NSDS50_REPL_LEGACY_CONSUMER:
+ /* remote replica is a legacy consumer */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to acquire replica: the replica "
+ "is supplied by a legacy supplier. "
+ "Replication is aborting.\n", agmt_get_long_name(prp->agmt));
+ return_value = ACQUIRE_FATAL_ERROR;
+ break;
+ case NSDS50_REPL_REPLICAID_ERROR:
+ /* remote replica detected a duplicate ReplicaID */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to aquire replica: the replica "
+ "has the same Replica ID as this one. "
+ "Replication is aborting.\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = ACQUIRE_FATAL_ERROR;
+ break;
+ case NSDS50_REPL_REPLICA_READY:
+ /* We've acquired the replica. */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Replica was successfully acquired.\n",
+ agmt_get_long_name(prp->agmt));
+ /* Parse the update vector */
+ if (NULL != ruv_bervals && NULL != ruv)
+ {
+ if (ruv_init_from_bervals(ruv_bervals, ruv) != RUV_SUCCESS)
+ {
+ /* Couldn't parse the update vector */
+ *ruv = NULL;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Warning: acquired replica, "
+ "but could not parse update vector. "
+ "The replica must be reinitialized.\n",
+ agmt_get_long_name(prp->agmt));
+ }
+ }
+
+ /* Save consumer's RUV in the replication agreement.
+ It is used by the changelog trimming code */
+ if (ruv && *ruv)
+ agmt_set_consumer_ruv (prp->agmt, *ruv);
+
+ return_value = ACQUIRE_SUCCESS;
+ break;
+ default:
+ return_value = ACQUIRE_FATAL_ERROR;
+ }
+ }
+ else
+ {
+ /* Couldn't parse the response */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to parse the response to the "
+ "startReplication extended operation. "
+ "Replication is aborting.\n",
+ agmt_get_long_name(prp->agmt));
+ prp->last_acquire_response_code = NSDS50_REPL_INTERNAL_ERROR;
+ return_value = ACQUIRE_FATAL_ERROR;
+ }
+ if (NULL != ruv_bervals)
+ ber_bvecfree(ruv_bervals);
+ }
+ else
+ {
+ int operation, error;
+ conn_get_error(conn, &operation, &error);
+
+ /* Couldn't send the extended operation */
+ return_value = ACQUIRE_TRANSIENT_ERROR; /* XXX right return value? */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to send a startReplication "
+ "extended operation to consumer (%s). Will retry later.\n",
+ agmt_get_long_name(prp->agmt),
+ error ? ldap_err2string(error) : "unknown error");
+ }
+ }
+ else
+ {
+ /* Couldn't get a current CSN */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to obtain current CSN. "
+ "Replication is aborting.\n",
+ agmt_get_long_name(prp->agmt));
+ return_value = ACQUIRE_FATAL_ERROR;
+ }
+ slapi_sdn_free(&replarea_sdn);
+ if (NULL != retoid)
+ ldap_memfree(retoid);
+ if (NULL != retdata)
+ ber_bvfree(retdata);
+ }
+ }
+
+ if (ACQUIRE_SUCCESS != return_value)
+ {
+ /* could not acquire the replica, so reinstate the linger timer, since this
+ means we won't call release_replica, which also reinstates the timer */
+ conn_start_linger(conn);
+ }
+ else
+ {
+ /* replica successfully acquired */
+ prp->replica_acquired = PR_TRUE;
+ }
+
+ return return_value;
+}
+
+
+/*
+ * Release a replica by sending an "end replication" extended request.
+ */
+void
+release_replica(Private_Repl_Protocol *prp)
+{
+ int rc;
+ struct berval *retdata = NULL;
+ char *retoid = NULL;
+ struct berval *payload = NULL;
+ Slapi_DN *replarea_sdn = NULL;
+
+ PR_ASSERT(NULL != prp);
+ PR_ASSERT(NULL != prp->conn);
+
+ if (!prp->replica_acquired)
+ return;
+
+ replarea_sdn = agmt_get_replarea(prp->agmt);
+ payload = NSDS50EndReplicationRequest_new((char *)slapi_sdn_get_dn(replarea_sdn)); /* XXXggood had to cast away const */
+ slapi_sdn_free(&replarea_sdn);
+ rc = conn_send_extended_operation(prp->conn,
+ REPL_END_NSDS50_REPLICATION_REQUEST_OID, payload, &retoid,
+ &retdata, NULL /* update control */, NULL /* returned controls */);
+ if (0 != rc)
+ {
+ int operation, error;
+ conn_get_error(prp->conn, &operation, &error);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Warning: unable to send endReplication extended operation (%s)\n",
+ agmt_get_long_name(prp->agmt),
+ error ? ldap_err2string(error) : "unknown error");
+ }
+ else
+ {
+ struct berval **ruv_bervals = NULL; /* Shouldn't actually be returned */
+ int extop_result;
+ int extop_rc = decode_repl_ext_response(retdata, &extop_result,
+ (struct berval ***)&ruv_bervals);
+ if (0 == extop_rc)
+ {
+ if (NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED == extop_result)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Successfully released consumer\n", agmt_get_long_name(prp->agmt));
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Unable to release consumer: response code %d\n",
+ agmt_get_long_name(prp->agmt), extop_result);
+ /* disconnect from the consumer so that it does not stay locked */
+ conn_disconnect (prp->conn);
+ }
+ }
+ else
+ {
+ /* Couldn't parse the response */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Warning: Unable to parse the response "
+ " to the endReplication extended operation.\n",
+ agmt_get_long_name(prp->agmt));
+ }
+ if (NULL != ruv_bervals)
+ ber_bvecfree(ruv_bervals);
+ /* XXXggood free ruv_bervals if we got them for some reason */
+ }
+ if (NULL != payload)
+ ber_bvfree(payload);
+ if (NULL != retoid)
+ ldap_memfree(retoid);
+ if (NULL != retdata)
+ ber_bvfree(retdata);
+
+ /* replica is released, start the linger timer on the connection, which
+ was stopped in acquire_replica */
+ conn_start_linger(prp->conn);
+
+ prp->replica_acquired = PR_FALSE;
+}
+
+/* converts consumer's response to a string */
+char *
+protocol_response2string (int response)
+{
+ switch (response)
+ {
+ case NSDS50_REPL_REPLICA_READY: return "replica acquired";
+ case NSDS50_REPL_REPLICA_BUSY: return "replica busy";
+ case NSDS50_REPL_EXCESSIVE_CLOCK_SKEW: return "excessive clock skew";
+ case NSDS50_REPL_PERMISSION_DENIED: return "permission denied";
+ case NSDS50_REPL_DECODING_ERROR: return "decoding error";
+ case NSDS50_REPL_UNKNOWN_UPDATE_PROTOCOL: return "unknown update protocol";
+ case NSDS50_REPL_NO_SUCH_REPLICA: return "no such replica";
+ case NSDS50_REPL_BELOW_PURGEPOINT: return "csn below purge point";
+ case NSDS50_REPL_INTERNAL_ERROR: return "internal error";
+ case NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED: return "replica released";
+ case NSDS50_REPL_LEGACY_CONSUMER: return "replica is a legacy consumer";
+ case NSDS50_REPL_REPLICAID_ERROR: return "duplicate replica ID detected";
+ case NSDS50_REPL_UPTODATE: return "no change to send";
+ default: return "unknown error";
+ }
+}
diff --git a/ldap/servers/plugins/replication/repl5_replica.c b/ldap/servers/plugins/replication/repl5_replica.c
new file mode 100644
index 00000000..5bc3e8ee
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_replica.c
@@ -0,0 +1,3387 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl5_replica.c */
+
+#include "slapi-plugin.h"
+#include "repl.h" /* ONREPL - this is bad */
+#include "repl5.h"
+#include "repl_shared.h"
+#include "csnpl.h"
+#include "cl5_api.h"
+
+/* from proto-slap.h */
+int g_get_shutdown();
+
+#define RUV_SAVE_INTERVAL (30 * 1000) /* 30 seconds */
+#define START_UPDATE_DELAY 2 /* 2 second */
+#define START_REAP_DELAY 3600 /* 1 hour */
+
+#define REPLICA_RDN "cn=replica"
+#define CHANGELOG_RDN "cn=legacy changelog"
+
+/*
+ * A replica is a locally-held copy of a portion of the DIT.
+ */
+struct replica {
+ Slapi_DN *repl_root; /* top of the replicated area */
+ char *repl_name; /* unique replica name */
+ PRBool new_name; /* new name was generated - need to be saved */
+ ReplicaUpdateDNList updatedn_list; /* list of dns with which a supplier should bind
+ to update this replica */
+ ReplicaType repl_type; /* is this replica read-only ? */
+ PRBool legacy_consumer; /* if true, this replica is supplied by 4.0 consumer */
+ char* legacy_purl; /* partial url of the legacy supplier */
+ ReplicaId repl_rid; /* replicaID */
+ Object *repl_ruv; /* replica update vector */
+ PRBool repl_ruv_dirty; /* Dirty flag for ruv */
+ CSNPL *min_csn_pl; /* Pending list for minimal CSN */
+ void *csn_pl_reg_id; /* registration assignment for csn callbacks */
+ unsigned long repl_state_flags; /* state flags */
+ PRUint32 repl_flags; /* persistent, externally visible flags */
+ PRLock *repl_lock; /* protects entire structure */
+ Slapi_Eq_Context repl_eqcxt_rs; /* context to cancel event that saves ruv */
+ Slapi_Eq_Context repl_eqcxt_tr; /* context to cancel event that reaps tombstones */
+ Object *repl_csngen; /* CSN generator for this replica */
+ PRBool repl_csn_assigned; /* Flag set when new csn is assigned. */
+ PRUint32 repl_purge_delay; /* When purgeable, CSNs are held on to for this many extra seconds */
+ PRBool tombstone_reap_stop; /* TRUE when the tombstone reaper should stop */
+ PRBool tombstone_reap_active; /* TRUE when the tombstone reaper is running */
+ long tombstone_reap_interval; /* Time in seconds between tombstone reaping */
+ Slapi_ValueSet *repl_referral; /* A list of administrator provided referral URLs */
+ PRBool state_update_inprogress; /* replica state is being updated */
+ PRLock *agmt_lock; /* protects agreement creation, start and stop */
+ char *locking_purl; /* supplier who has exclusive access */
+};
+
+
+typedef struct reap_callback_data
+{
+ int rc;
+ unsigned long num_entries;
+ unsigned long num_purged_entries;
+ CSN *purge_csn;
+ PRBool *tombstone_reap_stop;
+} reap_callback_data;
+
+
+/* Forward declarations of helper functions*/
+static Slapi_Entry* _replica_get_config_entry (const Slapi_DN *root);
+static int _replica_check_validity (const Replica *r);
+static int _replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext);
+static int _replica_update_entry (Replica *r, Slapi_Entry *e, char *errortext);
+static int _replica_configure_ruv (Replica *r, PRBool isLocked);
+static void _replica_update_state (time_t when, void *arg);
+static char * _replica_get_config_dn (const Slapi_DN *root);
+static char * _replica_type_as_string (const Replica *r);
+static int replica_create_ruv_tombstone(Replica *r);
+static void assign_csn_callback(const CSN *csn, void *data);
+static void abort_csn_callback(const CSN *csn, void *data);
+static void eq_cb_reap_tombstones(time_t when, void *arg);
+static CSN *_replica_get_purge_csn_nolock (const Replica *r);
+static void replica_get_referrals_nolock (const Replica *r, char ***referrals);
+static void replica_clear_legacy_referrals (const Slapi_DN *repl_root_sdn, char **referrals, const char *state);
+static void replica_remove_legacy_attr (const Slapi_DN *repl_root_sdn, const char *attr);
+static int replica_log_ruv_elements_nolock (const Replica *r);
+static void replica_replace_ruv_tombstone(Replica *r);
+static void start_agreements_for_replica (Replica *r, PRBool start);
+
+/* Allocates new replica and reads its state and state of its component from
+ * various parts of the DIT.
+ */
+Replica *
+replica_new(const Slapi_DN *root)
+{
+ Replica *r = NULL;
+ Slapi_Entry *e = NULL;
+ char errorbuf[BUFSIZ];
+ char ebuf[BUFSIZ];
+
+ PR_ASSERT (root);
+
+ /* check if there is a replica associated with the tree */
+ e = _replica_get_config_entry (root);
+ if (e)
+ {
+ errorbuf[0] = '\0';
+ r = replica_new_from_entry(e, errorbuf,
+ PR_FALSE /* not a newly added entry */);
+
+ if (NULL == r)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Unable to "
+ "configure replica %s: %s\n",
+ escape_string(slapi_sdn_get_dn(root), ebuf),
+ errorbuf);
+ }
+
+ slapi_entry_free (e);
+ }
+
+ return r;
+}
+
+/* constructs the replica object from the newly added entry */
+Replica *
+replica_new_from_entry (Slapi_Entry *e, char *errortext, PRBool is_add_operation)
+{
+ int rc = 0;
+ Replica *r;
+ RUV *ruv;
+ char *repl_name = NULL;
+
+ if (e == NULL)
+ {
+ if (NULL != errortext)
+ {
+ sprintf (errortext, "NULL entry");
+ }
+ return NULL;
+ }
+
+ r = (Replica *)slapi_ch_calloc(1, sizeof(Replica));
+
+ if ((r->repl_lock = PR_NewLock()) == NULL)
+ {
+ if (NULL != errortext)
+ {
+ sprintf (errortext, "failed to create replica lock");
+ }
+ rc = -1;
+ goto done;
+ }
+
+ if ((r->agmt_lock = PR_NewLock()) == NULL)
+ {
+ if (NULL != errortext)
+ {
+ sprintf (errortext, "failed to create replica lock");
+ }
+ rc = -1;
+ goto done;
+ }
+
+ /* read parameters from the replica config entry */
+ rc = _replica_init_from_config (r, e, errortext);
+ if (rc != 0)
+ {
+ goto done;
+ }
+
+ /* configure ruv */
+ rc = _replica_configure_ruv (r, PR_FALSE);
+ if (rc != 0)
+ {
+ goto done;
+ }
+
+ /* If smallest csn exists in RUV for our local replica, it's ok to begin iteration */
+ ruv = (RUV*) object_get_data (r->repl_ruv);
+ PR_ASSERT (ruv);
+
+ if (is_add_operation)
+ {
+ /*
+ * This is called by an ldap add operation.
+ * Update the entry to contain information generated
+ * during replica initialization
+ */
+ rc = _replica_update_entry (r, e, errortext);
+ }
+ else
+ {
+ /*
+ * Entry is already in dse.ldif - update it on the disk
+ * (done by the update state event scheduled below)
+ */
+ }
+ if (rc != 0)
+ goto done;
+
+ /* ONREPL - the state update can occur before the entry is added to the DIT.
+ In that case the updated would fail but nothing bad would happen. The next
+ scheduled update would save the state */
+ repl_name = slapi_ch_strdup (r->repl_name);
+ r->repl_eqcxt_rs = slapi_eq_repeat(_replica_update_state, repl_name,
+ current_time () + START_UPDATE_DELAY, RUV_SAVE_INTERVAL);
+
+ if (r->tombstone_reap_interval > 0)
+ {
+ /*
+ * Reap Tombstone should be started some time after the plugin started.
+ * This will allow the server to fully start before consuming resources.
+ */
+ repl_name = slapi_ch_strdup (r->repl_name);
+ r->repl_eqcxt_tr = slapi_eq_repeat(eq_cb_reap_tombstones, repl_name, current_time() + START_REAP_DELAY, 1000 * r->tombstone_reap_interval);
+ }
+
+ if (r->legacy_consumer)
+ {
+ char ebuf[BUFSIZ];
+
+ legacy_consumer_init_referrals (r);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_new_from_entry: "
+ "replica for %s was configured as legacy consumer\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ }
+
+done:
+ if (rc != 0 && r)
+ {
+ replica_destroy ((void**)&r);
+ }
+
+ return r;
+}
+
+
+void
+replica_flush(Replica *r)
+{
+ PR_ASSERT(NULL != r);
+ if (NULL != r)
+ {
+ PR_Lock(r->repl_lock);
+ /* Make sure we dump the CSNGen state */
+ r->repl_csn_assigned = PR_TRUE;
+ PR_Unlock(r->repl_lock);
+ /* This function take the Lock Inside */
+ /* And also write the RUV */
+ _replica_update_state((time_t)0, r->repl_name);
+ }
+}
+
+
+/*
+ * Deallocate a replica. arg should point to the address of a
+ * pointer that points to a replica structure.
+ */
+void
+replica_destroy(void **arg)
+{
+ Replica *r;
+ void *repl_name;
+
+ if (arg == NULL)
+ return;
+
+ r = *((Replica **)arg);
+
+ PR_ASSERT(r);
+
+ slapi_log_error (SLAPI_LOG_REPL, NULL, "replica_destroy\n");
+
+ /*
+ * The function will not be called unless the refcnt of its
+ * wrapper object is 0. Hopefully this refcnt could sync up
+ * this destruction and the events such as tombstone reap
+ * and ruv updates.
+ */
+
+ if (r->repl_eqcxt_rs)
+ {
+ repl_name = slapi_eq_get_arg (r->repl_eqcxt_rs);
+ slapi_ch_free (&repl_name);
+ slapi_eq_cancel(r->repl_eqcxt_rs);
+ r->repl_eqcxt_rs = NULL;
+ }
+
+ if (r->repl_eqcxt_tr)
+ {
+ repl_name = slapi_eq_get_arg (r->repl_eqcxt_tr);
+ slapi_ch_free (&repl_name);
+ slapi_eq_cancel(r->repl_eqcxt_tr);
+ r->repl_eqcxt_tr = NULL;
+ }
+
+ if (r->repl_root)
+ {
+ slapi_sdn_free(&r->repl_root);
+ }
+
+ slapi_ch_free_string(&r->locking_purl);
+
+ if (r->updatedn_list)
+ {
+ replica_updatedn_list_free(r->updatedn_list);
+ r->updatedn_list = NULL;
+ }
+
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void**)&r->repl_name);
+ slapi_ch_free ((void**)&r->legacy_purl);
+
+ if (r->repl_lock)
+ {
+ PR_DestroyLock(r->repl_lock);
+ r->repl_lock = NULL;
+ }
+
+ if (r->agmt_lock)
+ {
+ PR_DestroyLock(r->agmt_lock);
+ r->agmt_lock = NULL;
+ }
+
+ if(NULL != r->repl_ruv)
+ {
+ object_release(r->repl_ruv);
+ }
+
+ if(NULL != r->repl_csngen)
+ {
+ if (r->csn_pl_reg_id)
+ {
+ csngen_unregister_callbacks((CSNGen *)object_get_data (r->repl_csngen), r->csn_pl_reg_id);
+ }
+ object_release(r->repl_csngen);
+ }
+
+ if (NULL != r->repl_referral)
+ {
+ slapi_valueset_free(r->repl_referral);
+ }
+
+ if (NULL != r->min_csn_pl)
+ {
+ csnplFree(&r->min_csn_pl);;
+ }
+
+ slapi_ch_free((void **)arg);
+}
+
+/*
+ * Attempt to obtain exclusive access to replica (advisory only)
+ *
+ * Returns PR_TRUE if exclusive access was granted,
+ * PR_FALSE otherwise
+ * The parameter isInc tells whether or not the replica is being
+ * locked for an incremental update session - if the replica is
+ * successfully locked, this value is used - if the replica is already
+ * in use, this value will be set to TRUE or FALSE, depending on what
+ * type of update session has the replica in use currently
+ * locking_purl is the supplier who is attempting to acquire access
+ * current_purl is the supplier who already has access, if any
+ */
+PRBool
+replica_get_exclusive_access(Replica *r, PRBool *isInc, int connid, int opid,
+ const char *locking_purl,
+ char **current_purl)
+{
+ char ebuf[BUFSIZ];
+ PRBool rval = PR_TRUE;
+
+ PR_ASSERT(r);
+
+ PR_Lock(r->repl_lock);
+ if (r->repl_state_flags & REPLICA_IN_USE)
+ {
+ if (isInc)
+ *isInc = (r->repl_state_flags & REPLICA_INCREMENTAL_IN_PROGRESS);
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "conn=%d op=%d repl=\"%s\": "
+ "Replica in use locking_purl=%s\n",
+ connid, opid,
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf),
+ r->locking_purl ? r->locking_purl : "unknown");
+ rval = PR_FALSE;
+ if (current_purl)
+ {
+ *current_purl = slapi_ch_strdup(r->locking_purl);
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "conn=%d op=%d repl=\"%s\": Acquired replica\n",
+ connid, opid,
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ r->repl_state_flags |= REPLICA_IN_USE;
+ if (isInc && *isInc)
+ {
+ r->repl_state_flags |= REPLICA_INCREMENTAL_IN_PROGRESS;
+ }
+ else
+ {
+ /* if connid or opid != 0, it's a total update */
+ /* Both set to 0 means we're disabling replication */
+ if (connid || opid)
+ {
+ r->repl_state_flags |= REPLICA_TOTAL_IN_PROGRESS;
+ }
+ }
+ slapi_ch_free_string(&r->locking_purl);
+ r->locking_purl = slapi_ch_strdup(locking_purl);
+ }
+ PR_Unlock(r->repl_lock);
+ return rval;
+}
+
+/*
+ * Relinquish exclusive access to the replica
+ */
+void
+replica_relinquish_exclusive_access(Replica *r, int connid, int opid)
+{
+ char ebuf[BUFSIZ];
+ PRBool isInc;
+
+ PR_ASSERT(r);
+
+ PR_Lock(r->repl_lock);
+ isInc = (r->repl_state_flags & REPLICA_INCREMENTAL_IN_PROGRESS);
+ /* check to see if the replica is in use and log a warning if not */
+ if (!(r->repl_state_flags & REPLICA_IN_USE))
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "conn=%d op=%d repl=\"%s\": "
+ "Replica not in use\n",
+ connid, opid,
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ } else {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "conn=%d op=%d repl=\"%s\": "
+ "Released replica\n",
+ connid, opid,
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ slapi_ch_free_string(&r->locking_purl);
+ r->repl_state_flags &= ~(REPLICA_IN_USE);
+ if (isInc)
+ r->repl_state_flags &= ~(REPLICA_INCREMENTAL_IN_PROGRESS);
+ else
+ r->repl_state_flags &= ~(REPLICA_TOTAL_IN_PROGRESS);
+ }
+ PR_Unlock(r->repl_lock);
+}
+
+/*
+ * Returns root of the replicated area
+ */
+PRBool
+replica_get_tombstone_reap_active(const Replica *r)
+{
+ PR_ASSERT(r);
+
+ return(r->tombstone_reap_active);
+}
+
+/*
+ * Returns root of the replicated area
+ */
+const Slapi_DN *
+replica_get_root(const Replica *r) /* ONREPL - should we return copy instead? */
+{
+ PR_ASSERT(r);
+
+ /* replica root never changes so we don't have to lock */
+ return(r->repl_root);
+}
+
+/*
+ * Returns normalized dn of the root of the replicated area
+ */
+const char *
+replica_get_name(const Replica *r) /* ONREPL - should we return copy instead? */
+{
+ PR_ASSERT(r);
+
+ /* replica name never changes so we don't have to lock */
+ return(r->repl_name);
+}
+
+/*
+ * Returns replicaid of this replica
+ */
+ReplicaId
+replica_get_rid (const Replica *r)
+{
+ ReplicaId rid;
+ PR_ASSERT(r);
+
+ PR_Lock(r->repl_lock);
+ rid = r->repl_rid;
+ PR_Unlock(r->repl_lock);
+ return rid;
+}
+
+/*
+ * Sets replicaid of this replica - should only be used when also changing the type
+ */
+void
+replica_set_rid (Replica *r, ReplicaId rid)
+{
+ PR_ASSERT(r);
+
+ PR_Lock(r->repl_lock);
+ r->repl_rid = rid;
+ PR_Unlock(r->repl_lock);
+}
+
+/* Returns true if replica was initialized through ORC or import;
+ * otherwise, false. An uninitialized replica should return
+ * LDAP_UNWILLING_TO_PERFORM to all client requests
+ */
+PRBool
+replica_is_initialized (const Replica *r)
+{
+ PR_ASSERT(r);
+ return (r->repl_ruv != NULL);
+}
+
+/*
+ * Returns refcounted object that contains RUV. The caller should release the
+ * object once it is no longer used. To release, call object_release
+ */
+Object *
+replica_get_ruv (const Replica *r)
+{
+ Object *ruv = NULL;
+
+ PR_ASSERT(r);
+
+ PR_Lock(r->repl_lock);
+
+ PR_ASSERT (r->repl_ruv);
+
+ object_acquire (r->repl_ruv);
+
+ ruv = r->repl_ruv;
+
+ PR_Unlock(r->repl_lock);
+
+ return ruv;
+}
+
+/*
+ * Sets RUV vector. This function should be called during replica
+ * (re)initialization. During normal operation, the RUV is read from
+ * the root of the replicated in the replica_new call
+ */
+void
+replica_set_ruv (Replica *r, RUV *ruv)
+{
+ PR_ASSERT(r && ruv);
+
+ PR_Lock(r->repl_lock);
+
+ if(NULL != r->repl_ruv)
+ {
+ object_release(r->repl_ruv);
+ }
+
+ /* if the local replica is not in the RUV and it is writable - add it
+ and reinitialize min_csn pending list */
+ if (r->repl_type == REPLICA_TYPE_UPDATABLE)
+ {
+ CSN *csn = NULL;
+ if (r->min_csn_pl)
+ csnplFree (&r->min_csn_pl);
+
+ if (ruv_contains_replica (ruv, r->repl_rid))
+ {
+ ruv_get_smallest_csn_for_replica(ruv, r->repl_rid, &csn);
+ if (csn)
+ csn_free (&csn);
+ else
+ r->min_csn_pl = csnplNew ();
+ /* We need to make sure the local ruv element is the 1st. */
+ ruv_move_local_supplier_to_first(ruv, r->repl_rid);
+ }
+ else
+ {
+ r->min_csn_pl = csnplNew ();
+ /* To be sure that the local is in first */
+ ruv_add_index_replica(ruv, r->repl_rid, multimaster_get_local_purl(), 1);
+ }
+ }
+
+ r->repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy);
+ r->repl_ruv_dirty = PR_TRUE;
+
+ PR_Unlock(r->repl_lock);
+}
+
+/*
+ * Update one particular CSN in an RUV. This is meant to be called
+ * whenever (a) the server has processed a client operation and
+ * needs to update its CSN, or (b) the server is completing an
+ * inbound replication session operation, and needs to update its
+ * local RUV.
+ */
+void
+replica_update_ruv(Replica *r, const CSN *updated_csn, const char *replica_purl)
+{
+ char csn_str[CSN_STRSIZE];
+ char ebuf[BUFSIZ];
+
+ PR_ASSERT(NULL != r);
+ PR_ASSERT(NULL != updated_csn);
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "replica_update_ruv: csn %s\n",
+ csn_as_string(updated_csn, PR_FALSE, csn_str)); /* XXXggood remove debugging */
+#endif
+ if (NULL == r)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_ruv: replica "
+ "is NULL\n");
+ }
+ else if (NULL == updated_csn)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_ruv: csn "
+ "is NULL when updating replica %s\n", escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ }
+ else
+ {
+ RUV *ruv;
+ PR_Lock(r->repl_lock);
+
+ if (r->repl_ruv != NULL)
+ {
+ ruv = object_get_data(r->repl_ruv);
+ if (NULL != ruv)
+ {
+ ReplicaId rid = csn_get_replicaid(updated_csn);
+ if (rid == r->repl_rid)
+ {
+ if (NULL != r->min_csn_pl)
+ {
+ CSN *min_csn;
+ PRBool committed;
+ (void)csnplCommit(r->min_csn_pl, updated_csn);
+ min_csn = csnplGetMinCSN(r->min_csn_pl, &committed);
+ if (NULL != min_csn)
+ {
+ if (committed)
+ {
+ ruv_set_min_csn(ruv, min_csn, replica_purl);
+ csnplFree(&r->min_csn_pl);
+ }
+ csn_free(&min_csn);
+ }
+ }
+ }
+ /* Update max csn for local and remote replicas */
+ if (ruv_update_ruv (ruv, updated_csn, replica_purl, rid == r->repl_rid)
+ != RUV_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL,
+ repl_plugin_name, "replica_update_ruv: unable "
+ "to update RUV for replica %s, csn = %s\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf),
+ csn_as_string(updated_csn, PR_FALSE, csn_str));
+ }
+
+ r->repl_ruv_dirty = PR_TRUE;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "replica_update_ruv: unable to get RUV object for replica "
+ "%s\n", escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_update_ruv: "
+ "unable to initialize RUV for replica %s\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ }
+ PR_Unlock(r->repl_lock);
+ }
+}
+
+/*
+ * Returns refcounted object that contains csn generator. The caller should release the
+ * object once it is no longer used. To release, call object_release
+ */
+Object *
+replica_get_csngen (const Replica *r)
+{
+ Object *csngen;
+
+ PR_ASSERT(r);
+
+ PR_Lock(r->repl_lock);
+
+ object_acquire (r->repl_csngen);
+ csngen = r->repl_csngen;
+
+ PR_Unlock(r->repl_lock);
+
+ return csngen;
+}
+
+/*
+ * Returns the replica type.
+ */
+ReplicaType
+replica_get_type (const Replica *r)
+{
+ PR_ASSERT(r);
+ return r->repl_type;
+}
+
+/*
+ * Sets the replica type.
+ */
+void
+replica_set_type (Replica *r, ReplicaType type)
+{
+ PR_ASSERT(r);
+
+ PR_Lock(r->repl_lock);
+ r->repl_type = type;
+ PR_Unlock(r->repl_lock);
+}
+
+/*
+ * Returns PR_TRUE if this replica is a consumer of 4.0 server
+ * and PR_FALSE otherwise
+ */
+PRBool
+replica_is_legacy_consumer (const Replica *r)
+{
+ PR_ASSERT(r);
+ return r->legacy_consumer;
+}
+
+/*
+ * Sets the replica type.
+ */
+void
+replica_set_legacy_consumer (Replica *r, PRBool legacy_consumer)
+{
+ int legacy2mmr;
+ Slapi_DN *repl_root_sdn = NULL;
+ char **referrals = NULL;
+ char *replstate = NULL;
+ PR_ASSERT(r);
+
+ PR_Lock(r->repl_lock);
+
+ legacy2mmr = r->legacy_consumer && !legacy_consumer;
+
+ /* making the server a regular 5.0 replica */
+ if (legacy2mmr)
+ {
+ slapi_ch_free ((void**)&r->legacy_purl);
+ /* Remove copiedFrom/copyingFrom attributes from the root entry */
+ /* set the right state in the mapping tree */
+ if (r->repl_type == REPLICA_TYPE_READONLY)
+ {
+ replica_get_referrals_nolock (r, &referrals);
+ replstate = STATE_UPDATE_REFERRAL;
+ }
+ else /* updateable */
+ {
+ replstate = STATE_BACKEND;
+ }
+ }
+
+ r->legacy_consumer = legacy_consumer;
+ repl_root_sdn = slapi_sdn_dup(r->repl_root);
+ PR_Unlock(r->repl_lock);
+
+ if (legacy2mmr)
+ {
+ replica_clear_legacy_referrals(repl_root_sdn, referrals, replstate);
+ /* Also change state of the mapping tree node and/or referrals */
+ replica_remove_legacy_attr (repl_root_sdn, type_copiedFrom);
+ replica_remove_legacy_attr (repl_root_sdn, type_copyingFrom);
+ }
+ charray_free(referrals);
+ slapi_sdn_free(&repl_root_sdn);
+}
+
+/* Gets partial url of the legacy supplier - applicable for legacy consumer only */
+char *
+replica_get_legacy_purl (const Replica *r)
+{
+ char *purl;
+
+ PR_Lock (r->repl_lock);
+
+ PR_ASSERT (r->legacy_consumer);
+
+ purl = slapi_ch_strdup (r->legacy_purl);
+
+ PR_Unlock (r->repl_lock);
+
+ return purl;
+}
+
+void
+replica_set_legacy_purl (Replica *r, const char *purl)
+{
+ PR_Lock (r->repl_lock);
+
+ PR_ASSERT (r->legacy_consumer);
+
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void**)&r->legacy_purl);
+
+ r->legacy_purl = slapi_ch_strdup (purl);
+
+ PR_Unlock (r->repl_lock);
+}
+
+/*
+ * Returns true if sdn is the same as updatedn and false otherwise
+ */
+PRBool
+replica_is_updatedn (const Replica *r, const Slapi_DN *sdn)
+{
+ PRBool result;
+
+ PR_ASSERT (r);
+
+ PR_Lock(r->repl_lock);
+
+ if (sdn == NULL)
+ {
+ result = (r->updatedn_list == NULL);
+ }
+ else if (r->updatedn_list == NULL)
+ {
+ result = PR_FALSE;
+ }
+ else
+ {
+ result = replica_updatedn_list_ismember(r->updatedn_list, sdn);
+ }
+
+ PR_Unlock(r->repl_lock);
+
+ return result;
+}
+
+/*
+ * Sets updatedn list for this replica
+ */
+void
+replica_set_updatedn (Replica *r, const Slapi_ValueSet *vs, int mod_op)
+{
+ PR_ASSERT (r);
+
+ PR_Lock(r->repl_lock);
+
+ if (!r->updatedn_list)
+ r->updatedn_list = replica_updatedn_list_new(NULL);
+
+ if (mod_op & LDAP_MOD_DELETE || vs == NULL ||
+ (0 == slapi_valueset_count(vs))) /* null value also causes list deletion */
+ replica_updatedn_list_delete(r->updatedn_list, vs);
+ else if (mod_op & LDAP_MOD_REPLACE)
+ replica_updatedn_list_replace(r->updatedn_list, vs);
+ else if (mod_op & LDAP_MOD_ADD)
+ replica_updatedn_list_add(r->updatedn_list, vs);
+
+ PR_Unlock(r->repl_lock);
+}
+
+/* gets current replica generation for this replica */
+char *replica_get_generation (const Replica *r)
+{
+ int rc = 0;
+ char *gen = NULL;
+
+ if (r)
+ {
+ PR_Lock(r->repl_lock);
+
+ PR_ASSERT (r->repl_ruv);
+
+ if (rc == 0)
+ gen = ruv_get_replica_generation ((RUV*)object_get_data (r->repl_ruv));
+
+ PR_Unlock(r->repl_lock);
+ }
+
+ return gen;
+}
+
+PRBool replica_is_flag_set (const Replica *r, PRUint32 flag)
+{
+ if (r)
+ return (r->repl_flags & flag);
+ else
+ return PR_FALSE;
+}
+
+void replica_set_flag (Replica *r, PRUint32 flag, PRBool clear)
+{
+ if (r == NULL)
+ return;
+
+ PR_Lock(r->repl_lock);
+
+ if (clear)
+ {
+ r->repl_flags &= ~flag;
+ }
+ else
+ {
+ r->repl_flags |= flag;
+ }
+
+ PR_Unlock(r->repl_lock);
+}
+
+void replica_replace_flags (Replica *r, PRUint32 flags)
+{
+ if (r)
+ {
+ PR_Lock(r->repl_lock);
+ r->repl_flags = flags;
+ PR_Unlock(r->repl_lock);
+ }
+}
+
+void
+replica_get_referrals(const Replica *r, char ***referrals)
+{
+ PR_Lock(r->repl_lock);
+ replica_get_referrals_nolock (r, referrals);
+ PR_Unlock(r->repl_lock);
+}
+
+void
+replica_set_referrals(Replica *r,const Slapi_ValueSet *vs)
+{
+ int ii = 0;
+ Slapi_Value *vv = NULL;
+ if (r->repl_referral == NULL)
+ {
+ r->repl_referral = slapi_valueset_new();
+ }
+ else
+ {
+ slapi_valueset_done(r->repl_referral);
+ }
+ slapi_valueset_set_valueset(r->repl_referral, vs);
+ /* make sure the DN is included in the referral LDAP URL */
+ if (r->repl_referral)
+ {
+ Slapi_ValueSet *newvs = slapi_valueset_new();
+ const char *repl_root = slapi_sdn_get_dn(r->repl_root);
+ int rootlen = strlen(repl_root);
+ ii = slapi_valueset_first_value(r->repl_referral, &vv);
+ while (vv)
+ {
+ const char *ref = slapi_value_get_string(vv);
+ struct ldap_url_desc *lud = NULL;
+ int myrc = ldap_url_parse(ref, &lud);
+ /* see if the dn is already in the referral URL */
+ if (myrc == LDAP_URL_ERR_NODN || !lud || !lud->lud_dn) {
+ /* add the dn */
+ Slapi_Value *newval = NULL;
+ int len = strlen(ref);
+ char *tmpref = NULL;
+ int need_slash = 0;
+ if (ref[len-1] != '/') {
+ len++; /* add another one for the slash */
+ need_slash = 1;
+ }
+ len += rootlen + 2;
+ tmpref = slapi_ch_malloc(len);
+ sprintf(tmpref, "%s%s%s", ref, (need_slash ? "/" : ""),
+ repl_root);
+ newval = slapi_value_new_string(tmpref);
+ slapi_ch_free_string(&tmpref); /* sv_new_string makes a copy */
+ slapi_valueset_add_value(newvs, newval);
+ slapi_value_free(&newval); /* s_vs_add_value makes a copy */
+ }
+ if (lud)
+ ldap_free_urldesc(lud);
+ ii = slapi_valueset_next_value(r->repl_referral, ii, &vv);
+ }
+ if (slapi_valueset_count(newvs) > 0) {
+ slapi_valueset_done(r->repl_referral);
+ slapi_valueset_set_valueset(r->repl_referral, newvs);
+ }
+ slapi_valueset_free(newvs); /* s_vs_set_vs makes a copy */
+ }
+}
+
+int
+replica_update_csngen_state (Replica *r, const RUV *ruv)
+{
+ int rc = 0;
+ CSNGen *gen;
+ CSN *csn = NULL;
+
+ PR_ASSERT (r && ruv);
+
+ rc = ruv_get_max_csn(ruv, &csn);
+ if (rc != RUV_SUCCESS)
+ {
+ return -1;
+ }
+
+ if (csn == NULL) /* ruv contains no csn - we are done */
+ {
+ return 0;
+ }
+
+ PR_Lock(r->repl_lock);
+
+ gen = (CSNGen *)object_get_data (r->repl_csngen);
+ PR_ASSERT (gen);
+
+ rc = csngen_adjust_time (gen, csn);
+ if (rc != CSN_SUCCESS)
+ {
+ rc = -1;
+ goto done;
+ }
+
+ rc = 0;
+
+done:
+
+ PR_Unlock(r->repl_lock);
+ if (csn)
+ csn_free (&csn);
+
+ return rc;
+}
+
+/*
+ * dumps replica state for debugging purpose
+ */
+void
+replica_dump(Replica *r)
+{
+ char *updatedn_list = NULL;
+ PR_ASSERT (r);
+
+ PR_Lock(r->repl_lock);
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "Replica state:\n");
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\treplica root: %s\n",
+ slapi_sdn_get_ndn (r->repl_root));
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\treplica type: %s\n",
+ _replica_type_as_string (r));
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\treplica id: %d\n", r->repl_rid);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\tflags: %d\n", r->repl_flags);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\tstate flags: %d\n", r->repl_state_flags);
+ if (r->updatedn_list)
+ updatedn_list = replica_updatedn_list_to_string(r->updatedn_list, "\n\t\t");
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\tupdate dn: %s\n",
+ updatedn_list? updatedn_list : "not configured");
+ slapi_ch_free_string(&updatedn_list);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\truv: %s configured and is %sdirty\n",
+ r->repl_ruv ? "" : "not", r->repl_ruv_dirty ? "" : "not ");
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "\tCSN generator: %s configured\n",
+ r->repl_csngen ? "" : "not");
+ /* JCMREPL - Dump Referrals */
+
+ PR_Unlock(r->repl_lock);
+}
+
+
+/*
+ * Return the CSN of the purge point. Any CSNs smaller than the
+ * purge point can be safely removed from entries within this
+ * this replica. Returns an allocated CSN that must be freed by
+ * the caller, or NULL if purging is disabled.
+ */
+
+CSN *
+replica_get_purge_csn(const Replica *r)
+{
+ CSN *csn;
+
+ PR_Lock(r->repl_lock);
+
+ csn= _replica_get_purge_csn_nolock(r);
+
+ PR_Unlock(r->repl_lock);
+
+ return csn;
+}
+
+
+/*
+ * This function logs a dummy entry for the smallest csn in the RUV.
+ * This is necessary because, to get the next change, we need to position
+ * changelog on the previous change. So this function insures that we always have one.
+ */
+
+/* ONREPL we will need to change this function to log all the
+ * ruv elements not just the smallest when changelog iteration
+ * algoritm changes to iterate replica by replica
+*/
+int
+replica_log_ruv_elements (const Replica *r)
+{
+ int rc = 0;
+
+ PR_ASSERT (r);
+
+ PR_Lock(r->repl_lock);
+
+ rc = replica_log_ruv_elements_nolock (r);
+
+ PR_Unlock(r->repl_lock);
+
+ return rc;
+}
+
+void
+consumer5_set_mapping_tree_state_for_replica(const Replica *r, RUV *supplierRuv)
+{
+ const Slapi_DN *repl_root_sdn= replica_get_root(r);
+ char **ruv_referrals= NULL;
+ char **replica_referrals= NULL;
+ RUV *ruv;
+ int state_backend = -1;
+ const char *mtn_state = NULL;
+
+ PR_Lock (r->repl_lock);
+
+ if ( supplierRuv == NULL )
+ {
+ ruv = (RUV*)object_get_data (r->repl_ruv);
+ PR_ASSERT (ruv);
+
+ ruv_referrals= ruv_get_referrals(ruv); /* ruv_referrals has to be free'd */
+ }
+ else
+ {
+ ruv_referrals = ruv_get_referrals(supplierRuv);
+ }
+
+ replica_get_referrals_nolock (r, &replica_referrals); /* replica_referrals has to be free'd */
+
+ /* JCMREPL - What if there's a Total update in progress? */
+ if( (r->repl_type==REPLICA_TYPE_READONLY) || (r->legacy_consumer) )
+ {
+ state_backend = 0;
+ }
+ else if (r->repl_type==REPLICA_TYPE_UPDATABLE)
+ {
+ state_backend = 1;
+ }
+ /* Unlock to avoid changing MTN state under repl lock */
+ PR_Unlock (r->repl_lock);
+
+ if(state_backend == 0 )
+ {
+ /* Read-Only - The mapping tree should be refering all update operations. */
+ mtn_state = STATE_UPDATE_REFERRAL;
+ }
+ else if (state_backend == 1)
+ {
+ /* Updatable - The mapping tree should be accepting all update operations. */
+ mtn_state = STATE_BACKEND;
+ }
+
+ /* JCMREPL - Check the return code. */
+ repl_set_mtn_state_and_referrals(repl_root_sdn, mtn_state, NULL,
+ ruv_referrals, replica_referrals);
+ charray_free(ruv_referrals);
+ charray_free(replica_referrals);
+}
+
+void
+replica_set_enabled (Replica *r, PRBool enable)
+{
+ char *repl_name = NULL;
+
+ PR_ASSERT (r);
+
+ PR_Lock (r->repl_lock);
+
+ if (enable)
+ {
+ if (r->repl_eqcxt_rs == NULL) /* event is not already registered */
+ {
+ repl_name = slapi_ch_strdup (r->repl_name);
+ r->repl_eqcxt_rs = slapi_eq_repeat(_replica_update_state, repl_name,
+ current_time() + START_UPDATE_DELAY, RUV_SAVE_INTERVAL);
+ }
+ }
+ else /* disable */
+ {
+ if (r->repl_eqcxt_rs) /* event is still registerd */
+ {
+ repl_name = slapi_eq_get_arg (r->repl_eqcxt_rs);
+ slapi_ch_free ((void**)&repl_name);
+ slapi_eq_cancel(r->repl_eqcxt_rs);
+ r->repl_eqcxt_rs = NULL;
+ }
+ }
+
+ PR_Unlock (r->repl_lock);
+}
+
+/* This function is generally called when replica's data store
+ is reloaded. It retrieves new RUV from the datastore. If new
+ RUV does not exist or if it is not as up to date as the purge RUV
+ of the corresponding changelog file, we need to remove */
+
+/* the function minimizes the use of replica lock where ever possible.
+ Locking replica lock while calling changelog functions
+ causes a deadlock because changelog calls replica functions that
+ that lock the same lock */
+
+int
+replica_reload_ruv (Replica *r)
+{
+ int rc = 0;
+ Object *old_ruv_obj = NULL, *new_ruv_obj = NULL;
+ RUV *upper_bound_ruv = NULL;
+ RUV *new_ruv = NULL;
+ Object *r_obj;
+
+ PR_ASSERT (r);
+
+ PR_Lock (r->repl_lock);
+
+ old_ruv_obj = r->repl_ruv;
+
+ r->repl_ruv = NULL;
+
+ rc = _replica_configure_ruv (r, PR_TRUE);
+
+ PR_Unlock (r->repl_lock);
+
+ if (rc != 0)
+ {
+ return rc;
+ }
+
+ /* check if there is a changelog and whether this replica logs changes */
+ if (cl5GetState () == CL5_STATE_OPEN && r->repl_flags & REPLICA_LOG_CHANGES)
+ {
+
+ /* Compare new ruv to the changelog's upper bound ruv. We could only keep
+ the existing changelog if its upper bound is the same as replica's RUV.
+ This is because if changelog has changes not in RUV, they will be
+ eventually sent to the consumer's which will cause a state mismatch
+ (because the supplier does not actually contain the changes in its data store.
+ If, on the other hand, the changelog is not as up to date as the supplier,
+ it is not really useful since out of sync consumer's can't be brought
+ up to date using this changelog and hence will need to be reinitialized */
+
+ /* replace ruv to make sure we work with the correct changelog file */
+ PR_Lock (r->repl_lock);
+
+ new_ruv_obj = r->repl_ruv;
+ r->repl_ruv = old_ruv_obj;
+
+ PR_Unlock (r->repl_lock);
+
+ rc = cl5GetUpperBoundRUV (r, &upper_bound_ruv);
+ if (rc != CL5_SUCCESS && rc != CL5_NOTFOUND)
+ {
+ return -1;
+ }
+
+ if (upper_bound_ruv)
+ {
+ new_ruv = object_get_data (new_ruv_obj);
+ PR_ASSERT (new_ruv);
+
+ /* ONREPL - there are more efficient ways to establish RUV equality.
+ However, because this is not in the critical path and we at most
+ have 2 elements in the RUV, this will not effect performance */
+
+ if (!ruv_covers_ruv (new_ruv, upper_bound_ruv) ||
+ !ruv_covers_ruv (upper_bound_ruv, new_ruv))
+ {
+ char ebuf[BUFSIZ];
+
+ /* create a temporary replica object to conform to the interface */
+ r_obj = object_new (r, NULL);
+
+ /* We can't use existing changelog - remove existing file */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_reload_ruv: "
+ "Warning: new data for replica %s does not match the data in the changelog.\n"
+ " Recreating the changelog file. This could affect replication with replica's "
+ " consumers in which case the consumers should be reinitialized.\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ rc = cl5DeleteDBSync (r_obj);
+
+ /* reinstate new ruv */
+ PR_Lock (r->repl_lock);
+
+ r->repl_ruv = new_ruv_obj;
+
+ object_release (r_obj);
+
+ if (rc == CL5_SUCCESS)
+ {
+ /* log changes to mark starting point for replication */
+ rc = replica_log_ruv_elements_nolock (r);
+ }
+
+ PR_Unlock (r->repl_lock);
+ }
+ else
+ {
+ /* we just need to reinstate new ruv */
+ PR_Lock (r->repl_lock);
+
+ r->repl_ruv = new_ruv_obj;
+
+ PR_Unlock (r->repl_lock);
+ }
+ }
+ else /* upper bound vector is not there - we have no changes logged */
+ {
+ /* reinstate new ruv */
+ PR_Lock (r->repl_lock);
+
+ r->repl_ruv = new_ruv_obj;
+
+ /* just log elements of the current RUV. This is to have
+ a starting point for iteration through the changes */
+ rc = replica_log_ruv_elements_nolock (r);
+
+ PR_Unlock (r->repl_lock);
+ }
+ }
+
+ if (rc == 0)
+ {
+ consumer5_set_mapping_tree_state_for_replica(r, NULL);
+ /* reset mapping tree referrals based on new local RUV */
+ }
+
+ if (old_ruv_obj)
+ object_release (old_ruv_obj);
+
+ if (upper_bound_ruv)
+ ruv_destroy (&upper_bound_ruv);
+
+ return rc;
+}
+
+/* this function is called during server startup for each replica
+ to check whether the replica's data was reloaded offline and
+ whether replica's changelog needs to be reinitialized */
+
+/* the function does not use replica lock but all functions it calls are
+ thread safe. Locking replica lock while calling changelog functions
+ causes a deadlock because changelog calls replica functions that
+ that lock the same lock */
+int replica_check_for_data_reload (Replica *r, void *arg)
+{
+ int rc = 0;
+ RUV *upper_bound_ruv = NULL;
+ RUV *r_ruv = NULL;
+ Object *r_obj, *ruv_obj;
+ int cl_cover_be, be_cover_cl;
+
+ PR_ASSERT (r);
+
+ /* check that we have a changelog and if this replica logs changes */
+ if (cl5GetState () == CL5_STATE_OPEN && r->repl_flags & REPLICA_LOG_CHANGES)
+ {
+ /* Compare new ruv to the purge ruv. If the new contains csns which
+ are smaller than those in purge ruv, we need to remove old and
+ create new changelog file for this replica. This is because we
+ will not have sufficient changes to incrementally update a consumer
+ to the current state of the supplier. */
+
+ rc = cl5GetUpperBoundRUV (r, &upper_bound_ruv);
+ if (rc != CL5_SUCCESS && rc != CL5_NOTFOUND)
+ {
+ return -1;
+ }
+
+ if (upper_bound_ruv)
+ {
+ ruv_obj = replica_get_ruv (r);
+ r_ruv = object_get_data (ruv_obj);
+ PR_ASSERT (r_ruv);
+
+ /* Compare new ruv to the changelog's upper bound ruv. We could only keep
+ the existing changelog if its upper bound is the same as replica's RUV.
+ This is because if changelog has changes not in RUV, they will be
+ eventually sent to the consumer's which will cause a state mismatch
+ (because the supplier does not actually contain the changes in its data store.
+ If, on the other hand, the changelog is not as up to date as the supplier,
+ it is not really useful since out of sync consumer's can't be brought
+ up to date using this changelog and hence will need to be reinitialized */
+
+ /*
+ * Actually we can ignore the scenario that the changelog's upper
+ * bound ruv covers data store's ruv for two reasons: (1) a change
+ * is always written to the changelog after it is committed to the
+ * data store; (2) a change will be ignored if the server has seen
+ * it before - this happens frequently at the beginning of replication
+ * sessions.
+ */
+
+ be_cover_cl = ruv_covers_ruv (r_ruv, upper_bound_ruv);
+ cl_cover_be = ruv_covers_ruv (upper_bound_ruv, r_ruv);
+ if (!cl_cover_be)
+ {
+ /* the data was reloaded and we can no longer use existing changelog */
+ char ebuf[BUFSIZ];
+
+ /* create a temporary replica object to conform to the interface */
+ r_obj = object_new (r, NULL);
+
+ /* We can't use existing changelog - remove existing file */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_check_for_data_reload: "
+ "Warning: data for replica %s was reloaded and it no longer matches the data "
+ "in the changelog (replica data %s changelog). Recreating the changelog file. This could affect replication "
+ "with replica's consumers in which case the consumers should be reinitialized.\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf),
+ ((!be_cover_cl && !cl_cover_be) ? "<>" : (!be_cover_cl ? "<" : ">")) );
+
+ rc = cl5DeleteDBSync (r_obj);
+
+ object_release (r_obj);
+
+ if (rc == CL5_SUCCESS)
+ {
+ /* log changes to mark starting point for replication */
+ rc = replica_log_ruv_elements (r);
+ }
+ }
+
+ object_release (ruv_obj);
+ }
+ else /* we have no changes currently logged for this replica */
+ {
+ /* log changes to mark starting point for replication */
+ rc = replica_log_ruv_elements (r);
+ }
+ }
+
+ if (rc == 0)
+ {
+ /* reset mapping tree referrals based on new local RUV */
+ consumer5_set_mapping_tree_state_for_replica(r, NULL);
+ }
+
+ if (upper_bound_ruv)
+ ruv_destroy (&upper_bound_ruv);
+
+ return rc;
+}
+
+/* Helper functions */
+/* reads replica configuration entry. The entry is the child of the
+ mapping tree node for the replica's backend */
+
+static Slapi_Entry*
+_replica_get_config_entry (const Slapi_DN *root)
+{
+ int rc = 0;
+ char *dn = NULL;
+ Slapi_Entry **entries;
+ Slapi_Entry *e = NULL;
+ Slapi_PBlock *pb = NULL;
+
+ dn = _replica_get_config_dn (root);
+ pb = slapi_pblock_new ();
+
+ slapi_search_internal_set_pb (pb, dn, LDAP_SCOPE_BASE, "objectclass=*", NULL, 0, NULL,
+ NULL, repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_search_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc == 0)
+ {
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ e = slapi_entry_dup (entries [0]);
+ }
+
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy (pb);
+ slapi_ch_free_string(&dn);
+
+ return e;
+}
+
+static int
+_replica_check_validity (const Replica *r)
+{
+ PR_ASSERT (r);
+
+ if (r->repl_root == NULL || r->repl_type == 0 || r->repl_rid == 0 ||
+ r->repl_rid > MAX_REPLICA_ID || r->repl_csngen == NULL || r->repl_name == NULL)
+ {
+ return -1;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/* replica configuration entry has the following format:
+ dn: cn=replica,<mapping tree node dn>
+ objectclass: top
+ objectclass: nsds5Replica
+ objectclass: extensibleObject
+ nsds5ReplicaRoot: <root of the replica>
+ nsds5ReplicaId: <replica id>
+ nsds5ReplicaType: <type of the replica: primary, read-write or read-only>
+ nsState: <state of the csn generator> missing the first time replica is started
+ nsds5ReplicaBindDN: <supplier update dn> consumers only
+ nsds5ReplicaReferral: <referral URL to updatable replica> consumers only
+ nsds5ReplicaPurgeDelay: <time, in seconds, to keep purgeable CSNs, 0 == keep forever>
+ nsds5ReplicaTombstonePurgeInterval: <time, in seconds, between tombstone purge runs, 0 == don't reap>
+ nsds5ReplicaLegacyConsumer: <TRUE | FALSE>
+
+ richm: changed slapi entry from const to editable - if the replica id is supplied for a read
+ only replica, we ignore it and replace the value with the READ_ONLY_REPLICA_ID
+ */
+static int
+_replica_init_from_config (Replica *r, Slapi_Entry *e, char *errortext)
+{
+ int rc;
+ Slapi_Attr *attr;
+ char *val;
+ CSNGen *gen;
+ char buf [BUFSIZ];
+ char *errormsg = errortext? errortext : buf;
+ Slapi_Attr *a = NULL;
+ char dnescape[BUFSIZ]; /* for escape_string */
+
+ PR_ASSERT (r && e);
+
+ /* get replica root */
+ val = slapi_entry_attr_get_charptr (e, attr_replicaRoot);
+ if (val == NULL)
+ {
+ sprintf (errormsg, "failed to retrieve %s attribute from (%s)\n",
+ attr_replicaRoot,
+ escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e), dnescape));
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_replica_init_from_config: %s\n",
+ errormsg);
+
+ return -1;
+ }
+
+ r->repl_root = slapi_sdn_new_dn_passin (val);
+
+ /* get replica type */
+ val = slapi_entry_attr_get_charptr (e, attr_replicaType);
+ if (val)
+ {
+ r->repl_type = atoi(val);
+ slapi_ch_free ((void**)&val);
+ }
+ else
+ {
+ r->repl_type = REPLICA_TYPE_READONLY;
+ }
+
+ /* get legacy consumer flag */
+ val = slapi_entry_attr_get_charptr (e, type_replicaLegacyConsumer);
+ if (val)
+ {
+ if (strcasecmp (val, "on") == 0 || strcasecmp (val, "yes") == 0 ||
+ strcasecmp (val, "true") == 0 || strcasecmp (val, "1") == 0)
+ {
+ r->legacy_consumer = PR_TRUE;
+ }
+ else
+ {
+ r->legacy_consumer = PR_FALSE;
+ }
+
+ slapi_ch_free ((void**)&val);
+ }
+ else
+ {
+ r->legacy_consumer = PR_FALSE;
+ }
+
+ /* get replica flags */
+ r->repl_flags = slapi_entry_attr_get_ulong(e, attr_flags);
+
+ /* get replicaid */
+ /* the replica id is ignored for read only replicas and is set to the
+ special value READ_ONLY_REPLICA_ID */
+ if (r->repl_type == REPLICA_TYPE_READONLY)
+ {
+ r->repl_rid = READ_ONLY_REPLICA_ID;
+ slapi_entry_attr_set_uint(e, attr_replicaId, (unsigned int)READ_ONLY_REPLICA_ID);
+ }
+ /* a replica id is required for updatable and primary replicas */
+ else if (r->repl_type == REPLICA_TYPE_UPDATABLE ||
+ r->repl_type == REPLICA_TYPE_PRIMARY)
+ {
+ if ((val = slapi_entry_attr_get_charptr (e, attr_replicaId)))
+ {
+ int temprid = atoi (val);
+ slapi_ch_free ((void**)&val);
+ if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID)
+ {
+ sprintf (errormsg,
+ "attribute %s must have a value greater than 0 "
+ "and less than %d: entry %s",
+ attr_replicaId, READ_ONLY_REPLICA_ID,
+ escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e),
+ dnescape));
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_init_from_config: %s\n",
+ errormsg);
+ return -1;
+ }
+ else
+ {
+ r->repl_rid = (ReplicaId)temprid;
+ }
+ }
+ else
+ {
+ sprintf (errormsg, "failed to retrieve required %s attribute from %s",
+ attr_replicaId,
+ escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e),
+ dnescape));
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_init_from_config: %s\n",
+ errormsg);
+ return -1;
+ }
+ }
+
+ attr = NULL;
+ rc = slapi_entry_attr_find(e, attr_state, &attr);
+ gen = csngen_new (r->repl_rid, attr);
+ if (gen == NULL)
+ {
+ sprintf (errormsg, "failed to create csn generator for replica (%s)",
+ escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e),
+ dnescape));
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_init_from_config: %s\n",
+ errormsg);
+ return -1;
+ }
+ r->repl_csngen = object_new((void*)gen, (FNFree)csngen_free);
+
+ /* Hook generator so we can maintain min/max CSN info */
+ r->csn_pl_reg_id = csngen_register_callbacks(gen, assign_csn_callback, r, abort_csn_callback, r);
+
+ /* get replication bind dn */
+ r->updatedn_list = replica_updatedn_list_new(e);
+
+ /* get replica name */
+ val = slapi_entry_attr_get_charptr (e, attr_replicaName);
+ if (val) {
+ r->repl_name = val;
+ }
+ else
+ {
+ rc = slapi_uniqueIDGenerateString (&r->repl_name);
+ if (rc != UID_SUCCESS)
+ {
+ sprintf (errormsg, "failed to assign replica name for replica (%s); "
+ "uuid generator error - %d ",
+ escape_string((char*)slapi_entry_get_dn ((Slapi_Entry*)e), dnescape),
+ rc);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_replica_init_from_config: %s\n",
+ errormsg);
+ return -1;
+ }
+ else
+ r->new_name = PR_TRUE;
+ }
+
+ /* get the list of referrals */
+ slapi_entry_attr_find( e, attr_replicaReferral, &attr );
+ if(attr!=NULL)
+ {
+ slapi_attr_get_valueset(attr, &r->repl_referral);
+ }
+
+ /*
+ * Set the purge offset (default 7 days). This is the extra
+ * time we allow purgeable CSNs to stick around, in case a
+ * replica regresses. Could also be useful when LCUP happens,
+ * since we don't know about LCUP replicas, and they can just
+ * turn up whenever they want to.
+ */
+ if (slapi_entry_attr_find(e, type_replicaPurgeDelay, &a) == -1)
+ {
+ /* No purge delay provided, so use default */
+ r->repl_purge_delay = 60 * 60 * 24 * 7; /* One week, in seconds */
+ }
+ else
+ {
+ r->repl_purge_delay = slapi_entry_attr_get_uint(e, type_replicaPurgeDelay);
+ }
+
+ if (slapi_entry_attr_find(e, type_replicaTombstonePurgeInterval, &a) == -1)
+ {
+ /* No reap interval provided, so use default */
+ r->tombstone_reap_interval = 3600 * 24; /* One day */
+ }
+ else
+ {
+ r->tombstone_reap_interval = slapi_entry_attr_get_int(e, type_replicaTombstonePurgeInterval);
+ }
+
+ r->tombstone_reap_stop = r->tombstone_reap_active = PR_FALSE;
+
+ return (_replica_check_validity (r));
+}
+
+/* This function updates the entry to contain information generated
+ during replica initialization.
+ Returns 0 if successful and -1 otherwise */
+static int
+_replica_update_entry (Replica *r, Slapi_Entry *e, char *errortext)
+{
+ int rc;
+ Slapi_Mod smod;
+ Slapi_Value *val;
+
+ PR_ASSERT (r);
+
+ /* add attribute that stores state of csn generator */
+ rc = csngen_get_state ((CSNGen*)object_get_data (r->repl_csngen), &smod);
+ if (rc != CSN_SUCCESS)
+ {
+ sprintf (errortext, "failed to get csn generator's state; csn error - %d", rc);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_update_entry: %s\n", errortext);
+ return -1;
+ }
+
+ val = slapi_value_new_berval(slapi_mod_get_first_value(&smod));
+
+ rc = slapi_entry_add_value (e, slapi_mod_get_type (&smod), val);
+
+ slapi_value_free(&val);
+ slapi_mod_done (&smod);
+
+ if (rc != 0)
+ {
+ sprintf (errortext, "failed to update replica entry");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_update_entry: %s\n", errortext);
+ return -1;
+ }
+
+ /* add attribute that stores replica name */
+ rc = slapi_entry_add_string (e, attr_replicaName, r->repl_name);
+ if (rc != 0)
+ {
+ sprintf (errortext, "failed to update replica entry");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_update_entry: %s\n", errortext);
+ return -1;
+ }
+ else
+ r->new_name = PR_FALSE;
+
+ return 0;
+}
+
+/* DN format: cn=replica,cn=\"<root>\",cn=mapping tree,cn=config */
+static char*
+_replica_get_config_dn (const Slapi_DN *root)
+{
+ char *dn;
+ const char *mp_base = slapi_get_mapping_tree_config_root ();
+ int len;
+
+ PR_ASSERT (root);
+
+ len = strlen (REPLICA_RDN) + strlen (slapi_sdn_get_dn (root)) +
+ strlen (mp_base) + 8; /* 8 = , + cn= + \" + \" + , + \0 */
+
+ dn = (char*)slapi_ch_malloc (len);
+ sprintf (dn, "%s,cn=\"%s\",%s", REPLICA_RDN, slapi_sdn_get_dn (root), mp_base);
+
+ return dn;
+}
+
+/* This function retrieves RUV from the root of the replicated tree.
+ * The attribute can be missing if
+ * (1) this replica is the first supplier and replica generation has not been assigned
+ * or
+ * (2) this is a consumer that has not been yet initialized
+ * In either case, replica_set_ruv should be used to further initialize the replica.
+ * Returns 0 on success, -1 on failure. If 0 is returned, the RUV is present in the replica.
+ */
+static int
+_replica_configure_ruv (Replica *r, PRBool isLocked)
+{
+ Slapi_PBlock *pb = NULL;
+ char *attrs[2];
+ int rc;
+ int return_value = -1;
+ Slapi_Entry **entries = NULL;
+ Slapi_Attr *attr;
+ RUV *ruv = NULL;
+ CSN *csn = NULL;
+ ReplicaId rid = 0;
+ char ebuf[BUFSIZ];
+
+ /* read ruv state from the ruv tombstone entry */
+ pb = slapi_pblock_new();
+ attrs[0] = (char*)type_ruvElement;
+ attrs[1] = NULL;
+ slapi_search_internal_set_pb(
+ pb,
+ slapi_sdn_get_dn(r->repl_root),
+ LDAP_SCOPE_BASE,
+ "objectclass=*",
+ attrs,
+ 0, /* attrsonly */
+ NULL, /* controls */
+ RUV_STORAGE_ENTRY_UNIQUEID,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
+ OP_FLAG_REPLICATED); /* flags */
+ slapi_search_internal_pb (pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc == LDAP_SUCCESS)
+ {
+ /* get RUV attributes and construct the RUV */
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0])
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_configure_ruv: replica ruv tombstone entry for "
+ "replica %s not found\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ goto done;
+ }
+
+ rc = slapi_entry_attr_find(entries[0], type_ruvElement, &attr);
+ if (rc != 0) /* ruv attribute is missing - this not allowed */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_configure_ruv: replica ruv tombstone entry for "
+ "replica %s does not contain %s\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), type_ruvElement);
+ goto done;
+ }
+
+ /* Check in the tombstone we have retrieved if the local purl is
+ already present:
+ rid == 0: the local purl is not present
+ rid != 0: the local purl is present ==> nothing to do
+ */
+ ruv_init_from_slapi_attr_and_check_purl (attr, &ruv, &rid);
+ if (ruv)
+ {
+ char *generation = NULL;
+ generation = ruv_get_replica_generation(ruv);
+ if (NULL != generation)
+ {
+ r->repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy);
+
+ /* Is the local purl in the ruv? (the port or the host could have
+ changed)
+ */
+ /* A consumer only doesn't have its purl in its ruv */
+ if (r->repl_type == REPLICA_TYPE_UPDATABLE)
+ {
+ int need_update = 0;
+ if (rid == 0)
+ {
+ /* We can not have more than 1 ruv with the same rid
+ so we replace it */
+ const char *purl = NULL;
+
+ purl = multimaster_get_local_purl();
+ ruv_delete_replica(ruv, r->repl_rid);
+ ruv_add_index_replica(ruv, r->repl_rid, purl, 1);
+ need_update = 1; /* ruv changed, so write tombstone */
+ }
+ else /* bug 540844: make sure the local supplier rid is first in the ruv */
+ {
+ /* make sure local supplier is first in list */
+ ReplicaId first_rid = 0;
+ char *first_purl = NULL;
+ ruv_get_first_id_and_purl(ruv, &first_rid, &first_purl);
+ /* if the local supplier is not first in the list . . . */
+ if (rid != first_rid)
+ {
+ /* . . . move the local supplier to the beginning of the list */
+ ruv_move_local_supplier_to_first(ruv, rid);
+ need_update = 1; /* must update tombstone also */
+ }
+ }
+
+ /* Update also the directory entry */
+ if (need_update) {
+ /* richm 20010821 bug 556498
+ replica_replace_ruv_tombstone acquires the repl_lock, so release
+ the lock then reacquire it if locked */
+ if (isLocked) PR_Unlock(r->repl_lock);
+ replica_replace_ruv_tombstone(r);
+ if (isLocked) PR_Lock(r->repl_lock);
+ }
+ }
+
+ slapi_ch_free((void **)&generation);
+ return_value = 0;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "RUV for replica %s is missing replica generation\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ goto done;
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Unable to convert %s attribute in entry %s to a replica update vector.\n",
+ type_ruvElement, escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ goto done;
+ }
+
+ }
+ else /* search failed */
+ {
+ if (LDAP_NO_SUCH_OBJECT == rc)
+ {
+ /* The entry doesn't exist: create it */
+ rc = replica_create_ruv_tombstone(r);
+ if (LDAP_SUCCESS != rc)
+ {
+ /*
+ * XXXggood - the following error appears on startup if we try
+ * to initialize replica RUVs before the backend instance is up.
+ * It's alarming to see this error, and we should suppress it
+ * (or avoid trying to configure it) if the backend instance is
+ * not yet online.
+ */
+ /*
+ * XXXrichm - you can also get this error when the backend is in
+ * read only mode c.f. bug 539782
+ */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_configure_ruv: failed to create replica ruv tombstone "
+ "entry (%s); LDAP error - %d\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), rc);
+ goto done;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "_replica_configure_ruv: No ruv tombstone found for replica %s. "
+ "Created a new one\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ return_value = 0;
+ }
+ }
+ else
+ {
+ /* see if the suffix is disabled */
+ char *state = slapi_mtn_get_state(r->repl_root);
+ if (state && !strcasecmp(state, "disabled"))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_configure_ruv: replication disabled for "
+ "entry (%s); LDAP error - %d\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), rc);
+ slapi_ch_free_string(&state);
+ goto done;
+ }
+ else if (!r->repl_ruv) /* other error */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_configure_ruv: replication broken for "
+ "entry (%s); LDAP error - %d\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), rc);
+ slapi_ch_free_string(&state);
+ goto done;
+ }
+ else /* some error but continue anyway? */
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "_replica_configure_ruv: Error %d reading tombstone for replica %s.\n",
+ rc, escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ return_value = 0;
+ }
+ slapi_ch_free_string(&state);
+ }
+ }
+
+ if (NULL != r->min_csn_pl)
+ {
+ csnplFree (&r->min_csn_pl);
+ }
+
+ /* create pending list for min csn if necessary */
+ if (ruv_get_smallest_csn_for_replica ((RUV*)object_get_data (r->repl_ruv),
+ r->repl_rid, &csn) == RUV_SUCCESS)
+ {
+ csn_free (&csn);
+ r->min_csn_pl = NULL;
+ }
+ else
+ {
+ /*
+ * The local replica has not generated any of its own CSNs yet.
+ * We need to watch CSNs being generated and note the first
+ * locally-generated CSN that's committed. Once that event occurs,
+ * the RUV is suitable for iteration over locally generated
+ * changes.
+ */
+ r->min_csn_pl = csnplNew();
+ }
+
+done:
+ if (NULL != pb)
+ {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy (pb);
+ }
+ if (return_value != 0)
+ {
+ if (ruv)
+ ruv_destroy (&ruv);
+ }
+
+ return return_value;
+}
+
+/* NOTE - this is the only non-api function that performs locking because
+ it is called by the event queue */
+static void
+_replica_update_state (time_t when, void *arg)
+{
+ int rc;
+ const char *replica_name = (const char *)arg;
+ Object *replica_object = NULL;
+ Replica *r;
+ Slapi_Mod smod;
+ LDAPMod *mods[3];
+ Slapi_PBlock *pb = NULL;
+ char *dn = NULL;
+
+ if (NULL == replica_name)
+ return;
+
+ /*
+ * replica_get_by_name() will acquire the replica object
+ * and that could prevent the replica from being destroyed
+ * until the object_release is called.
+ */
+ replica_object = replica_get_by_name(replica_name);
+ if (NULL == replica_object)
+ {
+ return;
+ }
+
+ /* We have a reference, so replica won't vanish on us. */
+ r = (Replica *)object_get_data(replica_object);
+ if (NULL == r)
+ {
+ goto done;
+ }
+
+ PR_Lock(r->repl_lock);
+
+ /* replica state is currently being updated
+ or no CSN was assigned - bail out */
+ if (r->state_update_inprogress)
+ {
+ PR_Unlock(r->repl_lock);
+ goto done;
+ }
+
+ /* This might be a consumer */
+ if (!r->repl_csn_assigned)
+ {
+ /* EY: the consumer needs to flush ruv to disk. */
+ PR_Unlock(r->repl_lock);
+ replica_write_ruv(r);
+ goto done;
+ }
+
+ /* ONREPL update csn generator state of an updatable replica only */
+ /* ONREPL state always changes because we update time every second and
+ we write state to the disk less frequently */
+ rc = csngen_get_state ((CSNGen*)object_get_data (r->repl_csngen), &smod);
+ if (rc != 0)
+ {
+ PR_Unlock(r->repl_lock);
+ goto done;
+ }
+
+ r->state_update_inprogress = PR_TRUE;
+ r->repl_csn_assigned = PR_FALSE;
+
+ dn = _replica_get_config_dn (r->repl_root);
+ pb = slapi_pblock_new();
+ mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod);
+
+ /* we don't want to held lock during operations since it causes lock contention
+ and sometimes deadlock. So releasing lock here */
+
+ PR_Unlock(r->repl_lock);
+
+ /* replica repl_name and new_name attributes do not get changed once
+ the replica is configured - so it is ok that they are outside replica lock */
+
+ /* write replica name if it has not been written before */
+ if (r->new_name)
+ {
+ struct berval *vals[2];
+ struct berval val;
+ LDAPMod mod;
+
+ mods[1] = &mod;
+
+ mod.mod_op = LDAP_MOD_REPLACE;
+ mod.mod_type = (char*)attr_replicaName;
+ mod.mod_bvalues = vals;
+ vals [0] = &val;
+ vals [1] = NULL;
+ val.bv_val = r->repl_name;
+ val.bv_len = strlen (val.bv_val);
+ mods[2] = NULL;
+ }
+ else
+ {
+ mods[1] = NULL;
+ }
+
+ slapi_modify_internal_set_pb (pb, dn, mods, NULL, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ slapi_modify_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ char ebuf[BUFSIZ];
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_replica_update_state: "
+ "failed to update state of csn generator for replica %s: LDAP "
+ "error - %d\n", escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), rc);
+ }
+ else
+ {
+ r->new_name = PR_FALSE;
+ }
+
+ /* update RUV - performs its own locking */
+ replica_write_ruv (r);
+
+ /* since this is the only place this value is changed and we are
+ guaranteed that only one thread enters the function, its ok
+ to change it outside replica lock */
+ r->state_update_inprogress = PR_FALSE;
+
+ slapi_ch_free ((void**)&dn);
+ slapi_pblock_destroy (pb);
+ slapi_mod_done (&smod);
+
+done:
+ if (replica_object)
+ object_release (replica_object);
+}
+
+void
+replica_write_ruv (Replica *r)
+{
+ int rc;
+ Slapi_Mod smod;
+ Slapi_Mod smod_last_modified;
+ LDAPMod *mods [3];
+ Slapi_PBlock *pb;
+
+ PR_ASSERT(r);
+
+ PR_Lock(r->repl_lock);
+
+ if (!r->repl_ruv_dirty)
+ {
+ PR_Unlock(r->repl_lock);
+ return;
+ }
+
+ PR_ASSERT (r->repl_ruv);
+
+ ruv_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod);
+ ruv_last_modified_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod_last_modified);
+
+ PR_Unlock (r->repl_lock);
+
+ mods [0] = (LDAPMod *)slapi_mod_get_ldapmod_byref(&smod);
+ mods [1] = (LDAPMod *)slapi_mod_get_ldapmod_byref(&smod_last_modified);
+ mods [2] = NULL;
+ pb = slapi_pblock_new();
+
+ /* replica name never changes so it is ok to reference it outside the lock */
+ slapi_modify_internal_set_pb(
+ pb,
+ slapi_sdn_get_dn(r->repl_root), /* only used to select be */
+ mods,
+ NULL, /* controls */
+ RUV_STORAGE_ENTRY_UNIQUEID,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
+ /* Add OP_FLAG_TOMBSTONE_ENTRY so that this doesn't get logged in the Retro ChangeLog */
+ OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | OP_FLAG_TOMBSTONE_ENTRY);
+ slapi_modify_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+
+ /* ruv does not exist - create one */
+ PR_Lock(r->repl_lock);
+
+ if (rc == LDAP_SUCCESS)
+ {
+ r->repl_ruv_dirty = PR_FALSE;
+ }
+ else if (rc == LDAP_NO_SUCH_OBJECT)
+ {
+ /* this includes an internal operation - but since this only happens
+ during server startup - its ok that we have lock around it */
+ rc = _replica_configure_ruv (r, PR_TRUE);
+ if (rc == 0)
+ r->repl_ruv_dirty = PR_FALSE;
+ }
+ else /* error */
+ {
+ char ebuf[BUFSIZ];
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "replica_write_ruv: failed to update RUV tombstone for %s; "
+ "LDAP error - %d\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf), rc);
+ PR_ASSERT (0);
+ }
+
+ PR_Unlock(r->repl_lock);
+
+ slapi_mod_done (&smod);
+ slapi_mod_done (&smod_last_modified);
+ slapi_pblock_destroy (pb);
+}
+
+
+const CSN *
+_get_deletion_csn(Slapi_Entry *e)
+{
+ const CSN *deletion_csn = NULL;
+
+ PR_ASSERT(NULL != e);
+ if (NULL != e)
+ {
+ Slapi_Attr *oc_attr = NULL;
+ if (entry_attr_find_wsi(e, SLAPI_ATTR_OBJECTCLASS, &oc_attr) == ATTRIBUTE_PRESENT)
+ {
+ Slapi_Value *tombstone_value = NULL;
+ struct berval v;
+ v.bv_val = SLAPI_ATTR_VALUE_TOMBSTONE;
+ v.bv_len = strlen(SLAPI_ATTR_VALUE_TOMBSTONE);
+ if (attr_value_find_wsi(oc_attr, &v, &tombstone_value) == VALUE_PRESENT)
+ {
+ deletion_csn = value_get_csn(tombstone_value, CSN_TYPE_VALUE_UPDATED);
+ }
+ }
+ }
+ return deletion_csn;
+}
+
+
+static void
+_delete_tombstone(const char *tombstone_dn, const char *uniqueid)
+{
+
+ PR_ASSERT(NULL != tombstone_dn && NULL != uniqueid);
+ if (NULL == tombstone_dn || NULL == uniqueid)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "_delete_tombstone: "
+ "NULL tombstone_dn or uniqueid provided.\n");
+ }
+ else
+ {
+ int ldaprc;
+ Slapi_PBlock *pb = slapi_pblock_new();
+ slapi_delete_internal_set_pb(pb, tombstone_dn, NULL, /* controls */
+ uniqueid, repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+ OP_FLAG_TOMBSTONE_ENTRY);
+ slapi_delete_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ldaprc);
+ if (LDAP_SUCCESS != ldaprc)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_delete_tombstone: unable to delete tombstone %s, "
+ "uniqueid %s: %s.\n", tombstone_dn, uniqueid,
+ ldap_err2string(ldaprc));
+ }
+ slapi_pblock_destroy(pb);
+ }
+}
+
+static
+void get_reap_result (int rc, void *cb_data)
+{
+ PR_ASSERT (cb_data);
+
+ ((reap_callback_data*)cb_data)->rc = rc;
+}
+
+static
+int process_reap_entry (Slapi_Entry *entry, void *cb_data)
+{
+ char ebuf[BUFSIZ];
+ char deletion_csn_str[CSN_STRSIZE];
+ char purge_csn_str[CSN_STRSIZE];
+ unsigned long *num_entriesp = &((reap_callback_data *)cb_data)->num_entries;
+ unsigned long *num_purged_entriesp = &((reap_callback_data *)cb_data)->num_purged_entries;
+ CSN *purge_csn = ((reap_callback_data *)cb_data)->purge_csn;
+ PRBool *tombstone_reap_stop = ((reap_callback_data *)cb_data)->tombstone_reap_stop;
+ /* we only ask for the objectclass in the search - the deletion csn is in the
+ objectclass attribute values - if we need more attributes returned by the
+ search in the future, see _replica_reap_tombstones below and add more to the
+ attrs array */
+ const CSN *deletion_csn = _get_deletion_csn(entry);
+
+ if ((NULL == deletion_csn || csn_compare(deletion_csn, purge_csn) < 0) &&
+ (!is_ruv_tombstone_entry(entry))) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "_replica_reap_tombstones: removing tombstone %s "
+ "because its deletion csn (%s) is less than the "
+ "purge csn (%s).\n",
+ escape_string(slapi_entry_get_dn(entry), ebuf),
+ csn_as_string(deletion_csn, PR_FALSE, deletion_csn_str),
+ csn_as_string(purge_csn, PR_FALSE, purge_csn_str));
+ _delete_tombstone(slapi_entry_get_dn(entry),
+ slapi_entry_get_uniqueid(entry));
+ (*num_purged_entriesp)++;
+ }
+ else {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "_replica_reap_tombstones: NOT removing tombstone "
+ "%s\n", escape_string(slapi_entry_get_dn(entry),ebuf));
+ }
+ (*num_entriesp)++;
+ if (*tombstone_reap_stop || g_get_shutdown()) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+
+/* This does the actual work of searching for tombstones and deleting them.
+ This must be called in a separate thread because it may take a long time.
+*/
+static void
+_replica_reap_tombstones(void *arg)
+{
+ const char *replica_name = (const char *)arg;
+ Slapi_PBlock *pb = NULL;
+ Object *replica_object = NULL;
+ Replica *replica = NULL;
+ CSN *purge_csn = NULL;
+ char ebuf[BUFSIZ];
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Info: Beginning tombstone reap for replica %s.\n",
+ replica_name ? replica_name : "(null)");
+
+ if (NULL == replica_name)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Warning: Replica name is null in tombstone reap\n");
+ goto done;
+ }
+
+ /*
+ * replica_get_by_name() will acquire the replica object
+ * and that could prevent the replica from being destroyed
+ * until the object_release is called.
+ */
+ replica_object = replica_get_by_name(replica_name);
+ if (NULL == replica_object)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Warning: Replica object %s is null in tombstone reap\n", replica_name);
+ goto done;
+ }
+
+ /* We have a reference, so replica won't vanish on us. */
+ replica = (Replica *)object_get_data(replica_object);
+ if (NULL == replica)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Warning: Replica %s is null in tombstone reap\n", replica_name);
+ goto done;
+ }
+
+ if (replica->tombstone_reap_stop)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Info: Replica %s reap stop flag is set for tombstone reap\n", replica_name);
+ goto done;
+ }
+
+ purge_csn = replica_get_purge_csn(replica);
+ if (NULL != purge_csn)
+ {
+ LDAPControl **ctrls;
+ int oprc;
+ reap_callback_data cb_data;
+ char **attrs = NULL;
+
+ /* we just need the objectclass - for the deletion csn
+ and the dn and nsuniqueid - for possible deletion
+ saves time to return only 2 attrs
+ */
+ charray_add(&attrs, slapi_ch_strdup("objectclass"));
+ charray_add(&attrs, slapi_ch_strdup("nsuniqueid"));
+
+ ctrls = (LDAPControl **)slapi_ch_calloc (3, sizeof (LDAPControl *));
+ ctrls[0] = create_managedsait_control();
+ ctrls[1] = create_backend_control(replica->repl_root);
+ ctrls[2] = NULL;
+ pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(pb, slapi_sdn_get_dn(replica->repl_root),
+ LDAP_SCOPE_SUBTREE, "(&(objectclass=nstombstone)(nscpentrydn=*))",
+ attrs, 0, ctrls, NULL,
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0);
+
+ cb_data.rc = 0;
+ cb_data.num_entries = 0UL;
+ cb_data.num_purged_entries = 0UL;
+ cb_data.purge_csn = purge_csn;
+ cb_data.tombstone_reap_stop = &(replica->tombstone_reap_stop);
+
+ slapi_search_internal_callback_pb (pb, &cb_data /* callback data */,
+ get_reap_result /* result callback */,
+ process_reap_entry /* entry callback */,
+ NULL /* referral callback*/);
+
+ charray_free(attrs);
+
+ oprc = cb_data.rc;
+
+ if (LDAP_SUCCESS != oprc)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "_replica_reap_tombstones: failed when searching for "
+ "tombstones in replica %s: %s. Will try again in %d "
+ "seconds.\n", escape_string(slapi_sdn_get_dn(replica->repl_root),ebuf),
+ ldap_err2string(oprc), replica->tombstone_reap_interval);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "_replica_reap_tombstones: purged %d of %d tombstones "
+ "in replica %s. Will try again in %d "
+ "seconds.\n", cb_data.num_purged_entries, cb_data.num_entries,
+ escape_string(slapi_sdn_get_dn(replica->repl_root),ebuf),
+ replica->tombstone_reap_interval);
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Info: No purge CSN for tombstone reap for replica %s.\n",
+ replica_name ? replica_name : "(null)");
+ }
+
+ PR_Lock(replica->repl_lock);
+ replica->tombstone_reap_active = PR_FALSE;
+ PR_Unlock(replica->repl_lock);
+
+done:
+ if (NULL != purge_csn)
+ {
+ csn_free(&purge_csn);
+ }
+ if (NULL != pb)
+ {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ }
+ if (NULL != replica_object)
+ {
+ object_release(replica_object);
+ replica_object = NULL;
+ replica = NULL;
+ }
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Info: Finished tombstone reap for replica %s.\n",
+ replica_name ? replica_name : "(null)");
+
+}
+
+/*
+ We don't want to run the reaper function directly from the event
+ queue since it may hog the event queue, starving other events.
+ See bug 604441
+ The function eq_cb_reap_tombstones will fire off the actual thread
+ that does the real work.
+*/
+static void
+eq_cb_reap_tombstones(time_t when, void *arg)
+{
+ const char *replica_name = (const char *)arg;
+ Object *replica_object = NULL;
+ Replica *replica = NULL;
+
+ if (NULL != replica_name)
+ {
+ /*
+ * replica_get_by_name() will acquire the replica object
+ * and that could prevent the replica from being destroyed
+ * until the object_release is called.
+ */
+ replica_object = replica_get_by_name(replica_name);
+ if (NULL != replica_object)
+ {
+ /* We have a reference, so replica won't vanish on us. */
+ replica = (Replica *)object_get_data(replica_object);
+ if (replica)
+ {
+
+ PR_Lock(replica->repl_lock);
+
+ /* No action if purge is disabled or the previous purge is not done yet */
+ if (replica->tombstone_reap_interval != 0 &&
+ replica->tombstone_reap_active == PR_FALSE)
+ {
+ /* set the flag here to minimize race conditions */
+ replica->tombstone_reap_active = PR_TRUE;
+ if (PR_CreateThread(PR_USER_THREAD,
+ _replica_reap_tombstones, (void *)replica_name,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE) == NULL)
+ {
+ replica->tombstone_reap_active = PR_FALSE;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Error: unable to create the tombstone reap thread for replica %s. "
+ "Possible system resources problem\n",
+ replica_name);
+ }
+ }
+ /* reap thread will wait until this lock is released */
+ PR_Unlock(replica->repl_lock);
+ }
+ object_release(replica_object);
+ replica_object = NULL;
+ replica = NULL;
+ }
+ }
+}
+
+static char *
+_replica_type_as_string (const Replica *r)
+{
+ switch (r->repl_type)
+ {
+ case REPLICA_TYPE_PRIMARY: return "primary";
+ case REPLICA_TYPE_READONLY: return "read-only";
+ case REPLICA_TYPE_UPDATABLE: return "updatable";
+ default: return "unknown";
+ }
+}
+
+
+static const char *root_glue =
+ "dn: %s\n"
+ "objectclass: top\n"
+ "objectclass: nsTombstone\n"
+ "objectclass: extensibleobject\n"
+ "nsuniqueid: %s\n";
+
+static int
+replica_create_ruv_tombstone(Replica *r)
+{
+ int return_value = LDAP_LOCAL_ERROR;
+ char *root_entry_str;
+ Slapi_Entry *e;
+ const char *purl = NULL;
+ RUV *ruv;
+ struct berval **bvals = NULL;
+ Slapi_PBlock *pb = NULL;
+ int rc;
+ char ebuf[BUFSIZ];
+
+ PR_ASSERT(NULL != r && NULL != r->repl_root);
+ root_entry_str = slapi_ch_malloc(strlen(root_glue) +
+ slapi_sdn_get_ndn_len(r->repl_root) +
+ strlen(RUV_STORAGE_ENTRY_UNIQUEID) + 1);
+ sprintf(root_entry_str, root_glue, slapi_sdn_get_ndn(r->repl_root),
+ RUV_STORAGE_ENTRY_UNIQUEID);
+
+ e = slapi_str2entry(root_entry_str, SLAPI_STR2ENTRY_TOMBSTONE_CHECK);
+ if (e == NULL)
+ goto done;
+
+ /* Add ruv */
+ if (r->repl_ruv == NULL)
+ {
+ CSNGen *gen;
+ CSN *csn;
+ char csnstr [CSN_STRSIZE];
+
+ /* first attempt to write RUV tombstone - need to create RUV */
+ gen = (CSNGen *)object_get_data(r->repl_csngen);
+ PR_ASSERT (gen);
+
+ if (csngen_new_csn(gen, &csn, PR_FALSE /* notify */) == CSN_SUCCESS)
+ {
+ (void)csn_as_string(csn, PR_FALSE, csnstr);
+ csn_free(&csn);
+
+ /* if this is an updateable replica - add its own
+ element to the RUV so that referrals work correctly */
+ if (r->repl_type == REPLICA_TYPE_UPDATABLE)
+ purl = multimaster_get_local_purl();
+
+ if (ruv_init_new(csnstr, r->repl_rid, purl, &ruv) == RUV_SUCCESS)
+ {
+ r->repl_ruv = object_new((void*)ruv, (FNFree)ruv_destroy);
+ r->repl_ruv_dirty = PR_TRUE;
+ return_value = LDAP_SUCCESS;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Cannot create new replica update vector for %s\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ goto done;
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Cannot obtain CSN for new replica update vector for %s\n",
+ escape_string(slapi_sdn_get_dn(r->repl_root),ebuf));
+ goto done;
+ }
+ }
+ else /* failed to write the entry because DB was not initialized - retry */
+ {
+ ruv = (RUV*) object_get_data (r->repl_ruv);
+ PR_ASSERT (ruv);
+ }
+
+ PR_ASSERT (r->repl_ruv);
+
+ rc = ruv_to_bervals(ruv, &bvals);
+ if (rc != RUV_SUCCESS)
+ {
+ goto done;
+ }
+
+ /* ONREPL this is depricated function but there is currently no better API to use */
+ rc = slapi_entry_add_values(e, type_ruvElement, bvals);
+ if (rc != 0)
+ {
+ goto done;
+ }
+
+
+ pb = slapi_pblock_new();
+ slapi_add_entry_internal_set_pb(
+ pb,
+ e,
+ NULL /* controls */,
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+ OP_FLAG_TOMBSTONE_ENTRY | OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP);
+ slapi_add_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value);
+ if (return_value == LDAP_SUCCESS)
+ r->repl_ruv_dirty = PR_FALSE;
+
+done:
+ if (return_value != LDAP_SUCCESS)
+ {
+ slapi_entry_free (e);
+ }
+
+ if (bvals)
+ ber_bvecfree(bvals);
+
+ if (pb)
+ slapi_pblock_destroy(pb);
+
+ slapi_ch_free((void **) &root_entry_str);
+
+ return return_value;
+}
+
+
+static void
+assign_csn_callback(const CSN *csn, void *data)
+{
+ Replica *r = (Replica *)data;
+ Object *ruv_obj;
+ RUV *ruv;
+
+ PR_ASSERT(NULL != csn);
+ PR_ASSERT(NULL != r);
+
+ ruv_obj = replica_get_ruv (r);
+ PR_ASSERT (ruv_obj);
+ ruv = (RUV*)object_get_data (ruv_obj);
+ PR_ASSERT (ruv);
+
+ PR_Lock(r->repl_lock);
+
+ r->repl_csn_assigned = PR_TRUE;
+
+ if (NULL != r->min_csn_pl)
+ {
+ if (csnplInsert(r->min_csn_pl, csn) != 0)
+ {
+ char ebuf[BUFSIZ];
+ char csn_str[CSN_STRSIZE]; /* For logging only */
+ /* Ack, we can't keep track of min csn. Punt. */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "assign_csn_callback: "
+ "failed to insert csn %s for replica %s\n",
+ csn_as_string(csn, PR_FALSE, csn_str),
+ escape_string(slapi_sdn_get_dn(r->repl_root), ebuf));
+ csnplFree(&r->min_csn_pl);
+ }
+ }
+
+ ruv_add_csn_inprogress (ruv, csn);
+
+ PR_Unlock(r->repl_lock);
+
+ object_release (ruv_obj);
+}
+
+
+static void
+abort_csn_callback(const CSN *csn, void *data)
+{
+ Replica *r = (Replica *)data;
+ Object *ruv_obj;
+ RUV *ruv;
+ int rc;
+
+ PR_ASSERT(NULL != csn);
+ PR_ASSERT(NULL != data);
+
+ ruv_obj = replica_get_ruv (r);
+ PR_ASSERT (ruv_obj);
+ ruv = (RUV*)object_get_data (ruv_obj);
+ PR_ASSERT (ruv);
+
+ PR_Lock(r->repl_lock);
+
+ if (NULL != r->min_csn_pl)
+ {
+ rc = csnplRemove(r->min_csn_pl, csn);
+ PR_ASSERT(rc == 0);
+ }
+
+ ruv_cancel_csn_inprogress (ruv, csn);
+ PR_Unlock(r->repl_lock);
+
+ object_release (ruv_obj);
+}
+
+static CSN *
+_replica_get_purge_csn_nolock(const Replica *r)
+{
+ static unsigned long a_week = 3600*24*7;
+ CSN *purge_csn = NULL;
+ CSN **csns = NULL;
+ RUV *ruv;
+ time_t cutoff_time;
+ time_t max_time_in_csn_list;
+ int i;
+
+ if (r->repl_purge_delay > 0)
+ {
+ /*
+ * Don't let inactive or obsolete masters in the ruv hold back
+ * the purge forever:
+ * - set a graceful period of at least 7 days;
+ * - set cutoff_time = max(maxcsns) - gracefule_period;
+ * - the first maxcsn that was generated at or after the cutoff
+ * time would be the purge csn.
+ */
+
+ /* get a sorted list of all maxcsns in ruv in ascend order */
+ object_acquire(r->repl_ruv);
+ ruv = object_get_data(r->repl_ruv);
+ csns = cl5BuildCSNList (ruv, NULL);
+ object_release(r->repl_ruv);
+
+ if (csns == NULL)
+ return NULL;
+
+ /* locate the max csn in the csn list */
+ for (i = 0; csns[i]; i++);
+ max_time_in_csn_list = csn_get_time (csns[i-1]);
+
+ if ( r->repl_purge_delay > a_week )
+ {
+ cutoff_time = max_time_in_csn_list - r->repl_purge_delay;
+ }
+ else
+ {
+ cutoff_time = max_time_in_csn_list - a_week;
+ }
+ for (i = 0; csns[i]; i++)
+ {
+ if ( csn_get_time (csns[i]) >= cutoff_time )
+ {
+ purge_csn = csn_dup (csns[i]);
+ break;
+ }
+ }
+
+ /* Subtract purge delay */
+ if (purge_csn)
+ {
+ csn_set_time(purge_csn, csn_get_time(purge_csn) - r->repl_purge_delay);
+ }
+ }
+
+ if (csns)
+ cl5DestroyCSNList (&csns);
+
+ return purge_csn;
+}
+
+static void
+replica_get_referrals_nolock (const Replica *r, char ***referrals)
+{
+ if(referrals!=NULL)
+ {
+
+ int hint;
+ int i= 0;
+ Slapi_Value *v= NULL;
+
+ if (NULL == r->repl_referral)
+ {
+ *referrals = NULL;
+ }
+ else
+ {
+ /* richm: +1 for trailing NULL */
+ *referrals= (char**)slapi_ch_calloc(sizeof(char*),1+slapi_valueset_count(r->repl_referral));
+ hint= slapi_valueset_first_value( r->repl_referral, &v );
+ while(v!=NULL)
+ {
+ const char *s= slapi_value_get_string(v);
+ if(s!=NULL && s[0]!='\0')
+ {
+ (*referrals)[i]= slapi_ch_strdup(s);
+ i++;
+ }
+ hint= slapi_valueset_next_value( r->repl_referral, hint, &v);
+ }
+ (*referrals)[i] = NULL;
+ }
+
+ }
+}
+
+static void
+replica_clear_legacy_referrals(const Slapi_DN *repl_root_sdn,
+ char **referrals, const char *state)
+{
+ repl_set_mtn_state_and_referrals(repl_root_sdn, state, NULL, NULL, referrals);
+}
+
+static void
+replica_remove_legacy_attr (const Slapi_DN *repl_root_sdn, const char *attr)
+{
+ Slapi_PBlock *pb;
+ Slapi_Mods smods;
+ LDAPControl **ctrls;
+ int rc;
+
+ pb = slapi_pblock_new ();
+
+ slapi_mods_init(&smods, 1);
+ slapi_mods_add(&smods, LDAP_MOD_DELETE, attr, 0, NULL);
+
+
+ ctrls = (LDAPControl**)slapi_ch_malloc (2 * sizeof (LDAPControl*));
+ ctrls[0] = create_managedsait_control ();
+ ctrls[1] = NULL;
+
+ /* remove copiedFrom/copyingFrom first */
+ slapi_modify_internal_set_pb (pb, slapi_sdn_get_dn (repl_root_sdn),
+ slapi_mods_get_ldapmods_passout (&smods), ctrls,
+ NULL /*uniqueid */,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION) ,
+ 0 /* operation_flags */);
+
+ slapi_modify_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ char ebuf[BUFSIZ];
+
+ /* this is not a fatal error because the attribute may not be there */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_remove_legacy_attr: "
+ "failed to remove legacy attribute %s for replica %s; LDAP error - %d\n",
+ attr, escape_string(slapi_sdn_get_dn(repl_root_sdn),ebuf), rc);
+ }
+
+ slapi_mods_done (&smods);
+ slapi_pblock_destroy (pb);
+}
+
+static int
+replica_log_ruv_elements_nolock (const Replica *r)
+{
+ int rc = 0;
+ slapi_operation_parameters op_params;
+ RUV *ruv;
+ char *repl_gen;
+ CSN *csn = NULL;
+
+ ruv = (RUV*) object_get_data (r->repl_ruv);
+ PR_ASSERT (ruv);
+
+ if ((ruv_get_min_csn(ruv, &csn) == RUV_SUCCESS) && csn)
+ {
+ /* we log it as a delete operation to have the least number of fields
+ to set. the entry can be identified by a special target uniqueid and
+ special target dn */
+ memset (&op_params, 0, sizeof (op_params));
+ op_params.operation_type = SLAPI_OPERATION_DELETE;
+ op_params.target_address.dn = START_ITERATION_ENTRY_DN;
+ op_params.target_address.uniqueid = START_ITERATION_ENTRY_UNIQUEID;
+ op_params.csn = csn;
+ repl_gen = ruv_get_replica_generation (ruv);
+
+ rc = cl5WriteOperation(r->repl_name, repl_gen, &op_params, PR_FALSE);
+ if (rc == CL5_SUCCESS)
+ rc = 0;
+ else
+ rc = -1;
+
+ slapi_ch_free ((void**)&repl_gen);
+ csn_free (&csn);
+ }
+
+ return rc;
+}
+
+void
+replica_set_purge_delay(Replica *r, PRUint32 purge_delay)
+{
+ PR_ASSERT(r);
+ PR_Lock(r->repl_lock);
+ r->repl_purge_delay = purge_delay;
+ PR_Unlock(r->repl_lock);
+}
+
+void
+replica_set_tombstone_reap_interval (Replica *r, long interval)
+{
+ char *repl_name;
+
+ PR_Lock(r->repl_lock);
+
+ /*
+ * Leave the event there to purge the existing tombstones
+ * if we are about to turn off tombstone creation
+ */
+ if (interval > 0 && r->repl_eqcxt_tr && r->tombstone_reap_interval != interval)
+ {
+ int found;
+
+ repl_name = slapi_eq_get_arg (r->repl_eqcxt_tr);
+ slapi_ch_free ((void**)&repl_name);
+ found = slapi_eq_cancel (r->repl_eqcxt_tr);
+ slapi_log_error (SLAPI_LOG_REPL, NULL,
+ "tombstone_reap event (interval=%d) was %s\n",
+ r->tombstone_reap_interval, (found ? "cancelled" : "not found"));
+ r->repl_eqcxt_tr = NULL;
+ }
+ r->tombstone_reap_interval = interval;
+ if ( interval > 0 && r->repl_eqcxt_tr == NULL )
+ {
+ repl_name = slapi_ch_strdup (r->repl_name);
+ r->repl_eqcxt_tr = slapi_eq_repeat (eq_cb_reap_tombstones, repl_name, current_time() + START_REAP_DELAY, 1000 * r->tombstone_reap_interval);
+ slapi_log_error (SLAPI_LOG_REPL, NULL,
+ "tombstone_reap event (interval=%d) was %s\n",
+ r->tombstone_reap_interval, (r->repl_eqcxt_tr ? "scheduled" : "not scheduled successfully"));
+ }
+ PR_Unlock(r->repl_lock);
+}
+
+/* Update the tombstone entry to reflect the content of the ruv */
+static void
+replica_replace_ruv_tombstone(Replica *r)
+{
+ Slapi_PBlock *pb = NULL;
+ char *dn;
+ int rc;
+
+ Slapi_Mod smod;
+ Slapi_Mod smod_last_modified;
+ LDAPMod *mods [3];
+
+ PR_ASSERT(NULL != r && NULL != r->repl_root);
+
+ PR_Lock(r->repl_lock);
+
+ PR_ASSERT (r->repl_ruv);
+ ruv_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod);
+ ruv_last_modified_to_smod ((RUV*)object_get_data(r->repl_ruv), &smod_last_modified);
+
+ dn = _replica_get_config_dn (r->repl_root);
+ mods[0] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod);
+ mods[1] = (LDAPMod*)slapi_mod_get_ldapmod_byref(&smod_last_modified);
+
+ PR_Unlock (r->repl_lock);
+
+ mods [2] = NULL;
+ pb = slapi_pblock_new();
+
+ slapi_modify_internal_set_pb(
+ pb,
+ (char*)slapi_sdn_get_dn (r->repl_root), /* only used to select be */
+ mods,
+ NULL, /* controls */
+ RUV_STORAGE_ENTRY_UNIQUEID,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
+ OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP);
+
+ slapi_modify_internal_pb (pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+
+ if (rc != LDAP_SUCCESS)
+ {
+ if ((rc != LDAP_NO_SUCH_OBJECT) || !replica_is_state_flag_set(r, REPLICA_IN_USE))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_replace_ruv_tombstone: "
+ "failed to update replication update vector for replica %s: LDAP "
+ "error - %d\n", (char*)slapi_sdn_get_dn (r->repl_root), rc);
+ }
+ }
+
+ slapi_ch_free ((void**)&dn);
+ slapi_pblock_destroy (pb);
+ slapi_mod_done (&smod);
+ slapi_mod_done (&smod_last_modified);
+}
+
+void
+replica_update_ruv_consumer(Replica *r, RUV *supplier_ruv)
+{
+ ReplicaId supplier_id = 0;
+ char *supplier_purl = NULL;
+
+ if ( ruv_get_first_id_and_purl(supplier_ruv, &supplier_id, &supplier_purl) == RUV_SUCCESS )
+ {
+ RUV *local_ruv = NULL;
+
+ PR_Lock(r->repl_lock);
+
+ local_ruv = (RUV*)object_get_data (r->repl_ruv);
+ PR_ASSERT (local_ruv);
+
+ if ( ruv_local_contains_supplier(local_ruv, supplier_id) == 0 )
+ {
+ if ( r->repl_type == REPLICA_TYPE_UPDATABLE )
+ {
+ /* Add the new ruv right after the consumer own purl */
+ ruv_add_index_replica(local_ruv, supplier_id, supplier_purl, 2);
+ }
+ else
+ {
+ /* This is a consumer only, add it first */
+ ruv_add_index_replica(local_ruv, supplier_id, supplier_purl, 1);
+ }
+ }
+ else
+ {
+ /* Replace it */
+ ruv_replace_replica_purl(local_ruv, supplier_id, supplier_purl);
+ }
+ PR_Unlock(r->repl_lock);
+
+ /* Update also the directory entry */
+ replica_replace_ruv_tombstone(r);
+ }
+}
+
+void
+replica_set_ruv_dirty(Replica *r)
+{
+ PR_ASSERT(r);
+ PR_Lock(r->repl_lock);
+ r->repl_ruv_dirty = PR_TRUE;
+ PR_Unlock(r->repl_lock);
+}
+
+PRBool
+replica_is_state_flag_set(Replica *r, PRInt32 flag)
+{
+ PR_ASSERT(r);
+ if (r)
+ return (r->repl_state_flags & flag);
+ else
+ return PR_FALSE;
+}
+
+void
+replica_set_state_flag (Replica *r, PRUint32 flag, PRBool clear)
+{
+ if (r == NULL)
+ return;
+
+ PR_Lock(r->repl_lock);
+
+ if (clear)
+ {
+ r->repl_state_flags &= ~flag;
+ }
+ else
+ {
+ r->repl_state_flags |= flag;
+ }
+
+ PR_Unlock(r->repl_lock);
+}
+
+/* replica just came back online, probably after data was reloaded */
+void
+replica_enable_replication (Replica *r)
+{
+ int rc;
+
+ PR_ASSERT(r);
+
+ /* prevent creation of new agreements until the replica is enabled */
+ PR_Lock(r->agmt_lock);
+
+ /* retrieve new ruv */
+ rc = replica_reload_ruv (r);
+ if (rc) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_enable_replication: "
+ "reloading ruv failed\n");
+ /* What to do ? */
+ }
+
+ /* Replica came back online, Check if the total update was terminated.
+ If flag is still set, it was not terminated, therefore the data is
+ very likely to be incorrect, and we should not restart Replication threads...
+ */
+ if (!replica_is_state_flag_set(r, REPLICA_TOTAL_IN_PROGRESS)){
+ /* restart outbound replication */
+ start_agreements_for_replica (r, PR_TRUE);
+
+ /* enable ruv state update */
+ replica_set_enabled (r, PR_TRUE);
+ }
+
+ /* mark the replica as being available for updates */
+ replica_relinquish_exclusive_access(r, 0, 0);
+
+ replica_set_state_flag(r, REPLICA_AGREEMENTS_DISABLED, PR_TRUE /* clear */);
+ PR_Unlock(r->agmt_lock);
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_enable_replication: "
+ "replica %s is relinquished\n",
+ slapi_sdn_get_ndn (replica_get_root (r)));
+}
+
+/* replica is about to be taken offline */
+void
+replica_disable_replication (Replica *r, Object *r_obj)
+{
+ char *current_purl = NULL;
+ char *p_locking_purl = NULL;
+ char *locking_purl = NULL;
+ int junkrc;
+ ReplicaId junkrid;
+ PRBool isInc = PR_FALSE; /* get exclusive access, but not for inc update */
+ RUV *repl_ruv = NULL;
+
+ /* prevent creation of new agreements until the replica is disabled */
+ PR_Lock(r->agmt_lock);
+
+ /* stop ruv update */
+ replica_set_enabled (r, PR_FALSE);
+
+ /* disable outbound replication */
+ start_agreements_for_replica (r, PR_FALSE);
+
+ /* close the corresponding changelog file */
+ /* close_changelog_for_replica (r_obj); */
+
+ /* mark the replica as being unavailable for updates */
+ /* If an incremental update is in progress, we want to wait until it is
+ finished until we get exclusive access to the replica, because we have
+ to make sure no operations are in progress - it messes up replication
+ when a restore is in progress but we are still adding replicated entries
+ from a supplier
+ */
+ repl_ruv = (RUV*) object_get_data (r->repl_ruv);
+ junkrc = ruv_get_first_id_and_purl(repl_ruv, &junkrid, &p_locking_purl);
+ locking_purl = slapi_ch_strdup(p_locking_purl);
+ p_locking_purl = NULL;
+ repl_ruv = NULL;
+ while (!replica_get_exclusive_access(r, &isInc, 0, 0, "replica_disable_replication",
+ &current_purl)) {
+ if (!isInc) /* already locked, but not by inc update - break */
+ break;
+ isInc = PR_FALSE;
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "replica_disable_replication: "
+ "replica %s is already locked by (%s) for incoming "
+ "incremental update; sleeping 100ms\n",
+ slapi_sdn_get_ndn (replica_get_root (r)),
+ current_purl ? current_purl : "unknown");
+ slapi_ch_free_string(&current_purl);
+ DS_Sleep(PR_MillisecondsToInterval(100));
+ }
+
+ slapi_ch_free_string(&current_purl);
+ slapi_ch_free_string(&locking_purl);
+ replica_set_state_flag(r, REPLICA_AGREEMENTS_DISABLED, PR_FALSE);
+ PR_Unlock(r->agmt_lock);
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_disable_replication: "
+ "replica %s is acquired\n",
+ slapi_sdn_get_ndn (replica_get_root (r)));
+}
+
+static void
+start_agreements_for_replica (Replica *r, PRBool start)
+{
+ Object *agmt_obj;
+ Repl_Agmt *agmt;
+
+ agmt_obj = agmtlist_get_first_agreement_for_replica (r);
+ while (agmt_obj)
+ {
+ agmt = (Repl_Agmt*)object_get_data (agmt_obj);
+ PR_ASSERT (agmt);
+
+ if (start)
+ agmt_start (agmt);
+ else /* stop */
+ agmt_stop (agmt);
+
+ agmt_obj = agmtlist_get_next_agreement_for_replica (r, agmt_obj);
+ }
+}
+
+int replica_start_agreement(Replica *r, Repl_Agmt *ra)
+{
+ int ret = 0;
+
+ if (r == NULL) return -1;
+
+ PR_Lock(r->agmt_lock);
+
+ if (!replica_is_state_flag_set(r, REPLICA_AGREEMENTS_DISABLED)) {
+ ret = agmt_start(ra); /* Start the replication agreement */
+ }
+
+ PR_Unlock(r->agmt_lock);
+ return ret;
+}
+
+/*
+ * A callback function registed as op->o_csngen_handler and
+ * called by backend ops to generate opcsn.
+ */
+CSN *
+replica_generate_next_csn ( Slapi_PBlock *pb, const CSN *basecsn )
+{
+ CSN *opcsn = NULL;
+ Object *replica_obj;
+
+ replica_obj = replica_get_replica_for_op (pb);
+ if (NULL != replica_obj)
+ {
+ Replica *replica = (Replica*) object_get_data (replica_obj);
+ if ( NULL != replica )
+ {
+ Slapi_Operation *op;
+ slapi_pblock_get (pb, SLAPI_OPERATION, &op);
+ if ( replica->repl_type != REPLICA_TYPE_READONLY ||
+ operation_is_flag_set (op, OP_FLAG_LEGACY_REPLICATION_DN ))
+ {
+ Object *gen_obj = replica_get_csngen (replica);
+ if (NULL != gen_obj)
+ {
+ CSNGen *gen = (CSNGen*) object_get_data (gen_obj);
+ if (NULL != gen)
+ {
+ /* The new CSN should be greater than the base CSN */
+ csngen_new_csn (gen, &opcsn, PR_FALSE /* don't notify */);
+ if (csn_compare (opcsn, basecsn) <= 0)
+ {
+ char opcsnstr[CSN_STRSIZE], basecsnstr[CSN_STRSIZE];
+ char opcsn2str[CSN_STRSIZE];
+
+ csn_as_string (opcsn, PR_FALSE, opcsnstr);
+ csn_as_string (basecsn, PR_FALSE, basecsnstr);
+ csn_free ( &opcsn );
+ csngen_adjust_time (gen, basecsn);
+ csngen_new_csn (gen, &opcsn, PR_FALSE /* don't notify */);
+ csn_as_string (opcsn, PR_FALSE, opcsn2str);
+ slapi_log_error (SLAPI_LOG_FATAL, NULL,
+ "replica_generate_next_csn: "
+ "opcsn=%s <= basecsn=%s, adjusted opcsn=%s\n",
+ opcsnstr, basecsnstr, opcsn2str);
+ }
+ /*
+ * Insert opcsn into the csn pending list.
+ * This is the notify effect in csngen_new_csn().
+ */
+ assign_csn_callback (opcsn, (void *)replica);
+ }
+ object_release (gen_obj);
+ }
+ }
+ }
+ object_release (replica_obj);
+ }
+
+ return opcsn;
+}
+
+/*
+ * A callback function registed as op->o_replica_attr_handler and
+ * called by backend ops to get replica attributes.
+ */
+int
+replica_get_attr ( Slapi_PBlock *pb, const char* type, void *value )
+{
+ int rc = -1;
+
+ Object *replica_obj;
+ replica_obj = replica_get_replica_for_op (pb);
+ if (NULL != replica_obj)
+ {
+ Replica *replica = (Replica*) object_get_data (replica_obj);
+ if ( NULL != replica )
+ {
+ if (strcasecmp (type, type_replicaTombstonePurgeInterval) == 0)
+ {
+ *((int*)value) = replica->tombstone_reap_interval;
+ rc = 0;
+ }
+ else if (strcasecmp (type, type_replicaPurgeDelay) == 0)
+ {
+ *((int*)value) = replica->repl_purge_delay;
+ rc = 0;
+ }
+ }
+ object_release (replica_obj);
+ }
+
+ return rc;
+}
diff --git a/ldap/servers/plugins/replication/repl5_replica_config.c b/ldap/servers/plugins/replication/repl5_replica_config.c
new file mode 100644
index 00000000..df2573a0
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_replica_config.c
@@ -0,0 +1,750 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_replica_config.c - replica configuration over ldap */
+#include <ctype.h> /* for isdigit() */
+#include "repl.h" /* ONREPL - this is bad */
+#include "repl5.h"
+#include "cl5_api.h"
+
+#define CONFIG_BASE "cn=mapping tree,cn=config"
+#define CONFIG_FILTER "(objectclass=nsDS5Replica)"
+#define TASK_ATTR "nsds5Task"
+#define CL2LDIF_TASK "CL2LDIF"
+#define CLEANRUV "CLEANRUV"
+#define CLEANRUVLEN 8
+
+int slapi_log_urp = SLAPI_LOG_REPL;
+
+/* Forward Declartions */
+static int replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+static int replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+
+static int replica_config_change_type_and_id (Replica *r, const char *new_type, const char *new_id, char *returntext, int apply_mods);
+static int replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext, int apply_mods);
+static int replica_config_change_flags (Replica *r, const char *new_flags, char *returntext, int apply_mods);
+static int replica_execute_task (Object *r, const char *task_name, char *returntext, int apply_mods);
+static int replica_execute_cl2ldif_task (Object *r, char *returntext);
+static int replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext);
+
+static multimaster_mtnode_extension * _replica_config_get_mtnode_ext (const Slapi_Entry *e);
+
+static PRLock *s_configLock;
+
+static int
+dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+int
+replica_config_init()
+{
+ s_configLock = PR_NewLock ();
+ if (s_configLock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_init: "
+ "failed to cretate configuration lock; NSPR error - %d\n",
+ PR_GetError ());
+ return -1;
+ }
+
+ /* config DSE must be initialized before we get here */
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, replica_config_add, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, replica_config_modify,NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, dont_allow_that, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, replica_config_delete,NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, replica_config_search,NULL);
+ return 0;
+}
+
+void
+replica_config_destroy ()
+{
+ if (s_configLock)
+ {
+ PR_DestroyLock (s_configLock);
+ s_configLock = NULL;
+ }
+
+ /* config DSE must be initialized before we get here */
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, replica_config_add);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, replica_config_modify);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODRDN, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, dont_allow_that);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, replica_config_delete);
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, CONFIG_BASE, LDAP_SCOPE_SUBTREE,
+ CONFIG_FILTER, replica_config_search);
+}
+
+static int
+replica_config_add (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
+ int *returncode, char *errorbuf, void *arg)
+{
+ Replica *r = NULL;
+ multimaster_mtnode_extension *mtnode_ext;
+ char *replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
+ char buf [BUFSIZ];
+ char *errortext = errorbuf ? errorbuf : buf;
+
+ if (errorbuf)
+ {
+ errorbuf[0] = '\0';
+ }
+
+ *returncode = LDAP_SUCCESS;
+
+ PR_Lock (s_configLock);
+
+ /* add the dn to the dn hash so we can tell this replica is being configured */
+ replica_add_by_dn(replica_root);
+
+ mtnode_ext = _replica_config_get_mtnode_ext (e);
+ PR_ASSERT (mtnode_ext);
+
+ if (mtnode_ext->replica)
+ {
+ sprintf (errortext, "replica already configured for %s", replica_root);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: %s\n", errortext);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ goto done;
+ }
+
+ /* create replica object */
+ r = replica_new_from_entry (e, errortext, PR_TRUE /* is a newly added entry */);
+ if (r == NULL)
+ {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ /* Set the mapping tree node state, and the referrals from the RUV */
+ /* if this server is a 4.0 consumer the referrals are set by legacy plugin */
+ if (!replica_is_legacy_consumer (r))
+ consumer5_set_mapping_tree_state_for_replica(r, NULL);
+
+ /* ONREPL if replica is added as writable we need to execute protocol that
+ introduces new writable replica to the topology */
+
+ mtnode_ext->replica = object_new (r, replica_destroy); /* Refcnt is 1 */
+
+ /* add replica object to the hash */
+ *returncode = replica_add_by_name (replica_get_name (r), mtnode_ext->replica); /* Increments object refcnt */
+ /* delete the dn from the dn hash - done with configuration */
+ replica_delete_by_dn(replica_root);
+
+done:
+
+ PR_Unlock (s_configLock);
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void**)&replica_root);
+
+ if (*returncode != LDAP_SUCCESS)
+ {
+ if (mtnode_ext->replica)
+ object_release (mtnode_ext->replica);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ else
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static int
+replica_config_modify (Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e,
+ int *returncode, char *returntext, void *arg)
+{
+ int rc= 0;
+ LDAPMod **mods;
+ int i, apply_mods;
+ multimaster_mtnode_extension *mtnode_ext;
+ Replica *r = NULL;
+ char *replica_root = NULL;
+ char buf [BUFSIZ];
+ char *errortext = returntext ? returntext : buf;
+ char *config_attr, *config_attr_value;
+ Slapi_Operation *op;
+ void *identity;
+
+ if (returntext)
+ {
+ returntext[0] = '\0';
+ }
+ *returncode = LDAP_SUCCESS;
+
+ /* just let internal operations originated from replication plugin to go through */
+ slapi_pblock_get (pb, SLAPI_OPERATION, &op);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
+
+ if (operation_is_flag_set(op, OP_FLAG_INTERNAL) &&
+ (identity == repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION)))
+ {
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+
+ replica_root = (char*)slapi_entry_attr_get_charptr (e, attr_replicaRoot);
+
+ PR_Lock (s_configLock);
+
+ mtnode_ext = _replica_config_get_mtnode_ext (e);
+ PR_ASSERT (mtnode_ext);
+
+ if (mtnode_ext->replica)
+ object_acquire (mtnode_ext->replica);
+
+ if (mtnode_ext->replica == NULL)
+ {
+ sprintf (errortext, "replica does not exist for %s", replica_root);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
+ errortext);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ r = object_get_data (mtnode_ext->replica);
+ PR_ASSERT (r);
+
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ for (apply_mods = 0; apply_mods <= 1; apply_mods++)
+ {
+ /* we only allow the replica ID and type to be modified together e.g.
+ if converting a read only replica to a master or vice versa -
+ we will need to change both the replica ID and the type at the same
+ time - we must disallow changing the replica ID if the type is not
+ being changed and vice versa
+ */
+ char *new_repl_id = NULL;
+ char *new_repl_type = NULL;
+
+ if (*returncode != LDAP_SUCCESS)
+ break;
+
+ for (i = 0; (mods[i] && (LDAP_SUCCESS == rc)); i++)
+ {
+ if (*returncode != LDAP_SUCCESS)
+ break;
+
+ config_attr = (char *) mods[i]->mod_type;
+ PR_ASSERT (config_attr);
+
+ /* disallow modifications or removal of replica root,
+ replica name and replica state attributes */
+ if (strcasecmp (config_attr, attr_replicaRoot) == 0 ||
+ strcasecmp (config_attr, attr_replicaName) == 0 ||
+ strcasecmp (config_attr, attr_state) == 0)
+ {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ sprintf (errortext, "modification of %s attribute is not allowed",
+ config_attr);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
+ errortext);
+ }
+ /* this is a request to delete an attribute */
+ else if (mods[i]->mod_op & LDAP_MOD_DELETE || mods[i]->mod_bvalues == NULL
+ || mods[i]->mod_bvalues[0]->bv_val == NULL)
+ {
+ /* currently, you can only remove referral,
+ legacy consumer or bind dn attribute */
+ if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
+ {
+ *returncode = replica_config_change_updatedn (r, mods[i], errortext, apply_mods);
+ }
+ else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
+ {
+ if (apply_mods) {
+ replica_set_referrals(r, NULL);
+ if (!replica_is_legacy_consumer (r)) {
+ consumer5_set_mapping_tree_state_for_replica(r, NULL);
+ }
+ }
+ }
+ else if (strcasecmp (config_attr, type_replicaLegacyConsumer) == 0)
+ {
+ if (apply_mods)
+ replica_set_legacy_consumer (r, PR_FALSE);
+ }
+ else
+ {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ sprintf (errortext, "deletion of %s attribute is not allowed", config_attr);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
+ errortext);
+ }
+ }
+ else /* modify an attribute */
+ {
+ config_attr_value = (char *) mods[i]->mod_bvalues[0]->bv_val;
+
+ if (strcasecmp (config_attr, attr_replicaBindDn) == 0)
+ {
+ *returncode = replica_config_change_updatedn (r, mods[i],
+ errortext, apply_mods);
+ }
+ else if (strcasecmp (config_attr, attr_replicaType) == 0)
+ {
+ new_repl_type = slapi_ch_strdup(config_attr_value);
+ }
+ else if (strcasecmp (config_attr, attr_replicaId) == 0)
+ {
+ new_repl_id = slapi_ch_strdup(config_attr_value);
+ }
+ else if (strcasecmp (config_attr, attr_flags) == 0)
+ {
+ *returncode = replica_config_change_flags (r, config_attr_value,
+ errortext, apply_mods);
+ }
+ else if (strcasecmp (config_attr, TASK_ATTR) == 0)
+ {
+ *returncode = replica_execute_task (mtnode_ext->replica, config_attr_value,
+ errortext, apply_mods);
+ }
+ else if (strcasecmp (config_attr, attr_replicaReferral) == 0)
+ {
+ if (apply_mods)
+ {
+ Slapi_Mod smod;
+ Slapi_ValueSet *vs= slapi_valueset_new();
+ slapi_mod_init_byref(&smod,mods[i]);
+ slapi_valueset_set_from_smod(vs, &smod);
+ replica_set_referrals (r, vs);
+ slapi_mod_done(&smod);
+ slapi_valueset_free(vs);
+ if (!replica_is_legacy_consumer (r)) {
+ consumer5_set_mapping_tree_state_for_replica(r, NULL);
+ }
+ }
+ }
+ else if (strcasecmp (config_attr, type_replicaPurgeDelay) == 0)
+ {
+ if (apply_mods && config_attr_value && config_attr_value[0])
+ {
+ PRUint32 delay;
+ if (isdigit (config_attr_value[0]))
+ {
+ delay = (unsigned int)atoi(config_attr_value);
+ replica_set_purge_delay(r, delay);
+ }
+ else
+ *returncode = LDAP_OPERATIONS_ERROR;
+ }
+ }
+ else if (strcasecmp (config_attr, type_replicaTombstonePurgeInterval) == 0)
+ {
+ if (apply_mods && config_attr_value && config_attr_value[0])
+ {
+ long interval;
+ interval = atol (config_attr_value);
+ replica_set_tombstone_reap_interval (r, interval);
+ }
+ }
+ else if (strcasecmp (config_attr, type_replicaLegacyConsumer) == 0)
+ {
+ if (apply_mods)
+ {
+ PRBool legacy = (strcasecmp (config_attr_value, "on") == 0) ||
+ (strcasecmp (config_attr_value, "true") == 0) ||
+ (strcasecmp (config_attr_value, "yes") == 0) ||
+ (strcasecmp (config_attr_value, "1") == 0);
+
+ replica_set_legacy_consumer (r, legacy);
+ }
+ }
+ /* ignore modifiers attributes added by the server */
+ else if (strcasecmp (config_attr, "modifytimestamp") == 0 ||
+ strcasecmp (config_attr, "modifiersname") == 0)
+ {
+ *returncode = LDAP_SUCCESS;
+ }
+ else
+ {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ sprintf (errortext, "modification of attribute %s is not allowed in replica entry", config_attr);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_modify: %s\n",
+ errortext);
+ }
+ }
+ }
+
+ if (new_repl_id || new_repl_type)
+ {
+ *returncode = replica_config_change_type_and_id(r, new_repl_type,
+ new_repl_id, errortext,
+ apply_mods);
+ slapi_ch_free_string(&new_repl_id);
+ slapi_ch_free_string(&new_repl_type);
+ }
+ }
+
+done:
+ if (mtnode_ext->replica)
+ object_release (mtnode_ext->replica);
+
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void**)&replica_root);
+
+ PR_Unlock (s_configLock);
+
+ if (*returncode != LDAP_SUCCESS)
+ {
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ else
+ {
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+}
+
+static int
+replica_config_delete (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter,
+ int *returncode, char *returntext, void *arg)
+{
+ multimaster_mtnode_extension *mtnode_ext;
+ Replica *r;
+
+ PR_Lock (s_configLock);
+
+ mtnode_ext = _replica_config_get_mtnode_ext (e);
+ PR_ASSERT (mtnode_ext);
+
+ if (mtnode_ext->replica)
+ {
+ /* remove object from the hash */
+ r = (Replica*)object_get_data (mtnode_ext->replica);
+ PR_ASSERT (r);
+ replica_delete_by_name (replica_get_name (r));
+ object_release (mtnode_ext->replica);
+ mtnode_ext->replica = NULL;
+ }
+
+ PR_Unlock (s_configLock);
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static int
+replica_config_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode,
+ char *returntext, void *arg)
+{
+ multimaster_mtnode_extension *mtnode_ext;
+ int changeCount = 0;
+ char val [64];
+
+ /* add attribute that contains number of entries in the changelog for this replica */
+
+ PR_Lock (s_configLock);
+
+ /* if we have no changelog - we have no changes */
+ if (cl5GetState () == CL5_STATE_OPEN)
+ {
+ mtnode_ext = _replica_config_get_mtnode_ext (e);
+ PR_ASSERT (mtnode_ext);
+
+ if (mtnode_ext->replica)
+ {
+ object_acquire (mtnode_ext->replica);
+ changeCount = cl5GetOperationCount (mtnode_ext->replica);
+ object_release (mtnode_ext->replica);
+ }
+ }
+
+ sprintf (val, "%d", changeCount);
+ slapi_entry_add_string (e, type_replicaChangeCount, val);
+
+ PR_Unlock (s_configLock);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static int
+replica_config_change_type_and_id (Replica *r, const char *new_type,
+ const char *new_id, char *returntext,
+ int apply_mods)
+{
+ int type;
+ ReplicaType oldtype;
+ ReplicaId rid;
+ ReplicaId oldrid;
+
+ PR_ASSERT (r);
+
+ oldtype = replica_get_type(r);
+ oldrid = replica_get_rid(r);
+ if (new_type == NULL) /* by default - replica is read-only */
+ {
+ type = REPLICA_TYPE_READONLY;
+ }
+ else
+ {
+ type = atoi (new_type);
+ if (type <= REPLICA_TYPE_UNKNOWN || type >= REPLICA_TYPE_END)
+ {
+ sprintf (returntext, "invalid replica type %d", type);
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+
+ /* disallow changing type to itself just to permit a replica ID change */
+ if (oldtype == type)
+ {
+ sprintf (returntext, "replica type is already %d - not changing", type);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (type == REPLICA_TYPE_READONLY)
+ {
+ rid = READ_ONLY_REPLICA_ID; /* default rid for read only */
+ }
+ else if (!new_id)
+ {
+ sprintf(returntext, "a replica ID is required when changing replica type to read-write");
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ else
+ {
+ int temprid = atoi (new_id);
+ if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID)
+ {
+ sprintf(returntext,
+ "attribute %s must have a value greater than 0 "
+ "and less than %d",
+ attr_replicaId, READ_ONLY_REPLICA_ID);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ else
+ {
+ rid = (ReplicaId)temprid;
+ }
+ }
+
+ /* error if old rid == new rid */
+ if (oldrid == rid)
+ {
+ sprintf (returntext, "replica ID is already %d - not changing", rid);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (apply_mods)
+ {
+ replica_set_type (r, type);
+ replica_set_rid(r, rid);
+
+ /* Set the mapping tree node, and the list of referrals */
+ /* if this server is a 4.0 consumer the referrals are set by legacy plugin */
+ if (!replica_is_legacy_consumer(r))
+ consumer5_set_mapping_tree_state_for_replica(r, NULL);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+replica_config_change_updatedn (Replica *r, const LDAPMod *mod, char *returntext,
+ int apply_mods)
+{
+ PR_ASSERT (r);
+
+ if (apply_mods)
+ {
+ Slapi_Mod smod;
+ Slapi_ValueSet *vs= slapi_valueset_new();
+ slapi_mod_init_byref(&smod, (LDAPMod *)mod); /* cast away const */
+ slapi_valueset_set_from_smod(vs, &smod);
+ replica_set_updatedn(r, vs, mod->mod_op);
+ slapi_mod_done(&smod);
+ slapi_valueset_free(vs);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int replica_config_change_flags (Replica *r, const char *new_flags,
+ char *returntext, int apply_mods)
+{
+ PR_ASSERT (r);
+
+ if (apply_mods)
+ {
+ PRUint32 flags;
+
+ flags = atol (new_flags);
+
+ replica_replace_flags (r, flags);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int replica_execute_task (Object *r, const char *task_name, char *returntext,
+ int apply_mods)
+{
+
+ if (strcasecmp (task_name, CL2LDIF_TASK) == 0)
+ {
+ if (apply_mods)
+ {
+ return replica_execute_cl2ldif_task (r, returntext);
+ }
+ else
+ return LDAP_SUCCESS;
+ }
+ else if (strncasecmp (task_name, CLEANRUV, CLEANRUVLEN) == 0)
+ {
+ int temprid = atoi(&(task_name[CLEANRUVLEN]));
+ if (temprid <= 0 || temprid >= READ_ONLY_REPLICA_ID){
+ sprintf(returntext, "Invalid replica id for task - %s", task_name);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "replica_execute_task: %s\n", returntext);
+ return LDAP_OPERATIONS_ERROR;
+ }
+ if (apply_mods)
+ {
+ return replica_execute_cleanruv_task (r, (ReplicaId)temprid, returntext);
+ }
+ else
+ return LDAP_SUCCESS;
+ }
+ else
+ {
+ sprintf (returntext, "unsupported replica task - %s", task_name);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "replica_execute_task: %s\n", returntext);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+}
+
+static int replica_execute_cl2ldif_task (Object *r, char *returntext)
+{
+ int rc;
+ Object *rlist [2];
+ Replica *replica;
+ char fName [MAXPATHLEN];
+ char *clDir;
+
+ if (cl5GetState () != CL5_STATE_OPEN)
+ {
+ sprintf (returntext, "changelog is not open");
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "replica_execute_cl2ldif_task: %s\n", returntext);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ rlist[0] = r;
+ rlist[1] = NULL;
+
+ /* file is stored in the changelog directory and is named
+ <replica name>.ldif */
+ clDir = cl5GetDir ();
+ PR_ASSERT (clDir);
+
+ replica = (Replica*)object_get_data (r);
+ PR_ASSERT (replica);
+
+ sprintf (fName, "%s/%s.ldif", clDir, replica_get_name (replica));
+ slapi_ch_free ((void**)&clDir);
+
+ rc = cl5ExportLDIF (fName, rlist);
+ if (rc != CL5_SUCCESS)
+ {
+ sprintf (returntext, "failed to export changelog data to file %s; "
+ "changelog error - %d", fName, rc);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "replica_execute_cl2ldif_task: %s\n", returntext);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static multimaster_mtnode_extension *
+_replica_config_get_mtnode_ext (const Slapi_Entry *e)
+{
+ const char *replica_root;
+ Slapi_DN *sdn = NULL;
+ mapping_tree_node *mtnode;
+ multimaster_mtnode_extension *ext = NULL;
+ char ebuf[BUFSIZ];
+
+ /* retirve root of the tree for which replica is configured */
+ replica_root = slapi_entry_attr_get_charptr (e, attr_replicaRoot);
+ if (replica_root == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
+ "configuration entry %s missing %s attribute\n",
+ escape_string(slapi_entry_get_dn((Slapi_Entry *)e), ebuf),
+ attr_replicaRoot);
+ return NULL;
+ }
+
+ sdn = slapi_sdn_new_dn_passin (replica_root);
+
+ /* locate mapping tree node for the specified subtree */
+ mtnode = slapi_get_mapping_tree_node_by_dn (sdn);
+ if (mtnode == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_config_add: "
+ "failed to locate mapping tree node for dn %s\n",
+ escape_string(slapi_sdn_get_dn(sdn), ebuf));
+ }
+ else
+ {
+ /* check if replica object already exists for the specified subtree */
+ ext = (multimaster_mtnode_extension *)repl_con_get_ext (REPL_CON_EXT_MTNODE, mtnode);
+ }
+
+ slapi_sdn_free (&sdn);
+
+ return ext;
+}
+
+static int
+replica_execute_cleanruv_task (Object *r, ReplicaId rid, char *returntext)
+{
+ int rc = 0;
+ Object *RUVObj;
+ RUV *local_ruv = NULL;
+ Replica *replica = (Replica*)object_get_data (r);
+
+ PR_ASSERT (replica);
+
+ RUVObj = replica_get_ruv(replica);
+ PR_ASSERT(RUVObj);
+ local_ruv = (RUV*)object_get_data (RUVObj);
+ /* Need to check that :
+ * - rid is not the local one
+ * - rid is not the last one
+ */
+ if ((replica_get_rid(replica) == rid) ||
+ (ruv_replica_count(local_ruv) <= 1)) {
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ rc = ruv_delete_replica(local_ruv, rid);
+ replica_set_ruv_dirty(replica);
+ replica_write_ruv(replica);
+ object_release(RUVObj);
+
+ /* Update Mapping Tree to reflect RUV changes */
+ consumer5_set_mapping_tree_state_for_replica(replica, NULL);
+
+ if (rc != RUV_SUCCESS){
+ return LDAP_OPERATIONS_ERROR;
+ }
+ return LDAP_SUCCESS;
+}
+
+
diff --git a/ldap/servers/plugins/replication/repl5_replica_dnhash.c b/ldap/servers/plugins/replication/repl5_replica_dnhash.c
new file mode 100644
index 00000000..4b9f42b9
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_replica_dnhash.c
@@ -0,0 +1,189 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl5_replica_dnhash.c */
+
+#include "repl5.h"
+#include "plhash.h"
+
+/* global data */
+static PLHashTable *s_hash;
+static PRRWLock *s_lock;
+
+/* Forward declarations */
+static PRIntn replica_destroy_hash_entry (PLHashEntry *he, PRIntn index, void *arg);
+
+int replica_init_dn_hash ()
+{
+ /* allocate table */
+ s_hash = PL_NewHashTable(0, PL_HashString, PL_CompareStrings,
+ PL_CompareValues, NULL, NULL);
+ if (s_hash == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_init_dn_hash: "
+ "failed to allocate hash table; NSPR error - %d\n",
+ PR_GetError ());
+ return -1;
+ }
+
+ /* create lock */
+ s_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "replica_dnhash_lock");
+ if (s_lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_init_dn_hash: "
+ "failed to create lock; NSPR error - %d\n",
+ PR_GetError ());
+ replica_destroy_dn_hash ();
+ return -1;
+ }
+
+ return 0;
+}
+
+void replica_destroy_dn_hash ()
+{
+ /* destroy the content */
+ PL_HashTableEnumerateEntries(s_hash, replica_destroy_hash_entry, NULL);
+
+ if (s_hash)
+ PL_HashTableDestroy(s_hash);
+
+ if (s_lock)
+ PR_DestroyRWLock (s_lock);
+}
+
+int replica_add_by_dn (const char *dn)
+{
+ char *dn_copy = NULL;
+
+ if (dn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_add_by_dn: NULL argument\n");
+ return -1;
+ }
+
+ if (s_hash == NULL || s_lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_add_by_dn: "
+ "replica hash is not initialized\n");
+ return -1;
+ }
+
+ PR_RWLock_Wlock (s_lock);
+
+ /* make sure that the dn is unique */
+ if (PL_HashTableLookup(s_hash, dn) != NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_add_by_dn: "
+ "replica with dn (%s) already in the hash\n", dn);
+ PR_RWLock_Unlock (s_lock);
+ return -1 ;
+ }
+
+ /* add dn */
+ dn_copy = slapi_ch_strdup(dn);
+ if (PL_HashTableAdd(s_hash, dn_copy, dn_copy) == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_add_by_dn: "
+ "failed to add dn (%s); NSPR error - %d\n",
+ dn_copy, PR_GetError ());
+ slapi_ch_free((void **)&dn_copy);
+ PR_RWLock_Unlock (s_lock);
+ return -1;
+ }
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_add_by_dn: "
+ "added dn (%s)\n",
+ dn_copy);
+ PR_RWLock_Unlock (s_lock);
+ return 0;
+}
+
+int replica_delete_by_dn (const char *dn)
+{
+ char *dn_copy = NULL;
+
+ if (dn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_delete_by_dn: "
+ "NULL argument\n");
+ return -1;
+ }
+
+ if (s_hash == NULL || s_lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_delete_by_dn: "
+ "replica hash is not initialized\n");
+ return -1;
+ }
+
+ PR_RWLock_Wlock (s_lock);
+
+ /* locate object */
+ if (NULL == (dn_copy = (char *)PL_HashTableLookup(s_hash, dn)))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_delete_by_dn: "
+ "dn (%s) is not in the hash.\n", dn);
+ PR_RWLock_Unlock (s_lock);
+ return -1;
+ }
+
+ /* remove from hash */
+ PL_HashTableRemove(s_hash, dn);
+ slapi_ch_free((void **)&dn_copy);
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_delete_by_dn: "
+ "removed dn (%s)\n",
+ dn);
+ PR_RWLock_Unlock (s_lock);
+
+ return 0;
+}
+
+int replica_is_being_configured (const char *dn)
+{
+ if (dn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_is_dn_in_hash: "
+ "NULL argument\n");
+ return 0;
+ }
+
+ if (s_hash == NULL || s_lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_is_dn_in_hash: "
+ "dn hash is not initialized\n");
+ return 0;
+ }
+
+ PR_RWLock_Wlock (s_lock);
+
+ /* locate object */
+ if (NULL == PL_HashTableLookup(s_hash, dn))
+ {
+ PR_RWLock_Unlock (s_lock);
+ return 0;
+ }
+
+ PR_RWLock_Unlock (s_lock);
+
+ return 1;
+}
+
+/* Helper functions */
+
+/* this function called for each hash node during hash destruction */
+static PRIntn replica_destroy_hash_entry (PLHashEntry *he, PRIntn index, void *arg)
+{
+ char *dn_copy;
+
+ if (he == NULL)
+ return HT_ENUMERATE_NEXT;
+
+ dn_copy = (char*)he->value;
+ slapi_ch_free((void **)&dn_copy);
+
+ return HT_ENUMERATE_REMOVE;
+}
diff --git a/ldap/servers/plugins/replication/repl5_replica_hash.c b/ldap/servers/plugins/replication/repl5_replica_hash.c
new file mode 100644
index 00000000..92ea87f4
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_replica_hash.c
@@ -0,0 +1,243 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_replica_hash.c */
+
+#include "repl5.h"
+#include "plhash.h"
+
+/* global data */
+static PLHashTable *s_hash;
+static PRRWLock *s_lock;
+
+struct repl_enum_data
+{
+ FNEnumReplica fn;
+ void *arg;
+};
+
+/* Forward declarations */
+static PRIntn replica_destroy_hash_entry (PLHashEntry *he, PRIntn index, void *arg);
+static PRIntn replica_enumerate (PLHashEntry *he, PRIntn index, void *hash_data);
+
+
+int replica_init_name_hash ()
+{
+ /* allocate table */
+ s_hash = PL_NewHashTable(0, PL_HashString, PL_CompareStrings,
+ PL_CompareValues, NULL, NULL);
+ if (s_hash == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_init_name_hash: "
+ "failed to allocate hash table; NSPR error - %d\n",
+ PR_GetError ());
+ return -1;
+ }
+
+ /* create lock */
+ s_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "replica_hash_lock");
+ if (s_lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_init_name_hash: "
+ "failed to create lock; NSPR error - %d\n",
+ PR_GetError ());
+ replica_destroy_name_hash ();
+ return -1;
+ }
+
+ return 0;
+}
+
+void replica_destroy_name_hash ()
+{
+ /* destroy the content */
+ PL_HashTableEnumerateEntries(s_hash, replica_destroy_hash_entry, NULL);
+
+ if (s_hash)
+ PL_HashTableDestroy(s_hash);
+
+ if (s_lock)
+ PR_DestroyRWLock (s_lock);
+}
+
+int replica_add_by_name (const char *name, Object *replica)
+{
+ if (name == NULL || replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_add_by_name: NULL argument\n");
+ return -1;
+ }
+
+ if (s_hash == NULL || s_lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_add_by_name: "
+ "replica hash is not initialized\n");
+ return -1;
+ }
+
+ PR_RWLock_Wlock (s_lock);
+
+ /* make sure that the name is unique */
+ if (PL_HashTableLookup(s_hash, name) != NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_add_by_name: "
+ "replica with name (%s) already in the hash\n", name);
+ PR_RWLock_Unlock (s_lock);
+ return -1 ;
+ }
+
+ /* acquire replica object */
+ object_acquire (replica);
+
+ /* add replica */
+ if (PL_HashTableAdd(s_hash, name, replica) == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_add_by_name: "
+ "failed to add replica with name (%s); NSPR error - %d\n",
+ name, PR_GetError ());
+ object_release (replica);
+ PR_RWLock_Unlock (s_lock);
+ return -1;
+ }
+
+ PR_RWLock_Unlock (s_lock);
+ return 0;
+}
+
+int replica_delete_by_name (const char *name)
+{
+ Object *replica;
+
+ if (name == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_delete_by_name: "
+ "NULL argument\n");
+ return -1;
+ }
+
+ if (s_hash == NULL || s_lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_delete_by_name: "
+ "replica hash is not initialized\n");
+ return -1;
+ }
+
+ PR_RWLock_Wlock (s_lock);
+
+ /* locate object */
+ replica = (Object*)PL_HashTableLookup(s_hash, name);
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_delete_by_name: "
+ "replica with name (%s) is not in the hash.\n", name);
+ PR_RWLock_Unlock (s_lock);
+ return -1;
+ }
+
+ /* remove from hash */
+ PL_HashTableRemove(s_hash, name);
+
+ /* release replica */
+ object_release (replica);
+
+ PR_RWLock_Unlock (s_lock);
+
+ return 0;
+}
+
+Object* replica_get_by_name (const char *name)
+{
+ Object *replica;
+
+ if (name == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_get_by_name: "
+ "NULL argument\n");
+ return NULL;
+ }
+
+ if (s_hash == NULL || s_lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_get_by_name: "
+ "replica hash is not initialized\n");
+ return NULL;
+ }
+
+ PR_RWLock_Rlock (s_lock);
+
+ /* locate object */
+ replica = (Object*)PL_HashTableLookup(s_hash, name);
+ if (replica == NULL)
+ {
+ PR_RWLock_Unlock (s_lock);
+ return NULL;
+ }
+
+ object_acquire (replica);
+
+ PR_RWLock_Unlock (s_lock);
+
+ return replica;
+}
+
+void replica_enumerate_replicas (FNEnumReplica fn, void *arg)
+{
+ struct repl_enum_data data;
+
+ PR_ASSERT (fn);
+
+ data.fn = fn;
+ data.arg = arg;
+
+ PR_RWLock_Wlock (s_lock);
+ PL_HashTableEnumerateEntries(s_hash, replica_enumerate, &data);
+ PR_RWLock_Unlock (s_lock);
+}
+
+/* Helper functions */
+
+/* this function called for each hash node during hash destruction */
+static PRIntn replica_destroy_hash_entry (PLHashEntry *he, PRIntn index, void *arg)
+{
+ Object *r_obj;
+ Replica *r;
+
+ if (he == NULL)
+ return HT_ENUMERATE_NEXT;
+
+ r_obj = (Object*)he->value;
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r);
+
+ /* flash replica state to the disk */
+ replica_flush (r);
+
+ /* release replica object */
+ object_release (r_obj);
+
+ return HT_ENUMERATE_REMOVE;
+}
+
+static PRIntn replica_enumerate (PLHashEntry *he, PRIntn index, void *hash_data)
+{
+ Object *r_obj;
+ Replica *r;
+ struct repl_enum_data *data = hash_data;
+
+ r_obj = (Object*)he->value;
+ PR_ASSERT (r_obj);
+
+ object_acquire (r_obj);
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r);
+
+ data->fn (r, data->arg);
+
+ object_release (r_obj);
+
+ return HT_ENUMERATE_NEXT;
+}
+
diff --git a/ldap/servers/plugins/replication/repl5_replsupplier.c b/ldap/servers/plugins/replication/repl5_replsupplier.c
new file mode 100644
index 00000000..e98d0e58
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_replsupplier.c
@@ -0,0 +1,166 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl5_replsupplier.c */
+/*
+
+A replsupplier is an object that knows how to manage outbound replication
+for one consumer.
+
+Methods:
+init()
+configure()
+start()
+stop()
+destroy()
+status()
+notify()
+
+*/
+
+#include "slapi-plugin.h"
+#include "repl5.h"
+
+typedef struct repl_supplier {
+ PRUint32 client_change_count; /* # of client-supplied changes */
+ PRUint32 repl_change_count; /* # of replication updates */
+
+ PRLock *lock;
+
+} repl_supplier;
+
+
+static void repl_supplier_free(Repl_Supplier **rsp);
+
+/*
+ * Create and initialize this replsupplier object.
+ */
+Repl_Supplier *
+replsupplier_init(Slapi_Entry *e)
+{
+ Repl_Supplier *rs;
+
+ if ((rs = (Repl_Supplier *)slapi_ch_malloc(sizeof(Repl_Supplier))) == NULL)
+ {
+ goto loser;
+ }
+ if ((rs->lock = PR_NewLock()) == NULL)
+ {
+ goto loser;
+ }
+ return rs;
+
+loser:
+ repl_supplier_free(&rs);
+ return NULL;
+}
+
+
+
+static void
+repl_supplier_free(Repl_Supplier **rsp)
+{
+ if (NULL != rsp)
+ {
+ Repl_Supplier *rs = *rsp;
+ if (NULL != rs)
+ {
+ if (NULL != rs->lock)
+ {
+ PR_DestroyLock(rs->lock);
+ rs->lock = NULL;
+ }
+ slapi_ch_free((void **)rsp);
+ }
+ }
+}
+
+
+
+/*
+ * Configure a repl_supplier object.
+ */
+void
+replsupplier_configure(Repl_Supplier *rs, Slapi_PBlock *pb)
+{
+ PR_ASSERT(NULL != rs);
+
+}
+
+
+
+/*
+ * Start a repl_supplier object. This means that it's ok for
+ * the repl_supplier to begin normal replication duties. It does
+ * not necessarily mean that a replication session will occur
+ * immediately.
+ */
+void
+replsupplier_start(Repl_Supplier *rs)
+{
+ PR_ASSERT(NULL != rs);
+}
+
+
+
+
+/*
+ * Stop a repl_supplier object. This causes any active replication
+ * sessions to be stopped ASAP, and puts the repl_supplier into a
+ * stopped state. No additional replication activity will occur
+ * until the replsupplier_start() function is called.
+ */
+void
+replsupplier_stop(Repl_Supplier *rs)
+{
+ PR_ASSERT(NULL != rs);
+}
+
+
+
+
+/*
+ * Destroy a repl_supplier object. The object will be stopped, if it
+ * is not already stopped.
+ */
+void
+replsupplier_destroy(Repl_Supplier **rsp)
+{
+ Repl_Supplier *rs;
+
+ PR_ASSERT(NULL != rsp && NULL != *rsp);
+
+ rs = *rsp;
+
+ slapi_ch_free((void **)rsp);
+}
+
+
+
+/*
+ * This method should be called by the repl_bos whenever it determines
+ * that a change to the replicated area serviced by this repl_supplier
+ * has occurred. This gives the repl_supplier a chance to implement a
+ * scheduling policy.
+ */
+void
+replsupplier_notify(Repl_Supplier *rs, PRUint32 eventmask)
+{
+ PR_ASSERT(NULL != rs);
+}
+
+
+
+/*
+ * This method is used to obtain the status of this particular
+ * repl_supplier object. Eventually it will return some object containing
+ * status information. For now, it's just a placeholder function.
+ */
+PRUint32
+replsupplier_get_status(Repl_Supplier *rs)
+{
+ PR_ASSERT(NULL != rs);
+ return 0;
+}
diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c
new file mode 100644
index 00000000..b8cb79c9
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_ruv.c
@@ -0,0 +1,2022 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_ruv.c - implementation of replica update vector */
+/*
+ * The replica update vector is stored in the nsds50ruv attribute. The LDIF
+ * representation of the ruv is:
+ * nsds50ruv: {replicageneration} <gen-id-for-this-replica>
+ * nsds50ruv: {replica <rid>[ <url>]}[ <mincsn> <maxcsn>]
+ * nsds50ruv: {replica <rid>[ <url>]}[ <mincsn> <maxcsn>]
+ * ...
+ * nsds50ruv: {replica <rid>[ <url>]}[ <mincsn> <maxcsn>]
+ *
+ * nsruvReplicaLastModified: {replica <rid>[ <url>]} lastModifiedTime
+ * nsruvReplicaLastModified: {replica <rid>[ <url>]} lastModifiedTime
+ * ...
+ *
+ * For readability, ruv_dump appends nsruvReplicaLastModified to nsds50ruv:
+ * nsds50ruv: {replica <rid>[ <url>]}[ <mincsn> <maxcsn> [<lastModifiedTime>]]
+ */
+
+#include <string.h>
+#include <ctype.h> /* For isdigit() */
+#include "csnpl.h"
+#include "repl5_ruv.h"
+#include "repl_shared.h"
+#include "repl5.h"
+
+#define RIDSTR_SIZE 16 /* string large enough to hold replicaid*/
+#define RUVSTR_SIZE 256 /* string large enough to hold ruv and lastmodifiedtime */
+
+/* Data Structures */
+
+/* replica */
+typedef struct ruvElement
+{
+ ReplicaId rid; /* replica id for this element */
+ CSN *csn; /* largest csn that we know about that originated at the master */
+ CSN *min_csn; /* smallest csn that originated at the master */
+ char *replica_purl; /* Partial URL for replica */
+ CSNPL *csnpl; /* list of operations in progress */
+ time_t last_modified; /* timestamp the modification of csn */
+} RUVElement;
+
+/* replica update vector */
+struct _ruv
+{
+ char *replGen; /* replicated area generation: identifies replica
+ in space and in time */
+ DataList *elements; /* replicas */
+ PRRWLock *lock; /* concurrency control */
+};
+
+/* forward declarations */
+static int ruvInit (RUV **ruv, int initCount);
+static void ruvFreeReplica (void **data);
+static RUVElement* ruvGetReplica (const RUV *ruv, ReplicaId rid);
+static RUVElement* ruvAddReplica (RUV *ruv, const CSN *csn, const char *replica_purl);
+static RUVElement* ruvAddReplicaNoCSN (RUV *ruv, ReplicaId rid, const char *replica_purl);
+static RUVElement* ruvAddIndexReplicaNoCSN (RUV *ruv, ReplicaId rid, const char *replica_purl, int index);
+static int ruvReplicaCompare (const void *el1, const void *el2);
+static RUVElement *get_ruvelement_from_berval(const struct berval *bval);
+static char *get_replgen_from_berval(const struct berval *bval);
+
+static const char * const prefix_replicageneration = "{replicageneration}";
+static const char * const prefix_ruvcsn = "{replica "; /* intentionally missing '}' */
+
+
+/* API implementation */
+
+
+/*
+ * Allocate a new ruv and set its replica generation to the given generation.
+ */
+int
+ruv_init_new(const char *replGen, ReplicaId rid, const char *purl, RUV **ruv)
+{
+ int rc;
+ RUVElement *replica;
+
+ if (ruv == NULL || replGen == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_init_new: NULL argument\n");
+ return RUV_BAD_DATA;
+ }
+
+ rc = ruvInit (ruv, 0);
+ if (rc != RUV_SUCCESS)
+ return rc;
+
+ (*ruv)->replGen = slapi_ch_strdup (replGen);
+
+ /* we want to add the local writable replica to the RUV before any csns are created */
+ /* this is so that it can be referred to even before it accepted any changes */
+ if (purl)
+ {
+ replica = ruvAddReplicaNoCSN (*ruv, rid, purl);
+
+ if (replica == NULL)
+ return RUV_MEMORY_ERROR;
+ }
+
+ return RUV_SUCCESS;
+}
+
+
+/*
+ * Create a new RUV and initialize its contents from the provided Slapi_Attr.
+ * Returns:
+ * RUV_BAD_DATA if the values in the attribute were malformed.
+ * RUV_SUCCESS if all went well
+ */
+int
+ruv_init_from_slapi_attr(Slapi_Attr *attr, RUV **ruv)
+{
+ ReplicaId dummy = 0;
+
+ return (ruv_init_from_slapi_attr_and_check_purl(attr, ruv, &dummy));
+}
+
+/*
+ * Create a new RUV and initialize its contents from the provided Slapi_Attr.
+ * Returns:
+ * RUV_BAD_DATA if the values in the attribute were malformed.
+ * RUV_SUCCESS if all went well
+ * contain_purl is 0 if the ruv doesn't contain the local purl
+ * contain_purl is != 0 if the ruv contains the local purl (contains the rid)
+ */
+int
+ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *contain_purl)
+{
+ int return_value;
+
+ PR_ASSERT(NULL != attr && NULL != ruv);
+
+ if (NULL == ruv || NULL == attr)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_init_from_slapi_attr: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ int rc;
+ int numvalues;
+ slapi_attr_get_numvalues(attr, &numvalues);
+ if ((rc = ruvInit(ruv, numvalues)) != RUV_SUCCESS)
+ {
+ return_value = rc;
+ }
+ else
+ {
+ int hint;
+ Slapi_Value *value;
+ const struct berval *bval;
+ const char *purl = NULL;
+
+ return_value = RUV_SUCCESS;
+
+ purl = multimaster_get_local_purl();
+ *contain_purl = 0;
+
+ for (hint = slapi_attr_first_value(attr, &value);
+ hint != -1; hint = slapi_attr_next_value(attr, hint, &value))
+ {
+ bval = slapi_value_get_berval(value);
+ if (NULL != bval && NULL != bval->bv_val)
+ {
+ if (strncmp(bval->bv_val, prefix_replicageneration, strlen(prefix_replicageneration)) == 0) {
+ if (NULL == (*ruv)->replGen)
+ {
+ (*ruv)->replGen = get_replgen_from_berval(bval);
+ } else {
+ /* Twice replicageneration is wrong, just log and ignore */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_init_from_slapi_attr: %s is present more than once\n",
+ prefix_replicageneration);
+ }
+ }
+ else
+ {
+ RUVElement *ruve = get_ruvelement_from_berval(bval);
+ if (NULL != ruve)
+ {
+ /* Is the local purl already in the ruv ? */
+ if ( (*contain_purl==0) && (strncmp(ruve->replica_purl, purl, strlen(purl))==0) )
+ {
+ *contain_purl = ruve->rid;
+ }
+ dl_add ((*ruv)->elements, ruve);
+ }
+ }
+ }
+ }
+ }
+ }
+ return return_value;
+}
+
+
+
+/*
+ * Same as ruv_init_from_slapi_attr, but takes an array of pointers to bervals.
+ * I wish this wasn't a cut-n-paste of the above function, but I don't see a
+ * clean way to define one API in terms of the other.
+ */
+int
+ruv_init_from_bervals(struct berval **vals, RUV **ruv)
+{
+ int return_value;
+
+ PR_ASSERT(NULL != vals && NULL != ruv);
+
+ if (NULL == ruv || NULL == vals)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_init_from_slapi_value: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ int i, rc;
+ i = 0;
+ while (vals[i] != NULL)
+ {
+ i++;
+ }
+ if ((rc = ruvInit (ruv, i)) != RUV_SUCCESS)
+ {
+ return_value = rc;
+ }
+ else
+ {
+ return_value = RUV_SUCCESS;
+ for (i = 0; NULL != vals[i]; i++)
+ {
+ if (NULL != vals[i]->bv_val)
+ {
+ if (strncmp(vals[i]->bv_val, prefix_replicageneration, strlen(prefix_replicageneration)) == 0) {
+ if (NULL == (*ruv)->replGen)
+ {
+ (*ruv)->replGen = get_replgen_from_berval(vals[i]);
+ } else {
+ /* Twice replicageneration is wrong, just log and ignore */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_init_from_slapi_value: %s is present more than once\n",
+ prefix_replicageneration);
+ }
+ }
+ else
+ {
+ RUVElement *ruve = get_ruvelement_from_berval(vals[i]);
+ if (NULL != ruve)
+ {
+ dl_add ((*ruv)->elements, ruve);
+ }
+ }
+ }
+ }
+ }
+ }
+ return return_value;
+}
+
+
+
+RUV*
+ruv_dup (const RUV *ruv)
+{
+ int rc;
+ RUVElement *replica, *dupReplica;
+ int cookie;
+ RUV *dupRUV = NULL;
+
+ if (ruv == NULL)
+ return NULL;
+
+ PR_RWLock_Rlock (ruv->lock);
+
+ rc = ruvInit (&dupRUV, dl_get_count (ruv->elements));
+ if (rc != RUV_SUCCESS || dupRUV == NULL)
+ goto done;
+
+ dupRUV->replGen = slapi_ch_strdup (ruv->replGen);
+
+ for (replica = dl_get_first (ruv->elements, &cookie); replica;
+ replica = dl_get_next (ruv->elements, &cookie))
+ {
+ dupReplica = (RUVElement *)slapi_ch_calloc (1, sizeof (*dupReplica));
+ dupReplica->rid = replica->rid;
+ if (replica->csn)
+ dupReplica->csn = csn_dup (replica->csn);
+ if (replica->min_csn)
+ dupReplica->min_csn = csn_dup (replica->min_csn);
+ if (replica->replica_purl)
+ dupReplica->replica_purl = slapi_ch_strdup (replica->replica_purl);
+ dupReplica->last_modified = replica->last_modified;
+
+ /* ONREPL - we don't make copy of the pernding list. For now
+ we don't need it. */
+
+ dl_add (dupRUV->elements, dupReplica);
+ }
+
+done:
+ PR_RWLock_Unlock (ruv->lock);
+
+ return dupRUV;
+}
+
+void
+ruv_destroy (RUV **ruv)
+{
+ if (ruv != NULL && *ruv != NULL)
+ {
+ if ((*ruv)->elements)
+ {
+ dl_cleanup ((*ruv)->elements, ruvFreeReplica);
+ dl_free (&(*ruv)->elements);
+ }
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void **)&((*ruv)->replGen));
+
+ if ((*ruv)->lock)
+ {
+ PR_DestroyRWLock ((*ruv)->lock);
+ }
+
+ slapi_ch_free ((void**)ruv);
+ }
+}
+
+/*
+ * [610948]
+ * copy elements in srcruv to destruv
+ * destruv is the live wrapper, which could be referred by other threads.
+ * srcruv is cleaned up after copied.
+ */
+void
+ruv_copy_and_destroy (RUV **srcruv, RUV **destruv)
+{
+ DataList *elemp = NULL;
+ char *replgp = NULL;
+
+ if (NULL == srcruv || NULL == *srcruv || NULL == destruv)
+ {
+ return;
+ }
+
+ if (NULL == *destruv)
+ {
+ *destruv = *srcruv;
+ *srcruv = NULL;
+ }
+ else
+ {
+ PR_RWLock_Wlock((*destruv)->lock);
+ elemp = (*destruv)->elements;
+ (*destruv)->elements = (*srcruv)->elements;
+ if (elemp)
+ {
+ dl_cleanup (elemp, ruvFreeReplica);
+ dl_free (&elemp);
+ }
+
+ /* slapi_ch_free accepts NULL pointer */
+ replgp = (*destruv)->replGen;
+ (*destruv)->replGen = (*srcruv)->replGen;
+ slapi_ch_free ((void **)&replgp);
+
+ if ((*srcruv)->lock)
+ {
+ PR_DestroyRWLock ((*srcruv)->lock);
+ }
+ slapi_ch_free ((void**)srcruv);
+
+ PR_RWLock_Unlock((*destruv)->lock);
+ }
+ PR_ASSERT (*destruv != NULL && *srcruv == NULL);
+}
+
+int
+ruv_delete_replica (RUV *ruv, ReplicaId rid)
+{
+ int return_value;
+ if (ruv == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_delete_replica: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ /* check for duplicates */
+ PR_RWLock_Wlock (ruv->lock);
+ dl_delete (ruv->elements, (const void*)&rid, ruvReplicaCompare, ruvFreeReplica);
+ PR_RWLock_Unlock (ruv->lock);
+ return_value = RUV_SUCCESS;
+ }
+ return return_value;
+}
+
+int
+ruv_add_replica (RUV *ruv, ReplicaId rid, const char *replica_purl)
+{
+ RUVElement* replica;
+
+ PR_ASSERT (ruv && replica_purl);
+
+ PR_RWLock_Wlock (ruv->lock);
+ replica = ruvGetReplica (ruv, rid);
+ if (replica == NULL)
+ {
+ replica = ruvAddReplicaNoCSN (ruv, rid, replica_purl);
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+
+ if (replica)
+ return RUV_SUCCESS;
+ else
+ return RUV_MEMORY_ERROR;
+}
+
+int
+ruv_replace_replica_purl (RUV *ruv, ReplicaId rid, const char *replica_purl)
+{
+ RUVElement* replica;
+ int rc = RUV_NOTFOUND;
+
+ PR_ASSERT (ruv && replica_purl);
+
+ PR_RWLock_Wlock (ruv->lock);
+ replica = ruvGetReplica (ruv, rid);
+ if (replica != NULL)
+ {
+ slapi_ch_free((void **)&(replica->replica_purl));
+ replica->replica_purl = slapi_ch_strdup(replica_purl);
+ rc = RUV_SUCCESS;
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+ return rc;
+}
+
+int
+ruv_add_index_replica (RUV *ruv, ReplicaId rid, const char *replica_purl, int index)
+{
+ RUVElement* replica;
+
+ PR_ASSERT (ruv && replica_purl);
+
+ PR_RWLock_Wlock (ruv->lock);
+ replica = ruvGetReplica (ruv, rid);
+ if (replica == NULL)
+ {
+ replica = ruvAddIndexReplicaNoCSN (ruv, rid, replica_purl, index);
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+
+ if (replica)
+ return RUV_SUCCESS;
+ else
+ return RUV_MEMORY_ERROR;
+}
+
+
+PRBool
+ruv_contains_replica (const RUV *ruv, ReplicaId rid)
+{
+ RUVElement *replica;
+
+ if (ruv == NULL)
+ return PR_FALSE;
+
+ PR_RWLock_Rlock (ruv->lock);
+ replica = ruvGetReplica (ruv, rid);
+ PR_RWLock_Unlock (ruv->lock);
+
+ return replica != NULL;
+}
+
+
+
+
+#define GET_LARGEST_CSN 231
+#define GET_SMALLEST_CSN 232
+static int
+get_csn_internal(const RUV *ruv, ReplicaId rid, CSN **csn, int whichone)
+{
+ RUVElement *replica;
+ int return_value = RUV_SUCCESS;
+
+ if (ruv == NULL || csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_get_largest_csn_for_replica: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ *csn = NULL;
+ /* prevent element from being destroyed while we get its data */
+ PR_RWLock_Rlock (ruv->lock);
+
+ replica = ruvGetReplica (ruv, rid);
+ /* replica without min csn is treated as a non-existent replica */
+ if (replica == NULL || replica->min_csn == NULL)
+ {
+ return_value = RUV_NOTFOUND;
+ }
+ else
+ {
+ switch (whichone)
+ {
+ case GET_LARGEST_CSN:
+ *csn = replica->csn ? csn_dup (replica->csn) : NULL;
+ break;
+ case GET_SMALLEST_CSN:
+ *csn = replica->min_csn ? csn_dup (replica->min_csn) : NULL;
+ break;
+ default:
+ *csn = NULL;
+ }
+ }
+ PR_RWLock_Unlock (ruv->lock);
+ }
+ return return_value;
+}
+
+
+int
+ruv_get_largest_csn_for_replica(const RUV *ruv, ReplicaId rid, CSN **csn)
+{
+ return get_csn_internal(ruv, rid, csn, GET_LARGEST_CSN);
+}
+
+int
+ruv_get_smallest_csn_for_replica(const RUV *ruv, ReplicaId rid, CSN **csn)
+{
+ return get_csn_internal(ruv, rid, csn, GET_SMALLEST_CSN);
+}
+
+const char *
+ruv_get_purl_for_replica(const RUV *ruv, ReplicaId rid)
+{
+ RUVElement *replica;
+ const char *return_value = NULL;
+
+ PR_RWLock_Rlock (ruv->lock);
+
+ replica = ruvGetReplica (ruv, rid);
+ if (replica != NULL)
+ {
+ return_value = replica->replica_purl;
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+
+ return return_value;
+}
+
+
+static int
+set_min_csn_nolock(RUV *ruv, const CSN *min_csn, const char *replica_purl)
+{
+ int return_value;
+ ReplicaId rid = csn_get_replicaid (min_csn);
+ RUVElement *replica = ruvGetReplica (ruv, rid);
+ if (NULL == replica)
+ {
+ replica = ruvAddReplica (ruv, min_csn, replica_purl);
+ if (replica)
+ return_value = RUV_SUCCESS;
+ else
+ return_value = RUV_MEMORY_ERROR;
+ }
+ else
+ {
+ if (replica->min_csn == NULL || csn_compare (min_csn, replica->min_csn) < 0)
+ {
+ csn_free(&replica->min_csn);
+ replica->min_csn = csn_dup(min_csn);
+ }
+
+ return_value = RUV_SUCCESS;
+ }
+
+ return return_value;
+}
+
+static int
+set_max_csn_nolock(RUV *ruv, const CSN *max_csn, const char *replica_purl)
+{
+ int return_value;
+ ReplicaId rid = csn_get_replicaid (max_csn);
+ RUVElement *replica = ruvGetReplica (ruv, rid);
+ if (NULL == replica)
+ {
+ replica = ruvAddReplica (ruv, max_csn, replica_purl);
+ if (replica)
+ return_value = RUV_SUCCESS;
+ else
+ return_value = RUV_MEMORY_ERROR;
+ }
+ else
+ {
+ if (replica_purl && replica->replica_purl == NULL)
+ replica->replica_purl = slapi_ch_strdup (replica_purl);
+ csn_free(&replica->csn);
+ replica->csn = csn_dup(max_csn);
+ replica->last_modified = current_time();
+ return_value = RUV_SUCCESS;
+ }
+ return return_value;
+}
+
+int
+ruv_set_min_csn(RUV *ruv, const CSN *min_csn, const char *replica_purl)
+{
+ int return_value;
+ PR_RWLock_Wlock (ruv->lock);
+ return_value = set_min_csn_nolock(ruv, min_csn, replica_purl);
+ PR_RWLock_Unlock (ruv->lock);
+ return return_value;
+}
+
+
+int
+ruv_set_max_csn(RUV *ruv, const CSN *max_csn, const char *replica_purl)
+{
+ int return_value;
+ PR_RWLock_Wlock (ruv->lock);
+ return_value = set_max_csn_nolock(ruv, max_csn, replica_purl);
+ PR_RWLock_Unlock (ruv->lock);
+ return return_value;
+}
+
+int
+ruv_set_csns(RUV *ruv, const CSN *csn, const char *replica_purl)
+{
+ RUVElement *replica;
+ ReplicaId rid;
+ int return_value;
+
+ if (ruv == NULL || csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_set_csns: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ rid = csn_get_replicaid (csn);
+
+ /* prevent element from being destroyed while we get its data */
+ PR_RWLock_Wlock (ruv->lock);
+
+ replica = ruvGetReplica (ruv, rid);
+ if (replica == NULL) /* add new replica */
+ {
+ replica = ruvAddReplica (ruv, csn, replica_purl);
+ if (replica)
+ return_value = RUV_SUCCESS;
+ else
+ return_value = RUV_MEMORY_ERROR;
+ }
+ else
+ {
+ if (csn_compare (csn, replica->csn) > 0)
+ {
+ if (replica->csn != NULL)
+ {
+ csn_init_by_csn ( replica->csn, csn );
+ }
+ else
+ {
+ replica->csn = csn_dup(csn);
+ }
+ replica->last_modified = current_time();
+ if (replica_purl && (NULL == replica->replica_purl ||
+ strcmp(replica->replica_purl, replica_purl) != 0))
+ {
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free((void **)&replica->replica_purl);
+
+ replica->replica_purl = slapi_ch_strdup(replica_purl);
+ }
+ }
+ /* XXXggood only need to worry about this if real min csn not committed to changelog yet */
+ if (csn_compare (csn, replica->min_csn) < 0)
+ {
+ csn_free(&replica->min_csn);
+ replica->min_csn = csn_dup(csn);
+ }
+ return_value = RUV_SUCCESS;
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+ }
+ return return_value;
+}
+
+/* This function, for each replica keeps the smallest CSN its seen so far.
+ Used for initial setup of changelog purge vector */
+
+int
+ruv_set_csns_keep_smallest(RUV *ruv, const CSN *csn)
+{
+ RUVElement *replica;
+ ReplicaId rid;
+ int return_value;
+
+ if (ruv == NULL || csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_set_csns_keep_smallest: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ rid = csn_get_replicaid (csn);
+
+ /* prevent element from being destroyed while we get its data */
+ PR_RWLock_Wlock (ruv->lock);
+
+ replica = ruvGetReplica (ruv, rid);
+ if (replica == NULL) /* add new replica */
+ {
+ replica = ruvAddReplica (ruv, csn, NULL);
+ if (replica)
+ return_value = RUV_SUCCESS;
+ else
+ return_value = RUV_MEMORY_ERROR;
+ }
+ else
+ {
+ if (csn_compare (csn, replica->csn) < 0)
+ {
+ csn_free(&replica->csn);
+ replica->csn = csn_dup(csn);
+ replica->last_modified = current_time();
+ }
+
+ return_value = RUV_SUCCESS;
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+ }
+ return return_value;
+}
+
+
+void
+ruv_set_replica_generation(RUV *ruv, const char *csnstr)
+{
+ if (NULL != csnstr && NULL != ruv)
+ {
+ PR_RWLock_Wlock (ruv->lock);
+
+ if (NULL != ruv->replGen)
+ {
+ slapi_ch_free((void **)&ruv->replGen);
+ }
+ ruv->replGen = slapi_ch_strdup(csnstr);
+
+ PR_RWLock_Unlock (ruv->lock);
+ }
+}
+
+
+char *
+ruv_get_replica_generation(const RUV *ruv)
+{
+ char *return_str = NULL;
+
+ PR_RWLock_Rlock (ruv->lock);
+
+ if (ruv != NULL && ruv->replGen != NULL)
+ {
+ return_str = slapi_ch_strdup(ruv->replGen);
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+
+ return return_str;
+}
+
+static PRBool
+ruv_covers_csn_internal(const RUV *ruv, const CSN *csn, PRBool strict)
+{
+ RUVElement *replica;
+ ReplicaId rid;
+ PRBool return_value;
+
+ if (ruv == NULL || csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_covers_csn: NULL argument\n");
+ return_value = PR_FALSE;
+ }
+ else
+ {
+ rid = csn_get_replicaid(csn);
+ replica = ruvGetReplica (ruv, rid);
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_covers_csn: replica for id %d not found\n", rid);
+ return_value = PR_FALSE;
+ }
+ else
+ {
+ if (strict)
+ {
+ return_value = (csn_compare (csn, replica->csn) < 0);
+ }
+ else
+ {
+ return_value = (csn_compare (csn, replica->csn) <= 0);
+ }
+ }
+ }
+ return return_value;
+}
+
+PRBool
+ruv_covers_csn(const RUV *ruv, const CSN *csn)
+{
+ PRBool rc;
+
+ PR_RWLock_Rlock (ruv->lock);
+ rc = ruv_covers_csn_internal(ruv, csn, PR_FALSE);
+ PR_RWLock_Unlock (ruv->lock);
+
+ return rc;
+}
+
+PRBool
+ruv_covers_csn_strict(const RUV *ruv, const CSN *csn)
+{
+ PRBool rc;
+
+ PR_RWLock_Rlock (ruv->lock);
+ rc = ruv_covers_csn_internal(ruv, csn, PR_TRUE);
+ PR_RWLock_Unlock (ruv->lock);
+
+ return rc;
+}
+
+
+/*
+ * The function gets min{maxcsns of all ruv elements} if get_the_max=0,
+ * or max{maxcsns of all ruv elements} if get_the_max != 0.
+ */
+static int
+ruv_get_min_or_max_csn(const RUV *ruv, CSN **csn, int get_the_max)
+{
+ int return_value;
+
+ if (ruv == NULL || csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_get_min_or_max_csn: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ CSN *found = NULL;
+ RUVElement *replica;
+ int cookie;
+ PR_RWLock_Rlock (ruv->lock);
+ for (replica = dl_get_first (ruv->elements, &cookie); replica;
+ replica = dl_get_next (ruv->elements, &cookie))
+ {
+ /*
+ * Skip replica whose maxcsn is NULL otherwise
+ * the code will return different min_csn if
+ * the sequence of the replicas is altered.
+ *
+ * don't use READ_ONLY replicas for computing the value of
+ * "found", as they seem to have NULL csn and min_csn
+ */
+ if (replica->csn == NULL || replica->rid == READ_ONLY_REPLICA_ID)
+ {
+ continue;
+ }
+
+ if (found == NULL ||
+ (!get_the_max && csn_compare(found, replica->csn)>0) ||
+ ( get_the_max && csn_compare(found, replica->csn)<0))
+ {
+ found = replica->csn;
+ }
+ }
+ if (found == NULL)
+ {
+ *csn = NULL;
+ }
+ else
+ {
+ *csn = csn_dup (found);
+ }
+ PR_RWLock_Unlock (ruv->lock);
+ return_value = RUV_SUCCESS;
+ }
+ return return_value;
+}
+
+int
+ruv_get_max_csn(const RUV *ruv, CSN **csn)
+{
+ return ruv_get_min_or_max_csn(ruv, csn, 1 /* get the max */);
+}
+
+int
+ruv_get_min_csn(const RUV *ruv, CSN **csn)
+{
+ return ruv_get_min_or_max_csn(ruv, csn, 0 /* get the min */);
+}
+
+int
+ruv_enumerate_elements (const RUV *ruv, FNEnumRUV fn, void *arg)
+{
+ int cookie;
+ RUVElement *elem;
+ int rc = 0;
+ ruv_enum_data enum_data = {0};
+
+ if (ruv == NULL || fn == NULL)
+ {
+ /* ONREPL - log error */
+ return -1;
+ }
+
+ PR_RWLock_Rlock (ruv->lock);
+ for (elem = (RUVElement*)dl_get_first (ruv->elements, &cookie); elem;
+ elem = (RUVElement*)dl_get_next (ruv->elements, &cookie))
+ {
+ /* we only return elements that contains both minimal and maximal CSNs */
+ if (elem->csn && elem->min_csn)
+ {
+ enum_data.csn = elem->csn;
+ enum_data.min_csn = elem->min_csn;
+ rc = fn (&enum_data, arg);
+ if (rc != 0)
+ break;
+ }
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+
+ return rc;
+}
+
+/*
+ * Convert a replica update vector to a NULL-terminated array
+ * of bervals. The caller is responsible for freeing the bervals.
+ */
+int
+ruv_to_bervals(const RUV *ruv, struct berval ***bvals)
+{
+ struct berval **returned_bervals = NULL;
+ int return_value;
+ if (ruv == NULL || bvals == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_to_bervals: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ int count;
+ int i;
+ RUVElement *replica;
+ char csnStr1 [CSN_STRSIZE];
+ char csnStr2 [CSN_STRSIZE];
+ int cookie;
+ PR_RWLock_Rlock (ruv->lock);
+ count = dl_get_count (ruv->elements) + 2;
+ returned_bervals = (struct berval **)slapi_ch_malloc(sizeof(struct berval *) * count);
+ returned_bervals[count - 1] = NULL;
+ returned_bervals[0] = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
+ returned_bervals[0]->bv_val = slapi_ch_malloc(strlen(prefix_replicageneration) + strlen(ruv->replGen) + 2);
+ sprintf(returned_bervals[0]->bv_val, "%s %s",
+ prefix_replicageneration, ruv->replGen);
+ returned_bervals[0]->bv_len = strlen(returned_bervals[0]->bv_val);
+ for (i = 1, replica = dl_get_first (ruv->elements, &cookie); replica;
+ i++, replica = dl_get_next (ruv->elements, &cookie))
+ {
+ returned_bervals[i] = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
+ returned_bervals[i]->bv_val = slapi_ch_malloc(strlen(prefix_ruvcsn) + RIDSTR_SIZE +
+ ((replica->replica_purl == NULL) ? 0 : strlen(replica->replica_purl)) +
+ ((replica->min_csn == NULL) ? 0 : CSN_STRSIZE) +
+ ((replica->csn == NULL) ? 0 : CSN_STRSIZE) + 5);
+ sprintf(returned_bervals[i]->bv_val, "%s%d%s%s}%s%s%s%s",
+ prefix_ruvcsn, replica->rid,
+ replica->replica_purl == NULL ? "" : " ",
+ replica->replica_purl == NULL ? "" : replica->replica_purl,
+ replica->min_csn == NULL ? "" : " ",
+ replica->min_csn == NULL ? "" : csn_as_string (replica->min_csn, PR_FALSE, csnStr1),
+ replica->csn == NULL ? "" : " ",
+ replica->csn == NULL ? "" : csn_as_string (replica->csn, PR_FALSE, csnStr2));
+ returned_bervals[i]->bv_len = strlen(returned_bervals[i]->bv_val);
+ }
+ PR_RWLock_Unlock (ruv->lock);
+ return_value = RUV_SUCCESS;
+ *bvals = returned_bervals;
+ }
+ return return_value;
+}
+
+int
+ruv_to_smod(const RUV *ruv, Slapi_Mod *smod)
+{
+ int return_value;
+
+ if (ruv == NULL || smod == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_to_smod: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ struct berval val;
+ RUVElement *replica;
+ int cookie;
+ char csnStr1 [CSN_STRSIZE];
+ char csnStr2 [CSN_STRSIZE];
+#define B_SIZ 1024
+ char buf[B_SIZ];
+ PR_RWLock_Rlock (ruv->lock);
+ slapi_mod_init (smod, dl_get_count (ruv->elements) + 1);
+ slapi_mod_set_type (smod, type_ruvElement);
+ slapi_mod_set_operation (smod, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
+ PR_snprintf(buf, B_SIZ, "%s %s", prefix_replicageneration, ruv->replGen);
+ val.bv_val = buf;
+ val.bv_len = strlen(buf);
+ slapi_mod_add_value(smod, &val);
+ for (replica = dl_get_first (ruv->elements, &cookie); replica;
+ replica = dl_get_next (ruv->elements, &cookie))
+ {
+
+ PR_snprintf(buf, B_SIZ, "%s%d%s%s}%s%s%s%s", prefix_ruvcsn, replica->rid,
+ replica->replica_purl == NULL ? "" : " ",
+ replica->replica_purl == NULL ? "" : replica->replica_purl,
+ replica->min_csn == NULL ? "" : " ",
+ replica->min_csn == NULL ? "" : csn_as_string (replica->min_csn, PR_FALSE, csnStr1),
+ replica->csn == NULL ? "" : " ",
+ replica->csn == NULL ? "" : csn_as_string (replica->csn, PR_FALSE, csnStr2));
+ val.bv_len = strlen(buf);
+ slapi_mod_add_value(smod, &val);
+ }
+ PR_RWLock_Unlock (ruv->lock);
+ return_value = RUV_SUCCESS;
+ }
+ return return_value;
+}
+
+int
+ruv_last_modified_to_smod(const RUV *ruv, Slapi_Mod *smod)
+{
+ int return_value;
+
+ if (ruv == NULL || smod == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_last_modified_to_smod: NULL argument\n");
+ return_value = RUV_BAD_DATA;
+ }
+ else
+ {
+ struct berval val;
+ RUVElement *replica;
+ int cookie;
+ char buf[B_SIZ];
+ PR_RWLock_Rlock (ruv->lock);
+ slapi_mod_init (smod, dl_get_count (ruv->elements));
+ slapi_mod_set_type (smod, type_ruvElementUpdatetime);
+ slapi_mod_set_operation (smod, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
+ val.bv_val = buf;
+ for (replica = dl_get_first (ruv->elements, &cookie); replica;
+ replica = dl_get_next (ruv->elements, &cookie))
+ {
+ PR_snprintf(buf, B_SIZ, "%s%d%s%s} %08lx", prefix_ruvcsn, replica->rid,
+ replica->replica_purl == NULL ? "" : " ",
+ replica->replica_purl == NULL ? "" : replica->replica_purl,
+ replica->last_modified);
+ val.bv_len = strlen(buf);
+ slapi_mod_add_value(smod, &val);
+ }
+ PR_RWLock_Unlock (ruv->lock);
+ return_value = RUV_SUCCESS;
+ }
+ return return_value;
+}
+
+/*
+ * XXXggood do we need "ruv_covers_ruv_strict" ???? */
+PRBool
+ruv_covers_ruv(const RUV *covering_ruv, const RUV *covered_ruv)
+{
+ PRBool return_value = PR_TRUE;
+ RUVElement *replica;
+ int cookie;
+
+ /* compare replica generations first */
+ if (covering_ruv->replGen == NULL)
+ {
+ if (covered_ruv->replGen)
+ return PR_FALSE;
+ }
+ else
+ {
+ if (covered_ruv->replGen == NULL)
+ return PR_FALSE;
+ }
+
+ if (strcasecmp (covered_ruv->replGen, covering_ruv->replGen))
+ return PR_FALSE;
+
+ /* replica generation is the same, now compare element by element */
+ for (replica = dl_get_first (covered_ruv->elements, &cookie);
+ NULL != replica;
+ replica = dl_get_next (covered_ruv->elements, &cookie))
+ {
+ if (replica->csn &&
+ (ruv_covers_csn(covering_ruv, replica->csn) == PR_FALSE))
+ {
+ return_value = PR_FALSE;
+ /* Don't break here - may leave something referenced? */
+ }
+ }
+ return return_value;
+}
+
+PRInt32
+ruv_replica_count (const RUV *ruv)
+{
+ if (ruv == NULL)
+ return 0;
+ else
+ {
+ int count;
+
+ PR_RWLock_Rlock (ruv->lock);
+ count = dl_get_count (ruv->elements);
+ PR_RWLock_Unlock (ruv->lock);
+
+ return count;
+ }
+}
+
+/*
+ * Extract all the referral URL's from the RUV (but self URL),
+ * returning them in an array of strings, that
+ * the caller must free.
+ */
+char **
+ruv_get_referrals(const RUV *ruv)
+{
+ char **r= NULL;
+ int n;
+ const char *mypurl = multimaster_get_local_purl();
+
+ PR_RWLock_Rlock (ruv->lock);
+
+ n = ruv_replica_count(ruv);
+ if(n>0)
+ {
+ RUVElement *replica;
+ int cookie;
+ int i= 0;
+ r= (char**)slapi_ch_calloc(sizeof(char*),n+1);
+ for (replica = dl_get_first (ruv->elements, &cookie); replica;
+ replica = dl_get_next (ruv->elements, &cookie))
+ {
+ /* Add URL into referrals if doesn't match self URL */
+ if((replica->replica_purl!=NULL) &&
+ (slapi_utf8casecmp((unsigned char *)replica->replica_purl,
+ (unsigned char *)mypurl) != 0))
+ {
+ r[i]= slapi_ch_strdup(replica->replica_purl);
+ i++;
+ }
+ }
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+
+ return r; /* Caller must free this */
+}
+
+void
+ruv_dump(const RUV *ruv, char *ruv_name, PRFileDesc *prFile)
+{
+ RUVElement *replica;
+ int cookie;
+ char csnstr1[CSN_STRSIZE];
+ char csnstr2[CSN_STRSIZE];
+ char buff[RUVSTR_SIZE];
+ int len = sizeof (buff);
+
+ PR_ASSERT(NULL != ruv);
+
+ PR_RWLock_Rlock (ruv->lock);
+
+ PR_snprintf (buff, len, "%s: {replicageneration} %s\n",
+ ruv_name ? ruv_name : type_ruvElement,
+ ruv->replGen == NULL ? "" : ruv->replGen);
+
+ if (prFile)
+ {
+ slapi_write_buffer (prFile, buff, strlen(buff));
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, buff);
+ }
+ for (replica = dl_get_first (ruv->elements, &cookie); replica;
+ replica = dl_get_next (ruv->elements, &cookie))
+ {
+ /* prefix_ruvcsn = "{replica " */
+ PR_snprintf (buff, len, "%s: %s%d%s%s} %s %s\n",
+ ruv_name ? ruv_name : type_ruvElement,
+ prefix_ruvcsn, replica->rid,
+ replica->replica_purl == NULL ? "" : " ",
+ replica->replica_purl == NULL ? "" : replica->replica_purl,
+ csn_as_string(replica->min_csn, PR_FALSE, csnstr1),
+ csn_as_string(replica->csn, PR_FALSE, csnstr2));
+ if (strlen (csnstr1) > 0) {
+ PR_snprintf (buff + strlen(buff) - 1, len - strlen(buff), " %08lx\n",
+ replica->last_modified);
+ }
+ if (prFile)
+ {
+ slapi_write_buffer (prFile, buff, strlen(buff));
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, buff);
+ }
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+}
+
+/* this function notifies the ruv that there are operations in progress so that
+ they can be added to the pending list for the appropriate client. */
+int ruv_add_csn_inprogress (RUV *ruv, const CSN *csn)
+{
+ RUVElement* replica;
+ char csn_str[CSN_STRSIZE];
+ int rc = RUV_SUCCESS;
+
+ PR_ASSERT (ruv && csn);
+
+ /* locate ruvElement */
+ PR_RWLock_Wlock (ruv->lock);
+ replica = ruvGetReplica (ruv, csn_get_replicaid (csn));
+ if (replica == NULL)
+ {
+ replica = ruvAddReplicaNoCSN (ruv, csn_get_replicaid (csn), NULL/*purl*/);
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_add_csn_inprogress: failed to add replica"
+ " that created csn %s\n", csn_as_string (csn, PR_FALSE, csn_str));
+ rc = RUV_MEMORY_ERROR;
+ goto done;
+ }
+ }
+
+ /* check first that this csn is not already covered by this RUV */
+ if (ruv_covers_csn_internal(ruv, csn, PR_FALSE))
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_add_csn_inprogress: "
+ "the csn %s has already be seen - ignoring\n",
+ csn_as_string (csn, PR_FALSE, csn_str));
+ rc = RUV_COVERS_CSN;
+ goto done;
+ }
+
+ rc = csnplInsert (replica->csnpl, csn);
+ if (rc == 1) /* we already seen this csn */
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_add_csn_inprogress: "
+ "the csn %s has already be seen - ignoring\n",
+ csn_as_string (csn, PR_FALSE, csn_str));
+ rc = RUV_COVERS_CSN;
+ }
+ else if(rc != 0)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_add_csn_inprogress: failed to insert csn %s"
+ " into pending list\n", csn_as_string (csn, PR_FALSE, csn_str));
+ rc = RUV_UNKNOWN_ERROR;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_add_csn_inprogress: successfully inserted csn %s"
+ " into pending list\n", csn_as_string (csn, PR_FALSE, csn_str));
+ rc = RUV_SUCCESS;
+ }
+
+done:
+ PR_RWLock_Unlock (ruv->lock);
+ return rc;
+}
+
+int ruv_cancel_csn_inprogress (RUV *ruv, const CSN *csn)
+{
+ RUVElement* replica;
+ int rc = RUV_SUCCESS;
+
+ PR_ASSERT (ruv && csn);
+
+ /* locate ruvElement */
+ PR_RWLock_Wlock (ruv->lock);
+ replica = ruvGetReplica (ruv, csn_get_replicaid (csn));
+ if (replica == NULL)
+ {
+ /* ONREPL - log error */
+ rc = RUV_NOTFOUND;
+ goto done;
+ }
+
+ rc = csnplRemove (replica->csnpl, csn);
+ if (rc != 0)
+ rc = RUV_NOTFOUND;
+ else
+ rc = RUV_SUCCESS;
+
+done:
+ PR_RWLock_Unlock (ruv->lock);
+ return rc;
+}
+
+int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, PRBool isLocal)
+{
+ int rc=RUV_SUCCESS;
+ char csn_str[CSN_STRSIZE];
+ CSN *max_csn;
+ CSN *first_csn = NULL;
+ RUVElement *replica;
+
+ PR_ASSERT (ruv && csn);
+
+ PR_RWLock_Wlock (ruv->lock);
+
+ replica = ruvGetReplica (ruv, csn_get_replicaid (csn));
+ if (replica == NULL)
+ {
+ /* we should have a ruv element at this point because it would have
+ been added by ruv_add_inprogress function */
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_update_ruv: "
+ "can't locate RUV element for replica %d\n", csn_get_replicaid (csn));
+ goto done;
+ }
+
+ if (csnplCommit(replica->csnpl, csn) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "ruv_update_ruv: cannot commit csn %s\n",
+ csn_as_string(csn, PR_FALSE, csn_str));
+ rc = RUV_CSNPL_ERROR;
+ goto done;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_update_ruv: "
+ "successfully committed csn %s\n", csn_as_string(csn, PR_FALSE, csn_str));
+ }
+
+ if ((max_csn = csnplRollUp(replica->csnpl, &first_csn)) != NULL)
+ {
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "ruv_update_ruv: rolled up to csn %s\n",
+ csn_as_string(max_csn, PR_FALSE, csn_str)); /* XXXggood remove debugging */
+#endif
+ /* replica object sets min csn for local replica */
+ if (!isLocal && replica->min_csn == NULL) {
+ /* bug 559223 - it seems that, under huge stress, a server might pass
+ * through this code when more than 1 change has already been sent and commited into
+ * the pending lists... Therefore, as we are trying to set the min_csn ever
+ * generated by this replica, we need to set the first_csn as the min csn in the
+ * ruv */
+ set_min_csn_nolock(ruv, first_csn, replica_purl);
+ }
+ set_max_csn_nolock(ruv, max_csn, replica_purl);
+ /* It is possible that first_csn points to max_csn.
+ We need to free it once */
+ if (max_csn != first_csn) {
+ csn_free(&first_csn);
+ }
+ csn_free(&max_csn);
+ }
+
+done:
+ PR_RWLock_Unlock (ruv->lock);
+
+ return rc;
+}
+
+/* Helper functions */
+
+static int
+ruvInit (RUV **ruv, int initCount)
+{
+ PR_ASSERT (ruv);
+
+ /* allocate new RUV */
+ *ruv = (RUV *)slapi_ch_calloc (1, sizeof (RUV));
+ if (ruv == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruvInit: memory allocation failed\n");
+ return RUV_MEMORY_ERROR;
+ }
+
+ /* allocate elements */
+ (*ruv)->elements = dl_new ();
+ if ((*ruv)->elements == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruvInit: memory allocation failed\n");
+ return RUV_MEMORY_ERROR;
+ }
+
+ dl_init ((*ruv)->elements, initCount);
+
+ /* create lock */
+ (*ruv)->lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "ruv_lock");
+ if ((*ruv)->lock == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruvInit: failed to create lock\n");
+ return RUV_NSPR_ERROR;
+ }
+
+ return RUV_SUCCESS;
+}
+
+static void
+ruvFreeReplica (void **data)
+{
+ RUVElement *element = *(RUVElement**)data;
+
+ if (NULL != element)
+ {
+ if (NULL != element->csn)
+ {
+ csn_free (&element->csn);
+ }
+ if (NULL != element->min_csn)
+ {
+ csn_free (&element->min_csn);
+ }
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free((void **)&element->replica_purl);
+
+ if (element->csnpl)
+ {
+ csnplFree (&(element->csnpl));
+ }
+ slapi_ch_free ((void **)&element);
+ }
+}
+
+static RUVElement*
+ruvAddReplica (RUV *ruv, const CSN *csn, const char *replica_purl)
+{
+ RUVElement *replica;
+
+ PR_ASSERT (NULL != ruv);
+ PR_ASSERT (NULL != csn);
+
+ replica = (RUVElement *)slapi_ch_calloc (1, sizeof (RUVElement));
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruvAddReplica: memory allocation failed\n");
+ return NULL;
+ }
+
+ replica->rid = csn_get_replicaid (csn);
+/* PR_ASSERT(replica->rid != READ_ONLY_REPLICA_ID); */
+
+ replica->csn = csn_dup (csn);
+ replica->last_modified = current_time();
+ replica->min_csn = csn_dup (csn);
+
+ replica->replica_purl = slapi_ch_strdup(replica_purl);
+ replica->csnpl = csnplNew ();
+
+ dl_add (ruv->elements, replica);
+
+ return replica;
+}
+
+static RUVElement*
+ruvAddReplicaNoCSN (RUV *ruv, ReplicaId rid, const char *replica_purl)
+{
+ RUVElement *replica;
+
+ PR_ASSERT (NULL != ruv);
+/* PR_ASSERT(rid != READ_ONLY_REPLICA_ID); */
+
+ replica = (RUVElement *)slapi_ch_calloc (1, sizeof (RUVElement));
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruvAddReplicaNoCSN: memory allocation failed\n");
+ return NULL;
+ }
+
+ replica->rid = rid;
+ replica->replica_purl = slapi_ch_strdup(replica_purl);
+ replica->csnpl = csnplNew ();
+
+ dl_add (ruv->elements, replica);
+
+ return replica;
+}
+
+static RUVElement*
+ruvAddIndexReplicaNoCSN (RUV *ruv, ReplicaId rid, const char *replica_purl, int index)
+{
+ RUVElement *replica;
+
+ PR_ASSERT (NULL != ruv);
+/* PR_ASSERT(rid != READ_ONLY_REPLICA_ID); */
+
+ replica = (RUVElement *)slapi_ch_calloc (1, sizeof (RUVElement));
+ if (replica == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruvAddIndexReplicaNoCSN: memory allocation failed\n");
+ return NULL;
+ }
+
+ replica->rid = rid;
+ replica->replica_purl = slapi_ch_strdup(replica_purl);
+ replica->csnpl = csnplNew ();
+
+ dl_add_index (ruv->elements, replica, index);
+
+ return replica;
+}
+
+static RUVElement *
+ruvGetReplica (const RUV *ruv, ReplicaId rid)
+{
+ PR_ASSERT (ruv /* && rid >= 0 -- rid can't be negative */);
+
+ return (RUVElement *)dl_get (ruv->elements, (const void*)&rid, ruvReplicaCompare);
+}
+
+static int
+ruvReplicaCompare (const void *el1, const void *el2)
+{
+ RUVElement *replica = (RUVElement*)el1;
+ ReplicaId *rid1 = (ReplicaId*) el2;
+
+ if (replica == NULL || rid1 == NULL)
+ return -1;
+
+ if (*rid1 == replica->rid)
+ return 0;
+
+ if (*rid1 < replica->rid)
+ return -1;
+ else
+ return 1;
+}
+
+
+
+/*
+ * Given a berval that points to a string of the form:
+ * "{dbgen} generation-id", return a copy of the
+ * "generation-id" part in a null-terminated string.
+ * Returns NULL if the berval is malformed.
+ */
+static char *
+get_replgen_from_berval(const struct berval *bval)
+{
+ char *ret_string = NULL;
+
+ if (NULL != bval && NULL != bval->bv_val &&
+ (bval->bv_len > strlen(prefix_replicageneration)) &&
+ strncasecmp(bval->bv_val, prefix_replicageneration,
+ strlen(prefix_replicageneration)) == 0)
+ {
+ unsigned int index = strlen(prefix_replicageneration);
+ /* Skip any whitespace */
+ while (index++ < bval->bv_len && bval->bv_val[index] == ' ');
+ if (index < bval->bv_len)
+ {
+ unsigned int ret_len = bval->bv_len - index;
+ ret_string = slapi_ch_malloc(ret_len + 1);
+ memcpy(ret_string, &bval->bv_val[index], ret_len);
+ ret_string[ret_len] = '\0';
+ }
+ }
+ return ret_string;
+}
+
+
+
+/*
+ * Given a berval that points to a string of the form:
+ * "{replica ldap[s]//host:port} <min_csn> <csn>", parse out the
+ * partial URL and the CSNs into an RUVElement, and return
+ * a pointer to the copy. Returns NULL if the berval is
+ * malformed.
+ */
+static RUVElement *
+get_ruvelement_from_berval(const struct berval *bval)
+{
+ RUVElement *ret_ruve = NULL;
+ char *purl = NULL;
+ ReplicaId rid = 0;
+ char ridbuff [RIDSTR_SIZE];
+ int i;
+
+ if (NULL != bval && NULL != bval->bv_val &&
+ bval->bv_len > strlen(prefix_ruvcsn) &&
+ strncasecmp(bval->bv_val, prefix_ruvcsn, strlen(prefix_ruvcsn)) == 0)
+ {
+ unsigned int urlbegin = strlen(prefix_ruvcsn);
+ unsigned int urlend;
+ unsigned int mincsnbegin;
+
+ /* replica id must be here */
+ i = 0;
+ while (isdigit (bval->bv_val[urlbegin]))
+ {
+ ridbuff [i] = bval->bv_val[urlbegin];
+ i++;
+ urlbegin ++;
+ }
+
+ if (i == 0) /* replicaid is missing */
+ goto loser;
+
+ ridbuff[i] = '\0';
+ rid = atoi (ridbuff);
+
+ if (bval->bv_val[urlbegin] == '}')
+ {
+ /* No purl in this value */
+ purl = NULL;
+ mincsnbegin = urlbegin + 1;
+ }
+ else
+ {
+ while (urlbegin++ < bval->bv_len && bval->bv_val[urlbegin] == ' ');
+ urlend = urlbegin;
+ while (urlend++ < bval->bv_len && bval->bv_val[urlend] != '}');
+ purl = slapi_ch_malloc(urlend - urlbegin + 1);
+ memcpy(purl, &bval->bv_val[urlbegin], urlend - urlbegin);
+ purl[urlend - urlbegin] = '\0';
+ mincsnbegin = urlend;
+ }
+ /* Skip any whitespace before the first (minimum) CSN */
+ while (mincsnbegin++ < (bval->bv_len-1) && bval->bv_val[mincsnbegin] == ' ');
+ /* Now, mincsnbegin should contain the index of the beginning of the first csn */
+ if (mincsnbegin >= bval->bv_len)
+ {
+ /* Missing the entire content*/
+ if (purl == NULL)
+ goto loser;
+ else /* we have just purl - no changes from the replica has been seen */
+ {
+ ret_ruve = (RUVElement *)slapi_ch_calloc(1, sizeof(RUVElement));
+ ret_ruve->rid = rid;
+ ret_ruve->replica_purl = purl;
+ }
+ }
+ else
+ {
+ if (bval->bv_len - mincsnbegin != (_CSN_VALIDCSN_STRLEN * 2) + 1)
+ {
+ /* Malformed - incorrect length for 2 CSNs + space */
+ goto loser;
+ }
+ else
+ {
+ char mincsnstr[CSN_STRSIZE];
+ char maxcsnstr[CSN_STRSIZE];
+
+ memset(mincsnstr, '\0', CSN_STRSIZE);
+ memset(maxcsnstr, '\0', CSN_STRSIZE);
+ memcpy(mincsnstr, &bval->bv_val[mincsnbegin], _CSN_VALIDCSN_STRLEN);
+ memcpy(maxcsnstr, &bval->bv_val[mincsnbegin + _CSN_VALIDCSN_STRLEN + 1], _CSN_VALIDCSN_STRLEN);
+ ret_ruve = (RUVElement *)slapi_ch_calloc(1, sizeof(RUVElement));
+ ret_ruve->min_csn = csn_new_by_string(mincsnstr);
+ ret_ruve->csn = csn_new_by_string(maxcsnstr);
+ ret_ruve->rid = rid;
+ ret_ruve->replica_purl = purl;
+ if (NULL == ret_ruve->min_csn || NULL == ret_ruve->csn)
+ {
+ goto loser;
+ }
+ }
+ }
+ }
+
+ /* initialize csn pending list */
+ ret_ruve->csnpl = csnplNew ();
+ if (ret_ruve->csnpl == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "get_ruvelement_from_berval: failed to create csn pending list\n");
+ goto loser;
+ }
+
+ return ret_ruve;
+
+loser:
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free((void **)&purl);
+ if (NULL != ret_ruve)
+ {
+ if (NULL != ret_ruve->min_csn)
+ {
+ csn_free(&ret_ruve->min_csn);
+ }
+ if (NULL != ret_ruve->csn)
+ {
+ csn_free(&ret_ruve->csn);
+ }
+ slapi_ch_free((void **)&ret_ruve);
+ }
+ return NULL;
+}
+
+int
+ruv_move_local_supplier_to_first(RUV *ruv, ReplicaId aRid)
+{
+ RUVElement * elem = NULL;
+ int rc = RUV_NOTFOUND;
+
+ PR_ASSERT(ruv);
+
+ PR_RWLock_Wlock (ruv->lock);
+
+ elem = (RUVElement *)dl_delete(ruv->elements,(const void*)&aRid, ruvReplicaCompare, 0);
+ if (elem) {
+ dl_add_index(ruv->elements, elem, 1);
+ rc = RUV_SUCCESS;
+ }
+
+ PR_RWLock_Unlock (ruv->lock);
+
+ return rc;
+}
+
+
+int
+ruv_get_first_id_and_purl(RUV *ruv, ReplicaId *rid, char **replica_purl )
+{
+ RUVElement * first = NULL;
+ int cookie;
+ int rc;
+
+ PR_ASSERT(ruv);
+
+ PR_RWLock_Rlock (ruv->lock);
+ first = dl_get_first(ruv->elements, &cookie);
+ if ( first == NULL )
+ {
+ rc = RUV_MEMORY_ERROR;
+ }
+ else
+ {
+ *rid = first->rid;
+ *replica_purl = first->replica_purl;
+ rc = RUV_SUCCESS;
+ }
+ PR_RWLock_Unlock (ruv->lock);
+ return rc;
+}
+
+int ruv_local_contains_supplier(RUV *ruv, ReplicaId rid)
+{
+ int cookie;
+ RUVElement *elem = NULL;
+
+ PR_ASSERT(ruv);
+
+ PR_RWLock_Rlock (ruv->lock);
+ for (elem = dl_get_first (ruv->elements, &cookie);
+ elem;
+ elem = dl_get_next (ruv->elements, &cookie))
+ {
+ if (elem->rid == rid){
+ PR_RWLock_Unlock (ruv->lock);
+ return 1;
+ }
+ }
+ PR_RWLock_Unlock (ruv->lock);
+ return 0;
+}
+
+PRBool ruv_has_csns(const RUV *ruv)
+{
+ PRBool retval = PR_TRUE;
+ CSN *mincsn = NULL;
+ CSN *maxcsn = NULL;
+
+ ruv_get_min_csn(ruv, &mincsn);
+ ruv_get_max_csn(ruv, &maxcsn);
+ if (mincsn) {
+ csn_free(&mincsn);
+ csn_free(&maxcsn);
+ } else if (maxcsn) {
+ csn_free(&maxcsn);
+ } else {
+ retval = PR_FALSE; /* both min and max are false */
+ }
+
+ return retval;
+}
+
+/* Check if the first ruv is newer than the second one */
+PRBool
+ruv_is_newer (Object *sruvobj, Object *cruvobj)
+{
+ RUV *sruv, *cruv;
+ RUVElement *sreplica, *creplica;
+ int scookie, ccookie;
+ int is_newer = PR_FALSE;
+
+ if ( sruvobj == NULL ) {
+ return 0;
+ }
+ if ( cruvobj == NULL ) {
+ return 1;
+ }
+ sruv = (RUV *) object_get_data ( sruvobj );
+ cruv = (RUV *) object_get_data ( cruvobj );
+
+ for (sreplica = dl_get_first (sruv->elements, &scookie); sreplica;
+ sreplica = dl_get_next (sruv->elements, &scookie))
+ {
+ /* A hub may have a dummy ruv with rid 65535 */
+ if ( sreplica->csn == NULL ) continue;
+
+ for (creplica = dl_get_first (cruv->elements, &ccookie); creplica;
+ creplica = dl_get_next (cruv->elements, &ccookie))
+ {
+ if ( sreplica->rid == creplica->rid ) {
+ if ( csn_compare ( sreplica->csn, creplica->csn ) > 0 ) {
+ is_newer = PR_TRUE;
+ }
+ break;
+ }
+ }
+ if ( creplica == NULL || is_newer ) {
+ is_newer = PR_TRUE;
+ break;
+ }
+ }
+
+ return is_newer;
+}
+
+#ifdef TESTING /* Some unit tests for code in this file */
+
+static void
+ruv_dump_internal(RUV *ruv)
+{
+ RUVElement *replica;
+ int cookie;
+ char csnstr1[CSN_STRSIZE];
+ char csnstr2[CSN_STRSIZE];
+
+ PR_ASSERT(NULL != ruv);
+ printf("{replicageneration} %s\n", ruv->replGen == NULL ? "NULL" : ruv->replGen);
+ for (replica = dl_get_first (ruv->elements, &cookie); replica;
+ replica = dl_get_next (ruv->elements, &cookie))
+ {
+ printf("{replica%s%s} %s %s\n",
+ replica->replica_purl == NULL ? "" : " ",
+ replica->replica_purl == NULL ? "" : replica->replica_purl,
+ csn_as_string(replica->min_csn, PR_FALSE, csnstr1),
+ csn_as_string(replica->csn, PR_FALSE, csnstr2));
+ }
+}
+
+void
+ruv_test()
+{
+ const struct berval *vals[5];
+ struct berval val0, val1, val2, val3;
+ RUV *ruv;
+ Slapi_Attr *attr;
+ Slapi_Value *sv0, *sv1, *sv2, *sv3;
+ int rc;
+ char csnstr[CSN_STRSIZE];
+ char *gen;
+ CSN *newcsn;
+ ReplicaId *ids;
+ int nids;
+ Slapi_Mod smods;
+ PRBool covers;
+
+ vals[0] = &val0;
+ vals[1] = &val1;
+ vals[2] = &val2;
+ vals[3] = &val3;
+ vals[4] = NULL;
+
+ val0.bv_val = "{replicageneration} 0440FDC0A33F";
+ val0.bv_len = strlen(val0.bv_val);
+
+ val1.bv_val = "{replica ldap://ggood.mcom.com:389} 12345670000000FE0000 12345671000000FE0000";
+ val1.bv_len = strlen(val1.bv_val);
+
+ val2.bv_val = "{replica ldaps://an-impossibly-long-host-name-that-drags-on-forever-and-forever.mcom.com:389} 11112110000000FF0000 11112111000000FF0000";
+ val2.bv_len = strlen(val2.bv_val);
+
+ val3.bv_val = "{replica} 12345672000000FD0000 12345673000000FD0000";
+ val3.bv_len = strlen(val3.bv_val);
+
+ rc = ruv_init_from_bervals(vals, &ruv);
+ ruv_dump_internal(ruv);
+
+ attr = slapi_attr_new();
+ attr = slapi_attr_init(attr, "ruvelement");
+ sv0 = slapi_value_new();
+ sv1 = slapi_value_new();
+ sv2 = slapi_value_new();
+ sv3 = slapi_value_new();
+ slapi_value_init_berval(sv0, &val0);
+ slapi_value_init_berval(sv1, &val1);
+ slapi_value_init_berval(sv2, &val2);
+ slapi_value_init_berval(sv3, &val3);
+ slapi_attr_add_value(attr, sv0);
+ slapi_attr_add_value(attr, sv1);
+ slapi_attr_add_value(attr, sv2);
+ slapi_attr_add_value(attr, sv3);
+ rc = ruv_init_from_slapi_attr(attr, &ruv);
+ ruv_dump_internal(ruv);
+
+ rc = ruv_delete_replica(ruv, 0xFF);
+ /* Should delete one replica */
+ ruv_dump_internal(ruv);
+
+ rc = ruv_delete_replica(ruv, 0xAA);
+ /* No such replica - should not do anything */
+ ruv_dump_internal(ruv);
+
+ rc = ruv_get_largest_csn_for_replica(ruv, 0xFE, &newcsn);
+ if (NULL != newcsn)
+ {
+ csn_as_string(newcsn, PR_FALSE, csnstr);
+ printf("Replica 0x%X has largest csn \"%s\"\n", 0xFE, csnstr);
+ }
+ else
+ {
+ printf("BAD - can't get largest CSN for replica 0x%X\n", 0xFE);
+ }
+
+ rc = ruv_get_smallest_csn_for_replica(ruv, 0xFE, &newcsn);
+ if (NULL != newcsn)
+ {
+ csn_as_string(newcsn, PR_FALSE, csnstr);
+ printf("Replica 0x%X has smallest csn \"%s\"\n", 0xFE, csnstr);
+ }
+ else
+ {
+ printf("BAD - can't get smallest CSN for replica 0x%X\n", 0xFE);
+ }
+ rc = ruv_get_largest_csn_for_replica(ruv, 0xAA, &newcsn);
+ printf("ruv_get_largest_csn_for_replica on non-existent replica ID returns %d\n", rc);
+
+ rc = ruv_get_smallest_csn_for_replica(ruv, 0xAA, &newcsn);
+ printf("ruv_get_smallest_csn_for_replica on non-existent replica ID returns %d\n", rc);
+
+ newcsn = csn_new_by_string("12345674000000FE0000"); /* Old replica 0xFE */
+ rc = ruv_set_csns(ruv, newcsn, "ldaps://foobar.mcom.com");
+ /* Should update replica FE's CSN */
+ ruv_dump_internal(ruv);
+
+ newcsn = csn_new_by_string("12345675000000FB0000"); /* New replica 0xFB */
+ rc = ruv_set_csns(ruv, newcsn, "ldaps://foobar.mcom.com");
+ /* Should get a new replica in the list with min == max csn */
+ ruv_dump_internal(ruv);
+
+ newcsn = csn_new_by_string("12345676000000FD0000"); /* Old replica 0xFD */
+ rc = ruv_set_csns(ruv, newcsn, "ldaps://foobar.mcom.com");
+ /* Should update replica 0xFD so new CSN is newer than min CSN */
+ ruv_dump_internal(ruv);
+
+ gen = ruv_get_replica_generation(ruv);
+ printf("replica generation is \"%s\"\n", gen);
+
+ newcsn = csn_new_by_string("12345673000000FE0000"); /* Old replica 0xFE */
+ covers = ruv_covers_csn(ruv, newcsn); /* should say "true" */
+
+ newcsn = csn_new_by_string("12345675000000FE0000"); /* Old replica 0xFE */
+ covers = ruv_covers_csn(ruv, newcsn); /* Should say "false" */
+
+ newcsn = csn_new_by_string("123456700000000A0000"); /* New replica 0A */
+ rc = ruv_set_min_csn(ruv, newcsn, "ldap://repl0a.mcom.com");
+ ruv_dump_internal(ruv);
+
+ newcsn = csn_new_by_string("123456710000000A0000"); /* New replica 0A */
+ rc = ruv_set_max_csn(ruv, newcsn, "ldap://repl0a.mcom.com");
+ ruv_dump_internal(ruv);
+
+ newcsn = csn_new_by_string("123456700000000B0000"); /* New replica 0B */
+ rc = ruv_set_max_csn(ruv, newcsn, "ldap://repl0b.mcom.com");
+ ruv_dump_internal(ruv);
+
+ newcsn = csn_new_by_string("123456710000000B0000"); /* New replica 0B */
+ rc = ruv_set_min_csn(ruv, newcsn, "ldap://repl0b.mcom.com");
+ ruv_dump_internal(ruv);
+
+ /* ONREPL test ruv enumeration */
+
+ rc = ruv_to_smod(ruv, &smods);
+
+ ruv_destroy(&ruv);
+}
+#endif /* TESTING */
diff --git a/ldap/servers/plugins/replication/repl5_ruv.h b/ldap/servers/plugins/replication/repl5_ruv.h
new file mode 100644
index 00000000..8484e74b
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_ruv.h
@@ -0,0 +1,88 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_ruv.h - interface for replica update vector */
+
+#ifndef REPL5_RUV
+#define REPL5_RUV
+
+#include "slapi-private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct _ruv RUV;
+
+enum
+{
+ RUV_SUCCESS=0,
+ RUV_BAD_DATA,
+ RUV_NOTFOUND,
+ RUV_MEMORY_ERROR,
+ RUV_NSPR_ERROR,
+ RUV_BAD_FORMAT,
+ RUV_UNKNOWN_ERROR,
+ RUV_ALREADY_EXIST,
+ RUV_CSNPL_ERROR,
+ RUV_COVERS_CSN
+};
+
+typedef struct ruv_enum_data
+{
+ CSN *csn;
+ CSN *min_csn;
+} ruv_enum_data;
+
+typedef int (*FNEnumRUV) (const ruv_enum_data *element, void *arg);
+int ruv_init_new (const char *replGen, ReplicaId rid, const char *purl, RUV **ruv);
+int ruv_init_from_bervals(struct berval** vals, RUV **ruv);
+int ruv_init_from_slapi_attr(Slapi_Attr *attr, RUV **ruv);
+int ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *rid);
+RUV* ruv_dup (const RUV *ruv);
+void ruv_destroy (RUV **ruv);
+void ruv_copy_and_destroy (RUV **srcruv, RUV **destruv);
+int ruv_replace_replica_purl (RUV *ruv, ReplicaId rid, const char *replica_purl);
+int ruv_delete_replica (RUV *ruv, ReplicaId rid);
+int ruv_add_replica (RUV *ruv, ReplicaId rid, const char *replica_purl);
+int ruv_add_index_replica (RUV *ruv, ReplicaId rid, const char *replica_purl, int index);
+PRBool ruv_contains_replica (const RUV *ruv, ReplicaId rid);
+int ruv_get_largest_csn_for_replica(const RUV *ruv, ReplicaId rid, CSN **csn);
+int ruv_get_smallest_csn_for_replica(const RUV *ruv, ReplicaId rid, CSN **csn);
+int ruv_set_csns(RUV *ruv, const CSN *csn, const char *replica_purl);
+int ruv_set_csns_keep_smallest(RUV *ruv, const CSN *csn);
+int ruv_set_max_csn(RUV *ruv, const CSN *max_csn, const char *replica_purl);
+int ruv_set_min_csn(RUV *ruv, const CSN *min_csn, const char *replica_purl);
+const char *ruv_get_purl_for_replica(const RUV *ruv, ReplicaId rid);
+char *ruv_get_replica_generation (const RUV *ruv);
+void ruv_set_replica_generation (RUV *ruv, const char *generation);
+PRBool ruv_covers_ruv(const RUV *covering_ruv, const RUV *covered_ruv);
+PRBool ruv_covers_csn(const RUV *ruv, const CSN *csn);
+PRBool ruv_covers_csn_strict(const RUV *ruv, const CSN *csn);
+int ruv_get_min_csn(const RUV *ruv, CSN **csn);
+int ruv_get_max_csn(const RUV *ruv, CSN **csn);
+int ruv_enumerate_elements (const RUV *ruv, FNEnumRUV fn, void *arg);
+int ruv_to_smod(const RUV *ruv, Slapi_Mod *smod);
+int ruv_last_modified_to_smod(const RUV *ruv, Slapi_Mod *smod);
+int ruv_to_bervals(const RUV *ruv, struct berval ***bvals);
+PRInt32 ruv_replica_count (const RUV *ruv);
+char **ruv_get_referrals(const RUV *ruv);
+void ruv_dump(const RUV *ruv, char *ruv_name, PRFileDesc *prFile);
+int ruv_add_csn_inprogress (RUV *ruv, const CSN *csn);
+int ruv_cancel_csn_inprogress (RUV *ruv, const CSN *csn);
+int ruv_update_ruv (RUV *ruv, const CSN *csn, const char *replica_purl, PRBool isLocal);
+int ruv_move_local_supplier_to_first(RUV *ruv, ReplicaId rid);
+int ruv_get_first_id_and_purl(RUV *ruv, ReplicaId *rid, char **replica_purl );
+int ruv_local_contains_supplier(RUV *ruv, ReplicaId rid);
+/* returns true if the ruv has any csns, false otherwise - used for testing
+ whether or not an RUV is empty */
+PRBool ruv_has_csns(const RUV *ruv);
+PRBool ruv_is_newer (Object *sruv, Object *cruv);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ldap/servers/plugins/replication/repl5_schedule.c b/ldap/servers/plugins/replication/repl5_schedule.c
new file mode 100644
index 00000000..427e79a9
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_schedule.c
@@ -0,0 +1,742 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl5_schedule.c */
+/*
+
+The schedule object implements the scheduling policy for a DS 5.0 replication
+supplier.
+
+Methods:
+schedule_set() - sets the schedule
+schedule_get() - gets the schedule
+schedule_in_window_now() - returns TRUE if a replication session
+ should commence.
+schedule_next() - returns the next time that replication is
+ scheduled to occur.
+schedule_notify() - called to inform the scheduler when entries
+ have been updated.
+schedule_set_priority_attributes() - sets the attributes that are
+ considered "high priority". A modification to one of these attributes
+ will cause replication to commence asap, overriding the startup
+ delay and maximum backlog. Also includes an additional parameter
+ that controls whether priority attributes are propagated regardless
+ of the scheduling window, e.g. it's possible to configure things
+ so that password changes get propagated even if we're not in a
+ replication window.
+schedule_set_startup_delay() - sets the time that replication should
+ wait before commencing replication sessions.
+schedule_set_maximum_backlog() - sets the maximum number of updates
+ which can occur before replication will commence. If the backlog
+ threshhold is exceeded, then replication will commence ASAP,
+ overriding the startup delay.
+
+*/
+
+/* ONREPL - I made a simplifying assumption that a schedule item does not
+ cross day boundaries. Implementing this is hard because we search
+ for the items for a particular day only based on the item's staring time.
+ For instance if the current time is tuesday morning, we would not consider
+ the item that started on monday and continued through tuesday.
+ To simulate an item that crosses day boundaries, you can create 2 items -
+ one for the time in the first day and one for the time in the second.
+ We could do this internally by allowing items do span 2 days and
+ splitting them ourselves. This, however, is not currently implemented */
+
+#include "slapi-plugin.h"
+#include "repl5.h"
+
+#include <ctype.h> /* For isdigit() */
+
+/* from proto-slap.h */
+char *get_timestring(time_t *t);
+void free_timestring(char *timestr);
+
+typedef struct schedule_item {
+ struct schedule_item *next;
+ PRUint32 start; /* Start time, given as seconds after midnight */
+ PRUint32 end; /* End time */
+ unsigned char dow; /* Days of week, LSB = Sunday */
+} schedule_item;
+
+typedef struct schedule {
+ const char *session_id;
+ size_t max_backlog;
+ size_t startup_delay;
+ schedule_item *schedule_list; /* Linked list of schedule windows */
+ char **prio_attrs; /* Priority attributes - start replication now */
+ int prio_attrs_override_schedule;
+ PRTime last_session_end;
+ int last_session_status;
+ PRTime last_successful_session_end;
+ window_state_change_callback callback_fn; /* function to call when window opens/closes */
+ void *callback_arg; /* argument to pass to the window state change callback */
+ Slapi_Eq_Context pending_event; /* event scheduled with the event queue */
+ PRLock *lock;
+} schedule;
+
+/* Forward declarations */
+static schedule_item *parse_schedule_value(const Slapi_Value *v);
+static void schedule_window_state_change_event (Schedule *sch);
+static void unschedule_window_state_change_event (Schedule *sch);
+static void window_state_changed (time_t when, void *arg);
+static int schedule_in_window_now_nolock(Schedule *sch);
+static schedule_item* get_current_schedule_item (Schedule *sch);
+static time_t PRTime2time_t (PRTime tm);
+static PRTime schedule_next_nolock (Schedule *sch, PRBool start);
+static void free_schedule_list(schedule_item **schedule_list);
+
+#define SECONDS_PER_MINUTE 60
+#define SECONDS_PER_HOUR (60 * SECONDS_PER_MINUTE)
+#define SECONDS_PER_DAY (24 * SECONDS_PER_HOUR)
+#define DAYS_PER_WEEK 7
+#define ALL_DAYS 0x7F /* Bit mask */
+
+
+
+/*
+ * Create a new schedule object and return a pointer to it.
+ */
+Schedule*
+schedule_new(window_state_change_callback callback_fn, void *callback_arg, const char *session_id)
+{
+ Schedule *sch = NULL;
+ sch = (Schedule *)slapi_ch_calloc(1, sizeof(struct schedule));
+
+ sch->session_id = session_id ? session_id : "";
+ sch->callback_fn = callback_fn;
+ sch->callback_arg = callback_arg;
+
+ if ((sch->lock = PR_NewLock()) == NULL)
+ {
+ slapi_ch_free((void **)&sch);
+ }
+
+ return sch;
+}
+
+
+void
+schedule_destroy(Schedule *s)
+{
+ int i;
+
+ /* unschedule update window event if exists */
+ unschedule_window_state_change_event (s);
+
+ if (s->schedule_list)
+ {
+ free_schedule_list (&s->schedule_list);
+ }
+
+ if (NULL != s->prio_attrs)
+ {
+ for (i = 0; NULL != s->prio_attrs[i]; i++)
+ {
+ slapi_ch_free((void **)&(s->prio_attrs[i]));
+ }
+ slapi_ch_free((void **)&(s->prio_attrs));
+ }
+ PR_DestroyLock(s->lock);
+ s->lock = NULL;
+ slapi_ch_free((void **)&s);
+}
+
+static void
+free_schedule_list(schedule_item **schedule_list)
+{
+ schedule_item *si = *schedule_list;
+ schedule_item *tmp_si;
+ while (NULL != si)
+ {
+ tmp_si = si->next;
+ slapi_ch_free((void **)&si);
+ si = tmp_si;
+ }
+ *schedule_list = NULL;
+}
+
+
+
+/*
+ * Sets the schedule. Returns 0 if all of the schedule lines were
+ * correctly parsed and the new schedule has been put into effect.
+ * Returns -1 if one or more of the schedule items could not be
+ * parsed. If -1 is returned, then no changes have been made to the
+ * current schedule.
+ */
+int
+schedule_set(Schedule *sch, Slapi_Attr *attr)
+{
+ int return_value;
+ schedule_item *si = NULL;
+ schedule_item *new_schedule_list = NULL;
+ int valid = 1;
+
+ if (NULL != attr)
+ {
+ int ind;
+ Slapi_Value *sval;
+ ind = slapi_attr_first_value(attr, &sval);
+ while (ind >= 0)
+ {
+ si = parse_schedule_value(sval);
+ if (NULL == si)
+ {
+ valid = 0;
+ break;
+ }
+ /* Put at head of linked list */
+ si->next = new_schedule_list;
+ new_schedule_list = si;
+ ind = slapi_attr_next_value(attr, ind, &sval);
+ }
+ }
+
+ if (!valid)
+ {
+ /* deallocate any new schedule items */
+ free_schedule_list(&new_schedule_list);
+ return_value = -1;
+ }
+ else
+ {
+ PR_Lock(sch->lock);
+
+ /* if there is an update window event scheduled - unschedule it */
+ unschedule_window_state_change_event (sch);
+
+ free_schedule_list(&sch->schedule_list);
+ sch->schedule_list = new_schedule_list;
+
+ /* schedule an event to notify the caller about openning/closing of the update window */
+ schedule_window_state_change_event (sch);
+
+ PR_Unlock(sch->lock);
+ return_value = 0;
+ }
+ return return_value;
+}
+
+
+
+/*
+ * Returns the schedule.
+ */
+char **
+schedule_get(Schedule *sch)
+{
+ char **return_value = NULL;
+
+ return return_value;
+}
+
+
+
+/*
+ * Return an integer corresponding to the day of the week for
+ * "when".
+ */
+static PRInt32
+day_of_week(PRTime when)
+{
+
+ PRExplodedTime exp;
+
+ PR_ExplodeTime(when, PR_LocalTimeParameters, &exp);
+ return(exp.tm_wday);
+}
+
+
+/*
+ * Return the number of seconds between "when" and the
+ * most recent midnight.
+ */
+static PRUint32
+seconds_since_midnight(PRTime when)
+{
+ PRExplodedTime exp;
+
+ PR_ExplodeTime(when, PR_LocalTimeParameters, &exp);
+ return(exp.tm_hour * 3600 + exp.tm_min * 60 + exp.tm_sec);
+}
+
+
+/*
+ * Return 1 if "now" is within the schedule window
+ * specified by "si", 0 otherwise.
+ */
+static int
+time_in_window(PRTime now, schedule_item *si)
+{
+ unsigned char dow = 1 << day_of_week(now);
+ int return_value = 0;
+
+ if (dow & si->dow)
+ {
+ PRUint32 nowsec = seconds_since_midnight(now);
+
+ return_value = (nowsec >= si->start) && (nowsec <= si->end);
+ }
+
+ return return_value;
+}
+
+
+
+/*
+ * Returns a non-zero value if the current time is within a
+ * replication window and if scheduling constraints are all met.
+ * Otherwise, returns zero.
+ */
+
+int
+schedule_in_window_now (Schedule *sch)
+{
+ int rc;
+
+ PR_ASSERT(NULL != sch);
+ PR_Lock(sch->lock);
+
+ rc = schedule_in_window_now_nolock(sch);
+
+ PR_Unlock(sch->lock);
+
+ return rc;
+}
+
+/* Must be called under sch->lock */
+static int
+schedule_in_window_now_nolock(Schedule *sch)
+{
+ int return_value = 0;
+
+ if (NULL == sch->schedule_list)
+ {
+ /* Absence of a schedule is the same as 0000-2359 0123456 */
+ return_value = 1;
+ }
+ else
+ {
+ schedule_item *si = sch->schedule_list;
+ PRTime now;
+ now = PR_Now();
+ while (NULL != si)
+ {
+ if (time_in_window(now, si))
+ {
+ /* XXX check backoff timers??? */
+ return_value = 1;
+ break;
+ }
+ si = si->next;
+ }
+ }
+
+ return return_value;
+}
+
+
+
+/*
+ * Calculate the next time (expressed as a PRTime) when this
+ * schedule item will change state (from open to close or vice versa).
+ */
+static PRTime
+next_change_time(schedule_item *si, PRTime now, PRBool start)
+{
+ PRUint32 nowsec = seconds_since_midnight(now);
+ PRUint32 sec_til_change;
+ PRUint32 change_time;
+ PRExplodedTime exp;
+ PRInt32 dow = day_of_week(now);
+ unsigned char dow_bit = 1 << dow;
+ unsigned char next_dow;
+
+ if (start) /* we are looking for the next window opening */
+ {
+ change_time = si->start;
+ }
+ else /* we are looking for the next window closing */
+ {
+ /* open range is inclusive - so we need to add a minute if we are looking for close time */
+ change_time = si->end + SECONDS_PER_MINUTE;
+ }
+
+ /* we are replicating today and next change is also today */
+ if ((dow_bit & si->dow) && (nowsec < change_time))
+ {
+ sec_til_change = change_time - nowsec;
+ }
+ else /* not replicating today or the change already occured today */
+ {
+ int i;
+
+ /* find next day when we replicate */
+ for (i = 1; i <= DAYS_PER_WEEK; i++)
+ {
+ next_dow = 1 << ((dow + i) % DAYS_PER_WEEK);
+ if (next_dow & si->dow)
+ break;
+ }
+
+ sec_til_change = change_time + i * SECONDS_PER_DAY - nowsec;
+ }
+
+ PR_ExplodeTime(now, PR_LocalTimeParameters, &exp);
+ exp.tm_sec += sec_til_change;
+
+
+ PR_NormalizeTime(&exp, PR_LocalTimeParameters);
+ return PR_ImplodeTime(&exp);
+}
+
+
+
+/*
+ * Returns the next time that replication is scheduled to occur.
+ * Returns 0 if there is no time in the future that replication
+ * will begin (e.g. there's no schedule at all).
+ */
+PRTime
+schedule_next(Schedule *sch)
+{
+ PRTime tm;
+
+ PR_ASSERT(NULL != sch);
+ PR_Lock(sch->lock);
+
+ tm = schedule_next_nolock (sch, PR_TRUE);
+
+ PR_Unlock(sch->lock);
+
+ return tm;
+}
+
+/* Must be called under sch->lock */
+static PRTime
+schedule_next_nolock (Schedule *sch, PRBool start)
+{
+
+ PRTime closest_time = LL_Zero();
+
+ if (NULL != sch->schedule_list)
+ {
+ schedule_item *si = sch->schedule_list;
+ PRTime now = PR_Now();
+ unsigned char dow = 1 << day_of_week(now);
+
+ while (NULL != si)
+ {
+ PRTime tmp_time;
+
+ /* Check if this item's change time is sooner than the others */
+ tmp_time = next_change_time(si, now, start);
+ if (LL_IS_ZERO(closest_time))
+ {
+ LL_ADD(closest_time, tmp_time, LL_Zero()); /* Really just an asignment */
+ }
+ else if (LL_CMP(tmp_time, <, closest_time))
+ {
+ LL_ADD(closest_time, tmp_time, LL_Zero()); /* Really just an asignment */
+ }
+
+ si = si->next;
+ }
+ }
+
+ return closest_time;
+}
+
+
+
+
+/*
+ * Called by the enclosing object (replsupplier) when a change within the
+ * replicated area has occurred. This allows the scheduler to update its
+ * internal counters, timers, etc. Returns a non-zero value if replication
+ * should commence, zero if it should not.
+ */
+int
+schedule_notify(Schedule *sch, Slapi_PBlock *pb)
+{
+ int return_value = 0;
+
+ return return_value;
+}
+
+
+
+
+/*
+ * Provide a list of attributes which, if changed,
+ * will cause replication to commence as soon as possible. There
+ * is also a flag that tells the scheduler if the update of a
+ * priority attribute should cause the schedule to be overridden,
+ * e.g. if the administrator wants password changes to propagate
+ * even if not in a replication window.
+ *
+ * This function consumes "prio_attrs" and assumes management
+ * of the memory.
+ */
+void
+schedule_set_priority_attributes(Schedule *sch, char **prio_attrs, int override_schedule)
+{
+ PR_ASSERT(NULL != sch);
+ PR_Lock(sch->lock);
+ if (NULL != sch->prio_attrs)
+ {
+ int i;
+ for (i = 0; NULL != prio_attrs[i]; i++) {
+ slapi_ch_free((void **)&sch->prio_attrs[i]);
+ }
+ slapi_ch_free((void **)&sch->prio_attrs);
+ }
+ sch->prio_attrs = prio_attrs;
+ sch->prio_attrs_override_schedule = override_schedule;
+
+ PR_Unlock(sch->lock);
+}
+
+
+
+
+
+/*
+ * Set the time, in seconds, that replication will wait after a change is
+ * available before propagating it. This capability will allow multiple
+ * updates to be coalesced into a single replication session.
+ */
+void
+schedule_set_startup_delay(Schedule *sch, size_t startup_delay)
+{
+ PR_ASSERT(NULL != sch);
+ PR_Lock(sch->lock);
+ sch->startup_delay = startup_delay;
+ PR_Unlock(sch->lock);
+}
+
+
+
+
+
+/*
+ * Set the maximum number of pending changes allowed to accumulate
+ * before a replication session is begun.
+ */
+void
+schedule_set_maximum_backlog(Schedule *sch, size_t max_backlog)
+{
+ PR_ASSERT(NULL != sch);
+ PR_Lock(sch->lock);
+ sch->max_backlog = max_backlog;
+ PR_Unlock(sch->lock);
+}
+
+
+
+
+
+/*
+ * Notify the scheduler that a replication session completed at a certain
+ * time. There is also a status argument that says more about the session's
+ * termination (normal, abnormal), which the scheduler uses in determining
+ * the backoff strategy.
+ */
+void
+schedule_notify_session(Schedule *sch, PRTime session_end_time, unsigned int status)
+{
+ PR_ASSERT(NULL != sch);
+ PR_Lock(sch->lock);
+ sch->last_session_end = session_end_time;
+ sch->last_session_status = status;
+ if (REPLICATION_SESSION_SUCCESS == status)
+ {
+ sch->last_successful_session_end = session_end_time;
+ }
+ PR_Unlock(sch->lock);
+}
+
+/* schedule an event that will fire the next time the update window state
+ changes from open to closed or vice versa */
+static void
+schedule_window_state_change_event (Schedule *sch)
+{
+ time_t wakeup_time;
+ PRTime tm;
+ int window_opened;
+ char *timestr = NULL;
+
+ /* if we have a schedule and a callback function is registerd -
+ register an event with the event queue */
+ if (sch->schedule_list && sch->callback_fn)
+ {
+ /* ONREPL what if the window is really small and by the time we are done
+ with the computation - we cross window boundary.
+ I think we should put some constrains on schedule to avoid that */
+
+ window_opened = schedule_in_window_now_nolock(sch);
+
+ tm = schedule_next_nolock(sch, !window_opened);
+
+ wakeup_time = PRTime2time_t (tm);
+
+ /* schedule the event */
+ sch->pending_event = slapi_eq_once(window_state_changed, sch, wakeup_time);
+
+ timestr = get_timestring(&wakeup_time);
+ slapi_log_error (SLAPI_LOG_REPL, repl_plugin_name, "%s: Update window will %s at %s\n",
+ sch->session_id,
+ window_opened ? "close" : "open", timestr);
+ free_timestring(timestr);
+ timestr = NULL;
+ }
+}
+
+/* this function is called by the even queue the next time
+ the window is opened or closed */
+static void
+window_state_changed (time_t when, void *arg)
+{
+ Schedule *sch = (Schedule*)arg;
+ int open;
+
+ PR_ASSERT (sch);
+
+ PR_Lock(sch->lock);
+
+ open = schedule_in_window_now_nolock(sch);
+
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s: Update window is now %s\n",
+ sch->session_id,
+ open ? "open" : "closed");
+
+ /* schedule next event */
+ schedule_window_state_change_event (sch);
+
+ /* notify the agreement */
+ sch->callback_fn (sch->callback_arg, open);
+
+ PR_Unlock(sch->lock);
+}
+
+/* cancel the event registered with the event queue */
+static void
+unschedule_window_state_change_event (Schedule *sch)
+{
+ if (sch->pending_event)
+ {
+ slapi_eq_cancel(sch->pending_event);
+ sch->pending_event = NULL;
+ }
+}
+
+static time_t
+PRTime2time_t (PRTime tm)
+{
+ PRInt64 rt;
+
+ PR_ASSERT (tm);
+
+ LL_DIV(rt, tm, PR_USEC_PER_SEC);
+
+ return (time_t)rt;
+}
+
+/*
+ * Parse a schedule line.
+ * The format is:
+ * <start>-<end> <day_of_week>
+ * <start> and <end> are in 24-hour time
+ * <day_of_week> is like cron(5): 0 = Sunday, 1 = Monday, etc.
+ *
+ * The schedule item "*" is equivalen to 0000-2359 0123456
+ *
+ * Returns a pointer to a schedule item on success, NULL if the
+ * schedule item cannot be parsed.
+ */
+static schedule_item *
+parse_schedule_value(const Slapi_Value *v)
+{
+#define RANGE_VALID(p, limit) \
+ ((p + 9) < limit && \
+ isdigit(p[0]) && \
+ isdigit(p[1]) && \
+ isdigit(p[2]) && \
+ isdigit(p[3]) && \
+ ('-' == p[4]) && \
+ isdigit(p[5]) && \
+ isdigit(p[6]) && \
+ isdigit(p[7]) && \
+ isdigit(p[8]))
+
+ schedule_item *si = NULL;
+ int valid = 0;
+ const struct berval *sch_bval;
+
+ if (NULL != v && (sch_bval = slapi_value_get_berval(v)) != NULL &&
+ NULL != sch_bval && sch_bval->bv_len > 0 && NULL != sch_bval->bv_val )
+ {
+ char *p = sch_bval->bv_val;
+ char *limit = p + sch_bval->bv_len;
+
+ si = (schedule_item *)slapi_ch_malloc(sizeof(schedule_item));
+ si->next = NULL;
+ si->start = 0UL;
+ si->end = SECONDS_PER_DAY;
+ si->dow = ALL_DAYS;
+
+ if (*p == '*')
+ {
+ valid = 1;
+ goto done;
+ }
+ else
+ {
+ if (RANGE_VALID(p, limit))
+ {
+ si->start = ((strntoul(p, 2, 10) * 60) +
+ strntoul(p + 2, 2, 10)) * 60;
+ p += 5;
+ si->end = ((strntoul(p, 2, 10) * 60) +
+ strntoul(p + 2, 2, 10)) * 60;
+ p += 4;
+
+ /* ONREPL - for now wi don't allow items that span multiple days.
+ See note in the beginning of the file for more details. */
+ /* ONREPL - we should also decide on the minimum of the item size */
+ if (si->start > si->end)
+ {
+ valid = 0;
+ goto done;
+ }
+
+ if (p < limit && ' ' == *p)
+ {
+ /* Specific days of week */
+ si->dow = 0;
+ while (++p < limit)
+ {
+ if (!isdigit(*p))
+ {
+ valid = 0;
+ goto done;
+ }
+ si->dow |= (1 << strntoul(p, 1, 10));
+
+ }
+ }
+ valid = 1;
+ }
+ }
+ }
+
+done:
+ if (!valid)
+ {
+ slapi_ch_free((void **)&si);
+ }
+ return si;
+}
diff --git a/ldap/servers/plugins/replication/repl5_tot_protocol.c b/ldap/servers/plugins/replication/repl5_tot_protocol.c
new file mode 100644
index 00000000..45e91f3b
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_tot_protocol.c
@@ -0,0 +1,372 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_tot_protocol.c */
+/*
+
+ The tot_protocol object implements the DS 5.0 multi-master total update
+ replication protocol, used to (re)populate a replica.
+
+*/
+
+#include "repl.h"
+#include "repl5.h"
+#include "repl5_prot_private.h"
+
+/* Private data structures */
+typedef struct repl5_tot_private
+{
+ Repl_Protocol *rp;
+ Repl_Agmt *ra;
+ PRLock *lock;
+ PRUint32 eventbits;
+} repl5_tot_private;
+
+typedef struct callback_data
+{
+ Private_Repl_Protocol *prp;
+ int rc;
+ unsigned long num_entries;
+ time_t sleep_on_busy;
+ time_t last_busy;
+} callback_data;
+
+/*
+ * Number of window seconds to wait until we programmatically decide
+ * that the replica has got out of BUSY state
+ */
+#define SLEEP_ON_BUSY_WINDOW (10)
+
+/* Helper functions */
+static void get_result (int rc, void *cb_data);
+static int send_entry (Slapi_Entry *e, void *callback_data);
+static void repl5_tot_delete(Private_Repl_Protocol **prp);
+
+/*
+ * Completely refresh a replica. The basic protocol interaction goes
+ * like this:
+ * - Acquire Replica by sending a StartReplicationRequest extop, with the
+ * total update protocol OID and supplier's ruv.
+ * - Send a series of extended operations containing entries.
+ * - send an EndReplicationRequest extended operation
+ */
+static void
+repl5_tot_run(Private_Repl_Protocol *prp)
+{
+ int rc;
+ callback_data cb_data;
+ Slapi_PBlock *pb;
+ LDAPControl **ctrls;
+ PRBool replica_acquired = PR_FALSE;
+ char *hostname = NULL;
+ int portnum = 0;
+ Slapi_DN *area_sdn = NULL;
+ CSN *remote_schema_csn = NULL;
+
+ PR_ASSERT(NULL != prp);
+
+ prp->stopped = 0;
+ if (prp->terminate)
+ {
+ prp->stopped = 1;
+ goto done;
+ }
+
+ conn_set_timeout(prp->conn, agmt_get_timeout(prp->agmt));
+
+ /* acquire remote replica */
+ agmt_set_last_init_start(prp->agmt, current_time());
+ rc = acquire_replica (prp, REPL_NSDS50_TOTAL_PROTOCOL_OID, NULL /* ruv */);
+ /* We never retry total protocol, even in case a transient error.
+ This is because if somebody already updated the replica we don't
+ want to do it again */
+ if (rc != ACQUIRE_SUCCESS)
+ {
+ int optype, ldaprc;
+ conn_get_error(prp->conn, &optype, &ldaprc);
+ agmt_set_last_init_status(prp->agmt, ldaprc,
+ prp->last_acquire_response_code, NULL);
+ goto done;
+ }
+ else if (prp->terminate)
+ {
+ conn_disconnect(prp->conn);
+ prp->stopped = 1;
+ goto done;
+ }
+
+ hostname = agmt_get_hostname(prp->agmt);
+ portnum = agmt_get_port(prp->agmt);
+
+ agmt_set_last_init_status(prp->agmt, 0, 0, "Total schema update in progress");
+ remote_schema_csn = agmt_get_consumer_schema_csn ( prp->agmt );
+ rc = conn_push_schema(prp->conn, &remote_schema_csn);
+ if (CONN_SCHEMA_UPDATED != rc && CONN_SCHEMA_NO_UPDATE_NEEDED != rc)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Warning: unable to "
+ "replicate schema to host %s, port %d. Continuing with "
+ "total update session.\n",
+ hostname, portnum);
+ /* But keep going */
+ agmt_set_last_init_status(prp->agmt, 0, rc, "Total schema update failed");
+ }
+ else
+ {
+ agmt_set_last_init_status(prp->agmt, 0, 0, "Total schema update succeeded");
+ }
+
+ /* ONREPL - big assumption here is that entries a returned in the id order
+ and that the order implies that perent entry is always ahead of the
+ child entry in the list. Otherwise, the consumer would not be
+ properly updated because bulk import at the moment skips orphand entries. */
+ /* XXXggood above assumption may not be valid if orphaned entry moved???? */
+
+ agmt_set_last_init_status(prp->agmt, 0, 0, "Total update in progress");
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Beginning total update of replica "
+ "\"%s\".\n", agmt_get_long_name(prp->agmt));
+ pb = slapi_pblock_new ();
+
+ /* RMREPL - need to send schema here */
+
+ area_sdn = agmt_get_replarea(prp->agmt);
+ /* we need to provide managedsait control so that referral entries can
+ be replicated */
+ ctrls = (LDAPControl **)slapi_ch_calloc (3, sizeof (LDAPControl *));
+ ctrls[0] = create_managedsait_control ();
+ ctrls[1] = create_backend_control(area_sdn);
+
+ slapi_search_internal_set_pb (pb, slapi_sdn_get_dn (area_sdn),
+ LDAP_SCOPE_SUBTREE, "(|(objectclass=ldapsubentry)(objectclass=nstombstone)(nsuniqueid=*))", NULL, 0, ctrls, NULL,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION), 0);
+ cb_data.prp = prp;
+ cb_data.rc = 0;
+ cb_data.num_entries = 0UL;
+ cb_data.sleep_on_busy = 0UL;
+ cb_data.last_busy = current_time ();
+
+ /* this search get all the entries from the replicated area including tombstones
+ and referrals */
+ slapi_search_internal_callback_pb (pb, &cb_data /* callback data */,
+ get_result /* result callback */,
+ send_entry /* entry callback */,
+ NULL /* referral callback*/);
+ slapi_pblock_destroy (pb);
+ agmt_set_last_init_end(prp->agmt, current_time());
+ rc = cb_data.rc;
+ release_replica(prp);
+ slapi_sdn_free(&area_sdn);
+
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error (SLAPI_LOG_REPL, repl_plugin_name, "%s: repl5_tot_run: "
+ "failed to obtain data to send to the consumer; LDAP error - %d\n",
+ agmt_get_long_name(prp->agmt), rc);
+ agmt_set_last_init_status(prp->agmt, rc, 0, "Total update aborted");
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Finished total update of replica "
+ "\"%s\". Sent %d entries.\n", agmt_get_long_name(prp->agmt), cb_data.num_entries);
+ agmt_set_last_init_status(prp->agmt, 0, 0, "Total update succeeded");
+ }
+
+done:
+ slapi_ch_free_string(&hostname);
+ prp->stopped = 1;
+}
+
+static int
+repl5_tot_stop(Private_Repl_Protocol *prp)
+{
+ int return_value;
+ int seconds = 600;
+ PRIntervalTime start, maxwait, now;
+
+ prp->terminate = 1;
+ maxwait = PR_SecondsToInterval(seconds);
+ start = PR_IntervalNow();
+ now = start;
+ while (!prp->stopped && ((now - start) < maxwait))
+ {
+ DS_Sleep(PR_SecondsToInterval(1));
+ now = PR_IntervalNow();
+ }
+ if (!prp->stopped)
+ {
+ /* Isn't listening. Disconnect from the replica. */
+ slapi_log_error (SLAPI_LOG_REPL, repl_plugin_name, "repl5_tot_run: "
+ "protocol not stopped after waiting for %d seconds "
+ "for agreement %s\n", PR_IntervalToSeconds(now-start),
+ agmt_get_long_name(prp->agmt));
+ conn_disconnect(prp->conn);
+ return_value = -1;
+ }
+ else
+ {
+ return_value = 0;
+ }
+
+ return return_value;
+}
+
+
+
+static int
+repl5_tot_status(Private_Repl_Protocol *prp)
+{
+ int return_value = 0;
+ return return_value;
+}
+
+
+
+static void
+repl5_tot_noop(Private_Repl_Protocol *prp)
+{
+ /* noop */
+}
+
+
+Private_Repl_Protocol *
+Repl_5_Tot_Protocol_new(Repl_Protocol *rp)
+{
+ repl5_tot_private *rip = NULL;
+ Private_Repl_Protocol *prp = (Private_Repl_Protocol *)slapi_ch_malloc(sizeof(Private_Repl_Protocol));
+ prp->delete = repl5_tot_delete;
+ prp->run = repl5_tot_run;
+ prp->stop = repl5_tot_stop;
+ prp->status = repl5_tot_status;
+ prp->notify_update = repl5_tot_noop;
+ prp->notify_agmt_changed = repl5_tot_noop;
+ prp->notify_window_opened = repl5_tot_noop;
+ prp->notify_window_closed = repl5_tot_noop;
+ prp->update_now = repl5_tot_noop;
+ if ((prp->lock = PR_NewLock()) == NULL)
+ {
+ goto loser;
+ }
+ if ((prp->cvar = PR_NewCondVar(prp->lock)) == NULL)
+ {
+ goto loser;
+ }
+ prp->stopped = 1;
+ prp->terminate = 0;
+ prp->eventbits = 0;
+ prp->conn = prot_get_connection(rp);
+ prp->agmt = prot_get_agreement(rp);
+ rip = (void *)slapi_ch_malloc(sizeof(repl5_tot_private));
+ rip->rp = rp;
+ prp->private = (void *)rip;
+ prp->replica_acquired = PR_FALSE;
+ return prp;
+loser:
+ repl5_tot_delete(&prp);
+ return NULL;
+}
+
+static void
+repl5_tot_delete(Private_Repl_Protocol **prp)
+{
+}
+
+static
+void get_result (int rc, void *cb_data)
+{
+ PR_ASSERT (cb_data);
+ ((callback_data*)cb_data)->rc = rc;
+}
+
+static
+int send_entry (Slapi_Entry *e, void *cb_data)
+{
+ int rc;
+ Private_Repl_Protocol *prp;
+ BerElement *bere;
+ struct berval *bv;
+ unsigned long *num_entriesp;
+ time_t *sleep_on_busyp;
+ time_t *last_busyp;
+
+ PR_ASSERT (cb_data);
+
+ prp = ((callback_data*)cb_data)->prp;
+ num_entriesp = &((callback_data *)cb_data)->num_entries;
+ sleep_on_busyp = &((callback_data *)cb_data)->sleep_on_busy;
+ last_busyp = &((callback_data *)cb_data)->last_busy;
+ PR_ASSERT (prp);
+
+ if (prp->terminate)
+ {
+ conn_disconnect(prp->conn);
+ prp->stopped = 1;
+ ((callback_data*)cb_data)->rc = -1;
+ return -1;
+ }
+
+ /* skip ruv tombstone - need to do this because it might be
+ more up to date then the data we are sending to the client.
+ RUV is sent separately via the protocol */
+ if (is_ruv_tombstone_entry (e))
+ return 0;
+
+ /* ONREPL we would purge copiedFrom and copyingFrom here but I decided against it.
+ Instead, it will get removed when this replica stops being 4.0 consumer and
+ then propagated to all its consumer */
+
+ /* convert the entry to the on the wire format */
+ bere = entry2bere(e);
+ if (bere == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "%s: send_entry: Encoding Error\n",
+ agmt_get_long_name(prp->agmt));
+ ((callback_data*)cb_data)->rc = -1;
+ return -1;
+ }
+
+ rc = ber_flatten(bere, &bv);
+ ber_free (bere, 1);
+ if (rc != 0)
+ {
+ ((callback_data*)cb_data)->rc = -1;
+ return -1;
+ }
+
+ do {
+ /* push the entry to the consumer */
+ rc = conn_send_extended_operation(prp->conn, REPL_NSDS50_REPLICATION_ENTRY_REQUEST_OID,
+ bv /* payload */, NULL /* retoidp */,
+ NULL /* retdatap */, NULL /* update_control */,
+ NULL /* returned_controls */);
+
+ if (rc == CONN_BUSY) {
+ time_t now = current_time ();
+ if ((now - *last_busyp) < (*sleep_on_busyp + 10)) {
+ *sleep_on_busyp +=5;
+ }
+ else {
+ *sleep_on_busyp = 5;
+ }
+ *last_busyp = now;
+
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Replica \"%s\" is busy. Waiting %ds while"
+ " it finishes processing its current import queue\n",
+ agmt_get_long_name(prp->agmt), *sleep_on_busyp);
+ DS_Sleep(PR_SecondsToInterval(*sleep_on_busyp));
+ }
+ }
+ while (rc == CONN_BUSY);
+
+ ber_bvfree(bv);
+ (*num_entriesp)++;
+
+ if (CONN_OPERATION_SUCCESS == rc) {
+ return 0;
+ } else {
+ ((callback_data*)cb_data)->rc = rc;
+ return -1;
+ }
+}
+
diff --git a/ldap/servers/plugins/replication/repl5_total.c b/ldap/servers/plugins/replication/repl5_total.c
new file mode 100644
index 00000000..66dcc353
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_total.c
@@ -0,0 +1,869 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+
+/*
+ repl5_total.c - code that implements a total replica update.
+
+ The requestValue of the NSDS50ReplicationEntry looks like this:
+
+ requestValue ::= SEQUENCE {
+ uniqueid OCTET STRING,
+ dn LDAPDN,
+ annotatedAttributes AnnotatedAttributeList
+ }
+
+ AnnotatedAttributeList ::= SET OF SEQUENCE {
+ attributeType AttributeDescription,
+ attributeDeletionCSN OCTET STRING OPTIONAL,
+ attributeDeleted BOOLEAN DEFAULT FALSE,
+ annotatedValues SET OF AnnotatedValue
+ }
+
+ AnnotatedValue ::= SEQUENCE {
+ value AttributeValue,
+ valueDeleted BOOLEAN DEFAULT FALSE,
+ valueCSNSet SEQUENCE OF ValueCSN,
+ }
+
+ ValueCSN ::= SEQUENCE {
+ CSNType ENUMERATED {
+ valuePresenceCSN (1),
+ valueDeletionCSN (2),
+ valueDistinguishedCSN (3)
+ }
+ CSN OCTET STRING,
+ }
+*/
+
+#include "repl5.h"
+
+#define CSN_TYPE_VALUE_UPDATED_ON_WIRE 1
+#define CSN_TYPE_VALUE_DELETED_ON_WIRE 2
+#define CSN_TYPE_VALUE_DISTINGUISHED_ON_WIRE 3
+
+/* #define GORDONS_PATENTED_BER_DEBUG 1 */
+#ifdef GORDONS_PATENTED_BER_DEBUG
+#define BER_DEBUG(a) printf(a)
+#else
+#define BER_DEBUG(a)
+#endif
+
+/* Forward declarations */
+static int my_ber_printf_csn(BerElement *ber, const CSN *csn, const CSNType t);
+static int my_ber_printf_value(BerElement *ber, const char *type,
+ const Slapi_Value *value, PRBool deleted);
+static int my_ber_printf_attr (BerElement *ber, Slapi_Attr *attr, PRBool deleted);
+static int my_ber_scanf_attr (BerElement *ber, Slapi_Attr **attr, PRBool *deleted);
+static int my_ber_scanf_value(BerElement *ber, Slapi_Value **value, PRBool *deleted);
+
+/*
+ * Get a Slapi_Entry ready to send over the wire as part of
+ * a total update protocol stream. Convert the entry and all
+ * of its state information to a BerElement which will be the
+ * payload of an extended LDAP operation.
+ *
+ * Entries consist of:
+ * - An entry DN
+ * - A uniqueID
+ * - A set of present attributes, each of which consists of:
+ * - A set of present values, each of which consists of:
+ * - A value
+ * - A set of CSNs
+ * - A set of deleted values, each of which consists of:
+ * - A value
+ * - A set of CSNs
+ * - A set of deleted attibutes, each of which consists of:
+ * - An attribute type
+ * - A set of CSNs. Note that this list of CSNs will always contain exactly one CSN.
+ *
+ * This all gets mashed into one BerElement, ready to be blasted over the wire to
+ * a replica.
+ *
+ */
+BerElement *
+entry2bere(const Slapi_Entry *e)
+{
+ BerElement *ber = NULL;
+ const char *str = NULL;
+ const char *dnstr = NULL;
+ char *type;
+ Slapi_DN *sdn = NULL;
+ Slapi_Attr *attr = NULL, *prev_attr;
+ int rc;
+
+ PR_ASSERT(NULL != e);
+
+ if ((ber = ber_alloc()) == NULL)
+ {
+ goto loser;
+ }
+ BER_DEBUG("{");
+ if (ber_printf(ber, "{") == -1) /* Begin outer sequence */
+ {
+ goto loser;
+ }
+
+ /* Get the entry's uniqueid */
+ if ((str = slapi_entry_get_uniqueid(e)) == NULL)
+ {
+ goto loser;
+ }
+ BER_DEBUG("s(uniqueid)");
+ if (ber_printf(ber, "s", str) == -1)
+ {
+ goto loser;
+ }
+
+ /* Get the entry's DN */
+ if ((sdn = slapi_entry_get_sdn((Slapi_Entry *)e)) == NULL) /* XXXggood had to cast away const */
+ {
+ goto loser;
+ }
+ if ((dnstr = slapi_sdn_get_dn(sdn)) == NULL)
+ {
+ goto loser;
+ }
+ BER_DEBUG("s(dn)");
+ if (ber_printf(ber, "s", dnstr) == -1)
+ {
+ goto loser;
+ }
+
+ /* Next comes the annoted list of the entry's attributes */
+ BER_DEBUG("[");
+ if (ber_printf(ber, "[") == -1) /* Begin set of attributes */
+ {
+ goto loser;
+ }
+ /*
+ * We iterate over all of the non-deleted attributes first.
+ */
+ slapi_entry_first_attr(e, &attr);
+ while (NULL != attr)
+ {
+ /* ONREPL - skip uniqueid attribute since we already sent uniqueid
+ This is a hack; need to figure a better way of storing uniqueid
+ in an entry */
+ slapi_attr_get_type (attr, &type);
+ if (strcasecmp (type, SLAPI_ATTR_UNIQUEID) != 0)
+ {
+ /* Process this attribute */
+ rc = my_ber_printf_attr (ber, attr, PR_FALSE);
+ if (rc != 0)
+ {
+ goto loser;
+ }
+ }
+
+ prev_attr = attr;
+ slapi_entry_next_attr(e, prev_attr, &attr);
+ }
+
+ /*
+ * Now iterate over the deleted attributes.
+ */
+ entry_first_deleted_attribute(e, &attr);
+ while (attr != NULL)
+ {
+ /* Process this attribute */
+ rc = my_ber_printf_attr (ber, attr, PR_TRUE);
+ if (rc != 0)
+ {
+ goto loser;
+ }
+ entry_next_deleted_attribute(e, &attr);
+ }
+ BER_DEBUG("]");
+ if (ber_printf(ber, "]") == -1) /* End set for attributes */
+ {
+ goto loser;
+ }
+ BER_DEBUG("}");
+ if (ber_printf(ber, "}") == -1) /* End sequence for this entry */
+ {
+ goto loser;
+ }
+
+ /* If we get here, everything went ok */
+ BER_DEBUG("\n");
+ goto free_and_return;
+loser:
+ if (NULL != ber)
+ {
+ ber_free(ber, 1);
+ ber = NULL;
+ }
+
+free_and_return:
+ return ber;
+}
+
+
+/*
+ * Helper function - convert a CSN to a string and ber_printf() it.
+ */
+static int
+my_ber_printf_csn(BerElement *ber, const CSN *csn, const CSNType t)
+{
+ char csn_str[CSN_STRSIZE];
+ unsigned long len;
+ int rc = -1;
+ int csn_type_as_ber = -1;
+
+ switch (t)
+ {
+ case CSN_TYPE_VALUE_UPDATED:
+ csn_type_as_ber = CSN_TYPE_VALUE_UPDATED_ON_WIRE;
+ break;
+ case CSN_TYPE_VALUE_DELETED:
+ csn_type_as_ber = CSN_TYPE_VALUE_DELETED_ON_WIRE;
+ break;
+ case CSN_TYPE_VALUE_DISTINGUISHED:
+ csn_type_as_ber = CSN_TYPE_VALUE_DISTINGUISHED_ON_WIRE;
+ break;
+ case CSN_TYPE_ATTRIBUTE_DELETED:
+ break;
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_printf_csn: unknown "
+ "csn type %d encountered.\n", (int)t);
+ return -1;
+ }
+
+ csn_as_string(csn,PR_FALSE,csn_str);
+
+ /* we don't send type for attr csn since there is only one */
+ if (t == CSN_TYPE_ATTRIBUTE_DELETED)
+ {
+ rc = ber_printf(ber, "s", csn_str);
+ BER_DEBUG("s(csn_str)");
+ }
+ else
+ {
+ len = CSN_STRSIZE;
+ rc = ber_printf(ber, "{es}", csn_type_as_ber, csn_str);
+ BER_DEBUG("{e(csn type)s(csn)}");
+ }
+
+ return rc;
+}
+
+
+/*
+ * Send a single annotated attribute value.
+ */
+static int
+my_ber_printf_value(BerElement *ber, const char *type, const Slapi_Value *value, PRBool deleted)
+{
+ const struct berval *bval = NULL;
+ int rc = -1;
+ const CSNSet *csnset;
+ void *cookie;
+ CSN *csn;
+ CSNType t;
+
+ bval = slapi_value_get_berval(value);
+ BER_DEBUG("{o(value)");
+ if (ber_printf(ber, "{o", bval->bv_val, bval->bv_len) == -1) /* Start sequence */
+ {
+ goto done;
+ }
+
+/* if (ber_printf(ber, "o", bval->bv_val, bval->bv_len) == -1)
+ {
+ goto done;
+ } */
+
+ if (deleted)
+ {
+ BER_DEBUG("b(deleted flag)");
+ if (ber_printf (ber, "b", PR_TRUE) == -1)
+ {
+ goto done;
+ }
+ }
+ /* Send value CSN list */
+ BER_DEBUG("{");
+ if (ber_printf(ber, "{") == -1) /* Start set */
+ {
+ goto done;
+ }
+
+ /* Iterate over the sequence of CSNs. */
+ csnset = value_get_csnset (value);
+ if (csnset)
+ {
+ for (cookie = csnset_get_first_csn (csnset, &csn, &t); NULL != cookie;
+ cookie = csnset_get_next_csn (csnset, cookie, &csn, &t))
+ {
+ /* Don't send any adcsns, since that was already sent */
+ if (t != CSN_TYPE_ATTRIBUTE_DELETED)
+ {
+ if (my_ber_printf_csn(ber, csn, t) == -1)
+ {
+ goto done;
+ }
+ }
+ }
+ }
+
+ BER_DEBUG("}");
+ if (ber_printf(ber, "}") == -1) /* End CSN sequence */
+ {
+ goto done;
+ }
+ BER_DEBUG("}");
+ if (ber_printf(ber, "}") == -1) /* End sequence */
+ {
+ goto done;
+ }
+
+ /* Everything's ok */
+ rc = 0;
+
+done:
+ return rc;
+
+}
+
+/* send a single attribute */
+static int
+my_ber_printf_attr (BerElement *ber, Slapi_Attr *attr, PRBool deleted)
+{
+ Slapi_Value *value;
+ char *type;
+ int i;
+ const CSN *csn;
+
+ /* First, send the type */
+ slapi_attr_get_type(attr, &type);
+ BER_DEBUG("{s(type ");
+ BER_DEBUG(type);
+ BER_DEBUG(")");
+ if (ber_printf(ber, "{s", type) == -1) /* Begin sequence for this type */
+ {
+ goto loser;
+ }
+
+ /* Send the attribute deletion CSN if present */
+ csn = attr_get_deletion_csn(attr);
+ if (csn)
+ {
+ if (my_ber_printf_csn(ber, csn, CSN_TYPE_ATTRIBUTE_DELETED) == -1)
+ {
+ goto loser;
+ }
+ }
+
+ /* only send "is deleted" flag for deleted attributes since it defaults to false */
+ if (deleted)
+ {
+ BER_DEBUG("b(del flag)");
+ if (ber_printf (ber, "b", PR_TRUE) == -1)
+ {
+ goto loser;
+ }
+ }
+
+ /*
+ * Iterate through all the values.
+ */
+ BER_DEBUG("[");
+ if (ber_printf(ber, "[") == -1) /* Begin set */
+ {
+ goto loser;
+ }
+
+ /*
+ * Process the non-deleted values first.
+ */
+ i = slapi_attr_first_value(attr, &value);
+ while (i != -1)
+ {
+ if (my_ber_printf_value(ber, type, value, PR_FALSE) == -1)
+ {
+ goto loser;
+ }
+ i= slapi_attr_next_value(attr, i, &value);
+ }
+
+ /*
+ * Now iterate over all of the deleted values.
+ */
+ i= attr_first_deleted_value(attr, &value);
+ while (i != -1)
+ {
+ if (my_ber_printf_value(ber, type, value, PR_TRUE) == -1)
+ {
+ goto loser;
+ }
+ i= attr_next_deleted_value(attr, i, &value);
+ }
+ BER_DEBUG("]");
+ if (ber_printf(ber, "]") == -1) /* End set */
+ {
+ goto loser;
+ }
+
+ BER_DEBUG("}");
+ if (ber_printf(ber, "}") == -1) /* End sequence for this type */
+ {
+ goto loser;
+ }
+
+ return 0;
+loser:
+ return -1;
+}
+
+/*
+ * Get an annotated value from the BerElement. Returns 0 on
+ * success, -1 on failure.
+ */
+static int
+my_ber_scanf_value(BerElement *ber, Slapi_Value **value, PRBool *deleted)
+{
+ struct berval *attrval = NULL;
+ unsigned long len;
+ unsigned long tag;
+ CSN *csn = NULL;
+ char csnstring[CSN_STRSIZE + 1];
+ CSNType csntype;
+ char *lasti;
+
+ PR_ASSERT(ber && value && deleted);
+
+ *value = NULL;
+
+ if (NULL == ber && NULL == value)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 1\n");
+ goto loser;
+ }
+
+ /* Each value is a sequence */
+ if (ber_scanf(ber, "{O", &attrval) == -1)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 2\n");
+ goto loser;
+ }
+ /* Allocate and fill in the attribute value */
+ if ((*value = slapi_value_new_berval(attrval)) == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 3\n");
+ goto loser;
+ }
+
+ /* check if this is a deleted value */
+ if (ber_peek_tag(ber, &len) == LBER_BOOLEAN)
+ {
+ if (ber_scanf(ber, "b", deleted) == -1)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 4\n");
+ goto loser;
+ }
+ }
+
+ else /* default is present value */
+ {
+ *deleted = PR_FALSE;
+ }
+
+ /* Read the sequence of CSNs */
+ for (tag = ber_first_element(ber, &len, &lasti);
+ tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element(ber, &len, lasti))
+ {
+ long csntype_tmp;
+ /* Each CSN is in a sequence that includes a csntype and CSN */
+ len = CSN_STRSIZE;
+ if (ber_scanf(ber, "{es}", &csntype_tmp, csnstring, &len) == -1)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 7 - bval is %s\n", attrval->bv_val);
+ goto loser;
+ }
+ switch (csntype_tmp)
+ {
+ case CSN_TYPE_VALUE_UPDATED_ON_WIRE:
+ csntype = CSN_TYPE_VALUE_UPDATED;
+ break;
+ case CSN_TYPE_VALUE_DELETED_ON_WIRE:
+ csntype = CSN_TYPE_VALUE_DELETED;
+ break;
+ case CSN_TYPE_VALUE_DISTINGUISHED_ON_WIRE:
+ csntype = CSN_TYPE_VALUE_DISTINGUISHED;
+ break;
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Error: preposterous CSN type "
+ "%d received during total update.\n", csntype_tmp);
+ goto loser;
+ }
+ csn = csn_new_by_string(csnstring);
+ if (csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 8\n");
+ goto loser;
+ }
+ value_add_csn(*value, csntype, csn);
+ csn_free (&csn);
+ }
+
+ if (ber_scanf(ber, "}") == -1) /* End of annotated attribute value seq */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "my_ber_scanf_value BAD 10\n");
+ goto loser;
+ }
+
+ if (attrval)
+ ber_bvfree(attrval);
+ return 0;
+
+loser:
+ /* Free any stuff we allocated */
+ if (csn)
+ csn_free (&csn);
+ if (attrval)
+ ber_bvfree(attrval);
+ if (value)
+ {
+ slapi_value_free (value);
+ }
+
+ return -1;
+}
+
+static int
+my_ber_scanf_attr (BerElement *ber, Slapi_Attr **attr, PRBool *deleted)
+{
+ char *attrtype = NULL;
+ CSN *attr_deletion_csn = NULL;
+ PRBool val_deleted;
+ char *lasti;
+ unsigned long len;
+ unsigned long tag;
+ char *str;
+ int rc;
+ Slapi_Value *value;
+
+ PR_ASSERT (ber && attr && deleted);
+
+ /* allocate the attribute */
+ *attr = slapi_attr_new ();
+ if (attr == NULL)
+ {
+ goto loser;
+ }
+
+ if (ber_scanf(ber, "{a", &attrtype) == -1) /* Begin sequence for this attr */
+ {
+ goto loser;
+ }
+
+
+ slapi_attr_init(*attr, attrtype);
+ slapi_ch_free ((void **)&attrtype);
+
+ /* The attribute deletion CSN is next and is optional? */
+ if (ber_peek_tag(ber, &len) == LBER_OCTETSTRING)
+ {
+ if (ber_scanf(ber, "a", &str) == -1)
+ {
+ goto loser;
+ }
+ attr_deletion_csn = csn_new_by_string(str);
+ slapi_ch_free((void **)&str);
+ }
+
+ if (attr_deletion_csn)
+ {
+ rc = attr_set_deletion_csn(*attr, attr_deletion_csn);
+ csn_free (&attr_deletion_csn);
+ if (rc != 0)
+ {
+ goto loser;
+ }
+ }
+
+ /* The "attribute deleted" flag is next, and is optional */
+ if (ber_peek_tag(ber, &len) == LBER_BOOLEAN)
+ {
+ if (ber_scanf(ber, "b", deleted) == -1)
+ {
+ goto loser;
+ }
+ }
+ else /* default is present */
+ {
+ *deleted = PR_FALSE;
+ }
+
+ /* loop over the list of attribute values */
+ for (tag = ber_first_element(ber, &len, &lasti);
+ tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element(ber, &len, lasti))
+ {
+
+ value = NULL;
+ if (my_ber_scanf_value(ber, &value, &val_deleted) == -1)
+ {
+ goto loser;
+ }
+
+ if (val_deleted)
+ {
+ /* Add the value to the attribute */
+ if (attr_add_deleted_value(*attr, value) == -1) /* attr has ownership of value */
+ {
+ goto loser;
+ }
+ }
+ else
+ {
+ /* Add the value to the attribute */
+ if (slapi_attr_add_value(*attr, value) == -1) /* attr has ownership of value */
+ {
+ goto loser;
+ }
+ }
+ if (value)
+ slapi_value_free(&value);
+ }
+
+ if (ber_scanf(ber, "}") == -1) /* End sequence for this attribute */
+ {
+ goto loser;
+ }
+
+ return 0;
+loser:
+ if (*attr)
+ slapi_attr_free (attr);
+ if (value)
+ slapi_value_free (&value);
+
+ return -1;
+}
+
+/*
+ * Extract the payload from a total update extended operation,
+ * decode it, and produce a Slapi_Entry structure representing a new
+ * entry to be added to the local database.
+ */
+static int
+decode_total_update_extop(Slapi_PBlock *pb, Slapi_Entry **ep)
+{
+ BerElement *tmp_bere = NULL;
+ Slapi_Entry *e = NULL;
+ Slapi_Attr *attr = NULL;
+ char *str = NULL;
+ CSN *dn_csn = NULL;
+ struct berval *extop_value = NULL;
+ char *extop_oid = NULL;
+ unsigned long len;
+ char *lasto;
+ unsigned long tag;
+ int rc;
+ PRBool deleted;
+
+ PR_ASSERT(NULL != pb);
+ PR_ASSERT(NULL != ep);
+
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
+
+ if (NULL == extop_oid ||
+ strcmp(extop_oid, REPL_NSDS50_REPLICATION_ENTRY_REQUEST_OID) != 0 ||
+ NULL == extop_value)
+ {
+ /* Bogus */
+ goto loser;
+ }
+
+ if ((tmp_bere = ber_init(extop_value)) == NULL)
+ {
+ goto loser;
+ }
+
+ if ((e = slapi_entry_alloc()) == NULL)
+ {
+ goto loser;
+ }
+
+ if (ber_scanf(tmp_bere, "{") == -1) /* Begin outer sequence */
+ {
+ goto loser;
+ }
+
+ /* The entry's uniqueid is first */
+ if (ber_scanf(tmp_bere, "a", &str) == -1)
+ {
+ goto loser;
+ }
+ slapi_entry_set_uniqueid(e, str);
+ str = NULL; /* Slapi_Entry now owns the uniqueid */
+
+ /* The entry's DN is next */
+ if (ber_scanf(tmp_bere, "a", &str) == -1)
+ {
+ goto loser;
+ }
+ slapi_entry_set_dn(e, str);
+ str = NULL; /* Slapi_Entry now owns the dn */
+
+ /* Get the attributes */
+ for ( tag = ber_first_element( tmp_bere, &len, &lasto );
+ tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element( tmp_bere, &len, lasto ) )
+ {
+
+ if (my_ber_scanf_attr (tmp_bere, &attr, &deleted) != 0)
+ {
+ goto loser;
+ }
+
+ /* Add the attribute to the entry */
+ if (deleted)
+ entry_add_deleted_attribute_wsi(e, attr); /* entry now owns attr */
+ else
+ entry_add_present_attribute_wsi(e, attr); /* entry now owns attr */
+ attr = NULL;
+ }
+
+ if (ber_scanf(tmp_bere, "}") == -1) /* End sequence for this entry */
+ {
+ goto loser;
+ }
+
+ /* Check for ldapsubentries and tombstone entries to set flags properly */
+ slapi_entry_attr_find(e, "objectclass", &attr);
+ if (attr != NULL) {
+ struct berval bv;
+ bv.bv_val = "ldapsubentry";
+ bv.bv_len = strlen(bv.bv_val);
+ if (slapi_attr_value_find(attr, &bv) == 0) {
+ slapi_entry_set_flag(e, SLAPI_ENTRY_LDAPSUBENTRY);
+ }
+ bv.bv_val = SLAPI_ATTR_VALUE_TOMBSTONE;
+ bv.bv_len = strlen(bv.bv_val);
+ if (slapi_attr_value_find(attr, &bv) == 0) {
+ slapi_entry_set_flag(e, SLAPI_ENTRY_FLAG_TOMBSTONE);
+ }
+ }
+
+ /* If we get here, the entry is properly constructed. Return it. */
+
+ rc = 0;
+ *ep = e;
+ goto free_and_return;
+
+loser:
+ rc = -1;
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free((void **)&str);
+
+ if (NULL != dn_csn)
+ {
+ csn_free(&dn_csn);
+ }
+ if (attr != NULL)
+ {
+ slapi_attr_free (&attr);
+ }
+
+ if (NULL != e)
+ {
+ slapi_entry_free (e);
+ }
+ *ep = NULL;
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Error: could not decode extended "
+ "operation containing entry for total update.\n");
+
+free_and_return:
+ if (NULL != tmp_bere)
+ {
+ ber_free(tmp_bere, 1);
+ tmp_bere = NULL;
+ }
+ return rc;
+}
+
+/*
+ * This plugin entry point is called whenever an NSDS50ReplicationEntry
+ * extended operation is received.
+ */
+int
+multimaster_extop_NSDS50ReplicationEntry(Slapi_PBlock *pb)
+{
+ int rc;
+ Slapi_Entry *e = NULL;
+ Slapi_Connection *conn = NULL;
+ int connid, opid;
+
+ connid = 0;
+ slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
+ opid = 0;
+ slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opid);
+
+ /* Decode the extended operation */
+ rc = decode_total_update_extop(pb, &e);
+
+ if (0 == rc)
+ {
+#ifdef notdef
+ /*
+ * Just spew LDIF so we're sure we got it right. Later we'll firehose
+ * this into the database import code
+ */
+ int len;
+ char *str = slapi_entry2str_with_options(e, &len,SLAPI_DUMP_UNIQUEID);
+ puts(str);
+ free(str);
+#endif
+
+ rc = slapi_import_entry (pb, e);
+ /* slapi_import_entry return an LDAP error in case of problem
+ * LDAP_BUSY is used to indicate that the import queue is full
+ * and that flow control must happen to stop the supplier
+ * from sending entries
+ */
+ if ((rc != LDAP_SUCCESS) && (rc != LDAP_BUSY))
+ {
+ const char *dn = slapi_entry_get_dn_const(e);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Error %d: could not import entry dn %s "
+ "for total update operation conn=%d op=%d\n",
+ rc, dn, connid, opid);
+ rc = -1;
+ }
+
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Error %d: could not decode the total update extop "
+ "for total update operation conn=%d op=%d\n",
+ rc, connid, opid);
+ }
+
+ if ((rc != 0) && (rc != LDAP_BUSY))
+ {
+ /* just disconnect from the supplier. bulk import is stopped when
+ connection object is destroyed */
+ slapi_pblock_get (pb, SLAPI_CONNECTION, &conn);
+ if (conn)
+ {
+ slapi_disconnect_server(conn);
+ }
+
+ /* cleanup */
+ if (e)
+ {
+ slapi_entry_free (e);
+ }
+ }
+
+ return rc;
+}
diff --git a/ldap/servers/plugins/replication/repl5_updatedn_list.c b/ldap/servers/plugins/replication/repl5_updatedn_list.c
new file mode 100644
index 00000000..02304d19
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl5_updatedn_list.c
@@ -0,0 +1,243 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl5_updatedn_list.c */
+
+/*
+ This is the internal representation for the list of update DNs in the replica.
+ The list is implemented as a hash table - the key is the normalized DN, and the
+ value is the Slapi_DN representation of the DN
+*/
+
+#include "repl5.h"
+#include "plhash.h"
+
+/* global data */
+
+/* typedef ReplicaUpdateDNList PLHashTable; */
+
+struct repl_enum_data
+{
+ FNEnumDN fn;
+ void *arg;
+};
+
+/* Forward declarations */
+static PRIntn replica_destroy_hash_entry (PLHashEntry *he, PRIntn index, void *arg);
+static PRIntn updatedn_list_enumerate (PLHashEntry *he, PRIntn index, void *hash_data);
+
+static int
+updatedn_compare_dns(const void *d1, const void *d2)
+{
+ return (0 == slapi_sdn_compare((const Slapi_DN *)d1, (const Slapi_DN *)d2));
+}
+
+/* create a new updatedn list - if the entry is given, initialize the list from
+ the replicabinddn values given in the entry */
+ReplicaUpdateDNList
+replica_updatedn_list_new(const Slapi_Entry *entry)
+{
+ /* allocate table */
+ PLHashTable *hash = PL_NewHashTable(4, PL_HashString, PL_CompareStrings,
+ updatedn_compare_dns, NULL, NULL);
+ if (hash == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "replica_new_updatedn_list: "
+ "failed to allocate hash table; NSPR error - %d\n",
+ PR_GetError ());
+ return NULL;
+ }
+
+ if (entry) {
+ Slapi_Attr *attr = NULL;
+ if (!slapi_entry_attr_find(entry, attr_replicaBindDn, &attr)) {
+ Slapi_ValueSet *vs = NULL;
+ slapi_attr_get_valueset(attr, &vs);
+ replica_updatedn_list_replace(hash, vs);
+ slapi_valueset_free(vs);
+ }
+ }
+
+ return (ReplicaUpdateDNList)hash;
+}
+
+void
+replica_updatedn_list_free(ReplicaUpdateDNList list)
+{
+ /* destroy the content */
+ PLHashTable *hash = list;
+ PL_HashTableEnumerateEntries(hash, replica_destroy_hash_entry, NULL);
+
+ if (hash)
+ PL_HashTableDestroy(hash);
+}
+
+void
+replica_updatedn_list_replace(ReplicaUpdateDNList list, const Slapi_ValueSet *vs)
+{
+ replica_updatedn_list_delete(list, NULL); /* delete all values */
+ replica_updatedn_list_add(list, vs);
+}
+
+/* if vs is given, delete only those values - otherwise, delete all values */
+void
+replica_updatedn_list_delete(ReplicaUpdateDNList list, const Slapi_ValueSet *vs)
+{
+ PLHashTable *hash = list;
+ if (!vs || slapi_valueset_count(vs) == 0) { /* just delete everything */
+ PL_HashTableEnumerateEntries(hash, replica_destroy_hash_entry, NULL);
+ } else {
+ Slapi_ValueSet *vs_nc = (Slapi_ValueSet *)vs; /* cast away const */
+ Slapi_Value *val = NULL;
+ int index = 0;
+ for (index = slapi_valueset_first_value(vs_nc, &val); val;
+ index = slapi_valueset_next_value(vs_nc, index, &val)) {
+ Slapi_DN *dn = slapi_sdn_new_dn_byval(slapi_value_get_string(val));
+ /* locate object */
+ Slapi_DN *deldn = (Slapi_DN *)PL_HashTableLookup(hash, slapi_sdn_get_ndn(dn));
+ if (deldn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_updatedn_list_delete: "
+ "update DN with value (%s) is not in the update DN list.\n",
+ slapi_sdn_get_ndn(dn));
+ } else {
+ /* remove from hash */
+ PL_HashTableRemove(hash, slapi_sdn_get_ndn(dn));
+ /* free the pointer */
+ slapi_sdn_free(&deldn);
+ }
+ /* free the temp dn */
+ slapi_sdn_free(&dn);
+ }
+ }
+
+ return;
+}
+
+void
+replica_updatedn_list_add(ReplicaUpdateDNList list, const Slapi_ValueSet *vs)
+{
+ PLHashTable *hash = list;
+ Slapi_ValueSet *vs_nc = (Slapi_ValueSet *)vs; /* cast away const */
+ Slapi_Value *val = NULL;
+ int index = 0;
+
+ PR_ASSERT(list && vs);
+
+ for (index = slapi_valueset_first_value(vs_nc, &val); val;
+ index = slapi_valueset_next_value(vs_nc, index, &val)) {
+ Slapi_DN *dn = slapi_sdn_new_dn_byval(slapi_value_get_string(val));
+ const char *ndn = slapi_sdn_get_ndn(dn);
+
+ /* make sure that the name is unique */
+ if (PL_HashTableLookup(hash, ndn) != NULL)
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "replica_updatedn_list_add: "
+ "update DN with value (%s) already in the update DN list\n",
+ ndn);
+ slapi_sdn_free(&dn);
+ } else {
+ PL_HashTableAdd(hash, ndn, dn);
+ }
+ }
+
+ return;
+}
+
+PRBool
+replica_updatedn_list_ismember(ReplicaUpdateDNList list, const Slapi_DN *dn)
+{
+ PLHashTable *hash = list;
+ PRBool ret = PR_FALSE;
+
+ const char *ndn = slapi_sdn_get_ndn(dn);
+
+ /* Bug 605169 - null ndn would cause core dump */
+ if ( ndn ) {
+ ret = (PRBool)PL_HashTableLookupConst(hash, ndn);
+ }
+
+ return ret;
+}
+
+struct list_to_string_data {
+ char *string;
+ const char *delimiter;
+};
+
+static int
+convert_to_string(Slapi_DN *dn, void *arg)
+{
+ struct list_to_string_data *data = (struct list_to_string_data *)arg;
+ int newlen = strlen(slapi_sdn_get_dn(dn)) + strlen(data->delimiter) + 1;
+ if (data->string) {
+ newlen += strlen(data->string);
+ data->string = slapi_ch_realloc(data->string, newlen);
+ } else {
+ data->string = slapi_ch_calloc(1, newlen);
+ }
+ strcat(data->string, slapi_sdn_get_dn(dn));
+ strcat(data->string, data->delimiter);
+
+ return 1;
+}
+
+/* caller must slapi_ch_free_string the returned string */
+char *
+replica_updatedn_list_to_string(ReplicaUpdateDNList list, const char *delimiter)
+{
+ struct list_to_string_data data;
+ data.string = NULL;
+ data.delimiter = delimiter;
+ replica_updatedn_list_enumerate(list, convert_to_string, (void *)&data);
+ return data.string;
+}
+
+void
+replica_updatedn_list_enumerate(ReplicaUpdateDNList list, FNEnumDN fn, void *arg)
+{
+ PLHashTable *hash = list;
+ struct repl_enum_data data;
+
+ PR_ASSERT (fn);
+
+ data.fn = fn;
+ data.arg = arg;
+
+ PL_HashTableEnumerateEntries(hash, updatedn_list_enumerate, &data);
+}
+
+/* Helper functions */
+
+/* this function called for each hash node during hash destruction */
+static PRIntn
+replica_destroy_hash_entry(PLHashEntry *he, PRIntn index, void *arg)
+{
+ Slapi_DN *dn = NULL;
+
+ if (he == NULL)
+ return HT_ENUMERATE_NEXT;
+
+ dn = (Slapi_DN *)he->value;
+ PR_ASSERT (dn);
+
+ slapi_sdn_free(&dn);
+
+ return HT_ENUMERATE_REMOVE;
+}
+
+static PRIntn
+updatedn_list_enumerate(PLHashEntry *he, PRIntn index, void *hash_data)
+{
+ Slapi_DN *dn = NULL;
+ struct repl_enum_data *data = hash_data;
+
+ dn = (Slapi_DN*)he->value;
+ PR_ASSERT (dn);
+
+ data->fn(dn, data->arg);
+
+ return HT_ENUMERATE_NEXT;
+}
diff --git a/ldap/servers/plugins/replication/repl_add.c b/ldap/servers/plugins/replication/repl_add.c
new file mode 100644
index 00000000..3d47c1db
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_add.c
@@ -0,0 +1,30 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+
+
+/* Add Operation Plugin Functions for legacy replication plugin */
+
+int
+legacy_preop_add( Slapi_PBlock *pb )
+{
+ return legacy_preop( pb, "legacy_preop_add", OP_ADD );
+}
+
+int
+legacy_bepreop_add( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+ return rc;
+}
+
+int
+legacy_postop_add( Slapi_PBlock *pb )
+{
+ return legacy_postop( pb, "legacy_postop_add", OP_ADD );
+}
diff --git a/ldap/servers/plugins/replication/repl_bind.c b/ldap/servers/plugins/replication/repl_bind.c
new file mode 100644
index 00000000..e317e311
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_bind.c
@@ -0,0 +1,48 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+
+#include "slapi-plugin.h"
+#include "repl.h"
+#include "repl5.h"
+
+
+int
+legacy_preop_bind( Slapi_PBlock *pb )
+{
+ int return_value = 0;
+ char *dn = NULL;
+ struct berval *cred = NULL;
+ int method;
+ int one = 1;
+
+ slapi_pblock_get(pb, SLAPI_BIND_METHOD, &method);
+ slapi_pblock_get(pb, SLAPI_BIND_TARGET, &dn);
+ slapi_pblock_get(pb, SLAPI_BIND_CREDENTIALS, &cred);
+
+ if (LDAP_AUTH_SIMPLE == method)
+ {
+ if (legacy_consumer_is_replicationdn(dn) && legacy_consumer_is_replicationpw(cred))
+ {
+ /* Successful bind as replicationdn */
+ void *conn = NULL;
+ consumer_connection_extension *connext = NULL;
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_REPL, REPLICATION_SUBSYSTEM, "legacy_preop_bind: begin\n");
+#endif
+ slapi_pblock_get( pb, SLAPI_CONNECTION, &conn );
+ connext = (consumer_connection_extension*) repl_con_get_ext (REPL_CON_EXT_CONN, conn);
+ if (NULL != connext)
+ {
+ connext->is_legacy_replication_dn = 1;
+ }
+ slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
+ return_value = 1; /* Prevent further processing in front end */
+ }
+ }
+ return return_value;
+
+}
diff --git a/ldap/servers/plugins/replication/repl_compare.c b/ldap/servers/plugins/replication/repl_compare.c
new file mode 100644
index 00000000..34f2b944
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_compare.c
@@ -0,0 +1,34 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+
+int
+legacy_preop_compare( Slapi_PBlock *pb )
+{
+ int is_replicated_operation = 0;
+ char *compare_base = NULL;
+ struct berval **referral = NULL;
+ int return_code = 0;
+ Slapi_DN *basesdn;
+
+ slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
+ slapi_pblock_get(pb, SLAPI_COMPARE_TARGET, &compare_base);
+ basesdn= slapi_sdn_new_dn_byref(compare_base);
+ referral = get_data_source(pb, basesdn, 1, NULL);
+ slapi_sdn_free(&basesdn);
+ if (NULL != referral && !is_replicated_operation)
+ {
+ /*
+ * There is a copyingFrom in this entry or an ancestor.
+ * Return a referral to the supplier, and we're all done.
+ */
+ slapi_send_ldap_result(pb, LDAP_REFERRAL, NULL, NULL, 0, referral);
+ return_code = 1; /* return 1 to prevent further search processing */
+ }
+ return return_code;
+}
diff --git a/ldap/servers/plugins/replication/repl_connext.c b/ldap/servers/plugins/replication/repl_connext.c
new file mode 100644
index 00000000..8b0c0551
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_connext.c
@@ -0,0 +1,91 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl_connext.c - replication extension to the Connection object
+ */
+
+
+#include "repl.h"
+#include "repl5.h"
+
+
+/* ***** Supplier side ***** */
+
+/* NOT NEEDED YET */
+
+/* ***** Consumer side ***** */
+
+/* consumer connection extension constructor */
+void* consumer_connection_extension_constructor (void *object, void *parent)
+{
+ consumer_connection_extension *ext = (consumer_connection_extension*) slapi_ch_malloc (sizeof (consumer_connection_extension));
+ if (ext == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "unable to create replication consumer connection extension - out of memory\n" );
+ }
+ else
+ {
+ ext->is_legacy_replication_dn= 0;
+ ext->repl_protocol_version = REPL_PROTOCOL_UNKNOWN;
+ ext->replica_acquired = NULL;
+ ext->isreplicationsession= 0;
+ ext->supplier_ruv = NULL;
+ ext->connection = NULL;
+ }
+
+ return ext;
+}
+
+/* consumer connection extension destructor */
+void consumer_connection_extension_destructor (void *ext, void *object, void *parent)
+{
+ int connid = 0;
+ if (ext)
+ {
+ /* Check to see if this replication session has acquired
+ * a replica. If so, release it here.
+ */
+ consumer_connection_extension *connext = (consumer_connection_extension *)ext;
+ if (NULL != connext->replica_acquired)
+ {
+ Replica *r = object_get_data ((Object*)connext->replica_acquired);
+ /* If a total update was in progress, abort it */
+ if (REPL_PROTOCOL_50_TOTALUPDATE == connext->repl_protocol_version)
+ {
+ Slapi_PBlock *pb = slapi_pblock_new();
+ const Slapi_DN *repl_root_sdn = replica_get_root(r);
+ PR_ASSERT(NULL != repl_root_sdn);
+ if (NULL != repl_root_sdn)
+ {
+ slapi_pblock_set(pb, SLAPI_CONNECTION, connext->connection);
+ slapi_pblock_set(pb, SLAPI_TARGET_DN, (void*)slapi_sdn_get_dn(repl_root_sdn));
+ slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "Aborting total update in progress for replicated "
+ "area %s connid=%d\n", slapi_sdn_get_dn(repl_root_sdn),
+ connid);
+ slapi_stop_bulk_import(pb);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "consumer_connection_extension_destructor: can't determine root "
+ "of replicated area.\n");
+ }
+ slapi_pblock_destroy(pb);
+ }
+ replica_relinquish_exclusive_access(r, connid, -1);
+ object_release ((Object*)connext->replica_acquired);
+ connext->replica_acquired = NULL;
+ }
+
+ if (connext->supplier_ruv)
+ {
+ ruv_destroy ((RUV **)&connext->supplier_ruv);
+ }
+ connext->connection = NULL;
+ slapi_ch_free((void **)&ext);
+ }
+}
diff --git a/ldap/servers/plugins/replication/repl_controls.c b/ldap/servers/plugins/replication/repl_controls.c
new file mode 100644
index 00000000..ae1cb119
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_controls.c
@@ -0,0 +1,337 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl5.h"
+#include "repl.h" /* For LDAP_CONTROL_REPL_MODRDN_EXTRAMODS */
+
+/*
+ * repl_controls.c - convenience functions for creating and
+ * decoding controls that implement 5.0-style replication
+ * protocol operations.
+ *
+ * TODO: Send modrdn mods with modrdn operation
+ * Fix ber_printf() and ber_scanf() format strings - some are
+ * the wrong types.
+ */
+
+/*
+ * Return a pointer to a NSDS50ReplUpdateInfoControl.
+ * The control looks like this:
+ *
+ * NSDS50ReplUpdateInfoControl ::= SEQUENCE {
+ * uuid OCTET STRING,
+ * csn OCTET STRING,
+ * OPTIONAL [new]superior-uuid OCTET STRING
+ * OPTIONAL modrdn_mods XXXggood WHAT TYPE???
+ * }
+ */
+int
+create_NSDS50ReplUpdateInfoControl(const char *uuid,
+ const char *superior_uuid, const CSN *csn,
+ LDAPMod **modrdn_mods, LDAPControl **ctrlp)
+{
+ int retval;
+ BerElement *tmp_bere = NULL;
+ struct berval tmpval = {0};
+ char csn_str[CSN_STRSIZE];
+
+ if (NULL == ctrlp)
+ {
+ retval = LDAP_PARAM_ERROR;
+ goto loser;
+ }
+ else
+ {
+ if ((tmp_bere = ber_alloc()) == NULL)
+ {
+ retval = LDAP_NO_MEMORY;
+ goto loser;
+ }
+ else
+ {
+ /* Stuff uuid and csn into BerElement */
+ if (ber_printf(tmp_bere, "{") == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+
+ /* Stuff uuid of this entry into BerElement */
+ if (ber_printf(tmp_bere, "s", uuid) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+
+ /* Stuff csn of this change into BerElement */
+ csn_as_string(csn, PR_FALSE, csn_str);
+ if (ber_printf(tmp_bere, "s", csn_str) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+
+ /* If present, stuff uuid of parent entry into BerElement */
+ if (NULL != superior_uuid)
+ {
+ if (ber_printf(tmp_bere, "s", superior_uuid) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ }
+
+ /* If present, add the modrdn mods */
+ if (NULL != modrdn_mods)
+ {
+ int i;
+ if (ber_printf(tmp_bere, "{" ) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ /* for each modification to be performed... */
+ for (i = 0; NULL != modrdn_mods[i]; i++)
+ {
+ if (ber_printf(tmp_bere, "{e{s[V]}}",
+ modrdn_mods[i]->mod_op & ~LDAP_MOD_BVALUES,
+ modrdn_mods[i]->mod_type, modrdn_mods[i]->mod_bvalues ) == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ }
+ if (ber_printf(tmp_bere, "}") == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ }
+
+ /* Close the sequence */
+ if (ber_printf(tmp_bere, "}") == -1)
+ {
+ retval = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+
+ retval = slapi_build_control( REPL_NSDS50_UPDATE_INFO_CONTROL_OID,
+ tmp_bere, 1 /* is critical */, ctrlp);
+ }
+ }
+loser:
+ if (NULL != tmp_bere)
+ {
+ ber_free(tmp_bere, 1);
+ tmp_bere = NULL;
+ }
+ return retval;
+}
+
+
+/*
+ * Destroy a ReplUpdateInfoControl and set the pointer to NULL.
+ */
+void
+destroy_NSDS50ReplUpdateInfoControl(LDAPControl **ctrlp)
+{
+ if (NULL != ctrlp && NULL != *ctrlp)
+ {
+ ldap_control_free(*ctrlp);
+ *ctrlp = NULL;
+ }
+}
+
+
+
+
+/*
+ * Look through the array of controls. If an NSDS50ReplUpdateInfoControl
+ * is present, decode it and return pointers to the broken-out
+ * components. The caller is responsible for freeing pointers to
+ * the returned objects. The caller may indicate that it is not
+ * interested in any of the output parameters by passing NULL
+ * for that parameter.
+ *
+ * Returns 0 if the control is not present, 1 if it is present, and
+ * -1 if an error occurs.
+ */
+int
+decode_NSDS50ReplUpdateInfoControl(LDAPControl **controlsp,
+ char **uuid, char **superior_uuid,
+ CSN **csn, LDAPMod ***modrdn_mods)
+{
+ struct berval *ctl_value = NULL;
+ int iscritical = 0;
+ int rc = -1;
+ struct berval uuid_val = {0};
+ struct berval superior_uuid_val = {0};
+ struct berval csn_val = {0};
+ BerElement *tmp_bere = NULL;
+ Slapi_Mods modrdn_smods;
+ PRBool got_modrdn_mods = PR_FALSE;
+ unsigned long len;
+
+ slapi_mods_init(&modrdn_smods, 4);
+ if (slapi_control_present(controlsp, REPL_NSDS50_UPDATE_INFO_CONTROL_OID,
+ &ctl_value, &iscritical))
+ {
+ if ((tmp_bere = ber_init(ctl_value)) == NULL)
+ {
+ rc = -1;
+ goto loser;
+ }
+ if (ber_scanf(tmp_bere, "{oo", &uuid_val, &csn_val) == -1)
+ {
+ rc = -1;
+ goto loser;
+ }
+ if (ber_peek_tag(tmp_bere, &len) == LBER_OCTETSTRING)
+ {
+ /* The optional superior_uuid is present */
+ if (ber_scanf(tmp_bere, "o", &superior_uuid_val) == -1)
+ {
+ rc = -1;
+ goto loser;
+ }
+ }
+ if (ber_peek_tag(tmp_bere, &len) == LBER_SEQUENCE)
+ {
+ unsigned long emtag, emlen;
+ char *emlast;
+
+ for ( emtag = ber_first_element( tmp_bere, &emlen, &emlast );
+ emtag != LBER_ERROR && emtag != LBER_END_OF_SEQORSET;
+ emtag = ber_next_element( tmp_bere, &emlen, emlast ))
+ {
+ struct berval **embvals;
+ long op;
+ char *type;
+ if ( ber_scanf( tmp_bere, "{i{a[V]}}", &op, &type, &embvals ) == LBER_ERROR )
+ {
+ rc = -1;
+ goto loser;
+ }
+ slapi_mods_add_modbvps(&modrdn_smods, op, type, embvals);
+ free( type );
+ ber_bvecfree( embvals );
+ }
+ got_modrdn_mods = PR_TRUE;
+ }
+ if (ber_scanf(tmp_bere, "}") == -1)
+ {
+ rc = -1;
+ goto loser;
+ }
+
+ if (NULL != uuid)
+ {
+ *uuid = slapi_ch_malloc(uuid_val.bv_len + 1);
+ strncpy(*uuid, uuid_val.bv_val, uuid_val.bv_len);
+ (*uuid)[uuid_val.bv_len] = '\0';
+ }
+
+ if (NULL != csn)
+ {
+ char *csnstr = slapi_ch_malloc(csn_val.bv_len + 1);
+ strncpy(csnstr, csn_val.bv_val, csn_val.bv_len);
+ csnstr[csn_val.bv_len] = '\0';
+ *csn = csn_new_by_string(csnstr);
+ slapi_ch_free((void **)&csnstr);
+ }
+
+ if (NULL != superior_uuid && NULL != superior_uuid_val.bv_val)
+ {
+ *superior_uuid = slapi_ch_malloc(superior_uuid_val.bv_len + 1);
+ strncpy(*superior_uuid, superior_uuid_val.bv_val,
+ superior_uuid_val.bv_len);
+ (*superior_uuid)[superior_uuid_val.bv_len] = '\0';
+ }
+
+ if (NULL != modrdn_mods && got_modrdn_mods)
+ {
+ *modrdn_mods = slapi_mods_get_ldapmods_passout(&modrdn_smods);
+ }
+ slapi_mods_done(&modrdn_smods);
+
+ rc = 1;
+ }
+ else
+ {
+ rc = 0;
+ }
+loser:
+ /* XXXggood free CSN here if allocated */
+
+ if (NULL != tmp_bere)
+ {
+ ber_free(tmp_bere, 1);
+ tmp_bere = NULL;
+ }
+ if (NULL != uuid_val.bv_val)
+ {
+ ldap_memfree(uuid_val.bv_val);
+ uuid_val.bv_val = NULL;
+ }
+ if (NULL != superior_uuid_val.bv_val)
+ {
+ ldap_memfree(superior_uuid_val.bv_val);
+ superior_uuid_val.bv_val = NULL;
+ }
+ if (NULL != csn_val.bv_val)
+ {
+ ldap_memfree(csn_val.bv_val);
+ csn_val.bv_val = NULL;
+ }
+ return rc;
+}
+
+
+
+void
+add_repl_control_mods( Slapi_PBlock *pb, Slapi_Mods *smods )
+{
+ struct berval *embvp;
+ LDAPControl **controls = NULL;
+
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &controls);
+ if ( slapi_control_present( controls,
+ LDAP_CONTROL_REPL_MODRDN_EXTRAMODS,
+ &embvp, NULL ))
+ {
+ if ( embvp != NULL && embvp->bv_len > 0 && embvp->bv_val != NULL )
+ {
+ /* Parse the extramods stuff */
+ long op;
+ char *type;
+ unsigned long emlen;
+ unsigned long emtag;
+ char *emlast;
+ BerElement *ember = ber_init( embvp );
+ if ( ember != NULL )
+ {
+ for ( emtag = ber_first_element( ember, &emlen, &emlast );
+ emtag != LBER_ERROR && emtag != LBER_END_OF_SEQORSET;
+ emtag = ber_next_element( ember, &emlen, emlast ))
+ {
+ struct berval **embvals;
+ if ( ber_scanf( ember, "{i{a[V]}}", &op, &type, &embvals ) == LBER_ERROR )
+ {
+ continue;
+ /* GGOODREPL I suspect this will cause two sets of lastmods attr values
+ to end up in the entry. We need to remove the old ones.
+ */
+ }
+ slapi_mods_add_modbvps( smods, op, type, embvals);
+ free( type );
+ ber_bvecfree( embvals );
+ }
+ }
+ ber_free( ember, 1 );
+ }
+ }
+}
diff --git a/ldap/servers/plugins/replication/repl_delete.c b/ldap/servers/plugins/replication/repl_delete.c
new file mode 100644
index 00000000..6f8e07df
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_delete.c
@@ -0,0 +1,26 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+
+int
+legacy_preop_delete( Slapi_PBlock *pb )
+{
+ return legacy_preop(pb, "legacy_preop_delete", OP_DELETE);
+}
+
+int
+legacy_bepreop_delete( Slapi_PBlock *pb )
+{
+ return 0; /* OK */
+}
+
+int
+legacy_postop_delete( Slapi_PBlock *pb )
+{
+ return legacy_postop(pb, "legacy_preop_delete", OP_DELETE);
+}
diff --git a/ldap/servers/plugins/replication/repl_entry.c b/ldap/servers/plugins/replication/repl_entry.c
new file mode 100644
index 00000000..83bf2857
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_entry.c
@@ -0,0 +1,38 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+
+static int dumping_to_ldif= 0;
+static int doing_replica_init= 0;
+static char **include_suffix= NULL;
+
+/*
+ * This is passed the slapd command line arguments.
+ */
+void
+repl_entry_init(int argc, char** argv)
+{
+ int i;
+ for(i=1;i<argc;i++)
+ {
+ if(strcmp(argv[i],"db2ldif")==0)
+ {
+ dumping_to_ldif= 1;
+ }
+ if(strcmp(argv[i],"-r")==0)
+ {
+ doing_replica_init= 1;
+ }
+ if(strcmp(argv[i],"-s")==0)
+ {
+ char *s= slapi_dn_normalize ( slapi_ch_strdup(argv[i+1]) );
+ charray_add(&include_suffix,s);
+ i++;
+ }
+ }
+}
diff --git a/ldap/servers/plugins/replication/repl_ext.c b/ldap/servers/plugins/replication/repl_ext.c
new file mode 100644
index 00000000..4ad28726
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_ext.c
@@ -0,0 +1,113 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl_ext.c - manages operation extensions created by the
+ * replication system
+ */
+
+
+#include "repl.h"
+
+/* structure with information for each extension */
+typedef struct repl_ext
+{
+ char *object_name; /* name of the object extended */
+ int object_type; /* handle to the extended object */
+ int handle; /* extension handle */
+} repl_ext;
+
+/* ----------------------------- Supplier ----------------------------- */
+
+static repl_ext repl_sup_ext_list [REPL_EXT_ALL];
+
+/* initializes replication extensions */
+void repl_sup_init_ext ()
+{
+ int rc;
+
+ /* populate the extension list */
+ repl_sup_ext_list[REPL_SUP_EXT_OP].object_name = SLAPI_EXT_OPERATION;
+
+ rc = slapi_register_object_extension(repl_plugin_name,
+ SLAPI_EXT_OPERATION,
+ supplier_operation_extension_constructor,
+ supplier_operation_extension_destructor,
+ &repl_sup_ext_list[REPL_SUP_EXT_OP].object_type,
+ &repl_sup_ext_list[REPL_SUP_EXT_OP].handle);
+
+ if(rc!=0)
+ {
+ PR_ASSERT(0); /* JCMREPL Argh */
+ }
+}
+
+void* repl_sup_get_ext (ext_type type, void *object)
+{
+ /* find the requested extension */
+ repl_ext ext = repl_sup_ext_list [type];
+
+ void* data = slapi_get_object_extension(ext.object_type, object, ext.handle);
+
+ return data;
+}
+
+/* ----------------------------- Consumer ----------------------------- */
+
+static repl_ext repl_con_ext_list [REPL_EXT_ALL];
+
+/* initializes replication extensions */
+void repl_con_init_ext ()
+{
+ int rc;
+
+ /* populate the extension list */
+ repl_con_ext_list[REPL_CON_EXT_OP].object_name = SLAPI_EXT_OPERATION;
+ rc = slapi_register_object_extension(repl_plugin_name,
+ SLAPI_EXT_OPERATION,
+ consumer_operation_extension_constructor,
+ consumer_operation_extension_destructor,
+ &repl_con_ext_list[REPL_CON_EXT_OP].object_type,
+ &repl_con_ext_list[REPL_CON_EXT_OP].handle);
+ if(rc!=0)
+ {
+ PR_ASSERT(0); /* JCMREPL Argh */
+ }
+
+ repl_con_ext_list[REPL_CON_EXT_CONN].object_name = SLAPI_EXT_CONNECTION;
+ rc = slapi_register_object_extension(repl_plugin_name,
+ SLAPI_EXT_CONNECTION,
+ consumer_connection_extension_constructor,
+ consumer_connection_extension_destructor,
+ &repl_con_ext_list[REPL_CON_EXT_CONN].object_type,
+ &repl_con_ext_list[REPL_CON_EXT_CONN].handle);
+ if(rc!=0)
+ {
+ PR_ASSERT(0); /* JCMREPL Argh */
+ }
+
+ repl_con_ext_list[REPL_CON_EXT_MTNODE].object_name = SLAPI_EXT_MTNODE;
+ rc = slapi_register_object_extension(repl_plugin_name,
+ SLAPI_EXT_MTNODE,
+ multimaster_mtnode_extension_constructor,
+ multimaster_mtnode_extension_destructor,
+ &repl_con_ext_list[REPL_CON_EXT_MTNODE].object_type,
+ &repl_con_ext_list[REPL_CON_EXT_MTNODE].handle);
+ if(rc!=0)
+ {
+ PR_ASSERT(0); /* JCMREPL Argh */
+ }
+}
+
+void* repl_con_get_ext (ext_type type, void *object)
+{
+ /* find the requested extension */
+ repl_ext ext = repl_con_ext_list [type];
+
+ void* data = slapi_get_object_extension(ext.object_type, object, ext.handle);
+
+ return data;
+}
+
+
diff --git a/ldap/servers/plugins/replication/repl_extop.c b/ldap/servers/plugins/replication/repl_extop.c
new file mode 100644
index 00000000..b13ad6ac
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_extop.c
@@ -0,0 +1,1134 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+#include "repl5.h"
+#include "repl5_prot_private.h"
+#include "cl5_api.h"
+
+
+/*
+ * repl_extop.c - there are two types of functions in this file:
+ * - Code that implements an extended operation plugin.
+ * The replication DLL arranges for this code to
+ * be called when a StartNSDS50ReplicationRequest
+ * or an EndNSDS50ReplicationRequest extended operation
+ * is received.
+ * - Code that sends extended operations on an already-
+ * established client connection.
+ *
+ * The requestValue portion of the StartNSDS50ReplicationRequest
+ * looks like this:
+ *
+ * requestValue ::= SEQUENCE {
+ * replProtocolOID LDAPOID,
+ * replicatedTree LDAPDN,
+ supplierRUV OCTET STRING
+ * referralURLs SET of LDAPURL OPTIONAL
+ * csn OCTET STRING OPTIONAL
+ * }
+ *
+ */
+static int check_replica_id_uniqueness(Replica *replica, RUV *supplier_ruv);
+
+static int
+encode_ruv (BerElement *ber, const RUV *ruv)
+{
+ int rc = LDAP_SUCCESS;
+ struct berval **bvals = NULL;
+
+ PR_ASSERT (ber);
+ PR_ASSERT (ruv);
+
+ if (ruv_to_bervals(ruv, &bvals) != 0)
+ {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ if (ber_printf(ber, "[V]", bvals) == -1)
+ {
+ rc = LDAP_ENCODING_ERROR;
+ goto done;
+ }
+
+ rc = LDAP_SUCCESS;
+
+done:
+ if (bvals)
+ ber_bvecfree (bvals);
+
+ return rc;
+}
+
+static struct berval *
+create_NSDS50ReplicationExtopPayload(const char *protocol_oid,
+ const char *repl_root, char **extra_referrals, CSN *csn,
+ int send_end)
+{
+ struct berval *req_data = NULL;
+ BerElement *tmp_bere = NULL;
+ int rc = 0;
+ const char *csnstr = NULL;
+ Object *repl_obj, *ruv_obj = NULL;
+ Replica *repl;
+ RUV *ruv;
+ Slapi_DN *sdn;
+
+ PR_ASSERT(protocol_oid != NULL || send_end);
+ PR_ASSERT(repl_root != NULL);
+
+ /* Create the request data */
+
+ if ((tmp_bere = der_alloc()) == NULL)
+ {
+ rc = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ if (!send_end)
+ {
+ if (ber_printf(tmp_bere, "{ss", protocol_oid, repl_root) == -1)
+ {
+ rc = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ }
+ else
+ {
+ if (ber_printf(tmp_bere, "{s", repl_root) == -1)
+ {
+ rc = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ }
+
+ sdn = slapi_sdn_new_dn_byref(repl_root);
+ repl_obj = replica_get_replica_from_dn (sdn);
+ if (repl_obj == NULL)
+ {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto loser;
+ }
+
+ repl = (Replica*)object_get_data (repl_obj);
+ PR_ASSERT (repl);
+ ruv_obj = replica_get_ruv (repl);
+ if (ruv_obj == NULL)
+ {
+ rc = LDAP_OPERATIONS_ERROR;
+ goto loser;
+ }
+ ruv = object_get_data(ruv_obj);
+ PR_ASSERT(ruv);
+
+ /* send supplier's ruv so that consumer can build its own referrals.
+ In case of total protocol, it is also used as consumer's ruv once
+ protocol successfully completes */
+ /* We need to encode and send each time the local ruv in case we have changed it */
+ rc = encode_ruv (tmp_bere, ruv);
+ if (rc != 0)
+ {
+ goto loser;
+ }
+
+ if (!send_end)
+ {
+ char s[CSN_STRSIZE];
+ ReplicaId rid;
+ char *local_replica_referral[2] = {0};
+ char **referrals_to_send = NULL;
+ /* Add the referral URL(s), if present */
+ rid = replica_get_rid(repl);
+ if (!ruv_contains_replica(ruv, rid))
+ {
+ /*
+ * In the event that there is no RUV component for this replica (e.g.
+ * if the database was just loaded from LDIF and no local CSNs have been
+ * generated), then we need to explicitly add this server to the list
+ * of referrals, since it wouldn't have been sent with the RUV.
+ */
+ local_replica_referral[0] = (char *)multimaster_get_local_purl(); /* XXXggood had to cast away const */
+ }
+ charray_merge(&referrals_to_send, extra_referrals, 0);
+ charray_merge(&referrals_to_send, local_replica_referral, 0);
+ if (NULL != referrals_to_send)
+ {
+ if (ber_printf(tmp_bere, "[v]", referrals_to_send) == -1)
+ {
+ rc = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ slapi_ch_free((void **)&referrals_to_send);
+ }
+ /* Add the CSN */
+ PR_ASSERT(NULL != csn);
+ if (ber_printf(tmp_bere, "s", csnstr = csn_as_string(csn,PR_FALSE,s)) == -1)
+ {
+ rc = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+ }
+
+ if (ber_printf(tmp_bere, "}") == -1)
+ {
+ rc = LDAP_ENCODING_ERROR;
+ goto loser;
+ }
+
+ if (ber_flatten(tmp_bere, &req_data) == -1)
+ {
+ rc = LDAP_LOCAL_ERROR;
+ goto loser;
+ }
+ /* Success */
+ goto done;
+
+loser:
+ /* Free stuff we allocated */
+ if (NULL != req_data)
+ {
+ ber_bvfree(req_data); req_data = NULL;
+ }
+
+done:
+ if (NULL != tmp_bere)
+ {
+ ber_free(tmp_bere, 1); tmp_bere = NULL;
+ }
+ if (NULL != sdn)
+ {
+ slapi_sdn_free (&sdn); /* Put on stack instead of allocating? */
+ }
+ if (NULL != repl_obj)
+ {
+ object_release (repl_obj);
+ }
+ if (NULL != ruv_obj)
+ {
+ object_release (ruv_obj);
+ }
+ return req_data;
+}
+
+
+struct berval *
+NSDS50StartReplicationRequest_new(const char *protocol_oid,
+ const char *repl_root, char **extra_referrals, CSN *csn)
+{
+ return(create_NSDS50ReplicationExtopPayload(protocol_oid,
+ repl_root, extra_referrals, csn, 0));
+}
+
+struct berval *
+NSDS50EndReplicationRequest_new(char *repl_root)
+{
+ return(create_NSDS50ReplicationExtopPayload(NULL, repl_root, NULL, NULL, 1));
+}
+
+static int
+decode_ruv (BerElement *ber, RUV **ruv)
+{
+ int rc = -1;
+ struct berval **bvals = NULL;
+
+ PR_ASSERT (ber && ruv);
+
+ if (ber_scanf(ber, "[V]", &bvals) == -1)
+ {
+ goto done;
+ }
+
+ if (ruv_init_from_bervals(bvals, ruv) != 0)
+ {
+ goto done;
+ }
+
+ rc = 0;
+done:
+ if (bvals)
+ ber_bvecfree (bvals);
+
+ return rc;
+}
+
+/*
+ * Decode an NSDS50 Start Replication Request extended
+ * operation. Returns 0 on success, -1 on decoding error.
+ * The caller is responsible for freeing protocol_oid,
+ * repl_root, referrals, and csn.
+ */
+static int
+decode_startrepl_extop(Slapi_PBlock *pb, char **protocol_oid, char **repl_root,
+ RUV **supplier_ruv, char ***extra_referrals, char **csnstr)
+{
+ char *extop_oid = NULL;
+ struct berval *extop_value = NULL;
+ BerElement *tmp_bere = NULL;
+ unsigned long len;
+ int rc = 0;
+
+ PR_ASSERT (pb && protocol_oid && repl_root && supplier_ruv && extra_referrals && csnstr);
+
+ *protocol_oid = NULL;
+ *repl_root = NULL;
+ *supplier_ruv = NULL;
+ *extra_referrals = NULL;
+ *csnstr = NULL;
+
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
+
+ if (NULL == extop_oid ||
+ strcmp(extop_oid, REPL_START_NSDS50_REPLICATION_REQUEST_OID) != 0 ||
+ NULL == extop_value)
+ {
+ /* bogus */
+ rc = -1;
+ goto free_and_return;
+ }
+
+ if ((tmp_bere = ber_init(extop_value)) == NULL)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+ if (ber_scanf(tmp_bere, "{") == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+ /* Get the required protocol OID and root of replicated subtree */
+ if (ber_get_stringa(tmp_bere, protocol_oid) == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+ if (ber_get_stringa(tmp_bere, repl_root) == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+
+ /* get supplier's ruv */
+ if (decode_ruv (tmp_bere, supplier_ruv) == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+
+ /* Get the optional set of referral URLs */
+ if (ber_peek_tag(tmp_bere, &len) == LBER_SET)
+ {
+ if (ber_scanf(tmp_bere, "[v]", extra_referrals) == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+ }
+ /* Get the optional CSN */
+ if (ber_peek_tag(tmp_bere, &len) == LBER_OCTETSTRING)
+ {
+ if (ber_get_stringa(tmp_bere, csnstr) == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+ }
+ if (ber_scanf(tmp_bere, "}") == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+
+free_and_return:
+ if (-1 == rc)
+ {
+ /* Free everything when error encountered */
+
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free ((void**)protocol_oid);
+ slapi_ch_free ((void**)repl_root);
+ slapi_ch_free ((void **)extra_referrals);
+ slapi_ch_free ((void**)csnstr);
+
+ if (*supplier_ruv)
+ {
+ ruv_destroy (supplier_ruv);
+ }
+
+ }
+ if (NULL != tmp_bere)
+ {
+ ber_free(tmp_bere, 1);
+ tmp_bere = NULL;
+ }
+
+ return rc;
+}
+
+
+/*
+ * Decode an NSDS50 End Replication Request extended
+ * operation. Returns 0 on success, -1 on decoding error.
+ * The caller is responsible for freeing repl_root.
+ */
+static int
+decode_endrepl_extop(Slapi_PBlock *pb, char **repl_root)
+{
+ char *extop_oid = NULL;
+ struct berval *extop_value = NULL;
+ BerElement *tmp_bere = NULL;
+ int rc = 0;
+
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_OID, &extop_oid);
+ slapi_pblock_get(pb, SLAPI_EXT_OP_REQ_VALUE, &extop_value);
+
+ if (NULL == extop_oid ||
+ strcmp(extop_oid, REPL_END_NSDS50_REPLICATION_REQUEST_OID) != 0 ||
+ NULL == extop_value)
+ {
+ /* bogus */
+ rc = -1;
+ goto free_and_return;
+ }
+
+ if ((tmp_bere = ber_init(extop_value)) == NULL)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+ if (ber_scanf(tmp_bere, "{") == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+ /* Get the required root of replicated subtree */
+ if (ber_get_stringa(tmp_bere, repl_root) == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+ if (ber_scanf(tmp_bere, "}") == -1)
+ {
+ rc = -1;
+ goto free_and_return;
+ }
+
+free_and_return:
+ if (NULL != tmp_bere)
+ {
+ ber_free(tmp_bere, 1);
+ tmp_bere = NULL;
+ }
+
+ return rc;
+}
+
+
+
+
+/*
+ * Decode an NSDS50ReplicationResponse extended response.
+ * The extended response just contains a sequence that contains:
+ * 1) An integer response code
+ * 2) An optional array of bervals representing the consumer
+ * replica's update vector
+ * Returns 0 on success, or -1 if the response could not be parsed.
+ */
+int
+decode_repl_ext_response(struct berval *data, int *response_code,
+ struct berval ***ruv_bervals)
+{
+ BerElement *tmp_bere = NULL;
+ int return_value = 0;
+
+ PR_ASSERT(NULL != response_code);
+ PR_ASSERT(NULL != ruv_bervals);
+
+ if (NULL == data || NULL == response_code || NULL == ruv_bervals)
+ {
+ return_value = -1;
+ }
+ else
+ {
+ unsigned long len, tag = 0;
+ long temp_response_code = 0;
+ *ruv_bervals = NULL;
+ if ((tmp_bere = ber_init(data)) == NULL)
+ {
+ return_value = -1;
+ }
+ else if (ber_scanf(tmp_bere, "{e", &temp_response_code) == -1)
+ {
+ return_value = -1;
+ }
+ else if ((tag = ber_peek_tag(tmp_bere, &len)) == LBER_SEQUENCE)
+ {
+ if (ber_scanf(tmp_bere, "{V}}", ruv_bervals) == -1)
+ {
+ return_value = -1;
+ }
+ } else if (ber_scanf(tmp_bere, "}") == -1)
+ {
+ return_value = -1;
+ }
+ *response_code = (int)temp_response_code;
+ }
+ if (0 != return_value)
+ {
+ if (NULL != *ruv_bervals)
+ {
+ ber_bvecfree(*ruv_bervals);
+ }
+ }
+ if (NULL != tmp_bere)
+ {
+ ber_free(tmp_bere, 1); tmp_bere = NULL;
+ }
+ return return_value;
+}
+
+
+/*
+ * This plugin entry point is called whenever a
+ * StartNSDS50ReplicationRequest is received.
+ */
+int
+multimaster_extop_StartNSDS50ReplicationRequest(Slapi_PBlock *pb)
+{
+ int return_value = SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
+ int response = 0;
+ int rc = 0;
+ BerElement *resp_bere = NULL;
+ struct berval *resp_bval = NULL;
+ char *protocol_oid = NULL;
+ char *repl_root = NULL;
+ Slapi_DN *repl_root_sdn = NULL;
+ char **referrals = NULL;
+ Object *replica_object = NULL;
+ Replica *replica = NULL;
+ void *conn;
+ consumer_connection_extension *connext = NULL;
+ CSN *mycsn = NULL;
+ char *replicacsnstr = NULL;
+ CSN *replicacsn = NULL;
+ int zero = 0;
+ int one = 1;
+ RUV *ruv = NULL;
+ struct berval **ruv_bervals = NULL;
+ CSNGen *gen = NULL;
+ Object *gen_obj = NULL;
+ Slapi_DN *bind_sdn = NULL;
+ char *bind_dn = NULL;
+ Object *ruv_object = NULL;
+ RUV *supplier_ruv = NULL;
+ int connid, opid;
+ PRBool isInc = PR_FALSE; /* true if incremental update */
+ char *locking_purl = NULL; /* the supplier contacting us */
+ char *current_purl = NULL; /* the supplier which already has exclusive access */
+ char locking_session[24];
+
+ /* Decode the extended operation */
+ if (decode_startrepl_extop(pb, &protocol_oid, &repl_root, &supplier_ruv,
+ &referrals, &replicacsnstr) == -1)
+ {
+ response = NSDS50_REPL_DECODING_ERROR;
+ goto send_response;
+ }
+ if (NULL == protocol_oid || NULL == repl_root || NULL == replicacsnstr)
+ {
+ response = NSDS50_REPL_DECODING_ERROR;
+ goto send_response;
+ }
+
+ connid = 0;
+ slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
+ opid = 0;
+ slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opid);
+
+ /*
+ * Get a hold of the connection extension object and
+ * make sure it's there.
+ */
+ slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
+ connext = (consumer_connection_extension *)repl_con_get_ext(
+ REPL_CON_EXT_CONN, conn);
+ if (NULL == connext)
+ {
+ /* Something bad happened. Don't go any further */
+ response = NSDS50_REPL_INTERNAL_ERROR;
+ goto send_response;
+ }
+
+ /* Verify that we know about this replication protocol OID */
+ if (strcmp(protocol_oid, REPL_NSDS50_INCREMENTAL_PROTOCOL_OID) == 0)
+ {
+ /* Stash info that this is an incremental update session */
+ connext->repl_protocol_version = REPL_PROTOCOL_50_INCREMENTAL;
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "conn=%d op=%d repl=\"%s\": Begin incremental protocol\n",
+ connid, opid, repl_root);
+ isInc = PR_TRUE;
+ }
+ else if (strcmp(protocol_oid, REPL_NSDS50_TOTAL_PROTOCOL_OID) == 0)
+ {
+ /* Stash info that this is a total update session */
+ if (NULL != connext)
+ {
+ connext->repl_protocol_version = REPL_PROTOCOL_50_TOTALUPDATE;
+ }
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "conn=%d op=%d repl=\"%s\": Begin total protocol\n",
+ connid, opid, repl_root);
+ isInc = PR_FALSE;
+ }
+ else
+ {
+ /* Unknown replication protocol */
+ response = NSDS50_REPL_UNKNOWN_UPDATE_PROTOCOL;
+ goto send_response;
+ }
+
+ /* Verify that repl_root names a valid replicated area */
+ if ((repl_root_sdn = slapi_sdn_new_dn_byval(repl_root)) == NULL)
+ {
+ response = NSDS50_REPL_INTERNAL_ERROR;
+ goto send_response;
+ }
+
+ /* see if this replica is being configured and wait for it */
+ if (replica_is_being_configured(repl_root))
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "conn=%d op=%d replica=\"%s\": "
+ "Replica is being configured: try again later\n",
+ connid, opid, repl_root);
+ response = NSDS50_REPL_REPLICA_BUSY;
+ goto send_response;
+ }
+
+ replica_object = replica_get_replica_from_dn(repl_root_sdn);
+ if (NULL != replica_object)
+ {
+ replica = object_get_data(replica_object);
+ }
+ if (NULL == replica)
+ {
+ response = NSDS50_REPL_NO_SUCH_REPLICA;
+ goto send_response;
+ }
+
+ /* check that this replica is not a 4.0 consumer */
+ if (replica_is_legacy_consumer (replica))
+ {
+ response = NSDS50_REPL_LEGACY_CONSUMER;
+ goto send_response;
+ }
+
+ /* Check that bind dn is authorized to supply replication updates */
+ slapi_pblock_get(pb, SLAPI_CONN_DN, &bind_dn); /* bind_dn is allocated */
+ bind_sdn = slapi_sdn_new_dn_passin(bind_dn);
+ if (replica_is_updatedn(replica, bind_sdn) == PR_FALSE)
+ {
+ response = NSDS50_REPL_PERMISSION_DENIED;
+ goto send_response;
+ }
+
+ /* Check received CSN for clock skew */
+ gen_obj = replica_get_csngen(replica);
+ if (NULL != gen_obj)
+ {
+ gen = object_get_data(gen_obj);
+ if (NULL != gen)
+ {
+ if (csngen_new_csn(gen, &mycsn, PR_FALSE /* notify */) == CSN_SUCCESS)
+ {
+ replicacsn = csn_new_by_string(replicacsnstr);
+ if (NULL != replicacsn)
+ {
+ /* ONREPL - we used to manage clock skew here. However, csn generator
+ code already does it. The csngen also manages local skew caused by
+ system clock reset, so to keep it consistent, I removed code from here */
+ time_t diff = 0L;
+ diff = csn_time_difference(mycsn, replicacsn);
+ if (diff > 0)
+ {
+ /* update the state of the csn generator */
+ rc = csngen_adjust_time (gen, replicacsn);
+ if (rc == CSN_LIMIT_EXCEEDED) /* too much skew */
+ {
+ response = NSDS50_REPL_EXCESSIVE_CLOCK_SKEW;
+ goto send_response;
+ }
+ }
+ else if (diff <= 0)
+ {
+ /* Supplier's clock is behind ours */
+ /* XXXggood check if CSN smaller than purge point */
+ /* response = NSDS50_REPL_BELOW_PURGEPOINT; */
+ /* goto send_response; */
+ }
+ }
+ else
+ {
+ /* Oops, csnstr couldn't be converted */
+ response = NSDS50_REPL_INTERNAL_ERROR;
+ goto send_response;
+ }
+ }
+ else
+ {
+ /* Oops, csn generator failed */
+ response = NSDS50_REPL_INTERNAL_ERROR;
+ goto send_response;
+ }
+
+ /* update csn generator's state from the supplier's ruv */
+ rc = replica_update_csngen_state (replica, supplier_ruv); /* too much skew */
+ if (rc != 0)
+ {
+ response = NSDS50_REPL_EXCESSIVE_CLOCK_SKEW;
+ goto send_response;
+ }
+ }
+ else
+ {
+ /* Oops, no csn generator */
+ response = NSDS50_REPL_INTERNAL_ERROR;
+ goto send_response;
+ }
+ }
+ else
+ {
+ /* Oops, no csn generator object */
+ response = NSDS50_REPL_INTERNAL_ERROR;
+ goto send_response;
+ }
+
+ if (check_replica_id_uniqueness(replica, supplier_ruv) != 0){
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "conn=%d op=%d repl=\"%s\": "
+ "Replica has same replicaID %d as supplier\n",
+ connid, opid, repl_root, replica_get_rid(replica));
+ response = NSDS50_REPL_REPLICAID_ERROR;
+ goto send_response;
+ }
+
+ /* Attempt to acquire exclusive access to the replicated area */
+ /* Since partial URL is always the master, this locking_purl does not
+ * help us to know the true locker when it is a hub. Change to use
+ * the session's conn id and op id to identify the the supplier.
+ */
+ /* junkrc = ruv_get_first_id_and_purl(supplier_ruv, &junkrid, &locking_purl); */
+ sprintf(locking_session, "conn=%d id=%d", connid, opid);
+ locking_purl = &locking_session[0];
+ if (replica_get_exclusive_access(replica, &isInc, connid, opid,
+ locking_purl,
+ &current_purl) == PR_FALSE)
+ {
+ locking_purl = NULL; /* no dangling pointers */
+ response = NSDS50_REPL_REPLICA_BUSY;
+ goto send_response;
+ }
+ else
+ {
+ locking_purl = NULL; /* no dangling pointers */
+ /* Stick the replica object pointer in the connection extension */
+ connext->replica_acquired = (void *)replica_object;
+ replica_object = NULL;
+ }
+
+ /* If this is incremental protocol get replica's ruv to return to the supplier */
+ if (connext->repl_protocol_version == REPL_PROTOCOL_50_INCREMENTAL)
+ {
+ ruv_object = replica_get_ruv(replica);
+ if (NULL != ruv_object)
+ {
+ ruv = object_get_data(ruv_object);
+ (void)ruv_to_bervals(ruv, &ruv_bervals);
+ object_release(ruv_object);
+ }
+ }
+
+ /*
+ * Save the supplier ruv in the connection extension so it can
+ * either (a) be installed upon successful initialization (if this
+ * is a total update session) or used to update referral information
+ * for new replicas that show up in the supplier's RUV.
+ */
+ /*
+ * the supplier_ruv may have been set before, so free it here
+ * (in ruv_copy_and_destroy)
+ */
+ ruv_copy_and_destroy(&supplier_ruv, (RUV **)&connext->supplier_ruv);
+
+ if (connext->repl_protocol_version == REPL_PROTOCOL_50_INCREMENTAL)
+ {
+ /* The supplier ruv may have changed, so let's update the referrals */
+ consumer5_set_mapping_tree_state_for_replica(replica, connext->supplier_ruv);
+ }
+ else /* full protocol */
+ {
+ char *mtnstate = slapi_mtn_get_state(repl_root_sdn);
+ char **mtnreferral = slapi_mtn_get_referral(repl_root_sdn);
+
+ /* richm 20010831 - set the mapping tree to the referral state *before*
+ we invoke slapi_start_bulk_import - see bug 556992 -
+ slapi_start_bulk_import sets the database offline, if an operation comes
+ in while the database is offline but the mapping tree is not referring yet,
+ the server gets confused
+ */
+ /* During a total update we refer *all* operations */
+ repl_set_mtn_state_and_referrals(repl_root_sdn, STATE_REFERRAL,
+ connext->supplier_ruv, NULL, referrals);
+ /* LPREPL - check the return code.
+ * But what do we do if mapping tree could not be updated ? */
+
+ /* start the bulk import */
+ slapi_pblock_set (pb, SLAPI_TARGET_DN, repl_root);
+ rc = slapi_start_bulk_import (pb);
+ if (rc != LDAP_SUCCESS)
+ {
+ response = NSDS50_REPL_INTERNAL_ERROR;
+ /* reset the mapping tree state to what it was before
+ we tried to do the bulk import */
+ repl_set_mtn_state_and_referrals(repl_root_sdn, mtnstate,
+ NULL, NULL, mtnreferral);
+ slapi_ch_free_string(&mtnstate);
+ charray_free(mtnreferral);
+ mtnreferral = NULL;
+
+ goto send_response;
+ }
+ slapi_ch_free_string(&mtnstate);
+ charray_free(mtnreferral);
+ mtnreferral = NULL;
+ }
+
+ response = NSDS50_REPL_REPLICA_READY;
+ /* Set the "is replication session" flag in the connection extension */
+ slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &one );
+ connext->isreplicationsession = 1;
+ /* Save away the connection */
+ slapi_pblock_get(pb, SLAPI_CONNECTION, &connext->connection);
+
+send_response:
+ if (response != NSDS50_REPL_REPLICA_READY)
+ {
+ int resp_log_level = SLAPI_LOG_FATAL;
+ char purlstr[1024] = {0};
+ if (current_purl)
+ sprintf(purlstr, " locked by %s for %s update", current_purl,
+ isInc ? "incremental" : "total");
+
+ /* Don't log replica busy as errors - these are almost always not
+ errors - use the replication monitoring tools to determine if
+ a replica is not converging, then look for pathological replica
+ busy errors by turning on the replication log level */
+ if (response == NSDS50_REPL_REPLICA_BUSY) {
+ resp_log_level = SLAPI_LOG_REPL;
+ }
+
+ slapi_log_error (resp_log_level, repl_plugin_name,
+ "conn=%d op=%d replica=\"%s\": "
+ "Unable to acquire replica: error: %s%s\n",
+ connid, opid,
+ (replica ? slapi_sdn_get_dn(replica_get_root(replica)) : "unknown"),
+ protocol_response2string (response), purlstr);
+ }
+ /* Send the response */
+ if ((resp_bere = der_alloc()) == NULL)
+ {
+ /* ONREPL - not sure what we suppose to do here */
+ }
+ ber_printf(resp_bere, "{e", response);
+ if (NULL != ruv_bervals)
+ {
+ ber_printf(resp_bere, "{V}", ruv_bervals);
+ }
+ ber_printf(resp_bere, "}");
+ ber_flatten(resp_bere, &resp_bval);
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, REPL_NSDS50_REPLICATION_RESPONSE_OID);
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "conn=%d op=%d repl=\"%s\": "
+ "StartNSDS50ReplicationRequest: response=%d rc=%d\n",
+ connid, opid, repl_root,
+ response, rc);
+ slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
+
+ return_value = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
+
+ slapi_ch_free_string(&current_purl);
+
+ /* protocol_oid */
+ /* slapi_ch_free accepts NULL pointer */
+ slapi_ch_free((void **)&protocol_oid);
+
+ /* repl_root */
+ slapi_ch_free((void **)&repl_root);
+
+ /* supplier's ruv */
+ if (supplier_ruv)
+ {
+ ruv_destroy (&supplier_ruv);
+ }
+ /* referrals */
+ slapi_ch_free((void **)&referrals);
+
+ /* replicacsnstr */
+ slapi_ch_free((void **)&replicacsnstr);
+
+ /* repl_root_sdn */
+ if (NULL != repl_root_sdn)
+ {
+ slapi_sdn_free(&repl_root_sdn);
+ }
+ if (NSDS50_REPL_REPLICA_READY != response)
+ {
+ /*
+ * Something went wrong, and we never told the other end that the
+ * replica had been acquired, so we'd better release it.
+ */
+ if (NULL != connext && NULL != connext->replica_acquired)
+ {
+ Object *r_obj = (Object*)connext->replica_acquired;
+ replica_relinquish_exclusive_access((Replica*)object_get_data (r_obj),
+ connid, opid);
+ }
+ /* Remove any flags that would indicate repl session in progress */
+ if (NULL != connext)
+ {
+ connext->repl_protocol_version = REPL_PROTOCOL_UNKNOWN;
+ connext->isreplicationsession = 0;
+ }
+ slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &zero );
+ }
+ /* Release reference to replica_object */
+ if (NULL != replica_object)
+ {
+ object_release(replica_object);
+ }
+ /* bind_sdn */
+ if (NULL != bind_sdn)
+ {
+ slapi_sdn_free(&bind_sdn);
+ }
+ /* Release reference to gen_obj */
+ if (NULL != gen_obj)
+ {
+ object_release(gen_obj);
+ }
+ /* mycsn */
+ if (NULL != mycsn)
+ {
+ csn_free(&mycsn);
+ }
+ /* replicacsn */
+ if (NULL != replicacsn)
+ {
+ csn_free(&replicacsn);
+ }
+ /* resp_bere */
+ if (NULL != resp_bere)
+ {
+ ber_free(resp_bere, 1);
+ }
+ /* resp_bval */
+ if (NULL != resp_bval)
+ {
+ ber_bvfree(resp_bval);
+ }
+ /* ruv_bervals */
+ if (NULL != ruv_bervals)
+ {
+ ber_bvecfree(ruv_bervals);
+ }
+
+ return return_value;
+}
+
+/*
+ * This plugin entry point is called whenever an
+ * EndNSDS50ReplicationRequest is received.
+ * XXXggood this code is not finished.
+ */
+int
+multimaster_extop_EndNSDS50ReplicationRequest(Slapi_PBlock *pb)
+{
+ int return_value = SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
+ char *repl_root = NULL;
+ BerElement *resp_bere = NULL;
+ struct berval *resp_bval = NULL;
+ int response;
+ void *conn;
+ consumer_connection_extension *connext = NULL;
+ int rc;
+ int connid=-1, opid=-1;
+
+ /* Decode the extended operation */
+ if (decode_endrepl_extop(pb, &repl_root) == -1)
+ {
+ response = NSDS50_REPL_DECODING_ERROR;
+ }
+ else
+ {
+
+ /* First, verify that the current connection is a replication session */
+ /* XXXggood - do we need to wait around for any pending updates to complete?
+ I suppose it's possible that the end request may arrive asynchronously, before
+ we're really done processing all the updates.
+ */
+ /* Get a hold of the connection extension object */
+ slapi_pblock_get(pb, SLAPI_CONNECTION, &conn);
+ connext = (consumer_connection_extension *)repl_con_get_ext(
+ REPL_CON_EXT_CONN, conn);
+ if (NULL != connext && NULL != connext->replica_acquired)
+ {
+ int zero= 0;
+ Replica *r = (Replica*)object_get_data ((Object*)connext->replica_acquired);
+
+ /* if this is total protocol we need to install suppliers ruv for the replica */
+ if (connext->repl_protocol_version == REPL_PROTOCOL_50_TOTALUPDATE)
+ {
+ /* We no longer need to refer all operations...
+ * and update the referrals on the mapping tree node
+ */
+ consumer5_set_mapping_tree_state_for_replica(r, NULL);
+
+ /* LPREPL - First we clear the total in progress flag
+ Like this we know it's a normal termination of import. This is required by
+ the replication function that responds to backend state change.
+ If the flag is not clear, the callback knows that replication should not be
+ enabled again */
+ replica_set_state_flag(r, REPLICA_TOTAL_IN_PROGRESS, PR_TRUE /* clear flag */);
+
+ slapi_pblock_set (pb, SLAPI_TARGET_DN, repl_root);
+ slapi_stop_bulk_import (pb);
+
+ /* ONREPL - this is a bit of a hack. Once bulk import is finished,
+ the replication function that responds to backend state change
+ will be called. That function normally do all ruv and changelog
+ processing. However, in the case of replica initalization, it
+ will not do the right thing because supplier does not send its
+ ruv tombstone to the consumer. So that's why we need to do the
+ second processing here.
+ The supplier does not send its RUV entry because it could be
+ more up to date then the data send to the consumer.
+ The best solution I think, would be to "fake" on the supplier
+ an entry that corresponds to the ruv sent to the consumer and then
+ send it as part of the data */
+
+ if (cl5GetState () == CL5_STATE_OPEN)
+ {
+ rc = cl5DeleteDBSync (connext->replica_acquired);
+ }
+
+ replica_set_ruv (r, connext->supplier_ruv);
+ connext->supplier_ruv = NULL;
+
+ /* if changelog is enabled, we need to log a dummy change for the
+ smallest csn in the new ruv, so that this replica ca supply
+ other servers.
+ */
+ if (cl5GetState () == CL5_STATE_OPEN)
+ {
+ replica_log_ruv_elements (r);
+ }
+
+ /* ONREPL code that dealt with new RUV, etc was moved into the code
+ that enables replication when a backend comes back online. This
+ code is called once the bulk import is finished */
+ }
+ else if (connext->repl_protocol_version == REPL_PROTOCOL_50_INCREMENTAL)
+ {
+ /* The ruv from the supplier may have changed. Report the change on the
+ consumer side */
+
+ replica_update_ruv_consumer(r, connext->supplier_ruv);
+ }
+
+ /* Relinquish control of the replica */
+ slapi_pblock_get (pb, SLAPI_OPERATION_ID, &opid);
+ if (opid) slapi_pblock_get (pb, SLAPI_CONN_ID, &connid);
+ replica_relinquish_exclusive_access(r, connid, opid);
+ object_release ((Object*)connext->replica_acquired);
+ connext->replica_acquired = NULL;
+ connext->isreplicationsession= 0;
+ slapi_pblock_set( pb, SLAPI_CONN_IS_REPLICATION_SESSION, &zero );
+ response = NSDS50_REPL_REPLICA_RELEASE_SUCCEEDED;
+ /* Outbound replication agreements need to all be restarted now */
+ /* XXXGGOOD RESTART REEPL AGREEMENTS */
+ }
+ }
+
+ /* Send the response code */
+ if ((resp_bere = der_alloc()) == NULL)
+ {
+ rc = LDAP_ENCODING_ERROR;
+ goto free_and_return;
+ }
+ ber_printf(resp_bere, "{e}", response);
+ ber_flatten(resp_bere, &resp_bval);
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, REPL_NSDS50_REPLICATION_RESPONSE_OID);
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, resp_bval);
+ slapi_send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
+
+ return_value = SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
+
+free_and_return:
+ /* repl_root */
+ slapi_ch_free((void **)&repl_root);
+
+ /* BerElement */
+ if (NULL != resp_bere)
+ {
+ ber_free(resp_bere, 1);
+ }
+ /* response */
+ if (NULL != resp_bval)
+ {
+ ber_bvfree(resp_bval);
+ }
+
+ return return_value;
+}
+
+/*
+ * This plugin entry point is a noop entry
+ * point. It's used when registering extops that
+ * are only used as responses. We'll never receive
+ * one of those, unsolicited, but we still want to
+ * register them so they appear in the
+ * supportedextension attribute in the root DSE.
+ */
+int
+extop_noop(Slapi_PBlock *pb)
+{
+ return SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
+}
+
+
+static int
+check_replica_id_uniqueness(Replica *replica, RUV *supplier_ruv)
+{
+ ReplicaId local_rid = replica_get_rid(replica);
+ ReplicaId sup_rid = 0;
+ char *sup_purl = NULL;
+
+ if (ruv_get_first_id_and_purl(supplier_ruv, &sup_rid, &sup_purl) == RUV_SUCCESS) {
+ /* ReplicaID Uniqueness is checked only on Masters */
+ if ((replica_get_type(replica) == REPLICA_TYPE_UPDATABLE) &&
+ (sup_rid == local_rid)) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
diff --git a/ldap/servers/plugins/replication/repl_globals.c b/ldap/servers/plugins/replication/repl_globals.c
new file mode 100644
index 00000000..bee5dc4a
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_globals.c
@@ -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 **/
+
+#include "nspr.h"
+#include "repl.h"
+
+char *repl_plugin_name = REPL_PLUGIN_NAME;
+char *repl_plugin_name_cl = REPL_PLUGIN_NAME " - changelog program";
+
+/* String constants (no need to change these for I18N) */
+
+#define CHANGETYPE_ADD "add"
+#define CHANGETYPE_DELETE "delete"
+#define CHANGETYPE_MODIFY "modify"
+#define CHANGETYPE_MODRDN "modrdn"
+#define CHANGETYPE_MODDN "moddn"
+#define ATTR_CHANGENUMBER "changenumber"
+#define ATTR_TARGETDN "targetdn"
+#define ATTR_CHANGETYPE "changetype"
+#define ATTR_NEWRDN "newrdn"
+#define ATTR_DELETEOLDRDN "deleteoldrdn"
+#define ATTR_CHANGES "changes"
+#define ATTR_NEWSUPERIOR "newsuperior"
+#define ATTR_CHANGETIME "changetime"
+#define ATTR_DATAVERSION "dataVersion"
+#define ATTR_CSN "csn"
+#define TYPE_COPYINGFROM "copyingFrom"
+#define TYPE_COPIEDFROM "copiedFrom"
+#define FILTER_COPYINGFROM "copyingFrom=*"
+#define FILTER_COPIEDFROM "copiedFrom=*"
+#define FILTER_OBJECTCLASS "objectclass=*"
+
+
+char *changetype_add = CHANGETYPE_ADD;
+char *changetype_delete = CHANGETYPE_DELETE;
+char *changetype_modify = CHANGETYPE_MODIFY;
+char *changetype_modrdn = CHANGETYPE_MODRDN;
+char *changetype_moddn = CHANGETYPE_MODDN;
+char *attr_changenumber = ATTR_CHANGENUMBER;
+char *attr_targetdn = ATTR_TARGETDN;
+char *attr_changetype = ATTR_CHANGETYPE;
+char *attr_newrdn = ATTR_NEWRDN;
+char *attr_deleteoldrdn = ATTR_DELETEOLDRDN;
+char *attr_changes = ATTR_CHANGES;
+char *attr_newsuperior = ATTR_NEWSUPERIOR;
+char *attr_changetime = ATTR_CHANGETIME;
+char *attr_dataversion = ATTR_DATAVERSION;
+char *attr_csn = ATTR_CSN;
+char *type_copyingFrom = TYPE_COPYINGFROM;
+char *type_copiedFrom = TYPE_COPIEDFROM;
+char *filter_copyingFrom = FILTER_COPYINGFROM;
+char *filter_copiedFrom = FILTER_COPIEDFROM;
+char *filter_objectclass = FILTER_OBJECTCLASS;
+char *type_cn = "cn";
+char *type_objectclass = "objectclass";
+
+/* Names for replica attributes */
+const char *attr_replicaId = "nsDS5ReplicaId";
+const char *attr_replicaRoot = "nsDS5ReplicaRoot";
+const char *attr_replicaType = "nsDS5ReplicaType";
+const char *attr_replicaBindDn = "nsDS5ReplicaBindDn";
+const char *attr_state = "nsState";
+const char *attr_flags = "nsds5Flags";
+const char *attr_replicaName = "nsds5ReplicaName";
+const char *attr_replicaReferral = "nsds5ReplicaReferral";
+const char *type_ruvElement = "nsds50ruv";
+const char *type_replicaPurgeDelay = "nsds5ReplicaPurgeDelay";
+const char *type_replicaChangeCount = "nsds5ReplicaChangeCount";
+const char *type_replicaTombstonePurgeInterval = "nsds5ReplicaTombstonePurgeInterval";
+const char *type_replicaLegacyConsumer = "nsds5ReplicaLegacyConsumer";
+const char *type_ruvElementUpdatetime = "nsruvReplicaLastModified";
+
+/* Attribute names for replication agreement attributes */
+const char *type_nsds5ReplicaHost = "nsds5ReplicaHost";
+const char *type_nsds5ReplicaPort = "nsds5ReplicaPort";
+const char *type_nsds5TransportInfo = "nsds5ReplicaTransportInfo";
+const char *type_nsds5ReplicaBindDN = "nsds5ReplicaBindDN";
+const char *type_nsds5ReplicaCredentials = "nsds5ReplicaCredentials";
+const char *type_nsds5ReplicaBindMethod = "nsds5ReplicaBindMethod";
+const char *type_nsds5ReplicaRoot = "nsds5ReplicaRoot";
+const char *type_nsds5ReplicatedAttributeList = "nsds5ReplicatedAttributeList";
+const char *type_nsds5ReplicaUpdateSchedule = "nsds5ReplicaUpdateSchedule";
+const char *type_nsds5ReplicaInitialize = "nsds5BeginReplicaRefresh";
+const char *type_nsds5ReplicaTimeout = "nsds5ReplicaTimeout";
+const char *type_nsds5ReplicaBusyWaitTime = "nsds5ReplicaBusyWaitTime";
+const char *type_nsds5ReplicaSessionPauseTime = "nsds5ReplicaSessionPauseTime";
+
+/* To Allow Consumer Initialisation when adding an agreement - */
+const char *type_nsds5BeginReplicaRefresh = "nsds5BeginReplicaRefresh";
+
+static int repl_active_threads;
+
+int
+decrement_repl_active_threads()
+{
+ PR_AtomicIncrement(&repl_active_threads);
+ return repl_active_threads;
+}
+
+int
+increment_repl_active_threads()
+{
+ PR_AtomicDecrement(&repl_active_threads);
+ return repl_active_threads;
+}
diff --git a/ldap/servers/plugins/replication/repl_helper.c b/ldap/servers/plugins/replication/repl_helper.c
new file mode 100644
index 00000000..05616cf1
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_helper.c
@@ -0,0 +1,85 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "repl_helper.h"
+
+ReplGenericList *
+ReplGenericListNew(void)
+{
+ ReplGenericList *list=NULL;
+ if(NULL == (list = (ReplGenericList *)
+ slapi_ch_calloc(1,sizeof(ReplGenericList)))) {
+ return(NULL);
+ }
+ list->object = NULL;
+ list->next = NULL;
+ list->prev = NULL;
+ return(list);
+}
+
+void
+ReplGenericListAddObject(ReplGenericList *list,
+ void *newObject)
+{
+ if(list) {
+ ReplGenericList *new_struct = (ReplGenericList *)
+ slapi_ch_calloc(1, sizeof(ReplGenericList));
+
+ if (!new_struct)
+ return;
+ /* set back pointer of old first element */
+ if(list->next) {
+ list->next->prev = new_struct;
+ }
+
+ /* we might have a next but since we are the first we WONT have
+ a previous */
+ new_struct->object = newObject;
+ new_struct->next = list->next;
+ new_struct->prev = NULL;
+
+ /* the new element is the first one */
+ list->next = new_struct;
+
+ /* if this is the only element it is the end too */
+ if(NULL == list->prev)
+ list->prev = new_struct;
+
+ }
+ return;
+}
+
+ReplGenericList *
+ReplGenericListFindObject(ReplGenericList *list,
+ void *object)
+{
+ if(!list)
+ return(NULL);
+ list = list->next; /* the first list item never has data */
+
+ while (list) {
+ if(list->object == object)
+ return(list);
+ list = list->next;
+ }
+ return(NULL);
+}
+
+void
+ReplGenericListDestroy(ReplGenericList *list,
+ ReplGenericListObjectDestroyFn destroyFn)
+{
+ ReplGenericList *list_ptr;
+
+ while (list) {
+ list_ptr = list;
+ list = list->next;
+ if(destroyFn && list_ptr->object) {
+ (destroyFn)(list_ptr->object);
+ }
+ slapi_ch_free((void **)(&list_ptr));
+ }
+ return;
+}
diff --git a/ldap/servers/plugins/replication/repl_helper.h b/ldap/servers/plugins/replication/repl_helper.h
new file mode 100644
index 00000000..076710ce
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_helper.h
@@ -0,0 +1,69 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * repl_helper.h - Helper functions (should actually be repl_utils.h)
+ *
+ *
+ *
+ */
+
+#ifndef _REPL_HELPER_H
+#define _REPL_HELPER_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "nspr.h"
+#include "slapi-plugin.h"
+
+/*
+ * shamelessly stolen from the xp library
+ *
+ */
+
+/*
+ Linked list manipulation routines
+
+ this is a very standard linked list structure
+ used by many many programmers all over the world
+
+ The lists have been modified to be doubly linked. The
+ first element in a list is always the header. The 'next'
+ pointer of the header is the first element in the list.
+ The 'prev' pointer of the header is the last element in
+ the list.
+
+ The 'prev' pointer of the first real element in the list
+ is NULL as is the 'next' pointer of the last real element
+ in the list
+
+ */
+
+
+typedef struct _repl_genericList {
+ void *object;
+ struct _repl_genericList *next;
+ struct _repl_genericList *prev;
+} ReplGenericList;
+
+typedef void *(ReplGenericListObjectDestroyFn)(void *obj);
+
+ReplGenericList *ReplGenericListNew(void);
+void ReplGenericListDestroy(ReplGenericList *list, ReplGenericListObjectDestroyFn destroyFn);
+
+void ReplGenericListAddObject(ReplGenericList *list,
+ void *newObject);
+ReplGenericList *ReplGenericListFindObject(ReplGenericList *list,
+ void *obj);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/ldap/servers/plugins/replication/repl_init.c b/ldap/servers/plugins/replication/repl_init.c
new file mode 100644
index 00000000..42da2074
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_init.c
@@ -0,0 +1,312 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Add an entry like the following to dse.ldif to enable this plugin:
+
+dn: cn=Legacy Replication Plugin,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: Legacy Replication Plugin
+nsslapd-pluginpath: /export2/servers/Hydra-supplier/lib/replication-plugin.so
+nsslapd-plugininitfunc: replication_legacy_plugin_init
+nsslapd-plugintype: object
+nsslapd-pluginenabled: on
+nsslapd-plugin-depends-on-type: database
+nsslapd-plugin-depends-on-named: Class of Service
+nsslapd-plugin-depends-on-named: Multi-Master Replication Plugin
+nsslapd-pluginid: replication-legacy
+nsslapd-pluginversion: 5.0b1
+nsslapd-pluginvendor: Netscape Communications
+nsslapd-plugindescription: Legacy Replication Plugin
+
+NOTE: This plugin depends on the Multi-Master Replication Plugin
+
+*/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+#include "repl5.h"
+#include "repl_shared.h"
+#include "cl4.h" /* changelog interface */
+#include "dirver.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+/* ----------------------------- Legacy Replication Plugin */
+
+static Slapi_PluginDesc legacydesc = { "replication-legacy", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Legacy Replication Plugin" };
+static Slapi_PluginDesc legacypreopdesc = { "replication-legacy-preop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Legacy replication pre-operation plugin" };
+static Slapi_PluginDesc legacypostopdesc = { "replication-legacy-postop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Legacy replication post-operation plugin" };
+static Slapi_PluginDesc legacyinternalpreopdesc = { "replication-legacy-internalpreop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Legacy replication internal pre-operation plugin" };
+static Slapi_PluginDesc legacyinternalpostopdesc = { "replication-legacy-internalpostop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Legacy replication internal post-operation plugin" };
+static Slapi_PluginDesc legacybepostopdesc = { "replication-legacy-bepostop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Legacy replication bepost-operation plugin" };
+static Slapi_PluginDesc legacyentrydesc = { "replication-legacy-entry", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Legacy replication entry plugin" };
+
+static int legacy_stopped; /* A flag which is set when all the plugin threads are to stop */
+
+
+/* Initialize preoperation plugin points */
+int
+legacy_preop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&legacypreopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN, (void *) legacy_preop_bind ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_ADD_FN, (void *) legacy_preop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_DELETE_FN, (void *) legacy_preop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_MODIFY_FN, (void *) legacy_preop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_MODRDN_FN, (void *) legacy_preop_modrdn ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN, (void *) legacy_preop_search ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_COMPARE_FN, (void *) legacy_preop_compare ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_ENTRY_FN, (void *) legacy_pre_entry ))
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "legacy_preop_init failed\n" );
+ rc= -1;
+ }
+ return rc;
+}
+
+
+
+/* Initialize postoperation plugin points */
+static int
+legacy_postop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&legacypostopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_ADD_FN, (void *) legacy_postop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *) legacy_postop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *) legacy_postop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *) legacy_postop_modrdn ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "legacy_postop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+
+
+/* Initialize internal preoperation plugin points (called for internal operations) */
+static int
+legacy_internalpreop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&legacyinternalpreopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN, (void *) legacy_preop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN, (void *) legacy_preop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN, (void *) legacy_preop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN, (void *) legacy_preop_modrdn ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "legacy_internalpreop_init failed\n" );
+ rc= -1;
+ }
+ return rc;
+}
+
+
+
+/* Initialize internal postoperation plugin points (called for internal operations) */
+static int
+legacy_internalpostop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&legacyinternalpostopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *) legacy_postop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *) legacy_postop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *) legacy_postop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *) legacy_postop_modrdn ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "legacy_internalpostop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+
+
+/* Initialize the entry plugin point for the legacy replication plugin */
+static int
+legacy_entry_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ /* Set up the fn pointers for the preop and postop operations we're interested in */
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&legacyentrydesc ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "legacy_entry_init failed\n" );
+ rc= -1;
+ }
+ return rc;
+}
+
+
+
+
+/*
+ * Create the entry at the top of the replication configuration subtree.
+ */
+static int
+create_config_top()
+{
+ const char *dn = REPL_CONFIG_TOP;
+ char *entry_string = slapi_ch_strdup("dn: cn=replication,cn=config\nobjectclass: top\nobjectclass: extensibleobject\ncn: replication\n");
+ Slapi_PBlock *pb = slapi_pblock_new();
+ Slapi_Entry *e = slapi_str2entry(entry_string, 0);
+ int return_value;
+
+ slapi_add_entry_internal_set_pb(pb, e, NULL, /* controls */
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION), 0 /* flags */);
+ slapi_add_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &return_value);
+ slapi_pblock_destroy(pb);
+ slapi_ch_free((void **)&entry_string);
+ return return_value;
+}
+
+
+/* Start the legacy replication plugin */
+static int
+legacy_start( Slapi_PBlock *pb )
+{
+ static int legacy_started = 0;
+ int rc= 0; /* OK */
+
+ if (!legacy_started)
+ {
+ int ctrc;
+
+ /* Initialise support for cn=monitor */
+ repl_monitor_init();
+
+ /* Initialise support for "" (the rootdse) */
+ /* repl_rootdse_init(); */
+
+ /* Decode the command line args to see if we're dumping to LDIF */
+ {
+ int argc;
+ char **argv;
+ slapi_pblock_get( pb, SLAPI_ARGC, &argc);
+ slapi_pblock_get( pb, SLAPI_ARGV, &argv);
+ repl_entry_init(argc,argv);
+ }
+
+ /* Create the entry at the top of the config area, if it doesn't exist */
+ /* XXXggood this should be in the 5.0 plugin! */
+ ctrc = create_config_top();
+ if (ctrc != LDAP_SUCCESS && ctrc != LDAP_ALREADY_EXISTS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "Warning: unable to "
+ "create configuration entry %s: %s\n", REPL_CONFIG_TOP,
+ ldap_err2string(ctrc));
+ }
+ (void)legacy_consumer_config_init();
+
+ /* register to be notified when backend state changes */
+ slapi_register_backend_state_change((void *)legacy_consumer_be_state_change,
+ legacy_consumer_be_state_change);
+
+ legacy_started = 1;
+ legacy_stopped = 0;
+ }
+ return rc;
+}
+
+
+/* Post-start function for the legacy replication plugin */
+static int
+legacy_poststart( Slapi_PBlock *pb )
+{
+ int rc = 0; /* OK */
+ return rc;
+}
+
+
+/* Stop the legacy replication plugin */
+static int
+legacy_stop( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if (!legacy_stopped)
+ {
+ /*csnShutdown();*/
+ legacy_stopped = 1;
+ }
+
+ /* unregister backend state change notification */
+ slapi_unregister_backend_state_change((void *)legacy_consumer_be_state_change);
+
+ return rc;
+}
+
+
+/* Initialize the legacy replication plugin */
+int
+replication_legacy_plugin_init(Slapi_PBlock *pb)
+{
+ static int legacy_initialised= 0;
+ int rc= 0; /* OK */
+ void *identity = NULL;
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
+ PR_ASSERT (identity);
+ repl_set_plugin_identity (PLUGIN_LEGACY_REPLICATION, identity);
+
+ if(config_is_slapd_lite())
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, repl_plugin_name,
+ "replication plugin not approved for restricted"
+ " mode Directory Server.\n" );
+ rc= -1;
+ }
+ if(rc==0 && !legacy_initialised)
+ {
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&legacydesc );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) legacy_start );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) legacy_stop );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_POSTSTART_FN, (void *) legacy_poststart );
+
+ /* Register the plugin interfaces we implement */
+ rc= slapi_register_plugin("preoperation", 1 /* Enabled */, "legacy_preop_init", legacy_preop_init, "Legacy replication preoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("postoperation", 1 /* Enabled */, "legacy_postop_init", legacy_postop_init, "Legacy replication postoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("internalpreoperation", 1 /* Enabled */, "legacy_internalpreop_init", legacy_internalpreop_init, "Legacy replication internal preoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("internalpostoperation", 1 /* Enabled */, "legacy_internalpostop_init", legacy_internalpostop_init, "Legacy replication internal postoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("entry", 1 /* Enabled */, "legacy_entry_init", legacy_entry_init, "Legacy replication entry plugin", NULL, identity);
+
+ legacy_initialised= 1;
+ }
+ return rc;
+}
+
+
+int
+get_legacy_stop()
+{
+ return legacy_stopped;
+}
diff --git a/ldap/servers/plugins/replication/repl_modify.c b/ldap/servers/plugins/replication/repl_modify.c
new file mode 100644
index 00000000..26753cc0
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_modify.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 **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+
+/* The modify operation plugin functions for the legacy replication plugin */
+
+int
+legacy_preop_modify( Slapi_PBlock *pb )
+{
+ return legacy_preop( pb, "legacy_preop_modify", OP_MODIFY );
+}
+
+int
+legacy_bepreop_modify( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+ return rc;
+}
+
+int
+legacy_postop_modify( Slapi_PBlock *pb )
+{
+ return legacy_postop( pb, "legacy_postop_modify", OP_MODIFY );
+}
diff --git a/ldap/servers/plugins/replication/repl_modrdn.c b/ldap/servers/plugins/replication/repl_modrdn.c
new file mode 100644
index 00000000..653aff0a
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_modrdn.c
@@ -0,0 +1,28 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+
+/* The modrdn plugin points for the legacy replication plugin */
+
+int
+legacy_preop_modrdn( Slapi_PBlock *pb )
+{
+ return legacy_preop(pb, "legacy_preop_modrdn", OP_MODDN);
+}
+
+int
+legacy_bepreop_modrdn( Slapi_PBlock *pb )
+{
+ return 0; /* OK */
+}
+
+int
+legacy_postop_modrdn( Slapi_PBlock *pb )
+{
+ return legacy_postop(pb, "legacy_postop_modrdn", OP_MODDN);
+}
diff --git a/ldap/servers/plugins/replication/repl_monitor.c b/ldap/servers/plugins/replication/repl_monitor.c
new file mode 100644
index 00000000..ec52d611
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_monitor.c
@@ -0,0 +1,58 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <string.h>
+
+#include "repl.h"
+#include "slapi-plugin.h"
+
+/* Forward Declartions */
+static int repl_monitor_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+
+int
+repl_monitor_init()
+{
+ /* The FE DSE *must* be initialised before we get here */
+ int return_value= LDAP_SUCCESS;
+ static int initialized = 0;
+
+ if (!initialized)
+ {
+ /* ONREPL - this is commented until we implement 4.0 style changelog
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,"cn=monitor",LDAP_SCOPE_BASE,"(objectclass=*)",repl_monitor_search,NULL); */
+ initialized = 1;
+ }
+
+ return return_value;
+}
+
+static int
+repl_monitor_search(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ const char *sdv = get_server_dataversion();
+ if ( sdv != NULL )
+ {
+ int port;
+ char buf[BUFSIZ];
+ struct berval val;
+ struct berval *vals[2];
+ vals[0] = &val;
+ vals[1] = NULL;
+ port= config_get_port();
+ if(port==0)
+ {
+ port= config_get_secureport();
+ }
+ /* ONREPL - how do we publish changenumbers now with multiple changelogs?
+ sprintf( buf, "%s:%lu %s% lu", get_localhost_DNS(), port, sdv, ldapi_get_last_changenumber());
+ */
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_replace( e, attr_dataversion, vals );
+ }
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
diff --git a/ldap/servers/plugins/replication/repl_objset.c b/ldap/servers/plugins/replication/repl_objset.c
new file mode 100644
index 00000000..f0a68097
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_objset.c
@@ -0,0 +1,524 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* repl_objset.c */
+/*
+ * Support for lifetime management of sets of objects.
+ * Objects are refcounted. NOTE: this API is deprecated.
+ * Use the object/objset API provided by libslapd.
+ */
+
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+#include "repl_objset.h"
+#include <prlock.h>
+
+#define REPL_OBJSET_OBJ_FLAG_DELETED 0x1
+
+
+typedef struct repl_objset_object
+{
+ void *data; /* pointer to actual node data */
+ char *key; /* key for this object. null-terminated string */
+ int refcnt; /* reference count for this object */
+ unsigned long flags; /* state of this object */
+} Repl_Objset_object;
+
+typedef struct repl_objset
+{
+ LList *objects;
+ FNFree destructor; /* destructor for objects - provided by caller */
+ PRLock *lock;
+} repl_objset;
+
+
+/* Forward declarations */
+static void removeObjectNolock(Repl_Objset *o, Repl_Objset_object *co);
+static Repl_Objset_object *removeCurrentObjectAndGetNextNolock (Repl_Objset *o,
+ Repl_Objset_object *co, void *iterator);
+
+/*
+ * Create a new set.
+ *
+ * Arguments:
+ * destructor: a function to be called when an object is to be destroyed
+ *
+ * Returns:
+ * A pointer to the object set, or NULL if an error occured.
+ */
+Repl_Objset *
+repl_objset_new(FNFree destructor)
+{
+ Repl_Objset *p;
+
+ p = (Repl_Objset *)slapi_ch_malloc(sizeof(Repl_Objset));
+ p->lock = PR_NewLock();
+ if (NULL == p->lock)
+ {
+ free(p); p = NULL;
+ }
+ p->objects = llistNew();
+ p->destructor = destructor;
+ return p;
+}
+
+
+/*
+ * Destroy a Repl_Objset.
+ * Arguments:
+ * o: the object set to be destroyed
+ * maxwait: the maximum time to wait for all object refcnts to
+ * go to zero.
+ * panic_fn: a function to be called if, after waiting "maxwait"
+ * seconds, not all object refcnts are zero.
+ * The caller must ensure that no one else holds references to the
+ * set or any objects it contains.
+ */
+void
+repl_objset_destroy(Repl_Objset **o, time_t maxwait, FNFree panic_fn)
+{
+ Repl_Objset_object *co = NULL;
+ time_t now, stop_time;
+ int really_gone;
+ int loopcount;
+ void *cookie;
+
+ PR_ASSERT(NULL != o);
+ PR_ASSERT(NULL != *o);
+
+ time(&now);
+ stop_time = now + maxwait;
+
+ /*
+ * Loop over the objects until they all are actually gone,
+ * or until maxwait seconds have passed.
+ */
+ really_gone = 0;
+ loopcount = 0;
+
+ while (now < stop_time)
+ {
+ void *cookie;
+
+ PR_Lock((*o)->lock);
+
+ if ((co = llistGetFirst((*o)->objects, &cookie)) == NULL)
+ {
+ really_gone = 1;
+ PR_Unlock((*o)->lock);
+ break;
+ }
+ while (NULL != co)
+ {
+ /* Set the deleted flag so the object isn't returned by iterator */
+ co->flags |= REPL_OBJSET_OBJ_FLAG_DELETED;
+ if (0 == co->refcnt)
+ {
+ /* Remove the object */
+ co = removeCurrentObjectAndGetNextNolock ((*o), co, cookie);
+
+ }
+ else
+ co = llistGetNext((*o)->objects, &cookie);
+ }
+ PR_Unlock((*o)->lock);
+ time(&now);
+ if (loopcount > 0)
+ {
+ DS_Sleep(PR_TicksPerSecond());
+ }
+ loopcount++;
+ }
+
+ if (!really_gone)
+ {
+ if (NULL != panic_fn)
+ {
+ /*
+ * Call the "aargh, this thing won't go away" panic
+ * function for each remaining object.
+ */
+ PR_Lock((*o)->lock);
+ if ((co = llistGetFirst((*o)->objects, &cookie)) == NULL)
+ {
+ panic_fn(co->data);
+ while (NULL != co)
+ {
+ panic_fn(co->data);
+ co = llistGetNext((*o)->objects, &cookie);
+ }
+ }
+ PR_Unlock((*o)->lock);
+ }
+ }
+ else
+ {
+ /* Free the linked list */
+ llistDestroy(&(*o)->objects, (*o)->destructor);
+ PR_DestroyLock((*o)->lock);
+ free(*o); *o = NULL;
+ }
+}
+
+
+
+/*
+ * Add an object to an object set.
+ *
+ * Arguments:
+ * o: The object set to which the object is to be added.
+ * name: a null-terminated string that names the object. Must
+ * be unique.
+ * obj: pointer to the object to be added.
+ *
+ * Return codes:
+ * REPL_OBJSET_SUCCESS: the item was added to the object set
+ * REPL_OBJSET_DUPLICATE_KEY: an item with the same key is already
+ * in the object set.
+ * REPL_OBJSET_INTERNAL_ERROR: something bad happened.
+ */
+int
+repl_objset_add(Repl_Objset *o, const char *name, void *obj)
+{
+ Repl_Objset_object *co = NULL;
+ Repl_Objset_object *tmp = NULL;
+ int rc = REPL_OBJSET_SUCCESS;
+
+ PR_ASSERT(NULL != o);
+ PR_ASSERT(NULL != name);
+ PR_ASSERT(NULL != obj);
+
+ PR_Lock(o->lock);
+ tmp = llistGet(o->objects, name);
+ if (NULL != tmp)
+ {
+ rc = REPL_OBJSET_DUPLICATE_KEY;
+ goto loser;
+ }
+ co = (Repl_Objset_object *)slapi_ch_malloc(sizeof(Repl_Objset_object));
+ co->data = obj;
+ co->key = slapi_ch_strdup(name);
+ co->refcnt = 0;
+ co->flags = 0UL;
+ if (llistInsertHead(o->objects, name, co) != 0)
+ {
+ rc = REPL_OBJSET_INTERNAL_ERROR;
+ goto loser;
+ }
+ PR_Unlock(o->lock);
+ return rc;
+
+loser:
+ PR_Unlock(o->lock);
+ if (NULL != co)
+ {
+ if (NULL != co->key)
+ {
+ slapi_ch_free((void **)&co->key);
+ }
+ slapi_ch_free((void **)&co);
+ }
+ return rc;
+}
+
+
+/* Must be called with the repl_objset locked */
+static void
+removeObjectNolock(Repl_Objset *o, Repl_Objset_object *co)
+{
+ /* Remove from list */
+ llistRemove(o->objects, co->key);
+ /* Destroy the object */
+ o->destructor(&(co->data));
+ free(co->key);
+ /* Deallocate the container */
+ free(co);
+}
+
+static Repl_Objset_object *
+removeCurrentObjectAndGetNextNolock (Repl_Objset *o, Repl_Objset_object *co, void *iterator)
+{
+ Repl_Objset_object *ro;
+
+ PR_ASSERT (o);
+ PR_ASSERT (co);
+ PR_ASSERT (iterator);
+
+ ro = llistRemoveCurrentAndGetNext (o->objects, &iterator);
+
+ o->destructor(&(co->data));
+ free(co->key);
+ /* Deallocate the container */
+ free(co);
+
+ return ro;
+}
+
+/* Must be called with the repl_objset locked */
+static void
+acquireNoLock(Repl_Objset_object *co)
+{
+ co->refcnt++;
+}
+
+
+/* Must be called with the repl_objset locked */
+static void
+releaseNoLock(Repl_Objset *o, Repl_Objset_object *co)
+{
+ PR_ASSERT(co->refcnt >= 1);
+ if (--co->refcnt == 0)
+ {
+ if (co->flags & REPL_OBJSET_OBJ_FLAG_DELETED)
+ {
+ /* Remove the object */
+ removeObjectNolock(o, co);
+ }
+ }
+}
+
+/*
+ * Retrieve an object from the object set. If an object with
+ * the given key is found, its reference count is incremented,
+ * a pointer to the object is returned, and a handle to use
+ * to refer to the object is returned.
+ *
+ * Arguments:
+ * o: The object set to be searched.
+ * key: key of the object to be retrieved
+ * obj: pointer to void * that will be set to point to the
+ * object, if found.
+ * handle: pointer to void * that will be set to point to a
+ * handle, used to refer to the object, if found.
+ *
+ * Returns:
+ * REPL_OBJSET_SUCCESS: an item was found.
+ * REPL_OBJSET_KEY_NOT_FOUND: no item with the given key was found.
+ */
+int
+repl_objset_acquire(Repl_Objset *o, const char *key, void **obj, void **handle)
+{
+ Repl_Objset_object *co = NULL;
+ int rc = REPL_OBJSET_KEY_NOT_FOUND;
+
+ PR_ASSERT(NULL != o);
+ PR_ASSERT(NULL != key);
+ PR_ASSERT(NULL != obj);
+ PR_ASSERT(NULL != handle);
+
+ PR_Lock(o->lock);
+ co = llistGet(o->objects, key);
+ if (NULL != co && !(co->flags & REPL_OBJSET_OBJ_FLAG_DELETED))
+ {
+ acquireNoLock(co);
+ *obj = (void *)co->data;
+ *handle = (void *)co;
+ rc = REPL_OBJSET_SUCCESS;
+ }
+ PR_Unlock(o->lock);
+ return rc;
+}
+
+
+/*
+ * Return an object to the object set.
+ *
+ * Arguments:
+ * o: The object set containing the objct
+ * handle: reference to the object.
+ *
+ */
+void
+repl_objset_release(Repl_Objset *o, void *handle)
+{
+ Repl_Objset_object *co;
+
+ PR_ASSERT(NULL != o);
+ PR_ASSERT(NULL != handle);
+
+ co = (Repl_Objset_object *)handle;
+ PR_Lock(o->lock);
+ releaseNoLock(o, co);
+ PR_Unlock(o->lock);
+}
+
+
+
+/*
+ * Delete an object from the object set
+ *
+ * Arguments:
+ * o: The object set containing the object.
+ * handle: reference to the object.
+ */
+void
+repl_objset_delete(Repl_Objset *o, void *handle)
+{
+ Repl_Objset_object *co = (Repl_Objset_object *)handle;
+
+ PR_ASSERT(NULL != o);
+ PR_ASSERT(NULL != co);
+
+ PR_Lock(o->lock);
+ if (co->refcnt == 0)
+ {
+ removeObjectNolock(o, co);
+ }
+ else
+ {
+ /* Set deleted flag, clean up later */
+ co->flags |= REPL_OBJSET_OBJ_FLAG_DELETED;
+ }
+ PR_Unlock(o->lock);
+}
+
+
+typedef struct _iterator
+{
+ Repl_Objset *o; /* set for which iterator was created */
+ void *cookie; /* for linked list */
+ Repl_Objset_object *co; /* our wrapper */
+} iterator;
+
+/*
+ * Get the first object in an object set.
+ * Used when enumerating all of the objects in a set.
+ * Arguments:
+ * o: The object set being enumerated
+ * itcontext: an iteration context, to be passed back to subsequent calls
+ * to repl_objset_next_object.
+ * handle: a pointer to pointer to void. This will be filled in with
+ * a reference to the object's enclosing object.
+ * Returns:
+ * A pointer to the next object in the set, or NULL if there are no
+ * objects in the set.
+ *
+ */
+void *
+repl_objset_first_object(Repl_Objset *o, void **itcontext, void **handle)
+{
+ Repl_Objset_object *co = NULL;
+ void *cookie;
+ void *retptr = NULL;
+ iterator *it;
+
+ PR_ASSERT(NULL != o);
+ PR_ASSERT(NULL != itcontext);
+
+ *itcontext = NULL;
+
+ if (NULL == o->objects) {
+ return(NULL);
+ }
+
+ /* Find the first non-deleted object */
+ PR_Lock(o->lock);
+ co = llistGetFirst(o->objects, &cookie);
+ while (NULL != co && (co->flags & REPL_OBJSET_OBJ_FLAG_DELETED))
+ {
+ co = llistGetNext(o->objects, &cookie);
+ }
+
+ if (NULL != co)
+ {
+ /* Increment refcnt until item given back to us */
+ acquireNoLock(co);
+
+ /* Save away context */
+ it = (iterator *)slapi_ch_malloc(sizeof(iterator));
+ *itcontext = it;
+ it->o = o;
+ it->cookie = cookie;
+ it->co = co;
+ retptr = co->data;
+ }
+
+ PR_Unlock(o->lock);
+ if (NULL != handle)
+ {
+ *handle = co;
+ }
+
+ return retptr;
+}
+
+
+
+/*
+ * Get the next object in the set.
+ * Arguments:
+ * o: The object set being enumerated
+ * itcontext: an iteration context, to be passed back to subsequent calls
+ * to repl_objset_next_object.
+ * handle: a pointer to pointer to void. This will be filled in with
+ * a reference to the object's enclosing object.
+ *
+ * Returns:
+ * A pointer to the next object in the set, or NULL if there are no more
+ * objects.
+ */
+void *
+repl_objset_next_object(Repl_Objset *o, void *itcontext, void **handle)
+{
+ Repl_Objset_object *co = NULL;
+ Repl_Objset_object *tmp_co;
+ void *retptr = NULL;
+ iterator *it = (iterator *)itcontext;
+
+ PR_ASSERT(NULL != o);
+ PR_ASSERT(NULL != it);
+ PR_ASSERT(NULL != it->co);
+
+ PR_Lock(o->lock);
+ tmp_co = it->co;
+
+ /* Find the next non-deleted object */
+ while ((co = llistGetNext(o->objects, &it->cookie)) != NULL &&
+ !(co->flags & REPL_OBJSET_OBJ_FLAG_DELETED));
+
+ if (NULL != co)
+ {
+ acquireNoLock(co);
+ it->co = co;
+ retptr = co->data;
+ }
+ else
+ {
+ /*
+ * No more non-deleted objects - erase context (freeing
+ * it is responsibility of caller.
+ */
+ it->cookie = NULL;
+ it->co = NULL;
+ }
+ releaseNoLock(o, tmp_co);
+ PR_Unlock(o->lock);
+ if (NULL != handle)
+ {
+ *handle = co;
+ }
+ return retptr;
+}
+
+
+
+/*
+ * Destroy an itcontext iterator
+ */
+void
+repl_objset_iterator_destroy(void **itcontext)
+{
+ if (NULL != itcontext && NULL != *itcontext)
+ {
+ /* check if we did not iterate through the entire list
+ and need to release last accessed element */
+ iterator *it = *(iterator**)itcontext;
+ if (it->co)
+ repl_objset_release (it->o, it->co);
+
+ slapi_ch_free((void **)itcontext);
+ }
+}
diff --git a/ldap/servers/plugins/replication/repl_objset.h b/ldap/servers/plugins/replication/repl_objset.h
new file mode 100644
index 00000000..72af5109
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_objset.h
@@ -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 **/
+/*
+ */
+
+/* repl_objset.h */
+ /*
+ * Support for lifetime management of sets of objects.
+ * Objects are refcounted. NOTE: This API should go away
+ * in favor of the objset API provided by libslapd.
+ */
+#ifndef _REPL_OBJSET_H
+#define __REPL_OBJSET_H
+
+#include "llist.h"
+
+#define REPL_OBJSET_SUCCESS 0
+#define REPL_OBJSET_DUPLICATE_KEY 1
+#define REPL_OBJSET_INTERNAL_ERROR 2
+#define REPL_OBJSET_KEY_NOT_FOUND 3
+
+typedef struct repl_objset Repl_Objset;
+
+Repl_Objset *repl_objset_new(FNFree destructor);
+void repl_objset_destroy(Repl_Objset **o, time_t maxwait, FNFree panic_fn);
+int repl_objset_add(Repl_Objset *o, const char *name, void *obj);
+int repl_objset_acquire(Repl_Objset *o, const char *key, void **obj, void **handle);
+void repl_objset_release(Repl_Objset *o, void *handle);
+void repl_objset_delete(Repl_Objset *o, void *handle);
+void *repl_objset_next_object(Repl_Objset *o, void *cookie, void **handle);
+void *repl_objset_first_object(Repl_Objset *o, void **cookie, void **handle);
+void repl_objset_iterator_destroy(void **itcontext);
+
+#endif /* _REPL_OBJSET_H */
diff --git a/ldap/servers/plugins/replication/repl_opext.c b/ldap/servers/plugins/replication/repl_opext.c
new file mode 100644
index 00000000..d9c8d1ed
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_opext.c
@@ -0,0 +1,97 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* supplier_operation_extension.c - replication extension to the Operation object
+ */
+
+
+#include "repl.h"
+#include "repl5.h"
+
+/* ***** Supplier side ***** */
+
+/* JCMREPL -> PINAKIxxx The interface to the referral stuff is not correct */
+void ref_array_dup_free(void *the_copy); /* JCMREPL - should be #included */
+
+/* supplier operation extension constructor */
+void* supplier_operation_extension_constructor (void *object, void *parent)
+{
+ supplier_operation_extension *ext = (supplier_operation_extension*) slapi_ch_calloc (1, sizeof (supplier_operation_extension));
+ if (ext == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "unable to create replication supplier operation extension - out of memory\n" );
+ }
+ else
+ {
+ ext->prevent_recursive_call= 0;
+ }
+ return ext;
+}
+
+/* supplier operation extension destructor */
+void supplier_operation_extension_destructor (void *ext,void *object, void *parent)
+{
+ if (ext)
+ {
+ supplier_operation_extension *supext = (supplier_operation_extension *)ext;
+ if (supext->operation_parameters)
+ operation_parameters_free (&(supext->operation_parameters));
+ if (supext->repl_gen)
+ slapi_ch_free ((void**)&supext->repl_gen);
+ slapi_ch_free((void **)&ext);
+ }
+}
+
+/* ***** Consumer side ***** */
+
+/* consumer operation extension constructor */
+void* consumer_operation_extension_constructor (void *object, void *parent)
+{
+ consumer_operation_extension *ext = (consumer_operation_extension*) slapi_ch_calloc (1, sizeof (consumer_operation_extension));
+ if (ext == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name, "unable to create replication consumer operation extension - out of memory\n" );
+ }
+ if(object!=NULL && parent!=NULL)
+ {
+ consumer_connection_extension *connext;
+ connext = (consumer_connection_extension *)repl_con_get_ext(REPL_CON_EXT_CONN, parent);
+ if(NULL != connext)
+ {
+ /* We copy the Connection Replicated Session flag to the Replicated Operation flag */
+ if (connext->isreplicationsession)
+ {
+ operation_set_flag((Slapi_Operation *)object,OP_FLAG_REPLICATED);
+ }
+ /* We set the Replication DN flag if session bound as replication dn */
+ if (connext->is_legacy_replication_dn)
+ {
+ operation_set_flag((Slapi_Operation *)object, OP_FLAG_LEGACY_REPLICATION_DN);
+ }
+ }
+ }
+ else
+ {
+ /* (parent==NULL) for internal operations */
+ PR_ASSERT(object!=NULL);
+ }
+
+ return ext;
+}
+
+/* consumer operation extension destructor */
+void consumer_operation_extension_destructor (void *ext,void *object, void *parent)
+{
+ if (NULL != ext)
+ {
+ consumer_operation_extension *opext = (consumer_operation_extension *)ext;
+ if (NULL != opext->search_referrals)
+ {
+ ref_array_dup_free(opext->search_referrals); /* JCMREPL - undefined */
+ opext->search_referrals = NULL;
+ }
+ slapi_ch_free((void **)&ext);
+ }
+}
diff --git a/ldap/servers/plugins/replication/repl_ops.c b/ldap/servers/plugins/replication/repl_ops.c
new file mode 100644
index 00000000..e1e51355
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_ops.c
@@ -0,0 +1,180 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+#include "repl5.h"
+
+int
+legacy_postop( Slapi_PBlock *pb, const char *caller, int operation_type)
+{
+ int rc = 0;
+ Object *r_obj;
+ Replica *r;
+
+ r_obj = replica_get_replica_for_op (pb);
+ if (r_obj == NULL) /* there is no replica configured for this operations */
+ return 0;
+ else
+ {
+ /* check if this replica is 4.0 consumer */
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r);
+
+ /* this replica is not a 4.0 consumer - so we don't need to do any processing */
+ if (!replica_is_legacy_consumer (r))
+ {
+ object_release (r_obj);
+ return 0;
+ }
+
+ object_release (r_obj);
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ if (0 == rc)
+ {
+ if (OP_ADD == operation_type || OP_MODIFY == operation_type)
+ {
+ void *op;
+ consumer_operation_extension *opext = NULL;
+
+ /* Optimise out traversal of mods/entry if no cop{ied|ying}From present */
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ opext = (consumer_operation_extension*) repl_con_get_ext (REPL_CON_EXT_OP, op);
+ if (NULL != opext && opext->has_cf)
+ {
+ process_legacy_cf( pb );
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+
+static char *not_replicationdn_errmsg =
+ "An operation was submitted that contained copiedFrom or "
+ "copyingFrom attributes, but the connection was not bound "
+ "as the replicationdn.";
+
+int
+legacy_preop(Slapi_PBlock *pb, const char *caller, int operation_type)
+{
+ int rc = 0;
+ Slapi_Operation *operation = NULL;
+ consumer_operation_extension *opext = NULL;
+ int has_cf = 0;
+ Object *r_obj;
+ Replica *r;
+ int is_legacy_op = 0;
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
+ is_legacy_op = operation_is_flag_set(operation,OP_FLAG_LEGACY_REPLICATION_DN);
+ r_obj = replica_get_replica_for_op (pb);
+
+ if (r_obj == NULL) { /* there is no replica configured for this operations */
+ if (is_legacy_op){
+ /* This is a legacy replication operation but there are NO replica defined
+ Just refuse it */
+ slapi_send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Replication operation refused because the consumer is not defined as a replica", 0, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Incoming replication operation was refused because "
+ "there's no replica defined for this operation\n");
+ return -1;
+ }
+ else {
+ return 0;
+ }
+ }
+ else
+ {
+ /* check if this replica is 4.0 consumer */
+ r = (Replica*)object_get_data (r_obj);
+ PR_ASSERT (r);
+
+ if (!replica_is_legacy_consumer (r))
+ {
+ object_release (r_obj);
+ if (is_legacy_op) {
+ /* This is a legacy replication operation
+ but the replica is doesn't accept from legacy
+ Just refuse it */
+ slapi_send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Replication operation refused because "
+ "the consumer is not defined as a legacy replica", 0, NULL);
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "Incoming replication operation was refused because "
+ "there's no legacy replica defined for this operation\n");
+ return -1;
+ } else {
+ return 0;
+ }
+ }
+
+ object_release (r_obj);
+ }
+
+ opext = (consumer_operation_extension*) repl_con_get_ext (REPL_CON_EXT_OP, operation);
+
+ switch (operation_type) {
+ case OP_ADD:
+ {
+ Slapi_Entry *e = NULL;
+ Slapi_Attr *attr;
+ /*
+ * Check if the entry being added has copiedFrom/copyingFrom
+ * attributes.
+ */
+ slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
+ if (NULL != e)
+ {
+ if (slapi_entry_attr_find(e, type_copiedFrom, &attr) == 0)
+ {
+ has_cf = 1;
+ }
+ else
+ if (slapi_entry_attr_find(e, type_copyingFrom, &attr) == 0)
+ {
+ has_cf = 1;
+ }
+ }
+ /* JCMREPL - If this is a replicated operation then the baggage control also contains the Unique Identifier of the superior entry. */
+ }
+ break;
+ case OP_MODIFY:
+ {
+ LDAPMod **mods = NULL;
+ int i;
+
+ /*
+ * Check if the modification contains copiedFrom/copyingFrom
+ * attributes.
+ */
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ for (i = 0; NULL != mods && NULL != mods[i]; i++)
+ {
+ if ((strcasecmp(mods[i]->mod_type, type_copiedFrom) == 0) ||
+ (strcasecmp(mods[i]->mod_type, type_copyingFrom) == 0))
+ {
+ has_cf = 1;
+ }
+ }
+ }
+ break;
+ case OP_DELETE:
+ break;
+ case OP_MODDN:
+ break;
+ }
+
+ /* Squirrel away an optimization hint for the postop plugin */
+ opext->has_cf = has_cf;
+
+ return rc;
+}
diff --git a/ldap/servers/plugins/replication/repl_rootdse.c b/ldap/servers/plugins/replication/repl_rootdse.c
new file mode 100644
index 00000000..2bd1d8e8
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_rootdse.c
@@ -0,0 +1,79 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <string.h>
+
+#include "repl.h"
+#include "cl4.h"
+#include "slapi-plugin.h"
+
+/* Forward Declartions */
+static int repl_rootdse_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+
+int
+repl_rootdse_init()
+{
+ /* The FE DSE *must* be initialised before we get here */
+ int return_value= LDAP_SUCCESS;
+
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,"",LDAP_SCOPE_BASE,"(objectclass=*)",repl_rootdse_search,NULL);
+
+ return return_value;
+}
+
+static int
+repl_rootdse_search(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+
+#if 0
+ struct berval val;
+ struct berval *vals[2];
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* machine data suffix */
+ val.bv_val = REPL_CONFIG_TOP;
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, ATTR_NETSCAPEMDSUFFIX, vals );
+
+ /* Changelog information */
+/* ONREPL because we now support multiple 4.0 changelogs we no longer publish
+ info in the rootdse */
+ if ( get_repl_backend() != NULL )
+ {
+ char buf[BUFSIZ];
+ changeNumber cnum;
+
+ /* Changelog suffix */
+ val.bv_val = changelog4_get_suffix ();
+ if ( val.bv_val != NULL )
+ {
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "changelog", vals );
+ }
+ slapi_ch_free ((void **)&val.bv_val);
+
+ /* First change number contained in log */
+ cnum = ldapi_get_first_changenumber();
+ sprintf( buf, "%lu", cnum );
+ val.bv_val = buf;
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "firstchangenumber", vals );
+
+ /* Last change number contained in log */
+ cnum = ldapi_get_last_changenumber();
+ sprintf( buf, "%lu", cnum );
+ val.bv_val = buf;
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "lastchangenumber", vals );
+ }
+#endif
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+
diff --git a/ldap/servers/plugins/replication/repl_search.c b/ldap/servers/plugins/replication/repl_search.c
new file mode 100644
index 00000000..cfa21222
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_search.c
@@ -0,0 +1,25 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "repl.h"
+
+/* XXXggood I think we no longer need this - the mapping tree should do it for us */
+int
+legacy_preop_search( Slapi_PBlock *pb )
+{
+ int return_code = 0;
+ return return_code;
+}
+
+
+/* XXXggood I think we no longer need this - the mapping tree should do it for us */
+int
+legacy_pre_entry( Slapi_PBlock *pb )
+{
+ int return_code = 0;
+ return return_code;
+}
diff --git a/ldap/servers/plugins/replication/repl_shared.h b/ldap/servers/plugins/replication/repl_shared.h
new file mode 100644
index 00000000..0c7454ab
--- /dev/null
+++ b/ldap/servers/plugins/replication/repl_shared.h
@@ -0,0 +1,132 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* repl_shared.h - definitions shared between 4.0 and 5.0 replication
+ modules
+ */
+
+#ifndef REPL_SHARED_H
+#define REPL_SHARED_H
+
+#include "slapi-private.h"
+#include "slapi-plugin.h"
+#include "ldif.h" /* GGOODREPL - is this cheating? */
+
+#ifdef _WIN32
+#define FILE_PATHSEP '\\'
+#else
+#define FILE_PATHSEP '/'
+#endif
+
+#define CHANGELOGDB_TRIM_INTERVAL 300 /* 5 minutes */
+
+#define CONFIG_CHANGELOG_DIR_ATTRIBUTE "nsslapd-changelogdir"
+#define CONFIG_CHANGELOG_MAXENTRIES_ATTRIBUTE "nsslapd-changelogmaxentries"
+#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage"
+/* Changelog Internal Configuration Parameters -> DB related */
+#define CONFIG_CHANGELOG_DB_DBCACHESIZE "nsslapd-dbcachesize"
+#define CONFIG_CHANGELOG_DB_DURABLE_TRANSACTIONS "nsslapd-db-durable-transaction"
+#define CONFIG_CHANGELOG_DB_CHECKPOINT_INTERVAL "nsslapd-db-checkpoint-interval"
+#define CONFIG_CHANGELOG_DB_CIRCULAR_LOGGING "nsslapd-db-circular-logging"
+#define CONFIG_CHANGELOG_DB_PAGE_SIZE "nsslapd-db-page-size"
+#define CONFIG_CHANGELOG_DB_LOGFILE_SIZE "nsslapd-db-logfile-size"
+#define CONFIG_CHANGELOG_DB_MAXTXN_SIZE "nsslapd-db-max-txn"
+#define CONFIG_CHANGELOG_DB_VERBOSE "nsslapd-db-verbose"
+#define CONFIG_CHANGELOG_DB_DEBUG "nsslapd-db-debug"
+#define CONFIG_CHANGELOG_DB_TRICKLE_PERCENTAGE "nsslapd-db-trickle-percentage"
+#define CONFIG_CHANGELOG_DB_SPINCOUNT "nsslapd-db-spin-count"
+/* Changelog Internal Configuration Parameters -> Changelog Cache related */
+#define CONFIG_CHANGELOG_CACHESIZE "nsslapd-cachesize"
+#define CONFIG_CHANGELOG_CACHEMEMSIZE "nsslapd-cachememsize"
+#define CONFIG_CHANGELOG_NB_LOCK "nsslapd-db-locks"
+#define CONFIG_CHANGELOG_MAX_CONCURRENT_WRITES "nsslapd-changelogmaxconcurrentwrites"
+
+#define T_CHANGETYPESTR "changetype"
+#define T_CHANGETYPE 1
+#define T_TIMESTR "time"
+#define T_TIME 2
+#define T_DNSTR "dn"
+#define T_DN 3
+#define T_CHANGESTR "change"
+#define T_CHANGE 4
+
+#define T_ADDCTSTR "add"
+#define T_ADDCT 4
+#define T_MODIFYCTSTR "modify"
+#define T_MODIFYCT 5
+#define T_DELETECTSTR "delete"
+#define T_DELETECT 6
+#define T_MODRDNCTSTR "modrdn"
+#define T_MODRDNCT 7
+#define T_MODDNCTSTR "moddn"
+#define T_MODDNCT 8
+
+#define T_MODOPADDSTR "add"
+#define T_MODOPADD 9
+#define T_MODOPREPLACESTR "replace"
+#define T_MODOPREPLACE 10
+#define T_MODOPDELETESTR "delete"
+#define T_MODOPDELETE 11
+#define T_MODSEPSTR "-"
+#define T_MODSEP 12
+
+#define T_NEWRDNSTR "newrdn"
+#define T_NEWSUPERIORSTR ATTR_NEWSUPERIOR
+#define T_DRDNFLAGSTR "deleteoldrdn"
+
+#define T_ERR -1
+#define AWAITING_OP -1
+
+#define STATE_REFERRAL "referral"
+#define STATE_UPDATE_REFERRAL "referral on update"
+#define STATE_BACKEND "backend"
+
+#define REPL_PLUGIN_NAME "NSMMReplicationPlugin"
+/*
+ * Changed version from 1.0 to 2.0 when we switched from libdb32 to libdb33
+ * richm 20020708
+ * also changed name from REPL_PLUGIN_VERSION to CHANGELOG_DB_VERSION since we use
+ * a different version for the plugin itself and this particular version is only
+ * used for the changelog database
+*/
+/*
+ * Changed version from 2.0 to 3.0 when we switched from libdb33 to libdb41
+ * noriko 20021203
+ */
+#define CHANGELOG_DB_VERSION_PREV "3.0"
+#define CHANGELOG_DB_VERSION "4.0"
+extern char *repl_plugin_name;
+extern char *repl_plugin_name_cl;
+
+/* repl_monitor.c */
+int repl_monitor_init();
+
+/* In replutil.c */
+char ** get_cleattrs();
+unsigned long strntoul( char *from, size_t len, int base );
+void freepmods( LDAPMod **pmods );
+char *copy_berval (struct berval* from);
+void entry_print(Slapi_Entry *e);
+int copyfile(char* source, char *destination, int overwrite, int mode);
+time_t age_str2time (const char *age);
+const char* changeType2Str (int type);
+int str2ChangeType (const char *str);
+lenstr *make_changes_string(LDAPMod **ldm, char **includeattrs);
+Slapi_Mods* parse_changes_string(char *str);
+PRBool IsValidOperation (const slapi_operation_parameters *op);
+const char *map_repl_root_to_dbid(Slapi_DN *repl_root);
+PRBool is_ruv_tombstone_entry (Slapi_Entry *e);
+
+/* replication plugins */
+enum {
+ PLUGIN_LEGACY_REPLICATION,
+ PLUGIN_MULTIMASTER_REPLICATION,
+ PLUGIN_MAX
+};
+
+void* repl_get_plugin_identity (int pluginID);
+void repl_set_plugin_identity (int pluginID, void *identity);
+
+#endif
diff --git a/ldap/servers/plugins/replication/replication.def b/ldap/servers/plugins/replication/replication.def
new file mode 100644
index 00000000..e71be4f6
--- /dev/null
+++ b/ldap/servers/plugins/replication/replication.def
@@ -0,0 +1,16 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+;
+;
+DESCRIPTION 'Netscape Directory Server 7.0 Replication Plugin'
+;CODE SHARED READ EXECUTE
+;DATA SHARED READ WRITE
+EXPORTS
+ plugin_init_debug_level @1
+ replication_legacy_plugin_init @2
+ replication_multimaster_plugin_init @3
+ repl_chain_on_update @4
diff --git a/ldap/servers/plugins/replication/replutil.c b/ldap/servers/plugins/replication/replutil.c
new file mode 100644
index 00000000..f8a23f93
--- /dev/null
+++ b/ldap/servers/plugins/replication/replutil.c
@@ -0,0 +1,1073 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+ /*
+ * replutil.c - various utility functions common to all replication methods.
+ */
+
+#include <nspr.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#ifndef _WIN32
+#include <sys/file.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#endif
+#ifdef OS_solaris
+#include <dlfcn.h> /* needed for dlopen and dlsym */
+#endif /* solaris: dlopen */
+#include <time.h>
+#ifdef LINUX
+#include <errno.h> /* weird use of errno */
+#endif
+
+#include "slapi-plugin.h"
+#include "repl5.h"
+#include "repl.h"
+
+typedef int (*open_fn)(const char *path, int flags, ...);
+
+/* this is set during replication plugin initialization from the plugin entry */
+static char *replpluginpath = NULL;
+static PRBool is_chain_on_update_setup(const Slapi_DN *replroot);
+
+/*
+ * All standard changeLogEntry attributes (initialized in get_cleattrs)
+ */
+static char *cleattrs[ 10 ] = { NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL };
+
+/*
+ * Function: get_cleattrs
+ *
+ * Returns: an array of pointers to attribute names.
+ *
+ * Arguments: None.
+ *
+ * Description: Initializes, if necessary, and returns an array of char *s
+ * with attribute names used for retrieving changeLogEntry
+ * entries from the directory.
+ */
+char **
+get_cleattrs()
+{
+ if ( cleattrs[ 0 ] == NULL ) {
+ cleattrs[ 0 ] = type_objectclass;
+ cleattrs[ 1 ] = attr_changenumber;
+ cleattrs[ 2 ] = attr_targetdn;
+ cleattrs[ 3 ] = attr_changetype;
+ cleattrs[ 4 ] = attr_newrdn;
+ cleattrs[ 5 ] = attr_deleteoldrdn;
+ cleattrs[ 6 ] = attr_changes;
+ cleattrs[ 7 ] = attr_newsuperior;
+ cleattrs[ 8 ] = attr_changetime;
+ cleattrs[ 9 ] = NULL;
+ }
+ return cleattrs;
+}
+
+/*
+ * Function: add_bval2mods
+ *
+ * Description: same as add_val2mods, but sticks in a bval instead.
+ * val can be null.
+ */
+void
+add_bval2mods(LDAPMod **mod, char *type, char *val, int mod_op)
+{
+ *mod = (LDAPMod *) slapi_ch_calloc(1, sizeof (LDAPMod));
+ memset (*mod, 0, sizeof(LDAPMod));
+ (*mod)->mod_op = mod_op | LDAP_MOD_BVALUES;
+ (*mod)->mod_type = slapi_ch_strdup(type);
+
+ if (val != NULL){
+ (*mod)->mod_bvalues = (struct berval **) slapi_ch_calloc(2, sizeof(struct berval *));
+ (*mod)->mod_bvalues[0] = (struct berval *) slapi_ch_malloc (sizeof(struct berval));
+ (*mod)->mod_bvalues[1] = NULL;
+ (*mod)->mod_bvalues[0]->bv_len = strlen(val);
+ (*mod)->mod_bvalues[0]->bv_val = slapi_ch_strdup(val);
+ } else {
+ (*mod)->mod_bvalues = NULL;
+ }
+}
+
+
+char*
+copy_berval (struct berval* from)
+{
+ char* s = slapi_ch_malloc (from->bv_len + 1);
+ memcpy (s, from->bv_val, from->bv_len);
+ s [from->bv_len] = '\0';
+ return s;
+}
+
+
+/*
+ * Function: entry_print
+ * Arguments: e - entry to print
+ * Returns: nothing
+ * Description: Prints the contents of an Slapi_Entry struct. Used for debugging.
+ */
+void
+entry_print( Slapi_Entry *e )
+{
+ int sz;
+ char *p;
+
+ printf( "Slapi_Entry dump:\n" );
+
+ if ( e == NULL ) {
+ printf( "Slapi_Entry is NULL\n" );
+ return;
+ }
+
+ if (( p = slapi_entry2str( e, &sz )) == NULL ) {
+ printf( "slapi_entry2str returned NULL\n" );
+ return;
+ }
+ puts( p );
+ fflush( stdout );
+ free( p );
+ return;
+}
+
+/* NSPR supports large file, but, according to dboreham, it does not work.
+ The backed has its own functions to deal with large files. I thought
+ about making them slapi function, but I don't think it makes sense because
+ server should only export function which have to do with its operation
+ and copying files is not one of them. So, instead, I made a copy of it in the
+ replication module. I will switch it to NSPR once that stuff works.
+*/
+
+int copyfile(char* source, char * destination, int overwrite, int mode)
+{
+#if defined _WIN32
+ return (0 == CopyFile(source,destination,overwrite ? FALSE : TRUE));
+#else
+#ifdef DB_USE_64LFS
+#define OPEN_FUNCTION dblayer_open_large
+#else
+#define OPEN_FUNCTION open
+#endif
+ int source_fd = -1;
+ int dest_fd = -1;
+ char *buffer = NULL;
+ int return_value = -1;
+ int bytes_to_write = 0;
+
+ /* malloc the buffer */
+ buffer = (char*) malloc(64*1024);
+ if (NULL == buffer)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "copy file: memory allocation failed\n");
+ goto error;
+ }
+ /* Open source file */
+ source_fd = OPEN_FUNCTION(source,O_RDONLY,0);
+ if (-1 == source_fd)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "copyfile: failed to open source file %s\n", source);
+ goto error;
+ }
+ /* Open destination file */
+ dest_fd = OPEN_FUNCTION(destination,O_CREAT | O_WRONLY, mode);
+ if (-1 == dest_fd)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "copyfile: failed to open destination file %s\n", destination);
+ goto error;
+ }
+ /* Loop round reading data and writing it */
+ while (1)
+ {
+ return_value = read(source_fd,buffer,64*1024);
+ if (return_value <= 0)
+ {
+ /* means error or EOF */
+ break;
+ }
+ bytes_to_write = return_value;
+ return_value = write(dest_fd,buffer,bytes_to_write);
+ if (return_value != bytes_to_write)
+ {
+ /* means error */
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "copyfile: failed to write to destination file %s\n");
+ return_value = -1;
+ break;
+ }
+ }
+error:
+ if (source_fd != -1)
+ {
+ close(source_fd);
+ }
+ if (dest_fd != -1)
+ {
+ close(dest_fd);
+ }
+ if (NULL != buffer)
+ {
+ free(buffer);
+ }
+ return return_value;
+#endif
+}
+
+/* convert time from string like 1h (1 hour) to corresponding time in seconds */
+time_t
+age_str2time (const char *age)
+{
+ char *maxage;
+ char unit;
+ time_t ageval;
+
+ if (age == NULL || age[0] == '\0' || strcmp (age, "0") == 0)
+ {
+ return 0;
+ }
+
+ maxage = slapi_ch_strdup ( age );
+ unit = maxage[ strlen( maxage ) - 1 ];
+ maxage[ strlen( maxage ) - 1 ] = '\0';
+ ageval = strntoul( maxage, strlen( maxage ), 10 );
+ if ( maxage)
+ {
+ slapi_ch_free ( (void **) &maxage );
+ }
+ switch ( unit )
+ {
+ case 's':
+ break;
+ case 'm':
+ ageval *= 60;
+ break;
+ case 'h':
+ ageval *= ( 60 * 60 );
+ break;
+ case 'd':
+ ageval *= ( 24 * 60 * 60 );
+ break;
+ case 'w':
+ ageval *= ( 7 * 24 * 60 * 60 );
+ break;
+ default:
+ slapi_log_error( SLAPI_LOG_PLUGIN, repl_plugin_name,
+ "age_str2time: unknown unit \"%c\" "
+ "for maxiumum changelog age\n", unit );
+ ageval = -1;
+ }
+
+ return ageval;
+}
+
+const char*
+changeType2Str (int type)
+{
+ switch (type)
+ {
+ case T_ADDCT: return T_ADDCTSTR;
+ case T_MODIFYCT: return T_MODIFYCTSTR;
+ case T_MODRDNCT: return T_MODRDNCTSTR;
+ case T_DELETECT: return T_DELETECTSTR;
+ default: return NULL;
+ }
+}
+
+int
+str2ChangeType (const char *str)
+{
+ if (strcasecmp (str, T_ADDCTSTR) == 0)
+ return T_ADDCT;
+
+ if (strcasecmp (str, T_MODIFYCTSTR) == 0)
+ return T_MODIFYCT;
+
+ if (strcasecmp (str, T_MODRDNCTSTR) == 0)
+ return T_MODRDNCT;
+
+ if (strcasecmp (str, T_DELETECTSTR) == 0)
+ return T_DELETECT;
+
+ return -1;
+}
+
+lenstr *
+make_changes_string(LDAPMod **ldm, char **includeattrs)
+{
+ lenstr *l;
+ int i, j, len;
+ int skip;
+
+ /* loop through the LDAPMod struct and construct the changes attribute */
+ l = lenstr_new();
+
+ for ( i = 0; ldm[ i ] != NULL; i++ ) {
+ /* If a list of explicit attributes was given, only add those */
+ if ( NULL != includeattrs ) {
+ skip = 1;
+ for ( j = 0; includeattrs[ j ] != NULL; j++ ) {
+ if ( strcasecmp( includeattrs[ j ], ldm[ i ]->mod_type ) == 0 ) {
+ skip = 0;
+ break;
+ }
+ }
+ if ( skip ) {
+ continue;
+ }
+ }
+ switch ( ldm[ i ]->mod_op & ~LDAP_MOD_BVALUES ) {
+ case LDAP_MOD_ADD:
+ addlenstr( l, "add: " );
+ addlenstr( l, ldm[ i ]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+ case LDAP_MOD_DELETE:
+ addlenstr( l, "delete: " );
+ addlenstr( l, ldm[ i ]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+ case LDAP_MOD_REPLACE:
+ addlenstr( l, "replace: " );
+ addlenstr( l, ldm[ i ]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+ }
+ for ( j = 0; ldm[ i ]->mod_bvalues != NULL &&
+ ldm[ i ]->mod_bvalues[ j ] != NULL; j++ ) {
+ char *buf = NULL;
+ char *bufp = NULL;
+
+ len = strlen( ldm[ i ]->mod_type );
+ len = LDIF_SIZE_NEEDED( len,
+ ldm[ i ]->mod_bvalues[ j ]->bv_len ) + 1;
+ buf = slapi_ch_malloc( len );
+ bufp = buf;
+ ldif_put_type_and_value( &bufp, ldm[ i ]->mod_type,
+ ldm[ i ]->mod_bvalues[ j ]->bv_val,
+ ldm[ i ]->mod_bvalues[ j ]->bv_len );
+ *bufp = '\0';
+
+ addlenstr( l, buf );
+
+ free( buf );
+ }
+ addlenstr( l, "-\n" );
+ }
+ return l;
+}
+
+/* note that the string get modified by ldif_parse*** functions */
+Slapi_Mods *
+parse_changes_string(char *str)
+{
+ int rc;
+ Slapi_Mods *mods;
+ Slapi_Mod mod;
+ char *line, *next;
+ char *type, *value;
+ int vlen;
+ struct berval bv;
+
+ /* allocate mods array */
+ mods = slapi_mods_new ();
+ if (mods == NULL)
+ return NULL;
+
+ slapi_mods_init (mods, 16); /* JCMREPL - ONREPL : 16 bigger than needed? */
+
+ /* parse mods */
+ next = str;
+ line = ldif_getline (&next);
+ while (line)
+ {
+ slapi_mod_init (&mod, 0);
+ while (line)
+ {
+ char * errmsg = NULL;
+
+ if (strcasecmp (line, "-") == 0)
+ {
+ if (slapi_mod_isvalid (&mod))
+ {
+ slapi_mods_add_smod (mods, &mod);
+ /* JCMREPL - ONREPL - slapi_mod_done(&mod) ??? */
+ }
+ else
+ {
+ /* ONREPL - need to cleanup */
+ }
+
+ line = ldif_getline (&next);
+ break;
+ }
+
+ rc = ldif_parse_line(line, &type, &value, &vlen, &errmsg);
+ if (rc != 0)
+ {
+ /* ONREPL - log warning */
+ if ( errmsg != NULL ) {
+ slapi_log_error( SLAPI_LOG_PARSE, repl_plugin_name, "%s", errmsg );
+ slapi_ch_free( (void**)&errmsg );
+ }
+ slapi_log_error( SLAPI_LOG_REPL, repl_plugin_name,
+ "Failed to parse the ldif line.\n");
+ continue;
+ }
+
+ if (strcasecmp (type, "add") == 0)
+ {
+ slapi_mod_set_operation (&mod, LDAP_MOD_ADD | LDAP_MOD_BVALUES);
+ }
+ else if (strcasecmp (type, "delete") == 0)
+ {
+ slapi_mod_set_operation (&mod, LDAP_MOD_DELETE | LDAP_MOD_BVALUES);
+ }
+ else if (strcasecmp (type, "replace") == 0)
+ {
+ slapi_mod_set_operation (&mod, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
+ }
+ else /* attr: value pair */
+ {
+ /* adding first value */
+ if (slapi_mod_get_type (&mod) == NULL)
+ {
+ slapi_mod_set_type (&mod, type);
+ }
+
+ bv.bv_val = value;
+ bv.bv_len = vlen;
+
+ slapi_mod_add_value (&mod, &bv);
+ }
+
+ line = ldif_getline (&next);
+ }
+ }
+
+ return mods;
+}
+
+static void* g_plg_identity [PLUGIN_MAX];
+
+void*
+repl_get_plugin_identity (int pluginID)
+{
+ PR_ASSERT (pluginID < PLUGIN_MAX);
+ return g_plg_identity [pluginID];
+}
+
+void
+repl_set_plugin_identity (int pluginID, void *identity)
+{
+ PR_ASSERT (pluginID < PLUGIN_MAX);
+ g_plg_identity [pluginID] = identity;
+}
+
+/* this function validates operation parameters */
+PRBool
+IsValidOperation (const slapi_operation_parameters *op)
+{
+ if (op == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "IsValidOperation: NULL operation\n");
+ return PR_FALSE;
+ }
+
+ if (op->csn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "IsValidOperation: NULL operation CSN\n");
+ return PR_FALSE;
+ }
+
+ if (op->target_address.uniqueid == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "IsValidOperation: NULL entry uniqueid\n");
+ return PR_FALSE;
+ }
+
+ if (op->target_address.dn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "IsValidOperation: NULL entry DN\n");
+ return PR_FALSE;
+ }
+
+ switch (op->operation_type)
+ {
+ case SLAPI_OPERATION_ADD: if (op->p.p_add.target_entry == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "IsValidOperation: NULL entry for add operation\n");
+ return PR_FALSE;
+ }
+ else
+ break;
+
+ case SLAPI_OPERATION_MODIFY: if (op->p.p_modify.modify_mods == NULL ||
+ op->p.p_modify.modify_mods[0] == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "IsValidOperation: NULL mods for modify operation\n");
+ return PR_FALSE;
+ }
+ else
+ break;
+
+ case SLAPI_OPERATION_MODRDN: if (op->p.p_modrdn.modrdn_mods == NULL ||
+ op->p.p_modrdn.modrdn_mods[0] == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "IsValidOperation: NULL mods for modrdn operation\n");
+ return PR_FALSE;
+ }
+ if (op->p.p_modrdn.modrdn_newrdn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name,
+ "IsValidOperation: NULL new rdn for modrdn operation\n");
+ return PR_FALSE;
+ }
+ else
+ break;
+
+ case SLAPI_OPERATION_DELETE: break;
+
+ default: return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+
+
+const char *
+map_repl_root_to_dbid(Slapi_DN *repl_root)
+{
+ const char *return_ptr;
+
+ PR_ASSERT(NULL != repl_root);
+ if (NULL != repl_root)
+ {
+ /* XXXggood get per-database ID here, when code available */
+ }
+ return_ptr = get_server_dataversion(); /* XXXggood temporary hack until we have per-database instance dbids */
+ return return_ptr;
+}
+
+
+
+PRBool
+is_ruv_tombstone_entry (Slapi_Entry *e)
+{
+ char *dn;
+ char *match;
+ PR_ASSERT (e);
+
+ dn = slapi_entry_get_dn (e);
+ PR_ASSERT (dn);
+
+ /* tombstone has rdn: nsuniqueid=ffffffff-ffffffff-ffffffff-ffffffff */
+ match = strstr (dn, RUV_STORAGE_ENTRY_UNIQUEID);
+
+ return (match != NULL);
+}
+
+LDAPControl* create_managedsait_control ()
+{
+ LDAPControl *control;
+
+ control = (LDAPControl*)slapi_ch_malloc (sizeof (LDAPControl));
+
+ control->ldctl_oid = slapi_ch_strdup (LDAP_CONTROL_MANAGEDSAIT);
+ control->ldctl_value.bv_val = NULL;
+ control->ldctl_value.bv_len = 0;
+ control->ldctl_iscritical = '\0';
+
+ return control;
+}
+
+LDAPControl* create_backend_control (Slapi_DN *sdn)
+{
+ LDAPControl *control = NULL;
+ const char *be_name = slapi_mtn_get_backend_name(sdn);
+ if (NULL != be_name) {
+ control = (LDAPControl*)slapi_ch_malloc (sizeof (LDAPControl));
+
+ control->ldctl_oid = slapi_ch_strdup ("2.16.840.1.113730.3.4.14");
+ control->ldctl_value.bv_val = strdup(be_name);
+ control->ldctl_value.bv_len = strlen (be_name);
+ control->ldctl_iscritical = 1;
+ }
+
+ return control;
+}
+
+/*
+ * HREF_CHAR_ACCEPTABLE was copied from slapd/referral.c
+ * which was copied from libldap/tmplout.c.
+ */
+/* Note: an identical function is in ../../slapd/referral.c */
+#define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \
+ ( c >= '@' && c <= 'Z' ) || \
+ ( c == '_' ) || \
+ ( c >= 'a' && c <= 'z' ))
+
+/*
+ * Function: strcat_escaped
+ *
+ * Returns: nothing
+ *
+ * Description: Appends string s2 to s1, URL-escaping (%HH) unsafe
+ * characters in s2 as appropriate. This function was
+ * copied from slapd/referral.c.
+ * which was copied from libldap/tmplout.c.
+ * added const qualifier
+ *
+ * Author: MCS
+ */
+/*
+ * append s2 to s1, URL-escaping (%HH) unsafe characters
+ */
+/* Note: an identical function is in ../../slapd/referral.c */
+static void
+strcat_escaped( char *s1, const char *s2 )
+{
+ char *p, *q;
+ char *hexdig = "0123456789ABCDEF";
+
+ p = s1 + strlen( s1 );
+ for ( q = (char*)s2; *q != '\0'; ++q ) {
+ if ( HREF_CHAR_ACCEPTABLE( *q )) {
+ *p++ = *q;
+ } else {
+ *p++ = '%';
+ *p++ = hexdig[ 0x0F & ((*(unsigned char*)q) >> 4) ];
+ *p++ = hexdig[ 0x0F & *q ];
+ }
+ }
+
+ *p = '\0';
+}
+
+/*
+ This function appends the replication root to the purl referrals found
+ in the given ruv and the other given referrals, merges the lists, and sets the
+ referrals in the mapping tree node corresponding to the given sdn, which is the
+ repl_root
+ This function also sets the mapping tree state (e.g. disabled, backend, referral,
+ referral on update) - the mapping tree has very specific rules about how states
+ can be set in the presence of referrals - specifically:
+ 1) the nsslapd-referral attribute must be set before changing the state to referral
+ or referral on update
+ 2) the state must be set to backend or disabled before removing referrals
+*/
+void
+repl_set_mtn_state_and_referrals(
+ const Slapi_DN *repl_root_sdn,
+ const char *mtn_state,
+ const RUV *ruv,
+ char **ruv_referrals,
+ char **other_referrals
+)
+{
+ int rc = 0;
+ int ii = 0;
+ char **referrals_to_set = NULL;
+ PRBool chain_on_update = is_chain_on_update_setup(repl_root_sdn);
+
+ /* Fix for blackflag bug 601440: We want the new behaviour of DS,
+ ** going forward, to now be that if the nsds5replicareferral attrib
+ ** has values, it should be the only values in nsslapd-referral (as
+ ** opposed to older behaviour of concatenating with RUV-based
+ ** referrals). -jay@netscape.com
+ */
+ if (other_referrals) {
+ /* use the referrals passed in, instead of RUV-based referrals */
+ charray_merge(&referrals_to_set, other_referrals, 1);
+ /* Do copies. referrals is freed at the end */
+ }
+ else
+ {
+ /* use the referrals from the RUV */
+ ruv_referrals= (ruv ? ruv_get_referrals(ruv) : ruv_referrals);
+ if (ruv_referrals) {
+ charray_merge(&referrals_to_set, ruv_referrals, 1);
+ if (ruv) /* free referrals from ruv_get_referrals() */
+ charray_free(ruv_referrals);
+ }
+ }
+
+ /* next, add the repl root dn to each referral if not present */
+ for (ii = 0; referrals_to_set && referrals_to_set[ii]; ++ii) {
+ struct ldap_url_desc *lud = NULL;
+ int myrc = ldap_url_parse(referrals_to_set[ii], &lud);
+ /* see if the dn is already in the referral URL */
+ if (myrc == LDAP_URL_ERR_NODN || !lud || !lud->lud_dn) {
+ /* add the dn */
+ int len = strlen(referrals_to_set[ii]);
+ const char *cdn = slapi_sdn_get_dn(repl_root_sdn);
+ char *tmpref = NULL;
+ int need_slash = 0;
+ if (referrals_to_set[ii][len-1] != '/') {
+ len++; /* add another one for the slash */
+ need_slash = 1;
+ }
+ len += (strlen(cdn) * 3) + 2; /* 3 for %HH possible per char */
+ tmpref = slapi_ch_malloc(len);
+ sprintf(tmpref, "%s%s", referrals_to_set[ii], (need_slash ? "/" : ""));
+ strcat_escaped(tmpref, cdn);
+ slapi_ch_free((void **)&referrals_to_set[ii]);
+ referrals_to_set[ii] = tmpref;
+ }
+ if (lud)
+ ldap_free_urldesc(lud);
+ }
+
+ if (!referrals_to_set) { /* deleting referrals */
+ /* Set state before */
+ if (!chain_on_update) {
+ slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
+ }
+ /* We should delete referral only if we want to set the
+ replica database in backend state mode */
+ /* if chain on update mode, go ahead and set the referrals anyway */
+ if (strcasecmp(mtn_state, STATE_BACKEND) == 0 || chain_on_update) {
+ rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
+ if (rc == LDAP_NO_SUCH_ATTRIBUTE) {
+ /* we will get no such attribute (16) if we try to set the referrals to NULL if
+ there are no referrals - not an error */
+ rc = LDAP_SUCCESS;
+ }
+ }
+ } else { /* Replacing */
+ rc = slapi_mtn_set_referral(repl_root_sdn, referrals_to_set);
+ if (rc == LDAP_SUCCESS && !chain_on_update){
+ slapi_mtn_set_state(repl_root_sdn, (char *)mtn_state);
+ }
+ }
+
+ if (rc != LDAP_SUCCESS) {
+ char ebuf[BUFSIZ];
+ slapi_log_error(SLAPI_LOG_FATAL, repl_plugin_name, "repl_set_mtn_referrals: could "
+ "not set referrals for replica %s: %d\n",
+ escape_string(slapi_sdn_get_dn(repl_root_sdn), ebuf), rc);
+ }
+
+ charray_free(referrals_to_set);
+ return;
+}
+
+/*
+ * This function allows to use a local backend in conjunction with
+ * a chaining backend
+ * The local ldbm backend is the replication consumer database
+ * (e.g. on a hub or consumer) - it is read-only except for supplier updates
+ * The chaining backend points to the supplier(s)
+ * This distribution logic forwards the update request to the chaining
+ * backend, and sends the search request to the local ldbm database
+ *
+ * To be able to use it one must define one ldbm backend and one chaining
+ * backend in the mapping tree node - the ldbm backend will usually
+ * already be there
+ *
+ */
+int
+repl_chain_on_update(Slapi_PBlock *pb, Slapi_DN * target_dn,
+ char **mtn_be_names, int be_count,
+ Slapi_DN * node_dn, int *mtn_be_states)
+{
+ char * requestor_dn;
+ unsigned long op_type;
+ Slapi_Operation *op;
+ int repl_op = 0;
+ int local_backend = -1; /* index of local backend */
+ int chaining_backend = -1; /* index of chain backend */
+ PRBool local_online = PR_FALSE; /* true if the local db is online */
+ PRBool chain_online = PR_FALSE; /* true if the chain db is online */
+ int ii;
+ int opid, connid;
+
+ slapi_pblock_get(pb, SLAPI_CONN_ID, &connid);
+ slapi_pblock_get(pb, SLAPI_OPERATION_ID, &opid);
+ /* first, we have to decide which backend is the local backend
+ * and which is the chaining one
+ * also find out if any are not online (e.g. during import)
+ */
+ for (ii = 0; ii < be_count; ++ii)
+ {
+ Slapi_Backend *be = slapi_be_select_by_instance_name(mtn_be_names[ii]);
+ if (slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA))
+ {
+ chaining_backend = ii;
+ if (mtn_be_states[ii] == SLAPI_BE_STATE_ON)
+ {
+ chain_online = PR_TRUE;
+ }
+ }
+ else
+ {
+ local_backend = ii;
+ if (mtn_be_states[ii] == SLAPI_BE_STATE_ON)
+ {
+ local_online = PR_TRUE;
+ }
+ }
+/*
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "repl_chain_on_update: conn=%d op=%d be "
+ "%s is the %s backend and is %s\n",
+ connid, opid,
+ mtn_be_names[ii], (chaining_backend == ii) ? "chaining" : "local",
+ (mtn_be_states[ii] == SLAPI_BE_STATE_ON) ? "online" : "offline");
+*/
+ }
+
+ /* if no chaining backends are defined, just use the local one */
+ if (chaining_backend == -1) {
+ return local_backend;
+ }
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+
+ /* All internal operations go to the local backend */
+ if (operation_is_flag_set(op, OP_FLAG_INTERNAL)) {
+ return local_backend;
+ }
+
+ /* Check the operation type
+ * read-only operation will go to the local backend if online
+ */
+ op_type = slapi_op_get_type(op);
+ if (local_online &&
+ ((op_type == SLAPI_OPERATION_SEARCH) ||
+ (op_type == SLAPI_OPERATION_BIND) ||
+ (op_type == SLAPI_OPERATION_UNBIND) ||
+ (op_type == SLAPI_OPERATION_COMPARE))) {
+/*
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "repl_chain_on_update: conn=%d op=%d op is "
+ "%d: using local backend\n",
+ connid, opid, op_type);
+*/
+ return local_backend;
+ }
+
+ /* if the operation is done by directory manager
+ * use local database even for updates because it is an administrative
+ * operation
+ * remarks : one could also use an update DN in the same way
+ * to let update operation go to the local backend when they are done
+ * by specific administrator user but let all the other user
+ * go to the read-write replica
+ * also - I don't think it is possible to chain directory manager
+ */
+ slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &requestor_dn);
+ if (slapi_dn_isroot(requestor_dn)) {
+/*
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "repl_chain_on_update: conn=%d op=%d requestor "
+ "is root: using local backend\n", connid, opid);
+*/
+ return local_backend;
+ }
+
+ /* if the operation is a replicated operation
+ * use local database even for updates to avoid infinite loops
+ */
+ slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ if (repl_op) {
+/*
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "repl_chain_on_update: conn=%d op=%d op is "
+ "replicated: using local backend\n", connid, opid);
+*/
+ return local_backend;
+ }
+
+ /* all other case (update while not directory manager) :
+ * or any normal non replicated client operation while local is disabled (import) :
+ * use the chaining backend
+ */
+/*
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name, "repl_chain_on_update: conn=%d op=%d using "
+ "chaining backend\n", connid, opid);
+*/
+ return chaining_backend;
+}
+
+int
+repl_enable_chain_on_update(Slapi_DN *suffix)
+{
+ /* Submit a Modify operation to add the distribution function to the mapping tree
+ node for the given suffix */
+ slapi_mods smods;
+ Slapi_Operation *op = NULL;
+ int operation_result;
+ Slapi_PBlock *pb= slapi_pblock_new();
+ char *mtnnodedn;
+
+ slapi_mods_init(&smods,2);
+
+ /* need path and file name of the replication plugin here */
+ slapi_mods_add_string(&smods, LDAP_MOD_ADD, "nsslapd-distribution-plugin", replpluginpath);
+ slapi_mods_add_string(&smods, LDAP_MOD_ADD, "nsslapd-distribution-funct", "repl_chain_on_update");
+
+ /* need DN of mapping tree node here */
+ mtnnodedn = slapi_get_mapping_tree_node_configdn(suffix);
+ slapi_modify_internal_set_pb(
+ pb,
+ mtnnodedn,
+ slapi_mods_get_ldapmods_byref(&smods), /* JCM cast */
+ NULL, /*Controls*/
+ NULL, /*uniqueid*/
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+ 0);
+
+ slapi_modify_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &operation_result);
+ slapi_ch_free_string(&mtnnodedn);
+ slapi_pblock_destroy(pb);
+ switch(operation_result)
+ {
+ case LDAP_SUCCESS:
+ /* OK, everything is fine. */
+ break;
+ default:
+ PR_ASSERT(0); /* JCMREPL FOR DEBUGGING */
+ }
+ slapi_mods_done(&smods);
+
+ return operation_result;
+}
+
+int
+repl_disable_chain_on_update(Slapi_DN *suffix)
+{
+ /* Submit a Modify operation to remove the distribution function from the mapping tree
+ node for the given suffix */
+ slapi_mods smods;
+ Slapi_Operation *op = NULL;
+ int operation_result;
+ Slapi_PBlock *pb= slapi_pblock_new();
+ char *mtnnodedn;
+
+ slapi_mods_init(&smods,2);
+
+ slapi_mods_add_modbvps(&smods, LDAP_MOD_DELETE, "nsslapd-distribution-plugin", NULL);
+ slapi_mods_add_modbvps(&smods, LDAP_MOD_DELETE, "nsslapd-distribution-funct", NULL);
+
+ /* need DN of mapping tree node here */
+ mtnnodedn = slapi_get_mapping_tree_node_configdn(suffix);
+ slapi_modify_internal_set_pb(
+ pb,
+ mtnnodedn,
+ slapi_mods_get_ldapmods_byref(&smods), /* JCM cast */
+ NULL, /*Controls*/
+ NULL, /*uniqueid*/
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+ 0);
+
+ slapi_modify_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &operation_result);
+ slapi_ch_free_string(&mtnnodedn);
+ slapi_pblock_destroy(pb);
+ switch(operation_result)
+ {
+ case LDAP_SUCCESS:
+ /* OK, everything is fine. */
+ break;
+ default:
+ PR_ASSERT(0); /* JCMREPL FOR DEBUGGING */
+ }
+ slapi_mods_done(&smods);
+
+ return operation_result;
+}
+
+static PRBool
+is_chain_on_update_setup(const Slapi_DN *replroot)
+{
+ /* Do an internal search of the mapping tree node to see if chain on update is setup
+ for this replica
+ - has two backends
+ - has a distribution function
+ - has a distribution plugin
+ - one of the backends is a ldbm database
+ - one of the backends is a chaining database
+ */
+ static char* attrs[] = { "nsslapd-backend",
+ "nsslapd-distribution-plugin", "nsslapd-distribution-funct",
+ NULL };
+ int operation_result;
+ Slapi_PBlock *pb= slapi_pblock_new();
+ char *mtnnodedn = slapi_get_mapping_tree_node_configdn(replroot);
+ PRBool retval = PR_FALSE;
+
+ slapi_search_internal_set_pb(
+ pb,
+ mtnnodedn,
+ LDAP_SCOPE_BASE,
+ "objectclass=*",
+ attrs, /*attrs*/
+ 0, /*attrsonly*/
+ NULL, /*Controls*/
+ NULL, /*uniqueid*/
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+ 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &operation_result);
+ switch(operation_result)
+ {
+ case LDAP_SUCCESS:
+ {
+ Slapi_Entry **entries= NULL;
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if(entries!=NULL && entries[0]!=NULL)
+ {
+ Slapi_Entry *e = entries[0];
+
+ char **backends = slapi_entry_attr_get_charray(e, "nsslapd-backend");
+ char *plg = slapi_entry_attr_get_charptr(e, "nsslapd-distribution-plugin");
+ char *func = slapi_entry_attr_get_charptr(e, "nsslapd-distribution-funct");
+
+ if (backends && backends[0] && backends[1] && plg && func)
+ {
+ /* all the necessary attrs are present - check to see if we
+ have one chaining backend */
+ Slapi_Backend *be0 = slapi_be_select_by_instance_name(backends[0]);
+ Slapi_Backend *be1 = slapi_be_select_by_instance_name(backends[1]);
+ PRBool foundchain0 = slapi_be_is_flag_set(be0,SLAPI_BE_FLAG_REMOTE_DATA);
+ PRBool foundchain1 = slapi_be_is_flag_set(be1,SLAPI_BE_FLAG_REMOTE_DATA);
+ retval = (foundchain0 || foundchain1) &&
+ !(foundchain0 && foundchain1); /* 1 (but not both) backend is chaining */
+ }
+ slapi_ch_array_free(backends);
+ slapi_ch_free_string(&plg);
+ slapi_ch_free_string(&func);
+ }
+ else /* could not find mapping tree entry - assume not set up */
+ {
+ }
+ }
+ break;
+ default: /* search error - assume not set up */
+ break;
+ }
+ slapi_ch_free_string(&mtnnodedn);
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+
+ return retval;
+}
+
+void
+repl_set_repl_plugin_path(const char *path)
+{
+ replpluginpath = slapi_ch_strdup(path);
+}
diff --git a/ldap/servers/plugins/replication/tests/dnp_sim.c b/ldap/servers/plugins/replication/tests/dnp_sim.c
new file mode 100644
index 00000000..ff524988
--- /dev/null
+++ b/ldap/servers/plugins/replication/tests/dnp_sim.c
@@ -0,0 +1,1033 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* dnp_simulation.c - this file varifies the correctness of dnp algorithm
+ by generating random sequences of operations, applying
+ the algorithm and outputing the result
+
+ usage: dnp_sim [-h] [-n <number of simulations> ] [-v] [-f <output file>]
+ -h - print usage information.
+ -n <number of simulations> - how many simulations to perform; default - 1.
+ -v - verbose mode (prints full entry state after each operation execution)
+ -f <output file> - file where results are stored; by default results are
+ printed to the screen.
+ -o <op file> - file that contains operation sequence to execute; by default,
+ random sequence is generated.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <memory.h>
+#include <string.h>
+#include <time.h>
+
+#define MAX_OPS 12 /* maximum number of operations in a simulation */
+#define MAX_VALS 10 /* maximum number of values is entry or dn */
+#define NOT_PRESENT -1
+
+/* data types */
+typedef struct value_state
+{
+ int value_index; /* value */
+ int presense_csn; /* last time at which we know the value was present */
+ int distinguished_csn; /* last time at which we know the value was distinguished */
+ int delete_csn; /* last attempt to delete this value */
+ int non_distinguished_csns [MAX_OPS];/* list of times at which value became non-distinguished */
+ int present; /* flag that tells whether the value iscurrently present */
+} Value_State;
+
+typedef struct entry_state
+{
+ int dn_index;
+ int dn_csn;
+ Value_State values[MAX_VALS]; /* values of the attribute */
+ int attr_delete_csn; /* last attempt to delete the entire attribute */
+} Entry_State;
+
+typedef enum
+{
+ OP_ADD_VALUE,
+ OP_RENAME_ENTRY,
+ OP_DELETE_VALUE,
+ OP_DELETE_ATTR,
+ OP_END
+} Operation_Type;
+
+typedef struct operation
+{
+ Operation_Type type; /* operation type */
+ int csn; /* operation type */
+ int value_index; /* value to add, remove or rename from */
+ int old_dn_index; /* new dn - rename only */
+}Operation;
+
+typedef struct simulator_params
+{
+ int runs; /* number of runs */
+ FILE *fout; /* output file */
+ int value_count; /* number of values */
+ int verbose; /* verbose mode */
+ Operation *ops; /* operation sequence to apply */
+ int op_count;
+}Simulator_Params;
+
+
+/* gloabl data */
+Simulator_Params sim;
+char *g_values[] =
+{
+ "v",
+ "u",
+ "w",
+ NULL
+};
+
+/* forward declarations */
+
+/* initialization */
+void process_cmd (int argc, char **argv);
+void set_default_sim_params ();
+int count_values ();
+void parse_operations_file (char *name);
+void parse_operation (char *line, int pos);
+int value2index (char *value);
+void print_usage ();
+
+/* simulation run */
+void run_simulation ();
+void generate_operations (Operation **ops, int *op_count);
+void generate_operation (Operation *op, int csn, int *last_dn_index);
+int* generate_operation_order (int op_count, int seq_num);
+void apply_operation_sequence (Operation *ops, int op_count, int *order, Entry_State *entry);
+void init_entry_state (Entry_State *entry);
+void init_value_state (Value_State *val, int seq_num);
+void apply_operation (Entry_State *entry, Operation *op);
+void free_operations (Operation **ops);
+int ** new_perm_table (int op_count);
+void free_perm_table (int ***perm_table, int op_count);
+int get_perm_count (int op_count);
+void generate_perm_table (int *elements, int element_count, int static_part,
+ int **perm_table);
+void apply_add_operation (Entry_State *entry, Operation *op);
+void apply_value_delete_operation (Entry_State *entry, Operation *op);
+void apply_attr_delete_operation (Entry_State *entry, Operation *op);
+void apply_rename_operation (Entry_State *entry, Operation *op);
+void make_value_distinguished (int op_csn, Entry_State *entry, int value_index);
+void make_value_non_distinguished (int op_csn, Entry_State *entry, int value_index);
+void purge_value_state (Value_State *value);
+void purge_non_distinguished_csns (Value_State *value);
+void resolve_value_state (Entry_State *entry, int value_index);
+int value_distinguished_at_delete (Value_State *value, int attr_delete_csn);
+int compare_entry_state (Entry_State *entry1, Entry_State *entry2, int run);
+
+/* data tracing */
+void dump_operations (Operation *ops, int op_count, int *order);
+void dump_operation (Operation *op);
+void dump_perm_table (int **perm_table, int op_count);
+void dump_entry_state (Entry_State *entry);
+void dump_value_state (Value_State *value);
+void dump_list (int *list);
+
+/* misc functions */
+int max_val (int a, int b);
+int is_list_empty (int *list);
+int min_list_val (int *list);
+int list_equal (int *list1, int *list2);
+
+int main (int argc, char **argv)
+{
+ int i;
+
+ process_cmd (argc, argv);
+
+ for (i = 0; i < sim.runs; i++)
+ {
+ fprintf (sim.fout, "*******running simulation #%d ...\n\n", i+1);
+ run_simulation ();
+ fprintf (sim.fout, "\n*******done with simulation #%d ...\n\n", i+1);
+ }
+
+ if (sim.fout != stdout)
+ fclose (sim.fout);
+
+ return 0;
+}
+
+void process_cmd (int argc, char **argv)
+{
+ int i;
+
+ set_default_sim_params ();
+
+ if (argc == 1)
+ {
+ return;
+ }
+
+ if (strcmp (argv[1], "-h") == 0) /* print help */
+ {
+ print_usage ();
+ exit (0);
+ }
+
+ i = 1;
+ while (i < argc)
+ {
+ if (strcmp (argv[i], "-v") == 0) /* verbose mode */
+ {
+ sim.verbose = 1;
+ i ++;
+ }
+ else if (strcmp (argv[i], "-n") == 0)
+ {
+ if (i < argc - 1)
+ {
+ int runs = atoi (argv[i + 1]);
+ if (runs > 0)
+ sim.runs = runs;
+ i+=2;
+ }
+ else
+ {
+ /* ONREPL print warning */
+ i++;
+ }
+ }
+ else if (strcmp (argv[i], "-f") == 0) /* output file */
+ {
+ if (i < argc - 1)
+ {
+ FILE *f = fopen (argv[i + 1], "w");
+ if (f == 0)
+ {
+ printf ("failed to open output file; error - %s, using stdout\n",
+ strerror(errno));
+ }
+ else
+ {
+ /* ONREPL print warning */
+ sim.fout = f;
+ }
+
+ i += 2;
+ }
+ else
+ i++;
+ }
+ else if (strcmp (argv[i], "-o") == 0) /* file with operation sequence */
+ {
+ if (i < argc - 1)
+ {
+ parse_operations_file (argv[i+1]);
+ i += 2;
+ }
+ else
+ {
+ /* ONREPL print warning */
+ i ++;
+ }
+ }
+ else /* unknown option */
+ {
+ printf ("unknown option - %s; ignored\n", argv[i]);
+ i ++;
+ }
+
+ }
+}
+
+void set_default_sim_params ()
+{
+ memset (&sim, 0, sizeof (sim));
+ sim.runs = 1;
+ sim.fout = stdout;
+ sim.value_count = count_values ();
+}
+
+/* file format: <op count>
+ add <value>
+ delete <value>
+ delete attribute
+ rename <value> to <value>
+ */
+void parse_operations_file (char *name)
+{
+ FILE *file = fopen (name, "r");
+ char line [256];
+ int i;
+
+ if (file == NULL)
+ {
+ printf ("failed to open operations file %s: error = %d\n", name, errno);
+ print_usage ();
+ exit (1);
+ }
+
+ i = 0;
+ while (fgets (line, sizeof (line), file))
+ {
+ if (i == 0)
+ {
+ /* read operation count */
+ sim.op_count = atoi (line);
+ if (sim.op_count < 1 || sim.op_count > MAX_OPS/2)
+ {
+ printf ("invalid operation count - %d; value must be between 1 and %d\n",
+ sim.op_count, MAX_OPS/2);
+ print_usage ();
+ exit (1);
+ }
+ else
+ {
+ sim.ops = (Operation*)malloc (sim.op_count * sizeof (Operation));
+ }
+ }
+ else
+ {
+ if (strlen (line) == 0) /* skip empty lines */
+ continue;
+ parse_operation (line, i);
+ }
+
+ i ++;
+ }
+
+}
+
+void parse_operation (char *line, int i)
+{
+ sim.ops [i - 1].csn = i;
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ if (strncmp (line, "add", 3) == 0)
+ {
+ sim.ops [i - 1].type = OP_ADD_VALUE;
+ sim.ops [i - 1].value_index = value2index (&line[4]);
+ }
+ else if (strncmp (line, "delete attribute", 16) == 0)
+ {
+ sim.ops [i - 1].type = OP_DELETE_ATTR;
+ }
+ else if (strncmp (line, "delete", 6) == 0)
+ {
+ sim.ops [i - 1].type = OP_DELETE_VALUE;
+ sim.ops [i - 1].value_index = value2index (&line[7]);
+ }
+ else if (strncmp (line, "rename", 6) == 0)
+ {
+ char *tok;
+ sim.ops [i - 1].type = OP_RENAME_ENTRY;
+ /* strtok() is not MT safe, but it is okay to call here because this is a program test */
+ tok = strtok (&line[7], " ");
+ sim.ops [i - 1].old_dn_index = value2index (tok);
+ /* skip to */
+ tok = strtok (NULL, " ");
+ tok = strtok (NULL, " ");
+ sim.ops [i - 1].value_index = value2index (tok);
+ }
+ else
+ {
+ /* invalid line */
+ printf ("invalid operation: %s\n", line);
+ exit (1);
+ }
+}
+
+int value2index (char *value)
+{
+ int i;
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ if (strcmp (g_values[i], value) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+void print_usage ()
+{
+ printf ("usage: dnp_sim [-h] [-n <number of simulations> ] [-v] [-f <output file>]\n"
+ "\t-h - print usage information\n"
+ "\t-n <number of simulations>; default - 1\n"
+ "\t-v - verbose mode\n"
+ "\t-f <output file> - by default, results are printed to the screen\n"
+ "\t-o <op file> - file that contains operation sequence to execute;\n"
+ "\tby default, random sequence is generated.\n");
+}
+
+int count_values ()
+{
+ int i;
+
+ for (i = 0; g_values[i]; i++);
+
+ return i;
+}
+
+void run_simulation ()
+{
+ int *order;
+ int i;
+ int perm_count;
+ Entry_State entry_first, entry_current;
+ int error = 0;
+
+ init_entry_state (&entry_first);
+ fprintf (sim.fout, "initial entry state :\n");
+ dump_entry_state (&entry_first);
+
+ if (sim.ops == NULL)
+ {
+ generate_operations (&sim.ops, &sim.op_count);
+ }
+ fprintf (sim.fout, "initial operation set:\n");
+ dump_operations (sim.ops, sim.op_count, NULL/* order */);
+
+ perm_count = get_perm_count (sim.op_count);
+ for (i = 0; i < perm_count; i++)
+ {
+ fprintf (sim.fout, "--------------------------------\n");
+ fprintf (sim.fout, "simulation run %d\n", i + 1);
+ fprintf (sim.fout, "--------------------------------\n");
+ order = generate_operation_order (sim.op_count, i);
+ if (i == 0)
+ apply_operation_sequence (sim.ops, sim.op_count, order, &entry_first);
+ else
+ {
+ apply_operation_sequence (sim.ops, sim.op_count, order, &entry_current);
+ error |= compare_entry_state (&entry_first, &entry_current, i + 1);
+ }
+ }
+
+ switch (error)
+ {
+ case 0: fprintf (sim.fout, "all runs left the entry in the same state\n");
+ break;
+ case 1: fprintf (sim.fout, "while value presence is consistent across all runs, "
+ "the exact state does not match\n");
+ break;
+ case 3: fprintf (sim.fout, "the runs left entries in an inconsistent state\n");
+ break;
+ }
+
+ free_operations (&sim.ops);
+}
+
+void generate_operations (Operation **ops, int *op_count)
+{
+ int i;
+ int last_dn_index = 0;
+
+ /* generate number operations in the sequence */
+ *op_count = slapi_rand () % (MAX_OPS / 2) + 1;
+ *ops = (Operation *)malloc (*op_count * sizeof (Operation));
+
+ for (i = 0; i < *op_count; i ++)
+ {
+ generate_operation (&((*ops)[i]), i + 1, &last_dn_index);
+ }
+}
+
+void generate_operation (Operation *op, int csn, int *last_dn_index)
+{
+ /* generate operation type */
+ op->type = slapi_rand () % OP_END;
+
+ /* generate value to which operation applies */
+ op->value_index = slapi_rand () % sim.value_count;
+
+ op->csn = csn;
+
+ /* generate new distinguished value */
+ if (op->type == OP_RENAME_ENTRY)
+ {
+ op->old_dn_index = *last_dn_index;
+ while (op->value_index == op->old_dn_index)
+ op->value_index = slapi_rand () % sim.value_count;
+ *last_dn_index = op->value_index;
+ }
+}
+
+int* generate_operation_order (int op_count, int seq_num)
+{
+ static int **perm_table = NULL;
+
+ /* first request - generate pemutation table */
+ if (seq_num == 0)
+ {
+ int elements [MAX_OPS];
+ int i;
+
+ if (perm_table)
+ free_perm_table (&perm_table, op_count);
+ perm_table = new_perm_table (op_count);
+
+ for (i = 0; i < op_count; i++)
+ elements [i] = i;
+
+ generate_perm_table (elements, op_count, 0 /* static part */,
+ perm_table);
+ /* dump_perm_table (perm_table, op_count);*/
+ }
+
+ return perm_table [seq_num];
+}
+
+void apply_operation_sequence (Operation *ops, int op_count, int *order, Entry_State *entry)
+{
+ int i;
+
+ init_entry_state (entry);
+
+ if (!sim.verbose)
+ {
+ if (!sim.verbose)
+ {
+ fprintf (sim.fout, "operation_sequence for this run:\n");
+ dump_operations (ops, op_count, order);
+ }
+ }
+
+ for (i = 0; i < op_count; i++)
+ {
+ apply_operation (entry, &(ops [order[i]]));
+ }
+
+ if (!sim.verbose)
+ {
+ fprintf (sim.fout, "final entry state :\n");
+ dump_entry_state (entry);
+ }
+
+}
+
+void init_entry_state (Entry_State *entry)
+{
+ int i;
+
+ memset (entry, 0, sizeof (*entry));
+ entry->attr_delete_csn = NOT_PRESENT;
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ init_value_state (&(entry->values[i]), i);
+ }
+}
+
+void init_value_state (Value_State *val, int seq_num)
+{
+ memset (val, 0, sizeof (*val));
+ val->value_index = seq_num;
+ val->present = 1;
+ val->delete_csn = NOT_PRESENT;
+ if (seq_num > 0) /* only first value is distinguished */
+ val->distinguished_csn = -1;
+}
+
+void apply_operation (Entry_State *entry, Operation *op)
+{
+ switch (op->type)
+ {
+ case OP_ADD_VALUE: apply_add_operation (entry, op);
+ break;
+
+ case OP_DELETE_VALUE: apply_value_delete_operation (entry, op);
+ break;
+
+ case OP_DELETE_ATTR: apply_attr_delete_operation (entry, op);
+ break;
+
+ case OP_RENAME_ENTRY: apply_rename_operation (entry, op);
+ break;
+ }
+
+ if (sim.verbose)
+ {
+ fprintf (sim.fout, "operation: ");
+ dump_operation (op);
+ fprintf (sim.fout, "\n");
+ dump_entry_state (entry);
+ }
+}
+
+void free_operations (Operation **ops)
+{
+ free (*ops);
+ *ops = NULL;
+}
+
+int **new_perm_table (int op_count)
+{
+ int i;
+ int **perm_table;
+ int perm_count = get_perm_count (op_count);
+
+ perm_table = (int**)malloc (perm_count * sizeof (int*));
+ for (i = 0; i < perm_count; i ++)
+ perm_table [i] = (int*) malloc (op_count * sizeof (int));
+
+ return perm_table;
+}
+
+void free_perm_table (int ***perm_table, int op_count)
+{
+ int i;
+ int perm_count = get_perm_count (op_count);
+
+ for (i = 0; i < perm_count; i ++)
+ free ((*perm_table)[i]);
+
+ free (*perm_table);
+ *perm_table = NULL;
+}
+
+void generate_perm_table (int *elements, int element_count, int static_part,
+ int **perm_table)
+{
+ int i;
+ int elements_copy [MAX_OPS];
+ int start_pos;
+
+ if (element_count - 1 == static_part)
+ {
+ memcpy (*perm_table, elements, element_count * sizeof (int));
+ return;
+ }
+
+ start_pos = 0;
+ for (i = 0; i < element_count - static_part; i ++)
+ {
+ memcpy (elements_copy, elements, element_count * sizeof (int));
+ elements_copy [static_part] = elements [static_part + i];
+ elements_copy [static_part + i] = elements [static_part];
+ generate_perm_table (elements_copy, element_count, static_part + 1,
+ &perm_table [start_pos]);
+ start_pos += get_perm_count (element_count - static_part - 1);
+ }
+}
+
+int get_perm_count (int op_count)
+{
+ int i;
+ int perm_count = 1;
+
+ for (i = 2; i <= op_count; i ++)
+ perm_count *= i;
+
+ return perm_count;
+}
+
+void apply_add_operation (Entry_State *entry, Operation *op)
+{
+ if (entry->values[op->value_index].presense_csn < op->csn)
+ {
+ entry->values[op->value_index].presense_csn = op->csn;
+ entry->values[op->value_index].present = 1;
+ resolve_value_state (entry, op->value_index);
+ }
+}
+
+void apply_value_delete_operation (Entry_State *entry, Operation *op)
+{
+ if (entry->values[op->value_index].delete_csn < op->csn)
+ {
+ entry->values[op->value_index].delete_csn = op->csn;
+ resolve_value_state (entry, op->value_index);
+ }
+}
+
+void apply_attr_delete_operation (Entry_State *entry, Operation *op)
+{
+ int i;
+
+ if (entry->attr_delete_csn < op->csn)
+ {
+ entry->attr_delete_csn = op->csn;
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ resolve_value_state (entry, i);
+ }
+ }
+}
+
+void apply_rename_operation (Entry_State *entry, Operation *op)
+{
+ if (entry->dn_csn < op->csn)
+ {
+ entry->dn_index = op->value_index;
+ entry->dn_csn = op->csn;
+ }
+
+ make_value_non_distinguished (op->csn, entry, op->old_dn_index);
+ make_value_distinguished (op->csn, entry, op->value_index);
+}
+
+void make_value_distinguished (int op_csn, Entry_State *entry, int value_index)
+{
+ Value_State *value = &(entry->values[value_index]);
+
+ if (value->distinguished_csn < op_csn)
+ {
+ value->distinguished_csn = op_csn;
+
+ if (value->presense_csn < op_csn)
+ {
+ value->present = 1;
+ value->presense_csn = op_csn;
+ }
+
+ resolve_value_state (entry, value_index);
+ }
+}
+
+void make_value_non_distinguished (int op_csn, Entry_State *entry, int value_index)
+{
+ int i = 0;
+ int index;
+ Value_State *value = &(entry->values[value_index]);
+
+ if (op_csn < value->distinguished_csn)
+ return;
+
+ /* insert into sorted list */
+ while (value->non_distinguished_csns[i] && value->non_distinguished_csns[i] < op_csn)
+ i++;
+
+ if (value->non_distinguished_csns[i] == 0)
+ value->non_distinguished_csns[i] = op_csn;
+ else
+ {
+ index = i;
+
+ while (value->non_distinguished_csns[i])
+ i++;
+
+ memcpy (&(value->non_distinguished_csns[index + 1]),
+ &(value->non_distinguished_csns[index]), (i - index) * sizeof (int));
+
+ value->non_distinguished_csns[index] = op_csn;
+ }
+
+ resolve_value_state (entry, value_index);
+}
+
+void purge_value_state (Value_State *value)
+{
+ /* value state information can be purged once a value was
+ readed/made distinguished because at that point we know that the value
+ existed/was distinguished */
+
+ purge_non_distinguished_csns (value);
+
+ if (value->delete_csn < max_val (value->distinguished_csn, value->presense_csn))
+ value->delete_csn = NOT_PRESENT;
+}
+
+void purge_non_distinguished_csns (Value_State *value)
+{
+ int i = 0;
+ int index;
+
+ while (value->non_distinguished_csns[i] &&
+ value->non_distinguished_csns[i] < value->distinguished_csn)
+ i ++;
+
+ if (i > 0)
+ {
+ index = i-1;
+ while (value->non_distinguished_csns[i])
+ i ++;
+
+ if (i > index + 1)
+ {
+ memcpy (value->non_distinguished_csns, &value->non_distinguished_csns[index+1],
+ (i - index - 1) * sizeof (int));
+ memset (&(value->non_distinguished_csns[index+1]), 0, sizeof (int) * (i - index - 1));
+ }
+ else
+ {
+ memset (value->non_distinguished_csns, 0, sizeof (int) * i);
+ }
+ }
+}
+
+int is_list_empty (int *list)
+{
+ return (list[0] == 0);
+}
+
+int min_list_val (int *list)
+{
+ return (list [0]);
+}
+
+void resolve_value_state (Entry_State *entry, int value_index)
+{
+ Value_State *value = &(entry->values[value_index]);
+
+ purge_value_state (value);
+
+ /* no deletes that effect the state */
+ if (max_val (value->delete_csn, entry->attr_delete_csn) <
+ max_val (value->distinguished_csn, value->presense_csn))
+ return;
+
+ if (value->present) /* check if it should be removed based on the current state */
+ {
+ if (!value_distinguished_at_delete (value, entry->attr_delete_csn))
+ {
+ /* note that we keep presence csn because we might have to restore
+ the value in the future */
+ value->present = 0;
+ }
+ }
+ else /* not present - check if it should be restored */
+ {
+ if (value_distinguished_at_delete (value, entry->attr_delete_csn))
+ {
+ value->present = 1;
+ }
+ }
+}
+
+/* Note we can't trim distinguished_csn (even during regular trimming)
+ because in some cases we would not be able to figure out whether
+ a value was distinguished or not at the time of deletion.
+
+ Example 1: Example2:
+ csn order operation csn order operation
+ 1 1 make V distinguished 1 1 make V distinguished
+ 3 3 delete V 2 2 make V non distinguished
+ 4 2 make V non-distinguished 3 4 delete V
+ 4 3 make V non distinguished (on another server)
+
+ if the csns up to 2 were triimed, when delete operation is received, the state
+ is exactly the same in both examples but in example one delete should not go
+ through while in example 2 it should
+
+ */
+int value_distinguished_at_delete (Value_State *value, int attr_delete_csn)
+{
+ if (value->distinguished_csn >= 0 &&
+ (is_list_empty (value->non_distinguished_csns) ||
+ min_list_val (value->non_distinguished_csns) >
+ max_val (value->delete_csn, attr_delete_csn)))
+ return 1;
+ else
+ return 0;
+}
+
+int compare_entry_state (Entry_State *entry1, Entry_State *entry2, int run)
+{
+ int j;
+ int error = 0;
+
+ /* first - quick check for present / not present */
+ for (j = 0; j < sim.value_count; j++)
+ {
+ if (entry1->values[j].present != entry2->values[j].present)
+ {
+ fprintf (sim.fout,
+ "value %s is %s present in the first run but %s present in the %d run\n",
+ g_values[j], entry1->values[j].present ? "" : "not",
+ entry2->values[j].present ? "" : "not", run);
+ error = 1;
+ }
+ }
+
+ if (error)
+ return 3;
+
+ /* compare value state */
+ error = 0;
+ if (entry1->attr_delete_csn != entry2->attr_delete_csn)
+ {
+ fprintf (sim.fout, "attribute delete csn is %d for run 1 "
+ "but is %d for run %d\n", entry1->attr_delete_csn,
+ entry2->attr_delete_csn, run);
+ error = 1;
+ }
+
+ for (j = 0; j < sim.value_count; j++)
+ {
+ if (entry1->values[j].presense_csn != entry2->values[j].presense_csn)
+ {
+ fprintf (sim.fout, "presence csn for value %s is %d in run 1 "
+ "but is %d in run %d\n", g_values[j], entry1->values[j].presense_csn,
+ entry2->values[j].presense_csn, run);
+ error = 1;
+ }
+
+ if (entry1->values[j].distinguished_csn != entry2->values[j].distinguished_csn)
+ {
+ fprintf (sim.fout, "distinguished csn for value %s is %d in run 1 "
+ "but is %d in run %d\n", g_values[j], entry1->values[j].distinguished_csn,
+ entry2->values[j].distinguished_csn, run);
+ error = 1;
+ }
+
+ if (entry1->values[j].delete_csn != entry2->values[j].delete_csn)
+ {
+ fprintf (sim.fout, "delete csn for value %s is %d in run 1 "
+ "but is %d in run %d\n", g_values[j], entry1->values[j].delete_csn,
+ entry2->values[j].delete_csn, run);
+ error = 1;
+ }
+
+ if (!list_equal (entry1->values[j].non_distinguished_csns,
+ entry2->values[j].non_distinguished_csns))
+ {
+ fprintf (sim.fout, "pending list mismatch for valye %s in runs 1 and %d\n",
+ g_values[j], run);
+ dump_list (entry1->values[j].non_distinguished_csns);
+ dump_list (entry2->values[j].non_distinguished_csns);
+ }
+ }
+
+ if (error != 0)
+ {
+ return 1;
+ }
+ else
+ return 0;
+}
+
+void dump_operations (Operation *ops, int op_count, int *order)
+{
+ int index;
+ int i;
+
+ for (i = 0; i < op_count; i ++)
+ {
+ if (order == NULL) /* current order */
+ index = i;
+ else
+ index = order [i];
+
+ dump_operation (&ops[index]);
+ }
+
+ fprintf (sim.fout, "\n");
+}
+
+void dump_operation (Operation *op)
+{
+ switch (op->type)
+ {
+ case OP_ADD_VALUE:
+ fprintf (sim.fout, "\t%d add value %s\n", op->csn,
+ g_values [op->value_index]);
+ break;
+ case OP_DELETE_VALUE:
+ fprintf (sim.fout, "\t%d delete value %s\n", op->csn,
+ g_values [op->value_index]);
+ break;
+ case OP_DELETE_ATTR:
+ fprintf (sim.fout, "\t%d delete attribute\n", op->csn);
+ break;
+ case OP_RENAME_ENTRY:
+ fprintf (sim.fout, "\t%d rename entry from %s to %s\n", op->csn,
+ g_values [op->old_dn_index], g_values [op->value_index]);
+ break;
+ }
+}
+
+void dump_perm_table (int **perm_table, int op_count)
+{
+ int i, j;
+ int perm_count = get_perm_count (op_count);
+
+ for (i = 0; i < op_count; i++)
+ {
+ for (j = 0; j < perm_count; j++)
+ {
+ fprintf (sim.fout, "%d ", perm_table [j][i]);
+ }
+
+ fprintf (sim.fout, "\n");
+ }
+}
+
+void dump_entry_state (Entry_State *entry)
+{
+ int i;
+ fprintf (sim.fout, "\tentry dn: %s; dn csn - %d\n",
+ g_values [entry->dn_index], entry->dn_csn);
+
+ if (sim.verbose)
+ fprintf (sim.fout, "\n");
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ dump_value_state (&(entry->values[i]));
+ }
+
+ fprintf (sim.fout, "\n");
+}
+
+void dump_value_state (Value_State *value)
+{
+ fprintf (sim.fout, "\tvalue %s is %s\n", g_values[value->value_index],
+ value->present ? "present" : "not present");
+
+ if (sim.verbose)
+ {
+ fprintf (sim.fout, "\t\tpresent csn: %d\n", value->presense_csn);
+ fprintf (sim.fout, "\t\tdistinguished csn: %d\n", value->distinguished_csn);
+ fprintf (sim.fout, "\t\tdelete value csn: %d\n", value->delete_csn);
+ fprintf (sim.fout, "\t\tnon distinguished csns: ");
+
+ dump_list (value->non_distinguished_csns);
+
+ fprintf (sim.fout, "\n");
+ }
+}
+
+void dump_list (int *list)
+{
+ int i = 0;
+
+ while (list[i])
+ {
+ fprintf (sim.fout, "%d ", list[i]);
+ i ++;
+ }
+
+ fprintf (sim.fout, "\n");
+}
+
+/* misc functions */
+int max_val (int a, int b)
+{
+ if (a >= b)
+ return a;
+ else
+ return b;
+}
+
+int list_equal (int *list1, int *list2)
+{
+ int i;
+
+ i = 0;
+ while (list1[i] && list2[i])
+ {
+ if (list1[i] != list2[i])
+ return 0;
+
+ i ++;
+ }
+
+ if (list1[i] != list2[i])
+ return 0;
+ else
+ return 1;
+}
diff --git a/ldap/servers/plugins/replication/tests/dnp_sim2.c b/ldap/servers/plugins/replication/tests/dnp_sim2.c
new file mode 100644
index 00000000..e1838aa6
--- /dev/null
+++ b/ldap/servers/plugins/replication/tests/dnp_sim2.c
@@ -0,0 +1,972 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* dnp_simulation.c - this file varifies the correctness of dnp algorithm
+ by generating random sequences of operations, applying
+ the algorithm and outputing the result
+
+ usage: dnp_sim [-h] [-n <number of simulations> ] [-v] [-f <output file>]
+ -h - print usage information.
+ -n <number of simulations> - how many simulations to perform; default - 1.
+ -v - verbose mode (prints full entry state after each operation execution)
+ -f <output file> - file where results are stored; by default results are
+ printed to the screen.
+ -o <op file> - file that contains operation sequence to execute; by default,
+ random sequence is generated.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <memory.h>
+#include <string.h>
+#include <time.h>
+#include <windows.h>
+
+#define MAX_OPS 18 /* maximum number of operations in a simulation */
+#define MAX_VALS 10 /* maximum number of values is entry or dn */
+#define NOT_PRESENT -1
+
+/* data types */
+typedef struct value_state
+{
+ int value_index; /* value */
+ int presence_csn; /* last time at which we know the value was present */
+ int distinguished_index; /* index into dncsn list */
+ int delete_csn; /* last attempt to delete this value */
+ int present; /* flag that tells whether the value iscurrently present */
+} Value_State;
+
+typedef struct dn_csn
+{
+ int csn; /* dn csn */
+ int value_index; /* dn value */
+} Dn_Csn;
+
+typedef struct entry_state
+{
+ Dn_Csn dn_csns [MAX_VALS + 1]; /* list of dn csns for this entry */
+ int dn_csn_count; /* csn of the current dn */
+ Value_State values[MAX_VALS]; /* values of the attribute */
+ int attr_delete_csn; /* last attempt to delete the entire attribute */
+} Entry_State;
+
+typedef enum
+{
+ OP_ADD_VALUE,
+ OP_DELETE_VALUE,
+ OP_RENAME_ENTRY,
+ OP_DELETE_ATTR,
+ OP_END
+} Operation_Type;
+
+typedef struct operation
+{
+ Operation_Type type; /* operation type */
+ int csn; /* operation type */
+ int value_index; /* value to add, remove or rename from */
+}Operation;
+
+typedef struct simulator_params
+{
+ int runs; /* number of runs */
+ FILE *fout; /* output file */
+ int value_count; /* number of values */
+ int verbose; /* verbose mode */
+ Operation *ops; /* operation sequence to apply */
+ int op_count;
+}Simulator_Params;
+
+
+/* gloabl data */
+Simulator_Params sim;
+char *g_values[] =
+{
+ "v",
+ "u",
+ "w",
+ NULL
+};
+
+/* forward declarations */
+
+/* initialization */
+void process_cmd (int argc, char **argv);
+void set_default_sim_params ();
+int count_values ();
+void parse_operations_file (char *name);
+void parse_operation (char *line, int pos);
+int value2index (char *value);
+void print_usage ();
+
+/* simulation run */
+void run_simulation ();
+void generate_operations (Operation **ops, int *op_count);
+void generate_operation (Operation *op, int csn);
+int* generate_operation_order (int op_count, int seq_num);
+void apply_operation_sequence (Operation *ops, int op_count, int *order, Entry_State *entry);
+void init_entry_state (Entry_State *entry);
+void init_value_state (Value_State *val, int seq_num);
+void apply_operation (Entry_State *entry, Operation *op);
+void free_operations (Operation **ops);
+int ** new_perm_table (int op_count);
+void free_perm_table (int ***perm_table, int op_count);
+int get_perm_count (int op_count);
+void generate_perm_table (int *elements, int element_count, int static_part,
+ int **perm_table);
+void apply_add_operation (Entry_State *entry, Operation *op);
+void apply_value_delete_operation (Entry_State *entry, Operation *op);
+void apply_attr_delete_operation (Entry_State *entry, Operation *op);
+void apply_rename_operation (Entry_State *entry, Operation *op);
+void purge_value_state (Entry_State *entry, int index);
+void resolve_value_state (Entry_State *entry, int value_index);
+int value_distinguished_at_delete (Entry_State *entry, int value_index);
+int compare_entry_state (Entry_State *entry1, Entry_State *entry2, int run);
+
+/* dnc_csn handling */
+int dn_csn_add (Entry_State *entry, int value_index, int csn);
+int get_value_dn_csn (Entry_State *entry, int value_index);
+
+/* data tracing */
+void dump_operations (Operation *ops, int op_count, int *order);
+void dump_operation (Operation *op);
+void dump_perm_table (int **perm_table, int op_count);
+void dump_entry_state (Entry_State *entry);
+void dump_value_state (Value_State *value);
+void dump_dn_csn_list (Entry_State *entry);
+
+/* misc functions */
+int max_val (int a, int b);
+
+int main (int argc, char **argv)
+{
+ int i;
+
+ process_cmd (argc, argv);
+
+ for (i = 0; i < sim.runs; i++)
+ {
+ fprintf (sim.fout, "*******running simulation #%d ...\n\n", i+1);
+ run_simulation ();
+ fprintf (sim.fout, "\n*******done with simulation #%d ...\n\n", i+1);
+ }
+
+ if (sim.fout != stdout)
+ fclose (sim.fout);
+
+ return 0;
+}
+
+void process_cmd (int argc, char **argv)
+{
+ int i;
+
+ set_default_sim_params ();
+
+ if (argc == 1)
+ {
+ return;
+ }
+
+ if (strcmp (argv[1], "-h") == 0) /* print help */
+ {
+ print_usage ();
+ exit (0);
+ }
+
+ i = 1;
+ while (i < argc)
+ {
+ if (strcmp (argv[i], "-v") == 0) /* verbose mode */
+ {
+ sim.verbose = 1;
+ i ++;
+ }
+ else if (strcmp (argv[i], "-n") == 0)
+ {
+ if (i < argc - 1)
+ {
+ int runs = atoi (argv[i + 1]);
+ if (runs > 0)
+ sim.runs = runs;
+ i+=2;
+ }
+ else
+ {
+ /* ONREPL print warning */
+ i++;
+ }
+ }
+ else if (strcmp (argv[i], "-f") == 0) /* output file */
+ {
+ if (i < argc - 1)
+ {
+ FILE *f = fopen (argv[i + 1], "w");
+ if (f == 0)
+ {
+ printf ("failed to open output file; error - %s, using stdout\n",
+ strerror(errno));
+ }
+ else
+ {
+ /* ONREPL print warning */
+ sim.fout = f;
+ }
+
+ i += 2;
+ }
+ else
+ i++;
+ }
+ else if (strcmp (argv[i], "-o") == 0) /* file with operation sequence */
+ {
+ if (i < argc - 1)
+ {
+ parse_operations_file (argv[i+1]);
+ i += 2;
+ }
+ else
+ {
+ /* ONREPL print warning */
+ i ++;
+ }
+ }
+ else /* unknown option */
+ {
+ printf ("unknown option - %s; ignored\n", argv[i]);
+ i ++;
+ }
+
+ }
+}
+
+void set_default_sim_params ()
+{
+ memset (&sim, 0, sizeof (sim));
+ sim.runs = 1;
+ sim.fout = stdout;
+ sim.value_count = count_values ();
+}
+
+/* file format: <op count>
+ add <value>
+ delete <value>
+ delete attribute
+ rename to <value>
+
+ all spaces are significant
+ */
+void parse_operations_file (char *name)
+{
+ FILE *file = fopen (name, "r");
+ char line [256];
+ int i;
+
+ if (file == NULL)
+ {
+ printf ("failed to open operations file %s: error = %d\n", name, errno);
+ print_usage ();
+ exit (1);
+ }
+
+ i = 0;
+ while (fgets (line, sizeof (line), file))
+ {
+ if (i == 0)
+ {
+ /* read operation count */
+ sim.op_count = atoi (line);
+ if (sim.op_count < 1 || sim.op_count > MAX_OPS/2)
+ {
+ printf ("invalid operation count - %d; value must be between 1 and %d\n",
+ sim.op_count, MAX_OPS/2);
+ print_usage ();
+ exit (1);
+ }
+ else
+ {
+ sim.ops = (Operation*)malloc (sim.op_count * sizeof (Operation));
+ }
+ }
+ else
+ {
+ if (strlen (line) == 0) /* skip empty lines */
+ continue;
+ parse_operation (line, i);
+ }
+
+ i ++;
+ }
+}
+
+void parse_operation (char *line, int i)
+{
+ sim.ops [i - 1].csn = i;
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ if (strncmp (line, "add", 3) == 0)
+ {
+ sim.ops [i - 1].type = OP_ADD_VALUE;
+ sim.ops [i - 1].value_index = value2index (&line[4]);
+ }
+ else if (strncmp (line, "delete attribute", 16) == 0)
+ {
+ sim.ops [i - 1].type = OP_DELETE_ATTR;
+ }
+ else if (strncmp (line, "delete", 6) == 0)
+ {
+ sim.ops [i - 1].type = OP_DELETE_VALUE;
+ sim.ops [i - 1].value_index = value2index (&line[7]);
+ }
+ else if (strncmp (line, "rename to", 6) == 0)
+ {
+ sim.ops [i - 1].type = OP_RENAME_ENTRY;
+ sim.ops [i - 1].value_index = value2index (&line[10]);
+ }
+ else
+ {
+ /* invalid line */
+ printf ("invalid operation: %s\n", line);
+ exit (1);
+ }
+}
+
+int value2index (char *value)
+{
+ int i;
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ if (strcmp (g_values[i], value) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+void print_usage ()
+{
+ printf ("usage: dnp_sim [-h] [-n <number of simulations> ] [-v] [-f <output file>]\n"
+ "\t-h - print usage information\n"
+ "\t-n <number of simulations>; default - 1\n"
+ "\t-v - verbose mode\n"
+ "\t-f <output file> - by default, results are printed to the screen\n"
+ "\t-o <op file> - file that contains operation sequence to execute;\n"
+ "\tby default, random sequence is generated.\n");
+}
+
+int count_values ()
+{
+ int i;
+
+ for (i = 0; g_values[i]; i++);
+
+ return i;
+}
+
+void run_simulation ()
+{
+ int *order;
+ int i;
+ int perm_count;
+ Entry_State entry_first, entry_current;
+ int error = 0;
+
+ init_entry_state (&entry_first);
+ fprintf (sim.fout, "initial entry state :\n");
+ dump_entry_state (&entry_first);
+
+ if (sim.ops == NULL)
+ {
+ generate_operations (&sim.ops, &sim.op_count);
+ }
+ fprintf (sim.fout, "initial operation set:\n");
+ dump_operations (sim.ops, sim.op_count, NULL/* order */);
+
+ //DebugBreak ();
+
+ perm_count = get_perm_count (sim.op_count);
+ for (i = 0; i < perm_count; i++)
+ {
+ fprintf (sim.fout, "--------------------------------\n");
+ fprintf (sim.fout, "simulation run %d\n", i + 1);
+ fprintf (sim.fout, "--------------------------------\n");
+ order = generate_operation_order (sim.op_count, i);
+ if (i == 0)
+ apply_operation_sequence (sim.ops, sim.op_count, order, &entry_first);
+ else
+ {
+ apply_operation_sequence (sim.ops, sim.op_count, order, &entry_current);
+ error |= compare_entry_state (&entry_first, &entry_current, i + 1);
+ }
+ }
+
+ switch (error)
+ {
+ case 0: fprintf (sim.fout, "all runs left the entry in the same state\n");
+ break;
+ case 1: fprintf (sim.fout, "while value presence is consistent across all runs, "
+ "the exact state does not match\n");
+ break;
+ case 3: fprintf (sim.fout, "the runs left entries in an inconsistent state\n");
+ break;
+ }
+
+ free_operations (&sim.ops);
+}
+
+void generate_operations (Operation **ops, int *op_count)
+{
+ int i;
+
+ /* generate number operations in the sequence */
+ *op_count = slapi_rand () % (MAX_OPS / 2) + 1;
+ *ops = (Operation *)malloc (*op_count * sizeof (Operation));
+
+ for (i = 0; i < *op_count; i ++)
+ {
+ generate_operation (&((*ops)[i]), i + 1);
+ }
+}
+
+void generate_operation (Operation *op, int csn)
+{
+ /* generate operation type */
+ op->type = slapi_rand () % OP_END;
+
+ /* generate value to which operation applies */
+ op->value_index = slapi_rand () % sim.value_count;
+
+ op->csn = csn;
+}
+
+int* generate_operation_order (int op_count, int seq_num)
+{
+ static int **perm_table = NULL;
+
+ /* first request - generate pemutation table */
+ if (seq_num == 0)
+ {
+ int elements [MAX_OPS];
+ int i;
+
+ if (perm_table)
+ free_perm_table (&perm_table, op_count);
+ perm_table = new_perm_table (op_count);
+
+ for (i = 0; i < op_count; i++)
+ elements [i] = i;
+
+ generate_perm_table (elements, op_count, 0 /* static part */,
+ perm_table);
+ }
+
+ return perm_table [seq_num];
+}
+
+void apply_operation_sequence (Operation *ops, int op_count, int *order, Entry_State *entry)
+{
+ int i;
+
+ init_entry_state (entry);
+
+ if (!sim.verbose)
+ {
+ if (!sim.verbose)
+ {
+ fprintf (sim.fout, "operation_sequence for this run:\n");
+ dump_operations (ops, op_count, order);
+ }
+ }
+
+ for (i = 0; i < op_count; i++)
+ {
+ apply_operation (entry, &(ops [order[i]]));
+ }
+
+ if (!sim.verbose)
+ {
+ fprintf (sim.fout, "final entry state :\n");
+ dump_entry_state (entry);
+ }
+
+}
+
+void init_entry_state (Entry_State *entry)
+{
+ int i;
+
+ memset (entry, 0, sizeof (*entry));
+ entry->attr_delete_csn = NOT_PRESENT;
+ entry->dn_csn_count = 1;
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ init_value_state (&(entry->values[i]), i);
+ }
+}
+
+void init_value_state (Value_State *val, int seq_num)
+{
+ memset (val, 0, sizeof (*val));
+ val->value_index = seq_num;
+ val->present = 1;
+ val->delete_csn = NOT_PRESENT;
+ if (seq_num > 0) /* only first value is distinguished */
+ val->distinguished_index = -1;
+}
+
+void apply_operation (Entry_State *entry, Operation *op)
+{
+ switch (op->type)
+ {
+ case OP_ADD_VALUE: apply_add_operation (entry, op);
+ break;
+
+ case OP_DELETE_VALUE: apply_value_delete_operation (entry, op);
+ break;
+
+ case OP_DELETE_ATTR: apply_attr_delete_operation (entry, op);
+ break;
+
+ case OP_RENAME_ENTRY: apply_rename_operation (entry, op);
+ break;
+ }
+
+ if (sim.verbose)
+ {
+ fprintf (sim.fout, "operation: ");
+ dump_operation (op);
+ fprintf (sim.fout, "\n");
+ dump_entry_state (entry);
+ }
+}
+
+void free_operations (Operation **ops)
+{
+ free (*ops);
+ *ops = NULL;
+}
+
+int **new_perm_table (int op_count)
+{
+ int i;
+ int **perm_table;
+ int perm_count = get_perm_count (op_count);
+
+ perm_table = (int**)malloc (perm_count * sizeof (int*));
+ for (i = 0; i < perm_count; i ++)
+ perm_table [i] = (int*) malloc (op_count * sizeof (int));
+
+ return perm_table;
+}
+
+void free_perm_table (int ***perm_table, int op_count)
+{
+ int i;
+ int perm_count = get_perm_count (op_count);
+
+ for (i = 0; i < perm_count; i ++)
+ free ((*perm_table)[i]);
+
+ free (*perm_table);
+ *perm_table = NULL;
+}
+
+void generate_perm_table (int *elements, int element_count, int static_part,
+ int **perm_table)
+{
+ int i;
+ int elements_copy [MAX_OPS];
+ int start_pos;
+
+ if (element_count - 1 == static_part)
+ {
+ memcpy (*perm_table, elements, element_count * sizeof (int));
+ return;
+ }
+
+ start_pos = 0;
+ for (i = 0; i < element_count - static_part; i ++)
+ {
+ memcpy (elements_copy, elements, element_count * sizeof (int));
+ elements_copy [static_part] = elements [static_part + i];
+ elements_copy [static_part + i] = elements [static_part];
+ generate_perm_table (elements_copy, element_count, static_part + 1,
+ &perm_table [start_pos]);
+ start_pos += get_perm_count (element_count - static_part - 1);
+ }
+}
+
+int get_perm_count (int op_count)
+{
+ int i;
+ int perm_count = 1;
+
+ for (i = 2; i <= op_count; i ++)
+ perm_count *= i;
+
+ return perm_count;
+}
+
+void apply_add_operation (Entry_State *entry, Operation *op)
+{
+ if (entry->values[op->value_index].presence_csn < op->csn)
+ {
+ entry->values[op->value_index].presence_csn = op->csn;
+ resolve_value_state (entry, op->value_index);
+ }
+}
+
+void apply_value_delete_operation (Entry_State *entry, Operation *op)
+{
+ if (entry->values[op->value_index].delete_csn < op->csn)
+ {
+ entry->values[op->value_index].delete_csn = op->csn;
+ resolve_value_state (entry, op->value_index);
+ }
+}
+
+void apply_attr_delete_operation (Entry_State *entry, Operation *op)
+{
+ int i;
+
+ if (entry->attr_delete_csn < op->csn)
+ {
+ entry->attr_delete_csn = op->csn;
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ resolve_value_state (entry, i);
+ }
+ }
+}
+
+void apply_rename_operation (Entry_State *entry, Operation *op)
+{
+ int index;
+
+ if (entry->values[op->value_index].presence_csn == NOT_PRESENT)
+ entry->values[op->value_index].presence_csn = op->csn;
+
+ index = dn_csn_add (entry, op->value_index, op->csn);
+
+ if (index > 0)
+ resolve_value_state (entry, entry->dn_csns[index - 1].value_index);
+
+ resolve_value_state (entry, entry->dn_csns[index].value_index);
+}
+
+void purge_value_state (Entry_State *entry, int value_index)
+{
+ Value_State *value = &(entry->values[value_index]);
+ int value_distinguished_csn = get_value_dn_csn (entry, value_index);
+
+ if (value_distinguished_csn == -1 && value->presence_csn > value->delete_csn)
+ value->delete_csn = NOT_PRESENT;
+ else if (value->delete_csn < max_val (value_distinguished_csn, value->presence_csn))
+ value->delete_csn = NOT_PRESENT;
+}
+
+void resolve_value_state (Entry_State *entry, int value_index)
+{
+ Value_State *value = &(entry->values[value_index]);
+ int value_distinguished_csn = get_value_dn_csn (entry, value_index);
+
+ purge_value_state (entry, value_index);
+
+ /* no deletes that effect the state */
+ if (max_val (value->delete_csn, entry->attr_delete_csn) <
+ max_val (value_distinguished_csn, value->presence_csn))
+ {
+ value->present = 1;
+ return;
+ }
+
+ if (value->present) /* check if it should be removed based on the current state */
+ {
+ if (!value_distinguished_at_delete (entry, value_index))
+ {
+ value->present = 0;
+ }
+ }
+ else /* not present - check if it should be restored */
+ {
+ if (value_distinguished_at_delete (entry, value_index))
+ {
+ value->present = 1;
+ }
+ }
+}
+
+int value_distinguished_at_delete (Entry_State *entry, int value_index)
+{
+ Value_State *value = &(entry->values[value_index]);
+ int value_distinguished_csn = get_value_dn_csn (entry, value_index);
+ int delete_csn;
+ int i;
+
+ /* value has never been distinguished */
+ if (value_distinguished_csn == -1)
+ return 0;
+
+ delete_csn = max_val (entry->attr_delete_csn, value->delete_csn);
+
+ for (i = 0; i < entry->dn_csn_count; i++)
+ {
+ if (entry->dn_csns[i].csn > delete_csn)
+ break;
+ }
+
+ /* i is never equal to 0 because the csn of the first element is always
+ smaller than csn of any operation we can receive */
+ return (entry->dn_csns[i-1].value_index == value_index);
+}
+
+int compare_entry_state (Entry_State *entry1, Entry_State *entry2, int run)
+{
+ int i;
+ int error = 0;
+
+ /* first - quick check for present / not present */
+ for (i = 0; i < sim.value_count; i++)
+ {
+ if (entry1->values[i].present != entry2->values[i].present)
+ {
+ fprintf (sim.fout,
+ "value %s is %s present in the first run but %s present in the %d run\n",
+ g_values[i], entry1->values[i].present ? "" : "not",
+ entry2->values[i].present ? "" : "not", run);
+ error = 1;
+ }
+ }
+
+ if (error)
+ return 3;
+
+ /* compare dnc_csn list */
+ if (entry1->dn_csn_count != entry2->dn_csn_count)
+ {
+ fprintf (sim.fout, "dn_csn count is %d for run 1 and %d for run %d\n",
+ entry1->dn_csn_count, entry2->dn_csn_count, run);
+ error = 1;
+ }
+
+ for (i = 0; i < entry1->dn_csn_count; i++)
+ {
+ if (entry1->dn_csns [i].csn != entry2->dn_csns [i].csn ||
+ entry1->dn_csns [i].value_index != entry2->dn_csns [i].value_index)
+ {
+ fprintf (sim.fout,"elements %d of dn csn list are different:\n"
+ "\tfirst run: csn - %d, value - %s\n"
+ "\t%d run: csn - %d, value - %s\n", i,
+ entry1->dn_csns [i].csn,
+ g_values[entry1->dn_csns [i].value_index],
+ run, entry2->dn_csns [i].csn,
+ g_values[entry2->dn_csns [i].value_index]);
+
+ error = 1;
+ }
+ }
+
+ /* compare value state */
+ if (entry1->attr_delete_csn != entry2->attr_delete_csn)
+ {
+ fprintf (sim.fout, "attribute delete csn is %d for run 1 "
+ "but is %d for run %d\n", entry1->attr_delete_csn,
+ entry2->attr_delete_csn, run);
+ error = 1;
+ }
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ if (entry1->values[i].presence_csn != entry2->values[i].presence_csn)
+ {
+ fprintf (sim.fout, "presence csn for value %s is %d in run 1 "
+ "but is %d in run %d\n", g_values[i], entry1->values[i].presence_csn,
+ entry2->values[i].presence_csn, run);
+ error = 1;
+ }
+
+ if (entry1->values[i].distinguished_index != entry2->values[i].distinguished_index)
+ {
+ fprintf (sim.fout, "distinguished index for value %s is %d in run 1 "
+ "but is %d in run %d\n", g_values[i],
+ entry1->values[i].distinguished_index,
+ entry2->values[i].distinguished_index, run);
+ error = 1;
+ }
+
+ if (entry1->values[i].delete_csn != entry2->values[i].delete_csn)
+ {
+ fprintf (sim.fout, "delete csn for value %s is %d in run 1 "
+ "but is %d in run %d\n", g_values[i], entry1->values[i].delete_csn,
+ entry2->values[i].delete_csn, run);
+ error = 1;
+ }
+ }
+
+ if (error != 0)
+ {
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int dn_csn_add (Entry_State *entry, int value_index, int csn)
+{
+ int i, j;
+ int distinguished_index;
+
+ for (i = 0; i < entry->dn_csn_count; i++)
+ {
+ if (entry->dn_csns[i].csn > csn)
+ break;
+ }
+
+ if (i < entry->dn_csn_count)
+ {
+ distinguished_index = i;
+ for (j = i; j < entry->dn_csn_count; j ++)
+ {
+ if (entry->dn_csns[j].value_index == value_index)
+ distinguished_index = j + 1;
+
+ if (entry->values [entry->dn_csns[j].value_index].distinguished_index == j)
+ entry->values [entry->dn_csns[j].value_index].distinguished_index ++;
+ }
+
+ memcpy (&(entry->dn_csns[i+1]), &(entry->dn_csns[i]),
+ (entry->dn_csn_count - i) * sizeof (Dn_Csn));
+ }
+ else
+ {
+ distinguished_index = entry->dn_csn_count;
+ }
+
+ entry->values[value_index].distinguished_index = distinguished_index;
+ entry->dn_csns[i].csn = csn;
+ entry->dn_csns[i].value_index = value_index;
+ entry->dn_csn_count ++;
+
+ return i;
+}
+
+int get_value_dn_csn (Entry_State *entry, int value_index)
+{
+ Value_State *value = &(entry->values [value_index]);
+
+ if (value->distinguished_index == -1)
+ return -1;
+ else
+ return entry->dn_csns [value->distinguished_index].csn;
+}
+
+void dump_operations (Operation *ops, int op_count, int *order)
+{
+ int index;
+ int i;
+
+ for (i = 0; i < op_count; i ++)
+ {
+ if (order == NULL) /* current order */
+ index = i;
+ else
+ index = order [i];
+
+ dump_operation (&ops[index]);
+ }
+
+ fprintf (sim.fout, "\n");
+}
+
+void dump_operation (Operation *op)
+{
+ switch (op->type)
+ {
+ case OP_ADD_VALUE:
+ fprintf (sim.fout, "\t%d add value %s\n", op->csn,
+ g_values [op->value_index]);
+ break;
+ case OP_DELETE_VALUE:
+ fprintf (sim.fout, "\t%d delete value %s\n", op->csn,
+ g_values [op->value_index]);
+ break;
+ case OP_DELETE_ATTR:
+ fprintf (sim.fout, "\t%d delete attribute\n", op->csn);
+ break;
+ case OP_RENAME_ENTRY:
+ fprintf (sim.fout, "\t%d rename entry to %s\n", op->csn,
+ g_values [op->value_index]);
+ break;
+ }
+}
+
+void dump_perm_table (int **perm_table, int op_count)
+{
+ int i, j;
+ int perm_count = get_perm_count (op_count);
+
+ for (i = 0; i < op_count; i++)
+ {
+ for (j = 0; j < perm_count; j++)
+ {
+ fprintf (sim.fout, "%d ", perm_table [j][i]);
+ }
+
+ fprintf (sim.fout, "\n");
+ }
+}
+
+void dump_entry_state (Entry_State *entry)
+{
+ int i;
+
+ dump_dn_csn_list (entry);
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ dump_value_state (&(entry->values[i]));
+ }
+
+ fprintf (sim.fout, "\n");
+}
+
+void dump_value_state (Value_State *value)
+{
+ fprintf (sim.fout, "\tvalue %s is %s\n", g_values[value->value_index],
+ value->present ? "present" : "not present");
+
+ if (sim.verbose)
+ {
+ fprintf (sim.fout, "\t\tpresent csn: %d\n", value->presence_csn);
+ fprintf (sim.fout, "\t\tdistinguished index: %d\n", value->distinguished_index);
+ fprintf (sim.fout, "\t\tdelete value csn: %d\n", value->delete_csn);
+ }
+}
+
+void dump_dn_csn_list (Entry_State *entry)
+{
+ int i;
+
+ fprintf (sim.fout, "\tdn csn list: \n");
+ for (i = 0; i < entry->dn_csn_count; i++)
+ {
+ fprintf (sim.fout, "\t\tvalue: %s, csn: %d\n",
+ g_values[entry->dn_csns[i].value_index], entry->dn_csns[i].csn);
+ }
+}
+
+/* misc functions */
+int max_val (int a, int b)
+{
+ if (a >= b)
+ return a;
+ else
+ return b;
+}
diff --git a/ldap/servers/plugins/replication/tests/dnp_sim3.c b/ldap/servers/plugins/replication/tests/dnp_sim3.c
new file mode 100644
index 00000000..d018597a
--- /dev/null
+++ b/ldap/servers/plugins/replication/tests/dnp_sim3.c
@@ -0,0 +1,1489 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* dnp_simulation.c - this file varifies the correctness of dnp algorithm
+ by generating random sequences of operations, applying
+ the algorithm and outputing the result
+
+ usage: dnp_sim [-h] [-n <number of simulations> ] [-v] [-f <output file>]
+ -h - print usage information.
+ -n <number of simulations> - how many simulations to perform; default - 1.
+ -v - verbose mode (prints full entry state after each operation execution)
+ -f <output file> - file where results are stored; by default results are
+ printed to the screen.
+ -o <op file> - file that contains operation sequence to execute; by default,
+ random sequence is generated.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <memory.h>
+#include <string.h>
+#include <time.h>
+#include <windows.h>
+
+#define MAX_OPS 18 /* maximum number of operations in a simulation */
+#define MAX_VALS 10 /* maximum number of values is entry or dn */
+#define MAX_ATTR_NAME 16 /* max length of the attribute name */
+#define NOT_PRESENT -1
+#define SV_ATTR_NAME "sv_attr" /* name of the singlevalued attribute */
+#define MV_ATTR_NAME "mv_attr" /* name of the multivalued attribute */
+
+/* data types */
+
+/* value */
+typedef struct value_state
+{
+ int value_index; /* value */
+ int presence_csn; /* last time at which we know the value was present */
+ int delete_csn; /* last attempt to delete this value */
+ int present; /* flag that tells whether the value is present */
+} Value_State;
+
+/* shared attribute state */
+typedef struct attr_state
+{
+ int delete_csn; /* last deletion csn */
+ int present; /* flag that tells whether the attribute is present */
+}Attr_State;
+
+/* singlevalued attribute */
+typedef struct sv_attr_state
+{
+ Attr_State attr_state; /* shared attribute state */
+ Value_State current_value; /* current attribute value */
+ Value_State *pending_value; /* latest pending value */
+} SV_Attr_State;
+
+/* maltivalued attribute */
+typedef struct mv_attr_state
+{
+ Attr_State attr_state; /* shared attribute state */
+ Value_State values [MAX_VALS]; /* latest pending value */
+ int value_count; /* number of values in the array */
+} MV_Attr_State;
+
+/* node of dn_csn_list */
+typedef struct dn_csn
+{
+ int csn; /* dn csn */
+ int sv_attr; /* is this single valued or multivalued attr */
+ int value_index; /* dn value */
+} Dn_Csn;
+
+typedef struct entry_state
+{
+ Dn_Csn dn_csns [MAX_VALS + 1]; /* list of dn csns for this entry */
+ int dn_csn_count; /* csn of the current dn */
+ SV_Attr_State sv_attr; /* singlevalued attribute */
+ MV_Attr_State mv_attr; /* singlevalued attribute */
+} Entry_State;
+
+typedef enum
+{
+ OP_ADD_VALUE,
+ OP_DELETE_VALUE,
+ OP_RENAME_ENTRY,
+ OP_DELETE_ATTR,
+ OP_END
+} Operation_Type;
+
+typedef struct operation
+{
+ Operation_Type type; /* operation type */
+ int csn; /* operation csn */
+ int sv_attr; /* is this applied to singlevalued attribute */
+ int value_index; /* value to add, remove or rename from */
+ int delete_old_rdn; /* rename only */
+ int old_rdn_sv_attr; /* is oldrdn a singlevalued attribute */
+ int old_rdn_value_index; /* index of old_rdn */
+}Operation;
+
+typedef struct simulator_params
+{
+ int runs; /* number of runs */
+ FILE *fout; /* output file */
+ int value_count; /* number of values */
+ int verbose; /* verbose mode */
+ Operation *ops; /* operation sequence to apply */
+ int op_count;
+}Simulator_Params;
+
+
+/* gloabl data */
+Simulator_Params sim;
+char *g_values[] =
+{
+ "v",
+ "u",
+ "w",
+ NULL
+};
+
+/* forward declarations */
+
+/* initialization */
+void process_cmd (int argc, char **argv);
+void set_default_sim_params ();
+int count_values ();
+void parse_operations_file (char *name);
+void parse_operation (char *line, int pos);
+int value2index (char *value);
+void print_usage ();
+
+/* simulation run */
+void run_simulation ();
+void generate_operations (Operation **ops, int *op_count);
+void generate_operation (Operation *op, int csn);
+int* generate_operation_order (int op_count, int seq_num);
+void apply_operation_sequence (Operation *ops, int op_count, int *order, Entry_State *entry);
+void init_entry_state (Entry_State *entry);
+void init_sv_attr_state (SV_Attr_State *sv_attr);
+void init_mv_attr_state (MV_Attr_State *mv_attr);
+void init_value_state (Value_State *val, int seq_num);
+void free_operations (Operation **ops);
+int ** new_perm_table (int op_count);
+void free_perm_table (int ***perm_table, int op_count);
+int get_perm_count (int op_count);
+void generate_perm_table (int *elements, int element_count, int static_part,
+ int **perm_table);
+void apply_operation (Entry_State *entry, Operation *op);
+void apply_add_operation (Entry_State *entry, Operation *op);
+void apply_value_delete_operation (Entry_State *entry, Operation *op);
+void apply_attr_delete_operation (Entry_State *entry, Operation *op);
+void apply_rename_operation (Entry_State *entry, Operation *op);
+void resolve_mv_attr_state (Entry_State *entry, Value_State *value);
+void resolve_sv_attr_state (Entry_State *entry, Value_State *value);
+void purge_sv_attr_state (Entry_State *entry);
+void purge_mv_attr_state (Entry_State *entry, Value_State *value);
+int value_distinguished_at_csn (Entry_State *entry, int sv_attr, Value_State *value, int csn);
+
+/* state comparison */
+int compare_entry_state (Entry_State *entry1, Entry_State *entry2, int run);
+int compare_entry_state_quick (Entry_State *entry1, Entry_State *entry2, int run);
+int compare_sv_attr_state_quick (SV_Attr_State *sv_attr1, SV_Attr_State *sv_attr2, int run);
+int compare_mv_attr_state_quick (MV_Attr_State *mv_attr1, MV_Attr_State *mv_attr2, int run);
+int compare_sv_attr_state (SV_Attr_State *sv_attr1, SV_Attr_State *sv_attr2, int run);
+int compare_mv_attr_state (MV_Attr_State *mv_attr1, MV_Attr_State *mv_attr2, int run);
+int compare_value_state (Value_State *value1, Value_State *value2, int run);
+
+/* dnc_csn handling */
+int dn_csn_add (Entry_State *entry, int sv_attr, int value_index, int csn);
+
+/* data tracing */
+void dump_operations (Operation *ops, int op_count, int *order);
+void dump_operation (Operation *op);
+void dump_perm_table (int **perm_table, int op_count);
+void dump_entry_state (Entry_State *entry);
+void dump_sv_attr_state (SV_Attr_State *sv_attr);
+void dump_mv_attr_state (MV_Attr_State *mv_attr);
+void dump_value_state (Value_State *value, int sv_attr);
+void dump_dn_csn_list (Entry_State *entry);
+
+/* misc functions */
+int max_val (int a, int b);
+
+int main (int argc, char **argv)
+{
+ int i;
+
+ process_cmd (argc, argv);
+
+ for (i = 0; i < sim.runs; i++)
+ {
+ fprintf (sim.fout, "*******running simulation #%d ...\n\n", i+1);
+ run_simulation ();
+ fprintf (sim.fout, "\n*******done with simulation #%d ...\n\n", i+1);
+ }
+
+ if (sim.fout != stdout)
+ fclose (sim.fout);
+
+ return 0;
+}
+
+void process_cmd (int argc, char **argv)
+{
+ int i;
+
+ set_default_sim_params ();
+
+ if (argc == 1)
+ {
+ return;
+ }
+
+ if (strcmp (argv[1], "-h") == 0) /* print help */
+ {
+ print_usage ();
+ exit (0);
+ }
+
+ i = 1;
+ while (i < argc)
+ {
+ if (strcmp (argv[i], "-v") == 0) /* verbose mode */
+ {
+ sim.verbose = 1;
+ i ++;
+ }
+ else if (strcmp (argv[i], "-n") == 0)
+ {
+ if (i < argc - 1)
+ {
+ int runs = atoi (argv[i + 1]);
+ if (runs > 0)
+ sim.runs = runs;
+ i+=2;
+ }
+ else
+ {
+ /* ONREPL print warning */
+ i++;
+ }
+ }
+ else if (strcmp (argv[i], "-f") == 0) /* output file */
+ {
+ if (i < argc - 1)
+ {
+ FILE *f = fopen (argv[i + 1], "w");
+ if (f == 0)
+ {
+ printf ("failed to open output file; error - %s, using stdout\n",
+ strerror(errno));
+ }
+ else
+ {
+ /* ONREPL print warning */
+ sim.fout = f;
+ }
+
+ i += 2;
+ }
+ else
+ i++;
+ }
+ else if (strcmp (argv[i], "-o") == 0) /* file with operation sequence */
+ {
+ if (i < argc - 1)
+ {
+ parse_operations_file (argv[i+1]);
+ i += 2;
+ }
+ else
+ {
+ /* ONREPL print warning */
+ i ++;
+ }
+ }
+ else /* unknown option */
+ {
+ printf ("unknown option - %s; ignored\n", argv[i]);
+ i ++;
+ }
+
+ }
+}
+
+void set_default_sim_params ()
+{
+ memset (&sim, 0, sizeof (sim));
+ sim.runs = 1;
+ sim.fout = stdout;
+ sim.value_count = count_values ();
+}
+
+/* file format: <operation count>
+ add <attribute> <value>
+ delete <attribute>[ <value>]
+ rename to <attribute> <value>[ delete <attribute> <value>]
+
+ all spaces are significant
+ */
+void parse_operations_file (char *name)
+{
+ FILE *file = fopen (name, "r");
+ char line [256];
+ int i;
+
+ if (file == NULL)
+ {
+ printf ("failed to open operations file %s: error = %d\n", name, errno);
+ print_usage ();
+ exit (1);
+ }
+
+ i = 0;
+ while (fgets (line, sizeof (line), file))
+ {
+ if (i == 0)
+ {
+ /* read operation count */
+ sim.op_count = atoi (line);
+ if (sim.op_count < 1 || sim.op_count > MAX_OPS/2)
+ {
+ printf ("invalid operation count - %d; value must be between 1 and %d\n",
+ sim.op_count, MAX_OPS/2);
+ print_usage ();
+ exit (1);
+ }
+ else
+ {
+ sim.ops = (Operation*)malloc (sim.op_count * sizeof (Operation));
+ }
+ }
+ else
+ {
+ if (strlen (line) == 0) /* skip empty lines */
+ continue;
+ parse_operation (line, i);
+ }
+
+ i ++;
+ }
+}
+
+#define ADD_KEYWORD "add "
+#define DELETE_KEYWORD "delete "
+#define RENAME_KEYWORD "rename to "
+#define DELET_OLD_RDN_KEYWORD " delete "
+
+void parse_operation (char *line, int i)
+{
+ int rc = 0;
+ char *pos;
+ char buff [64];
+
+ sim.ops [i - 1].csn = i;
+
+ if (line[strlen(line) - 1] == '\n')
+ line[strlen(line) - 1] = '\0';
+
+ /* add <attribute> <value> */
+ if (strncmp (line, ADD_KEYWORD, strlen (ADD_KEYWORD)) == 0)
+ {
+ sim.ops [i - 1].type = OP_ADD_VALUE;
+ pos = strchr (&line[strlen (ADD_KEYWORD)], ' ');
+ if (pos == NULL)
+ {
+ rc = -1;
+ goto done;
+ }
+
+ memset (buff, 0, sizeof (buff));
+ strncpy (buff, &line[strlen (ADD_KEYWORD)], pos - &line[strlen (ADD_KEYWORD)]);
+ sim.ops [i - 1].sv_attr = strcmp (buff, MV_ATTR_NAME);
+ sim.ops [i - 1].value_index = value2index (pos + 1);
+ }
+ /* delete <attribute>[ <value>] */
+ else if (strncmp (line, DELETE_KEYWORD, strlen (DELETE_KEYWORD)) == 0)
+ {
+ pos = strchr (&line[strlen (DELETE_KEYWORD)], ' ');
+ if (pos == NULL) /* delete attribute version */
+ {
+ sim.ops [i - 1].type = OP_DELETE_ATTR;
+ sim.ops [i - 1].sv_attr = strcmp (&line[strlen (DELETE_KEYWORD)],
+ MV_ATTR_NAME);
+ }
+ else /* delete value version */
+ {
+ memset (buff, 0, sizeof (buff));
+ sim.ops [i - 1].type = OP_DELETE_VALUE;
+ strncpy (buff, &line[strlen (DELETE_KEYWORD)],
+ pos - &line[strlen (DELETE_KEYWORD)]);
+ sim.ops [i - 1].sv_attr = strcmp (buff, MV_ATTR_NAME);
+ sim.ops [i - 1].value_index = value2index (pos + 1);
+ }
+ }
+ /* rename to <attribute> <valued>[ delete <attribute> <value>] */
+ else if (strncmp (line, RENAME_KEYWORD, 10) == 0)
+ {
+ char *pos2;
+
+ sim.ops [i - 1].type = OP_RENAME_ENTRY;
+
+ pos = strchr (&line[strlen (RENAME_KEYWORD)], ' ');
+ if (pos == NULL)
+ {
+ rc = -1;
+ goto done;
+ }
+
+ memset (buff, 0, sizeof (buff));
+ strncpy (buff, &line[strlen (RENAME_KEYWORD)], pos - &line[strlen (RENAME_KEYWORD)]);
+ sim.ops [i - 1].sv_attr = strcmp (buff, MV_ATTR_NAME);
+
+ pos2 = strstr (pos + 1, DELET_OLD_RDN_KEYWORD);
+ if (pos2 == NULL) /* no delete old rdn part */
+ {
+ sim.ops [i - 1].value_index = value2index (pos + 1);
+ sim.ops [i - 1].delete_old_rdn = 0;
+ }
+ else
+ {
+ memset (buff, 0, sizeof (buff));
+ strncpy (buff, pos + 1, pos2 - pos - 1);
+ sim.ops [i - 1].value_index = value2index (buff);
+ pos2 += strlen (DELET_OLD_RDN_KEYWORD);
+ pos = strchr (pos2, ' ');
+ if (pos == NULL)
+ {
+ rc = -1;
+ goto done;
+ }
+
+ memset (buff, 0, sizeof (buff));
+ strncpy (buff, pos2, pos - pos2);
+ sim.ops [i - 1].delete_old_rdn = 1;
+ sim.ops [i - 1].old_rdn_sv_attr = strcmp (buff, MV_ATTR_NAME);
+ sim.ops [i - 1].old_rdn_value_index = value2index (pos + 1);
+ }
+ }
+ else
+ {
+ /* error */
+ rc = -1;
+ }
+
+done:
+ if (rc)
+ {
+ /* invalid line */
+ printf ("invalid operation: %s\n", line);
+ exit (1);
+ }
+}
+int value2index (char *value)
+{
+ int i;
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ if (strcmp (g_values[i], value) == 0)
+ return i;
+ }
+
+ return -1;
+}
+
+void print_usage ()
+{
+ printf ("usage: dnp_sim [-h] [-n <number of simulations> ] [-v] [-f <output file>]\n"
+ "\t-h - print usage information\n"
+ "\t-n <number of simulations>; default - 1\n"
+ "\t-v - verbose mode\n"
+ "\t-f <output file> - by default, results are printed to the screen\n"
+ "\t-o <op file> - file that contains operation sequence to execute;\n"
+ "\tby default, random sequence is generated.\n");
+}
+
+int count_values ()
+{
+ int i;
+
+ for (i = 0; g_values[i]; i++);
+
+ return i;
+}
+
+void run_simulation ()
+{
+ int *order;
+ int i;
+ int perm_count;
+ Entry_State entry_first, entry_current;
+ int error = 0;
+
+ init_entry_state (&entry_first);
+ fprintf (sim.fout, "initial entry state :\n");
+ dump_entry_state (&entry_first);
+
+ if (sim.ops == NULL)
+ {
+ generate_operations (&sim.ops, &sim.op_count);
+ }
+ fprintf (sim.fout, "initial operation set:\n");
+ dump_operations (sim.ops, sim.op_count, NULL/* order */);
+
+ perm_count = get_perm_count (sim.op_count);
+ for (i = 0; i < perm_count; i++)
+ {
+ fprintf (sim.fout, "--------------------------------\n");
+ fprintf (sim.fout, "simulation run %d\n", i + 1);
+ fprintf (sim.fout, "--------------------------------\n");
+ order = generate_operation_order (sim.op_count, i);
+ if (i == 0)
+ apply_operation_sequence (sim.ops, sim.op_count, order, &entry_first);
+ else
+ {
+ apply_operation_sequence (sim.ops, sim.op_count, order, &entry_current);
+ error |= compare_entry_state (&entry_first, &entry_current, i + 1);
+ }
+ }
+
+ switch (error)
+ {
+ case 0: fprintf (sim.fout, "all runs left the entry in the same state\n");
+ break;
+ case 1: fprintf (sim.fout, "while value presence is consistent across all runs, "
+ "the exact state does not match\n");
+ break;
+ case 3: fprintf (sim.fout, "the runs left entries in an inconsistent state\n");
+ break;
+ }
+
+ free_operations (&sim.ops);
+}
+
+void generate_operations (Operation **ops, int *op_count)
+{
+ int i;
+
+ /* generate number operations in the sequence */
+ *op_count = slapi_rand () % (MAX_OPS / 2) + 1;
+ *ops = (Operation *)malloc (*op_count * sizeof (Operation));
+
+ for (i = 0; i < *op_count; i ++)
+ {
+ generate_operation (&((*ops)[i]), i + 1);
+ }
+}
+
+void generate_operation (Operation *op, int csn)
+{
+ /* generate operation type */
+ op->type = slapi_rand () % OP_END;
+ op->csn = csn;
+
+ /* choose if the operation applies to the single value or
+ the multivalued attribute */
+ op->sv_attr = slapi_rand () % 2;
+
+ /* generate value to which operation applies */
+ op->value_index = slapi_rand () % sim.value_count;
+
+ if (op->type == OP_RENAME_ENTRY)
+ {
+ op->delete_old_rdn = slapi_rand () % 2;
+ if (op->delete_old_rdn)
+ {
+ op->old_rdn_sv_attr = slapi_rand () % 2;
+ op->old_rdn_value_index = slapi_rand () % sim.value_count;
+
+ while (op->old_rdn_sv_attr == op->sv_attr &&
+ op->old_rdn_value_index == op->value_index)
+ {
+ op->old_rdn_sv_attr = slapi_rand () % 2;
+ op->old_rdn_value_index = slapi_rand () % sim.value_count;
+ }
+ }
+ }
+}
+
+int* generate_operation_order (int op_count, int seq_num)
+{
+ static int **perm_table = NULL;
+
+ /* first request - generate pemutation table */
+ if (seq_num == 0)
+ {
+ int elements [MAX_OPS];
+ int i;
+
+ if (perm_table)
+ free_perm_table (&perm_table, op_count);
+ perm_table = new_perm_table (op_count);
+
+ for (i = 0; i < op_count; i++)
+ elements [i] = i;
+
+ generate_perm_table (elements, op_count, 0 /* static part */,
+ perm_table);
+ }
+
+ return perm_table [seq_num];
+}
+
+void apply_operation_sequence (Operation *ops, int op_count, int *order, Entry_State *entry)
+{
+ int i;
+
+ init_entry_state (entry);
+
+ if (!sim.verbose)
+ {
+ if (!sim.verbose)
+ {
+ fprintf (sim.fout, "operation_sequence for this run:\n");
+ dump_operations (ops, op_count, order);
+ }
+ }
+
+ for (i = 0; i < op_count; i++)
+ {
+ apply_operation (entry, &(ops [order[i]]));
+ }
+
+ if (!sim.verbose)
+ {
+ fprintf (sim.fout, "final entry state :\n");
+ dump_entry_state (entry);
+ }
+}
+
+void init_entry_state (Entry_State *entry)
+{
+ memset (entry, 0, sizeof (*entry));
+ entry->dn_csn_count = 1;
+
+ init_sv_attr_state (&entry->sv_attr);
+ init_mv_attr_state (&entry->mv_attr);
+}
+
+void init_sv_attr_state (SV_Attr_State *sv_attr)
+{
+ memset (sv_attr, 0, sizeof (*sv_attr));
+ sv_attr->attr_state.delete_csn = NOT_PRESENT;
+ sv_attr->attr_state.present = 1;
+ init_value_state (&sv_attr->current_value, 1);
+}
+
+void init_mv_attr_state (MV_Attr_State *mv_attr)
+{
+ int i;
+
+ memset (mv_attr, 0, sizeof (*mv_attr));
+ mv_attr->attr_state.delete_csn = NOT_PRESENT;
+ mv_attr->attr_state.present = 1;
+ mv_attr->value_count = sim.value_count;
+
+ for (i = 0; i < mv_attr->value_count; i++)
+ {
+ init_value_state (&(mv_attr->values[i]), i);
+ }
+}
+
+void init_value_state (Value_State *val, int seq_num)
+{
+ memset (val, 0, sizeof (*val));
+ val->value_index = seq_num;
+ val->present = 1;
+ val->delete_csn = NOT_PRESENT;
+}
+
+void apply_operation (Entry_State *entry, Operation *op)
+{
+ switch (op->type)
+ {
+ case OP_ADD_VALUE: apply_add_operation (entry, op);
+ break;
+
+ case OP_DELETE_VALUE: apply_value_delete_operation (entry, op);
+ break;
+
+ case OP_DELETE_ATTR: apply_attr_delete_operation (entry, op);
+ break;
+
+ case OP_RENAME_ENTRY: apply_rename_operation (entry, op);
+ break;
+ }
+
+ if (sim.verbose)
+ {
+ fprintf (sim.fout, "operation: ");
+ dump_operation (op);
+ fprintf (sim.fout, "\n");
+ dump_entry_state (entry);
+ }
+}
+
+void free_operations (Operation **ops)
+{
+ free (*ops);
+ *ops = NULL;
+}
+
+int **new_perm_table (int op_count)
+{
+ int i;
+ int **perm_table;
+ int perm_count = get_perm_count (op_count);
+
+ perm_table = (int**)malloc (perm_count * sizeof (int*));
+ for (i = 0; i < perm_count; i ++)
+ perm_table [i] = (int*) malloc (op_count * sizeof (int));
+
+ return perm_table;
+}
+
+void free_perm_table (int ***perm_table, int op_count)
+{
+ int i;
+ int perm_count = get_perm_count (op_count);
+
+ for (i = 0; i < perm_count; i ++)
+ free ((*perm_table)[i]);
+
+ free (*perm_table);
+ *perm_table = NULL;
+}
+
+void generate_perm_table (int *elements, int element_count, int static_part,
+ int **perm_table)
+{
+ int i;
+ int elements_copy [MAX_OPS];
+ int start_pos;
+
+ if (element_count - 1 == static_part)
+ {
+ memcpy (*perm_table, elements, element_count * sizeof (int));
+ return;
+ }
+
+ start_pos = 0;
+ for (i = 0; i < element_count - static_part; i ++)
+ {
+ memcpy (elements_copy, elements, element_count * sizeof (int));
+ elements_copy [static_part] = elements [static_part + i];
+ elements_copy [static_part + i] = elements [static_part];
+ generate_perm_table (elements_copy, element_count, static_part + 1,
+ &perm_table [start_pos]);
+ start_pos += get_perm_count (element_count - static_part - 1);
+ }
+}
+
+int get_perm_count (int op_count)
+{
+ int i;
+ int perm_count = 1;
+
+ for (i = 2; i <= op_count; i ++)
+ perm_count *= i;
+
+ return perm_count;
+}
+
+void apply_add_operation (Entry_State *entry, Operation *op)
+{
+ if (op->sv_attr)
+ {
+ Value_State *val;
+ Value_State temp_val;
+
+ if (op->value_index == entry->sv_attr.current_value.value_index)
+ {
+ val = &entry->sv_attr.current_value;
+ }
+ else if (entry->sv_attr.pending_value &&
+ op->value_index == entry->sv_attr.pending_value->value_index)
+ {
+ val = entry->sv_attr.pending_value;
+ }
+ else /* new value */
+ {
+ init_value_state (&temp_val, op->value_index);
+ val = &temp_val;
+ }
+
+ if (val->presence_csn < op->csn)
+ val->presence_csn = op->csn;
+
+ resolve_sv_attr_state (entry, val);
+ }
+ else
+ {
+ if (entry->mv_attr.values[op->value_index].presence_csn < op->csn)
+ {
+ entry->mv_attr.values[op->value_index].presence_csn = op->csn;
+ resolve_mv_attr_state (entry, &(entry->mv_attr.values[op->value_index]));
+ }
+ }
+}
+
+void apply_value_delete_operation (Entry_State *entry, Operation *op)
+{
+ if (op->sv_attr)
+ {
+ if (entry->sv_attr.attr_state.delete_csn < op->csn)
+ {
+ entry->sv_attr.attr_state.delete_csn = op->csn;
+ resolve_sv_attr_state (entry, NULL);
+ }
+ }
+ else /* mv attr */
+ {
+ if (entry->mv_attr.values[op->value_index].delete_csn < op->csn)
+ {
+ entry->mv_attr.values[op->value_index].delete_csn = op->csn;
+ resolve_mv_attr_state (entry, &(entry->mv_attr.values[op->value_index]));
+ }
+ }
+}
+
+void apply_attr_delete_operation (Entry_State *entry, Operation *op)
+{
+ int i;
+
+ if (op->sv_attr)
+ {
+ if (entry->sv_attr.attr_state.delete_csn < op->csn)
+ {
+ entry->sv_attr.attr_state.delete_csn = op->csn;
+ resolve_sv_attr_state (entry, NULL);
+ }
+ }
+ else /* mv attr */
+ {
+ if (entry->mv_attr.attr_state.delete_csn < op->csn)
+ {
+ entry->mv_attr.attr_state.delete_csn = op->csn;
+
+ for (i = 0; i < sim.value_count; i++)
+ {
+ resolve_mv_attr_state (entry, &(entry->mv_attr.values[i]));
+ }
+ }
+ }
+}
+
+void apply_rename_operation (Entry_State *entry, Operation *op)
+{
+ int index;
+ Operation del_op;
+
+ /* insert new dn into dn_csn_list */
+ index = dn_csn_add (entry, op->sv_attr, op->value_index, op->csn);
+
+ /* issue delete value operation for the old rdn */
+ if (op->delete_old_rdn)
+ {
+ del_op.type = OP_DELETE_VALUE;
+ del_op.csn = op->csn;
+ del_op.sv_attr = op->old_rdn_sv_attr;
+ del_op.value_index = op->old_rdn_value_index;
+
+ apply_value_delete_operation (entry, &del_op);
+ }
+
+ /* resolve state of the previous node in dn_csn_list */
+ if (index > 0)
+ {
+ if (entry->dn_csns[index-1].sv_attr)
+ {
+ if (entry->dn_csns[index-1].value_index ==
+ entry->sv_attr.current_value.value_index)
+ {
+ resolve_sv_attr_state (entry, &(entry->sv_attr.current_value));
+ }
+ else if (entry->sv_attr.pending_value &&
+ entry->dn_csns[index-1].value_index ==
+ entry->sv_attr.pending_value->value_index)
+ {
+ resolve_sv_attr_state (entry, entry->sv_attr.pending_value);
+ }
+ }
+ else
+ {
+ int i = entry->dn_csns[index-1].value_index;
+ resolve_mv_attr_state (entry, &(entry->mv_attr.values[i]));
+ }
+ }
+
+ /* resolve state of the new dn */
+ if (op->sv_attr)
+ {
+ Value_State *value;
+ Value_State temp_val;
+ if (op->value_index == entry->sv_attr.current_value.value_index)
+ {
+ value = &entry->sv_attr.current_value;
+ }
+ else if (entry->sv_attr.pending_value &&
+ op->value_index == entry->sv_attr.pending_value->value_index)
+ {
+ value = entry->sv_attr.pending_value;
+ }
+ else /* new value */
+ {
+ init_value_state (&temp_val, op->value_index);
+ value = &temp_val;
+ }
+
+ if (value->presence_csn == NOT_PRESENT || value->presence_csn < op->csn)
+ value->presence_csn = op->csn;
+ resolve_sv_attr_state (entry, value);
+ }
+ else
+ {
+ if (entry->mv_attr.values[op->value_index].presence_csn == NOT_PRESENT ||
+ entry->mv_attr.values[op->value_index].presence_csn < op->csn)
+ entry->mv_attr.values[op->value_index].presence_csn = op->csn;
+
+ resolve_mv_attr_state (entry, &(entry->mv_attr.values[op->value_index]));
+ }
+}
+
+void purge_mv_attr_state (Entry_State *entry, Value_State *value)
+{
+ if (value->presence_csn > value->delete_csn)
+ value->delete_csn = NOT_PRESENT;
+}
+
+void purge_sv_attr_state (Entry_State *entry)
+{
+ if (entry->sv_attr.attr_state.delete_csn != NOT_PRESENT)
+ {
+ if (entry->sv_attr.pending_value)
+ {
+ if (entry->sv_attr.attr_state.delete_csn <
+ entry->sv_attr.pending_value->presence_csn)
+ {
+ entry->sv_attr.attr_state.delete_csn = NOT_PRESENT;
+ }
+ }
+ else
+ {
+ if (entry->sv_attr.attr_state.delete_csn <
+ entry->sv_attr.current_value.presence_csn)
+ entry->sv_attr.attr_state.delete_csn = NOT_PRESENT;
+ }
+ }
+}
+
+void resolve_mv_attr_state (Entry_State *entry, Value_State *value)
+{
+ purge_mv_attr_state (entry, value);
+
+ /* no deletes that effect the state */
+ if (max_val (value->delete_csn, entry->mv_attr.attr_state.delete_csn) <
+ value->presence_csn)
+ {
+ value->present = 1;
+ return;
+ }
+
+ if (value->present) /* check if it should be removed based on the current state */
+ {
+ if (!value_distinguished_at_csn (entry, 0, value,
+ max (value->delete_csn, entry->mv_attr.attr_state.delete_csn)))
+ {
+ value->present = 0;
+ }
+ }
+ else /* not present - check if it should be restored */
+ {
+ if (value_distinguished_at_csn (entry, 0, value,
+ max (value->delete_csn, entry->mv_attr.attr_state.delete_csn)))
+ {
+ value->present = 1;
+ }
+ }
+
+ if (entry->mv_attr.attr_state.delete_csn == NOT_PRESENT)
+ {
+ entry->mv_attr.attr_state.present = 1;
+ }
+ else
+ {
+ int i;
+ int distinguished = 0;
+
+ for (i = 0; i < entry->mv_attr.value_count; i ++)
+ {
+ distinguished |= value_distinguished_at_csn (entry, 0,
+ &(entry->mv_attr.values[i]),
+ entry->mv_attr.attr_state.delete_csn);
+ }
+
+ entry->mv_attr.attr_state.present = distinguished;
+ }
+}
+
+void resolve_sv_attr_state (Entry_State *entry, Value_State *value)
+{
+ purge_sv_attr_state (entry);
+
+ if (value)
+ {
+ /* existing value is modified */
+ if (value == &(entry->sv_attr.current_value) ||
+ value == entry->sv_attr.pending_value)
+ {
+ /* check if current value should be replaced with the pending value */
+ if (entry->sv_attr.pending_value)
+ {
+ if (!value_distinguished_at_csn (entry, 1, &entry->sv_attr.current_value,
+ entry->sv_attr.current_value.presence_csn))
+ {
+ /* replace current value with the pending value */
+ memcpy (&entry->sv_attr.current_value, entry->sv_attr.pending_value,
+ sizeof (Value_State));
+ free (entry->sv_attr.pending_value);
+ entry->sv_attr.pending_value = NULL;
+ }
+ }
+ }
+ else /* addition of a new value */
+ {
+ /* new value is before the current value; note that, for new value,
+ presence_csn is the same as distinguished_csn */
+ if (value->presence_csn < entry->sv_attr.current_value.presence_csn)
+ {
+ /* if new value is distinguished, it should become current and the
+ current can become pending */
+ if (value_distinguished_at_csn (entry, 1, value,
+ entry->sv_attr.current_value.presence_csn))
+ {
+ if (entry->sv_attr.pending_value == NULL)
+ {
+ entry->sv_attr.pending_value = (Value_State*)
+ malloc (sizeof (Value_State));
+ memcpy (entry->sv_attr.pending_value, &entry->sv_attr.current_value,
+ sizeof (Value_State));
+ }
+
+ memcpy (&entry->sv_attr.current_value, value, sizeof (Value_State));
+ }
+ }
+ else /* new value is after the current value */
+ {
+ /* if current value is not distinguished, new value should
+ become distinguished */
+ if (!value_distinguished_at_csn (entry, 1, &entry->sv_attr.current_value,
+ value->presence_csn))
+ {
+ memcpy (&entry->sv_attr.current_value, value, sizeof (Value_State));
+ }
+ else /* current value is distinguished - check if new value should replace
+ the pending value */
+ { if (entry->sv_attr.pending_value)
+ {
+ if (value->presence_csn > entry->sv_attr.pending_value->presence_csn)
+ {
+ memcpy (entry->sv_attr.pending_value, value, sizeof (Value_State));
+ }
+ }
+ else
+ {
+ entry->sv_attr.pending_value = (Value_State*)malloc (sizeof (Value_State));
+ memcpy (entry->sv_attr.pending_value, value, sizeof (Value_State));
+ }
+ }
+ }
+ }
+ }
+
+ /* update the attribute state */
+ purge_sv_attr_state (entry);
+
+ /* set attribute state */
+ if (entry->sv_attr.attr_state.delete_csn != NOT_PRESENT &&
+ !value_distinguished_at_csn (entry, 1, &entry->sv_attr.current_value,
+ entry->sv_attr.attr_state.delete_csn))
+ {
+ entry->sv_attr.attr_state.present = 0;
+ }
+ else
+ {
+ entry->sv_attr.attr_state.present = 1;
+ }
+}
+
+int value_distinguished_at_csn (Entry_State *entry, int sv_attr, Value_State *value, int csn)
+{
+ int i;
+
+ for (i = 0; i < entry->dn_csn_count; i++)
+ {
+ if (entry->dn_csns[i].csn > csn)
+ break;
+ }
+
+ /* i is never equal to 0 because the csn of the first element is always
+ smaller than csn of any operation we can receive */
+ return (entry->dn_csns[i-1].value_index == value->value_index &&
+ entry->dn_csns[i-1].sv_attr == sv_attr);
+}
+
+int compare_entry_state (Entry_State *entry1, Entry_State *entry2, int run)
+{
+ int i;
+ int error = 0;
+
+ error = compare_entry_state_quick (entry1, entry2, run);
+
+ if (error)
+ return 3;
+
+ /* compare dnc_csn list */
+ if (entry1->dn_csn_count != entry2->dn_csn_count)
+ {
+ fprintf (sim.fout, "dn_csn count is %d for run 1 and %d for run %d\n",
+ entry1->dn_csn_count, entry2->dn_csn_count, run);
+ error = 1;
+ }
+
+ for (i = 0; i < entry1->dn_csn_count; i++)
+ {
+ if (entry1->dn_csns [i].csn != entry2->dn_csns [i].csn ||
+ entry1->dn_csns [i].sv_attr != entry2->dn_csns [i].sv_attr ||
+ entry1->dn_csns [i].value_index != entry2->dn_csns [i].value_index)
+ {
+ fprintf (sim.fout,"elements %d of dn csn list are different:\n"
+ "\tfirst run: csn - %d, attr - %s, value - %s\n"
+ "\t%d run: csn - %d, attr - %s value - %s\n", i,
+ entry1->dn_csns [i].csn,
+ entry1->dn_csns [i].sv_attr ? SV_ATTR_NAME : MV_ATTR_NAME,
+ g_values[entry1->dn_csns [i].value_index],
+ run, entry2->dn_csns [i].csn,
+ entry2->dn_csns [i].sv_attr ? SV_ATTR_NAME : MV_ATTR_NAME,
+ g_values[entry2->dn_csns [i].value_index]);
+
+ error = 1;
+ }
+ }
+
+ error |= compare_sv_attr_state (&entry1->sv_attr, &entry2->sv_attr, run);
+
+ error |= compare_mv_attr_state (&entry1->mv_attr, &entry2->mv_attr, run);
+
+ if (error != 0)
+ {
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/* just compare if the same attributes and values are present */
+int compare_entry_state_quick (Entry_State *entry1, Entry_State *entry2, int run)
+{
+ int error;
+
+ error = compare_sv_attr_state_quick (&entry1->sv_attr, &entry2->sv_attr, run);
+
+ error |= compare_mv_attr_state_quick (&entry1->mv_attr, &entry2->mv_attr, run);
+
+ return error;
+}
+
+int compare_sv_attr_state_quick (SV_Attr_State *sv_attr1, SV_Attr_State *sv_attr2, int run)
+{
+ int error = 0;
+ if (sv_attr1->attr_state.present != sv_attr2->attr_state.present)
+ {
+ fprintf (sim.fout, "singlevalued attribute is %s present in the first run "
+ "but is %s present in the %d run\n",
+ sv_attr1->attr_state.present ? "" : "not",
+ sv_attr2->attr_state.present ? "" : "not", run);
+ return 1;
+ }
+
+ if (sv_attr1->attr_state.present &&
+ sv_attr1->current_value.value_index != sv_attr2->current_value.value_index)
+ {
+ fprintf (sim.fout, "different values for singlevalued attribute: %s for the \n"
+ "first run and %s for the %d run\n",
+ g_values [sv_attr1->current_value.value_index],
+ g_values [sv_attr2->current_value.value_index], run);
+ return 1;
+ }
+
+ return 0;
+}
+
+int compare_mv_attr_state_quick (MV_Attr_State *mv_attr1, MV_Attr_State *mv_attr2, int run)
+{
+ int i;
+ int error = 0;
+
+ if (mv_attr1->attr_state.present != mv_attr2->attr_state.present)
+ {
+ fprintf (sim.fout, "multivalued attribute is %s present in the first run "
+ "but is %s present in the %d run\n",
+ mv_attr1->attr_state.present ? "" : "not",
+ mv_attr2->attr_state.present ? "" : "not", run);
+ return 1;
+ }
+
+ /* value count does not change during the iteration, so we don't have
+ to check if the count is the same for both attributes */
+ for (i = 0; i < mv_attr1->value_count; i++)
+ {
+ if (mv_attr1->values[i].present != mv_attr2->values[i].present)
+ {
+ fprintf (sim.fout, "value %s is %s present in the multivalued attribute\n"
+ "in the first run but %s present in the %d run\n",
+ g_values[i], mv_attr1->values[i].present ? "" : "not",
+ mv_attr2->values[i].present ? "" : "not", run);
+ error = 1;
+ }
+ }
+
+ return error;
+}
+
+int compare_sv_attr_state (SV_Attr_State *sv_attr1, SV_Attr_State *sv_attr2, int run)
+{
+ int error = 0;
+
+ if (sv_attr1->attr_state.delete_csn != sv_attr2->attr_state.delete_csn)
+ {
+ fprintf (sim.fout, "singlevalued attribute deletion csn is %d for run 1 "
+ "but is %d for run %d\n", sv_attr1->attr_state.delete_csn,
+ sv_attr2->attr_state.delete_csn, run);
+ error = 1;
+ }
+
+ error |= compare_value_state (&sv_attr1->current_value, &sv_attr2->current_value, run);
+
+ if ((sv_attr1->pending_value && !sv_attr1->pending_value) ||
+ (!sv_attr1->pending_value && sv_attr1->pending_value))
+ {
+ fprintf (sim.fout, "pending value is %s present in the singlevalued attribute\n"
+ " in the first run but is %s in the %d run\n",
+ sv_attr1->pending_value ? "" : "not",
+ sv_attr2->pending_value ? "" : "not", run);
+
+ return 1;
+ }
+
+ if (sv_attr1->pending_value)
+ error |= compare_value_state (sv_attr1->pending_value, sv_attr2->pending_value, run);
+
+ return 0;
+}
+
+int compare_mv_attr_state (MV_Attr_State *mv_attr1, MV_Attr_State *mv_attr2, int run)
+{
+ int error = 0;
+ int i;
+
+ if (mv_attr1->attr_state.delete_csn != mv_attr2->attr_state.delete_csn)
+ {
+ fprintf (sim.fout, "multivalued attribute deletion csn is %d for run 1 "
+ "but is %d for run %d\n", mv_attr1->attr_state.delete_csn,
+ mv_attr2->attr_state.delete_csn, run);
+ error = 1;
+ }
+
+ for (i = 0; i < mv_attr1->value_count; i++)
+ {
+ error |= compare_value_state (&mv_attr1->values[i], &mv_attr2->values[i], run);
+ }
+
+ return error;
+}
+
+int compare_value_state (Value_State *value1, Value_State *value2, int run)
+{
+ int error = 0;
+
+ if (value1->presence_csn != value2->presence_csn)
+ {
+ fprintf (sim.fout, "multivalued attribute: presence csn for value %s is %d "
+ "in run 1 but is %d in run %d\n", g_values[value1->value_index],
+ value1->presence_csn, value2->presence_csn, run);
+ error = 1;
+ }
+
+ if (value1->delete_csn != value2->delete_csn)
+ {
+ fprintf (sim.fout, "multivalued attribute: delete csn for value %s is %d in run 1 "
+ "but is %d in run %d\n", g_values[value1->value_index],
+ value1->delete_csn, value2->delete_csn, run);
+ error = 1;
+ }
+
+ return error;
+}
+
+int dn_csn_add (Entry_State *entry, int sv_attr, int value_index, int csn)
+{
+ int i;
+
+ for (i = 0; i < entry->dn_csn_count; i++)
+ {
+ if (entry->dn_csns[i].csn > csn)
+ break;
+ }
+
+ if (i < entry->dn_csn_count)
+ {
+ memcpy (&(entry->dn_csns[i+1]), &(entry->dn_csns[i]),
+ (entry->dn_csn_count - i) * sizeof (Dn_Csn));
+ }
+
+ entry->dn_csns[i].csn = csn;
+ entry->dn_csns[i].sv_attr = sv_attr;
+ entry->dn_csns[i].value_index = value_index;
+ entry->dn_csn_count ++;
+
+ return i;
+}
+
+void dump_operations (Operation *ops, int op_count, int *order)
+{
+ int index;
+ int i;
+
+ for (i = 0; i < op_count; i ++)
+ {
+ if (order == NULL) /* current order */
+ index = i;
+ else
+ index = order [i];
+
+ dump_operation (&ops[index]);
+ }
+
+ fprintf (sim.fout, "\n");
+}
+
+void dump_operation (Operation *op)
+{
+ switch (op->type)
+ {
+ case OP_ADD_VALUE:
+ fprintf (sim.fout, "\t%d add value %s to %s\n", op->csn,
+ g_values [op->value_index],
+ op->sv_attr ? SV_ATTR_NAME : MV_ATTR_NAME);
+ break;
+ case OP_DELETE_VALUE:
+ fprintf (sim.fout, "\t%d delete value %s from %s\n", op->csn,
+ g_values [op->value_index],
+ op->sv_attr ? SV_ATTR_NAME : MV_ATTR_NAME);
+ break;
+ case OP_DELETE_ATTR:
+ fprintf (sim.fout, "\t%d delete %s attribute\n", op->csn,
+ op->sv_attr ? SV_ATTR_NAME : MV_ATTR_NAME);
+ break;
+ case OP_RENAME_ENTRY:
+ fprintf (sim.fout, "\t%d rename entry to %s=%s", op->csn,
+ op->sv_attr ? SV_ATTR_NAME : MV_ATTR_NAME,
+ g_values [op->value_index]);
+ if (op->delete_old_rdn)
+ fprintf (sim.fout, " delete old rdn %s=%s\n",
+ op->old_rdn_sv_attr ? SV_ATTR_NAME : MV_ATTR_NAME,
+ g_values [op->old_rdn_value_index]);
+ else
+ fprintf (sim.fout, "\n");
+ break;
+ }
+}
+
+void dump_perm_table (int **perm_table, int op_count)
+{
+ int i, j;
+ int perm_count = get_perm_count (op_count);
+
+ for (i = 0; i < op_count; i++)
+ {
+ for (j = 0; j < perm_count; j++)
+ {
+ fprintf (sim.fout, "%d ", perm_table [j][i]);
+ }
+
+ fprintf (sim.fout, "\n");
+ }
+}
+
+void dump_entry_state (Entry_State *entry)
+{
+ dump_dn_csn_list (entry);
+
+ dump_sv_attr_state (&entry->sv_attr);
+ dump_mv_attr_state (&entry->mv_attr);
+
+ fprintf (sim.fout, "\n");
+}
+
+void dump_sv_attr_state (SV_Attr_State *sv_attr)
+{
+ fprintf (sim.fout, "\tattribute %s is %s present", SV_ATTR_NAME,
+ sv_attr->attr_state.present ? "" : "not");
+ if (sv_attr->attr_state.present)
+ {
+ fprintf (sim.fout, " and has the value of %s\n",
+ g_values[sv_attr->current_value.value_index]);
+ }
+ else
+ {
+ fprintf (sim.fout, "\n");
+ }
+
+ if (sim.verbose)
+ {
+ fprintf (sim.fout, "\t\tdeletion csn: %d\n", sv_attr->attr_state.delete_csn);
+ fprintf (sim.fout, "\t\tcurrent value: ");
+ dump_value_state (&sv_attr->current_value, 1/* for single valued attr */);
+ if (sv_attr->pending_value)
+ {
+ fprintf (sim.fout, "\t\tpending value: ");
+ dump_value_state (sv_attr->pending_value, 1/* for single valued attr */);
+ }
+ }
+}
+
+void dump_mv_attr_state (MV_Attr_State *mv_attr)
+{
+ int i;
+
+ fprintf (sim.fout, "\tattribute %s is %s present\n", MV_ATTR_NAME,
+ mv_attr->attr_state.present ? "" : "not");
+
+ if (sim.verbose)
+ {
+ fprintf (sim.fout, "\t\tdeletion csn: %d\n", mv_attr->attr_state.delete_csn);
+ }
+
+ for (i = 0; i < mv_attr->value_count; i++)
+ {
+ dump_value_state (&(mv_attr->values[i]), 0);
+ }
+}
+
+void dump_value_state (Value_State *value, int sv_attr)
+{
+ if (!sv_attr)
+ {
+ fprintf (sim.fout, "\tvalue %s is %s present\n", g_values[value->value_index],
+ value->present ? "" : "not");
+ }
+ else
+ {
+ fprintf (sim.fout, "%s\n", g_values[value->value_index]);
+ }
+
+ if (sim.verbose)
+ {
+ fprintf (sim.fout, "\t\t\tpresence csn: %d\n", value->presence_csn);
+ fprintf (sim.fout, "\t\t\tdeletion value csn: %d\n", value->delete_csn);
+ }
+}
+
+void dump_dn_csn_list (Entry_State *entry)
+{
+ int i;
+
+ fprintf (sim.fout, "\tdn csn list: \n");
+ for (i = 0; i < entry->dn_csn_count; i++)
+ {
+ fprintf (sim.fout, "\t\t %s=%s, csn: %d\n",
+ entry->dn_csns[i].sv_attr ? SV_ATTR_NAME : MV_ATTR_NAME,
+ g_values[entry->dn_csns[i].value_index], entry->dn_csns[i].csn);
+ }
+}
+
+/* misc functions */
+int max_val (int a, int b)
+{
+ if (a >= b)
+ return a;
+ else
+ return b;
+}
diff --git a/ldap/servers/plugins/replication/tests/makesim b/ldap/servers/plugins/replication/tests/makesim
new file mode 100755
index 00000000..0cedd6e1
--- /dev/null
+++ b/ldap/servers/plugins/replication/tests/makesim
@@ -0,0 +1,58 @@
+# 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 LDAP Server tools.
+#
+
+MCOM_ROOT = ../../../../../..
+LDAP_SRC = ../../../..
+
+NOSTDCLEAN=true # don't let nsconfig.mk define target clean
+NOSTDSTRIP=true # don't let nsconfig.mk define target strip
+
+OBJDEST = $(OBJDIR)/lib/replication-plugin
+BINDIR = $(OBJDIR)/bin
+
+include $(MCOM_ROOT)/netsite/nsdefs.mk
+include $(MCOM_ROOT)/netsite/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+LDFLAGS += $(EXLDFLAGS)
+
+ifeq ($(ARCH), WINNT)
+SUBSYSTEM=console
+endif
+
+DEPLIBS=
+
+EXTRA_LIBS_DEP =
+
+EXTRA_LIBS =
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS += user32.lib
+endif
+
+DNP_SIM = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, dnp_sim))
+
+
+all: $(OBJDEST) $(BINDIR) $(DNP_SIM)
+
+$(DNP_SIM): $(OBJDEST)/dnp_sim3.o $(EXTRA_LIBS_DEP)
+ $(LINK_EXE) $(OBJDEST)/dnp_sim3.o \
+ $(EXTRA_LIBS) $<
+
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(BINDIR):
+ $(MKDIR) $(BINDIR)
+
+clean:
+ -$(RM) $(ALL_OBJS)
+ -$(RM) $(BINS)
diff --git a/ldap/servers/plugins/replication/urp.c b/ldap/servers/plugins/replication/urp.c
new file mode 100644
index 00000000..a4dc86f9
--- /dev/null
+++ b/ldap/servers/plugins/replication/urp.c
@@ -0,0 +1,1282 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * urp.c - Update Resolution Procedures
+ */
+
+#include "slapi-plugin.h"
+#include "repl.h"
+#include "repl5.h"
+#include "urp.h"
+
+extern int slapi_log_urp;
+
+static int urp_add_resolve_parententry (Slapi_PBlock *pb, char *sessionid, Slapi_Entry *entry, Slapi_Entry *parententry, CSN *opcsn);
+static int urp_annotate_dn (char *sessionid, Slapi_Entry *entry, CSN *opcsn, const char *optype);
+static int urp_naming_conflict_removal (Slapi_PBlock *pb, char *sessionid, CSN *opcsn, const char *optype);
+static int mod_namingconflict_attr (const char *uniqueid, const char*entrydn, const char *conflictdn, CSN *opcsn);
+static int del_replconflict_attr (Slapi_Entry *entry, CSN *opcsn, int opflags);
+static char *get_dn_plus_uniqueid(char *sessionid,const char *olddn,const char *uniqueid);
+static char *get_rdn_plus_uniqueid(char *sessionid,const char *olddn,const char *uniqueid);
+static void set_pblock_dn (Slapi_PBlock* pb,int pblock_parameter,char *newdn);
+static int is_suffix_entry (Slapi_PBlock *pb, Slapi_Entry *entry, Slapi_DN **parenddn);
+
+/*
+ * Return 0 for OK, -1 for Error.
+ */
+int
+urp_modify_operation( Slapi_PBlock *pb )
+{
+ Slapi_Entry *modifyentry= NULL;
+ int op_result= 0;
+ int rc= 0; /* OK */
+
+ if ( slapi_op_abandoned(pb) )
+ {
+ return rc;
+ }
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_EXISTING_ENTRY, &modifyentry );
+
+ if(modifyentry!=NULL)
+ {
+ /*
+ * The entry to be modified exists.
+ * - the entry could be a tombstone... but that's OK.
+ * - the entry could be glue... that may not be OK. JCMREPL
+ */
+ rc= 0; /* OK, Modify the entry */
+ PROFILE_POINT; /* Modify Conflict; Entry Exists; Apply Modification */
+ }
+ else
+ {
+ /*
+ * The entry to be modified could not be found.
+ */
+ op_result= LDAP_NO_SUCH_OBJECT;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Must discard this Modification */
+ PROFILE_POINT; /* Modify Conflict; Entry Does Not Exist; Discard Modification */
+ }
+ return rc;
+}
+
+/*
+ * Return 0 for OK,
+ * -1 for Ignore or Error depending on SLAPI_RESULT_CODE,
+ * >0 for action code
+ * Action Code Bit 0: Fetch existing entry.
+ * Action Code Bit 1: Fetch parent entry.
+ * The function is called as a be pre-op on consumers.
+ */
+int
+urp_add_operation( Slapi_PBlock *pb )
+{
+ Slapi_Entry *existing_uniqueid_entry;
+ Slapi_Entry *existing_dn_entry;
+ Slapi_Entry *addentry;
+ const char *adduniqueid;
+ CSN *opcsn;
+ const char *basedn;
+ char sessionid[REPL_SESSION_ID_SIZE];
+ int r;
+ int op_result= 0;
+ int rc= 0; /* OK */
+
+ if ( slapi_op_abandoned(pb) )
+ {
+ return rc;
+ }
+
+ slapi_pblock_get( pb, SLAPI_ADD_EXISTING_UNIQUEID_ENTRY, &existing_uniqueid_entry );
+ if (existing_uniqueid_entry!=NULL)
+ {
+ /*
+ * An entry with this uniqueid already exists.
+ * - It could be a replay of the same Add, or
+ * - It could be a UUID generation collision, or
+ */
+ op_result = LDAP_SUCCESS;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Ignore this Operation */
+ PROFILE_POINT; /* Add Conflict; UniqueID Exists; Ignore */
+ goto bailout;
+ }
+
+ get_repl_session_id (pb, sessionid, &opcsn);
+ slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &addentry );
+ slapi_pblock_get( pb, SLAPI_ADD_EXISTING_DN_ENTRY, &existing_dn_entry );
+ if (existing_dn_entry==NULL) /* The target DN does not exist */
+ {
+ /* Check for parent entry... this could be an orphan. */
+ Slapi_Entry *parententry;
+ slapi_pblock_get( pb, SLAPI_ADD_PARENT_ENTRY, &parententry );
+ rc = urp_add_resolve_parententry (pb, sessionid, addentry, parententry, opcsn);
+ PROFILE_POINT; /* Add Entry */
+ goto bailout;
+ }
+
+ /*
+ * Naming conflict: an entry with the target DN already exists.
+ * Compare the DistinguishedNameCSN of the existing entry
+ * and the OperationCSN. The smaller CSN wins. The loser changes
+ * its RDN to uniqueid+baserdn, and adds operational attribute
+ * ATTR_NSDS5_REPLCONFLIC.
+ */
+ basedn = slapi_entry_get_ndn (addentry);
+ adduniqueid = slapi_entry_get_uniqueid (addentry);
+ r = csn_compare (entry_get_dncsn(existing_dn_entry), opcsn);
+ if (r<0)
+ {
+ /* Entry to be added is a loser */
+ char *newdn= get_dn_plus_uniqueid (sessionid, basedn, adduniqueid);
+ if(newdn==NULL)
+ {
+ op_result= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Abort this Operation */
+ PROFILE_POINT; /* Add Conflict; Entry Exists; Unique ID already in RDN - Abort this update. */
+ }
+ else
+ {
+ /* Add the nsds5ReplConflict attribute in the mods */
+ Slapi_Attr *attr = NULL;
+ Slapi_Value **vals = NULL;
+ Slapi_RDN *rdn;
+ char buf[BUFSIZ];
+
+ sprintf(buf, "%s %s", REASON_ANNOTATE_DN, basedn);
+ if (slapi_entry_attr_find (addentry, ATTR_NSDS5_REPLCONFLICT, &attr) == 0)
+ {
+ /* ATTR_NSDS5_REPLCONFLICT exists */
+ slapi_log_error (SLAPI_LOG_FATAL, sessionid, "New entry has nsds5ReplConflict already\n");
+ vals = attr_get_present_values (attr); /* this returns a pointer to the contents */
+ }
+ if ( vals == NULL || *vals == NULL )
+ {
+ /* Add new attribute */
+ slapi_entry_add_string (addentry, ATTR_NSDS5_REPLCONFLICT, buf);
+ }
+ else
+ {
+ /*
+ * Replace old attribute. We don't worry about the index
+ * change here since the entry is yet to be added.
+ */
+ slapi_value_set_string (*vals, buf);
+ }
+ slapi_entry_set_dn (addentry,slapi_ch_strdup(newdn));
+ set_pblock_dn(pb,SLAPI_ADD_TARGET,newdn); /* consumes newdn */
+
+ rdn = slapi_rdn_new_sdn ( slapi_entry_get_sdn_const(addentry) );
+ slapi_log_error (slapi_log_urp, sessionid,
+ "Naming conflict ADD. Add %s instead\n", slapi_rdn_get_rdn(rdn) );
+ slapi_rdn_free(&rdn);
+
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
+ PROFILE_POINT; /* Add Conflict; Entry Exists; Rename Operation Entry */
+ }
+ }
+ else if(r>0)
+ {
+ /* Existing entry is a loser */
+ if (!urp_annotate_dn(sessionid, existing_dn_entry, opcsn, "ADD"))
+ {
+ op_result= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Ignore this Operation */
+ }
+ else
+ {
+ /* The backend add code should now search for the existing entry again. */
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY);
+ }
+ PROFILE_POINT; /* Add Conflict; Entry Exists; Rename Existing Entry */
+ }
+ else /* r==0 */
+ {
+ /* The CSN of the Operation and the Entry DN are the same.
+ * This could only happen if:
+ * a) There are two replicas with the same ReplicaID.
+ * b) We've seen the Operation before.
+ * Let's go with (b) and ignore the little bastard.
+ */
+ op_result= LDAP_SUCCESS;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Ignore this Operation */
+ PROFILE_POINT; /* Add Conflict; Entry Exists; Same CSN */
+ }
+
+bailout:
+ return rc;
+}
+
+/*
+ * Return 0 for OK, -1 for Error, >0 for action code
+ * Action Code Bit 0: Fetch existing entry.
+ * Action Code Bit 1: Fetch parent entry.
+ */
+int
+urp_modrdn_operation( Slapi_PBlock *pb )
+{
+ slapi_operation_parameters *op_params = NULL;
+ Slapi_Entry *parent_entry;
+ Slapi_Entry *new_parent_entry;
+ Slapi_DN *newsuperior = NULL;
+ char *newsuperiordn;
+ Slapi_DN *parentdn = NULL;
+ Slapi_Entry *target_entry;
+ Slapi_Entry *existing_entry;
+ const CSN *target_entry_dncsn;
+ CSN *opcsn= NULL;
+ char *op_uniqueid = NULL;
+ const char *existing_uniqueid = NULL;
+ const char *target_dn;
+ const char *existing_dn;
+ char *newrdn;
+ char sessionid[REPL_SESSION_ID_SIZE];
+ int r;
+ int op_result= 0;
+ int rc= 0; /* OK */
+ int del_old_replconflict_attr = 0;
+
+ if ( slapi_op_abandoned(pb) )
+ {
+ return rc;
+ }
+
+ slapi_pblock_get (pb, SLAPI_MODRDN_TARGET_ENTRY, &target_entry);
+ if(target_entry==NULL)
+ {
+ /* An entry can't be found for the Unique Identifier */
+ op_result= LDAP_NO_SUCH_OBJECT;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* No entry to modrdn */
+ PROFILE_POINT; /* ModRDN Conflict; Entry does not Exist; Discard ModRDN */
+ goto bailout;
+ }
+
+ get_repl_session_id (pb, sessionid, &opcsn);
+ target_entry_dncsn = entry_get_dncsn (target_entry);
+ if ( csn_compare (target_entry_dncsn, opcsn) >= 0 )
+ {
+ /*
+ * The Operation CSN is not newer than the DN CSN.
+ * Either we're beaten by another ModRDN or we've applied the op.
+ */
+ op_result= LDAP_SUCCESS;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Ignore the modrdn */
+ PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; OPCSN is not newer. */
+ goto bailout;
+ }
+
+ /* The DN CSN is older than the Operation CSN. Apply the operation */
+ target_dn = slapi_entry_get_dn_const ( target_entry);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &newrdn);
+ slapi_pblock_get(pb, SLAPI_TARGET_UNIQUEID, &op_uniqueid);
+ slapi_pblock_get(pb, SLAPI_MODRDN_PARENT_ENTRY, &parent_entry);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWPARENT_ENTRY, &new_parent_entry);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperiordn);
+
+ if ( is_tombstone_entry (target_entry) )
+ {
+ /*
+ * It is a non-trivial task to rename a tombstone.
+ * This op has been ignored so far by
+ * setting SLAPI_RESULT_CODE to LDAP_NO_SUCH_OBJECT
+ * and rc to -1.
+ */
+
+ /* Turn the tombstone to glue before rename it */
+ /*
+ op_result = tombstone_to_glue (pb, sessionid, target_entry,
+ slapi_entry_get_sdn (target_entry), "renameTombstone", opcsn);
+ */
+ op_result = LDAP_NO_SUCH_OBJECT;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ if (op_result == 0)
+ {
+ /*
+ * Remember to turn this entry back to tombstone in post op.
+ * We'll just borrow an obsolete pblock type here.
+ */
+ slapi_pblock_set (pb, SLAPI_URP_TOMBSTONE_UNIQUEID, strdup(op_uniqueid));
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_TARGET_ENTRY);
+ rc = 0;
+ }
+ else
+ {
+ rc = -1;
+ }
+ PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; OPCSN is not newer. */
+ goto bailout;
+ }
+
+ slapi_pblock_get(pb, SLAPI_MODRDN_EXISTING_ENTRY, &existing_entry);
+ if(existing_entry!=NULL)
+ {
+ /*
+ * An entry with the target DN already exists.
+ * The smaller dncsn wins. The loser changes its RDN to
+ * uniqueid+baserdn, and adds operational attribute
+ * ATTR_NSDS5_REPLCONFLIC
+ */
+
+ existing_uniqueid = slapi_entry_get_uniqueid (existing_entry);
+ existing_dn = slapi_entry_get_dn_const ( existing_entry);
+
+ /*
+ * Dismiss the operation if the existing entry is the same as the target one.
+ */
+ if (strcmp(op_uniqueid, existing_uniqueid) == 0) {
+ op_result= LDAP_SUCCESS;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc = -1; /* Ignore the op */
+ PROFILE_POINT; /* ModRDN Replay */
+ goto bailout;
+ }
+
+ r= csn_compare ( entry_get_dncsn (existing_entry), opcsn);
+ if (r == 0)
+ {
+ /*
+ * The CSN of the Operation and the Entry DN are the same
+ * but the uniqueids are not.
+ * There might be two replicas with the same ReplicaID.
+ */
+ slapi_log_error(SLAPI_LOG_FATAL, sessionid,
+ "Duplicated CSN for different uniqueids [%s][%s]",
+ existing_uniqueid, op_uniqueid);
+ op_result= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Abort */
+ PROFILE_POINT; /* ModRDN Conflict; Duplicated CSN for Different Entries */
+ goto bailout;
+ }
+
+ if(r<0)
+ {
+ /* The target entry is a loser */
+
+ char *newrdn_with_uniqueid;
+ newrdn_with_uniqueid= get_rdn_plus_uniqueid (sessionid, newrdn, op_uniqueid);
+ if(newrdn_with_uniqueid==NULL)
+ {
+ op_result= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Ignore this Operation */
+ PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists;
+ Unique ID already in RDN - Change to Lost and Found entry */
+ goto bailout;
+ }
+ mod_namingconflict_attr (op_uniqueid, target_dn, existing_dn, opcsn);
+ set_pblock_dn (pb, SLAPI_MODRDN_NEWRDN, newrdn_with_uniqueid);
+ slapi_log_error(slapi_log_urp, sessionid,
+ "Naming conflict MODRDN. Rename target entry to %s\n",
+ newrdn_with_uniqueid );
+
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
+ PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; Rename Operation Entry */
+ goto bailout;
+ }
+
+ if ( r>0 )
+ {
+ /* The existing entry is a loser */
+
+ int resolve = urp_annotate_dn (sessionid, existing_entry, opcsn, "MODRDN");
+ if(!resolve)
+ {
+ op_result= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Abort this Operation */
+ goto bailout;
+ }
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_NEWPARENT_ENTRY);
+ if (LDAP_NO_SUCH_OBJECT == resolve) {
+ /* This means that existing_dn_entry did not really exist!!!
+ * This indicates that a get_copy_of_entry -> dn2entry returned
+ * an entry (existing_dn_entry) that was already removed from the ldbm.
+ * This is bad, because it indicates a dn cache or DB corruption.
+ * However, as far as the conflict is concerned, this error is harmless:
+ * if the existing_dn_entry did not exist in the first place, there was no
+ * conflict!! Return 0 for success to break the ldbm_back_modrdn loop
+ * and get out of this inexistent conflict resolution ASAP.
+ */
+ rc = 0;
+ }
+ /* Set flag to remove possible old naming conflict */
+ del_old_replconflict_attr = 1;
+ PROFILE_POINT; /* ModRDN Conflict; Entry with Target DN Exists; Rename Entry with Target DN */
+ goto bailout;
+ }
+ }
+ else
+ {
+ /*
+ * No entry with the target DN exists.
+ */
+
+ /* Set flag to remove possible old naming conflict */
+ del_old_replconflict_attr = 1;
+
+ if(new_parent_entry!=NULL)
+ {
+ /* The new superior entry exists */
+ rc= 0; /* OK, Apply the ModRDN */
+ PROFILE_POINT; /* ModRDN Conflict; OK */
+ goto bailout;
+ }
+
+ /* The new superior entry doesn't exist */
+
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperiordn);
+ if(newsuperiordn == NULL)
+ {
+ /* (new_parent_entry==NULL && newsuperiordn==NULL)
+ * This is ok - SLAPI_MODRDN_NEWPARENT_ENTRY will
+ * only be set if SLAPI_MODRDN_NEWSUPERIOR was
+ * suplied by the client. If it wasn't, we're just
+ * changing the RDN of the entry. In that case,
+ * if the entry exists, its parent won't change
+ * when it's renamed, and therefore we can assume
+ * its parent exists.
+ */
+ rc=0;
+ PROFILE_POINT; /* ModRDN OK */
+ goto bailout;
+ }
+
+ newsuperior= slapi_sdn_new_dn_byval(newsuperiordn);
+
+ if((0 == slapi_sdn_compare (slapi_entry_get_sdn(parent_entry), newsuperior)) ||
+ is_suffix_dn (pb, newsuperior, &parentdn) )
+ {
+ /*
+ * The new superior is the same as the current one, or
+ * this entry is a suffix whose parent can be absent.
+ */
+ rc= 0; /* OK, Move the entry */
+ PROFILE_POINT; /* ModRDN Conflict; Absent Target Parent; Create Suffix Entry */
+ goto bailout;
+ }
+
+ /*
+ * This entry is not a suffix entry, so the parent entry should exist.
+ * (This shouldn't happen in a ds5 server)
+ */
+ slapi_pblock_get ( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
+ op_result = create_glue_entry (pb, sessionid, newsuperior,
+ op_params->p.p_modrdn.modrdn_newsuperior_address.uniqueid, opcsn);
+ if (LDAP_SUCCESS != op_result)
+ {
+ /*
+ * FATAL ERROR
+ * We should probably just abort the rename
+ * this will cause replication divergence requiring
+ * admin intercession
+ */
+ slapi_log_error( SLAPI_LOG_FATAL, sessionid,
+ "Parent %s couldn't be found, nor recreated as a glue entry\n", newsuperiordn );
+ op_result= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc = -1;
+ PROFILE_POINT;
+ goto bailout;
+ }
+
+ /* The backend add code should now search for the parent again. */
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_NEWPARENT_ENTRY);
+ PROFILE_POINT; /* ModRDN Conflict; Absent Target Parent - Change to Lost and Found entry */
+ goto bailout;
+ }
+
+bailout:
+ if ( del_old_replconflict_attr && rc == 0 )
+ {
+ del_replconflict_attr (target_entry, opcsn, 0);
+ }
+ if ( parentdn )
+ slapi_sdn_free(&parentdn);
+ if ( newsuperior )
+ slapi_sdn_free(&newsuperior);
+ return rc;
+}
+
+/*
+ * Return 0 for OK, -1 for Error
+ */
+int
+urp_delete_operation( Slapi_PBlock *pb )
+{
+ Slapi_Entry *deleteentry;
+ CSN *opcsn= NULL;
+ char sessionid[REPL_SESSION_ID_SIZE];
+ int op_result= 0;
+ int rc= 0; /* OK */
+
+ if ( slapi_op_abandoned(pb) )
+ {
+ return rc;
+ }
+
+ slapi_pblock_get(pb, SLAPI_DELETE_EXISTING_ENTRY, &deleteentry);
+
+ if(deleteentry==NULL) /* uniqueid can't be found */
+ {
+ op_result= LDAP_NO_SUCH_OBJECT;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc= -1; /* Don't apply the Delete */
+ PROFILE_POINT; /* Delete Operation; Entry not exist. */
+ }
+ else if(is_tombstone_entry(deleteentry))
+ {
+ /* The entry is already a Tombstone, ignore this delete. */
+ op_result= LDAP_SUCCESS;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc = -1; /* Don't apply the Delete */
+ PROFILE_POINT; /* Delete Operation; Already a Tombstone. */
+ }
+ else /* The entry to be deleted exists and is not a tombstone */
+ {
+ get_repl_session_id (pb, sessionid, &opcsn);
+
+ /* Check if the entry has children. */
+ if(!slapi_entry_has_children(deleteentry))
+ {
+ /* Remove possible conflict attributes */
+ del_replconflict_attr (deleteentry, opcsn, 0);
+ rc= 0; /* OK, to delete the entry */
+ PROFILE_POINT; /* Delete Operation; OK. */
+ }
+ else
+ {
+ /* Turn this entry into a glue_absent_parent entry */
+ entry_to_glue(sessionid, deleteentry, REASON_RESURRECT_ENTRY, opcsn);
+
+ /* Turn the Delete into a No-Op */
+ op_result= LDAP_SUCCESS;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &op_result);
+ rc = -1; /* Don't apply the Delete */
+ PROFILE_POINT; /* Delete Operation; Entry has children. */
+ }
+ }
+ return rc;
+}
+
+int urp_post_modrdn_operation (Slapi_PBlock *pb)
+{
+ CSN *opcsn;
+ char sessionid[REPL_SESSION_ID_SIZE];
+ char *tombstone_uniqueid;
+ Slapi_Entry *postentry;
+ Slapi_Operation *op;
+
+ /*
+ * Do not abandon the post op - the processed CSN needs to be
+ * committed to keep the consistency between the changelog
+ * and the backend DB.
+ * if ( slapi_op_abandoned(pb) ) return 0;
+ */
+
+ slapi_pblock_get (pb, SLAPI_URP_TOMBSTONE_UNIQUEID, &tombstone_uniqueid );
+ if (tombstone_uniqueid == NULL)
+ {
+ /*
+ * The entry is not resurrected from tombstone. Hence
+ * we need to check if any naming conflict with its
+ * old dn can be resolved.
+ */
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op);
+ if (!operation_is_flag_set(op, OP_FLAG_REPL_FIXUP))
+ {
+ get_repl_session_id (pb, sessionid, &opcsn);
+ urp_naming_conflict_removal (pb, sessionid, opcsn, "MODRDN");
+ }
+ }
+ else
+ {
+ /*
+ * The entry was a resurrected tombstone.
+ * This could happen when we applied a rename
+ * to a tombstone to avoid server divergence. Now
+ * it's time to put the entry back to tombstone.
+ */
+ slapi_pblock_get ( pb, SLAPI_ENTRY_POST_OP, &postentry );
+ if (postentry && strcmp(tombstone_uniqueid, slapi_entry_get_uniqueid(postentry)) == 0)
+ {
+ entry_to_tombstone (pb, postentry);
+ }
+ slapi_ch_free ((void**)&tombstone_uniqueid);
+ slapi_pblock_set (pb, SLAPI_URP_TOMBSTONE_UNIQUEID, NULL);
+ }
+
+ return 0;
+}
+
+/*
+ * Conflict removal
+ */
+int
+urp_post_delete_operation( Slapi_PBlock *pb )
+{
+ Slapi_Operation *op;
+ Slapi_Entry *entry;
+ CSN *opcsn;
+ char sessionid[REPL_SESSION_ID_SIZE];
+ int op_result;
+
+ /*
+ * Do not abandon the post op - the processed CSN needs to be
+ * committed to keep the consistency between the changelog
+ * and the backend DB
+ * if ( slapi_op_abandoned(pb) ) return 0;
+ */
+
+ get_repl_session_id (pb, sessionid, &opcsn);
+
+ /*
+ * Conflict removal from the parent entry:
+ * If the parent is glue and has no more children,
+ * turn the parent to tombstone
+ */
+ slapi_pblock_get ( pb, SLAPI_DELETE_GLUE_PARENT_ENTRY, &entry );
+ if ( entry != NULL )
+ {
+ op_result = entry_to_tombstone ( pb, entry );
+ if ( op_result == LDAP_SUCCESS )
+ {
+ slapi_log_error ( slapi_log_urp, sessionid,
+ "Tombstoned glue entry %s since it has no more children\n",
+ slapi_entry_get_dn_const (entry) );
+ }
+ }
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op);
+ if (!operation_is_flag_set(op, OP_FLAG_REPL_FIXUP))
+ {
+ /*
+ * Conflict removal from the peers of the old dn
+ */
+ urp_naming_conflict_removal (pb, sessionid, opcsn, "DEL");
+ }
+
+ return 0;
+}
+
+int
+urp_fixup_add_entry (Slapi_Entry *e, const char *target_uniqueid, const char *parentuniqueid, CSN *opcsn, int opflags)
+{
+ Slapi_PBlock *newpb;
+ Slapi_Operation *op;
+ int op_result;
+
+ newpb = slapi_pblock_new ();
+
+ /*
+ * Mark this operation as replicated, so that the front end
+ * doesn't add extra attributes.
+ */
+ slapi_add_entry_internal_set_pb (
+ newpb,
+ e,
+ NULL, /*Controls*/
+ repl_get_plugin_identity ( PLUGIN_MULTIMASTER_REPLICATION ),
+ OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | opflags);
+ if (target_uniqueid)
+ {
+ slapi_pblock_set( newpb, SLAPI_TARGET_UNIQUEID, (void*)target_uniqueid);
+ }
+ if (parentuniqueid)
+ {
+ struct slapi_operation_parameters *op_params;
+ slapi_pblock_get( newpb, SLAPI_OPERATION_PARAMETERS, &op_params );
+ op_params->p.p_add.parentuniqueid = (char*)parentuniqueid; /* Consumes parentuniqueid */
+ }
+ slapi_pblock_get ( newpb, SLAPI_OPERATION, &op );
+ operation_set_csn ( op, opcsn );
+
+ slapi_add_internal_pb ( newpb );
+ slapi_pblock_get ( newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result );
+ slapi_pblock_destroy ( newpb );
+
+ return op_result;
+}
+
+int
+urp_fixup_rename_entry (Slapi_Entry *entry, const char *newrdn, int opflags)
+{
+ Slapi_PBlock *newpb;
+ Slapi_Operation *op;
+ CSN *opcsn;
+ int op_result;
+
+ newpb = slapi_pblock_new();
+
+ /*
+ * Must mark this operation as replicated,
+ * so that the frontend doesn't add extra attributes.
+ */
+ slapi_rename_internal_set_pb (
+ newpb,
+ slapi_entry_get_dn_const (entry),
+ newrdn, /*NewRDN*/
+ NULL, /*NewSuperior*/
+ 0, /* !Delete Old RDNS */
+ NULL, /*Controls*/
+ slapi_entry_get_uniqueid (entry), /*uniqueid*/
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+ OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | opflags);
+
+ /* set operation csn to the entry's dncsn */
+ opcsn = (CSN *)entry_get_dncsn (entry);
+ slapi_pblock_get (newpb, SLAPI_OPERATION, &op);
+ operation_set_csn (op, opcsn);
+
+ slapi_modrdn_internal_pb(newpb);
+ slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
+
+ slapi_pblock_destroy(newpb);
+ return op_result;
+}
+
+int
+urp_fixup_delete_entry (const char *uniqueid, const char *dn, CSN *opcsn, int opflags)
+{
+ Slapi_PBlock *newpb;
+ Slapi_Operation *op;
+ int op_result;
+
+ newpb = slapi_pblock_new ();
+
+ /*
+ * Mark this operation as replicated, so that the front end
+ * doesn't add extra attributes.
+ */
+ slapi_delete_internal_set_pb (
+ newpb,
+ dn,
+ NULL, /*Controls*/
+ uniqueid, /*uniqueid*/
+ repl_get_plugin_identity ( PLUGIN_MULTIMASTER_REPLICATION ),
+ OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | opflags );
+ slapi_pblock_get ( newpb, SLAPI_OPERATION, &op );
+ operation_set_csn ( op, opcsn );
+
+ slapi_delete_internal_pb ( newpb );
+ slapi_pblock_get ( newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result );
+ slapi_pblock_destroy ( newpb );
+
+ return op_result;
+}
+
+int
+urp_fixup_modify_entry (const char *uniqueid, const char *dn, CSN *opcsn, Slapi_Mods *smods, int opflags)
+{
+ Slapi_PBlock *newpb;
+ Slapi_Operation *op;
+ int op_result;
+
+ newpb = slapi_pblock_new();
+
+ slapi_modify_internal_set_pb (
+ newpb,
+ dn,
+ slapi_mods_get_ldapmods_byref (smods),
+ NULL, /* Controls */
+ uniqueid,
+ repl_get_plugin_identity (PLUGIN_MULTIMASTER_REPLICATION),
+ OP_FLAG_REPLICATED | OP_FLAG_REPL_FIXUP | opflags);
+
+ /* set operation csn */
+ slapi_pblock_get (newpb, SLAPI_OPERATION, &op);
+ operation_set_csn (op, opcsn);
+
+ /* do modify */
+ slapi_modify_internal_pb (newpb);
+ slapi_pblock_get (newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
+ slapi_pblock_destroy(newpb);
+
+ return op_result;
+}
+
+static int
+urp_add_resolve_parententry (Slapi_PBlock *pb, char *sessionid, Slapi_Entry *entry, Slapi_Entry *parententry, CSN *opcsn)
+{
+ Slapi_DN *parentdn = NULL;
+ Slapi_RDN *add_rdn = NULL;
+ char *newdn = NULL;
+ int ldap_rc;
+ int rc = 0;
+
+ if( is_suffix_entry (pb, entry, &parentdn) )
+ {
+ /* It's OK for the suffix entry's parent to be absent */
+ rc= 0;
+ PROFILE_POINT; /* Add Conflict; Suffix Entry */
+ goto bailout;
+ }
+
+ /* The entry is not a suffix. */
+ if(parententry==NULL) /* The parent entry was not found. */
+ {
+ /* Create a glue entry to stand in for the absent parent */
+ slapi_operation_parameters *op_params;
+ slapi_pblock_get( pb, SLAPI_OPERATION_PARAMETERS, &op_params );
+ ldap_rc = create_glue_entry (pb, sessionid, parentdn, op_params->p.p_add.parentuniqueid, opcsn);
+ if ( LDAP_SUCCESS == ldap_rc )
+ {
+ /* The backend code should now search for the parent again. */
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY);
+ PROFILE_POINT; /* Add Conflict; Orphaned Entry; Glue Parent */
+ }
+ else
+ {
+ /*
+ * Error. The parent can't be created as a glue entry.
+ * This will cause replication divergence and will
+ * require admin intercession
+ */
+ ldap_rc= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_rc);
+ rc= -1; /* Abort this Operation */
+ PROFILE_POINT; /* Add Conflict; Orphaned Entry; Impossible to create parent; Refuse Change. */
+ }
+ goto bailout;
+ }
+
+ if(is_tombstone_entry(parententry)) /* The parent is a tombstone */
+ {
+ /* The parent entry must be resurected from the dead. */
+ ldap_rc = tombstone_to_glue (pb, sessionid, parententry, parentdn, REASON_RESURRECT_ENTRY, opcsn);
+ if ( ldap_rc != LDAP_SUCCESS )
+ {
+ ldap_rc= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_rc);
+ rc = -1; /* Abort the operation */
+ }
+ else
+ {
+ /* The backend add code should now search for the parent again. */
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY);
+ }
+ PROFILE_POINT; /* Add Conflict; Orphaned Entry; Parent Was Tombstone */
+ goto bailout;
+ }
+
+ /* The parent is healthy */
+ /* Now we need to check that the parent has the correct DN */
+ if (slapi_sdn_isparent(slapi_entry_get_sdn(parententry), slapi_entry_get_sdn(entry)))
+ {
+ rc= 0; /* OK, Add the entry */
+ PROFILE_POINT; /* Add Conflict; Parent Exists */
+ goto bailout;
+ }
+
+ /*
+ * Parent entry doesn't have a DN parent to the entry.
+ * This can happen if parententry was renamed due to
+ * conflict and the child entry was created before
+ * replication occured. See defect 530942.
+ * We need to rename the entry to be child of its parent.
+ */
+ add_rdn = slapi_rdn_new_dn(slapi_entry_get_dn_const (entry));
+ newdn = slapi_dn_plus_rdn(slapi_entry_get_dn_const (parententry), slapi_rdn_get_rdn(add_rdn));
+ slapi_entry_set_dn ( entry,slapi_ch_strdup(newdn));
+ set_pblock_dn (pb,SLAPI_ADD_TARGET,newdn); /* consumes newdn */
+ slapi_log_error ( slapi_log_urp, sessionid,
+ "Parent was renamed. Renamed the child to %s\n", newdn );
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
+ PROFILE_POINT; /* Add Conflict; Parent Renamed; Rename Operation Entry */
+
+bailout:
+ if (parentdn)
+ slapi_sdn_free(&parentdn);
+ return rc;
+}
+
+/*
+ * urp_annotate_dn:
+ * Returns 0 on failure
+ * Returns > 0 on success (1 on general conflict resolution success, LDAP_NO_SUCH_OBJECT on no-conflict success)
+ *
+ * Use this function to annotate an existing entry only. To annotate
+ * a new entry (the operation entry) see urp_add_operation.
+ */
+static int
+urp_annotate_dn (char *sessionid, Slapi_Entry *entry, CSN *opcsn, const char *optype)
+{
+ int rc = 0; /* Fail */
+ int op_result;
+ char *newrdn;
+ const char *uniqueid;
+ const char *basedn;
+ char ebuf[BUFSIZ];
+
+ uniqueid = slapi_entry_get_uniqueid (entry);
+ basedn = slapi_entry_get_ndn (entry);
+ newrdn = get_rdn_plus_uniqueid ( sessionid, basedn, uniqueid );
+ if(newrdn!=NULL)
+ {
+ mod_namingconflict_attr (uniqueid, basedn, basedn, opcsn);
+ op_result = urp_fixup_rename_entry ( entry, newrdn, 0 );
+ switch(op_result)
+ {
+ case LDAP_SUCCESS:
+ slapi_log_error(slapi_log_urp, sessionid,
+ "Naming conflict %s. Renamed existing entry to %s\n",
+ optype, escape_string (newrdn, ebuf));
+ rc = 1;
+ break;
+ case LDAP_NO_SUCH_OBJECT:
+ /* This means that entry did not really exist!!!
+ * This is clearly indicating that there is a
+ * get_copy_of_entry -> dn2entry returned
+ * an entry (entry) that was already removed
+ * from the ldbm database...
+ * This is bad, because it clearly indicates
+ * some kind of db or cache corruption. We need to print
+ * this fact clearly in the errors log to try
+ * to solve this corruption one day.
+ * However, as far as the conflict is concerned,
+ * this error is completely harmless:
+ * if thew entry did not exist in the first place,
+ * there was never a room
+ * for a conflict!! After fix for 558293, this
+ * state can't be reproduced anymore (5-Oct-01)
+ */
+ slapi_log_error( SLAPI_LOG_FATAL, sessionid,
+ "Entry %s exists in cache but not in DB\n",
+ escape_string (basedn, ebuf) );
+ rc = LDAP_NO_SUCH_OBJECT;
+ break;
+ default:
+ slapi_log_error( slapi_log_urp, sessionid,
+ "Failed to annotate %s, err=%d\n", newrdn, op_result);
+ }
+ slapi_ch_free ( (void**)&newrdn );
+ }
+ return rc;
+}
+
+/*
+ * An URP Naming Collision helper function. Retreives a list of entries
+ * that have the given dn excluding the unique id of the entry. Any
+ * entries returned will be entries that have been added with the same
+ * dn, but caused a naming conflict when replicated. The URP to fix
+ * this constraint violation is to append the unique id of the entry
+ * to its RDN.
+ */
+static Slapi_Entry *
+urp_get_min_naming_conflict_entry ( Slapi_PBlock *pb, char *sessionid, CSN *opcsn )
+{
+ Slapi_PBlock *newpb = NULL;
+ LDAPControl **server_ctrls = NULL;
+ Slapi_Entry **entries = NULL;
+ Slapi_Entry *min_naming_conflict_entry = NULL;
+ const CSN *min_csn = NULL;
+ char *filter = NULL;
+ char *parent_dn = NULL;
+ char *basedn;
+ int i = 0;
+ int min_i = -1;
+ int op_result = LDAP_SUCCESS;
+
+ slapi_pblock_get (pb, SLAPI_URP_NAMING_COLLISION_DN, &basedn);
+ if (NULL == basedn || strncmp (basedn, SLAPI_ATTR_UNIQUEID, strlen(SLAPI_ATTR_UNIQUEID)) == 0)
+ return NULL;
+
+ slapi_log_error ( SLAPI_LOG_REPL, sessionid,
+ "Enter urp_get_min_naming_conflict_entry for %s\n", basedn);
+
+ filter = slapi_ch_malloc(50 + strlen(basedn));
+ sprintf(filter, "(%s=%s %s)", ATTR_NSDS5_REPLCONFLICT, REASON_ANNOTATE_DN, basedn);
+
+ /* server_ctrls will be freed when newpb is destroyed */
+ server_ctrls = (LDAPControl **)slapi_ch_calloc (2, sizeof (LDAPControl *));
+ server_ctrls[0] = create_managedsait_control();
+ server_ctrls[1] = NULL;
+
+ newpb = slapi_pblock_new();
+ parent_dn = slapi_dn_parent (basedn);
+ slapi_search_internal_set_pb(newpb,
+ parent_dn, /* Base DN */
+ LDAP_SCOPE_ONELEVEL,
+ filter,
+ NULL, /* Attrs */
+ 0, /* AttrOnly */
+ server_ctrls, /* Controls */
+ NULL, /* UniqueID */
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+ 0);
+ slapi_search_internal_pb(newpb);
+ slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
+ slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if ( (op_result != LDAP_SUCCESS) || (entries == NULL) )
+ {
+ /* Log a message */
+ goto done;
+ }
+ /* For all entries, get the one with the smallest dn csn */
+ for (i = 0; NULL != entries[i]; i++)
+ {
+ const CSN *dncsn;
+ dncsn = entry_get_dncsn(entries[i]);
+ if ((dncsn != opcsn) &&
+ ((min_csn == NULL) || (csn_compare(dncsn, min_csn) < 0)) &&
+ !is_tombstone_entry (entries[i]))
+ {
+ min_csn = dncsn;
+ min_i = i;
+ }
+ /*
+ * If there are too many conflicts, the current urp code has no
+ * guarantee for all servers to converge anyway, because the
+ * urp and the backend can't be done in one transaction due
+ * to either performance or the deadlock problem.
+ * Don't sacrifice the performance too much for impossible.
+ */
+ if (min_csn && i > 5)
+ {
+ break;
+ }
+ }
+
+ if (min_csn != NULL) {
+ /* Found one entry */
+ min_naming_conflict_entry = slapi_entry_dup(entries[min_i]);
+ }
+
+done:
+ slapi_ch_free((void **)&parent_dn);
+ slapi_ch_free((void **)&filter);
+ slapi_free_search_results_internal(newpb);
+ slapi_pblock_destroy(newpb);
+ newpb = NULL;
+
+ slapi_log_error ( SLAPI_LOG_REPL, sessionid,
+ "Leave urp_get_min_naming_conflict_entry (found %d entries)\n", i);
+
+ return min_naming_conflict_entry;
+}
+
+/*
+ * If an entry is deleted or renamed, a new winner may be
+ * chosen from its naming competitors.
+ * The entry with the smallest dncsn restores its original DN.
+ */
+static int
+urp_naming_conflict_removal ( Slapi_PBlock *pb, char *sessionid, CSN *opcsn, const char *optype )
+{
+ Slapi_Entry *min_naming_conflict_entry;
+ Slapi_RDN *oldrdn, *newrdn;
+ const char *oldrdnstr, *newrdnstr;
+ int op_result;
+
+ /*
+ * Backend op has set SLAPI_URP_NAMING_COLLISION_DN to the basedn.
+ */
+ min_naming_conflict_entry = urp_get_min_naming_conflict_entry (pb, sessionid, opcsn);
+ if (min_naming_conflict_entry == NULL)
+ {
+ return 0;
+ }
+
+ /* Step 1: Restore the entry's original DN */
+
+ oldrdn = slapi_rdn_new_sdn ( slapi_entry_get_sdn (min_naming_conflict_entry) );
+ oldrdnstr = slapi_rdn_get_rdn ( oldrdn );
+
+ /* newrdnstr is the old rdn of the entry minus the nsuniqueid part */
+ newrdn = slapi_rdn_new_rdn ( oldrdn );
+ slapi_rdn_remove_attr (newrdn, SLAPI_ATTR_UNIQUEID );
+ newrdnstr = slapi_rdn_get_rdn ( newrdn );
+
+ /*
+ * Set OP_FLAG_ACTION_INVOKE_FOR_REPLOP since this operation
+ * is done after DB lock was released. The backend modrdn
+ * will acquire the DB lock if it sees this flag.
+ */
+ op_result = urp_fixup_rename_entry (min_naming_conflict_entry, newrdnstr, OP_FLAG_ACTION_INVOKE_FOR_REPLOP);
+ if ( op_result != LDAP_SUCCESS )
+ {
+ slapi_log_error (slapi_log_urp, sessionid,
+ "Failed to restore RDN of %s, err=%d\n", oldrdnstr, op_result);
+ goto bailout;
+ }
+ slapi_log_error (slapi_log_urp, sessionid,
+ "Naming conflict removed by %s. RDN of %s was restored\n", optype, oldrdnstr);
+
+ /* Step2: Remove ATTR_NSDS5_REPLCONFLICT from the winning entry */
+ /*
+ * A fixup op will not invoke urp_modrdn_operation(). Even it does,
+ * urp_modrdn_operation() will do nothing because of the same CSN.
+ */
+ op_result = del_replconflict_attr (min_naming_conflict_entry, opcsn, OP_FLAG_ACTION_INVOKE_FOR_REPLOP);
+ if (op_result != LDAP_SUCCESS) {
+ slapi_log_error(SLAPI_LOG_REPL, sessionid,
+ "Failed to remove nsds5ReplConflict for %s, err=%d\n",
+ newrdnstr, op_result);
+ }
+
+bailout:
+ slapi_entry_free (min_naming_conflict_entry);
+ slapi_rdn_free(&oldrdn);
+ slapi_rdn_free(&newrdn);
+ return op_result;
+}
+
+/* The returned value is either null or "uniqueid=<uniqueid>+<basedn>" */
+static char *
+get_dn_plus_uniqueid(char *sessionid, const char *olddn, const char *uniqueid)
+{
+ Slapi_DN *sdn= slapi_sdn_new_dn_byval(olddn);
+ Slapi_RDN *rdn= slapi_rdn_new();
+ char *newdn;
+
+ PR_ASSERT(uniqueid!=NULL);
+
+ /* Check if the RDN already contains the Unique ID */
+ slapi_sdn_get_rdn(sdn,rdn);
+ if(slapi_rdn_contains(rdn,SLAPI_ATTR_UNIQUEID,uniqueid,strlen(uniqueid)))
+ {
+ /* The Unique ID is already in the RDN.
+ * This is a highly improbable collision.
+ * It suggests that a duplicate UUID was generated.
+ * This will cause replication divergence and will
+ * require admin intercession
+ */
+ slapi_log_error(SLAPI_LOG_FATAL, sessionid,
+ "Annotated DN %s has naming conflict\n", olddn );
+ newdn= NULL;
+ }
+ else
+ {
+ slapi_rdn_add(rdn,SLAPI_ATTR_UNIQUEID,uniqueid);
+ slapi_sdn_set_rdn(sdn, rdn);
+ newdn= slapi_ch_strdup(slapi_sdn_get_dn(sdn));
+ }
+ slapi_sdn_free(&sdn);
+ slapi_rdn_free(&rdn);
+ return newdn;
+}
+
+static char *
+get_rdn_plus_uniqueid(char *sessionid, const char *olddn, const char *uniqueid)
+{
+ char *newrdn;
+ /* Check if the RDN already contains the Unique ID */
+ Slapi_DN *sdn= slapi_sdn_new_dn_byval(olddn);
+ Slapi_RDN *rdn= slapi_rdn_new();
+ slapi_sdn_get_rdn(sdn,rdn);
+ PR_ASSERT(uniqueid!=NULL);
+ if(slapi_rdn_contains(rdn,SLAPI_ATTR_UNIQUEID,uniqueid,strlen(uniqueid)))
+ {
+ /* The Unique ID is already in the RDN.
+ * This is a highly improbable collision.
+ * It suggests that a duplicate UUID was generated.
+ * This will cause replication divergence and will
+ * require admin intercession
+ */
+ slapi_log_error(SLAPI_LOG_FATAL, sessionid,
+ "Annotated DN %s has naming conflict\n", olddn );
+ newrdn= NULL;
+ }
+ else
+ {
+ slapi_rdn_add(rdn,SLAPI_ATTR_UNIQUEID,uniqueid);
+ newrdn= slapi_ch_strdup(slapi_rdn_get_rdn(rdn));
+ }
+ slapi_sdn_free(&sdn);
+ slapi_rdn_free(&rdn);
+ return newrdn;
+}
+
+static void
+set_pblock_dn (Slapi_PBlock* pb,int pblock_parameter,char *newdn)
+{
+ char *olddn;
+ slapi_pblock_get( pb, pblock_parameter, &olddn );
+ slapi_ch_free((void**)&olddn);
+ slapi_pblock_set( pb, pblock_parameter, newdn );
+}
+
+static int
+is_suffix_entry ( Slapi_PBlock *pb, Slapi_Entry *entry, Slapi_DN **parentdn )
+{
+ return is_suffix_dn ( pb, slapi_entry_get_sdn(entry), parentdn );
+}
+
+int
+is_suffix_dn ( Slapi_PBlock *pb, const Slapi_DN *dn, Slapi_DN **parentdn )
+{
+ Slapi_Backend *backend;
+ int rc;
+
+ *parentdn = slapi_sdn_new();
+ slapi_pblock_get( pb, SLAPI_BACKEND, &backend );
+ slapi_sdn_get_backend_parent (dn, *parentdn, backend);
+
+ /* A suffix entry doesn't have parent dn */
+ rc = slapi_sdn_isempty (*parentdn) ? 1 : 0;
+
+ return rc;
+}
+
+static int
+mod_namingconflict_attr (const char *uniqueid, const char *entrydn, const char *conflictdn, CSN *opcsn)
+{
+ Slapi_Mods smods;
+ char buf[BUFSIZ];
+ int op_result;
+
+ sprintf (buf, "%s %s", REASON_ANNOTATE_DN, conflictdn);
+ slapi_mods_init (&smods, 2);
+ if ( strncmp (entrydn, SLAPI_ATTR_UNIQUEID, strlen(SLAPI_ATTR_UNIQUEID)) != 0 )
+ {
+ slapi_mods_add (&smods, LDAP_MOD_ADD, ATTR_NSDS5_REPLCONFLICT, strlen(buf), buf);
+ }
+ else
+ {
+ /*
+ * If the existing entry is already a naming conflict loser,
+ * the following replace operation should result in the
+ * replace of the ATTR_NSDS5_REPLCONFLICT index as well.
+ */
+ slapi_mods_add (&smods, LDAP_MOD_REPLACE, ATTR_NSDS5_REPLCONFLICT, strlen(buf), buf);
+ }
+ op_result = urp_fixup_modify_entry (uniqueid, entrydn, opcsn, &smods, 0);
+ slapi_mods_done (&smods);
+ return op_result;
+}
+
+static int
+del_replconflict_attr (Slapi_Entry *entry, CSN *opcsn, int opflags)
+{
+ Slapi_Attr *attr;
+ int op_result = 0;
+
+ if (slapi_entry_attr_find (entry, ATTR_NSDS5_REPLCONFLICT, &attr) == 0)
+ {
+ Slapi_Mods smods;
+ const char *uniqueid;
+ const char *entrydn;
+
+ uniqueid = slapi_entry_get_uniqueid (entry);
+ entrydn = slapi_entry_get_dn_const (entry);
+ slapi_mods_init (&smods, 2);
+ slapi_mods_add (&smods, LDAP_MOD_DELETE, ATTR_NSDS5_REPLCONFLICT, 0, NULL);
+ op_result = urp_fixup_modify_entry (uniqueid, entrydn, opcsn, &smods, opflags);
+ slapi_mods_done (&smods);
+ }
+ return op_result;
+}
diff --git a/ldap/servers/plugins/replication/urp.h b/ldap/servers/plugins/replication/urp.h
new file mode 100644
index 00000000..9db477bd
--- /dev/null
+++ b/ldap/servers/plugins/replication/urp.h
@@ -0,0 +1,45 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ */
+
+#define REASON_ANNOTATE_DN "namingConflict"
+#define REASON_RESURRECT_ENTRY "deletedEntryHasChildren"
+
+/*
+ * urp.c
+ */
+int urp_modify_operation( Slapi_PBlock *pb );
+int urp_add_operation( Slapi_PBlock *pb );
+int urp_delete_operation( Slapi_PBlock *pb );
+int urp_post_delete_operation( Slapi_PBlock *pb );
+int urp_modrdn_operation( Slapi_PBlock *pb );
+int urp_post_modrdn_operation( Slapi_PBlock *pb );
+
+/* urp internal ops */
+int urp_fixup_add_entry (Slapi_Entry *e, const char *target_uniqueid, const char *parentuniqueid, CSN *opcsn, int opflags);
+int urp_fixup_delete_entry (const char *uniqueid, const char *dn, CSN *opcsn, int opflags);
+int urp_fixup_rename_entry (Slapi_Entry *entry, const char *newrdn, int opflags);
+int urp_fixup_modify_entry (const char *uniqueid, const char *dn, CSN *opcsn, Slapi_Mods *smods, int opflags);
+
+int is_suffix_dn (Slapi_PBlock *pb, const Slapi_DN *dn, Slapi_DN **parenddn);
+
+/*
+ * urp_glue.c
+ */
+int is_glue_entry(const Slapi_Entry* entry);
+int create_glue_entry ( Slapi_PBlock *pb, char *sessionid, Slapi_DN *dn, const char *uniqueid, CSN *opcsn );
+int entry_to_glue(char *sessionid, const Slapi_Entry* entry, const char *reason, CSN *opcsn);
+int glue_to_entry (Slapi_PBlock *pb, Slapi_Entry *entry );
+PRBool get_glue_csn(const Slapi_Entry *entry, const CSN **gluecsn);
+
+/*
+ * urp_tombstone.c
+ */
+int is_tombstone_entry(const Slapi_Entry* entry);
+int tombstone_to_glue(Slapi_PBlock *pb, const char *sessionid, Slapi_Entry *entry, const Slapi_DN *parentdn, const char *reason, CSN *opcsn);
+int entry_to_tombstone ( Slapi_PBlock *pb, Slapi_Entry *entry );
+PRBool get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn);
diff --git a/ldap/servers/plugins/replication/urp_glue.c b/ldap/servers/plugins/replication/urp_glue.c
new file mode 100644
index 00000000..dcb2f72d
--- /dev/null
+++ b/ldap/servers/plugins/replication/urp_glue.c
@@ -0,0 +1,235 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * urp_glue.c - Update Resolution Procedures - Glue
+ */
+
+#include "slapi-plugin.h"
+#include "repl5.h"
+#include "urp.h"
+
+
+#define RDNBUFSIZE 2048
+extern int slapi_log_urp;
+
+/*
+ * Check if the entry is glue.
+ */
+int
+is_glue_entry(const Slapi_Entry* entry)
+{
+ /* JCMREPL - Is there a more efficient way to do this? */
+ return slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "glue");
+}
+
+/* returns PR_TRUE if the entry is a glue entry, PR_FALSE otherwise
+ sets the gluecsn if it is a glue entry - gluecsn may (but should not) be NULL */
+PRBool
+get_glue_csn(const Slapi_Entry *entry, const CSN **gluecsn)
+{
+ PRBool isglue = PR_FALSE;
+ Slapi_Attr *oc_attr = NULL;
+
+ /* cast away const - entry */
+ if (entry_attr_find_wsi((Slapi_Entry*)entry, SLAPI_ATTR_OBJECTCLASS, &oc_attr) == ATTRIBUTE_PRESENT)
+ {
+ Slapi_Value *glue_value = NULL;
+ struct berval v;
+ v.bv_val = "glue";
+ v.bv_len = strlen(v.bv_val);
+ if (attr_value_find_wsi(oc_attr, &v, &glue_value) == VALUE_PRESENT)
+ {
+ isglue = PR_TRUE;
+ *gluecsn = value_get_csn(glue_value, CSN_TYPE_VALUE_UPDATED);
+ }
+ }
+
+ return isglue;
+}
+
+/*
+ * Submit a Modify operation to turn the Entry into Glue.
+ */
+int
+entry_to_glue(char *sessionid, const Slapi_Entry* entry, const char *reason, CSN *opcsn)
+{
+ int op_result = 0;
+ const char *dn;
+ char ebuf[BUFSIZ];
+ slapi_mods smods;
+ Slapi_Attr *attr;
+
+ dn = slapi_entry_get_dn_const (entry);
+ slapi_mods_init(&smods, 4);
+ /*
+ richm: sometimes the entry is already a glue entry (how did that happen?)
+ OR
+ the entry is already objectclass extensibleObject or already has the
+ conflict attribute and/or value
+ */
+ if (!slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "glue"))
+ {
+ slapi_mods_add_string( &smods, LDAP_MOD_ADD, SLAPI_ATTR_OBJECTCLASS, "glue" );
+
+ if (!slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, "extensibleobject"))
+ slapi_mods_add_string( &smods, LDAP_MOD_ADD, SLAPI_ATTR_OBJECTCLASS, "extensibleobject" );
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: Target entry %s is already a glue entry reason %s\n",
+ sessionid, escape_string(dn, ebuf), reason);
+ }
+
+ if (slapi_entry_attr_find (entry, ATTR_NSDS5_REPLCONFLICT, &attr) == 0)
+ {
+ slapi_mods_add_string( &smods, LDAP_MOD_REPLACE, ATTR_NSDS5_REPLCONFLICT, reason);
+ }
+ else
+ {
+ slapi_mods_add_string( &smods, LDAP_MOD_ADD, ATTR_NSDS5_REPLCONFLICT, reason);
+ }
+
+ if (slapi_mods_get_num_mods(&smods) > 0)
+ {
+ op_result = urp_fixup_modify_entry (NULL, dn, opcsn, &smods, 0);
+ if (op_result == LDAP_SUCCESS)
+ {
+ slapi_log_error (slapi_log_urp, repl_plugin_name,
+ "%s: Turned the entry %s to glue, reason %s\n",
+ sessionid, escape_string(dn, ebuf), reason);
+ }
+ }
+
+ slapi_mods_done(&smods);
+ return op_result;
+}
+
+static const char *glue_entry =
+ "dn: %s\n"
+ "%s"
+ "objectclass: top\n"
+ "objectclass: extensibleObject\n" /* JCMREPL - To avoid schema checking. */
+ "objectclass: glue\n"
+ "nsuniqueid: %s\n"
+ "%s: %s\n"; /* Add why it's been created */
+
+static int
+do_create_glue_entry(const Slapi_RDN *rdn, const Slapi_DN *superiordn, const char *uniqueid, const char *reason, CSN *opcsn)
+{
+ int op_result= LDAP_OPERATIONS_ERROR;
+ int rdnval_index = 0;
+ int rdntype_len, rdnval_len, rdnpair_len, rdnstr_len, alloc_len;
+ Slapi_Entry *e;
+ Slapi_DN *sdn = NULL;
+ Slapi_RDN *newrdn = slapi_rdn_new_rdn(rdn);
+ char *estr, *rdnstr, *rdntype, *rdnval, *rdnpair;
+ sdn = slapi_sdn_new_dn_byval(slapi_sdn_get_ndn(superiordn));
+ slapi_sdn_add_rdn(sdn,rdn);
+
+
+ /* must take care of multi-valued rdn: split rdn into different lines introducing
+ * '\n' between each type/value pair.
+ */
+ alloc_len = RDNBUFSIZE;
+ rdnstr = slapi_ch_malloc(alloc_len);
+ rdnpair = rdnstr;
+ *rdnpair = '\0'; /* so that strlen(rdnstr) may return 0 the first time it's called */
+ while ((rdnval_index = slapi_rdn_get_next(newrdn, rdnval_index, &rdntype, &rdnval)) != -1) {
+ rdntype_len = strlen(rdntype);
+ rdnval_len = strlen(rdnval);
+ rdnpair_len = LDIF_SIZE_NEEDED(rdntype_len, rdnval_len);
+ rdnstr_len = strlen(rdnstr);
+ if ((rdnstr_len + rdnpair_len + 1) > alloc_len) {
+ alloc_len += (rdnpair_len + 1);
+ rdnstr = slapi_ch_realloc(rdnstr, alloc_len);
+ rdnpair = &rdnstr[rdnstr_len];
+ }
+ ldif_put_type_and_value_with_options(&rdnpair, rdntype,
+ rdnval, rdnval_len, LDIF_OPT_NOWRAP);
+ *rdnpair = '\0';
+ }
+ estr= slapi_ch_malloc(strlen(glue_entry) + slapi_sdn_get_ndn_len(sdn) +
+ strlen(rdnstr) + strlen(uniqueid) +
+ strlen(ATTR_NSDS5_REPLCONFLICT) + strlen(reason) + 1);
+ sprintf(estr, glue_entry, slapi_sdn_get_ndn(sdn), rdnstr, uniqueid,
+ ATTR_NSDS5_REPLCONFLICT, reason);
+ slapi_ch_free((void**)&rdnstr);
+ slapi_rdn_done(newrdn);
+ slapi_ch_free((void**)&newrdn);
+ e = slapi_str2entry( estr, 0 );
+ PR_ASSERT(e!=NULL);
+ if ( e!=NULL )
+ {
+ slapi_entry_set_uniqueid (e, slapi_ch_strdup(uniqueid));
+ op_result = urp_fixup_add_entry (e, NULL, NULL, opcsn, 0);
+ slapi_ch_free ( (void **) &estr ); /* XXXggood - this leaks if e == NULL */
+ }
+ slapi_sdn_free(&sdn);
+ return op_result;
+}
+
+int
+create_glue_entry ( Slapi_PBlock *pb, char *sessionid, Slapi_DN *dn, const char *uniqueid, CSN *opcsn )
+{
+ int op_result;
+ const char *dnstr;
+
+ if ( slapi_sdn_get_dn (dn) )
+ dnstr = slapi_sdn_get_dn (dn);
+ else
+ dnstr = "";
+
+ if ( NULL == uniqueid )
+ {
+ op_result = LDAP_OPERATIONS_ERROR;
+ slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Can't create glue %s, uniqueid=NULL\n", sessionid, dnstr);
+ }
+ else
+ {
+ Slapi_Backend *backend;
+ Slapi_DN *superiordn = slapi_sdn_new();
+ Slapi_RDN *rdn= slapi_rdn_new();
+ int done= 0;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &backend );
+ slapi_sdn_get_backend_parent ( dn, superiordn, backend );
+ slapi_sdn_get_rdn ( dn, rdn );
+
+ while(!done)
+ {
+ op_result= do_create_glue_entry(rdn, superiordn, uniqueid, "missingEntry", opcsn);
+ switch(op_result)
+ {
+ case LDAP_SUCCESS:
+ slapi_log_error ( SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Created glue entry %s uniqueid=%s reason missingEntry\n",
+ sessionid, dnstr, uniqueid);
+ done= 1;
+ break;
+ case LDAP_NO_SUCH_OBJECT:
+ /* The parent is missing */
+ {
+ /* JCMREPL - Create the parent ... recursion?... but what's the uniqueid? */
+ PR_ASSERT(0); /* JCMREPL */
+ }
+ default:
+ slapi_log_error ( SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Can't created glue entry %s uniqueid=%s, error %d\n",
+ sessionid, dnstr, uniqueid, op_result);
+ break;
+ }
+ /* JCMREPL - Could get trapped in this loop forever! */
+ }
+
+ slapi_rdn_free ( &rdn );
+ slapi_sdn_free ( &superiordn );
+ }
+
+ return op_result;
+}
diff --git a/ldap/servers/plugins/replication/urp_tombstone.c b/ldap/servers/plugins/replication/urp_tombstone.c
new file mode 100644
index 00000000..3b24b928
--- /dev/null
+++ b/ldap/servers/plugins/replication/urp_tombstone.c
@@ -0,0 +1,210 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * urp_tombstone.c - Update Resolution Procedures - Tombstones
+ */
+
+#include "slapi-plugin.h"
+#include "repl5.h"
+#include "urp.h"
+
+extern int slapi_log_urp;
+
+/*
+ * Check if the entry is a tombstone.
+ */
+int
+is_tombstone_entry(const Slapi_Entry* entry)
+{
+ int flag;
+
+ /* LP: This doesn't work very well with entries that we tombstone ourself */
+ flag = slapi_entry_flag_is_set (entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
+ if (flag == 0)
+ {
+ /* This is slow */
+ flag = slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE);
+ }
+ return flag;
+}
+
+PRBool
+get_tombstone_csn(const Slapi_Entry *entry, const CSN **delcsn)
+{
+ PRBool ists = PR_FALSE;
+ if (is_tombstone_entry(entry)) {
+ ists = PR_TRUE;
+ *delcsn = _get_deletion_csn((Slapi_Entry *)entry); /* cast away const */
+ }
+
+ return ists;
+}
+
+static int
+tombstone_to_glue_resolve_parent (
+ Slapi_PBlock *pb,
+ const char *sessionid,
+ const Slapi_DN *parentdn,
+ const char *parentuniqueid,
+ CSN *opcsn)
+{
+ /* Let's have a look at the parent of this entry... */
+ if(!slapi_sdn_isempty(parentdn) && parentuniqueid!=NULL)
+ {
+ int op_result;
+ Slapi_PBlock *newpb= slapi_pblock_new();
+ slapi_search_internal_set_pb(
+ newpb,
+ slapi_sdn_get_dn(parentdn), /* JCM - This DN just identifies the backend to be searched. */
+ LDAP_SCOPE_BASE,
+ "objectclass=*",
+ NULL, /*attrs*/
+ 0, /*attrsonly*/
+ NULL, /*Controls*/
+ parentuniqueid, /*uniqueid*/
+ repl_get_plugin_identity(PLUGIN_MULTIMASTER_REPLICATION),
+ 0);
+ slapi_search_internal_pb(newpb);
+ slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_RESULT, &op_result);
+ switch(op_result)
+ {
+ case LDAP_SUCCESS:
+ {
+ Slapi_Entry **entries= NULL;
+ /* OK, the tombstone entry parent exists. Is it also a tombstone? */
+ slapi_pblock_get(newpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if(entries!=NULL && entries[0]!=NULL)
+ {
+ if(is_tombstone_entry(entries[0]))
+ {
+ tombstone_to_glue (pb, sessionid, entries[0], parentdn, REASON_RESURRECT_ENTRY, opcsn);
+ }
+ }
+ else
+ {
+ /* JCM - Couldn't find the entry! */
+ }
+ }
+ break;
+ default:
+ /* So, the tombstone entry had a parent... but it's gone. */
+ /* That's probably a bad thing. */
+ break;
+ }
+ slapi_free_search_results_internal (newpb);
+ slapi_pblock_destroy(newpb);
+ }
+ return 0;
+}
+
+/*
+ * Convert a tombstone into a glue entry.
+ */
+int
+tombstone_to_glue (
+ Slapi_PBlock *pb,
+ const char *sessionid,
+ Slapi_Entry *tombstoneentry,
+ const Slapi_DN *tombstonedn,
+ const char *reason,
+ CSN *opcsn)
+{
+ Slapi_DN *parentdn;
+ char *parentuniqueid;
+ const char *tombstoneuniqueid;
+ Slapi_Entry *addingentry;
+ const char *addingdn;
+ int op_result;
+
+ /* JCMREPL
+ * Nothing logged to the 5.0 Change Log
+ * Add is logged to the 4.0 Change Log - Core server Add code
+ * must attach the entry to the Operation
+ */
+
+
+ /* Resurrect the parent entry first */
+
+ /* JCM - This DN calculation is odd. It could resolve to NULL
+ * which won't help us identify the correct backend to search.
+ */
+ is_suffix_dn (pb, tombstonedn, &parentdn);
+ parentuniqueid= slapi_entry_attr_get_charptr (tombstoneentry,
+ SLAPI_ATTR_VALUE_PARENT_UNIQUEID); /* Allocated */
+ tombstone_to_glue_resolve_parent (pb, sessionid, parentdn, parentuniqueid, opcsn);
+ slapi_sdn_free(&parentdn);
+
+ /* Submit an Add operation to turn the tombstone entry into glue. */
+ /*
+ * The tombstone is stored with an invalid DN, we must fix this.
+ */
+ addingentry = slapi_entry_dup(tombstoneentry);
+ addingdn = slapi_sdn_get_dn(tombstonedn);
+ slapi_entry_set_dn(addingentry,slapi_ch_strdup(addingdn)); /* consumes DN */
+
+ if (!slapi_entry_attr_hasvalue(addingentry, ATTR_NSDS5_REPLCONFLICT, reason))
+ {
+ /* Add the reason of turning it to glue - The backend code will use it*/
+ slapi_entry_add_string(addingentry, ATTR_NSDS5_REPLCONFLICT, reason);
+ }
+ tombstoneuniqueid= slapi_entry_get_uniqueid(tombstoneentry);
+ op_result = urp_fixup_add_entry (addingentry, tombstoneuniqueid, parentuniqueid, opcsn, OP_FLAG_RESURECT_ENTRY);
+ if (op_result == LDAP_SUCCESS)
+ {
+ slapi_log_error (slapi_log_urp, repl_plugin_name,
+ "%s: Resurrected tombstone %s to glue reason '%s'\n", sessionid, addingdn, reason);
+ }
+ else
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, repl_plugin_name,
+ "%s: Can't resurrect tombstone %s to glue reason '%s', error=%d\n",
+ sessionid, addingdn, reason, op_result);
+ }
+ slapi_entry_free (addingentry);
+ return op_result;
+}
+
+int
+entry_to_tombstone ( Slapi_PBlock *pb, Slapi_Entry *entry )
+{
+ Slapi_Operation *op;
+ Slapi_Mods smods;
+ CSN *opcsn;
+ const char *uniqueid;
+ int op_result = LDAP_SUCCESS;
+
+ slapi_pblock_get ( pb, SLAPI_OPERATION, &op );
+ opcsn = operation_get_csn ( op );
+ uniqueid = slapi_entry_get_uniqueid ( entry );
+
+
+ slapi_mods_init ( &smods, 2 );
+ /* Remove objectclass=glue */
+ slapi_mods_add ( &smods, LDAP_MOD_DELETE, SLAPI_ATTR_OBJECTCLASS, strlen("glue"), "glue");
+ /* Remove any URP conflict since a tombstone shouldn't
+ * be retrieved later for conflict removal.
+ */
+ slapi_mods_add ( &smods, LDAP_MOD_DELETE, ATTR_NSDS5_REPLCONFLICT, 0, NULL );
+
+ op_result = urp_fixup_modify_entry (uniqueid, slapi_entry_get_dn_const (entry), opcsn, &smods, 0);
+ slapi_mods_done ( &smods );
+
+ /*
+ * Delete the entry.
+ */
+ if ( op_result == LDAP_SUCCESS )
+ {
+ /*
+ * Using internal delete operation since it would go
+ * through the urp operations and trigger the recursive
+ * fixup if applicable.
+ */
+ op_result = urp_fixup_delete_entry (uniqueid, slapi_entry_get_dn_const (entry), opcsn, 0);
+ }
+
+ return op_result;
+}
diff --git a/ldap/servers/plugins/retrocl/Makefile b/ldap/servers/plugins/retrocl/Makefile
new file mode 100644
index 00000000..c81f0dfe
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/Makefile
@@ -0,0 +1,135 @@
+#
+# 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 "Retrocl" plugin
+
+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 = $(OBJDIR)/lib/retrocl-plugin
+BINDIR = $(LDAP_SERVER_RELDIR)
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+INCLUDES+=-I$(DB_INCLUDE)
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./retrocl.def
+endif
+
+CFLAGS += $(SLCFLAGS) -DSLAPD_LOGGING
+
+ifeq ($(ARCH), WINNT)
+CFLAGS += /WX
+endif
+
+ifdef TEST_CL5
+CFLAGS += -DTEST_CL5
+endif
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd -I$(DB_INCLUDE)
+
+ifeq ($(ARCH), WINNT)
+SUBSYSTEM=console
+endif
+
+LOCAL_OBJS= \
+ retrocl.o \
+ retrocl_po.o \
+ retrocl_rootdse.o \
+ retrocl_cn.o \
+ retrocl_trim.o \
+ retrocl_create.o \
+
+
+
+LIBRETROCL_OBJS = $(addprefix $(OBJDEST)/, $(LOCAL_OBJS))
+
+ifeq ($(ARCH), WINNT)
+RETROCL_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+LIBRETROCL= $(addprefix $(LIBDIR)/, $(RETROCL_DLL).$(DLL_SUFFIX))
+
+LT_OBJS = $(addprefix $(OBJDEST)/, linktest.o)
+
+#EXTRA_LIBS_DEP = $(LDAPSDK_DEP) \
+# $(LDAP_LIBLDIF_DEP) \
+# $(LDAP_SLIBLCACHE_DEP) $(DB_LIB_DEP) $(LIBSLAPD_DEP) \
+# $(LDAP_COMMON_LIBS_DEP)
+
+#EXTRA_LIBS = $(LIBACCESS) $(LDAP_SDK_LIBSSLDAP_LIB) $(ADMINUTIL_LINK) \
+# $(LDAP_SDK_LIBLDAP_DLL) $(LDAP_SLIBLCACHE) $(DB_LIB) \
+# $(PLATFORM_SPECIFIC_EXTRA_LIBRARY) $(LIBSLAPD) $(LDAP_LIBLITEKEY) \
+# $(NLSLINK) $(ALIBS) \
+# $(LDAP_SDK_LIBSSLDAP_LIB) $(LDAP_SDK_LIBLDAP_DLL) \
+# $(LIBSECURITYLINK) $(NSPRLINK) $(DBMLINK) \
+# $(THREADSLIB) $(LDAP_COMMON_LIBS) $(NSPRLINK) $(SVRCORELINK)
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(DB_LIB_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL) $(DB_LIB)
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP) $(DB_LIB_DEP) $(NSPR_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL) $(DB_LIB)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./retrocl.def"
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS += $(DLL_EXTRA_LIBS)
+LD=ld
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBRETROCL)
+
+linktest: $(LIBRETROCL) $(LT_OBJS)
+ $(LINK_EXE_NOLIBSOBJS) -o linktest $(LT_OBJS) $(LIBRETROCL) -Rlib -Rlib/../bin/slapd/lib -Llib -Llib/../bin/slapd/lib -lslapd $(EXTRA_LIBS) $(NSPRLINK)
+
+
+$(LIBRETROCL): $(LIBRETROCL_OBJS) $(RETROCL_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBRETROCL_OBJS) $(RETROCL_DLL_OBJ) $(PLATFORMLIBS) $(EXTRA_LIBS) $(LDAP_LIBLDIF) $(NSPRLINK)
+
+tests: $(TEST_PROGS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(LIBRETROCL_OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(RETROCL_DLL_OBJ)
+endif
+ $(RM) $(LIBRETROCL)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+#
+# header file dependencies (incomplete)
+#
+$(LIBRETROCL_OBJS):
diff --git a/ldap/servers/plugins/retrocl/dllmain.c b/ldap/servers/plugins/retrocl/dllmain.c
new file mode 100644
index 00000000..276b1fa9
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/dllmain.c
@@ -0,0 +1,90 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+ /*
+ * Microsoft Windows specifics for LIBRETROCL DLL
+ */
+#include "ldap.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; /* successful DLL_PROCESS_ATTACH */
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/retrocl/linktest.c b/ldap/servers/plugins/retrocl/linktest.c
new file mode 100644
index 00000000..22812c57
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/linktest.c
@@ -0,0 +1,16 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* This is a test program. Not linked into the shared library */
+
+#include "retrocl.h"
+
+int main(int a,char **b)
+{
+ int r;
+
+ r = retrocl_plugin_init(NULL);
+}
diff --git a/ldap/servers/plugins/retrocl/retrocl.c b/ldap/servers/plugins/retrocl/retrocl.c
new file mode 100644
index 00000000..e0d3e325
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl.c
@@ -0,0 +1,341 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Requires that create_instance.c have added a plugin entry similar to:
+
+dn: cn=Retrocl Plugin,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: RetroCL Plugin
+nsslapd-pluginpath: /export2/servers/Hydra-supplier/lib/retrocl-plugin.so
+nsslapd-plugininitfunc: retrocl_plugin_init
+nsslapd-plugintype: object
+nsslapd-pluginenabled: on
+nsslapd-plugin-depends-on-type: database
+nsslapd-pluginid: retrocl
+nsslapd-pluginversion: 5.0b2
+nsslapd-pluginvendor: Sun Microsystems, Inc.
+nsslapd-plugindescription: Retrocl Plugin
+
+ *
+ */
+
+#include "retrocl.h"
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+void* g_plg_identity [PLUGIN_MAX];
+
+Slapi_Backend *retrocl_be_changelog = NULL;
+
+/* ----------------------------- Retrocl Plugin */
+
+static Slapi_PluginDesc retrocldesc = {"retrocl", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Retrocl Plugin"};
+static Slapi_PluginDesc retroclpostopdesc = {"retrocl-postop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "retrocl post-operation plugin"};
+static Slapi_PluginDesc retroclinternalpostopdesc = {"retrocl-internalpostop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "retrocl internal post-operation plugin"};
+static Slapi_PluginDesc retroclbepostopdesc = {"retrocl-bepostop", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "Retrocl bepost-operation plugin"};
+
+
+/*
+ * Function: retrocl_*
+ *
+ * Returns: LDAP_
+ *
+ * Arguments: Pb of operation
+ *
+ * Description: wrappers around retrocl_postob registered as callback
+ *
+ */
+
+int retrocl_postop_add (Slapi_PBlock *pb) { return retrocl_postob(pb,OP_ADD);}
+int retrocl_postop_delete (Slapi_PBlock *pb) { return retrocl_postob(pb,OP_DELETE);}
+int retrocl_postop_modify (Slapi_PBlock *pb) { return retrocl_postob(pb,OP_MODIFY);}
+int retrocl_postop_modrdn (Slapi_PBlock *pb) { return retrocl_postob(pb,OP_MODRDN);}
+
+/*
+ * Function: retrocl_postop_init
+ *
+ * Returns: 0/-1
+ *
+ * Arguments: Pb
+ *
+ * Description: callback function
+ *
+ */
+
+int
+retrocl_postop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&retroclpostopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_ADD_FN, (void *) retrocl_postop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_DELETE_FN, (void *) retrocl_postop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODIFY_FN, (void *) retrocl_postop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODRDN_FN, (void *) retrocl_postop_modrdn ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "retrocl_postop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+/*
+ * Function: retrocl_internalpostop_init
+ *
+ * Returns: 0/-1
+ *
+ * Arguments: Pb
+ *
+ * Description: callback function
+ *
+ */
+
+int
+retrocl_internalpostop_init( Slapi_PBlock *pb )
+{
+ int rc= 0; /* OK */
+
+ if( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&retroclinternalpostopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_ADD_FN, (void *) retrocl_postop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN, (void *) retrocl_postop_delete ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN, (void *) retrocl_postop_modify ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN, (void *) retrocl_postop_modrdn ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME, "retrocl_internalpostop_init failed\n" );
+ rc= -1;
+ }
+
+ return rc;
+}
+
+/*
+ * Function: retrocl_rootdse_init
+ *
+ * Returns: LDAP_SUCCESS
+ *
+ * Arguments: none
+ *
+ * Description: The FE DSE *must* be initialised before we get here.
+ *
+ */
+static int retrocl_rootdse_init(void)
+{
+
+ int return_value= LDAP_SUCCESS;
+
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,"",
+ LDAP_SCOPE_BASE,"(objectclass=*)",
+ retrocl_rootdse_search,NULL);
+ return return_value;
+}
+
+/*
+ * Function: retrocl_select_backend
+ *
+ * Returns: LDAP_
+ *
+ * Arguments: none
+ *
+ * Description: simulates an add of the changelog to see if it exists. If not,
+ * creates it. Then reads the changenumbers. This function should be called
+ * exactly once at startup.
+ *
+ */
+
+static int retrocl_select_backend(void)
+{
+ int err;
+ Slapi_PBlock *pb;
+ Slapi_Backend *be = NULL;
+ Slapi_Entry *referral = NULL;
+ Slapi_Operation *op = NULL;
+ char errbuf[1024];
+
+ pb = slapi_pblock_new();
+
+ slapi_pblock_set (pb, SLAPI_PLUGIN_IDENTITY, g_plg_identity[PLUGIN_RETROCL]);
+
+ /* This is a simulated operation; no actual add is performed */
+ op = operation_new(OP_FLAG_INTERNAL);
+ operation_set_type(op,SLAPI_OPERATION_ADD); /* Ensure be not readonly */
+
+ operation_set_target_spec_str(op,RETROCL_CHANGELOG_DN);
+
+ slapi_pblock_set(pb,SLAPI_OPERATION, op);
+
+ err = slapi_mapping_tree_select(pb,&be,&referral,errbuf);
+ slapi_entry_free(referral);
+
+ operation_free(&op,NULL);
+
+ if (err != LDAP_SUCCESS || be == NULL || be == defbackend_get_backend()) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"Mapping tree select failed (%d) %s.\n",
+ err,errbuf,0);
+
+ /* could not find the backend for cn=changelog, either because
+ * it doesn't exist
+ * mapping tree not registered.
+ */
+ err = retrocl_create_config();
+
+ if (err != LDAP_SUCCESS) return err;
+ } else {
+ retrocl_be_changelog = be;
+ }
+
+ retrocl_create_cle();
+
+ return retrocl_get_changenumbers();
+}
+
+/*
+ * Function: retrocl_get_config_str
+ *
+ * Returns: malloc'ed string which must be freed.
+ *
+ * Arguments: attribute type name
+ *
+ * Description: reads a single-valued string attr from the plugins' own DSE.
+ * This is called twice: to obtain the trim max age during startup, and to
+ * obtain the change log directory. No callback is registered; you cannot
+ * change the trim max age without restarting the server.
+ *
+ */
+
+char *retrocl_get_config_str(const char *attrt)
+{
+ Slapi_Entry **entries;
+ Slapi_PBlock *pb = NULL;
+ char *ma;
+ int rc = 0;
+ char *dn;
+
+ dn = RETROCL_PLUGIN_DN;
+
+ pb = slapi_pblock_new();
+
+ slapi_search_internal_set_pb (pb, dn, LDAP_SCOPE_BASE, "objectclass=*", NULL, 0, NULL,
+ NULL, g_plg_identity[PLUGIN_RETROCL] , 0);
+ slapi_search_internal_pb (pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != 0) {
+ slapi_pblock_destroy(pb);
+ return NULL;
+ }
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+
+ ma = slapi_entry_attr_get_charptr(entries[0],attrt);
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+
+ return ma;
+}
+
+/*
+ * Function: retrocl_start
+ *
+ * Returns: 0 on success
+ *
+ * Arguments: Pb
+ *
+ * Description:
+ *
+ */
+
+static int retrocl_start (Slapi_PBlock *pb)
+{
+ static int retrocl_started = 0;
+ int rc = 0;
+
+ if (!retrocl_started) {
+ retrocl_rootdse_init();
+
+ rc = retrocl_select_backend();
+
+ if (rc == 0) {
+ retrocl_init_trimming();
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE,"Couldnt find backend, not trimming retro changelog (%d).\n",rc,0,0);
+ }
+ }
+
+ retrocl_started = 1;
+ return rc;
+}
+
+/*
+ * Function: retrocl_stop
+ *
+ * Returns: 0
+ *
+ * Arguments: Pb
+ *
+ * Description: called when the server is shutting down
+ *
+ */
+
+static int retrocl_stop (Slapi_PBlock *pb)
+{
+ int rc = 0;
+
+ retrocl_stop_trimming();
+ retrocl_be_changelog = NULL;
+ retrocl_forget_changenumbers();
+
+ return rc;
+}
+
+/*
+ * Function: retrocl_plugin_init
+ *
+ * Returns: 0 on successs
+ *
+ * Arguments: Pb
+ *
+ * Description: main entry point for retrocl
+ *
+ */
+
+int
+retrocl_plugin_init(Slapi_PBlock *pb)
+{
+ static int legacy_initialised= 0;
+ int rc = 0;
+ void *identity = NULL;
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &identity);
+ PR_ASSERT (identity);
+ g_plg_identity[PLUGIN_RETROCL] = identity;
+
+ if (!legacy_initialised) {
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&retrocldesc );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN, (void *) retrocl_start );
+ rc= slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN, (void *) retrocl_stop );
+
+ rc= slapi_register_plugin("postoperation", 1 /* Enabled */, "retrocl_postop_init", retrocl_postop_init, "Retrocl postoperation plugin", NULL, identity);
+ rc= slapi_register_plugin("internalpostoperation", 1 /* Enabled */, "retrocl_internalpostop_init", retrocl_internalpostop_init, "Retrocl internal postoperation plugin", NULL, identity);
+ }
+
+ legacy_initialised = 1;
+ return rc;
+}
+
+
+
diff --git a/ldap/servers/plugins/retrocl/retrocl.def b/ldap/servers/plugins/retrocl/retrocl.def
new file mode 100644
index 00000000..ce730c44
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl.def
@@ -0,0 +1,15 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+;
+
+DESCRIPTION 'Netscape Directory Server 7.0 Retro-Changelog Plugin'
+;CODE SHARED READ EXECUTE
+;DATA SHARED READ WRITE
+EXPORTS
+ plugin_init_debug_level @1
+ retrocl_plugin_init @2
+
diff --git a/ldap/servers/plugins/retrocl/retrocl.h b/ldap/servers/plugins/retrocl/retrocl.h
new file mode 100644
index 00000000..f96af64c
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl.h
@@ -0,0 +1,123 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _H_RETROCL
+#define _H_RETROCL 1
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "slapi-private.h"
+#include "slapi-plugin.h"
+/* #include "portable.h" */
+#include "dirver.h"
+#include "ldaplog.h"
+#include "ldif.h"
+#include "slap.h"
+#include <dirlite_strings.h>
+
+/* max len of a long (2^64), represented as a string, including null byte */
+#define CNUMSTR_LEN 21
+typedef unsigned long changeNumber;
+
+typedef struct _cnum_result_t {
+ int crt_nentries; /* number of entries returned from search */
+ int crt_err; /* err returned from backend */
+ Slapi_Entry *crt_entry; /* The entry returned from the backend */
+} cnum_result_t;
+
+typedef struct _cnumRet {
+ changeNumber cr_cnum;
+ char *cr_time;
+ int cr_lderr;
+} cnumRet;
+
+/* Operation types */
+#define OP_MODIFY 1
+#define OP_ADD 2
+#define OP_DELETE 3
+#define OP_MODRDN 4
+
+/*
+ * How often the changelog trimming thread runs. This is the minimum trim age.
+ */
+#define CHANGELOGDB_TRIM_INTERVAL 300*1000 /* 5 minutes */
+
+#define RETROCL_DLL_DEFAULT_THREAD_STACKSIZE 131072L
+#define RETROCL_BE_CACHEMEMSIZE "2097152"
+#define RETROCL_BE_CACHESIZE "-1"
+#define RETROCL_PLUGIN_NAME "DSRetroclPlugin"
+
+/* was originally changelogmaximumage */
+#define CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE "nsslapd-changelogmaxage"
+#define CONFIG_CHANGELOG_DIRECTORY_ATTRIBUTE "nsslapd-changelogdir"
+
+#define RETROCL_CHANGELOG_DN "cn=changelog"
+#define RETROCL_MAPPINGTREE_DN "cn=\"cn=changelog\",cn=mapping tree,cn=config"
+#define RETROCL_PLUGIN_DN "cn=Retro Changelog Plugin,cn=plugins,cn=config"
+#define RETROCL_LDBM_DN "cn=changelog,cn=ldbm database,cn=plugins,cn=config"
+#define RETROCL_INDEX_DN "cn=changenumber,cn=index,cn=changelog,cn=ldbm database,cn=plugins,cn=config"
+
+/* Allow anonymous access to the changelog base only, but not to the
+ * entries in the changelog.
+ */
+#define RETROCL_ACL "(target =\"ldap:///cn=changelog\")(targetattr != \"aci\")(version 3.0; acl \"changelog base\"; allow( read,search, compare ) userdn =\"ldap:///anyone\";)"
+
+enum {
+ PLUGIN_RETROCL,
+ PLUGIN_MAX
+};
+
+extern void* g_plg_identity [PLUGIN_MAX];
+extern Slapi_Backend *retrocl_be_changelog;
+
+extern const char *attr_changenumber;
+extern const char *attr_targetdn;
+extern const char *attr_changetype;
+extern const char *attr_newrdn;
+extern const char *attr_newsuperior;
+extern const char *attr_deleteoldrdn;
+extern const char *attr_changes;
+extern const char *attr_changetime;
+extern const char *attr_objectclass;
+
+extern PRLock *retrocl_internal_lock;
+
+/* Functions */
+
+/* from repl_shared.h: not sure where defined */
+unsigned long strntoul( char *from, size_t len, int base );
+
+extern int retrocl_plugin_init(Slapi_PBlock *pb);
+
+extern int retrocl_bepostop_delete (Slapi_PBlock *pb);
+extern int retrocl_postop_add (Slapi_PBlock *pb);
+extern int retrocl_postop_delete (Slapi_PBlock *pb);
+extern int retrocl_postop_modify (Slapi_PBlock *pb);
+extern int retrocl_postop_modrdn (Slapi_PBlock *pb);
+extern int retrocl_postob(Slapi_PBlock *,int);
+
+extern int retrocl_rootdse_search (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+
+extern void retrocl_create_cle(void);
+extern int retrocl_create_config(void);
+
+extern changeNumber retrocl_get_first_changenumber(void);
+extern void retrocl_set_first_changenumber(changeNumber cn);
+extern changeNumber retrocl_get_last_changenumber(void);
+extern void retrocl_commit_changenumber(void);
+extern void retrocl_release_changenumber(void);
+extern changeNumber retrocl_assign_changenumber(void);
+extern int retrocl_get_changenumbers(void);
+extern void retrocl_forget_changenumbers(void);
+extern time_t retrocl_getchangetime( int type, int *err );
+
+extern void retrocl_init_trimming(void);
+extern void retrocl_stop_trimming(void);
+extern char *retrocl_get_config_str(const char *attrt);
+
+#endif /* _H_RETROCL */
diff --git a/ldap/servers/plugins/retrocl/retrocl.txt b/ldap/servers/plugins/retrocl/retrocl.txt
new file mode 100644
index 00000000..e82368e8
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl.txt
@@ -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
+#
+
+Changelog user documentation
+Last Updated October 6, 2000
+
+1. Introduction
+
+This document describes a how DS 6.0 provides a change log broadly
+compatible with the Internet Draft draft-good-ldap-changelog-01.txt.
+
+When enabled, the change log appears in the DIT below cn=changelog. It
+consists of a single level of entries, each of class changeLogEntry. This
+object class allows the following attributes:
+ - changeNumber. This attribute is always present and contains a single
+ value, an integer which is unique for each change. The value for later
+ changes is larger than those of any change which is already present.
+ - targetDN. This attribute contains the distinguished name of the entry
+ which was added, modified or deleted. In the case of a ModifyDN operation,
+ the targetDN attribute contains the DN of the entry before it was renamed
+ or moved.
+ - changeType. This attribute contains one of the following values: "add",
+ "delete", "modify" or "modrdn".
+ - changes. This attribute contains the changes made to the entry, in LDIF
+ format, for a add or modify change.
+ - newRDN. This attribute contains the new RDN of the entry, for a modifyDN
+ change.
+ - deleteOldRDN. This attribute contains whether the old RDN of the entry
+ was deleted, for a modifyDN change.
+ - newSuperior. This attribute contains the newSuperior field of the entry,
+ for a modifyDN change.
+
+The change log is implemented in an LDBM database.
+
+2. Configuration
+
+To enable the change log, the following steps should be performed. First,
+change the nsslapd-pluginenabled attribute of the DSE cn=Retrocl Plugin,
+cn=plugins,cn=config to "on" instead of "off", Then start or restart the
+server. The server will automatically create the change log database.
+
+3. Trimming
+
+The entries in the change log may be automatically removed if they are older
+than a specified period of time. This is done by setting the
+changelogmaximumage attribute in the change log plugin DSE cn=Retrocl Plugin,
+cn=plugins,cn=config and restarting the server. If this attribute is not
+present, then changed are not trimmed.
+
+The changelogmaximumage attribute is single-valued, and its value consists of
+two parts: a number and a time units code. The time units codes are:
+ - 's' for seconds,
+ - 'm' for minutes,
+ - 'h' for hours,
+ - 'd' for days,
+ - 'w' for weeks.
+
+For example,
+
+changelogmaximumage: 2d
+
+The minimum value is 5 minutes.
+
+4. Access Control
+
+When the changelog backend is created, the default access control is to allow
+anonymous read, search and compare to the changelog base entry, cn=changelog,
+by anyone. No access is granted, except implicitly to the Directory Manager,
+to any of the entries in the change log.
+
+Read access to the entries in the change log should not be granted to anonymous
+users, as the changes attribute could contain modifications to sensitive
+attribute values (such as passwords). Only authenticated services should be
+allowed to access this information.
+
+5. Protocol interaction
+
+All search and compare operations are supported on the change log database.
+Search operations whose filter is of the form
+(&(changenumber>=X)(changeNumber<=Y) are optimized.
+
+Add or modify operations should not be performed on change log entries in the
+change log database. Change log entries can be deleted if desired. The
+change log base entry, cn=changelog, can be modified if desired, to vary the
+access control policy of the change log database.
+
+6. Caveats
+
+The change log does not currently record changes which are internally
+constructed to resolve conflicts during multi-master replication. As a
+result, the change log should not be used in deployments which use multi-master
+replication with more than two masters or suppliers for a database.
+
+==
+
+root dse firstchangenumber and lastchangenumber
+
+changelogdir attribute
+
+test chaining be
+if changelog db deleted - what happens?
+cannot change trim max age without restarting the server
diff --git a/ldap/servers/plugins/retrocl/retrocl_cn.c b/ldap/servers/plugins/retrocl/retrocl_cn.c
new file mode 100644
index 00000000..3623f4b3
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl_cn.c
@@ -0,0 +1,391 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "retrocl.h"
+
+static changeNumber retrocl_internal_cn = 0;
+static changeNumber retrocl_first_cn = 0;
+PRLock *retrocl_internal_lock = NULL;
+
+/*
+ * Function: a2changeNumber
+ *
+ * Returns: changeNumber (long)
+ *
+ * Arguments: string
+ *
+ * Description: parses the string to a changenumber. changenumbers are
+ * positive integers.
+ *
+ */
+
+static changeNumber a2changeNumber (const char *p)
+{
+ changeNumber c;
+
+ c = strntoul((char *)p,strlen(p),10);
+ return c;
+}
+
+/*
+ * Function: handle_cnum_entry
+ * Arguments: op - pointer to Operation struct for this operation
+ * e - pointer to returned entry.
+ * Returns: nothing
+ * Description: Search result handler for retrocl_getchangenum(). Sets the
+ * op->o_handler_data to point to a structure which contains
+ * the changenumber retrieved and an error code.
+ */
+static int
+handle_cnum_entry( Slapi_Entry *e, void *callback_data )
+{
+ cnumRet *cr = (cnumRet *)callback_data;
+ Slapi_Value *sval=NULL;
+ const struct berval *value;
+
+ cr->cr_cnum = 0UL;
+ cr->cr_time = NULL;
+
+ if ( NULL != e ) {
+ Slapi_Attr *chattr = NULL;
+ sval = NULL;
+ value = NULL;
+ if ( slapi_entry_attr_find( e, attr_changenumber, &chattr ) == 0 ) {
+ slapi_attr_first_value( chattr,&sval );
+ if ( NULL != sval ) {
+ value = slapi_value_get_berval ( sval );
+ if( NULL != value && NULL != value->bv_val &&
+ '\0' != value->bv_val[0]) {
+ cr->cr_cnum = a2changeNumber( value->bv_val );
+ }
+ }
+ }
+ chattr = NULL;
+ sval = NULL;
+ value = NULL;
+
+ chattr = NULL;
+ sval = NULL;
+ value = NULL;
+ if ( slapi_entry_attr_find( e, attr_changetime, &chattr ) == 0 ) {
+ slapi_attr_first_value( chattr,&sval );
+ if ( NULL != sval) {
+ value = slapi_value_get_berval ( sval );
+ if (NULL != value && NULL != value->bv_val &&
+ '\0' != value->bv_val[0]) {
+ cr->cr_time = slapi_ch_strdup( value->bv_val );
+ }
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Function: handle_cnum_result
+ * Arguments: err - error code returned from search
+ * callback_data - private data for callback
+ * Returns: nothing
+ * Description: result handler for retrocl_getchangenum(). Sets the cr_lderr
+ * field of the cnumRet struct to the error returned
+ * from the backend.
+ */
+static void
+handle_cnum_result( int err, void *callback_data )
+{
+ cnumRet *cr = (cnumRet *)callback_data;
+ cr->cr_lderr = err;
+}
+
+/*
+ * Function: retrocl_get_changenumbers
+ *
+ * Returns: 0/-1
+ *
+ * Arguments: none
+ *
+ * Description: reads the first and last entry in the changelog to obtain
+ * the starting and ending change numbers.
+ *
+ */
+
+int retrocl_get_changenumbers(void)
+{
+ cnumRet cr;
+
+ if (retrocl_internal_lock == NULL) {
+ retrocl_internal_lock = PR_NewLock();
+
+ if (retrocl_internal_lock == NULL) return -1;
+ }
+
+ if (retrocl_be_changelog == NULL) return -1;
+
+ cr.cr_cnum = 0;
+ cr.cr_time = 0;
+
+ slapi_seq_callback(RETROCL_CHANGELOG_DN,SLAPI_SEQ_FIRST,
+ (char *)attr_changenumber, /* cast away const */
+ NULL,NULL,0,&cr,NULL,handle_cnum_result,
+ handle_cnum_entry, NULL);
+
+ retrocl_first_cn = cr.cr_cnum;
+
+ slapi_ch_free(( void **) &cr.cr_time );
+
+ slapi_seq_callback(RETROCL_CHANGELOG_DN,SLAPI_SEQ_LAST,
+ (char *)attr_changenumber, /* cast away const */
+ NULL,NULL,0,&cr,NULL,handle_cnum_result,
+ handle_cnum_entry, NULL);
+
+ retrocl_internal_cn = cr.cr_cnum;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,"retrocl","Got changenumbers %d and %d\n",
+ retrocl_first_cn,
+ retrocl_internal_cn);
+
+ slapi_ch_free(( void **) &cr.cr_time );
+
+ return 0;
+}
+
+/*
+ * Function: retrocl_getchangetime
+ * Arguments: type - one of SLAPI_SEQ_FIRST, SLAPI_SEQ_LAST
+ * Returns: The time of the requested change record. If the return value is
+ * NO_TIME, the changelog could not be read.
+ * If err is non-NULL, the memory it points to is set the the
+ * error code returned from the backend. If "type" is not valid,
+ * *err is set to -1.
+ * Description: Get the first or last changenumber stored in the changelog,
+ * depending on the value of argument "type".
+ */
+time_t retrocl_getchangetime( int type, int *err )
+{
+ cnumRet cr;
+ time_t ret;
+
+ if ( type != SLAPI_SEQ_FIRST && type != SLAPI_SEQ_LAST ) {
+ if ( err != NULL ) {
+ *err = -1;
+ }
+ return NO_TIME;
+ }
+ memset( &cr, '\0', sizeof( cnumRet ));
+ slapi_seq_callback( RETROCL_CHANGELOG_DN, type,
+ (char *)attr_changenumber, /* cast away const */
+ NULL,
+ NULL, 0, &cr, NULL,
+ handle_cnum_result, handle_cnum_entry, NULL );
+
+ if ( err != NULL ) {
+ *err = cr.cr_lderr;
+ }
+
+ if ( NULL == cr.cr_time ) {
+ ret = NO_TIME;
+ } else {
+ ret = parse_localTime( cr.cr_time );
+ }
+ slapi_ch_free(( void **) &cr.cr_time );
+ return ret;
+}
+
+/*
+ * Function: retrocl_forget_changenumbers
+ *
+ * Returns: none
+ *
+ * Arguments: none
+ *
+ * Description: used only when the server is shutting down
+ *
+ */
+
+void retrocl_forget_changenumbers(void)
+{
+ if (retrocl_internal_lock == NULL) return;
+
+ PR_Lock(retrocl_internal_lock);
+ retrocl_first_cn = 0;
+ retrocl_internal_cn = 0;
+ PR_Unlock(retrocl_internal_lock);
+}
+
+/*
+ * Function: retrocl_get_first_changenumber
+ *
+ * Returns: changeNumber
+ *
+ * Arguments: none
+ *
+ * Description: used in root DSE
+ *
+ */
+
+changeNumber retrocl_get_first_changenumber(void)
+{
+ changeNumber cn;
+ PR_Lock(retrocl_internal_lock);
+ cn = retrocl_first_cn;
+ PR_Unlock(retrocl_internal_lock);
+ return cn;
+}
+
+/*
+ * Function: retrocl_set_first_changenumber
+ *
+ * Returns: none
+ *
+ * Arguments: changenumber
+ *
+ * Description: used in changelog trimming
+ *
+ */
+
+void retrocl_set_first_changenumber(changeNumber cn)
+{
+ PR_Lock(retrocl_internal_lock);
+ retrocl_first_cn = cn;
+ PR_Unlock(retrocl_internal_lock);
+}
+
+
+/*
+ * Function: retrocl_get_last_changenumber
+ *
+ * Returns:
+ *
+ * Arguments:
+ *
+ * Description: used in root DSE
+ *
+ */
+
+changeNumber retrocl_get_last_changenumber(void)
+{
+ changeNumber cn;
+ PR_Lock(retrocl_internal_lock);
+ cn = retrocl_internal_cn;
+ PR_Unlock(retrocl_internal_lock);
+ return cn;
+}
+
+/*
+ * Function: retrocl_commit_changenumber
+ *
+ * Returns: none
+ *
+ * Arguments: none, lock must be held
+ *
+ * Description: NOTE! MUST BE PRECEEDED BY retrocl_assign_changenumber
+ *
+ */
+
+void retrocl_commit_changenumber(void)
+{
+ if ( retrocl_first_cn == 0) {
+ retrocl_first_cn = retrocl_internal_cn;
+ }
+}
+
+/*
+ * Function: retrocl_release_changenumber
+ *
+ * Returns: none
+ *
+ * Arguments: none, lock must be held
+ *
+ * Description: NOTE! MUST BE PRECEEDED BY retrocl_assign_changenumber
+ *
+ */
+
+void retrocl_release_changenumber(void)
+{
+ retrocl_internal_cn--;
+}
+
+/*
+ * Function: retrocl_update_lastchangenumber
+ *
+ * Returns: 0/-1
+ *
+ * Arguments: none
+ *
+ * Description: reads the last entry in the changelog to obtain
+ * the last change number.
+ *
+ */
+
+int retrocl_update_lastchangenumber(void)
+{
+ cnumRet cr;
+
+ if (retrocl_internal_lock == NULL) {
+ retrocl_internal_lock = PR_NewLock();
+
+ if (retrocl_internal_lock == NULL) return -1;
+ }
+
+ if (retrocl_be_changelog == NULL) return -1;
+
+ cr.cr_cnum = 0;
+ cr.cr_time = 0;
+ slapi_seq_callback(RETROCL_CHANGELOG_DN,SLAPI_SEQ_LAST,
+ (char *)attr_changenumber, /* cast away const */
+ NULL,NULL,0,&cr,NULL,handle_cnum_result,
+ handle_cnum_entry, NULL);
+
+
+ retrocl_internal_cn = cr.cr_cnum;
+ slapi_log_error(SLAPI_LOG_PLUGIN,"retrocl","Refetched last changenumber = %d \n",
+ retrocl_internal_cn);
+
+ slapi_ch_free(( void **) &cr.cr_time );
+
+ return 0;
+}
+
+
+
+/*
+ * Function: retrocl_assign_changenumber
+ *
+ * Returns: change number, 0 on error
+ *
+ * Arguments: none. Lock must be held.
+ *
+ * Description: NOTE! MUST BE FOLLOWED BY retrocl_commit_changenumber or
+ * retrocl_release_changenumber
+ *
+ */
+
+changeNumber retrocl_assign_changenumber(void)
+{
+ changeNumber cn;
+
+ if (retrocl_internal_lock == NULL) return 0;
+
+ /* Before we assign the changenumber; we should check for the
+ * validity of the internal assignment of retrocl_internal_cn
+ * we had from the startup */
+
+ if(retrocl_internal_cn <= retrocl_first_cn){
+ /* the numbers have become out of sync - retrocl_get_changenumbers
+ * gets called only once during startup and it may have had a problem
+ * getting the last changenumber.
+ * If there was any problem then update the lastchangenumber from the changelog db.
+ * This function is being called by only the thread that is actually writing
+ * to the changelog.
+ */
+ retrocl_update_lastchangenumber();
+ }
+
+ retrocl_internal_cn++;
+ cn = retrocl_internal_cn;
+ return cn;
+}
diff --git a/ldap/servers/plugins/retrocl/retrocl_create.c b/ldap/servers/plugins/retrocl/retrocl_create.c
new file mode 100644
index 00000000..fbda8e36
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl_create.c
@@ -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 **/
+
+#include "retrocl.h"
+
+/*
+The changelog is created by
+ - changing the node in the dse tree which represents the changelog plugin
+ to enabled on,
+ - shutting down the server,
+ - starting the server.
+ */
+
+/******************************/
+
+/*
+ * Function: retrocl_create_be
+ *
+ * Returns: LDAP_
+ *
+ * Arguments: location in file system to put changelog, or NULL for default
+ *
+ * Description:
+ * add an entry of class nsBackendInstance below cn=ldbm,cn=plugins,cn=config
+ *
+ */
+
+static int retrocl_create_be(const char *bedir)
+{
+ Slapi_PBlock *pb = NULL;
+ Slapi_Entry *e;
+ struct berval *vals[2];
+ struct berval val;
+ int rc;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ e = slapi_entry_alloc();
+ slapi_entry_set_dn(e,slapi_ch_strdup(RETROCL_LDBM_DN));
+
+ /* Set the objectclass attribute */
+ val.bv_val = "top";
+ val.bv_len = 3;
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ /* Set the objectclass attribute */
+ val.bv_val = "extensibleObject";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ /* Set the objectclass attribute */
+ val.bv_val = "nsBackendInstance";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ val.bv_val = "changelog";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "cn", vals );
+
+ val.bv_val = RETROCL_BE_CACHESIZE;
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "nsslapd-cachesize", vals );
+
+ val.bv_val = RETROCL_CHANGELOG_DN;
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "nsslapd-suffix", vals );
+
+ val.bv_val = RETROCL_BE_CACHEMEMSIZE;
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "nsslapd-cachememsize", vals );
+
+ val.bv_val = "off";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "nsslapd-readonly", vals );
+
+ if (bedir) {
+ val.bv_val = (char *)bedir; /* cast const */
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "nsslapd-directory", vals );
+ }
+
+ pb = slapi_pblock_new ();
+ slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */,
+ g_plg_identity[PLUGIN_RETROCL],
+ 0 /* actions */ );
+ slapi_add_internal_pb (pb);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
+ slapi_pblock_destroy(pb);
+
+ if (rc == 0) {
+ slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "created changelog database node\n");
+ } else if (rc == LDAP_ALREADY_EXISTS) {
+ slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "changelog database node already existed\n");
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "Changelog LDBM backend could not be created (%d)\n", rc);
+ return rc;
+ }
+
+
+ /* we need the changenumber indexed */
+ e = slapi_entry_alloc();
+ slapi_entry_set_dn(e,slapi_ch_strdup(RETROCL_INDEX_DN));
+
+ /* Set the objectclass attribute */
+ val.bv_val = "top";
+ val.bv_len = 3;
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ /* Set the objectclass attribute */
+ val.bv_val = "nsIndex";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ val.bv_val = "changenumber";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "cn", vals );
+
+ val.bv_val = "false";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "nssystemindex", vals );
+
+ val.bv_val = "eq";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "nsindextype", vals );
+
+ pb = slapi_pblock_new ();
+ slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */,
+ g_plg_identity[PLUGIN_RETROCL],
+ 0 /* actions */ );
+ slapi_add_internal_pb (pb);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
+ slapi_pblock_destroy(pb);
+
+ if (rc == 0) {
+ slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "created changenumber index node\n");
+ } else if (rc == LDAP_ALREADY_EXISTS) {
+ slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "changelog index node already existed\n");
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "Changelog LDBM backend changenumber index could not be created (%d)\n", rc);
+ return rc;
+ }
+
+ return rc;
+}
+
+/*
+ * Function: retrocl_create_config
+ *
+ * Returns: LDAP_
+ *
+ * Arguments: none
+ *
+ * Description:
+ * This function is called if there was no mapping tree node or backend for
+ * cn=changelog.
+ */
+int retrocl_create_config(void)
+{
+ Slapi_PBlock *pb = NULL;
+ Slapi_Entry *e;
+ struct berval *vals[2];
+ struct berval val;
+ int rc;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* Assume the mapping tree node is missing. It doesn't hurt to
+ * attempt to add it if it already exists. You will see a warning
+ * in the errors file when the referenced backend does not exist.
+ */
+ e = slapi_entry_alloc();
+ slapi_entry_set_dn(e,slapi_ch_strdup(RETROCL_MAPPINGTREE_DN));
+
+ /* Set the objectclass attribute */
+ val.bv_val = "top";
+ val.bv_len = 3;
+ slapi_entry_add_values( e, "objectclass", vals );
+
+
+ /* Set the objectclass attribute */
+ val.bv_val = "extensibleObject";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ /* Set the objectclass attribute */
+ val.bv_val = "nsMappingTree";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ val.bv_val = "backend";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "nsslapd-state", vals );
+
+ val.bv_val = RETROCL_CHANGELOG_DN;
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "cn", vals );
+
+ val.bv_val = "changelog";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "nsslapd-backend", vals );
+
+ pb = slapi_pblock_new ();
+ slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */,
+ g_plg_identity[PLUGIN_RETROCL],
+ 0 /* actions */ );
+ slapi_add_internal_pb (pb);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
+ slapi_pblock_destroy(pb);
+
+ if (rc == 0) {
+ slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "created changelog mapping tree node\n");
+ } else if (rc == LDAP_ALREADY_EXISTS) {
+ slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "changelog mapping tree node already existed\n");
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "cn=\"cn=changelog\",cn=mapping tree,cn=config could not be created (%d)\n", rc);
+ return rc;
+ }
+
+ retrocl_be_changelog = slapi_be_select_by_instance_name("changelog");
+
+ if (retrocl_be_changelog == NULL) {
+ /* This is not the nsslapd-changelogdir from cn=changelog4,cn=config */
+ char *bedir;
+
+ bedir = retrocl_get_config_str(CONFIG_CHANGELOG_DIRECTORY_ATTRIBUTE);
+
+ if (bedir == NULL) {
+ /* none specified */
+ }
+
+ rc = retrocl_create_be(bedir);
+ slapi_ch_free ((void **)&bedir);
+ if (rc != LDAP_SUCCESS && rc != LDAP_ALREADY_EXISTS) {
+ return rc;
+ }
+
+ retrocl_be_changelog = slapi_be_select_by_instance_name("changelog");
+ }
+
+ return LDAP_SUCCESS;
+}
+
+/******************************/
+
+/* Function: retrocl_create_cle
+ *
+ * Arguments: none
+ * Returns: nothing
+ * Description: Attempts to create the cn=changelog entry which might already
+ * exist.
+ */
+
+void retrocl_create_cle (void)
+{
+ Slapi_PBlock *pb = NULL;
+ Slapi_Entry *e;
+ int rc;
+ struct berval *vals[2];
+ struct berval val;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ e = slapi_entry_alloc();
+ slapi_entry_set_dn(e,slapi_ch_strdup(RETROCL_CHANGELOG_DN));
+
+ /* Set the objectclass attribute */
+ val.bv_val = "top";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "objectclass", vals );
+
+
+ /* Set the objectclass attribute */
+ val.bv_val = "nsContainer";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "objectclass", vals );
+
+
+ /* Set the objectclass attribute */
+ val.bv_val = "changelog";
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "cn", vals );
+
+ val.bv_val = RETROCL_ACL;
+ val.bv_len = strlen(val.bv_val);
+ slapi_entry_add_values( e, "aci", vals );
+
+ pb = slapi_pblock_new ();
+ slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */,
+ g_plg_identity[PLUGIN_RETROCL],
+ 0 /* actions */ );
+ slapi_add_internal_pb (pb);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
+ slapi_pblock_destroy(pb);
+
+ if (rc == 0) {
+ slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "created cn=changelog\n");
+ } else if (rc == LDAP_ALREADY_EXISTS) {
+ slapi_log_error (SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "cn=changelog already existed\n");
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "cn=changelog could not be created (%d)\n", rc);
+ }
+}
+
diff --git a/ldap/servers/plugins/retrocl/retrocl_po.c b/ldap/servers/plugins/retrocl/retrocl_po.c
new file mode 100644
index 00000000..96512a51
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl_po.c
@@ -0,0 +1,529 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "retrocl.h"
+
+static int
+entry2reple( Slapi_Entry *e, Slapi_Entry *oe );
+
+static int
+mods2reple( Slapi_Entry *e, LDAPMod **ldm );
+
+static int
+modrdn2reple( Slapi_Entry *e, const char *newrdn, int deloldrdn,
+ LDAPMod **ldm, const char *newsup );
+
+/******************************/
+
+const char *attr_changenumber = "changenumber";
+const char *attr_targetdn = "targetdn";
+const char *attr_changetype = "changetype";
+const char *attr_newrdn = "newrdn";
+const char *attr_deleteoldrdn = "deleteoldrdn";
+const char *attr_changes = "changes";
+const char *attr_newsuperior = "newsuperior";
+const char *attr_changetime = "changetime";
+const char *attr_objectclass = "objectclass";
+
+/*
+ * Function: make_changes_string
+ *
+ * Returns:
+ *
+ * Arguments:
+ *
+ * Description:
+ * loop through the LDAPMod struct and construct the changes attribute/
+ *
+ */
+
+static lenstr *make_changes_string(LDAPMod **ldm, const char **includeattrs)
+{
+ lenstr *l;
+ int i, j, len;
+ int skip;
+
+ l = lenstr_new();
+
+ for ( i = 0; ldm[ i ] != NULL; i++ ) {
+ /* If a list of explicit attributes was given, only add those */
+ if ( NULL != includeattrs ) {
+ skip = 1;
+ for ( j = 0; includeattrs[ j ] != NULL; j++ ) {
+ if ( strcasecmp( includeattrs[ j ], ldm[ i ]->mod_type ) == 0 ) {
+ skip = 0;
+ break;
+ }
+ }
+ if ( skip ) {
+ continue;
+ }
+ }
+ switch ( ldm[ i ]->mod_op & ~LDAP_MOD_BVALUES ) {
+ case LDAP_MOD_ADD:
+ addlenstr( l, "add: " );
+ addlenstr( l, ldm[ i ]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+ case LDAP_MOD_DELETE:
+ addlenstr( l, "delete: " );
+ addlenstr( l, ldm[ i ]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+ case LDAP_MOD_REPLACE:
+ addlenstr( l, "replace: " );
+ addlenstr( l, ldm[ i ]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+ }
+ for ( j = 0; ldm[ i ]->mod_bvalues != NULL &&
+ ldm[ i ]->mod_bvalues[ j ] != NULL; j++ ) {
+ char *buf = NULL;
+ char *bufp = NULL;
+
+ len = strlen( ldm[ i ]->mod_type );
+ len = LDIF_SIZE_NEEDED( len,
+ ldm[ i ]->mod_bvalues[ j ]->bv_len ) + 1;
+ buf = slapi_ch_malloc( len );
+ bufp = buf;
+ ldif_put_type_and_value( &bufp, ldm[ i ]->mod_type,
+ ldm[ i ]->mod_bvalues[ j ]->bv_val,
+ ldm[ i ]->mod_bvalues[ j ]->bv_len );
+ *bufp = '\0';
+
+ addlenstr( l, buf );
+
+ free( buf );
+ }
+ addlenstr( l, "-\n" );
+ }
+ return l;
+}
+
+/*
+ * Function: write_replog_db
+ * Arguments: be - backend to which this change is being applied
+ * optype - type of LDAP operation being logged
+ * dn - distinguished name of entry being changed
+ * log_m - pointer to the actual change operation on a modify
+ * flag - only used by modrdn operations - value of deleteoldrdn
+ * curtime - the current time
+ * Returns: nothing
+ * Description: Given a change, construct an entry which is to be added to the
+ * changelog database.
+ */
+static void
+write_replog_db(
+ int optype,
+ char *dn,
+ LDAPMod **log_m,
+ int flag,
+ time_t curtime,
+ Slapi_Entry *log_e,
+ const char *newrdn,
+ LDAPMod **modrdn_mods,
+ const char *newsuperior
+)
+{
+ char *pat, *edn;
+ struct berval *vals[ 2 ];
+ struct berval val;
+ Slapi_Entry *e;
+ char chnobuf[ 20 ];
+ int err;
+ Slapi_PBlock *pb = NULL;
+ changeNumber changenum;
+
+ PR_Lock(retrocl_internal_lock);
+ changenum = retrocl_assign_changenumber();
+
+ PR_ASSERT( changenum > 0UL );
+ slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "write_replog_db: write change record %d for dn: \"%s\"\n",
+ changenum, ( dn == NULL ) ? "NULL" : dn );
+
+ /* Construct the dn of this change record */
+ pat = "%s=%lu,%s";
+ edn = slapi_ch_malloc( strlen( pat ) + strlen( RETROCL_CHANGELOG_DN) + 20 );
+ sprintf( edn, pat, attr_changenumber, changenum, RETROCL_CHANGELOG_DN);
+
+ /*
+ * Create the entry struct, and fill in fields common to all types
+ * of change records.
+ */
+ vals[ 0 ] = &val;
+ vals[ 1 ] = NULL;
+
+ e = slapi_entry_alloc();
+ slapi_entry_set_dn( e, slapi_ch_strdup( edn ));
+
+ /* Set the objectclass attribute */
+ val.bv_val = "top";
+ val.bv_len = 3;
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ val.bv_val = "changelogentry";
+ val.bv_len = 14;
+ slapi_entry_add_values( e, "objectclass", vals );
+
+ /* Set the changeNumber attribute */
+ sprintf( chnobuf, "%lu", changenum );
+ val.bv_val = chnobuf;
+ val.bv_len = strlen( chnobuf );
+ slapi_entry_add_values( e, attr_changenumber, vals );
+
+ /* Set the targetentrydn attribute */
+ val.bv_val = dn;
+ val.bv_len = strlen( dn );
+ slapi_entry_add_values( e, attr_targetdn, vals );
+
+ /* Set the changeTime attribute */
+ val.bv_val = format_genTime (curtime);
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_add_values( e, attr_changetime, vals );
+ free( val.bv_val );
+
+ /*
+ * Finish constructing the entry. How to do it depends on the type
+ * of modification being logged.
+ */
+ err = 0;
+ switch ( optype ) {
+ case OP_ADD:
+ if ( entry2reple( e, log_e ) != 0 ) {
+ err = 1;
+ }
+ break;
+
+ case OP_MODIFY:
+ if ( mods2reple( e, log_m ) != 0 ) {
+ err = 1;
+ }
+ break;
+
+ case OP_MODRDN:
+ if ( modrdn2reple( e, newrdn, flag, modrdn_mods, newsuperior ) != 0 ) {
+ err = 1;
+ }
+ break;
+
+ case OP_DELETE:
+ /* Set the changetype attribute */
+ val.bv_val = "delete";
+ val.bv_len = 6;
+ slapi_entry_add_values( e, attr_changetype, vals );
+ break;
+ default:
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "replog: Unknown LDAP operation type "
+ "%d.\n", optype );
+ err = 1;
+ }
+
+ /* Call the repl backend to add this entry */
+ if ( 0 == err ) {
+ int rc;
+
+ pb = slapi_pblock_new ();
+ slapi_add_entry_internal_set_pb( pb, e, NULL /* controls */,
+ g_plg_identity[PLUGIN_RETROCL],
+ 0 /* actions */ );
+ slapi_add_internal_pb (pb);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
+ slapi_pblock_destroy(pb);
+ if ( 0 != rc ) {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "replog: an error occured while adding change "
+ "number %d, dn = %s: %s. \n",
+ changenum, edn, ldap_err2string( rc ));
+ retrocl_release_changenumber();
+ } else {
+ /* Tell the change numbering system this one's committed to disk */
+ retrocl_commit_changenumber( );
+ }
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "An error occurred while constructing "
+ "change record number %ld.\n", changenum );
+ retrocl_release_changenumber();
+ }
+ PR_Unlock(retrocl_internal_lock);
+ if ( NULL != edn ) {
+ slapi_ch_free((void **) &edn);
+ }
+
+}
+
+
+/*
+ * Function: entry2reple
+ * Arguments: e - a partially-constructed Slapi_Entry structure
+ * oe - the original entry (an entry being added by a client).
+ * Returns: 0 on success.
+ * Description: Given an Slapi_Entry struct, construct a changelog entry which will be
+ * added to the replication database. It is assumed that e points
+ * to an entry obtained from slapi_entry_alloc().
+ */
+static int
+entry2reple( Slapi_Entry *e, Slapi_Entry *oe )
+{
+ char *p, *estr;
+ struct berval *vals[ 2 ];
+ struct berval val;
+ int len;
+
+ vals[ 0 ] = &val;
+ vals[ 1 ] = NULL;
+
+ /* Set the changetype attribute */
+ val.bv_val = "add";
+ val.bv_len = 3;
+ slapi_entry_add_values( e, attr_changetype, vals );
+
+ estr = slapi_entry2str( oe, &len );
+ p = estr;
+ /* Skip over the dn: line */
+ while (( p = strchr( p, '\n' )) != NULL ) {
+ p++;
+ if ( !ldap_utf8isspace( p )) {
+ break;
+ }
+ }
+ val.bv_val = p;
+ val.bv_len = len - ( p - estr ); /* length + terminating \0 */
+ slapi_entry_add_values( e, attr_changes, vals );
+ free( estr );
+ return 0;
+}
+
+/*
+ * Function: mods2reple
+ * Arguments: e - a partially-constructed Slapi_Entry structure
+ * ldm - an array of pointers to LDAPMod structures describing the
+ * change applied.
+ * Returns: 0 on success.
+ * Description: Given a pointer to an LDAPMod struct and a dn, construct
+ * a new entry which will be added to the replication database.
+ * It is assumed that e points to an entry obtained from
+ * slapi_entry_alloc().
+ */
+static int
+mods2reple( Slapi_Entry *e, LDAPMod **ldm )
+{
+ struct berval val;
+ struct berval *vals[ 2 ];
+ lenstr *l;
+
+ vals[ 0 ] = &val;
+ vals[ 1 ] = NULL;
+
+ /* Set the changetype attribute */
+ val.bv_val = "modify";
+ val.bv_len = 6;
+ slapi_entry_add_values( e, "changetype", vals );
+
+ if (NULL != ldm) {
+ l = make_changes_string( ldm, NULL );
+ if ( NULL != l ) {
+ val.bv_val = l->ls_buf;
+ val.bv_len = l->ls_len + 1; /* string + terminating \0 */
+ slapi_entry_add_values( e, attr_changes, vals );
+ lenstr_free( &l );
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * Function: modrdn2reple
+ * Arguments: e - a partially-constructed Slapi_Entry structure
+ * newrdn - the new relative distinguished name for the entry
+ * deloldrdn - the "deleteoldrdn" flag provided by the client
+ * ldm - any modifications applied as a side-effect of the modrdn
+ * Returns: 0 on success
+ * Description: Given a dn, a new rdn, and a deleteoldrdn flag, construct
+ * a new entry which will be added to the replication database reflecting a
+ * completed modrdn operation. The entry has the same form as above.
+ * It is assumed that e points to an entry obtained from slapi_entry_alloc().
+ */
+static int
+modrdn2reple(
+ Slapi_Entry *e,
+ const char *newrdn,
+ int deloldrdn,
+ LDAPMod **ldm,
+ const char *newsuperior
+)
+{
+ struct berval val;
+ struct berval *vals[ 2 ];
+ lenstr *l;
+ static const char *lastmodattrs[] = {"modifiersname", "modifytimestamp",
+ "creatorsname", "createtimestamp",
+ NULL };
+
+ vals[ 0 ] = &val;
+ vals[ 1 ] = NULL;
+
+ val.bv_val = "modrdn";
+ val.bv_len = 6;
+ slapi_entry_add_values( e, attr_changetype, vals );
+
+ if (newrdn) {
+ val.bv_val = (char *)newrdn; /* cast away const */
+ val.bv_len = strlen( newrdn );
+ slapi_entry_add_values( e, attr_newrdn, vals );
+ }
+
+ if ( deloldrdn == 0 ) {
+ val.bv_val = "FALSE";
+ val.bv_len = 5;
+ } else {
+ val.bv_val = "TRUE";
+ val.bv_len = 4;
+ }
+ slapi_entry_add_values( e, attr_deleteoldrdn, vals );
+
+ if (newsuperior) {
+ val.bv_val = (char *)newsuperior; /* cast away const */
+ val.bv_len = strlen(newsuperior);
+ slapi_entry_add_values(e, attr_newsuperior,vals);
+ }
+
+ if (NULL != ldm) {
+ l = make_changes_string( ldm, lastmodattrs );
+ if ( NULL != l ) {
+ val.bv_val = l->ls_buf;
+ val.bv_len = l->ls_len + 1; /* string + terminating \0 */
+ slapi_entry_add_values( e, attr_changes, vals );
+ lenstr_free( &l );
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: retrocl_postob
+ *
+ * Returns: 0 on success
+ *
+ * Arguments: pblock, optype (add, del, modify etc)
+ *
+ * Description: called from retrocl.c op-specific plugins.
+ *
+ * Please be aware that operation threads may be scheduled out between their
+ * being performed inside of the LDBM database and the changelog plugin
+ * running. For example, suppose MA and MB are two modify operations on the
+ * same entry. MA may be performed on the LDBM database, and then block
+ * before the changelog runs. MB then runs against the LDBM database and then
+ * is written to the changelog. MA starts running. In the changelog, MB will
+ * appear to have been performed before MA, but in the LDBM database the
+ * opposite will have occured.
+ *
+ *
+ */
+
+int retrocl_postob (Slapi_PBlock *pb,int optype)
+{
+ char *dn;
+ LDAPMod **log_m = NULL;
+ int flag = 0;
+ Slapi_Entry *te = NULL;
+ Slapi_Operation *op = NULL;
+ LDAPMod **modrdn_mods = NULL;
+ char *newrdn = NULL;
+ char *newsuperior = NULL;
+ Slapi_Backend *be = NULL;
+ time_t curtime;
+ int rc;
+
+ /*
+ * Check to see if the change was made to the replication backend db.
+ * If so, don't try to log it to the db (otherwise, we'd get in a loop).
+ */
+
+ (void)slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+
+ if (slapi_be_logchanges(be) == 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if not logging\n",
+ 0,0,0);
+ return 0;
+ }
+
+ if (retrocl_be_changelog == NULL || be == retrocl_be_changelog) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if no/cl be\n",0,0,0);
+ return 0;
+ }
+
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &rc);
+
+ if (rc != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if op failed %d\n",rc,
+ 0,0);
+ return 0;
+ }
+
+ if (slapi_op_abandoned(pb)) {
+ LDAPDebug(LDAP_DEBUG_PLUGIN,"not applying change if op abandoned\n",
+ 0,0,0);
+ return 0;
+ }
+
+ curtime = current_time();
+
+ (void)slapi_pblock_get( pb, SLAPI_ORIGINAL_TARGET_DN, &dn );
+
+ /* change number could be retrieved from Operation extension stored in
+ * the pblock, or else it needs to be made dynamically. */
+
+ /* get the operation extension and retrieve the change number */
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op );
+
+ if (op == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change if no op\n",0,0,0);
+ return 0;
+ }
+
+ if (operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY)){
+ LDAPDebug(LDAP_DEBUG_TRACE,"not applying change for nsTombstone entries\n",0,0,0);
+ return 0;
+ }
+
+ switch ( optype ) {
+ case OP_MODIFY:
+ (void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &log_m );
+ break;
+ case OP_ADD:
+ /*
+ * For adds, we want the unnormalized dn, so we can preserve
+ * spacing, case, when replicating it.
+ */
+ (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &te );
+ if ( NULL != te ) {
+ dn = slapi_entry_get_dn( te );
+ }
+ break;
+ case OP_DELETE:
+ break;
+ case OP_MODRDN:
+ (void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn );
+ (void)slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &flag );
+ (void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &modrdn_mods );
+ (void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperior);
+ break;
+ }
+
+
+ /* check if we should log change to retro changelog, and
+ * if so, do it here */
+ write_replog_db( optype, dn, log_m, flag, curtime, te,
+ newrdn, modrdn_mods, newsuperior );
+
+ return 0;
+}
+
+
diff --git a/ldap/servers/plugins/retrocl/retrocl_rootdse.c b/ldap/servers/plugins/retrocl/retrocl_rootdse.c
new file mode 100644
index 00000000..602858d3
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl_rootdse.c
@@ -0,0 +1,64 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "retrocl.h"
+
+
+
+/*
+ * Function: retrocl_rootdse_search
+ *
+ * Returns: SLAPI_DSE_CALLBACK_OK always
+ *
+ * Arguments: See plugin API
+ *
+ * Description: callback function plugged into base object search of root DSE.
+ * Adds changelog, firstchangenumber and lastchangenumber attributes.
+ *
+ */
+
+int
+retrocl_rootdse_search(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+
+ struct berval val;
+ struct berval *vals[2];
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* Changelog information */
+ if ( retrocl_be_changelog != NULL )
+ {
+ char buf[BUFSIZ];
+ changeNumber cnum;
+
+ /* Changelog suffix */
+ val.bv_val = RETROCL_CHANGELOG_DN;
+ if ( val.bv_val != NULL )
+ {
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "changelog", vals );
+ }
+
+ /* First change number contained in log */
+ cnum = retrocl_get_first_changenumber();
+ sprintf( buf, "%lu", cnum );
+ val.bv_val = buf;
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "firstchangenumber", vals );
+
+ /* Last change number contained in log */
+ cnum = retrocl_get_last_changenumber();
+ sprintf( buf, "%lu", cnum );
+ val.bv_val = buf;
+ val.bv_len = strlen( val.bv_val );
+ slapi_entry_attr_replace( e, "lastchangenumber", vals );
+ }
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
diff --git a/ldap/servers/plugins/retrocl/retrocl_trim.c b/ldap/servers/plugins/retrocl/retrocl_trim.c
new file mode 100644
index 00000000..5c413097
--- /dev/null
+++ b/ldap/servers/plugins/retrocl/retrocl_trim.c
@@ -0,0 +1,505 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+
+#include "retrocl.h"
+
+typedef struct _trim_status {
+ time_t ts_c_max_age; /* Constraint - max age of a changelog entry */
+ time_t ts_s_last_trim; /* Status - last time we trimmed */
+ int ts_s_initialized; /* Status - non-zero if initialized */
+ int ts_s_trimming; /* non-zero if trimming in progress */
+ PRLock *ts_s_trim_mutex; /* protects ts_s_trimming */
+} trim_status;
+static trim_status ts = {0L, 0L, 0, 0, NULL};
+
+/*
+ * All standard changeLogEntry attributes (initialized in get_cleattrs)
+ */
+static const char *cleattrs[ 10 ] = { NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL };
+
+static int retrocl_trimming = 0;
+static Slapi_Eq_Context retrocl_trim_ctx = NULL;
+
+/*
+ * Function: get_cleattrs
+ *
+ * Returns: an array of pointers to attribute names.
+ *
+ * Arguments: None.
+ *
+ * Description: Initializes, if necessary, and returns an array of char *s
+ * with attribute names used for retrieving changeLogEntry
+ * entries from the directory.
+ */
+static const char **get_cleattrs(void)
+{
+ if ( cleattrs[ 0 ] == NULL ) {
+ cleattrs[ 0 ] = attr_objectclass;
+ cleattrs[ 1 ] = attr_changenumber;
+ cleattrs[ 2 ] = attr_targetdn;
+ cleattrs[ 3 ] = attr_changetype;
+ cleattrs[ 4 ] = attr_newrdn;
+ cleattrs[ 5 ] = attr_deleteoldrdn;
+ cleattrs[ 6 ] = attr_changes;
+ cleattrs[ 7 ] = attr_newsuperior;
+ cleattrs[ 8 ] = attr_changetime;
+ cleattrs[ 9 ] = NULL;
+ }
+ return cleattrs;
+}
+
+/*
+ * Function: delete_changerecord
+ *
+ * Returns: LDAP_ error code
+ *
+ * Arguments: the number of the change to delete
+ *
+ * Description:
+ *
+ */
+
+static int
+delete_changerecord( changeNumber cnum )
+{
+ Slapi_PBlock *pb;
+ char *dnbuf;
+ int delrc;
+
+ dnbuf = slapi_ch_malloc( strlen( attr_changenumber ) + 20 +
+ strlen(RETROCL_CHANGELOG_DN));
+ /* Delete the record */
+ sprintf( dnbuf, "%s=%ld, %s", attr_changenumber, cnum,
+ RETROCL_CHANGELOG_DN);
+ pb = slapi_pblock_new ();
+ slapi_delete_internal_set_pb ( pb, dnbuf, NULL /*controls*/, NULL /* uniqueid */,
+ g_plg_identity[PLUGIN_RETROCL], 0 /* actions */ );
+ slapi_delete_internal_pb (pb);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &delrc );
+ slapi_pblock_destroy( pb );
+
+ if ( delrc != LDAP_SUCCESS ) {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "delete_changerecord: could not delete "
+ "change record %d\n", cnum );
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "delete_changerecord: deleted changelog entry \"%s\"\n", dnbuf);
+ }
+ slapi_ch_free((void **) &dnbuf );
+ return delrc;
+}
+
+/*
+ * Function: handle_getchangerecord_result
+ * Arguments: op - pointer to Operation struct for this operation
+ * err - error code returned from search
+ * Returns: nothing
+ * Description: result handler for get_changerecord(). Sets the crt_err
+ * field of the cnum_result_t struct to the error returned
+ * from the backend.
+ */
+static void
+handle_getchangerecord_result( int err, void *callback_data )
+{
+ cnum_result_t *crt = callback_data;
+
+ if ( crt == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "handle_getchangerecord_result: callback_data NULL\n" );
+ } else {
+ crt->crt_err = err;
+ }
+}
+
+/*
+ * Function: handle_getchangerecord_search
+ * Arguments: op - pointer to Operation struct for this operation
+ * e - entry returned by backend
+ * Returns: 0 in all cases
+ * Description: Search result operation handler for get_changerecord().
+ * Sets fields in the cnum_result_t struct pointed to by
+ * op->o_handler_data.
+ */
+static int
+handle_getchangerecord_search( Slapi_Entry *e, void *callback_data)
+{
+ cnum_result_t *crt = callback_data;
+
+ if ( crt == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "handle_getchangerecord_search: op->o_handler_data NULL\n" );
+ } else if ( crt->crt_nentries > 0 ) {
+ /* only return the first entry, I guess */
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME,
+ "handle_getchangerecord_search: multiple entries returned\n" );
+ } else {
+ crt->crt_nentries++;
+ crt->crt_entry = e;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Function: get_changerecord
+ * Arguments: cnum - number of change record to retrieve
+ * Returns: Pointer to an entry structure. The caller must free the entry.
+ * If "err" is non-NULL, an error code is returned in the memory
+ * location it points to.
+ * Description: Retrieve the change record entry whose number is "cnum".
+ */
+static Slapi_Entry *get_changerecord( changeNumber cnum, int *err )
+{
+ cnum_result_t crt, *crtp = &crt;
+ char fstr[ 16 + CNUMSTR_LEN + 2 ];
+ Slapi_PBlock *pb;
+
+ if ( cnum == 0UL ) {
+ if ( err != NULL ) {
+ *err = LDAP_PARAM_ERROR;
+ }
+ return NULL;
+ }
+ crtp->crt_nentries = crtp->crt_err = 0; crtp->crt_entry = NULL;
+ sprintf( fstr, "%s=%ld", attr_changenumber, cnum );
+
+ pb = slapi_pblock_new ();
+ slapi_search_internal_set_pb (pb, RETROCL_CHANGELOG_DN,
+ LDAP_SCOPE_SUBTREE, fstr,
+ (char **)get_cleattrs(), /* cast const */
+ 0 /* attrsonly */,
+ NULL /* controls */, NULL /* uniqueid */,
+ g_plg_identity[PLUGIN_RETROCL],
+ 0 /* actions */);
+
+ slapi_search_internal_callback_pb (pb, crtp,
+ handle_getchangerecord_result,
+ handle_getchangerecord_search, NULL );
+ if ( err != NULL ) {
+ *err = crtp->crt_err;
+ }
+
+ slapi_pblock_destroy (pb);
+
+ return( crtp->crt_entry );
+}
+
+/*
+ * Function: trim_changelog
+ *
+ * Arguments: none
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Description: Trims the changelog, according to the constraints
+ * described by the ts structure.
+ */
+static int trim_changelog(void)
+{
+ int rc = 0, ldrc, done;
+ time_t now;
+ changeNumber first_in_log = 0, last_in_log = 0;
+ Slapi_Entry *e = NULL;
+ int num_deleted = 0;
+ int me,lt;
+
+
+ now = current_time();
+
+ PR_Lock( ts.ts_s_trim_mutex );
+ me = ts.ts_c_max_age;
+ lt = ts.ts_s_last_trim;
+ PR_Unlock( ts.ts_s_trim_mutex );
+
+ if ( now - lt >= (CHANGELOGDB_TRIM_INTERVAL / 1000) ) {
+
+ /*
+ * Trim the changelog. Read sequentially through all the
+ * entries, deleting any which do not meet the criteria
+ * described in the ts structure.
+ */
+ done = 0;
+
+ while ( !done && retrocl_trimming == 1 ) {
+ int did_delete;
+ Slapi_Attr *attr;
+
+ did_delete = 0;
+ first_in_log = retrocl_get_first_changenumber();
+ if ( 0UL == first_in_log ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "trim_changelog: no changelog records "
+ "to trim\n" );
+ /* Bail out - we can't do any useful work */
+ break;
+ }
+
+ last_in_log = retrocl_get_last_changenumber();
+ if ( last_in_log == first_in_log ) {
+ /* Always leave at least one entry in the change log */
+ break;
+ }
+ if ( me > 0L ) {
+ e = get_changerecord( first_in_log, &ldrc );
+ if ( NULL != e ) {
+ Slapi_Value *sval = NULL;
+ const struct berval *val = NULL;
+ rc = slapi_entry_attr_find( e, attr_changetime, &attr );
+ /* Bug 624442: Logic checking for lack of timestamp was
+ reversed. */
+ if ( 0 != rc || slapi_attr_first_value( attr,&sval ) == -1 ||
+ (val = slapi_value_get_berval ( sval )) == NULL ||
+ NULL == val->bv_val ) {
+ /* What to do if there's no timestamp? Just delete it. */
+ retrocl_set_first_changenumber( first_in_log + 1 );
+ ldrc = delete_changerecord( first_in_log );
+ num_deleted++;
+ did_delete = 1;
+ } else {
+ time_t change_time = parse_localTime( val->bv_val );
+ if ( change_time + me < now ) {
+ retrocl_set_first_changenumber( first_in_log + 1 );
+ ldrc = delete_changerecord( first_in_log );
+ num_deleted++;
+ did_delete = 1;
+ }
+ /* slapi_entry_free( e ); */ /* XXXggood should we be freeing this? */
+ }
+ }
+ }
+ if ( !did_delete ) {
+ done = 1;
+ }
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_PLUGIN, "not yet time to trim: %d < (%d+%d)\n",
+ now,lt,(CHANGELOGDB_TRIM_INTERVAL/1000));
+ }
+ PR_Lock( ts.ts_s_trim_mutex );
+ ts.ts_s_trimming = 0;
+ ts.ts_s_last_trim = now;
+ PR_Unlock( ts.ts_s_trim_mutex );
+ if ( num_deleted > 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, RETROCL_PLUGIN_NAME,
+ "trim_changelog: removed %d change records\n",
+ num_deleted );
+ }
+ return rc;
+}
+
+static int retrocl_active_threads;
+
+/*
+ * Function: changelog_trim_thread_fn
+ *
+ * Returns: nothing
+ *
+ * Arguments: none
+ *
+ * Description: the thread creation callback. retrocl_active_threads is
+ * provided for debugging purposes.
+ *
+ */
+
+static void
+changelog_trim_thread_fn( void *arg )
+{
+ PR_AtomicIncrement(&retrocl_active_threads);
+ trim_changelog();
+ PR_AtomicDecrement(&retrocl_active_threads);
+}
+
+
+
+/*
+ * Function: retrocl_housekeeping
+ * Arguments: cur_time - the current time
+ * Returns: nothing
+ * Description: Determines if it is time to trim the changelog database,
+ * and if so, determines if the changelog database needs to
+ * be trimmed. If so, a thread is started which will trim
+ * the database.
+ */
+
+void retrocl_housekeeping ( time_t cur_time, void *noarg )
+{
+ static time_t thread_start_time;
+ int ldrc;
+
+ if (retrocl_be_changelog == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"not housekeeping if no cl be\n",0,0,0);
+ return;
+ }
+
+ if ( !ts.ts_s_initialized ) {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "changelog_housekeeping called before "
+ "trimming constraints set\n" );
+ return;
+ }
+
+ PR_Lock( ts.ts_s_trim_mutex );
+ if ( !ts.ts_s_trimming ) {
+ int must_trim = 0;
+ /* See if we need to trim */
+ /* Has enough time elapsed since our last check? */
+ if ( cur_time - ts.ts_s_last_trim >= (ts.ts_c_max_age) ) {
+ /* Is the first entry too old? */
+ time_t first_time;
+ /*
+ * good we could avoid going to the database to retrieve
+ * this time information if we cached the last value we'd read.
+ * But a client might have deleted it over protocol.
+ */
+ first_time = retrocl_getchangetime( SLAPI_SEQ_FIRST, &ldrc );
+ LDAPDebug(LDAP_DEBUG_PLUGIN,
+ "cltrim: ldrc=%d, first_time=%d, cur_time=%d\n",
+ ldrc,first_time,cur_time);
+ if ( LDAP_SUCCESS == ldrc && first_time > (time_t) 0L &&
+ first_time + ts.ts_c_max_age < cur_time ) {
+ must_trim = 1;
+ }
+ }
+ if ( must_trim ) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"changelog about to create thread\n",0,0,0);
+ /* Start a thread to trim the changelog */
+ thread_start_time = cur_time;
+ ts.ts_s_trimming = 1;
+ if ( PR_CreateThread( PR_USER_THREAD,
+ changelog_trim_thread_fn, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+ RETROCL_DLL_DEFAULT_THREAD_STACKSIZE ) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "unable to create changelog trimming thread\n" );
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_PLUGIN,
+ "changelog does not need to be trimmed\n",0,0,0);
+ }
+ }
+ PR_Unlock( ts.ts_s_trim_mutex );
+}
+
+
+/*
+ * Function: age_str2time
+ *
+ * Returns: time_t
+ *
+ * Arguments: string representation of age (digits and unit s,m,h,d or w)
+ *
+ * Description:
+ * convert time from string like 1h (1 hour) to corresponding time in seconds
+ *
+ */
+
+static time_t
+age_str2time (const char *age)
+{
+ char *maxage;
+ char unit;
+ time_t ageval;
+
+ if (age == NULL || age[0] == '\0' || strcmp (age, "0") == 0) {
+ return 0;
+ }
+
+ maxage = slapi_ch_strdup ( age );
+ unit = maxage[ strlen( maxage ) - 1 ];
+ maxage[ strlen( maxage ) - 1 ] = '\0';
+ ageval = strntoul( maxage, strlen( maxage ), 10 );
+ if ( maxage) {
+ slapi_ch_free ( (void **) &maxage );
+ }
+ switch ( unit ) {
+ case 's':
+ break;
+ case 'm':
+ ageval *= 60;
+ break;
+ case 'h':
+ ageval *= ( 60 * 60 );
+ break;
+ case 'd':
+ ageval *= ( 24 * 60 * 60 );
+ break;
+ case 'w':
+ ageval *= ( 7 * 24 * 60 * 60 );
+ break;
+ default:
+ slapi_log_error( SLAPI_LOG_PLUGIN, "retrocl",
+ "age_str2time: unknown unit \"%c\" "
+ "for maxiumum changelog age\n", unit );
+ ageval = -1;
+ }
+
+ return ageval;
+}
+
+/*
+ * Function: retrocl_init_trimming
+ *
+ * Returns: none, exits on fatal error
+ *
+ * Arguments: none
+ *
+ * Description: called during startup
+ *
+ */
+
+void retrocl_init_trimming (void)
+{
+ const char *cl_maxage;
+ time_t ageval;
+
+ cl_maxage = retrocl_get_config_str(CONFIG_CHANGELOG_MAXAGE_ATTRIBUTE);
+
+ if (cl_maxage == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"No maxage, not trimming retro changelog.\n",0,0,0);
+ return;
+ }
+ ageval = age_str2time (cl_maxage);
+ slapi_ch_free ((void **)&cl_maxage);
+
+ ts.ts_c_max_age = ageval;
+ ts.ts_s_last_trim = (time_t) 0L;
+ ts.ts_s_trimming = 0;
+ if (( ts.ts_s_trim_mutex = PR_NewLock()) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, RETROCL_PLUGIN_NAME, "set_changelog_trim_constraints: "
+ "cannot create new lock.\n" );
+ exit( 1 );
+ }
+ ts.ts_s_initialized = 1;
+ retrocl_trimming = 1;
+
+ retrocl_trim_ctx = slapi_eq_repeat(retrocl_housekeeping,
+ NULL,(time_t)0,
+ CHANGELOGDB_TRIM_INTERVAL);
+
+}
+
+/*
+ * Function: retrocl_stop_trimming
+ *
+ * Returns: none
+ *
+ * Arguments: none
+ *
+ * Description: called when server is shutting down to ensure trimming stops
+ * eventually.
+ *
+ */
+
+void retrocl_stop_trimming(void)
+{
+ retrocl_trimming = 0;
+ if (retrocl_trim_ctx) {
+ slapi_eq_cancel(retrocl_trim_ctx);
+ retrocl_trim_ctx = NULL;
+ }
+}
+
diff --git a/ldap/servers/plugins/rever/Makefile b/ldap/servers/plugins/rever/Makefile
new file mode 100644
index 00000000..76203a9c
--- /dev/null
+++ b/ldap/servers/plugins/rever/Makefile
@@ -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
+#
+#
+# GNU Makefile for Directory Server password_storaged-plugin.so password storage scheme plugins
+#
+
+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 = $(OBJDIR)/lib/libdes
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(MCOM_ROOT)/ldapserver/ns_usepurify.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./libdes.def
+endif
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd
+INCLUDES += -I$(MCOM_ROOT)/ldapserver/ldap/include
+
+REVER_OBJS= \
+ rever.o des.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(REVER_OBJS))
+
+ifeq ($(ARCH), WINNT)
+LIBREVER_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+REVER_DLL = des-plugin
+LIBREVER = $(addprefix $(LIBDIR)/, $(REVER_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += \
+ $(LIBSLAPD_DEP) \
+ $(LDAP_LIBUTIL_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP) \
+ $(SECURITY_DEP)
+EXTRA_LIBS += \
+ $(LIBSLAPD) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LIBUTIL) \
+ $(NSPRLINK) \
+ $(LDAP_COMMON_LIBS) \
+ $(SECURITYLINK)
+endif
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += \
+ $(LIBSLAPD_DEP) \
+ $(LDAP_LIBUTIL_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP) \
+ $(SECURITY_DEP)
+EXTRA_LIBS += \
+ $(LIBSLAPDLINK) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LIBUTIL) \
+ $(NSPRLINK) \
+ $(LDAP_COMMON_LIBS) \
+ $(SECURITYLINK)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libdes.def"
+CFLAGS+= /WX
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+LD=ld
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBREVER)
+
+$(LIBREVER): $(OBJS) $(LIBREVER_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBREVER_DLL_OBJ) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBREVER_DLL_OBJ)
+endif
+ $(RM) $(LIBREVER)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
diff --git a/ldap/servers/plugins/rever/des.c b/ldap/servers/plugins/rever/des.c
new file mode 100644
index 00000000..4b70c91d
--- /dev/null
+++ b/ldap/servers/plugins/rever/des.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 **/
+/* from /usr/project/iplanet/ws/ds5.ke/ns/svrcore/pkcs7/tstarchive.c */
+
+#include <string.h>
+#include <stdio.h>
+
+#include <ldap.h>
+#include <nspr.h>
+#include <nss.h>
+#include <secmod.h>
+/*
+#include <secasn1.h>
+#include <secpkcs7.h>
+*/
+#include <key.h>
+#include <certdb.h>
+#include <cert.h>
+#include <svrcore.h>
+#include <secmodt.h>
+#include <prtypes.h>
+#include <seccomon.h>
+#include <pk11func.h>
+
+#include "rever.h"
+#include <slap.h>
+#include "slapi-plugin.h"
+#include <uuid.h>
+
+
+struct pk11MechItem
+{
+ CK_MECHANISM_TYPE type;
+ const char *mechName;
+};
+static const struct pk11MechItem mymech = { CKM_DES_CBC, "DES CBC encryption" };
+
+
+static Slapi_Mutex *mylock = NULL;
+
+struct pk11ContextStore
+{
+ PK11SlotInfo *slot;
+ const struct pk11MechItem *mech;
+
+ PK11SymKey *key;
+ SECItem *params;
+
+ int length;
+ unsigned char *crypt;
+};
+
+static int encode_path(char *inPlain, char **outCipher, char *path);
+static int decode_path(char *inCipher, char **outPlain, char *path);
+static SVRCOREError genKey(struct pk11ContextStore **out, const char *token, char *path);
+static SVRCOREError cryptPassword(struct pk11ContextStore *store, char * clear, unsigned char **out);
+static SVRCOREError decryptPassword(struct pk11ContextStore *store, unsigned char *cipher, char **out, int len);
+static void freeDes(struct pk11ContextStore *out);
+
+static int init = 0;
+
+void
+init_des_plugin()
+{
+ mylock = slapi_new_mutex();
+}
+
+int
+encode(char *inPlain, char **outCipher)
+{
+ return encode_path(inPlain, outCipher, NULL);
+}
+
+static int
+encode_path(char *inPlain, char **outCipher, char *path)
+{
+ struct pk11ContextStore *context = NULL;
+ int err;
+
+ unsigned char *cipher = NULL;
+ char *tmp = NULL;
+ char *base = NULL;
+
+
+ *outCipher = NULL;
+ err = 1;
+
+ if ( genKey(&context, tokDes, path) == SVRCORE_Success )
+ {
+ /* Try an encryption */
+ if ( cryptPassword(context, inPlain, &cipher) == SVRCORE_Success )
+ {
+ base = BTOA_DataToAscii(cipher, context->length);
+ if ( base != NULL )
+ {
+ tmp = slapi_ch_malloc( 3 + strlen(REVER_SCHEME_NAME) + strlen(base));
+ if ( tmp != NULL )
+ {
+ sprintf( tmp, "%c%s%c%s", PWD_HASH_PREFIX_START, REVER_SCHEME_NAME, PWD_HASH_PREFIX_END, base);
+ *outCipher = tmp;
+ tmp = NULL;
+ err = 0;
+ }
+ PORT_Free(base);
+ }
+ }
+ }
+
+ freeDes(context);
+ slapi_ch_free((void **) &context);
+ return(err);
+}
+
+int
+decode(char *inCipher, char **outPlain)
+{
+ return decode_path(inCipher, outPlain, NULL);
+}
+
+
+static int
+decode_path(char *inCipher, char **outPlain, char *path)
+{
+ struct pk11ContextStore *context = NULL;
+ char *plain= NULL;
+ int err;
+
+ unsigned char *base = NULL;
+ int len = 0;
+
+
+ *outPlain = NULL;
+ err = 1;
+
+ if ( genKey(&context, tokDes, path) == SVRCORE_Success )
+ {
+ /* it seems that there is memory leak in that function: bug 400170 */
+
+ base = ATOB_AsciiToData(inCipher, (unsigned int*)&len);
+ if ( base != NULL )
+ {
+ if ( decryptPassword(context, base, &plain, len) == SVRCORE_Success )
+ {
+ *outPlain = plain;
+ err = 0;
+ }
+ }
+ }
+
+ PORT_Free(base);
+ freeDes(context);
+ slapi_ch_free((void **) &context);
+ return(err);
+}
+
+static void freeDes(struct pk11ContextStore *out)
+{
+ if (out)
+ {
+ if (out->slot)
+ slapd_pk11_freeSlot(out->slot);
+ if (out->key)
+ slapd_pk11_freeSymKey(out->key);
+ if (out->params)
+ SECITEM_FreeItem(out->params,PR_TRUE);
+ if (out->crypt)
+ free(out->crypt);
+ }
+}
+
+static SVRCOREError genKey(struct pk11ContextStore **out, const char *token, char *path)
+{
+ SVRCOREError err = SVRCORE_Success;
+ struct pk11ContextStore *store = NULL;
+ SECItem *pwitem = NULL;
+ SECItem *result = NULL;
+ SECAlgorithmID *algid = NULL;
+ SECOidTag algoid;
+ SECItem *salt = NULL;
+ CK_MECHANISM pbeMech;
+ CK_MECHANISM cryptoMech;
+
+ char *instancedir = NULL;
+ char *iv = NULL;
+
+ store = (struct pk11ContextStore*)slapi_ch_malloc(sizeof(*store));
+ if (store == NULL)
+ {
+ return (err = SVRCORE_NoMemory_Error);
+ }
+ *out = store;
+
+ /* Low-level init */
+ store->slot = NULL;
+ store->key = NULL;
+ store->params = NULL;
+ store->crypt = NULL;
+
+ /* Use the tokenName to find a PKCS11 slot */
+ store->slot = slapd_pk11_findSlotByName((char *)token);
+ if (store->slot == NULL)
+ {
+ return (err = SVRCORE_NoSuchToken_Error);
+ }
+
+ /* Generate a key and parameters to do the encryption */
+ store->mech = &mymech;
+
+ /* Generate a unique id, used as salt for the key generation */
+ if ( path == NULL )
+ {
+ instancedir = config_get_instancedir();
+ if ( instancedir == NULL )
+ {
+ return (err = SVRCORE_System_Error);
+ }
+ }
+ else
+ {
+ instancedir = slapi_ch_strdup(path);
+ }
+ if ( slapi_uniqueIDGenerateFromNameString (&iv, NULL, instancedir, strlen(instancedir)) != UID_SUCCESS )
+ {
+ slapi_ch_free((void**)&instancedir);
+ return (err = SVRCORE_System_Error);
+ }
+ slapi_ch_free((void**)&instancedir);
+
+ pwitem = (SECItem *) PORT_Alloc(sizeof(SECItem));
+ if (pwitem == NULL)
+ {
+ return (err = SVRCORE_NoMemory_Error);
+ }
+ pwitem->type = siBuffer;
+ pwitem->data = (unsigned char *)PORT_Alloc(strlen(iv)+1);
+ if (pwitem->data == NULL)
+ {
+ return (err = SVRCORE_NoMemory_Error);
+ }
+ strcpy((char*)pwitem->data, iv);
+ pwitem->len = strlen(iv) + 1;
+
+ algoid = SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC;
+
+ salt = (SECItem *) PORT_Alloc(sizeof(SECItem));
+ if (salt == NULL)
+ {
+ return (err = SVRCORE_NoMemory_Error);
+ }
+ salt->type = siBuffer;
+ salt->data = (unsigned char *)PORT_Alloc(strlen(iv)+1);
+ if ( salt->data == NULL )
+ {
+ return (err = SVRCORE_NoMemory_Error);
+ }
+ strcpy((char*)salt->data, iv);
+ salt->len = strlen(iv) + 1;
+ slapi_ch_free((void**)&iv);
+
+ algid = slapd_pk11_createPBEAlgorithmID(algoid, 2, salt);
+
+ slapi_lock_mutex(mylock);
+ store->key = slapd_pk11_pbeKeyGen(store->slot, algid, pwitem, 0, 0);
+ if (store->key == 0)
+ {
+ slapi_unlock_mutex(mylock);
+ return (err = SVRCORE_System_Error);
+ }
+
+ slapi_unlock_mutex(mylock);
+ pbeMech.mechanism = slapd_pk11_algtagToMechanism(algoid);
+ result = slapd_pk11_paramFromAlgid(algid);
+ secoid_destroyAlgorithmID(algid, PR_TRUE);
+ pbeMech.pParameter = result->data;
+ pbeMech.ulParameterLen = result->len;
+ if(slapd_pk11_mapPBEMechanismToCryptoMechanism(&pbeMech, &cryptoMech, pwitem,
+ PR_FALSE) != CKR_OK)
+ {
+ SECITEM_FreeItem(result, PR_TRUE);
+ return (err = SVRCORE_System_Error);
+ }
+ SECITEM_FreeItem(result, PR_TRUE);
+ SECITEM_FreeItem(pwitem, PR_TRUE);
+ SECITEM_FreeItem(salt, PR_TRUE);
+ store->params = (SECItem *) PORT_Alloc(sizeof(SECItem));
+ if (store->params == NULL)
+ {
+ return (err = SVRCORE_System_Error);
+ }
+ store->params->type = store->mech->type;
+ store->params->data = (unsigned char *)PORT_Alloc(cryptoMech.ulParameterLen);
+ if (store->params->data == NULL)
+ {
+ return (err = SVRCORE_System_Error);
+ }
+ memcpy(store->params->data, (unsigned char *)cryptoMech.pParameter, cryptoMech.ulParameterLen);
+ store->params->len = cryptoMech.ulParameterLen;
+ PORT_Free(cryptoMech.pParameter);
+ return (err);
+}
+
+static SVRCOREError decryptPassword(struct pk11ContextStore *store, unsigned char *cipher, char **out, int len)
+{
+ SVRCOREError err = SVRCORE_Success;
+ unsigned char *plain = NULL;
+ unsigned char *cipher_with_padding = NULL;
+ SECStatus rv;
+ PK11Context *ctx = 0;
+ int outLen = 0;
+ int blocksize = 0;
+
+ blocksize = slapd_pk11_getBlockSize(store->mech->type, 0);
+ store->length = len;
+
+ /* store->length is the max. length of the returned clear text -
+ must be >= length of crypted bytes - also must be a multiple
+ of blocksize */
+ if (blocksize != 0)
+ {
+ store->length += blocksize - (store->length % blocksize);
+ }
+
+ /* plain will hold the returned clear text */
+ plain = (unsigned char *)slapi_ch_calloc(sizeof(unsigned char),
+ store->length+1);
+ if (!plain)
+ {
+ return (err = SVRCORE_NoMemory_Error);
+ }
+
+ /* create a buffer holding the original cipher bytes, padded with
+ zeros to a multiple of blocksize - do not need +1 since buffer is not
+ a string */
+ cipher_with_padding = (unsigned char *)slapi_ch_calloc(sizeof(unsigned char),
+ store->length);
+ if (!cipher_with_padding)
+ {
+ return (err = SVRCORE_NoMemory_Error);
+ }
+ memcpy(cipher_with_padding, cipher, len);
+
+ ctx = slapd_pk11_createContextBySymKey(store->mech->type, CKA_DECRYPT,
+ store->key, store->params);
+ if (!ctx)
+ {
+ return (err = SVRCORE_System_Error);
+ }
+
+ /* warning - there is a purify UMR in the NSS des code - you may see it when the
+ password is not a multiple of 8 bytes long */
+ rv = slapd_pk11_cipherOp(ctx, plain, &outLen, store->length,
+ cipher_with_padding, store->length);
+ if (rv)
+ {
+ err = SVRCORE_System_Error;
+ }
+
+ rv = slapd_pk11_finalize(ctx);
+ /* we must do the finalize, but we only want to set the err return
+ code if it is not already set */
+ if (rv && (SVRCORE_Success == err))
+ err = SVRCORE_System_Error;
+
+ if (err == SVRCORE_Success)
+ *out = (char *)plain;
+
+ slapi_ch_free((void **)&cipher_with_padding);
+ /* We should free the PK11Context... Something like : */
+ slapd_pk11_destroyContext(ctx, PR_TRUE);
+ return err;
+}
+
+static SVRCOREError cryptPassword(struct pk11ContextStore *store, char * clear, unsigned char **out)
+{
+ SVRCOREError err = SVRCORE_Success;
+ SECStatus rv;
+ PK11Context *ctx = 0;
+ int outLen = 0;
+ int blocksize = 0;
+ unsigned char *clear_with_padding = NULL; /* clear with padding up to blocksize */
+
+ blocksize = slapd_pk11_getBlockSize(store->mech->type, 0);
+ store->length = strlen(clear);
+
+ /* the size of the clear text buffer passed to the des encryption functions
+ must be a multiple of blocksize (usually 8 bytes) - we allocate a buffer
+ of this size, copy the clear text password into it, and pad the rest with
+ zeros */
+ if (blocksize != 0)
+ {
+ store->length += blocksize - (store->length % blocksize);
+ }
+
+ /* store->crypt will hold the crypted password - it must be >= clear length */
+ store->crypt = (unsigned char *)slapi_ch_calloc(sizeof(unsigned char),
+ store->length+1);
+ if (!store->crypt)
+ {
+ return (err = SVRCORE_NoMemory_Error);
+ }
+
+ /* create a buffer big enough to hold the clear text password and padding */
+ clear_with_padding = (unsigned char *)slapi_ch_calloc(sizeof(unsigned char),
+ store->length+1);
+ if (!clear_with_padding)
+ {
+ return (err = SVRCORE_NoMemory_Error);
+ }
+ /* copy the clear text password into the buffer - the calloc insures the
+ remainder is zero padded */
+ strcpy((char *)clear_with_padding, clear);
+
+ ctx = slapd_pk11_createContextBySymKey(store->mech->type, CKA_ENCRYPT,
+ store->key, store->params);
+ if (!ctx)
+ {
+ return (err = SVRCORE_System_Error);
+ }
+
+ rv = slapd_pk11_cipherOp(ctx, store->crypt, &outLen, store->length,
+ clear_with_padding, store->length);
+ if (rv)
+ {
+ err = SVRCORE_System_Error;
+ }
+
+ rv = slapd_pk11_finalize(ctx);
+ /* we must do the finalize, but we only want to set the err return
+ code if it is not already set */
+ if (rv && (SVRCORE_Success == err))
+ err = SVRCORE_System_Error;
+
+ if (err == SVRCORE_Success)
+ *out = store->crypt;
+
+ slapi_ch_free((void **)&clear_with_padding);
+ /* We should free the PK11Context... Something like : */
+ slapd_pk11_destroyContext(ctx, PR_TRUE);
+ return err;
+}
+
+char *
+migrateCredentials(char *oldpath, char *newpath, char *oldcred)
+{
+ char *plain = NULL;
+ char *cipher = NULL;
+
+ init_des_plugin();
+
+ slapd_pk11_configurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
+ NSS_NoDB_Init(NULL);
+
+ if ( decode_path(oldcred, &plain, oldpath) == 0 )
+ {
+ if ( encode_path(plain, &cipher, newpath) != 0 )
+ return(NULL);
+ else
+ return(cipher);
+ }
+ else
+ return(NULL);
+}
diff --git a/ldap/servers/plugins/rever/dllmain.c b/ldap/servers/plugins/rever/dllmain.c
new file mode 100644
index 00000000..0bb85815
--- /dev/null
+++ b/ldap/servers/plugins/rever/dllmain.c
@@ -0,0 +1,91 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+ /*
+ * Microsoft Windows specifics for LIBPWDSTORAGE DLL
+ */
+#include "rever.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; /* successful DLL_PROCESS_ATTACH */
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/rever/libdes.def b/ldap/servers/plugins/rever/libdes.def
new file mode 100644
index 00000000..048af6f4
--- /dev/null
+++ b/ldap/servers/plugins/rever/libdes.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 'Directory Server 6.2.1 Local Credentials Reversible Encryption Plugin'
+EXPORTS
+ des_cmp @2
+ des_enc @3
+ des_dec @4
+ des_init @5
+ migrateCredentials @6
diff --git a/ldap/servers/plugins/rever/rever.c b/ldap/servers/plugins/rever/rever.c
new file mode 100644
index 00000000..10767944
--- /dev/null
+++ b/ldap/servers/plugins/rever/rever.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 **/
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "dirver.h"
+
+#include "rever.h"
+
+static Slapi_PluginDesc pdesc = { "des-storage-scheme", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "DES storage scheme plugin" };
+
+static char *plugin_name = "ReverStoragePlugin";
+
+int
+des_cmp( char *userpwd, char *dbpwd )
+{
+ char *cipher = NULL;
+
+ if ( encode(userpwd, &cipher) != 0 )
+ return 1;
+ else
+ return( strcmp(cipher, dbpwd) );
+}
+
+char *
+des_enc( char *pwd )
+{
+ char *cipher = NULL;
+
+ if ( encode(pwd, &cipher) != 0 )
+ return(NULL);
+ else
+ return( cipher );
+}
+
+char *
+des_dec( char *pwd )
+{
+ char *plain = NULL;
+
+ if ( decode(pwd, &plain) != 0 )
+ return(NULL);
+ else
+ return( plain );
+}
+
+int
+des_init( Slapi_PBlock *pb )
+{
+ int rc;
+ char *name;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "=> des_init\n" );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN,
+ (void *) des_enc);
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN,
+ (void *) des_cmp );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_DEC_FN,
+ (void *) des_dec );
+ name = slapi_ch_strdup(REVER_SCHEME_NAME);
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME,
+ name );
+
+ init_des_plugin();
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, plugin_name, "<= des_init %d\n\n", rc );
+
+ return( rc );
+}
diff --git a/ldap/servers/plugins/rever/rever.h b/ldap/servers/plugins/rever/rever.h
new file mode 100644
index 00000000..0992aea7
--- /dev/null
+++ b/ldap/servers/plugins/rever/rever.h
@@ -0,0 +1,34 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _REVER_H
+#define _REVER_H
+
+#include "slapi-plugin.h"
+#include "nspr.h"
+#include "base64.h"
+#include "slap.h"
+#include "ldaplog.h"
+
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+
+#define REVER_SCHEME_NAME "DES"
+#define PWD_HASH_PREFIX_START '{'
+#define PWD_HASH_PREFIX_END '}'
+
+
+int rever_cmp( char *userpwd, char *dbpwd );
+char *rever_enc( char *pwd );
+char *rever_dec( char *pwd );
+int rever_init( Slapi_PBlock *pb );
+void init_des_plugin();
+
+int encode(char *inPlain, char ** outCipher);
+int decode(char *inCipher, char **outPlain);
+
+char *migrateCredentials(char *oldpath, char *newpath, char *oldcred);
+typedef char *(*migrate_fn_type)(char *, char *, char *);
+
+#endif
diff --git a/ldap/servers/plugins/roles/Makefile b/ldap/servers/plugins/roles/Makefile
new file mode 100644
index 00000000..2e936fad
--- /dev/null
+++ b/ldap/servers/plugins/roles/Makefile
@@ -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
+#
+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 = $(OBJDIR)/lib/libroles
+LIBDIR = $(LIB_RELDIR)
+ifndef INSTDIR
+INSTDIR = c:/netscape/server4/
+endif
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./roles.def
+endif
+
+ROLES_OBJS = roles_plugin.o roles_cache.o
+OBJS = $(addprefix $(OBJDEST)/, $(ROLES_OBJS))
+
+ROLES_DLL = roles-plugin
+
+INCLUDES += -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+# DBDB this is clearly all nonsense: the libraries this thing links with should not depend on the platform.
+# However, for now I make this AIX-specific change and leave the NT-specifc stuff in place (I think it came
+# from the makefile I copied to make this one. After build 3, fix this.
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD)
+EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD) $(LDAP_LIBAVL)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), WINNT)
+ROLES_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), AIX)
+LD=ld
+EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD) $(LDAP_LIBAVL)
+endif
+
+ROLES= $(addprefix $(LIBDIR)/, $(ROLES_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(ROLES)
+
+ifeq ($(ARCH), WINNT)
+$(ROLES): $(OBJS) $(ROLES_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(ROLES_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(ROLES): $(OBJS) $(ROLES_DLL_OBJ)
+ $(LINK_DLL) $(ROLES_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(ROLES_DLL_OBJ)
+endif
+ $(RM) $(ROLES)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
+
+# Target to push the built binary to an installed server
+#ROLES_PUSH = $(addprefix $(INSTDIR)lib/, $(notdir $(ROLES)))
+#push: $(ROLES_PUSH)
+
+#$(ROLES_PUSH): $(ROLES)
+# cp $(ROLES) $(ROLES_PUSH)
diff --git a/ldap/servers/plugins/roles/dllmain.c b/ldap/servers/plugins/roles/dllmain.c
new file mode 100644
index 00000000..fabf8677
--- /dev/null
+++ b/ldap/servers/plugins/roles/dllmain.c
@@ -0,0 +1,96 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/roles/roles.def b/ldap/servers/plugins/roles/roles.def
new file mode 100644
index 00000000..0ae9d85f
--- /dev/null
+++ b/ldap/servers/plugins/roles/roles.def
@@ -0,0 +1,10 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 7.0 Roles Plugin'
+EXPORTS
+ roles_init @2
+ plugin_init_debug_level @3
diff --git a/ldap/servers/plugins/roles/roles_cache.c b/ldap/servers/plugins/roles/roles_cache.c
new file mode 100644
index 00000000..f4dc31c2
--- /dev/null
+++ b/ldap/servers/plugins/roles/roles_cache.c
@@ -0,0 +1,2061 @@
+/** 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 <string.h>
+#include <sys/types.h>
+#include "portable.h"
+#include "slapi-plugin.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+
+/* This is naughty ... */
+#include "slapi-private.h"
+
+/* include NSPR header files */
+#include "slap.h"
+#include "prthread.h"
+#include "prlock.h"
+#include "prerror.h"
+#include "prcvar.h"
+#include "prio.h"
+#include "avl.h"
+#include "vattr_spi.h"
+#include "roles_cache.h"
+#include "views.h"
+
+#ifdef SOLARIS
+#include <tnf/probe.h>
+#else
+#define TNF_PROBE_0(a,b,c)
+#endif
+
+#define MAX_NESTED_ROLES 30
+
+static char *allUserAttributes[] = {
+ LDAP_ALL_USER_ATTRS,
+ NULL
+};
+
+/* views scoping */
+static void **views_api;
+
+/* Service provider handler */
+static vattr_sp_handle *vattr_handle = NULL;
+
+/* List of nested roles */
+typedef struct _role_object_nested {
+ Slapi_DN *dn; /* value of attribute nsroledn in a nested role definition */
+} role_object_nested;
+
+/* Role object structure */
+typedef struct _role_object {
+ Slapi_DN *dn; /* dn of a role entry */
+ int type; /* ROLE_TYPE_MANAGED|ROLE_TYPE_FILTERED|ROLE_TYPE_NESTED */
+ Slapi_Filter *filter; /* if ROLE_TYPE_FILTERED */
+ Avlnode *avl_tree; /* if ROLE_TYPE_NESTED: tree of nested DNs (avl_data is a role_object_nested struct) */
+} role_object;
+
+/* Structure containing the roles definitions for a given suffix */
+typedef struct _roles_cache_def {
+
+ /* Suffix DN*/
+ Slapi_DN *suffix_dn;
+
+ /* Module level thread control */
+ PRThread *roles_tid;
+ int keeprunning;
+
+ Slapi_Mutex *cache_lock;
+ Slapi_Mutex *stop_lock;
+
+ Slapi_Mutex *change_lock;
+ Slapi_CondVar *something_changed;
+
+ Slapi_Mutex *create_lock;
+ Slapi_CondVar *suffix_created;
+ int is_ready;
+
+ /* Root of the avl tree containing all the roles definitions
+ NB: avl_data field is of type role_object
+ */
+ Avlnode *avl_tree;
+
+ /* Next roles suffix definitions */
+ struct _roles_cache_def *next;
+
+ /* Info passed from the server when an notification is sent to the plugin */
+ char *notified_dn;
+ Slapi_Entry *notified_entry;
+ int notified_operation;
+
+} roles_cache_def;
+
+
+/* Global list containing all the roles definitions per suffix */
+static roles_cache_def *roles_list = NULL;
+
+static PRRWLock *global_lock = NULL;
+
+/* Structure holding the nsrole values */
+typedef struct _roles_cache_build_result
+{
+ Slapi_ValueSet **nsrole_values; /* nsrole computed values */
+ Slapi_Entry *requested_entry; /* entry to get nsrole from */
+ int has_value; /* flag to determine if a new value has been added to the result */
+ int need_value; /* flag to determine if we need the result */
+} roles_cache_build_result;
+
+/* Structure used to check if is_entry_member_of is part of a role defined in its suffix */
+typedef struct _roles_cache_search_in_nested
+{
+ Slapi_Entry *is_entry_member_of;
+ int present; /* flag to know if the entry is part of a role */
+ int hint; /* to check the depth of the nested */
+} roles_cache_search_in_nested;
+
+/* Structure used to handle roles searches */
+typedef struct _roles_cache_search_roles
+{
+ roles_cache_def *suffix_def;
+ int rc; /* to check the depth of the nested */
+} roles_cache_search_roles;
+
+static roles_cache_def* roles_cache_create_suffix(Slapi_DN *sdn);
+static int roles_cache_add_roles_from_suffix(Slapi_DN *suffix_dn, roles_cache_def *suffix_def);
+static void roles_cache_wait_on_change(void * arg);
+static void roles_cache_trigger_update_suffix(void *handle, char *be_name, int old_be_state, int new_be_state);
+static void roles_cache_trigger_update_role(char *dn, Slapi_Entry *role_entry, Slapi_DN *be_dn, int operation);
+static int roles_cache_update(roles_cache_def *suffix_to_update);
+static int roles_get_roles_from_entry(Slapi_DN * suffix, Slapi_PBlock **int_search_pb);
+static int roles_cache_create_role_under(roles_cache_def** roles_cache_suffix, Slapi_Entry *entry);
+static int roles_cache_create_object_from_entry(Slapi_Entry *role_entry, role_object **result, int hint);
+static int roles_cache_determine_class(Slapi_Entry *role_entry);
+static int roles_cache_node_cmp( caddr_t d1, caddr_t d2 );
+static int roles_cache_insert_object(Avlnode **tree, role_object *object);
+static int roles_cache_node_nested_cmp( caddr_t d1, caddr_t d2 );
+static int roles_cache_insert_object_nested(Avlnode **tree, role_object_nested *object);
+static int roles_cache_object_nested_from_dn(Slapi_DN *role_dn, role_object_nested **result);
+static int roles_cache_build_nsrole( caddr_t data, caddr_t arg );
+static int roles_cache_find_node( caddr_t d1, caddr_t d2 );
+static int roles_cache_find_roles_in_suffix(Slapi_DN *target_entry_dn, roles_cache_def **list_of_roles);
+static int roles_is_entry_member_of_object(caddr_t data, caddr_t arg );
+static int roles_check_managed(Slapi_Entry *entry_to_check, role_object *role, int *present);
+static int roles_check_filtered(Slapi_Entry *entry_to_check, role_object *role, int *present);
+static int roles_check_nested(caddr_t data, caddr_t arg);
+static int roles_is_inscope(Slapi_Entry *entry_to_check, Slapi_DN *role_dn);
+static void berval_set_string(struct berval *bv, const char* string);
+static void roles_cache_role_def_delete(roles_cache_def *role_def);
+static void roles_cache_role_def_free(roles_cache_def *role_def);
+static void roles_cache_role_object_free(role_object *this_role);
+static void roles_cache_role_object_nested_free(role_object_nested *this_role);
+static int roles_cache_dump( caddr_t data, caddr_t arg );
+static int roles_cache_add_entry_cb(Slapi_Entry* e, void *callback_data);
+static void roles_cache_result_cb( int rc, void *callback_data);
+static Slapi_DN* roles_cache_get_top_suffix(Slapi_DN *suffix);
+
+/* ============== FUNCTIONS ================ */
+
+/* roles_cache_init
+ ----------------
+ create the cache for all the existing suffixes
+ starts up the threads which wait for changes
+ also registers vattr callbacks
+
+ return 0 if OK
+ return -1 otherwise
+*/
+int roles_cache_init()
+{
+ int rc = 0;
+ void *node = NULL;
+ Slapi_DN *sdn = NULL;
+ roles_cache_def *new_suffix = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_init\n");
+
+ if ( global_lock == NULL )
+ {
+ global_lock = PR_NewRWLock(0,"roles_cache");
+ }
+
+ /* grab the views interface */
+ if(slapi_apib_get_interface(Views_v1_0_GUID, &views_api))
+ {
+ /* lets be tolerant if views is disabled */
+ views_api = 0;
+ }
+
+ /* For each top suffix, get the roles definitions defined below it */
+ PR_RWLock_Wlock(global_lock);
+
+ sdn = slapi_get_first_suffix(&node, 0);
+ while (sdn)
+ {
+
+ if ( (new_suffix = roles_cache_create_suffix(sdn)) == NULL )
+ {
+ PR_DestroyRWLock(global_lock);
+ global_lock = NULL;
+ return(-1);
+ }
+
+ if ( roles_cache_add_roles_from_suffix(sdn, new_suffix) != 0 )
+ {
+ /* No roles in that suffix, stop the thread and remove it ? */
+ }
+ sdn = slapi_get_next_suffix(&node, 0);
+ }
+ PR_RWLock_Unlock(global_lock);
+
+ /* to expose roles_check to ACL plugin */
+ slapi_register_role_check(roles_check);
+
+ /* Register a callback on backends creation|modification|deletion,
+ so that we update the corresponding cache */
+ slapi_register_backend_state_change(NULL, roles_cache_trigger_update_suffix);
+
+ if ( slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
+ roles_sp_get_value,
+ roles_sp_compare_value,
+ roles_sp_list_types) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_init: slapi_vattrspi_register failed\n");
+
+ PR_DestroyRWLock(global_lock);
+ global_lock = NULL;
+ return(-1);
+ }
+ else if ( slapi_vattrspi_regattr(vattr_handle,NSROLEATTR,"", NULL) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_init: slapi_vattrspi_regattr failed\n");
+ free(vattr_handle);
+ PR_DestroyRWLock(global_lock);
+ global_lock = NULL;
+ return(-1);
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_init\n");
+ return rc;
+}
+
+/* roles_cache_create_suffix
+ -------------------------
+ Create a new entry in the global list
+ return a pointer on the suffix stucture: OK
+ return NULL: fail
+ */
+static roles_cache_def *roles_cache_create_suffix(Slapi_DN *sdn)
+{
+ roles_cache_def *current_suffix = NULL;
+ roles_cache_def *new_suffix = NULL;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_create_suffix\n");
+
+ /* Allocate a new suffix block */
+ new_suffix = (roles_cache_def*)slapi_ch_calloc(1, sizeof(roles_cache_def));
+ if ( new_suffix == NULL )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: Unable to allocate memory, cannot create role cache\n");
+ return(NULL);
+ }
+
+ new_suffix->cache_lock = slapi_new_mutex();
+ new_suffix->change_lock = slapi_new_mutex();
+ new_suffix->stop_lock = slapi_new_mutex();
+ new_suffix->create_lock = slapi_new_mutex();
+ if ( new_suffix->stop_lock == NULL ||
+ new_suffix->change_lock == NULL ||
+ new_suffix->cache_lock == NULL ||
+ new_suffix->create_lock == NULL )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: Lock creation failed\n");
+ roles_cache_role_def_free(new_suffix);
+ return(NULL);
+ }
+
+ new_suffix->something_changed = slapi_new_condvar(new_suffix->change_lock);
+ if ( new_suffix->something_changed == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: Lock creation failed\n");
+ roles_cache_role_def_free(new_suffix);
+ return(NULL);
+ }
+
+ new_suffix->suffix_created = slapi_new_condvar(new_suffix->create_lock);
+ if ( new_suffix->suffix_created == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: Lock creation failed\n");
+ roles_cache_role_def_free(new_suffix);
+ return(NULL);
+ }
+
+ new_suffix->keeprunning = 1;
+
+ new_suffix->suffix_dn = slapi_sdn_dup(sdn);
+
+ /* those 3 items are used to give back info to the thread when
+ it is awakened */
+ new_suffix->notified_dn = NULL;
+ new_suffix->notified_entry = NULL;
+ new_suffix->notified_operation = 0;
+
+ /* Create the global list */
+ if ( roles_list == NULL )
+ {
+ roles_list = new_suffix;
+ }
+ else
+ {
+ current_suffix = roles_list;
+ while ( current_suffix != NULL )
+ {
+ if ( current_suffix->next == NULL )
+ {
+ current_suffix->next = new_suffix;
+ break;
+ }
+ else
+ {
+ current_suffix = current_suffix->next;
+ }
+ }
+ }
+
+ /* to prevent deadlock */
+ new_suffix->is_ready = 0;
+ if ( (new_suffix->roles_tid = PR_CreateThread (PR_USER_THREAD,
+ roles_cache_wait_on_change,
+ (void*)new_suffix,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_suffix: PR_CreateThread failed\n");
+ roles_cache_role_def_delete(new_suffix);
+ return(NULL);
+ }
+
+ slapi_lock_mutex(new_suffix->create_lock);
+ if (new_suffix->is_ready != 1)
+ {
+ slapi_wait_condvar(new_suffix->suffix_created, NULL);
+ }
+ slapi_unlock_mutex(new_suffix->create_lock);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_create_suffix\n");
+ return(new_suffix);
+}
+
+/* roles_cache_wait_on_change
+ --------------------------
+ Sit around waiting on a notification that something has
+ changed, then fires off the updates
+ */
+static void roles_cache_wait_on_change(void * arg)
+{
+ roles_cache_def *roles_def = (roles_cache_def*)arg;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_wait_on_change\n");
+
+ slapi_lock_mutex(roles_def->stop_lock);
+ slapi_lock_mutex(roles_def->change_lock);
+
+ while ( roles_def->keeprunning)
+ {
+ slapi_unlock_mutex(roles_def->change_lock);
+ slapi_lock_mutex(roles_def->change_lock);
+
+ /* means that the thread corresponding to that suffix is ready to receive notifications
+ from the server */
+ slapi_lock_mutex(roles_def->create_lock);
+ if ( roles_def->is_ready == 0 )
+ {
+ slapi_notify_condvar( roles_def->suffix_created, 1 );
+ roles_def->is_ready = 1;
+ }
+ slapi_unlock_mutex(roles_def->create_lock);
+
+ /* XXX In case the BE containing this role_def signaled
+ a shut down between the unlock/lock above should
+ test roles_def->keeprunning before
+ going to sleep.
+ */
+ slapi_wait_condvar(roles_def->something_changed, NULL);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "roles_cache_wait_on_change \n");
+
+ if ( roles_def->keeprunning )
+ {
+ roles_cache_update(roles_def);
+ }
+ }
+
+ /* shut down the cache */
+ slapi_unlock_mutex(roles_def->change_lock);
+ slapi_unlock_mutex(roles_def->stop_lock);
+
+ roles_cache_role_def_free(roles_def);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_wait_on_change thread exit\n");
+}
+
+/* roles_cache_trigger_update_suffix
+ --------------------------------
+ This is called when a backend changes state (created|modified|deleted)
+ We simply signal to update the associated role cache in this case
+ */
+static void roles_cache_trigger_update_suffix(void *handle, char *be_name, int old_be_state, int new_be_state)
+{
+ roles_cache_def *current_role = roles_list;
+ const Slapi_DN *be_suffix_dn = NULL;
+ Slapi_DN *top_suffix_dn = NULL;
+ Slapi_Backend *backend = NULL;
+ int found = 0;
+
+ PR_RWLock_Wlock(global_lock);
+
+ if ( (new_be_state == SLAPI_BE_STATE_DELETE) || (new_be_state == SLAPI_BE_STATE_OFFLINE) )
+ {
+ /* Invalidate and rebuild the whole cache */
+ roles_cache_def *current_role = NULL;
+ roles_cache_def *next_role = NULL;
+ Slapi_DN *sdn = NULL;
+ void *node = NULL;
+ roles_cache_def *new_suffix = NULL;
+
+ /* Go through all the roles list and trigger the associated structure */
+ current_role = roles_list;
+ while ( current_role )
+ {
+ slapi_lock_mutex(current_role->change_lock);
+ current_role->keeprunning = 0;
+ next_role = current_role->next;
+ slapi_notify_condvar(current_role->something_changed, 1 );
+ slapi_unlock_mutex(current_role->change_lock);
+
+ current_role = next_role;
+ }
+
+ /* rebuild a new one */
+ roles_list = NULL;
+
+ sdn = slapi_get_first_suffix(&node, 0);
+ while (sdn)
+ {
+
+ if ( (new_suffix = roles_cache_create_suffix(sdn)) == NULL )
+ {
+ PR_RWLock_Unlock(global_lock);
+ return;
+ }
+
+ roles_cache_add_roles_from_suffix(sdn, new_suffix);
+ sdn = slapi_get_next_suffix(&node, 0);
+ }
+ PR_RWLock_Unlock(global_lock);
+ return;
+ }
+
+ /* Backend back on line or new one created*/
+ backend = slapi_be_select_by_instance_name(be_name);
+ if ( backend != NULL )
+ {
+ be_suffix_dn = slapi_be_getsuffix(backend, 0);
+ top_suffix_dn = roles_cache_get_top_suffix((Slapi_DN *)be_suffix_dn);
+ }
+
+ while ( (current_role != NULL) && !found && (top_suffix_dn != NULL) )
+ {
+ /* The backend already exists (back online): so invalidate "old roles definitions" */
+ if ( slapi_sdn_compare(current_role->suffix_dn, top_suffix_dn) == 0 )
+ {
+ roles_cache_role_def_delete(current_role);
+ found = 1;
+ }
+ else
+ {
+ current_role = current_role->next;
+ }
+ }
+
+ if ( top_suffix_dn != NULL )
+ {
+ /* Add the new definitions in the cache */
+ roles_cache_def *new_suffix = roles_cache_create_suffix(top_suffix_dn);
+
+ if ( new_suffix != NULL )
+ {
+ roles_cache_add_roles_from_suffix(top_suffix_dn, new_suffix);
+ }
+ slapi_sdn_free(&top_suffix_dn);
+ }
+
+ PR_RWLock_Unlock(global_lock);
+}
+
+/* roles_cache_trigger_update_role
+ --------------------------------
+ Call when an entry containing a role definition has been added, modified
+ or deleted
+ */
+static void roles_cache_trigger_update_role(char *dn, Slapi_Entry *roles_entry, Slapi_DN *be_dn, int operation)
+{
+ int found = 0;
+ roles_cache_def *current_role = NULL;
+
+ PR_RWLock_Wlock(global_lock);
+
+ current_role = roles_list;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_trigger_update_role: %x \n", roles_list);
+
+ /* Go through all the roles list and trigger the associated structure */
+
+ /* be_dn is already the top suffix for that dn */
+ while ( (current_role != NULL) && !found )
+ {
+ if ( slapi_sdn_compare(current_role->suffix_dn, be_dn) == 0 )
+ {
+ found = 1;
+ }
+ else
+ {
+ current_role = current_role->next;
+ }
+ }
+
+ if ( found )
+ {
+ slapi_lock_mutex(current_role->change_lock);
+
+ slapi_entry_free (current_role->notified_entry);
+ current_role->notified_entry = roles_entry;
+ slapi_ch_free ((void**)&(current_role->notified_dn));
+ current_role->notified_dn = dn;
+ current_role->notified_operation = operation;
+
+ roles_cache_update(current_role);
+
+ slapi_unlock_mutex(current_role->change_lock);
+ }
+
+ PR_RWLock_Unlock(global_lock);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_trigger_update_role: %x \n", roles_list);
+}
+
+/* roles_cache_update
+ ------------------
+ Update the cache associated to a suffix
+ Return 0: ok
+ Return -1: fail
+ */
+static int roles_cache_update(roles_cache_def *suffix_to_update)
+{
+ int rc = 0;
+ int operation;
+ Slapi_Entry *entry = NULL;
+ Slapi_DN *dn = NULL;
+ role_object *to_delete = NULL;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_update \n");
+
+ slapi_lock_mutex(suffix_to_update->cache_lock);
+
+ operation = suffix_to_update->notified_operation;
+ entry = suffix_to_update->notified_entry;
+ dn = slapi_sdn_new();
+ slapi_sdn_set_dn_byval(dn, suffix_to_update->notified_dn);
+
+ if ( (entry != NULL) && (dn != NULL) )
+ {
+ if ( (operation == SLAPI_OPERATION_MODIFY) ||
+ (operation == SLAPI_OPERATION_DELETE) )
+ {
+ /* delete it */
+ int dummy;
+
+ to_delete = (role_object *)avl_delete(&(suffix_to_update->avl_tree), dn, roles_cache_find_node, &dummy);
+ roles_cache_role_object_free(to_delete);
+ to_delete = NULL;
+ if ( slapi_is_loglevel_set(SLAPI_LOG_PLUGIN) )
+ {
+ avl_apply(suffix_to_update->avl_tree, (IFP)roles_cache_dump, &rc, -1, AVL_INORDER);
+ }
+
+ }
+ if ( (operation == SLAPI_OPERATION_MODIFY) ||
+ (operation ==SLAPI_OPERATION_ADD) )
+ {
+ rc = roles_cache_create_role_under(&suffix_to_update,entry);
+ }
+ if ( entry != NULL )
+ {
+ slapi_entry_free(entry);
+ }
+ suffix_to_update->notified_entry = NULL;
+
+ }
+ slapi_unlock_mutex(suffix_to_update->cache_lock);
+
+ if ( dn != NULL )
+ {
+ slapi_sdn_free(&dn);
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_update \n");
+ return(rc);
+}
+
+/* roles_cache_stop
+ ----------------
+
+ XXX the stop_lock of a roles_cache_def
+ doesn't seem to serve any useful purpose...
+
+ */
+void roles_cache_stop()
+{
+ roles_cache_def *current_role = NULL;
+ roles_cache_def *next_role = NULL;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_stop\n");
+
+ /* Go through all the roles list and trigger the associated structure */
+ PR_RWLock_Wlock(global_lock);
+ current_role = roles_list;
+ while ( current_role )
+ {
+ slapi_lock_mutex(current_role->change_lock);
+ current_role->keeprunning = 0;
+ next_role = current_role->next;
+ slapi_notify_condvar(current_role->something_changed, 1 );
+ slapi_unlock_mutex(current_role->change_lock);
+
+ current_role = next_role;
+ }
+ PR_RWLock_Unlock(global_lock);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_stop\n");
+}
+
+/* roles_cache_is_role_entry
+ -------------------------
+ Check if the entry is a role
+ return -1: error in processing
+ return 0: entry is not a role
+ return 1: entry is a role
+*/
+static int roles_cache_is_role_entry(struct slapi_entry *entry)
+{
+ Slapi_Attr *pObjclasses = NULL;
+ Slapi_Value *val = NULL;
+ char *pObj = NULL;
+ int index = 0;
+
+ int nsroledefinition = 0;
+ int nsrolesimpleOrComplex = 0;
+ int nsroletype = 0;
+
+ if ( entry == NULL )
+ {
+ return(0);
+ }
+
+ if ( slapi_entry_attr_find(entry, "objectclass", &pObjclasses) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_is_role_entry: failed to get objectclass from %s\n",slapi_entry_get_dn_const(entry));
+ return(-1);
+ }
+
+ /* Check out the object classes to see if this was a nsroledefinition */
+
+ val = 0;
+ index = slapi_attr_first_value( pObjclasses, &val );
+ while(val)
+ {
+ const char *p;
+ int len = 0;
+
+ pObj = (char*)slapi_value_get_string(val);
+
+ for ( p = pObj, len = 0;
+ (*p != '\0') && (*p != ' ');
+ p++, len++ )
+ {
+ ; /* NULL */
+ }
+
+ if ( !strncasecmp(pObj, (char*)"nsroledefinition", len) )
+ {
+ nsroledefinition = 1;
+ }
+ if ( !strncasecmp(pObj, (char*)"nssimpleroledefinition", len) ||
+ !strncasecmp(pObj, (char*)"nscomplexroledefinition", len) )
+ {
+ nsrolesimpleOrComplex = 1;
+ }
+ if( !strncasecmp(pObj, (char*)"nsmanagedroledefinition", len) ||
+ !strncasecmp(pObj, (char*)"nsfilteredroledefinition", len) ||
+ !strncasecmp(pObj, (char*)"nsnestedroledefinition", len)
+ )
+ {
+ nsroletype = 1;
+ }
+ index = slapi_attr_next_value( pObjclasses, index, &val );
+ }
+ if ( (nsroledefinition == 0) ||
+ (nsrolesimpleOrComplex == 0) ||
+ (nsroletype == 0) )
+ {
+ return(0);
+ }
+ return(1);
+}
+
+/* roles_cache_change_notify
+ -------------------------
+ determines if the change effects the cache and if so
+ signals a rebuild
+ -- called when modify|modrdn|add|delete operation is performed --
+ -- called from a postoperation on an entry
+ XXX this implies that the client may have already received his LDAP response,
+ but that there will be a delay before he sees the effect in the roles cache.
+ Should we be doing this processing in a BE_POST_MODIFY postop
+ which is called _before_ the response goes to the client ?
+*/
+void roles_cache_change_notify(Slapi_PBlock *pb)
+{
+ char *dn = NULL;
+ struct slapi_entry *e = NULL;
+ struct slapi_entry *pre = NULL;
+ struct slapi_entry *entry = NULL;
+ Slapi_Backend *be = NULL;
+ Slapi_Operation *pb_operation = NULL;
+ int operation;
+ int do_update = 0;
+ int rc = -1;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "--> roles_cache_change_notify\n");
+
+ /* if the current operation has failed, don't even try the post operation */
+ slapi_pblock_get( pb, SLAPI_PLUGIN_OPRETURN, &rc );
+ if ( rc != LDAP_SUCCESS )
+ {
+ return;
+ }
+
+ /* Don't update local cache when remote entries are updated */
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ if ( ( be!=NULL ) &&
+ ( slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)) )
+ {
+ return;
+ }
+
+ slapi_pblock_get(pb, SLAPI_TARGET_DN, &dn);
+ if( dn == NULL )
+ {
+ return;
+ }
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &pb_operation);
+ operation = operation_get_type(pb_operation);
+
+ switch (operation)
+ {
+ case SLAPI_OPERATION_DELETE:
+
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &e);
+ if( e == NULL )
+ {
+ return;
+ }
+ break;
+
+ case SLAPI_OPERATION_ADD:
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
+ if ( e == NULL )
+ {
+ return;
+ }
+ break;
+
+ case SLAPI_OPERATION_MODIFY:
+ case SLAPI_OPERATION_MODRDN:
+ /* those operations are treated the same way and modify is a deletion followed by an addition.
+ the only point to take care is that dn is the olddn */
+ operation = SLAPI_OPERATION_MODIFY;
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &pre);
+ if( pre == NULL )
+ {
+ return;
+ }
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &e);
+ if ( e == NULL )
+ {
+ return;
+ }
+ break;
+ default:
+ slapi_log_error( SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_change_notify: unknown operation %d\n",operation);
+ return;
+ }
+
+ if ( operation != SLAPI_OPERATION_MODIFY )
+ {
+ if ( roles_cache_is_role_entry(e) != 1 )
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_change_notify: not a role entry\n");
+ return;
+ }
+ entry = slapi_entry_dup(e);
+ do_update = 1;
+ }
+ else
+ {
+ int is_pre_role = roles_cache_is_role_entry(pre);
+ int is_post_role = roles_cache_is_role_entry(e);
+ if ( (is_pre_role==1) && (is_post_role==1) ) /* role definition has changed */
+ {
+ entry = slapi_entry_dup(e);
+ do_update = 1;
+ }
+ else if ( is_pre_role == 1 ) /* entry is no more a role */
+ {
+ operation = SLAPI_OPERATION_DELETE;
+ do_update = 1;
+ }
+ else if ( is_post_role == 1 ) /* entry is now a role */
+ {
+ operation = SLAPI_OPERATION_ADD;
+ entry = slapi_entry_dup(e);
+ do_update = 1;
+ }
+ else
+ {
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_change_notify: not a role entry\n");
+ return;
+ }
+ }
+
+ if ( do_update )
+ {
+#ifdef moretrace
+if ( e != NULL )
+{
+ Slapi_Attr *attr = NULL;
+ int rc;
+
+ /* Get the list of nested roles */
+ rc = slapi_entry_attr_find(e,ROLE_NESTED_ATTR_NAME,&attr);
+
+ if ( (rc == 0) && attr)
+ {
+ /* Recurse to get the definition objects for them */
+ Slapi_Value **va = attr_get_present_values(attr);
+ int i = 0;
+ char *string = NULL;
+
+ for ( i = 0; va[i] != NULL; i++ )
+ {
+ string = (char*)slapi_value_get_string(va[i]);
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "roles_cache_change_notify:%s\n",string);
+ }
+ }
+}
+#endif
+ Slapi_DN *top_suffix = roles_cache_get_top_suffix(*(be->be_suffix));
+
+ if ( top_suffix != NULL )
+ {
+ roles_cache_trigger_update_role( slapi_ch_strdup(dn), entry,
+ top_suffix,
+ operation);
+
+ slapi_sdn_free(&top_suffix);
+ }
+
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_change_notify\n");
+
+}
+
+/* roles_cache_get_top_suffix
+ -------------------------
+ The returned Slapi_DN must be freed with slapi_sdn_free().
+*/
+static Slapi_DN* roles_cache_get_top_suffix(Slapi_DN *suffix)
+{
+ Slapi_DN *current_suffix = NULL;
+ Slapi_DN parent_suffix;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_get_top_suffix\n");
+
+ if ( suffix == NULL )
+ {
+ return(NULL);
+ }
+ current_suffix = slapi_sdn_new();
+ slapi_sdn_init(&parent_suffix);
+
+ /* we must get the top suffix for that DN */
+ slapi_sdn_copy(suffix,current_suffix);
+ while ( !slapi_sdn_isempty(current_suffix) )
+ {
+ if ( slapi_is_root_suffix(current_suffix) != 1 )
+ {
+ slapi_sdn_get_parent(current_suffix,&parent_suffix);
+ slapi_sdn_copy(&parent_suffix, current_suffix);
+ }
+ else
+ {
+ slapi_sdn_done(&parent_suffix);
+ return(current_suffix);
+ }
+ }
+ /* we should not return that way ... */
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_get_top_suffix\n");
+ slapi_sdn_done(&parent_suffix);
+ slapi_sdn_free(&current_suffix);
+ return(NULL);
+}
+
+/* roles_cache_add_roles_from_suffix
+ -------------------------------
+ Get the roles entries under the suffix
+ return 0: OK
+ return -1: this suffix has no role defined
+ */
+static int roles_cache_add_roles_from_suffix(Slapi_DN *suffix_dn, roles_cache_def *suffix_def)
+{
+ /* Search subtree-level under this entry */
+ int rc = -1;
+ roles_cache_search_roles info;
+ Slapi_PBlock *int_search_pb = NULL;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_get_roles_from_entry\n");
+
+ info.suffix_def = suffix_def;
+ info.rc = LDAP_NO_SUCH_OBJECT;
+
+ /* Get the roles definitions of the given suffix_dn */
+ int_search_pb = slapi_pblock_new ();
+ slapi_search_internal_set_pb(int_search_pb,
+ (char*)slapi_sdn_get_ndn(suffix_dn),
+ LDAP_SCOPE_SUBTREE,
+ ROLE_DEFINITION_FILTER,
+ allUserAttributes,
+ 0 /* attrsonly */,
+ NULL /* controls */,
+ NULL /* uniqueid */,
+ roles_get_plugin_identity(),
+ SLAPI_OP_FLAG_NEVER_CHAIN /* actions : get local roles only */ );
+
+ slapi_search_internal_callback_pb(int_search_pb,
+ &info /* callback_data */,
+ roles_cache_result_cb,
+ roles_cache_add_entry_cb,
+ NULL /* referral_callback */);
+
+ slapi_pblock_destroy (int_search_pb);
+ int_search_pb = NULL;
+
+ if ( info.rc == LDAP_SUCCESS )
+ {
+ rc = 0;
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_get_roles_from_entry\n");
+
+ return(rc);
+}
+
+/* roles_cache_add_entry_cb
+ -----------------------
+*/
+static int roles_cache_add_entry_cb(Slapi_Entry* e, void *callback_data)
+{
+ roles_cache_search_roles *info=(roles_cache_search_roles *)callback_data;
+
+ roles_cache_def *suffix = info->suffix_def;
+
+ roles_cache_create_role_under(&suffix, e);
+ return(0);
+}
+
+/* roles_cache_result_cb
+ -----------------------
+*/
+static void roles_cache_result_cb( int rc, void *callback_data) {
+ roles_cache_search_roles *info=(roles_cache_search_roles *)callback_data;
+
+ info->rc = rc;
+}
+
+
+/* roles_cache_create_role_under
+ ----------------------------
+ Create the avl tree of roles definitions defined in the scope
+ of the suffix
+ Return 0: OK
+ Return -1: fail
+*/
+static int roles_cache_create_role_under(roles_cache_def** roles_cache_suffix, Slapi_Entry *entry)
+{
+ int rc;
+ role_object *new_role = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_create_role_under: %s - %x\n",
+ slapi_sdn_get_dn((*roles_cache_suffix)->suffix_dn),
+ (*roles_cache_suffix)->avl_tree);
+
+ rc = roles_cache_create_object_from_entry(entry,&new_role,0);
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_create_role_under: create node for entry %s - rc: %d SUFFIX: %x\n",
+ slapi_entry_get_dn_const(entry), rc, (*roles_cache_suffix)->avl_tree);
+
+ if ( (rc == 0) && new_role)
+ {
+ /* Add to the tree where avl_data is a role_object struct */
+ rc = roles_cache_insert_object(&((*roles_cache_suffix)->avl_tree),new_role);
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_create_role_under:%s in tree %x rc: %d\n",
+ (char*)slapi_sdn_get_ndn(new_role->dn),
+ (*roles_cache_suffix)->avl_tree, rc);
+ }
+ return(rc);
+}
+
+
+/* roles_cache_create_object_from_entry
+ ------------------------------------
+ Create a node role_object from the information contained in role_entry
+ Return 0
+ Return ENOMEM: fail
+ Return SLAPI_ROLE_DEFINITION_ERROR: fail
+ Return SLAPI_ROLE_ERROR_NO_FILTER_SPECIFIED: fail
+ Return SLAPI_ROLE_ERROR_FILTER_BAD: fail
+*/
+static int roles_cache_create_object_from_entry(Slapi_Entry *role_entry, role_object **result, int hint)
+{
+ int rc = 0;
+ int type = 0;
+ role_object *this_role = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "--> roles_cache_create_object_from_entry\n");
+
+ *result = NULL;
+
+ /* Do not allow circular dependencies */
+ if ( hint > MAX_NESTED_ROLES )
+ {
+ char *ndn = NULL;
+
+ ndn = slapi_entry_get_ndn( role_entry );
+ slapi_log_error(
+ SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "Maximum roles nesting exceeded (%d), not retrieving roles from entry %s--probable circular definition\n",
+ MAX_NESTED_ROLES,
+ ndn);
+
+ return (0);
+ }
+
+ /* Create the role cache definition */
+ this_role = (role_object*)slapi_ch_calloc(1, sizeof(role_object));
+ if (this_role == NULL )
+ {
+ return ENOMEM;
+ }
+
+ /* Check the entry is OK */
+ /* Determine role type and assign to structure */
+ /* We determine the role type by reading the objectclass */
+ if ( roles_cache_is_role_entry(role_entry) == 0 )
+ {
+ /* Bad type */
+ slapi_ch_free((void**)&this_role);
+ return SLAPI_ROLE_DEFINITION_ERROR;
+ }
+
+ type = roles_cache_determine_class(role_entry);
+
+ if (type != 0)
+ {
+ this_role->type = type;
+ }
+ else
+ {
+ /* Bad type */
+ slapi_ch_free((void**)&this_role);
+ return SLAPI_ROLE_DEFINITION_ERROR;
+ }
+
+ this_role->dn = slapi_sdn_new();
+ slapi_sdn_copy(slapi_entry_get_sdn(role_entry),this_role->dn);
+
+ /* Depending upon role type, pull out the remaining information we need */
+ switch (this_role->type)
+ {
+ case ROLE_TYPE_MANAGED:
+
+ /* Nothing further needed */
+ break;
+
+ case ROLE_TYPE_FILTERED:
+ {
+
+ Slapi_Filter *filter = NULL;
+ char *filter_attr_value = NULL;
+
+ /* Get the filter and retrieve the filter attribute */
+ filter_attr_value = slapi_entry_attr_get_charptr(role_entry,ROLE_FILTER_ATTR_NAME);
+ if ( filter_attr_value == NULL )
+ {
+ /* Means probably no attribute or no value there */
+ slapi_ch_free((void**)&this_role);
+ return SLAPI_ROLE_ERROR_NO_FILTER_SPECIFIED;
+ }
+
+ /* Turn it into a slapi filter object */
+ filter = slapi_str2filter(filter_attr_value);
+ slapi_ch_free((void**)&filter_attr_value);
+
+ if ( filter == NULL )
+ {
+ /* An error has occured */
+ slapi_ch_free((void**)&this_role);
+ return SLAPI_ROLE_ERROR_FILTER_BAD;
+ }
+ /* Store on the object */
+ this_role->filter = filter;
+
+ break;
+ }
+
+ case ROLE_TYPE_NESTED:
+ {
+ Slapi_Attr *attr = NULL;
+
+ /* Get the list of nested roles */
+ rc = slapi_entry_attr_find(role_entry,ROLE_NESTED_ATTR_NAME,&attr);
+
+ if ( (rc == 0) && attr)
+ {
+ /* Recurse to get the definition objects for them */
+ Slapi_Value **va = attr_get_present_values(attr);
+ int i = 0;
+ char *string = NULL;
+ Slapi_DN nested_role_dn;
+ role_object_nested *nested_role_object = NULL;
+
+ for ( i = 0; va[i] != NULL; i++ )
+ {
+ string = (char*)slapi_value_get_string(va[i]);
+
+ /* Make a DN from the string */
+ slapi_sdn_init_dn_byref(&nested_role_dn,string);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_create_object_from_entry: dn %s, nested %s\n",
+ (char*)slapi_sdn_get_ndn(this_role->dn),string);
+
+ /* Make a role object nested from the DN */
+ rc = roles_cache_object_nested_from_dn(&nested_role_dn,&nested_role_object);
+
+ /* Insert it into the nested list */
+ if ( (rc == 0) && nested_role_object)
+ {
+ /* Add to the tree where avl_data is a role_object_nested struct */
+ rc = roles_cache_insert_object_nested(&(this_role->avl_tree),nested_role_object);
+ }
+ slapi_sdn_done(&nested_role_dn);
+ }
+ }
+
+ break;
+ }
+
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM, "wrong role type\n");
+ }
+
+ if ( rc == 0 )
+ {
+ *result = this_role;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_cache_create_object_from_entry\n");
+
+
+ return rc;
+}
+
+/* roles_cache_determine_class:
+ ----------------------------
+ Determine the type of role depending on the objectclass
+ Return the type of the role
+ */
+static int roles_cache_determine_class(Slapi_Entry *role_entry)
+{
+ /* Examine the entry's objectclass attribute */
+ int found_managed = 0;
+ int found_filtered = 0;
+ int found_nested = 0;
+ Slapi_Attr *attr= NULL;
+ struct berval bv = {0};
+ int rc = 0;
+ int type = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "--> roles_cache_determine_class\n");
+
+ rc = slapi_entry_attr_find(role_entry,"objectclass",&attr);
+ if ( rc != 0 )
+ {
+ /* No objectclass, definitely an error */
+ return 0;
+ }
+
+ berval_set_string(&bv,ROLE_OBJECTCLASS_MANAGED);
+ rc = slapi_attr_value_find(attr,&bv);
+ if ( rc == 0 )
+ {
+ found_managed = 1;
+ type = ROLE_TYPE_MANAGED;
+ }
+
+ berval_set_string(&bv,ROLE_OBJECTCLASS_FILTERED);
+ rc = slapi_attr_value_find(attr,&bv);
+ if ( rc == 0 )
+ {
+ found_filtered = 1;
+ type = ROLE_TYPE_FILTERED;
+ }
+
+ berval_set_string(&bv,ROLE_OBJECTCLASS_NESTED);
+ rc = slapi_attr_value_find(attr,&bv);
+ if ( rc == 0 )
+ {
+ found_nested = 1;
+ type = ROLE_TYPE_NESTED;
+ }
+
+ if ( (found_managed + found_nested + found_filtered) > 1 )
+ {
+ /* Means some goofball configured a role definition which is trying to be more than one different type. error. */
+ return 0;
+ }
+
+ if ( (found_managed + found_nested + found_filtered) == 0)
+ {
+ /* Means this entry isn't any of the role types we handle. error. */
+ return 0;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_cache_determine_class\n");
+
+ /* Return the appropriate type ordinal */
+ return type;
+}
+
+/* roles_cache_node_cmp:
+ ---------------------
+ Comparison function to add a new node in the avl tree (avl_data is of type role_object)
+ */
+static int roles_cache_node_cmp( caddr_t d1, caddr_t d2 )
+{
+ role_object *role_to_insert = (role_object*)d1;
+ role_object *current_role = (role_object*)d2;
+
+ /* role_to_insert and current_role are never NULL in that context */
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_node_cmp\n");
+
+ return (slapi_sdn_compare((Slapi_DN *)role_to_insert->dn, (Slapi_DN *)current_role->dn));
+}
+
+/* roles_cache_insert_object:
+ --------------------------
+ Insert a new node in the avl tree of a specific suffix
+ */
+static int roles_cache_insert_object(Avlnode **tree, role_object *object)
+{
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_insert_object: %s in tree %x\n",
+ (char*)slapi_sdn_get_ndn(object->dn),
+ *tree);
+ return (avl_insert(tree, (caddr_t)object, roles_cache_node_cmp, avl_dup_error));
+}
+
+/* roles_cache_node_nested_cmp:
+ ----------------------------
+ Comparison function to add a new node in the avl tree
+ */
+static int roles_cache_node_nested_cmp( caddr_t d1, caddr_t d2 )
+{
+ role_object_nested *role_to_insert = (role_object_nested*)d1;
+ role_object_nested *current_role = (role_object_nested*)d2;
+
+ /* role_to_insert and current_role are never NULL in that context */
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_cache_node_nested_cmp\n");
+
+ return slapi_sdn_compare(role_to_insert->dn, current_role->dn);
+}
+
+/* roles_cache_insert_object_nested:
+ ---------------------------------
+ Insert a new node in the avl tree of a specific suffix
+ */
+static int roles_cache_insert_object_nested(Avlnode **tree, role_object_nested *object)
+{
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_insert_object_nested: %s in tree %x: \n",
+ (char*)slapi_sdn_get_ndn(object->dn), *tree);
+
+ return (avl_insert(tree, (caddr_t)object, roles_cache_node_nested_cmp, avl_dup_error));
+}
+
+/* roles_cache_object_nested_from_dn
+ ----------------------------------
+ Get the role associated to an entry DN
+ Return 0: OK
+ Return ENOMEM: fail
+ */
+static int roles_cache_object_nested_from_dn(Slapi_DN *role_dn, role_object_nested **result)
+{
+ role_object_nested *nested_role = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "--> roles_cache_object_nested_from_dn\n");
+
+ *result = NULL;
+
+ /* Create the role cache definition */
+ nested_role = (role_object_nested*)slapi_ch_calloc(1, sizeof(role_object_nested));
+ if (nested_role == NULL )
+ {
+ return ENOMEM;
+ }
+
+ nested_role->dn = slapi_sdn_new();
+ slapi_sdn_copy(role_dn,nested_role->dn);
+ *result = nested_role;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_cache_object_nested_from_dn\n");
+ return 0;
+}
+
+/* roles_cache_listroles
+ --------------------
+ Lists all the roles an entry posesses
+ return_values = 0 means that we don't need the nsrole values
+ return_values = 1 means that we need the nsrole values
+ Return 0: the entry has nsrole
+ Return -1: the entry has no nsrole
+ */
+int roles_cache_listroles(Slapi_Entry *entry, int return_values, Slapi_ValueSet **valueset_out)
+{
+ roles_cache_def *roles_cache = NULL;
+ role_object *this_role = NULL;
+ int rc = 0;
+ Avlnode * tree = NULL;
+ roles_cache_build_result arg;
+ Slapi_Backend *backend = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_listroles\n");
+
+ backend = slapi_mapping_tree_find_backend_for_sdn(slapi_entry_get_sdn(entry));
+ if ( (backend != NULL) && slapi_be_is_flag_set(backend,SLAPI_BE_FLAG_REMOTE_DATA) )
+ {
+ /* the entry is not local, so don't return anything */
+ return (-1);
+ }
+
+ if ( return_values )
+ {
+ *valueset_out = (Slapi_ValueSet*)slapi_ch_calloc(1,sizeof(Slapi_ValueSet));
+ slapi_valueset_init(*valueset_out);
+ }
+
+ /* First get a list of all the in-scope roles */
+ /* XXX really need a mutex for this read operation ? */
+ PR_RWLock_Rlock(global_lock);
+
+ rc = roles_cache_find_roles_in_suffix( slapi_entry_get_sdn(entry),&roles_cache);
+
+ PR_RWLock_Unlock(global_lock);
+
+ /* Traverse the tree checking if the entry has any of the roles */
+ if ( roles_cache != NULL )
+ {
+ if ( roles_cache->avl_tree )
+ {
+ arg.nsrole_values = valueset_out;
+ arg.need_value = return_values;
+ arg.requested_entry = entry;
+ arg.has_value = 0;
+
+ /* XXX really need a mutex for this read operation ? */
+ slapi_lock_mutex(roles_cache->cache_lock);
+
+ avl_apply(roles_cache->avl_tree, (IFP)roles_cache_build_nsrole, &arg, -1, AVL_INORDER);
+
+ slapi_unlock_mutex(roles_cache->cache_lock);
+
+ if( !arg.has_value )
+ {
+ if ( return_values )
+ {
+ slapi_valueset_free(*valueset_out);
+ *valueset_out = NULL;
+ }
+ rc = -1;
+ }
+ /* Free the list (we already did that) */
+ }
+ else
+ {
+ if ( return_values )
+ {
+ slapi_valueset_free(*valueset_out);
+ *valueset_out = NULL;
+ }
+ rc = -1;
+ }
+ }
+ else
+ {
+ /* no roles associated */
+ rc = -1;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_listroles\n");
+ return rc;
+}
+
+/* roles_cache_build_nsrole
+ ------------------------
+ Traverse the tree containing roles definitions for a suffix and for each
+ one of them, check wether the entry is a member of it or not
+ For ones which check out positive, we add their DN to the value
+ always return 0 to allow to trverse all the tree
+ */
+static int roles_cache_build_nsrole( caddr_t data, caddr_t arg )
+{
+ Slapi_Value *value = NULL;
+ roles_cache_build_result *result = (roles_cache_build_result*)arg;
+ role_object *this_role = (role_object*)data;
+ roles_cache_search_in_nested get_nsrole;
+ /* Return a value different from the stop flag to be able
+ to go through all the tree */
+ int rc = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_build_nsrole: role %s\n",
+ (char*) slapi_sdn_get_ndn(this_role->dn));
+
+ value = slapi_value_new_string("");
+
+ get_nsrole.is_entry_member_of = result->requested_entry;
+ get_nsrole.present = 0;
+ get_nsrole.hint = 0;
+
+ roles_is_entry_member_of_object((caddr_t)this_role, (caddr_t)&get_nsrole);
+
+ /* If so, add its DN to the attribute */
+ if (get_nsrole.present)
+ {
+ result->has_value = 1;
+ if ( result->need_value )
+ {
+ slapi_value_set_string(value,(char*) slapi_sdn_get_ndn(this_role->dn));
+ slapi_valueset_add_value(*(result->nsrole_values),value);
+ }
+ else
+ {
+ /* we don't need the value but we already know there is one nsrole.
+ stop the traversal
+ */
+ rc = -1;
+ }
+ }
+
+ slapi_value_free(&value);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_build_nsrole\n");
+
+ return rc;
+}
+
+
+/* roles_check
+ -----------
+ Checks if an entry has a presented role, assuming that we've already verified
+that
+ the role both exists and is in scope
+ return 0: no processing error
+ return -1: error
+ */
+int roles_check(Slapi_Entry *entry_to_check, Slapi_DN *role_dn, int *present)
+{
+ roles_cache_def *roles_cache = NULL;
+ role_object *this_role = NULL;
+ roles_cache_search_in_nested get_nsrole;
+
+ int rc = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_check\n");
+
+ *present = 0;
+
+ PR_RWLock_Rlock(global_lock);
+
+ if ( roles_cache_find_roles_in_suffix(slapi_entry_get_sdn(entry_to_check),
+ &roles_cache) != 0 )
+ {
+ PR_RWLock_Unlock(global_lock);
+ return -1;
+ }
+ PR_RWLock_Unlock(global_lock);
+
+ this_role = (role_object *)avl_find(roles_cache->avl_tree, role_dn, (IFP)roles_cache_find_node);
+
+ /* MAB: For some reason the assumption made by this function (the role exists and is in scope)
+ * does not seem to be true... this_role might be NULL after the avl_find call (is the avl_tree
+ * broken? Anyway, this is crashing the 5.1 server on 29-Aug-01, so I am applying the following patch
+ * to avoid the crash inside roles_is_entry_member_of_object */
+ /* Begin patch */
+ if (!this_role) {
+ /* Assume that the entry is not member of the role (*present=0) and leave... */
+ return rc;
+ }
+ /* End patch */
+
+ get_nsrole.is_entry_member_of = entry_to_check;
+ get_nsrole.present = 0;
+ get_nsrole.hint = 0;
+
+ roles_is_entry_member_of_object((caddr_t)this_role, (caddr_t)&get_nsrole);
+ *present = get_nsrole.present;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_check\n");
+
+ return rc;
+}
+
+/* roles_cache_find_node:
+ ---------------------
+ Comparison function to add a new node in the avl tree
+ */
+static int roles_cache_find_node( caddr_t d1, caddr_t d2 )
+{
+ Slapi_DN *data = (Slapi_DN *)d1;
+ role_object *role= (role_object *)d2;
+
+ /* role is not NULL in that context */
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_find_node: %s %s\n",
+ slapi_sdn_get_dn(data), slapi_sdn_get_dn(role->dn));
+
+ return (slapi_sdn_compare(data, (Slapi_DN *)role->dn));
+}
+
+/* roles_cache_find_roles_in_suffix
+ -------------------------------
+ Find all the roles in scope to an entry
+ */
+static int roles_cache_find_roles_in_suffix(Slapi_DN *target_entry_dn, roles_cache_def **list_of_roles)
+{
+ int rc = -1;
+ Slapi_Backend *backend = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_find_roles_in_suffix\n");
+
+ *list_of_roles = NULL;
+ backend = slapi_mapping_tree_find_backend_for_sdn(target_entry_dn);
+ if ( (backend != NULL) && !slapi_be_is_flag_set(backend,SLAPI_BE_FLAG_REMOTE_DATA) )
+ {
+ Slapi_DN *suffix = roles_cache_get_top_suffix(*(backend->be_suffix));
+ roles_cache_def *current_role = roles_list;
+
+ /* Go through all the roles list and trigger the associated structure */
+ while ( (current_role != NULL) && (suffix != NULL) )
+ {
+ if ( slapi_sdn_compare(current_role->suffix_dn, suffix) == 0 )
+ {
+ *list_of_roles = current_role;
+ /* OK, we have found one */
+ slapi_sdn_free(&suffix);
+ return 0;
+ }
+ else
+ {
+ current_role = current_role->next;
+ }
+ }
+ if ( suffix != NULL )
+ {
+ slapi_sdn_free(&suffix);
+ }
+ /* If we got out that way, means that we didn't have find
+ roles definitions for that suffix */
+ return rc;
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_find_roles_in_suffix\n");
+ return rc;
+}
+
+/* roles_is_entry_member_of_object
+ --------------------------------
+ Check if the entry is part of a role defined in its suffix
+ return 0: ok
+ return 1: fail
+ -> to check the presence, see present
+ */
+static int roles_is_entry_member_of_object(caddr_t data, caddr_t argument )
+{
+ int rc = -1;
+
+ roles_cache_search_in_nested *get_nsrole = (roles_cache_search_in_nested*)argument;
+ role_object *this_role = (role_object*)data;
+
+ Slapi_Entry *entry_to_check = get_nsrole->is_entry_member_of;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_is_entry_member_of_object\n");
+
+ if (!roles_is_inscope(entry_to_check, this_role->dn))
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_is_entry_member_of_object-> entry not in scope of role\n");
+ return rc;
+ }
+
+ if ( this_role != NULL )
+ {
+ /* Determine the role type */
+ switch (this_role->type)
+ {
+ case ROLE_TYPE_MANAGED:
+ rc = roles_check_managed(entry_to_check,this_role,&get_nsrole->present);
+ break;
+ case ROLE_TYPE_FILTERED:
+ rc = roles_check_filtered(entry_to_check,this_role,&get_nsrole->present);
+ break;
+ case ROLE_TYPE_NESTED:
+ {
+ /* Go through the tree of the nested DNs */
+ get_nsrole->hint++;
+ avl_apply(this_role->avl_tree, (IFP)roles_check_nested, get_nsrole, 0, AVL_INORDER);
+ get_nsrole->hint--;
+
+ /* kexcoff?? */
+ rc = get_nsrole->present;
+ break;
+ }
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_is_entry_member_of_object-> invalid role type\n");
+ }
+ }
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_is_entry_member_of_object\n");
+ return rc;
+}
+
+/* roles_check_managed
+ -------------------------
+ Check a managed role: we just need to check the content of the entry's nsRoleDN attribute
+ against the role DN
+ return 0: ok
+ return 1: fail
+ -> to check the presence, see present
+ */
+static int roles_check_managed(Slapi_Entry *entry_to_check, role_object *role, int *present)
+{
+ int rc = 0;
+ Slapi_Attr *attr = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_check_managed\n");
+ /* Get the attribute */
+ rc = slapi_entry_attr_find(entry_to_check,ROLE_MANAGED_ATTR_NAME,&attr);
+
+ if ( rc == 0)
+ {
+ struct berval bv = {0};
+ char *dn_string = NULL;
+
+ /* Check content against the presented DN */
+ /* We assume that this function handles normalization and so on */
+ dn_string = (char*) slapi_sdn_get_ndn(role->dn);
+ berval_set_string(&bv,dn_string);
+ rc = slapi_attr_value_find(attr,&bv);
+ if ( rc == 0 )
+ {
+ *present = 1;
+ }
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_check_managed: entry %s role %s present %d\n",
+ slapi_entry_get_dn_const(entry_to_check),(char*)slapi_sdn_get_ndn(role->dn),*present);
+ return rc;
+}
+
+/* roles_check_filtered
+ --------------------------
+ Check a filtered role: call slapi_filter_test here on the entry
+ and the filter from the role object
+ return 0: ok
+ return 1: fail
+ -> to check the presence, see present
+ */
+static int roles_check_filtered(Slapi_Entry *entry_to_check, role_object *role, int *present)
+{
+ int rc = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_check_filtered\n");
+ rc = slapi_filter_test_simple(entry_to_check,role->filter);
+ if ( rc == 0 )
+ {
+ *present = 1;
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "<-- roles_check_filtered: entry %s role %s present %d\n",
+ slapi_entry_get_dn_const(entry_to_check),(char*)slapi_sdn_get_ndn(role->dn),*present);
+ return rc;
+}
+
+
+/* roles_check_nested
+ ------------------------
+ Check a nested role
+ return 0: ok
+ return -1: fail
+ -> to check the presence, see present
+ */
+static int roles_check_nested(caddr_t data, caddr_t arg)
+{
+ roles_cache_search_in_nested *get_nsrole = (roles_cache_search_in_nested*)arg;
+ int rc = -1;
+ role_object_nested *current_nested_role = (role_object_nested*)data;
+
+
+ /* do not allow circular dependencies, the cheap and easy way */
+ if( get_nsrole->hint > MAX_NESTED_ROLES)
+ {
+ char *ndn = NULL;
+
+ ndn = slapi_entry_get_ndn( get_nsrole->is_entry_member_of );
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "Maximum roles nesting exceeded (max %d current %d), not checking roles in entry %s--probable circular definition\n",
+ MAX_NESTED_ROLES,
+ get_nsrole->hint,
+ ndn);
+
+ /* Stop traversal value */
+ return 0;
+ }
+
+ /* Here we traverse the list of nested roles, calling the appropriate
+ evaluation function for those in turn */
+
+ if (current_nested_role)
+ {
+ roles_cache_def *roles_cache = NULL;
+ role_object *this_role = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "-->roles_check_nested: entry %s role %s present %d\n",
+ slapi_entry_get_dn_const(get_nsrole->is_entry_member_of),
+ (char*)slapi_sdn_get_ndn(current_nested_role->dn),
+ get_nsrole->present);
+
+ if ( roles_cache_find_roles_in_suffix(current_nested_role->dn,
+ &roles_cache) != 0 )
+ {
+ return rc;
+ }
+
+ if ( slapi_is_loglevel_set(SLAPI_LOG_PLUGIN) )
+ {
+ avl_apply(roles_cache->avl_tree, (IFP)roles_cache_dump, &rc, -1, AVL_INORDER);
+ }
+
+ this_role = (role_object *)avl_find(roles_cache->avl_tree,
+ current_nested_role->dn,
+ (IFP)roles_cache_find_node);
+
+ if ( this_role == NULL )
+ {
+ /* the nested role doesn't exist */
+ slapi_log_error(SLAPI_LOG_FATAL,
+ ROLES_PLUGIN_SUBSYSTEM,
+ "The nested role %s doesn't exist\n",
+ (char*)slapi_sdn_get_ndn(current_nested_role->dn));
+ return rc;
+ }
+ /* get the role_object data associated to that dn */
+ if ( roles_is_inscope(get_nsrole->is_entry_member_of, this_role->dn) )
+ {
+ /* The list of nested roles is contained in the role definition */
+ roles_is_entry_member_of_object((caddr_t)this_role, (caddr_t)get_nsrole);
+ if ( get_nsrole->present == 1 )
+ {
+ return 0;
+ }
+ }
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_check_nested\n");
+ return rc;
+}
+
+/* roles_is_inscope
+ ----------------------
+ Tells us if a presented role is in scope with respect to the presented entry
+ */
+static int roles_is_inscope(Slapi_Entry *entry_to_check, Slapi_DN *role_dn)
+{
+ int rc;
+
+ Slapi_DN role_parent;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_is_inscope\n");
+
+ slapi_sdn_init(&role_parent);
+ slapi_sdn_get_parent(role_dn,&role_parent);
+
+ rc = slapi_sdn_scope_test(slapi_entry_get_sdn( entry_to_check ),
+ &role_parent,
+ LDAP_SCOPE_SUBTREE);
+ /* we need to check whether the entry would be returned by a view in scope */
+ if(!rc && views_api)
+ {
+ rc = views_entry_exists(views_api, (char*)slapi_sdn_get_ndn(&role_parent), entry_to_check);
+ }
+
+ slapi_sdn_done(&role_parent);
+
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_is_inscope: entry %s role %s result %d\n",
+ slapi_entry_get_dn_const(entry_to_check),(char*)slapi_sdn_get_ndn(role_dn), rc);
+
+ return (rc);
+}
+
+static void berval_set_string(struct berval *bv, const char* string)
+{
+ bv->bv_len= strlen(string);
+ bv->bv_val= (void*)string; /* We cast away the const, but we're not going to change anything
+*/
+}
+
+/* roles_cache_role_def_delete
+ ----------------------------
+*/
+static void roles_cache_role_def_delete(roles_cache_def *role_def)
+{
+ roles_cache_def *current = roles_list;
+ roles_cache_def *previous = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_def_delete\n");
+
+ while ( current!= NULL )
+ {
+ if ( slapi_sdn_compare(current->suffix_dn, role_def->suffix_dn) == 0 )
+ {
+ if ( previous== NULL )
+ {
+ roles_list = current->next;
+ }
+ else
+ {
+ previous->next = current->next;
+ }
+ slapi_lock_mutex(role_def->change_lock);
+ role_def->keeprunning = 0;
+ slapi_notify_condvar(role_def->something_changed, 1 );
+ slapi_unlock_mutex(role_def->change_lock);
+ break;
+ }
+ else
+ {
+ previous = current;
+ current = current->next;
+ }
+ }
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_role_def_delete\n");
+}
+
+/* roles_cache_role_def_free
+ ----------------------------
+*/
+static void roles_cache_role_def_free(roles_cache_def *role_def)
+{
+ roles_cache_def *next_def = NULL;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_def_free\n");
+ if ( role_def == NULL )
+ {
+ return;
+ }
+
+ slapi_lock_mutex(role_def->stop_lock);
+
+ avl_free(role_def->avl_tree, (IFP)roles_cache_role_object_free);
+ slapi_sdn_free(&(role_def->suffix_dn));
+ slapi_destroy_mutex(role_def->cache_lock);
+ role_def->cache_lock = NULL;
+ slapi_destroy_mutex(role_def->change_lock);
+ role_def->change_lock = NULL;
+ slapi_destroy_condvar(role_def->something_changed);
+ slapi_destroy_mutex(role_def->create_lock);
+ role_def->create_lock = NULL;
+ slapi_destroy_condvar(role_def->suffix_created);
+
+ slapi_ch_free((void**)&role_def->notified_dn);
+ if ( role_def->notified_entry != NULL )
+ {
+ slapi_entry_free(role_def->notified_entry);
+ }
+
+ slapi_unlock_mutex(role_def->stop_lock);
+ slapi_destroy_mutex(role_def->stop_lock);
+ role_def->stop_lock = NULL;
+
+ slapi_ch_free((void**)&role_def);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_role_def_free\n");
+}
+
+/* roles_cache_role_object_free
+ ----------------------------
+*/
+static void roles_cache_role_object_free(role_object *this_role)
+{
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_object_free\n");
+
+ if ( this_role == NULL )
+ {
+ return;
+ }
+
+ switch (this_role->type)
+ {
+ case ROLE_TYPE_MANAGED:
+ /* Nothing further needed */
+ break;
+ case ROLE_TYPE_FILTERED:
+ /* Free the filter */
+ if (this_role->filter)
+ {
+ slapi_filter_free(this_role->filter,1);
+ this_role->filter = NULL;
+ }
+ break;
+ case ROLE_TYPE_NESTED:
+ /* Free the list of nested roles */
+ {
+ avl_free(this_role->avl_tree, roles_cache_role_object_nested_free);
+ }
+ break;
+ }
+
+ slapi_sdn_free(&this_role->dn);
+
+ /* Free the object */
+ slapi_ch_free((void**)&this_role);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_role_object_free\n");
+}
+
+/* roles_cache_role_object_nested_free
+ ------------------------------------
+*/
+static void roles_cache_role_object_nested_free(role_object_nested *this_role)
+{
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "--> roles_cache_role_object_nested_free\n");
+
+ if ( this_role == NULL )
+ {
+ return;
+ }
+
+ slapi_sdn_free(&this_role->dn);
+
+ /* Free the object */
+ slapi_ch_free((void**)&this_role);
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "<-- roles_cache_role_object_nested_free\n");
+}
+
+static int roles_cache_dump( caddr_t data, caddr_t arg )
+{
+ role_object *this_role = (role_object*)data;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN,
+ ROLES_PLUGIN_SUBSYSTEM, "roles_cache_dump: %x - %s - %x\n",
+ this_role, (char*)slapi_sdn_get_ndn(this_role->dn), this_role->avl_tree);
+
+ return 0;
+}
diff --git a/ldap/servers/plugins/roles/roles_cache.h b/ldap/servers/plugins/roles/roles_cache.h
new file mode 100644
index 00000000..fbe6c641
--- /dev/null
+++ b/ldap/servers/plugins/roles/roles_cache.h
@@ -0,0 +1,52 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#if !defined( _ROLES_CACHE_H )
+
+#define SLAPD_ROLES_INTERFACE "roles-slapd"
+#define ROLES_PLUGIN_SUBSYSTEM "roles-plugin"
+#define NSROLEATTR "nsRole"
+
+#define ROLE_DEFINITION_FILTER "(&(objectclass=nsRoleDefinition)(objectclass=ldapsubentry))"
+#define OBJ_FILTER "(|(objectclass=*)(objectclass=ldapsubentry))"
+
+#define ROLE_TYPE_MANAGED 1
+#define ROLE_TYPE_FILTERED 2
+#define ROLE_TYPE_NESTED 3
+
+#define ROLE_OBJECTCLASS_MANAGED "nsManagedRoleDefinition"
+#define ROLE_OBJECTCLASS_FILTERED "nsFilteredRoleDefinition"
+#define ROLE_OBJECTCLASS_NESTED "nsNestedRoleDefinition"
+
+#define ROLE_FILTER_ATTR_NAME "nsRoleFilter"
+#define ROLE_MANAGED_ATTR_NAME "nsRoleDN"
+#define ROLE_NESTED_ATTR_NAME "nsRoleDN"
+
+#define SLAPI_ROLE_ERROR_NO_FILTER_SPECIFIED -1
+#define SLAPI_ROLE_ERROR_FILTER_BAD -2
+#define SLAPI_ROLE_DEFINITION_DOESNT_EXIST -3
+#define SLAPI_ROLE_DEFINITION_ERROR -4
+#define SLAPI_ROLE_DEFINITION_ALREADY_EXIST -5
+
+/* From roles_cache.c */
+int roles_cache_init();
+void roles_cache_stop();
+void roles_cache_change_notify(Slapi_PBlock *pb);
+int roles_cache_listroles(Slapi_Entry *entry, int return_value, Slapi_ValueSet **valueset_out);
+
+int roles_check(Slapi_Entry *entry_to_check, Slapi_DN *role_dn, int *present);
+
+/* From roles_plugin.c */
+int roles_init( Slapi_PBlock *pb );
+int roles_sp_get_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *free_flags, void *hint);
+
+int roles_sp_compare_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result,int flags, void *hint);
+
+int roles_sp_list_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags);
+
+void * roles_get_plugin_identity();
+
+#endif /* _ROLES_CACHE_H */
diff --git a/ldap/servers/plugins/roles/roles_plugin.c b/ldap/servers/plugins/roles/roles_plugin.c
new file mode 100644
index 00000000..d1ce5903
--- /dev/null
+++ b/ldap/servers/plugins/roles/roles_plugin.c
@@ -0,0 +1,254 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ Code to implement server roles features
+*/
+
+#include "slap.h"
+
+#include "vattr_spi.h"
+
+#include "roles_cache.h"
+#include "statechange.h"
+
+
+#ifdef SOURCEFILE
+#undef SOURCEFILE
+#endif
+#define SOURCEFILE "roles_plugin.c"
+static char *sourcefile = SOURCEFILE;
+
+#define STATECHANGE_ROLES_ID "Roles"
+#define STATECHANGE_ROLES_CONFG_FILTER "objectclass=nsRoleDefinition"
+#define STATECHANGE_ROLES_ENTRY_FILTER "objectclass=*"
+
+#define ROLES_PLUGIN_SUBSYSTEM "roles-plugin" /* for logging */
+static void * roles_plugin_identity = NULL;
+
+static Slapi_PluginDesc pdesc = { "roles",
+ PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT, "roles plugin" };
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+static int roles_start( Slapi_PBlock *pb );
+static int roles_post_op( Slapi_PBlock *pb );
+static int roles_close( Slapi_PBlock *pb );
+static void roles_set_plugin_identity(void * identity);
+
+/* roles_init
+ ----------
+ Initialization of the plugin
+ */
+int roles_init( Slapi_PBlock *pb )
+{
+ int rc = 0;
+ void *plugin_identity = NULL;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "=> roles_init\n" );
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
+ PR_ASSERT (plugin_identity);
+ roles_set_plugin_identity(plugin_identity);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *)SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN,
+ (void *)roles_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
+ (void *) roles_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN,
+ (void *) roles_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
+ (void *) roles_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
+ (void *) roles_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) roles_close ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, ROLES_PLUGIN_SUBSYSTEM,
+ "roles_init failed\n" );
+ rc = -1;
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "<= roles_init %d\n", rc );
+ return rc;
+}
+
+/* roles_start
+ -----------
+ kexcoff: cache build at init or at startup ?
+ */
+static int roles_start( Slapi_PBlock *pb )
+{
+ int rc = 0;
+ void **statechange_api;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "=> roles_start\n" );
+
+ roles_cache_init();
+
+ /* from Pete Rowley for vcache
+ * PLUGIN DEPENDENCY ON STATECHANGE PLUGIN
+ *
+ * register objectclasses which indicate a
+ * role configuration entry, and therefore
+ * a globally significant change for the vcache
+ */
+
+ if(!slapi_apib_get_interface(StateChange_v1_0_GUID, &statechange_api))
+ {
+ statechange_register(statechange_api, STATECHANGE_ROLES_ID, NULL, STATECHANGE_ROLES_CONFG_FILTER, &vattr_global_invalidate, (notify_callback) statechange_vattr_cache_invalidator_callback(statechange_api));
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "<= roles_start %d\n", rc );
+ return rc;
+}
+
+/* roles_close
+ -----------
+ kexcoff: ??
+ */
+static int roles_close( Slapi_PBlock *pb )
+{
+ int rc = 0;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "=> roles_close\n" );
+
+ roles_cache_stop();
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM,
+ "<= roles_close %d\n", rc );
+ return rc;
+}
+
+/* roles_sp_get_value
+ ------------------
+ Enumerate the values of the role attribute.
+ We do this by first locating all the roles which are in scope
+ Then we iterate over the in-scope roles calling Slapi_Role_Check().
+ For those which pass the check, we add their DN to the attribute's value set.
+*/
+int roles_sp_get_value(vattr_sp_handle *handle,
+ vattr_context *c,
+ Slapi_Entry *e,
+ char *type,
+ Slapi_ValueSet** results,
+ int *type_name_disposition,
+ char** actual_type_name,
+ int flags,
+ int *free_flags,
+ void *hint)
+{
+ int rc = -1;
+
+ rc = roles_cache_listroles(e, 1, results);
+ if (rc == 0)
+ {
+ *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
+ *actual_type_name = strdup(NSROLEATTR);
+
+ if (type_name_disposition)
+ {
+ *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ }
+ }
+
+ /* Need to check the return code here because the caller
+ doesn't understand roles return codes */
+
+ return rc;
+}
+
+
+/* roles_sp_compare_value
+ ----------------------
+ Compare the value of the role attribute with a presented value.
+ Return true or false to the client.
+ */
+
+int roles_sp_compare_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result,int flags, void *hint)
+{
+ int rc = 0;
+ Slapi_DN the_dn;
+
+ /* Extract the role's DN from the value passed in */
+ slapi_sdn_init_dn_byref(&the_dn,slapi_value_get_string(test_this));
+
+ return (roles_check(e,&the_dn,result));
+}
+
+int roles_sp_list_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags)
+{
+ static char* test_type_name = NSROLEATTR;
+ int ret =0;
+
+ if ( 0 == ( flags & SLAPI_VIRTUALATTRS_LIST_OPERATIONAL_ATTRS )) {
+ /*
+ * Operational attributes were NOT requested. Since the only
+ * attribute type we service is nsRole which IS operational,
+ * there is nothing for us to do in this case.
+ */
+ return 0;
+ }
+
+ ret = roles_cache_listroles(e, 0, NULL);
+ if(ret == 0)
+ {
+ vattr_type_thang thang = {0};
+ thang.type_name = test_type_name;
+ thang.type_flags = SLAPI_ATTR_FLAG_OPATTR;
+ slapi_vattrspi_add_type(type_context,&thang,SLAPI_VIRTUALATTRS_REQUEST_POINTERS);
+ }
+ return 0;
+}
+
+/* What do we do on shutdown ? */
+int roles_sp_cleanup()
+{
+ return 0;
+}
+
+/* roles_post_op
+ -----------
+ Catch all for all post operations that change entries
+ in some way - this simply notifies the cache of a
+ change - the cache decides if action is necessary
+*/
+static int roles_post_op( Slapi_PBlock *pb )
+{
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "--> roles_post_op\n");
+
+ roles_cache_change_notify(pb);
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, ROLES_PLUGIN_SUBSYSTEM, "<-- roles_post_op\n");
+ return 0; /* always succeed */
+}
+
+static void roles_set_plugin_identity(void * identity)
+{
+ roles_plugin_identity=identity;
+}
+
+void * roles_get_plugin_identity()
+{
+ return roles_plugin_identity;
+}
+
diff --git a/ldap/servers/plugins/shared/Makefile b/ldap/servers/plugins/shared/Makefile
new file mode 100644
index 00000000..847735ee
--- /dev/null
+++ b/ldap/servers/plugins/shared/Makefile
@@ -0,0 +1,56 @@
+#
+# 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 shared components for Directory Server plugins
+#
+#
+
+LDAP_SRC = ../../..
+MCOM_ROOT = ../../../../..
+
+SHARED=shared
+
+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 = $(OBJDIR)/lib/$(SHARED)
+LIBDIR = $(LDAP_LIBDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd
+
+LOCAL_OBJS= utils.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(LOCAL_OBJS))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS += $(LIBSLAPD)
+endif
+
+all: $(OBJDEST) $(OBJS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+#
+# header file dependencies (incomplete)
+#
+$(OBJS): plugin-utils.h
+
diff --git a/ldap/servers/plugins/shared/plugin-utils.h b/ldap/servers/plugins/shared/plugin-utils.h
new file mode 100644
index 00000000..31c956f4
--- /dev/null
+++ b/ldap/servers/plugins/shared/plugin-utils.h
@@ -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 **/
+/***********************************************************************
+**
+** NAME
+** plugin-utils.h
+**
+** DESCRIPTION
+**
+**
+** AUTHOR
+** <rweltman@netscape.com>
+**
+***********************************************************************/
+
+#ifndef _PLUGIN_UTILS_H_
+#define _PLUGIN_UTILS_H_
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+#include <slapi-plugin.h>
+/*
+ * slapi-plugin-compat4.h is needed because we use the following deprecated
+ * functions:
+ *
+ * slapi_search_internal()
+ * slapi_modify_internal()
+ */
+#include "slapi-plugin-compat4.h"
+#include <dirlite_strings.h>
+#include <stdio.h>
+#include <string.h>
+#ifdef _WINDOWS
+#undef strcasecmp
+#define strcasecmp strcmpi
+#endif
+#include "dirver.h"
+
+#ifdef LDAP_DEBUG
+#ifndef DEBUG
+#define DEBUG
+#endif
+#endif
+
+#define BEGIN do {
+#define END } while(0);
+
+int initCounterLock();
+int op_error(int internal_error);
+Slapi_PBlock *readPblockAndEntry( const char *baseDN, const char *filter,
+ char *attrs[] );
+int entryHasObjectClass(Slapi_PBlock *pb, Slapi_Entry *e,
+ const char *objectClass);
+Slapi_PBlock *dnHasObjectClass( const char *baseDN, const char *objectClass );
+Slapi_PBlock *dnHasAttribute( const char *baseDN, const char *attrName );
+int setCounter( Slapi_Entry *e, const char *attrName, int value );
+int updateCounter( Slapi_Entry *e, const char *attrName, int increment );
+int updateCounterByDN( const char *dn, const char *attrName, int increment );
+
+typedef struct DNLink {
+ char *dn;
+ void *data;
+ struct DNLink *next;
+} DNLink;
+
+DNLink *cacheInit( void );
+DNLink *cacheAdd( DNLink *root, char *dn, void *data );
+char *cacheRemove( DNLink *root, char *dn );
+int cacheDelete( DNLink *root, char *dn );
+DNLink *cacheFind( DNLink *root, char *dn );
+
+#endif /* _PLUGIN_UTILS_H_ */
diff --git a/ldap/servers/plugins/shared/utils.c b/ldap/servers/plugins/shared/utils.c
new file mode 100644
index 00000000..d5044b17
--- /dev/null
+++ b/ldap/servers/plugins/shared/utils.c
@@ -0,0 +1,467 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/***********************************************************************
+** NAME
+** utils.c
+**
+** DESCRIPTION
+**
+**
+** AUTHOR
+** <rweltman@netscape.com>
+**
+***********************************************************************/
+
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+#include "plugin-utils.h"
+
+static char *plugin_name = "utils";
+
+/*
+ * Lock for updating a counter (global for all counters)
+ */
+static Slapi_Mutex *counter_lock = NULL;
+
+/* ------------------------------------------------------------ */
+/*
+ * op_error - Record (and report) an operational error.
+ */
+int
+op_error(int internal_error) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "Internal error: %d\n", internal_error);
+
+ return LDAP_OPERATIONS_ERROR;
+}
+
+int initCounterLock() {
+ if ( NULL == counter_lock ) {
+ if ( !(counter_lock = slapi_new_mutex()) ) {
+ return 200;
+ }
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * readPblockAndEntry - search for and read an entry
+ * Return:
+ * A pblock containing the entry, or NULL
+ */
+Slapi_PBlock *
+readPblockAndEntry( const char *baseDN, const char *filter,
+ char *attrs[] ) {
+ int result = 0;
+ Slapi_PBlock *spb = NULL;
+
+ BEGIN
+ int sres;
+
+ /* Perform the search - the new pblock needs to be freed */
+ spb = slapi_search_internal((char *)baseDN, LDAP_SCOPE_BASE,
+ (char *)filter, NULL, attrs, 0);
+ if ( !spb ) {
+ result = op_error(20);
+ break;
+ }
+
+ if ( slapi_pblock_get( spb, SLAPI_PLUGIN_INTOP_RESULT, &sres ) ) {
+ result = op_error(21);
+ break;
+ } else if (sres) {
+ result = op_error(22);
+ break;
+ }
+ END
+
+ return spb;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * hasObjectClass - read an entry and check if it has a
+ * particular object class value
+ * Return:
+ * 1 - the entry contains the object class value
+ * 0 - the entry doesn't contain the object class value
+ */
+int
+entryHasObjectClass(Slapi_PBlock *pb, Slapi_Entry *e,
+ const char *objectClass) {
+ Slapi_Attr *attr;
+ Slapi_Value *v;
+ const struct berval *bv;
+ int vhint;
+
+ if ( slapi_entry_attr_find(e, "objectclass", &attr) ) {
+ return 0; /* no objectclass values! */
+ }
+
+ /*
+ * Check each of the object class values in turn.
+ */
+ for ( vhint = slapi_attr_first_value( attr, &v );
+ vhint != -1;
+ vhint = slapi_attr_next_value( attr, vhint, &v )) {
+ bv = slapi_value_get_berval(v);
+ if ( NULL != bv && NULL != bv->bv_val &&
+ !strcasecmp(bv->bv_val, objectClass) ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * dnHasObjectClass - read an entry if it has a particular object class
+ * Return:
+ * A pblock containing the entry, or NULL
+ */
+Slapi_PBlock *
+dnHasObjectClass( const char *baseDN, const char *objectClass ) {
+ int result = 0;
+ Slapi_PBlock *spb = NULL;
+
+ BEGIN
+ Slapi_Entry **entries;
+ char filter[1024];
+ char *attrs[2];
+
+ /* Perform the search - the new pblock needs to be freed */
+ attrs[0] = "objectclass";
+ attrs[1] = NULL;
+ sprintf( filter, "objectclass=%s", objectClass );
+ if ( !(spb = readPblockAndEntry( baseDN, filter, attrs) ) ) {
+ break;
+ }
+
+ if ( slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+ &entries) ) {
+ result = op_error(23);
+ break;
+ }
+ /*
+ * Can only be one entry returned on a base search; just check
+ * the first one
+ */
+ if ( !*entries ) {
+ /* Clean up */
+ slapi_free_search_results_internal(spb);
+ slapi_pblock_destroy(spb);
+ spb = NULL;
+ }
+ END
+
+ return spb;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * dnHasAttribute - read an entry if it has a particular attribute
+ * Return:
+ * The entry, or NULL
+ */
+Slapi_PBlock *
+dnHasAttribute( const char *baseDN, const char *attrName ) {
+ int result = 0;
+ Slapi_PBlock *spb = NULL;
+
+ BEGIN
+ int sres;
+ Slapi_Entry **entries;
+ char filter[1024];
+ char *attrs[2];
+
+ /* Perform the search - the new pblock needs to be freed */
+ attrs[0] = (char *)attrName;
+ attrs[1] = NULL;
+ sprintf( filter, "%s=*", attrName );
+ spb = slapi_search_internal((char *)baseDN, LDAP_SCOPE_BASE,
+ filter, NULL, attrs, 0);
+ if ( !spb ) {
+ result = op_error(20);
+ break;
+ }
+
+ if ( slapi_pblock_get( spb, SLAPI_PLUGIN_INTOP_RESULT, &sres ) ) {
+ result = op_error(21);
+ break;
+ } else if (sres) {
+ result = op_error(22);
+ break;
+ }
+
+ if ( slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+ &entries) ) {
+ result = op_error(23);
+ break;
+ }
+ /*
+ * Can only be one entry returned on a base search; just check
+ * the first one
+ */
+ if ( !*entries ) {
+ /* Clean up */
+ slapi_free_search_results_internal(spb);
+ slapi_pblock_destroy(spb);
+ spb = NULL;
+ }
+ END
+
+ return spb;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * setCounter - set the value of a counter
+ *
+ * Return:
+ * LDAP_SUCCESS - updated the attribute
+ * other - failure to update the count
+ */
+int
+setCounter( Slapi_Entry *e, const char *attrName, int value ) {
+ int result = LDAP_SUCCESS;
+ Slapi_PBlock *modifySpb = NULL;
+ char strValue[16];
+ char *strValues[2] = { NULL };
+ LDAPMod mod;
+ LDAPMod *mods[2];
+ int res;
+
+ BEGIN
+ /* Store the updated value */
+ strValues[0] = strValue;
+ sprintf( strValue, "%d", value );
+ mod.mod_op = LDAP_MOD_REPLACE;
+ mod.mod_type = (char *)attrName;
+ mod.mod_values = strValues;
+ mods[0] = &mod;
+ mods[1] = NULL;
+ modifySpb = slapi_modify_internal( slapi_entry_get_dn(e), mods,
+ NULL, 1 );
+ /* Check if the operation succeeded */
+ if ( slapi_pblock_get( modifySpb, SLAPI_PLUGIN_INTOP_RESULT,
+ &res ) ) {
+ result = op_error(33);
+ break;
+ } else if (res) {
+ result = op_error(34);
+ break;
+ }
+ slapi_pblock_destroy(modifySpb);
+ END
+ return result;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * updateCounter - read and increment/decrement the value of a counter
+ *
+ * Return:
+ * LDAP_SUCCESS - updated the attribute
+ * other - failure to update the count
+ */
+int
+updateCounter( Slapi_Entry *e, const char *attrName, int increment ) {
+ int result = LDAP_SUCCESS;
+ Slapi_PBlock *modifySpb = NULL;
+ Slapi_Attr *attr;
+ int value = 0;
+ char strValue[16];
+ char *strValues[2] = { NULL };
+ LDAPMod mod;
+ LDAPMod *mods[2];
+ int res;
+
+ BEGIN
+ /* Lock the entry */
+ slapi_lock_mutex(counter_lock);
+ /* Get the count attribute */
+ if ( slapi_entry_attr_find(e, (char *)attrName, &attr) ) {
+ /* No count yet; that's OK */
+ } else {
+ /* Get the first value for the attribute */
+ Slapi_Value *v = NULL;
+ const struct berval *bv = NULL;
+
+ if ( -1 == slapi_attr_first_value( attr, &v ) || NULL == v ||
+ NULL == ( bv = slapi_value_get_berval(v)) ||
+ NULL == bv->bv_val ) {
+ /* No values yet; that's OK, too */
+ } else {
+ value = atoi( bv->bv_val );
+ }
+ }
+ /* Add the increment */
+ value += increment;
+ if ( value < 0 ) {
+ value = 0;
+ }
+ /* Store the updated value */
+ strValues[0] = strValue;
+ sprintf( strValue, "%d", value );
+ mod.mod_op = LDAP_MOD_REPLACE;
+ mod.mod_type = (char *)attrName;
+ mod.mod_values = strValues;
+ mods[0] = &mod;
+ mods[1] = NULL;
+ modifySpb = slapi_modify_internal( slapi_entry_get_dn(e), mods,
+ NULL, 1 );
+ /* Check if the operation succeeded */
+ if ( slapi_pblock_get( modifySpb, SLAPI_PLUGIN_INTOP_RESULT,
+ &res ) ) {
+ result = op_error(33);
+ break;
+ } else if (res) {
+ result = op_error(34);
+ break;
+ }
+ slapi_pblock_destroy(modifySpb);
+ /* Unlock the entry */
+ slapi_unlock_mutex(counter_lock);
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "adjusted %s in %s by %d to %d\n",
+ attrName, slapi_entry_get_dn(e), increment, value);
+#endif
+
+ END
+ return result;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * updateCounterByDN - read and increment/decrement the value of a counter
+ *
+ * Return:
+ * LDAP_SUCCESS - updated the attribute
+ * other - failure to update the count
+ */
+int
+updateCounterByDN( const char *dn, const char *attrName, int increment ) {
+ int result = LDAP_SUCCESS;
+ Slapi_PBlock *spb = NULL;
+ Slapi_Entry **entries;
+
+ BEGIN
+ char *attrs[2];
+ int sres;
+
+ /* Perform the search - the new pblock needs to be freed */
+ attrs[0] = (char *)attrName;
+ attrs[1] = NULL;
+ spb = slapi_search_internal((char *)dn, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, attrs, 0);
+ if ( !spb ) {
+ result = op_error(20);
+ break;
+ }
+
+ if ( slapi_pblock_get( spb, SLAPI_PLUGIN_INTOP_RESULT, &sres ) ) {
+ result = op_error(21);
+ break;
+ } else if (sres) {
+ result = op_error(22);
+ break;
+ }
+
+ if ( slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+ &entries) ) {
+ result = op_error(23);
+ break;
+ }
+ END
+ if ( 0 == result ) {
+ result = updateCounter( *entries, attrName, increment );
+ }
+ if ( NULL != spb ) {
+ /* Clean up */
+ slapi_free_search_results_internal(spb);
+ slapi_pblock_destroy(spb);
+ }
+ return result;
+}
+
+/*
+ * Lock for accessing a cache (global for all caches)
+ */
+static Slapi_Mutex *cache_lock = NULL;
+
+DNLink *cacheInit() {
+ DNLink *root;
+ slapi_lock_mutex(cache_lock);
+ root = (DNLink *)malloc( sizeof(DNLink) );
+ root->next = NULL;
+ root->data = NULL;
+ root->dn = (char *)malloc(1);
+ root->dn[0] = 0;
+ slapi_unlock_mutex(cache_lock);
+ return root;
+}
+
+DNLink *cacheAdd( DNLink *root, char *dn, void *data ) {
+ if ( NULL == root ) {
+ return NULL;
+ }
+ slapi_lock_mutex(cache_lock);
+ for( ; root->next; root = root->next ) {
+ }
+ root->next = (DNLink *)malloc( sizeof(DNLink) );
+ root = root->next;
+ root->dn = dn;
+ root->data = data;
+ root->next = NULL;
+ slapi_unlock_mutex(cache_lock);
+ return root;
+}
+
+char *cacheRemove( DNLink *root, char *dn ) {
+ char *found = NULL;
+ DNLink *current = root;
+ DNLink *prev = NULL;
+ if ( NULL == root ) {
+ return NULL;
+ }
+ slapi_lock_mutex(cache_lock);
+ for( ; current; prev = current, current = current->next ) {
+ if ( !strcmp( current->dn, dn ) ) {
+ found = current->dn;
+ prev->next = current->next;
+ slapi_ch_free( (void **)&current );
+ break;
+ }
+ }
+ slapi_unlock_mutex(cache_lock);
+ return found;
+}
+
+int cacheDelete( DNLink *root, char *dn ) {
+ char *found = cacheRemove( root, dn );
+ if ( found ) {
+ slapi_ch_free( (void **)&found );
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+DNLink *cacheFind( DNLink *root, char *dn ) {
+ if ( NULL == root ) {
+ return NULL;
+ }
+ slapi_lock_mutex(cache_lock);
+ for( ; root && strcmp(dn, root->dn); root = root->next ) {
+ }
+ slapi_unlock_mutex(cache_lock);
+ return root;
+}
diff --git a/ldap/servers/plugins/statechange/Makefile b/ldap/servers/plugins/statechange/Makefile
new file mode 100644
index 00000000..bc04a3f0
--- /dev/null
+++ b/ldap/servers/plugins/statechange/Makefile
@@ -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
+#
+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 = $(OBJDIR)/lib/libstatechange
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./statechange.def
+endif
+
+STATECHANGE_OBJS = statechange.o
+OBJS = $(addprefix $(OBJDEST)/, $(STATECHANGE_OBJS))
+
+STATECHANGE_DLL = statechange-plugin
+
+INCLUDES += -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD)
+EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD)
+STATECHANGE_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), AIX)
+LD=ld
+EXTRA_LIBS += $(LIBSLAPD)
+endif
+
+STATECHANGE= $(addprefix $(LIBDIR)/, $(STATECHANGE_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(STATECHANGE)
+
+ifeq ($(ARCH), WINNT)
+$(STATECHANGE): $(OBJS) $(STATECHANGE_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(STATECHANGE_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(STATECHANGE): $(OBJS) $(STATECHANGE_DLL_OBJ)
+ $(LINK_DLL) $(STATECHANGE_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(STATECHANGE_DLL_OBJ)
+endif
+ $(RM) $(STATECHANGE)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
diff --git a/ldap/servers/plugins/statechange/dllmain.c b/ldap/servers/plugins/statechange/dllmain.c
new file mode 100644
index 00000000..fabf8677
--- /dev/null
+++ b/ldap/servers/plugins/statechange/dllmain.c
@@ -0,0 +1,96 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/statechange/statechange.c b/ldap/servers/plugins/statechange/statechange.c
new file mode 100644
index 00000000..c0942b41
--- /dev/null
+++ b/ldap/servers/plugins/statechange/statechange.c
@@ -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 **/
+/* plugin which provides a callback mechanism for state changes in the DS */
+
+#include <stdio.h>
+#include <string.h>
+#include "portable.h"
+#include "slapi-plugin.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+#include "statechange.h"
+
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+/* the circular list of systems to notify */
+typedef struct _statechange_notify
+{
+ char *caller_id;
+ char *dn;
+ char *filter;
+ Slapi_Filter *realfilter;
+ notify_callback func;
+ void *caller_data;
+ struct _statechange_notify *next;
+ struct _statechange_notify *prev;
+} SCNotify;
+
+static SCNotify *head; /* a place to start in the list */
+
+#define SCN_PLUGIN_SUBSYSTEM "statechange-plugin" /* used for logging */
+
+static void *api[5];
+static Slapi_Mutex *buffer_lock = 0;
+
+/* other function prototypes */
+int statechange_init( Slapi_PBlock *pb );
+static int statechange_start( Slapi_PBlock *pb );
+static int statechange_close( Slapi_PBlock *pb );
+static int statechange_post_op( Slapi_PBlock *pb, int modtype );
+static int statechange_mod_post_op( Slapi_PBlock *pb );
+static int statechange_modrdn_post_op( Slapi_PBlock *pb );
+static int statechange_add_post_op( Slapi_PBlock *pb );
+static int statechange_delete_post_op( Slapi_PBlock *pb );
+static int _statechange_register(char *caller_id, char *dn, char *filter, void *caller_data, notify_callback func);
+static void *_statechange_unregister(char *dn, char *filter, notify_callback func);
+static void _statechange_unregister_all(char *caller_id, caller_data_free_callback);
+static void _statechange_vattr_cache_invalidator_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data);
+static SCNotify *statechange_find_notify(char *dn, char *filter, notify_callback func);
+
+
+static Slapi_PluginDesc pdesc = { "statechange", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "state change notification service plugin" };
+
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+
+/*
+ statechange_init
+ --------
+ adds our callbacks to the list
+*/
+int statechange_init( Slapi_PBlock *pb )
+{
+ int ret = 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "--> statechange_init\n");
+
+ head = 0;
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) statechange_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODIFY_FN,
+ (void *) statechange_mod_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_MODRDN_FN,
+ (void *) statechange_modrdn_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_ADD_FN,
+ (void *) statechange_add_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_POST_DELETE_FN,
+ (void *) statechange_delete_post_op ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) statechange_close ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, SCN_PLUGIN_SUBSYSTEM,
+ "statechange_init: failed to register plugin\n" );
+ ret = -1;
+ }
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_init\n");
+ return ret;
+}
+
+
+/*
+ statechange_start
+ ---------
+ This function publishes the interface for this plugin
+*/
+static int statechange_start( Slapi_PBlock *pb )
+{
+ int ret = 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "--> statechange_start\n");
+
+ api[0] = 0; /* reserved for api broker use, must be zero */
+ api[1] = (void *)_statechange_register;
+ api[2] = (void *)_statechange_unregister;
+ api[3] = (void *)_statechange_unregister_all;
+ api[4] = (void *)_statechange_vattr_cache_invalidator_callback;
+
+ if(0 == (buffer_lock = slapi_new_mutex())) /* we never free this mutex */
+ {
+ /* badness */
+ slapi_log_error( SLAPI_LOG_FATAL, SCN_PLUGIN_SUBSYSTEM, "statechange: failed to create lock\n");
+ ret = -1;
+ }
+ else
+ {
+ if( slapi_apib_register(StateChange_v1_0_GUID, api) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, SCN_PLUGIN_SUBSYSTEM, "statechange: failed to publish state change interface\n");
+ ret = -1;
+ }
+ }
+
+ head = 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_start\n");
+ return ret;
+}
+
+/*
+ statechange_close
+ ---------
+ unregisters the interface for this plugin
+*/
+static int statechange_close( Slapi_PBlock *pb )
+{
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "--> statechange_close\n");
+
+ slapi_apib_unregister(StateChange_v1_0_GUID);
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_close\n");
+
+ return 0;
+}
+
+
+static int statechange_mod_post_op( Slapi_PBlock *pb )
+{
+ return statechange_post_op(pb, LDAP_CHANGETYPE_MODIFY);
+}
+
+static int statechange_modrdn_post_op( Slapi_PBlock *pb )
+{
+ return statechange_post_op(pb, LDAP_CHANGETYPE_MODDN);
+}
+
+static int statechange_add_post_op( Slapi_PBlock *pb )
+{
+ return statechange_post_op(pb, LDAP_CHANGETYPE_ADD);
+}
+
+static int statechange_delete_post_op( Slapi_PBlock *pb )
+{
+ return statechange_post_op(pb, LDAP_CHANGETYPE_DELETE);
+}
+
+
+/*
+ statechange_post_op
+ -----------
+ Catch all for all post operations that change entries
+ in some way - evaluate the change against the notification
+ entries and fire off the relevant callbacks - it is called
+ from the real postop functions which supply it with the
+ postop type
+*/
+static int statechange_post_op( Slapi_PBlock *pb, int modtype )
+{
+ SCNotify *notify = head;
+ int execute;
+ char *dn = NULL;
+ struct slapi_entry *e_before = NULL;
+ struct slapi_entry *e_after = NULL;
+
+ if(head == 0)
+ return 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "--> statechange_post_op\n");
+
+ /* evaluate this operation against the notification entries */
+
+ slapi_lock_mutex(buffer_lock);
+ if(head)
+ {
+ if(slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn ))
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, SCN_PLUGIN_SUBSYSTEM, "statechange_post_op: failed to get dn of changed entry");
+ goto bail;
+ }
+
+ slapi_dn_normalize( dn );
+
+ slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &e_before );
+ slapi_pblock_get( pb, SLAPI_ENTRY_POST_OP, &e_after );
+
+ do
+ {
+ execute = 0;
+
+ /* first dn */
+ if(notify && notify->dn)
+ {
+ if(0 != slapi_dn_issuffix(dn, notify->dn))
+ execute = 1;
+ }
+ else
+ /* note, if supplied null for everything in the entry *all* ops match */
+ if(notify)
+ execute = 1;
+
+ if(execute && notify->filter)
+ {
+ /* next the filter */
+ int filter_test = 0;
+
+ /* need to test entry both before and after op */
+ if(e_before && !slapi_filter_test_simple( e_before, notify->realfilter))
+ filter_test = 1;
+
+ if(!filter_test && e_after && !slapi_filter_test_simple( e_after, notify->realfilter))
+ filter_test = 1;
+
+ if(!filter_test)
+ execute = 0;
+ }
+
+ if(execute)
+ {
+ if(e_after)
+ (notify->func)(e_after, dn, modtype, pb, notify->caller_data);
+ else
+ (notify->func)(e_before, dn, modtype, pb, notify->caller_data);
+ }
+
+ notify = notify->next;
+ }
+ while(notify != head);
+ }
+bail:
+ slapi_unlock_mutex(buffer_lock);
+
+ slapi_log_error( SLAPI_LOG_TRACE, SCN_PLUGIN_SUBSYSTEM, "<-- statechange_post_op\n");
+ return 0; /* always succeed */
+}
+
+
+static int _statechange_register(char *caller_id, char *dn, char *filter, void *caller_data, notify_callback func)
+{
+ int ret = -1;
+ SCNotify *item;
+
+ /* simple - we don't check for duplicates */
+
+ item = (SCNotify*)slapi_ch_malloc(sizeof(SCNotify));
+ if(item)
+ {
+ char *writable_filter = slapi_ch_strdup(filter);
+ item->caller_id = slapi_ch_strdup(caller_id);
+ if(dn)
+ {
+ item->dn = slapi_ch_strdup(dn);
+ slapi_dn_normalize( item->dn );
+ }
+ else
+ item->dn = 0;
+ item->filter = slapi_ch_strdup(filter);
+ item->caller_data = caller_data;
+ item->realfilter = slapi_str2filter(writable_filter);
+ item->func = func;
+
+ slapi_lock_mutex(buffer_lock);
+ if(head == NULL)
+ {
+ head = item;
+ head->next = head;
+ head->prev = head;
+ }
+ else
+ {
+ item->next = head;
+ item->prev = head->prev;
+ head->prev = item;
+ item->prev->next = item;
+ }
+ slapi_unlock_mutex(buffer_lock);
+ slapi_ch_free_string(&writable_filter);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static void *_statechange_unregister(char *dn, char *filter, notify_callback thefunc)
+{
+ void *ret = NULL;
+ SCNotify *func = NULL;
+
+ if(buffer_lock == 0)
+ return ret;
+
+ slapi_lock_mutex(buffer_lock);
+
+ if(func = statechange_find_notify(dn, filter, thefunc))
+ {
+ func->prev->next = func->next;
+ func->next->prev = func->prev;
+
+ if(func == head)
+ {
+ head = func->next;
+ }
+
+ if(func == head) /* must be the last item, turn off the lights */
+ head = 0;
+
+ slapi_ch_free_string(&func->caller_id);
+ slapi_ch_free_string(&func->dn);
+ slapi_ch_free_string(&func->filter);
+ slapi_filter_free( func->realfilter, 1 );
+ ret = func->caller_data;
+ slapi_ch_free((void **)&func);
+ }
+
+ slapi_unlock_mutex(buffer_lock);
+
+ return ret;
+}
+
+static void _statechange_unregister_all(char *caller_id, caller_data_free_callback callback)
+{
+ SCNotify *notify = head;
+ SCNotify *start_notify = head;
+
+ if(buffer_lock == 0)
+ return;
+
+ slapi_lock_mutex(buffer_lock);
+
+
+ if(notify)
+ {
+ do
+ {
+ SCNotify *notify_next = notify->next;
+
+ if( slapi_utf8casecmp((unsigned char *)caller_id, (unsigned char *)notify->caller_id) )
+ {
+ notify->prev->next = notify->next;
+ notify->next->prev = notify->prev;
+
+ if(notify == head)
+ {
+ head = notify->next;
+ start_notify = notify->prev;
+ }
+
+ if(notify == head) /* must be the last item, turn off the lights */
+ head = 0;
+
+ if(callback)
+ callback(notify->caller_data);
+ slapi_ch_free_string(&notify->caller_id);
+ slapi_ch_free_string(&notify->dn);
+ slapi_ch_free_string(&notify->filter);
+ slapi_filter_free( notify->realfilter, 1 );
+ slapi_ch_free((void **)&notify);
+ }
+
+ notify = notify_next;
+ }
+ while(notify != start_notify && notify != NULL);
+ }
+
+ slapi_unlock_mutex(buffer_lock);
+}
+
+/* this func needs looking at to make work */
+static SCNotify *statechange_find_notify(char *dn, char *filter, notify_callback func)
+{
+ SCNotify *notify = head;
+ SCNotify *start_notify = head;
+
+ if(notify)
+ {
+ do
+ {
+ if( !slapi_utf8casecmp((unsigned char *)dn, (unsigned char *)notify->dn) &&
+ !slapi_utf8casecmp((unsigned char *)filter, (unsigned char *)notify->filter) && func == notify->func)
+ {
+ return notify;
+ }
+
+ notify = notify->next;
+ }
+ while(notify != start_notify);
+ }
+
+ return 0;
+}
+
+/* intended for use by vattr service providers
+ * to deal with significant vattr state changes
+ */
+static void _statechange_vattr_cache_invalidator_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data)
+{
+ /* simply get the significance data and act */
+ switch(*(int*)caller_data)
+ {
+ case STATECHANGE_VATTR_ENTRY_INVALIDATE:
+ if(e)
+ slapi_entry_vattrcache_watermark_invalidate(e);
+ break;
+
+ case STATECHANGE_VATTR_GLOBAL_INVALIDATE:
+ default:
+ slapi_entrycache_vattrcache_watermark_invalidate();
+ break;
+ }
+}
+
diff --git a/ldap/servers/plugins/statechange/statechange.def b/ldap/servers/plugins/statechange/statechange.def
new file mode 100644
index 00000000..ed6dca6b
--- /dev/null
+++ b/ldap/servers/plugins/statechange/statechange.def
@@ -0,0 +1,10 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 7.0 State Change Plugin'
+EXPORTS
+ statechange_init @2
+ plugin_init_debug_level @3
diff --git a/ldap/servers/plugins/syntaxes/Makefile b/ldap/servers/plugins/syntaxes/Makefile
new file mode 100644
index 00000000..edc9bd9c
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/Makefile
@@ -0,0 +1,87 @@
+#
+# 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 syntax-plugin.so syntax plugins
+#
+
+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 = $(OBJDIR)/lib/libsyntax
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./libsyntax.def
+endif
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd
+
+SYNTAX_OBJS= phonetic.o string.o cis.o sicis.o ces.o bin.o tel.o dn.o int.o \
+ value.o debug.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(SYNTAX_OBJS))
+
+ifeq ($(ARCH), WINNT)
+LIBSYNTAX_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+LIBSYNTAX= $(addprefix $(LIBDIR)/, $(SYNTAX_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAP_LIBUTIL_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL)
+endif
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAP_LIBUTIL_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL)
+endif
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libsyntax.def"
+CFLAGS+= /WX
+endif # WINNT
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS += $(DLL_EXTRA_LIBS)
+LD=ld
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBSYNTAX)
+
+$(LIBSYNTAX): $(OBJS) $(LIBSYNTAX_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBSYNTAX_DLL_OBJ) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBSYNTAX_DLL_OBJ)
+endif
+ $(RM) $(LIBSYNTAX)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
diff --git a/ldap/servers/plugins/syntaxes/bin.c b/ldap/servers/plugins/syntaxes/bin.c
new file mode 100644
index 00000000..da06e55e
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/bin.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 **/
+/* bin.c - bin syntax routines */
+
+/*
+ * This file actually implements two syntax plugins: OctetString and Binary.
+ * We treat them identically for now. XXXmcs: check if that is correct.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+static int bin_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
+static int bin_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals,
+ Slapi_Value ***ivals, int ftype );
+static int bin_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *bval,
+ Slapi_Value ***ivals, int ftype );
+
+/*
+ * Attribute syntaxes. We treat all of these the same for now, even though
+ * the specifications (e.g., RFC 2252) impose various constraints on the
+ * the format for each of these.
+ *
+ * Note: the first name is the official one from RFC 2252.
+ */
+static char *bin_names[] = { "Binary", "bin", BINARY_SYNTAX_OID, 0 };
+
+static char *octetstring_names[] = { "OctetString", OCTETSTRING_SYNTAX_OID, 0 };
+
+static char *jpeg_names[] = { "JPEG", JPEG_SYNTAX_OID, 0 };
+
+
+static Slapi_PluginDesc bin_pdesc = {
+ "bin-syntax", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "binary attribute syntax plugin"
+};
+
+static Slapi_PluginDesc octetstring_pdesc = {
+ "octetstring-syntax", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "octet string attribute syntax plugin"
+};
+
+static Slapi_PluginDesc jpeg_pdesc = {
+ "jpeg-syntax", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "JPEG attribute syntax plugin"
+};
+
+
+/*
+ * register_bin_like_plugin(): register all items for a bin-like plugin.
+ */
+static int
+register_bin_like_plugin( Slapi_PBlock *pb, Slapi_PluginDesc *pdescp,
+ char **names, char *oid )
+{
+ int rc;
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)pdescp );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_AVA,
+ (void *) bin_filter_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALUES2KEYS,
+ (void *) bin_values2keys );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA,
+ (void *) bin_assertion2keys_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NAMES,
+ (void *) names );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
+ (void *) oid );
+
+ return( rc );
+}
+
+
+int
+bin_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> bin_init\n", 0, 0, 0 );
+ rc = register_bin_like_plugin( pb, &bin_pdesc, bin_names,
+ BINARY_SYNTAX_OID );
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= bin_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+int
+octetstring_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> octetstring_init\n", 0, 0, 0 );
+ rc = register_bin_like_plugin( pb, &octetstring_pdesc, octetstring_names,
+ OCTETSTRING_SYNTAX_OID );
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= octetstring_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+int
+jpeg_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> jpeg_init\n", 0, 0, 0 );
+ rc = register_bin_like_plugin( pb, &jpeg_pdesc, jpeg_names,
+ JPEG_SYNTAX_OID );
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= jpeg_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+static int
+bin_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal )
+{
+ int i;
+
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ if ( slapi_value_get_length(bvals[i]) == bvfilter->bv_len &&
+ 0 == memcmp( slapi_value_get_string(bvals[i]), bvfilter->bv_val, bvfilter->bv_len ))
+ {
+ if(retVal!=NULL)
+ {
+ *retVal= bvals[i];
+ }
+ return( 0 );
+ }
+ }
+ if(retVal!=NULL)
+ {
+ *retVal= NULL;
+ }
+ return( -1 );
+}
+
+static int
+bin_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals,
+ Slapi_Value ***ivals, int ftype )
+{
+ int i;
+
+ if ( ftype != LDAP_FILTER_EQUALITY ) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ /* NULL */
+ }
+ (*ivals) = (Slapi_Value **) slapi_ch_malloc(( i + 1 ) *
+ sizeof(Slapi_Value *) );
+
+ for ( i = 0; bvals[i] != NULL; i++ )
+ {
+ (*ivals)[i] = slapi_value_dup(bvals[i]);
+ }
+ (*ivals)[i] = NULL;
+
+ return( 0 );
+}
+
+static int
+bin_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *bval,
+ Slapi_Value ***ivals, int ftype )
+{
+ Slapi_Value *tmpval=NULL;
+ size_t len;
+
+ if (( ftype != LDAP_FILTER_EQUALITY ) &&
+ ( ftype != LDAP_FILTER_EQUALITY_FAST))
+ {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+ if(ftype == LDAP_FILTER_EQUALITY_FAST) {
+ /* With the fast option, we are trying to avoid creating and freeing
+ * a bunch of structures - we just do one malloc here - see
+ * ava_candidates in filterentry.c
+ */
+ len=slapi_value_get_length(bval);
+ tmpval=(*ivals)[0];
+ if (len > tmpval->bv.bv_len) {
+ tmpval->bv.bv_val=(char *)slapi_ch_malloc(len);
+ }
+ tmpval->bv.bv_len=len;
+ memcpy(tmpval->bv.bv_val,slapi_value_get_string(bval),len);
+ } else {
+ (*ivals) = (Slapi_Value **) slapi_ch_malloc( 2 * sizeof(Slapi_Value *) );
+ (*ivals)[0] = slapi_value_dup( bval );
+ (*ivals)[1] = NULL;
+ }
+ return( 0 );
+}
diff --git a/ldap/servers/plugins/syntaxes/ces.c b/ldap/servers/plugins/syntaxes/ces.c
new file mode 100644
index 00000000..075da03b
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/ces.c
@@ -0,0 +1,168 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* ces.c - caseexactstring syntax routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+static int ces_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
+static int ces_filter_sub( Slapi_PBlock *pb, char *initial, char **any,
+ char *final, Slapi_Value **bvals );
+static int ces_values2keys( Slapi_PBlock *pb, Slapi_Value **val,
+ Slapi_Value ***ivals, int ftype );
+static int ces_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
+ Slapi_Value ***ivals, int ftype );
+static int ces_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
+ char *final, Slapi_Value ***ivals );
+static int ces_compare(struct berval *v1, struct berval *v2);
+
+/* the first name is the official one from RFC 2252 */
+static char *ia5_names[] = { "IA5String", "ces", "caseexactstring",
+ IA5STRING_SYNTAX_OID, 0 };
+
+/* the first name is the official one from RFC 2252 */
+static char *uri_names[] = { "URI", "1.3.6.1.4.1.4401.1.1.1",0};
+
+static Slapi_PluginDesc ia5_pdesc = { "ces-syntax", PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT, "caseExactString attribute syntax plugin" };
+
+static Slapi_PluginDesc uri_pdesc = { "uri-syntax", PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT, "uri attribute syntax plugin" };
+
+
+/*
+ * register_ces_like_plugin(): register all items for a cis-like plugin.
+ */
+static int
+register_ces_like_plugin( Slapi_PBlock *pb, Slapi_PluginDesc *pdescp,
+ char **names, char *oid )
+{
+ int rc, flags;
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *) pdescp );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_AVA,
+ (void *) ces_filter_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_SUB,
+ (void *) ces_filter_sub );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALUES2KEYS,
+ (void *) ces_values2keys );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA,
+ (void *) ces_assertion2keys_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB,
+ (void *) ces_assertion2keys_sub );
+ flags = SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING;
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FLAGS,
+ (void *) &flags );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NAMES,
+ (void *) names );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
+ (void *) oid );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
+ (void *) ces_compare );
+
+ return( rc );
+}
+
+int
+ces_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> ces_init\n", 0, 0, 0 );
+
+ rc = register_ces_like_plugin(pb,&ia5_pdesc,ia5_names,IA5STRING_SYNTAX_OID);
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= ces_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+int
+uri_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> uri_init\n", 0, 0, 0 );
+
+ rc = register_ces_like_plugin(pb,&uri_pdesc,uri_names,
+ "1.3.6.1.4.1.4401.1.1.1");
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= uri_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+static int
+ces_filter_ava(
+ Slapi_PBlock *pb,
+ struct berval *bvfilter,
+ Slapi_Value **bvals,
+ int ftype,
+ Slapi_Value **retVal
+)
+{
+ return( string_filter_ava( bvfilter, bvals, SYNTAX_CES, ftype,
+ retVal) );
+}
+
+static int
+ces_filter_sub(
+ Slapi_PBlock *pb,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value **bvals
+)
+{
+ return( string_filter_sub( pb, initial, any, final, bvals, SYNTAX_CES ) );
+}
+
+static int
+ces_values2keys(
+ Slapi_PBlock *pb,
+ Slapi_Value **vals,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ return( string_values2keys( pb, vals, ivals, SYNTAX_CES, ftype ) );
+}
+
+static int
+ces_assertion2keys_ava(
+ Slapi_PBlock *pb,
+ Slapi_Value *val,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ return(string_assertion2keys_ava( pb, val, ivals, SYNTAX_CES, ftype ));
+}
+
+static int
+ces_assertion2keys_sub(
+ Slapi_PBlock *pb,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value ***ivals
+)
+{
+ return( string_assertion2keys_sub( pb, initial, any, final, ivals,
+ SYNTAX_CES ) );
+}
+
+static int ces_compare(
+ struct berval *v1,
+ struct berval *v2
+)
+{
+ return value_cmp(v1,v2,SYNTAX_CES,3 /* Normalise both values */);
+}
diff --git a/ldap/servers/plugins/syntaxes/cis.c b/ldap/servers/plugins/syntaxes/cis.c
new file mode 100644
index 00000000..e2047fbc
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/cis.c
@@ -0,0 +1,298 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cis.c - caseignorestring syntax routines */
+
+/*
+ * This file actually implements three syntax plugins:
+ * DirectoryString
+ * Boolean
+ * GeneralizedTime
+ *
+ * We treat them identically for now. XXXmcs: we could do some validation on
+ * Boolean and GeneralizedTime values (someday, maybe).
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+static int cis_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
+static int cis_filter_sub( Slapi_PBlock *pb, char *initial, char **any,
+ char *final, Slapi_Value **bvals );
+static int cis_values2keys( Slapi_PBlock *pb, Slapi_Value **val,
+ Slapi_Value ***ivals, int ftype );
+static int cis_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
+ Slapi_Value ***ivals, int ftype );
+static int cis_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
+ char *final, Slapi_Value ***ivals );
+static int cis_compare(struct berval *v1, struct berval *v2);
+
+/*
+ * Attribute syntaxes. We treat all of these the same for now, even though
+ * the specifications (e.g., RFC 2252) impose various constraints on the
+ * the format for each of these.
+ *
+ * Note: the first name is the official one from RFC 2252.
+ */
+static char *dirstring_names[] = { "DirectoryString", "cis",
+ "caseignorestring", DIRSTRING_SYNTAX_OID, 0 };
+
+static char *boolean_names[] = { "Boolean", BOOLEAN_SYNTAX_OID, 0 };
+
+static char *time_names[] = { "GeneralizedTime", "time",
+ GENERALIZEDTIME_SYNTAX_OID, 0 };
+
+static char *country_names[] = { "Country String",
+ COUNTRYSTRING_SYNTAX_OID, 0};
+
+static char *postal_names[] = { "Postal Address",
+ POSTALADDRESS_SYNTAX_OID, 0};
+
+static char *oid_names[] = { "OID",
+ OID_SYNTAX_OID, 0};
+
+
+/*
+ TBD (XXX)
+
+ "1.3.6.1.4.1.1466.115.121.1.16 \"DIT Content Rule Description
+\" "
+ "1.3.6.1.4.1.1466.115.121.1.17 \"DIT Structure Rule Descripti
+on\" "
+ "1.3.6.1.4.1.1466.115.121.1.20 \"DSE Type\" "
+ "1.3.6.1.4.1.1466.115.121.1.30 \"Matching Rule Description\"
+"
+ "1.3.6.1.4.1.1466.115.121.1.31 \"Matching Rule Use Descriptio
+n\" "
+ "1.3.6.1.4.1.1466.115.121.1.35 \"Name Form Description\" "
+
+ "1.3.6.1.4.1.1466.115.121.1.44 \"Printable String\" "
+ "1.3.6.1.4.1.1466.115.121.1.45 \"Subtree Specification\" "
+ "1.3.6.1.4.1.1466.115.121.1.54 \"LDAP Syntax Description\" "
+ "1.3.6.1.4.1.1466.115.121.1.55 \"Modify Rights\" "
+ "1.3.6.1.4.1.1466.115.121.1.56 \"LDAP Schema Description\" "
+ "1.3.6.1.4.1.1466.115.121.1.25 \"Guide\" "
+ "1.3.6.1.4.1.1466.115.121.1.52 \"Telex Number\" "
+ "1.3.6.1.4.1.1466.115.121.1.51 \"Teletex Terminal Identifier\
+" "
+ "1.3.6.1.4.1.1466.115.121.1.14 \"Delivery Method\" "
+ "1.3.6.1.4.1.1466.115.121.1.43 \"Presentation Address\" "
+ "1.3.6.1.4.1.1466.115.121.1.21 \"Enhanced Guide\" "
+ "1.3.6.1.4.1.1466.115.121.1.34 \"Name and Optional UID\" "
+ "1.2.840.113556.1.4.905 \"CaseIgnoreString\" "
+ "1.3.6.1.1.1.0.0 \"nisNetgroupTripleSyntax\" "
+ "1.3.6.1.1.1.0.1 \"bootParameterSyntax\" ");
+ */
+
+
+static Slapi_PluginDesc dirstring_pdesc = { "directorystring-syntax",
+ PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "DirectoryString attribute syntax plugin" };
+
+static Slapi_PluginDesc boolean_pdesc = { "boolean-syntax",
+ PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "Boolean attribute syntax plugin" };
+
+static Slapi_PluginDesc time_pdesc = { "time-syntax",
+ PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "GeneralizedTime attribute syntax plugin" };
+
+static Slapi_PluginDesc country_pdesc = { "countrystring-syntax",
+ PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "Country String attribute syntax plugin" };
+
+static Slapi_PluginDesc postal_pdesc = { "postaladdress-syntax",
+ PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "Postal Address attribute syntax plugin" };
+
+static Slapi_PluginDesc oid_pdesc = { "oid-syntax",
+ PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "OID attribute syntax plugin" };
+
+
+/*
+ * register_cis_like_plugin(): register all items for a cis-like plugin.
+ */
+static int
+register_cis_like_plugin( Slapi_PBlock *pb, Slapi_PluginDesc *pdescp,
+ char **names, char *oid )
+{
+ int rc, flags;
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *) pdescp );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_AVA,
+ (void *) cis_filter_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_SUB,
+ (void *) cis_filter_sub );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALUES2KEYS,
+ (void *) cis_values2keys );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA,
+ (void *) cis_assertion2keys_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB,
+ (void *) cis_assertion2keys_sub );
+ flags = SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING;
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FLAGS,
+ (void *) &flags );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NAMES,
+ (void *) names );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
+ (void *) oid );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
+ (void *) cis_compare );
+
+ return( rc );
+}
+
+
+int
+cis_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> cis_init\n", 0, 0, 0 );
+ rc = register_cis_like_plugin( pb, &dirstring_pdesc, dirstring_names,
+ DIRSTRING_SYNTAX_OID );
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= cis_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+int
+boolean_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> boolean_init\n", 0, 0, 0 );
+ rc = register_cis_like_plugin( pb, &boolean_pdesc, boolean_names,
+ BOOLEAN_SYNTAX_OID );
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= boolean_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+int
+time_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> time_init\n", 0, 0, 0 );
+ rc = register_cis_like_plugin( pb, &time_pdesc, time_names,
+ GENERALIZEDTIME_SYNTAX_OID );
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= time_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+int
+country_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> country_init\n", 0, 0, 0 );
+ rc = register_cis_like_plugin( pb, &country_pdesc, country_names,
+ COUNTRYSTRING_SYNTAX_OID );
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= country_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+int
+postal_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> postal_init\n", 0, 0, 0 );
+ rc = register_cis_like_plugin( pb, &postal_pdesc, postal_names,
+ POSTALADDRESS_SYNTAX_OID );
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= postal_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+int
+oid_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> oid_init\n", 0, 0, 0 );
+ rc = register_cis_like_plugin( pb, &oid_pdesc, oid_names, OID_SYNTAX_OID );
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= oid_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+
+static int
+cis_filter_ava(
+ Slapi_PBlock *pb,
+ struct berval *bvfilter,
+ Slapi_Value **bvals,
+ int ftype,
+ Slapi_Value **retVal
+)
+{
+ return( string_filter_ava( bvfilter, bvals, SYNTAX_CIS, ftype,
+ retVal ) );
+}
+
+
+static int
+cis_filter_sub(
+ Slapi_PBlock *pb,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value **bvals
+)
+{
+ return( string_filter_sub( pb, initial, any, final, bvals, SYNTAX_CIS ) );
+}
+
+static int
+cis_values2keys(
+ Slapi_PBlock *pb,
+ Slapi_Value **vals,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ return( string_values2keys( pb, vals, ivals, SYNTAX_CIS, ftype ) );
+}
+
+static int
+cis_assertion2keys_ava(
+ Slapi_PBlock *pb,
+ Slapi_Value *val,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ return(string_assertion2keys_ava( pb, val, ivals, SYNTAX_CIS, ftype ));
+}
+
+static int
+cis_assertion2keys_sub(
+ Slapi_PBlock *pb,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value ***ivals
+)
+{
+ return( string_assertion2keys_sub( pb, initial, any, final, ivals,
+ SYNTAX_CIS ) );
+}
+
+static int cis_compare(
+ struct berval *v1,
+ struct berval *v2
+)
+{
+ return value_cmp(v1,v2,SYNTAX_CIS,3 /* Normalise both values */);
+}
diff --git a/ldap/servers/plugins/syntaxes/debug.c b/ldap/servers/plugins/syntaxes/debug.c
new file mode 100644
index 00000000..e4d69202
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/debug.c
@@ -0,0 +1,20 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* debug.c - syntax debug stuff */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
diff --git a/ldap/servers/plugins/syntaxes/dllmain.c b/ldap/servers/plugins/syntaxes/dllmain.c
new file mode 100644
index 00000000..1f7aa331
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/dllmain.c
@@ -0,0 +1,133 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for syntax-plugin DLL
+ */
+#include "ldap.h"
+#include "syntax.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
+
+#ifdef LDAP_DEBUG
+#ifndef _WIN32
+#include <stdarg.h>
+#include <stdio.h>
+
+void LDAPDebug( int level, char* fmt, ... )
+{
+ static char debugBuf[1024];
+
+ if (module_ldap_debug && (*module_ldap_debug & level))
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ _snprintf (debugBuf, sizeof(debugBuf), fmt, ap);
+ va_end (ap);
+
+ OutputDebugString (debugBuf);
+ }
+}
+#endif
+#endif
+
+#ifndef _WIN32
+
+/* The 16-bit version of the RTL does not implement perror() */
+
+#include <stdio.h>
+
+void perror( const char *msg )
+{
+ char buf[128];
+ wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ;
+ OutputDebugString( buf );
+}
+
+#endif
diff --git a/ldap/servers/plugins/syntaxes/dn.c b/ldap/servers/plugins/syntaxes/dn.c
new file mode 100644
index 00000000..e6a90df0
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/dn.c
@@ -0,0 +1,98 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* dn.c - dn syntax routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+static int dn_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
+static int dn_filter_sub( Slapi_PBlock *pb, char *initial, char **any,
+ char *final, Slapi_Value **bvals );
+static int dn_values2keys( Slapi_PBlock *pb, Slapi_Value **vals,
+ Slapi_Value ***ivals, int ftype );
+static int dn_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
+ Slapi_Value ***ivals, int ftype );
+static int dn_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
+ char *final, Slapi_Value ***ivals );
+
+/* the first name is the official one from RFC 2252 */
+static char *names[] = { "DN", DN_SYNTAX_OID, 0 };
+
+static Slapi_PluginDesc pdesc = { "dn-syntax", PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT, "distinguished name attribute syntax plugin" };
+
+int
+dn_init( Slapi_PBlock *pb )
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> dn_init\n", 0, 0, 0 );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_AVA,
+ (void *) dn_filter_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_SUB,
+ (void *) dn_filter_sub );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALUES2KEYS,
+ (void *) dn_values2keys );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA,
+ (void *) dn_assertion2keys_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB,
+ (void *) dn_assertion2keys_sub );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NAMES,
+ (void *) names );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
+ (void *) DN_SYNTAX_OID );
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= dn_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+static int
+dn_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal )
+{
+ return( string_filter_ava( bvfilter, bvals, SYNTAX_CIS | SYNTAX_DN,
+ ftype, retVal ) );
+}
+
+static int
+dn_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
+ Slapi_Value **bvals )
+{
+ return( string_filter_sub( pb, initial, any, final, bvals,
+ SYNTAX_CIS | SYNTAX_DN ) );
+}
+
+static int
+dn_values2keys( Slapi_PBlock *pb, Slapi_Value **vals, Slapi_Value ***ivals,
+ int ftype )
+{
+ return( string_values2keys( pb, vals, ivals, SYNTAX_CIS | SYNTAX_DN,
+ ftype ) );
+}
+
+static int
+dn_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
+ Slapi_Value ***ivals, int ftype )
+{
+ return( string_assertion2keys_ava( pb, val, ivals,
+ SYNTAX_CIS | SYNTAX_DN, ftype ) );
+}
+
+static int
+dn_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
+ Slapi_Value ***ivals )
+{
+ return( string_assertion2keys_sub( pb, initial, any, final, ivals,
+ SYNTAX_CIS | SYNTAX_DN ) );
+}
diff --git a/ldap/servers/plugins/syntaxes/int.c b/ldap/servers/plugins/syntaxes/int.c
new file mode 100644
index 00000000..f81167f2
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/int.c
@@ -0,0 +1,188 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* int.c - integer syntax routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+static int int_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
+static int int_values2keys( Slapi_PBlock *pb, Slapi_Value **val,
+ Slapi_Value ***ivals );
+static int int_assertion2keys( Slapi_PBlock *pb, Slapi_Value *val,
+ Slapi_Value ***ivals, int ftype );
+static int int_compare(struct berval *v1, struct berval *v2);
+static long int_to_canonical( long num );
+
+/* the first name is the official one from RFC 2252 */
+static char *names[] = { "INTEGER", "int", INTEGER_SYNTAX_OID, 0 };
+
+static Slapi_PluginDesc pdesc = { "int-syntax", PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT, "integer attribute syntax plugin" };
+
+int
+int_init( Slapi_PBlock *pb )
+{
+ int rc, flags;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> int_init\n", 0, 0, 0 );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_AVA,
+ (void *) int_filter_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALUES2KEYS,
+ (void *) int_values2keys );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA,
+ (void *) int_assertion2keys );
+ flags = SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING;
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FLAGS,
+ (void *) &flags );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NAMES,
+ (void *) names );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
+ (void *) INTEGER_SYNTAX_OID );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
+ (void *) int_compare );
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= int_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+static int
+int_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal )
+{
+ int i, rc;
+ long flong, elong;
+
+ if ( ftype == LDAP_FILTER_APPROX ) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+ if(retVal) {
+ *retVal=NULL;
+ }
+ flong = atol( bvfilter->bv_val );
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ elong = atol ( slapi_value_get_string(bvals[i]) );
+ rc = elong - flong;
+ switch ( ftype ) {
+ case LDAP_FILTER_GE:
+ if ( rc >= 0 ) {
+ if(retVal) {
+ *retVal = bvals[i];
+ }
+ return( 0 );
+ }
+ break;
+ case LDAP_FILTER_LE:
+ if ( rc <= 0 ) {
+ if(retVal) {
+ *retVal = bvals[i];
+ }
+ return( 0 );
+ }
+ break;
+ case LDAP_FILTER_EQUALITY:
+ if ( rc == 0 ) {
+ if(retVal) {
+ *retVal = bvals[i];
+ }
+ return( 0 );
+ }
+ break;
+ }
+ }
+
+ return( -1 );
+}
+
+static int
+int_values2keys( Slapi_PBlock *pb, Slapi_Value **vals, Slapi_Value ***ivals )
+{
+ long num;
+ int i;
+
+ for ( i = 0; vals[i] != NULL; i++ ) {
+ /* NULL */
+ }
+
+ *ivals = (Slapi_Value **) slapi_ch_malloc(( i + 1 ) * sizeof(Slapi_Value *) );
+
+ for ( i = 0; vals[i] != NULL; i++ )
+ {
+ num = atol( slapi_value_get_string(vals[i]) );
+ num = int_to_canonical( num );
+ (*ivals)[i] = slapi_value_new();
+ slapi_value_set((*ivals)[i],&num,sizeof(long));
+ }
+ (*ivals)[i] = NULL;
+
+ return( 0 );
+}
+
+static int
+int_assertion2keys( Slapi_PBlock *pb, Slapi_Value *val, Slapi_Value ***ivals, int ftype )
+{
+ long num;
+ size_t len;
+ unsigned char *b;
+ Slapi_Value *tmpval=NULL;
+
+ num = atol( slapi_value_get_string(val) );
+ num = int_to_canonical( num );
+ /* similar to string.c to optimize equality path: avoid malloc/free */
+ if(ftype == LDAP_FILTER_EQUALITY_FAST) {
+ len=sizeof(long);
+ tmpval=(*ivals)[0];
+ if ( len > tmpval->bv.bv_len) {
+ tmpval->bv.bv_val=(char *)slapi_ch_malloc(len);
+ }
+ tmpval->bv.bv_len=len;
+ b = (unsigned char *)&num;
+ memcpy(tmpval->bv.bv_val,b,len);
+ } else {
+ *ivals = (Slapi_Value **) slapi_ch_malloc( 2 * sizeof(Slapi_Value *) );
+ (*ivals)[0] = (Slapi_Value *) slapi_ch_malloc( sizeof(Slapi_Value) );
+ /* XXXSD initialize memory */
+ memset((*ivals)[0],0,sizeof(Slapi_Value));
+ slapi_value_set((*ivals)[0],&num,sizeof(long));
+ (*ivals)[1] = NULL;
+ }
+ return( 0 );
+}
+
+static int int_compare(
+ struct berval *v1,
+ struct berval *v2
+)
+{
+ long value1 = atol(v1->bv_val);
+ long value2 = atol(v2->bv_val);
+
+ if (value1 == value2) {
+ return 0;
+ }
+ return ( ((value1 - value2) > 0) ? 1 : -1);
+}
+
+static long
+int_to_canonical( long num )
+{
+ long ret = 0L;
+ unsigned char *b = (unsigned char *)&ret;
+
+ b[0] = (unsigned char)(num >> 24);
+ b[1] = (unsigned char)(num >> 16);
+ b[2] = (unsigned char)(num >> 8);
+ b[3] = (unsigned char)num;
+
+ return ret;
+}
diff --git a/ldap/servers/plugins/syntaxes/libsyntax.def b/ldap/servers/plugins/syntaxes/libsyntax.def
new file mode 100644
index 00000000..30cb6b40
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/libsyntax.def
@@ -0,0 +1,24 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Directory Server 7 syntaxes Plugin'
+EXPORTS
+ cis_init @2
+ ces_init @3
+ tel_init @4
+ dn_init @5
+ bin_init @6
+ int_init @7
+ plugin_init_debug_level @8
+ octetstring_init @9
+ boolean_init @10
+ time_init @11
+ uri_init @12
+ country_init @13
+ postal_init @14
+ jpeg_init @15
+ oid_init @16
+ sicis_init @17
diff --git a/ldap/servers/plugins/syntaxes/phonetic.c b/ldap/servers/plugins/syntaxes/phonetic.c
new file mode 100644
index 00000000..1c1c8ba5
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/phonetic.c
@@ -0,0 +1,461 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* phonetic.c - routines to do phonetic matching */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include "syntax.h"
+#include "portable.h"
+
+#if !defined(METAPHONE) && !defined(SOUNDEX)
+#define METAPHONE
+#endif
+
+#define iswordbreak(s) \
+(isascii(*(s)) \
+? (isspace(*(s)) || \
+ ispunct(*(s)) || \
+ isdigit(*(s)) || \
+ *(s) == '\0') \
+: utf8iswordbreak(s))
+
+static int
+utf8iswordbreak( const char* s )
+{
+ switch( LDAP_UTF8GETCC( s )) {
+ case 0x00A0: /* non-breaking space */
+ case 0x3000: /* ideographic space */
+ case 0xFEFF: /* zero-width non-breaking space */
+ return 1;
+ default: break;
+ }
+ return 0;
+}
+
+char *
+first_word( char *s )
+{
+ if ( s == NULL ) {
+ return( NULL );
+ }
+
+ while ( iswordbreak( s ) ) {
+ if ( *s == '\0' ) {
+ return( NULL );
+ } else {
+ LDAP_UTF8INC( s );
+ }
+ }
+
+ return( s );
+}
+
+char *
+next_word( char *s )
+{
+ if ( s == NULL ) {
+ return( NULL );
+ }
+
+ while ( ! iswordbreak( s ) ) {
+ LDAP_UTF8INC( s );
+ }
+
+ while ( iswordbreak( s ) ) {
+ if ( *s == '\0' ) {
+ return( NULL );
+ } else {
+ LDAP_UTF8INC( s );
+ }
+ }
+
+ return( s );
+}
+
+char *
+word_dup( char *w )
+{
+ char *s, *ret;
+ char save;
+
+ for ( s = w; !iswordbreak( s ); LDAP_UTF8INC( s ))
+ ; /* NULL */
+ save = *s;
+ *s = '\0';
+ ret = slapi_ch_strdup( w );
+ *s = save;
+
+ return( ret );
+}
+
+#ifndef MAXPHONEMELEN
+#define MAXPHONEMELEN 4
+#endif
+
+#if defined(SOUNDEX)
+
+/* lifted from isode-8.0 */
+char *
+phonetic( char *s )
+{
+ char code, adjacent, ch;
+ char *p;
+ char **c;
+ int i, cmax;
+ char phoneme[MAXPHONEMELEN + 1];
+
+ p = s;
+ if ( p == NULL || *p == '\0' ) {
+ return( NULL );
+ }
+
+ adjacent = '0';
+ phoneme[0] = TOUPPER(*p);
+
+ phoneme[1] = '\0';
+ for ( i = 0; i < 99 && (! iswordbreak(p)); LDAP_UTF8INC( p )) {
+ ch = TOUPPER (*p);
+
+ code = '0';
+
+ switch (ch) {
+ case 'B':
+ case 'F':
+ case 'P':
+ case 'V':
+ code = (adjacent != '1') ? '1' : '0';
+ break;
+ case 'S':
+ case 'C':
+ case 'G':
+ case 'J':
+ case 'K':
+ case 'Q':
+ case 'X':
+ case 'Z':
+ code = (adjacent != '2') ? '2' : '0';
+ break;
+ case 'D':
+ case 'T':
+ code = (adjacent != '3') ? '3' : '0';
+ break;
+ case 'L':
+ code = (adjacent != '4') ? '4' : '0';
+ break;
+ case 'M':
+ case 'N':
+ code = (adjacent != '5') ? '5' : '0';
+ break;
+ case 'R':
+ code = (adjacent != '6') ? '6' : '0';
+ break;
+ default:
+ adjacent = '0';
+ }
+
+ if ( i == 0 ) {
+ adjacent = code;
+ i++;
+ } else if ( code != '0' ) {
+ if ( i == MAXPHONEMELEN )
+ break;
+ adjacent = phoneme[i] = code;
+ i++;
+ }
+ }
+
+ if ( i > 0 )
+ phoneme[i] = '\0';
+
+ return( slapi_ch_strdup( phoneme ) );
+}
+
+#else
+#if defined(METAPHONE)
+
+/*
+ * Metaphone copied from C Gazette, June/July 1991, pp 56-57,
+ * author Gary A. Parker, with changes by Bernard Tiffany of the
+ * University of Michigan, and more changes by Tim Howes of the
+ * University of Michigan.
+ */
+
+/* Character coding array */
+static char vsvfn[26] = {
+ 1, 16, 4, 16, 9, 2, 4, 16, 9, 2, 0, 2, 2,
+ /* A B C D E F G H I J K L M */
+ 2, 1, 4, 0, 2, 4, 4, 1, 0, 0, 0, 8, 0};
+ /* N O P Q R S T U V W X Y Z */
+
+/* Macros to access character coding array */
+#define vowel(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 1) /* AEIOU */
+#define same(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 2) /* FJLMNR */
+#define varson(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 4) /* CGPST */
+#define frontv(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 8) /* EIY */
+#define noghf(x) ((x) != '\0' && vsvfn[(x) - 'A'] & 16) /* BDH */
+
+char *
+phonetic( char *Word )
+{
+ char *n, *n_start, *n_end; /* pointers to string */
+ char *metaph_end; /* pointers to metaph */
+ char ntrans[42]; /* word with uppercase letters */
+ int KSflag; /* state flag for X -> KS */
+ char buf[MAXPHONEMELEN + 2];
+ char *Metaph;
+
+ /*
+ * Copy Word to internal buffer, dropping non-alphabetic characters
+ * and converting to upper case
+ */
+ n = ntrans + 4; n_end = ntrans + 35;
+ while (!iswordbreak( Word ) && n < n_end) {
+ if (isascii(*Word)) {
+ if (isalpha(*Word)) {
+ *n++ = TOUPPER(*Word);
+ }
+ ++Word;
+ } else {
+ auto const size_t len = LDAP_UTF8COPY(n, Word);
+ n += len; Word += len;
+ }
+ }
+ Metaph = buf;
+ *Metaph = '\0';
+ if (n == ntrans + 4) {
+ return( slapi_ch_strdup( buf ) ); /* Return if null */
+ }
+ n_end = n; /* Set n_end to end of string */
+
+ /* ntrans[0] will always be == 0 */
+ ntrans[0] = '\0';
+ ntrans[1] = '\0';
+ ntrans[2] = '\0';
+ ntrans[3] = '\0';
+ *n++ = 0;
+ *n++ = 0;
+ *n++ = 0;
+ *n = 0; /* Pad with nulls */
+ n = ntrans + 4; /* Assign pointer to start */
+
+ /* Check for PN, KN, GN, AE, WR, WH, and X at start */
+ switch (*n) {
+ case 'P':
+ case 'K':
+ case 'G':
+ /* 'PN', 'KN', 'GN' becomes 'N' */
+ if (*(n + 1) == 'N')
+ *n++ = 0;
+ break;
+ case 'A':
+ /* 'AE' becomes 'E' */
+ if (*(n + 1) == 'E')
+ *n++ = 0;
+ break;
+ case 'W':
+ /* 'WR' becomes 'R', and 'WH' to 'H' */
+ if (*(n + 1) == 'R')
+ *n++ = 0;
+ else if (*(n + 1) == 'H') {
+ *(n + 1) = *n;
+ *n++ = 0;
+ }
+ break;
+ case 'X':
+ /* 'X' becomes 'S' */
+ *n = 'S';
+ break;
+ }
+
+ /*
+ * Now, loop step through string, stopping at end of string or when
+ * the computed 'metaph' is MAXPHONEMELEN characters long
+ */
+
+ KSflag = 0; /* state flag for KS translation */
+ for (metaph_end = Metaph + MAXPHONEMELEN, n_start = n;
+ n <= n_end && Metaph < metaph_end; n++) {
+ if (KSflag) {
+ KSflag = 0;
+ *Metaph++ = 'S';
+ } else if (!isascii(*n)) {
+ *Metaph++ = *n;
+ } else {
+ /* Drop duplicates except for CC */
+ if (*(n - 1) == *n && *n != 'C')
+ continue;
+ /* Check for F J L M N R or first letter vowel */
+ if (same(*n) || (n == n_start && vowel(*n))) {
+ *Metaph++ = *n;
+ } else {
+ switch (*n) {
+ case 'B':
+
+ /*
+ * B unless in -MB
+ */
+ if (n < (n_end - 1) && *(n - 1) != 'M') {
+ *Metaph++ = *n;
+ }
+ break;
+ case 'C':
+
+ /*
+ * X if in -CIA-, -CH- else S if in
+ * -CI-, -CE-, -CY- else dropped if
+ * in -SCI-, -SCE-, -SCY- else K
+ */
+ if (*(n - 1) != 'S' || !frontv(*(n + 1))) {
+ if (*(n + 1) == 'I' && *(n + 2) == 'A') {
+ *Metaph++ = 'X';
+ } else if (frontv(*(n + 1))) {
+ *Metaph++ = 'S';
+ } else if (*(n + 1) == 'H') {
+ *Metaph++ = ((n == n_start && !vowel(*(n + 2)))
+ || *(n - 1) == 'S')
+ ? (char) 'K' : (char) 'X';
+ } else {
+ *Metaph++ = 'K';
+ }
+ }
+ break;
+ case 'D':
+
+ /*
+ * J if in DGE or DGI or DGY else T
+ */
+ *Metaph++ = (*(n + 1) == 'G' && frontv(*(n + 2)))
+ ? (char) 'J' : (char) 'T';
+ break;
+ case 'G':
+
+ /*
+ * F if in -GH and not B--GH, D--GH,
+ * -H--GH, -H---GH else dropped if
+ * -GNED, -GN, -DGE-, -DGI-, -DGY-
+ * else J if in -GE-, -GI-, -GY- and
+ * not GG else K
+ */
+ if ((*(n + 1) != 'J' || vowel(*(n + 2))) &&
+ (*(n + 1) != 'N' || ((n + 1) < n_end &&
+ (*(n + 2) != 'E' || *(n + 3) != 'D'))) &&
+ (*(n - 1) != 'D' || !frontv(*(n + 1))))
+ *Metaph++ = (frontv(*(n + 1)) &&
+ *(n + 2) != 'G') ? (char) 'G' : (char) 'K';
+ else if (*(n + 1) == 'H' && !noghf(*(n - 3)) &&
+ *(n - 4) != 'H')
+ *Metaph++ = 'F';
+ break;
+ case 'H':
+
+ /*
+ * H if before a vowel and not after
+ * C, G, P, S, T else dropped
+ */
+ if (!varson(*(n - 1)) && (!vowel(*(n - 1)) ||
+ vowel(*(n + 1))))
+ *Metaph++ = 'H';
+ break;
+ case 'K':
+
+ /*
+ * dropped if after C else K
+ */
+ if (*(n - 1) != 'C')
+ *Metaph++ = 'K';
+ break;
+ case 'P':
+
+ /*
+ * F if before H, else P
+ */
+ *Metaph++ = *(n + 1) == 'H' ?
+ (char) 'F' : (char) 'P';
+ break;
+ case 'Q':
+
+ /*
+ * K
+ */
+ *Metaph++ = 'K';
+ break;
+ case 'S':
+
+ /*
+ * X in -SH-, -SIO- or -SIA- else S
+ */
+ *Metaph++ = (*(n + 1) == 'H' ||
+ (*(n + 1) == 'I' && (*(n + 2) == 'O' ||
+ *(n + 2) == 'A')))
+ ? (char) 'X' : (char) 'S';
+ break;
+ case 'T':
+
+ /*
+ * X in -TIA- or -TIO- else 0 (zero)
+ * before H else dropped if in -TCH-
+ * else T
+ */
+ if (*(n + 1) == 'I' && (*(n + 2) == 'O' ||
+ *(n + 2) == 'A'))
+ *Metaph++ = 'X';
+ else if (*(n + 1) == 'H')
+ *Metaph++ = '0';
+ else if (*(n + 1) != 'C' || *(n + 2) != 'H')
+ *Metaph++ = 'T';
+ break;
+ case 'V':
+
+ /*
+ * F
+ */
+ *Metaph++ = 'F';
+ break;
+ case 'W':
+
+ /*
+ * W after a vowel, else dropped
+ */
+ case 'Y':
+
+ /*
+ * Y unless followed by a vowel
+ */
+ if (vowel(*(n + 1)))
+ *Metaph++ = *n;
+ break;
+ case 'X':
+
+ /*
+ * KS
+ */
+ if (n == n_start)
+ *Metaph++ = 'S';
+ else {
+ *Metaph++ = 'K'; /* Insert K, then S */
+ KSflag = 1;
+ }
+ break;
+ case 'Z':
+
+ /*
+ * S
+ */
+ *Metaph++ = 'S';
+ break;
+ }
+ }
+ }
+ }
+
+ *Metaph = 0; /* Null terminate */
+ return( slapi_ch_strdup( buf ) );
+}
+
+#endif /* METAPHONE */
+#endif /* !SOUNDEX */
diff --git a/ldap/servers/plugins/syntaxes/sicis.c b/ldap/servers/plugins/syntaxes/sicis.c
new file mode 100644
index 00000000..4bd6623d
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/sicis.c
@@ -0,0 +1,139 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2002 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * sicis.c - space insensitive string syntax routines.
+ * these strings are also case insensitive.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+static int sicis_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
+static int sicis_filter_sub( Slapi_PBlock *pb, char *initial, char **any,
+ char *final, Slapi_Value **bvals );
+static int sicis_values2keys( Slapi_PBlock *pb, Slapi_Value **val,
+ Slapi_Value ***ivals, int ftype );
+static int sicis_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
+ Slapi_Value ***ivals, int ftype );
+static int sicis_assertion2keys_sub( Slapi_PBlock *pb, char *initial,
+ char **any, char *final, Slapi_Value ***ivals );
+static int sicis_compare(struct berval *v1, struct berval *v2);
+
+/* the first name is the official one from RFC 2252 */
+static char *names[] = { "SpaceInsensitiveString",
+ SPACE_INSENSITIVE_STRING_SYNTAX_OID, 0 };
+
+static Slapi_PluginDesc pdesc = { "spaceinsensitivestring-syntax",
+ PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "space insensitive string attribute syntax plugin" };
+
+int
+sicis_init( Slapi_PBlock *pb )
+{
+ int rc, flags;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> sicis_init\n", 0, 0, 0 );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_AVA,
+ (void *) sicis_filter_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_SUB,
+ (void *) sicis_filter_sub );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALUES2KEYS,
+ (void *) sicis_values2keys );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA,
+ (void *) sicis_assertion2keys_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB,
+ (void *) sicis_assertion2keys_sub );
+ flags = SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING;
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FLAGS,
+ (void *) &flags );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NAMES,
+ (void *) names );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
+ (void *) SPACE_INSENSITIVE_STRING_SYNTAX_OID );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
+ (void *) sicis_compare );
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= sicis_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+static int
+sicis_filter_ava(
+ Slapi_PBlock *pb,
+ struct berval *bvfilter,
+ Slapi_Value **bvals,
+ int ftype,
+ Slapi_Value **retVal
+)
+{
+ return( string_filter_ava( bvfilter, bvals, SYNTAX_SI | SYNTAX_CIS,
+ ftype, retVal ) );
+}
+
+
+static int
+sicis_filter_sub(
+ Slapi_PBlock *pb,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value **bvals
+)
+{
+ return( string_filter_sub( pb, initial, any, final, bvals, SYNTAX_SI | SYNTAX_CIS ) );
+}
+
+static int
+sicis_values2keys(
+ Slapi_PBlock *pb,
+ Slapi_Value **vals,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ return( string_values2keys( pb, vals, ivals, SYNTAX_SI | SYNTAX_CIS,
+ ftype ) );
+}
+
+static int
+sicis_assertion2keys_ava(
+ Slapi_PBlock *pb,
+ Slapi_Value *val,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ return(string_assertion2keys_ava( pb, val, ivals,
+ SYNTAX_SI | SYNTAX_CIS, ftype ));
+}
+
+static int
+sicis_assertion2keys_sub(
+ Slapi_PBlock *pb,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value ***ivals
+)
+{
+ return( string_assertion2keys_sub( pb, initial, any, final, ivals,
+ SYNTAX_SI | SYNTAX_CIS ) );
+}
+
+static int sicis_compare(
+ struct berval *v1,
+ struct berval *v2
+)
+{
+ return value_cmp(v1, v2, SYNTAX_SI|SYNTAX_CIS, 3 /* Normalise both values */);
+}
diff --git a/ldap/servers/plugins/syntaxes/string.c b/ldap/servers/plugins/syntaxes/string.c
new file mode 100644
index 00000000..d06a15f5
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/string.c
@@ -0,0 +1,612 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* string.c - common string syntax routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+#if defined(IRIX)
+#include <unistd.h>
+#endif
+#if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX )
+#include "regex.h"
+#endif
+
+static int string_filter_approx( struct berval *bvfilter,
+ Slapi_Value **bvals, Slapi_Value **retVal );
+static void substring_comp_keys( Slapi_Value ***ivals, int *nsubs, char *str,
+ int prepost, int syntax );
+
+int
+string_filter_ava( struct berval *bvfilter, Slapi_Value **bvals, int syntax,
+ int ftype, Slapi_Value **retVal )
+{
+ int i, rc;
+ struct berval bvfilter_norm;
+
+ if(retVal) {
+ *retVal = NULL;
+ }
+ if ( ftype == LDAP_FILTER_APPROX ) {
+ return( string_filter_approx( bvfilter, bvals, retVal ) );
+ }
+
+ bvfilter_norm.bv_val = slapi_ch_malloc( bvfilter->bv_len + 1 );
+ SAFEMEMCPY( bvfilter_norm.bv_val, bvfilter->bv_val, bvfilter->bv_len );
+ bvfilter_norm.bv_val[bvfilter->bv_len] = '\0';
+ value_normalize( bvfilter_norm.bv_val, syntax, 1 /* trim leading blanks */ );
+
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ rc = value_cmp( (struct berval*)slapi_value_get_berval(bvals[i]), &bvfilter_norm, syntax, 1/* Normalise the first value only */ );
+ switch ( ftype ) {
+ case LDAP_FILTER_GE:
+ if ( rc >= 0 ) {
+ if(retVal) {
+ *retVal = bvals[i];
+ }
+ slapi_ch_free ((void**)&bvfilter_norm.bv_val);
+ return( 0 );
+ }
+ break;
+ case LDAP_FILTER_LE:
+ if ( rc <= 0 ) {
+ if(retVal) {
+ *retVal = bvals[i];
+ }
+ slapi_ch_free ((void**)&bvfilter_norm.bv_val);
+ return( 0 );
+ }
+ break;
+ case LDAP_FILTER_EQUALITY:
+ if ( rc == 0 ) {
+ if(retVal) {
+ *retVal = bvals[i];
+ }
+ slapi_ch_free ((void**)&bvfilter_norm.bv_val);
+ return( 0 );
+ }
+ break;
+ }
+ }
+
+ slapi_ch_free ((void**)&bvfilter_norm.bv_val);
+ return( -1 );
+}
+
+static int
+string_filter_approx( struct berval *bvfilter, Slapi_Value **bvals,
+ Slapi_Value **retVal)
+{
+ int i, rc;
+ int ava_wordcount;
+ char *w1, *w2, *c1, *c2;
+
+ /*
+ * try to match words in each filter value in order
+ * in the attribute value.
+ * XXX should do this once for the filter and save it XXX
+ */
+ rc = -1;
+ if(retVal) {
+ *retVal = NULL;
+ }
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ w2 = (char*)slapi_value_get_string(bvals[i]); /* JCM cast */
+ ava_wordcount = 0;
+ /* for each word in the filter value */
+ for ( w1 = first_word( bvfilter->bv_val ); w1 != NULL;
+ w1 = next_word( w1 ) ) {
+ ++ava_wordcount;
+ if ( (c1 = phonetic( w1 )) == NULL ) {
+ break;
+ }
+
+ /*
+ * for each word in the attribute value from
+ * where we left off...
+ */
+ for ( w2 = first_word( w2 ); w2 != NULL;
+ w2 = next_word( w2 ) ) {
+ c2 = phonetic( w2 );
+ rc = strcmp( c1, c2 );
+ slapi_ch_free((void**)&c2 );
+ if ( rc == 0 ) {
+ if(retVal) {
+ *retVal = bvals[i];
+ }
+ break;
+ }
+ }
+ slapi_ch_free((void**)&c1 );
+
+ /*
+ * if we stopped because we ran out of words
+ * before making a match, go on to the next
+ * value. otherwise try to keep matching
+ * words in this value from where we left off.
+ */
+ if ( w2 == NULL ) {
+ break;
+ } else {
+ w2 = next_word( w2 );
+ }
+ }
+ /*
+ * if we stopped because we ran out of words and
+ * we found at leasy one word, we have a match.
+ */
+ if ( w1 == NULL && ava_wordcount > 0 ) {
+ rc = 0;
+ break;
+ }
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= string_filter_approx %d\n",
+ rc, 0, 0 );
+
+ return( rc );
+}
+
+int
+string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,
+ Slapi_Value **bvals, int syntax )
+{
+ int i, j, rc;
+ char *p, *end, *realval, *tmpbuf;
+ size_t tmpbufsize;
+ char pat[BUFSIZ];
+ char buf[BUFSIZ];
+ char ebuf[BUFSIZ];
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> string_filter_sub\n",
+ 0, 0, 0 );
+
+ /*
+ * construct a regular expression corresponding to the
+ * filter and let regex do the work for each value
+ * XXX should do this once and save it somewhere XXX
+ */
+ pat[0] = '\0';
+ p = pat;
+ end = pat + sizeof(pat) - 2; /* leave room for null */
+ if ( initial != NULL ) {
+ value_normalize( initial, syntax, 1 /* trim leading blanks */ );
+ strcpy( p, "^" );
+ p = strchr( p, '\0' );
+ /* 2 * in case every char is special */
+ if ( p + 2 * strlen( initial ) > end ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "not enough pattern space\n",
+ 0, 0, 0 );
+ return( -1 );
+ }
+ filter_strcpy_special( p, initial );
+ p = strchr( p, '\0' );
+ }
+ if ( any != NULL ) {
+ for ( i = 0; any[i] != NULL; i++ ) {
+ value_normalize( any[i], syntax, 0 /* DO NOT trim leading blanks */ );
+ /* ".*" + value */
+ if ( p + 2 * strlen( any[i] ) + 2 > end ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "not enough pattern space\n", 0, 0, 0 );
+ return( -1 );
+ }
+ strcpy( p, ".*" );
+ p = strchr( p, '\0' );
+ filter_strcpy_special( p, any[i] );
+ p = strchr( p, '\0' );
+ }
+ }
+ if ( final != NULL ) {
+ value_normalize( final, syntax, 0 /* DO NOT trim leading blanks */ );
+ /* ".*" + value */
+ if ( p + 2 * strlen( final ) + 2 > end ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "not enough pattern space\n",
+ 0, 0, 0 );
+ return( -1 );
+ }
+ strcpy( p, ".*" );
+ p = strchr( p, '\0' );
+ filter_strcpy_special( p, final );
+ p = strchr( p, '\0' );
+ strcpy( p, "$" );
+ }
+
+ /* compile the regex */
+ slapd_re_lock();
+ if ( (p = slapd_re_comp( pat )) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "re_comp (%s) failed (%s)\n",
+ pat, p, 0 );
+ slapd_re_unlock();
+ return( -1 );
+ } else {
+ LDAPDebug( LDAP_DEBUG_TRACE, "re_comp (%s)\n",
+ escape_string( pat, ebuf ), 0, 0 );
+ }
+
+ /*
+ * test the regex against each value
+ */
+ rc = -1;
+ tmpbuf = NULL;
+ tmpbufsize = 0;
+ for ( j = 0; bvals[j] != NULL; j++ ) {
+ int tmprc;
+ size_t len;
+ const struct berval *bvp = slapi_value_get_berval(bvals[j]);
+
+ len = bvp->bv_len;
+ if ( len < sizeof(buf) ) {
+ strcpy( buf, bvp->bv_val );
+ realval = buf;
+ } else if ( len < tmpbufsize ) {
+ strcpy( buf, bvp->bv_val );
+ realval = tmpbuf;
+ } else {
+ tmpbuf = (char *) slapi_ch_realloc( tmpbuf, len + 1 );
+ strcpy( tmpbuf, bvp->bv_val );
+ realval = tmpbuf;
+ }
+ value_normalize( realval, syntax, 1 /* trim leading blanks */ );
+
+ tmprc = slapd_re_exec( realval );
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "re_exec (%s) %i\n",
+ escape_string( realval, ebuf ), tmprc, 0 );
+ if ( tmprc != 0 ) {
+ rc = 0;
+ break;
+ }
+ }
+ slapd_re_unlock();
+ if ( tmpbuf != NULL ) {
+ slapi_ch_free((void**)&tmpbuf );
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= string_filter_sub %d\n",
+ rc, 0, 0 );
+ return( rc );
+}
+
+int
+string_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals,
+ Slapi_Value ***ivals, int syntax, int ftype )
+{
+ int nsubs, numbvals, i, n, j;
+ Slapi_Value **nbvals;
+ char *w, *c, *p;
+ char buf[SUBLEN+1];
+
+ switch ( ftype ) {
+ case LDAP_FILTER_EQUALITY:
+ /* allocate a new array for the normalized values */
+ for ( numbvals = 0; bvals[numbvals] != NULL; numbvals++ ) {
+ /* NULL */
+ }
+ nbvals = (Slapi_Value **) slapi_ch_malloc( (numbvals+1) * sizeof(Slapi_Value *));
+
+ for ( i = 0; i < numbvals; i++ )
+ {
+ c = slapi_ch_strdup(slapi_value_get_string(bvals[i]));
+ value_normalize( c, syntax, 1 /* trim leading blanks */ );
+ nbvals[i] = slapi_value_new_string_passin(c);
+ }
+ nbvals[i] = NULL;
+ *ivals = nbvals;
+ break;
+
+ case LDAP_FILTER_APPROX:
+ /* XXX should not do this twice! XXX */
+ /* get an upper bound on the number of ivals */
+ numbvals = 0;
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ for ( w = first_word( (char*)slapi_value_get_string(bvals[i]) ); w != NULL;
+ w = next_word( w ) ) {
+ numbvals++;
+ }
+ }
+ nbvals = (Slapi_Value **) slapi_ch_malloc( (numbvals + 1) * sizeof(Slapi_Value *) );
+
+ n = 0;
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ for ( w = first_word( (char*)slapi_value_get_string(bvals[i]) ); w != NULL;
+ w = next_word( w ) ) {
+ if ( (c = phonetic( w )) != NULL ) {
+ nbvals[n] = slapi_value_new_string_passin(c);
+ n++;
+ }
+ }
+ }
+ nbvals[n] = NULL;
+
+ if ( n == 0 ) {
+ slapi_ch_free((void**)ivals );
+ return( 0 );
+ }
+ *ivals = nbvals;
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ {
+ /* XXX should remove duplicates! XXX */
+ Slapi_Value *bvdup;
+ const struct berval *bvp;
+ nsubs = 0;
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ /*
+ * Note: this calculation may err on the high side,
+ * because value_normalize(), which is called below
+ * before we actually create the substring keys, may
+ * reduce the length of the value in some cases. For
+ * example, spaces are removed when space insensitive
+ * strings are normalized. But it's okay for nsubs to
+ * be too big. Since the ivals array is NULL terminated,
+ * the only downside is that we allocate more space than
+ * we really need.
+ */
+ nsubs += slapi_value_get_length(bvals[i]) - SUBLEN + 3;
+ }
+ *ivals = (Slapi_Value **) slapi_ch_malloc( (nsubs + 1) * sizeof(Slapi_Value *) );
+
+ buf[SUBLEN] = '\0';
+ n = 0;
+
+ bvdup= slapi_value_new();
+ for ( i = 0; bvals[i] != NULL; i++ )
+ {
+ c = slapi_ch_strdup(slapi_value_get_string(bvals[i]));
+ value_normalize( c, syntax, 1 /* trim leading blanks */ );
+ slapi_value_set_string_passin(bvdup, c);
+
+ bvp = slapi_value_get_berval(bvdup);
+
+ /* leading */
+ if ( bvp->bv_len > SUBLEN - 2 ) {
+ buf[0] = '^';
+ for ( j = 0; j < SUBLEN - 1; j++ ) {
+ buf[j + 1] = bvp->bv_val[j];
+ }
+ (*ivals)[n] = slapi_value_new_string(buf);
+ n++;
+ }
+
+ /* any */
+ for ( p = bvp->bv_val;
+ p < (bvp->bv_val + bvp->bv_len - SUBLEN + 1);
+ p++ ) {
+ for ( j = 0; j < SUBLEN; j++ ) {
+ buf[j] = p[j];
+ }
+ buf[SUBLEN] = '\0';
+ (*ivals)[n] = slapi_value_new_string(buf);
+ n++;
+ }
+
+ /* trailing */
+ if ( bvp->bv_len > SUBLEN - 2 ) {
+ p = bvp->bv_val + bvp->bv_len - SUBLEN + 1;
+ for ( j = 0; j < SUBLEN - 1; j++ ) {
+ buf[j] = p[j];
+ }
+ buf[SUBLEN - 1] = '$';
+ (*ivals)[n] = slapi_value_new_string(buf);
+ n++;
+ }
+ }
+ slapi_value_free(&bvdup);
+ (*ivals)[n] = NULL;
+ }
+ break;
+ }
+
+ return( 0 );
+}
+
+
+/* we've added code to make our equality filter processing faster */
+
+int
+string_assertion2keys_ava(
+ Slapi_PBlock *pb,
+ Slapi_Value *val,
+ Slapi_Value ***ivals,
+ int syntax,
+ int ftype
+)
+{
+ int i, numbvals;
+ size_t len;
+ char *w, *c;
+ Slapi_Value *tmpval=NULL;
+
+ switch ( ftype ) {
+ case LDAP_FILTER_EQUALITY_FAST:
+ /* this code is trying to avoid multiple malloc/frees */
+ len=slapi_value_get_length(val);
+ tmpval=(*ivals)[0];
+ if (len >= tmpval->bv.bv_len) {
+ tmpval->bv.bv_val=(char *)slapi_ch_malloc(len+1);
+ }
+ memcpy(tmpval->bv.bv_val,slapi_value_get_string(val),len);
+ tmpval->bv.bv_val[len]='\0';
+ value_normalize(tmpval->bv.bv_val, syntax, 1 /* trim leading blanks */ );
+ tmpval->bv.bv_len=strlen(tmpval->bv.bv_val);
+ break;
+ case LDAP_FILTER_EQUALITY:
+ (*ivals) = (Slapi_Value **) slapi_ch_malloc( 2 * sizeof(Slapi_Value *) );
+ (*ivals)[0] = slapi_value_dup( val );
+ value_normalize( (*ivals)[0]->bv.bv_val, syntax, 1 /* trim leading blanks */ );
+ (*ivals)[0]->bv.bv_len = strlen( (*ivals)[0]->bv.bv_val );
+ (*ivals)[1] = NULL;
+ break;
+
+ case LDAP_FILTER_APPROX:
+ /* XXX should not do this twice! XXX */
+ /* get an upper bound on the number of ivals */
+ numbvals = 0;
+ for ( w = first_word( (char*)slapi_value_get_string(val) ); w != NULL;
+ w = next_word( w ) ) {
+ numbvals++;
+ }
+ (*ivals) = (Slapi_Value **) slapi_ch_malloc( (numbvals + 1) *
+ sizeof(Slapi_Value *) );
+
+ i = 0;
+ for ( w = first_word( (char*)slapi_value_get_string(val) ); w != NULL;
+ w = next_word( w ) ) {
+ if ( (c = phonetic( w )) != NULL ) {
+ (*ivals)[i] = slapi_value_new_string_passin(c);
+ i++;
+ }
+ }
+ (*ivals)[i] = NULL;
+
+ if ( i == 0 ) {
+ slapi_ch_free((void**)ivals );
+ return( 0 );
+ }
+ break;
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "string_assertion2keys_ava: unknown ftype 0x%x\n",
+ ftype, 0, 0 );
+ break;
+ }
+
+ return( 0 );
+}
+
+int
+string_assertion2keys_sub(
+ Slapi_PBlock *pb,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value ***ivals,
+ int syntax
+)
+{
+ int nsubs, i, len;
+
+ *ivals = NULL;
+
+ /*
+ * First figure out how many keys we will return. The answer is based
+ * on the length of each assertion value. Since normalization may
+ * reduce the length (such as when spaces are removed from space
+ * insensitive strings), we call value_normalize() before checking
+ * the length.
+ */
+ nsubs = 0;
+ if ( initial != NULL ) {
+ value_normalize( initial, syntax, 0 /* do not trim leading blanks */ );
+ if ( strlen( initial ) > SUBLEN - 2 ) {
+ nsubs += strlen( initial ) - SUBLEN + 2;
+ } else {
+ initial = NULL; /* save some work later */
+ }
+ }
+ for ( i = 0; any != NULL && any[i] != NULL; i++ ) {
+ value_normalize( any[i], syntax, 0 /* do not trim leading blanks */ );
+ len = strlen( any[i] );
+ if ( len >= SUBLEN ) {
+ nsubs += len - SUBLEN + 1;
+ }
+ }
+ if ( final != NULL ) {
+ value_normalize( final, syntax, 0 /* do not trim leading blanks */ );
+ if ( strlen( final ) > SUBLEN - 2 ) {
+ nsubs += strlen( final ) - SUBLEN + 2;
+ } else {
+ final = NULL; /* save some work later */
+ }
+ }
+ if ( nsubs == 0 ) { /* no keys to return */
+ return( 0 );
+ }
+
+ /*
+ * Next, allocated the ivals array and fill it in with the actual
+ * keys. *ivals is a NULL terminated array of Slapi_Value pointers.
+ */
+
+ *ivals = (Slapi_Value **) slapi_ch_malloc( (nsubs + 1) * sizeof(Slapi_Value *) );
+
+ nsubs = 0;
+ if ( initial != NULL ) {
+ substring_comp_keys( ivals, &nsubs, initial, '^', syntax );
+ }
+ for ( i = 0; any != NULL && any[i] != NULL; i++ ) {
+ if ( strlen( any[i] ) < SUBLEN ) {
+ continue;
+ }
+ substring_comp_keys( ivals, &nsubs, any[i], 0, syntax );
+ }
+ if ( final != NULL ) {
+ substring_comp_keys( ivals, &nsubs, final, '$', syntax );
+ }
+ (*ivals)[nsubs] = NULL;
+
+ return( 0 );
+}
+
+static void
+substring_comp_keys(
+ Slapi_Value ***ivals,
+ int *nsubs,
+ char *str,
+ int prepost,
+ int syntax
+)
+{
+ int i, len;
+ char *p;
+ char buf[SUBLEN + 1];
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> substring_comp_keys (%s) %d\n",
+ str, prepost, 0 );
+
+ len = strlen( str );
+
+ /* prepend ^ for initial substring */
+ if ( prepost == '^' )
+ {
+ buf[0] = '^';
+ for ( i = 0; i < SUBLEN - 1; i++ )
+ {
+ buf[i + 1] = str[i];
+ }
+ buf[SUBLEN] = '\0';
+ (*ivals)[*nsubs] = slapi_value_new_string(buf);
+ (*nsubs)++;
+ }
+
+ for ( p = str; p < (str + len - SUBLEN + 1); p++ )
+ {
+ for ( i = 0; i < SUBLEN; i++ )
+ {
+ buf[i] = p[i];
+ }
+ buf[SUBLEN] = '\0';
+ (*ivals)[*nsubs] = slapi_value_new_string(buf);
+ (*nsubs)++;
+ }
+
+ if ( prepost == '$' )
+ {
+ p = str + len - SUBLEN + 1;
+ for ( i = 0; i < SUBLEN - 1; i++ )
+ {
+ buf[i] = p[i];
+ }
+ buf[SUBLEN - 1] = '$';
+ buf[SUBLEN] = '\0';
+ (*ivals)[*nsubs] = slapi_value_new_string(buf);
+ (*nsubs)++;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= substring_comp_keys\n", 0, 0, 0 );
+}
diff --git a/ldap/servers/plugins/syntaxes/syntax.h b/ldap/servers/plugins/syntaxes/syntax.h
new file mode 100644
index 00000000..d6d883c9
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/syntax.h
@@ -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 **/
+/* syntax.h - string syntax definitions */
+
+#ifndef _LIBSYNTAX_H_
+#define _LIBSYNTAX_H_
+
+#define SLAPD_LOGGING 1
+
+#include "slap.h"
+#include "slapi-plugin.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+
+#define SYNTAX_CIS 1
+#define SYNTAX_CES 2
+#define SYNTAX_TEL 4 /* telephone number: used with SYNTAX_CIS */
+#define SYNTAX_DN 8 /* distinguished name: used with SYNTAX_CIS */
+#define SYNTAX_SI 16 /* space insensitive: used with SYNTAX_CIS */
+
+#define SUBLEN 3
+
+#ifndef MIN
+#define MIN( a, b ) (a < b ? a : b )
+#endif
+
+int string_filter_sub( Slapi_PBlock *pb, char *initial, char **any, char *final,Slapi_Value **bvals, int syntax );
+int string_filter_ava( struct berval *bvfilter, Slapi_Value **bvals, int syntax,int ftype, Slapi_Value **retVal );
+int string_values2keys( Slapi_PBlock *pb, Slapi_Value **bvals,Slapi_Value ***ivals, int syntax, int ftype );
+int string_assertion2keys_ava(Slapi_PBlock *pb,Slapi_Value *val,Slapi_Value ***ivals,int syntax,int ftype );
+int string_assertion2keys_sub(Slapi_PBlock *pb,char *initial,char **any,char *final,Slapi_Value ***ivals,int syntax);
+int value_cmp(struct berval *v1,struct berval *v2,int syntax,int normalize);
+void value_normalize(char *s,int syntax,int trim_leading_blanks);
+
+char *first_word( char *s );
+char *next_word( char *s );
+char *phonetic( char *s );
+
+
+#endif
diff --git a/ldap/servers/plugins/syntaxes/tel.c b/ldap/servers/plugins/syntaxes/tel.c
new file mode 100644
index 00000000..c2c80d1a
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/tel.c
@@ -0,0 +1,135 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* tel.c - telephonenumber syntax routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+static int tel_filter_ava( Slapi_PBlock *pb, struct berval *bvfilter,
+ Slapi_Value **bvals, int ftype, Slapi_Value **retVal );
+static int tel_filter_sub( Slapi_PBlock *pb, char *initial, char **any,
+ char *final, Slapi_Value **bvals );
+static int tel_values2keys( Slapi_PBlock *pb, Slapi_Value **val,
+ Slapi_Value ***ivals, int ftype );
+static int tel_assertion2keys_ava( Slapi_PBlock *pb, Slapi_Value *val,
+ Slapi_Value ***ivals, int ftype );
+static int tel_assertion2keys_sub( Slapi_PBlock *pb, char *initial, char **any,
+ char *final, Slapi_Value ***ivals );
+static int tel_compare(struct berval *v1, struct berval *v2);
+
+/* the first name is the official one from RFC 2252 */
+static char *names[] = { "TelephoneNumber", "tel", TELEPHONE_SYNTAX_OID, 0 };
+
+static Slapi_PluginDesc pdesc = { "tele-syntax", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "telephoneNumber attribute syntax plugin" };
+
+int
+tel_init( Slapi_PBlock *pb )
+{
+ int rc, flags;
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "=> tel_init\n", 0, 0, 0 );
+
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_AVA,
+ (void *) tel_filter_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FILTER_SUB,
+ (void *) tel_filter_sub );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_VALUES2KEYS,
+ (void *) tel_values2keys );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA,
+ (void *) tel_assertion2keys_ava );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB,
+ (void *) tel_assertion2keys_sub );
+ flags = SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING;
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_FLAGS,
+ (void *) &flags );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_NAMES,
+ (void *) names );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_OID,
+ (void *) TELEPHONE_SYNTAX_OID );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_SYNTAX_COMPARE,
+ (void *) tel_compare );
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "<= tel_init %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+static int
+tel_filter_ava(
+ Slapi_PBlock *pb,
+ struct berval *bvfilter,
+ Slapi_Value **bvals,
+ int ftype,
+ Slapi_Value **retVal
+)
+{
+ return( string_filter_ava( bvfilter, bvals, SYNTAX_TEL | SYNTAX_CIS,
+ ftype, retVal ) );
+}
+
+
+static int
+tel_filter_sub(
+ Slapi_PBlock *pb,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value **bvals
+)
+{
+ return( string_filter_sub( pb, initial, any, final, bvals, SYNTAX_TEL | SYNTAX_CIS ) );
+}
+
+static int
+tel_values2keys(
+ Slapi_PBlock *pb,
+ Slapi_Value **vals,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ return( string_values2keys( pb, vals, ivals, SYNTAX_TEL | SYNTAX_CIS,
+ ftype ) );
+}
+
+static int
+tel_assertion2keys_ava(
+ Slapi_PBlock *pb,
+ Slapi_Value *val,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ return(string_assertion2keys_ava( pb, val, ivals,
+ SYNTAX_TEL | SYNTAX_CIS, ftype ));
+}
+
+static int
+tel_assertion2keys_sub(
+ Slapi_PBlock *pb,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value ***ivals
+)
+{
+ return( string_assertion2keys_sub( pb, initial, any, final, ivals,
+ SYNTAX_TEL | SYNTAX_CIS ) );
+}
+
+static int tel_compare(
+ struct berval *v1,
+ struct berval *v2
+)
+{
+ return value_cmp(v1, v2, SYNTAX_TEL|SYNTAX_CIS, 3 /* Normalise both values */);
+}
diff --git a/ldap/servers/plugins/syntaxes/value.c b/ldap/servers/plugins/syntaxes/value.c
new file mode 100644
index 00000000..be496091
--- /dev/null
+++ b/ldap/servers/plugins/syntaxes/value.c
@@ -0,0 +1,209 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* value.c - routines for dealing with values */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "syntax.h"
+
+/*
+ * Do not use the SDK ldap_utf8isspace directly until it is faster
+ * than this one.
+ */
+static int
+utf8isspace_fast( char* s )
+{
+ register unsigned char c = *(unsigned char*)s;
+ if (0x80 & c) return(ldap_utf8isspace(s));
+ switch (c) {
+ case 0x09:
+ case 0x0A:
+ case 0x0B:
+ case 0x0C:
+ case 0x0D:
+ case 0x20:
+ return 1;
+ default: break;
+ }
+ return 0;
+}
+
+/*
+** This function is used to normalizes search filter components,
+** and attribute values.
+**
+** jcm: I added the trim_spaces flag since this function
+** was incorrectly modifying search filter components. A search
+** of the form "cn=a* b*" (note the space) would be wrongly
+** normalized into "cn=a*b*", because this function is called
+** once for "a" and once for " b".
+*/
+void
+value_normalize(
+ char *s,
+ int syntax,
+ int trim_spaces
+)
+{
+ char *d;
+ int prevspace, curspace;
+
+ if ( ! (syntax & SYNTAX_CIS) && ! (syntax & SYNTAX_CES) ) {
+ return;
+ }
+
+ if ( syntax & SYNTAX_DN ) {
+ (void) slapi_dn_normalize_case( s );
+ return;
+ }
+
+ d = s;
+ if (trim_spaces) {
+ /* strip leading blanks */
+ while (utf8isspace_fast(s)) {
+ LDAP_UTF8INC(s);
+ }
+ }
+ /* handle value of all spaces - turn into single space */
+ /* unless space insensitive syntax - turn into zero length string */
+ if ( *s == '\0' && s != d ) {
+ if ( ! (syntax & SYNTAX_SI)) {
+ *d++ = ' ';
+ }
+ *d = '\0';
+ return;
+ }
+ prevspace = 0;
+ while ( *s ) {
+ curspace = utf8isspace_fast(s);
+
+ /* ignore spaces and '-' in telephone numbers */
+ if ( (syntax & SYNTAX_TEL) && (curspace || *s == '-') ) {
+ LDAP_UTF8INC(s);
+ continue;
+ }
+
+ /* ignore all spaces if this is a space insensitive value */
+ if ( (syntax & SYNTAX_SI) && curspace ) {
+ LDAP_UTF8INC(s);
+ continue;
+ }
+
+ /* compress multiple blanks */
+ if ( prevspace && curspace ) {
+ LDAP_UTF8INC(s);
+ continue;
+ }
+ prevspace = curspace;
+ if ( syntax & SYNTAX_CIS ) {
+ int ssz, dsz;
+ slapi_utf8ToLower((unsigned char*)s, (unsigned char *)d, &ssz, &dsz);
+ s += ssz;
+ d += dsz;
+ } else {
+ char *np;
+ int sz;
+
+ np = ldap_utf8next(s);
+ if (np == NULL || np == s) break;
+ sz = np - s;
+ memcpy(d,s,sz);
+ d += sz;
+ s += sz;
+ }
+ }
+ *d = '\0';
+ /* strip trailing blanks */
+ if (prevspace && trim_spaces) {
+ char *nd;
+
+ nd = ldap_utf8prev(d);
+ while (nd && utf8isspace_fast(nd)) {
+ d = nd;
+ nd = ldap_utf8prev(d);
+ *d = '\0';
+ }
+ }
+}
+
+int
+value_cmp(
+ struct berval *v1,
+ struct berval *v2,
+ int syntax,
+ int normalize
+)
+{
+ int rc;
+ struct berval bvcopy1;
+ struct berval bvcopy2;
+ char little_buffer[64];
+ size_t buffer_space = sizeof(little_buffer);
+ int buffer_offset = 0;
+ int free_v1 = 0;
+ int free_v2 = 0;
+
+ /* This code used to call malloc up to four times in the copying
+ * of attributes to be normalized. Now we attempt to keep everything
+ * on the stack and only malloc if the data is big
+ */
+ if ( normalize & 1 ) {
+ /* Do we have space in the little buffer ? */
+ if (v1->bv_len < buffer_space) {
+ bvcopy1.bv_len = v1->bv_len;
+ SAFEMEMCPY(&little_buffer[buffer_offset],v1->bv_val,v1->bv_len);
+ bvcopy1.bv_val = &little_buffer[buffer_offset];
+ bvcopy1.bv_val[v1->bv_len] = '\0';
+ v1 = &bvcopy1;
+ buffer_space-= v1->bv_len+1;
+ buffer_offset+= v1->bv_len+1;
+ } else {
+ v1 = ber_bvdup( v1 );
+ free_v1 = 1;
+ }
+ value_normalize( v1->bv_val, syntax, 1 /* trim leading blanks */ );
+ }
+ if ( normalize & 2 ) {
+ /* Do we have space in the little buffer ? */
+ if (v2->bv_len < buffer_space) {
+ bvcopy2.bv_len = v2->bv_len;
+ SAFEMEMCPY(&little_buffer[buffer_offset],v2->bv_val,v2->bv_len);
+ bvcopy2.bv_val = &little_buffer[buffer_offset];
+ bvcopy2.bv_val[v2->bv_len] = '\0';
+ v2 = &bvcopy2;
+ buffer_space-= v2->bv_len+1;
+ buffer_offset+= v2->bv_len+1;
+ } else {
+ v2 = ber_bvdup( v2 );
+ free_v2 = 1;
+ }
+ value_normalize( v2->bv_val, syntax, 1 /* trim leading blanks */ );
+ }
+
+ switch ( syntax ) {
+ case SYNTAX_CIS:
+ case (SYNTAX_CIS | SYNTAX_TEL):
+ case (SYNTAX_CIS | SYNTAX_DN):
+ case (SYNTAX_CIS | SYNTAX_SI):
+ rc = slapi_utf8casecmp( (unsigned char *)v1->bv_val,
+ (unsigned char *)v2->bv_val );
+ break;
+
+ case SYNTAX_CES:
+ rc = strcmp( v1->bv_val, v2->bv_val );
+ break;
+ }
+
+ if ( (normalize & 1) && free_v1) {
+ ber_bvfree( v1 );
+ }
+ if ( (normalize & 2) && free_v2) {
+ ber_bvfree( v2 );
+ }
+
+ return( rc );
+}
diff --git a/ldap/servers/plugins/uiduniq/7bit.c b/ldap/servers/plugins/uiduniq/7bit.c
new file mode 100644
index 00000000..535dbe9c
--- /dev/null
+++ b/ldap/servers/plugins/uiduniq/7bit.c
@@ -0,0 +1,722 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * 7bit.c
+ *
+ * Implements a directory server pre-operation plugin to test
+ * attributes for 7 bit clean within a defined subtree in the
+ * directory.
+ *
+ */
+#include <stdio.h>
+#include <slapi-plugin.h>
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include <string.h>
+#include "dirver.h"
+
+/* DBDB this should be pulled from a common header file */
+#ifdef _WIN32
+#ifndef strcasecmp
+#define strcasecmp(x,y) strcmpi(x,y)
+#endif
+#endif
+
+#if defined( LDAP_DEBUG ) && !defined( DEBUG )
+#define DEBUG
+#endif
+
+/*
+ * ISSUES:
+ * How should this plugin handle ACL issues? It seems wrong to reject
+ * adds and modifies because there is already a conflicting UID, when
+ * the request would have failed because of an ACL check anyway.
+ *
+ * This code currently defines a maximum filter string size of 512. Is
+ * this large enough?
+ *
+ * This code currently does not quote the value portion of the filter as
+ * it is created. This is a bug.
+ */
+
+/* */
+#define BEGIN do {
+#define END } while(0);
+
+/*
+ * Slapi plugin descriptor
+ */
+static char *plugin_name = "NS7bitAttr";
+static Slapi_PluginDesc
+pluginDesc = { "NS7bitAttr", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "Enforce 7-bit clean attribute values" };
+
+
+/*
+ * More information about constraint failure
+ */
+static char *moreInfo =
+ "The value is not 7-bit clean: ";
+
+/* ------------------------------------------------------------ */
+/*
+ * op_error - Record (and report) an operational error.
+ */
+static int
+op_error(int internal_error)
+{
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "Internal error: %d\n", internal_error);
+
+ return LDAP_OPERATIONS_ERROR;
+}
+
+static void
+issue_error(Slapi_PBlock *pb, int result, char *type, char *value)
+{
+ char *moreinfop;
+ int sz;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "%s result %d\n", type, result);
+
+ if (value == NULL) {
+ value = "unknown";
+ }
+ sz = strlen(moreInfo) + strlen(value) + 1;
+ moreinfop = (char *)slapi_ch_malloc(sz);
+ sprintf(moreinfop, "%s%s", moreInfo, value);
+
+ /* Send failure to the client */
+ slapi_send_ldap_result(pb, result, 0, moreinfop, 0, 0);
+ slapi_ch_free((void **)&moreinfop);
+
+ return;
+}
+
+
+/*
+ * Check 'value' for 7-bit cleanliness.
+ */
+static int
+bit_check_one_berval(const struct berval *value, char **violated)
+{
+ int result;
+ char *ch;
+ int i;
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "7-bit checking begin\n");
+#endif
+
+ result = LDAP_SUCCESS;
+ /* If no value, can't possibly be a conflict */
+ if ( (struct berval *)NULL == value )
+ return result;
+
+ for(i=0, ch=value->bv_val; ch && i < (int)(value->bv_len) ;
+ ch++, i++)
+ {
+
+ if (( 0x80 & *ch ) != 0 )
+ {
+ result = LDAP_CONSTRAINT_VIOLATION;
+ *violated = value->bv_val;
+ break;
+ }
+ }
+
+ return result;
+}
+
+
+/*
+ * Check a set of values for 7-bit cleanliness.
+ *
+ * If 'attr' is NULL, the values are taken from 'values'.
+ * If 'attr' is non-NULL, the values are taken from 'attr'.
+ */
+static int
+bit_check(Slapi_Attr *attr, struct berval **values, char **violated)
+{
+ int result = LDAP_SUCCESS;
+ *violated = NULL;
+
+ /* If no values, can't possibly be a conflict */
+ if ( (Slapi_Attr *)NULL == attr && (struct berval **)NULL == values )
+ return result;
+
+ if ( (Slapi_Attr *)NULL != attr )
+ {
+ Slapi_Value *v = NULL;
+ int vhint = -1;
+
+ for ( vhint = slapi_attr_first_value( attr, &v );
+ vhint != -1 && LDAP_SUCCESS == result;
+ vhint = slapi_attr_next_value( attr, vhint, &v ))
+ {
+ result = bit_check_one_berval(slapi_value_get_berval(v), violated);
+ }
+ }
+ else
+ {
+ for (;*values != NULL && LDAP_SUCCESS == result; values++)
+ {
+ result = bit_check_one_berval(*values, violated);
+ }
+ }
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "7 bit check result = %d\n", result);
+#endif
+
+ return result;
+}
+
+
+/* ------------------------------------------------------------ */
+/*
+ * preop_add - pre-operation plug-in for add
+ */
+static int
+preop_add(Slapi_PBlock *pb)
+{
+ int result;
+ char *violated;
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD begin\n");
+#endif
+
+ result = LDAP_SUCCESS;
+
+ /*
+ * Do constraint check on the added entry. Set result.
+ */
+ BEGIN
+ int err;
+ int argc;
+ char **argv;
+ char **attrName;
+ char *dn;
+ Slapi_Entry *e;
+ Slapi_Attr *attr;
+ char **firstSubtree;
+ char **subtreeDN;
+ int subtreeCnt;
+ int is_replicated_operation;
+
+ /*
+ * Get the arguments
+ */
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
+ if (err) { result = op_error(53); break; }
+
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+ if (err) { result = op_error(54); break; }
+
+ /*
+ * If this is a replication update, just be a noop.
+ */
+ err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
+ if (err) { result = op_error(56); break; }
+ if (is_replicated_operation)
+ {
+ break;
+ }
+
+ /*
+ * Get the target DN for this add operation
+ */
+ err = slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn);
+ if (err) { result = op_error(50); break; }
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD target=%s\n", dn);
+#endif
+
+ /*
+ * Get the entry data for this add. Check whether it
+ * contains a value for the unique attribute
+ */
+ err = slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
+ if (err) { result = op_error(51); break; }
+
+ for ( firstSubtree = argv; strcmp(*firstSubtree, ",") != 0;
+ firstSubtree++, argc--) {}
+ firstSubtree++;
+ argc--;
+
+ for (attrName = argv; strcmp(*attrName, ",") != 0; attrName++ )
+ {
+ /*
+ * if the attribute is userpassword, check unhashed#user#password
+ * instead. "userpassword" is encoded; it will always pass the 7bit
+ * check.
+ */
+ char *attr_name;
+ if ( strcasecmp(*attrName, "userpassword") == 0 )
+ {
+ attr_name = "unhashed#user#password";
+ } else {
+ attr_name = *attrName;
+ }
+ err = slapi_entry_attr_find(e, attr_name, &attr);
+ if (err) continue; /* break;*/ /* no 7-bit attribute */
+
+ /*
+ * For each DN in the managed list, do 7-bit checking if
+ * the target DN is a subnode in the tree.
+ */
+ for( subtreeDN=firstSubtree, subtreeCnt=argc ;subtreeCnt > 0;
+ subtreeCnt--,subtreeDN++)
+ {
+ /*
+ * issuffix determines whether the target is under the
+ * subtree *subtreeDN
+ */
+ if (slapi_dn_issuffix(dn, *subtreeDN))
+ {
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "ADD subtree=%s\n", *subtreeDN);
+#endif
+
+ /*
+ * Check if the value is 7-bit clean
+ */
+ result = bit_check(attr, NULL, &violated);
+ if (result) break;
+ }
+ }
+ /* don't have to go on if there is a value not 7-bit clean */
+ if (result) break;
+ }
+ END
+
+ if (result) {
+ issue_error(pb, result, "ADD", violated);
+ }
+
+ return (result==LDAP_SUCCESS)?0:-1;
+}
+
+static void
+addMod(LDAPMod ***modary, int *capacity, int *nmods, LDAPMod *toadd)
+{
+ if (*nmods == *capacity) {
+ *capacity += 4;
+ if (*modary) {
+ *modary = (LDAPMod **)slapi_ch_realloc((char *)*modary, *capacity * sizeof(LDAPMod *));
+ } else {
+ *modary = (LDAPMod **)slapi_ch_malloc(*capacity * sizeof(LDAPMod *));
+ }
+ }
+ *modary[*nmods] = toadd;
+ (*nmods)++;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * preop_modify - pre-operation plug-in for modify
+ */
+static int
+preop_modify(Slapi_PBlock *pb)
+{
+ int result;
+ char *violated;
+ LDAPMod **checkmods = NULL; /* holds mods to check */
+ int checkmodsCapacity = 0; /* max capacity of checkmods */
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODIFY begin\n");
+#endif
+
+ result = LDAP_SUCCESS;
+
+ BEGIN
+ int err;
+ int argc;
+ char **argv;
+ char **attrName;
+ LDAPMod **mods;
+ LDAPMod **firstMods;
+ LDAPMod *mod;
+ char *target;
+ char **firstSubtree;
+ char **subtreeDN;
+ int subtreeCnt;
+ int is_replicated_operation;
+
+ /*
+ * Get the arguments
+ */
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
+ if (err) { result = op_error(13); break; }
+
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+ if (err) { result = op_error(14); break; }
+
+ /*
+ * If this is a replication update, just be a noop.
+ */
+ err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
+ if (err) { result = op_error(16); break; }
+ if (is_replicated_operation)
+ {
+ break;
+ }
+
+ err = slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &firstMods);
+ if (err) { result = op_error(10); break; }
+
+ /* Get the target DN */
+ err = slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &target);
+ if (err) { result = op_error(11); break; }
+
+ /*
+ * Look for managed trees that include the target
+ * Arguments before "," are the 7-bit clean attribute names. Arguemnts
+ * after "," are subtreeDN's.
+ */
+ for ( firstSubtree = argv; strcmp(*firstSubtree, ",") != 0;
+ firstSubtree++, argc--) {}
+ firstSubtree++;
+ argc--;
+
+ for (attrName = argv; strcmp(*attrName, ",") != 0; attrName++ )
+ {
+ int modcount = 0;
+ int ii = 0;
+
+ /*
+ * if the attribute is userpassword, check unhashed#user#password
+ * instead. "userpassword" is encoded; it will always pass the 7bit
+ * check.
+ */
+ char *attr_name;
+ if ( strcasecmp(*attrName, "userpassword") == 0 )
+ {
+ attr_name = "unhashed#user#password";
+ } else {
+ attr_name = *attrName;
+ }
+
+ /* There may be more than one mod that matches e.g.
+ changetype: modify
+ delete: uid
+ uid: balster1950
+ -
+ add: uid
+ uid: scottg
+
+ So, we need to first find all mods that contain the attribute
+ which are add or replace ops and are bvalue encoded
+ */
+ /* find out how many mods meet this criteria */
+ for(mods=firstMods;*mods;mods++)
+ {
+ mod = *mods;
+ if ((slapi_attr_type_cmp(mod->mod_type, attr_name, 1) == 0) && /* mod contains target attr */
+ (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded (not string val) */
+ (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod actually contains some values */
+ (((mod->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) || /* mod is add */
+ (mod->mod_op & LDAP_MOD_REPLACE))) /* mod is replace */
+ {
+ addMod(&checkmods, &checkmodsCapacity, &modcount, mod);
+ }
+ }
+ if (modcount == 0) {
+ continue; /* no mods to check, go to next attr */
+ }
+
+ /*
+ * stop checking at first mod that fails the check
+ */
+ for (ii = 0; (result == 0) && (ii < modcount); ++ii)
+ {
+ mod = checkmods[ii];
+ /*
+ * For each DN in the managed list, do 7-bit checking if
+ * the target DN is a subnode in the tree.
+ */
+ for( subtreeDN=firstSubtree, subtreeCnt=argc ;subtreeCnt > 0;
+ subtreeCnt--,subtreeDN++)
+ {
+ /*
+ * issuffix determines whether the target is under the
+ * subtree *subtreeDN
+ */
+ if (slapi_dn_issuffix(target, *subtreeDN))
+ {
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODIFY subtree=%s\n", *subtreeDN);
+#endif
+ /*
+ * Check if the value is 7-bit clean
+ */
+ result = bit_check(NULL, mod->mod_bvalues, &violated);
+ if (result) break;
+ }
+ }
+ }
+ /* don't have to go on if there is a value not 7-bit clean */
+ if (result) break;
+ }
+ END
+
+ slapi_ch_free((void **)&checkmods);
+ if (result) {
+ issue_error(pb, result, "MODIFY", violated);
+ }
+
+ return (result==LDAP_SUCCESS)?0:-1;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * preop_modrdn - Pre-operation call for modify RDN
+ *
+ * Check that the new RDN does not include attributes that
+ * cause a constraint violation
+ */
+static int
+preop_modrdn(Slapi_PBlock *pb)
+{
+ int result;
+ Slapi_Entry *e;
+ char *violated;
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODRDN begin\n");
+#endif
+
+ /* Init */
+ result = LDAP_SUCCESS;
+ e = 0;
+
+ BEGIN
+ int err;
+ int argc;
+ char **argv;
+ char **attrName;
+ char *target;
+ char *superior;
+ char *rdn;
+ Slapi_Attr *attr;
+ char **firstSubtree;
+ char **subtreeDN;
+ int subtreeCnt;
+ int is_replicated_operation;
+
+ /*
+ * Get the arguments
+ */
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
+ if (err) { result = op_error(30); break; }
+
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+ if (err) { result = op_error(31); break; }
+
+ /*
+ * If this is a replication update, just be a noop.
+ */
+ err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
+ if (err) { result = op_error(16); break; }
+ if (is_replicated_operation)
+ {
+ break;
+ }
+
+ /* Get the DN of the entry being renamed */
+ err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET, &target);
+ if (err) { result = op_error(22); break; }
+
+ /* Get superior value - unimplemented in 3.0 DS */
+ err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &superior);
+ if (err) { result = op_error(20); break; }
+
+ /*
+ * No superior means the entry is just renamed at
+ * its current level in the tree. Use the target DN for
+ * determining which managed tree this belongs to
+ */
+ if (!superior) superior = target;
+
+ /* Get the new RDN - this has the attribute values */
+ err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &rdn);
+ if (err) { result = op_error(33); break; }
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODRDN newrdn=%s\n", rdn);
+#endif
+
+ /*
+ * Parse the RDN into attributes by creating a "dummy" entry
+ * and setting the attributes from the RDN.
+ *
+ * The new entry must be freed.
+ */
+ e = slapi_entry_alloc();
+ if (!e) { result = op_error(32); break; }
+
+ /* NOTE: strdup on the rdn, since it will be freed when
+ * the entry is freed */
+
+ slapi_entry_set_dn(e, slapi_ch_strdup(rdn));
+
+ err = slapi_entry_add_rdn_values(e);
+ if (err)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODRDN bad rdn value=%s\n", rdn);
+ break; /* Bad DN */
+ }
+
+ /*
+ * arguments before "," are the 7-bit clean attribute names. Arguemnts
+ * after "," are subtreeDN's.
+ */
+ for ( firstSubtree = argv; strcmp(*firstSubtree, ",") != 0;
+ firstSubtree++, argc--) {}
+ firstSubtree++;
+ argc--;
+
+ /*
+ * Find out if the node is being moved into one of
+ * the managed subtrees
+ */
+ for (attrName = argv; strcmp(*attrName, ",") != 0; attrName++ )
+ {
+ /*
+ * If the attribut type is userpassword, do not replace it by
+ * unhashed#user#password because unhashed#user#password does not exist
+ * in this case.
+ */
+ /*
+ * Find any 7-bit attribute data in the new RDN
+ */
+ err = slapi_entry_attr_find(e, *attrName, &attr);
+ if (err) continue; /* break;*/ /* no 7-bit attribute */
+
+ /*
+ * For each DN in the managed list, do 7-bit checking if
+ * the target DN is a subnode in the tree.
+ */
+ for( subtreeDN=firstSubtree, subtreeCnt=argc ;subtreeCnt > 0;
+ subtreeCnt--,subtreeDN++)
+ {
+ /*
+ * issuffix determines whether the target is under the
+ * subtree *subtreeDN
+ */
+ if (slapi_dn_issuffix(superior, *subtreeDN))
+ {
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODRDN subtree=%s\n", *subtreeDN);
+#endif
+
+ /*
+ * Check if the value is 7-bit clean
+ */
+ result = bit_check(attr, NULL, &violated);
+ if (result) break;
+ }
+ }
+ /* don't have to go on if there is a value not 7-bit clean */
+ if (result) break;
+ }
+ END
+
+ /* Clean-up */
+ if (e) slapi_entry_free(e);
+
+ if (result) {
+ issue_error(pb, result, "MODRDN", violated);
+ }
+
+ return (result==LDAP_SUCCESS)?0:-1;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * Initialize the plugin
+ *
+ */
+int
+NS7bitAttr_Init(Slapi_PBlock *pb)
+{
+ int err = 0;
+
+ BEGIN
+ int err;
+ int argc;
+ char **argv;
+
+ /* Declare plugin version */
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01);
+ if (err) break;
+
+ /*
+ * Get and normalize arguments
+ */
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
+ if (err) break;
+
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+ if (err) break;
+
+ /*
+ * Arguments before "," are the 7-bit attribute names. Arguments after
+ * "," are the subtree DN's.
+ */
+ if (argc < 1) { err = -1; break; }
+ for(;strcmp(*argv, ",") != 0 && argc > 0; argc--, argv++)
+ {};
+ if (argc == 0) { err = -1; break; }
+ argv++; argc--;
+
+ for(;argc > 0;argc--, argv++)
+ slapi_dn_normalize_case(*argv);
+
+ /* Provide descriptive information */
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void*)&pluginDesc);
+ if (err) break;
+
+ /* Register functions */
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN,
+ (void*)preop_add);
+ if (err) break;
+
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN,
+ (void*)preop_modify);
+ if (err) break;
+
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN,
+ (void*)preop_modrdn);
+ if (err) break;
+
+ END
+
+ if (err) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "NS7bitAttr_Init",
+ "Error: %d\n", err);
+ err = -1;
+ }
+ else
+ slapi_log_error(SLAPI_LOG_PLUGIN, "NS7bitAttr_Init",
+ "plugin loaded\n");
+
+ return err;
+}
+
diff --git a/ldap/servers/plugins/uiduniq/Makefile b/ldap/servers/plugins/uiduniq/Makefile
new file mode 100644
index 00000000..79b95995
--- /dev/null
+++ b/ldap/servers/plugins/uiduniq/Makefile
@@ -0,0 +1,99 @@
+#
+# 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 "Pass Through Authentication" plugin
+#
+#
+
+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 = $(OBJDIR)/lib/libuidunique
+LIBDIR = $(LIB_RELDIR)
+SHAREDLIB = $(OBJDIR)/lib/shared/utils.o
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./libuiduniq.def
+endif
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd -I../shared
+
+LOCAL_OBJS= uid.o 7bit.o
+
+SHAREDDIR= ../shared
+
+OBJS = $(addprefix $(OBJDEST)/, $(LOCAL_OBJS))
+
+ifeq ($(ARCH), WINNT)
+#LIBUIDUNIQUE_DLL_OBJ = $(addprefix $(OBJDEST)/, uid.o 7bit.o)
+endif
+
+LIBUIDUNIQUE= $(addprefix $(LIBDIR)/, $(UID_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL)
+endif
+
+
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libuiduniq.def"
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP)
+EXTRA_LIBS_DEP += $(LDAPSDK_DEP)
+EXTRA_LIBS += $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL)
+EXTRA_LIBS += $(DLL_EXTRA_LIBS)
+LD=ld
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+EXTRA_LIBS += $(SHAREDLIB)
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBUIDUNIQUE)
+
+$(LIBUIDUNIQUE): $(OBJS) $(LIBUIDUNIQUE_DLL_OBJ) $(DEF_FILE)
+# $(LINK_DLL) $(LIBUIDUNIQUE_DLL_OBJ) $(PLATFORMLIBS) $(EXTRA_LIBS)
+ $(LINK_DLL) $(PLATFORMLIBS) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBUIDUNIQUE_DLL_OBJ)
+endif
+ $(RM) $(LIBUIDUNIQUE)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+#
+# header file dependencies (incomplete)
+#
+$(OBJS): $(LDAP_SRC)/servers/slapd/slapi-plugin.h \
+ ../shared/plugin-utils.h
+
diff --git a/ldap/servers/plugins/uiduniq/UID-Notes b/ldap/servers/plugins/uiduniq/UID-Notes
new file mode 100644
index 00000000..3d3617ff
--- /dev/null
+++ b/ldap/servers/plugins/uiduniq/UID-Notes
@@ -0,0 +1,93 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+Unique UID Checking Plugin
+--------------------------
+
+Terry Hayes, April 16, 1998
+
+
+GOALS
+
+The Unique UID Checking Plugin supports the management of user entries in the
+directory by enforcing the constraints on the value of an attribute within a
+portion of the directory. This provides a central point for enforcing this
+constraint, which allows changes from any source to be checked (DSGW, Kingpin,
+LDAP utilities, or user application).
+
+CONFIGURATION
+
+The software operates as a preoperation plugin to the directory server. An
+entry must be added to the slapd.conf file for the server that declares the
+plugin and provides arguments required for its operation.
+
+The plugin is declared as follows (line split for clarity):
+
+ plugin preoperation "uid uniqueness" /home/thayes/testdir/lib/uid-plugin.so
+ uidunique_init <attribute_name> <subtree_dn> ...
+
+The first 5 values are the standard plugin declaration. The uidunique_init
+function registers preoperation callbacks for the add, modify and modRDN
+directory operations.
+
+The next argument ("attribute_name") specifies the name of the entry attribute
+to check for uniqueness. This attribute must be unique within each of the
+subtrees listed in the remainder of the arguments.
+
+For example:
+
+ plugin preoperation "uid uniqueness" /home/thayes/testdir/lib/uid-plugin.so
+ uidunique_init uid o=mcom.com
+
+This line specifies "uid" as the unique attribute, and lists a single subtree
+to be checked. This line is typical of an initial installation (see below).
+
+A more complex case:
+
+ plugin preoperation "uid uniqueness" /home/thayes/testdir/lib/uid-plugin.so
+ uidunique_init uid o=Coke o=Pepsi
+ plugin preoperation "uid uniqueness" /home/thayes/testdir/lib/uid-plugin.so
+ uidunique_init mail "o=Dr. Pepper"
+
+This configuration specifies a total of three subtrees to check. Two use the
+(standard) "uid" attribute as a unique value. The other specifies "mail"
+as the unique attribute.
+
+INSTALLATION
+
+The standard installation of the directory server will configure this plugin
+to check the "uid" attribute on the default suffix.
+
+OPERATION
+
+The plugin responds to the following LDAP operations:
+
+ + add
+ + modify
+ + modRDN
+
+For all operations, the plugin forces the LDAP operation to return
+CONSTRAINT_VIOLATION if the operation would result in two entries with
+the same unique attribute value.
+
+For an "add" operation that includes the unique attribute, the plugin checks
+that no other entry has the same value.
+
+For a "modify" operation, the operation will fail if the new value of the
+attribute exists in any entry OTHER than the target of the modify. If the
+value already exists, but is in the node being changed, the operation
+succeeds. For example, if a modify operation replaces a 'uid' attribute
+with the same set of values, the plugin will find the "new" values already
+exist. However since it is in the entry being modified, the operation is
+allowed to complete.
+
+For modRDN, the same checking as for "modify" is performed.
+
+ModRDN is coded to handle reparenting, but since the LDAP protocol to support
+this operation is not present, it cannot be exercised and has not been
+tested.
+
diff --git a/ldap/servers/plugins/uiduniq/libuiduniq.def b/ldap/servers/plugins/uiduniq/libuiduniq.def
new file mode 100644
index 00000000..52bbfcca
--- /dev/null
+++ b/ldap/servers/plugins/uiduniq/libuiduniq.def
@@ -0,0 +1,15 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+;
+;
+DESCRIPTION 'Netscape Directory Server 7 Unique Attribute Checking Plugin'
+;CODE SHARED READ EXECUTE
+;DATA SHARED READ WRITE
+EXPORTS
+ uidunique_init @1
+ NSUniqueAttr_Init @2
+ NS7bitAttr_Init @3
diff --git a/ldap/servers/plugins/uiduniq/uid.c b/ldap/servers/plugins/uiduniq/uid.c
new file mode 100644
index 00000000..f32e63ac
--- /dev/null
+++ b/ldap/servers/plugins/uiduniq/uid.c
@@ -0,0 +1,1073 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * uid.c
+ *
+ * Implements a directory server pre-operation plugin to test
+ * attributes for uniqueness within a defined subtree in the
+ * directory.
+ *
+ * Called uid.c since the original purpose of the plugin was to
+ * check the uid attribute in user entries.
+ */
+#include <slapi-plugin.h>
+#include <portable.h>
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include <string.h>
+#include "dirver.h"
+#include "plugin-utils.h"
+
+#if defined( LDAP_DEBUG ) && !defined( DEBUG )
+#define DEBUG
+#endif
+
+#define UNTAGGED_PARAMETER 12
+
+/* Quoting routine - this should be in a library somewhere (slapi?) */
+int ldap_quote_filter_value(
+ char *value, int len,
+ char *out, int maxLen,
+ int *outLen);
+
+
+static int search_one_berval(const char *baseDN, const char *attrName,
+ const struct berval *value, const char *target);
+
+/*
+ * ISSUES:
+ * How should this plugin handle ACL issues? It seems wrong to reject
+ * adds and modifies because there is already a conflicting UID, when
+ * the request would have failed because of an ACL check anyway.
+ *
+ * This code currently defines a maximum filter string size of 512. Is
+ * this large enough?
+ *
+ * This code currently does not quote the value portion of the filter as
+ * it is created. This is a bug.
+ */
+
+/* */
+#define BEGIN do {
+#define END } while(0);
+
+/*
+ * Slapi plugin descriptor
+ */
+static char *plugin_name = "NSUniqueAttr";
+static Slapi_PluginDesc
+pluginDesc = {
+ "NSUniqueAttr", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "Enforce unique attribute values"
+};
+static void* plugin_identity = NULL;
+
+
+/*
+ * More information about constraint failure
+ */
+static char *moreInfo =
+ "Another entry with the same attribute value already exists";
+
+static void
+freePblock( Slapi_PBlock *spb ) {
+ if ( spb )
+ {
+ slapi_free_search_results_internal( spb );
+ slapi_pblock_destroy( spb );
+ }
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * op_error - Record (and report) an operational error.
+ * name changed to uid_op_error so as not to conflict with the external function
+ * of the same name thereby preventing compiler warnings.
+ */
+static int
+uid_op_error(int internal_error)
+{
+ slapi_log_error(
+ SLAPI_LOG_PLUGIN,
+ plugin_name,
+ "Internal error: %d\n",
+ internal_error);
+
+ return LDAP_OPERATIONS_ERROR;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * Create an LDAP search filter from the attribute
+ * name and value supplied.
+ */
+
+static char *
+create_filter(const char *attribute, const struct berval *value)
+{
+ char *filter;
+ char *fp;
+ char *max;
+ int attrLen;
+ int valueLen;
+ int filterLen;
+
+ /* Compute the length of the required buffer */
+ attrLen = strlen(attribute);
+
+ if (ldap_quote_filter_value(value->bv_val,
+ value->bv_len, 0, 0, &valueLen))
+ return 0;
+
+ filterLen = attrLen + 1 + valueLen + 1;
+
+ /* Allocate the buffer */
+ filter = slapi_ch_malloc(filterLen);
+ fp = filter;
+ max = &filter[filterLen];
+
+ /* Place attribute name in filter */
+ strcpy(fp, attribute);
+ fp += attrLen;
+
+ /* Place comparison operator */
+ *fp++ = '=';
+
+ /* Place value in filter */
+ if (ldap_quote_filter_value(value->bv_val, value->bv_len,
+ fp, max-fp, &valueLen)) { slapi_ch_free((void**)&filter); return 0; }
+ fp += valueLen;
+
+ /* Terminate */
+ *fp = 0;
+
+ return filter;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * search - search a subtree for entries with a named attribute matching
+ * the list of values. An entry matching the 'target' DN is
+ * not considered in the search.
+ *
+ * If 'attr' is NULL, the values are taken from 'values'.
+ * If 'attr' is non-NULL, the values are taken from 'attr'.
+ *
+ * Return:
+ * LDAP_SUCCESS - no matches, or the attribute matches the
+ * target dn.
+ * LDAP_CONSTRAINT_VIOLATION - an entry was found that already
+ * contains the attribute value.
+ * LDAP_OPERATIONS_ERROR - a server failure.
+ */
+static int
+search(const char *baseDN, const char *attrName, Slapi_Attr *attr,
+ struct berval **values, const char *target)
+{
+ int result;
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "SEARCH baseDN=%s attr=%s target=%s\n", baseDN, attrName,
+ target?target:"None");
+#endif
+
+ result = LDAP_SUCCESS;
+
+ /* If no values, can't possibly be a conflict */
+ if ( (Slapi_Attr *)NULL == attr && (struct berval **)NULL == values )
+ return result;
+
+ /*
+ * Perform the search for each value provided
+ *
+ * Another possibility would be to search for all the values at once.
+ * However, this is more complex (for filter creation) and unique
+ * attributes values are probably only changed one at a time anyway.
+ */
+ if ( (Slapi_Attr *)NULL != attr )
+ {
+ Slapi_Value *v = NULL;
+ int vhint = -1;
+
+ for ( vhint = slapi_attr_first_value( attr, &v );
+ vhint != -1 && LDAP_SUCCESS == result;
+ vhint = slapi_attr_next_value( attr, vhint, &v ))
+ {
+ result = search_one_berval(baseDN,attrName,
+ slapi_value_get_berval(v),target);
+ }
+ }
+ else
+ {
+ for (;*values != NULL && LDAP_SUCCESS == result; values++)
+ {
+ result = search_one_berval(baseDN,attrName,*values,target);
+ }
+ }
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "SEARCH result = %d\n", result);
+#endif
+
+ return( result );
+}
+
+
+static int
+search_one_berval(const char *baseDN, const char *attrName,
+ const struct berval *value, const char *target)
+{
+ int result;
+ char *filter;
+ Slapi_PBlock *spb;
+
+ result = LDAP_SUCCESS;
+
+ /* If no value, can't possibly be a conflict */
+ if ( (struct berval *)NULL == value )
+ return result;
+
+ filter = 0;
+ spb = 0;
+
+ BEGIN
+ int err;
+ int sres;
+ Slapi_Entry **entries;
+ static char *attrs[] = { "1.1", 0 };
+
+ /* Create the filter - this needs to be freed */
+ filter = create_filter(attrName, value);
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "SEARCH filter=%s\n", filter);
+#endif
+
+ /* Perform the search using the new internal API */
+ spb = slapi_pblock_new();
+ if (!spb) { result = uid_op_error(2); break; }
+
+ slapi_search_internal_set_pb(spb, baseDN, LDAP_SCOPE_SUBTREE,
+ filter, attrs, 0 /* attrs only */, NULL, NULL, plugin_identity, 0 /* actions */);
+ slapi_search_internal_pb(spb);
+
+ err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_RESULT, &sres);
+ if (err) { result = uid_op_error(3); break; }
+
+ /* Allow search to report that there is nothing in the subtree */
+ if (sres == LDAP_NO_SUCH_OBJECT) break;
+
+ /* Other errors are bad */
+ if (sres) { result = uid_op_error(3); break; }
+
+ err = slapi_pblock_get(spb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+ &entries);
+ if (err) { result = uid_op_error(4); break; }
+
+ /*
+ * Look at entries returned. Any entry found must be the
+ * target entry or the constraint fails.
+ */
+ for(;*entries;entries++)
+ {
+ char *dn = slapi_entry_get_dn(*entries);
+
+ /*
+ * DNs are returned in the original value used to insert
+ * the entry. This must be "normalized" for comparison.
+ *
+ * This normalization is done "in-place" (modifying the value
+ * in the entry). This is OK, since this is the only user
+ * of this copy of the entry.
+ */
+ slapi_dn_normalize_case(dn);
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "SEARCH entry dn=%s\n", dn);
+#endif
+
+ /*
+ * It is a Constraint Violation if any entry is found, unless
+ * the entry is the target entry (if any).
+ */
+ if (!target || strcmp(dn, target) != 0)
+ {
+ result = LDAP_CONSTRAINT_VIOLATION;
+ break;
+ }
+ }
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "SEARCH complete result=%d\n", result);
+#endif
+ END
+
+ /* Clean-up */
+ if (spb) {
+ slapi_free_search_results_internal(spb);
+ slapi_pblock_destroy(spb);
+ }
+
+ slapi_ch_free((void**)&filter);
+
+ return result;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * searchAllSubtrees - search all subtrees in argv for entries
+ * with a named attribute matching the list of values, by
+ * calling search for each one.
+ *
+ * If 'attr' is NULL, the values are taken from 'values'.
+ * If 'attr' is non-NULL, the values are taken from 'attr'.
+ *
+ * Return:
+ * LDAP_SUCCESS - no matches, or the attribute matches the
+ * target dn.
+ * LDAP_CONSTRAINT_VIOLATION - an entry was found that already
+ * contains the attribute value.
+ * LDAP_OPERATIONS_ERROR - a server failure.
+ */
+static int
+searchAllSubtrees(int argc, char *argv[], const char *attrName,
+ Slapi_Attr *attr, struct berval **values, const char *dn)
+{
+ int result = LDAP_SUCCESS;
+
+ /*
+ * For each DN in the managed list, do uniqueness checking if
+ * the target DN is a subnode in the tree.
+ */
+ for(;argc > 0;argc--,argv++)
+ {
+ result = search(*argv, attrName, attr, values, dn);
+ if (result) break;
+ }
+ return result;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * getArguments - parse invocation parameters
+ * Return:
+ * 0 - success
+ * >0 - error parsing parameters
+ */
+static int
+getArguments(Slapi_PBlock *pb, char **attrName, char **markerObjectClass,
+ char **requiredObjectClass)
+{
+ int argc;
+ char **argv;
+
+ /*
+ * Get the arguments
+ */
+ if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc))
+ {
+ return uid_op_error(10);
+ }
+
+ if (slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv))
+ {
+ return uid_op_error(11);
+ }
+
+ /*
+ * Required arguments: attribute and markerObjectClass
+ * Optional argument: requiredObjectClass
+ */
+ for(;argc > 0;argc--,argv++)
+ {
+ char *param = *argv;
+ char *delimiter = strchr(param, '=');
+ if (NULL == delimiter)
+ {
+ /* Old style untagged parameter */
+ *attrName = *argv;
+ return UNTAGGED_PARAMETER;
+ }
+ if (strncasecmp(param, "attribute", delimiter-param) == 0)
+ {
+ /* It's OK to set a pointer here, because ultimately it points
+ * inside the argv array of the pblock, which will be staying
+ * arround.
+ */
+ *attrName = delimiter+1;
+ } else if (strncasecmp(param, "markerobjectclass", delimiter-param) == 0)
+ {
+ *markerObjectClass = delimiter+1;
+ } else if (strncasecmp(param, "requiredobjectclass", delimiter-param) == 0)
+ {
+ *requiredObjectClass = delimiter+1;
+ }
+ }
+ if (!*attrName || !*markerObjectClass)
+ {
+ return uid_op_error(13);
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * findSubtreeAndSearch - walk up the tree to find an entry with
+ * the marker object class; if found, call search from there and
+ * return the result it returns
+ *
+ * If 'attr' is NULL, the values are taken from 'values'.
+ * If 'attr' is non-NULL, the values are taken from 'attr'.
+ *
+ * Return:
+ * LDAP_SUCCESS - no matches, or the attribute matches the
+ * target dn.
+ * LDAP_CONSTRAINT_VIOLATION - an entry was found that already
+ * contains the attribute value.
+ * LDAP_OPERATIONS_ERROR - a server failure.
+ */
+static int
+findSubtreeAndSearch(char *parentDN, const char *attrName, Slapi_Attr *attr,
+ struct berval **values, const char *target, const char *markerObjectClass)
+{
+ int result = LDAP_SUCCESS;
+ Slapi_PBlock *spb = NULL;
+
+ while (NULL != (parentDN = slapi_dn_parent(parentDN)))
+ {
+ if (spb = dnHasObjectClass(parentDN, markerObjectClass))
+ {
+ freePblock(spb);
+ /*
+ * Do the search. There is no entry that is allowed
+ * to have the attribute already.
+ */
+ result = search(parentDN, attrName, attr, values, target);
+ break;
+ }
+ }
+ return result;
+}
+
+
+/* ------------------------------------------------------------ */
+/*
+ * preop_add - pre-operation plug-in for add
+ */
+static int
+preop_add(Slapi_PBlock *pb)
+{
+ int result;
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD begin\n");
+#endif
+
+ result = LDAP_SUCCESS;
+
+ /*
+ * Do constraint check on the added entry. Set result.
+ */
+
+ BEGIN
+ int err;
+ char *attrName = NULL;
+ char *markerObjectClass = NULL;
+ char *requiredObjectClass = NULL;
+ char *dn;
+ int isupdatedn;
+ Slapi_Entry *e;
+ Slapi_Attr *attr;
+ int argc;
+ char **argv = NULL;
+
+ /*
+ * If this is a replication update, just be a noop.
+ */
+ err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
+ if (err) { result = uid_op_error(50); break; }
+ if (isupdatedn)
+ {
+ break;
+ }
+
+ /*
+ * Get the arguments
+ */
+ result = getArguments(pb, &attrName, &markerObjectClass,
+ &requiredObjectClass);
+ if (UNTAGGED_PARAMETER == result)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "ADD parameter untagged: %s\n", attrName);
+ result = LDAP_SUCCESS;
+ /* Statically defined subtrees to monitor */
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
+ if (err) { result = uid_op_error(53); break; }
+
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+ if (err) { result = uid_op_error(54); break; }
+ argc--; argv++; /* First argument was attribute name */
+ } else if (0 != result)
+ {
+ break;
+ }
+
+ /*
+ * Get the target DN for this add operation
+ */
+ err = slapi_pblock_get(pb, SLAPI_ADD_TARGET, &dn);
+ if (err) { result = uid_op_error(51); break; }
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name, "ADD target=%s\n", dn);
+#endif
+
+ /*
+ * Get the entry data for this add. Check whether it
+ * contains a value for the unique attribute
+ */
+ err = slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
+ if (err) { result = uid_op_error(52); break; }
+
+ err = slapi_entry_attr_find(e, attrName, &attr);
+ if (err) break; /* no unique attribute */
+
+ /*
+ * Check if it contains the required object class
+ */
+ if (NULL != requiredObjectClass)
+ {
+ if (!entryHasObjectClass(pb, e, requiredObjectClass))
+ {
+ /* No, so we don't have to do anything */
+ break;
+ }
+ }
+
+ /*
+ * Passed all the requirements - this is an operation we
+ * need to enforce uniqueness on. Now find all parent entries
+ * with the marker object class, and do a search for each one.
+ */
+ if (NULL != markerObjectClass)
+ {
+ /* Subtree defined by location of marker object class */
+ result = findSubtreeAndSearch(dn, attrName, attr, NULL,
+ dn, markerObjectClass);
+ } else
+ {
+ /* Subtrees listed on invocation line */
+ result = searchAllSubtrees(argc, argv, attrName, attr, NULL, dn);
+ }
+ END
+
+ if (result)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "ADD result %d\n", result);
+
+ /* Send failure to the client */
+ slapi_send_ldap_result(pb, result, 0, moreInfo, 0, 0);
+ }
+
+ return (result==LDAP_SUCCESS)?0:-1;
+}
+
+static void
+addMod(LDAPMod ***modary, int *capacity, int *nmods, LDAPMod *toadd)
+{
+ if (*nmods == *capacity) {
+ *capacity += 4;
+ if (*modary) {
+ *modary = (LDAPMod **)slapi_ch_realloc((char *)*modary, *capacity * sizeof(LDAPMod *));
+ } else {
+ *modary = (LDAPMod **)slapi_ch_malloc(*capacity * sizeof(LDAPMod *));
+ }
+ }
+ *modary[*nmods] = toadd;
+ (*nmods)++;
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * preop_modify - pre-operation plug-in for modify
+ */
+static int
+preop_modify(Slapi_PBlock *pb)
+{
+
+ int result = LDAP_SUCCESS;
+ Slapi_PBlock *spb = NULL;
+ LDAPMod **checkmods = NULL;
+ int checkmodsCapacity = 0;
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODIFY begin\n");
+#endif
+
+ BEGIN
+ int err;
+ char *attrName;
+ char *markerObjectClass=NULL;
+ char *requiredObjectClass=NULL;
+ LDAPMod **mods;
+ int modcount = 0;
+ int ii;
+ LDAPMod *mod;
+ char *dn;
+ int isupdatedn;
+ int argc;
+ char **argv = NULL;
+
+ /*
+ * If this is a replication update, just be a noop.
+ */
+ err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
+ if (err) { result = uid_op_error(60); break; }
+ if (isupdatedn)
+ {
+ break;
+ }
+
+ /*
+ * Get the arguments
+ */
+ result = getArguments(pb, &attrName, &markerObjectClass,
+ &requiredObjectClass);
+ if (UNTAGGED_PARAMETER == result)
+ {
+ result = LDAP_SUCCESS;
+ /* Statically defined subtrees to monitor */
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
+ if (err) { result = uid_op_error(53); break; }
+
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+ if (err) { result = uid_op_error(54); break; }
+ argc--; /* First argument was attribute name */
+ argv++;
+ } else if (0 != result)
+ {
+ break;
+ }
+
+ err = slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ if (err) { result = uid_op_error(61); break; }
+
+ /* There may be more than one mod that matches e.g.
+ changetype: modify
+ delete: uid
+ uid: balster1950
+ -
+ add: uid
+ uid: scottg
+
+ So, we need to first find all mods that contain the attribute
+ which are add or replace ops and are bvalue encoded
+ */
+ /* find out how many mods meet this criteria */
+ for(;*mods;mods++)
+ {
+ mod = *mods;
+ if ((slapi_attr_type_cmp(mod->mod_type, attrName, 1) == 0) && /* mod contains target attr */
+ (mod->mod_op & LDAP_MOD_BVALUES) && /* mod is bval encoded (not string val) */
+ (mod->mod_bvalues && mod->mod_bvalues[0]) && /* mod actually contains some values */
+ (((mod->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) || /* mod is add */
+ (mod->mod_op & LDAP_MOD_REPLACE))) /* mod is replace */
+ {
+ addMod(&checkmods, &checkmodsCapacity, &modcount, mod);
+ }
+ }
+ if (modcount == 0) {
+ break; /* no mods to check, we are done */
+ }
+
+ /* Get the target DN */
+ err = slapi_pblock_get(pb, SLAPI_MODIFY_TARGET, &dn);
+ if (err) { result = uid_op_error(11); break; }
+
+ if (requiredObjectClass &&
+ !(spb = dnHasObjectClass(dn, requiredObjectClass))) { break; }
+
+ /*
+ * Passed all the requirements - this is an operation we
+ * need to enforce uniqueness on. Now find all parent entries
+ * with the marker object class, and do a search for each one.
+ */
+ /*
+ * stop checking at first mod that fails the check
+ */
+ for (ii = 0; (result == 0) && (ii < modcount); ++ii)
+ {
+ mod = checkmods[ii];
+ if (NULL != markerObjectClass)
+ {
+ /* Subtree defined by location of marker object class */
+ result = findSubtreeAndSearch(dn, attrName, NULL,
+ mod->mod_bvalues, dn,
+ markerObjectClass);
+ } else
+ {
+ /* Subtrees listed on invocation line */
+ result = searchAllSubtrees(argc, argv, attrName, NULL,
+ mod->mod_bvalues, dn);
+ }
+ }
+ END
+
+ slapi_ch_free((void **)&checkmods);
+ freePblock(spb);
+ if (result)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODIFY result %d\n", result);
+
+ slapi_send_ldap_result(pb, result, 0, moreInfo, 0, 0);
+ }
+
+ return (result==LDAP_SUCCESS)?0:-1;
+
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * preop_modrdn - Pre-operation call for modify RDN
+ *
+ * Check that the new RDN does not include attributes that
+ * cause a constraint violation
+ */
+static int
+preop_modrdn(Slapi_PBlock *pb)
+{
+ int result;
+ Slapi_Entry *e;
+
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODRDN begin\n");
+#endif
+
+ /* Init */
+ result = LDAP_SUCCESS;
+ e = 0;
+
+ BEGIN
+ int err;
+ char *attrName;
+ char *markerObjectClass=NULL;
+ char *requiredObjectClass=NULL;
+ char *dn;
+ char *superior;
+ char *rdn;
+ int isupdatedn;
+ Slapi_Attr *attr;
+ int argc;
+ char **argv = NULL;
+
+ /*
+ * If this is a replication update, just be a noop.
+ */
+ err = slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &isupdatedn);
+ if (err) { result = uid_op_error(30); break; }
+ if (isupdatedn)
+ {
+ break;
+ }
+
+ /*
+ * Get the arguments
+ */
+ result = getArguments(pb, &attrName, &markerObjectClass,
+ &requiredObjectClass);
+ if (UNTAGGED_PARAMETER == result)
+ {
+ result = LDAP_SUCCESS;
+ /* Statically defined subtrees to monitor */
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
+ if (err) { result = uid_op_error(53); break; }
+
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+ if (err) { result = uid_op_error(54); break; }
+ argc--; /* First argument was attribute name */
+ argv++;
+ } else if (0 != result)
+ {
+ break;
+ }
+
+ /* Get the DN of the entry being renamed */
+ err = slapi_pblock_get(pb, SLAPI_MODRDN_TARGET, &dn);
+ if (err) { result = uid_op_error(31); break; }
+
+ /* Get superior value - unimplemented in 3.0/4.0/5.0 DS */
+ err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &superior);
+ if (err) { result = uid_op_error(32); break; }
+
+ /*
+ * No superior means the entry is just renamed at
+ * its current level in the tree. Use the target DN for
+ * determining which managed tree this belongs to
+ */
+ if (!superior) superior = dn;
+
+ /* Get the new RDN - this has the attribute values */
+ err = slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &rdn);
+ if (err) { result = uid_op_error(33); break; }
+#ifdef DEBUG
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODRDN newrdn=%s\n", rdn);
+#endif
+
+ /*
+ * Parse the RDN into attributes by creating a "dummy" entry
+ * and setting the attributes from the RDN.
+ *
+ * The new entry must be freed.
+ */
+ e = slapi_entry_alloc();
+ if (!e) { result = uid_op_error(34); break; }
+
+ /* NOTE: strdup on the rdn, since it will be freed when
+ * the entry is freed */
+
+ slapi_entry_set_dn(e, slapi_ch_strdup(rdn));
+
+ err = slapi_entry_add_rdn_values(e);
+ if (err)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODRDN bad rdn value=%s\n", rdn);
+ break; /* Bad DN */
+ }
+
+ /*
+ * Find any unique attribute data in the new RDN
+ */
+ err = slapi_entry_attr_find(e, attrName, &attr);
+ if (err) break; /* no UID attribute */
+
+ /*
+ * Passed all the requirements - this is an operation we
+ * need to enforce uniqueness on. Now find all parent entries
+ * with the marker object class, and do a search for each one.
+ */
+ if (NULL != markerObjectClass)
+ {
+ /* Subtree defined by location of marker object class */
+ result = findSubtreeAndSearch(dn, attrName, attr, NULL, dn,
+ markerObjectClass);
+ } else
+ {
+ /* Subtrees listed on invocation line */
+ result = searchAllSubtrees(argc, argv, attrName, attr, NULL, dn);
+ }
+ END
+ /* Clean-up */
+ if (e) slapi_entry_free(e);
+
+ if (result)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, plugin_name,
+ "MODRDN result %d\n", result);
+
+ slapi_send_ldap_result(pb, result, 0, moreInfo, 0, 0);
+ }
+
+ return (result==LDAP_SUCCESS)?0:-1;
+
+}
+
+/* ------------------------------------------------------------ */
+/*
+ * Initialize the plugin
+ *
+ * uidunique_init (the old name) is deprecated
+ */
+int
+NSUniqueAttr_Init(Slapi_PBlock *pb)
+{
+ int err = 0;
+
+ BEGIN
+ int err;
+ int argc;
+ char **argv;
+
+ /* Declare plugin version */
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01);
+ if (err) break;
+
+ /*
+ * Get plugin identity and store it for later use
+ * Used for internal operations
+ */
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
+ /* PR_ASSERT (plugin_identity); */
+
+ /*
+ * Get and normalize arguments
+ */
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGC, &argc);
+ if (err) break;
+
+ err = slapi_pblock_get(pb, SLAPI_PLUGIN_ARGV, &argv);
+ if (err) break;
+
+ /* First argument is the unique attribute name */
+ if (argc < 1) { err = -1; break; }
+ argv++; argc--;
+
+ for(;argc > 0;argc--, argv++)
+ slapi_dn_normalize_case(*argv);
+
+ /* Provide descriptive information */
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void*)&pluginDesc);
+ if (err) break;
+
+ /* Register functions */
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_ADD_FN,
+ (void*)preop_add);
+ if (err) break;
+
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODIFY_FN,
+ (void*)preop_modify);
+ if (err) break;
+
+ err = slapi_pblock_set(pb, SLAPI_PLUGIN_PRE_MODRDN_FN,
+ (void*)preop_modrdn);
+ if (err) break;
+
+ END
+
+ if (err) {
+ slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init",
+ "Error: %d\n", err);
+ err = -1;
+ }
+ else
+ slapi_log_error(SLAPI_LOG_PLUGIN, "NSUniqueAttr_Init",
+ "plugin loaded\n");
+
+ return err;
+}
+
+int
+uidunique_init(Slapi_PBlock *pb)
+{
+ return NSUniqueAttr_Init(pb);
+}
+
+
+/* ------------------------------------------------------------ */
+/*
+ * ldap_quote_filter_value
+ *
+ * Quote the filter value according to RFC 2254 (Dec 1997)
+ *
+ * value - a UTF8 string containing the value. It may contain
+ * any of the chars needing quotes ( '(' ')' '*' '/' and NUL ).
+ * len - the length of the UTF8 value
+ * out - a buffer to recieve the converted value. May be NULL, in
+ * which case, only the length of the output is computed (and placed in
+ * outLen).
+ * maxLen - the size of the output buffer. It is an error if this length
+ * is exceeded. Ignored if out is NULL.
+ * outLen - recieves the size of the output. If an error occurs, this
+ * result is not available.
+ *
+ * Returns
+ * 0 - success
+ * -1 - failure (usually a buffer overflow)
+ */
+int /* Error value */
+ldap_quote_filter_value(
+ char *value, int len,
+ char *out, int maxLen,
+ int *outLen)
+{
+ int err;
+ char *eValue;
+ int resLen;
+#ifdef SLAPI_SUPPORTS_V3_ESCAPING
+ static char hexchars[16] = "0123456789abcdef";
+#endif
+
+ err = 0;
+ eValue = &value[len];
+ resLen = 0;
+
+ /*
+ * Convert each character in the input string
+ */
+ while(value < eValue)
+ {
+ switch(*value)
+ {
+ case '(':
+ case ')':
+ case '*':
+ case '\\':
+#ifdef SLAPI_SUPPORTS_V3_ESCAPING
+ case 0:
+#endif
+ /* Handle characters needing special escape sequences */
+
+ /* Compute size of output */
+#ifdef SLAPI_SUPPORTS_V3_ESCAPING
+ resLen += 3;
+#else
+ resLen += 2;
+#endif
+
+ /* Generate output if requested */
+ if (out)
+ {
+ /* Check for overflow */
+ if (resLen > maxLen) { err = -1; break; }
+
+ *out++ = '\\';
+#ifdef SLAPI_SUPPORTS_V3_ESCAPING
+ *out++ = hexchars[(*value >> 4) & 0xF];
+ *out++ = hexchars[*value & 0xF];
+#else
+ *out++ = *value;
+#endif
+ }
+
+ break;
+
+ default:
+ /* Compute size of output */
+ resLen += 1;
+
+ /* Generate output if requested */
+ if (out)
+ {
+ if (resLen > maxLen) { err = -1; break; }
+ *out++ = *value;
+ }
+
+ break;
+ }
+
+ if (err) break;
+
+ value++;
+ }
+
+ if (!err) *outLen = resLen;
+
+ return err;
+}
diff --git a/ldap/servers/plugins/vattrsp_template/Makefile b/ldap/servers/plugins/vattrsp_template/Makefile
new file mode 100644
index 00000000..0eb9e072
--- /dev/null
+++ b/ldap/servers/plugins/vattrsp_template/Makefile
@@ -0,0 +1,79 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+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 = $(OBJDIR)/lib/libvattrsp
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./vattrsp.def
+endif
+
+VATTRSP_OBJS = vattrsp.o
+OBJS = $(addprefix $(OBJDEST)/, $(VATTRSP_OBJS))
+
+VATTRSP_DLL = vattrsp-plugin
+
+INCLUDES += -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
+EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL)
+VATTRSP_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
+EXTRA_LIBS += $(LIBSLAPDLINK) $(NSPRLINK) $(LDAP_SDK_LIBLDAP_DLL)
+LD=ld
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+VATTRSP= $(addprefix $(LIBDIR)/, $(VATTRSP_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(VATTRSP)
+
+ifeq ($(ARCH), WINNT)
+$(VATTRSP): $(OBJS) $(VATTRSP_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(VATTRSP_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(VATTRSP): $(OBJS) $(VATTRSP_DLL_OBJ)
+ $(LINK_DLL) $(VATTRSP_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(VATTRSP_DLL_OBJ)
+endif
+ $(RM) $(VATTRSP)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
diff --git a/ldap/servers/plugins/vattrsp_template/dllmain.c b/ldap/servers/plugins/vattrsp_template/dllmain.c
new file mode 100644
index 00000000..fabf8677
--- /dev/null
+++ b/ldap/servers/plugins/vattrsp_template/dllmain.c
@@ -0,0 +1,96 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/vattrsp_template/vattrsp.c b/ldap/servers/plugins/vattrsp_template/vattrsp.c
new file mode 100644
index 00000000..52534b26
--- /dev/null
+++ b/ldap/servers/plugins/vattrsp_template/vattrsp.c
@@ -0,0 +1,397 @@
+/** 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 <string.h>
+#include "portable.h"
+#include "nspr.h"
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+#include "vattr_spi.h"
+
+/* the global plugin handle */
+static volatile vattr_sp_handle *vattr_handle = NULL;
+
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+
+#define VATTRSP_PLUGIN_SUBSYSTEM "vattrsp-template-plugin" /* used for logging */
+
+/* function prototypes */
+int vattrsp_init( Slapi_PBlock *pb );
+static int vattrsp_start( Slapi_PBlock *pb );
+static int vattrsp_close( Slapi_PBlock *pb );
+static int vattrsp_vattr_get(
+ vattr_sp_handle *handle,
+ vattr_context *c,
+ Slapi_Entry *e,
+ char *type,
+ Slapi_ValueSet** results,
+ int *type_name_disposition,
+ char** actual_type_name,
+ int flags,
+ int *free_flags,
+ void *hint
+ );
+static int vattrsp_vattr_compare(
+ vattr_sp_handle *handle,
+ vattr_context *c,
+ Slapi_Entry *e,
+ char *type,
+ Slapi_Value *test_this,
+ int* result,
+ int flags,
+ void *hint
+ );
+static int vattrsp_vattr_types(
+ vattr_sp_handle *handle,
+ Slapi_Entry *e,
+ vattr_type_list_context *type_context,
+ int flags
+ );
+
+
+static Slapi_PluginDesc pdesc = { "vattrsp", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "class of service plugin" };
+
+static void * vattrsp_plugin_identity = NULL;
+
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+/*
+ * Plugin identity mgmt
+ * --------------------
+ * Used for internal search api's
+ */
+
+void vattrsp_set_plugin_identity(void * identity)
+{
+ vattrsp_plugin_identity=identity;
+}
+
+void * vattrsp_get_plugin_identity()
+{
+ return vattrsp_plugin_identity;
+}
+
+/*
+ * vattrsp_init
+ * --------
+ * adds our callbacks to the list
+ * this is called even if the plugin is disabled
+ * so do not do anything here which enables the
+ * plugin functionality - also no other plugin has been started yet
+ * so you cant use the functionality of other plugins here
+ *
+ * When does this get called?
+ * At server start up. This is the first function in
+ * the plugin to get called, and no guarantees are made
+ * about whether the init() function of other plugins
+ * have been called. It is really only safe to register
+ * the standard SLAPI_PLUGIN_* interfaces here.
+ *
+ * returns 0 on success
+*/
+int vattrsp_init( Slapi_PBlock *pb )
+{
+ int ret = 0;
+ void * plugin_identity=NULL;
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"--> vattrsp_init\n");
+
+ /*
+ * Store the plugin identity for later use.
+ * Used for internal operations
+ */
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
+ PR_ASSERT (plugin_identity);
+ vattrsp_set_plugin_identity(plugin_identity);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) vattrsp_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) vattrsp_close ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, VATTRSP_PLUGIN_SUBSYSTEM,
+ "vattrsp_init: failed to register plugin\n" );
+ ret = -1;
+ }
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"<-- vattrsp_init\n");
+ return ret;
+}
+
+
+/*
+ * vattrsp_start
+ * ---------
+ * This is called after vattrsp_init, this is where plugin init starts.
+ * Dependencies on other plugins have been satisfied so
+ * feel free to use them e.g. statechange plugin to keep
+ * an eye on configuration changes
+ *
+ * pb should contain SLAPI_TARGET_DN, which is the dn
+ * of the entry representing this plugin, usually in
+ * cn=plugins, cn=config. Use this to get configuration
+ * specific to your plugin from the entry
+ *
+ * When does this get called?
+ * At server start up, after the vattrsp_init() function is
+ * called and when the start function of all plugins this one
+ * depends on have been called. It is safe to rely
+ * on dependencies from now on e.g. perform search operations
+ *
+ * returns 0 on success
+*/
+int vattrsp_start( Slapi_PBlock *pb )
+{
+ int ret = 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"--> vattrsp_start\n");
+
+ /* register this vattr service provider with vattr subsystem */
+ if (slapi_vattrspi_register((vattr_sp_handle **)&vattr_handle,
+ vattrsp_vattr_get,
+ vattrsp_vattr_compare,
+ vattrsp_vattr_types) != 0)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, VATTRSP_PLUGIN_SUBSYSTEM,
+ "vattrsp_start: cannot register as service provider\n" );
+ ret = -1;
+ goto out;
+ }
+
+ /* register a vattr */
+ /* TODO: change dummyAttr to your attribute type,
+ * or write some configuration code which discovers
+ * the attributes to register
+ */
+ slapi_vattrspi_regattr((vattr_sp_handle *)vattr_handle, "dummyAttr", NULL, NULL);
+
+out:
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"<-- vattrsp_start\n");
+ return ret;
+}
+
+/*
+ * vattrsp_close
+ * ---------
+ * closes down the plugin
+ *
+ * When does this get called?
+ * On server shutdown
+ *
+ * returns 0 on success
+*/
+int vattrsp_close( Slapi_PBlock *pb )
+{
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"--> vattrsp_close\n");
+
+ /* clean up stuff here */
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"<-- vattrsp_close\n");
+
+ return 0;
+}
+
+
+/*
+ * vattrsp_vattr_get
+ * -----------------
+ * vattr subsystem is requesting the value(s) for "type"
+ *
+ * When does this get called?
+ * Whenever a client requests the attribute "type"
+ * this may be indirectly by a request for all
+ * attributes
+ *
+ * returns 0 on success
+ */
+int vattrsp_vattr_get(
+ vattr_sp_handle *handle, /* pass through to subsequent vattr calls */
+ vattr_context *c, /* opaque context, pass through to subsequent vattr calls */
+ Slapi_Entry *e, /* the entry that the values are for */
+ char *type, /* the type that the values are requested for */
+ Slapi_ValueSet** results, /* put the values here */
+ int *type_name_disposition, /* whether the type is a sub-type etc. */
+ char** actual_type_name, /* maybe you call this another type */
+ int flags, /* see slapi-plugin.h to support these flags */
+ int *free_flags, /* let vattr subsystem know if you supplied value copies it must free */
+ void *hint /* opaque hint, pass through to subsequent vattr calls */
+ )
+{
+ int ret = SLAPI_VIRTUALATTRS_NOT_FOUND;
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"--> vattrsp_vattr_get\n");
+
+ /* usual to schema check an attribute
+ * there may be sanity checks which can
+ * be done prior to this "relatively"
+ * slow function to ensure least work done
+ * to fail
+ */
+ if(!slapi_vattr_schema_check_type(e, type))
+ return ret;
+
+ /* TODO: do your thing, resolve the attribute */
+ /* some vattr sps may look after more than one
+ * attribute, this one does not, so no need to
+ * check against "type", we know its our "dummyAttr"
+ */
+ {
+ /* TODO: replace this with your resolver */
+ Slapi_Value *val = slapi_value_new_string("dummyValue");
+
+ *results = slapi_valueset_new();
+ slapi_valueset_add_value(*results, val);
+
+ ret = 0;
+ }
+
+ if(ret == 0)
+ {
+ /* TODO: set *free_flags
+ * if allocated memory for values
+ * use: SLAPI_VIRTUALATTRS_RETURNED_COPIES
+ *
+ * otherwise, if you can guarantee that
+ * this value will live beyond this operation
+ * use: SLAPI_VIRTUALATTRS_RETURNED_POINTERS
+ */
+ *free_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
+
+ /* say the type is the same as the one requested
+ * could be your vattr needs to switch types, say to
+ * make one type look like another or something, but
+ * that is unusual
+ */
+ *actual_type_name = slapi_ch_strdup(type);
+
+ /* TODO: set *type_name_disposition
+ * if the type matched exactly or it
+ * is an alias for the type then
+ * use: SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS
+ *
+ * otherwise, the actual_type_name is a subtype
+ * of type
+ * use: SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE
+ */
+ *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ }
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"<-- vattrsp_cache_vattr_get\n");
+ return ret;
+}
+
+
+
+/*
+ * vattrsp_vattr_compare
+ * ---------------------
+ * vattr subsystem is requesting that the values are compared
+ *
+ * When does this get called?
+ * When an LDAP compare operation against this
+ * type is requested by the client
+ *
+ * returns 0 on success
+ */
+int vattrsp_vattr_compare(
+ vattr_sp_handle *handle, /* pass through to subsequent vattr calls */
+ vattr_context *c, /* opaque context, pass through to subsequent vattr calls */
+ Slapi_Entry *e, /* the entry that the values are for */
+ char *type, /* the type that the values belong to */
+ Slapi_Value *test_this, /* the value to compare against */
+ int* result, /* 1 for matched, 0 for not matched */
+ int flags, /* see slapi-plugin.h to support these flags */
+ void *hint /* opaque hint, pass through to subsequent vattr calls */
+ )
+{
+ int ret = SLAPI_VIRTUALATTRS_NOT_FOUND; /* assume failure */
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"--> vattrsp_vattr_compare\n");
+
+ /* TODO: do your thing, compare the attribute */
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"<-- vattrsp_vattr_compare\n");
+ return ret;
+}
+
+
+
+/*
+ * vattrsp_vattr_types
+ * -------------------
+ * vattr subsystem is requesting the types that you
+ * promise to supply values for if it calls
+ * vattrsp_vattr_get() with each type.
+ * Guesses are not good enough, the wrong answer
+ * effects what happens when all attributes
+ * are requested in the LDAP search operation.
+ * If you do not own up to an attribute,
+ * vattrsp_vattr_get() will never get called for it.
+ * If you say you will supply an attribute but
+ * vattrsp_vattr_get() does not supply a value
+ * then the attribute is returned, but *with* *no*
+ * *values*
+ *
+ * When does this get called?
+ * Only when all attributes are requested by the client
+ * and just prior to multiple calls to vattrsp_vattr_get()
+ *
+ * returns 0 on success
+ */
+int vattrsp_vattr_types(
+ vattr_sp_handle *handle, /* pass through to subsequent vattr calls */
+ Slapi_Entry *e, /* the entry that the types should have values for */
+ vattr_type_list_context *type_context, /* where we put the types */
+ int flags /* see slapi-plugin.h to support these flags */
+ )
+{
+ int ret = 0; /* assume success */
+ char *attr = "dummyAttr"; /* an attribute type that we will deliver */
+ int props = 0; /* properties of the attribute, make this SLAPI_ATTR_FLAG_OPATTR for operational attributes */
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"--> vattrsp_vattr_types\n");
+
+ /* TODO: for each type you will supply... */
+ if(ret)
+ {
+ /* ...do this */
+
+ /* entry contains this attr */
+ vattr_type_thang thang = {0};
+
+ thang.type_name = strcpy(thang.type_name,attr);
+ thang.type_flags = props;
+
+ /* add the type to the type context */
+ slapi_vattrspi_add_type(type_context,&thang,0);
+ }
+
+ slapi_log_error( SLAPI_LOG_TRACE, VATTRSP_PLUGIN_SUBSYSTEM,"<-- vattrsp_vattr_types\n");
+ return ret;
+}
+
+
+
diff --git a/ldap/servers/plugins/vattrsp_template/vattrsp.def b/ldap/servers/plugins/vattrsp_template/vattrsp.def
new file mode 100644
index 00000000..a0e2d8c0
--- /dev/null
+++ b/ldap/servers/plugins/vattrsp_template/vattrsp.def
@@ -0,0 +1,10 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 6.2.1 Virtual Attribute Service Provider Template Plugin'
+EXPORTS
+ vattrsp_init @2
+ plugin_init_debug_level @3
diff --git a/ldap/servers/plugins/views/Makefile b/ldap/servers/plugins/views/Makefile
new file mode 100644
index 00000000..495c7d97
--- /dev/null
+++ b/ldap/servers/plugins/views/Makefile
@@ -0,0 +1,79 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+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 = $(OBJDIR)/lib/libviews
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./views.def
+endif
+
+VIEWS_OBJS = views.o
+OBJS = $(addprefix $(OBJDEST)/, $(VIEWS_OBJS))
+
+VIEWS_DLL = views-plugin
+
+INCLUDES += -I../../slapd -I../../../include
+CFLAGS+=$(SLCFLAGS) -DSLAPD_LOGGING
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
+EXTRA_LIBS += $(NSPRLINK) $(LIBSLAPD) $(LDAP_SDK_LIBLDAP_DLL)
+VIEWS_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(SECURITY_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) $(ICULINK)
+endif
+
+ifeq ($(ARCH), AIX)
+LD=ld
+EXTRA_LIBS_DEP += $(LIBSLAPD) $(NSPR_DEP) $(LDAPSDK_DEP)
+EXTRA_LIBS += $(LIBSLAPDLINK) $(NSPRLINK) $(LDAP_SDK_LIBLDAP_DLL)
+endif
+
+VIEWS= $(addprefix $(LIBDIR)/, $(VIEWS_DLL).$(DLL_SUFFIX))
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(VIEWS)
+
+ifeq ($(ARCH), WINNT)
+$(VIEWS): $(OBJS) $(VIEWS_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(VIEWS_DLL_OBJ) $(EXTRA_LIBS) /DEF:$(DEF_FILE)
+else
+$(VIEWS): $(OBJS) $(VIEWS_DLL_OBJ)
+ $(LINK_DLL) $(VIEWS_DLL_OBJ) $(EXTRA_LIBS)
+endif
+
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(VIEWS_DLL_OBJ)
+endif
+ $(RM) $(VIEWS)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
diff --git a/ldap/servers/plugins/views/dllmain.c b/ldap/servers/plugins/views/dllmain.c
new file mode 100644
index 00000000..fabf8677
--- /dev/null
+++ b/ldap/servers/plugins/views/dllmain.c
@@ -0,0 +1,96 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
diff --git a/ldap/servers/plugins/views/views.c b/ldap/servers/plugins/views/views.c
new file mode 100644
index 00000000..b052167c
--- /dev/null
+++ b/ldap/servers/plugins/views/views.c
@@ -0,0 +1,1779 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* plugin which implements directory server views */
+
+#include <stdio.h>
+#include <string.h>
+#include "portable.h"
+#include "slapi-plugin.h"
+#include <dirlite_strings.h> /* PLUGIN_MAGIC_VENDOR_STR */
+#include "dirver.h"
+#include "statechange.h"
+#include "views.h"
+
+#include "slapi-plugin-compat4.h"
+#include "slapi-private.h"
+
+
+#define VIEW_OBJECTCLASS "nsView"
+#define VIEW_FILTER_ATTR "nsViewFilter"
+#define STATECHANGE_VIEWS_ID "Views"
+#define STATECHANGE_VIEWS_CONFG_FILTER "objectclass=" VIEW_OBJECTCLASS
+
+/* get file mode flags for unix */
+#ifndef _WIN32
+#include <sys/stat.h>
+#endif
+
+#define VIEWS_PLUGIN_SUBSYSTEM "views-plugin" /* used for logging */
+
+/* cache data structs */
+
+struct _viewLinkedList
+{
+ void *pNext;
+ void *pPrev;
+};
+typedef struct _viewLinkedList viewLinkedList;
+
+#if defined(DEBUG)
+#define _VIEW_DEBUG_FILTERS /* Turning on hurts performance */
+#endif
+
+struct _viewEntry
+{
+ viewLinkedList list;
+ char *pDn;
+ char *viewfilter; /* the raw view */
+ Slapi_Filter *includeAncestorFiltersFilter; /* the filter with all ancestor filters */
+ Slapi_Filter *excludeAllButDescendentViewsFilter; /* for building the view of views */
+ Slapi_Filter *excludeChildFiltersFilter; /* NOT all children views, for one level searches */
+ Slapi_Filter *excludeGrandChildViewsFilter; /* view filter for one level searches */
+ Slapi_Filter *includeChildViewsFilter; /* view filter for subtree searches */
+#ifdef _VIEW_DEBUG_FILTERS
+ /* monitor the cached filters with these */
+ char includeAncestorFiltersFilter_str[1024]; /* the filter with all ancestor filters */
+ char excludeAllButDescendentViewsFilter_str[1024]; /* for building the view of views */
+ char excludeChildFiltersFilter_str[1024]; /* NOT all children views, for one level searches */
+ char excludeGrandChildViewsFilter_str[1024]; /* view filter for one level searches */
+ char includeChildViewsFilter_str[1024]; /* view filter for subtree searches */
+#endif
+ char *pSearch_base; /* the parent of the top most view */
+ void *pParent;
+ void **pChildren;
+ int child_count;
+ unsigned long entryid; /* unique identifier for this entry */
+ unsigned long parentid; /* unique identifier for the parent entry */
+};
+typedef struct _viewEntry viewEntry;
+
+struct _globalViewCache
+{
+ viewEntry *pCacheViews;
+ viewEntry **ppViewIndex;
+ int cache_built;
+ int view_count;
+ PRThread *currentUpdaterThread;
+};
+typedef struct _globalViewCache golbalViewCache;
+
+static golbalViewCache theCache;
+
+/* other function prototypes */
+int views_init( Slapi_PBlock *pb );
+static int views_start( Slapi_PBlock *pb );
+static int views_close( Slapi_PBlock *pb );
+static int views_cache_create();
+static void views_update_views_cache( Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data );
+static int views_cache_build_view_list(viewEntry **pViews);
+static int views_cache_index();
+static int views_dn_views_cb (Slapi_Entry* e, void *callback_data);
+static int views_cache_add_dn_views(char *dn, viewEntry **pViews);
+static void views_cache_add_ll_entry(void** attrval, void *theVal);
+static void views_cache_discover_parent(viewEntry *pView);
+static void views_cache_discover_children(viewEntry *pView);
+static void views_cache_discover_view_scope(viewEntry *pView);
+static void views_cache_create_applied_filter(viewEntry *pView);
+static void views_cache_create_exclusion_filter(viewEntry *pView);
+static void views_cache_create_inclusion_filter(viewEntry *pView);
+Slapi_Filter *views_cache_create_descendent_filter(viewEntry *ancestor, PRBool useID);
+static int view_search_rewrite_callback(Slapi_PBlock *pb);
+static void views_cache_backend_state_change(void *handle, char *be_name, int old_be_state, int new_be_state);
+static void views_cache_act_on_change_thread(void *arg);
+static viewEntry *views_cache_find_view(char *view);
+
+/* our api broker published api */
+static void *api[3];
+static int _internal_api_views_entry_exists(char *view_dn, Slapi_Entry *e);
+static int _internal_api_views_entry_dn_exists(char *view_dn, char *e_dn);
+static int _internal_api_views_entry_exists_general(char *view_dn, Slapi_Entry *e, char *e_dn);
+
+
+static Slapi_PluginDesc pdesc = { "views", PLUGIN_MAGIC_VENDOR_STR, PRODUCTTEXT,
+ "virtual directory information tree views plugin" };
+
+static void * view_plugin_identity = NULL;
+
+static PRRWLock *g_views_cache_lock;
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+/*
+** Plugin identity mgmt
+*/
+
+void view_set_plugin_identity(void * identity)
+{
+ view_plugin_identity=identity;
+}
+
+void * view_get_plugin_identity()
+{
+ return view_plugin_identity;
+}
+
+/*
+ views_init
+ --------
+ adds our callbacks to the list
+*/
+int views_init( Slapi_PBlock *pb )
+{
+ int ret = 0;
+ void * plugin_identity=NULL;
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_init\n");
+
+ /*
+ ** Store the plugin identity for later use.
+ ** Used for internal operations
+ */
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &plugin_identity);
+ view_set_plugin_identity(plugin_identity);
+
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_START_FN,
+ (void *) views_start ) != 0 ||
+ slapi_pblock_set(pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) views_close ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc ) != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM,
+ "views_init: failed to register plugin\n" );
+ ret = -1;
+ }
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_init\n");
+ return ret;
+}
+
+void views_read_lock()
+{
+ PR_RWLock_Rlock(g_views_cache_lock);
+}
+
+void views_write_lock()
+{
+ PR_RWLock_Wlock(g_views_cache_lock);
+}
+
+void views_unlock()
+{
+ PR_RWLock_Unlock(g_views_cache_lock);
+}
+
+/*
+ views_start
+ ---------
+ This function publishes the interface for this plugin
+*/
+static int views_start( Slapi_PBlock *pb )
+{
+ int ret = 0;
+ void **statechange_api;
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_start\n");
+
+ theCache.cache_built = 0;
+ g_views_cache_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "views");
+
+ /* first register our backend state change func (we'll use func pointer as handle) */
+ slapi_register_backend_state_change((void *)views_cache_backend_state_change, views_cache_backend_state_change);
+
+ /* create the view cache */
+
+ views_cache_create();
+
+ /* register callbacks for filter and search rewriting */
+ slapi_compute_add_search_rewriter(view_search_rewrite_callback);
+
+ /* register for state changes to view configuration */
+ if(!slapi_apib_get_interface(StateChange_v1_0_GUID, &statechange_api))
+ {
+ statechange_register(statechange_api, STATECHANGE_VIEWS_ID, NULL, STATECHANGE_VIEWS_CONFG_FILTER, NULL, views_update_views_cache);
+ }
+
+ /* register our api so that other subsystems can be views aware */
+ api[0] = NULL; /* reserved for api broker use */
+ api[1] = (void *)_internal_api_views_entry_exists;
+ api[2] = (void *)_internal_api_views_entry_dn_exists;
+
+ if( slapi_apib_register(Views_v1_0_GUID, api) )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM, "views: failed to publish views interface\n");
+ ret = -1;
+ }
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_start\n");
+ return ret;
+}
+
+/* _internal_api_views_entry_exists()
+ * ----------------------------------
+ * externally published api to allow other subsystems to
+ * be views aware. Given a view and an entry, this function
+ * returns PR_TRUE if the entry would be returned by a subtree
+ * search on the view, PR_FALSE otherwise.
+ */
+static int _internal_api_views_entry_exists(char *view_dn, Slapi_Entry *e)
+{
+ return _internal_api_views_entry_exists_general(view_dn, e, NULL);
+}
+
+static int _internal_api_views_entry_dn_exists(char *view_dn, char *e_dn)
+{
+ return _internal_api_views_entry_exists_general(view_dn, NULL, e_dn);
+}
+
+static int _internal_api_views_entry_exists_general(char *view_dn, Slapi_Entry *e, char *e_dn)
+{
+ int ret = 0;
+ viewEntry *view;
+ char *dn;
+
+ /* there are two levels of scope for a view,
+ * from the parent of the view without a view filter
+ * and the parent of the top most view including a
+ * view filter - either match will do
+ */
+
+ /* find the view */
+ view = views_cache_find_view(view_dn);
+ if(0==view)
+ {
+ /* this is not the entry you are looking for */
+ goto bail;
+ }
+
+ /* normal scope - is the view an ancestor of the entry */
+ if(e_dn)
+ dn = e_dn;
+ else
+ dn = slapi_entry_get_ndn(e);
+
+ if(slapi_dn_issuffix(dn, view_dn))
+ {
+ /* this entry is physically contained in the view hiearchy */
+ ret = -1;
+ goto bail;
+ }
+
+ /* view scope - view hiearchy scope plus view filter */
+ if(slapi_dn_issuffix(dn, view->pSearch_base))
+ {
+ if(0==e)
+ {
+ Slapi_DN *sdn = slapi_sdn_new_dn_byref(dn);
+
+ slapi_search_internal_get_entry( sdn, NULL, &e , view_get_plugin_identity());
+
+ slapi_sdn_free(&sdn);
+ }
+
+ /* so far so good, apply filter */
+ if(0==slapi_filter_test_simple(e,view->includeAncestorFiltersFilter))
+ {
+ /* this entry would appear in the view */
+ ret = -1;
+ }
+ }
+
+bail:
+ return ret;
+}
+
+void views_cache_free()
+{
+ viewEntry *head = theCache.pCacheViews;
+ viewEntry *current;
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_cache_free\n");
+
+ /* free the cache */
+ current = head;
+
+ while(current != NULL)
+ {
+ viewEntry *theView = current;
+ current = current->list.pNext;
+
+ /* free the view */
+ slapi_ch_free((void**)&theView->pDn);
+ slapi_ch_free((void**)&theView->viewfilter);
+ slapi_filter_free(theView->includeAncestorFiltersFilter,1);
+ slapi_filter_free(theView->excludeAllButDescendentViewsFilter,1);
+ slapi_filter_free(theView->excludeChildFiltersFilter,1);
+ slapi_filter_free(theView->excludeGrandChildViewsFilter,1);
+ slapi_filter_free(theView->includeChildViewsFilter,1);
+ slapi_ch_free((void**)&theView->pSearch_base);
+ slapi_ch_free((void**)&theView->pChildren);
+ slapi_ch_free((void**)&theView);
+ }
+
+ theCache.pCacheViews = NULL;
+
+ slapi_ch_free((void**)&theCache.ppViewIndex);
+
+ theCache.view_count = 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_cache_free\n");
+}
+
+/*
+ views_close
+ ---------
+ unregisters the interface for this plugin
+*/
+static int views_close( Slapi_PBlock *pb )
+{
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_close\n");
+
+ /* unregister backend state change notification */
+ slapi_unregister_backend_state_change((void *)views_cache_backend_state_change);
+
+ views_cache_free();
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_close\n");
+
+ return 0;
+}
+
+
+/*
+ views_cache_create
+ ---------------------
+ Walks the views in the DIT and populates the cache.
+*/
+static int views_cache_create()
+{
+ int ret = -1;
+ static int firstTime = 1;
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_cache_create\n");
+
+
+ /* lock cache */
+ views_write_lock();
+
+ theCache.currentUpdaterThread = PR_GetCurrentThread(); /* to avoid deadlock */
+
+ if(theCache.pCacheViews)
+ {
+ /* need to get rid of the existing views */
+ views_cache_free();
+ }
+
+ /* grab the view entries */
+ ret = views_cache_build_view_list(&(theCache.pCacheViews));
+ if(!ret && theCache.pCacheViews)
+ {
+ viewEntry *head = theCache.pCacheViews;
+ viewEntry *current;
+
+ /* OK, we have a basic cache, now we need to
+ * fix up parent and children pointers
+ */
+ for(current = head; current != NULL; current = current->list.pNext)
+ {
+ views_cache_discover_parent(current);
+ views_cache_discover_children(current);
+ }
+
+ /* scope of views and cache search filters... */
+ for(current = head; current != NULL; current = current->list.pNext)
+ {
+ views_cache_discover_view_scope(current);
+ views_cache_create_applied_filter(current);
+ views_cache_create_exclusion_filter(current);
+ views_cache_create_inclusion_filter(current);
+ }
+
+ /* create the view index */
+ ret = views_cache_index();
+ if(ret != 0)
+ {
+ /* currently we cannot go on without the indexes */
+ slapi_log_error(SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM, "views_cache_create: failed to index cache\n");
+ }
+ else
+ theCache.cache_built = 1;
+ }
+ else
+ {
+ /* its ok to not have views to cache */
+ theCache.cache_built = 0;
+ ret = 0;
+ }
+
+ theCache.currentUpdaterThread = 0;
+
+ /* unlock cache */
+ views_unlock();
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_cache_create\n");
+ return ret;
+}
+
+/*
+ * views_cache_view_compare
+ * -----------------------
+ * compares the dns of two views - used for sorting the index
+ */
+int views_cache_view_compare(const void *e1, const void *e2)
+{
+ int ret;
+ Slapi_DN *dn1 = slapi_sdn_new_dn_byval((*(viewEntry**)e1)->pDn);
+ Slapi_DN *dn2 = slapi_sdn_new_dn_byval((*(viewEntry**)e2)->pDn);
+
+ ret = slapi_sdn_compare(dn1, dn2);
+
+ slapi_sdn_free(&dn1);
+ slapi_sdn_free(&dn2);
+
+ return ret;
+}
+
+/*
+ * views_cache_dn_compare
+ * -----------------------
+ * compares a dn with the dn of a view - used for searching the index
+ */
+int views_cache_dn_compare(const void *e1, const void *e2)
+{
+ int ret;
+ Slapi_DN *dn1 = slapi_sdn_new_dn_byval((char*)e1);
+ Slapi_DN *dn2 = slapi_sdn_new_dn_byval(((viewEntry*)e2)->pDn);
+
+ ret = slapi_sdn_compare(dn1, dn2);
+
+ slapi_sdn_free(&dn1);
+ slapi_sdn_free(&dn2);
+
+ return ret;
+}
+/*
+ * views_cache_index
+ * ----------------
+ * indexes the cache for fast look up of views
+ */
+static int views_cache_index()
+{
+ int ret = -1;
+ int i;
+ viewEntry *theView = theCache.pCacheViews;
+ viewEntry *current = 0;
+
+ if(theCache.ppViewIndex)
+ slapi_ch_free((void**)&theCache.ppViewIndex);
+
+ theCache.view_count = 0;
+
+ /* lets count the views */
+ for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
+ theCache.view_count++;
+
+
+ theCache.ppViewIndex = (viewEntry**)calloc(theCache.view_count, sizeof(viewEntry*));
+ if(theCache.ppViewIndex)
+ {
+ /* copy over the views */
+ for(i=0; i<theCache.view_count; i++)
+ {
+ theCache.ppViewIndex[i] = theView;
+ theView = theView->list.pNext;
+ }
+
+ /* sort the views */
+ qsort(theCache.ppViewIndex, theCache.view_count, sizeof(viewEntry*), views_cache_view_compare);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+
+/*
+ views_cache_view_index_bsearch - RECURSIVE
+ ----------------------------------------
+ performs a binary search on the cache view index
+ return -1 if key is not found
+*/
+viewEntry *views_cache_view_index_bsearch( const char *key, int lower, int upper )
+{
+ viewEntry *ret = 0;
+ int index = 0;
+ int compare_ret = 0;
+
+ if(upper >= lower)
+ {
+ if(upper != 0)
+ index = ((upper-lower)/2) + lower;
+ else
+ index = 0;
+
+ compare_ret = views_cache_dn_compare(key, theCache.ppViewIndex[index]);
+
+ if(!compare_ret)
+ {
+ ret = (theCache.ppViewIndex)[index];
+ }
+ else
+ {
+ /* seek elsewhere */
+ if(compare_ret < 0)
+ {
+ /* take the low road */
+ ret = views_cache_view_index_bsearch(key, lower, index-1);
+ }
+ else
+ {
+ /* go high */
+ ret = views_cache_view_index_bsearch(key, index+1, upper);
+ }
+ }
+ }
+
+ return ret;
+}
+
+
+/*
+ views_cache_find_view
+ -------------------
+ searches for a view, and if found returns it, null otherwise
+*/
+static viewEntry *views_cache_find_view(char *view)
+{
+ viewEntry *ret = 0; /* assume failure */
+
+ if(theCache.view_count != 1)
+ ret = views_cache_view_index_bsearch(view, 0, theCache.view_count-1);
+ else
+ {
+ /* only one view (that will fool our bsearch) lets check it here */
+ if(!slapi_utf8casecmp((unsigned char*)view, (unsigned char*)theCache.ppViewIndex[0]->pDn))
+ {
+ ret = theCache.ppViewIndex[0];
+ }
+ }
+
+ return ret;
+}
+
+
+/*
+ views_cache_discover_parent
+ ------------------------------
+ finds the parent of this view and caches it in view
+*/
+static void views_cache_discover_parent(viewEntry *pView)
+{
+ viewEntry *head = theCache.pCacheViews;
+ viewEntry *current;
+ int found = 0;
+
+ for(current = head; current != NULL && !found; current = current->list.pNext)
+ {
+ if(slapi_dn_isparent( current->pDn, pView->pDn ))
+ {
+ found = 1;
+ pView->pParent = current;
+ }
+ }
+
+ if(!found)
+ {
+ /* this is a top view */
+ pView->pParent = NULL;
+ }
+}
+
+
+/*
+ views_cache_discover_children
+ ------------------------------
+ finds the children of this view and caches them in view
+*/
+static void views_cache_discover_children(viewEntry *pView)
+{
+ viewEntry *head = theCache.pCacheViews;
+ viewEntry *current;
+ int child_count = 0;
+ int add_count = 0;
+
+ if(pView->pChildren)
+ {
+ slapi_ch_free((void**)&pView->pChildren);
+ pView->pChildren = NULL;
+ }
+
+ /* first lets count the children */
+ for(current = head; current != NULL; current = current->list.pNext)
+ {
+ if(slapi_dn_isparent(pView->pDn, current->pDn))
+ child_count++;
+ }
+
+ /* make the space for them */
+ pView->child_count = child_count;
+
+ pView->pChildren = calloc(child_count, sizeof(viewEntry*));
+
+ /* add them */
+ for(current = head; current != NULL; current = current->list.pNext)
+ {
+ if(slapi_dn_isparent(pView->pDn, current->pDn))
+ {
+ ((viewEntry**)pView->pChildren)[add_count] = current;
+ add_count++;
+ }
+ }
+}
+
+
+/*
+ views_cache_discover_view_scope
+ ------------------------------
+ finds the parent of the top most view and sets the scope of the view search
+*/
+
+static void views_cache_discover_view_scope(viewEntry *pView)
+{
+ viewEntry *current = pView;
+
+ if(pView->pSearch_base)
+ slapi_ch_free((void**)&pView->pSearch_base);
+
+ while(current != NULL)
+ {
+ if(current->pParent == NULL)
+ {
+ /* found top */
+ pView->pSearch_base = slapi_dn_parent(current->pDn);
+ }
+
+ current = current->pParent;
+ }
+
+}
+
+
+/*
+ views_cache_create_applied_filter
+ --------------------------------
+ builds the filters for:
+ char *includeAncestorFiltersFilter; the view with all ancestor views
+*/
+static void views_cache_create_applied_filter(viewEntry *pView)
+{
+ viewEntry *current = pView;
+ Slapi_Filter *pCurrentFilter = 0;
+ Slapi_Filter *pBuiltFilter = 0;
+ Slapi_Filter *pViewEntryExcludeFilter = 0;
+ char *buf = 0;
+ int len = 0;
+
+ if(pView->includeAncestorFiltersFilter)
+ {
+ /* release the current filter */
+ slapi_filter_free(pView->includeAncestorFiltersFilter, 1);
+ pView->includeAncestorFiltersFilter = 0;
+ }
+
+ /* create applied view filter (this view filter plus ancestors) */
+ while(current != NULL)
+ {
+ /* add this view filter to the built filter using AND */
+ char *buf;
+
+ if(!current->viewfilter)
+ {
+ current = current->pParent;
+ continue; /* skip this view */
+ }
+
+ buf = slapi_ch_strdup(current->viewfilter);
+
+ pCurrentFilter = slapi_str2filter( buf );
+ if(pBuiltFilter && pCurrentFilter)
+ pBuiltFilter = slapi_filter_join_ex( LDAP_FILTER_AND, pBuiltFilter, pCurrentFilter, 0 );
+ else
+ pBuiltFilter = pCurrentFilter;
+
+ slapi_ch_free((void **)&buf);
+
+ current = current->pParent;
+ }
+
+ /* filter for removing view entries from search */
+ pViewEntryExcludeFilter = slapi_str2filter( "(!(objectclass=" VIEW_OBJECTCLASS "))" );
+
+ if(pBuiltFilter)
+ pView->includeAncestorFiltersFilter = slapi_filter_join_ex( LDAP_FILTER_AND, pBuiltFilter, pViewEntryExcludeFilter, 0 );
+ else
+ pView->includeAncestorFiltersFilter = pViewEntryExcludeFilter;
+
+#ifdef _VIEW_DEBUG_FILTERS
+ slapi_filter_to_string(pView->includeAncestorFiltersFilter, pView->includeAncestorFiltersFilter_str, sizeof(pView->includeAncestorFiltersFilter_str));
+#endif
+}
+
+/* views_cache_create_exclusion_filter
+ * ----------------------------------
+ * makes a filter which is used for one level searches
+ * so that views show up correctly if the client filter
+ * allows: excludeGrandChildViewsFilter
+ *
+ * Also makes the filter which excludes entries which
+ * belong in descendent views: excludeChildFiltersFilter
+ */
+static void views_cache_create_exclusion_filter(viewEntry *pView)
+{
+ viewEntry *current = pView;
+ Slapi_Filter *pOrSubFilter = 0;
+ Slapi_Filter *excludeChildFiltersFilter = 0;
+ Slapi_Filter *pChildExcludeSubFilter = 0;
+ Slapi_Filter *pViewEntryExcludeFilter = 0;
+ int child_count = 0;
+ int len = 0;
+ char *buf = 0;
+ Slapi_RDN *rdn = 0;
+ char *str_rdn = 0;
+ Slapi_Filter *pCurrentFilter = 0;
+
+ /* create exclusion filter for one level searches
+ * this requires the rdns of the grandchildren of
+ * this view to be in a filter
+ */
+
+ if(pView->excludeGrandChildViewsFilter)
+ {
+ /* release the current filter */
+ slapi_filter_free(pView->excludeGrandChildViewsFilter, 1);
+ pView->excludeGrandChildViewsFilter = 0;
+ }
+
+ if(pView->excludeChildFiltersFilter)
+ {
+ /* release the current filter */
+ slapi_filter_free(pView->excludeChildFiltersFilter, 1);
+ pView->excludeChildFiltersFilter = 0;
+ }
+
+/* if(pView->child_count == 0)
+ {
+*/ /* this view has no children */
+/* pView->excludeGrandChildViewsFilter = 0;
+ pView->excludeChildFiltersFilter = 0;
+ return;
+ }
+
+
+ while(child_count < pView->child_count)
+ {
+ current = pView->pChildren[child_count];
+
+ if(current->child_count == 0)
+ {
+*/ /* no grandchildren here, skip */
+/* child_count++;
+ continue;
+ }
+*/
+ /* for each child we need to add its descendants */
+/* if(pOrSubFilter)
+ {
+ Slapi_Filter *pDescendents = views_cache_create_descendent_filter(current, TRUE);
+ if(pDescendents)
+ pOrSubFilter = slapi_filter_join_ex( LDAP_FILTER_OR, pOrSubFilter, pDescendents, 0 );
+ }
+ else
+ pOrSubFilter = views_cache_create_descendent_filter(current, TRUE);
+
+ child_count++;
+ }
+*/
+ buf=PR_smprintf("(parentid=%lu)", pView->entryid);
+ pView->excludeGrandChildViewsFilter = slapi_str2filter( buf );
+ PR_smprintf_free(buf);
+
+/* if(pOrSubFilter)
+ pView->excludeGrandChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_NOT, pOrSubFilter, NULL, 0 );*/
+
+ excludeChildFiltersFilter = views_cache_create_descendent_filter(pView, PR_FALSE);
+ if(excludeChildFiltersFilter)
+ pView->excludeChildFiltersFilter = slapi_filter_join_ex( LDAP_FILTER_NOT, excludeChildFiltersFilter, NULL, 0 );
+
+#ifdef _VIEW_DEBUG_FILTERS
+ slapi_filter_to_string(pView->excludeGrandChildViewsFilter, pView->excludeGrandChildViewsFilter_str, sizeof(pView->excludeGrandChildViewsFilter_str));
+ slapi_filter_to_string(pView->excludeChildFiltersFilter, pView->excludeChildFiltersFilter_str, sizeof(pView->excludeChildFiltersFilter_str));
+#endif
+}
+
+
+Slapi_Filter *views_cache_create_descendent_filter(viewEntry *ancestor, PRBool useEntryID)
+{
+ int child_count = 0;
+ Slapi_Filter *pOrSubFilter = 0;
+
+ while(child_count < ancestor->child_count)
+ {
+ Slapi_Filter *pDescendentSubFilter = 0;
+ Slapi_RDN *rdn = 0;
+ char *str_rdn = 0;
+ Slapi_Filter *pCurrentFilter = 0;
+ viewEntry *currentChild = ancestor->pChildren[child_count];
+ char *buf = 0;
+ int len = 0;
+
+ /* for each child we need to add its descendants
+ * we do this now before processing this view
+ * to try to help the filter code out by having
+ * the most significant filters first
+ */
+ pDescendentSubFilter = views_cache_create_descendent_filter(currentChild, useEntryID);
+ if(pDescendentSubFilter)
+ if(pOrSubFilter)
+ pOrSubFilter = slapi_filter_join_ex( LDAP_FILTER_OR, pOrSubFilter, pDescendentSubFilter, 0 );
+ else
+ pOrSubFilter = pDescendentSubFilter;
+
+ if(useEntryID)
+ {
+ /* we need the RDN of this child */
+/* rdn = slapi_rdn_new_dn(currentChild->pDn);
+ str_rdn = (char *)slapi_rdn_get_rdn(rdn);
+ len = strlen(str_rdn);
+
+ buf=PR_smprintf("(%s)", str_rdn);*/
+
+ /* uniquely identify this child */
+ buf=PR_smprintf("(parentid=%lu)", currentChild->entryid);
+ }
+ else
+ {
+ /* this is a filter based filter */
+ if(currentChild->viewfilter)
+ {
+ buf=PR_smprintf("%s",currentChild->viewfilter);
+ }
+ }
+
+ if(buf)
+ {
+ pCurrentFilter = slapi_str2filter( buf );
+ if(pOrSubFilter)
+ pOrSubFilter = slapi_filter_join_ex( LDAP_FILTER_OR, pOrSubFilter, pCurrentFilter, 0 );
+ else
+ pOrSubFilter = pCurrentFilter;
+
+ PR_smprintf_free(buf);
+ }
+
+
+ child_count++;
+ }
+
+ return pOrSubFilter;
+}
+
+
+/* views_cache_create_inclusion_filter
+ * ----------------------------------
+ * makes a filter which is used for subtree searches
+ * so that views show up correctly if the client filter
+ * allows
+ */
+static void views_cache_create_inclusion_filter(viewEntry *pView)
+{
+ viewEntry *head = theCache.pCacheViews;
+/* viewEntry *current; */
+/* Slapi_Filter *view_filter; */
+ char *view_filter_str;
+
+ if(pView->includeChildViewsFilter)
+ {
+ /* release the current filter */
+ slapi_filter_free(pView->includeChildViewsFilter, 1);
+ pView->includeChildViewsFilter = 0;
+ }
+#if 0
+ for(current = head; current != NULL; current = current->list.pNext)
+ {
+ Slapi_DN *viewDN;
+ Slapi_RDN *viewRDN;
+ char *viewRDNstr;
+ char *buf = 0;
+ Slapi_Filter *viewSubFilter;
+
+ /* if this is this a descendent, ignore it */
+ if(slapi_dn_issuffix(current->pDn,pView->pDn) && !(current == pView))
+ continue;
+
+ viewDN = slapi_sdn_new_dn_byref(current->pDn);
+ viewRDN = slapi_rdn_new();
+
+ slapi_sdn_get_rdn(viewDN,viewRDN);
+ viewRDNstr = (char *)slapi_rdn_get_rdn(viewRDN);
+
+ buf = calloc(1, strlen(viewRDNstr) + 11 ); /* 3 for filter */
+ sprintf(buf, "(%s)", viewRDNstr );
+ viewSubFilter = slapi_str2filter( buf );
+
+ if(pView->includeChildViewsFilter)
+ pView->includeChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_OR, pView->includeChildViewsFilter, viewSubFilter, 0 );
+ else
+ pView->includeChildViewsFilter = viewSubFilter;
+
+ slapi_ch_free((void **)&buf);
+ slapi_sdn_free(&viewDN);
+ slapi_rdn_free(&viewRDN);
+
+ child_count++;
+ }
+#endif
+
+ /* exclude all other view entries but decendents */
+/* pView->includeChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_NOT, pView->includeChildViewsFilter, NULL, 0 );
+*/
+ /* it seems reasonable to include entries which
+ * may not fit the view decription but which
+ * are actually *contained* in the view
+ * therefore we use parentids for the view
+ * filter
+ */
+
+
+ /* add decendents */
+ pView->includeChildViewsFilter = views_cache_create_descendent_filter(pView, PR_TRUE);
+
+ /* add this view */
+ view_filter_str = PR_smprintf("(parentid=%lu)", pView->entryid);
+
+ if(pView->includeChildViewsFilter)
+ {
+ pView->includeChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_OR, slapi_str2filter( view_filter_str ), pView->includeChildViewsFilter, PR_FALSE);
+ }
+ else
+ {
+ pView->includeChildViewsFilter = slapi_str2filter( view_filter_str );
+ }
+ PR_smprintf_free(view_filter_str);
+ view_filter_str = NULL;
+
+ /* and make sure the this applies only to views */
+
+/* if(pView->includeChildViewsFilter)
+ {*/
+/* Not necessary since we now use entryid in the filter,
+ so all will be views anyway, and the less sub-filters
+ the better
+ view_filter_str = strdup("(objectclass=" VIEW_OBJECTCLASS ")");
+ view_filter = slapi_str2filter( view_filter_str );
+*/
+ /* child views first because entryid indexed
+ * and makes evaluation faster when a bunch
+ * of indexed filter evaluations with only one
+ * target are evaluated first rather than an
+ * indexed filter which will provide many entries
+ * that may trigger an index evaluation short
+ * circuit. i.e. if one of the child filters is
+ * true then we have one entry, if not, then we
+ * have used indexes completely to determine that
+ * no entry matches and (objectclass=nsview) is never
+ * evaluated.
+ * I should imagine this will hold for all but the
+ * very deepest, widest view trees when subtree
+ * searches are performed from the top
+ */
+/* pView->includeChildViewsFilter = slapi_filter_join_ex( LDAP_FILTER_AND, pView->includeChildViewsFilter, view_filter, 0 );
+ }
+ else
+ {
+ view_filter_str = strdup("(objectclass=nsviewincludenone)"); *//* hackery to get the right result */
+/* pView->includeChildViewsFilter = slapi_str2filter( view_filter_str );
+ }
+*/
+#ifdef _VIEW_DEBUG_FILTERS
+ slapi_filter_to_string(pView->includeChildViewsFilter, pView->includeChildViewsFilter_str, sizeof(pView->includeChildViewsFilter_str));
+#endif
+}
+
+
+/*
+ views_cache_build_view_list
+ -------------------------------
+ builds the list of views by searching for them throughout the DIT
+*/
+static int views_cache_build_view_list(viewEntry **pViews)
+{
+ int ret = 0;
+ Slapi_PBlock *pSuffixSearch = 0;
+ Slapi_Entry **pSuffixList = 0;
+ Slapi_Attr *suffixAttr;
+ struct berval **suffixVals;
+ char *attrType = 0;
+ char *attrs[2];
+ int suffixIndex = 0;
+ int valIndex = 0;
+ int cos_def_available = 0;
+ static int firstTime = 1;
+
+ slapi_log_error(SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_cache_build_view_list\n");
+
+ /*
+ the views may be anywhere in the DIT,
+ so our first task is to find them.
+ */
+
+ attrs[0] = "namingcontexts";
+ attrs[1] = 0;
+
+ slapi_log_error(SLAPI_LOG_PLUGIN, VIEWS_PLUGIN_SUBSYSTEM, "views: Building view cache.\n");
+
+ pSuffixSearch = slapi_search_internal("",LDAP_SCOPE_BASE,"(objectclass=*)",NULL,attrs,0);
+ if(pSuffixSearch)
+ slapi_pblock_get( pSuffixSearch, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+
+ if(pSuffixSearch && ret == LDAP_SUCCESS)
+ {
+ /* iterate through the suffixes and search for views */
+ slapi_pblock_get( pSuffixSearch, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &pSuffixList);
+ if(pSuffixList)
+ {
+ while(pSuffixList[suffixIndex])
+ {
+ if(!slapi_entry_first_attr(pSuffixList[suffixIndex], &suffixAttr))
+ {
+ do
+ {
+ attrType = 0;
+ slapi_attr_get_type(suffixAttr, &attrType);
+ if(attrType && !slapi_utf8casecmp((unsigned char*)attrType, (unsigned char*)"namingcontexts"))
+ {
+ if(!slapi_attr_get_bervals_copy(suffixAttr, &suffixVals))
+ {
+ valIndex = 0;
+
+ if(suffixVals)
+ {
+ while(suffixVals[valIndex])
+ {
+ /* here's a suffix, lets search it... */
+ if(suffixVals[valIndex]->bv_val)
+ views_cache_add_dn_views(suffixVals[valIndex]->bv_val ,pViews);
+
+ valIndex++;
+ }
+
+
+ ber_bvecfree( suffixVals );
+ suffixVals = NULL;
+ }
+ }
+ }
+
+ } while(!slapi_entry_next_attr(pSuffixList[suffixIndex], suffixAttr, &suffixAttr));
+ }
+ suffixIndex++;
+ }
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, VIEWS_PLUGIN_SUBSYSTEM, "views_cache_build_view_list: failed to find suffixes\n");
+ ret = -1;
+ }
+
+ /* clean up */
+ if(pSuffixSearch)
+ {
+ slapi_free_search_results_internal(pSuffixSearch);
+ slapi_pblock_destroy(pSuffixSearch);
+ }
+
+
+ slapi_log_error(SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_cache_build_view_list\n");
+ return ret;
+}
+
+/* struct to support search callback API */
+struct dn_views_info {
+ viewEntry **pViews;
+ int ret;
+};
+
+/* does same funcationality as views_add_dn_views except it is invoked via a callback */
+
+static int views_dn_views_cb (Slapi_Entry* e, void *callback_data) {
+ struct dn_views_info *info;
+ char *filter = 0;
+ char *pDn = 0;
+ struct berval **dnVals;
+ Slapi_Attr *dnAttr;
+ char *attrType = 0;
+ char *attrs[3];
+ viewEntry *pView;
+
+ attrs[0] = VIEW_FILTER_ATTR;
+ attrs[1] = "entryid";
+ attrs[2] = 0;
+ info=(struct dn_views_info *)callback_data;
+
+ info->ret = 0;
+
+ pDn = slapi_entry_get_ndn(e);
+
+ /* create the view */
+ pView = calloc(1, sizeof(viewEntry));
+ pView->pDn = slapi_ch_strdup(pDn);
+
+ if(!slapi_entry_first_attr(e, &dnAttr))
+ {
+ do
+ {
+ attrType = 0;
+
+
+ /* get the filter */
+ slapi_attr_get_type(dnAttr, &attrType);
+ if(attrType && !strcasecmp(attrType,VIEW_FILTER_ATTR))
+ {
+ if(!slapi_attr_get_bervals_copy(dnAttr, &dnVals))
+ {
+ /* add filter */
+ pView->viewfilter = slapi_ch_strdup(dnVals[0]->bv_val);
+ }
+
+ ber_bvecfree( dnVals );
+ dnVals = NULL;
+ }
+
+ if(attrType && !strcasecmp(attrType,"entryid"))
+ {
+ Slapi_Value *val = 0;
+
+ slapi_attr_first_value(dnAttr, &val);
+ pView->entryid = slapi_value_get_ulong(val);
+ }
+
+ if(attrType && !strcasecmp(attrType,"parentid"))
+ {
+ Slapi_Value *val = 0;
+
+ slapi_attr_first_value(dnAttr, &val);
+ pView->parentid = slapi_value_get_ulong(val);
+ }
+
+ } while(!slapi_entry_next_attr(e, dnAttr, &dnAttr));
+
+ }
+
+ /* add view to the cache */
+ views_cache_add_ll_entry((void**)info->pViews, (void *)pView);
+
+ return info->ret;
+}
+
+
+/*
+ views_cache_add_dn_views
+ -------------------------
+ takes a dn as argument and searches the dn for views,
+ adding any found to the view cache. Change to use search callback API
+*/
+
+#define DN_VIEW_FILTER "(objectclass=" VIEW_OBJECTCLASS ")"
+
+static int views_cache_add_dn_views(char *dn, viewEntry **pViews)
+{
+ Slapi_PBlock *pDnSearch = 0;
+ struct dn_views_info info;
+ pDnSearch = slapi_pblock_new();
+ if (pDnSearch) {
+ info.ret=-1;
+ info.pViews=pViews;
+ slapi_search_internal_set_pb(pDnSearch, dn, LDAP_SCOPE_SUBTREE,
+ DN_VIEW_FILTER,NULL,0,
+ NULL,NULL,view_get_plugin_identity(),0);
+ slapi_search_internal_callback_pb(pDnSearch,
+ &info /* callback_data */,
+ NULL/* result_callback */,
+ views_dn_views_cb,
+ NULL /* referral_callback */);
+ slapi_pblock_destroy (pDnSearch);
+ }
+ return info.ret;
+}
+
+/*
+ views_cache_add_ll_entry
+ ---------------------------------------------------
+ the element is added to the head of the linked list
+
+ *NOTE* this function assumes and *requires* that the structures
+ passed to it in "attrval" and "theVal" have a viewLinkedList
+ member, and it is the *first* member of the structure. This
+ is safe because this is a module level function, and all functions
+ which call this one are part of the same sub-system.
+*/
+static void views_cache_add_ll_entry(void** attrval, void *theVal)
+{
+ slapi_log_error(SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_cache_add_ll_entry\n");
+
+ if(*attrval)
+ {
+ /* push this to the start of the list (because its quick) */
+ ((viewLinkedList*)theVal)->pNext = *attrval;
+ ((viewLinkedList*)(*attrval))->pPrev = theVal;
+ *attrval = theVal;
+ }
+ else
+ {
+ /* new or end of list */
+ ((viewLinkedList*)theVal)->pNext = NULL;
+ ((viewLinkedList*)theVal)->pPrev = NULL;
+ *attrval = theVal;
+ }
+
+ slapi_log_error(SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_cache_add_ll_entry\n");
+}
+
+
+/*
+ views_update_views_cache
+ -----------------------
+
+ update internal view cache after state change
+*/
+static void views_update_views_cache( Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data )
+{
+ char *pDn;
+ viewEntry *theView;
+ viewEntry *current;
+ Slapi_Attr *attr;
+ struct berval val;
+ int build_cache = 0;
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "--> views_update_views_cache\n");
+
+ views_write_lock();
+
+ if(!theCache.cache_built)
+ {
+ /* zarro views = no cache,
+ * this is probably an add op
+ * lets build the cache
+ */
+ build_cache = 1;
+ goto unlock_cache;
+ }
+
+ pDn = slapi_entry_get_ndn(e);
+ theView = views_cache_find_view(pDn);
+
+ switch(modtype)
+ {
+ case LDAP_CHANGETYPE_MODIFY:
+ /* if still a view and exists
+ * update string filter
+ * update the filters of all views
+ * if just became a view fall through to add op
+ * if stopped being a view fall through to delete op
+ */
+
+ /* determine what happenned - does the view exist currently? */
+ if(theView)
+ {
+ /* does it have the view objectclass? */
+ if(!slapi_entry_attr_find( e, "objectclass", &attr ))
+ {
+ val.bv_len = 8;
+ val.bv_val = VIEW_OBJECTCLASS;
+
+ if(!slapi_attr_value_find( attr, &val))
+ {
+ /* it is a view */
+ attr = 0;
+
+ /* has the filter changed? */
+ slapi_entry_attr_find( e, VIEW_FILTER_ATTR, &attr );
+
+ if(attr)
+ {
+ if(theView->viewfilter) /* NULL means a filter added */
+ {
+ /* we could translate the string filter into
+ * a real filter and compare against
+ * the view - that would tell us if the filter
+ * was substantively changed.
+ *
+ * But we're not gonna do that :)
+ */
+ val.bv_len = strlen(theView->viewfilter)+1;
+ val.bv_val = theView->viewfilter;
+
+ if(!slapi_attr_value_find( attr, &val))
+ {
+ /* filter unchanged */
+ break;
+ }
+ }
+ }
+ else
+ {
+ /* if no filter in view, then no change */
+ if(theView->viewfilter == 0)
+ break;
+ }
+
+ /* this was indeed a significant mod, add the new filter */
+ if(theView->viewfilter)
+ slapi_ch_free((void**)&theView->viewfilter);
+
+ if(attr)
+ {
+ Slapi_Value *v;
+ slapi_attr_first_value( attr, &v );
+ theView->viewfilter = slapi_ch_strdup(slapi_value_get_string(v));
+ }
+
+ /* update all filters */
+ for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
+ {
+ views_cache_create_applied_filter(current);
+ views_cache_create_exclusion_filter(current);
+ views_cache_create_inclusion_filter(current);
+ }
+ }
+ else
+ {
+ /* this is a delete operation */
+ modtype = LDAP_CHANGETYPE_DELETE;
+ }
+ }
+ else
+ /* thats bad */
+ break;
+ }
+ else
+ {
+ /* this is an add operation */
+ modtype = LDAP_CHANGETYPE_ADD;
+ }
+
+ case LDAP_CHANGETYPE_DELETE:
+ /* remove view entry from list
+ * update children of parent
+ * update all child filters
+ * re-index
+ */
+ if(modtype == LDAP_CHANGETYPE_DELETE)
+ {
+
+ if(theCache.view_count-1)
+ {
+ /* detach view */
+ if(theView->list.pPrev)
+ ((viewEntry*)(theView->list.pPrev))->list.pNext = theView->list.pNext;
+
+ if(theView->list.pNext)
+ {
+ ((viewEntry*)(theView->list.pNext))->list.pPrev = theView->list.pPrev;
+
+ if(theView->list.pPrev == NULL) /* if this is the head */
+ theCache.pCacheViews = (viewEntry*)(theView->list.pNext);
+ }
+
+ /* update children */
+ if(theView->pParent)
+ views_cache_discover_children((viewEntry*)theView->pParent);
+
+ /* update filters */
+ for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
+ {
+ views_cache_create_applied_filter(current);
+ views_cache_create_exclusion_filter(current);
+ views_cache_create_inclusion_filter(current);
+ }
+
+ /* reindex */
+ views_cache_index();
+ }
+ else
+ {
+ theCache.pCacheViews = NULL;
+ theCache.view_count = 0;
+ theCache.cache_built = 0;
+ }
+
+ /* free the view */
+ slapi_ch_free((void**)&theView->pDn);
+ slapi_ch_free((void**)&theView->viewfilter);
+ slapi_filter_free(theView->includeAncestorFiltersFilter,1);
+ slapi_filter_free(theView->excludeAllButDescendentViewsFilter,1);
+ slapi_filter_free(theView->excludeChildFiltersFilter,1);
+ slapi_filter_free(theView->excludeGrandChildViewsFilter,1);
+ slapi_filter_free(theView->includeChildViewsFilter,1);
+ slapi_ch_free((void**)&theView->pSearch_base);
+ slapi_ch_free((void**)&theView->pChildren);
+ slapi_ch_free((void**)&theView);
+
+ break;
+ }
+
+ case LDAP_CHANGETYPE_ADD:
+ /* create view entry
+ * add it to list
+ * update children of parent
+ * update all child filters
+ * re-index
+ */
+ if(modtype == LDAP_CHANGETYPE_ADD)
+ {
+ theView = calloc(1, sizeof(viewEntry));
+ theView->pDn = slapi_ch_strdup(pDn);
+
+ /* get the view filter, the entryid, and the parentid */
+ slapi_entry_attr_find( e, VIEW_FILTER_ATTR, &attr );
+
+ if(attr)
+ {
+ Slapi_Value *v;
+ slapi_attr_first_value( attr, &v );
+ theView->viewfilter = slapi_ch_strdup(slapi_value_get_string(v));
+ }
+ else
+ theView->viewfilter = NULL;
+
+ slapi_entry_attr_find( e, "entryid", &attr );
+
+ if(attr)
+ {
+ Slapi_Value *v;
+ slapi_attr_first_value( attr, &v );
+ theView->entryid = slapi_value_get_ulong(v);
+ }
+ else
+ theView->entryid = 0;
+
+ slapi_entry_attr_find( e, "parentid", &attr );
+
+ if(attr)
+ {
+ Slapi_Value *v;
+ slapi_attr_first_value( attr, &v );
+ theView->parentid = slapi_value_get_ulong(v);
+ }
+ else
+ theView->parentid = 0;
+
+ /* add view to the cache */
+ views_cache_add_ll_entry((void**)theCache.pCacheViews, (void *)theView);
+
+ views_cache_discover_parent(theView);
+ if(theView->pParent)
+ views_cache_discover_children((viewEntry*)theView->pParent);
+
+ /* update filters */
+ for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
+ {
+ views_cache_discover_view_scope(current); /* if ns-view oc added, new view may be top */
+ views_cache_create_applied_filter(current);
+ views_cache_create_exclusion_filter(current);
+ views_cache_create_inclusion_filter(current);
+ }
+
+ /* reindex */
+ views_cache_index();
+ break;
+ }
+
+ case LDAP_CHANGETYPE_MODDN:
+ /* get old dn to find the view
+ * change dn
+ * update parents and children
+ * update all filters
+ * reindex
+ */
+
+ {
+ char *old_dn;
+ Slapi_Entry *old_entry;
+
+ slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &old_entry );
+ old_dn = slapi_entry_get_ndn(old_entry);
+
+ theView = views_cache_find_view(old_dn);
+ if(theView)
+ {
+ slapi_ch_free((void**)&theView->pDn);
+ theView->pDn = slapi_ch_strdup(pDn);
+
+ for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
+ {
+ views_cache_discover_parent(current);
+ views_cache_discover_children(current);
+ }
+
+ for(current = theCache.pCacheViews; current != NULL; current = current->list.pNext)
+ {
+ views_cache_discover_view_scope(current);
+ views_cache_create_applied_filter(current);
+ views_cache_create_exclusion_filter(current);
+ views_cache_create_inclusion_filter(current);
+ }
+ }
+ /* reindex */
+ views_cache_index();
+ break;
+ }
+
+ default:
+ /* we don't care about this op */
+ break;
+ }
+
+unlock_cache:
+ views_unlock();
+
+ if(build_cache)
+ {
+ views_cache_create();
+ }
+
+ slapi_log_error( SLAPI_LOG_TRACE, VIEWS_PLUGIN_SUBSYSTEM, "<-- views_update_views_cache\n");
+}
+
+
+
+/*
+ * view_search_rewrite_callback
+ * ----------------------------
+ * this is the business end of the plugin
+ * this function is called from slapd
+ * rewrites the search to conform to the view
+ * Meaning of the return code :
+ * -1 : keep looking
+ * 0 : rewrote OK
+ * 1 : refuse to do this search
+ * 2 : operations error
+ */
+static int view_search_rewrite_callback(Slapi_PBlock *pb)
+{
+ int ret = -1;
+ char *base = 0;
+ Slapi_Filter *clientFilter = 0;
+ Slapi_Filter *includeAncestorFiltersFilter = 0; /* the view with all ancestor views */
+ Slapi_Filter *excludeChildFiltersFilter = 0; /* NOT all children views, for one level searches */
+ Slapi_Filter *excludeGrandChildViewsFilter = 0; /* view filter for one level searches */
+ Slapi_Filter *includeChildViewsFilter = 0; /* view filter for subtree searches */
+ Slapi_Filter *seeViewsFilter = 0; /* view filter to see views */
+ Slapi_Filter *outFilter = 0;
+ int scope = 0;
+ int set_scope = LDAP_SCOPE_SUBTREE;
+ viewEntry *theView = 0;
+
+#ifdef _VIEW_DEBUG_FILTERS
+ char outFilter_str[1024];
+ char clientFilter_str[1024];
+ char includeAncestorFiltersFilter_str[1024];
+ char excludeChildFiltersFilter_str[1024];
+ char excludeGrandChildViewsFilter_str[1024];
+ char includeChildViewsFilter_str[1024];
+#endif
+
+ /* if no cache, no views */
+ if(!theCache.cache_built)
+ goto end;
+
+ /* avoid locking if this thread is the updater */
+ if(theCache.currentUpdaterThread)
+ {
+ PRThread *thisThread = PR_GetCurrentThread();
+ if(thisThread == theCache.currentUpdaterThread)
+ goto end;
+ }
+
+ /* first, find out if this is a base search (we do nothing) */
+ slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
+ if(scope == LDAP_SCOPE_BASE)
+ goto end;
+
+ /* if base of the search is a view */
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &base);
+
+ /* Read lock the cache */
+ views_read_lock();
+
+ theView = views_cache_find_view(base);
+
+ /* if the view is disabled (we service subtree searches in this case) */
+ if(!theView || !theView->viewfilter && scope == LDAP_SCOPE_ONELEVEL)
+ {
+ /* unlock the cache */
+ views_unlock();
+ goto end;
+ }
+
+
+ /* this is a view search, and we are smokin' */
+
+ /* grab the view filters we are going to need now so we can release the cache lock */
+ if(scope == LDAP_SCOPE_ONELEVEL)
+ {
+ excludeChildFiltersFilter = slapi_filter_dup(theView->excludeChildFiltersFilter);
+ excludeGrandChildViewsFilter = slapi_filter_dup(theView->excludeGrandChildViewsFilter);
+
+#ifdef _VIEW_DEBUG_FILTERS
+ slapi_filter_to_string(excludeChildFiltersFilter, excludeChildFiltersFilter_str, sizeof(excludeChildFiltersFilter_str));
+ slapi_filter_to_string(excludeGrandChildViewsFilter, excludeGrandChildViewsFilter_str, sizeof(excludeGrandChildViewsFilter_str));
+#endif
+
+ }
+
+ includeChildViewsFilter = slapi_filter_dup(theView->includeChildViewsFilter);
+
+#ifdef _VIEW_DEBUG_FILTERS
+ slapi_filter_to_string(includeChildViewsFilter, includeChildViewsFilter_str, sizeof(includeChildViewsFilter_str));
+#endif
+
+ /* always used */
+ includeAncestorFiltersFilter = slapi_filter_dup(theView->includeAncestorFiltersFilter);
+
+#ifdef _VIEW_DEBUG_FILTERS
+ slapi_filter_to_string(includeAncestorFiltersFilter, includeAncestorFiltersFilter_str, sizeof(includeAncestorFiltersFilter_str));
+#endif
+
+ /* unlock the cache */
+ views_unlock();
+
+ /* rewrite search scope and base*/
+ slapi_pblock_set(pb, SLAPI_SEARCH_SCOPE, &set_scope);
+
+ base = slapi_ch_strdup(theView->pSearch_base);
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET, base);
+
+ /* concatenate the filters */
+
+ /* grab the client filter - we need 2 copies */
+ slapi_pblock_get(pb, SLAPI_SEARCH_FILTER, &clientFilter);
+
+#ifdef _VIEW_DEBUG_FILTERS
+ slapi_filter_to_string(clientFilter, clientFilter_str, sizeof(clientFilter_str));
+#endif
+
+ /* client supplied filter AND inclusion filter - make sure we can see views */
+ if(scope == LDAP_SCOPE_ONELEVEL)
+ {
+ Slapi_Filter *clientSeeViewsFilter = 0; /* view filter to see views */
+
+ clientSeeViewsFilter = slapi_filter_dup(clientFilter);
+ if(excludeGrandChildViewsFilter)
+ seeViewsFilter = slapi_filter_join_ex( LDAP_FILTER_AND, excludeGrandChildViewsFilter, clientSeeViewsFilter, 0 );
+ else
+ seeViewsFilter = clientSeeViewsFilter;
+ }
+
+ /* this filter is to lock our view to the subtree at hand */
+ if(seeViewsFilter && includeChildViewsFilter)
+ seeViewsFilter = slapi_filter_join_ex( LDAP_FILTER_AND, includeChildViewsFilter, seeViewsFilter, 0 );
+ else
+ {
+ if(includeChildViewsFilter)
+ seeViewsFilter = includeChildViewsFilter;
+ }
+
+ /* create target filter */
+ if(includeAncestorFiltersFilter)
+ outFilter = slapi_filter_join_ex( LDAP_FILTER_AND, includeAncestorFiltersFilter, clientFilter, 0 );
+ else
+ outFilter = clientFilter;
+
+ if(scope == LDAP_SCOPE_ONELEVEL)
+ {
+ if(excludeChildFiltersFilter)
+ outFilter = slapi_filter_join_ex( LDAP_FILTER_AND, outFilter, excludeChildFiltersFilter, 0 );
+ }
+
+ if(seeViewsFilter)
+ outFilter = slapi_filter_join_ex( LDAP_FILTER_OR, outFilter, seeViewsFilter, 0 );
+
+#ifdef _VIEW_DEBUG_FILTERS
+ slapi_filter_to_string(outFilter, outFilter_str, sizeof(outFilter_str));
+#endif
+
+ /* make it happen */
+ slapi_pblock_set(pb, SLAPI_SEARCH_FILTER, outFilter);
+
+ ret = -2;
+
+end:
+ return ret;
+}
+
+/*
+ * views_cache_backend_state_change()
+ * --------------------------------
+ * This is called when a backend changes state
+ * We simply signal to rebuild the cache in this case
+ *
+ */
+static void views_cache_backend_state_change(void *handle, char *be_name,
+ int old_be_state, int new_be_state)
+{
+ /* we will create a thread to do this since
+ * calling views_cache_create() directly will
+ * hold up the op
+ */
+ if ((PR_CreateThread (PR_USER_THREAD,
+ views_cache_act_on_change_thread,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, VIEWS_PLUGIN_SUBSYSTEM,
+ "views_cache_backend_state_change: PR_CreateThread failed\n" );
+ }
+}
+
+static void views_cache_act_on_change_thread(void *arg)
+{
+ views_cache_create();
+}
diff --git a/ldap/servers/plugins/views/views.def b/ldap/servers/plugins/views/views.def
new file mode 100644
index 00000000..26d28966
--- /dev/null
+++ b/ldap/servers/plugins/views/views.def
@@ -0,0 +1,10 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 7.0 State Change Plugin'
+EXPORTS
+ views_init @2
+ plugin_init_debug_level @3
diff --git a/ldap/servers/slapd/Makefile b/ldap/servers/slapd/Makefile
new file mode 100644
index 00000000..6935ac30
--- /dev/null
+++ b/ldap/servers/slapd/Makefile
@@ -0,0 +1,278 @@
+#
+# 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
+#
+
+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 = $(OBJDIR)/servers/obj
+BINDIR = $(LDAP_SERVER_RELDIR)
+ifndef INSTDIR
+INSTDIR = /netscape/server4/
+endif
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+include $(MCOM_ROOT)/ldapserver/ns_usepurify.mk
+include $(MCOM_ROOT)/ldapserver/ns_usequantify.mk
+include $(LDAP_SRC)/nsdeps.mk
+
+
+ifdef HEAPAGENT
+CFLAGS+=-DPURIFYING
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+
+ifdef USE_PURIFY
+CFLAGS+=-DPURIFYING
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+
+ifdef USE_QUANTIFY
+CFLAGS+=-DQUANTIFYING
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+
+# It looks like most of the latest versions of Unix that we ship on
+# have a good enough heap implementations that they don't need
+# SmartHeap. We still need it on NT, Solaris and HPUX.
+# Solaris 8 has mtmalloc but we still build on and support Solaris 2.6.
+# By contract HPUX must be aligned with Solaris.
+ifneq ($(ARCH), SOLARIS)
+ifneq ($(ARCH), WINNT)
+ifneq ($(ARCH), HPUX)
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+endif
+endif
+
+# Don't use smartheap for debug builds
+ifeq ($(DEBUG), full)
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+
+ifndef LDAP_DONT_USE_SMARTHEAP
+include $(MCOM_ROOT)/ldapserver/ns_usesh.mk
+INCLUDES+=-I$(SH_INCLUDE)
+else
+CFLAGS+=-DLDAP_DONT_USE_SMARTHEAP
+endif
+
+ifndef LDAP_USE_OLD_DB
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+_ldap_db_depend:=$(DB_LIB_DEP)
+INCLUDES+=-I$(DB_INCLUDE)
+endif
+
+INCLUDES += -I. -I$(ACLINC) -I$(MCOM_ROOT)/ldapserver/lib
+
+#ICONS = $(addprefix $(LDAP_SRC)/servers/slapd/ntwdog/, logo.ico key.ico)
+
+REGULAR_SLAPD_OBJS= abandon.o bind.o \
+ compare.o config.o connection.o daemon.o sasl_io.o \
+ detach.o globals.o house.o init.o \
+ monitor.o saslbind.o search.o strdup.o tempnam.o \
+ unbind.o extendop.o rootdse.o \
+ configdse.o pw_mgmt.o auth.o \
+ psearch.o conntable.o \
+ stubs.o protect_db.o fileio.o lite_entries.o \
+ getopt_ext.o start_tls_extop.o
+FEDSE_OBJ= fedse.o
+FEDSE_SRC= fedse.c
+SLAPD_OBJS= $(REGULAR_SLAPD_OBJS) $(FEDSE_OBJ)
+
+
+ifneq ($(ARCH), WINNT)
+SLAPD_OBJS += main.o
+endif
+
+ifeq ($(ARCH), WINNT)
+LDAP_COMMON_EXTRALIBSLIST=libsi18n
+LDAP_COMMON_EXTRALIBS = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LDAP_COMMON_EXTRALIBSLIST)))
+
+EXTRA_LIBS_DEP = \
+ $(LDAP_SDK_LIBLDAP_DLL_DEP) \
+ $(LDAP_SDK_LIBSSLDAP_LIB_DEP) $(LIBLDAPU_DEP) \
+ $(_ldap_db_depend) $(LDAP_COMMON_EXTRALIBS)
+
+EXTRA_LIBS += $(LIBSLAPD) $(LIBLDAPU) $(SVRCORELINK)\
+ $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) \
+ $(LDAP_COMMON_EXTRALIBS)
+
+# JCM - Warnings as Errors
+CFLAGS += /WX
+else
+LDFLAGS = $(SSLLIBFLAG)
+EXTRA_LIBS_DEP = $(SECURITY_DEP) $(NSPR_DEP) \
+ $(LDAP_LIBLDBM_DEP) $(LDAP_LIBAVL_DEP) $(LDAP_LIBLDIF_DEP) \
+ $(LDAPSDK_DEP) $(LIBLDAPU_DEP) \
+ $(_ldap_db_depend) \
+ $(SVRCORE_DEP)
+
+
+#IRIX linker needs LIBSEC first, couldn't find away that would make both IRIX and
+# solaris happy, hence the ifeq
+ifeq ($(ARCH), IRIX)
+# -llitekey is added; but it looks to me these two EXTRA_LIBS are identical...
+EXTRA_LIBS = $(LIBSLAPD) \
+ $(LIBLDAPU) $(LDAPLINK) \
+ $(SECURITYLINK) $(NSPRLINK) $(LDAP_LIBLDBM) \
+ $(DBMLINK) -lavl -lldif -llitekey \
+ $(ALIBS) $(DYNALIBS) $(THREADSLIB) $(SVRCORELINK)
+else
+EXTRA_LIBS = $(LIBSLAPD) \
+ $(LIBLDAPU) $(SECURITYLINK) $(LDAPLINK) \
+ $(NSPRLINK) $(LDAP_LIBLDBM) \
+ $(DBMLINK) -lavl -lldif -llitekey \
+ $(ALIBS) $(DYNALIBS) $(THREADSLIB) \
+ $(SVRCORELINK)
+endif
+
+endif
+
+EXTRA_LIBS_DEP+=$(LIBSLAPD_DEP)
+
+EXTRA_LIBS += $(SASL_LINK)
+
+ifeq ($(ARCH), Linux)
+EXTRA_LIBS += -lcrypt -lpthread
+endif
+
+# In order for debugging to work properly with shared libraries on HP/UX,
+# we need to link with end.o.
+ifeq ($(ARCH), HPUX)
+# need to add arch flags :maybe
+LDFLAGS+=$(ARCH_CFLAGS)
+# HPUX linker voodoo
+ifeq ($(DEBUG), full)
+ifeq ($(USE_64), 1)
+EXTRA_LIBS_TEMP:=$(EXTRA_LIBS)
+EXTRA_LIBS += /opt/langtools/lib/pa20_64/end.o
+else
+EXTRA_LIBS_TEMP:=$(EXTRA_LIBS)
+EXTRA_LIBS += /opt/langtools/lib/end.o
+endif #USE_64
+endif #DEBUG
+# Always put libpthread at the beginning of the library list, otherwise NSPR gets upset (very)
+EXTRA_LIBS_TEMP:=$(EXTRA_LIBS)
+EXTRA_LIBS = -lpthread $(EXTRA_LIBS_TEMP)
+endif #HPUX
+
+#Put SmartHeap at the beginning of the linker library list
+EXTRA_LIBS_TEMP:=$(EXTRA_LIBS)
+EXTRA_LIBS=$(SH_LIB) $(EXTRA_LIBS_TEMP)
+
+ifeq ($(ARCH), SOLARIS)
+ifeq ($(USE_64), 1)
+LDFLAGS+= -xarch=v9
+endif
+endif
+
+ifeq ($(ARCH), SOLARISx86)
+ SH_LIB = -lmtmalloc
+endif
+
+OBJS = $(addprefix $(OBJDEST)/, $(SLAPD_OBJS))
+
+STUB_OBJS = $(addprefix $(OBJDEST)/, stubrepl.o)
+
+ifeq ($(ARCH), WINNT)
+MAIN_OBJ = $(addprefix $(OBJDEST)/, main.o)
+SLAPD_RES = $(addprefix $(SVRCORE_LIBPATH)/, ntsvrcore.res)
+EXTRA_OBJS = $(MAIN_OBJ) $(SLAPD_RES)
+SUBSYSTEM=console
+endif
+
+ifeq ($(ARCH), WINNT)
+SLAPD = $(addprefix $(BINDIR)/, slapd.exe)
+else
+ifdef USE_PURIFY
+SLAPD = $(addprefix $(BINDIR)/, ns-slapd.pure)
+else
+ifdef USE_QUANTIFY
+SLAPD = $(addprefix $(BINDIR)/, ns-slapd.quantify)
+else
+SLAPD = $(addprefix $(BINDIR)/, ns-slapd)
+endif
+endif
+endif
+
+ifeq ($(ARCH), AIX)
+ifdef OLD_AIX_LINKING
+ CCC = svxlC_r
+endif
+
+#LDFLAGS += -bloadmap:$(BINDIR)/loadmap_slapd
+# setup the bmaxdata flag to use 5 segments (1.25 GB).
+# This is a trade-off that allows dbcachesize to be up to about 1GB.
+LDFLAGS += -bmaxdata:0x50000000
+EXTRA_LIBS += -L$(OBJDIR) $(EXE_EXTRA_LIBS)
+LINK_EXE = $(CCC) -bautoexp -brtl $(ALDFLAGS) $(LDFLAGS) \
+ $(RPATHFLAG_PREFIX)$(RPATHFLAG)$(RPATHFLAG_EXTRAS) \
+ -o $@ $(OBJS) $(EXTRA_LIBS)
+endif
+
+#ifeq ($(ARCH),OSF1)
+#LINK_EXE = $(CXX) $(ALDFLAGS) $(LDFLAGS) \
+# $(RPATHFLAG_PREFIX)$(RPATHFLAG)$(RPATHFLAG_EXTRAS) \
+# -o $@ $(OBJS) $(EXTRA_LIBS)
+#endif # OSF1
+
+# Special rule to compile a large source file on Win32:
+# Use the /Zm option to increase internal compiler heap size.
+ifeq ($(ARCH), WINNT)
+$(OBJDEST)/$(FEDSE_OBJ): $(FEDSE_SRC)
+ $(CC) -c /Zm250 $(CFLAGS) $(MCC_INCLUDE) $< -Fo$(OBJDEST)/$(FEDSE_OBJ) $(CBSCFLAGS)
+endif
+
+all: $(OBJDEST) $(BINDIR) $(BUILD_DEP) libslapd $(SLAPD) $(STUB_OBJS)
+
+static: $(OBJDEST) $(LIBSLAPD)
+
+clientSDK: static
+
+.PHONY: libslapd push
+
+libslapd $(LIBSLAPD_DEP):
+ $(MAKE) -f libmakefile $(MFLAGS) all
+
+#$(SLAPD_RES): $(LDAP_SRC)/libraries/libutil/ntslapd.rc \
+# $(DIRVER_H)
+# $(RSC) -fo $(SLAPD_RES) -i. -i $(OBJDIR)/include $<
+
+$(SLAPD): $(SH_LIB_DEP) $(OBJS) $(MAIN_OBJ) $(SLAPD_RES) $(EXTRA_LIBS_DEP)
+ $(QUANTIFY) $(PURIFY) $(PUREOPTS) $(LINK_EXE) $(EXTRA_OBJS) $(DB_LIB)
+
+veryclean: clean
+
+clean:
+ -$(RM) $(OBJS)
+ -$(RM) $(STUB_OBJS)
+ifeq ($(ARCH), WINNT)
+ -$(RM) $(MAIN_OBJ)
+# -$(RM) $(SLAPD_RES)
+endif
+ -$(RM) $(SLAPD)
+ $(MAKE) -f libmakefile clean
+
+# Target to push the built binary to an installed server
+SLAPD_PUSH = $(addprefix $(INSTDIR)/, bin/slapd/server/slapd.exe)
+push: $(SLAPD_PUSH)
+ $(MAKE) -f libmakefile $(MFLAGS) push
+
+$(SLAPD_PUSH): $(SLAPD)
+ cp $(SLAPD) $(SLAPD_PUSH)
+
diff --git a/ldap/servers/slapd/abandon.c b/ldap/servers/slapd/abandon.c
new file mode 100644
index 00000000..df099cda
--- /dev/null
+++ b/ldap/servers/slapd/abandon.c
@@ -0,0 +1,141 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* abandon.c - decode and handle an ldap abandon operation */
+
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+
+void
+do_abandon( Slapi_PBlock *pb )
+{
+ int id, err, suppressed_by_plugin = 0;
+ long long_id;
+ Operation *o;
+ BerElement *ber = pb->pb_op->o_ber;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_abandon\n", 0, 0, 0 );
+
+ /*
+ * Parse the abandon request. It looks like this:
+ *
+ * AbandonRequest := MessageID
+ */
+
+ if ( ber_scanf( ber, "i", &long_id ) == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=Abandon; params=ID)\n",
+ 0, 0 ,0 );
+ return;
+ }
+ id=long_id;
+
+ slapi_pblock_set( pb, SLAPI_ABANDON_MSGID, &id );
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "get_ldapmessage_controls failed: %d (%s) (op=Abandon)\n",
+ err, ldap_err2string( err ), 0);
+ /* LDAP does not allow any response to an abandon */
+ return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_ARGS, "do_abandon: id %d\n", id, 0 ,0 );
+
+ /*
+ * find the operation being abandoned and set the o_abandon
+ * flag. We don't allow the operation to abandon itself.
+ * It's up to the backend to periodically check this
+ * flag and abort the operation at a convenient time.
+ */
+
+ PR_Lock( pb->pb_conn->c_mutex );
+ for ( o = pb->pb_conn->c_ops; o != NULL; o = o->o_next ) {
+ if ( o->o_msgid == id && o != pb->pb_op)
+ break;
+ }
+
+ if ( o != NULL ) {
+ const Slapi_DN *ts = NULL;
+ /*
+ * call the pre-abandon plugins. if they succeed, call
+ * the backend abandon function. then call the post-abandon
+ * plugins.
+ */
+ /* ONREPL - plugins should be passed some information about abandoned operation */
+ /* target spec and abandoned operation type are used to decide which plugins
+ are applicable for the operation */
+ ts = operation_get_target_spec (o);
+ if (ts) {
+ operation_set_target_spec (pb->pb_op, ts);
+ } else {
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_abandon: no target spec of abandoned operation\n", 0,0,0);
+ }
+
+ operation_set_abandoned_op (pb->pb_op, o->o_abandoned_op);
+ if ( plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_ABANDON_FN )
+ == 0 ) {
+ int rc = 0;
+
+ if ( o->o_status != SLAPI_OP_STATUS_RESULT_SENT ) {
+ o->o_status = SLAPI_OP_STATUS_ABANDONED;
+ } else {
+ o = NULL; /* nothing was abandoned */
+ }
+
+ slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc );
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_ABANDON_FN );
+ } else {
+ suppressed_by_plugin = 1;
+ }
+ } else {
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_abandon: op not found\n", 0, 0,
+ 0 );
+ }
+
+ if ( NULL == o ) {
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d ABANDON"
+ " targetop=NOTFOUND msgid=%d\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid, id );
+ } else if ( suppressed_by_plugin ) {
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d ABANDON"
+ " targetop=SUPPRESSED-BY-PLUGIN msgid=%d\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid, id );
+ } else {
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d ABANDON"
+ " targetop=%d msgid=%d nentries=%d etime=%d\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid, o->o_opid, id,
+ o->o_results.r.r_search.nentries, current_time() - o->o_time );
+
+ }
+
+ PR_Unlock( pb->pb_conn->c_mutex );
+ /*
+ * Wake up the persistent searches, so they
+ * can notice if they've been abandoned.
+ */
+ ps_wakeup_all();
+}
diff --git a/ldap/servers/slapd/add.c b/ldap/servers/slapd/add.c
new file mode 100644
index 00000000..3e58f672
--- /dev/null
+++ b/ldap/servers/slapd/add.c
@@ -0,0 +1,781 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#include "pratom.h"
+#include "csngen.h"
+
+/* Forward declarations */
+static int add_internal_pb (Slapi_PBlock *pb);
+static void op_shared_add (Slapi_PBlock *pb);
+static void add_created_attrs(Operation *op, Slapi_Entry *e);
+static void handle_fast_add(Slapi_PBlock *pb, Slapi_Entry *entry);
+static void add_uniqueid (Slapi_Entry *e);
+static PRBool check_oc_subentry(Slapi_Entry *e, struct berval **vals, char *normtype);
+
+/* This function is called to process operation that come over external connections */
+void
+do_add( Slapi_PBlock *pb )
+{
+ Slapi_Operation *operation;
+ BerElement *ber;
+ char *last;
+ unsigned long len, tag;
+ Slapi_Entry *e = NULL;
+ int err;
+ int rc;
+ char ebuf[ BUFSIZ ];
+ PRBool searchsubentry=PR_TRUE;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_add\n", 0, 0, 0 );
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ ber = operation->o_ber;
+
+ /* count the add request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps);
+
+ /*
+ * Parse the add request. It looks like this:
+ *
+ * AddRequest := [APPLICATION 14] SEQUENCE {
+ * name DistinguishedName,
+ * attrs SEQUENCE OF SEQUENCE {
+ * type AttributeType,
+ * values SET OF AttributeValue
+ * }
+ * }
+ */
+ /* get the name */
+ {
+ char *dn;
+ if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=Add; params=DN)\n", 0, 0, 0 );
+ op_shared_log_error_access (pb, "ADD", "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "decoding error", 0, NULL );
+ return;
+ }
+ e = slapi_entry_alloc();
+ slapi_entry_init(e,dn,NULL); /* Responsibility for DN is passed to the Entry. */
+ }
+ LDAPDebug( LDAP_DEBUG_ARGS, " do_add: dn (%s)\n", slapi_entry_get_dn_const(e), 0, 0 );
+
+ /* get the attrs */
+ for ( tag = ber_first_element( ber, &len, &last );
+ tag != LBER_DEFAULT && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element( ber, &len, last ) ) {
+ char *type = NULL, *normtype = NULL;
+ struct berval **vals;
+ if ( ber_scanf( ber, "{a{V}}", &type, &vals ) == LBER_ERROR ) {
+ op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "decoding error", 0, NULL );
+ goto free_and_return;
+ }
+
+ if ( vals == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "no values for type %s\n", type, 0, 0 );
+ op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "null value");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL,
+ 0, NULL );
+ free( type );
+ goto free_and_return;
+ }
+
+ normtype = slapi_attr_syntax_normalize(type);
+ if ( !normtype || !*normtype ) {
+ rc = LDAP_INVALID_SYNTAX;
+ PR_snprintf (ebuf, BUFSIZ, "invalid type '%s'", type);
+ ebuf[BUFSIZ-1] = '\0';
+ op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), ebuf);
+ send_ldap_result( pb, rc, NULL, ebuf, 0, NULL );
+ free( type );
+ slapi_ch_free( (void**)&normtype );
+ ber_bvecfree( vals );
+ goto free_and_return;
+ }
+ free( type );
+
+ /* for now we just ignore attributes that client is not allowed
+ to modify so not to break existing clients */
+ if (op_shared_is_allowed_attr (normtype, pb->pb_conn->c_isreplication_session)){
+ if (( rc = slapi_entry_add_values( e, normtype, vals ))
+ != LDAP_SUCCESS ) {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d ADD dn=\"%s\", add values for type %s failed\n",
+ pb->pb_conn->c_connid, operation->o_opid,
+ escape_string( slapi_entry_get_dn_const(e), ebuf ), normtype );
+ send_ldap_result( pb, rc, NULL, NULL, 0, NULL );
+
+ slapi_ch_free( (void**)&normtype );
+ ber_bvecfree( vals );
+ goto free_and_return;
+ }
+
+ /* if this is uniqueid attribute, set uniqueid field of the entry */
+ if (strcasecmp (normtype, SLAPI_ATTR_UNIQUEID) == 0)
+ {
+ e->e_uniqueid = slapi_ch_strdup (vals[0]->bv_val);
+ }
+ if(searchsubentry) searchsubentry=check_oc_subentry(e,vals,normtype);
+ }
+ slapi_ch_free( (void**)&normtype );
+ ber_bvecfree( vals );
+ }
+
+ if ( tag == LBER_DEFAULT ) {
+ op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "decoding error", 0, NULL );
+ goto free_and_return;
+ }
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ op_shared_log_error_access (pb, "ADD", slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)),
+ "failed to decode LDAP controls");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &operation->o_isroot );
+ slapi_pblock_set( pb, SLAPI_ADD_ENTRY, e );
+
+ if (pb->pb_conn->c_flags & CONN_FLAG_IMPORT) {
+ /* this add is actually part of a bulk import -- punt */
+ handle_fast_add(pb, e);
+ } else {
+ op_shared_add ( pb );
+ }
+
+ /* make sure that we don't free entry if it is successfully added */
+ e = NULL;
+
+free_and_return:;
+ if (e)
+ slapi_entry_free (e);
+
+}
+
+/* This function is used to issue internal add operation
+ This is an old style API. Its use is discoraged because it is not extendable and
+ because it does not allow to check whether plugin has right to access part of the
+ tree it is trying to modify. Use slapi_add_internal_pb instead */
+Slapi_PBlock *
+slapi_add_internal(const char *idn,
+ LDAPMod **iattrs,
+ LDAPControl **controls,
+ int dummy)
+{
+ Slapi_Entry *e;
+ Slapi_PBlock *result_pb = NULL;
+ int opresult= -1;
+
+ if(iattrs == NULL)
+ {
+ opresult = LDAP_PARAM_ERROR;
+ goto done;
+ }
+
+ opresult = slapi_mods2entry (&e, (char*)idn, iattrs);
+ if (opresult != LDAP_SUCCESS)
+ {
+ goto done;
+ }
+
+ result_pb= slapi_add_entry_internal(e, controls, dummy);
+
+done:
+ if(result_pb==NULL)
+ {
+ result_pb = slapi_pblock_new();
+ pblock_init(result_pb);
+ slapi_pblock_set(result_pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ }
+
+ return result_pb;
+}
+
+/* This function is used to issue internal add operation
+ This is an old style API. Its use is discoraged because it is not extendable and
+ because it does not allow to check whether plugin has right to access part of the
+ tree it is trying to modify. Use slapi_add_internal_pb instead
+ Beware: The entry is consumed. */
+Slapi_PBlock *
+slapi_add_entry_internal(Slapi_Entry *e, LDAPControl **controls, int dummy)
+{
+ Slapi_PBlock pb;
+ Slapi_PBlock *result_pb = NULL;
+ int opresult;
+
+ pblock_init(&pb);
+
+ slapi_add_entry_internal_set_pb (&pb, e, controls, plugin_get_default_component_id(), 0);
+
+ add_internal_pb (&pb);
+
+ result_pb = slapi_pblock_new();
+ if (result_pb)
+ {
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ slapi_pblock_set(result_pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ }
+ pblock_done(&pb);
+
+ return result_pb;
+}
+
+/* This is new style API to issue internal add operation.
+ pblock should contain the following data (can be set via call to slapi_add_internal_set_pb):
+ SLAPI_TARGET_DN set to dn of the new entry
+ SLAPI_CONTROLS_ARG set to request controls if present
+ SLAPI_ADD_ENTRY set to Slapi_Entry to add
+ Beware: The entry is consumed. */
+int slapi_add_internal_pb (Slapi_PBlock *pb)
+{
+ if (pb == NULL)
+ return -1;
+
+ if (!allow_operation (pb))
+ {
+ slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "This plugin is not configured to access operation target data", 0, NULL );
+ return 0;
+ }
+
+ return add_internal_pb (pb);
+}
+
+int slapi_add_internal_set_pb (Slapi_PBlock *pb, const char *dn, LDAPMod **attrs, LDAPControl **controls,
+ Slapi_ComponentId *plugin_identity, int operation_flags)
+{
+ Slapi_Entry *e;
+ int rc;
+
+ if (pb == NULL || dn == NULL || attrs == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, NULL, "slapi_add_internal_set_pb: invalid argument\n");
+ return LDAP_PARAM_ERROR;
+ }
+
+ rc = slapi_mods2entry (&e, dn, attrs);
+ if (rc == LDAP_SUCCESS)
+ {
+ slapi_add_entry_internal_set_pb (pb, e, controls, plugin_identity, operation_flags);
+ }
+
+ return rc;
+}
+
+
+/* Initialize a pblock for a call to slapi_add_internal_pb() */
+void slapi_add_entry_internal_set_pb (Slapi_PBlock *pb, Slapi_Entry *e, LDAPControl **controls,
+ Slapi_ComponentId *plugin_identity, int operation_flags)
+{
+ Operation *op;
+ PR_ASSERT (pb != NULL);
+ if (pb == NULL || e == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_PLUGIN, NULL, "slapi_add_entry_internal_set_pb: invalid argument\n");
+ return;
+ }
+
+ op = internal_operation_new(SLAPI_OPERATION_ADD,operation_flags);
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ slapi_pblock_set(pb, SLAPI_ADD_ENTRY, e);
+ slapi_pblock_set(pb, SLAPI_CONTROLS_ARG, controls);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, plugin_identity);
+}
+
+/* Helper functions */
+
+static int add_internal_pb (Slapi_PBlock *pb)
+{
+ LDAPControl **controls;
+ Operation *op;
+ int opresult = 0;
+ Slapi_Entry *e;
+
+ PR_ASSERT (pb != NULL);
+
+ slapi_pblock_get(pb, SLAPI_ADD_ENTRY, &e);
+ slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
+
+ if (e == NULL)
+ {
+ opresult = LDAP_PARAM_ERROR;
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ return 0;
+ }
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op->o_handler_data = &opresult;
+ op->o_result_handler = internal_getresult_callback;
+
+ slapi_pblock_set(pb, SLAPI_REQCONTROLS, controls);
+
+ /* set parameters common to all internal operations */
+ set_common_params (pb);
+
+ /* set actions taken to process the operation */
+ set_config_params (pb);
+
+ /* perform the add operation */
+ op_shared_add (pb);
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+
+ return 0;
+}
+
+/* Code shared between regular and internal add operation */
+static void op_shared_add (Slapi_PBlock *pb)
+{
+ Slapi_Operation *operation;
+ Slapi_Entry *e, *pse;
+ Slapi_Backend *be = NULL;
+ int err;
+ char ebuf[BUFSIZ];
+ int internal_op, repl_op, legacy_op, lastmod;
+ char *pwdtype = NULL;
+ Slapi_Value **unhashed_password_vals = NULL;
+ Slapi_Attr *attr = NULL;
+ Slapi_Entry *referral;
+ char errorbuf[BUFSIZ];
+ struct slapdplugin *p = NULL;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+ slapi_pblock_get (pb, SLAPI_ADD_ENTRY, &e);
+ slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ slapi_pblock_get (pb, SLAPI_IS_LEGACY_REPLICATED_OPERATION, &legacy_op);
+ internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ operation_set_target_spec (operation, slapi_entry_get_sdn (e));
+
+ if ((err = slapi_entry_add_rdn_values(e)) != LDAP_SUCCESS)
+ {
+ send_ldap_result(pb, err, NULL, "failed to add RDN values", 0, NULL);
+ goto done;
+ }
+
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ if ( !internal_op )
+ {
+ slapi_log_access(LDAP_DEBUG_STATS, "conn=%d op=%d ADD dn=\"%s\"\n",
+ pb->pb_conn->c_connid,
+ operation->o_opid,
+ escape_string(slapi_entry_get_dn_const(e), ebuf));
+ }
+ else
+ {
+ slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d ADD dn=\"%s\"\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ escape_string(slapi_entry_get_dn_const(e), ebuf));
+ }
+ }
+
+ /*
+ * We could be serving multiple database backends. Select the
+ * appropriate one.
+ */
+ if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf)) != LDAP_SUCCESS) {
+ send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
+ be = NULL;
+ goto done;
+ }
+
+ if (referral)
+ {
+ int managedsait;
+
+ slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ if (managedsait)
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "cannot update referral", 0, NULL);
+ slapi_entry_free(referral);
+ goto done;
+ }
+
+ slapi_pblock_set(pb, SLAPI_TARGET_DN, (void*)slapi_sdn_get_ndn(operation_get_target_spec (operation)));
+ send_referrals_from_entry(pb,referral);
+ slapi_entry_free(referral);
+ goto done;
+ }
+
+ if (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)) {
+ /* look for user password attribute */
+ slapi_entry_attr_find(e, SLAPI_USERPWD_ATTR, &attr);
+ if (attr && !repl_op)
+ {
+ Slapi_Value **present_values;
+ present_values= attr_get_present_values(attr);
+
+ /* check password syntax */
+ if (check_pw_syntax(pb, slapi_entry_get_sdn_const(e), present_values, NULL, e, 0) == 0)
+ {
+ Slapi_Value **vals= NULL;
+ valuearray_add_valuearray(&unhashed_password_vals, present_values, 0);
+ valuearray_add_valuearray(&vals, present_values, 0);
+ pw_encodevals(vals);
+ add_password_attrs(pb, operation, e);
+ slapi_entry_attr_replace_sv(e, SLAPI_USERPWD_ATTR, vals);
+ valuearray_free(&vals);
+
+ /* Add the unhashed password pseudo-attribute to the entry */
+ pwdtype = slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
+ slapi_entry_add_values_sv(e, pwdtype, unhashed_password_vals);
+ } else {
+ /* error result is sent from check_pw_syntax */
+ goto done;
+ }
+ }
+
+ /* look for multiple backend local credentials or replication local credentials */
+ for ( p = get_plugin_list(PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME); p != NULL;
+ p = p->plg_next )
+ {
+ char *L_attr = NULL;
+ int i=0;
+
+ /* Get the appropriate decoding function */
+ for ( L_attr = p->plg_argv[i]; i<p->plg_argc; L_attr = p->plg_argv[++i])
+ {
+ /* look for multiple backend local credentials or replication local credentials */
+ char *L_normalized = slapi_attr_syntax_normalize(L_attr);
+ slapi_entry_attr_find(e, L_normalized, &attr);
+ if (attr)
+ {
+ Slapi_Value **present_values = NULL;
+ Slapi_Value **vals = NULL;
+
+ present_values= attr_get_present_values(attr);
+
+ valuearray_add_valuearray(&vals, present_values, 0);
+ pw_rever_encode(vals, L_normalized);
+ slapi_entry_attr_replace_sv(e, L_normalized, vals);
+ valuearray_free(&vals);
+ }
+ if (L_normalized)
+ slapi_ch_free ((void**)&L_normalized);
+ }
+ }
+ }
+
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ /* we set local password policy ACI for non-replicated operations only */
+ if (!repl_op &&
+ !operation_is_flag_set(operation, OP_FLAG_REPL_FIXUP) &&
+ !operation_is_flag_set(operation, OP_FLAG_LEGACY_REPLICATION_DN) &&
+ !slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA) &&
+ !slapi_be_private(be) &&
+ slapi_be_issuffix (be, slapi_entry_get_sdn_const(e)))
+ {
+ /* this is a suffix. update the pw aci */
+ slapdFrontendConfig_t *slapdFrontendConfig;
+ slapdFrontendConfig = getFrontendConfig();
+ pw_add_allowchange_aci(e, !slapdFrontendConfig->pw_policy.pw_change &&
+ !slapdFrontendConfig->pw_policy.pw_must_change);
+ }
+
+ /* can get lastmod only after backend is selected */
+ slapi_pblock_get(pb, SLAPI_BE_LASTMOD, &lastmod);
+ if (!repl_op && lastmod)
+ {
+ add_created_attrs(operation, e);
+ /* JCM - We could end up with an entry without a uniqueid...??? */
+ }
+
+ /* expand objectClass values to reflect the inheritance hierarchy */
+ if (!repl_op) {
+ slapi_schema_expand_objectclasses( e );
+ }
+
+
+ /* uniqueid needs to be generated for entries added during legacy replication */
+ if (legacy_op)
+ add_uniqueid (e);
+
+ /*
+ * call the pre-add plugins. if they succeed, call
+ * the backend add function. then call the post-add
+ * plugins.
+ */
+
+ slapi_pblock_set(pb, SLAPI_ADD_TARGET,
+ (char*)slapi_sdn_get_ndn(slapi_entry_get_sdn_const(e)));
+ if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN :
+ SLAPI_PLUGIN_PRE_ADD_FN) == 0)
+ {
+ int rc;
+ Slapi_Entry *ec;
+ char *add_target_dn;
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
+ set_db_default_result_handlers(pb);
+
+ /* Remove the unhashed password pseudo-attribute
+ from the entry before duplicating the entry */
+
+ if (unhashed_password_vals)
+ {
+ slapi_entry_delete_values(e, pwdtype, NULL);
+ }
+
+ /* because be_add frees the entry */
+ ec = slapi_entry_dup(e);
+ add_target_dn= slapi_ch_strdup(slapi_sdn_get_ndn(slapi_entry_get_sdn_const(ec)));
+ slapi_pblock_set(pb, SLAPI_ADD_TARGET, add_target_dn);
+
+ if (be->be_add != NULL)
+ {
+ rc = (*be->be_add)(pb);
+ slapi_pblock_set(pb, SLAPI_ADD_ENTRY, ec);
+ if (rc == 0)
+ {
+ /* acl is not enabled for internal operations */
+ /* don't update aci store for remote acis */
+ if ((!internal_op) &&
+ (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
+ {
+ plugin_call_acl_mods_update (pb, SLAPI_OPERATION_ADD);
+ }
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
+ {
+ write_audit_log_entry(pb); /* Record the operation in the audit log */
+ }
+
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
+ do_ps_service(pse, NULL, LDAP_CHANGETYPE_ADD, 0);
+
+ e = NULL; /* if be_add succeeded, then e is consumed. Must prevent e from being free'd. */
+ }
+ else
+ {
+ if (rc == SLAPI_FAIL_DISKFULL)
+ {
+ operation_out_of_disk_space();
+ goto done;
+ }
+ }
+ }
+ else
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Function not implemented", 0, NULL);
+ }
+
+ /* Reattach the unhashed password pseudo-attribute
+ to the entry copy (ec), before calling the postop plugin */
+ if(unhashed_password_vals)
+ {
+ slapi_entry_add_values_sv(ec, pwdtype, unhashed_password_vals);
+ }
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_ADD_FN :
+ SLAPI_PLUGIN_POST_ADD_FN);
+ slapi_entry_free(ec);
+ slapi_pblock_get(pb, SLAPI_ADD_TARGET, &add_target_dn);
+ slapi_ch_free((void**)&add_target_dn);
+ }
+
+done:
+ if (be)
+ slapi_be_Unlock(be);
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
+ slapi_entry_free(pse);
+ slapi_ch_free((void **)&operation->o_params.p.p_add.parentuniqueid);
+ slapi_entry_free(e);
+ valuearray_free(&unhashed_password_vals);
+ slapi_ch_free((void**)&pwdtype);
+}
+
+static void
+add_created_attrs(Operation *op, Slapi_Entry *e)
+{
+ char buf[20];
+ struct berval bv;
+ struct berval *bvals[2];
+ time_t curtime;
+ struct tm ltm;
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "add_created_attrs\n", 0, 0, 0);
+
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+
+ if (slapi_sdn_isempty(&op->o_sdn)) {
+ bv.bv_val = "";
+ bv.bv_len = strlen(bv.bv_val);
+ } else {
+ bv.bv_val = (char*)slapi_sdn_get_dn(&op->o_sdn);
+ bv.bv_len = strlen(bv.bv_val);
+ }
+ slapi_entry_attr_replace(e, "creatorsname", bvals);
+ slapi_entry_attr_replace(e, "modifiersname", bvals);
+
+ curtime = current_time();
+#ifdef _WIN32
+{
+ struct tm *pt;
+ pt = gmtime(&curtime);
+ memcpy(&ltm, pt, sizeof(struct tm));
+}
+#else
+ gmtime_r(&curtime, &ltm);
+#endif
+ strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &ltm);
+
+ bv.bv_val = buf;
+ bv.bv_len = strlen(bv.bv_val);
+ slapi_entry_attr_replace(e, "createtimestamp", bvals);
+
+ bv.bv_val = buf;
+ bv.bv_len = strlen(bv.bv_val);
+ slapi_entry_attr_replace(e, "modifytimestamp", bvals);
+
+ add_uniqueid (e);
+}
+
+
+static void handle_fast_add(Slapi_PBlock *pb, Slapi_Entry *entry)
+{
+ Slapi_Backend *be;
+ Slapi_Operation *operation;
+ int ret;
+
+ be = pb->pb_conn->c_bi_backend;
+
+ if ((be == NULL) || (be->be_wire_import == NULL)) {
+ /* can this even happen? */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "handle_fast_add: backend not supported\n", 0, 0, 0);
+ send_ldap_result(pb, LDAP_NOT_SUPPORTED, NULL, NULL, 0, NULL);
+ return;
+ }
+
+ /* ensure that the RDN values are present as attribute values */
+ if ((ret = slapi_entry_add_rdn_values(entry)) != LDAP_SUCCESS) {
+ send_ldap_result(pb, ret, NULL, "failed to add RDN values", 0, NULL);
+ return;
+ }
+
+ /* schema check */
+ slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
+ if (operation_is_flag_set(operation, OP_FLAG_ACTION_SCHEMA_CHECK) &&
+ (slapi_entry_schema_check(pb, entry) != 0)) {
+ char *errtext;
+ LDAPDebug(LDAP_DEBUG_TRACE, "entry failed schema check\n", 0, 0, 0);
+ slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext);
+ send_ldap_result(pb, LDAP_OBJECT_CLASS_VIOLATION, NULL, errtext, 0, NULL);
+ slapi_entry_free(entry);
+ return;
+ }
+
+ /* Check if the entry being added is a Tombstone. Could be if we are
+ * doing a replica init. */
+ if (slapi_entry_attr_hasvalue(entry, SLAPI_ATTR_OBJECTCLASS,
+ SLAPI_ATTR_VALUE_TOMBSTONE)) {
+ entry->e_flags |= SLAPI_ENTRY_FLAG_TOMBSTONE;
+ }
+
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ slapi_pblock_set(pb, SLAPI_BULK_IMPORT_ENTRY, entry);
+ ret = SLAPI_BI_STATE_ADD;
+ slapi_pblock_set(pb, SLAPI_BULK_IMPORT_STATE, &ret);
+ ret = (*be->be_wire_import)(pb);
+ if (ret != 0) {
+ if (ret != LDAP_BUSY) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "wire import: error during import (%d)\n",
+ ret, 0, 0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "wire import: asking client to wait before resuming (returning LDAP_BUSY)\n",
+ 0, 0, 0);
+ }
+ send_ldap_result(pb,
+ LDAP_BUSY == ret ? LDAP_BUSY : LDAP_OPERATIONS_ERROR,
+ NULL, NULL, 0, NULL);
+ slapi_entry_free(entry);
+
+ if (LDAP_BUSY != ret) {
+ /* turn off fast replica init -- import is now aborted */
+ pb->pb_conn->c_bi_backend = NULL;
+ pb->pb_conn->c_flags &= ~CONN_FLAG_IMPORT;
+ }
+ return;
+ }
+
+ send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
+ return;
+}
+
+static void
+add_uniqueid (Slapi_Entry *e)
+{
+ char *uniqueid;
+ int rc;
+
+ /* generate uniqueID for the entry */
+ rc = slapi_uniqueIDGenerateString (&uniqueid);
+ if (rc == UID_SUCCESS)
+ {
+ slapi_entry_set_uniqueid (e, uniqueid);
+ }
+ else
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "add_created_attrs: uniqueid generation failed for %s; error = %d\n",
+ slapi_entry_get_dn_const(e), rc, 0);
+ }
+}
+
+static PRBool
+check_oc_subentry(Slapi_Entry *e, struct berval **vals, char *normtype) {
+ int n;
+
+ PRBool subentry=PR_TRUE;
+ for(n=0; vals != NULL && vals[n] != NULL; n++) {
+ if((strcasecmp(normtype,"objectclass") == 0)
+ && (strncasecmp((const char *)vals[n]->bv_val,"ldapsubentry",vals[n]->bv_len) == 0)) {
+ e->e_flags |= SLAPI_ENTRY_LDAPSUBENTRY;
+ subentry=PR_FALSE;
+ break;
+ }
+ }
+ return subentry;
+}
diff --git a/ldap/servers/slapd/agtmmap.c b/ldap/servers/slapd/agtmmap.c
new file mode 100644
index 00000000..76abedeb
--- /dev/null
+++ b/ldap/servers/slapd/agtmmap.c
@@ -0,0 +1,330 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/********************************************************************
+ *
+ * agtmmap.c: Memory Map interface for SNMP sub-agent for
+ * Netscape Directory Server stats (for UNIX environment).
+ *
+ * Revision History:
+ * 07/22/97 Created Steve Ross
+ *
+ *
+ **********************************************************************/
+
+
+#include "agtmmap.h"
+#ifndef _WIN32
+#include <sys/mman.h>
+#include <unistd.h>
+#else
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <time.h>
+#include "nt/regparms.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#ifndef _WIN32
+agt_mmap_context_t mmap_tbl [2] = { {AGT_MAP_UNINIT, -1, (caddr_t) -1},
+ {AGT_MAP_UNINIT, -1, (caddr_t) -1} };
+#else
+agt_mmap_context_t mmap_tbl[2] = { {AGT_MAP_UNINIT, NULL, (caddr_t) -1, NULL},
+ {AGT_MAP_UNINIT, NULL, (caddr_t) -1, NULL} };
+#endif /* ! _WIN32 */
+
+
+/****************************************************************************
+ *
+ * agt_mopen_stats () - open and Memory Map the stats file. agt_mclose_stats()
+ * must be called prior to invoking agt_mopen_stats() again.
+ * Inputs:
+ * statsfile -> Name of stats file including full path or NULL.
+ * If NULL, default (slapd.stats) is assumed.
+ * mode -> Must be one of O_RDONLY / O_RDWR.
+ * O_RDWR creates the file if it does not exist.
+ * Outputs:
+ * hdl -> Opaque handle to the mapped file. Should be passed
+ * Passed to a subsequent agt_mupdate_stats() or
+ * agt_mread_stats() or agt_mclose_stats() call.
+ * Return Values:
+ * Returns 0 on successfully doing the memmap or error codes
+ * as defined in <errno.h>, otherwise.
+ *
+ ****************************************************************************/
+
+int
+agt_mopen_stats (char * statsfile, int mode, int *hdl)
+{
+ caddr_t fp;
+ char *path;
+#ifndef _WIN32
+ int fd;
+ char *buf;
+ int err;
+ size_t sz;
+ struct stat fileinfo;
+#endif /* _WIN32 */
+
+ switch (mode)
+ {
+ case O_RDONLY:
+ if (mmap_tbl [0].maptype != AGT_MAP_UNINIT)
+ {
+ *hdl = 0;
+ return (EEXIST); /* We already mapped it once */
+ }
+ break;
+
+ case O_RDWR:
+ if (mmap_tbl [1].maptype != AGT_MAP_UNINIT)
+ {
+ *hdl = 1;
+ return (EEXIST); /* We already mapped it once */
+ }
+ break;
+
+ default:
+ return (EINVAL); /* Invalid (mode) parameter */
+
+ } /* end switch */
+
+
+ if (statsfile != NULL)
+ path = statsfile;
+ else
+ path = AGT_STATS_FILE;
+
+
+#ifndef _WIN32
+ switch (mode)
+ {
+ case O_RDONLY:
+ if ( (fd = open (path, O_RDONLY)) < 0 )
+ {
+ err = errno;
+#if (0)
+ fprintf (stderr, "returning errno =%d from %s(line: %d)\n", err, __FILE__, __LINE__);
+#endif
+ return (err);
+ }
+
+ fp = mmap (NULL, sizeof (struct agt_stats_t), PROT_READ, MAP_PRIVATE, fd, 0);
+
+ if (fp == (caddr_t) -1)
+ {
+ err = errno;
+ close (fd);
+#if (0)
+ fprintf (stderr, "returning errno =%d from %s(line: %d)\n", err, __FILE__, __LINE__);
+#endif
+ return (err);
+ }
+
+ mmap_tbl [0].maptype = AGT_MAP_READ;
+ mmap_tbl [0].fd = fd;
+ mmap_tbl [0].fp = fp;
+ *hdl = 0;
+#if (0)
+ fprintf (stderr, "%s@%d> opened fp = %d\n", __FILE__, __LINE__, fp);
+#endif
+ return (0);
+
+ case O_RDWR:
+ fd = open (path,
+ O_RDWR | O_CREAT,
+ S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);
+
+ if ( fd < 0 )
+ {
+ err = errno;
+#if (0)
+ fprintf (stderr, "returning errno =%d from %s(line: %d)\n", err, __FILE__, __LINE__);
+#endif
+ return (err);
+ }
+
+ fstat (fd, &fileinfo);
+
+ sz = sizeof (struct agt_stats_t);
+
+ if (fileinfo.st_size < sz)
+ {
+ /* Without this we will get segv when we try to read/write later */
+ buf = calloc (1, sz);
+ write (fd, buf, sz);
+ free (buf);
+ }
+
+ fp = mmap (NULL, sz, (PROT_READ | PROT_WRITE), MAP_SHARED, fd, 0);
+
+ if (fp == (caddr_t) -1)
+ {
+ err = errno;
+ close (fd);
+#if (0)
+ fprintf (stderr, "returning errno =%d from %s(line: %d)\n", err, __FILE__, __LINE__);
+#endif
+ return (err);
+ }
+
+ mmap_tbl [1].maptype = AGT_MAP_RDWR;
+ mmap_tbl [1].fd = fd;
+ mmap_tbl [1].fp = fp;
+ *hdl = 1;
+ return (0);
+
+ } /* end switch */
+#else
+
+ switch (mode) {
+ case O_RDONLY:
+ {
+ HANDLE hFile = NULL;
+ HANDLE hMapFile = NULL;
+
+ /* Open existing disk file for read */
+ hFile = CreateFile(path,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL ) return GetLastError();
+
+ /* Create mapped file handle for reading */
+ hMapFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0,
+ sizeof(struct agt_stats_t),
+ NULL);
+ if ( hMapFile == NULL ) {
+ CloseHandle( hFile );
+ return GetLastError();
+ }
+
+ /* Create addr ptr to the start of the file */
+ fp = (caddr_t) MapViewOfFileEx( hMapFile, FILE_MAP_READ, 0, 0,
+ sizeof(struct agt_stats_t), NULL );
+ if ( fp == NULL ) {
+ CloseHandle( hMapFile );
+ CloseHandle( hFile );
+ return GetLastError();
+ }
+
+ /* Fill in info on this opaque handle */
+ mmap_tbl[0].maptype = AGT_MAP_READ;
+ mmap_tbl[0].fd = hFile;
+ mmap_tbl[0].fp = fp;
+ mmap_tbl[0].mfh = hMapFile;
+ *hdl = 0;
+ return 0;
+ }
+
+ case O_RDWR:
+ {
+
+ HANDLE hFile = NULL;
+ HANDLE hMapFile = NULL;
+
+ hFile = CreateFile( path,
+ GENERIC_WRITE | GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL );
+ if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL ) return GetLastError();
+
+ /* Create mapped file handle for reading */
+ hMapFile = CreateFileMapping( hFile, NULL, PAGE_READWRITE, 0,
+ sizeof(struct agt_stats_t),
+ NULL );
+ if ( hMapFile == NULL ) {
+ CloseHandle( hFile );
+ return GetLastError();
+ }
+
+ /* Create addr ptr to the start of the file */
+ fp = (caddr_t) MapViewOfFileEx( hMapFile, FILE_MAP_ALL_ACCESS, 0, 0,
+ sizeof(struct agt_stats_t), NULL );
+ if ( fp == NULL ) {
+ CloseHandle( hMapFile );
+ CloseHandle( hFile );
+ return GetLastError();
+ }
+
+ mmap_tbl[1].maptype = AGT_MAP_RDWR;
+ mmap_tbl[1].fd = hFile;
+ mmap_tbl[1].fp = fp;
+ mmap_tbl[1].mfh = hMapFile;
+ *hdl = 1;
+ return 0;
+
+ }
+
+
+ }
+
+#endif /* !__WINNT__ */
+
+return 0;
+
+} /* agt_mopen_stats () */
+
+
+/****************************************************************************
+ *
+ * agt_mclose_stats () - Close the Memory Map'ed the stats file.
+ *
+ *
+ * Inputs:
+ * hdl -> Opaque handle to the mapped file. Should be have been
+ * returned by an earlier call to agt_mopen_stats().
+ *
+ * Outputs: <NONE>
+ *
+ * Return Values:
+ * Returns 0 on normal completion or error codes
+ * as defined in <errno.h>, otherwise.
+ *
+ ****************************************************************************/
+int
+agt_mclose_stats (int hdl)
+{
+ if ( (hdl > 1) || (hdl < 0) )
+ {
+ return (EINVAL); /* Inavlid handle */
+ }
+
+ if (mmap_tbl [hdl].maptype == AGT_MAP_UNINIT)
+ return (0);
+
+ if (mmap_tbl [hdl].fp > (caddr_t) 0)
+ {
+#ifndef _WIN32
+ munmap (mmap_tbl [hdl].fp, sizeof (struct agt_stats_t));
+ mmap_tbl [hdl].fp = (caddr_t) -1;
+ close (mmap_tbl [hdl].fd);
+ mmap_tbl [hdl].fd = -1;
+#else
+ BOOL bUnmapped;
+
+ bUnmapped = UnmapViewOfFile( mmap_tbl[hdl].fp );
+ if ( mmap_tbl[hdl].mfh ) CloseHandle( mmap_tbl[hdl].mfh );
+ if ( mmap_tbl[hdl].fd ) CloseHandle( mmap_tbl[hdl].fd );
+
+ mmap_tbl[hdl].fp = (caddr_t) -1;
+ mmap_tbl[hdl].mfh = NULL;
+ mmap_tbl[hdl].fd = NULL;
+#endif /* ! _WIN32 */
+ mmap_tbl [hdl].maptype = AGT_MAP_UNINIT;
+ return (0);
+ }
+
+ return EINVAL;
+} /* agt_mclose_stats () */
diff --git a/ldap/servers/slapd/agtmmap.h b/ldap/servers/slapd/agtmmap.h
new file mode 100644
index 00000000..7f7cbfc1
--- /dev/null
+++ b/ldap/servers/slapd/agtmmap.h
@@ -0,0 +1,191 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/********************************************************************
+ *
+ * agtmmap.h: Memory Map interface for SNMP sub-agent for
+ * Netscape Directory Server stats (for UNIX environment).
+ *
+ * Revision History:
+ * 07/22/97 Created Steve Ross
+ *
+ *
+ *
+ **********************************************************************/
+
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#ifdef _WIN32
+#include <windows.h>
+#define caddr_t PCHAR
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define NUM_SNMP_INT_TBL_ROWS 5
+#ifndef _WIN32
+extern int errno;
+#endif
+
+#if !defined(_MAX_PATH)
+#define _MAX_PATH 256
+#endif
+#define AGT_STATS_FILE "slapd.stats"
+#define AGT_MJR_VERSION 1
+#define AGT_MNR_VERSION 0
+
+
+typedef enum { AGT_MAP_UNINIT = 0, AGT_MAP_READ, AGT_MAP_RDWR } agt_mmap_type;
+
+#ifndef _WIN32
+typedef struct
+{
+ agt_mmap_type maptype;
+ int fd;
+ caddr_t fp;
+} agt_mmap_context_t;
+#else
+typedef struct
+{
+ agt_mmap_type maptype;
+ HANDLE fd;
+ caddr_t fp;
+ HANDLE mfh;
+} agt_mmap_context_t;
+#endif /* ! _WIN32 */
+
+struct hdr_stats_t{
+ /*
+ * Header
+ */
+ int hdrVersionMjr;
+ int hdrVersionMnr;
+ int restarted; /* 1/0 = Yes/No */
+ time_t startTime;
+ time_t updateTime;
+
+};
+
+struct ops_stats_t{
+ /*
+ * Ops Table attributes
+ */
+ int dsAnonymousBinds;
+ int dsUnAuthBinds;
+ int dsSimpleAuthBinds;
+ int dsStrongAuthBinds;
+ int dsBindSecurityErrors;
+ int dsInOps;
+ int dsReadOps;
+ int dsCompareOps;
+ int dsAddEntryOps;
+ int dsRemoveEntryOps;
+ int dsModifyEntryOps;
+ int dsModifyRDNOps;
+ int dsListOps;
+ int dsSearchOps;
+ int dsOneLevelSearchOps;
+ int dsWholeSubtreeSearchOps;
+ int dsReferrals;
+ int dsChainings;
+ int dsSecurityErrors;
+ int dsErrors;
+ int dsConnections; /* Number of currently connected clients */
+ int dsConnectionSeq; /* Monotonically increasing number bumped on each new conn est */
+ int dsBytesRecv; /* Count of bytes read from clients */
+ int dsBytesSent; /* Count of bytes sent to clients */
+ int dsEntriesReturned; /* Number of entries returned by the server */
+ int dsReferralsReturned; /* Number of entries returned by the server */
+};
+
+struct entries_stats_t
+{
+ /*
+ * Entries Table Attributes
+ */
+
+ int dsMasterEntries;
+ int dsCopyEntries;
+ int dsCacheEntries;
+ int dsCacheHits;
+ int dsSlaveHits;
+
+};
+struct int_stats_t
+{
+ /*
+ * Interaction Table Attributes
+ */
+
+ int dsIntIndex;
+ char dsName[100];
+ time_t dsTimeOfCreation;
+ time_t dsTimeOfLastAttempt;
+ time_t dsTimeOfLastSuccess;
+ int dsFailuresSinceLastSuccess;
+ int dsFailures;
+ int dsSuccesses;
+ char dsURL[100];
+
+};
+struct agt_stats_t
+{
+ struct hdr_stats_t hdr_stats;
+ struct ops_stats_t ops_stats;
+ struct entries_stats_t entries_stats;
+ struct int_stats_t int_stats[NUM_SNMP_INT_TBL_ROWS];
+
+} ;
+
+extern agt_mmap_context_t mmap_tbl[];
+
+/****************************************************************************
+ *
+ * agt_mopen_stats () - open and Memory Map the stats file. agt_mclose_stats()
+ * must be called prior to invoking agt_mopen_stats() again.
+ * Inputs:
+ * statsfile -> Name of stats file including full path or NULL.
+ * If NULL, default ($NETSITE_ROOT/daemonstats.ldap) is assumed.
+ * mode -> Must be one of O_RDONLY / O_RDWR.
+ * O_RDWR creates the file if it does not exist.
+ * Outputs:
+ * hdl -> Opaque handle to the mapped file. Should be
+ * passed to a subsequent agt_mupdate_stats() or
+ * agt_mread_stats() or agt_mclose_stats() call.
+ * Return Values:
+ * Returns 0 on successfully doing the memmap or error
+ * codes as defined in <errno.h>, otherwise.
+ *
+ ****************************************************************************/
+
+int agt_mopen_stats (char * statsfile, int mode, int *hdl);
+
+/****************************************************************************
+ *
+ * agt_mclose_stats () - Close the Memory Map'ed stats file.
+ *
+ *
+ * Inputs:
+ * hdl -> Opaque handle to the mapped file. Should have been
+ * returned by an earlier call to agt_mopen_stats().
+ *
+ * Outputs: <NONE>
+ *
+ * Return Values: Returns 0 on normal completion or error codes
+ * as defined in <errno.h>, otherwise.
+ *
+ ****************************************************************************/
+int agt_mclose_stats (int hdl);
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/ldap/servers/slapd/apibroker.c b/ldap/servers/slapd/apibroker.c
new file mode 100644
index 00000000..28068401
--- /dev/null
+++ b/ldap/servers/slapd/apibroker.c
@@ -0,0 +1,245 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* ABAPI Broker */
+/* Pete Rowley */
+
+#include "stdio.h"
+#include "slap.h"
+#include "prlock.h"
+#include "prerror.h"
+#include "prcvar.h"
+#include "prio.h"
+
+static Slapi_Mutex *buffer_lock = 0;
+
+/* circular api buffer */
+
+typedef struct _THEABAPI
+{
+ char *guid;
+ void **api;
+ struct _THEABAPI *next;
+ struct _THEABAPI *prev;
+} ABAPI;
+
+typedef struct _API_FEATURES
+{
+ int refcount;
+ slapi_apib_callback_on_zero callback_on_zero;
+ Slapi_Mutex *lock;
+} APIB_FEATURES;
+
+static ABAPI *head = NULL;
+
+static ABAPI **ABAPIBroker_FindInterface(char *guid);
+
+int slapi_apib_register(char *guid, void **api )
+{
+ int ret = -1;
+ ABAPI *item;
+
+ if(buffer_lock == 0)
+ {
+ if(0 == (buffer_lock = slapi_new_mutex())) /* we never free this mutex */
+ /* badness */
+ return -1;
+ }
+
+ /* simple - we don't check for duplicates */
+
+ item = (ABAPI*)slapi_ch_malloc(sizeof(ABAPI));
+ if(item)
+ {
+ item->guid = guid;
+ item->api = api;
+
+ slapi_lock_mutex(buffer_lock);
+ if(head == NULL)
+ {
+ head = item;
+ head->next = head;
+ head->prev = head;
+ }
+ else
+ {
+ item->next = head;
+ item->prev = head->prev;
+ head->prev = item;
+ item->prev->next = item;
+ }
+ slapi_unlock_mutex(buffer_lock);
+
+ ret = 0;
+ }
+
+ return ret;
+}
+
+int slapi_apib_unregister(char *guid)
+{
+ int ret = -1;
+ ABAPI **api;
+
+ if(buffer_lock == 0)
+ return ret;
+
+ if(buffer_lock == 0)
+ {
+ if(0 == (buffer_lock = slapi_new_mutex())) /* we never free this mutex */
+ /* badness */
+ return -1;
+ }
+
+ slapi_lock_mutex(buffer_lock);
+
+ if((api = ABAPIBroker_FindInterface(guid)) != NULL)
+ {
+ (*api)->prev->next = (*api)->next;
+ (*api)->next->prev = (*api)->prev;
+
+ if(*api == head)
+ {
+ head = (*api)->next;
+ }
+
+ if(*api == head) /* must be the last item, turn off the lights */
+ head = 0;
+
+ slapi_ch_free((void**)api);
+ *api = 0;
+ ret = 0;
+ }
+
+ slapi_unlock_mutex(buffer_lock);
+
+ return ret;
+}
+
+int slapi_apib_get_interface(char *guid, void ***api)
+{
+ int ret = -1;
+ ABAPI **theapi;
+
+ if(buffer_lock == 0)
+ return ret;
+
+ if(buffer_lock == 0)
+ {
+ if(0 == (buffer_lock = slapi_new_mutex())) /* we never free this mutex */
+ /* badness */
+ return -1;
+ }
+
+ slapi_lock_mutex(buffer_lock);
+
+ if((theapi = ABAPIBroker_FindInterface(guid)) != NULL)
+ {
+ *api = (*theapi)->api;
+ if((*api)[0])
+ {
+ slapi_apib_addref(*api);
+ }
+
+ ret = 0;
+ }
+
+ slapi_unlock_mutex(buffer_lock);
+
+ return ret;
+}
+
+int slapi_apib_make_reference_counted(void **api, slapi_apib_callback_on_zero callback_on_zero)
+{
+ int ret = -1;
+
+ if(api[0] == 0)
+ {
+ api[0] = slapi_ch_malloc(sizeof(APIB_FEATURES));
+ if(api[0])
+ {
+ ((APIB_FEATURES*)(api[0]))->lock = slapi_new_mutex();
+ if(((APIB_FEATURES*)(api[0]))->lock)
+ {
+ ((APIB_FEATURES*)(api[0]))->refcount = 0; /* the ref count */
+ ((APIB_FEATURES*)(api[0]))->callback_on_zero = callback_on_zero;
+ ret = 0;
+ }
+ else
+ slapi_ch_free(&(api[0]));
+ }
+ }
+
+ return ret;
+}
+
+int slapi_apib_addref(void **api)
+{
+ int ret;
+
+ slapi_lock_mutex(((APIB_FEATURES*)(api[0]))->lock);
+
+ ret = ++(((APIB_FEATURES*)(api[0]))->refcount);
+
+ slapi_unlock_mutex(((APIB_FEATURES*)(api[0]))->lock);
+
+ return ret;
+}
+
+int slapi_apib_release(void **api)
+{
+ APIB_FEATURES *features;
+ int ret;
+
+ slapi_lock_mutex(((APIB_FEATURES*)(api[0]))->lock);
+
+ ret = --(((APIB_FEATURES*)(api[0]))->refcount);
+
+ if(((APIB_FEATURES*)(api[0]))->refcount == 0 && ((APIB_FEATURES*)(api[0]))->callback_on_zero)
+ {
+ /* save our stuff for when it gets zapped */
+ features = (APIB_FEATURES*)api[0];
+
+ if(0==((APIB_FEATURES*)(api[0]))->callback_on_zero(api)) /* this should deregister the interface */
+ {
+ slapi_unlock_mutex(features->lock);
+ slapi_destroy_mutex(features->lock);
+ slapi_ch_free((void **)&features);
+ }
+ else
+ slapi_unlock_mutex(features->lock);
+ }
+ else
+ slapi_unlock_mutex(((APIB_FEATURES*)(api[0]))->lock);
+
+ return ret;
+}
+
+
+static ABAPI **ABAPIBroker_FindInterface(char *guid)
+{
+ static ABAPI *api = 0; /* simple gut feeling optimization for constant calls on same api */
+ ABAPI *start_api = api;
+
+ if(!api) {
+ start_api = api = head;
+ }
+
+ if(api)
+ {
+ do
+ {
+ if(0 == strcmp(guid, api->guid))
+ {
+ return &api;
+ }
+
+ api = api->next;
+ }
+ while(api != start_api);
+ }
+
+ return 0;
+}
diff --git a/ldap/servers/slapd/attr.c b/ldap/servers/slapd/attr.c
new file mode 100644
index 00000000..78b1b2a0
--- /dev/null
+++ b/ldap/servers/slapd/attr.c
@@ -0,0 +1,849 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* attr.c - routines for dealing with attributes */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <sys/param.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#undef DEBUG /* disable counters */
+#include <prcountr.h>
+
+
+static int counters_created= 0;
+PR_DEFINE_COUNTER(slapi_attr_counter_created);
+PR_DEFINE_COUNTER(slapi_attr_counter_deleted);
+PR_DEFINE_COUNTER(slapi_attr_counter_exist);
+
+/*
+ * structure used within AVL value trees.
+ */
+typedef struct slapi_attr_value_index {
+ int savi_index; /* index into a_vals[] */
+ struct berval *savi_normval; /* normalized value */
+} SlapiAttrValueIndex;
+
+/*
+ * Utility function used by slapi_attr_type_cmp to
+ * find the next component of an attribute type.
+ */
+static const char *
+next_comp( const char *s )
+{
+ while ( *s && *s != ';' ) {
+ s++;
+ }
+ if ( *s == '\0' ) {
+ return( NULL );
+ } else {
+ return( s + 1 );
+ }
+}
+
+/*
+ * Utility function used by slapi_attr_type_cmp to
+ * compare two components of an attribute type.
+ */
+static int
+comp_cmp( const char *s1, const char *s2 )
+{
+ while ( *s1 && *s1 != ';' && tolower( *s1 ) == tolower( *s2 ) ) {
+ s1++, s2++;
+ }
+ if ( *s1 != *s2 ) {
+ if ( (*s1 == '\0' || *s1 == ';') &&
+ (*s2 == '\0' || *s2 == ';') ) {
+ return( 0 );
+ } else {
+ return( 1 );
+ }
+ } else {
+ return( 0 );
+ }
+}
+
+int
+slapi_attr_type_cmp( const char *a1, const char *a2, int opt )
+{
+ int rc= 0;
+
+ switch ( opt ) {
+ case SLAPI_TYPE_CMP_EXACT: /* compare base name + options as given */
+ rc = strcmp( a1, a2 );
+ break;
+
+ case SLAPI_TYPE_CMP_BASE: /* ignore options on both names - compare base names only */
+ rc = comp_cmp( a1, a2 );
+ break;
+
+ case SLAPI_TYPE_CMP_SUBTYPE: /* ignore options on second name that are not in first name */
+ /*
+ * first, check that the base types match
+ */
+ if ( comp_cmp( a1, a2 ) != 0 ) {
+ rc = 1;
+ break;
+ }
+ /*
+ * next, for each component in a1, make sure there is a
+ * matching component in a2. the order must be the same,
+ * so we can keep looking where we left off each time in a2
+ */
+ rc = 0;
+ for ( a1 = next_comp( a1 ); a1 != NULL; a1 = next_comp( a1 ) ) {
+ for ( a2 = next_comp( a2 ); a2 != NULL;
+ a2 = next_comp( a2 ) ) {
+ if ( comp_cmp( a1, a2 ) == 0 ) {
+ break;
+ }
+ }
+ if ( a2 == NULL ) {
+ rc = 1;
+ break;
+ }
+ }
+ break;
+ }
+
+ return( rc );
+}
+
+
+
+
+/*
+ * Return 1 if the two types are equivalent -- either the same type name,
+ * or aliases for one another, including OIDs.
+ *
+ * Objective: don't allocate any memory!
+ */
+int
+slapi_attr_types_equivalent(const char *t1, const char *t2)
+{
+ int retval = 0;
+ struct asyntaxinfo *asi1, *asi2;
+
+ if (NULL == t1 || NULL == t2) {
+ return 0;
+ }
+
+ asi1 = attr_syntax_get_by_name(t1);
+ asi2 = attr_syntax_get_by_name(t2);
+ if (NULL != asi1) {
+ if (NULL != asi2) {
+ /* Both found - compare normalized names */
+ if (strcasecmp(asi1->asi_name, asi2->asi_name) == 0) {
+ retval = 1;
+ } else {
+ retval = 0;
+ }
+ } else {
+ /* One found, the other wasn't, so not equivalent */
+ retval = 0;
+ }
+ } else if (NULL != asi2) {
+ /* One found, the other wasn't, so not equivalent */
+ retval = 0;
+ } else {
+ /* Neither found - perform case-insensitive compare */
+ if (strcasecmp(t1, t2) == 0) {
+ retval = 1;
+ } else {
+ retval = 0;
+ }
+ }
+
+ attr_syntax_return( asi1 );
+ attr_syntax_return( asi2 );
+
+ return retval;
+}
+
+Slapi_Attr *
+slapi_attr_new()
+{
+ Slapi_Attr *a= (Slapi_Attr *)slapi_ch_calloc( 1, sizeof(Slapi_Attr));
+ if(!counters_created)
+ {
+ PR_CREATE_COUNTER(slapi_attr_counter_created,"Slapi_Attr","created","");
+ PR_CREATE_COUNTER(slapi_attr_counter_deleted,"Slapi_Attr","deleted","");
+ PR_CREATE_COUNTER(slapi_attr_counter_exist,"Slapi_Attr","exist","");
+ counters_created= 1;
+ }
+ PR_INCREMENT_COUNTER(slapi_attr_counter_created);
+ PR_INCREMENT_COUNTER(slapi_attr_counter_exist);
+ return a;
+}
+
+Slapi_Attr *
+slapi_attr_init(Slapi_Attr *a, const char *type)
+{
+ return slapi_attr_init_locking_optional(a, type, PR_TRUE, PR_TRUE);
+}
+
+Slapi_Attr *
+slapi_attr_init_locking_optional(Slapi_Attr *a, const char *type, PRBool use_lock, PRBool ref_count)
+{
+ PR_ASSERT(a!=NULL);
+
+ if(NULL != a)
+ {
+ struct asyntaxinfo *asi= NULL;
+ const char *basetype= NULL;
+ char *tmp= NULL;
+
+ if(type!=NULL)
+ {
+ char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
+ basetype = buf;
+ tmp = slapi_attr_basetype(type, buf, sizeof(buf));
+ if(tmp != NULL)
+ {
+ basetype = tmp; /* basetype was malloc'd */
+ }
+ asi = attr_syntax_get_by_name_locking_optional(basetype, use_lock, ref_count);
+ }
+ if(NULL == asi)
+ {
+ a->a_type = attr_syntax_normalize_no_lookup( type );
+ /*
+ * no syntax for this type... return DirectoryString
+ * syntax. we accomplish this by looking up a well known
+ * attribute type that has that syntax.
+ */
+ asi = attr_syntax_get_by_name_locking_optional(
+ ATTR_WITH_DIRSTRING_SYNTAX, use_lock, ref_count);
+ }
+ else
+ {
+ char *attroptions = NULL;
+
+ if ( NULL != type ) {
+ attroptions = strchr( type, ';' );
+ }
+
+ if ( NULL == attroptions ) {
+ a->a_type = slapi_ch_strdup(asi->asi_name);
+ } else {
+ /*
+ * If the original type includes any attribute options,
+ * the a_type field is set to the type contained in the
+ * attribute syntax followed by a normalized copy of the
+ * options.
+ */
+ char *normalized_options;
+
+ normalized_options = attr_syntax_normalize_no_lookup( attroptions );
+ a->a_type = slapi_ch_malloc( strlen(asi->asi_name)
+ + strlen(normalized_options) +1 );
+ sprintf( a->a_type, "%s%s", asi->asi_name, normalized_options );
+ slapi_ch_free_string( &normalized_options );
+ }
+ }
+ if ( asi != NULL )
+ {
+ a->a_plugin = asi->asi_plugin;
+ a->a_flags = asi->asi_flags;
+ }
+ else
+ {
+ a->a_plugin = NULL; /* XXX - should be rare */
+ a->a_flags = 0; /* XXX - should be rare */
+ }
+
+ attr_syntax_return_locking_optional( asi, use_lock );
+
+ if (NULL != tmp)
+ {
+ slapi_ch_free_string(&tmp);
+ }
+ slapi_valueset_init(&a->a_present_values);
+ slapi_valueset_init(&a->a_deleted_values);
+ a->a_listtofree= NULL;
+ a->a_deletioncsn= NULL;
+ a->a_next= NULL;
+ }
+
+ return a;
+}
+
+Slapi_Attr *
+slapi_attr_dup(const Slapi_Attr *attr)
+{
+ Slapi_Attr *newattr= slapi_attr_new();
+ Slapi_Value **present_va= valueset_get_valuearray(&attr->a_present_values); /* JCM Mucking about inside the value set */
+ Slapi_Value **deleted_va= valueset_get_valuearray(&attr->a_deleted_values); /* JCM Mucking about inside the value set */
+ slapi_attr_init(newattr, attr->a_type);
+ valueset_add_valuearray( &newattr->a_present_values, present_va );
+ valueset_add_valuearray( &newattr->a_deleted_values, deleted_va );
+ newattr->a_deletioncsn= csn_dup(attr->a_deletioncsn);
+ return newattr;
+}
+
+void
+slapi_attr_free( Slapi_Attr **ppa )
+{
+ if(ppa!=NULL && *ppa!=NULL)
+ {
+ Slapi_Attr *a= *ppa;
+ attr_done(a);
+ slapi_ch_free( (void**)&a );
+ PR_INCREMENT_COUNTER(slapi_attr_counter_deleted);
+ PR_DECREMENT_COUNTER(slapi_attr_counter_exist);
+ }
+}
+
+void
+attr_done(Slapi_Attr *a)
+{
+ if(a!=NULL)
+ {
+ slapi_ch_free((void**)&a->a_type);
+ csn_free(&a->a_deletioncsn);
+ slapi_valueset_done(&a->a_present_values);
+ slapi_valueset_done(&a->a_deleted_values);
+ {
+ struct bervals2free *freelist;
+ struct bervals2free *tmp;
+ freelist = a->a_listtofree;
+ while(freelist) {
+ ber_bvecfree(freelist->bvals);
+ tmp=freelist;
+ freelist = freelist->next;
+ slapi_ch_free((void **)&tmp);
+ }
+ }
+ }
+}
+
+/*
+ * slapi_attr_basetype - extracts the attribute base type (without
+ * any attribute description options) from type. puts the result
+ * in buf if it can, otherwise, it malloc's and returns the base
+ * which should be free()'ed later.
+ */
+char *
+slapi_attr_basetype( const char *type, char *buf, size_t bufsize )
+{
+ unsigned int i;
+
+ i = 0;
+ while ( *type && *type != ';' && i < bufsize ) {
+ buf[i++] = *type++;
+ }
+ if ( i < bufsize ) {
+ buf[i] = '\0';
+ return( NULL );
+ } else {
+ int len;
+ char *tmp;
+
+ len = strlen( type );
+ tmp = slapi_ch_malloc( len + 1 );
+ slapi_attr_basetype( type, tmp, len + 1 );
+ return( tmp );
+ }
+}
+
+/*
+ * returns 0 if "v" is already a value within "a" and non-zero if not.
+ */
+int
+slapi_attr_value_find( const Slapi_Attr *a, const struct berval *v )
+{
+ struct ava ava;
+
+ if ( NULL == a ) {
+ return( -1 );
+ }
+
+ ava.ava_type = a->a_type;
+ ava.ava_value = *v;
+ return(plugin_call_syntax_filter_ava( a, LDAP_FILTER_EQUALITY, &ava ));
+}
+
+int
+slapi_attr_get_type( Slapi_Attr *a, char **type )
+{
+ *type = a->a_type;
+ return( 0 );
+}
+
+
+/*
+ * Fetch a copy of the values as an array of struct berval *'s.
+ * Returns 0 upon success and non-zero on failure.
+ * Free the array of values by calling ber_bvecfree().
+ */
+int
+slapi_attr_get_bervals_copy( Slapi_Attr *a, struct berval ***vals )
+{
+ int retVal= 0;
+
+ if ( NULL == vals )
+ {
+ return -1;
+ }
+
+ if(NULL==a || valueset_isempty(&a->a_present_values))
+ {
+ *vals = NULL;
+ }
+ else
+ {
+ Slapi_Value **va= valueset_get_valuearray(&a->a_present_values);
+ valuearray_get_bervalarray(va,vals);
+ }
+ return retVal;
+}
+
+
+/*
+ * JCM: BEWARE.. HIGHLY EVIL.. DO NOT USE THIS FUNCTION.
+ * XXXmcs: Why not? Because it is only provided as a not-quite-backwards
+ * compatible interface for older (pre-iDS 5.0) plugins. It works by
+ * making a copy of the attribute values (the pre-iDS 5.0 function with
+ * the same name returned a pointer into the Slapi_Attr structure -- no
+ * copying). Since older users of this interface did not have to free
+ * the values, this function arranges to free them WHEN THE Slapi_Attr
+ * IS DESTROYED. This is accomplished by adding a pointer to the newly
+ * allocated copy to a "to be freed" linked list inside the Slapi_Attr.
+ * But if the Slapi_Attr is not destroyed very often, and this function
+ * is called repeatedly, memory usage will grow without bound. Not good.
+ * The value copies are freed inside attr_done() which is called from
+ * slapi_attr_free() and a few other places.
+ *
+ * If you really want a copy of the values as a struct berval ** array,
+ * call slapi_attr_get_bervals_copy() and free it yourself by calling
+ * ber_bvecfree().
+ */
+int
+slapi_attr_get_values( Slapi_Attr *a, struct berval ***vals )
+{
+ int retVal = slapi_attr_get_bervals_copy( a, vals );
+
+ if ( 0 == retVal )
+ {
+ struct bervals2free *newfree;
+ newfree = (struct bervals2free *)slapi_ch_malloc(sizeof(struct bervals2free));
+ newfree->next = a->a_listtofree;
+ newfree->bvals = *vals;
+ a->a_listtofree = newfree;
+ }
+
+ return retVal;
+}
+
+
+/*
+ * Fetch a copy of the present valueset.
+ * Caller must free the valueset.
+ */
+int
+slapi_attr_get_valueset(const Slapi_Attr *a, Slapi_ValueSet **vs)
+{
+ int retVal= 0;
+ if(vs!=NULL)
+ {
+ *vs= valueset_dup(&a->a_present_values);
+ }
+ return retVal;
+}
+
+/*
+ * Careful... this returns a pointer to the contents!
+ */
+Slapi_Value **
+attr_get_present_values(const Slapi_Attr *a)
+{
+ return valueset_get_valuearray(&a->a_present_values);
+}
+
+int
+slapi_attr_get_flags( const Slapi_Attr *a, unsigned long *flags )
+{
+ *flags = a->a_flags;
+ return( 0 );
+}
+
+int
+slapi_attr_flag_is_set( const Slapi_Attr *a, unsigned long flag )
+{
+ return( a->a_flags & flag );
+}
+
+int
+slapi_attr_value_cmp( const Slapi_Attr *a, const struct berval *v1, const struct berval *v2 )
+{
+ int retVal;
+
+ if ( a->a_flags & SLAPI_ATTR_FLAG_CMP_BITBYBIT )
+ {
+ int cmplen = ( v1->bv_len <= v2->bv_len ? v1->bv_len : v2->bv_len );
+ retVal = memcmp(v1->bv_val, v2->bv_val, cmplen);
+ if ( retVal == 0 && v1->bv_len < v2->bv_len )
+ {
+ retVal = -1;
+ }
+ else if ( retVal == 0 && v1->bv_len > v2->bv_len )
+ {
+ retVal = 1;
+ }
+ }
+ else
+ {
+ Slapi_Attr a2;
+ struct ava ava;
+ Slapi_Value *cvals[2];
+ Slapi_Value tmpcval;
+
+ a2 = *a;
+ cvals[0] = &tmpcval;
+ cvals[0]->v_csnset = NULL;
+ cvals[0]->bv = *v1;
+ cvals[1] = NULL;
+ a2.a_present_values.va = cvals; /* JCM - PUKE */
+ ava.ava_type = a->a_type;
+ ava.ava_value = *v2;
+ retVal = plugin_call_syntax_filter_ava(&a2, LDAP_FILTER_EQUALITY, &ava);
+ }
+ return retVal;
+}
+
+/*
+ * Set the CSN of all the present values.
+ */
+int
+attr_set_csn( Slapi_Attr *a, const CSN *csn)
+{
+ PR_ASSERT(a!=NULL);
+ valueset_update_csn(&a->a_present_values, CSN_TYPE_VALUE_UPDATED, csn);
+ return 0;
+}
+
+int
+attr_set_deletion_csn( Slapi_Attr *a, const CSN *csn)
+{
+ PR_ASSERT(a!=NULL);
+ if(csn_compare(csn,a->a_deletioncsn)>0)
+ {
+ csn_free(&a->a_deletioncsn);
+ a->a_deletioncsn= csn_dup(csn);
+ }
+ return 0;
+}
+
+const CSN *
+attr_get_deletion_csn(const Slapi_Attr *a)
+{
+ PR_ASSERT(a!=NULL);
+ return a->a_deletioncsn;
+}
+
+int
+slapi_attr_first_value( Slapi_Attr *a, Slapi_Value **v )
+{
+ int rc;
+
+ if(NULL == a) {
+ rc = -1;
+ } else {
+ rc=slapi_valueset_first_value( &a->a_present_values, v );
+ }
+ return rc;
+}
+
+int
+slapi_attr_next_value( Slapi_Attr *a, int hint, Slapi_Value **v)
+{
+ int rc;
+
+ if(NULL == a) {
+ rc = -1;
+ } else {
+ rc=slapi_valueset_next_value( &a->a_present_values, hint, v );
+ }
+ return rc;
+}
+
+int
+slapi_attr_get_numvalues( const Slapi_Attr *a, int *numValues )
+{
+ if(NULL == a) {
+ *numValues = 0;
+ } else {
+ *numValues = slapi_valueset_count(&a->a_present_values);
+ }
+ return 0;
+}
+
+
+int
+attr_first_deleted_value( Slapi_Attr *a, Slapi_Value **v )
+{
+ return slapi_valueset_first_value( &a->a_deleted_values, v );
+}
+
+int
+attr_next_deleted_value( Slapi_Attr *a, int hint, Slapi_Value **v)
+{
+ return slapi_valueset_next_value( &a->a_deleted_values, hint, v );
+}
+
+/*
+ * Note: We are passing in the entry so that we may be able to "optimize"
+ * the csn related information and roll it up higher to the level of entry.
+ */
+void
+attr_purge_state_information(Slapi_Entry *entry, Slapi_Attr *attr, const CSN *csnUpTo)
+{
+ if(!valueset_isempty(&attr->a_deleted_values))
+ {
+ valueset_purge(&attr->a_deleted_values, csnUpTo);
+ }
+}
+
+/*
+ * Search an attribute for a value, it could be present, deleted, or not present.
+ */
+int
+attr_value_find_wsi(Slapi_Attr *a, const struct berval *bval, Slapi_Value **value)
+{
+ int retVal=0;
+ struct ava ava;
+
+ PR_ASSERT(a!=NULL);
+ PR_ASSERT(value!=NULL);
+
+ /*
+ * we will first search the present values, and then, if
+ * necessary, the deleted values.
+ */
+ ava.ava_type = a->a_type;
+ ava.ava_value = *bval;
+ retVal = plugin_call_syntax_filter_ava_sv(a, LDAP_FILTER_EQUALITY, &ava, value, 0 /* Present */);
+
+ if(retVal==0)
+ {
+ /* we found the value, so we don't search the deleted list */
+ retVal= VALUE_PRESENT;
+ }
+ else
+ {
+ retVal = plugin_call_syntax_filter_ava_sv(a, LDAP_FILTER_EQUALITY, &ava, value, 1 /* Deleted */);
+ if(retVal==0)
+ {
+ /* It was on the deleted value list */
+ retVal= VALUE_DELETED;
+ }
+ else
+ {
+ /* Couldn't find it */
+ retVal= VALUE_NOTFOUND;
+ }
+ }
+
+ return retVal;
+}
+
+int
+slapi_attr_add_value(Slapi_Attr *a, const Slapi_Value *v)
+{
+ slapi_valueset_add_value( &a->a_present_values, v);
+ return 0;
+}
+
+/* Make the valuset in SLapi_Attr be *vs--not a copy */
+int
+slapi_attr_set_valueset(Slapi_Attr *a, const Slapi_ValueSet *vs)
+{
+ slapi_valueset_set_valueset( &a->a_present_values, vs);
+ return 0;
+}
+
+int
+attr_add_deleted_value(Slapi_Attr *a, const Slapi_Value *v)
+{
+ slapi_valueset_add_value( &a->a_deleted_values, v);
+ return 0;
+}
+
+/*
+ * If we are adding or deleting SLAPD_MODUTIL_TREE_THRESHHOLD or more
+ * entries, we use an AVL tree to speed up searching for duplicates or
+ * values we are trying to delete. This threshhold is somewhat arbitrary;
+ * we should really take some measurements to determine an optimal number.
+ */
+#define SLAPD_MODUTIL_TREE_THRESHHOLD 5
+
+/*
+ * Add a value array to an attribute. If SLAPD_MODUTIL_TREE_THRESHHOLD or
+ * more values are being added, we build an AVL tree of any existing
+ * values and then update that in parallel with the existing values. This
+ * is done so that we do not waste a lot of CPU time searching for duplicate
+ * values. The AVL tree is created and destroyed all within this function.
+ *
+ * Returns
+ * LDAP_SUCCESS - OK
+ * LDAP_OPERATIONS_ERROR - Existing duplicates in attribute.
+ * LDAP_TYPE_OR_VALUE_EXISTS - Duplicate values.
+ */
+int
+attr_add_valuearray(Slapi_Attr *a, Slapi_Value **vals, const char *dn)
+{
+ int i = 0;
+ int duplicate_index = -1;
+ int was_present_null = 0;
+ int rc = LDAP_SUCCESS;
+
+ if (valuearray_isempty(vals)) {
+ /*
+ * No values to add (unexpected but acceptable).
+ */
+ return rc;
+ }
+
+ /*
+ * determine whether we should use an AVL tree of values or not
+ */
+ while ( i < SLAPD_MODUTIL_TREE_THRESHHOLD - 1 && vals[i] != NULL ) {
+ i++;
+ }
+
+ /*
+ * detect duplicate values
+ */
+ if ( i >= SLAPD_MODUTIL_TREE_THRESHHOLD - 1 ) {
+ /*
+ * Several values to add: use an AVL tree to detect duplicates.
+ */
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "slapi_entry_add_values: using an AVL tree to "
+ "detect duplicate values\n", 0, 0, 0 );
+
+ if (valueset_isempty(&a->a_present_values)) {
+ /* if the attribute contains no values yet, just check the
+ * input vals array for duplicates
+ */
+ Avlnode *vtree = NULL;
+ rc= valuetree_add_valuearray(a->a_type, a->a_plugin, vals, &vtree, &duplicate_index);
+ valuetree_free(&vtree);
+ was_present_null = 1;
+ } else {
+ /* the attr and vals both contain values, check intersection */
+ rc= valueset_intersectswith_valuearray(&a->a_present_values, a, vals, &duplicate_index);
+ }
+
+ } else if ( !valueset_isempty(&a->a_present_values) ) {
+ /*
+ * Small number of values to add: don't bother constructing
+ * an AVL tree, etc. since it probably isn't worth the time.
+ */
+ for ( i = 0; vals[i] != NULL; ++i ) {
+ if ( slapi_attr_value_find( a, slapi_value_get_berval(vals[i]) ) == 0 ) {
+ duplicate_index = i;
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ break;
+ }
+ }
+ }
+
+ /*
+ * add values if no duplicates detected
+ */
+ if(rc==LDAP_SUCCESS) {
+ valueset_add_valuearray( &a->a_present_values, vals );
+ }
+
+ /* In the case of duplicate value, rc == LDAP_TYPE_OR_VALUE_EXISTS or
+ * LDAP_OPERATIONS_ERROR
+ */
+ else if ( duplicate_index >= 0 ) {
+ char avdbuf[BUFSIZ];
+ char bvvalcopy[BUFSIZ];
+ char *duplicate_string = "null or non-ASCII";
+
+ i = 0;
+ while ( (unsigned int)i < vals[duplicate_index]->bv.bv_len &&
+ i < BUFSIZ - 1 &&
+ vals[duplicate_index]->bv.bv_val[i] &&
+ isascii ( vals[duplicate_index]->bv.bv_val[i] )) {
+ i++;
+ }
+
+ if ( i ) {
+ if ( vals[duplicate_index]->bv.bv_val[i] == 0 ) {
+ duplicate_string = vals[duplicate_index]->bv.bv_val;
+ }
+ else {
+ strncpy ( &bvvalcopy[0], vals[duplicate_index]->bv.bv_val, i );
+ bvvalcopy[i] = '\0';
+ duplicate_string = bvvalcopy;
+ }
+ }
+
+ slapi_log_error( SLAPI_LOG_FATAL, NULL, "add value \"%s\" to "
+ "attribute type \"%s\" in entry \"%s\" failed: %s\n",
+ duplicate_string,
+ a->a_type,
+ dn ? escape_string(dn,avdbuf) : "<null>",
+ (was_present_null ? "duplicate new value" : "value exists"));
+ }
+ return( rc );
+}
+
+/* quickly toss an attribute's values and replace them with new ones
+ * (used by attrlist_replace_fast)
+ */
+void attr_replace(Slapi_Attr *a, Slapi_Value **vals)
+{
+ valueset_replace(&a->a_present_values, vals);
+}
+
+int
+attr_check_onoff ( const char *attr_name, char *value, long minval, long maxval, char *errorbuf )
+{
+ int retVal = LDAP_SUCCESS;
+
+ if ( strcasecmp ( value, "on" ) != 0 &&
+ strcasecmp ( value, "off") != 0 &&
+ strcasecmp ( value, "1" ) != 0 &&
+ strcasecmp ( value, "0" ) != 0 &&
+ strcasecmp ( value, "true" ) != 0 &&
+ strcasecmp ( value, "false" ) != 0 ) {
+ PR_snprintf ( errorbuf, BUFSIZ,
+ "%s: invalid value \"%s\".", attr_name, value );
+ retVal = LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ return retVal;
+}
+
+int
+attr_check_minmax ( const char *attr_name, char *value, long minval, long maxval, char *errorbuf )
+{
+ int retVal = LDAP_SUCCESS;
+ long val;
+
+ val = strtol(value, NULL, 0);
+ if ( (minval != -1 ? (val < minval ? 1 : 0) : 0) ||
+ (maxval != -1 ? (val > maxval ? 1 : 0) : 0) ) {
+ PR_snprintf ( errorbuf, BUFSIZ,
+ "%s: invalid value \"%s\".",
+ attr_name, value );
+ retVal = LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ return retVal;
+}
diff --git a/ldap/servers/slapd/attrlist.c b/ldap/servers/slapd/attrlist.c
new file mode 100644
index 00000000..e57e473c
--- /dev/null
+++ b/ldap/servers/slapd/attrlist.c
@@ -0,0 +1,253 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slap.h"
+
+void
+attrlist_free(Slapi_Attr *alist)
+{
+ Slapi_Attr *a, *next;
+ for ( a = alist; a != NULL; a = next )
+ {
+ next = a->a_next;
+ slapi_attr_free( &a );
+ }
+}
+
+/*
+ * Search for the attribute.
+ * If not found then create it,
+ * and add it to the end of the list.
+ * Return 0 for found, 1 for created.
+ */
+int
+attrlist_find_or_create(Slapi_Attr **alist, const char *type, Slapi_Attr ***a)
+{
+ return attrlist_find_or_create_locking_optional(alist, type, a, PR_TRUE, PR_TRUE);
+}
+
+int
+attrlist_find_or_create_locking_optional(Slapi_Attr **alist, const char *type, Slapi_Attr ***a, PRBool use_lock, PRBool ref_count)
+{
+ int rc= 0; /* found */
+ if ( *a==NULL )
+ {
+ for ( *a = alist; **a != NULL; *a = &(**a)->a_next ) {
+ if ( strcasecmp( (**a)->a_type, type ) == 0 ) {
+ break;
+ }
+ }
+ }
+
+ if( **a==NULL )
+ {
+ **a = slapi_attr_new();
+ slapi_attr_init_locking_optional(**a, type, use_lock, ref_count);
+ rc= 1; /* created */
+ }
+ return rc;
+}
+
+/*
+ * attrlist_merge - merge the given type and value with the list of
+ * attributes in attrs.
+ */
+void
+attrlist_merge(Slapi_Attr **alist, const char *type, struct berval **vals)
+{
+ Slapi_Value **values= NULL;
+ valuearray_init_bervalarray(vals,&values); /* JCM SLOW FUNCTION */
+ attrlist_merge_valuearray(alist,type,values);
+ valuearray_free(&values);
+}
+
+
+/*
+ * attrlist_merge_valuearray - merge the given type and value with the list of
+ * attributes in attrs.
+ */
+void
+attrlist_merge_valuearray(Slapi_Attr **alist, const char *type, Slapi_Value **vals)
+{
+ Slapi_Attr **a= NULL;
+ attrlist_find_or_create(alist, type, &a);
+ valueset_add_valuearray( &(*a)->a_present_values, vals );
+}
+
+
+/*
+ * attrlist_find - find and return attribute type in list a
+ */
+
+Slapi_Attr *
+attrlist_find(Slapi_Attr *a, const char *type)
+{
+ for ( ; a != NULL; a = a->a_next ) {
+ if ( strcasecmp( a->a_type, type ) == 0 ) {
+ return( a );
+ }
+ }
+
+ return( NULL );
+}
+
+
+/*
+ * attrlist_count_subtypes
+ *
+ * Returns a count attributes which conform to type
+ * in the attr list a. This count includes all subtypes of
+ * type
+ */
+int
+attrlist_count_subtypes(Slapi_Attr *a, const char *type)
+{
+ int counter = 0;
+
+ for ( ; a != NULL; a = a->a_next ) {
+ if ( slapi_attr_type_cmp( type , a->a_type, SLAPI_TYPE_CMP_SUBTYPE) == 0 ) {
+ counter++;
+ }
+ }
+
+ return( counter );
+}
+
+/*
+ * attrlist_find_ex
+ *
+ * Finds the first subtype in the list which matches "type"
+ * starting at the beginning or hint depending on whether
+ * hint has a value
+ *
+ * It is intended that hint be zero when first called and then
+ * passed back in on subsequent calls until 0 is returned to mark
+ * the end of the filtered list
+ */
+Slapi_Attr *
+attrlist_find_ex(
+ Slapi_Attr *a,
+ const char *type,
+ int *type_name_disposition, /* pass null if you're not interested */
+ char** actual_type_name, /* pass null if you're not interested */
+ void **hint
+)
+{
+ Slapi_Attr **attr_cursor = (Slapi_Attr **)hint;
+
+ if (type_name_disposition) *type_name_disposition = 0;
+ if (actual_type_name) *actual_type_name = NULL;
+
+ if(*attr_cursor == NULL)
+ *attr_cursor = a; /* start at the beginning of the list */
+ else
+ *attr_cursor = (*attr_cursor)->a_next;
+
+ while(*attr_cursor != NULL) {
+
+ /* Determine whether the two types are related:*/
+ if ( slapi_attr_type_cmp( type , (*attr_cursor)->a_type, SLAPI_TYPE_CMP_SUBTYPE) == 0 ) {
+ /* We got a match. Now figure out if we matched because it was a subtype */
+ if (type_name_disposition) {
+ if ( 0 == slapi_attr_type_cmp( type , (*attr_cursor)->a_type, SLAPI_TYPE_CMP_EXACT) ) {
+ *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ } else {
+ *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE;
+ }
+ }
+
+ if (actual_type_name) {
+ *actual_type_name = (*attr_cursor)->a_type;
+ }
+
+ a = *attr_cursor; /* the attribute to return */
+ return( a );
+
+ }
+
+ *attr_cursor = (*attr_cursor)->a_next; /* no match, move cursor */
+ }
+
+ return( NULL );
+}
+
+/*
+ * attr_remove - remove the attribute from the list of attributes
+ */
+Slapi_Attr *
+attrlist_remove(Slapi_Attr **attrs, const char *type)
+{
+ Slapi_Attr **a;
+ Slapi_Attr *save= NULL;
+ for ( a = attrs; *a != NULL; a = &(*a)->a_next )
+ {
+ if ( strcasecmp( (*a)->a_type, type ) == 0 )
+ {
+ break;
+ }
+ }
+ if (*a != NULL)
+ {
+ save = *a;
+ *a = (*a)->a_next;
+ }
+ return save;
+}
+
+void
+attrlist_add(Slapi_Attr **attrs, Slapi_Attr *a)
+{
+ a->a_next= *attrs;
+ *attrs= a;
+}
+
+/*
+ * attrlist_delete - delete the attribute type in list pointed to by attrs
+ * return 0 deleted ok
+ * 1 not found in list a
+ * -1 something bad happened
+ */
+
+int
+attrlist_delete(Slapi_Attr **attrs, const char *type)
+{
+ Slapi_Attr **a;
+ Slapi_Attr *save;
+
+ for ( a = attrs; *a != NULL; a = &(*a)->a_next ) {
+ if ( strcasecmp( (*a)->a_type, type ) == 0 ) {
+ break;
+ }
+ }
+
+ if ( *a == NULL ) {
+ return( 1 );
+ }
+
+ save = *a;
+ *a = (*a)->a_next;
+ slapi_attr_free( &save );
+
+ return( 0 );
+}
+
+/*
+ * attrlist_replace - replace the attribute value(s) with this value(s)
+ */
+void attrlist_replace(Slapi_Attr **alist, const char *type, struct berval **vals)
+{
+ Slapi_Attr **a = NULL;
+ Slapi_Value **values = NULL;
+
+ if (vals == NULL || vals[0] == NULL) {
+ (void)attrlist_delete(alist, type);
+ } else {
+ attrlist_find_or_create(alist, type, &a);
+ valuearray_init_bervalarray(vals, &values);
+ attr_replace(*a, values);
+ }
+}
+
diff --git a/ldap/servers/slapd/attrsyntax.c b/ldap/servers/slapd/attrsyntax.c
new file mode 100644
index 00000000..845e9666
--- /dev/null
+++ b/ldap/servers/slapd/attrsyntax.c
@@ -0,0 +1,906 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* attrsyntax.c */
+
+#include "slap.h"
+#include <plhash.h>
+
+/*
+ * Note: if both the oid2asi and name2asi locks are acquired at the
+ * same time, the old2asi one should be acquired first,
+ */
+
+/*
+ * This hashtable maps the oid to the struct asyntaxinfo for that oid.
+ */
+static PLHashTable *oid2asi = NULL;
+/* read/write lock to protect table */
+static PRRWLock *oid2asi_lock = NULL;
+
+/*
+ * This hashtable maps the name or alias of the attribute to the
+ * syntax info structure for that attribute. An attribute type has as
+ * many entries in the name2asi table as it has names and aliases, but
+ * all entries point to the same struct asyntaxinfo.
+ */
+static PLHashTable *name2asi = NULL;
+/* read/write lock to protect table */
+static PRRWLock *name2asi_lock = NULL;
+
+#define AS_LOCK_READ(l) PR_RWLock_Rlock(l)
+#define AS_LOCK_WRITE(l) PR_RWLock_Wlock(l)
+#define AS_UNLOCK_READ(l) PR_RWLock_Unlock(l)
+#define AS_UNLOCK_WRITE(l) PR_RWLock_Unlock(l)
+
+
+
+static void *attr_syntax_get_plugin_by_name_with_default( const char *type );
+static void attr_syntax_delete_no_lock( struct asyntaxinfo *asip,
+ PRBool remove_from_oid_table );
+static struct asyntaxinfo *attr_syntax_get_by_oid_locking_optional( const
+ char *oid, PRBool use_lock, PRBool ref_count);
+
+#ifdef ATTR_LDAP_DEBUG
+static void attr_syntax_print();
+#endif
+static int attr_syntax_init(void);
+
+void
+attr_syntax_read_lock(void)
+{
+ if (0 != attr_syntax_init()) return;
+
+ AS_LOCK_READ(oid2asi_lock);
+ AS_LOCK_READ(name2asi_lock);
+}
+
+void
+attr_syntax_unlock_read(void)
+{
+ if(name2asi_lock) AS_UNLOCK_READ(name2asi_lock);
+ if(oid2asi_lock) AS_UNLOCK_READ(oid2asi_lock);
+}
+
+
+
+#if 0
+static int
+check_oid( const char *oid ) {
+
+ int i = 0, length_oid = 0, rc = 0;
+
+ if ( oid == NULL) {
+ /* this is bad */
+ LDAPDebug (LDAP_DEBUG_ANY, "NULL passed to check_oid\n",0,0,0);
+ return 0;
+ }
+
+ length_oid = strlen(oid);
+ if (length_oid < 4) {
+ /* this is probably bad */
+ LDAPDebug (LDAP_DEBUG_ANY, "Bad oid %s passed to check_oid\n",oid,0,0);
+ return 0;
+ }
+
+ rc = strcasecmp(oid+(length_oid-4), "-oid");
+
+ if ( 0 == rc ) {
+ return 1;
+ }
+
+ /* If not, the OID must begin and end with a digit, and contain only
+ digits and dots */
+
+ if ( !isdigit(oid[0]) ||
+ !isdigit(oid[length_oid-1]) ) {
+ LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0);
+ return 0;
+ }
+
+ /* check to see that it contains only digits and dots */
+ for ( i = 0; i < length_oid; i++ ) {
+ if ( !isdigit(oid[i]) && oid[i] != '.' ){
+ LDAPDebug (LDAP_DEBUG_ANY, "Non numeric oid %s passed to check_oid\n",oid,0,0);
+ return 0;
+ }
+ }
+
+ /* The oid is OK if we're here */
+ return 1;
+
+
+}
+#endif
+
+#define NBUCKETS(ht) (1 << (PL_HASH_BITS - (ht)->shift))
+
+#if 0
+static int
+attr_syntax_check_oids()
+{
+ int ii = 0;
+ int nbad = 0;
+ AS_LOCK_READ(oid2asi_lock);
+ ii = NBUCKETS(oid2asi);
+ for (;ii;--ii) {
+ PLHashEntry *he = oid2asi->buckets[ii-1];
+ for (; he; he = he->next) {
+ if (!check_oid(he->key)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: bad oid %s in bucket %d\n",
+ he->key, ii-1, 0);
+ nbad++;
+ }
+ }
+ }
+
+ AS_UNLOCK_READ(oid2asi_lock);
+ return nbad;
+}
+#endif
+
+void
+attr_syntax_free( struct asyntaxinfo *a )
+{
+ PR_ASSERT( a->asi_refcnt == 0 );
+
+ cool_charray_free( a->asi_aliases );
+ slapi_ch_free( (void**)&a->asi_name );
+ slapi_ch_free( (void **)&a->asi_desc );
+ slapi_ch_free( (void **)&a->asi_oid );
+ slapi_ch_free( (void **)&a->asi_superior );
+ slapi_ch_free( (void **)&a->asi_mr_equality );
+ slapi_ch_free( (void **)&a->asi_mr_ordering );
+ slapi_ch_free( (void **)&a->asi_mr_substring );
+ cool_charray_free( a->asi_origin );
+ slapi_ch_free( (void **) &a );
+}
+
+static struct asyntaxinfo *
+attr_syntax_new()
+{
+ return (struct asyntaxinfo *)slapi_ch_calloc(1, sizeof(struct asyntaxinfo));
+}
+
+/*
+ * hashNocaseString - used for case insensitive hash lookups
+ */
+static PLHashNumber
+hashNocaseString(const void *key)
+{
+ PLHashNumber h = 0;
+ const unsigned char *s;
+
+ for (s = key; *s; s++)
+ h = (h >> 28) ^ (h << 4) ^ (tolower(*s));
+ return h;
+}
+
+/*
+ * hashNocaseCompare - used for case insensitive hash key comparisons
+ */
+static PRIntn
+hashNocaseCompare(const void *v1, const void *v2)
+{
+ return (strcasecmp((char *)v1, (char *)v2) == 0);
+}
+
+/*
+ * Given an OID, return the syntax info. If there is more than one
+ * attribute syntax with the same OID (i.e. aliases), the first one
+ * will be returned. This is usually the "canonical" one, but it may
+ * not be.
+ *
+ * Note: once the caller is finished using it, the structure returned must
+ * be returned by calling to attr_syntax_return().
+ */
+struct asyntaxinfo *
+attr_syntax_get_by_oid(const char *oid)
+{
+ return attr_syntax_get_by_oid_locking_optional( oid, PR_TRUE, PR_TRUE);
+}
+
+
+static struct asyntaxinfo *
+attr_syntax_get_by_oid_locking_optional( const char *oid, PRBool use_lock, PRBool ref_count )
+{
+ struct asyntaxinfo *asi = 0;
+ if (oid2asi)
+ {
+ if ( use_lock ) AS_LOCK_READ(oid2asi_lock);
+ asi = (struct asyntaxinfo *)PL_HashTableLookup_const(oid2asi, oid);
+ if (asi)
+ {
+ if(ref_count) PR_AtomicIncrement( &asi->asi_refcnt );
+ }
+ if ( use_lock ) AS_UNLOCK_READ(oid2asi_lock);
+ }
+
+ return asi;
+}
+
+/*
+ * Add the syntax info pointer to the look-up-by-oid table.
+ * The lock parameter is used by the initialization code. Normally, we want
+ * to acquire a write lock before we modify the table, but during
+ * initialization, we are running in single threaded mode, so we don't have
+ * to worry about resource contention.
+ */
+static void
+attr_syntax_add_by_oid(const char *oid, struct asyntaxinfo *a, int lock)
+{
+ if (0 != attr_syntax_init()) return;
+
+ if (lock)
+ AS_LOCK_WRITE(oid2asi_lock);
+
+ PL_HashTableAdd(oid2asi, oid, a);
+
+ if (lock)
+ AS_UNLOCK_WRITE(oid2asi_lock);
+}
+
+/*
+ * Return the syntax info given an attribute name. The name may be the
+ * "canonical" name, an alias, or an OID. The given name need not be
+ * normalized since the look up is done case insensitively.
+ *
+ * Note: once the caller is finished using it, the structure returned must
+ * be returned by calling to attr_syntax_return().
+ */
+struct asyntaxinfo *
+attr_syntax_get_by_name(const char *name)
+{
+ return attr_syntax_get_by_name_locking_optional(name, PR_TRUE, PR_TRUE);
+}
+
+
+struct asyntaxinfo *
+attr_syntax_get_by_name_locking_optional(const char *name, PRBool use_lock, PRBool ref_count)
+{
+ struct asyntaxinfo *asi = 0;
+ if (name2asi)
+ {
+ if ( use_lock ) AS_LOCK_READ(name2asi_lock);
+ asi = (struct asyntaxinfo *)PL_HashTableLookup_const(name2asi, name);
+ if ( NULL != asi ) {
+ if(ref_count) PR_AtomicIncrement( &asi->asi_refcnt );
+ }
+ if ( use_lock ) AS_UNLOCK_READ(name2asi_lock);
+ }
+ if (!asi) /* given name may be an OID */
+ asi = attr_syntax_get_by_oid_locking_optional(name, use_lock, ref_count);
+
+ return asi;
+}
+
+
+/*
+ * Give up a reference to an asi.
+ * If the asi has been marked for delete, free it. This would be a bit
+ * easier if we could upgrade a read lock to a write one... but NSPR does
+ * not support that paradigm.
+ */
+void
+attr_syntax_return( struct asyntaxinfo *asi )
+{
+ attr_syntax_return_locking_optional( asi, PR_TRUE );
+}
+
+void
+attr_syntax_return_locking_optional( struct asyntaxinfo *asi, PRBool use_lock )
+{
+ if ( NULL != asi ) {
+ if ( 0 == PR_AtomicDecrement( &asi->asi_refcnt ))
+ {
+ PRBool delete_it;
+
+ if(use_lock) AS_LOCK_READ(name2asi_lock);
+ delete_it = asi->asi_marked_for_delete;
+ if(use_lock) AS_UNLOCK_READ(name2asi_lock);
+
+ if ( delete_it )
+ {
+ AS_LOCK_WRITE(name2asi_lock); /* get a write lock */
+ if ( asi->asi_marked_for_delete ) /* one final check */
+ {
+ attr_syntax_free(asi);
+ }
+ AS_UNLOCK_WRITE(name2asi_lock);
+ }
+ }
+ }
+}
+
+/*
+ * Add the syntax info to the look-up-by-name table. The asi_name and
+ * elements of the asi_aliasses field of the syntax info are the keys.
+ * These need not be normalized since the look up table is case insensitive.
+ * The lock parameter is used by the initialization code. Normally, we want
+ * to acquire a write lock before we modify the table, but during
+ * initialization, we are running in single threaded mode, so we don't have
+ * to worry about resource contention.
+ */
+static void
+attr_syntax_add_by_name(struct asyntaxinfo *a, int lock)
+{
+ if (0 != attr_syntax_init()) return;
+
+ if (lock)
+ AS_LOCK_WRITE(name2asi_lock);
+
+ PL_HashTableAdd(name2asi, a->asi_name, a);
+ if ( a->asi_aliases != NULL ) {
+ int i;
+
+ for ( i = 0; a->asi_aliases[i] != NULL; ++i ) {
+ PL_HashTableAdd(name2asi, a->asi_aliases[i], a);
+ }
+ }
+
+ if (lock)
+ AS_UNLOCK_WRITE(name2asi_lock);
+}
+
+
+/*
+ * Delete the attribute syntax and all entries corresponding to aliases
+ * and oids.
+ */
+void
+attr_syntax_delete( struct asyntaxinfo *asi )
+{
+ PR_ASSERT( asi );
+
+ if (oid2asi && name2asi) {
+ AS_LOCK_WRITE(oid2asi_lock);
+ AS_LOCK_WRITE(name2asi_lock);
+
+ attr_syntax_delete_no_lock( asi, PR_TRUE );
+
+ AS_UNLOCK_WRITE(name2asi_lock);
+ AS_UNLOCK_WRITE(oid2asi_lock);
+ }
+}
+
+
+/*
+ * Dispose of a node. The caller is responsible for locking. See
+ * attr_syntax_delete() for an example.
+ */
+static void
+attr_syntax_delete_no_lock( struct asyntaxinfo *asi,
+ PRBool remove_from_oidtable )
+{
+ int i;
+
+ if (oid2asi && remove_from_oidtable ) {
+ PL_HashTableRemove(oid2asi, asi->asi_oid);
+ }
+
+ if(name2asi) {
+ PL_HashTableRemove(name2asi, asi->asi_name);
+ if ( asi->asi_aliases != NULL ) {
+ for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) {
+ PL_HashTableRemove(name2asi, asi->asi_aliases[i]);
+ }
+ }
+ if ( asi->asi_refcnt > 0 ) {
+ asi->asi_marked_for_delete = PR_TRUE;
+ } else {
+ attr_syntax_free(asi);
+ }
+ }
+}
+
+
+/*
+ * Look up the attribute type in the syntaxes and return a copy of the
+ * normalised attribute type. If it's not there then return a normalised
+ * copy of what the caller gave us.
+ *
+ * Warning: The caller must free the returned string.
+ */
+
+
+
+char *
+slapi_attr_syntax_normalize( const char *s )
+{
+ struct asyntaxinfo *asi = NULL;
+ char *r;
+
+
+ if((asi=attr_syntax_get_by_name_locking_optional(s, PR_TRUE, PR_FALSE)) != NULL ) {
+ r = slapi_ch_strdup(asi->asi_name);
+ }
+ if ( NULL == asi ) {
+ r = attr_syntax_normalize_no_lookup( s );
+ }
+ return r;
+}
+
+
+/*
+ * attr_syntax_exists: return 1 if attr_name exists, 0 otherwise
+ *
+ */
+int
+attr_syntax_exists(const char *attr_name)
+{
+ struct asyntaxinfo *asi;
+
+ asi = attr_syntax_get_by_name(attr_name);
+ attr_syntax_return( asi );
+
+ if ( asi != NULL )
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/* check syntax without incrementing refcount -- handles locking itself */
+
+static void *
+attr_syntax_get_plugin_by_name_with_default( const char *type )
+{
+ struct asyntaxinfo *asi;
+ void *plugin = NULL;
+
+ /*
+ * first we look for this attribute type explictly
+ */
+ if ( (asi = attr_syntax_get_by_name_locking_optional(type, PR_TRUE, PR_FALSE)) == NULL ) {
+ /*
+ * no syntax for this type... return DirectoryString
+ * syntax. we accomplish this by looking up a well known
+ * attribute type that has that syntax.
+ */
+ asi = attr_syntax_get_by_name_locking_optional(
+ ATTR_WITH_DIRSTRING_SYNTAX, PR_TRUE, PR_FALSE);
+ }
+ if ( NULL != asi ) {
+ plugin = asi->asi_plugin;
+ }
+ return( plugin );
+}
+
+
+static struct asyntaxinfo *
+attr_syntax_dup( struct asyntaxinfo *a )
+{
+ struct asyntaxinfo *newas = attr_syntax_new();
+
+ newas->asi_aliases = cool_charray_dup( a->asi_aliases );
+ newas->asi_name = slapi_ch_strdup( a->asi_name );
+ newas->asi_desc = slapi_ch_strdup( a->asi_desc );
+ newas->asi_superior = slapi_ch_strdup( a->asi_superior );
+ newas->asi_mr_equality = slapi_ch_strdup( a->asi_mr_equality );
+ newas->asi_mr_ordering = slapi_ch_strdup( a->asi_mr_ordering );
+ newas->asi_mr_substring = slapi_ch_strdup( a->asi_mr_substring );
+ newas->asi_origin = cool_charray_dup( a->asi_origin );
+ newas->asi_plugin = a->asi_plugin;
+ newas->asi_flags = a->asi_flags;
+ newas->asi_oid = slapi_ch_strdup( a->asi_oid);
+ newas->asi_syntaxlength = a->asi_syntaxlength;
+
+ return( newas );
+}
+
+
+/*
+ * Add a new attribute type to the schema.
+ *
+ * Returns an LDAP error code (LDAP_SUCCESS if all goes well).
+ */
+int
+attr_syntax_add( struct asyntaxinfo *asip )
+{
+ int i, rc = LDAP_SUCCESS;
+ int nolock = asip->asi_flags & SLAPI_ATTR_FLAG_NOLOCKING;
+ struct asyntaxinfo *oldas_from_oid = NULL, *oldas_from_name = NULL;
+ /* attr names may have subtypes in them, and we may not want this
+ if strip_subtypes is true, the ; and anything after it in the
+ attr name or alias will be stripped */
+ /*int strip_subtypes = 1;*/
+
+ /* make sure the oid is unique */
+ if ( NULL != ( oldas_from_oid = attr_syntax_get_by_oid_locking_optional(
+ asip->asi_oid, !nolock, PR_TRUE))) {
+ if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)) {
+ /* failure - OID is in use; no override flag */
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ goto cleanup_and_return;
+ }
+ }
+
+ /* make sure the primary name is unique OR, if override is allowed, that
+ * the primary name and OID point to the same schema definition.
+ */
+ if ( NULL != ( oldas_from_name = attr_syntax_get_by_name_locking_optional(
+ asip->asi_name, !nolock, PR_TRUE))) {
+ if ( 0 == (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE)
+ || ( oldas_from_oid != oldas_from_name )) {
+ /* failure; no override flag OR OID and name don't match */
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ goto cleanup_and_return;
+ }
+ attr_syntax_delete(oldas_from_name);
+ } else if ( NULL != oldas_from_oid ) {
+ /* failure - OID is in use but name does not exist */
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ goto cleanup_and_return;
+ }
+
+ if ( NULL != asip->asi_aliases ) {
+ /* make sure the aliases are unique */
+ for (i = 0; asip->asi_aliases[i] != NULL; ++i) {
+ struct asyntaxinfo *tmpasi;
+
+ if ( NULL != ( tmpasi =
+ attr_syntax_get_by_name_locking_optional(
+ asip->asi_aliases[i], !nolock,PR_TRUE))) {
+ if (asip->asi_flags & SLAPI_ATTR_FLAG_OVERRIDE) {
+ attr_syntax_delete(tmpasi);
+ } else {
+ /* failure - one of the aliases is already in use */
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+
+ attr_syntax_return( tmpasi );
+ if ( LDAP_SUCCESS != rc ) {
+ goto cleanup_and_return;
+ }
+ }
+ }
+ }
+
+ /* the no lock flag is not worth keeping around */
+ asip->asi_flags &= ~SLAPI_ATTR_FLAG_NOLOCKING;
+ /* ditto for the override one */
+ asip->asi_flags &= ~SLAPI_ATTR_FLAG_OVERRIDE;
+
+ attr_syntax_add_by_oid( asip->asi_oid, asip, !nolock);
+ attr_syntax_add_by_name( asip, !nolock);
+
+cleanup_and_return:
+ attr_syntax_return( oldas_from_oid );
+ attr_syntax_return( oldas_from_name );
+ return rc;
+}
+
+
+/*
+ * Returns an LDAP result code.
+ */
+int
+attr_syntax_create(
+ const char *attr_oid,
+ char *const *attr_names,
+ int num_names,
+ const char *attr_desc,
+ const char *attr_superior,
+ const char *mr_equality,
+ const char *mr_ordering,
+ const char *mr_substring,
+ char *const *attr_origins,
+ const char *attr_syntax,
+ int syntaxlength,
+ unsigned long flags,
+ struct asyntaxinfo **asip
+)
+{
+ char *s;
+ struct asyntaxinfo a;
+
+ /* XXXmcs: had to cast away const in many places below */
+ memset(&a, 0, sizeof(a));
+ a.asi_name = slapi_ch_strdup(attr_names[0]);
+ if ( NULL != attr_names[1] ) {
+ a.asi_aliases = (char **)&attr_names[1]; /* all but the zero'th element */
+ }
+ a.asi_desc = (char*)attr_desc;
+ a.asi_oid = (char*)attr_oid;
+ a.asi_superior = (char*)attr_superior;
+ a.asi_mr_equality = (char*)mr_equality;
+ a.asi_mr_ordering = (char*)mr_ordering;
+ a.asi_mr_substring = (char*)mr_substring;
+ a.asi_origin = (char **)attr_origins;
+ a.asi_plugin = plugin_syntax_find( attr_syntax );
+ a.asi_syntaxlength = syntaxlength;
+ a.asi_flags = flags;
+
+ /*
+ * If the 'return exact case' option is on (the default), we store the
+ * first name (the canonical one) unchanged so that attribute names are
+ * returned exactly as they appear in the schema configuration files.
+ * But if 'return exact case' has been turned off, we convert the name
+ * to lowercase. In Netscape Directory Server 4.x and earlier versions,
+ * the default was to convert to lowercase.
+ */
+ if (!config_get_return_exact_case()) {
+ for (s = a.asi_name; *s; ++s) {
+ *s = TOLOWER(*s);
+ }
+ }
+
+ *asip = attr_syntax_dup(&a);
+ slapi_ch_free((void **)&a.asi_name);
+
+ return LDAP_SUCCESS;
+}
+
+
+/*
+ * slapi_attr_type2plugin - return the plugin handling the attribute type
+ * if type is unknown, we return the caseIgnoreString plugin used by the
+ * objectClass attribute type.
+ */
+
+int
+slapi_attr_type2plugin( const char *type, void **pi )
+{
+ char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
+ char *tmp, *basetype;
+ int rc;
+
+ basetype = buf;
+ if ( (tmp = slapi_attr_basetype( type, buf, sizeof(buf) )) != NULL ) {
+ basetype = tmp;
+ }
+ rc = -1;
+ *pi = attr_syntax_get_plugin_by_name_with_default( basetype );
+ if ( NULL != *pi ) {
+ rc = 0;
+ }
+ if ( tmp != NULL ) {
+ free( tmp );
+ }
+
+ return( rc );
+}
+
+/* deprecated -- not MT safe (pointer into asi is returned!) */
+int
+slapi_attr_get_oid( const Slapi_Attr *a, char **oid )
+{
+ struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
+ if (asi) {
+ *oid = asi->asi_oid;
+ attr_syntax_return(asi);
+ return( 0 );
+ } else {
+ *oid = NULL;
+ return( -1 );
+ }
+}
+
+
+/* The caller must dispose of oid by calling slapi_ch_free(). */
+int
+slapi_attr_get_oid_copy( const Slapi_Attr *a, char **oidp )
+{
+ struct asyntaxinfo *asi = attr_syntax_get_by_name(a->a_type);
+ if (asi) {
+ *oidp = slapi_ch_strdup( asi->asi_oid );
+ attr_syntax_return(asi);
+ return( 0 );
+ } else {
+ *oidp = NULL;
+ return( -1 );
+ }
+}
+
+#ifdef ATTR_LDAP_DEBUG
+
+PRIntn
+attr_syntax_printnode(PLHashEntry *he, PRIntn i, void *arg)
+{
+ char *alias = (char *)he->key;
+ struct asyntaxinfo *a = (struct asyntaxinfo *)he->value;
+ printf( " name: %s\n", a->asi_name );
+ printf( "\t flags : 0x%x\n", a->asi_flags );
+ printf( "\t alias : %s\n", alias );
+ printf( "\t desc : %s\n", a->asi_desc );
+ printf( "\t oid : %s\n", a->asi_oid );
+ printf( "\t superior : %s\n", a->asi_superior );
+ printf( "\t mr_equality : %s\n", a->asi_mr_equality );
+ printf( "\t mr_ordering : %s\n", a->asi_mr_ordering );
+ printf( "\t mr_substring: %s\n", a->asi_mr_substring );
+ if ( NULL != a->asi_origin ) {
+ for ( i = 0; NULL != a->asi_origin[i]; ++i ) {
+ printf( "\t origin : %s\n", a->asi_origin[i] );
+ }
+ }
+ printf( "\tplugin: %p\n", a->asi_plugin );
+ printf( "--------------\n" );
+
+ return HT_ENUMERATE_NEXT;
+}
+
+void
+attr_syntax_print()
+{
+ printf( "*** attr_syntax_print ***\n" );
+ PL_HashTableEnumerateEntries(name2asi, attr_syntax_printnode, 0);
+}
+
+#endif
+
+
+/* lowercase the attr name and chop trailing spaces */
+/* note that s may contain options also, e.g., userCertificate;binary */
+char *
+attr_syntax_normalize_no_lookup( const char *s )
+{
+ char *save, *tmps;
+
+ tmps = slapi_ch_strdup(s);
+ for ( save = tmps; (*tmps != '\0') && (*tmps != ' '); tmps++ )
+ {
+ *tmps = TOLOWER( *tmps );
+ }
+ *tmps = '\0';
+
+ return save;
+}
+
+struct enum_arg_wrapper {
+ AttrEnumFunc aef;
+ void *arg;
+};
+
+PRIntn
+attr_syntax_enumerate_internal(PLHashEntry *he, PRIntn i, void *arg)
+{
+ struct enum_arg_wrapper *eaw = (struct enum_arg_wrapper *)arg;
+ int rc;
+
+ rc = (eaw->aef)((struct asyntaxinfo *)he->value, eaw->arg);
+ if ( ATTR_SYNTAX_ENUM_STOP == rc ) {
+ rc = HT_ENUMERATE_STOP;
+ } else if ( ATTR_SYNTAX_ENUM_REMOVE == rc ) {
+ rc = HT_ENUMERATE_REMOVE;
+ } else {
+ rc = HT_ENUMERATE_NEXT;
+ }
+
+ return rc;
+}
+
+void
+attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock )
+{
+ struct enum_arg_wrapper eaw;
+ eaw.aef = aef;
+ eaw.arg = arg;
+
+ if (!oid2asi)
+ return;
+
+ if ( writelock ) {
+ AS_LOCK_WRITE(oid2asi_lock);
+ AS_LOCK_WRITE(name2asi_lock);
+ } else {
+ AS_LOCK_READ(oid2asi_lock);
+ AS_LOCK_READ(name2asi_lock);
+ }
+
+ PL_HashTableEnumerateEntries(oid2asi, attr_syntax_enumerate_internal, &eaw);
+
+ if ( writelock ) {
+ AS_UNLOCK_WRITE(oid2asi_lock);
+ AS_UNLOCK_WRITE(name2asi_lock);
+ } else {
+ AS_UNLOCK_READ(oid2asi_lock);
+ AS_UNLOCK_READ(name2asi_lock);
+ }
+}
+
+
+struct attr_syntax_enum_flaginfo {
+ unsigned long asef_flag;
+};
+
+static int
+attr_syntax_clear_flag_callback(struct asyntaxinfo *asip, void *arg)
+{
+ struct attr_syntax_enum_flaginfo *fi;
+
+ PR_ASSERT( asip != NULL );
+ fi = (struct attr_syntax_enum_flaginfo *)arg;
+ PR_ASSERT( fi != NULL );
+
+ asip->asi_flags &= ~(fi->asef_flag);
+
+ return ATTR_SYNTAX_ENUM_NEXT;
+}
+
+
+static int
+attr_syntax_delete_if_not_flagged(struct asyntaxinfo *asip, void *arg)
+{
+ struct attr_syntax_enum_flaginfo *fi;
+
+ PR_ASSERT( asip != NULL );
+ fi = (struct attr_syntax_enum_flaginfo *)arg;
+ PR_ASSERT( fi != NULL );
+
+ if ( 0 == ( asip->asi_flags & fi->asef_flag )) {
+ attr_syntax_delete_no_lock( asip, PR_FALSE );
+ return ATTR_SYNTAX_ENUM_REMOVE;
+ } else {
+ return ATTR_SYNTAX_ENUM_NEXT;
+ }
+}
+
+
+/*
+ * Clear 'flag' within all attribute definitions.
+ */
+void
+attr_syntax_all_clear_flag( unsigned long flag )
+{
+ struct attr_syntax_enum_flaginfo fi;
+
+ memset( &fi, 0, sizeof(fi));
+ fi.asef_flag = flag;
+ attr_syntax_enumerate_attrs( attr_syntax_clear_flag_callback,
+ (void *)&fi, PR_TRUE );
+}
+
+
+/*
+ * Delete all attribute definitions that do not contain any bits of 'flag'
+ * in their flags.
+ */
+void
+attr_syntax_delete_all_not_flagged( unsigned long flag )
+{
+ struct attr_syntax_enum_flaginfo fi;
+
+ memset( &fi, 0, sizeof(fi));
+ fi.asef_flag = flag;
+ attr_syntax_enumerate_attrs( attr_syntax_delete_if_not_flagged,
+ (void *)&fi, PR_TRUE );
+}
+
+static int
+attr_syntax_init(void)
+{
+ if (!oid2asi)
+ {
+ oid2asi = PL_NewHashTable(2047, hashNocaseString,
+ hashNocaseCompare,
+ PL_CompareValues, 0, 0);
+ if ( NULL == ( oid2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
+ "attrsyntax oid rwlock" ))) {
+ if(oid2asi) PL_HashTableDestroy(oid2asi);
+ oid2asi = NULL;
+
+ slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
+ "PR_NewRWLock() for oid2asi lock failed\n" );
+ return 1;
+ }
+ }
+
+ if (!name2asi)
+ {
+ name2asi = PL_NewHashTable(2047, hashNocaseString,
+ hashNocaseCompare,
+ PL_CompareValues, 0, 0);
+ if ( NULL == ( name2asi_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
+ "attrsyntax name2asi rwlock"))) {
+ if(name2asi) PL_HashTableDestroy(name2asi);
+ name2asi = NULL;
+
+ slapi_log_error( SLAPI_LOG_FATAL, "attr_syntax_init",
+ "PR_NewRWLock() for oid2asi lock failed\n" );
+ return 1;
+ }
+ }
+ return 0;
+}
diff --git a/ldap/servers/slapd/auditlog.c b/ldap/servers/slapd/auditlog.c
new file mode 100644
index 00000000..e2f11afb
--- /dev/null
+++ b/ldap/servers/slapd/auditlog.c
@@ -0,0 +1,217 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slap.h"
+
+/*
+ * JCM - The audit log might be better implemented as a post-op plugin.
+ */
+
+#define ATTR_CHANGETYPE "changetype"
+#define ATTR_NEWRDN "newrdn"
+#define ATTR_DELETEOLDRDN "deleteoldrdn"
+#define ATTR_MODIFIERSNAME "modifiersname"
+char *attr_changetype = ATTR_CHANGETYPE;
+char *attr_newrdn = ATTR_NEWRDN;
+char *attr_deleteoldrdn = ATTR_DELETEOLDRDN;
+char *attr_modifiersname = ATTR_MODIFIERSNAME;
+
+/* Forward Declarations */
+static void write_audit_file( int optype, char *dn, void *change, int flag, time_t curtime );
+
+void
+write_audit_log_entry( Slapi_PBlock *pb )
+{
+ time_t curtime;
+ char *dn;
+ void *change;
+ int flag = 0;
+ int internal_op = 0;
+ Operation *op;
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op );
+ internal_op = operation_is_flag_set(op, OP_FLAG_INTERNAL);
+ slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn );
+ switch ( operation_get_type(op) )
+ {
+ case SLAPI_OPERATION_MODIFY:
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &change );
+ break;
+ case SLAPI_OPERATION_ADD:
+ {
+ /*
+ * For adds, we want the unnormalized dn, so we can preserve
+ * spacing, case, when replicating it.
+ */
+ Slapi_Entry *te = NULL;
+ slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &change );
+ te = (Slapi_Entry *)change;
+ if ( NULL != te )
+ {
+ dn = slapi_entry_get_dn( te );
+ }
+ }
+ break;
+ case SLAPI_OPERATION_DELETE:
+ {
+ char * deleterDN = NULL;
+ slapi_pblock_get(pb, SLAPI_REQUESTOR_DN, &deleterDN);
+ change = deleterDN;
+ }
+ break;
+
+ case SLAPI_OPERATION_MODDN:
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &change );
+ slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &flag );
+ break;
+ }
+ curtime = current_time();
+ write_audit_file( operation_get_type(op), dn, change, flag, curtime );
+}
+
+
+
+/*
+ * Function: write_audit_file
+ * Arguments:
+ * optype - type of LDAP operation being logged
+ * dn - distinguished name of entry being changed
+ * change - pointer to the actual change operation
+ * For a delete operation, may contain the modifier's DN.
+ * flag - only used by modrdn operations - value of deleteoldrdn flag
+ * curtime - the current time
+ * Returns: nothing
+ */
+static void
+write_audit_file(
+ int optype,
+ char *dn,
+ void *change,
+ int flag,
+ time_t curtime
+)
+{
+ LDAPMod **mods;
+ Slapi_Entry *e;
+ char *newrdn, *tmp, *tmpsave;
+ int len, i, j;
+ char *timestr;
+ lenstr *l;
+
+ l = lenstr_new();
+
+ addlenstr( l, "time: " );
+ timestr = format_localTime( curtime );
+ addlenstr( l, timestr );
+ slapi_ch_free((void **) &timestr );
+ addlenstr( l, "\n" );
+ addlenstr( l, "dn: " );
+ addlenstr( l, dn );
+ addlenstr( l, "\n" );
+
+ switch ( optype )
+ {
+ case SLAPI_OPERATION_MODIFY:
+ addlenstr( l, attr_changetype );
+ addlenstr( l, ": modify\n" );
+ mods = change;
+ for ( j = 0; mods[j] != NULL; j++ )
+ {
+ int operationtype= mods[j]->mod_op & ~LDAP_MOD_BVALUES;
+ switch ( operationtype )
+ {
+ case LDAP_MOD_ADD:
+ addlenstr( l, "add: " );
+ addlenstr( l, mods[j]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+
+ case LDAP_MOD_DELETE:
+ addlenstr( l, "delete: " );
+ addlenstr( l, mods[j]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+
+ case LDAP_MOD_REPLACE:
+ addlenstr( l, "replace: " );
+ addlenstr( l, mods[j]->mod_type );
+ addlenstr( l, "\n" );
+ break;
+
+ default:
+ operationtype= LDAP_MOD_IGNORE;
+ break;
+ }
+ if(operationtype!=LDAP_MOD_IGNORE)
+ {
+ for ( i = 0; mods[j]->mod_bvalues != NULL && mods[j]->mod_bvalues[i] != NULL; i++ )
+ {
+ char *buf, *bufp;
+ len = strlen( mods[j]->mod_type );
+ len = LDIF_SIZE_NEEDED( len, mods[j]->mod_bvalues[i]->bv_len ) + 1;
+ buf = slapi_ch_malloc( len );
+ bufp = buf;
+ ldif_put_type_and_value( &bufp, mods[j]->mod_type,
+ mods[j]->mod_bvalues[i]->bv_val,
+ mods[j]->mod_bvalues[i]->bv_len );
+ *bufp = '\0';
+ addlenstr( l, buf );
+ slapi_ch_free( (void**)&buf );
+ }
+ }
+ addlenstr( l, "-\n" );
+ }
+ break;
+
+ case SLAPI_OPERATION_ADD:
+ e = change;
+ addlenstr( l, attr_changetype );
+ addlenstr( l, ": add\n" );
+ tmp = slapi_entry2str( e, &len );
+ tmpsave = tmp;
+ while (( tmp = strchr( tmp, '\n' )) != NULL )
+ {
+ tmp++;
+ if ( !ldap_utf8isspace( tmp ))
+ {
+ break;
+ }
+ }
+ addlenstr( l, tmp );
+ slapi_ch_free((void**)&tmpsave );
+ break;
+
+ case SLAPI_OPERATION_DELETE:
+ tmp = change;
+ addlenstr( l, attr_changetype );
+ addlenstr( l, ": delete\n" );
+ if (tmp && tmp[0]) {
+ addlenstr( l, attr_modifiersname );
+ addlenstr( l, ": ");
+ addlenstr( l, tmp);
+ addlenstr( l, "\n");
+ }
+ break;
+
+ case SLAPI_OPERATION_MODDN:
+ newrdn = change;
+ addlenstr( l, attr_changetype );
+ addlenstr( l, ": modrdn\n" );
+ addlenstr( l, attr_newrdn );
+ addlenstr( l, ": " );
+ addlenstr( l, newrdn );
+ addlenstr( l, "\n" );
+ addlenstr( l, attr_deleteoldrdn );
+ addlenstr( l, ": " );
+ addlenstr( l, flag ? "1" : "0" );
+ addlenstr( l, "\n" );
+ }
+ addlenstr( l, "\n" );
+
+ slapd_log_audit_proc (l->ls_buf, l->ls_len);
+
+ lenstr_free( &l );
+}
diff --git a/ldap/servers/slapd/auth.c b/ldap/servers/slapd/auth.c
new file mode 100644
index 00000000..cfcb1c2e
--- /dev/null
+++ b/ldap/servers/slapd/auth.c
@@ -0,0 +1,506 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdlib.h> /* getenv */
+#include <string.h> /* memcpy */
+#include <ldaputil/ldaputil.h> /* LDAPU_SUCCESS, ldapu_VTable_set */
+#include <ldaputil/init.h> /* ldaputil_init */
+#include <ldaputil/certmap.h> /* ldapu_cert_to_ldap_entry */
+#ifndef _WIN32
+#include <sys/param.h> /* MAXPATHLEN */
+#endif
+#include "slap.h" /* slapi_ch_malloc */
+#include "fe.h"
+
+char* client_auth_config_file = NULL;
+
+/* forward declarations */
+
+static void generate_id();
+static Slapi_ComponentId * auth_get_component_id();
+
+#define internal_ld NULL
+
+static int LDAP_CALL LDAP_CALLBACK
+slapu_msgfree( LDAP* ld, LDAPMessage* msg )
+{
+ Slapi_PBlock* pb = (Slapi_PBlock*)msg;
+ if (ld != internal_ld) {
+ return ldap_msgfree (msg);
+ }
+ if (pb) {
+ slapi_free_search_results_internal (pb);
+ slapi_pblock_destroy (pb);
+ }
+ return LDAP_SUCCESS;
+}
+
+static int LDAP_CALL LDAP_CALLBACK
+slapu_search_s( LDAP* ld, const char* baseDN, int scope, const char* filter,
+ char** attrs, int attrsonly, LDAPMessage** result )
+{
+ int err = LDAP_NO_SUCH_OBJECT;
+ Slapi_PBlock* pb;
+ LDAPControl **ctrls;
+
+ if (ld != internal_ld) {
+ return ldap_search_s (ld, baseDN, scope, filter, attrs, attrsonly, result);
+ }
+ LDAPDebug (LDAP_DEBUG_TRACE, "=> slapu_search_s (\"%s\", %i, %s)\n",
+ baseDN, scope, filter);
+ if (filter == NULL) filter = "objectclass=*";
+
+ /* use new internal search API */
+ pb=slapi_pblock_new();
+ /* we need to provide managedsait control to avoid returning continuation references */
+ ctrls = (LDAPControl **)slapi_ch_calloc (2, sizeof (LDAPControl *));
+ ctrls[0] = (LDAPControl*)slapi_ch_malloc (sizeof (LDAPControl));
+ ctrls[0]->ldctl_oid = slapi_ch_strdup (LDAP_CONTROL_MANAGEDSAIT);
+ ctrls[0]->ldctl_value.bv_val = NULL;
+ ctrls[0]->ldctl_value.bv_len = 0;
+ ctrls[0]->ldctl_iscritical = '\0';
+ slapi_search_internal_set_pb(pb, baseDN, scope, (char *)filter, attrs, attrsonly,
+ ctrls, NULL, auth_get_component_id(), 0 /* actions */);
+ slapi_search_internal_pb(pb);
+
+ if (pb != NULL) {
+ if (slapi_pblock_get (pb, SLAPI_PLUGIN_INTOP_RESULT, &err)) {
+ err = LDAP_LOCAL_ERROR;
+ }
+ if (err != LDAP_SUCCESS) {
+ slapu_msgfree (ld, (LDAPMessage*)pb);
+ pb = NULL;
+ if (scope == LDAP_SCOPE_SUBTREE) {
+ char ebuf[ BUFSIZ ], fbuf[ BUFSIZ ];
+ LDAPDebug (LDAP_DEBUG_ANY, "slapi_search_internal (\"%s\", subtree, %s) err %i\n",
+ escape_string( (char*)baseDN, ebuf ), escape_string( (char*)filter, fbuf ), err);
+ }
+ }
+ } else {
+ char ebuf[ BUFSIZ ], fbuf[ BUFSIZ ];
+ LDAPDebug (LDAP_DEBUG_ANY, "slapi_search_internal (\"%s\", %i, %s) NULL\n",
+ escape_string( (char*)baseDN, ebuf ), scope, escape_string( (char*)filter, fbuf ));
+ }
+ *result = (LDAPMessage*)pb;
+ LDAPDebug (LDAP_DEBUG_TRACE, "<= slapu_search_s %i\n", err, 0, 0);
+ return err;
+}
+
+static int LDAP_CALL LDAP_CALLBACK
+slapu_count_entries( LDAP* ld, LDAPMessage* msg )
+{
+ Slapi_Entry** entry = NULL;
+ int count = 0;
+ if (ld != internal_ld) {
+ return ldap_count_entries (ld, msg);
+ }
+ if (!slapi_pblock_get ((Slapi_PBlock*)msg, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry)
+ && entry) {
+ for (; *entry; ++entry) ++count;
+ }
+ return count;
+}
+
+/* slapu_search_s() returns a Slapi_PBlock*, but slapu_first_entry() and
+ * slapu_next_entry() return a Slapi_Entry** pointing into the same array
+ * as the PBlock. If one of the iteration (Slapi_Entry**) pointers was
+ * passed to slapu_msgfree(), havoc would ensue. ldaputil never does this.
+ * But ldap_msgfree() would support it (no?); so a plugin function might.
+ * Yet another way this doesn't support plugin functions.
+ */
+
+static LDAPMessage* LDAP_CALL LDAP_CALLBACK
+slapu_first_entry( LDAP* ld, LDAPMessage* msg )
+{
+ Slapi_Entry** entry = NULL;
+ if (ld != internal_ld) {
+ return ldap_first_entry (ld, msg);
+ }
+ if (!slapi_pblock_get ((Slapi_PBlock*)msg, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry)
+ && entry && *entry) {
+ return (LDAPMessage*)entry;
+ }
+ return NULL;
+}
+
+static LDAPMessage* LDAP_CALL LDAP_CALLBACK
+slapu_next_entry( LDAP* ld, LDAPMessage* msg )
+{
+ Slapi_Entry** entry = (Slapi_Entry**)msg;
+ if (ld != internal_ld) {
+ return ldap_next_entry (ld, msg);
+ }
+ if (entry && *entry && *++entry) {
+ return (LDAPMessage*)entry;
+ }
+ return NULL;
+}
+
+static char* LDAP_CALL LDAP_CALLBACK
+slapu_get_dn( LDAP* ld, LDAPMessage* entry )
+{
+ if (ld != internal_ld) {
+ return ldap_get_dn (ld, entry);
+ }
+ return slapi_ch_strdup (slapi_entry_get_dn (*(Slapi_Entry**)entry));
+}
+
+static void LDAP_CALL LDAP_CALLBACK
+slapu_memfree( LDAP* ld, void* dn )
+{
+ if (ld != internal_ld) {
+ ldap_memfree (dn);
+ } else {
+ free (dn);
+ }
+}
+
+static char*
+slapu_attr_get_desc( Slapi_Attr *attr )
+{
+ char* desc = NULL;
+ if (slapi_attr_get_type (attr, &desc) == LDAP_SUCCESS && desc) {
+ return slapi_ch_strdup (desc);
+ }
+ return NULL;
+}
+
+/* slapu_first_attribute and slapu_next_attribute use a Slapi_Attr*
+ * as an iterator. It is malloc'd by first() and free'd by ber_free().
+ */
+
+static char* LDAP_CALL LDAP_CALLBACK
+slapu_first_attribute( LDAP* ld, LDAPMessage* entry, BerElement** iter )
+{
+ if (ld != internal_ld) {
+ return ldap_first_attribute (ld, entry, iter);
+ } else {
+ Slapi_Attr** attr = (Slapi_Attr**) slapi_ch_malloc (sizeof(Slapi_Attr*));
+ *iter = (BerElement*) attr;
+ if (attr && slapi_entry_first_attr (*(Slapi_Entry**)entry, attr) == LDAP_SUCCESS) {
+ return slapu_attr_get_desc (*attr);
+ }
+ }
+ return NULL;
+}
+
+static char* LDAP_CALL LDAP_CALLBACK
+slapu_next_attribute( LDAP* ld, LDAPMessage* entry, BerElement* iter)
+{
+ Slapi_Attr** attr = (Slapi_Attr**)iter;
+ if (ld != internal_ld) {
+ return ldap_next_attribute (ld, entry, iter);
+ }
+ if (attr && slapi_entry_next_attr (*(Slapi_Entry**)entry, *attr, attr) == LDAP_SUCCESS) {
+ return slapu_attr_get_desc (*attr);
+ }
+ return NULL;
+}
+
+static void LDAP_CALL LDAP_CALLBACK
+slapu_ber_free( LDAP* ld, BerElement* iter, int freebuf )
+{
+ if (ld != internal_ld) {
+ ldap_ber_free (iter, freebuf);
+ } else {
+ free ((Slapi_Attr**)iter);
+ }
+}
+
+static struct berval** LDAP_CALL LDAP_CALLBACK
+slapu_get_values_len( LDAP *ld, LDAPMessage *entry, const char *desc )
+{
+ Slapi_Attr* attr = NULL;
+ if (ld != internal_ld) {
+ return ldap_get_values_len (ld, entry, desc);
+ }
+ if (slapi_entry_attr_find (*(Slapi_Entry**)entry, desc, &attr) == LDAP_SUCCESS
+ && attr) {
+ struct berval** values = NULL;
+ if ( slapi_attr_get_bervals_copy (attr, &values) == 0 ) {
+ return (values);
+ }
+ }
+ return NULL;
+}
+
+static void LDAP_CALL LDAP_CALLBACK
+slapu_value_free_len( LDAP* ld, struct berval **values )
+{
+ if (ld != internal_ld) {
+ ldap_value_free_len (values);
+ } else {
+ ber_bvecfree (values);
+ }
+}
+
+void
+client_auth_init ()
+{
+ char *instancedir;
+ int len = 0;
+ char *val = NULL;
+ char* filename;
+ char netsite_root[MAXPATHLEN];
+ int err;
+ if (client_auth_config_file == NULL) {
+ client_auth_config_file = "shared/config/certmap.conf";
+ }
+
+ /* calculate the server_root from instance dir */
+ instancedir = config_get_instancedir();
+ /* make sure path does not end in the path separator character */
+ len = strlen(instancedir);
+ if (instancedir[len-1] == '/' || instancedir[len-1] == '\\') {
+ instancedir[len-1] = '\0';
+ }
+
+ /* get the server root from the path */
+ val = strrchr(instancedir, '/');
+ if (!val) {
+ val = strrchr(instancedir, '\\');
+ }
+ if (val) {
+ val++;
+ *val = '\0';
+ }
+
+ strcpy(netsite_root, instancedir);
+ slapi_ch_free_string(&instancedir);
+ filename = PR_smprintf("%s%s", netsite_root, client_auth_config_file);
+
+ err = ldaputil_init (filename, "", netsite_root, "slapd", NULL);
+ if (err != LDAPU_SUCCESS) {
+ LDAPDebug (LDAP_DEBUG_TRACE, "ldaputil_init(%s,...) %i\n",
+ filename, err, 0);
+ } else {
+ LDAPUVTable_t vtable = {
+ NULL /* ssl_init */,
+ NULL /* set_option */,
+ NULL /* simple_bind_s */,
+ NULL /* unbind */,
+ slapu_search_s,
+ slapu_count_entries,
+ slapu_first_entry,
+ slapu_next_entry,
+ slapu_msgfree,
+ slapu_get_dn,
+ slapu_memfree,
+ slapu_first_attribute,
+ slapu_next_attribute,
+ slapu_ber_free,
+ NULL /* get_values */,
+ NULL /* value_free */,
+ slapu_get_values_len,
+ slapu_value_free_len};
+ ldapu_VTable_set (&vtable);
+ }
+ PR_smprintf_free (filename);
+ /* why do we define these strings if we never use them? */
+ if (ldapu_strings != NULL);
+
+ /* Generate a component id for cert-based authentication */
+ generate_id();
+}
+
+#include <ssl.h>
+#include "slapi-plugin.h" /* SLAPI_BERVAL_EQ */
+#include "slapi-private.h" /* COMPONENT_CERT_AUTH */
+
+static Slapi_ComponentId * auth_component_id=NULL;
+
+static void generate_id()
+{
+ if (auth_component_id == NULL ) {
+ auth_component_id=generate_componentid (NULL /* Not a plugin */ , COMPONENT_CERT_AUTH);
+ }
+}
+
+static Slapi_ComponentId * auth_get_component_id() {
+ return auth_component_id;
+}
+
+
+static char*
+subject_of (CERTCertificate* cert)
+{
+ char* dn = NULL;
+ if (cert != NULL) {
+ int err = ldapu_get_cert_subject_dn (cert, &dn);
+ if (err != LDAPU_SUCCESS) {
+ LDAPDebug (LDAP_DEBUG_ANY, "ldapu_get_cert_subject_dn(%p) %i (%s)\n",
+ (void*)cert, err, ldapu_err2string (err));
+ }
+ }
+ return dn;
+}
+
+static char*
+issuer_of (CERTCertificate* cert)
+{
+ char* dn = NULL;
+ if (cert != NULL) {
+ int err = ldapu_get_cert_issuer_dn (cert, &dn);
+ if (err != LDAPU_SUCCESS) {
+ LDAPDebug (LDAP_DEBUG_ANY, "ldapu_get_cert_issuer_dn(%p) %i (%s)\n",
+ (void*)cert, err, ldapu_err2string (err));
+ }
+ }
+ return dn;
+}
+
+/*
+ * Log a certificate that was rejected because the client didn't
+ * authenticate it.
+ *
+ * Note: handle_bad_certificate() is called via slapd_ssl_badCertHook().
+ * A Connection * is passed in client data. That connection must have its
+ * c_mutex locked.
+ */
+int
+handle_bad_certificate (void* clientData, PRFileDesc *prfd)
+{
+ char sbuf[ BUFSIZ ], ibuf[ BUFSIZ ];
+ Connection* conn = (Connection*) clientData;
+ CERTCertificate* clientCert = slapd_ssl_peerCertificate (prfd);
+
+ PRErrorCode errorCode = PR_GetError();
+ char* subject = subject_of (clientCert);
+ char* issuer = issuer_of (clientCert);
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d " SLAPI_COMPONENT_NAME_NSPR " error %i (%s); unauthenticated client %s; issuer %s\n",
+ conn->c_connid, errorCode, slapd_pr_strerror(errorCode),
+ subject ? escape_string( subject, sbuf ) : "NULL",
+ issuer ? escape_string( issuer, ibuf ) : "NULL" );
+ if (issuer) free (issuer);
+ if (subject) free (subject);
+ if (clientCert) CERT_DestroyCertificate (clientCert);
+ return -1; /* non-zero means reject this certificate */
+}
+
+
+/*
+ * Get an identity from the client's certificate (if any was sent).
+ *
+ * Note: handle_handshake_done() is called via slapd_ssl_handshakeCallback().
+ * A Connection * is passed in client data. That connection must have its
+ * c_mutex locked.
+ */
+void
+handle_handshake_done (PRFileDesc *prfd, void* clientData)
+{
+ Connection* conn = (Connection*) clientData;
+ CERTCertificate* clientCert = slapd_ssl_peerCertificate(prfd);
+
+ char* clientDN = NULL;
+ int keySize = 0;
+ char* cipher = NULL;
+ char* extraErrorMsg = "";
+ SSLChannelInfo channelInfo;
+ SSLCipherSuiteInfo cipherInfo;
+
+ if ( (slapd_ssl_getChannelInfo (prfd, &channelInfo, sizeof(channelInfo))) != SECSuccess ) {
+ PRErrorCode errorCode = PR_GetError();
+ slapi_log_access (LDAP_DEBUG_STATS,
+ "conn=%d SSL failed to obtain channel info; "
+ SLAPI_COMPONENT_NAME_NSPR " error %i (%s)\n",
+ conn->c_connid, errorCode, slapd_pr_strerror(errorCode));
+ return;
+ }
+ if ( (slapd_ssl_getCipherSuiteInfo (channelInfo.cipherSuite, &cipherInfo, sizeof(cipherInfo)) )
+ != SECSuccess) {
+ PRErrorCode errorCode = PR_GetError();
+ slapi_log_access (LDAP_DEBUG_STATS,
+ "conn=%d SSL failed to obtain cipher info; ",
+ SLAPI_COMPONENT_NAME_NSPR " error %i (%s)\n",
+ conn->c_connid, errorCode, slapd_pr_strerror(errorCode));
+ return;
+ }
+
+ keySize = cipherInfo.effectiveKeyBits;
+ cipher = slapi_ch_strdup(cipherInfo.symCipherName);
+
+ /* If inside an Start TLS operation, perform the privacy level discovery
+ * and if the security degree achieved after the handshake is not reckoned
+ * to be enough, close the SSL connection. */
+ if ( conn->c_flags & CONN_FLAG_START_TLS ) {
+ if ( cipherInfo.symKeyBits == 0 ) {
+ start_tls_graceful_closure( conn, NULL, 1 );
+ slapi_ch_free((void **)&cipher);
+ return ;
+ }
+ }
+
+ if (config_get_SSLclientAuth() == SLAPD_SSLCLIENTAUTH_OFF ) {
+ slapi_log_access (LDAP_DEBUG_STATS, "conn=%d SSL %i-bit %s\n",
+ conn->c_connid, keySize, cipher ? cipher : "NULL" );
+ slapi_ch_free((void **)&cipher);
+ return;
+ }
+ if (clientCert == NULL) {
+ slapi_log_access (LDAP_DEBUG_STATS, "conn=%d SSL %i-bit %s\n",
+ conn->c_connid, keySize, cipher ? cipher : "NULL" );
+ } else {
+ char* subject = subject_of (clientCert);
+ {
+ char* issuer = issuer_of (clientCert);
+ char sbuf[ BUFSIZ ], ibuf[ BUFSIZ ];
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d SSL %i-bit %s; client %s; issuer %s\n",
+ conn->c_connid, keySize, cipher ? cipher : "NULL",
+ subject ? escape_string( subject, sbuf ) : "NULL",
+ issuer ? escape_string( issuer, ibuf ) : "NULL");
+ if (issuer) free (issuer);
+ }
+ slapi_dn_normalize (subject);
+ {
+ LDAPMessage* chain = NULL;
+ char *basedn = config_get_basedn();
+ int err;
+
+ err = ldapu_cert_to_ldap_entry
+ (clientCert, internal_ld, basedn?basedn:""/*baseDN*/, &chain);
+ if (err == LDAPU_SUCCESS && chain) {
+ LDAPMessage* entry = slapu_first_entry (internal_ld, chain);
+ if (entry) {
+ clientDN = slapu_get_dn (internal_ld, entry);
+ if (clientDN) slapi_dn_normalize (clientDN);
+ } else {
+
+ extraErrorMsg = "no entry";
+ LDAPDebug (LDAP_DEBUG_TRACE, "<= ldapu_cert_to_ldap_entry() %s\n",
+ extraErrorMsg, 0, 0);
+ }
+ } else {
+ extraErrorMsg = ldapu_err2string(err);
+ LDAPDebug (LDAP_DEBUG_TRACE, "<= ldapu_cert_to_ldap_entry() %i (%s)%s\n",
+ err, extraErrorMsg, chain ? "" : " NULL");
+ }
+ slapi_ch_free((void**)&basedn);
+ slapu_msgfree (internal_ld, chain);
+ }
+ if (subject) free (subject);
+ }
+
+ if (clientDN != NULL) {
+ char ebuf[ BUFSIZ ];
+ slapi_log_access (LDAP_DEBUG_STATS, "conn=%d SSL client bound as %s\n",
+ conn->c_connid, escape_string( clientDN, ebuf ));
+ } else if (clientCert != NULL) {
+ slapi_log_access (LDAP_DEBUG_STATS,
+ "conn=%d SSL failed to map client certificate to LDAP DN (%s)\n",
+ conn->c_connid, extraErrorMsg );
+ }
+
+ /*
+ * Associate the new credentials with the connection. Note that
+ * clientDN and clientCert may be NULL.
+ */
+ bind_credentials_set( conn, SLAPD_AUTH_SSL, clientDN,
+ SLAPD_AUTH_SSL, clientDN, clientCert , NULL);
+
+ slapi_ch_free((void **)&cipher);
+ /* clientDN and clientCert will be freed later */
+}
diff --git a/ldap/servers/slapd/auth.h b/ldap/servers/slapd/auth.h
new file mode 100644
index 00000000..044b95e4
--- /dev/null
+++ b/ldap/servers/slapd/auth.h
@@ -0,0 +1,15 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _SLDAPD_AUTH_H_
+#define _SLDAPD_AUTH_H_
+
+#include <prio.h>
+
+void client_auth_init();
+void handle_handshake_done (PRFileDesc *prfd, void* clientData);
+int handle_bad_certificate (void* clientData, PRFileDesc *prfd);
+
+#endif
diff --git a/ldap/servers/slapd/ava.c b/ldap/servers/slapd/ava.c
new file mode 100644
index 00000000..9831315c
--- /dev/null
+++ b/ldap/servers/slapd/ava.c
@@ -0,0 +1,129 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* ava.c - routines for dealing with attribute value assertions */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+
+static void strcpy_special_undo();
+
+int
+get_ava(
+ BerElement *ber,
+ struct ava *ava
+)
+{
+ char *type;
+
+ if ( ber_scanf( ber, "{ao}", &type, &ava->ava_value )
+ == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY, " get_ava ber_scanf\n", 0, 0, 0 );
+ return( LDAP_PROTOCOL_ERROR );
+ }
+ ava->ava_type = slapi_attr_syntax_normalize(type);
+ free( type );
+
+ return( 0 );
+}
+
+void
+ava_done(
+ struct ava *ava
+)
+{
+ slapi_ch_free( (void**)&(ava->ava_type) );
+ slapi_ch_free( (void**)&(ava->ava_value.bv_val) );
+}
+
+int
+rdn2ava(
+ char *rdn,
+ struct ava *ava
+)
+{
+ char *s;
+
+ if ( (s = strchr( rdn, '=' )) == NULL ) {
+ return( -1 );
+ }
+ *s++ = '\0';
+
+ ava->ava_type = rdn;
+ strcpy_special_undo( s, s );
+ ava->ava_value.bv_val = s;
+ ava->ava_value.bv_len = strlen( s );
+
+ return( 0 );
+}
+
+/*
+** This function takes a quoted attribute value of the form "abc",
+** and strips off the enclosing quotes. It also deals with quoted
+** characters by removing the preceeding '\' character.
+**
+*/
+static void
+strcpy_special_undo( char *d, const char *s )
+{
+ const char *end = s + strlen(s);
+ for ( ; *s; s++ )
+ {
+ switch ( *s )
+ {
+ case '"':
+ break;
+ case '\\':
+ {
+ /*
+ * The '\' could be escaping a single character, ie \"
+ * or could be escaping a hex byte, ie \01
+ */
+ int singlecharacter= 1;
+ if ( s+2 < end )
+ {
+ int n = hexchar2int( s[1] );
+ if ( n >= 0 )
+ {
+ int n2 = hexchar2int( s[2] );
+ if ( n2 >= 0 )
+ {
+ singlecharacter= 0;
+ n = (n << 4) + n2;
+ if (n == 0)
+ {
+ /* don't change \00 */
+ *d++ = *++s;
+ *d++ = *++s;
+ }
+ else
+ {
+ /* change \xx to a single char */
+ ++s;
+ *(unsigned char*)(s+1) = n;
+ }
+ }
+ }
+ }
+ if(singlecharacter)
+ {
+ s++;
+ *d++ = *s;
+ }
+ break;
+ }
+ default:
+ *d++ = *s;
+ break;
+ }
+ }
+ *d = '\0';
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/Makefile b/ldap/servers/slapd/back-ldbm/Makefile
new file mode 100644
index 00000000..c86ec0b3
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/Makefile
@@ -0,0 +1,190 @@
+#
+# 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 libback-ldbm
+#
+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 = $(OBJDIR)/lib/libback-ldbm
+
+ifndef INSTDIR
+INSTDIR = /netscape/server4/
+endif
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+ifndef LDAP_USE_OLD_DB
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+INCLUDES+=-I$(DB_INCLUDE)
+else
+CFLAGS+=-DLDAP_USE_DB185
+endif
+include $(LDAP_SRC)/nsdeps.mk
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd
+
+LIBBACK_LDBM_OBJS= idl.o idl_shim.o idl_new.o idl_common.o cache.o dn2entry.o \
+ id2entry.o index.o haschildren.o nextid.o init.o \
+ filterindex.o close.o backentry.o monitor.o seq.o start.o \
+ rmdb.o ldif2ldbm.o dblayer.o findentry.o archive.o \
+ sort.o dbsize.o dbtest.o vlv.o vlv_key.o \
+ vlv_srch.o matchrule.o entrystore.o parents.o misc.o \
+ upgrade.o dbversion.o cleanup.o uniqueid2entry.o \
+ perfctrs.o instance.o import-threads.o import.o import-merge.o \
+ ldbm_config.o ldbm_instance_config.o ldbm_index_config.o ldbm_attrcrypt_config.o \
+ ldbm_attr.o \
+ ldbm_abandon.o \
+ ldbm_compare.o \
+ ldbm_add.o \
+ ldbm_search.o \
+ ldbm_modify.o \
+ ldbm_modrdn.o \
+ ldbm_delete.o \
+ ldbm_bind.o \
+ ldbm_unbind.o \
+ ancestorid.o \
+ ldbm_attrcrypt.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(LIBBACK_LDBM_OBJS))
+
+ifeq ($(ARCH), WINNT)
+LIBBACK_LDBM_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+LIBBACK_LDBM= $(addprefix $(LDAP_LIBBACK_LDBM_DLLDIR)/, $(LIBBACK_LDBM_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP) \
+ $(LDAP_LIBLDIF_DEP) \
+ $(LDAP_LIBAVL_DEP)
+EXTRA_LIBS += \
+ $(NSPRLINK) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LDAP_LIBLDIF) \
+ $(LDAP_LIBAVL)
+CFLAGS+= /WX
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += \
+ $(LDAP_SDK_LIBLDAP_DLL_DEP) \
+ $(LDAP_LIBLDIF_DEP) \
+ $(LDAP_LIBAVL_DEP)
+EXTRA_LIBS += \
+ $(NSPRLINK) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LDAP_LIBLDIF) \
+ $(LDAP_LIBAVL) \
+ $(DLL_EXTRA_LIBS)
+LD=ld
+endif
+
+ifeq ($(ARCH), SOLARIS)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP) \
+ $(LDAP_LIBLDIF_DEP) \
+ $(LDAP_LIBAVL_DEP)
+EXTRA_LIBS += \
+ $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) \
+ $(LDAP_LIBLDIF) \
+ $(LDAP_LIBAVL) \
+ $(DLL_EXTRA_LIBS) -lc
+LINK_DLL += -z defs
+endif
+
+ifeq ($(ARCH), HPUX)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP) \
+ $(LDAP_LIBLDIF_DEP) \
+ $(LDAP_LIBAVL_DEP)
+EXTRA_LIBS += \
+ $(LDAPLINK) $(SECURITYLINK) $(NSPRLINK) \
+ $(LDAP_LIBLDIF) \
+ $(LDAP_LIBAVL) \
+ $(DLL_EXTRA_LIBS) -lc
+endif
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libback-ldbm.def"
+IMPLIB= /IMPLIB:$(LDAP_LIBBACK_LDBM_LIBDIR)/$(LIBBACK_LDBM_DLL).lib
+MAPFILE= /MAP:$(LDAP_LIBBACK_LDBM_LIBDIR)/$(LIBBACK_LDBM_DLL).map
+endif # WINNT
+
+ifeq ($(ARCH), UnixWare)
+EXTRA_LIBS_DEP += $(LDAP_LIBAVL_DEP)
+EXTRA_LIBS += $(LDAP_LIBAVL)
+endif # UnixWare
+
+ifeq ($(ARCH), Linux)
+EXTRA_LIBS_DEP += $(LDAP_LIBLDBM_DEP) $(LDAP_LIBAVL_DEP) $(LDAP_LIBLDIF_DEP)
+EXTRA_LIBS += $(LDAP_LIBLDBM) $(LDAP_LIBAVL) $(LDAP_LIBLDIF)
+EXTRA_LIBS += $(DLL_EXTRA_LIBS)
+endif # Linux
+
+EXTRA_LIBS_DEP += $(DB_LIB_DEP)
+
+clientSDK:
+
+all: $(OBJDEST) $(LDAP_LIBBACK_LDBM_LIBDIR) $(LDAP_LIBBACK_LDBM_DLLDIR) \
+ $(BUILD_DEP) $(LIBBACK_LDBM)
+ifeq ($(ARCH), WINNT)
+ cd ntdbperfdll; $(MAKE) $(MFLAGS) all
+endif
+
+dummy:
+ -@echo LDAP_LIBDIR = $(LDAP_LIBDIR)
+ -@echo LDAP_LIBBACK_LDBM_LIBDIR = $(LDAP_LIBBACK_LDBM_LIBDIR)
+ -@echo LIB_RELDIR = $(LIB_RELDIR)
+ -@echo LDAP_LIBBACK_LDBM_DLLDIR = $(LDAP_LIBBACK_LDBM_DLLDIR)
+ -@echo LDAP_LIBBACK_LDBM = $(LDAP_LIBBACK_LDBM)
+ -@echo LIBBACK_LDBM = $(LIBBACK_LDBM)
+ abort
+
+$(LIBBACK_LDBM): $(OBJS) $(LIBBACK_LDBM_DLL_OBJ) $(EXTRA_LIBS_DEP) $(LIBSLAPD_DEP)
+ $(LINK_DLL) $(IMPLIB) $(MAPFILE) $(LIBBACK_LDBM_DLL_OBJ) $(EXTRA_LIBS) $(DB_LIB) $(LIBSLAPD)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBBACK_LDBM_DLL_OBJ)
+endif
+ $(RM) $(LIBBACK_LDBM)
+
+$(OBJDEST) $(LIBBACK_LDBM_LIBDIR):
+ $(MKDIR) $@
+
+ifeq ($(ARCH), AIX)
+ifeq ($(DEBUG), optimize)
+
+# For some reason compiling ldif2ldbm.c with the -O flag on AIX causes
+# the new import code to hang. For now we will avoid the -O flag.
+
+TEMP_CFLAGS = $(subst -O,,$(CFLAGS))
+
+$(OBJDEST)/ldif2ldbm.o: ldif2ldbm.c
+ $(CC) -o $(OBJDEST)/ldif2ldbm.o -c $(TEMP_CFLAGS) $(MCC_INCLUDE) ldif2ldbm.c
+endif
+endif
+
+# Target to push the built binary to an installed server
+LDBM_PUSH = $(addprefix $(INSTDIR)/, lib/libback-ldbm.dll)
+push: $(LDBM_PUSH)
+
+$(LDBM_PUSH): $(LIBBACK_LDBM)
+ cp $(LIBBACK_LDBM) $(LDBM_PUSH)
+
diff --git a/ldap/servers/slapd/back-ldbm/ancestorid.c b/ldap/servers/slapd/back-ldbm/ancestorid.c
new file mode 100644
index 00000000..0ec76a17
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ancestorid.c
@@ -0,0 +1,747 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "back-ldbm.h"
+
+static char *sourcefile = "ancestorid";
+
+/* Start of definitions for a simple cache using a hash table */
+
+typedef struct id2idl {
+ ID keyid;
+ IDList *idl;
+ struct id2idl *next;
+} id2idl;
+
+static void id2idl_free(id2idl **ididl);
+static int id2idl_same_key(const void *ididl, const void *k);
+
+typedef Hashtable id2idl_hash;
+
+#define id2idl_new_hash(size) new_hash(size,HASHLOC(id2idl,next),NULL,id2idl_same_key)
+#define id2idl_hash_lookup(ht,key,he) find_hash(ht,key,sizeof(ID),(void**)(he))
+#define id2idl_hash_add(ht,key,he,alt) add_hash(ht,key,sizeof(ID),he,(void**)(alt))
+#define id2idl_hash_remove(ht,key) remove_hash(ht,key,sizeof(ID))
+
+static void id2idl_hash_destroy(id2idl_hash *ht);
+
+/* End of definitions for a simple cache using a hash table */
+
+static int ldbm_parentid(backend *be, DB_TXN *txn, ID id, ID *ppid);
+static int check_cache(id2idl_hash *ht);
+static IDList *idl_union_allids(backend *be, struct attrinfo *ai, IDList *a, IDList *b);
+
+static int ldbm_get_nonleaf_ids(backend *be, DB_TXN *txn, IDList **idl)
+{
+ int ret = 0;
+ DB *db = NULL;
+ DBC *dbc = NULL;
+ DBT key = {0};
+ DBT data = {0};
+ struct attrinfo *ai = NULL;
+ IDList *nodes = NULL;
+ ID id;
+
+ /* Open the parentid index */
+ ainfo_get( be, "parentid", &ai );
+
+ /* Open the parentid index file */
+ ret = dblayer_get_index_file(be, ai, &db, DBOPEN_CREATE);
+ if (ret != 0) {
+ ldbm_nasty(sourcefile,13010,ret);
+ goto out;
+ }
+
+ /* Get a cursor so we can walk through the parentid */
+ ret = db->cursor(db,txn,&dbc,0);
+ if (ret != 0 ) {
+ ldbm_nasty(sourcefile,13020,ret);
+ goto out;
+ }
+
+ /* For each key which is an equality key */
+ do {
+ ret = dbc->c_get(dbc,&key,&data,DB_NEXT_NODUP);
+ if ((ret == 0) && (*(char*)key.data == EQ_PREFIX)) {
+ id = (ID) strtoul((char*)key.data+1, NULL, 10);
+ idl_insert(&nodes, id);
+ }
+ } while (ret == 0);
+
+ /* Check for success */
+ if (ret == DB_NOTFOUND) ret = 0;
+ if (ret != 0) ldbm_nasty(sourcefile,13030,ret);
+
+ out:
+ /* Close the cursor */
+ if (dbc != NULL) {
+ if (ret == 0) {
+ ret = dbc->c_close(dbc);
+ if (ret != 0) ldbm_nasty(sourcefile,13040,ret);
+ } else {
+ (void)dbc->c_close(dbc);
+ }
+ }
+
+ /* Release the parentid file */
+ if (db != NULL) {
+ dblayer_release_index_file( be, ai, db );
+ }
+
+ /* Return the idlist */
+ if (ret == 0) {
+ *idl = nodes;
+ LDAPDebug(LDAP_DEBUG_TRACE, "found %lu nodes for ancestorid\n",
+ (u_long)IDL_NIDS(nodes), 0, 0);
+ } else {
+ idl_free(nodes);
+ *idl = NULL;
+ }
+
+ return ret;
+}
+
+/*
+ * XXX: This function creates ancestorid index, which is a sort of hack.
+ * This function handles idl directly,
+ * which should have been implemented in the idl file(s).
+ * When the idl code would be updated in the future,
+ * this function may also get affected.
+ * (see also bug#: 605535)
+ *
+ * Construct the ancestorid index. Requirements:
+ * - The backend is read only.
+ * - The parentid index is accurate.
+ * - Non-leaf entries have IDs less than their descendants
+ * (guaranteed after a database import but not after a subtree move)
+ *
+ */
+int ldbm_ancestorid_create_index(backend *be)
+{
+ int ret = 0;
+ DB *db_pid = NULL;
+ DB *db_aid = NULL;
+ DBT key = {0};
+ DB_TXN *txn = NULL;
+ struct attrinfo *ai_pid = NULL;
+ struct attrinfo *ai_aid = NULL;
+ char keybuf[24];
+ IDList *nodes = NULL;
+ IDList *children = NULL, *descendants = NULL;
+ NIDS nids;
+ ID id, parentid;
+ id2idl_hash *ht = NULL;
+ id2idl *ididl;
+
+ /*
+ * We need to iterate depth-first through the non-leaf nodes
+ * in the tree amassing an idlist of descendant ids for each node.
+ * We would prefer to go through the parentid keys just once from
+ * highest id to lowest id but the btree ordering is by string
+ * rather than number. So we go through the parentid keys in btree
+ * order first of all to create an idlist of all the non-leaf nodes.
+ * Then we can use the idlist to iterate through parentid in the
+ * correct order.
+ */
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "Creating ancestorid index\n", 0,0,0);
+
+ /* Get the non-leaf node IDs */
+ ret = ldbm_get_nonleaf_ids(be, txn, &nodes);
+ if (ret != 0) return ret;
+
+ /* Get the ancestorid index */
+ ainfo_get(be, "ancestorid", &ai_aid);
+
+ /* Prevent any other use of the index */
+ ai_aid->ai_indexmask |= INDEX_OFFLINE;
+
+ /* Open the ancestorid index file */
+ ret = dblayer_get_index_file(be, ai_aid, &db_aid, DBOPEN_CREATE);
+ if (ret != 0) {
+ ldbm_nasty(sourcefile,13050,ret);
+ goto out;
+ }
+
+ /* Maybe nothing to do */
+ if (nodes == NULL || nodes->b_nids == 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Nothing to do to build ancestorid index\n",
+ 0, 0, 0);
+ goto out;
+ }
+
+ /* Create an ancestorid cache */
+ ht = id2idl_new_hash(nodes->b_nids);
+
+ /* Get the parentid index */
+ ainfo_get( be, "parentid", &ai_pid );
+
+ /* Open the parentid index file */
+ ret = dblayer_get_index_file(be, ai_pid, &db_pid, DBOPEN_CREATE);
+ if (ret != 0) {
+ ldbm_nasty(sourcefile,13060,ret);
+ goto out;
+ }
+
+ /* Initialize key DBT */
+ key.data = keybuf;
+ key.ulen = sizeof(keybuf);
+ key.flags = DB_DBT_USERMEM;
+
+ /* Iterate from highest to lowest ID */
+ nids = nodes->b_nids;
+ do {
+
+ nids--;
+ id = nodes->b_ids[nids];
+
+ /* Get immediate children from parentid index */
+ key.size = PR_snprintf(key.data, key.ulen, "%c%lu",
+ EQ_PREFIX, (u_long)id);
+ key.size++; /* include the null terminator */
+ ret = NEW_IDL_NO_ALLID;
+ children = idl_fetch(be, db_pid, &key, txn, ai_pid, &ret);
+ if (ret != 0) {
+ ldbm_nasty(sourcefile,13070,ret);
+ break;
+ }
+
+ /* Insert into ancestorid for this node */
+ if (id2idl_hash_lookup(ht, &id, &ididl)) {
+ descendants = idl_union_allids(be, ai_aid, ididl->idl, children);
+ idl_free(children);
+ if (id2idl_hash_remove(ht, &id) == 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ancestorid hash_remove failed\n", 0,0,0);
+ } else {
+ id2idl_free(&ididl);
+ }
+ } else {
+ descendants = children;
+ }
+ ret = idl_store_block(be, db_aid, &key, descendants, txn, ai_aid);
+ if (ret != 0) break;
+
+ /* Get parentid for this entry */
+ ret = ldbm_parentid(be, txn, id, &parentid);
+ if (ret != 0) {
+ idl_free(descendants);
+ break;
+ }
+
+ /* A suffix entry does not have a parent */
+ if (parentid == NOID) {
+ idl_free(descendants);
+ continue;
+ }
+
+ /* Insert into ancestorid for this node's parent */
+ if (id2idl_hash_lookup(ht, &parentid, &ididl)) {
+ IDList *idl = idl_union_allids(be, ai_aid, ididl->idl, descendants);
+ idl_free(descendants);
+ idl_free(ididl->idl);
+ ididl->idl = idl;
+ } else {
+ ididl = (id2idl*)slapi_ch_calloc(1,sizeof(id2idl));
+ ididl->keyid = parentid;
+ ididl->idl = descendants;
+ if (id2idl_hash_add(ht, &parentid, ididl, NULL) == 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ancestorid hash_add failed\n", 0,0,0);
+ }
+ }
+
+ } while (nids > 0);
+
+ if (ret != 0) {
+ goto out;
+ }
+
+ /* We're expecting the cache to be empty */
+ ret = check_cache(ht);
+
+ out:
+ if (ret == 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "Created ancestorid index\n", 0,0,0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "Failed to create ancestorid index\n", 0,0,0);
+ }
+
+ /* Destroy the cache */
+ id2idl_hash_destroy(ht);
+
+ /* Free any leftover idlists */
+ idl_free(nodes);
+
+ /* Release the parentid file */
+ if (db_pid != NULL) {
+ dblayer_release_index_file( be, ai_pid, db_pid );
+ }
+
+ /* Release the ancestorid file */
+ if (db_aid != NULL) {
+ dblayer_release_index_file( be, ai_aid, db_aid );
+ }
+
+ /* Enable the index */
+ if (ret == 0) {
+ ai_aid->ai_indexmask &= ~INDEX_OFFLINE;
+ }
+
+ return ret;
+}
+
+/*
+ * Get parentid of an id by reading the operational attr from id2entry.
+ */
+static int ldbm_parentid(backend *be, DB_TXN *txn, ID id, ID *ppid)
+{
+ int ret = 0;
+ DB *db = NULL;
+ DBT key = {0};
+ DBT data = {0};
+ ID stored_id;
+ char *p;
+
+ /* Open the id2entry file */
+ ret = dblayer_get_id2entry(be, &db);
+ if (ret != 0) {
+ ldbm_nasty(sourcefile,13100,ret);
+ goto out;
+ }
+
+ /* Initialize key and data DBTs */
+ id_internal_to_stored(id, (char *)&stored_id);
+ key.data = (char *)&stored_id;
+ key.size = sizeof(stored_id);
+ key.flags = DB_DBT_USERMEM;
+ data.flags = DB_DBT_MALLOC;
+
+ /* Read id2entry */
+ ret = db->get(db, txn, &key, &data, 0);
+ if (ret != 0) {
+ ldbm_nasty(sourcefile,13110,ret);
+ goto out;
+ }
+
+ /* Extract the parentid value */
+#define PARENTID_STR "\nparentid:"
+ p = strstr(data.data, PARENTID_STR);
+ if (p == NULL) {
+ *ppid = NOID;
+ goto out;
+ }
+ *ppid = strtoul(p + strlen(PARENTID_STR), NULL, 10);
+
+ out:
+ /* Free the entry value */
+ if (data.data != NULL) free(data.data);
+
+ /* Release the id2entry file */
+ if (db != NULL) {
+ dblayer_release_id2entry(be, db);
+ }
+ return ret;
+}
+
+static void id2idl_free(id2idl **ididl)
+{
+ idl_free((*ididl)->idl);
+ slapi_ch_free((void**)ididl);
+}
+
+static int id2idl_same_key(const void *ididl, const void *k)
+{
+ return (((id2idl *)ididl)->keyid == *(ID *)k);
+}
+
+static int check_cache(id2idl_hash *ht)
+{
+ id2idl *e;
+ u_long i, found = 0;
+ int ret = 0;
+
+ if (ht == NULL) return 0;
+
+ for (i = 0; i < ht->size; i++) {
+ e = (id2idl *)ht->slot[i];
+ while (e) {
+ found++;
+ e = e->next;
+ }
+ }
+
+ if (found > 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: parentid index is not complete (%lu extra keys in ancestorid cache)\n", found,0,0);
+ ret = -1;
+ }
+
+ return ret;
+}
+
+static void id2idl_hash_destroy(id2idl_hash *ht)
+{
+ u_long i;
+ id2idl *e, *next;
+
+ if (ht == NULL) return;
+
+ for (i = 0; i < ht->size; i++) {
+ e = (id2idl *)ht->slot[i];
+ while (e) {
+ next = e->next;
+ id2idl_free(&e);
+ e = next;
+ }
+ }
+ slapi_ch_free((void **)&ht);
+}
+
+/*
+ * idl_union_allids - return a union b
+ * takes attr index allids setting into account
+ */
+static IDList *idl_union_allids(backend *be, struct attrinfo *ai, IDList *a, IDList *b)
+{
+ if (!idl_get_idl_new()) {
+ if (a != NULL && b != NULL) {
+ if (ALLIDS( a ) || ALLIDS( b ) ||
+ (IDL_NIDS(a) + IDL_NIDS(b) > idl_get_allidslimit(ai))) {
+ return( idl_allids( be ) );
+ }
+ }
+ }
+ return idl_union(be, a, b);
+}
+
+static int ancestorid_addordel(
+ backend *be,
+ DB* db,
+ ID node_id,
+ ID id,
+ DB_TXN *txn,
+ struct attrinfo *ai,
+ int flags,
+ int *allids
+)
+{
+ DBT key = {0};
+ char keybuf[24];
+ int ret = 0;
+
+ /* Initialize key DBT */
+ key.data = keybuf;
+ key.ulen = sizeof(keybuf);
+ key.flags = DB_DBT_USERMEM;
+ key.size = PR_snprintf(key.data, key.ulen, "%c%lu",
+ EQ_PREFIX, (u_long)node_id);
+ key.size++; /* include the null terminator */
+
+ if (flags & BE_INDEX_ADD) {
+#if 1
+ LDAPDebug(LDAP_DEBUG_TRACE, "insert ancestorid %lu:%lu\n",
+ (u_long)node_id, (u_long)id, 0);
+#endif
+ ret = idl_insert_key(be, db, &key, id, txn, ai, allids);
+ } else {
+#if 1
+ LDAPDebug(LDAP_DEBUG_TRACE, "delete ancestorid %lu:%lu\n",
+ (u_long)node_id, (u_long)id, 0);
+#endif
+ ret = idl_delete_key(be, db, &key, id, txn, ai);
+ }
+
+ if (ret != 0) {
+ ldbm_nasty(sourcefile,13120,ret);
+ }
+
+ return ret;
+}
+
+/*
+ * Update ancestorid index inserting or deleting depending on flags.
+ * The entry ids to be indexed are given by id (a base object)
+ * and optionally subtree_idl (descendants of the base object).
+ * The ancestorid keys to be updated are derived from nodes
+ * in the tree from low up to high. Whether the low and high nodes
+ * themselves are updated is given by include_low and include_high.
+ */
+static int ldbm_ancestorid_index_update(
+ backend *be,
+ const Slapi_DN *low,
+ const Slapi_DN *high,
+ int include_low,
+ int include_high,
+ ID id,
+ IDList *subtree_idl,
+ int flags, /* BE_INDEX_ADD, BE_INDEX_DEL */
+ back_txn *txn
+)
+{
+ DB *db = NULL;
+ int allids = IDL_INSERT_NORMAL;
+ Slapi_DN dn = {0};
+ Slapi_DN nextdn = {0};
+ struct attrinfo *ai = NULL;
+ struct berval ndnv;
+ ID node_id, sub_id;
+ IDList *idl;
+ idl_iterator iter;
+ int err = 0, ret = 0;
+ DB_TXN *db_txn = txn != NULL ? txn->back_txn_txn : NULL;
+
+ /* Open the ancestorid index */
+ ainfo_get(be, "ancestorid", &ai);
+ ret = dblayer_get_index_file(be, ai, &db, DBOPEN_CREATE);
+ if (ret != 0) {
+ ldbm_nasty(sourcefile,13130,ret);
+ goto out;
+ }
+
+ slapi_sdn_copy(low, &dn);
+
+ if (include_low == 0) {
+ if (slapi_sdn_compare(&dn, high) == 0) {
+ goto out;
+ }
+ /* Get the next highest DN */
+ slapi_sdn_get_parent(&dn, &nextdn);
+ slapi_sdn_copy(&nextdn, &dn);
+ }
+
+ /* Iterate up through the tree */
+ do {
+ if (slapi_sdn_isempty(&dn)) {
+ break;
+ }
+
+ /* Have we reached the high node? */
+ if (include_high == 0 && slapi_sdn_compare(&dn, high) == 0) {
+ break;
+ }
+
+ /* Get the id for that DN */
+ ndnv.bv_val = (void*)slapi_sdn_get_ndn(&dn);
+ ndnv.bv_len = slapi_sdn_get_ndn_len(&dn);
+ err = 0;
+ idl = index_read(be, "entrydn", indextype_EQUALITY, &ndnv, txn, &err);
+ if (idl == NULL) {
+ if (err != 0 && err != DB_NOTFOUND) {
+ ldbm_nasty(sourcefile,13140,ret);
+ ret = err;
+ }
+ break;
+ }
+ node_id = idl_firstid(idl);
+ idl_free(idl);
+
+ /* Update ancestorid for the base entry */
+ ret = ancestorid_addordel(be, db, node_id, id, db_txn, ai, flags, &allids);
+ if (ret != 0) break;
+
+ /*
+ * If this node was already allids then all higher nodes must already
+ * be at allids since the higher nodes must have a greater number
+ * of descendants. Therefore no point continuing.
+ */
+ if (allids == IDL_INSERT_ALLIDS) break;
+
+ /* Update ancestorid for any subtree entries */
+ if (subtree_idl != NULL && ((flags & BE_INDEX_ADD) || (!ALLIDS(subtree_idl)))) {
+ iter = idl_iterator_init(subtree_idl);
+ while ((sub_id = idl_iterator_dereference_increment(&iter, subtree_idl)) != NOID) {
+ ret = ancestorid_addordel(be, db, node_id, sub_id, db_txn, ai, flags, &allids);
+ if (ret != 0) break;
+ }
+ if (ret != 0) break;
+ }
+
+ /* Have we reached the high node? */
+ if (slapi_sdn_compare(&dn, high) == 0) {
+ break;
+ }
+
+ /* Get the next highest DN */
+ slapi_sdn_get_parent(&dn, &nextdn);
+ slapi_sdn_copy(&nextdn, &dn);
+
+ } while (ret == 0);
+
+ out:
+ slapi_sdn_done(&dn);
+ slapi_sdn_done(&nextdn);
+
+ /* Release the ancestorid file */
+ if (db != NULL) {
+ dblayer_release_index_file(be, ai, db);
+ }
+
+ return ret;
+}
+
+/*
+ * Update the ancestorid index for a single entry.
+ * This function depends on the integrity of the entrydn index.
+ */
+int ldbm_ancestorid_index_entry(
+ backend *be,
+ struct backentry *e,
+ int flags, /* BE_INDEX_ADD, BE_INDEX_DEL */
+ back_txn *txn
+)
+{
+ int ret = 0;
+
+ ret = ldbm_ancestorid_index_update(be,
+ slapi_entry_get_sdn_const(e->ep_entry),
+ slapi_be_getsuffix(be, 0),
+ 0, 1, e->ep_id, NULL, flags, txn);
+
+ return ret;
+}
+
+/*
+ * Returns <0, 0, >0 according to whether right is a suffix of left,
+ * neither is a suffix of the other, or left is a suffix of right.
+ * If common is non-null then the common suffix of left and right
+ * is returned in *common.
+ */
+int slapi_sdn_suffix_cmp(
+ const Slapi_DN *left,
+ const Slapi_DN *right,
+ Slapi_DN *common
+)
+{
+ char **rdns1, **rdns2;
+ int count1, count2, i, ret = 0;
+ size_t len = 0;
+ char *p, *ndnstr;
+
+ rdns1 = ldap_explode_dn(slapi_sdn_get_ndn(left), 0);
+ rdns2 = ldap_explode_dn(slapi_sdn_get_ndn(right), 0);
+
+ for(count1 = 0; rdns1[count1]!=NULL; count1++){
+ }
+ count1--;
+
+ for(count2 = 0; rdns2[count2]!=NULL; count2++){
+ }
+ count2--;
+
+ while (count1 >= 0 && count2 >= 0) {
+ if (strcmp(rdns1[count1], rdns2[count2]) != 0) break;
+ count1--;
+ count2--;
+ }
+
+ count1++;
+ count2++;
+
+ if (count1 == 0 && count2 == 0) {
+ /* equal */
+ ret = 0;
+ } else if (count1 == 0) {
+ /* left is suffix of right */
+ ret = 1;
+ } else if (count2 == 0) {
+ /* right is suffix of left */
+ ret = -1;
+ } else {
+ /* common prefix (possibly root), not left nor right */
+ ret = 0;
+ }
+
+ /* if caller does not want the common prefix then we're done */
+ if (common == NULL) goto out;
+
+ /* figure out how much space we need */
+ for (i = count1; rdns1[i] != NULL; i++) {
+ len += strlen(rdns1[i]) + 1;
+ }
+
+ /* write the string */
+ p = ndnstr = slapi_ch_calloc(len+1,sizeof(char));
+ for (i = count1; rdns1[i] != NULL; i++) {
+ sprintf(p, "%s%s", (p != ndnstr) ? "," : "", rdns1[i]);
+ p += strlen(p);
+ }
+
+ /* return the DN */
+ slapi_sdn_set_dn_passin(common, ndnstr);
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "common suffix <%s>\n",
+ slapi_sdn_get_dn(common), 0, 0);
+
+ out:
+ ldap_value_free(rdns1);
+ ldap_value_free(rdns2);
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "slapi_sdn_suffix_cmp(<%s>, <%s>) => %d\n",
+ slapi_sdn_get_dn(left), slapi_sdn_get_dn(right), ret);
+
+ return ret;
+}
+
+int ldbm_ancestorid_move_subtree(
+ backend *be,
+ const Slapi_DN *olddn,
+ const Slapi_DN *newdn,
+ ID id,
+ IDList *subtree_idl,
+ back_txn *txn
+)
+{
+ int ret = 0;
+ Slapi_DN commondn = {0};
+
+ /* Determine the common ancestor */
+ (void)slapi_sdn_suffix_cmp(olddn, newdn, &commondn);
+
+ /* Delete from old ancestors */
+ ret = ldbm_ancestorid_index_update(be,
+ olddn,
+ &commondn,
+ 0,
+ 0,
+ id,
+ subtree_idl,
+ BE_INDEX_DEL,
+ txn);
+ if (ret != 0) goto out;
+
+ /* Add to new ancestors */
+ ret = ldbm_ancestorid_index_update(be,
+ newdn,
+ &commondn,
+ 0,
+ 0,
+ id,
+ subtree_idl,
+ BE_INDEX_ADD,
+ txn);
+
+ out:
+ slapi_sdn_done(&commondn);
+ return ret;
+}
+
+int ldbm_ancestorid_read(
+ backend *be,
+ back_txn *txn,
+ ID id,
+ IDList **idl
+)
+{
+ int ret = 0;
+ struct berval bv;
+ char keybuf[24];
+
+ bv.bv_val = keybuf;
+ bv.bv_len = PR_snprintf(keybuf, sizeof(keybuf), "%lu", (u_long)id);
+
+ *idl = index_read(be, "ancestorid", indextype_EQUALITY, &bv, txn, &ret);
+
+ return ret;
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/archive.c b/ldap/servers/slapd/back-ldbm/archive.c
new file mode 100644
index 00000000..2daee2c5
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/archive.c
@@ -0,0 +1,332 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* archive.c - ldap ldbm back-end archive and restore entry points */
+
+#include "back-ldbm.h"
+
+int ldbm_back_archive2ldbm( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li;
+ char *directory = NULL;
+ int return_value = -1;
+ int task_flags = 0;
+ int run_from_cmdline = 0;
+ Slapi_Task *task;
+ int is_old_to_new = 0;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_SEQ_VAL, &directory );
+ slapi_pblock_get( pb, SLAPI_BACKEND_TASK, &task );
+ slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags );
+ li->li_flags = run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE);
+
+ /* check the current idl format vs backup DB version */
+ if (idl_get_idl_new())
+ {
+ char dbversion[LDBM_VERSION_MAXBUF];
+ char dataversion[LDBM_VERSION_MAXBUF];
+ int value = 0;
+
+ if (dbversion_read(li, directory, dbversion, dataversion) != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: Unable to read dbversion "
+ "file in %s\n", directory, 0, 0);
+ }
+ value = lookup_dbversion(dbversion, DBVERSION_TYPE);
+ if (value & DBVERSION_OLD_IDL)
+ {
+ is_old_to_new = 1;
+ }
+ }
+
+ /* No ldbm be's exist until we process the config information. */
+ if (run_from_cmdline) {
+ mapping_tree_init();
+ ldbm_config_load_dse_info(li);
+ } else {
+ ldbm_instance *inst;
+ Object *inst_obj, *inst_obj2;
+
+ /* task does not support restore old idl onto new idl server */
+ if (is_old_to_new)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "backup has old idl format; "
+ "to restore old formated backup onto the new server, "
+ "please use command line utility \"bak2db\" .\n",
+ 0, 0, 0);
+ if (task)
+ {
+ slapi_task_log_notice(task,
+ "backup has old idl format; "
+ "to restore old formated backup onto the new server, "
+ "please use command line utility \"bak2db\" .\n");
+ }
+ return -1;
+ }
+ /* server is up -- mark all backends busy */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+
+ /* check if an import/restore is already ongoing... */
+ if (instance_set_busy(inst) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm: '%s' is already in the middle of "
+ "another task and cannot be disturbed.\n",
+ inst->inst_name, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "Backend '%s' is already in the middle of "
+ "another task and cannot be disturbed.\n",
+ inst->inst_name);
+ }
+
+ /* painfully, we have to clear the BUSY flags on the
+ * backends we'd already marked...
+ */
+ for (inst_obj2 = objset_first_obj(li->li_instance_set);
+ inst_obj2 && (inst_obj2 != inst_obj);
+ inst_obj2 = objset_next_obj(li->li_instance_set,
+ inst_obj2)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj2);
+ instance_set_not_busy(inst);
+ }
+ object_release(inst_obj2);
+ object_release(inst_obj);
+ return -1;
+ }
+ }
+
+ /* now take down ALL BACKENDS */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ LDAPDebug(LDAP_DEBUG_ANY, "Bringing %s offline...\n",
+ inst->inst_name, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task, "Bringing %s offline...",
+ inst->inst_name);
+ }
+ slapi_mtn_be_disable(inst->inst_be);
+ cache_clear(&inst->inst_cache);
+ }
+ /* now we know nobody's using any of the backend instances, so we
+ * can shutdown the dblayer -- this closes all instances too.
+ * Use DBLAYER_RESTORE_MODE to prevent loss of perfctr memory.
+ */
+ dblayer_close(li, DBLAYER_RESTORE_MODE);
+ }
+
+ /* tell the database to restore */
+ return_value = dblayer_restore(li, directory, task);
+ if (0 != return_value) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "archive2db: Failed to read backup file set. "
+ "Either the directory specified doesn't exist, "
+ "or it exists but doesn't contain a valid backup set, "
+ "or file permissions prevent the server reading "
+ "the backup set. error=%d (%s)\n",
+ return_value, dblayer_strerror(return_value), 0 );
+ if (task) {
+ slapi_task_log_notice(task, "Failed to read the backup file set "
+ "from %s", directory);
+ }
+ }
+
+ if (run_from_cmdline)
+ {
+ if (is_old_to_new)
+ {
+ /* does not exist */
+ char *p;
+ char c;
+ char *bakup_dir = NULL;
+ int skipinit = SLAPI_UPGRADEDB_SKIPINIT;
+
+ p = strrchr(directory, '/');
+ if (NULL == p)
+ {
+ p = strrchr(directory, '\\');
+ }
+
+ if (NULL == p) /* never happen, I guess */
+ {
+ directory = ".";
+ c = '/';
+ }
+ else
+ {
+ c = *p;
+ *p = '\0';
+ }
+ bakup_dir = (char *)slapi_ch_malloc(strlen(directory) +
+ sizeof("tmp") + 13);
+ sprintf(bakup_dir, "%s%ctmp_%010d", directory, c, time(0));
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "archive2db: backup dir: %s\n", bakup_dir, 0, 0);
+ *p = c;
+
+ slapi_pblock_set( pb, SLAPI_SEQ_VAL, bakup_dir );
+ slapi_pblock_set( pb, SLAPI_SEQ_TYPE, &skipinit );
+ return_value = ldbm_back_upgradedb( pb );
+ }
+ }
+ else
+ {
+ ldbm_instance *inst;
+ Object *inst_obj;
+ int ret;
+
+ if (0 != return_value) {
+ /* error case (607331)
+ * just to go back to the previous state if possible */
+ dblayer_start(li, DBLAYER_NORMAL_MODE);
+ }
+ /* bring all backends back online */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ ret = dblayer_instance_start(inst->inst_be, DBLAYER_NORMAL_MODE);
+ if (ret != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "archive2db: Unable to restart '%s'\n",
+ inst->inst_name, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task, "Unable to restart '%s'",
+ inst->inst_name);
+ }
+ } else {
+ slapi_mtn_be_enable(inst->inst_be);
+ instance_set_not_busy(inst);
+ }
+ }
+ }
+
+ return return_value;
+}
+
+int ldbm_back_ldbm2archive( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li;
+ char *directory = NULL;
+ int return_value = -1;
+ int task_flags = 0;
+ int run_from_cmdline = 0;
+ Slapi_Task *task;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_SEQ_VAL, &directory );
+ slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags );
+ li->li_flags = run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE);
+
+ slapi_pblock_get( pb, SLAPI_BACKEND_TASK, &task );
+
+ /* No ldbm be's exist until we process the config information. */
+ if (run_from_cmdline) {
+ mapping_tree_init();
+ ldbm_config_load_dse_info(li);
+ }
+ /* to avoid conflict w/ import, do this check for commandline, as well */
+ {
+ Object *inst_obj, *inst_obj2;
+ ldbm_instance *inst = NULL;
+
+ /* server is up -- mark all backends busy */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+
+ /* check if an import/restore is already ongoing... */
+ if (instance_set_busy(inst) != 0 || dblayer_in_import(inst) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm: '%s' is already in the middle of "
+ "another task and cannot be disturbed.\n",
+ inst->inst_name, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "Backend '%s' is already in the middle of "
+ "another task and cannot be disturbed.\n",
+ inst->inst_name);
+ }
+
+ /* painfully, we have to clear the BUSY flags on the
+ * backends we'd already marked...
+ */
+ for (inst_obj2 = objset_first_obj(li->li_instance_set);
+ inst_obj2 && (inst_obj2 != inst_obj);
+ inst_obj2 = objset_next_obj(li->li_instance_set,
+ inst_obj2)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj2);
+ instance_set_not_busy(inst);
+ }
+ object_release(inst_obj2);
+ object_release(inst_obj);
+ return -1;
+ }
+ }
+ }
+
+ if ( !directory || !*directory ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "db2archive: no archive name\n",
+ 0, 0, 0 );
+ return( -1 );
+ }
+ if (0 != MKDIR(directory,SLAPD_DEFAULT_DIR_MODE) && EEXIST != errno) {
+ char *msg = dblayer_strerror(errno);
+
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "db2archive: mkdir(%s) failed; errno %i (%s)\n",
+ directory, errno, msg ? msg : "unknown");
+ if (task) {
+ slapi_task_log_notice(task,
+ "mkdir(%s) failed; errno %i (%s)",
+ directory, errno, msg ? msg : "unknown");
+ }
+ }
+
+ /* start the database code up, do not attempt to perform recovery */
+ if (run_from_cmdline &&
+ 0 != dblayer_start(li,DBLAYER_ARCHIVE_MODE|DBLAYER_CMDLINE_MODE)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "db2archive: Failed to init database\n",
+ 0, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task, "Failed to init database");
+ }
+ return( -1 );
+ }
+
+ /* tell it to archive */
+ return_value = dblayer_backup(li, directory, task);
+
+ /* close the database down again */
+ if (run_from_cmdline &&
+ 0 != dblayer_close(li,DBLAYER_ARCHIVE_MODE|DBLAYER_CMDLINE_MODE)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "db2archive: Failed to close database\n",
+ 0, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task, "Failed to close database");
+ }
+
+ /* The backup succeeded, so a failed close is not really a
+ total error... */
+ /*return( -1 );*/
+ }
+
+ if (! run_from_cmdline) {
+ ldbm_instance *inst;
+ Object *inst_obj;
+
+ /* none of these backends are busy anymore */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ instance_set_not_busy(inst);
+ }
+ }
+
+ return return_value;
+}
diff --git a/ldap/servers/slapd/back-ldbm/attrcrypt.h b/ldap/servers/slapd/back-ldbm/attrcrypt.h
new file mode 100644
index 00000000..b6ba50fb
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/attrcrypt.h
@@ -0,0 +1,33 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Portions copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Private tructures and #defines used in the attribute encryption code. */
+
+#ifndef _ATTRCRYPT_H_
+#define _ATTRCRYPT_H_
+
+/* structure which holds our stuff in the attrinfo objects */
+struct attrcrypt_private
+{
+ int attrcrypt_cipher;
+};
+
+typedef struct _attrcrypt_cipher_entry
+{
+ int cipher_number;
+ char *cipher_display_name;
+ CK_MECHANISM_TYPE cipher_mechanism;
+ CK_MECHANISM_TYPE wrap_mechanism;
+ CK_MECHANISM_TYPE key_gen_mechanism;
+ int key_size;
+ int iv_length;
+} attrcrypt_cipher_entry;
+
+extern attrcrypt_cipher_entry attrcrypt_cipher_list[];
+
+/* The ciphers we support (used in attrcrypt_cipher above) */
+#define ATTRCRYPT_CIPHER_AES 1
+#define ATTRCRYPT_CIPHER_DES3 2
+
+#endif /* _ATTRCRYPT_H_ */
diff --git a/ldap/servers/slapd/back-ldbm/back-ldbm.h b/ldap/servers/slapd/back-ldbm/back-ldbm.h
new file mode 100644
index 00000000..efe24ed7
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/back-ldbm.h
@@ -0,0 +1,629 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* back-ldbm.h - ldap ldbm back-end header file */
+
+#ifndef _BACK_LDBM_H_
+#define _BACK_LDBM_H_
+
+#define SLAPD_LOGGING 1
+
+#if defined(irix) || defined(AIX) || defined(HPUX11) || defined(OS_solaris) || defined(linux)
+/* built-in 64-bit file I/O support */
+#define DB_USE_64LFS
+#endif
+
+/* needed by at least HPUX and Solaris, to define off64_t */
+#ifdef DB_USE_64LFS
+#define _LARGEFILE64_SOURCE
+#endif
+
+/* A bunch of random system headers taken from all the source files, no source file should #include
+ any system headers now */
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <stdlib.h>
+#include "prio.h" /* for PR_OpenDir etc */
+#include "prlog.h" /* for PR_ASSERT */
+/* The following cruft is for ldif2db only */
+#ifndef XP_WIN32
+#include <unistd.h> /* write/close (ldbm2ldif_write) */
+#else
+#include <io.h> /* write/close (ldbm2ldif_write) */
+#endif
+#include <fcntl.h>
+#include <time.h>
+/* And this cruft is from nextid.c */
+#ifndef _WIN32
+#include <sys/param.h>
+#endif /* ! _WIN32 */
+#include <limits.h> /* Used in search.c (why?) */
+
+
+
+#ifndef _WIN32
+/* for MAXPATHLEN */
+#include <sys/param.h>
+#define MKDIR(path,mode) mkdir((path),(mode))
+#else
+/* for mkdir */
+#include <direct.h>
+#define MKDIR(path,mode) mkdir(path)
+#endif
+
+#ifdef HPUX11
+#define __BIT_TYPES_DEFINED__
+typedef unsigned char u_int8_t;
+typedef unsigned int u_int32_t;
+typedef unsigned short u_int16_t;
+#endif
+#include "db.h"
+
+#define dptr data
+#define dsize size
+
+#define ID2ENTRY "id2entry" /* main db file name: ID2ENTRY+LDBM_SUFFIX */
+
+#define LDBM_SUFFIX_OLD ".db3"
+#define LDBM_SUFFIX ".db4"
+
+#define MEGABYTE (1024 * 1024)
+#define GIGABYTE (1024 * MEGABYTE)
+
+
+/* include NSPR header files */
+#include "nspr.h"
+#include "plhash.h"
+
+#include "slap.h"
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+#include "avl.h"
+#include "ldaplog.h"
+#include "portable.h"
+#include "proto-slap.h"
+
+/* We should only change the LDBM_VERSION when the format of the db files
+ * is changing in some (possibly incompatible) way -- so we can detect and
+ * treat older ldbm versions. Thus, f.e., DS4.1 will still use the same
+ * LDBM_VERSION as 4.0 and so on...
+ * Don't make the length of LDBM_VERSION longer than LDBM_VERSION_MAXBUF - 1
+ */
+#define LDBM_VERSION_MAXBUF 64
+#define LDBM_DATABASE_TYPE_NAME "ldbm database"
+/*
+ * While we support both new and old idl index,
+ * we distinguish them by the following 2 macros.
+ * When we drop the old idl code, we eliminate LDBM_VERSION_OLD.
+ * bug #604922
+ */
+/* To set new idl default, uncomment it. */
+#define USE_NEW_IDL 1
+
+#define LDBM_VERSION_BASE "Netscape-ldbm/"
+#define LDBM_VERSION "Netscape-ldbm/7.0" /* db42: new idl -> old */
+#define LDBM_VERSION_NEW "Netscape-ldbm/7.0_NEW" /* db42: new idl */
+ /* used only when
+ * USE_NEW_IDL is
+ * NOT defined
+ */
+#define LDBM_VERSION_OLD "Netscape-ldbm/7.0_CLASSIC" /* db42: old idl */
+ /* used only when
+ * USE_NEW_IDL is
+ * defined
+ */
+#define LDBM_VERSION_62 "Netscape-ldbm/6.2" /* db33: new idl */
+#define LDBM_VERSION_61 "Netscape-ldbm/6.1" /* db33: new idl */
+#define LDBM_VERSION_60 "Netscape-ldbm/6.0" /* db33: old idl */
+
+#define LDBM_VERSION_50 "Netscape-ldbm/5.0"
+#define LDBM_VERSION_40 "Netscape-ldbm/4.0"
+#define LDBM_VERSION_30 "Netscape-ldbm/3.0"
+#define LDBM_VERSION_31 "Netscape-ldbm/3.1"
+#define LDBM_FILENAME_SUFFIX ".db4"
+#define DBVERSION_FILENAME "DBVERSION"
+#define DEFAULT_CACHE_SIZE (size_t)10485760
+#define DEFAULT_CACHE_ENTRIES -1 /* no limit */
+#define DEFAULT_DBCACHE_SIZE 1000000
+#define DEFAULT_MODE 0600
+#define DEFAULT_ALLIDSTHRESHOLD 4000
+#define DEFAULT_LOOKTHROUGHLIMIT 5000
+#define DEFAULT_IDL_TUNE 1
+#define DEFAULT_SEARCH_TUNE 0
+#define DEFAULT_IMPORT_INDEX_BUFFER_SIZE 0
+#define SUBLEN 3
+#define LDBM_CACHE_RETRY_COUNT 1000 /* Number of times we re-try a cache operation */
+#define IDL_FETCH_RETRY_COUNT 5 /* Number of times we re-try idl_fetch if it returns deadlock */
+#define IMPORT_SUBCOUNT_HASHTABLE_SIZE 500 /* Number of buckets in hash used to accumulate subcount for broody parents */
+
+/* minimum max ids that a single index entry can map to in ldbm */
+#define SLAPD_LDBM_MIN_MAXIDS 4000
+
+/* clear the following flag to suppress "database files do not exist" warning */
+extern int ldbm_warn_if_no_db;
+
+/*
+ * there is a single index for each attribute. these prefixes insure
+ * that there is no collision among keys.
+ */
+#define EQ_PREFIX '=' /* prefix for equality keys */
+#define APPROX_PREFIX '~' /* prefix for approx keys */
+#define SUB_PREFIX '*' /* prefix for substring keys */
+#define CONT_PREFIX '\\' /* prefix for continuation keys */
+#define RULE_PREFIX ':' /* prefix for matchingRule keys */
+#define PRES_PREFIX '+'
+
+/* Values for "disposition" value in idl_insert_key() */
+#define IDL_INSERT_NORMAL 1
+#define IDL_INSERT_ALLIDS 2
+#define IDL_INSERT_NOW_ALLIDS 3
+
+#define DEFAULT_BLOCKSIZE 8192
+
+/*
+ * The candidate list size at which it is cheaper to apply the filter test
+ * to the whole list than to continue ANDing in IDLs.
+ */
+#define FILTER_TEST_THRESHOLD (NIDS)10
+
+/* flags to indicate what kind of startup the dblayer should do */
+#define DBLAYER_IMPORT_MODE 0x1
+#define DBLAYER_NORMAL_MODE 0x2
+#define DBLAYER_EXPORT_MODE 0x4
+#define DBLAYER_ARCHIVE_MODE 0x8
+#define DBLAYER_RESTORE_MODE 0x10
+#define DBLAYER_RESTORE_NO_RECOVERY_MODE 0x20
+#define DBLAYER_TEST_MODE 0x40
+#define DBLAYER_INDEX_MODE 0x80
+#define DBLAYER_CLEAN_RECOVER_MODE 0x100
+
+#define DBLAYER_CMDLINE_MODE 0x1000
+
+#define DBLAYER_RESTORE_MASK (DBLAYER_RESTORE_MODE|DBLAYER_RESTORE_NO_RECOVERY_MODE)
+
+
+/*
+ * the id used in the indexes to refer to an entry
+ */
+typedef u_int32_t ID;
+#define MAXID ((ID)-3)
+#define NOID ((ID)-2)
+#define ALLID ((ID)-1)
+
+/*
+ * effective only on idl_new_fetch
+ */
+#define NEW_IDL_NOOP 1 /* no need to fetch on new idl */
+#define NEW_IDL_NO_ALLID 2 /* force to return full idl (no allids) */
+#define NEW_IDL_DEFAULT 0
+
+/*
+ * if the id of any backend instance is above the threshold, then warning
+ * message will be logged about the need of rebuilding the database in question
+ */
+#define ID_WARNING_THRESHOLD (MAXID * 0.9)
+
+/*
+ * Use this to count and index into an array of ID.
+ */
+typedef u_int32_t NIDS;
+
+/*
+ * This structure represents an id block on disk and an id list
+ * in core.
+ *
+ * The fields have the following meanings:
+ *
+ * b_nmax maximum number of ids in this block. if this is == ALLIDSBLOCK,
+ * then this block represents all ids.
+ * b_nids current number of ids in use in this block. if this
+ * is == INDBLOCK, then this block is an indirect block
+ * containing a list of other blocks containing actual ids.
+ * the list is terminated by an id of NOID.
+ * b_ids a list of the actual ids themselves
+ */
+typedef struct block {
+ NIDS b_nmax; /* max number of ids in this list */
+#define ALLIDSBLOCK 0 /* == 0 => this is an allid block */
+ NIDS b_nids; /* current number of ids used */
+#define INDBLOCK 0 /* == 0 => this is an indirect blk */
+ ID b_ids[1]; /* the ids - actually bigger */
+} Block, IDList;
+
+#define ALLIDS( idl ) ((idl)->b_nmax == ALLIDSBLOCK)
+#define INDIRECT_BLOCK( idl ) ((idl)->b_nids == INDBLOCK)
+#define IDL_NIDS(idl) (idl ? (idl)->b_nids : (NIDS)0)
+
+typedef size_t idl_iterator;
+
+/* small hashtable implementation used in the entry cache -- the table
+ * stores little identical structs, and relies on using a (void *) inside
+ * the struct to store linkage information.
+ */
+typedef int (*HashTestFn)(const void *, const void *);
+typedef unsigned long (*HashFn)(const void *, size_t);
+typedef struct {
+ u_long offset; /* offset of linkage info in user struct */
+ u_long size; /* members in array below */
+ HashFn hashfn; /* compute a hash value on a key */
+ HashTestFn testfn; /* function to test if two entries are equal */
+ void * slot[1]; /* actually much bigger */
+} Hashtable;
+
+/* use this macro to find the offset of the linkage info into your structure
+ * (required for hashtable to work correctly)
+ * HASHLOC(struct mything, linkptr)
+ */
+#define HASHLOC(mem, node) (u_long)&(((mem *)0L)->node)
+
+struct backentry {
+ Slapi_Entry *ep_entry; /* real entry */
+ Slapi_Entry *ep_vlventry;
+ ID ep_id; /* entry id */
+ char ep_state; /* state in the cache */
+#define ENTRY_STATE_DELETED 0x1 /* entry is marked as deleted */
+#define ENTRY_STATE_CREATING 0x2 /* entry is being created; don't touch it */
+#define ENTRY_STATE_NOTINCACHE 0x4 /* cache_add failed; not in the cache */
+ int ep_refcnt; /* entry reference cnt */
+ void * ep_dn_link; /* linkage for the 3 hash */
+ void * ep_id_link; /* tables used for */
+ void * ep_uuid_link; /* looking up entries */
+ struct backentry *ep_lrunext; /* for the cache */
+ struct backentry *ep_lruprev; /* for the cache */
+ PRLock *ep_mutexp; /* protection for mods */
+ size_t size; /* for cache tracking */
+};
+
+/* for the in-core cache of entries */
+struct cache {
+ size_t c_maxsize; /* max size in bytes */
+ size_t c_cursize; /* size in bytes */
+ long c_maxentries; /* max entries allowed (-1: no limit) */
+ long c_curentries; /* current # entries in cache */
+ Hashtable *c_dntable;
+ Hashtable *c_idtable;
+#ifdef UUIDCACHE_ON
+ Hashtable *c_uuidtable;
+#endif
+ u_long c_hits; /* for analysis of hits/misses */
+ u_long c_tries;
+ struct backentry *c_lruhead; /* add entries here */
+ struct backentry *c_lrutail; /* remove entries here */
+ PRLock *c_mutex; /* lock for cache operations */
+ PRLock *c_emutexalloc_mutex;
+};
+
+/* various modules keep private data inside the attrinfo structure */
+typedef struct dblayer_private dblayer_private;
+typedef struct dblayer_private_env dblayer_private_env;
+typedef struct idl_private idl_private;
+typedef struct attrcrypt_private attrcrypt_private;
+
+
+/* for the cache of attribute information (which are indexed, etc.) */
+struct attrinfo {
+ char *ai_type; /* type name (cn, sn, ...) */
+ int ai_indexmask; /* how the attr is indexed */
+#define INDEX_PRESENCE 0x01
+#define INDEX_EQUALITY 0x02
+#define INDEX_APPROX 0x04
+#define INDEX_SUB 0x08
+#define INDEX_UNKNOWN 0x10
+#define INDEX_FROMINIT 0x20
+#define INDEX_RULES 0x40
+#define INDEX_VLV 0x80
+#define INDEX_ANY (INDEX_PRESENCE | INDEX_EQUALITY | INDEX_APPROX | INDEX_SUB | INDEX_RULES | INDEX_VLV)
+
+#define INDEX_OFFLINE 0x1000 /* index is being generated, or
+ * has been created but not indexed
+ * yet. */
+
+#define IS_INDEXED( a ) ( a & INDEX_ANY )
+ void *ai_plugin;
+ char **ai_index_rules; /* matching rule OIDs */
+ void *ai_dblayer; /* private data used by the dblayer code */
+ PRInt32 ai_dblayer_count; /* used by the dblayer code */
+ idl_private *ai_idl; /* private data used by the IDL code (eg locking the IDLs) */
+ attrcrypt_private *ai_attrcrypt; /* private data used by the attribute encryption code (eg is it enabled or not) */
+};
+
+#define MAXDBCACHE 20
+
+struct id_array {
+ int ida_next_index; /*The next index that is free*/
+ int ida_size; /*The size of this puppy*/
+ ID *ida_ids; /*The array of ids*/
+
+};
+typedef struct id_array Id_Array;
+
+struct _db_upgrade_info {
+ char* old_version_string;
+ int type;
+ int action;
+};
+typedef struct _db_upgrade_info db_upgrade_info;
+/* Values for dbversion_stuff->type */
+#define DBVERSION_COMPATIBLE 0x10
+#define DBVERSION_UPGRADABLE 0x20
+#define DBVERSION_SOL 0x40
+#define DBVERSION_OLD_IDL 0x1
+#define DBVERSION_NEW_IDL 0x2
+
+/* Values for dbversion_stuff->action + return value */
+#define DBVERSION_NO_UPGRADE 0x0
+#define DBVERSION_NEED_IDL_OLD2NEW 0x100
+#define DBVERSION_NEED_IDL_NEW2OLD 0x200
+#define DBVERSION_UPGRADE_3_4 0x400
+#define DBVERSION_NOT_SUPPORTED 0x800
+
+#define DBVERSION_TYPE 0x1
+#define DBVERSION_ACTION 0x2
+
+struct ldbminfo {
+ int li_mode;
+ int li_lookthroughlimit;
+ int li_allidsthreshold;
+ char *li_directory;
+ int li_reslimit_lookthrough_handle;
+ size_t li_dbcachesize;
+ int li_dbncache;
+ int li_import_cache_autosize; /* % of free memory to use
+ * for the import caches
+ * (-1=default, 80% on cmd import)
+ * (0 = off) -- overrides
+ * import cache size settings */
+ int li_cache_autosize; /* % of free memory to use
+ * for the combined caches
+ * (0 = off) -- overrides
+ * other cache size settings */
+ int li_cache_autosize_split; /* % of li_cache_autosize to
+ * use for the libdb cache.
+ * the rest is split up among
+ * the instance entry caches */
+ unsigned long li_cache_autosize_ec; /* new instances created while
+ * the server is up, should
+ * use this as the entry cache
+ * size (0 = autosize off) */
+ size_t li_import_cachesize; /* size of the mpool for
+ * imports */
+ PRLock *li_dbcache_mutex;
+ PRCondVar *li_dbcache_cv;
+ int li_shutdown; /* flag to tell any BE threads
+ * to end */
+ PRLock *li_shutdown_mutex; /* protect shutdown flag */
+ dblayer_private *li_dblayer_private; /* session ptr for databases */
+ int li_noparentcheck; /* check if parent exists on
+ * add */
+
+ /* the next 2 fields are for the params that don't get changed until
+ * the server is restarted (used by the admin console)
+ */
+ char *li_new_directory;
+ size_t li_new_dbcachesize;
+
+ int li_new_dbncache;
+
+ db_upgrade_info *upgrade_info;
+ int li_filter_bypass; /* bypass filter testing,
+ * when possible */
+ int li_filter_bypass_check; /* check that filter bypass
+ * is doing the right thing */
+ int li_use_vlv; /* use vlv indexes to short-
+ * circuit matches when
+ * possible */
+ void *li_identity; /* The ldbm plugin needs to keep
+ * track of its identity so it can
+ * perform internal ops. Its
+ * identity is given to it when
+ * its init function is called. */
+
+ Objset *li_instance_set; /* A set containing the ldbm
+ * instances. */
+
+ PRLock *li_config_mutex;
+
+ /* There are times when we need a pointer to the ldbm database
+ * plugin, so we will store a pointer to it here. Examples of
+ * when we need it are when we create a new instance and when
+ * we need the name of the plugin to do internal ops. */
+ struct slapdplugin *li_plugin;
+
+ /* factory extension markers for the Connection struct -- bulk import
+ * uses this to store state info on a Connection.
+ */
+ int li_bulk_import_object;
+ int li_bulk_import_handle;
+ /* maximum number of pass before merging the files during an import */
+ int li_maxpassbeforemerge;
+
+ /* charray of attributes to exclude from LDIF export */
+ char **li_attrs_to_exclude_from_export;
+
+ int li_flags;
+ int li_fat_lock; /* 608146 -- make this configurable, first */
+ int li_legacy_errcode; /* 615428 -- in case legacy err code is expected */
+};
+
+/* li_flags could store these bits defined in ../slap.h
+ * task flag (pb_task_flags) *
+ * #define TASK_RUNNING_AS_TASK 0x0
+ * #define TASK_RUNNING_FROM_COMMANDLINE 0x1
+ */
+/* allow conf w/o CONFIG_FLAG_ALLOW_RUNNING_CHANGE to be updated */
+#define LI_FORCE_MOD_CONFIG 0x10
+
+/* Structure used to hold stuff for the lifetime of an LDAP transaction */
+/* If we do clever stuff like LDAP transactions, we'll need a stack of TXN ID's */
+typedef struct back_txn back_txn;
+struct back_txn {
+ DB_TXN *back_txn_txn; /* Transaction ID for the database */
+};
+typedef void * back_txnid;
+
+#define RETRY_TIMES 50
+
+/* Structure used to communicate information about subordinatecount on import/upgrade */
+struct _import_subcount_stuff {
+ PLHashTable *hashtable;
+};
+typedef struct _import_subcount_stuff import_subcount_stuff;
+
+/* Handy structures for modify operations */
+
+struct _modify_context {
+ int new_entry_in_cache;
+ struct backentry *old_entry;
+ struct backentry *new_entry;
+ Slapi_Mods *smods;
+};
+typedef struct _modify_context modify_context;
+
+#define INSTANCE_DB_SUFFIX "-db"
+#define INSTANCE_CHANGELOG_SUFFIX "-changelog"
+
+
+/* This structure was moved here from dblayer.c because the ldbm_instance
+ * structure uses the dblayer_handle structure. */
+struct tag_dblayer_handle; typedef struct tag_dblayer_handle dblayer_handle;
+struct tag_dblayer_handle
+{
+ DB* dblayer_dbp;
+ PRLock *dblayer_lock; /* used when anyone wants exclusive access to a file */
+ dblayer_handle *dblayer_handle_next;
+ void **dblayer_handle_ai_backpointer; /* Voodo magic pointer to the place where we store a
+ pointer to this handle in the attrinfo structure */
+};
+
+/* This structure was moved here from perfctrs.c so the ldbm_instance structure
+ * could use it. */
+struct _perfctrs_private {
+#if defined(_WIN32)
+ /* Handle to the shared memory object */
+ HANDLE hMemory;
+ /* Handle to the update event */
+ HANDLE hEvent;
+#else
+ /* Nothing yet */
+#endif
+ /* Pointer to the shared memory */
+ void *memory;
+};
+typedef struct _perfctrs_private perfctrs_private;
+
+typedef struct _attrcrypt_state_private attrcrypt_state_private;
+
+/* flags for ldbm_instance */
+/* please lock inst_config_mutex before changing inst_flags */
+#define INST_FLAG_BUSY 0x0001 /* instance is doing an import or
+ * restore. */
+#define INST_FLAG_READONLY 0x0002 /* instance is truly readonly */
+
+/* Structure used to hold instance specific information. */
+typedef struct ldbm_instance {
+ char *inst_name; /* Name given for this instance. */
+ backend *inst_be; /* pointer back to the backend */
+ struct ldbminfo *inst_li; /* pointer back to global info */
+ int inst_flags; /* see above */
+
+ PRLock *inst_config_mutex;
+
+ PRInt32 *inst_ref_count; /* Keeps track of how many operations
+ * are currently using this instance */
+
+ char *inst_dir_name; /* The name of the directory in the db
+ * directory that holds the index files
+ * for this instance. Relative to the
+ * parent of the instance name dir */
+ char *inst_parent_dir_name; /* Absolute parent dir for this inst */
+
+ PRLock *inst_db_mutex; /* Used to synchronize modify operations
+ * on this instance. */
+
+ dblayer_handle *inst_handle_head; /* These are used to maintain a list */
+ dblayer_handle *inst_handle_tail; /* of open db handles for this instance */
+ PRLock *inst_handle_list_mutex;
+
+ DB *inst_id2entry; /* id2entry for this instance. */
+
+ perfctrs_private inst_perf_private; /* Private data for the performace
+ * counters specific to this instance */
+ attrcrypt_state_private *inst_attrcrypt_state_private;
+ int attrcrypt_configured; /* Are any attributes configured for encryption ? */
+
+ Avlnode *inst_attrs; /* Keeps track of what's indexed for
+ * this instance. */
+
+ struct cache inst_cache; /* The entry cache for this instance. */
+
+ PRLock *inst_nextid_mutex;
+ ID inst_nextid;
+
+ PRCondVar *inst_indexer_cv; /* indexer thread cond var */
+ PRThread *inst_indexer_tid; /* for the indexer thread */
+
+ long inst_cache_hits; /* used during imports to figure out when
+ * a pass should end. */
+ long inst_cache_misses;
+
+ char *inst_dataversion; /* The user data version tag. Used by
+ * replication. */
+ dblayer_private_env *import_env; /* use a different DB_ENV for imports */
+ int require_index; /* set to 1 to require an index be used
+ * in search */
+} ldbm_instance;
+
+/*
+ * This structure is passed through the PBlock from ldbm_back_search to
+ * ldbm_back_next_search_entry. It contains the candidate result set
+ * determined by ldbm_back_search, to be served up by ldbm_back_next_search_entry.
+ */
+typedef struct _back_search_result_set
+{
+ IDList* sr_candidates; /* the search results */
+ idl_iterator sr_current; /* the current position in the search results */
+ struct backentry* sr_entry; /* the last entry returned */
+ int sr_lookthroughcount; /* how many have we examined? */
+ int sr_lookthroughlimit; /* how many can we examine? */
+ int sr_virtuallistview; /* is this a VLV Search */
+ Slapi_Entry* sr_vlventry; /* a special VLV Entry for when the ACL check fails */
+ int sr_flags; /* Magic flags, defined below */
+} back_search_result_set;
+#define SR_FLAG_CAN_SKIP_FILTER_TEST 1 /* If set in sr_flags, means that we can safely skip the filter test */
+
+#include "proto-back-ldbm.h"
+#include "ldbm_config.h"
+
+/* flags used when adding/removing index items */
+#define BE_INDEX_ADD 1
+#define BE_INDEX_DEL 2
+#define BE_INDEX_PRESENCE 4 /* (w/DEL) remove the presence index */
+#define BE_INDEX_TOMBSTONE 8 /* Index entry as a tombstone */
+#define BE_INDEX_DONT_ENCRYPT 16 /* Disable any encryption if this flag is set */
+
+/* Name of attribute type used for binder-based look through limit */
+#define LDBM_LOOKTHROUGHLIMIT_AT "nsLookThroughLimit"
+
+/* OIDs for attribute types used internally */
+#define LDBM_ENTRYDN_OID "2.16.840.1.113730.3.1.602"
+#define LDBM_DNCOMP_OID "2.16.840.1.113730.3.1.603"
+#define LDBM_PARENTID_OID "2.16.840.1.113730.3.1.604"
+#define LDBM_ENTRYID_OID "2.16.840.1.113730.3.1.605"
+
+/* Name of psuedo attribute used to track default indexes */
+#define LDBM_PSEUDO_ATTR_DEFAULT ".default"
+
+/* for checking disk full errors. */
+#define LDBM_OS_ERR_IS_DISKFULL( err ) ((err)==ENOSPC || (err)==EFBIG)
+
+/* flag: open_flag for dblayer_get_index_file -> dblayer_open_file */
+#define DBOPEN_CREATE 0x1 /* oprinary mode: create a db file if needed */
+
+/* whether we call fat lock or not [608146] */
+#define SERIALLOCK(li) (li->li_fat_lock)
+#endif /* _back_ldbm_h_ */
diff --git a/ldap/servers/slapd/back-ldbm/backentry.c b/ldap/servers/slapd/back-ldbm/backentry.c
new file mode 100644
index 00000000..f38953d8
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/backentry.c
@@ -0,0 +1,89 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* backentry.c - wrapper routines to deal with entries */
+
+#include "back-ldbm.h"
+
+void
+backentry_free( struct backentry **bep )
+{
+ struct backentry *ep;
+ if ( NULL == bep || NULL == *bep ) {
+ return;
+ }
+ ep = *bep;
+ if ( ep->ep_entry != NULL ) {
+ slapi_entry_free( ep->ep_entry );
+ }
+ if ( ep->ep_mutexp != NULL ) {
+ PR_DestroyLock( ep->ep_mutexp );
+ }
+ slapi_ch_free( (void**)&ep );
+ *bep = NULL;
+}
+
+struct backentry *
+backentry_alloc()
+{
+ struct backentry *ec;
+ ec = (struct backentry *) slapi_ch_calloc( 1, sizeof(struct backentry) ) ;
+ ec->ep_state = ENTRY_STATE_NOTINCACHE;
+#ifdef LDAP_CACHE_DEBUG
+ ec->debug_sig = 0x45454545;
+#endif
+ return ec;
+}
+
+void backentry_clear_entry( struct backentry *ep )
+{
+ if (ep)
+ {
+ ep->ep_entry = NULL;
+ }
+}
+
+struct backentry *
+backentry_init( Slapi_Entry *e )
+{
+ struct backentry *ep;
+
+ ep = (struct backentry *) slapi_ch_calloc( 1, sizeof(struct backentry) );
+ ep->ep_entry= e;
+ ep->ep_state = ENTRY_STATE_NOTINCACHE;
+#ifdef LDAP_CACHE_DEBUG
+ ep->debug_sig = 0x23232323;
+#endif
+
+ return( ep );
+}
+
+struct backentry *
+backentry_dup( struct backentry *e )
+{
+ struct backentry *ec;
+
+ ec = (struct backentry *) slapi_ch_calloc( 1, sizeof(struct backentry) );
+ ec->ep_id = e->ep_id;
+ ec->ep_entry = slapi_entry_dup( e->ep_entry );
+ ec->ep_state = ENTRY_STATE_NOTINCACHE;
+#ifdef LDAP_CACHE_DEBUG
+ ec->debug_sig = 0x12121212;
+#endif
+
+ return( ec );
+}
+
+char *
+backentry_get_ndn(const struct backentry *e)
+{
+ return (char *)slapi_sdn_get_ndn(slapi_entry_get_sdn_const(e->ep_entry));
+}
+
+const Slapi_DN *
+backentry_get_sdn(const struct backentry *e)
+{
+ return slapi_entry_get_sdn_const(e->ep_entry);
+}
diff --git a/ldap/servers/slapd/back-ldbm/cache.c b/ldap/servers/slapd/back-ldbm/cache.c
new file mode 100644
index 00000000..e55bddb2
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/cache.c
@@ -0,0 +1,1195 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cache.c - routines to maintain an in-core cache of entries */
+
+#include "back-ldbm.h"
+
+#ifdef DEBUG
+#define LDAP_CACHE_DEBUG
+/* #define LDAP_CACHE_DEBUG_LRU */ /* causes slowdown */
+#endif
+
+/* cache can't get any smaller than this (in bytes) */
+#define MINCACHESIZE (size_t)200000
+
+/* don't let hash be smaller than this # of slots */
+#define MINHASHSIZE 1024
+
+/*
+ * the cache has three entry points (ways to find things):
+ *
+ * by entry e.g., if you already have an entry from the cache
+ * and want to delete it. (really by entry ptr)
+ * by dn e.g., when looking for the base object of a search
+ * by id e.g., for search candidates
+ * by uniqueid
+ *
+ * these correspond to three different avl trees that are maintained.
+ * those avl trees are being destroyed as we speak.
+ */
+
+#ifdef LDAP_CACHE_DEBUG
+#define ASSERT(_x) do { \
+ if (!(_x)) { \
+ LDAPDebug(LDAP_DEBUG_ANY, "BAD CACHE ASSERTION at %s/%d: %s\n", \
+ __FILE__, __LINE__, #_x); \
+ *(char *)0L = 23; \
+ } \
+} while (0)
+#define LOG(_a, _x1, _x2, _x3) LDAPDebug(LDAP_DEBUG_CACHE, _a, _x1, _x2, _x3)
+#else
+#define ASSERT(_x) ;
+#define LOG(_a, _x1, _x2, _x3) ;
+#endif
+
+
+/***** tiny hashtable implementation *****/
+
+#define HASH_VALUE(_key, _keylen) \
+ ((ht->hashfn == NULL) ? (*(unsigned int *)(_key)) : \
+ ((*ht->hashfn)(_key, _keylen)))
+#define HASH_NEXT(ht, entry) (*(void **)((char *)(entry) + (ht)->offset))
+
+static int entry_same_id(const void *e, const void *k)
+{
+ return (((struct backentry *)e)->ep_id == *(ID *)k);
+}
+
+static unsigned long dn_hash(const void *key, size_t keylen)
+{
+ unsigned char *x = (unsigned char *)key;
+ ssize_t i;
+ unsigned long val = 0;
+
+ for (i = keylen-1; i >= 0; i--)
+ val += ((val << 5) + (*x++)) & 0xffffffff;
+ return val;
+}
+
+#ifdef UUIDCACHE_ON
+static unsigned long uuid_hash(const void *key, size_t keylen)
+{
+ unsigned char *x = (unsigned char *)key;
+ size_t i;
+ unsigned long val = 0;
+
+ for (i = 0; i < keylen; i++, x++) {
+ char c = (*x <= '9' ? (*x - '0') : (*x - 'A' + 10));
+ val = ((val << 4) ^ (val >> 28) ^ c) & 0xffffffff;
+ }
+ return val;
+}
+
+static int entry_same_uuid(const void *e, const void *k)
+{
+ struct backentry *be = (struct backentry *)e;
+ const char *uuid = slapi_entry_get_uniqueid(be->ep_entry);
+
+ return (strcmp(uuid, (char *)k) == 0);
+}
+#endif
+
+static int entry_same_dn(const void *e, const void *k)
+{
+ struct backentry *be = (struct backentry *)e;
+ const char *ndn = slapi_sdn_get_ndn(backentry_get_sdn(be));
+
+ return (strcmp(ndn, (char *)k) == 0);
+}
+
+Hashtable *new_hash(u_long size, u_long offset, HashFn hfn,
+ HashTestFn tfn)
+{
+ static u_long prime[] = { 3, 5, 7, 11, 13, 17, 19 };
+ Hashtable *ht;
+ int ok = 0, i;
+
+ if (size < MINHASHSIZE)
+ size = MINHASHSIZE;
+ /* move up to nearest relative prime (it's a statistical thing) */
+ size |= 1;
+ do {
+ ok = 1;
+ for (i = 0; i < (sizeof(prime) / sizeof(prime[0])); i++)
+ if (!(size % prime[i]))
+ ok = 0;
+ if (!ok)
+ size += 2;
+ } while (!ok);
+
+ ht = (Hashtable*)slapi_ch_calloc(1, sizeof(Hashtable) + size*sizeof(void *));
+ if (!ht)
+ return NULL;
+ ht->size = size;
+ ht->offset = offset;
+ ht->hashfn = hfn;
+ ht->testfn = tfn;
+ /* calloc zeroes out the slots automagically */
+ return ht;
+}
+
+/* adds an entry to the hash -- returns 1 on success, 0 if the key was
+ * already there (filled into 'alt' if 'alt' is not NULL)
+ */
+int add_hash(Hashtable *ht, void *key, size_t keylen, void *entry,
+ void **alt)
+{
+ u_long val, slot;
+ void *e;
+
+ val = HASH_VALUE(key, keylen);
+ slot = (val % ht->size);
+ /* first, check if this key is already in the table */
+ e = ht->slot[slot];
+ while (e) {
+ if ((*ht->testfn)(e, key)) {
+ /* ack! already in! */
+ if (alt)
+ *alt = e;
+ return 0;
+ }
+ e = HASH_NEXT(ht, e);
+ }
+ /* ok, it's not already there, so add it */
+ HASH_NEXT(ht, entry) = ht->slot[slot];
+ ht->slot[slot] = entry;
+ return 1;
+}
+
+/* returns 1 if the item was found, and puts a ptr to it in 'entry' */
+int find_hash(Hashtable *ht, const void *key, size_t keylen, void **entry)
+{
+ u_long val, slot;
+ void *e;
+
+ val = HASH_VALUE(key, keylen);
+ slot = (val % ht->size);
+ e = ht->slot[slot];
+ while (e) {
+ if ((*ht->testfn)(e, key)) {
+ *entry = e;
+ return 1;
+ }
+ e = HASH_NEXT(ht, e);
+ }
+ /* no go */
+ *entry = NULL;
+ return 0;
+}
+
+/* returns 1 if the item was found and removed */
+int remove_hash(Hashtable *ht, const void *key, size_t keylen)
+{
+ u_long val, slot;
+ void *e, *laste = NULL;
+
+ val = HASH_VALUE(key, keylen);
+ slot = (val % ht->size);
+ e = ht->slot[slot];
+ while (e) {
+ if ((*ht->testfn)(e, key)) {
+ /* remove this one */
+ if (laste)
+ HASH_NEXT(ht, laste) = HASH_NEXT(ht, e);
+ else
+ ht->slot[slot] = HASH_NEXT(ht, e);
+ HASH_NEXT(ht, e) = NULL;
+ return 1;
+ }
+ laste = e;
+ e = HASH_NEXT(ht, e);
+ }
+ /* nope */
+ return 0;
+}
+
+/* hashtable distribution stats --
+ * slots: # of slots in the hashtable
+ * total_entries: # of entries in the hashtable
+ * max_entries_per_slot: highest number of chained entries in a single slot
+ * slot_stats: if X is the number of entries in a given slot, then
+ * slot_stats[X] will hold the number of slots that held X entries
+ */
+static void hash_stats(Hashtable *ht, u_long *slots, int *total_entries,
+ int *max_entries_per_slot, int **slot_stats)
+{
+#define MAX_SLOT_STATS 50
+ u_long i;
+ int x;
+ void *e;
+
+ *slot_stats = (int *)slapi_ch_malloc(MAX_SLOT_STATS * sizeof(int));
+ for (i = 0; i < MAX_SLOT_STATS; i++)
+ (*slot_stats)[i] = 0;
+
+ *slots = ht->size;
+ *max_entries_per_slot = 0;
+ *total_entries = 0;
+ for (i = 0; i < ht->size; i++) {
+ e = ht->slot[i];
+ x = 0;
+ while (e) {
+ x++;
+ (*total_entries)++;
+ e = HASH_NEXT(ht, e);
+ }
+ if (x < MAX_SLOT_STATS)
+ (*slot_stats)[x]++;
+ if (x > *max_entries_per_slot)
+ *max_entries_per_slot = x;
+ }
+}
+
+
+/***** add/remove entries to/from the LRU list *****/
+
+#ifdef LDAP_CACHE_DEBUG_LRU
+/* for debugging -- painstakingly verify the lru list is ok -- if 'in' is
+ * true, then entry 'e' should be in the list right now; otherwise, it
+ * should NOT be in the list.
+ */
+static void lru_verify(struct cache *cache, struct backentry *e, int in)
+{
+ int is_in = 0;
+ int count = 0;
+ struct backentry *ep;
+
+ ep = cache->c_lruhead;
+ while (ep) {
+ count++;
+ if (ep == e) {
+ is_in = 1;
+ }
+ if (ep->ep_lruprev) {
+ ASSERT(ep->ep_lruprev->ep_lrunext == ep);
+ } else {
+ ASSERT(ep == cache->c_lruhead);
+ }
+ if (ep->ep_lrunext) {
+ ASSERT(ep->ep_lrunext->ep_lruprev == ep);
+ } else {
+ ASSERT(ep == cache->c_lrutail);
+ }
+
+ ep = ep->ep_lrunext;
+ }
+ ASSERT(is_in == in);
+}
+#endif
+
+/* assume lock is held */
+static void lru_detach(struct cache *cache, struct backentry *e)
+{
+#ifdef LDAP_CACHE_DEBUG_LRU
+ lru_verify(cache, e, 1);
+#endif
+ if (e->ep_lruprev)
+ {
+ e->ep_lruprev->ep_lrunext = NULL;
+ cache->c_lrutail = e->ep_lruprev;
+ }
+ else
+ {
+ cache->c_lruhead = NULL;
+ cache->c_lrutail = NULL;
+ }
+#ifdef LDAP_CACHE_DEBUG_LRU
+ lru_verify(cache, e, 0);
+#endif
+}
+
+/* assume lock is held */
+static void lru_delete(struct cache *cache, struct backentry *e)
+{
+#ifdef LDAP_CACHE_DEBUG_LRU
+ lru_verify(cache, e, 1);
+#endif
+ if (e->ep_lruprev)
+ e->ep_lruprev->ep_lrunext = e->ep_lrunext;
+ else
+ cache->c_lruhead = e->ep_lrunext;
+ if (e->ep_lrunext)
+ e->ep_lrunext->ep_lruprev = e->ep_lruprev;
+ else
+ cache->c_lrutail = e->ep_lruprev;
+#ifdef LDAP_CACHE_DEBUG_LRU
+ e->ep_lrunext = e->ep_lruprev = NULL;
+ lru_verify(cache, e, 0);
+#endif
+}
+
+/* assume lock is held */
+static void lru_add(struct cache *cache, struct backentry *e)
+{
+#ifdef LDAP_CACHE_DEBUG_LRU
+ lru_verify(cache, e, 0);
+#endif
+ e->ep_lruprev = NULL;
+ e->ep_lrunext = cache->c_lruhead;
+ cache->c_lruhead = e;
+ if (e->ep_lrunext)
+ e->ep_lrunext->ep_lruprev = e;
+ if (! cache->c_lrutail)
+ cache->c_lrutail = e;
+#ifdef LDAP_CACHE_DEBUG_LRU
+ lru_verify(cache, e, 1);
+#endif
+}
+
+
+/***** cache overhead *****/
+
+static int cache_remove_int(struct cache *cache, struct backentry *e);
+
+static void cache_make_hashes(struct cache *cache)
+{
+ u_long hashsize = (cache->c_maxentries > 0) ? cache->c_maxentries :
+ (cache->c_maxsize/512);
+
+ cache->c_dntable = new_hash(hashsize,
+ HASHLOC(struct backentry, ep_dn_link),
+ dn_hash, entry_same_dn);
+ cache->c_idtable = new_hash(hashsize,
+ HASHLOC(struct backentry, ep_id_link),
+ NULL, entry_same_id);
+#ifdef UUIDCACHE_ON
+ cache->c_uuidtable = new_hash(hashsize,
+ HASHLOC(struct backentry, ep_uuid_link),
+ uuid_hash, entry_same_uuid);
+#endif
+}
+
+/* initialize the cache */
+int cache_init(struct cache *cache, size_t maxsize, long maxentries)
+{
+ LDAPDebug(LDAP_DEBUG_TRACE, "=> cache_init\n", 0, 0, 0);
+ cache->c_maxsize = maxsize;
+ cache->c_maxentries = maxentries;
+ cache->c_cursize = cache->c_curentries = 0;
+ cache->c_hits = cache->c_tries = 0;
+ cache->c_lruhead = cache->c_lrutail = NULL;
+ cache_make_hashes(cache);
+
+ if (((cache->c_mutex = PR_NewLock()) == NULL) ||
+ ((cache->c_emutexalloc_mutex = PR_NewLock()) == NULL)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: cache_init: PR_NewLock failed\n",
+ 0, 0, 0);
+ return 0;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE, "<= cache_init\n", 0, 0, 0);
+ return 1;
+}
+
+#define CACHE_FULL(cache) \
+ (((cache)->c_cursize > (cache)->c_maxsize) || \
+ (((cache)->c_maxentries > 0) && \
+ ((cache)->c_curentries > cache->c_maxentries)))
+
+
+/* clear out the cache to make room for new entries
+ * you must be holding cache->c_mutex !!
+ * return a pointer on the list of entries that get kicked out
+ * of the cache.
+ * These entries should be freed outside of the cache->c_mutex
+ */
+static struct backentry * cache_flush(struct cache *cache)
+{
+ struct backentry *e = NULL;
+
+ LOG("=> cache_flush\n", 0, 0, 0);
+
+ /* all entries on the LRU list are guaranteed to have a refcnt = 0
+ * (iow, nobody's using them), so just delete from the tail down
+ * until the cache is a managable size again.
+ * (cache->c_mutex is locked when we enter this)
+ */
+ while ((cache->c_lrutail != NULL) && CACHE_FULL(cache)) {
+ if (e == NULL)
+ {
+ e = cache->c_lrutail;
+ }
+ else
+ {
+ e = e->ep_lruprev;
+ }
+ ASSERT(e->ep_refcnt == 0);
+ e->ep_refcnt++;
+ if (cache_remove_int(cache, e) < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "cache flush: unable to delete entry\n",
+ 0, 0, 0);
+ break;
+ }
+ if(e == cache->c_lruhead) {
+ break;
+ }
+ }
+ if (e)
+ lru_detach(cache, e);
+ LOG("<= cache_flush (down to %lu entries, %lu bytes)\n", cache->c_curentries,
+ cache->c_cursize, 0);
+ return e;
+}
+
+/* remove everything from the cache */
+static void cache_clear_int(struct cache *cache)
+{
+ struct backentry *eflush = NULL;
+ struct backentry *eflushtemp = NULL;
+ size_t size = cache->c_maxsize;
+
+ cache->c_maxsize = 0;
+ eflush = cache_flush(cache);
+ while (eflush)
+ {
+ eflushtemp = eflush->ep_lrunext;
+ backentry_free(&eflush);
+ eflush = eflushtemp;
+ }
+ cache->c_maxsize = size;
+ if (cache->c_curentries > 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "somehow, there are still %ld entries "
+ "in the entry cache. :/\n", cache->c_curentries, 0, 0);
+ }
+}
+
+void cache_clear(struct cache *cache)
+{
+ PR_Lock(cache->c_mutex);
+ cache_clear_int(cache);
+ PR_Unlock(cache->c_mutex);
+}
+
+static void erase_cache(struct cache *cache)
+{
+ cache_clear_int(cache);
+ slapi_ch_free((void **)&cache->c_dntable);
+ slapi_ch_free((void **)&cache->c_idtable);
+#ifdef UUIDCACHE_ON
+ slapi_ch_free((void **)&cache->c_uuidtable);
+#endif
+}
+
+/* to be used on shutdown or when destroying a backend instance */
+void cache_destroy_please(struct cache *cache)
+{
+ erase_cache(cache);
+ PR_DestroyLock(cache->c_mutex);
+ PR_DestroyLock(cache->c_emutexalloc_mutex);
+}
+
+void cache_set_max_size(struct cache *cache, size_t bytes)
+{
+ struct backentry *eflush = NULL;
+ struct backentry *eflushtemp = NULL;
+
+ if (bytes < MINCACHESIZE) {
+ bytes = MINCACHESIZE;
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "WARNING -- Minimum cache size is %lu -- rounding up\n",
+ MINCACHESIZE, 0, 0);
+ }
+ PR_Lock(cache->c_mutex);
+ cache->c_maxsize = bytes;
+ LOG("entry cache size set to %lu\n", bytes, 0, 0);
+ /* check for full cache, and clear out if necessary */
+ if (CACHE_FULL(cache))
+ eflush = cache_flush(cache);
+ while (eflush)
+ {
+ eflushtemp = eflush->ep_lrunext;
+ backentry_free(&eflush);
+ eflush = eflushtemp;
+ }
+ if (cache->c_curentries < 50) {
+ /* there's hardly anything left in the cache -- clear it out and
+ * resize the hashtables for efficiency.
+ */
+ erase_cache(cache);
+ cache_make_hashes(cache);
+ }
+ PR_Unlock(cache->c_mutex);
+ if (! dblayer_is_cachesize_sane(&bytes)) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "WARNING -- Possible CONFIGURATION ERROR -- cachesize "
+ "(%lu) may be configured to use more than the available "
+ "physical memory.\n", bytes, 0, 0);
+ }
+}
+
+void cache_set_max_entries(struct cache *cache, long entries)
+{
+ struct backentry *eflush = NULL;
+ struct backentry *eflushtemp = NULL;
+
+ /* this is a dumb remnant of pre-5.0 servers, where the cache size
+ * was given in # entries instead of memory footprint. hopefully,
+ * we can eventually drop this.
+ */
+ PR_Lock(cache->c_mutex);
+ cache->c_maxentries = entries;
+ if (entries >= 0) {
+ LOG("entry cache entry-limit set to %lu\n", entries, 0, 0);
+ } else {
+ LOG("entry cache entry-limit turned off\n", 0, 0, 0);
+ }
+
+ /* check for full cache, and clear out if necessary */
+ if (CACHE_FULL(cache))
+ eflush = cache_flush(cache);
+ PR_Unlock(cache->c_mutex);
+ while (eflush)
+ {
+ eflushtemp = eflush->ep_lrunext;
+ backentry_free(&eflush);
+ eflush = eflushtemp;
+ }
+}
+
+size_t cache_get_max_size(struct cache *cache)
+{
+ size_t n;
+
+ PR_Lock(cache->c_mutex);
+ n = cache->c_maxsize;
+ PR_Unlock(cache->c_mutex);
+ return n;
+}
+
+long cache_get_max_entries(struct cache *cache)
+{
+ long n;
+
+ PR_Lock(cache->c_mutex);
+ n = cache->c_maxentries;
+ PR_Unlock(cache->c_mutex);
+ return n;
+}
+
+/* determine the general size of a cache entry */
+static size_t cache_entry_size(struct backentry *e)
+{
+ size_t size = 0;
+
+ if (e->ep_entry)
+ size += slapi_entry_size(e->ep_entry);
+ if (e->ep_vlventry)
+ size += slapi_entry_size(e->ep_vlventry);
+ /* cannot size ep_mutexp (PRLock) */
+ size += sizeof(struct backentry);
+ return size;
+}
+
+/* the monitor code wants to be able to safely fetch the cache stats --
+ * if it ever wants to pull out more info, we might want to change all
+ * these u_long *'s to a struct
+ */
+void cache_get_stats(struct cache *cache, u_long *hits, u_long *tries,
+ long *nentries, long *maxentries,
+ size_t *size, size_t *maxsize)
+{
+ PR_Lock(cache->c_mutex);
+ if (hits) *hits = cache->c_hits;
+ if (tries) *tries = cache->c_tries;
+ if (nentries) *nentries = cache->c_curentries;
+ if (maxentries) *maxentries = cache->c_maxentries;
+ if (size) *size = cache->c_cursize;
+ if (maxsize) *maxsize = cache->c_maxsize;
+ PR_Unlock(cache->c_mutex);
+}
+
+void cache_debug_hash(struct cache *cache, char **out)
+{
+ u_long slots;
+ int total_entries, max_entries_per_slot, *slot_stats;
+ int i, j;
+ Hashtable *ht;
+ char *name;
+
+ PR_Lock(cache->c_mutex);
+ *out = (char *)slapi_ch_malloc(1024);
+ **out = 0;
+
+ for (i = 0; i < 3; i++) {
+ if (i > 0)
+ sprintf(*out + strlen(*out), "; ");
+ switch(i) {
+ case 0:
+ ht = cache->c_dntable;
+ name = "dn";
+ break;
+ case 1:
+ ht = cache->c_idtable;
+ name = "id";
+ break;
+#ifdef UUIDCACHE_ON
+ case 2:
+ default:
+ ht = cache->c_uuidtable;
+ name = "uuid";
+ break;
+#endif
+ }
+ hash_stats(ht, &slots, &total_entries, &max_entries_per_slot,
+ &slot_stats);
+ sprintf(*out + strlen(*out), "%s hash: %lu slots, %d entries (%d max "
+ "entries per slot) -- ", name, slots, total_entries,
+ max_entries_per_slot);
+ for (j = 0; j <= max_entries_per_slot; j++)
+ sprintf(*out + strlen(*out), "%d[%d] ", j, slot_stats[j]);
+ slapi_ch_free((void **)&slot_stats);
+ }
+ PR_Unlock(cache->c_mutex);
+}
+
+
+/***** general-purpose cache stuff *****/
+
+/* remove an entry from the cache */
+/* you must be holding c_mutex !! */
+static int cache_remove_int(struct cache *cache, struct backentry *e)
+{
+ int ret = 1; /* assume not in cache */
+ const char *ndn;
+#ifdef UUIDCACHE_ON
+ const char *uuid;
+#endif
+
+ LOG("=> cache_remove (%s)\n", backentry_get_ndn(e), 0, 0);
+ if (e->ep_state & ENTRY_STATE_NOTINCACHE)
+ {
+ return ret;
+ }
+
+ /* remove from all hashtables -- this function may be called from places
+ * where the entry isn't in all the tables yet, so we don't care if any
+ * of these return errors.
+ */
+ ndn = slapi_sdn_get_ndn(backentry_get_sdn(e));
+ if (remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn)))
+ {
+ ret = 0;
+ }
+ else
+ {
+ LOG("remove %s from dn hash failed\n", ndn, 0, 0);
+ }
+ if (remove_hash(cache->c_idtable, &(e->ep_id), sizeof(ID)))
+ {
+ ret = 0;
+ }
+ else
+ {
+ LOG("remove %d from id hash failed\n", e->ep_id, 0, 0);
+ }
+#ifdef UUIDCACHE_ON
+ uuid = slapi_entry_get_uniqueid(e->ep_entry);
+ if (remove_hash(cache->c_uuidtable, (void *)uuid, strlen(uuid)))
+ {
+ ret = 0;
+ }
+ else
+ {
+ LOG("remove %d from uuid hash failed\n", uuid, 0, 0);
+ }
+#endif
+ if (ret == 0) {
+ /* won't be on the LRU list since it has a refcount on it */
+ /* adjust cache size */
+ cache->c_cursize -= e->size;
+ cache->c_curentries--;
+ LOG("<= cache_remove (size %lu): cache now %lu entries, %lu bytes\n",
+ e->size, cache->c_curentries, cache->c_cursize);
+ }
+
+ /* mark for deletion (will be erased when refcount drops to zero) */
+ e->ep_state |= ENTRY_STATE_DELETED;
+ LOG("<= cache_remove: %d\n", ret, 0, 0);
+ return ret;
+}
+
+/* remove an entry from the cache.
+ * you must have a refcount on e (iow, fetched via cache_find_*). the
+ * entry is removed from the cache, but NOT freed! you are responsible
+ * for freeing the entry yourself when done with it, preferrably via
+ * cache_return (called AFTER cache_remove). some code still does this
+ * via backentry_free, which is okay, as long as you know you're the only
+ * thread holding a reference to the deleted entry.
+ * returns: 0 on success
+ * 1 if the entry wasn't in the cache at all (not even partially)
+ */
+int cache_remove(struct cache *cache, struct backentry *e)
+{
+ int ret;
+
+ PR_Lock(cache->c_mutex);
+ ASSERT(e->ep_refcnt > 0);
+ ret = cache_remove_int(cache, e);
+ PR_Unlock(cache->c_mutex);
+ return ret;
+}
+
+/* replace an entry in the cache.
+ * returns: 0 on success
+ * 1 if the entry wasn't in the cache
+ */
+int cache_replace(struct cache *cache, struct backentry *olde,
+ struct backentry *newe)
+{
+ int found;
+ const char *oldndn;
+ const char *newndn;
+#ifdef UUIDCACHE_ON
+ const char *olduuid;
+ const char *newuuid;
+#endif
+
+ LOG("=> cache_replace (%s) -> (%s)\n", backentry_get_ndn(olde),
+ backentry_get_ndn(newe), 0);
+
+ /* remove from all hashtables -- this function may be called from places
+ * where the entry isn't in all the tables yet, so we don't care if any
+ * of these return errors.
+ */
+ oldndn = slapi_sdn_get_ndn(backentry_get_sdn(olde));
+#ifdef UUIDCACHE_ON
+ olduuid = slapi_entry_get_uniqueid(olde->ep_entry);
+ newuuid = slapi_entry_get_uniqueid(newe->ep_entry);
+#endif
+ newndn = slapi_sdn_get_ndn(backentry_get_sdn(newe));
+ PR_Lock(cache->c_mutex);
+
+ /*
+ * First, remove the old entry from all the hashtables.
+ * If the old entry is in cache but not in at least one of the
+ * cache tables, operation error
+ */
+ if ( (olde->ep_state & ENTRY_STATE_NOTINCACHE) == 0 ) {
+
+ found = remove_hash(cache->c_dntable, (void *)oldndn, strlen(oldndn));
+ found &= remove_hash(cache->c_idtable, &(olde->ep_id), sizeof(ID));
+#ifdef UUIDCACHE_ON
+ found &= remove_hash(cache->c_uuidtable, (void *)olduuid, strlen(olduuid));
+#endif
+ if (!found) {
+ LOG("cache replace: cache index tables out of sync\n", 0, 0, 0);
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+ }
+ if (! entry_same_dn(newe, (void *)oldndn) &&
+ (newe->ep_state & ENTRY_STATE_NOTINCACHE) == 0) {
+ /* if we're doing a modrdn, the new entry can be in the dn table
+ * already, so we need to remove that too.
+ */
+ if (remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn)))
+ {
+ cache->c_cursize -= newe->size;
+ cache->c_curentries--;
+ LOG("cache replace remove entry size %lu\n", newe->size, 0, 0);
+ }
+ }
+
+ /* now, add the new entry to the hashtables */
+ /* (probably don't need such extensive error handling, once this has been
+ * tested enough that we believe it works.)
+ */
+ if (!add_hash(cache->c_dntable, (void *)newndn, strlen(newndn), newe, NULL)) {
+ LOG("cache replace: can't add dn\n", 0, 0, 0);
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+ if (!add_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID), newe, NULL)) {
+ LOG("cache replace: can't add id\n", 0, 0, 0);
+ remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn));
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+#ifdef UUIDCACHE_ON
+ if (newuuid && !add_hash(cache->c_uuidtable, (void *)newuuid, strlen(newuuid),
+ newe, NULL)) {
+ LOG("cache replace: can't add uuid\n", 0, 0, 0);
+ remove_hash(cache->c_dntable, (void *)newndn, strlen(newndn));
+ remove_hash(cache->c_idtable, &(newe->ep_id), sizeof(ID));
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+#endif
+ /* adjust cache meta info */
+ newe->ep_refcnt = 1;
+ newe->size = cache_entry_size(newe);
+ cache->c_cursize += (newe->size - olde->size);
+ olde->ep_state = ENTRY_STATE_DELETED;
+ newe->ep_state = 0;
+ PR_Unlock(cache->c_mutex);
+ LOG("<= cache_replace OK, cache size now %lu cache count now %ld\n",
+ cache->c_cursize, cache->c_curentries, 0);
+ return 0;
+}
+
+/* call this when you're done with an entry that was fetched via one of
+ * the cache_find_* calls.
+ */
+void cache_return(struct cache *cache, struct backentry **bep)
+{
+ struct backentry *eflush = NULL;
+ struct backentry *eflushtemp = NULL;
+ struct backentry *e;
+ if (NULL == bep || NULL == *bep)
+ {
+ LOG("=> cache_return (null entry)\n", 0, 0, 0);
+ return;
+ }
+ e = *bep;
+ LOG("=> cache_return (%s) entry count: %d, entry in cache:%ld\n", backentry_get_ndn(e), e->ep_refcnt, cache->c_curentries);
+
+ PR_Lock(cache->c_mutex);
+ if (e->ep_state & ENTRY_STATE_NOTINCACHE)
+ {
+ backentry_free(bep);
+ }
+ else
+ {
+ ASSERT(e->ep_refcnt > 0);
+ if (! --e->ep_refcnt) {
+ if (e->ep_state & ENTRY_STATE_DELETED) {
+ backentry_free(bep);
+ } else {
+ lru_add(cache, e);
+ /* the cache might be overfull... */
+ if (CACHE_FULL(cache))
+ eflush = cache_flush(cache);
+ }
+ }
+ }
+ PR_Unlock(cache->c_mutex);
+ while (eflush)
+ {
+ eflushtemp = eflush->ep_lrunext;
+ backentry_free(&eflush);
+ eflush = eflushtemp;
+ }
+}
+
+
+/* lookup entry by DN (assume cache lock is held) */
+struct backentry *cache_find_dn(struct cache *cache, const char *dn, unsigned long ndnlen)
+{
+ struct backentry *e;
+
+ LOG("=> cache_find_dn (%s)\n", dn, 0, 0);
+
+ /*entry normalized by caller (dn2entry.c) */
+ PR_Lock(cache->c_mutex);
+ if (find_hash(cache->c_dntable, (void *)dn, ndnlen, (void **)&e)) {
+ /* need to check entry state */
+ if (e->ep_state != 0) {
+ /* entry is deleted or not fully created yet */
+ PR_Unlock(cache->c_mutex);
+ LOG("<= cache_find_dn (NOT FOUND)\n", 0, 0, 0);
+ return NULL;
+ }
+ if (e->ep_refcnt == 0)
+ lru_delete(cache, e);
+ e->ep_refcnt++;
+ cache->c_hits++;
+ }
+ cache->c_tries++;
+ PR_Unlock(cache->c_mutex);
+
+ LOG("<= cache_find_dn (%sFOUND)\n", e ? "" : "NOT ", 0, 0);
+ return e;
+}
+
+
+/* lookup an entry in the cache by its id# (you must return it later) */
+struct backentry *cache_find_id(struct cache *cache, ID id)
+{
+ struct backentry *e;
+
+ LOG("=> cache_find_id (%lu)\n", (u_long)id, 0, 0);
+
+ PR_Lock(cache->c_mutex);
+ if (find_hash(cache->c_idtable, &id, sizeof(ID), (void **)&e)) {
+ /* need to check entry state */
+ if (e->ep_state != 0) {
+ /* entry is deleted or not fully created yet */
+ PR_Unlock(cache->c_mutex);
+ LOG("<= cache_find_id (NOT FOUND)\n", 0, 0, 0);
+ return NULL;
+ }
+ if (e->ep_refcnt == 0)
+ lru_delete(cache, e);
+ e->ep_refcnt++;
+ cache->c_hits++;
+ }
+ cache->c_tries++;
+ PR_Unlock(cache->c_mutex);
+
+ LOG("<= cache_find_id (%sFOUND)\n", e ? "" : "NOT ", 0, 0);
+ return e;
+}
+
+#ifdef UUIDCACHE_ON
+/* lookup an entry in the cache by it's uuid (you must return it later) */
+struct backentry *cache_find_uuid(struct cache *cache, const char *uuid)
+{
+ struct backentry *e;
+
+ LOG("=> cache_find_uuid (%s)\n", uuid, 0, 0);
+
+ PR_Lock(cache->c_mutex);
+ if (find_hash(cache->c_uuidtable, uuid, strlen(uuid), (void **)&e)) {
+ /* need to check entry state */
+ if (e->ep_state != 0) {
+ /* entry is deleted or not fully created yet */
+ PR_Unlock(cache->c_mutex);
+ LOG("<= cache_find_uuid (NOT FOUND)\n", 0, 0, 0);
+ return NULL;
+ }
+ if (e->ep_refcnt == 0)
+ lru_delete(cache, e);
+ e->ep_refcnt++;
+ cache->c_hits++;
+ }
+ cache->c_tries++;
+ PR_Unlock(cache->c_mutex);
+
+ LOG("<= cache_find_uuid (%sFOUND)\n", e ? "" : "NOT ", 0, 0);
+ return e;
+}
+#endif
+
+/* add an entry to the cache */
+static int cache_add_int(struct cache *cache, struct backentry *e, int state,
+ struct backentry **alt)
+{
+ struct backentry *eflush = NULL;
+ struct backentry *eflushtemp = NULL;
+ const char *ndn = slapi_sdn_get_ndn(backentry_get_sdn(e));
+#ifdef UUIDCACHE_ON
+ const char *uuid = slapi_entry_get_uniqueid(e->ep_entry);
+#endif
+ struct backentry *my_alt;
+ int already_in = 0;
+
+ LOG("=> cache_add_int( \"%s\", %ld )\n", backentry_get_ndn(e),
+ e->ep_id, 0);
+
+ PR_Lock(cache->c_mutex);
+ if (! add_hash(cache->c_dntable, (void *)ndn, strlen(ndn), e,
+ (void **)&my_alt)) {
+ LOG("entry \"%s\" already in dn cache\n", backentry_get_ndn(e), 0, 0);
+ /* add_hash filled in 'my_alt' if necessary */
+ if (my_alt == e)
+ {
+ if ((e->ep_state & ENTRY_STATE_CREATING) && (state == 0))
+ {
+ /* attempting to "add" an entry that's already in the cache,
+ * and the old entry was a placeholder and the new one isn't?
+ * sounds like a confirmation of a previous add!
+ */
+ LOG("confirming a previous add\n", 0, 0, 0);
+ already_in = 1;
+ }
+ else
+ {
+ /* the entry already in the cache and either one of these:
+ * 1) ep_state: CREATING && state: CREATING
+ * ==> keep protecting the entry; increase the refcnt
+ * 2) ep_state: 0 && state: CREATING
+ * ==> change the state to CREATING (protect it);
+ * increase the refcnt
+ * 3) ep_state: 0 && state: 0
+ * ==> increase the refcnt
+ */
+ if (e->ep_refcnt == 0)
+ lru_delete(cache, e);
+ e->ep_refcnt++;
+ e->ep_state = state; /* might be CREATING */
+ /* returning 1 (entry already existed), but don't set to alt
+ * to prevent that the caller accidentally thinks the existing
+ * entry is not the same one the caller has and releases it.
+ */
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+ }
+ else
+ {
+ if (my_alt->ep_state & ENTRY_STATE_CREATING)
+ {
+ LOG("the entry is reserved\n", 0, 0, 0);
+ e->ep_state |= ENTRY_STATE_NOTINCACHE;
+ PR_Unlock(cache->c_mutex);
+ return -1;
+ }
+ else if (state != 0)
+ {
+ LOG("the entry already exists. cannot reserve it.\n", 0, 0, 0);
+ e->ep_state |= ENTRY_STATE_NOTINCACHE;
+ PR_Unlock(cache->c_mutex);
+ return -1;
+ }
+ else
+ {
+ if (alt) {
+ *alt = my_alt;
+ if ((*alt)->ep_refcnt == 0)
+ lru_delete(cache, *alt);
+ (*alt)->ep_refcnt++;
+ }
+ PR_Unlock(cache->c_mutex);
+ return 1;
+ }
+ }
+ }
+
+ /* creating an entry with ENTRY_STATE_CREATING just creates a stub
+ * which is only stored in the dn table (basically, reserving the dn) --
+ * doing an add later with state==0 will "confirm" the add
+ */
+ if (state == 0) {
+ /* neither of these should fail, or something is very wrong. */
+ if (! add_hash(cache->c_idtable, &(e->ep_id), sizeof(ID), e, NULL)) {
+ LOG("entry %s already in id cache!\n", backentry_get_ndn(e), 0, 0);
+ if (already_in) {
+ /* there's a bug in the implementatin of 'modify' and 'modrdn'
+ * that i'm working around here. basically they do a
+ * tentative add of the new (modified) entry, which places
+ * the new entry in the cache, indexed only by dn.
+ *
+ * later they call id2entry_add() on the new entry, which
+ * "adds" the new entry to the cache. unfortunately, that
+ * add will fail, since the old entry is still in the cache,
+ * and both the old and new entries have the same ID and UUID.
+ *
+ * i catch that here, and just return 0 for success, without
+ * messing with either entry. a later cache_replace() will
+ * remove the old entry and add the new one, and all will be
+ * fine (i think).
+ */
+ LOG("<= cache_add_int (ignoring)\n", 0, 0, 0);
+ PR_Unlock(cache->c_mutex);
+ return 0;
+ }
+ remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn));
+ e->ep_state |= ENTRY_STATE_NOTINCACHE;
+ PR_Unlock(cache->c_mutex);
+ return -1;
+ }
+#ifdef UUIDCACHE_ON
+ if (uuid) {
+ /* (only insert entries with a uuid) */
+ if (! add_hash(cache->c_uuidtable, (void *)uuid, strlen(uuid), e,
+ NULL)) {
+ LOG("entry %s already in uuid cache!\n", backentry_get_ndn(e),
+ 0, 0);
+ remove_hash(cache->c_dntable, (void *)ndn, strlen(ndn));
+ remove_hash(cache->c_idtable, &(e->ep_id), sizeof(ID));
+ e->ep_state |= ENTRY_STATE_NOTINCACHE;
+ PR_Unlock(cache->c_mutex);
+ return -1;
+ }
+ }
+#endif
+ }
+
+ e->ep_state = state;
+
+ if (! already_in) {
+ e->ep_refcnt = 1;
+ e->size = cache_entry_size(e);
+
+ cache->c_cursize += e->size;
+ cache->c_curentries++;
+ /* don't add to lru since refcnt = 1 */
+ LOG("added entry of size %lu -> total now %lu out of max %lu\n",
+ e->size, cache->c_cursize, cache->c_maxsize);
+ if (cache->c_maxentries >= 0) {
+ LOG(" total entries %ld out of %ld\n",
+ cache->c_curentries, cache->c_maxentries, 0);
+ }
+ /* check for full cache, and clear out if necessary */
+ if (CACHE_FULL(cache))
+ eflush = cache_flush(cache);
+ }
+ PR_Unlock(cache->c_mutex);
+
+ while (eflush)
+ {
+ eflushtemp = eflush->ep_lrunext;
+ backentry_free(&eflush);
+ eflush = eflushtemp;
+ }
+ LOG("<= cache_add_int OK\n", 0, 0, 0);
+ return 0;
+}
+
+/* create an entry in the cache, and increase its refcount (you must
+ * return it when you're done).
+ * returns: 0 entry has been created & locked
+ * 1 entry already existed
+ * -1 something bad happened
+ *
+ * if 'alt' is not NULL, and the entry is found to already exist in the
+ * cache, a refcounted pointer to that entry will be placed in 'alt'.
+ * (this means code which suffered from race conditions between multiple
+ * entry modifiers can now work.)
+ */
+int cache_add(struct cache *cache, struct backentry *e,
+ struct backentry **alt)
+{
+ return cache_add_int(cache, e, 0, alt);
+}
+
+/* same as above, but add it tentatively: nobody else can use this entry
+ * from the cache until you later call cache_add.
+ */
+int cache_add_tentative(struct cache *cache, struct backentry *e,
+ struct backentry **alt)
+{
+ return cache_add_int(cache, e, ENTRY_STATE_CREATING, alt);
+}
+
+/* locks an entry so that it can be modified (you should have gotten the
+ * entry via cache_find_*).
+ * returns 0 on success, 1 if the entry is scheduled for deletion.
+ */
+int cache_lock_entry(struct cache *cache, struct backentry *e)
+{
+ LOG("=> cache_lock_entry (%s)\n", backentry_get_ndn(e), 0, 0);
+
+ if (! e->ep_mutexp) {
+ /* make sure only one thread does this */
+ PR_Lock(cache->c_emutexalloc_mutex);
+ if (! e->ep_mutexp)
+ e->ep_mutexp = PR_NewLock();
+ PR_Unlock(cache->c_emutexalloc_mutex);
+ }
+
+ /* wait on entry lock (done w/o holding the cache lock) */
+ PR_Lock(e->ep_mutexp);
+
+ /* make sure entry hasn't been deleted now */
+ PR_Lock(cache->c_mutex);
+ if (e->ep_state & (ENTRY_STATE_DELETED|ENTRY_STATE_NOTINCACHE)) {
+ PR_Unlock(cache->c_mutex);
+ PR_Unlock(e->ep_mutexp);
+ LOG("<= cache_lock_entry (DELETED)\n", 0, 0, 0);
+ return 1;
+ }
+ PR_Unlock(cache->c_mutex);
+
+ LOG("<= cache_lock_entry (FOUND)\n", 0, 0, 0);
+ return 0;
+}
+
+/* the opposite of above */
+void cache_unlock_entry(struct cache *cache, struct backentry *e)
+{
+ LOG("=> cache_unlock_entry\n", 0, 0, 0);
+ PR_Unlock(e->ep_mutexp);
+}
diff --git a/ldap/servers/slapd/back-ldbm/cleanup.c b/ldap/servers/slapd/back-ldbm/cleanup.c
new file mode 100644
index 00000000..ef539134
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/cleanup.c
@@ -0,0 +1,51 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* cleanup.c - cleans up ldbm backend */
+
+#include "back-ldbm.h"
+
+int ldbm_back_cleanup( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li;
+ Slapi_Backend *be;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend cleaning up\n", 0, 0, 0 );
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+
+ if (be->be_state != BE_STATE_STOPPED &&
+ be->be_state != BE_STATE_DELETED)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldbm_back_cleanup: warning - backend is in a wrong state - %d\n",
+ be->be_state, 0, 0 );
+ return 0;
+ }
+
+ PR_Lock (be->be_state_lock);
+
+ if (be->be_state != BE_STATE_STOPPED &&
+ be->be_state != BE_STATE_DELETED)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldbm_back_cleanup: warning - backend is in a wrong state - %d\n",
+ be->be_state, 0, 0 );
+ PR_Unlock (be->be_state_lock);
+ return 0;
+ }
+
+ dblayer_terminate( li );
+
+/* JCM I tried adding this to tidy up memory on shutdown. */
+/* JCM But, the result was very messy. */
+/* JCM objset_delete(&li->li_instance_set); */
+
+ be->be_state = BE_STATE_CLEANED;
+
+ PR_Unlock (be->be_state_lock);
+
+ return 0;
+}
diff --git a/ldap/servers/slapd/back-ldbm/close.c b/ldap/servers/slapd/back-ldbm/close.c
new file mode 100644
index 00000000..ce2be3b9
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/close.c
@@ -0,0 +1,52 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* close.c - close ldbm backend */
+
+#include "back-ldbm.h"
+
+int ldbm_back_close( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend syncing\n", 0, 0, 0 );
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+
+ /* Kill off any sleeping threads by setting this flag */
+ PR_Lock(li->li_shutdown_mutex);
+ li->li_shutdown = 1;
+ PR_Unlock(li->li_shutdown_mutex);
+
+ dblayer_flush( li ); /* just be doubly sure! */
+
+ /* close down all the ldbm instances */
+ dblayer_close( li, DBLAYER_NORMAL_MODE );
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend done syncing\n", 0, 0, 0 );
+ return 0;
+}
+
+int ldbm_back_flush( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend flushing\n", 0, 0, 0 );
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ dblayer_flush( li );
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend done flushing\n", 0, 0, 0 );
+ return 0;
+}
+
+void ldbm_back_instance_set_destructor(void **arg)
+{
+ /*
+ Objset *instance_set = (Objset *) *arg;
+ */
+
+ /* This function is called when the instance set is destroyed.
+ * I can't really think of anything we should do here, but that
+ * may change in the future. */
+ LDAPDebug(LDAP_DEBUG_ANY, "Set of instances destroyed\n", 0, 0, 0);
+}
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.c b/ldap/servers/slapd/back-ldbm/dblayer.c
new file mode 100644
index 00000000..c852b475
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/dblayer.c
@@ -0,0 +1,5395 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ Abstraction layer which sits between db2.0 and
+ higher layers in the directory server---typically
+ the back-end.
+ This module's purposes are 1) to hide messy stuff which
+ db2.0 needs, and with which we don't want to pollute the back-end
+ code. 2) Provide some degree of portability to other databases
+ if that becomes a requirement. Note that it is NOT POSSIBLE
+ to revert to db1.85 because the backend is now using features
+ from db2.0 which db1.85 does not have.
+ Also provides an emulation of the ldbm_ functions, for anyone
+ who is still calling those. The use of these functions is
+ deprecated. Only for backwards-compatibility.
+ Blame: dboreham
+*/
+
+/* Return code conventions:
+ Unless otherwise advertised, all the functions in this module
+ return an int which is zero if the operation was successful
+ and non-zero if it wasn't. If the return'ed value was > 0,
+ it can be interpreted as a system errno value. If it was < 0,
+ its meaning is defined in dblayer.h
+*/
+
+/*
+ Some information about how this stuff is to be used:
+
+ Call dblayer_init() near the beginning of the application's life.
+ This allocates some resources and allows the config line processing
+ stuff to work.
+ Call dblayer_start() when you're sure all config stuff has been seen.
+ This needs to be called before you can do anything else.
+ Call dblayer_close() when you're finished using the db and want to exit.
+ This closes and flushes all files opened by your application since calling
+ dblayer_start. If you do NOT call dblayer_close(), we assume that the
+ application crashed, and initiate recover next time you call dblayer_start().
+ Call dblayer_terminate() after close. This releases resources.
+
+ DB* handles are retrieved from dblayer via these functions:
+
+ dblayer_get_id2entry()
+ dblayer_get_index_file()
+
+ the caller must honour the protocol that these handles are released back
+ to dblayer when you're done using them, use thse functions to do this:
+
+ dblayer_release_id2entry()
+ dblayer_release_index_file()
+
+
+*/
+
+#include "back-ldbm.h"
+#include "dblayer.h"
+#include <prrwlock.h>
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4100
+#define DB_OPEN(oflags, db, txnid, file, database, type, flags, mode, rval) \
+{ \
+ if (((oflags) & DB_INIT_TXN) && ((oflags) & DB_INIT_LOG)) \
+ { \
+ (rval) = (db)->open((db), (txnid), (file), (database), (type), (flags)|DB_AUTO_COMMIT, (mode)); \
+ } \
+ else \
+ { \
+ (rval) = (db)->open((db), (txnid), (file), (database), (type), (flags), (mode)); \
+ } \
+}
+/* 608145: db4.1 and newer does not require exclusive lock for checkpointing
+ * and transactions */
+#define DB_CHECKPOINT_LOCK(use_lock, lock) ;
+#define DB_CHECKPOINT_UNLOCK(use_lock, lock) ;
+#else /* older then db 41 */
+#define DB_OPEN(oflags, db, txnid, file, database, type, flags, mode, rval) \
+ (rval) = (db)->open((db), (file), (database), (type), (flags), (mode))
+#define DB_CHECKPOINT_LOCK(use_lock, lock) if(use_lock) PR_RWLock_Wlock(lock);
+#define DB_CHECKPOINT_UNLOCK(use_lock, lock) if(use_lock) PR_RWLock_Unlock(lock);
+#endif
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4000
+#define DB_ENV_SET_REGION_INIT(env) (env)->set_flags((env), DB_REGION_INIT, 1)
+#define DB_ENV_SET_TAS_SPINS(env, tas_spins) \
+ (env)->set_tas_spins((env), (tas_spins))
+#define TXN_BEGIN(env, parent_txn, tid, flags) \
+ (env)->txn_begin((env), (parent_txn), (tid), (flags))
+#define TXN_COMMIT(txn, flags) (txn)->commit((txn), (flags))
+#define TXN_ABORT(txn) (txn)->abort(txn)
+#define TXN_CHECKPOINT(env, kbyte, min, flags) \
+ (env)->txn_checkpoint((env), (kbyte), (min), (flags))
+#define MEMP_STAT(env, gsp, fsp, flags, malloc) \
+ (env)->memp_stat((env), (gsp), (fsp), (flags))
+#define MEMP_TRICKLE(env, pct, nwrotep) \
+ (env)->memp_trickle((env), (pct), (nwrotep))
+#define LOG_ARCHIVE(env, listp, flags, malloc) \
+ (env)->log_archive((env), (listp), (flags))
+#define LOG_FLUSH(env, lsn) (env)->log_flush((env), (lsn))
+#define LOCK_DETECT(env, flags, atype, aborted) \
+ (env)->lock_detect((env), (flags), (atype), (aborted))
+
+#else /* older than db 4.0 */
+#define DB_ENV_SET_REGION_INIT(env) db_env_set_region_init(1)
+#define DB_ENV_SET_TAS_SPINS(env, tas_spins) \
+ db_env_set_tas_spins((tas_spins))
+#define TXN_BEGIN(env, parent_txn, tid, flags) \
+ txn_begin((env), (parent_txn), (tid), (flags))
+#define TXN_COMMIT(txn, flags) txn_commit((txn), (flags))
+#define TXN_ABORT(txn) txn_abort((txn))
+#define TXN_CHECKPOINT(env, kbyte, min, flags) \
+ txn_checkpoint((env), (kbyte), (min), (flags))
+#define MEMP_TRICKLE(env, pct, nwrotep) memp_trickle((env), (pct), (nwrotep))
+#define LOG_FLUSH(env, lsn) log_flush((env), (lsn))
+#define LOCK_DETECT(env, flags, atype, aborted) \
+ lock_detect((env), (flags), (atype), (aborted))
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3300
+#define MEMP_STAT(env, gsp, fsp, flags, malloc) memp_stat((env), (gsp), (fsp))
+#define LOG_ARCHIVE(env, listp, flags, malloc) \
+ log_archive((env), (listp), (flags))
+
+#else /* older than db 3.3 */
+#define MEMP_STAT(env, gsp, fsp, flags, malloc) \
+ memp_stat((env), (gsp), (fsp), (malloc))
+#define LOG_ARCHIVE(env, listp, flags, malloc) \
+ log_archive((env), (listp), (flags), (malloc))
+#endif
+#endif
+
+static int perf_threadmain(void *param);
+static int checkpoint_threadmain(void *param);
+static int trickle_threadmain(void *param);
+static int deadlock_threadmain(void *param);
+static int commit_good_database(dblayer_private *priv);
+static int read_metadata(struct ldbminfo *li);
+static int count_dbfiles_in_dir(char *directory, int *count, int recurse);
+static int dblayer_override_libdb_functions(DB_ENV *pEnv, dblayer_private *priv);
+static int dblayer_force_checkpoint(struct ldbminfo *li);
+static int log_flush_threadmain(void *param);
+static int dblayer_delete_transaction_logs(const char * log_dir);
+
+static int dblayer_start_log_flush_thread(dblayer_private *priv);
+static int dblayer_start_deadlock_thread(struct ldbminfo *li);
+static int dblayer_start_checkpoint_thread(struct ldbminfo *li);
+static int dblayer_start_trickle_thread(struct ldbminfo *li);
+static int dblayer_start_perf_thread(struct ldbminfo *li);
+static int trans_batch_count=1;
+static int trans_batch_limit=0;
+static PRBool log_flush_thread=PR_FALSE;
+static int dblayer_db_remove_ex(dblayer_private_env *env, char const path[], char const dbName[], PRBool use_lock);
+static char* last_four_chars(const char* s);
+
+#define MEGABYTE (1024 * 1024)
+#define GIGABYTE (1024 * MEGABYTE)
+
+/* this flag use if user remotely turned batching off */
+
+#define FLUSH_REMOTEOFF -1
+/* routine that allows batch value to be changed remotely:
+
+ 1. value = 0 turns batching off
+ 2. value = 1 makes behavior be like 5.0 but leaves batching on
+ 3. value > 1 changes batch value
+
+ 2 and 3 assume that nsslapd-db-transaction-batch-val is greater 0 at startup
+*/
+
+int
+dblayer_set_batch_transactions(void *arg, void *value, char *errorbuf, int phase, int apply) {
+ int val = (int) value;
+ int retval = LDAP_SUCCESS;
+
+ if (apply) {
+ if(phase == CONFIG_PHASE_STARTUP) {
+ trans_batch_limit=val;
+ } else if(trans_batch_limit != FLUSH_REMOTEOFF ) {
+ if((val == 0) && (log_flush_thread)) {
+ log_flush_thread=PR_FALSE;
+ trans_batch_limit = FLUSH_REMOTEOFF;
+ } else if(val > 0) {
+ trans_batch_limit=val;
+ }
+ }
+ }
+ return retval;
+}
+
+void *
+dblayer_get_batch_transactions(void *arg) {
+ return (void *)trans_batch_limit;
+}
+
+
+/*
+ Threading: dblayer isolates upper layers from threading considerations
+ Everything in dblayer is free-threaded. That is, you can have multiple
+ threads performing operations on a database and not worry about things.
+ Obviously, if you do something stupid, like move a cursor forward in
+ one thread, and backwards in another at the same time, you get what you
+ deserve. However, such a calling pattern will not crash your application !
+*/
+
+static int
+dblayer_txn_checkpoint(struct ldbminfo *li, struct dblayer_private_env *env,
+ PRBool use_lock, PRBool busy_skip)
+{
+ int ret = 0;
+ if (busy_skip && is_anyinstance_busy(li))
+ {
+ return ret;
+ }
+ DB_CHECKPOINT_LOCK(use_lock, env->dblayer_env_lock);
+ ret = TXN_CHECKPOINT(env->dblayer_DB_ENV, 0, 0, DB_FORCE);
+ DB_CHECKPOINT_UNLOCK(use_lock, env->dblayer_env_lock);
+ return ret;
+}
+
+static int _dblayer_check_version(dblayer_private *priv)
+{
+ int major, minor = 0;
+ char *string = 0;
+ int ret = 0;
+
+ string = db_version(&major,&minor,NULL);
+ if (major < DB_VERSION_MAJOR)
+ {
+ ret = -1;
+ }
+ else
+ {
+ ret = 0;
+ }
+ /* DB3X: always POST 24 :) */
+ priv->dblayer_lib_version = DBLAYER_LIB_VERSION_POST_24;
+ LDAPDebug(LDAP_DEBUG_TRACE,"version check: %s (%d.%d)\n", string, major, minor);
+ return ret;
+}
+
+
+/*
+ * return nsslapd-db-home-directory (dblayer_dbhome_directory), if exists.
+ * Otherwise, return nsslapd-directory (dblayer_home_directory).
+ *
+ * if dblayer_dbhome_directory exists, set 1 to dbhome.
+ */
+char *
+dblayer_get_home_dir(struct ldbminfo *li, int *dbhome)
+{
+ dblayer_private *priv = (dblayer_private*)li->li_dblayer_private;
+ char *home_dir = priv->dblayer_home_directory;
+ if (dbhome)
+ *dbhome = 0;
+
+ if (priv->dblayer_dbhome_directory && *(priv->dblayer_dbhome_directory))
+ {
+ if (dbhome)
+ *dbhome = 1;
+ home_dir = priv->dblayer_dbhome_directory;
+ }
+ if (NULL == home_dir)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,"Db home directory is not set. "
+ "Possibly %s (optinally %s) is missing in the config file.\n",
+ CONFIG_DIRECTORY, CONFIG_DB_HOME_DIRECTORY, 0);
+ }
+ return home_dir;
+}
+
+/* Helper function which deletes the persistent state of the database library
+ * IMHO this should be in inside libdb, but keith won't have it.
+ * Stop press---libdb now does delete these files on recovery, so we don't call this any more.
+ */
+static void dblayer_reset_env(struct ldbminfo *li)
+{
+ /* Remove the memory regions */
+ dblayer_private *priv = (dblayer_private*)li->li_dblayer_private;
+ DB_ENV *pEnv = priv->dblayer_env->dblayer_DB_ENV;
+ char *home_dir = dblayer_get_home_dir(li, NULL);
+ if (home_dir)
+ pEnv->remove(pEnv, home_dir, DB_FORCE);
+}
+
+/* Callback function for libdb to spit error info into our log */
+static void dblayer_log_print(const char* prefix, char *buffer)
+{
+ /* We ignore the prefix since we know who we are anyway */
+ LDAPDebug(LDAP_DEBUG_ANY,"libdb: %s\n", buffer, 0, 0);
+}
+
+void dblayer_remember_disk_filled(struct ldbminfo *li)
+{
+ dblayer_private *priv = NULL;
+
+ PR_ASSERT(NULL != li);
+ priv = li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ priv->dblayer_bad_stuff_happened = 1;
+
+}
+
+/* Function which calls libdb to override some system calls which
+ * the library makes. We call this before calling any other function
+ * in libdb.
+ * Several OS use this, either partially or completely.
+ * This will eventually change---we will simply pass to libdb
+ * the addresses of a bunch of NSPR functions, and everything
+ * will magically work on all platforms (Ha!)
+ */
+
+#ifdef DB_USE_64LFS
+/* What is going on here ?
+ * Well, some platforms now support an extended API for dealing with
+ * files larger than 2G. (This apparently comes from the LFS -- "Large
+ * File Summit"... Summit, indeed.) Anyway, we try to detect at runtime
+ * whether this machine has the extended API, and use it if it's present.
+ *
+ */
+
+
+/* helper function for open64 */
+static int dblayer_open_large(const char *path, int oflag, mode_t mode)
+{
+ int err;
+
+ err = open64(path, oflag, mode);
+ /* weird but necessary: */
+ if (err >= 0) errno = 0;
+ return err;
+}
+
+/* this is REALLY dumb. but nspr 19980529(x) doesn't support 64-bit files
+ * because of some weirdness we're doing at initialization (?), so we need
+ * to export some function that can open huge files, so that exporting
+ * can work right. when we fix the nspr problem (or get a more recent
+ * version of nspr that might magically work?), this should be blown away.
+ * (call mode_t an int because NT can't handle that in prototypes.)
+ * -robey, 28oct98
+ */
+int dblayer_open_huge_file(const char *path, int oflag, int mode)
+{
+ return dblayer_open_large(path, oflag, (mode_t)mode);
+}
+
+
+/* Helper function for large seeks, db2.4 */
+static int dblayer_seek24_large(int fd, size_t pgsize, db_pgno_t pageno,
+ u_long relative, int isrewind, int whence)
+{
+ off64_t offset = 0, ret;
+
+ offset = (off64_t)pgsize * pageno + relative;
+ if (isrewind) offset = -offset;
+ ret = lseek64(fd, offset, whence);
+
+ return (ret < 0) ? errno : 0;
+}
+
+/* helper function for large fstat -- this depends on 'struct stat64' having
+ * the following members:
+ * off64_t st_size;
+ * long st_blksize;
+ */
+static int dblayer_ioinfo_large(const char *path, int fd, u_int32_t *mbytesp,
+ u_int32_t *bytesp, u_int32_t *iosizep)
+{
+ struct stat64 sb;
+
+ if (fstat64(fd, &sb) < 0)
+ return (errno);
+
+ /* Return the size of the file. */
+ if (mbytesp)
+ *mbytesp = (u_int32_t) (sb.st_size / (off64_t) MEGABYTE);
+ if (bytesp)
+ *bytesp = (u_int32_t) (sb.st_size % (off64_t) MEGABYTE);
+
+ if (iosizep)
+ *iosizep = (u_int32_t)(sb.st_blksize);
+ return 0;
+}
+/* Helper function to tell if a file exists */
+/* On Solaris, if you use stat() on a file >4Gbytes, it fails with EOVERFLOW,
+ causing us to think that the file does not exist when it in fact does */
+static int dblayer_exists_large(char *path, int *isdirp)
+{
+ struct stat64 sb;
+
+ if (stat64(path, &sb) != 0)
+ return (errno);
+
+ if (isdirp != NULL)
+ *isdirp = S_ISDIR(sb.st_mode);
+
+ return (0);
+}
+
+#else /* DB_USE_64LFS */
+
+int dblayer_open_huge_file(const char *path, int oflag, int mode)
+{
+ return open(path, oflag, mode);
+}
+
+#endif /* DB_USE_64LFS */
+
+
+static int dblayer_override_libdb_functions(DB_ENV *pEnv, dblayer_private *priv)
+{
+#ifdef DB_USE_64LFS
+ int major = 0;
+ int minor = 0;
+
+ /* Find out whether we are talking to a 2.3 or 2.4+ libdb */
+ db_version(&major, &minor, NULL);
+
+#ifndef irix
+ /* irix doesn't have open64() */
+ db_env_set_func_open((int (*)(const char *, int, ...))dblayer_open_large);
+#endif /* !irix */
+ db_env_set_func_ioinfo(dblayer_ioinfo_large);
+ db_env_set_func_exists((int (*)())dblayer_exists_large);
+ db_env_set_func_seek((int (*)())dblayer_seek24_large);
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "Enabled 64-bit files\n", 0, 0, 0);
+#endif /* DB_USE_64LFS */
+ return 0;
+}
+
+
+
+/* This function is called in the initialization code, before the
+ * config file is read in, so we can't do much here
+ */
+int dblayer_init(struct ldbminfo *li)
+{
+ /* Allocate memory we need, create mutexes etc. */
+ dblayer_private *priv = NULL;
+ int ret = 0;
+
+ PR_ASSERT(NULL != li);
+ if (NULL != li->li_dblayer_private)
+ {
+ return -1;
+ }
+
+ priv = (dblayer_private*) slapi_ch_calloc(1,sizeof(dblayer_private));
+ if (NULL == priv)
+ {
+ /* Memory allocation failed */
+ return -1;
+ }
+ li->li_dblayer_private = priv;
+
+ /* For now, we call this to get debug printout */
+ _dblayer_check_version(priv);
+
+ /* moved db_env_create to dblayer_start */
+ return ret;
+}
+
+int dblayer_terminate(struct ldbminfo *li)
+{
+ /* We assume that dblayer_close has been called already */
+ dblayer_private *priv = (dblayer_private*)li->li_dblayer_private;
+ Object *inst_obj;
+ ldbm_instance *inst;
+ int rval = 0;
+
+ if (NULL == priv) /* already terminated. nothing to do */
+ return rval;
+
+ /* clean up mutexes */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ if (NULL != inst->inst_db_mutex) {
+ PR_DestroyLock(inst->inst_db_mutex);
+ }
+ if (NULL != inst->inst_handle_list_mutex) {
+ PR_DestroyLock(inst->inst_handle_list_mutex);
+ }
+ }
+
+ slapi_ch_free_string(&priv->dblayer_log_directory);
+ /* no need to release dblayer_home_directory,
+ * which is one of dblayer_data_directories */
+ charray_free(priv->dblayer_data_directories);
+ slapi_ch_free((void**)&priv);
+ li->li_dblayer_private = NULL;
+
+ return 0;
+}
+
+static void dblayer_select_ncache(size_t cachesize, int *ncachep)
+{
+ /* First thing, if the user asked to use a particular ncache,
+ * we let them, and don't override it here.
+ */
+ if (*ncachep) {
+ return;
+ }
+ /* If the user asked for a cache that's larger than 4G,
+ * we _must_ select an ncache >0 , such that each
+ * chunk is <4G. This is because DB won't accept a
+ * larger chunk.
+ */
+#if defined(__LP64__) || defined (_LP64)
+ if ( (sizeof(cachesize) > 4) && (cachesize > (4L * GIGABYTE))) {
+ *ncachep = (cachesize / (4L * GIGABYTE)) + 1;
+ LDAPDebug(LDAP_DEBUG_ANY,"Setting ncache to: %d to keep each chunk below 4Gbytes\n",
+ *ncachep, 0, 0);
+ }
+#endif
+ /* On Windows, we know that it's hard to allocate more than some
+ * maximum chunk. In that case
+ * we set ncache to a sensible value.
+ */
+#if defined(_WIN32)
+ {
+ size_t max_windows_chunk = (300 * MEGABYTE); /* This number was determined empirically on Win2k */
+ if (cachesize > max_windows_chunk) {
+ *ncachep = (cachesize / max_windows_chunk) + 1;
+ LDAPDebug(LDAP_DEBUG_ANY,"Setting ncache to: %d for Windows memory address space fragmentation\n",
+ *ncachep, 0, 0);
+ }
+ }
+#endif
+}
+
+/* This function is no longer called :
+ It attempts to find the maximum allocatable chunk size
+ by performing the actual allocations. However as a result
+ it allocates pretty much _all_ the available memory,
+ causing the actual cache allocation to fail later.
+ If there turns out to be a good safe way to determine
+ the maximum chunk size, then we should use that instead.
+ For now we just guess in dblayer_pick_ncache().
+ */
+static void dblayer_get_ncache(size_t cachesize, int *ncachep)
+{
+ int myncache;
+ int mymaxncache;
+ int found = 0;
+ char **head;
+
+ if (*ncachep <= 0) /* negative ncache is not allowed */
+ myncache = 1;
+ else
+ myncache = *ncachep;
+
+ mymaxncache = myncache + 20; /* should be reasonable */
+
+ head = (char **)slapi_ch_malloc(mymaxncache * sizeof(char *));
+ do {
+ int i;
+ int end;
+ size_t sz;
+ size_t firstsz;
+ size_t rest;
+
+ rest = cachesize % myncache;
+ sz = cachesize / myncache;
+ firstsz = sz + rest;
+ end = myncache;
+ for (i = 0; i < myncache; i++) {
+ if (i == 0)
+ head[i] = (char *)malloc(firstsz);
+ else
+ head[i] = (char *)malloc(sz);
+ if (NULL == head[i]) {
+ end = i;
+ myncache++;
+ goto cleanup;
+ }
+ }
+ found = 1;
+cleanup:
+ for (i = 0; i < end; i++) {
+ slapi_ch_free((void **)&head[i]);
+ }
+ if (myncache == mymaxncache) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "WARNING: dbcachesize %lu too big\n", cachesize, 0, 0);
+ myncache = 0;
+ found = -1;
+ }
+ } while (0 == found);
+ *ncachep = myncache;
+ slapi_ch_free((void **)&head);
+ return;
+}
+
+static void dblayer_init_dbenv(DB_ENV *pEnv, dblayer_private *priv)
+{
+ size_t mysize;
+ int myncache = 1;
+
+ mysize = priv->dblayer_cachesize;
+ myncache = priv->dblayer_ncache;
+ dblayer_select_ncache(mysize, &myncache);
+ priv->dblayer_ncache = myncache;
+
+ pEnv->set_errpfx(pEnv, "ns-slapd");
+ pEnv->set_lg_max(pEnv, priv->dblayer_logfile_size);
+ pEnv->set_cachesize(pEnv, mysize / GIGABYTE, mysize % GIGABYTE, myncache);
+ pEnv->set_lk_max_locks(pEnv, priv->dblayer_lock_config);
+ pEnv->set_lk_max_objects(pEnv, priv->dblayer_lock_config);
+ pEnv->set_lk_max_lockers(pEnv, priv->dblayer_lock_config);
+ if (priv->dblayer_verbose) {
+ pEnv->set_verbose(pEnv, DB_VERB_CHKPOINT, 1); /* 1 means on */
+ pEnv->set_verbose(pEnv, DB_VERB_DEADLOCK, 1); /* 1 means on */
+ pEnv->set_verbose(pEnv, DB_VERB_RECOVERY, 1); /* 1 means on */
+ pEnv->set_verbose(pEnv, DB_VERB_WAITSFOR, 1); /* 1 means on */
+ }
+ if (priv->dblayer_debug) {
+ pEnv->set_errcall(pEnv, dblayer_log_print);
+ }
+
+ /* shm_key required for named_regions (DB_SYSTEM_MEM) */
+ pEnv->set_shm_key(pEnv, priv->dblayer_shm_key);
+
+ /* increase max number of active transactions */
+ pEnv->set_tx_max(pEnv, priv->dblayer_tx_max);
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3300
+ pEnv->set_alloc(pEnv, malloc, realloc, free);
+
+ /*
+ * The log region is used to store filenames and so needs to be
+ * increased in size from the default for a large number of files.
+ */
+ pEnv->set_lg_regionmax(pEnv, 1 * 1048576); /* 1 MB */
+#endif
+}
+
+/* returns system pagesize (in bytes) and the number of pages of physical
+ * RAM this machine has.
+ * as a bonus, if 'procpages' is non-NULL, it will be filled in with the
+ * approximate number of pages this process is using!
+ * on platforms that we haven't figured out how to do this yet, both fields
+ * are filled with zero and you're on your own.
+ *
+ * platforms supported so far:
+ * Solaris, Linux, Windows
+ */
+#ifdef OS_solaris
+#include <sys/procfs.h>
+#include <sys/resource.h>
+#endif
+#ifdef LINUX
+#include <linux/kernel.h>
+#include <linux/sys.h>
+#include <sys/sysinfo.h> /* undocumented (?) */
+#include <sys/resource.h>
+#endif
+#if defined ( hpux )
+#include <sys/pstat.h>
+#include <sys/resource.h>
+#endif
+
+#if !defined(_WIN32)
+static size_t dblayer_getvirtualmemsize()
+{
+ struct rlimit rl;
+
+ /* the maximum size of a process's total available memory, in bytes */
+ getrlimit(RLIMIT_AS, &rl);
+ return rl.rlim_cur;
+}
+#endif
+
+/* pages = number of pages of physical ram on the machine (corrected for 32-bit build on 64-bit machine).
+ * procpages = pages currently used by this process (or working set size, sometimes)
+ * availpages = some notion of the number of pages 'free'. Typically this number is not useful.
+ */
+void dblayer_sys_pages(size_t *pagesize, size_t *pages, size_t *procpages, size_t *availpages)
+{
+ *pagesize = *pages = *availpages = 0;
+ if (procpages)
+ *procpages = 0;
+
+#ifdef _WIN32
+ {
+ SYSTEM_INFO si;
+ MEMORYSTATUS ms;
+
+ GetSystemInfo(&si);
+ ms.dwLength = sizeof(ms);
+ GlobalMemoryStatus(&ms);
+ *pagesize = si.dwPageSize;
+ *pages = ms.dwTotalPhys / si.dwPageSize;
+ *availpages = ms.dwAvailVirtual / *pagesize;
+ if (procpages) {
+ DWORD minwss = 0, maxwss = 0;
+
+ GetProcessWorkingSetSize(GetCurrentProcess(), &minwss, &maxwss);
+ *procpages = (int)(maxwss / si.dwPageSize);
+ }
+ }
+#endif
+
+#ifdef OS_solaris
+ *pagesize = (int)sysconf(_SC_PAGESIZE);
+ *pages = (int)sysconf(_SC_PHYS_PAGES);
+ *availpages = dblayer_getvirtualmemsize() / *pagesize;
+ /* solaris has THE most annoying way to get this info */
+ if (procpages) {
+ struct prpsinfo psi;
+ char fn[40];
+ int fd;
+
+ sprintf(fn, "/proc/%d", getpid());
+ fd = open(fn, O_RDONLY);
+ if (fd >= 0) {
+ memset(&psi, 0, sizeof(psi));
+ if (ioctl(fd, PIOCPSINFO, (void *)&psi) == 0)
+ *procpages = psi.pr_size;
+ close(fd);
+ }
+ }
+#endif
+
+#ifdef LINUX
+ {
+ struct sysinfo si;
+ size_t pages_per_mem_unit = 0;
+ size_t mem_units_per_page = 0; /* We don't know if these units are really pages */
+
+ sysinfo(&si);
+ *pagesize = getpagesize();
+ if (si.mem_unit > *pagesize) {
+ pages_per_mem_unit = si.mem_unit / *pagesize;
+ *pages = si.totalram * pages_per_mem_unit;
+ } else {
+ mem_units_per_page = *pagesize / si.mem_unit;
+ *pages = si.totalram / mem_units_per_page;
+ }
+ *availpages = dblayer_getvirtualmemsize() / *pagesize;
+ /* okay i take that back, linux's method is more retarded here.
+ * hopefully linux doesn't have the FILE* problem that solaris does
+ * (where you can't use FILE if you have more than 256 fd's open)
+ */
+ if (procpages) {
+ FILE *f;
+ char fn[40], s[80];
+
+ sprintf(fn, "/proc/%d/status", getpid());
+ f = fopen(fn, "r");
+ while (! feof(f)) {
+ fgets(s, 79, f);
+ if (feof(f))
+ break;
+ if (strncmp(s, "VmSize:", 7) == 0) {
+ sscanf(s+7, "%d", procpages);
+ break;
+ }
+ }
+ fclose(f);
+ /* procpages is now in 1k chunks, not pages... */
+ *procpages /= (*pagesize / 1024);
+ }
+ }
+#endif
+
+#if defined ( hpux )
+ {
+ struct pst_static pst;
+ struct pst_dynamic pst_dyn;
+ int rval = pstat_getstatic(&pst, sizeof(pst), (size_t)1, 0);
+ if (rval < 0) /* pstat_getstatic failed */
+ return;
+ *pagesize = pst.page_size;
+ *pages = pst.physical_memory;
+ *availpages = dblayer_getvirtualmemsize() / *pagesize;
+ rval = pstat_getdynamic(&pst_dyn, sizeof(pst_dyn), (size_t)1, 0);
+ if (rval < 0) /* pstat_getdynamic failed */
+ return;
+ if (procpages)
+ {
+#define BURST (size_t)32 /* get BURST proc info at one time... */
+ struct pst_status psts[BURST];
+ int i, count;
+ int idx = 0; /* index within the context */
+ int mypid = getpid();
+
+ *procpages = 0;
+ /* loop until count == 0, will occur all have been returned */
+ while ((count = pstat_getproc(psts, sizeof(psts[0]), BURST, idx)) > 0) {
+ /* got count (max of BURST) this time. process them */
+ for (i = 0; i < count; i++) {
+ if (psts[i].pst_pid == mypid)
+ {
+ *procpages = (size_t)(psts[i].pst_dsize + psts[i].pst_tsize + psts[i].pst_ssize);
+ break;
+ }
+ }
+ if (i < count)
+ break;
+
+ /*
+ * now go back and do it again, using the next index after
+ * the current 'burst'
+ */
+ idx = psts[count-1].pst_idx + 1;
+ }
+ }
+ }
+#endif
+ /* If this is a 32-bit build, it might be running on a 64-bit machine,
+ * in which case, if the box has tons of ram, we can end up telling
+ * the auto cache code to use more memory than the process can address.
+ * so we cap the number returned here.
+ */
+#if defined(__LP64__) || defined (_LP64)
+#else
+ {
+ size_t one_gig_pages = GIGABYTE / *pagesize;
+ if (*pages > (2 * one_gig_pages) ) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"More than 2Gbytes physical memory detected. Since this is a 32-bit process, truncating memory size used for auto cache calculations to 2Gbytes\n",
+ 0, 0, 0);
+ *pages = (2 * one_gig_pages);
+ }
+ }
+#endif
+}
+
+
+int dblayer_is_cachesize_sane(size_t *cachesize)
+{
+ size_t pages = 0, pagesize = 0, procpages = 0, availpages = 0;
+ int issane = 1;
+
+ dblayer_sys_pages(&pagesize, &pages, &procpages, &availpages);
+ if (!pagesize || !pages)
+ return 1; /* do nothing when we can't get the avail mem */
+ /* If the requested cache size is larger than the remaining pysical memory
+ * after the current working set size for this process has been subtracted,
+ * then we say that's insane and try to correct.
+ */
+ issane = (int)(*cachesize / pagesize) <= (pages - procpages);
+ if (!issane) {
+ *cachesize = (size_t)((pages - procpages) * pagesize);
+ }
+ /* We now compensate for DB's own compensation for metadata size
+ * They increase the actual cache size by 25%, but only for sizes
+ * less than 500Meg.
+ */
+ if (*cachesize < 500*MEGABYTE) {
+ *cachesize = (size_t)((double)*cachesize * (double)0.8);
+ }
+
+ return issane;
+}
+
+
+static void dblayer_dump_config_tracing(dblayer_private *priv)
+{
+ if (priv->dblayer_home_directory) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"home_directory=%s\n",priv->dblayer_home_directory,0,0);
+ }
+ if (priv->dblayer_log_directory) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"log_directory=%s\n",priv->dblayer_log_directory,0,0);
+ }
+ if (priv->dblayer_dbhome_directory) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"dbhome_directory=%s\n",priv->dblayer_dbhome_directory,0,0);
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"trickle_percentage=%d\n",priv->dblayer_trickle_percentage,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"page_size=%lu\n",priv->dblayer_page_size,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"index_page_size=%lu\n",priv->dblayer_index_page_size,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"cachesize=%lu\n",priv->dblayer_cachesize,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"previous_cachesize=%lu\n",priv->dblayer_previous_cachesize,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"ncache=%d\n",priv->dblayer_ncache,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"previous_ncache=%d\n",priv->dblayer_previous_ncache,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"recovery_required=%d\n",priv->dblayer_recovery_required,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"durable_transactions=%d\n",priv->dblayer_durable_transactions,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"checkpoint_interval=%d\n",priv->dblayer_checkpoint_interval,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"transaction_batch_val=%d\n",trans_batch_limit,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"circular_logging=%d\n",priv->dblayer_circular_logging,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"idl_divisor=%d\n",priv->dblayer_idl_divisor,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"logfile_size=%lu\n",priv->dblayer_logfile_size,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"logbuf_size=%lu\n",priv->dblayer_logbuf_size,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"file_mode=%d\n",priv->dblayer_file_mode,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"cache_config=%d\n",priv->dblayer_cache_config,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"lib_version=%d\n",priv->dblayer_lib_version,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"spin_count=%d\n",priv->dblayer_spin_count,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"named_regions=%d\n",priv->dblayer_named_regions,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"private mem=%d\n",priv->dblayer_private_mem,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"private import mem=%d\n",priv->dblayer_private_import_mem,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"shm_key=%ld\n",priv->dblayer_shm_key,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"lockdown=%d\n",priv->dblayer_lockdown,0,0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"tx_max=%d\n",priv->dblayer_tx_max,0,0);
+}
+
+/* Check a given filesystem directory for access we need */
+#define DBLAYER_DIRECTORY_READ_ACCESS 1
+#define DBLAYER_DIRECTORY_WRITE_ACCESS 2
+#define DBLAYER_DIRECTORY_READWRITE_ACCESS 3
+static int dblayer_grok_directory(char *directory, int flags)
+{
+ /* First try to open the directory using NSPR */
+ /* If that fails, we can tell whether it's because it cannot be created or
+ * we don't have any permission to access it */
+ /* If that works, proceed to try to access files in the directory */
+ char filename[MAXPATHLEN];
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ PRFileInfo info;
+
+ dirhandle = PR_OpenDir(directory);
+ if (NULL == dirhandle)
+ {
+ /* it does not exist or wrong file is there */
+ /* try delete and mkdir */
+ PR_Delete(directory);
+ return mkdir_p(directory, 0700);
+ }
+
+ while (NULL !=
+ (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
+ if (NULL == direntry->name)
+ {
+ break;
+ }
+ sprintf(filename,"%s/%s",directory,direntry->name);
+
+ /* Right now this is set up to only look at files here.
+ * With multiple instances of the backend the are now other directories
+ * in the db home directory. This function wasn't ment to deal with
+ * other directories, so we skip them. */
+ if (PR_GetFileInfo(filename, &info) == PR_SUCCESS &&
+ info.type == PR_FILE_DIRECTORY) {
+ /* go into it (instance dir) */
+ int retval = dblayer_grok_directory(filename, flags);
+ PR_CloseDir(dirhandle);
+ return retval;
+ }
+
+ /* If we are here, it means that the directory exists, that we can read
+ * from it, and that there is at least one file there */
+ /* We will try to open that file now if we were asked for read access */
+ if (flags) {
+ PRFileDesc *prfd;
+ PRIntn open_flags = 0;
+ char *access_string = NULL;
+
+ if (DBLAYER_DIRECTORY_READ_ACCESS & flags) {
+ open_flags = PR_RDONLY;
+ }
+ if (DBLAYER_DIRECTORY_WRITE_ACCESS & flags) {
+ open_flags = PR_RDWR;
+ }
+ /* Let's hope that on Solaris we get to open large files OK */
+ prfd = PR_Open(filename,open_flags,0);
+ if (NULL == prfd) {
+ if (DBLAYER_DIRECTORY_READ_ACCESS == flags) {
+ access_string = "read";
+ } else {
+ if (DBLAYER_DIRECTORY_READ_ACCESS & flags) {
+ access_string = "write";
+ } else {
+ access_string = "****";
+ }
+ }
+ /* If we're here, it means that we did not have the requested
+ * permission on this file */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "WARNING---no %s permission to file %s\n",
+ access_string,filename,0);
+ } else {
+ PR_Close(prfd); /* okay */
+ }
+ }
+ }
+ PR_CloseDir(dirhandle);
+ return 0;
+}
+
+static void
+dblayer_set_data_dir(dblayer_private *priv, struct dblayer_private_env *pEnv,
+ char **data_directories)
+{
+ char **dirp;
+
+ if (!(pEnv->dblayer_priv_flags & DBLAYER_PRIV_SET_DATA_DIR))
+ {
+ for (dirp = data_directories; dirp && *dirp; dirp++)
+ {
+ pEnv->dblayer_DB_ENV->set_data_dir(pEnv->dblayer_DB_ENV, *dirp);
+ }
+ pEnv->dblayer_priv_flags |= DBLAYER_PRIV_SET_DATA_DIR;
+ }
+}
+
+static int
+dblayer_inst_exists(ldbm_instance *inst, char *dbname)
+{
+ PRStatus prst;
+ char id2entry_file[MAXPATHLEN];
+ char *parent_dir = inst->inst_parent_dir_name;
+ char sep = get_sep(parent_dir);
+ char *dbnamep;
+ if (dbname)
+ dbnamep = dbname;
+ else
+ dbnamep = ID2ENTRY LDBM_FILENAME_SUFFIX;
+ sprintf(id2entry_file, "%s%c%s%c%s", parent_dir, sep, inst->inst_dir_name,
+ sep, dbnamep);
+ prst = PR_Access(id2entry_file, PR_ACCESS_EXISTS);
+ if (PR_SUCCESS == prst)
+ return 1;
+ return 0;
+}
+
+/*
+ * create a new DB_ENV and fill it with the goodies from dblayer_private
+ */
+#define INIT_MAX_DIRS 32
+static int
+dblayer_make_env(struct dblayer_private_env **env, struct ldbminfo *li)
+{
+ dblayer_private *priv = (dblayer_private*)li->li_dblayer_private;
+ struct dblayer_private_env *pEnv;
+ char *home_dir = NULL;
+ int ret;
+ int data_dirs = INIT_MAX_DIRS;
+ Object *inst_obj;
+ ldbm_instance *inst = NULL;
+
+ pEnv =
+ (struct dblayer_private_env *) PR_Calloc(1, sizeof(dblayer_private_env));
+
+ if ((ret = db_env_create(&pEnv->dblayer_DB_ENV, 0)) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR -- Failed to create DB_ENV (returned: %d).\n",
+ ret, 0, 0);
+ }
+
+ DB_ENV_SET_REGION_INIT(pEnv->dblayer_DB_ENV);
+
+ /* Here we overide various system functions called by libdb */
+ ret = dblayer_override_libdb_functions(pEnv->dblayer_DB_ENV, priv);
+ if (ret != 0)
+ return ret;
+
+ if (priv->dblayer_spin_count != 0) {
+ DB_ENV_SET_TAS_SPINS(pEnv->dblayer_DB_ENV, priv->dblayer_spin_count);
+ }
+
+ dblayer_dump_config_tracing(priv);
+
+ /* set data dir to avoid having absolute paths in the transaction log */
+ priv->dblayer_data_directories = NULL;
+ for (inst_obj = objset_first_obj(li->li_instance_set);
+ inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj))
+ {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ if (inst->inst_parent_dir_name)
+ {
+ if (!charray_utf8_inlist(priv->dblayer_data_directories,
+ inst->inst_parent_dir_name))
+ {
+ charray_add(&(priv->dblayer_data_directories),
+ inst->inst_parent_dir_name);
+ }
+ }
+ }
+ home_dir = dblayer_get_home_dir(li, NULL);
+ /* user specified db home */
+ if (!charray_utf8_inlist(priv->dblayer_data_directories, home_dir))
+ {
+ charray_add(&(priv->dblayer_data_directories), home_dir);
+ }
+
+ /* user specified log dir */
+ if (priv->dblayer_log_directory && *(priv->dblayer_log_directory)) {
+ pEnv->dblayer_DB_ENV->set_lg_dir(pEnv->dblayer_DB_ENV,
+ priv->dblayer_log_directory);
+ }
+
+ /* set up cache sizes */
+ dblayer_init_dbenv(pEnv->dblayer_DB_ENV, priv);
+
+ pEnv->dblayer_env_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "checkpointer");
+
+ if (pEnv->dblayer_env_lock) {
+ *env = pEnv;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR -- Failed to create RWLock (returned: %d).\n",
+ ret, 0, 0);
+ }
+
+ return ret;
+}
+
+/* generate an absolute path if the given instance dir is not. */
+char *
+dblayer_get_full_inst_dir(struct ldbminfo *li, ldbm_instance *inst,
+ char *buf, int buflen)
+{
+ char *parent_dir;
+ int mylen;
+
+ if (!inst)
+ return NULL;
+
+ if (inst->inst_parent_dir_name)
+ {
+ parent_dir = inst->inst_parent_dir_name;
+ if (inst->inst_parent_dir_name)
+ {
+ mylen = strlen(parent_dir) + strlen(inst->inst_dir_name) + 2;
+ }
+ else
+ {
+ mylen = strlen(parent_dir) + 1;
+ }
+ }
+ else
+ {
+ parent_dir = dblayer_get_home_dir(li, NULL);
+ mylen = strlen(parent_dir);
+ inst->inst_parent_dir_name = slapi_ch_strdup(parent_dir);
+ }
+
+
+ if (inst->inst_dir_name)
+ {
+ mylen += strlen(inst->inst_dir_name) + 2;
+ if (!buf || mylen > buflen)
+ buf = slapi_ch_malloc(mylen);
+ sprintf(buf, "%s%c%s",
+ parent_dir, get_sep(parent_dir), inst->inst_dir_name);
+ }
+ else if (inst->inst_name)
+ {
+ inst->inst_dir_name = slapi_ch_strdup(inst->inst_name);
+ mylen += strlen(inst->inst_dir_name) + 2;
+ if (!buf || mylen > buflen)
+ buf = slapi_ch_malloc(mylen);
+ sprintf(buf, "%s%c%s",
+ parent_dir, get_sep(parent_dir), inst->inst_dir_name);
+ }
+ else
+ {
+ mylen += 1;
+ if (!buf || mylen > buflen)
+ buf = slapi_ch_malloc(mylen);
+ sprintf(buf, "%s", parent_dir);
+ }
+ return buf;
+}
+
+#if defined( OS_solaris )
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#endif
+
+#if defined( hpux )
+#undef f_type
+#include <sys/types.h>
+#include <sys/statvfs.h>
+#define f_type f_un.f_un_type
+#endif
+
+#if defined( linux )
+#undef f_type
+#include <sys/vfs.h>
+#define f_type f_un.f_un_type
+#endif
+
+static int
+no_diskspace(struct ldbminfo *li)
+{
+ int rval = 0;
+#if defined( OS_solaris ) || defined( hpux )
+ struct statvfs fsbuf;
+ if (statvfs(li->li_directory, &fsbuf) < 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Cannot get file system info; file system corrupted?\n", 0, 0, 0);
+ rval = 1;
+ }
+ else
+ {
+ double fsiz = ((double)fsbuf.f_bavail) * fsbuf.f_frsize;
+ double expected_siz = ((double)li->li_dbcachesize) * 1.5; /* dbcache +
+ region files */
+ if (fsiz < expected_siz)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "No enough space left on device (%lu bytes); "
+ "at least %lu bytes space is needed for db region files\n",
+ fsiz, expected_siz, 0);
+ rval = 1;
+ }
+ }
+#endif
+#if defined( linux )
+ struct statfs fsbuf;
+ if (statfs(li->li_directory, &fsbuf) < 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Cannot get file system info; file system corrupted?\n", 0, 0, 0);
+ rval = 1;
+ }
+ else
+ {
+ double fsiz = ((double)fsbuf.f_bavail) * fsbuf.f_bsize;
+ double expected_siz = ((double)li->li_dbcachesize) * 1.5; /* dbcache +
+ region files */
+ if (fsiz < expected_siz)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "No enough space left on device (%lu bytes); "
+ "at least %lu bytes space is needed for db region files\n",
+ fsiz, expected_siz, 0);
+ rval = 1;
+ }
+ }
+#endif
+ return rval;
+}
+
+/*
+ * This function is called after all the config options have been read in,
+ * so we can do real initialization work here.
+ */
+#define DBCONFLEN 3
+#define CATASTROPHIC (struct dblayer_private_env *)-1
+
+int dblayer_start(struct ldbminfo *li, int dbmode)
+{
+ /*
+ * So, here we open our DB_ENV session. We store it away for future use.
+ * We also check to see if we exited cleanly last time. If we didn't,
+ * we try to recover. If recovery fails, we're hosed.
+ * We also create the thread which handles checkpointing and logfile
+ * truncation here.
+ */
+ int return_value = -1;
+ dblayer_private *priv = NULL;
+ struct dblayer_private_env *pEnv = NULL;
+ char *region_dir = NULL; /* directory to place region files */
+ char *log_dir = NULL; /* directory to place txn log files */
+ int open_flags = 0;
+
+ PR_ASSERT(NULL != li);
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+
+ if (NULL == priv) {
+ /* you didn't call init successfully */
+ return -1;
+ }
+
+ if (NULL != priv->dblayer_env) {
+ if (CATASTROPHIC == priv->dblayer_env) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Error: DB previously failed to start.\n", 0, 0, 0);
+ return -1;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: DB already started.\n", 0, 0, 0);
+ return 0;
+ }
+ }
+
+ /* DBDB we should pick these up in our config routine, and do away with
+ * the li_ one */
+ PR_Lock(li->li_config_mutex);
+ priv->dblayer_home_directory = li->li_directory; /* nsslapd-directory */
+ priv->dblayer_cachesize = li->li_dbcachesize;
+ priv->dblayer_file_mode = li->li_mode;
+ priv->dblayer_ncache = li->li_dbncache;
+ PR_Unlock(li->li_config_mutex);
+
+ /* use nsslapd-db-home-directory (dblayer_dbhome_directory), if set */
+ /* Otherwise, nsslapd-directory (dblayer_home_directory). */
+ region_dir = dblayer_get_home_dir(li, NULL);
+ if (!region_dir || !(*region_dir)) {
+ return -1;
+ }
+
+ /* Check here that the database directory both exists, and that we have
+ * the appropriate access to it */
+ return_value = dblayer_grok_directory(region_dir,
+ DBLAYER_DIRECTORY_READWRITE_ACCESS);
+ if (0 != return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Can't start because the database "
+ "directory \"%s\" either doesn't exist, or is not "
+ "accessible\n", region_dir, 0, 0);
+ return return_value;
+ }
+
+ log_dir = priv->dblayer_log_directory; /* nsslapd-db-logdirectory */
+ if (log_dir && *log_dir) {
+ return_value = dblayer_grok_directory(log_dir,
+ DBLAYER_DIRECTORY_READWRITE_ACCESS);
+ if (0 != return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Can't start because the log "
+ "directory \"%s\" either doesn't exist, or is not "
+ "accessible\n", log_dir, 0, 0);
+ return return_value;
+ }
+ }
+
+ /* Sanity check on cache size on platforms which allow us to figure out
+ * the available phys mem */
+ if (!dblayer_is_cachesize_sane(&(priv->dblayer_cachesize))) {
+ /* Oops---looks like the admin misconfigured, let's warn them */
+ LDAPDebug(LDAP_DEBUG_ANY,"WARNING---Likely CONFIGURATION ERROR---"
+ "dbcachesize is configured to use more than the available "
+ "physical memory, decreased to the largest available size (%lu bytes).\n",
+ priv->dblayer_cachesize, 0, 0);
+ li->li_dbcachesize = priv->dblayer_cachesize;
+ }
+
+ /* fill in DB_ENV stuff from the common configuration */
+ return_value = dblayer_make_env(&pEnv, li);
+ if (return_value != 0)
+ return return_value;
+
+ if ((DBLAYER_NORMAL_MODE|DBLAYER_CLEAN_RECOVER_MODE) & dbmode)
+ {
+ /* Now, we read our metadata */
+ return_value = read_metadata(li);
+ if (0 != return_value) {
+ /* The error message was output by read_metadata() */
+ return -1;
+ }
+ }
+
+ priv->dblayer_env = pEnv;
+
+ open_flags = DB_CREATE | DB_INIT_MPOOL | DB_THREAD;
+
+ if (priv->dblayer_enable_transactions) {
+ open_flags |= (DB_INIT_TXN | DB_INIT_LOG | DB_INIT_LOCK);
+ if (priv->dblayer_recovery_required) {
+ open_flags |= DB_RECOVER;
+ if (DBLAYER_RESTORE_MODE & dbmode) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Recovering database after restore "
+ "from archive.\n", 0, 0, 0);
+ } else if (DBLAYER_CLEAN_RECOVER_MODE & dbmode) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Clean up db environment and start "
+ "from archive.\n", 0, 0, 0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "Detected Disorderly Shutdown last "
+ "time Directory Server was running, recovering "
+ "database.\n", 0, 0, 0);
+ }
+ }
+ switch (dbmode&DBLAYER_RESTORE_MASK) {
+ case DBLAYER_RESTORE_MODE:
+ open_flags |= DB_RECOVER_FATAL;
+ open_flags &= ~DB_RECOVER; /* shouldn't set both */
+ if (!(dbmode & DBLAYER_CMDLINE_MODE))
+ dbmode = DBLAYER_NORMAL_MODE; /* to restart helper threads */
+ break;
+ case DBLAYER_RESTORE_NO_RECOVERY_MODE:
+ open_flags &= ~(DB_RECOVER | DB_RECOVER_FATAL);
+ if (!(dbmode & DBLAYER_CMDLINE_MODE))
+ dbmode = DBLAYER_NORMAL_MODE; /* to restart helper threads */
+ }
+ }
+
+ if (priv->dblayer_private_mem) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "WARNING: Server is running with nsslapd-db-private-mem on; "
+ "No other process is allowed to access the database\n",
+ 0, 0, 0);
+ open_flags |= DB_PRIVATE;
+ }
+
+ if (priv->dblayer_named_regions) {
+ open_flags |= DB_SYSTEM_MEM;
+ }
+
+ if (priv->dblayer_lockdown) {
+ open_flags |= DB_LOCKDOWN;
+ }
+
+
+ /* Is the cache being re-sized ? (If we're just doing an archive or export,
+ * we don't care if the cache is being re-sized) */
+ if ( (priv->dblayer_previous_cachesize || priv->dblayer_previous_ncache) &&
+ ((priv->dblayer_cachesize != priv->dblayer_previous_cachesize) ||
+ (priv->dblayer_ncache != priv->dblayer_previous_ncache)) &&
+ !(dbmode & (DBLAYER_ARCHIVE_MODE|DBLAYER_EXPORT_MODE)) ) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "I'm resizing my cache now...cache was %lu and is now %lu\n",
+ priv->dblayer_previous_cachesize, priv->dblayer_cachesize, 0);
+ dblayer_reset_env(li);
+ /*
+ * Once pEnv->remove (via dblayer_reset_env) has been called,
+ * the DB_ENV (pEnv) needs to be created again.
+ */
+ if ((return_value = dblayer_make_env(&pEnv, li)) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR -- Failed to create DBENV (returned: %d).\n",
+ return_value, 0, 0);
+ }
+ priv->dblayer_env = pEnv;
+ }
+
+ /* transactions enabled and logbuf size greater than sleepycat's default */
+ if(priv->dblayer_enable_transactions && (priv->dblayer_logbuf_size > 0)) {
+ if(priv->dblayer_logbuf_size >= 32768) {
+ pEnv->dblayer_DB_ENV->set_lg_bsize(pEnv->dblayer_DB_ENV,priv->dblayer_logbuf_size);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "using default value for log bufsize because configured value (%lu) is too small.\n",
+ priv->dblayer_logbuf_size, 0, 0);
+ }
+ }
+
+ /* check if there's enough disk space to start */
+ if (no_diskspace(li))
+ {
+ return ENOSPC;
+ }
+
+ dblayer_set_data_dir(priv, pEnv, priv->dblayer_data_directories);
+ /* If we're doing recovery, we MUST open the env single-threaded ! */
+ if ( (open_flags & DB_RECOVER) || (open_flags & DB_RECOVER_FATAL) ) {
+ /* Recover, then close, then open again */
+ int recover_flags = open_flags & ~DB_THREAD;
+
+ if (DBLAYER_CLEAN_RECOVER_MODE & dbmode) /* upgrade case */
+ {
+ DB_ENV *thisenv = pEnv->dblayer_DB_ENV;
+ return_value = thisenv->remove(thisenv, region_dir, DB_FORCE);
+ if (0 != return_value)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dblayer_start: failed to remove old db env "
+ "in %s: %s\n", region_dir,
+ dblayer_strerror(return_value), 0);
+ return return_value;
+ }
+ dbmode = DBLAYER_NORMAL_MODE;
+
+ if ((return_value = dblayer_make_env(&pEnv, li)) != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR -- Failed to create DBENV (returned: %d).\n",
+ return_value, 0, 0);
+ return return_value;
+ }
+ }
+
+ return_value = pEnv->dblayer_DB_ENV->open(
+ pEnv->dblayer_DB_ENV,
+ region_dir,
+ recover_flags,
+ priv->dblayer_file_mode
+ );
+ if (0 != return_value) {
+ if (return_value == ENOMEM) {
+ /*
+ * https://blackflag.mcom.com/show_bug.cgi?id=557319
+ * Crash ns-slapd while running scalab01 after restart slapd
+ */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "mmap in opening database environment (recovery mode) "
+ "failed trying to allocate %lu bytes. (OS err %d - %s)\n",
+ li->li_dbcachesize, return_value, dblayer_strerror(return_value));
+ priv->dblayer_env = CATASTROPHIC;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "Database Recovery Process FAILED. "
+ "The database is not recoverable. err=%d: %s\n",
+ return_value, dblayer_strerror(return_value), 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Please make sure there is enough disk space for "
+ "dbcache (%lu bytes) and db region files\n",
+ li->li_dbcachesize, 0, 0);
+ }
+ return return_value;
+ } else {
+ open_flags &= ~(DB_RECOVER | DB_RECOVER_FATAL);
+ pEnv->dblayer_DB_ENV->close(pEnv->dblayer_DB_ENV, 0);
+ if ((return_value = dblayer_make_env(&pEnv, li)) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR -- Failed to create DBENV (returned: %d).\n",
+ return_value, 0, 0);
+ return return_value;
+ }
+ priv->dblayer_env = pEnv;
+ dblayer_set_data_dir(priv, pEnv, priv->dblayer_data_directories);
+ }
+ }
+
+ if ((!priv->dblayer_durable_transactions) ||
+ ((priv->dblayer_enable_transactions) && (trans_batch_limit > 0))){
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3200
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4100 /* db4.1 and newer */
+ pEnv->dblayer_DB_ENV->set_flags(pEnv->dblayer_DB_ENV, DB_TXN_WRITE_NOSYNC, 1);
+#else /* db3.3 */
+ pEnv->dblayer_DB_ENV->set_flags(pEnv->dblayer_DB_ENV, DB_TXN_NOSYNC, 1);
+#endif
+#else /* older */
+ open_flags |= DB_TXN_NOSYNC;
+#endif
+ }
+ if (!((DBLAYER_IMPORT_MODE|DBLAYER_INDEX_MODE) & dbmode))
+ {
+ pEnv->dblayer_openflags = open_flags;
+ return_value = pEnv->dblayer_DB_ENV->open(
+ pEnv->dblayer_DB_ENV,
+ region_dir,
+ open_flags,
+ priv->dblayer_file_mode
+ );
+
+
+ /* Now attempt to start up the checkpoint and deadlock threads */
+ if ( (DBLAYER_NORMAL_MODE & dbmode ) && (0 == return_value)) {
+ /* update the dbversion file */
+ dbversion_write(li, region_dir, NULL);
+
+ /* if dblayer_close then dblayer_start is called,
+ this flag is set */
+ priv->dblayer_stop_threads = 0;
+ if (0 != (return_value = dblayer_start_deadlock_thread(li))) {
+ return return_value;
+ }
+
+ if (0 != (return_value = dblayer_start_checkpoint_thread(li))) {
+ return return_value;
+ }
+
+ if (0 != (return_value = dblayer_start_log_flush_thread(priv))) {
+ return return_value;
+ }
+
+ if (0 != (return_value = dblayer_start_trickle_thread(li))) {
+ return return_value;
+ }
+
+ if (0 != (return_value = dblayer_start_perf_thread(li))) {
+ return return_value;
+ }
+
+ /* Now open the performance counters stuff */
+ perfctrs_init(li,&(priv->perf_private));
+ }
+ if (return_value != 0) {
+ if (return_value == ENOMEM) {
+ /*
+ * https://blackflag.mcom.com/show_bug.cgi?id=557319
+ * Crash ns-slapd while running scalab01 after restart slapd
+ */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "mmap in opening database environment "
+ "failed trying to allocate %d bytes. (OS err %lu - %s)\n",
+ li->li_dbcachesize, return_value, dblayer_strerror(return_value));
+ priv->dblayer_env = CATASTROPHIC;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Opening database environment (%s) failed. err=%d: %s\n",
+ region_dir, return_value, dblayer_strerror(return_value));
+ }
+ }
+ return return_value;
+ }
+ return 0;
+}
+
+void
+autosize_import_cache(struct ldbminfo *li)
+{
+ /*
+ * default behavior for ldif2db import cache,
+ * nsslapd-import-cache-autosize==-1,
+ * autosize 50% mem to import cache
+ */
+ if (li->li_import_cache_autosize == -1) {
+ li->li_import_cache_autosize = 50;
+ }
+
+ /* sanity check */
+ if (li->li_import_cache_autosize > 100) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "cache autosizing: bad setting, "
+ "import cache autosizing value should not be larger than 100(%).\n"
+ "set: 100(%).\n", NULL, NULL, NULL);
+ li->li_import_cache_autosize = 100;
+ }
+
+ /* autosizing importCache */
+ if (li->li_import_cache_autosize > 0) {
+ size_t pagesize, pages, procpages, availpages;
+
+ dblayer_sys_pages(&pagesize, &pages, &procpages, &availpages);
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_instance_start: "
+ "pagesize: %d, pages: %d, procpages: %d\n",
+ pagesize, pages, procpages);
+ if (pagesize) {
+ char s[32]; /* big enough to hold %ld */
+ int import_pages;
+ int pages_limit = (200 * 1024) / (pagesize/1024);
+ import_pages = (li->li_import_cache_autosize * pages) / 125;
+ /* We don't want to go wild with memory when auto-sizing, cap the
+ * cache size at 200 Megs to try to avoid situations where we
+ * attempt to allocate more memory than there is free page pool for, or
+ * where there's some system limit on the size of process memory
+ */
+ if (import_pages > pages_limit) {
+ import_pages = pages_limit;
+ }
+ LDAPDebug(LDAP_DEBUG_ANY, "cache autosizing: import cache: %dk \n",
+ import_pages*(pagesize/1024), NULL, NULL);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "li_import_cache_autosize: %d, import_pages: %d, pagesize: %d\n",
+ li->li_import_cache_autosize, import_pages,
+ pagesize);
+
+ sprintf(s, "%lu", (unsigned long)(import_pages * pagesize));
+ ldbm_config_internal_set(li, CONFIG_IMPORT_CACHESIZE, s);
+ }
+ }
+}
+
+/* mode is one of
+ * DBLAYER_NORMAL_MODE,
+ * DBLAYER_INDEX_MODE,
+ * DBLAYER_IMPORT_MODE,
+ * DBLAYER_EXPORT_MODE
+ */
+int dblayer_instance_start(backend *be, int mode)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ dblayer_private *priv;
+ struct dblayer_private_env *pEnv;
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = NULL;
+ int return_value;
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ pEnv = priv->dblayer_env;
+ if (CATASTROPHIC == pEnv || NULL == pEnv) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "instance %s: dbenv is not available (0x%x).\n",
+ inst?inst->inst_name:"unknown", pEnv, 0);
+ return -1;
+ }
+
+ if (NULL != inst->inst_id2entry) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: DB instance \"%s\" already started.\n",
+ inst->inst_name, 0, 0);
+ return 0;
+ }
+
+ attrcrypt_init(inst);
+
+ /* Get the name of the directory that holds index files
+ * for this instance. */
+ if (dblayer_get_instance_data_dir(be) != 0) {
+ /* Problem getting the name of the directory that holds the
+ * index files for this instance. */
+ return -1;
+ }
+
+ inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
+ return_value = dblayer_grok_directory(inst_dirp,
+ DBLAYER_DIRECTORY_READWRITE_ACCESS);
+ if (0 != return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Can't start because the database instance "
+ "directory \"%s\" either doesn't exist, "
+ "or the db files are not accessible\n",
+ inst_dirp, 0, 0);
+ goto errout;
+ }
+
+ if (mode & DBLAYER_NORMAL_MODE) {
+ /* In normal mode (not db2ldif, ldif2db, etc.) we need to deal with
+ * the dbversion file here. */
+
+ /* Read the dbversion file if there is one, and create it
+ * if it doesn't exist. */
+ if (dbversion_exists(li, inst_dirp)) {
+ char ldbmversion[LDBM_VERSION_MAXBUF];
+ char dataversion[LDBM_VERSION_MAXBUF];
+
+ if (dbversion_read(li, inst_dirp, ldbmversion, dataversion) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: Unable to read dbversion "
+ "file in %s\n", inst->inst_dir_name, 0, 0);
+ } else {
+ int rval = 0;
+#if defined(UPGRADEDB)
+ /* check the DBVERSION and reset idl-switch if needed (DS6.2) */
+ /* from the next major rel, we won't do this and just upgrade */
+ if (!(li->li_flags & LI_FORCE_MOD_CONFIG))
+ adjust_idl_switch(ldbmversion, li);
+#endif
+
+ /* check to make sure these instance was made with the correct
+ * version. */
+ rval = check_db_inst_version(inst);
+ if (rval & DBVERSION_NOT_SUPPORTED)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Instance %s does not have the "
+ "expected version\n", inst->inst_name, 0, 0);
+ PR_ASSERT(0);
+ return_value = -1;
+ goto errout;
+ }
+ if (rval & DBVERSION_NEED_IDL_OLD2NEW)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Instance %s: idl-switch is new while db idl format is "
+ "old, modify nsslapd-idl-switch in dse.ldif to old\n",
+ inst->inst_name, 0, 0);
+ }
+ if (rval & DBVERSION_NEED_IDL_NEW2OLD)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Instance %s: idl-switch is old while db idl format is "
+ "new, modify nsslapd-idl-switch in dse.ldif to new\n",
+ inst->inst_name, 0, 0);
+ }
+
+ /* record the dataversion */
+ if (dataversion[0] != '\0') {
+ inst->inst_dataversion = slapi_ch_strdup(dataversion);
+ }
+
+ rval = ldbm_upgrade(inst, rval);
+ if (0 != rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Upgrading instance %s failed\n",
+ inst->inst_name, 0, 0);
+ PR_ASSERT(0);
+ return_value = -1;
+ goto errout;
+ }
+ }
+ } else {
+ /* The dbversion file didn't exist, so we'll create one. */
+ dbversion_write(li, inst_dirp, NULL);
+ }
+ } /* on import we don't mess with the dbversion file except to write it
+ * when done with the import. */
+
+ /* Now attempt to open id2entry */
+ {
+ char *id2entry_file;
+ int open_flags = 0;
+ DB *dbp;
+ char *subname;
+ struct dblayer_private_env *mypEnv;
+
+ id2entry_file = slapi_ch_malloc(strlen(inst->inst_dir_name) +
+ strlen(ID2ENTRY LDBM_FILENAME_SUFFIX) + 2);
+ sprintf(id2entry_file, "%s/%s", inst->inst_dir_name,
+ ID2ENTRY LDBM_FILENAME_SUFFIX);
+
+ open_flags = DB_CREATE | DB_THREAD;
+
+ /* The subname argument allows applications to have
+ * subdatabases, i.e., multiple databases inside of a single
+ * physical file. This is useful when the logical databases
+ * are both numerous and reasonably small, in order to
+ * avoid creating a large number of underlying files.
+ */
+ subname = NULL;
+ mypEnv = NULL;
+ if (mode & (DBLAYER_IMPORT_MODE|DBLAYER_INDEX_MODE)) {
+ size_t cachesize;
+ char *data_directories[2] = {0, 0};
+ /* [605974] delete DB_PRIVATE:
+ * to make import visible to the other process */
+ int oflags = DB_CREATE | DB_INIT_MPOOL | DB_THREAD;
+ /*
+ * but nsslapd-db-private-import-mem should work with import,
+ * as well */
+ if (priv->dblayer_private_import_mem) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "WARNING: Import is running with "
+ "nsslapd-db-private-import-mem on; "
+ "No other process is allowed to access the database\n",
+ 0, 0, 0);
+ oflags |= DB_PRIVATE;
+ }
+ PR_Lock(li->li_config_mutex);
+ if ((li->li_flags & TASK_RUNNING_FROM_COMMANDLINE) &&
+ (li->li_import_cache_autosize)) /* Autosizing importCache
+ * Need to re-eval every time
+ * to guarantee the memory is
+ * really available
+ * (just for command line I/F)
+ */
+ {
+ autosize_import_cache(li);
+ }
+ cachesize = li->li_import_cachesize;
+ PR_Unlock(li->li_config_mutex);
+
+ if (cachesize < 1048576) {
+ /* make it at least 1M */
+ cachesize = 1048576;
+ }
+ priv->dblayer_cachesize = cachesize;
+ /* We always auto-calculate ncache for the import region */
+ priv->dblayer_ncache = 0;
+
+ /* use our own env */
+ return_value = dblayer_make_env(&mypEnv, li);
+ if (return_value != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Unable to create new DB_ENV for import/export! %d\n",
+ return_value, 0, 0);
+ goto out;
+ }
+ /* do not assume import cache size is under 1G */
+ mypEnv->dblayer_DB_ENV->set_cachesize(mypEnv->dblayer_DB_ENV,
+ cachesize/GIGABYTE,
+ cachesize%GIGABYTE,
+ priv->dblayer_ncache);
+ /* probably want to change this -- but for now, create the
+ * mpool files in the instance directory.
+ */
+ mypEnv->dblayer_openflags = oflags;
+ data_directories[0] = inst->inst_parent_dir_name;
+ dblayer_set_data_dir(priv, mypEnv, data_directories);
+ return_value = mypEnv->dblayer_DB_ENV->open(mypEnv->dblayer_DB_ENV,
+ inst_dirp,
+ oflags,
+ priv->dblayer_file_mode);
+ if (return_value != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Unable to open new DB_ENV for import/export! %d\n",
+ return_value, 0, 0);
+ goto out;
+ }
+ inst->import_env = mypEnv;
+ } else {
+ mypEnv = pEnv;
+ }
+
+ inst->inst_id2entry = NULL;
+ return_value = db_create(&inst->inst_id2entry, mypEnv->dblayer_DB_ENV, 0);
+ if (0 != return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Unable to create id2entry db file! %d\n",
+ return_value, 0, 0);
+ goto out;
+ }
+ dbp = inst->inst_id2entry;
+
+ return_value = dbp->set_pagesize(dbp,
+ (priv->dblayer_page_size == 0) ? DBLAYER_PAGESIZE :
+ priv->dblayer_page_size);
+ if (0 != return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dbp->set_pagesize(%lu or %lu) failed %d\n",
+ priv->dblayer_page_size, DBLAYER_PAGESIZE,
+ return_value);
+ goto out;
+ }
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 3300
+ return_value = dbp->set_malloc(dbp, malloc);
+ if (0 != return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dbp->set_malloc failed %d\n",
+ return_value, 0, 0);
+
+ goto out;
+ }
+#endif
+ if ((charray_get_index(priv->dblayer_data_directories,
+ inst->inst_parent_dir_name) != 0) &&
+ !dblayer_inst_exists(inst, NULL))
+ {
+ char *abs_id2entry_file = NULL;
+ int abs_len;
+ /* create a file with abs path, then try again */
+
+ abs_len = strlen(inst_dirp) +
+ strlen(ID2ENTRY LDBM_FILENAME_SUFFIX) + 2;
+ abs_id2entry_file = (char *)slapi_ch_malloc(abs_len);
+ sprintf(abs_id2entry_file, "%s%c%s", inst_dirp,
+ get_sep(inst_dirp), ID2ENTRY LDBM_FILENAME_SUFFIX);
+ DB_OPEN(mypEnv->dblayer_openflags,
+ dbp, NULL/* txnid */, abs_id2entry_file, subname, DB_BTREE,
+ open_flags, priv->dblayer_file_mode, return_value);
+ dbp->close(dbp, 0);
+ return_value = db_create(&inst->inst_id2entry,
+ mypEnv->dblayer_DB_ENV, 0);
+ if (0 != return_value)
+ goto out;
+ dbp = inst->inst_id2entry;
+ slapi_ch_free_string(&abs_id2entry_file);
+ }
+ DB_OPEN(mypEnv->dblayer_openflags,
+ dbp, NULL/* txnid */, id2entry_file, subname, DB_BTREE,
+ open_flags, priv->dblayer_file_mode, return_value);
+ if (0 != return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dbp->open(\"%s\") failed: %s (%d)\n",
+ id2entry_file, dblayer_strerror(return_value),
+ return_value);
+ /* if it's a newly created backend instance,
+ * need to check the inst_parent_dir already exists and
+ * set as a data dir */
+ if (strstr(dblayer_strerror(return_value),
+ "No such file or directory"))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Instance %s is not registered as a db data directory. "
+ "Please restart the server to create it.\n",
+ inst?inst->inst_name:"unknown", pEnv, 0);
+ }
+ else if (strstr(dblayer_strerror(return_value),
+ "Permission denied"))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Instance directory %s may not be writable\n",
+ inst_dirp, 0, 0);
+ }
+
+ goto out;
+ }
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR == 4100
+ /* lower the buffer cache priority to avoid sleep in memp_alloc */
+ /* W/ DB_PRIORITY_LOW, the db buffer page priority is calculated as:
+ * priority = lru_count + pages / (-1)
+ * (by default, priority = lru_count)
+ * When upgraded to db4.2, this setting may not needed, hopefully.
+ * ask sleepycat [#8301]; blackflag #619964
+ */
+ dbp->set_cache_priority(dbp, DB_PRIORITY_LOW);
+#endif
+out:
+ slapi_ch_free((void**)&id2entry_file);
+ }
+
+ if (0 == return_value) {
+ /* get nextid from disk now */
+ get_ids_from_disk(be);
+ }
+
+ if (mode & DBLAYER_NORMAL_MODE) {
+ dbversion_write(li, inst_dirp, NULL);
+ }
+
+ /*
+ * check if nextid is valid: it only matters if the database is either
+ * being imported or is in normal mode
+ */
+ if (inst->inst_nextid > MAXID && !(mode & DBLAYER_EXPORT_MODE)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_instance_start fail: backend '%s' "
+ "has no IDs left. DATABASE MUST BE REBUILT.\n",
+ be->be_name, 0, 0);
+ return 1;
+ }
+
+ if (return_value != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dblayer_instance_start fail: %s (%d)\n",
+ dblayer_strerror(return_value), return_value, 0);
+ }
+errout:
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ return return_value;
+}
+
+
+/* This returns a DB* for the primary index.
+ * If the database library is non-reentrant, we lock it.
+ * the caller MUST call to unlock the db library once they're
+ * finished with the handle. Luckily, the back-end already has
+ * these semantics for the older dbcache stuff.
+ */
+/* Things have changed since the above comment was
+ * written. The database library is reentrant. */
+int dblayer_get_id2entry(backend *be, DB **ppDB)
+{
+ ldbm_instance *inst;
+
+ PR_ASSERT(NULL != be);
+
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ *ppDB = inst->inst_id2entry;
+ return 0;
+}
+
+int dblayer_release_id2entry(backend *be, DB *pDB)
+{
+ return 0;
+}
+
+#ifdef UPGRADEDB
+/*
+ * dblayer_get_aux_id2entry:
+ * - create a dedicated db env and db handler for id2entry.
+ * - introduced for upgradedb not to share the env and db handler with
+ * other index files to support multiple passes and merge.
+ */
+int dblayer_get_aux_id2entry(backend *be, DB **ppDB, DB_ENV **ppEnv)
+{
+ ldbm_instance *inst;
+ struct dblayer_private_env *mypEnv = NULL;
+ DB *dbp = NULL;
+ int rval = 1;
+ struct ldbminfo *li;
+ dblayer_private *opriv;
+ dblayer_private *priv;
+ char *subname = NULL;
+ int envflags;
+ size_t cachesize;
+ PRFileInfo prfinfo;
+ PRStatus prst;
+ char *id2entry_file;
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = NULL;
+ char *data_directories[2] = {0, 0};
+
+ PR_ASSERT(NULL != be);
+
+ *ppDB = NULL;
+ *ppEnv = NULL;
+ inst = (ldbm_instance *) be->be_instance_info;
+ if (NULL == inst)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "No instance/env: persistent id2entry is not available\n", 0, 0, 0);
+ goto done;
+ }
+
+ li = inst->inst_li;
+ if (NULL == li)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "No ldbm info: persistent id2entry is not available\n", 0, 0, 0);
+ goto done;
+ }
+
+ opriv = li->li_dblayer_private;
+ if (NULL == opriv)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "No dblayer info: persistent id2entry is not available\n", 0, 0, 0);
+ goto done;
+ }
+ priv = (dblayer_private *)slapi_ch_malloc(sizeof(dblayer_private));
+ memcpy(priv, opriv, sizeof(dblayer_private));
+ priv->dblayer_spin_count = 0;
+
+ inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
+ priv->dblayer_home_directory =
+ slapi_ch_malloc(strlen(inst_dirp) + strlen("dbenv") + 2);
+ sprintf(priv->dblayer_home_directory, "%s/dbenv", inst_dirp);
+ priv->dblayer_log_directory = slapi_ch_strdup(priv->dblayer_home_directory);
+
+ prst = PR_GetFileInfo(inst_dirp, &prfinfo);
+ if (PR_FAILURE == prst || PR_FILE_DIRECTORY != prfinfo.type)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "No inst dir: persistent id2entry is not available\n", 0, 0, 0);
+ goto done;
+ }
+
+ prst = PR_GetFileInfo(priv->dblayer_home_directory, &prfinfo);
+ if (PR_SUCCESS == prst)
+ {
+ ldbm_delete_dirs(priv->dblayer_home_directory);
+ }
+ rval = mkdir_p(priv->dblayer_home_directory, 0700);
+ if (0 != rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "can't create env dir: persistent id2entry is not available\n", 0, 0, 0);
+ goto done;
+ }
+
+ /* use our own env */
+ rval = dblayer_make_env(&mypEnv, li);
+ if (rval != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Unable to create new DB_ENV for import/export! %d\n", rval, 0, 0);
+ goto err;
+ }
+
+ envflags = DB_CREATE | DB_INIT_MPOOL | DB_PRIVATE;
+ cachesize = 1048576; /* 1M */
+
+ mypEnv->dblayer_DB_ENV->set_cachesize(mypEnv->dblayer_DB_ENV,
+ 0, cachesize, priv->dblayer_ncache);
+
+ /* probably want to change this -- but for now, create the
+ * mpool files in the instance directory.
+ */
+ mypEnv->dblayer_openflags = envflags;
+ data_directories[0] = inst->inst_parent_dir_name;
+ dblayer_set_data_dir(priv, mypEnv, data_directories);
+ rval = mypEnv->dblayer_DB_ENV->open(mypEnv->dblayer_DB_ENV,
+ priv->dblayer_home_directory, envflags, priv->dblayer_file_mode);
+ if (rval != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Unable to open new DB_ENV for upgradedb/reindex %d\n", rval, 0, 0);
+ goto err;
+ }
+ *ppEnv = mypEnv->dblayer_DB_ENV;
+
+ rval = db_create(&dbp, mypEnv->dblayer_DB_ENV, 0);
+ if (0 != rval) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Unable to create id2entry db handler! %d\n", rval, 0, 0);
+ goto err;
+ }
+
+ rval = dbp->set_pagesize(dbp, (priv->dblayer_page_size == 0) ?
+ DBLAYER_PAGESIZE : priv->dblayer_page_size);
+ if (0 != rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dbp->set_pagesize(%lu or %lu) failed %d\n",
+ priv->dblayer_page_size, DBLAYER_PAGESIZE, rval);
+ goto err;
+ }
+
+ id2entry_file = slapi_ch_malloc(strlen(inst->inst_dir_name) +
+ strlen(ID2ENTRY LDBM_FILENAME_SUFFIX) + 2);
+ sprintf(id2entry_file, "%s/%s",
+ inst->inst_dir_name, ID2ENTRY LDBM_FILENAME_SUFFIX);
+
+ PR_ASSERT(dblayer_inst_exists(inst, NULL));
+ DB_OPEN(mypEnv->dblayer_openflags,
+ dbp, NULL/* txnid */, id2entry_file, subname, DB_BTREE,
+ 0, priv->dblayer_file_mode, rval);
+ if (0 != rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dbp->open(\"%s\") failed: %s (%d)\n",
+ id2entry_file, dblayer_strerror(rval), rval);
+ if (strstr(dblayer_strerror(rval), "Permission denied"))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Instance directory %s may not be writable\n", inst_dirp, 0, 0);
+ }
+ goto err;
+ }
+ *ppDB = dbp;
+ goto done;
+err:
+ if (*ppEnv)
+ (*ppEnv)->close(*ppEnv, 0);
+ if (priv->dblayer_home_directory)
+ ldbm_delete_dirs(priv->dblayer_home_directory);
+done:
+ slapi_ch_free_string(&id2entry_file);
+ slapi_ch_free_string(&priv->dblayer_home_directory);
+ slapi_ch_free_string(&priv->dblayer_log_directory);
+ /* Don't free priv->dblayer_data_directories since priv doesn't own the memory */
+ slapi_ch_free((void **)&priv);
+ slapi_ch_free((void **)&mypEnv);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ return rval;
+}
+
+int dblayer_release_aux_id2entry(backend *be, DB *pDB, DB_ENV *pEnv)
+{
+ ldbm_instance *inst;
+ char *envdir = NULL;
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = NULL;
+
+ inst = (ldbm_instance *) be->be_instance_info;
+ if (NULL == inst)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "No instance/env: persistent id2entry is not available\n", 0, 0, 0);
+ goto done;
+ }
+
+ inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ inst_dir, MAXPATHLEN);
+ envdir = slapi_ch_malloc(strlen(inst_dirp) + strlen("dbenv") + 2);
+ sprintf(envdir, "%s/dbenv", inst_dirp);
+
+done:
+ if (pDB)
+ pDB->close(pDB, 0);
+ if (pEnv)
+ pEnv->close(pEnv, 0);
+ if (envdir)
+ ldbm_delete_dirs(envdir);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ return 0;
+}
+#endif
+
+int dblayer_close_indexes(backend *be)
+{
+ ldbm_instance *inst;
+ DB *pDB = NULL;
+ dblayer_handle *handle = NULL;
+ dblayer_handle *next = NULL;
+ int return_value = 0;
+
+ PR_ASSERT(NULL != be);
+ inst = (ldbm_instance *) be->be_instance_info;
+ PR_ASSERT(NULL != inst);
+
+ for (handle = inst->inst_handle_head; handle != NULL; handle = next) {
+ /* Close it, and remove from the list */
+ pDB = handle->dblayer_dbp;
+ return_value |= pDB->close(pDB,0);
+ next = handle->dblayer_handle_next;
+ *(handle->dblayer_handle_ai_backpointer) = NULL;
+ slapi_ch_free((void**)&handle);
+ }
+
+ /* reset the list to make sure we don't use it again */
+ inst->inst_handle_tail = NULL;
+ inst->inst_handle_head = NULL;
+
+ return return_value;
+}
+
+int dblayer_instance_close(backend *be)
+{
+ DB *pDB = NULL;
+ int return_value = 0;
+ DB_ENV * env = 0;
+ ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
+
+ if (NULL == inst)
+ return -1;
+
+ return_value = dblayer_close_indexes(be);
+
+ /* Now close id2entry if it's open */
+ pDB = inst->inst_id2entry;
+ if (NULL != pDB) {
+ return_value |= pDB->close(pDB,0);
+ }
+ inst->inst_id2entry = NULL;
+
+ if (inst->import_env) {
+ /* ignore the value of env, close, because at this point, work is done with import env
+ by calling env.close, env and all the associated db handles will be closed, ignore,
+ if sleepycat complains, that db handles are open at env close time */
+ return_value |= inst->import_env->dblayer_DB_ENV->close(inst->import_env->dblayer_DB_ENV, 0);
+ return_value = db_env_create(&env, 0);
+ if (return_value == 0) {
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ inst_dir, MAXPATHLEN);
+ return_value = env->remove(env, inst_dirp, 0);
+ if (return_value == EBUSY) {
+ return_value = 0; /* something else is using the env so ignore */
+ }
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ }
+ PR_DestroyRWLock(inst->import_env->dblayer_env_lock);
+ PR_Free((void *)inst->import_env);
+ inst->import_env = NULL;
+ } else {
+ be->be_state = BE_STATE_STOPPED;
+ }
+
+ return return_value;
+}
+
+void dblayer_pre_close(struct ldbminfo *li)
+{
+ dblayer_private *priv = 0;
+
+ PR_ASSERT(NULL != li);
+ priv = (dblayer_private*)li->li_dblayer_private;
+
+ if (priv->dblayer_stop_threads) /* already stopped. do nothing... */
+ return;
+
+ /* Now stop the make sure they've stopped,
+ * the various threads we have running */
+ priv->dblayer_stop_threads = 1;
+ if (priv->dblayer_thread_count > 0) {
+ int sleep_counter = 0;
+ /* Print handy-dandy log message */
+ LDAPDebug(LDAP_DEBUG_ANY,"Waiting for %d database threads to stop\n",
+ priv->dblayer_thread_count, 0,0);
+ while(priv->dblayer_thread_count > 0) {
+ /* We have no alternative here but to wait for them to finish,
+ * since if any thread activity,
+ * such as a checkpoint, wasn't finished when we shut down,
+ * the database would need recovery on startup */
+ PRIntervalTime interval;
+
+ sleep_counter++;
+ if (0 == sleep_counter % 10) {
+ if (priv->dblayer_thread_count > 1) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Still waiting on %d database threads...\n",
+ priv->dblayer_thread_count,0,0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Still waiting one database thread...\n",0,0,0);
+ }
+ }
+
+ interval = PR_MillisecondsToInterval(DBLAYER_SLEEP_INTERVAL);
+ DS_Sleep(interval);
+ if (sleep_counter >= 100) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Timeout; leave %d thread(s)...\n",
+ priv->dblayer_thread_count,0,0);
+ /*
+ * The guardian file should not
+ * get created under the timeout condition.
+ */
+ priv->dblayer_bad_stuff_happened = 1;
+ goto timeout_escape;
+ }
+ }
+ LDAPDebug(LDAP_DEBUG_ANY,"All database threads now stopped\n",0,0,0);
+ }
+timeout_escape:
+ return;
+}
+
+int dblayer_post_close(struct ldbminfo *li, int dbmode)
+{
+ dblayer_private *priv = 0;
+ int return_value = 0;
+ dblayer_private_env *pEnv;
+
+ PR_ASSERT(NULL != li);
+ priv = (dblayer_private*)li->li_dblayer_private;
+
+ /* We close all the files we ever opened, and call pEnv->close. */
+ if (NULL == priv->dblayer_env) /* db env is already closed. do nothing. */
+ return return_value;
+ /* Shutdown the performance counter stuff */
+ if (DBLAYER_NORMAL_MODE & dbmode) {
+ if (priv->perf_private) {
+ perfctrs_terminate(&priv->perf_private);
+ }
+ }
+
+ /* Now release the db environment */
+ pEnv = priv->dblayer_env;
+ return_value = pEnv->dblayer_DB_ENV->close(pEnv->dblayer_DB_ENV, 0);
+ PR_DestroyRWLock(priv->dblayer_env->dblayer_env_lock);
+ PR_Free((void *) priv->dblayer_env);
+
+ priv->dblayer_env = NULL; /* pEnv is now garbage */
+
+ if (return_value == 0) {
+ DB_ENV *env = 0;
+ return_value = db_env_create(&env, 0);
+ /* don't be tempted to use the
+ previously nulled out env handle
+ as Sleepycat 3.x is unhappy if
+ the env handle handed to remove
+ was used elsewhere. rwagner */
+ if (return_value == 0) {
+ char *home_dir = dblayer_get_home_dir(li, NULL);
+ if (home_dir)
+ /* DBDB do NOT remove the environment: bad, bad idea
+ * return_value = env->remove(env, home_dir, 0);
+ */
+ if (0 == return_value
+ && !((DBLAYER_ARCHIVE_MODE|DBLAYER_EXPORT_MODE) & dbmode)
+ && !priv->dblayer_bad_stuff_happened) {
+ /*
+ * If we got here, we have a good consistent database,
+ * so we write the guard file
+ */
+ commit_good_database(priv);
+ } else if (return_value == EBUSY) {
+ /* something else is using the env so ignore */
+ /* but let's not make a guardian file */
+ return_value = 0;
+ }
+ }
+ }
+
+ return return_value;
+}
+
+/*
+ * This function is called when the server is shutting down.
+ * This is not safe to call while other threads are calling into the open
+ * databases !!! So: DON'T !
+ */
+int dblayer_close(struct ldbminfo *li, int dbmode)
+{
+ backend *be = NULL;
+ ldbm_instance *inst;
+ Object *inst_obj;
+ int return_value = 0;
+
+ dblayer_pre_close(li);
+
+ /*
+ * dblayer_close_indexes and pDB->close used to be located above loop:
+ * while(priv->dblayer_thread_count > 0) in pre_close.
+ * This order fixes a bug: shutdown under the stress makes txn_checkpoint
+ * (checkpoint_thread) fail b/c the mpool might have been already closed.
+ */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ be = inst->inst_be;
+ if (NULL != be->be_instance_info) {
+ return_value |= dblayer_instance_close(be);
+ }
+ }
+
+ if (return_value != 0) {
+ /* force recovery next startup if any close failed */
+ dblayer_private *priv;
+ PR_ASSERT(NULL != li);
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+ priv->dblayer_bad_stuff_happened = 1;
+ }
+
+ return_value |= dblayer_post_close(li, dbmode);
+
+ return return_value;
+}
+
+/*
+ * Called to tell us to flush any data not on disk to the disk
+ * for the transacted database, we interpret this as an instruction
+ * to write a checkpoint.
+ */
+int dblayer_flush(struct ldbminfo *li)
+{
+ return 0;
+}
+
+#if !defined(DB_DUPSORT)
+#define DB_DUPSORT 0
+#endif
+
+/* Routines for opening and closing random files in the DB_ENV.
+ Used by ldif2db merging code currently.
+
+ Return value:
+ Success: 0
+ Failure: -1
+ */
+int dblayer_open_file(backend *be, char* indexname, int open_flag, int index_flags, DB **ppDB)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ int open_flags = 0;
+ char *file_name = NULL;
+ char *rel_path = NULL;
+ dblayer_private_env *pENV = 0;
+ dblayer_private *priv = NULL;
+ int len;
+ int return_value = 0;
+ DB *dbp = NULL;
+ char *subname = NULL;
+
+ PR_ASSERT(NULL != li);
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ if (NULL == inst->inst_dir_name)
+ {
+ if (dblayer_get_instance_data_dir(be) != 0)
+ return -1;
+ }
+
+ if (NULL != inst->inst_parent_dir_name)
+ {
+ if (!charray_utf8_inlist(priv->dblayer_data_directories,
+ inst->inst_parent_dir_name) &&
+ !is_fullpath(inst->inst_dir_name))
+
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "The instance path %s is not registered for db_data_dir, "
+ "although %s is a relative path.\n",
+ inst->inst_parent_dir_name, inst->inst_dir_name, 0);
+ return -1;
+ }
+ }
+ len = strlen(indexname) + strlen(LDBM_FILENAME_SUFFIX) + 1;
+ file_name = slapi_ch_malloc(len);
+ len += strlen(inst->inst_dir_name) + 1;
+ rel_path = slapi_ch_malloc(len);
+
+ pENV = priv->dblayer_env;
+ if (inst->import_env)
+ pENV = inst->import_env;
+
+ PR_ASSERT(NULL != pENV);
+ sprintf(file_name, "%s%s", indexname, LDBM_FILENAME_SUFFIX);
+ sprintf(rel_path, "%s/%s", inst->inst_dir_name, file_name);
+
+ open_flags = DB_THREAD;
+ if (open_flag & DBOPEN_CREATE)
+ open_flags |= DB_CREATE;
+
+ if (!ppDB)
+ goto out;
+ return_value = db_create(ppDB, pENV->dblayer_DB_ENV, 0);
+ if (0 != return_value)
+ goto out;
+
+ dbp = *ppDB;
+/* With the new idl design, the large 8Kbyte pages we use are not
+ optimal. The page pool churns very quickly as we add new IDs under a
+ sustained add load. Smaller pages stop this happening so much and
+ consequently make us spend less time flushing dirty pages on checkpoints.
+ But 8K is still a good page size for id2entry. So we now allow different
+ page sizes for the primary and secondary indices.
+ Filed as bug: 604654
+ */
+ if (idl_get_idl_new()) {
+ return_value = dbp->set_pagesize(
+ dbp,
+ (priv->dblayer_index_page_size == 0) ?
+ DBLAYER_INDEX_PAGESIZE : priv->dblayer_index_page_size
+ );
+ } else {
+ return_value = dbp->set_pagesize(
+ dbp,
+ (priv->dblayer_page_size == 0) ?
+ DBLAYER_PAGESIZE : priv->dblayer_page_size
+ );
+ }
+ if (0 != return_value)
+ goto out;
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 3300
+ return_value = dbp->set_malloc(dbp, malloc);
+ if (0 != return_value) {
+ goto out;
+ }
+#endif
+
+ if (idl_get_idl_new() && !(index_flags & INDEX_VLV)) {
+ return_value = dbp->set_flags(dbp, DB_DUP | DB_DUPSORT);
+ if (0 != return_value)
+ goto out;
+
+ return_value = dbp->set_dup_compare(
+ dbp,
+ idl_new_compare_dups
+ );
+ if (0 != return_value)
+ goto out;
+ }
+
+ if (index_flags & INDEX_VLV) {
+ /*
+ * Need index with record numbers for
+ * Virtual List View index
+ */
+ return_value = dbp->set_flags(dbp, DB_RECNUM);
+ if (0 != return_value)
+ goto out;
+ }
+
+ /* The subname argument allows applications to have
+ * subdatabases, i.e., multiple databases inside of a single
+ * physical file. This is useful when the logical databases
+ * are both numerous and reasonably small, in order to
+ * avoid creating a large number of underlying files.
+ */
+ if ((charray_get_index(priv->dblayer_data_directories,
+ inst->inst_parent_dir_name) != 0) &&
+ !dblayer_inst_exists(inst, file_name))
+ {
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = NULL;
+ char *abs_file_name = NULL;
+ int abs_len;
+ /* create a file with abs path, then try again */
+
+ inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
+ abs_len = strlen(inst_dirp) + strlen(file_name) + 2;
+ abs_file_name = (char *)slapi_ch_malloc(abs_len);
+ sprintf(abs_file_name, "%s%c%s",
+ inst_dirp, get_sep(inst_dirp), file_name);
+ DB_OPEN(pENV->dblayer_openflags,
+ dbp, NULL/* txnid */, abs_file_name, subname, DB_BTREE,
+ open_flags, priv->dblayer_file_mode, return_value);
+ dbp->close(dbp, 0);
+ return_value = db_create(ppDB, pENV->dblayer_DB_ENV, 0);
+ if (0 != return_value)
+ goto out;
+ dbp = *ppDB;
+
+ slapi_ch_free_string(&abs_file_name);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ }
+ DB_OPEN(pENV->dblayer_openflags,
+ dbp, NULL, /* txnid */ rel_path, subname, DB_BTREE,
+ open_flags, priv->dblayer_file_mode, return_value);
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR == 4100
+ /* lower the buffer cache priority to avoid sleep in memp_alloc */
+ /* W/ DB_PRIORITY_LOW, the db buffer page priority is calculated as:
+ * priority = lru_count + pages / (-1)
+ * (by default, priority = lru_count)
+ * When upgraded to db4.2, this setting may not needed, hopefully.
+ * ask sleepycat [#8301]; blackflag #619964
+ */
+ dbp->set_cache_priority(dbp, DB_PRIORITY_LOW);
+#endif
+out:
+ slapi_ch_free((void**)&file_name);
+ slapi_ch_free((void**)&rel_path);
+ /* close the database handle to avoid handle leak */
+ if (dbp && (return_value != 0)) {
+ dblayer_close_file(dbp);
+ }
+ return return_value;
+}
+
+int dblayer_close_file(DB *db)
+{
+ return db->close(db,0);
+}
+
+/*
+ * OK, this is a tricky one. We store open DB* handles within an AVL
+ * structure used in other parts of the back-end. This is nasty, because
+ * that code has no idea we're doing this, and we don't have much control
+ * over what it does. But, the reason is that we want to get fast lookup
+ * of the index file pertaining to each particular attribute. Putting the
+ * DB* handles in the attribute info structures is an easy way to achieve this
+ * because we already lookup this structure as part of an index lookup.
+ */
+
+/*
+ * This function takes an attrinfo structure and returns a valid
+ * DB* handle for the index file corresponding to this attribute.
+ */
+
+/*
+ * If the db library is non-reentrant, we lock the mutex here,
+ * see comments above for id2entry for the details on this.
+ */
+
+/*
+ * The create flag determines if the index file should be created if it
+ * does not already exist.
+ */
+
+int dblayer_get_index_file(backend *be, struct attrinfo *a, DB** ppDB, int open_flags)
+{
+ /*
+ * We either already have a DB* handle in the attrinfo structure.
+ * in which case we simply return it to the caller, OR:
+ * we need to make one. We do this as follows:
+ * 1a) acquire the mutex that protects the handle list.
+ * 1b) check that the DB* is still null.
+ * 2) get the filename, and call libdb to open it
+ * 3) if successful, store the result in the attrinfo stucture
+ * 4) store the DB* in our own list so we can close it later.
+ * 5) release the mutex.
+ */
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ int return_value = -1;
+ DB *pDB = NULL;
+ char *attribute_name = a->ai_type;
+
+ *ppDB = NULL;
+
+ /* it's like a semaphore -- when count > 0, any file handle that's in
+ * the attrinfo will remain valid from here on.
+ */
+ PR_AtomicIncrement(&a->ai_dblayer_count);
+
+ if (NULL != a->ai_dblayer) {
+ /* This means that the pointer is valid, so we should return it. */
+ *ppDB = ((dblayer_handle*)(a->ai_dblayer))->dblayer_dbp;
+ return 0;
+ }
+
+ /* attrinfo handle is NULL, at least for now -- grab the mutex and try
+ * again.
+ */
+ PR_Lock(inst->inst_handle_list_mutex);
+ if (NULL != a->ai_dblayer) {
+ /* another thread set the handle while we were waiting on the lock */
+ *ppDB = ((dblayer_handle*)(a->ai_dblayer))->dblayer_dbp;
+ PR_Unlock(inst->inst_handle_list_mutex);
+ return 0;
+ }
+
+ /* attrinfo handle is still blank, and we have the mutex: open the
+ * index file and stuff it in the attrinfo.
+ */
+ return_value = dblayer_open_file(be, attribute_name, open_flags,
+ a->ai_indexmask, &pDB);
+ if (0 == return_value) {
+ /* Opened it OK */
+ dblayer_handle *handle = (dblayer_handle *)
+ slapi_ch_calloc(1, sizeof(dblayer_handle));
+
+ if (NULL == handle) {
+ /* Memory allocation failed */
+ return_value = -1;
+ } else {
+ dblayer_handle *prev_handle = inst->inst_handle_tail;
+
+ PR_ASSERT(NULL != pDB);
+ /* Store the returned DB* in our own private list of
+ * open files */
+ if (NULL == prev_handle) {
+ /* List was empty */
+ inst->inst_handle_tail = handle;
+ inst->inst_handle_head = handle;
+ } else {
+ /* Chain the handle onto the last structure in the
+ * list */
+ inst->inst_handle_tail = handle;
+ prev_handle->dblayer_handle_next = handle;
+ }
+ /* Stash a pointer to our wrapper structure in the
+ * attrinfo structure */
+ handle->dblayer_dbp = pDB;
+ /* And, most importantly, return something to the caller!*/
+ *ppDB = pDB;
+ /* and save the hande in the attrinfo structure for
+ * next time */
+ a->ai_dblayer = handle;
+ /* don't need to update count -- we incr'd it already */
+ handle->dblayer_handle_ai_backpointer = &(a->ai_dblayer);
+ }
+ } else {
+ /* Did not open it OK ! */
+ /* Do nothing, because return value and fact that we didn't
+ * store a DB* in the attrinfo is enough
+ */
+ }
+ PR_Unlock(inst->inst_handle_list_mutex);
+
+ if (return_value != 0) {
+ /* some sort of error -- we didn't open a handle at all.
+ * decrement the refcount back to where it was.
+ */
+ PR_AtomicDecrement(&a->ai_dblayer_count);
+ }
+
+ return return_value;
+}
+
+/*
+ * Unlock the db lib mutex here if we need to.
+ */
+int dblayer_release_index_file(backend *be,struct attrinfo *a, DB* pDB)
+{
+ PR_AtomicDecrement(&a->ai_dblayer_count);
+ return 0;
+}
+
+/*
+ dblayer_db_remove assumptions:
+
+ No environment has the given database open.
+
+*/
+
+static int
+dblayer_db_remove_ex(dblayer_private_env *env, char const path[], char const dbName[], PRBool use_lock) {
+ DB_ENV * db_env = 0;
+ int rc;
+ DB *db;
+
+ if (env) {
+ if(use_lock) PR_RWLock_Wlock(env->dblayer_env_lock); /* We will be causing logging activity */
+ db_env = env->dblayer_DB_ENV;
+ }
+
+ rc = db_create(&db, db_env, 0); /* must use new handle to database */
+ if (0 != rc) {
+ LDAPDebug(LDAP_DEBUG_ANY, "db_remove: Failed to create db (%d) %s\n",
+ rc, dblayer_strerror(rc), 0);
+ goto done;
+ }
+ rc = db->remove(db, path, dbName, 0); /* kiss the db goodbye! */
+
+done:
+ if (env) {
+ if(use_lock) PR_RWLock_Unlock(env->dblayer_env_lock);
+ }
+
+ return rc;
+}
+
+
+int
+dblayer_db_remove(dblayer_private_env * env, char const path[], char const dbName[]) {
+ return(dblayer_db_remove_ex(env,path,dbName,PR_TRUE));
+}
+
+#define DBLAYER_CACHE_DELAY PR_MillisecondsToInterval(250)
+int dblayer_erase_index_file_ex(backend *be, struct attrinfo *a,
+ PRBool use_lock, int no_force_checkpoint)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ dblayer_private *priv = (dblayer_private*) li->li_dblayer_private;
+ struct dblayer_private_env *pEnv = priv->dblayer_env;
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ dblayer_handle *handle;
+ char dbName[MAXPATHLEN];
+ char *dbNamep;
+ char *p;
+ int dbbasenamelen, dbnamelen;
+ int rc = 0;
+ DB *db = 0;
+
+ if (NULL == pEnv) /* index file does not exist */
+ return rc;
+
+ /* Added for bug 600401. Somehow the checkpoint thread deadlocked on
+ index file with this function, index file couldn't be removed on win2k.
+ Force a checkpoint here to break deadlock.
+ */
+ if (0 == no_force_checkpoint) {
+ dblayer_force_checkpoint(li);
+ }
+
+ if (dblayer_get_index_file(be, a, &db, DBOPEN_CREATE) == 0) {
+ /* first, remove the file handle for this index, if we have it open */
+ PR_Lock(inst->inst_handle_list_mutex);
+ if (a->ai_dblayer) {
+ /* there is a handle */
+ handle = (dblayer_handle *)a->ai_dblayer;
+
+ /* when we successfully called dblayer_get_index_file we bumped up
+ the reference count of how many threads are using the index. So we
+ must manually back off the count by one here.... rwagner */
+
+ dblayer_release_index_file(be, a, db);
+
+ while (a->ai_dblayer_count > 0) {
+ /* someone is using this index file */
+ /* ASSUMPTION: you have already set the INDEX_OFFLINE flag, because
+ * you intend to mess with this index. therefore no new requests
+ * for this indexfile should happen, so the dblayer_count should
+ * NEVER increase.
+ */
+ PR_ASSERT(a->ai_indexmask & INDEX_OFFLINE);
+ PR_Unlock(inst->inst_handle_list_mutex);
+ DS_Sleep(DBLAYER_CACHE_DELAY);
+ PR_Lock(inst->inst_handle_list_mutex);
+ }
+ dblayer_close_file(handle->dblayer_dbp);
+
+ /* remove handle from handle-list */
+ if (inst->inst_handle_head == handle) {
+ inst->inst_handle_head = handle->dblayer_handle_next;
+ if (inst->inst_handle_tail == handle) {
+ inst->inst_handle_tail = NULL;
+ }
+ } else {
+ dblayer_handle *hp;
+
+ for (hp = inst->inst_handle_head; hp; hp = hp->dblayer_handle_next) {
+ if (hp->dblayer_handle_next == handle) {
+ hp->dblayer_handle_next = handle->dblayer_handle_next;
+ if (inst->inst_handle_tail == handle) {
+ inst->inst_handle_tail = hp;
+ }
+ break;
+ }
+ }
+ }
+ dbNamep = dblayer_get_full_inst_dir(li, inst, dbName, MAXPATHLEN);
+ dbbasenamelen = strlen(dbNamep);
+ dbnamelen = dbbasenamelen + strlen(a->ai_type) + 6;
+ if (dbnamelen > MAXPATHLEN)
+ {
+ dbNamep = (char *)slapi_ch_realloc(dbNamep, dbnamelen);
+ }
+ p = dbNamep + dbbasenamelen;
+ sprintf(p, "%c%s%s", get_sep(dbNamep), a->ai_type, LDBM_FILENAME_SUFFIX);
+ rc = dblayer_db_remove_ex(pEnv, dbNamep, 0, use_lock);
+ a->ai_dblayer = NULL;
+ slapi_ch_free((void **)&handle);
+ if (dbNamep != dbName)
+ slapi_ch_free_string(&dbNamep);
+ } else {
+ /* no handle to close */
+ }
+ PR_Unlock(inst->inst_handle_list_mutex);
+
+ }
+
+ return rc;
+}
+
+int dblayer_erase_index_file_nolock(backend *be, struct attrinfo *a, int no_force_chkpt) {
+ return dblayer_erase_index_file_ex(be,a,PR_FALSE,no_force_chkpt);
+}
+
+int dblayer_erase_index_file(backend *be, struct attrinfo *a, int no_force_chkpt) {
+ return dblayer_erase_index_file_ex(be,a,PR_TRUE,no_force_chkpt);
+}
+
+
+/*
+ * Transaction stuff. The idea is that the caller doesn't need to
+ * know the transaction mechanism underneath (because the caller is
+ * typically a few calls up the stack from any DB stuff).
+ * Sadly, in slapd there was no handy structure associated with
+ * an LDAP operation, and passed around evberywhere, so we had
+ * to invent the back_txn structure.
+ * The lower levels of the back-end look into this structure, and
+ * take out the DB_TXN they need.
+ */
+int dblayer_txn_init(struct ldbminfo *li, back_txn *txn)
+{
+ PR_ASSERT(NULL != txn);
+
+ txn->back_txn_txn = NULL;
+ return 0;
+}
+
+
+int dblayer_txn_begin_ext(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn, PRBool use_lock)
+{
+ int return_value = -1;
+ dblayer_private *priv = NULL;
+ PR_ASSERT(NULL != txn);
+ PR_ASSERT(NULL != li);
+ /*
+ * When server is shutting down, some components need to
+ * flush some data (e.g. replication to write ruv).
+ * So don't check shutdown signal unless we can't write.
+ */
+ if ( g_get_shutdown() == SLAPI_SHUTDOWN_DISKFULL ) {
+ return return_value;
+ }
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ if (priv->dblayer_enable_transactions)
+ {
+ dblayer_private_env *pEnv = priv->dblayer_env;
+ if(use_lock) PR_RWLock_Rlock(pEnv->dblayer_env_lock);
+ return_value = TXN_BEGIN(pEnv->dblayer_DB_ENV,
+ (DB_TXN*)parent_txn,
+ &txn->back_txn_txn,
+ 0);
+ if (0 != return_value)
+ {
+ if(use_lock) PR_RWLock_Unlock(priv->dblayer_env->dblayer_env_lock);
+ txn->back_txn_txn = NULL;
+ }
+ } else
+ {
+ return_value = 0;
+ }
+ if (0 != return_value)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Serious Error---Failed in dblayer_txn_begin, err=%d (%s)\n",
+ return_value, dblayer_strerror(return_value), 0);
+ }
+ return return_value;
+}
+
+int dblayer_read_txn_begin(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn) {
+ return (dblayer_txn_begin_ext(li,parent_txn,txn,PR_FALSE));
+}
+
+int dblayer_txn_begin(struct ldbminfo *li, back_txnid parent_txn, back_txn *txn) {
+ return (dblayer_txn_begin_ext(li,parent_txn,txn,PR_TRUE));
+}
+
+
+int dblayer_txn_commit_ext(struct ldbminfo *li, back_txn *txn, PRBool use_lock)
+{
+ int return_value = -1;
+ dblayer_private *priv = NULL;
+ DB_TXN *db_txn;
+
+ PR_ASSERT(NULL != txn);
+ PR_ASSERT(NULL != li);
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ db_txn = txn->back_txn_txn;
+ if (NULL != db_txn &&
+ 1 != priv->dblayer_stop_threads &&
+ priv->dblayer_env &&
+ priv->dblayer_enable_transactions)
+ {
+ return_value = TXN_COMMIT(db_txn, 0);
+ if ((priv->dblayer_durable_transactions) && use_lock ) {
+ if(trans_batch_limit > 0) {
+ if(trans_batch_count % trans_batch_limit) {
+ trans_batch_count++;
+ } else {
+ LOG_FLUSH(priv->dblayer_env->dblayer_DB_ENV,0);
+ trans_batch_count=1;
+ }
+ } else if(trans_batch_limit == FLUSH_REMOTEOFF) { /* user remotely turned batching off */
+ LOG_FLUSH(priv->dblayer_env->dblayer_DB_ENV,0);
+ }
+ }
+ if(use_lock) PR_RWLock_Unlock(priv->dblayer_env->dblayer_env_lock);
+ } else
+ {
+ return_value = 0;
+ }
+
+ if (0 != return_value)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Serious Error---Failed in dblayer_txn_commit, err=%d (%s)\n",
+ return_value, dblayer_strerror(return_value), 0);
+ if (LDBM_OS_ERR_IS_DISKFULL(return_value)) {
+ operation_out_of_disk_space();
+ }
+ }
+ return return_value;
+}
+
+int dblayer_read_txn_commit(struct ldbminfo *li, back_txn *txn) {
+ return(dblayer_txn_commit_ext(li,txn,PR_FALSE));
+}
+
+int dblayer_txn_commit(struct ldbminfo *li, back_txn *txn) {
+ return(dblayer_txn_commit_ext(li,txn,PR_TRUE));
+}
+
+int dblayer_txn_abort_ext(struct ldbminfo *li, back_txn *txn, PRBool use_lock)
+{
+ int return_value = -1;
+ dblayer_private *priv = NULL;
+ DB_TXN *db_txn;
+
+ PR_ASSERT(NULL != txn);
+ PR_ASSERT(NULL != li);
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ db_txn = txn->back_txn_txn;
+ if (NULL != db_txn &&
+ priv->dblayer_env &&
+ priv->dblayer_enable_transactions)
+ {
+ return_value = TXN_ABORT(db_txn);
+ if(use_lock) PR_RWLock_Unlock(priv->dblayer_env->dblayer_env_lock);
+ } else
+ {
+ return_value = 0;
+ }
+
+ if (0 != return_value)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Serious Error---Failed in dblayer_txn_abort, err=%d (%s)\n",
+ return_value, dblayer_strerror(return_value), 0);
+ if (LDBM_OS_ERR_IS_DISKFULL(return_value)) {
+ operation_out_of_disk_space();
+ }
+ }
+ return return_value;
+}
+
+int dblayer_read_txn_abort(struct ldbminfo *li, back_txn *txn){
+ return(dblayer_txn_abort_ext(li,txn,PR_FALSE));
+}
+
+int dblayer_txn_abort(struct ldbminfo *li, back_txn *txn){
+ return(dblayer_txn_abort_ext(li,txn,PR_TRUE));
+}
+
+
+size_t dblayer_get_optimal_block_size(struct ldbminfo *li)
+{
+ dblayer_private *priv = NULL;
+ size_t page_size = 0;
+
+ PR_ASSERT(NULL != li);
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ page_size = (priv->dblayer_page_size == 0) ? DBLAYER_PAGESIZE : priv->dblayer_page_size;
+ if (priv->dblayer_idl_divisor == 0)
+ {
+ return page_size - DB_EXTN_PAGE_HEADER_SIZE;
+ } else
+ {
+ return page_size / priv->dblayer_idl_divisor;
+ }
+}
+
+
+/*
+ * The dblock serializes writes to the database,
+ * which reduces deadlocking in the db code,
+ * which means that we run faster.
+ */
+void dblayer_lock_backend(backend *be)
+{
+ ldbm_instance *inst;
+
+ PR_ASSERT(NULL != be);
+ inst = (ldbm_instance *) be->be_instance_info;
+ PR_ASSERT(NULL != inst);
+
+ if (NULL != inst->inst_db_mutex) {
+ PR_Lock(inst->inst_db_mutex);
+ }
+}
+
+void dblayer_unlock_backend(backend *be)
+{
+ ldbm_instance *inst;
+
+ PR_ASSERT(NULL != be);
+ inst = (ldbm_instance *) be->be_instance_info;
+ PR_ASSERT(NULL != inst);
+
+ if (NULL != inst->inst_db_mutex) {
+ PR_Unlock(inst->inst_db_mutex);
+ }
+}
+
+
+/* code which implements checkpointing and log file truncation */
+
+/*
+ * create a thread for perf_threadmain
+ */
+static int
+dblayer_start_perf_thread(struct ldbminfo *li)
+{
+ int return_value = 0;
+ if (NULL == PR_CreateThread (PR_USER_THREAD,
+ (VFP) (void *) perf_threadmain, li,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE) )
+ {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY, "failed to create database perf thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ return_value = -1;
+ }
+ return return_value;
+}
+
+/* Performance thread */
+static int perf_threadmain(void *param)
+{
+ dblayer_private *priv = NULL;
+ struct ldbminfo *li = NULL;
+
+ PR_ASSERT(NULL != param);
+ li = (struct ldbminfo*)param;
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+ PR_AtomicIncrement(&(priv->dblayer_thread_count));
+ while (!priv->dblayer_stop_threads) {
+ /* sleep for a while, updating perf counters if we need to */
+ perfctrs_wait(1000,priv->perf_private,priv->dblayer_env->dblayer_DB_ENV);
+ }
+ PR_AtomicDecrement(&(priv->dblayer_thread_count));
+ return 0;
+}
+
+/*
+ * create a thread for deadlock_threadmain
+ */
+static int
+dblayer_start_deadlock_thread(struct ldbminfo *li)
+{
+ int return_value = 0;
+ if (NULL == PR_CreateThread (PR_USER_THREAD,
+ (VFP) (void *) deadlock_threadmain, li,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE) )
+ {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY, "failed to create database deadlock thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ return_value = -1;
+ }
+ return return_value;
+}
+
+/* checkpoint thread main function */
+
+static int deadlock_threadmain(void *param)
+{
+ int rval = -1;
+ dblayer_private *priv = NULL;
+ struct ldbminfo *li = NULL;
+ PRIntervalTime interval; /*NSPR timeout stuffy*/
+
+ PR_ASSERT(NULL != param);
+ li = (struct ldbminfo*)param;
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ interval = PR_MillisecondsToInterval(100);
+ PR_AtomicIncrement(&(priv->dblayer_thread_count));
+ while (!priv->dblayer_stop_threads)
+ {
+ if (priv->dblayer_enable_transactions)
+ {
+ if (NULL != priv->dblayer_env->dblayer_DB_ENV->lk_handle) {
+ int aborted;
+ if ((rval = LOCK_DETECT(priv->dblayer_env->dblayer_DB_ENV,
+ 0,
+ DB_LOCK_YOUNGEST,
+ &aborted))
+ != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Serious Error---Failed in deadlock detect (aborted at 0x%x), err=%d (%s)\n",
+ aborted, rval, dblayer_strerror(rval));
+ }
+ }
+ }
+ DS_Sleep(interval);
+ }
+ PR_AtomicDecrement(&(priv->dblayer_thread_count));
+ return 0;
+}
+
+#define checkpoint_debug_message(debug, fmt, a1, a2, a3) \
+ if (debug) { LDAPDebug(LDAP_DEBUG_ANY,fmt,a1,a2,a3); }
+
+/* this thread tries to do two things:
+ 1. catch a group of transactions that are pending allowing a worker thread
+ to work
+ 2. flush any left over transactions ( a single transaction for example)
+*/
+
+static int
+dblayer_start_log_flush_thread(dblayer_private *priv)
+{
+ int return_value = 0;
+
+ if ((priv->dblayer_durable_transactions) &&
+ (priv->dblayer_enable_transactions) && (trans_batch_limit > 0)) {
+ log_flush_thread=PR_TRUE;
+ if (NULL == PR_CreateThread (PR_USER_THREAD,
+ (VFP) (void *) log_flush_threadmain, priv,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE) ) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "failed to create database log flush thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ return_value = -1;
+ }
+ }
+ return return_value;
+}
+
+/* this thread tries to do two things:
+ 1. catch a group of transactions that are pending allowing a worker thread
+ to work
+ 2. flush any left over transactions ( a single transaction for example)
+*/
+
+static int log_flush_threadmain(void *param)
+{
+ dblayer_private *priv = NULL;
+ PRIntervalTime interval;
+
+
+ PR_ASSERT(NULL != param);
+ priv = (dblayer_private *) param;
+ PR_ASSERT(NULL != priv);
+ interval = PR_MillisecondsToInterval(300);
+ PR_AtomicIncrement(&(priv->dblayer_thread_count));
+ while ((!priv->dblayer_stop_threads) && (log_flush_thread))
+ {
+ if (priv->dblayer_enable_transactions)
+ {
+ DB_CHECKPOINT_LOCK(1, priv->dblayer_env->dblayer_env_lock);
+ if(trans_batch_limit > 0) {
+ if(trans_batch_count > 1) {
+ LOG_FLUSH(priv->dblayer_env->dblayer_DB_ENV,0);
+ trans_batch_count=1;
+ }
+ }
+ DB_CHECKPOINT_UNLOCK(1, priv->dblayer_env->dblayer_env_lock);
+ }
+ DS_Sleep(interval);
+ }
+ PR_AtomicDecrement(&(priv->dblayer_thread_count));
+ return 0;
+}
+
+/*
+ * create a thread for checkpoint_threadmain
+ */
+static int
+dblayer_start_checkpoint_thread(struct ldbminfo *li)
+{
+ int return_value = 0;
+ if (NULL == PR_CreateThread (PR_USER_THREAD,
+ (VFP) (void *) checkpoint_threadmain, li,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE) )
+ {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "failed to create database checkpoint thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ return_value = -1;
+ }
+ return return_value;
+}
+
+static int checkpoint_threadmain(void *param)
+{
+ time_t time_of_last_checkpoint_completion = 0; /* seconds since epoch */
+ PRIntervalTime interval; /*NSPR timeout stuffy*/
+ int rval = -1;
+ dblayer_private *priv = NULL;
+ struct ldbminfo *li = NULL;
+ int debug_checkpointing = 0;
+ int checkpoint_interval;
+ char *home_dir = NULL;
+
+ PR_ASSERT(NULL != param);
+ li = (struct ldbminfo*)param;
+
+ home_dir = dblayer_get_home_dir(li, NULL);
+ if (NULL == home_dir)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Checkpoint thread failed due to missing db home directory info\n",
+ 0, 0, 0);
+ return rval;
+ }
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ /* work around a problem with newly created environments */
+ dblayer_force_checkpoint(li);
+
+ interval = PR_MillisecondsToInterval(DBLAYER_SLEEP_INTERVAL);
+ debug_checkpointing = priv->db_debug_checkpointing;
+ PR_AtomicIncrement(&(priv->dblayer_thread_count));
+ /* assumes dblayer_force_checkpoint worked */
+ time_of_last_checkpoint_completion = current_time();
+ while (!priv->dblayer_stop_threads)
+ {
+ /* sleep for a while */
+ /* why aren't we sleeping exactly the right amount of time ? */
+ /* answer---because the interval might be changed after the server
+ * starts up */
+ DS_Sleep(interval);
+
+ if (0 == priv->dblayer_enable_transactions)
+ continue;
+
+ PR_Lock(li->li_config_mutex);
+ checkpoint_interval = priv->dblayer_checkpoint_interval;
+ PR_Unlock(li->li_config_mutex);
+
+ /* Check to see if the checkpoint interval has elapsed */
+ if (current_time() - time_of_last_checkpoint_completion <
+ checkpoint_interval)
+ continue;
+
+ if (NULL == priv->dblayer_env->dblayer_DB_ENV->tx_handle)
+ continue;
+
+ /* now checkpoint */
+ checkpoint_debug_message(debug_checkpointing,
+ "Starting checkpoint\n", 0, 0, 0);
+ rval = dblayer_txn_checkpoint(li, priv->dblayer_env, PR_TRUE, PR_TRUE);
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ if (DB_INCOMPLETE == rval)
+ {
+ checkpoint_debug_message(debug_checkpointing,
+ "Retrying checkpoint\n", 0, 0, 0);
+ } else
+#endif
+ {
+ checkpoint_debug_message(debug_checkpointing,
+ "Checkpoint Done\n", 0, 0, 0);
+ if (rval != 0) {
+ /* bad error */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Serious Error---Failed to checkpoint database, "
+ "err=%d (%s)\n", rval, dblayer_strerror(rval), 0);
+ if (LDBM_OS_ERR_IS_DISKFULL(rval)) {
+ operation_out_of_disk_space();
+ goto diskfull_return;
+ }
+ } else {
+ time_of_last_checkpoint_completion = current_time();
+ }
+ }
+
+ checkpoint_debug_message(debug_checkpointing,
+ "Starting checkpoint\n", 0, 0, 0);
+ rval = dblayer_txn_checkpoint(li, priv->dblayer_env, PR_TRUE, PR_TRUE);
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ if (DB_INCOMPLETE == rval)
+ {
+ checkpoint_debug_message(debug_checkpointing,
+ "Retrying checkpoint\n", 0, 0, 0);
+ } else
+#endif
+ {
+ checkpoint_debug_message(debug_checkpointing,
+ "Checkpoint Done\n", 0, 0, 0);
+ if (rval != 0) {
+ /* bad error */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Serious Error---Failed to checkpoint database, "
+ "err=%d (%s)\n", rval, dblayer_strerror(rval), 0);
+ if (LDBM_OS_ERR_IS_DISKFULL(rval)) {
+ operation_out_of_disk_space();
+ goto diskfull_return;
+ }
+ } else {
+ time_of_last_checkpoint_completion = current_time();
+ }
+ }
+ {
+ char **list = NULL;
+ char **listp = NULL;
+ int return_value = -1;
+ char filename[MAXPATHLEN];
+ char *prefix = NULL;
+ struct dblayer_private_env *penv = priv->dblayer_env;
+ if ((NULL != priv->dblayer_log_directory) &&
+ (0 != strlen(priv->dblayer_log_directory)))
+ {
+ prefix = priv->dblayer_log_directory;
+ }
+ else
+ {
+ prefix = home_dir;
+ }
+ /* find out which log files don't contain active txns */
+ DB_CHECKPOINT_LOCK(PR_TRUE, penv->dblayer_env_lock);
+ return_value = LOG_ARCHIVE(penv->dblayer_DB_ENV, &list,
+ 0, malloc);
+ DB_CHECKPOINT_UNLOCK(PR_TRUE, penv->dblayer_env_lock);
+ checkpoint_debug_message(debug_checkpointing,
+ "Got list of logfiles not needed %d %p\n",
+ return_value,list, 0);
+ if (0 == return_value && NULL != list)
+ {
+ /* zap 'em ! */
+ for (listp = list; *listp != NULL; ++listp)
+ {
+ sprintf(filename,"%s/%s",prefix,*listp);
+ if (priv->dblayer_circular_logging) {
+ checkpoint_debug_message(debug_checkpointing,
+ "Deleting %s\n",filename, 0, 0);
+ unlink(filename);
+ } else {
+ char new_filename[MAXPATHLEN];
+ sprintf(new_filename,"%s/old.%s",
+ prefix,*listp);
+ checkpoint_debug_message(debug_checkpointing,
+ "Renaming %s\n",filename,0, 0);
+ rename(filename,new_filename);
+ }
+ }
+ slapi_ch_free((void**)&list);
+ }
+ }
+ }
+ dblayer_force_checkpoint(li);
+diskfull_return:
+ PR_AtomicDecrement(&(priv->dblayer_thread_count));
+ return 0;
+}
+
+/*
+ * create a thread for trickle_threadmain
+ */
+static int
+dblayer_start_trickle_thread(struct ldbminfo *li)
+{
+ int return_value = 0;
+ if (NULL == PR_CreateThread (PR_USER_THREAD,
+ (VFP) (void *) trickle_threadmain, li,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE) )
+ {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY, "failed to create database trickle thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ return_value = -1;
+ }
+ return return_value;
+}
+
+static int trickle_threadmain(void *param)
+{
+ PRIntervalTime interval; /*NSPR timeout stuffy*/
+ int rval = -1;
+ dblayer_private *priv = NULL;
+ struct ldbminfo *li = NULL;
+ int debug_checkpointing = 0;
+
+ PR_ASSERT(NULL != param);
+ li = (struct ldbminfo*)param;
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ interval = PR_MillisecondsToInterval(DBLAYER_SLEEP_INTERVAL);
+ debug_checkpointing = priv->db_debug_checkpointing;
+ PR_AtomicIncrement(&(priv->dblayer_thread_count));
+ while (!priv->dblayer_stop_threads)
+ {
+ DS_Sleep(interval); /* 622855: wait for other threads fully started */
+ if (priv->dblayer_enable_transactions)
+ {
+ if ( (NULL != priv->dblayer_env->dblayer_DB_ENV->mp_handle) &&
+ (0 != priv->dblayer_trickle_percentage) )
+ {
+ int pages_written = 0;
+ if ((rval = MEMP_TRICKLE(
+ priv->dblayer_env->dblayer_DB_ENV,
+ priv->dblayer_trickle_percentage,
+ &pages_written)) != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,"Serious Error---Failed to trickle, err=%d (%s)\n",rval,dblayer_strerror(rval), 0);
+ }
+ if (pages_written > 0)
+ {
+ checkpoint_debug_message(debug_checkpointing,"Trickle thread wrote %d pages\n",pages_written,0, 0);
+ }
+ }
+ }
+ }
+ PR_AtomicDecrement(&(priv->dblayer_thread_count));
+ return 0;
+}
+
+
+/* better atol -- it understands a trailing multiplier k/m/g
+ * for example, "32k" will be returned as 32768
+ * richm: added better error checking and support for 64 bit values.
+ * The err parameter is used by the caller to tell if there was an error
+ * during the a to i conversion - if 0, the value was successfully
+ * converted - if non-zero, there was some error (e.g. not a number)
+ */
+PRInt64 db_atol(char *str, int *err)
+{
+ PRInt64 mres1 = LL_INIT(0, 1);
+ PRInt64 mres2 = LL_INIT(0, 1);
+ PRInt64 mres3 = LL_INIT(0, 1);
+ PRInt64 onek = LL_INIT(0, 1024);
+ PRInt64 multiplier = LL_INIT(0, 1);
+ PRInt64 val = LL_INIT(0, 0);
+ PRInt64 result = LL_INIT(0, 0);
+ char x = 0;
+ int num = PR_sscanf(str, "%lld%c", &val, &x);
+ if (num < 1) { /* e.g. not a number */
+ if (err)
+ *err = 1;
+ return result; /* return 0 */
+ }
+
+ switch (x) {
+ case 'g':
+ case 'G':
+ LL_MUL(mres1, onek, multiplier);
+/* multiplier *= 1024;*/
+ case 'm':
+ case 'M':
+ LL_MUL(mres2, onek, mres1);
+/* multiplier *= 1024;*/
+ case 'k':
+ case 'K':
+ LL_MUL(mres3, onek, mres2);
+/* multiplier *= 1024;*/
+ }
+ LL_MUL(result, val, mres3);
+/* result = val * multiplier;*/
+ if (err)
+ *err = 0;
+ return result;
+}
+
+PRInt64 db_atoi(char *str, int *err)
+{
+ return db_atol(str, err);
+}
+
+unsigned long db_strtoul(const char *str, int *err)
+{
+ unsigned long val, result, multiplier = 1;
+ char *p;
+ errno = 0;
+
+ val = strtoul(str, &p, 10);
+ if (errno != 0) {
+ if (err) *err = errno;
+ return val;
+ }
+
+ switch (*p) {
+ case 'g':
+ case 'G':
+ multiplier *= 1024;
+ case 'm':
+ case 'M':
+ multiplier *= 1024;
+ case 'k':
+ case 'K':
+ multiplier *= 1024;
+ p++;
+ if (*p == 'b' || *p == 'B') p++;
+ if (err) {
+ /* extra chars? */
+ *err = (*p != '\0') ? EINVAL : 0;
+ }
+ break;
+ case '\0':
+ if (err) *err = 0;
+ break;
+ default:
+ if (err) *err = EINVAL;
+ return val;
+ }
+
+ result = val * multiplier;
+
+ return result;
+}
+
+/* functions called directly by the plugin interface from the front-end */
+
+/* Begin transaction */
+int dblayer_plugin_begin(Slapi_PBlock *pb)
+{
+ int return_value = -1;
+ struct ldbminfo *li = NULL;
+ back_txnid parent;
+ back_txn current;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_PARENT_TXN, (void**)&parent );
+
+ /* call begin, and put the result in the txnid parameter */
+ return_value = dblayer_txn_begin(li,parent,&current);
+
+ if (0 == return_value)
+ {
+ slapi_pblock_set( pb, SLAPI_TXN, (void*)current.back_txn_txn );
+ }
+
+ return return_value;
+}
+
+/* Commit transaction */
+int dblayer_plugin_commit(Slapi_PBlock *pb)
+{
+ /* get the txnid and call commit */
+ int return_value = -1;
+ struct ldbminfo *li = NULL;
+ back_txn current;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_TXN, (void**)&(current.back_txn_txn) );
+
+ /* call begin, and put the result in the txnid parameter */
+ return_value = dblayer_txn_commit(li,&current);
+
+ return return_value;
+}
+
+/* Abort Transaction */
+int dblayer_plugin_abort(Slapi_PBlock *pb)
+{
+ /* get the txnid and call abort */
+ return 0;
+}
+
+
+/* Helper function for monitor stuff */
+int dblayer_memp_stat(struct ldbminfo *li, DB_MPOOL_STAT **gsp,
+ DB_MPOOL_FSTAT ***fsp)
+{
+ dblayer_private *priv = NULL;
+ DB_ENV *env = NULL;
+
+ PR_ASSERT(NULL != li);
+
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ env = priv->dblayer_env->dblayer_DB_ENV;
+ PR_ASSERT(NULL != env);
+
+ return MEMP_STAT(env, gsp, fsp, 0, malloc);
+}
+
+/* import wants this one */
+int dblayer_memp_stat_instance(ldbm_instance *inst, DB_MPOOL_STAT **gsp,
+ DB_MPOOL_FSTAT ***fsp)
+{
+ DB_ENV *env = NULL;
+ dblayer_private *priv = NULL;
+
+ PR_ASSERT(NULL != inst);
+
+ if (inst->import_env->dblayer_DB_ENV) {
+ env = inst->import_env->dblayer_DB_ENV;
+ } else {
+ priv = (dblayer_private *)inst->inst_li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+ env = priv->dblayer_env->dblayer_DB_ENV;
+ }
+ PR_ASSERT(NULL != env);
+
+ return MEMP_STAT(env, gsp, fsp, 0, malloc);
+}
+
+/* Helper functions for recovery */
+
+#define DB_LINE_LENGTH 80
+
+static int commit_good_database(dblayer_private *priv)
+{
+ /* Write out the guard file */
+ char filename[MAXPATHLEN];
+ char line[DB_LINE_LENGTH * 2];
+ PRFileDesc *prfd;
+ int return_value = 0;
+ int num_bytes;
+
+ sprintf(filename,"%s/guardian",priv->dblayer_home_directory);
+
+ prfd = PR_Open(filename, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
+ priv->dblayer_file_mode );
+ if (NULL == prfd)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,"Fatal Error---Failed to write guardian file, database corruption possible" SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
+ filename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
+ return -1;
+ }
+ sprintf(line,"cachesize:%lu\nncache:%d\nversion:%d\n",
+ priv->dblayer_cachesize, priv->dblayer_ncache, 3);
+ num_bytes = strlen(line);
+ return_value = slapi_write_buffer(prfd, line, num_bytes);
+ if (return_value != num_bytes)
+ {
+ goto error;
+ }
+ return_value = PR_Close(prfd);
+ if (PR_SUCCESS == return_value)
+ {
+ return 0;
+ } else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,"Fatal Error---Failed to write guardian file, database corruption possible\n", 0,0, 0 );
+ (void)PR_Delete(filename);
+ return -1;
+ }
+error:
+ (void)PR_Close(prfd);
+ (void)PR_Delete(filename);
+ return -1;
+}
+
+/* read the guardian file from db/ and possibly recover the database */
+static int read_metadata(struct ldbminfo *li)
+{
+ char filename[MAXPATHLEN];
+ char *buf;
+ char *thisline;
+ char *nextline;
+ char **dirp;
+ PRFileDesc *prfd;
+ PRFileInfo prfinfo;
+ int return_value = 0;
+ PRInt32 byte_count = 0;
+ char attribute[512];
+ char value[128], delimiter;
+ int number = 0;
+ dblayer_private *priv = (dblayer_private *)li->li_dblayer_private;
+
+ priv->dblayer_previous_cachesize = 0;
+ priv->dblayer_previous_ncache = 0;
+ /* Open the guard file and read stuff, then delete it */
+ sprintf(filename,"%s/guardian",priv->dblayer_home_directory);
+
+ memset(&prfinfo, '\0', sizeof(PRFileInfo));
+ (void)PR_GetFileInfo(filename, &prfinfo);
+
+ priv->dblayer_recovery_required = 0;
+ prfd = PR_Open(filename,PR_RDONLY,priv->dblayer_file_mode);
+ if (NULL == prfd || 0 == prfinfo.size) {
+ /* file empty or not present--means the database needs recovered */
+ int count = 0;
+ priv->dblayer_recovery_required = 0;
+ for (dirp = priv->dblayer_data_directories; dirp && *dirp; dirp++)
+ {
+ count_dbfiles_in_dir(*dirp, &count, 1 /* recurse */);
+ if (count > 0) {
+#if 0
+ char *home_dir;
+ /* This code used to check for a broken import by looking
+ * for a dbversion file. If it wasn't there, then an import
+ * failed. Now each instance has its own dbversion file.
+ * If this check is done at all, it ought to be done when
+ * bringing up individual backend instances.
+ */
+ /* While we're here, let's check for a broken import.
+ This would be indicated by the following conditions:
+ 1. db files in the directory.
+ 2. No guardian file.
+ 3. No DBVERSION file.
+ If we're here we have confitions 1 and 2,
+ so we should check for condition 3.
+ */
+ if (!dbversion_exists(li, home_dir)) {
+ LDAPDebug( LDAP_DEBUG_ANY,"Fatal Error---database is corrupt. Server can't start. Most likely cause is a previously aborted import. Either re-import or delete the database and re-start the server.\n", 0,0, 0 );
+ return -1;
+ } else {
+ priv->dblayer_recovery_required = 1;
+ }
+#endif
+ priv->dblayer_recovery_required = 1;
+ return 0;
+ }
+ }
+ return 0; /* no files found; no need to run recover start */
+ }
+ /* dblayer_recovery_required is initialized in dblayer_init;
+ * and might be set 1 in check_db_version;
+ * we don't want to override it
+ * priv->dblayer_recovery_required = 0; */
+ /* So, we opened the file, now let's read the cache size and version stuff
+ */
+ buf = slapi_ch_calloc(1, prfinfo.size + 1);
+ byte_count = slapi_read_buffer(prfd, buf, prfinfo.size);
+ if (byte_count < 0) {
+ /* something bad happened while reading */
+ priv->dblayer_recovery_required = 1;
+ } else {
+ buf[ byte_count ] = '\0';
+ thisline = buf;
+ while (1) {
+ /* Find the end of the line */
+ nextline = strchr( thisline, '\n' );
+ if (NULL != nextline) {
+ *nextline++ = '\0';
+ while ('\n' == *nextline) {
+ nextline++;
+ }
+ }
+ sscanf(thisline,"%[a-z]%c%s",attribute,&delimiter,value);
+ if (0 == strcmp("cachesize",attribute)) {
+ priv->dblayer_previous_cachesize = strtoul(value, NULL, 10);
+ } else if (0 == strcmp("ncache",attribute)) {
+ number = atoi(value);
+ priv->dblayer_previous_ncache = number;
+ } else if (0 == strcmp("version",attribute)) {
+ }
+ if (NULL == nextline || '\0' == *nextline) {
+ /* Nothing more to read */
+ break;
+ }
+ thisline = nextline;
+ }
+ }
+ slapi_ch_free((void **)&buf);
+ (void)PR_Close(prfd);
+ return_value = PR_Delete(filename); /* very important that this happen ! */
+ if (PR_SUCCESS != return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Fatal Error---Failed to delete guardian file, "
+ "database corruption possible\n", 0, 0, 0 );
+ }
+ return return_value;
+}
+
+/* handy routine for checkpointing the db */
+static int dblayer_force_checkpoint(struct ldbminfo *li)
+{
+ int ret = 0, i;
+ dblayer_private *priv = (dblayer_private *)li->li_dblayer_private;
+ struct dblayer_private_env *pEnv;
+
+ if (NULL == priv){
+ /* already terminated. nothing to do */
+ return -1;
+ }
+
+ pEnv= priv->dblayer_env;
+
+
+ PR_ASSERT(pEnv != NULL);
+
+ if (priv->dblayer_enable_transactions) {
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "Checkpointing database ...\n", 0, 0, 0);
+
+ /*
+ * DB workaround. Newly created environments do not know what the
+ * previous checkpoint LSN is. The default LSN of [0][0] would
+ * cause us to read all log files from very beginning during a
+ * later recovery. Taking two checkpoints solves the problem.
+ */
+
+ for (i = 0; i < 2; i++) {
+ ret = dblayer_txn_checkpoint(li, pEnv, PR_TRUE, PR_FALSE);
+ if (ret == 0) continue;
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+ if (ret != DB_INCOMPLETE)
+#endif
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Checkpoint FAILED, error %s (%d)\n",
+ dblayer_strerror(ret), ret, 0);
+ break;
+ }
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR < 4100
+
+ LDAPDebug(LDAP_DEBUG_ANY, "Busy: retrying checkpoint\n", 0, 0, 0);
+
+ /* teletubbies: "again! again!" */
+ ret = dblayer_txn_checkpoint(li, pEnv, PR_TRUE, PR_FALSE);
+ if (ret == DB_INCOMPLETE) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Busy: giving up on checkpoint\n", 0, 0, 0);
+ break;
+ } else if (ret != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Checkpoint FAILED, error %s (%d)\n",
+ dblayer_strerror(ret), ret, 0);
+ break;
+ }
+#endif
+ }
+ }
+
+ return ret;
+}
+
+
+static int _dblayer_delete_instance_dir(ldbm_instance *inst)
+{
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ char filename[MAXPATHLEN];
+ struct ldbminfo *li = inst->inst_li;
+ dblayer_private *priv = NULL;
+ struct dblayer_private_env *pEnv = NULL;
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = NULL;
+ int rval = 0;
+
+ if (NULL != li)
+ {
+ priv = (dblayer_private*)li->li_dblayer_private;
+ if (NULL != priv)
+ {
+ pEnv = priv->dblayer_env;
+ }
+ }
+
+ if (inst->inst_dir_name == NULL)
+ dblayer_get_instance_data_dir(inst->inst_be);
+
+ inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
+ dirhandle = PR_OpenDir(inst_dirp);
+ if (! dirhandle) {
+ if ( PR_GetError() == PR_FILE_NOT_FOUND_ERROR ) {
+ /* the directory does not exist... that's not an error */
+ rval = 0;
+ goto done;
+ }
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "_dblayer_delete_instance_dir: PR_OpenDir(%s) failed (%d): %s\n",
+ inst_dirp, PR_GetError(),slapd_pr_strerror(PR_GetError()));
+ rval = -1;
+ goto done;
+ }
+
+ /*
+ Note the use of PR_Delete here as opposed to using
+ sleepycat to "remove" the file. Reason: One should
+ not expect logging to be able to recover the wholesale
+ removal of a complete directory... a directory that includes
+ files outside the scope of sleepycat's logging. rwagner
+
+ ADDITIONAL COMMENT:
+ libdb41 is more strict on the transaction log control.
+ Even if checkpoint is forced before this delete function,
+ no log regarding the file deleted found in the log file,
+ following checkpoint repeatedly complains with these error messages:
+ libdb: <path>/mail.db4: cannot sync: No such file or directory
+ libdb: txn_checkpoint: failed to flush the buffer cache
+ No such file or directory
+ */
+
+ while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT |
+ PR_SKIP_DOT_DOT))) {
+ if (! direntry->name)
+ break;
+ sprintf(filename, "%s/%s", inst_dirp, direntry->name);
+ if (pEnv &&
+ strcmp(LDBM_FILENAME_SUFFIX , last_four_chars(direntry->name)) == 0)
+ {
+ rval = dblayer_db_remove_ex(pEnv, filename, 0, PR_TRUE);
+ }
+ else
+ {
+ rval = PR_Delete(filename);
+ }
+ }
+ PR_CloseDir(dirhandle);
+done:
+ /* remove the directory itself too */
+ if (0 == rval)
+ PR_RmDir(inst_dirp);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ return rval;
+}
+
+/* delete the db3 files in a specific backend instance --
+ * this is probably only used for import.
+ * assumption: dblayer is open, but the instance has been closed.
+ */
+int dblayer_delete_instance_dir(backend *be)
+{
+ struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
+ int ret = dblayer_force_checkpoint(li);
+
+ if (ret != 0) {
+ return ret;
+ } else {
+ ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
+ return _dblayer_delete_instance_dir(inst);
+ }
+}
+
+/* delete an entire db/ directory, including all instances under it!
+ * this is used mostly for restores.
+ * dblayer is assumed to be closed.
+ */
+int dblayer_delete_database(struct ldbminfo *li)
+{
+ dblayer_private *priv = NULL;
+ Object *inst_obj;
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ char filename[MAXPATHLEN];
+ char *log_dir;
+ int ret;
+
+ PR_ASSERT(NULL != li);
+ priv = (dblayer_private *)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ /* delete each instance */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ ldbm_instance *inst = (ldbm_instance *)object_get_data(inst_obj);
+
+ if (inst->inst_be->be_instance_info != NULL) {
+ ret = _dblayer_delete_instance_dir(inst);
+ if (ret != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dblayer_delete_database: WARNING _dblayer_delete_instance_dir failed (%d)\n", ret, 0, 0);
+ return ret;
+ }
+ }
+ }
+
+ /* now smash everything else in the db/ dir */
+ dirhandle = PR_OpenDir(priv->dblayer_home_directory);
+ if (! dirhandle)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "PR_OpenDir (%s) failed (%d): %s\n",
+ priv->dblayer_home_directory,
+ PR_GetError(),slapd_pr_strerror(PR_GetError()));
+ return -1;
+ }
+ while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT |
+ PR_SKIP_DOT_DOT))) {
+ if (! direntry->name)
+ break;
+ sprintf(filename, "%s/%s", priv->dblayer_home_directory,
+ direntry->name);
+ PR_Delete(filename);
+ }
+
+ PR_CloseDir(dirhandle);
+ /* remove transaction logs */
+ if ((NULL != priv->dblayer_log_directory) &&
+ (0 != strlen(priv->dblayer_log_directory) ))
+ {
+ log_dir = priv->dblayer_log_directory;
+ }
+ else
+ {
+ log_dir = dblayer_get_home_dir(li, NULL);
+ }
+ ret = dblayer_delete_transaction_logs(log_dir);
+ if(ret) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dblayer_delete_database: dblayer_delete_transaction_logs failed (%d)\n",
+ ret, 0, 0);
+ return -1;
+ }
+ return 0;
+}
+
+
+/*
+ * Return the size of the database (in kilobytes). XXXggood returning
+ * the size in units of kb is really a hack, and is done because we
+ * don't have NSPR support for 64-bit file offsets.
+ * Caveats:
+ * - We can still return incorrect results if an individual file is
+ * larger than fit in a PRUint32.
+ * - PR_GetFileInfo doesn't do any special processing for symlinks,
+ * nor does it inform us if the file is a symlink. Nice. So if
+ * a file in the db directory is a symlink, the size we return
+ * will probably be way too small.
+ */
+int dblayer_database_size(struct ldbminfo *li, unsigned int *size)
+{
+ dblayer_private *priv = NULL;
+ int return_value = 0;
+ char filename[MAXPATHLEN];
+ PRDir *dirhandle = NULL;
+ /*
+ * XXXggood - NSPR will only give us an unsigned 32-bit quantity for
+ * file sizes. This is bad. Files can be bigger than that these days.
+ */
+ unsigned int cumulative_size = 0;
+ unsigned int remainder = 0;
+ PRFileInfo info;
+
+ PR_ASSERT(NULL != li);
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ dirhandle = PR_OpenDir(priv->dblayer_home_directory);
+ if (NULL != dirhandle)
+ {
+ PRDirEntry *direntry = NULL;
+ while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
+ if (NULL == direntry->name)
+ {
+ break;
+ }
+ sprintf(filename,"%s/%s",priv->dblayer_home_directory,direntry->name);
+ return_value = PR_GetFileInfo(filename, &info);
+ if (PR_SUCCESS == return_value)
+ {
+ cumulative_size += (info.size / 1024);
+ remainder += (info.size % 1024);
+ } else
+ {
+ cumulative_size = (PRUint32) 0;
+ return_value = -1;
+ break;
+ }
+ }
+ PR_CloseDir(dirhandle);
+ } else
+ {
+ return_value = -1;
+ }
+
+ *size = cumulative_size + (remainder / 1024);
+ return return_value;
+}
+
+static char* last_four_chars(const char* s)
+{
+ size_t l = strlen(s);
+ return ((char*)s + (l - 4));
+}
+
+static int count_dbfiles_in_dir(char *directory, int *count, int recurse)
+{
+ /* The new recurse argument was added to help with multiple backend
+ * instances. When recurse is true, this function will also look through
+ * the directories in the given directory for .db3 files. */
+ int return_value = 0;
+ PRDir *dirhandle = NULL;
+
+ if (!recurse) {
+ /* It is really the callers responsibility to set count to 0 before
+ * calling. However, if recurse isn't true, we can make sure it is
+ * set to 0. */
+ *count = 0;
+ }
+ dirhandle = PR_OpenDir(directory);
+ if (NULL != dirhandle) {
+ PRDirEntry *direntry = NULL;
+ char *direntry_name;
+ PRFileInfo info;
+
+ while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
+ if (NULL == direntry->name) {
+ break;
+ }
+ direntry_name = slapi_ch_malloc(strlen(directory) +
+ strlen(direntry->name) + 2);
+ sprintf(direntry_name, "%s/%s", directory, direntry->name);
+ if ((PR_GetFileInfo(direntry_name, &info) == PR_SUCCESS) &&
+ (PR_FILE_DIRECTORY == info.type) && recurse) {
+ /* Recurse into this directory but not any further. This is
+ * because each instance gets its own directory, but in those
+ * directories there should be only .db3 files. There should
+ * not be any more directories in an instance directory. */
+ count_dbfiles_in_dir(direntry_name, count, 0 /* don't recurse */);
+ }
+ slapi_ch_free((void**)&direntry_name);
+ if (strcmp( LDBM_FILENAME_SUFFIX , last_four_chars(direntry->name)) == 0) {
+ (*count)++;
+ }
+ }
+ PR_CloseDir(dirhandle);
+ } else {
+ return_value = -1;
+ }
+
+ return return_value;
+}
+
+/* And finally... Tubular Bells.
+ * Well, no, actually backup and restore...
+ */
+
+/* Backup works like this:
+ * the slapd executable is run like for ldif2ldbm and so on.
+ * this means that the front-end gets the back-end loaded, and then calls
+ * into the back-end backup entry point. This then gets us down to here.
+ *
+ * So, we need to copy the data files to the backup point.
+ * While we are doing that, we need to make sure that the logfile
+ * truncator in slapd doesn't delete our files. To do this we need
+ * some way to signal to it that it should cease its work, or we need
+ * to do something like start a long-lived transaction so that the
+ * log files look like they're needed.
+ *
+ * When we've copied the data files, we can then copy the log files
+ * too.
+ *
+ * Finally, we tell the log file truncator to go back about its business in peace
+ *
+ */
+
+int
+dblayer_copyfile(char *source, char *destination, int overwrite, int mode)
+{
+#if defined _WIN32
+ return (0 == CopyFile(source,destination,overwrite ? FALSE : TRUE));
+#else
+#ifdef DB_USE_64LFS
+#define OPEN_FUNCTION dblayer_open_large
+#else
+#define OPEN_FUNCTION open
+#endif
+ int source_fd = -1;
+ int dest_fd = -1;
+ char *buffer = NULL;
+ int return_value = -1;
+ int bytes_to_write = 0;
+
+ /* malloc the buffer */
+ buffer = slapi_ch_malloc(64*1024);
+ if (NULL == buffer)
+ {
+ goto error;
+ }
+ /* Open source file */
+ source_fd = OPEN_FUNCTION(source,O_RDONLY,0);
+ if (-1 == source_fd)
+ {
+ goto error;
+ }
+ /* Open destination file */
+ dest_fd = OPEN_FUNCTION(destination,O_CREAT | O_WRONLY, mode);
+ if (-1 == dest_fd)
+ {
+ goto error;
+ }
+ /* Loop round reading data and writing it */
+ while (1)
+ {
+ return_value = read(source_fd,buffer,64*1024);
+ if (return_value <= 0)
+ {
+ /* means error or EOF */
+ break;
+ }
+ bytes_to_write = return_value;
+ return_value = write(dest_fd,buffer,bytes_to_write);
+ if (return_value != bytes_to_write)
+ {
+ /* means error */
+ return_value = -1;
+ break;
+ }
+ }
+error:
+ if (source_fd != -1)
+ {
+ close(source_fd);
+ }
+ if (dest_fd != -1)
+ {
+ close(dest_fd);
+ }
+ slapi_ch_free((void**)&buffer);
+ return return_value;
+#endif
+}
+
+/*
+ * Copies all the .db# files in instance_dir to a directory with the same name
+ * in destination_dir. Both instance_dir and destination_dir are absolute
+ * paths.
+ * (#604921: added indexonly flag for the use in convindices
+ * -- backup/restore indices)
+ *
+ * If the argument restore is true,
+ * logging messages will be about "Restoring" files.
+ * If the argument restore is false,
+ * logging messages will be about "Backing up" files.
+ * The argument cnt is used to count the number of files that were copied.
+ *
+ * This function is used during db2bak and bak2db.
+ */
+int dblayer_copy_directory(struct ldbminfo *li,
+ Slapi_Task *task,
+ char *src_dir,
+ char *dest_dir,
+ int restore,
+ int *cnt,
+ int instance_dir_flag,
+ int indexonly)
+{
+ dblayer_private *priv = NULL;
+ char *new_src_dir = NULL;
+ char *new_dest_dir = NULL;
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ size_t filename_length = 0;
+ size_t offset = 0;
+ char *compare_piece = NULL;
+ char *filename1;
+ char *filename2;
+ int return_value = -1;
+ char *relative_instance_name = NULL;
+ char *inst_dirp = NULL;
+ char inst_dir[MAXPATHLEN];
+ char sep;
+ ldbm_instance *inst;
+
+ if (!src_dir || '\0' == *src_dir || !dest_dir || '\0' == *dest_dir)
+ return return_value;
+
+ priv = (dblayer_private *) li->li_dblayer_private;
+
+ /* get the backend instance name */
+ sep = get_sep(src_dir);
+ if ((relative_instance_name = strrchr(src_dir, sep)) == NULL)
+ relative_instance_name = src_dir;
+ else
+ relative_instance_name++;
+
+ inst = ldbm_instance_find_by_name(li, relative_instance_name);
+ if (NULL == inst)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Backend instance \"%s\" does not exist; "
+ "Instance path %s could be invalid.\n",
+ relative_instance_name, src_dir, 0);
+ return return_value;
+ }
+
+ inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ inst_dir, MAXPATHLEN);
+ if (is_fullpath(src_dir))
+ new_src_dir = src_dir;
+ else
+ {
+ int len = strlen(inst_dirp);
+ sep = get_sep(inst_dirp);
+ if (*(inst_dirp+len-1) == sep)
+ sep = '\0';
+ new_src_dir = (char *)slapi_ch_malloc(strlen(src_dir) + len + 2);
+ sprintf(new_src_dir, "%s%c%s", inst_dirp, sep, src_dir);
+ }
+
+ dirhandle = PR_OpenDir(new_src_dir);
+ if (NULL == dirhandle)
+ return return_value;
+
+ while (NULL != (direntry =
+ PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == direntry->name) {
+ /* NSPR doesn't behave like the docs say it should */
+ break;
+ }
+ if (indexonly &&
+ 0 == strcmp(direntry->name, ID2ENTRY LDBM_FILENAME_SUFFIX))
+ {
+ continue;
+ }
+
+ /* Look at the last three characters in the filename */
+ filename_length = strlen(direntry->name);
+ if (filename_length > 4) {
+ offset = filename_length - 4;
+ } else {
+ offset = 0;
+ }
+ compare_piece = (char *)direntry->name + offset;
+
+ if (0 == strcmp(compare_piece, LDBM_FILENAME_SUFFIX) || /* .db4 */
+ 0 == strcmp(compare_piece, LDBM_SUFFIX_OLD) || /* support .db3 */
+ 0 == strcmp(direntry->name, DBVERSION_FILENAME)) {
+ /* Found a database file. Copy it. */
+
+ if (NULL == new_dest_dir) {
+ /* Need to create the new directory where the files will be
+ * copied to. */
+ PRFileInfo info;
+ char *prefix = "";
+ char mysep = 0;
+
+ if (!is_fullpath(dest_dir))
+ {
+ prefix = dblayer_get_home_dir(li, NULL);
+ mysep = get_sep(prefix);
+ }
+
+ new_dest_dir = slapi_ch_malloc(strlen(dest_dir) +
+ strlen(relative_instance_name) +
+ strlen(prefix) + 3);
+ if (mysep)
+ sprintf(new_dest_dir, "%s%c%s%c%s",
+ prefix, mysep, dest_dir, mysep, relative_instance_name);
+ else
+ sprintf(new_dest_dir, "%s/%s",
+ dest_dir, relative_instance_name);
+ /* } */
+ if (PR_SUCCESS == PR_GetFileInfo(new_dest_dir, &info))
+ {
+ ldbm_delete_dirs(new_dest_dir);
+ }
+ if (mkdir_p(new_dest_dir, 0700) != PR_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Can't create new directory %s, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ new_dest_dir, PR_GetError(),
+ slapd_pr_strerror(PR_GetError()));
+ goto out;
+ }
+ }
+
+ filename1 = slapi_ch_malloc(strlen(new_src_dir) +
+ strlen(direntry->name) + 2);
+ sprintf(filename1, "%s/%s", new_src_dir, direntry->name);
+ filename2 = slapi_ch_malloc(strlen(new_dest_dir) +
+ strlen(direntry->name) + 2);
+ sprintf(filename2, "%s/%s", new_dest_dir, direntry->name);
+
+ if (restore) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Restoring file %d (%s)\n",
+ *cnt, filename2, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "Restoring file %d (%s)", *cnt, filename2);
+ slapi_task_log_status(task,
+ "Restoring file %d (%s)", *cnt, filename2);
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "Backing up file %d (%s)\n",
+ *cnt, filename2, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "Backing up file %d (%s)", *cnt, filename2);
+ slapi_task_log_status(task,
+ "Backing up file %d (%s)", *cnt, filename2);
+ }
+ }
+
+ /* copy filename1 to filename2 */
+ return_value = dblayer_copyfile(filename1, filename2,
+ 0, priv->dblayer_file_mode);
+ slapi_ch_free((void**)&filename1);
+ slapi_ch_free((void**)&filename2);
+ if (0 > return_value)
+ break;
+
+ (*cnt)++;
+ }
+ }
+out:
+ PR_CloseDir(dirhandle);
+ slapi_ch_free((void**)&new_dest_dir);
+ if (new_src_dir != src_dir)
+ slapi_ch_free((void**)&new_src_dir);
+ return return_value;
+}
+
+
+
+/* Destination Directory is an absolute pathname */
+int dblayer_backup(struct ldbminfo *li, char *dest_dir, Slapi_Task *task)
+{
+ dblayer_private *priv = NULL;
+ char **listA = NULL, **listB = NULL, **listi, **listj, *prefix;
+ char *home_dir = NULL;
+ int return_value = 0;
+ char *pathname1;
+ char *pathname2;
+ back_txn txn;
+ int cnt = 1, ok = 0;
+ ldbm_instance *inst;
+ Object *inst_obj;
+
+ PR_ASSERT(NULL != li);
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+ home_dir = dblayer_get_home_dir(li, NULL);
+ if (NULL == home_dir)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Backup failed due to missing db home directory info\n", 0, 0, 0);
+ return -1;
+ }
+
+ /*
+ * What are we doing here ?
+ * We want to copy into the backup directory:
+ * All the backend instance dir / database files;
+ * All the logfiles
+ * The version file
+ */
+
+ /* changed in may 1999 for political correctness.
+ * 1. take checkpoint
+ * 2. open transaction
+ * 3. get list of logfiles (A)
+ * 4. copy the db# files
+ * 5. get list of logfiles (B)
+ * 6. if !(A in B), goto 3
+ * (logfiles were flushed during our backup)
+ * 7. copy logfiles from list B
+ * 8. abort transaction
+ * 9. backup index config info
+ */
+
+ /* Order of checkpointing and txn creation reversed to work
+ * around DB problem. If we don't do it this way around DB
+ * thinks all old transaction logs are required for recovery
+ * when the DB environment has been newly created (such as
+ * after an import).
+ */
+
+ /* do a quick checkpoint */
+ dblayer_force_checkpoint(li);
+ dblayer_txn_init(li,&txn);
+ return_value=dblayer_txn_begin(li,NULL,&txn);
+ if (0 != return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Backup failed due to transaction failure\n", 0, 0, 0);
+ return -1;
+ }
+
+ if ( g_get_shutdown() || c_get_shutdown() ) {
+ dblayer_txn_abort(li,&txn);
+ return -1;
+ }
+
+ /* repeat this until the logfile sets match... */
+ do {
+ /* get the list of logfiles currently existing */
+ if (priv->dblayer_enable_transactions) {
+ return_value = LOG_ARCHIVE(priv->dblayer_env->dblayer_DB_ENV,
+ &listA, DB_ARCH_LOG, malloc);
+ if ((return_value != 0) || (listA == NULL)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "BAD: can't get list of logs\n",
+ 0, 0, 0);
+ dblayer_txn_abort(li,&txn);
+ return return_value;
+ }
+ } else {
+ ok=1;
+ }
+ if ( g_get_shutdown() || c_get_shutdown() ) {
+ dblayer_txn_abort(li,&txn);
+ return -1;
+ }
+
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj))
+ {
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = NULL;
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ inst_dir, MAXPATHLEN);
+ return_value = dblayer_copy_directory(li, task, inst_dirp,
+ dest_dir, 0 /* backup */, &cnt, 0, 0);
+ if (return_value != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: error copying directory (%s -> %s): err=%d\n",
+ inst_dirp, dest_dir, return_value);
+ if (task) {
+ slapi_task_log_notice(task,
+ "ERROR: error copying directory (%s -> %s): err=%d",
+ inst_dirp, dest_dir, return_value);
+ }
+ if (listA) {
+ free(listA);
+ }
+ dblayer_txn_abort(li,&txn);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ return return_value;
+ }
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ }
+ if (priv->dblayer_enable_transactions) {
+ /* now, get the list of logfiles that still exist */
+ return_value = LOG_ARCHIVE(priv->dblayer_env->dblayer_DB_ENV,
+ &listB, DB_ARCH_LOG, malloc);
+ if ((return_value != 0) || (listB == NULL)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: can't get list of logs\n",
+ 0, 0, 0);
+ free(listA);
+ dblayer_txn_abort(li,&txn);
+ return return_value;
+ }
+
+ /* compare: make sure everything in list A is still in list B */
+ ok = 1;
+ for (listi = listA; *listi && ok; listi++) {
+ int found = 0;
+ for (listj = listB; *listj && !found; listj++) {
+ if (strcmp(*listi, *listj) == 0)
+ found = 1;
+ }
+ if (! found) {
+ ok = 0; /* missing log: start over */
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: Log %s has been swiped "
+ "out from under me! (retrying)\n", *listi, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "WARNING: Log %s has been swiped out from under me! "
+ "(retrying)", *listi);
+ }
+ }
+ }
+
+ if ( g_get_shutdown() || c_get_shutdown() ) {
+ dblayer_txn_abort(li,&txn);
+ return -1;
+ }
+
+ if (ok) {
+ char **listptr;
+
+ prefix = NULL;
+ if ((NULL != priv->dblayer_log_directory) &&
+ (0 != strlen(priv->dblayer_log_directory))) {
+ prefix = priv->dblayer_log_directory;
+ } else {
+ prefix = home_dir;
+ }
+ /* log files have the same filename len(100 is a safety net:) */
+ pathname1 = (char *)slapi_ch_malloc(strlen(prefix) +
+ strlen(*listB) + 100);
+ pathname2 = (char *)slapi_ch_malloc(strlen(dest_dir) +
+ strlen(*listB) + 100);
+ /* We copy those over */
+ for (listptr = listB; (*listptr) && ok; ++listptr) {
+ sprintf(pathname1, "%s/%s", prefix, *listptr);
+ sprintf(pathname2, "%s/%s", dest_dir, *listptr);
+ LDAPDebug(LDAP_DEBUG_ANY, "Backing up file %d (%s)\n",
+ cnt, pathname2, 0);
+ if (task)
+ {
+ slapi_task_log_notice(task,
+ "Backing up file %d (%s)", cnt, pathname2);
+ slapi_task_log_status(task,
+ "Backing up file %d (%s)", cnt, pathname2);
+ }
+ return_value = dblayer_copyfile(pathname1, pathname2,
+ 0, priv->dblayer_file_mode);
+ if (0 > return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error copying file '%s' "
+ "(err=%d) -- Starting over...\n",
+ pathname1, return_value, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "Error copying file '%s' (err=%d) -- Starting "
+ "over...", pathname1, return_value);
+ }
+ ok = 0;
+ }
+ if ( g_get_shutdown() || c_get_shutdown() ) {
+ dblayer_txn_abort(li,&txn);
+ return -1;
+ }
+ cnt++;
+ }
+ slapi_ch_free((void **)&pathname1);
+ slapi_ch_free((void **)&pathname2);
+ }
+
+ if (listA) {
+ free(listA);
+ listA = NULL;
+ }
+ if (listB) {
+ free(listB);
+ listB = NULL;
+ }
+ }
+ } while (!ok);
+
+
+ if ( g_get_shutdown() || c_get_shutdown() ) {
+ dblayer_txn_abort(li,&txn);
+ return -1;
+ }
+
+ /* now copy the version file */
+ pathname1 = (char *)slapi_ch_malloc(strlen(home_dir) +
+ strlen(DBVERSION_FILENAME) + 2);
+ pathname2 = (char *)slapi_ch_malloc(strlen(dest_dir) +
+ strlen(DBVERSION_FILENAME) + 2);
+ sprintf(pathname1, "%s/%s", home_dir, DBVERSION_FILENAME);
+ sprintf(pathname2, "%s/%s", dest_dir, DBVERSION_FILENAME);
+ LDAPDebug(LDAP_DEBUG_ANY, "Backing up file %d (%s)\n",
+ cnt, pathname2, 0);
+ if (task) {
+ slapi_task_log_notice(task, "Backing up file %d (%s)", cnt, pathname2);
+ slapi_task_log_status(task, "Backing up file %d (%s)", cnt, pathname2);
+ }
+ return_value = dblayer_copyfile(pathname1,pathname2,0,priv->dblayer_file_mode);
+ slapi_ch_free((void **)&pathname1);
+ slapi_ch_free((void **)&pathname2);
+
+ /* Lastly we tell log file truncation to start again */
+
+ if (0 == return_value) /* if everything went well, backup the index conf */
+ return_value = dse_conf_backup(li, dest_dir);
+
+ return_value = dblayer_txn_abort(li,&txn);
+ return return_value;
+}
+
+
+/*
+ * Restore is pretty easy.
+ * We delete the current database.
+ * We then copy all the files over from the backup point.
+ * We then leave them there for the slapd process to pick up and do the recovery
+ * (which it will do as it sees no guard file).
+ */
+
+/* Helper function first */
+
+static int dblayer_is_logfilename(const char* path)
+{
+ int ret = 0;
+ /* Is the filename at least 4 characters long ? */
+ if (strlen(path) < 4)
+ {
+ return 0; /* Not a log file then */
+ }
+ /* Are the first 4 characters "log." ? */
+ ret = strncmp(path,"log.",4);
+ if (0 == ret)
+ {
+ /* Now, are the last 4 characters _not_ .db# ? */
+ const char *piece = path + (strlen(path) - 4);
+ ret = strcmp(piece,LDBM_FILENAME_SUFFIX);
+ if (0 != ret)
+ {
+ /* Is */
+ return 1;
+ }
+ }
+ return 0; /* Is not */
+}
+
+/* remove log.xxx from log directory*/
+static
+int dblayer_delete_transaction_logs(const char * log_dir)
+{
+ int rc=0;
+ char filename1[MAXPATHLEN];
+ PRDir *dirhandle = NULL;
+ dirhandle = PR_OpenDir(log_dir);
+ if (NULL != dirhandle) {
+ PRDirEntry *direntry = NULL;
+ int is_a_logfile = 0;
+ int pre=0;
+ PRFileInfo info ;
+
+ while (NULL != (direntry =
+ PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == direntry->name) {
+ /* NSPR doesn't behave like the docs say it should */
+ LDAPDebug(LDAP_DEBUG_ANY, "PR_ReadDir failed (%d): %s\n",
+ PR_GetError(),slapd_pr_strerror(PR_GetError()), 0);
+ break;
+ }
+ sprintf(filename1, "%s/%s", log_dir, direntry->name);
+ pre = PR_GetFileInfo(filename1, &info);
+ if (pre == PR_SUCCESS && PR_FILE_DIRECTORY == info.type) {
+ continue;
+ }
+ is_a_logfile = dblayer_is_logfilename(direntry->name);
+ if (is_a_logfile && (NULL != log_dir) && (0 != strlen(log_dir)) )
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Deleting log file: (%s)\n",
+ filename1, 0, 0);
+ unlink(filename1);
+ }
+ }
+ PR_CloseDir(dirhandle);
+ }
+ else if (PR_FILE_NOT_FOUND_ERROR != PR_GetError())
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dblayer_delete_transaction_logs: PR_OpenDir(%s) failed (%d): %s\n",
+ log_dir, PR_GetError(),slapd_pr_strerror(PR_GetError()));
+ rc=1;
+ }
+ return rc;
+}
+
+const char *skip_list[] =
+{
+ ".ldif",
+ NULL
+};
+
+static int doskip(const char *filename)
+{
+ const char **p;
+ int len = strlen(filename);
+
+ for (p = skip_list; p && *p; p++)
+ {
+ int n = strlen(*p);
+ if (0 == strncmp(filename + len - n, *p, n))
+ return 1;
+ }
+ return 0;
+}
+
+/* Destination Directory is an absolute pathname */
+
+int dblayer_restore(struct ldbminfo *li, char *src_dir, Slapi_Task *task)
+{
+ dblayer_private *priv = NULL;
+ int return_value = 0;
+ int tmp_rval;
+ char filename1[MAXPATHLEN];
+ char filename2[MAXPATHLEN];
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ PRFileInfo info;
+ ldbm_instance *inst;
+ int seen_logfiles = 0; /* Tells us if we restored any logfiles */
+ int is_a_logfile = 0;
+ int dbmode;
+ int action = 0;
+ char *home_dir = NULL;
+
+ PR_ASSERT(NULL != li);
+ priv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != priv);
+
+ /* DBDB this is a hack, take out later */
+ PR_Lock(li->li_config_mutex);
+ priv->dblayer_home_directory = li->li_directory;
+ priv->dblayer_cachesize = li->li_dbcachesize;
+ priv->dblayer_ncache = li->li_dbncache;
+ priv->dblayer_file_mode = li->li_mode;
+ PR_Unlock(li->li_config_mutex);
+
+ home_dir = dblayer_get_home_dir(li, NULL);
+ if (NULL == home_dir)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Restore failed due to missing db home directory info\n", 0, 0, 0);
+ return -1;
+ }
+
+ /* We find out if slapd is running */
+ /* If it is, we fail */
+ /* We check on the source staging area, no point in going further if it
+ * isn't there */
+ if (!dbversion_exists(li, src_dir)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "restore: source directory %s does not "
+ "contain a complete backup\n", src_dir, 0, 0);
+
+
+ if (task) {
+ slapi_task_log_notice(task, "Source directory %s does not "
+ "contain a complete backup", src_dir );
+ }
+ }
+
+ /*
+ * Check if the target is a superset of the backup.
+ * If not don't restore any db at all, otherwise
+ * the target will be crippled.
+ */
+ dirhandle = PR_OpenDir(src_dir);
+ if (NULL != dirhandle)
+ {
+ while ((direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))
+ && direntry->name)
+ {
+ sprintf(filename1, "%s/%s", src_dir, direntry->name);
+ tmp_rval = PR_GetFileInfo(filename1, &info);
+ if (tmp_rval == PR_SUCCESS && PR_FILE_DIRECTORY == info.type) {
+ inst = ldbm_instance_find_by_name(li, (char *)direntry->name);
+ if ( inst == NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: target server has no %s configured\n", direntry->name, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "ERROR: target server has no %s configured\n", direntry->name);
+ }
+ PR_CloseDir(dirhandle);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ }
+ }
+ PR_CloseDir(dirhandle);
+ }
+
+ /* We delete the existing database */
+ return_value = dblayer_delete_database(li);
+ if (return_value) {
+ return return_value;
+ }
+
+ /* We copy the files over from the staging area */
+ /* We want to treat the logfiles specially: if there's
+ * a log file directory configured, copy the logfiles there
+ * rather than to the db dirctory */
+ if (0 == return_value) {
+ dirhandle = PR_OpenDir(src_dir);
+ if (NULL != dirhandle) {
+ char *restore_dir;
+ char *prefix = NULL;
+ int cnt = 1;
+
+
+ while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT))) {
+ if (NULL == direntry->name) {
+ /* NSPR doesn't behave like the docs say it should */
+ break;
+ }
+
+ /* Is this entry a directory? */
+ sprintf(filename1, "%s/%s", src_dir, direntry->name);
+ tmp_rval = PR_GetFileInfo(filename1, &info);
+ if (tmp_rval == PR_SUCCESS && PR_FILE_DIRECTORY == info.type) {
+ /* This is an instance directory. It contains the *.db#
+ * files for the backend instance.
+ * restore directory is supposed to be where the backend
+ * directory is located.
+ */
+
+ inst = ldbm_instance_find_by_name(li, (char *)direntry->name);
+ if (inst == NULL)
+ continue;
+
+ restore_dir = inst->inst_parent_dir_name;
+
+ if (dblayer_copy_directory(li, task, filename1,
+ restore_dir, 1 /* restore */, &cnt, 0, 0) == 0)
+ continue;
+ else
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "restore: failed to copy directory %s\n",
+ filename1, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "Failed to copy directory %s", filename1);
+ }
+ break;
+ }
+ }
+
+ if (doskip(direntry->name))
+ continue;
+
+ /* Is this a log file ? */
+ /* Log files have names of the form "log.xxxxx" */
+ /* We detect these by looking for the prefix "log." and
+ * the lack of the ".db#" suffix */
+ is_a_logfile = dblayer_is_logfilename(direntry->name);
+ if (is_a_logfile) {
+ seen_logfiles = 1;
+ }
+ if (is_a_logfile && (NULL != priv->dblayer_log_directory) &&
+ (0 != strlen(priv->dblayer_log_directory)) ) {
+ prefix = priv->dblayer_log_directory;
+ } else {
+ prefix = home_dir;
+ }
+ mkdir_p(prefix, 0700);
+ sprintf(filename1, "%s/%s", src_dir, direntry->name);
+ sprintf(filename2, "%s/%s", prefix, direntry->name);
+ LDAPDebug(LDAP_DEBUG_ANY, "Restoring file %d (%s)\n",
+ cnt, filename2, 0);
+ if (task) {
+ slapi_task_log_notice(task, "Restoring file %d (%s)",
+ cnt, filename2);
+ slapi_task_log_status(task, "Restoring file %d (%s)",
+ cnt, filename2);
+ }
+ return_value = dblayer_copyfile(filename1, filename2, 0,
+ priv->dblayer_file_mode);
+ if (0 > return_value)
+ break;
+
+ cnt++;
+ }
+ PR_CloseDir(dirhandle);
+ }
+ }
+ /* We're done ! */
+
+#if defined(UPGRADEDB)
+ /* [605024] check the DBVERSION and reset idl-switch if needed */
+ if (dbversion_exists(li, home_dir))
+ {
+ char ldbmversion[LDBM_VERSION_MAXBUF];
+ char dataversion[LDBM_VERSION_MAXBUF];
+
+ if (dbversion_read(li, home_dir, ldbmversion, dataversion) != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: Unable to read dbversion "
+ "file in %s\n", home_dir, 0, 0);
+ }
+ else
+ {
+ adjust_idl_switch(ldbmversion, li);
+ }
+ }
+#endif
+
+ return_value = check_db_version(li, &action);
+ if (action & DBVERSION_UPGRADE_3_4)
+ {
+ dbmode = DBLAYER_CLEAN_RECOVER_MODE;/* upgrade: remove logs & recover */
+ }
+ else if (seen_logfiles)
+ {
+ dbmode = DBLAYER_RESTORE_MODE;
+ }
+ else
+ {
+ dbmode = DBLAYER_RESTORE_NO_RECOVERY_MODE;
+ }
+
+ /* now start the database code up, to prevent recovery next time the
+ * server starts;
+ * dse_conf_verify may need to have db started, as well. */
+ /* If no logfiles were stored, then fatal recovery isn't required */
+
+ if (li->li_flags & TASK_RUNNING_FROM_COMMANDLINE)
+ {
+ dbmode |= DBLAYER_CMDLINE_MODE;
+ }
+ else /* on-line mode */
+ {
+ allinstance_set_not_busy(li);
+ }
+
+ tmp_rval = dblayer_start(li, dbmode);
+ if (0 != tmp_rval) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dblayer_restore: Failed to init database\n", 0, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task, "Failed to init database");
+ }
+ return tmp_rval;
+ }
+
+ if (0 == return_value) { /* only when the copyfile succeeded */
+ /* check the DSE_* files, if any */
+ tmp_rval = dse_conf_verify(li, src_dir);
+ if (0 != tmp_rval)
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: Unable to verify the index configuration\n", 0, 0, 0);
+ }
+
+ if (li->li_flags & TASK_RUNNING_FROM_COMMANDLINE) {
+ /* command line: close the database down again */
+ tmp_rval = dblayer_close(li, dbmode);
+ if (0 != tmp_rval) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dblayer_restore: Failed to close database\n", 0, 0, 0);
+ }
+ } else {
+ allinstance_set_busy(li); /* on-line mode */
+ }
+
+ return_value = tmp_rval?tmp_rval:return_value;
+
+ return return_value;
+}
+
+
+static char *dblayer_make_friendly_instance_name(ldbm_instance *inst)
+{
+ char *name = slapi_ch_strdup(inst->inst_name);
+ int x;
+
+ if (name == NULL)
+ return NULL;
+ for (x = 0; name[x]; x++)
+ if (name[x] == ' ')
+ name[x] = '_';
+ return name;
+}
+
+/*
+ * inst_dir_name is a relative path (from 6.21)
+ * ==> txn log stores relative paths and becomes relocatable
+ * if full path is given, parent dir is inst_parent_dir_name;
+ * otherwise, inst_dir in home_dir
+ *
+ * Set an appropriate path to inst_dir_name, if not yet.
+ * Create the specified directory, if not exists.
+ */
+int dblayer_get_instance_data_dir(backend *be)
+{
+ struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
+ ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
+ char *full_namep = NULL;
+ char full_name[MAXPATHLEN];
+ PRDir *db_dir = NULL;
+ int ret = -1;
+
+ /* if a specific directory name was specified for this particular
+ * instance use it othewise use the ldbm-wide one
+ */
+ full_namep = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ full_name, MAXPATHLEN);
+ /* Does this directory already exist? */
+ if ((db_dir = PR_OpenDir(full_namep)) != NULL) {
+ /* yep. */
+ PR_CloseDir(db_dir);
+ ret = 0;
+ } else {
+ /* nope -- create it. */
+ ret = mkdir_p(full_namep, 0700);
+ }
+
+ if (full_name != full_namep)
+ slapi_ch_free_string(&full_namep);
+
+ return ret;
+}
+
+char *
+dblayer_strerror(int error)
+{
+ return db_strerror(error);
+}
+
+/* [605974] check a db region file's existence to know whether import is executed by other process or not */
+#define DB_REGION_PREFIX "__db."
+
+int
+dblayer_in_import(ldbm_instance *inst)
+{
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = NULL;
+ int rval = 0;
+
+ inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ inst_dir, MAXPATHLEN);
+ dirhandle = PR_OpenDir(inst_dirp);
+
+ if (NULL == dirhandle)
+ goto done;
+
+ while (NULL != (direntry = PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == direntry->name)
+ {
+ break;
+ }
+ if (0 ==strncmp(direntry->name, DB_REGION_PREFIX, 5))
+ {
+ rval = 1;
+ break;
+ }
+ }
+ PR_CloseDir(dirhandle);
+done:
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ return rval;
+}
+
+/*
+ * to change the db extention (e.g., .db3 -> .db4)
+ */
+int dblayer_update_db_ext(ldbm_instance *inst, char *oldext, char *newext)
+{
+ struct attrinfo *a = NULL;
+ backend *be = NULL;
+ struct ldbminfo *li = NULL;
+ dblayer_private *priv = NULL;
+ DB *thisdb = NULL;
+ int rval = 0;
+ char *ofile = NULL;
+ char *nfile = NULL;
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp;
+
+ if (NULL == inst)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "update_db_ext: Null instance is passed\n", 0, 0, 0);
+ return -1; /* non zero */
+ }
+ be = inst->inst_be;
+ li = inst->inst_li;
+ priv = (dblayer_private*)li->li_dblayer_private;
+ inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
+ for (a = (struct attrinfo *)avl_getfirst(inst->inst_attrs);
+ NULL != a;
+ a = (struct attrinfo *)avl_getnext())
+ {
+ PRFileInfo info;
+ ofile = slapi_ch_malloc(strlen(inst_dirp) +
+ strlen(a->ai_type) + strlen(oldext) + 2);
+ sprintf(ofile, "%s/%s%s", inst_dirp, a->ai_type, oldext);
+
+ if (PR_GetFileInfo(ofile, &info) != PR_SUCCESS)
+ {
+ slapi_ch_free_string(&ofile);
+ continue;
+ }
+
+ /* db->rename disable DB in it; we need to create for each */
+ rval = db_create(&thisdb, priv->dblayer_env->dblayer_DB_ENV, 0);
+ if (0 != rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "db_create returned %d (%s)\n",
+ rval, dblayer_strerror(rval), 0);
+ goto done;
+ }
+ nfile = slapi_ch_malloc(strlen(inst_dirp) +
+ strlen(a->ai_type) + strlen(newext) + 2);
+ sprintf(nfile, "%s/%s%s", inst_dirp, a->ai_type, newext);
+ LDAPDebug(LDAP_DEBUG_TRACE, "update_db_ext: rename %s -> %s\n",
+ ofile, nfile, 0);
+
+ rval = thisdb->rename(thisdb, (const char *)ofile, NULL /* subdb */,
+ (const char *)nfile, 0);
+ if (0 != rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "rename returned %d (%s)\n",
+ rval, dblayer_strerror(rval), 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "update_db_ext: index (%s) Failed to update index %s -> %s\n",
+ inst->inst_name, ofile, nfile);
+ goto done;
+ }
+ slapi_ch_free_string(&ofile);
+ slapi_ch_free_string(&nfile);
+ }
+
+ rval = db_create(&thisdb, priv->dblayer_env->dblayer_DB_ENV, 0);
+ if (0 != rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "db_create returned %d (%s)\n",
+ rval, dblayer_strerror(rval), 0);
+ goto done;
+ }
+ ofile = slapi_ch_malloc(strlen(inst_dirp) +
+ strlen(ID2ENTRY) + strlen(oldext) + 2);
+ nfile = slapi_ch_malloc(strlen(inst_dirp) +
+ strlen(ID2ENTRY) + strlen(newext) + 2);
+ sprintf(ofile, "%s/%s%s", inst_dirp, ID2ENTRY, oldext);
+ sprintf(nfile, "%s/%s%s", inst_dirp, ID2ENTRY, newext);
+ LDAPDebug(LDAP_DEBUG_TRACE, "update_db_ext: rename %s -> %s\n",
+ ofile, nfile, 0);
+ rval = thisdb->rename(thisdb, (const char *)ofile, NULL /* subdb */,
+ (const char *)nfile, 0);
+ if (0 != rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "rename returned %d (%s)\n",
+ rval, dblayer_strerror(rval), 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "update_db_ext: index (%s) Failed to update index %s -> %s\n",
+ inst->inst_name, ofile, nfile);
+ }
+done:
+ slapi_ch_free_string(&ofile);
+ slapi_ch_free_string(&nfile);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+
+ return rval;
+}
+
+/*
+ * delete the index files belonging to the instance
+ */
+int dblayer_delete_indices(ldbm_instance *inst)
+{
+ int rval = -1;
+ struct attrinfo *a = NULL;
+ int i;
+
+ if (NULL == inst)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "update_index_ext: Null instance is passed\n", 0, 0, 0);
+ return rval;
+ }
+ rval = 0;
+ for (a = (struct attrinfo *)avl_getfirst(inst->inst_attrs), i = 0;
+ NULL != a;
+ a = (struct attrinfo *)avl_getnext(), i++)
+ {
+ rval += dblayer_erase_index_file(inst->inst_be, a, i/* chkpt; 1st time only */);
+ }
+ return rval;
+}
+
+void dblayer_set_recovery_required(struct ldbminfo *li)
+{
+ if (NULL == li || NULL == li->li_dblayer_private)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,"set_recovery_required: no dblayer info\n",
+ 0, 0, 0);
+ return;
+ }
+ li->li_dblayer_private->dblayer_recovery_required = 1;
+}
diff --git a/ldap/servers/slapd/back-ldbm/dblayer.h b/ldap/servers/slapd/back-ldbm/dblayer.h
new file mode 100644
index 00000000..78274ec6
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/dblayer.h
@@ -0,0 +1,140 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Structures and #defines used in the dblayer. */
+
+#ifndef _DBLAYER_H_
+#define _DBLAYER_H_
+
+#ifdef DB_USE_64LFS
+#ifdef OS_solaris
+#include <dlfcn.h> /* needed for dlopen and dlsym */
+#endif /* solaris: dlopen */
+#ifdef OS_solaris
+#include <sys/mman.h> /* needed for mmap/mmap64 */
+#ifndef MAP_FAILED
+#define MAP_FAILED (-1)
+#endif
+#endif /* solaris: mmap */
+#endif /* DB_USE_64LFS */
+
+#define DBLAYER_PAGESIZE (size_t)8*1024
+#define DBLAYER_INDEX_PAGESIZE (size_t)8*1024 /* With the new idl design,
+ the large 8Kbyte pages we use are not optimal. The page pool churns very
+ quickly as we add new IDs under a sustained add load. Smaller pages stop
+ this happening so much and consequently make us spend less time flushing
+ dirty pages on checkpoints. But 8K is still a good page size for id2entry.
+ So we now allow different page sizes for the primary and secondary indices.
+ */
+
+/* Interval, in ms, that threads sleep when they are wanting to
+ * wait for a while withouth spinning. If this time is too long,
+ * the server takes too long to shut down. If this interval is too
+ * short, then CPU time gets burned by threads doing nothing.
+ * As CPU speed increases over time, we reduce this interval
+ * to allow the server to be more responsive to shutdown.
+ * (Why is this important ? : A: because the TET tests start up
+ * and shut down the server a gazillion times, so the server
+ * shut down delay has a significant impact on the overall test
+ * run time (which is very very very looooonnnnnggggg....).)
+*/
+#define DBLAYER_SLEEP_INTERVAL 250
+
+#define DB_EXTN_PAGE_HEADER_SIZE 64 /* DBDB this is a guess */
+
+#define DBLAYER_CACHE_FORCE_FILE 1
+
+#define DBLAYER_LIB_VERSION_PRE_24 1
+#define DBLAYER_LIB_VERSION_POST_24 2
+
+/* Define constants from DB2.4 when using DB2.3 header file */
+#ifndef DB_TSL_SPINS
+#define DB_TSL_SPINS 21 /* DB: initialize spin count. */
+#endif
+#ifndef DB_REGION_INIT
+#define DB_REGION_INIT 24 /* DB: page-fault regions in create. */
+#endif
+#ifndef DB_REGION_NAME
+#define DB_REGION_NAME 25 /* DB: named regions, no backing file. */
+#endif
+
+struct dblayer_private_env {
+ DB_ENV *dblayer_DB_ENV;
+ PRRWLock * dblayer_env_lock;
+ int dblayer_openflags;
+ int dblayer_priv_flags;
+};
+
+#define DBLAYER_PRIV_SET_DATA_DIR 0x1
+
+/* structure which holds our stuff */
+struct dblayer_private
+{
+ struct dblayer_private_env * dblayer_env;
+ char *dblayer_home_directory;
+ char *dblayer_log_directory;
+ char *dblayer_dbhome_directory; /* default path for relative inst paths */
+ char **dblayer_data_directories; /* passed to set_data_dir
+ * including dblayer_dbhome_directory */
+ char **dblayer_db_config;
+ int dblayer_ncache;
+ int dblayer_previous_ncache;
+ int dblayer_tx_max;
+ size_t dblayer_cachesize;
+ size_t dblayer_previous_cachesize; /* Cache size when we last shut down--
+ * used to determine if we delete
+ * the mpool */
+ int dblayer_recovery_required;
+ int dblayer_enable_transactions;
+ int dblayer_durable_transactions;
+ int dblayer_checkpoint_interval;
+ int dblayer_circular_logging;
+ size_t dblayer_page_size; /* db page size if configured,
+ * otherwise default to DBLAYER_PAGESIZE */
+ size_t dblayer_index_page_size; /* db index page size if configured,
+ * otherwise default to
+ * DBLAYER_INDEX_PAGESIZE */
+ int dblayer_idl_divisor; /* divide page size by this to get IDL
+ * size */
+ size_t dblayer_logfile_size; /* How large can one logfile be ? */
+ size_t dblayer_logbuf_size; /* how large log buffer can be */
+ int dblayer_file_mode; /* pmode for files we create */
+ int dblayer_verbose; /* Get libdb to exhale debugging info */
+ int dblayer_debug; /* Will libdb emit debugging info into
+ * our log ? */
+ int dblayer_trickle_percentage;
+ int dblayer_cache_config; /* Special cache configurations
+ * e.g. force file-based mpool */
+ int dblayer_lib_version;
+ int dblayer_spin_count; /* DB Mutex spin count, 0 == use default */
+ int dblayer_named_regions; /* Should the regions be named sections,
+ * or backed by files ? */
+ int dblayer_private_mem; /* private memory will be used for
+ * allocation of regions and mutexes */
+ int dblayer_private_import_mem; /* private memory will be used for
+ * allocation of regions and mutexes for
+ * import */
+ long dblayer_shm_key; /* base segment ID for named regions */
+ int db_debug_checkpointing; /* Enable debugging messages from
+ * checkpointing */
+ int dblayer_bad_stuff_happened; /* Means that something happened (e.g. out
+ * of disk space) such that the guardian
+ * file must not be written on shutdown */
+ perfctrs_private *perf_private; /* Private data for performance counters
+ * code */
+ int dblayer_stop_threads; /* Used to signal to threads that they
+ * should stop ASAP */
+ PRInt32 dblayer_thread_count; /* Tells us how many threads are running,
+ * used to figure out when they're all
+ * stopped */
+ int dblayer_lockdown; /* use DB_LOCKDOWN */
+ int dblayer_lock_config;
+};
+
+int dblayer_db_remove(dblayer_private_env * env, char const path[], char const dbName[]);
+
+int dblayer_delete_indices(ldbm_instance *inst);
+
+#endif /* _DBLAYER_H_ */
diff --git a/ldap/servers/slapd/back-ldbm/dbsize.c b/ldap/servers/slapd/back-ldbm/dbsize.c
new file mode 100644
index 00000000..891310fd
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/dbsize.c
@@ -0,0 +1,25 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * dbsize.c - ldbm backend routine which returns the size (in bytes)
+ * that the database occupies on disk.
+ */
+
+#include "back-ldbm.h"
+
+int
+ldbm_db_size( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li;
+ unsigned int size;
+ int rc;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ rc = dblayer_database_size(li, &size);
+ slapi_pblock_set( pb, SLAPI_DBSIZE, &size );
+
+ return rc;
+}
diff --git a/ldap/servers/slapd/back-ldbm/dbtest.c b/ldap/servers/slapd/back-ldbm/dbtest.c
new file mode 100644
index 00000000..e2ba3dd0
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/dbtest.c
@@ -0,0 +1,312 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* dbtest.c - ldbm database test program */
+
+#include "back-ldbm.h"
+
+#define SLAPI_LDBM_DBTEST_OPT_DUMPDATA 0x0001
+#define SLAPI_LDBM_DBTEST_OPT_KEY_IS_BINARY 0x0002
+#define SLAPI_LDBM_DBTEST_OPT_DATA_IS_BINARY 0x0004
+#define SLAPI_LDBM_DBTEST_OPT_DATA_IS_IDLIST 0x0008
+#define SLAPI_LDBM_DBTEST_OPT_KEY_IS_ID 0x0010
+
+static void dbtest_help( void );
+static void dbtest_traverse( DB *db, char *filename, unsigned int options,
+ FILE *outfp );
+static void dbtest_print_idlist( char *keystr, void *p, u_int32_t size,
+ FILE *outfp );
+static void dbtest_bprint( char *data, int len, char *lineprefix,
+ FILE *outfp );
+
+int ldbm_back_db_test( Slapi_PBlock *pb )
+{
+ char buf[256], *instance_name;
+ backend *be;
+ struct ldbminfo *li;
+ ldbm_instance *inst;
+ struct attrinfo *ai;
+ DB *db;
+ int err, traversal_options;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+
+ /* essential initialization */
+ mapping_tree_init();
+ ldbm_config_load_dse_info(li);
+ /* Turn off transactions */
+ ldbm_config_internal_set(li, CONFIG_DB_TRANSACTION_LOGGING, "off");
+
+ /* Find the instance */
+ slapi_pblock_get( pb, SLAPI_BACKEND_INSTANCE_NAME, &instance_name );
+ inst = ldbm_instance_find_by_name(li, instance_name);
+ if (NULL == inst) {
+ LDAPDebug(LDAP_DEBUG_ANY, "dbtest: unknown ldbm instance %s\n",
+ instance_name, 0, 0);
+ return -1;
+ }
+
+ /* store the be in the pb */
+ be = inst->inst_be;
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+
+ /***** prepare & init libdb, dblayer, and dbinstance *****/
+ if (0 != dblayer_start(li, DBLAYER_TEST_MODE)) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "dbtest: Failed to init database\n", 0, 0, 0 );
+ return( -1 );
+ }
+ if ( 0 != dblayer_instance_start(inst->inst_be, DBLAYER_NORMAL_MODE)) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "dbtest: failed to start instance\n", 0, 0, 0 );
+ return( -1 );
+ }
+
+ /* display commands help test */
+ dbtest_help();
+
+ while ( 1 ) {
+ traversal_options = 0;
+ fputs( "dbtest: ", stdout );
+
+ if ( fgets( buf, sizeof(buf), stdin ) == NULL )
+ break;
+
+ switch ( buf[0] ) {
+ case 'i':
+ traversal_options |= SLAPI_LDBM_DBTEST_OPT_DATA_IS_IDLIST;
+ /*FALLTHRU*/
+
+ case 't':
+ traversal_options |= SLAPI_LDBM_DBTEST_OPT_DUMPDATA;
+ /*FALLTHRU*/
+
+ case 'T':
+ /* read the index to traverse */
+ fputs( " attr: ", stdout );
+ if ( fgets( buf, sizeof(buf), stdin ) == NULL ) {
+ exit( 0 );
+ }
+ buf[strlen( buf ) - 1] = '\0';
+ ai = NULL;
+ ainfo_get( be, buf, &ai );
+ if ( ai == NULL ) {
+ fprintf( stderr, "no index for %s\n", buf );
+ continue;
+ }
+
+ /* open the index file */
+ if ( (err = dblayer_get_index_file( be, ai, &db, 0 /* no create */ ))
+ != 0 ) {
+ fprintf( stderr, "could not get index for %s (error %d - %s)\n",
+ buf, err, slapd_system_strerror( err ));
+ continue;
+ }
+
+ /* traverse the file */
+ traversal_options |= SLAPI_LDBM_DBTEST_OPT_DATA_IS_BINARY;
+ dbtest_traverse( db, buf, traversal_options, stdout );
+
+ /* clean up */
+ dblayer_release_index_file( be, ai, db );
+ break;
+
+ case 'u':
+ traversal_options |= SLAPI_LDBM_DBTEST_OPT_DUMPDATA;
+ /*FALLTHRU*/
+
+ case 'U':
+ /* open the id2entry file */
+ if ( (err = dblayer_get_id2entry( be, &db )) != 0 ) {
+ fprintf( stderr, "could not get i2entry\n" );
+ continue;
+ }
+
+ /* traverse the file */
+ traversal_options |= SLAPI_LDBM_DBTEST_OPT_KEY_IS_ID;
+ dbtest_traverse( db, "id2entry", traversal_options, stdout );
+
+ /* clean up */
+ dblayer_release_id2entry( be, db );
+ break;
+
+ default:
+ dbtest_help();
+ break;
+ }
+ }
+
+ return( 0 );
+}
+
+
+static void
+dbtest_help()
+{
+ puts( LDBM_DATABASE_TYPE_NAME " test mode" );
+ puts( "\nindex key prefixes:" );
+ printf( " %c presence (sn=*)\n", PRES_PREFIX );
+ printf( " %c equality (sn=jensen)\n", EQ_PREFIX );
+ printf( " %c approximate (sn~=jensin)\n", APPROX_PREFIX );
+ printf( " %c substring (sn=jen*)\n", SUB_PREFIX );
+ printf( " %c matching rule (sn:1.2.3.4.5:=Jensen)\n", RULE_PREFIX );
+ printf( " %c continuation\n", CONT_PREFIX );
+
+ puts( "\ncommands: i => traverse index keys and ID list values" );
+ puts( " t => traverse index keys and values" );
+ puts( " T => traverse index keys" );
+ puts( " u => traverse id2entry keys and values" );
+ puts( " U => traverse id2entry keys" );
+#if 0
+ puts( " l<c> => lookup index" );
+ puts( " L<c> => lookup index (all)" );
+ puts( " t<c> => traverse index keys and values" );
+ puts( " T<c> => traverse index keys" );
+ puts( " x<c> => delete from index" );
+ puts( " e<c> => edit index entry" );
+ puts( " a<c> => add index entry" );
+ puts( " c<c> => create index" );
+ puts( " i<c> => insert ids into index" );
+ puts( " b => change default backend" );
+ puts( " B => print default backend" );
+ puts( " d<n> => set slapd_ldap_debug to n" );
+ puts( "where <c> is a char selecting the index:" );
+ puts( " c => id2children" );
+ puts( " d => dn2id" );
+ puts( " e => id2entry" );
+ puts( " f => arbitrary file" );
+ puts( " i => attribute index" );
+#endif /* 0 */
+}
+
+
+/*
+ * get a cursor and walk over the databasea
+ */
+static void
+dbtest_traverse( DB *db, char *filename, unsigned int options, FILE *outfp )
+{
+ DBC *dbc;
+ DBT key, data;
+
+ dbc = NULL;
+ if ( db->cursor( db, NULL, &dbc, 0 ) != 0 ) {
+ fprintf( stderr, "could not get cursor for %s\n", filename );
+ return;
+ }
+
+ memset( &key, 0, sizeof(key) );
+ memset( &data, 0, sizeof(data) );
+ key.flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ while ( dbc->c_get( dbc, &key, &data, DB_NEXT ) == 0 ) {
+ if (( options & SLAPI_LDBM_DBTEST_OPT_KEY_IS_BINARY ) != 0 ) {
+ fputs( "\tkey: ", outfp );
+ dbtest_bprint( key.data, key.size, "\t ", outfp );
+ } else if (( options & SLAPI_LDBM_DBTEST_OPT_KEY_IS_ID ) != 0 ) {
+ fprintf( outfp, "\tkey: %ld\n",
+ (u_long)id_stored_to_internal( (char *)key.data ));
+ } else {
+ fprintf( outfp, "\tkey: %s\n", (char *)key.data );
+ }
+ if (( options & SLAPI_LDBM_DBTEST_OPT_DUMPDATA ) != 0 ) {
+ if (( options & SLAPI_LDBM_DBTEST_OPT_DATA_IS_IDLIST ) != 0 ) {
+ fputs( "\tdata: ", outfp );
+ dbtest_print_idlist( (char *)key.dptr, data.data, data.size,
+ outfp );
+ } else if (( options & SLAPI_LDBM_DBTEST_OPT_DATA_IS_BINARY ) != 0 ) {
+ fputs( "\tdata: ", outfp );
+ dbtest_bprint( data.data, data.size, "\t ", outfp );
+ } else {
+ fprintf( outfp, "\tdata: %s\n", (char *)data.data );
+ }
+ }
+ free( key.data );
+ free( data.data );
+ }
+ dbc->c_close(dbc);
+}
+
+static void
+dbtest_print_idlist( char *keystr, void *p, u_int32_t size, FILE *outfp )
+{
+ IDList *idl;
+ ID i;
+
+ idl = (IDList *)p;
+ if ( ALLIDS( idl )) {
+ fputs( "ALLIDS block\n", outfp );
+ } else if ( INDIRECT_BLOCK( idl )) {
+ fputs( "Indirect block)\n", outfp );
+ for ( i = 0; idl->b_ids[i] != NOID; ++i ) {
+ fprintf( outfp, "\t\tkey: %c%s%lu\n", CONT_PREFIX, keystr,
+ (u_long)idl->b_ids[i] );
+ }
+ } else {
+ const char *block_type;
+
+ if ( NULL != keystr && *keystr == CONT_PREFIX ) {
+ block_type = "Continued";
+ } else {
+ block_type = "Regular";
+ }
+ fprintf( outfp, "%s block (count=%lu, max=%lu)\n",
+ block_type, (u_long)idl->b_nids, (u_long)idl->b_nmax );
+ for ( i = 0; i < idl->b_nids; ++i ) {
+ fprintf( outfp, "\t\tid: %lu\n", (u_long)idl->b_ids[i] );
+ }
+ }
+}
+
+
+
+#define BPLEN 48
+
+static void
+dbtest_bprint( char *data, int len, char *lineprefix, FILE *outfp )
+{
+ static char hexdig[] = "0123456789abcdef";
+ char out[ BPLEN ], *curprefix;
+ int i = 0;
+
+ if ( NULL == lineprefix ) {
+ lineprefix = "";
+ }
+ curprefix = "";
+
+ memset( out, 0, BPLEN );
+ for ( ;; ) {
+ if ( len < 1 ) {
+ if ( i > 0 ) {
+ fprintf( outfp, "%s%s\n", curprefix, out );
+ }
+ break;
+ }
+
+#ifndef HEX
+ if ( isgraph( (unsigned char)*data )) {
+ out[ i ] = ' ';
+ out[ i+1 ] = *data;
+ } else {
+#endif
+ out[ i ] = hexdig[ ( *data & 0xf0 ) >> 4 ];
+ out[ i+1 ] = hexdig[ *data & 0x0f ];
+#ifndef HEX
+ }
+#endif
+ i += 2;
+ len--;
+ data++;
+
+ if ( i > BPLEN - 2 ) {
+ fprintf( outfp, "%s%s\n", curprefix, out );
+ curprefix = lineprefix;
+ memset( out, 0, BPLEN );
+ i = 0;
+ continue;
+ }
+ out[ i++ ] = ' ';
+ }
+}
diff --git a/ldap/servers/slapd/back-ldbm/dbversion.c b/ldap/servers/slapd/back-ldbm/dbversion.c
new file mode 100644
index 00000000..4c1a56da
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/dbversion.c
@@ -0,0 +1,181 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "back-ldbm.h"
+
+static void
+mk_dbversion_fullpath(struct ldbminfo *li, const char *directory, char *filename)
+{
+ if (li)
+ {
+ if (is_fullpath((char *)directory))
+ {
+ sprintf(filename, "%s/%s", directory, DBVERSION_FILENAME);
+ }
+ else
+ {
+ char *home_dir = dblayer_get_home_dir(li, NULL);
+ /* if relpath, nsslapd-dbhome_directory should be set */
+ sprintf(filename,"%s/%s/%s", home_dir,directory,DBVERSION_FILENAME);
+ }
+ }
+ else
+ {
+ sprintf(filename, "%s/%s", directory, DBVERSION_FILENAME);
+ }
+}
+
+/*
+ * Function: dbversion_write
+ *
+ * Returns: returns 0 on success, -1 on failure
+ *
+ * Description: This function writes the DB version file.
+ */
+int
+dbversion_write(struct ldbminfo *li, const char *directory,
+ const char *dataversion)
+{
+ char filename[ MAXPATHLEN*2 ];
+ PRFileDesc *prfd;
+ int rc = 0;
+
+ PR_ASSERT(is_fullpath((char *)directory));
+ mk_dbversion_fullpath(li, directory, filename);
+
+ /* Open the file */
+ if (( prfd = PR_Open( filename, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
+ SLAPD_DEFAULT_FILE_MODE )) == NULL )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Could not open file \"%s\" for writing "
+ SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
+ filename, PR_GetError(), slapd_pr_strerror(PR_GetError()) );
+ rc= -1;
+ }
+ else
+ {
+ /* Write the file */
+ PRInt32 len;
+ char buf[ LDBM_VERSION_MAXBUF ];
+ /* recognize the difference between an old/new database regarding idl
+ * (406922) */
+ if (idl_get_idl_new())
+ {
+#if defined(USE_NEW_IDL)
+ sprintf( buf, "%s\n", LDBM_VERSION );
+#else
+ sprintf( buf, "%s\n", LDBM_VERSION_NEW );
+#endif
+ }
+ else
+ {
+#if defined(USE_NEW_IDL)
+ sprintf( buf, "%s\n", LDBM_VERSION_OLD );
+#else
+ sprintf( buf, "%s\n", LDBM_VERSION );
+#endif
+ }
+ len = strlen( buf );
+ if ( slapi_write_buffer( prfd, buf, len ) != len )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Could not write to file \"%s\"\n", filename, 0, 0 );
+ rc= -1;
+ }
+ if(rc==0 && dataversion!=NULL)
+ {
+ sprintf( buf, "%s\n", dataversion );
+ len = strlen( buf );
+ if ( slapi_write_buffer( prfd, buf, len ) != len )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Could not write to file \"%s\"\n", filename, 0, 0 );
+ rc= -1;
+ }
+ }
+ (void)PR_Close( prfd );
+ }
+ return rc;
+}
+
+/*
+ * Function: dbversion_read
+ *
+ * Returns: returns 0 on success, -1 on failure
+ *
+ * Description: This function reads the DB version file.
+ */
+int
+dbversion_read(struct ldbminfo *li, const char *directory,
+ char *ldbmversion, char *dataversion)
+{
+ char filename[ MAXPATHLEN*2 ];
+ PRFileDesc *prfd;
+ int rc = -1;
+ char * iter = NULL;
+
+ PR_ASSERT(is_fullpath((char *)directory));
+ mk_dbversion_fullpath(li, directory, filename);
+
+ ldbmversion[0]= '\0';
+ dataversion[0]= '\0';
+
+ /* Open the file */
+ if (( prfd = PR_Open( filename, PR_RDONLY, SLAPD_DEFAULT_FILE_MODE )) ==
+ NULL )
+ {
+ /* File missing... we are probably creating a new database. */
+ }
+ else
+ {
+ char buf[LDBM_VERSION_MAXBUF];
+ PRInt32 nr = slapi_read_buffer( prfd, buf,
+ (PRInt32)LDBM_VERSION_MAXBUF-1 );
+ if ( nr > 0 && nr != (PRInt32)LDBM_VERSION_MAXBUF-1 )
+ {
+ char *t;
+ buf[nr]= '\0';
+ t= ldap_utf8strtok_r(buf,"\n", &iter);
+ if(t!=NULL)
+ {
+ strcpy(ldbmversion,t);
+ t= ldap_utf8strtok_r(NULL,"\n", &iter);
+ if(t!=NULL && t[0]!='\0')
+ {
+ strcpy(dataversion,t);
+ }
+ }
+ }
+ (void)PR_Close( prfd );
+ rc= 0;
+ }
+ return rc;
+}
+
+
+/*
+ * Function: dbversion_exists
+ *
+ * Returns: 1 for exists, 0 for not.
+ *
+ * Description: This function checks if the DB version file exists.
+ */
+int
+dbversion_exists(struct ldbminfo *li, const char *directory)
+{
+ char filename[ MAXPATHLEN*2 ];
+ PRFileDesc *prfd;
+
+ PR_ASSERT(is_fullpath((char *)directory));
+ mk_dbversion_fullpath(li, directory, filename);
+
+ if (( prfd = PR_Open( filename, PR_RDONLY, SLAPD_DEFAULT_FILE_MODE )) ==
+ NULL )
+ {
+ return 0;
+ }
+ (void)PR_Close( prfd );
+ return 1;
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/dllmain.c b/ldap/servers/slapd/back-ldbm/dllmain.c
new file mode 100644
index 00000000..d473ca49
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/dllmain.c
@@ -0,0 +1,128 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for BACK-LDBM DLL
+ */
+#include "back-ldbm.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
+
+#ifdef LDAP_DEBUG
+#ifndef _WIN32
+#include <stdarg.h>
+#include <stdio.h>
+
+void LDAPDebug( int level, char* fmt, ... )
+{
+ static char debugBuf[1024];
+
+ if (slapd_ldap_debug & level)
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ _snprintf (debugBuf, sizeof(debugBuf), fmt, ap);
+ va_end (ap);
+
+ OutputDebugString (debugBuf);
+ }
+}
+#endif
+#endif
+
+#ifndef _WIN32
+
+/* The 16-bit version of the RTL does not implement perror() */
+
+#include <stdio.h>
+
+void perror( const char *msg )
+{
+ char buf[128];
+ wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ;
+ OutputDebugString( buf );
+}
+
+#endif
diff --git a/ldap/servers/slapd/back-ldbm/dn2entry.c b/ldap/servers/slapd/back-ldbm/dn2entry.c
new file mode 100644
index 00000000..f34e7f77
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/dn2entry.c
@@ -0,0 +1,230 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* dn2entry.c - given a dn return an entry */
+
+#include "back-ldbm.h"
+
+/*
+ * Fetch the entry for this DN.
+ *
+ * Retuns NULL of the entry doesn't exist
+ */
+struct backentry *
+dn2entry(
+ Slapi_Backend *be,
+ const Slapi_DN *sdn,
+ back_txn *txn,
+ int *err
+)
+{
+ ldbm_instance *inst;
+ struct berval ndnv;
+ struct backentry *e = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2entry \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
+
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ *err = 0;
+ ndnv.bv_val = (void*)slapi_sdn_get_ndn(sdn); /* jcm - Had to cast away const */
+ ndnv.bv_len = slapi_sdn_get_ndn_len(sdn);
+
+ e = cache_find_dn(&inst->inst_cache, ndnv.bv_val, ndnv.bv_len);
+ if (e == NULL)
+ {
+ /* convert dn to entry id */
+ IDList *idl = NULL;
+ if ( (idl = index_read( be, "entrydn", indextype_EQUALITY, &ndnv, txn, err )) == NULL )
+ {
+ /* There's no entry with this DN. */
+ }
+ else
+ {
+ /* convert entry id to entry */
+ if ( (e = id2entry( be, idl_firstid( idl ), txn, err )) != NULL )
+ {
+ /* Means that we found the entry OK */
+ }
+ else
+ {
+ /* Hmm. The DN mapped onto an EntryID, but that didn't map onto an Entry. */
+ if ( *err != 0 && *err != DB_NOTFOUND )
+ {
+ /* JCM - Not sure if this is ever OK or not. */
+ }
+ else
+ {
+ /*
+ * this is pretty bad anyway. the dn was in the
+ * entrydn index, but we could not read the entry
+ * from the id2entry index. what should we do?
+ */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "dn2entry: the dn was in the entrydn index (id %lu), "
+ "but it did not exist in id2entry.\n",
+ (u_long)idl_firstid( idl ), 0, 0 );
+ }
+ }
+ slapi_ch_free((void**)&idl);
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= dn2entry %p\n", e, 0, 0 );
+ return( e );
+}
+
+/*
+ * dn2entry_or_ancestor - look up dn in the cache/indexes and return the
+ * corresponding entry. If the entry is not found, this function returns NULL
+ * and sets ancestordn to the DN of highest entry in the tree matched.
+ *
+ * ancestordn should be initialized before calling this function.
+ *
+ * When the caller is finished with the entry returned, it should return it
+ * to the cache:
+ * e = dn2entry_or_ancestor( ... );
+ * if ( NULL != e ) {
+ * cache_return( &inst->inst_cache, &e );
+ * }
+ */
+struct backentry *
+dn2entry_or_ancestor(
+ Slapi_Backend *be,
+ const Slapi_DN *sdn,
+ Slapi_DN *ancestordn,
+ back_txn *txn,
+ int *err
+)
+{
+ struct backentry *e;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2entry_or_ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
+
+ /*
+ * Fetch the entry asked for.
+ */
+
+ e= dn2entry(be,sdn,txn,err);
+
+ if(e==NULL)
+ {
+ /*
+ * could not find the entry named. crawl back up the dn and
+ * stop at the first ancestor that does exist, or when we get
+ * to the suffix.
+ */
+ e= dn2ancestor(be,sdn,ancestordn,txn,err);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= dn2entry_or_ancestor %p\n", e, 0, 0 );
+ return( e );
+}
+
+/*
+ * Use the DN to fetch the parent of the entry.
+ * If the parent entry doesn't exist, keep working
+ * up the DN until we hit "" or an backend suffix.
+ *
+ * ancestordn should be initialized before calling this function.
+ *
+ * Returns NULL for no entry found.
+ *
+ * When the caller is finished with the entry returned, it should return it
+ * to the cache:
+ * e = dn2ancestor( ... );
+ * if ( NULL != e ) {
+ * cache_return( &inst->inst_cache, &e );
+ * }
+ */
+struct backentry *
+dn2ancestor(
+ Slapi_Backend *be,
+ const Slapi_DN *sdn,
+ Slapi_DN *ancestordn,
+ back_txn *txn,
+ int *err
+)
+{
+ struct backentry *e = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> dn2ancestor \"%s\"\n", slapi_sdn_get_dn(sdn), 0, 0 );
+
+ /* stop when we get to "", or a backend suffix point */
+ slapi_sdn_done(ancestordn); /* free any previous contents */
+ slapi_sdn_get_backend_parent(sdn,ancestordn,be);
+ if ( !slapi_sdn_isempty(ancestordn) )
+ {
+ Slapi_DN *newsdn = slapi_sdn_dup(ancestordn);
+ e = dn2entry_or_ancestor( be, newsdn, ancestordn, txn, err );
+ slapi_sdn_free(&newsdn);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= dn2ancestor %p\n", e, 0, 0 );
+ return( e );
+}
+
+/*
+ * Use uniqueid2entry or dn2entry to fetch an entry from the cache,
+ * make a copy of it, and stash it in the pblock.
+ */
+int
+get_copy_of_entry(Slapi_PBlock *pb, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist) /* JCM - Move somewhere more appropriate */
+{
+ int err= 0;
+ int rc= LDAP_SUCCESS;
+ backend *be;
+ struct backentry *entry;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be);
+
+ if( addr->uniqueid!=NULL)
+ {
+ entry = uniqueid2entry(be, addr->uniqueid, txn, &err );
+ }
+ else
+ {
+ Slapi_DN sdn;
+ slapi_sdn_init_dn_byref (&sdn, addr->dn); /* We assume that the DN is not normalized */
+ entry = dn2entry( be, &sdn, txn, &err );
+ slapi_sdn_done (&sdn);
+ }
+ if ( 0 != err && DB_NOTFOUND != err )
+ {
+ if(must_exist)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Operation error fetching %s (%s), error %d.\n",
+ addr->dn, (addr->uniqueid==NULL?"null":addr->uniqueid), err );
+ }
+ rc= LDAP_OPERATIONS_ERROR;
+ }
+ else
+ {
+ /* If an entry is found, copy it into the PBlock. */
+ if(entry!=NULL)
+ {
+ ldbm_instance *inst;
+ slapi_pblock_set( pb, plock_parameter, slapi_entry_dup(entry->ep_entry));
+ inst = (ldbm_instance *) be->be_instance_info;
+ cache_return( &inst->inst_cache, &entry );
+ }
+ }
+ /* JCMREPL - Free the backentry? */
+ return rc;
+}
+
+void
+done_with_pblock_entry(Slapi_PBlock *pb, int plock_parameter) /* JCM - Move somewhere more appropriate */
+{
+ Slapi_Entry *entry;
+ slapi_pblock_get( pb, plock_parameter, &entry);
+ if(entry!=NULL)
+ {
+ slapi_entry_free(entry);
+ entry= NULL;
+ slapi_pblock_set( pb, plock_parameter, entry);
+ }
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/entrystore.c b/ldap/servers/slapd/back-ldbm/entrystore.c
new file mode 100644
index 00000000..46c011ae
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/entrystore.c
@@ -0,0 +1,12 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* entrystore.c --- functions dealing with entries and their storage.
+ Put computed attributes, compression etc here */
+
+#include "back-ldbm.h"
+
+/* Nothing here yet */
diff --git a/ldap/servers/slapd/back-ldbm/filterindex.c b/ldap/servers/slapd/back-ldbm/filterindex.c
new file mode 100644
index 00000000..445f3195
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/filterindex.c
@@ -0,0 +1,830 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* filterindex.c - generate the list of candidate entries from a filter */
+
+#include "back-ldbm.h"
+#include "../index_subsys.h"
+
+extern const char *indextype_PRESENCE;
+extern const char *indextype_EQUALITY;
+extern const char *indextype_APPROX;
+extern const char *indextype_SUB;
+
+static IDList *ava_candidates(Slapi_PBlock *pb, backend *be, Slapi_Filter *f, int ftype, Slapi_Filter *nextf, int range, int *err);
+static IDList *presence_candidates(Slapi_PBlock *pb, backend *be, Slapi_Filter *f, int *err);
+static IDList *extensible_candidates(backend *be, Slapi_Filter *f, int *err);
+static IDList *list_candidates(Slapi_PBlock *pb, backend *be, const char *base, Slapi_Filter *flist, int ftype, int *err);
+static IDList *substring_candidates(Slapi_PBlock *pb, backend *be, Slapi_Filter *f, int *err);
+static IDList * range_candidates(
+ Slapi_PBlock *pb,
+ backend *be,
+ char *type,
+ struct berval *low_val,
+ struct berval *high_val,
+ int *err
+);
+static IDList *
+keys2idl(
+ backend *be,
+ char *type,
+ const char *indextype,
+ Slapi_Value **ivals,
+ int *err
+);
+
+IDList *
+filter_candidates(
+ Slapi_PBlock *pb,
+ backend *be,
+ const char *base,
+ Slapi_Filter *f,
+ Slapi_Filter *nextf,
+ int range,
+ int *err
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ IDList *result;
+ int ftype;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> filter_candidates\n", 0, 0, 0 );
+
+ /* check if this is to be serviced by a virtual index */
+ if(INDEX_FILTER_EVALUTED == index_subsys_evaluate_filter(f, (Slapi_DN*)slapi_be_getsuffix(be, 0), (IndexEntryList**)&result))
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= filter_candidates %lu (vattr)\n",
+ (u_long)IDL_NIDS(result), 0, 0 );
+ return result;
+ }
+
+ if (li->li_use_vlv) {
+ /* first, check to see if this particular filter node matches any
+ * vlv indexes we're keeping. if so, we can use that index
+ * instead.
+ */
+ result = vlv_find_index_by_filter(be, base, f);
+ if (result) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= filter_candidates %lu (vlv)\n",
+ (u_long)IDL_NIDS(result), 0, 0 );
+ return result;
+ }
+ }
+
+ result = NULL;
+ switch ( (ftype = slapi_filter_get_choice( f )) ) {
+ case LDAP_FILTER_EQUALITY:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tEQUALITY\n", 0, 0, 0 );
+ result = ava_candidates( pb, be, f, LDAP_FILTER_EQUALITY, nextf, range, err );
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tSUBSTRINGS\n", 0, 0, 0 );
+ result = substring_candidates( pb, be, f, err );
+ break;
+
+ case LDAP_FILTER_GE:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tGE\n", 0, 0, 0 );
+ result = ava_candidates( pb, be, f, LDAP_FILTER_GE, nextf, range,
+ err );
+ break;
+
+ case LDAP_FILTER_LE:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tLE\n", 0, 0, 0 );
+ result = ava_candidates( pb, be, f, LDAP_FILTER_LE, nextf, range,
+ err );
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tPRESENT\n", 0, 0, 0 );
+ result = presence_candidates( pb, be, f, err );
+ break;
+
+ case LDAP_FILTER_APPROX:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tAPPROX\n", 0, 0, 0 );
+ result = ava_candidates( pb, be, f, LDAP_FILTER_APPROX, nextf,
+ range, err );
+ break;
+
+ case LDAP_FILTER_EXTENDED:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tEXTENSIBLE\n", 0, 0, 0 );
+ result = extensible_candidates( be, f, err );
+ break;
+
+ case LDAP_FILTER_AND:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tAND\n", 0, 0, 0 );
+ result = list_candidates( pb, be, base, f, LDAP_FILTER_AND, err );
+ break;
+
+ case LDAP_FILTER_OR:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tOR\n", 0, 0, 0 );
+ result = list_candidates( pb, be, base, f, LDAP_FILTER_OR, err );
+ break;
+
+ case LDAP_FILTER_NOT:
+ LDAPDebug( LDAP_DEBUG_FILTER, "\tNOT\n", 0, 0, 0 );
+ result = idl_allids( be );
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "filter_candidates: unknown type 0x%X\n",
+ ftype, 0, 0 );
+ break;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= filter_candidates %lu\n",
+ (u_long)IDL_NIDS(result), 0, 0 );
+ return( result );
+}
+
+static IDList *
+ava_candidates(
+ Slapi_PBlock *pb,
+ backend *be,
+ Slapi_Filter *f,
+ int ftype,
+ Slapi_Filter *nextf,
+ int range,
+ int *err
+)
+{
+ char *type, *indextype = NULL;
+ Slapi_Value sv;
+ struct berval *bval;
+ Slapi_Value **ivals;
+ IDList *idl;
+ void *pi;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ava_candidates\n", 0, 0, 0 );
+
+ if ( slapi_filter_get_ava( f, &type, &bval ) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, " slapi_filter_get_ava failed\n",
+ 0, 0, 0 );
+ return( NULL );
+ }
+
+#ifdef LDAP_DEBUG
+ if ( LDAPDebugLevelIsSet( LDAP_DEBUG_TRACE )) {
+ char *op = NULL;
+ char buf[BUFSIZ];
+
+ switch ( ftype ) {
+ case LDAP_FILTER_GE:
+ op = ">=";
+ break;
+ case LDAP_FILTER_LE:
+ op = "<=";
+ break;
+ case LDAP_FILTER_EQUALITY:
+ op = "=";
+ break;
+ case LDAP_FILTER_APPROX:
+ op = "~=";
+ break;
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, " %s%s%s\n", type, op,
+ encode( bval, buf ) );
+ }
+#endif
+
+ switch ( ftype ) {
+ case LDAP_FILTER_GE:
+ idl = range_candidates(pb, be, type, bval, NULL, err);
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n",
+ (u_long)IDL_NIDS(idl), 0, 0 );
+ return( idl );
+ case LDAP_FILTER_LE:
+ idl = range_candidates(pb, be, type, NULL, bval, err);
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n",
+ (u_long)IDL_NIDS(idl), 0, 0 );
+ return( idl );
+ case LDAP_FILTER_EQUALITY:
+ indextype = (char*)indextype_EQUALITY;
+ break;
+ case LDAP_FILTER_APPROX:
+ indextype = (char*)indextype_APPROX;
+ break;
+ }
+
+ /*
+ * get the keys corresponding to this assertion value
+ */
+ if ( slapi_attr_type2plugin( type, &pi ) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, " slapi_filter_get_ava no plugin\n",
+ 0, 0, 0 );
+ return( NULL );
+ }
+
+ /* This code is result of performance anlysis; we are trying to
+ * optimize our equality filter processing -- mainly by limiting
+ * malloc/free calls.
+ *
+ * When the filter type is LDAP_FILTER_EQUALITY_FAST, the
+ * syntax_assertion2keys functions are passed a stack-based
+ * destination Slapi_Value array (ivals) that contains room
+ * for one key value with a fixed size buffer (also stack-based).
+ * If the buffer provided is not large enough, the
+ * syntax_assertion2keys function can alloc a new buffer (and
+ * reset ivals[0]->bv.bv_val) or alloc an entirely new ivals array.
+ */
+
+ if(ftype==LDAP_FILTER_EQUALITY) {
+ Slapi_Value tmp, *ptr[2], fake;
+ char buf[1024];
+
+ tmp.bv = *bval;
+ tmp.v_csnset=NULL;
+ fake.bv.bv_val=buf;
+ fake.bv.bv_len=sizeof(buf);
+ ptr[0]=&fake;
+ ptr[1]=NULL;
+ ivals=ptr;
+
+ slapi_call_syntax_assertion2keys_ava_sv( pi, &tmp, (Slapi_Value ***)&ivals, LDAP_FILTER_EQUALITY_FAST);
+ idl = keys2idl( be, type, indextype, ivals, err );
+
+ /* We don't use valuearray_free here since the valueset, berval
+ * and value was all allocated at once in one big chunk for
+ * performance reasons
+ */
+ if (fake.bv.bv_val != buf) {
+ slapi_ch_free((void**)&fake.bv.bv_val);
+ }
+
+ /* Some syntax_assertion2keys functions may allocate a whole new
+ * ivals array. Free it if so.
+ */
+ if (ivals != ptr) {
+ slapi_ch_free((void**)&ivals);
+ }
+ } else {
+ slapi_value_init_berval(&sv, bval);
+ ivals=NULL;
+ slapi_call_syntax_assertion2keys_ava_sv( pi, &sv, &ivals, ftype );
+ value_done(&sv);
+ if ( ivals == NULL || *ivals == NULL ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= ava_candidates ALLIDS (no keys)\n", 0, 0, 0 );
+ return( idl_allids( be ) );
+ }
+ idl = keys2idl( be, type, indextype, ivals, err );
+ valuearray_free( &ivals );
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ava_candidates %lu\n",
+ (u_long)IDL_NIDS(idl), 0, 0 );
+ }
+ return( idl );
+}
+
+static IDList *
+presence_candidates(
+ Slapi_PBlock *pb,
+ backend *be,
+ Slapi_Filter *f,
+ int *err
+)
+{
+ char *type;
+ IDList *idl;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> presence_candidates\n", 0, 0, 0 );
+
+ if ( slapi_filter_get_type( f, &type ) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, " slapi_filter_get_type failed\n",
+ 0, 0, 0 );
+ return( NULL );
+ }
+ idl = index_read( be, type, indextype_PRESENCE, NULL, NULL, err );
+
+ if (idl != NULL && ALLIDS(idl) && strcasecmp(type, "nscpentrydn") == 0) {
+ /* try the equality index instead */
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "fallback to eq index as pres index gave allids\n",
+ 0, 0, 0);
+ idl_free(idl);
+ idl = index_range_read(pb, be, type, indextype_EQUALITY,
+ SLAPI_OP_GREATER_OR_EQUAL,
+ NULL, NULL, 0, NULL, err);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= presence_candidates %lu\n",
+ (u_long)IDL_NIDS(idl), 0, 0 );
+ return( idl );
+}
+
+static IDList *
+extensible_candidates(
+ backend *be,
+ Slapi_Filter *f,
+ int *err
+)
+{
+ IDList* idl = NULL;
+ Slapi_PBlock* pb = slapi_pblock_new();
+ int mrOP = 0;
+ LDAPDebug (LDAP_DEBUG_TRACE, "=> extensible_candidates\n", 0, 0, 0);
+ if ( ! slapi_mr_filter_index (f, pb) && !slapi_pblock_get (pb, SLAPI_PLUGIN_MR_QUERY_OPERATOR, &mrOP))
+ {
+ switch (mrOP)
+ {
+ case SLAPI_OP_LESS:
+ case SLAPI_OP_LESS_OR_EQUAL:
+ case SLAPI_OP_EQUAL:
+ case SLAPI_OP_GREATER_OR_EQUAL:
+ case SLAPI_OP_GREATER:
+ {
+ IFP mrINDEX = NULL;
+ void* mrOBJECT = NULL;
+ struct berval** mrVALUES = NULL;
+ char* mrOID = NULL;
+ char* mrTYPE = NULL;
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrINDEX);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_OBJECT, &mrOBJECT);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_VALUES, &mrVALUES);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_OID, &mrOID);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_TYPE, &mrTYPE);
+
+ if (mrVALUES != NULL && *mrVALUES != NULL)
+ {
+ /*
+ * Compute keys for each of the values, individually.
+ * Search the index, for the computed keys.
+ * Collect the resulting IDs in idl.
+ */
+ size_t n;
+ struct berval** val;
+ mrTYPE = slapi_attr_basetype (mrTYPE, NULL, 0);
+ for (n=0,val=mrVALUES; *val; ++n,++val)
+ {
+ struct berval** keys = NULL;
+ /* keys = mrINDEX (*val), conceptually. In detail: */
+ struct berval* bvec[2];
+ bvec[0] = *val;
+ bvec[1] = NULL;
+ if (slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, mrOBJECT) ||
+ slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUES, bvec) ||
+ mrINDEX (pb) ||
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_KEYS, &keys))
+ {
+ /* something went wrong. bail. */
+ break;
+ }
+ else if (keys == NULL || keys[0] == NULL)
+ {
+ /* no keys */
+ idl_free (idl);
+ idl = idl_allids (be);
+ }
+ else
+ {
+ IDList* idl2= NULL;
+ struct berval** key;
+ for (key = keys; *key != NULL; ++key)
+ {
+ IDList* idl3 = (mrOP == SLAPI_OP_EQUAL) ?
+ index_read (be, mrTYPE, mrOID, *key, NULL, err) :
+ index_range_read (pb, be, mrTYPE, mrOID, mrOP, *key, NULL, 0, NULL, err);
+ if (idl2 == NULL)
+ {
+ /* first iteration */
+ idl2 = idl3;
+ }
+ else
+ {
+ IDList* tmp = idl_intersection (be, idl2, idl3);
+ idl_free (idl2);
+ idl_free (idl3);
+ idl2 = tmp;
+ }
+ if (idl2 == NULL) break; /* look no further */
+ }
+ if (idl == NULL)
+ {
+ idl = idl2;
+ }
+ else if (idl2 != NULL)
+ {
+ IDList* tmp = idl_union (be, idl, idl2);
+ idl_free (idl);
+ idl_free (idl2);
+ idl = tmp;
+ }
+ }
+ }
+ slapi_ch_free((void**)&mrTYPE);
+ goto return_idl; /* possibly no matches */
+ }
+ }
+ break;
+ default:
+ /* unsupported query operator */
+ break;
+ }
+ }
+ if (idl == NULL)
+ {
+ /* this filter isn't indexed */
+ idl = idl_allids (be); /* all entries are candidates */
+ }
+return_idl:
+ slapi_pblock_destroy (pb);
+ LDAPDebug (LDAP_DEBUG_TRACE, "<= extensible_candidates %lu\n",
+ (u_long)IDL_NIDS(idl), 0, 0);
+ return idl;
+}
+
+static int
+slapi_berval_reverse_cmp(const struct berval *a, const struct berval *b)
+{
+ return slapi_berval_cmp(b, a);
+}
+
+static IDList *
+range_candidates(
+ Slapi_PBlock *pb,
+ backend *be,
+ char *type,
+ struct berval *low_val,
+ struct berval *high_val,
+ int *err
+)
+{
+ IDList *idl;
+ struct berval *low = NULL, *high = NULL;
+ struct berval **lows = NULL, **highs = NULL;
+ void *pi;
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "=> range_candidates attr=%s\n", type, 0, 0);
+
+ /*
+ * get the keys corresponding to the assertion values
+ */
+
+ if ( slapi_attr_type2plugin( type, &pi ) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, " slapi_filter_get_ava no plugin\n",
+ 0, 0, 0 );
+ return( NULL );
+ }
+
+ if (low_val != NULL) {
+ slapi_call_syntax_assertion2keys_ava(pi, low_val, &lows, LDAP_FILTER_EQUALITY);
+ if (lows == NULL || *lows == NULL) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= range_candidates ALLIDS (no keys)\n", 0, 0, 0 );
+ return( idl_allids( be ) );
+ }
+ low = attr_value_lowest(lows, slapi_berval_reverse_cmp);
+ }
+
+ if (high_val != NULL) {
+ slapi_call_syntax_assertion2keys_ava(pi, high_val, &highs, LDAP_FILTER_EQUALITY);
+ if (highs == NULL || *highs == NULL) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= range_candidates ALLIDS (no keys)\n", 0, 0, 0 );
+ if (lows) ber_bvecfree(lows);
+ return( idl_allids( be ) );
+ }
+ high = attr_value_lowest(highs, slapi_berval_cmp);
+ }
+
+ if (low == NULL) {
+ idl = index_range_read(pb, be, type, (char*)indextype_EQUALITY,
+ SLAPI_OP_LESS_OR_EQUAL,
+ high, NULL, 0, NULL, err);
+ } else if (high == NULL) {
+ idl = index_range_read(pb, be, type, (char*)indextype_EQUALITY,
+ SLAPI_OP_GREATER_OR_EQUAL,
+ low, NULL, 0, NULL, err);
+ } else {
+ idl = index_range_read(pb, be, type, (char*)indextype_EQUALITY,
+ SLAPI_OP_GREATER_OR_EQUAL,
+ low, high, 1, NULL, err);
+ }
+
+ if (lows) ber_bvecfree(lows);
+ if (highs) ber_bvecfree(highs);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= range_candidates %lu\n",
+ (u_long)IDL_NIDS(idl), 0, 0 );
+
+ return idl;
+}
+
+static IDList *
+list_candidates(
+ Slapi_PBlock *pb,
+ backend *be,
+ const char *base,
+ Slapi_Filter *flist,
+ int ftype,
+ int *err
+)
+{
+ IDList *idl, *tmp, *tmp2;
+ Slapi_Filter *f, *nextf, *f_head;
+ int range = 0;
+ int isnot;
+ int f_count = 0, le_count = 0, ge_count = 0, is_bounded_range = 1;
+ struct berval *low_val = NULL, *high_val = NULL;
+ char *t1;
+ Slapi_Filter *fpairs[2] = {NULL, NULL}; /* low, high */
+ char *tpairs[2] = {NULL, NULL};
+ struct berval *vpairs[2] = {NULL, NULL};
+ int is_and = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> list_candidates 0x%x\n", ftype, 0, 0 );
+
+ /*
+ * Optimize bounded range queries such as (&(cn>=A)(cn<=B)).
+ * Could be better by matching pairs in a longer list
+ * but for now support only a single pair.
+ */
+ if (ftype != LDAP_FILTER_AND)
+ {
+ is_bounded_range = 0;
+ }
+ for ( f = slapi_filter_list_first( flist );
+ f != NULL && is_bounded_range;
+ f = slapi_filter_list_next( flist, f ) ) {
+ f_count++;
+ switch (slapi_filter_get_choice(f)) {
+ case LDAP_FILTER_GE:
+ if ( slapi_filter_get_ava(f, &t1, &low_val) != 0 ) {
+ is_bounded_range = 0;
+ continue;
+ }
+ ge_count++;
+ if (NULL == fpairs[0])
+ {
+ fpairs[0] = f;
+ tpairs[0] = slapi_ch_strdup(t1);
+ vpairs[0] = slapi_ch_bvdup(low_val);
+ }
+ else if (NULL != fpairs[1] &&
+ slapi_attr_type_cmp(tpairs[1], t1, SLAPI_TYPE_CMP_EXACT) != 0)
+ {
+ fpairs[0] = f;
+ slapi_ch_free_string(&tpairs[0]);
+ tpairs[0] = slapi_ch_strdup(t1);
+ slapi_ch_bvfree(&vpairs[0]);
+ vpairs[0] = slapi_ch_bvdup(low_val);
+ }
+ break;
+ case LDAP_FILTER_LE:
+ if ( slapi_filter_get_ava(f, &t1, &high_val) != 0 ) {
+ is_bounded_range = 0;
+ continue;
+ }
+ le_count++;
+ if (NULL == fpairs[1])
+ {
+ fpairs[1] = f;
+ tpairs[1] = slapi_ch_strdup(t1);
+ vpairs[1] = slapi_ch_bvdup(high_val);
+ }
+ else if (NULL != fpairs[0] &&
+ slapi_attr_type_cmp(tpairs[0], t1, SLAPI_TYPE_CMP_EXACT) != 0)
+ {
+ fpairs[1] = f;
+ slapi_ch_free_string(&tpairs[1]);
+ tpairs[1] = slapi_ch_strdup(t1);
+ slapi_ch_bvfree(&vpairs[1]);
+ vpairs[1] = slapi_ch_bvdup(high_val);
+ }
+ break;
+ default:
+ continue;
+ }
+ }
+ if (ftype == LDAP_FILTER_AND && f_count > 1)
+ {
+ is_and = 1;
+ }
+ slapi_pblock_set(pb, SLAPI_SEARCH_IS_AND, &is_and);
+ if (le_count != 1 || ge_count != 1 || f_count != 2)
+ {
+ is_bounded_range = 0;
+ }
+ if (NULL == fpairs[0] || NULL == fpairs[1])
+ {
+ fpairs[0] = fpairs[1] = NULL;
+ slapi_ch_free_string(&tpairs[0]);
+ slapi_ch_bvfree(&vpairs[0]);
+ slapi_ch_free_string(&tpairs[1]);
+ slapi_ch_bvfree(&vpairs[1]);
+ is_bounded_range = 0;
+ }
+ if (is_bounded_range) {
+ idl = range_candidates(pb, be, tpairs[0], vpairs[0], vpairs[1], err);
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= list_candidates %lu\n",
+ (u_long)IDL_NIDS(idl), 0, 0 );
+ goto out;
+ }
+
+ idl = NULL;
+ nextf = NULL;
+ isnot = 0;
+ for ( f_head = f = slapi_filter_list_first( flist ); f != NULL;
+ f = slapi_filter_list_next( flist, f ) ) {
+
+ /* Look for NOT foo type filter elements where foo is simple equality */
+ isnot = (LDAP_FILTER_NOT == slapi_filter_get_choice( f )) &&
+ (LDAP_FILTER_AND == ftype &&
+ (LDAP_FILTER_EQUALITY == slapi_filter_get_choice(slapi_filter_list_first(f))));
+
+ if (isnot) {
+ /* if this is the first filter we have an allid search anyway, so bail */
+ if(f == f_head)
+ {
+ idl = idl_allids( be );
+ break;
+ }
+
+ /* Fetch the IDL for foo */
+ /* Later we'll remember to call idl_notin() */
+ LDAPDebug( LDAP_DEBUG_TRACE,"NOT filter\n", 0, 0, 0 );
+ tmp = ava_candidates( pb, be, slapi_filter_list_first(f), LDAP_FILTER_EQUALITY, nextf, range, err );
+ } else {
+ if (fpairs[0] == f)
+ {
+ continue;
+ }
+ else if (fpairs[1] == f)
+ {
+ tmp = range_candidates(pb, be, tpairs[0],
+ vpairs[0], vpairs[1], err);
+ if (tmp == NULL && ftype == LDAP_FILTER_AND)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= list_candidates NULL\n", 0, 0, 0 );
+ idl_free( idl );
+ idl = NULL;
+ goto out;
+ }
+ }
+ /* Proceed as normal */
+ else if ( (tmp = filter_candidates( pb, be, base, f, nextf, range, err ))
+ == NULL && ftype == LDAP_FILTER_AND ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= list_candidates NULL\n", 0, 0, 0 );
+ idl_free( idl );
+ idl = NULL;
+ goto out;
+ }
+ }
+
+ tmp2 = idl;
+ if ( idl == NULL ) {
+ idl = tmp;
+ if ( (ftype == LDAP_FILTER_AND) && ((idl == NULL) ||
+ (idl_length(idl) <= FILTER_TEST_THRESHOLD)))
+ break; /* We can exit the loop now, since the candidate list is small already */
+ } else if ( ftype == LDAP_FILTER_AND ) {
+ if (isnot) {
+ IDList *new_idl = NULL;
+ int notin_result = 0;
+ notin_result = idl_notin( be, idl, tmp, &new_idl );
+ if (notin_result) {
+ idl_free(idl);
+ idl = new_idl;
+ }
+ } else {
+ idl = idl_intersection(be, idl, tmp);
+ idl_free( tmp2 );
+ }
+ idl_free( tmp );
+ /* stop if the list has gotten too small */
+ if ((idl == NULL) ||
+ (idl_length(idl) <= FILTER_TEST_THRESHOLD))
+ break;
+ } else {
+ idl = idl_union( be, idl, tmp );
+ idl_free( tmp );
+ idl_free( tmp2 );
+ /* stop if we're already committed to an exhaustive
+ * search. :(
+ */
+ if (idl_is_allids(idl))
+ break;
+ }
+
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= list_candidates %lu\n",
+ (u_long)IDL_NIDS(idl), 0, 0 );
+out:
+ is_and = 0;
+ slapi_pblock_set(pb, SLAPI_SEARCH_IS_AND, &is_and);
+ slapi_ch_free_string(&tpairs[0]);
+ slapi_ch_bvfree(&vpairs[0]);
+ slapi_ch_free_string(&tpairs[1]);
+ slapi_ch_bvfree(&vpairs[1]);
+ return( idl );
+}
+
+static IDList *
+substring_candidates(
+ Slapi_PBlock *pb,
+ backend *be,
+ Slapi_Filter *f,
+ int *err
+)
+{
+ char *type, *initial, *final;
+ char **any;
+ IDList *idl;
+ void *pi;
+ Slapi_Value **ivals;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> sub_candidates\n", 0, 0, 0 );
+
+ if (slapi_filter_get_subfilt( f, &type, &initial, &any, &final ) != 0) {
+ LDAPDebug( LDAP_DEBUG_ANY, " slapi_filter_get_subfilt fails\n",
+ 0, 0, 0 );
+ return( NULL );
+ }
+
+ /*
+ * get the index keys corresponding to the substring
+ * assertion values
+ */
+ if ( slapi_attr_type2plugin( type, &pi ) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, " sub_candidates no plugin\n",
+ 0, 0, 0 );
+ return( NULL );
+ }
+ slapi_call_syntax_assertion2keys_sub_sv( pi, initial, any, final, &ivals );
+ if ( ivals == NULL || *ivals == NULL ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= sub_candidates ALLIDS (no keys)\n", 0, 0, 0 );
+ return( idl_allids( be ) );
+ }
+
+ /*
+ * look up each key in the index, ANDing the resulting
+ * IDLists together.
+ */
+ idl = keys2idl( be, type, indextype_SUB, ivals, err );
+ valuearray_free( &ivals );
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= sub_candidates %lu\n",
+ (u_long)IDL_NIDS(idl), 0, 0 );
+ return( idl );
+}
+
+static IDList *
+keys2idl(
+ backend *be,
+ char *type,
+ const char *indextype,
+ Slapi_Value **ivals,
+ int *err
+)
+{
+ IDList *idl;
+ int i;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> keys2idl type %s indextype %s\n",
+ type, indextype, 0 );
+ idl = NULL;
+ for ( i = 0; ivals[i] != NULL; i++ ) {
+ IDList *idl2;
+
+ idl2 = index_read( be, type, indextype, slapi_value_get_berval(ivals[i]), NULL, err );
+
+#ifdef LDAP_DEBUG
+ /* XXX if ( slapd_ldap_debug & LDAP_DEBUG_TRACE ) { XXX */
+ {
+ char buf[BUFSIZ];
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ " ival[%d] = \"%s\" => %lu IDs\n", i,
+ encode( slapi_value_get_berval(ivals[i]), buf ), (u_long)IDL_NIDS(idl2) );
+ }
+#endif
+ if ( idl2 == NULL ) {
+ idl_free( idl );
+ idl = NULL;
+ break;
+ }
+
+ if (idl == NULL) {
+ idl = idl2;
+ } else {
+ IDList *tmp;
+
+ tmp = idl;
+ idl = idl_intersection(be, idl, idl2);
+ idl_free( idl2 );
+ idl_free( tmp );
+ if ( idl == NULL ) {
+ break;
+ }
+ }
+ }
+
+ return( idl );
+}
diff --git a/ldap/servers/slapd/back-ldbm/findentry.c b/ldap/servers/slapd/back-ldbm/findentry.c
new file mode 100644
index 00000000..6565b279
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/findentry.c
@@ -0,0 +1,284 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* findentry.c - find a database entry, obeying referrals (& aliases?) */
+
+#include "back-ldbm.h"
+
+int
+check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, const char *callingfn) /* JCM - Move somewhere more appropriate */
+{
+ int rc=0, i=0, numValues=0;
+ Slapi_Attr *attr;
+
+ /* if the entry is a referral send the referral */
+ if ( slapi_entry_attr_find( entry, "ref", &attr ) == 0 )
+ {
+ Slapi_Value *val=NULL;
+ struct berval **refscopy=NULL;
+ struct berval **url=NULL;
+ slapi_attr_get_numvalues(attr, &numValues );
+ if(numValues > 0) {
+ url=(struct berval **) slapi_ch_malloc((numValues + 1) * sizeof(struct berval*));
+ }
+ for (i = slapi_attr_first_value(attr, &val); i != -1;
+ i = slapi_attr_next_value(attr, i, &val)) {
+ url[i]=(struct berval*)slapi_value_get_berval(val);
+ }
+ url[numValues]=NULL;
+ refscopy = ref_adjust( pb, url, slapi_entry_get_sdn(entry), 0 ); /* JCM - What's this PBlock* for? */
+ slapi_send_ldap_result( pb, LDAP_REFERRAL, matched, NULL, 0, refscopy );
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= %s sent referral to (%s) for (%s)\n",
+ callingfn,
+ refscopy ? refscopy[0]->bv_val : "",
+ slapi_entry_get_dn(entry));
+ if ( refscopy != NULL )
+ {
+ ber_bvecfree( refscopy );
+ }
+ if( url != NULL) {
+ slapi_ch_free( (void **)&url );
+ }
+ rc= 1;
+ }
+ return rc;
+}
+
+static struct backentry *
+find_entry_internal_dn(
+ Slapi_PBlock *pb,
+ backend *be,
+ const Slapi_DN *sdn,
+ int lock,
+ back_txn *txn,
+ int really_internal
+)
+{
+ struct backentry *e;
+ int managedsait = 0;
+ int err;
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ size_t tries = 0;
+
+ /* get the managedsait ldap message control */
+ slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
+
+ while ( (tries < LDBM_CACHE_RETRY_COUNT) &&
+ (e = dn2entry( be, sdn, txn, &err )) != NULL )
+ {
+ /*
+ * we found the entry. if the managedsait control is set,
+ * we return the entry. if managedsait is not set, we check
+ * for the presence of a ref attribute, returning to the
+ * client a referral to the ref'ed entry if a ref is present,
+ * returning the entry to the caller if not.
+ */
+ if ( !managedsait && !really_internal) {
+ /* see if the entry is a referral */
+ if(check_entry_for_referral(pb, e->ep_entry, NULL, "find_entry_internal_dn"))
+ {
+ cache_return( &inst->inst_cache, &e );
+ return( NULL );
+ }
+ }
+
+ /*
+ * we'd like to return the entry. lock it if requested,
+ * retrying if necessary.
+ */
+
+ /* wait for entry modify lock */
+ if ( !lock || cache_lock_entry( &inst->inst_cache, e ) == 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= find_entry_internal_dn found (%s)\n", slapi_sdn_get_dn(sdn), 0, 0 );
+ return( e );
+ }
+ /*
+ * this entry has been deleted - see if it was actually
+ * replaced with a new copy, and try the whole thing again.
+ */
+ LDAPDebug( LDAP_DEBUG_ARGS,
+ " find_entry_internal_dn retrying (%s)\n", slapi_sdn_get_dn(sdn), 0, 0 );
+ cache_return( &inst->inst_cache, &e );
+ tries++;
+ }
+ if (tries >= LDBM_CACHE_RETRY_COUNT) {
+ LDAPDebug( LDAP_DEBUG_ANY,"find_entry_internal_dn retry count exceeded (%s)\n", slapi_sdn_get_dn(sdn), 0, 0 );
+ }
+ /*
+ * there is no such entry in this server. see how far we
+ * can match, and check if that entry contains a referral.
+ * if it does and managedsait is not set, we return the
+ * referral to the client. if it doesn't, or managedsait
+ * is set, we return no such object.
+ */
+ if (!really_internal) {
+ struct backentry *me;
+ Slapi_DN ancestordn= {0};
+ me= dn2ancestor(pb->pb_backend,sdn,&ancestordn,txn,&err);
+ if ( !managedsait && me != NULL ) {
+ /* if the entry is a referral send the referral */
+ if(check_entry_for_referral(pb, me->ep_entry, (char*)slapi_sdn_get_dn(&ancestordn), "find_entry_internal_dn"))
+ {
+ cache_return( &inst->inst_cache, &me );
+ slapi_sdn_done(&ancestordn);
+ return( NULL );
+ }
+ /* else fall through to no such object */
+ }
+
+ /* entry not found */
+ slapi_send_ldap_result( pb, ( 0 == err || DB_NOTFOUND == err ) ?
+ LDAP_NO_SUCH_OBJECT : LDAP_OPERATIONS_ERROR, (char*)slapi_sdn_get_dn(&ancestordn), NULL,
+ 0, NULL );
+ slapi_sdn_done(&ancestordn);
+ cache_return( &inst->inst_cache, &me );
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= find_entry_internal_dn not found (%s)\n",
+ slapi_sdn_get_dn(sdn), 0, 0 );
+ return( NULL );
+}
+
+/* Note that this function does not issue any referals.
+ It should only be called in case of 5.0 replicated operation
+ which should not be referred.
+ */
+static struct backentry *
+find_entry_internal_uniqueid(
+ Slapi_PBlock *pb,
+ backend *be,
+ const char *uniqueid,
+ int lock,
+ back_txn *txn
+)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ struct backentry *e;
+ int err;
+ size_t tries = 0;
+
+ while ( (tries < LDBM_CACHE_RETRY_COUNT) &&
+ (e = uniqueid2entry(be, uniqueid, txn, &err ))
+ != NULL ) {
+
+ /*
+ * we'd like to return the entry. lock it if requested,
+ * retrying if necessary.
+ */
+
+ /* wait for entry modify lock */
+ if ( !lock || cache_lock_entry( &inst->inst_cache, e ) == 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= find_entry_internal_uniqueid found; uniqueid = (%s)\n",
+ uniqueid, 0, 0 );
+ return( e );
+ }
+ /*
+ * this entry has been deleted - see if it was actually
+ * replaced with a new copy, and try the whole thing again.
+ */
+ LDAPDebug( LDAP_DEBUG_ARGS,
+ " find_entry_internal_uniqueid retrying; uniqueid = (%s)\n",
+ uniqueid, 0, 0 );
+ cache_return( &inst->inst_cache, &e );
+ tries++;
+ }
+ if (tries >= LDBM_CACHE_RETRY_COUNT) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "find_entry_internal_uniqueid retry count exceeded; uniqueid = (%s)\n",
+ uniqueid , 0, 0 );
+ }
+
+ /* entry not found */
+ slapi_send_ldap_result( pb, ( 0 == err || DB_NOTFOUND == err ) ?
+ LDAP_NO_SUCH_OBJECT : LDAP_OPERATIONS_ERROR, NULL /* matched */, NULL,
+ 0, NULL );
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= find_entry_internal not found; uniqueid = (%s)\n",
+ uniqueid, 0, 0 );
+ return( NULL );
+}
+
+static struct backentry *
+find_entry_internal(
+ Slapi_PBlock *pb,
+ Slapi_Backend *be,
+ const entry_address *addr,
+ int lock,
+ back_txn *txn,
+ int really_internal
+)
+{
+ /* check if we should search based on uniqueid or dn */
+ if (addr->uniqueid!=NULL)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> find_entry_internal (uniqueid=%s) lock %d\n",
+ addr->uniqueid, lock, 0 );
+ return (find_entry_internal_uniqueid (pb, be, addr->uniqueid, lock, txn));
+ }
+ else
+ {
+ Slapi_DN sdn;
+ struct backentry *entry;
+
+ slapi_sdn_init_dn_ndn_byref (&sdn, addr->dn); /* normalized by front end */
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> find_entry_internal (dn=%s) lock %d\n",
+ addr->dn, lock, 0 );
+ entry = find_entry_internal_dn (pb, be, &sdn, lock, txn, really_internal);
+ slapi_sdn_done (&sdn);
+ return entry;
+ }
+
+}
+
+struct backentry *
+find_entry(
+ Slapi_PBlock *pb,
+ Slapi_Backend *be,
+ const entry_address *addr,
+ back_txn *txn
+)
+{
+ return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, 0/*!really_internal*/ ) );
+}
+
+struct backentry *
+find_entry2modify(
+ Slapi_PBlock *pb,
+ Slapi_Backend *be,
+ const entry_address *addr,
+ back_txn *txn
+)
+{
+ return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 0/*!really_internal*/ ) );
+}
+
+/* New routines which do not do any referral stuff.
+ Call these if all you want to do is get pointer to an entry
+ and certainly do not want any side-effects relating to client ! */
+
+struct backentry *
+find_entry_only(
+ Slapi_PBlock *pb,
+ Slapi_Backend *be,
+ const entry_address *addr,
+ back_txn *txn
+)
+{
+ return( find_entry_internal( pb, be, addr, 0/*!lock*/, txn, 1/*really_internal*/ ) );
+}
+
+struct backentry *
+find_entry2modify_only(
+ Slapi_PBlock *pb,
+ Slapi_Backend *be,
+ const entry_address *addr,
+ back_txn *txn
+)
+{
+ return( find_entry_internal( pb, be, addr, 1/*lock*/, txn, 1/*really_internal*/ ) );
+}
diff --git a/ldap/servers/slapd/back-ldbm/haschildren.c b/ldap/servers/slapd/back-ldbm/haschildren.c
new file mode 100644
index 00000000..6e2fa9d9
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/haschildren.c
@@ -0,0 +1,8 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* haschildren.c - tell if an entry has kids or not */
+
+
diff --git a/ldap/servers/slapd/back-ldbm/id2entry.c b/ldap/servers/slapd/back-ldbm/id2entry.c
new file mode 100644
index 00000000..7c5a00c2
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/id2entry.c
@@ -0,0 +1,250 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* id2entry.c - routines to deal with the id2entry index */
+
+#include "back-ldbm.h"
+
+/*
+ * The caller MUST check for DB_LOCK_DEADLOCK and DB_RUNRECOVERY returned
+ */
+int
+id2entry_add_ext( backend *be, struct backentry *e, back_txn *txn, int encrypt )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ DB *db = NULL;
+ DB_TXN *db_txn = NULL;
+ DBT data = {0};
+ DBT key = {0};
+ int len, rc;
+ char temp_id[sizeof(ID)];
+ struct backentry *encrypted_entry = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry_add( %lu, \"%s\" )\n",
+ (u_long)e->ep_id, backentry_get_ndn(e), 0 );
+
+ if ( (rc = dblayer_get_id2entry( be, &db )) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Could not open/create id2entry\n",
+ 0, 0, 0 );
+ return( -1 );
+ }
+
+ id_internal_to_stored(e->ep_id,temp_id);
+
+ key.dptr = temp_id;
+ key.dsize = sizeof(temp_id);
+
+ /* Encrypt attributes in this entry if necessary */
+ if (encrypt) {
+ rc = attrcrypt_encrypt_entry(be, e, &encrypted_entry);
+ if (rc) {
+ LDAPDebug( LDAP_DEBUG_ANY, "attrcrypt_encrypt_entry failed in id2entry_add\n",
+ 0, 0, 0 );
+ return ( -1 );
+ }
+ }
+
+ {
+ Slapi_Entry *entry_to_use = encrypted_entry ? encrypted_entry->ep_entry : e->ep_entry;
+ data.dptr = slapi_entry2str_with_options( entry_to_use, &len, SLAPI_DUMP_STATEINFO | SLAPI_DUMP_UNIQUEID);
+ data.dsize = len + 1;
+ /* If we had an encrypted entry, we no longer need it */
+ if (encrypted_entry) {
+ backentry_free(&encrypted_entry);
+ }
+ }
+
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ }
+
+ /* call pre-entry-store plugin */
+ plugin_call_entrystore_plugins( (char **) &data.dptr, &data.dsize );
+
+ /* store it */
+ rc = db->put( db, db_txn, &key, &data, 0);
+ /* DBDB looks like we're freeing memory allocated by another DLL, which is bad */
+ free( data.dptr );
+
+ dblayer_release_id2entry( be, db );
+
+ if (0 == rc)
+ {
+ /* DBDB the fact that we don't check the return code here is
+ * indicitive that there may be a latent race condition lurking
+ * ---what happens if the entry is already in the cache by this point?
+ */
+ /*
+ * For ldbm_back_add and ldbm_back_modify, this entry had been already
+ * reserved as a tentative entry. So, it should be safe.
+ * For ldbm_back_modify, the original entry having the same dn/id
+ * should be in the cache. Thus, this entry e won't be put into the
+ * entry cache. It'll be added by cache_replace.
+ */
+ (void) cache_add( &inst->inst_cache, e, NULL );
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry_add %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+int
+id2entry_add( backend *be, struct backentry *e, back_txn *txn )
+{
+ return id2entry_add_ext(be,e,txn,1);
+}
+
+/*
+ * The caller MUST check for DB_LOCK_DEADLOCK and DB_RUNRECOVERY returned
+ */
+int
+id2entry_delete( backend *be, struct backentry *e, back_txn *txn )
+{
+ DB *db = NULL;
+ DB_TXN *db_txn = NULL;
+ DBT key = {0};
+ int rc;
+ char temp_id[sizeof(ID)];
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry_delete( %lu, \"%s\" )\n",
+ (u_long)e->ep_id, backentry_get_ndn(e), 0 );
+
+ if ( (rc = dblayer_get_id2entry( be, &db )) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Could not open/create id2entry\n",
+ 0, 0, 0 );
+ return( -1 );
+ }
+
+ id_internal_to_stored(e->ep_id,temp_id);
+
+ key.dptr = temp_id;
+ key.dsize = sizeof(temp_id);
+
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ }
+
+ rc = db->del( db,db_txn,&key,0 );
+ dblayer_release_id2entry( be, db );
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry_delete %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+struct backentry *
+id2entry( backend *be, ID id, back_txn *txn, int *err )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ DB *db = NULL;
+ DB_TXN *db_txn = NULL;
+ DBT key = {0};
+ DBT data = {0};
+ struct backentry *e;
+ Slapi_Entry *ee;
+ char temp_id[sizeof(ID)];
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> id2entry( %lu )\n", (u_long)id, 0, 0 );
+
+ if ( (e = cache_find_id( &inst->inst_cache, id )) != NULL ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry %p (cache)\n", e, 0,
+ 0 );
+ return( e );
+ }
+
+ if ( (*err = dblayer_get_id2entry( be, &db )) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Could not open id2entry err %d\n",
+ *err, 0, 0 );
+ return( NULL );
+ }
+
+
+ id_internal_to_stored(id,temp_id);
+
+ key.data = temp_id;
+ key.size = sizeof(temp_id);
+
+ /* DBDB need to improve this, we're mallocing, freeing, all over the place here */
+ data.flags = DB_DBT_MALLOC;
+
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ }
+ do {
+ *err = db->get( db, db_txn, &key, &data, 0 );
+ if ( 0 != *err &&
+ DB_NOTFOUND != *err && DB_LOCK_DEADLOCK != *err )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "id2entry error %d\n",
+ *err, 0, 0 );
+ }
+ }
+ while ( DB_LOCK_DEADLOCK == *err && txn == NULL );
+
+ if ( 0 != *err && DB_NOTFOUND != *err && DB_LOCK_DEADLOCK != *err )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "id2entry get error %d\n",
+ *err, 0, 0 );
+ dblayer_release_id2entry( be, db );
+ return( NULL );
+ }
+
+ if ( data.dptr == NULL ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry( %lu ) not found\n",
+ (u_long)id, 0, 0 );
+ dblayer_release_id2entry( be, db );
+ return( NULL );
+ }
+
+ /* call post-entry plugin */
+ plugin_call_entryfetch_plugins( (char **) &data.dptr, &data.dsize );
+
+ if ( (ee = slapi_str2entry( data.dptr, 0 )) != NULL ) {
+ int retval = 0;
+ struct backentry *imposter = NULL;
+
+ PR_ASSERT(slapi_entry_get_uniqueid(ee) != NULL); /* All entries should have uniqueids */
+ e = backentry_init( ee ); /* ownership of the entry is passed into the backentry */
+ e->ep_id = id;
+
+ /* Decrypt any encrypted attributes in this entry, before adding it to the cache */
+ retval = attrcrypt_decrypt_entry(be, e);
+ if (retval) {
+ LDAPDebug( LDAP_DEBUG_ANY, "attrcrypt_decrypt_entry failed in id2entry\n",
+ 0, 0, 0 );
+ }
+
+ retval = cache_add( &inst->inst_cache, e, &imposter );
+ if (1 == retval) {
+ /* This means that someone else put the entry in the cache
+ while we weren't looking ! So, we need to use the pointer
+ returned and free the one we made earlier */
+ if (imposter)
+ {
+ backentry_free(&e);
+ e = imposter;
+ }
+ } else if (-1 == retval) {
+ /* the entry is in idtable but not in dntable, i.e., the entry
+ * could have been renamed */
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "id2entry: failed to put entry (id %lu, dn %s) into entry cache\n",
+ (u_long)id, backentry_get_ndn(e), 0 );
+ }
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY, "str2entry returned NULL for id %lu, string=\"%s\"\n", (u_long)id, (char*)data.data, 0);
+ e = NULL;
+ }
+
+ free( data.data );
+
+ dblayer_release_id2entry( be, db );
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= id2entry( %lu ) %p (disk)\n", (u_long)id, e,
+ 0 );
+ return( e );
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/idl.c b/ldap/servers/slapd/back-ldbm/idl.c
new file mode 100644
index 00000000..df97a979
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/idl.c
@@ -0,0 +1,1599 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* idl.c - ldap id list handling routines */
+
+#include "back-ldbm.h"
+
+/*
+ * Disable idl locking since it causes unbreakable deadlock.
+ */
+#undef IDL_LOCKING_ENABLE
+
+static int idl_delete( IDList **idl, ID id ) ;
+static void make_cont_key( DBT *contkey, DBT *key, ID id );
+static int idl_insert_maxids( IDList **idl, ID id, int maxids );
+
+/* for the cache of open index files */
+struct idl_private {
+ int idl_maxids; /* Number of IDS in a block */
+ int idl_maxindirect; /* Number of blocks allowed */
+ size_t idl_allidslimit; /* Max number of IDs before it turns to allids */
+#ifdef IDL_LOCKING_ENABLE
+ PRRWLock *idl_rwlock;
+#endif
+};
+
+static int idl_tune = DEFAULT_IDL_TUNE; /* tuning parameters for IDL code */
+#define IDL_TUNE_BSEARCH 1 /* do a binary search when inserting into an IDL */
+#define IDL_TUNE_NOPAD 2 /* Don't pad IDLs with space at the end */
+
+void idl_old_set_tune(int val)
+{
+ idl_tune = val;
+}
+
+int idl_old_get_tune() {
+ return idl_tune;
+}
+
+size_t idl_old_get_allidslimit(struct attrinfo *a)
+{
+ idl_private *priv = NULL;
+
+ PR_ASSERT(NULL != a);
+ PR_ASSERT(NULL != a->ai_idl);
+
+ priv = a->ai_idl;
+
+ return priv->idl_allidslimit;
+}
+
+static void idl_init_maxids(struct ldbminfo *li,idl_private *priv)
+{
+ const size_t blksize = dblayer_get_optimal_block_size(li);
+
+ if (0 == li->li_allidsthreshold) {
+ li->li_allidsthreshold = DEFAULT_ALLIDSTHRESHOLD;
+ }
+ priv->idl_maxids = (blksize / sizeof(ID)) - 2;
+ priv->idl_maxindirect = (li->li_allidsthreshold / priv->idl_maxids) + 1;
+ priv->idl_allidslimit = (priv->idl_maxids * priv->idl_maxindirect);
+ LDAPDebug (LDAP_DEBUG_ARGS,
+ "idl_init_private: blksize %lu, maxids %i, maxindirect %i\n",
+ (unsigned long)blksize, priv->idl_maxids, priv->idl_maxindirect);
+}
+
+/* routine to initialize the private data used by the IDL code per-attribute */
+int idl_old_init_private(backend *be,struct attrinfo *a)
+{
+ idl_private *priv = NULL;
+
+ PR_ASSERT(NULL != a);
+ PR_ASSERT(NULL == a->ai_idl);
+
+ priv = (idl_private*) slapi_ch_malloc(sizeof(idl_private));
+ if (NULL == priv) {
+ return -1; /* Memory allocation failure */
+ }
+ {
+ priv->idl_maxids = 0;
+ priv->idl_maxindirect = 0;
+ }
+#ifdef IDL_LOCKING_ENABLE
+ priv->idl_rwlock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "idl lock");
+
+ if (NULL == priv->idl_rwlock) {
+ slapi_ch_free((void**)&priv);
+ return -1;
+ }
+#endif
+ a->ai_idl = (void*)priv;
+ return 0;
+}
+
+/* routine to release resources used by IDL private data structure */
+int idl_old_release_private(struct attrinfo *a)
+{
+ PR_ASSERT(NULL != a);
+ if (NULL != a->ai_idl)
+ {
+#ifdef IDL_LOCKING_ENABLE
+ idl_private *priv = a->ai_idl;
+ PR_ASSERT(NULL != priv->idl_rwlock);
+ PR_DestroyRWLock(priv->idl_rwlock);
+#endif
+ free( a->ai_idl );
+ }
+ return 0;
+}
+
+/* Locks one IDL so we can modify it knowing that
+ * nobody else is trying to do so at the same time
+ * also called by readers, since they need to be blocked
+ * when they read to avoid them seeing inconsistent data
+ * This is not really necessary for update operations
+ * today because they are already serialized by a lock
+ * at the backend level but is still necessary to
+ * stop concurrent access by one update thread and
+ * some other search threads
+ */
+
+#ifdef IDL_LOCKING_ENABLE
+static void idl_Wlock_list(idl_private *priv, DBT *key)
+{
+ PRRWLock *lock = NULL;
+
+ PR_ASSERT(NULL != priv);
+ lock = priv->idl_rwlock;
+ PR_ASSERT(NULL != lock);
+
+ PR_RWLock_Wlock(lock);
+}
+
+static void idl_Rlock_list(idl_private *priv, DBT *key)
+{
+ PRRWLock *lock = NULL;
+
+ PR_ASSERT(NULL != priv);
+ lock = priv->idl_rwlock;
+ PR_ASSERT(NULL != lock);
+
+ PR_RWLock_Rlock(lock);
+}
+
+static void idl_unlock_list(idl_private *priv, DBT *key)
+{
+ PRRWLock *lock = NULL;
+
+ PR_ASSERT(NULL != priv);
+ lock = priv->idl_rwlock;
+ PR_ASSERT(NULL != lock);
+
+ PR_RWLock_Unlock(lock);
+}
+#endif
+
+#ifndef IDL_LOCKING_ENABLE
+#define idl_Wlock_list(idl,dbt)
+#define idl_Rlock_list(idl,dbt)
+#define idl_unlock_list(idl,dbt)
+#endif
+
+/*
+ * idl_fetch_one - fetch a single IDList from the database and return a
+ * pointer to it.
+ *
+ * this routine always propagates errors other than DB_LOCK_DEADLOCK.
+ * for DB_LOCK_DEADLOCK, it propagates the error if called inside a
+ * transaction. if called not inside a transaction, it loops on
+ * DB_LOCK_DEADLOCK, retrying the fetch.
+ *
+ */
+static IDList *
+idl_fetch_one(
+ struct ldbminfo *li,
+ DB *db,
+ DBT *key,
+ DB_TXN *txn,
+ int *err
+)
+{
+ DBT data = {0};
+ IDList *idl = NULL;
+
+ /* LDAPDebug( LDAP_DEBUG_TRACE, "=> idl_fetch_one\n", 0, 0, 0 ); */
+
+ data.flags = DB_DBT_MALLOC;
+
+ do {
+ *err = db->get( db, txn, key, &data, 0 );
+ if ( 0 != *err && DB_NOTFOUND != *err && DB_LOCK_DEADLOCK != *err )
+ {
+ char *msg;
+ if ( EPERM == *err && *err != errno ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "idl_fetch_one(%s): Database failed to run, "
+ "There is either insufficient disk space or "
+ "insufficient memory available for database.\n",
+ ((char*)key->dptr)[ key->dsize - 1 ] ?
+ "" : (char*)key->dptr, 0, 0 );
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "idl_fetch_one error %d %s\n",
+ *err, (msg = dblayer_strerror( *err )) ? msg : "", 0 );
+ }
+ }
+ }
+ while ( DB_LOCK_DEADLOCK == *err && NULL == txn );
+
+ if (0 == *err) {
+ idl = (IDList *) data.data;
+ }
+
+ return( idl );
+}
+
+IDList *
+idl_old_fetch(
+ backend *be,
+ DB *db,
+ DBT *key,
+ DB_TXN *txn,
+ struct attrinfo *a,
+ int *err
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ DBT k2 = {0};
+ IDList *idl;
+ IDList **tmp;
+ back_txn s_txn;
+ char *kstr;
+ int i;
+ unsigned long nids;
+
+ /* LDAPDebug( LDAP_DEBUG_TRACE, "=> idl_fetch\n", 0, 0, 0 ); */
+ if ( (idl = idl_fetch_one( li, db, key, txn, err )) == NULL ) {
+ return( NULL );
+ }
+
+ /* regular block */
+ if ( ! INDIRECT_BLOCK( idl ) ) {
+ /* make sure we have the current value of highest id */
+ if ( ALLIDS(idl) ) {
+ idl_free( idl );
+ idl = idl_allids( be );
+ }
+ return( idl );
+ }
+ idl_free( idl );
+
+ /* Taking a transaction is expensive; so we try and optimize for the common case by not
+ taking one above. If we have a indirect block; we need to take a transaction and re-read
+ the idl since they could have been changed by another thread after we read the first block
+ above */
+
+ dblayer_txn_init(li,&s_txn);
+ if (NULL != txn)
+ {
+ dblayer_read_txn_begin(li,txn,&s_txn);
+ }
+ if ( (idl = idl_fetch_one( li, db, key, s_txn.back_txn_txn, err )) == NULL ) {
+ dblayer_read_txn_commit(li,&s_txn);
+ return( NULL );
+ }
+
+ /* regular block */
+ if ( ! INDIRECT_BLOCK( idl ) ) {
+ dblayer_read_txn_commit(li,&s_txn);
+ /* make sure we have the current value of highest id */
+ if ( ALLIDS(idl) ) {
+ idl_free( idl );
+ idl = idl_allids( be );
+ }
+ return( idl );
+ }
+ /*
+ * this is an indirect block which points to other blocks.
+ * we need to read in all the blocks it points to and construct
+ * a big id list containing all the ids, which we will return.
+ */
+
+ /* count the number of blocks & allocate space for pointers to them */
+ for ( i = 0; idl->b_ids[i] != NOID; i++ )
+ ; /* NULL */
+ tmp = (IDList **) slapi_ch_malloc( (i + 1) * sizeof(IDList *) );
+
+ /* read in all the blocks */
+ kstr = (char *) slapi_ch_malloc( key->dsize + 20 );
+ nids = 0;
+ for ( i = 0; idl->b_ids[i] != NOID; i++ ) {
+ ID thisID = idl->b_ids[i];
+ ID nextID = idl->b_ids[i+1];
+
+ sprintf( kstr, "%c%s%lu", CONT_PREFIX, (char *)key->dptr, (u_long)thisID );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+
+ if ( (tmp[i] = idl_fetch_one( li, db, &k2, s_txn.back_txn_txn, err )) == NULL ) {
+ if(*err == DB_LOCK_DEADLOCK) {
+ dblayer_read_txn_abort(li,&s_txn);
+ } else {
+ dblayer_read_txn_commit(li,&s_txn);
+ }
+ slapi_ch_free((void**)&kstr );
+ slapi_ch_free((void**)&tmp );
+ return( NULL );
+ }
+
+ nids += tmp[i]->b_nids;
+
+ /* Check for inconsistencies: */
+ if ( tmp[i]->b_ids[0] != thisID ) {
+ LDAPDebug (LDAP_DEBUG_ANY, "idl_fetch_one(%s)->b_ids[0] == %lu\n",
+ k2.dptr, (u_long)tmp[i]->b_ids[0], 0);
+ }
+ if ( nextID != NOID ) {
+ if ( nextID <= thisID ) {
+ LDAPDebug (LDAP_DEBUG_ANY, "indirect block (%s) contains %lu, %lu\n",
+ key->dptr, (u_long)thisID, (u_long)nextID);
+ }
+ if ( nextID <= tmp[i]->b_ids[(tmp[i]->b_nids)-1] ) {
+ LDAPDebug (LDAP_DEBUG_ANY, "idl_fetch_one(%s)->b_ids[last] == %lu"
+ " >= %lu (next indirect ID)\n",
+ k2.dptr, (u_long)tmp[i]->b_ids[(tmp[i]->b_nids)-1], (u_long)nextID);
+ }
+ }
+ }
+ dblayer_read_txn_commit(li,&s_txn);
+ tmp[i] = NULL;
+ slapi_ch_free((void**)&kstr );
+ idl_free( idl );
+
+ /* allocate space for the big block */
+ idl = idl_alloc( nids );
+ idl->b_nids = nids;
+ nids = 0;
+
+ /* copy in all the ids from the component blocks */
+ for ( i = 0; tmp[i] != NULL; i++ ) {
+ if ( tmp[i] == NULL ) {
+ continue;
+ }
+
+ SAFEMEMCPY( (char *) &idl->b_ids[nids], (char *) tmp[i]->b_ids,
+ tmp[i]->b_nids * sizeof(ID) );
+ nids += tmp[i]->b_nids;
+
+ idl_free( tmp[i] );
+ }
+ slapi_ch_free((void**)&tmp );
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= idl_fetch %lu ids (%lu max)\n", (u_long)idl->b_nids,
+ (u_long)idl->b_nmax, 0 );
+ return( idl );
+}
+
+static int
+idl_store(
+ backend *be,
+ DB *db,
+ DBT *key,
+ IDList *idl,
+ DB_TXN *txn
+)
+{
+ int rc;
+ DBT data = {0};
+
+ /* LDAPDebug( LDAP_DEBUG_TRACE, "=> idl_store\n", 0, 0, 0 ); */
+
+ data.dptr = (char *) idl;
+ data.dsize = (2 + idl->b_nmax) * sizeof(ID);
+
+ rc = db->put( db, txn, key, &data, 0 );
+ if ( 0 != rc ) {
+ char *msg;
+ if ( EPERM == rc && rc != errno ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "idl_store(%s): Database failed to run, "
+ "There is insufficient memory available for database.\n",
+ ((char*)key->dptr)[ key->dsize - 1 ] ? "" : (char*)key->dptr, 0, 0 );
+ } else {
+ if (LDBM_OS_ERR_IS_DISKFULL(rc)) {
+ operation_out_of_disk_space();
+ }
+ LDAPDebug( ((DB_LOCK_DEADLOCK == rc) ? LDAP_DEBUG_TRACE : LDAP_DEBUG_ANY),
+ "idl_store(%s) returns %d %s\n",
+ ((char*)key->dptr)[ key->dsize - 1 ] ? "" : (char*)key->dptr,
+ rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ if (rc == DB_RUNRECOVERY) {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s\n", "Note: idl_store failures can be an indication of insufficient disk space.", 0, 0);
+ ldbm_nasty("idl_store",71,rc);
+ }
+ }
+ }
+
+ /* LDAPDebug( LDAP_DEBUG_TRACE, "<= idl_store %d\n", rc, 0, 0 ); */
+ return( rc );
+}
+
+static void
+idl_split_block(
+ IDList *b,
+ ID id,
+ IDList **n1,
+ IDList **n2
+)
+{
+ ID i;
+
+ /* find where to split the block */
+ for ( i = 0; i < b->b_nids && id > b->b_ids[i]; i++ )
+ ; /* NULL */
+
+ *n1 = idl_alloc( i == 0 ? 1 : i );
+ *n2 = idl_alloc( b->b_nids - i + (i == 0 ? 0 : 1));
+
+ /*
+ * everything before the id being inserted in the first block
+ * unless there is nothing, in which case the id being inserted
+ * goes there.
+ */
+ SAFEMEMCPY( (char *) &(*n1)->b_ids[0], (char *) &b->b_ids[0],
+ i * sizeof(ID) );
+ (*n1)->b_nids = (i == 0 ? 1 : i);
+
+ if ( i == 0 ) {
+ (*n1)->b_ids[0] = id;
+ } else {
+ (*n2)->b_ids[0] = id;
+ }
+
+ /* the id being inserted & everything after in the second block */
+ SAFEMEMCPY( (char *) &(*n2)->b_ids[i == 0 ? 0 : 1],
+ (char *) &b->b_ids[i], (b->b_nids - i) * sizeof(ID) );
+ (*n2)->b_nids = b->b_nids - i + (i == 0 ? 0 : 1);
+}
+
+/*
+ * idl_change_first - called when an indirect block's first key has
+ * changed, meaning it needs to be stored under a new key, and the
+ * header block pointing to it needs updating.
+ */
+
+static int
+idl_change_first(
+ backend *be,
+ DB *db,
+ DBT *hkey, /* header block key */
+ IDList *h, /* header block */
+ int pos, /* pos in h to update */
+ DBT *bkey, /* data block key */
+ IDList *b, /* data block */
+ DB_TXN *txn
+)
+{
+ int rc;
+ char *msg;
+
+ /* LDAPDebug( LDAP_DEBUG_TRACE, "=> idl_change_first\n", 0, 0, 0 ); */
+
+ /* delete old key block */
+ rc = db->del( db, txn, bkey, 0 );
+ if ( (rc != 0) && (DB_LOCK_DEADLOCK != rc) )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_change_first del (%s) err %d %s\n",
+ bkey->dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ if (rc == DB_RUNRECOVERY) {
+ ldbm_nasty("idl_store",72,rc);
+ }
+ return( rc );
+ }
+
+ /* write block with new key */
+ sprintf( bkey->dptr, "%c%s%lu", CONT_PREFIX, (char *)hkey->dptr, (u_long)b->b_ids[0] );
+ bkey->dsize = strlen( bkey->dptr ) + 1;
+ if ( (rc = idl_store( be, db, bkey, b, txn )) != 0 ) {
+ return( rc );
+ }
+
+ /* update + write indirect header block */
+ h->b_ids[pos] = b->b_ids[0];
+ if ( (rc = idl_store( be, db, hkey, h, txn )) != 0 ) {
+ return( rc );
+ }
+
+ return( 0 );
+}
+
+
+#define IDL_CHECK_FAILED(FORMAT, ARG1, ARG2) \
+do { \
+ char* fmt = slapi_ch_malloc (strlen(func) + strlen(note) + strlen(FORMAT) + 30); \
+ if (fmt != NULL) { \
+ sprintf (fmt, "%s(%%s,%lu) %s: %s\n", func, (u_long)id, note, FORMAT); \
+ LDAPDebug (LDAP_DEBUG_ANY, fmt, key->dptr, ARG1, ARG2); \
+ slapi_ch_free((void**)&fmt); \
+ } \
+} while(0)
+
+
+static void
+idl_check_indirect (IDList* idl, int i, IDList* tmp, IDList* tmp2,
+ char* func, char* note, DBT* key, ID id)
+ /* Check for inconsistencies; report any via LDAPDebug(LDAP_DEBUG_ANY).
+ The caller alleges that *idl is a header block, in which the
+ i'th item points to the indirect block *tmp, and either tmp2 == NULL
+ or *tmp2 is the indirect block to which the i+1'th item in *idl points.
+ The other parameters are merely output in each error message, like:
+ printf ("%s(%s,%lu) %s: ...", func, key->dptr, (u_long)id, note, ...)
+ */
+{
+ /* The implementation is optimized for no inconsistencies. */
+ const ID thisID = idl->b_ids[i];
+ const ID nextID = idl->b_ids[i+1];
+ const ID tmp0 = tmp->b_ids[0];
+ const ID tmpLast = tmp->b_ids[tmp->b_nids-1];
+
+ if (tmp0 != thisID) {
+ IDL_CHECK_FAILED ("tmp->b_ids[0] == %lu, not %lu\n",
+ (u_long)tmp0, (u_long)thisID);
+ }
+ if (tmp0 > tmpLast) {
+ IDL_CHECK_FAILED ("tmp->b_ids[0] == %lu > %lu [last]\n",
+ (u_long)tmp0, (u_long)tmpLast);
+ }
+ if (nextID == NOID) {
+ if (tmp2 != NULL) {
+ IDL_CHECK_FAILED ("idl->b_ids[%i+1] == NOID, but tmp2 != NULL\n", i, 0);
+ }
+ } else {
+ if (nextID <= thisID) {
+ IDL_CHECK_FAILED ("idl->b_ids contains %lu, %lu\n", (u_long)thisID, (u_long)nextID);
+ }
+ if (nextID <= tmpLast) {
+ IDL_CHECK_FAILED ("idl->b_ids[i+1] == %lu <= %lu (last of idl->b_ids[i])\n",
+ (u_long)nextID, (u_long)tmpLast);
+ }
+ if (tmp2 != NULL && tmp2->b_ids[0] != nextID) {
+ IDL_CHECK_FAILED ("tmp2->b_ids[0] == %lu, not %lu\n",
+ (u_long)tmp2->b_ids[0], (u_long)nextID);
+ }
+ }
+}
+
+
+int
+idl_old_insert_key(
+ backend *be,
+ DB *db,
+ DBT *key,
+ ID id,
+ DB_TXN *txn,
+ struct attrinfo *a,
+ int *disposition
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ int i, j, rc = 0;
+ char *msg;
+ IDList *idl, *tmp, *tmp2, *tmp3;
+ char *kstr;
+ DBT k2 = {0};
+ DBT k3 = {0};
+
+ if (NULL != disposition) {
+ *disposition = IDL_INSERT_NORMAL;
+ }
+
+ if (0 == a->ai_idl->idl_maxids) {
+ idl_init_maxids(li,a->ai_idl);
+ }
+
+ idl_Wlock_list(a->ai_idl,key);
+ if ( (idl = idl_fetch_one( li, db, key, txn, &rc )) == NULL ) {
+ if ( rc != 0 && rc != DB_NOTFOUND ) {
+ if ( rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_insert_key 0 BAD %d %s\n",
+ rc, (msg = dblayer_strerror( rc )) ? msg : "", 0 );
+ }
+ return( rc );
+ }
+ idl = idl_alloc( 1 );
+ idl->b_ids[idl->b_nids++] = id;
+ rc = idl_store( be, db, key, idl, txn );
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_insert_key 1 BAD %d %s\n",
+ rc, (msg = dblayer_strerror( rc )) ? msg : "", 0 );
+ }
+
+ idl_free( idl );
+ idl_unlock_list(a->ai_idl,key);
+ return( rc );
+ }
+
+ /* regular block */
+ if ( ! INDIRECT_BLOCK( idl ) ) {
+ switch ( idl_insert_maxids( &idl, id, a->ai_idl->idl_maxids ) ) {
+ case 0: /* id inserted - store the updated block */
+ case 1:
+ rc = idl_store( be, db, key, idl, txn );
+ break;
+
+ case 2: /* id already there - nothing to do */
+ rc = 0;
+ /* Could be an ALLID block, let's check */
+ if (ALLIDS(idl)) {
+ if (NULL != disposition) {
+ *disposition = IDL_INSERT_ALLIDS;
+ }
+ }
+ break;
+
+ case 3: /* id not inserted - block must be split */
+ /* check threshold for marking this an all-id block */
+ if ( a->ai_idl->idl_maxindirect < 2 ) {
+ idl_free( idl );
+ idl = idl_allids( be );
+ rc = idl_store( be, db, key, idl, txn );
+ idl_free( idl );
+
+ idl_unlock_list(a->ai_idl,key);
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_insert_key 2 BAD %d %s\n",
+ rc, (msg = dblayer_strerror( rc )) ? msg : "", 0 );
+ }
+ if (NULL != disposition) {
+ *disposition = IDL_INSERT_NOW_ALLIDS;
+ }
+ return( rc );
+ }
+
+ idl_split_block( idl, id, &tmp, &tmp2 );
+ idl_free( idl );
+
+ /* create the header indirect block */
+ idl = idl_alloc( 3 );
+ idl->b_nmax = 3;
+ idl->b_nids = INDBLOCK;
+ idl->b_ids[0] = tmp->b_ids[0];
+ idl->b_ids[1] = tmp2->b_ids[0];
+ idl->b_ids[2] = NOID;
+
+ /* store it */
+ rc = idl_store( be, db, key, idl, txn );
+ if ( rc != 0 ) {
+ idl_free( idl );
+ idl_free( tmp );
+ idl_free( tmp2 );
+ if ( rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_insert_key 3 BAD %d %s\n",
+ rc, (msg = dblayer_strerror( rc )) ? msg : "", 0 );
+ }
+ return( rc );
+ }
+
+ /* store the first id block */
+ kstr = (char *) slapi_ch_malloc( key->dsize + 20 );
+ sprintf( kstr, "%c%s%lu", CONT_PREFIX, (char *)key->dptr,
+ (u_long)tmp->b_ids[0] );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ rc = idl_store( be, db, &k2, tmp, txn );
+
+ /* store the second id block */
+ sprintf( kstr, "%c%s%lu", CONT_PREFIX, (char *)key->dptr,
+ (u_long)tmp2->b_ids[0] );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ rc = idl_store( be, db, &k2, tmp2, txn );
+ if ( rc != 0 ) {
+ idl_free( idl );
+ idl_free( tmp );
+ idl_free( tmp2 );
+ if ( rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_insert_key 4 BAD %d %s\n",
+ rc, (msg = dblayer_strerror( rc )) ? msg : "", 0 );
+ }
+ return( rc );
+ }
+ idl_check_indirect (idl, 0, tmp, tmp2,
+ "idl_insert_key", "split", key, id);
+
+ slapi_ch_free((void**)&kstr );
+ idl_free( tmp );
+ idl_free( tmp2 );
+ break;
+ }
+
+ idl_free( idl );
+ idl_unlock_list(a->ai_idl,key);
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_insert_key 5 BAD %d %s\n",
+ rc, (msg = dblayer_strerror( rc )) ? msg : "", 0 );
+ }
+ return( rc );
+ }
+
+ /*
+ * this is an indirect block which points to other blocks.
+ * we need to read in the block into which the id should be
+ * inserted, then insert the id and store the block. we might
+ * have to split the block if it is full, which means we also
+ * need to write a new "header" block.
+ */
+
+ /* select the block to try inserting into */
+ for ( i = 0; idl->b_ids[i] != NOID && id > idl->b_ids[i]; i++ )
+ ; /* NULL */
+ if ( id == idl->b_ids[i] ) { /* already in a block */
+#ifdef _DEBUG_LARGE_BLOCKS
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "id %lu for key (%s) is already in block %d\n",
+ (u_long)id, key.dptr, i);
+#endif
+ idl_unlock_list(a->ai_idl,key);
+ idl_free( idl );
+ return( 0 );
+ }
+ if ( i != 0 ) {
+ i--;
+ }
+
+ /* get the block */
+ kstr = (char *) slapi_ch_malloc( key->dsize + 20 );
+ sprintf( kstr, "%c%s%lu", CONT_PREFIX, (char *)key->dptr, (u_long)idl->b_ids[i] );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ if ( (tmp = idl_fetch_one( li, db, &k2, txn, &rc )) == NULL ) {
+ if ( rc != 0 ) {
+ if ( rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_insert_key 5.5 BAD %d %s\n",
+ rc, (msg = dblayer_strerror( rc )) ? msg : "", 0 );
+ }
+ return( rc );
+ }
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "nonexistent continuation block (%s)\n", k2.dptr, 0, 0 );
+ idl_unlock_list(a->ai_idl,key);
+ idl_free( idl );
+ slapi_ch_free((void**)&kstr );
+ return( -1 );
+ }
+
+ /* insert the id */
+ switch ( idl_insert_maxids( &tmp, id, a->ai_idl->idl_maxids ) ) {
+ case 0: /* id inserted ok */
+ rc = idl_store( be, db, &k2, tmp, txn );
+ if (0 != rc) {
+ idl_check_indirect (idl, i, tmp, NULL,
+ "idl_insert_key", "indirect", key, id);
+ }
+ break;
+
+ case 1: /* id inserted - first id in block has changed */
+ /*
+ * key for this block has changed, so we have to
+ * write the block under the new key, delete the
+ * old key block + update and write the indirect
+ * header block.
+ */
+
+ rc = idl_change_first( be, db, key, idl, i, &k2, tmp, txn );
+ if ( rc != 0 ) {
+ break; /* return error in rc */
+ }
+ idl_check_indirect (idl, i, tmp, NULL,
+ "idl_insert_key", "indirect 1", key, id);
+ break;
+
+ case 2: /* id not inserted - already there */
+ idl_check_indirect (idl, i, tmp, NULL,
+ "idl_insert_key", "indirect no change", key, id);
+ break;
+
+ case 3: /* id not inserted - block is full */
+ /*
+ * first, see if we can shift ids down one, moving
+ * the last id in the current block to the next
+ * block, and then adding the id we are inserting to
+ * the current block. we'll need to split the block
+ * otherwise.
+ */
+
+ /* is there a next block? */
+ if ( idl->b_ids[i + 1] != NOID ) {
+ char *kstr3 = (char *) slapi_ch_malloc( key->dsize + 20 );
+ /* yes - read it in */
+ sprintf( kstr3, "%c%s%lu", CONT_PREFIX, (char *)key->dptr,
+ (u_long)idl->b_ids[i + 1] );
+ k3.dptr = kstr3;
+ k3.dsize = strlen( kstr3 ) + 1;
+ if ( (tmp2 = idl_fetch_one( li, db, &k3, txn, &rc ))
+ == NULL ) {
+ if ( rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "idl_fetch_one (%s) returns NULL\n",
+ k3.dptr, 0, 0 );
+ }
+ if (0 != rc) {
+ idl_check_indirect (idl, i, tmp, NULL,
+ "idl_insert_key", "indirect missing", key, id);
+ }
+ break;
+ }
+
+ /*
+ * insert the last key in the previous block in
+ * the next block. it should go at the beginning
+ * always, if it fits at all.
+ */
+ rc = idl_insert_maxids (&tmp2,
+ id > tmp->b_ids[tmp->b_nids-1] ?
+ id : tmp->b_ids[tmp->b_nids-1],
+ a->ai_idl->idl_maxids);
+ switch ( rc ) {
+ case 1: /* id inserted first in block */
+ rc = idl_change_first( be, db, key, idl,
+ i + 1, &k3, tmp2, txn );
+ if ( rc != 0 ) {
+ break; /* return error in rc */
+ }
+
+ if (id < tmp->b_ids[tmp->b_nids-1]) {
+ /*
+ * we inserted the last id in the previous
+ * block in this block. we need to "remove"
+ * it from the previous block and insert the
+ * new id. decrementing the b_nids count
+ * in the previous block has the effect
+ * of removing the last id.
+ */
+
+ /* remove last id in previous block */
+ tmp->b_nids--;
+
+ /* insert new id in previous block */
+ switch ( (rc = idl_insert_maxids( &tmp, id,
+ a->ai_idl->idl_maxids )) ) {
+ case 0: /* id inserted */
+ rc = idl_store( be, db, &k2, tmp, txn );
+ break;
+ case 1: /* first in block */
+ rc = idl_change_first( be, db, key, idl,
+ i, &k2, tmp, txn );
+ break;
+ case 2: /* already there - how? */
+ case 3: /* split block - how? */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "not expecting (%d) from idl_insert_maxids of %lu in (%s)\n",
+ rc, (u_long)id, k2.dptr );
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "likely database corruption\n",
+ 0, 0, 0 );
+ rc = 0;
+ break;
+ }
+ }
+ if ( rc != 0 ) {
+ break; /* return error in rc */
+ }
+ idl_check_indirect (idl, i, tmp, tmp2,
+ "idl_insert_key", "overflow", key, id);
+
+ if ( k2.dptr != NULL ) {
+ free( k2.dptr );
+ }
+ if ( k3.dptr != NULL ) {
+ free( k3.dptr );
+ }
+ idl_free( tmp );
+ idl_free( tmp2 );
+ idl_free( idl );
+ idl_unlock_list(a->ai_idl,key);
+ return( rc );
+
+ case 0: /* id inserted not at start - how? */
+ case 2: /* id already there - how? */
+ /*
+ * if either of these cases happen, this
+ * index entry must have been corrupt when
+ * we started this insert. what can we do
+ * aside from log a warning?
+ */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "not expecting return %d from idl_insert_maxids of id %lu in block with key (%s)\n",
+ rc, (u_long)tmp->b_ids[tmp->b_nids-1], k3.dptr );
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "likely database corruption\n", 0, 0, 0 );
+ /* FALL */
+ case 3: /* block is full */
+ /*
+ * if this case happens, we fall back to
+ * splitting the original block.
+ * This is not an error condition. So set
+ * rc = 0 to continue. Otherwise, it will break
+ * from the case statement and return rc=3,
+ * which is not correct.
+ */
+ rc = 0;
+ idl_free( tmp2 );
+ break;
+ }
+ if ( rc != 0 ) {
+ break; /* return error in rc */
+ }
+ }
+
+ /*
+ * must split the block, write both new blocks + update
+ * and write the indirect header block.
+ */
+
+ /* count how many indirect blocks */
+ for ( j = 0; idl->b_ids[j] != NOID; j++ )
+ ; /* NULL */
+
+ /* check it against all-id thresholed */
+ if ( j + 1 > a->ai_idl->idl_maxindirect ) {
+ /*
+ * we've passed the all-id threshold, meaning
+ * that this set of blocks should be replaced
+ * by a single "all-id" block. our job: delete
+ * all the indirect blocks, and replace the header
+ * block by an all-id block.
+ */
+
+ /* delete all indirect blocks */
+ for ( j = 0; idl->b_ids[j] != NOID; j++ ) {
+ sprintf( kstr, "%c%s%lu", CONT_PREFIX, (char *)key->dptr,
+ (u_long)idl->b_ids[j] );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+
+ rc = db->del( db, txn, &k2, 0 );
+ if ( rc != 0 ) {
+ if (rc == DB_RUNRECOVERY) {
+ ldbm_nasty("",73,rc);
+ }
+ break;
+ }
+ }
+
+ /* store allid block in place of header block */
+ if ( 0 == rc ) {
+ idl_free( idl );
+ idl = idl_allids( be );
+ rc = idl_store( be, db, key, idl, txn );
+ if (NULL != disposition) {
+ *disposition = IDL_INSERT_NOW_ALLIDS;
+ }
+ }
+
+ if ( k2.dptr != NULL ) {
+ free( k2.dptr );
+ }
+ if ( k3.dptr != NULL ) {
+ free( k3.dptr );
+ }
+ idl_free( idl );
+ idl_free( tmp );
+ idl_unlock_list(a->ai_idl,key);
+ return( rc );
+ }
+
+ idl_split_block( tmp, id, &tmp2, &tmp3 );
+ idl_free( tmp );
+
+ /* create a new updated indirect header block */
+ tmp = idl_alloc( idl->b_nmax + 1 );
+ tmp->b_nids = INDBLOCK;
+ /* everything up to the split block */
+ SAFEMEMCPY( (char *) tmp->b_ids, (char *) idl->b_ids,
+ i * sizeof(ID) );
+ /* the two new blocks */
+ tmp->b_ids[i] = tmp2->b_ids[0];
+ tmp->b_ids[i + 1] = tmp3->b_ids[0];
+ /* everything after the split block */
+ SAFEMEMCPY( (char *) &tmp->b_ids[i + 2], (char *)
+ &idl->b_ids[i + 1], (idl->b_nmax - i - 1) * sizeof(ID) );
+
+ /* store the header block */
+ rc = idl_store( be, db, key, tmp, txn );
+ if ( rc != 0 ) {
+ idl_free( tmp2 );
+ idl_free( tmp3 );
+ break;
+ }
+
+ /* store the first id block */
+ sprintf( kstr, "%c%s%lu", CONT_PREFIX, (char *)key->dptr,
+ (u_long)tmp2->b_ids[0] );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ rc = idl_store( be, db, &k2, tmp2, txn );
+ if ( rc != 0 ) {
+ idl_free( tmp2 );
+ idl_free( tmp3 );
+ break;
+ }
+
+ /* store the second id block */
+ sprintf( kstr, "%c%s%lu", CONT_PREFIX, (char *)key->dptr,
+ (u_long)tmp3->b_ids[0] );
+ k2.dptr = kstr;
+ k2.dsize = strlen( kstr ) + 1;
+ rc = idl_store( be, db, &k2, tmp3, txn );
+ if ( rc != 0 ) {
+ idl_free( tmp2 );
+ idl_free( tmp3 );
+ break;
+ }
+
+ idl_check_indirect (tmp, i, tmp2, tmp3,
+ "idl_insert_key", "indirect split", key, id);
+ idl_free( tmp2 );
+ idl_free( tmp3 );
+ break;
+ }
+
+ if ( k2.dptr != NULL ) {
+ free( k2.dptr );
+ }
+ if ( k3.dptr != NULL ) {
+ free( k3.dptr );
+ }
+ idl_free( tmp );
+ idl_free( idl );
+ idl_unlock_list(a->ai_idl,key);
+ return( rc );
+}
+
+
+/* Store a complete IDL all in one go, there must not be an existing key with the same value */
+/* Routine used by merging import code */
+int idl_old_store_block(
+ backend *be,
+ DB *db,
+ DBT *key,
+ IDList *idl,
+ DB_TXN *txn,
+ struct attrinfo *a
+ )
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ int ret = 0;
+ idl_private *priv = a->ai_idl;
+
+ if (0 == a->ai_idl->idl_maxids) {
+ idl_init_maxids(li,a->ai_idl);
+ }
+
+ /* First, is it an ALLIDS block ? */
+ if (ALLIDS(idl)) {
+ /* If so, we can store it as-is */
+ ret = idl_store(be,db,key,idl,txn);
+ } else {
+ /* Next, is it a block with so many IDs in it that it _should_ be an ALLIDS block ? */
+ if (idl->b_nids > (ID)li->li_allidsthreshold) {
+ /* If so, store an ALLIDS block */
+ IDList *all = idl_allids(be);
+ ret = idl_store(be,db,key,all,txn);
+ idl_free(all);
+ } else {
+ /* Then , is it a block which is smaller than the size at which it needs splitting ? */
+ if (idl->b_nids <= (ID)priv->idl_maxids) {
+ /* If so, store as-is */
+ ret = idl_store(be,db,key,idl,txn);
+ } else {
+ size_t number_of_ids = 0;
+ size_t max_ids_in_block = 0;
+ size_t number_of_cont_blks = 0;
+ size_t i = 0;
+ size_t number_of_ids_left = 0;
+ IDList *master_block = NULL;
+ size_t index = 0;
+ DBT cont_key = {0};
+
+ number_of_ids = idl->b_nids;
+ max_ids_in_block = priv->idl_maxids;
+ number_of_cont_blks = number_of_ids / max_ids_in_block;
+ if (0 != number_of_ids % max_ids_in_block) {
+ number_of_cont_blks++;
+ }
+ number_of_ids_left = number_of_ids;
+ /* Block needs splitting into continuation blocks */
+ /* We need to make up a master block and n continuation blocks */
+ /* Alloc master block */
+ master_block = idl_alloc(number_of_cont_blks + 1);
+ if (NULL == master_block) {
+ return -1;
+ }
+ master_block->b_nids = INDBLOCK;
+ master_block->b_ids[number_of_cont_blks] = NOID;
+ /* Iterate over ids making the continuation blocks */
+ for (i = 0 ; i < number_of_cont_blks; i++) {
+ IDList *this_cont_block = NULL;
+ size_t size_of_this_block = 0;
+ ID lead_id = NOID;
+ size_t j = 0;
+
+ lead_id = idl->b_ids[index];
+ if (number_of_ids_left >= max_ids_in_block) {
+ size_of_this_block = max_ids_in_block;
+ } else {
+ size_of_this_block = number_of_ids_left;
+ }
+ this_cont_block = idl_alloc(size_of_this_block);
+ if (NULL == this_cont_block) {
+ return -1;
+ }
+ this_cont_block->b_nids = size_of_this_block;
+ /* Copy over the ids to the cont block we're making */
+ for (j = 0; j < size_of_this_block; j++) {
+ this_cont_block->b_ids[j] = idl->b_ids[index + j];
+ }
+ /* Make the continuation key */
+ make_cont_key(&cont_key,key,lead_id);
+ /* Now store the continuation block */
+ ret = idl_store(be,db,&cont_key,this_cont_block,txn);
+ idl_free(this_cont_block);
+ free(cont_key.data);
+ if ( ret != 0 && ret != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_store_block(%s) 1 BAD %d %s\n",key->data, ret, dblayer_strerror( ret ));
+ return ret;
+ }
+ /* Put the lead ID number in the header block */
+ master_block->b_ids[i] = lead_id;
+
+ /* Make our loop invariants correct */
+ number_of_ids_left -= size_of_this_block;
+ index += size_of_this_block;
+ }
+ PR_ASSERT(0 == number_of_ids_left);
+ /* Now store the master block */
+ ret = idl_store(be,db,key,master_block,txn);
+ /* And free it */
+ idl_free(master_block);
+ }
+ }
+ }
+ return ret;
+}
+
+/*
+ * idl_insert - insert an id into an id list.
+ */
+void idl_insert(IDList **idl, ID id)
+{
+ ID i, j;
+ NIDS nids;
+
+ if ((*idl) == NULL) {
+ (*idl) = idl_alloc(1);
+ idl_append((*idl), id);
+ return;
+ }
+
+ if (ALLIDS(*idl)) {
+ return;
+ }
+
+ i = nids = (*idl)->b_nids;
+
+ if (nids > 0) {
+ /* optimize for a simple append */
+ if (id == (*idl)->b_ids[nids-1]) {
+ return;
+ } else if (id > (*idl)->b_ids[nids-1]) {
+ if (nids < (*idl)->b_nmax) {
+ (*idl)->b_ids[nids] = id;
+ (*idl)->b_nids++;
+ return;
+ }
+
+ i = nids;
+
+ } else if (id < (*idl)->b_ids[0]) {
+ /* prepend */
+ i = 0;
+ } else {
+ int lo = 0;
+ int hi = (*idl)->b_nids - 1;
+ int mid = 0;
+ ID *ids = (*idl)->b_ids;
+
+ if (0 != (*idl)->b_nids) {
+ while (lo <= hi) {
+ mid = (hi + lo) >> 1;
+ if (ids[mid] > id) {
+ hi = mid - 1;
+ } else {
+ if (ids[mid] < id) {
+ lo = mid + 1;
+ } else {
+ /* Found it ! */
+ return;
+ }
+ }
+ }
+ }
+ i = lo;
+ }
+ }
+
+ /* do we need to make room for it? */
+ if ( (*idl)->b_nids == (*idl)->b_nmax ) {
+ (*idl)->b_nmax *= 2;
+
+ (*idl) = (IDList *) slapi_ch_realloc( (char *) (*idl),
+ ((*idl)->b_nmax + 2) * sizeof(ID) );
+ }
+
+ /* make a slot for the new id */
+ for ( j = (*idl)->b_nids; j != i; j-- ) {
+ (*idl)->b_ids[j] = (*idl)->b_ids[j-1];
+ }
+
+ (*idl)->b_ids[i] = id;
+ (*idl)->b_nids++;
+
+ memset( (char *) &(*idl)->b_ids[(*idl)->b_nids], '\0',
+ ((*idl)->b_nmax - (*idl)->b_nids) * sizeof(ID) );
+
+ return;
+}
+
+/*
+ * idl_insert_maxids - insert an id into an id list.
+ * returns 0 id inserted
+ * 1 id inserted, first id in block has changed
+ * 2 id not inserted, already there
+ * 3 id not inserted, block must be split
+ */
+
+static int
+idl_insert_maxids( IDList **idl, ID id, int maxids )
+{
+ ID i, j;
+ NIDS nids;
+
+ if ( ALLIDS( *idl ) ) {
+ return( 2 ); /* already there */
+ }
+
+ nids = (*idl)->b_nids;
+
+ if (nids > 0) {
+ /* optimize for a simple append */
+ if (id == (*idl)->b_ids[nids-1]) {
+ return (2);
+ } else if (id > (*idl)->b_ids[nids-1]) {
+ if (nids < (*idl)->b_nmax) {
+ (*idl)->b_ids[nids] = id;
+ (*idl)->b_nids++;
+ return 0;
+ }
+
+ i = nids;
+
+ } else if (idl_tune & IDL_TUNE_BSEARCH) {
+ int lo = 0;
+ int hi = (*idl)->b_nids - 1;
+ int mid = 0;
+ ID *ids = (*idl)->b_ids;
+ if (0 != (*idl)->b_nids) {
+ while (lo <= hi) {
+ mid = (hi + lo) >> 1;
+ if (ids[mid] > id) {
+ hi = mid - 1;
+ } else {
+ if (ids[mid] < id) {
+ lo = mid + 1;
+ } else {
+ /* Found it ! */
+ return(2);
+ }
+ }
+ }
+ }
+ i = lo;
+ } else {
+ /* is it already there? linear search */
+ for ( i = 0; i < (*idl)->b_nids && id > (*idl)->b_ids[i]; i++ ) {
+ ; /* NULL */
+ }
+ if ( i < (*idl)->b_nids && (*idl)->b_ids[i] == id ) {
+ return( 2 ); /* already there */
+ }
+ }
+ }
+
+ /* do we need to make room for it? */
+ if ( (*idl)->b_nids == (*idl)->b_nmax ) {
+ /* make room or indicate block needs splitting */
+ if ( (*idl)->b_nmax == (ID) maxids ) {
+ return( 3 ); /* block needs splitting */
+ }
+
+ if (idl_tune & IDL_TUNE_NOPAD) {
+ (*idl)->b_nmax++;
+ } else {
+ (*idl)->b_nmax *= 2;
+ }
+ if ( (*idl)->b_nmax > (ID)maxids ) {
+ (*idl)->b_nmax = maxids;
+ }
+ *idl = (IDList *) slapi_ch_realloc( (char *) *idl,
+ ((*idl)->b_nmax + 2) * sizeof(ID) );
+ }
+
+ /* make a slot for the new id */
+ for ( j = (*idl)->b_nids; j != i; j-- ) {
+ (*idl)->b_ids[j] = (*idl)->b_ids[j-1];
+ }
+ (*idl)->b_ids[i] = id;
+ (*idl)->b_nids++;
+ (void) memset( (char *) &(*idl)->b_ids[(*idl)->b_nids], '\0',
+ ((*idl)->b_nmax - (*idl)->b_nids) * sizeof(ID) );
+
+ return( i == 0 ? 1 : 0 ); /* inserted - first id changed or not */
+}
+
+/*
+ * idl_delete_key - delete an id from the index entry identified by key
+ * returns 0 id was deleted
+ * -666 no such index entry or id in index entry
+ * other an error code from db
+ */
+
+int
+idl_old_delete_key(
+ backend *be,
+ DB *db,
+ DBT *key,
+ ID id,
+ DB_TXN *txn,
+ struct attrinfo *a
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ int i, j, rc;
+ char *msg;
+ IDList *idl, *didl;
+ DBT contkey = {0};
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> idl_delete_key(%s,%lu)\n",
+ key->dptr, (u_long)id, 0 );
+
+ idl_Wlock_list(a->ai_idl,key);
+
+ if ( (idl = idl_fetch_one( li, db, key, txn, &rc )) == NULL ) {
+ idl_unlock_list(a->ai_idl,key);
+ if ( rc != 0 && rc != DB_NOTFOUND && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key(%s) 0 BAD %d %s\n",
+ key->dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ }
+ if ( 0 == rc || DB_NOTFOUND == rc ) rc = -666;
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= idl_delete_key(%s,%lu) %d !idl_fetch_one\n",
+ key->dptr, (u_long)id, rc );
+ return rc;
+ }
+
+ /* regular block */
+ if ( ! INDIRECT_BLOCK( idl ) ) {
+ switch ( idl_delete( &idl, id ) ) {
+ case 0: /* id deleted, store the updated block */
+ case 1: /* first id changed - ok in direct block */
+ rc = idl_store( be, db, key, idl, txn );
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key(%s) 1 BAD %d %s\n",
+ key->dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ }
+ break;
+
+ case 2: /* id deleted, block empty - delete it */
+ rc = db->del( db, txn, key, 0 );
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key(%s) 2 BAD %d %s\n",
+ key->dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ if (rc == DB_RUNRECOVERY) {
+ ldbm_nasty("",74,rc);
+ }
+
+ }
+ break;
+
+ case 3: /* not there - previously deleted */
+ case 4: /* all ids block */
+ rc = 0;
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key(%s) 3 BAD idl_delete\n",
+ key->dptr, 0, 0 );
+ break;
+ }
+
+ idl_free( idl );
+ idl_unlock_list(a->ai_idl,key);
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= idl_delete_key(%s,%lu) %d (not indirect)\n",
+ key->dptr, (u_long)id, rc );
+ return( rc );
+ }
+
+ /*
+ * this is an indirect block that points to other blocks. we
+ * need to read the block containing the id to delete, delete
+ * the id, and store the changed block. if the first id in the
+ * block changes, or the block becomes empty, we need to rewrite
+ * the header block too.
+ */
+
+ /* select the block the id is in */
+ for ( i = 0; idl->b_ids[i] != NOID && id > idl->b_ids[i]; i++ ) {
+ ; /* NULL */
+ }
+ /* id smaller than smallest id - not there */
+ if ( i == 0 && id < idl->b_ids[i] ) {
+ idl_free( idl );
+ idl_unlock_list(a->ai_idl,key);
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= idl_delete_key(%s,%lu) -666 (id not found)\n",
+ key->dptr, (u_long)id, 0 );
+ return( -666 );
+ }
+ if ( id != idl->b_ids[i] ) {
+ i--;
+ }
+
+ /* get the block to delete from */
+ make_cont_key( &contkey, key, idl->b_ids[i] );
+ if ( (didl = idl_fetch_one( li, db, &contkey, txn, &rc )) == NULL ) {
+ idl_free( idl );
+ idl_unlock_list(a->ai_idl,key);
+ if ( rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key(%s) 5 BAD %d %s\n",
+ contkey.dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= idl_delete_key(%s,%lu) %d idl_fetch_one(contkey)\n",
+ contkey.dptr, (u_long)id, rc );
+ if ( contkey.dptr != NULL ) {
+ free( contkey.dptr );
+ }
+ return( rc );
+ }
+
+ rc = 0;
+ switch ( idl_delete( &didl, id ) ) {
+ case 0: /* id deleted - rewrite block */
+ if ( (rc = idl_store( be, db, &contkey, didl, txn )) != 0 ) {
+ if ( rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key(%s) BAD %d %s\n",
+ contkey.dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ }
+ }
+ if (0 != rc) {
+ idl_check_indirect( idl, i, didl, NULL, "idl_delete_key", "0", key, id );
+ }
+ break;
+
+ case 1: /* id deleted, first id changed, - write hdr, block */
+ rc = idl_change_first( be, db, key, idl, i, &contkey, didl, txn );
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key(%s) 7 BAD %d %s\n",
+ contkey.dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ }
+ if (0 != rc) {
+ idl_check_indirect( idl, i, didl, NULL, "idl_delete_key", "1", key, id );
+ }
+ break;
+
+ case 2: /* id deleted, block empty - write hdr, del block */
+ for ( j = i; idl->b_ids[j] != NOID; j++ ) {
+ idl->b_ids[j] = idl->b_ids[j+1];
+ }
+ if ( idl->b_ids[0] != NOID ) { /* Write the header, first: */
+ rc = idl_store( be, db, key, idl, txn );
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key: idl_store(%s) BAD %d %s\n",
+ key->dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ }
+ } else { /* This index is entirely empty. Delete the header: */
+ rc = db->del( db, txn, key, 0 );
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key: db->del(%s) BAD %d %s\n",
+ key->dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ if (rc == DB_RUNRECOVERY) {
+ ldbm_nasty("",75,rc);
+ }
+
+ }
+ }
+ if ( rc == 0 ) { /* Delete the indirect block: */
+ rc = db->del( db, txn, &contkey, 0 );
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key: db->del(%s) BAD %d %s\n",
+ contkey.dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ if (rc == DB_RUNRECOVERY) {
+ ldbm_nasty("",76,rc);
+ }
+
+ }
+ }
+ break;
+
+ case 3: /* id not found - previously deleted */
+ rc = 0;
+ idl_check_indirect( idl, i, didl, NULL, "idl_delete_key", "3", key, id );
+ break;
+ case 4: /* all ids block - should not happen */
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key: cont block (%s) is allids\n",
+ contkey.dptr, 0, 0 );
+ rc = 0;
+ break;
+ }
+ idl_free( idl );
+ idl_free( didl );
+ if ( contkey.dptr != NULL ) {
+ free( contkey.dptr );
+ }
+ idl_unlock_list(a->ai_idl,key);
+ if ( rc != 0 && rc != DB_LOCK_DEADLOCK )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "idl_delete_key(%s) 9 BAD %d %s\n",
+ key->dptr, rc, (msg = dblayer_strerror( rc )) ? msg : "" );
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= idl_delete_key(%s,%lu) %d (indirect)\n",
+ key->dptr, (u_long)id, rc );
+ return( rc );
+}
+
+/*
+ * idl_delete - delete an id from an id list.
+ * returns 0 id deleted
+ * 1 id deleted, first id in block has changed
+ * 2 id deleted, block is empty
+ * 3 id not there
+ * 4 cannot delete from allids block
+ */
+
+static int
+idl_delete( IDList **idl, ID id )
+{
+ ID i, delpos;
+
+ if ( ALLIDS( *idl ) ) {
+ return( 4 ); /* cannot delete from allids block */
+ }
+
+ /* find the id to delete */
+ for ( i = 0; i < (*idl)->b_nids && id > (*idl)->b_ids[i]; i++ ) {
+ ; /* NULL */
+ }
+ if ( i == (*idl)->b_nids || (*idl)->b_ids[i] != id ) {
+ return( 3 ); /* id not there */
+ }
+
+ if ( --((*idl)->b_nids) == 0 ) {
+ return( 2 ); /* id deleted, block empty */
+ }
+
+ /* delete it */
+ delpos = i;
+ for ( ; i < (*idl)->b_nids; i++ ) {
+ (*idl)->b_ids[i] = (*idl)->b_ids[i+1];
+ }
+
+ return( delpos == 0 ? 1 : 0 ); /* first id changed : id deleted */
+}
+
+
+static void
+make_cont_key( DBT *contkey, DBT *key, ID id )
+{
+ contkey->dptr = (char *) slapi_ch_malloc( key->dsize + 20 );
+ sprintf( contkey->dptr, "%c%s%lu", CONT_PREFIX, (char *)key->dptr, (u_long)id );
+ contkey->dsize = strlen( contkey->dptr ) + 1;
+}
diff --git a/ldap/servers/slapd/back-ldbm/idl_common.c b/ldap/servers/slapd/back-ldbm/idl_common.c
new file mode 100644
index 00000000..2cea183e
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/idl_common.c
@@ -0,0 +1,402 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Common IDL code, used in both old and new indexing schemes */
+
+#include "back-ldbm.h"
+
+size_t idl_sizeof(IDList *idl)
+{
+ return (2 + idl->b_nmax) * sizeof(ID);
+}
+
+NIDS idl_length(IDList *idl)
+{
+ return (idl->b_nmax == ALLIDSBLOCK) ? UINT_MAX : idl->b_nids;
+}
+
+int idl_is_allids(IDList *idl)
+{
+ return (idl->b_nmax == ALLIDSBLOCK);
+}
+
+IDList *
+idl_alloc( NIDS nids )
+{
+ IDList *new;
+
+ /* nmax + nids + space for the ids */
+ new = (IDList *) slapi_ch_calloc( (2 + nids), sizeof(ID) );
+ new->b_nmax = nids;
+ new->b_nids = 0;
+
+ return( new );
+}
+
+IDList *
+idl_allids( backend *be )
+{
+ IDList *idl;
+
+ idl = idl_alloc( 0 );
+ idl->b_nmax = ALLIDSBLOCK;
+ idl->b_nids = next_id_get( be );
+
+ return( idl );
+}
+
+void
+idl_free( IDList *idl ) /* JCM - pass in ** */
+{
+ if ( idl == NULL ) {
+ return;
+ }
+
+ slapi_ch_free((void**)&idl );
+}
+
+
+/*
+ * idl_append - append an id to an id list.
+ *
+ * Warning: The ID List must be maintained in order.
+ * Use idl_insert if the id may not
+ *
+ * returns
+ * 0 - appended
+ * 1 - already in there
+ * 2 - not enough room
+ */
+
+int
+idl_append( IDList *idl, ID id)
+{
+ if ( ALLIDS( idl ) || ( (idl->b_nids) && (idl->b_ids[idl->b_nids - 1] == id)) ) {
+ return( 1 ); /* already there */
+ }
+
+ if ( idl->b_nids == idl->b_nmax ) {
+ return( 2 ); /* not enough room */
+ }
+
+ idl->b_ids[idl->b_nids] = id;
+ idl->b_nids++;
+
+ return( 0 );
+}
+
+static IDList *
+idl_dup( IDList *idl )
+{
+ IDList *new;
+
+ if ( idl == NULL ) {
+ return( NULL );
+ }
+
+ new = idl_alloc( idl->b_nmax );
+ SAFEMEMCPY( (char *) new, (char *) idl, (idl->b_nmax + 2)
+ * sizeof(ID) );
+
+ return( new );
+}
+
+static IDList *
+idl_min( IDList *a, IDList *b )
+{
+ return( a->b_nids > b->b_nids ? b : a );
+}
+
+/*
+ * idl_intersection - return a intersection b
+ */
+
+IDList *
+idl_intersection(
+ backend *be,
+ IDList *a,
+ IDList *b
+)
+{
+ NIDS ai, bi, ni;
+ IDList *n;
+
+ if ( a == NULL || b == NULL ) {
+ return( NULL );
+ }
+ if ( ALLIDS( a ) ) {
+ slapi_be_set_flag(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
+ return( idl_dup( b ) );
+ }
+ if ( ALLIDS( b ) ) {
+ slapi_be_set_flag(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
+ return( idl_dup( a ) );
+ }
+
+ n = idl_dup( idl_min( a, b ) );
+
+ for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
+ for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai]; bi++ )
+ ; /* NULL */
+
+ if ( bi == b->b_nids ) {
+ break;
+ }
+
+ if ( b->b_ids[bi] == a->b_ids[ai] ) {
+ n->b_ids[ni++] = a->b_ids[ai];
+ }
+ }
+
+ if ( ni == 0 ) {
+ idl_free( n );
+ return( NULL );
+ }
+ n->b_nids = ni;
+
+ return( n );
+}
+
+/*
+ * idl_union - return a union b
+ */
+
+IDList *
+idl_union(
+ backend *be,
+ IDList *a,
+ IDList *b
+)
+{
+ NIDS ai, bi, ni;
+ IDList *n;
+
+ if ( a == NULL ) {
+ return( idl_dup( b ) );
+ }
+ if ( b == NULL ) {
+ return( idl_dup( a ) );
+ }
+ if ( ALLIDS( a ) || ALLIDS( b ) ) {
+ return( idl_allids( be ) );
+ }
+
+ if ( b->b_nids < a->b_nids ) {
+ n = a;
+ a = b;
+ b = n;
+ }
+
+ n = idl_alloc( a->b_nids + b->b_nids );
+
+ for ( ni = 0, ai = 0, bi = 0; ai < a->b_nids && bi < b->b_nids; ) {
+ if ( a->b_ids[ai] < b->b_ids[bi] ) {
+ n->b_ids[ni++] = a->b_ids[ai++];
+ } else if ( b->b_ids[bi] < a->b_ids[ai] ) {
+ n->b_ids[ni++] = b->b_ids[bi++];
+ } else {
+ n->b_ids[ni++] = a->b_ids[ai];
+ ai++, bi++;
+ }
+ }
+
+ for ( ; ai < a->b_nids; ai++ ) {
+ n->b_ids[ni++] = a->b_ids[ai];
+ }
+ for ( ; bi < b->b_nids; bi++ ) {
+ n->b_ids[ni++] = b->b_ids[bi];
+ }
+ n->b_nids = ni;
+
+ return( n );
+}
+
+/*
+ * idl_notin - return a intersection ~b (or a minus b)
+ * DB --- changed the interface of this function (no code called it),
+ * such that it can modify IDL a in place (it'll always be the same
+ * or smaller than the a passed in if not allids).
+ * If a new list is generated, it's returned in new_result and the function
+ * returns 1. Otherwise the result remains in a, and the function returns 0.
+ * The intention is to optimize for the interesting case in filterindex.c
+ * where we are computing foo AND NOT bar, and both foo and bar are not allids.
+ */
+
+int
+idl_notin(
+ backend *be,
+ IDList *a,
+ IDList *b,
+ IDList **new_result
+)
+{
+ NIDS ni, ai, bi;
+ IDList *n;
+ *new_result = NULL;
+
+ if ( a == NULL ) {
+ return( 0 );
+ }
+ if ( b == NULL || ALLIDS( b ) ) {
+ *new_result = idl_dup( a );
+ return( 1 );
+ }
+
+ if ( ALLIDS( a ) ) { /* Not convinced that this code is really worth it */
+ /* It's trying to do allids notin b, where maxid is smaller than some size */
+ n = idl_alloc( SLAPD_LDBM_MIN_MAXIDS );
+ ni = 0;
+
+ for ( ai = 1, bi = 0; ai < a->b_nids && ni < n->b_nmax &&
+ bi < b->b_nmax; ai++ ) {
+ if ( b->b_ids[bi] == ai ) {
+ bi++;
+ } else {
+ n->b_ids[ni++] = ai;
+ }
+ }
+
+ for ( ; ai < a->b_nids && ni < n->b_nmax; ai++ ) {
+ n->b_ids[ni++] = ai;
+ }
+
+ if ( ni == n->b_nmax ) {
+ idl_free( n );
+ *new_result = idl_allids( be );
+ } else {
+ n->b_nids = ni;
+ *new_result = n;
+ }
+ return( 1 );
+ }
+
+ /* This is the case we're interested in, we want to detect where a and b don't overlap */
+ {
+ size_t ahii, aloi, bhii, bloi;
+ size_t ahi, alo, bhi, blo;
+ int aloblo, ahiblo, alobhi, ahibhi;
+
+ aloi = bloi = 0;
+ ahii = a->b_nids - 1;
+ bhii = b->b_nids - 1;
+
+ ahi = a->b_ids[ahii];
+ alo = a->b_ids[aloi];
+ bhi = b->b_ids[bhii];
+ blo = b->b_ids[bloi];
+ /* if the ranges don't overlap, we're done, current a is the result */
+ aloblo = alo < blo;
+ ahiblo = ahi < blo;
+ alobhi = ahi > bhi;
+ ahibhi = alo > bhi;
+ if ( (aloblo & ahiblo) || (alobhi & ahibhi) ) {
+ return 0;
+ } else {
+ /* Do what we did before */
+ n = idl_dup( a );
+
+ ni = 0;
+ for ( ai = 0, bi = 0; ai < a->b_nids; ai++ ) {
+ for ( ; bi < b->b_nids && b->b_ids[bi] < a->b_ids[ai];
+ bi++ ) {
+ ; /* NULL */
+ }
+
+ if ( bi == b->b_nids ) {
+ break;
+ }
+
+ if ( b->b_ids[bi] != a->b_ids[ai] ) {
+ n->b_ids[ni++] = a->b_ids[ai];
+ }
+ }
+
+ for ( ; ai < a->b_nids; ai++ ) {
+ n->b_ids[ni++] = a->b_ids[ai];
+ }
+ n->b_nids = ni;
+
+ *new_result = n;
+ return( 1 );
+ }
+ }
+}
+
+ID
+idl_firstid( IDList *idl )
+{
+ if ( idl == NULL || idl->b_nids == 0 ) {
+ return( NOID );
+ }
+
+ if ( ALLIDS( idl ) ) {
+ return( idl->b_nids == 1 ? NOID : 1 );
+ }
+
+ return( idl->b_ids[0] );
+}
+
+ID
+idl_nextid( IDList *idl, ID id )
+{
+ NIDS i;
+
+ if ( ALLIDS( idl ) ) {
+ return( ++id < idl->b_nids ? id : NOID );
+ }
+
+ for ( i = 0; i < idl->b_nids && idl->b_ids[i] < id; i++ ) {
+ ; /* NULL */
+ }
+ i++;
+
+ if ( i >= idl->b_nids ) {
+ return( NOID );
+ } else {
+ return( idl->b_ids[i] );
+ }
+}
+
+/* Make an ID list iterator */
+idl_iterator idl_iterator_init(const IDList *idl)
+{
+ return (idl_iterator) 0;
+}
+
+idl_iterator idl_iterator_increment(idl_iterator *i)
+{
+ size_t t = (size_t) *i;
+ t += 1;
+ *i = (idl_iterator) t;
+ return *i;
+}
+
+idl_iterator idl_iterator_decrement(idl_iterator *i)
+{
+ size_t t = (size_t) *i;
+ t -= 1;
+ *i = (idl_iterator) t;
+ return *i;
+}
+
+ID idl_iterator_dereference(idl_iterator i, const IDList *idl)
+{
+ if ( (NULL == idl) || (i >= idl->b_nids)) {
+ return NOID;
+ }
+ if (ALLIDS(idl)) {
+ return (ID) i + 1;
+ } else {
+ return idl->b_ids[i];
+ }
+}
+
+ID idl_iterator_dereference_increment(idl_iterator *i, const IDList *idl)
+{
+ ID t = idl_iterator_dereference(*i,idl);
+ idl_iterator_increment(i);
+ return t;
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/idl_new.c b/ldap/servers/slapd/back-ldbm/idl_new.c
new file mode 100644
index 00000000..d2038261
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/idl_new.c
@@ -0,0 +1,671 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* New IDL code for new indexing scheme */
+
+/* Note to future editors:
+ This file is now full of redundant code
+ (the DB_ALLIDS_ON_WRITE==true and DB_USE_BULK_FETCH==false code).
+ It should be stripped out at the beginning of a
+ major release cycle.
+ */
+
+#include "back-ldbm.h"
+
+static char* filename = "idl_new.c";
+
+/* Bulk fetch feature first in DB 3.3 */
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3300
+#define DB_USE_BULK_FETCH 1
+#define BULK_FETCH_BUFFER_SIZE (8*1024)
+#else
+#undef DB_USE_BULK_FETCH
+#endif
+
+/* We used to implement allids for inserts, but that's a bad idea.
+ Why ? Because:
+ 1) Allids results in hard to understand query behavior.
+ 2) The get() calls needed to check for allids on insert cost performance.
+ 3) Tests show that there is no significant performance benefit to having allids on writes,
+ either for updates or searches.
+ Set this to revert to that code */
+/* #undef DB_ALLIDS_ON_WRITE */
+/* We still enforce allids threshold on reads, to save time and space fetching vast id lists */
+#define DB_ALLIDS_ON_READ 1
+
+#if !defined(DB_NEXT_DUP)
+#define DB_NEXT_DUP 0
+#endif
+#if !defined(DB_GET_BOTH)
+#define DB_GET_BOTH 0
+#endif
+
+/* Structure used to hide private idl-specific data in the attrinfo object */
+struct idl_private {
+ size_t idl_allidslimit;
+ int dummy;
+};
+
+static int idl_tune = DEFAULT_IDL_TUNE; /* tuning parameters for IDL code */
+/* Currently none for new IDL code */
+
+#if defined(DB_ALLIDS_ON_WRITE)
+static int idl_new_store_allids(backend *be, DB *db, DBT *key, DB_TXN *txn);
+#endif
+
+void idl_new_set_tune(int val)
+{
+ idl_tune = val;
+}
+
+int idl_new_get_tune() {
+ return idl_tune;
+}
+
+/* Append an ID to an IDL, realloc-ing the space if needs be */
+/* ID presented is not to be already in the IDL. */
+static int
+idl_append_extend( IDList **orig_idl, ID id)
+{
+ IDList *idl = *orig_idl;
+
+ if (idl == NULL) {
+ idl = idl_alloc(1);
+ idl_append(idl, id);
+
+ *orig_idl = idl;
+ return 0;
+ }
+
+ if ( idl->b_nids == idl->b_nmax ) {
+ size_t x = 0;
+ /* No more room, need to extend */
+ /* Allocate new IDL with twice the space of this one */
+ IDList *idl_new = NULL;
+ idl_new = idl_alloc(idl->b_nmax * 2);
+ if (NULL == idl_new) {
+ return ENOMEM;
+ }
+ /* copy over the existing contents */
+ idl_new->b_nids = idl->b_nids;
+ for (x = 0; x < idl->b_nids;x++) {
+ idl_new->b_ids[x] = idl->b_ids[x];
+ }
+ idl_free(idl);
+ idl = idl_new;
+ }
+
+ idl->b_ids[idl->b_nids] = id;
+ idl->b_nids++;
+ *orig_idl = idl;
+
+ return 0;
+}
+
+size_t idl_new_get_allidslimit(struct attrinfo *a)
+{
+ idl_private *priv = NULL;
+
+ PR_ASSERT(NULL != a);
+ PR_ASSERT(NULL != a->ai_idl);
+
+ priv = a->ai_idl;
+
+ return priv->idl_allidslimit;
+}
+
+/* routine to initialize the private data used by the IDL code per-attribute */
+int idl_new_init_private(backend *be,struct attrinfo *a)
+{
+ idl_private *priv = NULL;
+ struct ldbminfo *li = (struct ldbminfo *)be->be_database->plg_private;
+
+ PR_ASSERT(NULL != a);
+ PR_ASSERT(NULL == a->ai_idl);
+
+ priv = (idl_private*) slapi_ch_calloc(sizeof(idl_private),1);
+ if (NULL == priv) {
+ return -1; /* Memory allocation failure */
+ }
+ priv->idl_allidslimit = li->li_allidsthreshold;
+ /* Initialize the structure */
+ a->ai_idl = (void*)priv;
+ return 0;
+}
+
+/* routine to release resources used by IDL private data structure */
+int idl_new_release_private(struct attrinfo *a)
+{
+ PR_ASSERT(NULL != a);
+ if (NULL != a->ai_idl)
+ {
+ slapi_ch_free((void**)&(a->ai_idl) );
+ }
+ return 0;
+}
+
+IDList * idl_new_fetch(
+ backend *be,
+ DB* db,
+ DBT *inkey,
+ DB_TXN *txn,
+ struct attrinfo *a,
+ int *flag_err
+)
+{
+ int ret = 0;
+ DBC *cursor = NULL;
+ IDList *idl = NULL;
+ DBT key = {0};
+ DBT data = {0};
+ ID id = 0;
+ size_t count = 0;
+#ifdef DB_USE_BULK_FETCH
+ /* beware that a large buffer on the stack might cause a stack overflow on some platforms */
+ char buffer[BULK_FETCH_BUFFER_SIZE];
+ void *ptr;
+ DBT dataret = {0};
+#endif
+
+ if (NEW_IDL_NOOP == *flag_err)
+ {
+ *flag_err = 0;
+ return NULL;
+ }
+
+ /* Make a cursor */
+ ret = db->cursor(db,txn,&cursor,0);
+ if (0 != ret) {
+ ldbm_nasty(filename,1,ret);
+ cursor = NULL;
+ goto error;
+ }
+#ifdef DB_USE_BULK_FETCH
+ data.ulen = sizeof(buffer);
+ data.size = sizeof(buffer);
+ data.data = buffer;
+ data.flags = DB_DBT_USERMEM;
+#else
+ data.ulen = sizeof(id);
+ data.size = sizeof(id);
+ data.data = &id;
+ data.flags = DB_DBT_USERMEM;
+#endif
+
+ /*
+ * We're not expecting the key to change in value
+ * so we can just use the input key as a buffer.
+ * This avoids memory management of the key.
+ */
+ key.ulen = inkey->size;
+ key.size = inkey->size;
+ key.data = inkey->data;
+ key.flags = DB_DBT_USERMEM;
+
+ /* Position cursor at the first matching key */
+#ifdef DB_USE_BULK_FETCH
+ ret = cursor->c_get(cursor,&key,&data,DB_SET|DB_MULTIPLE);
+#else
+ ret = cursor->c_get(cursor,&key,&data,DB_SET);
+#endif
+ if (0 != ret) {
+ if (DB_NOTFOUND == ret) {
+ ret = 0;
+ } else {
+#ifdef DB_USE_BULK_FETCH
+ if (ret == ENOMEM) {
+ LDAPDebug(LDAP_DEBUG_ANY, "database index is corrupt; "
+ "data item for key %s is too large for our buffer "
+ "(need=%d actual=%d)\n",
+ key.data, data.size, data.ulen);
+ }
+#endif
+ ldbm_nasty(filename,2,ret);
+ }
+ goto error; /* Not found is OK, return NULL IDL */
+ }
+
+ /* Iterate over the duplicates, amassing them into an IDL */
+#ifdef DB_USE_BULK_FETCH
+ for (;;) {
+
+ DB_MULTIPLE_INIT(ptr, &data);
+
+ for (;;) {
+ DB_MULTIPLE_NEXT(ptr, &data, dataret.data, dataret.size);
+ if (dataret.data == NULL) break;
+ if (ptr == NULL) break;
+
+ if (dataret.size != sizeof(ID)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "database index is corrupt; "
+ "key %s has a data item with the wrong size (%d)\n",
+ key.data, dataret.size, 0);
+ goto error;
+ }
+ memcpy(&id, dataret.data, sizeof(ID));
+
+ /* we got another ID, add it to our IDL */
+ idl_append_extend(&idl, id);
+
+ count++;
+ }
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "bulk fetch buffer nids=%d\n", count, 0, 0);
+
+ ret = cursor->c_get(cursor,&key,&data,DB_NEXT_DUP|DB_MULTIPLE);
+ if (0 != ret) {
+ break;
+ }
+#if defined(DB_ALLIDS_ON_READ)
+ /* enforce the allids read limit */
+ if (NEW_IDL_NO_ALLID != *flag_err &&
+ NULL != a && count > idl_new_get_allidslimit(a)) {
+ idl->b_nids = 1;
+ idl->b_ids[0] = ALLID;
+ ret = DB_NOTFOUND; /* fool the code below into thinking that we finished the dups */
+ break;
+ }
+#endif
+ }
+#else
+ for (;;) {
+ ret = cursor->c_get(cursor,&key,&data,DB_NEXT_DUP);
+ count++;
+ if (0 != ret) {
+ break;
+ }
+ /* we got another ID, add it to our IDL */
+ idl_append_extend(&idl, id);
+#if defined(DB_ALLIDS_ON_READ)
+ /* enforce the allids read limit */
+ if (count > idl_new_get_allidslimit(a)) {
+ idl->b_nids = 1;
+ idl->b_ids[0] = ALLID;
+ ret = DB_NOTFOUND; /* fool the code below into thinking that we finished the dups */
+ break;
+ }
+#endif
+ }
+#endif
+
+ if (ret != DB_NOTFOUND) {
+ idl_free(idl); idl = NULL;
+ ldbm_nasty(filename,59,ret);
+ goto error;
+ }
+
+ ret = 0;
+
+ /* check for allids value */
+ if (idl != NULL && idl->b_nids == 1 && idl->b_ids[0] == ALLID) {
+ idl_free(idl);
+ idl = idl_allids(be);
+ LDAPDebug(LDAP_DEBUG_TRACE, "idl_new_fetch %s returns allids\n",
+ key.data, 0, 0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE, "idl_new_fetch %s returns nids=%lu\n",
+ key.data, (u_long)IDL_NIDS(idl), 0);
+ }
+
+error:
+ /* Close the cursor */
+ if (NULL != cursor) {
+ if (0 != cursor->c_close(cursor)) {
+ ldbm_nasty(filename,3,ret);
+ }
+ }
+ *flag_err = ret;
+ return idl;
+}
+
+int idl_new_insert_key(
+ backend *be,
+ DB* db,
+ DBT *key,
+ ID id,
+ DB_TXN *txn,
+ struct attrinfo *a,
+ int *disposition
+)
+{
+ int ret = 0;
+ DBT data = {0};
+
+#if defined(DB_ALLIDS_ON_WRITE)
+ DBC *cursor = NULL;
+ db_recno_t count;
+ ID tmpid = 0;
+ /* Make a cursor */
+ ret = db->cursor(db,txn,&cursor,0);
+ if (0 != ret) {
+ ldbm_nasty(filename,58,ret);
+ cursor = NULL;
+ goto error;
+ }
+ data.ulen = sizeof(id);
+ data.size = sizeof(id);
+ data.flags = DB_DBT_USERMEM;
+ data.data = &tmpid;
+ ret = cursor->c_get(cursor,key,&data,DB_SET);
+ if (0 == ret) {
+ if (tmpid == ALLID) {
+ if (NULL != disposition) {
+ *disposition = IDL_INSERT_ALLIDS;
+ }
+ goto error; /* allid: don't bother inserting any more */
+ }
+ } else if (DB_NOTFOUND != ret) {
+ ldbm_nasty(filename,12,ret);
+ goto error;
+ }
+ if (NULL != disposition) {
+ *disposition = IDL_INSERT_NORMAL;
+ }
+
+ data.data = &id;
+
+ /* insert it */
+ ret = cursor->c_put(cursor, key, &data, DB_NODUPDATA);
+ if (0 != ret) {
+ if (DB_KEYEXIST == ret) {
+ /* this is okay */
+ ret = 0;
+ } else {
+ ldbm_nasty(filename,50,ret);
+ }
+ } else {
+ /* check for allidslimit exceeded in database */
+ if (cursor->c_count(cursor, &count, 0) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "could not obtain count for key %s\n",
+ key->data, 0, 0);
+ goto error;
+ }
+ if ((size_t)count > idl_new_get_allidslimit(a)) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "allidslimit exceeded for key %s\n",
+ key->data, 0, 0);
+ cursor->c_close(cursor);
+ cursor = NULL;
+ if ((ret = idl_new_store_allids(be, db, key, txn)) == 0) {
+ if (NULL != disposition) {
+ *disposition = IDL_INSERT_NOW_ALLIDS;
+ }
+ }
+ }
+error:
+ /* Close the cursor */
+ if (NULL != cursor) {
+ if (0 != cursor->c_close(cursor)) {
+ ldbm_nasty(filename,56,ret);
+ }
+ }
+#else
+ data.ulen = sizeof(id);
+ data.size = sizeof(id);
+ data.flags = DB_DBT_USERMEM;
+ data.data = &id;
+
+ if (NULL != disposition) {
+ *disposition = IDL_INSERT_NORMAL;
+ }
+
+ ret = db->put(db, txn, key, &data, DB_NODUPDATA);
+ if (0 != ret) {
+ if (DB_KEYEXIST == ret) {
+ /* this is okay */
+ ret = 0;
+ } else {
+ ldbm_nasty(filename,50,ret);
+ }
+ }
+#endif
+
+
+ return ret;
+}
+
+int idl_new_delete_key(
+ backend *be,
+ DB *db,
+ DBT *key,
+ ID id,
+ DB_TXN *txn,
+ struct attrinfo *a
+)
+{
+ int ret = 0;
+ DBC *cursor = NULL;
+ DBT data = {0};
+ ID tmpid = 0;
+
+ /* Make a cursor */
+ ret = db->cursor(db,txn,&cursor,0);
+ if (0 != ret) {
+ ldbm_nasty(filename,21,ret);
+ cursor = NULL;
+ goto error;
+ }
+ data.ulen = sizeof(id);
+ data.size = sizeof(id);
+ data.flags = DB_DBT_USERMEM;
+ data.data = &tmpid;
+ ret = cursor->c_get(cursor,key,&data,DB_SET);
+ if (0 == ret) {
+ if (tmpid == ALLID) {
+ goto error; /* allid: never delete it */
+ }
+ } else if (DB_NOTFOUND != ret) {
+ ldbm_nasty(filename,22,ret);
+ goto error;
+ }
+
+ /* Position cursor at the key, value pair */
+ data.data = &id;
+ ret = cursor->c_get(cursor,key,&data,DB_GET_BOTH);
+ if (0 != ret) {
+ if (DB_NOTFOUND == ret) {
+ ret = 0; /* Not Found is OK, return immediately */
+ } else {
+ ldbm_nasty(filename,23,ret);
+ }
+ goto error;
+ }
+ /* We found it, so delete it */
+ ret = cursor->c_del(cursor,0);
+error:
+ /* Close the cursor */
+ if (NULL != cursor) {
+ if (0 != cursor->c_close(cursor)) {
+ ldbm_nasty(filename,24,ret);
+ }
+ }
+ return ret;
+}
+
+#if defined(DB_ALLIDS_ON_WRITE)
+static int idl_new_store_allids(backend *be, DB *db, DBT *key, DB_TXN *txn)
+{
+ int ret = 0;
+ DBC *cursor = NULL;
+ DBT data = {0};
+ ID id = 0;
+
+ /* Make a cursor */
+ ret = db->cursor(db,txn,&cursor,0);
+ if (0 != ret) {
+ ldbm_nasty(filename,31,ret);
+ cursor = NULL;
+ goto error;
+ }
+ data.ulen = sizeof(ID);
+ data.size = sizeof(ID);
+ data.data = &id;
+ data.flags = DB_DBT_USERMEM;
+
+ /* Position cursor at the key */
+ ret = cursor->c_get(cursor,key,&data,DB_SET);
+ if (ret == 0) {
+ /* We found it, so delete all duplicates */
+ ret = cursor->c_del(cursor,0);
+ while (0 == ret) {
+ ret = cursor->c_get(cursor,key,&data,DB_NEXT_DUP);
+ if (0 != ret) {
+ break;
+ }
+ ret = cursor->c_del(cursor,0);
+ }
+ if (0 != ret && DB_NOTFOUND != ret) {
+ ldbm_nasty(filename,54,ret);
+ goto error;
+ } else {
+ ret = 0;
+ }
+ } else {
+ if (DB_NOTFOUND == ret) {
+ ret = 0; /* Not Found is OK */
+ } else {
+ ldbm_nasty(filename,32,ret);
+ goto error;
+ }
+ }
+
+ /* store the ALLID value */
+ id = ALLID;
+ ret = cursor->c_put(cursor, key, &data, DB_NODUPDATA);
+ if (0 != ret) {
+ ldbm_nasty(filename,53,ret);
+ goto error;
+ }
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "key %s has been set to allids\n",
+ key->data, 0, 0);
+
+error:
+ /* Close the cursor */
+ if (NULL != cursor) {
+ if (0 != cursor->c_close(cursor)) {
+ ldbm_nasty(filename,33,ret);
+ }
+ }
+ return ret;
+ /* If this function is called in "no-allids" mode, then it's a bug */
+ ldbm_nasty(filename,63,0);
+ return -1;
+}
+#endif
+
+int idl_new_store_block(
+ backend *be,
+ DB *db,
+ DBT *key,
+ IDList *idl,
+ DB_TXN *txn,
+ struct attrinfo *a
+)
+{
+ int ret = 0;
+ DBC *cursor = NULL;
+ DBT data = {0};
+ ID id = 0;
+ size_t x = 0;
+#if defined(DB_ALLIDS_ON_WRITE)
+ db_recno_t count;
+#endif
+
+ if (NULL == idl)
+ {
+ return ret;
+ }
+
+ /*
+ * Really we need an extra entry point to the DB here, which
+ * inserts a list of duplicate keys. In the meantime, we'll
+ * just do it by brute force.
+ */
+
+#if defined(DB_ALLIDS_ON_WRITE)
+ /* allids check on input idl */
+ if (ALLIDS(idl) || (idl->b_nids > (ID)idl_new_get_allidslimit(a))) {
+ return idl_new_store_allids(be, db, key, txn);
+ }
+#endif
+
+ /* Make a cursor */
+ ret = db->cursor(db,txn,&cursor,0);
+ if (0 != ret) {
+ ldbm_nasty(filename,41,ret);
+ cursor = NULL;
+ goto error;
+ }
+
+ /* initialize data DBT */
+ data.data = &id;
+ data.ulen = sizeof(id);
+ data.size = sizeof(id);
+ data.flags = DB_DBT_USERMEM;
+
+ /* Position cursor at the key, value pair */
+ ret = cursor->c_get(cursor,key,&data,DB_GET_BOTH);
+ if (ret == DB_NOTFOUND) {
+ ret = 0;
+ } else if (ret != 0) {
+ ldbm_nasty(filename,47,ret);
+ goto error;
+ }
+
+ /* Iterate over the IDs in the idl */
+ for (x = 0; x < idl->b_nids; x++) {
+ /* insert an id */
+ id = idl->b_ids[x];
+ ret = cursor->c_put(cursor, key, &data, DB_NODUPDATA);
+ if (0 != ret) {
+ if (DB_KEYEXIST == ret) {
+ ret = 0; /* exist is okay */
+ } else {
+ ldbm_nasty(filename,48,ret);
+ goto error;
+ }
+ }
+ }
+#if defined(DB_ALLIDS_ON_WRITE)
+ /* check for allidslimit exceeded in database */
+ if (cursor->c_count(cursor, &count, 0) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "could not obtain count for key %s\n",
+ key->data, 0, 0);
+ goto error;
+ }
+ if ((size_t)count > idl_new_get_allidslimit(a)) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "allidslimit exceeded for key %s\n",
+ key->data, 0, 0);
+ cursor->c_close(cursor);
+ cursor = NULL;
+ ret = idl_new_store_allids(be, db, key, txn);
+ }
+#endif
+
+error:
+ /* Close the cursor */
+ if (NULL != cursor) {
+ if (0 != cursor->c_close(cursor)) {
+ ldbm_nasty(filename,49,ret);
+ }
+ }
+ return ret;
+}
+
+/* idl_new_compare_dups: comparing ID, pass to libdb for callback */
+int idl_new_compare_dups(
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3200
+ DB *db,
+#endif
+ const DBT *a,
+ const DBT *b
+)
+{
+ ID a_copy, b_copy;
+ memmove(&a_copy, a->data, sizeof(ID));
+ memmove(&b_copy, b->data, sizeof(ID));
+ return a_copy - b_copy;
+}
diff --git a/ldap/servers/slapd/back-ldbm/idl_shim.c b/ldap/servers/slapd/back-ldbm/idl_shim.c
new file mode 100644
index 00000000..2332ce1b
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/idl_shim.c
@@ -0,0 +1,124 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Shim which forwards IDL calls to the appropriate implementation */
+
+#include "back-ldbm.h"
+
+static int idl_new = 0; /* non-zero if we're doing new IDL style */
+
+
+void idl_old_set_tune(int val);
+int idl_old_get_tune();
+int idl_old_init_private(backend *be, struct attrinfo *a);
+int idl_old_release_private(struct attrinfo *a);
+size_t idl_old_get_allidslimit(struct attrinfo *a);
+IDList * idl_old_fetch( backend *be, DB* db, DBT *key, DB_TXN *txn, struct attrinfo *a, int *err );
+int idl_old_insert_key( backend *be, DB* db, DBT *key, ID id, DB_TXN *txn, struct attrinfo *a,int *disposition );
+int idl_old_delete_key( backend *be, DB *db, DBT *key, ID id, DB_TXN *txn, struct attrinfo *a );
+int idl_old_store_block( backend *be,DB *db,DBT *key,IDList *idl,DB_TXN *txn,struct attrinfo *a);
+
+
+void idl_new_set_tune(int val);
+int idl_new_get_tune();
+int idl_new_init_private(backend *be, struct attrinfo *a);
+int idl_new_release_private(struct attrinfo *a);
+size_t idl_new_get_allidslimit(struct attrinfo *a);
+IDList * idl_new_fetch( backend *be, DB* db, DBT *key, DB_TXN *txn, struct attrinfo *a, int *err );
+int idl_new_insert_key( backend *be, DB* db, DBT *key, ID id, DB_TXN *txn, struct attrinfo *a,int *disposition );
+int idl_new_delete_key( backend *be, DB *db, DBT *key, ID id, DB_TXN *txn, struct attrinfo *a );
+int idl_new_store_block( backend *be,DB *db,DBT *key,IDList *idl,DB_TXN *txn,struct attrinfo *a);
+
+int idl_get_idl_new()
+{
+ return idl_new;
+}
+
+void idl_set_tune(int val)
+{
+ /* Catch idl_tune requests to use new idl code */
+ if (4096 == val) {
+ idl_new = 1;
+ } else {
+ idl_new = 0;
+ }
+ if (idl_new) {
+ idl_new_set_tune(val);
+ } else {
+ idl_old_set_tune(val);
+ }
+}
+
+int idl_get_tune()
+{
+ if (idl_new) {
+ return idl_new_get_tune();
+ } else {
+ return idl_old_get_tune();
+ }
+}
+
+int idl_init_private(backend *be, struct attrinfo *a)
+{
+ if (idl_new) {
+ return idl_new_init_private(be,a);
+ } else {
+ return idl_old_init_private(be,a);
+ }
+}
+
+int idl_release_private(struct attrinfo *a)
+{
+ if (idl_new) {
+ return idl_new_release_private(a);
+ } else {
+ return idl_old_release_private(a);
+ }
+}
+
+size_t idl_get_allidslimit(struct attrinfo *a)
+{
+ if (idl_new) {
+ return idl_new_get_allidslimit(a);
+ } else {
+ return idl_old_get_allidslimit(a);
+ }
+}
+
+IDList * idl_fetch( backend *be, DB* db, DBT *key, DB_TXN *txn, struct attrinfo *a, int *err )
+{
+ if (idl_new) {
+ return idl_new_fetch(be,db,key,txn,a,err);
+ } else {
+ return idl_old_fetch(be,db,key,txn,a,err);
+ }
+}
+
+int idl_insert_key( backend *be, DB* db, DBT *key, ID id, DB_TXN *txn, struct attrinfo *a,int *disposition )
+{
+ if (idl_new) {
+ return idl_new_insert_key(be,db,key,id,txn,a,disposition);
+ } else {
+ return idl_old_insert_key(be,db,key,id,txn,a,disposition);
+ }
+}
+
+int idl_delete_key(backend *be, DB *db, DBT *key, ID id, DB_TXN *txn, struct attrinfo *a )
+{
+ if (idl_new) {
+ return idl_new_delete_key(be,db,key,id,txn,a);
+ } else {
+ return idl_old_delete_key(be,db,key,id,txn,a);
+ }
+}
+
+int idl_store_block(backend *be,DB *db,DBT *key,IDList *idl,DB_TXN *txn,struct attrinfo *a)
+{
+ if (idl_new) {
+ return idl_new_store_block(be,db,key,idl,txn,a);
+ } else {
+ return idl_old_store_block(be,db,key,idl,txn,a);
+ }
+}
diff --git a/ldap/servers/slapd/back-ldbm/idlapi.h b/ldap/servers/slapd/back-ldbm/idlapi.h
new file mode 100644
index 00000000..39fe9c15
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/idlapi.h
@@ -0,0 +1,30 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _IDL_API_H_
+#define _IDL_API_H_
+
+/* mechanics */
+
+typedef IDList *(*api_idl_alloc)( NIDS nids );
+typedef void (*api_idl_insert)(IDList **idl, ID id);
+
+/* API ID for slapi_apib_get_interface */
+
+#define IDL_v1_0_GUID "ec228d97-971d-4b9e-91b5-4f90e1841f24"
+
+/* API */
+
+/* the api broker reserves api[0] for its use */
+
+#define IDList_alloc(api, nids) \
+ ((api_idl_alloc*)(api))[1](nids)
+
+#define IDList_insert(api, idl, id) \
+ ((api_idl_insert*)(api))[2](idl, id)
+
+
+#endif /*_IDL_API_H_*/
diff --git a/ldap/servers/slapd/back-ldbm/import-merge.c b/ldap/servers/slapd/back-ldbm/import-merge.c
new file mode 100644
index 00000000..b50aaaec
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/import-merge.c
@@ -0,0 +1,680 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * this is a bunch of routines for merging groups of db files together --
+ * currently it's only used for imports (when we import into several small
+ * db sets for speed, then merge them).
+ */
+
+#include "back-ldbm.h"
+#include "import.h"
+
+struct _import_merge_thang
+{
+ int type;
+#define IMPORT_MERGE_THANG_IDL 1 /* Values for type */
+#define IMPORT_MERGE_THANG_VLV 2
+ union {
+ IDList *idl; /* if type == IMPORT_MERGE_THANG_IDL */
+ DBT vlv_data; /* if type == IMPORT_MERGE_THANG_VLV */
+ } payload;
+};
+typedef struct _import_merge_thang import_merge_thang;
+
+struct _import_merge_queue_entry
+{
+ int *file_referenced_list;
+ import_merge_thang thang;
+ DBT key;
+ struct _import_merge_queue_entry *next;
+};
+typedef struct _import_merge_queue_entry import_merge_queue_entry;
+
+static int import_merge_get_next_thang(backend *be, DBC *cursor, DB *db, import_merge_thang *thang, DBT *key, int type)
+{
+ int ret = 0;
+ DBT value = {0};
+
+ value.flags = DB_DBT_MALLOC;
+ key->flags = DB_DBT_MALLOC;
+
+ thang->type = type;
+ if (IMPORT_MERGE_THANG_IDL == type) {
+ /* IDL case */
+ around:
+ ret = cursor->c_get(cursor, key, &value, DB_NEXT_NODUP);
+ if (0 == ret) {
+ /* Check that we've not reached the beginning of continuation
+ * blocks */
+ if (CONT_PREFIX != ((char*)key->data)[0]) {
+ /* If not, read the IDL using idl_fetch() */
+ key->flags = DB_DBT_REALLOC;
+ ret = NEW_IDL_NO_ALLID;
+ thang->payload.idl = idl_fetch(be, db, key, NULL, NULL, &ret);
+ PR_ASSERT(NULL != thang->payload.idl);
+ } else {
+ free(value.data);
+ free(key->data);
+ key->flags = DB_DBT_MALLOC;
+ goto around; /* Just skip these */
+ }
+ free(value.data);
+ } else {
+ if (DB_NOTFOUND == ret) {
+ /* This means that we're at the end of the file */
+ ret = EOF;
+ }
+ }
+ } else {
+ /* VLV case */
+ ret = cursor->c_get(cursor,key,&value,DB_NEXT);
+ if (0 == ret) {
+ thang->payload.vlv_data = value;
+ thang->payload.vlv_data.flags = 0;
+ key->flags = 0;
+ } else {
+ if (DB_NOTFOUND == ret) {
+ /* This means that we're at the end of the file */
+ ret = EOF;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static import_merge_queue_entry *import_merge_make_new_queue_entry(import_merge_thang *thang, DBT *key, int fileno, int passes)
+{
+ /* Make a new entry */
+ import_merge_queue_entry *new_entry = (import_merge_queue_entry *)slapi_ch_calloc(1, sizeof(import_merge_queue_entry));
+
+ if (NULL == new_entry) {
+ return NULL;
+ }
+ new_entry->key = *key;
+ new_entry->thang = *thang;
+ new_entry->file_referenced_list =
+ (int *)slapi_ch_calloc(passes, sizeof(fileno));
+
+ if (NULL == new_entry->file_referenced_list) {
+ return NULL;
+ }
+ (new_entry->file_referenced_list)[fileno] = 1;
+ return new_entry;
+}
+
+/* Put an IDL onto the priority queue */
+static int import_merge_insert_input_queue(backend *be, import_merge_queue_entry **queue,int fileno, DBT *key, import_merge_thang *thang,int passes)
+{
+ /* Walk the list, looking for a key value which is greater than or equal
+ * to the presented key */
+ /* If an equal key is found, compute the union of the IDLs and store that
+ * back in the queue entry */
+ /* If a key greater than is found, or no key greater than is found, insert
+ * a new queue entry */
+ import_merge_queue_entry *current_entry = NULL;
+ import_merge_queue_entry *previous_entry = NULL;
+
+ PR_ASSERT(NULL != thang);
+ if (NULL == *queue) {
+ /* Queue was empty--- put ourselves at the head */
+ *queue = import_merge_make_new_queue_entry(thang,key,fileno,passes);
+ if (NULL == *queue) {
+ return -1;
+ }
+ } else {
+ for (current_entry = *queue; current_entry != NULL;
+ current_entry = current_entry->next) {
+ int cmp = strcmp(key->data,current_entry->key.data);
+
+ if (0 == cmp) {
+ if (IMPORT_MERGE_THANG_IDL == thang->type) { /* IDL case */
+ IDList *idl = thang->payload.idl;
+ /* Equal --- merge into the stored IDL, add file ID
+ * to the list */
+ IDList *new_idl =
+ idl_union(be, current_entry->thang.payload.idl, idl);
+
+ idl_free(current_entry->thang.payload.idl);
+ idl_free(idl);
+ current_entry->thang.payload.idl = new_idl;
+ /* Add this file id into the entry's referenced list */
+ (current_entry->file_referenced_list)[fileno] = 1;
+ /* Because we merged the entries, we no longer need the
+ * key, so free it */
+ free(key->data);
+ goto done;
+ } else {
+ /* VLV case, we can see exact keys, this is not a bug ! */
+ /* We want to ensure that they key read most recently is
+ * put later in the queue than any others though */
+ }
+ } else {
+ if (cmp < 0) {
+ /* We compare smaller than the stored key, so we should
+ * insert ourselves before this entry */
+ break;
+ } else {
+ /* We compare greater than this entry, so we should keep
+ * going */ ;
+ }
+ }
+ previous_entry = current_entry;
+ }
+
+ /* Now insert */
+ {
+ import_merge_queue_entry *new_entry =
+ import_merge_make_new_queue_entry(thang, key, fileno, passes);
+
+ if (NULL == new_entry) {
+ return -1;
+ }
+
+ /* If not, then we must need to insert ourselves after the last
+ * entry */
+ new_entry->next = current_entry;
+ if (NULL == previous_entry) {
+ *queue = new_entry;
+ } else {
+ previous_entry->next = new_entry;
+ }
+ }
+ }
+
+done:
+ return 0;
+}
+
+static int import_merge_remove_input_queue(backend *be, import_merge_queue_entry **queue, import_merge_thang *thang,DBT *key,DBC **input_cursors, DB **input_files,int passes)
+{
+ import_merge_queue_entry *head = NULL;
+ int file_referenced = 0;
+ int i = 0;
+ int ret = 0;
+
+ PR_ASSERT(NULL != queue);
+ head = *queue;
+ if (head == NULL) {
+ /* Means we've exhausted the queue---we're done */
+ return EOF;
+ }
+ /* Remove the head of the queue */
+ *queue = head->next;
+ /* Get the IDL */
+ *thang = head->thang;
+ *key = head->key;
+ PR_ASSERT(NULL != thang);
+ /* Walk the list of referenced files, reading in the next IDL from each
+ * one to the queue */
+ for (i = 0 ; i < passes; i++) {
+ import_merge_thang new_thang = {0};
+ DBT new_key = {0};
+
+ file_referenced = (head->file_referenced_list)[i];
+ if (file_referenced) {
+ ret = import_merge_get_next_thang(be, input_cursors[i],
+ input_files[i], &new_thang, &new_key, thang->type);
+ if (0 != ret) {
+ if (EOF == ret) {
+ /* Means that we walked off the end of the list,
+ * do nothing */
+ ret = 0;
+ } else {
+ /* Some other error */
+ break;
+ }
+ } else {
+ /* This function is responsible for any freeing needed */
+ import_merge_insert_input_queue(be, queue, i, &new_key,
+ &new_thang, passes);
+ }
+ }
+ }
+ slapi_ch_free( (void**)&(head->file_referenced_list));
+ slapi_ch_free( (void**)&head);
+
+ return ret;
+}
+
+static int import_merge_open_input_cursors(DB**files, int passes, DBC ***cursors)
+{
+ int i = 0;
+ int ret = 0;
+ *cursors = (DBC**)slapi_ch_calloc(passes,sizeof(DBC*));
+ if (NULL == *cursors) {
+ return -1;
+ }
+
+ for (i = 0; i < passes; i++) {
+ DB *pDB = files[i];
+ DBC *pDBC = NULL;
+ if (NULL != pDB) {
+ /* Try to open a cursor onto the file */
+ ret = pDB->cursor(pDB,NULL,&pDBC,0);
+ if (0 != ret) {
+ break;
+ } else {
+ (*cursors)[i] = pDBC;
+ }
+ }
+ }
+
+ return ret;
+}
+
+static int import_count_merge_input_files(ldbm_instance *inst,
+ char *indexname, int passes, int *number_found, int *pass_number)
+{
+ int i = 0;
+ int found_one = 0;
+
+ *number_found = 0;
+ *pass_number = 0;
+
+ for (i = 0; i < passes; i++) {
+ int fd;
+ char *filename = NULL;
+ size_t filename_length = strlen(inst->inst_dir_name) + 1 +
+ strlen(indexname) + 10 ;
+
+ filename = slapi_ch_malloc(filename_length);
+ if (NULL == filename) {
+ return -1;
+ }
+ sprintf(filename, "%s/%s.%d%s", inst->inst_dir_name, indexname, i+1,
+ LDBM_FILENAME_SUFFIX);
+ fd = dblayer_open_huge_file(filename, O_RDONLY, 0);
+ slapi_ch_free( (void**)&filename);
+ if (fd >= 0) {
+ close(fd);
+ if (found_one == 0) {
+ *pass_number = i+1;
+ }
+ found_one = 1;
+ (*number_found)++;
+ } else {
+ ; /* Not finding a file is OK */
+ }
+ }
+
+ return 0;
+}
+
+static int import_open_merge_input_files(backend *be, char *indexname,
+ int passes, DB ***input_files, int *number_found, int *pass_number)
+{
+ int i = 0;
+ int ret = 0;
+ int found_one = 0;
+
+ *number_found = 0;
+ *pass_number = 0;
+ *input_files = (DB**)slapi_ch_calloc(passes,sizeof(DB*));
+ if (NULL == *input_files) {
+ /* Memory allocation error */
+ return -1;
+ }
+ for (i = 0; i < passes; i++) {
+ DB *pDB = NULL;
+ char *filename = NULL;
+ size_t filename_length = strlen(indexname) + 10 ;
+
+ filename = slapi_ch_malloc(filename_length);
+ if (NULL == filename) {
+ return -1;
+ }
+ sprintf(filename,"%s.%d", indexname, i+1);
+
+ if (vlv_isvlv(filename)) {
+ ret = dblayer_open_file(be, filename, 0, INDEX_VLV, &pDB);
+ } else {
+ ret = dblayer_open_file(be, filename, 0, 0, &pDB);
+ }
+
+ slapi_ch_free( (void**)&filename);
+ if (0 == ret) {
+ if (found_one == 0) {
+ *pass_number = i+1;
+ }
+ found_one = 1;
+ (*number_found)++;
+ (*input_files)[i] = pDB;
+ } else {
+ if (ENOENT == ret) {
+ ret = 0; /* Not finding a file is OK */
+ } else {
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/* Performs the n-way merge on one file */
+static int import_merge_one_file(ImportWorkerInfo *worker, int passes,
+ int *key_count)
+{
+ ldbm_instance *inst = worker->job->inst;
+ backend *be = inst->inst_be;
+ DB *output_file = NULL;
+ int ret = 0;
+ int preclose_ret = 0;
+ int number_found = 0;
+ int pass_number = 0;
+
+ PR_ASSERT(NULL != inst);
+
+ /* Try to open all the input files.
+ If we can't open file a file, we assume that is
+ because there was no data in it. */
+ ret = import_count_merge_input_files(inst, worker->index_info->name,
+ passes, &number_found, &pass_number);
+ if (0 != ret) {
+ goto error;
+ }
+ /* If there were no input files, then we're finished ! */
+ if (0 == number_found) {
+ ret = 0;
+ goto error;
+ }
+ /* Special-case where there's only one input file---just rename it */
+ if (1 == number_found) {
+ char *newname = NULL;
+ char *oldname = NULL;
+
+ ret = import_make_merge_filenames(inst->inst_dir_name,
+ worker->index_info->name, pass_number, &oldname, &newname);
+ if (0 != ret) {
+ import_log_notice(worker->job, "Failed making filename in merge");
+ goto error;
+ }
+ ret = PR_Rename(newname,oldname);
+ if (0 != ret) {
+ PRErrorCode prerr = PR_GetError();
+ import_log_notice(worker->job, "Failed to rename file \"%s\" to \"%s\" "
+ "in merge, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)",
+ oldname, newname, prerr, slapd_pr_strerror(prerr));
+ slapi_ch_free( (void**)&newname);
+ slapi_ch_free( (void**)&oldname);
+ goto error;
+ }
+ slapi_ch_free( (void**)&newname);
+ slapi_ch_free( (void**)&oldname);
+ *key_count = -1;
+ } else {
+ /* We really need to merge */
+ import_merge_queue_entry *merge_queue = NULL;
+ DB **input_files = NULL;
+ DBC **input_cursors = NULL;
+ DBT key = {0};
+ import_merge_thang thang = {0};
+ int i = 0;
+ int not_finished = 1;
+ int vlv_index = (INDEX_VLV == worker->index_info->ai->ai_indexmask);
+
+#if 0
+ /* Close and re-open regions, bugs otherwise */
+ ret = dblayer_close(inst->inst_li, DBLAYER_IMPORT_MODE);
+ if (0 != ret) {
+ if (ENOSPC == ret) {
+ import_log_notice(worker->job, "FAILED: NO DISK SPACE LEFT");
+ } else {
+ import_log_notice(worker->job, "MERGE FAIL 8 %d", ret);
+ }
+ return ret;
+ }
+ ret = dblayer_start(inst->inst_li, DBLAYER_IMPORT_MODE);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 9");
+ return ret;
+ }
+ ret = dblayer_instance_start(be, DBLAYER_IMPORT_MODE);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 9A");
+ return ret;
+ }
+#else
+ /* we have reason to believe that it's okay to leave the region files
+ * open in db3.x, since they track which files are opened and closed.
+ * if we had to close the region files, we'd have to take down the
+ * whole backend and defeat the purpose of an online import ---
+ * baaad medicine.
+ */
+ ret = dblayer_instance_close(be);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 8i %d\n", ret);
+ return ret;
+ }
+ ret = dblayer_instance_start(be, DBLAYER_IMPORT_MODE);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 8j %d\n", ret);
+ return ret;
+ }
+#endif
+
+ ret = import_open_merge_input_files(be, worker->index_info->name,
+ passes, &input_files, &number_found, &pass_number);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 10");
+ return ret;
+ }
+
+ ret = dblayer_open_file(be, worker->index_info->name, 1,
+ vlv_index ? INDEX_VLV : 0, &output_file);
+ if (0 != ret) {
+ import_log_notice(worker->job, "Failed to open output file for "
+ "index %s in merge", worker->index_info->name);
+ goto error;
+ }
+
+ /* OK, so we now have input and output files open and can proceed to
+ * merge */
+ /* We want to pre-fill the input IDL queue */
+ /* Open cursors onto the input files */
+ ret = import_merge_open_input_cursors(input_files, passes,
+ &input_cursors);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 2 %s %d",
+ worker->index_info->name, ret);
+ goto error;
+ }
+
+ /* Now read from the first location in each file and insert into the
+ * queue */
+ for (i = 0; i < passes; i++) if (input_files[i]) {
+ import_merge_thang prime_thang = {0};
+
+ /* Read an IDL from the file */
+ ret = import_merge_get_next_thang(be, input_cursors[i],
+ input_files[i], &prime_thang, &key,
+ vlv_index ? IMPORT_MERGE_THANG_VLV : IMPORT_MERGE_THANG_IDL);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 1 %s %d",
+ worker->index_info->name, ret);
+ goto error;
+ }
+ /* Put it on the queue */
+ ret = import_merge_insert_input_queue(be, &merge_queue, i,& key,
+ &prime_thang, passes);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 0 %s",
+ worker->index_info->name);
+ goto error;
+ }
+ }
+
+ /* We now have a pre-filled queue, so we may now proceed to remove the
+ head entry and write it to the output file, and repeat this process
+ until we've finished reading all the input data */
+ while (not_finished && (0 == ret) ) {
+ ret = import_merge_remove_input_queue(be, &merge_queue, &thang,
+ &key, input_cursors, input_files, passes);
+ if (0 != ret) {
+ /* Have we finished cleanly ? */
+ if (EOF == ret) {
+ not_finished = 0;
+ } else {
+ import_log_notice(worker->job, "MERGE FAIL 3 %s, %d",
+ worker->index_info->name, ret);
+ }
+ } else {
+ /* Write it out */
+ (*key_count)++;
+ if (vlv_index) {
+ /* Write the vlv index */
+ ret = output_file->put(output_file, NULL, &key,
+ &(thang.payload.vlv_data),0);
+ free(thang.payload.vlv_data.data);
+ thang.payload.vlv_data.data = NULL;
+ } else {
+ /* Write the IDL index */
+ ret = idl_store_block(be, output_file, &key,
+ thang.payload.idl, NULL, worker->index_info->ai);
+ /* Free the key we got back from the queue */
+ idl_free(thang.payload.idl);
+ thang.payload.idl = NULL;
+ }
+ free(key.data);
+ key.data = NULL;
+ if (0 != ret) {
+ /* Failed to write--- most obvious cause being out of
+ disk space, let's make sure that we at least print a
+ sensible error message right here. The caller should
+ really handle this properly, but we're always bad at
+ this. */
+ if (ret == DB_RUNRECOVERY || ret == ENOSPC) {
+ import_log_notice(worker->job, "OUT OF SPACE ON DISK, "
+ "failed writing index file %s",
+ worker->index_info->name);
+ } else {
+ import_log_notice(worker->job, "Failed to write "
+ "index file %s, errno=%d (%s)\n",
+ worker->index_info->name, errno,
+ dblayer_strerror(errno));
+ }
+ }
+ }
+ }
+ preclose_ret = ret;
+ /* Now close the files */
+ dblayer_close_file(output_file);
+ /* Close the cursors */
+ /* Close and delete the files */
+ for (i = 0; i < passes; i++) {
+ DBC *cursor = input_cursors[i];
+ DB *db = input_files[i];
+ if (NULL != db) {
+ PR_ASSERT(NULL != cursor);
+ ret = cursor->c_close(cursor);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 4");
+ }
+ ret = dblayer_close_file(db);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 5");
+ }
+ /* Now make the filename and delete the file */
+ {
+ char *newname = NULL;
+ char *oldname = NULL;
+ ret = import_make_merge_filenames(inst->inst_dir_name,
+ worker->index_info->name, i+1, &oldname, &newname);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 6");
+ } else {
+ ret = PR_Delete(newname);
+ if (0 != ret) {
+ import_log_notice(worker->job, "MERGE FAIL 7");
+ }
+ slapi_ch_free( (void**)&newname);
+ slapi_ch_free( (void**)&oldname);
+ }
+ }
+ }
+ }
+ if (preclose_ret != 0) ret = preclose_ret;
+ slapi_ch_free( (void**)&input_files);
+ slapi_ch_free( (void**)&input_cursors);
+ }
+ if (EOF == ret) {
+ ret = 0;
+ }
+
+error:
+ return ret;
+}
+
+/********** the real deal here: **********/
+
+/* Our mission here is as follows:
+ * for each index job except entrydn and id2entry:
+ * open all the pass files
+ * open a new output file
+ * iterate cursors over all of the input files picking each distinct
+ * key and combining the input IDLs into a merged IDL. Put that
+ * IDL to the output file.
+ */
+int import_mega_merge(ImportJob *job)
+{
+ ImportWorkerInfo *current_worker = NULL;
+ int ret = 0;
+ time_t beginning = 0;
+ time_t end = 0;
+ int passes = job->current_pass;
+
+ if (1 == job->number_indexers) {
+ import_log_notice(job, "Beginning %d-way merge of one file...", passes,
+ job->number_indexers);
+ } else {
+ import_log_notice(job, "Beginning %d-way merge of up to %lu files...",
+ passes, job->number_indexers);
+ }
+
+ time(&beginning);
+ /* Iterate over the files */
+ for (current_worker = job->worker_list;
+ (ret == 0) && (current_worker != NULL);
+ current_worker = current_worker->next) {
+ /* We need to ignore the primary index */
+ if ((current_worker->work_type != FOREMAN) &&
+ (current_worker->work_type != PRODUCER)) {
+ time_t file_beginning = 0;
+ time_t file_end = 0;
+ int key_count = 0;
+
+ time(&file_beginning);
+ ret = import_merge_one_file(current_worker,passes,&key_count);
+ time(&file_end);
+ if (key_count == 0) {
+ import_log_notice(job, "No files to merge for \"%s\".",
+ current_worker->index_info->name);
+ } else {
+ if (-1 == key_count) {
+ import_log_notice(job, "Merged \"%s\": Simple merge - "
+ "file renamed.",
+ current_worker->index_info->name);
+ } else {
+ import_log_notice(job, "Merged \"%s\": %d keys merged "
+ "in %ld seconds.",
+ current_worker->index_info->name,
+ key_count, file_end-file_beginning);
+ }
+ }
+ }
+ }
+
+ time(&end);
+ if (0 == ret) {
+ int seconds_to_merge = end - beginning;
+
+ import_log_notice(job, "Merging completed in %d seconds.",
+ seconds_to_merge);
+ }
+
+ return ret;
+}
diff --git a/ldap/servers/slapd/back-ldbm/import-threads.c b/ldap/servers/slapd/back-ldbm/import-threads.c
new file mode 100644
index 00000000..413eaca6
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/import-threads.c
@@ -0,0 +1,1992 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * the threads that make up an import:
+ * producer (1)
+ * foreman (1)
+ * worker (N: 1 for each index)
+ *
+ * a wire import (aka "fast replica" import) won't have a producer thread.
+ */
+
+#include "back-ldbm.h"
+#include "vlv_srch.h"
+#include "import.h"
+#ifdef XP_WIN32
+#define STDIN_FILENO 0
+#endif
+
+
+static struct backentry *import_make_backentry(Slapi_Entry *e, ID id)
+{
+ struct backentry *ep = backentry_alloc();
+
+ if (NULL != ep) {
+ ep->ep_entry = e;
+ ep->ep_id = id;
+ }
+ return ep;
+}
+
+static void import_decref_entry(struct backentry *ep)
+{
+ PR_AtomicDecrement(&(ep->ep_refcnt));
+ PR_ASSERT(ep->ep_refcnt >= 0);
+}
+
+/* generate uniqueid if requested */
+static void import_generate_uniqueid(ImportJob *job, Slapi_Entry *e)
+{
+ const char *uniqueid = slapi_entry_get_uniqueid(e);
+ int rc;
+
+ if (!uniqueid && (job->uuid_gen_type != SLAPI_UNIQUEID_GENERATE_NONE)) {
+ char *newuniqueid;
+
+ /* generate id based on dn */
+ if (job->uuid_gen_type == SLAPI_UNIQUEID_GENERATE_NAME_BASED) {
+ char *dn = slapi_entry_get_dn(e);
+
+ rc = slapi_uniqueIDGenerateFromNameString(&newuniqueid,
+ job->uuid_namespace, dn, strlen(dn));
+ } else {
+ /* time based */
+ rc = slapi_uniqueIDGenerateString(&newuniqueid);
+ }
+
+ if (rc == UID_SUCCESS) {
+ slapi_entry_set_uniqueid (e, newuniqueid);
+ } else {
+ char ebuf[BUFSIZ];
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "import_generate_uniqueid: failed to generate "
+ "uniqueid for %s; error=%d.\n",
+ escape_string(slapi_entry_get_dn_const(e), ebuf), rc, 0 );
+ }
+ }
+}
+
+
+/********** BETTER LDIF PARSER **********/
+
+
+/* like the function in libldif, except this one doesn't need to use
+ * FILE (which breaks on various platforms for >4G files or large numbers
+ * of open files)
+ */
+#define LDIF_BUFFER_SIZE 8192
+
+typedef struct {
+ char *b; /* buffer */
+ size_t size; /* how full the buffer is */
+ size_t offset; /* where the current entry starts */
+} ldif_context;
+
+static void import_init_ldif(ldif_context *c)
+{
+ c->size = c->offset = 0;
+ c->b = NULL;
+}
+
+static void import_free_ldif(ldif_context *c)
+{
+ if (c->b)
+ FREE(c->b);
+ import_init_ldif(c);
+}
+
+static char *import_get_entry(ldif_context *c, int fd, int *lineno)
+{
+ int ret;
+ int done = 0, got_lf = 0;
+ size_t bufSize = 0, bufOffset = 0, i;
+ char *buf = NULL;
+
+ while (!done) {
+
+ /* If there's no data in the buffer, get some */
+ if ((c->size == 0) || (c->offset == c->size)) {
+ /* Do we even have a buffer ? */
+ if (! c->b) {
+ c->b = slapi_ch_malloc(LDIF_BUFFER_SIZE);
+ if (! c->b)
+ return NULL;
+ }
+ ret = read(fd, c->b, LDIF_BUFFER_SIZE);
+ if (ret < 0) {
+ /* Must be error */
+ goto error;
+ } else if (ret == 0) {
+ /* eof */
+ if (buf) {
+ /* last entry */
+ buf[bufOffset] = 0;
+ return buf;
+ }
+ return NULL;
+ } else {
+ /* read completed OK */
+ c->size = ret;
+ c->offset = 0;
+ }
+ }
+
+ /* skip blank lines at start of entry */
+ if (bufOffset == 0) {
+ size_t n;
+ char *p;
+
+ for (n = c->offset, p = c->b + n; n < c->size; n++, p++) {
+ if (!(*p == '\r' || *p == '\n' || *p == ' '|| *p == '\t'))
+ break;
+ }
+ c->offset = n;
+ if (c->offset == c->size) continue;
+ }
+
+ i = c->offset;
+ while (!done && (i < c->size)) {
+ /* scan forward in the buffer, looking for the end of the entry */
+ while ((i < c->size) && (c->b[i] != '\n'))
+ i++;
+
+ if ((i < c->size) && (c->b[i] == '\n')) {
+ if (got_lf && ((i == 0) || ((i == 1) && (c->b[0] == '\r')))) {
+ /* saw an lf at the end of the last buffer */
+ i++, (*lineno)++;
+ done = 1;
+ got_lf = 0;
+ break;
+ }
+ got_lf = 0;
+ (*lineno)++;
+ /* is this the end? (need another linefeed) */
+ if (++i < c->size) {
+ if (c->b[i] == '\n') {
+ /* gotcha! */
+ i++, (*lineno)++;
+ done = 1;
+ } else if (c->b[i] == '\r') {
+ if (++i < c->size) {
+ if (c->b[i] == '\n') {
+ /* gotcha! (nt) */
+ i++, (*lineno)++;
+ done = 1;
+ }
+ } else {
+ got_lf = 1;
+ }
+ }
+ } else {
+ /* lf at the very end of the buffer */
+ got_lf = 1;
+ }
+ }
+ }
+
+ /* copy what we did so far into the output buffer */
+ /* (first, make sure the output buffer is large enough) */
+ if (bufSize - bufOffset < i - c->offset + 1) {
+ char *newbuf = NULL;
+ size_t newsize = (buf ? bufSize*2 : LDIF_BUFFER_SIZE);
+
+ newbuf = slapi_ch_malloc(newsize);
+ if (! newbuf)
+ goto error;
+ /* copy over the old data (if there was any) */
+ if (buf) {
+ memmove(newbuf, buf, bufOffset);
+ slapi_ch_free((void **)&buf);
+ }
+ buf = newbuf;
+ bufSize = newsize;
+ }
+ memmove(buf + bufOffset, c->b + c->offset, i - c->offset);
+ bufOffset += (i - c->offset);
+ c->offset = i;
+ }
+
+ /* add terminating NUL char */
+ buf[bufOffset] = 0;
+ return buf;
+
+error:
+ if (buf)
+ slapi_ch_free((void **)&buf);
+ return NULL;
+}
+
+
+/********** THREADS **********/
+
+/*
+ * Description:
+ * 1) return the ldif version #
+ * 2) replace "version: 1" with "#ersion: 1"
+ * to pretend like a comment for the str2entry
+ */
+static int
+import_get_version(char *str)
+{
+ char *s;
+ char *type;
+ char *valuecharptr;
+ char *mystr, *ms;
+ int offset;
+ int valuelen;
+ int my_version = 0;
+ int retmalloc = 0;
+
+ if ((s = strstr(str, "version:")) == NULL)
+ return 0;
+
+ offset = s - str;
+ mystr = ms = slapi_ch_strdup(str);
+ while ( (s = ldif_getline( &ms )) != NULL ) {
+ char *errmsg = NULL;
+ if ( (retmalloc = ldif_parse_line( s, &type, &valuecharptr, &valuelen, &errmsg )) >= 0 ) {
+ if (!strcasecmp(type, "version")) {
+ my_version = atoi(valuecharptr);
+ *(str + offset) = '#';
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (errmsg) slapi_ch_free((void **) &errmsg);
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ break;
+ }
+ } else if ( errmsg != NULL ) {
+ LDAPDebug( LDAP_DEBUG_PARSE, "%s", errmsg, 0, 0 );
+ }
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (errmsg) slapi_ch_free((void **) &errmsg);
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ }
+
+ slapi_ch_free((void **)&mystr);
+ return my_version;
+}
+
+/* producer thread:
+ * read through the given file list, parsing entries (str2entry), assigning
+ * them IDs and queueing them on the entry FIFO. other threads will do
+ * the indexing.
+ */
+void import_producer(void *param)
+{
+ ImportWorkerInfo *info = (ImportWorkerInfo *)param;
+ ImportJob *job = info->job;
+ ID id = job->first_ID, id_filestart = id;
+ Slapi_Entry *e = NULL;
+ struct backentry *ep = NULL, *old_ep = NULL;
+ ldbm_instance *inst = job->inst;
+ PRIntervalTime sleeptime;
+ char *estr = NULL;
+ int str2entry_flags =
+ SLAPI_STR2ENTRY_TOMBSTONE_CHECK |
+ SLAPI_STR2ENTRY_REMOVEDUPVALS |
+ SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES |
+ SLAPI_STR2ENTRY_ADDRDNVALS |
+ SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF;
+ int finished = 0;
+ int detected_eof = 0;
+ int fd, curr_file, curr_lineno;
+ char *curr_filename = NULL;
+ int idx;
+ ldif_context c;
+ int my_version = 0;
+ size_t newesize = 0;
+
+ PR_ASSERT(info != NULL);
+ PR_ASSERT(inst != NULL);
+
+ if ( job->flags & FLAG_ABORT ) {
+ goto error;
+ }
+
+ sleeptime = PR_MillisecondsToInterval(import_sleep_time);
+
+ /* pause until we're told to run */
+ while ((info->command == PAUSE) && !(job->flags & FLAG_ABORT)) {
+ info->state = WAITING;
+ DS_Sleep(sleeptime);
+ }
+ info->state = RUNNING;
+ import_init_ldif(&c);
+
+ /* jumpstart by opening the first file */
+ curr_file = 0;
+ fd = -1;
+ detected_eof = finished = 0;
+
+ /* we loop around reading the input files and processing each entry
+ * as we read it.
+ */
+ while (! finished) {
+ Slapi_Attr *attr = NULL;
+ int flags = 0;
+ int prev_lineno = 0;
+ int lines_in_entry = 0;
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ /* move on to next file? */
+ if (detected_eof) {
+ /* check if the file can still be read, whine if so... */
+ if (read(fd, (void *)&idx, 1) > 0) {
+ import_log_notice(job, "WARNING: Unexpected end of file found "
+ "at line %d of file \"%s\"", curr_lineno,
+ curr_filename);
+ }
+
+ if (fd == STDIN_FILENO) {
+ import_log_notice(job, "Finished scanning file stdin (%lu "
+ "entries)", (u_long)(id-id_filestart));
+ } else {
+ import_log_notice(job, "Finished scanning file \"%s\" (%lu "
+ "entries)", curr_filename, (u_long)(id-id_filestart));
+ }
+ close(fd);
+ fd = -1;
+ detected_eof = 0;
+ id_filestart = id;
+ curr_file++;
+ if (job->task) {
+ job->task->task_progress++;
+ slapi_task_status_changed(job->task);
+ }
+ if (job->input_filenames[curr_file] == NULL) {
+ /* done! */
+ finished = 1;
+ break;
+ }
+ }
+
+ /* separate from above, because this is also triggered when we
+ * start (to open the first file)
+ */
+ if (fd < 0) {
+ curr_lineno = 0;
+ curr_filename = job->input_filenames[curr_file];
+ if (strcmp(curr_filename, "-") == 0) {
+ fd = STDIN_FILENO;
+ } else {
+ int o_flag = O_RDONLY;
+#ifdef XP_WIN32
+ /* 613041 Somehow the windows low level io lose "\n"
+ at a very particular situation using O_TEXT mode read.
+ I think it is a windows bug for O_TEXT mode read.
+ Use O_BINARY instead, which honestly returns chars
+ without any translation.
+ */
+ o_flag |= O_BINARY;
+#endif
+ fd = dblayer_open_huge_file(curr_filename, o_flag, 0);
+ }
+ if (fd < 0) {
+ import_log_notice(job, "Could not open LDIF file \"%s\"",
+ curr_filename);
+ goto error;
+ }
+ if (fd == STDIN_FILENO) {
+ import_log_notice(job, "Processing file stdin");
+ } else {
+ import_log_notice(job, "Processing file \"%s\"", curr_filename);
+ }
+ }
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+
+ while ((info->command == PAUSE) && !(job->flags & FLAG_ABORT)){
+ info->state = WAITING;
+ DS_Sleep(sleeptime);
+ }
+ info->state = RUNNING;
+
+ prev_lineno = curr_lineno;
+ estr = import_get_entry(&c, fd, &curr_lineno);
+
+ lines_in_entry = curr_lineno - prev_lineno;
+ if (!estr) {
+ /* error reading entry, or end of file */
+ detected_eof = 1;
+ continue;
+ }
+
+ if (0 == my_version && strstr(estr, "version:")) {
+ my_version = import_get_version(estr);
+ str2entry_flags |= SLAPI_STR2ENTRY_INCLUDE_VERSION_STR;
+ }
+
+ /* If there are more than so many lines in the entry, we tell
+ * str2entry to optimize for a large entry.
+ */
+ if (lines_in_entry > STR2ENTRY_ATTRIBUTE_PRESENCE_CHECK_THRESHOLD) {
+ flags = str2entry_flags | SLAPI_STR2ENTRY_BIGENTRY;
+ } else {
+ flags = str2entry_flags;
+ }
+ e = slapi_str2entry(estr, flags);
+ FREE(estr);
+ if (! e) {
+ if (!(str2entry_flags & SLAPI_STR2ENTRY_INCLUDE_VERSION_STR))
+ import_log_notice(job, "WARNING: skipping bad LDIF entry "
+ "ending line %d of file \"%s\"", curr_lineno,
+ curr_filename);
+ continue;
+ }
+ if (0 == my_version) {
+ /* after the first entry version string won't be given */
+ my_version = -1;
+ }
+
+ if (! import_entry_belongs_here(e, inst->inst_be)) {
+ /* silently skip */
+ if (e) {
+ job->not_here_skipped++;
+ slapi_entry_free(e);
+ }
+ continue;
+ }
+
+ if (slapi_entry_schema_check(NULL, e) != 0) {
+ char ebuf[BUFSIZ];
+ import_log_notice(job, "WARNING: skipping entry \"%s\" which "
+ "violates schema, ending line %d of file "
+ "\"%s\"", escape_string(slapi_entry_get_dn(e), ebuf),
+ curr_lineno, curr_filename);
+ if (e)
+ slapi_entry_free(e);
+ job->skipped++;
+ continue;
+ }
+
+ /* generate uniqueid if necessary */
+ import_generate_uniqueid(job, e);
+
+ ep = import_make_backentry(e, id);
+ if (!ep)
+ goto error;
+
+ /* check for include/exclude subtree lists */
+ if (! ldbm_back_ok_to_dump(backentry_get_ndn(ep),
+ job->include_subtrees,
+ job->exclude_subtrees)) {
+ backentry_free(&ep);
+ continue;
+ }
+
+ /* not sure what this does, but it looked like it could be
+ * simplified. if it's broken, it's my fault. -robey
+ */
+ if (slapi_entry_attr_find(ep->ep_entry, "userpassword", &attr) == 0) {
+ Slapi_Value **va = attr_get_present_values(attr);
+
+ pw_encodevals( (Slapi_Value **)va ); /* jcm - cast away const */
+ }
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+
+ /* Now we have this new entry, all decoded
+ * Next thing we need to do is:
+ * (1) see if the appropriate fifo location contains an
+ * entry which had been processed by the indexers.
+ * If so, proceed.
+ * If not, spin waiting for it to become free.
+ * (2) free the old entry and store the new one there.
+ * (3) Update the job progress indicators so the indexers
+ * can use the new entry.
+ */
+ idx = id % job->fifo.size;
+ old_ep = job->fifo.item[idx].entry;
+ if (old_ep) {
+ /* for the slot to be recycled, it needs to be already absorbed
+ * by the foreman (id >= ready_ID), and all the workers need to
+ * be finished with it (refcount = 0).
+ */
+ while (((old_ep->ep_refcnt > 0) ||
+ (old_ep->ep_id >= job->ready_ID))
+ && (info->command != ABORT) && !(job->flags & FLAG_ABORT)) {
+ info->state = WAITING;
+ DS_Sleep(sleeptime);
+ }
+ if (job->flags & FLAG_ABORT){
+ goto error;
+ }
+ info->state = RUNNING;
+ PR_ASSERT(old_ep == job->fifo.item[idx].entry);
+ job->fifo.item[idx].entry = NULL;
+ if (job->fifo.c_bsize > job->fifo.item[idx].esize)
+ job->fifo.c_bsize -= job->fifo.item[idx].esize;
+ else
+ job->fifo.c_bsize = 0;
+ backentry_free(&old_ep);
+ }
+
+ newesize = (slapi_entry_size(ep->ep_entry) + sizeof(struct backentry));
+ if (newesize > job->fifo.bsize) { /* entry too big */
+ char ebuf[BUFSIZ];
+ import_log_notice(job, "WARNING: skipping entry \"%s\" "
+ "ending line %d of file \"%s\"",
+ escape_string(slapi_entry_get_dn(e), ebuf),
+ curr_lineno, curr_filename);
+ import_log_notice(job, "REASON: entry too large (%d bytes) for "
+ "the buffer size (%d bytes)", newesize, job->fifo.bsize);
+ backentry_free(&ep);
+ job->skipped++;
+ continue;
+ }
+ /* Now check if fifo has enough space for the new entry */
+ if ((job->fifo.c_bsize + newesize) > job->fifo.bsize) {
+ import_wait_for_space_in_fifo( job, newesize );
+ }
+
+ /* We have enough space */
+ job->fifo.item[idx].filename = curr_filename;
+ job->fifo.item[idx].line = curr_lineno;
+ job->fifo.item[idx].entry = ep;
+ job->fifo.item[idx].bad = 0;
+ job->fifo.item[idx].esize = newesize;
+
+ /* Add the entry size to total fifo size */
+ job->fifo.c_bsize += ep->ep_entry? job->fifo.item[idx].esize : 0;
+
+ /* Update the job to show our progress */
+ job->lead_ID = id;
+ if ((id - info->first_ID) <= job->fifo.size) {
+ job->trailing_ID = info->first_ID;
+ } else {
+ job->trailing_ID = id - job->fifo.size;
+ }
+
+ /* Update our progress meter too */
+ info->last_ID_processed = id;
+ id++;
+ if (job->flags & FLAG_ABORT){
+ goto error;
+ }
+ if (info->command == STOP) {
+ if (fd >= 0)
+ close(fd);
+ finished = 1;
+ }
+ }
+
+ import_free_ldif(&c);
+ info->state = FINISHED;
+ return;
+
+error:
+ info->state = ABORTED;
+}
+
+#if defined(UPGRADEDB)
+/* producer thread for re-indexing:
+ * read id2entry, parsing entries (str2entry) (needed???), assigning
+ * them IDs (again, needed???) and queueing them on the entry FIFO.
+ * other threads will do the indexing -- same as in import.
+ */
+void index_producer(void *param)
+{
+ ImportWorkerInfo *info = (ImportWorkerInfo *)param;
+ ImportJob *job = info->job;
+ ID id = job->first_ID;
+ Slapi_Entry *e = NULL;
+ struct backentry *ep = NULL, *old_ep = NULL;
+ ldbm_instance *inst = job->inst;
+ PRIntervalTime sleeptime;
+ int finished = 0;
+ int idx;
+
+ /* vars for Berkeley DB */
+ DB_ENV *env = NULL;
+ DB *db = NULL;
+ DBC *dbc = NULL;
+ DBT key = {0};
+ DBT data = {0};
+ int db_rval = -1;
+ backend *be = inst->inst_be;
+ int isfirst = 1;
+ int curr_entry = 0;
+ size_t newesize = 0;
+
+ PR_ASSERT(info != NULL);
+ PR_ASSERT(inst != NULL);
+ PR_ASSERT(be != NULL);
+
+ if ( job->flags & FLAG_ABORT )
+ goto error;
+
+ sleeptime = PR_MillisecondsToInterval(import_sleep_time);
+
+ /* pause until we're told to run */
+ while ((info->command == PAUSE) && !(job->flags & FLAG_ABORT)) {
+ info->state = WAITING;
+ DS_Sleep(sleeptime);
+ }
+ info->state = RUNNING;
+
+ /* open id2entry with dedicated db env and db handler */
+ if ( dblayer_get_aux_id2entry( be, &db, &env ) != 0 || db == NULL ||
+ env == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Could not open id2entry\n", 0, 0, 0 );
+ goto error;
+ }
+
+ /* get a cursor to we can walk over the table */
+ db_rval = db->cursor(db, NULL, &dbc, 0);
+ if ( 0 != db_rval ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Failed to get cursor for reindexing\n", 0, 0, 0 );
+ dblayer_release_id2entry(be, db);
+ goto error;
+ }
+
+ /* we loop around reading the input files and processing each entry
+ * as we read it.
+ */
+ finished = 0;
+ while (!finished) {
+ Slapi_Attr *attr = NULL;
+ ID temp_id;
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+ while ((info->command == PAUSE) && !(job->flags & FLAG_ABORT)){
+ info->state = WAITING;
+ DS_Sleep(sleeptime);
+ }
+ info->state = RUNNING;
+
+ key.flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ if (isfirst)
+ {
+ db_rval = dbc->c_get(dbc, &key, &data, DB_FIRST);
+ isfirst = 0;
+ }
+ else
+ {
+ db_rval = dbc->c_get(dbc, &key, &data, DB_NEXT);
+ }
+
+ if (0 != db_rval) {
+ if (DB_NOTFOUND != db_rval) {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: Failed to read database, "
+ "errno=%d (%s)\n", inst->inst_name, db_rval,
+ dblayer_strerror(db_rval));
+ if (job->task) {
+ slapi_task_log_notice(job->task,
+ "%s: Failed to read database, err %d (%s)",
+ inst->inst_name, db_rval,
+ dblayer_strerror(db_rval));
+ }
+ }
+ break;
+ }
+ curr_entry++;
+ temp_id = id_stored_to_internal((char *)key.data);
+ free(key.data);
+
+ /* call post-entry plugin */
+ plugin_call_entryfetch_plugins((char **) &data.dptr, &data.dsize);
+ e = slapi_str2entry(data.data, 0);
+ if ( NULL == e ) {
+ if (job->task) {
+ slapi_task_log_notice(job->task,
+ "%s: WARNING: skipping badly formatted entry (id %lu)",
+ inst->inst_name, (u_long)temp_id);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: WARNING: skipping badly formatted entry (id %lu)\n",
+ inst->inst_name, (u_long)temp_id, 0);
+ continue;
+ }
+ free(data.data);
+
+ /* generate uniqueid if necessary */
+ import_generate_uniqueid(job, e);
+
+ ep = import_make_backentry(e, temp_id);
+ if (!ep)
+ goto error;
+
+ /* not sure what this does, but it looked like it could be
+ * simplified. if it's broken, it's my fault. -robey
+ */
+ if (slapi_entry_attr_find(ep->ep_entry, "userpassword", &attr) == 0) {
+ Slapi_Value **va = attr_get_present_values(attr);
+
+ pw_encodevals( (Slapi_Value **)va ); /* jcm - cast away const */
+ }
+
+ if (job->flags & FLAG_ABORT)
+ goto error;
+
+ /* Now we have this new entry, all decoded
+ * Next thing we need to do is:
+ * (1) see if the appropriate fifo location contains an
+ * entry which had been processed by the indexers.
+ * If so, proceed.
+ * If not, spin waiting for it to become free.
+ * (2) free the old entry and store the new one there.
+ * (3) Update the job progress indicators so the indexers
+ * can use the new entry.
+ */
+ idx = id % job->fifo.size;
+ old_ep = job->fifo.item[idx].entry;
+ if (old_ep) {
+ /* for the slot to be recycled, it needs to be already absorbed
+ * by the foreman (id >= ready_ID), and all the workers need to
+ * be finished with it (refcount = 0).
+ */
+ while (((old_ep->ep_refcnt > 0) ||
+ (old_ep->ep_id >= job->ready_ID))
+ && (info->command != ABORT) && !(job->flags & FLAG_ABORT)) {
+ info->state = WAITING;
+ DS_Sleep(sleeptime);
+ }
+ if (job->flags & FLAG_ABORT)
+ goto error;
+
+ info->state = RUNNING;
+ PR_ASSERT(old_ep == job->fifo.item[idx].entry);
+ job->fifo.item[idx].entry = NULL;
+ if (job->fifo.c_bsize > job->fifo.item[idx].esize)
+ job->fifo.c_bsize -= job->fifo.item[idx].esize;
+ else
+ job->fifo.c_bsize = 0;
+ backentry_free(&old_ep);
+ }
+
+ newesize = (slapi_entry_size(ep->ep_entry) + sizeof(struct backentry));
+ if (newesize > job->fifo.bsize) { /* entry too big */
+ char ebuf[BUFSIZ];
+ import_log_notice(job, "WARNING: skipping entry \"%s\"",
+ escape_string(slapi_entry_get_dn(e), ebuf));
+ import_log_notice(job, "REASON: entry too large (%d bytes) for "
+ "the buffer size (%d bytes)", newesize, job->fifo.bsize);
+ backentry_free(&ep);
+ job->skipped++;
+ continue;
+ }
+ /* Now check if fifo has enough space for the new entry */
+ if ((job->fifo.c_bsize + newesize) > job->fifo.bsize) {
+ import_wait_for_space_in_fifo( job, newesize );
+ }
+
+ /* We have enough space */
+ job->fifo.item[idx].filename = ID2ENTRY LDBM_FILENAME_SUFFIX;
+ job->fifo.item[idx].line = curr_entry;
+ job->fifo.item[idx].entry = ep;
+ job->fifo.item[idx].bad = 0;
+ job->fifo.item[idx].esize = newesize;
+
+ /* Add the entry size to total fifo size */
+ job->fifo.c_bsize += ep->ep_entry? job->fifo.item[idx].esize : 0;
+
+ /* Update the job to show our progress */
+ job->lead_ID = id;
+ if ((id - info->first_ID) <= job->fifo.size) {
+ job->trailing_ID = info->first_ID;
+ } else {
+ job->trailing_ID = id - job->fifo.size;
+ }
+
+ /* Update our progress meter too */
+ info->last_ID_processed = id;
+ id++;
+ if (job->flags & FLAG_ABORT)
+ goto error;
+ if (info->command == STOP)
+ {
+ finished = 1;
+ }
+ }
+
+ dbc->c_close(dbc);
+ dblayer_release_aux_id2entry( be, db, env );
+ info->state = FINISHED;
+ return;
+
+error:
+ dbc->c_close(dbc);
+ dblayer_release_aux_id2entry( be, db, env );
+ info->state = ABORTED;
+}
+#endif
+
+static void
+import_wait_for_space_in_fifo(ImportJob *job, size_t new_esize)
+{
+ struct backentry *temp_ep = NULL;
+ size_t i;
+ int slot_found;
+ PRIntervalTime sleeptime;
+
+ sleeptime = PR_MillisecondsToInterval(import_sleep_time);
+
+ /* Now check if fifo has enough space for the new entry */
+ while ((job->fifo.c_bsize + new_esize) > job->fifo.bsize) {
+ for ( i = 0, slot_found = 0 ; i < job->fifo.size ; i++ ) {
+ temp_ep = job->fifo.item[i].entry;
+ if (temp_ep) {
+ if (temp_ep->ep_refcnt == 0 && temp_ep->ep_id < job->ready_ID) {
+ job->fifo.item[i].entry = NULL;
+ if (job->fifo.c_bsize > job->fifo.item[i].esize)
+ job->fifo.c_bsize -= job->fifo.item[i].esize;
+ else
+ job->fifo.c_bsize = 0;
+ backentry_free(&temp_ep);
+ slot_found = 1;
+ }
+ }
+ }
+ if ( slot_found == 0 )
+ DS_Sleep(sleeptime);
+ }
+}
+
+/* helper function for the foreman: */
+static int foreman_do_parentid(ImportJob *job, struct backentry *entry,
+ struct attrinfo *parentid_ai)
+{
+ backend *be = job->inst->inst_be;
+ Slapi_Value **svals = NULL;
+ Slapi_Attr *attr = NULL;
+ int idl_disposition = 0;
+ int ret = 0;
+
+ if (slapi_entry_attr_find(entry->ep_entry, "parentid", &attr) == 0) {
+ svals = attr_get_present_values(attr);
+ ret = index_addordel_values_ext_sv(be, "parentid", svals, NULL, entry->ep_id,
+ BE_INDEX_ADD, NULL, &idl_disposition, NULL);
+ if (idl_disposition != IDL_INSERT_NORMAL) {
+ char *attr_value = slapi_value_get_berval(svals[0])->bv_val;
+ ID parent_id = atol(attr_value);
+
+ if (idl_disposition == IDL_INSERT_NOW_ALLIDS) {
+ import_subcount_mother_init(job->mothers, parent_id,
+ idl_get_allidslimit(parentid_ai)+1);
+ } else if (idl_disposition == IDL_INSERT_ALLIDS) {
+ import_subcount_mother_count(job->mothers, parent_id);
+ }
+ }
+ if (ret != 0) {
+ import_log_notice(job, "ERROR: Can't update parentid index "
+ "(error %d)", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/* helper function for the foreman: */
+static int foreman_do_entrydn(ImportJob *job, FifoItem *fi)
+{
+ backend *be = job->inst->inst_be;
+ struct berval bv;
+ int err = 0, ret = 0;
+ IDList *IDL;
+
+ /* insert into the entrydn index */
+ bv.bv_val = (void*)backentry_get_ndn(fi->entry); /* jcm - Had to cast away const */
+ bv.bv_len = strlen(backentry_get_ndn(fi->entry));
+
+ /* We need to check here whether the DN is already present in
+ * the entrydn index. If it is then the input ldif
+ * contained a duplicate entry, which it isn't allowed to */
+ /* Due to popular demand, we only warn on this, given the
+ * tendency for customers to want to import dirty data */
+ /* So, we do an index read first */
+ err = 0;
+ IDL = index_read(be, "entrydn", indextype_EQUALITY, &bv, NULL, &err);
+
+ /* Did this work ? */
+ if (NULL != IDL) {
+ /* IMPOSTER ! Get thee hence... */
+ import_log_notice(job, "WARNING: Skipping duplicate entry "
+ "\"%s\" found at line %d of file \"%s\"",
+ slapi_entry_get_dn(fi->entry->ep_entry),
+ fi->line, fi->filename);
+ idl_free(IDL);
+ /* skip this one */
+ fi->bad = 1;
+ job->skipped++;
+ return -1; /* skip to next entry */
+ }
+ if ((ret = index_addordel_string(be, "entrydn",
+ bv.bv_val,
+ fi->entry->ep_id,
+ BE_INDEX_ADD, NULL)) != 0) {
+ import_log_notice(job, "Error writing entrydn index "
+ "(error %d: %s)",
+ ret, dblayer_strerror(ret));
+ return ret;
+ }
+ return 0;
+}
+
+/* foreman thread:
+ * i go through the FIFO just like the other worker threads, but i'm
+ * responsible for the interrelated indexes: entrydn, id2entry, and the
+ * operational attributes (plus the parentid index).
+ */
+void import_foreman(void *param)
+{
+ ImportWorkerInfo *info = (ImportWorkerInfo *)param;
+ ImportJob *job = info->job;
+ ldbm_instance *inst = job->inst;
+ backend *be = inst->inst_be;
+ PRIntervalTime sleeptime;
+ int finished = 0;
+ ID id = info->first_ID;
+ int ret = 0;
+ struct attrinfo *parentid_ai;
+ Slapi_PBlock *pb = slapi_pblock_new();
+
+ PR_ASSERT(info != NULL);
+ PR_ASSERT(inst != NULL);
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ /* the pblock is used only by add_op_attrs */
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ sleeptime = PR_MillisecondsToInterval(import_sleep_time);
+ info->state = RUNNING;
+
+ ainfo_get(be, "parentid", &parentid_ai);
+
+ while (! finished) {
+ FifoItem *fi = NULL;
+ int parent_status = 0;
+
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ while ( ((info->command == PAUSE) || (id > job->lead_ID)) &&
+ (info->command != STOP) && (info->command != ABORT) && !(job->flags & FLAG_ABORT)) {
+ /* Check to see if we've been told to stop */
+ info->state = WAITING;
+ DS_Sleep(sleeptime);
+ }
+ if (info->command == STOP) {
+ finished = 1;
+ continue;
+ }
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ info->state = RUNNING;
+
+ /* Read that entry from the cache */
+ fi = import_fifo_fetch(job, id, 0);
+ if (! fi) {
+ import_log_notice(job, "ERROR: foreman fifo error");
+ goto error;
+ }
+
+ /* first, fill in any operational attributes */
+ /* add_op_attrs wants a pblock for some reason. */
+ if (add_op_attrs(pb, inst->inst_li, fi->entry, &parent_status) != 0) {
+ import_log_notice(job, "ERROR: Could not add op attrs to "
+ "entry ending at line %d of file \"%s\"",
+ fi->line, fi->filename);
+ goto error;
+ }
+
+ if (! slapi_entry_flag_is_set(fi->entry->ep_entry,
+ SLAPI_ENTRY_FLAG_TOMBSTONE)) {
+ /*
+ * Only check for a parent and add to the entry2dn index if
+ * the entry is not a tombstone.
+ */
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ if (parent_status == IMPORT_ADD_OP_ATTRS_NO_PARENT) {
+ /* If this entry is a suffix entry, this is not a problem */
+ /* However, if it is not, this is an error---it means that
+ * someone tried to import an entry before importing its parent
+ * we reject the entry but carry on since we've not stored
+ * anything related to this entry.
+ */
+ if (! slapi_be_issuffix(inst->inst_be, backentry_get_sdn(fi->entry))) {
+ import_log_notice(job, "WARNING: Skipping entry \"%s\" "
+ "which has no parent, ending at line %d "
+ "of file \"%s\"",
+ slapi_entry_get_dn(fi->entry->ep_entry),
+ fi->line, fi->filename);
+ /* skip this one */
+ fi->bad = 1;
+ job->skipped++;
+ goto cont; /* below */
+ }
+ }
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+
+ /* insert into the entrydn index */
+ ret = foreman_do_entrydn(job, fi);
+ if (ret == -1)
+ goto cont; /* skip entry */
+ if (ret != 0)
+ goto error;
+ }
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+#if defined (UPGRADEDB)
+ if (!(job->flags & FLAG_REINDEXING))/* reindex reads data from id2entry */
+#endif
+ {
+ /* insert into the id2entry index
+ * (that isn't really an index -- it's the storehouse of the entries
+ * themselves.)
+ */
+ if ((ret = id2entry_add_ext(be, fi->entry, NULL, job->encrypt)) != 0) {
+ /* DB_RUNRECOVERY usually occurs if disk fills */
+ if (LDBM_OS_ERR_IS_DISKFULL(ret)) {
+ import_log_notice(job, "ERROR: OUT OF SPACE ON DISK or FILE TOO LARGE -- "
+ "Could not store the entry ending at line "
+ "%d of file \"%s\"",
+ fi->line, fi->filename);
+ } else if (ret == DB_RUNRECOVERY) {
+ import_log_notice(job, "FATAL ERROR: (LARGEFILE SUPPORT NOT ENABLED? OUT OF SPACE ON DISK?) -- "
+ "Could not store the entry ending at line "
+ "%d of file \"%s\"",
+ fi->line, fi->filename);
+ } else {
+ import_log_notice(job, "ERROR: Could not store the entry "
+ "ending at line %d of file \"%s\" -- "
+ "error %d", fi->line, fi->filename, ret);
+ }
+ goto error;
+ }
+ }
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ if (! slapi_entry_flag_is_set(fi->entry->ep_entry,
+ SLAPI_ENTRY_FLAG_TOMBSTONE)) {
+ /* parentid index
+ * (we have to do this here, because the parentID is dependent on
+ * looking up by entrydn.)
+ * Only add to the parent index if the entry is not a tombstone.
+ */
+ ret = foreman_do_parentid(job, fi->entry, parentid_ai);
+ if (ret != 0)
+ goto error;
+
+ /* Lastly, before we're finished with the entry, pass it to the
+ vlv code to see whether it's within the scope a VLV index. */
+ vlv_grok_new_import_entry(fi->entry, be);
+ }
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+
+ /* Remove the entry from the cache (caused by id2entry_add) */
+#if defined (UPGRADEDB)
+ if (!(job->flags & FLAG_REINDEXING))/* reindex reads data from id2entry */
+#endif
+ cache_remove(&inst->inst_cache, fi->entry);
+ fi->entry->ep_refcnt = job->number_indexers;
+
+ cont:
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ job->ready_ID = id;
+ info->last_ID_processed = id;
+ id++;
+
+ if (job->flags & FLAG_ABORT){
+ goto error;
+ }
+ }
+
+ slapi_pblock_destroy(pb);
+ info->state = FINISHED;
+ return;
+
+error:
+ slapi_pblock_destroy(pb);
+ info->state = ABORTED;
+}
+
+
+/* worker thread:
+ * given an attribute, this worker plows through the entry FIFO, building
+ * up the attribute index.
+ */
+void import_worker(void *param)
+{
+ ImportWorkerInfo *info = (ImportWorkerInfo *)param;
+ ImportJob *job = info->job;
+ ldbm_instance *inst = job->inst;
+ backend *be = inst->inst_be;
+ PRIntervalTime sleeptime;
+ int finished = 0;
+ ID id = info->first_ID;
+ int ret = 0;
+ int idl_disposition = 0;
+ struct vlvIndex* vlv_index = NULL;
+ void *substring_key_buffer = NULL;
+ FifoItem *fi;
+ int is_objectclass_attribute;
+ int is_nsuniqueid_attribute;
+ void *attrlist_cursor;
+
+ PR_ASSERT(NULL != info);
+ PR_ASSERT(NULL != inst);
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ if (INDEX_VLV == info->index_info->ai->ai_indexmask) {
+ vlv_index = vlv_find_indexname(info->index_info->name, be);
+ if (NULL == vlv_index) {
+ goto error;
+ }
+ }
+
+ /*
+ * If the entry is a Tombstone, then we only add it to the nsuniqeid index
+ * and the idlist for (objectclass=tombstone). These two flags are just
+ * handy for working out what to do in this case.
+ */
+ is_objectclass_attribute =
+ (strcasecmp(info->index_info->name, "objectclass") == 0);
+ is_nsuniqueid_attribute =
+ (strcasecmp(info->index_info->name, SLAPI_ATTR_UNIQUEID) == 0);
+
+ if (1 != idl_get_idl_new()) {
+ /* Is there substring indexing going on here ? */
+ if ( (INDEX_SUB & info->index_info->ai->ai_indexmask) &&
+ (info->index_buffer_size > 0) ) {
+ /* Then make a key buffer thing */
+ ret = index_buffer_init(info->index_buffer_size, 0,
+ &substring_key_buffer);
+ if (0 != ret) {
+ import_log_notice(job, "IMPORT FAIL 1 (error %d)", ret);
+ }
+ }
+ }
+
+ sleeptime = PR_MillisecondsToInterval(import_sleep_time);
+ info->state = RUNNING;
+ info->last_ID_processed = id-1;
+
+ while (! finished) {
+ struct backentry *ep = NULL;
+ Slapi_Value **svals = NULL;
+ Slapi_Attr *attr = NULL;
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ /* entry can be NULL if it turned out to be bogus */
+ while (!finished && !ep) {
+ /* This worker thread must wait if the command flag is "PAUSE" or
+ * the entry corresponds to the current entry treated by the foreman
+ * thread, and the state is neither STOP nor ABORT
+ */
+ while (((info->command == PAUSE) || (id > job->ready_ID)) &&
+ (info->command != STOP) && (info->command != ABORT) && !(job->flags & FLAG_ABORT)) {
+ /* Check to see if we've been told to stop */
+ info->state = WAITING;
+ DS_Sleep(sleeptime);
+ }
+
+ if (info->command == STOP) {
+ finished = 1;
+ continue;
+ }
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ info->state = RUNNING;
+
+ /* Read that entry from the cache */
+ fi = import_fifo_fetch(job, id, 1);
+ ep = fi ? fi->entry : NULL;
+ if (!ep) {
+ /* skipping an entry that turned out to be bad */
+ info->last_ID_processed = id;
+ id++;
+ }
+ }
+ if (finished)
+ continue;
+
+ if (! slapi_entry_flag_is_set(fi->entry->ep_entry,
+ SLAPI_ENTRY_FLAG_TOMBSTONE)) {
+ /* This is not a tombstone entry. */
+ /* Is this a VLV index ? */
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+ if (INDEX_VLV == info->index_info->ai->ai_indexmask) {
+ /* Yes, call VLV code -- needs pblock to find backend */
+ Slapi_PBlock *pb = slapi_pblock_new();
+
+ PR_ASSERT(NULL != vlv_index);
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ vlv_update_index(vlv_index, NULL, inst->inst_li, pb, NULL, ep);
+ slapi_pblock_destroy(pb);
+ } else {
+ /* No, process regular index */
+ /* Look for the attribute we're indexing and its subtypes */
+ /* For each attr write to the index */
+ attrlist_cursor = NULL;
+ while ((attr = attrlist_find_ex(ep->ep_entry->e_attrs,
+ info->index_info->name,
+ NULL,
+ NULL,
+ &attrlist_cursor)) != NULL) {
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+ if(valueset_isempty(&(attr->a_present_values))) continue;
+ svals = attr_get_present_values(attr);
+ ret = index_addordel_values_ext_sv(be, info->index_info->name,
+ svals, NULL, ep->ep_id, BE_INDEX_ADD | (job->encrypt ? 0 : BE_INDEX_DONT_ENCRYPT), NULL, &idl_disposition,
+ substring_key_buffer);
+
+ if (0 != ret) {
+ /* Something went wrong, eg disk filled up */
+ goto error;
+ }
+ }
+ }
+ } else {
+ /* This is a Tombstone entry... we only add it to the nsuniqeid
+ * index and the idlist for (objectclass=nstombstone).
+ */
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+ if (is_nsuniqueid_attribute) {
+ ret = index_addordel_string(be, SLAPI_ATTR_UNIQUEID,
+ slapi_entry_get_uniqueid(ep->ep_entry), ep->ep_id,
+ BE_INDEX_ADD, NULL);
+ if (0 != ret) {
+ /* Something went wrong, eg disk filled up */
+ goto error;
+ }
+ }
+ if (is_objectclass_attribute) {
+ ret = index_addordel_string(be, SLAPI_ATTR_OBJECTCLASS,
+ SLAPI_ATTR_VALUE_TOMBSTONE, ep->ep_id, BE_INDEX_ADD, NULL);
+ if (0 != ret) {
+ /* Something went wrong, eg disk filled up */
+ goto error;
+ }
+ }
+ }
+ import_decref_entry(ep);
+ info->last_ID_processed = id;
+ id++;
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+ }
+
+ if (job->flags & FLAG_ABORT) {
+ goto error;
+ }
+
+
+ /* If we were buffering index keys, now flush them */
+ if (substring_key_buffer) {
+ ret = index_buffer_flush(substring_key_buffer,
+ inst->inst_be, NULL,
+ info->index_info->ai);
+ if (0 != ret) {
+ goto error;
+ }
+ index_buffer_terminate(substring_key_buffer);
+ }
+ info->state = FINISHED;
+ return;
+
+error:
+ if (ret == DB_RUNRECOVERY) {
+ LDAPDebug(LDAP_DEBUG_ANY,"cannot import; database recovery needed\n",
+ 0,0,0);
+ } else if (ret == DB_LOCK_DEADLOCK) {
+ /* can this occur? */
+ }
+
+ info->state = ABORTED;
+}
+
+
+
+/*
+ * import entries to a backend, over the wire -- entries will arrive
+ * asynchronously, so this method has no "producer" thread. instead, the
+ * front-end drops new entries in as they arrive.
+ *
+ * this is sometimes called "fast replica initialization".
+ *
+ * some of this code is duplicated from ldif2ldbm, but i don't think we
+ * can avoid it.
+ */
+static int bulk_import_start(Slapi_PBlock *pb)
+{
+ struct ldbminfo *li = NULL;
+ ImportJob *job = NULL;
+ backend *be = NULL;
+ PRThread *thread = NULL;
+ int ret = 0;
+
+ job = CALLOC(ImportJob);
+ if (job == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "not enough memory to do import job\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+ PR_ASSERT(be != NULL);
+ li = (struct ldbminfo *)(be->be_database->plg_private);
+ job->inst = (ldbm_instance *)be->be_instance_info;
+
+ /* check if an import/restore is already ongoing... */
+ PR_Lock(job->inst->inst_config_mutex);
+ if (job->inst->inst_flags & INST_FLAG_BUSY) {
+ PR_Unlock(job->inst->inst_config_mutex);
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: '%s' is already in the middle of "
+ "another task and cannot be disturbed.\n",
+ job->inst->inst_name, 0, 0);
+ FREE(job);
+ return SLAPI_BI_ERR_BUSY;
+ }
+ job->inst->inst_flags |= INST_FLAG_BUSY;
+ PR_Unlock(job->inst->inst_config_mutex);
+
+ /* take backend offline */
+ slapi_mtn_be_disable(be);
+
+ /* get uniqueid info */
+ slapi_pblock_get(pb, SLAPI_LDIF2DB_GENERATE_UNIQUEID, &job->uuid_gen_type);
+ if (job->uuid_gen_type == SLAPI_UNIQUEID_GENERATE_NAME_BASED) {
+ char *namespaceid;
+
+ slapi_pblock_get(pb, SLAPI_LDIF2DB_NAMESPACEID, &namespaceid);
+ job->uuid_namespace = slapi_ch_strdup(namespaceid);
+ }
+
+ job->flags = 0; /* don't use files */
+ job->flags |= FLAG_INDEX_ATTRS;
+ job->flags |= FLAG_ONLINE;
+ job->starting_ID = 1;
+ job->first_ID = 1;
+
+ job->mothers = CALLOC(import_subcount_stuff);
+ /* how much space should we allocate to index buffering? */
+ job->job_index_buffer_size = import_get_index_buffer_size();
+ if (job->job_index_buffer_size == 0) {
+ /* 10% of the allocated cache size + one meg */
+ job->job_index_buffer_size = (job->inst->inst_li->li_dbcachesize/10) +
+ (1024*1024);
+ }
+ import_subcount_stuff_init(job->mothers);
+ job->wire_lock = PR_NewLock();
+ job->wire_cv = PR_NewCondVar(job->wire_lock);
+
+ /* COPIED from ldif2ldbm.c : */
+
+ /* shutdown this instance of the db */
+ cache_clear(&job->inst->inst_cache);
+ dblayer_instance_close(be);
+
+ /* Delete old database files */
+ dblayer_delete_instance_dir(be);
+ /* it's okay to fail -- it might already be gone */
+
+ /* dblayer_instance_start will init the id2entry index. */
+ /* it also (finally) fills in inst_dir_name */
+ ret = dblayer_instance_start(be, DBLAYER_IMPORT_MODE);
+ if (ret != 0)
+ goto fail;
+
+ /* END OF COPIED SECTION */
+
+ PR_Lock(job->wire_lock);
+ vlv_init(job->inst);
+
+ /* create thread for import_main, so we can return */
+ thread = PR_CreateThread(PR_USER_THREAD, import_main, (void *)job,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to spawn import thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ PR_Unlock(job->wire_lock);
+ ret = -2;
+ goto fail;
+ }
+
+ job->main_thread = thread;
+ slapi_set_object_extension(li->li_bulk_import_object, pb->pb_conn,
+ li->li_bulk_import_handle, job);
+
+ /* wait for the import_main to signal that it's ready for entries */
+ /* (don't want to send the success code back to the LDAP client until
+ * we're ready for the adds to start rolling in)
+ */
+ PR_WaitCondVar(job->wire_cv, PR_INTERVAL_NO_TIMEOUT);
+ PR_Unlock(job->wire_lock);
+
+ return 0;
+
+fail:
+ PR_Lock(job->inst->inst_config_mutex);
+ job->inst->inst_flags &= ~INST_FLAG_BUSY;
+ PR_Unlock(job->inst->inst_config_mutex);
+ import_free_job(job);
+ FREE(job);
+ return ret;
+}
+
+/* returns 0 on success, or < 0 on error
+ *
+ * on error, the import process is aborted -- so if this returns an error,
+ * don't try to queue any more entries or you'll be sorry.
+ *
+ * flag_block in used to know if this thread should block when
+ * the fifo is full or return an error LDAP_BUSY
+ * Typically, import done on from the GUI or the command line will
+ * block while online import as used by the replication total update
+ * will not block
+ */
+static int bulk_import_queue(ImportJob *job, Slapi_Entry *entry, int flag_block)
+{
+ struct backentry *ep = NULL, *old_ep = NULL;
+ int idx;
+ ID id = job->lead_ID + 1;
+ Slapi_Attr *attr = NULL;
+ size_t newesize = 0;
+
+ PR_Lock(job->wire_lock);
+
+ /* generate uniqueid if necessary */
+ import_generate_uniqueid(job, entry);
+
+ /* make into backentry */
+ ep = import_make_backentry(entry, id);
+ if (!ep) {
+ import_abort_all(job, 1);
+ PR_Unlock(job->wire_lock);
+ return -1;
+ }
+
+ /* encode the password */
+ if (slapi_entry_attr_find(ep->ep_entry, "userpassword", &attr) == 0) {
+ Slapi_Value **va = attr_get_present_values(attr);
+
+ pw_encodevals( (Slapi_Value **)va ); /* jcm - had to cast away const */
+ }
+
+ /* Now we have this new entry, all decoded
+ * Next thing we need to do is:
+ * (1) see if the appropriate fifo location contains an
+ * entry which had been processed by the indexers.
+ * If so, proceed.
+ * If not, spin waiting for it to become free.
+ * (2) free the old entry and store the new one there.
+ * (3) Update the job progress indicators so the indexers
+ * can use the new entry.
+ */
+ idx = id % job->fifo.size;
+ old_ep = job->fifo.item[idx].entry;
+ if (old_ep) {
+ while ((old_ep->ep_refcnt > 0) && !(job->flags & FLAG_ABORT))
+ {
+ if (flag_block)
+ DS_Sleep(PR_MillisecondsToInterval(import_sleep_time));
+ else
+ {
+ PR_Unlock(job->wire_lock);
+ return LDAP_BUSY;
+ }
+ }
+
+ /* the producer could be running thru the fifo while
+ * everyone else is cycling to a new pass...
+ * double-check that this entry is < ready_ID
+ */
+ while ((old_ep->ep_id >= job->ready_ID) && !(job->flags & FLAG_ABORT))
+ {
+ if (flag_block)
+ DS_Sleep(PR_MillisecondsToInterval(import_sleep_time));
+ else
+ {
+ PR_Unlock(job->wire_lock);
+ return LDAP_BUSY;
+ }
+ }
+
+ if (job->flags & FLAG_ABORT) {
+ PR_Unlock(job->wire_lock);
+ return -2;
+ }
+
+ PR_ASSERT(old_ep == job->fifo.item[idx].entry);
+ job->fifo.item[idx].entry = NULL;
+ if (job->fifo.c_bsize > job->fifo.item[idx].esize)
+ job->fifo.c_bsize -= job->fifo.item[idx].esize;
+ else
+ job->fifo.c_bsize = 0;
+ backentry_free(&old_ep);
+ }
+
+ newesize = (slapi_entry_size(ep->ep_entry) + sizeof(struct backentry));
+ if (newesize > job->fifo.bsize) { /* entry too big */
+ char ebuf[BUFSIZ];
+ import_log_notice(job, "WARNING: skipping entry \"%s\"",
+ escape_string(slapi_entry_get_dn(ep->ep_entry), ebuf));
+ import_log_notice(job, "REASON: entry too large (%d bytes) for "
+ "the buffer size (%d bytes)", newesize, job->fifo.bsize);
+ backentry_free(&ep);
+ PR_Unlock(job->wire_lock);
+ return -1;
+ }
+ /* Now check if fifo has enough space for the new entry */
+ if ((job->fifo.c_bsize + newesize) > job->fifo.bsize) {
+ import_wait_for_space_in_fifo( job, newesize );
+ }
+
+ /* We have enough space */
+ job->fifo.item[idx].filename = "(bulk import)";
+ job->fifo.item[idx].line = 0;
+ job->fifo.item[idx].entry = ep;
+ job->fifo.item[idx].bad = 0;
+ job->fifo.item[idx].esize = newesize;
+
+ /* Add the entry size to total fifo size */
+ job->fifo.c_bsize += ep->ep_entry? job->fifo.item[idx].esize : 0;
+
+ /* Update the job to show our progress */
+ job->lead_ID = id;
+ if ((id - job->starting_ID) <= job->fifo.size) {
+ job->trailing_ID = job->starting_ID;
+ } else {
+ job->trailing_ID = id - job->fifo.size;
+ }
+
+ PR_Unlock(job->wire_lock);
+ return 0;
+}
+
+void *factory_constructor(void *object, void *parent)
+{
+ return NULL;
+}
+
+void factory_destructor(void *extension, void *object, void *parent)
+{
+ ImportJob *job = (ImportJob *)extension;
+ PRThread *thread;
+
+ if (extension == NULL)
+ return;
+
+ /* connection was destroyed while we were still storing the extension --
+ * this is bad news and means we have a bulk import that needs to be
+ * aborted!
+ */
+ thread = job->main_thread;
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR bulk import abandoned\n",
+ 0, 0, 0);
+ import_abort_all(job, 1);
+ /* wait for import_main to finish... */
+ PR_JoinThread(thread);
+ /* extension object is free'd by import_main */
+ return;
+}
+
+/* plugin entry function for replica init */
+int ldbm_back_wire_import(Slapi_PBlock *pb)
+{
+ struct ldbminfo *li;
+ backend *be = NULL;
+ ImportJob *job;
+ PRThread *thread;
+ int state;
+
+ slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+ PR_ASSERT(be != NULL);
+ li = (struct ldbminfo *)(be->be_database->plg_private);
+ slapi_pblock_get(pb, SLAPI_BULK_IMPORT_STATE, &state);
+ if (state == SLAPI_BI_STATE_START) {
+ /* starting a new import */
+ return bulk_import_start(pb);
+ }
+
+ PR_ASSERT(pb->pb_conn != NULL);
+ if (pb->pb_conn != NULL) {
+ job = (ImportJob *)slapi_get_object_extension(li->li_bulk_import_object, pb->pb_conn, li->li_bulk_import_handle);
+ }
+
+ if ((job == NULL) || (pb->pb_conn == NULL)) {
+ /* import might be aborting */
+ return -1;
+ }
+
+ if (state == SLAPI_BI_STATE_ADD) {
+ /* continuing previous import */
+ if (! import_entry_belongs_here(pb->pb_import_entry,
+ job->inst->inst_be)) {
+ /* silently skip */
+ return 0;
+ }
+ return bulk_import_queue(job, pb->pb_import_entry,
+ job->flags & FLAG_USE_FILES);
+ }
+
+ thread = job->main_thread;
+
+ if (state == SLAPI_BI_STATE_DONE) {
+ /* finished with an import */
+ job->flags |= FLAG_PRODUCER_DONE;
+ /* "job" struct may vanish at any moment after we set the DONE
+ * flag, so keep a copy of the thread id in 'thread' for safekeeping.
+ */
+ /* wait for import_main to finish... */
+ PR_JoinThread(thread);
+ slapi_set_object_extension(li->li_bulk_import_object, pb->pb_conn,
+ li->li_bulk_import_handle, NULL);
+ return 0;
+ }
+
+ /* ??? unknown state */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: ldbm_back_wire_import: unknown state %d\n",
+ state, 0, 0);
+ return -1;
+}
+
+/*
+ * backup index configuration
+ * this function is called from dblayer_backup (ldbm2archive)
+ * [547427] index config must not change between backup and restore
+ */
+#define DSE_INDEX "dse_index.ldif"
+#define DSE_INSTANCE "dse_instance.ldif"
+#define DSE_INDEX_FILTER "(objectclass=nsIndex)"
+#define DSE_INSTANCE_FILTER "(objectclass=nsBackendInstance)"
+static int
+dse_conf_backup_core(struct ldbminfo *li, char *dest_dir, char *file_name, char *filter)
+{
+ Slapi_PBlock *srch_pb = NULL;
+ Slapi_Entry **entries = NULL;
+ Slapi_Entry **ep = NULL;
+ Slapi_Attr *attr = NULL;
+ char *attr_name;
+ char *filename = NULL;
+ PRFileDesc *prfd = NULL;
+ int rval = 0;
+ int dlen = 0;
+ PRInt32 prrval;
+ char tmpbuf[BUFSIZ];
+ char *tp = NULL;
+
+ dlen = strlen(dest_dir);
+ if (0 == dlen)
+ {
+ filename = file_name;
+ }
+ else
+ {
+ filename = (char *)slapi_ch_malloc(strlen(file_name) + dlen + 2);
+ sprintf(filename, "%s/%s", dest_dir, file_name);
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE, "dse_conf_backup(%s): backup file %s\n",
+ filter, filename, 0);
+
+ /* Open the file to write */
+ if ((prfd = PR_Open(filename, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
+ SLAPD_DEFAULT_FILE_MODE)) == NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dse_conf_backup(%s): open %s failed: (%s)\n",
+ filter, filename, slapd_pr_strerror(PR_GetError()));
+ rval = -1;
+ goto out;
+ }
+
+ srch_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(srch_pb, li->li_plugin->plg_dn,
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, li->li_identity, 0);
+ slapi_search_internal_pb(srch_pb);
+ slapi_pblock_get(srch_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ for (ep = entries; ep != NULL && *ep != NULL; ep++)
+ {
+ size_t l = strlen(slapi_entry_get_dn_const(*ep)) + 5 /* "dn: \n" */;
+ LDAPDebug(LDAP_DEBUG_TRACE, "\ndn: %s\n",
+ slapi_entry_get_dn_const(*ep), 0, 0);
+
+ if (l <= BUFSIZ)
+ tp = tmpbuf;
+ else
+ tp = (char *)slapi_ch_malloc(l); /* should be very rare ... */
+ sprintf(tp, "dn: %s\n", slapi_entry_get_dn_const(*ep));
+ prrval = PR_Write(prfd, tp, l);
+ if ((size_t)prrval != l)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dse_conf_backup(%s): write %s failed: %d (%s)\n",
+ filter, PR_GetError(), slapd_pr_strerror(PR_GetError()));
+ rval = -1;
+ if (l > BUFSIZ)
+ slapi_ch_free_string(&tp);
+ goto out;
+ }
+ if (l > BUFSIZ)
+ slapi_ch_free_string(&tp);
+
+ for (slapi_entry_first_attr(*ep, &attr); attr;
+ slapi_entry_next_attr(*ep, attr, &attr))
+ {
+ int i;
+ Slapi_Value *sval = NULL;
+ const struct berval *attr_val;
+ int attr_name_len;
+
+ slapi_attr_get_type(attr, &attr_name);
+ /* numsubordinates should not be backed up */
+ if (!strcasecmp("numsubordinates", attr_name))
+ continue;
+ attr_name_len = strlen(attr_name);
+ for (i = slapi_attr_first_value(attr, &sval); i != -1;
+ i = slapi_attr_next_value(attr, i, &sval))
+ {
+ attr_val = slapi_value_get_berval(sval);
+ l = strlen(attr_val->bv_val) + attr_name_len + 3; /* : \n" */
+ LDAPDebug(LDAP_DEBUG_TRACE, "%s: %s\n", attr_name,
+ attr_val->bv_val, 0);
+ if (l <= BUFSIZ)
+ tp = tmpbuf;
+ else
+ tp = (char *)slapi_ch_malloc(l);
+ sprintf(tp, "%s: %s\n", attr_name, attr_val->bv_val);
+ prrval = PR_Write(prfd, tp, l);
+ if ((size_t)prrval != l)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dse_conf_backup(%s): write %s failed: %d (%s)\n",
+ filter, PR_GetError(), slapd_pr_strerror(PR_GetError()));
+ rval = -1;
+ if (l > BUFSIZ)
+ slapi_ch_free_string(&tp);
+ goto out;
+ }
+ if (l > BUFSIZ)
+ slapi_ch_free_string(&tp);
+ }
+ }
+ if (ep+1 != NULL && *(ep+1) != NULL)
+ {
+ prrval = PR_Write(prfd, "\n", 1);
+ if ((int)prrval != 1)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dse_conf_backup(%s): write %s failed: %d (%s)\n",
+ filter, PR_GetError(), slapd_pr_strerror(PR_GetError()));
+ rval = -1;
+ goto out;
+ }
+ }
+ }
+
+out:
+ slapi_free_search_results_internal(srch_pb);
+ if (srch_pb)
+ {
+ slapi_pblock_destroy(srch_pb);
+ }
+
+ if (0 != dlen)
+ {
+ slapi_ch_free_string(&filename);
+ }
+
+ if (prfd)
+ {
+ prrval = PR_Close(prfd);
+ if (PR_SUCCESS != prrval)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Fatal Error---Failed to back up dse indexes %d (%s)\n",
+ PR_GetError(), slapd_pr_strerror(PR_GetError()), 0);
+ rval = -1;
+ }
+ }
+
+ return rval;
+}
+
+int
+dse_conf_backup(struct ldbminfo *li, char *dest_dir)
+{
+ int rval = 0;
+ rval = dse_conf_backup_core(li, dest_dir, DSE_INSTANCE, DSE_INSTANCE_FILTER);
+ rval += dse_conf_backup_core(li, dest_dir, DSE_INDEX, DSE_INDEX_FILTER);
+ return rval;
+}
+
+/*
+ * read the backed up index configuration
+ * adjust them if the current configuration is different from it.
+ * this function is called from dblayer_restore (archive2ldbm)
+ * these functions are placed here to borrow import_get_entry
+ * [547427] index config must not change between backup and restore
+ */
+int
+dse_conf_verify_core(struct ldbminfo *li, char *src_dir, char *file_name, char *filter, char *log_str)
+{
+ char *filename = NULL;
+ int rval = 0;
+ ldif_context c;
+ int fd = -1;
+ int curr_lineno = 0;
+ int finished = 0;
+ int backup_entry_len = 256;
+ Slapi_Entry **backup_entries = NULL;
+ Slapi_Entry **bep = NULL;
+ Slapi_Entry **curr_entries = NULL;
+ Slapi_PBlock srch_pb;
+
+ filename = (char *)slapi_ch_malloc(strlen(file_name) + strlen(src_dir) + 2);
+ sprintf(filename, "%s/%s", src_dir, file_name);
+
+ if (PR_SUCCESS != PR_Access(filename, PR_ACCESS_READ_OK))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: config backup file %s not found in backup\n",
+ file_name, 0, 0);
+ rval = 0;
+ goto out;
+ }
+
+ fd = dblayer_open_huge_file(filename, O_RDONLY, 0);
+ if (fd < 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: can't open config backup file: %s\n", filename, 0, 0);
+ rval = -1;
+ goto out;
+ }
+
+ import_init_ldif(&c);
+ bep = backup_entries = (Slapi_Entry **)slapi_ch_calloc(1,
+ backup_entry_len * sizeof(Slapi_Entry *));
+
+ while (!finished)
+ {
+ char *estr = NULL;
+ Slapi_Entry *e = NULL;
+ estr = import_get_entry(&c, fd, &curr_lineno);
+
+ if (!estr)
+ break;
+
+ e = slapi_str2entry(estr, 0);
+ slapi_ch_free_string(&estr);
+ if (!e) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: skipping bad LDIF entry "
+ "ending line %d of file \"%s\"", curr_lineno, filename, 0);
+ continue;
+ }
+ if (bep - backup_entries >= backup_entry_len)
+ {
+ backup_entries = (Slapi_Entry **)slapi_ch_realloc((char *)backup_entries,
+ 2 * backup_entry_len * sizeof(Slapi_Entry *));
+ bep = backup_entries + backup_entry_len;
+ backup_entry_len *= 2;
+ }
+ *bep = e;
+ bep++;
+ }
+ // 623986: terminate the list if we reallocated backup_entries
+ if (backup_entry_len > 256)
+ *bep = NULL;
+
+ pblock_init(&srch_pb);
+ slapi_search_internal_set_pb(&srch_pb, li->li_plugin->plg_dn,
+ LDAP_SCOPE_SUBTREE, filter, NULL, 0, NULL, NULL, li->li_identity, 0);
+ slapi_search_internal_pb(&srch_pb);
+ slapi_pblock_get(&srch_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &curr_entries);
+
+ if (0 != slapi_entries_diff(backup_entries, curr_entries, 1 /* test_all */,
+ log_str, 1 /* force_update */, li->li_identity))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING!!: current %s is "
+ "different from backed up configuration; "
+ "The backup is restored.\n", log_str, 0, 0);
+ }
+
+ slapi_free_search_results_internal(&srch_pb);
+ pblock_done(&srch_pb);
+ import_free_ldif(&c);
+out:
+ for (bep = backup_entries; bep && *bep; bep++)
+ slapi_entry_free(*bep);
+ slapi_ch_free((void **)&backup_entries);
+
+ slapi_ch_free_string(&filename);
+
+ if (fd > 0)
+ close(fd);
+
+ return rval;
+}
+
+int
+dse_conf_verify(struct ldbminfo *li, char *src_dir)
+{
+ int rval;
+ rval = dse_conf_verify_core(li, src_dir, DSE_INSTANCE, DSE_INSTANCE_FILTER,
+ "Instance Config");
+ rval += dse_conf_verify_core(li, src_dir, DSE_INDEX, DSE_INDEX_FILTER,
+ "Index Config");
+ return rval;
+}
diff --git a/ldap/servers/slapd/back-ldbm/import.c b/ldap/servers/slapd/back-ldbm/import.c
new file mode 100644
index 00000000..47e05fa6
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/import.c
@@ -0,0 +1,1465 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * the "new" ("deluxe") backend import code
+ *
+ * please make sure you use 4-space indentation on this file.
+ */
+
+
+#include "back-ldbm.h"
+#include "vlv_srch.h"
+#include "import.h"
+
+#define ERR_IMPORT_ABORTED -23
+
+
+/********** routines to manipulate the entry fifo **********/
+
+/* this is pretty bogus -- could be a HUGE amount of memory */
+/* Not anymore with the Import Queue Adaptative Algorithm (Regulation) */
+#define MAX_FIFO_SIZE 8000
+
+static int import_fifo_init(ImportJob *job)
+{
+ ldbm_instance *inst = job->inst;
+
+ /* Work out how big the entry fifo can be */
+ if (inst->inst_cache.c_maxentries > 0)
+ job->fifo.size = inst->inst_cache.c_maxentries;
+ else
+ job->fifo.size = inst->inst_cache.c_maxsize / 1024; /* guess */
+
+ /* byte limit that should be respected to avoid memory starvation */
+ /* conservative computing: multiply by .8 to allow for reasonable overflow */
+ job->fifo.bsize = (inst->inst_cache.c_maxsize/10) << 3;
+
+ job->fifo.c_bsize = 0;
+
+ if (job->fifo.size > MAX_FIFO_SIZE)
+ job->fifo.size = MAX_FIFO_SIZE;
+ /* has to be at least 1 or 2, and anything less than about 100 destroys
+ * the point of doing all this optimization in the first place. */
+ if (job->fifo.size < 100)
+ job->fifo.size = 100;
+
+ /* Get memory for the entry fifo */
+ /* This is used to keep a ref'ed pointer to the last <cachesize>
+ * processed entries */
+ PR_ASSERT(NULL == job->fifo.item);
+ job->fifo.item = (FifoItem *)slapi_ch_calloc(job->fifo.size,
+ sizeof(FifoItem));
+ if (NULL == job->fifo.item) {
+ /* Memory allocation error */
+ return -1;
+ }
+ return 0;
+}
+
+FifoItem *import_fifo_fetch(ImportJob *job, ID id, int worker)
+{
+ int idx = id % job->fifo.size;
+ FifoItem *fi;
+
+ if (job->fifo.item) {
+ fi = &(job->fifo.item[idx]);
+ } else {
+ return NULL;
+ }
+ if (fi->entry) {
+ if (id != fi->entry->ep_id)
+ fi = NULL;
+ else if (worker) {
+ if (fi->bad) return NULL;
+ PR_ASSERT(fi->entry->ep_refcnt > 0);
+ }
+ }
+ return fi;
+}
+
+static void import_fifo_destroy(ImportJob *job)
+{
+ /* Free any entries in the fifo first */
+ struct backentry *be = NULL;
+ size_t i = 0;
+
+ for (i = 0; i < job->fifo.size; i++) {
+ be = job->fifo.item[i].entry;
+ backentry_free(&be);
+ job->fifo.item[i].entry = NULL;
+ job->fifo.item[i].filename = NULL;
+ }
+ free(job->fifo.item);
+ job->fifo.item = NULL;
+}
+
+
+/********** logging stuff **********/
+
+#define LOG_BUFFER 256
+
+/* this changes the 'nsTaskStatus' value, which is transient (anything logged
+ * here wipes out any previous status)
+ */
+static void import_log_status_start(ImportJob *job)
+{
+ if (! job->task_status)
+ job->task_status = (char *)slapi_ch_malloc(10 * LOG_BUFFER);
+ if (! job->task_status)
+ return; /* out of memory? */
+
+ job->task_status[0] = 0;
+}
+
+static void import_log_status_add_line(ImportJob *job, char *format, ...)
+{
+ va_list ap;
+ int len = 0;
+
+ if (! job->task_status)
+ return;
+ len = strlen(job->task_status);
+ if (len + 5 > (10 * LOG_BUFFER))
+ return; /* no room */
+
+ if (job->task_status[0])
+ strcat(job->task_status, "\n");
+
+ va_start(ap, format);
+ PR_vsnprintf(job->task_status + len, (10 * LOG_BUFFER) - len, format, ap);
+ va_end(ap);
+}
+
+static void import_log_status_done(ImportJob *job)
+{
+ if (job->task) {
+ int len = 0;
+ len = strlen(job->task_status);
+ slapi_task_log_status(job->task, "%s", job->task_status);
+ }
+}
+
+/* this adds a line to the 'nsTaskLog' value, which is cumulative (anything
+ * logged here is added to the end)
+ */
+void import_log_notice(ImportJob *job, char *format, ...)
+{
+ va_list ap;
+ char buffer[LOG_BUFFER];
+
+ va_start(ap, format);
+ PR_vsnprintf(buffer, LOG_BUFFER, format, ap);
+ va_end(ap);
+
+ if (job->task) {
+ slapi_task_log_notice(job->task, "%s", buffer);
+ }
+ /* also save it in the logs for posterity */
+ LDAPDebug(LDAP_DEBUG_ANY, "import %s: %s\n", job->inst->inst_name,
+ buffer, 0);
+}
+
+static int import_task_destroy(Slapi_Task *task)
+{
+ ImportJob *job = (ImportJob *)task->task_private;
+
+ if (task->task_log) {
+ slapi_ch_free((void **)&task->task_log);
+ }
+
+ if (task->task_status) {
+ slapi_ch_free((void **)&task->task_status);
+ }
+
+
+ if (job && job->task_status) {
+ slapi_ch_free((void **)&job->task_status);
+ job->task_status = NULL;
+ }
+ FREE(job);
+ task->task_private = NULL;
+ return 0;
+}
+
+static int import_task_abort(Slapi_Task *task)
+{
+ ImportJob *job;
+
+ /* don't log anything from here, because we're still holding the
+ * DSE lock for modify...
+ */
+
+ if (task->task_state == SLAPI_TASK_FINISHED) {
+ /* too late */
+ return 0;
+ }
+
+ /*
+ * Race condition.
+ * If the import thread happens to finish right now we're in trouble
+ * because it will free the job.
+ */
+
+ job = (ImportJob *)task->task_private;
+
+ import_abort_all(job, 0);
+ while (task->task_state != SLAPI_TASK_FINISHED)
+ DS_Sleep(PR_MillisecondsToInterval(100));
+
+
+ return 0;
+}
+
+
+/********** helper functions for importing **********/
+
+
+/* Function used to gather a list of indexed attrs */
+static int import_attr_callback(void *node, void *param)
+{
+ ImportJob *job = (ImportJob *)param;
+ struct attrinfo *a = (struct attrinfo *)node;
+
+ /* OK, so we now have hold of the attribute structure and the job info,
+ * let's see what we have. Remember that although this function is called
+ * many times, all these calls are in the context of a single thread, so we
+ * don't need to worry about protecting the data in the job structure.
+ */
+
+ /* We need to specifically exclude the entrydn & parentid indexes because
+ * we build those in the foreman thread.
+ */
+ if (IS_INDEXED(a->ai_indexmask) &&
+ (strcasecmp(a->ai_type, "entrydn") != 0) &&
+ (strcasecmp(a->ai_type, "parentid") != 0) &&
+ (strcasecmp(a->ai_type, "ancestorid") != 0) &&
+ (strcasecmp(a->ai_type, numsubordinates) != 0)) {
+ /* Make an import_index_info structure, fill it in and insert into the
+ * job's list */
+ IndexInfo *info = CALLOC(IndexInfo);
+
+ if (NULL == info) {
+ /* Memory allocation error */
+ return -1;
+ }
+ info->name = slapi_ch_strdup(a->ai_type);
+ info->ai = a;
+ if (NULL == info->name) {
+ /* Memory allocation error */
+ free(info);
+ return -1;
+ }
+ info->next = job->index_list;
+ job->index_list = info;
+ job->number_indexers++;
+ }
+ return 0;
+}
+
+static void import_set_index_buffer_size(ImportJob *job)
+{
+ IndexInfo *current_index = NULL;
+ size_t substring_index_count = 0;
+ size_t proposed_size = 0;
+
+ /* Count the substring indexes we have */
+ for (current_index = job->index_list; current_index != NULL;
+ current_index = current_index->next) {
+ if (current_index->ai->ai_indexmask & INDEX_SUB) {
+ substring_index_count++;
+ }
+ }
+ if (substring_index_count > 0) {
+ /* Make proposed size such that if all substring indices were
+ * reasonably full, we'd hit the target space */
+ proposed_size = (job->job_index_buffer_size / substring_index_count) /
+ IMPORT_INDEX_BUFFER_SIZE_CONSTANT;
+ if (proposed_size > IMPORT_MAX_INDEX_BUFFER_SIZE) {
+ proposed_size = IMPORT_MAX_INDEX_BUFFER_SIZE;
+ }
+ if (proposed_size < IMPORT_MIN_INDEX_BUFFER_SIZE) {
+ proposed_size = 0;
+ }
+ }
+
+ job->job_index_buffer_suggestion = proposed_size;
+}
+
+static void import_free_thread_data(ImportJob *job)
+{
+ /* DBDB free the lists etc */
+ ImportWorkerInfo *worker = job->worker_list;
+
+ while (worker != NULL) {
+ ImportWorkerInfo *asabird = worker;
+ worker = worker->next;
+ if (asabird->work_type != PRODUCER)
+ slapi_ch_free( (void**)&asabird);
+ }
+}
+
+void import_free_job(ImportJob *job)
+{
+ /* DBDB free the lists etc */
+ IndexInfo *index = job->index_list;
+
+ import_free_thread_data(job);
+ while (index != NULL) {
+ IndexInfo *asabird = index;
+ index = index->next;
+ slapi_ch_free( (void**)&asabird->name);
+ slapi_ch_free( (void**)&asabird);
+ }
+ job->index_list = NULL;
+ if (NULL != job->mothers) {
+ import_subcount_stuff_term(job->mothers);
+ slapi_ch_free( (void**)&job->mothers);
+ }
+
+ ldbm_back_free_incl_excl(job->include_subtrees, job->exclude_subtrees);
+ charray_free(job->input_filenames);
+ if (job->fifo.size)
+ import_fifo_destroy(job);
+ if (NULL != job->uuid_namespace)
+ slapi_ch_free((void **)&job->uuid_namespace);
+ if (job->wire_lock)
+ PR_DestroyLock(job->wire_lock);
+ if (job->wire_cv)
+ PR_DestroyCondVar(job->wire_cv);
+ slapi_ch_free((void **)&job->task_status);
+}
+
+/* determine if we are the correct backend for this entry
+ * (in a distributed suffix, some entries may be for other backends).
+ * if the entry's dn actually matches one of the suffixes of the be, we
+ * automatically take it as a belonging one, for such entries must be
+ * present in EVERY backend independently of the distribution applied.
+ */
+int import_entry_belongs_here(Slapi_Entry *e, backend *be)
+{
+ Slapi_Backend *retbe;
+ Slapi_DN *sdn = slapi_entry_get_sdn(e);
+
+ if (slapi_be_issuffix(be, sdn))
+ return 1;
+
+ retbe = slapi_mapping_tree_find_backend_for_sdn(sdn);
+ return (retbe == be);
+}
+
+
+/********** starting threads and stuff **********/
+
+/* Solaris is weird---we need an LWP per thread but NSPR doesn't give us
+ * one unless we make this magic belshe-call */
+/* Fixed on Solaris 8; NSPR supports PR_GLOBAL_BOUND_THREAD */
+#define CREATE_THREAD PR_CreateThread
+
+static void import_init_worker_info(ImportWorkerInfo *info, ImportJob *job)
+{
+ info->command = PAUSE;
+ info->job = job;
+ info->first_ID = job->first_ID;
+ info->index_buffer_size = job->job_index_buffer_suggestion;
+}
+
+static int import_start_threads(ImportJob *job)
+{
+ IndexInfo *current_index = NULL;
+ ImportWorkerInfo *foreman = NULL, *worker = NULL;
+
+ foreman = CALLOC(ImportWorkerInfo);
+ if (!foreman)
+ goto error;
+
+ /* start the foreman */
+ import_init_worker_info(foreman, job);
+ foreman->work_type = FOREMAN;
+ if (! CREATE_THREAD(PR_USER_THREAD, (VFP)import_foreman, foreman,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE)) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to spawn import foreman thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ FREE(foreman);
+ goto error;
+ }
+
+ foreman->next = job->worker_list;
+ job->worker_list = foreman;
+
+ /* Start follower threads, if we are doing attribute indexing */
+ current_index = job->index_list;
+ if (job->flags & FLAG_INDEX_ATTRS) {
+ while (current_index) {
+ /* make a new thread info structure */
+ worker = CALLOC(ImportWorkerInfo);
+ if (! worker)
+ goto error;
+
+ /* fill it in */
+ import_init_worker_info(worker, job);
+ worker->index_info = current_index;
+ worker->work_type = WORKER;
+
+ /* Start the thread */
+ if (! CREATE_THREAD(PR_USER_THREAD, (VFP)import_worker, worker,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to spawn import worker thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ FREE(worker);
+ goto error;
+ }
+
+ /* link it onto the job's thread list */
+ worker->next = job->worker_list;
+ job->worker_list = worker;
+ current_index = current_index->next;
+ }
+ }
+ return 0;
+
+error:
+ import_log_notice(job, "Import thread creation failed.");
+ import_log_notice(job, "Aborting all import threads...");
+ import_abort_all(job, 1);
+ import_log_notice(job, "Import threads aborted.");
+ return -1;
+}
+
+
+/********** monitoring the worker threads **********/
+
+static void import_clear_progress_history(ImportJob *job)
+{
+ int i = 0;
+
+ for (i = 0; i < IMPORT_JOB_PROG_HISTORY_SIZE /*- 1*/; i++) {
+ job->progress_history[i] = job->first_ID;
+ job->progress_times[i] = job->start_time;
+ }
+ /* reset libdb cache stats */
+ job->inst->inst_cache_hits = job->inst->inst_cache_misses = 0;
+}
+
+static double import_grok_db_stats(ldbm_instance *inst)
+{
+ DB_MPOOL_STAT *mpstat = NULL;
+ DB_MPOOL_FSTAT **mpfstat = NULL;
+ int return_value = -1;
+ double cache_hit_ratio = 0.0;
+
+ return_value = dblayer_memp_stat_instance(inst, &mpstat, &mpfstat);
+
+ if (0 == return_value) {
+ unsigned long current_cache_hits = mpstat->st_cache_hit;
+ unsigned long current_cache_misses = mpstat->st_cache_miss;
+
+ if (inst->inst_cache_hits) {
+ unsigned long hit_delta, miss_delta;
+
+ hit_delta = current_cache_hits - inst->inst_cache_hits;
+ miss_delta = current_cache_misses - inst->inst_cache_misses;
+ if (hit_delta != 0) {
+ cache_hit_ratio = (double)hit_delta /
+ (double)(hit_delta + miss_delta);
+ }
+ }
+ inst->inst_cache_misses = current_cache_misses;
+ inst->inst_cache_hits = current_cache_hits;
+
+ if (mpstat)
+ free(mpstat);
+ if (mpfstat) {
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR + DB_VERSION_PATCH <= 3204
+ /* In DB 3.2.4 and earlier, we need to free each element */
+ DB_MPOOL_FSTAT **tfsp;
+ for (tfsp = mpfstat; *tfsp; tfsp++)
+ free(*tfsp);
+#endif
+ free(mpfstat);
+ }
+ }
+ return cache_hit_ratio;
+}
+
+static char* import_decode_worker_state(int state)
+{
+ switch (state) {
+ case WAITING:
+ return "W";
+ case RUNNING:
+ return "R";
+ case FINISHED:
+ return "F";
+ case ABORTED:
+ return "A";
+ default:
+ return "?";
+ }
+}
+
+static void import_print_worker_status(ImportWorkerInfo *info)
+{
+ char *name = (info->work_type == PRODUCER ? "Producer" :
+ (info->work_type == FOREMAN ? "Foreman" :
+ info->index_info->name));
+
+ import_log_status_add_line(info->job,
+ "%-25s %s%10ld %7.1f", name,
+ import_decode_worker_state(info->state),
+ info->last_ID_processed, info->rate);
+}
+
+
+#define IMPORT_CHUNK_TEST_HOLDOFF_TIME (5*60) /* Seconds */
+
+/* Got to be lower than this: */
+#define IMPORT_CHUNK_TEST_CACHE_HIT_RATIO (0.99)
+/* Less than half as fast as we were doing: */
+#define IMPORT_CHUNK_TEST_SLOWDOWN_RATIO_A (0.5)
+/* A lot less fast than we were doing: */
+#define IMPORT_CHUNK_TEST_SLOWDOWN_RATIO_B (0.1)
+
+static int import_throw_in_towel(ImportJob *job, time_t current_time,
+ ID trailing_ID)
+{
+ static int number_of_times_here = 0;
+
+ /* secret -c option allows specific chunk size to be set... */
+ if (job->merge_chunk_size != 0) {
+ if ((0 != job->lead_ID) &&
+ (trailing_ID > job->first_ID) &&
+ (trailing_ID - job->first_ID > job->merge_chunk_size)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /* Check stats to decide whether we're getting bogged down and should
+ * terminate this pass.
+ */
+
+ /* Check #1 : are we more than 10 minutes into the chunk ? */
+ if (current_time - job->start_time > IMPORT_CHUNK_TEST_HOLDOFF_TIME) {
+ /* Check #2 : Have we slowed down considerably recently ? */
+ if ((job->recent_progress_rate / job->average_progress_rate) <
+ IMPORT_CHUNK_TEST_SLOWDOWN_RATIO_A) {
+ /* Check #3: Cache performing poorly---the puported reason
+ * for the slowdown */
+ if (job->cache_hit_ratio < IMPORT_CHUNK_TEST_CACHE_HIT_RATIO) {
+ /* We have a winner ! */
+ import_log_notice(job, "Decided to end this pass because "
+ "the progress rate has dropped below "
+ "the %.0f%% threshold.",
+ IMPORT_CHUNK_TEST_SLOWDOWN_RATIO_A*100.0);
+ return 1;
+ }
+ } else {
+ if ((job->recent_progress_rate / job->average_progress_rate) <
+ IMPORT_CHUNK_TEST_SLOWDOWN_RATIO_B) {
+ /* Alternative check: have we really, really slowed down,
+ * without the test for cache overflow? */
+ /* This is designed to catch the case where the cache has
+ * been misconfigured too large */
+ if (number_of_times_here > 10) {
+ /* Got to get here ten times at least */
+ import_log_notice(job, "Decided to end this pass "
+ "because the progress rate "
+ "plummeted below %.0f%%",
+ IMPORT_CHUNK_TEST_SLOWDOWN_RATIO_B*100.0);
+ return 1;
+ }
+ number_of_times_here++;
+ }
+ }
+ }
+
+ number_of_times_here = 0;
+ return 0;
+}
+
+static void import_push_progress_history(ImportJob *job, ID current_id,
+ time_t current_time)
+{
+ int i = 0;
+
+ for (i = 0; i < IMPORT_JOB_PROG_HISTORY_SIZE - 1; i++) {
+ job->progress_history[i] = job->progress_history[i+1];
+ job->progress_times[i] = job->progress_times[i+1];
+ }
+ job->progress_history[i] = current_id;
+ job->progress_times[i] = current_time;
+}
+
+static void import_calc_rate(ImportWorkerInfo *info, int time_interval)
+{
+ size_t ids = info->last_ID_processed - info->previous_ID_counted;
+ double rate = (double)ids / time_interval;
+
+ if ( (info->previous_ID_counted != 0) && (info->last_ID_processed != 0) ) {
+ info->rate = rate;
+ } else {
+ info->rate = 0;
+ }
+ info->previous_ID_counted = info->last_ID_processed;
+}
+
+/* find the rate (ids/time) of work from a worker thread between history
+ * marks A and B.
+ */
+#define HISTORY(N) (job->progress_history[N])
+#define TIMES(N) (job->progress_times[N])
+#define PROGRESS(A, B) ((HISTORY(B) > HISTORY(A)) ? \
+ ((double)(HISTORY(B) - HISTORY(A)) / \
+ (double)(TIMES(B) - TIMES(A))) : \
+ (double)0)
+
+static int import_monitor_threads(ImportJob *job, int *status)
+{
+ PRIntervalTime tenthsecond = PR_MillisecondsToInterval(100);
+ ImportWorkerInfo *current_worker = NULL;
+ ImportWorkerInfo *producer = NULL, *foreman = NULL;
+ int finished = 0;
+ int giveup = 0;
+ int count = 1; /* 1 to prevent premature status report */
+ int producer_done = 0;
+ const int display_interval = 200;
+ time_t time_now = 0;
+ time_t last_time = 0;
+ time_t time_interval = 0;
+
+
+ for (current_worker = job->worker_list; current_worker != NULL;
+ current_worker = current_worker->next) {
+ current_worker->command = RUN;
+ if (current_worker->work_type == PRODUCER)
+ producer = current_worker;
+ if (current_worker->work_type == FOREMAN)
+ foreman = current_worker;
+ }
+
+
+ if (job->flags & FLAG_USE_FILES)
+ PR_ASSERT(producer != NULL);
+ PR_ASSERT(foreman != NULL);
+
+ time(&last_time);
+ job->start_time = last_time;
+ import_clear_progress_history(job);
+
+ while (!finished) {
+ ID trailing_ID = NOID;
+
+ DS_Sleep(tenthsecond);
+ finished = 1;
+
+ /* First calculate the time interval since last reported */
+ if (0 == (count % display_interval)) {
+ time(&time_now);
+ time_interval = time_now - last_time;
+ last_time = time_now;
+ /* Now calculate our rate of progress overall for this chunk */
+ if (time_now != job->start_time) {
+ /* log a cute chart of the worker progress */
+ import_log_status_start(job);
+ import_log_status_add_line(job,
+ "Index status for import of %s:", job->inst->inst_name);
+ import_log_status_add_line(job,
+ "-------Index Task-------State---Entry----Rate-");
+
+ import_push_progress_history(job, foreman->last_ID_processed,
+ time_now);
+ job->average_progress_rate =
+ (double)(HISTORY(IMPORT_JOB_PROG_HISTORY_SIZE-1)+1 - foreman->first_ID) /
+ (double)(TIMES(IMPORT_JOB_PROG_HISTORY_SIZE-1) - job->start_time);
+ job->recent_progress_rate =
+ PROGRESS(0, IMPORT_JOB_PROG_HISTORY_SIZE-1);
+ job->cache_hit_ratio = import_grok_db_stats(job->inst);
+ }
+ }
+
+ for (current_worker = job->worker_list; current_worker != NULL;
+ current_worker = current_worker->next) {
+ /* Calculate the ID at which the slowest worker is currently
+ * processing */
+ if ((trailing_ID > current_worker->last_ID_processed) &&
+ (current_worker->work_type == WORKER)) {
+ trailing_ID = current_worker->last_ID_processed;
+ }
+ if (0 == (count % display_interval) && time_interval) {
+ import_calc_rate(current_worker, time_interval);
+ import_print_worker_status(current_worker);
+ }
+ if (current_worker->state != FINISHED) {
+ finished = 0;
+ }
+ if (current_worker->state == ABORTED) {
+ goto error_abort;
+ }
+ }
+
+ if ((0 == (count % display_interval)) &&
+ (job->start_time != time_now)) {
+ char buffer[256], *p = buffer;
+
+ import_log_status_done(job);
+ p += sprintf(p, "Processed %lu entries ", (u_long)job->ready_ID);
+ if (job->total_pass > 1)
+ p += sprintf(p, "(pass %d) ", job->total_pass);
+
+ p += sprintf(p, "-- average rate %.1f/sec, ",
+ job->average_progress_rate);
+ p += sprintf(p, "recent rate %.1f/sec, ",
+ job->recent_progress_rate);
+ p += sprintf(p, "hit ratio %.0f%%", job->cache_hit_ratio * 100.0);
+ import_log_notice(job, "%s", buffer);
+ }
+
+ /* Then let's see if it's time to complete this import pass */
+ if (!giveup) {
+ giveup = import_throw_in_towel(job, time_now, trailing_ID);
+ if (giveup) {
+ /* If so, signal the lead thread to stop */
+ import_log_notice(job, "Ending pass number %d ...",
+ job->total_pass);
+ foreman->command = STOP;
+ while (foreman->state != FINISHED) {
+ DS_Sleep(tenthsecond);
+ }
+ import_log_notice(job, "Foreman is done; waiting for "
+ "workers to finish...");
+ }
+ }
+
+ /* if the producer is finished, and the foreman has caught up... */
+ if (producer) {
+ producer_done = (producer->state == FINISHED);
+ } else {
+ producer_done = (job->flags & FLAG_PRODUCER_DONE);
+ }
+ if (producer_done && (job->lead_ID == job->ready_ID)) {
+ /* tell the foreman to stop if he's still working. */
+ if (foreman->state != FINISHED)
+ foreman->command = STOP;
+
+ /* if all the workers are caught up too, we're done */
+ if (trailing_ID == job->lead_ID)
+ break;
+ }
+
+ /* if the foreman is done (end of pass) and the worker threads
+ * have caught up...
+ */
+ if ((foreman->state == FINISHED) && (job->ready_ID == trailing_ID)) {
+ break;
+ }
+
+ count++;
+ }
+
+ import_log_notice(job, "Workers finished; cleaning up...");
+
+ /* Now tell all the workers to stop */
+ for (current_worker = job->worker_list; current_worker != NULL;
+ current_worker = current_worker->next) {
+ if (current_worker->work_type != PRODUCER)
+ current_worker->command = STOP;
+ }
+
+ /* Having done that, wait for them to say that they've stopped */
+ for (current_worker = job->worker_list; current_worker != NULL; ) {
+ if ((current_worker->state != FINISHED) &&
+ (current_worker->state != ABORTED) &&
+ (current_worker->work_type != PRODUCER)) {
+ DS_Sleep(tenthsecond); /* Only sleep if we hit a thread that is still not done */
+ continue;
+ } else {
+ current_worker = current_worker->next;
+ }
+ }
+ import_log_notice(job, "Workers cleaned up.");
+
+ /* If we're here and giveup is true, and the primary hadn't finished
+ * processing the input files, we need to return IMPORT_INCOMPLETE_PASS */
+ if (giveup && (job->input_filenames || (job->flags & FLAG_ONLINE) ||
+ (job->flags & FLAG_REINDEXING /* support multi-pass */))) {
+ if (producer_done && (job->ready_ID == job->lead_ID)) {
+ /* foreman caught up with the producer, and the producer is
+ * done.
+ */
+ *status = IMPORT_COMPLETE_PASS;
+ } else {
+ *status = IMPORT_INCOMPLETE_PASS;
+ }
+ } else {
+ *status = IMPORT_COMPLETE_PASS;
+ }
+ return 0;
+
+error_abort:
+ return ERR_IMPORT_ABORTED;
+}
+
+
+/********** running passes **********/
+
+static int import_run_pass(ImportJob *job, int *status)
+{
+ int ret = 0;
+
+ /* Start the threads running */
+ ret = import_start_threads(job);
+ if (ret != 0) {
+ import_log_notice(job, "Starting threads failed: %d\n", ret);
+ goto error;
+ }
+
+ /* Monitor the threads until we're done or fail */
+ ret = import_monitor_threads(job, status);
+ if (ret == ERR_IMPORT_ABORTED) {
+ goto error;
+ } else if (ret != 0) {
+ import_log_notice(job, "Thread monitoring aborted: %d\n", ret);
+ goto error;
+ }
+
+error:
+ return ret;
+}
+
+static void import_set_abort_flag_all(ImportJob *job, int wait_for_them)
+{
+
+ ImportWorkerInfo *worker;
+
+ /* tell all the worker threads to abort */
+ job->flags |= FLAG_ABORT;
+
+ /* setting of the flag in the job will be detected in the worker, foreman
+ * threads and if there are any threads which have a sleeptime 200 msecs
+ * = import_sleep_time; after that time, they will examine the condition
+ * (job->flags & FLAG_ABORT) which will unblock the thread to proceed to
+ * abort. Hence, we will sleep here for atleast 3 sec to make sure clean
+ * up occurs */
+ /* allow all the aborts to be processed */
+ DS_Sleep(PR_MillisecondsToInterval(3000));
+
+ if (wait_for_them) {
+ /* Having done that, wait for them to say that they've stopped */
+ for (worker = job->worker_list; worker != NULL; ) {
+ DS_Sleep(PR_MillisecondsToInterval(100));
+ if ((worker->state != FINISHED) &&
+ (worker->state != ABORTED)){
+ continue;
+ }
+ else{
+ worker = worker->next;
+ }
+ }
+ }
+
+}
+
+
+/* tell all the threads to abort */
+void import_abort_all(ImportJob *job, int wait_for_them)
+{
+ ImportWorkerInfo *worker;
+
+ /* tell all the worker threads to abort */
+ job->flags |= FLAG_ABORT;
+
+ for (worker = job->worker_list; worker; worker = worker->next)
+ worker->command = ABORT;
+
+ if (wait_for_them) {
+ /* Having done that, wait for them to say that they've stopped */
+ for (worker = job->worker_list; worker != NULL; ) {
+ DS_Sleep(PR_MillisecondsToInterval(100));
+ if ((worker->state != FINISHED) &&
+ (worker->state != ABORTED))
+ continue;
+ else
+ worker = worker->next;
+ }
+ }
+}
+
+/* Helper function to make up filenames */
+int import_make_merge_filenames(char *directory, char *indexname, int pass,
+ char **oldname, char **newname)
+{
+ /* Filenames look like this: attributename<LDBM_FILENAME_SUFFIX>
+ and need to be renamed to: attributename<LDBM_FILENAME_SUFFIX>.n
+ where n is the pass number.
+ */
+ size_t oldname_length = strlen(directory) + 1 + strlen(indexname) +
+ strlen(LDBM_FILENAME_SUFFIX) + 1 ;
+ /* Enough space for an 8-digit pass number */
+ size_t newname_length = oldname_length + 9;
+
+ *oldname = slapi_ch_malloc(oldname_length);
+ if (NULL == oldname)
+ return -1;
+ *newname = slapi_ch_malloc(newname_length);
+ if (NULL == newname)
+ return -1;
+ sprintf(*oldname, "%s/%s%s", directory, indexname, LDBM_FILENAME_SUFFIX);
+ sprintf(*newname, "%s/%s.%d%s", directory, indexname, pass,
+ LDBM_FILENAME_SUFFIX);
+ return 0;
+}
+
+/* Task here is as follows:
+ * First, if this is pass #1, check for the presence of a merge
+ * directory. If it is not present, create it.
+ * If it is present, delete all the files in it.
+ * Then, flush the dblayer and close files.
+ * Now create a numbered subdir of the merge directory for this pass.
+ * Next, move the index files, except entrydn, parentid and id2entry to
+ * the merge subdirectory. Important to move if we can, because
+ * that can be millions of times faster than a copy.
+ * Finally open the dblayer back up because the caller expects
+ * us to not muck with it.
+ */
+static int import_sweep_after_pass(ImportJob *job)
+{
+ backend *be = job->inst->inst_be;
+ int ret = 0;
+
+ import_log_notice(job, "Sweeping files for merging later...");
+
+ ret = dblayer_instance_close(be);
+
+ if (0 == ret) {
+ /* Walk the list of index jobs */
+ ImportWorkerInfo *current_worker = NULL;
+
+ for (current_worker = job->worker_list; current_worker != NULL;
+ current_worker = current_worker->next) {
+ /* Foreach job, rename the file to <filename>.n, where n is the
+ * pass number */
+ if ((current_worker->work_type != FOREMAN) &&
+ (current_worker->work_type != PRODUCER) &&
+ (strcasecmp(current_worker->index_info->name, "parentid") != 0)) {
+ char *newname = NULL;
+ char *oldname = NULL;
+
+ ret = import_make_merge_filenames(job->inst->inst_dir_name,
+ current_worker->index_info->name, job->current_pass,
+ &oldname, &newname);
+ if (0 != ret) {
+ break;
+ }
+ if (PR_Access(oldname, PR_ACCESS_EXISTS) == PR_SUCCESS) {
+ ret = PR_Rename(oldname, newname);
+ if (ret != PR_SUCCESS) {
+ PRErrorCode prerr = PR_GetError();
+ import_log_notice(job, "Failed to rename file \"%s\" to \"%s\", "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)",
+ oldname, newname, prerr, slapd_pr_strerror(prerr));
+ slapi_ch_free( (void**)&newname);
+ slapi_ch_free( (void**)&oldname);
+ break;
+ }
+ }
+ slapi_ch_free( (void**)&newname);
+ slapi_ch_free( (void**)&oldname);
+ }
+ }
+
+ ret = dblayer_instance_start(be, DBLAYER_IMPORT_MODE);
+ }
+
+ if (0 == ret) {
+ import_log_notice(job, "Sweep done.");
+ } else {
+ if (ENOSPC == ret) {
+ import_log_notice(job, "ERROR: NO DISK SPACE LEFT in sweep phase");
+ } else {
+ import_log_notice(job, "ERROR: Sweep phase error %d (%s)", ret,
+ dblayer_strerror(ret));
+ }
+ }
+
+ return ret;
+}
+
+/* when the import is done, this function is called to bring stuff back up.
+ * returns 0 on success; anything else is an error
+ */
+static int import_all_done(ImportJob *job, int ret)
+{
+ ldbm_instance *inst = job->inst;
+
+ /* Writing this file indicates to future server startups that
+ * the db is OK */
+ if (ret == 0) {
+ char inst_dir[MAXPATHLEN*2];
+ char *inst_dirp = NULL;
+ inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ inst_dir, MAXPATHLEN*2);
+ ret = dbversion_write(inst->inst_li, inst_dirp, NULL);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ }
+
+ if (job->task != NULL && 0 == job->task->task_refcount) {
+ /* exit code */
+ job->task->task_exitcode = ret;
+ job->task->task_state = SLAPI_TASK_FINISHED;
+ job->task->task_progress = job->task->task_work;
+ job->task->task_private = NULL;
+ slapi_task_status_changed(job->task);
+ }
+
+ if (job->flags & FLAG_ONLINE) {
+ /* start up the instance */
+ ret = dblayer_instance_start(job->inst->inst_be, DBLAYER_NORMAL_MODE);
+ if (ret != 0)
+ return ret;
+
+ /* bring backend online again */
+ slapi_mtn_be_enable(inst->inst_be);
+ }
+
+ return ret;
+}
+
+
+int import_main_offline(void *arg)
+{
+ ImportJob *job = (ImportJob *)arg;
+ ldbm_instance *inst = job->inst;
+ backend *be = inst->inst_be;
+ int ret = 0;
+ time_t beginning = 0;
+ time_t end = 0;
+ int finished = 0;
+ int status = 0;
+ int verbose = 1;
+ ImportWorkerInfo *producer = NULL;
+
+ if (job->task)
+ job->task->task_refcount++;
+
+ PR_ASSERT(inst != NULL);
+ time(&beginning);
+
+ /* Decide which indexes are needed */
+ if (job->flags & FLAG_INDEX_ATTRS) {
+ /* Here, we get an AVL tree which contains nodes for all attributes
+ * in the schema. Given this tree, we need to identify those nodes
+ * which are marked for indexing. */
+ avl_apply(job->inst->inst_attrs, (IFP)import_attr_callback,
+ (caddr_t)job, -1, AVL_INORDER);
+ vlv_getindices((IFP)import_attr_callback, (void *)job, be);
+ }
+
+ /* Determine how much index buffering space to allocate to each index */
+ import_set_index_buffer_size(job);
+
+ /* initialize the entry FIFO */
+ ret = import_fifo_init(job);
+ if (ret) {
+ if (! (job->flags & FLAG_USE_FILES)) {
+ PR_Lock(job->wire_lock);
+ PR_NotifyCondVar(job->wire_cv);
+ PR_Unlock(job->wire_lock);
+ }
+ goto error;
+ }
+
+ if (job->flags & FLAG_USE_FILES) {
+ /* importing from files: start up a producer thread to read the
+ * files and queue them
+ */
+ producer = CALLOC(ImportWorkerInfo);
+ if (! producer)
+ goto error;
+
+ /* start the producer */
+ import_init_worker_info(producer, job);
+ producer->work_type = PRODUCER;
+#if defined(UPGRADEDB)
+ if (job->flags & FLAG_REINDEXING)
+ {
+ if (! CREATE_THREAD(PR_USER_THREAD, (VFP)index_producer, producer,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "unable to spawn index producer thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ goto error;
+ }
+ }
+ else
+#endif
+ {
+ import_log_notice(job, "Beginning import job...");
+ if (! CREATE_THREAD(PR_USER_THREAD, (VFP)import_producer, producer,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_BOUND_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "unable to spawn import producer thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ goto error;
+ }
+ }
+
+ if (0 == job->job_index_buffer_suggestion)
+ import_log_notice(job, "Index buffering is disabled.");
+ else
+ import_log_notice(job,
+ "Index buffering enabled with bucket size %lu",
+ job->job_index_buffer_suggestion);
+
+ job->worker_list = producer;
+ } else {
+ /* release the startup lock and let the entries start queueing up
+ * in for import */
+ PR_Lock(job->wire_lock);
+ PR_NotifyCondVar(job->wire_cv);
+ PR_Unlock(job->wire_lock);
+ }
+
+ /* Run as many passes as we need to complete the job or die honourably in
+ * the attempt */
+ while (! finished) {
+ job->current_pass++;
+ job->total_pass++;
+ ret = import_run_pass(job, &status);
+ /* The following could have happened:
+ * (a) Some error happened such that we're hosed.
+ * This is indicated by a non-zero return code.
+ * (b) We finished the complete file without needing a second pass
+ * This is indicated by a zero return code and a status of
+ * IMPORT_COMPLETE_PASS and current_pass == 1;
+ * (c) We completed a pass and need at least another one
+ * This is indicated by a zero return code and a status of
+ * IMPORT_INCOMPLETE_PASS
+ * (d) We just completed what turned out to be the last in a
+ * series of passes
+ * This is indicated by a zero return code and a status of
+ * IMPORT_COMPLETE_PASS and current_pass > 1
+ */
+ if (ret == ERR_IMPORT_ABORTED) {
+ /* at least one of the threads has aborted -- shut down ALL
+ * of the threads */
+ import_log_notice(job, "Aborting all import threads...");
+ /* this abort sets the abort flag on the threads and will block for
+ * the exit of all threads
+ */
+ import_set_abort_flag_all(job, 1);
+ import_log_notice(job, "Import threads aborted.");
+ goto error;
+ }
+
+ if (0 != ret) {
+ /* Some horrible fate has befallen the import */
+ import_log_notice(job, "Fatal pass error %d", ret);
+ goto error;
+ }
+
+ /* No error, but a number of possibilities */
+ if ( IMPORT_COMPLETE_PASS == status ) {
+ if (1 == job->current_pass) {
+ /* We're done !!!! */ ;
+ } else {
+ /* Save the files, then merge */
+ ret = import_sweep_after_pass(job);
+ if (0 != ret) {
+ goto error;
+ }
+ ret = import_mega_merge(job);
+ if (0 != ret) {
+ goto error;
+ }
+ }
+ finished = 1;
+ } else {
+ if (IMPORT_INCOMPLETE_PASS == status) {
+ /* Need to go round again */
+ /* Time to save the files we've built for later */
+ ret = import_sweep_after_pass(job);
+ if (0 != ret) {
+ goto error;
+ }
+ if ( (inst->inst_li->li_maxpassbeforemerge != 0) &&
+ (job->current_pass > inst->inst_li->li_maxpassbeforemerge) )
+ {
+ ret = import_mega_merge(job);
+ if (0 != ret) {
+ goto error;
+ }
+ job->current_pass = 1;
+ ret = import_sweep_after_pass(job);
+ if (0 != ret) {
+ goto error;
+ }
+ }
+
+ /* Fixup the first_ID value to reflect previous work */
+ job->first_ID = job->ready_ID + 1;
+ import_free_thread_data(job);
+ job->worker_list = producer;
+ import_log_notice(job, "Beginning pass number %d",
+ job->total_pass+1);
+ } else {
+ /* Bizarro-slapd */
+ goto error;
+ }
+ }
+ }
+
+ /* kill the producer now; we're done */
+ if (producer) {
+ import_log_notice(job, "Cleaning up producer thread...");
+ producer->command = STOP;
+ /* wait for the lead thread to stop */
+ while (producer->state != FINISHED) {
+ DS_Sleep(PR_MillisecondsToInterval(100));
+ }
+ }
+
+ /* Now do the numsubordinates attribute */
+ import_log_notice(job, "Indexing complete. Post-processing...");
+ /* [610066] reindexed db cannot be used in the following backup/restore */
+ if ( !(job->flags & FLAG_REINDEXING) &&
+ (ret = update_subordinatecounts(be, job->mothers, NULL)) != 0) {
+ import_log_notice(job, "Failed to update numsubordinates attributes");
+ goto error;
+ }
+
+ /* And the ancestorid index */
+ if ((ret = ldbm_ancestorid_create_index(be)) != 0) {
+ import_log_notice(job, "Failed to create ancestorid index");
+ goto error;
+ }
+
+ import_log_notice(job, "Flushing caches...");
+ if (0 != (ret = dblayer_flush(job->inst->inst_li)) ) {
+ import_log_notice(job, "Failed to flush database");
+ goto error;
+ }
+
+ /* New way to exit the routine: check the return code.
+ * If it's non-zero, delete the database files.
+ * Otherwise don't, but always close the database layer properly.
+ * Then return. This ensures that we can't make a half-good/half-bad
+ * Database. */
+
+error:
+ /* If we fail, the database is now in a mess, so we delete it */
+ import_log_notice(job, "Closing files...");
+ cache_clear(&job->inst->inst_cache);
+ if (0 != ret) {
+ dblayer_delete_instance_dir(be);
+ dblayer_instance_close(job->inst->inst_be);
+ } else {
+ if (0 != (ret = dblayer_instance_close(job->inst->inst_be)) ) {
+ import_log_notice(job, "Failed to close database");
+ }
+ }
+ if (!(job->flags & FLAG_ONLINE))
+ dblayer_close(job->inst->inst_li, DBLAYER_IMPORT_MODE);
+
+ time(&end);
+ if (verbose && (0 == ret)) {
+ int seconds_to_import = end - beginning;
+ size_t entries_processed = job->lead_ID - (job->starting_ID - 1);
+ double entries_per_second = (double) entries_processed /
+ (double) seconds_to_import;
+
+ if (job->not_here_skipped)
+ {
+ if (job->skipped)
+ import_log_notice(job, "Import complete. Processed %lu entries "
+ "(%d bad entries were skipped, "
+ "%d entries were skipped because they don't "
+ "belong to this database) in %d seconds. "
+ "(%.2f entries/sec)", entries_processed,
+ job->skipped, job->not_here_skipped,
+ seconds_to_import, entries_per_second);
+ else
+ import_log_notice(job, "Import complete. Processed %lu entries "
+ "(%d entries were skipped because they don't "
+ "belong to this database) "
+ "in %d seconds. (%.2f entries/sec)",
+ entries_processed, job->not_here_skipped,
+ seconds_to_import, entries_per_second);
+ }
+ else
+ {
+ if (job->skipped)
+ import_log_notice(job, "Import complete. Processed %lu entries "
+ "(%d were skipped) in %d seconds. "
+ "(%.2f entries/sec)", entries_processed,
+ job->skipped, seconds_to_import,
+ entries_per_second);
+ else
+ import_log_notice(job, "Import complete. Processed %lu entries "
+ "in %d seconds. (%.2f entries/sec)",
+ entries_processed, seconds_to_import,
+ entries_per_second);
+ }
+ }
+
+ if (0 != ret) {
+ import_log_notice(job, "Import failed.");
+ if (job->task != NULL) {
+ job->task->task_state = SLAPI_TASK_FINISHED;
+ job->task->task_exitcode = ret;
+ slapi_task_status_changed(job->task);
+ }
+ } else {
+ if (job->task)
+ job->task->task_refcount--;
+
+ import_all_done(job, ret);
+ }
+
+ /* This instance isn't busy anymore */
+ instance_set_not_busy(job->inst);
+
+ import_free_job(job);
+ if (producer)
+ FREE(producer);
+
+
+ return(ret);
+}
+
+/*
+ * to be called by online import using PR_CreateThread()
+ * offline import directly calls import_main_offline()
+ *
+ */
+void import_main(void *arg)
+{
+ import_main_offline(arg);
+}
+
+int ldbm_back_ldif2ldbm_deluxe(Slapi_PBlock *pb)
+{
+ backend *be = NULL;
+ int noattrindexes = 0;
+ ImportJob *job = NULL;
+ char **name_array = NULL;
+ int total_files, i;
+ PRThread *thread = NULL;
+
+ job = CALLOC(ImportJob);
+ if (job == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "not enough memory to do import job\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be);
+ PR_ASSERT(NULL != be);
+ job->inst = (ldbm_instance *)be->be_instance_info;
+ slapi_pblock_get( pb, SLAPI_LDIF2DB_NOATTRINDEXES, &noattrindexes );
+ slapi_pblock_get( pb, SLAPI_LDIF2DB_FILE, &name_array );
+
+ /* the removedupvals field is blatantly overloaded here to mean
+ * the chunk size too. (chunk size = number of entries that should
+ * be imported before starting a new pass. usually for debugging.)
+ */
+ slapi_pblock_get(pb, SLAPI_LDIF2DB_REMOVEDUPVALS, &job->merge_chunk_size);
+ if (job->merge_chunk_size == 1)
+ job->merge_chunk_size = 0;
+ /* get list of specifically included and/or excluded subtrees from
+ * the front-end */
+ ldbm_back_fetch_incl_excl(pb, &job->include_subtrees,
+ &job->exclude_subtrees);
+ /* get cn=tasks info, if any */
+ slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &job->task);
+ slapi_pblock_get(pb, SLAPI_LDIF2DB_ENCRYPT, &job->encrypt);
+ /* get uniqueid info */
+ slapi_pblock_get(pb, SLAPI_LDIF2DB_GENERATE_UNIQUEID, &job->uuid_gen_type);
+ if (job->uuid_gen_type == SLAPI_UNIQUEID_GENERATE_NAME_BASED) {
+ char *namespaceid;
+
+ slapi_pblock_get(pb, SLAPI_LDIF2DB_NAMESPACEID, &namespaceid);
+ job->uuid_namespace = slapi_ch_strdup(namespaceid);
+ }
+
+ job->flags = FLAG_USE_FILES;
+#if defined(UPGRADEDB)
+ if (NULL == name_array) /* no ldif file is given -> reindexing */
+ job->flags |= FLAG_REINDEXING;
+#endif
+ if (!noattrindexes)
+ job->flags |= FLAG_INDEX_ATTRS;
+ for (i = 0; name_array && name_array[i] != NULL; i++)
+ charray_add(&job->input_filenames, slapi_ch_strdup(name_array[i]));
+ job->starting_ID = 1;
+ job->first_ID = 1;
+ job->mothers = CALLOC(import_subcount_stuff);
+
+ /* how much space should we allocate to index buffering? */
+ job->job_index_buffer_size = import_get_index_buffer_size();
+ if (job->job_index_buffer_size == 0) {
+ /* 10% of the allocated cache size + one meg */
+ PR_Lock(job->inst->inst_li->li_config_mutex);
+ job->job_index_buffer_size = (job->inst->inst_li->li_import_cachesize/10) +
+ (1024*1024);
+ PR_Unlock(job->inst->inst_li->li_config_mutex);
+ }
+ import_subcount_stuff_init(job->mothers);
+
+ if (job->task != NULL) {
+ /* count files, use that to track "progress" in cn=tasks */
+ total_files = 0;
+ while (name_array && name_array[total_files] != NULL)
+ total_files++;
+ /* add 1 to account for post-import cleanup (which can take a
+ * significant amount of time)
+ */
+ if (0 == total_files) /* reindexing */
+ job->task->task_work = 2;
+ else
+ job->task->task_work = total_files + 1;
+ job->task->task_progress = 0;
+ job->task->task_state = SLAPI_TASK_RUNNING;
+ job->task->task_private = job;
+ job->task->destructor = import_task_destroy;
+ job->task->cancel = import_task_abort;
+ job->flags |= FLAG_ONLINE;
+
+ /* create thread for import_main, so we can return */
+ thread = PR_CreateThread(PR_USER_THREAD, import_main, (void *)job,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to spawn import thread, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+ import_free_job(job);
+ FREE(job);
+ return -2;
+ }
+ return 0;
+ }
+
+ /* old style -- do it all synchronously (THIS IS GOING AWAY SOON) */
+ return import_main_offline((void *)job);
+}
diff --git a/ldap/servers/slapd/back-ldbm/import.h b/ldap/servers/slapd/back-ldbm/import.h
new file mode 100644
index 00000000..866ef9f8
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/import.h
@@ -0,0 +1,199 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * structures & constants used for the import code
+ */
+
+
+/* Number of lines in the entry above which we switch to
+ using a tree to check for attribute presence in str2entry().
+ */
+#define STR2ENTRY_ATTRIBUTE_PRESENCE_CHECK_THRESHOLD 100
+
+#define IMPORT_ADD_OP_ATTRS_OK 0
+#define IMPORT_ADD_OP_ATTRS_NO_PARENT 1
+
+#define IMPORT_COMPLETE_PASS 1
+#define IMPORT_INCOMPLETE_PASS 2
+
+/* Constants for index buffering */
+#define IMPORT_MAX_INDEX_BUFFER_SIZE 100
+#define IMPORT_MIN_INDEX_BUFFER_SIZE 5
+#define IMPORT_INDEX_BUFFER_SIZE_CONSTANT (20*20*20*sizeof(ID))
+
+static const int import_sleep_time = 200; /* in millisecs */
+
+extern char *numsubordinates;
+extern char *hassubordinates;
+
+typedef struct _import_worker_info ImportWorkerInfo;
+typedef struct _import_index_info IndexInfo;
+
+
+/* structure which describes an indexing job */
+struct _import_index_info
+{
+ char *name;
+ struct attrinfo *ai;
+ IndexInfo *next;
+};
+
+/* item on the entry FIFO */
+typedef struct {
+ struct backentry *entry;
+ char *filename; /* or NULL */
+ int line; /* filename/line are used to report errors */
+ int bad; /* foreman did not like the entry */
+ size_t esize; /* entry size */
+} FifoItem;
+
+typedef struct {
+ FifoItem *item;
+ size_t size; /* Queue size in entries (computed in import_fifo_init). */
+ size_t bsize; /* Queue limitation in max bytes */
+ size_t c_bsize; /* Current queue size in bytes */
+} Fifo;
+
+/* notes on the import gang:
+ * 1. producer: reads the file(s), performs str2entry() and assigns IDs.
+ * job->lead_ID is the last entry in the FIFO it's decoded. as it
+ * circles the FIFO, it pauses whenever it runs into an entry with a
+ * non-zero refcount, and waits for the worker threads to finish.
+ * 2. foreman: reads the FIFO (up to lead_ID), adding operational attrs,
+ * and creating the entrydn & id2entry indexes. job->ready_ID is the
+ * last entry in the FIFO it's finished with. (workers can't browse
+ * the entries it's working on because it's effectively modifying the
+ * entry.)
+ * 3. workers (one for each other index): read the FIFO (up to ready_ID),
+ * creating the index for a particular attribute.
+ */
+
+/* Structure holding stuff about the whole import job */
+#define IMPORT_JOB_PROG_HISTORY_SIZE 3
+typedef struct {
+ ldbm_instance *inst; /* db instance we're importing to */
+ Slapi_Task *task; /* cn=tasks entry ptr */
+ int flags; /* (see below) */
+ char **input_filenames; /* NULL-terminated list of charz pointers */
+ IndexInfo *index_list; /* A list of indexing jobs to do */
+ ImportWorkerInfo *worker_list; /* A list of threads to work on the
+ * indexes */
+ size_t number_indexers; /* count of the indexer threads (not including
+ * the primary) */
+ ID starting_ID; /* Import starts work at this ID */
+ ID first_ID; /* Import pass starts at this ID */
+ ID lead_ID; /* Highest ID available in the cache */
+ ID ready_ID; /* Highest ID the foreman is done with */
+ ID trailing_ID; /* Lowest ID still available in the cache */
+ int current_pass; /* un-merged pass number in a multi-pass import */
+ int total_pass; /* total pass number in a multi-pass import */
+ int skipped; /* # entries skipped because they were bad */
+ int not_here_skipped; /* # entries skipped because they belong
+ * to another backend */
+ size_t merge_chunk_size; /* Allows us to manually override the magic
+ * voodoo logic for deciding when to begin
+ * another pass */
+ int uuid_gen_type; /* kind of uuid to generate */
+ char *uuid_namespace; /* namespace for name-generated uuid */
+ import_subcount_stuff *mothers;
+ double average_progress_rate;
+ double recent_progress_rate;
+ double cache_hit_ratio;
+ time_t start_time;
+ ID progress_history[IMPORT_JOB_PROG_HISTORY_SIZE];
+ time_t progress_times[IMPORT_JOB_PROG_HISTORY_SIZE];
+ size_t job_index_buffer_size; /* Suggested size of index buffering
+ * for all indexes */
+ size_t job_index_buffer_suggestion; /* Suggested size of index buffering
+ * for one index */
+ char **include_subtrees; /* list of subtrees to import */
+ char **exclude_subtrees; /* list of subtrees to NOT import */
+ Fifo fifo; /* entry fifo for indexing */
+ char *task_status; /* transient state info for the end-user */
+ PRLock *wire_lock; /* lock for serializing wire imports */
+ PRCondVar *wire_cv; /* ... and ordering the startup */
+ PRThread *main_thread; /* for FRI: import_main() thread id */
+ int encrypt;
+} ImportJob;
+
+#define FLAG_INDEX_ATTRS 0x01 /* should we index the attributes? */
+#define FLAG_USE_FILES 0x02 /* import from files */
+#define FLAG_PRODUCER_DONE 0x04 /* frontend is done sending entries
+ * for replica initialization */
+#define FLAG_ABORT 0x08 /* import has been aborted */
+#define FLAG_ONLINE 0x10 /* bring backend online when done */
+#if defined(UPGRADEDB)
+#define FLAG_REINDEXING 0x20 /* read from id2entry and do indexing */
+#endif
+
+
+/* Structure holding stuff about a worker thread and what it's up to */
+struct _import_worker_info {
+ int work_type; /* What sort of work is this ? */
+ int command; /* Used to control the thread */
+ int state; /* Thread indicates its state here */
+ IndexInfo *index_info; /* info on what we're asked to do */
+ ID last_ID_processed;
+ ID previous_ID_counted; /* Used by the monitor to calculate progress
+ * rate */
+ double rate; /* Number of IDs processed per second */
+ ID first_ID; /* Tell the thread to start at this ID */
+ ImportJob *job;
+ ImportWorkerInfo *next;
+ size_t index_buffer_size; /* Size of index buffering for this index */
+};
+
+/* Values for work_type */
+#define WORKER 1
+#define FOREMAN 2
+#define PRODUCER 3
+
+/* Values for command */
+#define RUN 1
+#define PAUSE 2
+#define ABORT 3
+#define STOP 4
+
+/* Values for state */
+#define WAITING 1
+#define RUNNING 2
+#define FINISHED 3
+#define ABORTED 4
+
+/* this is just a convenience, because the slapi_ch_* calls are annoying */
+#define CALLOC(name) (name *)slapi_ch_calloc(1, sizeof(name))
+#define FREE(x) slapi_ch_free((void **)&(x))
+
+
+/* import.c */
+FifoItem *import_fifo_fetch(ImportJob *job, ID id, int worker);
+void import_free_job(ImportJob *job);
+void import_log_notice(ImportJob *job, char *format, ...);
+void import_abort_all(ImportJob *job, int wait_for_them);
+int import_entry_belongs_here(Slapi_Entry *e, backend *be);
+int import_make_merge_filenames(char *directory, char *indexname, int pass,
+ char **oldname, char **newname);
+void import_main(void *arg);
+int import_main_offline(void *arg);
+int ldbm_back_ldif2ldbm_deluxe(Slapi_PBlock *pb);
+
+/* import-merge.c */
+int import_mega_merge(ImportJob *job);
+
+/* ldif2ldbm.c */
+void reset_progress( void );
+void report_progress( int count, int done );
+int add_op_attrs(Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *ep,
+ int *status);
+
+/* import-threads.c */
+void import_producer(void *param);
+#if defined(UPGRADEDB)
+void index_producer(void *param);
+#endif
+void import_foreman(void *param);
+void import_worker(void *param);
+static void import_wait_for_space_in_fifo(ImportJob *job, size_t new_esize);
diff --git a/ldap/servers/slapd/back-ldbm/index.c b/ldap/servers/slapd/back-ldbm/index.c
new file mode 100644
index 00000000..c742c5fe
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/index.c
@@ -0,0 +1,1852 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* index.c - routines for dealing with attribute indexes */
+
+#include "back-ldbm.h"
+#if ( defined ( OSF1 ))
+#undef BUFSIZ
+#define BUFSIZ 1024
+#endif
+
+static const char *errmsg = "database index operation failed";
+
+static int is_indexed (const char* indextype, int indexmask, char** index_rules);
+static char* index2prefix (const char* indextype);
+static void free_prefix (char*);
+static Slapi_Value **
+valuearray_minus_valuearray(
+ void *plugin,
+ Slapi_Value **a,
+ Slapi_Value **b
+);
+static int index_addordel_values( backend *be, const char *type, struct berval **vals, struct berval **evals, ID id, int flags, back_txn *txn );
+static int index_addordel_values_ext( backend *be, const char *type, struct berval **vals, struct berval **evals, ID id, int flags, back_txn *txn,int *idl_disposition, void *buffer_handle );
+
+const char* indextype_PRESENCE = "pres";
+const char* indextype_EQUALITY = "eq";
+const char* indextype_APPROX = "approx";
+const char* indextype_SUB = "sub";
+
+static char prefix_PRESENCE[2] = {PRES_PREFIX, 0};
+static char prefix_EQUALITY[2] = {EQ_PREFIX, 0};
+static char prefix_APPROX [2] = {APPROX_PREFIX, 0};
+static char prefix_SUB [2] = {SUB_PREFIX, 0};
+
+/* Yes, prefix_PRESENCE and prefix_SUB are identical.
+ * It works because SUB is always followed by a key value,
+ * but PRESENCE never is. Too slick by half.
+ */
+
+
+/* Structures for index key buffering magic used by import code */
+struct _index_buffer_bin {
+ DBT key;
+ IDList *value;
+};
+typedef struct _index_buffer_bin index_buffer_bin;
+
+struct _index_buffer_handle {
+ int flags;
+ size_t buffer_size;
+ size_t idl_size;
+ size_t max_key_length;
+ index_buffer_bin *bins;
+ unsigned char high_key_byte_range;
+ unsigned char low_key_byte_range;
+ unsigned char special_byte_a;
+ unsigned char special_byte_b;
+ size_t byte_range;
+ /* Statistics */
+ int inserts;
+ int keys;
+};
+typedef struct _index_buffer_handle index_buffer_handle;
+#define INDEX_BUFFER_FLAG_SERIALIZE 1
+#define INDEX_BUFFER_FLAG_STATS 2
+
+/* Index buffering functions */
+
+static int
+index_buffer_init_internal(size_t idl_size,
+ unsigned char high_key_byte_range, unsigned char low_key_byte_range,
+ size_t max_key_length,unsigned char special_byte_a, unsigned char special_byte_b,
+ int flags,void **h)
+{
+ size_t bin_count = 0;
+ /* Allocate the handle */
+ index_buffer_bin *bins = NULL;
+ size_t i = 0;
+ size_t byte_range = 0;
+
+ index_buffer_handle *handle = (index_buffer_handle *) slapi_ch_calloc(1,sizeof(index_buffer_handle));
+ if (NULL == handle) {
+ return -1;
+ }
+ handle->idl_size = idl_size;
+ handle->flags = flags;
+ handle->high_key_byte_range = high_key_byte_range;
+ handle->low_key_byte_range = low_key_byte_range;
+ handle->special_byte_a = special_byte_a;
+ handle->special_byte_b = special_byte_b;
+ handle->max_key_length = max_key_length;
+ byte_range = (high_key_byte_range - low_key_byte_range) + 3 + 10;
+ handle->byte_range = byte_range;
+ /* Allocate the bins */
+ bin_count = 1;
+ for (i = 0 ; i < max_key_length - 2; i++) {
+ bin_count *= byte_range;
+ }
+ handle->buffer_size = bin_count;
+ bins = (index_buffer_bin *)slapi_ch_calloc(bin_count, sizeof(index_buffer_bin));
+ if (NULL == bins) {
+ return -1;
+ }
+ handle->bins = bins;
+ *h = (void*) handle;
+ return 0;
+}
+
+int index_buffer_init(size_t size,int flags,void **h)
+{
+ return index_buffer_init_internal(size,'z','a',5,'^','$',flags,h);
+}
+
+static int
+index_put_idl(index_buffer_bin *bin,backend *be, DB_TXN *txn,struct attrinfo *a)
+{
+ int ret = 0;
+ DB *db = NULL;
+ int need_to_freed_new_idl = 0;
+ IDList *old_idl = NULL;
+ IDList *new_idl = NULL;
+
+ if ( (ret = dblayer_get_index_file( be, a, &db, DBOPEN_CREATE )) != 0 ) {
+ return ret;
+ }
+ if (bin->key.data && bin->value) {
+ /* Need to read the IDL at the key, if present, and form the union with what we have */
+ ret = NEW_IDL_NOOP; /* this flag is for new idl only;
+ * but this func is called only from index_buffer,
+ * which is enabled only for old idl.
+ */
+ old_idl = idl_fetch(be,db,&bin->key,txn,a,&ret);
+ if ( (0 != ret) && (DB_NOTFOUND != ret)) {
+ goto error;
+ }
+ if ( (old_idl != NULL) && !ALLIDS(old_idl)) {
+ /* We need to merge in our block with what was there */
+ new_idl = idl_union(be,old_idl,bin->value);
+ need_to_freed_new_idl = 1;
+ } else {
+ /* Nothing there previously, we store just what we have */
+ new_idl = bin->value;
+ }
+ /* Then write back the result, but only if the existing idl wasn't ALLIDS */
+ if (!old_idl || (old_idl && !ALLIDS(old_idl))) {
+ ret = idl_store_block(be,db,&bin->key,new_idl,txn,a);
+ }
+ if (0 != ret) {
+ goto error;
+ }
+ slapi_ch_free((void**)&bin->key.data );
+ idl_free(bin->value);
+ /* If we're already at allids, store an allids block to prevent needless accumulation of blocks */
+ if (old_idl && ALLIDS(old_idl)) {
+ bin->value = idl_allids(be);
+ } else {
+ bin->value = NULL;
+ }
+ }
+error:
+ if (old_idl) {
+ idl_free(old_idl);
+ }
+ if (new_idl && need_to_freed_new_idl) {
+ idl_free(new_idl);
+ }
+ dblayer_release_index_file( be, a, db );
+ return ret;
+}
+
+/* The caller MUST check for DB_RUNRECOVERY being returned */
+
+int
+index_buffer_flush(void *h,backend *be, DB_TXN *txn,struct attrinfo *a)
+{
+ index_buffer_handle *handle = (index_buffer_handle *) h;
+ index_buffer_bin *bin = NULL;
+ int ret = 0;
+ size_t i = 0;
+ DB *db = NULL;
+
+ PR_ASSERT(h);
+
+ /* Note to the wary: here we do NOT create the index file up front */
+ /* This is becuase there may be no buffers to flush, and the goal is to
+ * never create the index file (merging gets confused by this, among other things */
+
+ /* Walk along the bins, writing them to the database */
+ for (i = 0; i < handle->buffer_size; i++) {
+ bin = &(handle->bins[i]);
+ if (bin->key.data && bin->value) {
+ if (NULL == db) {
+ if ( (ret = dblayer_get_index_file( be, a, &db, DBOPEN_CREATE )) != 0 ) {
+ return ret;
+ }
+ }
+ ret = index_put_idl(bin,be,txn,a);
+ if (0 != ret) {
+ goto error;
+ }
+ }
+ }
+error:
+ if (NULL != db) {
+ dblayer_release_index_file( be, a, db );
+ }
+ return ret;
+}
+
+int
+index_buffer_terminate(void *h)
+{
+ index_buffer_handle *handle = (index_buffer_handle *) h;
+ index_buffer_bin *bin = NULL;
+ size_t i = 0;
+
+ PR_ASSERT(h);
+ /* Free all the buffers */
+ /* First walk down the bins, freeing the IDLs and the bins they're in */
+ for (i = 0; i < handle->buffer_size; i++) {
+ bin = &(handle->bins[i]);
+ if (bin->value) {
+ idl_free(bin->value);
+ bin->value = NULL;
+ }
+ if (bin->key.data) {
+ free(bin->key.data);
+ }
+ }
+ free(handle->bins);
+ /* Now free the handle */
+ free(handle);
+ return 0;
+}
+
+/* This function returns -1 or -2 for local errors, and DB_ errors as well. */
+
+static int
+index_buffer_insert(void *h, DBT *key, ID id,backend *be, DB_TXN *txn,struct attrinfo *a)
+{
+ index_buffer_handle *handle = (index_buffer_handle *) h;
+ index_buffer_bin *bin = NULL;
+ size_t index = 0;
+ int idl_ret = 0;
+ unsigned char x = 0;
+ unsigned int i = 0;
+ int ret = 0;
+
+ PR_ASSERT(h);
+
+ /* Check key length for validity */
+ if (key->size > handle->max_key_length) {
+ return -2;
+ }
+ /* discard the first character, as long as its the substring prefix */
+ if ((unsigned char)((char*)key->data)[0] != SUB_PREFIX) {
+ return -2;
+ }
+ /* Compute the bin index from the key */
+ /* Walk along the key data, byte by byte */
+ for (i = 1; i < (key->size - 1); i++) {
+ /* foreach byte, normalize to the range we accept */
+ x = (unsigned char) ((char*)key->data)[i];
+ if ( (x == handle->special_byte_a) || (x == handle->special_byte_b) ) {
+ if (x == handle->special_byte_a) {
+ x = handle->high_key_byte_range + 1;
+ }
+ if (x == handle->special_byte_b) {
+ x = handle->high_key_byte_range + 2;
+ }
+ } else {
+ if ( x >= '0' && x <= '9' ) {
+ x = (x - '0') + handle->high_key_byte_range + 3;
+ } else {
+ if (x > handle->high_key_byte_range) {
+ return -2; /* Out of range */
+ }
+ if (x < handle->low_key_byte_range) {
+ return -2; /* Out of range */
+ }
+ }
+ }
+ x = x - handle->low_key_byte_range;
+ index *= handle->byte_range;
+ index += x;
+ }
+ /* Check that the last byte in the key is zero */
+ if (0 != (unsigned char)((char*)key->data)[i]) {
+ return -2;
+ }
+ PR_ASSERT(index < handle->buffer_size);
+ /* Get the bin */
+ bin = &(handle->bins[index]);
+ /* Is the key already there ? */
+retry:
+ if (!(bin->key).data) {
+ (bin->key).size = key->size;
+ (bin->key).data = malloc(key->size);
+ if (NULL == bin->key.data) {
+ return -1;
+ }
+ memcpy(bin->key.data,key->data,key->size);
+ /* Make the IDL */
+ bin->value = idl_alloc(handle->idl_size);
+ if (!bin->value) {
+ return -1;
+ }
+ }
+ idl_ret = idl_append(bin->value, id);
+ if (0 != idl_ret) {
+ if (1 == idl_ret) {
+ /* ID already present */
+ } else {
+ /* If we get to here, it means that we've overflowed our IDL */
+ /* So, we need to write it out to the DB and zero out the pointers */
+ ret = index_put_idl(bin,be,txn,a);
+ /* Now we need to append the ID we have at hand */
+ if (0 == ret) {
+ goto retry;
+ }
+ }
+ }
+ return ret;
+}
+
+/*
+ * Add or Delete an entry from the attribute indexes.
+ * 'flags' is either BE_INDEX_ADD or BE_INDEX_DEL
+ */
+int
+index_addordel_entry(
+ backend *be,
+ struct backentry *e,
+ int flags,
+ back_txn *txn
+)
+{
+ char *type;
+ Slapi_Value **svals;
+ int rc, result;
+ Slapi_Attr *attr;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> index_%s_entry( \"%s\", %lu )\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del",
+ backentry_get_ndn(e), (u_long)e->ep_id );
+
+ /* if we are adding a tombstone entry (see ldbm_add.c) */
+ if ((flags & BE_INDEX_TOMBSTONE) && (flags & BE_INDEX_ADD))
+ {
+ Slapi_DN parent;
+ Slapi_DN *sdn = slapi_entry_get_sdn(e->ep_entry);
+ slapi_sdn_init(&parent);
+ slapi_sdn_get_parent(sdn, &parent);
+ /*
+ * Just index the "nstombstone" attribute value from the objectclass
+ * attribute, and the nsuniqueid attribute value, and the entrydn value of the deleted entry.
+ */
+ result = index_addordel_string(be, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE, e->ep_id, flags, txn);
+ if ( result != 0 ) {
+ ldbm_nasty(errmsg, 1010, result);
+ return( result );
+ }
+ result = index_addordel_string(be, SLAPI_ATTR_UNIQUEID, slapi_entry_get_uniqueid(e->ep_entry), e->ep_id, flags, txn);
+ if ( result != 0 ) {
+ ldbm_nasty(errmsg, 1020, result);
+ return( result );
+ }
+ result = index_addordel_string(be, SLAPI_ATTR_NSCP_ENTRYDN, slapi_sdn_get_ndn(&parent), e->ep_id, flags, txn);
+ if ( result != 0 ) {
+ ldbm_nasty(errmsg, 1020, result);
+ return( result );
+ }
+ slapi_sdn_done(&parent);
+ }
+ else
+ {
+ /* add each attribute to the indexes */
+ rc = 0, result = 0;
+ for ( rc = slapi_entry_first_attr( e->ep_entry, &attr ); rc == 0;
+ rc = slapi_entry_next_attr( e->ep_entry, attr, &attr ) ) {
+ slapi_attr_get_type( attr, &type );
+ svals = attr_get_present_values(attr);
+ result = index_addordel_values_sv( be, type, svals, NULL, e->ep_id,
+ flags, txn );
+ if ( result != 0 ) {
+ ldbm_nasty(errmsg, 1030, result);
+ return( result );
+ }
+ }
+
+ /* update ancestorid index . . . */
+ /* . . . only if we are not deleting a tombstone entry - tombstone entries are not in the ancestor id index - see bug 603279 */
+ if (!((flags & BE_INDEX_TOMBSTONE) && (flags & BE_INDEX_DEL))) {
+ result = ldbm_ancestorid_index_entry(be, e, flags, txn);
+ if ( result != 0 ) {
+ return( result );
+ }
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= index_%s_entry%s %d\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del",
+ (flags & BE_INDEX_TOMBSTONE) ? " (tombstone)" : "", result );
+ return( result );
+}
+
+/*
+ * Add ID to attribute indexes for which Add/Replace/Delete modifications exist
+ * [olde is the OLD entry, before modifications]
+ * [newe is the NEW entry, after modifications]
+ * the old entry is used for REPLACE; the new for DELETE */
+int
+index_add_mods(
+ backend *be,
+ const LDAPMod **mods,
+ struct backentry *olde,
+ struct backentry *newe,
+ back_txn *txn
+)
+{
+ int rc = 0;
+ int i;
+ Slapi_Attr *attr;
+ ID id = olde->ep_id;
+ Slapi_Value **svals = NULL;
+
+ for ( i = 0; mods[i] != NULL; i++ ) {
+ switch ( mods[i]->mod_op & ~LDAP_MOD_BVALUES ) {
+ case LDAP_MOD_REPLACE:
+ /* We need to first remove the old values from the
+ * index. */
+ if ( slapi_entry_attr_find( olde->ep_entry, mods[i]->mod_type, &attr ) == 0 &&
+ (svals = attr_get_present_values(attr)) != NULL ) {
+ index_addordel_values_sv( be, mods[i]->mod_type,
+ svals, NULL, id,
+ BE_INDEX_DEL|BE_INDEX_PRESENCE,
+ txn );
+ }
+ case LDAP_MOD_ADD:
+ if ( mods[i]->mod_bvalues == NULL ) {
+ rc = 0;
+ } else {
+ Slapi_Value **mods_valueArray = NULL;
+ valuearray_init_bervalarray(mods[i]->mod_bvalues,
+ &mods_valueArray);
+ rc = index_addordel_values_sv( be,
+ mods[i]->mod_type,
+ mods_valueArray, NULL,
+ id, BE_INDEX_ADD, txn );
+ valuearray_free(&mods_valueArray);
+ }
+ break;
+
+ case LDAP_MOD_DELETE:
+ if ( (mods[i]->mod_bvalues == NULL) ||
+ (mods[i]->mod_bvalues[0] == NULL) ) {
+ rc = 0;
+ /* if no value are specified all the values will
+ * be suppressed -> remove the presence index
+ */
+ if ( slapi_entry_attr_find( olde->ep_entry, mods[i]->mod_type, &attr ) == 0 &&
+ (svals = attr_get_present_values(attr)) != NULL ) {
+ index_addordel_values_sv( be, mods[i]->mod_type,
+ svals, NULL, id, BE_INDEX_DEL|BE_INDEX_PRESENCE, txn);
+ }
+ } else {
+ /* determine if the presence key should be
+ * removed (are we removing the last value
+ * for this attribute?)
+ */
+ int flags = BE_INDEX_DEL;
+ Slapi_Value ** svals = NULL;
+ Slapi_Value **mods_valueArray = NULL;
+
+ valuearray_init_bervalarray(mods[i]->mod_bvalues,
+ &mods_valueArray);
+
+ if (slapi_entry_attr_find(newe->ep_entry,
+ mods[i]->mod_type, &attr) == 0) {
+ svals = attr_get_present_values(attr);
+ }
+
+ if (svals == NULL || svals[0] == NULL) {
+ flags |= BE_INDEX_PRESENCE;
+ }
+
+ rc = index_addordel_values_sv( be, mods[i]->mod_type,
+ mods_valueArray,
+ svals, id, flags, txn );
+ valuearray_free(&mods_valueArray);
+ }
+ rc = 0;
+ break;
+ }
+
+ if ( rc != 0 ) {
+ ldbm_nasty(errmsg, 1040, rc);
+ return( rc );
+ }
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * Convert a 'struct berval' into a displayable ASCII string
+ */
+
+#define SPECIAL(c) (c < 32 || c > 126 || c == '\\' || c == '"')
+
+const char*
+encode (const struct berval* data, char buf[BUFSIZ])
+{
+ char* s;
+ char* last;
+ if (data == NULL || data->bv_len == 0) return "";
+ last = data->bv_val + data->bv_len - 1;
+ for (s = data->bv_val; s < last; ++s) {
+ if ( SPECIAL (*s)) {
+ char* first = data->bv_val;
+ char* bufNext = buf;
+ size_t bufSpace = BUFSIZ - 4;
+ while (1) {
+/* printf ("%lu bytes ASCII\n", (unsigned long)(s - first)); */
+ if (bufSpace < (size_t)(s - first)) s = first + bufSpace - 1;
+ if (s != first) {
+ memcpy (bufNext, first, s - first);
+ bufNext += (s - first);
+ bufSpace -= (s - first);
+ }
+ do {
+ *bufNext++ = '\\'; --bufSpace;
+ if (bufSpace < 2) {
+ memcpy (bufNext, "..", 2);
+ bufNext += 2;
+ goto bail;
+ }
+ if (*s == '\\' || *s == '"') {
+ *bufNext++ = *s; --bufSpace;
+ } else {
+ sprintf (bufNext, "%02x", (unsigned)*(unsigned char*)s);
+ bufNext += 2; bufSpace -= 2;
+ }
+ } while (++s <= last && SPECIAL (*s));
+ if (s > last) break;
+ first = s;
+ while ( ! SPECIAL (*s) && s <= last) ++s;
+ }
+ bail:
+ *bufNext = '\0';
+/* printf ("%lu chars in buffer\n", (unsigned long)(bufNext - buf)); */
+ return buf;
+ }
+ }
+/* printf ("%lu bytes, all ASCII\n", (unsigned long)(s - data->bv_val)); */
+ return data->bv_val;
+}
+
+static const char*
+encoded (DBT* d, char buf [BUFSIZ])
+{
+ struct berval data;
+ data.bv_len = d->dsize;
+ data.bv_val = d->dptr;
+ return encode (&data, buf);
+}
+
+IDList *
+index_read(
+ backend *be,
+ char *type,
+ const char *indextype,
+ const struct berval *val,
+ back_txn *txn,
+ int *err
+)
+{
+ return index_read_ext(be, type, indextype, val, txn, err, NULL);
+}
+
+/*
+ * Extended version of index_read.
+ * The unindexed flag can be used to distinguish between a
+ * return of allids due to the attr not being indexed or
+ * the value really being allids.
+ */
+IDList *
+index_read_ext(
+ backend *be,
+ char *type,
+ const char *indextype,
+ const struct berval *val,
+ back_txn *txn,
+ int *err,
+ int *unindexed
+)
+{
+ DB *db = NULL;
+ DB_TXN *db_txn = NULL;
+ DBT key = {0};
+ IDList *idl;
+ char *prefix;
+ char *tmpbuf = NULL;
+ char buf[BUFSIZ];
+ char typebuf[ SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH ];
+ struct attrinfo *ai = NULL;
+ char *basetmp, *basetype;
+ int retry_count = 0;
+ struct berval *encrypted_val = NULL;
+
+ *err = 0;
+
+ if (unindexed != NULL) *unindexed = 0;
+ prefix = index2prefix( indextype );
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> index_read( \"%s\" %s \"%s\" )\n",
+ type, prefix, encode (val, buf));
+
+ basetype = typebuf;
+ if ( (basetmp = slapi_attr_basetype( type, typebuf, sizeof(typebuf) ))
+ != NULL ) {
+ basetype = basetmp;
+ }
+
+ ainfo_get( be, basetype, &ai );
+ if (ai == NULL) {
+ free_prefix( prefix );
+ slapi_ch_free_string( &basetmp );
+ return NULL;
+ }
+
+ LDAPDebug( LDAP_DEBUG_ARGS, " indextype: \"%s\" indexmask: 0x%x\n",
+ indextype, ai->ai_indexmask, 0 );
+
+ if ( !is_indexed( indextype, ai->ai_indexmask, ai->ai_index_rules ) ) {
+ idl = idl_allids( be );
+ if (unindexed != NULL) *unindexed = 1;
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= index_read %lu candidates "
+ "(allids - not indexed)\n", (u_long)IDL_NIDS(idl), 0, 0 );
+ free_prefix( prefix );
+ slapi_ch_free_string( &basetmp );
+ return( idl );
+ }
+ if ( (*err = dblayer_get_index_file( be, ai, &db, DBOPEN_CREATE )) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= index_read NULL (index file open for attr %s)\n",
+ basetype, 0, 0 );
+ free_prefix (prefix);
+ slapi_ch_free_string( &basetmp );
+ return( NULL );
+ }
+ slapi_ch_free_string( &basetmp );
+
+ if ( val != NULL ) {
+ size_t plen, vlen;
+ char *realbuf;
+ int ret = 0;
+
+ /* If necessary, encrypt this index key */
+ ret = attrcrypt_encrypt_index_key(be, ai, val, &encrypted_val);
+ if (ret) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "index_read failed to encrypt index key for %s\n",
+ basetype, 0, 0 );
+ }
+ if (encrypted_val) {
+ val = encrypted_val;
+ }
+ plen = strlen( prefix );
+ vlen = val->bv_len;
+ realbuf = (plen + vlen < sizeof(buf)) ?
+ buf : (tmpbuf = slapi_ch_malloc( plen + vlen + 1 ));
+ memcpy( realbuf, prefix, plen );
+ memcpy( realbuf+plen, val->bv_val, vlen );
+ realbuf[plen+vlen] = '\0';
+ key.data = realbuf;
+ key.size = key.ulen = plen + vlen + 1;
+ key.flags = DB_DBT_USERMEM;
+ } else {
+ key.data = prefix;
+ key.size = key.ulen = strlen( prefix ) + 1; /* include 0 terminator */
+ key.flags = DB_DBT_USERMEM;
+ }
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ }
+ for (retry_count = 0; retry_count < IDL_FETCH_RETRY_COUNT; retry_count++) {
+ *err = NEW_IDL_DEFAULT;
+ idl = idl_fetch( be, db, &key, db_txn, ai, err );
+ if(*err == DB_LOCK_DEADLOCK) {
+ ldbm_nasty("index read retrying transaction", 1045, *err);
+ continue;
+ } else {
+ break;
+ }
+ }
+ if(retry_count == IDL_FETCH_RETRY_COUNT) {
+ ldbm_nasty("index_read retry count exceeded",1046,*err);
+ } else if ( *err != 0 && *err != DB_NOTFOUND ) {
+ ldbm_nasty(errmsg, 1050, *err);
+ }
+ slapi_ch_free_string(&tmpbuf);
+
+ dblayer_release_index_file( be, ai, db );
+
+ free_prefix (prefix);
+
+ if (encrypted_val) {
+ ber_bvfree(encrypted_val);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= index_read %lu candidates\n",
+ (u_long)IDL_NIDS(idl), 0, 0 );
+ return( idl );
+}
+
+static int
+DBTcmp (DBT* L, DBT* R)
+{
+ struct berval Lv;
+ struct berval Rv;
+ Lv.bv_val = L->dptr; Lv.bv_len = L->dsize;
+ Rv.bv_val = R->dptr; Rv.bv_len = R->dsize;
+ return slapi_berval_cmp (&Lv, &Rv);
+}
+
+#define DBT_EQ(L,R) ((L)->dsize == (R)->dsize &&\
+ ! memcmp ((L)->dptr, (R)->dptr, (L)->dsize))
+
+
+#define DBT_FREE_PAYLOAD(d) if ((d).data) {free((d).data);(d).data=NULL;}
+
+/* Steps to the next key without keeping a cursor open */
+/* Returns the new key value in the DBT */
+static int index_range_next_key(DB *db,DBT *key,DB_TXN *db_txn)
+{
+ DBC *cursor = NULL;
+ DBT data = {0};
+ int ret = 0;
+ void *saved_key = key->data;
+
+ /* Make cursor */
+retry:
+ ret = db->cursor(db,db_txn,&cursor, 0);
+ if (0 != ret) {
+ return ret;
+ }
+ /* Seek to the last key */
+ data.flags = DB_DBT_MALLOC;
+ ret = cursor->c_get(cursor,key,&data,DB_SET); /* data allocated here, we don't need it */
+ DBT_FREE_PAYLOAD(data);
+ if (DB_NOTFOUND == ret) {
+ void *old_key_buffer = key->data;
+ /* If this happens, it means that we tried to seek to a key which has just been deleted */
+ /* So, we seek to the nearest one instead */
+ ret = cursor->c_get(cursor,key,&data,DB_SET_RANGE);
+ /* a new key and data are allocated here, need to free them both */
+ if (old_key_buffer != key->data) {
+ DBT_FREE_PAYLOAD(*key);
+ }
+ DBT_FREE_PAYLOAD(data);
+ }
+ if (0 != ret) {
+ if (DB_LOCK_DEADLOCK == ret)
+ {
+ /* Deadlock detected, retry the operation */
+ cursor->c_close(cursor);
+ cursor = NULL;
+ key->data = saved_key;
+ goto retry;
+ } else
+ {
+ goto error;
+ }
+ }
+ /* Seek to the next one
+ * [612498] NODUP is needed for new idl to get the next non-duplicated key
+ * No effect on old idl since there's no dup there (i.e., DB_NEXT == DB_NEXT_NODUP)
+ */
+ ret = cursor->c_get(cursor,key,&data,DB_NEXT_NODUP); /* new key and data are allocated, we only need the key */
+ DBT_FREE_PAYLOAD(data);
+ if (DB_LOCK_DEADLOCK == ret)
+ {
+ /* Deadlock detected, retry the operation */
+ cursor->c_close(cursor);
+ cursor = NULL;
+ key->data = saved_key;
+ goto retry;
+ }
+error:
+ /* Close the cursor */
+ cursor->c_close(cursor);
+ if (saved_key) { /* Need to free the original key passed in */
+ if (saved_key == key->data) {
+ /* Means that we never allocated a new key */
+ ;
+ } else {
+ free(saved_key);
+ }
+ }
+ return ret;
+}
+
+IDList *
+index_range_read(
+ Slapi_PBlock *pb,
+ backend *be,
+ char *type,
+ const char *indextype,
+ int operator,
+ struct berval *val,
+ struct berval *nextval,
+ int range,
+ back_txn *txn,
+ int *err
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ DB *db;
+ DB_TXN *db_txn = NULL;
+ DBC *dbc = NULL;
+ DBT lowerkey = {0};
+ DBT upperkey = {0};
+ DBT cur_key = {0};
+ DBT data = {0} ;
+ IDList *idl= NULL;
+ char *prefix;
+ char *realbuf, *nextrealbuf;
+ size_t reallen, nextreallen;
+ size_t plen;
+ ID i;
+ struct attrinfo *ai = NULL;
+ int lookthrough_limit = -1; /* default no limit */
+ int retry_count = 0;
+ int is_and = 0;
+ int sizelimit = 0;
+
+ *err = 0;
+ plen = strlen( prefix = index2prefix( indextype ));
+ slapi_pblock_get(pb, SLAPI_SEARCH_IS_AND, &is_and);
+ if (!is_and)
+ {
+ slapi_pblock_get(pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit);
+ }
+
+ /*
+ * Determine the lookthrough_limit from the PBlock.
+ * No limit if there is no PBlock supplied or if there is no
+ * search result set and the requestor is root.
+ */
+ if (pb != NULL) {
+ back_search_result_set *sr = NULL;
+
+ slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &sr );
+ if (sr != NULL) {
+ /* the normal case */
+ lookthrough_limit = sr->sr_lookthroughlimit;
+ } else {
+ int isroot = 0;
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ if (!isroot) {
+ lookthrough_limit = li->li_lookthroughlimit;
+ }
+ }
+ }
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "index_range_read lookthrough_limit=%d\n",
+ lookthrough_limit, 0, 0);
+
+ switch( operator ) {
+ case SLAPI_OP_LESS:
+ case SLAPI_OP_LESS_OR_EQUAL:
+ case SLAPI_OP_GREATER_OR_EQUAL:
+ case SLAPI_OP_GREATER:
+ break;
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "<= index_range_read(%s,%s) NULL (operator %i)\n",
+ type, prefix, operator );
+ return( NULL );
+ }
+ ainfo_get( be, type, &ai );
+ if (ai == NULL) return NULL;
+ LDAPDebug( LDAP_DEBUG_ARGS, " indextype: \"%s\" indexmask: 0x%x\n",
+ indextype, ai->ai_indexmask, 0 );
+ if ( !is_indexed( indextype, ai->ai_indexmask, ai->ai_index_rules )) {
+ idl = idl_allids( be );
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= index_range_read(%s,%s) %lu candidates (allids)\n",
+ type, prefix, (u_long)IDL_NIDS(idl) );
+ return( idl );
+ }
+ if ( (*err = dblayer_get_index_file( be, ai, &db, DBOPEN_CREATE )) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "<= index_range_read(%s,%s) NULL (could not open index file)\n",
+ type, prefix, 0 );
+ return( NULL ); /* why not allids? */
+ }
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ }
+ /* get a cursor so we can walk over the table */
+ *err = db->cursor(db,db_txn,&dbc,0);
+ if (0 != *err ) {
+ ldbm_nasty(errmsg, 1060, *err);
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "<= index_range_read(%s,%s) NULL: db->cursor() == %i\n",
+ type, prefix, *err );
+ dblayer_release_index_file( be, ai, db );
+ return( NULL ); /* why not allids? */
+ }
+
+ /* set up the starting and ending keys for a range search */
+ if ( val != NULL ) { /* compute a key from val */
+ const size_t vlen = val->bv_len;
+ reallen = plen + vlen + 1;
+ realbuf = slapi_ch_malloc( reallen );
+ memcpy( realbuf, prefix, plen );
+ memcpy( realbuf+plen, val->bv_val, vlen );
+ realbuf[plen+vlen] = '\0';
+ } else {
+ reallen = plen + 1; /* include 0 terminator */
+ realbuf = slapi_ch_strdup(prefix);
+ }
+ if (range != 1) {
+ char *tmpbuf = NULL;
+ /* this is a search with only one boundary value */
+ switch( operator ) {
+ case SLAPI_OP_LESS:
+ case SLAPI_OP_LESS_OR_EQUAL:
+ lowerkey.dptr = slapi_ch_strdup(prefix);
+ lowerkey.dsize = plen;
+ upperkey.dptr = realbuf;
+ upperkey.dsize = reallen;
+ break;
+ case SLAPI_OP_GREATER_OR_EQUAL:
+ case SLAPI_OP_GREATER:
+ lowerkey.dptr = realbuf;
+ lowerkey.dsize = reallen;
+ /* upperkey = a value slightly greater than prefix */
+ tmpbuf = slapi_ch_malloc (plen + 1);
+ memcpy (tmpbuf, prefix, plen + 1);
+ ++(tmpbuf[plen-1]);
+ upperkey.dptr = tmpbuf;
+ upperkey.dsize = plen;
+ tmpbuf = NULL;
+ /* ... but not greater than the last key in the index */
+ cur_key.flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ *err = dbc->c_get(dbc,&cur_key,&data,DB_LAST); /* key and data allocated here, need to free them */
+ DBT_FREE_PAYLOAD(data);
+ /* Note that cur_key needs to get freed somewhere below */
+ if (0 != *err) {
+ if (DB_NOTFOUND == *err) {
+ /* There are no keys in the index so we should return no candidates. */
+ *err = 0;
+ idl = NULL;
+ slapi_ch_free( (void**)&realbuf);
+ dbc->c_close(dbc);
+ goto error;
+ } else {
+ ldbm_nasty(errmsg, 1070, *err);
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "index_range_read(%s,%s) seek to end of index file err %i\n",
+ type, prefix, *err );
+ }
+ } else if (DBTcmp (&upperkey, &cur_key) > 0) {
+ tmpbuf = slapi_ch_realloc (tmpbuf, cur_key.dsize);
+ memcpy (tmpbuf, cur_key.dptr, cur_key.dsize);
+ DBT_FREE_PAYLOAD(upperkey);
+ upperkey.dptr = tmpbuf;
+ upperkey.dsize = cur_key.dsize;
+ }
+ break;
+ }
+ } else {
+ /* this is a search with two boundary values (starting and ending) */
+ if ( nextval != NULL ) { /* compute a key from nextval */
+ const size_t vlen = nextval->bv_len;
+ nextreallen = plen + vlen + 1;
+ nextrealbuf = slapi_ch_malloc( plen + vlen + 1 );
+ memcpy( nextrealbuf, prefix, plen );
+ memcpy( nextrealbuf+plen, nextval->bv_val, vlen );
+ nextrealbuf[plen+vlen] = '\0';
+ } else {
+ nextreallen = plen + 1; /* include 0 terminator */
+ nextrealbuf = slapi_ch_strdup(prefix);
+ }
+ /* set up the starting and ending keys for search */
+ switch( operator ) {
+ case SLAPI_OP_LESS:
+ case SLAPI_OP_LESS_OR_EQUAL:
+ lowerkey.dptr = nextrealbuf;
+ lowerkey.dsize = nextreallen;
+ upperkey.dptr = realbuf;
+ upperkey.dsize = reallen;
+ break;
+ case SLAPI_OP_GREATER_OR_EQUAL:
+ case SLAPI_OP_GREATER:
+ lowerkey.dptr = realbuf;
+ lowerkey.dsize = reallen;
+ upperkey.dptr = nextrealbuf;
+ upperkey.dsize = nextreallen;
+ break;
+ }
+ }
+ /* if (LDAP_DEBUG_FILTER) {
+ char encbuf [BUFSIZ];
+ LDAPDebug( LDAP_DEBUG_FILTER, " lowerkey=%s(%li bytes)\n",
+ encoded (&lowerkey, encbuf), (long)lowerkey.dsize, 0 );
+ LDAPDebug( LDAP_DEBUG_FILTER, " upperkey=%s(%li bytes)\n",
+ encoded (&upperkey, encbuf), (long)upperkey.dsize, 0 );
+ } */
+ data.flags = DB_DBT_MALLOC;
+ lowerkey.flags = DB_DBT_MALLOC;
+ {
+ void *old_lower_key_data = lowerkey.data;
+ *err = dbc->c_get(dbc,&lowerkey,&data,DB_SET_RANGE); /* lowerkey, if allocated and needs freed */
+ DBT_FREE_PAYLOAD(data);
+ if (old_lower_key_data != lowerkey.data) {
+ free(old_lower_key_data);
+ }
+ }
+ /* If the seek above fails due to DB_NOTFOUND, this means that there are no keys
+ which are >= the target key. This means that we should return no candidates */
+ if (0 != *err) {
+ /* Free the key we just read above */
+ DBT_FREE_PAYLOAD(lowerkey);
+ if (DB_NOTFOUND == *err) {
+ *err = 0;
+ idl = NULL;
+ } else {
+ idl = idl_allids( be );
+ ldbm_nasty(errmsg, 1080, *err);
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "<= index_range_read(%s,%s) allids (seek to lower key in index file err %i)\n",
+ type, prefix, *err );
+ }
+ dbc->c_close(dbc);
+ goto error;
+ }
+ /* We now close the cursor, since we're about to iterate over many keys */
+ *err = dbc->c_close(dbc);
+
+ /* step through the indexed db to retrive IDs within the search range */
+ DBT_FREE_PAYLOAD(cur_key);
+ cur_key.data = lowerkey.data;
+ cur_key.size = lowerkey.size;
+ lowerkey.data = NULL; /* Don't need this any more, since the memory will be freed from cur_key */
+ if (operator == SLAPI_OP_GREATER) {
+ *err = index_range_next_key(db,&cur_key,db_txn);
+ }
+ while (*err == 0 &&
+ (operator == SLAPI_OP_LESS) ?
+ DBTcmp(&cur_key, &upperkey) < 0 :
+ DBTcmp(&cur_key, &upperkey) <= 0) {
+ /* exit the loop when we either run off the end of the table,
+ * fail to read a key, or read a key that's out of range.
+ */
+ IDList *tmp, *tmp2;
+ /*
+ char encbuf [BUFSIZ];
+ LDAPDebug( LDAP_DEBUG_FILTER, " cur_key=%s(%li bytes)\n",
+ encoded (&cur_key, encbuf), (long)cur_key.dsize, 0 );
+ */
+ /* Check to see if we've already looked too hard */
+ if (idl != NULL && lookthrough_limit != -1 && idl->b_nids > (ID)lookthrough_limit) {
+ if (NULL != idl) {
+ idl_free(idl);
+ }
+ idl = idl_allids( be );
+ LDAPDebug(LDAP_DEBUG_TRACE, "index_range_read lookthrough_limit exceeded\n",
+ 0, 0, 0);
+ break;
+ }
+ if (idl != NULL && sizelimit > 0 && idl->b_nids > (ID)sizelimit)
+ {
+ LDAPDebug(LDAP_DEBUG_TRACE, "index_range_read sizelimit exceeded\n",
+ 0, 0, 0);
+ break;
+ }
+
+ /* Check to see if the operation has been abandoned (also happens
+ * when the connection is closed by the client).
+ */
+ if ( slapi_op_abandoned( pb )) {
+ if (NULL != idl) {
+ idl_free(idl);
+ idl = NULL;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "index_range_read - operation abandoned\n", 0, 0, 0);
+ break; /* clean up happens outside the while() loop */
+ }
+
+ /* the cur_key DBT already has the first entry in it when we enter the loop */
+ /* so we process the entry then step to the next one */
+ cur_key.flags = 0;
+ for (retry_count = 0; retry_count < IDL_FETCH_RETRY_COUNT; retry_count++) {
+ *err = NEW_IDL_DEFAULT;
+ tmp = idl_fetch( be, db, &cur_key, NULL, ai, err );
+ if(*err == DB_LOCK_DEADLOCK) {
+ ldbm_nasty("index_range_read retrying transaction", 1090, *err);
+ continue;
+ } else {
+ break;
+ }
+ }
+ if(retry_count == IDL_FETCH_RETRY_COUNT) {
+ ldbm_nasty("index_range_read retry count exceeded",1095,*err);
+ }
+ tmp2 = idl_union( be, idl, tmp );
+ idl_free( idl );
+ idl_free( tmp );
+ idl = tmp2;
+ if (ALLIDS(idl)) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "index_range_read hit an allids value\n",
+ 0, 0, 0);
+ break;
+ }
+ if (DBT_EQ (&cur_key, &upperkey)) { /* this is the last key */
+ break;
+ /* Another c_get would return the same key, with no error. */
+ }
+ data.flags = DB_DBT_MALLOC;
+ cur_key.flags = DB_DBT_MALLOC;
+ *err = index_range_next_key(db,&cur_key,db_txn);
+ /* *err = dbc->c_get(dbc,&cur_key,&data,DB_NEXT); */
+ if (*err == DB_NOTFOUND) {
+ *err = 0;
+ break;
+ }
+ }
+ if (*err) LDAPDebug( LDAP_DEBUG_FILTER, " dbc->c_get(...DB_NEXT) == %i\n", *err, 0, 0);
+#ifdef LDAP_DEBUG
+ /* this is for debugging only */
+ if (idl != NULL)
+ {
+ if (ALLIDS(idl)) {
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ " idl=ALLIDS\n", 0, 0, 0 );
+ } else {
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ " idl->b_nids=%d\n", idl->b_nids, 0, 0 );
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ " idl->b_nmax=%d\n", idl->b_nmax, 0, 0 );
+
+ for ( i= 0; i< idl->b_nids; i++)
+ {
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ " idl->b_ids[%d]=%d\n", i, idl->b_ids[i], 0);
+ }
+ }
+ }
+#endif
+error:
+ DBT_FREE_PAYLOAD(cur_key);
+ DBT_FREE_PAYLOAD(upperkey);
+
+ dblayer_release_index_file( be, ai, db );
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= index_range_read(%s,%s) %lu candidates\n",
+ type, prefix, (u_long)IDL_NIDS(idl) );
+ return( idl );
+}
+
+/* DBDB: this function is never actually called */
+#if 0
+static int
+addordel_values(
+ backend *be,
+ DB *db,
+ char *type,
+ const char *indextype,
+ struct berval **vals,
+ ID id,
+ int flags, /* BE_INDEX_ADD, etc */
+ back_txn *txn,
+ struct attrinfo *a,
+ int *idl_disposition,
+ void *buffer_handle
+)
+{
+ int rc = 0;
+ int i = 0;
+ DBT key = {0};
+ DB_TXN *db_txn = NULL;
+ size_t plen, vlen, len;
+ char *tmpbuf = NULL;
+ size_t tmpbuflen = 0;
+ char *realbuf;
+ char *prefix;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> %s_values\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del", 0, 0);
+
+ prefix = index2prefix( indextype );
+ if ( vals == NULL ) {
+ key.dptr = prefix;
+ key.dsize = strlen( prefix ) + 1; /* include null terminator */
+ key.flags = DB_DBT_MALLOC;
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ }
+
+ if (flags & BE_INDEX_ADD) {
+ rc = idl_insert_key( be, db, &key, id, db_txn, a, idl_disposition );
+ } else {
+ rc = idl_delete_key( be, db, &key, id, db_txn, a );
+ /* check for no such key/id - ok in some cases */
+ if ( rc == DB_NOTFOUND || rc == -666 ) {
+ rc = 0;
+ }
+ }
+
+ if ( rc != 0)
+ {
+ ldbm_nasty(errmsg, 1090, rc);
+ }
+ free_prefix (prefix);
+ if (NULL != key.dptr && prefix != key.dptr)
+ slapi_ch_free( (void**)&key.dptr );
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= %s_values %d\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del", rc, 0 );
+ return( rc );
+ }
+
+ plen = strlen( prefix );
+ for ( i = 0; vals[i] != NULL; i++ ) {
+ vlen = vals[i]->bv_len;
+ len = plen + vlen;
+
+ if ( len < tmpbuflen ) {
+ realbuf = tmpbuf;
+ } else {
+ tmpbuf = slapi_ch_realloc( tmpbuf, len + 1 );
+ tmpbuflen = len + 1;
+ realbuf = tmpbuf;
+ }
+
+ memcpy( realbuf, prefix, plen );
+ memcpy( realbuf+plen, vals[i]->bv_val, vlen );
+ realbuf[len] = '\0';
+ key.dptr = realbuf;
+ key.size = plen + vlen + 1;
+ /* should be okay to use USERMEM here because we know what
+ * the key is and it should never return a different value
+ * than the one we pass in.
+ */
+ key.flags = DB_DBT_USERMEM;
+ key.ulen = tmpbuflen;
+#ifdef LDAP_DEBUG
+ /* XXX if ( slapd_ldap_debug & LDAP_DEBUG_TRACE ) XXX */
+ {
+ char encbuf[BUFSIZ];
+
+ LDAPDebug (LDAP_DEBUG_TRACE, " %s_value(\"%s\")\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del",
+ encoded (&key, encbuf), 0);
+ }
+#endif
+
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ }
+
+ if ( flags & BE_INDEX_ADD ) {
+ if (buffer_handle) {
+ rc = index_buffer_insert(buffer_handle,&key,id,be,db_txn,a);
+ if (rc == -2) {
+ rc = idl_insert_key( be, db, &key, id, db_txn, a, idl_disposition );
+ }
+ } else {
+ rc = idl_insert_key( be, db, &key, id, db_txn, a, idl_disposition );
+ }
+ } else {
+ rc = idl_delete_key( be, db, &key, id, db_txn, a );
+ /* check for no such key/id - ok in some cases */
+ if ( rc == DB_NOTFOUND || rc == -666 ) {
+ rc = 0;
+ }
+ }
+ if ( rc != 0 ) {
+ ldbm_nasty(errmsg, 1100, rc);
+ break;
+ }
+ if ( NULL != key.dptr && realbuf != key.dptr) { /* realloc'ed */
+ tmpbuf = key.dptr;
+ tmpbuflen = key.size;
+ }
+ }
+ free_prefix (prefix);
+ if ( tmpbuf != NULL ) {
+ slapi_ch_free( (void**)&tmpbuf );
+ }
+
+ if ( rc != 0 )
+ {
+ ldbm_nasty(errmsg, 1110, rc);
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= %s_values %d\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del", rc, 0 );
+ return( rc );
+}
+#endif
+
+static int
+addordel_values_sv(
+ backend *be,
+ DB *db,
+ char *type,
+ const char *indextype,
+ Slapi_Value **vals,
+ ID id,
+ int flags, /* BE_INDEX_ADD, etc */
+ back_txn *txn,
+ struct attrinfo *a,
+ int *idl_disposition,
+ void *buffer_handle
+)
+{
+ int rc = 0;
+ int i = 0;
+ DBT key = {0};
+ DB_TXN *db_txn = NULL;
+ size_t plen, vlen, len;
+ char *tmpbuf = NULL;
+ size_t tmpbuflen = 0;
+ char *realbuf;
+ char *prefix;
+ const struct berval *bvp;
+ struct berval *encrypted_bvp = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> %s_values\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del", 0, 0);
+
+ prefix = index2prefix( indextype );
+ if ( vals == NULL ) {
+ key.dptr = prefix;
+ key.dsize = strlen( prefix ) + 1; /* include null terminator */
+ key.flags = DB_DBT_MALLOC;
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ }
+
+ if (flags & BE_INDEX_ADD) {
+ rc = idl_insert_key( be, db, &key, id, db_txn, a, idl_disposition );
+ } else {
+ rc = idl_delete_key( be, db, &key, id, db_txn, a );
+ /* check for no such key/id - ok in some cases */
+ if ( rc == DB_NOTFOUND || rc == -666 ) {
+ rc = 0;
+ }
+ }
+
+ if ( rc != 0 )
+ {
+ ldbm_nasty(errmsg, 1120, rc);
+ }
+ free_prefix (prefix);
+ if (NULL != key.dptr && prefix != key.dptr)
+ slapi_ch_free( (void**)&key.dptr );
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= %s_values %d\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del", rc, 0 );
+ return( rc );
+ }
+
+ plen = strlen( prefix );
+ for ( i = 0; vals[i] != NULL; i++ ) {
+ bvp = slapi_value_get_berval(vals[i]);
+
+ /* Encrypt the index key if necessary */
+ {
+ if (a->ai_attrcrypt && (0 == (flags & BE_INDEX_DONT_ENCRYPT)))
+ {
+ rc = attrcrypt_encrypt_index_key(be,a,bvp,&encrypted_bvp);
+ if (rc)
+ {
+ LDAPDebug (LDAP_DEBUG_ANY, "Failed to encrypt index key for %s\n", a->ai_type ,0,0);
+ } else {
+ bvp = encrypted_bvp;
+ }
+ }
+ }
+
+ vlen = bvp->bv_len;
+ len = plen + vlen;
+
+ if ( len < tmpbuflen ) {
+ realbuf = tmpbuf;
+ } else {
+ tmpbuf = slapi_ch_realloc( tmpbuf, len + 1 );
+ tmpbuflen = len + 1;
+ realbuf = tmpbuf;
+ }
+
+ memcpy( realbuf, prefix, plen );
+ memcpy( realbuf+plen, bvp->bv_val, vlen );
+ realbuf[len] = '\0';
+ key.dptr = realbuf;
+ key.size = plen + vlen + 1;
+ /* Free the encrypted berval if necessary */
+ if (encrypted_bvp)
+ {
+ ber_bvfree(encrypted_bvp);
+ encrypted_bvp = NULL;
+ }
+ /* should be okay to use USERMEM here because we know what
+ * the key is and it should never return a different value
+ * than the one we pass in.
+ */
+ key.flags = DB_DBT_USERMEM;
+ key.ulen = tmpbuflen;
+#ifdef LDAP_DEBUG
+ /* XXX if ( slapd_ldap_debug & LDAP_DEBUG_TRACE ) XXX */
+ {
+ char encbuf[BUFSIZ];
+
+ LDAPDebug (LDAP_DEBUG_TRACE, " %s_value(\"%s\")\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del",
+ encoded (&key, encbuf), 0);
+ }
+#endif
+
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ }
+
+ if ( flags & BE_INDEX_ADD ) {
+ if (buffer_handle) {
+ rc = index_buffer_insert(buffer_handle,&key,id,be,db_txn,a);
+ if (rc == -2) {
+ rc = idl_insert_key( be, db, &key, id, db_txn, a, idl_disposition );
+ }
+ } else {
+ rc = idl_insert_key( be, db, &key, id, db_txn, a, idl_disposition );
+ }
+ } else {
+ rc = idl_delete_key( be, db, &key, id, db_txn, a );
+ /* check for no such key/id - ok in some cases */
+ if ( rc == DB_NOTFOUND || rc == -666 ) {
+ rc = 0;
+ }
+ }
+ if ( rc != 0 ) {
+ ldbm_nasty(errmsg, 1130, rc);
+ break;
+ }
+ if ( NULL != key.dptr && realbuf != key.dptr) { /* realloc'ed */
+ tmpbuf = key.dptr;
+ tmpbuflen = key.size;
+ }
+ }
+ free_prefix (prefix);
+ if ( tmpbuf != NULL ) {
+ slapi_ch_free( (void**)&tmpbuf );
+ }
+
+ if ( rc != 0 )
+ {
+ ldbm_nasty(errmsg, 1140, rc);
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= %s_values %d\n",
+ (flags & BE_INDEX_ADD) ? "add" : "del", rc, 0 );
+ return( rc );
+}
+
+int
+index_addordel_string(backend *be, const char *type, const char *s, ID id, int flags, back_txn *txn)
+{
+ Slapi_Value *svp[2];
+ Slapi_Value sv;
+
+ memset(&sv,0,sizeof(Slapi_Value));
+ sv.bv.bv_len= strlen(s);
+ sv.bv.bv_val= (void*)s;
+ svp[0] = &sv;
+ svp[1] = NULL;
+ return index_addordel_values_ext_sv(be,type,svp,NULL,id,flags,txn,NULL,NULL);
+}
+
+int
+index_addordel_values_sv(
+ backend *be,
+ const char *type,
+ Slapi_Value **vals,
+ Slapi_Value **evals, /* existing values */
+ ID id,
+ int flags,
+ back_txn *txn
+)
+{
+ return index_addordel_values_ext_sv(be,type,vals,evals,
+ id,flags,txn,NULL,NULL);
+}
+
+int
+index_addordel_values_ext_sv(
+ backend *be,
+ const char *type,
+ Slapi_Value **vals,
+ Slapi_Value **evals,
+ ID id,
+ int flags,
+ back_txn *txn,
+ int *idl_disposition,
+ void *buffer_handle
+)
+{
+ DB *db;
+ struct attrinfo *ai = NULL;
+ int err = -1;
+ Slapi_Value **ivals;
+ char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
+ char *basetmp, *basetype;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "=> index_addordel_values( \"%s\", %lu )\n", type, (u_long)id, 0 );
+
+ basetype = buf;
+ if ( (basetmp = slapi_attr_basetype( type, buf, sizeof(buf) ))
+ != NULL ) {
+ basetype = basetmp;
+ }
+
+ ainfo_get( be, basetype, &ai );
+ if ( ai == NULL || ai->ai_indexmask == 0
+ || ai->ai_indexmask == INDEX_OFFLINE ) {
+ slapi_ch_free_string( &basetmp );
+ return( 0 );
+ }
+ LDAPDebug( LDAP_DEBUG_ARGS, " index_addordel_values indexmask 0x%x\n",
+ ai->ai_indexmask, 0, 0 );
+ if ( (err = dblayer_get_index_file( be, ai, &db, DBOPEN_CREATE )) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "<= index_read NULL (could not open index attr %s)\n",
+ basetype, 0, 0 );
+ slapi_ch_free_string( &basetmp );
+ if ( err != 0 ) {
+ ldbm_nasty(errmsg, 1210, err);
+ }
+ goto bad;
+ }
+
+ /*
+ * presence index entry
+ */
+ if (( ai->ai_indexmask & INDEX_PRESENCE ) &&
+ (flags & (BE_INDEX_ADD|BE_INDEX_PRESENCE))) {
+ /* on delete, only remove the presence index if the
+ * BE_INDEX_PRESENCE flag is set.
+ */
+ err = addordel_values_sv( be, db, basetype, indextype_PRESENCE,
+ NULL, id, flags, txn, ai, idl_disposition, NULL );
+ if ( err != 0 ) {
+ ldbm_nasty(errmsg, 1220, err);
+ goto bad;
+ }
+ }
+
+ /*
+ * equality index entry
+ */
+ if ( ai->ai_indexmask & INDEX_EQUALITY ) {
+ slapi_call_syntax_values2keys_sv( ai->ai_plugin, vals, &ivals,
+ LDAP_FILTER_EQUALITY );
+
+ err = addordel_values_sv( be, db, basetype, indextype_EQUALITY,
+ ivals != NULL ? ivals : vals, id, flags, txn, ai, idl_disposition, NULL );
+ if ( ivals != NULL ) {
+ valuearray_free( &ivals );
+ }
+ if ( err != 0 ) {
+ ldbm_nasty(errmsg, 1230, err);
+ goto bad;
+ }
+ }
+
+ /*
+ * approximate index entry
+ */
+ if ( ai->ai_indexmask & INDEX_APPROX ) {
+ slapi_call_syntax_values2keys_sv( ai->ai_plugin, vals, &ivals,
+ LDAP_FILTER_APPROX );
+
+ if ( ivals != NULL ) {
+ err = addordel_values_sv( be, db, basetype,
+ indextype_APPROX, ivals, id, flags, txn, ai, idl_disposition, NULL );
+ valuearray_free( &ivals );
+ if ( err != 0 ) {
+ ldbm_nasty(errmsg, 1240, err);
+ goto bad;
+ }
+ }
+ }
+
+ /*
+ * substrings index entry
+ */
+ if ( ai->ai_indexmask & INDEX_SUB ) {
+ Slapi_Value **esubvals = NULL;
+ Slapi_Value **substresult = NULL;
+ Slapi_Value **origvals = NULL;
+ slapi_call_syntax_values2keys_sv( ai->ai_plugin, vals, &ivals,
+ LDAP_FILTER_SUBSTRINGS );
+
+ origvals = ivals;
+ /* delete only: if the attribute has multiple values,
+ * figure out the substrings that should remain
+ * by slapi_call_syntax_values2keys,
+ * then get rid of them from the being deleted values
+ */
+ if ( evals != NULL ) {
+ slapi_call_syntax_values2keys_sv( ai->ai_plugin, evals, &esubvals,
+ LDAP_FILTER_SUBSTRINGS );
+ substresult = valuearray_minus_valuearray( ai->ai_plugin, ivals, esubvals );
+ ivals = substresult;
+ valuearray_free( &esubvals );
+ }
+ if ( ivals != NULL ) {
+ err = addordel_values_sv( be, db, basetype, indextype_SUB,
+ ivals, id, flags, txn, ai, idl_disposition, buffer_handle );
+ if ( ivals != origvals )
+ valuearray_free( &origvals );
+ valuearray_free( &ivals );
+ if ( err != 0 ) {
+ ldbm_nasty(errmsg, 1250, err);
+ goto bad;
+ }
+
+ ivals = NULL;
+ }
+ }
+
+ /*
+ * matching rule index entries
+ */
+ if ( ai->ai_indexmask & INDEX_RULES )
+ {
+ Slapi_PBlock* pb = slapi_pblock_new();
+ char** oid = ai->ai_index_rules;
+ for (; *oid != NULL; ++oid)
+ {
+ if(create_matchrule_indexer(&pb,*oid,basetype)==0)
+ {
+ char* officialOID = NULL;
+ if (!slapi_pblock_get (pb, SLAPI_PLUGIN_MR_OID, &officialOID) && officialOID != NULL)
+ {
+ Slapi_Value** keys = NULL;
+ matchrule_values_to_keys_sv(pb,vals,&keys);
+ if(keys != NULL && keys[0] != NULL)
+ {
+ /* we've computed keys */
+ err = addordel_values_sv (be, db, basetype, officialOID, keys, id, flags, txn, ai, idl_disposition, NULL);
+ if ( err != 0 )
+ {
+ ldbm_nasty(errmsg, 1260, err);
+ goto bad;
+ }
+ }
+ /*
+ * It would improve speed to save the indexer, for future use.
+ * But, for simplicity, we destroy it now:
+ */
+ destroy_matchrule_indexer(pb);
+ }
+ }
+ }
+ slapi_pblock_destroy (pb);
+ }
+
+ dblayer_release_index_file( be, ai, db );
+ if ( basetmp != NULL ) {
+ slapi_ch_free( (void**)&basetmp );
+ }
+
+ LDAPDebug (LDAP_DEBUG_TRACE, "<= index_addordel_values\n", 0, 0, 0 );
+ return( 0 );
+
+ bad:
+ dblayer_release_index_file(be, ai, db);
+ return err;
+}
+
+int
+index_delete_values(
+ struct ldbminfo *li,
+ char *type,
+ struct berval **vals,
+ ID id
+)
+{
+ return -1;
+}
+
+static int
+is_indexed (const char* indextype, int indexmask, char** index_rules)
+{
+ int indexed;
+ if (indextype == indextype_PRESENCE) indexed = INDEX_PRESENCE & indexmask;
+ else if (indextype == indextype_EQUALITY) indexed = INDEX_EQUALITY & indexmask;
+ else if (indextype == indextype_APPROX) indexed = INDEX_APPROX & indexmask;
+ else if (indextype == indextype_SUB) indexed = INDEX_SUB & indexmask;
+ else { /* matching rule */
+ indexed = 0;
+ if (INDEX_RULES & indexmask) {
+ char** rule;
+ for (rule = index_rules; *rule; ++rule) {
+ if ( ! strcmp( *rule, indextype )) {
+ indexed = INDEX_RULES;
+ break;
+ }
+ }
+ }
+ }
+
+ /* if index is currently being generated, pretend it doesn't exist */
+ if (indexmask & INDEX_OFFLINE)
+ indexed = 0;
+
+ return indexed;
+}
+
+static char*
+index2prefix (const char* indextype)
+{
+ char* prefix;
+ if ( indextype == indextype_PRESENCE ) prefix = prefix_PRESENCE;
+ else if ( indextype == indextype_EQUALITY ) prefix = prefix_EQUALITY;
+ else if ( indextype == indextype_APPROX ) prefix = prefix_APPROX;
+ else if ( indextype == indextype_SUB ) prefix = prefix_SUB;
+ else { /* indextype is a matching rule name */
+ const size_t len = strlen (indextype);
+ char* p = slapi_ch_malloc (len + 3);
+ p[0] = RULE_PREFIX;
+ memcpy( p+1, indextype, len );
+ p[len+1] = ':';
+ p[len+2] = '\0';
+ prefix = p;
+ }
+ return( prefix );
+}
+
+static void
+free_prefix (char* prefix)
+{
+ if (prefix == NULL ||
+ prefix == prefix_PRESENCE ||
+ prefix == prefix_EQUALITY ||
+ prefix == prefix_APPROX ||
+ prefix == prefix_SUB) {
+ /* do nothing */
+ } else {
+ slapi_ch_free( (void**)&prefix);
+ }
+}
+
+/* helper stuff for valuearray_minus_valuearray */
+
+typedef struct {
+ value_compare_fn_type cmp_fn;
+ Slapi_Value *data;
+} SVSORT;
+
+static int
+svsort_cmp(const void *x, const void *y)
+{
+ return ((SVSORT*)x)->cmp_fn(slapi_value_get_berval(((SVSORT*)x)->data),
+ slapi_value_get_berval(((SVSORT*)y)->data));
+}
+
+static int
+bvals_strcasecmp(const struct berval *a, const struct berval *b)
+{
+ return strcasecmp(a->bv_val, b->bv_val);
+}
+
+/* a - b = c */
+/* the returned array of Slapi_Value needs to be freed. */
+static Slapi_Value **
+valuearray_minus_valuearray(
+ void *plugin,
+ Slapi_Value **a,
+ Slapi_Value **b
+)
+{
+ int rc, i, j, k, acnt, bcnt;
+ SVSORT *atmp = NULL, *btmp = NULL;
+ Slapi_Value **c;
+ value_compare_fn_type cmp_fn;
+
+ /* get berval comparison function */
+ plugin_call_syntax_get_compare_fn(plugin, &cmp_fn);
+ if (cmp_fn == NULL) {
+ cmp_fn = (value_compare_fn_type)bvals_strcasecmp;
+ }
+
+ /* determine length of a */
+ for (acnt = 0; a[acnt] != NULL; acnt++);
+
+ /* determine length of b */
+ for (bcnt = 0; b[bcnt] != NULL; bcnt++);
+
+ /* allocate return array as big as a */
+ c = (Slapi_Value**)calloc(acnt+1, sizeof(Slapi_Value*));
+ if (acnt == 0) return c;
+
+ /* sort a */
+ atmp = (SVSORT*) slapi_ch_malloc(acnt*sizeof(SVSORT));
+ for (i = 0; i < acnt; i++) {
+ atmp[i].cmp_fn = cmp_fn;
+ atmp[i].data = a[i];
+ }
+ qsort((void*)atmp, acnt, (size_t)sizeof(SVSORT), svsort_cmp);
+
+ /* sort b */
+ if (bcnt > 0) {
+ btmp = (SVSORT*) slapi_ch_malloc(bcnt*sizeof(SVSORT));
+ for (i = 0; i < bcnt; i++) {
+ btmp[i].cmp_fn = cmp_fn;
+ btmp[i].data = b[i];
+ }
+ qsort((void*)btmp, bcnt, (size_t)sizeof(SVSORT), svsort_cmp);
+ }
+
+ /* lock step through a and b */
+ for (i = 0, j = 0, k = 0; i < acnt && j < bcnt; ) {
+ rc = svsort_cmp(&atmp[i], &btmp[j]);
+ if (rc == 0) {
+ i++;
+ } else if (rc < 0) {
+ c[k++] = slapi_value_new_value(atmp[i++].data);
+ } else {
+ j++;
+ }
+ }
+
+ /* copy what's left from a */
+ while (i < acnt) {
+ c[k++] = slapi_value_new_value(atmp[i++].data);
+ }
+
+ /* clean up */
+ slapi_ch_free((void**)&atmp);
+ if (btmp) slapi_ch_free((void**)&btmp);
+
+ return c;
+}
diff --git a/ldap/servers/slapd/back-ldbm/init.c b/ldap/servers/slapd/back-ldbm/init.c
new file mode 100644
index 00000000..a740ce76
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/init.c
@@ -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 **/
+/* init.c - initialize ldbm backend */
+
+#include "back-ldbm.h"
+#include "../slapi-plugin.h"
+#include "idlapi.h"
+
+static void *IDL_api[3];
+
+static Slapi_PluginDesc pdesc = { "ldbm-backend", PLUGIN_MAGIC_VENDOR_STR,
+ PRODUCTTEXT, "high-performance LDAP backend database plugin" };
+
+static int add_ldbm_internal_attr_syntax( const char *name, const char *oid,
+ const char *syntax, const char *mr_equality, unsigned long extraflags );
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void
+plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+int
+ldbm_back_init( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li;
+ int rc;
+ struct slapdplugin *p;
+ static int interface_published = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldbm_back_init\n", 0, 0, 0 );
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN, &p);
+
+ /* allocate backend-specific stuff */
+ li = (struct ldbminfo *) slapi_ch_calloc( 1, sizeof(struct ldbminfo) );
+
+ /* Record the identity of the ldbm plugin. The plugin
+ * identity is used during internal ops. */
+ slapi_pblock_get(pb, SLAPI_PLUGIN_IDENTITY, &(li->li_identity));
+
+ /* keep a pointer back to the plugin */
+ li->li_plugin = p;
+
+ /* set shutdown flag to zero.*/
+ li->li_shutdown = 0;
+
+ /* Initialize the set of instances. */
+ li->li_instance_set = objset_new(&ldbm_back_instance_set_destructor);
+
+ /* initialize dblayer */
+ if (dblayer_init(li)) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ldbm_back_init: dblayer_init failed\n",0, 0, 0 );
+ return (-1);
+ }
+
+ /* Fill in the fields of the ldbminfo and the dblayer_private
+ * structures with some default values */
+ ldbm_config_setup_default(li);
+
+ /* ask the factory to give us space in the Connection object
+ * (only bulk import uses this)
+ */
+ if (slapi_register_object_extension(p->plg_name, SLAPI_EXT_CONNECTION,
+ factory_constructor, factory_destructor,
+ &li->li_bulk_import_object, &li->li_bulk_import_handle) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm_back_init: "
+ "slapi_register_object_extension failed.\n", 0, 0, 0);
+ return (-1);
+ }
+
+ /* add some private attributes */
+ rc = add_ldbm_internal_attr_syntax( "entrydn",
+ LDBM_ENTRYDN_OID, DN_SYNTAX_OID, DNMATCH_NAME,
+ SLAPI_ATTR_FLAG_SINGLE );
+
+ rc = add_ldbm_internal_attr_syntax( "dncomp",
+ LDBM_DNCOMP_OID, DN_SYNTAX_OID, DNMATCH_NAME,
+ 0 );
+
+ rc = add_ldbm_internal_attr_syntax( "parentid",
+ LDBM_PARENTID_OID, DIRSTRING_SYNTAX_OID, CASEIGNOREMATCH_NAME,
+ SLAPI_ATTR_FLAG_SINGLE );
+
+ rc = add_ldbm_internal_attr_syntax( "entryid",
+ LDBM_ENTRYID_OID, DIRSTRING_SYNTAX_OID, CASEIGNOREMATCH_NAME,
+ SLAPI_ATTR_FLAG_SINGLE );
+
+ /* set plugin private pointer and initialize locks, etc. */
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_PRIVATE, (void *) li );
+
+ if ((li->li_dbcache_mutex = PR_NewLock()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ldbm_back_init: PR_NewLock failed\n",
+ 0, 0, 0 );
+ return(-1);
+ }
+
+ if ((li->li_shutdown_mutex = PR_NewLock()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ldbm_back_init: PR_NewLock failed\n",
+ 0, 0, 0 );
+ return(-1);
+ }
+
+ if ((li->li_config_mutex = PR_NewLock()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ldbm_back_init: PR_NewLock failed\n",
+ 0, 0, 0 );
+ return(-1);
+ }
+
+ if ((li->li_dbcache_cv = PR_NewCondVar( li->li_dbcache_mutex )) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ldbm_back_init: PR_NewCondVar failed\n", 0, 0, 0 );
+ exit(-1);
+ }
+
+ /* set all of the necessary database plugin callback functions */
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_03 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_BIND_FN,
+ (void *) ldbm_back_bind );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_UNBIND_FN,
+ (void *) ldbm_back_unbind );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_SEARCH_FN,
+ (void *) ldbm_back_search );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN,
+ (void *) ldbm_back_next_search_entry );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN,
+ (void *) ldbm_back_next_search_entry_ext );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ENTRY_RELEASE_FN,
+ (void *) ldbm_back_entry_release );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_COMPARE_FN,
+ (void *) ldbm_back_compare );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_MODIFY_FN,
+ (void *) ldbm_back_modify );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_MODRDN_FN,
+ (void *) ldbm_back_modrdn );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ADD_FN,
+ (void *) ldbm_back_add );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_DELETE_FN,
+ (void *) ldbm_back_delete );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ABANDON_FN,
+ (void *) ldbm_back_abandon );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) ldbm_back_close );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_CLEANUP_FN,
+ (void *) ldbm_back_cleanup );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_FLUSH_FN,
+ (void *) ldbm_back_flush );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN,
+ (void *) ldbm_back_start );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_SEQ_FN,
+ (void *) ldbm_back_seq );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_RMDB_FN,
+ (void *) ldbm_back_rmdb );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_LDIF2DB_FN,
+ (void *) ldbm_back_ldif2ldbm );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_DB2LDIF_FN,
+ (void *) ldbm_back_ldbm2ldif );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_DB2INDEX_FN,
+ (void *) ldbm_back_ldbm2index );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ARCHIVE2DB_FN,
+ (void *) ldbm_back_archive2ldbm );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_DB2ARCHIVE_FN,
+ (void *) ldbm_back_ldbm2archive );
+#if defined(UPGRADEDB)
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_UPGRADEDB_FN,
+ (void *) ldbm_back_upgradedb );
+#endif
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_BEGIN_FN,
+ (void *) dblayer_plugin_begin );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_COMMIT_FN,
+ (void *) dblayer_plugin_commit );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ABORT_FN,
+ (void *) dblayer_plugin_abort );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_SIZE_FN,
+ (void *) ldbm_db_size );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_TEST_FN,
+ (void *) ldbm_back_db_test );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_INIT_INSTANCE_FN,
+ (void *) ldbm_back_init ); /* register itself so that the secon instance
+ can be initialized */
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_WIRE_IMPORT_FN,
+ (void *) ldbm_back_wire_import);
+
+ if ( rc != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ldbm_back_init failed\n", 0, 0, 0 );
+ return( -1 );
+ }
+
+ /* register the IDL interface with the API broker */
+ if(!interface_published)
+ {
+ IDL_api[0] = 0;
+ IDL_api[1] = (void *)idl_alloc;
+ IDL_api[2] = (void *)idl_insert;
+
+ if( slapi_apib_register(IDL_v1_0_GUID, IDL_api) )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "ldbm_back_init: failed to publish IDL interface\n", 0, 0, 0);
+ return( -1 );
+ }
+
+ interface_published = 1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldbm_back_init\n", 0, 0, 0 );
+
+ return( 0 );
+}
+
+
+/*
+ * Add an attribute syntax using some default flags, etc.
+ * Returns an LDAP error code (LDAP_SUCCESS if all goes well)
+ */
+static int
+add_ldbm_internal_attr_syntax( const char *name, const char *oid,
+ const char *syntax, const char *mr_equality, unsigned long extraflags )
+{
+ int rc = LDAP_SUCCESS;
+ struct asyntaxinfo *asip;
+ char *names[2];
+ char *origins[2];
+ unsigned long std_flags = SLAPI_ATTR_FLAG_STD_ATTR | SLAPI_ATTR_FLAG_OPATTR
+ | SLAPI_ATTR_FLAG_NOUSERMOD;
+
+ names[0] = (char *)name;
+ names[1] = NULL;
+
+ origins[0] = SLAPD_VERSION_STR;
+ origins[1] = NULL;
+
+ rc = attr_syntax_create( oid, names, 1,
+ "Netscape defined attribute type",
+ NULL, /* superior */
+ mr_equality, NULL, NULL, /* matching rules */
+ origins, syntax,
+ SLAPI_SYNTAXLENGTH_NONE,
+ std_flags | extraflags,
+ &asip );
+
+ if ( rc == LDAP_SUCCESS ) {
+ rc = attr_syntax_add( asip );
+ }
+
+ return rc;
+}
diff --git a/ldap/servers/slapd/back-ldbm/instance.c b/ldap/servers/slapd/back-ldbm/instance.c
new file mode 100644
index 00000000..aa672000
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/instance.c
@@ -0,0 +1,353 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "back-ldbm.h"
+
+/* Forward declarations */
+static void ldbm_instance_destructor(void **arg);
+
+
+
+/* Creates and initializes a new ldbm_instance structure.
+ * Also sets up some default indexes for the new instance.
+ */
+int ldbm_instance_create(backend *be, char *name)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ ldbm_instance *inst;
+
+ /* Allocate storage for the ldbm_instance structure. Information specific
+ * to this instance of the ldbm backend will be held here. */
+ inst = (ldbm_instance *) slapi_ch_calloc(1, sizeof(ldbm_instance));
+
+ /* Record the name of this instance. */
+ inst->inst_name = strdup(name);
+
+ /* initialize the entry cache */
+ if (! cache_init(&(inst->inst_cache), DEFAULT_CACHE_SIZE,
+ DEFAULT_CACHE_ENTRIES)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm_instance_create: cache_init failed\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ /* Lock for the list of open db handles */
+ inst->inst_handle_list_mutex = PR_NewLock();
+ if (NULL == inst->inst_handle_list_mutex) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm_instance_create: PR_NewLock failed\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ /* Lock used to synchronize modify operations. */
+ inst->inst_db_mutex = PR_NewLock();
+ if (NULL == inst->inst_db_mutex) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm_instance_create: PR_NewLock failed\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ if ((inst->inst_config_mutex = PR_NewLock()) == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm_instance_create: PR_NewLock failed\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ if ((inst->inst_nextid_mutex = PR_NewLock()) == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm_instance_create: PR_NewLock failed\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ if ((inst->inst_indexer_cv = PR_NewCondVar(inst->inst_nextid_mutex)) == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm_instance_create: PR_NewCondVar failed\n", 0, 0, 0 );
+ return -1;
+ }
+
+ inst->inst_be = be;
+ inst->inst_li = li;
+ be->be_instance_info = inst;
+
+ /* Initialize the fields with some default values. */
+ ldbm_instance_config_setup_default(inst);
+
+ /* Add this new instance to the the set of instances */
+ {
+ Object *instance_obj;
+
+ instance_obj = object_new((void *) inst, &ldbm_instance_destructor);
+ objset_add_obj(li->li_instance_set, instance_obj);
+ object_release(instance_obj);
+ }
+
+ return 0;
+}
+
+/* create the default indexes separately
+ * (because when we're creating a new backend while the server is running,
+ * the DSE needs to be pre-seeded first.)
+ */
+int ldbm_instance_create_default_indexes(backend *be)
+{
+ char *argv[ 9 ];
+ ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
+ /* write the dse file only on the final index */
+ int flags = LDBM_INSTANCE_CONFIG_DONT_WRITE;
+
+ /*
+ * Always index entrydn, parentid, objectclass, subordinatecount
+ * copiedFrom, and aci,
+ * since they are used by some searches, replication and the
+ * ACL routines.
+ */
+
+ argv[ 0 ] = "entrydn";
+ argv[ 1 ] = "eq";
+ argv[ 2 ] = NULL;
+ ldbm_instance_config_add_index_entry(inst, 2, argv, flags);
+
+ argv[ 0 ] = "parentid";
+ argv[ 1 ] = "eq";
+ argv[ 2 ] = NULL;
+ ldbm_instance_config_add_index_entry(inst, 2, argv, flags);
+
+ argv[ 0 ] = "objectclass";
+ argv[ 1 ] = "eq";
+ argv[ 2 ] = NULL;
+ ldbm_instance_config_add_index_entry(inst, 2, argv, flags);
+
+ argv[ 0 ] = "aci";
+ argv[ 1 ] = "pres";
+ argv[ 2 ] = NULL;
+ ldbm_instance_config_add_index_entry(inst, 2, argv, flags);
+
+#if 0 /* don't need copiedfrom */
+ argv[ 0 ] = "copiedfrom";
+ argv[ 1 ] = "pres";
+ argv[ 2 ] = NULL;
+ ldbm_instance_config_add_index_entry(inst, 2, argv, flags);
+#endif
+
+ argv[ 0 ] = "numsubordinates";
+ argv[ 1 ] = "pres";
+ argv[ 2 ] = NULL;
+ ldbm_instance_config_add_index_entry(inst, 2, argv, flags);
+
+ argv[ 0 ] = SLAPI_ATTR_UNIQUEID;
+ argv[ 1 ] = "eq";
+ argv[ 2 ] = NULL;
+ ldbm_instance_config_add_index_entry(inst, 2, argv, flags);
+
+ /* For MMR, we need this attribute (to replace use of dncomp in delete). */
+ argv[ 0 ] = ATTR_NSDS5_REPLCONFLICT;
+ argv[ 1 ] = "eq";
+ argv[ 2 ] = NULL;
+ ldbm_instance_config_add_index_entry(inst, 2, argv, flags);
+
+ /* write the dse file only on the final index */
+ argv[ 0 ] = SLAPI_ATTR_NSCP_ENTRYDN;
+ argv[ 1 ] = "eq";
+ argv[ 2 ] = NULL;
+ ldbm_instance_config_add_index_entry(inst, 2, argv, 0);
+
+ argv[ 0 ] = LDBM_PSEUDO_ATTR_DEFAULT;
+ argv[ 1 ] = "none";
+ argv[ 2 ] = NULL;
+ /* ldbm_instance_config_add_index_entry(inst, 2, argv); */
+ attr_index_config( be, "ldbm index init", 0, 2, argv, 1 );
+
+ /*
+ * ancestorid is special, there is actually no such attr type
+ * but we still want to use the attr index file APIs.
+ */
+ argv[ 0 ] = "ancestorid";
+ argv[ 1 ] = "eq";
+ argv[ 2 ] = NULL;
+ attr_index_config( be, "ldbm index init", 0, 2, argv, 1 );
+
+ return 0;
+}
+
+
+/* Starts a backend instance */
+int
+ldbm_instance_start(backend *be)
+{
+ int rc;
+ PR_Lock (be->be_state_lock);
+
+ if (be->be_state != BE_STATE_STOPPED &&
+ be->be_state != BE_STATE_DELETED) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldbm_instance_start: warning - backend is in a wrong state - %d\n",
+ be->be_state, 0, 0 );
+ PR_Unlock (be->be_state_lock);
+ return 0;
+ }
+
+ rc = dblayer_instance_start(be, DBLAYER_NORMAL_MODE);
+ be->be_state = BE_STATE_STARTED;
+
+ PR_Unlock (be->be_state_lock);
+
+ return rc;
+}
+
+
+/* Stops a backend instance */
+int
+ldbm_instance_stop(backend *be)
+{
+ int rc;
+ ldbm_instance *inst = (ldbm_instance *)be->be_instance_info;
+
+ PR_Lock (be->be_state_lock);
+
+ if (be->be_state != BE_STATE_STARTED) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ldbm_back_close: warning - backend %s is in the wrong state - %d\n",
+ inst ? inst->inst_name : "", be->be_state, 0 );
+ PR_Unlock (be->be_state_lock);
+ return 0;
+ }
+
+ rc = dblayer_instance_close(be);
+
+ be->be_state = BE_STATE_STOPPED;
+ PR_Unlock (be->be_state_lock);
+
+ cache_destroy_please(&inst->inst_cache);
+
+ return rc;
+}
+
+
+/* Walks down the set of instances, starting each one. */
+int
+ldbm_instance_startall(struct ldbminfo *li)
+{
+ Object *inst_obj;
+ ldbm_instance *inst;
+ int rc = 0;
+
+ inst_obj = objset_first_obj(li->li_instance_set);
+ while (inst_obj != NULL) {
+ int rc1;
+ inst = (ldbm_instance *) object_get_data(inst_obj);
+ rc1 = ldbm_instance_start(inst->inst_be);
+ if (rc1 != 0) {
+ rc = rc1;
+ } else {
+ vlv_init(inst);
+ }
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj);
+ }
+
+ return rc;
+}
+
+
+/* Walks down the set of instances, stopping each one. */
+int ldbm_instance_stopall(struct ldbminfo *li)
+{
+ Object *inst_obj;
+ ldbm_instance *inst;
+
+ inst_obj = objset_first_obj(li->li_instance_set);
+ while (inst_obj != NULL) {
+ inst = (ldbm_instance *) object_get_data(inst_obj);
+ ldbm_instance_stop(inst->inst_be);
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj);
+ }
+
+ return 0;
+}
+
+
+/* Walks down the set of instance, looking for one
+ * with the given name. Returns a pointer to the
+ * instance if found, and NULL if not found. The
+ * string compare on the instance name is NOT case
+ * sensitive.
+ */
+/* Currently this function doesn't bump
+ * the ref count of the instance returned.
+ */
+ldbm_instance *
+ldbm_instance_find_by_name(struct ldbminfo *li, char *name)
+{
+ Object *inst_obj;
+ ldbm_instance *inst;
+
+ inst_obj = objset_first_obj(li->li_instance_set);
+ while (inst_obj != NULL) {
+ inst = (ldbm_instance *) object_get_data(inst_obj);
+ if (!strcasecmp(inst->inst_name, name)) {
+ /* Currently we release the object here. There is no
+ * function for callers of this function to call to
+ * release the object.
+ */
+ object_release(inst_obj);
+ return inst;
+ }
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj);
+ }
+ return NULL;
+}
+
+
+/* Called when all references to the instance are gone. */
+/* (ie, only when an instance is being deleted) */
+static void
+ldbm_instance_destructor(void **arg)
+{
+ ldbm_instance *inst = (ldbm_instance *) *arg;
+
+ LDAPDebug(LDAP_DEBUG_ANY, "Destructor for instance %s called\n",
+ inst->inst_name, 0, 0);
+
+ slapi_ch_free((void **)&inst->inst_name);
+ PR_DestroyLock(inst->inst_config_mutex);
+ slapi_ch_free((void **)&inst->inst_dir_name);
+ PR_DestroyLock(inst->inst_db_mutex);
+ PR_DestroyLock(inst->inst_handle_list_mutex);
+ PR_DestroyLock(inst->inst_nextid_mutex);
+ PR_DestroyCondVar(inst->inst_indexer_cv);
+ attrinfo_deletetree(inst);
+ if (inst->inst_dataversion) {
+ slapi_ch_free((void **)&inst->inst_dataversion);
+ }
+ /* cache has already been destroyed */
+
+ slapi_ch_free((void **)&inst);
+}
+
+
+static int
+ldbm_instance_comparator(Object *object, const void *name)
+{
+ void *data = object_get_data(object);
+ return (data == name) ? 0 : 1;
+}
+
+
+/* find the instance in the objset and remove it */
+int
+ldbm_instance_destroy(ldbm_instance *inst)
+{
+ Object *object = NULL;
+ struct ldbminfo *li = inst->inst_li;
+
+ object = objset_find(li->li_instance_set, ldbm_instance_comparator, inst);
+ if (object == NULL) {
+ return -1;
+ }
+ /* decref from objset_find */
+ object_release(object);
+
+ /* now remove from the instance set */
+ objset_remove_obj(li->li_instance_set, object);
+ return 0;
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_abandon.c b/ldap/servers/slapd/back-ldbm/ldbm_abandon.c
new file mode 100644
index 00000000..6dd8c087
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_abandon.c
@@ -0,0 +1,14 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* abandon.c - ldbm backend abandon routine */
+
+#include "back-ldbm.h"
+
+int ldbm_back_abandon(Slapi_PBlock *pb)
+{
+ /* DBDB need to implement this */
+ return 0;
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_add.c b/ldap/servers/slapd/back-ldbm/ldbm_add.c
new file mode 100644
index 00000000..1c4b8541
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_add.c
@@ -0,0 +1,880 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* add.c - ldap ldbm back-end add routine */
+
+#include "back-ldbm.h"
+
+extern char *numsubordinates;
+extern char *hassubordinates;
+
+static void delete_update_entry_dn_operational_attributes(struct backentry *ep);
+
+/* in order to find the parent, we must have either the parent dn or uniqueid
+ This function will return true if either are set, or false otherwise */
+static int
+have_parent_address(const Slapi_DN *parentsdn, const char *parentuniqueid)
+{
+ if (parentuniqueid && parentuniqueid[0]) {
+ return 1; /* have parent uniqueid */
+ }
+
+ if (parentsdn && !slapi_sdn_isempty(parentsdn)) {
+ return 1; /* have parent dn */
+ }
+
+ return 0; /* have no address */
+}
+
+int
+ldbm_back_add( Slapi_PBlock *pb )
+{
+ backend *be;
+ struct ldbminfo *li;
+ ldbm_instance *inst;
+ char *dn = NULL;
+ Slapi_Entry *e;
+ struct backentry *tombstoneentry = NULL;
+ struct backentry *addingentry = NULL;
+ struct backentry *parententry = NULL;
+ ID pid;
+ int isroot;
+ char *errbuf= NULL;
+ back_txn txn;
+ back_txnid parent_txn;
+ int retval = -1;
+ char *msg;
+ int managedsait;
+ int ldap_result_code = LDAP_SUCCESS;
+ char *ldap_result_message= NULL;
+ char *ldap_result_matcheddn= NULL;
+ int retry_count = 0;
+ int disk_full = 0;
+ modify_context parent_modify_c = {0};
+ int parent_found = 0;
+ int rc;
+ int addingentry_id_assigned= 0;
+ int addingentry_in_cache= 0;
+ int tombstone_in_cache= 0;
+ Slapi_DN sdn;
+ Slapi_DN parentsdn;
+ Slapi_Operation *operation;
+ int dblock_acquired= 0;
+ int is_replicated_operation= 0;
+ int is_resurect_operation= 0;
+ int is_tombstone_operation= 0;
+ int is_fixup_operation= 0;
+ CSN *opcsn = NULL;
+ entry_address addr;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e );
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
+ slapi_pblock_get( pb, SLAPI_PARENT_TXN, (void**)&parent_txn );
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
+ slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation );
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be);
+
+ is_resurect_operation= operation_is_flag_set(operation,OP_FLAG_RESURECT_ENTRY);
+ is_tombstone_operation= operation_is_flag_set(operation,OP_FLAG_TOMBSTONE_ENTRY);
+ is_fixup_operation = operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP);
+
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ slapi_sdn_init(&sdn);
+ slapi_sdn_init(&parentsdn);
+
+ /* Get rid of ldbm backend attributes that you are not allowed to specify yourself */
+ slapi_entry_delete_values( e, hassubordinates, NULL );
+ slapi_entry_delete_values( e, numsubordinates, NULL );
+
+ dblayer_txn_init(li,&txn);
+
+ /* The dblock serializes writes to the database,
+ * which reduces deadlocking in the db code,
+ * which means that we run faster.
+ *
+ * But, this lock is re-enterant for the fixup
+ * operations that the URP code in the Replication
+ * plugin generates.
+ */
+ if(SERIALLOCK(li) && !is_fixup_operation)
+ {
+ dblayer_lock_backend(be);
+ dblock_acquired= 1;
+ }
+
+ rc= 0;
+
+ /*
+ * We are about to pass the last abandon test, so from now on we are
+ * committed to finish this operation. Set status to "will complete"
+ * before we make our last abandon check to avoid race conditions in
+ * the code that processes abandon operations.
+ */
+ if (operation) {
+ operation->o_status = SLAPI_OP_STATUS_WILL_COMPLETE;
+ }
+ if ( slapi_op_abandoned( pb ) ) {
+ goto error_return;
+ }
+
+
+ if (!is_tombstone_operation && !is_resurect_operation)
+ {
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
+ }
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_UNIQUEID_ENTRY);
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY);
+ while(rc!=0)
+ {
+ /* JCM - copying entries can be expensive... should optimize */
+ /*
+ * Some present state information is passed through the PBlock to the
+ * backend pre-op plugin. To ensure a consistent snapshot of this state
+ * we wrap the reading of the entry with the dblock.
+ */
+ if(slapi_isbitset_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_UNIQUEID_ENTRY))
+ {
+ /* Check if an entry with the intended uniqueid already exists. */
+ done_with_pblock_entry(pb,SLAPI_ADD_EXISTING_UNIQUEID_ENTRY); /* Could be through this multiple times */
+ addr.dn = NULL;
+ addr.uniqueid = (char*)slapi_entry_get_uniqueid(e); /* jcm - cast away const */
+ ldap_result_code= get_copy_of_entry(pb, &addr, &txn, SLAPI_ADD_EXISTING_UNIQUEID_ENTRY, !is_replicated_operation);
+ }
+ if(slapi_isbitset_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY))
+ {
+ slapi_pblock_get( pb, SLAPI_ADD_TARGET, &dn );
+ slapi_sdn_set_dn_byref(&sdn, dn);
+ slapi_sdn_get_backend_parent(&sdn,&parentsdn,pb->pb_backend);
+ /* Check if an entry with the intended DN already exists. */
+ done_with_pblock_entry(pb,SLAPI_ADD_EXISTING_DN_ENTRY); /* Could be through this multiple times */
+ addr.dn = dn;
+ addr.uniqueid = NULL;
+ ldap_result_code= get_copy_of_entry(pb, &addr, &txn, SLAPI_ADD_EXISTING_DN_ENTRY, !is_replicated_operation);
+ }
+ /* if we can find the parent by dn or uniqueid, and the operation has requested the parent
+ then get it */
+ if(have_parent_address(&parentsdn, operation->o_params.p.p_add.parentuniqueid) &&
+ slapi_isbitset_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY))
+ {
+ done_with_pblock_entry(pb,SLAPI_ADD_PARENT_ENTRY); /* Could be through this multiple times */
+ addr.dn = (char*)slapi_sdn_get_ndn (&parentsdn);
+ addr.uniqueid = operation->o_params.p.p_add.parentuniqueid;
+ ldap_result_code= get_copy_of_entry(pb, &addr, &txn, SLAPI_ADD_PARENT_ENTRY, !is_replicated_operation);
+ /* need to set parentsdn or parentuniqueid if either is not set? */
+ }
+
+ /* Call the Backend Pre Add plugins */
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+ rc= plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_ADD_FN);
+ if(rc==-1)
+ {
+ /*
+ * Plugin indicated some kind of failure,
+ * or that this Operation became a No-Op.
+ */
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+ goto error_return;
+ }
+ /*
+ * (rc!=-1 && rc!= 0) means that the plugin changed things, so we go around
+ * the loop once again to get the new present state.
+ */
+ /* JCMREPL - Warning: A Plugin could cause an infinite loop by always returning a result code that requires some action. */
+ }
+
+ /*
+ * Originally (in the U-M LDAP 3.3 code), there was a comment near this
+ * code about a race condition. The race was that a 2nd entry could be
+ * added between the time when we check for an already existing entry
+ * and the cache_add_entry_lock() call below. A race condition no
+ * longer exists, because now we keep the parent entry locked for
+ * the duration of the old race condition's window of opportunity.
+ */
+
+ /*
+ * Fetch the parent entry and acquire the cache lock.
+ */
+ if(have_parent_address(&parentsdn, operation->o_params.p.p_add.parentuniqueid))
+ {
+ addr.dn = (char*)slapi_sdn_get_ndn (&parentsdn);
+ addr.uniqueid = operation->o_params.p.p_add.parentuniqueid;
+ parententry = find_entry2modify_only(pb,be,&addr,&txn);
+ if (parententry && parententry->ep_entry) {
+ if (!operation->o_params.p.p_add.parentuniqueid){
+ /* Set the parentuniqueid now */
+ operation->o_params.p.p_add.parentuniqueid = slapi_ch_strdup(slapi_entry_get_uniqueid(parententry->ep_entry));
+ }
+ if (slapi_sdn_isempty(&parentsdn)) {
+ /* Set the parentsdn now */
+ slapi_sdn_set_dn_byval(&parentsdn, slapi_entry_get_dn_const(parententry->ep_entry));
+ }
+ }
+ modify_init(&parent_modify_c,parententry);
+ }
+
+ /* Check if the entry we have been asked to add already exists */
+ {
+ Slapi_Entry *entry;
+ slapi_pblock_get( pb, SLAPI_ADD_EXISTING_DN_ENTRY, &entry);
+ if ( entry != NULL )
+ {
+ /* The entry already exists */
+ ldap_result_code= LDAP_ALREADY_EXISTS;
+ goto error_return;
+ }
+ else
+ {
+ /*
+ * did not find the entry - this is good, since we're
+ * trying to add it, but we have to check whether the
+ * entry we did match has a referral we should return
+ * instead. we do this only if managedsait is not on.
+ */
+ if ( !managedsait && !is_tombstone_operation )
+ {
+ int err= 0;
+ Slapi_DN ancestordn= {0};
+ struct backentry *ancestorentry;
+ ancestorentry= dn2ancestor(pb->pb_backend,&sdn,&ancestordn,&txn,&err);
+ slapi_sdn_done(&ancestordn);
+ if ( ancestorentry != NULL )
+ {
+ int sentreferral= check_entry_for_referral(pb, ancestorentry->ep_entry, backentry_get_ndn(ancestorentry), "ldbm_back_add");
+ cache_return( &inst->inst_cache, &ancestorentry );
+ if(sentreferral)
+ {
+ ldap_result_code= -1; /* The result was sent by check_entry_for_referral */
+ goto error_return;
+ }
+ }
+ }
+ }
+ }
+
+
+ if ((operation_is_flag_set(operation,OP_FLAG_ACTION_SCHEMA_CHECK)) && slapi_entry_schema_check(pb, e) != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_TRACE, "entry failed schema check\n", 0, 0, 0);
+ ldap_result_code = LDAP_OBJECT_CLASS_VIOLATION;
+ slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
+ goto error_return;
+ }
+
+ opcsn = operation_get_csn (operation);
+ if(is_resurect_operation)
+ {
+ char *reason = NULL;
+ /*
+ * When we resurect a tombstone we must use its UniqueID
+ * to find the tombstone entry and lock it down in the cache.
+ */
+ addr.dn = NULL;
+ addr.uniqueid = (char *)slapi_entry_get_uniqueid(e); /* jcm - cast away const */
+ tombstoneentry = find_entry2modify( pb, be, &addr, NULL );
+ if ( tombstoneentry==NULL )
+ {
+ ldap_result_code= -1;
+ goto error_return; /* error result sent by find_entry2modify() */
+ }
+ tombstone_in_cache = 1;
+
+ addingentry = backentry_dup( tombstoneentry );
+ if ( addingentry==NULL )
+ {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ /*
+ * To resurect a tombstone we must fix its DN and remove the
+ * parent UniqueID that we stashed in there.
+ *
+ * The entry comes back to life as a Glue entry, so we add the
+ * magic objectclass.
+ */
+ slapi_pblock_get( pb, SLAPI_ADD_TARGET, &dn );
+ slapi_sdn_set_dn_byref(&sdn, dn);
+ slapi_entry_set_dn(addingentry->ep_entry, slapi_ch_strdup(dn)); /* The DN is passed into the entry. */
+ /* LPREPL: the DN is normalized...Somehow who should get a not normalized one */
+ addingentry->ep_id = slapi_entry_attr_get_ulong(addingentry->ep_entry,"entryid");
+ slapi_entry_attr_delete(addingentry->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID);
+ slapi_entry_delete_string(addingentry->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE);
+ /* Now also remove the nscpEntryDN */
+ if (slapi_entry_attr_delete(addingentry->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN) != 0){
+ LDAPDebug(LDAP_DEBUG_REPL, "Resurrection of %s - Couldn't remove %s\n", dn, SLAPI_ATTR_NSCP_ENTRYDN, 0);
+ }
+
+ /* And copy the reason from e */
+ reason = slapi_entry_attr_get_charptr(e, "nsds5ReplConflict");
+ if (reason) {
+ if (!slapi_entry_attr_hasvalue(addingentry->ep_entry, "nsds5ReplConflict", reason)) {
+ slapi_entry_add_string(addingentry->ep_entry, "nsds5ReplConflict", reason);
+ LDAPDebug(LDAP_DEBUG_REPL, "Resurrection of %s - Added Conflict reason %s\n", dn, reason, 0);
+ }
+ slapi_ch_free((void **)&reason);
+ }
+ /* Clear the Tombstone Flag in the entry */
+ slapi_entry_clear_flag(addingentry->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
+
+ /* make sure the objectclass
+ - does not contain any duplicate values
+ - has CSNs for the new values we added
+ */
+ {
+ Slapi_Attr *sa = NULL;
+ Slapi_Value sv;
+ const struct berval *svbv = NULL;
+
+ /* add the extensibleobject objectclass with csn if not present */
+ slapi_entry_attr_find(addingentry->ep_entry, SLAPI_ATTR_OBJECTCLASS, &sa);
+ slapi_value_init_string(&sv, "extensibleobject");
+ svbv = slapi_value_get_berval(&sv);
+ if (slapi_attr_value_find(sa, svbv)) { /* not found, so add it */
+ if (opcsn) {
+ value_update_csn(&sv, CSN_TYPE_VALUE_UPDATED, opcsn);
+ }
+ slapi_attr_add_value(sa, &sv);
+ }
+ value_done(&sv);
+
+ /* add the glue objectclass with csn if not present */
+ slapi_value_init_string(&sv, "glue");
+ svbv = slapi_value_get_berval(&sv);
+ if (slapi_attr_value_find(sa, svbv)) { /* not found, so add it */
+ if (opcsn) {
+ value_update_csn(&sv, CSN_TYPE_VALUE_UPDATED, opcsn);
+ }
+ slapi_attr_add_value(sa, &sv);
+ }
+ value_done(&sv);
+ }
+ }
+ else
+ {
+ /*
+ * Try to add the entry to the cache, assign it a new entryid
+ * and mark it locked. This should only fail if the entry
+ * already exists.
+ */
+ /*
+ * next_id will add this id to the list of ids that are pending
+ * id2entry indexing.
+ */
+ addingentry = backentry_init( e );
+ if ( ( addingentry->ep_id = next_id( be ) ) >= MAXID ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "add: maximum ID reached, cannot add entry to "
+ "backend '%s'", be->be_name, 0, 0 );
+ ldap_result_code = LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ addingentry_id_assigned= 1;
+
+ if (!is_fixup_operation)
+ {
+ if ( opcsn == NULL && operation->o_csngen_handler )
+ {
+ /*
+ * Current op is a user request. Opcsn will be assigned
+ * if the dn is in an updatable replica.
+ */
+ opcsn = entry_assign_operation_csn ( pb, e, parententry ? parententry->ep_entry : NULL );
+ }
+ if ( opcsn != NULL )
+ {
+ entry_set_csn (e, opcsn);
+ entry_add_dncsn (e, opcsn);
+ entry_add_rdn_csn (e, opcsn);
+ entry_set_maxcsn (e, opcsn);
+ }
+ }
+
+ if (is_tombstone_operation)
+ {
+ /* Directly add the entry as a tombstone */
+ /*
+ * 1) If the entry has an existing DN, change it to be
+ * "nsuniqueid=<uniqueid>, <old dn>"
+ * 2) Add the objectclass value "tombstone" and arrange for only
+ * that value to be indexed.
+ * 3) If the parent entry was found, set the nsparentuniqueid
+ * attribute to be the unique id of that parent.
+ */
+ char *untombstoned_dn = slapi_entry_get_dn(e);
+ if (NULL == untombstoned_dn)
+ {
+ untombstoned_dn = "";
+ }
+ slapi_entry_set_dn(addingentry->ep_entry, compute_entry_tombstone_dn(untombstoned_dn, addr.uniqueid));
+ /* Work around pb with slapi_entry_add_string (defect 522327) doesn't check duplicate values */
+ if (!slapi_entry_attr_hasvalue(addingentry->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE)) {
+ slapi_entry_add_string(addingentry->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE);
+ slapi_entry_set_flag(addingentry->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
+ }
+ if (NULL != operation->o_params.p.p_add.parentuniqueid)
+ {
+ slapi_entry_add_string(addingentry->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID, operation->o_params.p.p_add.parentuniqueid);
+ }
+ }
+ if ( cache_add_tentative( &inst->inst_cache, addingentry, NULL )!= 0 )
+ {
+ LDAPDebug( LDAP_DEBUG_CACHE, "cache_add_tentative concurrency detected\n", 0, 0, 0 );
+ ldap_result_code= LDAP_ALREADY_EXISTS;
+ goto error_return;
+ }
+ addingentry_in_cache= 1;
+ }
+
+ /*
+ * Get the parent dn and see if the corresponding entry exists.
+ * If the parent does not exist, only allow the "root" user to
+ * add the entry.
+ */
+ if ( !slapi_sdn_isempty(&parentsdn) )
+ {
+ /* This is getting the parent */
+ if (NULL == parententry)
+ {
+ /* Here means that we didn't find the parent */
+ int err = 0;
+ Slapi_DN ancestordn= {0};
+ struct backentry *ancestorentry;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "parent does not exist, pdn = %s\n",
+ slapi_sdn_get_dn(&parentsdn), 0, 0 );
+
+ ancestorentry = dn2ancestor(be, &parentsdn, &ancestordn, &txn, &err );
+ cache_return( &inst->inst_cache, &ancestorentry );
+
+ ldap_result_code= LDAP_NO_SUCH_OBJECT;
+ ldap_result_matcheddn= slapi_ch_strdup((char *)slapi_sdn_get_dn(&ancestordn)); /* jcm - cast away const. */
+ slapi_sdn_done(&ancestordn);
+ goto error_return;
+ }
+ ldap_result_code = plugin_call_acl_plugin (pb, e, NULL, NULL, SLAPI_ACL_ADD,
+ ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
+ if ( ldap_result_code != LDAP_SUCCESS )
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "no access to parent\n", 0, 0, 0 );
+ ldap_result_message= errbuf;
+ goto error_return;
+ }
+ pid = parententry->ep_id;
+ }
+ else
+ { /* no parent */
+ if ( !isroot && !is_replicated_operation)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "no parent & not root\n",
+ 0, 0, 0 );
+ ldap_result_code= LDAP_INSUFFICIENT_ACCESS;
+ goto error_return;
+ }
+ parententry = NULL;
+ pid = 0;
+ }
+
+ if(is_resurect_operation)
+ {
+ /*
+ * add the entrydn operational attributes
+ */
+ add_update_entrydn_operational_attributes(addingentry);
+ }
+ else if (is_tombstone_operation)
+ {
+ /* Remove the entrydn operational attributes */
+ delete_update_entry_dn_operational_attributes(addingentry);
+ }
+ else
+ {
+ /*
+ * add the parentid, entryid and entrydn operational attributes
+ */
+ add_update_entry_operational_attributes(addingentry, pid);
+ }
+
+ /*
+ * Before we add the entry, find out if the syntax of the aci
+ * aci attribute values are correct or not. We don't want to
+ * the entry if the syntax is incorrect.
+ */
+ if ( plugin_call_acl_verify_syntax (pb, addingentry->ep_entry, &errbuf) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "ACL syntax error\n", 0,0,0);
+ ldap_result_code= LDAP_INVALID_SYNTAX;
+ ldap_result_message= errbuf;
+ goto error_return;
+ }
+
+ /* Having decided that we're really going to do the operation, let's modify
+ the in-memory state of the parent to reflect the new child (update
+ subordinate count specifically */
+ if (NULL != parententry)
+ {
+ retval = parent_update_on_childchange(&parent_modify_c,1,NULL); /* 1==add */\
+ /* The modify context now contains info needed later */
+ if (0 != retval) {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ parent_found = 1;
+ parententry = NULL;
+ }
+ /*
+ * So, we believe that no code up till here actually added anything
+ * to persistent store. From now on, we're transacted
+ */
+
+ for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) {
+ if (retry_count > 0) {
+ dblayer_txn_abort(li,&txn);
+ /* We're re-trying */
+ LDAPDebug( LDAP_DEBUG_TRACE, "Add Retrying Transaction\n", 0, 0, 0 );
+#ifndef LDBM_NO_BACKOFF_DELAY
+ {
+ PRIntervalTime interval;
+ interval = PR_MillisecondsToInterval(slapi_rand() % 100);
+ DS_Sleep(interval);
+ }
+#endif
+ }
+ retval = dblayer_txn_begin(li,parent_txn,&txn);
+ if (0 != retval) {
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto diskfull_return;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ retval = id2entry_add( be, addingentry, &txn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "add 1 DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (retval != 0) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "id2entry_add failed, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto diskfull_return;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ if(is_resurect_operation)
+ {
+ retval = index_addordel_string(be,SLAPI_ATTR_OBJECTCLASS,SLAPI_ATTR_VALUE_TOMBSTONE,addingentry->ep_id,BE_INDEX_DEL,&txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "add 2 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "add 1 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto diskfull_return;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ retval = index_addordel_string(be,SLAPI_ATTR_UNIQUEID,slapi_entry_get_uniqueid(addingentry->ep_entry),addingentry->ep_id,BE_INDEX_DEL,&txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "add 3 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "add 2 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto diskfull_return;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ retval = index_addordel_string(be,SLAPI_ATTR_NSCP_ENTRYDN,slapi_sdn_get_ndn(&sdn),addingentry->ep_id,BE_INDEX_DEL,&txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "add 4 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "add 3 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto diskfull_return;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ }
+ if (is_tombstone_operation)
+ {
+ retval = index_addordel_entry( be, addingentry, BE_INDEX_ADD | BE_INDEX_TOMBSTONE, &txn );
+ }
+ else
+ {
+ retval = index_addordel_entry( be, addingentry, BE_INDEX_ADD, &txn );
+ }
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "add 5 DEADLOCK\n", 0, 0, 0 );
+ /* retry txn */
+ continue;
+ }
+ if (retval != 0) {
+ LDAPDebug( LDAP_DEBUG_ANY, "add: attempt to index %lu failed\n",
+ (u_long)addingentry->ep_id, 0, 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto diskfull_return;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ if (parent_found) {
+ /* Push out the db modifications from the parent entry */
+ retval = modify_update_all(be,pb,&parent_modify_c,&txn);
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "add 4 DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "add 1 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto diskfull_return;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ }
+ /*
+ * Update the Virtual List View indexes
+ */
+ retval= vlv_update_all_indexes(&txn, be, pb, NULL, addingentry);
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "add DEADLOCK vlv_update_index\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "vlv_update_index failed, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto diskfull_return;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ if (retval == 0 ) {
+ break;
+ }
+
+ }
+ if (retry_count == RETRY_TIMES) {
+ /* Failed */
+ LDAPDebug( LDAP_DEBUG_ANY, "Retry count exceeded in add\n", 0, 0, 0 );
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ /*
+ * At this point, everything's cool, and the only thing which
+ * can go wrong is a transaction commit failure.
+ */
+ slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, NULL );
+ slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, slapi_entry_dup( addingentry->ep_entry ));
+
+ if(is_resurect_operation)
+ {
+ /*
+ * We can now switch the tombstone entry with the real entry.
+ */
+ if (cache_replace( &inst->inst_cache, tombstoneentry, addingentry ) != 0 )
+ {
+ /* This happens if the dn of addingentry already exists */
+ ldap_result_code= LDAP_ALREADY_EXISTS;
+ cache_unlock_entry( &inst->inst_cache, tombstoneentry );
+ goto error_return;
+ }
+ /*
+ * The tombstone was locked down in the cache... we can
+ * get rid of the entry in the cache now.
+ */
+ cache_unlock_entry( &inst->inst_cache, tombstoneentry );
+ cache_return( &inst->inst_cache, &tombstoneentry );
+ tombstone_in_cache = 0; /* deleted */
+ }
+ if (parent_found)
+ {
+ /* switch the parent entry copy into play */
+ modify_switch_entries( &parent_modify_c,be);
+ }
+
+ retval = dblayer_txn_commit(li,&txn);
+ if (0 != retval)
+ {
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto diskfull_return;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ rc= 0;
+ goto common_return;
+
+error_return:
+ if ( addingentry_id_assigned )
+ {
+ next_id_return( be, addingentry->ep_id );
+ }
+ if ( NULL != addingentry )
+ {
+ if ( addingentry_in_cache )
+ {
+ cache_remove(&inst->inst_cache, addingentry);
+ }
+ backentry_clear_entry(addingentry); /* e is released in the frontend */
+ backentry_free( &addingentry ); /* release the backend wrapper, here */
+ }
+ if(tombstone_in_cache)
+ {
+ cache_return(&inst->inst_cache, &tombstoneentry);
+ }
+
+ if (rc == DB_RUNRECOVERY) {
+ dblayer_remember_disk_filled(li);
+ ldbm_nasty("Add",80,rc);
+ disk_full = 1;
+ }
+
+ /* It is specifically OK to make this call even when no transaction was in progress */
+ dblayer_txn_abort(li,&txn); /* abort crashes in case disk full */
+diskfull_return:
+
+ if (disk_full)
+ rc= return_on_disk_full(li);
+ else
+ rc= SLAPI_FAIL_GENERAL;
+
+common_return:
+
+ if (addingentry_in_cache)
+ {
+ cache_return( &inst->inst_cache, &addingentry );
+ }
+ /* JCMREPL - The bepostop is called even if the operation fails. */
+ plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_ADD_FN);
+
+ modify_term(&parent_modify_c,be);
+ done_with_pblock_entry(pb,SLAPI_ADD_EXISTING_DN_ENTRY);
+ done_with_pblock_entry(pb,SLAPI_ADD_EXISTING_UNIQUEID_ENTRY);
+ done_with_pblock_entry(pb,SLAPI_ADD_PARENT_ENTRY);
+ if(dblock_acquired)
+ {
+ dblayer_unlock_backend(be);
+ }
+ if(ldap_result_code!=-1)
+ {
+ slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn, ldap_result_message, 0, NULL );
+ }
+ slapi_sdn_done(&sdn);
+ slapi_sdn_done(&parentsdn);
+ slapi_ch_free( (void**)&ldap_result_matcheddn );
+ slapi_ch_free( (void**)&errbuf );
+ return rc;
+}
+
+/*
+ * add the parentid, entryid and entrydn, operational attributes.
+ *
+ * Note: This is called from the ldif2ldbm code.
+ */
+void
+add_update_entry_operational_attributes(struct backentry *ep, ID pid)
+{
+ struct berval bv;
+ struct berval *bvp[2];
+ char buf[40]; /* Enough for an EntryID */
+
+ bvp[0] = &bv;
+ bvp[1] = NULL;
+
+ /* parentid */
+ /* If the pid is 0, then the entry does not have a parent. It
+ * may be the case that the entry is a suffix. In any case,
+ * the parentid attribute should only be added if the entry
+ * has a parent. */
+ if (pid != 0) {
+ sprintf( buf, "%lu", (u_long)pid );
+ bv.bv_val = buf;
+ bv.bv_len = strlen( buf );
+ entry_replace_values( ep->ep_entry, "parentid", bvp );
+ }
+
+ /* entryid */
+ sprintf( buf, "%lu", (u_long)ep->ep_id );
+ bv.bv_val = buf;
+ bv.bv_len = strlen( buf );
+ entry_replace_values( ep->ep_entry, "entryid", bvp );
+
+ /* entrydn */
+ add_update_entrydn_operational_attributes(ep);
+}
+
+/*
+ * add the entrydn operational attribute.
+ */
+void
+add_update_entrydn_operational_attributes(struct backentry *ep)
+{
+ struct berval bv;
+ struct berval *bvp[2];
+
+ /* entrydn */
+ bvp[0] = &bv;
+ bvp[1] = NULL;
+ bv.bv_val = (void*)backentry_get_ndn(ep);
+ bv.bv_len = strlen( bv.bv_val );
+ entry_replace_values( ep->ep_entry, "entrydn", bvp );
+}
+
+/*
+ * delete the entrydn operational attributes
+ */
+static void
+delete_update_entry_dn_operational_attributes(struct backentry *ep)
+{
+ slapi_entry_attr_delete( ep->ep_entry, "entrydn");
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attr.c b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
new file mode 100644
index 00000000..246a8d7d
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_attr.c
@@ -0,0 +1,635 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* attr.c - backend routines for dealing with attributes */
+
+#include "back-ldbm.h"
+
+extern char **str2charray();
+
+struct attrinfo *
+attrinfo_new()
+{
+ struct attrinfo *p= (struct attrinfo *)slapi_ch_calloc(1, sizeof(struct attrinfo));
+ p->ai_type= 0;
+ p->ai_indexmask= 0;
+ p->ai_plugin= NULL;
+ p->ai_index_rules= NULL;
+ p->ai_dblayer= NULL;
+ p->ai_dblayer_count = 0;
+ p->ai_idl= NULL;
+ return p;
+}
+
+void
+attrinfo_delete(struct attrinfo **pp)
+{
+ if(pp!=NULL && *pp!=NULL)
+ {
+ idl_release_private(*pp);
+ slapi_ch_free((void**)&((*pp)->ai_type));
+ slapi_ch_free((void**)(*pp)->ai_index_rules);
+ slapi_ch_free((void**)pp);
+ *pp= NULL;
+ }
+}
+
+static int
+attrinfo_internal_delete( caddr_t data, caddr_t arg )
+{
+ struct attrinfo *n = (struct attrinfo *)data;
+ attrinfo_delete(&n);
+ return 0;
+}
+
+void
+attrinfo_deletetree(ldbm_instance *inst)
+{
+ avl_free( inst->inst_attrs, attrinfo_internal_delete );
+}
+
+
+static int
+ainfo_type_cmp(
+ char *type,
+ struct attrinfo *a
+)
+{
+ return( strcasecmp( type, a->ai_type ) );
+}
+
+static int
+ainfo_cmp(
+ struct attrinfo *a,
+ struct attrinfo *b
+)
+{
+ return( strcasecmp( a->ai_type, b->ai_type ) );
+}
+
+/*
+ * Called when a duplicate "index" line is encountered.
+ *
+ * returns 1 => original from init code, indexmask updated
+ * 2 => original not from init code, warn the user
+ *
+ * Hard coded to return a 1 always...
+ *
+ */
+
+static int
+ainfo_dup(
+ struct attrinfo *a,
+ struct attrinfo *b
+)
+{
+ /* merge duplicate indexing information */
+ if (b->ai_indexmask == 0 || b->ai_indexmask == INDEX_OFFLINE) {
+ a->ai_indexmask = INDEX_OFFLINE; /* turns off all indexes */
+ charray_free ( a->ai_index_rules );
+ a->ai_index_rules = NULL;
+ }
+ a->ai_indexmask |= b->ai_indexmask;
+ if ( b->ai_indexmask & INDEX_RULES ) {
+ charray_merge( &a->ai_index_rules, b->ai_index_rules, 1 );
+ }
+
+ return( 1 );
+}
+
+void
+ainfo_get(
+ backend *be,
+ char *type,
+ struct attrinfo **at
+)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ if ( (*at = (struct attrinfo *) avl_find( inst->inst_attrs, type,
+ ainfo_type_cmp )) == NULL ) {
+ if ( (*at = (struct attrinfo *) avl_find( inst->inst_attrs,
+ LDBM_PSEUDO_ATTR_DEFAULT, ainfo_type_cmp )) == NULL ) {
+ return;
+ }
+ }
+}
+
+void
+attr_index_config(
+ backend *be,
+ char *fname,
+ int lineno,
+ int argc,
+ char **argv,
+ int init
+)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ int i, j;
+ char **attrs;
+ char **indexes = NULL;
+ char **index_rules = NULL;
+ struct attrinfo *a;
+ int return_value = -1;
+
+ attrs = str2charray( argv[0], "," );
+ if ( argc > 1 ) {
+ indexes = str2charray( argv[1], "," );
+ if ( argc > 2 ) {
+ index_rules = str2charray( argv[2], "," );
+ }
+ }
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ a = attrinfo_new();
+ a->ai_type = slapi_attr_basetype( attrs[i], NULL, 0 );
+ slapi_attr_type2plugin( a->ai_type, &a->ai_plugin );
+ if ( argc == 1 ) {
+ a->ai_indexmask = (INDEX_PRESENCE | INDEX_EQUALITY |
+ INDEX_APPROX | INDEX_SUB);
+ } else {
+ a->ai_indexmask = 0;
+ for ( j = 0; indexes[j] != NULL; j++ ) {
+ if ( strncasecmp( indexes[j], "pres", 4 )
+ == 0 ) {
+ a->ai_indexmask |= INDEX_PRESENCE;
+ } else if ( strncasecmp( indexes[j], "eq", 2 )
+ == 0 ) {
+ a->ai_indexmask |= INDEX_EQUALITY;
+ } else if ( strncasecmp( indexes[j], "approx",
+ 6 ) == 0 ) {
+ a->ai_indexmask |= INDEX_APPROX;
+ } else if ( strncasecmp( indexes[j], "sub", 3 )
+ == 0 ) {
+ a->ai_indexmask |= INDEX_SUB;
+ } else if ( strncasecmp( indexes[j], "none", 4 )
+ == 0 ) {
+ if ( a->ai_indexmask != 0 ) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: line %d: index type \"none\" cannot be combined with other types\n",
+ fname, lineno, 0);
+ }
+ a->ai_indexmask = INDEX_OFFLINE; /* note that the index isn't available */
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: line %d: unknown index type \"%s\" (ignored)\n",
+ fname, lineno, indexes[j]);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "valid index types are \"pres\", \"eq\", \"approx\", or \"sub\"\n",
+ 0, 0, 0);
+ }
+ }
+
+ /* compute a->ai_index_rules: */
+ j = 0;
+ if (index_rules != NULL) for (; index_rules[j] != NULL; ++j);
+ if (j > 0) { /* there are some candidates */
+ char** official_rules = (char**)
+ slapi_ch_malloc ((j + 1) * sizeof (char*));
+ size_t k = 0;
+ for (j = 0; index_rules[j] != NULL; ++j) {
+ /* Check that index_rules[j] is an official OID */
+ char* officialOID = NULL;
+ IFP mrINDEX = NULL;
+ Slapi_PBlock* pb = slapi_pblock_new();
+ if (!slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, index_rules[j]) &&
+ !slapi_pblock_set (pb, SLAPI_PLUGIN_MR_TYPE, a->ai_type) &&
+ !slapi_mr_indexer_create (pb) &&
+ !slapi_pblock_get (pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrINDEX) &&
+ mrINDEX != NULL &&
+ !slapi_pblock_get (pb, SLAPI_PLUGIN_MR_OID, &officialOID) &&
+ officialOID != NULL) {
+ if (!strcasecmp (index_rules[j], officialOID)) {
+ official_rules[k++] = slapi_ch_strdup (officialOID);
+ } else {
+ char* preamble = slapi_ch_malloc (strlen (fname) + 30);
+ sprintf (preamble, "%s: line %d", fname, lineno);
+ LDAPDebug (LDAP_DEBUG_ANY, "%s: use \"%s\" instead of \"%s\" (ignored)\n",
+ preamble, officialOID, index_rules[j] );
+ slapi_ch_free((void**)&preamble);
+ }
+ } else {
+ LDAPDebug (LDAP_DEBUG_ANY, "%s: line %d: "
+ "unknown index rule \"%s\" (ignored)\n",
+ fname, lineno, index_rules[j] );
+ }
+ {/* It would improve speed to save the indexer, for future use.
+ But, for simplicity, we destroy it now: */
+ IFP mrDESTROY = NULL;
+ if (!slapi_pblock_get (pb, SLAPI_PLUGIN_DESTROY_FN, &mrDESTROY) &&
+ mrDESTROY != NULL) {
+ mrDESTROY (pb);
+ }
+ }
+ slapi_pblock_destroy (pb);
+ }
+ official_rules[k] = NULL;
+ if (k > 0) {
+ a->ai_index_rules = official_rules;
+ a->ai_indexmask |= INDEX_RULES;
+ } else {
+ slapi_ch_free((void**)&official_rules);
+ }
+ }
+ }
+#if 0 /* seems to not matter -- INDEX_FROMINIT is checked nowhere else */
+ if ( init ) {
+ a->ai_indexmask |= INDEX_FROMINIT;
+ a->ai_indexmask &= ~INDEX_OFFLINE;
+ }
+#endif
+
+ /* initialize the IDL code's private data */
+ return_value = idl_init_private(be, a);
+ if (0 != return_value) {
+ /* fatal error, exit */
+ LDAPDebug(LDAP_DEBUG_ANY,"%s: line %d:Fatal Error: Failed to initialize attribute structure\n",
+ fname, lineno, 0);
+ exit( 1 );
+ }
+
+ if ( avl_insert( &inst->inst_attrs, a, ainfo_cmp, ainfo_dup ) != 0 ) {
+ /* duplicate - existing version updated */
+ attrinfo_delete(&a);
+ }
+ }
+ charray_free( attrs );
+ if ( indexes != NULL ) {
+ charray_free( indexes );
+ }
+ if ( index_rules != NULL ) {
+ charray_free( index_rules );
+ }
+}
+
+/*
+ * Function that creates a new attrinfo structure and
+ * inserts it into the avl tree. This is used by code
+ * that wants to store attribute-level configuration data
+ * e.g. attribute encryption, but where the attr_info
+ * structure doesn't exist because the attribute in question
+ * is not indexed.
+ */
+void
+attr_create_empty(backend *be,char *type,struct attrinfo **ai)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ struct attrinfo *a = attrinfo_new();
+ a->ai_type = slapi_ch_strdup(type);
+ if ( avl_insert( &inst->inst_attrs, a, ainfo_cmp, ainfo_dup ) != 0 ) {
+ /* duplicate - existing version updated */
+ attrinfo_delete(&a);
+ ainfo_get(be,type,&a);
+ }
+ *ai = a;
+}
+
+/* Code for computed attributes */
+extern char* hassubordinates;
+extern char* numsubordinates;
+
+static int
+ldbm_compute_evaluator(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_compute_output_t outputfn)
+{
+ int rc = 0;
+
+ if ( strcasecmp (type, numsubordinates ) == 0)
+ {
+ Slapi_Attr *read_attr = NULL;
+ /* Check to see whether this attribute is already present in the entry */
+ if (0 != slapi_entry_attr_find( e, numsubordinates, &read_attr ))
+ {
+ /* If not, we return it as zero */
+ Slapi_Attr our_attr;
+ slapi_attr_init(&our_attr, numsubordinates);
+ our_attr.a_flags = SLAPI_ATTR_FLAG_OPATTR;
+ valueset_add_string(&our_attr.a_present_values,"0",CSN_TYPE_UNKNOWN,NULL);
+ rc = (*outputfn) (c, &our_attr, e);
+ attr_done(&our_attr);
+ return (rc);
+ }
+ }
+ if ( strcasecmp (type, hassubordinates ) == 0)
+ {
+ Slapi_Attr *read_attr = NULL;
+ Slapi_Attr our_attr;
+ slapi_attr_init(&our_attr, hassubordinates);
+ our_attr.a_flags = SLAPI_ATTR_FLAG_OPATTR;
+ /* This attribute is always computed */
+ /* Check to see whether the subordinate count attribute is already present in the entry */
+ rc = slapi_entry_attr_find( e, numsubordinates, &read_attr );
+ if ( (0 != rc) || slapi_entry_attr_hasvalue(e,numsubordinates,"0") ) {
+ /* If not, or present and zero, we return FALSE, otherwise TRUE */
+ valueset_add_string(&our_attr.a_present_values,"FALSE",CSN_TYPE_UNKNOWN,NULL);
+ } else {
+ valueset_add_string(&our_attr.a_present_values,"TRUE",CSN_TYPE_UNKNOWN,NULL);
+ }
+ rc = (*outputfn) (c, &our_attr, e);
+ attr_done(&our_attr);
+ return (rc);
+ }
+
+ return -1; /* I see no ships */
+}
+
+/*
+ * string_find(): case sensitive search for the substring str2 within str1.
+ */
+static
+char * string_find (
+ const char * str1,
+ const char * str2
+ )
+{
+ char *cp = (char *) str1;
+ char *s1, *s2;
+
+ if ( !*str2 )
+ return((char *)str1);
+
+ while (*cp)
+ {
+ s1 = cp;
+ s2 = (char *) str2;
+
+ while ( *s1 && *s2 && !(*s1-*s2) )
+ s1++, s2++;
+
+ if (!*s2)
+ return(cp);
+
+ cp++;
+ }
+
+ return(NULL);
+
+}
+
+/* What are we doing ?
+ The back-end can't search properly for the hasSubordinates and
+ numSubordinates attributes. The reason being that they're not
+ always stored on entries, so filter test fails to do the correct thing.
+ However, it is possible to rewrite a given search to one
+ which will work, given that numSubordinates is present when non-zero,
+ and we maintain a presence index for numSubordinates.
+ */
+/* Searches we rewrite here :
+ substrings of the form
+ (hassubordinates=TRUE) to (&(numsubordinates=*)(numsubordinates>=1)) [indexed]
+ (hassubordinates=FALSE) to (&(objectclass=*)(!(numsubordinates=*))) [not indexed]
+ (hassubordinates=*) to (objectclass=*) [not indexed]
+ (numsubordinates=*) to (objectclass=*) [not indexed]
+ (numsubordinates=x) to (&(numsubordinates=*)(numsubordinates=x)) [indexed]
+ (numsubordinates>=x) to (&(numsubordinates=*)(numsubordinates>=x)) [indexed where X > 0]
+ (numsubordinates<=x) to (&(numsubordinates=*)(numsubordinates<=x)) [indexed]
+
+ anything else involving numsubordinates and hassubordinates we flag as unwilling to perform
+
+*/
+
+/* Before calling this function, you must free all the parts
+ which will be overwritten, this function dosn't know
+ how to do that */
+static int replace_filter(Slapi_Filter *f, char *s)
+{
+ Slapi_Filter *newf = NULL;
+ Slapi_Filter *temp = NULL;
+/* LP: Fix for defect 515161. Crash on AIX
+ * slapi_str2filter is a nasty function that mangle whatever gets passed in.
+ * AIX crashes on altering the literal string.
+ * So we need to allocate the string and then free it.
+ */
+ char *buf = slapi_ch_strdup(s);
+
+ newf = slapi_str2filter(buf);
+ slapi_ch_free((void **)&buf);
+
+ if (NULL == newf) {
+ return -1;
+ }
+
+ /* Now take the parts of newf and put them in f */
+ /* An easy way to do this is to preserve the "next" ptr */
+ temp = f->f_next;
+ *f = *newf;
+ f->f_next = temp;
+ /* Free the new filter husk */
+ slapi_ch_free((void**)&newf);
+ return 0;
+}
+
+static void find_our_friends(char *s, int *has, int *num)
+{
+ *has = (0 == strcasecmp(s,"hassubordinates"));
+ if (!(*has)) {
+ *num = (0 == strcasecmp(s,"numsubordinates"));
+ }
+}
+
+/* Free the parts of a filter we're about to overwrite */
+void free_the_filter_bits(Slapi_Filter *f)
+{
+ /* We need to free: */
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ ava_done( &f->f_ava );
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ if ( f->f_type != NULL ) {
+ slapi_ch_free( (void**)&(f->f_type) );
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int grok_and_rewrite_filter(Slapi_Filter *f)
+{
+ Slapi_Filter *p = NULL;
+ int has = 0;
+ int num = 0;
+ char *rhs = NULL;
+ struct berval rhs_berval;
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ /* Does this involve either of our target attributes ? */
+ find_our_friends(f->f_ava.ava_type,&has,&num);
+ if (has || num) {
+ rhs = f->f_ava.ava_value.bv_val;
+ if (has) {
+ if (0 == strcasecmp(rhs,"TRUE")) {
+ free_the_filter_bits(f);
+ replace_filter(f,"(&(numsubordinates=*)(numsubordinates>=1))");
+ } else if (0 == strcasecmp(rhs, "FALSE")) {
+ free_the_filter_bits(f);
+ replace_filter(f,"(&(objectclass=*)(!(numsubordinates=*)))");
+ } else {
+ return 1; /* Filter we can't rewrite */
+ }
+ }
+ if (num) {
+ int rhs_number = 0;
+
+ rhs_number = atoi(rhs);
+ if (rhs_number > 0) {
+
+ char * theType=f->f_ava.ava_type;
+ rhs_berval = f->f_ava.ava_value;
+ replace_filter(f,"(&(numsubordinates=*)(numsubordinates=x))");
+ /* Now fixup the resulting filter so that x = rhs */
+ slapi_ch_free((void**)&(f->f_and->f_next->f_ava.ava_value.bv_val));
+ /*free type also */
+ slapi_ch_free((void**)&theType);
+
+ f->f_and->f_next->f_ava.ava_value = rhs_berval;
+ } else {
+ if (rhs_number == 0) {
+ /* This is the same as hassubordinates=FALSE */
+ free_the_filter_bits(f);
+ replace_filter(f,"(&(objectclass=*)(!(numsubordinates=*)))");
+ } else {
+ return 1;
+ }
+ }
+ }
+ return 0;
+ }
+ break;
+
+ case LDAP_FILTER_GE:
+ find_our_friends(f->f_ava.ava_type,&has,&num);
+ if (has) {
+ return 1; /* Makes little sense for this attribute */
+ }
+ if (num) {
+ int rhs_num = 0;
+ rhs = f->f_ava.ava_value.bv_val;
+ /* is the value zero ? */
+ rhs_num = atoi(rhs);
+ if (0 == rhs) {
+ /* If so, rewrite to same as numsubordinates=* */
+ free_the_filter_bits(f);
+ replace_filter(f,"(objectclass=*)");
+ } else {
+ /* Rewrite to present and GE the rhs */
+ char * theType=f->f_ava.ava_type;
+ rhs_berval = f->f_ava.ava_value;
+
+ replace_filter(f,"(&(numsubordinates=*)(numsubordinates>=x))");
+ /* Now fixup the resulting filter so that x = rhs */
+ slapi_ch_free((void**)&(f->f_and->f_next->f_ava.ava_value.bv_val));
+ /*free type also */
+ slapi_ch_free((void**)&theType);
+
+ f->f_and->f_next->f_ava.ava_value = rhs_berval;
+ }
+ return 0;
+ }
+ break;
+
+ case LDAP_FILTER_LE:
+ find_our_friends(f->f_ava.ava_type,&has,&num);
+ if (has) {
+ return 1; /* Makes little sense for this attribute */
+ }
+ if (num) {
+ /* One could imagine doing this one, but it's quite hard */
+ return 1;
+ }
+ break;
+
+ case LDAP_FILTER_APPROX:
+ find_our_friends(f->f_ava.ava_type,&has,&num);
+ if (has || num) {
+ /* Not allowed */
+ return 1;
+ }
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ find_our_friends(f->f_sub_type,&has,&num);
+ if (has || num) {
+ /* Not allowed */
+ return 1;
+ }
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ find_our_friends(f->f_type,&has,&num);
+ if (has || num) {
+ /* we rewrite this search to (objectclass=*) */
+ slapi_ch_free((void**)&(f->f_type));
+ f->f_type = slapi_ch_strdup("objectclass");
+ return 0;
+ } /* We already weeded out the special search we use use in the console */
+ break;
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ for ( p = f->f_list; p != NULL; p = p->f_next ) {
+ grok_and_rewrite_filter( p );
+ }
+ break;
+
+ default:
+ return -1; /* Bad, might be an extended filter or something */
+ }
+ return -1;
+}
+
+static int
+ldbm_compute_rewriter(Slapi_PBlock *pb)
+{
+ int rc = -1;
+ char *fstr= NULL;
+
+ /*
+ * We need to look at the filter and see whether it might contain
+ * numSubordinates or hasSubordinates. We want to do a quick check
+ * before we look thoroughly.
+ */
+ slapi_pblock_get( pb, SLAPI_SEARCH_STRFILTER, &fstr );
+
+ if ( NULL != fstr ) {
+ char *lc_fstr = (char *)slapi_utf8StrToLower( (unsigned char *)fstr );
+
+ if (string_find(lc_fstr,"subordinates")) {
+ Slapi_Filter *f = NULL;
+ /* Look for special filters we want to leave alone */
+ if (0 == strcmp(lc_fstr, "(&(numsubordinates=*)(numsubordinates>=1))" )) {
+ ; /* Do nothing, this one works OK */
+ } else {
+ /* So let's grok the filter in detail and try to rewrite it */
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &f );
+ rc = grok_and_rewrite_filter(f);
+ if (0 == rc) {
+ /* he rewrote it ! fixup the string version */
+ /* slapi_pblock_set( pb, SLAPI_SEARCH_STRFILTER, newfstr ); */
+ }
+ }
+ }
+
+ slapi_ch_free_string( &lc_fstr );
+ }
+ return rc;
+}
+
+
+int ldbm_compute_init()
+{
+ int ret = 0;
+ ret = slapi_compute_add_evaluator(ldbm_compute_evaluator);
+ if (0 == ret) {
+ ret = slapi_compute_add_search_rewriter(ldbm_compute_rewriter);
+ }
+ return ret;
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c
new file mode 100644
index 00000000..c114fdd6
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt.c
@@ -0,0 +1,870 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 1999, 2001-2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* This file handles attribute encryption.
+ */
+
+
+#include "back-ldbm.h"
+#include "attrcrypt.h"
+#include "pk11func.h"
+#include "keyhi.h"
+#include "nss.h"
+
+/*
+ * Todo:
+ * Remember to free the private structures in the attrinfos, so avoid a leak.
+ */
+
+attrcrypt_cipher_entry attrcrypt_cipher_list[] = { {ATTRCRYPT_CIPHER_AES, "AES", CKM_AES_CBC_PAD, CKM_AES_CBC_PAD, CKM_AES_CBC_PAD, 128/8, 16} ,
+ {ATTRCRYPT_CIPHER_DES3 , "3DES" , CKM_DES3_CBC_PAD, CKM_DES3_CBC_PAD, CKM_DES3_CBC_PAD, 112/8, 8},
+ {0} };
+
+#define KEY_ATTRIBUTE_NAME "nsSymmetricKey"
+
+/*
+ * We maintain one of these structures per cipher that we handle
+ */
+
+typedef struct _attrcrypt_cipher_state {
+ char *cipher_display_name;
+ PRLock *cipher_lock;
+ PK11SlotInfo *slot;
+ PK11SymKey *key;
+ attrcrypt_cipher_entry *ace;
+} attrcrypt_cipher_state;
+
+struct _attrcrypt_state_private {
+ attrcrypt_cipher_state *acs_array[1];
+};
+
+static int attrcrypt_wrap_key(attrcrypt_cipher_state *acs, PK11SymKey *symmetric_key, SECKEYPublicKey *public_key, SECItem *wrapped_symmetric_key);
+static int attrcrypt_unwrap_key(attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, SECItem *wrapped_symmetric_key, PK11SymKey **unwrapped_symmetric_key);
+
+/*
+ * Copied from front-end because it's private to plugins
+ */
+
+static int
+local_valuearray_count( Slapi_Value **va)
+{
+ int i=0;
+ if(va!=NULL)
+ {
+ while(NULL != va[i]) i++;
+ }
+ return(i);
+}
+
+/*
+ * Helper functions for key management
+ */
+
+static Slapi_Entry *
+getConfigEntry( const char *dn, Slapi_Entry **e2 ) {
+ Slapi_DN sdn;
+
+ slapi_sdn_init_dn_byref( &sdn, dn );
+ slapi_search_internal_get_entry( &sdn, NULL, e2,
+ plugin_get_default_component_id());
+ slapi_sdn_done( &sdn );
+ return *e2;
+}
+
+/**
+ * Free an entry
+ */
+static void
+freeConfigEntry( Slapi_Entry ** e ) {
+ if ( (e != NULL) && (*e != NULL) ) {
+ slapi_entry_free( *e );
+ *e = NULL;
+ }
+}
+
+static int
+attrcrypt_get_ssl_cert_name(char **cert_name)
+{
+ char *config_entry_dn = "cn=RSA,cn=encryption,cn=config";
+ Slapi_Entry *config_entry = NULL;
+
+ *cert_name = NULL;
+ getConfigEntry(config_entry_dn, &config_entry);
+ if (NULL == config_entry) {
+ return -1;
+ }
+ *cert_name = slapi_entry_attr_get_charptr( config_entry, "nssslpersonalityssl" );
+ freeConfigEntry(&config_entry);
+ return 0;
+}
+
+/* Retrieve a symmetric key from dse.ldif for a specified cipher */
+static int
+attrcrypt_keymgmt_get_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, PK11SymKey **key_from_store)
+{
+ int ret = 0;
+ Slapi_Entry *entry = NULL;
+ char *dn_template = "cn=%s,cn=encrypted attribute keys,cn=%s,cn=ldbm database,cn=plugins,cn=config";
+ char *instance_name = li->inst_name;
+ size_t dn_string_length = 0;
+ char *dn_string = NULL;
+ Slapi_Attr *keyattr = NULL;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_keymgmt_get_key\n", 0, 0, 0);
+ dn_string_length = strlen(dn_template) + strlen(instance_name) + strlen(acs->ace->cipher_display_name);
+ dn_string = slapi_ch_malloc(dn_string_length);
+ sprintf(dn_string, dn_template, acs->ace->cipher_display_name, instance_name);
+ /* Fetch the entry */
+ getConfigEntry(dn_string, &entry);
+ /* Did we find the entry ? */
+ if (NULL != entry) {
+ SECItem key_to_unwrap = {0};
+ /* If so then look for the attribute that contains the key */
+ slapi_entry_attr_find(entry, KEY_ATTRIBUTE_NAME, &keyattr);
+ if (keyattr != NULL) {
+ Slapi_Value *v = NULL;
+ slapi_valueset_first_value( &keyattr->a_present_values, &v);
+ key_to_unwrap.len = slapi_value_get_length(v);
+ key_to_unwrap.data = (void*)slapi_value_get_string(v);
+ }
+ /* Unwrap it */
+ ret = attrcrypt_unwrap_key(acs, private_key, &key_to_unwrap, key_from_store);
+ if (entry) {
+ freeConfigEntry(&entry);
+ }
+ } else {
+ ret = -2; /* Means: we didn't find the entry (which happens if the key has never been generated) */
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_keymgmt_get_key\n", 0, 0, 0);
+ return ret;
+}
+
+/* Store a symmetric key for a given cipher in dse.ldif */
+static int
+attrcrypt_keymgmt_store_key(ldbm_instance *li, attrcrypt_cipher_state *acs, SECKEYPublicKey *public_key, PK11SymKey *key_to_store)
+{
+ int ret = 0;
+ SECItem wrapped_symmetric_key = {0};
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_keymgmt_store_key\n", 0, 0, 0);
+ /* Wrap the key and then store it in the right place in dse.ldif */
+ ret = attrcrypt_wrap_key(acs, key_to_store, public_key, &wrapped_symmetric_key);
+ if (!ret) {
+ /* Make the entry to store */
+ Slapi_Entry *e = NULL;
+ Slapi_PBlock *pb = slapi_pblock_new();
+ Slapi_Value *key_value = NULL;
+ struct berval key_as_berval = {0};
+ int rc = 0;
+ char *entry_template =
+ "dn: cn=%s,cn=encrypted attribute keys,cn=%s,cn=ldbm database,cn=plugins,cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:%s\n";
+ char *instance_name = li->inst_name;
+ char *entry_string = NULL;
+ size_t entry_string_length = strlen(entry_template) + strlen(instance_name) + (strlen(acs->ace->cipher_display_name)*2);
+ entry_string = slapi_ch_malloc(entry_string_length);
+ sprintf(entry_string, entry_template,acs->ace->cipher_display_name,instance_name,acs->ace->cipher_display_name);
+ e = slapi_str2entry(entry_string, 0);
+ /* Add the key as a binary attribute */
+ key_as_berval.bv_val = wrapped_symmetric_key.data;
+ key_as_berval.bv_len = wrapped_symmetric_key.len;
+ key_value = slapi_value_new_berval(&key_as_berval);
+ slapi_entry_add_value(e, KEY_ATTRIBUTE_NAME, key_value);
+ slapi_value_free(&key_value);
+ /* Store the entry */
+ slapi_add_entry_internal_set_pb(pb, e, NULL, li->inst_li->li_identity, 0);
+ if ((rc = slapi_add_internal_pb(pb)) != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "attrcrypt_keymgmt_store_key: failed to add config key entries to the DSE: %d\n", rc, 0, 0);
+ }
+ if (entry_string) {
+ slapi_ch_free((void**)&entry_string);
+ }
+ if (pb) {
+ slapi_pblock_destroy(pb);
+ }
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_keymgmt_store_key\n", 0, 0, 0);
+ return ret;
+}
+
+/*
+ * Helper functions for key generation and wrapping
+ */
+
+/* Wrap a key with the server's public assymetric key for storage */
+static int
+attrcrypt_wrap_key(attrcrypt_cipher_state *acs, PK11SymKey *symmetric_key, SECKEYPublicKey *public_key, SECItem *wrapped_symmetric_key)
+{
+ int ret = 0;
+ SECStatus s = 0;
+ CK_MECHANISM_TYPE wrap_mechanism = CKM_RSA_PKCS;
+ SECKEYPublicKey *wrapping_key = public_key;
+ wrapped_symmetric_key->len = slapd_SECKEY_PublicKeyStrength(public_key);
+ wrapped_symmetric_key->data = slapi_ch_malloc(wrapped_symmetric_key->len);
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_wrap_key\n", 0, 0, 0);
+ s = slapd_pk11_PubWrapSymKey(wrap_mechanism, wrapping_key, symmetric_key, wrapped_symmetric_key);
+ if (SECSuccess != s) {
+ ret = -1;
+ LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_wrap_key: failed to wrap key for cipher %s\n", acs->ace->cipher_display_name, 0, 0);
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_wrap_key\n", 0, 0, 0);
+ return ret;
+}
+
+/* Unwrap a key previously wrapped with the server's private key */
+static int
+attrcrypt_unwrap_key(attrcrypt_cipher_state *acs, SECKEYPrivateKey *private_key, SECItem *wrapped_symmetric_key, PK11SymKey **unwrapped_symmetric_key)
+{
+ int ret = 0;
+ CK_MECHANISM_TYPE wrap_mechanism = acs->ace->wrap_mechanism;
+ SECKEYPrivateKey *unwrapping_key = private_key;
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_unwrap_key\n", 0, 0, 0);
+ *unwrapped_symmetric_key = slapd_pk11_PubUnwrapSymKey(unwrapping_key, wrapped_symmetric_key, wrap_mechanism, CKA_UNWRAP, 0);
+ if (NULL == *unwrapped_symmetric_key) {
+ ret = -1;
+ LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_unwrap_key: failed to unwrap key for cipher %s\n", acs->ace->cipher_display_name, 0, 0);
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_unwrap_key\n", 0, 0, 0);
+ return ret;
+}
+
+/* Generate a random key for a specified cipher */
+static int
+attrcrypt_generate_key(attrcrypt_cipher_state *acs,PK11SymKey **symmetric_key)
+{
+ int ret = -1;
+ PK11SymKey *new_symmetric_key = NULL;
+ *symmetric_key = NULL;
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_generate_key\n", 0, 0, 0);
+ new_symmetric_key = slapd_pk11_KeyGen(acs->slot, acs->ace->key_gen_mechanism, NULL, acs->ace->key_size, NULL);
+ if (new_symmetric_key) {
+ *symmetric_key = new_symmetric_key;
+ ret = 0;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_generate_key\n", 0, 0, 0);
+ return ret;
+}
+
+static int
+attrcrypt_fetch_public_key(SECKEYPublicKey **public_key)
+{
+ int ret = 0;
+ CERTCertificate *cert = NULL;
+ SECKEYPublicKey *key = NULL;
+ PRErrorCode errorCode = 0;
+ char *default_cert_name = "server-cert";
+ char *cert_name = NULL;
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_fetch_public_key\n", 0, 0, 0);
+ *public_key = NULL;
+ /* Try to grok the server cert name from the SSL config */
+ ret = attrcrypt_get_ssl_cert_name(&cert_name);
+ if (ret) {
+ cert_name = default_cert_name;
+ }
+ /* We assume that the server core pin stuff is already enabled, via the SSL initialization done in the front-end */
+ cert = slapd_pk11_findCertFromNickname(cert_name, NULL);
+ if (cert == NULL) {
+ errorCode = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,"Can't find certificate %s in attrcrypt_fetch_public_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
+ }
+ if( cert != NULL ) {
+ key = slapd_CERT_ExtractPublicKey(cert);
+ }
+ if (key == NULL) {
+ errorCode = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,"Can't get private key from cert %s in attrcrypt_fetch_public_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
+ ret = -1;
+ }
+ if (cert) {
+ slapd_pk11_CERT_DestroyCertificate(cert);
+ }
+ if (key) {
+ *public_key = key;
+ }else {
+ ret = -1;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_fetch_public_key\n", 0, 0, 0);
+ return ret;
+}
+
+static int
+attrcrypt_fetch_private_key(SECKEYPrivateKey **private_key)
+{
+ int ret = 0;
+ CERTCertificate *cert = NULL;
+ SECKEYPrivateKey *key = NULL;
+ PRErrorCode errorCode = 0;
+ char *default_cert_name = "server-cert";
+ char *cert_name = NULL;
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_fetch_private_key\n", 0, 0, 0);
+ *private_key = NULL;
+ /* Try to grok the server cert name from the SSL config */
+ ret = attrcrypt_get_ssl_cert_name(&cert_name);
+ if (ret) {
+ cert_name = default_cert_name;
+ }
+ /* We assume that the server core pin stuff is already enabled, via the SSL initialization done in the front-end */
+ cert = slapd_pk11_findCertFromNickname(cert_name, NULL);
+ if (cert == NULL) {
+ errorCode = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,"Can't find certificate %s in attrcrypt_fetch_private_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
+ }
+ if( cert != NULL ) {
+ key = slapd_pk11_findKeyByAnyCert(cert, NULL);
+ }
+ if (key == NULL) {
+ errorCode = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,"Can't get private key from cert %s in attrcrypt_fetch_private_key: %d - %s\n", cert_name, errorCode, slapd_pr_strerror(errorCode));
+ ret = -1;
+ }
+ if (cert) {
+ slapd_pk11_CERT_DestroyCertificate(cert);
+ }
+ if (key) {
+ *private_key = key;
+ } else {
+ ret = -1;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_fetch_private_key\n", 0, 0, 0);
+ return ret;
+}
+
+/*
+ CKM_AES_CBC_PAD
+ CKM_DES3_CBC_PAD
+ */
+
+/* Initialize the structure for a single cipher */
+static int
+attrcrypt_cipher_init(ldbm_instance *li, attrcrypt_cipher_entry *ace, SECKEYPrivateKey *private_key, SECKEYPublicKey *public_key, attrcrypt_cipher_state *acs)
+{
+ int ret = 0;
+ PK11SymKey *symmetric_key = NULL;
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_cipher_init\n", 0, 0, 0);
+ acs->cipher_lock = PR_NewLock();
+ /* Fill in some basic stuff */
+ acs->ace = ace;
+ acs->cipher_display_name = ace->cipher_display_name;
+ if (NULL == acs->cipher_lock) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Failed to create cipher lock in attrcrypt_cipher_init\n", 0, 0, 0);
+ }
+ acs->slot = slapd_pk11_GetInternalKeySlot();
+ if (NULL == acs->slot) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Failed to create a slot for cipher %s in attrcrypt_cipher_entry\n", acs->cipher_display_name, 0, 0);
+ goto error;
+ }
+ /* Try to get the symmetric key for this cipher */
+ ret = attrcrypt_keymgmt_get_key(li,acs,private_key,&symmetric_key);
+ if (ret) {
+ if (-2 == ret) {
+ LDAPDebug(LDAP_DEBUG_ANY,"No symmetric key found for cipher %s in backend %s, attempting to create one...\n", acs->cipher_display_name, li->inst_name, 0);
+ ret = attrcrypt_generate_key(acs,&symmetric_key);
+ if (ret) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Failed to generate key for %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
+ }
+ if (symmetric_key) {
+ ret = attrcrypt_keymgmt_store_key(li,acs,public_key,symmetric_key);
+ if (ret) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Failed to store key for cipher %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,"Key for cipher %s successfully generated and stored\n", acs->cipher_display_name, 0, 0);
+ }
+ }
+
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,"Failed to retrieve key for cipher %s in attrcrypt_cipher_init\n", acs->cipher_display_name, 0, 0);
+ }
+ }
+ if (symmetric_key) {
+ /* we loaded the symmetric key, store it in the acs */
+ acs->key = symmetric_key;
+ }
+error:
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_cipher_init\n", 0, 0, 0);
+ return ret;
+}
+
+static void
+attrcrypt_acs_list_add(ldbm_instance *li,attrcrypt_cipher_state *acs)
+{
+ /* Realloc the existing list and add to the end */
+ attrcrypt_cipher_state **current = NULL;
+ size_t list_size = 0;
+ /* Is the list already there ? */
+ if (NULL == li->inst_attrcrypt_state_private) {
+ /* If not, add it */
+ li->inst_attrcrypt_state_private = (attrcrypt_state_private *) slapi_ch_calloc(sizeof(attrcrypt_cipher_state *), 2); /* 2 == The pointer and a NULL terminator */
+ } else {
+ /* Otherwise re-size it */
+ for (current = &(li->inst_attrcrypt_state_private->acs_array[0]); *current; current++) {
+ list_size++;
+ }
+ li->inst_attrcrypt_state_private = (attrcrypt_state_private *) slapi_ch_realloc((char*)li->inst_attrcrypt_state_private,sizeof(attrcrypt_cipher_state *) * (list_size + 2));
+ li->inst_attrcrypt_state_private->acs_array[list_size + 1] = NULL;
+ }
+ li->inst_attrcrypt_state_private->acs_array[list_size] = acs;
+}
+
+int
+attrcrypt_init(ldbm_instance *li)
+{
+ int ret = 0;
+ attrcrypt_cipher_entry *ace = NULL;
+ SECKEYPrivateKey *private_key = NULL;
+ SECKEYPublicKey *public_key = NULL;
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_init\n", 0, 0, 0);
+ if (slapd_security_library_is_initialized()) {
+ li->inst_attrcrypt_state_private = NULL;
+ /* Get the server's private key, which is used to unwrap the stored symmetric keys */
+ ret = attrcrypt_fetch_private_key(&private_key);
+ if (!ret) {
+ ret = attrcrypt_fetch_public_key(&public_key);
+ if (!ret) {
+ for (ace = attrcrypt_cipher_list; ace && ace->cipher_number && !ret; ace++) {
+ /* Make a state object for this cipher */
+ attrcrypt_cipher_state *acs = (attrcrypt_cipher_state *) slapi_ch_calloc(sizeof(attrcrypt_cipher_state),1);
+ ret = attrcrypt_cipher_init(li, ace, private_key, public_key, acs);
+ if (ret) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Failed to initialize cipher %s in attrcrypt_init\n", ace->cipher_display_name, 0, 0);
+ } else {
+ /* Since we succeeded, add the acs to the backend instance list */
+ attrcrypt_acs_list_add(li,acs);
+ LDAPDebug(LDAP_DEBUG_TRACE,"Initialized cipher %s in attrcrypt_init\n", ace->cipher_display_name, 0, 0);
+ }
+
+ }
+ }
+ }
+ } else {
+ if (li->attrcrypt_configured) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Warning: encryption is configured in backend %s, but because SSL is not enabled, database encryption is not available and the configuration will be overridden.\n", li->inst_name, 0, 0);
+ }
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_init : %d\n", ret, 0, 0);
+ return ret;
+}
+
+/*
+ * Called by the config code when a new attribute is added,
+ * to make sure that we already have the runtime state and key
+ * stored for that cipher. If not, we attmept to make it.
+ * If this function succeeds, then its ok to go on to use the
+ * cipher.
+ */
+int attrcrypt_check_enable_cipher(attrcrypt_cipher_entry *ace)
+{
+ int ret = 0;
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_check_enable_cipher\n", 0, 0, 0);
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_check_enable_cipher\n", 0, 0, 0);
+ return ret;
+}
+
+int
+attrcrypt_cleanup(attrcrypt_cipher_state *acs)
+{
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_cleanup\n", 0, 0, 0);
+ if (acs->key) {
+ slapd_pk11_FreeSymKey(acs->key);
+ }
+ if (acs->slot) {
+ slapd_pk11_FreeSlot(acs->slot);
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_cleanup\n", 0, 0, 0);
+ return 0;
+}
+
+static attrcrypt_cipher_state *
+attrcrypt_get_acs(backend *be, attrcrypt_private *priv)
+{
+ /* Walk the list of acs objects looking for the one for our cipher */
+ int cipher = priv->attrcrypt_cipher;
+ ldbm_instance *li = (ldbm_instance *) be->be_instance_info;
+ attrcrypt_state_private* iasp = li->inst_attrcrypt_state_private;
+ if (iasp) {
+ attrcrypt_cipher_state **current = &(iasp->acs_array[0]);
+ while (current) {
+ if ((*current)->ace->cipher_number == cipher) {
+ return *current;
+ }
+ current++;
+ }
+ }
+ return NULL;
+}
+
+#if defined(DEBUG_ATTRCRYPT)
+static void log_bytes(char* format_string, unsigned char *bytes, size_t length)
+{
+ size_t max_length = 20;
+ size_t truncated_length = (length > max_length) ? max_length : length;
+ size_t x = 0;
+ char *print_buffer = NULL;
+ char *print_ptr = NULL;
+
+ print_buffer = (char*)slapi_ch_malloc((truncated_length * 3) + 1);
+ print_ptr = print_buffer;
+
+ for (x = 0; x < truncated_length; x++) {
+ print_ptr += sprintf(print_ptr, "%02x ", bytes[x]);
+ }
+
+ LDAPDebug(LDAP_DEBUG_ANY,format_string, print_buffer, length, 0);
+
+ slapi_ch_free((void**)&print_buffer);
+}
+#endif
+
+/* Either encipher or decipher an attribute value */
+static int
+attrcrypt_crypto_op(attrcrypt_private *priv, backend *be, struct attrinfo *ai, char *in_data, size_t in_size, char **out_data, size_t *out_size, int encrypt)
+{
+ int ret = 0;
+ SECStatus secret = 0;
+ PK11Context* sec_context = NULL;
+ SECItem iv_item = {0};
+ SECItem *security_parameter = NULL;
+ int output_buffer_length = 0;
+ int output_buffer_size1 = 0;
+ int output_buffer_size2 = 0;
+ unsigned char *output_buffer = NULL;
+ attrcrypt_cipher_state *acs = NULL;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op\n", 0, 0, 0);
+ acs = attrcrypt_get_acs(be,ai->ai_attrcrypt);
+ if (NULL == acs) {
+ /* This happens if SSL/NSS has not been enabled */
+ return -1;
+ }
+#if defined(DEBUG_ATTRCRYPT)
+ if (encrypt) {
+ LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op encrypt '%s' (%d)\n", in_data, in_size, 0);
+ } else {
+ log_bytes("attrcrypt_crypto_op decrypt '%s' (%d)\n", in_data, in_size);
+ }
+#endif
+ /* Allocate the output buffer */
+ output_buffer_length = in_size + 16;
+ output_buffer = slapi_ch_malloc(output_buffer_length);
+ /* Now call NSS to do the cipher op */
+ iv_item.data = "aaaaaaaaaaaaaaaa"; /* ptr to an array of IV bytes */
+ iv_item.len = acs->ace->iv_length; /* length of the array of IV bytes */
+ security_parameter = slapd_pk11_ParamFromIV(acs->ace->cipher_mechanism, &iv_item);
+ if (NULL == security_parameter) {
+ int errorCode = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed to make IV for cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
+ goto error;
+ }
+ sec_context = slapd_pk11_createContextBySymKey(acs->ace->cipher_mechanism, (encrypt ? CKA_ENCRYPT : CKA_DECRYPT), acs->key, security_parameter);
+ if (NULL == sec_context) {
+ int errorCode = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
+ goto error;
+ }
+ secret = slapd_pk11_cipherOp(sec_context, output_buffer, &output_buffer_size1, output_buffer_length, in_data, in_size);
+ if (SECSuccess != secret) {
+ int errorCode = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
+ goto error;
+ }
+#if defined(DEBUG_ATTRCRYPT)
+ LDAPDebug(LDAP_DEBUG_ANY,"slapd_pk11_cipherOp %d\n", output_buffer_size1, 0, 0);
+#endif
+ secret = slapd_pk11_DigestFinal(sec_context, output_buffer + output_buffer_size1, &output_buffer_size2, output_buffer_length - output_buffer_size1);
+ if (SECSuccess != secret) {
+ int errorCode = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_crypto_op digest final failed on cipher %s : %d - %s\n", acs->ace->cipher_display_name, errorCode, slapd_pr_strerror(errorCode));
+ goto error;
+ } else {
+#if defined(DEBUG_ATTRCRYPT)
+ if (encrypt) {
+ log_bytes("slapd_pk11_DigestFinal '%s' (%d)\n", output_buffer, output_buffer_size1 + output_buffer_size2);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,"slapd_pk11_DigestFinal '%s', %d\n", output_buffer, output_buffer_size2, 0);
+ }
+#endif
+ *out_size = output_buffer_size1 + output_buffer_size2;
+ *out_data = output_buffer;
+ }
+error:
+ if (sec_context) {
+ slapd_pk11_DestroyContext(sec_context, PR_TRUE);
+ }
+ if (security_parameter) {
+ slapd_SECITEM_FreeItem(security_parameter, PR_TRUE);
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op\n", 0, 0, 0);
+ return ret;
+}
+
+static int
+attrcrypt_crypto_op_value(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value *invalue, Slapi_Value **outvalue, int encrypt)
+{
+ int ret = 0;
+ char *in_data = NULL;
+ size_t in_size = 0;
+ char *out_data = NULL;
+ size_t out_size = 0;
+ struct berval *bval = NULL;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_value\n", 0, 0, 0);
+
+ bval = (struct berval *) slapi_value_get_berval(invalue);
+ in_data = bval->bv_val;
+ in_size = bval->bv_len;
+
+ ret = attrcrypt_crypto_op(priv,be,ai,in_data,in_size,&out_data,&out_size,encrypt);
+
+ if (0 == ret) {
+ struct berval outbervalue = {0};
+ outbervalue.bv_len = out_size;
+ outbervalue.bv_val = out_data;
+ /* This call makes a copy of the payload data, so we need to free the original data after making the call */
+ *outvalue = slapi_value_new_berval(&outbervalue);
+ slapi_ch_free((void**)&out_data);
+ }
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_value: %d\n", ret, 0, 0);
+ return ret;
+}
+
+int
+attrcrypt_crypto_op_value_replace(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value *inoutvalue, int encrypt)
+{
+ int ret = 0;
+ char *in_data = NULL;
+ size_t in_size = 0;
+ char *out_data = NULL;
+ size_t out_size = 0;
+ struct berval *bval = NULL;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_value_replace\n", 0, 0, 0);
+
+ bval = (struct berval *) slapi_value_get_berval(inoutvalue);
+ in_data = bval->bv_val;
+ in_size = bval->bv_len;
+
+ ret = attrcrypt_crypto_op(priv,be,ai,in_data,in_size,&out_data,&out_size,encrypt);
+
+ if (0 == ret) {
+ struct berval outbervalue = {0};
+ outbervalue.bv_len = out_size;
+ outbervalue.bv_val = out_data;
+ /* This takes a copy of the payload, so we need to free it now */
+ slapi_value_set_berval(inoutvalue,&outbervalue);
+ slapi_ch_free((void**)&out_data);
+ }
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_value_replace: %d\n", ret, 0, 0);
+ return ret;
+}
+
+static int
+attrcrypt_crypto_op_values(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value **invalues, Slapi_Value ***outvalues, int encrypt)
+{
+ int ret = 0;
+ int i = 0;
+ Slapi_Value **encrypted_values = NULL;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_values\n", 0, 0, 0);
+ encrypted_values = (Slapi_Value **) slapi_ch_calloc(sizeof(Slapi_Value *),local_valuearray_count(invalues) + 1);
+ for ( i = 0; (invalues[i] != NULL) && (ret == 0); i++ ) {
+ Slapi_Value *encrypted_value = NULL;
+
+ ret = attrcrypt_crypto_op_value(priv,be,ai,invalues[i],&encrypted_value,encrypt);
+ if (0 == ret) {
+ encrypted_values[i] = encrypted_value;
+ }
+ }
+ *outvalues = encrypted_values;
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_values: %d\n", ret, 0, 0);
+ return ret;
+}
+
+static int
+attrcrypt_crypto_op_values_replace(attrcrypt_private *priv, backend *be, struct attrinfo *ai, Slapi_Value **invalues, int encrypt)
+{
+ int ret = 0;
+ int i = 0;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_crypto_op_values_replace\n", 0, 0, 0);
+ for ( i = 0; (invalues[i] != NULL) && (ret == 0); i++ ) {
+
+ ret = attrcrypt_crypto_op_value_replace(priv,be,ai,invalues[i],encrypt);
+ if (ret) {
+ break;
+ }
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_crypto_op_values_replace\n", 0, 0, 0);
+ return ret;
+}
+
+/* Modifies the entry in-place to decrypt any encrypted attributes */
+int
+attrcrypt_decrypt_entry(backend *be, struct backentry *e)
+{
+ int ret = 0;
+ int rc = 0;
+ Slapi_Attr *attr = NULL;
+ char *type = NULL;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_decrypt_entry\n", 0, 0, 0);
+ /* Scan through the entry's attributes, looking to see if any are configured for crypto */
+ for ( rc = slapi_entry_first_attr( e->ep_entry, &attr ); rc == 0 && attr ; rc = slapi_entry_next_attr( e->ep_entry, attr, &attr )) {
+
+ struct attrinfo *ai = NULL;
+ Slapi_Value *value = NULL;
+ int i = 0;
+
+ slapi_attr_get_type( attr, &type );
+ ainfo_get(be, type, &ai);
+
+ if (ai && ai->ai_attrcrypt) {
+ i = slapi_attr_first_value(attr,&value);
+ while (NULL != value && i != -1)
+ {
+ /* Now decrypt the attribute values in place on the original entry */
+ ret = attrcrypt_crypto_op_value_replace(ai->ai_attrcrypt,be,ai,value,0);
+ if (ret) {
+ LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_decrypt_entry: FAILING because decryption operation failed\n", 0, 0, 0);
+ return ret;
+ }
+ i = slapi_attr_next_value(attr,i,&value);
+ }
+ /* Now do the same thing with deleted values */
+ i = attr_first_deleted_value(attr,&value);
+ while (NULL != value && i != -1)
+ {
+ /* Now decrypt the attribute values in place on the original entry */
+ ret = attrcrypt_crypto_op_value_replace(ai->ai_attrcrypt,be,ai,value,0);
+ if (ret) {
+ LDAPDebug(LDAP_DEBUG_ANY,"attrcrypt_decrypt_entry: FAILING because decryption operation failed\n", 0, 0, 0);
+ return ret;
+ }
+ i = attr_next_deleted_value(attr,i,&value);
+ }
+ }
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_decrypt_entry\n", 0, 0, 0);
+ return ret;
+}
+
+/* Encrypts attributes on this entry in-place (only changes the attribute data, nothing else)
+ */
+int
+attrcrypt_encrypt_entry_inplace(backend *be, const struct backentry *inout)
+{
+ int ret = 0;
+ int rc = 0;
+ char *type = NULL;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value **svals = NULL;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_encrypt_entry_inplace\n", 0, 0, 0);
+ /* Scan the entry's attributes looking for any that are configured for encryption */
+ for ( rc = slapi_entry_first_attr( inout->ep_entry, &attr ); rc == 0;
+ rc = slapi_entry_next_attr( inout->ep_entry, attr, &attr ) ) {
+
+ struct attrinfo *ai = NULL;
+
+ slapi_attr_get_type( attr, &type );
+
+ ainfo_get(be, type, &ai);
+
+ if (ai && ai->ai_attrcrypt) {
+ svals = attr_get_present_values(attr);
+ if (svals) {
+ /* Now encrypt the attribute values in place on the new entry */
+ ret = attrcrypt_crypto_op_values_replace(ai->ai_attrcrypt,be,ai,svals,1);
+ }
+ }
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_encrypt_entry_inplace\n", 0, 0, 0);
+ return ret;
+}
+
+/* Makes a copy of the entry that has all necessary attributes encrypted
+ * as a performance optimization, if there are no attributes configured
+ * for encryption in the entry, then no copy is returned.
+ */
+int
+attrcrypt_encrypt_entry(backend *be, const struct backentry *in, struct backentry **out)
+{
+ int ret = 0;
+ int rc = 0;
+ struct backentry *new_entry = NULL;
+ char *type = NULL;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value **svals = NULL;
+ Slapi_Value **new_vals = NULL;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_encrypt_entry\n", 0, 0, 0);
+ *out = NULL;
+ /* Scan the entry's attributes looking for any that are configured for encryption */
+ for ( rc = slapi_entry_first_attr( in->ep_entry, &attr ); rc == 0;
+ rc = slapi_entry_next_attr( in->ep_entry, attr, &attr ) ) {
+
+ struct attrinfo *ai = NULL;
+
+ slapi_attr_get_type( attr, &type );
+
+ ainfo_get(be, type, &ai);
+
+ if (ai && ai->ai_attrcrypt) {
+ svals = attr_get_present_values(attr);
+ if (svals) {
+ /* If we find one, did we make the new entry yet ? */
+ if (NULL == new_entry) {
+ /* If not then make it now as a copy of the old entry */
+ new_entry = backentry_dup((struct backentry *)in);
+ }
+ /* Now encrypt the attribute values in place on the new entry */
+ ret = attrcrypt_crypto_op_values(ai->ai_attrcrypt,be,ai,svals,&new_vals,1);
+ if (ret) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Error: attrcrypt_crypto_op_values failed in attrcrypt_encrypt_entry\n", 0, 0, 0);
+ break;
+ }
+ /* DBDB does this call free the old value memory ? */
+ slapi_entry_attr_replace_sv(new_entry->ep_entry, type, new_vals);
+ }
+ }
+ }
+ *out = new_entry;
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_encrypt_entry\n", 0, 0, 0);
+ return ret;
+}
+
+/*
+ * Encrypt an index key. There is never any need to decrypt index keys since
+ * we only ever look them up using plain text.
+ */
+int
+attrcrypt_encrypt_index_key(backend *be, struct attrinfo *ai, const struct berval *in, struct berval **out)
+{
+ int ret = 0;
+ char *in_data = in->bv_val;
+ size_t in_size = in->bv_len;
+ char *out_data = NULL;
+ size_t out_size = 0;
+ struct berval *out_berval = NULL;
+
+ if (ai->ai_attrcrypt) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"-> attrcrypt_encrypt_index_key\n", 0, 0, 0);
+ ret = attrcrypt_crypto_op(ai->ai_attrcrypt,be,ai, in_data,in_size,&out_data,&out_size, 1);
+ if (0 == ret) {
+ out_berval = (struct berval *)ber_alloc();
+ if (NULL == out_berval) {
+ return ENOMEM;
+ }
+ out_berval->bv_len = out_size;
+ /* Because we're making a new berval, we copy the payload pointer in */
+ /* It's now the responsibility of our caller to free that data */
+ out_berval->bv_val = out_data;
+ *out = out_berval;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE,"<- attrcrypt_encrypt_index_key\n", 0, 0, 0);
+ }
+ return ret;
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt_config.c b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt_config.c
new file mode 100644
index 00000000..7ec93554
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_attrcrypt_config.c
@@ -0,0 +1,298 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* This file handles configuration information that is specific
+ * to ldbm instance attribute encryption configuration.
+ */
+
+/* DBDB I left in the Sun copyright statement because some of the code
+ * in this file is derived from an older file : ldbm_index_config.c
+ */
+
+#include "back-ldbm.h"
+#include "attrcrypt.h"
+
+/* Forward declarations for the callbacks */
+int ldbm_instance_attrcrypt_config_add_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int ldbm_instance_attrcrypt_config_delete_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+
+/*
+
+Config entries look like this:
+
+dn: cn=<attributeName>, cn=encrypted attributes, cn=databaseName, cn=ldbm database, cn=plugins, cn=config
+objectclass: top
+objectclass: nsAttributeEncryption
+cn: <attributeName>
+nsEncryptionAlgorithm: <cipherName>
+
+*/
+
+static int
+ldbm_attrcrypt_parse_cipher(char* cipher_display_name)
+{
+ attrcrypt_cipher_entry *ce = attrcrypt_cipher_list;
+ while (ce->cipher_number) {
+ if (0 == strcmp(ce->cipher_display_name,cipher_display_name)) {
+ return ce->cipher_number;
+ }
+ ce++;
+ }
+ return 0;
+}
+
+static int
+ldbm_attrcrypt_parse_entry(ldbm_instance *inst, Slapi_Entry *e,
+ char **attribute_name,
+ int *cipher)
+{
+ Slapi_Attr *attr;
+ const struct berval *attrValue;
+ Slapi_Value *sval;
+
+ *cipher = 0;
+ *attribute_name = NULL;
+
+ /* Get the name of the attribute to index which will be the value
+ * of the cn attribute. */
+ if (slapi_entry_attr_find(e, "cn", &attr) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: malformed attribute encryption entry %s\n",
+ slapi_entry_get_dn(e), 0, 0);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ *attribute_name = slapi_ch_strdup(attrValue->bv_val);
+
+ /* Get the list of index types from the entry. */
+ if (0 == slapi_entry_attr_find(e, "nsEncryptionAlgorithm", &attr)) {
+ slapi_attr_first_value(attr, &sval);
+ if (sval) {
+ attrValue = slapi_value_get_berval(sval);
+ *cipher = ldbm_attrcrypt_parse_cipher(attrValue->bv_val);
+ if (0 == *cipher)
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: attempt to configure unrecognized cipher %s in encrypted attribute config entry %s\n",
+ attrValue->bv_val, slapi_entry_get_dn(e), 0);
+ }
+ }
+ return LDAP_SUCCESS;
+}
+
+static void
+ldbm_instance_attrcrypt_enable(struct attrinfo *ai, int cipher)
+{
+ attrcrypt_private *priv = NULL;
+ if (NULL == ai->ai_attrcrypt) {
+ /* No existing private structure, allocate one */
+ ai->ai_attrcrypt = (attrcrypt_private*) slapi_ch_calloc(1, sizeof(attrcrypt_private));
+ }
+ priv = ai->ai_attrcrypt;
+ priv->attrcrypt_cipher = cipher;
+}
+
+static void
+ldbm_instance_attrcrypt_disable(struct attrinfo *ai)
+{
+ if (NULL != ai->ai_attrcrypt) {
+ /* Don't free the structure here, because other threads might be
+ * concurrently referencing it.
+ */
+ ai->ai_attrcrypt = 0;
+ }
+}
+
+/*
+ * Config DSE callback for attribute encryption entry add.
+ */
+int
+ldbm_instance_attrcrypt_config_add_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* eAfter, int *returncode, char *returntext, void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *) arg;
+ char *attribute_name = NULL;
+ int cipher = 0;
+ int ret = 0;
+
+ returntext[0] = '\0';
+
+ /* For add, we parse the entry, then check the attribute exists,
+ * then check that indexing config does not preclude us encrypting it,
+ * and finally we set the private structure in the attrinfo for the attribute.
+ */
+
+ *returncode = ldbm_attrcrypt_parse_entry(inst, e, &attribute_name , &cipher);
+
+ if (*returncode == LDAP_SUCCESS) {
+
+ struct attrinfo *ai = NULL;
+
+ /* If the cipher was invalid, return unwilling to perform */
+ if (0 == cipher) {
+ returntext = "invalid cipher";
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ ret = SLAPI_DSE_CALLBACK_ERROR;
+ } else {
+
+ ainfo_get(inst->inst_be, attribute_name, &ai);
+ /* If we couldn't find a non-default attrinfo, then that means
+ * that no indexing or encryption has yet been defined for this attribute
+ * therefore , create a new attrinfo structure now.
+ */
+ if ((ai == NULL) || (0 == strcmp(LDBM_PSEUDO_ATTR_DEFAULT, ai->ai_type) )) {
+ /* If this attribute doesn't exist in the schema, then we DO NOT fail
+ * (this is because entensible objects and disabled schema checking allow
+ * non-schema attributes to exist.
+ */
+ /* Make a new attrinfo object */
+ attr_create_empty(inst->inst_be,attribute_name,&ai);
+ }
+ if (ai) {
+ ldbm_instance_attrcrypt_enable(ai, cipher);
+ /* Remember that we have some encryption enabled, so we can be intelligent about warning when SSL is not enabled */
+ inst->attrcrypt_configured = 1;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: attempt to encryption on a non-existent attribute: %s\n",
+ attribute_name, 0, 0);
+ returntext = "attribute does not exist";
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ ret = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ ret = SLAPI_DSE_CALLBACK_OK;
+ }
+
+ } else {
+ ret = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ if (attribute_name) {
+ slapi_ch_free(&attribute_name);
+ }
+ return ret;
+}
+
+/*
+ * Temp callback that gets called for each attribute encryption entry when a new
+ * instance is starting up.
+ */
+int
+ldbm_attrcrypt_init_entry_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ return ldbm_instance_attrcrypt_config_add_callback(pb,e,entryAfter,returncode,returntext,arg);
+}
+
+/*
+ * Config DSE callback for attribute encryption deletes.
+ */
+int
+ldbm_instance_attrcrypt_config_delete_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *) arg;
+ char *attribute_name = NULL;
+ int cipher = 0;
+ int ret = SLAPI_DSE_CALLBACK_ERROR;
+
+ returntext[0] = '\0';
+
+ /* For add, we parse the entry, then check the attribute exists,
+ * then check that indexing config does not preclude us encrypting it,
+ * and finally we set the private structure in the attrinfo for the attribute.
+ */
+
+ *returncode = ldbm_attrcrypt_parse_entry(inst, e, &attribute_name , &cipher);
+
+ if (*returncode == LDAP_SUCCESS) {
+
+ struct attrinfo *ai = NULL;
+
+ ainfo_get(inst->inst_be, attribute_name, &ai);
+ if (ai == NULL && (0 == strcmp(LDBM_PSEUDO_ATTR_DEFAULT, ai->ai_type)) ) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: attempt to delete encryption for non-existant attribute: %s\n",
+ attribute_name, 0, 0);
+ } else {
+ ldbm_instance_attrcrypt_disable(ai);
+ ret = SLAPI_DSE_CALLBACK_OK;
+ }
+ }
+ if (attribute_name) {
+ slapi_ch_free((void **)&attribute_name);
+ }
+ return ret;
+}
+
+/*
+ * Config DSE callback for index entry changes.
+ *
+ * this function is huge!
+ */
+int
+ldbm_instance_attrcrypt_config_modify_callback(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+ Slapi_Attr *attr;
+ Slapi_Value *sval;
+ const struct berval *attrValue;
+ struct attrinfo *ainfo = NULL;
+ LDAPMod **mods;
+ int i = 0;
+ int j = 0;
+
+ returntext[0] = '\0';
+ *returncode = LDAP_SUCCESS;
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+
+ slapi_entry_attr_find(e, "cn", &attr);
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ ainfo_get(inst->inst_be, attrValue->bv_val, &ainfo);
+ if (NULL == ainfo) {
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ for (i = 0; mods[i] != NULL; i++) {
+
+ char *config_attr = (char *)mods[i]->mod_type;
+
+ /* There are basically three cases in the modify:
+ * 1. The attribute was added
+ * 2. The attribute was deleted
+ * 3. The attribute was modified (deleted and added).
+ * Now, of these three, only #3 is legal.
+ * This is because the attribute is mandatory and single-valued in the schema.
+ * We handle this as follows: an add will always replace what's there (if anything).
+ * a delete will remove what's there as long as it matches what's being deleted.
+ * this is to avoid ordering problems with the adds and deletes.
+ */
+
+ if (strcasecmp(config_attr, "nsEncryptionAlgorithm") == 0) {
+
+ if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+
+ for (j = 0; mods[i]->mod_bvalues[j] != NULL; j++) {
+ int cipher = ldbm_attrcrypt_parse_cipher(mods[i]->mod_bvalues[j]->bv_val);
+ if (0 == cipher) {
+ /* Tried to configure an invalid cipher */
+ }
+ ldbm_instance_attrcrypt_enable(ainfo,cipher);
+ }
+ continue;
+ }
+ if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ if ((mods[i]->mod_bvalues == NULL) ||
+ (mods[i]->mod_bvalues[0] == NULL)) {
+ /* Not legal */
+ return SLAPI_DSE_CALLBACK_ERROR;
+ } else {
+ for (j = 0; mods[i]->mod_bvalues[j] != NULL; j++) {
+ /* Code before here should ensure that we only ever delete something that was already here */
+ ldbm_instance_attrcrypt_disable(ainfo);
+ }
+ }
+ continue;
+ }
+ }
+ }
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_bind.c b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
new file mode 100644
index 00000000..de70c601
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_bind.c
@@ -0,0 +1,245 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* bind.c - ldbm backend bind and unbind routines */
+
+#include "back-ldbm.h"
+
+#if defined( XP_WIN32 )
+
+typedef enum LDAPWAEnum {
+ LDAPWA_NoDomainAttr = -3,
+ LDAPWA_InvalidCredentials = -2,
+ LDAPWA_Failure = -1,
+ LDAPWA_Success= 0
+} LDAPWAStatus;
+
+int
+GetDomainUsername(
+ char *pszNTuserdomainid,
+ char *pszNTDomain,
+ char *pszNTUsername
+)
+{
+ char *pszAttr, *pDomain, *pUsername;
+
+ if( !pszNTuserdomainid )
+ return( 1 );
+
+ // Split the specially constructed attribute.
+ pszAttr = slapi_ch_strdup( pszNTuserdomainid );
+
+ pDomain = pszAttr;
+
+ pUsername = strchr( pszAttr, ':' );
+ if( pUsername == NULL )
+ return( 1 );
+
+ // Set the end of the NT Domain name,
+ // and the start of the NT username.
+ *pUsername = (char)NULL;
+ pUsername++;
+
+ strcpy( pszNTDomain, pDomain);
+ strcpy( pszNTUsername, pUsername);
+
+ slapi_ch_free( (void**)&pszAttr );
+
+ return( 0 );
+}
+
+/* Attempt Windows NT Authentication, using the password from the client app,
+ with the NT Domain and NT username, both stored in the entry.
+ If successful, the ldap_bind() is completed successsfully. */
+
+LDAPWAStatus
+WindowsAuthentication(
+ struct backentry *e,
+ struct berval *cred
+)
+{
+ Slapi_Attr *a;
+ Slapi_Value *sval = NULL;
+ int iStatus;
+ char szNTDomain[MAX_PATH], szNTUsername[MAX_PATH];
+ HANDLE hToken = NULL;
+ BOOL bLogonStatus = FALSE;
+ int i= -1;
+
+ /* Get the NT Domain and username - if the entry has such an attribute */
+ if( !e || !e->ep_entry ||
+ slapi_entry_attr_find( e->ep_entry, "ntuserdomainid", &a ) != 0)
+ {
+ return( LDAPWA_NoDomainAttr );
+ }
+
+ i= slapi_attr_first_value( a, &sval );
+ if(sval==NULL)
+ {
+ return( LDAPWA_NoDomainAttr );
+ }
+
+ while(i != -1)
+ {
+ const struct berval *val = slapi_value_get_berval(sval);
+ char * colon = NULL;
+
+ if (!val->bv_val || (strlen(val->bv_val) > (MAX_PATH<<1))) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "WindowsAuthentication => validation FAILED for \"%s\" on NT Domain : "
+ "ntuserdomainid attr value too long\n",
+ val->bv_val, 0, 0);
+ i= slapi_attr_next_value(a, i, &sval);
+ continue;
+ }
+ colon = strchr( val->bv_val, ':' );
+ if (!colon || ((colon - val->bv_val)/sizeof(char) > MAX_PATH)) {
+ if (!colon) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "WindowsAuthentication => validation FAILED for \"%s\" on NT Domain : "
+ "a colon is missing in ntuserdomainid attr value\n",
+ val->bv_val, 0, 0);
+ }
+ else {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "WindowsAuthentication => validation FAILED for \"%s\" on NT Domain : "
+ "domain in ntuserdomainid attr value too long\n",
+ val->bv_val, 0, 0);
+ }
+ i= slapi_attr_next_value(a, i, &sval);
+ continue;
+ }
+
+ if(( iStatus = GetDomainUsername( val->bv_val,
+ szNTDomain,
+ szNTUsername )) != 0)
+ {
+ i= slapi_attr_next_value(a, i, &sval);
+ continue;
+ }
+
+#if !defined( LOGON32_LOGON_NETWORK )
+/* This is specified in the WIn32 LogonUser() documentation, but not defined
+ in the Visual C++ 4.2 include file winbase.h. A search of the lastest version
+ of this file at www.microsoft.com finds that LOGON32_LOGON_NETWORK == 3.
+ */
+#define LOGON32_LOGON_NETWORK 3
+#endif
+ /* Now do the Logon attempt */
+ bLogonStatus = LogonUser( szNTUsername, // string that specifies the user name
+ szNTDomain, // string that specifies the domain or server
+ cred->bv_val, // string that specifies the password
+ LOGON32_LOGON_NETWORK, // the type of logon operation,
+ LOGON32_PROVIDER_DEFAULT, // specifies the logon provider
+ &hToken ); // pointer to variable to receive token handle
+ if( bLogonStatus && hToken )
+ CloseHandle( hToken );
+
+ if( bLogonStatus )
+ {
+ // Successful validation
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "WindowsAuthentication => validated \"%s\" on NT Domain \"%s\"\n",
+ szNTUsername, szNTDomain, 0 );
+ return( LDAPWA_Success );
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "WindowsAuthentication => validation FAILED for \"%s\" on NT Domain \"%s\", reason %d\n",
+ szNTUsername, szNTDomain, GetLastError() );
+ return( LDAPWA_InvalidCredentials );
+ }
+ i= slapi_attr_next_value(a, i, &sval);
+ }
+
+
+ return( LDAPWA_Failure );
+
+}
+#endif
+
+int
+ldbm_back_bind( Slapi_PBlock *pb )
+{
+ backend *be;
+ ldbm_instance *inst;
+ int method;
+ struct berval *cred;
+ struct ldbminfo *li;
+ struct backentry *e;
+ Slapi_Attr *attr;
+ Slapi_Value **bvals;
+ entry_address *addr;
+
+ /* get parameters */
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr );
+ slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method );
+ slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred );
+
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ /* always allow noauth simple binds (front end will send the result) */
+ if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
+ return( SLAPI_BIND_ANONYMOUS );
+ }
+
+ /*
+ * find the target entry. find_entry() takes care of referrals
+ * and sending errors if the entry does not exist.
+ */
+ if (( e = find_entry( pb, be, addr, NULL /* no txn */ )) == NULL ) {
+ return( SLAPI_BIND_FAIL );
+ }
+
+ switch ( method ) {
+ case LDAP_AUTH_SIMPLE:
+ {
+ Slapi_Value cv;
+ if ( slapi_entry_attr_find( e->ep_entry, "userpassword", &attr ) != 0 ) {
+#if defined( XP_WIN32 )
+ if( WindowsAuthentication( e, cred ) == LDAPWA_Success ) {
+ break;
+ }
+#endif
+ slapi_send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
+ NULL, 0, NULL );
+ cache_return( &inst->inst_cache, &e );
+ return( SLAPI_BIND_FAIL );
+ }
+ bvals= attr_get_present_values(attr);
+ slapi_value_init_berval(&cv,cred);
+ if ( slapi_pw_find_sv( bvals, &cv ) != 0 ) {
+#if defined( XP_WIN32 )
+ /* One last try - attempt Windows authentication,
+ if the user has a Windows account. */
+ if( WindowsAuthentication( e, cred ) == LDAPWA_Success ) {
+ break;
+ }
+#endif
+ slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
+ NULL, 0, NULL );
+ cache_return( &inst->inst_cache, &e );
+ value_done(&cv);
+ return( SLAPI_BIND_FAIL );
+ }
+ value_done(&cv);
+ }
+ break;
+
+ default:
+ slapi_send_ldap_result( pb, LDAP_STRONG_AUTH_NOT_SUPPORTED, NULL,
+ "auth method not supported", 0, NULL );
+ cache_return( &inst->inst_cache, &e );
+ return( SLAPI_BIND_FAIL );
+ }
+
+ cache_return( &inst->inst_cache, &e );
+
+ /* success: front end will send result */
+ return( SLAPI_BIND_SUCCESS );
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_compare.c b/ldap/servers/slapd/back-ldbm/ldbm_compare.c
new file mode 100644
index 00000000..a63f6009
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_compare.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 **/
+/* compare.c - ldbm backend compare routine */
+
+#include "back-ldbm.h"
+
+int
+ldbm_back_compare( Slapi_PBlock *pb )
+{
+ backend *be;
+ ldbm_instance *inst;
+ struct ldbminfo *li;
+ struct backentry *e;
+ int err;
+ char *type;
+ struct berval *bval;
+ entry_address *addr;
+ Slapi_Value compare_value;
+ int result;
+ int ret = 0;
+ Slapi_DN *namespace_dn;
+
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr);
+ slapi_pblock_get( pb, SLAPI_COMPARE_TYPE, &type );
+ slapi_pblock_get( pb, SLAPI_COMPARE_VALUE, &bval );
+
+ inst = (ldbm_instance *) be->be_instance_info;
+ /* get the namespace dn */
+ namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
+
+ if ( (e = find_entry( pb, be, addr, NULL )) == NULL ) {
+ return( -1 ); /* error result sent by find_entry() */
+ }
+
+ err = slapi_access_allowed (pb, e->ep_entry, type, bval, SLAPI_ACL_COMPARE);
+ if ( err != LDAP_SUCCESS ) {
+ slapi_send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ ret = 1;
+ } else {
+
+ slapi_value_init_berval(&compare_value,bval);
+
+ err = slapi_vattr_namespace_value_compare(e->ep_entry,namespace_dn,type,&compare_value,&result,0);
+
+ if (0 != err) {
+ /* Was the attribute not found ? */
+ if (SLAPI_VIRTUALATTRS_NOT_FOUND == err) {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL,0, NULL );
+ ret = 1;
+ } else {
+ /* Some other problem, call it an operations error */
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL,0, NULL );
+ ret = -1;
+ }
+ } else {
+ /* Interpret the result */
+ if (result) {
+ /* Compare true */
+ slapi_send_ldap_result( pb, LDAP_COMPARE_TRUE, NULL, NULL, 0, NULL );
+ } else {
+ /* Compare false */
+ slapi_send_ldap_result( pb, LDAP_COMPARE_FALSE, NULL, NULL, 0, NULL );
+ }
+ ret = 0;
+ }
+ value_done(&compare_value);
+ }
+
+ cache_return( &inst->inst_cache, &e );
+ return( ret );
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.c b/ldap/servers/slapd/back-ldbm/ldbm_config.c
new file mode 100644
index 00000000..59e197f3
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.c
@@ -0,0 +1,1730 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* ldbm_config.c - Handles configuration information that is global to all ldbm instances. */
+
+#include "back-ldbm.h"
+#include "dblayer.h"
+
+/* Forward declarations */
+static int parse_ldbm_config_entry(struct ldbminfo *li, Slapi_Entry *e, config_info *config_array);
+
+/* Forward callback declarations */
+int ldbm_config_search_entry_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int ldbm_config_modify_entry_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+
+static char *ldbm_skeleton_entries[] =
+{
+ "dn:cn=config, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:config\n",
+
+ "dn:cn=monitor, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:monitor\n",
+
+ "dn:cn=database, cn=monitor, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:database\n",
+
+ ""
+};
+
+/* Used to add an array of entries, like the one above and
+ * ldbm_instance_skeleton_entries in ldbm_instance_config.c, to the dse.
+ * Returns 0 on success.
+ */
+int ldbm_config_add_dse_entries(struct ldbminfo *li, char **entries, char *string1, char *string2, char *string3, int flags)
+{
+ int x;
+ Slapi_Entry *e;
+ Slapi_PBlock *util_pb = NULL;
+ int rc;
+ char entry_string[512];
+ int dont_write_file = 0;
+
+ if (flags & LDBM_INSTANCE_CONFIG_DONT_WRITE) {
+ dont_write_file = 1;
+ }
+
+ for(x = 0; strlen(entries[x]) > 0; x++) {
+ util_pb = slapi_pblock_new();
+ sprintf(entry_string, entries[x], string1, string2, string3);
+ e = slapi_str2entry(entry_string, 0);
+ slapi_add_entry_internal_set_pb(util_pb, e, NULL, li->li_identity, 0);
+ slapi_pblock_set(util_pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING,
+ &dont_write_file);
+ if ((rc = slapi_add_internal_pb(util_pb)) != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Unable to add config entries to the DSE: %d\n", rc, 0, 0);
+ }
+ slapi_pblock_destroy(util_pb);
+ }
+
+ return 0;
+}
+
+/* used to add a single entry, special case of above */
+int ldbm_config_add_dse_entry(struct ldbminfo *li, char *entry, int flags)
+{
+ char *entries[] = { "%s", "" };
+
+ return ldbm_config_add_dse_entries(li, entries, entry, NULL, NULL, flags);
+}
+
+/* Finds an entry in a config_info array with the given name. Returns
+ * the entry on success and NULL when not found.
+ */
+config_info *get_config_info(config_info *config_array, char *attr_name)
+{
+ int x;
+
+ for(x = 0; config_array[x].config_name != NULL; x++) {
+ if (!strcasecmp(config_array[x].config_name, attr_name)) {
+ return &(config_array[x]);
+ }
+ }
+ return NULL;
+}
+
+/*------------------------------------------------------------------------
+ * Get and set functions for ldbm and dblayer variables
+ *----------------------------------------------------------------------*/
+static void *ldbm_config_lookthroughlimit_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) (li->li_lookthroughlimit);
+}
+
+static int ldbm_config_lookthroughlimit_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ /* Do whatever we can to make sure the data is ok. */
+
+ if (apply) {
+ li->li_lookthroughlimit = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_mode_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) (li->li_mode);
+}
+
+static int ldbm_config_mode_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ /* Do whatever we can to make sure the data is ok. */
+
+ if (apply) {
+ li->li_mode = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_allidsthreshold_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) (li->li_allidsthreshold);
+}
+
+static int ldbm_config_allidsthreshold_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ /* Do whatever we can to make sure the data is ok. */
+
+ /* Catch attempts to configure a stupidly low allidsthreshold */
+ if (val < 100) {
+ val = 100;
+ }
+
+ if (apply) {
+ li->li_allidsthreshold = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_directory_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ /* Remember get functions of type string need to return
+ * alloced memory. */
+ return (void *) slapi_ch_strdup(li->li_new_directory);
+}
+
+static int ldbm_config_directory_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ char *val = (char *) value;
+ char tmpbuf[BUFSIZ];
+
+ errorbuf[0] = '\0';
+
+ if (!apply) {
+ /* we should really do some error checking here. */
+ return retval;
+ }
+
+ if (CONFIG_PHASE_RUNNING == phase) {
+ slapi_ch_free((void **) &(li->li_new_directory));
+ li->li_new_directory = slapi_ch_strdup(val);
+ LDAPDebug(LDAP_DEBUG_ANY, "New db directory location will not take affect until the server is restarted\n", 0, 0, 0);
+ } else {
+ if (!strcmp(val, "get default")) {
+ /* Generate the default db directory name. The default db directory
+ * should be the instance directory with a '/db' thrown on the end.
+ * We need to read cn=config to get the instance dir. */
+ /* We use this funky "get default" string for the caller to
+ * tell us that it has no idea what the db directory should
+ * be. This code figures it out be reading cn=config. */
+
+ Slapi_PBlock *search_pb;
+ Slapi_Entry **entries = NULL;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *v = NULL;
+ const char *s = NULL;
+ int res;
+
+ search_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(search_pb, "cn=config", LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL, li->li_identity, 0);
+ slapi_search_internal_pb(search_pb);
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if (res != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: ldbm plugin unable to read cn=config\n",
+ 0, 0, 0);
+ goto done;
+ }
+
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: ldbm plugin unable to read cn=config\n",
+ 0, 0, 0);
+ res = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ res = slapi_entry_attr_find(entries[0], "nsslapd-instancedir", &attr);
+ if (res != 0 || attr == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: ldbm plugin unable to read attribute nsslapd-instancedir from cn=config\n",
+ 0, 0, 0);
+ res = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+ if ( slapi_attr_first_value(attr,&v) != 0
+ || ( NULL == v )
+ || ( NULL == ( s = slapi_value_get_string( v )))) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: ldbm plugin unable to read attribute nsslapd-instancedir from cn=config\n",
+ 0, 0, 0);
+ res = LDAP_OPERATIONS_ERROR;
+ goto done;
+ }
+
+done:
+ slapi_pblock_destroy(search_pb);
+ if (res != LDAP_SUCCESS) {
+ return res;
+ }
+ sprintf(tmpbuf, "%s/db", s );
+ val = tmpbuf;
+ }
+ slapi_ch_free((void **) &(li->li_new_directory));
+ slapi_ch_free((void **) &(li->li_directory));
+ li->li_new_directory = slapi_ch_strdup(val);
+ li->li_directory = slapi_ch_strdup(val);
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_dbcachesize_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) (li->li_new_dbcachesize);
+}
+
+static int ldbm_config_dbcachesize_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ size_t val = (size_t) value;
+
+ if (apply) {
+ /* Stop the user configuring a stupidly small cache */
+ /* min: 8KB (page size) * def thrd cnts (threadnumber==20). */
+#define DBDEFMINSIZ 500000
+ if (val < DBDEFMINSIZ) {
+ LDAPDebug( LDAP_DEBUG_ANY,"WARNING: cache too small, increasing to %dK bytes\n", DBDEFMINSIZ/1000, 0, 0);
+ val = DBDEFMINSIZ;
+ }
+
+ if (CONFIG_PHASE_RUNNING == phase) {
+ li->li_new_dbcachesize = val;
+ LDAPDebug(LDAP_DEBUG_ANY, "New db cache size will not take affect until the server is restarted\n", 0, 0, 0);
+ } else {
+ li->li_new_dbcachesize = val;
+ li->li_dbcachesize = val;
+ }
+
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_maxpassbeforemerge_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) (li->li_maxpassbeforemerge);
+}
+
+static int ldbm_config_maxpassbeforemerge_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ if (val < 0) {
+ LDAPDebug( LDAP_DEBUG_ANY,"WARNING: maxpassbeforemerge will not take negative value\n", 0, 0, 0);
+ val = 100;
+ }
+
+ li->li_maxpassbeforemerge = val;
+ }
+
+ return retval;
+}
+
+
+static void *ldbm_config_dbncache_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) (li->li_new_dbncache);
+}
+
+static int ldbm_config_dbncache_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ if (val < 0) {
+ LDAPDebug( LDAP_DEBUG_ANY,"WARNING: ncache will not take negative value\n", 0, 0, 0);
+ val = 0;
+ }
+
+ if (CONFIG_PHASE_RUNNING == phase) {
+ li->li_new_dbncache = val;
+ LDAPDebug(LDAP_DEBUG_ANY, "New db ncache will not take affect until the server is restarted\n", 0, 0, 0);
+ } else {
+ li->li_new_dbncache = val;
+ li->li_dbncache = val;
+ }
+
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_logdirectory_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ /* Remember get functions of type string need to return
+ * alloced memory. */
+ /* if dblayer_log_directory is set to a string different from ""
+ * then it has been set, return this variable
+ * otherwise it is set to default, use the instance home directory
+ */
+ if (strlen(li->li_dblayer_private->dblayer_log_directory) > 0)
+ return (void *) slapi_ch_strdup(li->li_dblayer_private->dblayer_log_directory);
+ else
+ return (void *) slapi_ch_strdup(li->li_new_directory);
+
+}
+
+static int ldbm_config_db_logdirectory_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ char *val = (char *) value;
+
+ if (apply) {
+ slapi_ch_free((void **) &(li->li_dblayer_private->dblayer_log_directory));
+ li->li_dblayer_private->dblayer_log_directory = slapi_ch_strdup(val);
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_durable_transactions_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_durable_transactions;
+}
+
+static int ldbm_config_db_durable_transactions_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_durable_transactions = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_lockdown_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_lockdown;
+}
+
+static int ldbm_config_db_lockdown_set(
+ void *arg,
+ void *value,
+ char *errorbuf,
+ int phase,
+ int apply
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_lockdown = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_circular_logging_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_circular_logging;
+}
+
+static int ldbm_config_db_circular_logging_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_circular_logging = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_transaction_logging_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_enable_transactions;
+}
+
+static int ldbm_config_db_transaction_logging_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_enable_transactions = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_logbuf_size_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_logbuf_size;
+}
+
+static int ldbm_config_db_logbuf_size_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ size_t val = (size_t) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_logbuf_size = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_checkpoint_interval_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_checkpoint_interval;
+}
+
+static int ldbm_config_db_checkpoint_interval_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_checkpoint_interval = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_page_size_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_page_size;
+}
+
+static int ldbm_config_db_page_size_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ size_t val = (size_t) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_page_size = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_index_page_size_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_index_page_size;
+}
+
+static int ldbm_config_db_index_page_size_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ size_t val = (size_t) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_index_page_size = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_idl_divisor_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_idl_divisor;
+}
+
+static int ldbm_config_db_idl_divisor_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_idl_divisor = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_logfile_size_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_logfile_size;
+}
+
+static int ldbm_config_db_logfile_size_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ size_t val = (size_t) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_logfile_size = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_spin_count_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_spin_count;
+}
+
+static int ldbm_config_db_spin_count_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_spin_count = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_trickle_percentage_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_trickle_percentage;
+}
+
+static int ldbm_config_db_trickle_percentage_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (val < 0 || val > 100) {
+ sprintf(errorbuf, "Error: Invalid value for %s (%d). Must be between 0 and 100\n", CONFIG_DB_TRICKLE_PERCENTAGE, val);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", errorbuf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_trickle_percentage = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_verbose_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_verbose;
+}
+
+static int ldbm_config_db_verbose_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_verbose = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_debug_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_debug;
+}
+
+static int ldbm_config_db_debug_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_debug = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_named_regions_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_named_regions;
+}
+
+static int ldbm_config_db_named_regions_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_named_regions = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_private_mem_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_private_mem;
+}
+
+static int ldbm_config_db_private_mem_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_private_mem = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_private_import_mem_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_private_import_mem;
+}
+
+static int ldbm_config_db_private_import_mem_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_private_import_mem = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_shm_key_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_shm_key;
+}
+
+static int ldbm_config_db_shm_key_set(
+ void *arg,
+ void *value,
+ char *errorbuf,
+ int phase,
+ int apply
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_shm_key = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_lock_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_lock_config;
+}
+
+
+static int ldbm_config_db_lock_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ size_t val = (size_t) value;
+
+ if (apply) {
+ if (CONFIG_PHASE_RUNNING == phase) {
+ li->li_dblayer_private->dblayer_lock_config = val;
+ LDAPDebug(LDAP_DEBUG_ANY, "New db cache size will not take affect until the server is restarted\n", 0, 0, 0);
+ } else {
+ li->li_dblayer_private->dblayer_lock_config = val;
+ }
+
+ }
+
+ return retval;
+}
+static void *ldbm_config_db_cache_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_cache_config;
+}
+
+static int ldbm_config_db_cache_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_cache_config = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_debug_checkpointing_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->db_debug_checkpointing;
+}
+
+static int ldbm_config_db_debug_checkpointing_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->db_debug_checkpointing = val;
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_db_home_directory_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ /* Remember get functions of type string need to return
+ * alloced memory. */
+ return (void *) slapi_ch_strdup(li->li_dblayer_private->dblayer_dbhome_directory);
+}
+
+static int ldbm_config_db_home_directory_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ char *val = (char *) value;
+
+ if (apply) {
+ slapi_ch_free((void **) &(li->li_dblayer_private->dblayer_dbhome_directory));
+ li->li_dblayer_private->dblayer_dbhome_directory = slapi_ch_strdup(val);
+ }
+
+ return retval;
+}
+
+static void *ldbm_config_import_cache_autosize_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ return (void *)(li->li_import_cache_autosize);
+}
+
+static int ldbm_config_import_cache_autosize_set(void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ if (apply)
+ li->li_import_cache_autosize = (int)value;
+ return LDAP_SUCCESS;
+}
+
+static void *ldbm_config_cache_autosize_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ return (void *)(li->li_cache_autosize);
+}
+
+static int ldbm_config_cache_autosize_set(void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ if (apply)
+ li->li_cache_autosize = (int)value;
+ return LDAP_SUCCESS;
+}
+
+static void *ldbm_config_cache_autosize_split_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ return (void *)(li->li_cache_autosize_split);
+}
+
+static int ldbm_config_cache_autosize_split_set(void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ if (apply)
+ li->li_cache_autosize_split = (int)value;
+ return LDAP_SUCCESS;
+}
+
+static void *ldbm_config_import_cachesize_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ return (void *)(li->li_import_cachesize);
+}
+
+static int ldbm_config_import_cachesize_set(void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ if (apply)
+ li->li_import_cachesize = (size_t)value;
+ return LDAP_SUCCESS;
+}
+
+static void *ldbm_config_index_buffer_size_get(void *arg)
+{
+ return (void *)import_get_index_buffer_size();
+}
+
+static int ldbm_config_index_buffer_size_set(void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ if (apply)
+ import_configure_index_buffer_size((size_t)value);
+ return LDAP_SUCCESS;
+}
+
+static void *ldbm_config_idl_get_idl_new(void *arg)
+{
+ if (idl_get_idl_new())
+ return slapi_ch_strdup("new");
+ else
+ return slapi_ch_strdup("old");
+}
+
+static int ldbm_config_idl_set_tune(void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ if (!strcasecmp("new", value))
+ idl_set_tune(4096);
+ else
+ idl_set_tune(0);
+ return LDAP_SUCCESS;
+}
+
+static void *ldbm_config_serial_lock_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_fat_lock;
+}
+
+static int ldbm_config_serial_lock_set(void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ if (apply) {
+ li->li_fat_lock = (int) value;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static void *ldbm_config_legacy_errcode_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_legacy_errcode;
+}
+
+static int ldbm_config_legacy_errcode_set(void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ if (apply) {
+ li->li_legacy_errcode = (int) value;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+ldbm_config_set_bypass_filter_test(void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ if (apply) {
+ char *myvalue = (char *)value;
+
+ if (0 == strcasecmp(myvalue, "on")) {
+ li->li_filter_bypass = 1;
+ li->li_filter_bypass_check = 0;
+ } else if (0 == strcasecmp(myvalue, "verify")) {
+ li->li_filter_bypass = 1;
+ li->li_filter_bypass_check = 1;
+ } else {
+ li->li_filter_bypass = 0;
+ li->li_filter_bypass_check = 0;
+ }
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *ldbm_config_get_bypass_filter_test(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+ char *retstr = NULL;
+
+ if (li->li_filter_bypass) {
+ if (li->li_filter_bypass_check) {
+ /* meaningful only if is bypass filter test called */
+ retstr = slapi_ch_strdup("verify");
+ } else {
+ retstr = slapi_ch_strdup("on");
+ }
+ } else {
+ retstr = slapi_ch_strdup("off");
+ }
+ return (void *)retstr;
+}
+
+static int ldbm_config_set_use_vlv_index(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int val = (int) value;
+
+ if (apply) {
+ int setval = 0;
+ if (val) {
+ li->li_use_vlv = 1;
+ } else {
+ li->li_use_vlv = 0;
+ }
+ }
+ return LDAP_SUCCESS;
+}
+
+static void *ldbm_config_get_use_vlv_index(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_use_vlv;
+}
+
+static int
+ldbm_config_exclude_from_export_set( void *arg, void *value, char *errorbuf,
+ int phase, int apply)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+
+ if ( apply ) {
+ if ( NULL != li->li_attrs_to_exclude_from_export ) {
+ charray_free( li->li_attrs_to_exclude_from_export );
+ li->li_attrs_to_exclude_from_export = NULL;
+ }
+
+ if ( NULL != value ) {
+ char *dupvalue = slapi_ch_strdup( value );
+ li->li_attrs_to_exclude_from_export = str2charray( dupvalue, " " );
+ slapi_ch_free((void**)&dupvalue);
+ }
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static void *
+ldbm_config_exclude_from_export_get( void *arg )
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+ char *p, *retstr = NULL;
+ size_t len = 0;
+
+ if ( NULL != li->li_attrs_to_exclude_from_export &&
+ NULL != li->li_attrs_to_exclude_from_export[0] ) {
+ int i;
+
+ for ( i = 0; li->li_attrs_to_exclude_from_export[i] != NULL; ++i ) {
+ len += strlen( li->li_attrs_to_exclude_from_export[i] ) + 1;
+ }
+ p = retstr = slapi_ch_malloc( len );
+ for ( i = 0; li->li_attrs_to_exclude_from_export[i] != NULL; ++i ) {
+ if ( i > 0 ) {
+ *p++ = ' ';
+ }
+ strcpy( p, li->li_attrs_to_exclude_from_export[i] );
+ p += strlen( p );
+ }
+ *p = '\0';
+ } else {
+ retstr = slapi_ch_strdup( "" );
+ }
+
+ return (void *)retstr;
+}
+
+static void *ldbm_config_db_tx_max_get(void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+
+ return (void *) li->li_dblayer_private->dblayer_tx_max;
+}
+
+static int ldbm_config_db_tx_max_set(
+ void *arg,
+ void *value,
+ char *errorbuf,
+ int phase,
+ int apply
+)
+{
+ struct ldbminfo *li = (struct ldbminfo *) arg;
+ int retval = LDAP_SUCCESS;
+ int val = (int) value;
+
+ if (apply) {
+ li->li_dblayer_private->dblayer_tx_max = val;
+ }
+
+ return retval;
+}
+
+
+/*------------------------------------------------------------------------
+ * Configuration array for ldbm and dblayer variables
+ *----------------------------------------------------------------------*/
+static config_info ldbm_config[] = {
+ {CONFIG_LOOKTHROUGHLIMIT, CONFIG_TYPE_INT, "5000", &ldbm_config_lookthroughlimit_get, &ldbm_config_lookthroughlimit_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_MODE, CONFIG_TYPE_INT_OCTAL, "0600", &ldbm_config_mode_get, &ldbm_config_mode_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_IDLISTSCANLIMIT, CONFIG_TYPE_INT, "4000", &ldbm_config_allidsthreshold_get, &ldbm_config_allidsthreshold_set, CONFIG_FLAG_ALWAYS_SHOW},
+ {CONFIG_DIRECTORY, CONFIG_TYPE_STRING, "", &ldbm_config_directory_get, &ldbm_config_directory_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_DBCACHESIZE, CONFIG_TYPE_SIZE_T, "10000000", &ldbm_config_dbcachesize_get, &ldbm_config_dbcachesize_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_DBNCACHE, CONFIG_TYPE_INT, "0", &ldbm_config_dbncache_get, &ldbm_config_dbncache_set, CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_MAXPASSBEFOREMERGE, CONFIG_TYPE_INT, "100", &ldbm_config_maxpassbeforemerge_get, &ldbm_config_maxpassbeforemerge_set, 0},
+
+ /* dblayer config attributes */
+ {CONFIG_DB_LOGDIRECTORY, CONFIG_TYPE_STRING, "", &ldbm_config_db_logdirectory_get, &ldbm_config_db_logdirectory_set, CONFIG_FLAG_ALWAYS_SHOW},
+ {CONFIG_DB_DURABLE_TRANSACTIONS, CONFIG_TYPE_ONOFF, "on", &ldbm_config_db_durable_transactions_get, &ldbm_config_db_durable_transactions_set, CONFIG_FLAG_ALWAYS_SHOW},
+ {CONFIG_DB_CIRCULAR_LOGGING, CONFIG_TYPE_ONOFF, "on", &ldbm_config_db_circular_logging_get, &ldbm_config_db_circular_logging_set, 0},
+ {CONFIG_DB_TRANSACTION_LOGGING, CONFIG_TYPE_ONOFF, "on", &ldbm_config_db_transaction_logging_get, &ldbm_config_db_transaction_logging_set, CONFIG_FLAG_ALWAYS_SHOW},
+ {CONFIG_DB_CHECKPOINT_INTERVAL, CONFIG_TYPE_INT, "60", &ldbm_config_db_checkpoint_interval_get, &ldbm_config_db_checkpoint_interval_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_DB_TRANSACTION_BATCH, CONFIG_TYPE_INT, "0", &dblayer_get_batch_transactions, &dblayer_set_batch_transactions, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_DB_LOGBUF_SIZE, CONFIG_TYPE_SIZE_T, "0", &ldbm_config_db_logbuf_size_get, &ldbm_config_db_logbuf_size_set, CONFIG_FLAG_ALWAYS_SHOW},
+ {CONFIG_DB_PAGE_SIZE, CONFIG_TYPE_SIZE_T, "0", &ldbm_config_db_page_size_get, &ldbm_config_db_page_size_set, 0},
+ {CONFIG_DB_INDEX_PAGE_SIZE, CONFIG_TYPE_SIZE_T, "0", &ldbm_config_db_index_page_size_get, &ldbm_config_db_index_page_size_set, 0},
+ {CONFIG_DB_IDL_DIVISOR, CONFIG_TYPE_INT, "0", &ldbm_config_db_idl_divisor_get, &ldbm_config_db_idl_divisor_set, 0},
+ {CONFIG_DB_LOGFILE_SIZE, CONFIG_TYPE_SIZE_T, "0", &ldbm_config_db_logfile_size_get, &ldbm_config_db_logfile_size_set, 0},
+ {CONFIG_DB_TRICKLE_PERCENTAGE, CONFIG_TYPE_INT, "5", &ldbm_config_db_trickle_percentage_get, &ldbm_config_db_trickle_percentage_set, 0},
+ {CONFIG_DB_SPIN_COUNT, CONFIG_TYPE_INT, "0", &ldbm_config_db_spin_count_get, &ldbm_config_db_spin_count_set, 0},
+ {CONFIG_DB_VERBOSE, CONFIG_TYPE_ONOFF, "off", &ldbm_config_db_verbose_get, &ldbm_config_db_verbose_set, 0},
+ {CONFIG_DB_DEBUG, CONFIG_TYPE_ONOFF, "on", &ldbm_config_db_debug_get, &ldbm_config_db_debug_set, 0},
+ {CONFIG_DB_NAMED_REGIONS, CONFIG_TYPE_ONOFF, "off", &ldbm_config_db_named_regions_get, &ldbm_config_db_named_regions_set, 0},
+ {CONFIG_DB_LOCK, CONFIG_TYPE_INT, "10000", &ldbm_config_db_lock_get, &ldbm_config_db_lock_set, 0},
+ {CONFIG_DB_PRIVATE_MEM, CONFIG_TYPE_ONOFF, "off", &ldbm_config_db_private_mem_get, &ldbm_config_db_private_mem_set, 0},
+ {CONFIG_DB_PRIVATE_IMPORT_MEM, CONFIG_TYPE_ONOFF, "on", &ldbm_config_db_private_import_mem_get, &ldbm_config_db_private_import_mem_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_DB_SHM_KEY, CONFIG_TYPE_LONG, "389389", &ldbm_config_db_shm_key_get, &ldbm_config_db_shm_key_set, 0},
+ {CONFIG_DB_CACHE, CONFIG_TYPE_INT, "0", &ldbm_config_db_cache_get, &ldbm_config_db_cache_set, 0},
+ {CONFIG_DB_DEBUG_CHECKPOINTING, CONFIG_TYPE_ONOFF, "off", &ldbm_config_db_debug_checkpointing_get, &ldbm_config_db_debug_checkpointing_set, 0},
+ {CONFIG_DB_HOME_DIRECTORY, CONFIG_TYPE_STRING, "", &ldbm_config_db_home_directory_get, &ldbm_config_db_home_directory_set, 0},
+ {CONFIG_IMPORT_CACHE_AUTOSIZE, CONFIG_TYPE_INT, "-1", &ldbm_config_import_cache_autosize_get, &ldbm_config_import_cache_autosize_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_CACHE_AUTOSIZE, CONFIG_TYPE_INT, "0", &ldbm_config_cache_autosize_get, &ldbm_config_cache_autosize_set, 0},
+ {CONFIG_CACHE_AUTOSIZE_SPLIT, CONFIG_TYPE_INT, "50", &ldbm_config_cache_autosize_split_get, &ldbm_config_cache_autosize_split_set, 0},
+ {CONFIG_IMPORT_CACHESIZE, CONFIG_TYPE_SIZE_T, "20000000", &ldbm_config_import_cachesize_get, &ldbm_config_import_cachesize_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+#if defined(USE_NEW_IDL)
+ {CONFIG_IDL_SWITCH, CONFIG_TYPE_STRING, "new", &ldbm_config_idl_get_idl_new, &ldbm_config_idl_set_tune, CONFIG_FLAG_ALWAYS_SHOW},
+#else
+ {CONFIG_IDL_SWITCH, CONFIG_TYPE_STRING, "old", &ldbm_config_idl_get_idl_new, &ldbm_config_idl_set_tune, CONFIG_FLAG_ALWAYS_SHOW},
+#endif
+ {CONFIG_BYPASS_FILTER_TEST, CONFIG_TYPE_STRING, "on", &ldbm_config_get_bypass_filter_test, &ldbm_config_set_bypass_filter_test, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_USE_VLV_INDEX, CONFIG_TYPE_ONOFF, "on", &ldbm_config_get_use_vlv_index, &ldbm_config_set_use_vlv_index, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_DB_LOCKDOWN, CONFIG_TYPE_ONOFF, "off", &ldbm_config_db_lockdown_get, &ldbm_config_db_lockdown_set, 0},
+ {CONFIG_INDEX_BUFFER_SIZE, CONFIG_TYPE_INT, "0", &ldbm_config_index_buffer_size_get, &ldbm_config_index_buffer_size_set, 0},
+ {CONFIG_EXCLUDE_FROM_EXPORT, CONFIG_TYPE_STRING,
+ CONFIG_EXCLUDE_FROM_EXPORT_DEFAULT_VALUE,
+ &ldbm_config_exclude_from_export_get,
+ &ldbm_config_exclude_from_export_set, CONFIG_FLAG_ALWAYS_SHOW},
+ {CONFIG_DB_TX_MAX, CONFIG_TYPE_INT, "200", &ldbm_config_db_tx_max_get, &ldbm_config_db_tx_max_set, 0},
+ {CONFIG_SERIAL_LOCK, CONFIG_TYPE_ONOFF, "on", &ldbm_config_serial_lock_get, &ldbm_config_serial_lock_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_USE_LEGACY_ERRORCODE, CONFIG_TYPE_ONOFF, "off", &ldbm_config_legacy_errcode_get, &ldbm_config_legacy_errcode_set, 0},
+ {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+void ldbm_config_setup_default(struct ldbminfo *li)
+{
+ config_info *config;
+ char err_buf[BUFSIZ];
+
+ for (config = ldbm_config; config->config_name != NULL; config++) {
+ ldbm_config_set((void *)li, config->config_name, ldbm_config, NULL /* use default */, err_buf, CONFIG_PHASE_INITIALIZATION, 1 /* apply */);
+ }
+}
+
+void
+ldbm_config_read_instance_entries(struct ldbminfo *li, const char *backend_type)
+{
+ Slapi_PBlock *tmp_pb;
+ char basedn[BUFSIZ];
+ Slapi_Entry **entries = NULL;
+
+ /* Construct the base dn of the subtree that holds the instance entries. */
+ sprintf(basedn, "cn=%s, cn=plugins, cn=config", backend_type);
+
+ /* Do a search of the subtree containing the instance entries */
+ tmp_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(tmp_pb, basedn, LDAP_SCOPE_SUBTREE, "(objectclass=nsBackendInstance)", NULL, 0, NULL, NULL, li->li_identity, 0);
+ slapi_search_internal_pb (tmp_pb);
+ slapi_pblock_get(tmp_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (entries!=NULL) {
+ int i;
+ for (i=0; entries[i]!=NULL; i++) {
+ ldbm_instance_add_instance_entry_callback(NULL, entries[i], NULL, NULL, NULL, li);
+ }
+ }
+
+ slapi_free_search_results_internal(tmp_pb);
+ slapi_pblock_destroy(tmp_pb);
+}
+
+/* Reads in any config information held in the dse for the ldbm plugin.
+ * Creates dse entries used to configure the ldbm plugin and dblayer
+ * if they don't already exist. Registers dse callback functions to
+ * maintain those dse entries. Returns 0 on success.
+ */
+int ldbm_config_load_dse_info(struct ldbminfo *li)
+{
+ Slapi_PBlock *search_pb;
+ Slapi_Entry **entries = NULL;
+ int res;
+ char dn[BUFSIZ];
+
+ /* We try to read the entry
+ * cn=config, cn=ldbm database, cn=plugins, cn=config. If the entry is
+ * there, then we process the config information it stores.
+ */
+ sprintf(dn, "cn=config, cn=%s, cn=plugins, cn=config",
+ li->li_plugin->plg_name);
+ search_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(search_pb, dn, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL, li->li_identity, 0);
+ slapi_search_internal_pb (search_pb);
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if (LDAP_NO_SUCH_OBJECT == res) {
+ /* Add skeleten dse entries for the ldbm plugin */
+ ldbm_config_add_dse_entries(li, ldbm_skeleton_entries,
+ li->li_plugin->plg_name, NULL, NULL, 0);
+ } else if (res != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error accessing the ldbm config DSE\n",
+ 0, 0, 0);
+ return 1;
+ } else {
+ /* Need to parse the configuration information for the ldbm
+ * plugin that is held in the DSE. */
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+ &entries);
+ if (NULL == entries || entries[0] == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error accessing the ldbm config DSE\n",
+ 0, 0, 0);
+ return 1;
+ }
+ parse_ldbm_config_entry(li, entries[0], ldbm_config);
+ }
+
+ if (search_pb) {
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+ }
+
+ /* Find all the instance entries and create a Slapi_Backend and an
+ * ldbm_instance for each */
+ ldbm_config_read_instance_entries(li, li->li_plugin->plg_name);
+
+ /* setup the dse callback functions for the ldbm backend config entry */
+ sprintf(dn, "cn=config, cn=%s, cn=plugins, cn=config",
+ li->li_plugin->plg_name);
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_config_search_entry_callback,
+ (void *) li);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_config_modify_entry_callback,
+ (void *) li);
+ slapi_config_register_callback(DSE_OPERATION_WRITE, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_config_search_entry_callback,
+ (void *) li);
+
+ /* setup the dse callback functions for the ldbm backend monitor entry */
+ sprintf(dn, "cn=monitor, cn=%s, cn=plugins, cn=config",
+ li->li_plugin->plg_name);
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_back_monitor_search,
+ (void *)li);
+
+ /* And the ldbm backend database monitor entry */
+ sprintf(dn, "cn=database, cn=monitor, cn=%s, cn=plugins, cn=config",
+ li->li_plugin->plg_name);
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_back_dbmonitor_search,
+ (void *)li);
+
+ /* setup the dse callback functions for the ldbm backend instance
+ * entries */
+ sprintf(dn, "cn=%s, cn=plugins, cn=config", li->li_plugin->plg_name);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsBackendInstance)",
+ ldbm_instance_add_instance_entry_callback, (void *) li);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_POSTOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsBackendInstance)",
+ ldbm_instance_postadd_instance_entry_callback, (void *) li);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsBackendInstance)",
+ ldbm_instance_delete_instance_entry_callback, (void *) li);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_POSTOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsBackendInstance)",
+ ldbm_instance_post_delete_instance_entry_callback, (void *) li);
+
+ return 0;
+}
+
+
+/* Utility function used in creating config entries. Using the
+ * config_info, this function gets info and formats in the correct
+ * way.
+ */
+void ldbm_config_get(void *arg, config_info *config, char *buf)
+{
+ char *tmp_string;
+
+ if (config == NULL) {
+ buf[0] = '\0';
+ }
+
+ switch(config->config_type) {
+ case CONFIG_TYPE_INT:
+ sprintf(buf, "%d", (int) config->config_get_fn(arg));
+ break;
+ case CONFIG_TYPE_INT_OCTAL:
+ sprintf(buf, "%o", (int) config->config_get_fn(arg));
+ break;
+ case CONFIG_TYPE_LONG:
+ sprintf(buf, "%ld", (long) config->config_get_fn(arg));
+ break;
+ case CONFIG_TYPE_SIZE_T:
+ sprintf(buf, "%lu", (size_t) config->config_get_fn(arg));
+ break;
+ case CONFIG_TYPE_STRING:
+ /* Remember the get function for strings returns memory
+ * that must be freed. */
+ tmp_string = (char *) config->config_get_fn(arg);
+ sprintf(buf, "%s", (char *) tmp_string);
+ slapi_ch_free((void **)&tmp_string);
+ break;
+ case CONFIG_TYPE_ONOFF:
+ if ((int) config->config_get_fn(arg)) {
+ sprintf(buf, "on");
+ } else {
+ sprintf(buf, "off");
+ }
+ break;
+ }
+}
+
+/*
+ * Returns:
+ * SLAPI_DSE_CALLBACK_ERROR on failure
+ * SLAPI_DSE_CALLBACK_OK on success
+ */
+int ldbm_config_search_entry_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ char buf[BUFSIZ];
+ struct berval *vals[2];
+ struct berval val;
+ struct ldbminfo *li= (struct ldbminfo *) arg;
+ config_info *config;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ returntext[0] = '\0';
+
+ PR_Lock(li->li_config_mutex);
+
+ for(config = ldbm_config; config->config_name != NULL; config++) {
+ /* Go through the ldbm_config table and fill in the entry. */
+
+ if (!(config->config_flags & (CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_PREVIOUSLY_SET))) {
+ /* This config option shouldn't be shown */
+ continue;
+ }
+
+ ldbm_config_get((void *) li, config, buf);
+
+ val.bv_val = buf;
+ val.bv_len = strlen(buf);
+ slapi_entry_attr_replace(e, config->config_name, vals);
+ }
+
+ PR_Unlock(li->li_config_mutex);
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+int ldbm_config_ignored_attr(char *attr_name)
+{
+ /* These are the names of attributes that are in the
+ * config entries but are not config attributes. */
+ if (!strcasecmp("objectclass", attr_name) ||
+ !strcasecmp("cn", attr_name) ||
+ !strcasecmp("creatorsname", attr_name) ||
+ !strcasecmp("modifiersname", attr_name) ||
+ !strcasecmp("createtimestamp", attr_name) ||
+ !strcasecmp("numsubordinates", attr_name) ||
+ !strcasecmp("modifytimestamp", attr_name)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* Returns LDAP_SUCCESS on success */
+int ldbm_config_set(void *arg, char *attr_name, config_info *config_array, struct berval *bval, char *err_buf, int phase, int apply_mod)
+{
+ config_info *config;
+ int use_default;
+ int int_val;
+ long long_val;
+ size_t sz_val;
+ PRInt64 llval;
+ int maxint = (int)(((unsigned int)~0)>>1);
+ int minint = ~maxint;
+ PRInt64 llmaxint;
+ PRInt64 llminint;
+ int err = 0;
+ char *str_val;
+ int retval = 0;
+
+ LL_I2L(llmaxint, maxint);
+ LL_I2L(llminint, minint);
+
+ config = get_config_info(config_array, attr_name);
+ if (NULL == config) {
+ LDAPDebug(LDAP_DEBUG_CONFIG, "Unknown config attribute %s\n", attr_name, 0, 0);
+ sprintf(err_buf, "Unknown config attribute %s\n", attr_name);
+ return LDAP_SUCCESS; /* Ignore unknown attributes */
+ }
+
+ /* Some config attrs can't be changed while the server is running. */
+ if (phase == CONFIG_PHASE_RUNNING &&
+ !(config->config_flags & CONFIG_FLAG_ALLOW_RUNNING_CHANGE)) {
+ sprintf(err_buf, "%s can't be modified while the server is running.\n", attr_name);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", err_buf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ /* If the config phase is initialization or if bval is NULL, we will use
+ * the default value for the attribute. */
+ if (CONFIG_PHASE_INITIALIZATION == phase || NULL == bval) {
+ use_default = 1;
+ } else {
+ use_default = 0;
+
+ /* Since we are setting the value for the config attribute, we
+ * need to turn on the CONFIG_FLAG_PREVIOUSLY_SET flag to make
+ * sure this attribute is shown. */
+ config->config_flags |= CONFIG_FLAG_PREVIOUSLY_SET;
+ }
+
+ switch(config->config_type) {
+ case CONFIG_TYPE_INT:
+ if (use_default) {
+ str_val = config->config_default_value;
+ } else {
+ str_val = bval->bv_val;
+ }
+ /* get the value as a 64 bit value */
+ llval = db_atoi(str_val, &err);
+ /* check for parsing error (e.g. not a number) */
+ if (err) {
+ sprintf(err_buf, "Error: value %s for attr %s is not a number\n",
+ str_val, attr_name);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", err_buf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ /* check for overflow */
+ } else if (LL_CMP(llval, >, llmaxint)) {
+ sprintf(err_buf, "Error: value %s for attr %s is greater than the maximum %d\n",
+ str_val, attr_name, maxint);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", err_buf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ /* check for underflow */
+ } else if (LL_CMP(llval, <, llminint)) {
+ sprintf(err_buf, "Error: value %s for attr %s is less than the minimum %d\n",
+ str_val, attr_name, minint);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", err_buf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ /* convert 64 bit value to 32 bit value */
+ LL_L2I(int_val, llval);
+ retval = config->config_set_fn(arg, (void *) int_val, err_buf, phase, apply_mod);
+ break;
+ case CONFIG_TYPE_INT_OCTAL:
+ if (use_default) {
+ int_val = (int) strtol(config->config_default_value, NULL, 8);
+ } else {
+ int_val = (int) strtol((char *)bval->bv_val, NULL, 8);
+ }
+ retval = config->config_set_fn(arg, (void *) int_val, err_buf, phase, apply_mod);
+ break;
+ case CONFIG_TYPE_LONG:
+ if (use_default) {
+ str_val = config->config_default_value;
+ } else {
+ str_val = bval->bv_val;
+ }
+ /* get the value as a 64 bit value */
+ llval = db_atoi(str_val, &err);
+ /* check for parsing error (e.g. not a number) */
+ if (err) {
+ sprintf(err_buf, "Error: value %s for attr %s is not a number\n",
+ str_val, attr_name);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", err_buf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ /* check for overflow */
+ } else if (LL_CMP(llval, >, llmaxint)) {
+ sprintf(err_buf, "Error: value %s for attr %s is greater than the maximum %d\n",
+ str_val, attr_name, maxint);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", err_buf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ /* check for underflow */
+ } else if (LL_CMP(llval, <, llminint)) {
+ sprintf(err_buf, "Error: value %s for attr %s is less than the minimum %d\n",
+ str_val, attr_name, minint);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", err_buf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ /* convert 64 bit value to 32 bit value */
+ LL_L2I(long_val, llval);
+ retval = config->config_set_fn(arg, (void *) long_val, err_buf, phase, apply_mod);
+ break;
+ case CONFIG_TYPE_SIZE_T:
+ if (use_default) {
+ str_val = config->config_default_value;
+ } else {
+ str_val = bval->bv_val;
+ }
+
+ /* get the value as a size_t value */
+ sz_val = db_strtoul(str_val, &err);
+
+ /* check for parsing error (e.g. not a number) */
+ if (err == EINVAL) {
+ sprintf(err_buf, "Error: value %s for attr %s is not a number\n",
+ str_val, attr_name);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", err_buf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ /* check for overflow */
+ } else if (err == ERANGE) {
+ sprintf(err_buf, "Error: value %s for attr %s is outside the range of representable values\n",
+ str_val, attr_name);
+ LDAPDebug(LDAP_DEBUG_ANY, "%s", err_buf, 0, 0);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ retval = config->config_set_fn(arg, (void *) sz_val, err_buf, phase, apply_mod);
+ break;
+ case CONFIG_TYPE_STRING:
+ if (use_default) {
+ retval = config->config_set_fn(arg, config->config_default_value, err_buf, phase, apply_mod);
+ } else {
+ retval = config->config_set_fn(arg, bval->bv_val, err_buf, phase, apply_mod);
+ }
+ break;
+ case CONFIG_TYPE_ONOFF:
+ if (use_default) {
+ int_val = !strcasecmp(config->config_default_value, "on");
+ } else {
+ int_val = !strcasecmp((char *) bval->bv_val, "on");
+ }
+ retval = config->config_set_fn(arg, (void *) int_val, err_buf, phase, apply_mod);
+ break;
+ }
+
+ return retval;
+}
+
+
+static int parse_ldbm_config_entry(struct ldbminfo *li, Slapi_Entry *e, config_info *config_array)
+{
+ Slapi_Attr *attr = NULL;
+
+ for (slapi_entry_first_attr(e, &attr); attr; slapi_entry_next_attr(e, attr, &attr)) {
+ char *attr_name = NULL;
+ Slapi_Value *sval = NULL;
+ struct berval *bval;
+ char err_buf[BUFSIZ];
+
+ slapi_attr_get_type(attr, &attr_name);
+
+ /* There are some attributes that we don't care about, like objectclass. */
+ if (ldbm_config_ignored_attr(attr_name)) {
+ continue;
+ }
+
+ slapi_attr_first_value(attr, &sval);
+ bval = (struct berval *) slapi_value_get_berval(sval);
+
+ if (ldbm_config_set(li, attr_name, config_array, bval, err_buf, CONFIG_PHASE_STARTUP, 1 /* apply */) != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error with config attribute %s : %s\n", attr_name, err_buf, 0);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Returns:
+ * SLAPI_DSE_CALLBACK_ERROR on failure
+ * SLAPI_DSE_CALLBACK_OK on success
+ */
+int ldbm_config_modify_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ int i;
+ char *attr_name;
+ LDAPMod **mods;
+ int rc = LDAP_SUCCESS;
+ int apply_mod = 0;
+ struct ldbminfo *li= (struct ldbminfo *) arg;
+
+ /* This lock is probably way too conservative, but we don't expect much
+ * contention for it. */
+ PR_Lock(li->li_config_mutex);
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ returntext[0] = '\0';
+
+ /*
+ * First pass: set apply mods to 0 so only input validation will be done;
+ * 2nd pass: set apply mods to 1 to apply changes to internal storage
+ */
+ for ( apply_mod = 0; apply_mod <= 1 && LDAP_SUCCESS == rc; apply_mod++ ) {
+ for (i = 0; mods[i] && LDAP_SUCCESS == rc; i++) {
+ attr_name = mods[i]->mod_type;
+
+ /* There are some attributes that we don't care about, like modifiersname. */
+ if (ldbm_config_ignored_attr(attr_name)) {
+ continue;
+ }
+
+ if ((mods[i]->mod_op & LDAP_MOD_DELETE) ||
+ ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD)) {
+ rc= LDAP_UNWILLING_TO_PERFORM;
+ sprintf(returntext, "%s attributes is not allowed",
+ (mods[i]->mod_op & LDAP_MOD_DELETE) ? "Deleting" : "Adding");
+ } else if (mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ /* This assumes there is only one bval for this mod. */
+ rc = ldbm_config_set((void *) li, attr_name, ldbm_config,
+ ( mods[i]->mod_bvalues == NULL ) ? NULL
+ : mods[i]->mod_bvalues[0], returntext,
+ ((li->li_flags&LI_FORCE_MOD_CONFIG)?
+ CONFIG_PHASE_INTERNAL:CONFIG_PHASE_RUNNING),
+ apply_mod);
+ }
+ }
+ }
+
+ PR_Unlock(li->li_config_mutex);
+
+ *returncode= rc;
+ if(LDAP_SUCCESS == rc) {
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+ else {
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+}
+
+
+/* This function is used to set config attributes. It can be used as a
+ * shortcut to doing an internal modify operation on the config DSE.
+ */
+void ldbm_config_internal_set(struct ldbminfo *li, char *attrname, char *value)
+{
+ char err_buf[BUFSIZ];
+ struct berval bval;
+
+ bval.bv_val = value;
+ bval.bv_len = strlen(value);
+
+ if (ldbm_config_set((void *) li, attrname, ldbm_config, &bval,
+ err_buf, CONFIG_PHASE_INTERNAL, 1 /* apply */) != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Internal Error: Error setting instance config attr %s to %s: %s\n",
+ attrname, value, err_buf);
+ exit(1);
+ }
+}
+
+/*
+ * replace_ldbm_config_value:
+ * - update an ldbm database config value
+ */
+void replace_ldbm_config_value(char *conftype, char *val, struct ldbminfo *li)
+{
+ Slapi_PBlock pb;
+ Slapi_Mods smods;
+
+ pblock_init(&pb);
+ slapi_mods_init(&smods, 1);
+ slapi_mods_add(&smods, LDAP_MOD_REPLACE, conftype, strlen(val), val);
+ slapi_modify_internal_set_pb(&pb,
+ "cn=config,cn=ldbm database,cn=plugins,cn=config",
+ slapi_mods_get_ldapmods_byref(&smods),
+ NULL, NULL, li->li_identity, 0);
+ slapi_modify_internal_pb(&pb);
+ pblock_done(&pb);
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_config.h b/ldap/servers/slapd/back-ldbm/ldbm_config.h
new file mode 100644
index 00000000..a26a73ed
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_config.h
@@ -0,0 +1,133 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _LDBM_CONFIG_H_
+#define _LDBM_CONFIG_H_
+
+struct config_info;
+typedef struct config_info config_info;
+
+typedef int config_set_fn_t(void *arg, void *value, char *errorbuf, int phase, int apply);
+typedef void *config_get_fn_t(void *arg);
+ /* The value for these is passed around as a
+ * void *, the actual value should be gotten
+ * by casting the void * as shown below. */
+#define CONFIG_TYPE_ONOFF 1 /* val = (int) value */
+#define CONFIG_TYPE_STRING 2 /* val = (char *) value - The get functions
+ * for this type must return alloced memory
+ * that should be freed by the caller. */
+#define CONFIG_TYPE_INT 3 /* val = (int) value */
+#define CONFIG_TYPE_LONG 4 /* val = (long) value */
+#define CONFIG_TYPE_INT_OCTAL 5 /* Same as CONFIG_TYPE_INT, but shown in
+ * octal */
+#define CONFIG_TYPE_SIZE_T 6 /* val = (size_t) value */
+
+/* How changes to some config attributes are handled depends on what
+ * "phase" the server is in. Initialization, reading the config
+ * information at startup, or actually running. */
+#define CONFIG_PHASE_INITIALIZATION 1
+#define CONFIG_PHASE_STARTUP 2
+#define CONFIG_PHASE_RUNNING 3
+#define CONFIG_PHASE_INTERNAL 4
+
+#define CONFIG_FLAG_PREVIOUSLY_SET 1
+#define CONFIG_FLAG_ALWAYS_SHOW 2
+#define CONFIG_FLAG_ALLOW_RUNNING_CHANGE 4
+
+struct config_info {
+ char *config_name;
+ int config_type;
+ char *config_default_value;
+ config_get_fn_t *config_get_fn;
+ config_set_fn_t *config_set_fn;
+ int config_flags;
+};
+
+#define CONFIG_INSTANCE "nsslapd-instance"
+#define CONFIG_LOOKTHROUGHLIMIT "nsslapd-lookthroughlimit"
+#define CONFIG_IDLISTSCANLIMIT "nsslapd-idlistscanlimit"
+#define CONFIG_DIRECTORY "nsslapd-directory"
+#define CONFIG_MODE "nsslapd-mode"
+#define CONFIG_DBCACHESIZE "nsslapd-dbcachesize"
+#define CONFIG_DBNCACHE "nsslapd-dbncache"
+#define CONFIG_MAXPASSBEFOREMERGE "nsslapd-maxpassbeforemerge"
+#define CONFIG_IMPORT_CACHE_AUTOSIZE "nsslapd-import-cache-autosize"
+#define CONFIG_CACHE_AUTOSIZE "nsslapd-cache-autosize"
+#define CONFIG_CACHE_AUTOSIZE_SPLIT "nsslapd-cache-autosize-split"
+#define CONFIG_IMPORT_CACHESIZE "nsslapd-import-cachesize"
+#define CONFIG_INDEX_BUFFER_SIZE "nsslapd-index-buffer-size"
+#define CONFIG_EXCLUDE_FROM_EXPORT "nsslapd-exclude-from-export"
+#define CONFIG_EXCLUDE_FROM_EXPORT_DEFAULT_VALUE \
+ "entrydn entryid dncomp parentid numSubordinates"
+
+/* dblayer config options - These are hidden from the user
+ * and can't be updated on the fly. */
+#define CONFIG_DB_LOGDIRECTORY "nsslapd-db-logdirectory"
+#define CONFIG_DB_DURABLE_TRANSACTIONS "nsslapd-db-durable-transaction"
+#define CONFIG_DB_CIRCULAR_LOGGING "nsslapd-db-circular-logging"
+#define CONFIG_DB_TRANSACTION_LOGGING "nsslapd-db-transaction-logging"
+#define CONFIG_DB_CHECKPOINT_INTERVAL "nsslapd-db-checkpoint-interval"
+#define CONFIG_DB_TRANSACTION_BATCH "nsslapd-db-transaction-batch-val"
+#define CONFIG_DB_LOGBUF_SIZE "nsslapd-db-logbuf-size"
+#define CONFIG_DB_PAGE_SIZE "nsslapd-db-page-size"
+#define CONFIG_DB_INDEX_PAGE_SIZE "nsslapd-db-index-page-size" /* With the new
+ idl design, the large 8Kbyte pages we use are not
+ optimal. The page pool churns very quickly as we add new IDs under a
+ sustained add load. Smaller pages stop this happening so much and
+ consequently make us spend less time flushing dirty pages on checkpoints.
+ But 8K is still a good page size for id2entry. So we now allow different
+ page sizes for the primary and secondary indices. */
+#define CONFIG_DB_IDL_DIVISOR "nsslapd-db-idl-divisor"
+#define CONFIG_DB_LOGFILE_SIZE "nsslapd-db-logfile-size"
+#define CONFIG_DB_TRICKLE_PERCENTAGE "nsslapd-db-trickle-percentage"
+#define CONFIG_DB_SPIN_COUNT "nsslapd-db-spin-count"
+#define CONFIG_DB_VERBOSE "nsslapd-db-verbose"
+#define CONFIG_DB_DEBUG "nsslapd-db-debug"
+#define CONFIG_DB_LOCK "nsslapd-db-locks"
+#define CONFIG_DB_NAMED_REGIONS "nsslapd-db-named-regions"
+#define CONFIG_DB_PRIVATE_MEM "nsslapd-db-private-mem"
+#define CONFIG_DB_PRIVATE_IMPORT_MEM "nsslapd-db-private-import-mem"
+#define CONFIG_DB_SHM_KEY "nsslapd-db-shm-key"
+#define CONFIG_DB_CACHE "nsslapd-db-cache"
+#define CONFIG_DB_DEBUG_CHECKPOINTING "nsslapd-db-debug-checkpointing"
+#define CONFIG_DB_HOME_DIRECTORY "nsslapd-db-home-directory"
+#define CONFIG_DB_LOCKDOWN "nsslapd-db-lockdown"
+#define CONFIG_DB_TX_MAX "nsslapd-db-tx-max"
+
+#define CONFIG_IDL_SWITCH "nsslapd-idl-switch"
+#define CONFIG_BYPASS_FILTER_TEST "nsslapd-search-bypass-filter-test"
+#define CONFIG_USE_VLV_INDEX "nsslapd-search-use-vlv-index"
+#define CONFIG_SERIAL_LOCK "nsslapd-serial-lock"
+
+/* instance config options */
+#define CONFIG_INSTANCE_CACHESIZE "nsslapd-cachesize"
+#define CONFIG_INSTANCE_CACHEMEMSIZE "nsslapd-cachememsize"
+#define CONFIG_INSTANCE_SUFFIX "nsslapd-suffix"
+#define CONFIG_INSTANCE_READONLY "nsslapd-readonly"
+#define CONFIG_INSTANCE_DIR "nsslapd-directory"
+
+#define CONFIG_INSTANCE_REQUIRE_INDEX "nsslapd-require-index"
+
+#define CONFIG_USE_LEGACY_ERRORCODE "nsslapd-do-not-use-vlv-error"
+
+#define LDBM_INSTANCE_CONFIG_DONT_WRITE 1
+
+/* Some fuctions in ldbm_config.c used by ldbm_instance_config.c */
+int ldbm_config_add_dse_entries(struct ldbminfo *li, char **entries, char *string1, char *string2, char *string3, int flags);
+int ldbm_config_add_dse_entry(struct ldbminfo *li, char *entry, int flags);
+void ldbm_config_get(void *arg, config_info *config, char *buf);
+int ldbm_config_set(void *arg, char *attr_name, config_info *config_array, struct berval *bval, char *err_buf, int phase, int apply_mod);
+int ldbm_config_ignored_attr(char *attr_name);
+
+/* Functions in ldbm_instance_config.c used in ldbm_config.c */
+int ldbm_instance_config_load_dse_info(ldbm_instance *inst);
+int ldbm_instance_config_add_index_entry(ldbm_instance *inst, int argc,
+ char **argv, int flags);
+int
+ldbm_instance_index_config_enable_index(ldbm_instance *inst, Slapi_Entry* e);
+int ldbm_instance_create_default_user_indexes(ldbm_instance *inst);
+
+
+#endif /* _LDBM_CONFIG_H_ */
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_delete.c b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
new file mode 100644
index 00000000..55d8f162
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_delete.c
@@ -0,0 +1,633 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* delete.c - ldbm backend delete routine */
+
+#include "back-ldbm.h"
+
+int
+ldbm_back_delete( Slapi_PBlock *pb )
+{
+ backend *be;
+ ldbm_instance *inst;
+ struct ldbminfo *li = NULL;
+ struct backentry *e = NULL;
+ struct backentry *tombstone = NULL;
+ char *dn = NULL;
+ back_txn txn;
+ back_txnid parent_txn;
+ int retval = -1;
+ char *msg;
+ char *errbuf = NULL;
+ int retry_count = 0;
+ int disk_full = 0;
+ int parent_found = 0;
+ modify_context parent_modify_c = {0};
+ int rc;
+ int ldap_result_code= LDAP_SUCCESS;
+ char *ldap_result_message= NULL;
+ Slapi_DN sdn;
+ char *e_uniqueid = NULL;
+ Slapi_DN *nscpEntrySDN = NULL;
+ int dblock_acquired= 0;
+ Slapi_Operation *operation;
+ CSN *opcsn = NULL;
+ int is_fixup_operation = 0;
+ int is_replicated_operation= 0;
+ int is_tombstone_entry = 0; /* True if the current entry is alreday a tombstone */
+ int delete_tombstone_entry = 0; /* We must remove the given tombstone entry from the DB */
+ int create_tombstone_entry = 0; /* We perform a "regular" LDAP delete but since we use */
+ /* replication, we must create a new tombstone entry */
+ int tombstone_in_cache = 0;
+ entry_address *addr;
+ int addordel_flags = 0; /* passed to index_addordel */
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_DELETE_TARGET, &dn );
+ slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr);
+ slapi_pblock_get( pb, SLAPI_PARENT_TXN, (void**)&parent_txn );
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
+ slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation );
+
+ if (pb->pb_conn)
+ {
+ slapi_log_error (SLAPI_LOG_TRACE, "ldbm_back_delete", "enter conn=%d op=%d\n", pb->pb_conn->c_connid, operation->o_opid);
+ }
+
+ is_fixup_operation = operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP);
+ delete_tombstone_entry = operation_is_flag_set(operation, OP_FLAG_TOMBSTONE_ENTRY);
+
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ slapi_sdn_init_dn_byref(&sdn,dn);
+
+ dblayer_txn_init(li,&txn);
+
+ /* The dblock serializes writes to the database,
+ * which reduces deadlocking in the db code,
+ * which means that we run faster.
+ *
+ * But, this lock is re-enterant for the fixup
+ * operations that the URP code in the Replication
+ * plugin generates.
+ */
+ if(SERIALLOCK(li) && !operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP))
+ {
+ dblayer_lock_backend(be);
+ dblock_acquired= 1;
+ }
+
+ /*
+ * We are about to pass the last abandon test, so from now on we are
+ * committed to finish this operation. Set status to "will complete"
+ * before we make our last abandon check to avoid race conditions in
+ * the code that processes abandon operations.
+ */
+ if (operation) {
+ operation->o_status = SLAPI_OP_STATUS_WILL_COMPLETE;
+ }
+ if ( slapi_op_abandoned( pb ) ) {
+ goto error_return;
+ }
+
+ /* Don't call pre-op for Tombstone entries */
+ if (!delete_tombstone_entry)
+ {
+ /*
+ * Some present state information is passed through the PBlock to the
+ * backend pre-op plugin. To ensure a consistent snapshot of this state
+ * we wrap the reading of the entry with the dblock.
+ */
+ ldap_result_code= get_copy_of_entry(pb, addr, &txn, SLAPI_DELETE_EXISTING_ENTRY, !is_replicated_operation);
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+ if(plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_DELETE_FN)==-1)
+ {
+ /*
+ * Plugin indicated some kind of failure,
+ * or that this Operation became a No-Op.
+ */
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+ goto error_return;
+ }
+ }
+
+
+ /* find and lock the entry we are about to modify */
+ if ( (e = find_entry2modify( pb, be, addr, NULL )) == NULL )
+ {
+ ldap_result_code= -1;
+ goto error_return; /* error result sent by find_entry2modify() */
+ }
+
+ if ( slapi_entry_has_children( e->ep_entry ) )
+ {
+ ldap_result_code= LDAP_NOT_ALLOWED_ON_NONLEAF;
+ goto error_return;
+ }
+
+ /*
+ * Sanity check to avoid to delete a non-tombstone or to tombstone again
+ * a tombstone entry. This should not happen (see bug 561003).
+ */
+ is_tombstone_entry = slapi_entry_flag_is_set(e->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
+ if (delete_tombstone_entry) {
+ PR_ASSERT(is_tombstone_entry);
+ if (!is_tombstone_entry) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "Attempt to delete a non-tombstone entry %s\n", dn);
+ delete_tombstone_entry = 0;
+ }
+ } else {
+ PR_ASSERT(!is_tombstone_entry);
+ if (is_tombstone_entry) {
+ slapi_log_error(SLAPI_LOG_FATAL, "ldbm_back_delete",
+ "Attempt to Tombstone again a tombstone entry %s\n", dn);
+ delete_tombstone_entry = 1;
+ }
+ }
+
+ /*
+ * If a CSN is set, we need to tombstone the entry,
+ * rather than deleting it outright.
+ */
+ opcsn = operation_get_csn (operation);
+ if (!delete_tombstone_entry)
+ {
+ if (opcsn == NULL && !is_fixup_operation && operation->o_csngen_handler)
+ {
+ /*
+ * Current op is a user request. Opcsn will be assigned
+ * by entry_assign_operation_csn() if the dn is in an
+ * updatable replica.
+ */
+ opcsn = entry_assign_operation_csn ( pb, e->ep_entry, NULL );
+ }
+ if (opcsn != NULL)
+ {
+ if (!is_fixup_operation)
+ {
+ entry_set_maxcsn (e->ep_entry, opcsn);
+ }
+ /*
+ * We are dealing with replication and if we haven't been called to
+ * remove a tombstone, then it's because we want to create a new one.
+ */
+ if ( slapi_operation_get_replica_attr (pb, operation, "nsds5ReplicaTombstonePurgeInterval", &create_tombstone_entry) == 0)
+ {
+ create_tombstone_entry = (create_tombstone_entry < 0) ? 0 : 1;
+ }
+ }
+ }
+
+#if DEBUG
+ slapi_log_error(SLAPI_LOG_REPL, "ldbm_back_delete",
+ "entry: %s - flags: delete %d is_tombstone_entry %d create %d \n",
+ dn, delete_tombstone_entry, is_tombstone_entry, create_tombstone_entry);
+#endif
+
+ /* Save away a copy of the entry, before modifications */
+ slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( e->ep_entry ));
+
+ /* JCMACL - Shouldn't the access check be before the has children check...
+ * otherwise we're revealing the fact that an entry exists and has children */
+ ldap_result_code = plugin_call_acl_plugin (pb, e->ep_entry, NULL, NULL, SLAPI_ACL_DELETE,
+ ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
+ if ( ldap_result_code != LDAP_SUCCESS )
+ {
+ ldap_result_message= errbuf;
+ goto error_return;
+ }
+
+ /*
+ * Get the entry's parent. We do this here because index_read
+ * seems to deadlock the database when dblayer_txn_begin is
+ * called.
+ */
+ if (!delete_tombstone_entry)
+ {
+ Slapi_DN parentsdn;
+
+ slapi_sdn_init(&parentsdn);
+ slapi_sdn_get_backend_parent(&sdn,&parentsdn,pb->pb_backend);
+ if ( !slapi_sdn_isempty(&parentsdn) )
+ {
+ struct backentry *parent = NULL;
+ entry_address parent_addr;
+
+ parent_addr.dn = (char*)slapi_sdn_get_ndn (&parentsdn);
+ parent_addr.uniqueid = NULL;
+ parent = find_entry2modify_only(pb,be,&parent_addr,&txn);
+ if (NULL != parent) {
+ int isglue;
+ size_t haschildren = 0;
+
+ /* Unfortunately findentry doesn't tell us whether it just didn't find the entry, or if
+ there was an error, so we have to assume that the parent wasn't found */
+ parent_found = 1;
+
+ /* Modify the parent in memory */
+ modify_init(&parent_modify_c,parent);
+ retval = parent_update_on_childchange(&parent_modify_c,2,&haschildren); /* 2==delete */\
+ /* The modify context now contains info needed later */
+ if (0 != retval) {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ /*
+ * Replication urp_post_delete will delete the parent entry
+ * if it is a glue entry without any more children.
+ * Those urp condition checkings are done here to
+ * save unnecessary entry dup.
+ */
+ isglue = slapi_entry_attr_hasvalue (parent_modify_c.new_entry->ep_entry,
+ SLAPI_ATTR_OBJECTCLASS, "glue");
+ if ( opcsn && parent_modify_c.new_entry && !haschildren && isglue)
+ {
+ slapi_pblock_set ( pb, SLAPI_DELETE_GLUE_PARENT_ENTRY,
+ slapi_entry_dup (parent_modify_c.new_entry->ep_entry) );
+ }
+ }
+ }
+ slapi_sdn_done(&parentsdn);
+ }
+
+ if(create_tombstone_entry)
+ {
+ /*
+ * The entry is not removed from the disk when we tombstone an
+ * entry. We change the DN, add objectclass=tombstone, and record
+ * the UniqueID of the parent entry.
+ */
+ const char *childuniqueid= slapi_entry_get_uniqueid(e->ep_entry);
+ const char *parentuniqueid= NULL;
+ char *tombstone_dn = compute_entry_tombstone_dn(slapi_entry_get_dn(e->ep_entry),
+ childuniqueid);
+ Slapi_Value *tomb_value;
+
+ nscpEntrySDN = slapi_entry_get_sdn(e->ep_entry);
+
+ /* Copy the entry unique_id for URP conflict checking */
+ e_uniqueid = slapi_ch_strdup(childuniqueid);
+
+ if(parent_modify_c.old_entry!=NULL)
+ {
+ /* The suffix entry has no parent */
+ parentuniqueid= slapi_entry_get_uniqueid(parent_modify_c.old_entry->ep_entry);
+ }
+ tombstone = backentry_dup( e );
+ slapi_entry_set_dn(tombstone->ep_entry,tombstone_dn); /* Consumes DN */
+ /* Set tombstone flag on ep_entry */
+ slapi_entry_set_flag(tombstone->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE);
+
+ if(parentuniqueid!=NULL)
+ {
+ /* The suffix entry has no parent */
+ slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_VALUE_PARENT_UNIQUEID, parentuniqueid);
+ }
+ if(nscpEntrySDN!=NULL)
+ {
+ slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN, slapi_sdn_get_ndn(nscpEntrySDN));
+ }
+ tomb_value = slapi_value_new_string(SLAPI_ATTR_VALUE_TOMBSTONE);
+ value_update_csn(tomb_value, CSN_TYPE_VALUE_UPDATED,
+ operation_get_csn(operation));
+ slapi_entry_add_value(tombstone->ep_entry, SLAPI_ATTR_OBJECTCLASS, tomb_value);
+ slapi_value_free(&tomb_value);
+
+ /* XXXggood above used to be: slapi_entry_add_string(tombstone->ep_entry, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE); */
+ /* JCMREPL - Add a description of what's going on? */
+ }
+
+ /*
+ * So, we believe that no code up till here actually added anything
+ * to the persistent store. From now on, we're transacted
+ */
+
+ for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) {
+ if (retry_count > 0) {
+ dblayer_txn_abort(li,&txn);
+ /* We're re-trying */
+ LDAPDebug( LDAP_DEBUG_TRACE, "Delete Retrying Transaction\n", 0, 0, 0 );
+#ifndef LDBM_NO_BACKOFF_DELAY
+ {
+ PRIntervalTime interval;
+ interval = PR_MillisecondsToInterval(slapi_rand() % 100);
+ DS_Sleep(interval);
+ }
+#endif
+ }
+ retval = dblayer_txn_begin(li,parent_txn,&txn);
+ if (0 != retval) {
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ if(create_tombstone_entry)
+ {
+ /*
+ * The entry is not removed from the disk when we tombstone an
+ * entry. We change the DN, add objectclass=tombstone, and record
+ * the UniqueID of the parent entry.
+ */
+ retval = id2entry_add( be, tombstone, &txn );
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete 1 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Abort and re-try */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_ANY, "id2entry_add failed, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ tombstone_in_cache = 1;
+ }
+ else
+ {
+ /* delete the entry from disk */
+ retval = id2entry_delete( be, e, &txn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete 2 DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (retval != 0 ) {
+ if (retval == DB_RUNRECOVERY ||
+ LDBM_OS_ERR_IS_DISKFULL(retval)) {
+ disk_full = 1;
+ }
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ }
+ /* delete from attribute indexes */
+ addordel_flags = BE_INDEX_DEL|BE_INDEX_PRESENCE;
+ if (delete_tombstone_entry)
+ {
+ addordel_flags |= BE_INDEX_TOMBSTONE; /* tell index code we are deleting a tombstone */
+ }
+ retval = index_addordel_entry( be, e, addordel_flags, &txn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete 1 DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (retval != 0) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "index_del_entry failed\n", 0, 0, 0 );
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ if(create_tombstone_entry)
+ {
+ /*
+ * The tombstone entry is removed from all attribute indexes
+ * above, but we want it to remain in the nsUniqueID and nscpEntryDN indexes
+ * and for objectclass=tombstone.
+ */
+ retval = index_addordel_string(be,SLAPI_ATTR_OBJECTCLASS,SLAPI_ATTR_VALUE_TOMBSTONE,tombstone->ep_id,BE_INDEX_ADD,&txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete 4 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "delete 1 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ retval = index_addordel_string(be,SLAPI_ATTR_UNIQUEID,slapi_entry_get_uniqueid(tombstone->ep_entry),tombstone->ep_id,BE_INDEX_ADD,&txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete 5 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "delete 2 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ retval = index_addordel_string(be,SLAPI_ATTR_NSCP_ENTRYDN, slapi_sdn_get_ndn(nscpEntrySDN),tombstone->ep_id,BE_INDEX_ADD,&txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete 6 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "delete 3 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ } else if (delete_tombstone_entry)
+ {
+ /*
+ * We need to remove the Tombstone entry from the remaining indexes:
+ * objectclass=nsTombstone, nsUniqueID, nscpEntryDN
+ */
+ char *nscpedn = NULL;
+
+ retval = index_addordel_string(be,SLAPI_ATTR_OBJECTCLASS,SLAPI_ATTR_VALUE_TOMBSTONE,e->ep_id,BE_INDEX_DEL,&txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete 4 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "delete 1 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ retval = index_addordel_string(be,SLAPI_ATTR_UNIQUEID,slapi_entry_get_uniqueid(e->ep_entry),e->ep_id,BE_INDEX_DEL,&txn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete 5 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "delete 2 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ nscpedn = slapi_entry_attr_get_charptr(e->ep_entry, SLAPI_ATTR_NSCP_ENTRYDN);
+ if (nscpedn) {
+ retval = index_addordel_string(be,SLAPI_ATTR_NSCP_ENTRYDN, nscpedn, e->ep_id,BE_INDEX_DEL,&txn);
+ slapi_ch_free((void **)&nscpedn);
+ if (DB_LOCK_DEADLOCK == retval) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete 6 DB_LOCK_DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "delete 3 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ }
+ }
+
+ if (parent_found) {
+ /* Push out the db modifications from the parent entry */
+ retval = modify_update_all(be,pb,&parent_modify_c,&txn);
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "del 4 DEADLOCK\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "delete 3 BAD, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ }
+ /*
+ * first check if searchentry needs to be removed
+ * Remove the entry from the Virtual List View indexes.
+ *
+ */
+ if(!delete_tombstone_entry &&
+ !vlv_delete_search_entry(pb,e->ep_entry,inst)) {
+ retval = vlv_update_all_indexes(&txn, be, pb, e, NULL);
+ }
+
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "delete DEADLOCK vlv_update_index\n", 0, 0, 0 );
+ /* Retry txn */
+ continue;
+ }
+ if (retval != 0 ) {
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ if (retval == 0 ) {
+ break;
+ }
+ }
+ if (retry_count == RETRY_TIMES) {
+ /* Failed */
+ LDAPDebug( LDAP_DEBUG_ANY, "Retry count exceeded in delete\n", 0, 0, 0 );
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ retval = dblayer_txn_commit(li,&txn);
+ if (0 != retval)
+ {
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ /* delete from cache and clean up */
+ cache_remove(&inst->inst_cache, e);
+ cache_unlock_entry( &inst->inst_cache, e );
+ cache_return( &inst->inst_cache, &e );
+ if (parent_found)
+ {
+ /* Replace the old parent entry with the newly modified one */
+ modify_switch_entries( &parent_modify_c,be);
+ }
+
+
+ rc= 0;
+ goto common_return;
+
+error_return:
+ if (e!=NULL) {
+ cache_unlock_entry( &inst->inst_cache, e );
+ cache_return( &inst->inst_cache, &e );
+ }
+ if (tombstone_in_cache)
+ {
+ cache_remove( &inst->inst_cache, tombstone );
+ }
+ else
+ {
+ backentry_free( &tombstone );
+ }
+
+ if (retval == DB_RUNRECOVERY) {
+ dblayer_remember_disk_filled(li);
+ ldbm_nasty("Delete",79,retval);
+ disk_full = 1;
+ }
+
+ if (disk_full) {
+ rc= return_on_disk_full(li);
+ goto diskfull_return;
+ }
+ else
+ rc= SLAPI_FAIL_GENERAL;
+
+ /* It is specifically OK to make this call even when no transaction was in progress */
+ dblayer_txn_abort(li,&txn); /* abort crashes in case disk full */
+
+common_return:
+ if (tombstone_in_cache)
+ {
+ cache_return( &inst->inst_cache, &tombstone );
+ }
+
+ /*
+ * The bepostop is called even if the operation fails,
+ * but not if the operation is purging tombstones.
+ */
+ if (!delete_tombstone_entry) {
+ plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_DELETE_FN);
+ }
+
+diskfull_return:
+ if(ldap_result_code!=-1)
+ {
+ slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+ }
+ modify_term(&parent_modify_c,be);
+ if(dblock_acquired)
+ {
+ dblayer_unlock_backend(be);
+ }
+ if (rc == 0 && opcsn && !is_fixup_operation && !delete_tombstone_entry)
+ {
+ /* URP Naming Collision
+ * When an entry is deleted by a replicated delete operation
+ * we must check for entries that have had a naming collision
+ * with this entry. Now that this name has been given up, one
+ * of those entries can take over the name.
+ */
+ slapi_pblock_set(pb, SLAPI_URP_NAMING_COLLISION_DN, slapi_ch_strdup (dn));
+ }
+ done_with_pblock_entry(pb, SLAPI_DELETE_EXISTING_ENTRY);
+ slapi_ch_free((void**)&errbuf);
+ slapi_sdn_done(&sdn);
+ slapi_ch_free_string(&e_uniqueid);
+ if (pb->pb_conn)
+ {
+ slapi_log_error (SLAPI_LOG_TRACE, "ldbm_back_delete", "leave conn=%d op=%d\n", pb->pb_conn->c_connid, operation->o_opid);
+ }
+ return rc;
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_index_config.c b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c
new file mode 100644
index 00000000..bd604cdb
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_index_config.c
@@ -0,0 +1,698 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* This file handles configuration information that is specific
+ * to ldbm instance indexes.
+ */
+
+#include "back-ldbm.h"
+#include "dblayer.h"
+
+/* Forward declarations for the callbacks */
+int ldbm_instance_index_config_add_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int ldbm_instance_index_config_delete_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+
+
+
+
+
+/* attrinfo2ConfIndexes: converts attrinfo into "pres,eq,sub,approx"
+ * as seen in index entries within dse.ldif
+ */
+static char *attrinfo2ConfIndexes (struct attrinfo *pai)
+{
+ char buffer[128];
+
+ buffer[0] = '\0';
+ if (!(IS_INDEXED( pai->ai_indexmask ))) { /* skip if no index */
+ strcat (buffer, "none");
+ }
+
+ if (pai->ai_indexmask & INDEX_PRESENCE) {
+ if (strlen (buffer)) {
+ strcat (buffer, ",");
+ }
+ strcat (buffer, "pres");
+ }
+ if (pai->ai_indexmask & INDEX_EQUALITY) {
+ if (strlen (buffer)) {
+ strcat (buffer, ",");
+ }
+ strcat (buffer, "eq");
+ }
+ if (pai->ai_indexmask & INDEX_APPROX) {
+ if (strlen(buffer)) {
+ strcat (buffer, ",");
+ }
+ strcat (buffer, "approx");
+ }
+ if (pai->ai_indexmask & INDEX_SUB) {
+ if (strlen (buffer)) {
+ strcat (buffer, ",");
+ }
+ strcat (buffer, "sub");
+ }
+
+ return (slapi_ch_strdup (buffer) );
+}
+
+
+/* attrinfo2ConfMatchingRules: converts attrinfo into matching rule oids, as
+ * seen in index entries within dse.ldif
+ */
+static char *attrinfo2ConfMatchingRules (struct attrinfo *pai)
+{
+ int i;
+ char buffer[1024];
+
+ buffer[0] = '\0';
+
+ if (pai->ai_index_rules) {
+ strcat (buffer, "\t");
+ for (i = 0; pai->ai_index_rules[i]; i++) {
+ strcat (buffer, pai->ai_index_rules[i]);
+ if (pai->ai_index_rules[i+1]) {
+ strcat (buffer, ",");
+ }
+ }
+ }
+ return (slapi_ch_strdup (buffer) );
+}
+
+
+/* used by the two callbacks below, to parse an index entry into something
+ * awkward that we can pass to attr_index_config().
+ */
+#define MAX_TMPBUF 256
+#define ZCAT_SAFE(_buf, _x1, _x2) do { \
+ if (strlen(_buf) + strlen(_x1) + strlen(_x2) + 2 < MAX_TMPBUF) { \
+ strcat(_buf, _x1); \
+ strcat(_buf, _x2); \
+ } \
+} while (0)
+static int ldbm_index_parse_entry(ldbm_instance *inst, Slapi_Entry *e,
+ const char *trace_string,
+ char **index_name)
+{
+ char *arglist[] = { NULL, NULL, NULL, NULL };
+ int argc = 0, i;
+ Slapi_Attr *attr;
+ const struct berval *attrValue;
+ Slapi_Value *sval;
+ char tmpBuf[MAX_TMPBUF];
+
+ /* Get the name of the attribute to index which will be the value
+ * of the cn attribute. */
+ if (slapi_entry_attr_find(e, "cn", &attr) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: malformed index entry %s\n",
+ slapi_entry_get_dn(e), 0, 0);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ arglist[argc++] = slapi_ch_strdup(attrValue->bv_val);
+ if (index_name != NULL) {
+ *index_name = slapi_ch_strdup(attrValue->bv_val);
+ }
+
+ /* Get the list of index types from the entry. */
+ if (0 == slapi_entry_attr_find(e, "nsIndexType", &attr)) {
+ for (i = slapi_attr_first_value(attr, &sval); i != -1;
+ i = slapi_attr_next_value(attr, i, &sval)) {
+ attrValue = slapi_value_get_berval(sval);
+ if (0 == i) {
+ tmpBuf[0] = 0;
+ ZCAT_SAFE(tmpBuf, "", attrValue->bv_val);
+ } else {
+ ZCAT_SAFE(tmpBuf, ",", attrValue->bv_val);
+ }
+ }
+ arglist[argc++] = slapi_ch_strdup(tmpBuf);
+ }
+
+ /* Get the list of matching rules from the entry. */
+ if (0 == slapi_entry_attr_find(e, "nsMatchingRule", &attr)) {
+ for (i = slapi_attr_first_value(attr, &sval); i != -1;
+ i = slapi_attr_next_value(attr, i, &sval)) {
+ attrValue = slapi_value_get_berval(sval);
+ if (0 == i) {
+ tmpBuf[0] = 0;
+ ZCAT_SAFE(tmpBuf, "", attrValue->bv_val);
+ } else {
+ ZCAT_SAFE(tmpBuf, ",", attrValue->bv_val);
+ }
+ }
+ arglist[argc++] = slapi_ch_strdup(tmpBuf);
+ }
+
+ arglist[argc] = NULL;
+ attr_index_config(inst->inst_be, (char *)trace_string, 0, argc, arglist, 0);
+ for (i = 0; i < argc; i++) {
+ slapi_ch_free((void **)&arglist[i]);
+ }
+ return LDAP_SUCCESS;
+}
+
+
+/*
+ * Temp callback that gets called for each index entry when a new
+ * instance is starting up.
+ */
+int
+ldbm_index_init_entry_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *) arg;
+
+ returntext[0] = '\0';
+ *returncode = ldbm_index_parse_entry(inst, e, "from ldbm instance init",
+ NULL);
+ if (*returncode == LDAP_SUCCESS) {
+ return SLAPI_DSE_CALLBACK_OK;
+ } else {
+ sprintf(returntext, "Problem initializing index entry %s\n",
+ slapi_entry_get_dn(e));
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+}
+
+/*
+ * Config DSE callback for index additions.
+ */
+int
+ldbm_instance_index_config_add_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* eAfter, int *returncode, char *returntext, void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *) arg;
+ char *index_name;
+
+ returntext[0] = '\0';
+ *returncode = ldbm_index_parse_entry(inst, e, "from DSE add", &index_name);
+ if (*returncode == LDAP_SUCCESS) {
+ struct attrinfo *ai = NULL;
+
+ /* if the index is a "system" index, we assume it's being added by
+ * by the server, and it's okay for the index to go online immediately.
+ * if not, we set the index "offline" so it won't actually be used
+ * until someone runs db2index on it.
+ */
+ if (! ldbm_attribute_always_indexed(index_name)) {
+ ainfo_get(inst->inst_be, index_name, &ai);
+ PR_ASSERT(ai != NULL);
+ ai->ai_indexmask |= INDEX_OFFLINE;
+ }
+ slapi_ch_free((void **)&index_name);
+ return SLAPI_DSE_CALLBACK_OK;
+ } else {
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+}
+
+/*
+ * Config DSE callback for index deletes.
+ */
+int
+ldbm_instance_index_config_delete_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *) arg;
+ char *arglist[4];
+ Slapi_Attr *attr;
+ Slapi_Value *sval;
+ const struct berval *attrValue;
+ int argc = 0;
+ int rc = SLAPI_DSE_CALLBACK_OK;
+ struct attrinfo *ainfo = NULL;
+
+ returntext[0] = '\0';
+ *returncode = LDAP_SUCCESS;
+
+ slapi_entry_attr_find(e, "cn", &attr);
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+
+ arglist[argc++] = slapi_ch_strdup(attrValue->bv_val);
+ arglist[argc++] = slapi_ch_strdup("none");
+ arglist[argc] = NULL;
+ attr_index_config(inst->inst_be, "From DSE delete", 0, argc, arglist, 0);
+ slapi_ch_free((void **)&arglist[0]);
+ slapi_ch_free((void **)&arglist[1]);
+
+ ainfo_get(inst->inst_be, attrValue->bv_val, &ainfo);
+
+ if (NULL == ainfo) {
+ *returncode = LDAP_UNAVAILABLE;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ } else {
+ if (dblayer_erase_index_file(inst->inst_be, ainfo, 0 /* do chkpt */)) {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Config DSE callback for index entry changes.
+ *
+ * this function is huge!
+ */
+int
+ldbm_instance_index_config_modify_callback(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+ Slapi_Attr *attr;
+ Slapi_Value *sval;
+ const struct berval *attrValue;
+ struct attrinfo *ainfo = NULL;
+ LDAPMod **mods;
+ char *arglist[4];
+ char *config_attr;
+ char *origIndexTypes, *origMatchingRules;
+ char **origIndexTypesArray = NULL;
+ char **origMatchingRulesArray = NULL;
+ char **addIndexTypesArray = NULL;
+ char **addMatchingRulesArray = NULL;
+ char **deleteIndexTypesArray = NULL;
+ char **deleteMatchingRulesArray = NULL;
+ int i, j;
+ int dodeletes = 0;
+ char tmpBuf[MAX_TMPBUF];
+
+ returntext[0] = '\0';
+ *returncode = LDAP_SUCCESS;
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+
+ slapi_entry_attr_find(e, "cn", &attr);
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ ainfo_get(inst->inst_be, attrValue->bv_val, &ainfo);
+ if (NULL == ainfo) {
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ origIndexTypes = attrinfo2ConfIndexes(ainfo);
+ origMatchingRules = attrinfo2ConfMatchingRules(ainfo);
+ origIndexTypesArray = str2charray(origIndexTypes, ",");
+ origMatchingRulesArray = str2charray(origMatchingRules, ",");
+
+ for (i = 0; mods[i] != NULL; i++) {
+ config_attr = (char *)mods[i]->mod_type;
+
+ if (strcasecmp(config_attr, "nsIndexType") == 0) {
+ if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ for (j = 0; mods[i]->mod_bvalues[j] != NULL; j++) {
+ charray_add(&addIndexTypesArray,
+ slapi_ch_strdup(mods[i]->mod_bvalues[j]->bv_val));
+ }
+ continue;
+ }
+ if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ if ((mods[i]->mod_bvalues == NULL) ||
+ (mods[i]->mod_bvalues[0] == NULL)) {
+ if (deleteIndexTypesArray) {
+ charray_free(deleteIndexTypesArray);
+ }
+ deleteIndexTypesArray = charray_dup(origIndexTypesArray);
+ } else {
+ for (j = 0; mods[i]->mod_bvalues[j] != NULL; j++) {
+ charray_add(&deleteIndexTypesArray,
+ slapi_ch_strdup(mods[i]->mod_bvalues[j]->bv_val));
+ }
+ }
+ continue;
+ }
+ }
+ if (strcasecmp(config_attr, "nsMatchingRule") == 0) {
+ if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ for (j = 0; mods[i]->mod_bvalues[j] != NULL; j++) {
+ charray_add(&addMatchingRulesArray,
+ slapi_ch_strdup(mods[i]->mod_bvalues[j]->bv_val));
+ }
+ continue;
+ }
+ if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ if ((mods[i]->mod_bvalues == NULL) ||
+ (mods[i]->mod_bvalues[0] == NULL)) {
+ if (deleteMatchingRulesArray) {
+ charray_free(deleteMatchingRulesArray);
+ }
+ deleteMatchingRulesArray = charray_dup(origMatchingRulesArray);
+ } else {
+ for (j = 0; mods[i]->mod_bvalues[j] != NULL; j++) {
+ charray_add(&deleteMatchingRulesArray,
+ slapi_ch_strdup(mods[i]->mod_bvalues[j]->bv_val));
+ }
+ }
+ continue;
+ }
+ }
+ }
+
+ /* create the new set of index types */
+ if (deleteIndexTypesArray) {
+ for (i = 0; origIndexTypesArray[i] != NULL; i++) {
+ if (charray_inlist(deleteIndexTypesArray,
+ origIndexTypesArray[i])) {
+ slapi_ch_free((void **)&(origIndexTypesArray[i]));
+ dodeletes = 1;
+ if (origIndexTypesArray[i+1] != NULL) {
+ for (j = i+1; origIndexTypesArray[j] != NULL; j++) {
+ origIndexTypesArray[j-1] = origIndexTypesArray[j];
+ }
+ origIndexTypesArray[j-1] = NULL;
+ i--;
+ }
+ }
+ }
+ }
+
+ if (addIndexTypesArray) {
+ for (i = 0; addIndexTypesArray[i] != NULL; i++) {
+ if (!charray_inlist(origIndexTypesArray, addIndexTypesArray[i])) {
+ charray_add(&origIndexTypesArray,
+ slapi_ch_strdup(addIndexTypesArray[i]));
+ }
+ }
+ }
+
+ if (deleteMatchingRulesArray) {
+ for (i = 0; origMatchingRulesArray[i] != NULL; i++) {
+ if (charray_inlist(deleteMatchingRulesArray,
+ origMatchingRulesArray[i])) {
+ slapi_ch_free((void **)&(origMatchingRulesArray[i]));
+ dodeletes = 1;
+ if (origMatchingRulesArray[i+1] != NULL) {
+ for (j = i+1; origMatchingRulesArray[j] != NULL; j++) {
+ origMatchingRulesArray[j-1] = origMatchingRulesArray[j];
+ }
+ origMatchingRulesArray[j-1] = NULL;
+ i--;
+ }
+ }
+ }
+ }
+
+ if (addMatchingRulesArray) {
+ for (i = 0; addMatchingRulesArray[i] != NULL; i++) {
+ if (!charray_inlist(origMatchingRulesArray,
+ addMatchingRulesArray[i])) {
+ charray_add(&origMatchingRulesArray,
+ slapi_ch_strdup(addMatchingRulesArray[i]));
+ }
+ }
+ }
+
+ if (dodeletes) {
+ i = 0;
+ arglist[i++] = slapi_ch_strdup(attrValue->bv_val);
+ arglist[i++] = slapi_ch_strdup("none");
+ arglist[i] = NULL;
+ attr_index_config(inst->inst_be, "from DSE modify", 0, i, arglist, 0);
+
+ /* Free args */
+ slapi_ch_free((void **)&arglist[0]);
+ slapi_ch_free((void **)&arglist[1]);
+ }
+
+ i = 0;
+ arglist[i++] = slapi_ch_strdup(attrValue->bv_val);
+ if (origIndexTypesArray && origIndexTypesArray[0]) {
+ tmpBuf[0] = 0;
+ ZCAT_SAFE(tmpBuf, "", origIndexTypesArray[0]);
+ for (j = 1; origIndexTypesArray[j] != NULL; j++) {
+ ZCAT_SAFE(tmpBuf, ",", origIndexTypesArray[j]);
+ }
+ arglist[i++] = slapi_ch_strdup(tmpBuf);
+ } else {
+ arglist[i++] = slapi_ch_strdup("none");
+ }
+
+ if (origMatchingRulesArray && origMatchingRulesArray[0]) {
+ tmpBuf[0] = 0;
+ ZCAT_SAFE(tmpBuf, "", origMatchingRulesArray[0]);
+ for (j = 1; origMatchingRulesArray[j] != NULL; j++) {
+ ZCAT_SAFE(tmpBuf, ",", origMatchingRulesArray[j]);
+ }
+ arglist[i++] = slapi_ch_strdup(tmpBuf);
+ }
+
+ arglist[i] = NULL;
+ attr_index_config(inst->inst_be, "from DSE modify", 0, i, arglist, 0);
+
+ /* Free args */
+ for (i=0; arglist[i]; i++) {
+ slapi_ch_free((void **)&arglist[i]);
+ }
+
+ if(origIndexTypesArray) {
+ charray_free(origIndexTypesArray);
+ }
+ if(origMatchingRulesArray) {
+ charray_free(origMatchingRulesArray);
+ }
+ if(addIndexTypesArray) {
+ charray_free(addIndexTypesArray);
+ }
+ if(deleteIndexTypesArray) {
+ charray_free(deleteIndexTypesArray);
+ }
+ if(addMatchingRulesArray) {
+ charray_free(addMatchingRulesArray);
+ }
+ if(deleteMatchingRulesArray) {
+ charray_free(deleteMatchingRulesArray);
+ }
+ if (origIndexTypes) {
+ slapi_ch_free ((void **)&origIndexTypes);
+ }
+ if (origMatchingRules) {
+ slapi_ch_free ((void **)&origMatchingRules);
+ }
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* add index entries to the per-instance DSE (used only from instance.c) */
+int ldbm_instance_config_add_index_entry(
+ ldbm_instance *inst,
+ int argc,
+ char **argv,
+ int flags
+)
+{
+ char **attrs = NULL;
+ char **indexes = NULL;
+ char **matchingRules = NULL;
+ char eBuf[BUFSIZ];
+ int i = 0;
+ int j = 0;
+ char *basetype = NULL;
+ char tmpAttrsStr[256];
+ char tmpIndexesStr[256];
+ char tmpMatchingRulesStr[1024];
+ struct ldbminfo *li = inst->inst_li;
+
+ if ((argc < 2) || (NULL == argv) || (NULL == argv[0]) ||
+ (NULL == argv[1])) {
+ return(-1);
+ }
+
+ strcpy(tmpAttrsStr,argv[0]);
+ attrs = str2charray( tmpAttrsStr, "," );
+ strcpy(tmpIndexesStr,argv[1]);
+ indexes = str2charray( tmpIndexesStr, ",");
+
+ if(argc > 2) {
+ strcpy(tmpMatchingRulesStr,argv[2]);
+ matchingRules = str2charray( tmpMatchingRulesStr, ",");
+ }
+
+ for(i=0; attrs[i] !=NULL; i++)
+ {
+ if('\0' == attrs[i][0]) continue;
+ basetype = slapi_attr_basetype(attrs[i], NULL, 0);
+ sprintf(eBuf,
+ "dn: cn=%s, cn=index, cn=%s, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:nsIndex\n"
+ "cn:%s\n"
+ "nsSystemIndex:%s\n",
+ basetype, inst->inst_name, li->li_plugin->plg_name,
+ basetype,
+ (ldbm_attribute_always_indexed(basetype)?"true":"false"));
+ for(j=0; indexes[j] != NULL; j++)
+ {
+ strcat(eBuf, "nsIndexType:");
+ strcat(eBuf,indexes[j]);
+ strcat(eBuf,"\n");
+ }
+ if((argc>2)&&(argv[2]))
+ {
+ for(j=0; matchingRules[j] != NULL; j++)
+ {
+ strcat(eBuf,"nsMatchingRule:");
+ strcat(eBuf,matchingRules[j]);
+ strcat(eBuf,"\n");
+ }
+ }
+
+ ldbm_config_add_dse_entry(li, eBuf, flags);
+
+ slapi_ch_free((void**)&basetype);
+ }
+
+ if(NULL != attrs) {
+ charray_free(attrs);
+ }
+ if(NULL != indexes) {
+ charray_free(indexes);
+ }
+ if(NULL != matchingRules) {
+ charray_free(matchingRules);
+ }
+ return (0);
+}
+
+int
+ldbm_instance_index_config_enable_index(ldbm_instance *inst, Slapi_Entry* e)
+{
+ char *index_name;
+ int rc;
+
+ rc=ldbm_index_parse_entry(inst, e, "from DSE add", &index_name);
+ if (rc == LDAP_SUCCESS) {
+ struct attrinfo *ai = NULL;
+
+ /* Assume the caller knows if it is OK to go online immediatly */
+
+ ainfo_get(inst->inst_be, index_name, &ai);
+ PR_ASSERT(ai != NULL);
+ ai->ai_indexmask &= ~INDEX_OFFLINE;
+ slapi_ch_free((void **)&index_name);
+ }
+ return rc;
+}
+
+
+/*
+** create the default user-defined indexes
+*/
+
+int ldbm_instance_create_default_user_indexes(ldbm_instance *inst)
+{
+
+ /*
+ ** Search for user-defined default indexes and add them
+ ** to the backend instance beeing created.
+ */
+
+ Slapi_PBlock *aPb;
+ Slapi_Entry **entries = NULL;
+ Slapi_Attr *attr;
+ Slapi_Value *sval = NULL;
+ const struct berval *attrValue;
+ char *argv[ 8 ];
+ char basedn[BUFSIZ];
+ char tmpBuf[MAX_TMPBUF];
+ char tmpBuf2[MAX_TMPBUF];
+ int argc;
+
+ struct ldbminfo *li;
+
+ /* write the dse file only on the final index */
+ int flags = LDBM_INSTANCE_CONFIG_DONT_WRITE;
+
+ if (NULL == inst) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: can't initialize default user indexes (invalid instance).\n", 0,0,0);
+ return -1;
+ }
+
+ li = inst->inst_li;
+ strcpy(tmpBuf,"");
+
+ /* Construct the base dn of the subtree that holds the default user indexes. */
+ sprintf(basedn, "cn=default indexes, cn=config, cn=%s, cn=plugins, cn=config",
+ li->li_plugin->plg_name);
+
+ /* Do a search of the subtree containing the index entries */
+ aPb = slapi_pblock_new();
+ slapi_search_internal_set_pb(aPb, basedn, LDAP_SCOPE_SUBTREE,
+ "(objectclass=nsIndex)", NULL, 0 , NULL, NULL, li->li_identity, 0);
+ slapi_search_internal_pb (aPb);
+ slapi_pblock_get(aPb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (entries!=NULL) {
+ int i,j;
+ for (i=0; entries[i]!=NULL; i++) {
+
+ /* Get the name of the attribute to index which will be the value
+ * of the cn attribute. */
+
+ if (slapi_entry_attr_find(entries[i], "cn", &attr) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Warning: malformed index entry %s. Index ignored.\n",
+ slapi_entry_get_dn(entries[i]), 0, 0);
+ continue;
+ }
+ slapi_attr_first_value(attr, &sval);
+ attrValue = slapi_value_get_berval(sval);
+ argv[0] = attrValue->bv_val;
+ argc=1;
+
+ /* Get the list of index types from the entry. */
+
+ if (0 == slapi_entry_attr_find(entries[i], "nsIndexType", &attr)) {
+ for (j = slapi_attr_first_value(attr, &sval); j != -1;
+ j = slapi_attr_next_value(attr, j, &sval)) {
+ attrValue = slapi_value_get_berval(sval);
+ if (0 == j) {
+ tmpBuf[0] = 0;
+ ZCAT_SAFE(tmpBuf, "", attrValue->bv_val);
+ } else {
+ ZCAT_SAFE(tmpBuf, ",", attrValue->bv_val);
+ }
+ }
+ argv[argc]=tmpBuf;
+ argc++;
+ }
+
+ /* Get the list of matching rules from the entry. */
+
+ if (0 == slapi_entry_attr_find(entries[i], "nsMatchingRule", &attr)) {
+ for (j = slapi_attr_first_value(attr, &sval); j != -1;
+ j = slapi_attr_next_value(attr, j, &sval)) {
+ attrValue = slapi_value_get_berval(sval);
+ if (0 == j) {
+ tmpBuf2[0] = 0;
+ ZCAT_SAFE(tmpBuf2, "", attrValue->bv_val);
+ } else {
+ ZCAT_SAFE(tmpBuf2, ",", attrValue->bv_val);
+ }
+ }
+ argv[argc]=tmpBuf2;
+ argc++;
+ }
+
+ argv[argc]=NULL;
+
+ /* Create the index entry in the backend */
+
+ if (entries[i+1] == NULL) {
+ /* write the dse file only on the final index */
+ flags = 0;
+ }
+
+ ldbm_instance_config_add_index_entry(inst, argc, argv, flags);
+
+ /* put the index online */
+
+ ldbm_instance_index_config_enable_index(inst, entries[i]);
+ }
+ }
+
+ slapi_free_search_results_internal(aPb);
+ slapi_pblock_destroy(aPb);
+ return 0;
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c b/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c
new file mode 100644
index 00000000..a5819d6f
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_instance_config.c
@@ -0,0 +1,997 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* This file handles configuration information that is specific
+ * to ldbm instances.
+ */
+
+#include "back-ldbm.h"
+#include "dblayer.h"
+
+/* Forward declarations for the callbacks */
+int ldbm_instance_search_config_entry_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
+int ldbm_instance_modify_config_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+
+static char *ldbm_instance_attrcrypt_filter = "(objectclass=nsAttributeEncryption)";
+
+/* dse entries add for a new ldbm instance */
+static char *ldbm_instance_skeleton_entries[] =
+{
+ "dn:cn=monitor, cn=%s, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:monitor\n",
+
+ "dn:cn=index, cn=%s, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:index\n",
+
+ "dn:cn=encrypted attributes, cn=%s, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:encrypted attributes\n",
+
+ "dn:cn=encrypted attribute keys, cn=%s, cn=%s, cn=plugins, cn=config\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:encrypted attribute keys\n",
+
+ ""
+};
+
+
+/*------------------------------------------------------------------------
+ * Get and set functions for ldbm instance variables
+ *----------------------------------------------------------------------*/
+static void *
+ldbm_instance_config_cachesize_get(void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *) arg;
+
+ return (void *) cache_get_max_entries(&(inst->inst_cache));
+}
+
+static int
+ldbm_instance_config_cachesize_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ ldbm_instance *inst = (ldbm_instance *) arg;
+ int retval = LDAP_SUCCESS;
+ long val = (long) value;
+
+ /* Do whatever we can to make sure the data is ok. */
+
+ if (apply) {
+ cache_set_max_entries(&(inst->inst_cache), val);
+ }
+
+ return retval;
+}
+
+static void *
+ldbm_instance_config_cachememsize_get(void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *) arg;
+
+ return (void *) cache_get_max_size(&(inst->inst_cache));
+}
+
+static int
+ldbm_instance_config_cachememsize_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ ldbm_instance *inst = (ldbm_instance *) arg;
+ int retval = LDAP_SUCCESS;
+ size_t val = (size_t) value;
+
+ /* Do whatever we can to make sure the data is ok. */
+
+ if (apply) {
+ cache_set_max_size(&(inst->inst_cache), val);
+ }
+
+ return retval;
+}
+
+static void *
+ldbm_instance_config_readonly_get(void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+
+ return (void *)inst->inst_be->be_readonly;
+}
+
+static void *
+ldbm_instance_config_instance_dir_get(void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+
+ if (inst->inst_dir_name == NULL)
+ return slapi_ch_strdup("");
+ else if (inst->inst_parent_dir_name)
+ {
+ int len = strlen(inst->inst_parent_dir_name) +
+ strlen(inst->inst_dir_name) + 2;
+ char *full_inst_dir = (char *)slapi_ch_malloc(len);
+ sprintf(full_inst_dir, "%s%c%s",
+ inst->inst_parent_dir_name, get_sep(inst->inst_parent_dir_name),
+ inst->inst_dir_name);
+ return full_inst_dir;
+ }
+ else
+ return slapi_ch_strdup(inst->inst_dir_name);
+}
+
+static void *
+ldbm_instance_config_require_index_get(void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+
+ return (void *)inst->require_index;
+}
+
+static int
+ldbm_instance_config_instance_dir_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+
+ if (!apply) {
+ return LDAP_SUCCESS;
+ }
+
+ if ((value == NULL) || (strlen(value) == 0))
+ {
+ inst->inst_dir_name = NULL;
+ inst->inst_parent_dir_name = NULL;
+ }
+ else
+ {
+ char *dir = (char *)value;
+ if (is_fullpath(dir))
+ {
+ char sep = get_sep(dir);
+ char *p = strrchr(dir, sep);
+ if (NULL == p) /* never happens, tho */
+ {
+ inst->inst_parent_dir_name = NULL;
+ inst->inst_dir_name = slapi_ch_strdup(dir);
+ }
+ else
+ {
+ *p = '\0';
+ inst->inst_parent_dir_name = slapi_ch_strdup(dir);
+ inst->inst_dir_name = slapi_ch_strdup(p+1);
+ *p = sep;
+ }
+ }
+ else
+ {
+ inst->inst_parent_dir_name = NULL;
+ inst->inst_dir_name = slapi_ch_strdup(dir);
+ }
+ }
+ return LDAP_SUCCESS;
+}
+
+static int
+ldbm_instance_config_readonly_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+
+ if (!apply) {
+ return LDAP_SUCCESS;
+ }
+
+ if (CONFIG_PHASE_RUNNING == phase) {
+ /* if the instance is busy, we'll save the user's readonly settings
+ * but won't change them until the instance is un-busy again.
+ */
+ if (! (inst->inst_flags & INST_FLAG_BUSY)) {
+ slapi_mtn_be_set_readonly(inst->inst_be, (int)value);
+ }
+ if ((int)value) {
+ inst->inst_flags |= INST_FLAG_READONLY;
+ } else {
+ inst->inst_flags &= ~INST_FLAG_READONLY;
+ }
+ } else {
+ slapi_be_set_readonly(inst->inst_be, (int)value);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static int
+ldbm_instance_config_require_index_set(void *arg, void *value, char *errorbuf, int phase, int apply)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+
+ if (!apply) {
+ return LDAP_SUCCESS;
+ }
+
+ inst->require_index = (int)value;
+
+ return LDAP_SUCCESS;
+}
+
+
+/*------------------------------------------------------------------------
+ * ldbm instance configuration array
+ *----------------------------------------------------------------------*/
+static config_info ldbm_instance_config[] = {
+ {CONFIG_INSTANCE_CACHESIZE, CONFIG_TYPE_LONG, "-1", &ldbm_instance_config_cachesize_get, &ldbm_instance_config_cachesize_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_INSTANCE_CACHEMEMSIZE, CONFIG_TYPE_SIZE_T, "10485760", &ldbm_instance_config_cachememsize_get, &ldbm_instance_config_cachememsize_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_INSTANCE_READONLY, CONFIG_TYPE_ONOFF, "off", &ldbm_instance_config_readonly_get, &ldbm_instance_config_readonly_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_INSTANCE_REQUIRE_INDEX, CONFIG_TYPE_ONOFF, "off", &ldbm_instance_config_require_index_get, &ldbm_instance_config_require_index_set, CONFIG_FLAG_ALWAYS_SHOW|CONFIG_FLAG_ALLOW_RUNNING_CHANGE},
+ {CONFIG_INSTANCE_DIR, CONFIG_TYPE_STRING, NULL, &ldbm_instance_config_instance_dir_get, &ldbm_instance_config_instance_dir_set, CONFIG_FLAG_ALWAYS_SHOW},
+ {NULL, 0, NULL, NULL, NULL, 0}
+};
+
+void
+ldbm_instance_config_setup_default(ldbm_instance *inst)
+{
+ config_info *config;
+ char err_buf[BUFSIZ];
+
+ for (config = ldbm_instance_config; config->config_name != NULL; config++) {
+ ldbm_config_set((void *)inst, config->config_name, ldbm_instance_config, NULL /* use default */, err_buf, CONFIG_PHASE_INITIALIZATION, 1 /* apply */);
+ }
+}
+
+static int
+parse_ldbm_instance_entry(Slapi_Entry *e, char **instance_name)
+{
+ Slapi_Attr *attr = NULL;
+
+ for (slapi_entry_first_attr(e, &attr); attr;
+ slapi_entry_next_attr(e, attr, &attr)) {
+ char *attr_name = NULL;
+
+ slapi_attr_get_type(attr, &attr_name);
+ if (strcasecmp(attr_name, "cn") == 0) {
+ Slapi_Value *sval = NULL;
+ struct berval *bval;
+ slapi_attr_first_value(attr, &sval);
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ *instance_name = slapi_ch_strdup((char *)bval->bv_val);
+ }
+ }
+ return 0;
+}
+
+/* When a new instance is started, we need to read the dse to
+ * find out what indexes should be maintained. This function
+ * does that. Returns 0 on success. */
+static int
+read_instance_index_entries(ldbm_instance *inst)
+{
+ Slapi_PBlock *tmp_pb;
+ int scope = LDAP_SCOPE_SUBTREE;
+ char basedn[BUFSIZ];
+ const char *searchfilter = "(objectclass=nsIndex)";
+
+ /* Construct the base dn of the subtree that holds the index entries
+ * for this instance. */
+ sprintf(basedn, "cn=index, cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, inst->inst_li->li_plugin->plg_name);
+
+ /* Set up a tmp callback that will handle the init for each index entry */
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP,
+ basedn, scope, searchfilter, ldbm_index_init_entry_callback,
+ (void *) inst);
+
+ /* Do a search of the subtree containing the index entries */
+ tmp_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(tmp_pb, basedn, LDAP_SCOPE_SUBTREE,
+ searchfilter, NULL, 0, NULL, NULL, inst->inst_li->li_identity, 0);
+ slapi_search_internal_pb (tmp_pb);
+
+ /* Remove the tmp callback */
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP,
+ basedn, scope, searchfilter, ldbm_index_init_entry_callback);
+ slapi_free_search_results_internal(tmp_pb);
+ slapi_pblock_destroy(tmp_pb);
+
+ return 0;
+}
+
+/* When a new instance is started, we need to read the dse to
+ * find out what attributes should be encrypted. This function
+ * does that. Returns 0 on success. */
+static int
+read_instance_attrcrypt_entries(ldbm_instance *inst)
+{
+ Slapi_PBlock *tmp_pb;
+ int scope = LDAP_SCOPE_SUBTREE;
+ char basedn[BUFSIZ];
+ const char *searchfilter = ldbm_instance_attrcrypt_filter;
+
+ /* Construct the base dn of the subtree that holds the index entries
+ * for this instance. */
+ sprintf(basedn, "cn=encrypted attributes, cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, inst->inst_li->li_plugin->plg_name);
+
+ /* Set up a tmp callback that will handle the init for each index entry */
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP,
+ basedn, scope, searchfilter, ldbm_attrcrypt_init_entry_callback,
+ (void *) inst);
+
+ /* Do a search of the subtree containing the index entries */
+ tmp_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(tmp_pb, basedn, LDAP_SCOPE_SUBTREE,
+ searchfilter, NULL, 0, NULL, NULL, inst->inst_li->li_identity, 0);
+ slapi_search_internal_pb (tmp_pb);
+
+ /* Remove the tmp callback */
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP,
+ basedn, scope, searchfilter, ldbm_attrcrypt_init_entry_callback);
+ slapi_free_search_results_internal(tmp_pb);
+ slapi_pblock_destroy(tmp_pb);
+
+ return 0;
+}
+
+/* Handles the parsing of the config entry for an ldbm instance. Returns 0
+ * on success. */
+static int
+parse_ldbm_instance_config_entry(ldbm_instance *inst, Slapi_Entry *e, config_info *config_array)
+{
+ Slapi_Attr *attr = NULL;
+
+ for (slapi_entry_first_attr(e, &attr); attr;
+ slapi_entry_next_attr(e, attr, &attr)) {
+ char *attr_name = NULL;
+ Slapi_Value *sval = NULL;
+ struct berval *bval;
+ char err_buf[BUFSIZ];
+
+ slapi_attr_get_type(attr, &attr_name);
+
+ /* There are some attributes that we don't care about,
+ * like objectclass. */
+ if (ldbm_config_ignored_attr(attr_name)) {
+ continue;
+ }
+
+ /* We have to handle suffix attributes a little differently */
+ if (strcasecmp(attr_name, CONFIG_INSTANCE_SUFFIX) == 0) {
+ Slapi_DN suffix;
+
+ slapi_attr_first_value(attr, &sval);
+ bval = (struct berval *) slapi_value_get_berval(sval);
+ slapi_sdn_init_dn_byref(&suffix, bval->bv_val);
+ if (!slapi_be_issuffix(inst->inst_be, &suffix)) {
+ be_addsuffix(inst->inst_be, &suffix);
+ }
+ slapi_sdn_done(&suffix);
+ continue;
+ }
+
+ /* We are assuming that each of these attributes are to have
+ * only one value. If they have more than one value, like
+ * the nsslapd-suffix attribute, then they need to be
+ * handled differently. */
+ slapi_attr_first_value(attr, &sval);
+ bval = (struct berval *) slapi_value_get_berval(sval);
+
+ if (ldbm_config_set((void *) inst, attr_name, config_array, bval,
+ err_buf, CONFIG_PHASE_STARTUP, 1 /* apply */) != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error with config attribute %s : %s\n",
+ attr_name, err_buf, 0);
+ return 1;
+ }
+ }
+
+ /* Read the index entries */
+ read_instance_index_entries(inst);
+ /* Read the attribute encryption entries */
+ read_instance_attrcrypt_entries(inst);
+
+ return 0;
+}
+
+/* general-purpose callback to deny an operation */
+static int ldbm_instance_deny_config(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+/* Reads in any config information held in the dse for the given
+ * entry. Creates dse entries used to configure the given instance
+ * if they don't already exist. Registers dse callback functions to
+ * maintain those dse entries. Returns 0 on success. */
+int
+ldbm_instance_config_load_dse_info(ldbm_instance *inst)
+{
+ struct ldbminfo *li = inst->inst_li;
+ Slapi_PBlock *search_pb;
+ Slapi_Entry **entries = NULL;
+ int res;
+ char dn[BUFSIZ];
+
+ /* We try to read the entry
+ * cn=instance_name, cn=ldbm database, cn=plugins, cn=config. If the
+ * entry is there, then we process the config information it stores.
+ */
+ sprintf(dn, "cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ search_pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(search_pb, dn, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL,
+ li->li_identity, 0);
+ slapi_search_internal_pb (search_pb);
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if (res != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error accessing the config DSE\n", 0, 0, 0);
+ return 1;
+ } else {
+ /* Need to parse the configuration information for the ldbm
+ * plugin that is held in the DSE. */
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+ &entries);
+ if ((!entries) || (!entries[0])) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error accessing the config DSE\n",
+ 0, 0, 0);
+ return 1;
+ }
+ parse_ldbm_instance_config_entry(inst, entries[0],
+ ldbm_instance_config);
+ }
+
+ if (search_pb)
+ {
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+ }
+
+ /* now check for cn=monitor -- if not present, add default child entries */
+ search_pb = slapi_pblock_new();
+ sprintf(dn, "cn=monitor, cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ slapi_search_internal_set_pb(search_pb, dn, LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, 0, NULL, NULL,
+ li->li_identity, 0);
+ slapi_search_internal_pb(search_pb);
+ slapi_pblock_get(search_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if (res == LDAP_NO_SUCH_OBJECT) {
+ /* Add skeleton dse entries for this instance */
+ ldbm_config_add_dse_entries(li, ldbm_instance_skeleton_entries,
+ inst->inst_name, li->li_plugin->plg_name,
+ inst->inst_name, 0);
+ }
+
+ if (search_pb) {
+ slapi_free_search_results_internal(search_pb);
+ slapi_pblock_destroy(search_pb);
+ }
+
+ /* setup the dse callback functions for the ldbm instance config entry */
+ sprintf(dn, "cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)",
+ ldbm_instance_search_config_entry_callback, (void *) inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)",
+ ldbm_instance_modify_config_entry_callback, (void *) inst);
+ slapi_config_register_callback(DSE_OPERATION_WRITE, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)",
+ ldbm_instance_search_config_entry_callback, (void *) inst);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)",
+ ldbm_instance_deny_config, (void *)inst);
+ /* delete is handled by a callback set in ldbm_config.c */
+
+ /* don't forget the monitor! */
+ sprintf(dn, "cn=monitor, cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ /* make callback on search; deny add/modify/delete */
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_back_monitor_instance_search,
+ (void *)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=*)", ldbm_instance_deny_config,
+ (void *)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_instance_deny_config,
+ (void *)inst);
+ /* delete is okay */
+
+ /* Callbacks to handle indexes */
+ sprintf(dn, "cn=index, cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)",
+ ldbm_instance_index_config_add_callback, (void *) inst);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)",
+ ldbm_instance_index_config_delete_callback, (void *) inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)",
+ ldbm_instance_index_config_modify_callback, (void *) inst);
+
+ /* Callbacks to handle attribute encryption */
+ sprintf(dn, "cn=encrypted attributes, cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, ldbm_instance_attrcrypt_filter,
+ ldbm_instance_attrcrypt_config_add_callback, (void *) inst);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, ldbm_instance_attrcrypt_filter,
+ ldbm_instance_attrcrypt_config_delete_callback, (void *) inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, ldbm_instance_attrcrypt_filter,
+ ldbm_instance_attrcrypt_config_modify_callback, (void *) inst);
+
+ return 0;
+}
+
+/*
+ * Config. DSE callback for instance entry searches.
+ */
+int
+ldbm_instance_search_config_entry_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ char buf[BUFSIZ];
+ struct berval *vals[2];
+ struct berval val;
+ ldbm_instance *inst = (ldbm_instance *) arg;
+ config_info *config;
+ int x;
+ const Slapi_DN *suffix;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ returntext[0] = '\0';
+
+ /* show the suffixes */
+ attrlist_delete(&e->e_attrs, CONFIG_INSTANCE_SUFFIX);
+ x = 0;
+ do {
+ suffix = slapi_be_getsuffix(inst->inst_be, x);
+ if (suffix != NULL) {
+ val.bv_val = (char *) slapi_sdn_get_dn(suffix);
+ val.bv_len = strlen (val.bv_val);
+ attrlist_merge( &e->e_attrs, CONFIG_INSTANCE_SUFFIX, vals );
+ }
+ x++;
+ } while(suffix!=NULL);
+
+ PR_Lock(inst->inst_config_mutex);
+
+ for(config = ldbm_instance_config; config->config_name != NULL; config++) {
+ /* Go through the ldbm_config table and fill in the entry. */
+
+ if (!(config->config_flags & (CONFIG_FLAG_ALWAYS_SHOW | CONFIG_FLAG_PREVIOUSLY_SET))) {
+ /* This config option shouldn't be shown */
+ continue;
+ }
+
+ ldbm_config_get((void *) inst, config, buf);
+
+ val.bv_val = buf;
+ val.bv_len = strlen(buf);
+ slapi_entry_attr_replace(e, config->config_name, vals);
+ }
+
+ PR_Unlock(inst->inst_config_mutex);
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* This function is used by the instance modify callback to add a new
+ * suffix. It return LDAP_SUCCESS on success.
+ */
+int
+add_suffix(ldbm_instance *inst, struct berval **bvals, int apply_mod, char *returntext)
+{
+ Slapi_DN suffix;
+ int x;
+
+ returntext[0] = '\0';
+ for (x = 0; bvals[x]; x++) {
+ slapi_sdn_init_dn_byref(&suffix, bvals[x]->bv_val);
+ if (!slapi_be_issuffix(inst->inst_be, &suffix) && apply_mod) {
+ be_addsuffix(inst->inst_be, &suffix);
+ }
+ slapi_sdn_done(&suffix);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+/*
+ * Config. DSE callback for instance entry modifies.
+ */
+int
+ldbm_instance_modify_config_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ int i;
+ char *attr_name;
+ LDAPMod **mods;
+ int rc = LDAP_SUCCESS;
+ int apply_mod = 0;
+ ldbm_instance *inst = (ldbm_instance *) arg;
+
+ /* This lock is probably way too conservative, but we don't expect much
+ * contention for it. */
+ PR_Lock(inst->inst_config_mutex);
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ returntext[0] = '\0';
+
+ /*
+ * First pass: set apply mods to 0 so only input validation will be done;
+ * 2nd pass: set apply mods to 1 to apply changes to internal storage
+ */
+ for ( apply_mod = 0; apply_mod <= 1 && LDAP_SUCCESS == rc; apply_mod++ ) {
+ for (i = 0; mods[i] && LDAP_SUCCESS == rc; i++) {
+ attr_name = mods[i]->mod_type;
+
+ if (strcasecmp(attr_name, CONFIG_INSTANCE_SUFFIX) == 0) {
+ /* naughty naughty, we don't allow this */
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ if (returntext) {
+ sprintf(returntext,
+ "Can't change the root suffix of a backend");
+ }
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm: modify attempted to change the root suffix "
+ "of a backend (which is not allowed)\n",
+ 0, 0, 0);
+ continue;
+ }
+
+ /* There are some attributes that we don't care about, like
+ * modifiersname. */
+ if (ldbm_config_ignored_attr(attr_name)) {
+ continue;
+ }
+
+ if ((mods[i]->mod_op & LDAP_MOD_DELETE) ||
+ (mods[i]->mod_op & LDAP_MOD_ADD)) {
+ rc= LDAP_UNWILLING_TO_PERFORM;
+ sprintf(returntext, "%s attributes is not allowed",
+ (mods[i]->mod_op & LDAP_MOD_DELETE) ?
+ "Deleting" : "Adding");
+ } else if (mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ /* This assumes there is only one bval for this mod. */
+ rc = ldbm_config_set((void *) inst, attr_name,
+ ldbm_instance_config, mods[i]->mod_bvalues[0], returntext,
+ CONFIG_PHASE_RUNNING, apply_mod);
+ }
+ }
+ }
+
+ PR_Unlock(inst->inst_config_mutex);
+
+ *returncode = rc;
+ if (LDAP_SUCCESS == rc) {
+ return SLAPI_DSE_CALLBACK_OK;
+ } else {
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+}
+
+/* This function is used to set instance config attributes. It can be used as a
+ * shortcut to doing an internal modify operation on the config DSE.
+ */
+void
+ldbm_instance_config_internal_set(ldbm_instance *inst, char *attrname, char *value)
+{
+ char err_buf[BUFSIZ];
+ struct berval bval;
+
+ bval.bv_val = value;
+ bval.bv_len = strlen(value);
+
+ if (ldbm_config_set((void *) inst, attrname, ldbm_instance_config, &bval,
+ err_buf, CONFIG_PHASE_INTERNAL, 1 /* apply */) != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Internal Error: Error setting instance config attr %s to %s: %s\n",
+ attrname, value, err_buf);
+ exit(1);
+ }
+}
+
+
+
+static int ldbm_instance_generate(struct ldbminfo *li, char *instance_name,
+ Slapi_Backend **ret_be)
+{
+ Slapi_Backend *new_be = NULL;
+ int rc = 0;
+
+ /* Create a new instance, process config info for it,
+ * and then call slapi_be_new and create a new backend here
+ */
+ new_be = slapi_be_new(LDBM_DATABASE_TYPE_NAME /* type */, instance_name,
+ 0 /* public */, 1 /* do log changes */);
+ new_be->be_database = li->li_plugin;
+ ldbm_instance_create(new_be, instance_name);
+
+ ldbm_instance_config_load_dse_info(new_be->be_instance_info);
+ rc = ldbm_instance_create_default_indexes(new_be);
+
+ if (ret_be != NULL) {
+ *ret_be = new_be;
+ }
+
+ return rc;
+}
+
+int
+ldbm_instance_postadd_instance_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ backend *be = NULL;
+ struct ldbm_instance *inst;
+ char *instance_name;
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+ int rval = 0;
+
+ parse_ldbm_instance_entry(entryBefore, &instance_name);
+ ldbm_instance_generate(li, instance_name, &be);
+
+ inst = ldbm_instance_find_by_name(li, instance_name);
+
+ /* Add default indexes */
+ ldbm_instance_create_default_user_indexes(inst);
+
+ /* Initialize and register callbacks for VLV indexes */
+ vlv_init(inst);
+
+ /* this is an ACTUAL ADD being done while the server is running!
+ * start up the appropriate backend...
+ */
+ rval = ldbm_instance_start(be);
+ if (0 != rval)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm_instance_postadd_instance_entry_callback: "
+ "ldbm_instnace_start (%s) failed (%d)\n",
+ instance_name, rval, 0);
+ }
+
+ slapi_ch_free((void **)&instance_name);
+
+ /* instance must be fully ready before we call this */
+ slapi_mtn_be_started(be);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+int
+ldbm_instance_add_instance_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ char *instance_name;
+ struct ldbm_instance *inst= NULL;
+ struct ldbminfo *li= (struct ldbminfo *) arg;
+ int rc = 0;
+
+ parse_ldbm_instance_entry(entryBefore, &instance_name);
+
+ /* Make sure we don't create two instances with the same name. */
+ inst = ldbm_instance_find_by_name(li, instance_name);
+ if (inst != NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: ldbm instance %s already exists\n",
+ instance_name, 0, 0);
+ if (returntext != NULL)
+ sprintf(returntext, "An ldbm instance with the name %s already exists\n",
+ instance_name);
+ if (returncode != NULL)
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ slapi_ch_free((void **)&instance_name);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ if (pb == NULL) {
+ /* called during startup -- do the rest now */
+ rc = ldbm_instance_generate(li, instance_name, NULL);
+ }
+ /* if called during a normal ADD operation, the postadd callback
+ * will do the rest.
+ */
+
+ slapi_ch_free((void **)&instance_name);
+ return (rc == 0) ? SLAPI_DSE_CALLBACK_OK : SLAPI_DSE_CALLBACK_ERROR;
+}
+
+
+
+
+/* unregister the DSE callbacks on a backend -- this needs to be done when
+ * deleting a backend, so that adding the same backend later won't cause
+ * these expired callbacks to be called.
+ */
+static void ldbm_instance_unregister_callbacks(ldbm_instance *inst)
+{
+ struct ldbminfo *li = inst->inst_li;
+ char dn[BUFSIZ];
+
+ /* tear down callbacks for the instance config entry */
+ sprintf(dn, "cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)",
+ ldbm_instance_search_config_entry_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)",
+ ldbm_instance_modify_config_entry_callback);
+ slapi_config_remove_callback(DSE_OPERATION_WRITE, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)",
+ ldbm_instance_search_config_entry_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)",
+ ldbm_instance_deny_config);
+
+ /* now the cn=monitor entry */
+ sprintf(dn, "cn=monitor, cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_back_monitor_instance_search);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=*)", ldbm_instance_deny_config);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", ldbm_instance_deny_config);
+
+ /* now the cn=index entries */
+ sprintf(dn, "cn=index, cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)",
+ ldbm_instance_index_config_add_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)",
+ ldbm_instance_index_config_delete_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=nsIndex)",
+ ldbm_instance_index_config_modify_callback);
+
+ /* now the cn=encrypted attributes entries */
+ sprintf(dn, "cn=encrypted attributes, cn=%s, cn=%s, cn=plugins, cn=config",
+ inst->inst_name, li->li_plugin->plg_name);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, ldbm_instance_attrcrypt_filter,
+ ldbm_instance_attrcrypt_config_add_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, ldbm_instance_attrcrypt_filter,
+ ldbm_instance_attrcrypt_config_delete_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, ldbm_instance_attrcrypt_filter,
+ ldbm_instance_attrcrypt_config_modify_callback);
+
+ vlv_remove_callbacks(inst);
+}
+
+
+int
+ldbm_instance_post_delete_instance_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ char *instance_name;
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+ struct ldbm_instance *inst = NULL;
+
+ parse_ldbm_instance_entry(entryBefore, &instance_name);
+ inst = ldbm_instance_find_by_name(li, instance_name);
+
+ if (inst == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: instance '%s' does not exist! (2)\n",
+ instance_name, 0, 0);
+ if (returntext) {
+ sprintf(returntext, "No ldbm instance exists with the name '%s' (2)\n",
+ instance_name);
+ }
+ if (returncode) {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ }
+ slapi_ch_free((void **)&instance_name);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: removing '%s'.\n", instance_name, 0, 0);
+
+ {
+ struct ldbminfo *li = (struct ldbminfo *) inst->inst_be->be_database->plg_private;
+ dblayer_private *priv = (dblayer_private*) li->li_dblayer_private;
+ struct dblayer_private_env *pEnv = priv->dblayer_env;
+ if(pEnv) {
+ PRDir *dirhandle = NULL;
+ char dbName[MAXPATHLEN*2];
+ char *dbNamep = NULL;
+ char *p;
+ int dbbasenamelen, dbnamelen;
+ int rc;
+ if (inst->inst_dir_name == NULL){
+ dblayer_get_instance_data_dir(inst->inst_be);
+ }
+ dirhandle = PR_OpenDir(inst->inst_dir_name);
+ /* the db dir instance may have been removed already */
+ if (dirhandle){
+ dbNamep = dblayer_get_full_inst_dir(li, inst,
+ dbName, MAXPATHLEN*2);
+ dbbasenamelen = strlen(dbNamep);
+ dbnamelen = dbbasenamelen + 14; /* "/id2entry.db#" + '\0' */
+ if (dbnamelen > MAXPATHLEN*2)
+ {
+ dbNamep = (char *)slapi_ch_realloc(dbNamep, dbnamelen);
+ }
+ p = dbNamep + dbbasenamelen;
+ sprintf(p, "%c%s%s", get_sep(dbNamep),
+ "id2entry", LDBM_FILENAME_SUFFIX);
+ rc = dblayer_db_remove(pEnv, dbName, 0);
+ PR_ASSERT(rc == 0);
+ if (dbNamep != dbName)
+ slapi_ch_free_string(&dbNamep);
+ PR_CloseDir(dirhandle);
+ } /* non-null dirhandle */
+ } /* non-null pEnv */
+ }
+
+ ldbm_instance_unregister_callbacks(inst);
+ slapi_be_free(&inst->inst_be);
+ ldbm_instance_destroy(inst);
+ slapi_ch_free((void **)&instance_name);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+int
+ldbm_instance_delete_instance_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ char *instance_name;
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+ struct ldbm_instance *inst = NULL;
+
+ parse_ldbm_instance_entry(entryBefore, &instance_name);
+ inst = ldbm_instance_find_by_name(li, instance_name);
+ if (inst == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: instance '%s' does not exist!\n",
+ instance_name, 0, 0);
+ if (returntext) {
+ sprintf(returntext, "No ldbm instance exists with the name '%s'\n",
+ instance_name);
+ }
+ if (returncode) {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ }
+ slapi_ch_free((void **)&instance_name);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* check if some online task is happening */
+ if (instance_set_busy(inst) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: '%s' is in the middle of a task. "
+ "Cancel the task or wait for it to finish, "
+ "then try again.\n", instance_name, 0, 0);
+ if (returntext) {
+ sprintf(returntext, "ldbm instance '%s' is in the middle of a "
+ "task. Cancel the task or wait for it to finish, "
+ "then try again.\n", instance_name);
+ }
+ if (returncode) {
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ }
+ slapi_ch_free((void **)&instance_name);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* okay, we're gonna delete this database instance. take it offline. */
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: Bringing %s offline...\n",
+ instance_name, 0, 0);
+ slapi_mtn_be_stopping(inst->inst_be);
+ dblayer_instance_close(inst->inst_be);
+ cache_destroy_please(&inst->inst_cache);
+ slapi_ch_free((void **)&instance_name);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modify.c b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
new file mode 100644
index 00000000..1df2e6fd
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modify.c
@@ -0,0 +1,567 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* modify.c - ldbm backend modify routine */
+
+#include "back-ldbm.h"
+
+extern char *numsubordinates;
+extern char *hassubordinates;
+
+static void remove_illegal_mods(LDAPMod **mods);
+static int mods_have_effect (Slapi_Entry *entry, Slapi_Mods *smods);
+
+/* Modify context structure constructor, sans allocation */
+void modify_init(modify_context *mc,struct backentry *old_entry)
+{
+ /* Store the old entry */
+ PR_ASSERT(NULL == mc->old_entry);
+ PR_ASSERT(NULL == mc->new_entry);
+
+ mc->old_entry = old_entry;
+ mc->new_entry_in_cache = 0;
+}
+
+int modify_apply_mods(modify_context *mc, Slapi_Mods *smods)
+{
+ int ret = 0;
+ /* Make a copy of the entry */
+ PR_ASSERT(mc->old_entry != NULL);
+ PR_ASSERT(mc->new_entry == NULL);
+ mc->new_entry = backentry_dup(mc->old_entry);
+ PR_ASSERT(smods!=NULL);
+ if ( mods_have_effect (mc->new_entry->ep_entry, smods) ) {
+ ret = entry_apply_mods( mc->new_entry->ep_entry, slapi_mods_get_ldapmods_byref(smods));
+ }
+ mc->smods= smods;
+ return ret;
+}
+
+/* Modify context structure destructor */
+int modify_term(modify_context *mc,struct backend *be)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+
+ slapi_mods_free(&mc->smods);
+ /* Unlock and return entries */
+ if (NULL != mc->old_entry) {
+ cache_unlock_entry(&inst->inst_cache, mc->old_entry);
+ cache_return( &(inst->inst_cache), &(mc->old_entry) );
+ mc->old_entry= NULL;
+ }
+ if (mc->new_entry_in_cache) {
+ cache_return( &(inst->inst_cache), &(mc->new_entry) );
+ } else {
+ backentry_free(&(mc->new_entry));
+ }
+ mc->new_entry= NULL;
+ return 0;
+}
+
+/* Modify context structure member to switch entries in the cache */
+int modify_switch_entries(modify_context *mc,backend *be)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ int ret = 0;
+ if (mc->old_entry!=NULL && mc->new_entry!=NULL) {
+ ret = cache_replace(&(inst->inst_cache), mc->old_entry, mc->new_entry);
+ if (ret == 0) mc->new_entry_in_cache = 1;
+ }
+ return ret;
+}
+
+/* This routine does that part of a modify operation which involves
+ updating the on-disk data: updates idices, id2entry.
+ Copes properly with DB_LOCK_DEADLOCK. The caller must be able to cope with
+ DB_LOCK_DEADLOCK returned.
+ The caller is presumed to proceed as follows:
+ Find the entry you want to modify;
+ Lock it for modify;
+ Make a copy of it; (call backentry_dup() )
+ Apply modifications to the copy in memory (call entry_apply_mods() )
+ begin transaction;
+ Do any other mods to on-disk data you want
+ Call this routine;
+ Commit transaction;
+ You pass it environment data: struct ldbminfo, pb (not sure why, but the vlv code seems to need it)
+ the copy of the entry before modfication, the entry after modification;
+ an LDAPMods array containing the modifications performed
+*/
+int modify_update_all(backend *be, Slapi_PBlock *pb,
+ modify_context *mc,
+ back_txn *txn)
+{
+ static char *function_name = "modify_update_all";
+ int retval = 0;
+
+ /*
+ * Update the ID to Entry index.
+ * Note that id2entry_add replaces the entry, so the Entry ID stays the same.
+ */
+ retval = id2entry_add( be, mc->new_entry, txn );
+ if ( 0 != retval ) {
+ if (DB_LOCK_DEADLOCK != retval)
+ {
+ ldbm_nasty(function_name,66,retval);
+ }
+ goto error;
+ }
+ retval = index_add_mods( be, (const LDAPMod **)slapi_mods_get_ldapmods_byref(mc->smods), mc->old_entry, mc->new_entry, txn );
+ if ( 0 != retval ) {
+ if (DB_LOCK_DEADLOCK != retval)
+ {
+ ldbm_nasty(function_name,65,retval);
+ }
+ goto error;
+ }
+ /*
+ * Remove the old entry from the Virtual List View indexes.
+ * Add the new entry to the Virtual List View indexes.
+ * Because the VLV code calls slapi_filter_test(), which requires a pb (why?),
+ * we allow the caller sans pb to get everything except vlv indexing.
+ */
+ if (NULL != pb) {
+ retval= vlv_update_all_indexes(txn, be, pb, mc->old_entry, mc->new_entry);
+ if ( 0 != retval ) {
+ if (DB_LOCK_DEADLOCK != retval)
+ {
+ ldbm_nasty(function_name,64,retval);
+ }
+ goto error;
+ }
+ }
+error:
+ return retval;
+}
+
+int
+ldbm_back_modify( Slapi_PBlock *pb )
+{
+ backend *be;
+ ldbm_instance *inst;
+ struct ldbminfo *li;
+ struct backentry *e, *ec = NULL;
+ Slapi_Entry *postentry = NULL;
+ LDAPMod **mods;
+ back_txn txn;
+ back_txnid parent_txn;
+ int retval = -1;
+ char *msg;
+ char *errbuf = NULL;
+ int retry_count = 0;
+ int disk_full = 0;
+ int ldap_result_code= LDAP_SUCCESS;
+ char *ldap_result_message= NULL;
+ int rc = 0;
+ Slapi_Operation *operation;
+ int dblock_acquired= 0;
+ entry_address *addr;
+ int change_entry = 0;
+ int ec_in_cache = 0;
+ int is_fixup_operation= 0;
+ CSN *opcsn = NULL;
+ int repl_op;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr );
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ slapi_pblock_get( pb, SLAPI_PARENT_TXN, (void**)&parent_txn );
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
+ slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ is_fixup_operation = operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP);
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ dblayer_txn_init(li,&txn);
+
+ /* The dblock serializes writes to the database,
+ * which reduces deadlocking in the db code,
+ * which means that we run faster.
+ *
+ * But, this lock is re-enterant for the fixup
+ * operations that the URP code in the Replication
+ * plugin generates.
+ */
+ if(SERIALLOCK(li) && !operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP))
+ {
+ dblayer_lock_backend(be);
+ dblock_acquired= 1;
+ }
+
+ /* find and lock the entry we are about to modify */
+ if ( (e = find_entry2modify( pb, be, addr, NULL )) == NULL ) {
+ ldap_result_code= -1;
+ goto error_return; /* error result sent by find_entry2modify() */
+ }
+
+ if ( !is_fixup_operation )
+ {
+ opcsn = operation_get_csn (operation);
+ if (NULL == opcsn && operation->o_csngen_handler)
+ {
+ /*
+ * Current op is a user request. Opcsn will be assigned
+ * if the dn is in an updatable replica.
+ */
+ opcsn = entry_assign_operation_csn ( pb, e->ep_entry, NULL );
+ }
+ if (opcsn)
+ {
+ entry_set_maxcsn (e->ep_entry, opcsn);
+ }
+ }
+
+ /* Save away a copy of the entry, before modifications */
+ slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( e->ep_entry ));
+
+ if ( (ldap_result_code = plugin_call_acl_mods_access( pb, e->ep_entry, mods, &errbuf)) != LDAP_SUCCESS ) {
+ ldap_result_message= errbuf;
+ goto error_return;
+ }
+
+ /* create a copy of the entry and apply the changes to it */
+ if ( (ec = backentry_dup( e )) == NULL ) {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ remove_illegal_mods(mods);
+
+ /* ec is the entry that our bepreop should get to mess with */
+ slapi_pblock_set( pb, SLAPI_MODIFY_EXISTING_ENTRY, ec->ep_entry );
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+ plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODIFY_FN);
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+ /* The Plugin may have messed about with some of the PBlock parameters... ie. mods */
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ {
+ Slapi_Mods smods;
+ CSN *csn = operation_get_csn(operation);
+ slapi_mods_init_byref(&smods,mods);
+ if ( (change_entry = mods_have_effect (ec->ep_entry, &smods)) ) {
+ ldap_result_code = entry_apply_mods_wsi(ec->ep_entry, &smods, csn, operation_is_flag_set(operation,OP_FLAG_REPLICATED));
+ /*
+ * XXXmcs: it would be nice to get back an error message from
+ * the above call so we could pass it along to the client, e.g.,
+ * "duplicate value for attribute givenName."
+ */
+ } else {
+ /* If the entry was not actually changed, we still need to
+ * set the SLAPI_ENTRY_POST_OP field in the pblock (post-op
+ * plugins expect that field to be present for all modify
+ * operations that return LDAP_SUCCESS).
+ */
+ postentry = slapi_entry_dup( e->ep_entry );
+ slapi_pblock_set ( pb, SLAPI_ENTRY_POST_OP, postentry );
+ postentry = NULL; /* avoid removal/free in error_return code */
+ }
+ slapi_mods_done(&smods);
+ if ( !change_entry || ldap_result_code != 0 ) {
+ /* change_entry == 0 is not an error, but we need to free lock etc */
+ goto error_return;
+ }
+ }
+
+ /*
+ * If we are not handling a replicated operation, AND if the
+ * objectClass attribute type was modified in any way, expand
+ * the objectClass values to reflect the inheritance hierarchy.
+ * [blackflag 624152]: repl_op covers both regular and legacy replication
+ */
+ if(!repl_op)
+ {
+ int i;
+
+ for ( i = 0; mods[i] != NULL; ++i ) {
+ if ( 0 == strcasecmp( SLAPI_ATTR_OBJECTCLASS, mods[i]->mod_type )) {
+ slapi_schema_expand_objectclasses( ec->ep_entry );
+ break;
+ }
+ }
+ }
+
+ /*
+ * We are about to pass the last abandon test, so from now on we are
+ * committed to finish this operation. Set status to "will complete"
+ * before we make our last abandon check to avoid race conditions in
+ * the code that processes abandon operations.
+ */
+ if (operation) {
+ operation->o_status = SLAPI_OP_STATUS_WILL_COMPLETE;
+ }
+ if ( slapi_op_abandoned( pb ) ) {
+ goto error_return;
+ }
+
+ /* check that the entry still obeys the schema */
+ if ( (operation_is_flag_set(operation,OP_FLAG_ACTION_SCHEMA_CHECK)) &&
+ slapi_entry_schema_check( pb, ec->ep_entry ) != 0 ) {
+ ldap_result_code= LDAP_OBJECT_CLASS_VIOLATION;
+ slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
+ goto error_return;
+ }
+
+ /*
+ * make sure the entry contains all values in the RDN.
+ * if not, the modification must have removed them.
+ */
+ if ( ! slapi_entry_rdn_values_present( ec->ep_entry ) ) {
+ ldap_result_code= LDAP_NOT_ALLOWED_ON_RDN;
+ goto error_return;
+ }
+
+ for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++) {
+
+ if (retry_count > 0) {
+ dblayer_txn_abort(li,&txn);
+ LDAPDebug( LDAP_DEBUG_TRACE, "Modify Retrying Transaction\n", 0, 0, 0 );
+#ifndef LDBM_NO_BACKOFF_DELAY
+ {
+ PRIntervalTime interval;
+ interval = PR_MillisecondsToInterval(slapi_rand() % 100);
+ DS_Sleep(interval);
+ }
+#endif
+ }
+
+ /* Nothing above here modifies persistent store, everything after here is subject to the transaction */
+ retval = dblayer_txn_begin(li,parent_txn,&txn);
+
+ if (0 != retval) {
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ /*
+ * Update the ID to Entry index.
+ * Note that id2entry_add replaces the entry, so the Entry ID stays the same.
+ */
+ retval = id2entry_add( be, ec, &txn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Abort and re-try */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_ANY, "id2entry_add failed, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ ec_in_cache = 1;
+ retval = index_add_mods( be, (const LDAPMod**)mods, e, ec, &txn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Abort and re-try */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_ANY, "index_add_mods failed, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+ /*
+ * Remove the old entry from the Virtual List View indexes.
+ * Add the new entry to the Virtual List View indexes.
+ */
+ retval= vlv_update_all_indexes(&txn, be, pb, e, ec);
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Abort and re-try */
+ continue;
+ }
+ if (0 != retval) {
+ LDAPDebug( LDAP_DEBUG_ANY, "vlv_update_index failed, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ if (0 == retval) {
+ break;
+ }
+ }
+ if (retry_count == RETRY_TIMES) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Retry count exceeded in modify\n", 0, 0, 0 );
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ if (cache_replace( &inst->inst_cache, e, ec ) != 0 ) {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ postentry = slapi_entry_dup( ec->ep_entry );
+ slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, postentry );
+
+ /* invalidate virtual cache */
+ ec->ep_entry->e_virtual_watermark = 0;
+
+ /* we must return both e (which has been deleted) and new entry ec */
+ cache_unlock_entry( &inst->inst_cache, e );
+ cache_return( &inst->inst_cache, &e );
+ /*
+ * LP Fix of crash when the commit will fail:
+ * If the commit fail, the common error path will
+ * try to unlock the entry again and crash (PR_ASSERT
+ * in debug mode.
+ * By just setting e to NULL, we avoid this. It's OK since
+ * we don't use e after that in the normal case.
+ */
+ e = NULL;
+
+ retval = dblayer_txn_commit(li,&txn);
+ if (0 != retval) {
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ rc= 0;
+ goto common_return;
+
+error_return:
+ if (ec_in_cache)
+ {
+ cache_remove( &inst->inst_cache, ec );
+ }
+ else
+ {
+ backentry_free(&ec);
+ }
+ if ( postentry != NULL )
+ {
+ slapi_entry_free( postentry );
+ postentry = NULL;
+ slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, NULL );
+ }
+
+ if (e!=NULL) {
+ cache_unlock_entry( &inst->inst_cache, e);
+ cache_return( &inst->inst_cache, &e);
+ }
+
+ if (retval == DB_RUNRECOVERY) {
+ dblayer_remember_disk_filled(li);
+ ldbm_nasty("Modify",81,retval);
+ disk_full = 1;
+ }
+
+ if (disk_full)
+ rc= return_on_disk_full(li);
+ else if (ldap_result_code != LDAP_SUCCESS) {
+ /* It is specifically OK to make this call even when no transaction was in progress */
+ dblayer_txn_abort(li,&txn); /* abort crashes in case disk full */
+ rc= SLAPI_FAIL_GENERAL;
+ }
+
+
+common_return:
+
+ if (ec_in_cache)
+ {
+ cache_return( &inst->inst_cache, &ec );
+ }
+ /* JCMREPL - The bepostop is called even if the operation fails. */
+ if (!disk_full)
+ plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_MODIFY_FN);
+
+ if(dblock_acquired)
+ {
+ dblayer_unlock_backend(be);
+ }
+ if(ldap_result_code!=-1)
+ {
+ slapi_send_ldap_result( pb, ldap_result_code, NULL, ldap_result_message, 0, NULL );
+ }
+
+ slapi_ch_free( (void**)&errbuf);
+ return rc;
+}
+
+/* Function removes mods which are not allowed over-the-wire */
+static void
+remove_illegal_mods(LDAPMod **mods)
+{
+ int i, j;
+ LDAPMod *tmp;
+
+ /* remove any attempts by the user to modify these attrs */
+ for ( i = 0; mods[i] != NULL; i++ ) {
+ if ( strcasecmp( mods[i]->mod_type, numsubordinates ) == 0
+ || strcasecmp( mods[i]->mod_type, hassubordinates ) == 0 )
+ {
+ tmp = mods[i];
+ for ( j = i; mods[j] != NULL; j++ ) {
+ mods[j] = mods[j + 1];
+ }
+ slapi_ch_free( (void**)&(tmp->mod_type) );
+ if ( tmp->mod_bvalues != NULL ) {
+ ber_bvecfree( tmp->mod_bvalues );
+ }
+ slapi_ch_free( (void**)&tmp );
+ i--;
+ }
+ }
+}
+
+/* A mod has no effect if it is trying to replace a non-existing
+ * attribute with null value
+ */
+static int
+mods_have_effect (Slapi_Entry *entry, Slapi_Mods *smods)
+{
+ LDAPMod *mod;
+ Slapi_Attr *attr;
+ int have_effect = 1;
+ int j;
+
+ /* Mods have effect if there is at least a non-replace mod or
+ * a non-null-value mod.
+ */
+ for ( j = 0; j < smods->num_mods - 1; j++ ) {
+ if ( (mod = smods->mods[j]) != NULL ) {
+ if ( (mod->mod_op & LDAP_MOD_REPLACE) == 0 ||
+ mod->mod_vals.modv_bvals &&
+ strcasecmp (mod->mod_type, "modifiersname") &&
+ strcasecmp (mod->mod_type, "modifytime") ) {
+ goto done;
+ }
+ }
+ }
+
+ if ( entry && entry->e_sdn.dn ) {
+ for ( j = 0; j < smods->num_mods - 1; j++ ) {
+ if ( (mod = smods->mods[j]) != NULL &&
+ strcasecmp (mod->mod_type, "modifiersname") &&
+ strcasecmp (mod->mod_type, "modifytime") ) {
+ for ( attr = entry->e_attrs; attr; attr = attr->a_next ) {
+ /* Mods have effect if at least a null-value-mod is
+ * to actually remove an existing attribute
+ */
+ if ( strcasecmp ( mod->mod_type, attr->a_type ) == 0 ) {
+ goto done;
+ }
+ }
+ have_effect = 0;
+ }
+ }
+
+ }
+
+done:
+
+ /* Return true would let the flow continue along the old path before
+ * this function was added
+ */
+ return have_effect;
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
new file mode 100644
index 00000000..8658886a
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_modrdn.c
@@ -0,0 +1,1403 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* modrdn.c - ldbm backend modrdn routine */
+
+#include "back-ldbm.h"
+
+static const char *moddn_get_newdn(Slapi_PBlock *pb, Slapi_DN *dn_olddn, Slapi_DN *dn_newrdn, Slapi_DN *dn_newsuperiordn);
+static void moddn_unlock_and_return_entries(backend *be,struct backentry **targetentry, struct backentry **existingentry);
+static int moddn_newrdn_mods(Slapi_PBlock *pb, const char *olddn, struct backentry *ec, Slapi_Mods *smods, Slapi_Mods *smods_wsi, int is_repl_op);
+static IDList *moddn_get_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, struct backentry *parententry, Slapi_DN *parentdn, struct backentry ***child_entries, struct backentry ***child_entry_copies);
+static int moddn_rename_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, IDList *children, Slapi_DN *dn_parentdn, Slapi_DN *dn_newsuperiordn, struct backentry *child_entries[], struct backentry *child_entry_copies[]);
+static int modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *e, struct backentry *ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3);
+static void mods_remove_nsuniqueid(Slapi_Mods *smods);
+
+int
+ldbm_back_modrdn( Slapi_PBlock *pb )
+{
+ backend *be;
+ ldbm_instance *inst;
+ struct ldbminfo *li;
+ struct backentry *e= NULL;
+ struct backentry *ec= NULL;
+ int ec_in_cache= 0;
+ back_txn txn;
+ back_txnid parent_txn;
+ int retval = -1;
+ char *msg;
+ Slapi_Entry *postentry = NULL;
+ char *errbuf = NULL;
+ int disk_full = 0;
+ int retry_count = 0;
+ int ldap_result_code= LDAP_SUCCESS;
+ char *ldap_result_message= NULL;
+ char *ldap_result_matcheddn= NULL;
+ struct backentry *parententry= NULL;
+ struct backentry *newparententry= NULL;
+ struct backentry *existingentry= NULL;
+ modify_context parent_modify_context = {0};
+ modify_context newparent_modify_context = {0};
+ IDList *children= NULL;
+ struct backentry **child_entries= NULL;
+ struct backentry **child_entry_copies= NULL;
+ Slapi_DN dn_olddn;
+ Slapi_DN dn_newdn;
+ Slapi_DN dn_newrdn;
+ Slapi_DN dn_newsuperiordn;
+ Slapi_DN dn_parentdn;
+ int rc;
+ int isroot;
+ LDAPMod **mods;
+ Slapi_Mods smods_operation_wsi = {0};
+ Slapi_Mods smods_generated = {0};
+ Slapi_Mods smods_generated_wsi = {0};
+ Slapi_Operation *operation;
+ int dblock_acquired= 0;
+ int is_replicated_operation= 0;
+ int is_fixup_operation = 0;
+ entry_address new_addr;
+ entry_address *old_addr;
+ entry_address oldparent_addr;
+ entry_address *newsuperior_addr;
+ char *dn;
+ char ebuf[BUFSIZ];
+ CSN *opcsn = NULL;
+
+ slapi_sdn_init(&dn_newdn);
+ slapi_sdn_init(&dn_parentdn);
+
+ slapi_pblock_get( pb, SLAPI_MODRDN_TARGET, &dn );
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_PARENT_TXN, (void**)&parent_txn );
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
+ slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation );
+ is_fixup_operation = operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP);
+
+ if (pb->pb_conn)
+ {
+ slapi_log_error (SLAPI_LOG_TRACE, "ldbm_back_modrdn", "enter conn=%d op=%d\n", pb->pb_conn->c_connid, operation->o_opid);
+ }
+
+ inst = (ldbm_instance *) be->be_instance_info;
+ {
+ char *newrdn, *newsuperiordn;
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn );
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperiordn );
+ slapi_sdn_init_dn_byref(&dn_olddn,dn);
+ slapi_sdn_init_dn_byref(&dn_newrdn,newrdn);
+ slapi_sdn_init_dn_byref(&dn_newsuperiordn,newsuperiordn);
+ slapi_sdn_get_parent(&dn_olddn,&dn_parentdn);
+ }
+
+ /* if old and new superior are equals, newsuperior should not be set
+ * Here we have to reset newsuperiordn in order to save processing and
+ * avoid later deadlock when trying to fetch twice the same entry
+ */
+ if (slapi_sdn_compare(&dn_newsuperiordn, &dn_parentdn) == 0)
+ {
+ slapi_sdn_done(&dn_newsuperiordn);
+ slapi_sdn_init_dn_byref(&dn_newsuperiordn,NULL);
+ }
+
+ /* Replicated Operations are allowed to change the superior */
+ if ( !is_replicated_operation && !slapi_sdn_isempty(&dn_newsuperiordn))
+ {
+ slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "server does not support moving of entries", 0, NULL );
+ return( -1 );
+ }
+
+ dblayer_txn_init(li,&txn);
+
+ /* The dblock serializes writes to the database,
+ * which reduces deadlocking in the db code,
+ * which means that we run faster.
+ *
+ * But, this lock is re-enterant for the fixup
+ * operations that the URP code in the Replication
+ * plugin generates.
+ *
+ * Also some URP post-op operations are called after
+ * the backend has committed the change and released
+ * the dblock. Acquire the dblock again for them
+ * if OP_FLAG_ACTION_INVOKE_FOR_REPLOP is set.
+ */
+ if(SERIALLOCK(li) && (!operation_is_flag_set(operation,OP_FLAG_REPL_FIXUP) || operation_is_flag_set(operation,OP_FLAG_ACTION_INVOKE_FOR_REPLOP)))
+ {
+ dblayer_lock_backend(be);
+ dblock_acquired= 1;
+ }
+
+ /* Work out what the new name of the entry will be */
+ {
+ const char *newdn= moddn_get_newdn(pb,&dn_olddn,&dn_newrdn,&dn_newsuperiordn);
+ slapi_sdn_set_dn_passin(&dn_newdn,newdn);
+ }
+
+ rc= 0;
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY);
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY);
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_NEWPARENT_ENTRY);
+ rc= slapi_setbit_int(rc,SLAPI_RTN_BIT_FETCH_TARGET_ENTRY);
+ while(rc!=0)
+ {
+ /* JCM - copying entries can be expensive... should optimize */
+ /*
+ * Some present state information is passed through the PBlock to the
+ * backend pre-op plugin. To ensure a consistent snapshot of this state
+ * we wrap the reading of the entry with the dblock.
+ */
+ if(slapi_isbitset_int(rc,SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY))
+ {
+ const char *newdn = NULL;
+ char * newrdn = NULL;
+
+ /* see if an entry with the new name already exists */
+ done_with_pblock_entry(pb,SLAPI_MODRDN_EXISTING_ENTRY); /* Could be through this multiple times */
+ slapi_sdn_done(&dn_newrdn);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &newrdn);
+ slapi_sdn_init_dn_byref(&dn_newrdn,newrdn);
+ newdn= moddn_get_newdn(pb,&dn_olddn,&dn_newrdn,&dn_newsuperiordn);
+ slapi_sdn_set_dn_passin(&dn_newdn,newdn);
+ new_addr.dn = (char*)slapi_sdn_get_ndn (&dn_newdn);
+ new_addr.uniqueid = NULL;
+ ldap_result_code= get_copy_of_entry(pb, &new_addr, &txn, SLAPI_MODRDN_EXISTING_ENTRY, 0);
+ }
+ if(slapi_isbitset_int(rc,SLAPI_RTN_BIT_FETCH_PARENT_ENTRY))
+ {
+ /* find and lock the old parent entry */
+ done_with_pblock_entry(pb,SLAPI_MODRDN_PARENT_ENTRY); /* Could be through this multiple times */
+ oldparent_addr.dn = (char*)slapi_sdn_get_ndn (&dn_parentdn);
+ oldparent_addr.uniqueid = NULL;
+ ldap_result_code= get_copy_of_entry(pb, &oldparent_addr, &txn, SLAPI_MODRDN_PARENT_ENTRY, !is_replicated_operation);
+ }
+ if(slapi_sdn_get_ndn(&dn_newsuperiordn)!=NULL && slapi_isbitset_int(rc,SLAPI_RTN_BIT_FETCH_NEWPARENT_ENTRY))
+ {
+ /* JCM - Could check that this really is a new superior, and not the same old one. Compare parentdn & newsuperior */
+ /* find and lock the new parent entry */
+ done_with_pblock_entry(pb,SLAPI_MODRDN_NEWPARENT_ENTRY); /* Could be through this multiple times */
+ /* JCMREPL - If this is a replicated operation then should fetch new superior with uniqueid */
+ slapi_pblock_get (pb, SLAPI_MODRDN_NEWSUPERIOR_ADDRESS, &newsuperior_addr);
+ ldap_result_code= get_copy_of_entry(pb, newsuperior_addr, &txn, SLAPI_MODRDN_NEWPARENT_ENTRY, !is_replicated_operation);
+ }
+ if(slapi_isbitset_int(rc,SLAPI_RTN_BIT_FETCH_TARGET_ENTRY))
+ {
+ /* find and lock the entry we are about to modify */
+ done_with_pblock_entry(pb,SLAPI_MODRDN_TARGET_ENTRY); /* Could be through this multiple times */
+ slapi_pblock_get (pb, SLAPI_TARGET_ADDRESS, &old_addr);
+ ldap_result_code= get_copy_of_entry(pb, old_addr, &txn, SLAPI_MODRDN_TARGET_ENTRY, !is_replicated_operation);
+ if(ldap_result_code==LDAP_OPERATIONS_ERROR)
+ {
+ /* JCM - Usually the call to find_entry2modify would generate the result code. */
+ /* JCM !!! */
+ goto error_return;
+ }
+ }
+ /* Call the Backend Pre ModRDN plugins */
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+ rc= plugin_call_plugins(pb, SLAPI_PLUGIN_BE_PRE_MODRDN_FN);
+ if(rc==-1)
+ {
+ /*
+ * Plugin indicated some kind of failure,
+ * or that this Operation became a No-Op.
+ */
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &ldap_result_code);
+ goto error_return;
+ }
+ /*
+ * (rc!=-1) means that the plugin changed things, so we go around
+ * the loop once again to get the new present state.
+ */
+ /* JCMREPL - Warning: A Plugin could cause an infinite loop by always returning a result code that requires some action. */
+ }
+
+ /* find and lock the entry we are about to modify */
+ /* JCMREPL - Argh, what happens about the stinking referrals? */
+ slapi_pblock_get (pb, SLAPI_TARGET_ADDRESS, &old_addr);
+ e = find_entry2modify( pb, be, old_addr, NULL );
+ if ( e == NULL )
+ {
+ ldap_result_code= -1;
+ goto error_return; /* error result sent by find_entry2modify() */
+ }
+
+ /* Check that an entry with the same DN doesn't already exist. */
+ {
+ Slapi_Entry *entry;
+ slapi_pblock_get( pb, SLAPI_MODRDN_EXISTING_ENTRY, &entry);
+ if(entry!=NULL)
+ {
+ ldap_result_code= LDAP_ALREADY_EXISTS;
+ goto error_return;
+ }
+ }
+
+ /* Fetch and lock the parent of the entry that is moving */
+ oldparent_addr.dn = (char*)slapi_sdn_get_ndn (&dn_parentdn);
+ oldparent_addr.uniqueid = NULL;
+ parententry = find_entry2modify_only( pb, be, &oldparent_addr, NULL );
+ modify_init(&parent_modify_context,parententry);
+
+ /* Fetch and lock the new parent of the entry that is moving */
+ if(slapi_sdn_get_ndn(&dn_newsuperiordn)!=NULL)
+ {
+ slapi_pblock_get (pb, SLAPI_MODRDN_NEWSUPERIOR_ADDRESS, &newsuperior_addr);
+ newparententry = find_entry2modify_only( pb, be, newsuperior_addr, NULL);
+ modify_init(&newparent_modify_context,newparententry);
+ }
+
+ opcsn = operation_get_csn (operation);
+ if (!is_fixup_operation)
+ {
+ if ( opcsn == NULL && operation->o_csngen_handler)
+ {
+ /*
+ * Current op is a user request. Opcsn will be assigned
+ * if the dn is in an updatable replica.
+ */
+ opcsn = entry_assign_operation_csn ( pb, e->ep_entry, parententry ? parententry->ep_entry : NULL );
+ }
+ if ( opcsn != NULL )
+ {
+ entry_set_maxcsn (e->ep_entry, opcsn);
+ }
+ }
+
+ /*
+ * Now that we have the old entry, we reset the old DN and recompute
+ * the new DN. Why? Because earlier when we computed the new DN, we did
+ * not have the old entry, so we used the DN that was presented as the
+ * target DN in the ModRDN operation itself, and we would prefer to
+ * preserve the case and spacing that are in the actual entry's DN
+ * instead. Otherwise, a ModRDN operation will potentially change an
+ * entry's entire DN (at least with respect to case and spacing).
+ */
+ slapi_sdn_copy( slapi_entry_get_sdn_const( e->ep_entry ), &dn_olddn );
+ if (newparententry != NULL) {
+ /* don't forget we also want to preserve case of new superior */
+ slapi_sdn_copy(slapi_entry_get_sdn_const(newparententry->ep_entry), &dn_newsuperiordn);
+ }
+ slapi_sdn_set_dn_passin(&dn_newdn,
+ moddn_get_newdn(pb, &dn_olddn, &dn_newrdn, &dn_newsuperiordn));
+
+ /* Check that we're allowed to add an entry below the new superior */
+ if ( newparententry == NULL )
+ {
+ /* There may not be a new parent because we don't intend there to be one. */
+ if(slapi_sdn_get_ndn(&dn_newsuperiordn)!=NULL)
+ {
+ /* If the new entry is to be a suffix, and we're root, then it's OK that the new parent doesn't exist */
+ if(!(slapi_dn_isbesuffix(pb,slapi_sdn_get_ndn(&dn_newdn)) && isroot))
+ {
+ /* Here means that we didn't find the parent */
+ int err = 0;
+ Slapi_DN ancestordn = {0};
+ struct backentry *ancestorentry;
+ ancestorentry= dn2ancestor(be,&dn_newdn,&ancestordn,&txn,&err);
+ cache_return( &inst->inst_cache, &ancestorentry );
+ ldap_result_matcheddn= slapi_ch_strdup((char *) slapi_sdn_get_dn(&ancestordn));
+ ldap_result_code= LDAP_NO_SUCH_OBJECT;
+ LDAPDebug( LDAP_DEBUG_TRACE, "New superior does not exist matched %s, newsuperior = %s\n",
+ ldap_result_matcheddn == NULL ? "NULL" : ldap_result_matcheddn, slapi_sdn_get_ndn(&dn_newsuperiordn), 0 );
+ slapi_sdn_done(&ancestordn);
+ goto error_return;
+ }
+ }
+ }
+ else
+ {
+ ldap_result_code= plugin_call_acl_plugin (pb, newparententry->ep_entry, NULL, NULL, SLAPI_ACL_ADD, ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
+ if ( ldap_result_code != LDAP_SUCCESS )
+ {
+ ldap_result_message= errbuf;
+ LDAPDebug( LDAP_DEBUG_TRACE, "No access to new superior.\n", 0, 0, 0 );
+ goto error_return;
+ }
+ }
+
+ /* Check that the target entry has a parent */
+ if ( parententry == NULL )
+ {
+ /* If the entry a suffix, and we're root, then it's OK that the parent doesn't exist */
+ if(!(slapi_dn_isbesuffix(pb,slapi_sdn_get_ndn(&dn_olddn)) && isroot))
+ {
+ /* Here means that we didn't find the parent */
+ ldap_result_matcheddn = slapi_ch_strdup((char *) slapi_entry_get_dn(parententry->ep_entry));
+ ldap_result_code= LDAP_NO_SUCH_OBJECT;
+ LDAPDebug( LDAP_DEBUG_TRACE, "Parent does not exist matched %s, parentdn = %s\n",
+ ldap_result_matcheddn == NULL ? "NULL" : ldap_result_matcheddn, slapi_sdn_get_ndn(&dn_parentdn), 0 );
+ goto error_return;
+ }
+ }
+
+ /* Replicated Operations are allowed to rename entries with children */
+ if ( !is_replicated_operation && slapi_entry_has_children( e->ep_entry ))
+ {
+ ldap_result_code = LDAP_NOT_ALLOWED_ON_NONLEAF;
+ goto error_return;
+ }
+
+
+ /*
+ * JCM - All the child entries must be locked in the cache, so the size of
+ * subtree that can be renamed is limited by the cache size.
+ */
+
+ /* Save away a copy of the entry, before modifications */
+ slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( e->ep_entry ));
+
+ /* create a copy of the entry and apply the changes to it */
+ if ( (ec = backentry_dup( e )) == NULL )
+ {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ /* JCMACL - Should be performed before the child check. */
+ /* JCMACL - Why is the check performed against the copy, rather than the existing entry? */
+ /*ldap_result_code = plugin_call_acl_plugin (pb, ec->ep_entry, NULL , NULL , SLAPI_ACL_WRITE, ACLPLUGIN_ACCESS_DEFAULT, &errbuf );*/
+ ldap_result_code = plugin_call_acl_plugin (pb, ec->ep_entry,
+ NULL /*attr*/, NULL /*value*/, SLAPI_ACL_WRITE,
+ ACLPLUGIN_ACCESS_MODRDN, &errbuf );
+ if ( ldap_result_code != LDAP_SUCCESS )
+ {
+ goto error_return;
+ }
+
+ slapi_entry_set_sdn( ec->ep_entry, &dn_newdn );
+
+ /* create it in the cache - prevents others from creating it */
+ if ( cache_add_tentative( &inst->inst_cache, ec, NULL ) != 0 ) {
+ /* somebody must've created it between dn2entry() and here */
+ /* JCMREPL - Hmm... we can't permit this to happen...? */
+ ldap_result_code= LDAP_ALREADY_EXISTS;
+ goto error_return;
+ }
+ ec_in_cache= 1;
+
+ /* Build the list of modifications required to the existing entry */
+ {
+ slapi_mods_init(&smods_generated,4);
+ slapi_mods_init(&smods_generated_wsi,4);
+ ldap_result_code = moddn_newrdn_mods(pb, slapi_sdn_get_ndn(&dn_olddn), ec, &smods_generated, &smods_generated_wsi,
+ is_replicated_operation);
+ if (ldap_result_code != LDAP_SUCCESS) {
+ if (ldap_result_code == LDAP_UNWILLING_TO_PERFORM)
+ ldap_result_message = "Modification of old rdn attribute type not allowed.";
+ goto error_return;
+ }
+ /*
+ * Remove the old entrydn index entry, and add the new one.
+ */
+ slapi_mods_add( &smods_generated, LDAP_MOD_DELETE, "entrydn", strlen(backentry_get_ndn(e)), backentry_get_ndn(e));
+ slapi_mods_add( &smods_generated, LDAP_MOD_REPLACE, "entrydn", strlen(backentry_get_ndn(ec)), backentry_get_ndn(ec));
+
+ /*
+ * Update parentid if we have a new superior.
+ */
+ if(slapi_sdn_get_dn(&dn_newsuperiordn)!=NULL) {
+ char buf[40]; /* Enough for an ID */
+
+ if (parententry != NULL) {
+ sprintf( buf, "%lu", (u_long)parententry->ep_id );
+ slapi_mods_add_string(&smods_generated, LDAP_MOD_DELETE, "parentid", buf);
+ }
+ if (newparententry != NULL) {
+ sprintf( buf, "%lu", (u_long)newparententry->ep_id );
+ slapi_mods_add_string(&smods_generated, LDAP_MOD_REPLACE, "parentid", buf);
+ }
+ }
+ }
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ slapi_mods_init_byref(&smods_operation_wsi,mods);
+
+ /*
+ * We are about to pass the last abandon test, so from now on we are
+ * committed to finish this operation. Set status to "will complete"
+ * before we make our last abandon check to avoid race conditions in
+ * the code that processes abandon operations.
+ */
+ if (operation) {
+ operation->o_status = SLAPI_OP_STATUS_WILL_COMPLETE;
+ }
+ if ( slapi_op_abandoned( pb ) ) {
+ goto error_return;
+ }
+
+ /*
+ * First, we apply the generated mods that do not involve any state information.
+ */
+ if ( entry_apply_mods( ec->ep_entry, slapi_mods_get_ldapmods_byref(&smods_generated) ) != 0 )
+ {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm_modrdn: entry_apply_mods failed for entry %s\n",
+ escape_string(slapi_entry_get_dn_const(ec->ep_entry), ebuf), 0, 0);
+ goto error_return;
+ }
+
+ /*
+ * Now we apply the generated mods that do involve state information.
+ */
+ if (slapi_mods_get_num_mods(&smods_generated_wsi)>0)
+ {
+ if (entry_apply_mods_wsi(ec->ep_entry, &smods_generated_wsi, operation_get_csn(operation), is_replicated_operation)!=0)
+ {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm_modrdn: entry_apply_mods_wsi failed for entry %s\n",
+ escape_string(slapi_entry_get_dn_const(ec->ep_entry), ebuf), 0, 0);
+ goto error_return;
+ }
+ }
+
+ /*
+ * Now we apply the operation mods that do involve state information.
+ * (Operational attributes).
+ * The following block looks redundent to the one above. But it may
+ * be necessary - check the comment for version 1.3.16.22.2.76 of
+ * this file and compare that version with its previous one.
+ */
+ if (slapi_mods_get_num_mods(&smods_operation_wsi)>0)
+ {
+ if (entry_apply_mods_wsi(ec->ep_entry, &smods_operation_wsi, operation_get_csn(operation), is_replicated_operation)!=0)
+ {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm_modrdn: entry_apply_mods_wsi (operational attributes) failed for entry %s\n",
+ escape_string(slapi_entry_get_dn_const(ec->ep_entry), ebuf), 0, 0);
+ goto error_return;
+ }
+ }
+ /* check that the entry still obeys the schema */
+ if ( slapi_entry_schema_check( pb, ec->ep_entry ) != 0 ) {
+ ldap_result_code = LDAP_OBJECT_CLASS_VIOLATION;
+ slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &ldap_result_message);
+ goto error_return;
+ }
+
+ /*
+ * Update the DN CSN of the entry.
+ */
+ entry_add_dncsn(ec->ep_entry,operation_get_csn(operation));
+ entry_add_rdn_csn(ec->ep_entry,operation_get_csn(operation));
+
+ /*
+ * If the entry has a new superior then the subordinate count
+ * of the parents must be updated.
+ */
+ if(slapi_sdn_get_dn(&dn_newsuperiordn)!=NULL)
+ {
+ /*
+ * Update the subordinate count of the parents to reflect the moved child.
+ */
+ if ( parententry!=NULL )
+ {
+ retval = parent_update_on_childchange(&parent_modify_context,2,NULL); /* 2==delete */
+ /* The parent modify context now contains info needed later */
+ if (0 != retval)
+ {
+ goto error_return;
+ }
+ }
+ if ( newparententry!=NULL )
+ {
+ retval = parent_update_on_childchange(&newparent_modify_context,1,NULL); /* 1==add */
+ /* The newparent modify context now contains info needed later */
+ if (0 != retval)
+ {
+ goto error_return;
+ }
+ }
+ }
+
+ /*
+ * If the entry has children then we're going to have to rename them all.
+ */
+ if (slapi_entry_has_children( e->ep_entry ))
+ {
+ /* JCM - This is where the subtree lock will appear */
+ children= moddn_get_children(&txn, pb, be, e, &dn_olddn, &child_entries, &child_entry_copies);
+ /* JCM - Shouldn't we perform an access control check on all the children. */
+ /* JCMREPL - But, the replication client has total rights over its subtree, so no access check needed. */
+ /* JCM - A subtree move could break ACIs, static groups, and dynamic groups. */
+ }
+
+ /*
+ * So, we believe that no code up till here actually added anything
+ * to persistent store. From now on, we're transacted
+ */
+ for (retry_count = 0; retry_count < RETRY_TIMES; retry_count++)
+ {
+ if (retry_count > 0)
+ {
+ dblayer_txn_abort(li,&txn);
+ /* We're re-trying */
+ LDAPDebug( LDAP_DEBUG_TRACE, "Modrdn Retrying Transaction\n", 0, 0, 0 );
+ }
+ retval = dblayer_txn_begin(li,parent_txn,&txn);
+ if (0 != retval) {
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ goto error_return;
+ }
+
+ /*
+ * Update the indexes for the entry.
+ */
+ retval = modrdn_rename_entry_update_indexes(&txn, pb, li, e, ec, &smods_generated, &smods_generated_wsi, &smods_operation_wsi);
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ continue;
+ }
+ if (retval != 0 )
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "modrdn_rename_entry_update_indexes failed, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ }
+
+ /*
+ * add new name to index
+ */
+ {
+ char **rdns;
+ int i;
+ if ( (rdns = ldap_explode_rdn( slapi_sdn_get_dn(&dn_newrdn), 0 )) != NULL )
+ {
+ for ( i = 0; rdns[i] != NULL; i++ )
+ {
+ char *type;
+ Slapi_Value *svp[2];
+ Slapi_Value sv;
+ memset(&sv,0,sizeof(Slapi_Value));
+ if ( slapi_rdn2typeval( rdns[i], &type, &sv.bv ) != 0 )
+ {
+ char ebuf[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY, "modrdn: rdn2typeval (%s) failed\n",
+ escape_string( rdns[i], ebuf ), 0, 0 );
+ goto error_return;
+ }
+ svp[0] = &sv;
+ svp[1] = NULL;
+ retval = index_addordel_values_sv( be, type, svp, NULL, ec->ep_id, BE_INDEX_ADD, &txn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ continue;
+ }
+ if (retval != 0 )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "modrdn: could not add new value to index, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ }
+ }
+ ldap_value_free( rdns );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ goto error_return;
+ }
+ }
+ }
+ if (slapi_sdn_get_dn(&dn_newsuperiordn)!=NULL)
+ {
+ /* Push out the db modifications from the parent entry */
+ retval = modify_update_all(be, pb, &parent_modify_context, &txn);
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "moddn: could not update parent, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ }
+ /* Push out the db modifications from the new parent entry */
+ if(retval==0)
+ {
+ retval = modify_update_all(be, pb, &newparent_modify_context, &txn);
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ continue;
+ }
+ if (0 != retval)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "moddn: could not update parent, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ }
+ }
+ }
+
+ /*
+ * Update ancestorid index.
+ */
+ if (slapi_sdn_get_dn(&dn_newsuperiordn)!=NULL) {
+ retval = ldbm_ancestorid_move_subtree(be, &dn_olddn, &dn_newdn, e->ep_id, children, &txn);
+ if (retval != 0) {
+ if (retval == DB_LOCK_DEADLOCK) continue;
+ if (retval == DB_RUNRECOVERY || LDBM_OS_ERR_IS_DISKFULL(retval))
+ disk_full = 1;
+ goto error_return;
+ }
+ }
+
+ /*
+ * If the entry has children, then rename them all.
+ */
+ if (children!=NULL)
+ {
+ retval= moddn_rename_children( &txn, pb, be, children, &dn_olddn, &dn_newdn, child_entries, child_entry_copies);
+ }
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ continue;
+ }
+ if (retval != 0)
+ {
+ if (retval == DB_RUNRECOVERY || LDBM_OS_ERR_IS_DISKFULL(retval))
+ disk_full = 1;
+ goto error_return;
+ }
+
+ break; /* retval==0, Done, Terminate the loop */
+ }
+ if (retry_count == RETRY_TIMES)
+ {
+ /* Failed */
+ LDAPDebug( LDAP_DEBUG_ANY, "Retry count exceeded in modrdn\n", 0, 0, 0 );
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ postentry = slapi_entry_dup( ec->ep_entry );
+
+ if(parententry!=NULL)
+ {
+ modify_switch_entries( &parent_modify_context,be);
+ }
+ if(newparententry!=NULL)
+ {
+ modify_switch_entries( &newparent_modify_context,be);
+ }
+
+ retval = dblayer_txn_commit(li,&txn);
+ if (0 != retval)
+ {
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) disk_full = 1;
+ ldap_result_code= LDAP_OPERATIONS_ERROR;
+ goto error_return;
+ }
+
+ if(children!=NULL)
+ {
+ int i=0;
+ for (; child_entries[i]!=NULL; i++) {
+ cache_unlock_entry( &inst->inst_cache, child_entries[i]) ;
+ cache_return( &inst->inst_cache, &(child_entries[i]) );
+ cache_return( &inst->inst_cache, &(child_entry_copies[i]) );
+ }
+ }
+
+ retval= 0;
+#if 0 /* this new entry in the cache can be used for future; don't remove it */
+ /* remove from cache so that memory can be freed by cache_return */
+ if (ec_in_cache) {
+ cache_remove(&inst->inst_cache, ec);
+ }
+#endif
+ goto common_return;
+
+error_return:
+ /* result already sent above - just free stuff */
+ if ( NULL != postentry )
+ {
+ slapi_entry_free( postentry );
+ postentry= NULL;
+ }
+ if( ec!=NULL ) {
+ if (ec_in_cache) {
+ cache_remove(&inst->inst_cache, ec);
+ } else {
+ backentry_free( &ec );
+ }
+ }
+ if(children!=NULL)
+ {
+ int i=0;
+ for(;child_entries[i]!=NULL;i++) {
+ cache_unlock_entry(&inst->inst_cache, child_entries[i]);
+ cache_return(&inst->inst_cache, &(child_entries[i]));
+ if (child_entry_copies[i] != NULL) {
+ cache_remove(&inst->inst_cache, child_entry_copies[i]);
+ cache_return( &inst->inst_cache, &(child_entry_copies[i]) );
+ }
+ }
+ }
+
+
+ if (retval == DB_RUNRECOVERY) {
+ dblayer_remember_disk_filled(li);
+ ldbm_nasty("ModifyDN",82,retval);
+ disk_full = 1;
+ }
+
+ if (disk_full)
+ {
+ retval = return_on_disk_full(li);
+ }
+ else
+ {
+ /* It is specifically OK to make this call even when no transaction was in progress */
+ dblayer_txn_abort(li,&txn); /* abort crashes in case disk full */
+ retval= SLAPI_FAIL_GENERAL;
+ }
+
+common_return:
+
+ /* Free up the resource we don't need any more */
+ if(ec_in_cache) {
+ cache_return( &inst->inst_cache, &ec );
+ }
+
+ /*
+ * The bepostop is called even if the operation fails.
+ */
+ plugin_call_plugins (pb, SLAPI_PLUGIN_BE_POST_MODRDN_FN);
+
+ if (ldap_result_code!=-1)
+ {
+ slapi_send_ldap_result( pb, ldap_result_code, ldap_result_matcheddn,
+ ldap_result_message, 0,NULL );
+ }
+ slapi_mods_done(&smods_operation_wsi);
+ slapi_mods_done(&smods_generated);
+ slapi_mods_done(&smods_generated_wsi);
+ moddn_unlock_and_return_entries(be,&e,&existingentry);
+ slapi_ch_free((void**)&child_entries);
+ slapi_ch_free((void**)&child_entry_copies);
+ slapi_ch_free((void**)&ldap_result_matcheddn);
+ idl_free(children);
+ slapi_sdn_done(&dn_olddn);
+ slapi_sdn_done(&dn_newdn);
+ slapi_sdn_done(&dn_newrdn);
+ slapi_sdn_done(&dn_newsuperiordn);
+ slapi_sdn_done(&dn_parentdn);
+ modify_term(&parent_modify_context,be);
+ modify_term(&newparent_modify_context,be);
+ done_with_pblock_entry(pb,SLAPI_MODRDN_EXISTING_ENTRY);
+ done_with_pblock_entry(pb,SLAPI_MODRDN_PARENT_ENTRY);
+ done_with_pblock_entry(pb,SLAPI_MODRDN_NEWPARENT_ENTRY);
+ done_with_pblock_entry(pb,SLAPI_MODRDN_TARGET_ENTRY);
+ if(dblock_acquired)
+ {
+ dblayer_unlock_backend(be);
+ }
+ slapi_ch_free((void**)&errbuf);
+ if (retval == 0 && opcsn != NULL && !is_fixup_operation)
+ {
+ slapi_pblock_set(pb, SLAPI_URP_NAMING_COLLISION_DN, slapi_ch_strdup (dn));
+ }
+ slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, postentry );
+ if (pb->pb_conn)
+ {
+ slapi_log_error (SLAPI_LOG_TRACE, "ldbm_back_modrdn", "leave conn=%d op=%d\n", pb->pb_conn->c_connid, operation->o_opid);
+ }
+ return retval;
+}
+
+/*
+ * Work out what the new DN of the entry will be.
+ */
+static const char *
+moddn_get_newdn(Slapi_PBlock *pb, Slapi_DN *dn_olddn, Slapi_DN *dn_newrdn, Slapi_DN *dn_newsuperiordn)
+{
+ char *newdn;
+ const char *newrdn= slapi_sdn_get_dn(dn_newrdn);
+ const char *newsuperiordn= slapi_sdn_get_dn(dn_newsuperiordn);
+
+ if( newsuperiordn!=NULL)
+ {
+ /* construct the new dn */
+ if(slapi_dn_isroot(newsuperiordn))
+ {
+ newdn= slapi_ch_strdup(newrdn);
+ }
+ else
+ {
+ newdn= slapi_dn_plus_rdn(newsuperiordn, newrdn); /* JCM - Use Slapi_RDN */
+ }
+ }
+ else
+ {
+ /* construct the new dn */
+ char *pdn;
+ const char *dn= slapi_sdn_get_dn(dn_olddn);
+ pdn = slapi_dn_beparent( pb, dn );
+ if ( pdn != NULL )
+ {
+ newdn= slapi_dn_plus_rdn(pdn, newrdn); /* JCM - Use Slapi_RDN */
+ }
+ else
+ {
+ newdn= slapi_ch_strdup(newrdn);
+ }
+ slapi_ch_free( (void**)&pdn );
+ }
+ return newdn;
+}
+
+/*
+ * Return the entries to the cache.
+ */
+static void
+moddn_unlock_and_return_entries(
+ backend *be,
+ struct backentry **targetentry,
+ struct backentry **existingentry)
+ {
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+
+ /* Something bad happened so we should give back all the entries */
+ if ( *targetentry!=NULL ) {
+ cache_unlock_entry(&inst->inst_cache, *targetentry);
+ cache_return( &inst->inst_cache, targetentry );
+ *targetentry= NULL;
+ }
+ if ( *existingentry!=NULL ) {
+ cache_return( &inst->inst_cache, existingentry );
+ *existingentry= NULL;
+ }
+ }
+
+
+/*
+ * JCM - There was a problem with multi-valued RDNs where
+ * JCM - there was an intersection of the two sets RDN Components
+ * JCM - and the deleteoldrdn flag was set. A value was deleted
+ * JCM - but not re-added because the value is found to already
+ * JCM - exist.
+ *
+ * This function returns 1 if it is necessary to add an RDN value
+ * to the entry. This is necessary if either:
+ * 1 the attribute or the value is not present in the entry, or
+ * 2 the attribute is present, deleteoldrdn is set, and the RDN value
+ * is in the deleted list.
+ *
+ * For example, suppose you rename cn=a to cn=a+sn=b. The cn=a value
+ * is removed from the entry and then readded.
+ */
+
+static int
+moddn_rdn_add_needed (
+ struct backentry *ec,
+ char *type,
+ struct berval *bvp,
+ int deleteoldrdn,
+ Slapi_Mods *smods_wsi
+)
+{
+ Slapi_Attr *attr;
+ LDAPMod *mod;
+
+ if (slapi_entry_attr_find(ec->ep_entry, type, &attr) != 0 ||
+ slapi_attr_value_find( attr, bvp ) != 0 )
+ {
+ return 1;
+ }
+
+ if (deleteoldrdn == 0) return 0;
+
+ /* in a multi-valued RDN, the RDN value might have been already
+ * put on the smods_wsi list to be deleted, yet might still be
+ * in the target RDN.
+ */
+
+ for (mod = slapi_mods_get_first_mod(smods_wsi);
+ mod != NULL;
+ mod = slapi_mods_get_next_mod(smods_wsi)) {
+ if (((mod->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) &&
+ (strcasecmp(mod->mod_type, type) == 0) &&
+ (mod->mod_bvalues != NULL) &&
+ (slapi_attr_value_cmp(attr, *mod->mod_bvalues, bvp) == 0)) {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Build the list of modifications to apply to the Existing Entry
+ * With State Information:
+ * - delete old rdn values from the entry if deleteoldrdn is set
+ * - add new rdn values to the entry
+ * Without State Information
+ * - No changes
+ */
+static int
+moddn_newrdn_mods(Slapi_PBlock *pb, const char *olddn, struct backentry *ec, Slapi_Mods *smods, Slapi_Mods *smods_wsi, int is_repl_op)
+{
+ char ebuf[BUFSIZ];
+ char **rdns = NULL;
+ char **dns = NULL;
+ int deleteoldrdn;
+ char *type = NULL;
+ char *dn = NULL;
+ char *newrdn = NULL;
+ int i;
+ struct berval *bvps[2];
+ struct berval bv;
+
+ bvps[0] = &bv;
+ bvps[1] = NULL;
+
+ /* slapi_pblock_get( pb, SLAPI_MODRDN_TARGET, &dn ); */
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn );
+ slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &deleteoldrdn );
+
+
+ /*
+ * This loop removes the old RDN of the existing entry.
+ */
+ if (deleteoldrdn) {
+ int baddn = 0; /* set to true if could not parse dn */
+ int badrdn = 0; /* set to true if could not parse rdn */
+ dn = slapi_ch_strdup(olddn);
+ dns = ldap_explode_dn( dn, 0 );
+ if ( dns != NULL )
+ {
+ rdns = ldap_explode_rdn( dns[0], 0 );
+ if ( rdns != NULL )
+ {
+ for ( i = 0; rdns[i] != NULL; i++ )
+ {
+ /* delete from entry attributes */
+ if ( deleteoldrdn && slapi_rdn2typeval( rdns[i], &type, &bv ) == 0 )
+ {
+ /* check if user is allowed to modify the specified attribute */
+ /*
+ * It would be better to do this check in the front end
+ * end inside op_shared_rename(), but unfortunately we
+ * don't have access to the target entry there.
+ */
+ if (!op_shared_is_allowed_attr (type, is_repl_op))
+ {
+ ldap_value_free( rdns );
+ ldap_value_free( dns );
+ slapi_ch_free_string(&dn);
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ if (strcasecmp (type, SLAPI_ATTR_UNIQUEID) != 0)
+ slapi_mods_add_modbvps( smods_wsi, LDAP_MOD_DELETE, type, bvps );
+ }
+ }
+ ldap_value_free( rdns );
+ }
+ else
+ {
+ badrdn = 1;
+ }
+ ldap_value_free( dns );
+ }
+ else
+ {
+ baddn = 1;
+ }
+ slapi_ch_free_string(&dn);
+
+ if ( baddn || badrdn )
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "moddn_newrdn_mods failed: olddn=%s baddn=%d badrdn=%d\n",
+ escape_string(olddn, ebuf), baddn, badrdn);
+ return LDAP_OPERATIONS_ERROR;
+ }
+ }
+ /*
+ * add new RDN values to the entry (non-normalized)
+ */
+ rdns = ldap_explode_rdn( newrdn, 0 );
+ if ( rdns != NULL )
+ {
+ for ( i = 0; rdns[i] != NULL; i++ )
+ {
+ if ( slapi_rdn2typeval( rdns[i], &type, &bv ) != 0) {
+ continue;
+ }
+
+ /* add to entry if it's not already there or if was
+ * already deleted
+ */
+ if (moddn_rdn_add_needed(ec, type, &bv,
+ deleteoldrdn,
+ smods_wsi) == 1) {
+ slapi_mods_add_modbvps( smods_wsi, LDAP_MOD_ADD, type, bvps );
+ }
+ }
+ ldap_value_free( rdns );
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "moddn_newrdn_mods failed: could not parse new rdn %s\n",
+ escape_string(newrdn, ebuf), 0, 0);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+static void
+mods_remove_nsuniqueid(Slapi_Mods *smods)
+{
+ int i;
+
+ LDAPMod **mods = slapi_mods_get_ldapmods_byref(smods);
+ for ( i = 0; mods[i] != NULL; i++ ) {
+ if (!strcasecmp(mods[i]->mod_type, SLAPI_ATTR_UNIQUEID)) {
+ mods[i]->mod_op = LDAP_MOD_IGNORE;
+ }
+ }
+}
+
+
+/*
+ * Update the indexes to reflect the DN change made.
+ * e is the entry before, ec the entry after.
+ * mods contains the list of attribute change made.
+ */
+static int
+modrdn_rename_entry_update_indexes(back_txn *ptxn, Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *e, struct backentry *ec, Slapi_Mods *smods1, Slapi_Mods *smods2, Slapi_Mods *smods3)
+{
+ backend *be;
+ ldbm_instance *inst;
+ int retval= 0;
+ char *msg;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be);
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ /*
+ * Update the ID to Entry index.
+ * Note that id2entry_add replaces the entry, so the Entry ID stays the same.
+ */
+ retval = id2entry_add( be, ec, ptxn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ goto error_return;
+ }
+ if (retval != 0)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "id2entry_add failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ goto error_return;
+ }
+ if(smods1!=NULL && slapi_mods_get_num_mods(smods1)>0)
+ {
+ /*
+ * update the indexes: lastmod, rdn, etc.
+ */
+ retval = index_add_mods( be, (const LDAPMod **)slapi_mods_get_ldapmods_byref(smods1), e, ec, ptxn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ goto error_return;
+ }
+ if (retval != 0)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "index_add_mods 1 failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ goto error_return;
+ }
+ }
+ if(smods2!=NULL && slapi_mods_get_num_mods(smods2)>0)
+ {
+ /*
+ * smods2 contains the state generated mods. One of them might be the removal of a "nsuniqueid" rdn component
+ * previously gnerated through a conflict resolution. We need to make sure we don't remove the index for "nsuniqueid"
+ * so let's get it out from the mods before calling index_add_mods...
+ */
+ mods_remove_nsuniqueid(smods2);
+ /*
+ * update the indexes: lastmod, rdn, etc.
+ */
+ retval = index_add_mods( be, (const LDAPMod **)slapi_mods_get_ldapmods_byref(smods2), e, ec, ptxn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ goto error_return;
+ }
+ if (retval != 0)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "index_add_mods 2 failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ goto error_return;
+ }
+ }
+ if(smods3!=NULL && slapi_mods_get_num_mods(smods3)>0)
+ {
+ /*
+ * update the indexes: lastmod, rdn, etc.
+ */
+ retval = index_add_mods( be, (const LDAPMod **)slapi_mods_get_ldapmods_byref(smods3), e, ec, ptxn );
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Retry txn */
+ goto error_return;
+ }
+ if (retval != 0)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "index_add_mods 3 failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ goto error_return;
+ }
+ }
+ /*
+ * Remove the old entry from the Virtual List View indexes.
+ * Add the new entry to the Virtual List View indexes.
+ */
+ retval= vlv_update_all_indexes(ptxn, be, pb, e, ec);
+ if (DB_LOCK_DEADLOCK == retval)
+ {
+ /* Abort and re-try */
+ goto error_return;
+ }
+ if (retval != 0)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "vlv_update_all_indexes failed, err=%d %s\n", retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ goto error_return;
+ }
+ if (cache_replace( &inst->inst_cache, e, ec ) != 0 ) {
+ retval= -1;
+ goto error_return;
+ }
+error_return:
+ return retval;
+}
+
+
+/*
+ */
+static int
+moddn_rename_child_entry(
+ back_txn *ptxn,
+ Slapi_PBlock *pb,
+ struct ldbminfo *li,
+ struct backentry *e,
+ struct backentry *ec,
+ int parentdncomps,
+ char **newsuperiordns,
+ int newsuperiordncomps,
+ CSN *opcsn)
+{
+ /*
+ * Construct the new DN for the entry by taking the old DN
+ * excluding the old parent entry DN, and adding the new
+ * superior entry DN.
+ *
+ * ldap_explode_dn is probably a bit slow, but it knows about
+ * DN escaping which is pretty complicated, and we wouldn't
+ * want to reimplement that here.
+ *
+ * JCM - This was written before Slapi_RDN... so this could be made much neater.
+ */
+ int retval;
+ char *olddn;
+ char *newdn;
+ char **olddns;
+ int olddncomps= 0;
+ int need= 1; /* For the '\0' */
+ int i;
+
+ olddn = slapi_entry_get_dn(ec->ep_entry);
+ olddns = ldap_explode_dn( olddn, 0 );
+ for(;olddns[olddncomps]!=NULL;olddncomps++);
+ for(i=0;i<olddncomps-parentdncomps;i++)
+ {
+ need+= strlen(olddns[i]) + 2; /* For the ", " */
+ }
+ for(i=0;i<newsuperiordncomps;i++)
+ {
+ need+= strlen(newsuperiordns[i]) + 2; /* For the ", " */
+ }
+ need--; /* We don't have a comma on the end of the last component */
+ newdn= slapi_ch_malloc(need);
+ newdn[0]= '\0';
+ for(i=0;i<olddncomps-parentdncomps;i++)
+ {
+ strcat(newdn,olddns[i]);
+ strcat(newdn,", ");
+ }
+ for(i=0;i<newsuperiordncomps;i++)
+ {
+ strcat(newdn,newsuperiordns[i]);
+ if(i<newsuperiordncomps-1)
+ {
+ /* We don't have a comma on the end of the last component */
+ strcat(newdn,", ");
+ }
+ }
+ ldap_value_free( olddns );
+ slapi_entry_set_dn( ec->ep_entry, newdn );
+ add_update_entrydn_operational_attributes (ec);
+
+ /*
+ * Update the DN CSN of the entry.
+ */
+ {
+ entry_add_dncsn(e->ep_entry, opcsn);
+ entry_add_rdn_csn(e->ep_entry, opcsn);
+ entry_set_maxcsn(e->ep_entry, opcsn);
+ }
+ {
+ Slapi_Mods smods;
+ slapi_mods_init(&smods, 2);
+ slapi_mods_add( &smods, LDAP_MOD_DELETE, "entrydn", strlen( backentry_get_ndn(e) ), backentry_get_ndn(e) );
+ slapi_mods_add( &smods, LDAP_MOD_REPLACE, "entrydn", strlen( backentry_get_ndn(ec) ), backentry_get_ndn(ec) );
+ /*
+ * Update all the indexes.
+ */
+ retval= modrdn_rename_entry_update_indexes(ptxn, pb, li, e, ec, &smods, NULL, NULL); /* JCMREPL - Should the children get updated modifiersname and lastmodifiedtime? */
+ slapi_mods_done(&smods);
+ }
+ return retval;
+}
+
+/*
+ * Rename all the children of an entry who's name has changed.
+ */
+static int
+moddn_rename_children(
+ back_txn *ptxn,
+ Slapi_PBlock *pb,
+ backend *be,
+ IDList *children,
+ Slapi_DN *dn_parentdn,
+ Slapi_DN *dn_newsuperiordn,
+ struct backentry *child_entries[],
+ struct backentry *child_entry_copies[])
+{
+ /* Iterate over the children list renaming every child */
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ Slapi_Operation *operation;
+ CSN *opcsn;
+ int retval= 0, i;
+ char **newsuperiordns;
+ int newsuperiordncomps= 0;
+ int parentdncomps= 0;
+
+ /*
+ * Break down the parent entry dn into its components.
+ */
+ {
+ char **parentdns;
+ parentdns = ldap_explode_dn( slapi_sdn_get_dn(dn_parentdn), 0 );
+ for(;parentdns[parentdncomps]!=NULL;parentdncomps++);
+ ldap_value_free( parentdns );
+ }
+
+ /*
+ * Break down the new superior entry dn into its components.
+ */
+ newsuperiordns = ldap_explode_dn( slapi_sdn_get_dn(dn_newsuperiordn), 0 );
+ for(;newsuperiordns[newsuperiordncomps]!=NULL;newsuperiordncomps++);
+
+ /*
+ * Iterate over the child entries renaming them.
+ */
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation );
+ opcsn = operation_get_csn (operation);
+ for (i = 0; retval == 0 && child_entries[i] != NULL; i++) {
+ retval= moddn_rename_child_entry(ptxn, pb, li, child_entries[i], child_entry_copies[i], parentdncomps, newsuperiordns, newsuperiordncomps, opcsn );
+ }
+ if (retval != 0) {
+ while (child_entries[i] != NULL) {
+ backentry_free(&(child_entry_copies[i]));
+ i++;
+ }
+ }
+ ldap_value_free( newsuperiordns );
+ return retval;
+}
+
+
+/*
+ * Get an IDList of all the children of an entry.
+ */
+static IDList *
+moddn_get_children(back_txn *ptxn, Slapi_PBlock *pb, backend *be, struct backentry *parententry, Slapi_DN *dn_parentdn, struct backentry ***child_entries, struct backentry ***child_entry_copies)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ int err= 0;
+ IDList *candidates;
+ IDList *result_idl = NULL;
+ char filterstr[20];
+ Slapi_Filter *filter;
+ NIDS nids;
+ int entrynumber= 0;
+ ID id;
+ idl_iterator sr_current; /* the current position in the search results */
+ struct backentry *e= NULL;
+
+ /* Fetch a candidate list of all the entries below the entry being moved */
+ strcpy( filterstr, "objectclass=*" );
+ filter = slapi_str2filter( filterstr );
+ candidates= subtree_candidates(pb, be, slapi_sdn_get_ndn(dn_parentdn), parententry, filter, 1 /* ManageDSAIT */, NULL /* allids_before_scopingp */, &err);
+ slapi_filter_free(filter,1);
+
+ if (candidates!=NULL)
+ {
+ sr_current = idl_iterator_init(candidates);
+ result_idl= idl_alloc(candidates->b_nids);
+ do
+ {
+ id = idl_iterator_dereference_increment(&sr_current, candidates);
+ if ( id!=NOID )
+ {
+ int err= 0;
+ e = id2entry( be, id, NULL, &err );
+ if (e!=NULL)
+ {
+ /* The subtree search will have included the parent entry in the result set */
+ if (e!=parententry)
+ {
+ /* Check that the candidate entry is really below the base. */
+ if(slapi_dn_issuffix( backentry_get_ndn(e), slapi_sdn_get_ndn(dn_parentdn)))
+ {
+ idl_append(result_idl,id);
+ }
+ }
+ cache_return(&inst->inst_cache, &e);
+ }
+ }
+ } while (id!=NOID);
+ idl_free(candidates);
+ }
+
+ nids = result_idl ? result_idl->b_nids : 0;
+
+ *child_entries= (struct backentry**)slapi_ch_calloc(sizeof(struct backentry*),nids+1);
+ *child_entry_copies= (struct backentry**)slapi_ch_calloc(sizeof(struct backentry*),nids+1);
+
+ sr_current = idl_iterator_init(result_idl);
+ do {
+ id = idl_iterator_dereference_increment(&sr_current, result_idl);
+ if ( id!=NOID ) {
+ e= cache_find_id( &inst->inst_cache, id );
+ if ( e != NULL ) {
+ cache_lock_entry(&inst->inst_cache, e);
+ (*child_entries)[entrynumber]= e;
+ (*child_entry_copies)[entrynumber]= backentry_dup(e);
+ entrynumber++;
+ }
+ }
+ } while (id!=NOID);
+
+ return result_idl;
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
new file mode 100644
index 00000000..ee33011d
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -0,0 +1,1345 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* search.c - ldbm backend search function */
+/* view with ts=4 */
+
+#include "back-ldbm.h"
+#include "vlv_srch.h"
+
+/* prototypes */
+static int build_candidate_list( Slapi_PBlock *pb, backend *be,
+ struct backentry *e, const char * base, int scope,
+ int *lookup_returned_allidsp, IDList** candidates);
+static IDList *base_candidates( Slapi_PBlock *pb, struct backentry *e );
+static IDList *onelevel_candidates( Slapi_PBlock *pb, backend *be, const char *base, struct backentry *e, Slapi_Filter *filter, int managedsait, int *lookup_returned_allidsp, int *err );
+static back_search_result_set* new_search_result_set(IDList* idl,int vlv, int lookthroughlimit);
+static void delete_search_result_set( back_search_result_set **sr );
+static int can_skip_filter_test( Slapi_PBlock *pb, struct slapi_filter *f,
+ int scope, IDList *idl );
+
+/* This is for performance testing, allows us to disable ACL checking altogether */
+#if defined(DISABLE_ACL_CHECK)
+#define ACL_CHECK_FLAG 0
+#else
+#define ACL_CHECK_FLAG 1
+#endif
+
+#define ISLEGACY(be) (be?(be->be_instance_info?(((ldbm_instance *)be->be_instance_info)->inst_li?(((ldbm_instance *)be->be_instance_info)->inst_li->li_legacy_errcode):0):0):0)
+
+static int
+compute_lookthrough_limit( Slapi_PBlock *pb, struct ldbminfo *li )
+{
+ Slapi_Connection *conn = NULL;
+ int limit;
+
+ slapi_pblock_get( pb, SLAPI_CONNECTION, &conn);
+
+ if ( slapi_reslimit_get_integer_limit( conn,
+ li->li_reslimit_lookthrough_handle, &limit )
+ != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ /*
+ * no limit associated with binder/connection or some other error
+ * occurred. use the default.
+ */
+ int isroot = 0;
+
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ if (isroot) {
+ limit = -1;
+ } else {
+ PR_Lock(li->li_config_mutex);
+ limit = li->li_lookthroughlimit;
+ PR_Unlock(li->li_config_mutex);
+ }
+ }
+
+ return( limit );
+}
+
+/* don't free the berval, just clean it */
+static void
+berval_done(struct berval *val)
+{
+ slapi_ch_free_string(&val->bv_val);
+}
+
+/*
+ * We call this function as we exit ldbm_back_search
+ */
+int ldbm_back_search_cleanup(Slapi_PBlock *pb, struct ldbminfo *li, sort_spec_thing *sort_control, int ldap_result, char* ldap_result_description, int function_result, Slapi_DN *sdn, struct vlv_request *vlv_request_control)
+{
+ if(sort_control!=NULL)
+ {
+ sort_spec_free(sort_control);
+ }
+ if(ldap_result>=LDAP_SUCCESS)
+ {
+ slapi_send_ldap_result( pb, ldap_result, NULL, ldap_result_description, 0, NULL );
+ }
+ {
+ /* hack hack --- code to free the result set if we don't need it */
+ /* We get it and check to see if the structure was ever used */
+ back_search_result_set *sr = NULL;
+ slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &sr );
+ if ( (NULL != sr) && (function_result != 0) ) {
+ delete_search_result_set(&sr);
+ }
+ }
+ slapi_sdn_done(sdn);
+ if (vlv_request_control)
+ {
+ berval_done(&vlv_request_control->value);
+ }
+ return function_result;
+}
+
+/*
+ * Return values from ldbm_back_search are:
+ *
+ * 0: Success. A result set is in the pblock. No results have been
+ * sent to the client.
+ * 1: Success. The result has already been sent to the client.
+ * -1: An error occurred, and results have been sent to the client.
+ * -2: Disk Full. Abandon ship!
+ */
+int
+ldbm_back_search( Slapi_PBlock *pb )
+{
+ /* Search stuff */
+ backend *be;
+ ldbm_instance *inst;
+ struct ldbminfo *li;
+ struct backentry *e;
+ IDList *candidates= NULL;
+ char *base;
+ Slapi_DN basesdn;
+ int scope;
+ LDAPControl **controls = NULL;
+ Slapi_Operation *operation;
+ entry_address *addr;
+
+ /* SORT control stuff */
+ int sort = 0;
+ int vlv = 0;
+ struct berval *sort_spec = NULL;
+ int is_sorting_critical = 0;
+ int is_sorting_critical_orig = 0;
+ sort_spec_thing *sort_control = NULL;
+
+ /* VLV control stuff */
+ int virtual_list_view = 0;
+ struct berval *vlv_spec = NULL;
+ int is_vlv_critical = 0;
+ struct vlv_request vlv_request_control;
+ back_search_result_set *sr = NULL;
+
+ /* Fix for bugid #394184, SD, 20 Jul 00 */
+ int tmp_err = -1; /* must be lower than LDAP_SUCCESS */
+ char * tmp_desc = NULL;
+ /* end Fix for defect #394184 */
+
+ int lookup_returned_allids = 0;
+ int backend_count = 1;
+ static int print_once = 1;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base );
+ slapi_pblock_get( pb, SLAPI_TARGET_ADDRESS, &addr);
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
+ slapi_pblock_get( pb, SLAPI_REQCONTROLS, &controls );
+ slapi_pblock_get( pb, SLAPI_BACKEND_COUNT, &backend_count );
+
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ slapi_sdn_init_dn_ndn_byref(&basesdn,base); /* normalized by front end*/
+ /* Initialize the result set structure here because we need to use it during search processing */
+ /* Beware that if we exit this routine sideways, we might leak this structure */
+ sr = new_search_result_set( NULL, 0,
+ compute_lookthrough_limit( pb, li ));
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_SET, sr );
+
+ /* clear this out so we can free it later */
+ memset(&vlv_request_control, 0, sizeof(vlv_request_control));
+ if ( NULL != controls )
+ {
+ /* Are we being asked to sort the results ? */
+ sort = slapi_control_present( controls, LDAP_CONTROL_SORTREQUEST, &sort_spec, &is_sorting_critical_orig );
+ if(sort)
+ {
+ int r= parse_sort_spec(sort_spec, &sort_control);
+ if(r!=0)
+ {
+ /* Badly formed SORT control */
+ return ldbm_back_search_cleanup(pb, li, sort_control, LDAP_PROTOCOL_ERROR, "Sort Control", SLAPI_FAIL_GENERAL, &basesdn, NULL);
+ }
+ }
+ is_sorting_critical = is_sorting_critical_orig;
+
+ /* Are we to provide a virtual view of the list? */
+ if ((vlv = slapi_control_present( controls, LDAP_CONTROL_VLVREQUEST, &vlv_spec, &is_vlv_critical)))
+ {
+ if(sort)
+ {
+ int r = vlv_parse_request_control( be, vlv_spec, &vlv_request_control );
+ if(r!=LDAP_SUCCESS)
+ {
+ /* Badly formed VLV control */
+ return ldbm_back_search_cleanup(pb, li, sort_control, r, "VLV Control", SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
+ }
+ {
+ /* Access Control Check to see if the client is allowed to use the VLV Control. */
+ Slapi_Entry *feature;
+ char dn[128];
+ char *dummyAttr = "dummy#attr";
+ char *dummyAttrs[2] = { NULL, NULL };
+
+ dummyAttrs[0] = dummyAttr;
+
+ sprintf(dn,"dn: oid=%s,cn=features,cn=config",LDAP_CONTROL_VLVREQUEST);
+ feature= slapi_str2entry(dn,0);
+ r= plugin_call_acl_plugin (pb, feature, dummyAttrs, NULL, SLAPI_ACL_READ, ACLPLUGIN_ACCESS_DEFAULT, NULL);
+ slapi_entry_free(feature);
+ if(r!=LDAP_SUCCESS)
+ {
+ /* Client isn't allowed to do this. */
+ return ldbm_back_search_cleanup(pb, li, sort_control, r, "VLV Control", SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
+ }
+ }
+ /*
+ * Sorting must always be critical for VLV; Force it be so.
+ */
+ is_sorting_critical= 1;
+ virtual_list_view= 1;
+ }
+ else
+ {
+ /* Can't have a VLV control without a SORT control */
+ return ldbm_back_search_cleanup(pb, li, sort_control, LDAP_SORT_CONTROL_MISSING, "VLV Control", SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
+ }
+ }
+ }
+ if ((virtual_list_view || sort) && backend_count > 0)
+ {
+ char *ctrlstr = NULL;
+ struct vlv_response vlv_response = {0};
+ if (virtual_list_view)
+ {
+ if (sort)
+ {
+ ctrlstr = "The VLV and sort controls cannot be processed";
+ }
+ else
+ {
+ ctrlstr = "The VLV control cannot be processed";
+ }
+ }
+ else
+ {
+ if (sort)
+ {
+ ctrlstr = "The sort control cannot be processed";
+ }
+ }
+
+ PR_ASSERT(NULL != ctrlstr);
+
+ if (print_once)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: %s "
+ "when more than one backend is involved. "
+ "VLV indexes that will never be used should be removed.\n",
+ ctrlstr, 0, 0);
+ print_once = 0;
+ }
+
+ /* 402380: mapping tree must refuse VLV and SORT control
+ * when several backends are impacted by a search */
+ if (0 != is_vlv_critical)
+ {
+ vlv_response.result = LDAP_UNWILLING_TO_PERFORM;
+ vlv_make_response_control(pb, &vlv_response);
+ if (sort)
+ {
+ make_sort_response_control(pb, LDAP_UNWILLING_TO_PERFORM, NULL);
+ }
+ if (ISLEGACY(be))
+ {
+ return ldbm_back_search_cleanup(pb, li, sort_control,
+ LDAP_UNWILLING_TO_PERFORM, ctrlstr,
+ SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
+ }
+ else
+ {
+ return ldbm_back_search_cleanup(pb, li, sort_control,
+ LDAP_VIRTUAL_LIST_VIEW_ERROR, ctrlstr,
+ SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
+ }
+ }
+ else
+ {
+ if (0 != is_sorting_critical_orig)
+ {
+ if (virtual_list_view)
+ {
+ vlv_response.result = LDAP_UNWILLING_TO_PERFORM;
+ vlv_make_response_control(pb, &vlv_response);
+ }
+ make_sort_response_control(pb, LDAP_UNWILLING_TO_PERFORM, NULL);
+ return ldbm_back_search_cleanup(pb, li, sort_control,
+ LDAP_UNAVAILABLE_CRITICAL_EXTENSION, ctrlstr,
+ SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
+ }
+ else /* vlv and sorting are not critical, so ignore the control */
+ {
+ if (virtual_list_view)
+ {
+ vlv_response.result = LDAP_UNWILLING_TO_PERFORM;
+ vlv_make_response_control(pb, &vlv_response);
+ }
+ if (sort)
+ {
+ make_sort_response_control(pb, LDAP_UNWILLING_TO_PERFORM, NULL);
+ }
+ sort = 0;
+ virtual_list_view = 0;
+ }
+ }
+ }
+
+ /*
+ * Get the base object for the search.
+ * The entry "" will never be contained in the database,
+ * so treat it as a special case.
+ */
+ if ( *base == '\0' )
+ {
+ e = NULL;
+ }
+ else
+ {
+ if ( ( e = find_entry( pb, be, addr, NULL )) == NULL )
+ {
+ /* error or referral sent by find_entry */
+ return ldbm_back_search_cleanup(pb, li, sort_control, -1, NULL, 1, &basesdn, &vlv_request_control);
+ }
+ }
+
+ /*
+ * If this is a persistent search then the client is only
+ * interested in entries that change, so we skip building
+ * a candidate list.
+ */
+ if (operation_is_flag_set( operation, OP_FLAG_PS_CHANGESONLY ))
+ {
+ candidates = NULL;
+ }
+ else
+ {
+ time_t time_up= 0;
+ int lookthrough_limit = 0;
+ struct vlv_response vlv_response_control;
+ int abandoned= 0;
+ int vlv_rc;
+ /*
+ * Build a list of IDs for this entry and scope
+ */
+ if ((NULL != controls) && (sort)) {
+ switch (vlv_search_build_candidate_list(pb, &basesdn, &vlv_rc, sort_control, (vlv ? &vlv_request_control : NULL), &candidates, &vlv_response_control)) {
+ case VLV_ACCESS_DENIED:
+ return ldbm_back_search_cleanup(pb, li, sort_control, vlv_rc, "VLV Control", SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
+
+ case VLV_BLD_LIST_FAILED:
+ return ldbm_back_search_cleanup(pb, li, sort_control, vlv_response_control.result, NULL, SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
+
+ case LDAP_SUCCESS:
+ /* Log to the access log the particulars of this sort request */
+ /* Log message looks like this: SORT <key list useful for input to ldapsearch> <#candidates> | <unsortable> */
+ sort_log_access(pb,sort_control,NULL);
+ /* Since a pre-computed index was found for the VLV Search then
+ * the candidate list now contains exactly what should be returned.
+ * There's no need to sort or trim the candidate list.
+ *
+ * However, the client will be expecting a Sort Response control
+ */
+ if (LDAP_SUCCESS != make_sort_response_control( pb, 0, NULL ) )
+ {
+ return ldbm_back_search_cleanup(pb, li, sort_control, LDAP_OPERATIONS_ERROR, "Sort Response Control", SLAPI_FAIL_GENERAL, &basesdn, &vlv_request_control);
+ }
+ }
+ }
+ if(candidates==NULL)
+ {
+ int rc = build_candidate_list(pb, be, e, base, scope,
+ &lookup_returned_allids, &candidates);
+ if (rc)
+ {
+ /* Error result sent by build_candidate_list */
+ return ldbm_back_search_cleanup(pb, li, sort_control, -1, NULL, rc, &basesdn, &vlv_request_control);
+ }
+ /*
+ * If we're sorting then we must check what administrative
+ * limits should be imposed. Work out at what time to give
+ * up, and how many entries we should sift through.
+ */
+ if (sort && (NULL != candidates))
+ {
+ time_t optime = 0;
+ time_t tlimit = 0;
+
+ slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &tlimit );
+ slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
+ /*
+ * (tlimit==-1) means no time limit
+ */
+ time_up = ( tlimit==-1 ? -1 : optime + tlimit);
+
+ lookthrough_limit = compute_lookthrough_limit( pb, li );
+ }
+
+ /*
+ * If we're presenting a virtual list view, then apply the
+ * search filter before sorting.
+ */
+ if (virtual_list_view && (NULL != candidates))
+ {
+ int r= 0;
+ IDList *idl= NULL;
+ Slapi_Filter *filter= NULL;
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
+ r= vlv_filter_candidates(be, pb, candidates, &basesdn, scope, filter, &idl, lookthrough_limit, time_up);
+ if(r==0)
+ {
+ idl_free(candidates);
+ candidates= idl;
+ }
+ else
+ {
+ return ldbm_back_search_cleanup(pb, li, sort_control, r, NULL, -1, &basesdn, &vlv_request_control);
+ }
+ }
+ /*
+ * Client wants the server to sort the results.
+ */
+ if (sort && (NULL != candidates))
+ {
+ /* Before we haste off to sort the candidates, we need to
+ * prepare some information for the purpose of imposing the
+ * administrative limits.
+ * We figure out the time when the time limit will be up.
+ * We can't use the size limit because we might be sorting
+ * a candidate list larger than the result set.
+ * But, we can use the lookthrough limit---we count each
+ * time we access an entry as one look and act accordingly.
+ */
+
+ char *sort_error_type = NULL;
+ int sort_return_value = 0;
+
+ /* Log to the access log the particulars of this sort request */
+ /* Log message looks like this: SORT <key list useful for input to ldapsearch> <#candidates> | <unsortable> */
+ sort_log_access(pb,sort_control,candidates);
+ sort_return_value = sort_candidates( be, lookthrough_limit, time_up, pb, candidates, sort_control, &sort_error_type );
+ /* Fix for bugid # 394184, SD, 20 Jul 00 */
+ /* replace the hard coded return value by the appropriate LDAP error code */
+ switch (sort_return_value) {
+ case LDAP_SUCCESS: /* Everything OK */
+ vlv_response_control.result= LDAP_SUCCESS;
+ break;
+ case LDAP_PROTOCOL_ERROR: /* A protocol error */
+ return ldbm_back_search_cleanup(pb, li, sort_control, LDAP_PROTOCOL_ERROR, "Sort Control", -1, &basesdn, &vlv_request_control);
+ case LDAP_UNWILLING_TO_PERFORM: /* Too hard */
+ case LDAP_OPERATIONS_ERROR: /* Operation error */
+ case LDAP_TIMELIMIT_EXCEEDED: /* Timeout */
+ vlv_response_control.result= LDAP_TIMELIMIT_EXCEEDED;
+ break;
+ case LDAP_ADMINLIMIT_EXCEEDED: /* Admin limit exceeded */
+ vlv_response_control.result= LDAP_ADMINLIMIT_EXCEEDED;
+ break;
+ case LDAP_OTHER: /* Abandoned */
+ abandoned= 1; /* So that we don't return a result code */
+ is_sorting_critical= 1; /* In order to have the results discarded */
+ break;
+ default: /* Should never get here */
+ break;
+ }
+ /* End fix for bug # 394184 */
+ /*
+ * If the sort control was marked as critical, and there was an error in sorting,
+ * don't return any entries, and return unavailableCriticalExtension in the
+ * searchResultDone message.
+ */
+ /* Fix for bugid #394184, SD, 05 Jul 00 */
+ /* we were not actually returning unavailableCriticalExtension;
+ now fixed (hopefully !) */
+ if (is_sorting_critical && (0 != sort_return_value))
+ {
+ idl_free(candidates);
+ candidates = idl_alloc(0);
+ tmp_err = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ tmp_desc = "Sort Response Control";
+ }
+ /* end Fix for bugid #394184 */
+ /* Generate the control returned to the client to indicate sort result */
+ if (LDAP_SUCCESS != make_sort_response_control( pb, sort_return_value, sort_error_type ) )
+ {
+ return ldbm_back_search_cleanup(pb, li, sort_control, (abandoned?-1:LDAP_PROTOCOL_ERROR), "Sort Response Control", -1, &basesdn, &vlv_request_control);
+ }
+ }
+ /*
+ * If we're presenting a virtual list view, then the candidate list
+ * must be trimmed down to just the range of entries requested.
+ */
+ if (virtual_list_view)
+ {
+ if (NULL != candidates && candidates->b_nids>0)
+ {
+ IDList *idl= NULL;
+ vlv_response_control.result= vlv_trim_candidates(be, candidates, sort_control, &vlv_request_control, &idl, &vlv_response_control);
+ if(vlv_response_control.result==0)
+ {
+ idl_free(candidates);
+ candidates= idl;
+ }
+ else
+ {
+ return ldbm_back_search_cleanup(pb, li, sort_control, vlv_response_control.result, NULL, -1, &basesdn, &vlv_request_control);
+ }
+ }
+ else
+ {
+ vlv_response_control.targetPosition= 0;
+ vlv_response_control.contentCount= 0;
+ vlv_response_control.result= LDAP_SUCCESS;
+ }
+ }
+ }
+ if (virtual_list_view)
+ {
+ if(LDAP_SUCCESS != vlv_make_response_control( pb, &vlv_response_control ))
+ {
+ return ldbm_back_search_cleanup(pb, li, sort_control, (abandoned?-1:LDAP_PROTOCOL_ERROR), "VLV Response Control", -1, &basesdn, &vlv_request_control);
+ }
+ /* Log the VLV operation */
+ vlv_print_access_log(pb,&vlv_request_control,&vlv_response_control);
+ }
+ }
+
+ cache_return( &inst->inst_cache, &e );
+
+ /*
+ * if the candidate list is an allids list, arrange for access log
+ * to record that fact.
+ */
+ if ( NULL != candidates && ALLIDS( candidates )) {
+ unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
+ int ri = 0;
+
+ /*
+ * Return error if nsslapd-require-index is set and
+ * this is not an internal operation.
+ * We hope the plugins know what they are doing!
+ */
+ if (!operation_is_flag_set(operation, OP_FLAG_INTERNAL)) {
+
+ PR_Lock(inst->inst_config_mutex);
+ ri = inst->require_index;
+ PR_Unlock(inst->inst_config_mutex);
+
+ if (ri) {
+ idl_free(candidates);
+ candidates = idl_alloc(0);
+ tmp_err = LDAP_UNWILLING_TO_PERFORM;
+ tmp_desc = "Search is not indexed";
+ }
+ }
+
+ slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
+ }
+
+ sr->sr_candidates = candidates;
+ sr->sr_virtuallistview = virtual_list_view;
+
+ /* check to see if we can skip the filter test */
+ if ( li->li_filter_bypass && NULL != candidates && !virtual_list_view
+ && !lookup_returned_allids ) {
+ Slapi_Filter *filter= NULL;
+
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
+ if ( can_skip_filter_test( pb, filter, scope, candidates)) {
+ sr->sr_flags |= SR_FLAG_CAN_SKIP_FILTER_TEST;
+ }
+ }
+
+ /* Fix for bugid #394184, SD, 05 Jul 00 */
+ /* tmp_err == -1: no error */
+ return ldbm_back_search_cleanup(pb, li, sort_control, tmp_err, tmp_desc, (tmp_err == -1 ? 0 : -1), &basesdn, &vlv_request_control);
+ /* end Fix for bugid #394184 */
+}
+
+/*
+ * Build a candidate list for this backentry and scope.
+ * Could be a BASE, ONELEVEL, or SUBTREE search.
+ *
+ * Returns:
+ * 0 - success
+ * <0 - fail
+ *
+ */
+static int
+build_candidate_list( Slapi_PBlock *pb, backend *be, struct backentry *e,
+ const char * base, int scope, int *lookup_returned_allidsp,
+ IDList** candidates)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ int managedsait= 0;
+ Slapi_Filter *filter= NULL;
+ int err= 0;
+ int r= 0;
+
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
+ slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
+
+ switch ( scope ) {
+ case LDAP_SCOPE_BASE:
+ *candidates = base_candidates( pb, e );
+ break;
+
+ case LDAP_SCOPE_ONELEVEL:
+ *candidates = onelevel_candidates( pb, be, base, e, filter, managedsait,
+ lookup_returned_allidsp, &err );
+ break;
+
+ case LDAP_SCOPE_SUBTREE:
+ *candidates = subtree_candidates(pb, be, base, e, filter, managedsait,
+ lookup_returned_allidsp, &err);
+ break;
+
+ default:
+ slapi_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "Bad scope", 0, NULL );
+ r = SLAPI_FAIL_GENERAL;
+ }
+ if ( 0 != err && DB_NOTFOUND != err ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "database error %d\n", err, 0, 0 );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL,
+ 0, NULL );
+ if (LDBM_OS_ERR_IS_DISKFULL(err)) r = return_on_disk_full(li);
+ else r = SLAPI_FAIL_GENERAL;
+ }
+
+ /*
+ * If requested, set a flag to indicate whether the indexed
+ * lookup returned an ALLIDs block. Note that this is taken care of
+ * above already for subtree searches.
+ */
+ if ( NULL != lookup_returned_allidsp ) {
+ if ( 0 == err ) {
+ if ( !(*lookup_returned_allidsp) && LDAP_SCOPE_SUBTREE != scope ) {
+ *lookup_returned_allidsp =
+ ( NULL != *candidates && ALLIDS( *candidates ));
+ }
+ } else {
+ *lookup_returned_allidsp = 0;
+ }
+ }
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "candidate list has %lu ids\n",
+ *candidates ? (*candidates)->b_nids : 0L, 0, 0);
+
+ return r;
+}
+
+/*
+ * Build a candidate list for a BASE scope search.
+ */
+static IDList *
+base_candidates(Slapi_PBlock *pb, struct backentry *e)
+{
+ IDList *idl= idl_alloc( 1 );
+ idl_append( idl, NULL == e ? 0 : e->ep_id );
+ return( idl );
+}
+
+/*
+ * Modify the filter to include entries of the referral objectclass
+ *
+ * make (|(originalfilter)(objectclass=referral))
+ *
+ * "focref, forr" are temporary filters which the caller must free
+ * non-recursively when done with the returned filter.
+ */
+static Slapi_Filter*
+create_referral_filter(Slapi_Filter* filter, Slapi_Filter** focref, Slapi_Filter** forr)
+{
+ char *buf = slapi_ch_strdup( "objectclass=referral" );
+
+ *focref = slapi_str2filter( buf );
+ *forr = slapi_filter_join( LDAP_FILTER_OR, filter, *focref );
+
+ slapi_ch_free((void **)&buf);
+ return *forr;
+}
+
+/*
+ * Modify the filter to be a one level search.
+ *
+ * (&(parentid=idofbase)(|(originalfilter)(objectclass=referral)))
+ *
+ * "fid2kids, focref, fand, forr" are temporary filters which the
+ * caller must free'd non-recursively when done with the returned filter.
+ *
+ * This function is exported for the VLV code to use.
+ */
+Slapi_Filter*
+create_onelevel_filter(Slapi_Filter* filter, const struct backentry *baseEntry, int managedsait, Slapi_Filter** fid2kids, Slapi_Filter** focref, Slapi_Filter** fand, Slapi_Filter** forr)
+{
+ Slapi_Filter *ftop= filter;
+ char buf[40];
+
+ if ( !managedsait )
+ {
+ ftop= create_referral_filter(filter, focref, forr);
+ }
+
+ sprintf( buf, "parentid=%lu", (u_long)(baseEntry != NULL ? baseEntry->ep_id : 0) );
+ *fid2kids = slapi_str2filter( buf );
+ *fand = slapi_filter_join( LDAP_FILTER_AND, ftop, *fid2kids );
+
+ return *fand;
+}
+
+/*
+ * Build a candidate list for a ONELEVEL scope search.
+ */
+static IDList *
+onelevel_candidates(
+ Slapi_PBlock *pb,
+ backend *be,
+ const char *base,
+ struct backentry *e,
+ Slapi_Filter *filter,
+ int managedsait,
+ int *lookup_returned_allidsp,
+ int *err
+)
+{
+ Slapi_Filter *fid2kids= NULL;
+ Slapi_Filter *focref= NULL;
+ Slapi_Filter *fand= NULL;
+ Slapi_Filter *forr= NULL;
+ Slapi_Filter *ftop= NULL;
+ IDList *candidates;
+
+ /*
+ * modify the filter to be something like this:
+ *
+ * (&(parentid=idofbase)(|(originalfilter)(objectclass=referral)))
+ */
+
+ ftop= create_onelevel_filter(filter, e, managedsait, &fid2kids, &focref, &fand, &forr);
+
+ /* from here, it's just like subtree_candidates */
+ candidates = filter_candidates( pb, be, base, ftop, NULL, 0, err );
+
+ *lookup_returned_allidsp = slapi_be_is_flag_set(be, SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST);
+
+ /* free up just the filter stuff we allocated above */
+ slapi_filter_free( fid2kids, 0 );
+ slapi_filter_free( fand, 0 );
+ slapi_filter_free( forr, 0 );
+ slapi_filter_free( focref, 0 );
+
+ return( candidates );
+}
+
+
+#define GRABSIZE2 50
+#define BUF_ALLOC_CAT( cpyfunc, s ) { \
+ int len = 2 * strlen( s ); \
+ while ( bmax - bcur < len + 1 ) { \
+ bmax += GRABSIZE2; \
+ buf = slapi_ch_realloc( buf, bmax ); \
+ } \
+ cpyfunc( buf + bcur, s ); \
+ bcur += strlen( buf + bcur ); \
+}
+
+/*
+ * We need to modify the filter to be something like this:
+ *
+ * (|(originalfilter)(objectclass=referral))
+ *
+ * the "objectclass=referral" part is used to select referrals to return.
+ * it is only included if the managedsait service control is not set.
+ *
+ * This function is exported for the VLV code to use.
+ */
+Slapi_Filter*
+create_subtree_filter(Slapi_Filter* filter, int managedsait, Slapi_Filter** focref, Slapi_Filter** forr)
+{
+ Slapi_Filter *ftop= filter;
+
+ if ( !managedsait )
+ {
+ ftop= create_referral_filter(filter, focref, forr);
+ }
+
+ return ftop;
+}
+
+
+static int
+nscpentrydn_check_filter(Slapi_Filter *f)
+{
+ if (!f || (f->f_choice != LDAP_FILTER_AND))
+ return 0; /* Not nscpEntryDN filter */
+
+ if ( 0 == strcasecmp ( f->f_and->f_avtype, SLAPI_ATTR_NSCP_ENTRYDN)) {
+ return 1; /* Contains a nscpEntryDN filter */
+ } else if ( 0 == strcasecmp ( f->f_and->f_next->f_avtype, SLAPI_ATTR_NSCP_ENTRYDN)) {
+ return 1;
+ }
+ return 0; /* Not nscpEntryDN filter */
+}
+
+
+/*
+ * Build a candidate list for a SUBTREE scope search.
+ */
+IDList *
+subtree_candidates(
+ Slapi_PBlock *pb,
+ backend *be,
+ const char *base,
+ const struct backentry *e,
+ Slapi_Filter *filter,
+ int managedsait,
+ int *allids_before_scopingp,
+ int *err
+)
+{
+ Slapi_Filter *focref= NULL;
+ Slapi_Filter *forr= NULL;
+ Slapi_Filter *ftop= NULL;
+ IDList *candidates;
+ PRBool has_tombstone_filter;
+ int isroot = 0;
+
+ /* make (|(originalfilter)(objectclass=referral)) */
+ ftop= create_subtree_filter(filter, managedsait, &focref, &forr);
+
+ /* Fetch a candidate list for the original filter */
+ candidates = filter_candidates( pb, be, base, ftop, NULL, 0, err );
+ slapi_filter_free( forr, 0 );
+ slapi_filter_free( focref, 0 );
+
+ /* set 'allids before scoping' flag */
+ if ( NULL != allids_before_scopingp ) {
+ *allids_before_scopingp = ( NULL != candidates && ALLIDS( candidates ));
+ }
+
+ has_tombstone_filter = (filter->f_flags & SLAPI_FILTER_TOMBSTONE);
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+
+ /*
+ * Apply the DN components if the candidate list is greater than
+ * our threshold, and if the filter is not "(objectclass=nstombstone)",
+ * since tombstone entries are not indexed in the ancestorid index.
+ */
+ if(candidates!=NULL && ( idl_length(candidates)>FILTER_TEST_THRESHOLD) && !has_tombstone_filter)
+ {
+ IDList *tmp = candidates, *descendants = NULL;
+
+ *err = ldbm_ancestorid_read(be, NULL, e->ep_id, &descendants);
+ idl_insert(&descendants, e->ep_id);
+ candidates = idl_intersection(be, candidates, descendants);
+ idl_free(tmp);
+ idl_free(descendants);
+ }
+ /*
+ * If the search is initiated by the Directory Manager,
+ * and the filter includes objectclass=nsTombstone,
+ * then we union the candidate list with all the tombstone
+ * entries in this backend instance.
+ */
+ if (has_tombstone_filter && isroot && !nscpentrydn_check_filter(filter))
+ {
+ IDList *idl;
+ IDList *tmp= candidates;
+ struct slapi_filter f = {0};
+ f.f_choice = LDAP_FILTER_EQUALITY;
+ f.f_avtype = "objectclass";
+ f.f_avvalue.bv_val = SLAPI_ATTR_VALUE_TOMBSTONE;
+ f.f_avvalue.bv_len = strlen(SLAPI_ATTR_VALUE_TOMBSTONE);
+ f.f_next= NULL;
+ idl = filter_candidates( pb, be, NULL, &f, NULL, 0, err );
+
+ /*
+ * If that gave allids then try (nscpentrydn=*) instead.
+ * The nscpentrydn equality index contains all the tombstones
+ * and can be used to resolve a presence filter without
+ * hitting allids.
+ */
+ if (idl && ALLIDS(idl)) {
+ idl_free(idl);
+ f.f_choice = LDAP_FILTER_PRESENT;
+ f.f_avtype = SLAPI_ATTR_NSCP_ENTRYDN;
+ idl = filter_candidates( pb, be, NULL, &f, NULL, 0, err );
+ }
+
+ candidates = idl_union( be, idl, tmp );
+ idl_free( idl );
+ idl_free( tmp );
+ }
+
+ return( candidates );
+}
+
+static int grok_filter(struct slapi_filter *f);
+#if 0
+/* Helper for grok_filter() */
+static int
+grok_filter_list(struct slapi_filter *flist)
+{
+ struct slapi_filter *f;
+
+ /* Scan the clauses of the AND filter, if any of them fails the grok, then we fail */
+ for ( f = flist; f != NULL; f = f->f_next ) {
+ if ( !grok_filter(f) ) {
+ return( 0 );
+ }
+ }
+ return( 1 );
+}
+#endif
+
+/* Helper function for can_skip_filter_test() */
+static int grok_filter(struct slapi_filter *f)
+{
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ return 1; /* If there's an ID list and an equality filter, we can skip the filter test */
+ case LDAP_FILTER_SUBSTRINGS:
+ return 0;
+
+ case LDAP_FILTER_GE:
+ return 1;
+
+ case LDAP_FILTER_LE:
+ return 1;
+
+ case LDAP_FILTER_PRESENT:
+ return 1; /* If there's an ID list, and a presence filter, we can skip the filter test */
+
+ case LDAP_FILTER_APPROX:
+ return 0;
+
+ case LDAP_FILTER_EXTENDED:
+ return 0;
+
+ case LDAP_FILTER_AND:
+ return 0; /* Unless we check to see whether the presence and equality branches
+ of the search filter were all indexed, we get things wrong here,
+ so let's punt for now */
+ /* return grok_filter_list(f->f_and); AND clauses are potentially OK */
+
+ case LDAP_FILTER_OR:
+ return 0;
+
+ case LDAP_FILTER_NOT:
+ return 0;
+
+ default:
+ return 0;
+ }
+}
+
+/* Routine which says whether or not the indices produced a "correct" answer */
+static int
+can_skip_filter_test(
+ Slapi_PBlock *pb,
+ struct slapi_filter *f,
+ int scope,
+ IDList *idl
+)
+{
+ /* Is the ID list ALLIDS ? */
+ if ( ALLIDS(idl)) {
+ /* If so, then can't optimize */
+ return 0;
+ }
+
+ /* Is this a base scope search? */
+ if ( scope == LDAP_SCOPE_BASE ) {
+ /*
+ * If so, then we can't optimize. Why not? Because we only consult
+ * the entrydn index in producing our 1 candidate, and that means
+ * we have not used the filter to produce the candidate list.
+ */
+ return 0;
+ }
+
+ /* Grok the filter and tell me if it has only equality components in it */
+ return grok_filter(f);
+}
+
+
+
+/*
+ * Return the next entry in the result set. The entry is returned
+ * in the pblock.
+ * Returns 0 normally. If -1 is returned, it means that some
+ * exceptional condition, e.g. timelimit exceeded has occurred,
+ * and this routine has sent a result to the client. If zero
+ * is returned and no entry is available in the PBlock, then
+ * we've iterated through all the entries.
+ */
+int
+ldbm_back_next_search_entry( Slapi_PBlock *pb )
+{
+ return ldbm_back_next_search_entry_ext( pb, 0 );
+}
+
+int
+ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension )
+{
+ backend *be;
+ ldbm_instance *inst;
+ struct ldbminfo *li;
+ int scope;
+ int managedsait;
+ Slapi_Attr *attr;
+ Slapi_Filter *filter;
+ char *base;
+ back_search_result_set *sr;
+ ID id;
+ struct backentry *e;
+ int nentries;
+ time_t curtime, stoptime, optime;
+ int tlimit, llimit, slimit, isroot;
+ struct berval **urls = NULL;
+ int err;
+ Slapi_DN basesdn;
+ char *target_uniqueid;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
+ slapi_pblock_get( pb, SLAPI_MANAGEDSAIT, &managedsait );
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base );
+ slapi_pblock_get( pb, SLAPI_NENTRIES, &nentries );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &slimit );
+ slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &tlimit );
+ slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime );
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ slapi_pblock_get( pb, SLAPI_SEARCH_REFERRALS, &urls );
+ slapi_pblock_get( pb, SLAPI_SEARCH_RESULT_SET, &sr );
+ slapi_pblock_get( pb, SLAPI_TARGET_UNIQUEID, &target_uniqueid );
+
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ slapi_sdn_init_dn_ndn_byref(&basesdn,base); /* normalized by front end */
+ /* Return to the cache the entry we handed out last time */
+ /* If we are using the extension, the front end will tell
+ * us when to do this so we don't do it now */
+ if ( !use_extension )
+ {
+ cache_return( &inst->inst_cache, &(sr->sr_entry) );
+ }
+
+ if(sr->sr_vlventry != NULL && !use_extension )
+ {
+ /* This empty entry was handed out last time because the ACL check failed on a VLV Search. */
+ /* The empty entry has a pointer to the cache entry dn... make sure we don't free the dn */
+ /* which belongs to the cache entry. */
+ slapi_entry_free( sr->sr_vlventry );
+ sr->sr_vlventry = NULL;
+ }
+
+ stoptime = optime + tlimit;
+ llimit = sr->sr_lookthroughlimit;
+
+ /* Find the next candidate entry and return it. */
+ while ( 1 )
+ {
+
+ /* check for abandon */
+ if ( slapi_op_abandoned( pb ))
+ {
+ delete_search_result_set( &sr );
+ if ( use_extension ) {
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, NULL );
+ }
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
+ slapi_sdn_done(&basesdn);
+ return -1;
+ }
+
+ /* check time limit */
+ curtime = current_time();
+ if ( tlimit != -1 && curtime > stoptime )
+ {
+ slapi_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL, NULL, nentries, urls );
+ delete_search_result_set( &sr );
+ if ( use_extension ) {
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, NULL );
+ }
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
+ slapi_sdn_done(&basesdn);
+ return -1;
+ }
+
+ /* check lookthrough limit */
+ if ( llimit != -1 && sr->sr_lookthroughcount >= llimit )
+ {
+ slapi_send_ldap_result( pb, LDAP_ADMINLIMIT_EXCEEDED, NULL, NULL, nentries, urls );
+ delete_search_result_set( &sr );
+ if ( use_extension ) {
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, NULL );
+ }
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
+ slapi_sdn_done(&basesdn);
+ return -1;
+ }
+
+ /* get the entry */
+ id = idl_iterator_dereference_increment(&(sr->sr_current), sr->sr_candidates);
+ if ( id == NOID )
+ {
+ /* No more entries */
+ delete_search_result_set( &sr );
+ if ( use_extension ) {
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, NULL );
+ }
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, NULL );
+ slapi_sdn_done(&basesdn);
+ return 0;
+ }
+
+ ++sr->sr_lookthroughcount; /* checked above */
+
+ /* get the entry */
+ if ( (e = id2entry( be, id, NULL, &err )) == NULL )
+ {
+ if ( err != 0 && err != DB_NOTFOUND )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "next_search_entry db err %d\n", err, 0, 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(err))
+ {
+ /* disk full in the middle of returning search results
+ * is gonna be traumatic. unavoidable.
+ */
+ slapi_send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
+ slapi_sdn_done(&basesdn);
+ return return_on_disk_full(li);
+ }
+ }
+ LDAPDebug( LDAP_DEBUG_ARGS, "candidate %lu not found\n", (u_long)id, 0, 0 );
+ if ( err == DB_NOTFOUND )
+ {
+ /* Since we didn't really look at this entry, we should
+ * decrement the lookthrough counter (it was just incremented).
+ * If we didn't do this, it would be possible to go over the
+ * lookthrough limit when there are fewer entries in the database
+ * than the lookthrough limit. This could happen on an ALLIDS
+ * search after adding a bunch of entries and then deleting
+ * them. */
+ --sr->sr_lookthroughcount;
+ }
+ continue;
+ }
+ e->ep_vlventry = NULL;
+ sr->sr_entry = e;
+
+ /*
+ * If it's a referral, return it without checking the
+ * filter explicitly here since it's only a candidate anyway. Do
+ * check the scope though.
+ */
+ if ( !managedsait && slapi_entry_attr_find( e->ep_entry, "ref", &attr ) == 0)
+ {
+ Slapi_Value **refs= attr_get_present_values(attr);
+ if ( refs == NULL || refs[0] == NULL )
+ {
+ char ebuf[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY, "null ref in (%s)\n", escape_string( backentry_get_ndn(e), ebuf ), 0, 0 );
+ }
+ else if ( slapi_sdn_scope_test( backentry_get_sdn(e), &basesdn, scope ))
+ {
+ if ( use_extension ) {
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, e );
+ }
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, e->ep_entry );
+ slapi_sdn_done(&basesdn);
+ return 0;
+ }
+ }
+ else
+ {
+ /*
+ * As per slapi_filter_test:
+ * 0 filter matched
+ * -1 filter did not match
+ * >0 an ldap error code
+ */
+ int filter_test = -1;
+
+ if((slapi_entry_flag_is_set(e->ep_entry,SLAPI_ENTRY_LDAPSUBENTRY)
+ && !filter_flag_is_set(filter,SLAPI_FILTER_LDAPSUBENTRY)) ||
+ (slapi_entry_flag_is_set(e->ep_entry,SLAPI_ENTRY_FLAG_TOMBSTONE)
+ && (!isroot || !filter_flag_is_set(filter, SLAPI_FILTER_TOMBSTONE))))
+ {
+ /* If the entry is an LDAP subentry and filter don't filter subentries OR
+ * the entry is a TombStone and filter don't filter Tombstone
+ * don't return the entry
+ */
+ /* ugaston - we don't want to mistake this filter failure with the one below due to ACL,
+ * because whereas the former should be read as 'no entry must be returned', the latter
+ * might still lead to return an empty entry. */
+ filter_test=-1;
+ }
+ else
+ {
+ /* it's a regular entry, check if it matches the filter, and passes the ACL check */
+ if ( 0 != ( sr->sr_flags & SR_FLAG_CAN_SKIP_FILTER_TEST )) {
+ /* Since we do access control checking in the filter test (?Why?) we need to check access now */
+ LDAPDebug( LDAP_DEBUG_FILTER, "Bypassing filter test\n", 0, 0, 0 );
+ if ( ACL_CHECK_FLAG ) {
+ filter_test = slapi_vattr_filter_test_ext( pb, e->ep_entry, filter, ACL_CHECK_FLAG, 1 /* Only perform access checking, thank you */);
+ } else {
+ filter_test = 0;
+ }
+ if (li->li_filter_bypass_check) {
+ int ft_rc;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "Checking bypass\n", 0, 0, 0 );
+ ft_rc = slapi_vattr_filter_test( pb, e->ep_entry, filter,
+ ACL_CHECK_FLAG );
+ if (filter_test != ft_rc) {
+ /* Oops ! This means that we thought we could bypass the filter test, but noooo... */
+ char ebuf[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY, "Filter bypass ERROR on entry %s\n", escape_string( backentry_get_ndn(e), ebuf ), 0, 0 );
+ filter_test = ft_rc; /* Fix the error */
+ }
+ }
+ } else {
+ /* Old-style case---we need to do a filter test */
+ filter_test = slapi_vattr_filter_test( pb, e->ep_entry, filter, ACL_CHECK_FLAG);
+ }
+ }
+ if ( (filter_test == 0) || (sr->sr_virtuallistview && (filter_test != -1)) )
+ /* ugaston - if filter failed due to subentries or tombstones (filter_test=-1),
+ * just forget about it, since we don't want to return anything at all. */
+ {
+ if ( slapi_uniqueIDCompareString(target_uniqueid, e->ep_entry->e_uniqueid) ||
+ slapi_sdn_scope_test( backentry_get_sdn(e), &basesdn, scope ))
+ {
+ /* check size limit */
+ if ( slimit >= 0 )
+ {
+ if ( --slimit < 0 ) {
+ cache_return( &inst->inst_cache, &e );
+ delete_search_result_set( &sr );
+ slapi_send_ldap_result( pb, LDAP_SIZELIMIT_EXCEEDED, NULL, NULL, nentries, urls );
+ slapi_sdn_done(&basesdn);
+ return -1;
+ }
+ slapi_pblock_set( pb, SLAPI_SEARCH_SIZELIMIT, &slimit );
+ }
+ if ( (filter_test != 0) && sr->sr_virtuallistview)
+ {
+ /* Slapi Filter Test failed.
+ * Must be that the ACL check failed.
+ * Send back an empty entry.
+ */
+ sr->sr_vlventry = slapi_entry_alloc();
+ slapi_entry_init(sr->sr_vlventry,slapi_ch_strdup(slapi_entry_get_dn_const(e->ep_entry)),NULL);
+ e->ep_vlventry = sr->sr_vlventry;
+ if ( use_extension ) {
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, e );
+ }
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, sr->sr_vlventry );
+ } else {
+ if ( use_extension ) {
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, e );
+ }
+ slapi_pblock_set( pb, SLAPI_SEARCH_RESULT_ENTRY, e->ep_entry );
+ }
+ slapi_sdn_done(&basesdn);
+ return 0;
+ }
+ else
+ {
+ cache_return ( &inst->inst_cache, &(sr->sr_entry) );
+ }
+ }
+ else
+ {
+ /* Failed the filter test, and this isn't a VLV Search */
+ cache_return( &inst->inst_cache, &(sr->sr_entry) );
+ }
+ }
+ }
+ /*NOTREACHED*/
+ slapi_sdn_done(&basesdn);
+}
+
+
+static back_search_result_set*
+new_search_result_set(IDList *idl, int vlv, int lookthroughlimit)
+{
+ back_search_result_set *p= (back_search_result_set *)slapi_ch_malloc( sizeof( back_search_result_set ));
+ p->sr_candidates = idl;
+ p->sr_current = idl_iterator_init(idl);
+ p->sr_entry = NULL;
+ p->sr_lookthroughcount = 0;
+ p->sr_lookthroughlimit = lookthroughlimit;
+ p->sr_virtuallistview= vlv;
+ p->sr_vlventry = NULL;
+ p->sr_flags = 0;
+ return p;
+}
+
+static void
+delete_search_result_set( back_search_result_set **sr )
+{
+ if ( NULL == sr || NULL == *sr)
+ {
+ return;
+ }
+ if ( NULL != (*sr)->sr_candidates )
+ {
+ idl_free( (*sr)->sr_candidates );
+ }
+ slapi_ch_free( (void**)sr );
+}
+
+
+int
+ldbm_back_entry_release( Slapi_PBlock *pb, void *backend_info_ptr ) {
+ backend *be;
+ ldbm_instance *inst;
+
+ if ( backend_info_ptr == NULL )
+ return 1;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ cache_return( &inst->inst_cache, (struct backentry **)&backend_info_ptr );
+
+ if( ((struct backentry *) backend_info_ptr)->ep_vlventry != NULL )
+ {
+ /* This entry was created during a vlv search whose acl check failed. It needs to be
+ * freed here */
+ slapi_entry_free( ((struct backentry *) backend_info_ptr)->ep_vlventry );
+ ((struct backentry *) backend_info_ptr)->ep_vlventry = NULL;
+ }
+ return 0;
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_unbind.c b/ldap/servers/slapd/back-ldbm/ldbm_unbind.c
new file mode 100644
index 00000000..9d3e80fa
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldbm_unbind.c
@@ -0,0 +1,14 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* unbind.c - handle an ldap unbind operation */
+
+#include "back-ldbm.h"
+
+int
+ldbm_back_unbind( Slapi_PBlock *pb )
+{
+ return( 0 );
+}
diff --git a/ldap/servers/slapd/back-ldbm/ldif2ldbm.c b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
new file mode 100644
index 00000000..1930cb51
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/ldif2ldbm.c
@@ -0,0 +1,2440 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* ldif2ldbm.c
+ *
+ * common functions for import (old and new) and export
+ * the export code (db2ldif)
+ * code for db2index (is this still in use?)
+ */
+
+#include "back-ldbm.h"
+#include "vlv_srch.h"
+#include "dblayer.h"
+#include "import.h"
+
+static char *sourcefile = "ldif2ldbm.c";
+
+
+static int db2index_add_indexed_attr(backend *be, char *attrString);
+
+static int ldbm_exclude_attr_from_export( struct ldbminfo *li,
+ const char *attr, int dump_uniqueid );
+
+
+/********** common routines for classic/deluxe import code **********/
+
+static size_t import_config_index_buffer_size = DEFAULT_IMPORT_INDEX_BUFFER_SIZE;
+
+void import_configure_index_buffer_size(size_t size)
+{
+ import_config_index_buffer_size = size;
+}
+
+size_t import_get_index_buffer_size() {
+ return import_config_index_buffer_size;
+}
+
+static PRIntn import_subcount_hash_compare_keys(const void *v1, const void *v2)
+{
+ return( ((ID)v1 == (ID)v2 ) ? 1 : 0);
+}
+
+static PRIntn import_subcount_hash_compare_values(const void *v1, const void *v2)
+{
+ return( ((size_t)v1 == (size_t)v2 ) ? 1 : 0);
+}
+
+static PLHashNumber import_subcount_hash_fn(const void *id)
+{
+ return (PLHashNumber) id;
+}
+
+void import_subcount_stuff_init(import_subcount_stuff *stuff)
+{
+ stuff->hashtable = PL_NewHashTable(IMPORT_SUBCOUNT_HASHTABLE_SIZE,
+ import_subcount_hash_fn, import_subcount_hash_compare_keys,
+ import_subcount_hash_compare_values, NULL, NULL);
+}
+
+void import_subcount_stuff_term(import_subcount_stuff *stuff)
+{
+ if ( stuff != NULL && stuff->hashtable != NULL ) {
+ PL_HashTableDestroy(stuff->hashtable);
+ }
+}
+
+/* fetch include/exclude DNs from the pblock and normalize them --
+ * returns true if there are any include/exclude DNs
+ * [used by both ldif2db and db2ldif]
+ */
+int ldbm_back_fetch_incl_excl(Slapi_PBlock *pb, char ***include,
+ char ***exclude)
+{
+ char **pb_incl, **pb_excl;
+ char subtreeDn[BUFSIZ];
+ char *normSubtreeDn;
+ int i;
+
+ slapi_pblock_get(pb, SLAPI_LDIF2DB_INCLUDE, &pb_incl);
+ slapi_pblock_get(pb, SLAPI_LDIF2DB_EXCLUDE, &pb_excl);
+ *include = *exclude = NULL;
+
+ /* normalize */
+ if (pb_excl) {
+ for (i = 0; pb_excl[i]; i++) {
+ strcpy(subtreeDn, pb_excl[i]);
+ normSubtreeDn = slapi_dn_normalize_case(subtreeDn);
+ charray_add(exclude, slapi_ch_strdup(normSubtreeDn));
+ }
+ }
+ if (pb_incl) {
+ for (i = 0; pb_incl[i]; i++) {
+ strcpy(subtreeDn, pb_incl[i]);
+ normSubtreeDn = slapi_dn_normalize_case(subtreeDn);
+ charray_add(include, slapi_ch_strdup(normSubtreeDn));
+ }
+ }
+ return (pb_incl || pb_excl);
+}
+
+void ldbm_back_free_incl_excl(char **include, char **exclude)
+{
+ if (include) {
+ charray_free(include);
+ }
+ if (exclude) {
+ charray_free(exclude);
+ }
+}
+
+/* check if a DN is in the include list but NOT the exclude list
+ * [used by both ldif2db and db2ldif]
+ */
+int ldbm_back_ok_to_dump(const char *dn, char **include, char **exclude)
+{
+ int i = 0;
+
+ if (!(include || exclude))
+ return(1);
+
+ if (exclude) {
+ i = 0;
+ while (exclude[i]) {
+ if (slapi_dn_issuffix(dn,exclude[i]))
+ return(0);
+ i++;
+ }
+ }
+
+ if (include) {
+ i = 0;
+ while (include[i]) {
+ if (slapi_dn_issuffix(dn,include[i]))
+ return(1);
+ i++;
+ }
+ /* not in include... bye. */
+ return(0);
+ }
+
+ return(1);
+}
+
+
+/*
+ * add_op_attrs - add the parentid, entryid, dncomp,
+ * and entrydn operational attributes to an entry.
+ * Also---new improved washes whiter than white version
+ * now removes any bogus operational attributes you're not
+ * allowed to specify yourself on entries.
+ * Currenty the list of these is: numSubordinates, hasSubordinates
+ */
+int add_op_attrs(Slapi_PBlock *pb, struct ldbminfo *li, struct backentry *ep,
+ int *status)
+{
+ backend *be;
+ const char *pdn;
+ ID pid = 0;
+
+ slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+
+ /*
+ * add the parentid and entryid operational attributes
+ */
+
+ if (NULL != status) {
+ *status = IMPORT_ADD_OP_ATTRS_OK;
+ }
+
+ /* parentid */
+ if ( (pdn = slapi_dn_parent( backentry_get_ndn(ep))) != NULL ) {
+ struct berval bv;
+ IDList *idl;
+ int err = 0;
+
+ /*
+ * read the entrydn index to get the id of the parent
+ * If this entry's parent is not present in the index,
+ * we'll get a DB_NOTFOUND error here.
+ * In olden times, we just ignored this, but now...
+ * we see this as meaning that the entry is either a
+ * suffix entry, or its erroneous. So, we signal this to the
+ * caller via the status parameter.
+ */
+ bv.bv_val = (char *)pdn;
+ bv.bv_len = strlen(pdn);
+ if ( (idl = index_read( be, "entrydn", indextype_EQUALITY, &bv, NULL,
+ &err )) != NULL ) {
+ pid = idl_firstid( idl );
+ idl_free( idl );
+ } else if ( 0 != err ) {
+ if (DB_NOTFOUND != err ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "database error %d\n", err, 0, 0 );
+ slapi_ch_free( (void**)&pdn );
+ return( -1 );
+ } else {
+ if (NULL != status) {
+ *status = IMPORT_ADD_OP_ATTRS_NO_PARENT;
+ }
+ }
+ }
+ slapi_ch_free( (void**)&pdn );
+ } else {
+ if (NULL != status) {
+ *status = IMPORT_ADD_OP_ATTRS_NO_PARENT;
+ }
+ }
+
+ /* Get rid of attributes you're not allowed to specify yourself */
+ slapi_entry_delete_values( ep->ep_entry, hassubordinates, NULL );
+ slapi_entry_delete_values( ep->ep_entry, numsubordinates, NULL );
+
+ /* Add the entryid, parentid and entrydn operational attributes */
+ /* Note: This function is provided by the Add code */
+ add_update_entry_operational_attributes(ep, pid);
+
+ return( 0 );
+}
+
+/********** functions for maintaining the subordinate count **********/
+
+/* Update subordinate count in a hint list, given the parent's ID */
+int import_subcount_mother_init(import_subcount_stuff *mothers, ID parent_id,
+ size_t count)
+{
+ PR_ASSERT(NULL == PL_HashTableLookup(mothers->hashtable,(void*)parent_id));
+ PL_HashTableAdd(mothers->hashtable,(void*)parent_id,(void*)count);
+ return 0;
+}
+
+/* Look for a subordinate count in a hint list, given the parent's ID */
+static int import_subcount_mothers_lookup(import_subcount_stuff *mothers,
+ ID parent_id, size_t *count)
+{
+ size_t stored_count = 0;
+
+ *count = 0;
+ /* Lookup hash table for ID */
+ stored_count = (size_t)PL_HashTableLookup(mothers->hashtable,
+ (void*)parent_id);
+ /* If present, return the count found */
+ if (0 != stored_count) {
+ *count = stored_count;
+ return 0;
+ }
+ return -1;
+}
+
+/* Update subordinate count in a hint list, given the parent's ID */
+int import_subcount_mother_count(import_subcount_stuff *mothers, ID parent_id)
+{
+ size_t stored_count = 0;
+
+ /* Lookup the hash table for the target ID */
+ stored_count = (size_t)PL_HashTableLookup(mothers->hashtable,
+ (void*)parent_id);
+ PR_ASSERT(0 != stored_count);
+ /* Increment the count */
+ stored_count++;
+ PL_HashTableAdd(mothers->hashtable, (void*)parent_id, (void*)stored_count);
+ return 0;
+}
+
+static int import_update_entry_subcount(backend *be, ID parentid,
+ size_t sub_count)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ int ret = 0;
+ modify_context mc = {0};
+ char value_buffer[20]; /* enough digits for 2^64 children */
+ struct backentry *e = NULL;
+ int isreplace = 0;
+
+ /* Get hold of the parent */
+ e = id2entry(be,parentid,NULL,&ret);
+ if ( (NULL == e) || (0 != ret)) {
+ ldbm_nasty(sourcefile,5,ret);
+ return (0 == ret) ? -1 : ret;
+ }
+ /* Lock it (not really required since we're single-threaded here, but
+ * let's do it so we can reuse the modify routines) */
+ cache_lock_entry( &inst->inst_cache, e );
+ modify_init(&mc,e);
+ sprintf(value_buffer,"%lu",sub_count);
+ /* attr numsubordinates could already exist in the entry,
+ let's check whether it's already there or not */
+ isreplace = (attrlist_find(e->ep_entry->e_attrs, numsubordinates) != NULL);
+ {
+ int op = isreplace ? LDAP_MOD_REPLACE : LDAP_MOD_ADD;
+ Slapi_Mods *smods= slapi_mods_new();
+
+ slapi_mods_add(smods, op | LDAP_MOD_BVALUES, numsubordinates,
+ strlen(value_buffer), value_buffer);
+ ret = modify_apply_mods(&mc,smods); /* smods passed in */
+ }
+ if (0 == ret || LDAP_TYPE_OR_VALUE_EXISTS == ret) {
+ /* This will correctly index subordinatecount: */
+ ret = modify_update_all(be,NULL,&mc,NULL);
+ if (0 == ret) {
+ modify_switch_entries( &mc,be);
+ }
+ }
+ modify_term(&mc,be);
+ return ret;
+}
+
+struct _import_subcount_trawl_info {
+ struct _import_subcount_trawl_info *next;
+ ID id;
+ size_t sub_count;
+};
+typedef struct _import_subcount_trawl_info import_subcount_trawl_info;
+
+static void import_subcount_trawl_add(import_subcount_trawl_info **list, ID id)
+{
+ import_subcount_trawl_info *new_info = CALLOC(import_subcount_trawl_info);
+
+ new_info->next = *list;
+ new_info->id = id;
+ *list = new_info;
+}
+
+static int import_subcount_trawl(backend *be, import_subcount_trawl_info *trawl_list)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ ID id = 1;
+ int ret = 0;
+ import_subcount_trawl_info *current = NULL;
+ char value_buffer[20]; /* enough digits for 2^64 children */
+
+ /* OK, we do */
+ /* We open id2entry and iterate through it */
+ /* Foreach entry, we check to see if its parentID matches any of the
+ * values in the trawl list . If so, we bump the sub count for that
+ * parent in the list.
+ */
+ while (1) {
+ struct backentry *e = NULL;
+
+ /* Get the next entry */
+ e = id2entry(be,id,NULL,&ret);
+ if ( (NULL == e) || (0 != ret)) {
+ if (DB_NOTFOUND == ret) {
+ break;
+ } else {
+ ldbm_nasty(sourcefile,8,ret);
+ return ret;
+ }
+ }
+ for (current = trawl_list; current != NULL; current = current->next) {
+ sprintf(value_buffer,"%lu",(u_long)current->id);
+ if (slapi_entry_attr_hasvalue(e->ep_entry,"parentid",value_buffer)) {
+ /* If this entry's parent ID matches one we're trawling for,
+ * bump its count */
+ current->sub_count++;
+ }
+ }
+ /* Free the entry */
+ cache_remove(&inst->inst_cache, e);
+ cache_return(&inst->inst_cache, &e);
+ id++;
+ }
+ /* Now update the parent entries from the list */
+ for (current = trawl_list; current != NULL; current = current->next) {
+ /* Update the parent entry with the correctly counted subcount */
+ ret = import_update_entry_subcount(be,current->id,current->sub_count);
+ if (0 != ret) {
+ ldbm_nasty(sourcefile,10,ret);
+ break;
+ }
+ }
+ return ret;
+}
+
+/*
+ * Function: update_subordinatecounts
+ *
+ * Returns: Nothing
+ *
+ */
+int update_subordinatecounts(backend *be, import_subcount_stuff *mothers,
+ DB_TXN *txn)
+{
+ int ret = 0;
+ DB *db = NULL;
+ DBC *dbc = NULL;
+ struct attrinfo *ai = NULL;
+ DBT key = {0};
+ DBT data = {0};
+ import_subcount_trawl_info *trawl_list = NULL;
+
+ /* Open the parentid index */
+ ainfo_get( be, "parentid", &ai );
+
+ /* Open the parentid index file */
+ if ( (ret = dblayer_get_index_file( be, ai, &db, DBOPEN_CREATE )) != 0 ) {
+ ldbm_nasty(sourcefile,67,ret);
+ return(ret);
+ }
+
+ /* Get a cursor so we can walk through the parentid */
+ ret = db->cursor(db,txn,&dbc,0);
+ if (ret != 0 ) {
+ ldbm_nasty(sourcefile,68,ret);
+ dblayer_release_index_file( be, ai, db );
+ return ret;
+ }
+
+ /* Walk along the index */
+ while (1) {
+ size_t sub_count = 0;
+ int found_count = 1;
+ ID parentid = 0;
+
+ /* Foreach key which is an equality key : */
+ data.flags = DB_DBT_MALLOC;
+ key.flags = DB_DBT_MALLOC;
+ ret = dbc->c_get(dbc,&key,&data,DB_NEXT_NODUP);
+ if (NULL != data.data) {
+ free(data.data);
+ data.data = NULL;
+ }
+ if (0 != ret) {
+ if (ret != DB_NOTFOUND) {
+ ldbm_nasty(sourcefile,62,ret);
+ }
+ if (NULL != key.data) {
+ free(key.data);
+ key.data = NULL;
+ }
+ break;
+ }
+ if (*(char*)key.data == EQ_PREFIX) {
+ char *idptr = NULL;
+
+ /* construct the parent's ID from the key */
+ /* Look for the ID in the hint list supplied by the caller */
+ /* If its there, we know the answer already */
+ idptr = (((char *) key.data) + 1);
+ parentid = (ID) atol(idptr);
+ PR_ASSERT(0 != parentid);
+ ret = import_subcount_mothers_lookup(mothers,parentid,&sub_count);
+ if (0 != ret) {
+ IDList *idl = NULL;
+
+ /* If it's not, we need to compute it ourselves: */
+ /* Load the IDL matching the key */
+ key.flags = DB_DBT_REALLOC;
+ ret = NEW_IDL_NO_ALLID;
+ idl = idl_fetch(be,db,&key,NULL,NULL,&ret);
+ if ( (NULL == idl) || (0 != ret)) {
+ ldbm_nasty(sourcefile,4,ret);
+ dblayer_release_index_file( be, ai, db );
+ return (0 == ret) ? -1 : ret;
+ }
+ /* The number of IDs in the IDL tells us the number of
+ * subordinates for the entry */
+ /* Except, the number might be above the allidsthreshold,
+ * in which case */
+ if (ALLIDS(idl)) {
+ /* We add this ID to the list for which to trawl */
+ import_subcount_trawl_add(&trawl_list,parentid);
+ found_count = 0;
+ } else {
+ /* We get the count from the IDL */
+ sub_count = idl->b_nids;
+ }
+ idl_free(idl);
+ }
+ /* Did we get the count ? */
+ if (found_count) {
+ PR_ASSERT(0 != sub_count);
+ /* If so, update the parent now */
+ import_update_entry_subcount(be,parentid,sub_count);
+ }
+ }
+ if (NULL != key.data) {
+ free(key.data);
+ key.data = NULL;
+ }
+ }
+
+ ret = dbc->c_close(dbc);
+ if (0 != ret) {
+ ldbm_nasty(sourcefile,6,ret);
+ }
+ dblayer_release_index_file( be, ai, db );
+
+ /* Now see if we need to go trawling through id2entry for the info
+ * we need */
+ if (NULL != trawl_list) {
+ ret = import_subcount_trawl(be,trawl_list);
+ if (0 != ret) {
+ ldbm_nasty(sourcefile,7,ret);
+ }
+ }
+ return(ret);
+}
+
+
+/********** ldif2db entry point **********/
+
+/*
+ Some notes about this stuff:
+
+ The front-end does call our init routine before calling us here.
+ So, we get the regular chance to parse the config file etc.
+ However, it does _NOT_ call our start routine, so we need to
+ do whatever work that did and which we need for this work , here.
+ Furthermore, the front-end simply exits after calling us, so we need
+ to do any cleanup work here also.
+ */
+
+/*
+ * ldbm_back_ldif2ldbm - backend routine to convert an ldif file to
+ * a database.
+ */
+int ldbm_back_ldif2ldbm( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li;
+ ldbm_instance *inst = NULL;
+ char *instance_name;
+ int ret, task_flags;
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_BACKEND_INSTANCE_NAME, &instance_name );
+
+ /* BEGIN complex dependencies of various initializations. */
+ /* hopefully this will go away once import is not run standalone... */
+
+ slapi_pblock_get(pb, SLAPI_TASK_FLAGS, &task_flags);
+ if (task_flags & TASK_RUNNING_FROM_COMMANDLINE) {
+ li->li_flags |= TASK_RUNNING_FROM_COMMANDLINE;
+ ldbm_config_load_dse_info(li);
+ autosize_import_cache(li);
+ }
+
+ /* Find the instance that the ldif2db will be done on. */
+ inst = ldbm_instance_find_by_name(li, instance_name);
+ if (NULL == inst) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Unknown ldbm instance %s\n", instance_name,
+ 0, 0);
+ return -1;
+ }
+
+ /* check if an import/restore is already ongoing... */
+ if (instance_set_busy(inst) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: '%s' is already in the middle of "
+ "another task and cannot be disturbed.\n",
+ inst->inst_name, 0, 0);
+ return -1;
+ }
+
+ /***** prepare & init libdb and dblayer *****/
+
+ if (! (task_flags & TASK_RUNNING_FROM_COMMANDLINE)) {
+ /* shutdown this instance of the db */
+ LDAPDebug(LDAP_DEBUG_ANY, "Bringing %s offline...\n",
+ instance_name, 0, 0);
+ slapi_mtn_be_disable(inst->inst_be);
+
+ cache_clear(&inst->inst_cache);
+ dblayer_instance_close(inst->inst_be);
+ dblayer_delete_indices(inst);
+ } else {
+ /* from the command line, libdb needs to be started up */
+ ldbm_config_internal_set(li, CONFIG_DB_TRANSACTION_LOGGING, "off");
+
+ if (0 != (ret = dblayer_start(li, DBLAYER_IMPORT_MODE)) ) {
+ if (LDBM_OS_ERR_IS_DISKFULL(ret)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: Failed to init database. "
+ "There is either insufficient disk space or "
+ "insufficient memory available to initialize the "
+ "database.\n", 0, 0, 0);
+ LDAPDebug(LDAP_DEBUG_ANY,"Please check that\n"
+ "1) disks are not full,\n"
+ "2) no file exceeds the file size limit,\n"
+ "3) the configured dbcachesize is not too large for the available memory on this machine.\n",
+ 0, 0, 0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: Failed to init database "
+ "(error %d: %s)\n", ret, dblayer_strerror(ret), 0);
+ }
+ goto fail;
+ }
+ }
+
+ /* Delete old database files */
+ dblayer_delete_instance_dir(inst->inst_be);
+ /* it's okay to fail -- the directory might have already been deleted */
+
+ /* dblayer_instance_start will init the id2entry index. */
+ /* it also (finally) fills in inst_dir_name */
+ ret = dblayer_instance_start(inst->inst_be, DBLAYER_IMPORT_MODE);
+ if (ret != 0) {
+ goto fail;
+ }
+
+ vlv_init(inst);
+
+ /***** done init libdb and dblayer *****/
+
+ /* always use "new" import code now */
+ slapi_pblock_set(pb, SLAPI_BACKEND, inst->inst_be);
+ return ldbm_back_ldif2ldbm_deluxe(pb);
+
+fail:
+ /* DON'T enable the backend -- leave it offline */
+ instance_set_not_busy(inst);
+ return ret;
+}
+
+
+/********** db2ldif, db2index **********/
+
+
+/* fetch an IDL for the series of subtree specs */
+/* (used for db2ldif) */
+static IDList *ldbm_fetch_subtrees(backend *be, char **include, int *err)
+{
+ int i;
+ ID id;
+ IDList *idltotal = NULL, *idltmp;
+ back_txn *txn = NULL;
+ struct berval bv;
+
+ /* for each subtree spec... */
+ for (i = 0; include[i]; i++) {
+ IDList *idl = NULL;
+
+ /*
+ * First map the suffix to its entry ID.
+ * Note that the suffix is already normalized.
+ */
+ bv.bv_val = include[i];
+ bv.bv_len = strlen(include[i]);
+ idl = index_read(be, "entrydn", indextype_EQUALITY, &bv, txn, err);
+ if (idl == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "warning: entrydn not indexed on '%s'\n",
+ include[i], 0, 0);
+ continue;
+ }
+ id = idl_firstid(idl);
+ idl_free(idl);
+ idl = NULL;
+
+ /*
+ * Now get all the descendants of that suffix.
+ */
+ *err = ldbm_ancestorid_read(be, txn, id, &idl);
+ if (idl == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "warning: ancestorid not indexed on %lu\n",
+ id, 0, 0);
+ continue;
+ }
+
+ /* Insert the suffix itself */
+ idl_insert(&idl, id);
+
+ /* Merge the idlists */
+ if (! idltotal) {
+ idltotal = idl;
+ } else if (idl) {
+ idltmp = idl_union(be, idltotal, idl);
+ idl_free(idltotal);
+ idl_free(idl);
+ idltotal = idltmp;
+ }
+ }
+
+ return idltotal;
+}
+
+#define FD_STDOUT 1
+
+
+/*
+ * ldbm_back_ldbm2ldif - backend routine to convert database to an
+ * ldif file.
+ * (reunified at last)
+ */
+int
+ldbm_back_ldbm2ldif( Slapi_PBlock *pb )
+{
+ backend *be;
+ struct ldbminfo *li = NULL;
+ DB *db = NULL;
+ DBC *dbc = NULL;
+ struct backentry *ep;
+ DBT key = {0};
+ DBT data = {0};
+ char *type, *fname = NULL;
+ int len, printkey, rc, ok_index;
+ int return_value = 0;
+ int nowrap = 0;
+ int nobase64 = 0;
+ NIDS idindex = 0;
+ ID temp_id;
+ char **exclude_suffix = NULL;
+ char **include_suffix = NULL;
+ int decrypt = 0;
+ int dump_replica = 0;
+ int dump_uniqueid = 1;
+ int fd;
+ IDList *idl = NULL; /* optimization for -s include lists */
+ int cnt = 0, lastcnt = 0;
+ int options = 0;
+ int keepgoing = 1;
+ int isfirst = 1;
+ int appendmode = 0;
+ int appendmode_1 = 0;
+ int noversion = 0;
+ ID lastid;
+ int task_flags;
+ Slapi_Task *task;
+ int run_from_cmdline = 0;
+ char *instance_name;
+ ldbm_instance *inst;
+ int str2entry_options= 0;
+ int retry;
+ int we_start_the_backends = 0;
+ int server_running;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldbm_back_ldbm2ldif\n", 0, 0, 0 );
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_TASK_FLAGS, &task_flags );
+ slapi_pblock_get( pb, SLAPI_DB2LDIF_DECRYPT, &decrypt );
+ slapi_pblock_get( pb, SLAPI_DB2LDIF_SERVER_RUNNING, &server_running );
+ run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE);
+
+ dump_replica = pb->pb_ldif_dump_replica;
+ if (run_from_cmdline) {
+ li->li_flags |= TASK_RUNNING_FROM_COMMANDLINE;
+ if (!dump_replica) {
+ we_start_the_backends = 1;
+ }
+ }
+
+ if (we_start_the_backends) {
+ /* No ldbm be's exist until we process the config information. */
+
+ /*
+ * Note that we should only call this once. If we're
+ * dumping several backends then it gets called multiple
+ * times and we get warnings in the error log like this:
+ * WARNING: ldbm instance NetscapeRoot already exists
+ */
+ ldbm_config_load_dse_info(li);
+ }
+
+ if (run_from_cmdline && li->li_dblayer_private->dblayer_private_mem
+ && server_running)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Cannot export the database while the server is running and "
+ "nsslapd-db-private-mem option is used, "
+ "please use ldif2db.pl\n", 0, 0, 0);
+ return_value = -1;
+ goto bye;
+ }
+
+ if (run_from_cmdline) {
+
+ /* Now that we have processed the config information, we look for
+ * the be that should do the db2ldif. */
+ slapi_pblock_get(pb, SLAPI_BACKEND_INSTANCE_NAME, &instance_name);
+ inst = ldbm_instance_find_by_name(li, instance_name);
+ if (NULL == inst) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Unknown ldbm instance %s\n",
+ instance_name, 0, 0);
+ return_value = -1;
+ goto bye;
+ }
+ /* [605974] command db2ldif should not be able to run when on-line
+ * import is running */
+ if (dblayer_in_import(inst)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "instance %s is busy\n",
+ instance_name, 0, 0);
+ return_value = -1;
+ goto bye;
+ }
+
+ /* store the be in the pb */
+ be = inst->inst_be;
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ } else {
+ slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+ inst = (ldbm_instance *)be->be_instance_info;
+
+ if (NULL == inst) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Unknown ldbm instance\n", 0, 0, 0);
+ return_value = -1;
+ goto bye;
+ }
+
+ /* check if an import/restore is already ongoing... */
+ if (instance_set_busy(inst) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: '%s' is already in the middle"
+ " of another task and cannot be disturbed.\n",
+ inst->inst_name, 0, 0);
+ return_value = -1;
+ goto bye;
+ }
+ }
+
+ slapi_pblock_get( pb, SLAPI_BACKEND_TASK, &task );
+
+ ldbm_back_fetch_incl_excl(pb, &include_suffix, &exclude_suffix);
+
+ str2entry_options= (dump_replica?0:SLAPI_STR2ENTRY_TOMBSTONE_CHECK);
+
+ slapi_pblock_get( pb, SLAPI_DB2LDIF_FILE, &fname );
+ slapi_pblock_get( pb, SLAPI_DB2LDIF_PRINTKEY, &printkey );
+ slapi_pblock_get( pb, SLAPI_DB2LDIF_DUMP_UNIQUEID, &dump_uniqueid );
+
+ /* tsk, overloading printkey. shame on me. */
+ ok_index = !(printkey & EXPORT_ID2ENTRY_ONLY);
+ printkey &= ~EXPORT_ID2ENTRY_ONLY;
+
+ nobase64 = (printkey & EXPORT_MINIMAL_ENCODING);
+ printkey &= ~EXPORT_MINIMAL_ENCODING;
+ nowrap = (printkey & EXPORT_NOWRAP);
+ printkey &= ~EXPORT_NOWRAP;
+ appendmode = (printkey & EXPORT_APPENDMODE);
+ printkey &= ~EXPORT_APPENDMODE;
+ appendmode_1 = (printkey & EXPORT_APPENDMODE_1);
+ printkey &= ~EXPORT_APPENDMODE_1;
+ noversion = (printkey & EXPORT_NOVERSION);
+ printkey &= ~EXPORT_NOVERSION;
+
+ /* decide whether to dump uniqueid */
+ if (dump_uniqueid)
+ options |= SLAPI_DUMP_UNIQUEID;
+ if (nowrap)
+ options |= SLAPI_DUMP_NOWRAP;
+ if (nobase64)
+ options |= SLAPI_DUMP_MINIMAL_ENCODING;
+ if (dump_replica)
+ options |= SLAPI_DUMP_STATEINFO;
+
+ if (fname == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "db2ldif: no LDIF filename supplied\n",
+ 0, 0, 0);
+ return_value = -1;
+ goto bye;
+ }
+
+ if (strcmp(fname, "-")) { /* not '-' */
+ if (appendmode) {
+ if (appendmode_1) {
+ fd = dblayer_open_huge_file(fname, O_WRONLY|O_CREAT|O_TRUNC,
+ SLAPD_DEFAULT_FILE_MODE);
+ } else {
+ fd = dblayer_open_huge_file(fname, O_WRONLY|O_CREAT|O_APPEND,
+ SLAPD_DEFAULT_FILE_MODE);
+ }
+ } else {
+ /* open it */
+ fd = dblayer_open_huge_file(fname, O_WRONLY|O_CREAT|O_TRUNC,
+ SLAPD_DEFAULT_FILE_MODE);
+ }
+ if (fd < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "db2ldif: can't open %s: %d (%s)\n",
+ fname, errno, dblayer_strerror(errno));
+ return_value = -1;
+ goto bye;
+ }
+ } else { /* '-' */
+ fd = FD_STDOUT;
+ }
+
+ if ( we_start_the_backends ) {
+ if (0 != dblayer_start(li,DBLAYER_EXPORT_MODE)) {
+ LDAPDebug( LDAP_DEBUG_ANY, "db2ldif: Failed to init database\n",
+ 0, 0, 0 );
+ return_value = -1;
+ goto bye;
+ }
+ /* dblayer_instance_start will init the id2entry index. */
+ if (0 != dblayer_instance_start(be, DBLAYER_EXPORT_MODE)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "db2ldif: Failed to init instance\n",
+ 0, 0, 0);
+ return_value = -1;
+ goto bye;
+ }
+ }
+
+ /* idl manipulation requires nextid to be init'd now */
+ if (include_suffix && ok_index)
+ get_ids_from_disk(be);
+
+ if ((( dblayer_get_id2entry( be, &db )) != 0) || (db == NULL)) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Could not open/create id2entry\n",
+ 0, 0, 0 );
+ ldbm_back_free_incl_excl(include_suffix, exclude_suffix);
+ return_value = -1;
+ goto bye;
+ }
+
+ /* if an include_suffix was given (and we're pretty sure the
+ * entrydn and ancestorid indexes are valid), we try to
+ * assemble an id-list of candidates instead of plowing thru
+ * the whole database. this is a big performance improvement
+ * when exporting config info (which is usually on the order
+ * of 100 entries) from a database that may be on the order of
+ * GIGS in size.
+ */
+ {
+ /* Here, we assume that the table is ordered in EID-order,
+ * which it is !
+ */
+ /* get a cursor to we can walk over the table */
+ return_value = db->cursor(db,NULL,&dbc,0);
+ if (0 != return_value ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Failed to get cursor for db2ldif\n",
+ 0, 0, 0 );
+ ldbm_back_free_incl_excl(include_suffix, exclude_suffix);
+ return_value = -1;
+ goto bye;
+ }
+ key.flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ return_value = dbc->c_get(dbc,&key,&data,DB_LAST);
+ if (0 != return_value) {
+ keepgoing = 0;
+ } else {
+ lastid = id_stored_to_internal((char *)key.data);
+ free( key.data );
+ free( data.data );
+ isfirst = 1;
+ }
+ }
+ if (include_suffix && ok_index && !dump_replica) {
+ int err;
+
+ idl = ldbm_fetch_subtrees(be, include_suffix, &err);
+ if (! idl) {
+ /* most likely, indexes are bad. */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Failed to fetch subtree lists (error %d) %s\n",
+ err, dblayer_strerror(err), 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Possibly the entrydn or ancestorid index is corrupted or "
+ "does not exist.\n", 0, 0, 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Attempting direct unindexed export instead.\n",
+ 0, 0, 0);
+ ok_index = 0;
+ idl = NULL;
+ } else if (ALLIDS(idl)) {
+ /* allids list is no help at all -- revert to trawling
+ * the whole list. */
+ ok_index = 0;
+ idl_free(idl);
+ idl = NULL;
+ }
+ idindex = 0;
+ }
+
+ /* When user has specifically asked not to print the version
+ * or when this is not the first backend that is append into
+ * this file : don't print the version
+ */
+ if ((!noversion) && ((!appendmode) || (appendmode_1))) {
+ char vstr[64];
+ int myversion = 1; /* XXX: ldif version;
+ * needs to be modified when version
+ * control begins.
+ */
+
+ sprintf(vstr, "version: %d\n\n", myversion);
+ write(fd, vstr, strlen(vstr));
+ }
+
+ while ( keepgoing ) {
+ Slapi_Attr *this_attr, *next_attr;
+
+ /*
+ * All database operations in a transactional environment,
+ * including non-transactional reads can receive a return of
+ * DB_LOCK_DEADLOCK. Which operation gets aborted depends
+ * on the deadlock detection policy, but can include
+ * non-transactional reads (in which case the single
+ * operation should just be retried).
+ */
+
+ if (idl) {
+ /* exporting from an ID list */
+ if (idindex >= idl->b_nids)
+ break;
+ id_internal_to_stored(idl->b_ids[idindex], (char *)&temp_id);
+ key.data = (char *)&temp_id;
+ key.size = sizeof(temp_id);
+ data.flags = DB_DBT_MALLOC;
+
+ for (retry = 0; retry < RETRY_TIMES; retry++) {
+ return_value = db->get(db, NULL, &key, &data, 0);
+ if (return_value != DB_LOCK_DEADLOCK) break;
+ }
+ if (return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY, "db2ldif: failed to read "
+ "entry %lu, err %d\n", (u_long)idl->b_ids[idindex],
+ return_value, 0);
+ return_value = -1;
+ break;
+ }
+ /* back to internal format: */
+ temp_id = idl->b_ids[idindex];
+ idindex++;
+ } else {
+ /* follow the cursor */
+ key.flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ if (isfirst) {
+ for (retry = 0; retry < RETRY_TIMES; retry++) {
+ return_value = dbc->c_get(dbc,&key,&data,DB_FIRST);
+ if (return_value != DB_LOCK_DEADLOCK) break;
+ }
+ isfirst = 0;
+ } else {
+ for (retry = 0; retry < RETRY_TIMES; retry++) {
+ return_value = dbc->c_get(dbc,&key,&data,DB_NEXT);
+ if (return_value != DB_LOCK_DEADLOCK) break;
+ }
+ }
+
+ if (0 != return_value)
+ break;
+
+ /* back to internal format */
+ temp_id = id_stored_to_internal((char *)key.data);
+ free(key.data);
+ }
+
+ /* call post-entry plugin */
+ plugin_call_entryfetch_plugins( (char **) &data.dptr, &data.dsize );
+
+ ep = backentry_alloc();
+ ep->ep_entry = slapi_str2entry( data.data, str2entry_options );
+ free(data.data);
+
+ if ( (ep->ep_entry) != NULL ) {
+ ep->ep_id = temp_id;
+ cnt++;
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "skipping badly formatted entry with id %lu\n",
+ (u_long)temp_id, 0, 0 );
+ backentry_free( &ep );
+ continue;
+ }
+ if (!ldbm_back_ok_to_dump(backentry_get_ndn(ep), include_suffix,
+ exclude_suffix)) {
+ backentry_free( &ep );
+ continue;
+ }
+ if(!dump_replica && slapi_entry_flag_is_set(ep->ep_entry, SLAPI_ENTRY_FLAG_TOMBSTONE))
+ {
+ /* We only dump the tombstones if the user needs to create a replica from the ldif */
+ backentry_free( &ep );
+ continue;
+ }
+
+
+ /* do not output attributes that are in the "exclude" list */
+ /* Also, decrypt any encrypted attributes, if we're asked to */
+ rc = slapi_entry_first_attr( ep->ep_entry, &this_attr );
+ while (0 == rc) {
+ rc = slapi_entry_next_attr( ep->ep_entry,
+ this_attr, &next_attr );
+ slapi_attr_get_type( this_attr, &type );
+ if ( ldbm_exclude_attr_from_export( li, type, dump_uniqueid )) {
+ slapi_entry_delete_values( ep->ep_entry, type, NULL );
+ }
+ this_attr = next_attr;
+ }
+ if (decrypt) {
+ /* Decrypt in place */
+ rc = attrcrypt_decrypt_entry(be, ep);
+ if (rc) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Failed to decrypt entry%s\n", ep->ep_entry->e_sdn , 0, 0);
+ }
+ }
+
+ data.data = slapi_entry2str_with_options( ep->ep_entry, &len, options );
+ data.size = len + 1;
+
+ if ( printkey & EXPORT_PRINTKEY ) {
+ char idstr[32];
+
+ sprintf(idstr, "# entry-id: %lu\n", (u_long)ep->ep_id);
+ write(fd, idstr, strlen(idstr));
+ }
+ write(fd, data.data, len);
+ write(fd, "\n", 1);
+ if (cnt % 1000 == 0) {
+ int percent;
+
+ if (idl) {
+ percent = (idindex*100 / idl->b_nids);
+ } else {
+ percent = (ep->ep_id*100 / lastid);
+ }
+ if (task != NULL) {
+ slapi_task_log_status(task,
+ "%s: Processed %d entries (%d%%).",
+ inst->inst_name, cnt, percent);
+ slapi_task_log_notice(task,
+ "%s: Processed %d entries (%d%%).",
+ inst->inst_name, cnt, percent);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "export %s: Processed %d entries (%d%%).\n",
+ inst->inst_name, cnt, percent);
+ lastcnt = cnt;
+ }
+
+ backentry_free( &ep );
+ free( data.data );
+ }
+ /* DB_NOTFOUND -> successful end */
+ if (return_value == DB_NOTFOUND)
+ return_value = 0;
+
+ /* done cycling thru entries to write */
+ if (lastcnt != cnt) {
+ if (task) {
+ slapi_task_log_status(task,
+ "%s: Processed %d entries (100%%).",
+ inst->inst_name, cnt);
+ slapi_task_log_notice(task,
+ "%s: Processed %d entries (100%%).",
+ inst->inst_name, cnt);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "export %s: Processed %d entries (100%%).\n",
+ inst->inst_name, cnt, 0);
+ }
+
+ if (idl) {
+ idl_free(idl);
+ }
+ if (dbc) {
+ dbc->c_close(dbc);
+ }
+
+ dblayer_release_id2entry( be, db );
+ ldbm_back_free_incl_excl(include_suffix, exclude_suffix);
+
+ if (fd != FD_STDOUT) {
+ close(fd);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldbm_back_ldbm2ldif\n", 0, 0, 0 );
+
+ if (we_start_the_backends && 0 != dblayer_flush(li)) {
+ LDAPDebug( LDAP_DEBUG_ANY, "db2ldif: Failed to flush database\n",
+ 0, 0, 0 );
+ }
+
+ if (we_start_the_backends) {
+ if (0 != dblayer_close(li,DBLAYER_EXPORT_MODE)) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "db2ldif: Failed to close database\n",
+ 0, 0, 0 );
+ }
+ } else if (run_from_cmdline && dump_replica) {
+ /*
+ * It should not be necessary to close the dblayer here.
+ * However it masks complex thread timing issues that
+ * prevent a correct shutdown of the plugins. Closing the
+ * dblayer here means we cannot dump multiple replicas
+ * using -r, but the server doesn't allow that either.
+ */
+
+ /*
+ * Use DBLAYER_NORMAL_MODE to match the value that was provided
+ * to dblayer_start() and ensure creation of the guardian file.
+ */
+ if (0 != dblayer_close(li,DBLAYER_NORMAL_MODE)) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "db2ldif: Failed to close database\n",
+ 0, 0, 0 );
+ }
+ }
+
+ if (!run_from_cmdline) {
+ instance_set_not_busy(inst);
+ }
+
+bye:
+ if (inst != NULL) {
+ PR_Lock(inst->inst_config_mutex);
+ inst->inst_flags &= ~INST_FLAG_BUSY;
+ PR_Unlock(inst->inst_config_mutex);
+ }
+
+ return( return_value );
+}
+
+
+static void ldbm2index_bad_vlv(Slapi_Task *task, ldbm_instance *inst,
+ char *index)
+{
+ char *text = vlv_getindexnames(inst->inst_be);
+
+ if (task) {
+ slapi_task_log_status(task, "%s: Unknown VLV index '%s'",
+ inst->inst_name, index);
+ slapi_task_log_notice(task, "%s: Unknown VLV index '%s'",
+ inst->inst_name, index);
+ slapi_task_log_notice(task, "%s: Known VLV indexes are: %s",
+ inst->inst_name, text);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm2index: Unknown VLV Index named '%s'\n", index, 0, 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm2index: Known VLV Indexes are: %s\n", text, 0, 0);
+ slapi_ch_free((void**)&text);
+}
+
+/*
+ * ldbm_back_ldbm2index - backend routine to create a new index from an
+ * existing database
+ */
+int
+ldbm_back_ldbm2index(Slapi_PBlock *pb)
+{
+ char *instance_name;
+ struct ldbminfo *li;
+ int task_flags, run_from_cmdline;
+ ldbm_instance *inst;
+ backend *be;
+ DB *db = NULL;
+ DBC *dbc = NULL;
+ char **indexAttrs = NULL;
+ struct vlvIndex **pvlv= NULL;
+ DBT key = {0};
+ DBT data = {0};
+ IDList *idl = NULL; /* optimization for vlv index creation */
+ int numvlv = 0;
+ int return_value = -1;
+ ID temp_id;
+ int i, j;
+ ID lastid;
+ struct backentry *ep;
+ char *type;
+ NIDS idindex = 0;
+ int count = 0;
+ Slapi_Attr *attr;
+ Slapi_Task *task;
+ int ret = 0;
+ int isfirst = 1;
+ int index_aid = 0; /* index ancestorid */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldbm_back_ldbm2index\n", 0, 0, 0 );
+
+ slapi_pblock_get(pb, SLAPI_BACKEND_INSTANCE_NAME, &instance_name);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li);
+ slapi_pblock_get(pb, SLAPI_TASK_FLAGS, &task_flags);
+ run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE);
+ slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &task);
+
+ if (run_from_cmdline) {
+ /* No ldbm backend exists until we process the config info. */
+ li->li_flags |= TASK_RUNNING_FROM_COMMANDLINE;
+ ldbm_config_load_dse_info(li);
+ }
+
+ inst = ldbm_instance_find_by_name(li, instance_name);
+ if (NULL == inst) {
+ if (task) {
+ slapi_task_log_notice(task, "Unknown ldbm instance %s",
+ instance_name, 0, 0);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY, "Unknown ldbm instance %s\n",
+ instance_name, 0, 0);
+ return -1;
+ }
+ be = inst->inst_be;
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+
+ /* would love to be able to turn off transactions here, but i don't
+ * think it's in the cards...
+ */
+ if (run_from_cmdline) {
+ /* Turn off transactions */
+ ldbm_config_internal_set(li, CONFIG_DB_TRANSACTION_LOGGING, "off");
+
+ if (0 != dblayer_start(li,DBLAYER_INDEX_MODE)) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ldbm2index: Failed to init database\n", 0, 0, 0 );
+ return( -1 );
+ }
+
+ /* dblayer_instance_start will init the id2entry index. */
+ if (0 != dblayer_instance_start(be, DBLAYER_INDEX_MODE)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "db2ldif: Failed to init instance\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ /* Initialise the Virtual List View code */
+ vlv_init(inst);
+ }
+
+ /* make sure no other tasks are going, and set the backend readonly */
+ if (instance_set_busy_and_readonly(inst) != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm: '%s' is already in the middle of "
+ "another task and cannot be disturbed.\n",
+ inst->inst_name, 0, 0);
+ return -1;
+ }
+
+ if ((( dblayer_get_id2entry( be, &db )) != 0 ) || (db == NULL)) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Could not open/create id2entry\n",
+ 0, 0, 0 );
+ instance_set_not_busy(inst);
+ return( -1 );
+ }
+
+ /* get a cursor to we can walk over the table */
+ return_value = db->cursor(db, NULL, &dbc, 0);
+ if (0 != return_value ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Failed to get cursor for ldbm2index\n", 0, 0, 0 );
+ dblayer_release_id2entry(be, db);
+ instance_set_not_busy(inst);
+ return( -1 );
+ }
+
+ /* ask for the last id so we can give cute percentages */
+ key.flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ return_value = dbc->c_get(dbc, &key, &data, DB_LAST);
+ if (return_value == DB_NOTFOUND) {
+ lastid = 0;
+ isfirst = 0; /* neither a first nor a last */
+ } else if (return_value == 0) {
+ lastid = id_stored_to_internal((char *)key.data);
+ free(key.data);
+ free(data.data);
+ isfirst = 1;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Failed to seek within id2entry (BAD %d)\n",
+ return_value, 0 ,0);
+ dbc->c_close(dbc);
+ dblayer_release_id2entry(be, db);
+ instance_set_not_busy(inst);
+ return( -1 );
+ }
+
+ /* Work out which indexes we should build */
+ /* explanation: for archaic reasons, the list of indexes is passed to
+ * ldif2index as a string list, where each string either starts with a
+ * 't' (normal index) or a 'T' (vlv index).
+ * example: "tcn" (normal index cn)
+ */
+ {
+ char **attrs = NULL;
+ struct vlvIndex *p = NULL;
+ struct attrinfo *ai = NULL;
+
+ slapi_pblock_get(pb, SLAPI_DB2INDEX_ATTRS, &attrs);
+ for (i = 0; attrs[i] != NULL; i++) {
+ switch(attrs[i][0]) {
+ case 't': /* attribute type to index */
+ db2index_add_indexed_attr(be, attrs[i]);
+ ainfo_get(be, attrs[i]+1, &ai);
+ /* the ai was added above, if it didn't already exist */
+ PR_ASSERT(ai != NULL);
+ if (strcasecmp(attrs[i]+1, "ancestorid") == 0) {
+ if (task) {
+ slapi_task_log_notice(task, "%s: Indexing ancestorid",
+ inst->inst_name);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: Indexing ancestorid\n",
+ inst->inst_name, 0, 0);
+ index_aid = 1;
+ } else {
+ charray_add(&indexAttrs, attrs[i]+1);
+ ai->ai_indexmask |= INDEX_OFFLINE;
+ if (task) {
+ slapi_task_log_notice(task, "%s: Indexing attribute: %s",
+ inst->inst_name, attrs[i]+1);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: Indexing attribute: %s\n",
+ inst->inst_name, attrs[i]+1, 0);
+ }
+ dblayer_erase_index_file(be, ai, i/* chkpt; 1st time only */);
+ break;
+ case 'T': /* VLV Search to index */
+ p = vlv_find_searchname((attrs[i])+1, be);
+ if (p == NULL) {
+ ldbm2index_bad_vlv(task, inst, attrs[i]+1);
+ ret = -1;
+ goto out;
+ } else {
+ vlvIndex_go_offline(p, be);
+ if (pvlv == NULL) {
+ pvlv = (struct vlvIndex **)slapi_ch_calloc(1,
+ sizeof(struct vlvIndex *));
+ } else {
+ pvlv = (struct vlvIndex **)slapi_ch_realloc((char*)pvlv,
+ (numvlv+1)*sizeof(struct vlvIndex *));
+ }
+ pvlv[numvlv] = p;
+ numvlv++;
+ /* Get rid of the index if it already exists */
+ PR_Delete(vlvIndex_filename(p));
+ if (task) {
+ slapi_task_log_notice(task, "%s: Indexing VLV: %s",
+ inst->inst_name, attrs[i]+1);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: Indexing VLV: %s\n",
+ inst->inst_name, attrs[i]+1, 0);
+ }
+ break;
+ }
+ }
+ }
+
+ /* if we're only doing vlv indexes, we can accomplish this with an
+ * idl composed from the ancestorid list, instead of traversing the
+ * entire database.
+ */
+ if (!indexAttrs && !index_aid && pvlv) {
+ int i, err;
+ char **suffix_list = NULL;
+
+ /* create suffix list */
+ for (i = 0; i < numvlv; i++) {
+ char *s = slapi_ch_strdup(slapi_sdn_get_dn(vlvIndex_getBase(pvlv[i])));
+
+ s = slapi_dn_normalize_case(s);
+ charray_add(&suffix_list, s);
+ }
+ idl = ldbm_fetch_subtrees(be, suffix_list, &err);
+ charray_free(suffix_list);
+ if (! idl) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: WARNING: Failed to fetch subtree lists: (%d) %s\n",
+ inst->inst_name, err, dblayer_strerror(err));
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Possibly the entrydn or ancestorid index is "
+ "corrupted or does not exist.\n", inst->inst_name, 0, 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Attempting brute-force method instead.\n",
+ inst->inst_name, 0, 0);
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: WARNING: Failed to fetch subtree lists (err %d) -- "
+ "attempting brute-force method instead.",
+ inst->inst_name, err);
+ }
+ } else if (ALLIDS(idl)) {
+ /* that's no help. */
+ idl_free(idl);
+ idl = NULL;
+ }
+ }
+
+ if (idl) {
+ /* don't need that cursor, we have a shopping list. */
+ dbc->c_close(dbc);
+ idindex = 0;
+ }
+
+ /* Bug 603120: slapd dumps core while indexing and deleting the db at the
+ * same time. Now added the lock for the indexing code too.
+ */
+ vlv_acquire_lock(be);
+ while (1) {
+ if (idl) {
+ if (idindex >= idl->b_nids)
+ break;
+ id_internal_to_stored(idl->b_ids[idindex], (char *)&temp_id);
+ key.data = (char *)&temp_id;
+ key.size = sizeof(temp_id);
+ data.flags = DB_DBT_MALLOC;
+
+ return_value = db->get(db, NULL, &key, &data, 0);
+ if (return_value) {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: Failed "
+ "to read database, errno=%d (%s)\n",
+ inst->inst_name, return_value,
+ dblayer_strerror(return_value));
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: Failed to read database, err %d (%s)",
+ inst->inst_name, return_value,
+ dblayer_strerror(return_value));
+ }
+ break;
+ }
+ /* back to internal format: */
+ temp_id = idl->b_ids[idindex];
+ idindex++;
+ } else {
+ key.flags = DB_DBT_MALLOC;
+ data.flags = DB_DBT_MALLOC;
+ if (isfirst) {
+ return_value = dbc->c_get(dbc, &key, &data, DB_FIRST);
+ isfirst = 0;
+ } else{
+ return_value = dbc->c_get(dbc, &key, &data, DB_NEXT);
+ }
+
+ if (0 != return_value) {
+ if (DB_NOTFOUND == return_value) {
+ break;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: Failed to read database, "
+ "errno=%d (%s)\n", inst->inst_name, return_value,
+ dblayer_strerror(return_value));
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: Failed to read database, err %d (%s)",
+ inst->inst_name, return_value,
+ dblayer_strerror(return_value));
+ }
+ break;
+ }
+ }
+ temp_id = id_stored_to_internal((char *)key.data);
+ free(key.data);
+ }
+
+ /* call post-entry plugin */
+ plugin_call_entryfetch_plugins( (char **) &data.dptr, &data.dsize );
+
+ ep = backentry_alloc();
+ ep->ep_entry = slapi_str2entry( data.data, 0 );
+ free(data.data);
+
+ if ( ep->ep_entry != NULL ) {
+ ep->ep_id = temp_id;
+ } else {
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: WARNING: skipping badly formatted entry (id %lu)",
+ inst->inst_name, (u_long)temp_id);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: WARNING: skipping badly formatted entry (id %lu)\n",
+ inst->inst_name, (u_long)temp_id, 0);
+ backentry_free( &ep );
+ continue;
+ }
+
+ if ( add_op_attrs( pb, li, ep, NULL ) != 0 ) {
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: ERROR: Could not add op attrs to entry (id %lu)",
+ inst->inst_name, (u_long)ep->ep_id);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: ERROR: Could not add op attrs to entry (id %lu)\n",
+ inst->inst_name, (u_long)ep->ep_id, 0);
+ backentry_free( &ep );
+ ret = -1;
+ goto out;
+ }
+
+ /*
+ * Update the attribute indexes
+ */
+ if (indexAttrs != NULL) {
+ for (i = slapi_entry_first_attr(ep->ep_entry, &attr); i == 0;
+ i = slapi_entry_next_attr(ep->ep_entry, attr, &attr)) {
+ Slapi_Value **svals;
+ int rc = 0;
+
+ slapi_attr_get_type( attr, &type );
+ for ( j = 0; indexAttrs[j] != NULL; j++ ) {
+ if (slapi_attr_type_cmp(indexAttrs[j], type,
+ SLAPI_TYPE_CMP_SUBTYPE) == 0 ) {
+ back_txn txn;
+ svals = attr_get_present_values(attr);
+
+ if (run_from_cmdline)
+ {
+ txn.back_txn_txn = NULL;
+ }
+ else
+ {
+ rc = dblayer_txn_begin(li, NULL, &txn);
+ if (0 != rc) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: ERROR: failed to begin txn for update "
+ "index '%s'\n",
+ inst->inst_name, indexAttrs[j], 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Error %d: %s\n", inst->inst_name, rc,
+ dblayer_strerror(rc));
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to begin txn for "
+ "update index '%s' (err %d: %s)",
+ inst->inst_name, indexAttrs[j], rc,
+ dblayer_strerror(rc));
+ }
+ ret = -2;
+ goto out;
+ }
+ }
+ rc = index_addordel_values_sv(
+ be, indexAttrs[j], svals,
+ NULL, ep->ep_id, BE_INDEX_ADD, &txn);
+ if (rc != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: ERROR: failed to update index '%s'\n",
+ inst->inst_name, indexAttrs[j], 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Error %d: %s\n", inst->inst_name, rc,
+ dblayer_strerror(rc));
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to update index '%s' "
+ "(err %d: %s)", inst->inst_name,
+ indexAttrs[j], rc, dblayer_strerror(rc));
+ }
+ if (!run_from_cmdline)
+ dblayer_txn_abort(li, &txn);
+ ret = -2;
+ goto out;
+ }
+ if (!run_from_cmdline)
+ {
+ rc = dblayer_txn_commit(li, &txn);
+ if (0 != rc) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: ERROR: failed to commit txn for "
+ "update index '%s'\n",
+ inst->inst_name, indexAttrs[j], 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Error %d: %s\n", inst->inst_name, rc,
+ dblayer_strerror(rc));
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to commit txn for "
+ "update index '%s' "
+ "(err %d: %s)", inst->inst_name,
+ indexAttrs[j], rc, dblayer_strerror(rc));
+ }
+ ret = -2;
+ goto out;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Update the Virtual List View indexes
+ */
+ for ( j = 0; j<numvlv; j++ ) {
+ back_txn txn;
+ int rc = 0;
+ if (run_from_cmdline)
+ {
+ txn.back_txn_txn = NULL;
+ }
+ else
+ if (!run_from_cmdline)
+ {
+ rc = dblayer_txn_begin(li, NULL, &txn);
+ if (0 != rc) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: ERROR: failed to begin txn for update index '%s'\n",
+ inst->inst_name, indexAttrs[j], 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Error %d: %s\n", inst->inst_name, rc,
+ dblayer_strerror(rc));
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to begin txn for update index '%s' "
+ "(err %d: %s)", inst->inst_name,
+ indexAttrs[j], rc, dblayer_strerror(rc));
+ }
+ ret = -2;
+ goto out;
+ }
+ }
+ vlv_update_index(pvlv[j], &txn, li, pb, NULL, ep);
+ if (!run_from_cmdline)
+ {
+ rc = dblayer_txn_commit(li, &txn);
+ if (0 != rc) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: ERROR: failed to commit txn for update index '%s'\n",
+ inst->inst_name, indexAttrs[j], 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Error %d: %s\n", inst->inst_name, rc,
+ dblayer_strerror(rc));
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to commit txn for update index '%s' "
+ "(err %d: %s)", inst->inst_name,
+ indexAttrs[j], rc, dblayer_strerror(rc));
+ }
+ ret = -2;
+ goto out;
+ }
+ }
+ }
+
+ /*
+ * Update the ancestorid index
+ */
+ if (index_aid) {
+ int rc;
+
+ rc = ldbm_ancestorid_index_entry(be, ep, BE_INDEX_ADD, NULL);
+ if (rc != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: ERROR: failed to update index 'ancestorid'\n",
+ inst->inst_name, 0, 0);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Error %d: %s\n", inst->inst_name, rc,
+ dblayer_strerror(rc));
+ if (task) {
+ slapi_task_log_notice(task,
+ "%s: ERROR: failed to update index 'ancestorid' "
+ "(err %d: %s)", inst->inst_name,
+ rc, dblayer_strerror(rc));
+ }
+ ret = -2;
+ goto out;
+ }
+ }
+
+ count++;
+ if ((count % 1000) == 0) {
+ int percent;
+
+ if (idl) {
+ percent = (idindex*100 / (idl->b_nids ? idl->b_nids : 1));
+ } else {
+ percent = (ep->ep_id*100 / (lastid ? lastid : 1));
+ }
+ if (task) {
+ task->task_progress = (idl ? idindex : ep->ep_id);
+ task->task_work = (idl ? idl->b_nids : lastid);
+ slapi_task_status_changed(task);
+ slapi_task_log_status(task, "%s: Indexed %d entries (%d%%).",
+ inst->inst_name, count, percent);
+ slapi_task_log_notice(task, "%s: Indexed %d entries (%d%%).",
+ inst->inst_name, count, percent);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: Indexed %d entries (%d%%).\n",
+ inst->inst_name, count, percent);
+ }
+
+ backentry_free( &ep );
+ }
+ vlv_release_lock(be);
+
+ /* if we got here, we finished successfully */
+
+ /* activate all the indexes we added */
+ for (i = 0; indexAttrs && indexAttrs[i]; i++) {
+ struct attrinfo *ai = NULL;
+
+ ainfo_get(be, indexAttrs[i], &ai);
+ PR_ASSERT(ai != NULL);
+ ai->ai_indexmask &= ~INDEX_OFFLINE;
+ }
+ for (i = 0; i < numvlv; i++) {
+ vlvIndex_go_online(pvlv[i], be);
+ }
+
+ if (task) {
+ slapi_task_log_status(task, "%s: Finished indexing.",
+ inst->inst_name);
+ slapi_task_log_notice(task, "%s: Finished indexing.",
+ inst->inst_name);
+ }
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: Finished indexing.\n",
+ inst->inst_name, 0, 0);
+
+out:
+ if (idl) {
+ idl_free(idl);
+ } else {
+ dbc->c_close(dbc);
+ }
+ dblayer_release_id2entry( be, db );
+
+ instance_set_not_busy(inst);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldbm_back_ldbm2index\n", 0, 0, 0 );
+
+ if (run_from_cmdline) {
+ if (0 != dblayer_flush(li)) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Failed to flush database\n", inst->inst_name, 0, 0);
+ }
+ dblayer_instance_close(be);
+ if (0 != dblayer_close(li,DBLAYER_INDEX_MODE)) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: Failed to close database\n", inst->inst_name, 0, 0);
+ }
+ }
+
+ if (indexAttrs) {
+ slapi_ch_free((void **)&indexAttrs);
+ }
+
+ return (ret);
+}
+
+/*
+ * The db2index mode of slapd accepts commandline specification of
+ * an attribute to be indexed and the types of indexes to be created.
+ * The format is:
+ * (ns-)slapd db2index -tattributeName[:indextypes[:matchingrules]]
+ * where indextypes and matchingrules(OIDs) are comma separated lists
+ * e.g.,
+ * -tuid:eq,pres
+ * -tuid:sub:2.1.15.17.blah
+ */
+static int
+db2index_add_indexed_attr(backend *be, char *attrString)
+{
+ char *iptr = NULL;
+ char *mptr = NULL;
+ char *nsslapd_index_value[4];
+ int argc = 0;
+ int i;
+
+ if (NULL == (iptr = strchr(attrString, ':'))) {
+ return(0);
+ }
+ iptr[0] = '\0';
+ iptr++;
+
+ nsslapd_index_value[argc++] = slapi_ch_strdup(attrString+1);
+
+ if (NULL != (mptr = strchr(iptr, ':'))) {
+ mptr[0] = '\0';
+ mptr++;
+ }
+ nsslapd_index_value[argc++] = slapi_ch_strdup(iptr);
+ if (NULL != mptr) {
+ nsslapd_index_value[argc++] = slapi_ch_strdup(mptr);
+ }
+ nsslapd_index_value[argc] = NULL;
+ attr_index_config(be, "from db2index()", 0, argc, nsslapd_index_value, 0);
+
+ for ( i=0; i<argc; i++ ) {
+ slapi_ch_free((void **)&nsslapd_index_value[i]);
+ }
+ return(0);
+}
+
+
+/*
+ * Determine if the given normalized 'attr' is to be excluded from LDIF
+ * exports.
+ *
+ * Returns a non-zero value if:
+ * 1) The 'attr' is in the configured list of attribute types that
+ * are to be excluded.
+ * OR 2) dump_uniqueid is non-zero and 'attr' is the unique ID attribute.
+ *
+ * Return 0 if the attribute is not to be excluded.
+ */
+static int
+ldbm_exclude_attr_from_export( struct ldbminfo *li , const char *attr,
+ int dump_uniqueid )
+
+{
+ int i, rc = 0;
+
+ if ( !dump_uniqueid && 0 == strcasecmp( SLAPI_ATTR_UNIQUEID, attr )) {
+ rc = 1; /* exclude */
+
+ } else if ( NULL != li && NULL != li->li_attrs_to_exclude_from_export ) {
+ for ( i = 0; li->li_attrs_to_exclude_from_export[i] != NULL; ++i ) {
+ if ( 0 == strcasecmp( li->li_attrs_to_exclude_from_export[i],
+ attr )) {
+ rc = 1; /* exclude */
+ break;
+ }
+ }
+ }
+
+ return( rc );
+}
+
+#if defined(UPGRADEDB)
+/*
+ * ldbm_back_upgradedb -
+ *
+ * functions to convert idl from the old format to the new one
+ * (604921) Support a database uprev process any time post-install
+ */
+
+void upgradedb_core(Slapi_PBlock *pb, ldbm_instance *inst);
+int upgradedb_copy_logfiles(struct ldbminfo *li, char *destination_dir, int restore, int *cnt);
+int upgradedb_delete_indices_4cmd(ldbm_instance *inst);
+void normalize_dir(char *dir);
+
+/*
+ * ldbm_back_upgradedb -
+ * check the DB version and if it's old idl'ed index,
+ * then reindex using new idl.
+ *
+ * standalone only -- not allowed to run while DS is up.
+ */
+int ldbm_back_upgradedb(Slapi_PBlock *pb)
+{
+ struct ldbminfo *li;
+ Object *inst_obj = NULL;
+ ldbm_instance *inst = NULL;
+ int run_from_cmdline = 0;
+ int task_flags = 0;
+ int server_running = 0;
+ int rval = 0;
+ int backup_rval = 0;
+ char *dest_dir = NULL;
+ char *orig_dest_dir = NULL;
+ char *home_dir = NULL;
+ int up_flags;
+ int i;
+ Slapi_Task *task;
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = NULL;
+
+ slapi_pblock_get(pb, SLAPI_SEQ_TYPE, &up_flags);
+ slapi_log_error(SLAPI_LOG_TRACE, "upgrade DB", "Reindexing all...\n");
+ slapi_pblock_get(pb, SLAPI_TASK_FLAGS, &task_flags);
+ slapi_pblock_get(pb, SLAPI_BACKEND_TASK, &task);
+ slapi_pblock_get(pb, SLAPI_DB2LDIF_SERVER_RUNNING, &server_running);
+
+ run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &li);
+ if (run_from_cmdline)
+ {
+ if (!(up_flags & SLAPI_UPGRADEDB_SKIPINIT))
+ {
+ ldbm_config_load_dse_info(li);
+ }
+ autosize_import_cache(li);
+ }
+ else
+ {
+ Object *inst_obj, *inst_obj2;
+ ldbm_instance *inst = NULL;
+
+ /* server is up -- mark all backends busy */
+ slapi_log_error(SLAPI_LOG_TRACE, "upgrade DB",
+ "server is up -- marking all LDBM backends busy\n");
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj))
+ {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ /* check if an import/restore is already ongoing... */
+ /* BUSY flag is cleared at the end of import_main (join thread);
+ it should not cleared in this thread [610347] */
+ if (instance_set_busy(inst) != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "ldbm: '%s' is already in the middle of "
+ "another task and cannot be disturbed.\n",
+ inst->inst_name);
+ if (task)
+ {
+ slapi_task_log_notice(task,
+ "Backend '%s' is already in the middle of "
+ "another task and cannot be disturbed.\n",
+ inst->inst_name);
+ }
+
+ /* painfully, we have to clear the BUSY flags on the
+ * backends we'd already marked...
+ */
+ for (inst_obj2 = objset_first_obj(li->li_instance_set);
+ inst_obj2 && (inst_obj2 != inst_obj);
+ inst_obj2 = objset_next_obj(li->li_instance_set, inst_obj2))
+ {
+ inst = (ldbm_instance *)object_get_data(inst_obj2);
+ instance_set_not_busy(inst);
+ }
+ object_release(inst_obj2);
+ object_release(inst_obj);
+ return -1;
+ }
+ }
+ }
+
+ inst_obj = objset_first_obj(li->li_instance_set);
+ if (inst_obj)
+ {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ if (!(up_flags & SLAPI_UPGRADEDB_FORCE))
+ { /* upgrade idl to new */
+ li->li_flags |= LI_FORCE_MOD_CONFIG;
+ /* set new idl */
+ ldbm_config_internal_set(li, CONFIG_IDL_SWITCH, "new");
+ /* First check the dbversion */
+ rval = check_db_inst_version(inst);
+ if (!(DBVERSION_NEED_IDL_OLD2NEW & rval))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Index version is up-to-date\n");
+ return 0;
+ }
+ }
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL,
+ "upgrade DB", "No instance to be upgraded\n");
+ return -1;
+ }
+
+ /* we are going to go forward */
+ /*
+ * First, backup index files and checkpoint log files
+ * since the server is not up and running, we can just copy them.
+ */
+ slapi_pblock_get( pb, SLAPI_SEQ_VAL, &dest_dir );
+ if (NULL == dest_dir)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Backup directory is not specified.\n");
+ return -1;
+ }
+
+ {
+ int cnt = 0;
+ PRFileInfo info;
+
+ orig_dest_dir = dest_dir;
+ normalize_dir(dest_dir);
+ /* clean up the backup dir first, then create it */
+ rval = PR_GetFileInfo(dest_dir, &info);
+ if (PR_SUCCESS == rval)
+ {
+ if (PR_FILE_DIRECTORY == info.type) /* directory exists */
+ {
+ time_t tm = time(0); /* long */
+
+ char *tmpname = (char *)slapi_ch_malloc(strlen(dest_dir) + 32);
+ sprintf(tmpname, "%s/%d", dest_dir, tm);
+ dest_dir = tmpname;
+ }
+ else /* not a directory */
+ PR_Delete(dest_dir);
+ }
+
+ if (mkdir_p(dest_dir, 0700) < 0)
+ goto fail0;
+
+ while (1)
+ {
+ inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ inst_dir, MAXPATHLEN);
+ backup_rval = dblayer_copy_directory(li, NULL /* task */,
+ inst_dirp, dest_dir, 0/*backup*/,
+ &cnt, 0, 1);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ if (backup_rval < 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Warning: Failed to backup index files (instance %s).\n",
+ inst_dirp);
+ goto fail1;
+ }
+
+ /* delete index files to be reindexed */
+ if (run_from_cmdline)
+ {
+ if (0 != upgradedb_delete_indices_4cmd(inst))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Can't clean up indices in %s\n", inst->inst_dir_name);
+ goto fail1;
+ }
+ }
+ else
+ {
+ if (0 != dblayer_delete_indices(inst))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Can't clean up indices in %s\n", inst->inst_dir_name);
+ goto fail1;
+ }
+ }
+
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj);
+ if (NULL == inst_obj)
+ break;
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ }
+
+ /* copy checkpoint logs */
+ backup_rval += upgradedb_copy_logfiles(li, dest_dir, 0, &cnt);
+ }
+
+ if (run_from_cmdline)
+ ldbm_config_internal_set(li, CONFIG_DB_TRANSACTION_LOGGING, "off");
+
+ inst_obj = objset_first_obj(li->li_instance_set);
+ for (i = 0; NULL != inst_obj; i++)
+ {
+ if (run_from_cmdline)
+ {
+ /* need to call dblayer_start for each instance,
+ since dblayer_close is called in upgradedb_core =>
+ ldbm_back_ldif2ldbm_deluxe */
+ if (0 != dblayer_start(li, DBLAYER_IMPORT_MODE))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "upgradedb: Failed to init database\n");
+ goto fail1;
+ }
+ }
+
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ slapi_pblock_set(pb, SLAPI_BACKEND, inst->inst_be);
+ slapi_pblock_set(pb, SLAPI_BACKEND_INSTANCE_NAME, inst->inst_name);
+ upgradedb_core(pb, inst);
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj);
+ }
+
+ /* upgrade idl to new; otherwise no need to modify idl-switch */
+ if (!(up_flags & SLAPI_UPGRADEDB_FORCE))
+ {
+ replace_ldbm_config_value(CONFIG_IDL_SWITCH, "new", li);
+ }
+
+ home_dir = dblayer_get_home_dir(li, NULL);
+
+ /* write db version files */
+ dbversion_write(li, home_dir, NULL);
+
+ inst_obj = objset_first_obj(li->li_instance_set);
+ while (NULL != inst_obj)
+ {
+ char *inst_dirp = NULL;
+ inst_dirp = dblayer_get_full_inst_dir(li, inst, inst_dir, MAXPATHLEN);
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ dbversion_write(li, inst_dirp, NULL);
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ }
+
+ /* close the database down again */
+ if (run_from_cmdline)
+ {
+ if (0 != dblayer_flush(li))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Failed to flush database\n");
+ }
+ if (0 != dblayer_close(li,DBLAYER_IMPORT_MODE))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Failed to close database\n");
+ goto fail1;
+ }
+ }
+
+ /* delete backup */
+ if (NULL != dest_dir)
+ ldbm_delete_dirs(dest_dir);
+
+ if (dest_dir != orig_dest_dir)
+ slapi_ch_free_string(&dest_dir);
+
+ return 0;
+
+fail1:
+ if (0 != dblayer_flush(li))
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Failed to flush database\n");
+
+ /* Ugly! (we started dblayer with DBLAYER_IMPORT_MODE)
+ * We just want not to generate a guardian file...
+ */
+ if (0 != dblayer_close(li,DBLAYER_ARCHIVE_MODE))
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Failed to close database\n");
+
+ /* restore from the backup, if possible */
+ if (NULL != dest_dir)
+ {
+ if (0 == backup_rval) /* only when the backup succeeded... */
+ {
+ int cnt = 0;
+
+ inst_obj = objset_first_obj(li->li_instance_set);
+ while (NULL != inst_obj)
+ {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+
+ inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ inst_dir, MAXPATHLEN);
+ backup_rval = dblayer_copy_directory(li, NULL /* task */,
+ inst->inst_dir_name,
+ dest_dir, 1/*restore*/,
+ &cnt, 0, 1);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ if (backup_rval < 0)
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Failed to restore index files (instance %s).\n",
+ inst->inst_name);
+
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj);
+ }
+
+ backup_rval = upgradedb_copy_logfiles(li, dest_dir, 1, &cnt);
+ if (backup_rval < 0)
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "Failed to restore log files.\n");
+ }
+
+ /* anyway clean up the backup dir */
+ ldbm_delete_dirs(dest_dir);
+ }
+
+fail0:
+ if (dest_dir != orig_dest_dir)
+ slapi_ch_free_string(&dest_dir);
+
+ return rval;
+}
+
+void normalize_dir(char *dir)
+{
+ int l = strlen(dir);
+ if ('/' == dir[l-1] || '\\' == dir[l-1])
+ {
+ dir[l-1] = '\0';
+ }
+}
+
+#define LOG "log."
+#define LOGLEN 4
+int upgradedb_copy_logfiles(struct ldbminfo *li, char *destination_dir,
+ int restore, int *cnt)
+{
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ char *src;
+ char *dest;
+ int srclen;
+ int destlen;
+ int rval = 0;
+ int len0 = 0;
+ int len1 = 0;
+ char *from = NULL;
+ char *to = NULL;
+
+ *cnt = 0;
+ if (restore)
+ {
+ src = destination_dir;
+ dest = li->li_directory;
+ }
+ else
+ {
+ src = li->li_directory;
+ dest = destination_dir;
+ }
+ srclen = strlen(src);
+ destlen = strlen(dest);
+
+ /* Open the instance dir so we can look what's in it. */
+ dirhandle = PR_OpenDir(src);
+ if (NULL == dirhandle)
+ return -1;
+
+ while (NULL != (direntry =
+ PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (NULL == direntry->name)
+ break;
+
+ if (0 == strncmp(direntry->name, LOG, 4))
+ {
+ int filelen = strlen(direntry->name);
+ char *p, *endp;
+ int fromlen, tolen;
+ int notalog = 0;
+
+ endp = (char *)direntry->name + filelen;
+ for (p = (char *)direntry->name + LOGLEN; p < endp; p++)
+ {
+ if (!isdigit(*p))
+ {
+ notalog = 1;
+ break;
+ }
+ }
+ if (notalog)
+ continue; /* go to next file */
+
+ fromlen = srclen + filelen + 2;
+ if (len0 < fromlen)
+ {
+ slapi_ch_free_string(&from);
+ from = slapi_ch_calloc(1, fromlen);
+ len0 = fromlen;
+ }
+ sprintf(from, "%s/%s", src, direntry->name);
+ tolen = destlen + filelen + 2;
+ if (len1 < tolen)
+ {
+ slapi_ch_free_string(&to);
+ to = slapi_ch_calloc(1, tolen);
+ len1 = tolen;
+ }
+ sprintf(to, "%s/%s", dest, direntry->name);
+ if (NULL == from || NULL == to)
+ break;
+ rval = dblayer_copyfile(from, to, 1, DEFAULT_MODE);
+ if (rval < 0)
+ break;
+ cnt++;
+ }
+ }
+ slapi_ch_free_string(&from);
+ slapi_ch_free_string(&to);
+ PR_CloseDir(dirhandle);
+
+ return rval;
+}
+
+int upgradedb_delete_indices_4cmd(ldbm_instance *inst)
+{
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ int rval = 0;
+ char fullpath[MAXPATHLEN];
+ char *fullpathp = fullpath;
+ char inst_dir[MAXPATHLEN];
+ char *inst_dirp = dblayer_get_full_inst_dir(inst->inst_li, inst,
+ inst_dir, MAXPATHLEN);
+
+ slapi_log_error(SLAPI_LOG_TRACE, "upgrade DB",
+ "upgradedb_delete_indices_4cmd: %s\n");
+ dirhandle = PR_OpenDir(inst_dirp);
+ if (!dirhandle)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "upgradedb_delete_indices_4cmd: PR_OpenDir failed\n");
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ return -1;
+ }
+
+ while (NULL != (direntry =
+ PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ PRFileInfo info;
+ int len;
+
+ if (! direntry->name)
+ break;
+
+ if (0 == strcmp(direntry->name, ID2ENTRY LDBM_FILENAME_SUFFIX))
+ continue;
+
+ len = strlen(inst_dirp) + strlen(direntry->name) + 2;
+ if (len > MAXPATHLEN)
+ {
+ fullpathp = (char *)slapi_ch_malloc(len);
+ }
+ sprintf(fullpathp, "%s/%s", inst_dirp, direntry->name);
+ rval = PR_GetFileInfo(fullpathp, &info);
+ if (PR_SUCCESS == rval && PR_FILE_DIRECTORY != info.type)
+ {
+ PR_Delete(fullpathp);
+ slapi_log_error(SLAPI_LOG_TRACE, "upgrade DB",
+ "upgradedb_delete_indices_4cmd: %s deleted\n", fullpath);
+ }
+ if (fullpathp != fullpath)
+ slapi_ch_free_string(&fullpathp);
+ }
+ PR_CloseDir(dirhandle);
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ return rval;
+}
+
+/*
+ * upgradedb_core
+ */
+void upgradedb_core(Slapi_PBlock *pb, ldbm_instance *inst)
+{
+ backend *be = NULL;
+ int task_flags = 0;
+ int run_from_cmdline = 0;
+
+ slapi_pblock_get(pb, SLAPI_TASK_FLAGS, &task_flags);
+ run_from_cmdline = (task_flags & TASK_RUNNING_FROM_COMMANDLINE);
+
+ be = inst->inst_be;
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "%s: Start upgradedb.\n", inst->inst_name);
+
+ if (!run_from_cmdline)
+ {
+ /* shutdown this instance of the db */
+ slapi_log_error(SLAPI_LOG_TRACE, "upgrade DB",
+ "Bringing %s offline...\n", inst->inst_name);
+ slapi_mtn_be_disable(inst->inst_be);
+
+ cache_clear(&inst->inst_cache);
+ dblayer_instance_close(be);
+ }
+
+ /* dblayer_instance_start will init the id2entry index. */
+ if (0 != dblayer_instance_start(be, DBLAYER_IMPORT_MODE))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "upgrade DB",
+ "upgradedb: Failed to init instance %s\n", inst->inst_name);
+ return;
+ }
+
+ if (run_from_cmdline)
+ vlv_init(inst); /* Initialise the Virtual List View code */
+
+ ldbm_back_ldif2ldbm_deluxe(pb);
+}
+
+#endif /* UPGRADEDB */
diff --git a/ldap/servers/slapd/back-ldbm/libback-ldbm.def b/ldap/servers/slapd/back-ldbm/libback-ldbm.def
new file mode 100644
index 00000000..0967d9c5
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/libback-ldbm.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 'Directory Server 2.0 DB Backend Plugin'
+EXPORTS
+ ldbm_back_init @2
+ plugin_init_debug_level @3
+; ldbm_back_changelog_init @4
+
+
diff --git a/ldap/servers/slapd/back-ldbm/matchrule.c b/ldap/servers/slapd/back-ldbm/matchrule.c
new file mode 100644
index 00000000..0d7197ab
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/matchrule.c
@@ -0,0 +1,126 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* matchrule.c */
+
+
+#include "back-ldbm.h"
+
+/* NPCTE fix for bug # 394184, SD, 20 Jul 00 */
+/* replace the hard coded return value by the appropriate LDAP error code */
+/*
+ * Returns: 0 -- OK now is: LDAP_SUCCESS (fix for bug #394184)
+ * -1 -- protocol error now is: LDAP_PROTOCOL_ERROR
+ * -3 -- operation error now is: LDAP_OPERATIONS_ERROR
+ */
+int
+create_matchrule_indexer(Slapi_PBlock **pb,char* matchrule,char* type)
+{
+ IFP mrINDEX = NULL;
+ int return_value = LDAP_SUCCESS;
+ unsigned int sort_indicator = SLAPI_PLUGIN_MR_USAGE_SORT;
+
+ if(pb==NULL)
+ {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if(*pb==NULL)
+ {
+ *pb = slapi_pblock_new();
+ }
+ if(*pb==NULL)
+ {
+ /* Memory allocation faliure */
+ /* Operations error to the calling routine */
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* If these fail, it's an operations error */
+ return_value |= slapi_pblock_set (*pb, SLAPI_PLUGIN_MR_OID, matchrule);
+ return_value |= slapi_pblock_set (*pb, SLAPI_PLUGIN_MR_TYPE, type);
+ return_value |= slapi_pblock_set (*pb, SLAPI_PLUGIN_MR_USAGE, (void*)&sort_indicator);
+ if (0 != return_value)
+ {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* If this fails, could be operations error, or that OID is not supported */
+ return_value = slapi_mr_indexer_create (*pb);
+ if (0 != return_value)
+ {
+ return LDAP_PROTOCOL_ERROR;
+ }
+
+ /* If these fail, ops error */
+ return_value = slapi_pblock_get (*pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrINDEX);
+
+ if ( (0 != return_value) || (mrINDEX == NULL) )
+ {
+ return LDAP_OPERATIONS_ERROR;
+ }
+ else
+ {
+ return LDAP_SUCCESS;
+ }
+}
+/* End NPCTE fix for bug # 394184 */
+
+int
+destroy_matchrule_indexer(Slapi_PBlock *pb)
+{
+ IFP mrDESTROY = NULL;
+ if (!slapi_pblock_get (pb, SLAPI_PLUGIN_DESTROY_FN, &mrDESTROY))
+ {
+ if (mrDESTROY != NULL)
+ {
+ mrDESTROY (pb);
+ }
+ }
+ return 0;
+}
+
+
+/*
+ * This routine returns pointer to memory which is owned by the plugin, so don't
+ * free it. Gets freed by the next call to this routine, or when the indexer
+ * is destroyed
+ */
+int
+matchrule_values_to_keys(Slapi_PBlock *pb,struct berval **input_values,struct berval ***output_values)
+{
+ IFP mrINDEX = NULL;
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrINDEX);
+ slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUES, input_values);
+ mrINDEX (pb);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_KEYS, output_values);
+ return 0;
+}
+
+/*
+ * This routine returns pointer to memory which is owned by the plugin, so don't
+ * free it. Gets freed by the next call to this routine, or when the indexer
+ * is destroyed
+ */
+int
+matchrule_values_to_keys_sv(Slapi_PBlock *pb,Slapi_Value **input_values,Slapi_Value ***output_values)
+{
+ IFP mrINDEX = NULL;
+ struct berval **bvi, **bvo;
+
+ valuearray_get_bervalarray(input_values, &bvi);
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrINDEX);
+ slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUES, bvi);
+ mrINDEX (pb);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_MR_KEYS, &bvo);
+
+ slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUES, NULL);
+ ber_bvecfree(bvi);
+
+ valuearray_init_bervalarray(bvo, output_values);
+ return 0;
+}
diff --git a/ldap/servers/slapd/back-ldbm/misc.c b/ldap/servers/slapd/back-ldbm/misc.c
new file mode 100644
index 00000000..b2a8d6de
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/misc.c
@@ -0,0 +1,356 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* misc.c - backend misc routines */
+
+#include "back-ldbm.h"
+
+/* Takes a return code supposed to be errno or from lidb
+ which we don't expect to see and prints a handy log message */
+void ldbm_nasty(const char* str, int c, int err)
+{
+ char *msg = NULL;
+ char buffer[200];
+ if (err == DB_LOCK_DEADLOCK) {
+ sprintf(buffer,"%s WARNING %d",str,c);
+ LDAPDebug(LDAP_DEBUG_TRACE,"%s, err=%d %s\n",
+ buffer,err,(msg = dblayer_strerror( err )) ? msg : "");
+ } else if (err == DB_RUNRECOVERY) {
+ LDAPDebug(LDAP_DEBUG_ANY,"FATAL ERROR at %s (%d); server stopping as database recovery needed.\n", str,c,0);
+ exit(1);
+ } else {
+ sprintf(buffer,"%s BAD %d",str,c);
+ LDAPDebug(LDAP_DEBUG_ANY,"%s, err=%d %s\n",
+ buffer,err,(msg = dblayer_strerror( err )) ? msg : "");
+ }
+}
+
+/* Put a message in the access log, complete with connection ID and operation ID */
+void ldbm_log_access_message(Slapi_PBlock *pblock,char *string)
+{
+ int ret = 0;
+ int connection_id = 0;
+ int operation_id = 0;
+ Operation *operation = NULL; /* DBDB this is sneaky---opid should be covered by the API directly */
+
+ ret = slapi_pblock_get(pblock,SLAPI_OPERATION,&operation);
+ if (0 != ret) {
+ return;
+ }
+ ret = slapi_pblock_get(pblock,SLAPI_CONN_ID,&connection_id);
+ if (0 != ret) {
+ return;
+ }
+ operation_id = operation->o_opid;
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d %s\n",connection_id, operation_id,string);
+}
+
+int return_on_disk_full(struct ldbminfo *li)
+{
+ dblayer_remember_disk_filled(li);
+ return SLAPI_FAIL_DISKFULL;
+}
+
+
+/* System Indexes */
+
+static const char *systemIndexes[] = {
+ "entrydn",
+ "parentid",
+ "objectclass",
+ "aci",
+ "numsubordinates",
+ SLAPI_ATTR_UNIQUEID,
+ SLAPI_ATTR_NSCP_ENTRYDN,
+ ATTR_NSDS5_REPLCONFLICT,
+ NULL
+};
+
+int
+ldbm_attribute_always_indexed(const char *attrtype)
+{
+ int r= 0;
+ if(NULL != attrtype)
+ {
+ int i=0;
+ while (!r && systemIndexes[i] != NULL)
+ {
+ if(!strcasecmp(attrtype,systemIndexes[i]))
+ {
+ r= 1;
+ }
+ i++;
+ }
+ }
+ return(r);
+}
+
+
+
+/*
+ * Given an entry dn and a uniqueid, compute the
+ * DN of the entry's tombstone. Returns a pointer
+ * to an allocated block of memory.
+ */
+char *
+compute_entry_tombstone_dn(const char *entrydn, const char *uniqueid)
+{
+ const char *tombstone_dn_pattern = "%s=%s, %s";
+ char *tombstone_dn;
+
+ PR_ASSERT(NULL != entrydn);
+ PR_ASSERT(NULL != uniqueid);
+
+ tombstone_dn = slapi_ch_malloc(strlen(SLAPI_ATTR_UNIQUEID) +
+ strlen(tombstone_dn_pattern) +
+ strlen(uniqueid) +
+ strlen(entrydn) + 1);
+ sprintf(tombstone_dn, tombstone_dn_pattern,
+ SLAPI_ATTR_UNIQUEID,
+ uniqueid,
+ entrydn);
+ return tombstone_dn;
+}
+
+
+/* mark a backend instance "busy"
+ * returns 0 on success, -1 if the instance is ALREADY busy
+ */
+int instance_set_busy(ldbm_instance *inst)
+{
+ PR_Lock(inst->inst_config_mutex);
+ if (inst->inst_flags & INST_FLAG_BUSY) {
+ PR_Unlock(inst->inst_config_mutex);
+ return -1;
+ }
+
+ inst->inst_flags |= INST_FLAG_BUSY;
+ PR_Unlock(inst->inst_config_mutex);
+ return 0;
+}
+
+int instance_set_busy_and_readonly(ldbm_instance *inst)
+{
+ PR_Lock(inst->inst_config_mutex);
+ if (inst->inst_flags & INST_FLAG_BUSY) {
+ PR_Unlock(inst->inst_config_mutex);
+ return -1;
+ }
+
+ inst->inst_flags |= INST_FLAG_BUSY;
+
+ /* save old readonly state */
+ if (slapi_be_get_readonly(inst->inst_be)) {
+ inst->inst_flags |= INST_FLAG_READONLY;
+ } else {
+ inst->inst_flags &= ~INST_FLAG_READONLY;
+ }
+ slapi_mtn_be_set_readonly(inst->inst_be, 1);
+
+ PR_Unlock(inst->inst_config_mutex);
+ return 0;
+}
+
+/* mark a backend instance to be not "busy" anymore */
+void instance_set_not_busy(ldbm_instance *inst)
+{
+ int readonly;
+
+ PR_Lock(inst->inst_config_mutex);
+ inst->inst_flags &= ~INST_FLAG_BUSY;
+ /* set backend readonly flag to match instance flags again
+ * (sometimes the instance changes the readonly status when it's busy)
+ */
+ readonly = (inst->inst_flags & INST_FLAG_READONLY ? 1 : 0);
+ slapi_mtn_be_set_readonly(inst->inst_be, readonly);
+ PR_Unlock(inst->inst_config_mutex);
+}
+
+void
+allinstance_set_not_busy(struct ldbminfo *li)
+{
+ ldbm_instance *inst;
+ Object *inst_obj;
+
+ /* server is up -- mark all backends busy */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ instance_set_not_busy(inst);
+ }
+ if (inst_obj)
+ object_release(inst_obj);
+}
+
+void
+allinstance_set_busy(struct ldbminfo *li)
+{
+ ldbm_instance *inst;
+ Object *inst_obj;
+
+ /* server is up -- mark all backends busy */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ instance_set_busy(inst);
+ }
+ if (inst_obj)
+ object_release(inst_obj);
+}
+
+int
+is_anyinstance_busy(struct ldbminfo *li)
+{
+ ldbm_instance *inst;
+ Object *inst_obj;
+ int rval = 0;
+
+ /* server is up -- mark all backends busy */
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ PR_Lock(inst->inst_config_mutex);
+ rval = inst->inst_flags & INST_FLAG_BUSY;
+ PR_Unlock(inst->inst_config_mutex);
+ if (0 != rval) {
+ break;
+ }
+ }
+ if (inst_obj)
+ object_release(inst_obj);
+ return rval;
+}
+
+/*
+ * delete the given file/directory and its sub files/directories
+ */
+int
+ldbm_delete_dirs(char *path)
+{
+ PRDir *dirhandle = NULL;
+ PRDirEntry *direntry = NULL;
+ char fullpath[MAXPATHLEN];
+ int rval = 0;
+ PRFileInfo info;
+
+ dirhandle = PR_OpenDir(path);
+ if (! dirhandle)
+ {
+ PR_Delete(path);
+ return 0;
+ }
+
+ while (NULL != (direntry =
+ PR_ReadDir(dirhandle, PR_SKIP_DOT | PR_SKIP_DOT_DOT)))
+ {
+ if (! direntry->name)
+ break;
+
+ sprintf(fullpath, "%s/%s", path, direntry->name);
+ rval = PR_GetFileInfo(fullpath, &info);
+ if (PR_SUCCESS == rval)
+ {
+ if (PR_FILE_DIRECTORY == info.type)
+ rval += ldbm_delete_dirs(fullpath);
+ }
+ if (PR_FILE_DIRECTORY != info.type)
+ PR_Delete(fullpath);
+ }
+ PR_CloseDir(dirhandle);
+ /* remove the directory itself too */
+ rval += PR_RmDir(path);
+ return rval;
+}
+
+char
+get_sep(char *path)
+{
+ if (NULL == path)
+ return '/'; /* default */
+ if (NULL != strchr(path, '/'))
+ return '/';
+ if (NULL != strchr(path, '\\'))
+ return '\\';
+ return '/'; /* default */
+}
+
+/* mkdir -p */
+int
+mkdir_p(char *dir, unsigned int mode)
+{
+ PRFileInfo info;
+ int rval;
+ char sep = get_sep(dir);
+
+ rval = PR_GetFileInfo(dir, &info);
+ if (PR_SUCCESS == rval)
+ {
+ if (PR_FILE_DIRECTORY != info.type) /* not a directory */
+ {
+ PR_Delete(dir);
+ if (PR_SUCCESS != PR_MkDir(dir, mode))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "mkdir_p %s: error %d (%s)\n",
+ dir, PR_GetError(),slapd_pr_strerror(PR_GetError()));
+ return -1;
+ }
+ }
+ return 0;
+ }
+ else
+ {
+ /* does not exist */
+ char *p, *e;
+ char c[2] = {0, 0};
+ int len = strlen(dir);
+ rval = 0;
+
+ e = dir + len - 1;
+ if (*e == sep)
+ {
+ c[1] = *e;
+ *e = '\0';
+ }
+
+ c[0] = '/';
+ p = strrchr(dir, sep);
+ if (NULL != p)
+ {
+ *p = '\0';
+ rval = mkdir_p(dir, mode);
+ *p = c[0];
+ }
+ if (c[1])
+ *e = c[1];
+ if (0 != rval)
+ return rval;
+ if (PR_SUCCESS != PR_MkDir(dir, mode))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "mkdir_p %s: error %d (%s)\n",
+ dir, PR_GetError(),slapd_pr_strerror(PR_GetError()));
+ return -1;
+ }
+ return 0;
+ }
+}
+
+int
+is_fullpath(char *path)
+{
+ int len;
+ if (NULL == path || '\0' == *path)
+ return 0;
+
+ if ('/' == *path || '\\' == *path)
+ return 1;
+
+ len = strlen(path);
+ if (len > 2)
+ {
+ if (':' == path[1] && ('/' == path[2] || '\\' == path[2])) /* Windows */
+ return 1;
+ }
+ return 0;
+}
diff --git a/ldap/servers/slapd/back-ldbm/monitor.c b/ldap/servers/slapd/back-ldbm/monitor.c
new file mode 100644
index 00000000..1c5a2960
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/monitor.c
@@ -0,0 +1,274 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* monitor.c - ldbm backend monitor function */
+
+#include "back-ldbm.h"
+#include "dblayer.h" /* XXXmcs: not sure this is good to do... */
+#include <sys/stat.h>
+
+
+#define MSET(_attr) do { \
+ val.bv_val = buf; \
+ val.bv_len = strlen(buf); \
+ attrlist_replace(&e->e_attrs, (_attr), vals); \
+} while (0)
+
+#define MSETF(_attr, _x) do { \
+ char tmp_atype[37]; \
+ sprintf(tmp_atype, _attr, _x); \
+ MSET(tmp_atype); \
+} while (0)
+
+
+/* DSE callback to monitor stats for a particular instance */
+int ldbm_back_monitor_instance_search(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+ struct ldbminfo *li = NULL;
+ struct berval val;
+ struct berval *vals[2];
+ char buf[BUFSIZ];
+ u_long hits, tries;
+ long nentries,maxentries;
+ size_t size,maxsize;
+/* NPCTE fix for bugid 544365, esc 0. <P.R> <04-Jul-2001> */
+ struct stat astat;
+/* end of NPCTE fix for bugid 544365 */
+ DB_MPOOL_FSTAT **mpfstat = NULL;
+ int i,j;
+
+ /* Get the LDBM Info structure for the ldbm backend */
+ if (inst->inst_be->be_database == NULL) {
+ *returncode= LDAP_OPERATIONS_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ li = (struct ldbminfo *)inst->inst_be->be_database->plg_private;
+ if (li == NULL) {
+ *returncode= LDAP_OPERATIONS_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ if (inst->inst_be->be_state != BE_STATE_STARTED)
+ {
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* database name */
+ sprintf(buf, "%s", li->li_plugin->plg_name);
+ MSET("database");
+
+ /* read-only status */
+ sprintf( buf, "%d", inst->inst_be->be_readonly );
+ MSET("readOnly");
+
+ /* fetch cache statistics */
+ cache_get_stats(&(inst->inst_cache), &hits, &tries,
+ &nentries, &maxentries, &size, &maxsize);
+ sprintf(buf, "%lu", hits);
+ MSET("entryCacheHits");
+ sprintf(buf, "%lu", tries);
+ MSET("entryCacheTries");
+ sprintf(buf, "%lu", (unsigned long)(100.0*(double)hits / (double)(tries > 0 ? tries : 1)));
+ MSET("entryCacheHitRatio");
+ sprintf(buf, "%lu", size);
+ MSET("currentEntryCacheSize");
+ sprintf(buf, "%lu", maxsize);
+ MSET("maxEntryCacheSize");
+ sprintf(buf, "%ld", nentries);
+ MSET("currentEntryCacheCount");
+ sprintf(buf, "%ld", maxentries);
+ MSET("maxEntryCacheCount");
+
+#ifdef DEBUG
+ {
+ /* debugging for hash statistics */
+ char *x;
+ cache_debug_hash(&(inst->inst_cache), &x);
+ val.bv_val = x;
+ val.bv_len = strlen(x);
+ attrlist_replace(&e->e_attrs, "entrycache-hashtables", vals);
+ slapi_ch_free((void **)&x);
+ }
+#endif
+
+ if (dblayer_memp_stat(li, NULL, &mpfstat) != 0) {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ for (i = 0;(mpfstat[i] && (mpfstat[i]->file_name != NULL)); i++) {
+#ifdef _WIN32
+ int fpos = 0;
+#endif
+ char *absolute_pathname = NULL;
+ size_t absolute_pathname_size = 0;
+
+ /* only print out stats on files used by this instance */
+ if (strlen(mpfstat[i]->file_name) < strlen(inst->inst_dir_name))
+ continue;
+ if (strncmp(mpfstat[i]->file_name, inst->inst_dir_name,
+ strlen(inst->inst_dir_name)) != 0)
+ continue;
+
+ /* Since the filenames are now relative, we need to construct an absolute version
+ * for the purpose of stat() etc below...
+ */
+ if (absolute_pathname) {
+ slapi_ch_free(&absolute_pathname);
+ }
+ absolute_pathname_size = strlen(inst->inst_parent_dir_name) + strlen(mpfstat[i]->file_name) + 2;
+ absolute_pathname = slapi_ch_malloc(absolute_pathname_size);
+ sprintf(absolute_pathname, "%s%c%s" , inst->inst_parent_dir_name, get_sep(inst->inst_parent_dir_name), mpfstat[i]->file_name );
+
+/* NPCTE fix for bugid 544365, esc 0. <P.R> <04-Jul-2001> */
+ /* Hide statistic of deleted files (mainly indexes) */
+ if (stat(absolute_pathname,&astat))
+ continue;
+ /* If the file has been re-created after been deleted
+ * We should show only statistics for the last instance
+ * Since SleepyCat returns the statistic of the last open file first,
+ * we should only display the first statistic record for a given file
+ */
+ for (j=0;j<i;j++)
+ if (!strcmp(mpfstat[i]->file_name,mpfstat[j]->file_name))
+ break;
+ if (j<i)
+ continue;
+/* end of NPCTE fix for bugid 544365 */
+
+ /* Get each file's stats */
+ sprintf(buf, "%s", mpfstat[i]->file_name);
+#ifdef _WIN32
+ /*
+ * For NT, switch the last
+ * backslash to a foward
+ * slash. - RJP
+ */
+ for (fpos = strlen(buf); fpos >= 0; fpos--) {
+ if (buf[fpos] == '\\') {
+ buf[fpos] = '/';
+ break;
+ }
+ }
+#endif
+ MSETF("dbFilename-%d", i);
+
+ sprintf(buf, "%u", mpfstat[i]->st_cache_hit);
+ MSETF("dbFileCacheHit-%d", i);
+ sprintf(buf, "%u", mpfstat[i]->st_cache_miss);
+ MSETF("dbFileCacheMiss-%d", i);
+ sprintf(buf, "%u", mpfstat[i]->st_page_in);
+ MSETF("dbFilePageIn-%d", i);
+ sprintf(buf, "%u", mpfstat[i]->st_page_out);
+ MSETF("dbFilePageOut-%d", i);
+
+ if (absolute_pathname) {
+ slapi_ch_free(&absolute_pathname);
+ }
+
+ }
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR + DB_VERSION_PATCH <= 3204
+ /* In DB 3.2.4 and earlier, we need to free each element */
+ for (i = 0; mpfstat[i]; i++)
+ free(mpfstat[i]);
+#endif
+ free(mpfstat);
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+
+}
+
+
+/* monitor global ldbm stats */
+int ldbm_back_monitor_search(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ struct ldbminfo *li = (struct ldbminfo *)arg;
+ struct berval val;
+ struct berval *vals[2];
+ char buf[BUFSIZ];
+ DB_MPOOL_STAT *mpstat = NULL;
+ DB_MPOOL_FSTAT **mpfstat = NULL;
+ u_int32_t cache_tries;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* database name */
+ sprintf(buf, "%s", li->li_plugin->plg_name);
+ MSET("database");
+
+ /* we have to ask for file stats in order to get correct global stats */
+ if (dblayer_memp_stat(li, &mpstat, &mpfstat) != 0) {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* cache hits*/
+ sprintf(buf, "%u", mpstat->st_cache_hit);
+ MSET("dbCacheHits");
+
+ /* cache tries*/
+ cache_tries = (mpstat->st_cache_miss + mpstat->st_cache_hit);
+ sprintf(buf, "%u", cache_tries);
+ MSET("dbCacheTries");
+
+ /* cache hit ratio*/
+ sprintf(buf, "%lu", (unsigned long)(100.0 * (double)mpstat->st_cache_hit / (double)(cache_tries > 0 ? cache_tries : 1) ));
+ MSET("dbCacheHitRatio");
+
+ sprintf(buf, "%u", mpstat->st_page_in);
+ MSET("dbCachePageIn");
+ sprintf(buf, "%u", mpstat->st_page_out);
+ MSET("dbCachePageOut");
+ sprintf(buf, "%u", mpstat->st_ro_evict);
+ MSET("dbCacheROEvict");
+ sprintf(buf, "%u", mpstat->st_rw_evict);
+ MSET("dbCacheRWEvict");
+
+ free(mpstat);
+
+ if (mpfstat) {
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR + DB_VERSION_PATCH <= 3204
+ /* In DB 3.2.4 and earlier, we need to free each element */
+ int i;
+ for (i = 0; mpfstat[i]; i++)
+ free(mpfstat[i]);
+#endif
+ free(mpfstat);
+ }
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+/* monitor global ldbm database stats */
+int
+ldbm_back_dbmonitor_search(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ dblayer_private *dbpriv = NULL;
+ struct ldbminfo *li = NULL;
+
+ PR_ASSERT(NULL != arg);
+ li = (struct ldbminfo*)arg;
+ dbpriv = (dblayer_private*)li->li_dblayer_private;
+ PR_ASSERT(NULL != dbpriv);
+
+ perfctrs_as_entry( e, dbpriv->perf_private, dbpriv->dblayer_env->dblayer_DB_ENV);
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
diff --git a/ldap/servers/slapd/back-ldbm/nextid.c b/ldap/servers/slapd/back-ldbm/nextid.c
new file mode 100644
index 00000000..12773768
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/nextid.c
@@ -0,0 +1,204 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* id.c - keep track of the next id to be given out */
+
+#include "back-ldbm.h"
+
+ID
+next_id(backend *be)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ ID id;
+
+ /*Lock*/
+ PR_Lock( inst->inst_nextid_mutex );
+
+ /*Test if nextid hasn't been initialized. */
+ if (inst->inst_nextid < 1) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ldbm backend instance: nextid not initialized... exiting.\n", 0,0,0);
+ exit(1);
+ }
+
+ /*Increment the in-memory nextid*/
+ inst->inst_nextid++;
+
+ id = inst->inst_nextid - 1;
+
+ /*unlock*/
+ PR_Unlock( inst->inst_nextid_mutex );
+
+ /* if ID is above the threshold, the database may need rebuilding soon */
+ if (id >= ID_WARNING_THRESHOLD) {
+ if ( id >= MAXID ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ldbm backend instance: FATAL ERROR: backend '%s' has no"
+ "IDs left. DATABASE MUST BE REBUILT.\n", be->be_name, 0,
+ 0);
+ id = MAXID;
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ldbm backend instance: WARNING: backend '%s' may run out "
+ "of IDs. Please, rebuild database.\n", be->be_name, 0, 0);
+ }
+ }
+ return( id );
+}
+
+void
+next_id_return( backend *be, ID id )
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+
+ /*Lock*/
+ PR_Lock( inst->inst_nextid_mutex );
+
+ /*Test if nextid hasn't been initialized. */
+ if (inst->inst_nextid < 1) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ldbm backend instance: nextid not initialized... exiting\n", 0,0,0);
+ exit(1);
+ }
+
+ if ( id != inst->inst_nextid - 1 ) {
+ PR_Unlock( inst->inst_nextid_mutex );
+ return;
+ }
+
+ /*decrement the in-memory version*/
+ inst->inst_nextid--;
+
+ /*unlock this bad boy*/
+ PR_Unlock( inst->inst_nextid_mutex );
+}
+
+ID
+next_id_get( backend *be )
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ ID id;
+
+ /*lock*/
+ PR_Lock( inst->inst_nextid_mutex );
+
+ /*Test if nextid hasn't been initialized.*/
+ if (inst->inst_nextid < 1) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ldbm backend instance: nextid not initialized... exiting\n", 0,0,0);
+ exit(1);
+ }
+
+ id = inst->inst_nextid;
+ PR_Unlock( inst->inst_nextid_mutex );
+
+ return( id );
+}
+
+/*
+ * Function: get_ids_from_disk
+ *
+ * Returns: squat
+ *
+ * Description: Opend the id2entry file and obtains the largest
+ * ID in use, and sets li->li_nextid. If no IDs
+ * could be read from id2entry, li->li_nextid
+ * is set to 1.
+ */
+void
+get_ids_from_disk(backend *be)
+{
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ DB *id2entrydb; /*the id2entry database*/
+ int return_value = -1;
+
+ /*For the nextid, we go directly to the id2entry database,
+ and grab the max ID*/
+
+ /*Get a copy of the id2entry database*/
+ if ( (return_value = dblayer_get_id2entry( be, &id2entrydb )) != 0 ) {
+ id2entrydb = NULL;
+ }
+
+ /* lock the nextid mutex*/
+ PR_Lock( inst->inst_nextid_mutex );
+
+ /*
+ * If there is no id2entry database, then we can assume that there
+ * are no entries, and that nextid should be 1
+ */
+ if (id2entrydb == NULL) {
+ inst->inst_nextid = 1;
+
+ /* unlock */
+ PR_Unlock( inst->inst_nextid_mutex );
+ return;
+
+ } else {
+
+ /*Get the last key*/
+ DBC *dbc = NULL;
+ DBT key = {0}; /*For the nextid*/
+ DBT Value = {0};
+ Value.flags = DB_DBT_MALLOC;
+ key.flags = DB_DBT_MALLOC;
+ return_value = id2entrydb->cursor(id2entrydb,NULL,&dbc,0);
+ if (0 == return_value) {
+ return_value = dbc->c_get(dbc,&key,&Value,DB_LAST);
+ if (0 == return_value) {
+ inst->inst_nextid = id_stored_to_internal(key.dptr) + 1;
+ }
+ if (NULL != key.data) {
+ free(key.data);
+ }
+ if (NULL != Value.data) {
+ free(Value.data);
+ }
+ dbc->c_close(dbc);
+ }
+ if ( (key.dptr == NULL) || (0 != return_value) ) {
+ inst->inst_nextid = 1;
+
+ /*close the cache*/
+ dblayer_release_id2entry( be, id2entrydb );
+
+ /* unlock */
+ PR_Unlock( inst->inst_nextid_mutex );
+ return;
+ }
+
+ }
+
+ /*close the cache*/
+ dblayer_release_id2entry( be, id2entrydb );
+
+ /* unlock */
+ PR_Unlock( inst->inst_nextid_mutex );
+}
+
+
+/* routines to turn an internal machine-representation ID into the one we store (big-endian) */
+
+void id_internal_to_stored(ID i,char *b)
+{
+ if ( sizeof(ID) > 4 ) {
+ memset (b+4, 0, sizeof(ID)-4);
+ }
+
+ b[0] = (char)(i >> 24);
+ b[1] = (char)(i >> 16);
+ b[2] = (char)(i >> 8);
+ b[3] = (char)i;
+}
+
+ID id_stored_to_internal(char* b)
+{
+ ID i;
+ i = (ID)b[3] & 0x000000ff;
+ i |= (((ID)b[2]) << 8) & 0x0000ff00;
+ i |= (((ID)b[1]) << 16) & 0x00ff0000;
+ i |= ((ID)b[0]) << 24;
+ return i;
+}
diff --git a/ldap/servers/slapd/back-ldbm/parents.c b/ldap/servers/slapd/back-ldbm/parents.c
new file mode 100644
index 00000000..80fec7ac
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/parents.c
@@ -0,0 +1,105 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* parents.c - where the adults live */
+
+#include "back-ldbm.h"
+
+char *numsubordinates = "numsubordinates";
+char *hassubordinates = "hassubordinates";
+
+/* Routine where any in-memory modification of a parent entry happens on some state-change in
+ one of its children. vaid op values are: 1 == child entry newly added, 2 == child entry about to be
+ deleted; 3 == child modified, in which case childmods points to the modifications. The child entry
+ passed is in the state which reflects the mods having been appied. op ==3 HAS NOT BEEN IMPLEMENTED YET
+ The routine is allowed to modify the parent entry, and to return a set of LDAPMods reflecting
+ the changes it made. The LDAPMods array must be freed by the called by calling ldap_free_mods(p,1)
+
+ */
+int parent_update_on_childchange(modify_context *mc,int op, size_t *new_sub_count )
+{
+ int ret = 0;
+ int mod_op = 0;
+ Slapi_Attr *read_attr = NULL;
+ size_t current_sub_count = 0;
+ int already_present = 0;
+
+ if (new_sub_count)
+ *new_sub_count = 0;
+
+ /* Check nobody is trying to use op == 3, it's not implemented yet */
+ PR_ASSERT( (op == 1) || (op == 2));
+
+ /* We want to invent a mods set to be passed to modify_apply_mods() */
+
+ /* For now, we're only interested in subordinatecount.
+ We first examine the present value for the attribute.
+ If it isn't present and we're adding, we assign value 1 to the attribute and add it.
+ If it is present, we increment or decrement depending upon whether we're adding or deleting.
+ If the value after decrementing is zero, we remove it.
+ */
+
+ /* Get the present value of the subcount attr, or 0 if not present */
+ ret = slapi_entry_attr_find(mc->old_entry->ep_entry,numsubordinates,&read_attr);
+ if (0 == ret) {
+ /* decode the value */
+ Slapi_Value *sval;
+ slapi_attr_first_value( read_attr, &sval );
+ if (sval!=NULL) {
+ const struct berval *bval = slapi_value_get_berval(sval);
+ if(NULL != bval) {
+ already_present = 1;
+ current_sub_count = atol(bval->bv_val);
+ }
+ }
+ }
+ /* are we adding ? */
+ if ( (1 == op) && !already_present) {
+ /* If so, and the parent entry does not already have a subcount attribute, we need to add it */
+ mod_op = LDAP_MOD_ADD;
+ } else {
+ if (2 == op) {
+ if (!already_present) {
+ /* This means that something is wrong---deleting a child but no subcount present on parent */
+ LDAPDebug( LDAP_DEBUG_ANY, "numsubordinates assertion failure\n", 0, 0, 0 );
+ return -1;
+ } else {
+ if (current_sub_count == 1) {
+ mod_op = LDAP_MOD_DELETE;
+ } else {
+ mod_op = LDAP_MOD_REPLACE;
+ }
+ }
+ } else {
+ mod_op = LDAP_MOD_REPLACE;
+ }
+ }
+
+ /* Mow compute the new value */
+ if (1 == op) {
+ current_sub_count++;
+ } else {
+ current_sub_count--;
+ }
+
+ {
+ Slapi_Mods *smods= slapi_mods_new();
+ if (mod_op == LDAP_MOD_DELETE)
+ {
+ slapi_mods_add(smods, mod_op | LDAP_MOD_BVALUES, numsubordinates, 0, NULL);
+ }
+ else
+ {
+ char value_buffer[20]; /* enough digits for 2^64 children */
+ sprintf(value_buffer,"%lu", current_sub_count);
+ slapi_mods_add(smods, mod_op | LDAP_MOD_BVALUES, numsubordinates, strlen(value_buffer), value_buffer);
+ }
+ ret = modify_apply_mods(mc,smods); /* smods passed in */
+ }
+
+ if (new_sub_count)
+ *new_sub_count = current_sub_count;
+ return ret;
+}
diff --git a/ldap/servers/slapd/back-ldbm/perfctrs.c b/ldap/servers/slapd/back-ldbm/perfctrs.c
new file mode 100644
index 00000000..0457e170
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/perfctrs.c
@@ -0,0 +1,444 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Database performance counters stuff */
+#include "back-ldbm.h"
+
+#include "perfctrs.h"
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4000
+#define TXN_STAT(env, statp, flags, malloc) \
+ (env)->txn_stat((env), (statp), (flags))
+#define MEMP_STAT(env, gsp, fsp, flags, malloc) \
+ (env)->memp_stat((env), (gsp), (fsp), (flags))
+#define LOG_STAT(env, spp, flags, malloc) (env)->log_stat((env), (spp), (flags))
+#define LOCK_STAT(env, statp, flags, malloc) \
+ (env)->lock_stat((env), (statp), (flags))
+
+#else /* older than db 4.0 */
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3300
+#define TXN_STAT(env, statp, flags, malloc) txn_stat((env), (statp))
+#define MEMP_STAT(env, gsp, fsp, flags, malloc) memp_stat((env), (gsp), (fsp))
+#define LOG_STAT(env, spp, flags, malloc) log_stat((env), (spp))
+#define LOCK_STAT(env, statp, flags, malloc) lock_stat((env), (statp))
+
+#else /* older than db 3.3 */
+#define TXN_STAT(env, statp, flags, malloc) txn_stat((env), (statp), (malloc))
+#define MEMP_STAT(env, gsp, fsp, flags, malloc)
+ memp_stat((env), (gsp), (fsp), (malloc))
+#define LOG_STAT(env, spp, flags, malloc) log_stat((env), (spp), (malloc))
+#define LOCK_STAT(env, statp, flags, malloc) lock_stat((env), (statp), (malloc))
+#endif
+#endif
+
+static void perfctrs_update(perfctrs_private *priv, DB_ENV *db_env);
+static void perfctr_add_to_entry( Slapi_Entry *e, char *type,
+ PRUint32 countervalue );
+
+/*
+ * Win32 specific code (to support the Windows NT/2000 Performance Monitor).
+ */
+#if defined(_WIN32)
+static
+char * string_concatenate(char *a, char* b)
+{
+ size_t string_length = 0;
+ char *string = NULL;
+
+ string_length = strlen(a) + strlen(b) + 1;
+ string = malloc(string_length);
+ if (NULL == string) {
+ return string;
+ }
+ sprintf(string,"%s%s",a,b);
+ return string;
+}
+
+static void init_shared_memory(perfctrs_private *priv)
+{
+ performance_counters *perf = (performance_counters*)priv->memory;
+ if (NULL != perf) {
+ memset(perf,sizeof(performance_counters),0);
+ }
+}
+
+static int open_event(char *name, perfctrs_private *priv)
+{
+ HANDLE hEvent = INVALID_HANDLE_VALUE;
+
+ hEvent = OpenEvent(EVENT_ALL_ACCESS,FALSE,name);
+ if (NULL == hEvent) {
+ hEvent = CreateEvent(NULL,FALSE,FALSE,name);
+ if (NULL == hEvent) {
+ LDAPDebug(LDAP_DEBUG_ANY,"BAD EV 1, err=%d\n",GetLastError(),0,0);
+ return -1;
+ }
+ }
+ priv->hEvent = hEvent;
+ return 0;
+}
+
+static int open_shared_memory(char *name, perfctrs_private *priv)
+{
+ HANDLE hMapping = INVALID_HANDLE_VALUE;
+ void *pMemory = NULL;
+ /* We fear a bug in NT where it fails to attach to an existing region on calling CreateFileMapping, so let's call OpenFileMapping first */
+ hMapping = OpenFileMapping(FILE_MAP_ALL_ACCESS,FALSE,name);
+ if (NULL == hMapping) {
+ hMapping = CreateFileMapping((HANDLE)0xFFFFFFFF,NULL,PAGE_READWRITE,0,sizeof(performance_counters),name);
+ if (NULL == hMapping) {
+ LDAPDebug(LDAP_DEBUG_ANY,"BAD MAP 1, err=%d\n",GetLastError(),0,0);
+ return -1;
+ }
+ }
+ /* If we got to here, we have the mapping object open */
+ pMemory = MapViewOfFile(hMapping,FILE_MAP_ALL_ACCESS,0,0,0);
+ if (NULL == pMemory) {
+ LDAPDebug(LDAP_DEBUG_ANY,"BAD MAP 2, err=%d\n",GetLastError(),0,0);
+ return -1;
+ }
+ priv->memory = pMemory;
+ priv->hMemory = hMapping;
+ return 0;
+}
+#endif
+
+/* Init perf ctrs */
+void perfctrs_init(struct ldbminfo *li, perfctrs_private **ret_priv)
+{
+ perfctrs_private *priv = NULL;
+
+#if defined(_WIN32)
+ /* XXX What's my instance name ? */
+
+ /*
+ * We have a single DB environment for all backend databases.
+ * Therefore the instance name can be the server instance name.
+ * To match the db perf ctr DLL the instance name should be the
+ * name of a key defined in the registry under:
+ * HKEY_LOCAL_MACHINE\SOFTWARE\Netscape\Directory\5
+ * i.e. slapd-servername
+ */
+
+ char *string = NULL;
+ char *instance_name = li->li_plugin->plg_name; /* XXX does not identify server instance */
+#endif
+
+ *ret_priv = NULL;
+
+#if defined(_WIN32)
+ /*
+ * On Windows, the performance counters reside in shared memory.
+ */
+ if (NULL == instance_name) {
+ return;
+ }
+ /* Invent the name for the shared memory region */
+ string = string_concatenate(instance_name,PERFCTRS_REGION_SUFFIX);
+ if (NULL == string) {
+ return;
+ }
+#endif
+
+ /*
+ * We need the perfctrs_private area on all platforms.
+ */
+ priv = calloc(1,sizeof(perfctrs_private));
+ if (NULL == priv) {
+ return;
+ }
+
+#if defined(_WIN32)
+ /* Try to open the shared memory region */
+ open_shared_memory(string,priv);
+ free(string);
+ /* Invent the name for the update mutex */
+ string = string_concatenate(instance_name,PERFCTRS_MUTEX_SUFFIX);
+ if (NULL == string) {
+ return;
+ }
+ open_event(string,priv);
+ free(string);
+ init_shared_memory(priv);
+
+#else
+ /*
+ * On other platforms, the performance counters reside in regular memory.
+ */
+ if ( NULL == ( priv->memory = calloc( 1, sizeof( performance_counters )))) {
+ return;
+ }
+#endif
+
+ *ret_priv = priv;
+}
+
+/* Terminate perf ctrs */
+void perfctrs_terminate(perfctrs_private **priv)
+{
+#if defined(_WIN32)
+ if (NULL != (*priv)->memory) {
+ UnmapViewOfFile((*priv)->memory);
+ }
+ if (NULL != (*priv)->hMemory) {
+ CloseHandle((*priv)->hMemory);
+ }
+ if (NULL != (*priv)->hEvent) {
+ CloseHandle((*priv)->hEvent);
+ }
+#else
+ if (NULL != (*priv)->memory) {
+ free((*priv)->memory);
+ }
+#endif
+
+ free( (*priv) );
+ (*priv) = NULL;
+}
+
+/* Wait while checking for perfctr update requests */
+void perfctrs_wait(size_t milliseconds,perfctrs_private *priv,DB_ENV *db_env)
+{
+#if defined(_WIN32)
+ if (NULL != priv) {
+ DWORD ret = 0;
+ if (NULL != priv->hEvent) {
+ /* Sleep waiting on the perfctrs update event */
+ ret = WaitForSingleObject(priv->hEvent,milliseconds);
+ /* If we didn't time out, update the perfctrs */
+ if (ret == WAIT_OBJECT_0) {
+ perfctrs_update(priv,db_env);
+ }
+ } else {
+ Sleep(milliseconds);
+ }
+ }
+#else
+ /* Just sleep */
+ PRIntervalTime interval; /*NSPR timeout stuffy*/
+ interval = PR_MillisecondsToInterval(milliseconds);
+ DS_Sleep(interval);
+#endif
+}
+
+/* Update perfctrs */
+static
+void perfctrs_update(perfctrs_private *priv, DB_ENV *db_env)
+{
+ int ret = 0;
+ performance_counters *perf;
+ if (NULL == priv) {
+ return;
+ }
+ if (NULL == db_env) {
+ return;
+ }
+ perf = (performance_counters*)priv->memory;
+ if (NULL == perf) {
+ return;
+ }
+ /* Call libdb to get the various stats */
+ if (NULL != db_env->lg_handle)
+ {
+ DB_LOG_STAT *logstat = NULL;
+ ret = LOG_STAT(db_env,&logstat,0,malloc);
+ if (0 == ret) {
+ perf->log_region_wait_rate = logstat->st_region_wait;
+ perf->log_write_rate = 1024*1024*logstat->st_w_mbytes + logstat->st_w_bytes;
+ perf->log_bytes_since_checkpoint = 1024*1024*logstat->st_wc_mbytes + logstat->st_wc_bytes;
+ }
+ free(logstat);
+ }
+ if (NULL != db_env->tx_handle)
+ {
+ DB_TXN_STAT *txnstat = NULL;
+ ret = TXN_STAT(db_env, &txnstat, 0, malloc);
+ if (0 == ret) {
+ perf->active_txns = txnstat->st_nactive;
+ perf->commit_rate = txnstat->st_ncommits;
+ perf->abort_rate = txnstat->st_naborts;
+ perf->txn_region_wait_rate = txnstat->st_region_wait;
+ }
+ if (txnstat)
+ free(txnstat);
+ }
+ if (NULL != db_env->lk_handle)
+ {
+ DB_LOCK_STAT *lockstat = NULL;
+ ret = LOCK_STAT(db_env,&lockstat,0,malloc);
+ if (0 == ret) {
+ perf->lock_region_wait_rate = lockstat->st_region_wait;
+ perf->deadlock_rate = lockstat->st_ndeadlocks;
+ perf->configured_locks = lockstat->st_maxlocks;
+ perf->current_locks = lockstat->st_nlocks;
+ perf->max_locks = lockstat->st_maxnlocks;
+ perf->lockers = lockstat->st_nlockers;
+ perf->lock_conflicts = lockstat->st_nconflicts;
+ perf->lock_request_rate = lockstat->st_nrequests;
+ perf->current_lock_objects = lockstat->st_nobjects;
+ perf->max_lock_objects = lockstat->st_maxnobjects;
+ }
+ free(lockstat);
+ }
+ if (NULL != db_env->mp_handle)
+ {
+ DB_MPOOL_STAT *mpstat = NULL;
+ ret = MEMP_STAT(db_env,&mpstat,NULL,0,malloc);
+ if (0 == ret) {
+#define ONEG 1073741824
+ perf->cache_size_bytes = mpstat->st_gbytes * ONEG + mpstat->st_bytes;
+ perf->page_access_rate = mpstat->st_cache_hit + mpstat->st_cache_miss;
+ perf->cache_hit = mpstat->st_cache_hit;
+ perf->cache_try = mpstat->st_cache_hit + mpstat->st_cache_miss;
+ perf->page_create_rate = mpstat->st_page_create;
+ perf->page_read_rate = mpstat->st_page_in;
+ perf->page_write_rate = mpstat->st_page_out;
+ perf->page_ro_evict_rate = mpstat->st_ro_evict;
+ perf->page_rw_evict_rate = mpstat->st_rw_evict;
+ perf->hash_buckets = mpstat->st_hash_buckets;
+ perf->hash_search_rate = mpstat->st_hash_searches;
+ perf->longest_chain_length = mpstat->st_hash_longest;
+ perf->hash_elements_examine_rate = mpstat->st_hash_examined;
+ perf->pages_in_use = mpstat->st_page_dirty + mpstat->st_page_clean;
+ perf->dirty_pages = mpstat->st_page_dirty;
+ perf->clean_pages = mpstat->st_page_clean;
+ perf->page_trickle_rate = mpstat->st_page_trickle;
+ perf->cache_region_wait_rate = mpstat->st_region_wait;
+ free(mpstat);
+ }
+ }
+ /* Place the stats in the shared memory region */
+ /* Bump the sequence number */
+ perf->sequence_number++;
+}
+
+
+
+/*
+ * Define a map (array of structures) which is used to retrieve performance
+ * counters from the performance_counters structure and map them to an
+ * LDAP attribute type.
+ */
+
+#define SLAPI_LDBM_PERFCTR_AT_PREFIX "nsslapd-db-"
+typedef struct slapi_ldbm_perfctr_at_map {
+ char *pam_type; /* name of LDAP attribute type */
+ size_t pam_offset; /* offset into performance_counters struct */
+} SlapiLDBMPerfctrATMap;
+
+static SlapiLDBMPerfctrATMap perfctr_at_map[] = {
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "abort-rate",
+ offsetof( performance_counters, abort_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "active-txns",
+ offsetof( performance_counters, active_txns ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "cache-hit",
+ offsetof( performance_counters, cache_hit ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "cache-try",
+ offsetof( performance_counters, cache_try ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "cache-region-wait-rate",
+ offsetof( performance_counters, cache_region_wait_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "cache-size-bytes",
+ offsetof( performance_counters, cache_size_bytes ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "clean-pages",
+ offsetof( performance_counters, clean_pages ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "commit-rate",
+ offsetof( performance_counters, commit_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "deadlock-rate",
+ offsetof( performance_counters, deadlock_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "dirty-pages",
+ offsetof( performance_counters, dirty_pages ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "hash-buckets",
+ offsetof( performance_counters, hash_buckets ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "hash-elements-examine-rate",
+ offsetof( performance_counters, hash_elements_examine_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "hash-search-rate",
+ offsetof( performance_counters, hash_search_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "lock-conflicts",
+ offsetof( performance_counters, lock_conflicts ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "lock-region-wait-rate",
+ offsetof( performance_counters, lock_region_wait_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "lock-request-rate",
+ offsetof( performance_counters, lock_request_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "lockers",
+ offsetof( performance_counters, lockers ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "configured-locks",
+ offsetof( performance_counters, configured_locks ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "current-locks",
+ offsetof( performance_counters, current_locks ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "max-locks",
+ offsetof( performance_counters, max_locks ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "current-lock-objects",
+ offsetof( performance_counters, current_lock_objects ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "max-lock-objects",
+ offsetof( performance_counters, max_lock_objects ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "log-bytes-since-checkpoint",
+ offsetof( performance_counters, log_bytes_since_checkpoint ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "log-region-wait-rate",
+ offsetof( performance_counters, log_region_wait_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "log-write-rate",
+ offsetof( performance_counters, log_write_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "longest-chain-length",
+ offsetof( performance_counters, longest_chain_length ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "objects-locked",
+ offsetof( performance_counters, page_access_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "page-create-rate",
+ offsetof( performance_counters, page_create_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "page-read-rate",
+ offsetof( performance_counters, page_read_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "page-ro-evict-rate",
+ offsetof( performance_counters, page_ro_evict_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "page-rw-evict-rate",
+ offsetof( performance_counters, page_rw_evict_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "page-trickle-rate",
+ offsetof( performance_counters, page_trickle_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "page-write-rate",
+ offsetof( performance_counters, page_write_rate ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "pages-in-use",
+ offsetof( performance_counters, pages_in_use ) },
+ { SLAPI_LDBM_PERFCTR_AT_PREFIX "txn-region-wait-rate",
+ offsetof( performance_counters, txn_region_wait_rate ) },
+};
+#define SLAPI_LDBM_PERFCTR_AT_MAP_COUNT \
+ (sizeof(perfctr_at_map) / sizeof(SlapiLDBMPerfctrATMap))
+
+
+/*
+ * Set attributes and values in entry `e' based on performance counter
+ * information (from `priv').
+ */
+void
+perfctrs_as_entry( Slapi_Entry *e, perfctrs_private *priv, DB_ENV *db_env )
+{
+ performance_counters *perf;
+ int i;
+
+ if (priv == NULL) return;
+
+ perf = (performance_counters*)priv->memory;
+
+ /*
+ * First, update the values so they are current.
+ */
+ perfctrs_update( priv, db_env );
+
+ /*
+ * Then convert all the counters to attribute values.
+ */
+ for ( i = 0; i < SLAPI_LDBM_PERFCTR_AT_MAP_COUNT; ++i ) {
+ perfctr_add_to_entry( e, perfctr_at_map[i].pam_type,
+ *((PRUint32 *)((char *)perf + perfctr_at_map[i].pam_offset)));
+ }
+}
+
+
+static void
+perfctr_add_to_entry( Slapi_Entry *e, char *type, PRUint32 countervalue )
+{
+ /*
+ * XXXmcs: the following line assumes that long's are 32 bits or larger,
+ * which we assume in other places too I am sure.
+ */
+ slapi_entry_attr_set_ulong( e, type, (unsigned long)countervalue );
+}
diff --git a/ldap/servers/slapd/back-ldbm/perfctrs.h b/ldap/servers/slapd/back-ldbm/perfctrs.h
new file mode 100644
index 00000000..8aed8d55
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/perfctrs.h
@@ -0,0 +1,51 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Structure definition for performance data */
+/* This stuff goes in shared memory, so make sure the packing is consistent */
+
+struct _performance_counters {
+ PRUint32 sequence_number;
+ PRUint32 lock_region_wait_rate;
+ PRUint32 deadlock_rate;
+ PRUint32 configured_locks;
+ PRUint32 current_locks;
+ PRUint32 max_locks;
+ PRUint32 lockers;
+ PRUint32 current_lock_objects;
+ PRUint32 max_lock_objects;
+ PRUint32 lock_conflicts;
+ PRUint32 lock_request_rate;
+ PRUint32 log_region_wait_rate;
+ PRUint32 log_write_rate;
+ PRUint32 log_bytes_since_checkpoint;
+ PRUint32 cache_size_bytes;
+ PRUint32 page_access_rate;
+ PRUint32 cache_hit;
+ PRUint32 cache_try;
+ PRUint32 page_create_rate;
+ PRUint32 page_read_rate;
+ PRUint32 page_write_rate;
+ PRUint32 page_ro_evict_rate;
+ PRUint32 page_rw_evict_rate;
+ PRUint32 hash_buckets;
+ PRUint32 hash_search_rate;
+ PRUint32 longest_chain_length;
+ PRUint32 hash_elements_examine_rate;
+ PRUint32 pages_in_use;
+ PRUint32 dirty_pages;
+ PRUint32 clean_pages;
+ PRUint32 page_trickle_rate;
+ PRUint32 cache_region_wait_rate;
+ PRUint32 active_txns;
+ PRUint32 commit_rate;
+ PRUint32 abort_rate;
+ PRUint32 txn_region_wait_rate;
+};
+typedef struct _performance_counters performance_counters;
+
+#define PERFCTRS_REGION_SUFFIX "-sm"
+#define PERFCTRS_MUTEX_SUFFIX "-mx"
+
diff --git a/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
new file mode 100644
index 00000000..4e8ed4df
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/proto-back-ldbm.h
@@ -0,0 +1,582 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _PROTO_BACK_LDBM
+#define _PROTO_BACK_LDBM
+
+/*
+ * attr.c
+ */
+struct attrinfo * attrinfo_new();
+void attrinfo_delete(struct attrinfo **pp);
+void ainfo_get( backend *be, char *type, struct attrinfo **at );
+void attr_masks( backend *be, char *type, int *indexmask,
+ int *syntaxmask );
+void attr_masks_ex( backend *be, char *type, int *indexmask,
+ int *syntaxmask, struct attrinfo **at );
+void attr_index_config( backend *be, char *fname, int lineno,
+ int argc, char **argv, int init );
+int ldbm_compute_init();
+void attrinfo_deletetree(ldbm_instance *inst);
+void attr_create_empty(backend *be,char *type,struct attrinfo **ai);
+
+/*
+ * cache.c
+ */
+int cache_init(struct cache *cache, size_t maxsize, long maxentries);
+void cache_clear(struct cache *cache);
+void cache_destroy_please(struct cache *cache);
+void cache_set_max_size(struct cache *cache, size_t bytes);
+void cache_set_max_entries(struct cache *cache, long entries);
+size_t cache_get_max_size(struct cache *cache);
+long cache_get_max_entries(struct cache *cache);
+void cache_get_stats(struct cache *cache, u_long *hits, u_long *tries,
+ long *entries,long *maxentries,
+ size_t *size, size_t *maxsize);
+void cache_debug_hash(struct cache *cache, char **out);
+int cache_remove(struct cache *cache, struct backentry *e);
+void cache_return(struct cache *cache, struct backentry **bep);
+struct backentry *cache_find_dn(struct cache *cache, const char *dn, unsigned long ndnlen);
+struct backentry *cache_find_id(struct cache *cache, ID id);
+struct backentry *cache_find_uuid(struct cache *cache, const char *uuid);
+int cache_add(struct cache *cache, struct backentry *e,
+ struct backentry **alt);
+int cache_add_tentative(struct cache *cache, struct backentry *e,
+ struct backentry **alt);
+int cache_lock_entry(struct cache *cache, struct backentry *e);
+void cache_unlock_entry(struct cache *cache, struct backentry *e);
+int cache_replace(struct cache *cache, struct backentry *olde,
+ struct backentry *newe);
+
+Hashtable *new_hash(u_long size, u_long offset, HashFn hfn,
+ HashTestFn tfn);
+int add_hash(Hashtable *ht, void *key, size_t keylen, void *entry,
+ void **alt);
+int find_hash(Hashtable *ht, const void *key, size_t keylen, void **entry);
+int remove_hash(Hashtable *ht, const void *key, size_t keylen);
+
+/*
+ * dblayer.c
+ */
+int dblayer_init(struct ldbminfo *li);
+int dblayer_terminate(struct ldbminfo *li);
+int dblayer_start(struct ldbminfo *li, int dbmode);
+int dblayer_flush(struct ldbminfo *li );
+int dblayer_close(struct ldbminfo *li, int dbmode );
+void dblayer_pre_close(struct ldbminfo *li);
+int dblayer_post_close(struct ldbminfo *li, int dbmode );
+int dblayer_instance_close(backend *be);
+int dblayer_get_index_file(backend *be,struct attrinfo *a, DB** ppDB, int create);
+int dblayer_release_index_file(backend *be,struct attrinfo *a, DB* pDB);
+int dblayer_erase_index_file(backend *be, struct attrinfo *a, int no_force_chkpt);
+int dblayer_erase_index_file_nolock(backend *be, struct attrinfo *a, int no_force_chkpt);
+int dblayer_get_id2entry(backend *be, DB **ppDB);
+int dblayer_release_id2entry(backend *be, DB *pDB);
+int dblayer_get_aux_id2entry(backend *be, DB **ppDB, DB_ENV **ppEnv);
+int dblayer_release_aux_id2entry(backend *be, DB *pDB, DB_ENV *pEnv);
+int dblayer_txn_init(struct ldbminfo *li, back_txn *txn);
+int dblayer_txn_begin(struct ldbminfo *li,back_txnid parent_txn, back_txn *txn);
+int dblayer_txn_commit(struct ldbminfo *li, back_txn *txn);
+int dblayer_txn_abort(struct ldbminfo *li, back_txn *txn);
+int dblayer_read_txn_abort(struct ldbminfo *li, back_txn *txn);
+int dblayer_read_txn_begin(struct ldbminfo *li,back_txnid parent_txn, back_txn *txn);
+int dblayer_read_txn_commit(struct ldbminfo *li, back_txn *txn);
+size_t dblayer_get_optimal_block_size(struct ldbminfo *li);
+void dblayer_unlock_backend(backend *be);
+void dblayer_lock_backend(backend *be);
+int dblayer_plugin_begin(Slapi_PBlock *pb);
+int dblayer_plugin_commit(Slapi_PBlock *pb);
+int dblayer_plugin_abort(Slapi_PBlock *pb);
+int dblayer_memp_stat(struct ldbminfo *li, DB_MPOOL_STAT **gsp,DB_MPOOL_FSTAT ***fsp);
+int dblayer_memp_stat_instance(ldbm_instance *inst, DB_MPOOL_STAT **gsp, DB_MPOOL_FSTAT ***fsp);
+int dblayer_backup(struct ldbminfo *li, char *destination_directory,
+ Slapi_Task *task);
+int dblayer_restore(struct ldbminfo *li, char* source_directory, Slapi_Task *task);
+int dblayer_copy_directory(struct ldbminfo *li, Slapi_Task *task,
+ char *instance_dir, char *destination_dir,
+ int restore, int *cnt, int instance_dir_flag,
+ int indexonly);
+int dblayer_copyfile(char* source, char * destination, int overwrite, int mode);
+int dblayer_delete_instance_dir(backend *be);
+int dblayer_delete_database(struct ldbminfo *li);
+int dblayer_database_size(struct ldbminfo *li, unsigned int *size);
+int dblayer_terminate(struct ldbminfo *li);
+int dblayer_close_indexes(backend *be);
+int dblayer_open_file(backend *be, char* indexname, int create, int index_flags, DB **ppDB);
+int dblayer_close_file(DB *db);
+void dblayer_sys_pages(size_t *pagesize, size_t *pages, size_t *procpages, size_t *availpages);
+int dblayer_is_cachesize_sane(size_t *cachesize);
+void dblayer_remember_disk_filled(struct ldbminfo *li);
+int dblayer_open_huge_file(const char *path, int oflag, int mode);
+int dblayer_instance_start(backend *be, int normal_mode);
+int dblayer_make_new_instance_data_dir(backend *be);
+int dblayer_get_instance_data_dir(backend *be);
+char *dblayer_strerror(int error);
+PRInt64 db_atol(char *str, int *err);
+PRInt64 db_atoi(char *str, int *err);
+unsigned long db_strtoul(const char *str, int *err);
+int dblayer_set_batch_transactions(void *arg, void *value, char *errorbuf, int phase, int apply);
+void *dblayer_get_batch_transactions(void *arg);
+int dblayer_in_import(ldbm_instance *inst);
+
+int dblayer_update_db_ext(ldbm_instance *inst, char *oldext, char *newext);
+void dblayer_set_recovery_required(struct ldbminfo *li);
+
+char *dblayer_get_home_dir(struct ldbminfo *li, int *dbhome);
+char *dblayer_get_full_inst_dir(struct ldbminfo *li, ldbm_instance *inst,
+ char *buf, int buflen);
+void autosize_import_cache(struct ldbminfo *li);
+
+
+/*
+ * dn2entry.c
+ */
+struct backentry *dn2entry(Slapi_Backend *be, const Slapi_DN *sdn, back_txn *txn, int *err);
+struct backentry *dn2entry_or_ancestor(Slapi_Backend *be, const Slapi_DN *sdn, Slapi_DN *ancestor, back_txn *txn, int *err);
+struct backentry *dn2ancestor(Slapi_Backend *be,const Slapi_DN *sdn,Slapi_DN *ancestordn,back_txn *txn,int *err);
+int get_copy_of_entry(Slapi_PBlock *pb, const entry_address *addr, back_txn *txn, int plock_parameter, int must_exist);
+void done_with_pblock_entry(Slapi_PBlock *pb, int plock_parameter);
+
+/*
+ * uniqueid2entry.c
+ */
+struct backentry * uniqueid2entry(backend *be, const char *uniqueid,
+ back_txn *txn, int *err);
+
+/*
+ * filterindex.c
+ */
+IDList * filter_candidates( Slapi_PBlock *pb, backend *be, const char *base, Slapi_Filter *f, Slapi_Filter *nextf, int range, int *err );
+
+/*
+ * findentry.c
+ */
+struct backentry * find_entry2modify( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
+struct backentry * find_entry( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn );
+struct backentry * find_entry2modify_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
+struct backentry * find_entry_only( Slapi_PBlock *pb, Slapi_Backend *be, const entry_address *addr, back_txn *txn);
+int check_entry_for_referral(Slapi_PBlock *pb, Slapi_Entry *entry, char *matched, const char *callingfn);
+
+/*
+ * haschildren.c
+ */
+int has_children( struct ldbminfo *li, struct backentry *p, back_txn *txn, int *err );
+
+/*
+ * id2entry.c
+ */
+int id2entry_add( backend *be, struct backentry *e, back_txn *txn );
+int id2entry_add_ext( backend *be, struct backentry *e, back_txn *txn, int encrypt );
+int id2entry_delete( backend *be, struct backentry *e, back_txn *txn );
+struct backentry * id2entry( backend *be, ID id, back_txn *txn, int *err );
+
+/*
+ * idl.c
+ */
+IDList * idl_alloc( NIDS nids );
+void idl_free( IDList *idl );
+NIDS idl_length(IDList *idl);
+int idl_is_allids(IDList *idl);
+int idl_append( IDList *idl, ID id);
+void idl_insert(IDList **idl, ID id);
+IDList * idl_allids( backend *be );
+IDList * idl_fetch( backend *be, DB* db, DBT *key, DB_TXN *txn, struct attrinfo *a, int *err );
+int idl_insert_key( backend *be, DB* db, DBT *key, ID id, DB_TXN *txn, struct attrinfo *a,int *disposition );
+int idl_delete_key( backend *be, DB *db, DBT *key, ID id, DB_TXN *txn, struct attrinfo *a );
+IDList * idl_intersection( backend *be, IDList *a, IDList *b );
+IDList * idl_union( backend *be, IDList *a, IDList *b );
+int idl_notin( backend *be, IDList *a, IDList *b , IDList **new_result);
+ID idl_firstid( IDList *idl );
+ID idl_nextid( IDList *idl, ID id );
+int idl_init_private(backend *be, struct attrinfo *a);
+int idl_release_private(struct attrinfo *a);
+
+idl_iterator idl_iterator_init(const IDList *idl);
+idl_iterator idl_iterator_increment(idl_iterator *i);
+idl_iterator idl_iterator_decrement(idl_iterator *i);
+ID idl_iterator_dereference(idl_iterator i, const IDList *idl);
+ID idl_iterator_dereference_increment(idl_iterator *i, const IDList *idl);
+size_t idl_sizeof(IDList *idl);
+int idl_store_block(backend *be,DB *db,DBT *key,IDList *idl,DB_TXN *txn,struct attrinfo *a);
+void idl_set_tune(int val);
+int idl_get_tune();
+size_t idl_get_allidslimit(struct attrinfo *a);
+int idl_get_idl_new();
+int idl_new_compare_dups(
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 3200
+ DB *db,
+#endif
+ const DBT *a,
+ const DBT *b
+);
+
+/*
+ * index.c
+ */
+int index_addordel_entry( backend *be, struct backentry *e, int flags, back_txn *txn );
+int index_add_mods( backend *be, const LDAPMod**mods, struct backentry *olde, struct backentry *newe, back_txn *txn );
+int index_addordel_string(backend *be, const char *type, const char *s, ID id, int flags, back_txn *txn);
+int index_addordel_values_sv( backend *be, const char *type, Slapi_Value **vals, Slapi_Value **evals, ID id, int flags, back_txn *txn );
+int index_addordel_values_ext_sv( backend *be, const char *type, Slapi_Value **vals, Slapi_Value **evals, ID id, int flags, back_txn *txn,int *idl_disposition, void *buffer_handle );
+int id_array_init(Id_Array *new_guy, int size);
+
+IDList* index_read( backend *be, char *type, const char* indextype, const struct berval* val, back_txn *txn, int *err );
+IDList* index_read_ext( backend *be, char *type, const char* indextype, const struct berval* val, back_txn *txn, int *err, int *unindexed );
+IDList* index_range_read( Slapi_PBlock *pb, backend *be, char *type, const char* indextype, int ftype, struct berval* val, struct berval* nextval, int range, back_txn *txn, int *err );
+const char *encode( const struct berval* data, char buf[BUFSIZ] );
+
+extern const char* indextype_PRESENCE;
+extern const char* indextype_EQUALITY;
+extern const char* indextype_APPROX;
+extern const char* indextype_SUB;
+
+int index_buffer_init(size_t size,int flags,void **h);
+int index_buffer_flush(void *h,backend *be, DB_TXN *txn,struct attrinfo *a);
+int index_buffer_terminate(void *h);
+
+/*
+ * instance.c
+ */
+int ldbm_instance_create(backend *be, char *name);
+int ldbm_instance_create_default_indexes(backend *be);
+int ldbm_instance_start(backend *be);
+int ldbm_instance_stop(backend *be);
+int ldbm_instance_startall(struct ldbminfo *li);
+int ldbm_instance_stopall(struct ldbminfo *li);
+ldbm_instance *ldbm_instance_find_by_name(struct ldbminfo *li, char *name);
+int ldbm_instance_destroy(ldbm_instance *inst);
+
+/*
+ * ldif2ldbm.c
+ */
+int import_subcount_mother_init(import_subcount_stuff *mothers,ID parent_id, size_t count);
+int import_subcount_mother_count(import_subcount_stuff *mothers,ID parent_id);
+void import_subcount_stuff_init(import_subcount_stuff *stuff);
+void import_subcount_stuff_term(import_subcount_stuff *stuff);
+int update_subordinatecounts(backend *be,import_subcount_stuff *mothers, DB_TXN *txn);
+void import_configure_index_buffer_size(size_t size);
+size_t import_get_index_buffer_size();
+int ldbm_back_fetch_incl_excl(Slapi_PBlock *pb, char ***include,
+ char ***exclude);
+void ldbm_back_free_incl_excl(char **include, char **exclude);
+int ldbm_back_ok_to_dump(const char *dn, char **include, char **exclude);
+int ldbm_back_wire_import(Slapi_PBlock *pb);
+void *factory_constructor(void *object, void *parent);
+void factory_destructor(void *extension, void *object, void *parent);
+
+/*
+ * modify.c
+ */
+int modify_update_all(backend *be, Slapi_PBlock *pb,modify_context *mc,back_txn *txn);
+void modify_init(modify_context *mc,struct backentry *old_entry);
+int modify_apply_mods(modify_context *mc, Slapi_Mods *smods);
+int modify_term(modify_context *mc,backend *be);
+int modify_switch_entries(modify_context *mc,backend *be);
+
+/*
+ * add.c
+ */
+void add_update_entry_operational_attributes(struct backentry *ep, ID pid);
+void add_update_entrydn_operational_attributes(struct backentry *ep);
+
+/*
+ * misc.c
+ */
+void ldbm_nasty(const char* str, int c, int err);
+void ldbm_log_access_message(Slapi_PBlock *pblock,char *string);
+int return_on_disk_full(struct ldbminfo *li);
+int ldbm_attribute_always_indexed(const char *attrtype);
+void ldbm_destroy_instance_name(struct ldbminfo *li);
+char *compute_entry_tombstone_dn(const char *entrydn, const char *uniqueid);
+int instance_set_busy(ldbm_instance *inst);
+int instance_set_busy_and_readonly(ldbm_instance *inst);
+void instance_set_not_busy(ldbm_instance *inst);
+void allinstance_set_busy(struct ldbminfo *li);
+void allinstance_set_not_busy(struct ldbminfo *li);
+int is_anyinstance_busy(struct ldbminfo *li);
+int ldbm_delete_dirs(char *path);
+int mkdir_p(char *dir, unsigned int mode);
+int is_fullpath(char *path);
+char get_sep(char *path);
+
+/*
+ * nextid.c
+ */
+ID next_id( backend *be );
+void next_id_return( backend *be, ID id );
+ID next_id_get( backend *be );
+void id_internal_to_stored(ID,char*);
+ID id_stored_to_internal(char*);
+#if 0
+int write_dbversion( ldbm_instance *inst );
+#endif
+void get_ids_from_disk(backend *be);
+void get_both_ids( struct ldbminfo *li, ID *nextid, ID *nextid2index );
+
+/*
+ * backentry.c
+ */
+struct backentry *backentry_init( Slapi_Entry *e );
+struct backentry *backentry_alloc();
+void backentry_free( struct backentry **bep );
+struct backentry *backentry_dup( struct backentry * );
+void backentry_clear_entry( struct backentry * );
+char *backentry_get_ndn(const struct backentry *e);
+const Slapi_DN *backentry_get_sdn(const struct backentry *e);
+
+/*
+ * parents.c
+ */
+int parent_update_on_childchange(modify_context *mc,int op, size_t *numofchildren);
+
+/*
+ * perfctrs.c
+ */
+void perfctrs_wait(size_t milliseconds,perfctrs_private *priv,DB_ENV *db_env);
+void perfctrs_init(struct ldbminfo *li,perfctrs_private **priv);
+void perfctrs_terminate(perfctrs_private **priv);
+void perfctrs_as_entry( Slapi_Entry *e, perfctrs_private *priv, DB_ENV *db_env );
+
+/*
+ * rmdb.c
+ */
+int ldbm_back_rmdb( Slapi_PBlock *pb );
+
+/*
+ * sort.c
+ */
+
+/*
+ * Definitions for sort spec object
+ */
+struct sort_spec_thing
+{
+ char *type;
+ char *matchrule; /* Matching rule string */
+ int order; /* 0 == ascending, 1 == decending */
+ struct sort_spec_thing *next; /* Link to the next one */
+ Slapi_PBlock *mr_pb; /* For matchrule indexing */
+ value_compare_fn_type compare_fn; /* For non-matchrule indexing */
+};
+typedef struct sort_spec_thing sort_spec_thing;
+typedef struct sort_spec_thing sort_spec;
+
+void sort_spec_free(sort_spec *s);
+int sort_candidates(backend *be, int lookthrough_limit, time_t time_up, Slapi_PBlock *pb, IDList *candidates, sort_spec_thing *sort_spec, char **sort_error_type) ;
+int make_sort_response_control ( Slapi_PBlock *pb, int code, char *error_type);
+int parse_sort_spec(struct berval *sort_spec_ber, sort_spec **ps);
+struct berval* attr_value_lowest(struct berval **values, value_compare_fn_type compare_fn);
+int sort_attr_compare(struct berval ** value_a, struct berval ** value_b, value_compare_fn_type compare_fn);
+void sort_log_access(Slapi_PBlock *pb,sort_spec_thing *s,IDList *candidates);
+
+/*
+ * dbsize.c
+ */
+int ldbm_db_size( Slapi_PBlock *pb );
+
+/*
+ * external functions
+ */
+int ldbm_back_bind( Slapi_PBlock *pb );
+int ldbm_back_unbind( Slapi_PBlock *pb );
+int ldbm_back_search( Slapi_PBlock *pb );
+int ldbm_back_compare( Slapi_PBlock *pb );
+int ldbm_back_modify( Slapi_PBlock *pb );
+int ldbm_back_modrdn( Slapi_PBlock *pb );
+int ldbm_back_add( Slapi_PBlock *pb );
+int ldbm_back_delete( Slapi_PBlock *pb );
+int ldbm_back_abandon( Slapi_PBlock *pb );
+int ldbm_back_config( Slapi_PBlock *pb );
+int ldbm_back_close( Slapi_PBlock *pb );
+int ldbm_back_cleanup( Slapi_PBlock *pb );
+void ldbm_back_instance_set_destructor(void **arg);
+int ldbm_back_flush( Slapi_PBlock *pb );
+int ldbm_back_start( Slapi_PBlock *pb );
+int ldbm_back_seq( Slapi_PBlock *pb );
+int ldbm_back_ldif2ldbm( Slapi_PBlock *pb );
+int ldbm_back_ldbm2ldif( Slapi_PBlock *pb );
+int ldbm_back_ldbm2ldifalt( Slapi_PBlock *pb );
+int ldbm_back_ldbm2index( Slapi_PBlock *pb );
+int ldbm_back_archive2ldbm( Slapi_PBlock *pb );
+int ldbm_back_ldbm2archive( Slapi_PBlock *pb );
+#if defined(UPGRADEDB)
+int ldbm_back_upgradedb( Slapi_PBlock *pb );
+#endif
+int ldbm_back_next_search_entry( Slapi_PBlock *pb );
+int ldbm_back_next_search_entry_ext( Slapi_PBlock *pb, int use_extension );
+int ldbm_back_db_test( Slapi_PBlock *pb );
+int ldbm_back_entry_release( Slapi_PBlock *pb, void *backend_info_ptr );
+int ldbm_back_init( Slapi_PBlock *pb );
+
+/*
+ * monitor.c
+ */
+
+int ldbm_back_monitor_search(Slapi_PBlock *pb, Slapi_Entry* e,
+ Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int ldbm_back_monitor_instance_search(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
+int ldbm_back_dbmonitor_search(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
+
+/*
+ * vlv.c
+ */
+struct vlv_request
+{
+ unsigned long beforeCount;
+ unsigned long afterCount;
+ unsigned long tag;
+ unsigned long index;
+ unsigned long contentCount;
+ struct berval value;
+};
+
+struct vlv_response
+{
+ unsigned long targetPosition;
+ unsigned long contentCount;
+ unsigned long result;
+};
+
+int vlv_init(ldbm_instance *inst);
+int vlv_remove_callbacks(ldbm_instance *inst);
+const Slapi_Entry **vlv_get_search_entries();
+struct vlvIndex* vlv_find_searchname(const char * name, backend *be);
+struct vlvIndex* vlv_find_indexname(const char * name, backend *be);
+char *vlv_getindexnames();
+int vlv_search_build_candidate_list(Slapi_PBlock *pb, const Slapi_DN *base, int *rc, const sort_spec* sort_control,
+ const struct vlv_request *vlv_request_control, IDList** candidates, struct vlv_response *vlv_response_control);
+int vlv_update_index(struct vlvIndex* p, back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct backentry* oldEntry, struct backentry* newEntry);
+int vlv_update_all_indexes(back_txn *txn, backend *be, Slapi_PBlock *pb, struct backentry* oldEntry, struct backentry* newEntry);
+int vlv_filter_candidates(backend *be, Slapi_PBlock *pb, const IDList *candidates, const Slapi_DN *base, int scope, Slapi_Filter *filter, IDList** filteredCandidates,int lookthrough_limit, time_t time_up);
+int vlv_trim_candidates(backend *be, const IDList *candidates, const sort_spec* sort_control, const struct vlv_request *vlv_request_control, IDList** filteredCandidates,struct vlv_response *pResponse);
+int vlv_parse_request_control(backend *be, struct berval *vlv_spec_ber, struct vlv_request* vlvp);
+int vlv_make_response_control(Slapi_PBlock *pb, const struct vlv_response* vlvp);
+void vlv_getindices(IFP callback_fn,void *param, backend *be);
+void vlv_print_access_log(Slapi_PBlock *pb,struct vlv_request* vlvi, struct vlv_response *vlvo);
+void vlv_grok_new_import_entry(const struct backentry *e, backend *be);
+IDList *vlv_find_index_by_filter(struct backend *be, const char *base,
+ Slapi_Filter *f);
+int vlv_delete_search_entry(Slapi_PBlock *pb, Slapi_Entry* e, ldbm_instance *inst);
+void vlv_acquire_lock(backend *be);
+void vlv_release_lock(backend *be);
+int vlv_isvlv(char *filename);
+
+/*
+ * Indexfile.c
+ */
+int indexfile_delete_all_keys(backend *be,char* type,back_txn *txn);
+int indexfile_primary_modifyall(backend *be, LDAPMod **mods_to_perform,char **indexes_to_update,back_txn *txn);
+
+/*
+ * bedse.c
+ */
+#if 0
+int bedse_init();
+int bedse_search(Slapi_PBlock *pb);
+struct dse_callback *bedse_register_callback(int operation, const Slapi_DN *base, int scope, const char *filter, int (*fn)(Slapi_PBlock *,Slapi_Entry *,Slapi_Entry *,int*,char*,void *), void *fn_arg);
+void bedse_remove_callback(int operation, const Slapi_DN *base, int scope, const char *filter, int (*fn)(Slapi_PBlock *,Slapi_Entry *,Slapi_Entry *,int*,char*,void *));
+int bedse_add_index_entry(int argc, char **argv);
+#endif
+
+/*
+ * search.c
+ */
+Slapi_Filter* create_onelevel_filter(Slapi_Filter* filter, const struct backentry *e, int managedsait, Slapi_Filter** fid2kids, Slapi_Filter** focref, Slapi_Filter** fand, Slapi_Filter** forr);
+Slapi_Filter* create_subtree_filter(Slapi_Filter* filter, int managedsait, Slapi_Filter** focref, Slapi_Filter** forr);
+IDList* subtree_candidates(Slapi_PBlock *pb, backend *be, const char *base, const struct backentry *e, Slapi_Filter *filter, int managedsait, int *allids_before_scopingp, int *err);
+void search_set_tune(struct ldbminfo *li,int val);
+int search_get_tune(struct ldbminfo *li);
+
+/*
+ * matchrule.c
+ */
+int create_matchrule_indexer(Slapi_PBlock **pb,char* matchrule,char* type);
+int destroy_matchrule_indexer(Slapi_PBlock *pb);
+int matchrule_values_to_keys(Slapi_PBlock *pb,struct berval **input_values,struct berval ***output_values);
+int matchrule_values_to_keys_sv(Slapi_PBlock *pb,Slapi_Value **input_values, Slapi_Value ***output_values);
+
+/*
+ * upgrade.c
+ */
+int check_db_version(struct ldbminfo *li, int *action);
+int check_db_inst_version(ldbm_instance *inst);
+#if defined(UPGRADEDB)
+int adjust_idl_switch(char *ldbmversion, struct ldbminfo *li);
+#endif
+int ldbm_upgrade(ldbm_instance *inst, int action);
+int lookup_dbversion(char *dbversion, int flag);
+
+
+/*
+ * init.c
+ */
+int ldbm_attribute_always_indexed(const char *attrtype);
+
+/*
+ * dbversion.c
+ */
+int dbversion_write(struct ldbminfo *li, const char *dir, const char *dversion);
+int dbversion_read(struct ldbminfo *li, const char *directory,
+ char *ldbmversion, char *dataversion);
+int dbversion_exists(struct ldbminfo *li, const char *directory);
+
+/*
+ * config_ldbm.c
+ */
+int ldbm_config_load_dse_info(struct ldbminfo *li);
+void ldbm_config_setup_default(struct ldbminfo *li);
+void ldbm_config_internal_set(struct ldbminfo *li, char *attrname, char *value);
+void ldbm_instance_config_internal_set(ldbm_instance *inst, char *attrname, char *value);
+void ldbm_instance_config_setup_default(ldbm_instance *inst);
+int ldbm_instance_postadd_instance_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int ldbm_instance_add_instance_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int ldbm_instance_delete_instance_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int ldbm_instance_post_delete_instance_entry_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+/* Index config functions */
+int ldbm_index_init_entry_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int ldbm_instance_index_config_add_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int ldbm_instance_index_config_delete_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int ldbm_instance_index_config_modify_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
+/* Attribute Encryption config functions */
+int ldbm_attrcrypt_init_entry_callback(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int ldbm_instance_attrcrypt_config_add_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int ldbm_instance_attrcrypt_config_delete_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int ldbm_instance_attrcrypt_config_modify_callback(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
+
+void replace_ldbm_config_value(char *conftype, char *val, struct ldbminfo *li);
+
+/*
+ * ancestorid.c
+ */
+int ldbm_ancestorid_create_index(backend *be);
+int ldbm_ancestorid_index_entry(backend *be, struct backentry *e, int flags, back_txn *txn);
+int ldbm_ancestorid_read(backend *be, back_txn *txn, ID id, IDList **idl);
+int ldbm_ancestorid_move_subtree(
+ backend *be,
+ const Slapi_DN *olddn,
+ const Slapi_DN *newdn,
+ ID id,
+ IDList *subtree_idl,
+ back_txn *txn
+);
+
+#endif
+
+/*
+ * import-threads.c
+ */
+int dse_conf_backup(struct ldbminfo *li, char *destination_directory);
+int dse_conf_verify(struct ldbminfo *li, char *src_dir);
+
+/*
+ * ldbm_attrcrypt.c
+ */
+int attrcrypt_decrypt_entry(backend *be, struct backentry *e);
+int attrcrypt_encrypt_entry_inplace(backend *be, const struct backentry *inout);
+int attrcrypt_encrypt_entry(backend *be, const struct backentry *in, struct backentry **out);
+int attrcrypt_encrypt_index_key(backend *be, struct attrinfo *ai, const struct berval *in, struct berval **out);
+int attrcrypt_init(ldbm_instance *li);
diff --git a/ldap/servers/slapd/back-ldbm/rmdb.c b/ldap/servers/slapd/back-ldbm/rmdb.c
new file mode 100644
index 00000000..d4b760bd
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/rmdb.c
@@ -0,0 +1,54 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * rmdb.c - ldbm backend routine which deletes an entire database.
+ * This routine is not exposed in the public SLAPI interface. It
+ * is called by the replication subsystem when then changelog must
+ * be erased.
+ */
+
+#include "back-ldbm.h"
+
+int
+ldbm_back_rmdb( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li = NULL;
+ /* char *directory = NULL;*/
+ int return_value = -1;
+ Slapi_Backend *be;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+
+ if (be->be_state != BE_STATE_STOPPED)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldbm_back_cleanup: warning - backend is in a wrong state - %d\n",
+ be->be_state, 0, 0 );
+ return 0;
+ }
+
+ PR_Lock (be->be_state_lock);
+
+ if (be->be_state != BE_STATE_STOPPED)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "ldbm_back_cleanup: warning - backend is in a wrong state - %d\n",
+ be->be_state, 0, 0 );
+ PR_Unlock (be->be_state_lock);
+ return 0;
+ }
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+/* slapi_pblock_get( pb, SLAPI_SEQ_VAL, &directory );*/
+ return_value = dblayer_delete_database( li );
+
+ if (return_value == 0)
+ be->be_state = BE_STATE_DELETED;
+
+ PR_Unlock (be->be_state_lock);
+
+ return return_value;
+}
diff --git a/ldap/servers/slapd/back-ldbm/seq.c b/ldap/servers/slapd/back-ldbm/seq.c
new file mode 100644
index 00000000..6a61fd2e
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/seq.c
@@ -0,0 +1,262 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* seq.c - ldbm backend sequential access function */
+
+#include "back-ldbm.h"
+
+#define SEQ_LITTLE_BUFFER_SIZE 100
+
+/*
+ * Access the database sequentially.
+ * There are 4 ways to call this routine. In each case, the equality index
+ * for "attrname" is consulted:
+ * 1) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_FIRST, then this routine
+ * will find the smallest key greater than or equal to the SLAPI_SEQ_VAL
+ * parameter, and return all entries that key's IDList. If SLAPI_SEQ_VAL
+ * is NULL, then the smallest key is retrieved and the associaated
+ * entries are returned.
+ * 2) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_NEXT, then this routine
+ * will find the smallest key strictly greater than the SLAPI_SEQ_VAL
+ * parameter, and return all entries that key's IDList.
+ * 3) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_PREV, then this routine
+ * will find the greatest key strictly less than the SLAPI_SEQ_VAL
+ * parameter, and return all entries that key's IDList.
+ * 4) If the SLAPI_SEQ_TYPE parameter is SLAPI_SEQ_LAST, then this routine
+ * will find the largest equality key in the index and return all entries
+ * which match that key. The SLAPI_SEQ_VAL parameter is ignored.
+ */
+int
+ldbm_back_seq( Slapi_PBlock *pb )
+{
+ backend *be;
+ ldbm_instance *inst;
+ struct ldbminfo *li;
+ IDList *idl = NULL;
+ int err = LDAP_SUCCESS;
+ DB *db;
+ DBC *dbc = NULL;
+ int type;
+ char *attrname, *val;
+ int isroot;
+ struct attrinfo *ai = NULL;
+ int return_value = -1;
+ int nentries = 0;
+ int retry_count=0;
+
+ /* Decode arguments */
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be);
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+ slapi_pblock_get( pb, SLAPI_SEQ_TYPE, &type );
+ slapi_pblock_get( pb, SLAPI_SEQ_ATTRNAME, &attrname );
+ slapi_pblock_get( pb, SLAPI_SEQ_VAL, &val );
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+
+ inst = (ldbm_instance *) be->be_instance_info;
+
+ /* Validate arguments */
+ if ( type != SLAPI_SEQ_FIRST &&
+ type != SLAPI_SEQ_LAST &&
+ type != SLAPI_SEQ_NEXT &&
+ type != SLAPI_SEQ_PREV )
+ {
+ slapi_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "Bad seq access type", 0, NULL );
+ return( -1 );
+ }
+
+ /* get a database */
+
+ ainfo_get( be, attrname, &ai );
+ LDAPDebug( LDAP_DEBUG_ARGS,
+ " seq: indextype: %s indexmask: 0x%x seek type: %d\n",
+ ai->ai_type, ai->ai_indexmask, type );
+ if ( ! (INDEX_EQUALITY & ai->ai_indexmask) ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "seq: caller specified un-indexed attribute %s\n",
+ attrname ? attrname : "", 0, 0 );
+ slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Unindexed seq access type", 0, NULL );
+ return -1;
+ }
+
+ if ( (return_value = dblayer_get_index_file( be, ai, &db, DBOPEN_CREATE )) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "<= ldbm_back_seq NULL (could not open index file for attribute %s)\n",
+ attrname, 0, 0 );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return -1;
+ }
+
+ /* First, get a database cursor */
+
+ return_value = db->cursor(db,NULL,&dbc,0);
+
+ if (0 == return_value)
+ {
+ DBT data = {0};
+ DBT key = {0};
+ char little_buffer[SEQ_LITTLE_BUFFER_SIZE];
+ char *big_buffer = NULL;
+ char keystring = EQ_PREFIX;
+
+ /* Set data */
+ data.flags = DB_DBT_MALLOC;
+
+ /* Set up key */
+ key.flags = DB_DBT_MALLOC;
+ if (NULL == val)
+ {
+ /* this means, goto the first equality key */
+ /* seek to key >= "=" */
+ key.data = &keystring;
+ key.size = 1;
+ }
+ else
+ {
+ size_t key_length = strlen(val) + 2;
+ if (key_length <= SEQ_LITTLE_BUFFER_SIZE) {
+ key.data = &little_buffer;
+ } else {
+ big_buffer = slapi_ch_malloc(key_length);
+ if (NULL == big_buffer) {
+ /* memory allocation failure */
+ dblayer_release_index_file( be, ai, db );
+ return -1;
+ }
+ key.data = big_buffer;
+ }
+ key.size = sprintf(key.data,"%c%s",EQ_PREFIX,val);
+ }
+
+ /* decide which type of operation we're being asked to do and do the db bit */
+ /* The c_get call always mallocs memory for data.data */
+ /* The c_get call mallocs memory for key.data, except for DB_SET */
+ /* after this, we leave data containing the retrieved IDL, or NULL if we didn't get it */
+
+ switch (type) {
+ case SLAPI_SEQ_FIRST:
+ /* if (NULL == val) goto the first equality key ( seek to key >= "=" ) */
+ /* else goto the first equality key >= val ( seek to key >= "=val" )*/
+ return_value = dbc->c_get(dbc,&key,&data,DB_SET_RANGE);
+ break;
+ case SLAPI_SEQ_NEXT:
+ /* seek to the indicated =value, then seek to the next entry, */
+ return_value = dbc->c_get(dbc,&key,&data,DB_SET);
+ if (0 == return_value)
+ {
+ free(data.data);
+ return_value = dbc->c_get(dbc,&key,&data,DB_NEXT);
+ }
+ else
+ {
+ /* DB_SET doesn't allocate key data. Make sure we don't try to free it... */
+ key.data= NULL;
+ }
+ break;
+ case SLAPI_SEQ_PREV:
+ /* seek to the indicated =value, then seek to the previous entry, */
+ return_value = dbc->c_get(dbc,&key,&data,DB_SET);
+ if (0 == return_value )
+ {
+ free(data.data);
+ return_value = dbc->c_get(dbc,&key,&data,DB_PREV);
+ }
+ else
+ {
+ /* DB_SET doesn't allocate key data. Make sure we don't try to free it... */
+ key.data= NULL;
+ }
+ break;
+ case SLAPI_SEQ_LAST:
+ /* seek to the first possible key after all the equality keys (">"), then seek back one */
+ {
+ keystring = EQ_PREFIX + 1;
+ key.data = &keystring;
+ key.size = 1;
+ return_value = dbc->c_get(dbc,&key,&data,DB_SET_RANGE);
+ if (0 == return_value || DB_NOTFOUND == return_value)
+ {
+ free(data.data);
+ return_value = dbc->c_get(dbc,&key,&data,DB_PREV);
+ }
+ }
+ break;
+ default:
+ PR_ASSERT(0);
+ }
+
+ dbc->c_close(dbc);
+
+ if (0 == return_value && key.data!=NULL)
+ {
+
+ /* Now check that the key we eventually settled on was an equality key ! */
+ if (*((char*)key.data) == EQ_PREFIX)
+ {
+ /* Retrieve the idlist for this key */
+ key.flags = 0;
+ for (retry_count = 0; retry_count < IDL_FETCH_RETRY_COUNT; retry_count++) {
+ err = NEW_IDL_DEFAULT;
+ idl = idl_fetch( be, db, &key, NULL, ai, &err );
+ if(err == DB_LOCK_DEADLOCK) {
+ ldbm_nasty("ldbm_back_seq deadlock retry", 1600, err);
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ if(retry_count == IDL_FETCH_RETRY_COUNT) {
+ ldbm_nasty("ldbm_back_seq retry count exceeded",1645,err);
+ } else if ( err != 0 && err != DB_NOTFOUND ) {
+ ldbm_nasty("ldbm_back_seq database error", 1650, err);
+ }
+ free( data.data );
+ if ( key.data != little_buffer && key.data != &keystring ) {
+ free( key.data );
+ }
+ free( big_buffer );
+ }
+
+ /* null idlist means there were no matching keys */
+ if ( idl != NULL )
+ {
+ /*
+ * Step through the IDlist. For each ID, get the entry
+ * and send it.
+ */
+ ID id;
+ struct backentry *e;
+ for ( id = idl_firstid( idl ); id != NOID;
+ id = idl_nextid( idl, id ))
+ {
+ if (( e = id2entry( be, id, NULL, &err )) == NULL )
+ {
+ if ( err != LDAP_SUCCESS )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "seq id2entry err %d\n", err, 0, 0 );
+ }
+ LDAPDebug( LDAP_DEBUG_ARGS,
+ "ldbm_back_seq: candidate %lu not found\n",
+ (u_long)id, 0, 0 );
+ continue;
+ }
+ if ( slapi_send_ldap_search_entry( pb, e->ep_entry, NULL, NULL, 0 ) == 0 )
+ {
+ nentries++;
+ }
+ cache_return( &inst->inst_cache, &e );
+ }
+ idl_free( idl );
+ }
+
+ dblayer_release_index_file( be, ai, db );
+
+ slapi_send_ldap_result( pb, LDAP_SUCCESS == err ? LDAP_SUCCESS : LDAP_OPERATIONS_ERROR, NULL, NULL, nentries, NULL );
+
+ return 0;
+}
diff --git a/ldap/servers/slapd/back-ldbm/sort.c b/ldap/servers/slapd/back-ldbm/sort.c
new file mode 100644
index 00000000..4a25e068
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/sort.c
@@ -0,0 +1,1031 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Code to implement result sorting */
+
+#include "back-ldbm.h"
+
+#define CHECK_INTERVAL 10 /* The frequency whith which we'll check the admin limits */
+
+/* Structure to carry the things we need down the call stack */
+struct baggage_carrier {
+ backend *be; /* For id2entry */
+ Slapi_PBlock *pb; /* For slapi_op_abandoned */
+ time_t stoptime; /* For timelimit policing */
+ int lookthrough_limit;
+ int check_counter; /* Used to avoid checking every 100ns */
+};
+typedef struct baggage_carrier baggage_carrier;
+
+static int slapd_qsort (baggage_carrier *bc,IDList *list,sort_spec *s);
+static int print_out_sort_spec(char* buffer,sort_spec *s,int *size);
+
+static void sort_spec_thing_free(sort_spec_thing *s)
+{
+ if (NULL != s->type) {
+ slapi_ch_free((void **)&s->type);
+ }
+ if (NULL != s->matchrule) {
+ slapi_ch_free( (void**)&s->matchrule);
+ }
+ if (NULL != s->mr_pb) {
+ destroy_matchrule_indexer(s->mr_pb);
+ slapi_pblock_destroy (s->mr_pb);
+ }
+ slapi_ch_free( (void**)&s);
+}
+
+static sort_spec_thing *sort_spec_thing_allocate()
+{
+ return (sort_spec_thing *) slapi_ch_calloc(1,sizeof (sort_spec_thing));
+}
+
+void sort_spec_free(sort_spec *s)
+{
+ /* Walk down the list freeing */
+ sort_spec_thing *t = (sort_spec_thing*)s;
+ sort_spec_thing *p = NULL;
+ do {
+ p = t->next;
+ sort_spec_thing_free(t);
+ t = p;
+ } while (p);
+}
+
+static sort_spec_thing * sort_spec_thing_new(char *type, char* matchrule, int reverse)
+{
+ sort_spec_thing *s = sort_spec_thing_allocate();
+ if (NULL == s) {
+ return s;
+ }
+ s->type = type;
+ s->matchrule = matchrule;
+ s->order = reverse;
+ return s;
+}
+
+void sort_log_access(Slapi_PBlock *pb,sort_spec_thing *s,IDList *candidates)
+{
+#define SORT_LOG_BSZ 64
+#define SORT_LOG_PAD 22 /* space for the number of candidates */
+ char stack_buffer[SORT_LOG_BSZ + SORT_LOG_PAD];
+ char *buffer = NULL;
+ int ret = 0;
+ int size = SORT_LOG_BSZ + SORT_LOG_PAD;
+ char *prefix = "SORT ";
+ int prefix_size = strlen(prefix);
+
+ buffer = stack_buffer;
+ size -= sprintf(buffer,"%s",prefix);
+ ret = print_out_sort_spec(buffer+prefix_size,s,&size);
+ if (0 != ret) {
+ /* It wouldn't fit in the buffer */
+ buffer = slapi_ch_malloc(prefix_size + size + SORT_LOG_PAD);
+ sprintf(buffer,"%s",prefix);
+ ret = print_out_sort_spec(buffer+prefix_size,s,&size);
+ }
+ if (candidates) {
+ if (ALLIDS(candidates)) {
+ sprintf(buffer+size+prefix_size,"(*)");
+ } else {
+ sprintf(buffer+size+prefix_size,"(%lu)",(u_long)candidates->b_nids);
+ }
+ }
+ /* Now output it */
+ ldbm_log_access_message(pb,buffer);
+ if (buffer != stack_buffer) {
+ slapi_ch_free( (void**)&buffer);
+ }
+}
+
+/* Fix for bug # 394184, SD, 20 Jul 00 */
+/* replace the hard coded return value by the appropriate LDAP error code */
+/* also removed an useless if (0 == return_value) {} statement */
+/* Given a candidate list and a list of sort order specifications, sort this, or cop out */
+/* Returns: 0 -- sorted OK now is: LDAP_SUCCESS (fix for bug #394184)
+ * -1 -- protocol error now is: LDAP_PROTOCOL_ERROR
+ * -2 -- too hard to sort these now is: LDAP_UNWILLING_TO_PERFORM
+ * -3 -- operation error now is: LDAP_OPERATIONS_ERROR
+ * -4 -- timeout now is: LDAP_TIMELIMIT_EXCEEDED
+ * -5 -- admin limit exceeded now is: LDAP_ADMINLIMIT_EXCEEDED
+ * -6 -- abandoned now is: LDAP_OTHER
+ */
+/*
+ * So here's the plan:
+ * Plan A: We do a regular quicksort on the entries.
+ * Plan B: Through some hint given us from on high, we
+ * determine that the entries are _already_
+ * sorted as requested, thus we do nothing !
+ * Plan C: We determine that sorting these suckers is
+ * far too hard for us to even try, so we refuse.
+ */
+int sort_candidates(backend *be,int lookthrough_limit,time_t time_up, Slapi_PBlock *pb,
+ IDList *candidates, sort_spec_thing *s, char **sort_error_type)
+{
+ int return_value = LDAP_SUCCESS;
+ baggage_carrier bc = {0};
+ sort_spec_thing *this_s = NULL;
+
+ /* We refuse to sort a non-existent IDlist */
+ if (NULL == candidates) {
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ /* we refuse to sort a candidate list which is vast */
+ if (ALLIDS(candidates)) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "Asked to sort ALLIDS candidate list, refusing\n",0, 0, 0 );
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ /* Iterate over the sort types */
+ for (this_s = s; this_s; this_s=this_s->next) {
+ if (NULL == this_s->matchrule) {
+ void *pi;
+ int return_value = 0;
+ return_value = slapi_attr_type2plugin( this_s->type, &pi );
+ if (0 == return_value) {
+ return_value = plugin_call_syntax_get_compare_fn( pi, &(this_s->compare_fn) );
+ }
+ if (return_value != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "Attempting to sort a non-ordered attribute (%s)\n",this_s->type, 0, 0 );
+ /* DBDB we should set the error type here */
+ return_value = LDAP_UNWILLING_TO_PERFORM;
+ *sort_error_type = this_s->type;
+ return return_value;
+ }
+ } else {
+ /* Need to---find the matching rule plugin,
+ * tell it it needs to do ordering for this OID
+ * see whether it agrees---if not signal error to client
+ * Then later use it for generating ordering keys.
+ * finally, free it up
+ */
+ return_value = create_matchrule_indexer(&this_s->mr_pb,this_s->matchrule,this_s->type);
+ if (LDAP_SUCCESS != return_value) {
+ *sort_error_type = this_s->type;
+ return return_value;
+ }
+ this_s->compare_fn = slapi_berval_cmp;
+ }
+ }
+
+ bc.be = be;
+ bc.pb = pb;
+ bc.stoptime = time_up;
+ bc.lookthrough_limit = lookthrough_limit;
+ bc.check_counter = 1;
+
+ return_value = slapd_qsort(&bc,candidates,s);
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= Sorting done\n",0, 0, 0 );
+
+ return return_value;
+}
+/* End fix for bug # 394184 */
+
+/* Fix for bug # 394184, SD, 20 Jul 00 */
+/* fix and cleanup (switch(code) {} removed) */
+/* arg 'code' has now the correct sortResult value */
+int
+make_sort_response_control ( Slapi_PBlock *pb, int code, char *error_type) {
+
+ LDAPControl new_ctrl = {0};
+ BerElement *ber= NULL;
+ struct berval *bvp = NULL;
+ int rc = -1;
+ int control_code = code;
+
+ /*
+ SortResult ::= SEQUENCE {
+ sortResult ENUMERATED {
+ success (0), -- results are sorted
+ operationsError (1), -- server internal failure
+ timeLimitExceeded (3), -- timelimit reached before
+ -- sorting was completed
+ strongAuthRequired (8), -- refused to return sorted
+ -- results via insecure
+ -- protocol
+ adminLimitExceeded (11), -- too many matching entries
+ -- for the server to sort
+ noSuchAttribute (16), -- unrecognized attribute
+ -- type in sort key
+ inappropriateMatching (18), -- unrecognized or inappro-
+ -- priate matching rule in
+ -- sort key
+ insufficientAccessRights (50), -- refused to return sorted
+ -- results to this client
+ busy (51), -- too busy to process
+ unwillingToPerform (53), -- unable to sort
+ other (80)
+ },
+ attributeType [0] AttributeType OPTIONAL }
+
+ */
+
+ if ( ( ber = ber_alloc()) == NULL ) {
+ return -1;
+ }
+
+ if (( rc = ber_printf( ber, "{e", control_code )) != -1 ) {
+ if ( rc != -1 && NULL != error_type ) {
+ rc = ber_printf( ber, "s", error_type );
+ }
+ if ( rc != -1 ) {
+ rc = ber_printf( ber, "}" );
+ }
+ }
+ if ( rc != -1 ) {
+ rc = ber_flatten( ber, &bvp );
+ }
+
+ ber_free( ber, 1 );
+
+ if ( rc == -1 ) {
+ return rc;
+ }
+
+ new_ctrl.ldctl_oid = LDAP_CONTROL_SORTRESPONSE;
+ new_ctrl.ldctl_value = *bvp;
+ new_ctrl.ldctl_iscritical = 1;
+
+ if ( slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, &new_ctrl ) != 0 ) {
+ ber_bvfree(bvp);
+ return( -1 );
+ }
+
+ ber_bvfree(bvp);
+ return( LDAP_SUCCESS );
+}
+/* End fix for bug #394184 */
+
+static int term_tag(unsigned long tag)
+{
+ return ( (LBER_END_OF_SEQORSET == tag) || (LBER_ERROR == tag) );
+}
+
+/* hacky function to convert a sort spec to a string
+ you specify a buffer and a size. If the thing won't fit, it returns
+ non-zero, and the size needed. Pass NULL buffer to just get the size */
+static int print_out_sort_spec(char* buffer,sort_spec *s,int *size)
+{
+ /* Walk down the list printing */
+ sort_spec_thing *t = (sort_spec_thing*)s;
+ sort_spec_thing *p = NULL;
+ int buffer_size = 0;
+ int input_size = 0;
+
+ if (NULL != size) {
+ input_size = *size;
+ }
+ do {
+ p = t->next;
+
+ buffer_size += strlen(t->type);
+ if (t->order) {
+ buffer_size += 1; /* For the '-' */
+ }
+ if (NULL != t->matchrule) {
+ /* space for matchrule + semicolon */
+ buffer_size += strlen(t->matchrule) + 1;
+ }
+ buffer_size += 1; /* for the space */
+ if ( (NULL != buffer) && (buffer_size <= input_size) ) {
+ /* write into the buffer */
+ buffer += sprintf(buffer,"%s%s%s%s ",
+ t->order ? "-" : "",
+ t->type,
+ ( NULL == t->matchrule ) ? "" : ";",
+ ( NULL == t->matchrule ) ? "" : t->matchrule);
+ }
+
+ t = p;
+ } while (p);
+ if (NULL != size) {
+ *size = buffer_size;
+ }
+ if (buffer_size <= input_size) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+int parse_sort_spec(struct berval *sort_spec_ber, sort_spec **ps)
+{
+ /* So here we call ber_scanf to get the sort spec */
+ /* This control looks like this :
+ SortKeyList ::= SEQUENCE OF SEQUENCE {
+ attributeType AttributeType,
+ orderingRule [0] MatchingRuleId OPTIONAL,
+ reverseOrder [1] BOOLEAN DEFAULT FALSE }
+ */
+ BerElement *ber = NULL;
+ sort_spec_thing *listhead = NULL;
+ unsigned long tag = 0;
+ unsigned long len = 0;
+ char *last = NULL;
+ sort_spec_thing *listpointer = NULL;
+ char *type = NULL;
+ char *matchrule = NULL;
+ int rc = LDAP_SUCCESS;
+
+ ber = ber_init(sort_spec_ber);
+ if(ber==NULL)
+ {
+ return -1;
+ }
+
+ /* Work our way along the BER, one sort spec at a time */
+ for ( tag = ber_first_element( ber, &len, &last ); !term_tag(tag); tag = ber_next_element( ber, &len, last )) {
+ /* we're now pointing at the beginning of a sequence of type, matching rule and reverse indicator */
+
+ char *inner_last = NULL;
+ char *rtype = NULL;
+ int reverse = 0;
+ unsigned long next_tag = 0;
+ sort_spec_thing *s = NULL;
+ unsigned long return_value;
+
+ next_tag = ber_first_element( ber, &len, &inner_last );
+
+ /* The type is not optional */
+
+ return_value = ber_scanf(ber,"a",&rtype);
+ if (LBER_ERROR == return_value) {
+ rc = LDAP_PROTOCOL_ERROR;
+ goto err;
+ }
+ /* normalize */
+ type = slapi_attr_syntax_normalize(rtype);
+ free(rtype);
+
+ /* Now look for the next tag. */
+
+ next_tag = ber_next_element(ber,&len, inner_last);
+
+ /* Are we done ? */
+ if ( !term_tag(next_tag) ) {
+ /* Is it the matching rule ? */
+ if (LDAP_TAG_SK_MATCHRULE == next_tag) {
+ /* If so, get it */
+ ber_scanf(ber,"a",&matchrule);
+ /* That can be followed by a reverse indicator */
+ next_tag = ber_next_element(ber,&len, inner_last);
+ if (LDAP_TAG_SK_REVERSE == next_tag) {
+ /* Get the reverse sort indicator here */
+ ber_scanf(ber,"b",&reverse);
+ /* The protocol police say--"You must have other than your default value" */
+ if (0 == reverse) {
+ /* Protocol error */
+ rc = LDAP_PROTOCOL_ERROR;
+ goto err;
+ }
+ } else {
+ /* Perhaps we're done now ? */
+ if (LBER_END_OF_SEQORSET != next_tag) {
+ /* Protocol error---we got a matching rule, but followed by something other
+ * than reverse or end of sequence.
+ */
+ rc = LDAP_PROTOCOL_ERROR;
+ goto err;
+ }
+ }
+ } else {
+ /* Is it the reverse indicator ? */
+ if (LDAP_TAG_SK_REVERSE == next_tag) {
+ /* If so, get it */
+ ber_scanf(ber,"b",&reverse);
+ } else {
+ /* Protocol error---tag which isn't either of the legal ones came first */
+ rc = LDAP_PROTOCOL_ERROR;
+ goto err;
+ }
+ }
+ }
+
+ s = sort_spec_thing_new(type,matchrule,reverse);
+ if (NULL == s) {
+ /* Memory allocation failed */
+ rc = LDAP_OPERATIONS_ERROR;
+ goto err;
+ }
+ type = matchrule = NULL;
+ if (NULL != listpointer) {
+ listpointer->next = s;
+ }
+ listpointer = s;
+ if (NULL == listhead) {
+ listhead = s;
+ }
+
+ }
+
+ if (NULL == listhead) { /* LP - defect #559792 - don't return null listhead */
+ *ps = NULL;
+ rc = LDAP_PROTOCOL_ERROR;
+ goto err;
+ }
+
+ /* the ber encoding is no longer needed */
+ ber_free(ber,1);
+
+ *ps = (sort_spec *)listhead;
+
+
+ return LDAP_SUCCESS;
+
+ err:
+ if (listhead) sort_spec_free((sort_spec*) listhead);
+ slapi_ch_free((void**)&type);
+ slapi_ch_free((void**)&matchrule);
+ ber_free(ber,1);
+
+ return rc;
+}
+
+#if 0
+static int attr_value_compare(struct berval *value_a, struct berval *value_b)
+{
+ /* return value_cmp(value_a,value_b,syntax,3); */
+ return strcasecmp(value_a->bv_val, value_b->bv_val);
+}
+#endif
+
+struct berval* attr_value_lowest(struct berval **values, value_compare_fn_type compare_fn)
+{
+ /* We iterate through the values, storing our last best guess as to the lowest */
+ struct berval *lowest_so_far = values[0];
+ struct berval *this_one = NULL;
+
+ for (this_one = *values; this_one; this_one = *values++) {
+ if (compare_fn(lowest_so_far,this_one) > 0) {
+ lowest_so_far = this_one;
+ }
+ }
+ return lowest_so_far;
+}
+
+int sort_attr_compare(struct berval ** value_a, struct berval ** value_b, value_compare_fn_type compare_fn)
+{
+ /* So, the thing we need to do here is to look out for multi-valued
+ * attributes. When we get one of those, we need to look through all the
+ * values to find the lowest one (per X.511 edict). We then use that one to
+ * compare against the other. We should really put some logic in here to
+ * prevent us partying on an attribute with thousands of values for a long time.
+ */
+ struct berval *compare_value_a = NULL;
+ struct berval *compare_value_b = NULL;
+
+ compare_value_a = attr_value_lowest(value_a, compare_fn);
+ compare_value_b = attr_value_lowest(value_b, compare_fn);
+
+ return compare_fn(compare_value_a,compare_value_b);
+
+}
+
+
+#if 0
+/* USE THE _SV VERSION NOW */
+
+/* Comparison routine, called by qsort.
+ * The job here is to return the correct value
+ * for the operation a < b
+ * Returns:
+ * <0 when a < b
+ * 0 when a == b
+ * >0 when a > b
+ */
+static int compare_entries(ID *id_a, ID *id_b, sort_spec *s,baggage_carrier *bc, int *error)
+{
+ /* We get passed the IDs, but need to fetch the entries in order to
+ * perform the comparison .
+ */
+ struct backentry *a = NULL;
+ struct backentry *b = NULL;
+ int result = 0;
+ sort_spec_thing *this_one = NULL;
+ int return_value = -1;
+ backend *be = bc->be;
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ int err;
+
+ *error = 1;
+ a = id2entry(be,*id_a,NULL,&err);
+ if (NULL == a) {
+ if (0 != err ) {
+ LDAPDebug(LDAP_DEBUG_ANY,"compare_entries db err %d\n",err,0,0);
+ }
+ /* Were up a creek without paddle here */
+ /* Best to log error and set some flag */
+ return 0;
+ }
+ b = id2entry(be,*id_b,NULL,&err);
+ if (NULL == b) {
+ if (0 != err ) {
+ LDAPDebug(LDAP_DEBUG_ANY,"compare_entries db err %d\n",err,0,0);
+ }
+ return 0;
+ }
+ /* OK, now we have the entries, so we work our way down the attribute list comparing as we go */
+ for (this_one = (sort_spec_thing*)s; this_one ; this_one = this_one->next) {
+
+ char *type = this_one->type;
+ int order = this_one->order;
+ Slapi_Attr *attr_a = NULL;
+ Slapi_Attr *attr_b = NULL;
+ struct berval **value_a = NULL;
+ struct berval **value_b = NULL;
+
+ /* Get the two attribute values from the entries */
+ return_value = slapi_entry_attr_find(a->ep_entry,type,&attr_a);
+ return_value = slapi_entry_attr_find(b->ep_entry,type,&attr_b);
+ /* What do we do if one or more of the entries lacks this attribute ? */
+ /* if one lacks the attribute */
+ if (NULL == attr_a) {
+ /* then if the other does too, they're equal */
+ if (NULL == attr_b) {
+ result = 0;
+ continue;
+ } else
+ {
+ /* If one has the attribute, and the other
+ * doesn't, the missing attribute is the
+ * LARGER one. (bug #108154) -robey
+ */
+ result = 1;
+ break;
+ }
+ }
+ if (NULL == attr_b) {
+ result = -1;
+ break;
+ }
+ /* Somewhere in here, we need to go sideways for match rule case
+ * we need to call the match rule plugin to get the attribute values
+ * converted into ordering keys. Then we proceed as usual to use those,
+ * but ensuring that we don't leak memory anywhere. This works as follows:
+ * the code assumes that the attrs are references into the entry, so
+ * doesn't try to free them. We need to note at the right place that
+ * we're on the matchrule path, and accordingly free the keys---this turns out
+ * to be when we free the indexer */
+ if (NULL == s->matchrule) {
+ /* Non-match rule case */
+ /* xxxPINAKI
+ needs modification
+
+ value_a = attr_a->a_vals;
+ value_b = attr_b->a_vals;
+ */
+ } else {
+ /* Match rule case */
+ struct berval **actual_value_b = NULL;
+ struct berval **temp_value = NULL;
+
+ /* xxxPINAKI
+ needs modification
+ struct berval **actual_value_a = NULL;
+
+ actual_value_a = attr_a->a_vals;
+ actual_value_b = attr_b->a_vals;
+ matchrule_values_to_keys(s->mr_pb,actual_value_a,&temp_value);
+ */
+ /* Now copy it, so the second call doesn't crap on it */
+ value_a = slapi_ch_bvecdup(temp_value); /* Really, we'd prefer to not call the chXXX variant...*/
+ matchrule_values_to_keys(s->mr_pb,actual_value_b,&value_b);
+ }
+ /* Compare them */
+ if (!order) {
+ result = sort_attr_compare(value_a, value_b, s->compare_fn);
+ } else {
+ /* If reverse, invert the sense of the comparison */
+ result = sort_attr_compare(value_b, value_a, s->compare_fn);
+ }
+ /* Time to free up the attribute allocated above */
+ if (NULL != s->matchrule) {
+ ber_bvecfree(value_a);
+ }
+ /* Are they equal ? */
+ if (0 != result) {
+ /* If not, we're done */
+ break;
+ }
+ /* If so, proceed to the next attribute for comparison */
+ }
+ cache_return(&inst->inst_cache,&a);
+ cache_return(&inst->inst_cache,&b);
+ *error = 0;
+ return result;
+}
+#endif
+
+/* Comparison routine, called by qsort.
+ * The job here is to return the correct value
+ * for the operation a < b
+ * Returns:
+ * <0 when a < b
+ * 0 when a == b
+ * >0 when a > b
+ */
+static int compare_entries_sv(ID *id_a, ID *id_b, sort_spec *s,baggage_carrier *bc, int *error)
+{
+ /* We get passed the IDs, but need to fetch the entries in order to
+ * perform the comparison .
+ */
+ struct backentry *a = NULL;
+ struct backentry *b = NULL;
+ int result = 0;
+ sort_spec_thing *this_one = NULL;
+ int return_value = -1;
+ backend *be = bc->be;
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+ int err;
+
+ *error = 1;
+ a = id2entry(be,*id_a,NULL,&err);
+ if (NULL == a) {
+ if (0 != err ) {
+ LDAPDebug(LDAP_DEBUG_ANY,"compare_entries db err %d\n",err,0,0);
+ }
+ /* Were up a creek without paddle here */
+ /* Best to log error and set some flag */
+ return 0;
+ }
+ b = id2entry(be,*id_b,NULL,&err);
+ if (NULL == b) {
+ if (0 != err ) {
+ LDAPDebug(LDAP_DEBUG_ANY,"compare_entries db err %d\n",err,0,0);
+ }
+ return 0;
+ }
+ /* OK, now we have the entries, so we work our way down the attribute list comparing as we go */
+ for (this_one = (sort_spec_thing*)s; this_one ; this_one = this_one->next) {
+
+ char *type = this_one->type;
+ int order = this_one->order;
+ Slapi_Attr *attr_a = NULL;
+ Slapi_Attr *attr_b = NULL;
+ struct berval **value_a = NULL;
+ struct berval **value_b = NULL;
+
+ /* Get the two attribute values from the entries */
+ return_value = slapi_entry_attr_find(a->ep_entry,type,&attr_a);
+ return_value = slapi_entry_attr_find(b->ep_entry,type,&attr_b);
+ /* What do we do if one or more of the entries lacks this attribute ? */
+ /* if one lacks the attribute */
+ if (NULL == attr_a) {
+ /* then if the other does too, they're equal */
+ if (NULL == attr_b) {
+ result = 0;
+ continue;
+ } else
+ {
+ /* If one has the attribute, and the other
+ * doesn't, the missing attribute is the
+ * LARGER one. (bug #108154) -robey
+ */
+ result = 1;
+ break;
+ }
+ }
+ if (NULL == attr_b) {
+ result = -1;
+ break;
+ }
+ /* Somewhere in here, we need to go sideways for match rule case
+ * we need to call the match rule plugin to get the attribute values
+ * converted into ordering keys. Then we proceed as usual to use those,
+ * but ensuring that we don't leak memory anywhere. This works as follows:
+ * the code assumes that the attrs are references into the entry, so
+ * doesn't try to free them. We need to note at the right place that
+ * we're on the matchrule path, and accordingly free the keys---this turns out
+ * to be when we free the indexer */
+ if (NULL == s->matchrule) {
+ /* Non-match rule case */
+ valuearray_get_bervalarray(valueset_get_valuearray(&attr_a->a_present_values),&value_a);
+ valuearray_get_bervalarray(valueset_get_valuearray(&attr_b->a_present_values),&value_b);
+ } else {
+ /* Match rule case */
+ struct berval **actual_value_a = NULL;
+ struct berval **actual_value_b = NULL;
+ struct berval **temp_value = NULL;
+
+ valuearray_get_bervalarray(valueset_get_valuearray(&attr_a->a_present_values),&actual_value_a);
+ valuearray_get_bervalarray(valueset_get_valuearray(&attr_b->a_present_values),&actual_value_b);
+ matchrule_values_to_keys(s->mr_pb,actual_value_a,&temp_value);
+ /* Now copy it, so the second call doesn't crap on it */
+ value_a = slapi_ch_bvecdup(temp_value); /* Really, we'd prefer to not call the chXXX variant...*/
+ matchrule_values_to_keys(s->mr_pb,actual_value_b,&value_b);
+ if (actual_value_a) ber_bvecfree(actual_value_a);
+ if (actual_value_b) ber_bvecfree(actual_value_b);
+ }
+ /* Compare them */
+ if (!order) {
+ result = sort_attr_compare(value_a, value_b, s->compare_fn);
+ } else {
+ /* If reverse, invert the sense of the comparison */
+ result = sort_attr_compare(value_b, value_a, s->compare_fn);
+ }
+ /* Time to free up the attributes allocated above */
+ if (NULL != s->matchrule) {
+ ber_bvecfree(value_a);
+ } else {
+ ber_bvecfree(value_a);
+ ber_bvecfree(value_b);
+ }
+ /* Are they equal ? */
+ if (0 != result) {
+ /* If not, we're done */
+ break;
+ }
+ /* If so, proceed to the next attribute for comparison */
+ }
+ cache_return(&inst->inst_cache,&a);
+ cache_return(&inst->inst_cache,&b);
+ *error = 0;
+ return result;
+}
+
+/* Fix for bug # 394184, SD, 20 Jul 00 */
+/* replace the hard coded return value by the appropriate LDAP error code */
+/*
+ * Returns:
+ * 0: Everything OK now is: LDAP_SUCCESS (fix for bug #394184)
+ * -1: A protocol error now is: LDAP_PROTOCOL_ERROR
+ * -2: Too hard now is: LDAP_UNWILLING_TO_PERFORM
+ * -3: Operation error now is: LDAP_OPERATIONS_ERROR
+ * -4: Timeout now is: LDAP_TIMELIMIT_EXCEEDED
+ * -5: Admin limit exceeded now is: LDAP_ADMINLIMIT_EXCEEDED
+ * -6: Abandoned now is: LDAP_OTHER
+ */
+static int sort_nazi(baggage_carrier *bc)
+{
+ time_t curtime = 0;
+ /* check for abandon */
+ if ( slapi_op_abandoned( bc->pb)) {
+ return LDAP_OTHER;
+ }
+
+ /* Check to see if our journey is really necessary */
+
+ if (0 == ((bc->check_counter)++ % CHECK_INTERVAL) ) {
+
+ /* check time limit */
+ curtime = current_time();
+ if ( bc->stoptime != -1 && curtime > bc->stoptime ) {
+ return LDAP_TIMELIMIT_EXCEEDED;
+ }
+
+ /* Fix for bugid #394184, SD, 05 Jul 00 */
+ /* not sure this is the appropriate place to do this;
+ since the entries are swaped in slapd_qsort, some of them are most
+ probably counted more than once */
+ /* hence commenting out the following test and moving it into slapd_qsort */
+ /* check lookthrough limit */
+ /* if ( bc->lookthrough_limit != -1 && (bc->lookthrough_limit -= CHECK_INTERVAL) < 0 ) {
+ return LDAP_ADMINLIMIT_EXCEEDED;
+ } */
+ /* end for bugid #394184 */
+
+ }
+ return LDAP_SUCCESS;
+}
+/* End fix for bug # 394184 */
+
+/* prototypes for local routines */
+static void shortsort(baggage_carrier *bc,ID *lo, ID *hi,sort_spec *s );
+static void swap (ID *a,ID *b);
+
+/* this parameter defines the cutoff between using quick sort and
+ insertion sort for arrays; arrays with lengths shorter or equal to the
+ below value use insertion sort */
+
+#define CUTOFF 8 /* testing shows that this is good value */
+
+
+/* Fix for bug # 394184, SD, 20 Jul 00 */
+/* replace the hard coded return value by the appropriate LDAP error code */
+/* Our qsort needs to police the client timeout and lookthrough limit ?
+ * It knows how to compare entries, so we don't bother with all the void * stuff.
+ */
+/*
+ * Returns:
+ * 0: Everything OK now is: LDAP_SUCCESS (fix for bug #394184)
+ * -1: A protocol error now is: LDAP_PROTOCOL_ERROR
+ * -2: Too hard now is: LDAP_UNWILLING_TO_PERFORM
+ * -3: Operation error now is: LDAP_OPERATIONS_ERROR
+ * -4: Timeout now is: LDAP_TIMELIMIT_EXCEEDED
+ * -5: Admin limit exceeded now is: LDAP_ADMINLIMIT_EXCEEDED
+ * -6: Abandoned now is: LDAP_OTHER
+ */
+static int slapd_qsort(baggage_carrier *bc,IDList *list, sort_spec *s)
+{
+ ID *lo, *hi; /* ends of sub-array currently sorting */
+ ID *mid; /* points to middle of subarray */
+ ID *loguy, *higuy; /* traveling pointers for partition step */
+ NIDS size; /* size of the sub-array */
+ ID *lostk[30], *histk[30];
+ int stkptr; /* stack for saving sub-array to be processed */
+ NIDS num = list->b_nids;
+ int return_value = LDAP_SUCCESS;
+ int error = 0;
+
+ /* Note: the number of stack entries required is no more than
+ 1 + log2(size), so 30 is sufficient for any array */
+ if (num < 2 )
+ return LDAP_SUCCESS; /* nothing to do */
+
+ stkptr = 0; /* initialize stack */
+
+ lo = &(list->b_ids[0]);
+ hi = &(list->b_ids[num-1]); /* initialize limits */
+
+ /* Fix for bugid #394184, SD, 20 Jul 00 */
+ if ( bc->lookthrough_limit != -1 && ( bc->lookthrough_limit <= (int) list->b_nids) ) {
+ return LDAP_ADMINLIMIT_EXCEEDED;
+ }
+ /* end Fix for bugid #394184 */
+
+ /* this entry point is for pseudo-recursion calling: setting
+ lo and hi and jumping to here is like recursion, but stkptr is
+ prserved, locals aren't, so we preserve stuff on the stack */
+recurse:
+
+ size = (hi - lo) + 1; /* number of el's to sort */
+
+ /* below a certain size, it is faster to use a O(n^2) sorting method */
+ if (size <= CUTOFF) {
+ shortsort(bc,lo, hi, s );
+ }
+ else {
+ /* First we pick a partititioning element. The efficiency of the
+ algorithm demands that we find one that is approximately the
+ median of the values, but also that we select one fast. Using
+ the first one produces bad performace if the array is already
+ sorted, so we use the middle one, which would require a very
+ wierdly arranged array for worst case performance. Testing shows
+ that a median-of-three algorithm does not, in general, increase
+ performance. */
+
+ mid = lo + (size / 2); /* find middle element */
+ swap(mid, lo); /* swap it to beginning of array */
+
+ /* We now wish to partition the array into three pieces, one
+ consisiting of elements <= partition element, one of elements
+ equal to the parition element, and one of element >= to it. This
+ is done below; comments indicate conditions established at every
+ step. */
+
+ loguy = lo;
+ higuy = hi + 1;
+
+ /* Note that higuy decreases and loguy increases on every iteration,
+ so loop must terminate. */
+ for (;;) {
+ /* lo <= loguy < hi, lo < higuy <= hi + 1,
+ A[i] <= A[lo] for lo <= i <= loguy,
+ A[i] >= A[lo] for higuy <= i <= hi */
+
+ do {
+ loguy ++;
+ } while (loguy <= hi && compare_entries_sv(loguy, lo, s, bc, &error) <= 0);
+
+ /* lo < loguy <= hi+1, A[i] <= A[lo] for lo <= i < loguy,
+ either loguy > hi or A[loguy] > A[lo] */
+
+ do {
+ higuy --;
+ } while (higuy > lo && compare_entries_sv(higuy, lo, s, bc, &error) >= 0);
+
+ /* lo-1 <= higuy <= hi, A[i] >= A[lo] for higuy < i <= hi,
+ either higuy <= lo or A[higuy] < A[lo] */
+
+ if (higuy < loguy)
+ break;
+
+ /* if loguy > hi or higuy <= lo, then we would have exited, so
+ A[loguy] > A[lo], A[higuy] < A[lo],
+ loguy < hi, highy > lo */
+
+ swap(loguy, higuy);
+
+ /* Check admin and time limits here on the sort */
+ if ( LDAP_SUCCESS != (return_value = sort_nazi(bc)) )
+ {
+ return return_value;
+ }
+
+ /* A[loguy] < A[lo], A[higuy] > A[lo]; so condition at top
+ of loop is re-established */
+ }
+
+ /* A[i] >= A[lo] for higuy < i <= hi,
+ A[i] <= A[lo] for lo <= i < loguy,
+ higuy < loguy, lo <= higuy <= hi
+ implying:
+ A[i] >= A[lo] for loguy <= i <= hi,
+ A[i] <= A[lo] for lo <= i <= higuy,
+ A[i] = A[lo] for higuy < i < loguy */
+
+ swap(lo, higuy); /* put partition element in place */
+
+ /* OK, now we have the following:
+ A[i] >= A[higuy] for loguy <= i <= hi,
+ A[i] <= A[higuy] for lo <= i < higuy
+ A[i] = A[lo] for higuy <= i < loguy */
+
+ /* We've finished the partition, now we want to sort the subarrays
+ [lo, higuy-1] and [loguy, hi].
+ We do the smaller one first to minimize stack usage.
+ We only sort arrays of length 2 or more.*/
+
+ if ( higuy - 1 - lo >= hi - loguy ) {
+ if (lo + 1 < higuy) {
+ lostk[stkptr] = lo;
+ histk[stkptr] = higuy - 1;
+ ++stkptr;
+ } /* save big recursion for later */
+
+ if (loguy < hi) {
+ lo = loguy;
+ goto recurse; /* do small recursion */
+ }
+ }
+ else {
+ if (loguy < hi) {
+ lostk[stkptr] = loguy;
+ histk[stkptr] = hi;
+ ++stkptr; /* save big recursion for later */
+ }
+
+ if (lo + 1 < higuy) {
+ hi = higuy - 1;
+ goto recurse; /* do small recursion */
+ }
+ }
+ }
+
+ /* We have sorted the array, except for any pending sorts on the stack.
+ Check if there are any, and do them. */
+
+ --stkptr;
+ if (stkptr >= 0) {
+ lo = lostk[stkptr];
+ hi = histk[stkptr];
+ goto recurse; /* pop subarray from stack */
+ }
+ else
+ return LDAP_SUCCESS; /* all subarrays done */
+}
+/* End fix for bug # 394184 */
+
+
+static void shortsort (
+ baggage_carrier *bc,
+ ID *lo,
+ ID *hi,
+ sort_spec *s
+ )
+{
+ ID *p, *max;
+ int error = 0;
+
+ /* Note: in assertions below, i and j are alway inside original bound of
+ array to sort. */
+
+ while (hi > lo) {
+ /* A[i] <= A[j] for i <= j, j > hi */
+ max = lo;
+ for (p = lo+1; p <= hi; p++) {
+ /* A[i] <= A[max] for lo <= i < p */
+ if (compare_entries_sv(p,max,s,bc,&error) > 0) {
+ max = p;
+ }
+ /* A[i] <= A[max] for lo <= i <= p */
+ }
+
+ /* A[i] <= A[max] for lo <= i <= hi */
+
+ swap(max, hi);
+
+ /* A[i] <= A[hi] for i <= hi, so A[i] <= A[j] for i <= j, j >= hi */
+
+ hi--;
+
+ /* A[i] <= A[j] for i <= j, j > hi, loop top condition established */
+ }
+ /* A[i] <= A[j] for i <= j, j > lo, which implies A[i] <= A[j] for i < j,
+ so array is sorted */
+}
+
+static void swap (ID *a,ID *b)
+{
+ ID tmp;
+
+ if ( a != b ) {
+ tmp = *a;
+ *a = *b;
+ *b = tmp;
+ }
+}
+
+
diff --git a/ldap/servers/slapd/back-ldbm/start.c b/ldap/servers/slapd/back-ldbm/start.c
new file mode 100644
index 00000000..f87b7112
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/start.c
@@ -0,0 +1,177 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * start.c
+ */
+
+#include "back-ldbm.h"
+
+/*
+ * Start the LDBM plugin, and all its instances.
+ */
+int
+ldbm_back_start( Slapi_PBlock *pb )
+{
+ struct ldbminfo *li;
+ static int initialized = 0;
+ char *home_dir;
+ int action;
+ int retval;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend starting\n", 0, 0, 0 );
+
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &li );
+
+ /* parse the config file here */
+ ldbm_config_load_dse_info(li);
+
+ /* register with the binder-based resource limit subsystem so that */
+ /* lookthroughlimit can be supported on a per-connection basis. */
+ if ( slapi_reslimit_register( SLAPI_RESLIMIT_TYPE_INT,
+ LDBM_LOOKTHROUGHLIMIT_AT, &li->li_reslimit_lookthrough_handle )
+ != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "start: Resource limit registration failed\n",
+ 0, 0, 0 );
+ return SLAPI_FAIL_GENERAL;
+ }
+
+ /* If the db directory hasn't been set yet, we need to set it to
+ * the default. */
+ if ('\0' == li->li_directory[0]) {
+ /* "get default" is a special string that tells the config
+ * routines to figure out the default db directory by
+ * reading cn=config. */
+ ldbm_config_internal_set(li, CONFIG_DIRECTORY, "get default");
+ }
+
+ /* sanity check the autosizing values,
+ no value or sum of values larger than 100.
+ */
+ if ( (li->li_cache_autosize > 100) ||
+ (li->li_cache_autosize_split > 100) ||
+ (li->li_import_cache_autosize > 100) ||
+ ((li->li_cache_autosize > 0) && (li->li_import_cache_autosize > 0) &&
+ (li->li_cache_autosize + li->li_import_cache_autosize > 100)) )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "cache autosizing: bad settings, "
+ "value or sum of values can not larger than 100.\n", 0, 0, 0 );
+ } else
+ /* if cache autosize was selected, select the cache sizes now */
+ if ((li->li_cache_autosize > 0) || (li->li_import_cache_autosize > 0)) {
+ size_t pagesize, pages, procpages, availpages;
+
+ dblayer_sys_pages(&pagesize, &pages, &procpages, &availpages);
+ if (pagesize) {
+ char s[32]; /* big enough to hold %ld */
+ unsigned long cache_size_to_configure = 0;
+ int zone_pages, db_pages, entry_pages, import_pages;
+ Object *inst_obj;
+ ldbm_instance *inst;
+ /* autosizing dbCache and entryCache */
+ if (li->li_cache_autosize) {
+ zone_pages = (li->li_cache_autosize * pages) / 100;
+ /* now split it according to user prefs */
+ db_pages = (li->li_cache_autosize_split * zone_pages) / 100;
+ /* fudge an extra instance into our calculations... */
+ entry_pages = (zone_pages - db_pages) /
+ (objset_size(li->li_instance_set) + 1);
+ LDAPDebug(LDAP_DEBUG_ANY, "cache autosizing. found %dk physical memory\n",
+ pages*(pagesize/1024), 0, 0);
+ LDAPDebug(LDAP_DEBUG_ANY, "cache autosizing: db cache: %dk, "
+ "each entry cache (%d total): %dk\n",
+ db_pages*(pagesize/1024), objset_size(li->li_instance_set),
+ entry_pages*(pagesize/1024));
+
+ /* libdb allocates 1.25x the amount we tell it to, but only for values < 500Meg */
+ if (cache_size_to_configure < (500 * MEGABYTE)) {
+ cache_size_to_configure = (unsigned long)((db_pages * pagesize) / 1.25);
+ } else {
+ cache_size_to_configure = (unsigned long)(db_pages * pagesize);
+ }
+ sprintf(s, "%lu", cache_size_to_configure);
+ ldbm_config_internal_set(li, CONFIG_DBCACHESIZE, s);
+ li->li_cache_autosize_ec = (unsigned long)entry_pages * pagesize;
+
+ for (inst_obj = objset_first_obj(li->li_instance_set); inst_obj;
+ inst_obj = objset_next_obj(li->li_instance_set, inst_obj)) {
+ inst = (ldbm_instance *)object_get_data(inst_obj);
+ cache_set_max_entries(&(inst->inst_cache), -1);
+ cache_set_max_size(&(inst->inst_cache), li->li_cache_autosize_ec);
+ }
+ }
+ /* autosizing importCache */
+ if (li->li_import_cache_autosize) {
+ /* For some reason, -1 means 50 ... */
+ if (li->li_import_cache_autosize == -1) {
+ li->li_import_cache_autosize = 50;
+ }
+ import_pages = (li->li_import_cache_autosize * pages) / 100;
+ LDAPDebug(LDAP_DEBUG_ANY, "cache autosizing: import cache: %dk \n",
+ import_pages*(pagesize/1024), NULL, NULL);
+
+ sprintf(s, "%lu", (unsigned long)(import_pages * pagesize));
+ ldbm_config_internal_set(li, CONFIG_IMPORT_CACHESIZE, s);
+ }
+ }
+ }
+
+ retval = check_db_version(li, &action);
+ if (0 != retval)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "start: db version is not supported\n",
+ 0, 0, 0);
+ return SLAPI_FAIL_GENERAL;
+ }
+
+ if (action & DBVERSION_UPGRADE_3_4)
+ {
+ retval = dblayer_start(li,DBLAYER_CLEAN_RECOVER_MODE);
+ }
+ else
+ {
+ retval = dblayer_start(li,DBLAYER_NORMAL_MODE);
+ }
+ if (0 != retval) {
+ char *msg;
+ LDAPDebug( LDAP_DEBUG_ANY, "start: Failed to init database, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) return return_on_disk_full(li);
+ else return SLAPI_FAIL_GENERAL;
+ }
+
+ /* Walk down the instance list, starting all the instances. */
+ retval = ldbm_instance_startall(li);
+ if (0 != retval) {
+ char *msg;
+ LDAPDebug( LDAP_DEBUG_ANY, "start: Failed to start databases, err=%d %s\n",
+ retval, (msg = dblayer_strerror( retval )) ? msg : "", 0 );
+ if (LDBM_OS_ERR_IS_DISKFULL(retval)) return return_on_disk_full(li);
+ else return SLAPI_FAIL_GENERAL;
+ }
+
+ /* write DBVERSION file if one does not exist */
+ home_dir = dblayer_get_home_dir(li, NULL);
+ if (!dbversion_exists(li, home_dir))
+ {
+ dbversion_write (li, home_dir, NULL);
+ }
+
+
+ /* this function is called every time new db is initialized */
+ /* currently it is called the 2nd time when changelog db is */
+ /* dynamically created. Code below should only be called once */
+ if (!initialized)
+ {
+ ldbm_compute_init();
+
+ initialized = 1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend done starting\n", 0, 0, 0 );
+
+ return( 0 );
+
+}
diff --git a/ldap/servers/slapd/back-ldbm/tools/index_dump/Makefile b/ldap/servers/slapd/back-ldbm/tools/index_dump/Makefile
new file mode 100644
index 00000000..7b41ae90
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/tools/index_dump/Makefile
@@ -0,0 +1,40 @@
+#
+# 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 libback-ldbm
+#
+
+LDAP_SRC = ../../../../..
+MCOM_ROOT = ../../../../../../..
+
+OBJDEST = $(OBJDIR)/lib/libback-ldbm
+LIBDIR = $(LDAP_LIBDIR)
+
+include $(MCOM_ROOT)/netsite/nsdefs.mk
+include $(MCOM_ROOT)/netsite/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+include $(MCOM_ROOT)/netsite/ns_usedb.mk
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd
+
+INDEX_DUMP_OBJS= index_dump.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(INDEX_DUMP_OBJS))
+
+all: $(OBJDEST) $(LIBDIR) $(SLIBBACK_LDBM) $(LIBBACK_LDBM)
+
+veryclean: clean
+
+clean:
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(BINDIR):
+ $(MKDIR) $(LIBDIR)
+
diff --git a/ldap/servers/slapd/back-ldbm/tools/index_dump/index_dump.c b/ldap/servers/slapd/back-ldbm/tools/index_dump/index_dump.c
new file mode 100644
index 00000000..66998e49
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/tools/index_dump/index_dump.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 **/
+
+void configure __P((char *));
+DB_ENV *db_init __P((char *));
+void pheader __P((DB *, int));
+void usage __P((void));
+
+const char
+ *progname = "db_dump"; /* Program name. */
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ extern char *optarg;
+ extern int optind;
+ DB *dbp;
+ DBC *dbcp;
+ DBT key, data;
+ DB_ENV *dbenv;
+ int ch, checkprint, dflag;
+ char *home;
+
+ home = NULL;
+ checkprint = dflag = 0;
+ while ((ch = getopt(argc, argv, "df:h:p")) != EOF)
+ switch (ch) {
+ case 'd':
+ dflag = 1;
+ break;
+ case 'f':
+ if (freopen(optarg, "w", stdout) == NULL)
+ err(1, "%s", optarg);
+ break;
+ case 'h':
+ home = optarg;
+ break;
+ case 'p':
+ checkprint = 1;
+ break;
+ case '?':
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc != 1)
+ usage();
+
+ if (dflag) {
+ if (home != NULL)
+ errx(1,
+ "the -d and -h options may not both be specified");
+ if (checkprint)
+ errx(1,
+ "the -d and -p options may not both be specified");
+ }
+ /* Initialize the environment. */
+ dbenv = dflag ? NULL : db_init(home);
+
+ /* Open the DB file. */
+ if ((errno =
+ db_open(argv[0], DB_UNKNOWN, DB_RDONLY, 0, dbenv, NULL, &dbp)) != 0)
+ err(1, "%s", argv[0]);
+
+ /* DB dump. */
+ if (dflag) {
+ (void)__db_dump(dbp, NULL, 1);
+ if ((errno = dbp->close(dbp, 0)) != 0)
+ err(1, "close");
+ exit (0);
+ }
+
+ /* Get a cursor and step through the database. */
+ if ((errno = dbp->cursor(dbp, NULL, &dbcp)) != 0) {
+ (void)dbp->close(dbp, 0);
+ err(1, "cursor");
+ }
+
+ /* Print out the header. */
+ pheader(dbp, checkprint);
+
+ /* Print out the key/data pairs. */
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+ while ((errno = dbcp->c_get(dbcp, &key, &data, DB_NEXT)) == 0) {
+ if (dbp->type != DB_RECNO &&
+ (errno = __db_prdbt(&key, checkprint, stdout)) != 0)
+ break;
+ if ((errno = __db_prdbt(&data, checkprint, stdout)) != 0)
+ break;
+ }
+
+ if (errno != DB_NOTFOUND)
+ err(1, "cursor get");
+
+ if ((errno = dbp->close(dbp, 0)) != 0)
+ err(1, "close");
+ return (0);
+}
+
+/*
+ * db_init --
+ * Initialize the environment.
+ */
+DB_ENV *
+db_init(home)
+ char *home;
+{
+ DB_ENV *dbenv;
+
+ if ((dbenv = (DB_ENV *)calloc(sizeof(DB_ENV), 1)) == NULL) {
+ errno = ENOMEM;
+ err(1, NULL);
+ }
+ dbenv->db_errfile = stderr;
+ dbenv->db_errpfx = progname;
+
+ if ((errno =
+ db_appinit(home, NULL, dbenv, DB_CREATE | DB_USE_ENVIRON)) != 0)
+ err(1, "db_appinit");
+ return (dbenv);
+}
+
+/*
+ * pheader --
+ * Write out the header information.
+ */
+void
+pheader(dbp, pflag)
+ DB *dbp;
+ int pflag;
+{
+ DB_BTREE_STAT *btsp;
+ HTAB *hashp;
+ HASHHDR *hdr;
+ db_pgno_t pgno;
+
+ printf("format=%s\n", pflag ? "print" : "bytevalue");
+ switch (dbp->type) {
+ case DB_BTREE:
+ printf("type=btree\n");
+ if ((errno = dbp->stat(dbp, &btsp, NULL, 0)) != 0)
+ err(1, "dbp->stat");
+ if (F_ISSET(dbp, DB_BT_RECNUM))
+ printf("recnum=1\n");
+ if (btsp->bt_maxkey != 0)
+ printf("bt_maxkey=%lu\n", (u_long)btsp->bt_maxkey);
+ if (btsp->bt_minkey != 0)
+ printf("bt_minkey=%lu\n", (u_long)btsp->bt_minkey);
+ break;
+ case DB_HASH:
+ printf("type=hash\n");
+ hashp = dbp->internal;
+ pgno = PGNO_METADATA;
+ if (memp_fget(dbp->mpf, &pgno, 0, &hdr) == 0) {
+ if (hdr->ffactor != 0)
+ printf("h_ffactor=%lu\n", (u_long)hdr->ffactor);
+ if (hdr->nelem != 0)
+ printf("h_nelem=%lu\n", (u_long)hdr->nelem);
+ (void)memp_fput(dbp->mpf, hdr, 0);
+ }
+ break;
+ case DB_RECNO:
+ printf("type=recno\n");
+ if (F_ISSET(dbp, DB_RE_RENUMBER))
+ printf("renumber=1\n");
+ if (F_ISSET(dbp, DB_RE_FIXEDLEN))
+ printf("re_len=%lu\n", (u_long)btsp->bt_re_len);
+ if (F_ISSET(dbp, DB_RE_PAD))
+ printf("re_pad=%#x\n", btsp->bt_re_pad);
+ break;
+ case DB_UNKNOWN:
+ abort();
+ /* NOTREACHED */
+ }
+
+ if (F_ISSET(dbp, DB_AM_DUP))
+ printf("duplicates=1\n");
+
+ if (dbp->dbenv->db_lorder != 0)
+ printf("db_lorder=%lu\n", (u_long)dbp->dbenv->db_lorder);
+
+ if (!F_ISSET(dbp, DB_AM_PGDEF))
+ printf("db_pagesize=%lu\n", (u_long)dbp->pgsize);
+
+ printf("HEADER=END\n");
+}
+
+/*
+ * usage --
+ * Display the usage message.
+ */
+void
+usage()
+{
+ (void)fprintf(stderr,
+ "usage: db_dump [-dp] [-f file] [-h home] db_file\n");
+ exit(1);
+}
diff --git a/ldap/servers/slapd/back-ldbm/uniqueid2entry.c b/ldap/servers/slapd/back-ldbm/uniqueid2entry.c
new file mode 100644
index 00000000..31f53898
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/uniqueid2entry.c
@@ -0,0 +1,74 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* uniqueid2entry.c - given a dn return an entry */
+
+#include "back-ldbm.h"
+
+/*
+ * uniqueid2entry - look up uniqueid in the cache/indexes and return the
+ * corresponding entry.
+ */
+
+struct backentry *
+uniqueid2entry(
+ backend *be,
+ const char *uniqueid,
+ back_txn *txn,
+ int *err
+)
+{
+#ifdef UUIDCACHE_ON
+ ldbm_instance *inst = (ldbm_instance *) be->be_instance_info;
+#endif
+ struct berval idv;
+ IDList *idl = NULL;
+ struct backentry *e = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> uniqueid2entry \"%s\"\n", uniqueid,
+ 0, 0 );
+#ifdef UUIDCACHE_ON
+ e = cache_find_uuid(&inst->inst_cache, uniqueid);
+#endif
+ if (e == NULL) {
+ /* convert dn to entry id */
+ *err = 0;
+ idv.bv_val = (void*)uniqueid;
+ idv.bv_len = strlen( idv.bv_val );
+
+ if ( (idl = index_read( be, SLAPI_ATTR_UNIQUEID, indextype_EQUALITY, &idv, txn,
+ err )) == NULL ) {
+ if ( *err != 0 && *err != DB_NOTFOUND ) {
+ goto ext;
+ }
+ } else {
+ /* convert entry id to entry */
+ if ( (e = id2entry( be, idl_firstid( idl ), txn, err ))
+ != NULL ) {
+ goto ext;
+ } else {
+ if ( *err != 0 && *err != DB_NOTFOUND ) {
+ goto ext;
+ }
+ /*
+ * this is pretty bad anyway. the dn was in the
+ * SLAPI_ATTR_UNIQUEID index, but we could not
+ * read the entry from the id2entry index.
+ * what should we do?
+ */
+ }
+ }
+ } else {
+ goto ext;
+ }
+
+ext:
+ if (NULL != idl) {
+ slapi_ch_free( (void**)&idl);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= uniqueid2entry %p\n", e, 0, 0 );
+ return( e );
+}
diff --git a/ldap/servers/slapd/back-ldbm/upgrade.c b/ldap/servers/slapd/back-ldbm/upgrade.c
new file mode 100644
index 00000000..1c0bfb9d
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/upgrade.c
@@ -0,0 +1,352 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* upgrade.c --- upgrade from a previous version of the database */
+
+#include "back-ldbm.h"
+
+#if 0
+static char* filename = "upgrade.c";
+#endif
+/*
+ * ldbm_compat_versions holds DBVERSION strings for all versions of the
+ * database with which we are (upwards) compatible. If check_db_version
+ * encounters a database with a version that is not listed in this array,
+ * we display a warning message.
+ */
+
+db_upgrade_info ldbm_version_suss[] = {
+#if defined(USE_NEW_IDL)
+ {LDBM_VERSION,DBVERSION_NEW_IDL,DBVERSION_NO_UPGRADE},
+ {LDBM_VERSION_OLD,DBVERSION_OLD_IDL,DBVERSION_NO_UPGRADE},
+#else
+ /* default: old idl (DS6.2) */
+ {LDBM_VERSION_NEW,DBVERSION_NEW_IDL,DBVERSION_NO_UPGRADE},
+ {LDBM_VERSION,DBVERSION_OLD_IDL,DBVERSION_NO_UPGRADE},
+#endif
+ {LDBM_VERSION_61,DBVERSION_NEW_IDL,DBVERSION_UPGRADE_3_4},
+ {LDBM_VERSION_60,DBVERSION_OLD_IDL,DBVERSION_UPGRADE_3_4},
+ {NULL,0,0}
+};
+
+
+/* clear the following flag to suppress "database files do not exist" warning
+int ldbm_warn_if_no_db = 0;
+*/
+/* global LDBM version in the db home */
+
+int
+lookup_dbversion(char *dbversion, int flag)
+{
+ int i, matched = 0;
+ int rval = 0;
+
+ for ( i = 0; ldbm_version_suss[i].old_version_string != NULL; ++i )
+ {
+ if ( strcmp( dbversion, ldbm_version_suss[i].old_version_string ) == 0 )
+ {
+ matched = 1;
+ break;
+ }
+ }
+ if ( matched )
+ {
+ if ( flag & DBVERSION_TYPE )
+ {
+ rval |= ldbm_version_suss[i].type;
+ }
+ if ( flag & DBVERSION_ACTION )
+ {
+ rval |= ldbm_version_suss[i].action;
+ }
+ }
+ return rval;
+}
+
+/*
+ * this function reads the db/DBVERSION file and check
+ * 1) if the db version is supported, and
+ * 2) if the db version requires some migration operation
+ *
+ * return: 0: supported
+ * DBVERSION_NOT_SUPPORTED: not supported
+ *
+ * action: 0: nothing is needed
+ * DBVERSION_UPGRADE_3_4: db3->db4 uprev is needed
+ */
+int
+check_db_version( struct ldbminfo *li, int *action )
+{
+ int value = 0;
+ char ldbmversion[BUFSIZ];
+ char dataversion[BUFSIZ];
+
+ *action = 0;
+ dbversion_read(li, li->li_directory,ldbmversion,dataversion);
+ if (0 == strlen(ldbmversion))
+ return 0;
+
+ value = lookup_dbversion( ldbmversion, DBVERSION_TYPE | DBVERSION_ACTION);
+ if ( !value )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: Database version mismatch (expecting "
+ "'%s' but found '%s' in directory %s)\n",
+ LDBM_VERSION, ldbmversion, li->li_directory );
+ /*
+ * A non-zero return here will cause slapd to exit during startup.
+ */
+ return DBVERSION_NOT_SUPPORTED;
+ }
+ if ( value & DBVERSION_UPGRADE_3_4 )
+ {
+ dblayer_set_recovery_required(li);
+ *action = DBVERSION_UPGRADE_3_4;
+ }
+ return 0;
+}
+
+/*
+ * this function reads the db/<inst>/DBVERSION file and check
+ * 1) if the db version is supported, and
+ * 2) if the db version matches the idl configuration
+ * (nsslapd-idl-switch: new|old)
+ * note that old idl will disappear from the next major update (6.5? 7.0?)
+ *
+ * return: 0: supported and the version matched
+ * DBVERSION_NEED_IDL_OLD2NEW: old->new uprev is needed
+ * (used in convindices)
+ * DBVERSION_NEED_IDL_NEW2OLD: old db is found, for the new idl config
+ * DBVERSION_NOT_SUPPORTED: not supported
+ *
+ * DBVERSION_UPGRADE_3_4: db3->db4 uprev is needed
+ */
+int
+check_db_inst_version( ldbm_instance *inst )
+{
+ int value = 0;
+ char ldbmversion[BUFSIZ];
+ char dataversion[BUFSIZ];
+ int rval = 0;
+ char inst_dir[MAXPATHLEN*2];
+ char *inst_dirp = NULL;
+
+ inst_dirp =
+ dblayer_get_full_inst_dir(inst->inst_li, inst, inst_dir, MAXPATHLEN*2);
+
+ dbversion_read(inst->inst_li, inst_dirp,ldbmversion,dataversion);
+ if (0 == strlen(ldbmversion))
+ return rval;
+
+ value = lookup_dbversion( ldbmversion, DBVERSION_TYPE | DBVERSION_ACTION);
+ if ( !value )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: Database version mismatch (expecting "
+ "'%s' but found '%s' in directory %s)\n",
+ LDBM_VERSION, ldbmversion, inst->inst_dir_name );
+ /*
+ * A non-zero return here will cause slapd to exit during startup.
+ */
+ return DBVERSION_NOT_SUPPORTED;
+ }
+
+ /* recognize the difference between an old/new database regarding idl
+ * (406922) */
+ if (idl_get_idl_new() && !(value & DBVERSION_NEW_IDL) )
+ {
+ rval |= DBVERSION_NEED_IDL_OLD2NEW;
+ }
+ else if (!idl_get_idl_new() && !(value & DBVERSION_OLD_IDL) )
+ {
+ rval |= DBVERSION_NEED_IDL_NEW2OLD;
+ }
+ if ( value & DBVERSION_UPGRADE_3_4 )
+ {
+ rval |= DBVERSION_UPGRADE_3_4;
+ }
+ if (inst_dirp != inst_dir)
+ slapi_ch_free_string(&inst_dirp);
+ return rval;
+}
+
+#if defined(UPGRADEDB)
+/*
+ * adjust_idl_switch
+ * if the current nsslapd-idl-switch is different from ldbmversion,
+ * update the value of nsslapd-idl-switch (in LDBM_CONFIG_ENTRY)
+ */
+int
+adjust_idl_switch(char *ldbmversion, struct ldbminfo *li)
+{
+ int rval = 0;
+
+ li->li_flags |= LI_FORCE_MOD_CONFIG;
+#if defined(USE_NEW_IDL)
+ if ((0 == strcmp(ldbmversion, LDBM_VERSION)) ||
+ (0 == strcmp(ldbmversion, LDBM_VERSION_61))) /* db: new idl */
+#else
+ if ((0 == strcmp(ldbmversion, LDBM_VERSION_NEW)) ||
+ (0 == strcmp(ldbmversion, LDBM_VERSION_61))) /* db: new idl */
+#endif
+ {
+ if (!idl_get_idl_new()) /* config: old idl */
+ {
+ replace_ldbm_config_value(CONFIG_IDL_SWITCH, "new", li);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: Dbversion %s does not meet nsslapd-idl-switch: \"old\"; "
+ "nsslapd-idl-switch is updated to \"new\"\n",
+
+ ldbmversion, 0, 0);
+ }
+ }
+#if defined(USE_NEW_IDL)
+ else if ((0 == strcmp(ldbmversion, LDBM_VERSION_OLD)) ||
+ (0 == strcmp(ldbmversion, LDBM_VERSION_60))) /* db: old */
+#else
+ else if ((0 == strcmp(ldbmversion, LDBM_VERSION)) || /* ds6.2: old */
+ (0 == strcmp(ldbmversion, LDBM_VERSION_60))) /* db: old */
+#endif
+ {
+ if (idl_get_idl_new()) /* config: new */
+ {
+ replace_ldbm_config_value(CONFIG_IDL_SWITCH, "old", li);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: Dbversion %s does not meet nsslapd-idl-switch: \"new\"; "
+ "nsslapd-idl-switch is updated to \"old\"\n",
+ ldbmversion, 0, 0);
+ }
+ }
+ else
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: Dbversion %s is not supported\n",
+ ldbmversion, 0, 0);
+ rval = 1;
+ }
+
+ /* ldbminfo is a common resource; should clean up when the job is done */
+ li->li_flags &= ~LI_FORCE_MOD_CONFIG;
+ return rval;
+}
+#endif
+
+/* Do the work to upgrade a database if needed */
+/* When we're called, the database files have been opened, and any
+recovery needed has been performed. */
+int ldbm_upgrade(ldbm_instance *inst, int action)
+{
+ int rval = 0;
+
+ if (0 == action)
+ {
+ return rval;
+ }
+
+ if (action & DBVERSION_UPGRADE_3_4) /* upgrade from db3 to db4 */
+ {
+ /* basically, db4 supports db3.
+ * so, what we need to do is rename XXX.db3 to XXX.db4 */
+
+ int rval = dblayer_update_db_ext(inst, LDBM_SUFFIX_OLD, LDBM_SUFFIX);
+ if (0 == rval)
+ {
+#if defined(USE_NEW_IDL)
+ if (idl_get_idl_new())
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm_upgrade: Upgrading instance %s to %s%s is successfully done.\n",
+ inst->inst_name, LDBM_VERSION_BASE, PRODUCTTEXT);
+ }
+ else
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm_upgrade: Upgrading instance %s to %s%s is successfully done.\n",
+ inst->inst_name, LDBM_VERSION_OLD, 0);
+ }
+#else
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm_upgrade: Upgrading instance %s to %s%s is successfully done.\n",
+ inst->inst_name, LDBM_VERSION_BASE, PRODUCTTEXT);
+#endif
+ }
+ else
+ {
+ /* recovery effort ... */
+ dblayer_update_db_ext(inst, LDBM_SUFFIX, LDBM_SUFFIX_OLD);
+ return rval;
+ }
+ }
+
+ return 0; /* Means that the database is new */
+}
+
+/* Here's the upgrade process :
+ Delete all the keys from the parentid index
+ Scan the id2entry file:
+ Remove any hassubordinates attribute present
+ Update the parentid index, maintaining a hash of high-count parents
+ Scan the newly created parentid index updating the subordinatecount attributes.
+
+ Most of the functionality is implemented in the import code.
+ */
+#if 0
+static int upgrade_db_3x_40(backend *be)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ int ret = 0;
+ back_txn txn;
+
+ static char* indexes_modified[] = {"parentid", "numsubordinates", NULL};
+
+ LDAPDebug( LDAP_DEBUG_ANY, "WARNING: Detected a database older than this server, upgrading data...\n",0,0,0);
+
+ dblayer_txn_init(li,&txn);
+ ret = dblayer_txn_begin(li,NULL,&txn);
+ if (0 != ret) {
+ ldbm_nasty(filename,69,ret);
+ goto error;
+ }
+ ret = indexfile_delete_all_keys(be,"parentid",&txn);
+ if (0 != ret) {
+ ldbm_nasty(filename,70,ret);
+ goto error;
+ }
+
+ {
+ Slapi_Mods smods;
+ slapi_mods_init(&smods,1);
+ /* Mods are to remove the hassubordinates attribute */
+ slapi_mods_add(&smods, LDAP_MOD_DELETE, "hassubordinates", 0, NULL);
+ /* This function takes care of generating the subordinatecount attribute and indexing it */
+ ret = indexfile_primary_modifyall(be,slapi_mods_get_ldapmods_byref(&smods),indexes_modified,&txn);
+ slapi_mods_done(&smods);
+ }
+
+ if (0 != ret) {
+ ldbm_nasty(filename,61,ret);
+ }
+
+error:
+ if (0 != ret ) {
+ dblayer_txn_abort(li,&txn);
+ } else {
+ ret = dblayer_txn_commit(li,&txn);
+ if (0 != ret) {
+ ldbm_nasty(filename,60,ret);
+ } else {
+ /* Now update DBVERSION file */
+ }
+ }
+ if (0 == ret) {
+ LDAPDebug( LDAP_DEBUG_ANY, "...upgrade complete.\n",0,0,0);
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: Attempt to upgrade the older database FAILED.\n",0,0,0);
+ }
+ return ret;
+}
+
+#endif
diff --git a/ldap/servers/slapd/back-ldbm/vlv.c b/ldap/servers/slapd/back-ldbm/vlv.c
new file mode 100644
index 00000000..8397ef0e
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/vlv.c
@@ -0,0 +1,1947 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* vlv.c */
+
+
+/*
+ * References to on-line documentation here.
+ *
+ * http://BLUES/users/dboreham/publish/Design_Documentation/RFCs/draft-ietf-asid-ldapv3-virtuallistview-01.html
+ * http://warp.mcom.com/server/directory-server/clientsdk/hammerhead/design/virtuallistview.html
+ * ftp://ftp.ietf.org/internet-drafts/draft-ietf-ldapext-ldapv3-vlv-00.txt
+ * http://rocknroll/users/merrells/publish/vlvimplementation.html
+ */
+
+
+#include "back-ldbm.h"
+#include "vlv_srch.h"
+#include "vlv_key.h"
+
+static PRUint32 vlv_trim_candidates_byindex(PRUint32 length, const struct vlv_request *vlv_request_control);
+static PRUint32 vlv_trim_candidates_byvalue(backend *be, const IDList *candidates, const sort_spec* sort_control, const struct vlv_request *vlv_request_control);
+static int vlv_build_candidate_list( backend *be, struct vlvIndex* p, const struct vlv_request *vlv_request_control, IDList** candidates, struct vlv_response *vlv_response_control);
+
+/* New mutex for vlv locking
+PRRWLock * vlvSearchList_lock=NULL;
+static struct vlvSearch *vlvSearchList= NULL;
+*/
+
+#define ISLEGACY(be) (be?(be->be_instance_info?(((ldbm_instance *)be->be_instance_info)->inst_li?(((ldbm_instance *)be->be_instance_info)->inst_li->li_legacy_errcode):0):0):0)
+
+/* Callback to add a new VLV Search specification. Added write lock.*/
+
+int vlv_AddSearchEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ ldbm_instance *inst = (ldbm_instance *)arg;
+ struct vlvSearch* newVlvSearch= vlvSearch_new();
+ backend *be = inst->inst_be;
+
+ vlvSearch_init(newVlvSearch, pb, entryBefore, inst);
+ PR_RWLock_Wlock(be->vlvSearchList_lock);
+ vlvSearch_addtolist(newVlvSearch, (struct vlvSearch **)&be->vlvSearchList);
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* Callback to add a new VLV Index specification. Added write lock.*/
+
+int vlv_AddIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ struct vlvSearch *parent;
+ backend *be= ((ldbm_instance*)arg)->inst_be;
+ Slapi_DN parentdn;
+
+ slapi_sdn_init(&parentdn);
+ slapi_sdn_get_parent(slapi_entry_get_sdn(entryBefore),&parentdn);
+ {
+ PR_RWLock_Wlock(be->vlvSearchList_lock);
+ parent= vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, &parentdn);
+ if(parent!=NULL)
+ {
+ struct vlvIndex* newVlvIndex= vlvIndex_new();
+ newVlvIndex->vlv_be=be;
+ vlvIndex_init(newVlvIndex, be, parent, entryBefore);
+ vlvSearch_addIndex(parent, newVlvIndex);
+ }
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ }
+ slapi_sdn_done(&parentdn);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* Callback to delete a VLV Index specification. Added write lock.*/
+
+int vlv_DeleteSearchEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ struct vlvSearch* p=NULL;
+ backend *be= ((ldbm_instance*)arg)->inst_be;
+
+ PR_RWLock_Wlock(be->vlvSearchList_lock);
+ p = vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, slapi_entry_get_sdn(entryBefore));
+ if(p!=NULL)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Deleted Virtual List View Search (%s).\n", p->vlv_name, 0, 0);
+ vlvSearch_removefromlist((struct vlvSearch **)&be->vlvSearchList,p->vlv_dn);
+ vlvSearch_delete(&p);
+ }
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+/* Stub Callback to delete a VLV Index specification.*/
+
+int vlv_DeleteIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ LDAPDebug( LDAP_DEBUG_ANY, "Deleted Virtual List View Index.\n", 0, 0, 0);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+/* Callback to modify a VLV Search specification. Added read lock.*/
+
+int vlv_ModifySearchEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ struct vlvSearch* p=NULL;
+ backend *be= ((ldbm_instance*)arg)->inst_be;
+
+ PR_RWLock_Rlock(be->vlvSearchList_lock);
+ p= vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, slapi_entry_get_sdn(entryBefore));
+ if(p!=NULL)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Modified Virtual List View Search (%s), which will be enabled when the database is rebuilt.\n", p->vlv_name, 0, 0);
+ }
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return SLAPI_DSE_CALLBACK_DO_NOT_APPLY;
+}
+
+
+/* Stub callback to modify a VLV Index specification. */
+
+int vlv_ModifyIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ LDAPDebug( LDAP_DEBUG_ANY, "Modified Virtual List View Index.\n", 0, 0, 0);
+ return SLAPI_DSE_CALLBACK_DO_NOT_APPLY;
+}
+
+
+/* Callback to rename a VLV Search specification. Added read lock.*/
+
+int vlv_ModifyRDNSearchEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ struct vlvSearch* p=NULL;
+ backend *be= ((ldbm_instance*)arg)->inst_be;
+
+ PR_RWLock_Rlock(be->vlvSearchList_lock);
+ p= vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, slapi_entry_get_sdn(entryBefore));
+ if(p!=NULL)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Modified Virtual List View Search (%s), which will be enabled when the database is rebuilt.\n", p->vlv_name, 0, 0);
+ }
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return SLAPI_DSE_CALLBACK_DO_NOT_APPLY;
+}
+
+
+/* Stub callback to modify a VLV Index specification. */
+
+int vlv_ModifyRDNIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ LDAPDebug( LDAP_DEBUG_ANY, "Modified Virtual List View Index.\n", 0, 0, 0);
+ return SLAPI_DSE_CALLBACK_DO_NOT_APPLY;
+}
+
+/* Something may have just read a VLV Entry. */
+
+int vlv_SearchIndexEntry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ char *name= slapi_entry_attr_get_charptr(entryBefore,type_vlvName);
+ backend *be= ((ldbm_instance*)arg)->inst_be;
+ if (name!=NULL)
+ {
+ struct vlvIndex* p= vlv_find_searchname(name, be); /* lock list */
+ slapi_ch_free((void **) &name);
+ if(p!=NULL)
+ {
+ if(vlvIndex_enabled(p))
+ {
+ slapi_entry_attr_set_charptr(entryBefore, type_vlvEnabled, "1");
+ }
+ else
+ {
+ slapi_entry_attr_set_charptr(entryBefore, type_vlvEnabled, "0");
+ }
+ slapi_entry_attr_set_ulong(entryBefore, type_vlvUses, p->vlv_uses);
+ }
+ }
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* Handle results of a search for objectclass "vlvIndex". Called by vlv_init at inittime -- no need to lock*/
+
+static int
+vlv_init_index_entry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ struct vlvIndex* newVlvIndex;
+ struct vlvSearch* pSearch;
+ Slapi_Backend *be= ((ldbm_instance*)arg)->inst_be;
+ char ebuf[BUFSIZ];
+
+ if(be!=NULL)
+ {
+ Slapi_DN parentdn;
+
+ slapi_sdn_init(&parentdn);
+ newVlvIndex= vlvIndex_new();
+ slapi_sdn_get_parent(slapi_entry_get_sdn(entryBefore),&parentdn);
+ pSearch= vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, &parentdn);
+ if (pSearch == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Parent doesn't exist for entry %s.\n",
+ escape_string(slapi_entry_get_dn(entryBefore), ebuf), 0, 0);
+ }
+ else {
+ vlvIndex_init(newVlvIndex, be, pSearch, entryBefore);
+ vlvSearch_addIndex(pSearch, newVlvIndex);
+ }
+ slapi_sdn_done(&parentdn);
+ }
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* Handle results of a search for objectclass "vlvSearch". Called by vlv_init at inittime -- no need to lock*/
+
+static int
+vlv_init_search_entry(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ struct vlvSearch* newVlvSearch= vlvSearch_new();
+ ldbm_instance *inst = (ldbm_instance*)arg;
+ backend *be= inst->inst_be;
+
+ vlvSearch_init(newVlvSearch, pb, entryBefore, inst);
+ vlvSearch_addtolist(newVlvSearch, (struct vlvSearch **)&be->vlvSearchList);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* Look at a new entry, and the set of VLV searches, and see whether
+there are any which have deferred initialization and which can now
+be initialized given the new entry. Added write lock. */
+
+
+void vlv_grok_new_import_entry(const struct backentry *e, backend *be)
+{
+ struct vlvSearch* p = NULL;
+ static int seen_them_all = 0;
+ int any_not_done = 0;
+
+
+ PR_RWLock_Wlock(be->vlvSearchList_lock);
+ if (seen_them_all) {
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return;
+ }
+ p=(struct vlvSearch *)be->vlvSearchList;
+
+ /* Walk the list of searches */
+ for(;p!=NULL;p= p->vlv_next)
+ /* is this one not initialized ? */
+ if (0 == p->vlv_initialized) {
+ any_not_done = 1;
+ /* Is its base the entry we have here ? */
+ if (0 == slapi_sdn_compare(backentry_get_sdn(e),p->vlv_base) ) {
+ /* Then initialize it */
+ vlvSearch_reinit(p,e);
+ }
+ }
+ if (!any_not_done) {
+ seen_them_all = 1;
+ }
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+}
+
+/*
+ * Search for the VLV entries which describe the pre-computed indexes we
+ * support. Register administartion DSE callback functions.
+ * This is exported to the backend initialisation routine.
+ * 'inst' may be NULL for non-slapd initialization...
+ */
+int
+vlv_init(ldbm_instance *inst)
+{
+ /* The FE DSE *must* be initialised before we get here */
+ int return_value= LDAP_SUCCESS;
+ int scope= LDAP_SCOPE_SUBTREE;
+ char *basedn, buf[512];
+ const char *searchfilter = "(objectclass=vlvsearch)";
+ const char *indexfilter = "(objectclass=vlvindex)";
+ backend *be= inst->inst_be;
+
+ /* Initialize lock first time through */
+ if(be->vlvSearchList_lock == NULL) {
+ char *rwlockname = (char *)slapi_ch_malloc(sizeof("vlvSearchList") +
+ strlen(inst->inst_name) + 2);
+ sprintf(rwlockname, "vlvSearchList_%s", inst->inst_name);
+ be->vlvSearchList_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, rwlockname);
+ slapi_ch_free((void**)&rwlockname);
+ }
+ if (NULL != (struct vlvSearch *)be->vlvSearchList)
+ {
+ struct vlvSearch *t = NULL;
+ struct vlvSearch *nt = NULL;
+ PR_RWLock_Wlock(be->vlvSearchList_lock);
+ for (t = (struct vlvSearch *)be->vlvSearchList; NULL != t; )
+ {
+ nt = t->vlv_next;
+ vlvSearch_delete(&t);
+ t = nt;
+ }
+ be->vlvSearchList = NULL;
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ }
+ if (inst == NULL) {
+ basedn = NULL;
+ } else {
+ sprintf(buf, "cn=%s,cn=%s,cn=plugins,cn=config",
+ inst->inst_name, inst->inst_li->li_plugin->plg_name);
+ basedn = buf;
+ }
+
+ /* Find the VLV Search Entries */
+ {
+ Slapi_PBlock *tmp_pb;
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_init_search_entry,(void *)inst);
+ tmp_pb= slapi_search_internal(basedn, scope, searchfilter, NULL, NULL, 0);
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_init_search_entry);
+ slapi_free_search_results_internal(tmp_pb);
+ slapi_pblock_destroy(tmp_pb);
+ }
+
+ /* Find the VLV Index Entries */
+ {
+ Slapi_PBlock *tmp_pb;
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_init_index_entry,(void*)inst);
+ tmp_pb= slapi_search_internal(basedn, scope, indexfilter, NULL, NULL, 0);
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_init_index_entry);
+ slapi_free_search_results_internal(tmp_pb);
+ slapi_pblock_destroy(tmp_pb);
+ }
+
+ /* Only need to register these callbacks for SLAPD mode... */
+ if(basedn!=NULL)
+ {
+ slapi_config_register_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_SearchIndexEntry,(void*)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_AddSearchEntry,(void*)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_AddIndexEntry,(void*)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifySearchEntry,(void*)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyIndexEntry,(void*)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_DeleteSearchEntry,(void*)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_DeleteIndexEntry,(void*)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifyRDNSearchEntry,(void*)inst);
+ slapi_config_register_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyRDNIndexEntry,(void*)inst);
+ }
+
+ return return_value;
+}
+
+/* Removes callbacks from above when instance is removed. */
+
+int
+vlv_remove_callbacks(ldbm_instance *inst) {
+
+ int return_value= LDAP_SUCCESS;
+ int scope= LDAP_SCOPE_SUBTREE;
+ char *basedn, buf[512];
+ const char *searchfilter = "(objectclass=vlvsearch)";
+ const char *indexfilter = "(objectclass=vlvindex)";
+
+ if (inst == NULL) {
+ basedn = NULL;
+ } else {
+ sprintf(buf, "cn=%s,cn=%s,cn=plugins,cn=config",
+ inst->inst_name, inst->inst_li->li_plugin->plg_name);
+ basedn = buf;
+ }
+ if(basedn!=NULL)
+ {
+ slapi_config_remove_callback(SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_SearchIndexEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_AddSearchEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_AddIndexEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifySearchEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyIndexEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_DeleteSearchEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_DeleteIndexEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,searchfilter,vlv_ModifyRDNSearchEntry);
+ slapi_config_remove_callback(SLAPI_OPERATION_MODRDN,DSE_FLAG_PREOP,basedn,scope,indexfilter,vlv_ModifyRDNIndexEntry);
+ }
+ return return_value;
+}
+
+/* Find an enabled index which matches this description. */
+
+static struct vlvIndex*
+vlv_find_search(backend *be, const Slapi_DN *base, int scope, const char *filter, const sort_spec* sort_control)
+{
+ return vlvSearch_findenabled(be,(struct vlvSearch *)be->vlvSearchList,base,scope,filter,sort_control);
+}
+
+
+/* Find a search which matches this name. Added read lock. */
+
+struct vlvIndex*
+vlv_find_searchname(const char * name, backend *be)
+{
+ struct vlvIndex *p=NULL;
+
+ PR_RWLock_Rlock(be->vlvSearchList_lock);
+ p=vlvSearch_findname((struct vlvSearch *)be->vlvSearchList,name);
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return p;
+}
+
+/* Find a search which matches this indexname. Added to read lock */
+
+struct vlvIndex*
+vlv_find_indexname(const char * name, backend *be)
+{
+
+ struct vlvIndex *p=NULL;
+
+ PR_RWLock_Rlock(be->vlvSearchList_lock);
+ p=vlvSearch_findindexname((struct vlvSearch *)be->vlvSearchList,name);
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return p;
+}
+
+
+/* Get a list of known VLV Indexes. Added read lock */
+
+char *
+vlv_getindexnames(backend *be)
+{
+ char *n=NULL;
+
+ PR_RWLock_Rlock(be->vlvSearchList_lock);
+ n=vlvSearch_getnames((struct vlvSearch *)be->vlvSearchList);
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return n;
+}
+
+/* Return the list of VLV indices to the import code. Added read lock */
+
+void
+vlv_getindices(IFP callback_fn,void *param, backend *be)
+{
+ /* Traverse the list, calling the import code's callback function */
+ struct vlvSearch* ps = NULL;
+
+ PR_RWLock_Rlock(be->vlvSearchList_lock);
+ ps = (struct vlvSearch *)be->vlvSearchList;
+ for(;ps!=NULL;ps= ps->vlv_next)
+ {
+ struct vlvIndex* pi= ps->vlv_index;
+ for(;pi!=NULL;pi= pi->vlv_next)
+ {
+ callback_fn(pi->vlv_attrinfo,param);
+ }
+ }
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+}
+
+/*
+ * Create a key for the entry in the vlv index.
+ *
+ * The key is a composite of a value from each sorted attribute.
+ *
+ * If a sorted attribute has many values, then the key is built
+ * with the attribute value with the lowest value.
+ *
+ * The primary sorted attribute value is followed by a 0x00 to
+ * ensure that short attribute values appear before longer ones.
+ *
+ * Many entries may have the same attribute values, which would
+ * generate the same composite key, so we append the EntryID
+ * to ensure the uniqueness of the key.
+ *
+ * Always creates a key. Never returns NULL.
+ */
+static struct vlv_key *
+vlv_create_key(struct vlvIndex* p, struct backentry* e)
+{
+ struct berval val, *lowest_value = NULL;
+ unsigned char char_min = 0x00;
+ unsigned char char_max = 0xFF;
+ struct vlv_key *key= vlv_key_new();
+ if(p->vlv_sortkey!=NULL)
+ {
+ /* Foreach sorted attribute... */
+ int sortattr= 0;
+ while(p->vlv_sortkey[sortattr]!=NULL)
+ {
+ Slapi_Attr* attr= attrlist_find(e->ep_entry->e_attrs, p->vlv_sortkey[sortattr]->sk_attrtype);
+ {
+ /*
+ * If there's a matching rule associated with the sorted
+ * attribute then use the indexer to mangle the attr values.
+ * This ensures that the international characters will
+ * collate in the correct order.
+ */
+
+ /* xxxPINAKI */
+ /* need to free some stuff! */
+ Slapi_Value **cvalue = NULL;
+ struct berval **value = NULL;
+ int free_value= 0;
+ if (attr != NULL && !valueset_isempty(&attr->a_present_values))
+ {
+ /* Sorted attribute found. */
+ int totalattrs;
+ if (p->vlv_sortkey[sortattr]->sk_matchruleoid==NULL)
+ {
+ /* No matching rule. Syntax Plugin mangles value. */
+ Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
+ slapi_call_syntax_values2keys_sv( p->vlv_syntax_plugin[sortattr], va, &cvalue, LDAP_FILTER_EQUALITY );
+ valuearray_get_bervalarray(cvalue,&value);
+
+ /* XXXSD need to free some more stuff */
+ {
+ int numval;
+ for (numval=0; cvalue&&cvalue[numval];numval++) {
+ slapi_value_free(&cvalue[numval]);
+ }
+ if (cvalue)
+ slapi_ch_free((void **)&cvalue);
+ }
+
+ free_value= 1;
+ }
+ else
+ {
+ /* Matching rule. Do the magic mangling. Plugin owns the memory. */
+ if(p->vlv_mrpb[sortattr]!=NULL)
+ {
+ /* xxxPINAKI */
+ struct berval **bval=NULL;
+ Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
+ valuearray_get_bervalarray(va,&bval);
+ matchrule_values_to_keys(p->vlv_mrpb[sortattr],bval,&value);
+ }
+ }
+ for(totalattrs=0;value[totalattrs]!=NULL;totalattrs++) {}; /* Total Number of Attributes */
+ if(totalattrs==1)
+ {
+ lowest_value= value[0];
+ }
+ else
+ {
+ lowest_value = attr_value_lowest(value, slapi_berval_cmp);
+ }
+ } /* end of if (attr != NULL && ...) */
+ if(p->vlv_sortkey[sortattr]->sk_reverseorder)
+ {
+ /*
+ * This attribute is reverse sorted, so we must
+ * invert the attribute value so that the keys
+ * will be in the correct order.
+ */
+ unsigned int i;
+ char *attributeValue = NULL;
+ /* Bug 605477 : Don't malloc 0 bytes */
+ if (attr != NULL && lowest_value->bv_len != 0) {
+ attributeValue = (char*)slapi_ch_malloc(lowest_value->bv_len);
+ for(i=0;i<lowest_value->bv_len;i++)
+ {
+ attributeValue[i]= UCHAR_MAX - ((char*)lowest_value->bv_val)[i];
+ }
+ val.bv_len= lowest_value->bv_len;
+ val.bv_val= (void*)attributeValue;
+ } else {
+ /* Reverse Sort: We use an attribute value of 0x00 when
+ * there is no attribute value or attrbute is absent
+ */
+ val.bv_val= (void*)&char_min;
+ val.bv_len= 1;
+ }
+ vlv_key_addattr(key,&val);
+ slapi_ch_free((void**)&attributeValue);
+ }
+ else
+ {
+ /*
+ * This attribute is forward sorted, so add the
+ * attribute value to the end of all the keys.
+ */
+
+ /* If the forward-sorted attribute is absent or has no
+ * value, we need to use the value of 0xFF.
+ */
+ if (attr != NULL && lowest_value->bv_len > 0) {
+ vlv_key_addattr(key,lowest_value);
+ } else {
+ val.bv_val = (void*)&char_max;
+ val.bv_len = 1;
+ vlv_key_addattr(key,&val);
+ }
+ }
+ if(sortattr==0)
+ {
+ /*
+ * If this is the first attribute (the typedown attribute)
+ * then it should be followed by a zero. This is to ensure
+ * that shorter attribute values appear before longer ones.
+ */
+ char zero = 0;
+ val.bv_len= 1;
+ val.bv_val= (void*)&zero;
+ vlv_key_addattr(key,&val);
+ }
+ if(free_value)
+ {
+ ber_bvecfree(value);
+ }
+ }
+ sortattr++;
+ }
+ }
+ {
+ /* Append the EntryID to the key to ensure uniqueness */
+ val.bv_len= sizeof(e->ep_id);
+ val.bv_val= (void*)&e->ep_id;
+ vlv_key_addattr(key,&val);
+ }
+ return key;
+}
+
+/*
+ * Insert or Delete the entry to or from the index
+ */
+
+static int
+do_vlv_update_index(back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct vlvIndex* pIndex, struct backentry* entry, int insert)
+{
+ backend *be;
+ int rc= 0;
+ DB *db = NULL;
+ DB_TXN *db_txn = NULL;
+ struct vlv_key *key = NULL;
+
+ slapi_pblock_get(pb, SLAPI_BACKEND, &be);
+
+ rc = dblayer_get_index_file(be, pIndex->vlv_attrinfo, &db, DBOPEN_CREATE);
+ if (rc != 0) {
+ if(rc != DB_LOCK_DEADLOCK)
+ LDAPDebug(LDAP_DEBUG_ANY, "VLV: can't get index file '%s' (err %d)\n",
+ pIndex->vlv_attrinfo->ai_type, rc, 0);
+ return rc;
+ }
+
+ key = vlv_create_key(pIndex,entry);
+ if (NULL != txn) {
+ db_txn = txn->back_txn_txn;
+ } else {
+ /* Very bad idea to do this outside of a transaction */
+ }
+
+ if (insert) {
+ DBT data = {0};
+ data.size = sizeof(entry->ep_id);
+ data.data = &entry->ep_id;
+ rc = db->put(db, db_txn, &key->key, &data, 0);
+ if (rc == 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "vlv_update_index: %s Insert %s ID=%lu\n",
+ pIndex->vlv_name, key->key.data, (u_long)entry->ep_id);
+ vlvIndex_increment_indexlength(pIndex, db, txn);
+ } else if (rc == DB_RUNRECOVERY) {
+ ldbm_nasty(pIndex->vlv_name,77,rc);
+ } else if(rc != DB_LOCK_DEADLOCK) {
+ /* jcm: This error is valid if the key already exists.
+ * Identical multi valued attr values could do this. */
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "vlv_update_index: %s Insert %s ID=%lu FAILED\n",
+ pIndex->vlv_name, key->key.data, (u_long)entry->ep_id);
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "vlv_update_index: %s Delete %s\n",
+ pIndex->vlv_name, key->key.data, 0);
+ rc = db->del(db, db_txn, &key->key, 0);
+ if (rc == 0) {
+ vlvIndex_decrement_indexlength(pIndex, db, txn);
+ } else if (rc == DB_RUNRECOVERY) {
+ ldbm_nasty(pIndex->vlv_name,78,rc);
+ } else if (rc != DB_LOCK_DEADLOCK) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "vlv_update_index: %s Delete %s FAILED\n",
+ pIndex->vlv_name, key->key.data, 0);
+ }
+ }
+
+ vlv_key_delete(&key);
+ dblayer_release_index_file(be, pIndex->vlv_attrinfo, db);
+ return rc;
+}
+
+/*
+ * Given an entry modification check if a VLV index needs to be updated.
+ */
+
+int
+vlv_update_index(struct vlvIndex* p, back_txn *txn, struct ldbminfo *li, Slapi_PBlock *pb, struct backentry* oldEntry, struct backentry* newEntry)
+{
+ int return_value=0;
+ /* Check if the old entry is in this VLV index */
+ if(oldEntry!=NULL)
+ {
+ if(slapi_sdn_scope_test(backentry_get_sdn(oldEntry),vlvIndex_getBase(p),vlvIndex_getScope(p)))
+ {
+ if(slapi_filter_test( pb, oldEntry->ep_entry, vlvIndex_getFilter(p), 0 /* No ACL Check */) == 0 )
+ {
+ /* Remove the entry from the index */
+ return_value=do_vlv_update_index(txn, li, pb, p, oldEntry, 0 /* Delete Key */);
+ }
+ }
+ }
+ /* Check if the new entry should be in the VLV index */
+ if(newEntry!=NULL)
+ {
+ if(slapi_sdn_scope_test(backentry_get_sdn(newEntry),vlvIndex_getBase(p),vlvIndex_getScope(p)))
+ {
+ if(slapi_filter_test( pb, newEntry->ep_entry, vlvIndex_getFilter(p), 0 /* No ACL Check */) == 0 )
+ {
+ /* Add the entry to the index */
+ return_value=do_vlv_update_index(txn, li, pb, p, newEntry, 1 /* Insert Key */);
+ }
+ }
+ }
+ return return_value;
+}
+
+/*
+ * Given an entry modification check if a VLV index needs to be updated.
+ *
+ * This is called for every modifying operation, so it must be very efficient.
+ *
+ * We need to know if we're adding, deleting, or modifying
+ * because we could be leaving and/or joining an index
+ *
+ * ADD: oldEntry==NULL && newEntry!=NULL
+ * DEL: oldEntry!=NULL && newEntry==NULL
+ * MOD: oldEntry!=NULL && newEntry!=NULL
+ *
+ * JCM: If only non-sorted attributes are changed, then the indexes don't need updating.
+ * JCM: Detecting this fact, given multi-valued atribibutes, might be tricky...
+ * Added write lock
+*/
+
+int
+vlv_update_all_indexes(back_txn *txn, backend *be, Slapi_PBlock *pb, struct backentry* oldEntry, struct backentry* newEntry)
+{
+ int return_value= LDAP_SUCCESS;
+ struct vlvSearch* ps=NULL;
+ struct ldbminfo *li = ((ldbm_instance *)be->be_instance_info)->inst_li;
+
+ PR_RWLock_Wlock(be->vlvSearchList_lock);
+ ps = (struct vlvSearch *)be->vlvSearchList;
+ for(;ps!=NULL;ps= ps->vlv_next)
+ {
+ struct vlvIndex* pi= ps->vlv_index;
+ for (return_value = LDAP_SUCCESS; return_value == LDAP_SUCCESS && pi!=NULL; pi=pi->vlv_next)
+ return_value=vlv_update_index(pi, txn, li, pb, oldEntry, newEntry);
+ }
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return return_value;
+}
+
+/*
+ * Determine the range of record numbers to return.
+ * Prevent an underrun, or overrun.
+ */
+ /* jcm: Should we make sure that start < stop */
+
+static void
+determine_result_range(const struct vlv_request *vlv_request_control, PRUint32 index, PRUint32 length, PRUint32* pstart, PRUint32 *pstop)
+{
+ if (vlv_request_control == NULL)
+ {
+ *pstart= 0;
+ if (0 == length) /* 609377: index size could be 0 */
+ {
+ *pstop= 0;
+ }
+ else
+ {
+ *pstop= length - 1;
+ }
+ }
+ else
+ {
+ /* Make sure we don't run off the start */
+ if(index < vlv_request_control->beforeCount)
+ {
+ *pstart= 0;
+ }
+ else
+ {
+ *pstart= index - vlv_request_control->beforeCount;
+ }
+ /* Make sure we don't run off the end */
+ if(ULONG_MAX - index > vlv_request_control->afterCount)
+ {
+ *pstop= index + vlv_request_control->afterCount;
+ }
+ else
+ {
+ *pstop= ULONG_MAX;
+ }
+ /* Client tried to index off the end */
+ if (0 == length) /* 609377: index size could be 0 */
+ {
+ *pstop= 0;
+ }
+ else if(*pstop > length - 1)
+ {
+ *pstop= length - 1;
+ }
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_determine_result_range: Result Range %lu-%lu\n", *pstart, *pstop, 0 );
+}
+
+/*
+ * This is a utility function to pass the client
+ * supplied attribute value through the appropriate
+ * matching rule indexer.
+ *
+ * It allocates a berval vector which the caller
+ * must free.
+ */
+
+static struct berval **
+vlv_create_matching_rule_value( Slapi_PBlock* pb, struct berval *original_value)
+{
+ struct berval **value= NULL;
+ if(pb!=NULL)
+ {
+ struct berval **outvalue = NULL;
+ struct berval *invalue[2];
+ invalue[0]= original_value; /* jcm: cast away const */
+ invalue[1]= NULL;
+ /* The plugin owns the memory it returns in outvalue */
+ matchrule_values_to_keys(pb,invalue,&outvalue);
+ if(outvalue!=NULL)
+ {
+ value= slapi_ch_bvecdup(outvalue);
+ }
+ }
+ if(value==NULL)
+ {
+ struct berval *outvalue[2];
+ outvalue[0]= original_value; /* jcm: cast away const */
+ outvalue[1]= NULL;
+ value= slapi_ch_bvecdup(outvalue);
+ }
+ return value;
+}
+
+
+/*
+ * Find the record number in a VLV index for a given attribute value.
+ * The returned index is counted from zero.
+ */
+
+static PRUint32
+vlv_build_candidate_list_byvalue( struct vlvIndex* p, DBC *dbc, PRUint32 length, const struct vlv_request *vlv_request_control)
+{
+ PRUint32 si= 0; /* The Selected Index */
+ int err= 0;
+ DBT key= {0};
+ DBT data= {0};
+ /*
+ * If the primary sorted attribute has an associated
+ * matching rule, then we must mangle the typedown
+ * value.
+ */
+ struct berval **typedown_value= NULL;
+ struct berval *invalue[2];
+ invalue[0]= (struct berval *)&vlv_request_control->value; /* jcm: cast away const */
+ invalue[1]= NULL;
+ if (p->vlv_sortkey[0]->sk_matchruleoid==NULL)
+ {
+ slapi_call_syntax_values2keys(p->vlv_syntax_plugin[0],invalue,&typedown_value,LDAP_FILTER_EQUALITY); /* JCM SLOW FUNCTION */
+ }
+ else
+ {
+ typedown_value= vlv_create_matching_rule_value(p->vlv_mrpb[0],(struct berval *)&vlv_request_control->value); /* jcm: cast away const */
+ }
+ if(p->vlv_sortkey[0]->sk_reverseorder)
+ {
+ /*
+ * The primary attribute is reverse sorted, so we must
+ * invert the typedown value in order to match the key.
+ */
+ unsigned int i;
+ for(i=0;i<(*typedown_value)->bv_len;i++)
+ {
+ ((char*)(*typedown_value)->bv_val)[i]= UCHAR_MAX - ((char*)(*typedown_value)->bv_val)[i];
+ }
+ }
+
+ key.flags= DB_DBT_MALLOC;
+ key.size= typedown_value[0]->bv_len;
+ key.data= typedown_value[0]->bv_val;
+ data.flags= DB_DBT_MALLOC;
+ err= dbc->c_get(dbc,&key,&data,DB_SET_RANGE);
+ if(err==0)
+ {
+ free(data.data);
+ err= dbc->c_get(dbc,&key,&data,DB_GET_RECNO);
+ if(err==0)
+ {
+ si= *((db_recno_t*)data.data);
+ /* Records are numbered from one. */
+ si--;
+ free(data.data);
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_build_candidate_list_byvalue: Found. Index=%lu\n",si,0,0);
+ }
+ else
+ {
+ /* Couldn't get the record number for the record we found. */
+ }
+ }
+ else
+ {
+ /* Couldn't find an entry which matches the value,
+ * so return the last entry
+ * (609377) when the index file is empty, there is no "last entry".
+ */
+ if (0 == length)
+ {
+ si = 0;
+ }
+ else
+ {
+ si = length - 1;
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_build_candidate_list_byvalue: Not Found. Index=%lu\n",si,0,0);
+ }
+ ber_bvecfree((struct berval**)typedown_value);
+ return si;
+}
+
+static int
+vlv_idl_sort_cmp(const void *x, const void *y)
+{
+ return *(ID *)x - *(ID *)y;
+}
+
+/* build a candidate list (IDL) from a VLV index, given the starting index
+ * and the ending index (as an inclusive list).
+ * returns 0 on success, or an LDAP error code.
+ */
+int vlv_build_idl(PRUint32 start, PRUint32 stop, DB *db, DBC *dbc,
+ IDList **candidates, int dosort)
+{
+ IDList *idl = NULL;
+ int err;
+ PRUint32 recno;
+ DBT key = {0};
+ DBT data = {0};
+ ID id;
+
+ idl = idl_alloc(stop-start+1);
+ if (!idl) {
+ /* out of memory :( */
+ return LDAP_OPERATIONS_ERROR;
+ }
+ recno = start+1;
+ key.size = sizeof(recno);
+ key.data = &recno;
+ key.flags = DB_DBT_MALLOC;
+ data.ulen = sizeof(ID);
+ data.data = &id;
+ data.flags = DB_DBT_USERMEM; /* don't alloc */
+ err = dbc->c_get(dbc, &key, &data, DB_SET_RECNO);
+ while ((err == 0) && (recno <= stop+1)) {
+ if (key.data != &recno)
+ free(key.data);
+ idl_append(idl, *(ID *)data.data);
+ if (++recno <= stop+1) {
+ err = dbc->c_get(dbc, &key, &data, DB_NEXT);
+ }
+ }
+ if (err != 0) {
+ /* some db error...? */
+ LDAPDebug(LDAP_DEBUG_ANY, "vlv_build_idl: can't follow db cursor "
+ "(err %d)\n", err, 0, 0);
+ if (err == ENOMEM)
+ LDAPDebug(LDAP_DEBUG_ANY, " nomem: wants %d key, %d data\n",
+ key.size, data.size, 0);
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* success! */
+ if (idl) {
+ if (candidates)
+ {
+ if (dosort)
+ {
+ qsort((void *)&idl->b_ids[0], idl->b_nids,
+ (size_t)sizeof(ID), vlv_idl_sort_cmp);
+ }
+ *candidates = idl;
+ }
+ else
+ idl_free(idl); /* ??? */
+ }
+ return LDAP_SUCCESS;
+}
+
+
+/* This function does vlv_access, searching and building list all while holding read lock
+
+ 1. vlv_find_search fails, set:
+ unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
+ slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
+ return FIND_SEARCH FAILED
+
+ 2. vlvIndex_accessallowed fails
+ return VLV_LDBM_ACCESS_DENIED
+
+ 3. vlv_build_candidate_list fails:
+ return VLV_BLD_LIST_FAILED
+
+ 4. return LDAP_SUCCESS
+*/
+
+int
+vlv_search_build_candidate_list(Slapi_PBlock *pb, const Slapi_DN *base, int *vlv_rc, const sort_spec* sort_control,
+ const struct vlv_request *vlv_request_control,
+ IDList** candidates, struct vlv_response *vlv_response_control) {
+ struct vlvIndex* pi = NULL;
+ backend *be;
+ int scope, rc=LDAP_SUCCESS;
+ char *fstr;
+
+ slapi_pblock_get( pb, SLAPI_BACKEND, &be );
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
+ slapi_pblock_get( pb, SLAPI_SEARCH_STRFILTER, &fstr );
+ PR_RWLock_Rlock(be->vlvSearchList_lock);
+ if((pi=vlv_find_search(be, base, scope, fstr, sort_control)) == NULL) {
+ unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
+ slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
+ rc = VLV_FIND_SEARCH_FAILED;
+ } else if((*vlv_rc=vlvIndex_accessallowed(pi, pb)) != LDAP_SUCCESS) {
+ rc = VLV_ACCESS_DENIED;
+ } else if ((*vlv_rc=vlv_build_candidate_list(be,pi,vlv_request_control,candidates,vlv_response_control)) != LDAP_SUCCESS) {
+ rc = VLV_BLD_LIST_FAILED;
+ vlv_response_control->result=*vlv_rc;
+ }
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return rc;
+}
+
+/*
+ * Given the SORT and VLV controls return a candidate list from the
+ * pre-computed index file.
+ *
+ * Returns:
+ * success (0),
+ * operationsError (1),
+ * unwillingToPerform (53),
+ * timeLimitExceeded (3),
+ * adminLimitExceeded (11),
+ * indexRangeError (61),
+ * other (80)
+ */
+
+
+static int
+vlv_build_candidate_list( backend *be, struct vlvIndex* p, const struct vlv_request *vlv_request_control, IDList** candidates, struct vlv_response *vlv_response_control)
+{
+ int return_value = LDAP_SUCCESS;
+ DB *db = NULL;
+ DBC *dbc = NULL;
+ int rc, err;
+ PRUint32 si = 0; /* The Selected Index */
+ PRUint32 length;
+ int do_trim= 1;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "=> vlv_build_candidate_list: %s %s Using VLV Index %s\n",
+ slapi_sdn_get_dn(vlvIndex_getBase(p)), p->vlv_search->vlv_filter,
+ vlvIndex_getName(p));
+ if (!vlvIndex_online(p)) {
+ return -1;
+ }
+ rc = dblayer_get_index_file(be, p->vlv_attrinfo, &db, 0);
+ if (rc != 0) {
+ /* shouldn't happen */
+ LDAPDebug(LDAP_DEBUG_ANY, "VLV: can't get index file '%s' (err %d)\n",
+ p->vlv_attrinfo->ai_type, rc, 0);
+ return -1;
+ }
+
+ err = db->cursor(db, 0 /* txn */, &dbc, 0);
+ if (err != 0) {
+ /* shouldn't happen */
+ LDAPDebug(LDAP_DEBUG_ANY, "VLV: couldn't get cursor (err %d)\n",
+ rc, 0, 0);
+ return -1;
+ }
+
+ length = vlvIndex_get_indexlength(p, db, 0 /* txn */);
+
+ /* Increment the usage counter */
+ vlvIndex_incrementUsage(p);
+
+ if (vlv_request_control)
+ {
+ switch(vlv_request_control->tag) {
+ case 0: /* byIndex */
+ si = vlv_trim_candidates_byindex(length, vlv_request_control);
+ break;
+ case 1: /* byValue */
+ si = vlv_build_candidate_list_byvalue(p, dbc, length,
+ vlv_request_control);
+ if (si==length) {
+ do_trim = 0;
+ *candidates = idl_alloc(0);
+ }
+ break;
+ default:
+ /* Some wierd tag value. Shouldn't ever happen */
+ if (ISLEGACY(be)) {
+ return_value = LDAP_OPERATIONS_ERROR;
+ } else {
+ return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
+ }
+ break;
+ }
+
+ /* Tell the client what the real content count is.
+ * Client counts from 1. */
+ vlv_response_control->targetPosition = si + 1;
+ vlv_response_control->contentCount = length;
+ vlv_response_control->result = return_value;
+ }
+
+ if ((return_value == LDAP_SUCCESS) && do_trim) {
+ /* Work out the range of records to return */
+ PRUint32 start, stop;
+ determine_result_range(vlv_request_control, si, length, &start, &stop);
+
+ /* fetch the idl */
+ return_value = vlv_build_idl(start, stop, db, dbc, candidates, 0);
+ }
+ dbc->c_close(dbc);
+
+ dblayer_release_index_file( be, p->vlv_attrinfo, db );
+ return return_value;
+}
+
+/*
+ * Given a candidate list and a filter specification, filter the candidate list
+ *
+ * Returns:
+ * success (0),
+ * operationsError (1),
+ * unwillingToPerform (53),
+ * timeLimitExceeded (3),
+ * adminLimitExceeded (11),
+ * indexRangeError (61),
+ * other (80)
+ */
+int
+vlv_filter_candidates(backend *be, Slapi_PBlock *pb, const IDList *candidates, const Slapi_DN *base, int scope, Slapi_Filter *filter, IDList** filteredCandidates, int lookthrough_limit, time_t time_up)
+{
+ IDList* resultIdl= NULL;
+ int return_value = LDAP_SUCCESS;
+
+ /* Refuse to filter a non-existent IDlist */
+ if (NULL == candidates)
+ {
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> vlv_filter_candidates: Filtering %lu Candidates\n",(u_long)candidates->b_nids, 0, 0 );
+
+ if (0 == return_value && candidates->b_nids>0)
+ {
+ /* jcm: Could be an idlist function. create_filtered_idlist */
+ /* Iterate over the ID List applying the filter */
+ int lookedat= 0;
+ int done= 0;
+ int counter= 0;
+ ID id = NOID;
+ idl_iterator current = idl_iterator_init(candidates);
+ resultIdl= idl_alloc(candidates->b_nids);
+ do
+ {
+ id = idl_iterator_dereference_increment(&current, candidates);
+ if ( id != NOID )
+ {
+ int err= 0;
+ struct backentry *e= NULL;
+ e = id2entry( be, id, NULL, &err );
+ if ( e == NULL )
+ {
+ /*
+ * The ALLIDS ID List contains IDs for which there is no entry.
+ * This is because the entries have been deleted. An error in
+ * this case is ok.
+ */
+ if(!(ALLIDS(candidates) && err==DB_NOTFOUND))
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "vlv_filter_candidates: Candidate %lu not found err=%d\n", (u_long)id, err, 0 );
+ }
+ }
+ else
+ {
+ lookedat++;
+ if(slapi_sdn_scope_test(backentry_get_sdn(e),base,scope))
+ {
+ if ( slapi_filter_test( pb, e->ep_entry, filter, 0 /* No ACL Check */) == 0 )
+ {
+ /* The entry passed the filter test, add the id to the list */
+ LDAPDebug( LDAP_DEBUG_TRACE, "vlv_filter_candidates: Candidate %lu Passed Filter\n", (u_long)id, 0, 0 );
+ idl_append(resultIdl,id);
+ }
+ }
+ cache_return(&(((ldbm_instance *) be->be_instance_info)->inst_cache), &e);
+ }
+ }
+
+ done= slapi_op_abandoned(pb);
+
+ /* Check to see if our journey is really necessary */
+ if ( counter++ % 10 == 0 )
+ {
+ /* check time limit */
+ time_t curtime = current_time();
+ if ( time_up != -1 && curtime > time_up )
+ {
+ return_value= LDAP_TIMELIMIT_EXCEEDED;
+ done= 1;
+ }
+ /* check lookthrough limit */
+ if ( lookthrough_limit != -1 && lookedat>lookthrough_limit )
+ {
+ return_value= LDAP_ADMINLIMIT_EXCEEDED;
+ done= 1;
+ }
+ }
+ } while (!done && id!=NOID);
+ }
+ if(filteredCandidates!=NULL)
+ *filteredCandidates= resultIdl;
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_filter_candidates: Filtering done\n",0, 0, 0 );
+
+ return return_value;
+}
+
+/*
+ * Given a candidate list and a virtual list view specification, trim the candidate list
+ *
+ * Returns:
+ * success (0),
+ * operationsError (1),
+ * unwillingToPerform (53),
+ * timeLimitExceeded (3),
+ * adminLimitExceeded (11),
+ * indexRangeError (61),
+ * other (80)
+ */
+int
+vlv_trim_candidates(backend *be, const IDList *candidates, const sort_spec* sort_control, const struct vlv_request *vlv_request_control, IDList** trimmedCandidates,struct vlv_response *vlv_response_control)
+{
+ IDList* resultIdl= NULL;
+ int return_value= LDAP_SUCCESS;
+ PRUint32 si= 0; /* The Selected Index */
+ int do_trim= 1;
+
+ /* Refuse to trim a non-existent IDlist */
+ if (NULL == candidates || candidates->b_nids==0)
+ {
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ switch(vlv_request_control->tag)
+ {
+ case 0: /* byIndex */
+ si= vlv_trim_candidates_byindex(candidates->b_nids, vlv_request_control);
+ break;
+ case 1: /* byValue */
+ si= vlv_trim_candidates_byvalue(be, candidates, sort_control, vlv_request_control);
+ /* Don't bother sending results if the attribute value wasn't found */
+ if(si==candidates->b_nids)
+ {
+ do_trim= 0;
+ resultIdl= idl_alloc(0);
+ }
+ break;
+ default:
+ /* Some wierd tag value. Shouldn't ever happen */
+ if (ISLEGACY(be)) {
+ return_value = LDAP_OPERATIONS_ERROR;
+ } else {
+ return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
+ }
+ break;
+ }
+
+ /* Tell the client what the real content count is. Clients count from 1 */
+ vlv_response_control->targetPosition= si + 1;
+ vlv_response_control->contentCount= candidates->b_nids;
+
+ if(return_value==LDAP_SUCCESS && do_trim)
+ {
+ /* Work out the range of records to return */
+ PRUint32 start, stop;
+ determine_result_range(vlv_request_control,si,candidates->b_nids,&start,&stop);
+ /* Build a new list containing the (start..stop) range */
+ /* JCM: Should really be a function in idlist.c to copy a range */
+ resultIdl= idl_alloc(stop-start+1);
+ {
+ PRUint32 cursor= 0;
+ for(cursor=start;cursor<=stop;cursor++)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "vlv_trim_candidates: Include ID %lu\n",(u_long)candidates->b_ids[cursor], 0, 0 );
+ idl_append(resultIdl,candidates->b_ids[cursor]);
+ }
+ }
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_trim_candidates: Trimmed list contains %lu entries.\n",(u_long)resultIdl->b_nids, 0, 0 );
+ if(trimmedCandidates!=NULL)
+ *trimmedCandidates= resultIdl;
+ return return_value;
+}
+
+/*
+ * Work out the Selected Index given the length of the candidate list
+ * and the request control from the client.
+ *
+ * If the client sends Index==0 we behave as if I=1
+ * If the client sends Index==Size==1 we behave as if I=1, S=0
+ */
+static PRUint32
+vlv_trim_candidates_byindex(PRUint32 length, const struct vlv_request *vlv_request_control)
+{
+ PRUint32 si= 0; /* The Selected Index */
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> vlv_trim_candidates_byindex: length=%lu index=%lu size=%lu\n",length, vlv_request_control->index, vlv_request_control->contentCount );
+ if(vlv_request_control->index==0)
+ {
+ /* Always select the first entry in the list */
+ si= 0;
+ }
+ else
+ {
+ if(vlv_request_control->contentCount==0)
+ {
+ /* The client has no idea what the content count might be. */
+ /* Can't scale the index, so use as is */
+ si= vlv_request_control->index;
+ if (0 == length) /* 609377: index size could be 0 */
+ {
+ if (si > 0)
+ {
+ si = length;
+ }
+ }
+ else if(si > length - 1)
+ {
+ si= length - 1;
+ }
+ }
+ else
+ {
+ if(vlv_request_control->index>=vlv_request_control->contentCount)
+ {
+ /* Always select the last entry in the list */
+ if (0 == length) /* 609377: index size could be 0 */
+ {
+ si = 0;
+ }
+ else
+ {
+ si= length-1;
+ }
+ }
+ else
+ {
+ /* The three components of this expression are (PRUint32) and may well have a value up to ULONG_MAX */
+ /* SelectedIndex = ActualContentCount * ( ClientIndex / ClientContentCount ) */
+ si= ((PRUint32)((double)length * (double)(vlv_request_control->index / (double)vlv_request_control->contentCount )));
+ }
+ }
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_trim_candidates_byindex: Selected Index %lu\n",si, 0, 0 );
+ return si;
+}
+
+/*
+ * Iterate over the Candidate ID List looking for an entry >= the provided attribute value.
+ */
+static PRUint32
+vlv_trim_candidates_byvalue(backend *be, const IDList *candidates, const sort_spec* sort_control, const struct vlv_request *vlv_request_control)
+{
+ PRUint32 si= 0; /* The Selected Index */
+ PRUint32 low= 0;
+ PRUint32 high= candidates->b_nids-1;
+ PRUint32 current= 0;
+ ID id = NOID;
+ int found= 0;
+ struct berval **typedown_value;
+
+ /* For non-matchrule indexing */
+ value_compare_fn_type compare_fn= NULL;
+
+ /*
+ * If the primary sorted attribute has an associated
+ * matching rule, then we must mangle the typedown
+ * value.
+ */
+ if (sort_control->matchrule==NULL)
+ {
+ void *pi= NULL;
+ if(slapi_attr_type2plugin(sort_control->type, &pi)==0)
+ {
+ struct berval *invalue[2];
+ invalue[0]= (struct berval *)&vlv_request_control->value; /* jcm: cast away const */
+ invalue[1]= NULL;
+ slapi_call_syntax_values2keys(pi,invalue,&typedown_value,LDAP_FILTER_EQUALITY); /* JCM SLOW FUNCTION */
+ plugin_call_syntax_get_compare_fn( pi, &compare_fn );
+ if (compare_fn == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "vlv_trim_candidates_byvalue: "
+ "attempt to compare an unordered attribute",
+ 0, 0, 0);
+ compare_fn = slapi_berval_cmp;
+ }
+ }
+ }
+ else
+ {
+ typedown_value= vlv_create_matching_rule_value(sort_control->mr_pb,(struct berval *)&vlv_request_control->value);
+ compare_fn= slapi_berval_cmp;
+ }
+ /*
+ * Perform a binary search over the candidate list
+ */
+ do {
+ int err= 0;
+ struct backentry *e= NULL;
+ if(!sort_control->order)
+ {
+ current = (low + high)/2;
+ }
+ else
+ {
+ current = (1 + low + high)/2;
+ }
+ id= candidates->b_ids[current];
+ e = id2entry( be, id, NULL, &err );
+ if ( e == NULL )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "vlv_trim_candidates_byvalue: Candidate ID %lu not found err=%d\n", (u_long)id, err, 0 );
+ }
+ else
+ {
+ /* Check if vlv_request_control->value is greater than or equal to the primary key. */
+ int match;
+ Slapi_Attr *attr;
+ if ( (NULL != compare_fn) && (slapi_entry_attr_find( e->ep_entry, sort_control->type, &attr ) == 0) )
+ {
+ /*
+ * If there's a matching rule associated with the primary
+ * attribute then use the indexer to mangle the attr values.
+ */
+ Slapi_Value **csn_value = valueset_get_valuearray(&attr->a_present_values);
+ struct berval **entry_value = /* xxxPINAKI needs modification attr->a_vals */NULL;
+ if(sort_control->mr_pb!=NULL)
+ {
+ struct berval **tmp_entry_value = NULL;
+
+ valuearray_get_bervalarray(csn_value,&tmp_entry_value);
+ /* Matching rule. Do the magic mangling. Plugin owns the memory. */
+ matchrule_values_to_keys(sort_control->mr_pb,/* xxxPINAKI needs modification attr->a_vals */tmp_entry_value,&entry_value);
+ }
+ else
+ {
+ valuearray_get_bervalarray(csn_value,&entry_value);
+ }
+ if(!sort_control->order)
+ {
+ match= sort_attr_compare(entry_value, (struct berval**)typedown_value, compare_fn);
+ }
+ else
+ {
+ match= sort_attr_compare((struct berval**)typedown_value, entry_value, compare_fn);
+ }
+ }
+ else
+ {
+ /*
+ * This attribute doesn't exist on this entry.
+ */
+ if(sort_control->order)
+ {
+ match= 1;
+ }
+ else
+ {
+ match= 0;
+ }
+ }
+ if(!sort_control->order)
+ {
+ if (match>=0)
+ {
+ high= current;
+ }
+ else
+ {
+ low= current+1;
+ }
+ }
+ else
+ {
+ if (match>=0)
+ {
+ high= current-1;
+ }
+ else
+ {
+ low= current;
+ }
+ }
+ if (low>=high)
+ {
+ found= 1;
+ si= high;
+ if(si==candidates->b_nids && !match)
+ {
+ /* Couldn't find an entry which matches the value, so return contentCount */
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_trim_candidates_byvalue: Not Found. Index %lu\n",si, 0, 0 );
+ si= candidates->b_nids;
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_trim_candidates_byvalue: Found. Index %lu\n",si, 0, 0 );
+ }
+ }
+ }
+ } while (!found);
+ ber_bvecfree((struct berval**)typedown_value);
+ return si;
+}
+
+/*
+ * Encode the VLV RESPONSE control.
+ *
+ * Create a virtual list view response control,
+ * and add it to the PBlock to be returned to the client.
+ *
+ * Returns:
+ * success ( 0 )
+ * operationsError (1),
+ */
+int
+vlv_make_response_control (Slapi_PBlock *pb, const struct vlv_response* vlvp)
+{
+ BerElement *ber= NULL;
+ struct berval *bvp = NULL;
+ int rc = -1;
+
+ /*
+ VirtualListViewResponse ::= SEQUENCE {
+ targetPosition INTEGER (0 .. maxInt),
+ contentCount INTEGER (0 .. maxInt),
+ virtualListViewResult ENUMERATED {
+ success (0),
+ operationsError (1),
+ unwillingToPerform (53),
+ insufficientAccessRights (50),
+ busy (51),
+ timeLimitExceeded (3),
+ adminLimitExceeded (11),
+ sortControlMissing (60),
+ indexRangeError (61),
+ other (80) } }
+ */
+
+ if ( ( ber = ber_alloc()) == NULL )
+ {
+ return rc;
+ }
+
+ rc = ber_printf( ber, "{iie}", vlvp->targetPosition, vlvp->contentCount, vlvp->result );
+ if ( rc != -1 )
+ {
+ rc = ber_flatten( ber, &bvp );
+ }
+
+ ber_free( ber, 1 );
+
+ if ( rc != -1 )
+ {
+ LDAPControl new_ctrl = {0};
+ new_ctrl.ldctl_oid = LDAP_CONTROL_VLVRESPONSE;
+ new_ctrl.ldctl_value = *bvp;
+ new_ctrl.ldctl_iscritical = 1;
+ rc= slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, &new_ctrl );
+ ber_bvfree(bvp);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= vlv_make_response_control: Index=%lu Size=%lu Result=%lu\n", vlvp->targetPosition, vlvp->contentCount, vlvp->result );
+
+ return (rc==-1?LDAP_OPERATIONS_ERROR:LDAP_SUCCESS);
+}
+
+/*
+ * Generate a logging string for the vlv request and response
+ */
+void vlv_print_access_log(Slapi_PBlock *pb,struct vlv_request* vlvi, struct vlv_response *vlvo)
+{
+#define VLV_LOG_BS (21*6 + 4 + 5) /* space for 20-digit values for all parameters + 'VLV ' + status */
+ char stack_buffer[VLV_LOG_BS];
+ char *buffer = stack_buffer;
+ char *p;
+
+ if (vlvi->value.bv_len > 20) {
+ buffer = slapi_ch_malloc(VLV_LOG_BS + vlvi->value.bv_len);
+ }
+ p = buffer;
+ p+= sprintf(p,"VLV ");
+ if (0 == vlvi->tag) {
+ /* By Index case */
+ p+= sprintf(p,"%ld:%ld:%ld:%ld",
+ vlvi->beforeCount ,
+ vlvi->afterCount ,
+ vlvi->index ,
+ vlvi->contentCount
+ );
+ } else {
+ /* By value case */
+#define VLV_LOG_SS 32
+ char stack_string[VLV_LOG_SS];
+ char *string = stack_string;
+
+ if (vlvi->value.bv_len >= VLV_LOG_SS) {
+ string = slapi_ch_malloc(vlvi->value.bv_len+1);
+ }
+ strncpy(string,vlvi->value.bv_val,vlvi->value.bv_len);
+ string[vlvi->value.bv_len] = '\0';
+ p += sprintf(p,"%ld:%ld:%s",
+ vlvi->beforeCount ,
+ vlvi->afterCount ,
+ string
+ );
+ if (string != stack_string) {
+ slapi_ch_free( (void**)&string);
+ }
+ }
+ /* Now the response info */
+ p += sprintf(p," %ld:%ld (%ld)",
+ vlvo->targetPosition ,
+ vlvo->contentCount,
+ vlvo->result
+ );
+
+
+ ldbm_log_access_message(pb,buffer);
+
+ if (buffer != stack_buffer) {
+ slapi_ch_free( (void**)&buffer);
+ }
+}
+
+/*
+ * Decode the VLV REQUEST control.
+ *
+ * If the client sends Index==0 we behave as if I=1
+ *
+ * Returns:
+ * success (0),
+ * operationsError (1),
+ *
+ */
+int
+vlv_parse_request_control( backend *be, struct berval *vlv_spec_ber,struct vlv_request* vlvp)
+{
+ /* This control looks like this :
+
+ VirtualListViewRequest ::= SEQUENCE {
+ beforeCount INTEGER (0 .. maxInt),
+ afterCount INTEGER (0 .. maxInt),
+ CHOICE {
+ byIndex [0] SEQUENCE {
+ index INTEGER (0 .. maxInt),
+ contentCount INTEGER (0 .. maxInt) }
+ greaterThanOrEqual [1] assertionValue }
+ */
+ BerElement *ber = NULL;
+ int return_value = LDAP_SUCCESS;
+ PRUint32 rc= 0;
+ long long_beforeCount;
+ long long_afterCount;
+ long long_index;
+ long long_contentCount;
+
+ vlvp->value.bv_len = 0;
+ vlvp->value.bv_val = NULL;
+
+ ber = ber_init(vlv_spec_ber);
+ rc = ber_scanf(ber,"{ii",&long_beforeCount,&long_afterCount);
+ vlvp->beforeCount = long_beforeCount;
+ vlvp->afterCount = long_afterCount;
+ if (LBER_ERROR == rc)
+ {
+ return_value= LDAP_OPERATIONS_ERROR;
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "vlv_parse_request_control: Before=%lu After=%lu\n", vlvp->beforeCount, vlvp->afterCount, 0 );
+ rc = ber_scanf(ber,"t",&vlvp->tag);
+ switch(vlvp->tag)
+ {
+ case LDAP_TAG_VLV_BY_INDEX:
+ /* byIndex */
+ vlvp->tag= 0;
+ rc = ber_scanf(ber,"{ii}}",&long_index,&long_contentCount);
+ vlvp->index = long_index;
+ vlvp->contentCount = long_contentCount;
+ if (LBER_ERROR == rc)
+ {
+ if (ISLEGACY(be)) {
+ return_value = LDAP_OPERATIONS_ERROR;
+ } else {
+ return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
+ }
+ }
+ else
+ {
+ /* Client Counts from 1. */
+ if(vlvp->index!=0)
+ {
+ vlvp->index--;
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "vlv_parse_request_control: Index=%lu Content=%lu\n", vlvp->index, vlvp->contentCount, 0 );
+ }
+ break;
+ case LDAP_TAG_VLV_BY_VALUE:
+ /* byValue */
+ vlvp->tag= 1;
+ rc = ber_scanf(ber,"o}",&vlvp->value);
+ if (LBER_ERROR == rc)
+ {
+ if (ISLEGACY(be)) {
+ return_value = LDAP_OPERATIONS_ERROR;
+ } else {
+ return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
+ }
+ }
+ {
+ /* jcm: isn't there a utility fn to do this? */
+ char *p= slapi_ch_malloc(vlvp->value.bv_len+1);
+ strncpy(p,vlvp->value.bv_val,vlvp->value.bv_len);
+ p[vlvp->value.bv_len]= '\0';
+ LDAPDebug( LDAP_DEBUG_TRACE, "vlv_parse_request_control: Value=%s\n", p, 0, 0 );
+ slapi_ch_free( (void**)&p);
+ }
+ break;
+ default:
+ if (ISLEGACY(be)) {
+ return_value = LDAP_OPERATIONS_ERROR;
+ } else {
+ return_value = LDAP_VIRTUAL_LIST_VIEW_ERROR;
+ }
+ }
+ }
+
+ /* the ber encoding is no longer needed */
+ ber_free(ber,1);
+
+ return return_value;
+}
+
+/* given a slapi_filter, check if there's a vlv index that matches that
+ * filter. if so, return the IDL for that index (else return NULL).
+ * -- a vlv index will match ONLY if that vlv index is subtree-scope and
+ * has the same search base and search filter.
+ * added read lock */
+
+IDList *vlv_find_index_by_filter(struct backend *be, const char *base,
+ Slapi_Filter *f)
+{
+ struct vlvSearch *t = NULL;
+ struct vlvIndex *vi;
+ Slapi_DN base_sdn;
+ PRUint32 length;
+ int err;
+ DB *db = NULL;
+ DBC *dbc = NULL;
+ IDList *idl;
+ Slapi_Filter *vlv_f;
+
+ PR_RWLock_Rlock(be->vlvSearchList_lock);
+ slapi_sdn_init_dn_byref(&base_sdn, base);
+ for (t = (struct vlvSearch *)be->vlvSearchList; t; t = t->vlv_next) {
+ /* all vlv "filters" start with (|(xxx)(objectclass=referral)).
+ * we only care about the (xxx) part.
+ */
+ vlv_f = t->vlv_slapifilter->f_or;
+ if ((t->vlv_scope == LDAP_SCOPE_SUBTREE) &&
+ (slapi_sdn_compare(t->vlv_base, &base_sdn) == 0) &&
+ (slapi_filter_compare(vlv_f, f) == 0)) {
+ /* found match! */
+ slapi_sdn_done(&base_sdn);
+
+ /* is there an index that's ready? */
+ vi = t->vlv_index;
+ while (!vlvIndex_online(vi) && vi) {
+ vi = vi->vlv_next;
+ }
+ if (!vi) {
+ /* no match */
+ LDAPDebug(LDAP_DEBUG_TRACE, "vlv: no index online for %s\n",
+ t->vlv_filter, 0, 0);
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return NULL;
+ }
+
+ if (dblayer_get_index_file(be, vi->vlv_attrinfo, &db, 0) == 0) {
+ err = db->cursor(db, 0 /* txn */, &dbc, 0);
+ if (err == 0) {
+ length = vlvIndex_get_indexlength(vi, db, 0 /* txn */);
+ if (length == 0) /* 609377: index size could be 0 */
+ {
+ LDAPDebug(LDAP_DEBUG_TRACE, "vlv: index %s is empty\n",
+ t->vlv_filter, 0, 0);
+ idl = NULL;
+ }
+ else
+ {
+ err = vlv_build_idl(0, length-1, db, dbc, &idl, 1 /* dosort */);
+ }
+ dbc->c_close(dbc);
+ }
+ dblayer_release_index_file(be, vi->vlv_attrinfo, db);
+ if (err == 0) {
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return idl;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "vlv find index: err %d\n",
+ err, 0, 0);
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ return NULL;
+ }
+ }
+ }
+ }
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ /* no match */
+ slapi_sdn_done(&base_sdn);
+ return NULL;
+}
+
+
+
+/* replace c with c2 in string -- probably exists somewhere but I can't find it slapi maybe? */
+
+static void replace_char(char *name, char c, char c2)
+{
+ int x;
+
+ for (x = 0; name[x] != '\0'; x++) {
+ if (c == name[x]) {
+ name[x] = c2;
+ }
+ }
+}
+
+/* similar to what the console GUI does */
+
+char *create_vlv_search_tag(const char* dn) {
+ char *tmp2=strdup(dn);
+
+ replace_char(tmp2,',',' ');
+ replace_char(tmp2,'"','-');
+ replace_char(tmp2,'+','_');
+ return tmp2;
+}
+
+/* Builds strings from Slapi_DN similar console GUI. Uses those dns to
+ delete vlvsearch's if they match. New write lock.
+ */
+
+#define LDBM_PLUGIN_ROOT ", cn=ldbm database, cn=plugins, cn=config"
+#define TAG "cn=by MCC "
+
+int vlv_delete_search_entry(Slapi_PBlock *pb, Slapi_Entry* e, ldbm_instance *inst)
+{
+ int rc=0;
+ Slapi_PBlock *tmppb;
+ Slapi_DN *newdn;
+ struct vlvSearch* p=NULL;
+ char *buf, *buf2, *tag1, *tag2;
+ const char *dn= slapi_sdn_get_dn(&e->e_sdn);
+ backend *be= inst->inst_be;
+
+ tag1=create_vlv_search_tag(dn);
+ buf=slapi_ch_malloc(strlen("cn=MCC ")+strlen(tag1)+strlen(", cn=")+strlen(inst->inst_name)+strlen(LDBM_PLUGIN_ROOT) + 1);
+ sprintf(buf,"%s%s%s%s%s","cn=MCC ",tag1,", cn=",inst->inst_name,LDBM_PLUGIN_ROOT);
+ newdn=slapi_sdn_new_dn_byval(buf);
+ PR_RWLock_Wlock(be->vlvSearchList_lock);
+ p = vlvSearch_finddn((struct vlvSearch *)be->vlvSearchList, newdn);
+ if(p!=NULL)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Deleted Virtual List View Search (%s).\n", p->vlv_name, 0, 0);
+ tag2=create_vlv_search_tag(dn);
+ buf2=slapi_ch_malloc(strlen(TAG)+strlen(tag2)+strlen(buf)+2);
+ sprintf(buf2,"%s%s,%s",TAG,tag2,buf);
+ vlvSearch_removefromlist((struct vlvSearch **)&be->vlvSearchList,p->vlv_dn);
+ /* This line release lock to prevent recursive deadlock caused by slapi_internal_delete calling vlvDeleteSearchEntry */
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ vlvSearch_delete(&p);
+ tmppb = slapi_pblock_new();
+ slapi_delete_internal_set_pb(tmppb, buf2, NULL, NULL,
+ (void *)plugin_get_default_component_id(), 0);
+ slapi_delete_internal_pb(tmppb);
+ slapi_pblock_get (tmppb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if(rc != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "vlv_delete_search_entry:can't delete dse entry '%s'\n", buf2, 0, 0);
+ }
+ pblock_done(tmppb);
+ pblock_init(tmppb);
+ slapi_delete_internal_set_pb(tmppb, buf, NULL, NULL,
+ (void *)plugin_get_default_component_id(), 0);
+ slapi_delete_internal_pb(tmppb);
+ slapi_pblock_get (tmppb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if(rc != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "vlv_delete_search_entry:can't delete dse entry '%s'\n", buf, 0, 0);
+ }
+ slapi_pblock_destroy(tmppb);
+ slapi_ch_free((void **)&tag2);
+ slapi_ch_free((void **)&buf2);
+ } else {
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+ }
+ slapi_ch_free((void **)&tag1);
+ slapi_ch_free((void **)&buf);
+ slapi_sdn_free(&newdn);
+ return rc;
+}
+
+void
+vlv_acquire_lock(backend *be)
+{
+ LDAPDebug(LDAP_DEBUG_TRACE, "vlv_acquire_lock => trying to acquire the lock\n", 0, 0, 0);
+ PR_RWLock_Wlock(be->vlvSearchList_lock);
+}
+
+void
+vlv_release_lock(backend *be)
+{
+ LDAPDebug(LDAP_DEBUG_TRACE, "vlv_release_lock => trying to release the lock\n", 0, 0, 0);
+ PR_RWLock_Unlock(be->vlvSearchList_lock);
+}
diff --git a/ldap/servers/slapd/back-ldbm/vlv_key.c b/ldap/servers/slapd/back-ldbm/vlv_key.c
new file mode 100644
index 00000000..d80aaa34
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/vlv_key.c
@@ -0,0 +1,69 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* vlv_key.c */
+
+
+#include "back-ldbm.h"
+#include "vlv_key.h"
+
+/*
+ * These functions manipulate keys for the virtual list view indexes.
+ * A key consists of a string of attribute values concatinated together,
+ * plus an entry DN to ensure uniqueness.
+ */
+
+struct vlv_key *
+vlv_key_new()
+{
+ struct vlv_key *p= (struct vlv_key*)slapi_ch_malloc(sizeof(struct vlv_key));
+ p->keymem= 64;
+ memset(&p->key,0,sizeof(DBT));
+ p->key.data= slapi_ch_malloc(p->keymem);
+ p->key.size= 0;
+ return p;
+}
+
+void
+vlv_key_delete(struct vlv_key **p)
+{
+ slapi_ch_free(&((*p)->key.data));
+ slapi_ch_free((void **)p);
+}
+
+#if 0
+static void
+vlv_key_copy(const struct vlv_key *p1,struct vlv_key *p2)
+{
+ p2->keymem= p1->keymem;
+ p2->key.data= slapi_ch_realloc(p2->key.data,p2->keymem);
+ strcpy(p2->key.data, p1->key.data);
+ p2->key.size= p1->key.size;
+}
+#endif
+
+/*
+ * Add an attribute value to the end of a composite key.
+ */
+void
+vlv_key_addattr(struct vlv_key *p,struct berval *val)
+{
+ /* If there isn't room then allocate some more memory */
+ unsigned int need = p->key.size + val->bv_len;
+ if(need > p->keymem)
+ {
+ p->keymem*= 2;
+ if(need > p->keymem)
+ {
+ p->keymem= need;
+ }
+ p->key.data= slapi_ch_realloc(p->key.data,p->keymem);
+ }
+ memcpy(((char*)p->key.data)+p->key.size, val->bv_val, val->bv_len);
+ p->key.size+= val->bv_len;
+}
+
+
+
diff --git a/ldap/servers/slapd/back-ldbm/vlv_key.h b/ldap/servers/slapd/back-ldbm/vlv_key.h
new file mode 100644
index 00000000..d7436629
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/vlv_key.h
@@ -0,0 +1,22 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* vlv_key.h */
+
+
+#if !defined(__VLV_KEY_H)
+#define __VLV_KEY_H
+
+struct vlv_key
+{
+ PRUint32 keymem;
+ DBT key;
+};
+
+struct vlv_key *vlv_key_new();
+void vlv_key_delete(struct vlv_key **p);
+void vlv_key_addattr(struct vlv_key *p,struct berval *val);
+
+#endif
diff --git a/ldap/servers/slapd/back-ldbm/vlv_srch.c b/ldap/servers/slapd/back-ldbm/vlv_srch.c
new file mode 100644
index 00000000..0f72c418
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/vlv_srch.c
@@ -0,0 +1,901 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* vlv_srch.c */
+
+
+#include "back-ldbm.h"
+#include "vlv_srch.h"
+
+/* Attributes for vlvSearch */
+char* const type_vlvName = "cn";
+char* const type_vlvBase = "vlvBase";
+char* const type_vlvScope = "vlvScope";
+char* const type_vlvFilter = "vlvFilter";
+
+/* Attributes for vlvIndex */
+char* const type_vlvSort = "vlvSort";
+char* const type_vlvFilename = "vlvFilename";
+char* const type_vlvEnabled = "vlvEnabled";
+char* const type_vlvUses = "vlvUses";
+
+static const char *file_prefix= "vlv#"; /* '#' used to avoid collision with real attributes */
+static const char *file_suffix= LDBM_FILENAME_SUFFIX;
+
+static int vlvIndex_createfilename(struct vlvIndex* pIndex, char **ppc);
+
+static int vlvIndex_equal(const struct vlvIndex* p1, const sort_spec* sort_control);
+static void vlvIndex_checkforindex(struct vlvIndex* p, backend *be);
+
+/*
+ * Create a new vlvSearch object
+ */
+struct vlvSearch*
+vlvSearch_new()
+{
+ struct vlvSearch* p = (struct vlvSearch*)slapi_ch_calloc(1,sizeof(struct vlvSearch));
+ if(p!=NULL)
+ {
+ p->vlv_e= NULL;
+ p->vlv_dn= NULL;
+ p->vlv_name= NULL;
+ p->vlv_base= NULL;
+ p->vlv_scope= LDAP_SCOPE_BASE;
+ p->vlv_filter= NULL;
+ p->vlv_slapifilter= NULL;
+ p->vlv_index= NULL;
+ p->vlv_next= NULL;
+ }
+ return p;
+}
+
+/*
+ * Trim spaces off the end of the string
+ */
+static void
+trimspaces(char *s)
+{
+ PRUint32 i= strlen(s) - 1;
+ while(i > 0 && isascii(s[i]) && isspace(s[i]))
+ {
+ s[i]= '\0';
+ i--;
+ }
+}
+
+/*
+ * Re-Initialise a vlvSearch object
+ */
+void
+vlvSearch_reinit(struct vlvSearch* p, const struct backentry *base)
+{
+ if (p->vlv_initialized) {
+ return; /* no work to do */
+ }
+ if (LDAP_SCOPE_ONELEVEL != p->vlv_scope) {
+ /* Only kind we re-init is onelevel searches */
+ return;
+ }
+ /* Now down to work */
+ if (NULL != p->vlv_slapifilter) {
+ slapi_filter_free(p->vlv_slapifilter,1);
+ }
+ p->vlv_slapifilter= slapi_str2filter( p->vlv_filter );
+ filter_normalize(p->vlv_slapifilter);
+ /* make (&(parentid=idofbase)(|(originalfilter)(objectclass=referral))) */
+ {
+ Slapi_Filter *fid2kids= NULL;
+ Slapi_Filter *focref= NULL;
+ Slapi_Filter *fand= NULL;
+ Slapi_Filter *forr= NULL;
+ p->vlv_slapifilter= create_onelevel_filter(p->vlv_slapifilter, base, 0 /* managedsait */, &fid2kids, &focref, &fand, &forr);
+ }
+}
+
+/*
+ * Initialise a vlvSearch object
+ */
+void
+vlvSearch_init(struct vlvSearch* p, Slapi_PBlock *pb, const Slapi_Entry *e, ldbm_instance *inst)
+{
+ /* VLV specification */
+ /* Need to copy the entry here because this one is in the cache,
+ * not forever ! */
+ p->vlv_e= slapi_entry_dup( e );
+ p->vlv_dn= slapi_sdn_dup(slapi_entry_get_sdn_const(e));
+ p->vlv_name= slapi_entry_attr_get_charptr(e,type_vlvName);
+ p->vlv_base= slapi_sdn_new_dn_passin(slapi_entry_attr_get_charptr(e,type_vlvBase));
+ p->vlv_scope= slapi_entry_attr_get_int(e,type_vlvScope);
+ p->vlv_filter= slapi_entry_attr_get_charptr(e,type_vlvFilter);
+ p->vlv_initialized = 1;
+
+ /* JCM: Should perform some validation and report errors to the error log */
+ /* JCM: Add brackets around the filter if none are there... */
+ trimspaces(p->vlv_name);
+ trimspaces(p->vlv_filter);
+
+ if(strlen(p->vlv_filter)>0)
+ {
+ /* Convert the textual filter, into a Slapi_Filter structure */
+ p->vlv_slapifilter= slapi_str2filter( p->vlv_filter );
+ filter_normalize(p->vlv_slapifilter);
+ }
+
+ /* JCM: Really should convert the slapifilter into a string and use that. */
+
+ /* Convert the filter based on the scope of the search */
+ switch(p->vlv_scope)
+ {
+ case LDAP_SCOPE_BASE:
+ /* Don't need to alter the filter */
+ break;
+ case LDAP_SCOPE_ONELEVEL:
+ {
+ /*
+ * Get the base object for the search.
+ * The entry "" will never be contained in the database,
+ * so treat it as a special case.
+ */
+ struct backentry *e= NULL;
+ if ( !slapi_sdn_isempty(p->vlv_base)) {
+ Slapi_Backend *oldbe = NULL;
+ entry_address addr;
+
+ /* switch context to the target backend */
+ slapi_pblock_get(pb, SLAPI_BACKEND, &oldbe);
+ slapi_pblock_set(pb, SLAPI_BACKEND, inst->inst_be);
+ slapi_pblock_set(pb, SLAPI_PLUGIN, inst->inst_be->be_database);
+
+ addr.dn = (char*)slapi_sdn_get_ndn (p->vlv_base);
+ addr.uniqueid = NULL;
+ e = find_entry( pb, inst->inst_be, &addr, NULL );
+ /* Check to see if the entry is absent. If it is, mark this search
+ * as not initialized */
+ if (NULL == e) {
+ p->vlv_initialized = 0;
+ /* We crash on anyhow, and rely on the fact that the filter
+ * we create is bogus to prevent chaos */
+ }
+
+ /* switch context back to the DSE backend */
+ slapi_pblock_set(pb, SLAPI_BACKEND, oldbe);
+ slapi_pblock_set(pb, SLAPI_PLUGIN, oldbe->be_database);
+ }
+
+ /* make (&(parentid=idofbase)(|(originalfilter)(objectclass=referral))) */
+ {
+ Slapi_Filter *fid2kids= NULL;
+ Slapi_Filter *focref= NULL;
+ Slapi_Filter *fand= NULL;
+ Slapi_Filter *forr= NULL;
+ p->vlv_slapifilter= create_onelevel_filter(p->vlv_slapifilter, e, 0 /* managedsait */, &fid2kids, &focref, &fand, &forr);
+ /* jcm: fid2kids, focref, fand, and forr get freed when we free p->vlv_slapifilter */
+ cache_return(&inst->inst_cache,&e);
+ }
+ }
+ break;
+ case LDAP_SCOPE_SUBTREE:
+ {
+ /* make (|(originalfilter)(objectclass=referral))) */
+ /* No need for scope-filter since we apply a scope test before the filter test */
+ Slapi_Filter *focref= NULL;
+ Slapi_Filter *forr= NULL;
+ p->vlv_slapifilter= create_subtree_filter(p->vlv_slapifilter, 0 /* managedsait */, &focref, &forr);
+ /* jcm: focref and forr get freed when we free p->vlv_slapifilter */
+ }
+ break;
+ }
+}
+
+/*
+ * Destroy an existing vlvSearch object
+ */
+void
+vlvSearch_delete(struct vlvSearch** ppvs)
+{
+ if(ppvs!=NULL && *ppvs!=NULL)
+ {
+ struct vlvIndex *pi, *ni;
+ slapi_sdn_free(&((*ppvs)->vlv_dn));
+ slapi_ch_free((void**)&((*ppvs)->vlv_name));
+ slapi_sdn_free(&((*ppvs)->vlv_base));
+ slapi_ch_free((void**)&((*ppvs)->vlv_filter));
+ slapi_filter_free((*ppvs)->vlv_slapifilter,1);
+ for(pi= (*ppvs)->vlv_index;pi!=NULL;)
+ {
+ ni= pi->vlv_next;
+ if(pi->vlv_be != NULL) {
+ vlvIndex_go_offline(pi,pi->vlv_be);
+ }
+ vlvIndex_delete(&pi);
+ pi= ni;
+ }
+ slapi_ch_free((void**)ppvs);
+ *ppvs= NULL;
+ }
+}
+
+/*
+ * Add a search to a list.
+ *
+ * We add it to the end of the list because there could
+ * be other threads traversing the list at this time.
+ */
+void
+vlvSearch_addtolist(struct vlvSearch* p, struct vlvSearch** pplist)
+{
+ if(pplist!=NULL && p!=NULL)
+ {
+ p->vlv_next= NULL;
+ if(*pplist==NULL)
+ {
+ *pplist= p;
+ }
+ else
+ {
+ struct vlvSearch* last= *pplist;
+ for(;last->vlv_next!=NULL;last=last->vlv_next);
+ last->vlv_next= p;
+ }
+ }
+}
+
+
+/*
+ * Compare two VLV Searches to see if they're the same, based on their VLV Search specification.
+ */
+static struct vlvIndex *
+vlvSearch_equal(const struct vlvSearch* p1, const Slapi_DN *base, int scope, const char *filter, const sort_spec* sort_control)
+{
+ struct vlvIndex *pi= NULL;
+ int r= (slapi_sdn_compare(p1->vlv_base,base)==0);
+ if(r) r= (p1->vlv_scope==scope);
+ if(r) r= (strcasecmp(p1->vlv_filter,filter)==0);
+ if(r)
+ {
+ pi= p1->vlv_index;
+ r= 0;
+ for(;!r && pi!=NULL;)
+ {
+ r= vlvIndex_equal(pi, sort_control);
+ if(!r)
+ {
+ pi= pi->vlv_next;
+ }
+ }
+ }
+ return pi;
+}
+
+/*
+ * Find an enabled VLV Search in a list which matches the
+ * description provided in "base, scope, filter, sort_control"
+ */
+struct vlvIndex*
+vlvSearch_findenabled(backend *be,struct vlvSearch* plist, const Slapi_DN *base, int scope, const char *filter, const sort_spec* sort_control)
+{
+ struct vlvSearch *t= plist;
+ struct vlvIndex *pi= NULL;
+ for(; (t!=NULL) && (pi == NULL); t= t->vlv_next)
+ {
+ pi= vlvSearch_equal(t,base,scope,filter,sort_control);
+ if(pi!=NULL)
+ {
+ if(!vlvIndex_enabled(pi))
+ {
+ /*
+ * A VLV Spec which matched the search criteria was found.
+ * But it hasn't been enabled yet. Check to see if the
+ * index is there. But, only check once every 60 seconds.
+ */
+ time_t curtime = current_time();
+ if(curtime>pi->vlv_lastchecked+60)
+ {
+ vlvIndex_checkforindex(pi, be);
+ pi->vlv_lastchecked= current_time();
+ }
+ }
+ if(!vlvIndex_enabled(pi))
+ {
+ pi= NULL;
+ }
+ }
+ }
+ return pi;
+}
+
+/*
+ * Find a VLV Search in a list which matches the name
+ */
+struct vlvIndex*
+vlvSearch_findname(const struct vlvSearch* plist, const char *name)
+{
+ const struct vlvSearch* t= plist;
+ for(; t!=NULL ; t= t->vlv_next)
+ {
+ struct vlvIndex *pi= t->vlv_index;
+ for(;pi!=NULL;pi= pi->vlv_next)
+ {
+ if(strcasecmp(pi->vlv_name,name)==0)
+ {
+ return pi;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Find a VLV Search in a list which matches the index name
+ */
+struct vlvIndex*
+vlvSearch_findindexname(const struct vlvSearch* plist, const char *name)
+{
+ const struct vlvSearch* t= plist;
+ for(; t!=NULL ; t= t->vlv_next)
+ {
+ struct vlvIndex *pi= t->vlv_index;
+ for(;pi!=NULL;pi= pi->vlv_next)
+ {
+ if(strcasecmp(pi->vlv_attrinfo->ai_type,name)==0)
+ {
+ return pi;
+ }
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Get a list of VLV Index names.
+ * The returned pointer must be freed with slapi_ch_free
+ */
+char *
+vlvSearch_getnames(const struct vlvSearch* plist)
+{
+ /* Work out how long the string will be */
+ char *text;
+ int length= 5; /* enough to hold 'none' */
+ const struct vlvSearch* t= plist;
+ for(; t!=NULL ; t= t->vlv_next)
+ {
+ struct vlvIndex *pi= t->vlv_index;
+ for(;pi!=NULL;pi= pi->vlv_next)
+ {
+ length+= strlen(pi->vlv_name) + 4;
+ }
+ }
+ /* Build a comma delimited list of Index names */
+ text= slapi_ch_malloc(length);
+ if(length==5)
+ {
+ strcpy(text,"none");
+ }
+ else
+ {
+ text[0]= '\0';
+ t= plist;
+ for(; t!=NULL ; t= t->vlv_next)
+ {
+ struct vlvIndex *pi= t->vlv_index;
+ for(;pi!=NULL;pi= pi->vlv_next)
+ {
+ sprintf(text + strlen(text),"'%s', ",pi->vlv_name);
+ }
+ }
+ }
+ return text;
+}
+
+/*
+ * Find a VLV Search in a list, based on the DN.
+ */
+struct vlvSearch*
+vlvSearch_finddn(const struct vlvSearch* plist, const Slapi_DN *dn)
+{
+ const struct vlvSearch* curr= plist;
+ for(; curr!=NULL && slapi_sdn_compare(curr->vlv_dn,dn)!=0; curr= curr->vlv_next);
+ return (struct vlvSearch*)curr;
+}
+
+/*
+ * Remove a VLV Search from a list, based on the DN.
+ */
+void
+vlvSearch_removefromlist(struct vlvSearch** pplist, const Slapi_DN *dn)
+{
+ int done= 0;
+ struct vlvSearch* prev= NULL;
+ struct vlvSearch* curr= *pplist;
+ while(curr!=NULL && !done)
+ {
+ if(slapi_sdn_compare(curr->vlv_dn,dn)==0)
+ {
+ if(curr==*pplist)
+ {
+ *pplist= curr->vlv_next;
+ }
+ else
+ {
+ prev->vlv_next= curr->vlv_next;
+ }
+ done= 1;
+ }
+ else
+ {
+ prev= curr;
+ curr= curr->vlv_next;
+ }
+ }
+}
+
+/*
+ * Access Control Check to see if the client is allowed to use this VLV Search.
+ */
+int
+vlvSearch_accessallowed(struct vlvSearch *p, Slapi_PBlock *pb)
+{
+ char *attrs[2] = { NULL, NULL};
+
+ attrs[0] = type_vlvName;
+ return (plugin_call_acl_plugin ( pb, (Slapi_Entry*)p->vlv_e, attrs, NULL,
+ SLAPI_ACL_READ, ACLPLUGIN_ACCESS_READ_ON_VLV, NULL ) );
+}
+
+const Slapi_DN *vlvSearch_getBase(struct vlvSearch* p)
+{
+ return p->vlv_base;
+}
+
+int vlvSearch_getScope(struct vlvSearch* p)
+{
+ return p->vlv_scope;
+}
+
+Slapi_Filter *vlvSearch_getFilter(struct vlvSearch* p)
+{
+ return p->vlv_slapifilter;
+}
+
+int vlvSearch_isVlvSearchEntry(Slapi_Entry *e)
+{
+ return slapi_entry_attr_hasvalue(e, "objectclass", "vlvsearch");
+}
+
+void vlvSearch_addIndex(struct vlvSearch *pSearch, struct vlvIndex *pIndex)
+{
+ pIndex->vlv_next= NULL;
+ if(pSearch->vlv_index==NULL)
+ {
+ pSearch->vlv_index= pIndex;
+ }
+ else
+ {
+ struct vlvIndex* last= pSearch->vlv_index;
+ for(;last->vlv_next!=NULL;last=last->vlv_next);
+ last->vlv_next= pIndex;
+ }
+}
+
+/* ============================================================================================== */
+
+/*
+ * Create a new vlvIndex object
+ */
+struct vlvIndex*
+vlvIndex_new()
+{
+ struct vlvIndex* p = (struct vlvIndex*)slapi_ch_calloc(1,sizeof(struct vlvIndex));
+ if(p!=NULL)
+ {
+ p->vlv_sortspec= NULL;
+ p->vlv_attrinfo= attrinfo_new();
+ p->vlv_sortkey= NULL;
+ p->vlv_filename= NULL;
+ p->vlv_mrpb= NULL;
+ p->vlv_syntax_plugin= NULL;
+ p->vlv_indexlength_lock= PR_NewLock();
+ p->vlv_indexlength_cached= 0;
+ p->vlv_indexlength= 0;
+ p->vlv_online = 1;
+ p->vlv_enabled = 0;
+ p->vlv_lastchecked= 0;
+ p->vlv_uses= 0;
+ p->vlv_search= NULL;
+ p->vlv_next= NULL;
+ }
+ return p;
+}
+
+/*
+ * Destroy an existing vlvIndex object
+ */
+void
+vlvIndex_delete(struct vlvIndex** ppvs)
+{
+ if(ppvs!=NULL && *ppvs!=NULL)
+ {
+ slapi_ch_free((void**)&((*ppvs)->vlv_sortspec));
+ {
+ int n;
+ for(n=0;(*ppvs)->vlv_sortkey[n]!=NULL;n++)
+ {
+ if((*ppvs)->vlv_mrpb[n] != NULL) {
+ destroy_matchrule_indexer((*ppvs)->vlv_mrpb[n]);
+ slapi_pblock_destroy((*ppvs)->vlv_mrpb[n]);
+ }
+ }
+ }
+ ldap_free_sort_keylist((*ppvs)->vlv_sortkey);
+ attrinfo_delete(&((*ppvs)->vlv_attrinfo));
+ slapi_ch_free((void**)&((*ppvs)->vlv_mrpb));
+ slapi_ch_free((void**)&((*ppvs)->vlv_syntax_plugin));
+ PR_DestroyLock((*ppvs)->vlv_indexlength_lock);
+ slapi_ch_free((void**)ppvs);
+ *ppvs= NULL;
+ }
+}
+
+/*
+ * Initialise a vlvSearch object
+ */
+void
+vlvIndex_init(struct vlvIndex* p, backend *be, struct vlvSearch* pSearch, const Slapi_Entry *e)
+{
+ struct ldbminfo *li = (struct ldbminfo *) be->be_database->plg_private;
+ char *filename= NULL;
+
+ if (NULL == p)
+ return;
+
+ /* JCM: Should perform some validation and report errors to the error log */
+ /* JCM: Add brackets around the filter if none are there... */
+ p->vlv_sortspec= slapi_entry_attr_get_charptr(e,type_vlvSort);
+ trimspaces(p->vlv_sortspec);
+
+ p->vlv_name= slapi_entry_attr_get_charptr(e,type_vlvName);
+ trimspaces(p->vlv_name);
+
+ p->vlv_search= pSearch;
+
+ /* Convert the textual sort specification into a keylist structure */
+ ldap_create_sort_keylist(&(p->vlv_sortkey),p->vlv_sortspec);
+ {
+ /*
+ * For each sort attribute find the appropriate syntax plugin,
+ * and if it has a matching rule, create a matching rule indexer object.
+ */
+ int n;
+ for(n=0;p->vlv_sortkey[n]!=NULL;n++);
+ p->vlv_mrpb= (Slapi_PBlock**)slapi_ch_calloc(n+1,sizeof(Slapi_PBlock*));
+ p->vlv_syntax_plugin= (void **)(Slapi_PBlock**)slapi_ch_calloc(n+1,sizeof(Slapi_PBlock*));
+ for(n=0;p->vlv_sortkey[n]!=NULL;n++)
+ {
+ slapi_attr_type2plugin( p->vlv_sortkey[n]->sk_attrtype, &p->vlv_syntax_plugin[n] );
+ if(p->vlv_sortkey[n]->sk_matchruleoid!=NULL)
+ {
+ create_matchrule_indexer(&p->vlv_mrpb[n],p->vlv_sortkey[n]->sk_matchruleoid,p->vlv_sortkey[n]->sk_attrtype);
+ }
+
+ }
+
+ }
+
+ /* Create an index filename for the search */
+ if(vlvIndex_createfilename(p,&filename))
+ {
+ p->vlv_filename= slapi_ch_malloc(strlen(file_prefix) + strlen(filename) + strlen(file_suffix) + 1);
+ sprintf(p->vlv_filename,"%s%s%s",file_prefix,filename,file_suffix);
+
+ /* Create an attrinfo structure */
+ p->vlv_attrinfo->ai_type= slapi_ch_malloc(strlen(file_prefix) + strlen(filename) + 1);
+ sprintf(p->vlv_attrinfo->ai_type,"%s%s",file_prefix,filename);
+ p->vlv_attrinfo->ai_indexmask= INDEX_VLV;
+
+ /* Check if the index file actually exists */
+ if(li!=NULL)
+ {
+ vlvIndex_checkforindex(p, be);
+ }
+ p->vlv_lastchecked= current_time();
+ }
+ slapi_ch_free((void**)&filename);
+}
+
+/*
+ * Determine how many {key,data} pairs there are in the VLV Index.
+ * We only work out the length of the index once, then we cache
+ * it and maintain it.
+ */
+PRUint32
+vlvIndex_get_indexlength(struct vlvIndex* p, DB *db, back_txn *txn)
+{
+ if (NULL == p)
+ return 0;
+
+ if(!p->vlv_indexlength_cached)
+ {
+ DBC *dbc = NULL;
+ DB_TXN *db_txn = NULL;
+ int err= 0;
+ if (NULL != txn)
+ {
+ db_txn = txn->back_txn_txn;
+ }
+ err = db->cursor(db, db_txn, &dbc, 0);
+ if(err==0)
+ {
+ DBT key= {0};
+ DBT data= {0};
+ key.flags= DB_DBT_MALLOC;
+ data.flags= DB_DBT_MALLOC;
+ err= dbc->c_get(dbc,&key,&data,DB_LAST);
+ if(err==0)
+ {
+ free(key.data); key.data= NULL;
+ free(data.data); data.data= NULL;
+ err= dbc->c_get(dbc,&key,&data,DB_GET_RECNO);
+ if(err==0)
+ {
+ PR_Lock(p->vlv_indexlength_lock);
+ p->vlv_indexlength_cached= 1;
+ p->vlv_indexlength= *((db_recno_t*)data.data);
+ PR_Unlock(p->vlv_indexlength_lock);
+ free(data.data);
+ }
+ }
+ dbc->c_close(dbc);
+ }
+ else
+ {
+ /* couldn't get cursor??? */
+ }
+ }
+ return p->vlv_indexlength;
+}
+
+/*
+ * Increment the index length count.
+ * We keep track of the index length for efficiency.
+ */
+void
+vlvIndex_increment_indexlength(struct vlvIndex* p, DB *db, back_txn *txn)
+{
+ if (NULL == p)
+ return;
+
+ if(p->vlv_indexlength_cached)
+ {
+ PR_Lock(p->vlv_indexlength_lock);
+ p->vlv_indexlength++;
+ PR_Unlock(p->vlv_indexlength_lock);
+ }
+ else
+ {
+ p->vlv_indexlength= vlvIndex_get_indexlength(p, db, txn);
+ }
+}
+
+/*
+ * Decrement the index length count.
+ * We keep track of the index length for efficiency.
+ */
+void
+vlvIndex_decrement_indexlength(struct vlvIndex* p, DB *db, back_txn *txn)
+{
+ if (NULL == p)
+ return;
+
+ if(p->vlv_indexlength_cached)
+ {
+ /* jcm: Check for underflow? */
+ PR_Lock(p->vlv_indexlength_lock);
+ p->vlv_indexlength--;
+ PR_Unlock(p->vlv_indexlength_lock);
+ }
+ else
+ {
+ p->vlv_indexlength= vlvIndex_get_indexlength(p, db, txn);
+ }
+}
+
+/*
+ * Increment the usage counter
+ */
+void
+vlvIndex_incrementUsage(struct vlvIndex* p)
+{
+ if (NULL == p)
+ return;
+ p->vlv_uses++;
+}
+
+/*
+ * Get the filename of the index.
+ */
+const char *
+vlvIndex_filename(const struct vlvIndex* p)
+{
+ if (NULL == p)
+ return NULL;
+ return p->vlv_filename;
+}
+
+/*
+ * Check if the index is available.
+ */
+int vlvIndex_enabled(const struct vlvIndex* p)
+{
+ if (NULL == p)
+ return 0;
+ return p->vlv_enabled;
+}
+
+int vlvIndex_online(const struct vlvIndex *p)
+{
+ if (NULL == p)
+ return 0;
+ return p->vlv_online;
+}
+
+void vlvIndex_go_offline(struct vlvIndex *p, backend *be)
+{
+ if (NULL == p)
+ return;
+ p->vlv_online = 0;
+ p->vlv_enabled = 0;
+ p->vlv_indexlength = 0;
+ p->vlv_attrinfo->ai_indexmask |= INDEX_OFFLINE;
+ dblayer_erase_index_file_nolock(be, p->vlv_attrinfo, 1 /* chkpt if not busy */);
+}
+
+void vlvIndex_go_online(struct vlvIndex *p, backend *be)
+{
+ if (NULL == p)
+ return;
+ p->vlv_attrinfo->ai_indexmask &= ~INDEX_OFFLINE;
+ p->vlv_online = 1;
+ vlvIndex_checkforindex(p, be);
+}
+
+
+/*
+ * Access Control Check to see if the client is allowed to use this VLV Index.
+ */
+int
+vlvIndex_accessallowed(struct vlvIndex *p, Slapi_PBlock *pb)
+{
+ if (NULL == p)
+ return 0;
+ return vlvSearch_accessallowed(p->vlv_search, pb);
+}
+
+const Slapi_DN *vlvIndex_getBase(struct vlvIndex* p)
+{
+ if (NULL == p)
+ return NULL;
+ return vlvSearch_getBase(p->vlv_search);
+}
+
+int vlvIndex_getScope(struct vlvIndex* p)
+{
+ if (NULL == p)
+ return 0;
+ return vlvSearch_getScope(p->vlv_search);
+}
+
+Slapi_Filter *vlvIndex_getFilter(struct vlvIndex* p)
+{
+ if (NULL == p)
+ return NULL;
+ return vlvSearch_getFilter(p->vlv_search);
+}
+
+const char *vlvIndex_getName(struct vlvIndex* p)
+{
+ if (NULL == p)
+ return NULL;
+ return p->vlv_name;
+}
+
+/*
+ * JCM: Could also match reverse sense of index and use in reverse.
+ */
+static int
+vlvIndex_equal(const struct vlvIndex* p1, const sort_spec* sort_control)
+{
+ int r= 1;
+ const sort_spec *t1= sort_control;
+ LDAPsortkey *t2= p1->vlv_sortkey[0];
+ int n= 1;
+ for(;t1!=NULL && t2!=NULL && r;t1= t1->next,t2=p1->vlv_sortkey[n],n++)
+ {
+ r= (t1->order && t2->sk_reverseorder) || (!t1->order && !t2->sk_reverseorder);
+ if(r) r= (strcasecmp(t1->type, t2->sk_attrtype)==0);
+ if(r)
+ {
+ if(t1->matchrule==NULL && t2->sk_matchruleoid==NULL)
+ {
+ r= 1;
+ }
+ else if(t1->matchrule!=NULL && t2->sk_matchruleoid!=NULL)
+ {
+ r= (strcasecmp(t1->matchrule, t2->sk_matchruleoid)==0);
+ }
+ else
+ {
+ r= 0;
+ }
+ }
+ }
+ if(r) r= (t1==NULL && t2==NULL);
+ return r;
+}
+
+/*
+ * Check if the index file actually exists,
+ * and set vlv_enabled appropriately
+ */
+static void
+vlvIndex_checkforindex(struct vlvIndex* p, backend *be)
+{
+ DB *db = NULL;
+
+ /* if the vlv index is offline (being generated), don't even look */
+ if (! p->vlv_online)
+ return;
+
+ if (dblayer_get_index_file(be, p->vlv_attrinfo, &db, 0) == 0) {
+ p->vlv_enabled = 1;
+ dblayer_release_index_file( be, p->vlv_attrinfo, db );
+ } else {
+ p->vlv_enabled = 0;
+ }
+}
+
+int vlvIndex_isVlvIndexEntry(Slapi_Entry *e)
+{
+ return slapi_entry_attr_hasvalue(e, "objectclass", "vlvindex");
+}
+
+/*
+ * Create the filename for the index.
+ * Extract all the alphanumeric characters from the descriptive name.
+ * Convert to all lower case.
+ */
+static int
+vlvIndex_createfilename(struct vlvIndex* pIndex, char **ppc)
+{
+ int filenameValid= 1;
+ unsigned int i;
+ char *p, *filename;
+ filename= slapi_ch_malloc(strlen(pIndex->vlv_name) + 1);
+ p= filename;
+ for(i=0;i<strlen(pIndex->vlv_name);i++)
+ {
+ if(isalnum(pIndex->vlv_name[i]))
+ {
+ *p= TOLOWER( pIndex->vlv_name[i] );
+ p++;
+ }
+ }
+ *p= '\0';
+ if(strlen(filename)==0)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Couldn't generate valid filename from Virtual List View Index Name (%s). Need some alphabetical characters.\n", pIndex->vlv_name, 0, 0);
+ filenameValid= 0;
+ }
+ /* JCM: Check if this file clashes with another VLV Index filename */
+ *ppc= filename;
+ return filenameValid;
+}
+
+int
+vlv_isvlv(char *filename)
+{
+ if (0 == strncmp(filename, file_prefix, 4))
+ return 1;
+ return 0;
+}
diff --git a/ldap/servers/slapd/back-ldbm/vlv_srch.h b/ldap/servers/slapd/back-ldbm/vlv_srch.h
new file mode 100644
index 00000000..c892f6b4
--- /dev/null
+++ b/ldap/servers/slapd/back-ldbm/vlv_srch.h
@@ -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 **/
+/* vlv_srch.h */
+
+
+#if !defined(__VLV_SRCH_H)
+#define __VLV_SRCH_H
+
+extern char* const type_vlvName;
+extern char* const type_vlvBase;
+extern char* const type_vlvScope;
+extern char* const type_vlvFilter;
+extern char* const type_vlvSort;
+extern char* const type_vlvFilename;
+extern char* const type_vlvEnabled;
+extern char* const type_vlvUses;
+
+/*
+ * This structure is the internal representation of a VLV Search.
+ */
+struct vlvSearch
+{
+ /* The VLV Search Specification Entry */
+ const Slapi_Entry *vlv_e;
+
+ /* Extracted from the VLV Search Specification entry */
+ Slapi_DN *vlv_dn;
+ char *vlv_name;
+ Slapi_DN *vlv_base;
+ int vlv_scope;
+ char *vlv_filter;
+ int vlv_initialized;
+
+ /* Derived from the VLV Entry */
+ Slapi_Filter *vlv_slapifilter;
+
+ /* List of Indexes for this Search */
+ struct vlvIndex* vlv_index;
+
+ /* The next VLV Search in the list */
+ struct vlvSearch* vlv_next;
+};
+
+struct vlvIndex
+{
+ char *vlv_name;
+ char *vlv_sortspec;
+
+ /* Derived from the VLV Entry */
+ LDAPsortkey **vlv_sortkey;
+
+ /* The Index filename */
+ char *vlv_filename;
+
+ /* Attribute Structure maps filename onto index */
+ struct attrinfo *vlv_attrinfo;
+
+ /* Syntax Plugin. One for each LDAPsortkey */
+ void **vlv_syntax_plugin;
+
+ /* Matching Rule PBlock. One for each LDAPsortkey */
+ Slapi_PBlock **vlv_mrpb;
+
+ /* Keep track of the index length */
+ PRLock *vlv_indexlength_lock;
+ int vlv_indexlength_cached;
+ db_recno_t vlv_indexlength;
+
+ int vlv_enabled; /* index file is there & ready */
+ int vlv_online; /* turned off when generating index */
+
+ /* The last time we checked to see if the index file was available */
+ time_t vlv_lastchecked;
+
+ /* The number of uses this search has received since start up */
+ PRUint32 vlv_uses;
+
+ struct backend* vlv_be; /* need backend to remove the index when done */
+
+ /* The parent Search Specification for this Index */
+ struct vlvSearch* vlv_search;
+
+ /* The next VLV Index in the list */
+ struct vlvIndex* vlv_next;
+};
+
+struct vlvSearch* vlvSearch_new();
+void vlvSearch_init(struct vlvSearch*, Slapi_PBlock *pb, const Slapi_Entry *e, ldbm_instance *inst);
+void vlvSearch_reinit(struct vlvSearch* p, const struct backentry *base);
+void vlvSearch_delete(struct vlvSearch** ppvs);
+void vlvSearch_addtolist(struct vlvSearch* p, struct vlvSearch** pplist);
+struct vlvSearch* vlvSearch_find(const struct vlvSearch* plist, const char *base, int scope, const char *filter, const char *sortspec);
+struct vlvIndex* vlvSearch_findenabled(backend *be,struct vlvSearch* plist, const Slapi_DN *base, int scope, const char *filter, const sort_spec* sort_control);
+struct vlvSearch* vlvSearch_finddn(const struct vlvSearch* plist, const Slapi_DN *dn);
+struct vlvIndex* vlvSearch_findname(const struct vlvSearch* plist, const char *name);
+struct vlvIndex* vlvSearch_findindexname(const struct vlvSearch* plist, const char *name);
+char *vlvSearch_getnames(const struct vlvSearch* plist);
+void vlvSearch_removefromlist(struct vlvSearch** pplist, const Slapi_DN *dn);
+int vlvSearch_accessallowed(struct vlvSearch *p, Slapi_PBlock *pb);
+const Slapi_DN *vlvSearch_getBase(struct vlvSearch* p);
+int vlvSearch_getScope(struct vlvSearch* p);
+Slapi_Filter *vlvSearch_getFilter(struct vlvSearch* p);
+int vlvSearch_isVlvSearchEntry(Slapi_Entry *e);
+void vlvSearch_addIndex(struct vlvSearch *pSearch, struct vlvIndex *pIndex);
+
+
+struct vlvIndex* vlvIndex_new();
+void vlvIndex_init(struct vlvIndex* p, backend *be, struct vlvSearch* pSearch, const Slapi_Entry *e);
+void vlvIndex_delete(struct vlvIndex** ppvs);
+PRUint32 vlvIndex_get_indexlength(struct vlvIndex* p, DB *db, back_txn *txn);
+void vlvIndex_increment_indexlength(struct vlvIndex* p, DB *db, back_txn *txn);
+void vlvIndex_decrement_indexlength(struct vlvIndex* p, DB *db, back_txn *txn);
+void vlvIndex_incrementUsage(struct vlvIndex* p);
+const char *vlvIndex_filename(const struct vlvIndex* p);
+int vlvIndex_enabled(const struct vlvIndex* p);
+int vlvIndex_online(const struct vlvIndex *p);
+void vlvIndex_go_offline(struct vlvIndex *p, backend *be);
+void vlvIndex_go_online(struct vlvIndex *p, backend *be);
+int vlvIndex_accessallowed(struct vlvIndex *p, Slapi_PBlock *pb);
+const Slapi_DN *vlvIndex_getBase(struct vlvIndex* p);
+int vlvIndex_getScope(struct vlvIndex* p);
+Slapi_Filter *vlvIndex_getFilter(struct vlvIndex* p);
+const char *vlvIndex_getName(struct vlvIndex* p);
+int vlvIndex_isVlvIndexEntry(Slapi_Entry *e);
+
+#define VLV_ACCESS_DENIED -1
+#define VLV_BLD_LIST_FAILED -2
+#define VLV_FIND_SEARCH_FAILED -3
+
+
+#endif
diff --git a/ldap/servers/slapd/back-ldif/Makefile b/ldap/servers/slapd/back-ldif/Makefile
new file mode 100644
index 00000000..1b7037cd
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/Makefile
@@ -0,0 +1,81 @@
+#
+# 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 LDAP Back-ldif backend
+#
+
+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 = $(OBJDIR)/lib/libback-ldif
+LIBDIR = $(LDAP_LIBDIR)
+SERVER_OBJDEST = $(OBJDIR)/servers/obj
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+BACKLDIF_OBJS = close.o delete.o modrdn.o unbind.o add.o \
+ compare.o init.o search.o bind.o config.o modify.o monitor.o \
+ start.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(BACKLDIF_OBJS))
+
+SERVER_OBJS= ch_malloc.o entry.o result.o modutil.o
+
+EXTRA_OBJS = $(addprefix $(SERVER_OBJDEST)/, $(SERVER_OBJS))
+
+INCLUDES += -I..
+
+ifeq ($(ARCH), WINNT)
+BACKLDIF_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+LDAP_BACKLDIF= $(addprefix $(LIBDIR)/, $(LIBBACK_LDIF_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += $(LIBSECURITY) $(LIBNSPR) \
+ $(LDAP_COMMON_LIBS_DEP) $(LDAP_SDK_LIBS_DEP) \
+ $(LIBSLAPD_DEP) $(LIBLDAPU_DEP)
+
+EXTRA_LIBS += $(LIBSECURITY) $(LIBNSPR) \
+ $(LDAP_COMMON_LIBS) $(LDAP_SDK_LIBS) \
+ $(LIBSLAPD) $(THREADSLIB) $(LIBLDAPU)
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS += $(DLL_EXTRA_LIBS)
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LDAP_BACKLDIF)
+
+$(LIBDIR):
+ $(MKDIR) $(LIBDIR)
+
+$(LDAP_BACKLDIF): $(OBJS) $(BACKLDIF_DLL_OBJ)
+ $(LINK_DLL) $(BACKLDIF_DLL_OBJ) $(EXTRA_LIBS)
+
+$(SERVER_OBJDEST)/ch_malloc.o: ../ch_malloc.c
+ $(CC) -c $(CFLAGS) $(MCC_INCLUDE) $< $(OFFLAG)$*.o
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(BACKLDIF_DLL_OBJ)
+endif
+ $(RM) $(LDAP_BACKLDIF)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
diff --git a/ldap/servers/slapd/back-ldif/add.c b/ldap/servers/slapd/back-ldif/add.c
new file mode 100644
index 00000000..cd0b81dc
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/add.c
@@ -0,0 +1,189 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: add.c
+ *
+ * Functions:
+ *
+ * ldif_back_add() - ldap ldif back-end add routine
+ * ldifentry_init() - takes an Entry and makes an ldif_Entry
+ *
+ */
+
+#include "back-ldif.h"
+ldif_Entry * ldifentry_init(Slapi_Entry *);
+
+/*
+ * Function: ldif_back_add
+ *
+ * Returns: returns 0 if good, -1 else.
+ *
+ * Description: For changetype: add, this function adds the entry
+ */
+int
+ldif_back_add( Slapi_PBlock *pb )
+{
+ LDIF *db; /*Stores the ldif database*/
+ char *dn = NULL, *parentdn = NULL;
+ Slapi_Entry *e; /*The new entry to add*/
+ ldif_Entry *new, *old; /*Used for various accounting purposes*/
+ ldif_Entry *prev; /*Used to add new ldif_Entry to db*/
+ ldif_Entry *tprev; /*Dummy pointer for traversing the list*/
+ char *errbuf = NULL;
+
+ prev = NULL;
+ tprev = NULL;
+
+ /*Turn on tracing to see this printed out*/
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_add\n", 0, 0, 0 );
+
+ /*Get the database, the dn and the entry to add*/
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_ADD_TARGET, &dn ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e ) < 0){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ /*Check to make sure the entry passes the schema check*/
+ if ( slapi_entry_schema_check( pb, e ) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "entry failed schema check\n", 0, 0, 0 );
+ slapi_send_ldap_result( pb, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL, 0, NULL );
+ return( -1 );
+ }
+
+ prev = NULL;
+
+ /*Lock the database*/
+ PR_Lock( db->ldif_lock );
+
+ /*
+ * Attempt to find this dn in db. If there is no such dn,
+ * ldif_find_entry should return NULL, and prev should point
+ * to the last element in the list.
+ */
+ if ((old = (ldif_Entry *)ldif_find_entry(pb, db, dn, &prev)) != NULL) {
+
+ /*
+ * If we've reached this code, there is an entry in db
+ * whose dn matches dn, so release the db lock,
+ * tell the user and return
+ */
+ PR_Unlock( db->ldif_lock );
+ slapi_send_ldap_result( pb, LDAP_ALREADY_EXISTS, NULL, NULL, 0, NULL );
+ return( -1 );
+ }
+
+
+ /*
+ * Get the parent dn and see if the corresponding entry exists.
+ * If the parent does not exist, only allow the "root" user to
+ * add the entry.
+ */
+ if ( (parentdn = slapi_dn_beparent( pb, dn )) != NULL ) {
+ int rc;
+ if ((old = (ldif_Entry *)ldif_find_entry( pb, db, parentdn, &tprev)) == NULL ) {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ LDAPDebug( LDAP_DEBUG_TRACE, "parent does not exist\n", 0, 0, 0 );
+ goto error_return;
+ }
+ rc= slapi_access_allowed( pb, e, NULL, NULL, SLAPI_ACL_ADD );
+ if ( rc!=LDAP_SUCCESS ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "no access to parent\n", 0,0, 0 );
+ slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL );
+ goto error_return;
+ }
+ } else { /* no parent */
+ int isroot;
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ if ( !isroot ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "no parent & not root\n", 0, 0, 0 );
+ slapi_send_ldap_result( pb, LDAP_INSUFFICIENT_ACCESS, NULL, NULL, 0, NULL );
+ goto error_return;
+ }
+
+ }
+
+ /*
+ * Before we add the entry, find out if the syntax of the aci
+ * aci attribute values are correct or not. We don't want to add
+ * the entry if the syntax is incorrect.
+ */
+ if ( slapi_acl_verify_aci_syntax(pb, e, &errbuf) != 0 ) {
+ slapi_send_ldap_result( pb, LDAP_INVALID_SYNTAX, NULL, errbuf, 0, NULL );
+ if (errbuf) free(errbuf);
+ goto error_return;
+ }
+
+ /*Make a new element for the linked list*/
+ if ( (new = (ldif_Entry *)ldifentry_init( e )) == NULL){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ goto error_return;
+
+ }
+
+ /*Add the new element to the end of the list of entries in db*/
+ if ( update_db(pb, db, new, prev, LDIF_DB_ADD) != 0)
+ {
+ ldifentry_free( new );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ goto error_return;
+
+ }
+
+ /*We have been sucessful. Tell the user*/
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+
+ /*Release the database lock*/
+ PR_Unlock( db->ldif_lock );
+
+ /*Free the parentdn, and return*/
+ if ( parentdn != NULL ){
+ free( (void *)parentdn );
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_add\n", 0, 0, 0 );
+ return( 0 );
+
+ error_return:;
+ if ( parentdn != NULL ){
+ free( (void *)parentdn );
+ }
+
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+}
+
+/*
+ * Function: ldifentry_init
+ *
+ * Returns: a pointer to an ldif_Entry, or NULL
+ *
+ * Description: Takes a pointer to an Entry, and sticks
+ * it into an ldif_Entry structure.
+ * Note, uses Malloc.
+ */
+ldif_Entry *
+ldifentry_init(Slapi_Entry *e)
+{
+ ldif_Entry *new;
+
+ /*Alloc a new ldif_entry*/
+ new = (ldif_Entry *) malloc(sizeof(ldif_Entry));
+
+ /*Did it work? if not, return NULL*/
+ if (new == NULL) {
+ return (NULL);
+ }
+ /*If it did work, then fill it*/
+ new->lde_e = e;
+ new->next = NULL;
+
+ /*Send it*/
+ return (new);
+}
+
+
+
diff --git a/ldap/servers/slapd/back-ldif/back-ldif.h b/ldap/servers/slapd/back-ldif/back-ldif.h
new file mode 100644
index 00000000..5875c985
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/back-ldif.h
@@ -0,0 +1,94 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: back-ldif.h
+ *
+ * Description: This header file contains the definitions
+ * for the data structures used in the ldif backend database
+ */
+
+#define SLAPD_LOGGING 1
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+
+/* include NSPR header files */
+#include "prlock.h"
+
+#include "ldaplog.h"
+#include "portable.h"
+#include "dirver.h"
+#include "slap.h"
+
+#ifdef _WIN32
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#else
+#include <sys/socket.h>
+#endif /* _WIN32 */
+
+/*Defines*/
+#define LDIF_DB_ADD 0
+#define LDIF_DB_DELETE 1
+#define LDIF_DB_REPLACE 2
+
+
+/*This structure basically allows the entries to be linked listed*/
+struct ldif_entry{
+ Slapi_Entry *lde_e; /*ptr to the Entry datatype, but you knew that*/
+ struct ldif_entry *next; /*ptr to the next list element.*/
+};
+typedef struct ldif_entry ldif_Entry;
+
+
+/*Holds the data from the ldif file*/
+struct ldif {
+ long ldif_n; /*The number of entries in the database*/
+ long ldif_tries; /*The number of accesses to the database*/
+ long ldif_hits; /*The number of succesful searches to the db*/
+ char *ldif_file; /*From where we read the ldif data*/
+ PRLock *ldif_lock; /*Write & read lock.(a simple locking model)*/
+ ldif_Entry *ldif_entries; /*The linked list of entries*/
+};
+typedef struct ldif LDIF;
+
+
+/*Prototypes*/
+ int ldif_back_modify( Slapi_PBlock * );
+ int update_db(Slapi_PBlock *, LDIF *, ldif_Entry *, ldif_Entry *, int);
+ int db2disk(Slapi_PBlock *, LDIF *);
+ void ldifentry_free(ldif_Entry *);
+ ldif_Entry *ldifentry_dup(ldif_Entry *);
+ ldif_Entry *ldif_find_entry(Slapi_PBlock *, LDIF *, char *, ldif_Entry **);
+ int apply_mods( Slapi_Entry *, LDAPMod ** );
+
+ int ldif_back_add( Slapi_PBlock *);
+ ldif_Entry *ldifentry_init(Slapi_Entry *);
+ int ldif_back_config( Slapi_PBlock *);
+ static char * ldif_read_one_record( FILE *);
+ int ldif_back_delete( Slapi_PBlock *);
+ int has_children(LDIF *, ldif_Entry *);
+ int ldif_back_init( Slapi_PBlock *);
+
+ int ldif_back_search( Slapi_PBlock * );
+
+ int ldif_back_modrdn( Slapi_PBlock * );
+ static int rdn2typeval(char *, char **, struct berval *);
+ void add_mod( LDAPMod ***, int, char *, struct berval ** );
+
+ int ldif_back_bind( Slapi_PBlock * );
+ int ldif_back_unbind( Slapi_PBlock * );
+
+ int ldif_back_start( Slapi_PBlock * );
+ void ldif_back_close( Slapi_PBlock * );
+ void ldif_back_flush( Slapi_PBlock * );
+ void ldif_free_db(LDIF *);
+
+ int ldif_back_compare( Slapi_PBlock * );
+
+ char * get_monitordn(Slapi_PBlock * );
+ int ldif_back_monitor_info( Slapi_PBlock *pb, LDIF *db);
diff --git a/ldap/servers/slapd/back-ldif/bind.c b/ldap/servers/slapd/back-ldif/bind.c
new file mode 100644
index 00000000..b95a589f
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/bind.c
@@ -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 **/
+/*
+ * File: bind.c
+ *
+ * Functions:
+ *
+ * ldif_back_bind() - ldap ldif back-end bind routine
+ *
+ */
+
+#include "back-ldif.h"
+
+/*
+ * Function: ldif_back_bind
+ *
+ * Returns: returns 0|1 if good, -1 else.
+ *
+ * Description: performs an ldap bind.
+ */
+int
+ldif_back_bind( Slapi_PBlock *pb )
+{
+ char *dn; /*Storage for the dn*/
+ int method; /*Storage for the bind method*/
+ struct berval *cred; /*Storage for the bind credentials*/
+ struct berval **bvals;
+ LDIF *db; /*The database*/
+ ldif_Entry *e, *prev; /*Used for searching the db*/
+ int rc, syntax; /*Storage for error return values*/
+ Slapi_Attr *attr;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_bind\n", 0, 0, 0 );
+
+ prev = NULL;
+
+ /*Get the parameters*/
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_TARGET, &dn ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred ) < 0){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ /*Lock the database*/
+ PR_Lock( db->ldif_lock );
+
+
+ /*Find the entry that the person is attempting to bind as*/
+ if ( (e = (ldif_Entry *)ldif_find_entry( pb, db, dn, &prev )) == NULL ) {
+
+ /* Allow noauth binds */
+ if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
+ rc = SLAPI_BIND_ANONYMOUS;
+ } else {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ rc = SLAPI_BIND_FAIL;
+ }
+
+ /*Unlock the database*/
+ PR_Unlock( db->ldif_lock );
+
+ return( rc );
+ }
+
+ switch ( method ) {
+ case LDAP_AUTH_SIMPLE:
+ if ( cred->bv_len == 0 ) {
+ PR_Unlock( db->ldif_lock );
+ return( SLAPI_BIND_ANONYMOUS );
+ }
+
+ if ( slapi_entry_attr_find( e->lde_e, "userpassword", &attr ) != 0 ) {
+ slapi_send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( SLAPI_BIND_FAIL );
+ }
+ /*
+ * XXXmcs: slapi_attr_get_values() is deprecated and should be avoided
+ * See XXXmcs comments in ../attr.c for detailed information.
+ */
+ slapi_attr_get_values( attr, &bvals );
+
+ if ( slapi_pw_find( bvals, cred ) != 0 ) {
+ slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( SLAPI_BIND_FAIL );
+ }
+ break;
+
+ default:
+ slapi_send_ldap_result( pb, LDAP_STRONG_AUTH_NOT_SUPPORTED, NULL,
+ "auth method not supported", 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( SLAPI_BIND_FAIL );
+ }
+
+ PR_Unlock( db->ldif_lock );
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_bind\n", 0, 0, 0 );
+
+ /* success: front end will send result */
+ return( SLAPI_BIND_SUCCESS );
+}
diff --git a/ldap/servers/slapd/back-ldif/close.c b/ldap/servers/slapd/back-ldif/close.c
new file mode 100644
index 00000000..34048eca
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/close.c
@@ -0,0 +1,79 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: close.c
+ *
+ * Functions:
+ *
+ * ldif_back_close() - ldap ldif back-end close routine
+ *
+ */
+
+#include "back-ldif.h"
+
+/*
+ * Function: ldif_free_db
+ *
+ * Returns: void
+ *
+ * Description: frees up the ldif database
+ */
+void
+ldif_free_db(LDIF *db)
+{
+ ldif_Entry *cur; /*Used for walking down the list*/
+
+ /*If db is null, there is nothing to do*/
+ if (db == NULL) {
+ return;
+ }
+
+ /*Walk down the list, freeing up the ldif_entries*/
+ for (cur = db->ldif_entries; cur != NULL; cur = cur->next){
+ ldifentry_free(cur);
+ }
+
+ /*Free the ldif_file string, and then the db itself*/
+ free ((void *)db->ldif_file);
+ free((void *) db);
+}
+
+
+
+/*
+ * Function: ldif_back_close
+ *
+ * Returns: void
+ *
+ * Description: closes the ldif backend, frees up the database
+ */
+void
+ldif_back_close( Slapi_PBlock *pb )
+{
+ LDIF *db;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend syncing\n", 0, 0, 0 );
+ slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db );
+ ldif_free_db(db);
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend done syncing\n", 0, 0, 0 );
+}
+
+/*
+ * Function: ldif_back_flush
+ *
+ * Returns: void
+ *
+ * Description: does nothing
+ */
+void
+ldif_back_flush( Slapi_PBlock *pb )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend flushing\n", 0, 0, 0 );
+ LDAPDebug( LDAP_DEBUG_TRACE, "ldbm backend done flushing\n", 0, 0, 0 );
+ return;
+}
+
+
diff --git a/ldap/servers/slapd/back-ldif/compare.c b/ldap/servers/slapd/back-ldif/compare.c
new file mode 100644
index 00000000..bb0c3754
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/compare.c
@@ -0,0 +1,82 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: compare.c
+ *
+ * Functions:
+ *
+ * ldif_back_compare() - ldap ldif back-end compare routine
+ *
+ */
+
+#include "back-ldif.h"
+
+/*
+ * Function: ldif_back_compare
+ *
+ * Returns: -1, 0 or 1
+ *
+ * Description: compares entries in the ldif backend
+ */
+int
+ldif_back_compare( Slapi_PBlock *pb )
+{
+ LDIF *db; /*The Database*/
+ ldif_Entry *e, *prev; /*Used for searching the database*/
+ char *dn, *type; /*The dn and the type*/
+ struct berval *bval;
+ Slapi_Attr *attr;
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_compare\n", 0, 0, 0 );
+ prev = NULL;
+
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_COMPARE_TARGET, &dn ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_COMPARE_TYPE, &type ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_COMPARE_VALUE, &bval ) < 0){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ /*Lock the database*/
+ PR_Lock( db->ldif_lock );
+
+
+ /*Find the entry for comparison*/
+ if ( (e = (ldif_Entry*) ldif_find_entry( pb, db, dn, &prev )) == NULL ) {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( 1 );
+ }
+
+ /*Check the access*/
+ rc= slapi_access_allowed( pb, e->lde_e, type, bval, SLAPI_ACL_COMPARE );
+ if ( rc!=LDAP_SUCCESS ) {
+ slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( 1 );
+ }
+
+ /*find the attribute*/
+ if ( slapi_entry_attr_find( e->lde_e, type, &attr ) != 0 ) {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_ATTRIBUTE, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( 1 );
+ }
+
+ if ( slapi_attr_value_find( attr, bval ) == 0 ) {
+ slapi_send_ldap_result( pb, LDAP_COMPARE_TRUE, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( 0 );
+ }
+
+ slapi_send_ldap_result( pb, LDAP_COMPARE_FALSE, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_compare\n", 0, 0, 0 );
+ return( 0 );
+}
+
diff --git a/ldap/servers/slapd/back-ldif/config.c b/ldap/servers/slapd/back-ldif/config.c
new file mode 100644
index 00000000..a62335a5
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/config.c
@@ -0,0 +1,203 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: config.c
+ *
+ * Functions:
+ *
+ * ldif_back_config() - Reads in and stores ldif file for ldif backend
+ * ldif_read_one_record() - Reads in one record from ldif file as a string
+ *
+ */
+
+#include "back-ldif.h"
+#define LDAPMOD_MAXLINE 4096
+#define safe_realloc( ptr, size ) ( ptr == NULL ? malloc( size ) : \
+ realloc( ptr, size ))
+static char *ldif_read_one_record();
+
+
+/*
+ * Function: ldif_back_config
+ *
+ * Returns: 0 if success, -1 if not
+ *
+ * Description: Reads the data in the ldif file specified in ldif.conf
+ * stores it in db
+ */
+int
+ldif_back_config( Slapi_PBlock *pb )
+{
+ LDIF *db; /*The ldif file will be read into this structure*/
+ char *fname; /*Config file name*/
+ int lineno, argc; /*Config file stuff*/
+ char **argv; /*More config file stuff*/
+ FILE *fp; /*Pointer to ldif file*/
+ char *buf; /*Tmp storage for ldif entries*/
+ int first; /*Boolean to determine if db is empty*/
+ ldif_Entry *cur; /*For db manipulation*/
+ ldif_Entry *new; /*For db manipulation*/
+ Slapi_Entry *tmp; /*Used for initialization purposes*/
+
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_config\n", 0, 0, 0 );
+
+ /*
+ * Get the private_info structure you created in ldif_back_init().
+ * Also get the config file name, current line number, and arguments
+ * from the current line, broken out into an argv.
+ */
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_CONFIG_FILENAME, &fname ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_CONFIG_LINENO, &lineno ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_CONFIG_ARGC, &argc ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_CONFIG_ARGV, &argv ) < 0 ){
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to get data from front end\n", 0, 0, 0);
+ return(-1);
+ }
+
+
+ /*
+ * Process the config info. For example, if the config file
+ * contains a line like this:
+ *
+ * file /path/to/ldif/file
+ *
+ * then argv[0] would be "file", and argv[1] would be the file
+ * name.
+ */
+
+ /*Check for the correct number of arguments*/
+ if (argc != 2){
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: Unable to configure; invalid ldif input file specification line format (file: %s, line: %d)\n",
+ fname, lineno, 0);
+ return(-1);
+ }
+
+ /*Check for the right format*/
+ if (strcmp(argv[0], "file") != 0){
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to configure; invalid parameter \"%s\" in config file (file: %s, line: %d)\n",
+ argv[0], fname, lineno );
+ return(-1);
+ }
+
+ /*Now we fopen the file and grab up the contents*/
+ fp = fopen (argv[1], "r");
+ if (fp == NULL){
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to read ldif file %s\n", argv[1], 0, 0);
+ fp = fopen (argv[1], "w");
+ if(fp == NULL){
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to create ldif file %s\n", argv[1], 0, 0);
+ return -1;
+ }
+ }
+
+ first = 1;
+
+ /* Lock the database first, just to be safe*/
+ PR_Lock( db->ldif_lock );
+
+ /*Save the filename, for modifications to the file later*/
+ if ((db->ldif_file = strdup(argv[1])) == NULL){
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: out of memory\n", 0, 0, 0);
+ PR_Unlock( db->ldif_lock );
+ fclose(fp);
+ return(-1);
+ }
+
+ /*
+ * Loop through the entries in the file, and add them to the end
+ * of the linked list
+ */
+ while ((buf = ldif_read_one_record(fp)) != NULL){
+
+ /*Create a new element for the linked list of entries*/
+ tmp = (Slapi_Entry *) slapi_str2entry(buf,
+ SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF);
+ new = (ldif_Entry *) ldifentry_init(tmp);
+ if (new == NULL){
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to read in ldif file; out of memory\n",0 ,0 ,0 );
+ PR_Unlock( db->ldif_lock );
+ fclose(fp);
+ return(-1);
+ }
+
+ /*
+ * If this is the first entry we are adding,
+ * we have to make it the first element in the list
+ */
+ if (first){
+ db->ldif_entries = new;
+ first = 0;
+ } else{
+ cur->next = new;
+ }
+
+ /*Reset the pointer to the last element in the list*/
+ cur = new;
+
+ /*Increment the number of entries*/
+ db->ldif_n++;
+
+ /*Free the buffer*/
+ free ((void *) buf );
+
+ }
+
+ /*By now, the database should be read in*/
+ PR_Unlock( db->ldif_lock );
+ fclose(fp);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_config\n", 0, 0, 0 );
+ return( 0 );
+}
+
+
+
+/*
+ * Function: ldif_read_one_record
+ *
+ * Returns: a long string representing an ldif record
+ *
+ * Description: Returns a huge string comprised of 1 ldif record
+ * read from fp.
+ *
+ */
+static char *
+ldif_read_one_record( FILE *fp )
+{
+ int len, gotnothing;
+ char *buff, line[ LDAPMOD_MAXLINE ];
+ int lcur, lmax;
+
+ lcur = lmax = 0;
+ buff = NULL;
+ gotnothing = 1;
+
+ while ( fgets( line, sizeof(line), fp ) != NULL ) {
+ if ( (len = strlen( line )) < 2 ) {
+ if ( gotnothing ) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ gotnothing = 0;
+ if ( lcur + len + 1 > lmax ) {
+ lmax = LDAPMOD_MAXLINE
+ * (( lcur + len + 1 ) / LDAPMOD_MAXLINE + 1 );
+ if (( buff = (char *)safe_realloc( buff, lmax )) == NULL ) {
+ perror( "safe_realloc" );
+ exit( LDAP_NO_MEMORY );
+ }
+ }
+ strcpy( buff + lcur, line );
+ lcur += len;
+ }
+
+ return( buff );
+}
+
diff --git a/ldap/servers/slapd/back-ldif/delete.c b/ldap/servers/slapd/back-ldif/delete.c
new file mode 100644
index 00000000..cf155ad4
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/delete.c
@@ -0,0 +1,136 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: delete.c
+ *
+ * Functions:
+ *
+ * ldif_back_delete() - ldap ldif back-end delete routine
+ * has_children() - determines if an entry has any children
+ *
+ */
+
+#include "back-ldif.h"
+
+/*
+ * Function: ldif_back_delete
+ *
+ * Returns: returns 0 if good, -1 else.
+ *
+ * Description: For changetype: delete, this function deletes the entry
+ */
+int
+ldif_back_delete( Slapi_PBlock *pb )
+{
+ LDIF *db; /*The database*/
+ ldif_Entry *bye, *prev; /*"bye" is the record to be deleted*/
+ char *dn; /*Storage for the dn*/
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_delete\n", 0, 0, 0 );
+
+ prev = NULL;
+
+ /*Get the database and the dn to delete*/
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_DELETE_TARGET, &dn ) < 0){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ /*Lock the database*/
+ PR_Lock( db->ldif_lock );
+
+ /* Find the entry we're about to delete*/
+ bye = (ldif_Entry *) ldif_find_entry(pb, db, dn, &prev);
+ if (bye == NULL) {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ LDAPDebug( LDAP_DEBUG_TRACE, "entry for delete does not exist\n", 0, 0, 0 );
+ PR_Unlock( db->ldif_lock );
+ return(-1);
+ }
+
+ /*Make sure that we are trying to delete a leaf.*/
+ if ( has_children( db, bye ) ) {
+ slapi_send_ldap_result( pb, LDAP_NOT_ALLOWED_ON_NONLEAF, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+ }
+
+ /*Check the access*/
+ rc= slapi_access_allowed( pb, bye->lde_e, "entry", NULL, SLAPI_ACL_DELETE );
+ if ( rc!=LDAP_SUCCESS) {
+ slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+ }
+
+ /* Delete from disk and database */
+ if ( update_db(pb, db, NULL, prev, LDIF_DB_DELETE) != 0){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return(-1);
+
+ }
+
+ /*Success*/
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_delete\n", 0, 0, 0 );
+ return( 0 );
+}
+
+/*
+ * Function: has_children
+ *
+ * Returns: returns 1 if the entry has kids, 0 else.
+ *
+ * Description: Determines if the entry has children
+ */
+int
+has_children(LDIF *db, ldif_Entry *p)
+{
+ char *parentdn; /*Basically the dn of p (copied)*/
+ char *childdn; /*Will be used to test if p has any children*/
+ ldif_Entry *cur; /*Used to walk down the list*/
+ int has_kid = 0; /*Flag to return*/
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> has_children\n", 0, 0, 0);
+
+ /*If there is no p or db, then there can be no children*/
+ if (p == NULL || db == NULL){
+ return(0);
+ }
+
+ /*Get a copy of p's dn, and normalize it (squeeze any unneeded spaces out)*/
+ parentdn = strdup( slapi_entry_get_dn(p->lde_e) );
+ (void) slapi_dn_normalize( parentdn );
+
+ /*Walk down the list, seeing if each entry has p as a parent*/
+ for (cur = db->ldif_entries; cur != NULL; cur = cur->next){
+ childdn = strdup(slapi_entry_get_dn(cur->lde_e));
+ (void) slapi_dn_normalize(childdn);
+
+ /*Test to see if this childdn is a child of the parentdn*/
+ if (slapi_dn_issuffix( childdn, parentdn ) && strlen(childdn) > strlen(parentdn))
+ {
+ has_kid = 1;
+ free( (void *) childdn);
+ break;
+ }
+ free( (void *) childdn);
+
+ }
+
+ free( (void *) parentdn );
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= has_children %d\n", has_kid, 0, 0);
+ return( has_kid );
+}
+
+
+
+
diff --git a/ldap/servers/slapd/back-ldif/dllmain.c b/ldap/servers/slapd/back-ldif/dllmain.c
new file mode 100644
index 00000000..69d0ceb5
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/dllmain.c
@@ -0,0 +1,132 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for LIBLDAP DLL
+ */
+#include "ldap.h"
+
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored. */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
+
+#ifdef LDAP_DEBUG
+#ifndef _WIN32
+#include <stdarg.h>
+#include <stdio.h>
+
+void LDAPDebug( int level, char* fmt, ... )
+{
+ static char debugBuf[1024];
+
+ if (slapd_ldap_debug & level)
+ {
+ va_list ap;
+ va_start (ap, fmt);
+ _snprintf (debugBuf, sizeof(debugBuf), fmt, ap);
+ va_end (ap);
+
+ OutputDebugString (debugBuf);
+ }
+}
+#endif
+#endif
+
+#ifndef _WIN32
+
+/* The 16-bit version of the RTL does not implement perror() */
+
+#include <stdio.h>
+
+void perror( const char *msg )
+{
+ char buf[128];
+ wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ;
+ OutputDebugString( buf );
+}
+
+#endif
diff --git a/ldap/servers/slapd/back-ldif/init.c b/ldap/servers/slapd/back-ldif/init.c
new file mode 100644
index 00000000..8196d371
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/init.c
@@ -0,0 +1,114 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: init.c
+ *
+ * Functions:
+ *
+ * ldif_back_init() - ldap ldif back-end initialize routine
+ *
+ */
+
+#include "back-ldif.h"
+
+static Slapi_PluginDesc pdesc = { "ldif-backend", "Netscape", PRODUCTTEXT,
+ "LDIF backend database plugin" };
+
+#ifdef _WIN32
+int *module_ldap_debug = 0;
+
+void plugin_init_debug_level(int *level_ptr)
+{
+ module_ldap_debug = level_ptr;
+}
+#endif
+
+/*
+ * Function: ldif_back_init
+ *
+ * Returns: returns 0 if good, -1 else.
+ *
+ * Description: Allocates a database for filling by ldif_back_config
+ */
+int
+ldif_back_init( Slapi_PBlock *pb )
+{
+ LDIF *db; /*This will hold the ldif file in memory*/
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_init\n", 0, 0, 0 );
+
+ /*
+ * Allocate and initialize db with everything we
+ * need to keep track of in this backend. In ldif_back_config(),
+ * we will fill in db with things like the name
+ * of the ldif file containing the database, and any other
+ * options we allow people to set through the config file.
+ */
+
+ /*Allocate memory for our database and check if success*/
+ db = (LDIF *) malloc( sizeof(LDIF) );
+ if (db == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to initialize; out of memory\n", 0, 0, 0);
+ return(-1);
+ }
+
+ /*Fill with initial values, including the mutex*/
+ db->ldif_n = 0;
+ db->ldif_entries = NULL;
+ db->ldif_tries = 0;
+ db->ldif_hits = 0;
+ db->ldif_file = NULL;
+ db->ldif_lock = PR_NewLock();
+ if (&db->ldif_lock == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: Lock creation failed\n", 0, 0, 0);
+ return(-1);
+ }
+
+
+ /*
+ * set SLAPI_PLUGIN_PRIVATE field in pb, so it's available
+ * later in ldif_back_config(), ldif_back_search(), etc.
+ */
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_PRIVATE, (void *) db );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *) &pdesc );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ (void *) SLAPI_PLUGIN_VERSION_01 );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_BIND_FN,
+ (void *) ldif_back_bind );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_UNBIND_FN,
+ (void *) ldif_back_unbind );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_SEARCH_FN,
+ (void *) ldif_back_search );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_COMPARE_FN,
+ (void *) ldif_back_compare );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_MODIFY_FN,
+ (void *) ldif_back_modify );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_MODRDN_FN,
+ (void *) ldif_back_modrdn );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ADD_FN,
+ (void *) ldif_back_add );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_DELETE_FN,
+ (void *) ldif_back_delete );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_CONFIG_FN,
+ (void *) ldif_back_config );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *) ldif_back_close );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_FLUSH_FN,
+ (void *) ldif_back_flush );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN,
+ (void *) ldif_back_start );
+ if (rc != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Ldif Backend: unable to pass database information to front end\n",0 ,0 ,0);
+ return(-1);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_init\n", 0, 0, 0 );
+
+ return( 0 );
+}
+
+
diff --git a/ldap/servers/slapd/back-ldif/libback-ldif.def b/ldap/servers/slapd/back-ldif/libback-ldif.def
new file mode 100644
index 00000000..f4724f97
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/libback-ldif.def
@@ -0,0 +1,12 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Directory Server LDIF Backend Plugin'
+EXPORTS
+ ldif_back_init @2
+ plugin_init_debug_level @3
+
+
diff --git a/ldap/servers/slapd/back-ldif/modify.c b/ldap/servers/slapd/back-ldif/modify.c
new file mode 100644
index 00000000..53f0bb2e
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/modify.c
@@ -0,0 +1,557 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: modify.c
+ *
+ * Functions:
+ *
+ * ldif_back_modify() - ldif backend modify function
+ * update_db() - updates memory and disk db to reflect changes
+ * db2disk() - writes out ldif database to disk
+ * ldifentry_free() - frees an ldif_Entry
+ * ldifentry_dup() - copies an ldif_Entry
+ * ldif_find_entry() - searches an ldif DB for a particular dn
+ * apply_mods() - applies the modifications to an Entry
+ *
+ */
+
+#include "back-ldif.h"
+
+/*Prototypes*/
+void ldifentry_free(ldif_Entry *);
+ldif_Entry * ldifentry_dup(ldif_Entry *);
+int apply_mods( Slapi_Entry *, LDAPMod ** );
+ldif_Entry * ldif_find_entry(Slapi_PBlock *, LDIF *, char *, ldif_Entry **);
+int db2disk(Slapi_PBlock *, LDIF *);
+int update_db(Slapi_PBlock *, LDIF *, ldif_Entry *, ldif_Entry *, int );
+
+/*
+ * Function: ldif_back_modify
+ *
+ * Returns: returns 0 if good, -1 else.
+ *
+ * Description: For changetype: modify, this makes the changes
+ */
+int
+ldif_back_modify( Slapi_PBlock *pb )
+{
+ LDIF *db; /*The ldif file is stored here*/
+ ldif_Entry *entry, *entry2,*prev; /*For db manipulation*/
+ int err; /*House keeping stuff*/
+ LDAPMod **mods; /*Used to apply the modifications*/
+ char *dn; /*Storage for the dn*/
+ char *errbuf = NULL; /* To get error back */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_modify\n", 0, 0, 0 );
+ prev = NULL;
+
+ /*Get the database, the dn and the mods*/
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_MODIFY_TARGET, &dn ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ) < 0){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+ /*Lock the database*/
+ PR_Lock( db->ldif_lock );
+
+ /*
+ * Find the entry we are about to modify.
+ * prev will point to the previous element in the list,
+ * NULL if there is no previous element.
+ */
+ if ( (entry = (ldif_Entry *)ldif_find_entry( pb, db, dn, &prev)) == NULL ) {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+ }
+
+ /*Check acl, note that entry is not an Entry, but a ldif_Entry*/
+ if ( (err = slapi_acl_check_mods( pb, entry->lde_e, mods, &errbuf )) != LDAP_SUCCESS ) {
+ slapi_send_ldap_result( pb, err, NULL, errbuf, 0, NULL );
+ if (errbuf) free (errbuf);
+ PR_Unlock( db->ldif_lock );
+ goto error_return;
+ }
+
+ /* Create a copy of the entry and apply the changes to it */
+ if ( (entry2 = (ldif_Entry *) ldifentry_dup( entry )) == NULL ) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ goto error_return;
+ }
+
+ /*Actually apply the modifications*/
+ if ( (err = apply_mods( entry2->lde_e, mods )) != 0 ) {
+ slapi_send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ goto error_return;
+ }
+
+ /* Check for abandon */
+ if ( slapi_op_abandoned( pb ) ) {
+ PR_Unlock( db->ldif_lock );
+ goto error_return;
+ }
+
+ /* Check that the entry still obeys the schema */
+ if ( slapi_entry_schema_check( pb, entry2->lde_e ) != 0 ) {
+ slapi_send_ldap_result( pb, LDAP_OBJECT_CLASS_VIOLATION, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ goto error_return;
+ }
+
+ /* Check for abandon again */
+ if ( slapi_op_abandoned( pb ) ) {
+ PR_Unlock( db->ldif_lock );
+ goto error_return;
+ }
+
+ /* Change the entry itself both on disk and in the cache */
+ if ( update_db(pb, db, entry2, prev, LDIF_DB_REPLACE) != 0) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ goto error_return;
+ }
+
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_modify\n", 0, 0, 0 );
+ return( 0 );
+
+ error_return:;
+ if ( entry2 != NULL ) {
+ ldifentry_free( entry2 );
+ }
+
+ return( -1 );
+}
+
+/*
+ * Function: update_db
+ *
+ * Returns: returns 0 if good, -1 else.
+ *
+ * Description: Will update the database in memory, and on disk
+ * if prev == NULL, then the element to be deleted/replaced
+ * is the first in the list.
+ * mode = LDIF_DB_ADD | LDIF_DB_REPLACE | LDIF_DB_DELETE
+ * The database should be locked when this function is called.
+ * Note that on replaces and deletes, the old ldif_Entry's
+ * are freed.
+ */
+int
+update_db(Slapi_PBlock *pb, LDIF *db, ldif_Entry *new, ldif_Entry *prev, int mode)
+{
+ ldif_Entry *tmp; /*Used to free the removed/replaced entries*/
+ char *buf; /*Used to convert entries to strings for output to file*/
+ FILE *fp; /*File ptr to the ldif file*/
+ int len; /*Used by slapi_entry2str*/
+ int db_updated=0; /*Flag to designate if db in memory has been updated*/
+
+ /*Make sure that the database is not null. Everything else can be, though*/
+ if (db == NULL){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ /*
+ * If we are adding an entry, then prev should be pointing
+ * to the last element in the list, or null if the list is empty,
+ * and new should not be null.
+ */
+ if (mode == LDIF_DB_ADD) {
+
+ /*Make sure there is something to add*/
+ if ( new == NULL ) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ /*If prev is null, then there had better be no entries in the list*/
+ if (prev == NULL){
+ if( db->ldif_entries != NULL) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+ /*There are no elements, so let's add the new one*/
+ db->ldif_entries = new;
+ db->ldif_n++;
+
+ /*Set a flag*/
+ db_updated = 1;
+
+ }
+ /*
+ * Last error case to test for is if prev is not null, and prev->next
+ * points to something. This means that we are not at the end of the list
+ */
+ if (prev != NULL) {
+ if (prev->next != NULL) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ /*We're at the end of the list, so tack the new entry onto the end*/
+ prev->next = new;
+ db->ldif_n++;
+
+ db_updated = 1;
+
+ }
+
+ /*If the database has been updated in memory, update the disk*/
+ if (db_updated && db->ldif_file!=NULL) {
+
+ /*Update the disk by appending to the ldif file*/
+ fp = fopen(db->ldif_file, "a");
+ if (fp == NULL) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ /*This is s pretty serious problem, so we exit*/
+ exit(-1);
+ }
+
+ /*Convert the entry to ldif format*/
+ buf = slapi_entry2str(new->lde_e, &len);
+ fprintf(fp, "%s\n", buf);
+ free ( (void *) buf);
+ fclose(fp);
+ return(0);
+ } else {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ fclose(fp);
+ return(-1);
+
+ }
+
+ } else if (mode == LDIF_DB_DELETE){
+
+ /*We're not deleting the first entry in the list*/
+ if (prev != NULL){
+ /*Make sure there is something to delete*/
+ if (prev->next == NULL) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+ tmp = prev->next;
+ prev->next = tmp->next;
+ db->ldif_n--;
+ ldifentry_free(tmp);
+
+ db_updated = 1;
+
+ } else { /*We are deleting the first entry in the list*/
+
+ /*Make sure there is something to delete*/
+ if (db->ldif_entries == NULL) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ tmp = db->ldif_entries;
+ db->ldif_entries = tmp->next;
+ db->ldif_n--;
+
+ /*Free the entry, and set the flag*/
+ ldifentry_free(tmp);
+ db_updated = 1;
+ }
+
+ /*
+ * Update the disk by rewriting entire ldif file
+ * I know, I know, but simplicity is the key here.
+ */
+ if (db_updated) {
+ return(db2disk(pb, db));
+ } else {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+
+ }
+
+ } else if (mode == LDIF_DB_REPLACE) {
+
+ /*Make sure there is something to replace with*/
+ if ( new == NULL ) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+
+ /*We're not replacing the first element in the list*/
+ if (prev != NULL){
+
+ /*Make sure there is something to replace*/
+ if (prev->next == NULL) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ /*Splice out the old entry, and put in the new*/
+ tmp = prev->next;
+ prev->next = new;
+ new->next = tmp->next;
+
+ /*Free it*/
+ ldifentry_free(tmp);
+ db_updated = 1;
+ } else { /*We are replacing the first entry in the list*/
+
+ /*Make sure there is something to replace*/
+ if (db->ldif_entries == NULL) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ /*Splice out the old entry, and put in the new*/
+ tmp = db->ldif_entries;
+ db->ldif_entries = new;
+ new->next = tmp->next;
+
+ /*Free it*/
+ ldifentry_free(tmp);
+ db_updated = 1;
+ }
+
+ /*Update the disk by rewriting entire ldif file*/
+ if (db_updated) {
+ return(db2disk(pb, db));
+ } else {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ }
+}
+
+/*
+ * Function: db2disk
+ *
+ * Returns: returns 0 if good, exits else
+ *
+ * Description: Takes an ldif database, db, and writes it out to disk
+ * if it can't open the file, there's trouble, so we exit
+ * because this function is usually called after the db
+ * in memory has been updated.
+ *
+ */
+int
+db2disk(Slapi_PBlock *pb, LDIF *db)
+{
+ ldif_Entry *cur; /*Used for walking down the list*/
+ char *buf; /*temp storage for Entry->ldif converter*/
+ FILE *fp; /*File pointer to ldif target file*/
+ int len; /*length returned by slapi_entry2str*/
+
+ /*Open the file*/
+ fp = fopen(db->ldif_file, "w");
+ if (fp == NULL) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ /*This is s pretty serious problem, so we exit*/
+ exit(-1);
+ }
+
+ /*
+ * Walk down the list, converting each entry to a string,
+ * writing the string out to fp
+ */
+ for (cur = db->ldif_entries; cur != NULL; cur = cur->next){
+ buf = slapi_entry2str(cur->lde_e, &len);
+ fprintf(fp, "%s\n",buf);
+ free ( (void *) buf);
+ }
+
+ fclose(fp);
+ return(0);
+
+}
+
+
+/*
+ * Function: ldifentry_free
+ *
+ * Returns: void
+ *
+ * Description: Frees an ldif_Entry
+ */
+void
+ldifentry_free(ldif_Entry *e)
+{
+
+ /*Make sure that there is actually something to free*/
+ if (e == NULL){
+ return;
+ }
+
+ /*Free the entry*/
+ slapi_entry_free(e->lde_e);
+
+ /*Free the entire thing*/
+ free ((void *) e);
+}
+
+/*
+ * Function: ldifentry_dup
+ *
+ * Returns: a pointer to the new ldif_entry, or NULL
+ *
+ * Description: Copies and returns a pointer to a new
+ * ldif_Entry whose contents are a copy of e's contents
+ * Note: uses malloc
+ */
+ldif_Entry *
+ldifentry_dup(ldif_Entry *e)
+{
+ ldif_Entry *new;
+
+ /*Let's make sure that e is not null*/
+ if (e == NULL){
+ return(NULL);
+ }
+
+ /*Allocate a new ldif_entry, and return it if it is null*/
+ new = (ldif_Entry *) malloc( (sizeof(ldif_Entry)));
+ if (new == NULL) {
+ return(new);
+ }
+
+ /*Copy the Entry in e*/
+ new->lde_e = slapi_entry_dup(e->lde_e);
+ new->next = NULL;
+
+ return(new);
+
+
+}
+
+/*
+ * Function: ldif_find_entry
+ *
+ * Returns: A pointer to the matched ldif_Entry, or Null
+ *
+ * Description: Goes down the list of entries in db to find the entry
+ * matching dn. Returns a pointer to the entry,
+ * and sets prev to point to the entry before the match.
+ * If there is no match, prev points to the last
+ * entry in the list, and null is returned.
+ * If the first element matches, prev points to NULL
+ */
+ldif_Entry *
+ldif_find_entry(Slapi_PBlock *pb, LDIF *db, char *dn, ldif_Entry **prev)
+{
+ ldif_Entry *cur; /*Used for walking down the list*/
+ char *finddn, *targetdn; /*Copies of dns for searching */
+ int found_it = 0; /*A flag to denote a successful search*/
+
+ /*Set cur to the start of the list*/
+ cur =db->ldif_entries;
+
+ /*Increase the number of accesses*/
+ db->ldif_tries++;
+
+ /*Make a copy of the target dn, and normalize it*/
+ targetdn = strdup(dn);
+ (void) slapi_dn_normalize(targetdn);
+
+
+ /*Go down the list until we find the entry*/
+ while(cur != NULL) {
+ finddn = strdup(slapi_entry_get_dn(cur->lde_e));
+ (void) slapi_dn_normalize(finddn);
+
+
+ /*Test to see if we got the entry matching the dn*/
+ if (strcasecmp(targetdn, finddn) == 0)
+ {
+ found_it = 1;
+ free ((void *)finddn);
+ db->ldif_hits++;
+ break;
+ }
+
+ /*Udpate the pointers*/
+ *prev = cur;
+ cur = cur->next;
+ free ((void *)finddn);
+
+ }
+
+ free ((void *)targetdn);
+
+
+ /*
+ * If we didn't find a matching entry, we should
+ * return, and let the caller handle this (possible) error
+ */
+ if (!found_it){
+ return(NULL);
+ }
+
+ /*
+ * If the first entry matches, we have to set prev to null,
+ * so the caller knows.
+ */
+ if (*prev == cur){
+ *prev = NULL;
+ }
+
+ return( cur );
+}
+
+/*
+ * Function: apply_mods
+ *
+ * Returns: LDAP_SUCCESS if success
+ *
+ * Description: Applies the modifications specified in mods to e.
+ */
+int
+apply_mods( Slapi_Entry *e, LDAPMod **mods )
+{
+ int err, i, j;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> apply_mods\n", 0, 0, 0 );
+
+ err = LDAP_SUCCESS;
+ for ( j = 0; mods[j] != NULL; j++ ) {
+ switch ( mods[j]->mod_op & ~LDAP_MOD_BVALUES ) {
+ case LDAP_MOD_ADD:
+ LDAPDebug( LDAP_DEBUG_ARGS, " add: %s\n",
+ mods[j]->mod_type, 0, 0 );
+ err = slapi_entry_add_values( e, mods[j]->mod_type,
+ mods[j]->mod_bvalues );
+ break;
+
+ case LDAP_MOD_DELETE:
+ LDAPDebug( LDAP_DEBUG_ARGS, " delete: %s\n",
+ mods[j]->mod_type, 0, 0 );
+ err = slapi_entry_delete_values( e, mods[j]->mod_type,
+ mods[j]->mod_bvalues );
+ break;
+
+ case LDAP_MOD_REPLACE:
+ LDAPDebug( LDAP_DEBUG_ARGS, " replace: %s\n",
+ mods[j]->mod_type, 0, 0 );
+ err = entry_replace_values( e, mods[j]->mod_type,
+ mods[j]->mod_bvalues );
+ break;
+ }
+ for ( i = 0; mods[j]->mod_bvalues != NULL &&
+ mods[j]->mod_bvalues[i] != NULL; i++ ) {
+ LDAPDebug( LDAP_DEBUG_ARGS, " %s: %s\n",
+ mods[j]->mod_type, mods[j]->mod_bvalues[i]->bv_val,
+ 0 );
+ }
+ LDAPDebug( LDAP_DEBUG_ARGS, " -\n", 0, 0, 0 );
+
+ if ( err != LDAP_SUCCESS ) {
+ break;
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= apply_mods %d\n", err, 0, 0 );
+ return( err );
+}
diff --git a/ldap/servers/slapd/back-ldif/modrdn.c b/ldap/servers/slapd/back-ldif/modrdn.c
new file mode 100644
index 00000000..d2dfcdb8
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/modrdn.c
@@ -0,0 +1,282 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: modrdn.c
+ *
+ * Functions:
+ *
+ * ldif_back_modrdn() - ldap ldif back-end modrdn routine
+ * rdn2typval() - rdn to typval converter
+ * ldif_add_mod() - Adds a modification to be performed.
+ *
+ */
+
+#include "back-ldif.h"
+int rdn2typval(char *, char **, struct berval *);
+void ldif_add_mod( LDAPMod ***, int, char *, struct berval ** );
+
+/*
+ * Function: ldif_back_modrdn
+ *
+ * Returns: returns 0 if good, -1 else.
+ *
+ * Description: For changetype: modrdn, this modifies the rdn of the entry
+ */
+int
+ldif_back_modrdn( Slapi_PBlock *pb )
+{
+ LDIF *db; /*ldif backend database*/
+ ldif_Entry *prev, *tprev, *entry, *entry2, *test;
+ char *pdn, *newdn; /*Used for dn manipulation*/
+ char *dn, *newrdn, *type; /*Used for dn manipulation*/
+ int i; /*A counter*/
+ char **rdns, **dns; /*Used for dn manipulation*/
+ int deleteoldrdn; /*Flag from user to delete old rdn*/
+ struct berval bv;
+ struct berval *bvps[2];
+ LDAPMod **mods; /*Holds the list of modifications*/
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_modrdn\n", 0, 0, 0 );
+
+ prev = NULL;
+
+ /*Get the information from the front end, including the database*/
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db )< 0 ||
+ slapi_pblock_get( pb, SLAPI_MODRDN_TARGET, &dn ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &deleteoldrdn ) <0){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+
+ }
+
+ /*Lock the database*/
+ PR_Lock( db->ldif_lock );
+
+ /*
+ * Find the entry we are about to modify
+ * prev will point to the previous element in the list,
+ * NULL if there is no previous element
+ */
+ if ( (entry = (ldif_Entry *)ldif_find_entry( pb, db, dn, &prev)) == NULL ) {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+ }
+
+ /*Make sure that we are trying to modify the rdn of a leaf.*/
+ if ( has_children( db, entry ) ) {
+ slapi_send_ldap_result( pb, LDAP_NOT_ALLOWED_ON_NONLEAF, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+ }
+
+
+ /* Create a copy of the entry and apply the changes to it */
+ if ( (entry2 = (ldif_Entry *)ldifentry_dup( entry )) == NULL ) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+ }
+
+ /*Check the access*/
+ rc= slapi_access_allowed( pb, entry2->lde_e, NULL, NULL, SLAPI_ACL_WRITE );
+ if ( rc!=LDAP_SUCCESS ) {
+ slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL );
+ ldifentry_free( entry2 );
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+ }
+
+ /* Construct the new dn */
+ if ( (pdn = slapi_dn_beparent( pb, dn )) != NULL ) {
+
+ /* parent + rdn + separator(s) + null */
+ newdn = (char *) malloc( strlen( pdn ) + strlen( newrdn ) + 3 );
+ if (newdn == NULL){
+ LDAPDebug( LDAP_DEBUG_ANY,"malloc failed", 0, 0, 0 );
+ exit(1);
+ }
+
+ strcpy( newdn, newrdn );
+ strcat( newdn, ", " );
+ strcat( newdn, pdn );
+ } else {
+ newdn = strdup( newrdn );
+ }
+ free( pdn );
+
+ /*Normalize the newdn, that is, squeeze out all unnecessary spaces*/
+ (void) slapi_dn_normalize( newdn );
+
+
+ /* Add the new dn to our working copy of the entry */
+ slapi_entry_set_dn( entry2->lde_e, newdn );
+
+
+ /* See if an entry with the new name already exists */
+ if ( (test = (ldif_Entry *)ldif_find_entry( pb, db, newdn, &tprev )) != NULL ) {
+ slapi_send_ldap_result( pb, LDAP_ALREADY_EXISTS, NULL, NULL, 0, NULL );
+
+ goto error_return;
+ }
+
+
+ /*
+ * Delete old rdn values from the entry if deleteoldrdn is set.
+ * Add new rdn values to the entry.
+ */
+ mods = NULL;
+ bvps[0] = &bv;
+ bvps[1] = NULL;
+ if ( (dns = ldap_explode_dn( dn, 0 )) != NULL ) {
+ if ( (rdns = ldap_explode_rdn( dns[0], 0 )) != NULL ) {
+ for ( i = 0; rdns[i] != NULL; i++ ) {
+
+ /* Delete from entry attributes */
+ if ( deleteoldrdn && rdn2typval( rdns[i], &type, &bv ) == 0 ) {
+ ldif_add_mod( &mods, LDAP_MOD_DELETE, type, bvps );
+ }
+ }
+ ldap_value_free( rdns );
+ }
+ ldap_value_free( dns );
+ }
+ if ( dns == NULL || rdns == NULL ) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ goto error_return;
+ }
+ /* Add new rdn values to the entry */
+ if ( (rdns = ldap_explode_rdn( newrdn, 0 )) != NULL ) {
+ for ( i = 0; rdns[i] != NULL; i++ ) {
+ /* Add to entry */
+ if ( rdn2typval( rdns[i], &type, &bv ) == 0 ) {
+ ldif_add_mod( &mods, LDAP_MOD_ADD, type, bvps );
+ }
+ }
+ ldap_value_free( rdns );
+ } else {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ goto error_return;
+ }
+ bv.bv_val = newdn;
+ bv.bv_len = strlen( newdn );
+ ldif_add_mod( &mods, LDAP_MOD_REPLACE, "entrydn", bvps );
+
+ /* Check for abandon */
+ if ( slapi_op_abandoned( pb ) ) {
+ goto error_return;
+ }
+
+ /* Apply the mods we built above to the copy of the entry */
+ if ( apply_mods( entry2->lde_e, mods ) != 0 ) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+
+ goto error_return;
+ }
+
+ /* Update the database and the disk */
+ if ( update_db(pb, db, entry2, prev, LDIF_DB_REPLACE) != 0) {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+
+ goto error_return;
+ }
+
+ /*Unlock the database, and tell the user the good news*/
+ PR_Unlock( db->ldif_lock );
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_modrdn\n", 0, 0, 0 );
+ return( 0 );
+
+error_return:;
+
+ /* Result already sent above - just free stuff */
+ PR_Unlock( db->ldif_lock );
+ ldifentry_free( entry2 );
+
+ return( -1 );
+}
+
+/*
+ * Function: rdn2typval
+ *
+ * Returns: returns 0 if good, -1 else.
+ *
+ * Description: converts an rdn to a typeval
+ */
+int
+rdn2typval(char *rdn, char **type, struct berval *bv)
+{
+ char *s;
+
+ if ( (s = strchr( rdn, '=' )) == NULL ) {
+ return( -1 );
+ }
+ *s++ = '\0';
+
+ *type = rdn;
+ bv->bv_val = s;
+ bv->bv_len = strlen( s );
+
+ return( 0 );
+}
+
+/*
+ * Function: ldif_add_mod
+ *
+ * Returns: void
+ *
+ * Description: Adds a modification (add, delete, etc) to the list
+ * of modifications that will eventually be made to some entry
+ */
+void
+ldif_add_mod( LDAPMod ***modlist, int modtype, char *type, struct berval **bvps )
+{
+ int i;
+
+ for ( i = 0; modlist[i] != NULL; i++ ) {
+ ; /* NULL */
+ }
+
+ *modlist = (LDAPMod **) realloc( (char *) *modlist,
+ (i + 2) * sizeof(LDAPMod *) );
+
+ if (*modlist == NULL){
+ LDAPDebug( LDAP_DEBUG_ANY, "realloc failed", 0, 0, 0 );
+ exit(1);
+ }
+ (*modlist)[i] = (LDAPMod *) malloc( sizeof(LDAPMod) );
+
+ if ((*modlist)[i] == NULL){
+ LDAPDebug( LDAP_DEBUG_ANY,"malloc failed", 0, 0, 0 );
+ exit(1);
+ }
+
+ (*modlist)[i]->mod_type = (char *) strdup( type );
+ if ((*modlist)[i]->mod_type == NULL){
+ LDAPDebug( LDAP_DEBUG_ANY,"strdup failed", 0, 0, 0 );
+ exit(1);
+ }
+
+
+ (*modlist)[i]->mod_op = modtype;
+ (*modlist)[i]->mod_bvalues = (struct berval **) malloc(2*sizeof(struct berval *));
+ if ((*modlist)[i]->mod_bvalues == NULL){
+ LDAPDebug( LDAP_DEBUG_ANY,"malloc failed",0, 0, 0 );
+ exit(1);
+ }
+ (*modlist)[i]->mod_bvalues[0] = ber_bvdup( bvps[0] );
+ (*modlist)[i]->mod_bvalues[1] = NULL;
+ (*modlist)[i+1] = NULL;
+}
+
+
+
+
+
+
+
diff --git a/ldap/servers/slapd/back-ldif/monitor.c b/ldap/servers/slapd/back-ldif/monitor.c
new file mode 100644
index 00000000..b4b721b0
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/monitor.c
@@ -0,0 +1,124 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: monitor.c
+ *
+ * Functions:
+ *
+ * ldif_back_monitor_info() - ldap ldif back-end initialize routine
+ *
+ * get_monitordn() - gets the monitor dn for this backend
+ *
+ */
+
+#include "back-ldif.h"
+
+extern char Versionstr[];
+
+
+/*
+ * Function: ldif_back_monitor_info
+ *
+ * Returns: returns 1
+ *
+ * Description: This function wraps up backend specific monitor information
+ * and returns it to the client as an entry. This function
+ * is usually called by ldif_back_search upon receipt of
+ * the monitor dn for this backend.
+ */
+int
+ldif_back_monitor_info( Slapi_PBlock *pb, LDIF *db)
+{
+ Slapi_Entry *e; /*Entry*/
+ char buf[BUFSIZ]; /*Buffer for getting the attrs*/
+ struct berval val; /*More attribute storage*/
+ struct berval *vals[2]; /*Even more*/
+ char *type; /*Database name (type) */
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /*Alloc the entry and set the monitordn*/
+ e = slapi_entry_alloc();
+ slapi_entry_set_dn(e, (char *) get_monitordn(pb));
+
+ /* Get the database name (be_type) */
+ slapi_pblock_get( pb, SLAPI_BE_TYPE, &type);
+ sprintf( buf, "%s", type );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_merge( e, "database", vals );
+
+ /*Lock the database*/
+ PR_Lock( db->ldif_lock );
+
+ /*Get the number of database hits */
+ sprintf( buf, "%ld", db->ldif_hits);
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_merge( e, "entrycachehits", vals );
+
+ /*Get the number of database tries */
+ sprintf( buf, "%ld", db->ldif_tries);
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_merge( e, "entrycachetries", vals );
+
+ /*Get the current size of the entrycache (db) */
+ sprintf( buf, "%ld", db->ldif_n);
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_merge( e, "currententrycachesize", vals );
+
+
+ /*
+ * Get the maximum size of the entrycache (db)
+ * in this database, there is no max, so return the current size
+ */
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ slapi_entry_attr_merge( e, "maxentrycachesize", vals );
+
+ /* Release the lock*/
+ PR_Unlock( db->ldif_lock );
+
+ /*Send the results back to the client*/
+ slapi_send_ldap_search_entry( pb, e, NULL, NULL, 0 );
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 1, NULL );
+
+ slapi_entry_free( e );
+
+ return(1);
+
+
+}
+
+
+/*
+ * Function: get_monitordn
+ *
+ * Returns: returns ptr to string if success, NULL else
+ *
+ * Description: get_monitordn takes a pblock and extracts the
+ * monitor dn of this backend. The monitordn is a special
+ * signal to the backend to return backend specific monitor
+ * information (usually called by back_ldif_search()).
+ */
+char *
+get_monitordn(Slapi_PBlock *pb )
+{
+ char *mdn;
+
+ slapi_pblock_get( pb, SLAPI_BE_MONITORDN, &mdn );
+
+ if (mdn == NULL) {
+ return(NULL);
+
+ }
+
+ return(strdup(mdn));
+
+}
diff --git a/ldap/servers/slapd/back-ldif/search.c b/ldap/servers/slapd/back-ldif/search.c
new file mode 100644
index 00000000..1f9adbfb
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/search.c
@@ -0,0 +1,197 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: search.c
+ *
+ * Functions:
+ *
+ * ldif_back_search() - ldif backend search function
+ *
+ */
+
+#include "back-ldif.h"
+
+/*
+ * Function: ldif_back_search
+ *
+ * Returns: returns 0 if good, -1 else.
+ *
+ * Description: Searches the database for entries satisfying the
+ * user's criteria
+ */
+int
+ldif_back_search( Slapi_PBlock *pb )
+{
+ LDIF *db; /*The database*/
+ char *base; /*Base of the search*/
+ int scope; /*Scope of the search*/
+ int deref; /*Should we dereference aliases?*/
+ int slimit; /*Size limit of the search*/
+ int tlimit; /*Time limit of the search*/
+ Slapi_Filter *filter; /*The filter*/
+ time_t dummy=0; /*Used for time()*/
+ char **attrs; /*Attributes*/
+ int attrsonly; /*Should we just return the attributes found?*/
+ time_t optime; /*Time the operation started*/
+ int nentries; /*Number of entries found thus far*/
+ ldif_Entry *cur; /*Used for traversing the list of entries*/
+ int hitflag=0; /*Used to test if we found the entry in the db*/
+ char *freeme; /*Tmp storage for monitordn*/
+ time_t currtime; /*The current time*/
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ldif_back_search\n", 0, 0, 0 );
+
+ /*
+ * Get private information created in the init routine.
+ * Also get the parameters of the search operation. These come
+ * more or less directly from the client.
+ */
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &db ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_DEREF, &deref ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &slimit ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &tlimit ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly ) <0 ||
+ slapi_pblock_get( pb, SLAPI_OPINITIATED_TIME, &optime ) < 0){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+
+ /*
+ * If we get a search request for the backend monitor dn,
+ * call ldif_back_monitor_info(), which packages up the
+ * backend database analysis info and sends it back to the
+ * client
+ */
+ if ( scope == LDAP_SCOPE_BASE ) {
+
+ /*Get the backend's monitor dn*/
+ freeme = (char *) get_monitordn(pb);
+
+ if (freeme != NULL){
+
+ /*
+ * Compare the monitor dn with the base,
+ * if they match, call monitor_info, which
+ * will return all the relevant info to the client
+ */
+ if ( strcasecmp( base, freeme) == 0 ) {
+ ldif_back_monitor_info( pb, db );
+ free ((void *) freeme);
+ return(-1);
+ }
+ free ((void *) freeme);
+ }
+ }
+
+
+ /*
+ * First we lock the whole database (clumsy, inefficient and
+ * inelegant, but simple)
+ */
+ PR_Lock( db->ldif_lock );
+
+ /*Increase the number of accesses*/
+ db->ldif_tries++;
+
+ /*
+ * Look through each entry in the ldif file and see if it matches
+ * the filter and scope of the search. Do this by calling the
+ * slapi_filter_test() routine.
+ */
+ nentries = 0;
+ for (cur=db->ldif_entries; cur != NULL; cur = cur->next ) {
+
+ /*Make sure we're not exceeding our time limit...*/
+ currtime = time(&dummy);
+ if ((tlimit > 0) && ((currtime - optime) > tlimit)){
+ slapi_send_ldap_result( pb, LDAP_TIMELIMIT_EXCEEDED, NULL, NULL, nentries, NULL);
+
+ /*We "hit" the cache*/
+ if (hitflag)
+ {
+ db->ldif_hits++;
+ }
+
+ PR_Unlock( db->ldif_lock );
+ return(-1);
+ }
+
+ /*...or that we haven't been abandoned*/
+ if ( slapi_op_abandoned( pb ) ) {
+
+ /*We "hit" the cache*/
+ if (hitflag)
+ {
+ db->ldif_hits++;
+ }
+
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+ }
+
+ /*Test for exceedence of size limit*/
+ if ((slimit > -1) && (nentries >= slimit)){
+ slapi_send_ldap_result( pb, LDAP_SIZELIMIT_EXCEEDED, NULL, NULL, nentries, NULL);
+
+ /*We hit the "cache"*/
+ if (hitflag)
+ {
+ db->ldif_hits++;
+ }
+ PR_Unlock( db->ldif_lock );
+ return(-1);
+ }
+
+
+
+ /*Test if this entry matches the filter*/
+ if ( slapi_vattr_filter_test( pb, cur->lde_e, filter, 1 /* verify access */ ) == 0 ) {
+
+ /* Entry matches - send it */
+ hitflag = 1;
+
+ switch ( slapi_send_ldap_search_entry( pb, cur->lde_e, NULL, attrs,
+ attrsonly ) ) {
+ case 0: /* Entry sent ok */
+ nentries++;
+ break;
+ case 1: /* Entry not sent - because of acl, etc. */
+ break;
+ case -1:/* Connection closed */
+ /* Clean up and return */
+
+ /*We "hit" the cache*/
+ if (hitflag)
+ {
+ db->ldif_hits++;
+ }
+ PR_Unlock( db->ldif_lock );
+ return( -1 );
+ }
+
+
+ }
+ }
+
+ /*If we succeeded, we should update the ldif_hits entry of db*/
+ if (hitflag)
+ {
+ db->ldif_hits++;
+ }
+
+
+ /* Search is done, send LDAP_SUCCESS */
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, nentries, NULL );
+ PR_Unlock( db->ldif_lock );
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ldif_back_search\n", 0, 0, 0 );
+ return( -1 );
+
+}
diff --git a/ldap/servers/slapd/back-ldif/start.c b/ldap/servers/slapd/back-ldif/start.c
new file mode 100644
index 00000000..4e22cb08
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/start.c
@@ -0,0 +1,31 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: start.c
+ *
+ * Functions:
+ *
+ * ldif_back_start() - ldap ldif back-end start routine
+ *
+ */
+#include "back-ldif.h"
+
+/*
+ * Function: ldif_back_start
+ *
+ * Returns: returns 0
+ *
+ * Description: After the config file is read, the backend start function is called.
+ * This allows the backend writer to start any threads or perform any
+ * operations that need to be done after the config file has been read in.
+ * The ldif backend requires no such operations to be performed.
+ *
+ */
+int
+ldif_back_start( Slapi_PBlock *pb )
+{
+ return( 0 );
+}
diff --git a/ldap/servers/slapd/back-ldif/unbind.c b/ldap/servers/slapd/back-ldif/unbind.c
new file mode 100644
index 00000000..77c45adb
--- /dev/null
+++ b/ldap/servers/slapd/back-ldif/unbind.c
@@ -0,0 +1,27 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * File: unbind.c
+ *
+ * Functions:
+ *
+ * ldif_back_unbind() - ldap ldif back-end unbind routine
+ *
+ */
+#include "back-ldif.h"
+
+/*
+ * Function: ldif_back_unbind
+ *
+ * Returns: returns 0
+ *
+ * Description: performs an ldap unbind.
+ */
+int
+ldif_back_unbind( Slapi_PBlock *pb )
+{
+ return( 0 );
+}
diff --git a/ldap/servers/slapd/backend.c b/ldap/servers/slapd/backend.c
new file mode 100644
index 00000000..f4ffcc87
--- /dev/null
+++ b/ldap/servers/slapd/backend.c
@@ -0,0 +1,505 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* backend.c - Slapi_Backend methods */
+
+#include "slap.h"
+
+void
+be_init( Slapi_Backend *be, const char *type, const char *name, int isprivate, int logchanges, int sizelimit, int timelimit )
+{
+ char text[128];
+ slapdFrontendConfig_t *fecfg;
+ be->be_suffix = NULL;
+ be->be_suffixlock= PR_NewLock();
+ be->be_suffixcount= 0;
+ /* e.g. dn: cn=config,cn=NetscapeRoot,cn=ldbm database,cn=plugins,cn=config */
+ sprintf(text, "cn=%s,cn=%s,cn=plugins,cn=config", name, type);
+ be->be_basedn= slapi_ch_strdup(slapi_dn_normalize(text));
+ sprintf(text, "cn=config,cn=%s,cn=%s,cn=plugins,cn=config", name, type);
+ be->be_configdn= slapi_ch_strdup(slapi_dn_normalize(text));
+ sprintf(text, "cn=monitor,cn=%s,cn=%s,cn=plugins,cn=config", name, type);
+ be->be_monitordn= slapi_ch_strdup(slapi_dn_normalize(text));
+ be->be_sizelimit = sizelimit;
+ be->be_timelimit = timelimit;
+ /* maximum group nesting level before giving up */
+ be->be_maxnestlevel = SLAPD_DEFAULT_GROUPNESTLEVEL;
+ be->be_noacl= 0;
+ be->be_flags=0;
+ if (( fecfg = getFrontendConfig()) != NULL )
+ {
+ if ( fecfg->backendconfig != NULL && fecfg->backendconfig[ 0 ] != NULL )
+ {
+ be->be_backendconfig = slapi_ch_strdup( fecfg->backendconfig[0] );
+ }
+ else
+ {
+ be->be_backendconfig= NULL;
+ }
+ be->be_readonly = fecfg->readonly;
+ }
+ else
+ {
+ be->be_readonly= 0;
+ be->be_backendconfig= NULL;
+ }
+ be->be_lastmod = LDAP_UNDEFINED;
+ be->be_type = slapi_ch_strdup(type);
+ be->be_include = NULL;
+ be->be_private = isprivate;
+ be->be_logchanges = logchanges;
+ be->be_database = NULL;
+ be->be_writeconfig = NULL;
+ be->be_delete_on_exit = 0;
+ be->be_state = BE_STATE_STOPPED;
+ be->be_state_lock = PR_NewLock();
+ be->be_name = slapi_ch_strdup(name);
+ be->be_mapped = 0;
+}
+
+void
+be_done(Slapi_Backend *be)
+{
+ int i;
+
+ for(i=0;i<be->be_suffixcount;i++)
+ {
+ slapi_sdn_free(&be->be_suffix[i]);
+ }
+ slapi_ch_free((void**)&be->be_suffix);
+ PR_DestroyLock(be->be_suffixlock);
+ slapi_ch_free((void **)&be->be_basedn);
+ slapi_ch_free((void **)&be->be_configdn);
+ slapi_ch_free((void **)&be->be_monitordn);
+ slapi_ch_free((void **)&be->be_type);
+ slapi_ch_free((void **)&be->be_backendconfig);
+ /* JCM char **be_include; ??? */
+ slapi_ch_free((void **)&be->be_name);
+ PR_DestroyLock(be->be_state_lock);
+}
+
+void
+slapi_be_delete_onexit (Slapi_Backend *be)
+{
+ be->be_delete_on_exit = 1;
+}
+
+void
+slapi_be_set_readonly(Slapi_Backend *be, int readonly)
+{
+ be->be_readonly = readonly;
+}
+
+int
+slapi_be_get_readonly(Slapi_Backend *be)
+{
+ return be->be_readonly;
+}
+
+/*
+ * Check if suffix, exactly matches a registered
+ * suffix of this backend.
+ */
+int
+slapi_be_issuffix( const Slapi_Backend *be, const Slapi_DN *suffix )
+{
+ int r= 0;
+ /* this backend is no longer valid */
+ if (be->be_state != BE_STATE_DELETED)
+ {
+ int i;
+ PR_Lock(be->be_suffixlock);
+ for ( i = 0; be->be_suffix != NULL && i<be->be_suffixcount; i++ )
+ {
+ if ( slapi_sdn_compare( be->be_suffix[i], suffix ) == 0)
+ {
+ r= 1;
+ break;
+ }
+ }
+ PR_Unlock(be->be_suffixlock);
+ }
+ return r;
+}
+
+void
+be_addsuffix(Slapi_Backend *be,const Slapi_DN *suffix)
+{
+ if (be->be_state != BE_STATE_DELETED)
+ {
+ PR_Lock(be->be_suffixlock);
+ if(be->be_suffix==NULL)
+ {
+ be->be_suffix= (Slapi_DN **)slapi_ch_malloc(sizeof(Slapi_DN *));
+ }
+ else
+ {
+ be->be_suffix= (Slapi_DN **)slapi_ch_realloc((char*)be->be_suffix,(be->be_suffixcount+1)*sizeof(Slapi_DN *));
+ }
+ be->be_suffix[be->be_suffixcount]= slapi_sdn_dup(suffix);
+ be->be_suffixcount++;
+ PR_Unlock(be->be_suffixlock);
+ }
+}
+
+void slapi_be_addsuffix(Slapi_Backend *be,const Slapi_DN *suffix)
+{
+ be_addsuffix(be,suffix);
+}
+
+/*
+ * The caller may use the returned pointer without holding the
+ * be_suffixlock since we never remove suffixes from the array.
+ * The Slapi_DN pointer will always be valid even though the array
+ * itself may be changing due to the addition of a suffix.
+ */
+const Slapi_DN *
+slapi_be_getsuffix(Slapi_Backend *be,int n)
+{
+ Slapi_DN *sdn = NULL;
+
+ if(NULL == be)
+ return NULL;
+
+ if(be->be_state != BE_STATE_DELETED) {
+ PR_Lock(be->be_suffixlock);
+ if (be->be_suffix !=NULL && n<be->be_suffixcount) {
+ sdn = be->be_suffix[n];
+ }
+ PR_Unlock(be->be_suffixlock);
+ }
+ return sdn;
+}
+
+const char *
+slapi_be_gettype(Slapi_Backend *be)
+{
+ const char *r= NULL;
+ if (be->be_state != BE_STATE_DELETED)
+ {
+ r= be->be_type;
+ }
+ return r;
+}
+
+Slapi_DN *
+be_getconfigdn(Slapi_Backend *be, Slapi_DN *dn)
+{
+ if (be->be_state == BE_STATE_DELETED)
+ {
+ slapi_sdn_set_ndn_byref(dn,NULL);
+ }
+ else
+ {
+ slapi_sdn_set_ndn_byref(dn,be->be_configdn);
+ }
+ return dn;
+}
+
+Slapi_DN *
+be_getmonitordn(Slapi_Backend *be, Slapi_DN *dn)
+{
+ if (be->be_state == BE_STATE_DELETED)
+ {
+ slapi_sdn_set_ndn_byref(dn,NULL);
+ }
+ else
+ {
+ slapi_sdn_set_ndn_byref(dn,be->be_monitordn);
+ }
+ return dn;
+}
+
+int
+be_writeconfig ( Slapi_Backend *be )
+{
+ Slapi_PBlock *newpb;
+
+ if (be->be_state == BE_STATE_DELETED || be->be_private ||
+ (be->be_writeconfig == NULL) ) {
+ return -1;
+ }
+ else {
+ newpb = slapi_pblock_new();
+ slapi_pblock_set ( newpb, SLAPI_PLUGIN, (void *) be->be_database );
+ slapi_pblock_set ( newpb, SLAPI_BACKEND, (void *) be );
+ (be->be_writeconfig)(newpb);
+ slapi_pblock_destroy ( newpb );
+ return 1;
+ }
+}
+
+/*
+ * Find out if changes made to entries in this backend
+ * should be recorded in the changelog.
+ */
+int
+slapi_be_logchanges(Slapi_Backend *be)
+{
+ if (be->be_state == BE_STATE_DELETED)
+ return 0;
+
+ return be->be_logchanges;
+}
+
+int
+slapi_be_private ( Slapi_Backend *be )
+{
+ if ( be!=NULL )
+ {
+ return (be->be_private);
+ }
+
+ return 0;
+}
+
+void *
+slapi_be_get_instance_info(Slapi_Backend * be)
+{
+ PR_ASSERT(NULL != be);
+ return be->be_instance_info;
+}
+
+void
+slapi_be_set_instance_info(Slapi_Backend * be, void * data)
+{
+ PR_ASSERT(NULL != be);
+ be->be_instance_info=data;
+}
+
+int
+slapi_be_getentrypoint(Slapi_Backend *be, int entrypoint, void **ret_fnptr, Slapi_PBlock *pb)
+{
+ PR_ASSERT(NULL != be);
+
+ /* this is something needed for most of the entry points */
+ if (pb)
+ {
+ slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database );
+ slapi_pblock_set( pb, SLAPI_BACKEND, be );
+ }
+
+ switch (entrypoint) {
+ case SLAPI_PLUGIN_DB_BIND_FN:
+ *ret_fnptr = (void*)be->be_bind;
+ break;
+ case SLAPI_PLUGIN_DB_UNBIND_FN:
+ *ret_fnptr = (void*)be->be_unbind;
+ break;
+ case SLAPI_PLUGIN_DB_SEARCH_FN:
+ *ret_fnptr = (void*)be->be_search;
+ break;
+ case SLAPI_PLUGIN_DB_COMPARE_FN:
+ *ret_fnptr = (void*)be->be_compare;
+ break;
+ case SLAPI_PLUGIN_DB_MODIFY_FN:
+ *ret_fnptr = (void*)be->be_modify;
+ break;
+ case SLAPI_PLUGIN_DB_MODRDN_FN:
+ *ret_fnptr = (void*)be->be_modrdn;
+ break;
+ case SLAPI_PLUGIN_DB_ADD_FN:
+ *ret_fnptr = (void*)be->be_add;
+ break;
+ case SLAPI_PLUGIN_DB_DELETE_FN:
+ *ret_fnptr = (void*)be->be_delete;
+ break;
+ case SLAPI_PLUGIN_DB_ABANDON_FN:
+ *ret_fnptr = (void*)be->be_abandon;
+ break;
+ case SLAPI_PLUGIN_DB_CONFIG_FN:
+ *ret_fnptr = (void*)be->be_config;
+ break;
+ case SLAPI_PLUGIN_CLOSE_FN:
+ *ret_fnptr = (void*)be->be_close;
+ break;
+ case SLAPI_PLUGIN_DB_FLUSH_FN:
+ *ret_fnptr = (void*)be->be_flush;
+ break;
+ case SLAPI_PLUGIN_START_FN:
+ *ret_fnptr = (void*)be->be_start;
+ break;
+ case SLAPI_PLUGIN_DB_RESULT_FN:
+ *ret_fnptr = (void*)be->be_result;
+ break;
+ case SLAPI_PLUGIN_DB_LDIF2DB_FN:
+ *ret_fnptr = (void*)be->be_ldif2db;
+ break;
+ case SLAPI_PLUGIN_DB_DB2LDIF_FN:
+ *ret_fnptr = (void*)be->be_db2ldif;
+ break;
+ case SLAPI_PLUGIN_DB_ARCHIVE2DB_FN:
+ *ret_fnptr = (void*)be->be_archive2db;
+ break;
+ case SLAPI_PLUGIN_DB_DB2ARCHIVE_FN:
+ *ret_fnptr = (void*)be->be_db2archive;
+ break;
+ case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN:
+ *ret_fnptr = (void*)be->be_next_search_entry;
+ break;
+ case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN:
+ *ret_fnptr = (void*)be->be_next_search_entry_ext;
+ break;
+ case SLAPI_PLUGIN_DB_ENTRY_RELEASE_FN:
+ *ret_fnptr = (void*)be->be_entry_release;
+ break;
+ case SLAPI_PLUGIN_DB_SIZE_FN:
+ *ret_fnptr = (void*)be->be_dbsize;
+ break;
+ case SLAPI_PLUGIN_DB_TEST_FN:
+ *ret_fnptr = (void*)be->be_dbtest;
+ break;
+ case SLAPI_PLUGIN_DB_RMDB_FN:
+ *ret_fnptr = (void*)be->be_rmdb;
+ break;
+ case SLAPI_PLUGIN_DB_INIT_INSTANCE_FN:
+ *ret_fnptr = (void*)be->be_init_instance;
+ break;
+ case SLAPI_PLUGIN_DB_SEQ_FN:
+ *ret_fnptr = (void*)be->be_seq;
+ break;
+ case SLAPI_PLUGIN_DB_DB2INDEX_FN:
+ *ret_fnptr = (void*)be->be_db2index;
+ break;
+ case SLAPI_PLUGIN_CLEANUP_FN:
+ *ret_fnptr = (void*)be->be_cleanup;
+ break;
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_be_getentrypoint: unknown entry point %d\n", entrypoint);
+ return -1;
+ }
+ return 0;
+}
+
+int
+slapi_be_setentrypoint(Slapi_Backend *be, int entrypoint, void *ret_fnptr, Slapi_PBlock *pb)
+{
+ PR_ASSERT(NULL != be);
+
+ /* this is something needed for most of the entry points */
+ if (pb)
+ {
+ be->be_database=pb->pb_plugin;
+ return 0;
+ }
+
+ switch (entrypoint) {
+ case SLAPI_PLUGIN_DB_BIND_FN:
+ be->be_bind=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_UNBIND_FN:
+ be->be_unbind=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_SEARCH_FN:
+ be->be_search=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_COMPARE_FN:
+ be->be_compare=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_MODIFY_FN:
+ be->be_modify=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_MODRDN_FN:
+ be->be_modrdn=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_ADD_FN:
+ be->be_add=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_DELETE_FN:
+ be->be_delete=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_ABANDON_FN:
+ be->be_abandon=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_CONFIG_FN:
+ be->be_config=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_CLOSE_FN:
+ be->be_close=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_FLUSH_FN:
+ be->be_flush=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_START_FN:
+ be->be_start=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_RESULT_FN:
+ be->be_result=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_LDIF2DB_FN:
+ be->be_ldif2db=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_DB2LDIF_FN:
+ be->be_db2ldif=(IFP) ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_ARCHIVE2DB_FN:
+ be->be_archive2db=(IFP) ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_DB2ARCHIVE_FN:
+ be->be_db2archive=(IFP) ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN:
+ be->be_next_search_entry=(IFP) ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN:
+ be->be_next_search_entry_ext=(IFP) ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_ENTRY_RELEASE_FN:
+ be->be_entry_release=(IFP) ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_SIZE_FN:
+ be->be_dbsize=(IFP) ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_TEST_FN:
+ be->be_dbtest=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_RMDB_FN:
+ be->be_rmdb=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_INIT_INSTANCE_FN:
+ be->be_init_instance=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_SEQ_FN:
+ be->be_seq=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_DB_DB2INDEX_FN:
+ be->be_db2index=(IFP)ret_fnptr;
+ break;
+ case SLAPI_PLUGIN_CLEANUP_FN:
+ be->be_cleanup=(IFP)ret_fnptr;
+ break;
+ default:
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_be_setentrypoint: unknown entry point %d\n", entrypoint);
+ return -1;
+ }
+ return 0;
+}
+
+int slapi_be_is_flag_set(Slapi_Backend * be, int flag)
+{
+ return be->be_flags & flag;
+}
+
+void slapi_be_set_flag(Slapi_Backend * be, int flag)
+{
+ be->be_flags|= flag;
+}
+
+char * slapi_be_get_name(Slapi_Backend * be)
+{
+ return be->be_name;
+}
+
+void be_set_sizelimit(Slapi_Backend * be, int sizelimit)
+{
+ be->be_sizelimit = sizelimit;
+}
+
+void be_set_timelimit(Slapi_Backend * be, int timelimit)
+{
+ be->be_timelimit = timelimit;
+}
diff --git a/ldap/servers/slapd/backend_manager.c b/ldap/servers/slapd/backend_manager.c
new file mode 100644
index 00000000..18a9e8a6
--- /dev/null
+++ b/ldap/servers/slapd/backend_manager.c
@@ -0,0 +1,770 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* backend_manager.c - routines for dealing with back-end databases */
+
+#include "slap.h"
+
+#define BACKEND_GRAB_SIZE 10
+
+/* JCM - searching the backend array is linear... */
+
+static int defsize = SLAPD_DEFAULT_SIZELIMIT;
+static int deftime = SLAPD_DEFAULT_TIMELIMIT;
+static int nbackends= 0;
+static Slapi_Backend **backends= NULL;
+static int maxbackends= 0;
+
+Slapi_Backend *
+slapi_be_new( const char *type, const char *name, int isprivate, int logchanges )
+{
+ Slapi_Backend *be;
+ int i;
+
+ /* should add some locking here to prevent concurrent access */
+ if ( nbackends == maxbackends )
+ {
+ int oldsize = maxbackends;
+ maxbackends += BACKEND_GRAB_SIZE;
+ backends = (Slapi_Backend **) slapi_ch_realloc( (char *) backends, maxbackends * sizeof(Slapi_Backend *) );
+ memset( &backends[oldsize], '\0', BACKEND_GRAB_SIZE * sizeof(Slapi_Backend *) );
+ }
+
+ for (i=0; ((i<maxbackends) && (backends[i])); i++)
+ ;
+
+ PR_ASSERT(i<maxbackends);
+
+ be = (Slapi_Backend *) slapi_ch_calloc(1, sizeof(Slapi_Backend));
+ be->be_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, name );
+ be_init( be, type, name, isprivate, logchanges, defsize, deftime );
+
+ backends[i] = be;
+ nbackends++;
+ return( be );
+}
+
+void
+slapi_be_stopping (Slapi_Backend *be)
+{
+ int i;
+
+ PR_Lock (be->be_state_lock);
+ for (i=0; ((i<maxbackends) && backends[i] != be); i++)
+ ;
+
+ PR_ASSERT(i<maxbackends);
+
+ backends[i] = NULL;
+ be->be_state = BE_STATE_DELETED;
+ if (be->be_lock != NULL)
+ {
+ PR_DestroyRWLock(be->be_lock);
+ be->be_lock = NULL;
+ }
+
+ nbackends--;
+ PR_Unlock (be->be_state_lock);
+}
+
+
+void
+slapi_be_free(Slapi_Backend **be)
+{
+ be_done(*be);
+ slapi_ch_free((void**)be);
+ *be = NULL;
+}
+
+static int
+be_plgfn_unwillingtoperform(Slapi_PBlock *pb)
+{
+ send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Operation on Directory Specific Entry not allowed", 0, NULL );
+ return -1;
+}
+
+/* JCM - Seems rather DSE specific... why's it here?... Should be in fedse.c... */
+
+Slapi_Backend *
+be_new_internal(struct dse *pdse, const char *type, const char *name)
+{
+ Slapi_Backend *be= slapi_be_new(type, name, 1 /* Private */, 0 /* Do Not Log Changes */);
+ be->be_database = (struct slapdplugin *) slapi_ch_calloc( 1, sizeof(struct slapdplugin) );
+ be->be_database->plg_private= (void*)pdse;
+ be->be_database->plg_bind= &dse_bind;
+ be->be_database->plg_unbind= &dse_unbind;
+ be->be_database->plg_search= &dse_search;
+ be->be_database->plg_next_search_entry= &dse_next_search_entry;
+ be->be_database->plg_compare= &be_plgfn_unwillingtoperform;
+ be->be_database->plg_modify= &dse_modify;
+ be->be_database->plg_modrdn= &be_plgfn_unwillingtoperform;
+ be->be_database->plg_add= &dse_add;
+ be->be_database->plg_delete= &dse_delete;
+ be->be_database->plg_abandon= &be_plgfn_unwillingtoperform;
+ be->be_database->plg_cleanup = dse_deletedse;
+ /* All the other function pointers default to NULL */
+ return be;
+}
+
+Slapi_Backend*
+slapi_get_first_backend (char **cookie)
+{
+ int i;
+
+ for (i = 0; i < maxbackends; i++)
+ {
+ if ( backends[i] && (backends[i]->be_state != BE_STATE_DELETED))
+ {
+ *cookie = (char*)slapi_ch_malloc (sizeof (int));
+ memcpy (*cookie, &i, sizeof (int));
+ return backends[i];
+ }
+ }
+
+ return NULL;
+}
+
+Slapi_Backend*
+slapi_get_next_backend (char *cookie)
+{
+ int i, last_be;
+ if (cookie == NULL)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "slapi_get_next_backend: NULL argument\n",
+ 0, 0, 0 );
+ return NULL;
+ }
+
+ last_be = *(int *)cookie;
+
+ if ( last_be < 0 || last_be >= maxbackends)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "slapi_get_next_backend: argument out of range\n",
+ 0, 0, 0 );
+ return NULL;
+ }
+
+ if (last_be == maxbackends - 1)
+ return NULL; /* done */
+
+ for (i = last_be + 1; i < maxbackends; i++)
+ {
+ if (backends[i] && (backends[i]->be_state != BE_STATE_DELETED))
+ {
+ memcpy (cookie, &i, sizeof (int));
+ return backends [i];
+ }
+ }
+
+ return NULL;
+}
+
+Slapi_Backend *
+g_get_user_backend( int n )
+{
+ int i, useri;
+
+ useri = 0;
+ for ( i = 0; i < maxbackends; i++ ) {
+ if ( (backends[i] == NULL) || (backends[i]->be_private == 1) ) {
+ continue;
+ }
+
+ if ( useri == n ) {
+ if (backends[i]->be_state != BE_STATE_DELETED)
+ return backends[i];
+ else
+ return NULL;
+ }
+ useri++;
+ }
+ return NULL;
+}
+
+void
+g_set_deftime(int val)
+{
+ deftime = val;
+}
+
+void
+g_set_defsize(int val)
+{
+ defsize = val;
+}
+
+int
+g_get_deftime()
+{
+ return deftime;
+}
+
+int
+g_get_defsize()
+{
+ return defsize;
+}
+
+int strtrimcasecmp(const char *s1, const char *s2)
+{
+ char * s1bis, *s2bis;
+ int len_s1 = 0, len_s2 = 0;
+
+ if ( ((s1 == NULL) && (s2 != NULL))
+ || ((s2 == NULL) && (s1 != NULL)) )
+ return 1;
+
+ if ((s1 == NULL) && (s2 == NULL))
+ return 0;
+
+ while (*s1 == ' ')
+ s1++;
+
+ while (*s2 == ' ')
+ s2++;
+
+ s1bis = (char *) s1;
+ while ((*s1bis != ' ') && (*s1bis != 0))
+ {
+ len_s1 ++;
+ s1bis ++;
+ }
+
+ s2bis = (char *) s2;
+ while ((*s2bis != ' ') && (*s2bis != 0))
+ {
+ len_s2 ++;
+ s2bis ++;
+ }
+
+ if (len_s2 != len_s1)
+ return 1;
+
+ return strncasecmp(s1, s2, len_s1);
+}
+/*
+ * Find the backend of the given type.
+ */
+Slapi_Backend *
+slapi_be_select_by_instance_name( const char *name )
+{
+ int i;
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] && (backends[i]->be_state != BE_STATE_DELETED) &&
+ strtrimcasecmp( backends[i]->be_name, name ) == 0)
+ {
+ return backends[i];
+ }
+ }
+ return NULL;
+}
+
+/* void
+be_cleanupall()
+{
+ int i;
+ Slapi_PBlock pb;
+
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] &&
+ backends[i]->be_cleanup != NULL &&
+ (backends[i]->be_state == BE_STATE_STOPPED ||
+ backends[i]->be_state == BE_STATE_DELETED))
+ {
+ slapi_pblock_set( &pb, SLAPI_PLUGIN, backends[i]->be_database );
+ slapi_pblock_set( &pb, SLAPI_BACKEND, backends[i] );
+
+ (*backends[i]->be_cleanup)( &pb );
+ }
+ }
+}*/
+
+void
+be_cleanupall()
+{
+ int i;
+ Slapi_PBlock pb;
+
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if (backends[i] &&
+ backends[i]->be_cleanup != NULL &&
+ (backends[i]->be_state == BE_STATE_STOPPED ||
+ backends[i]->be_state == BE_STATE_DELETED))
+ {
+ slapi_pblock_set( &pb, SLAPI_PLUGIN, backends[i]->be_database );
+ slapi_pblock_set( &pb, SLAPI_BACKEND, backends[i] );
+
+ (*backends[i]->be_cleanup)( &pb );
+ be_done(backends[i]);
+ slapi_ch_free((void **)&backends[i]);
+ }
+ }
+ slapi_ch_free((void**)&backends);
+}
+
+void
+be_flushall()
+{
+ int i;
+ Slapi_PBlock pb;
+
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] &&
+ backends[i]->be_state == BE_STATE_STARTED &&
+ backends[i]->be_flush != NULL )
+ {
+ slapi_pblock_set( &pb, SLAPI_PLUGIN, backends[i]->be_database );
+ slapi_pblock_set( &pb, SLAPI_BACKEND, backends[i] );
+ (*backends[i]->be_flush)( &pb );
+ }
+ }
+}
+
+void
+be_unbindall(Connection *conn, Operation *op)
+{
+ int i;
+ Slapi_PBlock pb;
+
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] && (backends[i]->be_unbind != NULL) )
+ {
+ pblock_init_common( &pb, backends[i], conn, op );
+
+ if ( plugin_call_plugins( &pb, SLAPI_PLUGIN_PRE_UNBIND_FN ) == 0 )
+ {
+ int rc;
+ slapi_pblock_set( &pb, SLAPI_PLUGIN, backends[i]->be_database );
+ if(backends[i]->be_state != BE_STATE_DELETED &&
+ backends[i]->be_unbind!=NULL)
+ {
+ rc = (*backends[i]->be_unbind)( &pb );
+ }
+ slapi_pblock_set( &pb, SLAPI_PLUGIN_OPRETURN, &rc );
+ (void) plugin_call_plugins( &pb, SLAPI_PLUGIN_POST_UNBIND_FN );
+ }
+ }
+ }
+}
+
+int
+be_nbackends_public()
+{
+ int i;
+ int n= 0;
+ for ( i = 0; i < maxbackends; i++ )
+ {
+ if ( backends[i] &&
+ (backends[i]->be_state != BE_STATE_DELETED) &&
+ (!backends[i]->be_private) )
+ {
+ n++;
+ }
+ }
+ return n;
+}
+
+/* backend instance management */
+/* JCM - These are hardcoded for the LDBM database */
+#define LDBM_CLASS_PREFIX "cn=ldbm database,cn=plugins,cn=config"
+#define LDBM_CONFIG_ENTRY "cn=config,cn=ldbm database,cn=plugins,cn=config"
+#define INSTANCE_ATTR "nsslapd-instance"
+#define SUFFIX_ATTR "nsslapd-suffix"
+#define CACHE_ATTR "nsslapd-cachememsize"
+
+/* add nsslapd-instance attribute to cn=config,cn=ldbm database,cn=plugins,cn=config
+ entry. This causes empty backend instance creation */
+/* JCM - Should be adding an instance entry, not an attr value */
+static int
+be_add_instance (const char *name, void *plugin_identity)
+{
+ Slapi_PBlock pb;
+ Slapi_Mods smods;
+ int rc;
+
+ PR_ASSERT (name && plugin_identity);
+
+ slapi_mods_init (&smods, 1);
+ slapi_mods_add(&smods, LDAP_MOD_ADD, INSTANCE_ATTR, strlen (name), name);
+
+ pblock_init (&pb);
+ slapi_modify_internal_set_pb (&pb, LDBM_CONFIG_ENTRY,
+ slapi_mods_get_ldapmods_byref(&smods), NULL,
+ NULL, plugin_identity, 0);
+ slapi_modify_internal_pb (&pb);
+ slapi_mods_done (&smods);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT,&rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "failed to modify ldbm configuration entry; LDAP error - %d\n", rc);
+ pblock_done(&pb);
+ return -1;
+ }
+
+ pblock_done(&pb);
+ return 0;
+}
+
+static char*
+be_get_instance_dn (const char *index_name, const char *name)
+{
+ int len;
+ char *dn;
+
+ PR_ASSERT (name);
+
+ len = strlen ("cn=config,") + strlen (name) +
+ strlen (LDBM_CLASS_PREFIX) + 4; /* 4 = "cn=" + ',' + '\0' */
+
+ if (index_name)
+ {
+ len += strlen (index_name) + strlen ("cn=index,") + 4; /* 4 = "cn=" + ',' */
+ }
+
+ dn = (char*)slapi_ch_malloc (len);
+ if (dn)
+ {
+ if (index_name)
+ {
+ sprintf (dn, "cn=%s,cn=index,cn=config,cn=%s,%s", index_name, name,
+ LDBM_CLASS_PREFIX);
+ }
+ else
+ {
+ sprintf (dn, "cn=config,cn=%s,%s", name, LDBM_CLASS_PREFIX);
+ }
+ }
+
+ return dn;
+}
+
+
+/* configure newly added backend by modifying instance's configuration entry:
+ cn=config,cn=<instance name>,cn=ldbm database,cn=plugins,cn=config.
+ Can configure backend root and cache size */
+static int
+be_configure_instance (const char *name, const char *root, int cache_size,
+ void *plugin_identity)
+{
+ Slapi_PBlock pb;
+ Slapi_Mods smods;
+ char value [128];
+ char *dn;
+ int rc;
+
+ PR_ASSERT (name && root && plugin_identity);
+
+ dn = be_get_instance_dn (NULL, name);
+
+ slapi_mods_init (&smods, 2);
+ slapi_mods_add(&smods, LDAP_MOD_ADD, SUFFIX_ATTR, strlen (root), root);
+ if (cache_size > 0)
+ {
+ sprintf (value, "%d", cache_size);
+ slapi_mods_add(&smods, LDAP_MOD_REPLACE, CACHE_ATTR, strlen (value), value);
+ }
+
+ pblock_init (&pb);
+ slapi_modify_internal_set_pb (&pb, dn, slapi_mods_get_ldapmods_byref(&smods),
+ NULL, NULL, plugin_identity, 0);
+ slapi_modify_internal_pb (&pb);
+
+ slapi_mods_done (&smods);
+ slapi_ch_free ((void**)&dn);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "failed to update instance entry; LDAP error - %d\n", rc);
+ pblock_done(&pb);
+ return -1;
+ }
+
+ pblock_done(&pb);
+ return 0;
+}
+
+/* configure instance indexes by adding an index entry:
+ "cn=<attr name>,cn=index,cn=config,cn=<instance name>,
+ cn=ldbm database,cn=plugins,cn=config".*/
+static int
+be_configure_instance_indexes (const char *name, IndexConfig *indexes,
+ int index_count, void *plugin_identity)
+{
+ int rc;
+ Slapi_PBlock pb;
+ Slapi_Entry *e;
+ char *dn;
+ int i;
+ char *start, *end;
+ char index_type [16];
+
+ PR_ASSERT (name && indexes && index_count > 0 && plugin_identity);
+
+ for (i = 0; i < index_count; i++)
+ {
+ dn = be_get_instance_dn (indexes[i].attr_name, name);
+ e = slapi_entry_alloc ();
+ slapi_entry_init (e, dn, NULL);
+
+ /* add objectclases */
+ slapi_entry_add_string (e, "objectclass", "top");
+ slapi_entry_add_string (e, "objectclass", "nsIndex");
+ slapi_entry_add_string (e, "cn", indexes[i].attr_name);
+ slapi_entry_add_string (e, "nssystemindex", indexes[i].system ? "true" : "false");
+
+ start = indexes[i].index_type;
+ while ((end = strchr (start, ' ')) != NULL)
+ {
+ if ((end - start) >= 16)
+ continue;
+
+ strncpy (index_type, start, end - start);
+ slapi_entry_add_string (e, "nsindextype", index_type);
+ start = end + 1;
+ }
+
+ slapi_entry_add_string (e, "nsindextype", start);
+
+ pblock_init (&pb);
+ slapi_add_entry_internal_set_pb (&pb, e, NULL /* controls */, plugin_identity,
+ 0/* operation flags */);
+ slapi_add_internal_pb (&pb);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "failed to update instance entry; LDAP error - %d\n", rc);
+ pblock_done(&pb);
+ return -1;
+ }
+ }
+
+ pblock_done(&pb);
+ return 0;
+}
+
+int
+be_create_instance (const char *type, const char *name, const char *root,
+ int cache_size, IndexConfig *indexes, int index_count,
+ void *plugin_identity)
+{
+ int rc;
+
+ if (type == NULL || strcasecmp (type, "ldbm") != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "invalid backend type: %s.\n", type ? type : "null");
+ return -1;
+ }
+
+ if (name == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: null instance name.\n");
+ return -1;
+ }
+
+ if (root == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: null root dn.\n");
+ return -1;
+ }
+
+ if (plugin_identity == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: null plugin identity.\n");
+ return -1;
+ }
+
+ rc = be_add_instance (name, plugin_identity);
+ if (rc != 0)
+ return rc;
+
+ rc = be_configure_instance (name, root, cache_size, plugin_identity);
+ if (rc != 0)
+ return rc;
+
+ if (index_count > 0)
+ rc = be_configure_instance_indexes (name, indexes, index_count, plugin_identity);
+
+ return rc;
+}
+
+int
+be_remove_instance (const char *type, const char *name, void *plugin_identity)
+{
+ int rc;
+ char *dn;
+ Slapi_PBlock pb;
+
+ if (type == NULL || strcasecmp (type, "ldbm") != 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_remove_instance: "
+ "invalid backend type: %s.\n", type ? type : "null");
+ return -1;
+ }
+
+ if (name == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_remove_instance: null instance name.\n");
+ return -1;
+ }
+
+ if (plugin_identity == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_remove_instance: null plugin identity.\n");
+ return -1;
+ }
+
+ dn = be_get_instance_dn (NULL, name);
+
+ pblock_init (&pb);
+ slapi_delete_internal_set_pb (&pb, dn, NULL, NULL, plugin_identity, 0);
+ slapi_delete_internal_pb (&pb);
+
+ slapi_ch_free ((void**)&dn);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc != LDAP_SUCCESS)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "be_create_instance: "
+ "failed to update instance entry; LDAP error - %d\n", rc);
+ pblock_done(&pb);
+ return -1;
+ }
+
+ pblock_done(&pb);
+ return 0;
+}
+
+void
+slapi_be_Rlock(Slapi_Backend * be)
+{
+ PR_RWLock_Rlock(be->be_lock);
+}
+
+void
+slapi_be_Wlock(Slapi_Backend * be)
+{
+ PR_RWLock_Wlock(be->be_lock);
+}
+
+void
+slapi_be_Unlock(Slapi_Backend * be)
+{
+ PR_RWLock_Unlock(be->be_lock);
+}
+
+/*
+ * lookup instance names by suffix.
+ * if isexact == 0: returns instances including ones that associates with
+ * its sub suffixes.
+ * e.g., suffix: "o=<suffix>" is given, these are returned:
+ * suffixes: o=<suffix>, ou=<ou>,o=<suffix>, ...
+ * instances: inst of "o=<suffix>",
+ * inst of "ou=<ou>,o=<suffix>",
+ * ...
+ * if isexact != 0: returns an instance that associates with the given suffix
+ * e.g., suffix: "o=<suffix>" is given, these are returned:
+ * suffixes: "o=<suffix>"
+ * instances: inst of "o=<suffix>"
+ * Note: if suffixes
+ */
+int
+slapi_lookup_instance_name_by_suffix(char *suffix,
+ char ***suffixes, char ***instances, int isexact)
+{
+ Slapi_Backend *be = NULL;
+ char *cookie = NULL;
+ const char *thisdn;
+ int thisdnlen;
+ int suffixlen;
+ int maxinst = 1;
+ int i;
+ int rval = -1;
+
+ if (instances == NULL)
+ return rval;
+
+ rval = 0;
+ suffixlen = strlen(suffix);
+ cookie = NULL;
+ be = slapi_get_first_backend (&cookie);
+ while (be) {
+ if (NULL == be->be_suffix) {
+ be = (backend *)slapi_get_next_backend (cookie);
+ continue;
+ }
+ PR_Lock(be->be_suffixlock);
+ for (i = 0; be->be_suffix && i < be->be_suffixcount; i++) {
+ thisdn = slapi_sdn_get_ndn(be->be_suffix[i]);
+ thisdnlen = slapi_sdn_get_ndn_len(be->be_suffix[i]);
+ if (isexact?suffixlen!=thisdnlen:suffixlen>thisdnlen)
+ continue;
+ if (isexact?(!slapi_UTF8CASECMP(suffix, (char *)thisdn)):
+ (!slapi_UTF8CASECMP(suffix,
+ (char *)thisdn+thisdnlen-suffixlen))) {
+ charray_add(instances, slapi_ch_strdup(be->be_name));
+ if (suffixes)
+ charray_add(suffixes, slapi_ch_strdup(thisdn));
+ }
+ }
+ PR_Unlock(be->be_suffixlock);
+ be = (backend *)slapi_get_next_backend (cookie);
+ }
+
+ return rval;
+}
+
+/*
+ * lookup instance names by included suffixes and excluded suffixes.
+ *
+ * Get instance names associated with the given included suffixes
+ * as well as the excluded suffixes.
+ * Subtract the excluded instances from the included instance.
+ * Assign the result to instances.
+ */
+int
+slapi_lookup_instance_name_by_suffixes(char **included, char **excluded,
+ char ***instances)
+{
+ char **incl_instances, **excl_instances;
+ char **p;
+ int rval = -1;
+
+ if (instances == NULL)
+ return rval;
+
+ *instances = NULL;
+ incl_instances = NULL;
+ for (p = included; p && *p; p++) {
+ if (slapi_lookup_instance_name_by_suffix(*p, NULL, &incl_instances, 0)
+ < 0)
+ return rval;
+ }
+
+ excl_instances = NULL;
+ for (p = excluded; p && *p; p++) {
+ /* okay to be empty */
+ slapi_lookup_instance_name_by_suffix(*p, NULL, &excl_instances, 0);
+ }
+
+ rval = 0;
+ if (excl_instances) {
+ charray_subtract(incl_instances, excl_instances, NULL);
+ charray_free(excl_instances);
+ }
+ *instances = incl_instances;
+ return rval;
+}
diff --git a/ldap/servers/slapd/bind.c b/ldap/servers/slapd/bind.c
new file mode 100644
index 00000000..ab9ca89d
--- /dev/null
+++ b/ldap/servers/slapd/bind.c
@@ -0,0 +1,710 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* bind.c - decode an ldap bind operation and pass it to a backend db */
+
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#include "fe.h"
+
+#include "pratom.h"
+#include <sasl.h>
+
+static void log_bind_access(
+ Slapi_PBlock *pb,
+ const char* dn,
+ int method,
+ int version,
+ const char *saslmech,
+ const char *msg
+);
+
+
+/*
+ * Function: is_root_dn_pw
+ *
+ * Returns: 1 if the password for the root dn is correct.
+ * 0 otherwise.
+ * dn must be normalized
+ *
+ */
+static int
+is_root_dn_pw( const char *dn, const Slapi_Value *cred )
+{
+ int rv= 0;
+ char *rootpw = config_get_rootpw();
+ if ( rootpw == NULL || !slapi_dn_isroot( dn ) )
+ {
+ rv = 0;
+ }
+ else
+ {
+ Slapi_Value rdnpwbv;
+ Slapi_Value *rdnpwvals[2];
+ slapi_value_init_string(&rdnpwbv,rootpw);
+ rdnpwvals[ 0 ] = &rdnpwbv;
+ rdnpwvals[ 1 ] = NULL;
+ rv = slapi_pw_find_sv( rdnpwvals, cred ) == 0;
+ value_done(&rdnpwbv);
+ }
+ slapi_ch_free( (void **) &rootpw );
+ return rv;
+}
+
+void
+do_bind( Slapi_PBlock *pb )
+{
+ BerElement *ber = pb->pb_op->o_ber;
+ int err, version = -1, method = -1, isroot;
+ long long_method = -1;
+ long ber_version = -1;
+ int auth_response_requested = 0;
+ int pw_response_requested = 0;
+ char *dn, *saslmech = NULL;
+ struct berval cred = {0};
+ Slapi_Backend *be = NULL;
+ unsigned long rc;
+ Slapi_DN sdn;
+ Slapi_Entry *referral;
+ char errorbuf[BUFSIZ];
+ char **supported, **pmech;
+ char authtypebuf[256]; /* >26 (strlen(SLAPD_AUTH_SASL)+SASL_MECHNAMEMAX+1) */
+ Slapi_Entry *bind_target_entry = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_bind\n", 0, 0, 0 );
+
+ /*
+ * Parse the bind request. It looks like this:
+ *
+ * BindRequest ::= SEQUENCE {
+ * version INTEGER, -- version
+ * name DistinguishedName, -- dn
+ * authentication CHOICE {
+ * simple [0] OCTET STRING, -- passwd
+ * krbv42ldap [1] OCTET STRING, -- not used
+ * krbv42dsa [2] OCTET STRING, -- not used
+ * sasl [3] SaslCredentials -- v3 only
+ * }
+ * }
+ *
+ * Saslcredentials ::= SEQUENCE {
+ * mechanism LDAPString,
+ * credentials OCTET STRING
+ * }
+ */
+
+ rc = ber_scanf( ber, "{iat", &ber_version, &dn, &long_method );
+ method = long_method;
+ version = ber_version;
+ if ( rc == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=Bind; params=Version,DN,Method)\n",
+ 0, 0, 0 );
+ log_bind_access (pb, "???", method, version, saslmech, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "decoding error", 0, NULL );
+ return;
+ }
+
+ slapi_sdn_init_dn_passin(&sdn,dn);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "BIND dn=\"%s\" method=%d version=%d\n",
+ dn, method, version );
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ operation_set_target_spec (pb->pb_op, &sdn);
+
+ switch ( method ) {
+ case LDAP_AUTH_SASL:
+ if ( version < LDAP_VERSION3 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "got SASL credentials from LDAPv2 client\n",
+ 0, 0, 0 );
+ log_bind_access (pb, slapi_sdn_get_dn (&sdn), method, version, saslmech, "SASL credentials only in LDAPv3");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "SASL credentials only in LDAPv3", 0, NULL );
+ goto free_and_return;
+ }
+ /* Get the SASL mechanism */
+ rc = ber_scanf( ber, "{a", &saslmech );
+ /* Get the (optional) SASL credentials */
+ if ( rc != LBER_ERROR ) {
+ /* Credentials are optional in SASL bind */
+ unsigned long clen;
+ if (( ber_peek_tag( ber, &clen )) == LBER_OCTETSTRING ) {
+ rc = ber_scanf( ber, "o}}", &cred );
+ } else {
+ rc = ber_scanf( ber, "}}" );
+ }
+ }
+ break;
+ case LDAP_AUTH_KRBV41:
+ /* FALLTHROUGH */
+ case LDAP_AUTH_KRBV42:
+ if ( version >= LDAP_VERSION3 ) {
+ static char *kmsg =
+ "LDAPv2-style kerberos authentication received "
+ "on LDAPv3 connection.";
+ LDAPDebug( LDAP_DEBUG_ANY, kmsg, 0, 0, 0 );
+ log_bind_access (pb, slapi_sdn_get_dn (&sdn), method, version, saslmech, kmsg);
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ kmsg, 0, NULL );
+ goto free_and_return;
+ }
+ /* FALLTHROUGH */
+ case LDAP_AUTH_SIMPLE:
+ rc = ber_scanf( ber, "o}", &cred );
+ break;
+ default:
+ log_bind_access (pb, slapi_sdn_get_dn (&sdn), method, version, saslmech, "Unknown bind method");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "Unknown bind method", 0, NULL );
+ goto free_and_return;
+ }
+ if ( rc == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=Bind; params=Credentials)\n",
+ 0, 0, 0 );
+ log_bind_access (pb, slapi_sdn_get_dn (&sdn), method, version, saslmech, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "decoding error", 0, NULL );
+ goto free_and_return;
+ }
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend.
+ * We also check for the presence of an "Authentication Request
+ * Control" and set a flag so we know later whether we need to send
+ * an "Authentication Response Control" with Success responses.
+ */
+ {
+ LDAPControl **reqctrls;
+
+ if (( err = get_ldapmessage_controls( pb, ber, &reqctrls ))
+ != 0 ) {
+ log_bind_access (pb, slapi_sdn_get_dn (&sdn), method,
+ version, saslmech, "failed to parse LDAP controls");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+
+ auth_response_requested = slapi_control_present( reqctrls,
+ LDAP_CONTROL_AUTH_REQUEST, NULL, NULL );
+ slapi_pblock_get (pb, SLAPI_PWPOLICY, &pw_response_requested);
+ }
+
+ log_bind_access(pb, dn, method, version, saslmech, NULL);
+
+ /* According to RFC2251,
+ * "if the bind fails, the connection will be treated as anonymous".
+ */
+ PR_Lock( pb->pb_conn->c_mutex );
+ bind_credentials_clear( pb->pb_conn, PR_FALSE, /* conn is already locked */
+ PR_FALSE /* do not clear external creds. */ );
+ /* Clear the password policy flag that forbid operation
+ * other than Bind, Modify, Unbind :
+ * With a new bind, the flag should be reset so that the new
+ * bound user can work properly
+ */
+ pb->pb_conn->c_needpw = 0;
+ PR_Unlock( pb->pb_conn->c_mutex );
+
+ switch ( version ) {
+ case LDAP_VERSION2:
+ if (method == LDAP_AUTH_SIMPLE
+ && (dn == NULL || *dn == '\0') && cred.bv_len == 0
+ && pb->pb_conn->c_external_dn != NULL) {
+ /* Treat this like a SASL EXTERNAL Bind: */
+ method = LDAP_AUTH_SASL;
+ saslmech = slapi_ch_strdup (LDAP_SASL_EXTERNAL);
+ /* This enables a client to establish an identity by sending
+ * a certificate in the SSL handshake, and also use LDAPv2
+ * (by sending this type of Bind request).
+ */
+ }
+ break;
+ case LDAP_VERSION3:
+ break;
+ default:
+ LDAPDebug( LDAP_DEBUG_TRACE, "bind: unknown LDAP protocol version %d\n",
+ version, 0, 0 );
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "version not supported", 0, NULL );
+ goto free_and_return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_bind: version %d method 0x%x dn %s\n",
+ version, method, dn );
+ pb->pb_conn->c_ldapversion = version;
+
+ isroot = slapi_dn_isroot( slapi_sdn_get_ndn(&sdn) );
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ slapi_pblock_set( pb, SLAPI_BIND_TARGET, (void*)slapi_sdn_get_ndn(&sdn) );
+ slapi_pblock_set( pb, SLAPI_BIND_METHOD, &method );
+ slapi_pblock_set( pb, SLAPI_BIND_SASLMECHANISM, saslmech );
+ slapi_pblock_set( pb, SLAPI_BIND_CREDENTIALS, &cred );
+
+ if (method != LDAP_AUTH_SASL) {
+ /*
+ * RFC2251: client may abort a sasl bind negotiation by sending
+ * an authentication choice other than sasl.
+ */
+ pb->pb_conn->c_flags &= ~CONN_FLAG_SASL_CONTINUE;
+ }
+
+ switch ( method ) {
+ case LDAP_AUTH_SASL:
+ /*
+ * All SASL auth methods are categorized as strong binds,
+ * although they are not necessarily stronger than simple.
+ */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsStrongAuthBinds);
+ if ( saslmech == NULL || *saslmech == '\0' ) {
+ send_ldap_result( pb, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL,
+ "SASL mechanism absent", 0, NULL );
+ goto free_and_return;
+ }
+
+ if (strlen(saslmech) > SASL_MECHNAMEMAX) {
+ send_ldap_result( pb, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL,
+ "SASL mechanism name is too long", 0, NULL );
+ goto free_and_return;
+ }
+
+ supported = slapi_get_supported_saslmechanisms_copy();
+ if ( (pmech = supported) != NULL ) while (1) {
+ if (*pmech == NULL) {
+ /* As we call the safe function, we receive a strdup'd saslmechanisms
+ charray. Therefore, we need to remove it instead of NULLing it */
+ charray_free(supported);
+ pmech = supported = NULL;
+ break;
+ }
+ if (!strcasecmp (saslmech, *pmech)) break;
+ ++pmech;
+ }
+ if (!pmech) {
+ /* now check the sasl library */
+ ids_sasl_check_bind(pb);
+ goto free_and_return;
+ }
+ else {
+ charray_free(supported); /* Avoid leaking */
+ }
+
+ if (!strcasecmp (saslmech, LDAP_SASL_EXTERNAL)) {
+ /*
+ * if this is not an SSL connection, fail and return an
+ * inappropriateAuth error.
+ */
+ if ( 0 == ( pb->pb_conn->c_flags & CONN_FLAG_SSL )) {
+ send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL,
+ "SASL EXTERNAL bind requires an SSL connection",
+ 0, NULL );
+ goto free_and_return;
+ }
+
+ /*
+ * if the client sent us a certificate but we could not map it
+ * to an LDAP DN, fail and return an invalidCredentials error.
+ */
+ if ( NULL != pb->pb_conn->c_client_cert &&
+ NULL == pb->pb_conn->c_external_dn ) {
+ send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
+ "client certificate mapping failed", 0, NULL );
+ goto free_and_return;
+ }
+
+ /*
+ * copy external credentials into connection structure
+ */
+ bind_credentials_set( pb->pb_conn,
+ pb->pb_conn->c_external_authtype,
+ pb->pb_conn->c_external_dn,
+ NULL, NULL, NULL , NULL);
+ if ( auth_response_requested ) {
+ add_auth_response_control( pb, pb->pb_conn->c_external_dn );
+ }
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+ break;
+ case LDAP_AUTH_SIMPLE:
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsSimpleAuthBinds);
+ /* accept null binds */
+ if (dn == NULL || *dn == '\0') {
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
+ /* by definition its anonymous is also UnAuthenticated so increment
+ that counter */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds);
+
+ /* call preop plugins */
+ if (plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_BIND_FN ) == 0){
+ if ( auth_response_requested ) {
+ add_auth_response_control( pb, "" );
+ }
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+
+ /* call postop plugins */
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
+ }
+ goto free_and_return;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * handle binds as the manager here, pass others to the backend
+ */
+
+ if ( isroot && method == LDAP_AUTH_SIMPLE ) {
+ if ( cred.bv_len == 0 ) {
+ /* unauthenticated bind */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds);
+
+ } else {
+ /* a passwd was supplied -- check it */
+ Slapi_Value cv;
+ slapi_value_init_berval(&cv,&cred);
+
+ if ( is_root_dn_pw( slapi_sdn_get_ndn(&sdn), &cv )) {
+ /* right dn and passwd - authorize */
+ bind_credentials_set( pb->pb_conn, SLAPD_AUTH_SIMPLE,
+ slapi_ch_strdup( slapi_sdn_get_ndn(&sdn) ),
+ NULL, NULL, NULL , NULL);
+
+ /* right dn, wrong passwd - reject with invalid creds */
+ } else {
+ send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL,
+ NULL, 0, NULL );
+ /* increment BindSecurityErrorcount */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
+ value_done(&cv);
+ goto free_and_return;
+ }
+ value_done(&cv);
+ }
+
+ /* call preop plugin */
+ if (plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_BIND_FN ) == 0){
+ if ( auth_response_requested ) {
+ add_auth_response_control( pb,
+ ( cred.bv_len == 0 ) ? "" :
+ slapi_sdn_get_ndn(&sdn));
+ }
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+
+ /* call postop plugins */
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
+ }
+ goto free_and_return;
+ }
+
+ /* We could be serving multiple database backends. Select the appropriate one */
+ if (slapi_mapping_tree_select(pb, &be, &referral, errorbuf) != LDAP_SUCCESS) {
+ send_nobackend_ldap_result( pb );
+ be = NULL;
+ goto free_and_return;
+ }
+
+ if (referral)
+ {
+ send_referrals_from_entry(pb,referral);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ slapi_pblock_set( pb, SLAPI_BACKEND, be );
+
+ /* not root dn - pass to the backend */
+ if ( be->be_bind != NULL ) {
+
+ /*
+ * call the pre-bind plugins. if they succeed, call
+ * the backend bind function. then call the post-bind
+ * plugins.
+ */
+ if ( plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_BIND_FN )
+ == 0 ) {
+ int rc = 0;
+
+ /*
+ * Is this account locked ?
+ * could be locked through the account inactivation
+ * or by the password policy
+ *
+ * rc=0: account not locked
+ * rc=1: account locked, can not bind, result has been sent
+ * rc!=0 and rc!=1: error. Result was not sent, lets be_bind
+ * deal with it.
+ *
+ */
+
+ /* get the entry now, so that we can give it to check_account_lock and reslimit_update_from_dn */
+ if (! slapi_be_is_flag_set(be, SLAPI_BE_FLAG_REMOTE_DATA)) {
+ bind_target_entry = get_entry(pb, slapi_sdn_get_ndn(&sdn));
+ rc = check_account_lock ( pb, bind_target_entry, pw_response_requested);
+ }
+
+ slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database );
+ set_db_default_result_handlers(pb);
+ if ( (rc != 1) && (((rc = (*be->be_bind)( pb ))
+ == SLAPI_BIND_SUCCESS ) || rc
+ == SLAPI_BIND_ANONYMOUS )) {
+ long t;
+ {
+ char* authtype = NULL;
+ switch ( method ) {
+ case LDAP_AUTH_SIMPLE:
+ if (cred.bv_len != 0) {
+ authtype = SLAPD_AUTH_SIMPLE;
+ }
+ break;
+ case LDAP_AUTH_SASL:
+ /* authtype = SLAPD_AUTH_SASL && saslmech: */
+ sprintf(authtypebuf, "%s%s", SLAPD_AUTH_SASL, saslmech);
+ authtype = authtypebuf;
+ break;
+ default: /* ??? */
+ break;
+ }
+
+ if ( rc == SLAPI_BIND_SUCCESS ) {
+ bind_credentials_set( pb->pb_conn,
+ authtype, slapi_ch_strdup(
+ slapi_sdn_get_ndn(&sdn)),
+ NULL, NULL, NULL, bind_target_entry );
+ if ( auth_response_requested ) {
+ add_auth_response_control( pb,
+ slapi_sdn_get_ndn(&sdn));
+ }
+ } else { /* anonymous */
+ if ( auth_response_requested ) {
+ add_auth_response_control( pb,
+ "" );
+ }
+ }
+ }
+
+ if ( rc != SLAPI_BIND_ANONYMOUS &&
+ ! slapi_be_is_flag_set(be,
+ SLAPI_BE_FLAG_REMOTE_DATA)) {
+ /* check if need new password before sending
+ the bind success result */
+ switch ( need_new_pw (pb, &t, bind_target_entry, pw_response_requested )) {
+
+ case 1:
+ (void)add_pwd_control ( pb,
+ LDAP_CONTROL_PWEXPIRED, 0);
+ break;
+
+ case 2:
+ (void)add_pwd_control ( pb,
+ LDAP_CONTROL_PWEXPIRING, t);
+ break;
+ case -1:
+ goto free_and_return;
+ default:
+ break;
+ }
+ } /* end if */
+ }else{
+
+ if(cred.bv_len == 0) {
+ /* its an UnAuthenticated Bind, DN specified but no pw */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds);
+ }else{
+ /* password must have been invalid */
+ /* increment BindSecurityError count */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors);
+ }
+
+ }
+
+ /*
+ * if rc != SLAPI_BIND_SUCCESS and != SLAPI_BIND_ANONYMOUS,
+ * the result has already been sent by the backend. otherwise,
+ * we assume it is success and send it here to avoid a race
+ * condition where the client could be told by the
+ * backend that the bind succeeded before we set the
+ * c_dn field in the connection structure here in
+ * the front end.
+ */
+ if ( rc == SLAPI_BIND_SUCCESS || rc == SLAPI_BIND_ANONYMOUS) {
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL,
+ 0, NULL );
+ }
+
+ slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc );
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_BIND_FN );
+ }
+ } else {
+ send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Function not implemented", 0, NULL );
+ }
+
+ free_and_return:;
+ if (be)
+ slapi_be_Unlock(be);
+ slapi_sdn_done(&sdn);
+ if ( saslmech != NULL ) {
+ free( saslmech );
+ }
+ if ( cred.bv_val != NULL ) {
+ free( cred.bv_val );
+ }
+ if ( bind_target_entry != NULL )
+ slapi_entry_free(bind_target_entry);
+}
+
+
+/*
+ * register all of the LDAPv3 SASL mechanisms we know about.
+ */
+void
+init_saslmechanisms( void )
+{
+ ids_sasl_init();
+ slapi_register_supported_saslmechanism( LDAP_SASL_EXTERNAL );
+}
+
+static void
+log_bind_access (
+ Slapi_PBlock *pb,
+ const char* dn,
+ int method,
+ int version,
+ const char *saslmech,
+ const char *msg
+)
+{
+ char ebuf[ BUFSIZ ];
+ const char *edn;
+
+ edn = escape_string( dn, ebuf );
+
+ if (method == LDAP_AUTH_SASL && saslmech && msg) {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d BIND dn=\"%s\" "
+ "method=sasl version=%d mech=%s, %s\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid, edn,
+ version, saslmech, msg );
+ } else if (method == LDAP_AUTH_SASL && saslmech) {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d BIND dn=\"%s\" "
+ "method=sasl version=%d mech=%s\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid, edn,
+ version, saslmech );
+ } else if (msg) {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d BIND dn=\"%s\" "
+ "method=%d version=%d, %s\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid, edn,
+ method, version, msg );
+ } else {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d BIND dn=\"%s\" "
+ "method=%d version=%d\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid, edn,
+ method, version );
+ }
+}
+
+
+void
+add_auth_response_control( Slapi_PBlock *pb, const char *binddn )
+{
+ LDAPControl arctrl;
+ char dnbuf_fixedsize[ 512 ], *dnbuf, *dnbuf_dynamic = NULL;
+ size_t dnlen;
+
+ if ( NULL == binddn ) {
+ binddn = "";
+ }
+ dnlen = strlen( binddn );
+
+ /*
+ * According to draft-weltman-ldapv3-auth-response-03.txt section
+ * 4 (Authentication Response Control):
+ *
+ * The controlType is "2.16.840.1.113730.3.4.15". If the bind request
+ * succeeded and resulted in an identity (not anonymous), the
+ * controlValue contains the authorization identity [AUTH] granted to
+ * the requestor. If the bind request resulted in anonymous
+ * authentication, the controlValue field is a string of zero length.
+ *
+ * [AUTH] is a reference to RFC 2829, which in section 9 defines
+ * authorization identity as:
+ *
+ *
+ * The authorization identity is a string in the UTF-8 character set,
+ * corresponding to the following ABNF [7]:
+ *
+ * ; Specific predefined authorization (authz) id schemes are
+ * ; defined below -- new schemes may be defined in the future.
+ *
+ * authzId = dnAuthzId / uAuthzId
+ *
+ * ; distinguished-name-based authz id.
+ * dnAuthzId = "dn:" dn
+ * dn = utf8string ; with syntax defined in RFC 2253
+ *
+ * ; unspecified userid, UTF-8 encoded.
+ * uAuthzId = "u:" userid
+ * userid = utf8string ; syntax unspecified
+ *
+ * A utf8string is defined to be the UTF-8 encoding of one or more ISO
+ * 10646 characters.
+ *
+ * We always map identities to DNs, so we always use the dnAuthzId form.
+ */
+ arctrl.ldctl_oid = LDAP_CONTROL_AUTH_RESPONSE;
+ arctrl.ldctl_iscritical = 0;
+
+ if ( dnlen == 0 ) { /* anonymous -- return zero length value */
+ arctrl.ldctl_value.bv_val = "";
+ arctrl.ldctl_value.bv_len = 0;
+ } else { /* mapped to a DN -- return "dn:<DN>" */
+ if ( 3 + dnlen < sizeof( dnbuf_fixedsize )) {
+ dnbuf = dnbuf_fixedsize;
+ } else {
+ dnbuf = dnbuf_dynamic = slapi_ch_malloc( 4 + dnlen );
+ }
+ strcpy( dnbuf, "dn:" );
+ strcpy( dnbuf + 3, binddn );
+ arctrl.ldctl_value.bv_val = dnbuf;
+ arctrl.ldctl_value.bv_len = 3 + dnlen;
+ }
+
+ if ( slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, &arctrl ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, "bind",
+ "unable to add authentication response control" );
+ }
+
+ if ( NULL != dnbuf_dynamic ) {
+ slapi_ch_free( (void **)&dnbuf_dynamic );
+ }
+}
diff --git a/ldap/servers/slapd/bitset.c b/ldap/servers/slapd/bitset.c
new file mode 100644
index 00000000..5bdc5291
--- /dev/null
+++ b/ldap/servers/slapd/bitset.c
@@ -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 **/
+
+unsigned char
+slapi_setbit_uchar(unsigned char f,unsigned char bitnum)
+{
+ return (f | ((unsigned char)1 << bitnum));
+}
+
+unsigned char
+slapi_unsetbit_uchar(unsigned char f,unsigned char bitnum)
+{
+/* TEMPORARY WORKAROUND FOR x86 compiler problem on solaris
+ * return (f & (~((unsigned char)1 << bitnum)));
+ */
+ unsigned char t;
+ t = f & (~((unsigned char)1 << bitnum));
+ return(t);
+}
+
+int
+slapi_isbitset_uchar(unsigned char f,unsigned char bitnum)
+{
+ return (f & ((unsigned char)1 << bitnum));
+}
+
+
+unsigned int
+slapi_setbit_int(unsigned int f,unsigned int bitnum)
+{
+ return (f | ((unsigned int)1 << bitnum));
+}
+
+unsigned int
+slapi_unsetbit_int(unsigned int f,unsigned int bitnum)
+{
+ return (f & (~((unsigned int)1 << bitnum)));
+}
+
+int
+slapi_isbitset_int(unsigned int f,unsigned int bitnum)
+{
+ return (f & ((unsigned int)1 << bitnum));
+}
diff --git a/ldap/servers/slapd/bulk_import.c b/ldap/servers/slapd/bulk_import.c
new file mode 100644
index 00000000..ea531cb3
--- /dev/null
+++ b/ldap/servers/slapd/bulk_import.c
@@ -0,0 +1,149 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+/* The functions in this file allow plugins to perform bulk import of data
+ comming over ldap connection. Note that the code will not work if
+ there is now active connection since import state is stored in the
+ connection extension */
+
+#include "slap.h"
+
+/* forward declarations */
+static int process_bulk_import_op (Slapi_PBlock *pb, int state, Slapi_Entry *e);
+
+/* This function initiates bulk import. The pblock must contain
+ SLAPI_LDIF2DB_GENERATE_UNIQUEID -- currently always set to TIME_BASED
+ SLAPI_CONNECTION -- connection over which bulk import is coming
+ SLAPI_BACKEND -- the backend being imported
+ or
+ SLAPI_TARGET_DN that contains root of the imported area.
+ The function returns LDAP_SUCCESS or LDAP error code
+*/
+
+int slapi_start_bulk_import (Slapi_PBlock *pb)
+{
+ return (process_bulk_import_op (pb, SLAPI_BI_STATE_START, NULL));
+}
+
+/* This function stops bulk import. The pblock must contain
+ SLAPI_CONNECTION -- connection over which bulk import is coming
+ SLAPI_BACKEND -- the backend being imported
+ or
+ SLAPI_TARGET_DN that contains root of the imported area.
+ The function returns LDAP_SUCCESS or LDAP error code
+*/
+int slapi_stop_bulk_import (Slapi_PBlock *pb)
+{
+ return (process_bulk_import_op (pb, SLAPI_BI_STATE_DONE, NULL));
+}
+
+/* This function adds an entry to the bulk import. The pblock must contain
+ SLAPI_CONNECTION -- connection over which bulk import is coming
+ SLAPI_BACKEND -- optional backend pointer; if missing computed based on entry dn
+ The function returns LDAP_SUCCESS or LDAP error code
+*/
+int slapi_import_entry (Slapi_PBlock *pb, Slapi_Entry *e)
+{
+ return (process_bulk_import_op (pb, SLAPI_BI_STATE_ADD, e));
+}
+
+static int
+process_bulk_import_op (Slapi_PBlock *pb, int state, Slapi_Entry *e)
+{
+ int rc;
+ Slapi_Backend *be = NULL;
+ char *dn = NULL;
+ Slapi_DN sdn;
+ const Slapi_DN *target_sdn = NULL;
+
+ if (pb == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "process_bulk_import_op: NULL pblock\n");
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (state == SLAPI_BI_STATE_ADD && e == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "process_bulk_import_op: NULL entry\n");
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ slapi_pblock_get (pb, SLAPI_BACKEND, &be);
+ if (be == NULL)
+ {
+ /* try to get dn to select backend */
+ if (e)
+ {
+ target_sdn = slapi_entry_get_sdn_const (e);
+ be = slapi_be_select (target_sdn);
+ }
+ else
+ {
+ slapi_sdn_init(&sdn);
+ slapi_pblock_get (pb, SLAPI_TARGET_DN, &dn);
+ if (dn)
+ {
+ slapi_sdn_init_dn_byref(&sdn, dn);
+ be = slapi_be_select (&sdn);
+ target_sdn = &sdn;
+ }
+ }
+
+ if (be)
+ {
+ if (state == SLAPI_BI_STATE_START && (!slapi_be_issuffix(be, target_sdn)))
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "process_bulk_import_op: wrong backend suffix\n");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ slapi_pblock_set (pb, SLAPI_BACKEND, be);
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "process_bulk_import_op: NULL backend\n");
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (NULL == e)
+ slapi_sdn_done (&sdn);
+ }
+
+ if (be->be_wire_import == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "slapi_start_bulk_import: "
+ "bulk import is not supported by this (%s) backend\n",
+ be->be_type);
+ return LDAP_NOT_SUPPORTED;
+ }
+
+ /* set required parameters */
+ slapi_pblock_set (pb, SLAPI_BULK_IMPORT_STATE, &state);
+ if (e)
+ slapi_pblock_set (pb, SLAPI_BULK_IMPORT_ENTRY, e);
+
+ rc = be->be_wire_import (pb);
+ if (rc != 0)
+ {
+ if (rc != LDAP_BUSY)
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "slapi_start_bulk_import: "
+ "failed; error = %d\n", rc);
+ return (LDAP_BUSY == rc ? LDAP_BUSY : LDAP_OPERATIONS_ERROR);
+ }
+
+ return LDAP_SUCCESS;
+}
diff --git a/ldap/servers/slapd/ch_malloc.c b/ldap/servers/slapd/ch_malloc.c
new file mode 100644
index 00000000..c4d1e748
--- /dev/null
+++ b/ldap/servers/slapd/ch_malloc.c
@@ -0,0 +1,657 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* slapi_ch_malloc.c - malloc routines that test returns from malloc and friends */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h> /* strdup */
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#undef DEBUG /* disable counters */
+#include <prcountr.h>
+#include "slap.h"
+
+static int counters_created= 0;
+PR_DEFINE_COUNTER(slapi_ch_counter_malloc);
+PR_DEFINE_COUNTER(slapi_ch_counter_calloc);
+PR_DEFINE_COUNTER(slapi_ch_counter_realloc);
+PR_DEFINE_COUNTER(slapi_ch_counter_strdup);
+PR_DEFINE_COUNTER(slapi_ch_counter_free);
+PR_DEFINE_COUNTER(slapi_ch_counter_created);
+PR_DEFINE_COUNTER(slapi_ch_counter_exist);
+
+#define OOM_PREALLOC_SIZE 65536
+static void *oom_emergency_area = NULL;
+static PRLock *oom_emergency_lock = NULL;
+
+#if defined(_WIN32)
+static int recording= 0;
+#endif
+
+#define SLAPD_MODULE "memory allocator"
+
+static const char* const oom_advice =
+ "\nThe server has probably allocated all available virtual memory. To solve\n"
+ "this problem, make more virtual memory available to your server, or reduce\n"
+ "one or more of the following server configuration settings:\n"
+ " nsslapd-cachesize (Database Settings - Maximum entries in cache)\n"
+ " nsslapd-cachememsize (Database Settings - Memory available for cache)\n"
+ " nsslapd-dbcachesize (LDBM Plug-in Settings - Maximum cache size)\n"
+ " nsslapd-import-cachesize (LDBM Plug-in Settings - Import cache size).\n"
+ "Can't recover; calling exit(1).\n";
+
+#if defined(_WIN32) && defined(DEBUG)
+static void add_memory_record(void *p,unsigned long size);
+static void remove_memory_record(void *p);
+static int memory_record_dump( caddr_t data, caddr_t arg );
+static int memory_record_delete( caddr_t data, caddr_t arg );
+#endif
+
+static void
+create_counters()
+{
+ PR_CREATE_COUNTER(slapi_ch_counter_malloc,"slapi_ch","malloc","");
+ PR_CREATE_COUNTER(slapi_ch_counter_calloc,"slapi_ch","calloc","");
+ PR_CREATE_COUNTER(slapi_ch_counter_realloc,"slapi_ch","realloc","");
+ PR_CREATE_COUNTER(slapi_ch_counter_strdup,"slapi_ch","strdup","");
+ PR_CREATE_COUNTER(slapi_ch_counter_free,"slapi_ch","free","");
+ PR_CREATE_COUNTER(slapi_ch_counter_created,"slapi_ch","created","");
+ PR_CREATE_COUNTER(slapi_ch_counter_exist,"slapi_ch","exist","");
+
+ /* ensure that we have space to allow for shutdown calls to malloc()
+ * from should we run out of memory.
+ */
+ if (oom_emergency_area == NULL) {
+ oom_emergency_area = malloc(OOM_PREALLOC_SIZE);
+ }
+ oom_emergency_lock = PR_NewLock();
+}
+
+/* called when we have just detected an out of memory condition, before
+ * we make any other library calls. Note that LDAPDebug() calls malloc,
+ * indirectly. By making 64KB free, we should be able to have a few
+ * mallocs' succeed before we shut down.
+ */
+void oom_occurred(void)
+{
+ int tmp_errno = errno; /* callers will need the error from malloc */
+ if (oom_emergency_lock == NULL) return;
+
+ PR_Lock(oom_emergency_lock);
+ if (oom_emergency_area) {
+ free(oom_emergency_area);
+ oom_emergency_area = NULL;
+ }
+ PR_Unlock(oom_emergency_lock);
+ errno = tmp_errno;
+}
+
+static void
+log_negative_alloc_msg( const char *op, const char *units, unsigned long size )
+{
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPD_MODULE,
+ "cannot %s %lu %s;\n"
+ "trying to allocate 0 or a negative number of %s is not portable and\n"
+ "gives different results on different platforms.\n",
+ op, size, units, units );
+}
+
+char *
+slapi_ch_malloc(
+ unsigned long size
+)
+{
+ char *newmem;
+
+ if (size <= 0) {
+ log_negative_alloc_msg( "malloc", "bytes", size );
+ return 0;
+ }
+
+ if ( (newmem = (char *) malloc( size )) == NULL ) {
+ int oserr = errno;
+
+ oom_occurred();
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPD_MODULE,
+ "malloc of %lu bytes failed; OS error %d (%s)%s\n",
+ size, oserr, slapd_system_strerror( oserr ), oom_advice );
+ exit( 1 );
+ }
+ if(!counters_created)
+ {
+ create_counters();
+ counters_created= 1;
+ }
+ PR_INCREMENT_COUNTER(slapi_ch_counter_malloc);
+ PR_INCREMENT_COUNTER(slapi_ch_counter_created);
+ PR_INCREMENT_COUNTER(slapi_ch_counter_exist);
+#if defined(_WIN32) && defined(DEBUG)
+ if(recording)
+ {
+ add_memory_record(newmem,size);
+ }
+#endif
+
+ return( newmem );
+}
+
+char *
+slapi_ch_realloc(
+ char *block,
+ unsigned long size
+)
+{
+ char *newmem;
+
+ if ( block == NULL ) {
+ return( slapi_ch_malloc( size ) );
+ }
+
+ if (size <= 0) {
+ log_negative_alloc_msg( "realloc", "bytes", size );
+ return block;
+ }
+
+ if ( (newmem = (char *) realloc( block, size )) == NULL ) {
+ int oserr = errno;
+
+ oom_occurred();
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPD_MODULE,
+ "realloc of %lu bytes failed; OS error %d (%s)%s\n",
+ size, oserr, slapd_system_strerror( oserr ), oom_advice );
+ exit( 1 );
+ }
+ if(!counters_created)
+ {
+ create_counters();
+ counters_created= 1;
+ }
+ PR_INCREMENT_COUNTER(slapi_ch_counter_realloc);
+#if defined(_WIN32) && defined(DEBUG)
+ if(recording)
+ {
+ remove_memory_record(block);
+ add_memory_record(newmem,size);
+ }
+#endif
+
+ return( newmem );
+}
+
+char *
+slapi_ch_calloc(
+ unsigned long nelem,
+ unsigned long size
+)
+{
+ char *newmem;
+
+ if (size <= 0) {
+ log_negative_alloc_msg( "calloc", "bytes", size );
+ return 0;
+ }
+
+ if (nelem <= 0) {
+ log_negative_alloc_msg( "calloc", "elements", nelem );
+ return 0;
+ }
+
+ if ( (newmem = (char *) calloc( nelem, size )) == NULL ) {
+ int oserr = errno;
+
+ oom_occurred();
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPD_MODULE,
+ "calloc of %lu elems of %lu bytes failed; OS error %d (%s)%s\n",
+ nelem, size, oserr, slapd_system_strerror( oserr ), oom_advice );
+ exit( 1 );
+ }
+ if(!counters_created)
+ {
+ create_counters();
+ counters_created= 1;
+ }
+ PR_INCREMENT_COUNTER(slapi_ch_counter_calloc);
+ PR_INCREMENT_COUNTER(slapi_ch_counter_created);
+ PR_INCREMENT_COUNTER(slapi_ch_counter_exist);
+#if defined(_WIN32) && defined(DEBUG)
+ if(recording)
+ {
+ add_memory_record(newmem,size);
+ }
+#endif
+ return( newmem );
+}
+
+char*
+slapi_ch_strdup ( const char* s1)
+{
+ char* newmem;
+
+ /* strdup pukes on NULL strings...bail out now */
+ if(NULL == s1)
+ return NULL;
+ newmem = strdup (s1);
+ if (newmem == NULL) {
+ int oserr = errno;
+ oom_occurred();
+
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPD_MODULE,
+ "strdup of %lu characters failed; OS error %d (%s)%s\n",
+ (unsigned long)strlen(s1), oserr, slapd_system_strerror( oserr ),
+ oom_advice );
+ exit (1);
+ }
+ if(!counters_created)
+ {
+ create_counters();
+ counters_created= 1;
+ }
+ PR_INCREMENT_COUNTER(slapi_ch_counter_strdup);
+ PR_INCREMENT_COUNTER(slapi_ch_counter_created);
+ PR_INCREMENT_COUNTER(slapi_ch_counter_exist);
+#if defined(_WIN32) && defined(DEBUG)
+ if(recording)
+ {
+ add_memory_record(newmem,strlen(s1)+1);
+ }
+#endif
+ return newmem;
+}
+
+struct berval*
+slapi_ch_bvdup (const struct berval* v)
+{
+ struct berval* newberval = ber_bvdup ((struct berval *)v);
+ if (newberval == NULL) {
+ int oserr = errno;
+
+ oom_occurred();
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPD_MODULE,
+ "ber_bvdup of %lu bytes failed; OS error %d (%s)%s\n",
+ (unsigned long)v->bv_len, oserr, slapd_system_strerror( oserr ),
+ oom_advice );
+ exit( 1 );
+ }
+ return newberval;
+}
+
+struct berval**
+slapi_ch_bvecdup (struct berval** v)
+{
+ struct berval** newberval = NULL;
+ if (v != NULL) {
+ size_t i = 0;
+ while (v[i] != NULL) ++i;
+ newberval = (struct berval**) slapi_ch_malloc ((i + 1) * sizeof (struct berval*));
+ newberval[i] = NULL;
+ while (i-- > 0) {
+ newberval[i] = slapi_ch_bvdup (v[i]);
+ }
+ }
+ return newberval;
+}
+
+/*
+ * Function: slapi_ch_free
+ *
+ * Returns: nothing
+ *
+ * Description: frees the pointer, and then sets it to NULL to
+ * prevent free-memory writes.
+ * Note: pass in the address of the pointer you want to free.
+ * Note: you can pass in null pointers, it's cool.
+ */
+void
+slapi_ch_free(void **ptr)
+{
+ if (ptr==NULL || *ptr == NULL){
+ return;
+ }
+
+#if defined(_WIN32) && defined(DEBUG)
+ if(recording)
+ {
+ remove_memory_record(*ptr);
+ }
+#endif
+ free (*ptr);
+ *ptr = NULL;
+ if(!counters_created)
+ {
+ create_counters();
+ counters_created= 1;
+ }
+ PR_INCREMENT_COUNTER(slapi_ch_counter_free);
+ PR_DECREMENT_COUNTER(slapi_ch_counter_exist);
+ return;
+}
+
+
+/* just like slapi_ch_free, takes the address of the struct berval pointer */
+void
+slapi_ch_bvfree(struct berval** v)
+{
+ if (v == NULL || *v == NULL)
+ return;
+
+ slapi_ch_free((void **)&((*v)->bv_val));
+ slapi_ch_free((void **)v);
+
+ return;
+}
+
+/* just like slapi_ch_free, but the argument is the address of a string
+ This helps with compile time error checking
+*/
+void
+slapi_ch_free_string(char **s)
+{
+ slapi_ch_free((void **)s);
+}
+
+/* ========================= NT Specific Leak Checking Code ================================== */
+
+#if defined(_WIN32) && defined(DEBUG)
+#define STOP_TRAVERSAL -2
+#define MR_CALL_STACK 16
+#define MR_DUMP_AMOUNT 16
+static Avlnode *mr_tree= NULL;
+static PRLock *mr_tree_lock= NULL;
+#endif
+
+void
+slapi_ch_start_recording()
+{
+#if defined(_WIN32) && defined(DEBUG)
+ if(mr_tree_lock==NULL)
+ {
+ mr_tree_lock = PR_NewLock();
+ }
+ PR_Lock( mr_tree_lock );
+ recording= 1;
+ PR_Unlock( mr_tree_lock );
+#endif
+}
+
+void
+slapi_ch_stop_recording()
+{
+#if defined(_WIN32) && defined(DEBUG)
+ PR_Lock( mr_tree_lock );
+ recording= 0;
+ avl_apply( mr_tree, memory_record_dump, NULL, STOP_TRAVERSAL, AVL_INORDER );
+ avl_free( mr_tree, memory_record_delete );
+ mr_tree= NULL;
+ PR_Unlock( mr_tree_lock );
+#endif
+}
+
+#if defined(_WIN32) && defined(DEBUG)
+
+struct memory_record
+{
+ void *p;
+ unsigned long size;
+ DWORD ra[MR_CALL_STACK];
+};
+
+
+static void
+mr_to_hex_dump(char* dest, void *addr, int size, int MaxBytes)
+{
+ int i;
+ for (i=0; i<MaxBytes; i++)
+ {
+ if(i<size)
+ {
+ wsprintf(dest+i*2, "%02x", ((unsigned char*)addr)[i]);
+ }
+ else
+ {
+ strcpy(dest+i*2, " ");
+ }
+ }
+}
+
+static void
+mr_to_char_dump(char* dest, void *addr, int size, int MaxBytes)
+{
+ int i;
+ char *c= (char*)addr;
+ for(i=0;i<MaxBytes;i++)
+ {
+ if(i<size)
+ {
+ *(dest+i)= (isprint(*c)?*c:'.');
+ c++;
+ }
+ else
+ {
+ *(dest+i)= ' ';
+ }
+ }
+ *(dest+i)= '\0';
+}
+
+
+/*
+ * Check that the address is (probably) valid
+ */
+static int ValidateBP(UINT bp)
+{
+ return !(IsBadReadPtr((void*)bp, 4) || IsBadWritePtr((void*)bp, 4));
+}
+
+/*
+ * Check that the address is (probably) valid
+ */
+static int ValidateIP(UINT ip)
+{
+ return !IsBadReadPtr((void*)ip, 4);
+}
+
+static int
+memory_record_delete( caddr_t data, caddr_t arg )
+{
+ struct memory_record *mr = (struct memory_record *)data;
+ free(mr);
+ return 0;
+}
+
+static int
+memory_record_duplicate_disallow( caddr_t d1, caddr_t d2 )
+{
+ return -1;
+}
+
+static int
+memory_record_compare( caddr_t d1, caddr_t d2 )
+{
+ struct memory_record *mr1 = (struct memory_record *)d1;
+ struct memory_record *mr2 = (struct memory_record *)d2;
+ return (mr1->p==mr2->p);
+}
+
+static void
+grab_stack(DWORD *ra,int framestograb,int framestoskip)
+{
+ int framelookingat = 0;
+ int framestoring = 0;
+ DWORD _bp = 0;
+
+ /* for every function the frame layout is:
+ * ---------
+ * |ret add|
+ * ---------
+ * |old bp | <- new bp
+ * ---------
+ */
+
+ __asm mov _bp, ebp;
+
+ if(framestoskip==0)
+ {
+ ra[framestoring]= _bp;
+ framestoring++;
+ }
+ while (framelookingat < framestograb+framestoskip-1)
+ {
+ DWORD returnAddress = *(((DWORD*)_bp)+1);
+ _bp = *((DWORD*)_bp);
+ if (!ValidateBP(_bp)) break;
+ if (!ValidateIP(returnAddress)) break;
+ if(framelookingat>=framestoskip)
+ {
+ ra[framestoring]= returnAddress;
+ framestoring++;
+ }
+ framelookingat++;
+ }
+ ra[framestoring]= 0;
+}
+
+static void
+add_memory_record(void *p,unsigned long size)
+{
+ struct memory_record *mr= (struct memory_record *)malloc(sizeof(struct memory_record));
+ mr->p= p;
+ mr->size= size;
+ grab_stack(mr->ra,MR_CALL_STACK,1);
+ PR_Lock( mr_tree_lock );
+ avl_insert( &mr_tree, mr, memory_record_compare, memory_record_duplicate_disallow );
+ PR_Unlock( mr_tree_lock );
+}
+
+static void
+remove_memory_record(void *p)
+{
+ struct memory_record *mr = NULL;
+ struct memory_record search;
+ PR_Lock( mr_tree_lock );
+ search.p= p;
+ mr = (struct memory_record *)avl_find( mr_tree, &search, memory_record_compare );
+ if(mr!=NULL)
+ {
+ avl_delete( &mr_tree, mr, memory_record_compare );
+ }
+ PR_Unlock( mr_tree_lock );
+}
+
+#include <imagehlp.h>
+#pragma comment(lib, "imagehlp")
+
+static BOOL SymInitialized= FALSE;
+static HANDLE s_hProcess= NULL;
+
+BOOL InitialiseImageHelp()
+{
+ if (!SymInitialized)
+ {
+ /*
+ * searchpath= <instancedir>\bin\slapd\server;<instancedir>\lib
+ */
+ char *searchpath= NULL;
+ char *id= config_get_instancedir();
+ if(id!=NULL)
+ {
+ char *p= id;
+ while(p!=NULL)
+ {
+ p= strchr(id,'/');
+ if(p!=NULL) *p='\\';
+ }
+ p= strrchr(id,'\\');
+ if(p!=NULL)
+ {
+ *p= '\0';
+ searchpath= slapi_ch_malloc(100+strlen(p)*2);
+ strcpy(searchpath,id);
+ strcat(searchpath,"\\bin\\slapd\\server;");
+ strcat(searchpath,id);
+ strcat(searchpath,"\\lib");
+ }
+ }
+ s_hProcess = GetCurrentProcess();
+ SymInitialized = SymInitialize(s_hProcess, searchpath, TRUE);
+ slapi_ch_free((void**)&id);
+ slapi_ch_free((void**)&searchpath);
+ if (SymInitialized)
+ {
+ SymSetOptions(SYMOPT_DEFERRED_LOADS);
+ }
+ }
+ return SymInitialized;
+}
+
+BOOL AddressToName(DWORD Addr, LPTSTR Str, int Max)
+{
+ DWORD base;
+ if (!InitialiseImageHelp())
+ return FALSE;
+ base = SymGetModuleBase(s_hProcess, Addr);
+ if (base)
+ {
+ struct
+ {
+ IMAGEHLP_SYMBOL ihs;
+ char NameBuf[256];
+ } SymInfo;
+ DWORD Displacement = 0;
+ SymInfo.ihs.SizeOfStruct = sizeof(SymInfo);
+ SymInfo.ihs.MaxNameLength = sizeof(SymInfo.NameBuf);
+ if (SymGetSymFromAddr(s_hProcess, Addr, &Displacement, &SymInfo.ihs))
+ {
+ if (Displacement)
+ _snprintf(Str, Max-1, "%s+%x", SymInfo.ihs.Name, Displacement);
+ else
+ _snprintf(Str, Max-1, "%s", SymInfo.ihs.Name);
+ return TRUE;
+ }
+ else
+ {
+ _snprintf(Str, Max, "SymGetSymFromAddr failed (%d)", GetLastError());
+ }
+ }
+ else
+ {
+ _snprintf(Str, Max, "SymGetModuleBase failed (%d)", GetLastError());
+ }
+ return FALSE;
+}
+
+static int
+memory_record_dump( caddr_t data, caddr_t arg )
+{
+ int frame= 0;
+ char b1[MR_DUMP_AMOUNT*2+1];
+ char b2[MR_DUMP_AMOUNT+1];
+ char b3[128];
+ int size= 0;
+ struct memory_record *mr = (struct memory_record *)data;
+ if(!IsBadReadPtr(mr->p, MR_DUMP_AMOUNT))
+ {
+ size= MR_DUMP_AMOUNT;
+ }
+ mr_to_hex_dump(b1, mr->p, size, MR_DUMP_AMOUNT);
+ mr_to_char_dump(b2, mr->p, size, MR_DUMP_AMOUNT);
+ sprintf(b3,"%p %ld %s %s",mr->p,mr->size,b1,b2);
+ LDAPDebug( LDAP_DEBUG_ANY, "%s\n",b3,0,0);
+ while(mr->ra[frame]!=0)
+ {
+ char fn[100];
+ AddressToName(mr->ra[frame], fn, 100);
+ LDAPDebug( LDAP_DEBUG_ANY, "%d %p %s\n",frame,mr->ra[frame],fn);
+ frame++;
+ }
+ return 0;
+}
+
+#endif
+
+
diff --git a/ldap/servers/slapd/charray.c b/ldap/servers/slapd/charray.c
new file mode 100644
index 00000000..77c264ca
--- /dev/null
+++ b/ldap/servers/slapd/charray.c
@@ -0,0 +1,354 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* charray.c - routines for dealing with char * arrays */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+
+void
+charray_add(
+ char ***a,
+ char *s
+)
+{
+ int n;
+
+ if ( *a == NULL ) {
+ *a = (char **) slapi_ch_malloc( 2 * sizeof(char *) );
+ n = 0;
+ } else {
+ for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
+ ; /* NULL */
+ }
+
+ *a = (char **) slapi_ch_realloc( (char *) *a,
+ (n + 2) * sizeof(char *) );
+ }
+
+ /* At this point, *a may be different from the value it had when this
+ * function is called. Furthermore, *a[n] may contain an arbitrary
+ * value, such as a pointer to the middle of a unallocated area.
+ */
+
+#ifdef TEST_BELLATON
+ (*a)[n+1] = NULL;
+ (*a)[n] = s;
+#endif
+
+ /* Putting code back so that thread conflict can be made visible */
+
+ (*a)[n++] = s;
+ (*a)[n] = NULL;
+
+}
+
+void
+charray_merge(
+ char ***a,
+ char **s,
+ int copy_strs
+)
+{
+ int i, n, nn;
+
+ if ( (s == NULL) || (s[0] == NULL) )
+ return;
+
+ for ( n = 0; *a != NULL && (*a)[n] != NULL; n++ ) {
+ ; /* NULL */
+ }
+ for ( nn = 0; s[nn] != NULL; nn++ ) {
+ ; /* NULL */
+ }
+
+ *a = (char **) slapi_ch_realloc( (char *) *a, (n + nn + 1) * sizeof(char *) );
+
+ for ( i = 0; i < nn; i++ ) {
+ if ( copy_strs ) {
+ (*a)[n + i] = slapi_ch_strdup( s[i] );
+ } else {
+ (*a)[n + i] = s[i];
+ }
+ }
+ (*a)[n + nn] = NULL;
+}
+
+/* Routines which don't pound on malloc. Don't interchange the arrays with the
+ * regular calls---they can end up freeing non-heap memory, which is wrong */
+
+void
+cool_charray_free( char **array )
+{
+ slapi_ch_free((void**)&array);
+}
+
+/* Like strcpy, but returns a pointer to the next byte after the last one written to */
+static char *strcpy_len(char *dest, char *source)
+{
+ if('\0' == (*source)) {
+ return(dest);
+ }
+ do {
+ *dest++ = *source++;
+ } while (*source);
+ return dest;
+}
+
+char **
+cool_charray_dup( char **a )
+{
+ int i,size, num_strings;
+ char **newa;
+ char *p;
+
+ if ( a == NULL ) {
+ return( NULL );
+ }
+
+ for ( i = 0; a[i] != NULL; i++ )
+ ; /* NULL */
+
+ num_strings = i;
+ size = (i + 1) * sizeof(char *);
+
+ for ( i = 0; a[i] != NULL; i++ ) {
+ size += strlen( a[i] ) + 1;
+ }
+
+ newa = (char **) slapi_ch_malloc( size );
+
+ p = (char *) &(newa[num_strings + 1]);
+
+ for ( i = 0; a[i] != NULL; i++ ) {
+ newa[i] = p;
+ p = strcpy_len(p, a[i] );
+ *p++ = '\0';
+ }
+ newa[i] = NULL;
+
+ return( newa );
+}
+
+void
+charray_free( char **array )
+{
+ char **a;
+
+ if ( array == NULL ) {
+ return;
+ }
+
+ for ( a = array; *a != NULL; a++ )
+ {
+ char *tmp= *a;
+ slapi_ch_free((void**)&tmp);
+ }
+ slapi_ch_free( (void**)&array );
+}
+
+/*
+ * charray_free version for plugins: there is a need for plugins to free
+ * the ch_arrays returned by functions like:
+ * slapi_get_supported_extended_ops_copy
+ * slapi_get_supported_saslmechanisms_copy
+ * slapi_get_supported_controls_copy
+ */
+void
+slapi_ch_array_free( char **array )
+{
+ charray_free (array);
+}
+
+
+/* case insensitive search */
+int
+charray_inlist(
+ char **a,
+ char *s
+)
+{
+ int i;
+
+ if ( a == NULL ) {
+ return( 0 );
+ }
+
+ for ( i = 0; a[i] != NULL; i++ ) {
+ if ( strcasecmp( s, a[i] ) == 0 ) {
+ return( 1 );
+ }
+ }
+
+ return( 0 );
+}
+
+/* case insensitive search covering non-ascii */
+int
+charray_utf8_inlist(
+ char **a,
+ char *s
+)
+{
+ int i;
+
+ if ( a == NULL ) {
+ return( 0 );
+ }
+
+ for ( i = 0; a[i] != NULL; i++ ) {
+ if (!slapi_UTF8CASECMP(a[i], s)) {
+ return( 1 );
+ }
+ }
+
+ return( 0 );
+}
+
+char **
+charray_dup( char **a )
+{
+ int i;
+ char **newa;
+
+ if ( a == NULL ) {
+ return( NULL );
+ }
+
+ for ( i = 0; a[i] != NULL; i++ )
+ ; /* NULL */
+
+ newa = (char **) slapi_ch_malloc( (i + 1) * sizeof(char *) );
+
+ for ( i = 0; a[i] != NULL; i++ ) {
+ newa[i] = slapi_ch_strdup( a[i] );
+ }
+ newa[i] = NULL;
+
+ return( newa );
+}
+
+char **
+str2charray( char *str, char *brkstr )
+{
+ char **res;
+ char *s;
+ int i;
+ char * iter = NULL;
+
+ i = 1;
+ for ( s = str; *s; s++ ) {
+ if ( strchr( brkstr, *s ) != NULL ) {
+ i++;
+ }
+ }
+
+ res = (char **) slapi_ch_malloc( (i + 1) * sizeof(char *) );
+ i = 0;
+ for ( s = ldap_utf8strtok_r( str, brkstr , &iter); s != NULL;
+ s = ldap_utf8strtok_r( NULL, brkstr , &iter) ) {
+ res[i++] = slapi_ch_strdup( s );
+ }
+ res[i] = NULL;
+
+ return( res );
+}
+
+void
+charray_print( char **a )
+{
+ int i;
+
+ printf( "charray_print:\n");
+ for ( i = 0; a!= NULL && a[i] != NULL; i++ ) {
+ printf( "\t%s\n", a[i]);
+ }
+}
+
+/*
+ * Remove the char string from the array of char strings.
+ * Performs a case *insensitive* comparison!
+ * Just shunts the strings down to cover the deleted string.
+ * Doesn't free up the unused memory.
+ * Returns 1 if the entry found and removed, 0 if not.
+ */
+int
+charray_remove(
+ char **a,
+ const char *s
+)
+{
+ int i;
+ int found= 0;
+ for ( i=0; a!= NULL && a[i] != NULL; i++ )
+ {
+ if ( !found && strcasecmp (a[i],s) == 0 )
+ {
+ found= 1;
+ }
+ if (found)
+ {
+ a[i]= a[i+1];
+ }
+ }
+ return found;
+}
+
+/*
+ * if c == NULL, a = a - b
+ * if c != NULL, *c = a - b
+ */
+#define SUBTRACT_DEL (char *)(-1)
+void
+charray_subtract(char **a, char **b, char ***c)
+{
+ char **bp, **cp, **tmp;
+ char **p;
+
+ if (c)
+ tmp = *c = cool_charray_dup(a);
+ else
+ tmp = a;
+
+ for (cp = tmp; cp && *cp; cp++) {
+ for (bp = b; bp && *bp; bp++) {
+ if (!slapi_UTF8CASECMP(*cp, *bp)) {
+ slapi_ch_free((void **)&*cp);
+ *cp = SUBTRACT_DEL;
+ break;
+ }
+ }
+ }
+
+ for (cp = tmp; cp && *cp; cp++) {
+ if (*cp == SUBTRACT_DEL) {
+ for (p = cp+1; *p && *p == (char *)SUBTRACT_DEL; p++)
+ ;
+ *cp = *p;
+ if (*p == NULL)
+ break;
+ else
+ *p = SUBTRACT_DEL;
+ }
+ }
+}
+
+int
+charray_get_index(char **array, char *s)
+{
+ int i;
+
+ for (i = 0; array && array[i]; i++)
+ {
+ if (!slapi_UTF8CASECMP(array[i], s))
+ return i;
+ }
+ return -1;
+}
diff --git a/ldap/servers/slapd/compare.c b/ldap/servers/slapd/compare.c
new file mode 100644
index 00000000..8030871b
--- /dev/null
+++ b/ldap/servers/slapd/compare.c
@@ -0,0 +1,153 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#include "pratom.h"
+
+
+void
+do_compare( Slapi_PBlock *pb )
+{
+ BerElement *ber = pb->pb_op->o_ber;
+ char *dn;
+ struct ava ava;
+ Slapi_Backend *be = NULL;
+ int err;
+ char ebuf[ BUFSIZ ];
+ Slapi_DN sdn;
+ Slapi_Entry *referral;
+ char errorbuf[BUFSIZ];
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_compare\n", 0, 0, 0 );
+
+ /* count the compare request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsCompareOps);
+
+ /*
+ * Parse the compare request. It looks like this:
+ *
+ * CompareRequest := [APPLICATION 14] SEQUENCE {
+ * entry DistinguishedName,
+ * ava SEQUENCE {
+ * type AttributeType,
+ * value AttributeValue
+ * }
+ * }
+ */
+
+
+ if ( ber_scanf( ber, "{a{ao}}", &dn, &ava.ava_type,
+ &ava.ava_value ) == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=Compare; params=DN,Type,Value)\n",
+ 0, 0, 0 );
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
+ NULL );
+ return;
+ }
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+ slapi_sdn_init_dn_passin(&sdn,dn);
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ operation_set_target_spec (pb->pb_op, &sdn);
+
+ LDAPDebug( LDAP_DEBUG_ARGS, "do_compare: dn (%s) attr (%s)\n",
+ dn, ava.ava_type, 0 );
+
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d CMP dn=\"%s\" attr=\"%s\"\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid,
+ escape_string( dn, ebuf ), ava.ava_type );
+
+ /*
+ * We could be serving multiple database backends. Select the
+ * appropriate one.
+ */
+ if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf)) != LDAP_SUCCESS) {
+ send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
+ be = NULL;
+ goto free_and_return;
+ }
+
+ if (referral)
+ {
+ int managedsait;
+
+ slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ if (managedsait)
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "cannot compare referral", 0, NULL);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ send_referrals_from_entry(pb,referral);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ if ( be->be_compare != NULL ) {
+ int isroot;
+
+ slapi_pblock_set( pb, SLAPI_BACKEND, be );
+ isroot = pb->pb_op->o_isroot;
+
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ slapi_pblock_set( pb, SLAPI_COMPARE_TARGET, (void*)slapi_sdn_get_ndn(&sdn) );
+ slapi_pblock_set( pb, SLAPI_COMPARE_TYPE, ava.ava_type);
+ slapi_pblock_set( pb, SLAPI_COMPARE_VALUE, &ava.ava_value );
+ /*
+ * call the pre-compare plugins. if they succeed, call
+ * the backend compare function. then call the
+ * post-compare plugins.
+ */
+ if ( plugin_call_plugins( pb,
+ SLAPI_PLUGIN_PRE_COMPARE_FN ) == 0 ) {
+ int rc;
+
+ slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database );
+ set_db_default_result_handlers(pb);
+ rc = (*be->be_compare)( pb );
+
+ slapi_pblock_set( pb, SLAPI_PLUGIN_OPRETURN, &rc );
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_COMPARE_FN );
+ }
+ } else {
+ send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Function not implemented", 0, NULL );
+ }
+
+free_and_return:;
+ if (be)
+ slapi_be_Unlock(be);
+ slapi_sdn_done(&sdn);
+ ava_done( &ava );
+}
diff --git a/ldap/servers/slapd/computed.c b/ldap/servers/slapd/computed.c
new file mode 100644
index 00000000..638c8159
--- /dev/null
+++ b/ldap/servers/slapd/computed.c
@@ -0,0 +1,208 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* Handles computed attributes for entries as they're returned to the client */
+
+#include "slap.h"
+
+
+/* Structure used to pass the context needed for completing a computed attribute operation */
+struct _computed_attr_context {
+ BerElement *ber;
+ int attrsonly;
+ char *requested_type;
+ Slapi_PBlock *pb;
+};
+
+
+struct _compute_evaluator {
+ struct _compute_evaluator *next;
+ slapi_compute_callback_t function;
+};
+typedef struct _compute_evaluator compute_evaluator;
+
+static compute_evaluator *compute_evaluators = NULL;
+static PRRWLock *compute_evaluators_lock = NULL;
+
+static int
+compute_stock_evaluator(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_compute_output_t outputfn);
+
+struct _compute_rewriter {
+ struct _compute_rewriter *next;
+ slapi_search_rewrite_callback_t function;
+};
+typedef struct _compute_rewriter compute_rewriter;
+
+static compute_rewriter *compute_rewriters = NULL;
+static PRRWLock *compute_rewriters_lock = NULL;
+
+/* Function called by evaluators to have the value output */
+static int
+compute_output_callback(computed_attr_context *c,Slapi_Attr *a , Slapi_Entry *e)
+{
+ return encode_attr (c->pb, c->ber, e, a, c->attrsonly, c->requested_type);
+}
+
+static int
+compute_call_evaluators(computed_attr_context *c,slapi_compute_output_t outfn,char *type,Slapi_Entry *e)
+{
+ int rc = -1;
+ compute_evaluator *current = NULL;
+ /* Walk along the list (locked) calling the evaluator functions util one says yes, an error happens, or we finish */
+ PR_RWLock_Rlock(compute_evaluators_lock);
+ for (current = compute_evaluators; (current != NULL) && (-1 == rc); current = current->next) {
+ rc = (*(current->function))(c,type,e,outfn);
+ }
+ PR_RWLock_Unlock(compute_evaluators_lock);
+ return rc;
+}
+
+/* Returns : -1 if no attribute matched the requested type */
+/* 0 if one matched and it was processed without error */
+/* >0 if an error happened */
+int
+compute_attribute(char *type, Slapi_PBlock *pb,BerElement *ber,Slapi_Entry *e,int attrsonly,char *requested_type)
+{
+ computed_attr_context context;
+
+ context.ber = ber;
+ context.attrsonly = attrsonly;
+ context.requested_type = requested_type;
+ context.pb = pb;
+
+ return compute_call_evaluators(&context,compute_output_callback,type,e);
+}
+
+static int
+compute_stock_evaluator(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_compute_output_t outputfn)
+{
+ int rc= -1;
+ static char* subschemasubentry = "subschemasubentry";
+
+ if ( strcasecmp (type, subschemasubentry ) == 0)
+ {
+ Slapi_Attr our_attr;
+ slapi_attr_init(&our_attr, subschemasubentry);
+ our_attr.a_flags = SLAPI_ATTR_FLAG_OPATTR;
+ valueset_add_string(&our_attr.a_present_values,SLAPD_SCHEMA_DN,CSN_TYPE_UNKNOWN,NULL);
+ rc = (*outputfn) (c, &our_attr, e);
+ attr_done(&our_attr);
+ return (rc);
+ }
+ return rc; /* I see no ships */
+}
+
+int slapi_compute_add_evaluator(slapi_compute_callback_t function)
+{
+ int rc = 0;
+ compute_evaluator *new_eval = NULL;
+ PR_ASSERT(NULL != function);
+ PR_ASSERT(NULL != compute_evaluators_lock);
+ PR_RWLock_Wlock(compute_evaluators_lock);
+ new_eval = calloc(1,sizeof (compute_evaluator));
+ if (NULL == new_eval) {
+ rc = ENOMEM;
+ } else {
+ new_eval->next = compute_evaluators;
+ new_eval->function = function;
+ compute_evaluators = new_eval;
+ }
+ PR_RWLock_Unlock(compute_evaluators_lock);
+ return rc;
+}
+
+/* Call this on server startup, before the first LDAP operation is serviced */
+int compute_init()
+{
+ /* Initialize the lock */
+ compute_evaluators_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE, "compute_attr_lock" );
+ if (NULL == compute_evaluators_lock) {
+ /* Out of resources */
+ return ENOMEM;
+ }
+ compute_rewriters_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE, "compute_rewriters_lock" );
+ if (NULL == compute_rewriters_lock) {
+ /* Out of resources */
+ return ENOMEM;
+ }
+ /* Now add the stock evaluators to the list */
+ return slapi_compute_add_evaluator(compute_stock_evaluator);
+}
+
+/* Call this on server shutdown, after the last LDAP operation has
+terminated */
+int compute_terminate()
+{
+ /* Free the list */
+ if (NULL != compute_evaluators_lock) {
+ compute_evaluator *current = compute_evaluators;
+ PR_RWLock_Wlock(compute_evaluators_lock);
+ while (current != NULL) {
+ compute_evaluator *asabird = current;
+ current = current->next;
+ free(asabird);
+ }
+ PR_RWLock_Unlock(compute_evaluators_lock);
+ /* Free the lock */
+ PR_DestroyRWLock(compute_evaluators_lock);
+ }
+ if (NULL != compute_rewriters_lock) {
+ compute_rewriter *current = compute_rewriters;
+ PR_RWLock_Wlock(compute_rewriters_lock);
+ while (current != NULL) {
+ compute_rewriter *asabird = current;
+ current = current->next;
+ free(asabird);
+ }
+ PR_RWLock_Unlock(compute_rewriters_lock);
+ PR_DestroyRWLock(compute_rewriters_lock);
+ }
+ return 0;
+}
+
+/* Functions dealing with re-writing of search filters */
+
+int slapi_compute_add_search_rewriter(slapi_search_rewrite_callback_t function)
+{
+ int rc = 0;
+ compute_rewriter *new_rewriter = NULL;
+ PR_ASSERT(NULL != function);
+ PR_ASSERT(NULL != compute_rewriters_lock);
+ new_rewriter = calloc(1,sizeof (compute_rewriter));
+ if (NULL == new_rewriter) {
+ rc = ENOMEM;
+ } else {
+ PR_RWLock_Wlock(compute_rewriters_lock);
+ new_rewriter->next = compute_rewriters;
+ new_rewriter->function = function;
+ compute_rewriters = new_rewriter;
+ PR_RWLock_Unlock(compute_rewriters_lock);
+ }
+ return rc;
+}
+
+int compute_rewrite_search_filter(Slapi_PBlock *pb)
+{
+ /* Iterate through the listed rewriters until one says it matched */
+ int rc = -1;
+ compute_rewriter *current = NULL;
+ /* Walk along the list (locked) calling the evaluator functions util one says yes, an error happens, or we finish */
+ PR_RWLock_Rlock(compute_rewriters_lock);
+ for (current = compute_rewriters; (current != NULL) && (-1 == rc); current = current->next) {
+ rc = (*(current->function))(pb);
+ /* Meaning of the return code :
+ -1 : keep looking
+ 0 : rewrote OK
+ 1 : refuse to do this search
+ 2 : operations error
+ */
+ }
+ PR_RWLock_Unlock(compute_rewriters_lock);
+ return rc;
+
+}
+
+
diff --git a/ldap/servers/slapd/config.c b/ldap/servers/slapd/config.c
new file mode 100644
index 00000000..2e3170a4
--- /dev/null
+++ b/ldap/servers/slapd/config.c
@@ -0,0 +1,459 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* config.c - configuration file handling routines */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifdef _WIN32
+#include <direct.h> /* for getcwd */
+#else
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <pwd.h>
+#endif
+#include "slap.h"
+#include "pw.h"
+#include <sys/stat.h>
+#include <prio.h>
+
+#define MAXARGS 1000
+
+
+extern int should_detach;
+extern Slapi_PBlock *repl_pb;
+
+
+extern char* slapd_SSL3ciphers;
+
+#ifndef _WIN32
+extern char *localuser;
+#endif
+
+char* rel2abspath( char * );
+
+/*
+ See if the given entry has an attribute with the given name and the
+ given value; if value is NULL, just test for the presence of the given
+ attribute; if value is an empty string (i.e. value[0] == 0),
+ the first value in the attribute will be copied into the given buffer
+ and returned
+*/
+static int
+entry_has_attr_and_value(Slapi_Entry *e, const char *attrname,
+ char *value, size_t valuebufsize )
+{
+ int retval = 0;
+ Slapi_Attr *attr = 0;
+ if (!e || !attrname)
+ return retval;
+
+ /* see if the entry has the specified attribute name */
+ if (!slapi_entry_attr_find(e, attrname, &attr) && attr)
+ {
+ /* if value is not null, see if the attribute has that
+ value */
+ if (!value)
+ {
+ retval = 1;
+ }
+ else
+ {
+ Slapi_Value *v = 0;
+ int index = 0;
+ for (index = slapi_attr_first_value(attr, &v);
+ v && (index != -1);
+ index = slapi_attr_next_value(attr, index, &v))
+ {
+ const char *s = slapi_value_get_string(v);
+ if (!s)
+ continue;
+
+ if (!*value)
+ {
+ size_t len = strlen(s);
+
+ if ( len < valuebufsize )
+ {
+ strcpy(value, s);
+ retval = 1;
+ }
+ else
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, "bootstrap config",
+ "Ignoring extremely large value for"
+ " configuration attribute %s"
+ " (length=%d, value=%40.40s...)\n",
+ attrname, len, s );
+ retval = 0; /* value is too large: ignore it */
+ }
+ break;
+ }
+ else if (!strcasecmp(s, value))
+ {
+ retval = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
+
+/*
+ Extract just the configuration information we need for bootstrapping
+ purposes
+ 1) set up error logging
+ 2) disable syntax checking
+ 3) load the syntax plugins
+ etc.
+*/
+int
+slapd_bootstrap_config(const char *configdir)
+{
+ char configfile[MAXPATHLEN+1];
+ PRFileInfo prfinfo;
+ int rc = 0; /* Fail */
+ int done = 0;
+ PRInt32 nr = 0;
+ PRFileDesc *prfd = 0;
+ char *buf = 0;
+ char *lastp = 0;
+ char *entrystr = 0;
+
+ PR_snprintf(configfile, sizeof(configfile), "%s/%s", configdir,
+ CONFIG_FILENAME);
+ if ( (rc = PR_GetFileInfo( configfile, &prfinfo )) != PR_SUCCESS )
+ {
+ /* the "real" file does not exist; see if there is a tmpfile */
+ char tmpfile[MAXPATHLEN+1];
+ PR_snprintf(tmpfile, sizeof(tmpfile), "%s/%s.tmp", configdir,
+ CONFIG_FILENAME);
+ if ( PR_GetFileInfo( tmpfile, &prfinfo ) == PR_SUCCESS ) {
+ rc = PR_Rename(tmpfile, configfile);
+ if (rc == PR_SUCCESS) {
+ slapi_log_error(SLAPI_LOG_FATAL, "config",
+ "The configuration file %s was restored from backup %s\n",
+ configfile, tmpfile);
+ rc = 1;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, "config",
+ "The configuration file %s was not restored from backup %s, error %d\n",
+ configfile, tmpfile, rc);
+ rc = 0;
+ }
+ } else {
+ rc = 0; /* fail */
+ }
+ }
+ if ( (rc = PR_GetFileInfo( configfile, &prfinfo )) != PR_SUCCESS )
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error(SLAPI_LOG_FATAL, "config", "The given config file %s could not be accessed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ configfile, prerr, slapd_pr_strerror(prerr));
+ rc = 0; /* Fail */
+ }
+ else if (( prfd = PR_Open( configfile, PR_RDONLY,
+ SLAPD_DEFAULT_FILE_MODE )) == NULL )
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error(SLAPI_LOG_FATAL, "config", "The given config file %s could not be opened for reading, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ configfile, prerr, slapd_pr_strerror(prerr));
+ rc = 0; /* Fail */
+ }
+ else
+ {
+ /* read the entire file into core */
+ buf = slapi_ch_malloc( prfinfo.size + 1 );
+ if (( nr = slapi_read_buffer( prfd, buf, prfinfo.size )) < 0 )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "config", "Could only read %d of %d bytes from config file %s\n",
+ nr, prfinfo.size, configfile);
+ rc = 0; /* Fail */
+ done= 1;
+ }
+
+ (void)PR_Close(prfd);
+ buf[ nr ] = '\0';
+
+ if(!done)
+ {
+ char errorlog[MAXPATHLEN+1];
+ char loglevel[BUFSIZ];
+ char maxdescriptors[BUFSIZ];
+ char val[BUFSIZ];
+ char logenabled[BUFSIZ];
+ char schemacheck[BUFSIZ];
+ Slapi_DN plug_dn;
+
+ errorlog[0] = loglevel[0] = maxdescriptors[0] = '\0';
+ val[0] = logenabled[0] = schemacheck[0] = '\0';
+
+ /* Convert LDIF to entry structures */
+ slapi_sdn_init_dn_byref(&plug_dn, PLUGIN_BASE_DN);
+ while ((entrystr = dse_read_next_entry(buf, &lastp)) != NULL)
+ {
+ char errorbuf[BUFSIZ];
+ /*
+ * XXXmcs: it would be better to also pass
+ * SLAPI_STR2ENTRY_REMOVEDUPVALS in the flags, but
+ * duplicate value checking requires that the syntax
+ * and schema subsystems be initialized... and they
+ * are not yet.
+ */
+ Slapi_Entry *e = slapi_str2entry(entrystr,
+ SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF);
+ if (e == NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "The entry [%s] in the configfile %s was empty or could not be parsed\n",
+ entrystr, configfile, 0);
+ continue;
+ }
+
+ /* increase file descriptors */
+#if !defined(_WIN32) && !defined(AIX)
+ if (!maxdescriptors[0] &&
+ entry_has_attr_and_value(e, CONFIG_MAXDESCRIPTORS_ATTRIBUTE,
+ maxdescriptors, sizeof(maxdescriptors)))
+ {
+ if (config_set_maxdescriptors(
+ CONFIG_MAXDESCRIPTORS_ATTRIBUTE,
+ maxdescriptors, errorbuf, CONFIG_APPLY)
+ != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
+ CONFIG_MAXDESCRIPTORS_ATTRIBUTE, errorbuf);
+ }
+ }
+#endif /* !defined(_WIN32) && !defined(AIX) */
+
+ /* see if we need to enable error logging */
+ if (!logenabled[0] &&
+ entry_has_attr_and_value(e,
+ CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE,
+ logenabled, sizeof(logenabled)))
+ {
+ if (log_set_logging(
+ CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE,
+ logenabled, SLAPD_ERROR_LOG, errorbuf, CONFIG_APPLY)
+ != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
+ CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE, errorbuf);
+ }
+ }
+
+ /* set the log file name */
+ if (!errorlog[0] &&
+ entry_has_attr_and_value(e, CONFIG_ERRORLOG_ATTRIBUTE,
+ errorlog, sizeof(errorlog)))
+ {
+ if (config_set_errorlog(CONFIG_ERRORLOG_ATTRIBUTE,
+ errorlog, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile,
+ CONFIG_ERRORLOG_ATTRIBUTE, errorbuf);
+ }
+ }
+
+ /* set the error log level */
+ if (!loglevel[0] &&
+ entry_has_attr_and_value(e, CONFIG_LOGLEVEL_ATTRIBUTE,
+ loglevel, sizeof(loglevel)))
+ {
+ if (should_detach || !config_get_errorlog_level())
+ { /* -d wasn't on command line */
+ if (config_set_errorlog_level(CONFIG_LOGLEVEL_ATTRIBUTE,
+ loglevel, errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s. \n", configfile,
+ CONFIG_LOGLEVEL_ATTRIBUTE, errorbuf);
+ }
+ }
+ else
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "%s: ignoring %s (since -d %d was given on "
+ "the command line)\n",
+ CONFIG_LOGLEVEL_ATTRIBUTE, loglevel,
+ config_get_errorlog_level());
+ }
+ }
+
+ /* see if the entry is a child of the plugin base dn */
+ if (slapi_sdn_isparent(&plug_dn,
+ slapi_entry_get_sdn_const(e)))
+ {
+ if (entry_has_attr_and_value(e, "objectclass",
+ "nsSlapdPlugin", 0) &&
+ (entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE,
+ "syntax", 0) ||
+ entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE,
+ "matchingrule", 0)))
+ {
+ /* add the syntax/matching scheme rule plugin */
+ if (plugin_setup(e, 0, 0, 1))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "The plugin entry [%s] in the configfile %s was invalid\n", slapi_entry_get_dn(e), configfile, 0);
+ rc = 0;
+ goto bail;
+ }
+ }
+ }
+ /* see if the entry is a grand child of the plugin base dn */
+ if (slapi_sdn_isgrandparent(&plug_dn,
+ slapi_entry_get_sdn_const(e)))
+ {
+ if (entry_has_attr_and_value(e, "objectclass",
+ "nsSlapdPlugin", 0) &&
+ ( entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE,
+ "pwdstoragescheme", 0) ||
+ entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE,
+ "reverpwdstoragescheme", 0) ) )
+ {
+ /* add the pwd storage scheme rule plugin */
+ if (plugin_setup(e, 0, 0, 1))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "The plugin entry [%s] in the configfile %s was invalid\n", slapi_entry_get_dn(e), configfile, 0);
+ rc = 0;
+ goto bail;
+ }
+ }
+ }
+
+ /* see if we need to disable schema checking */
+ if (!schemacheck[0] &&
+ entry_has_attr_and_value(e, CONFIG_SCHEMACHECK_ATTRIBUTE,
+ schemacheck, sizeof(schemacheck)))
+ {
+ if (config_set_schemacheck(CONFIG_SCHEMACHECK_ATTRIBUTE,
+ schemacheck, errorbuf, CONFIG_APPLY)
+ != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
+ CONFIG_SCHEMACHECK_ATTRIBUTE, errorbuf);
+ }
+ }
+
+ /* see if we need to expect quoted schema values */
+ if (entry_has_attr_and_value(e, CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE,
+ val, sizeof(val)))
+ {
+ if (config_set_enquote_sup_oc(
+ CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, val, errorbuf,
+ CONFIG_APPLY) != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
+ CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, errorbuf);
+ }
+ val[0] = 0;
+ }
+
+ /* see if we need to maintain case in AT and OC names */
+ if (entry_has_attr_and_value(e,
+ CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, val, sizeof(val)))
+ {
+ if (config_set_return_exact_case(
+ CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, val,
+ errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
+ CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, errorbuf);
+ }
+ val[0] = 0;
+ }
+
+ /* see if we should allow attr. name exceptions, e.g. '_'s */
+ if (entry_has_attr_and_value(e,
+ CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE,
+ val, sizeof(val)))
+ {
+ if (config_set_attrname_exceptions(
+ CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE, val,
+ errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
+ CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE,
+ errorbuf);
+ }
+ val[0] = 0;
+ }
+
+ /* see if we need to maintain schema compatibility with 4.x */
+ if (entry_has_attr_and_value(e,
+ CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE, val, sizeof(val)))
+ {
+ if (config_set_ds4_compatible_schema(
+ CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE, val,
+ errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
+ CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE,
+ errorbuf);
+ }
+ val[0] = 0;
+ }
+
+ /* see if we need to allow trailing spaces in OC and AT names */
+ if (entry_has_attr_and_value(e,
+ CONFIG_SCHEMA_IGNORE_TRAILING_SPACES, val, sizeof(val)))
+ {
+ if (config_set_schema_ignore_trailing_spaces(
+ CONFIG_SCHEMA_IGNORE_TRAILING_SPACES, val,
+ errorbuf, CONFIG_APPLY) != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n", configfile,
+ CONFIG_SCHEMA_IGNORE_TRAILING_SPACES,
+ errorbuf);
+ }
+ val[0] = 0;
+ }
+
+ /* rfc1274-rewrite */
+ if (entry_has_attr_and_value(e,
+ CONFIG_REWRITE_RFC1274_ATTRIBUTE,
+ val, sizeof(val))) {
+ if (config_set_rewrite_rfc1274(
+ CONFIG_REWRITE_RFC1274_ATTRIBUTE, val,
+ errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "%s: %s: %s\n",
+ configfile,
+ CONFIG_REWRITE_RFC1274_ATTRIBUTE,
+ errorbuf);
+ }
+ }
+
+ if (e)
+ slapi_entry_free(e);
+ }
+
+ /* kexcoff: initialize rootpwstoragescheme and pw_storagescheme
+ * if not explicilty set in the config file
+ */
+ if ( config_set_storagescheme() ) { /* default scheme plugin not loaded */
+ slapi_log_error(SLAPI_LOG_FATAL, "startup",
+ "The default password storage scheme SSHA could not be read or was not found in the file %s. It is mandatory.\n",
+ configfile);
+ exit (1);
+ }
+ else {
+ slapi_sdn_done(&plug_dn);
+ rc= 1; /* OK */
+ }
+ }
+
+ slapi_ch_free((void **)&buf);
+ }
+
+bail:
+ return rc;
+}
+
diff --git a/ldap/servers/slapd/configdse.c b/ldap/servers/slapd/configdse.c
new file mode 100644
index 00000000..b2fba44e
--- /dev/null
+++ b/ldap/servers/slapd/configdse.c
@@ -0,0 +1,515 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* configdse.c - routines to manage the config DSE */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <sys/param.h>
+#endif
+#include "log.h"
+#include "slap.h"
+#include "pw.h"
+
+static int check_all_maxdiskspace_and_mlogsize(Slapi_PBlock *pb, LDAPMod **mod, char *returntext);
+static void get_log_max_size( LDAPMod *mod,
+ char *maxdiskspace_str,
+ char *mlogsize_str,
+ int *maxdiskspace,
+ int *mlogsize);
+
+/* List of attributes which require server restart to take effect */
+static const char *requires_restart[] = {
+ "cn=config:nsslapd-port",
+ "cn=config:nsslapd-secureport",
+ "cn=config:nsslapd-workingdir",
+ "cn=config:nsslapd-plugin",
+ "cn=config:nsslapd-sslclientauth",
+ "cn=config:nsslapd-changelogdir",
+ "cn=config:nsslapd-changelogsuffix",
+ "cn=config:nsslapd-changelogmaxentries",
+ "cn=config:nsslapd-changelogmaxage",
+ "cn=config:nsslapd-db-locks",
+#if !defined(_WIN32) && !defined(AIX)
+ "cn=config:nsslapd-maxdescriptors",
+#endif
+ "cn=config:" CONFIG_RETURN_EXACT_CASE_ATTRIBUTE,
+ "cn=config:" CONFIG_SCHEMA_IGNORE_TRAILING_SPACES,
+ "cn=config,cn=ldbm:nsslapd-idlistscanlimit",
+ "cn=config,cn=ldbm:nsslapd-parentcheck",
+ "cn=config,cn=ldbm:nsslapd-dbcachesize",
+ "cn=config,cn=ldbm:nsslapd-dbncache",
+ "cn=config,cn=ldbm:nsslapd-cachesize",
+ "cn=config,cn=ldbm:nsslapd-plugin",
+ "cn=encryption,cn=config:nssslsessiontimeout",
+ "cn=encryption,cn=config:nssslclientauth",
+ "cn=encryption,cn=config:nsssl2",
+ "cn=encryption,cn=config:nsssl3" };
+
+static int
+isASyntaxOrMrPluginOrPss(Slapi_Entry *e)
+{
+ char *ptype = slapi_entry_attr_get_charptr(e, ATTR_PLUGIN_TYPE);
+ int retval = (ptype && !strcasecmp(ptype, "syntax"));
+ if (!retval)
+ retval = (ptype && !strcasecmp(ptype, "matchingrule"));
+ if (!retval)
+ retval = (ptype && !strcasecmp(ptype, "pwdstoragescheme"));
+ if (!retval)
+ retval = (ptype && !strcasecmp(ptype, "reverpwdstoragescheme"));
+ slapi_ch_free((void**)&ptype);
+ return retval;
+}
+
+/* these attr types are ignored for the purposes of configuration search/modify */
+static int
+ignore_attr_type(const char *attr_type)
+{
+ if ( !attr_type ||
+ (strcasecmp (attr_type, "cn") == 0) ||
+ (strcasecmp (attr_type, "aci") == 0) ||
+ (strcasecmp (attr_type, "objectclass") == 0) ||
+ (strcasecmp (attr_type, "numsubordinates") == 0) ||
+ (strcasecmp (attr_type, "modifytimestamp") == 0) ||
+ (strcasecmp (attr_type, "modifiersname") == 0)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+read_config_dse (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ struct berval *vals[2];
+ struct berval val;
+ Slapi_Backend *be;
+ slapdFrontendConfig_t *slapdFrontendConfig;
+ struct slapdplugin *pPlugin;
+ char *cookie;
+ int i;
+
+ slapdFrontendConfig = getFrontendConfig();
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /*
+ * We can skip using the config accessor functions here because we're holding
+ * the read lock explicitly
+ */
+ CFG_LOCK_READ(slapdFrontendConfig);
+
+ /* show backend config */
+ attrlist_delete ( &e->e_attrs, "nsslapd-backendconfig");
+ for ( i = 0;
+ slapdFrontendConfig->backendconfig &&
+ slapdFrontendConfig->backendconfig[i];
+ i++) {
+ val.bv_val = slapdFrontendConfig->backendconfig[i];
+ val.bv_len = strlen ( val.bv_val );
+ attrlist_merge ( &e->e_attrs, "nsslapd-backendconfig", vals);
+ }
+
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ /* show other config entries */
+ attrlist_delete ( &e->e_attrs, "nsslapd-backendconfig");
+ cookie = NULL;
+ be = slapi_get_first_backend (&cookie);
+ while ( be )
+ {
+ if(!be->be_private)
+ {
+ Slapi_DN dn;
+ slapi_sdn_init(&dn);
+ be_getconfigdn(be,&dn);
+ val.bv_val = (char*)slapi_sdn_get_ndn(&dn);
+ val.bv_len = strlen (val.bv_val);
+ attrlist_merge ( &e->e_attrs, "nsslapd-backendconfig", vals);
+ slapi_sdn_done(&dn);
+ }
+
+ be = slapi_get_next_backend (cookie);
+ }
+
+ slapi_ch_free ((void **)&cookie);
+
+ /* show be_type */
+ attrlist_delete( &e->e_attrs, "nsslapd-betype");
+ cookie = NULL;
+ be = slapi_get_first_backend(&cookie);
+ while ( be ) {
+ if( !be->be_private )
+ {
+ val.bv_val = be->be_type;
+ val.bv_len = strlen (be->be_type);
+ attrlist_replace( &e->e_attrs, "nsslapd-betype", vals );
+ }
+
+ be = slapi_get_next_backend(cookie);
+ }
+
+ slapi_ch_free ( (void **) &cookie);
+
+ /* show private suffixes */
+ attrlist_delete ( &e->e_attrs, "nsslapd-privatenamespaces");
+ cookie = NULL;
+ be = slapi_get_first_backend(&cookie);
+ while ( be )
+ {
+ if(be->be_private)
+ {
+ int n= 0;
+ const Slapi_DN *base= NULL;
+ do {
+ base= slapi_be_getsuffix(be,n);
+ if(base!=NULL)
+ {
+ val.bv_val = (void*)slapi_sdn_get_dn(base); /* jcm: had to cast away const */
+ val.bv_len = strlen (val.bv_val);
+ attrlist_merge ( &e->e_attrs, "nsslapd-privatenamespaces", vals);
+ }
+ n++;
+ } while (base!=NULL);
+ }
+
+ be = slapi_get_next_backend(cookie);
+ }
+
+ slapi_ch_free ((void **) &cookie);
+
+ /* show syntax plugins */
+ attrlist_delete ( &e->e_attrs, CONFIG_PLUGIN_ATTRIBUTE );
+ for ( pPlugin = slapi_get_global_syntax_plugins(); pPlugin != NULL;
+ pPlugin = pPlugin->plg_next ) {
+ val.bv_val = pPlugin->plg_dn;
+ val.bv_len = strlen ( val.bv_val );
+ attrlist_merge ( &e->e_attrs, CONFIG_PLUGIN_ATTRIBUTE, vals );
+ }
+
+ /* show matching rule plugins */
+ for ( pPlugin = slapi_get_global_mr_plugins(); pPlugin != NULL;
+ pPlugin = pPlugin->plg_next ) {
+ val.bv_val = pPlugin->plg_dn;
+ val.bv_len = strlen ( val.bv_val );
+ attrlist_merge ( &e->e_attrs, CONFIG_PLUGIN_ATTRIBUTE, vals );
+ }
+
+ /* show requiresrestart */
+ attrlist_delete( &e->e_attrs, "nsslapd-requiresrestart");
+ for ( i = 0; i < sizeof(requires_restart)/sizeof(requires_restart[0]); i++ ) {
+ val.bv_val = (char *)requires_restart[i];
+ val.bv_len = strlen (val.bv_val);
+ attrlist_merge ( &e->e_attrs, "nsslapd-requiresrestart", vals);
+ }
+
+ /* show the rest of the configuration parameters */
+ *returncode= config_set_entry(e);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+int
+load_config_dse(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* ignored, int *returncode, char *returntext, void *arg)
+{
+ int retval = LDAP_SUCCESS;
+ Slapi_Attr *attr = 0;
+
+ for (slapi_entry_first_attr(e, &attr); (retval == LDAP_SUCCESS) && attr;
+ slapi_entry_next_attr(e, attr, &attr))
+ {
+ char *attr_name = 0;
+ struct berval **values = 0;
+ int nvals = 0;
+
+ slapi_attr_get_type(attr, &attr_name);
+ if (ignore_attr_type(attr_name))
+ continue;
+
+ slapi_attr_get_numvalues(attr, &nvals);
+
+ /* convert the values into an array of bervals */
+ if (nvals)
+ {
+ Slapi_Value *v = 0;
+ int index = 0;
+
+ values = (struct berval **)slapi_ch_malloc((nvals+1) *
+ sizeof(struct berval *));
+ values[nvals] = 0;
+ for (index = slapi_attr_first_value(attr, &v);
+ v && (index != -1);
+ index = slapi_attr_next_value(attr, index, &v))
+ {
+ values[index] = (struct berval *)slapi_value_get_berval(v);
+ }
+ }
+
+ if (attr_name)
+ {
+ retval = config_set(attr_name, values, returntext, 1 /* force apply */);
+ if ((retval != LDAP_SUCCESS) &&
+ slapi_attr_flag_is_set(attr, SLAPI_ATTR_FLAG_OPATTR))
+ retval = LDAP_SUCCESS; /* ignore attempts to modify operational attrs */
+ }
+
+ if (values)
+ {
+ /* slapi_value_get_berval returns the actual memory owned by the
+ slapi attr, so we cannot free it */
+ slapi_ch_free((void **)&values);
+ }
+ }
+
+ *returncode = retval;
+ return (retval == LDAP_SUCCESS) ? SLAPI_DSE_CALLBACK_OK
+ : SLAPI_DSE_CALLBACK_ERROR;
+}
+
+int
+load_plugin_entry(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* ignored, int *returncode, char *returntext, void *arg)
+{
+ int retval = LDAP_SUCCESS;
+
+ if (isASyntaxOrMrPluginOrPss(e))
+ {
+ /*
+ * syntax/matching/passwd storage scheme rule plugins are loaded
+ * at bootstrap time, so no need to load them here. BUT -- the
+ * descriptive information that is registered by the plugin is
+ * thrown away during bootstrap time, so we set it here.
+ */
+ (void)plugin_add_descriptive_attributes( e, NULL );
+
+ } else {
+ /*
+ * Process plugins that were not loaded during bootstrap.
+ */
+ retval = plugin_setup(e, 0, 0, 1);
+
+ /*
+ * well this damn well sucks, but this function is used as a callback
+ * and to ensure we do not continue if a plugin fails to load or init
+ * properly we must exit here.
+ */
+ if(retval)
+ {
+ char dnbuf[ BUFSIZ ];
+
+ slapi_log_error( SLAPI_LOG_FATAL, NULL,
+ "Unable to load plugin \"%s\"\n",
+ escape_string( slapi_entry_get_dn_const( e ), dnbuf ));
+ exit(1);
+ }
+ }
+
+ *returncode = retval;
+ return (retval == LDAP_SUCCESS) ? SLAPI_DSE_CALLBACK_OK
+ : SLAPI_DSE_CALLBACK_ERROR;
+}
+
+int
+modify_config_dse(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ char *config_attr;
+ LDAPMod **mods;
+ int rc = LDAP_SUCCESS;
+ int apply_mods = 0;
+ char *pwd = 0;
+ int checked_all_maxdiskspace_and_mlogsize = 0;
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+
+ returntext[0] = '\0';
+
+ /*
+ * First pass: set apply mods to 0 so only input validation will be done;
+ * 2nd pass: set apply mods to 1 to apply changes to internal storage
+ */
+ for ( apply_mods = 0; apply_mods <= 1; apply_mods++ ) {
+ int i = 0;
+ for (i = 0; (mods[i] && (LDAP_SUCCESS == rc)); i++) {
+ if ((mods[i]->mod_op & LDAP_MOD_DELETE) ||
+ (mods[i]->mod_op & LDAP_MOD_ADD)) {
+ rc= LDAP_UNWILLING_TO_PERFORM;
+ sprintf(returntext, "%s attributes is not allowed",
+ (mods[i]->mod_op & LDAP_MOD_DELETE) ? "Deleting" : "Adding");
+ } else if (mods[i]->mod_op & LDAP_MOD_REPLACE) {
+ /* send all aci modifications to the backend */
+ config_attr = (char *)mods[i]->mod_type;
+ if (ignore_attr_type(config_attr))
+ continue;
+
+ if ( (checked_all_maxdiskspace_and_mlogsize == 0 ) &&
+ ((strcasecmp( mods[i]->mod_type, CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE) == 0) ||
+ (strcasecmp( mods[i]->mod_type, CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE) == 0) ||
+ (strcasecmp( mods[i]->mod_type, CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE) == 0) ||
+ (strcasecmp( mods[i]->mod_type, CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE) == 0) ||
+ (strcasecmp( mods[i]->mod_type, CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE) == 0) ||
+ (strcasecmp( mods[i]->mod_type, CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE) == 0)) )
+ {
+ checked_all_maxdiskspace_and_mlogsize = 1;
+ if ( (rc=check_all_maxdiskspace_and_mlogsize(pb, mods, returntext)) != LDAP_SUCCESS )
+ {
+ goto finish_and_return;
+ }
+ }
+
+ rc = config_set(config_attr, mods[i]->mod_bvalues, returntext,
+ apply_mods);
+ }
+ }
+ }
+
+finish_and_return:
+ /*
+ * The DSE code will be writing the resultant entry value to the
+ * dse.ldif file. We *must*not* write plain passwords into here.
+ */
+ slapi_entry_attr_delete( e, CONFIG_ROOTPW_ATTRIBUTE );
+ /* if the password has been set, it will be hashed */
+ if ((pwd = config_get_rootpw()) != NULL) {
+ slapi_entry_attr_set_charptr(e, CONFIG_ROOTPW_ATTRIBUTE, pwd);
+ slapi_ch_free((void**)&pwd);
+ }
+
+ *returncode= rc;
+ if(LDAP_SUCCESS == rc) {
+ return(SLAPI_DSE_CALLBACK_OK); /* success -- apply the mods. */
+ }
+ else {
+ return(SLAPI_DSE_CALLBACK_ERROR); /* failure -- reject the mods. */
+ }
+}
+
+int
+postop_modify_config_dse(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ static int num_requires_restart = sizeof(requires_restart)/sizeof(char*);
+ LDAPMod **mods;
+ int i, j;
+ char *p;
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ returntext[0] = '\0';
+
+ for (i = 0; mods[i]; i++) {
+ if (mods[i]->mod_op & LDAP_MOD_REPLACE ) {
+ /* Check if the server needs to be restarted */
+ for (j = 0; j < num_requires_restart; j++)
+ {
+ p = strchr (requires_restart[j], ':');
+ if (p == NULL)
+ continue;
+ while ( *(++p) == ' ' || *p == '\t' );
+ if ( strcasecmp (p, mods[i]->mod_type) == 0 ) {
+ sprintf(returntext,
+ "The change of %s will not take effect "
+ "until the server is restarted", mods[i]->mod_type);
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "%s\n", returntext);
+ break;
+ }
+ }
+ if (j < num_requires_restart) {
+ /* That's enough, don't check remaining mods any more */
+ break;
+ }
+ }
+ }
+
+ *returncode = LDAP_SUCCESS;
+ return *returncode;
+}
+
+static int
+check_all_maxdiskspace_and_mlogsize(Slapi_PBlock *pb, LDAPMod **mods, char *returntext)
+{
+ int i = 0;
+ int rc = LDAP_SUCCESS;
+ int errormaxdiskspace = -1;
+ int errormlogsize = -1;
+ int accessmaxdiskspace = -1;
+ int accessmlogsize = -1;
+ int auditmaxdiskspace = -1;
+ int auditmlogsize = -1;
+
+ for (i = 0; mods[i] ; i++)
+ {
+ get_log_max_size(mods[i],
+ CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE,
+ CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE,
+ &errormaxdiskspace,
+ &errormlogsize);
+
+ get_log_max_size(mods[i],
+ CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE,
+ CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE,
+ &accessmaxdiskspace,
+ &accessmlogsize);
+
+ get_log_max_size(mods[i],
+ CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE,
+ CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE,
+ &auditmaxdiskspace,
+ &auditmlogsize);
+ }
+
+ if ( (rc=check_log_max_size(
+ CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE,
+ CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE,
+ errormaxdiskspace,
+ errormlogsize,
+ returntext,
+ SLAPD_ERROR_LOG)) != LDAP_SUCCESS )
+ {
+ return rc;
+ }
+ if ( (rc=check_log_max_size(
+ CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE,
+ CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE,
+ accessmaxdiskspace,
+ accessmlogsize,
+ returntext,
+ SLAPD_ACCESS_LOG)) != LDAP_SUCCESS )
+ {
+ return rc;
+ }
+ if ( (rc=check_log_max_size(
+ CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE,
+ CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE,
+ auditmaxdiskspace,
+ auditmlogsize,
+ returntext,
+ SLAPD_AUDIT_LOG)) != LDAP_SUCCESS )
+ {
+ return rc;
+ }
+ return rc;
+}
+
+static void
+get_log_max_size( LDAPMod *mod,
+ char *maxdiskspace_str,
+ char *mlogsize_str,
+ int *maxdiskspace,
+ int *mlogsize)
+{
+ if ( mod->mod_bvalues != NULL &&
+ (strcasecmp( mod->mod_type, maxdiskspace_str ) == 0) )
+ {
+ *maxdiskspace = atoi((char *) mod->mod_bvalues[0]->bv_val);
+ }
+
+ if ( mod->mod_bvalues != NULL &&
+ (strcasecmp( mod->mod_type, mlogsize_str ) == 0) )
+ {
+ *mlogsize = atoi((char *) mod->mod_bvalues[0]->bv_val);
+ }
+}
diff --git a/ldap/servers/slapd/connection.c b/ldap/servers/slapd/connection.c
new file mode 100644
index 00000000..4cf7869b
--- /dev/null
+++ b/ldap/servers/slapd/connection.c
@@ -0,0 +1,2485 @@
+/** 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 <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <stdlib.h>
+#endif
+#define TCPLEN_T int
+#include <signal.h>
+#include "slap.h"
+#include "prcvar.h"
+#include "prlog.h" /* for PR_ASSERT */
+#include "fe.h"
+#include <sasl.h>
+#if defined(LINUX)
+#include <netinet/tcp.h> /* for TCP_CORK */
+#endif
+
+
+static void connection_threadmain( void );
+static void add_pb( Slapi_PBlock * );
+static Slapi_PBlock *get_pb( void );
+static void connection_add_operation(Connection* conn, Operation *op);
+static void connection_free_private_buffer(Connection *conn);
+static void op_copy_identity(Connection *conn, Operation *op);
+static int is_ber_too_big(const Connection *conn,unsigned long ber_len);
+static void log_ber_too_big_error(const Connection *conn,
+ unsigned long ber_len, unsigned long maxbersize);
+
+/*
+ * We maintain a global work queue of Slapi_PBlock's that have not yet
+ * been handed off to an operation thread.
+ */
+struct Slapi_PBlock_q
+{
+ Slapi_PBlock *pb;
+ struct Slapi_PBlock_q *next_pb;
+ int pb_fd;
+};
+
+static struct Slapi_PBlock_q *first_pb= NULL; /* global work queue head */
+static struct Slapi_PBlock_q *last_pb= NULL; /* global work queue tail */
+static PRLock *pb_q_lock=NULL; /* protects first_pb & last_pb */
+
+static PRCondVar *op_thread_cv; /* used by operation threads to wait for work */
+static PRLock *op_thread_lock; /* associated with op_thread_cv */
+static int op_shutdown= 0; /* if non-zero, server is shutting down */
+
+#define LDAP_SOCKET_IO_BUFFER_SIZE 512 /* Size of the buffer we give to the I/O system for reads */
+
+
+/*
+ * We really are done with this connection. Get rid of everything.
+ *
+ * Note: this function should be called with conn->c_mutex already locked
+ * or at a time when multiple threads are not in play that might touch the
+ * connection structure.
+ */
+void
+connection_done(Connection *conn)
+{
+ connection_cleanup(conn);
+ /* free the private content, the buffer has been freed by above connection_cleanup */
+ slapi_ch_free((void**)&conn->c_private);
+ if (NULL != conn->c_sb)
+ {
+ ber_sockbuf_free(conn->c_sb);
+ }
+ if (NULL != conn->c_mutex)
+ {
+ PR_DestroyLock(conn->c_mutex);
+ }
+ if (NULL != conn->c_pdumutex)
+ {
+ PR_DestroyLock(conn->c_pdumutex);
+ }
+}
+
+/*
+ * We're going to be making use of this connection again.
+ * So, get rid of everything we can't make use of.
+ *
+ * Note: this function should be called with conn->c_mutex already locked
+ * or at a time when multiple threads are not in play that might touch the
+ * connection structure.
+ */
+void
+connection_cleanup(Connection *conn)
+{
+ bind_credentials_clear( conn, PR_FALSE /* do not lock conn */,
+ PR_TRUE /* clear external creds. */ );
+ slapi_ch_free((void**)&conn->c_authtype);
+
+ /* Call the plugin extension destructors */
+ factory_destroy_extension(connection_type,conn,NULL/*Parent*/,&(conn->c_extension));
+ /*
+ * We hang onto these, since we can reuse them.
+ * Sockbuf *c_sb;
+ * PRLock *c_mutex;
+ * PRLock *c_pdumutex;
+ * Conn_private *c_private;
+ */
+
+#ifdef _WIN32
+ if (conn->c_prfd && (conn->c_flags & CONN_FLAG_SSL))
+ {
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "conn=%d fd=%d closed now\n",
+ conn->c_connid, conn->c_sd,0);
+ PR_Close(conn->c_prfd);
+ }
+ else if (conn->c_sd)
+ {
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "conn=%d fd=%d closed now\n",
+ conn->c_connid, conn->c_sd,0);
+ closesocket(conn->c_sd);
+ }
+#else
+ if (conn->c_prfd)
+ {
+ PR_Close(conn->c_prfd);
+ }
+#endif
+
+ conn->c_sd= SLAPD_INVALID_SOCKET;
+ conn->c_ldapversion= 0;
+
+ conn->c_isreplication_session = 0;
+ slapi_ch_free((void**)&conn->cin_addr );
+ slapi_ch_free((void**)&conn->cin_destaddr );
+ if ( conn->c_domain != NULL )
+ {
+ ber_bvecfree( conn->c_domain );
+ conn->c_domain = NULL;
+ }
+ /* conn->c_ops= NULL; */
+ conn->c_gettingber= 0;
+ conn->c_currentber= NULL;
+ conn->c_starttime= 0;
+ conn->c_connid= 0;
+ conn->c_opsinitiated= 0;
+ conn->c_opscompleted= 0;
+ conn->c_threadnumber= 0;
+ conn->c_refcnt= 0;
+ conn->c_idlesince= 0;
+ conn->c_flags= 0;
+ conn->c_needpw= 0;
+ conn->c_prfd= NULL;
+ /* c_ci stays as it is */
+ conn->c_fdi= SLAPD_INVALID_SOCKET_INDEX;
+ conn->c_next= NULL;
+ conn->c_prev= NULL;
+ conn->c_extension= NULL;
+ /* remove any SASL I/O from the connection */
+ sasl_io_cleanup(conn);
+ sasl_dispose((sasl_conn_t**)&conn->c_sasl_conn);
+
+ /* free the connection socket buffer */
+ connection_free_private_buffer(conn);
+}
+
+/*
+ * Callers of connection_reset() must hold the conn->c_mutex lock.
+ */
+void
+connection_reset(Connection* conn, int ns, PRNetAddr * from, int fromLen, int is_SSL)
+{
+ char * pTmp = is_SSL ? "SSL " : "";
+ TCPLEN_T l_fromLen = (TCPLEN_T)fromLen;
+ TCPLEN_T addrlen, destaddrlen;
+ struct sockaddr_in addr, destaddr;
+ char *str_ip, *str_destip, buf_ip[ 256 ], buf_destip[ 256 ];
+ char *str_unknown = "unknown";
+ int in_referral_mode = config_check_referral_mode();
+
+ LDAPDebug( LDAP_DEBUG_CONNS, "new %sconnection on %d\n", pTmp, conn->c_sd, 0 );
+
+ /* bump our count of connections and update SNMP stats */
+ PR_Lock( num_conns_mutex );
+ conn->c_connid = num_conns++;
+ PR_Unlock( num_conns_mutex );
+
+ if (! in_referral_mode) {
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsConnectionSeq);
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsConnections);
+ }
+
+ /* get peer address (IP address of this client) */
+ addrlen = sizeof( addr );
+ memset( &addr, 0, addrlen );
+
+ if ( ((from->ipv6.ip.pr_s6_addr32[0] != 0) ||
+ (from->ipv6.ip.pr_s6_addr32[1] != 0) ||
+ (from->ipv6.ip.pr_s6_addr32[2] != 0) ||
+ (from->ipv6.ip.pr_s6_addr32[3] != 0)) ||
+ ((conn->c_prfd != NULL) && (PR_GetPeerName( conn->c_prfd, from ) == 0)) ) {
+ conn->cin_addr = (PRNetAddr *) slapi_ch_malloc( sizeof( PRNetAddr ) );
+ memcpy( conn->cin_addr, from, sizeof( PRNetAddr ) );
+
+ if ( PR_IsNetAddrType( conn->cin_addr, PR_IpAddrV4Mapped ) ) {
+ PRNetAddr v4addr;
+ memset( &v4addr, 0, sizeof( v4addr ) );
+ v4addr.inet.family = PR_AF_INET;
+ v4addr.inet.ip = conn->cin_addr->ipv6.ip.pr_s6_addr32[3];
+ PR_NetAddrToString( &v4addr, buf_ip, sizeof( buf_ip ) );
+ } else {
+ PR_NetAddrToString( conn->cin_addr, buf_ip, sizeof( buf_ip ) );
+ }
+ buf_ip[ sizeof( buf_ip ) - 1 ] = '\0';
+ str_ip = buf_ip;
+
+ } else if ( (conn->c_prfd == NULL) &&
+ (getpeername( conn->c_sd, (struct sockaddr*)&addr, &addrlen ) == 0) ) {
+ conn->cin_addr = (PRNetAddr *)slapi_ch_malloc( sizeof( PRNetAddr ) );
+
+ if ( PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, addr.sin_port, conn->cin_addr)
+ != PR_SUCCESS ) {
+ int oserr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "PR_SetNetAddr() failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ oserr, slapd_pr_strerror(oserr), 0 );
+ } else {
+ PR_ConvertIPv4AddrToIPv6(addr.sin_addr.s_addr, &(conn->cin_addr->ipv6.ip));
+ }
+
+ /* copy string equivalent of address into a buffer to use for
+ * logging since each call to inet_ntoa() returns a pointer to a
+ * single thread-specific buffer (which prevents us from calling
+ * inet_ntoa() twice in one call to slapi_log_access()).
+ */
+ str_ip = inet_ntoa( addr.sin_addr );
+ strncpy( buf_ip, str_ip, sizeof( buf_ip ) - 1 );
+ buf_ip[ sizeof( buf_ip ) - 1 ] = '\0';
+ str_ip = buf_ip;
+
+ } else {
+ str_ip = str_unknown;
+ }
+
+
+ /*
+ * get destination address (server IP address this client connected to)
+ */
+ destaddrlen = sizeof( destaddr );
+ memset( &destaddr, 0, destaddrlen );
+
+
+ if ( conn->c_prfd != NULL ) {
+ conn->cin_destaddr = (PRNetAddr *) slapi_ch_malloc( sizeof( PRNetAddr ) );
+ if (PR_GetSockName( conn->c_prfd, conn->cin_destaddr ) == 0) {
+ if ( PR_IsNetAddrType( conn->cin_destaddr, PR_IpAddrV4Mapped ) ) {
+ PRNetAddr v4destaddr;
+ memset( &v4destaddr, 0, sizeof( v4destaddr ) );
+ v4destaddr.inet.family = PR_AF_INET;
+ v4destaddr.inet.ip = conn->cin_destaddr->ipv6.ip.pr_s6_addr32[3];
+ PR_NetAddrToString( &v4destaddr, buf_destip, sizeof( buf_destip ) );
+ } else {
+ PR_NetAddrToString( conn->cin_destaddr, buf_destip, sizeof( buf_destip ) );
+ }
+ buf_destip[ sizeof( buf_destip ) - 1 ] = '\0';
+ str_destip = buf_destip;
+ } else {
+ str_destip = str_unknown;
+ }
+ } else if ( (conn->c_prfd == NULL) &&
+ (getsockname( conn->c_sd, (struct sockaddr*)&destaddr, &destaddrlen ) == 0) ) {
+ conn->cin_destaddr = (PRNetAddr *)slapi_ch_malloc( sizeof( PRNetAddr ) );
+
+ if ( PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, destaddr.sin_port, conn->cin_destaddr)
+ != PR_SUCCESS ) {
+ int oserr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "PR_SetNetAddr() failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ oserr, slapd_pr_strerror(oserr), 0 );
+ } else {
+ PR_ConvertIPv4AddrToIPv6(destaddr.sin_addr.s_addr, &(conn->cin_destaddr->ipv6.ip));
+ }
+
+ /* copy string equivalent of address into a buffer to use for
+ * logging since each call to inet_ntoa() returns a pointer to a
+ * single thread-specific buffer (which prevents us from calling
+ * inet_ntoa() twice in one call to slapi_log_access()).
+ */
+ str_destip = inet_ntoa( destaddr.sin_addr );
+ strncpy( buf_destip, str_destip, sizeof( buf_destip ) - 1 );
+ buf_destip[ sizeof( buf_destip ) - 1 ] = '\0';
+ str_destip = buf_destip;
+
+ } else {
+ str_destip = str_unknown;
+ }
+
+
+ if ( !in_referral_mode ) {
+ /* create a sasl connection */
+ ids_sasl_server_new(conn);
+ }
+
+ /* log useful stuff to our access log */
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d fd=%d slot=%d %sconnection from %s to %s\n",
+ conn->c_connid, conn->c_sd, ns, pTmp, str_ip, str_destip );
+
+ /* initialize the remaining connection fields */
+ conn->c_ldapversion = LDAP_VERSION3;
+ conn->c_starttime = current_time();
+ conn->c_idlesince = conn->c_starttime;
+ conn->c_flags = is_SSL ? CONN_FLAG_SSL : 0;
+ conn->c_authtype = slapi_ch_strdup(SLAPD_AUTH_NONE);
+}
+
+/* Create a pool of threads for handling the operations */
+void
+init_op_threads()
+{
+ int i;
+ PRErrorCode errorCode;
+ int max_threads = config_get_threadnumber();
+ /* Initialize the locks and cv */
+
+ if ((pb_q_lock = PR_NewLock()) == NULL ) {
+ errorCode = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "init_op_threads: PR_NewLock failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ errorCode, slapd_pr_strerror(errorCode), 0 );
+ exit(-1);
+ }
+
+ if ((op_thread_lock = PR_NewLock()) == NULL ) {
+ errorCode = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "init_op_threads: PR_NewLock failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ errorCode, slapd_pr_strerror(errorCode), 0 );
+ exit(-1);
+ }
+
+ if ((op_thread_cv = PR_NewCondVar( op_thread_lock )) == NULL) {
+ errorCode = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "init_op_threads: PR_NewCondVar failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ errorCode, slapd_pr_strerror(errorCode), 0 );
+ exit(-1);
+ }
+
+ /* start the operation threads */
+ for (i=0; i < max_threads; i++) {
+ PR_SetConcurrency(4);
+ if (PR_CreateThread (PR_USER_THREAD,
+ (VFP) (void *) connection_threadmain, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE
+ ) == NULL ) {
+ int prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "PR_CreateThread failed, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror( prerr ), 0 );
+ } else {
+ PR_AtomicIncrement(&active_threads);
+ }
+ }
+}
+
+static void
+referral_mode_reply(Slapi_PBlock *pb)
+{
+ struct slapdplugin *plugin;
+ plugin = (struct slapdplugin *) slapi_ch_calloc(1, sizeof(struct slapdplugin));
+ if (plugin!=NULL)
+ {
+ struct berval *urls[2], url;
+ char *refer;
+ refer = config_get_referral_mode();
+ pb->pb_plugin = plugin;
+ set_db_default_result_handlers(pb);
+ urls[0] = &url;
+ urls[1] = NULL;
+ url.bv_val = refer;
+ url.bv_len = refer ? strlen(refer) : 0;
+ slapi_send_ldap_result(pb, LDAP_REFERRAL, NULL, NULL, 0, urls);
+ slapi_ch_free((void **)&plugin);
+ slapi_ch_free((void **)&refer);
+ }
+}
+
+static int
+connection_need_new_password(const Connection *conn, const Operation *op, Slapi_PBlock *pb)
+{
+ int r= 0;
+ /*
+ * add tag != LDAP_REQ_SEARCH to allow admin server 3.5 to do
+ * searches when the user needs to reset
+ * the pw the first time logon.
+ * LP: 22 Dec 2000: Removing LDAP_REQ_SEARCH. It's very unlikely that AS 3.5 will
+ * be used to manage DS5.0
+ */
+
+ if ( conn->c_needpw && op->o_tag != LDAP_REQ_MODIFY &&
+ op->o_tag != LDAP_REQ_BIND && op->o_tag != LDAP_REQ_UNBIND &&
+ op->o_tag != LDAP_REQ_ABANDON )
+ {
+ add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d %s\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid,
+ "need new password" );
+ send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM,
+ NULL, NULL, 0, NULL );
+ r= 1;
+ }
+ return r;
+}
+
+
+static void
+connection_dispatch_operation(Connection *conn, Operation *op, Slapi_PBlock *pb)
+{
+ /* Copy the Connection DN into the operation struct */
+ op_copy_identity( conn, op );
+
+ /* process the operation */
+
+ switch ( op->o_tag ) {
+ case LDAP_REQ_BIND:
+ operation_set_type(op,SLAPI_OPERATION_BIND);
+ do_bind( pb );
+ break;
+
+ case LDAP_REQ_UNBIND:
+ operation_set_type(op,SLAPI_OPERATION_UNBIND);
+ do_unbind( pb );
+ break;
+
+ case LDAP_REQ_ADD:
+ operation_set_type(op,SLAPI_OPERATION_ADD);
+ do_add( pb );
+ break;
+
+ case LDAP_REQ_DELETE:
+ operation_set_type(op,SLAPI_OPERATION_DELETE);
+ do_delete( pb );
+ break;
+
+ case LDAP_REQ_MODRDN:
+ operation_set_type(op,SLAPI_OPERATION_MODRDN);
+ do_modrdn( pb );
+ break;
+
+ case LDAP_REQ_MODIFY:
+ operation_set_type(op,SLAPI_OPERATION_MODIFY);
+ do_modify( pb );
+ break;
+
+ case LDAP_REQ_COMPARE:
+ operation_set_type(op,SLAPI_OPERATION_COMPARE);
+ do_compare( pb );
+ break;
+
+ case LDAP_REQ_SEARCH:
+ operation_set_type(op,SLAPI_OPERATION_SEARCH);
+
+
+ /* On Linux we can use TCP_CORK to get us 5-10% speed benefit when one entry is returned */
+ /* Nagle needs to be turned _off_, the default is off on linux, in daemon.c */
+#if defined(LINUX)
+ {
+ int i = 1;
+ int ret = 0;
+ /* Set TCP_CORK here */
+ ret = setsockopt(conn->c_sd,IPPROTO_TCP,TCP_CORK,&i,sizeof(i));
+ if (ret < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Failed to set TCP_CORK on connection %d\n",conn->c_connid, 0, 0);
+ }
+#endif
+
+ do_search( pb );
+
+#if defined(LINUX)
+ /* Clear TCP_CORK to flush any unsent data */
+ i = 0;
+ ret = setsockopt(conn->c_sd,IPPROTO_TCP,TCP_CORK,&i,sizeof(i));
+ if (ret < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Failed to clear TCP_CORK on connection %d\n",conn->c_connid, 0, 0);
+ }
+ }
+#endif
+ break;
+
+ /* for some strange reason, the console is using this old obsolete
+ * value for ABANDON so we have to support it until the console
+ * get fixed
+ * otherwise the console has VERY BAD performances when a fair amount
+ * of entries are created in the DIT
+ */
+ case LDAP_REQ_ABANDON_30:
+ case LDAP_REQ_ABANDON:
+ operation_set_type(op,SLAPI_OPERATION_ABANDON);
+ do_abandon( pb );
+ break;
+
+ case LDAP_REQ_EXTENDED:
+ operation_set_type(op,SLAPI_OPERATION_EXTENDED);
+ do_extended( pb );
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ignoring unknown LDAP request (conn=%d, tag=0x%lx)\n",
+ conn->c_connid, op->o_tag, 0 );
+ break;
+ }
+}
+
+/* this function should be called under c_mutex */
+int connection_release_nolock (Connection *conn)
+{
+ if (conn->c_refcnt <= 0)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "connection",
+ "conn=%d fd=%d Attempt to release connection that is not aquired\n",
+ conn->c_connid, conn->c_sd);
+ PR_ASSERT (PR_FALSE);
+ return -1;
+ }
+ else
+ {
+ conn->c_refcnt--;
+
+ return 0;
+ }
+}
+
+/* this function should be called under c_mutex */
+int connection_acquire_nolock (Connection *conn)
+{
+ /* connection in the closing state can't be acquired */
+ if (conn->c_flags & CONN_FLAG_CLOSING)
+ {
+ /* This may happen while other threads are still working on this connection */
+ slapi_log_error(SLAPI_LOG_FATAL, "connection",
+ "conn=%d fd=%d Attempt to acquire connection in the closing state\n",
+ conn->c_connid, conn->c_sd);
+ return -1;
+ }
+ else
+ {
+ conn->c_refcnt++;
+ return 0;
+ }
+}
+
+/* returns non-0 if connection can be reused and 0 otherwise */
+int connection_is_free (Connection *conn)
+{
+ int rc;
+
+ PR_Lock(conn->c_mutex);
+ rc = conn->c_sd == SLAPD_INVALID_SOCKET && conn->c_refcnt == 0 &&
+ !(conn->c_flags & CONN_FLAG_CLOSING);
+ PR_Unlock(conn->c_mutex);
+
+ return rc;
+}
+
+int connection_is_active_nolock (Connection *conn)
+{
+ return (conn->c_sd != SLAPD_INVALID_SOCKET) &&
+ !(conn->c_flags & CONN_FLAG_CLOSING);
+}
+
+/* returns non-0 if this is an active connection meaning it is in use
+ and not in the closing mode */
+
+#if defined LDAP_IOCP
+/*
+ * IO Completion ports are currently only available on NT.
+ */
+
+typedef enum {read_data, write_data, new_connection} work_type;
+static int wait_on_new_work(Connection **ppConn, work_type *type);
+static int issue_new_read(Connection *conn);
+static int finished_chomping(Connection *conn);
+static int read_the_data(Connection *op, int *process_op);
+static int is_new_operation(Connection *conn);
+static int process_operation(Connection *conn, Operation *op);
+static int connection_operation_new(Connection *conn, Operation **ppOp);
+Operation *get_current_op(Connection *conn);
+static int handle_read_data(Connection *conn,Operation **op,
+ int * connection_referenced);
+
+static void inc_op_count(Connection* conn)
+{
+ PR_AtomicIncrement(&conn->c_opscompleted);
+ PR_AtomicIncrement(&ops_completed);
+}
+
+static int connection_increment_reference(Connection *conn)
+{
+ int rc = 0;
+ PR_Lock( conn->c_mutex );
+ rc = connection_acquire_nolock (conn);
+ PR_Unlock( conn->c_mutex );
+ return rc;
+}
+
+static void connection_decrement_reference(Connection *conn)
+{
+ PR_Lock( conn->c_mutex );
+ connection_release_nolock (conn);
+ PR_Unlock( conn->c_mutex );
+}
+
+static void
+connection_threadmain()
+{
+ /*
+ * OK, so this is the thread main routine for the thread pool.
+ * This is the general idea : wait on the i/o completion port.
+ * then get some data. There are three cases here:
+ * 1) This is the first piece of data read for a new LDAP op.
+ * 2) This is a subsequent, but not final, piece of data read in the current LDAP op on this connection
+ * 3) This is the last piece of the current LDAP op on the current connection.
+ * Note that these cases are NOT exclusive ! In particular, all three can occur for the same read.
+ * based on detecting these cases, we end up doing one or more of the following things:
+ * a) Create new structures for a new op.
+ * b) Read data into the BER buffer for the op.
+ * c) Press on to service the operation request (note that the results are currently written
+ * synchronously.
+ * We always queue a new read on the socket too.
+ * (Note, we need to make sure we don't issue the new read operation until we've copied
+ * the data from the existing one. Otherwise we'd open ourselves to getting OOO data.)
+ *
+ * The intention is that this code will be clean enough to be used for the UNIX build,
+ * once we fake up I/O completion ports with select and another thread.
+ */
+
+ Connection *conn = NULL;
+ Operation *op = NULL;
+ int return_value = -1;
+ int abandon_connection = 0;
+ work_type command = 0;
+ int connection_referenced = 0;
+
+ /* Don't ask me, and I will tell you no lies */
+#if defined( OSF1 ) || defined( hpux ) || defined( LINUX )
+ /* Arrange to ignore SIGPIPE signals. */
+ SIGNAL( SIGPIPE, SIG_IGN );
+#endif
+
+ while (1) {
+
+ abandon_connection = 1; /* we start off assuming that we'll fail somewhere */
+ conn = NULL; /* just make sure we don't step on an old connection by mistake */
+ op = NULL; /* Same goes for the operation */
+
+ return_value = wait_on_new_work(&conn,&command);
+ if( op_shutdown )
+ break;
+ if (0 == return_value) {
+ connection_referenced = 0; /* No outstanding ref count on connection if wait for work returned OK */
+ switch (command) {
+ case read_data:
+ return_value = handle_read_data(conn,&op,&connection_referenced);
+ if (0 == return_value)
+ {
+ abandon_connection = 0;
+ }
+ break;
+ case write_data:
+ /* NYI, but we need to go and find the state for the connection, find the operation
+ * which queued the write, and then get whatever data we need to write, then write it ! */
+ break;
+ case new_connection:
+ /* NYI, but this would consist of the same stuff which is currently in daemon.c.
+ * On NT, we'd use AcceptEx() */
+ break;
+ default:
+ break;
+ }
+ finished_chomping(conn);
+ } else {
+ PR_SetError(PR_IO_ERROR, return_value);
+ connection_referenced = 1; /* There is an outstanding refcnt on the conn, so we get to close the right one ! */
+ }
+
+ /* If anything went wrong with the connection above, such that we need to
+ * disconnect it, we'll know here and shoot it in the foot.
+ */
+ if ( (NULL != conn) && abandon_connection) {
+ disconnect_server(conn, conn->c_connid, op ? op->o_opid : -1, SLAPD_DISCONNECT_ABORT, 0 );
+ if (connection_referenced) {
+ connection_decrement_reference(conn);
+ }
+ }
+ }
+ PR_AtomicDecrement(&active_threads);
+}
+
+static int handle_read_data(Connection *conn,Operation **op,
+ int * connection_referenced)
+{
+ int return_value = 0;
+ int process_op = 0; /* Do we or do we not process a complete operation now ? */
+
+ if (is_new_operation(conn)) {
+ return_value = connection_operation_new(conn,op);
+ } else {
+ *op = get_current_op(conn);
+ }
+
+ /* if connection is closing */
+ if (return_value != 0) {
+ LDAPDebug(LDAP_DEBUG_CONNS,
+ "handle_read_data returns as conn %d closing, fd=%d\n",
+ conn->c_connid,conn->c_sd,0);
+ return return_value;
+ }
+
+ return_value = read_the_data(conn,&process_op);
+
+ if (0 == return_value) {
+ if (0 != process_op)
+ return_value = process_operation(conn,*op);
+ }
+ else
+ *connection_referenced = 1;
+
+ return return_value;
+}
+
+/* Function which does the work involved in servicing an LDAP operation. */
+static int process_operation(Connection *conn, Operation *op)
+{
+ Slapi_PBlock *pb = NULL;
+ unsigned long len, tag;
+ long msgid;
+ int return_value = 0;
+ int destroy_content = 1;
+
+
+ pb = (Slapi_PBlock *) slapi_ch_calloc( 1, sizeof(Slapi_PBlock) );
+ pb->pb_conn = conn;
+ pb->pb_op = op;
+ /* destroy operation content when done */
+ slapi_pblock_set (pb, SLAPI_DESTROY_CONTENT, &destroy_content);
+
+ if (! config_check_referral_mode()) {
+ PR_AtomicIncrement(&ops_initiated);
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsInOps);
+ }
+
+ if ( (tag = ber_get_int( op->o_ber, &msgid ))
+ != LDAP_TAG_MSGID ) {
+ /* log, close and send error */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "conn=%d unable to read tag for incoming request\n", conn->c_connid, 0, 0 );
+ return_value = -1;
+ goto done;
+ }
+ op->o_msgid = msgid;
+
+ tag = ber_peek_tag( op->o_ber, &len );
+ switch ( tag ) {
+ case LBER_ERROR:
+ case LDAP_TAG_LDAPDN: /* optional username, for CLDAP */
+ /* log, close and send error */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "conn=%d ber_peek_tag returns 0x%lx\n", conn->c_connid, tag, 0 );
+ return_value = -1;
+ goto done;
+ default:
+ break;
+ }
+ op->o_tag = tag;
+
+ /* are we in referral-only mode? */
+ if (config_check_referral_mode() && tag != LDAP_REQ_UNBIND)
+ {
+ referral_mode_reply(pb);
+ goto done;
+ }
+
+ /* check if new password is required */
+ if(connection_need_new_password(conn, op, pb))
+ {
+ goto done;
+ }
+
+ /* if this is a bulk import, only "add" and "import done (extop)" are
+ * allowed */
+ if (conn->c_flags & CONN_FLAG_IMPORT) {
+ if ((tag != LDAP_REQ_ADD) && (tag != LDAP_REQ_EXTENDED)) {
+ /* no cookie for you. */
+ LDAPDebug(LDAP_DEBUG_ANY, "Attempted operation %d from "
+ "within bulk import\n", tag, 0, 0);
+ slapi_send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL, NULL,
+ 0, NULL);
+ return_value = -1;
+ goto done;
+ }
+ }
+
+ /*
+ * Call the do_<operation> function to process this request.
+ */
+ connection_dispatch_operation(conn, op, pb);
+
+done:
+
+ /* If we're here, it means that we successfully completed an operation , so bump the counts */
+ inc_op_count(conn);
+
+ if ( !( pb->pb_op->o_flags & OP_FLAG_PS )) {
+ /*
+ * If not a persistent search, remove the operation
+ * from this connection's list.
+ */
+ PR_Lock( conn->c_mutex );
+ connection_remove_operation( conn, op );
+ PR_Unlock( conn->c_mutex );
+
+ /* destroying the pblock will cause destruction of the operation
+ * so this must happen before releasing the connection
+ */
+ slapi_pblock_destroy( pb );
+
+ PR_Lock( conn->c_mutex );
+ if (connection_release_nolock (conn) != 0)
+ {
+ return_value = -1;
+ }
+ PR_Unlock( conn->c_mutex );
+
+ }
+ return return_value;
+}
+
+/* Helper functions for the code above: */
+
+
+struct Conn_private {
+ /* First the platform-dependent part */
+#ifdef _WIN32
+ OVERLAPPED c_overlapped;
+ DWORD c_buffer_size;
+ char *c_buffer;
+ DWORD c_number_of_async_bytes_read;
+ DWORD c_buffer_offset;
+#else
+#endif
+ /* Now the platform independent part */
+ Operation *c_current_op;
+ int c_flags;
+};
+
+static void connection_free_private_buffer(Connection *conn)
+{
+#ifdef _WIN32
+ if (NULL != conn->c_private) {
+ slapi_ch_free( (void**)&conn->c_private->c_buffer);
+ }
+#else
+#endif
+}
+
+#define FLAG_CONN_HAD_SOME 1 /* Set when we've read the first piece of data already, means we don't need to allocate a new op */
+#define FLAG_CONN_COMPLETE 2 /* Set when we've read all of an LDAP operation request, means we can proceed to process it */
+
+
+/* Little helper functions */
+
+Operation *get_current_op(Connection *conn)
+{
+ Operation *return_op = conn->c_private->c_current_op;
+ PR_ASSERT(NULL != return_op);
+ return return_op;
+}
+
+static int is_new_operation(Connection *conn)
+{
+ if (0 == conn->c_private->c_flags) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/* Called when a new operation comes in on a connection */
+static int connection_operation_new(Connection *conn, Operation **ppOp)
+{
+ /* we need to make a new operation structure and chain it onto the connection */
+ Operation *temp_op = NULL;
+ int rc;
+
+ PR_Lock( conn->c_mutex );
+ if (connection_is_active_nolock(conn) == 0) {
+ LDAPDebug(LDAP_DEBUG_CONNS,
+ "not creating a new operation when conn %d closing\n",
+ conn->c_connid,0,0);
+ PR_Unlock( conn->c_mutex );
+ return -1;
+ }
+ temp_op = operation_new( plugin_build_operation_action_bitmap( 0,
+ plugin_get_server_plg() ));
+ connection_add_operation( conn, temp_op);
+ rc = connection_acquire_nolock (conn);
+ PR_Unlock( conn->c_mutex );
+ /* Stash the op pointer in the connection structure for later use */
+ PR_ASSERT(NULL == conn->c_private->c_current_op);
+ conn->c_private->c_current_op = temp_op;
+ *ppOp = temp_op;
+ return rc;
+}
+
+/* Call this to tell the select thread to put us back into the read-ready signal set */
+static int add_to_select_set(Connection *conn)
+{
+ conn->c_gettingber = 0;
+ signal_listner();
+ return 0;
+}
+
+static int remove_from_select_set(Connection *conn)
+{
+ conn->c_gettingber = 1;
+ return 0;
+}
+
+/* Helper functions from here on are platform-dependent */
+/* First the NT ones */
+
+#ifdef _WIN32
+
+static HANDLE completion_port = INVALID_HANDLE_VALUE;
+#define COMPKEY_DIE ((DWORD) -1L) /* used to kill off workers */
+
+static int push_back_data(Connection *conn, size_t offset, size_t length);
+
+/* Called when we've read from the completion queue, so there's data
+ * waiting for us to pickup. We're told: the number of bytes read, the
+ * address of the buffer, the state of this connection (new op, middle of op).
+ */
+static int read_the_data(Connection *conn, int *process_op)
+{
+ Conn_private *priv = conn->c_private;
+ Operation *op = NULL;
+ DWORD Bytes_Read = 0;
+ char *Buffer = NULL;
+ int tag = 0;
+ int return_value = -1;
+ unsigned long ber_len = 0;
+ unsigned long Bytes_Scanned = 0;
+
+ op = priv->c_current_op;
+ Bytes_Read = priv->c_number_of_async_bytes_read;
+ Buffer = priv->c_buffer + priv->c_buffer_offset;
+
+ PR_ASSERT(NULL != op->o_ber);
+
+ /* Is this an SSL connection ? */
+ if (0 == (conn->c_flags & CONN_FLAG_SSL)) {
+ /* Not SSL */
+
+ if (! config_check_referral_mode()) {
+ /* Update stats */
+ PR_Lock( op_thread_lock );
+ (*(g_get_global_snmp_vars()->ops_tbl.dsBytesRecv)) += Bytes_Read;
+ PR_Unlock( op_thread_lock );
+ }
+
+ /* We need to read the data into the BER buffer */
+ /* This can return a tag pr LBER_DEFAULT, indicating some error condition */
+ tag = ber_get_next_buffer_ext( Buffer, Bytes_Read, &ber_len, op->o_ber, &Bytes_Scanned, conn->c_sb );
+ if(LBER_DEFAULT == tag)
+ {
+ if (0 == Bytes_Scanned)
+ {
+ /* Means we encountered an error---eg the client sent us pure crap---
+ a bunch of bytes which we took to be a tag, length, then we ran off the
+ end of the buffer. The next time we get here, we'll be returned LBER_DEFAULT
+ This means that everything we've seen up till now is useless because it wasn't
+ an LDAP message.
+ So, we toss it away ! */
+ if (errno == EMSGSIZE) {
+ log_ber_too_big_error(conn, ber_len, 0);
+ }
+ PR_Lock( conn->c_mutex );
+ connection_remove_operation( conn, op );
+ operation_free(&op, conn);
+ priv->c_current_op = NULL;
+ PR_Unlock( conn->c_mutex );
+ return -1; /* Abandon Connection */
+ }
+ }
+ if (is_ber_too_big(conn,ber_len))
+ {
+ PR_Lock( conn->c_mutex );
+ connection_remove_operation( conn, op );
+ operation_free(&op, conn);
+ priv->c_current_op = NULL;
+ PR_Unlock( conn->c_mutex );
+ return -1; /* Abandon Connection */
+ }
+
+ /* We set the flag to indicate that we'er in the middle of an op */
+ priv->c_flags |= FLAG_CONN_HAD_SOME;
+
+ /* Then we decide whether this is the last read for the current op */
+ /* and set the flag accordingly */
+ if (LBER_DEFAULT != tag) { /* we received a complete message */
+ if (LDAP_TAG_MESSAGE == tag) { /* looks like an LDAP message */
+ /* It's time to process this operation */
+ *process_op = 1;
+ priv->c_current_op = NULL;
+ priv->c_flags = 0;
+ } else {
+ /*
+ * We received a non-LDAP message. Log and close connection.
+ */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "conn=%d received a non-LDAP message"
+ " (tag 0x%lx, expected 0x%lx)\n",
+ conn->c_connid, tag, LDAP_TAG_MESSAGE );
+ PR_Lock( conn->c_mutex );
+ connection_remove_operation( conn, op );
+ operation_free(&op, conn);
+ priv->c_current_op = NULL;
+ PR_Unlock( conn->c_mutex );
+ return -1; /* Abandon Connection */
+ }
+ }
+
+ /* Finally, mark whether there's the beginning of another operation remaining in the buffer */
+ /* If there is, queue up another I/O completion request on the port to get it handled OK */
+ /* If not, issue a new read on the socket. */
+ if (Bytes_Scanned != Bytes_Read) {
+ if (connection_increment_reference(conn) == -1) {
+ LDAPDebug(LDAP_DEBUG_CONNS,
+ "could not acquire lock in issue_new_read as conn %d closing fd=%d\n",
+ conn->c_connid,conn->c_sd,0);
+ /* XXX how to handle this error? */
+ /* MAB: 25 Jan 01: let's try like this and pray this won't leak... */
+ /* GB : this should be OK because an error here
+ * means some other thread decided to close the
+ * connection, which mean a fatal error happened
+ * in that case just forget about the remaining
+ * data and return
+ */
+ return (0);
+ }
+ if ((return_value = push_back_data(conn,priv->c_overlapped.Offset + Bytes_Scanned,
+ Bytes_Read-Bytes_Scanned)) == -1) {
+ /* MAB: 25 jan 01 we need to decrement the conn refcnt before leaving... Otherwise,
+ * this thread will unbalance the ref_cnt inc and dec for this connection
+ * and the result is that the connection is never closed and instead is kept
+ * forever an never released -> this was causing a fd starvation on NT
+ */
+ connection_decrement_reference(conn);
+ LDAPDebug(LDAP_DEBUG_CONNS,
+ "push_back_data failed: closing conn %d fd=%d\n",
+ conn->c_connid,conn->c_sd,0);
+ }
+ } else {
+ priv->c_overlapped.Offset = 0;
+ return_value = issue_new_read(conn);
+ }
+ } else {
+ /* SSL */
+ if ( (tag = ber_get_next( conn->c_sb, &ber_len, op->o_ber ))
+ != LDAP_TAG_MESSAGE ) {
+ return( -1 );
+ }
+ if(is_ber_too_big(conn,ber_len))
+ {
+ return( -1 );
+ }
+ /* Put this connection back into the read-ready signal state */
+ /* priv->c_flags |= FLAG_CONN_COMPLETE; Redundant now */
+ /* It's time to process this operation */
+ *process_op = 1;
+ priv->c_current_op = NULL;
+ priv->c_flags = 0;
+ return_value = 0;
+ add_to_select_set(conn);
+ }
+
+ return return_value;
+}
+
+int push_back_data(Connection *conn, size_t offset, size_t length)
+{
+ /* Use PostQueuedCompletionStatus() to push the data back up the pipe */
+ BOOL return_bool = FALSE;
+
+ conn->c_private->c_overlapped.Offset = offset;
+ return_bool = PostQueuedCompletionStatus(completion_port,length,(DWORD)conn,&conn->c_private->c_overlapped);
+
+ if (return_bool) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/* This function issues a new read operation on the connection.
+ * Called once we've finished reading everything from the buffer.
+ * VMS crusties will notice the similarity to $QIO.
+ */
+int issue_new_read(Connection *conn)
+{
+ BOOL return_bool = FALSE;
+ HANDLE socket = INVALID_HANDLE_VALUE;
+ void **buffer = NULL;
+ DWORD bytes_read = 0;
+ DWORD buffer_size = 0;
+ OVERLAPPED *overlapped = NULL;
+
+ PR_ASSERT(NULL != conn);
+ socket = (HANDLE)conn->c_sd;
+ PR_ASSERT(NULL != socket);
+
+ /* here we make sure that we have a buffer allocated */
+ buffer = &conn->c_private->c_buffer;
+ if (NULL == *buffer) {
+ *buffer = (void*)slapi_ch_malloc(LDAP_SOCKET_IO_BUFFER_SIZE);
+ if (NULL == *buffer) {
+ /* memory allocation failure */
+ return -1;
+ }
+ conn->c_private->c_buffer_size = LDAP_SOCKET_IO_BUFFER_SIZE;
+ }
+
+ buffer_size = conn->c_private->c_buffer_size;
+ overlapped = &conn->c_private->c_overlapped;
+
+ if (connection_increment_reference(conn) == -1) {
+ LDAPDebug(LDAP_DEBUG_CONNS,
+ "could not acquire lock in issue_new_read as conn %d closing fd=%d\n",
+ conn->c_connid,conn->c_sd,0);
+ /* This means that the connection is closing */
+ return -1;
+ }
+ return_bool = ReadFile(socket,*buffer,buffer_size,&bytes_read,overlapped);
+ if ( !return_bool && ERROR_IO_PENDING != GetLastError( ) ) {
+ /* This means that the connection is shot for some reason */
+ connection_decrement_reference(conn);
+ return -1;
+ } else {
+ /* Our work is done, i/o read now queued */
+ return 0;
+ }
+}
+
+static int wait_on_new_work(Connection **ppConn, work_type *type)
+{
+ /* Here, we wait on the I/O completion port for new data */
+ /* because we're not sure whether the completion port has been created yet,
+ * we wait 'till it has been.
+ */
+ Connection *temp_conn = NULL;
+ DWORD Bytes_Received = 0;
+ OVERLAPPED *pOverlapped = NULL;
+ BOOL return_bool = FALSE;
+
+ *type = read_data;
+
+ while ( (INVALID_HANDLE_VALUE == completion_port) && (!op_shutdown) ) {
+ Sleep(100);
+ }
+ while (1) {
+ if (op_shutdown) {
+ return EINTR;
+ }
+ return_bool = GetQueuedCompletionStatus(completion_port,&Bytes_Received,(DWORD*)&temp_conn,&pOverlapped,INFINITE);
+ if ((unsigned long)temp_conn == COMPKEY_DIE ) {
+ continue; /* kill this worker */
+ }
+ if (TRUE == return_bool) {
+ /* we successfully completed the I/O operation */
+ /* set the connection pointer the caller gave us to the one from the port */
+ PR_ASSERT(NULL != pOverlapped);
+ PR_ASSERT(NULL != temp_conn);
+ *ppConn = temp_conn;
+ /* store the # bytes read in the connection structure */
+ (*ppConn)->c_private->c_number_of_async_bytes_read = Bytes_Received;
+ (*ppConn)->c_private->c_buffer_offset = (*ppConn)->c_private->c_overlapped.Offset;
+ if( Bytes_Received == 0 )
+ {
+ /* 0 bytes received from a completed overlapped I/O
+ operation means the socket's been closed. */
+ break;
+ }
+ (*ppConn)->c_idlesince = current_time();
+ /* If we exit here, everything is OK */
+ connection_decrement_reference(temp_conn);
+ return 0;
+ }
+ if ( (FALSE == return_bool) && (NULL == pOverlapped) ) {
+ /* we timed out */
+ /* slapi_log_error( SLAPI_LOG_FATAL, "connection",
+ "GetQueuedCompletionStatus call timed out\n");*/
+ continue;
+ }
+ if ( (FALSE == return_bool) && (NULL != pOverlapped)) {
+ /* signifies some sort of i/o error, most likely an abortive close */
+ /* slapi_log_error( SLAPI_LOG_FATAL, "connection",
+ "GetQueuedCompletionStatus call failed; error - %ld\n", GetLastError());*/
+ if (NULL != temp_conn) {
+ /* If we were told the connection, return it--otherwise we can't tell which connection to close */
+ *ppConn = temp_conn;
+ }
+ break;
+ }
+ }
+ return EPIPE; /* we failed to read for some reason */
+}
+
+int connection_new_private(Connection *conn)
+{
+ /* first add to the completion port */
+ DWORD threads = 10; /* DBDB hackhack */
+ HANDLE socket = INVALID_HANDLE_VALUE;
+ HANDLE return_port = NULL;
+ Conn_private *priv = NULL;
+ int return_value = -1;
+
+ PR_ASSERT(NULL != conn);
+
+ socket = (HANDLE) conn->c_sd;
+
+ /* make the private data if it isn't already there */
+
+ if (NULL == conn->c_private) {
+ Conn_private *new_private = (Conn_private *)slapi_ch_malloc(sizeof(Conn_private));
+ if (NULL == new_private) {
+ /* memory allocation failed */
+ return -1;
+ }
+ conn->c_private = new_private;
+ ZeroMemory(conn->c_private,sizeof(Conn_private));
+ }
+ priv = conn->c_private;
+ /* Make sure the private structure is cleared */
+ /* Note: you must modify this code if the contents
+ * of the structure are changed---we can't simply
+ * zero the structure because we want to preserve the
+ * buffer. IMPORTANT---here we reuse the I/O buffer
+ * from before. This is deliberate, to avoid mallocing again */
+ ZeroMemory(&(priv->c_overlapped),sizeof(OVERLAPPED));
+ priv->c_number_of_async_bytes_read = 0;
+ priv->c_buffer_offset = 0;
+ priv->c_flags = 0;
+ priv->c_current_op = NULL;
+
+
+ if (INVALID_HANDLE_VALUE == completion_port) {
+ /* completion port not yet setup, we need to make it */
+ completion_port = CreateIoCompletionPort(INVALID_HANDLE_VALUE,NULL,0,0);
+ if (NULL == completion_port) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Failed to create master I/O completion port\n",0,0,0);
+ return -1;
+ }
+ }
+ /* If the connection is SSL, don't do the right thing */
+ if (0 == (conn->c_flags & CONN_FLAG_SSL)) {
+ return_port = CreateIoCompletionPort(socket,completion_port,(DWORD)conn,0);
+ if (NULL == return_port) {
+ LDAPDebug(LDAP_DEBUG_ANY,"Failed to associate socket with I/O completion port, fd=%d,GetLastError = %d\n",socket,GetLastError(),0);
+ return -1;
+ }
+ /* Now queue the initial read on this connection */
+ return_value = issue_new_read(conn);
+ } else {
+ return_value = 0;
+ }
+
+ return return_value;
+}
+
+/* If all is well, this only gets called for SSL connections */
+int connection_activity(Connection *conn)
+{
+ /* First check that this really is an SSL connection */
+ if (0 == (conn->c_flags & CONN_FLAG_SSL)) {
+ return -1;
+ }
+ /* Now, the plan here is to push something up the IOCP pipe */
+ /* We need to fake something up so that the code which pulls
+ * it off the queue does the right thing. Here's what we do:
+ * We just call PostQueuedCompletionStatus like normal.
+ * The connection is marked as SSL, and it is this that the
+ * reading code notices. Simple !
+ */
+ /* Also, we need to participate in the signaling protocol to the select thread */
+ remove_from_select_set(conn);
+ /* We hold the lock already, increment the reference count, which will
+ be decremented in wait_for_new_work(). */
+ if (connection_acquire_nolock (conn) == -1) {
+ LDAPDebug(LDAP_DEBUG_CONNS,
+ "could not acquire lock in connection_activity as conn %d closing fd=%d\n",
+ conn->c_connid,conn->c_sd,0);
+ /* XXX how to handle this error? */
+ /* MAB: 25 Jan 01: let's return on error and pray this won't leak */
+ return (-1);
+ }
+ return push_back_data(conn, 0, 1);
+}
+
+static int finished_chomping(Connection *conn)
+{
+ /* On NT we don't need to do anything here */
+ return 0;
+}
+
+#else /* WIN32/UNIX */
+
+/*
+ * This is where the UNIX Helper functions would be if IO
+ * Completion Ports were supported on UNIX.
+ */
+
+#endif /* WIN32/UNIX */
+
+#else /* LDAP_IOCP */
+
+/*
+ * IO Completion Ports are not available on this platform.
+ */
+
+static int counter= 0; /* JCM Dumb Name */
+
+/* The connection private structure for UNIX turbo mode */
+struct Conn_private
+{
+ int turbo_flag; /* set if we are currently in turbo mode */
+ int previous_op_count; /* the operation counter value last time we sampled it, used to compute operation rate */
+ int operation_rate; /* rate (ops/sample period) at which this connection has been processing operations */
+ time_t previous_count_check_time; /* The wall clock time we last sampled the operation count */
+ size_t c_buffer_size; /* size of the socket read buffer */
+ char *c_buffer; /* pointer to the socket read buffer */
+ size_t c_buffer_bytes; /* number of bytes currently stored in the buffer */
+ size_t c_buffer_offset; /* offset to the location of new data in the buffer */
+};
+
+int
+connection_new_private(Connection *conn)
+{
+ if (NULL == conn->c_private) {
+ Conn_private *new_private = (Conn_private *)slapi_ch_calloc(1,sizeof(Conn_private));
+ if (NULL == new_private) {
+ /* memory allocation failed */
+ return -1;
+ }
+ conn->c_private = new_private;
+ }
+
+ /* The c_buffer is supposed to be NULL here, cleaned by connection_cleanup,
+ double check to avoid memory leak */
+ if (NULL == conn->c_private->c_buffer) {
+ conn->c_private->c_buffer = (char*)slapi_ch_malloc(LDAP_SOCKET_IO_BUFFER_SIZE);
+ if (NULL == conn->c_private->c_buffer) {
+ /* memory allocation failure */
+ return -1;
+ }
+ conn->c_private->c_buffer_size = LDAP_SOCKET_IO_BUFFER_SIZE;
+ }
+
+ /*
+ * Clear the private structure, preserving the buffer and length in
+ * case we are reusing the buffer.
+ */
+ {
+ char *c_buffer = conn->c_private->c_buffer;
+ size_t c_buffer_size = conn->c_private->c_buffer_size;;
+
+ memset( conn->c_private, 0, sizeof(Conn_private));
+ conn->c_private->c_buffer = c_buffer;
+ conn->c_private->c_buffer_size = c_buffer_size;
+ }
+
+ return 0;
+}
+
+static void
+connection_free_private_buffer(Connection *conn)
+{
+ if (NULL != conn->c_private) {
+ slapi_ch_free((void*)&(conn->c_private->c_buffer));
+ }
+}
+
+/*
+ * Turbo Mode:
+ * Turbo Connection Mode is designed to more efficiently
+ * serve a small number of highly active connections performing
+ * mainly search operations. It is only used on UNIX---completion
+ * ports on NT make it unnecessary.
+ * A connection can be in turbo mode, or not in turbo mode.
+ * For non-turbo mode, the code path is the same as was before:
+ * worker threads wait on a condition variable for work.
+ * When they awake they consult the operation queue for
+ * something to do, read the operation from the connection's socket,
+ * perform the operation and go back to waiting on the condition variable.
+ * In Turbo Mode, a worker thread becomes associated with a connection.
+ * It then waits not on the condition variable, but directly on read ready
+ * state on the connection's socket. When new data arrives, it decodes
+ * the operation and executes it, and then goes back to read another
+ * operation from the same socket, or block waiting on new data.
+ * The read is done non-blocking, wait in poll with a timeout.
+ *
+ * There is a mechanism to ensure that only the most active
+ * connections are in turbo mode at any time. If this were not
+ * the case we could starve out some client operation requests
+ * due to waiting on I/O in many turbo threads at the same time.
+ *
+ * Each worker thread periodically (every 10 seconds) examines
+ * the activity level for the connection it is processing.
+ * This applies regardless of whether the connection is
+ * currently in turbo mode or not. Activity is measured as
+ * the number of operations initiated since the last check was done.
+ * The N connections with the highest activity level are allowed
+ * to enter turbo mode. If the current connection is in the top N,
+ * then we decide to enter turbo mode. If the current connection
+ * is no longer in the top N, then we leave turbo mode.
+ * The decision to enter or leave turbo mode is taken under
+ * the connection mutex, preventing race conditions where
+ * more than one thread can change the turbo state of a connection
+ * concurrently.
+ */
+
+
+/* Connection status values returned by
+ connection_wait_for_new_pb(), connection_read_operation(), etc. */
+
+#define CONN_FOUND_WORK_TO_DO 0
+#define CONN_SHUTDOWN 1
+#define CONN_NOWORK 2
+#define CONN_DONE 3
+#define CONN_TIMEDOUT 4
+
+#define CONN_TURBO_TIMEOUT_INTERVAL 1000 /* milliseconds */
+#define CONN_TURBO_CHECK_INTERVAL 5 /* seconds */
+#define CONN_TURBO_PERCENTILE 50 /* proportion of threads allowed to be in turbo mode */
+#define CONN_TURBO_HYSTERESIS 0 /* avoid flip flopping in and out of turbo mode */
+
+int connection_wait_for_new_pb(Slapi_PBlock **ppb, PRIntervalTime interval)
+{
+ int ret = CONN_FOUND_WORK_TO_DO;
+
+ PR_Lock( op_thread_lock );
+
+ /* While there is no operation to do... */
+ while( counter < 1) {
+ /* Check if we should shutdown. */
+ if (op_shutdown) {
+ PR_Unlock( op_thread_lock );
+ return CONN_SHUTDOWN;
+ }
+ PR_WaitCondVar( op_thread_cv, interval);
+ }
+
+ /* There is some work to do. */
+
+ counter--;
+ PR_Unlock( op_thread_lock );
+
+ /* Get the next operation from the work queue. */
+
+ *ppb = get_pb();
+ if (*ppb == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY, "pb is null \n", 0, 0, 0 );
+ PR_Lock( op_thread_lock );
+ counter++;
+ PR_Unlock( op_thread_lock );
+ ret = CONN_NOWORK;
+ }
+ return ret;
+}
+
+void connection_make_new_pb(Slapi_PBlock **ppb, Connection *conn)
+{
+ /* In the classic case, the pb is made in connection_activity() and then
+ queued. get_pb() dequeues it. So we can just make it ourselves here */
+
+ /* *ppb = (Slapi_PBlock *) slapi_ch_calloc( 1, sizeof(Slapi_PBlock) ); */
+ *ppb = slapi_pblock_new();
+ (*ppb)->pb_conn = conn;
+ (*ppb)->pb_op = operation_new( plugin_build_operation_action_bitmap( 0,
+ plugin_get_server_plg() ));
+ connection_add_operation( conn, (*ppb)->pb_op );
+}
+
+
+/*
+ * Utility function called by connection_read_operation(). This is a
+ * small wrapper on top of libldap's ber_get_next_buffer_ext().
+ */
+static int
+get_next_from_buffer( void *buffer, size_t buffer_size, unsigned long *lenp,
+ unsigned long *tagp, BerElement *ber, Connection *conn )
+{
+ PRErrorCode err = 0;
+ PRInt32 syserr = 0;
+ unsigned long bytes_scanned = 0;
+
+ *lenp = 0;
+ *tagp = ber_get_next_buffer_ext( buffer, buffer_size, lenp, ber,
+ &bytes_scanned, conn->c_sb );
+ if (LBER_DEFAULT == *tagp && 0 == bytes_scanned) {
+ if (errno == EMSGSIZE) {
+ log_ber_too_big_error(conn, *lenp, 0);
+ err = SLAPD_DISCONNECT_BER_TOO_BIG;
+ } else {
+ syserr = errno;
+ }
+ /* Bad stuff happened, like the client sent us some junk */
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "ber_get_next failed for connection %d\n", conn->c_connid, 0, 0 );
+ /* reset private buffer */
+ conn->c_private->c_buffer_bytes = conn->c_private->c_buffer_offset = 0;
+
+ /* drop connection */
+ disconnect_server( conn, conn->c_connid, -1, err, syserr );
+ return -1;
+ }
+
+ /* success, or need to wait for more data */
+ conn->c_private->c_buffer_offset += bytes_scanned;
+ return 0;
+}
+
+/* Either read read data into the connection buffer, or fail with err set */
+static int
+connection_read_ldap_data(Connection *conn, PRInt32 *err)
+{
+ int ret = 0;
+ /* Is SASL encryption enabled on this connection ? */
+ if (conn->c_sasl_io) {
+ /* If so, call the SASL I/O layer */
+ ret = sasl_recv_connection(conn,conn->c_private->c_buffer, conn->c_private->c_buffer_size,err);
+ } else
+ {
+ /* Otherwise, just call PRRecv() */
+ ret = PR_Recv(conn->c_prfd,conn->c_private->c_buffer,conn->c_private->c_buffer_size,0,PR_INTERVAL_NO_WAIT);
+ if (ret < 0) {
+ *err = PR_GetError();
+ }
+ }
+ return ret;
+}
+
+/* Upon returning from this function, we have either:
+ 1. Read a PDU successfully.
+ 2. Detected some error condition with the connection which requires closing it.
+ 3. In Turbo mode, we Timed out without seeing any data.
+
+ We also handle the case where we read ahead beyond the current PDU
+ by buffering the data and setting the 'remaining_data' flag.
+
+ */
+int connection_read_operation(Connection *conn, Operation *op, unsigned long *tag, int *remaining_data)
+{
+ unsigned long len = 0;
+ int ret = 0;
+ int waits_done = 0;
+ long msgid;
+ int new_operation = 1; /* Are we doing the first I/O read for a new operation ? */
+ char *buffer = conn->c_private->c_buffer;
+ PRErrorCode err = 0;
+ PRInt32 syserr = 0;
+
+ /*
+ * if the socket is still valid, get the ber element
+ * waiting for us on this connection. timeout is handled
+ * in the low-level [secure_]read_function.
+ */
+ if ( (conn->c_sd == SLAPD_INVALID_SOCKET) ||
+ (conn->c_flags & CONN_FLAG_CLOSING) ) {
+ return CONN_DONE;
+ }
+
+ /* See if we should enable SASL I/O for this connection */
+ if (conn->c_enable_sasl_io) {
+ ret = sasl_io_setup(conn);
+ if (ret) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "conn=%d unable to enable SASL I/O\n", conn->c_connid, 0, 0 );
+ disconnect_server( conn, conn->c_connid, -1, SLAPD_DISCONNECT_BAD_BER_TAG, EPROTO );
+ return CONN_DONE;
+ }
+ }
+
+ *tag = LBER_DEFAULT;
+ /* First check to see if we have buffered data from "before" */
+ if (conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset) {
+ /* If so, use that data first */
+ if ( 0 != get_next_from_buffer( buffer
+ + conn->c_private->c_buffer_offset,
+ conn->c_private->c_buffer_bytes
+ - conn->c_private->c_buffer_offset,
+ &len, tag, op->o_ber, conn )) {
+ return CONN_DONE;
+ }
+ new_operation = 0;
+ }
+ /* If we still haven't seen a complete PDU, read from the network */
+ while (*tag == LBER_DEFAULT) {
+ int ioblocktimeout_waits = config_get_ioblocktimeout() / CONN_TURBO_TIMEOUT_INTERVAL;
+ /* We should never get here with data remaining in the buffer */
+ PR_ASSERT( !new_operation || 0 == (conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset) );
+ /* We make a non-blocking read call */
+ /* ret = PR_Recv(conn->c_prfd,conn->c_private->c_buffer,conn->c_private->c_buffer_size,0,PR_INTERVAL_NO_WAIT); */
+ ret = connection_read_ldap_data(conn,&err);
+ if (ret <= 0) {
+ if (0 == ret) {
+ /* Connection is closed */
+ PR_Lock( conn->c_mutex );
+ disconnect_server_nomutex( conn, conn->c_connid, -1, SLAPD_DISCONNECT_BAD_BER_TAG, 0 );
+ conn->c_gettingber = 0;
+ PR_Unlock( conn->c_mutex );
+ signal_listner();
+ return CONN_DONE;
+ }
+ /* err = PR_GetError(); */
+ /* If we would block, we need to poll for a while */
+ if ( SLAPD_PR_WOULD_BLOCK_ERROR( err ) ) {
+ struct PRPollDesc pr_pd;
+ PRIntervalTime timeout = PR_MillisecondsToInterval(CONN_TURBO_TIMEOUT_INTERVAL);
+ pr_pd.fd = (PRFileDesc *)conn->c_prfd;
+ pr_pd.in_flags = PR_POLL_READ;
+ pr_pd.out_flags = 0;
+ ret = PR_Poll(&pr_pd, 1, timeout);
+ waits_done++;
+ /* Did we time out ? */
+ if (0 == ret) {
+ /* We timed out, should the server shutdown ? */
+ if (op_shutdown) {
+ return CONN_SHUTDOWN;
+ }
+ /* We timed out, is this the first read in a PDU ? */
+ if (new_operation) {
+ /* If so, we return */
+ return CONN_TIMEDOUT;
+ } else {
+ /* Otherwise we loop, unless we exceeded the ioblock timeout */
+ if (waits_done > ioblocktimeout_waits) {
+ LDAPDebug( LDAP_DEBUG_CONNS,"ioblock timeout expired on connection %d\n", conn->c_connid, 0, 0 );
+ disconnect_server( conn, conn->c_connid, -1,
+ SLAPD_DISCONNECT_IO_TIMEOUT, 0 );
+ return CONN_DONE;
+ } else {
+
+ /* The turbo mode may cause threads starvation.
+ Do a yield here to reduce the starving.
+ */
+ PR_Sleep(PR_INTERVAL_NO_WAIT);
+
+ continue;
+ }
+ }
+ }
+ if (-1 == ret) {
+ /* PR_Poll call failed */
+ err = PR_GetError();
+ syserr = PR_GetOSError();
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "PR_Poll for connection %d returns %d (%s)\n", conn->c_connid, err, slapd_pr_strerror( err ) );
+ /* If this happens we should close the connection */
+ disconnect_server( conn, conn->c_connid, -1, err, syserr );
+ return CONN_DONE;
+ }
+ } else {
+ /* Some other error, typically meaning bad stuff */
+ syserr = PR_GetOSError();
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "PR_Recv for connection %d returns %d (%s)\n", conn->c_connid, err, slapd_pr_strerror( err ) );
+ /* If this happens we should close the connection */
+ disconnect_server( conn, conn->c_connid, -1, err, syserr );
+ return CONN_DONE;
+ }
+ } else {
+ /* We read some data off the network, do something with it */
+ conn->c_private->c_buffer_bytes = ret;
+ conn->c_private->c_buffer_offset = 0;
+
+ if ( get_next_from_buffer( buffer,
+ conn->c_private->c_buffer_bytes
+ - conn->c_private->c_buffer_offset,
+ &len, tag, op->o_ber, conn ) != 0 ) {
+ return CONN_DONE;
+ }
+
+ new_operation = 0;
+ ret = 0;
+ waits_done = 0; /* got some data: reset counter */
+ }
+ }
+ /* If there is remaining buffered data, set the flag to tell the caller */
+ if (conn->c_private->c_buffer_bytes - conn->c_private->c_buffer_offset) {
+ *remaining_data = 1;
+ }
+
+ if ( *tag != LDAP_TAG_MESSAGE ) {
+ /*
+ * We received a non-LDAP message. Log and close connection.
+ */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "conn=%d received a non-LDAP message (tag 0x%lx, expected 0x%lx)\n",
+ conn->c_connid, *tag, LDAP_TAG_MESSAGE );
+ disconnect_server( conn, conn->c_connid, -1,
+ SLAPD_DISCONNECT_BAD_BER_TAG, EPROTO );
+ return CONN_DONE;
+ }
+
+ if ( (*tag = ber_get_int( op->o_ber, &msgid ))
+ != LDAP_TAG_MSGID ) {
+ /* log, close and send error */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "conn=%d unable to read tag for incoming request\n", conn->c_connid, 0, 0 );
+ disconnect_server( conn, conn->c_connid, -1, SLAPD_DISCONNECT_BAD_BER_TAG, EPROTO );
+ return CONN_DONE;
+ }
+ if(is_ber_too_big(conn,len))
+ {
+ disconnect_server( conn, conn->c_connid, -1, SLAPD_DISCONNECT_BER_TOO_BIG, 0 );
+ return CONN_DONE;
+ }
+ op->o_msgid = msgid;
+
+ *tag = ber_peek_tag( op->o_ber, &len );
+ switch ( *tag ) {
+ case LBER_ERROR:
+ case LDAP_TAG_LDAPDN: /* optional username, for CLDAP */
+ /* log, close and send error */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "conn=%d ber_peek_tag returns 0x%lx\n", conn->c_connid, *tag, 0 );
+ disconnect_server( conn, conn->c_connid, -1, SLAPD_DISCONNECT_BER_PEEK, EPROTO );
+ return CONN_DONE;
+ default:
+ break;
+ }
+ op->o_tag = *tag;
+ return ret;
+}
+
+void connection_make_readable(Connection *conn)
+{
+ PR_Lock( conn->c_mutex );
+ conn->c_gettingber = 0;
+ PR_Unlock( conn->c_mutex );
+ signal_listner();
+}
+
+/*
+ * Figure out the operation completion rate for this connection
+ */
+void connection_check_activity_level(Connection *conn)
+{
+ int current_count = 0;
+ int delta_count = 0;
+ PR_Lock( conn->c_mutex );
+ /* get the current op count */
+ current_count = conn->c_opscompleted;
+ /* compare to the previous op count */
+ delta_count = current_count - conn->c_private->previous_op_count;
+ /* delta is the rate, store that */
+ conn->c_private->operation_rate = delta_count;
+ /* store current count in the previous count slot */
+ conn->c_private->previous_op_count = current_count;
+ /* update the last checked time */
+ conn->c_private->previous_count_check_time = current_time();
+ PR_Unlock( conn->c_mutex );
+ LDAPDebug(LDAP_DEBUG_CONNS,"conn %d activity level = %d\n",conn->c_connid,delta_count,0);
+}
+
+typedef struct table_iterate_info_struct {
+ int connection_count;
+ int rank_count;
+ int our_rate;
+} table_iterate_info;
+
+int table_iterate_function(Connection *conn, void *arg)
+{
+ int ret = 0;
+ table_iterate_info *pinfo = (table_iterate_info*)arg;
+ pinfo->connection_count++;
+ if (conn->c_private->operation_rate > pinfo->our_rate) {
+ pinfo->rank_count++;
+ }
+ return ret;
+}
+
+/*
+ * Scan the list of active connections, evaluate our relative rank
+ * for connection activity.
+ */
+void connection_find_our_rank(Connection *conn,int *connection_count, int *our_rank)
+{
+ int ret = 0;
+ table_iterate_info info = {0};
+ info.our_rate = conn->c_private->operation_rate;
+ ret = connection_table_iterate_active_connections(the_connection_table, &info, &table_iterate_function);
+ *connection_count = info.connection_count;
+ *our_rank = info.rank_count;
+}
+
+/*
+ * Evaluate the turbo policy for this connection
+ */
+void connection_enter_leave_turbo(Connection *conn, int *new_turbo_flag)
+{
+ int current_mode = 0;
+ int new_mode = 0;
+ int connection_count = 0;
+ int our_rank = 0;
+ int threshold_rank = 0;
+ PR_Lock(conn->c_mutex);
+ /* We can already be in turbo mode, or not */
+ current_mode = conn->c_private->turbo_flag;
+ if(conn->c_private->operation_rate == 0) {
+ /* The connection is ranked by the passed activities. If some other connection have more activity,
+ increase rank by one. The highest rank is least activity, good candidates to move out of turbo mode.
+ However, if no activity on all the connections, then every connection gets 0 rank, so none move out.
+ No bother to do so much calcuation, short-cut to non-turbo mode if no activities in passed interval */
+ new_mode = 0;
+ } else {
+ connection_find_our_rank(conn,&connection_count, &our_rank);
+ LDAPDebug(LDAP_DEBUG_CONNS,"conn %d turbo rank = %d out of %d conns\n",conn->c_connid,our_rank,connection_count);
+ threshold_rank = (int)((double)active_threads * ((double)CONN_TURBO_PERCENTILE / 100.0) );
+
+ /* adjust threshold_rank according number of connections,
+ less turbo threads as more connections,
+ one measure to reduce thread startvation.
+ */
+ if (connection_count > threshold_rank) {
+ threshold_rank -= (connection_count - threshold_rank) / 5;
+ }
+
+ if (current_mode) {
+ /* We're currently in turbo mode */
+ /* Policy says that we stay in turbo mode provided
+ connection activity is still high.
+ */
+ if (our_rank - CONN_TURBO_HYSTERESIS < threshold_rank) {
+ /* Stay in turbo mode */
+ new_mode = 1;
+ } else {
+ /* Exit turbo mode */
+ new_mode = 0;
+ }
+ } else {
+ /* We're currently not in turbo mode */
+ /* Policy says that we go into turbo mode if
+ recent connection activity is high.
+ */
+ if (our_rank + CONN_TURBO_HYSTERESIS < threshold_rank) {
+ /* Enter turbo mode */
+ new_mode = 1;
+ } else {
+ /* Stay out of turbo mode */
+ new_mode = 0;
+ }
+ }
+ }
+ conn->c_private->turbo_flag = new_mode;
+ PR_Unlock(conn->c_mutex);
+ if (current_mode != new_mode) {
+ if (current_mode) {
+ LDAPDebug(LDAP_DEBUG_CONNS,"conn %d leaving turbo mode\n",conn->c_connid,0,0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_CONNS,"conn %d entering turbo mode\n",conn->c_connid,0,0);
+ }
+ }
+ *new_turbo_flag = new_mode;
+}
+
+static void
+connection_threadmain()
+{
+ Slapi_PBlock *pb = NULL;
+ PRIntervalTime interval = PR_SecondsToInterval(10);
+ Connection *conn = NULL;
+ Operation *op;
+ unsigned long tag = 0;
+ int need_wakeup;
+ int thread_turbo_flag = 0;
+ int ret = 0;
+ int more_data = 0;
+
+#if defined( OSF1 ) || defined( hpux )
+ /* Arrange to ignore SIGPIPE signals. */
+ SIGNAL( SIGPIPE, SIG_IGN );
+#endif
+
+ while (1) {
+ int is_timedout = 0;
+
+ if( op_shutdown ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "op_thread received shutdown signal\n", 0, 0, 0 );
+ PR_AtomicDecrement(&active_threads);
+ return;
+ }
+
+ if (!thread_turbo_flag && (NULL == pb) && !more_data) {
+ /* If more data is left from the previous connection_read_operation,
+ we should finish the op now. Client might be thinking it's
+ done sending the request and wait for the response forever.
+ [blackflag 624234] */
+ ret = connection_wait_for_new_pb(&pb,interval);
+ switch (ret) {
+ case CONN_NOWORK:
+ continue;
+ case CONN_SHUTDOWN:
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "op_thread received shutdown signal\n", 0, 0, 0 );
+ PR_AtomicDecrement(&active_threads);
+ return;
+ case CONN_FOUND_WORK_TO_DO:
+ default:
+ break;
+ }
+ } else if (NULL == pb) {
+
+ /* The turbo mode may cause threads starvation.
+ Do a yield here to reduce the starving
+ */
+ PR_Sleep(PR_INTERVAL_NO_WAIT);
+
+ PR_Lock(conn->c_mutex);
+ /* Make our own pb in turbo mode */
+ connection_make_new_pb(&pb,conn);
+ PR_Unlock(conn->c_mutex);
+ if (! config_check_referral_mode()) {
+ PR_AtomicIncrement(&ops_initiated);
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsInOps);
+ }
+ }
+ /* Once we're here we have a pb */
+ conn = pb->pb_conn;
+ op = pb->pb_op;
+
+ more_data = 0;
+ ret = connection_read_operation(conn,op,&tag,&more_data);
+
+#define DB_PERF_TURBO 1
+#if defined(DB_PERF_TURBO)
+ /* If it's been a while since we last did it ... */
+ if (current_time() - conn->c_private->previous_count_check_time > CONN_TURBO_CHECK_INTERVAL) {
+ int new_turbo_flag = 0;
+ /* Check the connection's activity level */
+ connection_check_activity_level(conn);
+ /* And if appropriate, change into or out of turbo mode */
+ connection_enter_leave_turbo(conn,&new_turbo_flag);
+ thread_turbo_flag = new_turbo_flag;
+ }
+
+ /* turn off turbo mode immediately if any pb waiting in global queue */
+ if (thread_turbo_flag && (counter > 0)) {
+ thread_turbo_flag = 0;
+ LDAPDebug(LDAP_DEBUG_CONNS,"conn %d leaving turbo mode\n",conn->c_connid,0,0);
+ }
+#endif
+
+ switch (ret) {
+ case CONN_DONE:
+ /* This means that the connection was closed, so clear turbo mode */
+ /*FALLTHROUGH*/
+ case CONN_TIMEDOUT:
+ thread_turbo_flag = 0;
+ is_timedout = 1;
+ /* note:
+ * should call connection_make_readable after the op is removed
+ * connection_make_readable(conn);
+ */
+ goto done;
+ case CONN_SHUTDOWN:
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "op_thread received shutdown signal\n", 0, 0, 0 );
+ PR_AtomicDecrement(&active_threads);
+ return;
+ default:
+ break;
+ }
+
+ /*
+ * Do not put the connection back to the read ready poll list
+ * if the operation is unbind. Unbind will close the socket.
+ * Similarly, if we are in turbo mode, don't send the socket
+ * back to the poll set.
+ * more_data: [blackflag 624234]
+ */
+ if (tag != LDAP_REQ_UNBIND && (!thread_turbo_flag) && !more_data) {
+ connection_make_readable(conn);
+ }
+
+ /* are we in referral-only mode? */
+ if (config_check_referral_mode() && tag != LDAP_REQ_UNBIND) {
+ referral_mode_reply(pb);
+ goto done;
+ }
+
+ /* check if new password is required */
+ if(connection_need_new_password(conn, op, pb)) {
+ goto done;
+ }
+
+ /* if this is a bulk import, only "add" and "import done"
+ * are allowed */
+ if (conn->c_flags & CONN_FLAG_IMPORT) {
+ if ((tag != LDAP_REQ_ADD) && (tag != LDAP_REQ_EXTENDED)) {
+ /* no cookie for you. */
+ LDAPDebug(LDAP_DEBUG_ANY, "Attempted operation %d "
+ "from within bulk import\n",
+ tag, 0, 0);
+ slapi_send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL,
+ NULL, 0, NULL);
+ goto done;
+ }
+ }
+
+ /*
+ * Call the do_<operation> function to process this request.
+ */
+ connection_dispatch_operation(conn, op, pb);
+
+done:
+ /*
+ * done with this operation. delete it from the op
+ * queue for this connection, delete the number of
+ * threads devoted to this connection, and see if
+ * there's more work to do right now on this conn.
+ */
+
+ /* number of ops on this connection */
+ PR_AtomicIncrement(&conn->c_opscompleted);
+ /* total number of ops for the server */
+ PR_AtomicIncrement(&ops_completed);
+ /* If this op isn't a persistent search, remove it */
+ if ( !( pb->pb_op->o_flags & OP_FLAG_PS )) {
+ /* delete from connection operation queue & decr refcnt */
+ PR_Lock( conn->c_mutex );
+ connection_remove_operation( conn, op );
+ /* destroying the pblock will cause destruction of the operation
+ * so this must happend before releasing the connection
+ */
+ slapi_pblock_destroy( pb );
+
+ /* If we're in turbo mode, we keep our reference to the connection
+ alive */
+ if (!thread_turbo_flag && !more_data) {
+ connection_release_nolock (conn);
+ }
+ PR_Unlock( conn->c_mutex );
+ }
+ if (1 == is_timedout && !more_data)
+ connection_make_readable(conn);
+ pb = NULL;
+
+ if (!thread_turbo_flag && !more_data) { /* Don't do this in turbo mode */
+ PR_Lock( conn->c_mutex );
+ /* if the threadnumber of now below the maximum, wakeup
+ * the listener thread so that we start polling on this
+ * connection again
+ */
+ /* DBDB I think this code is bogus -- we already signaled the listener above here */
+ if (conn->c_threadnumber == config_get_maxthreadsperconn())
+ need_wakeup = 1;
+ else
+ need_wakeup = 0;
+ conn->c_threadnumber--;
+ PR_Unlock( conn->c_mutex );
+
+ if (need_wakeup)
+ signal_listner();
+ }
+
+
+ } /* while (1) */
+}
+
+/* thread need to hold conn->c_mutex before calling this function */
+int
+connection_activity(Connection *conn)
+{
+ Slapi_PBlock *pb;
+
+ connection_make_new_pb(&pb, conn);
+
+ /* Add pb to the end of the work queue. */
+ add_pb( pb );
+
+ /* Check if exceed the max thread per connection. If so, increment
+ c_pbwait. Otherwise increment the counter and notify the cond. var.
+ there is work to do. */
+
+ if (connection_acquire_nolock (conn) == -1) {
+ LDAPDebug(LDAP_DEBUG_CONNS,
+ "could not acquire lock in connection_activity as conn %d closing fd=%d\n",
+ conn->c_connid,conn->c_sd,0);
+ /* XXX how to handle this error? */
+ /* MAB: 25 Jan 01: let's return on error and pray this won't leak */
+ return (-1);
+ }
+ conn->c_gettingber = 1;
+ conn->c_threadnumber++;
+ PR_Lock( op_thread_lock );
+ counter++;
+ PR_NotifyCondVar( op_thread_cv );
+ PR_Unlock( op_thread_lock );
+
+ if (! config_check_referral_mode()) {
+ PR_AtomicIncrement(&ops_initiated);
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsInOps);
+ }
+ return 0;
+}
+
+/* add_pb(): will add a pb to the end of the global work queue. The work queue
+ is implemented as a singal link list. */
+
+static void
+add_pb( Slapi_PBlock *pb)
+{
+
+ struct Slapi_PBlock_q *new_pb=NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "add_pb \n", 0, 0, 0 );
+
+ new_pb = (struct Slapi_PBlock_q *) slapi_ch_malloc ( sizeof( struct Slapi_PBlock_q ));
+ new_pb->pb = pb;
+ new_pb->next_pb =NULL;
+
+ PR_Lock( pb_q_lock );
+ if (last_pb == NULL) {
+ last_pb = new_pb;
+ first_pb = new_pb;
+ }
+ else {
+ last_pb->next_pb = new_pb;
+ last_pb = new_pb;
+ }
+ PR_Unlock( pb_q_lock );
+}
+
+/* get_pb(): will get a pb from the begining of the work queue, return NULL if
+ the queue is empty.*/
+
+static Slapi_PBlock *
+get_pb()
+{
+
+ struct Slapi_PBlock_q *tmp = NULL;
+ Slapi_PBlock *pb;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "get_pb \n", 0, 0, 0 );
+ PR_Lock( pb_q_lock );
+ if (first_pb == NULL) {
+ PR_Unlock( pb_q_lock );
+ LDAPDebug( LDAP_DEBUG_ANY, "get_pb: the work queue is empty.\n",
+ 0, 0, 0 );
+ return NULL;
+ }
+
+ tmp = first_pb;
+ if ( first_pb == last_pb ) {
+ last_pb = NULL;
+ }
+ first_pb = tmp->next_pb;
+ PR_Unlock( pb_q_lock );
+
+ pb = tmp->pb;
+ /* Free the memory used by the pb found. */
+ free ((char *) tmp);
+
+ return (pb);
+}
+#endif /* LDAP_IOCP */
+
+
+/* Helper functions common to both varieties of connection code: */
+
+/* op_thread_cleanup() : This function is called by daemon thread when it gets
+ the slapd_shutdown signal. It will set op_shutdown to 1 and notify
+ all thread waiting on op_thread_cv to terminate. */
+
+void
+op_thread_cleanup()
+{
+#ifdef _WIN32
+ int i;
+ PRIntervalTime interval;
+ int max_threads = config_get_threadnumber();
+ interval = PR_SecondsToInterval(3);
+#endif
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "slapd shutting down - signaling operation threads\n", 0, 0, 0);
+
+ PR_Lock( op_thread_lock );
+ op_shutdown = 1;
+ PR_NotifyAllCondVar ( op_thread_cv );
+ PR_Unlock( op_thread_lock );
+#ifdef _WIN32
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "slapd shutting down - waiting for %d threads to terminate\n",
+ active_threads, 0, 0 );
+ /* kill off each worker waiting on GetQueuedCompletionStatus */
+ for ( i = 0; i < max_threads; ++ i )
+ {
+ PostQueuedCompletionStatus( completion_port, 0, COMPKEY_DIE ,0);
+ }
+ /* don't sleep: there's no reason to do so here DS_Sleep(interval); */ /* sleep 3 seconds */
+#endif
+}
+
+static void
+connection_add_operation(Connection* conn,Operation* op)
+{
+ Operation **olist= &conn->c_ops;
+ int id= conn->c_opsinitiated++;
+ int connid= conn->c_connid;
+ Operation **tmp;
+
+ /* slapi_ch_stop_recording(); */
+
+ for ( tmp = olist; *tmp != NULL; tmp = &(*tmp)->o_next )
+ ; /* NULL */
+
+ *tmp= op;
+ op->o_opid = id;
+ op->o_connid = connid;
+ /* Call the plugin extension constructors */
+ op->o_extension = factory_create_extension(get_operation_object_type(),op,conn);
+}
+
+/*
+ * Find an Operation on the Connection, and zap it in the butt.
+ * Call this function with conn->c_mutex locked.
+ */
+void
+connection_remove_operation( Connection *conn, Operation *op )
+{
+ Operation **olist= &conn->c_ops;
+ Operation **tmp;
+
+ for ( tmp = olist; *tmp != NULL && *tmp != op; tmp = &(*tmp)->o_next )
+ ; /* NULL */
+
+ if ( *tmp == NULL )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "connection_remove_operation: can't find op %d for conn %d\n",
+ op->o_msgid, conn->c_connid, 0 );
+ }
+ else
+ {
+ *tmp = (*tmp)->o_next;
+ }
+}
+
+
+/*
+ * Return a non-zero value if any operations are pending on conn.
+ * Operation op2ignore is ignored (okay to pass NULL). Typically, op2ignore
+ * is the caller's op (because the caller wants to check if all other
+ * ops are done).
+ * If test_resultsent is non-zero, operations that have already sent
+ * a result to the client are ignored.
+ * Call this function with conn->c_mutex locked.
+ */
+int
+connection_operations_pending( Connection *conn, Operation *op2ignore,
+ int test_resultsent )
+{
+ Operation *op;
+
+ PR_ASSERT( conn != NULL );
+
+ for ( op = conn->c_ops; op != NULL; op = op->o_next ) {
+ if ( op == op2ignore ) {
+ continue;
+ }
+ if ( !test_resultsent || op->o_status != SLAPI_OP_STATUS_RESULT_SENT ) {
+ break;
+ }
+ }
+
+ return( op != NULL );
+}
+
+
+/* Copy the authorization identity from the connection struct into the
+ * operation struct. We do this late, because an operation might start
+ * before authentication is complete, at least on an SSL connection.
+ * We want each operation to get its authorization identity after the
+ * SSL software has had its chance to finish the SSL handshake;
+ * that is, after the first few bytes of the request are received.
+ * In particular, we want the first request from an LDAPS client
+ * to have an authorization identity derived from the initial SSL
+ * handshake.
+ */
+static void
+op_copy_identity(Connection *conn, Operation *op)
+{
+ size_t dnlen;
+ size_t typelen;
+
+ PR_Lock( conn->c_mutex );
+ dnlen= conn->c_dn ? strlen (conn->c_dn) : 0;
+ typelen= conn->c_authtype ? strlen (conn->c_authtype) : 0;
+
+ slapi_sdn_done(&op->o_sdn);
+ slapi_ch_free((void **) &(op->o_authtype));
+ if (dnlen <= 0 && typelen <= 0) {
+ op->o_authtype = NULL;
+ } else {
+ char* id = slapi_ch_malloc (typelen + 1);
+ if (typelen <= 0)
+ id[dnlen+1] = '\0';
+ else
+ memcpy (id, conn->c_authtype, typelen + 1);
+ slapi_sdn_set_dn_byval(&op->o_sdn,conn->c_dn);
+ op->o_authtype = id;
+ }
+ /* XXX We should also copy c_client_cert into *op here; it's
+ * part of the authorization identity. The operation's copy
+ * (not c_client_cert) should be used for access control.
+ */
+
+ /* copy isroot flag as well so root DN privileges are preserved */
+ op->o_isroot = conn->c_isroot;
+ PR_Unlock( conn->c_mutex );
+}
+
+
+static int
+is_ber_too_big(const Connection *conn,unsigned long ber_len)
+{
+ unsigned long maxbersize= config_get_maxbersize();
+ if(ber_len>maxbersize)
+ {
+ log_ber_too_big_error(conn, ber_len, maxbersize);
+ return 1;
+ }
+ return 0;
+}
+
+
+/*
+ * Pass 0 for maxbersize if you do not have it handy. It is also OK to pass
+ * 0 for ber_len, in which case a slightly less informative message is
+ * logged.
+ */
+static void
+log_ber_too_big_error(const Connection *conn, unsigned long ber_len,
+ unsigned long maxbersize)
+{
+ if (0 == maxbersize) {
+ maxbersize= config_get_maxbersize();
+ }
+ if (0 == ber_len) {
+ slapi_log_error( SLAPI_LOG_FATAL, "connection",
+ "conn=%d fd=%d Incoming BER Element was too long, max allowable"
+ " is %ld bytes. Change the nsslapd-maxbersize attribute in"
+ " cn=config to increase.\n",
+ conn->c_connid, conn->c_sd, maxbersize );
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, "connection",
+ "conn=%d fd=%d Incoming BER Element was %ld bytes, max allowable"
+ " is %ld bytes. Change the nsslapd-maxbersize attribute in"
+ " cn=config to increase.\n",
+ conn->c_connid, conn->c_sd, ber_len, maxbersize );
+ }
+}
+
+
+void
+disconnect_server( Connection *conn, int opconnid, int opid, PRErrorCode reason, PRInt32 error )
+{
+ PR_Lock( conn->c_mutex );
+ disconnect_server_nomutex( conn, opconnid, opid, reason, error );
+ PR_Unlock( conn->c_mutex );
+}
+
+static ps_wakeup_all_fn_ptr ps_wakeup_all_fn = NULL;
+
+/*
+ * disconnect_server - close a connection. takes the connection to close,
+ * the connid associated with the operation generating the close (so we
+ * don't accidentally close a connection that's not ours), and the opid
+ * of the operation generating the close (for logging purposes).
+ */
+
+void
+disconnect_server_nomutex( Connection *conn, int opconnid, int opid, PRErrorCode reason, PRInt32 error )
+{
+ if ( ( conn->c_sd != SLAPD_INVALID_SOCKET &&
+ conn->c_connid == opconnid ) && !(conn->c_flags & CONN_FLAG_CLOSING) ) {
+
+ /*
+ * PR_Close must be called before anything else is done because
+ * of NSPR problem on NT which requires that the socket on which
+ * I/O timed out is closed before any other I/O operation is
+ * attempted by the thread.
+ * WARNING : As of today the current code does not fulfill the
+ * requirements above.
+ */
+
+ /* Mark that the socket should be closed on this connection.
+ * We don't want to actually close the socket here, because
+ * the listener thread could be PR_Polling over it right now.
+ * The last thread to stop using the connection will do the closing.
+ */
+ conn->c_flags |= CONN_FLAG_CLOSING;
+ g_decrement_current_conn_count();
+
+ /*
+ * Print the error captured above.
+ */
+ if (error && (EPIPE != error) ) {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d fd=%d closed error %d (%s) - %s\n",
+ conn->c_connid, opid, conn->c_sd, error,
+ slapd_system_strerror(error),
+ slapd_pr_strerror(reason));
+ } else {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d fd=%d closed - %s\n",
+ conn->c_connid, opid, conn->c_sd,
+ slapd_pr_strerror(reason));
+ }
+
+ if (! config_check_referral_mode()) {
+ PR_AtomicDecrement(g_get_global_snmp_vars()->ops_tbl.dsConnections);
+ }
+
+ conn->c_gettingber = 0;
+ connection_abandon_operations( conn );
+
+ if (! config_check_referral_mode()) {
+ /*
+ * If any of the outstanding operations on this
+ * connection were persistent searches, then
+ * ding all the persistent searches to get them
+ * to notice that their operations have been abandoned.
+ */
+ int found_ps = 0;
+ Operation *o;
+
+ for ( o = conn->c_ops; !found_ps && o != NULL; o = o->o_next ) {
+ if ( o->o_flags & OP_FLAG_PS ) {
+ found_ps = 1;
+ }
+ }
+ if ( found_ps ) {
+ if ( NULL == ps_wakeup_all_fn ) {
+ if ( get_entry_point( ENTRY_POINT_PS_WAKEUP_ALL,
+ (caddr_t *)(&ps_wakeup_all_fn )) == 0 ) {
+ (ps_wakeup_all_fn)();
+ }
+ } else {
+ (ps_wakeup_all_fn)();
+ }
+ }
+ }
+ }
+}
+
+void
+connection_abandon_operations( Connection *c )
+{
+ Operation *op;
+ for ( op = c->c_ops; op != NULL; op = op->o_next )
+ {
+ /* abandon the operation only if it is not yet
+ completed (i.e., no result has been sent yet to
+ the client */
+ if ( op->o_status != SLAPI_OP_STATUS_RESULT_SENT ) {
+ op->o_status = SLAPI_OP_STATUS_ABANDONED;
+ }
+ }
+}
diff --git a/ldap/servers/slapd/conntable.c b/ldap/servers/slapd/conntable.c
new file mode 100644
index 00000000..8297971c
--- /dev/null
+++ b/ldap/servers/slapd/conntable.c
@@ -0,0 +1,515 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Connection Table */
+
+#include "fe.h"
+
+Connection_Table *
+connection_table_new(int table_size)
+{
+ Connection_Table *ct;
+ int i = 0;
+
+
+ ct= (Connection_Table*)slapi_ch_calloc( 1, sizeof(Connection_Table) );
+ ct->size= table_size;
+ ct->c = (Connection *)slapi_ch_calloc( 1, table_size * sizeof(Connection) );
+ ct->fd = (struct POLL_STRUCT *)slapi_ch_calloc(1, table_size * sizeof(struct POLL_STRUCT));
+ ct->table_mutex = PR_NewLock();
+
+ /* We rely on the fact that we called calloc, which zeros the block, so we don't
+ * init any structure element unless a zero value is troublesome later
+ */
+ for ( i = 0; i < table_size; i++ )
+ {
+ int invalid_socket;
+ unsigned long maxbersize= config_get_maxbersize();
+ /* DBDB---move this out of here once everything works */
+ ct->c[i].c_sb = ber_sockbuf_alloc();
+ invalid_socket = SLAPD_INVALID_SOCKET;
+ ber_sockbuf_set_option( ct->c[i].c_sb, LBER_SOCKBUF_OPT_DESC, &invalid_socket );
+ ct->c[i].c_sd = SLAPD_INVALID_SOCKET;
+ ber_sockbuf_set_option( ct->c[i].c_sb, LBER_SOCKBUF_OPT_NO_READ_AHEAD, LBER_OPT_ON );
+ ber_sockbuf_set_option( ct->c[i].c_sb, LBER_SOCKBUF_OPT_MAX_INCOMING_SIZE, &maxbersize );
+#ifndef _WIN32
+ /* all connections start out invalid */
+ ct->fd[i].fd = SLAPD_INVALID_SOCKET;
+#endif
+ /* The connection table has a double linked list running through it.
+ * This is used to find out which connections should be looked at
+ * in the poll loop. Slot 0 in the table is always the head of
+ * the linked list. Each slot has a c_next and c_prev which are
+ * pointers back into the array of connection slots. */
+ ct->c[i].c_next = NULL;
+ ct->c[i].c_prev = NULL;
+ ct->c[i].c_ci= i;
+ ct->c[i].c_fdi= SLAPD_INVALID_SOCKET_INDEX;
+ }
+ return ct;
+}
+
+void connection_table_free(Connection_Table *ct)
+{
+ int i;
+ for (i = 0; i < ct->size; i++)
+ {
+ /* Free the contents of the connection structure */
+ Connection *c= &(ct->c[i]);
+ connection_done(c);
+ }
+ slapi_ch_free((void**)&ct->c);
+ slapi_ch_free((void**)&ct->fd);
+ PR_DestroyLock(ct->table_mutex);
+ slapi_ch_free((void**)&ct);
+}
+
+
+#ifdef _WIN32
+/*
+ * This function looks up connection by nspr fd. It is
+ * slow because it iterrates through the entire connection
+ * array. Currently, it is only used on NT in secure_read_function
+ * to handle I/O timeout on SSL socket we should almost never
+ * happen.
+ */
+Connection*
+connection_table_get_connection_from_fd(Connection_Table *ct,PRFileDesc *prfd)
+{
+ int i;
+ for (i = 0; i < ct->size; i++)
+ {
+ if (ct->c[i].c_prfd == prfd)
+ {
+ return (&(ct->c[i]));
+ }
+ }
+
+ return NULL;
+}
+#endif
+
+void
+connection_table_abandon_all_operations(Connection_Table *ct)
+{
+ int i;
+ for ( i = 0; i < ct->size; i++ )
+ {
+ if ( ct->c[i].c_mutex != NULL )
+ {
+ PR_Lock( ct->c[i].c_mutex );
+ connection_abandon_operations( &ct->c[i] );
+ PR_Unlock( ct->c[i].c_mutex );
+ }
+ }
+}
+
+/* Given a file descriptor for a socket, this function will return
+ * a slot in the connection table to use.
+ *
+ * Note: this function is only called from the slapd_daemon (listener)
+ * thread, which means it will never be called by two threads at
+ * the same time.
+ *
+ * Returns a Connection on success
+ * Returns NULL on failure
+ */
+Connection *
+connection_table_get_connection(Connection_Table *ct, int sd)
+{
+ Connection *c= NULL;
+ int index, count;
+
+ index = sd % ct->size;
+ for( count = 0; count < ct->size; count++, index = (index + 1) % ct->size)
+ {
+ /* Do not use slot 0, slot 0 is head of the list of active connections */
+ if ( index == 0 )
+ {
+ continue;
+ }
+ else if( ct->c[index].c_mutex == NULL )
+ {
+ break;
+ }
+
+ if( connection_is_free (&(ct->c[index])))
+ {
+ break;
+ }
+ }
+
+ if ( count < ct->size )
+ {
+ /* Found an available Connection */
+ c= &(ct->c[index]);
+ PR_ASSERT(c->c_next==NULL);
+ PR_ASSERT(c->c_prev==NULL);
+ PR_ASSERT(c->c_extension==NULL);
+ if ( c->c_mutex == NULL )
+ {
+ PR_Lock( ct->table_mutex );
+ c->c_mutex = PR_NewLock();
+ c->c_pdumutex = PR_NewLock();
+ PR_Unlock( ct->table_mutex );
+ if ( c->c_mutex == NULL || c->c_pdumutex == NULL )
+ {
+ c->c_mutex = NULL;
+ c->c_pdumutex = NULL;
+ LDAPDebug( LDAP_DEBUG_ANY,"PR_NewLock failed\n",0, 0, 0 );
+ c= NULL;
+ }
+ }
+ /* Let's make sure there's no cruft left on there from the last time this connection was used. */
+ /* Note: no need to lock c->c_mutex because this function is only
+ * called by one thread (the slapd_daemon thread), and if we got this
+ * far then `c' is not being used by any operation threads, etc.
+ */
+ connection_cleanup(c);
+ }
+ else
+ {
+ /* couldn't find a Connection */
+ LDAPDebug( LDAP_DEBUG_CONNS, "max open connections reached\n", 0, 0, 0);
+ }
+ return c;
+}
+
+/* active connection iteration functions */
+
+Connection*
+connection_table_get_first_active_connection (Connection_Table *ct)
+{
+ return ct->c[0].c_next;
+}
+
+Connection*
+connection_table_get_next_active_connection (Connection_Table *ct, Connection *c)
+{
+ return c->c_next;
+}
+
+int connection_table_iterate_active_connections(Connection_Table *ct, void* arg, Connection_Table_Iterate_Function f)
+{
+ /* Locking in this area seems rather undeveloped, I think because typically only one
+ * thread accesses the connection table (daemon thread). But now we allow other threads
+ * to iterate over the table. So we use the "new mutex mutex" to lock the table.
+ */
+ Connection *current_conn = NULL;
+ int ret = 0;
+ PR_Lock(ct->table_mutex);
+ current_conn = connection_table_get_first_active_connection (ct);
+ while (current_conn) {
+ ret = f(current_conn, arg);
+ if (ret) {
+ break;
+ }
+ current_conn = connection_table_get_next_active_connection (ct, current_conn);
+ }
+ PR_Unlock(ct->table_mutex);
+ return ret;
+}
+
+static void
+connection_table_dump_active_connection (Connection *c)
+{
+ slapi_log_error(SLAPI_LOG_FATAL, "connection", "conn=%p fd=%d refcnt=%d c_flags=%d\n"
+ "mutex=%p next=%p prev=%p\n\n", c, c->c_sd, c->c_refcnt, c->c_flags,
+ c->c_mutex, c->c_next, c->c_prev);
+}
+
+static void
+connection_table_dump_active_connections (Connection_Table *ct)
+{
+ Connection* c;
+
+ PR_Lock(ct->table_mutex);
+ slapi_log_error(SLAPI_LOG_FATAL, "connection", "********** BEGIN DUMP ************\n");
+ c = connection_table_get_first_active_connection (ct);
+ while (c)
+ {
+ connection_table_dump_active_connection (c);
+ c = connection_table_get_next_active_connection (ct, c);
+ }
+
+ slapi_log_error(SLAPI_LOG_FATAL, "connection", "********** END DUMP ************\n");
+ PR_Unlock(ct->table_mutex);
+}
+
+/*
+ * There's a double linked list of active connections running through the array
+ * of connections. This function removes a connection (by index) from that
+ * list. This list is used to find the connections that should be used in the
+ * poll call.
+ */
+void
+connection_table_move_connection_out_of_active_list(Connection_Table *ct,Connection *c)
+{
+ /* we always have previous element because list contains a dummy header */;
+ PR_ASSERT (c->c_prev);
+
+ /* slapi_log_error(SLAPI_LOG_FATAL, "connection", "Moving connection out of active list\n");
+ connection_table_dump_active_connection (c);*/
+
+ /*
+ * Note: the connection will NOT be moved off the active list if any other threads still hold
+ * a reference to the connection (that is, its reference count must be 1 or less).
+ */
+ if(c->c_refcnt > 1) return;
+
+ /* We need to lock here because we're modifying the linked list */
+ PR_Lock(ct->table_mutex);
+
+ c->c_prev->c_next = c->c_next;
+
+ if (c->c_next)
+ {
+ c->c_next->c_prev = c->c_prev;
+ }
+
+ connection_release_nolock (c);
+
+ connection_cleanup (c);
+
+ PR_Unlock(ct->table_mutex);
+
+ /* connection_table_dump_active_connections (ct); */
+}
+
+/*
+ * There's a double linked list of active connections running through the array
+ * of connections. This function adds a connection (by index) to the head of
+ * that list. This list is used to find the connections that should be used in the
+ * poll call.
+ */
+void
+connection_table_move_connection_on_to_active_list(Connection_Table *ct,Connection *c)
+{
+ PR_ASSERT(c->c_next==NULL);
+ PR_ASSERT(c->c_prev==NULL);
+
+ PR_Lock(ct->table_mutex);
+
+ connection_acquire_nolock (c);
+
+ /* slapi_log_error(SLAPI_LOG_FATAL, "connection", "Moving connection into active list\n");
+ connection_table_dump_active_connection (c);*/
+
+ c->c_next = ct->c[0].c_next;
+ if ( c->c_next != NULL )
+ {
+ c->c_next->c_prev = c;
+ }
+ c->c_prev = &(ct->c[0]);
+ ct->c[0].c_next = c;
+
+ PR_Unlock(ct->table_mutex);
+
+ /* connection_table_dump_active_connections (ct); */
+}
+
+/*
+ * Replace the following attributes within the entry 'e' with
+ * information about the connection table:
+ * connection // multivalued; one value for each active connection
+ * currentconnections // single valued; an integer count
+ * totalconnections // single valued; an integer count
+ * dtablesize // single valued; an integer size
+ * readwaiters // single valued; an integer count
+ */
+void
+connection_table_as_entry(Connection_Table *ct, Slapi_Entry *e)
+{
+ char buf[BUFSIZ];
+ struct berval val;
+ struct berval *vals[2];
+ int i, nconns, nreadwaiters;
+ struct tm utm;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ attrlist_delete( &e->e_attrs, "connection");
+ nconns = 0;
+ nreadwaiters = 0;
+ for ( i = 0; i < (ct!=NULL?ct->size:0); i++ )
+ {
+ PR_Lock( ct->table_mutex );
+ if ( (ct->c[i].c_mutex == NULL) || (ct->c[i].c_mutex == (PRLock*)-1) )
+ {
+ PR_Unlock( ct->table_mutex );
+ continue;
+ }
+ /* Can't take c_mutex if holding table_mutex; temporarily unlock */
+ PR_Unlock( ct->table_mutex );
+
+ PR_Lock( ct->c[i].c_mutex );
+ if ( ct->c[i].c_sd != SLAPD_INVALID_SOCKET )
+ {
+ char buf2[20];
+ int lendn = ct->c[i].c_dn ? strlen(ct->c[i].c_dn) : 6; /* "NULLDN" */
+ char *bufptr = &buf[0];
+ char *newbuf = NULL;
+
+ nconns++;
+ if ( ct->c[i].c_gettingber )
+ {
+ nreadwaiters++;
+ }
+
+#ifdef _WIN32
+ {
+ struct tm *pt;
+ pt = gmtime( &ct->c[i].c_starttime );
+ memcpy(&utm, pt, sizeof(struct tm) );
+ }
+#else
+ gmtime_r( &ct->c[i].c_starttime, &utm );
+#endif
+ strftime( buf2, sizeof(buf2), "%Y%m%d%H%M%SZ", &utm );
+
+ if (lendn > (BUFSIZ - 46)) {
+ /*
+ * 46 = 4 for the "i" couter + 20 for buf2 +
+ * 10 for c_opsinitiated + 10 for c_opscompleted +
+ * 1 for c_gettingber + 1
+ */
+ newbuf = (char *) slapi_ch_malloc(lendn + 46);
+ bufptr = newbuf;
+ }
+
+ sprintf( bufptr, "%d:%s:%d:%d:%s%s:%s", i,
+ buf2,
+ ct->c[i].c_opsinitiated,
+ ct->c[i].c_opscompleted,
+ ct->c[i].c_gettingber ? "r" : "",
+ "",
+ ct->c[i].c_dn ? ct->c[i].c_dn : "NULLDN" );
+ val.bv_val = bufptr;
+ val.bv_len = strlen( bufptr );
+ attrlist_merge( &e->e_attrs, "connection", vals );
+ if (newbuf) {
+ slapi_ch_free((void **) &newbuf);
+ }
+ }
+ PR_Unlock( ct->c[i].c_mutex );
+ }
+
+ sprintf( buf, "%d", nconns );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "currentconnections", vals );
+
+ PR_Lock( num_conns_mutex );
+ sprintf( buf, "%d", num_conns );
+ PR_Unlock( num_conns_mutex );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "totalconnections", vals );
+
+ sprintf( buf, "%d", (ct!=NULL?ct->size:0) );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "dtablesize", vals );
+
+ sprintf( buf, "%d", nreadwaiters );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "readwaiters", vals );
+}
+
+void
+connection_table_dump_activity_to_errors_log(Connection_Table *ct)
+{
+ int i;
+ for ( i = 0; i < ct->size; i++ )
+ {
+ Connection *c= &(ct->c[i]);
+ if ( c->c_mutex != NULL )
+ {
+ /* Find the connection we are referring to */
+ int j= c->c_fdi;
+ PR_Lock( c->c_mutex );
+ if ( c->c_sd != SLAPD_INVALID_SOCKET && c->c_prfd == ct->fd[j].fd )
+ {
+ int r = ct->fd[j].out_flags & SLAPD_POLL_FLAGS;
+ if ( r )
+ {
+ LDAPDebug( LDAP_DEBUG_CONNS,"activity on %d%s\n", i, r ? "r" : "",0 );
+ }
+ }
+ PR_Unlock( c->c_mutex );
+ }
+ }
+}
+
+#if 0
+void dump_op_list(FILE *file, Operation *op);
+
+void
+connection_table_dump(Connection_Table *ct)
+{
+ FILE *file;
+
+ file = fopen("/tmp/slapd.conn", "a+");
+ if (file != NULL)
+ {
+ int i;
+ fprintf(file, "=============pid=%d==================\n", getpid());
+ for ( i = 0; i < ct->size; i++ )
+ {
+ if ( (ct->c[i].c_sd == SLAPD_INVALID_SOCKET) && (ct->c[i].c_connid == 0) )
+ {
+ continue;
+ }
+ fprintf(file, "c[%d].c_dn=0x%x\n", i, ct->c[i].c_dn);
+ dump_op_list(file, ct->c[i].c_ops);
+ fprintf(file, "c[%d].c_sb.sb_sd=%d\n", i, ct->c[i].c_sd);
+ fprintf(file, "c[%d].c_connid=%d\n", i, ct->c[i].c_connid);
+ fprintf(file, "c[%d].c_opsinitiated=%d\n", i, ct->c[i].c_opsinitiated);
+ fprintf(file, "c[%d].c_opscompleted=%d\n", i, ct->c[i].c_opscompleted);
+ }
+ fclose(file);
+ }
+}
+
+static const char *
+op_status2str( int o_status )
+{
+ const char *s = "unknown";
+
+ switch( o_status ) {
+ case SLAPI_OP_STATUS_PROCESSING:
+ s = "processing";
+ break;
+ case SLAPI_OP_STATUS_ABANDONED:
+ s = "abandoned";
+ break;
+ case SLAPI_OP_STATUS_WILL_COMPLETE:
+ s = "will_complete";
+ break;
+ case SLAPI_OP_STATUS_RESULT_SENT:
+ s = "result_sent";
+ break;
+ }
+
+ return s;
+}
+
+void
+dump_op_list(FILE *file, Operation *op)
+{
+ Operation *tmp;
+
+ for ( tmp = op; tmp != NULL; tmp = tmp->o_next )
+ {
+ fprintf(file,
+ "(o_msgid=%d, o_tag=%d, o_sdn=0x%x, o_opid=%d, o_connid=%d, o_status=%s)\n",
+ tmp->o_msgid, tmp->o_tag, slapi_sdn_get_dn(&tmp->o_sdn), tmp->o_connid,
+ *tmp->o_tid, op_status2str( tmp->o_status ));
+ }
+}
+#endif /* 0 */
+
diff --git a/ldap/servers/slapd/control.c b/ldap/servers/slapd/control.c
new file mode 100644
index 00000000..012d3d4c
--- /dev/null
+++ b/ldap/servers/slapd/control.c
@@ -0,0 +1,592 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* control.c - routines for dealing with LDAPMessage controls */
+
+#include <stdio.h>
+#include "slap.h"
+
+
+/*
+ * static variables used to track information about supported controls.
+ * supported_controls is a NULL-terminated array of OIDs.
+ * supported_controls_ops is an array of bitmaps that hold SLAPI_OPERATION_*
+ * flags that specify the operation(s) for which a control is supported.
+ * The elements in the supported_controls_ops array align with the ones
+ * in the supported_controls array.
+ */
+static char **supported_controls = NULL;
+static unsigned long *supported_controls_ops = NULL;
+static int supported_controls_count = 0;
+static PRRWLock *supported_controls_lock = NULL;
+
+/*
+ * Register all of the LDAPv3 controls we know about "out of the box."
+ */
+void
+init_controls( void )
+{
+ supported_controls_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE,
+ "supported controls rwlock");
+ if (NULL == supported_controls_lock) {
+ /* Out of resources */
+ slapi_log_error(SLAPI_LOG_FATAL, "startup",
+ "init_controls: failed to create lock.\n");
+ exit (1);
+ }
+
+ slapi_register_supported_control( LDAP_CONTROL_MANAGEDSAIT,
+ SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE
+ | SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE
+ | SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN );
+ slapi_register_supported_control( LDAP_CONTROL_PERSISTENTSEARCH,
+ SLAPI_OPERATION_SEARCH );
+ slapi_register_supported_control( LDAP_CONTROL_PWEXPIRED,
+ SLAPI_OPERATION_NONE );
+ slapi_register_supported_control( LDAP_CONTROL_PWEXPIRING,
+ SLAPI_OPERATION_NONE );
+ slapi_register_supported_control( LDAP_CONTROL_SORTREQUEST,
+ SLAPI_OPERATION_SEARCH );
+ slapi_register_supported_control( LDAP_CONTROL_VLVREQUEST,
+ SLAPI_OPERATION_SEARCH );
+ slapi_register_supported_control( LDAP_CONTROL_AUTH_REQUEST,
+ SLAPI_OPERATION_BIND );
+ slapi_register_supported_control( LDAP_CONTROL_AUTH_RESPONSE,
+ SLAPI_OPERATION_NONE );
+ slapi_register_supported_control( LDAP_CONTROL_REAL_ATTRS_ONLY,
+ SLAPI_OPERATION_SEARCH );
+ slapi_register_supported_control( LDAP_CONTROL_VIRT_ATTRS_ONLY,
+ SLAPI_OPERATION_SEARCH );
+ slapi_register_supported_control( LDAP_X_CONTROL_PWPOLICY_REQUEST,
+ SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE
+ | SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE
+ | SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN );
+ slapi_register_supported_control( LDAP_X_CONTROL_PWPOLICY_RESPONSE,
+ SLAPI_OPERATION_SEARCH | SLAPI_OPERATION_COMPARE
+ | SLAPI_OPERATION_ADD | SLAPI_OPERATION_DELETE
+ | SLAPI_OPERATION_MODIFY | SLAPI_OPERATION_MODDN );
+ slapi_register_supported_control( LDAP_CONTROL_GET_EFFECTIVE_RIGHTS,
+ SLAPI_OPERATION_SEARCH );
+}
+
+
+/*
+ * register a supported control so it can be returned as part of the root DSE.
+ */
+void
+slapi_register_supported_control( char *controloid, unsigned long controlops )
+{
+ if ( controloid != NULL ) {
+ PR_RWLock_Wlock(supported_controls_lock);
+ ++supported_controls_count;
+ charray_add( &supported_controls,
+ slapi_ch_strdup( controloid ));
+ supported_controls_ops = (unsigned long *)slapi_ch_realloc(
+ (char *)supported_controls_ops,
+ supported_controls_count * sizeof( unsigned long ));
+ supported_controls_ops[ supported_controls_count - 1 ] =
+ controlops;
+ PR_RWLock_Unlock(supported_controls_lock);
+ }
+}
+
+
+/*
+ * retrieve supported controls OID and/or operations arrays.
+ * return 0 if successful and -1 if not.
+ * This function is not MTSafe and should be deprecated.
+ * slapi_get_supported_controls_copy should be used instead.
+ */
+int
+slapi_get_supported_controls( char ***ctrloidsp, unsigned long **ctrlopsp )
+{
+ if ( ctrloidsp != NULL ) {
+ *ctrloidsp = supported_controls;
+ }
+ if ( ctrlopsp != NULL ) {
+ *ctrlopsp = supported_controls_ops;
+ }
+
+ return( 0 );
+}
+
+
+static
+unsigned long *supported_controls_ops_dup(unsigned long *ctrlops)
+{
+ int i;
+ unsigned long *dup_ops = (unsigned long *)slapi_ch_calloc(
+ supported_controls_count + 1, sizeof( unsigned long ));
+ if (NULL != dup_ops) {
+ for (i=0; i < supported_controls_count; i++)
+ dup_ops[i] = supported_controls_ops[i];
+ }
+ return dup_ops;
+}
+
+
+int slapi_get_supported_controls_copy( char ***ctrloidsp, unsigned long **ctrlopsp )
+{
+ PR_RWLock_Rlock(supported_controls_lock);
+ if ( ctrloidsp != NULL ) {
+ *ctrloidsp = charray_dup(supported_controls);
+ }
+ if ( ctrlopsp != NULL ) {
+ *ctrlopsp = supported_controls_ops_dup(supported_controls_ops);
+ }
+ PR_RWLock_Unlock(supported_controls_lock);
+ return (0);
+}
+
+
+int
+get_ldapmessage_controls(
+ Slapi_PBlock *pb,
+ BerElement *ber,
+ LDAPControl ***controlsp /* can be NULL if no need to return */
+)
+{
+ LDAPControl **ctrls, *new;
+ unsigned long tag, len;
+ int rc, maxcontrols, curcontrols;
+ char *last;
+ int managedsait, pwpolicy_ctrl;
+
+ /*
+ * Each LDAPMessage can have a set of controls appended
+ * to it. Controls are used to extend the functionality
+ * of an LDAP operation (e.g., add an attribute size limit
+ * to the search operation). These controls look like this:
+ *
+ * Controls ::= SEQUENCE OF Control
+ *
+ * Control ::= SEQUENCE {
+ * controlType LDAPOID,
+ * criticality BOOLEAN DEFAULT FALSE,
+ * controlValue OCTET STRING
+ * }
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> get_ldapmessage_controls\n", 0, 0, 0 );
+
+ ctrls = NULL;
+ slapi_pblock_set( pb, SLAPI_REQCONTROLS, ctrls );
+ if ( controlsp != NULL ) {
+ *controlsp = NULL;
+ }
+ rc = LDAP_PROTOCOL_ERROR; /* most popular error we may return */
+
+ /*
+ * check to see if controls were included
+ */
+ if ( ber_get_option( ber, LBER_OPT_REMAINING_BYTES, &len ) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= get_ldapmessage_controls LDAP_OPERATIONS_ERROR\n",
+ 0, 0, 0 );
+ return( LDAP_OPERATIONS_ERROR ); /* unexpected error */
+ }
+ if ( len == 0 ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= get_ldapmessage_controls no controls\n", 0, 0, 0 );
+ return( LDAP_SUCCESS ); /* no controls */
+ }
+ if (( tag = ber_peek_tag( ber, &len )) != LDAP_TAG_CONTROLS ) {
+ if ( tag == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= get_ldapmessage_controls LDAP_PROTOCOL_ERROR\n",
+ 0, 0, 0 );
+ return( LDAP_PROTOCOL_ERROR ); /* decoding error */
+ }
+ /*
+ * We found something other than controls. This should never
+ * happen in LDAPv3, but we don't treat this is a hard error --
+ * we just ignore the extra stuff.
+ */
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= get_ldapmessage_controls ignoring unrecognized data in request (tag 0x%x)\n",
+ tag, 0, 0 );
+ return( LDAP_SUCCESS );
+ }
+
+ /*
+ * A sequence of controls is present. If connection is not LDAPv3
+ * or better, return a protocol error. Otherwise, parse the controls.
+ */
+ if ( pb != NULL && pb->pb_conn != NULL
+ && pb->pb_conn->c_ldapversion < LDAP_VERSION3 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, "connection",
+ "received control(s) on an LDAPv%d connection\n",
+ pb->pb_conn->c_ldapversion );
+ return( LDAP_PROTOCOL_ERROR );
+ }
+
+ maxcontrols = curcontrols = 0;
+ for ( tag = ber_first_element( ber, &len, &last );
+ tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element( ber, &len, last ) ) {
+ if ( curcontrols >= maxcontrols - 1 ) {
+#define CONTROL_GRABSIZE 6
+ maxcontrols += CONTROL_GRABSIZE;
+ ctrls = (LDAPControl **) slapi_ch_realloc( (char *)ctrls,
+ maxcontrols * sizeof(LDAPControl *) );
+ }
+ new = (LDAPControl *) slapi_ch_calloc( 1, sizeof(LDAPControl) );
+ ctrls[curcontrols++] = new;
+ ctrls[curcontrols] = NULL;
+
+ if ( ber_scanf( ber, "{a", &new->ldctl_oid ) == LBER_ERROR ) {
+ goto free_and_return;
+ }
+
+ /* the criticality is optional */
+ if ( ber_peek_tag( ber, &len ) == LBER_BOOLEAN ) {
+ if ( ber_scanf( ber, "b", &new->ldctl_iscritical )
+ == LBER_ERROR ) {
+ goto free_and_return;
+ }
+ } else {
+ /* absent is synonomous with FALSE */
+ new->ldctl_iscritical = 0;
+ }
+
+ /*
+ * return an appropriate error if this control is marked
+ * critical and either:
+ * a) we do not support it at all OR
+ * b) it is not supported for this operation
+ */
+ if ( new->ldctl_iscritical ) {
+ int i;
+
+ PR_RWLock_Rlock(supported_controls_lock);
+ for ( i = 0; supported_controls != NULL
+ && supported_controls[i] != NULL; ++i ) {
+ if ( strcmp( supported_controls[i],
+ new->ldctl_oid ) == 0 ) {
+ break;
+ }
+ }
+
+ if ( supported_controls == NULL ||
+ supported_controls[i] == NULL ||
+ ( 0 == ( supported_controls_ops[i] &
+ operation_get_type(pb->pb_op) ))) {
+ rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ PR_RWLock_Unlock(supported_controls_lock);
+ goto free_and_return;
+ }
+ PR_RWLock_Unlock(supported_controls_lock);
+ }
+
+ /* the control value is optional */
+ if ( ber_peek_tag( ber, &len ) == LBER_OCTETSTRING ) {
+ if ( ber_scanf( ber, "o", &new->ldctl_value )
+ == LBER_ERROR ) {
+ goto free_and_return;
+ }
+ } else {
+ (new->ldctl_value).bv_val = NULL;
+ (new->ldctl_value).bv_len = 0;
+ }
+ }
+
+ if ( tag == LBER_ERROR ) {
+ goto free_and_return;
+ }
+
+ slapi_pblock_set( pb, SLAPI_REQCONTROLS, ctrls );
+ managedsait = slapi_control_present( ctrls,
+ LDAP_CONTROL_MANAGEDSAIT, NULL, NULL );
+ slapi_pblock_set( pb, SLAPI_MANAGEDSAIT, &managedsait );
+ pwpolicy_ctrl = slapi_control_present( ctrls,
+ LDAP_X_CONTROL_PWPOLICY_REQUEST, NULL, NULL );
+ slapi_pblock_set( pb, SLAPI_PWPOLICY, &pwpolicy_ctrl );
+
+ if ( controlsp != NULL ) {
+ *controlsp = ctrls;
+ }
+
+#ifdef SLAPD_ECHO_CONTROL
+ /*
+ * XXXmcs: Start of hack: if a control with OID "1.1" was sent by
+ * the client, echo all controls back to the client unchanged. Note
+ * that this is just a hack to test control handling in libldap and
+ * should be removed once we support all interesting controls.
+ */
+ if ( slapi_control_present( ctrls, "1.1", NULL, NULL )) {
+ int i;
+
+ for ( i = 0; ctrls[i] != NULL; ++i ) {
+ slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL,
+ (void *)ctrls[i] );
+ }
+ }
+#endif /* SLAPD_ECHO_CONTROL */
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= get_ldapmessage_controls %d controls\n", curcontrols, 0, 0 );
+ return( LDAP_SUCCESS );
+
+free_and_return:;
+ ldap_controls_free( ctrls );
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= get_ldapmessage_controls %i\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+int
+slapi_control_present( LDAPControl **controls, char *oid, struct berval **val, int *iscritical )
+{
+ int i;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "=> slapi_control_present (looking for %s)\n", oid, 0, 0 );
+
+ if ( val != NULL ) {
+ *val = NULL;
+ }
+
+ if ( controls == NULL ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= slapi_control_present 0 (NO CONTROLS)\n", 0, 0, 0 );
+ return( 0 );
+ }
+
+ for ( i = 0; controls[i] != NULL; i++ ) {
+ if ( strcmp( controls[i]->ldctl_oid, oid ) == 0 ) {
+ if ( val != NULL ) {
+ if (NULL != val) {
+ *val = &controls[i]->ldctl_value;
+ }
+ if (NULL != iscritical) {
+ *iscritical = (int) controls[i]->ldctl_iscritical;
+ }
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= slapi_control_present 1 (FOUND)\n", 0, 0, 0 );
+ return( 1 );
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= slapi_control_present 0 (NOT FOUND)\n", 0, 0, 0 );
+ return( 0 );
+}
+
+
+/*
+ * Write sequence of controls in "ctrls" to "ber".
+ * Return zero on success and -1 if an error occurs.
+ */
+int
+write_controls( BerElement *ber, LDAPControl **ctrls )
+{
+ int i;
+ unsigned long rc;
+
+ rc= ber_start_seq( ber, LDAP_TAG_CONTROLS );
+ if ( rc == LBER_ERROR ) {
+ return( -1 );
+ }
+
+ /* if the criticality is false, it should be absent from the encoding */
+ for ( i = 0; ctrls[ i ] != NULL; ++i ) {
+ if ( ctrls[ i ]->ldctl_value.bv_val == 0 ) {
+ if ( ctrls[ i ]->ldctl_iscritical ) {
+ rc = ber_printf( ber, "{sb}", ctrls[ i ]->ldctl_oid,
+ ctrls[ i ]->ldctl_iscritical );
+ } else {
+ rc = ber_printf( ber, "{s}", ctrls[ i ]->ldctl_oid );
+ }
+ } else {
+ if ( ctrls[ i ]->ldctl_iscritical ) {
+ rc = ber_printf( ber, "{sbo}", ctrls[ i ]->ldctl_oid,
+ ctrls[ i ]->ldctl_iscritical,
+ ctrls[ i ]->ldctl_value.bv_val,
+ ctrls[ i ]->ldctl_value.bv_len );
+ } else {
+ rc = ber_printf( ber, "{so}", ctrls[ i ]->ldctl_oid,
+ ctrls[ i ]->ldctl_value.bv_val,
+ ctrls[ i ]->ldctl_value.bv_len );
+ }
+ }
+ if ( rc == LBER_ERROR ) {
+ return( -1 );
+ }
+ }
+
+ rc= ber_put_seq( ber );
+ if ( rc == LBER_ERROR ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * duplicate "newctrl" and add it to the array of controls "*ctrlsp"
+ * note that *ctrlsp may be reset and that it is okay to pass NULL for it.
+ */
+void
+add_control( LDAPControl ***ctrlsp, LDAPControl *newctrl )
+{
+ int count;
+
+ if ( *ctrlsp == NULL ) {
+ count = 0;
+ } else {
+ for ( count = 0; (*ctrlsp)[count] != NULL; ++count ) {
+ ;
+ }
+ }
+
+ *ctrlsp = (LDAPControl **)slapi_ch_realloc( (char *)*ctrlsp,
+ ( count + 2 ) * sizeof(LDAPControl *));
+
+ (*ctrlsp)[ count ] = slapi_dup_control( newctrl );
+ (*ctrlsp)[ ++count ] = NULL;
+}
+
+
+/*
+ * return a malloc'd copy of "ctrl"
+ */
+LDAPControl *
+slapi_dup_control( LDAPControl *ctrl )
+{
+ LDAPControl *rctrl;
+
+ rctrl = (LDAPControl *)slapi_ch_malloc( sizeof( LDAPControl ));
+
+ rctrl->ldctl_oid = slapi_ch_strdup( ctrl->ldctl_oid );
+ rctrl->ldctl_iscritical = ctrl->ldctl_iscritical;
+
+ if ( ctrl->ldctl_value.bv_val == NULL ) { /* no value */
+ rctrl->ldctl_value.bv_len = 0;
+ rctrl->ldctl_value.bv_val = NULL;
+ } else if ( ctrl->ldctl_value.bv_len <= 0 ) { /* zero length value */
+ rctrl->ldctl_value.bv_len = 0;
+ rctrl->ldctl_value.bv_val = slapi_ch_malloc( 1 );
+ rctrl->ldctl_value.bv_val[0] = '\0';
+ } else { /* value with content */
+ rctrl->ldctl_value.bv_len = ctrl->ldctl_value.bv_len;
+ rctrl->ldctl_value.bv_val =
+ slapi_ch_malloc( ctrl->ldctl_value.bv_len );
+ memcpy( rctrl->ldctl_value.bv_val, ctrl->ldctl_value.bv_val,
+ ctrl->ldctl_value.bv_len );
+ }
+
+ return( rctrl );
+}
+
+
+int
+slapi_build_control( char *oid, BerElement *ber,
+ char iscritical, LDAPControl **ctrlp )
+{
+ int rc = 0;
+ int return_value = LDAP_SUCCESS;
+ struct berval *bvp = NULL;
+
+ PR_ASSERT( NULL != oid && NULL != ctrlp );
+
+ if ( NULL == ber ) {
+ bvp = NULL;
+ } else {
+ /* allocate struct berval with contents of the BER encoding */
+ rc = ber_flatten( ber, &bvp );
+ if ( -1 == rc ) {
+ return_value = LDAP_NO_MEMORY;
+ goto loser;
+ }
+ }
+
+ /* allocate the new control structure */
+ *ctrlp = (LDAPControl *)slapi_ch_calloc( 1, sizeof(LDAPControl));
+
+ /* fill in the fields of this new control */
+ (*ctrlp)->ldctl_iscritical = iscritical;
+ (*ctrlp)->ldctl_oid = slapi_ch_strdup( oid );
+ if ( NULL == bvp ) {
+ (*ctrlp)->ldctl_value.bv_len = 0;
+ (*ctrlp)->ldctl_value.bv_val = NULL;
+ } else {
+ (*ctrlp)->ldctl_value = *bvp; /* struct copy */
+ ldap_memfree(bvp); /* free container, but not contents */
+ bvp = NULL;
+ }
+
+loser:
+ return return_value;
+}
+
+
+#if 0
+/*
+ * rbyrne: This is version of the above using the slapi_build_control_from_berval()
+ * I'll enable this afterwards.
+ * Build an allocated LDAPv3 control from a BerElement.
+ * Returns an LDAP error code.
+ */
+int
+slapi_build_control( char *oid, BerElement *ber,
+ char iscritical, LDAPControl **ctrlp )
+{
+ int rc = 0;
+ int return_value = LDAP_SUCCESS;
+ struct berval *bvp = NULL;
+
+ PR_ASSERT( NULL != oid && NULL != ctrlp );
+
+ if ( NULL == ber ) {
+ bvp = NULL;
+ } else {
+ /* allocate struct berval with contents of the BER encoding */
+ rc = ber_flatten( ber, &bvp );
+ if ( -1 == rc ) {
+ return_value = LDAP_NO_MEMORY;
+ goto loser;
+ }
+ }
+
+ return_value = slapi_build_control_from_berval( oid, bvp, iscritical,
+ ctrlp);
+ if ( bvp != NULL ) {
+ ldap_memfree(bvp); /* free container, but not contents */
+ bvp = NULL;
+ }
+
+loser:
+ return return_value;
+}
+#endif
+
+/*
+ * Build an allocated LDAPv3 control from a berval. Returns an LDAP error code.
+ */
+int
+slapi_build_control_from_berval( char *oid, struct berval *bvp,
+ char iscritical, LDAPControl **ctrlp )
+{
+ int return_value = LDAP_SUCCESS;
+
+ /* allocate the new control structure */
+ *ctrlp = (LDAPControl *)slapi_ch_calloc( 1, sizeof(LDAPControl));
+
+ /* fill in the fields of this new control */
+ (*ctrlp)->ldctl_iscritical = iscritical;
+ (*ctrlp)->ldctl_oid = slapi_ch_strdup( oid );
+ if ( NULL == bvp ) {
+ (*ctrlp)->ldctl_value.bv_len = 0;
+ (*ctrlp)->ldctl_value.bv_val = NULL;
+ } else {
+ (*ctrlp)->ldctl_value = *bvp; /* struct copy */
+ }
+
+ return return_value;
+}
+
diff --git a/ldap/servers/slapd/counters.c b/ldap/servers/slapd/counters.c
new file mode 100644
index 00000000..f9875790
--- /dev/null
+++ b/ldap/servers/slapd/counters.c
@@ -0,0 +1,151 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <prcountr.h>
+#include "slap.h"
+
+#if defined(DEBUG)
+struct counter
+{
+ const char *qname;
+ const char *rname;
+ const char *description;
+ PRUint32 before_counter;
+ PRUint32 after_counter;
+};
+
+static int num_counters= 0;
+static struct counter *counters= NULL;
+
+static int
+count_counters()
+{
+ int i= 0;
+ PR_DEFINE_COUNTER(qh);
+ PR_INIT_COUNTER_HANDLE(qh,NULL);
+ PR_FIND_NEXT_COUNTER_QNAME(qh,qh);
+ while(qh!=NULL)
+ {
+ PR_DEFINE_COUNTER(rh);
+ PR_INIT_COUNTER_HANDLE(rh,NULL);
+ PR_FIND_NEXT_COUNTER_RNAME(rh,rh,qh);
+ while(rh!=NULL)
+ {
+ i++;
+ PR_FIND_NEXT_COUNTER_RNAME(rh,rh,qh);
+ }
+ PR_FIND_NEXT_COUNTER_QNAME(qh,qh);
+ }
+ return i;
+}
+
+static int
+do_fetch_counters()
+{
+ int i= 0;
+ PR_DEFINE_COUNTER(qh);
+ PR_INIT_COUNTER_HANDLE(qh,NULL);
+ PR_FIND_NEXT_COUNTER_QNAME(qh,qh);
+ while(qh!=NULL)
+ {
+ PR_DEFINE_COUNTER(rh);
+ PR_INIT_COUNTER_HANDLE(rh,NULL);
+ PR_FIND_NEXT_COUNTER_RNAME(rh,rh,qh);
+ while(rh!=NULL)
+ {
+ if(i<num_counters)
+ {
+ counters[i].before_counter= counters[i].after_counter;
+ PR_GET_COUNTER_NAME_FROM_HANDLE(rh,&counters[i].qname,&counters[i].rname,&counters[i].description);
+ PR_GET_COUNTER(counters[i].after_counter,rh);
+ }
+ i++;
+ PR_FIND_NEXT_COUNTER_RNAME(rh,rh,qh);
+ }
+ PR_FIND_NEXT_COUNTER_QNAME(qh,qh);
+ }
+ return i;
+}
+
+static void
+fetch_counters()
+{
+ int i;
+ if(counters==NULL)
+ {
+ num_counters= count_counters();
+ counters= (struct counter*)calloc(num_counters,sizeof(struct counter));
+ }
+ i= do_fetch_counters();
+ if(i>num_counters)
+ {
+ free(counters);
+ counters= NULL;
+ num_counters= i;
+ counters= (struct counter*)calloc(num_counters,sizeof(struct counter));
+ do_fetch_counters();
+ }
+}
+
+static size_t
+counter_size(struct counter *counter)
+{
+ size_t r= 0;
+ r+= (counter->qname?strlen(counter->qname):0);
+ r+= (counter->rname?strlen(counter->rname):0);
+ r+= (counter->description?strlen(counter->description):0);
+ return r;
+}
+
+static void
+counter_dump(char *name, char *value, int i)
+{
+ PRUint32 diff_counter;
+ sprintf(name,"%s_%s_%s",counters[i].qname,counters[i].rname,counters[i].description);
+ diff_counter= counters[i].after_counter-counters[i].before_counter;
+ sprintf(value,"%d -> %d (%s%d)",
+ counters[i].before_counter,
+ counters[i].after_counter,
+ (diff_counter>0?"+":""),
+ diff_counter);
+}
+#endif
+
+void
+counters_as_entry(Slapi_Entry* e)
+{
+#if defined(DEBUG)
+ int i;
+ fetch_counters();
+ for(i=0;i<num_counters;i++)
+ {
+ char value[40];
+ char *type= (char*)malloc(counter_size(&counters[i])+4);
+ counter_dump(type,value,i);
+ slapi_entry_attr_set_charptr( e, type, value);
+ free(type);
+ }
+#endif
+}
+
+
+void
+counters_to_errors_log(const char *text)
+{
+#if defined(DEBUG)
+ int i;
+ fetch_counters();
+ LDAPDebug( LDAP_DEBUG_ANY, "Counter Dump - %s\n",text, 0, 0);
+ for(i=0;i<num_counters;i++)
+ {
+ char value[40];
+ char *type= (char*)malloc(counter_size(&counters[i])+4);
+ counter_dump(type,value,i);
+ LDAPDebug( LDAP_DEBUG_ANY, "%s %s\n",type, value, 0);
+ free(type);
+ }
+#endif
+}
diff --git a/ldap/servers/slapd/csn.c b/ldap/servers/slapd/csn.c
new file mode 100644
index 00000000..30243d88
--- /dev/null
+++ b/ldap/servers/slapd/csn.c
@@ -0,0 +1,383 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * csn.c - CSN
+ */
+
+#include <string.h>
+#include "slap.h"
+#include <prcountr.h>
+
+#define _CSN_TSTAMP_STRSIZE_STR "8"
+#define _CSN_SEQNUM_STRSIZE_STR "4"
+#define _CSN_REPLID_STRSIZE_STR "4"
+#define _CSN_SUBSEQNUM_STRSIZE_STR "4"
+
+#define _CSN_TSTAMP_SCANSTR "%"_CSN_TSTAMP_STRSIZE_STR"lx"
+#define _CSN_SEQNUM_SCANSTR "%"_CSN_SEQNUM_STRSIZE_STR"hx"
+#define _CSN_REPLID_SCANSTR "%"_CSN_REPLID_STRSIZE_STR"hx"
+#define _CSN_SUBSEQNUM_SCANSTR "%"_CSN_SUBSEQNUM_STRSIZE_STR"hx"
+
+#define _CSN_TSORDER_SPRINTSTR "%08x%04x%04x%04x"
+
+#define _CSN_TSORDER_TSTAMP_OFFSET 0
+#define _CSN_TSORDER_SEQNUM_OFFSET 8
+#define _CSN_TSORDER_REPLID_OFFSET 12
+#define _CSN_TSORDER_SUBSEQNUM_OFFSET 16
+
+static PRBool _csnIsValidString(const char *csnStr);
+
+/*
+ * Debugging counters.
+ */
+static int counters_created= 0;
+PR_DEFINE_COUNTER(slapi_csn_counter_created);
+PR_DEFINE_COUNTER(slapi_csn_counter_deleted);
+PR_DEFINE_COUNTER(slapi_csn_counter_exist);
+
+/*
+ * **************************************************************************
+ * CSN Functions
+ * **************************************************************************
+ */
+
+static void
+csn_create_counters()
+{
+ PR_CREATE_COUNTER(slapi_csn_counter_created,"Slapi_CSN","created","");
+ PR_CREATE_COUNTER(slapi_csn_counter_deleted,"Slapi_CSN","deleted","");
+ PR_CREATE_COUNTER(slapi_csn_counter_exist,"Slapi_CSN","exist","");
+ counters_created= 1;
+}
+
+CSN *csn_new()
+{
+ if(!counters_created)
+ {
+ csn_create_counters();
+ }
+ PR_INCREMENT_COUNTER(slapi_csn_counter_created);
+ PR_INCREMENT_COUNTER(slapi_csn_counter_exist);
+ return (CSN*)slapi_ch_calloc(sizeof(CSN),1);
+}
+
+CSN *csn_new_by_string(const char *s)
+{
+ CSN *newcsn= NULL;
+ if(s!=NULL)
+ {
+ if(_csnIsValidString(s))
+ {
+ newcsn= csn_new();
+ csn_init_by_string(newcsn,s);
+ }
+ }
+ return newcsn;
+}
+
+void csn_init(CSN *csn)
+{
+ if(csn!=NULL)
+ {
+ memset(csn,0,sizeof(CSN));
+ }
+}
+
+void csn_init_by_csn(CSN *csn1,const CSN *csn2)
+{
+ if(csn2!=NULL)
+ {
+ memcpy(csn1,csn2,sizeof(CSN));
+ }
+ else
+ {
+ csn_init(csn1);
+ }
+}
+
+void csn_init_by_string(CSN *csn, const char *s)
+{
+ time_t csnTime= 0;
+ PRUint16 csnSeqNum= 0;
+ ReplicaId rid= 0;
+ PRUint16 csnSubSeqNum= 0;
+
+ if(_csnIsValidString(s))
+ {
+ /* JCM - char2hex faster */
+ sscanf((s+_CSN_TSORDER_TSTAMP_OFFSET), _CSN_TSTAMP_SCANSTR, &csnTime); /* JCM - scanf is very slow */
+ sscanf((s+_CSN_TSORDER_SEQNUM_OFFSET), _CSN_SEQNUM_SCANSTR, &csnSeqNum);/* JCM - scanf is very slow */
+ sscanf((s+_CSN_TSORDER_REPLID_OFFSET), _CSN_REPLID_SCANSTR, &rid);/* JCM - scanf is very slow */
+ sscanf((s+_CSN_TSORDER_SUBSEQNUM_OFFSET), _CSN_SUBSEQNUM_SCANSTR, &csnSubSeqNum);/* JCM - scanf is very slow */
+ csn->tstamp= csnTime;
+ csn->seqnum= csnSeqNum;
+ csn->rid= rid;
+ csn->subseqnum= csnSubSeqNum;
+ }
+}
+
+CSN *csn_dup(const CSN *csn)
+{
+ CSN *newcsn= NULL;
+ if(csn!=NULL)
+ {
+ newcsn= csn_new();
+ csn_init_by_csn(newcsn,csn);
+ }
+ return newcsn;
+}
+
+void csn_done(CSN *csn)
+{
+}
+
+void csn_free(CSN **csn)
+{
+ if(csn!=NULL && *csn!=NULL)
+ {
+ if(!counters_created)
+ {
+ csn_create_counters();
+ }
+ PR_INCREMENT_COUNTER(slapi_csn_counter_deleted);
+ PR_DECREMENT_COUNTER(slapi_csn_counter_exist);
+ slapi_ch_free((void **)csn);
+ }
+ return;
+}
+
+void csn_set_replicaid(CSN *csn, ReplicaId rid)
+{
+ csn->rid= rid;
+}
+
+void csn_set_time(CSN *csn, time_t csntime)
+{
+ csn->tstamp= csntime;
+}
+
+void csn_set_seqnum(CSN *csn, PRUint16 seqnum)
+{
+ csn->seqnum= seqnum;
+}
+
+ReplicaId csn_get_replicaid(const CSN *csn)
+{
+ return csn->rid;
+}
+
+PRUint16 csn_get_seqnum(const CSN *csn)
+{
+ return csn->seqnum;
+}
+
+time_t csn_get_time(const CSN *csn)
+{
+ if(csn==NULL)
+ {
+ return 0;
+ }
+ else
+ {
+ return csn->tstamp;
+ }
+}
+
+
+/*
+ * WARNING: ss must point to memory at least CSN_STRSIZE bytes long,
+ * WARNING: or be NULL, which means this function will allocate the
+ * WARNING: memory, which must be free'd by the caller.
+ */
+char *
+csn_as_string(const CSN *csn, PRBool replicaIdOrder, char *ss)
+{
+ char *s= ss;
+ if(s==NULL)
+ {
+ s= slapi_ch_malloc(CSN_STRSIZE);
+ }
+ if(csn==NULL)
+ {
+ s[0]= '\0';
+ }
+ else
+ {
+ /* JCM - hex2char would be quicker */
+ sprintf(s,"%08lx%04x%04x%04x",
+ csn->tstamp,csn->seqnum,csn->rid, csn->subseqnum);
+ }
+ return s;
+}
+
+
+/*
+ * WARNING: ss must point to memory at least (7+CSN_STRSIZE) bytes long,
+ * WARNING: or be NULL, which means this function will allocate the
+ * WARNING: memory, which must be free'd by the caller.
+ */
+char *
+csn_as_attr_option_string(CSNType t,const CSN *csn,char *ss)
+{
+ char *s= ss;
+ if(csn!=NULL)
+ {
+ if(s==NULL)
+ {
+ s= slapi_ch_malloc(8+CSN_STRSIZE);
+ }
+ s[0]= ';';
+ switch(t)
+ {
+ case CSN_TYPE_UNKNOWN:
+ s[1]= 'x';
+ s[2]= '1';
+ break;
+ case CSN_TYPE_NONE:
+ s[1]= 'x';
+ s[2]= '2';
+ break;
+ case CSN_TYPE_ATTRIBUTE_DELETED:
+ s[1]= 'a';
+ s[2]= 'd';
+ break;
+ case CSN_TYPE_VALUE_UPDATED:
+ s[1]= 'v';
+ s[2]= 'u';
+ break;
+ case CSN_TYPE_VALUE_DELETED:
+ s[1]= 'v';
+ s[2]= 'd';
+ break;
+ case CSN_TYPE_VALUE_DISTINGUISHED:
+ s[1]= 'm';
+ s[2]= 'd';
+ break;
+ }
+ s[3]= 'c';
+ s[4]= 's';
+ s[5]= 'n';
+ s[6]= '-';
+ csn_as_string(csn,PR_FALSE,s+7);
+ }
+ return s;
+}
+
+int
+csn_compare(const CSN *csn1, const CSN *csn2)
+{
+ PRInt32 retVal;
+ if(csn1!=NULL && csn2!=NULL)
+ {
+ /* csns can't be compared via memcmp (previuos version of the code)
+ because, on NT, bytes are reversed */
+ if (csn1->tstamp < csn2->tstamp)
+ retVal = -1;
+ else if (csn1->tstamp > csn2->tstamp)
+ retVal = 1;
+ else
+ {
+ if (csn1->seqnum < csn2->seqnum)
+ retVal = -1;
+ else if (csn1->seqnum > csn2->seqnum)
+ retVal = 1;
+ else
+ {
+ if (csn1->rid < csn2->rid)
+ retVal = -1;
+ else if (csn1->rid > csn2->rid)
+ retVal = 1;
+ else
+ {
+ if (csn1->subseqnum < csn2->subseqnum)
+ retVal = -1;
+ else if (csn1->subseqnum > csn2->subseqnum)
+ retVal = 1;
+ else
+ retVal = 0;
+ }
+ }
+ }
+
+ }
+ else if(csn1!=NULL && csn2==NULL)
+ {
+ retVal= 1; /* csn1>csn2 */
+ }
+ else if (csn1==NULL && csn2!=NULL)
+ {
+ retVal= -1; /* csn1<csn2 */
+ }
+ else /* (csn1==NULL && csn2==NULL) */
+ {
+ retVal= 0; /* The same */
+ }
+
+ return(retVal);
+}
+
+time_t csn_time_difference(const CSN *csn1, const CSN *csn2)
+{
+ return csn_get_time(csn1) - csn_get_time(csn2);
+}
+
+const CSN *
+csn_max(const CSN *csn1,const CSN *csn2)
+{
+ if(csn_compare(csn1, csn2)>0)
+ {
+ return csn1;
+ }
+ else
+ {
+ return csn2;
+ }
+}
+
+int csn_increment_subsequence (CSN *csn)
+{
+ if (csn == NULL)
+ {
+ return -1;
+ }
+ else if (csn->subseqnum == 0xFFFFFFFF)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "csn_increment_subsequence: subsequence overflow\n");
+
+ return -1;
+ }
+ else
+ {
+ csn->subseqnum ++;
+ return 0;
+ }
+}
+
+/*
+ * sizeof(vucsn-011111111222233334444)
+ * Does not include the trailing '\0'
+ */
+size_t
+csn_string_size()
+{
+ return LDIF_CSNPREFIX_MAXLENGTH + _CSN_VALIDCSN_STRLEN;
+}
+
+static PRBool
+_csnIsValidString(const char *s)
+{
+ if(NULL == s) {
+ return(PR_FALSE);
+ }
+ if(strlen(s) < _CSN_VALIDCSN_STRLEN) {
+ return(PR_FALSE);
+ }
+
+ /* some more checks on validity of tstamp portion? */
+ return(PR_TRUE);
+}
diff --git a/ldap/servers/slapd/csngen.c b/ldap/servers/slapd/csngen.c
new file mode 100644
index 00000000..16fe2afa
--- /dev/null
+++ b/ldap/servers/slapd/csngen.c
@@ -0,0 +1,762 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * csngen.c - CSN Generator
+ */
+
+#ifdef _WIN32
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+#endif
+
+#include <string.h>
+#include "prcountr.h"
+#include "slap.h"
+
+#define CSN_MAX_SEQNUM 0xffff /* largest sequence number */
+#define CSN_MAX_TIME_ADJUST 24*60*60 /* maximum allowed time adjustment (in seconds) = 1 day */
+#define ATTR_CSN_GENERATOR_STATE "nsState" /* attribute that stores csn state information */
+#define STATE_FORMAT "%8x%8x%8x%4hx%4hx"
+#define STATE_LENGTH 32
+#define MAX_VAL(x,y) ((x)>(y)?(x):(y))
+
+/*
+ * **************************************************************************
+ * data structures
+ * **************************************************************************
+ */
+
+/* callback node */
+typedef struct callback_node
+{
+ GenCSNFn gen_fn; /* function to be called when new csn is generated */
+ void *gen_arg; /* argument to pass to gen_fn function */
+ AbortCSNFn abort_fn; /* function to be called when csn is aborted */
+ void *abort_arg; /* argument to pass to abort_fn function */
+} callback_node;
+
+typedef struct callback_list
+{
+ PRRWLock *lock;
+ DataList *list; /* list of callback_node structures */
+} callback_list;
+
+/* persistently stored generator's state */
+typedef struct csngen_state
+{
+ ReplicaId rid; /* replica id of the replicated area to which it is attached */
+ time_t sampled_time; /* time last obtained from time() */
+ time_t local_offset; /* offset due to the local clock being set back */
+ time_t remote_offset; /* offset due to clock difference with remote systems */
+ PRUint16 seq_num; /* used to allow to generate multiple csns within a second */
+}csngen_state;
+
+/* data maintained for each generator */
+struct csngen
+{
+ csngen_state state; /* persistent state of the generator */
+ callback_list callbacks; /* list of callbacks registered with the generator */
+ PRRWLock *lock; /* concurrency control */
+};
+
+/*
+ * **************************************************************************
+ * global data
+ * **************************************************************************
+ */
+
+static time_t g_sampled_time; /* time obtained from time() call */
+
+/*
+ * **************************************************************************
+ * forward declarations of helper functions
+ * **************************************************************************
+ */
+
+static int _csngen_parse_state (CSNGen *gen, Slapi_Attr *state);
+static int _csngen_init_callbacks (CSNGen *gen);
+static void _csngen_call_callbacks (const CSNGen *gen, const CSN *csn, PRBool abort);
+static int _csngen_cmp_callbacks (const void *el1, const void *el2);
+static void _csngen_free_callbacks (CSNGen *gen);
+static int _csngen_adjust_local_time (CSNGen *gen, time_t cur_time);
+
+/*
+ * **************************************************************************
+ * forward declarations of tester functions
+ * **************************************************************************
+ */
+
+static int _csngen_start_test_threads (CSNGen *gen);
+static void _csngen_stop_test_threads ();
+static void _csngen_gen_tester_main (void *data);
+static void _csngen_local_tester_main (void *data);
+static void _csngen_remote_tester_main (void *data);
+
+/*
+ * **************************************************************************
+ * API
+ * **************************************************************************
+ */
+CSNGen*
+csngen_new (ReplicaId rid, Slapi_Attr *state)
+{
+ int rc = CSN_SUCCESS;
+ CSNGen *gen = NULL;
+
+ gen = (CSNGen*)slapi_ch_calloc (1, sizeof (CSNGen));
+ if (gen == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "csngen_new: memory allocation failed\n");
+ return NULL;
+ }
+
+ /* create lock to control the access to the state information */
+ gen->lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "state_lock");
+ if (gen->lock == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "csngen_new: failed to create lock\n");
+ rc = CSN_NSPR_ERROR;
+ goto done;
+ }
+
+ /* initialize callback list */
+ _csngen_init_callbacks (gen);
+
+ gen->state.rid = rid;
+
+ if (state)
+ {
+ rc = _csngen_parse_state (gen, state);
+ if (rc != CSN_SUCCESS)
+ {
+ goto done;
+ }
+ }
+ else
+ {
+ /* new generator */
+ gen->state.sampled_time = current_time ();
+ gen->state.local_offset = 0;
+ gen->state.remote_offset = 0;
+ gen->state.seq_num = 0;
+ }
+
+done:
+ if (rc != CSN_SUCCESS)
+ {
+ if (gen)
+ {
+ csngen_free (&gen);
+ }
+
+ return NULL;
+ }
+
+ return gen;
+}
+
+void
+csngen_free (CSNGen **gen)
+{
+ if (gen == NULL || *gen == NULL)
+ return;
+
+ _csngen_free_callbacks (*gen);
+
+ if ((*gen)->lock)
+ PR_DestroyRWLock ((*gen)->lock);
+}
+
+int
+csngen_new_csn (CSNGen *gen, CSN **csn, PRBool notify)
+{
+ int rc = CSN_SUCCESS;
+ time_t cur_time;
+ int delta;
+
+ if (gen == NULL || csn == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "csngen_new_csn: invalid argument\n");
+ return CSN_INVALID_PARAMETER;
+ }
+
+ *csn = csn_new ();
+ if (*csn == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "csngen_new_csn: memory allocation failed\n");
+ return CSN_MEMORY_ERROR;
+ }
+
+ PR_RWLock_Wlock (gen->lock);
+
+ if (g_sampled_time == 0)
+ csngen_update_time ();
+
+ cur_time = g_sampled_time;
+
+ /* check if the time should be adjusted */
+ delta = cur_time - gen->state.sampled_time;
+ if (delta > 0)
+ {
+ rc = _csngen_adjust_local_time (gen, cur_time);
+ if (rc != CSN_SUCCESS)
+ {
+ PR_RWLock_Unlock (gen->lock);
+ return rc;
+ }
+ }
+ else if (delta < -300) {
+ /*
+ * The maxseqnum could support up to 65535 CSNs per second.
+ * That means that we could avoid duplicated CSN's for
+ * delta up to 300 secs if update rate is 200/sec (usually
+ * the max rate is below 20/sec).
+ * Beyond 300 secs, we advance gen->state.sampled_time by
+ * one sec to recycle seqnum.
+ */
+ slapi_log_error (SLAPI_LOG_FATAL, "csngen_new_csn", "Warning: too much time skew (%d secs). Current seqnum=%0x\n", delta, gen->state.seq_num );
+ rc = _csngen_adjust_local_time (gen, gen->state.sampled_time+1);
+ if (rc != CSN_SUCCESS)
+ {
+ PR_RWLock_Unlock (gen->lock);
+ return rc;
+ }
+
+ }
+
+ if (gen->state.seq_num == CSN_MAX_SEQNUM)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "csngen_new_csn: sequence rollover; "
+ "local offset updated.\n");
+ gen->state.local_offset ++;
+ gen->state.seq_num = 0;
+ }
+
+ (*csn)->tstamp = gen->state.sampled_time + gen->state.local_offset +
+ gen->state.remote_offset;
+ (*csn)->seqnum = gen->state.seq_num ++;
+ (*csn)->rid = gen->state.rid;
+ (*csn)->subseqnum = 0;
+
+ /* The lock is intentionally unlocked before callbacks are called.
+ This is to prevent deadlocks. The callback management code has
+ its own lock */
+ PR_RWLock_Unlock (gen->lock);
+
+ /* notify modules that registered interest in csn generation */
+ if (notify)
+ {
+ _csngen_call_callbacks (gen, *csn, 0);
+ }
+
+ return rc;
+}
+
+/* this function should be called for csns generated with non-zero notify
+ that were unused because the corresponding operation was aborted.
+ The function calls "abort" functions registered through
+ csngen_register_callbacks call */
+void csngen_abort_csn (CSNGen *gen, const CSN *csn)
+{
+ _csngen_call_callbacks (gen, csn, 1);
+}
+
+/* this function should be called when a remote CSN for the same part of
+ the dit becomes known to the server (for instance, as part of RUV during
+ replication session. In response, the generator would adjust its notion
+ of time so that it does not generate smaller csns */
+int csngen_adjust_time (CSNGen *gen, const CSN* csn)
+{
+ time_t remote_time, remote_offset;
+ PRUint16 remote_seqnum;
+
+ if (gen == NULL || csn == NULL)
+ return CSN_INVALID_PARAMETER;
+
+ remote_time = csn_get_time (csn);
+ remote_seqnum = csn_get_seqnum (csn);
+
+ PR_RWLock_Wlock (gen->lock);
+
+ if (remote_seqnum > gen->state.seq_num )
+ {
+ if (remote_seqnum < CSN_MAX_SEQNUM)
+ {
+ gen->state.seq_num = remote_seqnum + 1;
+ }
+ else
+ {
+ remote_time++;
+ }
+ }
+
+ if (remote_time >= gen->state.sampled_time)
+ {
+ remote_offset = remote_time - gen->state.sampled_time;
+ if (remote_offset > gen->state.remote_offset)
+ {
+ if (remote_offset <= CSN_MAX_TIME_ADJUST)
+ {
+ gen->state.remote_offset = remote_offset;
+ }
+ else /* remote_offset > CSN_MAX_TIME_ADJUST */
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "csngen_adjust_time: "
+ "adjustment limit exceeded; value - %d, limit - %d\n",
+ remote_offset, CSN_MAX_TIME_ADJUST);
+ PR_RWLock_Unlock (gen->lock);
+ return CSN_LIMIT_EXCEEDED;
+ }
+ }
+ }
+
+ PR_RWLock_Unlock (gen->lock);
+
+ return CSN_SUCCESS;
+}
+
+/* returns PR_TRUE if the csn was generated by this generator and
+ PR_FALSE otherwise. */
+PRBool csngen_is_local_csn(const CSNGen *gen, const CSN *csn)
+{
+ return (gen && csn && gen->state.rid == csn_get_replicaid(csn));
+}
+
+/* returns current state of the generator so that it can be saved in the DIT */
+int csngen_get_state (const CSNGen *gen, Slapi_Mod *state)
+{
+ struct berval bval;
+
+ if (gen == NULL || state == NULL)
+ return CSN_INVALID_PARAMETER;
+
+ PR_RWLock_Rlock (gen->lock);
+
+ slapi_mod_init (state, 1);
+ slapi_mod_set_type (state, ATTR_CSN_GENERATOR_STATE);
+ slapi_mod_set_operation (state, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES);
+ bval.bv_val = (char*)&gen->state;
+ bval.bv_len = sizeof (gen->state);
+ slapi_mod_add_value(state, &bval);
+
+ PR_RWLock_Unlock (gen->lock);
+
+ return CSN_SUCCESS;
+}
+
+/* registers callbacks to be called when csn is created or aborted */
+void* csngen_register_callbacks(CSNGen *gen, GenCSNFn genFn, void *genArg,
+ AbortCSNFn abortFn, void *abortArg)
+{
+ callback_node *node;
+ if (gen == NULL || (genFn == NULL && abortFn == NULL))
+ return NULL;
+
+ node = (callback_node *)slapi_ch_malloc (sizeof (callback_node));
+ node->gen_fn = genFn;
+ node->gen_arg = genArg;
+ node->abort_fn = abortFn;
+ node->abort_arg = abortArg;
+
+ PR_RWLock_Wlock (gen->callbacks.lock);
+ dl_add (gen->callbacks.list, node);
+ PR_RWLock_Unlock (gen->callbacks.lock);
+
+ return node;
+}
+
+/* unregisters callbacks registered via call to csngenRegisterCallbacks */
+void csngen_unregister_callbacks(CSNGen *gen, void *cookie)
+{
+ if (gen && cookie)
+ {
+ PR_RWLock_Wlock (gen->callbacks.lock);
+ dl_delete (gen->callbacks.list, cookie, _csngen_cmp_callbacks, slapi_ch_free);
+ PR_RWLock_Unlock (gen->callbacks.lock);
+ }
+}
+
+/* this functions is periodically called from daemon.c to
+ update time used by all generators */
+void csngen_update_time ()
+{
+ g_sampled_time = current_time ();
+}
+
+/* debugging function */
+void csngen_dump_state (const CSNGen *gen)
+{
+ if (gen)
+ {
+ PR_RWLock_Rlock (gen->lock);
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "CSN generator's state:\n");
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "\treplica id: %d\n", gen->state.rid);
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "\tsampled time: %d\n", gen->state.sampled_time);
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "\tlocal offset: %d\n", gen->state.local_offset);
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "\tremote offset: %d\n", gen->state.remote_offset);
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "\tsequence number: %d\n", gen->state.seq_num);
+ PR_RWLock_Unlock (gen->lock);
+ }
+}
+
+#define TEST_TIME 600 /* 10 minutes */
+/* This function tests csn generator. It verifies that csn's are generated in
+ monotnically increasing order in the face of local and remote time skews */
+void csngen_test ()
+{
+ int rc;
+ CSNGen *gen = csngen_new (255, NULL);
+
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "staring csn generator test ...");
+ csngen_dump_state (gen);
+
+ rc = _csngen_start_test_threads(gen);
+ if (rc == 0)
+ {
+ DS_Sleep(PR_SecondsToInterval(TEST_TIME));
+ }
+
+ _csngen_stop_test_threads(gen);
+ csngen_dump_state (gen);
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "csn generator test is complete...");
+}
+
+/*
+ * **************************************************************************
+ * Helper functions
+ * **************************************************************************
+ */
+static int
+_csngen_parse_state (CSNGen *gen, Slapi_Attr *state)
+{
+ int rc;
+ Slapi_Value *val;
+ const struct berval *bval;
+ ReplicaId rid = gen->state.rid;
+
+ PR_ASSERT (gen && state);
+
+ rc = slapi_attr_first_value(state, &val);
+ if (rc != 0)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "_csngen_parse_state: invalid state format\n");
+ return CSN_INVALID_FORMAT;
+ }
+
+ bval = slapi_value_get_berval(val);
+ memcpy (&gen->state, bval->bv_val, bval->bv_len);
+
+ /* replicaid does not match */
+ if (rid != gen->state.rid)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "_csngen_parse_state: replica id"
+ " mismatch; current id - %d, replica id in the state - %d\n",
+ rid, gen->state.rid);
+ return CSN_INVALID_FORMAT;
+ }
+
+ return CSN_SUCCESS;
+}
+
+static int
+_csngen_init_callbacks (CSNGen *gen)
+{
+ /* create a lock to control access to the callback list */
+ gen->callbacks.lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "callback_lock");
+ if (gen->callbacks.lock == NULL)
+ {
+ return CSN_NSPR_ERROR;
+ }
+
+ gen->callbacks.list = dl_new ();
+ dl_init (gen->callbacks.list, 0);
+
+ return CSN_SUCCESS;
+}
+
+static void
+_csngen_free_callbacks (CSNGen *gen)
+{
+ PR_ASSERT (gen);
+
+ if (gen->callbacks.list)
+ {
+ dl_cleanup (gen->callbacks.list, slapi_ch_free);
+ dl_free (&(gen->callbacks.list));
+ }
+
+ if (gen->callbacks.lock)
+ PR_DestroyRWLock (gen->callbacks.lock);
+}
+
+static void
+_csngen_call_callbacks (const CSNGen *gen, const CSN *csn, PRBool abort)
+{
+ int cookie;
+ callback_node* node;
+
+ PR_ASSERT (gen && csn);
+
+ PR_RWLock_Rlock (gen->callbacks.lock);
+ node = (callback_node*)dl_get_first (gen->callbacks.list, &cookie);
+ while (node)
+ {
+ if (abort)
+ {
+ if (node->abort_fn)
+ node->abort_fn (csn, node->abort_arg);
+ }
+ else
+ {
+ if (node->gen_fn)
+ node->gen_fn (csn, node->gen_arg);
+ }
+ node = (callback_node*)dl_get_next (gen->callbacks.list, &cookie);
+ }
+
+ PR_RWLock_Unlock (gen->callbacks.lock);
+}
+
+/* el1 is just a pointer to the callback_node */
+static int
+_csngen_cmp_callbacks (const void *el1, const void *el2)
+{
+ if (el1 == el2)
+ return 0;
+
+ if (el1 < el2)
+ return -1;
+ else
+ return 1;
+}
+
+static int
+_csngen_adjust_local_time (CSNGen *gen, time_t cur_time)
+{
+ time_t time_diff = cur_time - gen->state.sampled_time;
+
+ if (time_diff > 0)
+ {
+ gen->state.sampled_time = cur_time;
+ if (time_diff > gen->state.local_offset)
+ gen->state.local_offset = 0;
+ else
+ gen->state.local_offset = gen->state.local_offset - time_diff;
+
+ gen->state.seq_num = 0;
+
+ return CSN_SUCCESS;
+ }
+ else /* time was turend back */
+ {
+ if (abs (time_diff) > CSN_MAX_TIME_ADJUST)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "_csngen_adjust_local_time: "
+ "adjustment limit exceeded; value - %d, limit - %d\n",
+ abs (time_diff), CSN_MAX_TIME_ADJUST);
+ return CSN_LIMIT_EXCEEDED;
+ }
+
+ gen->state.sampled_time = cur_time;
+ gen->state.local_offset = MAX_VAL (gen->state.local_offset, abs (time_diff));
+ gen->state.seq_num = 0;
+
+ return CSN_SUCCESS;
+ }
+}
+
+/*
+ * **************************************************************************
+ * test code
+ * **************************************************************************
+ */
+
+/*
+ * The defult thread stacksize for nspr21 is 64k. For OSF, we require
+ * a larger stacksize as actual storage allocation is higher i.e
+ * pointers are allocated 8 bytes but lower 4 bytes are used.
+ * The value 0 means use the default stacksize.
+ */
+#if defined (OSF1)
+#define DEFAULT_THREAD_STACKSIZE 131072L
+#else
+#define DEFAULT_THREAD_STACKSIZE 0
+#endif
+
+#define GEN_TREAD_COUNT 20
+int s_thread_count;
+int s_must_exit;
+
+static int
+_csngen_start_test_threads(CSNGen *gen)
+{
+ int i;
+
+ PR_ASSERT (gen);
+
+ s_thread_count = 0;
+ s_must_exit = 0;
+
+ /* create threads that generate csns */
+ for(i=0; i< GEN_TREAD_COUNT; i++)
+ {
+ if (PR_CreateThread(PR_USER_THREAD, _csngen_gen_tester_main, gen,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+ DEFAULT_THREAD_STACKSIZE) == NULL)
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "failed to create a CSN generator thread number %d; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ i, prerr, slapd_pr_strerror(prerr));
+ return -1;
+ }
+
+ s_thread_count ++;
+ }
+
+ /* create a thread that modifies remote time */
+ if (PR_CreateThread(PR_USER_THREAD, _csngen_remote_tester_main, (void *)gen,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+ DEFAULT_THREAD_STACKSIZE) == NULL)
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "failed to create the remote CSN tester thread; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr));
+ return -1;
+ }
+
+ s_thread_count ++;
+
+ /* create a thread that modifies local time */
+ if (PR_CreateThread(PR_USER_THREAD, _csngen_local_tester_main, (void *)gen,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+ DEFAULT_THREAD_STACKSIZE) == NULL)
+
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "failed to create the local CSN tester thread; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr));
+ return -1;
+ }
+
+ s_thread_count ++;
+
+
+ return 0;
+}
+
+static void _csngen_stop_test_threads ()
+{
+ s_must_exit = 1;
+
+ while (s_thread_count > 0)
+ {
+ /* sleep for 30 seconds */
+ DS_Sleep (PR_SecondsToInterval(20));
+ }
+}
+
+/* periodically generate a csn and dump it to the error log */
+static void
+_csngen_gen_tester_main (void *data)
+{
+ CSNGen *gen = (CSNGen*)data;
+ CSN *csn;
+ char buff [CSN_STRSIZE];
+ int rc;
+
+ PR_ASSERT (gen);
+
+ while (!s_must_exit)
+ {
+ rc = csngen_new_csn (gen, &csn, PR_FALSE);
+ if (rc != CSN_SUCCESS)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL,
+ "failed to generate csn; csn error - %d\n", rc);
+ }
+ else
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "generate csn %s\n",
+ csn_as_string(csn, PR_FALSE, buff));
+ }
+
+ /* sleep for 30 seconds */
+ DS_Sleep (PR_SecondsToInterval(10));
+ }
+
+ PR_AtomicDecrement (&s_thread_count);
+}
+
+/* simulate clock skew with remote servers that causes
+ generator to advance its remote offset */
+static void
+_csngen_remote_tester_main (void *data)
+{
+ CSNGen *gen = (CSNGen*)data;
+ CSN *csn;
+ time_t csn_time;
+ int rc;
+
+ PR_ASSERT (gen);
+
+ while (!s_must_exit)
+ {
+ rc = csngen_new_csn (gen, &csn, PR_FALSE);
+ if (rc != CSN_SUCCESS)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL,
+ "failed to generate csn; csn error - %d\n", rc);
+ }
+ else
+ {
+ csn_time = csn_get_time(csn);
+ csn_set_time (csn, csn_time + slapi_rand () % 100);
+
+ rc = csngen_adjust_time (gen, csn);
+ if (rc != CSN_SUCCESS)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL,
+ "failed to adjust generator's time; csn error - %d\n", rc);
+ }
+
+ csngen_dump_state (gen);
+
+ }
+
+ /* sleep for 30 seconds */
+ DS_Sleep (PR_SecondsToInterval(60));
+ }
+
+ PR_AtomicDecrement (&s_thread_count);
+}
+
+/* simulate local clock being set back */
+static void
+_csngen_local_tester_main (void *data)
+{
+ CSNGen *gen = (CSNGen*)data;
+
+ PR_ASSERT (gen);
+
+
+ while (!s_must_exit)
+ {
+ /* sleep for 30 seconds */
+ DS_Sleep (PR_SecondsToInterval(60));
+
+ g_sampled_time -= slapi_rand () % 100;
+
+ csngen_dump_state (gen);
+ }
+
+ PR_AtomicDecrement (&s_thread_count);
+}
+
+
diff --git a/ldap/servers/slapd/csngen.h b/ldap/servers/slapd/csngen.h
new file mode 100644
index 00000000..14021c41
--- /dev/null
+++ b/ldap/servers/slapd/csngen.h
@@ -0,0 +1,27 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _REPL_CSNGEN_H
+#define _REPL_CSNGEN_H
+
+#include <stdio.h>
+#include <time.h>
+#include "slapi-private.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/* the "exported" function declarations can be found in slapi-private.h */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/ldap/servers/slapd/csnset.c b/ldap/servers/slapd/csnset.c
new file mode 100644
index 00000000..700cbc82
--- /dev/null
+++ b/ldap/servers/slapd/csnset.c
@@ -0,0 +1,360 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slap.h"
+#include "slapi-private.h"
+
+static const CSNSet *csnset_get_csnset_node_from_csn(const CSNSet *csnset, const CSN *csn);
+static const CSNSet *csnset_get_csnset_node_from_type(const CSNSet *csnset, CSNType t);
+static CSNSet *csnset_get_previous_csnset_node(CSNSet *csnset, const CSN *csn);
+
+/*
+ * The CSN is always added to the end of the list.
+ */
+void
+csnset_add_csn(CSNSet **csnset, CSNType t, const CSN *csn)
+{
+ if(csn!=NULL)
+ {
+ CSNSet *newcsn= (CSNSet*)slapi_ch_malloc(sizeof(CSNSet));
+ newcsn->type= t;
+ csn_init_by_csn(&newcsn->csn,csn);
+ newcsn->next= NULL;
+ {
+ CSNSet **p= csnset;
+ CSNSet *n= *csnset;
+ while(n!=NULL)
+ {
+ p= &(n->next);
+ n= n->next;
+ }
+ *p= newcsn;
+ }
+ }
+}
+
+/*
+ * The CSN is inserted into the list at the appropriate point..
+ */
+void
+csnset_insert_csn(CSNSet **csnset, CSNType t, const CSN *csn)
+{
+ if((csn!=NULL) && (*csnset==NULL))
+ {
+ csnset_add_csn(csnset, t, csn);
+ }
+ else if(csn!=NULL)
+ {
+ CSNSet *newcsn= (CSNSet*)slapi_ch_malloc(sizeof(CSNSet));
+ CSNSet *f= csnset_get_previous_csnset_node(*csnset, csn);
+ newcsn->type= t;
+ csn_init_by_csn(&newcsn->csn,csn);
+ if(f==NULL)
+ {
+ /* adding to the list head */
+ newcsn->next= *csnset;
+ *csnset= newcsn;
+ }
+ else
+ {
+ newcsn->next= f->next;
+ f->next= newcsn;
+ }
+ }
+}
+
+/*
+ * Find the CSN of the given type and update it.
+ */
+void
+csnset_update_csn(CSNSet **csnset, CSNType t, const CSN *csn)
+{
+ const CSNSet *f= csnset_get_csnset_node_from_type(*csnset, t);
+ if(f==NULL)
+ {
+ csnset_add_csn(csnset,t,csn);
+ }
+ else
+ {
+ if (csn_compare(csn, (CSN*)(&f->csn)) > 0)
+ {
+ csn_init_by_csn((CSN*)(&f->csn),csn);
+ }
+ }
+}
+
+/*
+ * Check if the set CSN of CSNs contains a given CSN.
+ */
+int
+csnset_contains(const CSNSet *csnset, const CSN *csn)
+{
+ const CSNSet *f= csnset_get_csnset_node_from_csn(csnset, csn);
+ return(f!=NULL);
+}
+
+/*
+ * Remove the first CSN of the given type.
+ */
+void
+csnset_remove_csn(CSNSet **csnset, CSNType t)
+{
+ CSNSet **p= csnset;
+ CSNSet *n= *csnset;
+ while(n!=NULL)
+ {
+ if(n->type==t)
+ {
+ *p= n->next;
+ slapi_ch_free((void**)&n);
+ }
+ else
+ {
+ p= &n->next;
+ n= n->next;
+ }
+ }
+}
+
+void
+csnset_free(CSNSet **csnset)
+{
+ csnset_purge(csnset, NULL);
+}
+
+/*
+ * Get the first CSN of the given type.
+ */
+const CSN *
+csnset_get_csn_of_type(const CSNSet *csnset, CSNType t)
+{
+ const CSN *csn= NULL;
+ const CSNSet *f= csnset_get_csnset_node_from_type(csnset, t);
+ if(f!=NULL)
+ {
+ csn= &f->csn;
+ }
+ return csn;
+}
+
+const CSN *
+csnset_get_previous_csn(const CSNSet *csnset, const CSN *csn)
+{
+ const CSN *prevcsn= NULL;
+ CSNSet *f= csnset_get_previous_csnset_node((CSNSet*)csnset, csn);
+ if(f!=NULL)
+ {
+ prevcsn= &f->csn;
+ }
+ return prevcsn;
+}
+
+const CSN *
+csnset_get_last_csn(const CSNSet *csnset)
+{
+ const CSN *csn= NULL;
+ const CSNSet *n= csnset;
+ while(n!=NULL)
+ {
+ if(n->next==NULL)
+ {
+ csn= &n->csn;
+ }
+ n= n->next;
+ }
+ return csn;
+}
+
+void*
+csnset_get_first_csn (const CSNSet *csnset, CSN **csn, CSNType *t)
+{
+ if (csnset)
+ {
+ *csn = (CSN*)&csnset->csn;
+ *t = csnset->type;
+ return (void*)csnset;
+ }
+ else
+ return NULL;
+}
+
+void*
+csnset_get_next_csn (const CSNSet *csnset, void *cookie, CSN **csn, CSNType *t)
+{
+ CSNSet *node;
+
+ if (csnset && cookie)
+ {
+ node = ((CSNSet*)cookie)->next;
+ if (node)
+ {
+ *csn = (CSN*)&node->csn;
+ *t = node->type;
+ return node;
+ }
+ else
+ return NULL;
+ }
+ else
+ return NULL;
+}
+
+static CSNSet *
+csnset_get_previous_csnset_node(CSNSet *csnset, const CSN *csn)
+{
+ CSNSet *f= NULL;
+ CSNSet *p= NULL;
+ CSNSet *n= csnset;
+ while(n!=NULL)
+ {
+ if(csn_compare(&n->csn, csn)>0)
+ {
+ f= p;
+ n= NULL;
+ }
+ else
+ {
+ p= n;
+ n= n->next;
+ if(n==NULL)
+ {
+ /* Got to the end of the list... */
+ f= p;
+ }
+ }
+ }
+ return f;
+}
+
+static const CSNSet *
+csnset_get_csnset_node_from_csn(const CSNSet *csnset, const CSN *csn)
+{
+ const CSNSet *f= NULL;
+ const CSNSet *n= csnset;
+ while(n!=NULL)
+ {
+ if(csn_compare(&n->csn, csn)==0)
+ {
+ f= n;
+ n= NULL;
+ }
+ else
+ {
+ n= n->next;
+ }
+ }
+ return f;
+}
+
+static const CSNSet *
+csnset_get_csnset_node_from_type(const CSNSet *csnset, CSNType t)
+{
+ const CSNSet *f= NULL;
+ const CSNSet *n= csnset;
+ while(n!=NULL)
+ {
+ if(n->type==t)
+ {
+ f= n;
+ n= NULL;
+ }
+ else
+ {
+ n= n->next;
+ }
+ }
+ return f;
+}
+
+/*
+ * Remove any CSNs older than csnUpTo. If csnUpTo is NULL,
+ * remove all CSNs.
+ */
+void
+csnset_purge(CSNSet **csnset, const CSN *csnUpTo)
+{
+ if (csnset != NULL)
+ {
+ CSNSet *n = *csnset, *nprev = NULL, *nnext;
+ while (n != NULL)
+ {
+ if (NULL == csnUpTo || (csn_compare(&n->csn, csnUpTo) < 0))
+ {
+ nnext = n->next;
+ if (*csnset == n)
+ {
+ /* Deletion of head */
+ *csnset = nnext;
+ }
+ else if (nprev)
+ {
+ /* nprev was not purged, but n will be */
+ nprev->next = nnext;
+ }
+ slapi_ch_free((void**)&n);
+ n = nnext;
+ }
+ else
+ {
+ nprev = n;
+ n = n->next;
+ }
+ }
+ }
+}
+
+size_t
+csnset_string_size(CSNSet *csnset)
+{
+ size_t s= 0;
+ CSNSet *n= csnset;
+ while(n!=NULL)
+ {
+ /* sizeof(;vucsn-011111111222233334444) */
+ s+= 1 + LDIF_CSNPREFIX_MAXLENGTH + _CSN_VALIDCSN_STRLEN;
+ n= n->next;
+ }
+ return s;
+}
+
+size_t
+csnset_size(CSNSet *csnset)
+{
+ size_t s= 0;
+ CSNSet *n= csnset;
+ while(n!=NULL)
+ {
+ s+= sizeof(CSNSet);
+ n= n->next;
+ }
+ return s;
+}
+
+CSNSet *
+csnset_dup(const CSNSet *csnset)
+{
+ CSNSet *newcsnset= NULL;
+ const CSNSet *n= csnset;
+ while(n!=NULL)
+ {
+ csnset_add_csn(&newcsnset,n->type,&n->csn);
+ n= n->next;
+ }
+ return newcsnset;
+}
+
+void
+csnset_as_string(const CSNSet *csnset,char *s)
+{
+ const CSNSet *n= csnset;
+ while(n!=NULL)
+ {
+ csn_as_attr_option_string(n->type,&n->csn,s);
+ /* sizeof(;vucsn-011111111222233334444) */
+ s+= 1 + LDIF_CSNPREFIX_MAXLENGTH + _CSN_VALIDCSN_STRLEN;
+ n= n->next;
+ }
+}
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
new file mode 100644
index 00000000..db79288f
--- /dev/null
+++ b/ldap/servers/slapd/daemon.c
@@ -0,0 +1,2694 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <string.h>
+#include <sys/types.h>
+#ifdef _WIN32
+#include <windows.h>
+#include <process.h> /* for getpid */
+#include "proto-ntutil.h"
+#include "ntslapdmessages.h"
+#else
+#include <unistd.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <netinet/tcp.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#endif
+#include <time.h>
+#include <signal.h>
+#if defined(IRIX6_2) || defined(IRIX6_3)
+#include <sys/param.h>
+#endif
+#if defined(_AIX)
+#include <sys/select.h>
+#include <sys/param.h>
+#endif
+#include <fcntl.h>
+#define TCPLEN_T int
+#if !defined( _WIN32 )
+#ifdef NEED_FILIO
+#include <sys/filio.h>
+#else /* NEED_FILIO */
+#include <sys/ioctl.h>
+#endif /* NEED_FILIO */
+#endif /* !defined( _WIN32 ) */
+/* for some reason, linux tty stuff defines CTIME */
+#ifdef LINUX
+#undef CTIME
+#endif
+#include "slap.h"
+#include "slapi-plugin.h"
+
+#include "snmp_collator.h"
+#include <private/pprio.h>
+
+#if defined( NET_SSL )
+#include <ssl.h>
+#endif /* defined(NET_SSL) */
+
+#include "fe.h"
+
+/*
+ * Define the backlog number for use in listen() call.
+ * We use the same definition as in ldapserver/include/base/systems.h
+ */
+#ifndef DAEMON_LISTEN_SIZE
+#define DAEMON_LISTEN_SIZE 128
+#endif
+
+#if defined (LDAP_IOCP)
+#define SLAPD_WAKEUP_TIMER 250
+#else
+#define SLAPD_WAKEUP_TIMER 250
+#endif
+
+int slapd_wakeup_timer = SLAPD_WAKEUP_TIMER; /* time in ms to wakeup */
+#ifdef notdef /* GGOODREPL */
+/*
+ * time in secs to do housekeeping:
+ * this must be greater than slapd_wakeup_timer
+ */
+short slapd_housekeeping_timer = 10;
+#endif /* notdef GGOODREPL */
+
+/* Do we support timeout on socket send() ? */
+int have_send_timeouts = 0;
+
+PRFileDesc* signalpipe[2];
+static int writesignalpipe = SLAPD_INVALID_SOCKET;
+static int readsignalpipe = SLAPD_INVALID_SOCKET;
+
+#define FDS_SIGNAL_PIPE 0
+#define FDS_N_TCPS 1
+#define FDS_S_TCPS 2
+
+static int get_configured_connection_table_size();
+#ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
+static void get_loopback_by_addr( void );
+#endif
+
+#ifdef XP_WIN32
+static int createlistensocket(unsigned short port, const PRNetAddr *listenaddr);
+#endif
+static PRFileDesc *createprlistensocket(unsigned short port,
+ const PRNetAddr *listenaddr, int secure);
+static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
+ size_t addrbuflen);
+static void set_shutdown (int);
+static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc *n_tcps, PRFileDesc *s_tcps, PRIntn *num_to_read);
+
+#ifdef HPUX10
+static void* catch_signals();
+#endif
+
+#if defined( _WIN32 )
+HANDLE hServDoneEvent = NULL;
+#endif
+
+static int createsignalpipe( void );
+
+
+#if defined( _WIN32 )
+/* Set an event to hook the NT Service termination */
+void *slapd_service_exit_wait()
+{
+#if defined( PURIFYING )
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+ char module[_MAX_FNAME];
+ char exit_file_name[_MAX_FNAME];
+ char drive[_MAX_DRIVE];
+ char dir[_MAX_DIR];
+ char fname[_MAX_FNAME];
+ char ext[_MAX_EXT];
+ struct stat statbuf;
+
+ memset( module, 0, sizeof( module ) );
+ memset( exit_file_name, 0, sizeof( exit_file_name ) );
+
+ GetModuleFileName(GetModuleHandle( NULL ), module, sizeof( module ) );
+
+ _splitpath( module, drive, dir, fname, ext );
+
+ sprintf( exit_file_name, "%s%s%s", drive, dir, "exitnow.txt" );
+
+ LDAPDebug( LDAP_DEBUG_ANY, "PURIFYING - Create %s to terminate the process.\n", exit_file_name, 0, 0 );
+
+ while ( TRUE )
+ {
+ if( stat( exit_file_name, &statbuf ) < 0)
+ {
+ Sleep( 5000 ); /* 5 Seconds */
+ continue;
+ }
+ LDAPDebug( LDAP_DEBUG_ANY, "slapd shutting down immediately, "
+ "\"%s\" exists - don't forget to delete it\n", exit_file_name, 0, 0 );
+ g_set_shutdown( SLAPI_SHUTDOWN_SIGNAL );
+ return NULL;
+ }
+
+#else /* PURIFYING */
+
+ DWORD dwWait;
+ char szDoneEvent[256];
+
+ sprintf(szDoneEvent, "NS_%s", pszServerName);
+
+ hServDoneEvent = CreateEvent( NULL, // default security attributes (LocalSystem)
+ TRUE, // manual reset event
+ FALSE, // not-signalled
+ szDoneEvent );// named after the service itself.
+
+ /* Wait indefinitely until hServDoneEvent is signaled. */
+ dwWait = WaitForSingleObject( hServDoneEvent, // event object
+ INFINITE ); // wait indefinitely
+
+ /* The termination event has been signalled, log this occurrence, and signal to exit. */
+ ReportSlapdEvent( EVENTLOG_INFORMATION_TYPE, MSG_SERVER_SHUTDOWN_STARTING, 0, NULL );
+
+ g_set_shutdown( SLAPI_SHUTDOWN_SIGNAL );
+ return NULL;
+#endif /* PURIFYING */
+}
+#endif /* _WIN32 */
+
+static char *
+get_pid_file()
+{
+ return(pid_file);
+}
+
+static int daemon_configure_send_timeout(int s,size_t timeout /* Miliseconds*/)
+{
+ /* Currently this function is only good for NT, and expects the s argument to be a SOCKET */
+#if defined(_WIN32)
+ return setsockopt(
+ s,
+ SOL_SOCKET,
+ SO_SNDTIMEO,
+ (char*) &timeout,
+ sizeof(timeout)
+ );
+#else
+ return 0;
+#endif
+}
+
+#if defined (_WIN32)
+/* This function is a workaround for accept problem on NT.
+ Accept call fires on NT during syn scan even though the connection is not
+ open. This causes a resource leak. For more details, see bug 391414.
+ Experimentally, we determined that, in case of syn scan, the local
+ address is set to 0. This in undocumented and my change in the future
+
+ The function returns 0 if this is normal connection
+ 1 if this is syn_scan connection
+ -1 in case of any other error
+ */
+static int
+syn_scan (int sock)
+{
+ int rc;
+ struct sockaddr_in addr;
+ int size = sizeof (addr);
+
+ if (sock == SLAPD_INVALID_SOCKET)
+ return -1;
+
+ rc = getsockname (sock, (struct sockaddr*)&addr, &size);
+ if (rc != 0)
+ return -1;
+ else if (addr.sin_addr.s_addr == 0)
+ return 1;
+ else
+ return 0;
+}
+
+#endif
+
+static int
+accept_and_configure(int s, PRFileDesc *pr_acceptfd, PRNetAddr *pr_netaddr,
+ int addrlen, int secure, PRFileDesc **pr_clonefd)
+{
+ int ns = 0;
+ int ioblock_timeout = config_get_ioblocktimeout();
+ int enable_nagle = config_get_nagle();
+
+ PRIntervalTime pr_timeout = PR_MillisecondsToInterval(slapd_wakeup_timer);
+
+#if !defined( XP_WIN32 )
+ (*pr_clonefd) = PR_Accept(pr_acceptfd, pr_netaddr, pr_timeout);
+ if( !(*pr_clonefd) ) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "PR_Accept() failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0 );
+ return(SLAPD_INVALID_SOCKET);
+ }
+
+ ns = configure_pr_socket( pr_clonefd, secure );
+
+#else
+ if( secure ) {
+ (*pr_clonefd) = PR_Accept(pr_acceptfd, pr_netaddr, pr_timeout);
+ if( !(*pr_clonefd) ) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "PR_Accept() failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0 );
+
+ /* Bug 613324: Call PR_NT_CancelIo if an error occurs */
+ if( (prerr == PR_IO_TIMEOUT_ERROR ) ||
+ (prerr == PR_PENDING_INTERRUPT_ERROR) ) {
+ if( (PR_NT_CancelIo( pr_acceptfd )) != PR_SUCCESS) {
+ prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "PR_NT_CancelIo() failed, "
+ SLAPI_COMPONENT_NAME_NSPR
+ " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0 );
+ }
+ }
+ return(SLAPD_INVALID_SOCKET);
+ }
+
+ ns = configure_pr_socket( pr_clonefd, secure );
+
+ } else {
+ struct sockaddr *addr;
+
+ addr = (struct sockaddr *) slapi_ch_malloc( sizeof(struct sockaddr) );
+ ns = accept (s, addr, (TCPLEN_T *)&addrlen);
+
+ if (ns == SLAPD_INVALID_SOCKET) {
+ int oserr = errno;
+
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "accept(%d) failed errno %d (%s)\n",
+ s, oserr, slapd_system_strerror(oserr));
+ }
+
+ else if (syn_scan (ns))
+ {
+ /* this is a work around for accept problem with SYN scan on NT.
+ See bug 391414 for more details */
+ LDAPDebug(LDAP_DEBUG_ANY, "syn-scan request is received - ignored\n", 0, 0, 0);
+ closesocket (ns);
+ ns = SLAPD_INVALID_SOCKET;
+ }
+
+ if ( PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, ((struct sockaddr_in *)addr)->sin_port, pr_netaddr)
+ != PR_SUCCESS ) {
+ int oserr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "PR_SetNetAddr() failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ oserr, slapd_pr_strerror(oserr), 0 );
+ } else {
+ PR_ConvertIPv4AddrToIPv6(((struct sockaddr_in *)addr)->sin_addr.s_addr, &(pr_netaddr->ipv6.ip));
+ }
+
+ (*pr_clonefd) = NULL;
+
+ slapi_ch_free( (void **)&addr );
+ configure_ns_socket( &ns );
+ }
+#endif
+
+ return ns;
+}
+
+/*
+ * This is the shiny new re-born daemon function, without all the hair
+ */
+#ifdef _WIN32
+static void setup_read_fds(Connection_Table *ct, fd_set *readfds, int n_tcps, int s_tcps );
+static void handle_read_ready(Connection_Table *ct, fd_set *readfds);
+static void set_timeval_ms(struct timeval *t, int ms);
+#endif
+/* GGOODREPL static void handle_timeout( void ); */
+static void handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll);
+static int handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure );
+#ifdef _WIN32
+static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, int n_tcps, PRFileDesc *s_tcps);
+#else
+static void unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, PRFileDesc *n_tcps, PRFileDesc *s_tcps);
+#endif
+static int write_pid_file();
+static int init_shutdown_detect();
+#ifdef _WIN32
+static int clear_signal(fd_set *readfdset);
+#else
+static int clear_signal(struct POLL_STRUCT *fds);
+#endif
+
+/* Globals which are used to store the sockets between
+ * calls to daemon_pre_setuid_init() and the daemon thread
+ * creation. */
+
+int daemon_pre_setuid_init(daemon_ports_t *ports)
+{
+ int rc = 0;
+
+ if (0 != ports->n_port) {
+#if defined( XP_WIN32 )
+ ports->n_socket = createlistensocket((unsigned short)ports->n_port,
+ &ports->n_listenaddr);
+#else
+ ports->n_socket = createprlistensocket(ports->n_port,
+ &ports->n_listenaddr, 0);
+#endif
+ }
+
+ if ( config_get_security() && (0 != ports->s_port) ) {
+ ports->s_socket = createprlistensocket((unsigned short)ports->s_port,
+ &ports->s_listenaddr, 1);
+#ifdef XP_WIN32
+ ports->s_socket_native = PR_FileDesc2NativeHandle(ports->s_socket);
+#endif
+ /* check if ports->s_socket != -1 ? */
+ rc = slapd_ssl_init2 ( &ports->s_socket, 0 );
+ } else {
+ ports->s_socket = SLAPD_INVALID_SOCKET;
+#ifdef XP_WIN32
+ ports->s_socket_native = SLAPD_INVALID_SOCKET;
+#endif
+ }
+
+ return( rc );
+}
+
+
+/* Decide whether we're running on a platform which supports send with timeouts */
+static void detect_timeout_support()
+{
+ /* Currently we know that NT4.0 or higher DOES support timeouts */
+#if defined _WIN32
+ /* Get the OS revision */
+ OSVERSIONINFO ver;
+ ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&ver);
+ if (ver.dwPlatformId == VER_PLATFORM_WIN32_NT && ver.dwMajorVersion >= 4) {
+ have_send_timeouts = 1;
+ }
+#else
+ /* Some UNIXen do, but for now I don't feel confident which , and whether timeouts really work there */
+#endif
+}
+
+
+/*
+ * The time_shutdown static variable is used to signal the time thread
+ * to shutdown. We used to shut down the time thread when g_get_shutdown()
+ * returned a non-zero value, but that caused the clock to stop, so to speak,
+ * and all error log entries to have the same timestamp once the shutdown
+ * process began.
+ */
+static int time_shutdown = 0;
+
+void *
+time_thread(void *nothing)
+{
+ PRIntervalTime interval;
+
+ interval = PR_SecondsToInterval(1);
+
+ while(!time_shutdown) {
+ poll_current_time();
+ csngen_update_time ();
+ DS_Sleep(interval);
+ }
+
+ /*NOTREACHED*/
+ return(NULL);
+}
+
+
+void slapd_daemon( daemon_ports_t *ports )
+{
+ /* We are passed a pair of ports---one for regular connections, the
+ * other for SSL connections.
+ */
+ /* Previously there was a ton of code #defined on NET_SSL.
+ * This looked horrible, so now I'm doing it this way:
+ * If you want me to do SSL, pass me something in the ssl port number.
+ * If you don't, pass me zero.
+ */
+
+#if defined( XP_WIN32 )
+ int n_tcps = 0;
+ int s_tcps_native = 0;
+#else
+ PRFileDesc *n_tcps = NULL;
+ PRFileDesc *tcps = 0;
+#endif
+ PRFileDesc *s_tcps = NULL;
+ PRIntn num_poll = 0;
+ PRIntervalTime pr_timeout = PR_MillisecondsToInterval(slapd_wakeup_timer);
+ PRThread *time_thread_p;
+ int threads;
+ int in_referral_mode = config_check_referral_mode();
+
+ int connection_table_size = get_configured_connection_table_size();
+ the_connection_table= connection_table_new(connection_table_size);
+
+#ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
+ /*
+ * Some DNS resolver implementations, such as the one built into
+ * Solaris <= 8, need to use one or more low numbered file
+ * descriptors internally (probably because they use a deficient
+ * implementation of stdio). So we make a call now that uses the
+ * resolver so it has an opportunity to grab whatever low file
+ * descriptors it needs (before we use up all of the low numbered
+ * ones for incoming client connections and so on).
+ */
+ get_loopback_by_addr();
+#endif
+
+ /* Retrieve the sockets from their hiding place */
+ n_tcps = ports->n_socket;
+ s_tcps = ports->s_socket;
+#ifdef XP_WIN32
+ s_tcps_native = ports->s_socket_native;
+#endif
+
+ createsignalpipe();
+
+ init_shutdown_detect();
+
+#if defined( XP_WIN32 )
+ if ( (n_tcps == SLAPD_INVALID_SOCKET) &&
+#else
+ if ( (n_tcps == NULL) &&
+#endif
+ (s_tcps == NULL) ) { /* nothing to do */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "no port to listen on\n", 0, 0, 0 );
+ exit( 1 );
+ }
+
+ unfurl_banners(the_connection_table,ports,n_tcps,s_tcps);
+ init_op_threads ();
+ detect_timeout_support();
+
+ /* Start the time thread */
+ time_thread_p = PR_CreateThread(PR_SYSTEM_THREAD,
+ (VFP) (void *) time_thread, NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_JOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if ( NULL == time_thread_p ) {
+ PRErrorCode errorCode = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY, "Unable to create time thread - Shutting Down ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)\n",
+ errorCode, slapd_pr_strerror(errorCode), 0);
+ g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
+ }
+
+ /* We are now ready to accept imcoming connections */
+#if defined( XP_WIN32 )
+ if ( n_tcps != SLAPD_INVALID_SOCKET
+ && listen( n_tcps, DAEMON_LISTEN_SIZE ) == -1 ) {
+ int oserr = errno;
+ char addrbuf[ 256 ];
+
+ slapi_log_error(SLAPI_LOG_FATAL, "slapd_daemon",
+ "listen() on %s port %d failed: OS error %d (%s)\n",
+ netaddr2string(&ports->n_listenaddr, addrbuf, sizeof(addrbuf)),
+ ports->n_port, oserr, slapd_system_strerror( oserr ) );
+ g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
+ }
+#else
+ if ( n_tcps != NULL
+ && PR_Listen( n_tcps, DAEMON_LISTEN_SIZE ) == PR_FAILURE) {
+ PRErrorCode prerr = PR_GetError();
+ char addrbuf[ 256 ];
+
+ slapi_log_error(SLAPI_LOG_FATAL, "slapd_daemon",
+ "PR_Listen() on %s port %d failed: %s error %d (%s)\n",
+ netaddr2string(&ports->n_listenaddr, addrbuf, sizeof(addrbuf)),
+ ports->n_port, SLAPI_COMPONENT_NAME_NSPR, prerr,
+ slapd_pr_strerror( prerr ));
+ g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
+ }
+#endif
+
+ if ( s_tcps != NULL
+ && PR_Listen( s_tcps, DAEMON_LISTEN_SIZE ) == PR_FAILURE ) {
+ PRErrorCode prerr = PR_GetError();
+ char addrbuf[ 256 ];
+
+ slapi_log_error(SLAPI_LOG_FATAL, "slapd_daemon",
+ "PR_Listen() on %s port %d failed: %s error %d (%s)\n",
+ netaddr2string(&ports->s_listenaddr, addrbuf, sizeof(addrbuf)),
+ ports->s_port, SLAPI_COMPONENT_NAME_NSPR, prerr,
+ slapd_pr_strerror( prerr ));
+ g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
+ }
+
+ /* Now we write the pid file, indicating that the server is finally and listening for connections */
+ write_pid_file();
+
+ /* The meat of the operation is in a loop on a call to select */
+ while(!g_get_shutdown())
+ {
+#ifdef _WIN32
+ fd_set readfds;
+ struct timeval wakeup_timer;
+ int oserr;
+#endif
+ int select_return = 0;
+ int secure = 0; /* is a new connection an SSL one ? */
+#ifndef _WIN32
+ PRErrorCode prerr;
+#endif
+
+#ifdef _WIN32
+ set_timeval_ms(&wakeup_timer, slapd_wakeup_timer);
+ setup_read_fds(the_connection_table,&readfds,n_tcps, s_tcps_native);
+ /* This select needs to timeout to give the server a chance to test for shutdown */
+ select_return = select(connection_table_size, &readfds, NULL, 0, &wakeup_timer);
+#else
+ setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,&num_poll);
+ select_return = POLL_FN(the_connection_table->fd, num_poll, pr_timeout);
+#endif
+ switch (select_return) {
+ case 0: /* Timeout */
+ /* GGOODREPL handle_timeout(); */
+ break;
+ case -1: /* Error */
+#ifdef _WIN32
+ oserr = errno;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "select failed errno %d (%s)\n", oserr,
+ slapd_system_strerror(oserr), 0 );
+#else
+ prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_TRACE, "PR_Poll() failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_system_strerror(prerr), 0 );
+#endif
+ break;
+ default: /* either a new connection or some new data ready */
+ /* Figure out if we are dealing with one of the listen sockets */
+#ifdef _WIN32
+ /* If so, then handle a new connection */
+ if ( n_tcps != SLAPD_INVALID_SOCKET && FD_ISSET( n_tcps,&readfds ) ) {
+ handle_new_connection(the_connection_table,n_tcps,NULL,0);
+ }
+ /* If so, then handle a new connection */
+ if ( s_tcps != SLAPD_INVALID_SOCKET && FD_ISSET( s_tcps_native,&readfds ) ) {
+ handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,s_tcps,1);
+ }
+ /* handle new data ready */
+ handle_read_ready(the_connection_table,&readfds);
+ clear_signal(&readfds);
+#else
+ tcps = NULL;
+ /* info for n_tcps is always in fd[FDS_N_TCPS] and info for s_tcps is always
+ * in fd[FDS_S_TCPS] */
+ if( n_tcps != NULL &&
+ the_connection_table->fd[FDS_N_TCPS].out_flags & SLAPD_POLL_FLAGS ) {
+ tcps = n_tcps;
+ } else if ( s_tcps != NULL &&
+ the_connection_table->fd[FDS_S_TCPS].out_flags & SLAPD_POLL_FLAGS ) {
+ tcps = s_tcps;
+ secure = 1;
+ }
+ /* If so, then handle a new connection */
+ if ( tcps != NULL ) {
+ handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,tcps,secure);
+ }
+ /* handle new data ready */
+ handle_pr_read_ready(the_connection_table, connection_table_size);
+ clear_signal(the_connection_table->fd);
+#endif
+ break;
+ }
+
+ }
+ /* We get here when the server is shutting down */
+ /* Do what we have to do before death */
+
+ connection_table_abandon_all_operations(the_connection_table); /* abandon all operations in progress */
+
+ if ( ! in_referral_mode ) {
+ ps_stop_psearch_system(); /* stop any persistent searches */
+ }
+
+#ifdef _WIN32
+ if ( n_tcps != SLAPD_INVALID_SOCKET ) {
+ closesocket( n_tcps );
+#else
+ if ( n_tcps != NULL ) {
+ PR_Close( n_tcps );
+#endif
+ }
+ if ( s_tcps != NULL ) {
+ PR_Close( s_tcps );
+ }
+
+ /* Might compete with housecleaning thread, but so far so good */
+ be_flushall();
+ op_thread_cleanup();
+ housekeeping_stop(); /* Run this after op_thread_cleanup() logged sth */
+
+#ifndef _WIN32
+ if ( active_threads > 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "slapd shutting down - waiting for %d thread%s to terminate\n",
+ active_threads, ( active_threads > 1 ) ? "s" : "", 0 );
+ }
+#endif
+
+ threads = active_threads;
+ while ( active_threads > 0 ) {
+ PRPollDesc xpd;
+ char x;
+ int spe = 0;
+
+ /* try to read from the signal pipe, in case threads are
+ * blocked on it. */
+ xpd.fd = signalpipe[0];
+ xpd.in_flags = PR_POLL_READ;
+ xpd.out_flags = 0;
+ spe = PR_Poll(&xpd, 1, PR_INTERVAL_NO_WAIT);
+ if (spe > 0) {
+ spe = PR_Read(signalpipe[0], &x, 1);
+ if (spe < 0) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "listener could not clear signal pipe, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_system_strerror(prerr), 0 );
+ break;
+ }
+ } else if (spe == -1) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "PR_Poll() failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_system_strerror(prerr), 0 );
+ break;
+ } else {
+ /* no data */
+ }
+ DS_Sleep(PR_INTERVAL_NO_WAIT);
+ if ( threads != active_threads ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "slapd shutting down - waiting for %d threads to terminate\n",
+ active_threads, 0, 0 );
+ threads = active_threads;
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "slapd shutting down - closing down internal subsystems and plugins\n",
+ 0, 0, 0 );
+
+ log_access_flush();
+
+ /* let backends do whatever cleanup they need to do */
+ LDAPDebug( LDAP_DEBUG_TRACE,"slapd shutting down - waiting for backends to close down\n", 0, 0,0 );
+
+ eq_stop();
+ if ( ! in_referral_mode ) {
+ task_shutdown();
+ uniqueIDGenCleanup ();
+ }
+
+ plugin_closeall( 1 /* Close Backends */, 1 /* Close Gloabls */);
+
+ if ( ! in_referral_mode ) {
+ /* Close SNMP collator after the plugins closed...
+ * Replication plugin still performs internal ops that
+ * may try to increment snmp stats.
+ * Fix for defect 523780
+ */
+ snmp_collator_stop();
+ mapping_tree_free ();
+ }
+
+ be_cleanupall ();
+ LDAPDebug( LDAP_DEBUG_TRACE, "slapd shutting down - backends closed down\n",
+ 0, 0, 0 );
+ referrals_free();
+
+ connection_table_free(the_connection_table);
+ the_connection_table= NULL;
+
+ /* tell the time thread to shutdown and then wait for it */
+ time_shutdown = 1;
+ PR_JoinThread( time_thread_p );
+
+#ifdef _WIN32
+ WSACleanup();
+#endif
+}
+
+int signal_listner()
+{
+ /* Replaces previous macro---called to bump the thread out of select */
+#if defined( _WIN32 )
+ if ( PR_Write( signalpipe[1], "", 1) != 1 ) {
+ /* this now means that the pipe is full
+ * this is not a problem just go-on
+ */
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "listener could not write to signal pipe %d\n",
+ errno, 0, 0 );
+ }
+
+#else
+ if ( write( writesignalpipe, "", 1) != 1 ) {
+ /* this now means that the pipe is full
+ * this is not a problem just go-on
+ */
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "listener could not write to signal pipe %d\n",
+ errno, 0, 0 );
+ }
+#endif
+ return( 0 );
+}
+
+#ifdef _WIN32
+static int clear_signal(fd_set *readfdset)
+#else
+static int clear_signal(struct POLL_STRUCT *fds)
+#endif
+{
+#ifdef _WIN32
+ if ( FD_ISSET(readsignalpipe, readfdset)) {
+#else
+ if ( fds[FDS_SIGNAL_PIPE].out_flags & SLAPD_POLL_FLAGS ) {
+#endif
+ char buf[200];
+
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "listener got signaled\n",
+ 0, 0, 0 );
+#ifdef _WIN32
+ if ( PR_Read( signalpipe[0], buf, 20 ) < 1 ) {
+#else
+ if ( read( readsignalpipe, buf, 200 ) < 1 ) {
+#endif
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "listener could not clear signal pipe\n",
+ 0, 0, 0 );
+ }
+ }
+ return 0;
+}
+
+#ifdef _WIN32
+static void set_timeval_ms(struct timeval *t, int ms)
+{
+ t->tv_sec = ms/1000;
+ t->tv_usec = (ms % 1000)*1000;
+}
+#endif
+
+#ifdef _WIN32
+static void setup_read_fds(Connection_Table *ct, fd_set *readfds, int n_tcps, int s_tcps)
+{
+ Connection *c= NULL;
+ Connection *next= NULL;
+ int accept_new_connections;
+ static int last_accept_new_connections = -1;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ LBER_SOCKET socketdesc = SLAPD_INVALID_SOCKET;
+
+ FD_ZERO( readfds );
+
+ accept_new_connections = ((ct->size - g_get_current_conn_count())
+ > slapdFrontendConfig->reservedescriptors);
+ if ( ! accept_new_connections ) {
+ if ( last_accept_new_connections ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Not listening for new "
+ "connections - too many fds open\n", 0, 0, 0 );
+ }
+ } else {
+ if ( ! last_accept_new_connections &&
+ last_accept_new_connections != -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Listening for new "
+ "connections again\n", 0, 0, 0 );
+ }
+ }
+ last_accept_new_connections = accept_new_connections;
+ if (n_tcps != SLAPD_INVALID_SOCKET && accept_new_connections) {
+ FD_SET( n_tcps, readfds );
+ LDAPDebug( LDAP_DEBUG_HOUSE,
+ "listening for connections on %d\n", n_tcps, 0, 0 );
+ }
+ if (s_tcps != SLAPD_INVALID_SOCKET && accept_new_connections) {
+ FD_SET( s_tcps, readfds );
+ LDAPDebug( LDAP_DEBUG_HOUSE,
+ "listening for connections on %d\n", s_tcps, 0, 0 );
+ }
+
+ if ((s_tcps != SLAPD_INVALID_SOCKET)
+ && (readsignalpipe != SLAPD_INVALID_SOCKET)) {
+ FD_SET( readsignalpipe, readfds );
+ }
+
+ /* Walk down the list of active connections to find
+ * out which connections we should poll over. If a connection
+ * is no longer in use, we should remove it from the linked
+ * list. */
+ c= connection_table_get_first_active_connection (ct);
+ while (c)
+ {
+ next = connection_table_get_next_active_connection (ct, c);
+ if ( c->c_mutex == NULL )
+ {
+ connection_table_move_connection_out_of_active_list(ct,c);
+ }
+ else
+ {
+ PR_Lock( c->c_mutex );
+ if ( c->c_flags & CONN_FLAG_CLOSING )
+ {
+ /* A worker thread has marked that this connection
+ * should be closed by calling disconnect_server.
+ * move this connection out of the active list
+ * the last thread to use the connection will close it
+ */
+ connection_table_move_connection_out_of_active_list(ct,c);
+ }
+ else if ( c->c_sd == SLAPD_INVALID_SOCKET )
+ {
+ connection_table_move_connection_out_of_active_list(ct,c);
+ }
+ else
+ {
+#if defined(LDAP_IOCP) /* When we have IO completion ports, we don't want to do this */
+ if ( !c->c_gettingber && (c->c_flags & CONN_FLAG_SSL) )
+#else
+ if ( !c->c_gettingber )
+#endif
+ {
+ FD_SET( c->c_sd, readfds );
+ }
+ }
+ PR_Unlock( c->c_mutex );
+ }
+ c = next;
+ }
+}
+#endif /* _WIN32 */
+
+static int first_time_setup_pr_read_pds = 1;
+static void
+setup_pr_read_pds(Connection_Table *ct, PRFileDesc *n_tcps, PRFileDesc *s_tcps, PRIntn *num_to_read)
+{
+ Connection *c= NULL;
+ Connection *next= NULL;
+ LBER_SOCKET socketdesc = SLAPD_INVALID_SOCKET;
+ int accept_new_connections;
+ static int last_accept_new_connections = -1;
+ PRIntn count = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int max_threads_per_conn = config_get_maxthreadsperconn();
+
+ accept_new_connections = ((ct->size - g_get_current_conn_count())
+ > slapdFrontendConfig->reservedescriptors);
+ if ( ! accept_new_connections ) {
+ if ( last_accept_new_connections ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Not listening for new "
+ "connections - too many fds open\n", 0, 0, 0 );
+ /* reinitialize n_tcps and s_tcps to the pds */
+ first_time_setup_pr_read_pds = 1;
+ }
+ } else {
+ if ( ! last_accept_new_connections &&
+ last_accept_new_connections != -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Listening for new "
+ "connections again\n", 0, 0, 0 );
+ /* reinitialize n_tcps and s_tcps to the pds */
+ first_time_setup_pr_read_pds = 1;
+ }
+ }
+ last_accept_new_connections = accept_new_connections;
+
+
+ /* initialize the mapping from connection table entries to fds entries */
+ if (first_time_setup_pr_read_pds)
+ {
+ int i;
+ for (i = 0; i < ct->size; i++)
+ {
+ ct->c[i].c_fdi = SLAPD_INVALID_SOCKET_INDEX;
+ }
+
+ /* The fds entry for n_tcps is always FDS_N_TCPS */
+ if (n_tcps != NULL && accept_new_connections)
+ {
+ ct->fd[FDS_N_TCPS].fd = n_tcps;
+ ct->fd[FDS_N_TCPS].in_flags = SLAPD_POLL_FLAGS;
+ ct->fd[FDS_N_TCPS].out_flags = 0;
+ LDAPDebug( LDAP_DEBUG_HOUSE,
+ "listening for connections on %d\n", socketdesc, 0, 0 );
+ } else {
+ ct->fd[FDS_N_TCPS].fd = NULL;
+ }
+
+ /* The fds entry for s_tcps is always FDS_S_TCPS */
+ if (s_tcps != NULL && accept_new_connections)
+ {
+ ct->fd[FDS_S_TCPS].fd = s_tcps;
+ ct->fd[FDS_S_TCPS].in_flags = SLAPD_POLL_FLAGS;
+ ct->fd[FDS_S_TCPS].out_flags = 0;
+ LDAPDebug( LDAP_DEBUG_HOUSE,
+ "listening for SSL connections on %d\n", socketdesc, 0, 0 );
+ } else {
+ ct->fd[FDS_S_TCPS].fd = NULL;
+ }
+
+#if !defined(_WIN32)
+ /* The fds entry for the signalpipe is always FDS_SIGNAL_PIPE */
+ ct->fd[FDS_SIGNAL_PIPE].fd = signalpipe[0];
+ ct->fd[FDS_SIGNAL_PIPE].in_flags = SLAPD_POLL_FLAGS;
+ ct->fd[FDS_SIGNAL_PIPE].out_flags = 0;
+#else
+ ct->fd[FDS_SIGNAL_PIPE].fd = NULL;
+#endif
+ first_time_setup_pr_read_pds = 0;
+ }
+
+ /* count is the number of entries we've place in the fds array.
+ * we always put n_tcps in slot FDS_N_TCPS, s_tcps in slot
+ * FDS_S_TCPS and the signal pipe in slot FDS_SIGNAL_PIPE
+ * so we now set count to 3 */
+ count = 3;
+
+ /* Walk down the list of active connections to find
+ * out which connections we should poll over. If a connection
+ * is no longer in use, we should remove it from the linked
+ * list. */
+ c = connection_table_get_first_active_connection (ct);
+ while (c)
+ {
+ next = connection_table_get_next_active_connection (ct, c);
+ if ( c->c_mutex == NULL )
+ {
+ connection_table_move_connection_out_of_active_list(ct,c);
+ }
+ else
+ {
+ PR_Lock( c->c_mutex );
+ if (c->c_flags & CONN_FLAG_CLOSING)
+ {
+ /* A worker thread has marked that this connection
+ * should be closed by calling disconnect_server.
+ * move this connection out of the active list
+ * the last thread to use the connection will close it
+ */
+ connection_table_move_connection_out_of_active_list(ct,c);
+ }
+ else if ( c->c_sd == SLAPD_INVALID_SOCKET )
+ {
+ connection_table_move_connection_out_of_active_list(ct,c);
+ }
+ else if ( c->c_prfd != NULL)
+ {
+ if ((!c->c_gettingber)
+ && (c->c_threadnumber < max_threads_per_conn))
+ {
+ ct->fd[count].fd = c->c_prfd;
+ ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
+ /* slot i of the connection table is mapped to slot
+ * count of the fds array */
+ c->c_fdi = count;
+ count++;
+ }
+ else
+ {
+ c->c_fdi = SLAPD_INVALID_SOCKET_INDEX;
+ }
+ }
+ PR_Unlock( c->c_mutex );
+ }
+ c = next;
+ }
+
+ if( num_to_read )
+ (*num_to_read) = count;
+
+}
+
+#ifdef notdef /* GGOODREPL */
+static void
+handle_timeout( void )
+{
+ static time_t prevtime = 0;
+ static time_t housekeeping_fire_time = 0;
+ time_t curtime = current_time();
+
+ if (0 == prevtime) {
+ prevtime = time (&housekeeping_fire_time);
+ }
+
+ if ( difftime(curtime, prevtime) >=
+ slapd_housekeeping_timer ) {
+ int num_active_threads;
+
+ snmp_collator_update();
+
+ prevtime = curtime;
+ num_active_threads = active_threads;
+ if ( (num_active_threads == 0) ||
+ (difftime(curtime, housekeeping_fire_time) >=
+ slapd_housekeeping_timer*3) ) {
+ housekeeping_fire_time = curtime;
+ housekeeping_start(curtime);
+ }
+ }
+
+}
+#endif /* notdef */
+
+
+static int idletimeout_reslimit_handle = -1;
+
+/*
+ * Register the idletimeout with the binder-based resource limits
+ * subsystem. A SLAPI_RESLIMIT_STATUS_... code is returned.
+ */
+int
+daemon_register_reslimits( void )
+{
+ return( slapi_reslimit_register( SLAPI_RESLIMIT_TYPE_INT, "nsIdleTimeout",
+ &idletimeout_reslimit_handle ));
+}
+
+
+/*
+ * Compute the idle timeout for the connection.
+ *
+ * Note: this function must always be called with conn->c_mutex locked.
+ */
+static int
+compute_idletimeout( slapdFrontendConfig_t *fecfg, Connection *conn )
+{
+ int idletimeout;
+
+ if ( slapi_reslimit_get_integer_limit( conn, idletimeout_reslimit_handle,
+ &idletimeout ) != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ /*
+ * no limit associated with binder/connection or some other error
+ * occurred. use the default idle timeout.
+ */
+ if ( conn->c_isroot ) {
+ idletimeout = 0; /* no limit for Directory Manager */
+ } else {
+ idletimeout = fecfg->idletimeout;
+ }
+ }
+
+ return( idletimeout );
+}
+
+
+#ifdef _WIN32
+static void
+handle_read_ready(Connection_Table *ct, fd_set *readfds)
+{
+ Connection *c= NULL;
+ time_t curtime = current_time();
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int idletimeout;
+
+#ifdef LDAP_DEBUG
+ if ( slapd_ldap_debug & LDAP_DEBUG_CONNS )
+ {
+ connection_table_dump_activity_to_errors_log(ct);
+ }
+#endif /* LDAP_DEBUG */
+
+
+ /* Instead of going through the whole connection table to see which
+ * connections we can read from, we'll only check the slots in the
+ * linked list */
+ c = connection_table_get_first_active_connection (ct);
+ while ( c!=NULL )
+ {
+ if ( c->c_mutex != NULL )
+ {
+ PR_Lock( c->c_mutex );
+ if (connection_is_active_nolock (c) && c->c_gettingber == 0 )
+ {
+ /* read activity */
+ short readready= ( FD_ISSET( c->c_sd, readfds ) );
+
+ /* read activity */
+ if ( readready )
+ {
+ LDAPDebug( LDAP_DEBUG_CONNS, "read activity on %d\n", c->c_ci, 0, 0 );
+ c->c_idlesince = curtime;
+
+ /* This is where the work happens ! */
+ connection_activity( c );
+
+ /* idle timeout */
+ }
+ else if (( idletimeout = compute_idletimeout(
+ slapdFrontendConfig, c )) > 0 &&
+ (curtime - c->c_idlesince) >= idletimeout &&
+ NULL == c->c_ops )
+ {
+ disconnect_server_nomutex( c, c->c_connid, -1,
+ SLAPD_DISCONNECT_IDLE_TIMEOUT, EAGAIN );
+ }
+ }
+ PR_Unlock( c->c_mutex );
+ }
+ c = connection_table_get_next_active_connection (ct, c);
+ }
+}
+#endif /* _WIN32 */
+
+
+static void
+handle_pr_read_ready(Connection_Table *ct, PRIntn num_poll)
+{
+ Connection *c;
+ time_t curtime = current_time();
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int idletimeout;
+#if defined( XP_WIN32 )
+ int i;
+#endif
+
+#if LDAP_DEBUG
+ if ( slapd_ldap_debug & LDAP_DEBUG_CONNS )
+ {
+ connection_table_dump_activity_to_errors_log(ct);
+ }
+#endif /* LDAP_DEBUG */
+
+#if defined( XP_WIN32 )
+ /*
+ * WIN32: this function is only called for SSL connections and
+ * num_poll indicates exactly how many PR fds we polled on.
+ */
+ for ( i = 0; i < num_poll; i++ )
+ {
+ short readready;
+ readready = (ct->fd[i].out_flags & SLAPD_POLL_FLAGS);
+
+ /* Find the connection we are referring to */
+ for ( c = connection_table_get_first_active_connection (ct); c != NULL;
+ c = connection_table_get_next_active_connection (ct, c) )
+ {
+ if ( c->c_mutex != NULL )
+ {
+ PR_Lock( c->c_mutex );
+ if ( c->c_prfd == ct->fd[i].fd )
+ {
+ break; /* c_mutex is still locked! */
+ }
+ PR_Unlock( c->c_mutex );
+ }
+ }
+
+ if ( c == NULL )
+ { /* connection not found! */
+ LDAPDebug( LDAP_DEBUG_CONNS, "handle_pr_read_ready: "
+ "connection not found for poll slot %d\n", i,0,0 );
+ }
+ else
+ {
+ /* c_mutex is still locked... check for activity and errors */
+ if ( !readready && ct->fd[i].out_flags && c->c_prfd == ct->fd[i].fd )
+ {
+ /* some error occured */
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "poll says connection on sd %d is bad "
+ "(closing)\n", c->c_sd, 0, 0 );
+ disconnect_server_nomutex( c, c->c_connid, -1, SLAPD_DISCONNECT_POLL, EPIPE );
+ }
+ else if ( readready && c->c_prfd == ct->fd[i].fd )
+ {
+ /* read activity */
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "read activity on %d\n", i, 0, 0 );
+ c->c_idlesince = curtime;
+
+ /* This is where the work happens ! */
+ connection_activity( c );
+ }
+ else if (( idletimeout = compute_idletimeout( slapdFrontendConfig,
+ c )) > 0 &&
+ c->c_prfd == ct->fd[i].fd &&
+ (curtime - c->c_idlesince) >= idletimeout &&
+ NULL == c->c_ops )
+ {
+ /* idle timeout */
+ disconnect_server_nomutex( c, c->c_connid, -1,
+ SLAPD_DISCONNECT_IDLE_TIMEOUT, EAGAIN );
+ }
+
+ PR_Unlock( c->c_mutex );
+ }
+ }
+#else
+
+ /*
+ * non-WIN32: this function is called for all connections, so we
+ * traverse the entire active connection list to find any errors,
+ * activity, etc.
+ */
+ for ( c = connection_table_get_first_active_connection (ct); c != NULL;
+ c = connection_table_get_next_active_connection (ct, c) )
+ {
+ if ( c->c_mutex != NULL )
+ {
+ PR_Lock( c->c_mutex );
+ if ( connection_is_active_nolock (c) && c->c_gettingber == 0 )
+ {
+ PRInt16 out_flags;
+ short readready;
+
+ if (c->c_fdi != SLAPD_INVALID_SOCKET_INDEX)
+ {
+ out_flags = ct->fd[c->c_fdi].out_flags;
+ }
+ else
+ {
+ out_flags = 0;
+ }
+
+ readready = ( out_flags & SLAPD_POLL_FLAGS );
+
+ if ( !readready && out_flags )
+ {
+ /* some error occured */
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "POLL_FN() says connection on sd %d is bad "
+ "(closing)\n", c->c_sd, 0, 0 );
+ disconnect_server_nomutex( c, c->c_connid, -1,
+ SLAPD_DISCONNECT_POLL, EPIPE );
+ }
+ else if ( readready )
+ {
+ /* read activity */
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "read activity on %d\n", c->c_ci, 0, 0 );
+ c->c_idlesince = curtime;
+
+ /* This is where the work happens ! */
+ /* MAB: 25 jan 01, error handling added */
+ if ((connection_activity( c )) == -1) {
+ /* This might happen as a result of
+ * trying to acquire a closing connection
+ */
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "connection_activity: abandoning conn %d as fd=%d is already closing\n",
+ c->c_connid,c->c_sd,0);
+ /* The call disconnect_server should do nothing,
+ * as the connection c should be already set to CLOSING */
+ disconnect_server_nomutex( c, c->c_connid, -1,
+ SLAPD_DISCONNECT_POLL, EPIPE );
+ }
+ }
+ else if (( idletimeout = compute_idletimeout(
+ slapdFrontendConfig, c )) > 0 &&
+ (curtime - c->c_idlesince) >= idletimeout &&
+ NULL == c->c_ops )
+ {
+ /* idle timeout */
+ disconnect_server_nomutex( c, c->c_connid, -1,
+ SLAPD_DISCONNECT_IDLE_TIMEOUT, EAGAIN );
+ }
+ }
+ PR_Unlock( c->c_mutex );
+ }
+ }
+#endif
+}
+
+/*
+ * wrapper functions required so we can implement ioblock_timeout and
+ * avoid blocking forever.
+ */
+
+#define SLAPD_POLLIN 0
+#define SLAPD_POLLOUT 1
+
+/* Return 1 if the given handle is ready for input or output,
+ * or if it becomes ready within g_ioblock_timeout [msec].
+ * Return -1 if handle is not ready and g_ioblock_timeout > 0,
+ * or something goes seriously wrong. Otherwise, return 0.
+ * If -1 is returned, PR_GetError() explains why.
+ * Revision: handle changed to void * to allow 64bit support
+ */
+static int
+slapd_poll( void *handle, int output, int secure )
+{
+ int rc;
+ int ioblock_timeout = config_get_ioblocktimeout();
+
+#if defined( XP_WIN32 )
+ if( !secure ) {
+ fd_set handle_set;
+ struct timeval timeout;
+ int windows_handle = (int) handle;
+
+ memset (&timeout, 0, sizeof(timeout));
+ if (ioblock_timeout > 0) {
+ timeout.tv_sec = ioblock_timeout / 1000;
+ timeout.tv_usec = (ioblock_timeout % 1000) * 1000;
+ }
+ FD_ZERO(&handle_set);
+ FD_SET(windows_handle, &handle_set);
+ rc = output ? select(FD_SETSIZE, NULL, &handle_set, NULL, &timeout)
+ : select(FD_SETSIZE, &handle_set, NULL, NULL, &timeout);
+ } else {
+ struct POLL_STRUCT pr_pd;
+ PRIntervalTime timeout = PR_MillisecondsToInterval( ioblock_timeout );
+
+ if (timeout < 0) timeout = 0;
+ pr_pd.fd = (PRFileDesc *)handle;
+ pr_pd.in_flags = output ? PR_POLL_WRITE : PR_POLL_READ;
+ pr_pd.out_flags = 0;
+ rc = POLL_FN(&pr_pd, 1, timeout);
+ }
+#else
+ struct POLL_STRUCT pr_pd;
+ PRIntervalTime timeout = PR_MillisecondsToInterval(ioblock_timeout);
+
+ if (timeout < 0) timeout = 0;
+ pr_pd.fd = (PRFileDesc *)handle;
+ pr_pd.in_flags = output ? PR_POLL_WRITE : PR_POLL_READ;
+ pr_pd.out_flags = 0;
+ rc = POLL_FN(&pr_pd, 1, timeout);
+#endif
+
+ if (rc < 0) {
+#if defined( XP_WIN32 )
+ if( !secure ) {
+ int oserr = errno;
+
+ LDAPDebug(LDAP_DEBUG_CONNS, "slapd_poll(%d) error %d (%s)\n",
+ handle, oserr, slapd_system_strerror(oserr));
+ if ( SLAPD_SYSTEM_WOULD_BLOCK_ERROR(oserr)) {
+ rc = 0; /* try again */
+ }
+ } else {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_CONNS, "slapd_poll(%d) "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ handle, prerr, slapd_pr_strerror(prerr));
+ if ( prerr == PR_PENDING_INTERRUPT_ERROR ||
+ SLAPD_PR_WOULD_BLOCK_ERROR(prerr)) {
+ rc = 0; /* try again */
+ }
+ }
+#else
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY, "slapd_poll(%d) "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ handle, prerr, slapd_pr_strerror(prerr));
+ if ( prerr == PR_PENDING_INTERRUPT_ERROR ||
+ SLAPD_PR_WOULD_BLOCK_ERROR(prerr)) {
+ rc = 0; /* try again */
+ }
+#endif
+
+ } else if (rc == 0 && ioblock_timeout > 0) {
+ PRIntn ihandle;
+#if !defined( XP_WIN32 )
+ ihandle = PR_FileDesc2NativeHandle((PRFileDesc *)handle);
+#else
+ if( secure )
+ ihandle = PR_FileDesc2NativeHandle((PRFileDesc *)handle);
+ else
+ ihandle = (PRIntn)handle;
+#endif
+ LDAPDebug(LDAP_DEBUG_ANY, "slapd_poll(%d) timed out\n",
+ ihandle, 0, 0);
+#if defined( XP_WIN32 )
+ /*
+ * Bug 624303 - This connection will be cleaned up soon.
+ * During cleanup (see connection_cleanup()), SSL3_SendAlert()
+ * will be called by PR_Close(), and its default wTimeout
+ * in sslSocket associated with the handle
+ * is no time out (I gave up after waited for 30 minutes).
+ * It was during this closing period that server won't
+ * response to new connection requests.
+ * PR_Send() null is a hack here to change the default wTimeout
+ * (see ssl_Send()) to one second which affects PR_Close()
+ * only in the current scenario.
+ */
+ if( secure ) {
+ PR_Send ((PRFileDesc *)handle, NULL, 0, 0, PR_SecondsToInterval(1));
+ }
+#endif
+ PR_SetError(PR_IO_TIMEOUT_ERROR, EAGAIN); /* timeout */
+ rc = -1;
+ }
+ return rc;
+}
+
+/* The following 4 functions each read or write count bytes from or to
+ * a socket handle. If all goes well, they return the same count;
+ * otherwise they return -1 and PR_GetError() explains the problem.
+ * Revision: handle changed to struct lextiof_socket_private * and first
+ * argument which used to be handle is now ignored.
+ */
+int
+secure_read_function( int ignore, void *buffer, int count, struct lextiof_socket_private *handle )
+{
+ int gotbytes = 0;
+ int bytes;
+ int ioblock_timeout = config_get_ioblocktimeout();
+ PRIntervalTime pr_timeout = PR_MillisecondsToInterval(ioblock_timeout);
+
+ if (handle == SLAPD_INVALID_SOCKET) {
+ PR_SetError(PR_NOT_SOCKET_ERROR, EBADF);
+ } else {
+ while (1) {
+ bytes = PR_Recv( (PRFileDesc *)handle, (char *)buffer + gotbytes,
+ count - gotbytes, 0, pr_timeout );
+ if (bytes > 0) {
+ gotbytes += bytes;
+ } else if (bytes < 0) {
+ PRErrorCode prerr = PR_GetError();
+
+#ifdef _WIN32
+ /* we need to do this because on NT, once an I/O
+ times out on an NSPR socket, that socket must
+ be closed before any other I/O can happen in
+ this thread.
+ */
+ if (prerr == PR_IO_TIMEOUT_ERROR){
+ Connection *conn = connection_table_get_connection_from_fd(the_connection_table,(PRFileDesc *)handle);
+ if (conn == NULL)
+ return -1;
+
+ disconnect_server (conn, conn->c_connid, -1, SLAPD_DISCONNECT_NTSSL_TIMEOUT, 0);
+ /* Disconnect_server just tells the poll thread that the
+ * socket should be closed. We'll sleep 2 seconds here to
+ * to make sure that the poll thread has time to run
+ * and close this socket. */
+ DS_Sleep(PR_SecondsToInterval(2));
+
+ LDAPDebug(LDAP_DEBUG_CONNS, "SSL PR_Recv(%d) "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ handle, prerr, slapd_pr_strerror(prerr));
+
+ return -1;
+ }
+#endif
+
+ LDAPDebug(LDAP_DEBUG_CONNS,
+ "SSL PR_Recv(%d) error %d (%s)\n",
+ handle, prerr, slapd_pr_strerror(prerr));
+ if ( !SLAPD_PR_WOULD_BLOCK_ERROR(prerr) ) {
+ break; /* fatal error */
+ }
+ } else if (gotbytes < count) {
+ LDAPDebug(LDAP_DEBUG_CONNS,
+ "SSL PR_Recv(%d) 0 (EOF)\n", /* disconnected */
+ handle, 0, 0);
+ PR_SetError(PR_PIPE_ERROR, EPIPE);
+ break;
+ }
+ if (gotbytes == count) { /* success */
+ return count;
+ } else if (gotbytes > count) { /* too many bytes */
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, EMSGSIZE);
+ break;
+ } else if (slapd_poll(handle, SLAPD_POLLIN, 1) < 0) { /* error */
+ break;
+ }
+ }
+ }
+ return -1;
+}
+
+
+/*
+ * Revision: handle changed to struct lextiof_socket_private * and first
+ * argument which used to be handle is now ignored.
+ */
+int
+secure_write_function( int ignore, const void *buffer, int count, struct lextiof_socket_private *handle )
+{
+ int sentbytes = 0;
+ int bytes;
+
+ if (handle == SLAPD_INVALID_SOCKET) {
+ PR_SetError(PR_NOT_SOCKET_ERROR, EBADF);
+ } else {
+ while (1) {
+ if (slapd_poll(handle, SLAPD_POLLOUT, 1) < 0) { /* error */
+ break;
+ }
+ bytes = PR_Write((PRFileDesc *)handle, (char *)buffer + sentbytes,
+ count - sentbytes);
+ if (bytes > 0) {
+ sentbytes += bytes;
+ } else if (bytes < 0) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_CONNS, "SSL PR_Write(%d) "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ handle, prerr, slapd_pr_strerror( prerr ));
+ if ( !SLAPD_PR_WOULD_BLOCK_ERROR(prerr)) {
+ break; /* fatal error */
+ }
+ } else if (sentbytes < count) {
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "SSL PR_Write(%d) 0\n", /* ??? */ handle, 0, 0);
+ PR_SetError(PR_PIPE_ERROR, EPIPE);
+ break;
+ }
+ if (sentbytes == count) { /* success */
+ return count;
+ } else if (sentbytes > count) { /* too many bytes */
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, EMSGSIZE);
+ break;
+ }
+ }
+ }
+ return -1;
+}
+
+/* stub functions required because we need to call send/recv on NT,
+ * but the SDK requires functions with a read/write signature.
+ * Revision: handle changed to struct lextiof_socket_private * and first
+ * argument which used to be handle is now ignored.
+ */
+int
+read_function(int ignore, void *buffer, int count, struct lextiof_socket_private *handle )
+{
+ int gotbytes = 0;
+ int bytes;
+#if !defined( XP_WIN32 )
+ PRIntervalTime pr_timeout = PR_MillisecondsToInterval(1000);
+#endif
+
+ if (handle == SLAPD_INVALID_SOCKET) {
+ PR_SetError(PR_NOT_SOCKET_ERROR, EBADF);
+ } else {
+ while (1) {
+#if !defined( XP_WIN32 )
+ bytes = PR_Recv((PRFileDesc *)handle, (char *)buffer + gotbytes,
+ count - gotbytes, 0, pr_timeout);
+#else
+ bytes = recv((int)handle, (char *)buffer + gotbytes,
+ count - gotbytes, 0);
+#endif
+ if (bytes > 0) {
+ gotbytes += bytes;
+ } else if (bytes < 0) {
+#if !defined( XP_WIN32 )
+ PRErrorCode prerr = PR_GetError();
+
+ LDAPDebug(LDAP_DEBUG_CONNS, "PR_Recv(%d) "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ handle, prerr, slapd_pr_strerror( prerr ));
+ if ( !SLAPD_PR_WOULD_BLOCK_ERROR(prerr)) {
+#else
+ int oserr = errno;
+
+ LDAPDebug(LDAP_DEBUG_CONNS, "recv(%d) OS error %d (%s)\n",
+ handle, oserr, slapd_system_strerror(oserr));
+ if ( !SLAPD_SYSTEM_WOULD_BLOCK_ERROR(oserr)) {
+ PR_SetError(PR_UNKNOWN_ERROR, oserr);
+#endif
+ break; /* fatal error */
+ }
+ } else if (gotbytes < count) { /* disconnected */
+#if !defined( XP_WIN32 )
+ LDAPDebug(LDAP_DEBUG_CONNS, "PR_Recv(%d) 0 (EOF)\n",
+ handle, 0, 0);
+#else
+ LDAPDebug(LDAP_DEBUG_CONNS, "recv(%d) 0 (EOF)\n",
+ handle, 0, 0);
+#endif
+ PR_SetError(PR_PIPE_ERROR, EPIPE);
+ break;
+ }
+ if (gotbytes == count) { /* success */
+ return count;
+ } else if (gotbytes > count) { /* too many bytes */
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, EMSGSIZE);
+ break;
+ }
+ /* we did not get the whole PDU
+ * call slapd_poll before starting a new read to get
+ * sure some new data have been received and
+ * thus avoid active looping in the while
+ */
+ if (slapd_poll(handle, SLAPD_POLLIN, 0) < 0) {
+ break;
+ }
+ }
+ }
+ return -1;
+}
+
+/*
+Slapd's old (3.x) network I/O code works something like this:
+ when I want to send some data to the client, I will call send().
+ That might block for a long time, resulting in thread pool starvation,
+ so let's not call it unless we're sure that data can be buffered
+ locally. The mechanism for achieving this is to call select()
+ (poll() on UNIX), on the target socket, passing a short timeout
+ (configurable via cn=config).
+
+ Now, this means that to send some data we're making two system
+ calls. Slowness results.
+
+ I did some research and found the following in the MSDN
+ that NT4.0 and beyond do support the configuration of a send timeout
+ on sockets, so this is code which makes use of that and saves the
+ call to select.
+*/
+
+/*Revision: handle changed from int to void * to allow 64bit support
+ *
+ */
+static int send_with_timeout(void *handle, const char * buffer, int count,int *bytes_sent)
+{
+ int ret = 0;
+#if defined( XP_WIN32 )
+ *bytes_sent = send((SOCKET)handle, buffer,count,0);
+#else
+ *bytes_sent = PR_Write((PRFileDesc *)handle,buffer,count);
+ if (*bytes_sent < 0)
+ {
+ PRErrorCode prerr = PR_GetError();
+ if (SLAPD_PR_WOULD_BLOCK_ERROR(prerr))
+ {
+ if ((ret = slapd_poll(handle, SLAPD_POLLOUT, 0)) < 0)
+ { /* error */
+ *bytes_sent = 0;
+ return ret;
+ }
+
+ }
+ }
+#endif
+
+ return ret;
+}
+
+int
+write_function(int ignore, const void *buffer, int count, struct lextiof_socket_private *handle)
+{
+ int sentbytes = 0;
+ int bytes;
+
+
+ if (handle == SLAPD_INVALID_SOCKET) {
+ PR_SetError(PR_NOT_SOCKET_ERROR, EBADF);
+ } else {
+ while (1) {
+
+ if (send_with_timeout(handle, (char *)buffer + sentbytes, count - sentbytes,&bytes) < 0) { /* error */
+ break;
+ }
+ if (bytes > 0) {
+ sentbytes += bytes;
+ } else if (bytes < 0) {
+#if !defined( XP_WIN32 )
+ PRErrorCode prerr = PR_GetError();
+
+ LDAPDebug(LDAP_DEBUG_CONNS, "PR_Write(%d) "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ handle, prerr, slapd_pr_strerror(prerr));
+ if ( !SLAPD_PR_WOULD_BLOCK_ERROR(prerr)) {
+#else
+ int oserr = errno; /* DBDB this is almost certainly wrong, should be a call to WSAGetLastError() */
+
+ LDAPDebug(LDAP_DEBUG_CONNS, "send(%d) error %d (%s)\n",
+ handle, oserr, slapd_system_strerror(oserr));
+ if ( !SLAPD_SYSTEM_WOULD_BLOCK_ERROR(oserr)) {
+ PR_SetError(PR_UNKNOWN_ERROR, oserr);
+#endif
+ break; /* fatal error */
+ }
+ } else if (sentbytes < count) {
+ LDAPDebug(LDAP_DEBUG_CONNS, "send(%d) 0\n", /* ??? */
+ handle, 0, 0);
+ PR_SetError(PR_PIPE_ERROR, EPIPE);
+ break;
+ }
+ if (sentbytes == count) { /* success */
+ return count;
+ } else if (sentbytes > count) { /* too many bytes */
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, EMSGSIZE);
+ break;
+ }
+ }
+ }
+ return -1;
+}
+
+int connection_type = -1; /* The type number assigned by the Factory for 'Connection' */
+
+void
+daemon_register_connection()
+{
+ if(connection_type==-1)
+ {
+ /* The factory is given the name of the object type, in
+ * return for a type handle. Whenever the object is created
+ * or destroyed the factory is called with the handle so
+ * that it may call the constructors or destructors registered
+ * with it.
+ */
+ connection_type= factory_register_type(SLAPI_EXT_CONNECTION,offsetof(Connection,c_extension));
+ }
+}
+
+/* NOTE: this routine is not reentrant */
+static int
+handle_new_connection(Connection_Table *ct, int tcps, PRFileDesc *pr_acceptfd, int secure)
+{
+ int ns = 0;
+ Connection *conn = NULL;
+ /* struct sockaddr_in from;*/
+ PRNetAddr from;
+ PRFileDesc *pr_clonefd = NULL;
+
+ if ( (ns = accept_and_configure( tcps, pr_acceptfd, &from,
+ sizeof(from), secure, &pr_clonefd)) == SLAPD_INVALID_SOCKET ) {
+ return -1;
+ }
+
+ /* get a new Connection from the Connection Table */
+ conn= connection_table_get_connection(ct,ns);
+ if(conn==NULL)
+ {
+ PR_Close(pr_acceptfd);
+ return -1;
+ }
+ PR_Lock( conn->c_mutex );
+
+#if !defined( XP_WIN32 )
+ ber_sockbuf_set_option(conn->c_sb,LBER_SOCKBUF_OPT_DESC,&pr_clonefd);
+#else
+ if( !secure )
+ ber_sockbuf_set_option(conn->c_sb,LBER_SOCKBUF_OPT_DESC,&ns);
+ else
+ ber_sockbuf_set_option(conn->c_sb,LBER_SOCKBUF_OPT_DESC,&pr_clonefd);
+#endif
+
+ conn->c_sd = ns;
+ conn->c_prfd = pr_clonefd;
+ conn->c_flags &= ~CONN_FLAG_CLOSING;
+
+ /* Store the fact that this new connection is an SSL connection */
+ if (secure) {
+ conn->c_flags |= CONN_FLAG_SSL;
+ }
+
+#ifndef _WIN32
+ /*
+ * clear the "returned events" field in ns' slot within the poll fds
+ * array so that handle_read_ready() doesn't look at out_flags for an
+ * old connection by mistake and do something bad such as close the
+ * connection we just accepted.
+ */
+
+ /* Dont have to worry about this now because of our mapping from
+ * the connection table to the fds array. This new connection
+ * won't have a mapping. */
+ /* fds[ns].out_flags = 0; */
+#endif
+
+ if (secure) {
+ /*structure added to enable 64bit support changed from
+ *the commented code that follows each of the next two
+ *blocks of code
+ */
+ struct lber_x_ext_io_fns *func_pointers = malloc(LBER_X_EXTIO_FNS_SIZE);
+ func_pointers->lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ func_pointers->lbextiofn_read = secure_read_function;
+ func_pointers->lbextiofn_write = secure_write_function;
+ func_pointers->lbextiofn_writev = NULL;
+ func_pointers->lbextiofn_socket_arg = (struct lextiof_socket_private *) pr_clonefd;
+ ber_sockbuf_set_option( conn->c_sb,
+ LBER_SOCKBUF_OPT_EXT_IO_FNS, func_pointers);
+
+ /* changed here by Cheston
+ ber_sockbuf_set_option( conn->c_sb,
+ LBER_SOCKBUF_OPT_READ_FN, (void *)secure_read_function );
+ ber_sockbuf_set_option( conn->c_sb,
+ LBER_SOCKBUF_OPT_WRITE_FN, (void *)secure_write_function );
+ */
+ } else {
+ struct lber_x_ext_io_fns *func_pointers = malloc(LBER_X_EXTIO_FNS_SIZE);
+ func_pointers->lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ func_pointers->lbextiofn_read = read_function;
+ func_pointers->lbextiofn_write = write_function;
+ func_pointers->lbextiofn_writev = NULL;
+#ifdef _WIN32
+ func_pointers->lbextiofn_socket_arg = (struct lextiof_socket_private *) ns;
+#else
+ func_pointers->lbextiofn_socket_arg = (struct lextiof_socket_private *) pr_clonefd;
+#endif
+ ber_sockbuf_set_option( conn->c_sb,
+ LBER_SOCKBUF_OPT_EXT_IO_FNS, func_pointers);
+ /*
+ ber_sockbuf_set_option( conn->c_sb,
+ LBER_SOCKBUF_OPT_READ_FN, (void *)read_function );
+ ber_sockbuf_set_option( conn->c_sb,
+ LBER_SOCKBUF_OPT_WRITE_FN, (void *)write_function );
+ */
+ }
+
+#if defined(NET_SSL)
+ if( secure && config_get_SSLclientAuth() != SLAPD_SSLCLIENTAUTH_OFF ) {
+ /* Prepare to handle the client's certificate (if any): */
+ int rv;
+
+ rv = slapd_ssl_handshakeCallback (conn->c_prfd, (void*)handle_handshake_done, conn);
+
+ if (rv < 0) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug (LDAP_DEBUG_ANY, "SSL_HandshakeCallback() %d "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ rv, prerr, slapd_pr_strerror( prerr ));
+ }
+ rv = slapd_ssl_badCertHook (conn->c_prfd, (void*)handle_bad_certificate, conn);
+
+ if (rv < 0) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug (LDAP_DEBUG_ANY, "SSL_BadCertHook(%i) %i "
+ SLAPI_COMPONENT_NAME_NSPR " error %d\n",
+ conn->c_sd, rv, prerr);
+ }
+ }
+#endif
+
+ connection_reset(conn, ns, &from, sizeof(from), secure);
+
+ /* Call the plugin extension constructors */
+ conn->c_extension = factory_create_extension(connection_type,conn,NULL /* Parent */);
+
+
+ /* Add this connection slot to the doubly linked list of active connections. This
+ * list is used to find the connections that should be used in the poll call. This
+ * connection will be added directly after slot 0 which serves as the head of the list */
+ if ( conn != NULL && conn->c_next == NULL && conn->c_prev == NULL )
+ {
+ /* Now give the new connection to the connection code */
+ connection_table_move_connection_on_to_active_list(the_connection_table,conn);
+ }
+
+ PR_Unlock( conn->c_mutex );
+
+ connection_new_private(conn);
+
+ g_increment_current_conn_count();
+
+ return 0;
+}
+
+static int init_shutdown_detect()
+{
+
+#ifdef _WIN32
+ PRThread *service_exit_wait_tid;
+#else
+ /* First of all, we must reset the signal mask to get rid of any blockages
+ * the process may have inherited from its parent (such as the console), which
+ * might result in the process not delivering those blocked signals, and thus,
+ * misbehaving....
+ */
+ {
+ int rc;
+ sigset_t proc_mask;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "Reseting signal mask....\n", 0, 0, 0);
+ (void)sigemptyset( &proc_mask );
+ rc = pthread_sigmask( SIG_SETMASK, &proc_mask, NULL );
+ LDAPDebug( LDAP_DEBUG_TRACE, " %s \n",
+ rc ? "Failed to reset signal mask":"....Done (signal mask reset)!!", 0, 0 );
+ }
+#endif
+
+#ifdef _WIN32
+
+ /* Create a thread to wait on the Win32 event which will
+ be signalled by the watchdog when the Service is
+ being halted. */
+ service_exit_wait_tid = PR_CreateThread( PR_USER_THREAD,
+ (VFP) (void *) slapd_service_exit_wait, (void *) NULL,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if( service_exit_wait_tid == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Error: PR_CreateThread(slapd_service_exit_wait) failed\n", 0, 0, 0 );
+ }
+#elif defined ( HPUX10 )
+ PR_CreateThread ( PR_USER_THREAD,
+ catch_signals,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE);
+#else
+#ifdef HPUX11
+ /* In the optimized builds for HPUX, the signal handler doesn't seem
+ * to get set correctly unless the primordial thread gets a chance
+ * to run before we make the call to SIGNAL. (At this point the
+ * the primordial thread has spawned the daemon thread which called
+ * this function.) The call to DS_Sleep will give the primordial
+ * thread a chance to run.
+ */
+ DS_Sleep(0);
+#endif
+ (void) SIGNAL( SIGPIPE, SIG_IGN );
+ (void) SIGNAL( SIGCHLD, slapd_wait4child );
+#ifndef LINUX
+ /* linux uses USR1/USR2 for thread synchronization, so we aren't
+ * allowed to mess with those.
+ */
+ (void) SIGNAL( SIGUSR1, slapd_do_nothing );
+ (void) SIGNAL( SIGUSR2, set_shutdown );
+#endif
+ (void) SIGNAL( SIGTERM, set_shutdown );
+ (void) SIGNAL( SIGHUP, set_shutdown );
+#endif /* _WIN32 */
+ return 0;
+}
+
+#if defined( XP_WIN32 )
+static void
+unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, int n_tcps, PRFileDesc *s_tcps)
+#else
+static void
+unfurl_banners(Connection_Table *ct,daemon_ports_t *ports, PRFileDesc *n_tcps, PRFileDesc *s_tcps)
+#endif
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char addrbuf[ 256 ];
+
+ if ( ct->size <= slapdFrontendConfig->reservedescriptors ) {
+#ifdef _WIN32
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: Not enough descriptors to accept any connections. "
+ "This may be because the maxdescriptors configuration "
+ "directive is too small, or the reservedescriptors "
+ "configuration directive is too large. "
+ "Try increasing the number of descriptors available to "
+ "the slapd process. The current value is %d. %d "
+ "descriptors are currently reserved for internal "
+ "slapd use, so the total number of descriptors available "
+ "to the process must be greater than %d.\n",
+ ct->size, slapdFrontendConfig->reservedescriptors, slapdFrontendConfig->reservedescriptors );
+#else /* _WIN32 */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: Not enough descriptors to accept any connections. "
+ "This may be because the maxdescriptors configuration "
+ "directive is too small, the hard limit on descriptors is "
+ "too small (see limit(1)), or the reservedescriptors "
+ "configuration directive is too large. "
+ "Try increasing the number of descriptors available to "
+ "the slapd process. The current value is %d. %d "
+ "descriptors are currently reserved for internal "
+ "slapd use, so the total number of descriptors available "
+ "to the process must be greater than %d.\n",
+ ct->size, slapdFrontendConfig->reservedescriptors, slapdFrontendConfig->reservedescriptors );
+#endif /* _WIN32 */
+ exit( 1 );
+ }
+
+ /*
+ * This final startup message gives a definite signal to the admin
+ * program that the server is up. It must contain the string
+ * "slapd started." because some of the administrative programs
+ * depend on this. See ldap/admin/lib/dsalib_updown.c.
+ */
+#if !defined( XP_WIN32 )
+ if ( n_tcps != NULL ) { /* standard LDAP */
+#else
+ if ( n_tcps != SLAPD_INVALID_SOCKET ) { /* standard LDAP */
+#endif
+
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "slapd started. Listening on %s port %d for LDAP requests\n",
+ netaddr2string(&ports->n_listenaddr, addrbuf, sizeof(addrbuf)),
+ ports->n_port, 0 );
+ }
+
+ if ( s_tcps != NULL ) { /* LDAP over SSL; separate port */
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Listening on %s port %d for LDAPS requests\n",
+ netaddr2string(&ports->s_listenaddr, addrbuf, sizeof(addrbuf)),
+ ports->s_port, 0 );
+ }
+}
+
+#if defined( _WIN32 )
+/* On Windows, we signal the SCM when we're ready to accept connections */
+static int
+write_pid_file()
+{
+ if( SlapdIsAService() )
+ {
+ /* Initialization complete and successful. Set service to running */
+ LDAPServerStatus.dwCurrentState = SERVICE_RUNNING;
+ LDAPServerStatus.dwCheckPoint = 0;
+ LDAPServerStatus.dwWaitHint = 0;
+
+ if (!SetServiceStatus(hLDAPServerServiceStatus, &LDAPServerStatus)) {
+ ReportSlapdEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVER_START_FAILED, 1,
+ "Could not set Service status.");
+ exit(1);
+ }
+ }
+
+ ReportSlapdEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVER_STARTED, 0, NULL );
+ return 0;
+}
+#else /* WIN32 */
+/* On UNIX, we create a file with our PID in it */
+static int
+write_pid_file()
+{
+ FILE *fp = NULL;
+ /*
+ * The following section of code is closely coupled with the
+ * admin programs. Please do not make changes here without
+ * consulting the start/stop code for the admin code.
+ */
+ if ( (fp = fopen( get_pid_file(), "w" )) != NULL ) {
+ fprintf( fp, "%d\n", getpid() );
+ fclose( fp );
+ return 0;
+ } else
+ {
+ return -1;
+ }
+}
+#endif /* WIN32 */
+
+static void
+set_shutdown (int sig)
+{
+ /* don't log anything from a signal handler:
+ * you could be holding a lock when the signal was trapped. more
+ * specifically, you could be holding the logfile lock (and deadlock
+ * yourself).
+ */
+#if 0
+ LDAPDebug( LDAP_DEBUG_ANY, "slapd got shutdown signal\n", 0, 0, 0 );
+#endif
+ g_set_shutdown( SLAPI_SHUTDOWN_SIGNAL );
+#ifndef _WIN32
+#ifndef LINUX
+ /* don't mess with USR1/USR2 on linux, used by libpthread */
+ (void) SIGNAL( SIGUSR2, set_shutdown );
+#endif
+ (void) SIGNAL( SIGTERM, set_shutdown );
+ (void) SIGNAL( SIGHUP, set_shutdown );
+#endif
+}
+
+#ifndef LINUX
+void
+slapd_do_nothing (int sig)
+{
+ /* don't log anything from a signal handler:
+ * you could be holding a lock when the signal was trapped. more
+ * specifically, you could be holding the logfile lock (and deadlock
+ * yourself).
+ */
+#if 0
+ LDAPDebug( LDAP_DEBUG_TRACE, "slapd got SIGUSR1\n", 0, 0, 0 );
+#endif
+#ifndef _WIN32
+ (void) SIGNAL( SIGUSR1, slapd_do_nothing );
+#endif
+
+#if 0
+ /*
+ * Actually do a little more: dump the conn struct and
+ * send it to a tmp file
+ */
+ connection_table_dump(connection_table);
+#endif
+}
+#endif /* LINUX */
+
+#ifndef _WIN32
+void
+slapd_wait4child(int sig)
+{
+ WAITSTATUSTYPE status;
+
+ /* don't log anything from a signal handler:
+ * you could be holding a lock when the signal was trapped. more
+ * specifically, you could be holding the logfile lock (and deadlock
+ * yourself).
+ */
+#if 0
+ LDAPDebug( LDAP_DEBUG_ARGS, "listener: catching SIGCHLD\n", 0, 0, 0 );
+#endif
+#ifdef USE_WAITPID
+ while (waitpid ((pid_t) -1, 0, WAIT_FLAGS) > 0)
+#else /* USE_WAITPID */
+ while ( wait3( &status, WAIT_FLAGS, 0 ) > 0 )
+#endif /* USE_WAITPID */
+ ; /* NULL */
+
+ (void) SIGNAL( SIGCHLD, slapd_wait4child );
+}
+#endif
+
+#ifdef XP_WIN32
+static int
+createlistensocket(unsigned short port, const PRNetAddr *listenaddr)
+{
+ int tcps;
+ struct sockaddr_in addr;
+ char *logname = "createlistensocket";
+ char addrbuf[ 256 ];
+
+ if (!port) goto suppressed;
+
+ PR_ASSERT( listenaddr != NULL );
+
+ /* create TCP socket */
+ if ((tcps = socket(AF_INET, SOCK_STREAM, 0))
+ == SLAPD_INVALID_SOCKET) {
+ int oserr = errno;
+
+ slapi_log_error(SLAPI_LOG_FATAL, logname,
+ "socket() failed: OS error %d (%s)\n",
+ oserr, slapd_system_strerror( oserr ));
+ goto failed;
+ }
+
+ /* initialize listener address */
+ (void) memset( (void *) &addr, '\0', sizeof(addr) );
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons( port );
+ if (listenaddr->raw.family == PR_AF_INET) {
+ addr.sin_addr.s_addr = listenaddr->inet.ip;
+ } else if (PR_IsNetAddrType(listenaddr,PR_IpAddrAny)) {
+ addr.sin_addr.s_addr = INADDR_ANY;
+ } else {
+ if (!PR_IsNetAddrType(listenaddr,PR_IpAddrV4Mapped)) {
+ /*
+ * When Win32 supports IPv6, we will be able to use IPv6
+ * addresses here. But not yet.
+ */
+ slapi_log_error(SLAPI_LOG_FATAL, logname,
+ "unable to listen on %s port %d (IPv6 addresses "
+ "are not supported on this platform)\n",
+ netaddr2string(listenaddr, addrbuf, sizeof(addrbuf)),
+ port );
+ goto failed;
+ }
+
+ addr.sin_addr.s_addr = listenaddr->ipv6.ip.pr_s6_addr32[3];
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "%s - binding to %s:%d\n",
+ logname, inet_ntoa( addr.sin_addr ), port )
+
+ if ( bind( tcps, (struct sockaddr *) &addr, sizeof(addr) ) == -1 ) {
+ int oserr = errno;
+
+ slapi_log_error(SLAPI_LOG_FATAL, logname,
+ "bind() on %s port %d failed: OS error %d (%s)\n",
+ inet_ntoa( addr.sin_addr ), port, oserr,
+ slapd_system_strerror( oserr ));
+ goto failed;
+ }
+
+ return tcps;
+
+failed:
+ WSACleanup();
+ exit( 1 );
+suppressed:
+ return -1;
+} /* createlistensocket */
+#endif /* XP_WIN32 */
+
+
+static PRFileDesc *
+createprlistensocket(unsigned short port, const PRNetAddr *listenaddr,
+ int secure)
+{
+ PRFileDesc *sock;
+ PRNetAddr sa_server;
+ PRErrorCode prerr = 0;
+ PRSocketOptionData pr_socketoption;
+ char addrbuf[ 256 ];
+ char *logname = "createprlistensocket";
+
+ if (!port) goto suppressed;
+
+ PR_ASSERT( listenaddr != NULL );
+
+ /* create TCP socket */
+ if ((sock = PR_OpenTCPSocket(PR_AF_INET6)) == SLAPD_INVALID_SOCKET) {
+ prerr = PR_GetError();
+ slapi_log_error(SLAPI_LOG_FATAL, logname,
+ "PR_OpenTCPSocket(PR_AF_INET6) failed: %s error %d (%s)\n",
+ SLAPI_COMPONENT_NAME_NSPR, prerr, slapd_pr_strerror(prerr));
+ goto failed;
+ }
+
+ pr_socketoption.option = PR_SockOpt_Reuseaddr;
+ pr_socketoption.value.reuse_addr = 1;
+ if ( PR_SetSocketOption(sock, &pr_socketoption ) == PR_FAILURE) {
+ prerr = PR_GetError();
+ slapi_log_error(SLAPI_LOG_FATAL, logname,
+ "PR_SetSocketOption(PR_SockOpt_Reuseaddr) failed: %s error %d (%s)\n",
+ SLAPI_COMPONENT_NAME_NSPR, prerr, slapd_pr_strerror( prerr ));
+ goto failed;
+ }
+
+ /* set up listener address, including port */
+ memcpy(&sa_server, listenaddr, sizeof(sa_server));
+ if ( PR_SetNetAddr(PR_IpAddrNull, PR_AF_INET6, port, &sa_server)
+ != PR_SUCCESS ) {
+ prerr = PR_GetError();
+ slapi_log_error(SLAPI_LOG_FATAL, logname,
+ "PR_SetNetAddr() failed: %s error %d (%s)\n",
+ SLAPI_COMPONENT_NAME_NSPR,
+ prerr, slapd_pr_strerror(prerr));
+ goto failed;
+ }
+
+ if ( PR_Bind(sock, &sa_server) == PR_FAILURE) {
+ prerr = PR_GetError();
+ slapi_log_error(SLAPI_LOG_FATAL, logname,
+ "PR_Bind() on %s port %d failed: %s error %d (%s)\n",
+ netaddr2string(&sa_server, addrbuf, sizeof(addrbuf)), port,
+ SLAPI_COMPONENT_NAME_NSPR, prerr, slapd_pr_strerror(prerr));
+ goto failed;
+ }
+
+ return( sock );
+
+failed:
+#ifdef XP_WIN32
+ WSACleanup();
+#endif /* XP_WIN32 */
+ exit( 1 );
+
+suppressed:
+ return (PRFileDesc *)-1;
+} /* createprlistensocket */
+
+
+/*
+ * Initialize the *addr structure based on listenhost.
+ * Returns: 0 if successful and -1 if not (after logging an error message).
+ */
+int
+slapd_listenhost2addr(const char *listenhost, PRNetAddr *addr)
+{
+ char *logname = "slapd_listenhost2addr";
+ PRErrorCode prerr = 0;
+ PRHostEnt hent;
+ char hbuf[ PR_NETDB_BUF_SIZE ];
+
+ PR_ASSERT( addr != NULL );
+
+ if (NULL == listenhost) {
+ /* listen on all interfaces */
+ if ( PR_SUCCESS != PR_SetNetAddr(PR_IpAddrAny, PR_AF_INET6, 0, addr)) {
+ prerr = PR_GetError();
+ slapi_log_error( SLAPI_LOG_FATAL, logname,
+ "PR_SetNetAddr(PR_IpAddrAny) failed - %s error %d (%s)\n",
+ SLAPI_COMPONENT_NAME_NSPR, prerr, slapd_pr_strerror(prerr));
+ goto failed;
+ }
+ } else if (PR_SUCCESS == PR_StringToNetAddr(listenhost, addr)) {
+ if (PR_AF_INET == PR_NetAddrFamily(addr)) {
+ PRUint32 ipv4ip = addr->inet.ip;
+ memset(addr, 0, sizeof(PRNetAddr));
+ PR_ConvertIPv4AddrToIPv6(ipv4ip, &addr->ipv6.ip);
+ addr->ipv6.family = PR_AF_INET6;
+ }
+ } else if (PR_SUCCESS == PR_GetIPNodeByName(listenhost,
+ PR_AF_INET6, PR_AI_DEFAULT | PR_AI_ALL,
+ hbuf, sizeof(hbuf), &hent )) {
+ /* just use the first IP address returned */
+ if (PR_EnumerateHostEnt(0, &hent, 0, addr) < 0) {
+ slapi_log_error( SLAPI_LOG_FATAL, logname,
+ "PR_EnumerateHostEnt() failed - %s error %d (%s)\n",
+ SLAPI_COMPONENT_NAME_NSPR, prerr, slapd_pr_strerror(prerr));
+ goto failed;
+ }
+ } else { /* failure */
+ slapi_log_error( SLAPI_LOG_FATAL, logname,
+ "PR_GetIPNodeByName(%s) failed - %s error %d (%s)\n",
+ listenhost, SLAPI_COMPONENT_NAME_NSPR, prerr,
+ slapd_pr_strerror(prerr));
+ goto failed;
+ }
+
+ return( 0 );
+
+failed:
+ return( -1 );
+}
+
+
+/*
+ * Map addr to a string equivalent and place the result in addrbuf.
+ */
+static const char *
+netaddr2string(const PRNetAddr *addr, char *addrbuf, size_t addrbuflen)
+{
+ const char *retstr;
+
+ if (NULL == addr || PR_IsNetAddrType(addr, PR_IpAddrAny)) {
+ retstr = "All Interfaces";
+ } else if (PR_IsNetAddrType(addr, PR_IpAddrLoopback)) {
+ if ( addr->raw.family == PR_AF_INET6 &&
+ !PR_IsNetAddrType(addr, PR_IpAddrV4Mapped)) {
+ retstr = "IPv6 Loopback";
+ } else {
+ retstr = "Loopback";
+ }
+ } else if (PR_SUCCESS == PR_NetAddrToString( addr, addrbuf, addrbuflen)) {
+ if (0 == strncmp( addrbuf, "::ffff:", 7 )) {
+ /* IPv4 address mapped into IPv6 address space */
+ retstr = addrbuf + 7;
+ } else {
+ /* full blown IPv6 address */
+ retstr = addrbuf;
+ }
+ } else { /* punt */
+ retstr = "address conversion failed";
+ }
+
+ return(retstr);
+}
+
+
+static int
+createsignalpipe( void )
+{
+#if defined( _WIN32 )
+ if ( PR_NewTCPSocketPair(&signalpipe[0])) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "PR_CreatePipe() failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), SLAPD_DEFAULT_THREAD_STACKSIZE );
+ return( -1 );
+ }
+ writesignalpipe = PR_FileDesc2NativeHandle(signalpipe[1]);
+ readsignalpipe = PR_FileDesc2NativeHandle(signalpipe[0]);
+#else
+ if ( PR_CreatePipe( &signalpipe[0], &signalpipe[1] ) != 0 ) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY, "PR_CreatePipe() failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), SLAPD_DEFAULT_THREAD_STACKSIZE );
+ return( -1 );
+ }
+ writesignalpipe = PR_FileDesc2NativeHandle(signalpipe[1]);
+ readsignalpipe = PR_FileDesc2NativeHandle(signalpipe[0]);
+ fcntl(writesignalpipe, F_SETFD, O_NONBLOCK);
+ fcntl(readsignalpipe, F_SETFD, O_NONBLOCK);
+#endif
+
+ return( 0 );
+}
+
+
+#ifdef HPUX10
+#include <pthread.h> /* for sigwait */
+/*
+ * Set up a thread to catch signals
+ * SIGUSR1 (ignore), SIGCHLD (call slapd_wait4child),
+ * SIGUSR2 (set slapd_shutdown), SIGTERM (set slapd_shutdown),
+ * SIGHUP (set slapd_shutdown)
+ */
+static void *
+catch_signals()
+{
+ sigset_t caught_signals;
+ int sig;
+
+ sigemptyset( &caught_signals );
+
+ while ( !g_get_shutdown() ) {
+
+ /* Set the signals we're interested in catching */
+ sigaddset( &caught_signals, SIGUSR1 );
+ sigaddset( &caught_signals, SIGCHLD );
+ sigaddset( &caught_signals, SIGUSR2 );
+ sigaddset( &caught_signals, SIGTERM );
+ sigaddset( &caught_signals, SIGHUP );
+
+ (void)sigprocmask( SIG_BLOCK, &caught_signals, NULL );
+
+ if (( sig = sigwait( &caught_signals )) < 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "catch_signals: sigwait returned -1\n",
+ 0, 0, 0 );
+ continue;
+ } else {
+ LDAPDebug( LDAP_DEBUG_TRACE, "catch_signals: detected signal %d\n",
+ sig, 0, 0 );
+ switch ( sig ) {
+ case SIGUSR1:
+ continue; /* ignore SIGUSR1 */
+ case SIGUSR2: /* fallthrough */
+ case SIGTERM: /* fallthrough */
+ case SIGHUP:
+ g_set_shutdown( SLAPI_SHUTDOWN_SIGNAL );
+ return NULL;
+ case SIGCHLD:
+ slapd_wait4child( sig );
+ break;
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "catch_signals: unknown signal (%d) received\n",
+ sig, 0, 0 );
+ }
+ }
+ }
+}
+#endif /* HPUX */
+
+static int
+get_configured_connection_table_size()
+{
+ int size;
+ size = config_get_conntablesize();
+
+/*
+ * Cap the table size at nsslapd-maxdescriptors.
+ */
+#if !defined(_WIN32) && !defined(AIX)
+ {
+ int maxdesc = config_get_maxdescriptors();
+
+ if ( maxdesc >= 0 && size > maxdesc ) {
+ size = maxdesc;
+ }
+ }
+#endif
+
+ return size;
+}
+
+
+
+
+PRFileDesc * get_ssl_listener_fd()
+{
+ PRFileDesc * listener;
+
+ listener = the_connection_table->fd[FDS_S_TCPS].fd;
+
+ return listener;
+}
+
+
+
+int configure_pr_socket( PRFileDesc **pr_socket, int secure )
+{
+ int ns = 0;
+ int reservedescriptors = config_get_reservedescriptors();
+ int ioblock_timeout = config_get_ioblocktimeout();
+ int enable_nagle = config_get_nagle();
+
+ PRSocketOptionData pr_socketoption;
+
+#if defined(LINUX)
+ /* On Linux we use TCP_CORK so we must enable nagle */
+ enable_nagle = 1;
+#endif
+
+ ns = PR_FileDesc2NativeHandle( *pr_socket );
+
+#if !defined(_WIN32)
+ /*
+ * Some OS or third party libraries may require that low
+ * numbered file descriptors be available, e.g., the DNS resolver
+ * library on most operating systems. Therefore, we try to
+ * replace the file descriptor returned by accept() with a
+ * higher numbered one. If this fails, we log an error and
+ * continue (not considered a truly fatal error).
+ */
+ if ( reservedescriptors > 0 && ns < reservedescriptors ) {
+ int newfd = fcntl( ns, F_DUPFD, reservedescriptors );
+
+ if ( newfd > 0 ) {
+ PRFileDesc *nspr_layer_fd = PR_GetIdentitiesLayer( *pr_socket,
+ PR_NSPR_IO_LAYER );
+ if ( NULL == nspr_layer_fd ) {
+ slapi_log_error( SLAPI_LOG_FATAL, "configure_pr_socket",
+ "Unable to move socket file descriptor %d above %d:"
+ " PR_GetIdentitiesLayer( 0x%x, PR_NSPR_IO_LAYER )"
+ " failed\n", ns, reservedescriptors, *pr_socket );
+ close( newfd ); /* can't fix things up in NSPR -- close copy */
+ } else {
+ PR_ChangeFileDescNativeHandle( nspr_layer_fd, newfd );
+ close( ns ); /* dup succeeded -- close the original */
+ ns = newfd;
+ }
+ } else {
+ int oserr = errno;
+ slapi_log_error(SLAPI_LOG_FATAL, "configure_pr_socket",
+ "Unable to move socket file descriptor %d above %d:"
+ " OS error %d (%s)\n", ns, reservedescriptors, oserr,
+ slapd_system_strerror( oserr ) );
+ }
+ }
+#endif /* !_WIN32 */
+
+ if ( secure ) {
+
+ pr_socketoption.option = PR_SockOpt_Nonblocking;
+ pr_socketoption.value.non_blocking = 0;
+ if ( PR_SetSocketOption( *pr_socket, &pr_socketoption ) == PR_FAILURE ) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "PR_SetSocketOption(PR_SockOpt_Nonblocking) failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0 );
+ }
+ } else {
+ /* We always want to have non-blocking I/O */
+ pr_socketoption.option = PR_SockOpt_Nonblocking;
+ pr_socketoption.value.non_blocking = 1;
+ if ( PR_SetSocketOption( *pr_socket, &pr_socketoption ) == PR_FAILURE ) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "PR_SetSocketOption(PR_SockOpt_Nonblocking) failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0 );
+ }
+
+ if ( have_send_timeouts ) {
+ daemon_configure_send_timeout(ns,config_get_ioblocktimeout());
+ }
+
+ } /* else (secure) */
+
+
+ if ( !enable_nagle ) {
+
+ pr_socketoption.option = PR_SockOpt_NoDelay;
+ pr_socketoption.value.no_delay = 1;
+ if ( PR_SetSocketOption( *pr_socket, &pr_socketoption ) == PR_FAILURE) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "PR_SetSocketOption(PR_SockOpt_NoDelay) failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror( prerr ), 0 );
+ }
+ } else {
+ pr_socketoption.option = PR_SockOpt_NoDelay;
+ pr_socketoption.value.no_delay = 0;
+ if ( PR_SetSocketOption( *pr_socket, &pr_socketoption ) == PR_FAILURE) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "PR_SetSocketOption(PR_SockOpt_NoDelay) failed, "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror( prerr ), 0 );
+ }
+ } /* else (!enable_nagle) */
+
+
+ return ns;
+
+}
+
+
+
+
+void configure_ns_socket( int * ns )
+{
+
+ int ioblock_timeout = config_get_ioblocktimeout();
+ int enable_nagle = config_get_nagle();
+ int on;
+
+#if defined(LINUX)
+ /* On Linux we use TCP_CORK so we must enable nagle */
+ enable_nagle = 1;
+#endif
+
+ if ( have_send_timeouts ) {
+ daemon_configure_send_timeout( *ns, config_get_ioblocktimeout() );
+ }
+
+
+ if ( !enable_nagle ) {
+ on = 1;
+ setsockopt( *ns, IPPROTO_TCP, TCP_NODELAY, (char * ) &on, sizeof(on) );
+ } else {
+ on = 0;
+ setsockopt( *ns, IPPROTO_TCP, TCP_NODELAY, (char * ) &on, sizeof(on) );
+ } /* else (!enable_nagle) */
+
+
+ return;
+
+}
+
+
+#ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
+/*
+ * A function that uses the DNS resolver in a simple way. This is only
+ * used to ensure that the DNS resolver has opened its files, etc.
+ * using low numbered file descriptors.
+ */
+static void
+get_loopback_by_addr( void )
+{
+#ifdef GETHOSTBYADDR_BUF_T
+ struct hostent hp;
+ GETHOSTBYADDR_BUF_T hbuf;
+#endif
+ unsigned long ipaddr;
+ struct in_addr ia;
+ int herrno, rc = 0;
+
+ memset( (char *)&hp, 0, sizeof(hp));
+ ipaddr = htonl( INADDR_LOOPBACK );
+ (void) GETHOSTBYADDR( (char *)&ipaddr, sizeof( ipaddr ),
+ AF_INET, &hp, hbuf, sizeof(hbuf), &herrno );
+}
+#endif /* RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS */
diff --git a/ldap/servers/slapd/defbackend.c b/ldap/servers/slapd/defbackend.c
new file mode 100644
index 00000000..abd76d88
--- /dev/null
+++ b/ldap/servers/slapd/defbackend.c
@@ -0,0 +1,200 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * defbackend.c - implement a "backend of last resort" which is used only
+ * when a request's basedn does not match one of the suffixes of any of the
+ * configured backends.
+ *
+ */
+
+#include "slap.h"
+
+/*
+ * ---------------- Macros ---------------------------------------------------
+ */
+#define DEFBACKEND_TYPE "default"
+
+#define DEFBACKEND_OP_NOT_HANDLED 0
+#define DEFBACKEND_OP_HANDLED 1
+
+
+/*
+ * ---------------- Static Variables -----------------------------------------
+ */
+static struct slapdplugin defbackend_plugin;
+static Slapi_Backend *defbackend_backend = NULL;
+
+
+/*
+ * ---------------- Prototypes for Private Functions -------------------------
+ */
+static int defbackend_default( Slapi_PBlock *pb );
+static int defbackend_noop( Slapi_PBlock *pb );
+static int defbackend_abandon( Slapi_PBlock *pb );
+static int defbackend_bind( Slapi_PBlock *pb );
+static int defbackend_next_search_entry( Slapi_PBlock *pb );
+
+
+/*
+ * ---------------- Public Functions -----------------------------------------
+ */
+
+/*
+ * defbackend_init: instantiate the default backend
+ */
+void
+defbackend_init( void )
+{
+ int rc;
+ char *errmsg;
+ Slapi_PBlock pb;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "defbackend_init\n", 0, 0, 0 );
+
+ /*
+ * create a new backend
+ */
+ pblock_init( &pb );
+ defbackend_backend = slapi_be_new( DEFBACKEND_TYPE , DEFBACKEND_TYPE, 1 /* Private */, 0 /* Do Not Log Changes */ );
+ if (( rc = slapi_pblock_set( &pb, SLAPI_BACKEND, defbackend_backend ))
+ != 0 ) {
+ errmsg = "slapi_pblock_set SLAPI_BACKEND failed";
+ goto cleanup_and_return;
+ }
+
+ /*
+ * create a plugin structure for this backend since the
+ * slapi_pblock_set()/slapi_pblock_get() functions assume there is one.
+ */
+ memset( &defbackend_plugin, '\0', sizeof( struct slapdplugin ));
+ defbackend_plugin.plg_type = SLAPI_PLUGIN_DATABASE;
+ defbackend_backend->be_database = &defbackend_plugin;
+ if (( rc = slapi_pblock_set( &pb, SLAPI_PLUGIN, &defbackend_plugin ))
+ != 0 ) {
+ errmsg = "slapi_pblock_set SLAPI_PLUGIN failed";
+ goto cleanup_and_return;
+ }
+
+ /* default backend is managed as if it would */
+ /* contain remote data. */
+ slapi_be_set_flag(defbackend_backend,SLAPI_BE_FLAG_REMOTE_DATA);
+
+ /*
+ * install handler functions, etc.
+ */
+ errmsg = "slapi_pblock_set handlers failed";
+ rc = slapi_pblock_set( &pb, SLAPI_PLUGIN_VERSION,
+ (void *)SLAPI_PLUGIN_CURRENT_VERSION );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_BIND_FN,
+ (void *)defbackend_bind );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_UNBIND_FN,
+ (void *)defbackend_noop );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_SEARCH_FN,
+ (void *)defbackend_default );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN,
+ (void *)defbackend_next_search_entry );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_COMPARE_FN,
+ (void *)defbackend_default );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_MODIFY_FN,
+ (void *)defbackend_default );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_MODRDN_FN,
+ (void *)defbackend_default );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_ADD_FN,
+ (void *)defbackend_default );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_DELETE_FN,
+ (void *)defbackend_default );
+ rc |= slapi_pblock_set( &pb, SLAPI_PLUGIN_DB_ABANDON_FN,
+ (void *)defbackend_abandon );
+
+cleanup_and_return:
+ if ( rc != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "defbackend_init: failed (%s)\n",
+ errmsg, 0, 0 );
+ exit( 1 );
+ }
+}
+
+
+/*
+ * defbackend_get_backend: return a pointer to the default backend.
+ * we never return NULL.
+ */
+Slapi_Backend *
+defbackend_get_backend( void )
+{
+ return( defbackend_backend );
+}
+
+
+/*
+ * ---------------- Private Functions ----------------------------------------
+ */
+
+static int
+defbackend_default( Slapi_PBlock *pb )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "defbackend_default\n", 0, 0, 0 );
+
+ send_nobackend_ldap_result( pb );
+
+ return( DEFBACKEND_OP_HANDLED );
+}
+
+
+static int
+defbackend_noop( Slapi_PBlock *pb )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "defbackend_noop\n", 0, 0, 0 );
+
+ return( DEFBACKEND_OP_HANDLED );
+}
+
+
+static int
+defbackend_abandon( Slapi_PBlock *pb )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "defbackend_abandon\n", 0, 0, 0 );
+
+ /* nothing to do */
+ return( DEFBACKEND_OP_HANDLED );
+}
+
+
+static int
+defbackend_bind( Slapi_PBlock *pb )
+{
+ int rc, method;
+ struct berval *cred;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "defbackend_bind\n", 0, 0, 0 );
+
+ /*
+ * Accept simple binds that do not contain passwords (but do not
+ * update the bind DN field in the connection structure since we don't
+ * grant access based on these "NULL binds")
+ */
+ slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method );
+ slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred );
+ if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 ) {
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds);
+ rc = SLAPI_BIND_ANONYMOUS;
+ } else {
+ send_nobackend_ldap_result( pb );
+ rc = SLAPI_BIND_FAIL;
+ }
+
+ return( rc );
+}
+
+
+
+static int
+defbackend_next_search_entry( Slapi_PBlock *pb )
+{
+ LDAPDebug( LDAP_DEBUG_TRACE, "defbackend_next_search_entry\n", 0, 0, 0 );
+
+ return( 0 ); /* no entries and no error */
+}
diff --git a/ldap/servers/slapd/delete.c b/ldap/servers/slapd/delete.c
new file mode 100644
index 00000000..6e009709
--- /dev/null
+++ b/ldap/servers/slapd/delete.c
@@ -0,0 +1,324 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#include "pratom.h"
+
+/* Forward declarations */
+static int delete_internal_pb (Slapi_PBlock *pb);
+static void op_shared_delete (Slapi_PBlock *pb);
+
+/* This function is called to process operation that come over external connections */
+void
+do_delete( Slapi_PBlock *pb )
+{
+ Slapi_Operation *operation;
+ BerElement *ber;
+ char *dn;
+ int err;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_delete\n", 0, 0, 0 );
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ ber = operation->o_ber;
+
+ /* count the delete request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps);
+
+ /*
+ * Parse the delete request. It looks like this:
+ *
+ * DelRequest := DistinguishedName
+ */
+
+ if ( ber_scanf( pb->pb_op->o_ber, "a", &dn ) == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=Delete; params=DN)\n", 0, 0, 0 );
+ op_shared_log_error_access (pb, "DEL", "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
+ NULL );
+ return;
+ }
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ op_shared_log_error_access (pb, "DEL", dn, "decoding error");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_ARGS, "do_delete: dn (%s)\n", dn, 0, 0 );
+
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot );
+ slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, dn);
+
+ op_shared_delete (pb);
+
+free_and_return:;
+ slapi_ch_free ((void**)&dn);
+}
+
+/* This function is used to issue internal delete operation
+ This is an old style API. Its use is discoraged because it is not extendable and
+ because it does not allow to check whether plugin has right to access part of the
+ tree it is trying to modify. Use slapi_delete_internal_pb instead */
+Slapi_PBlock *
+slapi_delete_internal(const char *idn, LDAPControl **controls, int dummy)
+{
+ Slapi_PBlock pb;
+ Slapi_PBlock *result_pb;
+ int opresult;
+
+ pblock_init (&pb);
+
+ slapi_delete_internal_set_pb (&pb, idn, controls, NULL, plugin_get_default_component_id(), 0);
+
+ delete_internal_pb (&pb);
+
+ result_pb = slapi_pblock_new();
+ if (result_pb)
+ {
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ slapi_pblock_set(result_pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ }
+ pblock_done(&pb);
+
+ return result_pb;
+}
+
+/* This is new style API to issue internal delete operation.
+ pblock should contain the following data (can be set via call to slapi_delete_internal_set_pb):
+ For uniqueid based operation:
+ SLAPI_TARGET_DN set to dn that allows to select right backend, can be stale
+ SLAPI_TARGET_UNIQUEID set to the uniqueid of the entry we are looking for
+ SLAPI_CONTROLS_ARG set to request controls if present
+
+ For dn based search:
+ SLAPI_TARGET_DN set to the entry dn
+ SLAPI_CONTROLS_ARG set to request controls if present
+ */
+int slapi_delete_internal_pb (Slapi_PBlock *pb)
+{
+ if (pb == NULL)
+ return -1;
+
+ if (!allow_operation (pb))
+ {
+ slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "This plugin is not configured to access operation target data", 0, NULL );
+ return 0;
+ }
+
+ return delete_internal_pb (pb);
+}
+
+/* Initialize a pblock for a call to slapi_delete_internal_pb() */
+void slapi_delete_internal_set_pb (Slapi_PBlock *pb, const char *dn, LDAPControl **controls, const char *uniqueid,
+ Slapi_ComponentId *plugin_identity, int operation_flags)
+{
+ Operation *op;
+ PR_ASSERT (pb != NULL);
+ if (pb == NULL || dn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_delete_internal_set_pb: NULL parameter\n");
+ return;
+ }
+
+ op = internal_operation_new(SLAPI_OPERATION_DELETE,operation_flags);
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ slapi_pblock_set(pb, SLAPI_ORIGINAL_TARGET, (void*)dn);
+ slapi_pblock_set(pb, SLAPI_CONTROLS_ARG, controls);
+ if (uniqueid)
+ {
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, (void*)uniqueid);
+ }
+ slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, plugin_identity);
+}
+
+/* Helper functions */
+
+static int delete_internal_pb (Slapi_PBlock *pb)
+{
+ LDAPControl **controls;
+ Operation *op;
+ int opresult = 0;
+
+ PR_ASSERT (pb != NULL);
+
+ slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op->o_handler_data = &opresult;
+ op->o_result_handler = internal_getresult_callback;
+
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ slapi_pblock_set(pb, SLAPI_REQCONTROLS, controls);
+
+ /* set parameters common for all internal operations */
+ set_common_params (pb);
+
+ /* set actions taken to process the operation */
+ set_config_params (pb);
+
+ /* perform delete operation */
+ op_shared_delete (pb);
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+
+ return 0;
+}
+
+static void op_shared_delete (Slapi_PBlock *pb)
+{
+ char *dn;
+ Slapi_Backend *be = NULL;
+ char ebuf[ BUFSIZ ];
+ int internal_op;
+ Slapi_DN sdn;
+ Slapi_Operation *operation;
+ Slapi_Entry *referral;
+ Slapi_Entry *ecopy = NULL;
+ char errorbuf[BUFSIZ];
+ int err;
+
+ slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET, &dn);
+ slapi_pblock_get(pb, SLAPI_OPERATION, &operation);
+ internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
+
+ slapi_sdn_init_dn_byref(&sdn,dn);
+ slapi_pblock_set(pb, SLAPI_DELETE_TARGET, (void*)slapi_sdn_get_ndn (&sdn));
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ operation_set_target_spec (operation, &sdn);
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ if (!internal_op )
+ {
+ slapi_log_access(LDAP_DEBUG_STATS, "conn=%d op=%d DEL dn=\"%s\"\n",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ escape_string(dn, ebuf));
+ }
+ else
+ {
+ slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d DEL dn=\"%s\"\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ escape_string(dn, ebuf));
+ }
+ }
+
+ /*
+ * We could be serving multiple database backends. Select the
+ * appropriate one.
+ */
+ if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf)) != LDAP_SUCCESS) {
+ send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
+ be = NULL;
+ goto free_and_return;
+ }
+
+ if (referral)
+ {
+ int managedsait;
+
+ slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ if (managedsait)
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "cannot delete referral", 0, NULL);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ send_referrals_from_entry(pb,referral);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+
+ /*
+ * call the pre-delete plugins. if they succeed, call
+ * the backend delete function. then call the
+ * post-delete plugins.
+ */
+ if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN :
+ SLAPI_PLUGIN_PRE_DELETE_FN) == 0)
+ {
+ int rc;
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
+ set_db_default_result_handlers(pb);
+ if (be->be_delete != NULL)
+ {
+ if ((rc = (*be->be_delete)(pb)) == 0)
+ {
+ /* we don't perform acl check for internal operations */
+ /* Dont update aci store for remote acis */
+ if ((!internal_op) &&
+ (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
+ plugin_call_acl_mods_update (pb, SLAPI_OPERATION_DELETE);
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
+ write_audit_log_entry(pb); /* Record the operation in the audit log */
+
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
+ do_ps_service(ecopy, NULL, LDAP_CHANGETYPE_DELETE, 0UL);
+ }
+ else
+ {
+ if (rc == SLAPI_FAIL_DISKFULL)
+ {
+ operation_out_of_disk_space();
+ goto free_and_return;
+ }
+ }
+ }
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN :
+ SLAPI_PLUGIN_POST_DELETE_FN);
+ }
+
+free_and_return:
+ if (be)
+ slapi_be_Unlock(be);
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
+ slapi_entry_free(ecopy);
+ slapi_pblock_get ( pb, SLAPI_DELETE_GLUE_PARENT_ENTRY, &ecopy );
+ if (ecopy)
+ {
+ slapi_entry_free (ecopy);
+ slapi_pblock_set (pb, SLAPI_DELETE_GLUE_PARENT_ENTRY, NULL);
+ }
+ slapi_pblock_get(pb, SLAPI_URP_NAMING_COLLISION_DN, &dn);
+ slapi_ch_free((void **)&dn);
+ slapi_sdn_done(&sdn);
+}
diff --git a/ldap/servers/slapd/detach.c b/ldap/servers/slapd/detach.c
new file mode 100644
index 00000000..8c86358d
--- /dev/null
+++ b/ldap/servers/slapd/detach.c
@@ -0,0 +1,244 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1990, 1994 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifdef SVR4
+#include <sys/stat.h>
+#endif /* svr4 */
+#include <fcntl.h>
+#ifndef _WIN32
+#include <errno.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#endif
+#include <signal.h>
+#ifdef LINUX
+#undef CTIME
+#endif
+#include "slap.h"
+#include "fe.h"
+
+#if defined(USE_SYSCONF) || defined(LINUX)
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+void
+detach()
+{
+#ifndef _WIN32
+ int i, sd;
+ char *workingdir = 0;
+ char *errorlog = 0;
+ char *ptr = 0;
+ char errorbuf[BUFSIZ];
+ extern char *config_get_errorlog(void);
+#endif
+
+#ifndef _WIN32
+ if ( should_detach ) {
+ for ( i = 0; i < 5; i++ ) {
+#if defined( sunos5 ) && ( defined( THREAD_SUNOS5_LWP ) || defined( NSPR20 ))
+ switch ( fork1() ) {
+#else
+ switch ( fork() ) {
+#endif
+ case -1:
+ sleep( 5 );
+ continue;
+
+ case 0:
+ break;
+
+ default:
+ _exit( 0 );
+ }
+ break;
+ }
+
+ workingdir = config_get_workingdir();
+ if ( NULL == workingdir ) {
+ errorlog = config_get_errorlog();
+ if ( NULL == errorlog ) {
+ (void) chdir( "/" );
+ } else {
+ if ((ptr = strrchr(errorlog, '/')) ||
+ (ptr = strrchr(errorlog, '\\'))) {
+ *ptr = 0;
+ }
+ (void) chdir( errorlog );
+ config_set_workingdir(CONFIG_WORKINGDIR_ATTRIBUTE, errorlog, errorbuf, 1);
+ slapi_ch_free((void**)&errorlog);
+ }
+ } else {
+ /* calling config_set_workingdir to check for validity of directory, don't apply */
+ if (config_set_workingdir(CONFIG_WORKINGDIR_ATTRIBUTE, workingdir, errorbuf, 0) == LDAP_OPERATIONS_ERROR) {
+ exit(1);
+ }
+ (void) chdir( workingdir );
+ slapi_ch_free((void**)&workingdir);
+ }
+
+ if ( (sd = open( "/dev/null", O_RDWR )) == -1 ) {
+ perror( "/dev/null" );
+ exit( 1 );
+ }
+ (void) dup2( sd, 0 );
+ (void) dup2( sd, 1 );
+ (void) dup2( sd, 2 );
+ close( sd );
+
+#ifdef USE_SETSID
+ setsid();
+#else /* USE_SETSID */
+ if ( (sd = open( "/dev/tty", O_RDWR )) != -1 ) {
+ (void) ioctl( sd, TIOCNOTTY, NULL );
+ (void) close( sd );
+ }
+#endif /* USE_SETSID */
+
+ g_set_detached(1);
+ }
+
+ (void) SIGNAL( SIGPIPE, SIG_IGN );
+#endif /* _WIN32 */
+}
+
+
+#ifndef _WIN32
+/*
+ * close all open files except stdin/out/err
+ */
+void
+close_all_files()
+{
+ int i, nbits;
+
+#ifdef USE_SYSCONF
+ nbits = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+ nbits = getdtablesize();
+#endif /* USE_SYSCONF */
+
+ for ( i = 3; i < nbits; i++ ) {
+ close( i );
+ }
+}
+#endif /* !_WIN32 */
+
+/*
+ * There is no need to do anything on some platforms (NT) and not try to
+ * raise fds on AIX.
+ */
+
+static void raise_process_fd_limits(void)
+{
+#if !defined(_WIN32) && !defined(AIX)
+ struct rlimit rl, setrl;
+ RLIM_TYPE curlim;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ if ( slapdFrontendConfig->maxdescriptors < 0 ) {
+ return;
+ }
+
+ /*
+ * Try to set our file descriptor limit. Our basic strategy is:
+ * 1) Try to set the soft limit and the hard limit if
+ * necessary to match our maxdescriptors value.
+ * 2) If that fails and our soft limit is less than our hard
+ * limit, we try to raise it to match the hard.
+ */
+ if ( getrlimit( RLIMIT_NOFILE, &rl ) != 0 ) {
+ int oserr = errno;
+
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "getrlimit of descriptor limit failed - error %d (%s)\n",
+ oserr, slapd_system_strerror( oserr ), 0 );
+ return;
+ }
+
+ if ( rl.rlim_cur == slapdFrontendConfig->maxdescriptors ) { /* already correct */
+ return;
+ }
+ curlim = rl.rlim_cur;
+ setrl = rl; /* struct copy */
+ setrl.rlim_cur = slapdFrontendConfig->maxdescriptors;
+ /* don't lower the hard limit as it's irreversible */
+ if (setrl.rlim_cur > setrl.rlim_max) {
+ setrl.rlim_max = setrl.rlim_cur;
+ }
+ if ( setrlimit( RLIMIT_NOFILE, &setrl ) != 0 && curlim < rl.rlim_max ) {
+ setrl = rl; /* struct copy */
+ setrl.rlim_cur = setrl.rlim_max;
+ if ( setrlimit( RLIMIT_NOFILE, &setrl ) != 0 ) {
+ int oserr = errno;
+
+ LDAPDebug( LDAP_DEBUG_ANY, "setrlimit of descriptor "
+ "limit to %d failed - error %d (%s)\n",
+ setrl.rlim_cur, oserr,
+ slapd_system_strerror(oserr));
+ return;
+ }
+ }
+
+ (void)getrlimit( RLIMIT_NOFILE, &rl );
+ LDAPDebug( LDAP_DEBUG_TRACE, "descriptor limit changed from %d to %d\n",
+ curlim, rl.rlim_cur, 0 );
+#endif /* !_WIN32 && !AIX */
+}
+
+/*
+ * Try to raise relevant per-process limits
+ */
+void
+raise_process_limits()
+{
+#if !defined(_WIN32)
+ struct rlimit rl;
+
+ raise_process_fd_limits();
+
+#ifdef RLIMIT_DATA
+ if (getrlimit(RLIMIT_DATA,&rl) == 0) {
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit(RLIMIT_DATA,&rl) != 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"setrlimit(RLIMIT_DATA) failed %d\n",
+ errno,0,0);
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE,"getrlimit(RLIMIT_DATA) failed %d\n",
+ errno,0,0);
+ }
+#endif
+
+#ifdef RLIMIT_VMEM
+ if (getrlimit(RLIMIT_VMEM,&rl) == 0) {
+ rl.rlim_cur = rl.rlim_max;
+ if (setrlimit(RLIMIT_VMEM,&rl) != 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE,"setrlimit(RLIMIT_VMEM) failed %d\n",
+ errno,0,0);
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE,"getrlimit(RLIMIT_VMEM) failed %d\n",
+ errno,0,0);
+ }
+#endif /* RLIMIT_VMEM */
+
+#endif /* !_WIN32 */
+}
+
diff --git a/ldap/servers/slapd/disconnect_error_strings.h b/ldap/servers/slapd/disconnect_error_strings.h
new file mode 100644
index 00000000..673d3528
--- /dev/null
+++ b/ldap/servers/slapd/disconnect_error_strings.h
@@ -0,0 +1,30 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* disconnect_error_strings.h
+ *
+ * Strings describing the errors used in logging the reason a connection
+ * was closed.
+ */
+#ifndef __DISCONNECT_ERROR_STRINGS_H_
+#define __DISCONNECT_ERROR_STRINGS_H_
+
+ER2( SLAPD_DISCONNECT_ABORT, "A1" )
+ER2( SLAPD_DISCONNECT_BAD_BER_TAG, "B1" )
+ER2( SLAPD_DISCONNECT_BER_TOO_BIG, "B2" )
+ER2( SLAPD_DISCONNECT_BER_PEEK, "B3" )
+ER2( SLAPD_DISCONNECT_BER_FLUSH, "B4" )
+ER2( SLAPD_DISCONNECT_IDLE_TIMEOUT, "T1" )
+ER2( SLAPD_DISCONNECT_REVENTS, "R1" )
+ER2( SLAPD_DISCONNECT_IO_TIMEOUT, "T2" )
+ER2( SLAPD_DISCONNECT_PLUGIN, "P1" )
+ER2( SLAPD_DISCONNECT_UNBIND, "U1" )
+ER2( SLAPD_DISCONNECT_POLL, "P2" )
+ER2( SLAPD_DISCONNECT_NTSSL_TIMEOUT,"T2" )
+ER2( SLAPD_DISCONNECT_SASL_FAIL,"S1" )
+
+
+#endif /* __DISCONNECT_ERROR_STRINGS_H_ */
+
diff --git a/ldap/servers/slapd/disconnect_errors.h b/ldap/servers/slapd/disconnect_errors.h
new file mode 100644
index 00000000..c992b874
--- /dev/null
+++ b/ldap/servers/slapd/disconnect_errors.h
@@ -0,0 +1,32 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* disconnect_errors.h
+ *
+ * Errors used in logging the reason a connection was closed.
+ */
+#ifndef __DISCONNECT_ERRORS_H_
+#define __DISCONNECT_ERRORS_H_
+
+#define SLAPD_DISCONNECT_ERROR_BASE -5000
+
+#define SLAPD_DISCONNECT_ABORT SLAPD_DISCONNECT_ERROR_BASE + 0
+#define SLAPD_DISCONNECT_BAD_BER_TAG SLAPD_DISCONNECT_ERROR_BASE + 1
+#define SLAPD_DISCONNECT_BER_TOO_BIG SLAPD_DISCONNECT_ERROR_BASE + 2
+#define SLAPD_DISCONNECT_BER_PEEK SLAPD_DISCONNECT_ERROR_BASE + 3
+#define SLAPD_DISCONNECT_BER_FLUSH SLAPD_DISCONNECT_ERROR_BASE + 4
+#define SLAPD_DISCONNECT_IDLE_TIMEOUT SLAPD_DISCONNECT_ERROR_BASE + 5
+#define SLAPD_DISCONNECT_REVENTS SLAPD_DISCONNECT_ERROR_BASE + 6
+#define SLAPD_DISCONNECT_IO_TIMEOUT SLAPD_DISCONNECT_ERROR_BASE + 7
+#define SLAPD_DISCONNECT_PLUGIN SLAPD_DISCONNECT_ERROR_BASE + 8
+#define SLAPD_DISCONNECT_UNBIND SLAPD_DISCONNECT_ERROR_BASE + 9
+#define SLAPD_DISCONNECT_POLL SLAPD_DISCONNECT_ERROR_BASE + 10
+#define SLAPD_DISCONNECT_NTSSL_TIMEOUT SLAPD_DISCONNECT_ERROR_BASE + 11
+#define SLAPD_DISCONNECT_SASL_FAIL SLAPD_DISCONNECT_ERROR_BASE + 12
+
+
+
+#endif /* __DISCONNECT_ERRORS_H_ */
+
diff --git a/ldap/servers/slapd/dl.c b/ldap/servers/slapd/dl.c
new file mode 100644
index 00000000..b4724b06
--- /dev/null
+++ b/ldap/servers/slapd/dl.c
@@ -0,0 +1,219 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* DataList access functions */
+#define INIT_ALLOC 8
+#define ALLOC_INCREMENT 4
+
+#include "slap.h"
+
+DataList* dl_new ()
+{
+ return (DataList*)slapi_ch_malloc (sizeof (DataList));
+}
+void dl_free (DataList **dl)
+{
+ slapi_ch_free ((void**) dl);
+}
+
+void dl_init (DataList *dl, int init_alloc)
+{
+ PR_ASSERT (dl);
+
+ memset (dl, 0, sizeof (*dl));
+
+ if (init_alloc <= 0)
+ dl->alloc_count = INIT_ALLOC;
+ else
+ dl->alloc_count = init_alloc;
+
+ dl->elements = (void**)slapi_ch_calloc (dl->alloc_count, sizeof (void*));
+}
+
+void dl_cleanup (DataList *dl, FREEFN freefn)
+{
+ PR_ASSERT (dl);
+
+ if (freefn && dl->elements)
+ {
+ int i;
+
+ for (i = 0; i < dl->element_count; i++)
+ {
+ freefn (&(dl->elements[i]));
+ }
+ }
+
+ if (dl->elements)
+ {
+ slapi_ch_free ((void**)&dl->elements);
+ }
+
+ memset (dl, 0, sizeof (*dl));
+}
+
+/* index == 1 : insert first */
+void dl_add_index (DataList *dl, void *element, int index)
+{
+ int i = 0;
+
+ PR_ASSERT (dl);
+ PR_ASSERT (element);
+
+ if (dl->element_count == dl->alloc_count)
+ {
+ dl->alloc_count += ALLOC_INCREMENT;
+ dl->elements = (void**)slapi_ch_realloc ((char*)dl->elements, dl->alloc_count * sizeof (void*));
+ }
+
+ dl->element_count ++;
+
+ for (i = dl->element_count-1; i >= index; i--)
+ {
+ dl->elements[i] = dl->elements[i-1];
+ }
+ if ( dl->element_count < index )
+ {
+ /* Means that we are adding the first element */
+ dl->elements[0] = element;
+ }
+ else
+ {
+ dl->elements[i] = element;
+ }
+}
+
+void dl_add (DataList *dl, void *element)
+{
+ PR_ASSERT (dl);
+ PR_ASSERT (element);
+
+ if (dl->element_count == dl->alloc_count)
+ {
+ dl->alloc_count += ALLOC_INCREMENT;
+ dl->elements = (void**)slapi_ch_realloc ((char*)dl->elements, dl->alloc_count * sizeof (void*));
+ }
+
+ dl->elements[dl->element_count] = element;
+ dl->element_count ++;
+}
+
+void *dl_get_first (const DataList *dl, int *cookie)
+{
+ PR_ASSERT (dl);
+ PR_ASSERT (cookie);
+
+ if (dl->element_count == 0)
+ return NULL;
+
+ *cookie = 1;
+ return dl->elements[0];
+}
+
+void *dl_get_next (const DataList *dl, int *cookie)
+{
+ PR_ASSERT (dl);
+ PR_ASSERT (cookie && *cookie > 0);
+
+ if (*cookie >= dl->element_count)
+ return NULL;
+
+ return dl->elements[(*cookie)++];
+}
+
+void *dl_replace(const DataList *dl, const void *elementOld, void *elementNew, CMPFN cmpfn, FREEFN freefn)
+{
+ int i;
+ void *save;
+
+ PR_ASSERT (dl);
+ PR_ASSERT (elementOld);
+ PR_ASSERT (elementNew);
+ PR_ASSERT (cmpfn);
+
+ for (i = 0; i < dl->element_count; i++)
+ {
+ if (cmpfn (dl->elements[i], elementOld) == 0)
+ {
+ /* if we have destructor - free the data; otherwise, return it to the client */
+ if (freefn)
+ {
+ freefn (&dl->elements[i]);
+ save = NULL;
+ }
+ else
+ save = dl->elements[i];
+
+ dl->elements[i] = elementNew;
+
+ return save;
+ }
+ }
+
+ return NULL;
+}
+
+void *dl_get (const DataList *dl, const void *element, CMPFN cmpfn)
+{
+ int i;
+
+ PR_ASSERT (dl);
+ PR_ASSERT (element);
+ PR_ASSERT (cmpfn);
+
+ for (i = 0; i < dl->element_count; i++)
+ {
+ if (cmpfn (dl->elements[i], element) == 0)
+ {
+ return dl->elements[i];
+ }
+ }
+
+ return NULL;
+}
+
+void *dl_delete (DataList *dl, const void *element, CMPFN cmpfn, FREEFN freefn)
+{
+ int i;
+ void *save;
+
+ PR_ASSERT (dl);
+ PR_ASSERT (element);
+ PR_ASSERT (cmpfn);
+
+ for (i = 0; i < dl->element_count; i++)
+ {
+ if (cmpfn (dl->elements[i], element) == 0)
+ {
+ /* if we have destructor - free the data; otherwise, return it to the client */
+ if (freefn)
+ {
+ freefn (&dl->elements[i]);
+ save = NULL;
+ }
+ else
+ save = dl->elements[i];
+
+ if (i != dl->element_count - 1)
+ {
+ memcpy (&dl->elements[i], &dl->elements[i+1], (dl->element_count - i - 1) * sizeof (void*));
+ }
+
+ dl->element_count --;
+
+ return save;
+ }
+ }
+
+ return NULL;
+}
+
+int dl_get_count (const DataList *dl)
+{
+ PR_ASSERT (dl);
+
+ return dl->element_count;
+}
+
diff --git a/ldap/servers/slapd/dn.c b/ldap/servers/slapd/dn.c
new file mode 100644
index 00000000..0a05a6a8
--- /dev/null
+++ b/ldap/servers/slapd/dn.c
@@ -0,0 +1,1469 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* dn.c - routines for dealing with distinguished names */
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+
+#undef SDN_DEBUG
+
+static void add_rdn_av( char *avstart, char *avend, int *rdn_av_countp,
+ struct berval **rdn_avsp, struct berval *avstack );
+static void reset_rdn_avs( struct berval **rdn_avsp, int *rdn_av_countp );
+static void sort_rdn_avs( struct berval *avs, int count );
+static int rdn_av_cmp( struct berval *av1, struct berval *av2 );
+static void rdn_av_swap( struct berval *av1, struct berval *av2 );
+
+
+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 );
+}
+
+#define DNSEPARATOR(c) (c == ',' || c == ';')
+#define SEPARATOR(c) (c == ',' || c == ';' || c == '+')
+#define SPACE(c) (c == ' ' || c == '\n') /* XXX 518524 */
+#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
+
+#define SLAPI_DNNORM_INITIAL_RDN_AVS 10
+#define SLAPI_DNNORM_SMALL_RDN_AV 512
+
+/*
+ * 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).
+ *
+ * Finally, if the DN contains any RDNs that are multivalued, we sort
+ * the values in the RDN(s) to help meet goal 3. Ordering is based on a
+ * case-insensitive comparison of the "attribute=value" pairs.
+ *
+ * This function does not support UTF-8 multi-byte encoding for attribute
+ * values, in particular it does not support UTF-8 whitespace. First the
+ * SPACE macro above is limited, but also its frequent use of '-1' indexing
+ * into a char[] may hit the middle of a multi-byte UTF-8 whitespace character
+ * encoding (518524).
+ */
+
+char *
+substr_dn_normalize( char *dn, char *end )
+{
+ /* \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 = NULL;
+ char *value_separator = NULL;
+ char *d = NULL;
+ char *s = NULL;
+ char *typestart = NULL;
+ int gotesc = 0;
+ int state = B4TYPE;
+ int rdn_av_count = 0;
+ struct berval *rdn_avs = NULL;
+ struct berval initial_rdn_av_stack[ SLAPI_DNNORM_INITIAL_RDN_AVS ];
+
+ for ( d = s = dn; s != end; s++ ) {
+ switch ( state ) {
+ case B4TYPE:
+ if ( ! SPACE( *s ) ) {
+ state = INTYPE;
+ typestart = d;
+ *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: */
+ char *L = NULL; /* char after last seperator */
+ char *R; /* value character iterator */
+ int escape_skips = 0; /* number of escapes we have seen after the first */
+
+ for ( R = value; (R = strchr( R, '\\' )) && (R < d); L = ++R ) {
+ if ( SEPARATOR( R[1] )) {
+ if ( L == NULL ) {
+ /* executes once, at first escape, adds opening quote */
+ const size_t len = R - value;
+
+ /* make room for quote by covering escape */
+ if ( len > 0 ) {
+ memmove( value+1, value, len );
+ }
+
+ *value = '"'; /* opening quote */
+ value = R + 1; /* move passed what has been parsed */
+ } else {
+ const size_t len = R - L;
+ if ( len > 0 ) {
+ /* remove the seperator */
+ memmove( value, L, len );
+ value += len; /* move passed what has been parsed */
+ }
+ --d;
+ ++escape_skips;
+ }
+ }
+ }
+ memmove( value, L, d - L + escape_skips );
+ *d++ = '"'; /* closing quote */
+ }
+ state = B4TYPE;
+
+ /*
+ * Track and sort attribute values within
+ * multivalued RDNs.
+ */
+ if ( *s == '+' || rdn_av_count > 0 ) {
+ add_rdn_av( typestart, d, &rdn_av_count,
+ &rdn_avs, initial_rdn_av_stack );
+ }
+ if ( *s != '+' ) { /* at end of this RDN */
+ if ( rdn_av_count > 1 ) {
+ sort_rdn_avs( rdn_avs, rdn_av_count );
+ }
+ if ( rdn_av_count > 0 ) {
+ reset_rdn_avs( &rdn_avs, &rdn_av_count );
+ }
+ }
+
+ *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;
+
+ /*
+ * Track and sort attribute values within
+ * multivalued RDNs.
+ */
+ if ( *s == '+' || rdn_av_count > 0 ) {
+ add_rdn_av( typestart, d, &rdn_av_count,
+ &rdn_avs, initial_rdn_av_stack );
+ }
+ if ( *s != '+' ) { /* at end of this RDN */
+ if ( rdn_av_count > 1 ) {
+ sort_rdn_avs( rdn_avs, rdn_av_count );
+ }
+ if ( rdn_av_count > 0 ) {
+ reset_rdn_avs( &rdn_avs, &rdn_av_count );
+ }
+ }
+
+ *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 ) {
+ int n = hexchar2int( s[1] );
+ if ( n >= 0 ) {
+ 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;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * Track and sort attribute values within multivalued RDNs.
+ */
+ if ( rdn_av_count > 0 ) {
+ add_rdn_av( typestart, d, &rdn_av_count,
+ &rdn_avs, initial_rdn_av_stack );
+ }
+ if ( rdn_av_count > 1 ) {
+ sort_rdn_avs( rdn_avs, rdn_av_count );
+ }
+ if ( rdn_av_count > 0 ) {
+ reset_rdn_avs( &rdn_avs, &rdn_av_count );
+ }
+
+ /* Trim trailing spaces */
+ while ( d != dn && *(d - 1) == ' ' ) d--; /* XXX 518524 */
+
+ return( d );
+}
+
+
+
+/*
+ * Append previous AV to the attribute value array if multivalued RDN.
+ * We use a stack based array at first and if we overflow that, we
+ * allocate a larger one from the heap, copy the stack based data in,
+ * and continue to grow the heap based one as needed.
+ */
+static void
+add_rdn_av( char *avstart, char *avend, int *rdn_av_countp,
+ struct berval **rdn_avsp, struct berval *avstack )
+{
+ if ( *rdn_av_countp == 0 ) {
+ *rdn_avsp = avstack;
+ } else if ( *rdn_av_countp == SLAPI_DNNORM_INITIAL_RDN_AVS ) {
+ struct berval *tmpavs;
+
+ tmpavs = (struct berval *)slapi_ch_calloc(
+ SLAPI_DNNORM_INITIAL_RDN_AVS * 2, sizeof( struct berval ));
+ memcpy( tmpavs, *rdn_avsp,
+ SLAPI_DNNORM_INITIAL_RDN_AVS * sizeof( struct berval ));
+ *rdn_avsp = tmpavs;
+ } else if (( *rdn_av_countp % SLAPI_DNNORM_INITIAL_RDN_AVS ) == 0 ) {
+ *rdn_avsp = (struct berval *)slapi_ch_realloc( (char *)*rdn_avsp,
+ (*rdn_av_countp + SLAPI_DNNORM_INITIAL_RDN_AVS)*sizeof(struct berval) );
+ }
+
+ /*
+ * Note: The bv_val's are just pointers into the dn itself. Also,
+ * we DO NOT zero-terminate the bv_val's. The sorting code in
+ * sort_rdn_avs() takes all of this into account.
+ */
+ (*rdn_avsp)[ *rdn_av_countp ].bv_val = avstart;
+ (*rdn_avsp)[ *rdn_av_countp ].bv_len = avend - avstart;
+ ++(*rdn_av_countp);
+}
+
+
+/*
+ * Reset RDN attribute value array, freeing memory if any was allocated.
+ */
+static void
+reset_rdn_avs( struct berval **rdn_avsp, int *rdn_av_countp )
+{
+ if ( *rdn_av_countp > SLAPI_DNNORM_INITIAL_RDN_AVS ) {
+ slapi_ch_free( (void **)rdn_avsp );
+ }
+ *rdn_avsp = NULL;
+ *rdn_av_countp = 0;
+}
+
+
+/*
+ * Perform an in-place, case-insensitive sort of RDN attribute=value pieces.
+ * This function is always called with more than one element in "avs".
+ *
+ * Note that this is used by the DN normalization code, so if any changes
+ * are made to the comparison function used for sorting customers will need
+ * to rebuild their database/index files.
+ *
+ * Also note that the bv_val's in the "avas" array are not zero-terminated.
+ */
+static void
+sort_rdn_avs( struct berval *avs, int count )
+{
+ int i, j, swaps;
+
+ /*
+ * Since we expect there to be a small number of AVs, we use a
+ * simple bubble sort. rdn_av_swap() only works correctly on
+ * adjacent values anyway.
+ */
+ for ( i = 0; i < count - 1; ++i ) {
+ swaps = 0;
+ for ( j = 0; j < count - 1; ++j ) {
+ if ( rdn_av_cmp( &avs[j], &avs[j+1] ) > 0 ) {
+ rdn_av_swap( &avs[j], &avs[j+1] );
+ ++swaps;
+ }
+ }
+ if ( swaps == 0 ) {
+ break; /* stop early if no swaps made during the last pass */
+ }
+ }
+}
+
+
+/*
+ * strcasecmp()-like function for RDN attribute values.
+ */
+static int
+rdn_av_cmp( struct berval *av1, struct berval *av2 )
+{
+ int rc;
+
+ rc = strncasecmp( av1->bv_val, av2->bv_val,
+ ( av1->bv_len < av2->bv_len ) ? av1->bv_len : av2->bv_len );
+
+ if ( rc == 0 ) {
+ return( av1->bv_len - av2->bv_len ); /* longer is greater */
+ } else {
+ return( rc );
+ }
+}
+
+
+/*
+ * Swap two adjacent attribute=value pieces within an (R)DN.
+ * Avoid allocating any heap memory for reasonably small AVs.
+ */
+static void
+rdn_av_swap( struct berval *av1, struct berval *av2 )
+{
+ char *buf1, *buf2;
+ char stackbuf1[ SLAPI_DNNORM_SMALL_RDN_AV ];
+ char stackbuf2[ SLAPI_DNNORM_SMALL_RDN_AV ];
+ int len1, len2;
+
+ /*
+ * Copy the two avs into temporary buffers. We use stack-based buffers
+ * if the avs are small and allocate buffers from the heap to hold
+ * large values.
+ */
+ if (( len1 = av1->bv_len ) <= SLAPI_DNNORM_SMALL_RDN_AV ) {
+ buf1 = stackbuf1;
+ } else {
+ buf1 = slapi_ch_malloc( len1 );
+ }
+ memcpy( buf1, av1->bv_val, len1 );
+
+ if (( len2 = av2->bv_len ) <= SLAPI_DNNORM_SMALL_RDN_AV ) {
+ buf2 = stackbuf2;
+ } else {
+ buf2 = slapi_ch_malloc( len2 );
+ }
+ memcpy( buf2, av2->bv_val, len2 );
+
+ /*
+ * Copy av2 over av1 and reset length of av1.
+ */
+ memcpy( av1->bv_val, buf2, av2->bv_len );
+ av1->bv_len = len2;
+
+ /*
+ * Add separator character (+) and copy av1 into place.
+ * Also reset av2 pointer and length.
+ */
+ av2->bv_val = av1->bv_val + len2;
+ *(av2->bv_val)++ = '+';
+ memcpy( av2->bv_val, buf1, len1 );
+ av2->bv_len = len1;
+
+ /*
+ * Clean up.
+ */
+ if ( len1 > SLAPI_DNNORM_SMALL_RDN_AV ) {
+ slapi_ch_free( (void **)&buf1 );
+ }
+ if ( len2 > SLAPI_DNNORM_SMALL_RDN_AV ) {
+ slapi_ch_free( (void **)&buf2 );
+ }
+}
+
+
+/*
+ * slapi_dn_normalize - put dn into a canonical format. the dn is
+ * normalized in place, as well as returned.
+ */
+
+char *
+slapi_dn_normalize( char *dn )
+{
+ /* LDAPDebug( LDAP_DEBUG_TRACE, "=> slapi_dn_normalize \"%s\"\n", dn, 0, 0 ); */
+ *(substr_dn_normalize( dn, dn + strlen( dn ))) = '\0';
+ /* LDAPDebug( LDAP_DEBUG_TRACE, "<= slapi_dn_normalize \"%s\"\n", dn, 0, 0 ); */
+ return dn;
+}
+
+/* Note that this routine normalizes to the end and doesn't null terminate */
+char *
+slapi_dn_normalize_to_end( char *dn , char *end)
+{
+ return ( substr_dn_normalize( dn, end ? end : dn + strlen( dn )) );
+}
+
+/*
+ * dn could contain UTF-8 multi-byte characters,
+ * which also need to be converted to the lower case.
+ */
+char *
+slapi_dn_ignore_case( char *dn )
+{
+ unsigned char *s, *d;
+ int ssz, dsz;
+ /* normalize case (including UTF-8 multi-byte chars) */
+ for ( s = d = (unsigned char *)dn; *s; s += ssz, d += dsz ) {
+ slapi_utf8ToLower( s, d, &ssz, &dsz );
+ }
+ *d = '\0'; /* utf8ToLower result may be shorter than the original */
+ return( dn );
+}
+
+/*
+ * slapi_dn_normalize_case - put dn into a canonical form suitable for storing
+ * in a hash database. this involves normalizing the case as well as
+ * the format. the dn is normalized in place as well as returned.
+ */
+
+char *
+slapi_dn_normalize_case( char *dn )
+{
+ /* normalize format */
+ slapi_dn_normalize( dn );
+
+ /* normalize case */
+ return( slapi_dn_ignore_case( dn ));
+}
+
+/*
+ * slapi_dn_beparent - return a copy of the dn of dn's parent,
+ * NULL if the DN is a suffix of the backend.
+ */
+char *
+slapi_dn_beparent(
+ Slapi_PBlock *pb,
+ const char *dn
+)
+{
+ char *r= NULL;
+ if ( dn != NULL && *dn != '\0')
+ {
+ if(!slapi_dn_isbesuffix( pb, dn ))
+ {
+ r= slapi_dn_parent( dn );
+ }
+ }
+ return r;
+}
+
+char*
+slapi_dn_parent( const char *dn )
+{
+ const char *s;
+ int inquote;
+
+ if ( dn == NULL || *dn == '\0' ) {
+ return( NULL );
+ }
+
+ /*
+ * An X.500-style distinguished name looks like this:
+ * foo=bar,sha=baz,...
+ */
+
+ inquote = 0;
+ for ( s = dn; *s; s++ ) {
+ if ( *s == '\\' ) {
+ if ( *(s + 1) )
+ s++;
+ continue;
+ }
+ if ( inquote ) {
+ if ( *s == '"' )
+ inquote = 0;
+ } else {
+ if ( *s == '"' )
+ inquote = 1;
+ else if ( DNSEPARATOR( *s ) )
+ return( slapi_ch_strdup( s + 1 ) );
+ }
+ }
+
+ return( NULL );
+}
+
+/*
+ * slapi_dn_issuffix - tells whether suffix is a suffix of dn. both dn
+ * and suffix must be normalized.
+ */
+int
+slapi_dn_issuffix(const char *dn, const char *suffix)
+{
+ int dnlen, suffixlen;
+
+ if ( dn==NULL || suffix==NULL)
+ {
+ return( 0 );
+ }
+
+ suffixlen = strlen( suffix );
+ dnlen = strlen( dn );
+
+ if ( suffixlen > dnlen )
+ {
+ return( 0 );
+ }
+
+ if ( suffixlen == 0 )
+ {
+ return ( 1 );
+ }
+
+ return( (slapi_utf8casecmp( (unsigned char *)(dn + dnlen - suffixlen),
+ (unsigned char *)suffix ) == 0)
+ && ( (dnlen == suffixlen) || DNSEPARATOR(dn[dnlen-suffixlen-1])) );
+}
+
+int
+slapi_dn_isbesuffix( Slapi_PBlock *pb, const char *dn )
+{
+ int r;
+ Slapi_DN sdn;
+ slapi_sdn_init_dn_byref(&sdn,dn);
+ r= slapi_be_issuffix( pb->pb_backend, &sdn );
+ slapi_sdn_done(&sdn);
+ return r;
+}
+
+/*
+ * slapi_dn_isparent - returns non-zero if parentdn is the parent of childdn,
+ * 0 otherwise
+ */
+int
+slapi_dn_isparent( const char *parentdn, const char *childdn )
+{
+ char *realparentdn, *copyparentdn;
+ int rc;
+
+ /* child is root - has no parent */
+ if ( childdn == NULL || *childdn == '\0' ) {
+ return( 0 );
+ }
+
+ /* construct the actual parent dn and normalize it */
+ if ( (realparentdn = slapi_dn_parent( childdn )) == NULL ) {
+ return( parentdn == NULL || *parentdn == '\0' );
+ }
+ slapi_dn_normalize( realparentdn );
+
+ /* normalize the purported parent dn */
+ copyparentdn = slapi_ch_strdup( (char *)parentdn );
+ slapi_dn_normalize( copyparentdn );
+
+ /* compare them */
+ rc = ! strcasecmp( realparentdn, copyparentdn );
+ slapi_ch_free( (void**)&copyparentdn );
+ slapi_ch_free( (void**)&realparentdn );
+
+ return( rc );
+}
+
+/*
+ * Function: slapi_dn_isroot
+ *
+ * Returns: 1 if "dn" is the root dn
+ * 0 otherwise.
+ * dn must be normalized
+ *
+ */
+int
+slapi_dn_isroot( const char *dn )
+{
+ int rc;
+ char *rootdn;
+
+ if ( NULL == dn ) {
+ return( 0 );
+ }
+ if ( NULL == (rootdn = config_get_rootdn())) {
+ return( 0 );
+ }
+
+ /* note: global root dn is normalized when read from config. file */
+ rc = (strcasecmp( rootdn, dn ) == 0);
+ slapi_ch_free ( (void **) &rootdn );
+ return( rc );
+}
+
+int
+slapi_is_rootdse( const char *dn )
+{
+ if ( NULL != dn )
+ {
+ if ( *dn == '\0' )
+ {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+/*
+** This function takes a quoted attribute value of the form "abc",
+** and strips off the enclosing quotes. It also deals with quoted
+** characters by removing the preceeding '\' character.
+**
+*/
+static void
+strcpy_unescape_dnvalue( char *d, const char *s )
+{
+ const char *end = s + strlen(s);
+ for ( ; *s; s++ )
+ {
+ switch ( *s )
+ {
+ case '"':
+ break;
+ case '\\':
+ {
+ /*
+ * The '\' could be escaping a single character, ie \"
+ * or could be escaping a hex byte, ie \01
+ */
+ int singlecharacter= 1;
+ if ( s+2 < end )
+ {
+ int n = hexchar2int( s[1] );
+ if ( n >= 0 )
+ {
+ int n2 = hexchar2int( s[2] );
+ if ( n2 >= 0 )
+ {
+ singlecharacter= 0;
+ n = (n << 4) + n2;
+ if (n == 0)
+ {
+ /* don't change \00 */
+ *d++ = *++s;
+ *d++ = *++s;
+ }
+ else
+ {
+ /* change \xx to a single char */
+ ++s;
+ *(unsigned char*)(s+1) = n;
+ }
+ }
+ }
+ }
+ if(singlecharacter)
+ {
+ s++;
+ *d++ = *s;
+ }
+ break;
+ }
+ default:
+ *d++ = *s;
+ break;
+ }
+ }
+ *d = '\0';
+}
+
+
+
+int
+slapi_rdn2typeval(
+ char *rdn,
+ char **type,
+ struct berval *bv
+)
+{
+ char *s;
+
+ if ( (s = strchr( rdn, '=' )) == NULL ) {
+ return( -1 );
+ }
+ *s++ = '\0';
+
+ *type = rdn;
+
+ /* MAB 9 Oct 00 : explicit bug fix of 515715
+ implicit bug fix of 394800 (can't reproduce anymore)
+ When adding the rdn attribute in the entry, we need to remove
+ all special escaped characters included in the value itself,
+ i.e., strings like "\;" must be converted to ";" and so on... */
+ strcpy_unescape_dnvalue(s,s);
+
+ bv->bv_val = s;
+ bv->bv_len = strlen( s );
+
+ return( 0 );
+}
+
+/*
+ * Add an RDN to a DN, getting back the new DN.
+ */
+char *
+slapi_dn_plus_rdn(const char *dn, const char *rdn)
+{
+ /* rdn + separator + dn + null */
+ char *newdn = (char *) slapi_ch_malloc( strlen( dn ) + strlen( rdn ) + 2 );
+ strcpy( newdn, rdn );
+ strcat( newdn, "," );
+ strcat( newdn, dn );
+ return newdn;
+}
+
+/* ====== Slapi_DN functions ====== */
+
+#ifdef SDN_DEBUG
+#define SDN_DUMP(sdn,name) sdn_dump(sdn,name)
+static void sdn_dump( const Slapi_DN *sdn, const char *text);
+#else
+#define SDN_DUMP(sdn,name) ((void)0)
+#endif
+
+#ifndef SLAPI_DN_COUNTERS
+#undef DEBUG /* disable counters */
+#endif
+#include <prcountr.h>
+
+static int counters_created= 0;
+PR_DEFINE_COUNTER(slapi_sdn_counter_created);
+PR_DEFINE_COUNTER(slapi_sdn_counter_deleted);
+PR_DEFINE_COUNTER(slapi_sdn_counter_exist);
+PR_DEFINE_COUNTER(slapi_sdn_counter_dn_created);
+PR_DEFINE_COUNTER(slapi_sdn_counter_dn_deleted);
+PR_DEFINE_COUNTER(slapi_sdn_counter_dn_exist);
+PR_DEFINE_COUNTER(slapi_sdn_counter_ndn_created);
+PR_DEFINE_COUNTER(slapi_sdn_counter_ndn_deleted);
+PR_DEFINE_COUNTER(slapi_sdn_counter_ndn_exist);
+
+static void
+sdn_create_counters()
+{
+ PR_CREATE_COUNTER(slapi_sdn_counter_created,"Slapi_DN","created","");
+ PR_CREATE_COUNTER(slapi_sdn_counter_deleted,"Slapi_DN","deleted","");
+ PR_CREATE_COUNTER(slapi_sdn_counter_exist,"Slapi_DN","exist","");
+ PR_CREATE_COUNTER(slapi_sdn_counter_dn_created,"Slapi_DN","internal_dn_created","");
+ PR_CREATE_COUNTER(slapi_sdn_counter_dn_deleted,"Slapi_DN","internal_dn_deleted","");
+ PR_CREATE_COUNTER(slapi_sdn_counter_dn_exist,"Slapi_DN","internal_dn_exist","");
+ PR_CREATE_COUNTER(slapi_sdn_counter_ndn_created,"Slapi_DN","internal_ndn_created","");
+ PR_CREATE_COUNTER(slapi_sdn_counter_ndn_deleted,"Slapi_DN","internal_ndn_deleted","");
+ PR_CREATE_COUNTER(slapi_sdn_counter_ndn_exist,"Slapi_DN","internal_ndn_exist","");
+ counters_created= 1;
+}
+
+#define FLAG_ALLOCATED 0
+#define FLAG_DN 1
+#define FLAG_NDN 2
+
+Slapi_DN *
+slapi_sdn_new()
+{
+ Slapi_DN *sdn= (Slapi_DN *)slapi_ch_malloc(sizeof(Slapi_DN));
+ slapi_sdn_init(sdn);
+ sdn->flag= slapi_setbit_uchar(sdn->flag,FLAG_ALLOCATED);
+ SDN_DUMP( sdn, "slapi_sdn_new");
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_created);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_exist);
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_init(Slapi_DN *sdn)
+{
+ sdn->flag= 0;
+ sdn->dn= NULL;
+ sdn->ndn= NULL;
+ sdn->ndn_len=0;
+ if(!counters_created)
+ {
+ sdn_create_counters();
+ }
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_init_dn_byref(Slapi_DN *sdn,const char *dn)
+{
+ slapi_sdn_init(sdn);
+ slapi_sdn_set_dn_byref(sdn,dn);
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_init_dn_byval(Slapi_DN *sdn,const char *dn)
+{
+ slapi_sdn_init(sdn);
+ slapi_sdn_set_dn_byval(sdn,dn);
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_init_dn_passin(Slapi_DN *sdn,const char *dn)
+{
+ slapi_sdn_init(sdn);
+ slapi_sdn_set_dn_passin(sdn,dn);
+ return sdn;
+}
+
+/* use when dn is normalized previously */
+Slapi_DN *
+slapi_sdn_init_dn_ndn_byref(Slapi_DN *sdn,const char *dn) {
+ slapi_sdn_init(sdn);
+ slapi_sdn_set_dn_byref(sdn,dn);
+ /* slapi_sdn_set_ndn_byref nulls out dn set in above statement */
+ sdn->flag= slapi_unsetbit_uchar(sdn->flag,FLAG_NDN);
+ sdn->ndn= dn;
+ if(dn == NULL) {
+ sdn->ndn_len=0;
+ } else {
+ sdn->ndn_len=strlen(dn);
+ }
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_init_ndn_byref(Slapi_DN *sdn,const char *dn)
+{
+ slapi_sdn_init(sdn);
+ slapi_sdn_set_ndn_byref(sdn,dn);
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_init_ndn_byval(Slapi_DN *sdn,const char *dn)
+{
+ slapi_sdn_init(sdn);
+ slapi_sdn_set_ndn_byval(sdn,dn);
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_new_dn_byval(const char *dn)
+{
+ Slapi_DN *sdn= slapi_sdn_new();
+ slapi_sdn_set_dn_byval(sdn,dn);
+ SDN_DUMP( sdn, "slapi_sdn_new_dn_byval");
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_new_ndn_byval(const char *ndn)
+{
+ Slapi_DN *sdn= slapi_sdn_new();
+ slapi_sdn_set_ndn_byval(sdn,ndn);
+ SDN_DUMP( sdn, "slapi_sdn_new_ndn_byval");
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_new_dn_byref(const char *dn)
+{
+ Slapi_DN *sdn= slapi_sdn_new();
+ slapi_sdn_set_dn_byref(sdn,dn);
+ SDN_DUMP( sdn, "slapi_sdn_new_dn_byref");
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_new_dn_passin(const char *dn)
+{
+ Slapi_DN *sdn= slapi_sdn_new();
+ slapi_sdn_set_dn_passin(sdn,dn);
+ SDN_DUMP( sdn, "slapi_sdn_new_dn_passin");
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_new_ndn_byref(const char *ndn)
+{
+ Slapi_DN *sdn= slapi_sdn_new();
+ slapi_sdn_set_ndn_byref(sdn,ndn);
+ SDN_DUMP( sdn, "slapi_sdn_new_ndn_byref");
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_set_dn_byval(Slapi_DN *sdn, const char *dn)
+{
+ slapi_sdn_done(sdn);
+ sdn->flag= slapi_setbit_uchar(sdn->flag,FLAG_DN);
+ if(dn!=NULL)
+ {
+ sdn->dn= slapi_ch_strdup(dn);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_dn_created);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_dn_exist);
+ }
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_set_dn_byref(Slapi_DN *sdn, const char *dn)
+{
+ slapi_sdn_done(sdn);
+ sdn->flag= slapi_unsetbit_uchar(sdn->flag,FLAG_DN);
+ sdn->dn= dn;
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_set_dn_passin(Slapi_DN *sdn, const char *dn)
+{
+ slapi_sdn_done(sdn);
+ sdn->flag= slapi_setbit_uchar(sdn->flag,FLAG_DN);
+ sdn->dn= dn;
+ if(dn!=NULL)
+ {
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_dn_created);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_dn_exist);
+ }
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_set_ndn_byval(Slapi_DN *sdn, const char *ndn)
+{
+ slapi_sdn_done(sdn);
+ sdn->flag= slapi_setbit_uchar(sdn->flag,FLAG_NDN);
+ if(ndn!=NULL)
+ {
+ sdn->ndn= slapi_ch_strdup(ndn);
+ sdn->ndn_len=strlen(ndn);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_ndn_created);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_ndn_exist);
+ }
+ return sdn;
+}
+
+Slapi_DN *
+slapi_sdn_set_ndn_byref(Slapi_DN *sdn, const char *ndn)
+{
+ slapi_sdn_done(sdn);
+ sdn->flag= slapi_unsetbit_uchar(sdn->flag,FLAG_NDN);
+ sdn->ndn= ndn;
+ if(ndn == NULL) {
+ sdn->ndn_len=0;
+ } else {
+ sdn->ndn_len=strlen(ndn);
+ }
+ return sdn;
+}
+
+/*
+ * Set the RDN of the DN.
+ */
+Slapi_DN *
+slapi_sdn_set_rdn(Slapi_DN *sdn, const Slapi_RDN *rdn)
+{
+ const char *rawrdn= slapi_rdn_get_rdn(rdn);
+ if(slapi_sdn_isempty(sdn))
+ {
+ slapi_sdn_set_dn_byval(sdn,rawrdn);
+ }
+ else
+ {
+ /* NewDN= NewRDN + OldParent */
+ char *parentdn= slapi_dn_parent(sdn->dn);
+ char *newdn= slapi_ch_malloc(strlen(rawrdn)+1+strlen(parentdn)+1);
+ strcpy( newdn, rawrdn );
+ strcat( newdn, "," );
+ strcat( newdn, parentdn );
+ slapi_ch_free((void**)&parentdn);
+ slapi_sdn_set_dn_passin(sdn,newdn);
+ }
+ return sdn;
+}
+
+/*
+ * Add the RDN to the DN.
+ */
+Slapi_DN *
+slapi_sdn_add_rdn(Slapi_DN *sdn, const Slapi_RDN *rdn)
+{
+ const char *rawrdn= slapi_rdn_get_rdn(rdn);
+ if(slapi_sdn_isempty(sdn))
+ {
+ slapi_sdn_set_dn_byval(sdn,rawrdn);
+ }
+ else
+ {
+ /* NewDN= NewRDN + DN */
+ const char *dn= slapi_sdn_get_dn(sdn);
+ char *newdn= slapi_ch_malloc(strlen(rawrdn)+1+strlen(dn)+1);
+ strcpy( newdn, rawrdn );
+ strcat( newdn, "," );
+ strcat( newdn, dn );
+ slapi_sdn_set_dn_passin(sdn,newdn);
+ }
+ return sdn;
+}
+
+/*
+ * Set the parent of the DN.
+ */
+Slapi_DN *
+slapi_sdn_set_parent(Slapi_DN *sdn, const Slapi_DN *parentdn)
+{
+ if(slapi_sdn_isempty(sdn))
+ {
+ slapi_sdn_copy(parentdn, sdn);
+ }
+ else
+ {
+ /* NewDN= OldRDN + NewParent */
+ Slapi_RDN rdn;
+ const char *rawrdn;
+ slapi_rdn_init_dn(&rdn,sdn->dn);
+ rawrdn= slapi_rdn_get_rdn(&rdn);
+ if(slapi_sdn_isempty(parentdn))
+ {
+ slapi_sdn_set_dn_byval(sdn,rawrdn);
+ }
+ else
+ {
+ char *newdn;
+ newdn= slapi_ch_malloc(strlen(rawrdn)+1+strlen(parentdn->dn)+1);
+ strcpy( newdn, rawrdn );
+ strcat( newdn, "," );
+ strcat( newdn, parentdn->dn );
+ slapi_sdn_set_dn_passin(sdn,newdn);
+ }
+ slapi_rdn_done(&rdn);
+ }
+ return sdn;
+}
+
+void
+slapi_sdn_done(Slapi_DN *sdn)
+{
+ /* sdn_dump( sdn, "slapi_sdn_done"); */
+ if(sdn->dn!=NULL)
+ {
+ if(slapi_isbitset_uchar(sdn->flag,FLAG_DN))
+ {
+ slapi_ch_free((void**)&(sdn->dn));
+ sdn->flag= slapi_unsetbit_uchar(sdn->flag,FLAG_DN);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_dn_deleted);
+ PR_DECREMENT_COUNTER(slapi_sdn_counter_dn_exist);
+ }
+ else
+ {
+ sdn->dn= NULL;
+ }
+ }
+ if(sdn->ndn!=NULL)
+ {
+ if(slapi_isbitset_uchar(sdn->flag,FLAG_NDN))
+ {
+ slapi_ch_free((void**)&(sdn->ndn));
+ sdn->flag= slapi_unsetbit_uchar(sdn->flag,FLAG_NDN);
+ sdn->ndn_len=0;
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_ndn_deleted);
+ PR_DECREMENT_COUNTER(slapi_sdn_counter_ndn_exist);
+ }
+ else
+ {
+ sdn->ndn= NULL;
+ sdn->ndn_len=0;
+ }
+ }
+}
+
+void
+slapi_sdn_free(Slapi_DN **sdn)
+{
+ if(sdn!=NULL && *sdn!=NULL)
+ {
+ SDN_DUMP( *sdn, "slapi_sdn_free");
+ slapi_sdn_done(*sdn);
+ if(slapi_isbitset_uchar((*sdn)->flag,FLAG_ALLOCATED))
+ {
+ slapi_ch_free((void**)sdn);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_deleted);
+ PR_DECREMENT_COUNTER(slapi_sdn_counter_exist);
+ }
+ }
+}
+
+const char *
+slapi_sdn_get_dn(const Slapi_DN *sdn)
+{
+ return (sdn->dn!=NULL ? sdn->dn : sdn->ndn);
+}
+
+const char *
+slapi_sdn_get_ndn(const Slapi_DN *sdn)
+{
+ if(sdn->ndn==NULL)
+ {
+ if(sdn->dn!=NULL)
+ {
+ char *p= slapi_ch_strdup(sdn->dn);
+ Slapi_DN *ncsdn= (Slapi_DN*)sdn; /* non-const Slapi_DN */
+ slapi_dn_normalize_case(p);
+ ncsdn->ndn= p;
+ ncsdn->ndn_len=strlen(p);
+ ncsdn->flag= slapi_setbit_uchar(sdn->flag,FLAG_NDN);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_ndn_created);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_ndn_exist);
+ }
+ }
+ return sdn->ndn;
+}
+
+void
+slapi_sdn_get_parent(const Slapi_DN *sdn,Slapi_DN *sdn_parent)
+{
+ const char *parentdn= slapi_dn_parent(slapi_sdn_get_dn(sdn));
+ slapi_sdn_set_dn_passin(sdn_parent,parentdn);
+ sdn_parent->flag= slapi_setbit_uchar(sdn_parent->flag,FLAG_DN);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_dn_created);
+ PR_INCREMENT_COUNTER(slapi_sdn_counter_dn_exist);
+}
+
+void
+slapi_sdn_get_backend_parent(const Slapi_DN *sdn,Slapi_DN *sdn_parent,const Slapi_Backend *backend)
+{
+ if(slapi_sdn_isempty(sdn) || slapi_be_issuffix( backend, sdn ))
+ {
+ slapi_sdn_done(sdn_parent);
+ }
+ else
+ {
+ slapi_sdn_get_parent(sdn,sdn_parent);
+ }
+}
+
+void
+slapi_sdn_get_rdn(const Slapi_DN *sdn,Slapi_RDN *rdn)
+{
+ slapi_rdn_set_dn(rdn,sdn->dn);
+}
+
+Slapi_DN *
+slapi_sdn_dup(const Slapi_DN *sdn)
+{
+ Slapi_DN *tmp;
+ SDN_DUMP( sdn, "slapi_sdn_dup");
+ tmp=slapi_sdn_new_dn_byval(slapi_sdn_get_dn(sdn));
+ /* can't use slapi_set_ndn_byval -- it nulls the dn */
+ tmp->flag= slapi_setbit_uchar(tmp->flag,FLAG_NDN);
+ if(sdn->ndn!=NULL)
+ {
+ tmp->ndn= slapi_ch_strdup(sdn->ndn);
+ tmp->ndn_len=sdn->ndn_len;
+ } else tmp->ndn=NULL;
+ return tmp;
+}
+
+void
+slapi_sdn_copy(const Slapi_DN *from, Slapi_DN *to)
+{
+ SDN_DUMP( from, "slapi_sdn_copy from");
+ SDN_DUMP( to, "slapi_sdn_copy to");
+ slapi_sdn_done(to);
+ slapi_sdn_set_dn_byval(to,slapi_sdn_get_dn(from));
+}
+
+int
+slapi_sdn_compare( const Slapi_DN *sdn1, const Slapi_DN *sdn2 )
+{
+ int rc;
+ const char *ndn1= slapi_sdn_get_ndn(sdn1);
+ const char *ndn2= slapi_sdn_get_ndn(sdn2);
+ if(ndn1==ndn2)
+ {
+ rc= 0;
+ }
+ else
+ {
+ if(ndn1==NULL)
+ {
+ rc= -1;
+ }
+ else
+ {
+ if(ndn2==NULL)
+ {
+ rc= 1;
+ }
+ else
+ {
+ rc= strcmp(ndn1,ndn2);
+ }
+ }
+ }
+ return rc;
+}
+
+int
+slapi_sdn_isempty( const Slapi_DN *sdn)
+{
+ const char *dn= slapi_sdn_get_dn(sdn);
+ return (dn==NULL || dn[0]=='\0');
+}
+
+int
+slapi_sdn_issuffix(const Slapi_DN *sdn, const Slapi_DN *suffixsdn)
+{
+ int rc;
+ const char *dn= slapi_sdn_get_ndn(sdn);
+ const char *suffixdn= slapi_sdn_get_ndn(suffixsdn);
+ if(dn!=NULL && suffixdn!=NULL)
+ {
+ int dnlen = slapi_sdn_get_ndn_len(sdn);
+ int suffixlen= slapi_sdn_get_ndn_len(suffixsdn);
+ if (dnlen<suffixlen)
+ {
+ rc= 0;
+ }
+ else
+ {
+ if ( suffixlen == 0 )
+ {
+ return ( 1 );
+ }
+
+ rc= ( (strcasecmp(suffixdn, dn+dnlen-suffixlen)==0)
+ && ( (dnlen == suffixlen)
+ || DNSEPARATOR(dn[dnlen-suffixlen-1])) );
+ }
+ }
+ else
+ {
+ rc= 0;
+ }
+ return rc;
+}
+
+/* normalizes sdn if it hasn't already been done */
+int
+slapi_sdn_get_ndn_len(const Slapi_DN *sdn)
+{
+ int r= 0;
+ const char *ndn=slapi_sdn_get_ndn(sdn);
+ if(sdn->ndn!=NULL)
+ {
+ r= sdn->ndn_len;
+ }
+ return r;
+}
+
+int
+slapi_sdn_isparent( const Slapi_DN *parent, const Slapi_DN *child )
+{
+ int rc= 0;
+
+ /* child is root - has no parent */
+ if ( !slapi_sdn_isempty(child) )
+ {
+ Slapi_DN childparent;
+ slapi_sdn_init(&childparent);
+ slapi_sdn_get_parent(child,&childparent);
+ rc= (slapi_sdn_compare(parent,&childparent)==0);
+ slapi_sdn_done(&childparent);
+ }
+ return( rc );
+}
+
+int
+slapi_sdn_isgrandparent( const Slapi_DN *parent, const Slapi_DN *child )
+{
+ int rc= 0;
+
+ /* child is root - has no parent */
+ if ( !slapi_sdn_isempty(child) )
+ {
+ Slapi_DN childparent;
+ slapi_sdn_init(&childparent);
+ slapi_sdn_get_parent(child,&childparent);
+ if ( !slapi_sdn_isempty(&childparent) )
+ {
+ Slapi_DN childchildparent;
+ slapi_sdn_init(&childchildparent);
+ slapi_sdn_get_parent(&childparent,&childchildparent);
+ rc= (slapi_sdn_compare(parent,&childchildparent)==0);
+ slapi_sdn_done(&childchildparent);
+ }
+ slapi_sdn_done(&childparent);
+ }
+ return( rc );
+}
+
+/*
+ * Return non-zero if "dn" matches the scoping criteria
+ * given by "base" and "scope".
+ */
+int
+slapi_sdn_scope_test( const Slapi_DN *dn, const Slapi_DN *base, int scope )
+{
+ int rc = 0;
+
+ switch ( scope ) {
+ case LDAP_SCOPE_BASE:
+ rc = ( slapi_sdn_compare( dn, base ) == 0 );
+ break;
+ case LDAP_SCOPE_ONELEVEL:
+ rc = ( slapi_sdn_isparent( base, dn ) != 0 );
+ break;
+ case LDAP_SCOPE_SUBTREE:
+ rc = ( slapi_sdn_issuffix( dn, base ) != 0 );
+ break;
+ }
+ return rc;
+}
+
+/*
+ * build the new dn of an entry for moddn operations
+ */
+char *
+slapi_moddn_get_newdn(Slapi_DN *dn_olddn, char *newrdn, char *newsuperiordn)
+{
+ char *newdn;
+
+ if( newsuperiordn!=NULL)
+ {
+ /* construct the new dn */
+ newdn= slapi_dn_plus_rdn(newsuperiordn, newrdn); /* JCM - Use Slapi_RDN */
+ }
+ else
+ {
+ /* construct the new dn */
+ char *pdn;
+ const char *dn= slapi_sdn_get_dn(dn_olddn);
+ pdn = slapi_dn_parent( dn );
+ if ( pdn != NULL )
+ {
+ newdn= slapi_dn_plus_rdn(pdn, newrdn); /* JCM - Use Slapi_RDN */
+ }
+ else
+ {
+ newdn= slapi_ch_strdup(newrdn);
+ }
+ slapi_ch_free( (void**)&pdn );
+ }
+ return newdn;
+}
+
+/* JCM slapi_sdn_get_first ? */
+/* JCM slapi_sdn_get_next ? */
+
+#ifdef SDN_DEBUG
+static void
+sdn_dump( const Slapi_DN *sdn, const char *text)
+{
+ LDAPDebug( LDAP_DEBUG_ANY, "SDN %s ptr=%lx dn=%s\n", text, sdn, (sdn->dn==NULL?"NULL":sdn->dn));
+}
+#endif
diff --git a/ldap/servers/slapd/dse.c b/ldap/servers/slapd/dse.c
new file mode 100644
index 00000000..31c23e3b
--- /dev/null
+++ b/ldap/servers/slapd/dse.c
@@ -0,0 +1,2304 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * dse.c - DSE (DSA-Specific Entry) persistent storage.
+ *
+ * The DSE store is an LDIF file contained in the file
+ * INSTANCEDIR/config/XXX.ldif, where INSTANCEDIR is
+ * the directory of the server instance, and XXX is
+ * dfined by the caller of dse_new.
+ *
+ * In core, the DSEs are stored in an AVL tree, keyed on
+ * DN. Whenever a modification is made to a DSE, the
+ * in-core entry is updated, then dse_write_file() is
+ * called to commit the changes to disk.
+ *
+ * This is designed for a small number of DSEs, say
+ * a maximum of 10 or 20. If large numbers of DSEs
+ * need to be stored, this approach of writing out
+ * the entire contents on every modification will
+ * be insufficient.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <prio.h>
+#include <prcountr.h>
+#include "slap.h"
+
+#if !defined (_WIN32)
+#include <pwd.h>
+#endif /* _WIN32 */
+
+/* #define SLAPI_DSE_DEBUG */ /* define this to force trace log */
+ /* messages to always be logged */
+
+#ifdef SLAPI_DSE_DEBUG
+#define SLAPI_DSE_TRACELEVEL LDAP_DEBUG_ANY
+#else /* SLAPI_DSE_DEBUG */
+#define SLAPI_DSE_TRACELEVEL LDAP_DEBUG_TRACE
+#endif /* SLAPI_DSE_DEBUG */
+
+#define STOP_TRAVERSAL -2
+
+/* This is returned by dupentry_replace if the duplicate entry was found and
+ replaced. This is returned up through the avl_insert() in
+ dse_replace_entry(). Otherwise, if avl_insert() returns 0, the
+ entry was added i.e. a duplicate was not found.
+*/
+#define DSE_ENTRY_WAS_REPLACED -3
+/* This is returned by dupentry_merge if the duplicate entry was found and
+ merged. This is returned up through the avl_insert() in dse_add_entry_pb().
+ Otherwise, if avl_insert() returns 0, the
+ entry was added i.e. a duplicate was not found.
+*/
+#define DSE_ENTRY_WAS_MERGED -4
+
+/* some functions can be used either from within a lock or "standalone" */
+#define DSE_USE_LOCK 1
+#define DSE_NO_LOCK 0
+
+struct dse_callback
+{
+ int operation;
+ int flags;
+ Slapi_DN *base;
+ int scope;
+ char *filter; /* NULL means match all entries */
+ Slapi_Filter *slapifilter; /* NULL means match all entries */
+ int (*fn)(Slapi_PBlock *,Slapi_Entry *,Slapi_Entry *,int*,char*,void *);
+ void *fn_arg;
+ struct dse_callback *next;
+};
+
+struct dse
+{
+ char *dse_filename; /* these are the primary files which get read from */
+ char *dse_tmpfile; /* and written to when changes are made via LDAP */
+ char *dse_fileback; /* contain the latest info, just before a new change */
+ char *dse_filestartOK; /* contain the latest info with which the server has successfully started */
+ Avlnode *dse_tree;
+ struct dse_callback *dse_callback;
+ PRRWLock *dse_rwlock; /* a read-write lock to protect the whole dse backend */
+ char **dse_filelist; /* these are additional read only files used to */
+ /* initialize the dse */
+ int dse_is_updateable; /* if non-zero, this DSE can be written to */
+ int dse_readonly_error_reported; /* used to ensure that read-only errors are logged only once */
+};
+
+struct dse_node
+{
+ Slapi_Entry *entry;
+};
+
+/* search set stuff - used to pass search results to the frontend */
+typedef struct dse_search_set
+{
+ DataList dl;
+ int current_entry;
+} dse_search_set;
+
+static int dse_permission_to_write(struct dse* pdse, int loglevel);
+static int dse_write_file_nolock(struct dse* pdse);
+static int dse_apply_nolock(struct dse* pdse, IFP fp, caddr_t arg);
+static int dse_replace_entry( struct dse* pdse, Slapi_Entry *e, int write_file, int use_lock );
+static dse_search_set* dse_search_set_new ();
+static void dse_search_set_delete (dse_search_set *ss);
+static void dse_search_set_clean (dse_search_set *ss);
+static void dse_free_entry (void **data);
+static void dse_search_set_add_entry (dse_search_set *ss, Slapi_Entry *e);
+static Slapi_Entry* dse_search_set_get_next_entry (dse_search_set *ss);
+static int dse_add_entry_pb(struct dse* pdse, Slapi_Entry *e, Slapi_PBlock *pb);
+static struct dse_node *dse_find_node( struct dse* pdse, const Slapi_DN *dn );
+
+/*
+ richm: In almost all modes e.g. db2ldif, ldif2db, etc. we do not need/want
+ to write out the dse.ldif and ldbm.ldif files. The only mode which really
+ needs to write out the file is the regular server mode. The variable
+ dont_ever_write_dse_files tells dse_write_file_nolock whether or not to write
+ the .ldif file for the entry. The default is 1, which means never write the
+ file. The server, when it starts up in regular mode, must call
+ dse_unset_dont_ever_write_dse_files() to enable this file to be written
+*/
+static int dont_ever_write_dse_files = 1;
+
+/* Forward declarations */
+static int entry_dn_cmp( caddr_t d1, caddr_t d2 );
+static int dupentry_disallow( caddr_t d1, caddr_t d2 );
+static int dupentry_merge( caddr_t d1, caddr_t d2 );
+static int dse_write_entry( caddr_t data, caddr_t arg );
+static int ldif_record_end( char *p );
+static int dse_call_callback(struct dse* pdse, Slapi_PBlock *pb, int operation, int flags, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char* returntext);
+
+/*
+ * Map a DN onto a dse_node.
+ * Returns NULL if not found.
+ * You must have a read or write lock on the dse_rwlock while
+ * using the returned node.
+ */
+static struct dse_node *
+dse_find_node( struct dse* pdse, const Slapi_DN *dn )
+{
+ struct dse_node *n = NULL;
+ if ( NULL != dn )
+ {
+ struct dse_node searchNode;
+ Slapi_Entry *fe= slapi_entry_alloc();
+ slapi_entry_init(fe, NULL, NULL);
+ slapi_entry_set_sdn(fe,dn);
+ searchNode.entry= fe;
+
+ n = (struct dse_node *)avl_find( pdse->dse_tree, &searchNode, entry_dn_cmp );
+
+ slapi_entry_free(fe);
+ }
+ return n;
+}
+
+static int counters_created= 0;
+PR_DEFINE_COUNTER(dse_entries_exist);
+
+/*
+ * Map a DN onto a real Entry.
+ * Returns NULL if not found.
+ */
+static Slapi_Entry *
+dse_get_entry_copy( struct dse* pdse, const Slapi_DN *dn, int use_lock )
+{
+ Slapi_Entry *e= NULL;
+ struct dse_node *n;
+
+ if (use_lock == DSE_USE_LOCK)
+ PR_RWLock_Rlock(pdse->dse_rwlock);
+
+ n = dse_find_node( pdse, dn );
+ if(n!=NULL)
+ {
+ e = slapi_entry_dup(n->entry);
+ }
+
+ if (use_lock == DSE_USE_LOCK)
+ PR_RWLock_Unlock(pdse->dse_rwlock);
+
+ return e;
+}
+
+static struct dse_callback *
+dse_callback_new(int operation, int flags, const Slapi_DN *base, int scope, const char *filter, dseCallbackFn fn, void *fn_arg)
+{
+ struct dse_callback *p= NULL;
+ p = (struct dse_callback *)slapi_ch_malloc(sizeof(struct dse_callback));
+ if (p!=NULL) {
+ p->operation= operation;
+ p->flags = flags;
+ p->base= slapi_sdn_dup(base);
+ p->scope= scope;
+ if ( NULL == filter ) {
+ p->filter= NULL;
+ p->slapifilter= NULL;
+ } else {
+ p->filter= slapi_ch_strdup(filter);
+ p->slapifilter= slapi_str2filter( p->filter );
+ filter_normalize(p->slapifilter);
+ }
+ p->fn= fn;
+ p->fn_arg= fn_arg;
+ p->next= NULL;
+ }
+ return p;
+}
+
+static void
+dse_callback_delete(struct dse_callback **pp)
+{
+ if (pp!=NULL) {
+ slapi_sdn_free(&((*pp)->base));
+ slapi_ch_free((void**)&((*pp)->filter));
+ slapi_filter_free((*pp)->slapifilter,1);
+ slapi_ch_free((void**)pp);
+ }
+}
+
+static void
+dse_callback_deletelist(struct dse_callback **pp)
+{
+ if(pp!=NULL)
+ {
+ struct dse_callback *p, *n;
+ for(p= *pp;p!=NULL;)
+ {
+ n= p->next;
+ dse_callback_delete(&p);
+ p= n;
+ }
+ }
+}
+
+/*
+ Makes a copy of the entry passed in, so it's const
+*/
+static struct dse_node *
+dse_node_new(const Slapi_Entry *entry)
+{
+ struct dse_node *p= NULL;
+ p= (struct dse_node *)slapi_ch_malloc(sizeof(struct dse_node));
+ if(p!=NULL)
+ {
+ p->entry= slapi_entry_dup(entry);
+ }
+ if(!counters_created)
+ {
+ PR_CREATE_COUNTER(dse_entries_exist,"DSE","entries","");
+ counters_created= 1;
+ }
+ PR_INCREMENT_COUNTER(dse_entries_exist);
+ return p;
+}
+
+static void
+dse_node_delete(struct dse_node **pp)
+{
+ slapi_entry_free((*pp)->entry);
+ slapi_ch_free((void **)&(*pp));
+ PR_DECREMENT_COUNTER(dse_entries_exist);
+}
+
+static void
+dse_callback_addtolist(struct dse_callback **pplist, struct dse_callback *p)
+{
+ if(pplist!=NULL)
+ {
+ p->next= NULL;
+ if(*pplist==NULL)
+ {
+ *pplist= p;
+ }
+ else
+ {
+ struct dse_callback *t= *pplist;
+ for(;t->next!=NULL;t= t->next);
+ t->next= p;
+ }
+ }
+}
+
+static void
+dse_callback_removefromlist(struct dse_callback **pplist, int operation, int flags, const Slapi_DN *base, int scope, const char *filter, dseCallbackFn fn)
+{
+ if (pplist != NULL) {
+ struct dse_callback *t= *pplist;
+ struct dse_callback *prev= NULL;
+ for(; t!=NULL; ) {
+ if ((t->operation == operation) && (t->flags == flags) &&
+ (t->fn == fn) && (scope == t->scope) &&
+ (slapi_sdn_compare(base,t->base) == 0) &&
+ (( NULL == filter && NULL == t->filter ) ||
+ (strcasecmp(filter, t->filter) == 0))) {
+ if (prev == NULL) {
+ *pplist= t->next;
+ } else {
+ prev->next= t->next;
+ }
+ dse_callback_delete(&t);
+ t= NULL;
+ } else {
+ prev= t;
+ t= t->next;
+ }
+ }
+ }
+}
+
+/*
+ * Create a new dse structure.
+ */
+struct dse *
+dse_new( char *filename, char *tmpfilename, char *backfilename, char *startokfilename, const char *configdir)
+{
+ struct dse *pdse= NULL;
+ const char *config_sub_dir = "config";
+ char *id = config_get_instancedir();
+ char *realconfigdir = NULL;
+
+ if (configdir!=NULL) {
+ realconfigdir = slapi_ch_malloc(strlen(configdir)+1);
+ strcpy(realconfigdir, configdir);
+ } else if (id!=NULL) {
+ realconfigdir = slapi_ch_malloc(strlen(id)+strlen(config_sub_dir)+3);
+ sprintf(realconfigdir, "%s/%s", id, config_sub_dir);
+ }
+ if(realconfigdir!=NULL)
+ {
+ pdse= (struct dse *)slapi_ch_calloc(1, sizeof(struct dse));
+ if(pdse!=NULL)
+ {
+ pdse->dse_rwlock = PR_NewRWLock(PR_RWLOCK_RANK_NONE,"dse lock");
+ /* Set the full path name for the config DSE entry */
+ if (!strstr(filename, realconfigdir))
+ {
+ pdse->dse_filename = slapi_ch_malloc( strlen( realconfigdir ) +
+ strlen( filename ) + 3 );
+ sprintf( pdse->dse_filename, "%s/%s", realconfigdir, filename );
+ }
+ else
+ pdse->dse_filename = slapi_ch_strdup(filename);
+
+ if (!strstr(tmpfilename, realconfigdir)) {
+ pdse->dse_tmpfile = slapi_ch_malloc( strlen( realconfigdir ) +
+ strlen( tmpfilename ) + 3 );
+ sprintf( pdse->dse_tmpfile, "%s/%s", realconfigdir, tmpfilename );
+ }
+ else
+ pdse->dse_tmpfile = slapi_ch_strdup(tmpfilename);
+
+ if ( backfilename != NULL )
+ {
+ if (!strstr(backfilename, realconfigdir)) {
+ pdse->dse_fileback = slapi_ch_malloc( strlen( realconfigdir ) +
+ strlen( backfilename ) + 3 );
+ sprintf( pdse->dse_fileback, "%s/%s", realconfigdir, backfilename );
+ }
+ else
+ pdse->dse_fileback = slapi_ch_strdup(backfilename);
+ }
+ else
+ pdse->dse_fileback = NULL;
+
+ if ( startokfilename != NULL )
+ {
+ if (!strstr(startokfilename, realconfigdir)) {
+ pdse->dse_filestartOK = slapi_ch_malloc( strlen( realconfigdir ) +
+ strlen( startokfilename ) + 3 );
+ sprintf( pdse->dse_filestartOK, "%s/%s", realconfigdir, startokfilename );
+ }
+ else
+ pdse->dse_filestartOK = slapi_ch_strdup(startokfilename);
+ }
+ else
+ pdse->dse_filestartOK = NULL;
+
+ pdse->dse_tree= NULL;
+ pdse->dse_callback= NULL;
+ pdse->dse_is_updateable = dse_permission_to_write(pdse,
+ SLAPI_LOG_TRACE);
+ }
+ slapi_ch_free( (void **) &realconfigdir );
+ }
+ slapi_ch_free( (void **) &id );
+ return pdse;
+}
+
+/*
+ * Create a new dse structure with a file list
+ */
+struct dse *
+dse_new_with_filelist(char *filename, char *tmpfilename, char *backfilename, char *startokfilename, const char *configdir,
+ char **filelist)
+{
+ struct dse *newdse = dse_new(filename, tmpfilename, backfilename, startokfilename, configdir);
+ newdse->dse_filelist = filelist;
+ return newdse;
+}
+
+static int
+dse_internal_delete_entry( caddr_t data, caddr_t arg )
+{
+ struct dse_node *n = (struct dse_node *)data;
+ dse_node_delete(&n);
+ return 0;
+}
+
+/*
+ * Get rid of a dse structure.
+ */
+int
+dse_deletedse(Slapi_PBlock *pb)
+{
+ struct dse *pdse = NULL;
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_PRIVATE, &pdse);
+
+ if (pdse)
+ {
+ int nentries = 0;
+ PR_RWLock_Wlock(pdse->dse_rwlock);
+ slapi_ch_free((void **)&(pdse->dse_filename));
+ slapi_ch_free((void **)&(pdse->dse_tmpfile));
+ slapi_ch_free((void **)&(pdse->dse_fileback));
+ slapi_ch_free((void **)&(pdse->dse_filestartOK));
+ dse_callback_deletelist(&pdse->dse_callback);
+ nentries = avl_free(pdse->dse_tree, dse_internal_delete_entry);
+ PR_RWLock_Unlock(pdse->dse_rwlock);
+ PR_DestroyRWLock(pdse->dse_rwlock);
+ slapi_ch_free((void **)&pdse);
+ LDAPDebug( SLAPI_DSE_TRACELEVEL, "Removed [%d] entries from the dse tree.\n",
+ nentries,0,0 );
+ }
+
+ /* data is freed, so make sure no one tries to use it */
+ slapi_pblock_set(pb, SLAPI_PLUGIN_PRIVATE, NULL);
+
+ return 0;
+}
+
+static char* subordinatecount = "numsubordinates";
+
+/*
+ * Get the number of subordinates for this entry.
+ */
+static size_t
+dse_numsubordinates(Slapi_Entry *entry)
+{
+ int ret= 0;
+ Slapi_Attr *read_attr = NULL;
+ size_t current_sub_count = 0;
+
+ /* Get the present value of the subcount attr, or 0 if not present */
+ ret = slapi_entry_attr_find(entry,subordinatecount,&read_attr);
+ if (0 == ret)
+ {
+ /* decode the value */
+ Slapi_Value *sval;
+ slapi_attr_first_value( read_attr,&sval );
+ if (sval!=NULL)
+ {
+ const struct berval *bval = slapi_value_get_berval( sval );
+ if( NULL != bval )
+ current_sub_count = atol(bval->bv_val);
+ }
+ }
+ return current_sub_count;
+}
+
+/*
+ * Update the numsubordinates count.
+ * mod_op is either an Add or Delete.
+ */
+static void
+dse_updateNumSubordinates(Slapi_Entry *entry, int op)
+{
+ int ret= 0;
+ int mod_op = 0;
+ Slapi_Attr *read_attr = NULL;
+ size_t current_sub_count = 0;
+ int already_present = 0;
+
+ /* For now, we're only interested in subordinatecount.
+ We first examine the present value for the attribute.
+ If it isn't present and we're adding, we assign value 1 to the attribute and add it.
+ If it is present, we increment or decrement depending upon whether we're adding or deleting.
+ If the value after decrementing is zero, we remove it.
+ */
+
+ /* Get the present value of the subcount attr, or 0 if not present */
+ ret = slapi_entry_attr_find(entry,subordinatecount,&read_attr);
+ if (0 == ret)
+ {
+ /* decode the value */
+ Slapi_Value *sval;
+ slapi_attr_first_value( read_attr,&sval );
+ if (sval!=NULL)
+ {
+ const struct berval *bval = slapi_value_get_berval( sval );
+ if (bval!=NULL)
+ {
+ already_present = 1;
+ current_sub_count = atol(bval->bv_val);
+ }
+ }
+ }
+
+ /* are we adding ? */
+ if ( (SLAPI_OPERATION_ADD == op) && !already_present)
+ {
+ /* If so, and the parent entry does not already have a subcount attribute, we need to add it */
+ mod_op = LDAP_MOD_ADD;
+ }
+ else
+ {
+ if (SLAPI_OPERATION_DELETE == op)
+ {
+ if (!already_present)
+ {
+ /* This means that something is wrong---deleting a child but no subcount present on parent */
+ slapi_log_error( SLAPI_LOG_FATAL, "dse",
+ "numsubordinates assertion failure\n" );
+ return;
+ }
+ else
+ {
+ if (current_sub_count == 1)
+ {
+ mod_op = LDAP_MOD_DELETE;
+ }
+ else
+ {
+ mod_op = LDAP_MOD_REPLACE;
+ }
+ }
+ }
+ else
+ {
+ mod_op = LDAP_MOD_REPLACE;
+ }
+ }
+
+ /* Now compute the new value */
+ if (SLAPI_OPERATION_ADD == op)
+ {
+ current_sub_count++;
+ }
+ else
+ {
+ current_sub_count--;
+ }
+ {
+ char value_buffer[20]; /* enough digits for 2^64 children */
+ struct berval *vals[2];
+ struct berval val;
+ vals[0] = &val;
+ vals[1] = NULL;
+ sprintf(value_buffer,"%u",current_sub_count);
+ val.bv_val = value_buffer;
+ val.bv_len = strlen (val.bv_val);
+ switch(mod_op)
+ {
+ case LDAP_MOD_ADD:
+ attrlist_merge( &entry->e_attrs, subordinatecount, vals);
+ break;
+ case LDAP_MOD_REPLACE:
+ attrlist_replace( &entry->e_attrs, subordinatecount, vals);
+ break;
+ case LDAP_MOD_DELETE:
+ attrlist_delete( &entry->e_attrs, subordinatecount);
+ break;
+ }
+ }
+}
+
+/* the write lock should always be acquired before calling this function */
+static void
+dse_updateNumSubOfParent(struct dse *pdse, const Slapi_DN *child, int op)
+{
+ Slapi_DN parent;
+ slapi_sdn_init(&parent);
+ slapi_sdn_get_parent(child, &parent);
+ if ( !slapi_sdn_isempty(&parent) )
+ {
+ /* no lock because caller should already have the write lock */
+ Slapi_Entry *parententry= dse_get_entry_copy( pdse, &parent, DSE_NO_LOCK );
+ if( parententry!=NULL )
+ {
+ /* Decrement the numsubordinate count of the parent entry */
+ dse_updateNumSubordinates(parententry, op);
+ /* no lock because caller should always have the write lock */
+ dse_replace_entry( pdse, parententry, 0, DSE_NO_LOCK );
+ slapi_entry_free(parententry);
+ }
+ }
+ slapi_sdn_done(&parent);
+}
+
+static int
+dse_read_one_file(struct dse *pdse, const char *filename, Slapi_PBlock *pb,
+ int primary_file )
+{
+ Slapi_Entry *e= NULL;
+ char *entrystr= NULL;
+ char *buf = NULL;
+ char *lastp = NULL;
+ int rc= 0; /* Fail */
+ PRInt32 remaining;
+ PRInt32 nr = 0;
+ PRFileInfo prfinfo;
+ PRFileDesc *prfd = 0;
+
+ if ( (NULL != pdse) && (NULL != filename) )
+ {
+ if ( (rc = PR_GetFileInfo( filename, &prfinfo )) != PR_SUCCESS )
+ {
+ /* the "real" file does not exist; see if there is a tmpfile */
+ if ( pdse->dse_tmpfile &&
+ PR_GetFileInfo( pdse->dse_tmpfile, &prfinfo ) == PR_SUCCESS ) {
+ rc = PR_Rename(pdse->dse_tmpfile, filename);
+ if (rc == PR_SUCCESS) {
+ slapi_log_error(SLAPI_LOG_FATAL, "dse",
+ "The configuration file %s was restored from backup %s\n",
+ filename, pdse->dse_tmpfile);
+ rc = 1;
+ } else {
+ slapi_log_error(SLAPI_LOG_FATAL, "dse",
+ "The configuration file %s was not restored from backup %s, error %d\n",
+ filename, pdse->dse_tmpfile, rc);
+ rc = 0;
+ }
+ } else {
+ rc = 0; /* fail */
+ }
+ }
+ if ( (rc = PR_GetFileInfo( filename, &prfinfo )) != PR_SUCCESS )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "dse",
+ "The configuration file %s could not be accessed, error %d\n",
+ filename, rc);
+ rc = 0; /* Fail */
+ }
+ else if (( prfd = PR_Open( filename, PR_RDONLY, SLAPD_DEFAULT_FILE_MODE )) == NULL )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "dse",
+ "The configuration file %s could not be read. "
+ SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
+ filename,
+ PR_GetError(), slapd_pr_strerror(PR_GetError()));
+ rc = 0; /* Fail */
+ }
+ else
+ {
+ int done= 0;
+ /* read the entire file into core */
+ buf = slapi_ch_malloc( prfinfo.size + 1 );
+ remaining = prfinfo.size;
+ if (( nr = slapi_read_buffer( prfd, buf, prfinfo.size )) < 0 )
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "dse",
+ "Could only read %d of %d bytes from config file %s\n",
+ nr, prfinfo.size, filename);
+ rc = 0; /* Fail */
+ done= 1;
+ }
+
+ (void)PR_Close( prfd );
+ buf[ nr ] = '\0';
+
+ if(!done)
+ {
+ int dont_check_dups = 0;
+ int str2entry_flags = SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES |
+ SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF ;
+
+ PR_ASSERT(pb);
+ slapi_pblock_get(pb, SLAPI_DSE_DONT_CHECK_DUPS, &dont_check_dups);
+ if ( !dont_check_dups ) {
+ str2entry_flags |= SLAPI_STR2ENTRY_REMOVEDUPVALS;
+ }
+
+ /* Convert LDIF to entry structures */
+ rc= 1; /* assume we will succeed */
+ while (( entrystr = dse_read_next_entry( buf, &lastp )) != NULL )
+ {
+ e = slapi_str2entry( entrystr, str2entry_flags );
+ if ( e != NULL )
+ {
+ int returncode = 0;
+ char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= {0};
+
+ LDAPDebug(SLAPI_DSE_TRACELEVEL, "dse_read_one_file"
+ " processing entry \"%s\" in file %s%s\n",
+ slapi_entry_get_dn_const(e), filename,
+ primary_file ? " (primary file)" : "" );
+
+ /* remove the numsubordinates attr, which may be bogus */
+ slapi_entry_attr_delete(e, subordinatecount);
+
+ /* set the "primary file" flag if appropriate */
+ slapi_pblock_set( pb, SLAPI_DSE_IS_PRIMARY_FILE, &primary_file );
+ if(dse_call_callback(pdse, pb, DSE_OPERATION_READ,
+ DSE_FLAG_PREOP, e, NULL, &returncode,
+ returntext) == SLAPI_DSE_CALLBACK_OK)
+ {
+ /* this will free the entry if not added, so it is
+ definitely consumed by this call */
+ dse_add_entry_pb(pdse, e, pb);
+ }
+ else /* free entry if not used */
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "dse",
+ "The entry %s in file %s is invalid, error code %d (%s) - %s\n",
+ slapi_entry_get_dn_const(e),
+ filename, returncode,
+ ldap_err2string(returncode),
+ returntext);
+ slapi_entry_free(e);
+ rc = 0; /* failure */
+ }
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, "dse",
+ "parsing dse entry [%s]\n", entrystr );
+ rc = 0; /* failure */
+ }
+ }
+ }
+ slapi_ch_free((void **)&buf);
+ }
+ }
+
+ return rc;
+}
+
+/*
+ * Read the file we were initialised with into memory.
+ * If not NULL call entry_filter_fn on each entry as it's read.
+ * The function is free to modify the entry before it's places
+ * into the AVL tree. True means add the entry. False means don't.
+ *
+ * Return 1 for OK, 0 for Fail.
+ */
+int
+dse_read_file(struct dse *pdse, Slapi_PBlock *pb)
+{
+ int rc= 1; /* Good */
+ int ii;
+ char **filelist = 0;
+ char *filename = 0;
+
+ filelist = charray_dup(pdse->dse_filelist);
+ filename = slapi_ch_strdup(pdse->dse_filename);
+
+ for (ii = 0; rc && filelist && filelist[ii]; ++ii)
+ {
+ if (strcasecmp(filename, filelist[ii])!=0)
+ {
+ rc = dse_read_one_file(pdse, filelist[ii], pb, 0 /* not primary */);
+ }
+ }
+
+ if (rc)
+ {
+ rc = dse_read_one_file(pdse, filename, pb, 1 /* primary file */);
+ }
+
+ charray_free(filelist);
+ slapi_ch_free((void **)&filename);
+
+ return rc;
+}
+
+/*
+ * Structure to carry context information whilst
+ * traversing the tree writing the entries to disk.
+ */
+typedef struct _fpw
+{
+ PRFileDesc *fpw_prfd;
+ int fpw_rc;
+ struct dse *fpw_pdse;
+} FPWrapper;
+
+
+static int
+dse_rw_permission_to_one_file(const char *name, int loglevel)
+{
+ PRErrorCode prerr = 0;
+ const char *accesstype = "";
+
+ if ( NULL == name ) {
+ return 1; /* file won't be used -- return "sufficient permission" */
+ }
+
+ if ( PR_Access( name, PR_ACCESS_EXISTS ) == PR_SUCCESS ) {
+ /* file exists: check for read and write permission */
+ if ( PR_Access( name, PR_ACCESS_WRITE_OK ) != PR_SUCCESS ) {
+ prerr = PR_GetError();
+ accesstype = "write";
+ } else if ( PR_Access( name, PR_ACCESS_READ_OK ) != PR_SUCCESS ) {
+ prerr = PR_GetError();
+ accesstype = "read";
+ }
+ } else {
+ /* file does not exist: make sure we can create it */
+ PRFileDesc *prfd;
+
+ prfd = PR_Open( name, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE,
+ SLAPD_DEFAULT_FILE_MODE );
+ if ( NULL == prfd ) {
+ prerr = PR_GetError();
+ accesstype = "create";
+ } else {
+ PR_Close( prfd );
+ PR_Delete( name );
+ }
+ }
+
+ if ( prerr != 0 ) {
+ slapi_log_error( loglevel, "dse", "Unable to %s \"%s\": "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ accesstype, name, prerr, slapd_pr_strerror(prerr));
+ return 0; /* insufficient permission */
+ } else {
+ return 1; /* sufficient permission */
+ }
+}
+
+
+/*
+ * Check that we have permission to write to all the files that
+ * dse_write_file_nolock() uses.
+ * Returns a non-zero value if sufficient permission and 0 if not.
+ */
+static int
+dse_permission_to_write(struct dse* pdse, int loglevel)
+{
+ int rc = 1; /* sufficient permission */
+
+ if ( NULL != pdse->dse_filename ) {
+ if ( !dse_rw_permission_to_one_file( pdse->dse_filename, loglevel ) ||
+ !dse_rw_permission_to_one_file( pdse->dse_fileback, loglevel ) ||
+ !dse_rw_permission_to_one_file( pdse->dse_tmpfile, loglevel )) {
+ rc = 0; /* insufficient permission */
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * Check for read-only status and return an appropriate error to the
+ * LDAP client.
+ * Returns 0 if no error was returned and non-zero if one was.
+ */
+static int
+dse_check_for_readonly_error(Slapi_PBlock *pb, struct dse* pdse)
+{
+ int rc = 0; /* default: no error */
+
+ PR_RWLock_Rlock(pdse->dse_rwlock);
+
+ if ( !pdse->dse_is_updateable ) {
+ if ( !pdse->dse_readonly_error_reported ) {
+ if ( NULL != pdse->dse_filename ) {
+ slapi_log_error( SLAPI_LOG_FATAL, "dse",
+ "The DSE database stored in \"%s\" is not writeable\n",
+ pdse->dse_filename );
+ /* log the details too */
+ (void)dse_permission_to_write(pdse, SLAPI_LOG_FATAL);
+ }
+ pdse->dse_readonly_error_reported = 1;
+ }
+ rc = 1; /* return an error to the client */
+ }
+
+ PR_RWLock_Unlock(pdse->dse_rwlock);
+
+ if ( rc != 0 ) {
+ slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "DSE database is read-only", 0, NULL );
+ }
+
+ return rc; /* no error */
+}
+
+
+/*
+ * Write the AVL tree of entries back to the LDIF file.
+ */
+static int
+dse_write_file_nolock(struct dse* pdse)
+{
+ FPWrapper fpw;
+ int rc = 0;
+
+ if (dont_ever_write_dse_files)
+ return rc;
+
+ fpw.fpw_rc = 0;
+ fpw.fpw_prfd = NULL;
+
+ if ( NULL != pdse->dse_filename )
+ {
+ if (( fpw.fpw_prfd = PR_Open( pdse->dse_tmpfile, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, SLAPD_DEFAULT_FILE_MODE )) == NULL )
+ {
+ rc = PR_GetOSError();
+ slapi_log_error( SLAPI_LOG_FATAL, "dse", "Cannot open "
+ "temporary DSE file \"%s\" for update: OS error %d (%s)\n",
+ pdse->dse_tmpfile, rc, slapd_system_strerror( rc ));
+ }
+ else
+ {
+ fpw.fpw_pdse = pdse;
+ if ( avl_apply( pdse->dse_tree, dse_write_entry, &fpw, STOP_TRAVERSAL, AVL_INORDER ) == STOP_TRAVERSAL )
+ {
+ rc = fpw.fpw_rc;
+ slapi_log_error( SLAPI_LOG_FATAL, "dse", "Cannot write "
+ " temporary DSE file \"%s\": OS error %d (%s)\n",
+ pdse->dse_tmpfile, rc, slapd_system_strerror( rc ));
+ (void)PR_Close( fpw.fpw_prfd );
+ fpw.fpw_prfd = NULL;
+ }
+ else
+ {
+ (void)PR_Close( fpw.fpw_prfd );
+ fpw.fpw_prfd = NULL;
+ if ( pdse->dse_fileback != NULL )
+ {
+ rc = slapi_destructive_rename( pdse->dse_filename, pdse->dse_fileback );
+ if ( rc != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, "dse", "Cannot backup"
+ " DSE file \"%s\" to \"%s\": OS error %d (%s)\n",
+ pdse->dse_filename, pdse->dse_fileback,
+ rc, slapd_system_strerror( rc ));
+ }
+ }
+ rc = slapi_destructive_rename( pdse->dse_tmpfile, pdse->dse_filename );
+ if ( rc != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, "dse", "Cannot rename"
+ " temporary DSE file \"%s\" to \"%s\":"
+ " OS error %d (%s)\n",
+ pdse->dse_tmpfile, pdse->dse_filename,
+ rc, slapd_system_strerror( rc ));
+ }
+ }
+ }
+ if (fpw.fpw_prfd)
+ (void)PR_Close(fpw.fpw_prfd);
+ }
+
+ return rc;
+}
+
+/*
+ * Local function for writing an entry to a file.
+ * Called by the AVL code during traversal.
+ */
+static int
+dse_write_entry( caddr_t data, caddr_t arg )
+{
+ struct dse_node *n = (struct dse_node *)data;
+ FPWrapper *fpw = (FPWrapper *)arg;
+ char *s;
+ PRInt32 len;
+
+ if ( NULL != n && NULL != n->entry )
+ {
+ int returncode;
+ char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= "";
+ /* need to make a duplicate here for two reasons:
+ 1) we don't want to hold on to the raw data in the node for any longer
+ than we have to; we will usually be inside the dse write lock, but . . .
+ 2) the write callback may modify the entry, so we want to pass it a
+ writeable copy rather than the raw avl tree data pointer
+ */
+ Slapi_Entry *ec = slapi_entry_dup(n->entry);
+ if(dse_call_callback(fpw->fpw_pdse, NULL, DSE_OPERATION_WRITE,
+ DSE_FLAG_PREOP, ec, NULL, &returncode, returntext)
+ == SLAPI_DSE_CALLBACK_OK)
+ {
+ /*
+ * 3-August-2000 mcs: We used to pass the SLAPI_DUMP_NOOPATTRS
+ * option to slapi_entry2str_with_options() so that operational
+ * attributes were NOT stored in the DSE LDIF files. But now
+ * we store all attribute types.
+ */
+ if (( s = slapi_entry2str_with_options( ec, &len, 0 )) != NULL )
+ {
+ if ( slapi_write_buffer( fpw->fpw_prfd, s, len ) != len )
+ {
+ fpw->fpw_rc = PR_GetOSError();;
+ slapi_ch_free((void **) &s);
+ return STOP_TRAVERSAL;
+ }
+ if ( slapi_write_buffer( fpw->fpw_prfd, "\n", 1 ) != 1 )
+ {
+ fpw->fpw_rc = PR_GetOSError();;
+ slapi_ch_free((void **) &s);
+ return STOP_TRAVERSAL;
+ }
+ slapi_ch_free((void **) &s);
+ }
+ }
+ slapi_entry_free(ec);
+ }
+ return 0;
+}
+
+static int
+dse_add_entry_pb(struct dse* pdse, Slapi_Entry *e, Slapi_PBlock *pb)
+{
+ int dont_write_file = 0, merge = 0; /* defaults */
+ int rc= 0;
+ struct dse_node *n = dse_node_new(e); /* copies e */
+ Slapi_Entry *schemacheckentry= NULL; /* to use for schema checking */
+
+ PR_ASSERT(pb);
+ slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
+ slapi_pblock_get(pb, SLAPI_DSE_MERGE_WHEN_ADDING, &merge);
+
+ /* keep write lock during both tree update and file write operations */
+ PR_RWLock_Wlock(pdse->dse_rwlock);
+ if (merge)
+ {
+ rc= avl_insert( &(pdse->dse_tree), n, entry_dn_cmp, dupentry_merge );
+ }
+ else
+ {
+ rc= avl_insert( &(pdse->dse_tree), n, entry_dn_cmp, dupentry_disallow );
+ }
+ if (-1 != rc) {
+ /* update num sub of parent with no lock; we already hold the write lock */
+ if (0 == rc) { /* entry was added, not merged; update numsub */
+ dse_updateNumSubOfParent(pdse, slapi_entry_get_sdn_const(e),
+ SLAPI_OPERATION_ADD);
+ } else { /* entry was merged, free temp unused data */
+ dse_node_delete(&n);
+ }
+ if (!dont_write_file) {
+ dse_write_file_nolock(pdse);
+ }
+ } else { /* duplicate entry ignored */
+ dse_node_delete(&n); /* This also deletes the contained entry */
+ }
+ PR_RWLock_Unlock(pdse->dse_rwlock);
+
+ if (rc == -1)
+ {
+ /* duplicate entry ignored */
+ schemacheckentry = dse_get_entry_copy( pdse,
+ slapi_entry_get_sdn_const(e),
+ DSE_USE_LOCK );
+ }
+ else /* entry added or merged */
+ {
+ /* entry was added or merged */
+ if (0 == rc) /* 0 return means entry was added, not merged */
+ {
+ /* save a search of the tree, since we added the entry, the
+ contents of e should be the same as what is in the tree */
+ schemacheckentry = slapi_entry_dup(e);
+ }
+ else /* merged */
+ {
+ /* schema check the new merged entry, so get it from the tree */
+ schemacheckentry = dse_get_entry_copy( pdse,
+ slapi_entry_get_sdn_const(e),
+ DSE_USE_LOCK );
+ }
+ }
+ if ( NULL != schemacheckentry )
+ {
+ /*
+ * Verify that the new or merged entry conforms to the schema.
+ * Errors are logged by slapi_entry_schema_check().
+ */
+ (void)slapi_entry_schema_check( pb, schemacheckentry );
+ slapi_entry_free(schemacheckentry);
+ }
+
+ /* callers expect e (SLAPI_ADD_ENTRY) to be freed or otherwise consumed */
+ slapi_entry_free(e);
+
+ return rc;
+}
+
+/*
+ * Local function for comparing two entries by DN. Store the entries
+ * so that when they are printed out, the child entries are below their
+ * ancestor entries
+ */
+static int
+entry_dn_cmp( caddr_t d1, caddr_t d2 )
+{
+ struct dse_node *n1 = (struct dse_node *)d1;
+ struct dse_node *n2 = (struct dse_node *)d2;
+ const Slapi_DN *dn1 = slapi_entry_get_sdn_const(n1->entry);
+ const Slapi_DN *dn2 = slapi_entry_get_sdn_const(n2->entry);
+ int retval = slapi_sdn_compare(dn1, dn2);
+
+ if (retval != 0)
+ {
+ if (slapi_sdn_issuffix(dn1, dn2))
+ {
+ retval = 1;
+ }
+ else if (slapi_sdn_issuffix(dn2, dn1))
+ {
+ retval = -1;
+ }
+ else
+ {
+ /* put fewer rdns before more rdns */
+ int rc = 0;
+ char **dnlist1 = ldap_explode_dn(slapi_sdn_get_ndn(dn1), 0);
+ char **dnlist2 = ldap_explode_dn(slapi_sdn_get_ndn(dn2), 0);
+ int len1 = 0;
+ int len2 = 0;
+ if (dnlist1)
+ for (len1 = 0; dnlist1[len1]; ++len1);
+ if (dnlist2)
+ for (len2 = 0; dnlist2[len2]; ++len2);
+
+ if (len1 == len2)
+ {
+ len1--;
+ for (; (rc == 0) && (len1 >= 0); --len1)
+ {
+ rc = strcmp(dnlist1[len1], dnlist2[len1]);
+ }
+ if (rc)
+ retval = rc;
+ }
+ else
+ retval = len1 - len2;
+
+ if (dnlist1)
+ ldap_value_free(dnlist1);
+ if (dnlist2)
+ ldap_value_free(dnlist2);
+ }
+ }
+ /* else entries are equal if dns are equal */
+
+ return retval;
+}
+
+
+static int
+dupentry_disallow( caddr_t d1, caddr_t d2 )
+{
+ return -1;
+}
+
+
+static int
+dupentry_replace( caddr_t d1, caddr_t d2 )
+{
+ /*
+ * Hack attack: since we don't have the address of the pointer
+ * in the avl node, we have to replace the e_dn and e_attrs
+ * members of the entry which is in the AVL tree with our
+ * new entry DN and attrs. We then point the "new" entry's
+ * e_dn and e_attrs pointers to point to the values we just
+ * replaced, on the assumption that the caller will be freeing
+ * these.
+ */
+ struct dse_node *n1 = (struct dse_node *)d1; /* OLD */
+ struct dse_node *n2 = (struct dse_node *)d2; /* NEW */
+ Slapi_Entry *e= n1->entry;
+ n1->entry= n2->entry;
+ n2->entry= e;
+ return DSE_ENTRY_WAS_REPLACED;
+}
+
+static int
+dupentry_merge( caddr_t d1, caddr_t d2 )
+{
+ struct dse_node *n1 = (struct dse_node *)d1; /* OLD */
+ struct dse_node *n2 = (struct dse_node *)d2; /* NEW */
+ Slapi_Entry *e1= n1->entry;
+ Slapi_Entry *e2= n2->entry;
+ int rc = 0;
+ Slapi_Attr *newattr = 0;
+
+ for (rc = slapi_entry_first_attr(e2, &newattr);
+ !rc && newattr;
+ rc = slapi_entry_next_attr(e2, newattr, &newattr)) {
+ char *type = 0;
+ slapi_attr_get_type(newattr, &type);
+ if (type) {
+ /* insure there are no duplicate values in e1 */
+ rc = slapi_entry_merge_values_sv(e1, type,
+ attr_get_present_values(newattr));
+ }
+ }
+
+ return DSE_ENTRY_WAS_MERGED;
+}
+
+/*
+ * Add an entry to the DSE without locking the DSE avl tree.
+ * Replaces the entry if it already exists.
+ *
+ * The given entry e is never consumed. It is the responsibility of the
+ * caller to free it when it is no longer needed.
+ *
+ * The write_file flag is used if we want to update the entry in memory
+ * but we do not want to write out the file. For example, if we update
+ * the numsubordinates in the entry, this is an operational attribute that
+ * we do not want saved to disk.
+ */
+static int
+dse_replace_entry( struct dse* pdse, Slapi_Entry *e, int write_file, int use_lock )
+{
+ int rc= -1;
+ if ( NULL != e )
+ {
+ struct dse_node *n= dse_node_new(e);
+ if (use_lock)
+ PR_RWLock_Wlock(pdse->dse_rwlock);
+ rc = avl_insert( &(pdse->dse_tree), n, entry_dn_cmp, dupentry_replace );
+ if (write_file)
+ dse_write_file_nolock(pdse);
+ /* If the entry was replaced i.e. not added as a new entry, we need to
+ free the old data, which is set in dupentry_replace */
+ if (DSE_ENTRY_WAS_REPLACED == rc) {
+ dse_node_delete(&n);
+ rc = 0; /* for return to caller */
+ }
+ if (use_lock)
+ PR_RWLock_Unlock(pdse->dse_rwlock);
+ }
+ return rc;
+}
+
+
+/*
+ * Return -1 if p does not point to a valid LDIF
+ * end-of-record delimiter (a NULL, two newlines, or two
+ * pairs of CRLF). Otherwise, return the length of
+ * the delimiter found.
+ */
+static int
+ldif_record_end( char *p )
+{
+ if ( NULL != p )
+ {
+ if ( '\0' == *p )
+ {
+ return 0;
+ }
+ else if ( '\n' == *p && '\n' == *( p + 1 ))
+ {
+ return 2;
+ }
+ else if ( '\r' == *p && '\n' == *( p + 1 ) && '\r' == *( p + 2 ) && '\n' == *( p + 3 ))
+ {
+ return 4;
+ }
+ }
+ return -1;
+}
+
+char *
+dse_read_next_entry( char *buf, char **lastp )
+{
+ char *p, *start;
+
+ if ( NULL == buf )
+ {
+ *lastp = NULL;
+ return NULL;
+ }
+ p = start = ( NULL == *lastp ) ? buf : *lastp;
+ /* Skip over any leading record delimiters */
+ while ( '\n' == *p || '\r' == *p )
+ {
+ p++;
+ }
+ if ( '\0' == *p )
+ {
+ *lastp = NULL;
+ return NULL;
+ }
+ while ( '\0' != *p )
+ {
+ int rc;
+ if (( rc = ldif_record_end( p )) >= 0 )
+ {
+ /* Found end of LDIF record */
+ *p = '\0';
+ p += rc;
+ break;
+ }
+ else
+ {
+ p++;
+ }
+ }
+ *lastp = p;
+ return start;
+}
+
+/*
+ * Apply the function to each entry. The caller is responsible for locking
+ * the rwlock in the dse for the appropriate type of operation e.g. for
+ * searching, a read lock, for modifying in place, a write lock
+ */
+static int
+dse_apply_nolock(struct dse* pdse,IFP fp,caddr_t arg)
+{
+ avl_apply( pdse->dse_tree, fp, arg, STOP_TRAVERSAL, AVL_INORDER );
+ return 1;
+}
+
+
+/*
+ * Remove the entry from the tree.
+ * Returns 1 if entry is removed and 0 if not.
+ */
+static int
+dse_delete_entry(struct dse* pdse, Slapi_PBlock *pb, const Slapi_Entry *e)
+{
+ int dont_write_file = 0;
+ struct dse_node *n= dse_node_new(e);
+ struct dse_node *deleted_node = NULL;
+
+ slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
+
+ /* keep write lock for both tree deleting and file writing */
+ PR_RWLock_Wlock(pdse->dse_rwlock);
+ if (deleted_node = (struct dse_node *)avl_delete(&pdse->dse_tree,
+ n, entry_dn_cmp))
+ dse_node_delete(&deleted_node);
+ dse_node_delete(&n);
+
+ if (!dont_write_file)
+ {
+ /* Decrement the numsubordinate count of the parent entry */
+ dse_updateNumSubOfParent(pdse, slapi_entry_get_sdn_const(e),
+ SLAPI_OPERATION_DELETE);
+ dse_write_file_nolock(pdse);
+ }
+ PR_RWLock_Unlock(pdse->dse_rwlock);
+
+ return 1;
+}
+
+
+/*
+ * Returns a SLAPI_BIND_xxx retun code.
+ */
+int
+dse_bind( Slapi_PBlock *pb ) /* JCM There should only be one exit point from this function! */
+{
+ char *dn; /* The bind DN */
+ int method; /* The bind method */
+ struct berval *cred; /* The bind credentials */
+ Slapi_Value **bvals;
+ struct dse* pdse;
+ Slapi_Attr *attr;
+ Slapi_DN sdn;
+ Slapi_Entry *ec= NULL;
+
+ /*Get the parameters*/
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_TARGET, &dn ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &cred ) < 0){
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return SLAPI_BIND_FAIL;
+ }
+
+ /* always allow noauth simple binds */
+ if ( method == LDAP_AUTH_SIMPLE && cred->bv_len == 0 )
+ {
+ /*
+ * report success to client, but return
+ * SLAPI_BIND_FAIL so we don't
+ * authorize based on noauth credentials
+ */
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ return( SLAPI_BIND_FAIL );
+ }
+
+ /* Find the entry that the person is attempting to bind as */
+ slapi_sdn_init_dn_byref(&sdn,dn);
+ ec = dse_get_entry_copy(pdse,&sdn,DSE_USE_LOCK);
+ if ( ec == NULL )
+ {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return( SLAPI_BIND_FAIL );
+ }
+
+ switch ( method )
+ {
+ case LDAP_AUTH_SIMPLE:
+ {
+ Slapi_Value cv;
+ if ( slapi_entry_attr_find( ec, "userpassword", &attr ) != 0 )
+ {
+ slapi_send_ldap_result( pb, LDAP_INAPPROPRIATE_AUTH, NULL, NULL, 0, NULL );
+ slapi_entry_free(ec);
+ slapi_sdn_done(&sdn);
+ return SLAPI_BIND_FAIL;
+ }
+ bvals= attr_get_present_values( attr );
+
+ slapi_value_init_berval(&cv,cred);
+ if ( slapi_pw_find_sv( bvals, &cv ) != 0 )
+ {
+ slapi_send_ldap_result( pb, LDAP_INVALID_CREDENTIALS, NULL, NULL, 0, NULL );
+ slapi_entry_free(ec);
+ slapi_sdn_done(&sdn);
+ value_done(&cv);
+ return SLAPI_BIND_FAIL;
+ }
+ value_done(&cv);
+ }
+ break;
+
+ default:
+ slapi_send_ldap_result( pb, LDAP_STRONG_AUTH_NOT_SUPPORTED, NULL, "auth method not supported", 0, NULL );
+ slapi_entry_free(ec);
+ slapi_sdn_done(&sdn);
+ return SLAPI_BIND_FAIL;
+ }
+ slapi_entry_free(ec);
+ slapi_sdn_done(&sdn);
+ /* success: front end will send result */
+ return SLAPI_BIND_SUCCESS;
+}
+
+int
+dse_unbind( Slapi_PBlock *pb )
+{
+ return 0;
+}
+
+/*
+ * This structure is simply to pass parameters to dse_search_filter_entry.
+ */
+struct magicSearchStuff
+{
+ Slapi_PBlock *pb;
+ struct dse *pdse;
+ int scope;
+ const Slapi_DN *basedn;
+ Slapi_Filter *filter;
+ int nentries;
+ char **attrs; /*Attributes*/
+ int attrsonly; /*Should we just return the attributes found?*/
+ dse_search_set *ss; /* for the temporary results - to pass to the dse search callbacks */
+};
+
+/*
+ * The function which is called on each node of the AVL tree.
+ */
+static int
+dse_search_filter_entry(caddr_t data, caddr_t arg)
+{
+ struct dse_node *n = (struct dse_node *)data;
+ struct magicSearchStuff *p= (struct magicSearchStuff *)arg;
+ if(slapi_sdn_scope_test( slapi_entry_get_sdn_const(n->entry), p->basedn, p->scope))
+ {
+ if(slapi_vattr_filter_test( p->pb, n->entry, p->filter, 1 /* verify access */ )==0)
+ {
+ Slapi_Entry *ec = slapi_entry_dup( n->entry );
+ p->nentries++;
+ if (!p->ss)
+ {
+ p->ss = dse_search_set_new();
+ }
+ dse_search_set_add_entry(p->ss, ec); /* consumes the entry */
+ } else {
+/*
+ slapd_log_error_proc("dse_search_filter_entry",
+ "filter test failed: dn %s did not match filter %d\n",
+ slapi_entry_get_dn_const(n->entry), p->filter->f_choice);
+*/
+ }
+ } else {
+/*
+ slapd_log_error_proc("dse_search_filter_entry",
+ "scope test failed: dn %s is not in scope %d of dn [%s]\n",
+ slapi_entry_get_dn_const(n->entry), p->scope,
+ slapi_sdn_get_dn(p->basedn));
+*/
+ }
+ return 0;
+}
+
+/*
+ * The function which kicks off the traversal of the AVL tree.
+ * Returns the number of entries returned.
+ */
+/* jcm: Not very efficient if there are many DSE entries. */
+/* jcm: It applies the filter to every node in the tree regardless */
+static int
+do_dse_search(struct dse* pdse, Slapi_PBlock *pb, int scope, const Slapi_DN *basedn, Slapi_Filter *filter, char **attrs, int attrsonly)
+{
+ struct magicSearchStuff stuff;
+ stuff.pb= pb;
+ stuff.pdse= pdse;
+ stuff.scope= scope;
+ stuff.basedn= basedn;
+ stuff.filter= filter;
+ stuff.nentries= 0;
+ stuff.attrs= attrs;
+ stuff.attrsonly= attrsonly;
+ stuff.ss = NULL;
+
+ /*
+ * If this is a persistent search and the client is only interested in
+ * entries that change, we skip looking through the DSE entries.
+ */
+ if ( pb->pb_op == NULL
+ || !operation_is_flag_set( pb->pb_op, OP_FLAG_PS_CHANGESONLY )) {
+ PR_RWLock_Rlock(pdse->dse_rwlock);
+ dse_apply_nolock(pdse,dse_search_filter_entry,(caddr_t)&stuff);
+ PR_RWLock_Unlock(pdse->dse_rwlock);
+ }
+
+ if (stuff.ss) /* something was found which matched our criteria */
+ {
+ Slapi_Entry *e = NULL;
+ for (e = dse_search_set_get_next_entry(stuff.ss);
+ e;
+ e = dse_search_set_get_next_entry(stuff.ss))
+ {
+ int returncode = 0;
+ char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= "";
+
+ if(dse_call_callback(pdse, pb, SLAPI_OPERATION_SEARCH,
+ DSE_FLAG_PREOP, e, NULL, &returncode, returntext)
+ == SLAPI_DSE_CALLBACK_OK)
+ {
+ dse_search_set *ss = NULL;
+ slapi_pblock_get (pb, SLAPI_SEARCH_RESULT_SET, &ss);
+ /* if this is the first entry - allocate dse_search_set structure */
+ if (ss == NULL)
+ {
+ ss = dse_search_set_new ();
+ slapi_pblock_set (pb, SLAPI_SEARCH_RESULT_SET, ss);
+ }
+ /* make another reference to e (stuff.ss references it too)
+ the stuff.ss reference is removed by dse_search_set_clean()
+ below, leaving ss as the sole owner of the memory */
+ dse_search_set_add_entry(ss, e);
+ } else {
+ stuff.nentries--; /* rejected entry */
+ /* this leaves a freed pointer in stuff.ss, but that's ok because
+ it should never be referenced, and the reference is removed by
+ the call to dse_search_set_clean() below */
+ slapi_entry_free(e);
+ }
+ }
+ dse_search_set_clean(stuff.ss);
+ }
+
+ /* the pblock ss now contains the "real" search result set and the copies of
+ the entries allocated in dse_search_filter_entry; any entries rejected by
+ the search callback were freed above by the call to slapi_entry_free() */
+ return stuff.nentries;
+}
+
+/*
+ * -1 means something went wrong.
+ * 0 means everything went ok.
+ */
+int
+dse_search(Slapi_PBlock *pb) /* JCM There should only be one exit point from this function! */
+{
+ char *base; /*Base of the search*/
+ int scope; /*Scope of the search*/
+ Slapi_Filter *filter; /*The filter*/
+ char **attrs; /*Attributes*/
+ int attrsonly; /*Should we just return the attributes found?*/
+ /*int nentries= 0; Number of entries found thus far*/
+ struct dse* pdse;
+ int returncode= LDAP_SUCCESS;
+ int isrootdse= 0;
+ char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= "";
+ Slapi_DN basesdn;
+
+ /*
+ * Get private information created in the init routine.
+ * Also get the parameters of the search operation. These come
+ * more or less directly from the client.
+ */
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &base ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly ) <0)
+ {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return(-1);
+ }
+
+ slapi_sdn_init_dn_byref(&basesdn,base);
+
+ /*
+ * Sadly the root dse is still a special case. We must not allow
+ * acl checks on it, or allow onelevel or subtree searches on it.
+ */
+ isrootdse= slapi_sdn_isempty(&basesdn);
+
+ switch(scope)
+ {
+ case LDAP_SCOPE_BASE:
+ {
+ Slapi_Entry *baseentry= NULL;
+ baseentry = dse_get_entry_copy(pdse,&basesdn,DSE_USE_LOCK);
+ if ( baseentry == NULL )
+ {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ slapi_log_error(SLAPI_LOG_PLUGIN,"dse_search", "node %s was not found\n",
+ slapi_sdn_get_dn(&basesdn));
+ slapi_sdn_done(&basesdn);
+ return -1;
+ }
+ /*
+ * We don't want to do an acl check for the root dse... because the acl
+ * code thinks it's a suffix of every target... so every acl applies to
+ * the root dse... which is wrong.
+ */
+ if(slapi_vattr_filter_test( pb, baseentry, filter, !isrootdse /* verify access */ )==0)
+ {
+ /* Callbacks modify a copy of the entry */
+ if(dse_call_callback(pdse, pb, SLAPI_OPERATION_SEARCH,
+ DSE_FLAG_PREOP, baseentry, NULL, &returncode, returntext)
+ == SLAPI_DSE_CALLBACK_OK)
+ {
+ dse_search_set *ss;
+ ss = dse_search_set_new ();
+ slapi_pblock_set (pb, SLAPI_SEARCH_RESULT_SET, ss);
+ dse_search_set_add_entry (ss, baseentry); /* consumes the entry */
+ baseentry= NULL;
+ }
+ }
+ slapi_entry_free(baseentry);
+ }
+ break;
+ case LDAP_SCOPE_ONELEVEL:
+ /* FALL THROUGH */
+ case LDAP_SCOPE_SUBTREE:
+ if(!isrootdse)
+ {
+ do_dse_search(pdse, pb, scope, &basesdn, filter, attrs, attrsonly);
+ }
+ break;
+ }
+
+ /* Search is done, send LDAP_SUCCESS */
+ slapi_sdn_done(&basesdn);
+ return 0;
+}
+
+
+/*
+ * -1 means something went wrong.
+ * 0 means everything went ok.
+ */
+
+static int
+dse_modify_return( int rv, Slapi_Entry *ec, Slapi_Entry *ecc )
+{
+ slapi_entry_free(ec);
+ slapi_entry_free(ecc);
+ return rv;
+}
+
+int
+dse_modify(Slapi_PBlock *pb) /* JCM There should only be one exit point from this function! */
+{
+ int err; /*House keeping stuff*/
+ LDAPMod **mods; /*Used to apply the modifications*/
+ char *dn; /*Storage for the dn*/
+ char *errbuf = NULL; /* To get error back */
+ struct dse* pdse;
+ Slapi_Entry *ec= NULL;
+ Slapi_Entry *ecc= NULL;
+ int returncode= LDAP_SUCCESS;
+ char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= "";
+ Slapi_DN sdn;
+ int dont_write_file = 0; /* default */
+
+ PR_ASSERT(pb);
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_MODIFY_TARGET, &dn ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ) < 0 || (NULL == pdse))
+ {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return( -1 );
+ }
+
+ slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
+ if ( !dont_write_file && dse_check_for_readonly_error(pb,pdse)) {
+ return( -1 );
+ }
+
+ slapi_sdn_init_dn_byref(&sdn,dn);
+
+ /* Find the entry we are about to modify. */
+ ec = dse_get_entry_copy(pdse,&sdn,DSE_USE_LOCK);
+ if ( ec == NULL )
+ {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_modify_return( -1, ec, ecc );
+ }
+
+ /* Check acl */
+ err = plugin_call_acl_mods_access ( pb, ec, mods, &errbuf );
+ if ( err != LDAP_SUCCESS )
+ {
+ slapi_send_ldap_result( pb, err, NULL, errbuf, 0, NULL );
+ if (errbuf) slapi_ch_free ((void**)&errbuf);
+ slapi_sdn_done(&sdn);
+ return dse_modify_return( -1, ec, ecc );
+ }
+
+ /* Save away a copy of the entry, before modifications */
+ slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( ec )); /* JCM - When does this get free'd? */
+ /* richm - it is freed in modify.c */
+
+ /* Modify a copy of the entry*/
+ ecc = slapi_entry_dup( ec );
+ err = entry_apply_mods( ecc, mods );
+
+ /* XXXmcs: should we expand objectclass values here?? */
+
+ switch(dse_call_callback(pdse, pb, SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, ec, ecc, &returncode, returntext))
+ {
+ case SLAPI_DSE_CALLBACK_ERROR:
+ {
+ /* Error occured in the callback -- return error code from callback */
+ slapi_send_ldap_result( pb, returncode, NULL, returntext, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_modify_return( -1, ec, ecc );
+ }
+
+ case SLAPI_DSE_CALLBACK_DO_NOT_APPLY:
+ {
+ /* Callback says don't apply the changes -- return Success */
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_modify_return( 0, ec, ecc );
+ }
+
+ case SLAPI_DSE_CALLBACK_OK:
+ {
+ /* The callback may alter the mods in the pblock. This happens
+ for example in the schema code. Since the schema attributes
+ are managed exclusively by the schema code, we should not
+ apply those mods. However, for reasons unknown to me, we
+ must in the general case call entry_apply_mods before calling
+ the modify callback above. In the case of schema, the schema
+ code will remove the schema attributes from the mods. So, we
+ reapply the mods to the entry for the attributes we manage in
+ the dse code (e.g. aci)
+ */
+ int reapply_mods = 0; /* default is to not reapply entry_apply_mods */
+ slapi_pblock_get(pb, SLAPI_DSE_REAPPLY_MODS, &reapply_mods);
+ /* Callback says apply the changes */
+ if ( reapply_mods )
+ {
+ LDAPMod **modsagain = NULL; /*Used to apply the modifications*/
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &modsagain );
+ if (NULL != modsagain)
+ {
+ /* the dse modify callback must have modified ecc back to it's
+ original state, before the earlier apply_mods, but without the
+ attributes it did not want us to apply mods to */
+ err = entry_apply_mods( ecc, modsagain );
+ }
+ }
+
+ if (err != 0)
+ {
+ /* entry_apply_mods() failed above, so return an error now */
+ slapi_send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_modify_return( -1, ec, ecc );
+ }
+ break;
+ }
+ }
+
+ /* We're applying the mods... check that the entry still obeys the schema */
+ if ( slapi_entry_schema_check( pb, ecc ) != 0 )
+ {
+ char *errtext;
+
+ slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext);
+ slapi_send_ldap_result( pb, LDAP_OBJECT_CLASS_VIOLATION, NULL, errtext, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_modify_return( -1, ec, ecc );
+ }
+
+ /* Change the entry itself both on disk and in the AVL tree */
+ /* dse_replace_entry free's the existing entry. */
+ if (dse_replace_entry( pdse, ecc, !dont_write_file, DSE_USE_LOCK )!=0 )
+ {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_modify_return( -1, ec, ecc );
+ }
+ slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, slapi_entry_dup(ecc) ); /* JCM - When does this get free'd? */
+ /* richm - it is freed in modify.c */
+ dse_call_callback(pdse, pb, SLAPI_OPERATION_MODIFY, DSE_FLAG_POSTOP, ec, ecc, &returncode, returntext);
+
+ slapi_send_ldap_result( pb, returncode, NULL, returntext, 0, NULL );
+
+ slapi_sdn_done(&sdn);
+ return dse_modify_return(0, ec, ecc);
+}
+
+static int
+dse_add_return( int rv, Slapi_Entry *e)
+{
+ slapi_entry_free(e);
+ return rv;
+}
+
+/*
+ * -1 means something went wrong.
+ * 0 means everything went ok.
+ */
+int
+dse_add(Slapi_PBlock *pb) /* JCM There should only be one exit point from this function! */
+{
+ char *dn = NULL;
+ Slapi_Entry *e; /*The new entry to add*/
+ Slapi_Entry *e_copy = NULL; /* copy of added entry */
+ char *errbuf = NULL;
+ int rc = LDAP_SUCCESS;
+ int error = -1;
+ int dont_write_file = 0; /* default */
+ struct dse* pdse;
+ int returncode= LDAP_SUCCESS;
+ char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= "";
+ Slapi_DN sdn;
+ Slapi_DN parent;
+
+ /*
+ * Get the database, the dn and the entry to add
+ */
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_ADD_TARGET, &dn ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e ) < 0 || (NULL == pdse))
+ {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return error;
+ }
+
+ slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
+ if ( !dont_write_file && dse_check_for_readonly_error(pb,pdse)) {
+ return( error );
+ }
+
+ slapi_sdn_init_dn_byref(&sdn,dn);
+
+ /*
+ * Check to make sure the entry passes the schema check
+ */
+ if ( slapi_entry_schema_check( pb, e ) != 0 )
+ {
+ char *errtext;
+ LDAPDebug( SLAPI_DSE_TRACELEVEL,
+ "dse_add: entry failed schema check\n", 0, 0, 0 );
+ slapi_pblock_get(pb, SLAPI_PB_RESULT_TEXT, &errtext);
+ slapi_send_ldap_result( pb, LDAP_OBJECT_CLASS_VIOLATION, NULL, errtext, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return error;
+ }
+
+ /*
+ * Attempt to find this dn.
+ */
+ {
+ Slapi_Entry *existingentry= dse_get_entry_copy( pdse, &sdn, DSE_USE_LOCK );
+ if(existingentry!=NULL)
+ {
+ /*
+ * If we've reached this code, there is an entry
+ * whose dn matches dn, so tell the user and return
+ */
+ slapi_send_ldap_result( pb, LDAP_ALREADY_EXISTS, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ slapi_entry_free(existingentry);
+ return dse_add_return(error, NULL);
+ }
+ }
+
+ /*
+ * Get the parent dn and see if the corresponding entry exists.
+ * If the parent does not exist, only allow the "root" user to
+ * add the entry.
+ */
+ slapi_sdn_init(&parent);
+ slapi_sdn_get_parent(&sdn,&parent);
+ if ( !slapi_sdn_isempty(&parent) )
+ {
+ Slapi_Entry *parententry= NULL;
+ parententry= dse_get_entry_copy( pdse, &parent, DSE_USE_LOCK );
+ if( parententry==NULL )
+ {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ LDAPDebug( SLAPI_DSE_TRACELEVEL, "dse_add: parent does not exist\n", 0, 0, 0 );
+ slapi_sdn_done(&sdn);
+ slapi_sdn_done(&parent);
+ return dse_add_return(error, NULL);
+ }
+ rc= plugin_call_acl_plugin ( pb, parententry, NULL, NULL, SLAPI_ACL_ADD, ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
+ slapi_entry_free(parententry);
+ if ( rc!=LDAP_SUCCESS )
+ {
+ LDAPDebug( SLAPI_DSE_TRACELEVEL, "dse_add: no access to parent\n", 0, 0, 0 );
+ slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL );
+ slapi_ch_free((void**)&errbuf);
+ slapi_sdn_done(&sdn);
+ slapi_sdn_done(&parent);
+ return dse_add_return(rc, NULL);
+ }
+ }
+ else
+ {
+ /* no parent */
+ int isroot;
+ slapi_pblock_get( pb, SLAPI_REQUESTOR_ISROOT, &isroot );
+ if ( !isroot )
+ {
+ LDAPDebug( SLAPI_DSE_TRACELEVEL, "dse_add: no parent and not root\n", 0, 0, 0 );
+ slapi_send_ldap_result( pb, LDAP_INSUFFICIENT_ACCESS, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ slapi_sdn_done(&parent);
+ return dse_add_return(error, NULL);
+ }
+ }
+ slapi_sdn_done(&parent);
+
+ /*
+ * Before we add the entry, find out if the syntax of the aci
+ * aci attribute values are correct or not. We don't want to add
+ * the entry if the syntax is incorrect.
+ */
+ if ( plugin_call_acl_verify_syntax (pb, e, &errbuf) != 0 )
+ {
+ slapi_send_ldap_result( pb, LDAP_INVALID_SYNTAX, NULL, errbuf, 0, NULL );
+ slapi_ch_free((void**)&errbuf);
+ return dse_add_return(error, NULL);
+ }
+
+ if(dse_call_callback(pdse, pb, SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, e,
+ NULL, &returncode, returntext)!=SLAPI_DSE_CALLBACK_OK)
+ {
+ slapi_send_ldap_result( pb, returncode, NULL, returntext, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_add_return(error, NULL);
+ }
+
+ /* make copy for postop fns because add_entry_pb consumes e */
+ e_copy = slapi_entry_dup(e);
+ if ( dse_add_entry_pb(pdse, e, pb) != 0)
+ {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_add_return(error, e_copy);
+ }
+
+ /* e has been consumed, so use the copy for the post ops */
+ slapi_pblock_set(pb, SLAPI_ADD_ENTRY, e_copy);
+
+ /* The postop must be called after the write lock is released. */
+ dse_call_callback(pdse, pb, SLAPI_OPERATION_ADD, DSE_FLAG_POSTOP, e_copy, NULL, &returncode, returntext);
+
+ /* We have been successful. Tell the user */
+ slapi_send_ldap_result( pb, returncode, NULL, NULL, 0, NULL );
+
+ slapi_pblock_set( pb, SLAPI_ENTRY_POST_OP, slapi_entry_dup( e_copy ));
+
+ /* entry has been freed, so make sure no one tries to use it later */
+ slapi_pblock_set(pb, SLAPI_ADD_ENTRY, NULL);
+
+ /* Free the dn, and return */
+ slapi_sdn_done(&sdn);
+
+ return dse_add_return(rc, e_copy);
+}
+
+/*
+ * -1 means something went wrong.
+ * 0 means everything went ok.
+ */
+
+static int
+dse_delete_return( int rv, Slapi_Entry *ec)
+{
+ slapi_entry_free(ec);
+ return rv;
+}
+
+int
+dse_delete(Slapi_PBlock *pb) /* JCM There should only be one exit point from this function! */
+{
+ char *dn = NULL;
+ int rc= -1;
+ int dont_write_file = 0; /* default */
+ struct dse* pdse = NULL;
+ int returncode= LDAP_SUCCESS;
+ char returntext[SLAPI_DSE_RETURNTEXT_SIZE]= "";
+ char *entry_str = "entry";
+ char *errbuf = NULL;
+ char *attrs[2] = { NULL, NULL };
+ Slapi_DN sdn;
+ Slapi_Entry *ec = NULL; /* copy of entry to delete */
+
+ /*
+ * Get the database and the dn
+ */
+ if (slapi_pblock_get( pb, SLAPI_PLUGIN_PRIVATE, &pdse ) < 0 ||
+ slapi_pblock_get( pb, SLAPI_DELETE_TARGET, &dn ) < 0 || (pdse == NULL))
+ {
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL );
+ return rc;
+ }
+
+ slapi_pblock_get(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
+ if ( !dont_write_file && dse_check_for_readonly_error(pb,pdse)) {
+ return( rc );
+ }
+
+ slapi_sdn_init_dn_byref(&sdn,dn);
+
+ ec= dse_get_entry_copy( pdse, &sdn, DSE_USE_LOCK );
+ if (ec == NULL)
+ {
+ slapi_send_ldap_result( pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_delete_return( rc, ec );
+ }
+
+ /*
+ * Check if this node has any children.
+ */
+ if(dse_numsubordinates(ec)>0)
+ {
+ slapi_send_ldap_result( pb, LDAP_NOT_ALLOWED_ON_NONLEAF, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_delete_return( rc, ec );
+ }
+
+ /*
+ * Check the access
+ */
+ attrs[0] = entry_str;
+ attrs[1] = NULL;
+ returncode= plugin_call_acl_plugin ( pb, ec, attrs, NULL, SLAPI_ACL_DELETE, ACLPLUGIN_ACCESS_DEFAULT, &errbuf );
+ if ( returncode!=LDAP_SUCCESS)
+ {
+ slapi_send_ldap_result( pb, returncode, NULL, NULL, 0, NULL );
+ slapi_ch_free ( (void**)&errbuf );
+ slapi_sdn_done(&sdn);
+ return dse_delete_return( rc, ec );
+ }
+
+ if(dse_call_callback(pdse, pb, SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, ec, NULL, &returncode,returntext)==SLAPI_DSE_CALLBACK_OK)
+ {
+ if(dse_delete_entry(pdse, pb, ec)==0)
+ {
+ returncode= LDAP_OPERATIONS_ERROR;
+ }
+ }
+ else
+ {
+ slapi_send_ldap_result( pb, returncode, NULL, NULL, 0, NULL );
+ slapi_sdn_done(&sdn);
+ return dse_delete_return( rc, ec );
+ }
+
+ dse_call_callback(pdse, pb, SLAPI_OPERATION_DELETE, DSE_FLAG_POSTOP, ec, NULL, &returncode, returntext);
+
+ slapi_send_ldap_result( pb, returncode, NULL, returntext, 0, NULL );
+ slapi_pblock_set( pb, SLAPI_ENTRY_PRE_OP, slapi_entry_dup( ec ));
+ slapi_sdn_done(&sdn);
+ return dse_delete_return(0, ec);
+}
+
+struct dse_callback *
+dse_register_callback(struct dse* pdse, int operation, int flags, const Slapi_DN *base, int scope, const char *filter, dseCallbackFn fn, void *fn_arg)
+{
+ struct dse_callback *callback = dse_callback_new(operation, flags, base, scope, filter, fn, fn_arg);
+ dse_callback_addtolist(&pdse->dse_callback, callback);
+ return callback;
+}
+
+void
+dse_remove_callback(struct dse* pdse, int operation, int flags, const Slapi_DN *base, int scope, const char *filter, dseCallbackFn fn)
+{
+ dse_callback_removefromlist(&pdse->dse_callback, operation, flags, base, scope, filter, fn);
+}
+
+/*
+ * Return values:
+ * SLAPI_DSE_CALLBACK_ERROR -- Callback failed.
+ * SLAPI_DSE_CALLBACK_OK -- OK, do it.
+ * SLAPI_DSE_CALLBACK_DO_NOT_APPLY -- No error, but don't apply changes.
+ */
+static int
+dse_call_callback(struct dse* pdse, Slapi_PBlock *pb, int operation, int flags, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char *returntext)
+{
+ /* ONREPL callbacks can potentially modify pblock parameters like backend
+ * which would cause problems during request processing. We need to save
+ * "important" fields before calls and restoring them afterwards */
+ int r = SLAPI_DSE_CALLBACK_OK;
+ if (pdse->dse_callback != NULL) {
+ struct dse_callback *p;
+ p=pdse->dse_callback;
+ while (p!=NULL) {
+ struct dse_callback *p_next = p->next;
+ if ((p->operation & operation) && (p->flags & flags)) {
+ if(slapi_sdn_scope_test(slapi_entry_get_sdn_const(entryBefore), p->base, p->scope))
+ {
+ if(NULL == p->slapifilter ||
+ slapi_vattr_filter_test(pb, entryBefore, p->slapifilter,
+ 0 /* !verify access */ )==0)
+ {
+ int result= (*p->fn)(pb, entryBefore,entryAfter,returncode,returntext,p->fn_arg);
+ if(result<r)
+ {
+ r= result;
+ }
+ }
+ }
+ }
+ p = p_next;
+ }
+ }
+ return r;
+}
+
+int
+slapi_config_register_callback(int operation, int flags, const char *base, int scope, const char *filter, dseCallbackFn fn, void *fn_arg)
+{
+ int rc= 0;
+ Slapi_Backend *be= slapi_be_select_by_instance_name(DSE_BACKEND);
+ if (be != NULL) {
+ struct dse* pdse= (struct dse*)be->be_database->plg_private;
+ if (pdse!=NULL) {
+ Slapi_DN dn;
+ slapi_sdn_init_dn_byref(&dn,base);
+ rc = (NULL != dse_register_callback(pdse, operation, flags, &dn, scope, filter, fn, fn_arg));
+ slapi_sdn_done(&dn);
+ }
+ }
+ return rc;
+}
+
+int
+slapi_config_remove_callback(int operation, int flags, const char *base, int scope, const char *filter, dseCallbackFn fn)
+{
+ int rc= 0;
+ Slapi_Backend *be= slapi_be_select_by_instance_name(DSE_BACKEND);
+ if(be != NULL) {
+ struct dse* pdse = (struct dse*)be->be_database->plg_private;
+ if (pdse != NULL) {
+ Slapi_DN dn;
+ slapi_sdn_init_dn_byref(&dn,base);
+ dse_remove_callback(pdse, operation, flags, &dn, scope, filter, fn);
+ slapi_sdn_done(&dn);
+ rc= 1;
+ }
+ }
+ return rc;
+}
+
+void
+dse_set_dont_ever_write_dse_files()
+{
+ dont_ever_write_dse_files = 1;
+}
+
+void
+dse_unset_dont_ever_write_dse_files()
+{
+ dont_ever_write_dse_files = 0;
+}
+
+static dse_search_set*
+dse_search_set_new ()
+{
+ dse_search_set *ss;
+
+ ss = (dse_search_set *)slapi_ch_malloc (sizeof (*ss));
+
+ if (ss)
+ {
+ dl_init (&ss->dl, 0);
+ ss->current_entry = -1;
+ }
+
+ return ss;
+}
+
+/* This is similar to delete, but it does not free the entries contained in the
+ search set. This is useful in do_dse_search when we copy the entries from
+ 1 search set to the other. */
+static void
+dse_search_set_clean(dse_search_set *ss)
+{
+ if (ss)
+ {
+ dl_cleanup(&ss->dl, NULL);
+ slapi_ch_free((void **)&ss);
+ }
+}
+
+static void
+dse_search_set_delete (dse_search_set *ss)
+{
+ if (ss)
+ {
+ dl_cleanup (&ss->dl, dse_free_entry);
+ slapi_ch_free ((void**)&ss);
+ }
+}
+
+static void
+dse_free_entry (void **data)
+{
+ Slapi_Entry **e;
+
+ if (data)
+ {
+ e = (Slapi_Entry **)data;
+ if (*e)
+ slapi_entry_free (*e);
+ }
+}
+
+static void
+dse_search_set_add_entry (dse_search_set *ss, Slapi_Entry *e)
+{
+ PR_ASSERT (ss && e);
+
+ dl_add (&ss->dl, e);
+}
+
+static Slapi_Entry*
+dse_search_set_get_next_entry (dse_search_set *ss)
+{
+ PR_ASSERT (ss);
+
+ if (ss->current_entry == -1)
+ return (dl_get_first (&ss->dl, &ss->current_entry));
+ else
+ return (dl_get_next (&ss->dl, &ss->current_entry));
+}
+
+int
+dse_next_search_entry (Slapi_PBlock *pb)
+{
+ dse_search_set *ss;
+ Slapi_Entry *e;
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_SET, &ss);
+
+ /* no entries to return */
+ if (ss == NULL)
+ {
+ slapi_pblock_set (pb, SLAPI_SEARCH_RESULT_ENTRY, NULL);
+ return 0;
+ }
+
+ e = dse_search_set_get_next_entry (ss);
+ slapi_pblock_set (pb, SLAPI_SEARCH_RESULT_ENTRY, e);
+
+ /* we reached the end of the list */
+ if (e == NULL)
+ {
+ dse_search_set_delete (ss);
+ slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, NULL);
+ }
+
+ return 0;
+}
diff --git a/ldap/servers/slapd/dynalib.c b/ldap/servers/slapd/dynalib.c
new file mode 100644
index 00000000..4839a17b
--- /dev/null
+++ b/ldap/servers/slapd/dynalib.c
@@ -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 **/
+/* dynalib.c - dynamic library routines */
+
+#include <stdio.h>
+#include "prlink.h"
+#include "slap.h"
+#if defined(SOLARIS)
+#include <dlfcn.h> /* dlerror */
+#endif
+
+
+static struct dynalib {
+ char *dl_name;
+ PRLibrary *dl_handle;
+} **libs = NULL;
+
+static void symload_report_error( char *libpath, char *symbol, char *plugin,
+ int libopen );
+
+void *
+sym_load( char *libpath, char *symbol, char *plugin, int report_errors )
+{
+ int i;
+ void *handle;
+
+ for ( i = 0; libs != NULL && libs[i] != NULL; i++ ) {
+ if ( strcasecmp( libs[i]->dl_name, libpath ) == 0 ) {
+ handle = PR_FindSymbol( libs[i]->dl_handle, symbol );
+ if ( NULL == handle && report_errors ) {
+ symload_report_error( libpath, symbol, plugin, 1 /* lib open */ );
+ }
+ return handle;
+ }
+ }
+
+ if ( (handle = PR_LoadLibrary( libpath )) == NULL ) {
+ if ( report_errors ) {
+ symload_report_error( libpath, symbol, plugin, 0 /* lib not open */ );
+ }
+ return( NULL );
+ }
+
+ libs = (struct dynalib **) slapi_ch_realloc( (char *) libs, (i + 2) *
+ sizeof(struct dynalib) );
+ libs[i] = (struct dynalib *) slapi_ch_malloc( sizeof(struct dynalib) );
+ libs[i]->dl_name = slapi_ch_strdup( libpath );
+ libs[i]->dl_handle = handle;
+ libs[ i + 1 ] = NULL;
+
+ handle = PR_FindSymbol( libs[i]->dl_handle, symbol );
+ if ( NULL == handle && report_errors ) {
+ symload_report_error( libpath, symbol, plugin, 1 /* lib open */ );
+ }
+ return handle;
+}
+
+
+static void
+symload_report_error( char *libpath, char *symbol, char *plugin, int libopen )
+{
+ char *errtext = NULL;
+ PRInt32 errlen, err;
+
+ errlen = PR_GetErrorTextLength();
+ if ( errlen > 0 ) {
+ errtext = slapi_ch_malloc( errlen );
+ if (( err = PR_GetErrorText( errtext )) > 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, SLAPI_COMPONENT_NAME_NSPR " error %d: %s\n",
+ PR_GetError(), errtext, 0 );
+ }
+ slapi_ch_free( (void **)&errtext );
+ }
+ if ( libopen ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Could not load symbol \"%s\" from \"%s\" for plugin %s\n",
+ symbol, libpath, plugin );
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Could not open library \"%s\" for plugin %s\n",
+ libpath, plugin, 0 );
+ }
+}
diff --git a/ldap/servers/slapd/entry.c b/ldap/servers/slapd/entry.c
new file mode 100644
index 00000000..0d315053
--- /dev/null
+++ b/ldap/servers/slapd/entry.c
@@ -0,0 +1,3124 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* entry.c - routines for dealing with entries */
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#undef DEBUG /* disable counters */
+#include <prcountr.h>
+#include "slap.h"
+
+
+#undef ENTRY_DEBUG
+
+#define DELETED_ATTR_STRING ";deletedattribute"
+#define DELETED_ATTR_STRSIZE 17 /* sizeof(";deletedattribute") */
+#define DELETED_VALUE_STRING ";deleted"
+#define DELETED_VALUE_STRSIZE 8 /* sizeof(";deleted") */
+
+/*
+ * An attribute name is of the form 'basename[;option]'.
+ * The state informaion is encoded in options. For example:
+ *
+ * telephonenumber;vucsn-011111111222233334444: 1 650 937 5739
+ *
+ * This function strips out the csn options, leaving behind a
+ * type with any non-csn options left intact.
+ */
+/*
+ * WARNING: s gets butchered... the base type remains.
+ */
+void
+str2entry_state_information_from_type(char *s,CSNSet **csnset,CSN **attributedeletioncsn,CSN **maxcsn,int *value_state,int *attr_state)
+{
+ char *p= strchr(s, ';');
+ *value_state= VALUE_PRESENT;
+ *attr_state= ATTRIBUTE_PRESENT;
+ while(p!=NULL)
+ {
+ if(p[3]=='c' && p[4]=='s' && p[5]=='n' && p[6]=='-')
+ {
+ CSNType t= CSN_TYPE_UNKNOWN;
+ if(p[1]=='x' && p[2]=='1')
+ {
+ t= CSN_TYPE_UNKNOWN;
+ }
+ if(p[1]=='x' && p[2]=='2')
+ {
+ t= CSN_TYPE_NONE;
+ }
+ if(p[1]=='a' && p[2]=='d')
+ {
+ t= CSN_TYPE_ATTRIBUTE_DELETED;
+ }
+ if(p[1]=='v' && p[2]=='u')
+ {
+ t= CSN_TYPE_VALUE_UPDATED;
+ }
+ if(p[1]=='v' && p[2]=='d')
+ {
+ t= CSN_TYPE_VALUE_DELETED;
+ }
+ if(p[1]=='m' && p[2]=='d')
+ {
+ t= CSN_TYPE_VALUE_DISTINGUISHED;
+ }
+ p[0]='\0';
+ if(t!=CSN_TYPE_ATTRIBUTE_DELETED)
+ {
+ CSN csn;
+ csn_init_by_string(&csn,p+7);
+ csnset_add_csn(csnset,t,&csn);
+ if ( *maxcsn == NULL )
+ {
+ *maxcsn = csn_dup ( &csn );
+ }
+ else if ( csn_compare (*maxcsn, &csn) < 0 )
+ {
+ csn_init_by_csn ( *maxcsn, &csn );
+ }
+ }
+ else
+ {
+ *attributedeletioncsn= csn_new_by_string(p+7);
+ if ( *maxcsn == NULL )
+ {
+ *maxcsn = csn_dup ( *attributedeletioncsn );
+ }
+ else if ( csn_compare (*maxcsn, *attributedeletioncsn) < 0 )
+ {
+ csn_init_by_csn ( *maxcsn, *attributedeletioncsn );
+ }
+ }
+ }
+ else if(strncmp(p+1,"deletedattribute", 16)==0)
+ {
+ p[0]='\0';
+ *attr_state= ATTRIBUTE_DELETED;
+ }
+ else if(strncmp(p+1,"deleted", 7)==0)
+ {
+ p[0]='\0';
+ *value_state= VALUE_DELETED;
+ }
+ p= strchr(p+1, ';');
+ }
+}
+
+
+static Slapi_Entry *
+str2entry_fast( char *s, int flags, int read_stateinfo )
+{
+ Slapi_Entry *e;
+ char *next, *ptype=NULL;
+ int nvals= 0;
+ int del_nvals= 0;
+ int retmalloc = 0;
+ unsigned long attr_val_cnt = 0;
+ CSN *attributedeletioncsn= NULL; /* Moved to this level so that the JCM csn_free call below gets useful */
+ CSNSet *valuecsnset= NULL; /* Moved to this level so that the JCM csn_free call below gets useful */
+ CSN *maxcsn = NULL;
+
+ /*
+ * In string format, an entry looks like this:
+ *
+ * dn: <dn>\n
+ * [<attr>:[:] <value>\n]
+ * [<tab><continuedvalue>\n]*
+ * ...
+ *
+ * If a double colon is used after a type, it means the
+ * following value is encoded as a base 64 string. This
+ * happens if the value contains a non-printing character
+ * or newline.
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> str2entry_fast\n", 0, 0, 0 );
+
+ e = slapi_entry_alloc();
+ slapi_entry_init(e,NULL,NULL);
+
+ /* dn + attributes */
+ next = s;
+
+ /* get the read lock of name2asi for performance purpose.
+ It reduces read locking by per-entry lock, instead of per-attribute.
+ */
+ attr_syntax_read_lock();
+
+ while ( (s = ldif_getline( &next )) != NULL &&
+ attr_val_cnt < ENTRY_MAX_ATTRIBUTE_VALUE_COUNT )
+ {
+ Slapi_Attr **a;
+ char *valuecharptr=NULL;
+ int valuelen;
+ CSNType attributecsntype;
+ int value_state= VALUE_NOTFOUND;
+ int attr_state= ATTRIBUTE_NOTFOUND;
+ int maxvals;
+ int del_maxvals;
+ char *type;
+ char *errmsg = NULL;
+
+ if ( *s == '\n' || *s == '\0' ) {
+ break;
+ }
+
+ if ( (retmalloc = ldif_parse_line( s, &type, &valuecharptr, &valuelen, &errmsg )) < 0 ) {
+ if ( errmsg != NULL ) {
+ LDAPDebug( LDAP_DEBUG_PARSE, "%s", errmsg, 0, 0 );
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ slapi_ch_free( (void**)&errmsg );
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= str2entry_fast NULL (parse_line)\n", 0, 0, 0 );
+ continue;
+ }
+
+ /* We don't use errmsg anywhere later. free it to avoid leaking... */
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ slapi_ch_free( (void**)&errmsg );
+
+ /*
+ * Extract the attribute and value CSNs from the attribute type.
+ */
+ attributecsntype= CSN_TYPE_NONE;
+ csn_free(&attributedeletioncsn); /* JCM - Do this more efficiently */
+ csnset_free(&valuecsnset);
+ value_state= VALUE_NOTFOUND;
+ attr_state= ATTRIBUTE_NOTFOUND;
+ str2entry_state_information_from_type(type,&valuecsnset,&attributedeletioncsn,&maxcsn,&value_state,&attr_state);
+ if(!read_stateinfo)
+ {
+ /* We are not maintaining state information */
+ if(value_state==VALUE_DELETED || attr_state==ATTRIBUTE_DELETED)
+ {
+ /* ignore deleted values and attributes */
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ continue;
+ }
+ /* Ignore CSNs */
+ csn_free(&attributedeletioncsn);
+ csnset_free(&valuecsnset);
+ }
+ /*
+ * We cache some stuff as we go around the loop.
+ */
+ if((ptype==NULL)||(strcasecmp(type,ptype) != 0))
+ {
+ ptype=type;
+ nvals = 0;
+ maxvals = 0;
+ del_nvals = 0;
+ del_maxvals = 0;
+ a = NULL;
+ }
+
+ if ( strcasecmp( type, "dn" ) == 0 )
+ {
+ if ( slapi_entry_get_dn_const(e)!=NULL )
+ {
+ char ebuf[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "str2entry_fast: entry has multiple dns \"%s\" and \"%s\" (second ignored)\n",
+ escape_string( slapi_entry_get_dn_const(e), ebuf ),
+ escape_string( valuecharptr, ebuf ), 0 );
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ continue;
+ }
+ slapi_entry_set_dn(e,slapi_ch_strdup( valuecharptr ));
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ continue;
+ }
+
+ /* retrieve uniqueid */
+ if ( strcasecmp (type, SLAPI_ATTR_UNIQUEID) == 0 ){
+
+ if (e->e_uniqueid != NULL){
+ LDAPDebug (LDAP_DEBUG_ANY, "str2entry_fast: entry has multiple "
+ "uniqueids %s and %s (second ignored)\n",
+ e->e_uniqueid, valuecharptr, 0);
+ }else{
+ /* name2asi will be locked in slapi_entry_set_uniqueid */
+ attr_syntax_unlock_read();
+ slapi_entry_set_uniqueid (e, slapi_ch_strdup(valuecharptr));
+ attr_syntax_read_lock();
+ }
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ continue;
+ }
+
+ if (strcasecmp(type,"objectclass") == 0) {
+ if (strcasecmp(valuecharptr,"ldapsubentry") == 0)
+ e->e_flags |= SLAPI_ENTRY_LDAPSUBENTRY;
+ if (strcasecmp(valuecharptr, SLAPI_ATTR_VALUE_TOMBSTONE) == 0)
+ e->e_flags |= SLAPI_ENTRY_FLAG_TOMBSTONE;
+ }
+
+ {
+ Slapi_Value *value= value_new(NULL,CSN_TYPE_NONE,NULL);
+ slapi_value_set( value, valuecharptr, valuelen );
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ value->v_csnset= valuecsnset;
+ valuecsnset= NULL;
+ if(a==NULL)
+ {
+ switch(attr_state)
+ {
+ case ATTRIBUTE_PRESENT:
+ if(attrlist_find_or_create_locking_optional(&e->e_attrs, type, &a, PR_FALSE, PR_TRUE)==0 /* Found */)
+ {
+ LDAPDebug (LDAP_DEBUG_ANY, "str2entry_fast: Error. Non-contiguous attribute values for %s\n", type, 0, 0);
+ PR_ASSERT(0);
+ continue;
+ }
+ break;
+ case ATTRIBUTE_DELETED:
+ if(attrlist_find_or_create_locking_optional(&e->e_deleted_attrs, type, &a, PR_FALSE, PR_TRUE)==0 /* Found */)
+ {
+ LDAPDebug (LDAP_DEBUG_ANY, "str2entry_fast: Error. Non-contiguous deleted attribute values for %s\n", type, 0, 0);
+ PR_ASSERT(0);
+ continue;
+ }
+ break;
+ case ATTRIBUTE_NOTFOUND:
+ LDAPDebug (LDAP_DEBUG_ANY, "str2entry_fast: Error. Non-contiguous deleted attribute values for %s\n", type, 0, 0);
+ PR_ASSERT(0);
+ continue;
+ /* break; ??? */
+ }
+
+ }
+ {
+ const CSN *distinguishedcsn= csnset_get_csn_of_type(value->v_csnset,CSN_TYPE_VALUE_DISTINGUISHED);
+ if(distinguishedcsn!=NULL)
+ {
+ entry_add_dncsn_ext(e,distinguishedcsn, ENTRY_DNCSN_INCREASING);
+ }
+ }
+ if(value_state==VALUE_DELETED)
+ {
+ /* consumes the value */
+ valuearray_add_value_fast(
+ &(*a)->a_deleted_values.va, /* JCM .va is private */
+ value,
+ del_nvals,
+ &del_maxvals,
+ 0/*!Exact*/,
+ 1/*Passin*/ );
+ del_nvals++;
+ }
+ else
+ {
+ /* consumes the value */
+ valuearray_add_value_fast(
+ &(*a)->a_present_values.va, /* JCM .va is private */
+ value,
+ nvals,
+ &maxvals,
+ 0 /*!Exact*/,
+ 1 /*Passin*/ );
+ nvals++;
+ }
+ if(attributedeletioncsn!=NULL)
+ {
+ attr_set_deletion_csn(*a,attributedeletioncsn);
+ }
+ }
+ csn_free(&attributedeletioncsn);
+ csnset_free(&valuecsnset);
+ attr_val_cnt++;
+ }
+ if ( attr_val_cnt >= ENTRY_MAX_ATTRIBUTE_VALUE_COUNT )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "str2entry_fast: entry %s exceeded max attribute value cound %ld\n",
+ slapi_entry_get_dn_const(e)?slapi_entry_get_dn_const(e):"unkown",
+ attr_val_cnt, 0 );
+ }
+ if (read_stateinfo && maxcsn)
+ {
+ e->e_maxcsn = maxcsn;
+ }
+
+ /* release read lock of name2asi, per-entry lock */
+ attr_syntax_unlock_read();
+
+ /* check to make sure there was a dn: line */
+ if ( slapi_entry_get_dn_const(e)==NULL ) {
+ if (!(SLAPI_STR2ENTRY_INCLUDE_VERSION_STR & flags))
+ LDAPDebug( LDAP_DEBUG_ANY, "str2entry_fast: entry has no dn\n",
+ 0, 0, 0 );
+ slapi_entry_free( e );
+ return( NULL );
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= str2entry_fast 0x%x\n",
+ e, 0, 0 );
+ return( e );
+}
+
+
+#define STR2ENTRY_SMALL_BUFFER_SIZE 64
+#define STR2ENTRY_INITIAL_BERVAL_ARRAY_SIZE 8
+#define STR2ENTRY_VALUE_DUPCHECK_THRESHOLD 5
+
+typedef struct _entry_attr_data {
+ int ead_attrarrayindex;
+ const char *ead_attrtypename;
+ char ead_allocated; /* non-zero if this struct needs to be freed */
+} entry_attr_data;
+
+/* Structure which stores a tree for the attributes on the entry rather than the linked list on a regular entry struture */
+typedef struct _entry_attrs {
+ Avlnode *ea_attrlist;
+ int ea_attrdatacount;
+ entry_attr_data ea_attrdata[ STR2ENTRY_SMALL_BUFFER_SIZE ];
+} entry_attrs;
+
+typedef struct _str2entry_attr {
+ char *sa_type;
+ int sa_state;
+ struct valuearrayfast sa_present_values;
+ struct valuearrayfast sa_deleted_values;
+ int sa_numdups;
+ struct slapdplugin *sa_pi;
+ value_compare_fn_type sa_comparefn;
+ Avlnode *sa_vtree;
+ CSN *sa_attributedeletioncsn;
+} str2entry_attr;
+
+static void
+entry_attr_init(str2entry_attr *sa, const char *type, int state)
+{
+ sa->sa_type= slapi_ch_strdup(type);
+ sa->sa_state= state;
+ valuearrayfast_init(&sa->sa_present_values,NULL);
+ valuearrayfast_init(&sa->sa_deleted_values,NULL);
+ sa->sa_numdups= 0;
+ sa->sa_pi= NULL;
+ sa->sa_comparefn = NULL;
+ sa->sa_vtree= NULL;
+ sa->sa_attributedeletioncsn= NULL;
+}
+
+/*
+ * Create a tree of attributes.
+ */
+static int
+entry_attrs_new(entry_attrs **pea)
+{
+ entry_attrs *tmp = (entry_attrs *)slapi_ch_calloc(1, sizeof(entry_attrs));
+ if (NULL == tmp) {
+ return -1;
+ } else {
+ *pea = tmp;
+ return 0;
+ }
+}
+
+/*
+ * Delete an attribute type tree node.
+ */
+static void
+attr_type_node_free( caddr_t data )
+{
+ entry_attr_data *ea = (entry_attr_data *)data;
+ if ( NULL != ea && ea->ead_allocated ) {
+ slapi_ch_free( (void **)&ea );
+ }
+}
+
+
+/*
+ * Delete a tree of attributes.
+ */
+static void
+entry_attrs_delete(entry_attrs **pea)
+{
+ if (NULL != *pea) {
+ /* Delete the AVL tree */
+ avl_free((*pea)->ea_attrlist, attr_type_node_free);
+ slapi_ch_free((void**)pea);
+ }
+}
+
+static int
+attr_type_node_cmp( caddr_t d1, caddr_t d2 )
+{
+ /*
+ * A simple strcasecmp() will do here because we do not care
+ * about subtypes, etc. The slapi_str2entry() function treats
+ * subtypes as distinct attribute types, because that is how
+ * they are stored within the Slapi_Entry structure.
+ */
+ entry_attr_data *ea1= (entry_attr_data *)d1;
+ entry_attr_data *ea2= (entry_attr_data *)d2;
+ PR_ASSERT( ea1 != NULL );
+ PR_ASSERT( ea1->ead_attrtypename != NULL );
+ PR_ASSERT( ea2 != NULL );
+ PR_ASSERT( ea2->ead_attrtypename != NULL );
+ return strcasecmp(ea1->ead_attrtypename,ea2->ead_attrtypename);
+}
+
+/*
+ * Adds a new attribute to the attribute tree.
+ */
+static void
+entry_attrs_add(entry_attrs *ea, const char *atname, int atarrayindex)
+{
+ entry_attr_data *ead;
+
+ if ( ea->ea_attrdatacount < STR2ENTRY_SMALL_BUFFER_SIZE ) {
+ ead = &(ea->ea_attrdata[ ea->ea_attrdatacount ]);
+ ead->ead_allocated = 0;
+ } else {
+ ead = (entry_attr_data *)slapi_ch_malloc( sizeof( entry_attr_data ));
+ ead->ead_allocated = 1;
+ }
+ ++ea->ea_attrdatacount;
+ ead->ead_attrarrayindex = atarrayindex;
+ ead->ead_attrtypename = atname; /* a reference, not a strdup! */
+
+ avl_insert( &(ea->ea_attrlist), ead, attr_type_node_cmp, avl_dup_error );
+}
+
+/*
+ * Checks for an attribute in the tree. Returns the attr array index or -1
+ * if not found;
+ */
+static int
+entry_attrs_find(entry_attrs *ea,char *type)
+{
+ entry_attr_data tmpead = {0};
+ entry_attr_data *foundead;
+
+ tmpead.ead_attrtypename = type;
+ foundead = (entry_attr_data *)avl_find( ea->ea_attrlist, &tmpead,
+ attr_type_node_cmp );
+ return ( NULL != foundead ) ? foundead->ead_attrarrayindex : -1;
+}
+
+/* What's going on here then ?
+ Well, originally duplicate value checking was done by taking each
+ new value and comparing in turn against all the previous values.
+ Needless to say this was costly when there were many values.
+ So, new code was written which built a binary tree of index keys
+ for the values, and the test was done against the tree.
+ Nothing wrong with this, it speeded up the case where there were
+ many values nicely.
+ Unfortunately, when there are few values, it proved to be a significent
+ performance sink.
+ So, now we check the old way up 'till there's 5 attribute values, then
+ switch to the tree-based scheme.
+
+ Note that duplicate values are only checked for and ignored
+ if flags contains SLAPI_STR2ENTRY_REMOVEDUPVALS.
+ */
+
+static Slapi_Entry *
+str2entry_dupcheck( char *s, int flags, int read_stateinfo )
+{
+ Slapi_Entry *e;
+ str2entry_attr stack_attrs[STR2ENTRY_SMALL_BUFFER_SIZE];
+ str2entry_attr *dyn_attrs = NULL;
+ str2entry_attr *attrs = stack_attrs;
+ str2entry_attr *prev_attr= NULL;
+ int nattrs;
+ int maxattrs = STR2ENTRY_SMALL_BUFFER_SIZE;
+ char *type;
+ str2entry_attr *sa;
+ int i, j;
+ char *next=NULL;
+ char *valuecharptr=NULL;
+ char *errmsg = NULL;
+ int retmalloc = 0;
+ int rc;
+ int fast_dup_check = 0;
+ entry_attrs *ea = NULL;
+ int tree_attr_checking = 0;
+ int big_entry_attr_presence_check = 0;
+ int check_for_duplicate_values =
+ ( 0 != ( flags & SLAPI_STR2ENTRY_REMOVEDUPVALS ));
+ Slapi_Value *value = 0;
+ CSN *maxcsn= NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> str2entry_dupcheck\n", 0, 0, 0 );
+
+ e = slapi_entry_alloc();
+ slapi_entry_init(e,NULL,NULL);
+ next = s;
+ nattrs = 0;
+
+ if (flags & SLAPI_STR2ENTRY_BIGENTRY)
+ {
+ big_entry_attr_presence_check = 1;
+ }
+ while ( (s = ldif_getline( &next )) != NULL )
+ {
+ CSN *attributedeletioncsn= NULL;
+ CSNType attributecsntype;
+ CSNSet *valuecsnset= NULL;
+ int value_state= VALUE_NOTFOUND;
+ int attr_state= VALUE_NOTFOUND;
+ int valuelen;
+
+ if ( *s == '\n' || *s == '\0' ) {
+ break;
+ }
+
+ if ( (retmalloc = ldif_parse_line( s, &type, &valuecharptr, &valuelen, &errmsg )) < 0 ) {
+ if ( errmsg != NULL ) {
+ LDAPDebug( LDAP_DEBUG_PARSE, "%s", errmsg, 0, 0 );
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ slapi_ch_free( (void**)&errmsg );
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= slapi_str2entry NULL (parse_line)\n", 0, 0, 0 );
+ continue;
+ }
+
+ /* We don't use errmsg anywhere later. free it to avoid leaking... */
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ slapi_ch_free( (void**)&errmsg );
+
+ /*
+ * Extract the attribute and value CSNs from the attribute type.
+ */
+ attributecsntype= CSN_TYPE_UNKNOWN;
+ csn_free(&attributedeletioncsn);
+ csnset_free(&valuecsnset);
+ value_state= VALUE_NOTFOUND;
+ attr_state= VALUE_NOTFOUND;
+ str2entry_state_information_from_type(type,&valuecsnset,&attributedeletioncsn,&maxcsn,&value_state,&attr_state);
+ if(!read_stateinfo)
+ {
+ /* We are not maintaining state information */
+ if(value_state==VALUE_DELETED || attr_state==ATTRIBUTE_DELETED)
+ {
+ /* ignore deleted values and attributes */
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ continue;
+ }
+ /* Ignore CSNs */
+ csn_free(&attributedeletioncsn);
+ csnset_free(&valuecsnset);
+ }
+
+ if ( strcasecmp( type, "dn" ) == 0 ) {
+ if ( slapi_entry_get_dn_const(e)!=NULL ) {
+ char ebuf[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "slapi_str2entry: entry has multiple dns \"%s\" and \"%s\" (second ignored)\n",
+ escape_string( slapi_entry_get_dn_const(e), ebuf ),
+ escape_string( valuecharptr, ebuf ), 0 );
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ continue;
+ }
+ slapi_entry_set_dn(e,slapi_ch_strdup( valuecharptr ));
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ continue;
+ }
+
+ /* retrieve uniqueid */
+ if ( strcasecmp (type, SLAPI_ATTR_UNIQUEID) == 0 ){
+
+ if (e->e_uniqueid != NULL){
+ LDAPDebug (LDAP_DEBUG_ANY, "slapi_str2entry: entry has multiple "
+ "uniqueids %s and %s (second ignored)\n",
+ e->e_uniqueid, valuecharptr, 0);
+ }else{
+ slapi_entry_set_uniqueid (e, slapi_ch_strdup(valuecharptr));
+ }
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ continue;
+ }
+
+ if (strcasecmp(type,"objectclass") == 0) {
+ if (strcasecmp(valuecharptr,"ldapsubentry") == 0)
+ e->e_flags |= SLAPI_ENTRY_LDAPSUBENTRY;
+ if (strcasecmp(valuecharptr, SLAPI_ATTR_VALUE_TOMBSTONE) == 0)
+ e->e_flags |= SLAPI_ENTRY_FLAG_TOMBSTONE;
+ }
+
+ /* Here we have a quick look to see if this attribute is a new
+ value for the type we last processed or a new type.
+ If not, we look to see if we've seen this attribute type before.
+ */
+ if ( prev_attr!=NULL && strcasecmp( type, prev_attr->sa_type ) != 0 )
+ {
+ /* Different attribute type - find it, or alloc new */
+ prev_attr = NULL;
+ /* The linear check below can take a while, so we change to use a tree if there are many attrs */
+ if (!big_entry_attr_presence_check)
+ {
+ for ( i = 0; i < nattrs; i++ )
+ {
+ if (strcasecmp( type, attrs[i].sa_type ) == 0 )
+ {
+ prev_attr = &attrs[i];
+ break;
+ }
+ }
+ }
+ else
+ {
+ int prev_index;
+
+ /* Did we just switch checking mechanism ? */
+ if (!tree_attr_checking)
+ {
+ /* If so then put the exising attrs into the tree */
+ if (0 != entry_attrs_new(&ea))
+ {
+ /* Something very bad happened */
+ return NULL;
+ }
+ for ( i = 0; i < nattrs; i++ )
+ {
+ entry_attrs_add(ea,attrs[i].sa_type, i);
+ }
+ tree_attr_checking = 1;
+ }
+ prev_index = entry_attrs_find(ea,type);
+ if ( prev_index >= 0 ) {
+ prev_attr = &attrs[prev_index];
+ /* (prev_attr!=NULL) Means that we already had that one in the set */
+ }
+ }
+ }
+ if ( prev_attr==NULL )
+ {
+ /* Haven't seen this type yet */
+ fast_dup_check = 1;
+ if ( nattrs == maxattrs )
+ {
+ /* Out of space - reallocate */
+ maxattrs *= 2;
+ if ( nattrs == STR2ENTRY_SMALL_BUFFER_SIZE ) {
+ /* out of fixed space - switch to dynamic */
+ PR_ASSERT( dyn_attrs == NULL );
+ dyn_attrs = (str2entry_attr *)
+ slapi_ch_malloc( sizeof( str2entry_attr ) *
+ maxattrs );
+ memcpy( dyn_attrs, stack_attrs,
+ STR2ENTRY_SMALL_BUFFER_SIZE *
+ sizeof( str2entry_attr ));
+ attrs = dyn_attrs;
+ } else {
+ /* Need more dynamic space */
+ dyn_attrs = (str2entry_attr *)
+ slapi_ch_realloc( (char *) dyn_attrs,
+ sizeof( str2entry_attr ) * maxattrs );
+ attrs = dyn_attrs; /* realloc may change base pointer */
+ }
+ }
+
+ /* Record the new type in the array */
+ entry_attr_init(&attrs[nattrs], type, attr_state);
+
+ if ( check_for_duplicate_values )
+ {
+ if ( slapi_attr_type2plugin( type,(void **)&(attrs[nattrs].sa_pi) ) != 0 )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "<= slapi_str2entry NULL (slapi_attr_type2plugin)\n",
+ 0, 0, 0 );
+ slapi_entry_free( e ); e = NULL;
+ goto free_and_return;
+ }
+ /* Get the comparison function for later use */
+ plugin_call_syntax_get_compare_fn( attrs[nattrs].sa_pi, &(attrs[nattrs].sa_comparefn));
+ /*
+ * If the compare function wasn't available,
+ * we have to revert to AVL-tree-based dup checking,
+ * which uses index keys for comparisons
+ */
+ if (NULL == attrs[nattrs].sa_comparefn)
+ {
+ fast_dup_check = 0;
+ }
+ /*
+ * If we are maintaining the attribute tree,
+ * then add the new attribute to the tree.
+ */
+ if (big_entry_attr_presence_check && tree_attr_checking)
+ {
+ entry_attrs_add(ea,attrs[nattrs].sa_type, nattrs);
+ }
+ }
+ prev_attr = &attrs[nattrs];
+ nattrs++;
+ }
+
+ sa = prev_attr; /* For readability */
+ value= value_new(NULL,CSN_TYPE_NONE,NULL);
+ slapi_value_set( value, valuecharptr, valuelen );
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ if (retmalloc) slapi_ch_free((void **) &valuecharptr);
+ value->v_csnset= valuecsnset;
+ valuecsnset= NULL;
+ {
+ const CSN *distinguishedcsn= csnset_get_csn_of_type(value->v_csnset,CSN_TYPE_VALUE_DISTINGUISHED);
+ if(distinguishedcsn!=NULL)
+ {
+ entry_add_dncsn(e,distinguishedcsn);
+ }
+ }
+
+ if(value_state==VALUE_DELETED)
+ {
+ /*
+ * for deleted values, we do not want to perform a dupcheck against
+ * existing values. Also, we do not want to add it to the
+ * avl tree (if one is being maintained)
+ *
+ */
+ rc = 0; /* Presume no duplicate */
+ }
+ else if ( !check_for_duplicate_values )
+ {
+ rc = LDAP_SUCCESS; /* presume no duplicate */
+ } else {
+ /* For value dup checking, we either use brute-force, if there's a small number */
+ /* Or a tree-based approach if there's a large number. */
+ /* The tree code is expensive, which is why we don't use it unless there's many attributes */
+ rc = 0; /* Presume no duplicate */
+ if (fast_dup_check)
+ {
+ /* Fast dup-checking */
+ /* Do we now have so many values that we should switch to tree-based checking ? */
+ if (sa->sa_present_values.num > STR2ENTRY_VALUE_DUPCHECK_THRESHOLD)
+ {
+ /* Make the tree from the existing attr values */
+ rc= valuetree_add_valuearray( sa->sa_type, sa->sa_pi, sa->sa_present_values.va, &sa->sa_vtree, NULL);
+ /* Check if the value already exists, in the tree. */
+ rc= valuetree_add_value( sa->sa_type, sa->sa_pi, value, &sa->sa_vtree);
+ fast_dup_check = 0;
+ }
+ else
+ {
+ /* JCM - need an efficient valuearray function to do this */
+ /* Brute-force check */
+ for ( j = 0; j < sa->sa_present_values.num; j++ )/* JCM innards */
+ {
+ if (0 == sa->sa_comparefn(slapi_value_get_berval(value),slapi_value_get_berval(sa->sa_present_values.va[j])))/* JCM innards */
+ {
+ /* Oops---this value matches one already present */
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ /* Check if the value already exists, in the tree. */
+ rc = valuetree_add_value( sa->sa_type, sa->sa_pi, value, &sa->sa_vtree);
+ }
+ }
+
+ if ( rc==LDAP_SUCCESS )
+ {
+ if(value_state==VALUE_DELETED)
+ {
+ valuearrayfast_add_value_passin(&sa->sa_deleted_values,value);
+ value= NULL; /* value was consumed */
+ }
+ else
+ {
+ valuearrayfast_add_value_passin(&sa->sa_present_values,value);
+ value= NULL; /* value was consumed */
+ }
+ if(attributedeletioncsn!=NULL)
+ {
+ sa->sa_attributedeletioncsn= attributedeletioncsn;
+ attributedeletioncsn= NULL; /* csn was consumed */
+ }
+ }
+ else if (rc==LDAP_TYPE_OR_VALUE_EXISTS)
+ {
+ sa->sa_numdups++;
+ }
+ else
+ {
+ /* Failure adding to value tree */
+ LDAPDebug( LDAP_DEBUG_ANY, "slapi_str2entry: unexpected failure %d constructing value tree\n", rc, 0, 0 );
+ slapi_entry_free( e ); e = NULL;
+ goto free_and_return;
+ }
+
+ slapi_value_free(&value);
+ }
+
+ /* All done with parsing. Now create the entry. */
+ /* check to make sure there was a dn: line */
+ if ( slapi_entry_get_dn_const(e)==NULL )
+ {
+ if (!(SLAPI_STR2ENTRY_INCLUDE_VERSION_STR & flags))
+ LDAPDebug( LDAP_DEBUG_ANY, "slapi_str2entry: entry has no dn\n",
+ 0, 0, 0 );
+ slapi_entry_free( e ); e = NULL;
+ goto free_and_return;
+ }
+
+ /* get the read lock of name2asi for performance purpose.
+ It reduces read locking by per-entry lock, instead of per-attribute.
+ */
+ attr_syntax_read_lock();
+
+ /*
+ * For each unique attribute in the array,
+ * Create a Slapi_Attr and set it's present and deleted values.
+ */
+ for ( i = 0; i < nattrs; i++ )
+ {
+ sa = &attrs[i];
+ if ( sa->sa_numdups > 0 )
+ {
+ if ( sa->sa_numdups > 1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "%d duplicate values for attribute "
+ "type %s detected in entry %s. Extra values ignored.\n",
+ sa->sa_numdups, sa->sa_type, slapi_entry_get_dn_const(e) );
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY, "Duplicate value for attribute "
+ "type %s detected in entry %s. Extra value ignored.\n",
+ sa->sa_type, slapi_entry_get_dn_const(e), 0 );
+ }
+ }
+ {
+ Slapi_Attr **alist= NULL;
+ if(sa->sa_state==ATTRIBUTE_DELETED)
+ {
+ if(read_stateinfo)
+ {
+ alist= &e->e_deleted_attrs;
+ }
+ else
+ {
+ /*
+ * if we are not maintaining state info,
+ * ignore the deleted attributes
+ */
+ }
+ }
+ else
+ {
+ alist= &e->e_attrs;
+ }
+ if(alist!=NULL)
+ {
+ int maxvals = 0;
+ Slapi_Attr **a= NULL;
+ attrlist_find_or_create_locking_optional(alist, sa->sa_type, &a, PR_FALSE, PR_TRUE);
+ valuearray_add_valuearray_fast( /* JCM should be calling a valueset function */
+ &(*a)->a_present_values.va, /* JCM .va is private */
+ sa->sa_present_values.va,
+ 0, /* Currently there are no present values on the attribute */
+ sa->sa_present_values.num,
+ &maxvals,
+ 1/*Exact*/,
+ 1/*Passin*/);
+ sa->sa_present_values.num= 0; /* The values have been consumed */
+ maxvals = 0;
+ valuearray_add_valuearray_fast( /* JCM should be calling a valueset function */
+ &(*a)->a_deleted_values.va, /* JCM .va is private */
+ sa->sa_deleted_values.va,
+ 0, /* Currently there are no deleted values on the attribute */
+ sa->sa_deleted_values.num,
+ &maxvals,
+ 1/*Exact*/,
+ 1/*Passin*/);
+ sa->sa_deleted_values.num= 0; /* The values have been consumed */
+ if(sa->sa_attributedeletioncsn!=NULL)
+ {
+ attr_set_deletion_csn(*a,sa->sa_attributedeletioncsn);
+ }
+ }
+ }
+ }
+
+ /* release read lock of name2asi, per-entry lock */
+ attr_syntax_unlock_read();
+
+
+ /* Add the RDN values, if asked, and if not already present */
+ if ( flags & SLAPI_STR2ENTRY_ADDRDNVALS ) {
+ if ( slapi_entry_add_rdn_values( e ) != LDAP_SUCCESS ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "slapi_str2entry: entry has badly formatted dn\n",
+ 0, 0, 0 );
+ slapi_entry_free( e ); e = NULL;
+ goto free_and_return;
+ }
+ }
+
+ if (read_stateinfo)
+ {
+ e->e_maxcsn = maxcsn;
+ }
+
+free_and_return:
+ for ( i = 0; i < nattrs; i++ )
+ {
+ slapi_ch_free((void **) &(attrs[ i ].sa_type));
+ valuearrayfast_done(&attrs[ i ].sa_present_values);
+ valuearrayfast_done(&attrs[ i ].sa_deleted_values);
+ valuetree_free( &attrs[ i ].sa_vtree );
+ }
+ if (tree_attr_checking)
+ {
+ entry_attrs_delete(&ea);
+ }
+ slapi_ch_free((void **) &dyn_attrs );
+ if (value) slapi_value_free(&value);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= str2entry_dupcheck 0x%x \"%s\"\n",
+ e, slapi_sdn_get_dn (slapi_entry_get_sdn_const(e)), 0 );
+ return e;
+}
+
+/*
+ *
+ * Convert an entry in LDIF format into a
+ * Slapi_Entry structure. If we can assume that the
+ * LDIF is well-formed we call str2entry_fast(),
+ * which does no error checking.
+ * Otherwise we do not assume well-formed LDIF, and
+ * call str2entry_dupcheck(), which checks for
+ * duplicate attribute values and does not assume
+ * that values are all contiguous.
+ *
+ * Well-formed LDIF has the following characteristics:
+ * 1) There are no duplicate attribute values
+ * 2) The RDN is an attribute of the entry
+ * 3) All values for a given attribute type are
+ * contiguous.
+ */
+#define SLAPI_STRENTRY_FLAGS_HANDLED_IN_SLAPI_STR2ENTRY \
+ ( SLAPI_STR2ENTRY_IGNORE_STATE \
+ | SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES \
+ | SLAPI_STR2ENTRY_TOMBSTONE_CHECK \
+ )
+
+#define SLAPI_STRENTRY_FLAGS_HANDLED_BY_STR2ENTRY_FAST \
+ ( SLAPI_STR2ENTRY_INCLUDE_VERSION_STR \
+ | SLAPI_STRENTRY_FLAGS_HANDLED_IN_SLAPI_STR2ENTRY \
+ )
+
+
+Slapi_Entry *
+slapi_str2entry( char *s, int flags )
+{
+ Slapi_Entry *e;
+ int read_stateinfo= ~( flags & SLAPI_STR2ENTRY_IGNORE_STATE );
+
+ LDAPDebug( LDAP_DEBUG_ARGS,
+ "slapi_str2entry: flags=0x%x, entry=\"%.50s...\"\n",
+ flags, s, 0 );
+
+
+ /*
+ * If well-formed LDIF has not been provided OR if a flag that is
+ * not handled by str2entry_fast() has been passed in, call the
+ * slower but more forgiving str2entry_dupcheck() function.
+ */
+ if ( 0 != ( flags & SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF ) ||
+ 0 != ( flags & ~SLAPI_STRENTRY_FLAGS_HANDLED_BY_STR2ENTRY_FAST ))
+ {
+ e= str2entry_dupcheck( s, flags, read_stateinfo );
+ }
+ else
+ {
+ e= str2entry_fast( s, flags, read_stateinfo );
+ }
+ if (!e)
+ return e; /* e == NULL */
+
+ if ( flags & SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES )
+ {
+ slapi_schema_expand_objectclasses( e );
+ }
+
+ if ( flags & SLAPI_STR2ENTRY_TOMBSTONE_CHECK )
+ {
+ /*
+ * Check if the entry is a tombstone.
+ */
+ if(slapi_entry_attr_hasvalue(e, SLAPI_ATTR_OBJECTCLASS, SLAPI_ATTR_VALUE_TOMBSTONE))
+ {
+ e->e_flags |= SLAPI_ENTRY_FLAG_TOMBSTONE;
+ }
+ }
+ return e;
+}
+
+static size_t
+entry2str_internal_size_value( const char *attrtype, const Slapi_Value *v, int entry2str_ctrl, int attribute_state, int value_state )
+{
+ size_t elen= 0;
+ if(attrtype!=NULL)
+ {
+ size_t attrtypelen= strlen(attrtype);
+ if(entry2str_ctrl & SLAPI_DUMP_STATEINFO)
+ {
+ attrtypelen+= csnset_string_size(v->v_csnset);
+ if (attribute_state==ATTRIBUTE_DELETED)
+ {
+ attrtypelen += DELETED_ATTR_STRSIZE;
+ }
+ if(value_state==VALUE_DELETED)
+ {
+ attrtypelen += DELETED_VALUE_STRSIZE;
+ }
+ }
+ elen = LDIF_SIZE_NEEDED(attrtypelen, slapi_value_get_berval(v)->bv_len);
+ }
+ return elen;
+}
+
+static size_t
+entry2str_internal_size_valueset( const char *attrtype, const Slapi_ValueSet *vs, int entry2str_ctrl, int attribute_state, int value_state )
+{
+ size_t elen= 0;
+ if(!valueset_isempty(vs))
+ {
+ int i;
+ Slapi_Value **va= valueset_get_valuearray(vs);
+ for (i = 0; va[i]; i++)
+ {
+ elen+= entry2str_internal_size_value(attrtype, va[i], entry2str_ctrl,
+ attribute_state, value_state );
+ }
+ }
+ return elen;
+}
+
+static size_t
+entry2str_internal_size_attrlist( const Slapi_Attr *attrlist, int entry2str_ctrl, int attribute_state )
+{
+ size_t elen= 0;
+ const Slapi_Attr *a;
+ for (a= attrlist; a; a = a->a_next)
+ {
+ /* skip operational attributes if not requested */
+ if ((entry2str_ctrl & SLAPI_DUMP_NOOPATTRS) &&
+ slapi_attr_flag_is_set(a, SLAPI_ATTR_FLAG_OPATTR))
+ continue;
+
+ /* Count the space required for the present and deleted values */
+ elen+= entry2str_internal_size_valueset(a->a_type, &a->a_present_values,
+ entry2str_ctrl, attribute_state,
+ VALUE_PRESENT);
+ if(entry2str_ctrl & SLAPI_DUMP_STATEINFO)
+ {
+ elen+= entry2str_internal_size_valueset(a->a_type, &a->a_deleted_values,
+ entry2str_ctrl, attribute_state,
+ VALUE_DELETED);
+ /* ";adcsn-" + a->a_deletioncsn */
+ if ( a->a_deletioncsn )
+ {
+ elen+= 1 + LDIF_CSNPREFIX_MAXLENGTH + CSN_STRSIZE;
+ }
+ }
+ }
+ return elen;
+}
+
+static void
+entry2str_internal_put_value( const char *attrtype, const CSN *attrcsn, CSNType attrcsntype, int attr_state, const Slapi_Value *v, int value_state, char **ecur, char **typebuf, size_t *typebuf_len, int entry2str_ctrl )
+{
+ const char *type;
+ unsigned long options = 0;
+ const struct berval *bvp;
+ if(entry2str_ctrl & SLAPI_DUMP_STATEINFO)
+ {
+ char *p;
+ size_t attrtypelen= strlen(attrtype);
+ size_t attrcsnlen= 0;
+ size_t valuecsnlen= 0;
+ size_t need= attrtypelen+1;
+ if(attrcsn!=NULL)
+ {
+ /* ; csntype csn */
+ attrcsnlen= 1 + csn_string_size();
+ need+= attrcsnlen;
+ }
+ if(v->v_csnset!=NULL)
+ {
+ /* +(; csntype csn) */
+ valuecsnlen= csnset_string_size(v->v_csnset);
+ need+= valuecsnlen;
+ }
+ if(attr_state==ATTRIBUTE_DELETED)
+ {
+ need+= DELETED_ATTR_STRSIZE;
+ }
+ if(value_state==VALUE_DELETED)
+ {
+ need+= DELETED_VALUE_STRSIZE; /* ;deleted */
+ }
+ if(*typebuf_len<need)
+ {
+ *typebuf= (char*)slapi_ch_realloc(*typebuf,need);
+ *typebuf_len= need;
+ }
+ p= *typebuf;
+ type= p;
+ strcpy(p,attrtype);
+ p+= attrtypelen;
+ if(attrcsn!=NULL)
+ {
+ csn_as_attr_option_string(attrcsntype,attrcsn,p);
+ p+= attrcsnlen;
+ }
+ if(v->v_csnset!=NULL)
+ {
+ csnset_as_string(v->v_csnset,p);
+ p+= valuecsnlen;
+ }
+ if(attr_state==ATTRIBUTE_DELETED)
+ {
+ strcpy(p,DELETED_ATTR_STRING);
+ p+= DELETED_ATTR_STRSIZE;
+ }
+ if(value_state==VALUE_DELETED)
+ {
+ strcpy(p,DELETED_VALUE_STRING);
+ }
+ }
+ else
+ {
+ type= attrtype;
+ }
+ if (entry2str_ctrl & SLAPI_DUMP_NOWRAP)
+ options |= LDIF_OPT_NOWRAP;
+ if (entry2str_ctrl & SLAPI_DUMP_MINIMAL_ENCODING)
+ options |= LDIF_OPT_MINIMAL_ENCODING;
+ bvp = slapi_value_get_berval(v);
+ ldif_put_type_and_value_with_options( ecur, (char*)type, bvp->bv_val, bvp->bv_len, options );
+}
+
+static void
+entry2str_internal_put_valueset( const char *attrtype, const CSN *attrcsn, CSNType attrcsntype, int attr_state, const Slapi_ValueSet *vs, int value_state, char **ecur, char **typebuf, size_t *typebuf_len, int entry2str_ctrl )
+{
+ if(!valueset_isempty(vs))
+ {
+ int i;
+ Slapi_Value **va= valueset_get_valuearray(vs);
+ for ( i = 0; va[i] != NULL; i++ )
+ {
+ /* Attach the attribute deletion csn on the first value */
+ if((entry2str_ctrl & SLAPI_DUMP_STATEINFO) && i==0)
+ {
+ entry2str_internal_put_value( attrtype, attrcsn, attrcsntype, attr_state, va[i], value_state, ecur, typebuf, typebuf_len, entry2str_ctrl );
+ }
+ else
+ {
+ entry2str_internal_put_value( attrtype, NULL, CSN_TYPE_UNKNOWN, attr_state, va[i], value_state, ecur, typebuf, typebuf_len, entry2str_ctrl );
+ }
+ }
+ }
+}
+
+static void
+entry2str_internal_put_attrlist( const Slapi_Attr *attrlist, int attr_state, int entry2str_ctrl, char **ecur, char **typebuf, size_t *typebuf_len)
+{
+ const Slapi_Attr *a;
+
+ /* Put the present attributes */
+ for (a= attrlist; a; a = a->a_next)
+ {
+ /* skip operational attributes if not requested */
+ if ((entry2str_ctrl & SLAPI_DUMP_NOOPATTRS) &&
+ slapi_attr_flag_is_set(a, SLAPI_ATTR_FLAG_OPATTR))
+ continue;
+
+ /* don't dump uniqueid if not asked */
+ if (!(strcasecmp(a->a_type, SLAPI_ATTR_UNIQUEID) == 0 &&
+ !(SLAPI_DUMP_UNIQUEID & entry2str_ctrl)))
+ {
+ /* Putting present attribute values */
+ /* put "<type>:[:] <value>" line for each value */
+ int present_values= !valueset_isempty(&a->a_present_values);
+ if(present_values)
+ {
+ entry2str_internal_put_valueset(a->a_type, a->a_deletioncsn, CSN_TYPE_ATTRIBUTE_DELETED, attr_state, &a->a_present_values, VALUE_PRESENT, ecur, typebuf, typebuf_len, entry2str_ctrl);
+ }
+ if(entry2str_ctrl & SLAPI_DUMP_STATEINFO)
+ {
+ /* Putting deleted attribute values */
+ if(present_values)
+ {
+ entry2str_internal_put_valueset(a->a_type, NULL, CSN_TYPE_NONE, attr_state, &a->a_deleted_values, VALUE_DELETED, ecur, typebuf, typebuf_len, entry2str_ctrl);
+ }
+ else
+ {
+ /* There were no present values on which to place the ADCSN, so we put it on the first deleted value. */
+ entry2str_internal_put_valueset(a->a_type, a->a_deletioncsn, CSN_TYPE_ATTRIBUTE_DELETED, attr_state, &a->a_deleted_values, VALUE_DELETED, ecur, typebuf, typebuf_len, entry2str_ctrl);
+ }
+ }
+ }
+ }
+}
+
+static char *
+entry2str_internal( Slapi_Entry *e, int *len, int entry2str_ctrl )
+{
+ char *ebuf;
+ char *ecur;
+ size_t elen = 0;
+ size_t typebuf_len= 64;
+ char *typebuf= (char *)slapi_ch_malloc(typebuf_len);
+ Slapi_Value dnvalue;
+
+ /*
+ * In string format, an entry looks like this:
+ * dn: <dn>\n
+ * [<attr>: <value>\n]*
+ */
+
+ ecur = ebuf = NULL;
+
+ value_init(&dnvalue,NULL,CSN_TYPE_NONE,NULL);
+
+ /* find length of buffer needed to hold this entry */
+ if (slapi_entry_get_dn_const(e)!=NULL)
+ {
+ slapi_value_set_string(&dnvalue,slapi_entry_get_dn_const(e));
+ elen+= entry2str_internal_size_value( "dn", &dnvalue, entry2str_ctrl,
+ ATTRIBUTE_PRESENT, VALUE_PRESENT );
+ }
+
+ /* Count the space required for the present attributes */
+ elen+= entry2str_internal_size_attrlist( e->e_attrs, entry2str_ctrl, ATTRIBUTE_PRESENT );
+
+ /* Count the space required for the deleted attributes */
+ if(entry2str_ctrl & SLAPI_DUMP_STATEINFO)
+ {
+ elen+= entry2str_internal_size_attrlist( e->e_deleted_attrs, entry2str_ctrl,
+ ATTRIBUTE_DELETED );
+ }
+
+ elen += 1;
+ ecur = ebuf = (char *)slapi_ch_malloc(elen);
+
+ /* put the dn */
+ if ( slapi_entry_get_dn_const(e)!=NULL)
+ {
+ /* put "dn: <dn>" */
+ entry2str_internal_put_value("dn", NULL, CSN_TYPE_NONE, ATTRIBUTE_PRESENT, &dnvalue, VALUE_PRESENT, &ecur, &typebuf, &typebuf_len, entry2str_ctrl);
+ }
+
+ /* Put the present attributes */
+ entry2str_internal_put_attrlist( e->e_attrs, ATTRIBUTE_PRESENT, entry2str_ctrl, &ecur, &typebuf, &typebuf_len );
+
+ /* Put the deleted attributes */
+ if(entry2str_ctrl & SLAPI_DUMP_STATEINFO)
+ {
+ entry2str_internal_put_attrlist( e->e_deleted_attrs, ATTRIBUTE_DELETED, entry2str_ctrl, &ecur, &typebuf, &typebuf_len );
+ }
+
+ *ecur = '\0';
+ if ( (size_t)(ecur - ebuf + 1) > elen )
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL,
+ "entry2str_internal: array boundary wrote: bufsize=%d wrote=%d\n",
+ elen, (ecur - ebuf + 1));
+ }
+
+ if ( NULL != len ) {
+ *len = ecur - ebuf;
+ }
+
+ slapi_ch_free((void**)&typebuf);
+ value_done(&dnvalue);
+
+ return ebuf;
+}
+
+char *
+slapi_entry2str( Slapi_Entry *e, int *len )
+{
+ return entry2str_internal(e, len, 0);
+}
+
+char *
+slapi_entry2str_dump_uniqueid( Slapi_Entry *e, int *len )
+{
+ return entry2str_internal(e, len, SLAPI_DUMP_UNIQUEID);
+}
+
+char *
+slapi_entry2str_no_opattrs( Slapi_Entry *e, int *len )
+{
+ return entry2str_internal(e, len, SLAPI_DUMP_NOOPATTRS);
+}
+
+char *
+slapi_entry2str_with_options( Slapi_Entry *e, int *len, int options )
+{
+ return entry2str_internal(e, len, options);
+}
+
+static int entry_type = -1; /* The type number assigned by the Factory for 'Entry' */
+
+int
+get_entry_object_type()
+{
+ if(entry_type==-1)
+ {
+ /* The factory is given the name of the object type, in
+ * return for a type handle. Whenever the object is created
+ * or destroyed the factory is called with the handle so
+ * that it may call the constructors or destructors registered
+ * with it.
+ */
+ entry_type= factory_register_type(SLAPI_EXT_ENTRY,offsetof(Slapi_Entry,e_extension));
+ }
+ return entry_type;
+}
+
+/* ====== Slapi_Entry functions ====== */
+
+#ifdef ENTRY_DEBUG
+static void entry_dump( const Slapi_Entry *e, const char *text);
+#define ENTRY_DUMP(e,name) entry_dump(e,name)
+#else
+#define ENTRY_DUMP(e,name) ((void)0)
+#endif
+
+
+static int counters_created= 0;
+PR_DEFINE_COUNTER(slapi_entry_counter_created);
+PR_DEFINE_COUNTER(slapi_entry_counter_deleted);
+PR_DEFINE_COUNTER(slapi_entry_counter_exist);
+
+Slapi_Entry *
+slapi_entry_alloc()
+{
+ Slapi_Entry *e= (Slapi_Entry *) slapi_ch_calloc( 1, sizeof(struct slapi_entry) );
+ slapi_sdn_init(&e->e_sdn);
+ e->e_extension = factory_create_extension(get_entry_object_type(),e,NULL);
+ if(!counters_created)
+ {
+ PR_CREATE_COUNTER(slapi_entry_counter_created,"Slapi_Entry","created","");
+ PR_CREATE_COUNTER(slapi_entry_counter_deleted,"Slapi_Entry","deleted","");
+ PR_CREATE_COUNTER(slapi_entry_counter_exist,"Slapi_Entry","exist","");
+ counters_created= 1;
+ }
+ PR_INCREMENT_COUNTER(slapi_entry_counter_created);
+ PR_INCREMENT_COUNTER(slapi_entry_counter_exist);
+ ENTRY_DUMP(e,"slapi_entry_alloc");
+ return e;
+}
+
+/*
+ * WARNING - The DN is passed in *not* copied.
+ */
+void
+slapi_entry_init(Slapi_Entry *e, char *dn, Slapi_Attr *a)
+{
+ slapi_sdn_set_dn_passin(slapi_entry_get_sdn(e), dn);
+ e->e_uniqueid= NULL;
+ e->e_attrs= a;
+ e->e_dncsnset= NULL;
+ e->e_maxcsn= NULL;
+ e->e_deleted_attrs= NULL;
+ e->e_virtual_attrs= NULL;
+ e->e_virtual_watermark= 0;
+ e->e_virtual_lock= PR_NewRWLock(PR_RWLOCK_RANK_NONE, "vattrValueCache");
+ e->e_flags= 0;
+}
+
+void
+slapi_entry_free( Slapi_Entry *e ) /* JCM - Should be ** so that we can NULL the ptr */
+{
+ if(e!=NULL)
+ {
+ ENTRY_DUMP(e,"slapi_entry_free");
+ factory_destroy_extension(get_entry_object_type(),e,NULL/*Parent*/,&(e->e_extension));
+ slapi_sdn_done(&e->e_sdn);
+ csnset_free(&e->e_dncsnset);
+ csn_free(&e->e_maxcsn);
+ slapi_ch_free((void **)&e->e_uniqueid);
+ attrlist_free(e->e_attrs);
+ attrlist_free(e->e_deleted_attrs);
+ attrlist_free(e->e_virtual_attrs);
+ if(e->e_virtual_lock)
+ PR_DestroyRWLock(e->e_virtual_lock);
+ slapi_ch_free((void**)&e);
+ PR_INCREMENT_COUNTER(slapi_entry_counter_deleted);
+ PR_DECREMENT_COUNTER(slapi_entry_counter_exist);
+ }
+}
+
+static size_t slapi_attrlist_size(Slapi_Attr *attrs)
+{
+ size_t size = 0;
+ Slapi_Attr *a;
+
+ for (a= attrs; a; a = a->a_next) {
+ if (a->a_type) size += strlen(a->a_type) + 1;
+ size += valueset_size(&a->a_present_values);
+ size += valueset_size(&a->a_deleted_values);
+ /* Don't bother with a_listtofree. This is only set
+ * by a call to slapi_attr_get_values, which should
+ * never be used on a cache entry since it can cause
+ * the entry to grow without bound.
+ */
+ if (a->a_deletioncsn) size += sizeof(CSN);
+ size += sizeof(Slapi_Attr);
+ }
+
+ return size;
+}
+
+static size_t slapi_dn_size(Slapi_DN *sdn)
+{
+ size_t size = 0;
+
+ if (sdn == NULL) return 0;
+
+ if (sdn->dn) size += strlen(sdn->dn) + 1;
+ if (sdn->ndn) size *= 2;
+
+ return size;
+}
+
+/* return the approximate size of an entry --
+ * useful for checking cache sizes, etc
+ */
+size_t
+slapi_entry_size(Slapi_Entry *e)
+{
+ u_long size = 0;
+
+ /* doesn't include memory used by e_extension */
+
+ if (e->e_uniqueid) size += strlen(e->e_uniqueid) + 1;
+ if (e->e_dncsnset) size += csnset_size(e->e_dncsnset);
+ if (e->e_maxcsn) size += sizeof( CSN );
+ size += slapi_dn_size(&e->e_sdn);
+ size += slapi_attrlist_size(e->e_attrs);
+ if (e->e_deleted_attrs) size += slapi_attrlist_size(e->e_deleted_attrs);
+ if (e->e_virtual_attrs) size += slapi_attrlist_size(e->e_virtual_attrs);
+ size += sizeof(Slapi_Entry);
+
+ return size;
+}
+
+
+/*
+ * return a complete copy of entry pointed to by "e"
+ * LPXXX: entry extensions are not duplicated
+ */
+Slapi_Entry *
+slapi_entry_dup( const Slapi_Entry *e )
+{
+ Slapi_Entry *ec;
+ Slapi_Attr *a;
+ Slapi_Attr *lastattr= NULL;
+
+ PR_ASSERT( NULL != e );
+
+ ec = slapi_entry_alloc();
+
+ /*
+ * init the new entry--some things (eg. locks in the entry) are not dup'ed
+ */
+ slapi_entry_init(ec,NULL,NULL);
+
+ slapi_sdn_copy(slapi_entry_get_sdn_const(e),&ec->e_sdn);
+
+ /* duplicate the dncsn also */
+ ec->e_dncsnset= csnset_dup(e->e_dncsnset);
+ ec->e_maxcsn= csn_dup(e->e_maxcsn);
+
+ /* don't use slapi_entry_set_uniqueid here because
+ it will cause uniqueid to be added twice to the
+ attribute list
+ */
+ if ( e->e_uniqueid != NULL )
+ {
+ ec->e_uniqueid = slapi_ch_strdup( e->e_uniqueid ); /* JCM - UniqueID Dup function? */
+ }
+
+ for ( a = e->e_attrs; a != NULL; a = a->a_next )
+ {
+ Slapi_Attr *newattr= slapi_attr_dup(a);
+ if(lastattr==NULL)
+ {
+ ec->e_attrs= newattr;
+ }
+ else
+ {
+ lastattr->a_next= newattr;
+ }
+ lastattr= newattr;
+ }
+ lastattr= NULL;
+ for ( a = e->e_deleted_attrs; a != NULL; a = a->a_next )
+ {
+ Slapi_Attr *newattr= slapi_attr_dup(a);
+ if(lastattr==NULL)
+ {
+ ec->e_deleted_attrs= newattr;
+ }
+ else
+ {
+ lastattr->a_next= newattr;
+ }
+ lastattr= newattr;
+ }
+
+ /* Copy flags as well */
+ ec->e_flags = e->e_flags;
+
+ ENTRY_DUMP(ec,"slapi_entry_dup");
+ return( ec );
+}
+
+#ifdef ENTRY_DEBUG
+static void
+entry_dump( const Slapi_Entry *e, const char *text)
+{
+ const char *dn= slapi_entry_get_dn_const(e);
+ LDAPDebug( LDAP_DEBUG_ANY, "Entry %s ptr=%lx dn=%s\n", text, e, (dn==NULL?"NULL":dn));
+}
+#endif
+
+char *
+slapi_entry_get_dn( Slapi_Entry *e )
+{
+ /* jcm - This is evil... we have to cast away the const. */
+ return (char*)(slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)));
+}
+char *
+slapi_entry_get_ndn( Slapi_Entry *e )
+{
+ /* jcm - This is evil... we have to cast away the const. */
+ return (char*)(slapi_sdn_get_ndn(slapi_entry_get_sdn_const(e)));
+}
+
+const Slapi_DN *
+slapi_entry_get_sdn_const( const Slapi_Entry *e )
+{
+ return &e->e_sdn;
+}
+
+Slapi_DN *
+slapi_entry_get_sdn( Slapi_Entry *e )
+{
+ return &e->e_sdn;
+}
+
+const char *
+slapi_entry_get_dn_const( const Slapi_Entry *e )
+{
+ return (slapi_sdn_get_dn(slapi_entry_get_sdn_const(e)));
+}
+
+/*
+ * WARNING - The DN is passed in *not* copied.
+ */
+void
+slapi_entry_set_dn( Slapi_Entry *e, char *dn )
+{
+ slapi_sdn_set_dn_passin(slapi_entry_get_sdn(e),dn);
+}
+
+void
+slapi_entry_set_sdn( Slapi_Entry *e, const Slapi_DN *sdn )
+{
+ slapi_sdn_copy(sdn,slapi_entry_get_sdn(e));
+}
+
+const char *
+slapi_entry_get_uniqueid( const Slapi_Entry *e )
+{
+ return( e->e_uniqueid );
+}
+
+/*
+ * WARNING - The UniqueID is passed in *not* copied.
+ */
+void
+slapi_entry_set_uniqueid( Slapi_Entry *e, char *uniqueid )
+{
+ e->e_uniqueid = uniqueid;
+
+ /* also add it to the list of attributes - it makes things easier */
+ slapi_entry_attr_set_charptr ( e, SLAPI_ATTR_UNIQUEID, uniqueid );
+}
+
+int
+slapi_entry_first_attr( const Slapi_Entry *e, Slapi_Attr **a )
+{
+ return slapi_entry_next_attr( e, NULL, a);
+}
+
+int
+slapi_entry_next_attr( const Slapi_Entry *e, Slapi_Attr *prevattr, Slapi_Attr **a )
+{
+ int done= 0;
+ /*
+ * We skip over any attributes that have no present values.
+ * Our state information storage scheme can cause this, since
+ * we have to hang onto the deleted value state information.
+ * <jcm - actually we don't do this any more... so this skipping
+ * may now be redundant.>
+ */
+ while(!done)
+ {
+ if(prevattr==NULL)
+ {
+ *a = e->e_attrs;
+ }
+ else
+ {
+ *a = prevattr->a_next;
+ }
+ if(*a!=NULL)
+ {
+ done= !valueset_isempty(&((*a)->a_present_values));
+ }
+ else
+ {
+ done= 1;
+ }
+ if(!done)
+ {
+ prevattr= *a;
+ }
+ }
+ return( *a ? 0 : -1 );
+}
+
+int
+slapi_entry_attr_find( const Slapi_Entry *e, const char *type, Slapi_Attr **a )
+{
+ int r= -1;
+ *a = attrlist_find( e->e_attrs, type );
+ if (*a != NULL)
+ {
+ if(valueset_isempty(&((*a)->a_present_values)))
+ {
+ /*
+ * We ignore attributes that have no present values.
+ * Our state information storage scheme can cause this, since
+ * we have to hang onto the deleted value state information.
+ */
+ *a= NULL;
+ }
+ else
+ {
+ r= 0;
+ }
+ }
+ return r;
+}
+
+/* the following functions control virtual attribute cache invalidation */
+
+static PRInt32 g_virtual_watermark = -1; /* good enough to init */
+
+int slapi_entry_vattrcache_watermark_isvalid(const Slapi_Entry *e)
+{
+ return e->e_virtual_watermark == g_virtual_watermark;
+}
+
+void slapi_entry_vattrcache_watermark_set(Slapi_Entry *e)
+{
+ e->e_virtual_watermark = g_virtual_watermark;
+}
+
+void slapi_entry_vattrcache_watermark_invalidate(Slapi_Entry *e)
+{
+ e->e_virtual_watermark = 0;
+}
+
+void slapi_entrycache_vattrcache_watermark_invalidate()
+{
+ PR_AtomicIncrement(&g_virtual_watermark);
+ if (g_virtual_watermark == 0) {
+ PR_AtomicIncrement(&g_virtual_watermark);
+ }
+}
+
+/*
+ * slapi_entry_vattrcache_findAndTest()
+ *
+ * returns:
+ * SLAPI_ENTRY_VATTR_NOT_RESOLVED--not found in vattrcache; *rc set to -1.
+ * SLAPI_ENTRY_VATTR_RESOLVED_ABSENT--present in vattrcache but empty value:
+ * means tjhat vattr type is not present in
+ * that entry.
+ * SLAPI_ENTRY_VATTR_RESOLVED_EXISTS--found vattr in the cache, in which
+ * case *rc contains the result of testing
+ * the filter f of type filter_type
+ * on the value of type in e.
+ * rc==-1=>not a filter match
+ * rc==0=>a filter match
+ * rc>0=>an LDAP error code.
+ */
+
+int
+slapi_entry_vattrcache_findAndTest( const Slapi_Entry *e, const char *type,
+ Slapi_Filter *f,
+ filter_type_t filter_type,
+ int *rc )
+{
+ Slapi_Attr *tmp_attr = NULL;
+
+ int r= SLAPI_ENTRY_VATTR_NOT_RESOLVED; /* assume not resolved yet */
+ *rc = -1;
+
+ if( slapi_vattrcache_iscacheable(type) &&
+ slapi_entry_vattrcache_watermark_isvalid(e) && e->e_virtual_attrs)
+ {
+
+ if(e->e_virtual_lock == NULL) {
+ return r;
+ }
+
+ vattrcache_entry_READ_LOCK(e);
+ tmp_attr = attrlist_find( e->e_virtual_attrs, type );
+ if (tmp_attr != NULL)
+ {
+ if(valueset_isempty(&(tmp_attr->a_present_values)))
+ {
+ /*
+ * this is a vattr that has been
+ * cached already but does not exist
+ */
+ r= SLAPI_ENTRY_VATTR_RESOLVED_ABSENT; /* hard coded for prototype */
+ }
+ else
+ {
+ /*
+ * this is a cached vattr--test the filter on it.
+ *
+ */
+ r= SLAPI_ENTRY_VATTR_RESOLVED_EXISTS;
+ if ( filter_type == FILTER_TYPE_AVA ) {
+ *rc = plugin_call_syntax_filter_ava( tmp_attr,
+ f->f_choice,
+ &f->f_ava );
+ } else if ( filter_type == FILTER_TYPE_SUBSTRING) {
+ *rc = plugin_call_syntax_filter_sub( tmp_attr,
+ &f->f_sub);
+ } else if ( filter_type == FILTER_TYPE_PRES ) {
+ /* type is there, that's all we need to know. */
+ *rc = 0;
+ }
+ }
+ }
+ vattrcache_entry_READ_UNLOCK(e);
+ }
+
+ return r;
+}
+
+/*
+ * slapi_entry_vattrcache_find_values_and_type_ex()
+ *
+ * returns:
+ * SLAPI_ENTRY_VATTR_NOT_RESOLVED--not found in vattrcache.
+ * SLAPI_ENTRY_VATTR_RESOLVED_ABSENT--found in vattrcache but empty value
+ * ==>that vattr type is not present in the
+ * entry.
+ * SLAPI_ENTRY_VATTR_RESOLVED_EXISTS--found vattr in the vattr cache,
+ * in which case **results is a
+ * pointer to a duped Slapi_Valueset
+ * containing the values of type and
+ * **actual_type_name is the actual type
+ * name.
+*/
+
+int
+slapi_entry_vattrcache_find_values_and_type_ex( const Slapi_Entry *e,
+ const char *type,
+ Slapi_ValueSet ***results,
+ char ***actual_type_name)
+{
+ Slapi_Attr *tmp_attr = NULL;
+
+ int r= SLAPI_ENTRY_VATTR_NOT_RESOLVED; /* assume not resolved yet */
+
+ if( slapi_vattrcache_iscacheable(type) &&
+ slapi_entry_vattrcache_watermark_isvalid(e) && e->e_virtual_attrs)
+ {
+
+ if(e->e_virtual_lock == NULL) {
+ return r;
+ }
+
+ vattrcache_entry_READ_LOCK(e);
+ tmp_attr = attrlist_find( e->e_virtual_attrs, type );
+ if (tmp_attr != NULL)
+ {
+ if(valueset_isempty(&(tmp_attr->a_present_values)))
+ {
+ /*
+ * this is a vattr that has been
+ * cached already but does not exist
+ */
+ r= SLAPI_ENTRY_VATTR_RESOLVED_ABSENT; /* hard coded for prototype */
+ }
+ else
+ {
+ /*
+ * this is a cached vattr
+ * return a duped copy of the values and type
+ */
+ char *vattr_type=NULL;
+
+ r= SLAPI_ENTRY_VATTR_RESOLVED_EXISTS;
+ *results = (Slapi_ValueSet**)slapi_ch_calloc(1, sizeof(*results));
+ **results = valueset_dup(&(tmp_attr->a_present_values));
+
+ *actual_type_name =
+ (char**)slapi_ch_malloc(sizeof(*actual_type_name));
+ slapi_attr_get_type( tmp_attr, &vattr_type );
+ **actual_type_name = strdup(vattr_type);
+
+ }
+ }
+ vattrcache_entry_READ_UNLOCK(e);
+ }
+
+ return r;
+}
+
+/*
+ * Deprecated in favour of slapi_entry_vattrcache_find_values_and_type_ex()
+ * which meshes better with slapi_vattr_values_get_sp_ex().
+*/
+SLAPI_DEPRECATED int
+slapi_entry_vattrcache_find_values_and_type( const Slapi_Entry *e,
+ const char *type,
+ Slapi_ValueSet **results,
+ char **actual_type_name)
+{
+ Slapi_Attr *tmp_attr = NULL;
+
+ int r= SLAPI_ENTRY_VATTR_NOT_RESOLVED; /* assume not resolved yet */
+
+ if( slapi_vattrcache_iscacheable(type) &&
+ slapi_entry_vattrcache_watermark_isvalid(e) && e->e_virtual_attrs)
+ {
+
+ if(e->e_virtual_lock == NULL) {
+ return r;
+ }
+
+ vattrcache_entry_READ_LOCK(e);
+ tmp_attr = attrlist_find( e->e_virtual_attrs, type );
+ if (tmp_attr != NULL)
+ {
+ if(valueset_isempty(&(tmp_attr->a_present_values)))
+ {
+ /*
+ * this is a vattr that has been
+ * cached already but does not exist
+ */
+ r= SLAPI_ENTRY_VATTR_RESOLVED_ABSENT; /* hard coded for prototype */
+ }
+ else
+ {
+ /*
+ * this is a cached vattr
+ * return a duped copy of the values and type
+ */
+ char *vattr_type=NULL;
+
+ r= SLAPI_ENTRY_VATTR_RESOLVED_EXISTS;
+ *results = valueset_dup(&(tmp_attr->a_present_values));
+
+ slapi_attr_get_type( tmp_attr, &vattr_type );
+ *actual_type_name = strdup(vattr_type);
+
+ }
+ }
+ vattrcache_entry_READ_UNLOCK(e);
+ }
+
+ return r;
+}
+
+SLAPI_DEPRECATED int
+slapi_entry_attr_merge( Slapi_Entry *e, const char *type, struct berval **vals )
+{
+ Slapi_Value **values= NULL;
+ int rc=0;
+ valuearray_init_bervalarray(vals,&values); /* JCM SLOW FUNCTION */
+ rc = slapi_entry_attr_merge_sv(e, type, values);
+ valuearray_free(&values);
+ return(rc);
+}
+
+int
+slapi_entry_attr_merge_sv(Slapi_Entry *e, const char *type, Slapi_Value **vals )
+{
+ attrlist_merge_valuearray( &e->e_attrs, type, vals );
+ return 0;
+}
+
+/*
+ * Merge this valuset for type into e's vattrcache list.
+ * Creates the type if necessary.
+ * Dups valset.
+ * Only merge's in cacheable vattrs.
+*/
+
+int
+slapi_entry_vattrcache_merge_sv(Slapi_Entry *e, const char *type,
+ Slapi_ValueSet *valset)
+{
+ Slapi_Value **vals = NULL;
+
+ /* only attempt to merge if it's a cacheable attribute */
+ if ( slapi_vattrcache_iscacheable(type) ) {
+
+ if(e->e_virtual_lock == NULL) {
+ return 0;
+ }
+
+ vattrcache_entry_WRITE_LOCK(e);
+
+ if(!slapi_entry_vattrcache_watermark_isvalid(e) && e->e_virtual_attrs)
+ {
+ attrlist_free(e->e_virtual_attrs);
+ e->e_virtual_attrs = NULL;
+ }
+
+ if(valset)
+ vals = valueset_get_valuearray(valset);
+
+ /* dups the type (if necessary) and vals */
+ attrlist_merge_valuearray( &e->e_virtual_attrs, type, vals);
+ slapi_entry_vattrcache_watermark_set(e);
+
+ vattrcache_entry_WRITE_UNLOCK(e);
+
+ }
+
+ return 0;
+}
+
+int
+slapi_entry_attr_delete( Slapi_Entry *e, const char *type )
+{
+ return( attrlist_delete(&e->e_attrs, type) );
+}
+
+SLAPI_DEPRECATED int
+slapi_entry_attr_replace( Slapi_Entry *e, const char *type, struct berval **vals )
+{
+ slapi_entry_attr_delete(e, type);
+ slapi_entry_attr_merge(e, type, vals);
+ return 0;
+}
+
+int
+slapi_entry_attr_replace_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals )
+{
+ slapi_entry_attr_delete(e, type);
+ slapi_entry_attr_merge_sv(e, type, vals);
+ return 0;
+}
+
+int
+slapi_entry_add_value (Slapi_Entry *e, const char *type, const Slapi_Value *value)
+{
+ Slapi_Attr **a= NULL;
+ attrlist_find_or_create(&e->e_attrs, type, &a);
+ if(value != (Slapi_Value *) NULL) {
+ slapi_valueset_add_value ( &(*a)->a_present_values, value);
+ }
+ return 0;
+}
+
+
+int
+slapi_entry_add_string(Slapi_Entry *e, const char *type, const char *value)
+{
+ Slapi_Attr **a= NULL;
+ attrlist_find_or_create(&e->e_attrs, type, &a);
+ valueset_add_string ( &(*a)->a_present_values, value, CSN_TYPE_UNKNOWN, NULL);
+ return 0;
+}
+
+int
+slapi_entry_delete_string(Slapi_Entry *e, const char *type, const char *value)
+{
+ Slapi_Attr *a= attrlist_find(e->e_attrs, type);
+ if (a != NULL)
+ valueset_remove_string(a,&a->a_present_values, value);
+ return 0;
+}
+
+/* caller must free with slapi_ch_array_free */
+char **
+slapi_entry_attr_get_charray( const Slapi_Entry* e, const char *type)
+{
+ char **parray = NULL;
+ Slapi_Attr* attr = NULL;
+ slapi_entry_attr_find(e, type, &attr);
+ if(attr!=NULL)
+ {
+ int hint;
+ Slapi_Value *v = NULL;
+ for (hint = slapi_attr_first_value(attr, &v);
+ hint != -1;
+ hint = slapi_attr_next_value(attr, hint, &v))
+ {
+ const struct berval *bvp = slapi_value_get_berval(v);
+ char *p = slapi_ch_malloc(bvp->bv_len + 1);
+ memcpy(p, bvp->bv_val, bvp->bv_len);
+ p[bvp->bv_len]= '\0';
+ charray_add(&parray, p);
+ }
+ }
+ return parray;
+}
+
+char *
+slapi_entry_attr_get_charptr( const Slapi_Entry* e, const char *type)
+{
+ char *p= NULL;
+ Slapi_Attr* attr;
+ slapi_entry_attr_find(e, type, &attr);
+ if(attr!=NULL)
+ {
+ Slapi_Value *v;
+ const struct berval *bvp;
+ slapi_valueset_first_value( &attr->a_present_values, &v);
+ bvp = slapi_value_get_berval(v);
+ p= slapi_ch_malloc(bvp->bv_len + 1);
+ memcpy(p, bvp->bv_val, bvp->bv_len);
+ p[bvp->bv_len]= '\0';
+ }
+ return p;
+}
+
+int
+slapi_entry_attr_get_int( const Slapi_Entry* e, const char *type)
+{
+ int r= 0;
+ Slapi_Attr* attr;
+ slapi_entry_attr_find(e, type, &attr);
+ if (attr!=NULL)
+ {
+ Slapi_Value *v;
+ slapi_valueset_first_value( &attr->a_present_values, &v);
+ r= slapi_value_get_int(v);
+ }
+ return r;
+}
+
+unsigned int
+slapi_entry_attr_get_uint( const Slapi_Entry* e, const char *type)
+{
+ unsigned int r= 0;
+ Slapi_Attr* attr;
+ slapi_entry_attr_find(e, type, &attr);
+ if (attr!=NULL)
+ {
+ Slapi_Value *v;
+ slapi_valueset_first_value( &attr->a_present_values, &v);
+ r= slapi_value_get_uint(v);
+ }
+ return r;
+}
+
+long
+slapi_entry_attr_get_long( const Slapi_Entry* e, const char *type)
+{
+ long r = 0;
+ Slapi_Attr* attr;
+ slapi_entry_attr_find(e, type, &attr);
+ if (attr!=NULL)
+ {
+ Slapi_Value *v;
+ slapi_valueset_first_value( &attr->a_present_values, &v);
+ r = slapi_value_get_long(v);
+ }
+ return r;
+}
+
+unsigned long
+slapi_entry_attr_get_ulong( const Slapi_Entry* e, const char *type)
+{
+ unsigned long r = 0;
+ Slapi_Attr* attr;
+ slapi_entry_attr_find(e, type, &attr);
+ if (attr!=NULL)
+ {
+ Slapi_Value *v;
+ slapi_valueset_first_value( &attr->a_present_values, &v);
+ r = slapi_value_get_ulong(v);
+ }
+ return r;
+}
+
+void
+slapi_entry_attr_set_charptr( Slapi_Entry* e, const char *type, const char *value)
+{
+ struct berval bv;
+ struct berval *bvals[2];
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+ bv.bv_val = (char*)value;
+ bv.bv_len = strlen( value );
+ slapi_entry_attr_replace( e, type, bvals );
+}
+
+void
+slapi_entry_attr_set_int( Slapi_Entry* e, const char *type, int l)
+{
+ char value[16];
+ struct berval bv;
+ struct berval *bvals[2];
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+ sprintf(value,"%d",l);
+ bv.bv_val = value;
+ bv.bv_len = strlen( value );
+ slapi_entry_attr_replace( e, type, bvals );
+}
+
+void
+slapi_entry_attr_set_uint( Slapi_Entry* e, const char *type, unsigned int l)
+{
+ char value[16];
+ struct berval bv;
+ struct berval *bvals[2];
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+ sprintf(value,"%u",l);
+ bv.bv_val = value;
+ bv.bv_len = strlen( value );
+ slapi_entry_attr_replace( e, type, bvals );
+}
+
+void
+slapi_entry_attr_set_long( Slapi_Entry* e, const char *type, long l)
+{
+ char value[16];
+ struct berval bv;
+ struct berval *bvals[2];
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+ sprintf(value,"%ld",l);
+ bv.bv_val = value;
+ bv.bv_len = strlen( value );
+ slapi_entry_attr_replace( e, type, bvals );
+}
+
+void
+slapi_entry_attr_set_ulong( Slapi_Entry* e, const char *type, unsigned long l)
+{
+ char value[16];
+ struct berval bv;
+ struct berval *bvals[2];
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+ sprintf(value,"%lu",l);
+ bv.bv_val = value;
+ bv.bv_len = strlen( value );
+ slapi_entry_attr_replace( e, type, bvals );
+}
+
+/* JCM: The strcasecmp below should really be a bervalcmp
+ * deprecatred in favour of slapi_entry_attr_has_syntax_value
+ * which does respect the syntax of the attribute type.
+*/
+
+SLAPI_DEPRECATED int
+slapi_entry_attr_hasvalue(const Slapi_Entry *e, const char *type, const char *value) /* JCM - (const char *) => (struct berval *) */
+{
+ int r= 0;
+ Slapi_Attr *attr;
+ Slapi_Value *sval;
+ if(slapi_entry_attr_find(e, type, &attr)==0)
+ {
+ int i= slapi_attr_first_value( attr, &sval );
+ while(!r && i!=-1)
+ {
+ const struct berval *val= slapi_value_get_berval(sval);
+ r= (strcasecmp(val->bv_val,value)==0);
+ i= slapi_attr_next_value( attr, i, &sval );
+ }
+ }
+ return r;
+}
+
+
+/*
+ * Checks if e contains an attr type with a value
+ * of value.
+ * Unlike slapi_entry_attr_hasvalue(), it does teh comparison
+ * respecting the syntax of type.
+ *
+ * returns non-zero if type has value in e, zero otherwise.
+ *
+ *
+*/
+
+int
+slapi_entry_attr_has_syntax_value(const Slapi_Entry *e,
+ const char *type,
+ const Slapi_Value *value)
+{
+ int r= 0;
+ Slapi_Attr *attr;
+
+ if(slapi_entry_attr_find(e, type, &attr)==0)
+ {
+ const struct berval *bv = slapi_value_get_berval(value);
+
+ if ( bv != NULL) {
+ r = (slapi_attr_value_find(attr, bv) == 0);
+ }
+
+ }
+
+ return r;
+}
+
+
+int
+slapi_entry_rdn_values_present( const Slapi_Entry *e )
+{
+ char **dns, **rdns;
+ int i, rc;
+ Slapi_Attr *attr;
+ struct ava ava;
+ const char *dn = slapi_entry_get_dn_const(e);
+
+ if (slapi_is_rootdse(dn))
+ return 1; /* the root dse has no RDN, so it should default to TRUE */
+
+ /* JCM Use the Slapi_RDN code */
+ rc = 1;
+ if ( (dns = ldap_explode_dn( slapi_entry_get_dn_const(e), 0 )) != NULL )
+ {
+ if ( (rdns = ldap_explode_rdn( dns[0], 0 )) != NULL )
+ {
+ for ( i = 0; rdns[i] != NULL; i++ )
+ {
+ if ( rdn2ava( rdns[i], &ava ) == 0 )
+ {
+ char *type = slapi_attr_syntax_normalize( ava.ava_type );
+ if ( slapi_entry_attr_find( e, type, &attr ) != 0 )
+ {
+ rc = 0;
+ }
+
+ slapi_ch_free((void **)&type);
+
+ if ( 0 == rc ) { /* attribute not found */
+ break;
+ }
+
+ if ( slapi_attr_value_find( attr, &(ava.ava_value) ) != 0 )
+ {
+ rc = 0;
+ break; /* value not found */
+ }
+ }
+ }
+ ldap_value_free( rdns );
+ } else {
+ rc = 0; /* Failure: the RDN seems invalid */
+ }
+
+ ldap_value_free( dns );
+ }
+ else
+ {
+ rc = 0; /* failure: the RDN seems to be invalid */
+ }
+
+ return( rc );
+}
+
+int
+slapi_entry_add_rdn_values( Slapi_Entry *e )
+{
+ const char *dn;
+ char **dns, **rdns;
+ int i, rc = LDAP_SUCCESS;
+ Slapi_Value *foundVal;
+ Slapi_Attr *attr;
+
+ if ( NULL == e || (dn = slapi_entry_get_dn_const(e))==NULL ) {
+ return( LDAP_SUCCESS );
+ }
+
+ if (slapi_is_rootdse(dn)) {
+ return( LDAP_SUCCESS );
+ }
+
+ /* JCM Use the Slapi_RDN code */
+ /* make sure RDN values are also in the entry */
+ if ( (dns = ldap_explode_dn( dn, 0 )) == NULL ) {
+ return( LDAP_INVALID_DN_SYNTAX );
+ }
+ if ( (rdns = ldap_explode_rdn( dns[0], 0 )) == NULL ) {
+ ldap_value_free( dns );
+ return( LDAP_INVALID_DN_SYNTAX );
+ }
+ ldap_value_free( dns );
+ for ( i = 0; rdns[i] != NULL && rc == LDAP_SUCCESS; i++ ) {
+ struct ava ava;
+ char *type;
+
+ if ( rdn2ava( rdns[i], &ava ) != 0 ) {
+ ldap_value_free( rdns );
+ return( LDAP_INVALID_DN_SYNTAX );
+ }
+
+ foundVal = NULL;
+
+ type = slapi_attr_syntax_normalize( ava.ava_type );
+
+ if ( slapi_entry_attr_find( e, type, &attr ) == 0 ) {
+ rc = plugin_call_syntax_filter_ava_sv(attr, LDAP_FILTER_EQUALITY,
+ &ava, &foundVal, 0);
+
+ if (rc == 0 && foundVal != NULL) {
+ const struct berval *bv = slapi_value_get_berval(foundVal);
+
+ /*
+ * A subtlety to consider is that LDAP does not
+ * allow two values which compare the same for
+ * equality in an attribute at once.
+ */
+
+ if ((ava.ava_value.bv_len != bv->bv_len) ||
+ (memcmp(ava.ava_value.bv_val, bv->bv_val, bv->bv_len) != 0)) {
+ /* bytes not identical so reject */
+ char avdbuf[BUFSIZ];
+ LDAPDebug(LDAP_DEBUG_TRACE, "RDN value is not identical to entry value for type %s in entry %s\n",
+ type, dn ? escape_string(dn,avdbuf) : "<null>", 0 );
+#if 0
+ /*
+ * This would be the right thing to do except that
+ * it breaks our own clients.
+ */
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+#endif
+ }
+ /* exact same ava already present in entry, that's OK */
+ }
+ }
+
+ if (foundVal == NULL) {
+ struct berval *vals[2];
+
+ vals[0] = &ava.ava_value;
+ vals[1] = NULL;
+ rc = slapi_entry_add_values( e, type, vals );
+ }
+
+ slapi_ch_free( (void **)&type );
+ }
+ ldap_value_free( rdns );
+
+ return( rc );
+}
+
+/*
+ * Function: slapi_entry_has_children
+ *
+ * Returns: 0 if "p" has no children, 1 if "p" has children.
+ *
+ * Description: We (RJP+DB) modified this code to take advantage
+ * of the subordinatecount operational attribute that
+ * each entry now has.
+ *
+ * Author/Modifier: RJP
+ */
+int
+slapi_entry_has_children(const Slapi_Entry *entry)
+{
+ Slapi_Attr *attr;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> slapi_has_children( %s )\n", slapi_entry_get_dn_const(entry), 0, 0);
+
+ /*If the subordinatecount exists, and it's nonzero, then return 1.*/
+ if (slapi_entry_attr_find( entry, "numsubordinates", &attr) == 0)
+ {
+ Slapi_Value *sval;
+ slapi_attr_first_value( attr, &sval );
+ if(sval!=NULL)
+ {
+ const struct berval *bval = slapi_value_get_berval( sval );
+ if(bval!=NULL)
+ {
+ /* The entry has the attribute, and it's non-zero */
+ if (strcmp(bval->bv_val, "0") != 0)
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= slapi_has_children 1\n", 0, 0, 0 );
+ return(1);
+ }
+ }
+ }
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= slapi_has_children 0\n", 0, 0, 0 );
+ return(0);
+}
+
+/*
+ * Apply a set of modifications to an entry
+ */
+int
+entry_apply_mods( Slapi_Entry *e, LDAPMod **mods )
+{
+ int err, j;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> entry_apply_mods\n", 0, 0, 0 );
+
+ err = LDAP_SUCCESS;
+ for ( j = 0; mods[j] != NULL; j++ )
+ {
+ err= entry_apply_mod( e, mods[j] );
+ if ( err != LDAP_SUCCESS ) {
+ break;
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= entry_apply_mods %d\n", err, 0, 0 );
+ return( err );
+}
+
+/*
+ * Apply a modification to an entry
+ */
+int
+entry_apply_mod( Slapi_Entry *e, const LDAPMod *mod )
+{
+ int i;
+ int err = LDAP_SUCCESS;
+ PRBool sawsubentry=PR_FALSE;
+
+ for ( i = 0; mod->mod_bvalues != NULL && mod->mod_bvalues[i] != NULL; i++ ) {
+ if((strcasecmp(mod->mod_type,"objectclass") == 0)
+ && (strncasecmp((const char *)mod->mod_bvalues[i]->bv_val,"ldapsubentry",mod->mod_bvalues[i]->bv_len) == 0))
+ sawsubentry=PR_TRUE;
+ LDAPDebug( LDAP_DEBUG_ARGS, " %s: %s\n", mod->mod_type, mod->mod_bvalues[i]->bv_val, 0 );
+ }
+
+ switch ( mod->mod_op & ~LDAP_MOD_BVALUES )
+ {
+ case LDAP_MOD_ADD:
+ LDAPDebug( LDAP_DEBUG_ARGS, " add: %s\n", mod->mod_type, 0, 0 );
+ if(sawsubentry) e->e_flags |= SLAPI_ENTRY_LDAPSUBENTRY;
+ err = slapi_entry_add_values( e, mod->mod_type, mod->mod_bvalues );
+ break;
+
+ case LDAP_MOD_DELETE:
+ LDAPDebug( LDAP_DEBUG_ARGS, " delete: %s\n", mod->mod_type, 0, 0 );
+ if(sawsubentry) e->e_flags |= 0;
+ err = slapi_entry_delete_values( e, mod->mod_type, mod->mod_bvalues );
+ break;
+
+ case LDAP_MOD_REPLACE:
+ LDAPDebug( LDAP_DEBUG_ARGS, " replace: %s\n", mod->mod_type, 0, 0 );
+ err = entry_replace_values( e, mod->mod_type, mod->mod_bvalues );
+ break;
+ }
+ LDAPDebug( LDAP_DEBUG_ARGS, " -\n", 0, 0, 0 );
+
+ return( err );
+}
+
+
+/*
+ * Add an array of "vals" to entry "e".
+ */
+SLAPI_DEPRECATED int
+slapi_entry_add_values(
+ Slapi_Entry *e,
+ const char *type,
+ struct berval **vals
+)
+{
+ Slapi_Value **values= NULL;
+ int rc=0;
+ valuearray_init_bervalarray(vals,&values); /* JCM SLOW FUNCTION */
+ rc=slapi_entry_add_values_sv(e,type,values);
+ valuearray_free(&values);
+ return(rc);
+}
+
+/*
+ * Add an array of "vals" to entry "e".
+ */
+int
+slapi_entry_add_values_sv(Slapi_Entry *e,
+ const char *type,
+ Slapi_Value **vals)
+{
+ int rc= LDAP_SUCCESS;
+ if (valuearray_isempty(vals))
+ {
+ /*
+ * No values to add (unexpected but acceptable).
+ */
+ }
+ else
+ {
+ Slapi_Attr **a= NULL;
+ Slapi_Attr **alist= &e->e_attrs;
+ attrlist_find_or_create(alist, type, &a);
+ rc= attr_add_valuearray(*a,vals,slapi_entry_get_dn_const(e));
+ }
+ return( rc );
+}
+
+/*
+ * Add a value set of "vs" to entry "e".
+ *
+ * 0 is success anything else failure.
+ */
+
+int
+slapi_entry_add_valueset(Slapi_Entry *e, const char *type, Slapi_ValueSet *vs)
+{
+ Slapi_Value *v;
+
+ int i= slapi_valueset_first_value(vs,&v);
+ while(i!=-1) {
+
+ slapi_entry_add_value( e, type, v);
+ i= slapi_valueset_next_value(vs,i,&v);
+ }/* while */
+
+ return(0);
+}
+
+
+/*
+ * Delete an array of bervals from entry.
+ *
+ * Note that if this function fails, it leaves the values for "type" within
+ * "e" in an indeterminate state. The present value set may be truncated.
+ */
+SLAPI_DEPRECATED int
+slapi_entry_delete_values(
+ Slapi_Entry *e,
+ const char *type,
+ struct berval **vals
+)
+{
+ Slapi_Value **values= NULL;
+ int rc=0;
+ valuearray_init_bervalarray(vals,&values); /* JCM SLOW FUNCTION */
+ rc=slapi_entry_delete_values_sv(e,type,values);
+ valuearray_free(&values);
+ return(rc);
+}
+
+
+static int
+delete_values_sv_internal(
+ Slapi_Entry *e,
+ const char *type,
+ Slapi_Value **valuestodelete,
+ int flags
+)
+{
+ Slapi_Attr *a;
+ int retVal= LDAP_SUCCESS;
+
+ /* delete the entire attribute */
+ if ( valuestodelete == NULL || valuestodelete[0] == NULL ){
+ LDAPDebug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n",
+ type, 0, 0 );
+ return( attrlist_delete( &e->e_attrs, type) ?
+ LDAP_NO_SUCH_ATTRIBUTE : LDAP_SUCCESS );
+ }
+
+ /* delete specific values - find the attribute first */
+ a= attrlist_find(e->e_attrs, type);
+ if ( a == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "could not find attribute %s\n",
+ type, 0, 0 );
+ return( LDAP_NO_SUCH_ATTRIBUTE );
+ }
+
+ {
+ retVal= valueset_remove_valuearray(&a->a_present_values, a, valuestodelete, flags, NULL);
+ if(retVal==LDAP_SUCCESS)
+ {
+ /*
+ * all values have been deleted -- remove entire attribute
+ */
+ if ( valueset_isempty(&a->a_present_values) )
+ {
+ attrlist_delete( &e->e_attrs, a->a_type );
+ }
+ }
+ else
+ {
+ /* Failed
+ * - Duplicate value
+ * - Value not found
+ * - Operations error
+ */
+ if ( retVal==LDAP_OPERATIONS_ERROR )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Possible existing duplicate "
+ "value for attribute type %s found in "
+ "entry %s\n", a->a_type, slapi_entry_get_dn_const(e), 0 );
+ }
+ }
+ }
+
+ return( retVal );
+}
+
+
+/*
+ * Delete an array of present values from an entry.
+ *
+ * Note that if this function fails, it leaves the values for "type" within
+ * "e" in an indeterminate state. The present value set may be truncated.
+ */
+int
+slapi_entry_delete_values_sv(
+ Slapi_Entry *e,
+ const char *type,
+ Slapi_Value **valuestodelete
+)
+{
+ return( delete_values_sv_internal( e, type, valuestodelete,
+ 0 /* Do Not Ignore Errors */ ));
+}
+
+
+int
+entry_replace_values(
+ Slapi_Entry *e,
+ const char *type,
+ struct berval **vals
+)
+{
+ attrlist_replace( &e->e_attrs, type, vals );
+ return 0;
+}
+
+int
+slapi_entry_flag_is_set( const Slapi_Entry *e, unsigned char flag )
+{
+ return( e->e_flags & flag );
+}
+
+void slapi_entry_set_flag( Slapi_Entry *e, unsigned char flag)
+{
+ e->e_flags |= flag;
+}
+
+void slapi_entry_clear_flag( Slapi_Entry *e, unsigned char flag)
+{
+ e->e_flags &= ~flag;
+}
+
+
+/*
+ * Add the missing values in `vals' to an entry.
+ *
+ * Note that if this function fails, it leaves the values for "type" within
+ * "e" in an indeterminate state. The present value set may be truncated.
+ */
+int
+slapi_entry_merge_values_sv(
+ Slapi_Entry *e,
+ const char *type,
+ Slapi_Value **vals
+)
+{
+ int rc;
+
+ rc = delete_values_sv_internal( e, type, vals, SLAPI_VALUE_FLAG_IGNOREERROR );
+
+ if ( rc == LDAP_SUCCESS || rc == LDAP_NO_SUCH_ATTRIBUTE ) {
+ rc = slapi_entry_attr_merge_sv( e, type, vals );
+ }
+
+ return( rc );
+}
+
+void
+send_referrals_from_entry(Slapi_PBlock *pb, Slapi_Entry *referral)
+{
+ Slapi_Value *val=NULL;
+ Slapi_Attr *attr=NULL;
+ int i=0, numValues=0;
+ struct berval **refscopy=NULL;
+ struct berval **url=NULL;
+
+ slapi_entry_attr_find( referral, "ref", &attr );
+ if(attr != NULL) {
+ slapi_attr_get_numvalues(attr, &numValues );
+ if(numValues > 0) {
+ url=(struct berval **) slapi_ch_malloc((numValues + 1) * sizeof(struct berval*));
+ }
+ for (i = slapi_attr_first_value(attr, &val); i != -1;
+ i = slapi_attr_next_value(attr, i, &val)) {
+ url[i]=(struct berval*)slapi_value_get_berval(val);
+ }
+ url[numValues]=NULL;
+ }
+ refscopy = ref_adjust(pb, url, slapi_entry_get_sdn(referral), 0);
+ send_ldap_result(pb, LDAP_REFERRAL,
+ slapi_entry_get_dn(referral), NULL, 0, refscopy );
+ if(url != NULL) {
+ slapi_ch_free( (void **)&url );
+ }
+ if ( refscopy != NULL ) {
+ ber_bvecfree( refscopy );
+ }
+}
+
+/*
+ * slapi_entry_diff: perform diff between entry e1 and e2
+ * and set mods to smods which updates e1 to e2.
+ * diff_ctrl: SLAPI_DUMP_NOOPATTRS => skip operational attributes
+ */
+void
+slapi_entry_diff(Slapi_Mods *smods, Slapi_Entry *e1, Slapi_Entry *e2, int diff_ctrl)
+{
+ Slapi_Attr *e1_attr = NULL;
+ Slapi_Attr *e2_attr = NULL;
+ char *e1_attr_name = NULL;
+ char *e2_attr_name = NULL;
+ int rval = 0;
+
+ slapi_mods_init(smods, 0);
+
+ for (slapi_entry_first_attr(e1, &e1_attr); e1_attr;
+ slapi_entry_next_attr(e1, e1_attr, &e1_attr))
+ {
+ /* skip operational attributes if not requested */
+ if ((diff_ctrl & SLAPI_DUMP_NOOPATTRS) &&
+ slapi_attr_flag_is_set(e1_attr, SLAPI_ATTR_FLAG_OPATTR))
+ continue;
+
+ slapi_attr_get_type(e1_attr, &e1_attr_name);
+ rval = slapi_entry_attr_find(e2, e1_attr_name, &e2_attr);
+ if (0 == rval)
+ {
+ int i;
+ Slapi_Value *e1_val;
+ /* attr e1_attr_names is shared with e2 */
+ /* XXX: not very efficient.
+ * needs to be rewritten for the schema w/ lots of attributes
+ */
+ for (i = slapi_attr_first_value(e1_attr, &e1_val); i != -1;
+ i = slapi_attr_next_value(e1_attr, i, &e1_val))
+ {
+ if (0 != slapi_attr_value_find(e2_attr,
+ slapi_value_get_berval(e1_val)))
+ {
+ /* attr-value e1_val not found in e2_attr; replace it */
+ /* XXX: does not support multi-value here */
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "slapi_entry_diff: attr-val of %s is not in e2; "
+ "replace it\n",
+ e1_attr_name, 0, 0);
+ slapi_mods_add(smods, LDAP_MOD_REPLACE, e1_attr_name,
+ e1_val->bv.bv_len, e1_val->bv.bv_val);
+ }
+ }
+ }
+ else
+ {
+ /* attr e1_attr_names not found in e2 */
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "slapi_entry_diff: attr %s is not in e2; add it\n",
+ e1_attr_name, 0, 0);
+ slapi_mods_add_mod_values(smods, LDAP_MOD_ADD,
+ e1_attr_name,
+ attr_get_present_values(e1_attr));
+ }
+ }
+
+ for (slapi_entry_first_attr(e2, &e2_attr); e2_attr;
+ slapi_entry_next_attr(e2, e2_attr, &e2_attr)) {
+ /* skip operational attributes if not requested */
+ if ((diff_ctrl & SLAPI_DUMP_NOOPATTRS) &&
+ slapi_attr_flag_is_set(e2_attr, SLAPI_ATTR_FLAG_OPATTR))
+ continue;
+
+ slapi_attr_get_type(e2_attr, &e2_attr_name);
+ rval = slapi_entry_attr_find(e1, e2_attr_name, &e1_attr);
+ if (0 != rval)
+ {
+ /* attr e2_attr_names not in e1 */
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "slapi_entry_diff: attr %s is not in e1; delete it\n",
+ e2_attr_name, 0, 0);
+ slapi_mods_add_mod_values(smods, LDAP_MOD_DELETE, e2_attr_name, NULL);
+ }
+ }
+
+ return;
+}
+
+static int
+entry_cmp_with_dn(const void *e1, const void *e2)
+{
+ return slapi_sdn_compare(slapi_entry_get_sdn_const(*(Slapi_Entry **)e1),
+ slapi_entry_get_sdn_const(*(Slapi_Entry **)e2));
+}
+
+/* delete the entry (and sub entries if any) specified with dn */
+static void
+delete_subtree(Slapi_PBlock *pb, const char *dn, void *plg_id)
+{
+ Slapi_PBlock mypb;
+ int ret = 0;
+ int opresult;
+
+ slapi_search_internal_set_pb(pb, dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)",
+ NULL, 0, NULL, NULL, plg_id, 0);
+ slapi_search_internal_pb(pb);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret == LDAP_SUCCESS) {
+ Slapi_Entry **entries = NULL;
+ Slapi_Entry **ep = NULL;
+ Slapi_DN *rootDN = slapi_sdn_new_dn_byval(dn);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ for (ep = entries; ep && *ep; ep++) {
+ const Slapi_DN *sdn = slapi_entry_get_sdn_const(*ep);
+
+ if (slapi_sdn_compare(sdn, rootDN) == 0)
+ continue;
+ pblock_init(&mypb);
+ slapi_delete_internal_set_pb(&mypb, slapi_sdn_get_dn(sdn),
+ NULL, NULL, plg_id, 0);
+ slapi_delete_internal_pb(&mypb);
+ slapi_pblock_get(&mypb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ pblock_done(&mypb);
+ }
+ slapi_sdn_free(&rootDN);
+ }
+ pblock_done(pb);
+
+ pblock_init(pb);
+ slapi_delete_internal_set_pb(pb, dn, NULL, NULL, plg_id, 0);
+ slapi_delete_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ pblock_done(pb);
+}
+
+/*
+ * slapi_entries_diff: diff between entry array old_entries and curr_entries
+ * (testall == 0) => return immediately after the 1st diff
+ * (testall != 0) => scan all the entries
+ * (force_update == 0) => just print the diff info
+ * (force_update != 0) => force to go back to old
+ *
+ * return 0, if identical
+ * return 1, otherwise
+ */
+int
+slapi_entries_diff(Slapi_Entry **old_entries, Slapi_Entry **curr_entries,
+ int testall, const char *logging_prestr,
+ const int force_update, void *plg_id)
+{
+ char *my_logging_prestr = "";
+ Slapi_Entry **oep, **cep;
+ int rval = 0;
+ Slapi_PBlock pb;
+#ifdef ENTRY_DIFF_DEBUG
+ int i;
+#endif
+
+ for (oep = old_entries; oep != NULL && *oep != NULL; oep++)
+ ;
+
+ qsort(old_entries, oep - old_entries, sizeof(Slapi_Entry **),
+ entry_cmp_with_dn);
+
+#ifdef ENTRY_DIFF_DEBUG
+ LDAPDebug(LDAP_DEBUG_TRACE, "Old entries:\n", 0, 0, 0);
+ for (oep = old_entries, i = 0; oep != NULL && *oep != NULL; oep++, i++)
+ {
+ LDAPDebug(LDAP_DEBUG_TRACE, "%d: %s\n", i, slapi_entry_get_dn_const(*oep), 0);
+ }
+#endif
+
+ for (cep = curr_entries; cep != NULL && *cep != NULL; cep++)
+ ;
+
+ qsort(curr_entries, cep - curr_entries, sizeof(Slapi_Entry **),
+ entry_cmp_with_dn);
+
+#ifdef ENTRY_DIFF_DEBUG
+ LDAPDebug(LDAP_DEBUG_TRACE, "New entries:\n", 0, 0, 0);
+ for (cep = curr_entries, i = 0; cep != NULL && *cep != NULL; cep++, i++)
+ {
+ LDAPDebug(LDAP_DEBUG_TRACE, "%d: %s\n", i, slapi_entry_get_dn_const(*cep), 0);
+ }
+#endif
+
+ if (NULL != logging_prestr && '\0' != *logging_prestr)
+ {
+ my_logging_prestr = (char *)slapi_ch_malloc(strlen(logging_prestr) + 2);
+ sprintf(my_logging_prestr, "%s ", logging_prestr);
+ }
+
+ for (oep = old_entries; oep != NULL && *oep != NULL; )
+ {
+ for (cep = curr_entries; cep != NULL && *cep != NULL; )
+ {
+ int dncmp = slapi_sdn_compare(slapi_entry_get_sdn_const(*oep),
+ slapi_entry_get_sdn_const(*cep));
+ if (force_update)
+ {
+ pblock_init(&pb);
+ }
+
+ if (0 == dncmp)
+ {
+ Slapi_Mods *smods = slapi_mods_new();
+ LDAPMod *mod;
+ int isfirst = 1;
+
+ /* check the attr diff and do modify */
+ slapi_entry_diff(smods, *oep, *cep, SLAPI_DUMP_NOOPATTRS);
+
+ for (mod = slapi_mods_get_first_mod(smods);
+ mod != NULL;
+ mod = slapi_mods_get_next_mod(smods))
+ {
+ rval = 1;
+ if (isfirst)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "%sEntry %s\n", my_logging_prestr,
+ slapi_entry_get_dn_const(*oep), 0);
+ isfirst = 0;
+ }
+
+ switch (mod->mod_op & ~LDAP_MOD_BVALUES)
+ {
+ case LDAP_MOD_DELETE:
+ LDAPDebug(LDAP_DEBUG_ANY,
+ " Del Attribute %s Value %s\n",
+ mod->mod_type, mod->mod_bvalues?
+ mod->mod_bvalues[0]->bv_val:"N/A", 0);
+ break;
+ case LDAP_MOD_ADD:
+ LDAPDebug(LDAP_DEBUG_ANY,
+ " Add Attribute %s Value %s\n",
+ mod->mod_type, mod->mod_bvalues[0]->bv_val, 0);
+ break;
+ case LDAP_MOD_REPLACE:
+ LDAPDebug(LDAP_DEBUG_ANY,
+ " Rep Attribute %s Value %s\n",
+ mod->mod_type, mod->mod_bvalues[0]->bv_val, 0);
+ break;
+ default:
+ LDAPDebug(LDAP_DEBUG_ANY,
+ " Unknown op %d Attribute %s\n",
+ mod->mod_op & ~LDAP_MOD_BVALUES,
+ mod->mod_type, 0);
+ break;
+ }
+
+ if (!testall)
+ {
+ slapi_mods_free(&smods);
+ goto out;
+ }
+ }
+ if (0 == isfirst && force_update && testall)
+ {
+ slapi_modify_internal_set_pb(&pb,
+ slapi_entry_get_dn_const(*oep),
+ slapi_mods_get_ldapmods_byref(smods),
+ NULL, NULL, plg_id, 0);
+
+ slapi_modify_internal_pb(&pb);
+ }
+
+ slapi_mods_free(&smods);
+ oep++; cep++;
+ }
+ else if (dncmp > 0) /* old_entries does not have cep */
+ {
+ rval = 1;
+
+ LDAPDebug(LDAP_DEBUG_ANY, "Del %sEntry %s\n",
+ my_logging_prestr, slapi_entry_get_dn_const(*cep), 0);
+
+ if (testall)
+ {
+ if (force_update)
+ delete_subtree(&pb, slapi_entry_get_dn_const(*cep), plg_id);
+ }
+ else
+ {
+ goto out;
+ }
+ cep++;
+ }
+ else /* if (dncmp < 0) curr_entries does not have oep */
+ {
+ rval = 1;
+ LDAPDebug(LDAP_DEBUG_ANY, "Add %sEntry %s\n",
+ my_logging_prestr, slapi_entry_get_dn_const(*oep), 0);
+ if (testall)
+ {
+ if (force_update)
+ {
+ LDAPMod **mods;
+ slapi_entry2mods(*oep, NULL, &mods);
+ slapi_add_internal_set_pb(&pb,
+ slapi_entry_get_dn_const(*oep), mods, NULL, plg_id, 0);
+ slapi_add_internal_pb(&pb);
+ freepmods(mods);
+ }
+ }
+ else
+ {
+ goto out;
+ }
+ oep++;
+ }
+ if (force_update)
+ {
+ pblock_done(&pb);
+ }
+ }
+ }
+out:
+ if (NULL != logging_prestr && '\0' != *logging_prestr)
+ slapi_ch_free_string(&my_logging_prestr);
+
+ return rval;
+}
diff --git a/ldap/servers/slapd/entrywsi.c b/ldap/servers/slapd/entrywsi.c
new file mode 100644
index 00000000..8a39b941
--- /dev/null
+++ b/ldap/servers/slapd/entrywsi.c
@@ -0,0 +1,1151 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* entrywsi.c - routines for dealing with entries... With State Information */
+
+#include "slap.h"
+#include "slapi-plugin.h"
+
+static void resolve_attribute_state(Slapi_Entry *e, Slapi_Attr *a, int attribute_state);
+
+static int
+entry_present_value_to_deleted_value(Slapi_Attr *a, Slapi_Value *v)
+{
+ Slapi_Value *r= valueset_remove_value(a, &a->a_present_values, v);
+ if(r!=NULL)
+ {
+ slapi_valueset_add_value_ext(&a->a_deleted_values, r, SLAPI_VALUE_FLAG_PASSIN);
+ }
+ return LDAP_SUCCESS;
+}
+
+static int
+entry_present_value_to_zapped_value(Slapi_Attr *a, Slapi_Value *v)
+{
+ if(v!=NULL)
+ {
+ Slapi_Value *r= valueset_remove_value(a, &a->a_present_values, v);
+ if(r!=NULL)
+ {
+ slapi_value_free(&r);
+ }
+ }
+ return LDAP_SUCCESS;
+}
+
+static int
+entry_deleted_value_to_present_value(Slapi_Attr *a, Slapi_Value *v)
+{
+ Slapi_Value *r= valueset_remove_value(a, &a->a_deleted_values, v);
+ if(r!=NULL)
+ {
+ slapi_valueset_add_value_ext(&a->a_present_values, r, SLAPI_VALUE_FLAG_PASSIN);
+ }
+ return LDAP_SUCCESS;
+}
+
+static int
+entry_deleted_value_to_zapped_value(Slapi_Attr *a, Slapi_Value *v)
+{
+ if(v!=NULL)
+ {
+ Slapi_Value *r= valueset_remove_value(a, &a->a_deleted_values, v);
+ if(r!=NULL)
+ {
+ slapi_value_free(&r);
+ }
+ }
+ return LDAP_SUCCESS;
+}
+
+static int
+entry_present_attribute_to_deleted_attribute(Slapi_Entry *e, Slapi_Attr *a)
+{
+ attrlist_remove(&e->e_attrs,a->a_type);
+ attrlist_add(&e->e_deleted_attrs,a);
+ return LDAP_SUCCESS;
+}
+
+static int
+entry_deleted_attribute_to_present_attribute(Slapi_Entry *e, Slapi_Attr *a)
+{
+ attrlist_remove(&e->e_deleted_attrs,a->a_type);
+ attrlist_add(&e->e_attrs,a);
+ return LDAP_SUCCESS;
+}
+
+/*
+ * Get the first deleted attribute.
+ *
+ * Return 0: Return the type and the CSN of the deleted attribute.
+ * Return -1: There are no deleted attributes.
+ */
+int
+entry_first_deleted_attribute( const Slapi_Entry *e, Slapi_Attr **a)
+{
+ *a= e->e_deleted_attrs;
+ return( *a ? 0 : -1 );
+}
+
+/*
+ * Get the next deleted attribute.
+ *
+ * Return 0: the type and the CSN of the deleted attribute.
+ * Return -1: no deleted attributes.
+ */
+int
+entry_next_deleted_attribute( const Slapi_Entry *e, Slapi_Attr **a)
+{
+ *a= (*a)->a_next;
+ return( *a ? 0 : -1 );
+}
+
+const CSN *
+entry_get_maxcsn ( const Slapi_Entry *entry )
+{
+ return entry->e_maxcsn;
+}
+
+void
+entry_set_maxcsn ( Slapi_Entry *entry, const CSN *csn )
+{
+ if ( NULL == entry->e_maxcsn )
+ {
+ entry->e_maxcsn = csn_dup ( csn );
+ }
+ else if ( csn_compare ( entry->e_maxcsn, csn ) < 0 )
+ {
+ csn_init_by_csn ( entry->e_maxcsn, csn );
+ }
+}
+
+/*
+ * Get the DN CSN of an entry.
+ */
+const CSN *
+entry_get_dncsn(const Slapi_Entry *entry)
+{
+ return csnset_get_last_csn(entry->e_dncsnset);
+}
+
+/*
+ * Get the DN CSN set of an entry.
+ */
+const CSNSet *
+entry_get_dncsnset(const Slapi_Entry *entry)
+{
+ return entry->e_dncsnset;
+}
+
+/*
+ * Add a DN CSN to an entry.
+ */
+int
+entry_add_dncsn(Slapi_Entry *entry, const CSN *csn)
+{
+ PR_ASSERT(entry!=NULL);
+ if(!csnset_contains(entry->e_dncsnset,csn))
+ {
+ csnset_add_csn(&entry->e_dncsnset, CSN_TYPE_VALUE_DISTINGUISHED, csn);
+ }
+ return 0;
+}
+
+/*
+ * Add a DN CSN to an entry, but uses flags to control the behavior
+ * Using the ENTRY_DNCSN_INCREASING flag makes sure the csnset is in
+ * order of increasing csn. csnset_insert_csn may not be very fast, so
+ * we may have to revisit this if it becomes a performance problem.
+ * In most cases, storing the csn unsorted is ok since the server
+ * usually makes sure the csn is already in order. However, when doing
+ * a str2entry, the order is not preserved unless we sort it.
+ */
+int
+entry_add_dncsn_ext(Slapi_Entry *entry, const CSN *csn, PRUint32 flags)
+{
+ PR_ASSERT(entry!=NULL);
+ if(!csnset_contains(entry->e_dncsnset,csn))
+ {
+ if (flags & ENTRY_DNCSN_INCREASING)
+ {
+ csnset_insert_csn(&entry->e_dncsnset, CSN_TYPE_VALUE_DISTINGUISHED, csn);
+ }
+ else
+ {
+ csnset_add_csn(&entry->e_dncsnset, CSN_TYPE_VALUE_DISTINGUISHED, csn);
+ }
+ }
+ return 0;
+}
+
+/*
+ * Set the CSN for all the present values on the entry.
+ * This is only intended to be used for new entries
+ * being added.
+ */
+int
+entry_set_csn(Slapi_Entry *entry, const CSN *csn)
+{
+ Slapi_Attr *a;
+
+ PR_ASSERT(entry!=NULL);
+
+ slapi_entry_first_attr( entry, &a );
+ while(a!=NULL)
+ {
+ /*
+ * JCM - it'd be more efficient if the str2entry code
+ * set a flag on the attribute structure.
+ */
+ if(strcasecmp(a->a_type, SLAPI_ATTR_UNIQUEID)!=0)
+ {
+ attr_set_csn(a,csn);
+ }
+ slapi_entry_next_attr( entry, a, &a );
+ }
+ return 0;
+}
+
+/*
+ * Set the Distinguished CSN for the RDN components of the entry.
+ */
+void
+entry_add_rdn_csn(Slapi_Entry *e, const CSN *csn)
+{
+ char *type;
+ char *value;
+ int index;
+ const Slapi_DN *dn= slapi_entry_get_sdn_const(e);
+ Slapi_RDN *rdn= slapi_rdn_new_sdn(dn);
+ index= slapi_rdn_get_first(rdn, &type, &value);
+ while(index!=-1)
+ {
+ Slapi_Attr *a= NULL;
+ Slapi_Value *v= NULL;
+ entry_attr_find_wsi(e, type, &a);
+ if(a!=NULL)
+ {
+ struct berval bv;
+ bv.bv_len= strlen(value);
+ bv.bv_val= (void*)value;
+ attr_value_find_wsi(a, &bv, &v);
+ }
+ if(v!=NULL)
+ {
+ value_update_csn(v,CSN_TYPE_VALUE_DISTINGUISHED,csn);
+ }
+ else
+ {
+ /* JCM RDN component isn't a present value - this is illegal. */
+ }
+ index= slapi_rdn_get_next(rdn, index, &type, &value);
+ }
+ slapi_rdn_free(&rdn);
+}
+
+CSN*
+entry_assign_operation_csn ( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *parententry )
+{
+ Slapi_Operation *op;
+ const CSN *basecsn = NULL;
+ const CSN *parententry_dncsn = NULL;
+ CSN *opcsn = NULL;
+
+ slapi_pblock_get ( pb, SLAPI_OPERATION, &op );
+
+ /*
+ * The replication pre-op would have set op->o_csngen_handler for
+ * user requests that are against a replica.
+ */
+ if ( op->o_csngen_handler )
+ {
+ /*
+ * Sync up the CSN generator so that the new csn is greater
+ * than the entry's maxcsn and/or the parent's max dncsn.
+ */
+ if ( e )
+ {
+ basecsn = entry_get_maxcsn ( e );
+ }
+ if ( parententry )
+ {
+ parententry_dncsn = entry_get_dncsn ( parententry );
+ if ( csn_compare ( parententry_dncsn, basecsn ) > 0 )
+ {
+ basecsn = parententry_dncsn;
+ }
+ }
+ opcsn = op->o_csngen_handler ( pb, basecsn );
+
+ if (NULL != opcsn)
+ {
+ operation_set_csn (op, opcsn);
+ }
+ }
+
+ return opcsn;
+}
+
+/*
+ * Purge state information from the entry older than csnUpTo
+ *
+ * if csnUpTo is NULL, get rid of all the CSN related info.
+ * if csnUpTo is non-NULL, purge all info older than csnUpTo
+ */
+void
+entry_purge_state_information(Slapi_Entry *e, const CSN *csnUpTo)
+{
+ Slapi_Attr *a=NULL;
+
+ PR_ASSERT(e!=NULL);
+
+ for(a = e->e_attrs; NULL != a; a = a->a_next)
+ {
+ /*
+ * we are passing in the entry so that we may be able to "optimize"
+ * the csn related information and roll it up higher to the level
+ * of entry
+ */
+ attr_purge_state_information(e, a, csnUpTo);
+ }
+ for(a = e->e_deleted_attrs; NULL != a; a = a->a_next)
+ {
+ /*
+ * we are passing in the entry so that we may be able to "optimize"
+ * the csn related information and roll it up higher to the level
+ * of entry
+ */
+ attr_purge_state_information(e, a, csnUpTo);
+ }
+}
+
+/*
+ * Look for the attribute on the present and deleted attribute lists.
+ */
+int
+entry_attr_find_wsi(Slapi_Entry *e, const char *type, Slapi_Attr **a)
+{
+ int retVal= ATTRIBUTE_NOTFOUND;
+
+ PR_ASSERT(e!=NULL);
+ PR_ASSERT(type!=NULL);
+ PR_ASSERT(a!=NULL);
+
+ /* Look on the present attribute list */
+ *a= attrlist_find(e->e_attrs,type);
+ if(*a!=NULL)
+ {
+ /* The attribute is present */
+ retVal= ATTRIBUTE_PRESENT;
+ }
+ else
+ {
+ /* Maybe the attribue was deleted... */
+ *a= attrlist_find(e->e_deleted_attrs,type);
+ if(*a!=NULL)
+ {
+ /* The attribute is deleted */
+ retVal= ATTRIBUTE_DELETED;
+ }
+ else
+ {
+ /* The attribute was not found */
+ retVal= ATTRIBUTE_NOTFOUND;
+ }
+ }
+ return retVal;
+}
+
+/*
+ * Add the attribute to the deleted attribute list.
+ *
+ * Consumes the attribute.
+ */
+int
+entry_add_deleted_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a)
+{
+ PR_ASSERT( e!=NULL );
+ PR_ASSERT( a!=NULL );
+ attrlist_add(&e->e_deleted_attrs, a);
+ return 0;
+}
+
+/*
+ * Add the attribute to the present attribute list.
+ *
+ * Consumes the attribute.
+ */
+int
+entry_add_present_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a)
+{
+ PR_ASSERT( e!=NULL );
+ PR_ASSERT( a!=NULL );
+ attrlist_add(&e->e_attrs, a);
+ return 0;
+}
+
+/*
+ * Add a list of values to the attribute, whilst maintaining state information.
+ *
+ * Preserves LDAP Information Model constraints,
+ * returning an LDAP result code.
+ */
+static int
+entry_add_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **bervals, const CSN *csn, int urp, long flags)
+{
+ int retVal= LDAP_SUCCESS;
+ Slapi_Value **valuestoadd = NULL;
+ valuearray_init_bervalarray(bervals,&valuestoadd); /* JCM SLOW FUNCTION */
+ if(!valuearray_isempty(valuestoadd))
+ {
+ Slapi_Attr *a= NULL;
+ long a_flags_orig;
+ int attr_state= entry_attr_find_wsi(e, type, &a);
+ if (ATTRIBUTE_NOTFOUND == attr_state)
+ {
+ /* Create a new attribute */
+ a = slapi_attr_new();
+ slapi_attr_init(a, type);
+ attrlist_add(&e->e_attrs, a);
+ }
+ a_flags_orig = a->a_flags;
+ a->a_flags |= flags;
+ if(urp)
+ {
+ /*
+ * Consolidate a->a_present_values and the pending values:
+ * Delete the pending values from a->a_present_values
+ * and transfer their csnsets to valuestoadd.
+ */
+ valueset_remove_valuearray (&a->a_present_values, a, valuestoadd,
+ SLAPI_VALUE_FLAG_IGNOREERROR |
+ SLAPI_VALUE_FLAG_PRESERVECSNSET, NULL);
+ /*
+ * Consolidate a->a_deleted_values and the pending values
+ * similarly.
+ */
+ valueset_remove_valuearray (&a->a_deleted_values, a, valuestoadd,
+ SLAPI_VALUE_FLAG_IGNOREERROR |
+ SLAPI_VALUE_FLAG_PRESERVECSNSET, NULL);
+
+ /* Append the pending values to a->a_present_values */
+ valuearray_update_csn (valuestoadd,CSN_TYPE_VALUE_UPDATED,csn);
+ valueset_add_valuearray_ext(&a->a_present_values, valuestoadd, SLAPI_VALUE_FLAG_PASSIN);
+ slapi_ch_free ( (void **)&valuestoadd );
+
+ /*
+ * Now delete non-RDN values from a->a_present_values; and
+ * restore possible RDN values from a->a_deleted_values
+ */
+ resolve_attribute_state(e, a, attr_state);
+ retVal= LDAP_SUCCESS;
+ }
+ else
+ {
+ Slapi_Value **deletedvalues= NULL;
+ switch(attr_state)
+ {
+ case ATTRIBUTE_PRESENT:
+ /* The attribute is already on the present list */
+ break;
+ case ATTRIBUTE_DELETED:
+ /* Move the deleted attribute onto the present list */
+ entry_deleted_attribute_to_present_attribute(e, a);
+ break;
+ case ATTRIBUTE_NOTFOUND:
+ /* No-op - attribute was initialized & added to entry above */
+ break;
+ }
+ /* Check if any of the values to be added are on the deleted list */
+ valueset_remove_valuearray(&a->a_deleted_values, a, valuestoadd, SLAPI_VALUE_FLAG_IGNOREERROR,&deletedvalues); /* JCM Check return code */
+ if(deletedvalues!=NULL && deletedvalues[0]!=NULL)
+ {
+ /* Some of the values to be added were on the deleted list */
+ Slapi_Value **v= NULL;
+ Slapi_ValueSet vs;
+ /* Add each deleted value to the present list */
+ valuearray_update_csn(deletedvalues,CSN_TYPE_VALUE_UPDATED,csn);
+ valueset_add_valuearray_ext(&a->a_present_values, deletedvalues, SLAPI_VALUE_FLAG_PASSIN);
+ /* Remove the deleted values from the values to add */
+ valueset_set_valuearray_passin(&vs,valuestoadd);
+ valueset_remove_valuearray(&vs, a, deletedvalues, SLAPI_VALUE_FLAG_IGNOREERROR, &v);
+ valuestoadd= valueset_get_valuearray(&vs);
+ valuearray_free(&v);
+ slapi_ch_free((void **)&deletedvalues);
+ }
+ valuearray_update_csn(valuestoadd,CSN_TYPE_VALUE_UPDATED,csn);
+ retVal= attr_add_valuearray(a, valuestoadd, slapi_entry_get_dn_const(e));
+ valuearray_free(&valuestoadd);
+ }
+ a->a_flags = a_flags_orig;
+ }
+ return(retVal);
+}
+
+/*
+ * Delete a list of values from an attribute, whilst maintaining state information.
+ *
+ * Preserves LDAP Information Model constraints,
+ * returning an LDAP result code.
+ */
+static int
+entry_delete_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **vals, const CSN *csn, int urp, int mod_op)
+{
+ int retVal= LDAP_SUCCESS;
+ Slapi_Attr *a= NULL;
+ int attr_state= entry_attr_find_wsi(e, type, &a);
+ if(attr_state==ATTRIBUTE_PRESENT || (attr_state==ATTRIBUTE_DELETED && urp))
+ {
+ /* The attribute is on the present list, or the deleted list and we're doing URP */
+ if ( vals == NULL || vals[0] == NULL )
+ {
+ /* delete the entire attribute */
+ LDAPDebug( LDAP_DEBUG_ARGS, "removing entire attribute %s\n", type, 0, 0 );
+ attr_set_deletion_csn(a,csn);
+ if(urp)
+ {
+ resolve_attribute_state(e, a, attr_state); /* ABSOLVED */
+ }
+ else
+ {
+ if(!slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE))
+ {
+ /* We don't maintain a deleted value list for single valued attributes */
+ valueset_add_valueset(&a->a_deleted_values, &a->a_present_values); /* JCM Would be better to passin the valuestodelete */
+ }
+ slapi_valueset_done(&a->a_present_values);
+ entry_present_attribute_to_deleted_attribute(e, a);
+ }
+ retVal= LDAP_SUCCESS; /* This Operation always succeeds when the attribute is Present */
+ }
+ else
+ {
+ /* delete some specific values */
+ Slapi_Value **valuestodelete= NULL;
+ valuearray_init_bervalarray(vals,&valuestodelete); /* JCM SLOW FUNCTION */
+ if(urp)
+ {
+ Slapi_Value **valuesupdated= NULL;
+ valueset_update_csn_for_valuearray(&a->a_present_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated);
+ /* if we removed the last value, we need to mark the attribute as deleted
+ the resolve_attribute_state() code will "resurrect" the attribute if
+ there are present values with a later CSN - otherwise, even though
+ the value will be updated with a VDCSN which is later than the VUCSN,
+ the attribute will not be deleted */
+ if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE) && valuesupdated &&
+ *valuesupdated)
+ {
+ attr_set_deletion_csn(a,csn);
+ }
+ valuearray_free(&valuesupdated);
+ valueset_update_csn_for_valuearray(&a->a_deleted_values, a, valuestodelete, CSN_TYPE_VALUE_DELETED, csn, &valuesupdated);
+ valuearray_free(&valuesupdated);
+ valuearray_update_csn(valuestodelete,CSN_TYPE_VALUE_DELETED,csn);
+ valueset_add_valuearray_ext(&a->a_deleted_values, valuestodelete, SLAPI_VALUE_FLAG_PASSIN);
+ /* all the elements in valuestodelete are passed;
+ * should free valuestodelete only (don't call valuearray_free)
+ * [622023] */
+ slapi_ch_free((void **)&valuestodelete);
+ resolve_attribute_state(e, a, attr_state);
+ retVal= LDAP_SUCCESS;
+ }
+ else
+ {
+ Slapi_Value **deletedvalues= NULL;
+ retVal= valueset_remove_valuearray(&a->a_present_values, a, valuestodelete, 0 /* Do Not Ignore Errors */,&deletedvalues);
+ if(retVal==LDAP_SUCCESS && deletedvalues != NULL)
+ {
+ if(!slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE))
+ {
+ /* We don't maintain a deleted value list for single valued attributes */
+ /* Add each deleted value to the deleted set */
+ valuearray_update_csn(deletedvalues,CSN_TYPE_VALUE_DELETED,csn);
+ valueset_add_valuearray_ext(&a->a_deleted_values, deletedvalues, SLAPI_VALUE_FLAG_PASSIN);
+ slapi_ch_free((void **)&deletedvalues);
+ }
+ else {
+ valuearray_free(&deletedvalues);
+ }
+ if(valueset_isempty(&a->a_present_values))
+ {
+ /* There are no present values, so move the
+ * attribute to the deleted attribute list. */
+ entry_present_attribute_to_deleted_attribute(e, a);
+ }
+ }
+ else if (retVal != LDAP_SUCCESS)
+ {
+ /* Failed
+ * - Duplicate value
+ * - Value not found
+ * - Operations error
+ */
+ if ( retVal==LDAP_OPERATIONS_ERROR )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Possible existing duplicate "
+ "value for attribute type %s found in "
+ "entry %s\n", a->a_type, slapi_entry_get_dn_const(e), 0 );
+ }
+ }
+ valuearray_free(&valuestodelete);
+ }
+ }
+ }
+ else if (attr_state==ATTRIBUTE_DELETED)
+ {
+ retVal= LDAP_NO_SUCH_ATTRIBUTE;
+ }
+ else if (attr_state==ATTRIBUTE_NOTFOUND)
+ {
+ if (!urp)
+ {
+ /* Only warn if not urping */
+ LDAPDebug( LDAP_DEBUG_ARGS, "could not find attribute %s\n", type, 0, 0 );
+ }
+ retVal= LDAP_NO_SUCH_ATTRIBUTE;
+ if (LDAP_MOD_REPLACE == mod_op)
+ {
+ /* Create a new attribute and set the adcsn */
+ Slapi_Attr *a = slapi_attr_new();
+ slapi_attr_init(a, type);
+ /* According to URP there should be an adcsn.
+ * According to Tests, there should not
+ * since the attribute never existed
+ * Tests 26 and 27 of MMRepl state. */
+ if (urp)
+ attr_set_deletion_csn(a,csn);
+ attrlist_add(&e->e_attrs, a);
+ }
+ }
+ return( retVal );
+}
+
+/*
+ * Replace all the values of an attribute with a list of attribute values.
+ *
+ * Preserves LDAP Information Model constraints,
+ * returning an LDAP result code.
+ */
+static int
+entry_replace_present_values_wsi(Slapi_Entry *e, const char *type, struct berval **vals, const CSN *csn, int urp)
+{
+ /*
+ * Remove all existing values.
+ */
+ entry_delete_present_values_wsi(e, type, NULL /* Delete all values */, csn, urp, LDAP_MOD_REPLACE);
+
+ /*
+ * Add the new values. If there are no new values,
+ * slapi_entry_add_values() returns LDAP_SUCCESS and so the
+ * attribute remains deleted (which is the correct outcome).
+ */
+ return( entry_add_present_values_wsi( e, type, vals, csn, urp, SLAPI_ATTR_FLAG_CMP_BITBYBIT ));
+}
+
+/*
+ * Applies the modification to the entry whilst
+ * maintaining state information.
+ */
+int
+entry_apply_mod_wsi(Slapi_Entry *e, const LDAPMod *mod, const CSN *csn, int urp)
+{
+ int retVal= LDAP_SUCCESS;
+ int i;
+
+ switch ( mod->mod_op & ~LDAP_MOD_BVALUES )
+ {
+ case LDAP_MOD_ADD:
+ LDAPDebug( LDAP_DEBUG_ARGS, " add: %s\n", mod->mod_type, 0, 0 );
+ retVal = entry_add_present_values_wsi( e, mod->mod_type, mod->mod_bvalues, csn, urp, 0 );
+ break;
+
+ case LDAP_MOD_DELETE:
+ LDAPDebug( LDAP_DEBUG_ARGS, " delete: %s\n", mod->mod_type, 0, 0 );
+ retVal = entry_delete_present_values_wsi( e, mod->mod_type, mod->mod_bvalues, csn, urp, mod->mod_op );
+ break;
+
+ case LDAP_MOD_REPLACE:
+ LDAPDebug( LDAP_DEBUG_ARGS, " replace: %s\n", mod->mod_type, 0, 0 );
+ retVal = entry_replace_present_values_wsi( e, mod->mod_type, mod->mod_bvalues, csn, urp );
+ break;
+ }
+ for ( i = 0; mod->mod_bvalues != NULL && mod->mod_bvalues[i] != NULL; i++ )
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, " %s: %s\n", mod->mod_type, mod->mod_bvalues[i]->bv_val, 0 );
+ }
+ LDAPDebug( LDAP_DEBUG_ARGS, " -\n", 0, 0, 0 );
+
+ return retVal;
+}
+
+/*
+ * Applies the set of modifications to the entry whilst
+ * maintaining state information.
+ */
+int
+entry_apply_mods_wsi(Slapi_Entry *e, Slapi_Mods *smods, const CSN *csn, int urp)
+{
+ int retVal= LDAP_SUCCESS;
+ LDAPMod *mod;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> entry_apply_mods_wsi\n", 0, 0, 0 );
+
+ mod = slapi_mods_get_first_mod(smods);
+ while(NULL!=mod && retVal==LDAP_SUCCESS)
+ {
+ if(csn!=NULL)
+ {
+ retVal= entry_apply_mod_wsi(e, mod, csn, urp);
+ }
+ else
+ {
+ retVal= entry_apply_mod(e, mod);
+ }
+ mod = slapi_mods_get_next_mod(smods);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= entry_apply_mods_wsi %d\n", retVal, 0, 0 );
+
+ return retVal;
+}
+
+/*
+ * This code implements a computed attribute called 'nscpEntryWSI'.
+ * By specifically asking for this attribute the client will recieve
+ * an LDIF dump of the entry with all its state information.
+ *
+ * JCM - Security... Only for the Directory Manager.
+ */
+static const char *nscpEntryWSI= "nscpEntryWSI";
+/*
+ */
+static int
+entry_compute_nscpentrywsi(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_compute_output_t outputfn)
+{
+ int rc = 0;
+
+ if ( strcasecmp(type, nscpEntryWSI ) == 0)
+ {
+ /* If not, we return it as zero */
+ char *es;
+ char *s;
+ char *p;
+ int len;
+ Slapi_Attr our_attr;
+ slapi_attr_init(&our_attr, nscpEntryWSI);
+ our_attr.a_flags = SLAPI_ATTR_FLAG_OPATTR;
+ es= slapi_entry2str_with_options(e, &len, SLAPI_DUMP_STATEINFO | SLAPI_DUMP_UNIQUEID | SLAPI_DUMP_NOWRAP);
+ s= es;
+ p= ldif_getline( &s );
+ while(p!=NULL)
+ {
+ Slapi_Value *v;
+ char *t, *d;
+ /* Strip out the Continuation Markers (JCM - I think that NOWRAP means we don't need to do this any more)*/
+ for ( t = p, d = p; *t; t++ )
+ {
+ if ( *t != 0x01 )
+ *d++ = *t;
+ }
+ *d = '\0';
+ v= slapi_value_new_string(p);
+ slapi_attr_add_value(&our_attr,v);
+ slapi_value_free(&v);
+ p= ldif_getline( &s );
+ }
+ slapi_ch_free((void**)&es);
+ rc = (*outputfn) (c, &our_attr, e);
+ attr_done(&our_attr);
+ return (rc);
+ }
+
+ return -1; /* I see no ships */
+}
+
+
+int
+entry_computed_attr_init()
+{
+ slapi_compute_add_evaluator(entry_compute_nscpentrywsi);
+ return 0;
+}
+
+static void
+purge_attribute_state_multi_valued(const Slapi_Attr *a, Slapi_Value *v)
+{
+ const CSN *vdcsn= value_get_csn(v,CSN_TYPE_VALUE_DELETED);
+ const CSN *vucsn= value_get_csn(v,CSN_TYPE_VALUE_UPDATED);
+ if(vdcsn && csn_compare(vdcsn,vucsn)<0)
+ {
+ value_remove_csn(v,CSN_TYPE_VALUE_DELETED);
+ }
+}
+
+/*
+ * utility function for value_distinguished_at_csn...
+ */
+static const CSN *
+vdac_sniff_value(Slapi_ValueSet *vs, const Slapi_Value *v, const CSN *csn, const CSN *most_recent_mdcsn)
+{
+ const CSN *mdcsn= value_get_csn(v,CSN_TYPE_VALUE_DISTINGUISHED);
+ if(mdcsn!=NULL)
+ {
+ /* This value was/is distinguished... */
+ if(csn_compare(csn,most_recent_mdcsn)<0)
+ {
+ /* ...and was distinguished before the point in time we're interested in... */
+ int r= csn_compare(mdcsn,most_recent_mdcsn);
+ if(r>0)
+ {
+ /* ...and is the most recent MDCSN we've seen thus far. */
+ slapi_valueset_done(vs);
+ slapi_valueset_add_value(vs,v);
+ most_recent_mdcsn= mdcsn;
+ }
+ else if(r==0)
+ {
+ /* ...and is as recent as the last most recent MDCSN we've seen thus far. */
+ /* Must have been a multi-valued RDN */
+ slapi_valueset_add_value(vs,v);
+ }
+ }
+ }
+ return most_recent_mdcsn;
+}
+
+/*
+ * utility function for value_distinguished_at_csn...
+ */
+static const CSN *
+vdac_sniff_attribute(Slapi_ValueSet *vs, Slapi_Attr *a, const CSN *csn, const CSN *most_recent_mdcsn)
+{
+ Slapi_Value *v;
+ int i= slapi_attr_first_value( a, &v );
+ while(i!=-1)
+ {
+ most_recent_mdcsn= vdac_sniff_value( vs, v, csn, most_recent_mdcsn );
+ i= slapi_attr_next_value( a, i, &v );
+ }
+ i= attr_first_deleted_value( a, &v );
+ while(i!=-1)
+ {
+ most_recent_mdcsn= vdac_sniff_value( vs, v, csn, most_recent_mdcsn );
+ i= attr_next_deleted_value( a, i, &v );
+ }
+ return most_recent_mdcsn;
+}
+
+/*
+ * utility function for value_distinguished_at_csn...
+ *
+ * Return the set of values that made up the RDN at or before the csn point.
+ */
+static const CSN *
+distinguished_values_at_csn(const Slapi_Entry *e, const CSN *csn, Slapi_ValueSet *vs)
+{
+ const CSN *most_recent_mdcsn= NULL;
+ Slapi_Attr *a;
+ int i= slapi_entry_first_attr( e, &a );
+ while(i!=-1)
+ {
+ most_recent_mdcsn= vdac_sniff_attribute( vs, a, csn, most_recent_mdcsn);
+ i= slapi_entry_next_attr( e, a, &a );
+ }
+ i= entry_first_deleted_attribute( e, &a );
+ while(i!=-1)
+ {
+ most_recent_mdcsn= vdac_sniff_attribute( vs, a, csn, most_recent_mdcsn);
+ i= entry_next_deleted_attribute( e, &a );
+ }
+ return most_recent_mdcsn;
+}
+
+/*
+ * Work out if the value was distinguished at time csn.
+ */
+static int
+value_distinguished_at_csn(const Slapi_Entry *e, const Slapi_Attr *original_attr, Slapi_Value *original_value, const CSN *csn)
+{
+ int r= 0;
+ const CSN *mdcsn= value_get_csn(original_value,CSN_TYPE_VALUE_DISTINGUISHED);
+ if(mdcsn!=NULL)
+ {
+ /*
+ * Oh bugger. This means that we have to work out what the RDN components
+ * were at this point in time. This is non-trivial since we must walk
+ * through all the present and deleted attributes and their present and
+ * deleted values. Slow :-(
+ */
+ Slapi_ValueSet *vs= slapi_valueset_new();
+ const CSN *most_recent_mdcsn= distinguished_values_at_csn(e, csn, vs);
+ /*
+ * We now know what the RDN components were at the point in time we're interested in.
+ * And the question we need to answer is :-
+ * 'Was the provided value one of those RDN components?'
+ */
+ if(most_recent_mdcsn!=NULL)
+ {
+ Slapi_Value *v;
+ int i= slapi_valueset_first_value( vs, &v );
+ while(i!=-1)
+ {
+ if(slapi_value_compare(original_attr, original_value, v)==0)
+ {
+ /* This value was distinguished at the time in question. */
+ r= 1;
+ i= -1;
+ }
+ else
+ {
+ i= slapi_valueset_next_value( vs, i, &v );
+ }
+ }
+ }
+ slapi_valueset_free(vs);
+ }
+ else
+ {
+ /* This value has never been distinguished */
+ r= 0;
+ }
+ return r;
+}
+
+static void
+resolve_attribute_state_multi_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+{
+ int i;
+ const CSN *adcsn= attr_get_deletion_csn(a);
+ Slapi_ValueSet *vs= valueset_dup(&a->a_present_values); /* JCM This is slow... but otherwise we end up iterating through a changing array */
+ Slapi_Value *v;
+
+ /* Loop over the present attribute values */
+ i= slapi_valueset_first_value( vs, &v );
+ while(v!=NULL)
+ {
+ const CSN *vdcsn;
+ const CSN *vucsn;
+ const CSN *deletedcsn;
+ /* This call ensures that the value does not contain a deletion_csn
+ * which is before the presence_csn or distinguished_csn of the value.
+ */
+ purge_attribute_state_multi_valued(a, v);
+ vdcsn= value_get_csn(v, CSN_TYPE_VALUE_DELETED);
+ vucsn= value_get_csn(v, CSN_TYPE_VALUE_UPDATED);
+ deletedcsn= csn_max(vdcsn, adcsn);
+ if(csn_compare(vucsn,deletedcsn)<0) /* check if the attribute or value was deleted after the value was last updated */
+ {
+ if(!value_distinguished_at_csn(e, a, v, deletedcsn))
+ {
+ entry_present_value_to_deleted_value(a,v);
+ }
+ }
+ i= slapi_valueset_next_value( vs, i, &v );
+ }
+ slapi_valueset_free(vs);
+
+ /* Loop over the deleted attribute values */
+ vs= valueset_dup(&a->a_deleted_values); /* JCM This is slow... but otherwise we end up iterating through a changing array */
+ i= slapi_valueset_first_value( vs, &v );
+ while(v!=NULL)
+ {
+ const CSN *vdcsn;
+ const CSN *vucsn;
+ const CSN *deletedcsn;
+ /* This call ensures that the value does not contain a deletion_csn which is before the presence_csn or distinguished_csn of the value. */
+ purge_attribute_state_multi_valued(a, v);
+ vdcsn= value_get_csn(v, CSN_TYPE_VALUE_DELETED);
+ vucsn= value_get_csn(v, CSN_TYPE_VALUE_UPDATED);
+ deletedcsn= csn_max(vdcsn, adcsn);
+ if((csn_compare(vucsn,deletedcsn)>=0) || /* check if the attribute or value was deleted after the value was last updated */
+ value_distinguished_at_csn(e, a, v, deletedcsn))
+ {
+ entry_deleted_value_to_present_value(a,v);
+ }
+ i= slapi_valueset_next_value( vs, i, &v );
+ }
+ slapi_valueset_free(vs);
+
+ if(valueset_isempty(&a->a_present_values))
+ {
+ if(attribute_state==ATTRIBUTE_PRESENT)
+ {
+ entry_present_attribute_to_deleted_attribute(e, a);
+ }
+ }
+ else
+ {
+ if(attribute_state==ATTRIBUTE_DELETED)
+ {
+ entry_deleted_attribute_to_present_attribute(e, a);
+ }
+ }
+}
+
+static void
+resolve_attribute_state_single_valued(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+{
+ Slapi_Value *current_value= NULL;
+ Slapi_Value *pending_value= NULL;
+ Slapi_Value *new_value= NULL;
+ const CSN *current_value_vucsn;
+ const CSN *pending_value_vucsn;
+ const CSN *adcsn;
+ int i;
+
+ /*
+ * this call makes sure that the attribute does not have a pending_value
+ * or deletion_csn which is before the current_value.
+ */
+ i= slapi_attr_first_value(a,&current_value);
+ if(i!=-1)
+ {
+ slapi_attr_next_value(a,i,&new_value);
+ }
+ attr_first_deleted_value(a,&pending_value);
+
+ /* purge_attribute_state_single_valued */
+ adcsn= attr_get_deletion_csn(a);
+ current_value_vucsn= value_get_csn(current_value, CSN_TYPE_VALUE_UPDATED);
+ pending_value_vucsn= value_get_csn(pending_value, CSN_TYPE_VALUE_UPDATED);
+ if((pending_value!=NULL && (csn_compare(adcsn, pending_value_vucsn)<0)) ||
+ (pending_value==NULL && (csn_compare(adcsn, current_value_vucsn)<0)))
+ {
+ attr_set_deletion_csn(a,NULL);
+ adcsn= NULL;
+ }
+
+ if(new_value==NULL)
+ {
+ /* check if the pending value should become the current value */
+ if(pending_value!=NULL)
+ {
+ if(!value_distinguished_at_csn(e,a,current_value,pending_value_vucsn))
+ {
+ /* attribute.current_value = attribute.pending_value; */
+ /* attribute.pending_value = NULL; */
+ entry_present_value_to_zapped_value(a,current_value);
+ entry_deleted_value_to_present_value(a,pending_value);
+ current_value= pending_value;
+ pending_value= NULL;
+ current_value_vucsn= pending_value_vucsn;
+ pending_value_vucsn= NULL;
+ }
+ }
+ /* check if the current value should be deleted */
+ if(current_value!=NULL)
+ {
+ if(csn_compare(adcsn,current_value_vucsn)>0) /* check if the attribute was deleted after the value was last updated */
+ {
+ if(!value_distinguished_at_csn(e,a,current_value,current_value_vucsn))
+ {
+ entry_present_value_to_zapped_value(a,current_value);
+ current_value= NULL;
+ current_value_vucsn= NULL;
+ }
+ }
+ }
+ }
+ else /* addition of a new value */
+ {
+ const CSN *new_value_vucsn= value_get_csn(new_value,CSN_TYPE_VALUE_UPDATED);
+ if(csn_compare(new_value_vucsn,current_value_vucsn)<0)
+ {
+ /*
+ * if the new value was distinguished at the time the current value was added
+ * then the new value should become current
+ */
+ if(value_distinguished_at_csn(e,a,new_value,current_value_vucsn))
+ {
+ /* attribute.pending_value = attribute.current_value */
+ /* attribute.current_value = new_value */
+ if(pending_value==NULL)
+ {
+ entry_present_value_to_deleted_value(a,current_value);
+ }
+ else
+ {
+ entry_present_value_to_zapped_value(a,current_value);
+ }
+ pending_value= current_value;
+ current_value= new_value;
+ new_value= NULL;
+ pending_value_vucsn= current_value_vucsn;
+ current_value_vucsn= new_value_vucsn;
+ }
+ else
+ {
+ /* new_value= NULL */
+ entry_present_value_to_zapped_value(a, new_value);
+ new_value= NULL;
+ }
+ }
+ else /* new value is after the current value */
+ {
+ if(!value_distinguished_at_csn(e, a, current_value, new_value_vucsn))
+ {
+ /* attribute.current_value = new_value */
+ entry_present_value_to_zapped_value(a, current_value);
+ current_value= new_value;
+ new_value= NULL;
+ current_value_vucsn= new_value_vucsn;
+ }
+ else /* value is distinguished - check if we should replace the current pending value */
+ {
+ if(csn_compare(new_value_vucsn, pending_value_vucsn)>0)
+ {
+ /* attribute.pending_value = new_value */
+ entry_deleted_value_to_zapped_value(a,pending_value);
+ entry_present_value_to_deleted_value(a,new_value);
+ pending_value= new_value;
+ new_value= NULL;
+ pending_value_vucsn= new_value_vucsn;
+ }
+ }
+ }
+ }
+
+ /*
+ * This call ensures that the attribute does not have a pending_value
+ * or a deletion_csn that is earlier than the current_value.
+ */
+ /* purge_attribute_state_single_valued */
+ if((pending_value!=NULL && (csn_compare(adcsn, pending_value_vucsn)<0)) ||
+ (pending_value==NULL && (csn_compare(adcsn, current_value_vucsn)<0)))
+ {
+ attr_set_deletion_csn(a,NULL);
+ adcsn= NULL;
+ }
+
+ /* set attribute state */
+ if(current_value==NULL)
+ {
+ if(attribute_state==ATTRIBUTE_PRESENT)
+ {
+ entry_present_attribute_to_deleted_attribute(e, a);
+ }
+ }
+ else
+ {
+ if(attribute_state==ATTRIBUTE_DELETED)
+ {
+ entry_deleted_attribute_to_present_attribute(e, a);
+ }
+ }
+}
+
+static void
+resolve_attribute_state(Slapi_Entry *e, Slapi_Attr *a, int attribute_state)
+{
+ if(slapi_attr_flag_is_set(a,SLAPI_ATTR_FLAG_SINGLE))
+ {
+ resolve_attribute_state_single_valued(e,a,attribute_state);
+ }
+ else
+ {
+ resolve_attribute_state_multi_valued(e,a,attribute_state);
+ }
+}
diff --git a/ldap/servers/slapd/errormap.c b/ldap/servers/slapd/errormap.c
new file mode 100644
index 00000000..8e7f2151
--- /dev/null
+++ b/ldap/servers/slapd/errormap.c
@@ -0,0 +1,186 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * errormap.c - map NSPR and OS errors to strings
+ *
+ */
+
+#include "slap.h"
+
+#ifndef SYSERRLIST_IN_STDIO
+extern int sys_nerr;
+extern char *sys_errlist[];
+#endif
+
+/*
+ * function protoypes
+ */
+static const char *SECU_Strerror(PRErrorCode errNum);
+
+
+/*
+ * return the string equivalent of an NSPR error
+ */
+char *
+slapd_pr_strerror( const int prerrno )
+{
+ char *s;
+
+ if (( s = (char *)SECU_Strerror( (PRErrorCode)prerrno )) == NULL ) {
+ s = "unknown";
+ }
+
+ return( s );
+}
+
+
+/*
+ * return the string equivalent of a system error
+ */
+const char *
+slapd_system_strerror( const int syserrno )
+{
+ const char *s;
+ /* replaced
+ if ( syserrno > -1 && syserrno < sys_nerr ) {
+ s = sys_errlist[ syserrno ];
+ } else {
+ s = "unknown";
+ }
+ with s= strerror(syserrno)*/
+ s=strerror(syserrno);
+ return( s );
+}
+
+
+/*
+ * return the string equivalent of an NSPR error. If "prerrno" is not
+ * an NSPR error, assume it is a system error. Please use slapd_pr_strerror()
+ * or slapd_system_strerror() if you can since the concept behind this
+ * function is a bit of a kludge -- one should *really* know what kind of
+ * error code they have.
+ */
+const char *
+slapd_versatile_strerror( const PRErrorCode prerrno )
+{
+ const char *s;
+
+ if (( s = (const char *)SECU_Strerror( prerrno )) == NULL ) {
+ s = slapd_system_strerror( (const int)prerrno );
+ }
+
+ return( s );
+}
+
+
+/*
+ ****************************************************************************
+ * The code below this point was provided by Nelson Bolyard <nelsonb> of the
+ * Netscape Certificate Server team on 27-March-1998.
+ * Taken from the file ns/security/cmd/lib/secerror.c on NSS_1_BRANCH.
+ * Last updated from there: 24-July-1998 by Mark Smith <mcs>
+ *
+ * All of the Directory Server specific changes are enclosed inside
+ * #ifdef NS_DS.
+ ****************************************************************************
+ */
+#include "nspr.h"
+
+struct tuple_str {
+ PRErrorCode errNum;
+ const char * errString;
+};
+
+typedef struct tuple_str tuple_str;
+
+#define ER2(a,b) {a, b},
+#define ER3(a,b,c) {a, c},
+
+#include "secerr.h"
+#include "sslerr.h"
+
+static const tuple_str errStrings[] = {
+
+/* keep this list in ascending order of error numbers */
+#ifdef NS_DS
+#include "dberrstrs.h"
+#include "sslerrstrs.h"
+#include "secerrstrs.h"
+#include "prerrstrs.h"
+#include "disconnect_error_strings.h"
+#else /* NS_DS */
+#include "SSLerrs.h"
+#include "SECerrs.h"
+#include "NSPRerrs.h"
+#endif /* NS_DS */
+
+};
+
+static const PRInt32 numStrings = sizeof(errStrings) / sizeof(tuple_str);
+
+/* Returns a UTF-8 encoded constant error string for "errNum".
+ * Returns NULL of errNum is unknown.
+ */
+#ifdef NS_DS
+static
+#endif /* NS_DS */
+const char *
+SECU_Strerror(PRErrorCode errNum) {
+ PRInt32 low = 0;
+ PRInt32 high = numStrings - 1;
+ PRInt32 i;
+ PRErrorCode num;
+ static int initDone;
+
+ /* make sure table is in ascending order.
+ * binary search depends on it.
+ */
+ if (!initDone) {
+ PRErrorCode lastNum = errStrings[low].errNum;
+ for (i = low + 1; i <= high; ++i) {
+ num = errStrings[i].errNum;
+ if (num <= lastNum) {
+#ifdef NS_DS
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "sequence error in error strings at item %d\n"
+ "error %d (%s)\n",
+ i, lastNum, errStrings[i-1].errString );
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "should come after \n"
+ "error %d (%s)\n",
+ num, errStrings[i].errString, 0 );
+#else /* NS_DS */
+ fprintf(stderr,
+"sequence error in error strings at item %d\n"
+"error %d (%s)\n"
+"should come after \n"
+"error %d (%s)\n",
+ i, lastNum, errStrings[i-1].errString,
+ num, errStrings[i].errString);
+#endif /* NS_DS */
+ }
+ lastNum = num;
+ }
+ initDone = 1;
+ }
+
+ /* Do binary search of table. */
+ while (low + 1 < high) {
+ i = (low + high) / 2;
+ num = errStrings[i].errNum;
+ if (errNum == num)
+ return errStrings[i].errString;
+ if (errNum < num)
+ high = i;
+ else
+ low = i;
+ }
+ if (errNum == errStrings[low].errNum)
+ return errStrings[low].errString;
+ if (errNum == errStrings[high].errNum)
+ return errStrings[high].errString;
+ return NULL;
+}
diff --git a/ldap/servers/slapd/eventq.c b/ldap/servers/slapd/eventq.c
new file mode 100644
index 00000000..3acd027f
--- /dev/null
+++ b/ldap/servers/slapd/eventq.c
@@ -0,0 +1,482 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* ********************************************************
+eventq.c - Event queue/scheduling system.
+
+There are 3 publicly-accessible entry points:
+
+slapi_eq_once(): cause an event to happen exactly once
+slapi_eq_repeat(): cause an event to happen repeatedly
+slapi_eq_cancel(): cancel a pending event
+
+There is also an initialization point which must be
+called by the server to initialize the event queue system:
+eq_start(), and an entry point used to shut down the system:
+eq_stop().
+*********************************************************** */
+
+#include "slap.h"
+#include "prlock.h"
+#include "prcvar.h"
+#include "prinit.h"
+
+/*
+ * Private definition of slapi_eq_context. Only this
+ * module (eventq.c) should know about the layout of
+ * this structure.
+ */
+typedef struct _slapi_eq_context {
+ time_t ec_when;
+ time_t ec_interval;
+ slapi_eq_fn_t ec_fn;
+ void *ec_arg;
+ Slapi_Eq_Context ec_id;
+ struct _slapi_eq_context *ec_next;
+} slapi_eq_context;
+
+/*
+ * Definition of the event queue.
+ */
+typedef struct _event_queue {
+ PRLock *eq_lock;
+ PRCondVar *eq_cv;
+ slapi_eq_context *eq_queue;
+} event_queue;
+
+/*
+ * The event queue itself.
+ */
+static event_queue eqs = {0};
+static event_queue *eq = &eqs;
+
+/*
+ * Thread ID of the main thread loop
+ */
+static PRThread *eq_loop_tid = NULL;
+
+/*
+ * Flags used to control startup/shutdown of the event queue
+ */
+static int eq_running = 0;
+static int eq_stopped = 0;
+static int eq_initialized = 0;
+PRLock *ss_lock = NULL;
+PRCondVar *ss_cv = NULL;
+PRCallOnceType init_once = {0};
+
+/* Forward declarations */
+static slapi_eq_context *eq_new(slapi_eq_fn_t fn, void *arg,
+ time_t when, unsigned long interval);
+static void eq_enqueue(slapi_eq_context *newec);
+static slapi_eq_context *eq_dequeue(time_t now);
+static PRStatus eq_create(void);
+
+
+/* ******************************************************** */
+
+
+
+/*
+ * slapi_eq_once: cause an event to happen exactly once.
+ *
+ * Arguments:
+ * fn: the function to call
+ * arg: an argument to pass to the called function
+ * when: the time that the function should be called
+ * Returns:
+ * slapi_eq_context - a handle to an opaque object which
+ * the caller can use to refer to this particular scheduled
+ * event.
+ */
+Slapi_Eq_Context
+slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when)
+{
+ slapi_eq_context *tmp;
+ PR_ASSERT(eq_initialized);
+ if (!eq_stopped) {
+
+ Slapi_Eq_Context id;
+
+ tmp = eq_new(fn, arg, when, 0UL);
+ id = tmp->ec_id;
+
+ eq_enqueue(tmp);
+
+ /* After this point, <tmp> may have */
+ /* been freed, depending on the thread */
+ /* scheduling. Too bad */
+
+ slapi_log_error(SLAPI_LOG_HOUSE, NULL,
+ "added one-time event id 0x%x at time %u\n",
+ id, when);
+ return(id);
+ }
+ return NULL; /* JCM - Not sure if this should be 0 or something else. */
+}
+
+
+
+
+/*
+ * slapi_eq_repeat: cause an event to happen repeatedly.
+ *
+ * Arguments:
+ * fn: the function to call
+ * arg: an argument to pass to the called function
+ * when: the time that the function should first be called
+ * interval: the amount of time (in milliseconds) between
+ * successive calls to the function
+ * Returns:
+ * slapi_eq_context - a handle to an opaque object which
+ * the caller can use to refer to this particular scheduled
+ */
+Slapi_Eq_Context
+slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval)
+{
+ slapi_eq_context *tmp ;
+ PR_ASSERT(eq_initialized);
+ if (!eq_stopped) {
+ tmp = eq_new(fn, arg, when, interval);
+ eq_enqueue(tmp);
+ slapi_log_error(SLAPI_LOG_HOUSE, NULL,
+ "added repeating event id 0x%x at time %u, interval %u\n",
+ tmp->ec_id, when, interval);
+ return(tmp->ec_id);
+ }
+ return NULL; /* JCM - Not sure if this should be 0 or something else. */
+}
+
+
+
+/*
+ * slapi_eq_cancel: cancel a pending event.
+ * Arguments:
+ * ctx: the context of the event which should be de-scheduled
+ */
+int
+slapi_eq_cancel(Slapi_Eq_Context ctx)
+{
+ slapi_eq_context **p, *tmp = NULL;
+ int found = 0;
+
+ PR_ASSERT(eq_initialized);
+ if (!eq_stopped) {
+ PR_Lock(eq->eq_lock);
+ p = &(eq->eq_queue);
+ while (!found && *p != NULL) {
+ if ((*p)->ec_id == ctx) {
+ tmp = *p;
+ *p = (*p)->ec_next;
+ slapi_ch_free((void**)&tmp);
+ found = 1;
+ } else {
+ p = &((*p)->ec_next);
+ }
+ }
+ PR_Unlock(eq->eq_lock);
+ }
+ slapi_log_error(SLAPI_LOG_HOUSE, NULL,
+ "cancellation of event id 0x%x requested: %s\n",
+ ctx, found ? "cancellation succeeded" : "event not found");
+ return found;
+}
+
+
+
+
+/*
+ * Construct a new ec structure
+ */
+static slapi_eq_context *
+eq_new(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval)
+{
+ slapi_eq_context *retptr = (slapi_eq_context *)slapi_ch_calloc(1, sizeof(slapi_eq_context));
+ time_t now;
+
+ retptr->ec_fn = fn;
+ retptr->ec_arg = arg;
+ now = current_time();
+ retptr->ec_when = when < now ? now : when;
+ retptr->ec_interval = interval == 0UL ? 0UL : (interval + 999) / 1000;
+ retptr->ec_id = (Slapi_Eq_Context)retptr;
+ return retptr;
+}
+
+
+
+
+/*
+ * Add a new event to the event queue.
+ */
+static void
+eq_enqueue(slapi_eq_context *newec)
+{
+ slapi_eq_context **p;
+
+ PR_ASSERT(NULL != newec);
+ PR_Lock(eq->eq_lock);
+ /* Insert <newec> in order (sorted by start time) in the list */
+ for (p = &(eq->eq_queue); *p != NULL; p = &((*p)->ec_next)) {
+ if ((*p)->ec_when > newec->ec_when) {
+ break;
+ }
+ }
+ if (NULL != *p) {
+ newec->ec_next = *p;
+ } else {
+ newec->ec_next = NULL;
+ }
+ *p = newec;
+ PR_NotifyCondVar(eq->eq_cv); /* wake up scheduler thread */
+ PR_Unlock(eq->eq_lock);
+}
+
+
+
+
+/*
+ * If there is an event in the queue scheduled at time
+ * <now> or before, dequeue it and return a pointer
+ * to it. Otherwise, return NULL.
+ */
+static slapi_eq_context *
+eq_dequeue(time_t now)
+{
+ slapi_eq_context *retptr = NULL;
+
+ PR_Lock(eq->eq_lock);
+ if (NULL != eq->eq_queue && eq->eq_queue->ec_when <= now) {
+ retptr = eq->eq_queue;
+ eq->eq_queue = retptr->ec_next;
+ }
+ PR_Unlock(eq->eq_lock);
+ return retptr;
+}
+
+
+
+/*
+ * Call all events which are due to run.
+ * Note that if we've missed a schedule
+ * opportunity, we don't try to catch up
+ * by calling the function repeatedly.
+ */
+static void
+eq_call_all()
+{
+ slapi_eq_context *p;
+
+ while ((p = eq_dequeue(current_time())) != NULL) {
+ /* Call the scheduled function */
+ p->ec_fn(p->ec_when, p->ec_arg);
+ slapi_log_error(SLAPI_LOG_HOUSE, NULL,
+ "Event id 0x%x called at %u (scheduled for %u)\n",
+ p->ec_id, current_time(), p->ec_when);
+ if (0UL != p->ec_interval) {
+ /* This is a repeating event. Requeue it. */
+ do {
+ p->ec_when += p->ec_interval;
+ } while (p->ec_when < current_time());
+ eq_enqueue(p);
+ } else {
+ slapi_ch_free((void **)&p);
+ }
+ }
+}
+
+
+
+
+/*
+ * The main event queue loop.
+ */
+#define WORK_AVAILABLE ((NULL != eq->eq_queue) && (eq->eq_queue->ec_when <= current_time()))
+
+static void
+eq_loop(void *arg)
+{
+ while (eq_running) {
+ PRIntervalTime timeout;
+ int until;
+ PR_Lock(eq->eq_lock);
+ while (!WORK_AVAILABLE) {
+ if (!eq_running) {
+ PR_Unlock(eq->eq_lock);
+ goto bye;
+ }
+ /* Compute new timeout */
+ if (NULL != eq->eq_queue) {
+ until = eq->eq_queue->ec_when - current_time();
+ timeout = PR_SecondsToInterval(until);
+ } else {
+ timeout = PR_INTERVAL_NO_TIMEOUT;
+ }
+ PR_WaitCondVar(eq->eq_cv, timeout);
+ }
+ /* There is some work to do */
+ PR_Unlock(eq->eq_lock);
+ eq_call_all();
+ }
+bye:
+ eq_stopped = 1;
+ PR_Lock(ss_lock);
+ PR_NotifyAllCondVar(ss_cv);
+ PR_Unlock(ss_lock);
+}
+
+
+
+/*
+ * Allocate and initialize the event queue structures.
+ */
+static PRStatus
+eq_create(void)
+{
+ PR_ASSERT(NULL == eq->eq_lock);
+ if ((eq->eq_lock = PR_NewLock()) == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "eq_start PR_NewLock failed\n");
+ exit(1);
+ }
+ if ((eq->eq_cv = PR_NewCondVar(eq->eq_lock)) == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "eq_start PR_NewCondVar failed\n");
+ exit(1);
+ }
+ if ((ss_lock = PR_NewLock()) == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "eq_start PR_NewLock failed\n");
+ exit(1);
+ }
+ if ((ss_cv = PR_NewCondVar(ss_lock)) == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "eq_start PR_NewCondVar failed\n");
+ exit(1);
+ }
+ eq->eq_queue = NULL;
+ eq_initialized = 1;
+ return PR_SUCCESS;
+}
+
+
+
+
+
+/*
+ * eq_start: start the event queue system.
+ *
+ * This should be called exactly once. It will start a
+ * thread which wakes up periodically and schedules events.
+ */
+void
+eq_start()
+{
+ PR_ASSERT(eq_initialized);
+ eq_running = 1;
+ if ((eq_loop_tid = PR_CreateThread(PR_USER_THREAD, (VFP)eq_loop,
+ NULL, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL, "eq_init PR_CreateThread failed\n");
+ exit(1);
+ }
+ slapi_log_error(SLAPI_LOG_HOUSE, NULL, "event queue services have started\n");
+}
+
+
+
+/*
+ * eq_init: initialize the event queue system.
+ *
+ * This function should be called early in server startup.
+ * Once it has been called, the event queue will queue
+ * events, but will not fire any events. Once all of the
+ * server plugins have been started, the eq_start()
+ * function should be called, and events will then start
+ * to fire.
+ */
+void
+eq_init()
+{
+ if (!eq_initialized) {
+ PR_CallOnce(&init_once, eq_create);
+ }
+}
+
+
+
+/*
+ * eq_stop: shut down the event queue system.
+ * Does not return until event queue is fully
+ * shut down.
+ */
+void
+eq_stop()
+{
+ slapi_eq_context *p, *q;
+
+ if ( NULL == eq || NULL == eq->eq_lock ) { /* never started */
+ eq_stopped = 1;
+ return;
+ }
+
+ eq_stopped = 0;
+ eq_running = 0;
+ /*
+ * Signal the eq thread function to stop, and wait until
+ * it acknowledges by setting eq_stopped.
+ */
+ while (!eq_stopped) {
+ PR_Lock(eq->eq_lock);
+ PR_NotifyAllCondVar(eq->eq_cv);
+ PR_Unlock(eq->eq_lock);
+ PR_Lock(ss_lock);
+ PR_WaitCondVar(ss_cv, PR_MillisecondsToInterval(100));
+ PR_Unlock(ss_lock);
+ }
+ (void)PR_JoinThread(eq_loop_tid);
+ /*
+ * XXXggood we don't free the actual event queue data structures.
+ * This is intentional, to allow enqueueing/cancellation of events
+ * even after event queue services have shut down (these are no-ops).
+ * The downside is that the event queue can't be stopped and restarted
+ * easily.
+ */
+ PR_Lock(eq->eq_lock);
+ p = eq->eq_queue;
+ while (p != NULL) {
+ q = p->ec_next;
+ slapi_ch_free((void**)&p);
+ /* Some ec_arg could get leaked here in shutdown (e.g., replica_name)
+ * This can be fixed by specifying a flag when the context is queued.
+ * [After 6.2]
+ */
+ p = q;
+ }
+ PR_Unlock(eq->eq_lock);
+ slapi_log_error(SLAPI_LOG_HOUSE, NULL, "event queue services have shut down\n");
+}
+
+/*
+ * return arg (ec_arg) only if the context is in the event queue
+ */
+void *
+slapi_eq_get_arg ( Slapi_Eq_Context ctx )
+{
+ slapi_eq_context **p;
+
+ PR_ASSERT(eq_initialized);
+ if (!eq_stopped) {
+ PR_Lock(eq->eq_lock);
+ p = &(eq->eq_queue);
+ while (p && *p != NULL) {
+ if ((*p)->ec_id == ctx) {
+ PR_Unlock(eq->eq_lock);
+ return (*p)->ec_arg;
+ } else {
+ p = &((*p)->ec_next);
+ }
+ }
+ PR_Unlock(eq->eq_lock);
+ }
+ return NULL;
+}
diff --git a/ldap/servers/slapd/extendop.c b/ldap/servers/slapd/extendop.c
new file mode 100644
index 00000000..8044f2f3
--- /dev/null
+++ b/ldap/servers/slapd/extendop.c
@@ -0,0 +1,297 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* extendedop.c - handle an LDAPv3 extended operation */
+
+#include <stdio.h>
+#include "slap.h"
+
+static const char *extended_op_oid2string( const char *oid );
+
+
+/********** this stuff should probably be moved when it's done **********/
+
+static void extop_handle_import_start(Slapi_PBlock *pb, char *extoid,
+ struct berval *extval)
+{
+ char *suffix;
+ Slapi_DN *sdn = NULL;
+ Slapi_Backend *be = NULL;
+ struct berval bv;
+ int ret;
+
+ if (extval == NULL || extval->bv_val == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "extop_handle_import_start: no data supplied\n", 0, 0, 0);
+ send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
+ "no data supplied", 0, NULL);
+ return;
+ }
+ suffix = slapi_ch_malloc(extval->bv_len+1);
+ strncpy(suffix, extval->bv_val, extval->bv_len);
+ suffix[extval->bv_len] = 0;
+
+ sdn = slapi_sdn_new_dn_byval(suffix);
+ if (!sdn) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "extop_handle_import_start: out of memory\n", 0, 0, 0);
+ send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
+ return;
+ }
+ /* be = slapi_be_select(sdn); */
+ be = slapi_mapping_tree_find_backend_for_sdn(sdn);
+ slapi_sdn_free(&sdn);
+ if (be == NULL || be == defbackend_get_backend()) {
+ /* might be instance name instead of suffix */
+ be = slapi_be_select_by_instance_name(suffix);
+ }
+ if (be == NULL || be == defbackend_get_backend()) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "bulk import: invalid suffix or instance name '%s'\n",
+ suffix, 0, 0);
+ send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL,
+ "invalid suffix or instance name", 0, NULL);
+ goto out;
+ }
+
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot );
+
+ {
+ /* Access Control Check to see if the client is
+ * allowed to use task import
+ */
+ char *dummyAttr = "dummy#attr";
+ char *dummyAttrs[2] = { NULL, NULL };
+ int rc = 0;
+ char dn[128];
+ Slapi_Entry *feature;
+
+ /* slapi_str2entry modify its dn parameter so we must copy
+ * this string each time we call it !
+ */
+ sprintf(dn, "dn: oid=%s,cn=features,cn=config",
+ EXTOP_BULK_IMPORT_START_OID);
+
+ dummyAttrs[0] = dummyAttr;
+ feature = slapi_str2entry(dn, 0);
+ rc = plugin_call_acl_plugin (pb, feature, dummyAttrs, NULL,
+ SLAPI_ACL_WRITE, ACLPLUGIN_ACCESS_DEFAULT, NULL);
+ slapi_entry_free(feature);
+ if (rc != LDAP_SUCCESS)
+ {
+ /* Client isn't allowed to do this. */
+ send_ldap_result(pb, rc, NULL, NULL, 0, NULL);
+ goto out;
+ }
+ }
+
+ if (be->be_wire_import == NULL) {
+ /* not supported by this backend */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "bulk import attempted on '%s' (not supported)\n",
+ suffix, 0, 0);
+ send_ldap_result(pb, LDAP_NOT_SUPPORTED, NULL, NULL, 0, NULL);
+ goto out;
+ }
+
+ ret = SLAPI_UNIQUEID_GENERATE_TIME_BASED;
+ slapi_pblock_set(pb, SLAPI_LDIF2DB_GENERATE_UNIQUEID, &ret);
+ ret = SLAPI_BI_STATE_START;
+ slapi_pblock_set(pb, SLAPI_BULK_IMPORT_STATE, &ret);
+ ret = (*be->be_wire_import)(pb);
+ if (ret != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "extop_handle_import_start: error starting import (%d)\n",
+ ret, 0, 0);
+ send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
+ goto out;
+ }
+
+ /* okay, the import is starting now -- save the backend in the
+ * connection block & mark this connection as belonging to a bulk import
+ */
+ PR_Lock(pb->pb_conn->c_mutex);
+ pb->pb_conn->c_flags |= CONN_FLAG_IMPORT;
+ pb->pb_conn->c_bi_backend = be;
+ PR_Unlock(pb->pb_conn->c_mutex);
+
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, EXTOP_BULK_IMPORT_START_OID);
+ bv.bv_val = NULL;
+ bv.bv_len = 0;
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, &bv);
+ send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Bulk import: begin import on '%s'.\n", suffix, 0, 0);
+
+out:
+ slapi_ch_free((void **)&suffix);
+ return;
+}
+
+static void extop_handle_import_done(Slapi_PBlock *pb, char *extoid,
+ struct berval *extval)
+{
+ Slapi_Backend *be;
+ struct berval bv;
+ int ret;
+
+ PR_Lock(pb->pb_conn->c_mutex);
+ pb->pb_conn->c_flags &= ~CONN_FLAG_IMPORT;
+ be = pb->pb_conn->c_bi_backend;
+ pb->pb_conn->c_bi_backend = NULL;
+ PR_Unlock(pb->pb_conn->c_mutex);
+
+ if ((be == NULL) || (be->be_wire_import == NULL)) {
+ /* can this even happen? */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "extop_handle_import_done: backend not supported\n",
+ 0, 0, 0);
+ send_ldap_result(pb, LDAP_NOT_SUPPORTED, NULL, NULL, 0, NULL);
+ return;
+ }
+
+ /* signal "done" to the backend */
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ slapi_pblock_set(pb, SLAPI_BULK_IMPORT_ENTRY, NULL);
+ ret = SLAPI_BI_STATE_DONE;
+ slapi_pblock_set(pb, SLAPI_BULK_IMPORT_STATE, &ret);
+ ret = (*be->be_wire_import)(pb);
+ if (ret != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "bulk import: error ending import (%d)\n",
+ ret, 0, 0);
+ send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, NULL, 0, NULL);
+ return;
+ }
+
+ /* more goofiness */
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_OID, EXTOP_BULK_IMPORT_DONE_OID);
+ bv.bv_val = NULL;
+ bv.bv_len = 0;
+ slapi_pblock_set(pb, SLAPI_EXT_OP_RET_VALUE, &bv);
+ send_ldap_result(pb, LDAP_SUCCESS, NULL, NULL, 0, NULL);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Bulk import completed successfully.\n", 0, 0, 0);
+ return;
+}
+
+
+void
+do_extended( Slapi_PBlock *pb )
+{
+ char *extoid = NULL, *errmsg;
+ struct berval extval = {0};
+ int lderr, rc;
+ unsigned long len, tag;
+ const char *name;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_extended\n", 0, 0, 0 );
+
+ /*
+ * Parse the extended request. It looks like this:
+ *
+ * ExtendedRequest := [APPLICATION 23] SEQUENCE {
+ * requestName [0] LDAPOID,
+ * requestValue [1] OCTET STRING OPTIONAL
+ * }
+ */
+
+ if ( ber_scanf( pb->pb_op->o_ber, "{a", &extoid )
+ == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=extended; params=OID)\n",
+ 0, 0, 0 );
+ op_shared_log_error_access (pb, "EXT", "???", "decoding error: fail to get extension OID");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
+ NULL );
+ goto free_and_return;
+ }
+ tag = ber_peek_tag(pb->pb_op->o_ber, &len);
+
+ if (tag == LDAP_TAG_EXOP_REQ_VALUE) {
+ if ( ber_scanf( pb->pb_op->o_ber, "o}", &extval ) == LBER_ERROR ) {
+ op_shared_log_error_access (pb, "EXT", "???", "decoding error: fail to get extension value");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
+ NULL );
+ goto free_and_return;
+ }
+ } else {
+ if ( ber_scanf( pb->pb_op->o_ber, "}") == LBER_ERROR ) {
+ op_shared_log_error_access (pb, "EXT", "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0,
+ NULL );
+ goto free_and_return;
+ }
+ }
+ if ( NULL == ( name = extended_op_oid2string( extoid ))) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "do_extended: oid (%s)\n", extoid, 0, 0 );
+
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d EXT oid=\"%s\"\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid, extoid );
+ } else {
+ LDAPDebug( LDAP_DEBUG_ARGS, "do_extended: oid (%s-%s)\n",
+ extoid, name, 0 );
+
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d EXT oid=\"%s\" name=\"%s\"\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid, extoid, name );
+ }
+
+ /* during a bulk import, only BULK_IMPORT_DONE is allowed!
+ * (and this is the only time it's allowed)
+ */
+ if (pb->pb_conn->c_flags & CONN_FLAG_IMPORT) {
+ if (strcmp(extoid, EXTOP_BULK_IMPORT_DONE_OID) != 0) {
+ send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL);
+ goto free_and_return;
+ }
+ extop_handle_import_done(pb, extoid, &extval);
+ goto free_and_return;
+ }
+
+ if (strcmp(extoid, EXTOP_BULK_IMPORT_START_OID) == 0) {
+ extop_handle_import_start(pb, extoid, &extval);
+ goto free_and_return;
+ }
+
+ slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_OID, extoid );
+ slapi_pblock_set( pb, SLAPI_EXT_OP_REQ_VALUE, &extval );
+ rc = plugin_call_exop_plugins( pb, extoid );
+
+ if ( SLAPI_PLUGIN_EXTENDED_SENT_RESULT != rc ) {
+ if ( SLAPI_PLUGIN_EXTENDED_NOT_HANDLED == rc ) {
+ lderr = LDAP_PROTOCOL_ERROR; /* no plugin handled the op */
+ errmsg = "unsupported extended operation";
+ } else {
+ errmsg = NULL;
+ lderr = rc;
+ }
+ send_ldap_result( pb, lderr, NULL, errmsg, 0, NULL );
+ }
+free_and_return:
+ if (extoid)
+ slapi_ch_free((void **)&extoid);
+ if (extval.bv_val)
+ slapi_ch_free((void **)&extval.bv_val);
+ return;
+}
+
+
+static const char *
+extended_op_oid2string( const char *oid )
+{
+ const char *rval = NULL;
+
+ if ( 0 == strcmp(oid, EXTOP_BULK_IMPORT_START_OID)) {
+ rval = "Netscape Bulk Import Start";
+ } else if ( 0 == strcmp(oid, EXTOP_BULK_IMPORT_DONE_OID)) {
+ rval = "Netscape Bulk Import End";
+ } else {
+ rval = plugin_extended_op_oid2string( oid );
+ }
+
+ return( rval );
+}
diff --git a/ldap/servers/slapd/factory.c b/ldap/servers/slapd/factory.c
new file mode 100644
index 00000000..b4ef0585
--- /dev/null
+++ b/ldap/servers/slapd/factory.c
@@ -0,0 +1,458 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slap.h"
+
+/*
+ * This module provides a mechanism for extending core server objects.
+ * This functionality is provided to plugin writers so that they may
+ * efficiently pass state information between plugin calls. Typically
+ * a plugin might register both a pre-op and post-op call. It's very
+ * convenient for the plugin to associate it's private data with the
+ * operation object that's passed through the PBlock.
+ *
+ * --- An interface is made available to the core server.
+ *
+ * int factory_register_type(const char *name, size_t offset)
+ * void *factory_create_extension(int type,void *object,void *parent)
+ * void factory_destroy_extension(int type,void *object,void *parent,void **extension)
+ *
+ * An object that wishes to make itself available for extension must
+ * register with the Factory. It passes it's name, say 'Operation',
+ * and an offset into the structure of where the extension block
+ * is to be stored. In return a type handle is passed back, which is
+ * used in place of the name in the creation and destruction calls.
+ *
+ * When an object is created, which has registered as extensible, it
+ * must call the factory_create_extension with its type handle so that
+ * the extension block can be constructed. A pointer to the block is
+ * returned that *must* be stored in the object structure at the offset
+ * declared by the call to factory_register_type.
+ *
+ * When an extensible object is destroyed the extension block must also
+ * be destroyed. The factory_destroy_extension call is provided to
+ * tidy up and free any extenions created for this object.
+ *
+ * --- An interface is made available to the plugins.
+ *
+ * int slapi_register_object_extension(
+ * const char* objectname,
+ * slapi_extension_constructor_fnptr constructor,
+ * slapi_extension_destructor_fnptr destructor,
+ * int *objecttype,
+ * int *extensionhandle)
+ * void *slapi_get_object_extension(int objecttype,void *object,int extensionhandle)
+ *
+ * When the plugin is initialised it must register its object extensions.
+ * It must provide the name of the object to be extended, say 'Operation',
+ * and constructor and destructor functions. These functions are called
+ * when the object is constructed and destroyed. The extension functions
+ * would probably allocate some memory and initialise it for its
+ * own use. The registration function will fail if any objects have already
+ * been created. This is why the registration *must* happen during plugin
+ * initialisation. In return the plugin will receive two handles, one for
+ * the object type, and one for the object extension. These only have meaning
+ * for the slapi_get_object_extension function.
+ *
+ * A plugin retrieves a pointer to its own extension by calling slapi_get_
+ * object_extension with the object from which the extension is to be
+ * retrieved. The factory uses the objecttype to find the offset into the
+ * object of where the extension block is stored. The extension handle is
+ * then used to find the appropriate extension within the block.
+ *
+ * Currently (Oct 98) the only supported objects are Operation and Connection.
+ *
+ * This documentation is available here...
+ *
+ * http://warp/server/directory-server/hydra/replication/objext.html
+ */
+
+/* JCM: Could implement simple object leak detection here */
+
+
+/* ---------------------- Factory Extension ---------------------- */
+
+struct factory_extension
+{
+ const char *pluginname;
+ slapi_extension_constructor_fnptr constructor;
+ slapi_extension_destructor_fnptr destructor;
+};
+
+static struct factory_extension*
+new_factory_extension(
+ const char *pluginname,
+ slapi_extension_constructor_fnptr constructor,
+ slapi_extension_destructor_fnptr destructor)
+{
+ struct factory_extension* fe= (struct factory_extension*)slapi_ch_malloc(sizeof(struct factory_extension));
+ if(pluginname!=NULL)
+ {
+ fe->pluginname= slapi_ch_strdup(pluginname);
+ }
+ fe->constructor= constructor;
+ fe->destructor= destructor;
+ return fe;
+}
+
+static void
+delete_factory_extension(struct factory_extension **fe)
+{
+ slapi_ch_free( (void **) &((*fe)->pluginname) );
+ slapi_ch_free( (void **) fe);
+}
+
+/* ---------------------- Factory Type ---------------------- */
+
+#define MAX_EXTENSIONS 32
+
+struct factory_type
+{
+ char *name; /* The name of the object that can be extended */
+ int extension_count; /* The number of extensions registered for this object */
+ PRLock *extension_lock; /* Protect the array of extensions */
+ size_t extension_offset; /* The offset into the object where the extension pointer is */
+ long existence_count; /* Keep track of how many extensions blocks are in existence */
+ struct factory_extension *extensions[MAX_EXTENSIONS]; /* The extension registered for this object type */
+};
+
+static struct factory_type*
+new_factory_type(const char *name, size_t offset)
+{
+ struct factory_type* ft= (struct factory_type*)slapi_ch_malloc(sizeof(struct factory_type));
+ ft->name= slapi_ch_strdup(name);
+ ft->extension_lock = PR_NewLock();
+ ft->extension_count= 0;
+ ft->extension_offset= offset;
+ ft->existence_count= 0;
+ return ft;
+}
+
+static void
+delete_factory_type(struct factory_type **ft)
+{
+ slapi_ch_free( (void **) &((*ft)->name));
+ PR_DestroyLock((*ft)->extension_lock);
+ slapi_ch_free( (void **) ft);
+}
+
+static int
+factory_type_add_extension(struct factory_type *ft,struct factory_extension *fe)
+{
+ int extensionhandle= -1;
+ PR_Lock(ft->extension_lock);
+ if(ft->existence_count>0)
+ {
+ /* Can't register an extension if there are objects already with extension blocks */
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Registration of %s extension by %s failed.\n", ft->name, fe->pluginname, 0);
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %lu %s objects already in existence.\n", ft->existence_count, ft->name, 0);
+ }
+ else
+ {
+ if(ft->extension_count<MAX_EXTENSIONS)
+ {
+ extensionhandle= ft->extension_count;
+ ft->extensions[ft->extension_count]= fe;
+ ft->extension_count++;
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Registration of %s extension by %s failed.\n", ft->name, fe->pluginname, 0);
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %d extensions already registered. Max is %d\n", ft->extension_count, MAX_EXTENSIONS, 0);
+ }
+ }
+ PR_Unlock(ft->extension_lock);
+ return extensionhandle;
+}
+
+static void
+factory_type_increment_existence(struct factory_type *ft)
+{
+ ft->existence_count++;
+}
+
+static void
+factory_type_decrement_existence(struct factory_type *ft)
+{
+ ft->existence_count--;
+ if(ft->existence_count<0)
+ {
+ /* This just shouldn't happen */
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %lu %s object extensions in existence.\n", ft->extension_count, ft->name, 0);
+ }
+}
+
+/* ---------------------- Factory Type Store ---------------------- */
+
+#define MAX_TYPES 16
+
+static PRLock *factory_type_store_lock;
+static struct factory_type* factory_type_store[MAX_TYPES];
+static int number_of_types= 0;
+
+static void
+factory_type_store_init()
+{
+ int i= 0;
+ factory_type_store_lock= PR_NewLock(); /* JCM - Should really free this at shutdown */
+ for(i=0;i<MAX_TYPES;i++)
+ {
+ factory_type_store[number_of_types]= NULL;
+ }
+}
+
+static int
+factory_type_store_add(struct factory_type* ft)
+{
+ int type= number_of_types;
+ factory_type_store[type]= ft;
+ number_of_types++;
+ return type;
+}
+
+static void
+factory_type_store_remove(struct factory_type *ft)
+{
+ int i;
+ int found_it = 0;
+
+ for (i = 0; i < number_of_types; i++)
+ {
+ if (!found_it)
+ {
+ if (factory_type_store[i] == ft)
+ {
+ found_it = 1;
+ }
+ }
+ else
+ {
+ factory_type_store[i-1] = factory_type_store[i];
+ }
+ }
+
+ if (found_it)
+ {
+ factory_type_store[i-1] = NULL;
+ number_of_types--;
+ }
+}
+
+static struct factory_type*
+factory_type_store_get_factory_type(int type)
+{
+ if(type>=0 && type<number_of_types)
+ {
+ return factory_type_store[type];
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+static int
+factory_type_store_name_to_type(const char* name)
+{
+ int i;
+ for(i=0;i<number_of_types;i++)
+ {
+ if(strcasecmp(factory_type_store[i]->name,name)==0)
+ {
+ return i;
+ }
+ }
+ return -1;
+}
+
+/* ---------------------- Core Server Functions ---------------------- */
+
+/*
+ * Function for core server usage.
+ * See documentation at head of file.
+ */
+int
+factory_register_type(const char *name, size_t offset)
+{
+ int type= 0;
+ if(number_of_types==0)
+ {
+ factory_type_store_init();
+ }
+ PR_Lock(factory_type_store_lock);
+ if(number_of_types<MAX_TYPES)
+ {
+ struct factory_type* ft= new_factory_type(name,offset);
+ type= factory_type_store_add(ft);
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Registration of %s object failed.\n", name, 0, 0);
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: %d objects already registered. Max is %d\n", number_of_types, MAX_TYPES, 0);
+ type= -1;
+ }
+ PR_Unlock(factory_type_store_lock);
+ return type;
+}
+
+/*
+ * Function for core server usage.
+ * See documentation at head of file.
+ */
+void *
+factory_create_extension(int type,void *object,void *parent)
+{
+ int n;
+ void **extension= NULL;
+ struct factory_type* ft= factory_type_store_get_factory_type(type);
+
+ if(ft!=NULL)
+ {
+ PR_Lock(ft->extension_lock);
+ if((n = ft->extension_count)>0)
+ {
+ int i;
+ factory_type_increment_existence(ft);
+ PR_Unlock(ft->extension_lock);
+ extension= (void**)slapi_ch_malloc(n*sizeof(void*));
+ for(i=0;i<n;i++)
+ {
+ slapi_extension_constructor_fnptr constructor= ft->extensions[i]->constructor;
+ if(constructor!=NULL)
+ {
+ extension[i]= (*constructor)(object,parent);
+ }
+ }
+ }
+ else
+ {
+ /* No extensions registered. That's OK */
+ PR_Unlock(ft->extension_lock);
+ }
+ }
+ else
+ {
+ /* The type wasn't registered. Programming error? */
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Object type handle %d not valid. Object not registered?\n", type, 0, 0);
+ }
+ return (void*)extension;
+}
+
+/*
+ * Function for core server usage.
+ * See documentation at head of file.
+ */
+void
+factory_destroy_extension(int type,void *object,void *parent,void **extension)
+{
+ if(extension!=NULL && *extension!=NULL)
+ {
+ struct factory_type* ft= factory_type_store_get_factory_type(type);
+ if(ft!=NULL)
+ {
+ int i,n;
+
+ PR_Lock(ft->extension_lock);
+ n=ft->extension_count;
+ factory_type_decrement_existence(ft);
+ PR_Unlock(ft->extension_lock);
+ for(i=0;i<n;i++)
+ {
+ slapi_extension_destructor_fnptr destructor= ft->extensions[i]->destructor;
+ if(destructor!=NULL)
+ {
+ void **extention_array= (void**)(*extension);
+ (*destructor)(extention_array[i],object,parent);
+ }
+ }
+ }
+ else
+ {
+ /* The type wasn't registered. Programming error? */
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Object type handle %d not valid. Object not registered?\n", type, 0, 0);
+ }
+ slapi_ch_free(extension);
+ }
+}
+
+/* ---------------------- Slapi Functions ---------------------- */
+
+/*
+ * Function for plugin usage.
+ * See documentation at head of file.
+ */
+int
+slapi_register_object_extension(
+ const char* pluginname,
+ const char* objectname,
+ slapi_extension_constructor_fnptr constructor,
+ slapi_extension_destructor_fnptr destructor,
+ int *objecttype,
+ int *extensionhandle)
+{
+ int rc= 0;
+ struct factory_extension* fe;
+ struct factory_type* ft;
+ fe= new_factory_extension(pluginname,constructor, destructor);
+ *objecttype= factory_type_store_name_to_type(objectname);
+ ft= factory_type_store_get_factory_type(*objecttype);
+ if(ft!=NULL)
+ {
+ *extensionhandle= factory_type_add_extension(ft,fe);
+ if(*extensionhandle==-1)
+ {
+ delete_factory_extension(&fe);
+ factory_type_store_remove(ft);
+ delete_factory_type(&ft);
+ }
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR: factory.c: Plugin %s failed to register extension for object %s.\n", pluginname, objectname, 0);
+ rc= -1;
+ }
+ return rc;
+}
+
+/*
+ * Function for plugin usage.
+ * See documentation at head of file.
+ */
+void *
+slapi_get_object_extension(int objecttype,void *object,int extensionhandle)
+{
+ void *object_extension= NULL;
+ struct factory_type* ft= factory_type_store_get_factory_type(objecttype);
+ if(ft!=NULL)
+ {
+ char *object_base= (char*)object;
+ void **o_extension= (void**)(object_base + ft->extension_offset);
+ void **extension_array= (void**)(*o_extension);
+ if ( extension_array != NULL ) {
+ object_extension= extension_array[extensionhandle];
+ }
+ }
+ return object_extension;
+}
+
+/*
+ * sometimes a plugin would like to change its extension, too.
+ */
+void
+slapi_set_object_extension(int objecttype, void *object, int extensionhandle,
+ void *extension)
+{
+ void *object_extension = NULL;
+ struct factory_type *ft = factory_type_store_get_factory_type(objecttype);
+ if (ft != NULL) {
+ char *object_base = (char *)object;
+ void **o_extension = (void **)(object_base + ft->extension_offset);
+ void **extension_array= (void**)(*o_extension);
+ if (extension_array != NULL) {
+ extension_array[extensionhandle] = extension;
+ }
+ }
+}
diff --git a/ldap/servers/slapd/fe.h b/ldap/servers/slapd/fe.h
new file mode 100644
index 00000000..f1e8dae6
--- /dev/null
+++ b/ldap/servers/slapd/fe.h
@@ -0,0 +1,159 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _SLAPD_FE_H_
+#define _SLAPD_FE_H_
+
+#include <prio.h>
+#include "slap.h"
+
+/*
+ * Global Variables...
+ */
+#ifdef LDAP_DEBUG
+#if defined( _WIN32 )
+#ifndef DONT_DECLARE_SLAPD_LDAP_DEBUG
+extern __declspec(dllimport) int slapd_ldap_debug;
+#endif /* DONT_DECLARE_SLAPD_LDAP_DEBUG */
+#endif
+#endif
+extern int active_threads;
+extern PRInt32 ops_initiated;
+extern PRInt32 ops_completed;
+extern PRLock *ops_mutex;
+extern PRThread *listener_tid;
+extern PRThread *listener_tid;
+extern int num_conns;
+extern PRLock *num_conns_mutex;
+extern char *pid_file;
+extern char *start_pid_file;
+extern int should_detach;
+extern int connection_type; /* JCM - Evil. Solve by creating a real connection constructor & destructor */
+#ifndef HAVE_TIME_R
+extern PRLock *time_func_mutex;
+#endif /* HAVE_TIME_R */
+extern PRLock *currenttime_mutex;
+extern time_t starttime;
+extern char *configfile;
+#if defined( _WIN32 )
+extern LPTSTR pszServerName;
+#endif
+#if defined( _WIN32 )
+/* String constants (no change for international) */
+extern HANDLE hSlapdEventSource;
+extern SERVICE_STATUS LDAPServerStatus;
+extern SERVICE_STATUS_HANDLE hLDAPServerServiceStatus;
+#endif
+
+/*
+ * auth.c
+ *
+ */
+void client_auth_init();
+void handle_handshake_done (PRFileDesc *prfd, void* clientData);
+int handle_bad_certificate (void* clientData, PRFileDesc *prfd);
+
+/*
+ * connection.c
+ */
+void op_thread_cleanup();
+
+/*
+ * ntuserpin.c - Prompts for the key database passphrase.
+ */
+#include "svrcore.h"
+typedef struct SVRCORENTUserPinObj SVRCORENTUserPinObj;
+SVRCOREError SVRCORE_CreateNTUserPinObj(SVRCORENTUserPinObj **out);
+void SVRCORE_SetNTUserPinInteractive(SVRCORENTUserPinObj *obj, PRBool interactive);
+void SVRCORE_DestroyNTUserPinObj(SVRCORENTUserPinObj *obj);
+
+/*
+ * connection.c
+ */
+void connection_abandon_operations( Connection *conn );
+int connection_activity( Connection *conn );
+void init_op_threads();
+int connection_new_private(Connection *conn);
+void connection_remove_operation( Connection *conn, Operation *op );
+int connection_operations_pending( Connection *conn, Operation *op2ignore,
+ int test_resultsent );
+void connection_done(Connection *conn);
+void connection_cleanup(Connection *conn);
+void connection_reset(Connection* conn, int ns, PRNetAddr * from, int fromLen, int is_SSL);
+
+/*
+ * conntable.c
+ */
+
+/*
+ * Note: the correct order to use when acquiring multiple locks is
+ * c[i]->c_mutex followed by table_mutex.
+ */
+struct connection_table
+{
+ int size;
+ /* An array of connections, file descriptors, and a mapping between them. */
+ Connection *c;
+ struct POLL_STRUCT *fd;
+ PRLock *table_mutex;
+};
+typedef struct connection_table Connection_Table;
+
+extern Connection_Table *the_connection_table; /* JCM - Exported from globals.c for daemon.c, monitor.c, puke, gag, etc */
+
+Connection_Table *connection_table_new(int table_size);
+void connection_table_free(Connection_Table *ct);
+void connection_table_abandon_all_operations(Connection_Table *ct);
+Connection *connection_table_get_connection(Connection_Table *ct, int sd);
+void connection_table_move_connection_out_of_active_list(Connection_Table *ct, Connection *c);
+void connection_table_move_connection_on_to_active_list(Connection_Table *ct, Connection *c);
+void connection_table_as_entry(Connection_Table *ct, Slapi_Entry *e);
+void connection_table_dump_activity_to_errors_log(Connection_Table *ct);
+Connection* connection_table_get_first_active_connection (Connection_Table *ct);
+Connection* connection_table_get_next_active_connection (Connection_Table *ct, Connection *c);
+typedef int (*Connection_Table_Iterate_Function)(Connection *c, void *arg);
+int connection_table_iterate_active_connections(Connection_Table *ct, void* arg, Connection_Table_Iterate_Function f);
+#if defined( _WIN32 )
+Connection* connection_table_get_connection_from_fd(Connection_Table *ct,PRFileDesc *prfd);
+#endif
+#if 0
+void connection_table_dump(Connection_Table *ct);
+#endif
+
+/*
+ * daemon.c
+ */
+int signal_listner();
+int daemon_pre_setuid_init(daemon_ports_t *ports);
+void slapd_daemon( daemon_ports_t *ports );
+void daemon_register_connection();
+int slapd_listenhost2addr( const char *listenhost, PRNetAddr *addr );
+int daemon_register_reslimits( void );
+int secure_read_function( int ignore , void *buffer, int count, struct lextiof_socket_private *handle );
+int secure_write_function( int ignore, const void *buffer, int count, struct lextiof_socket_private *handle );
+int read_function(int ignore, void *buffer, int count, struct lextiof_socket_private *handle );
+int write_function(int ignore, const void *buffer, int count, struct lextiof_socket_private *handle );
+PRFileDesc * get_ssl_listener_fd();
+int configure_pr_socket( PRFileDesc **pr_socket, int secure );
+void configure_ns_socket( int * ns );
+
+/*
+ * sasl_io.c
+ */
+int sasl_read_function(int ignore, void *buffer, int count, struct lextiof_socket_private *handle );
+int sasl_write_function(int ignore, const void *buffer, int count, struct lextiof_socket_private *handle );
+int sasl_io_enable(Connection *c);
+int sasl_recv_connection(Connection *c, char *buffer, size_t count,PRInt32 *err);
+
+/*
+ * sasl_map.c
+ */
+int sasl_map_config_add(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int sasl_map_config_delete(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+int sasl_map_domap(char *sasl_user, char *sasl_realm, char **ldap_search_base, char **ldap_search_filter);
+int sasl_map_init();
+int sasl_map_done();
+
+#endif
diff --git a/ldap/servers/slapd/fedse.c b/ldap/servers/slapd/fedse.c
new file mode 100644
index 00000000..e2779e08
--- /dev/null
+++ b/ldap/servers/slapd/fedse.c
@@ -0,0 +1,1886 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * fedse.c - Front End DSE (DSA-Specific Entry) persistent storage.
+ *
+ * The DSE store is an LDIF file contained in the file
+ * INSTANCEDIR/config/dse.ldif, where INSTANCEDIR is
+ * the directory of the server instance.
+ *
+ * In core, the DSEs are stored in an AVL tree, keyed on
+ * DN. Whenever a modification is made to a DSE, the
+ * in-core entry is updated, then dse_write_file() is
+ * called to commit the changes to disk.
+ *
+ * This is designed for a small number of DSEs, say
+ * a maximum of 10 or 20. Currently, there is only
+ * one DSE, the root DSE. If large numbers of DSEs
+ * need to be stored, this approach of writing out
+ * the entire contents on every modification will
+ * be insufficient.
+ *
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <prio.h>
+#include <prcountr.h>
+#include "slap.h"
+#include "fe.h"
+
+#if !defined (_WIN32)
+#include <pwd.h>
+#endif /* _WIN32 */
+
+extern char ** getSupportedCiphers();
+
+static const char *internal_entries[] =
+{
+ "dn:\n"
+ "objectclass: top\n"
+ "aci: (targetattr != \"aci\")(version 3.0; aci \"rootdse anon read access\"; allow(read,search,compare) userdn=\"ldap:///anyone\";)\n",
+
+ "dn:cn=features,cn=config\n"
+ "objectclass:top\n"
+ "objectclass:nsContainer\n"
+ "cn:features\n",
+
+ "dn:oid=2.16.840.1.113730.3.4.9,cn=features,cn=config\n"
+ "objectclass:top\n"
+ "objectclass:directoryServerFeature\n"
+ "oid:2.16.840.1.113730.3.4.9\n"
+ "cn: VLV Request Control\n"
+ "aci: (targetattr != \"aci\")(version 3.0; acl \"VLV Request Control\"; allow( read, search, compare, proxy ) userdn = \"ldap:///all\";)\n",
+
+ "dn:oid="EXTOP_BULK_IMPORT_START_OID",cn=features,cn=config\n"
+ "objectclass:top\n"
+ "objectclass:directoryServerFeature\n"
+ "cn: Bulk Import\n",
+
+ "dn:cn=options,cn=features,cn=config\n"
+ "objectclass:top\n"
+ "objectclass:nsContainer\n"
+ "cn:options\n",
+
+ "dn:cn=encryption,cn=config\n"
+ "objectclass:top\n"
+ "objectclass:nsEncryptionConfig\n"
+ "cn:encryption\n"
+ "nsSSLSessionTimeout:0\n"
+ "nsSSLClientAuth:allowed\n"
+ "nsSSL2:off\n"
+ "nsSSL3:off\n",
+
+ "dn:cn=monitor\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:monitor\n"
+ "aci: (target =\"ldap:///cn=monitor*\")(targetattr != \"aci || connection\")(version 3.0; acl \"monitor\"; allow( read, search, compare ) userdn = \"ldap:///anyone\";)\n",
+
+ "dn:cn=snmp,cn=monitor\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:snmp\n",
+
+ "dn:cn=counters,cn=monitor\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "cn:counters\n",
+
+ "dn:cn=sasl,cn=config\n"
+ "objectclass:top\n"
+ "objectclass:nsContainer\n"
+ "cn:sasl\n",
+
+ "dn:cn=mapping,cn=sasl,cn=config\n"
+ "objectclass:top\n"
+ "objectclass:nsContainer\n"
+ "cn:mapping\n",
+
+ "dn:cn=SNMP,cn=config\n"
+ "objectclass:top\n"
+ "objectclass:nsSNMP\n"
+ "cn:SNMP\n"
+ "nsSNMPEnabled:on\n"
+ "nsSNMPOrganization:\n"
+ "nsSNMPLocation:\n"
+ "nsSNMPContact:\n"
+ "nsSNMPDescription:\n"
+ "nsSNMPMasterHost:\n"
+ "nsSNMPMasterPort:\n"
+ "aci:(target=\"ldap:///cn=SNMP,cn=config\")(targetattr !=\"aci\")(version 3.0;acl \"snmp\";allow (read, search, compare)(userdn = \"ldap:///anyone\");)\n",
+};
+
+static int NUM_INTERNAL_ENTRIES = sizeof(internal_entries)/sizeof(internal_entries[0]);
+
+static char *easter_egg_entry=
+{
+"1E14405A150F47341F0E09191B0A1F5A3E13081F190E1508035A2E1F1B1756191447171514"
+"130E1508701518101F190E39161B0909405A0E150A701518101F190E39161B0909405A1508"
+"1D1B1413001B0E1315141B162F14130E701518101F190E39161B0909405A1E13081F190E15"
+"0803040E1F1B17041F020E1F14091318161F041518101F190E70150F405A341F0E09191B0A"
+"1F5A291F190F08130E035A2915160F0E1315140970150F405A341F0E09191B0A1F5A3E1308"
+"1F190E1508035A2E1F1B17701E1F091908130A0E131514405A3E1B0C131E5A3815081F121B"
+"17565A301B190B0F1F1613141F5A3815081F121B17565A3B140E121514035A3C15020D1508"
+"0E12565A3B161511705A5A3D15141E121B161F111B08565A3508161B5A321F1D1B080E0356"
+"5A3415081311155A3215091513565A341B0E121B145A3113141E1F08565A3E1F15145A361B"
+"19111F0356705A5A2E1215171B095A361B19111F03565A281319125A371F1D1D1314091514"
+"565A2D1316165A371508081309565A3F161613150E5A291912161F1D1F161713161912565A"
+"705A5A371B08115A2917130E12565A5A2815185A2D1F160E171B14565A2F161C5A2D1F160E"
+"171B14565A5A39121F090E15145A2D131616131B1709701E1F091908130A0E131514405A3B"
+"141E5A1B16165A0E121F5A150E121F08095A0D12155A121B0C1F5A1D15141F5A181F1C1508"
+"1F5A0F095470705A70707070"
+};
+
+#define NUM_EASTER_EGG_PHOTOS 3
+
+static const char *easter_egg_photo1 =
+"jpegphoto:: /9j/4AAQSkZJRgABAgAAZABkAAD/7AARRHVja3kAAQAEAAAAHgAA/+4ADkFkb2JlAGTAAAAA"
+"Af/bAIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMv"
+"L0BAQEBAQEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzAr"
+"LicnJy4rNTUwMDU1QEA/QEBAQEBAQEBAQEBA/8AAEQgBewHnAwEiAAIRAQMRAf/EAKgAAAID"
+"AQEBAAAAAAAAAAAAAAQFAgMGAQAHAQADAQEBAAAAAAAAAAAAAAAAAQIDBAUQAAIBAwIDBQYD"
+"BQUFBwQDAAECAwARBCESMUEFUWFxIhOBkaEyFAaxQiPB0VIzFeFicoKS8KKyQyTxwlM0JTUW"
+"0uJzg/JjkxEAAgIBBAEDAwIFBAMAAAAAAAERAiExQRIDUWFxIoEyE1IEkaHBQiPwseFi0XIz"
+"/9oADAMBAAIRAxEAPwDNRpcMb2VQSCeFxpbxqYkIvtIVbBSdbXH76aR46C8U4ADRX5m8hHK3"
+"940E2MqKSNBtU8NfONfdeseaZUE8eOO6Dam8CzBzxIa5IPKwohbvGgI9Ro7FuwF23248gKEn"
+"ikgkQuxZiLFOwniB4VYilIpV1UqdDe+4HS/vqHGslaFrY43bksscpICq2qFTrfwqeQjQpH5X"
+"MWrb2Fka5Fl8QKrV2jygioHZbgAi9iQra+6u5mS07Isy3Ubl2HTaSSbAjShTKFnwQVQwaUED"
+"b8ykX3HbuueyrE9SNGnQEJYElgLany6VAH9IopJZQN1zcEHmNOVSzQ8eq6xunlIFrqDwokGc"
+"DiaVHYEMT5teK2vbjVebGZVMse677ShDcBzDDUGpqsog9bdqlxe1z5iB8eVWMkxxwyy7CRqR"
+"+W//APHjQ25QRgUrmyodsouFN+Vx28u6m2DaRo5IwNqkPtOl7eY8B8KTZeO8TXdmYm12Itc1"
+"XBkzY7gxyGM3sCDwrS1eSwyJawayXbHaSS6tcqg4gE226t2dtCuHaEhRaxPqAak2NgV99JW6"
+"jNLA8c0jO1/KxPbyql2lgjVxOCz/AJEJuPGs10tbj5DxvRg2GR9vpqAxI01YaewVATwGVv1h"
+"tYENr8qlfdSQ52TY3bcpB0bXjVKkufKpJP5V/sql1eWLl6GoiUSWkZg25ShI57uY8KXf0b1p"
+"XLyEJYkyNqd3Hb8aVR5U8LmzEMNNDRa9YyEVY0eyn52Iv3cKOF19rHK3Q0XHxulRtINpljIB"
+"LcWYBTp43NIZHUylillPLgdanLlZEsnqs5dr3BI07OFVLG8u9+OwbmJPfaqpV1l2ctibnQ80"
+"pKBWN1X5ewa1C4bhoOZq30gYmYpqCLG4FrX0tRqpCMVUx45JXchpQFIjvptFz7eBqm4CCiPp"
+"2Q+55V2xwoZSW0ut9unjVDIuhivbna+1fbzpr1TEaFY5sqb1SyhWSK4VDa4Tncjneg4kd3/U"
+"crDFa0a+ZmBF9APiaStiZCNimbHCSLArepIbbj+UE6m3bRkUGVhRxZBQbGJBBtqRbW9U4kCS"
+"vkxtodoEdyAb7hcAnSniKZcaPpmQg9YKCsYvYi1+J56VN7RC18lJF0GbHkhGVSkpYEo1gQL7"
+"bjtGtU9Wf0MNikjJul3Mm7Ugj99URStJF9MCIss3VCCD5EvcXF+PChMmbLkzCZf1CAFtt0rN"
+"U+XiMwNvAJJNktGx22hlYDThuXs99dxDkjHmCPsjIu7E29ntorISNRHjYswVW8027QK47KqX"
+"NDwJiuoeNWJ3KdpOvOtdsIiPU7jYLlklmt6b/KCdSD4VZnvgokkccX6l7B7m620t30Nl9QWW"
+"R1giEIYBAq+awBvxq2DAeVv+qkCKYmljJO7dYE/GlDmbOPQeNEheGXdYcK83OqVte99at486"
+"1gmB3hpn4no5MCPPjzojyBAAd2qgH20xaOXIBMqskZNjHcHaW5m3IV3ouFjTdFgchVmYuPVW"
+"+9Qh48fdVkUVx6kkjDHU7tpHFhwLNqbVy3ct4yi3XGBflNtknZb+nGiKreBF65jJiyZGPMHO"
+"9UuLi/6t2tvoeXI9dnga6Y3qEiVbmO7a2Y2qcCqsK+g4ZEciSULYqLEWBJ18apJpEQHZE4jx"
+"WiWIvIoUSHivnvrfv5Upg9Y3jVtrSaC4+YqPl/fRHSUny2kgLEbxuLkkqqDuphnRJGY5IVt9"
+"OrK1vLxU8u+hQnx1G4xALgjb/wBXkFI0IHqEgnhrbWmKT40iiT0wGPCVhwHctJscATQzZDho"
+"YxudCrDnpxHfTGDLiypzEPIFBNv4rd9R2Vct5eP4CgOklMO4MdEGjP2ngAKAeXIyDFOsR3jy"
+"ofyndpotdcxZRI3bkj1YaWBA/Nzq7Nc/TxiJvSeELcd54a1KWi3AX5yxY+Qs9i21hv0uGIoG"
+"QvNlBEVQRqOQ11pvk47Zm2bY3oRXEi6A3B+Ve80vGD6rqYmsHU2I7lvxrWrUJvXQAOUrjysq"
+"OTItiHvz5iuwtk5Eh9J7SseN7Ht41WMZjO0Ol1J1OlEY/pYWSrMPVdSA6Ecf8NaPTy4EXSpn"
+"xMpyg2mgl+Ye+r8qCV1iaA6myMd3mZjwNuw0zyshJ4kxpBckqUA02gr2js4caFkjgxyWcpsI"
+"ssZF9wW3Pjf3VlyUoBUks+NMwldlax8tyQT/AGUyh6sJoFVSFe4V/wCI3Op1q5ZOmRxRTSRl"
+"jLuZDbygoDxBsbe2gJMCKV48uSRZYJTa8QYN/pIGutU6Jrk1oMYwzYyNcOFK6l/mPaB3eNRn"
+"6nJeVYlDhjZVI5DmKD+vgw1jjSDayi0it8+7iOXKuP1HIkmaQxNCI1LDaoDa663rNUzMClhx"
+"kWSCFtqvG5BJ+UK5Pxoz1YhjXMZuTuJCm9Ioup75EZkBgS14lGp28KNw8vLyVky5ZlhxUfSK"
+"1207DRattxhkk6LCufuO1rkgAHaxAXzdlVZMEM2EciVyYLi7W12AggVJuoQS48u9gYWJ23AU"
+"MD7OZFL83qh82LFKDALDYvAqQOfaKda5WopPPJFl5imA+nIjBolUabRxJ7729lFQ9NxYsR5Z"
+"SHY2DuW1vfW1AYcuFjyvKNwGxlY9xZRYc+fGpSZE2XkxY8BtAOIY2FudOybwpqktQDBi9OlH"
+"r46FUjJ9ZtxAKi9xavUSkMcSfRbr7o2AHMBuP416sZf/AG4+QgEPqS5iqmi7lJX+6PObe6uu"
+"NrAEXRUba1rDd6rbd3vFFIiS5RKtZXRXdT+Wyqy27Ryqua7xRPMhWOV5QCON122/G9am0YFq"
+"xSSeg7eZkm2NfUEmx5UYuIzYcsk9lb5UXQ7lLFrjw/fRMBMLO0YG5yEBHG4u7t7bVwRMkXp2"
+"ZolO8seJbazBaHOiCAeVTvkUaEI242G6+3jVEeL6xl9UaAFwD83AL++ipFjlP6IJTaSSw81y"
+"NtjbsuKjhv6uTGbFlJKEcC9wT+yhToJlMMLfq22s51a3Cw10+Huq9AjRiFr6rblZSb6ipZEW"
+"PjCOSNi3lN1A5NcG9TI2yPBtAW8YDdgBKqfjQx7QVY4JQKy7ZZHVTcWuD8t6teKKU5CfIUUp"
+"Go1G4FbaeHDxqyWISOo3kn0Yyzka2Rb8u38a9LHFuYxkRul/WF9AVN2t32F6WQ0AZIlbZuFp"
+"EZWdbXA/IT76VfS4YlkZ2M0guVRBoSxrRTGMS7UiWZXREkbcRuBG3y7TzNL8mFsHIfJijVce"
+"NSskbaHcbjb43/fV0b0Ja3EuR0+bGiSdiCJOA56C+tC2O7UceFqZFMjKQ5U42Q2G0X43O2yj"
+"2UFKpLXC210FbJ+dSXqUm5GpsRpbuqxMmSMEQn07jzFdL1wwsNzGwCkBtdRepQYhyZhFCSbg"
+"nW3AU8CRXdtu1h311IJZLFF0JsL8yNaZ/RYmTisMUgZEY85kYKLLt4X53oMQ+mISkoVpFB48"
+"CSR+FJWn0HBQiyOSV82mtdhQvKsSkrvYAns8aYYixYeO8uUhkaQmOOG1iHTa2/XsBoaJt7fU"
+"s6o0flAK+Ykgtfs46UTrAQNem9Pwb5AZPUlgYBw4vwBvt8CD7LUZ9TFj4ZmxiZfSDLc8L6rv"
+"9zV7puQozkULf1LyPID+m5IbTw83woXr50GPjLaJfPJY32nW48Ky1tk00WBbLmT5GNtn/kRH"
+"RVsCXbXcx51Tiyv69w7KjrskIsW9PmBeqv8AqMhtkYLWG4qOxRxriwP6TTcNpC2B1JrWFEGc"
+"5k0KYGOcnHMaho9pYMLAG19u5e3to7qQglx0ZJVhngPlmNhu2ggoGFzfWgoLv0gJcs+3yvx2"
+"MxPtAI4cqGxiBLEiZCs5O8xyC+0nyrY/xVjnWdC/6l8EMuDKZReQySMr7SAbJrc3/ivQOVJm"
+"wvBBYrkITezXe5bg1OOorkYk0U8eOqSzFh6rkbDpsAuOw6+ak8mVHbISCEyS21ygd23Xa3Ln"
+"eqUvOoPwDpjerkFUUyyAkut7/wCI34WFRjjO1/LtQDzHmbH8tSxpZBAYbem24kkEhpNPlY34"
+"VWssJ8rEiw1Gt7r+UeNXkmDkbLGfVtuQ3BX8wHDXxqcOU6QOC6yBYyqqwuVDG3lPtvVQjdh6"
+"kYsBrbsr0uN5d24bmFyovxFPG4gdRY1YBc6VWqEnWpxrpf4VQGv+1caVsD1iymFHcheLb9AT"
+"2cKKz45JDbB2GOB7kEXAB+aw/MNao+03v058e+pmbs5qv7q7LmLg5rQyqzGVyEN97bDbTlXN"
+"aeVmlOTSVCBHxHx5X+mZcuGQC2ARbcp43PDymhMroMibJEk9H6hijRAnRgN9uPDlT1o4cVjH"
+"ZoxPdRJe4G4W8tz2mqsmM58MMeHOrzQkiUEhNxJH5vmqa9v0FKf/ACLej4bh5MkkmCL9NgNN"
+"zHXb5reNWQ5Es7HduZJGu7NwF7hW91OvTdV2SC8ZjVtosLEW3WA433H3ClOSk+TH6aRvGd25"
+"mcBCqj5RQrTZvBLWcEo+mmbD1ezM5G78wUEgLbvqvM6fDEpUMEd4zYC5I2i1vE1fleqnTt4u"
+"H9RrjTbu7D3d9EYrbUgVITaQfqMSGbdp5mY8qWdXYOPlg2MkCYuPJPaHAkIQtEb3kOmvhVss"
+"MORk/TxMrRYu0vIRuLk/lv2qKaTS4ZwmgWIBUbaq2AFzY7l770vjMUYeNSBJcWhA1Peal3S0"
+"mRtpYR55tvrmJVLxfqqFF7N8o9wquHbkBJtqxxRqAEGhG8bW91QjxMv1JI5CBGzfqMhs21ba"
+"adpoWV5kncIvlmkBFrm1v4KpNPCZEhE3TYMpiXLI7MWQ7fmA0PDl30LJ09I8MQKoeaRv5wGn"
+"zbgATRedkNFj7AzL642MxJvtPE93fQ8GbgRzIqsbwixDaXYDiviaptwozANlK4uYkAilcRxq"
+"fJuuWN+S91LpZ8mF/RkLAA6WAvtPfrTyXMjnWLJsBGCCFY32tfbreheqzqAMcRKHyF3+pzUf"
+"3fCiryk0nIirHERKzZE7NBGGRV0Juw8wseRvaicXqWN6h9FDobkCwAIG1XXhypV9NkRj1/SP"
+"05JCX0NgOJqfqRQ+izB0ZTukvoGXgbHl5a0dJ3b9ikgqPEkyMmWeaNnUOd7tqbMO0cCLVYuB"
+"kuHlnk3XJCqGs1iL+Y6U7wi2YI0CmFYgrqpAAdeXCiJ8EsjSsQZLgqqjzWvqLeFTnSDTijPT"
+"dNlxFaeNAI0spI1NmtbXmReoZfR51hBD2QEi4vYjVuQ561qZ8eM4ixG4W50tqwI1PdXUx5PS"
+"WNWBMNrbrWJvf9tKWHFNmLmx8ZcWxZnIZN7G+iFhu2jttS7KDJkPCb+jG7bBflfQ+6tPNhva"
+"eO24EOp9PQ3I0B9prORvDLDbJJ3BQEIHHxNbUyiLKCzHn9KJ1TzRvY+Ya+XlTPBgGdslVTFH"
+"Cu4spGrKeHtpRj4zmRlTUgE6a0y6Q0u7YiFZL3aTUrbvWpvprAl4Yy/p26Qzq7hlILHiTqXI"
+"94r1FtsGOqJIRGSWMnM30NeqOX/ZxH8yoRyDHCyCeVf5kUdwOA9QqCp/0CqeovIIgzLtELq5"
+"Rb23Fdo08RR8YX0XjDFhGLPc2ZbA3v8ACgMuGVsF5A7M6CN3BI8x2ttb3moWpoymMGyDcCYy"
+"VMnDVgdxP+mjnb9G+2wCFnOp3NtVfAcaCBAmlKEfonfa1uChG/fRhKJBZbHdsUgkhrMPcTbW"
+"qhiKY98GNOwYFtAgGp2EroTVYVCnrHymAMQBwJJa3DxrptsZEuY7gXOhYLryomOQPDIqoACd"
+"u0A63G5bHxpACyRM87ILBhsYknQB7MwHfUo4nGYsbeYFh5TxKgXvr2GvM+yciNS7pGAoPHy3"
+"83javAkZpZ7ho5FBZfmGrFrX7hThgFRRBJ44jYDciAmw3KEN7/5taodFFnd9C28WGu0Da1/G"
+"uy+mJAHPrLEQxBNj6b34c9NalGwlUyAhrjcpA0NgUb40hlSJGiASbdpj3vxJ2sbKF7Cp1rpx"
+"jkp6eV5rMWAbk17ebtFuHcagSsckMafq23h+/T/YUTkxSLFBLFuUgIpB8t1QbR4cNacNCQNk"
+"wxTRBWiuu8LGL2AIIJF7dhpfLgLLnZDWsgT9Phobfl7qOlmk9MlbhiQdgFwdq7X1v2LUFhOR"
+"ZmFiEcoeFyugAt/iq1hCaTYFHirHhNjpCZ8qRlcPwVUsS17876Uujxc2bKdkI9QCzFRoLj5f"
+"KK2CqxiRiV9VlCmQKdGjGot2/tpdirZXVQEdAWjBHzcefbrehW1E6mfdYooQXjIkYXZGP5fl"
+"v+2mC9MyV9DMw4/VbaPIRu2n5x3cKKnGFDK2VkGzbNqqbsfIwIC/4qV5XWepIfTS+MjeZQuh"
+"I1sb+001L0/mLC1JZMmZDkxZOZ509Q2hY+UWsCLHgKBaKN4neNgCH27WNjYjja1XMZ5sePKc"
+"AmNjGWPBrDcN16tx+nvJkxLkG3rAu6jRlUa34dmoqphE66FOLm5GIb47FlUEPcaeYWIr0s+d"
+"mb5Xa4Ita4W4HGw52phl/beXisXx3E0Wp2toxCi5uKvi6DHk46ZWVL9OXuFQWCrb99LnXXA4"
+"toZ9RJGu4XW9xfgCp0OtOkiRsaPEVI1Z1MsTsbsSQNwdhwsKY5+IrYkONhxolm9MMRfdddT/"
+"AL1EJ0rHMUUVtksMlmZRx3qPm/Gpd5XgpVgV5bQTYCIu9EwkAaReEuthttxuSDrwoObp8rRx"
+"TQfIV3NfivPd5daYSZuIcRMGIO8cSsJJDooHbyvc/wBlKsvqciSsuLL+kY1jUBbWQch7RRVW"
+"2C3qSyOpZE+NH0/JYenASVJWzam53UJ9QUUpAx28DyJ9gocNI7FmJJa+p1JNXY2HlZEghjTz"
+"nj2acya14rQgI37woCnciWJNitxe5taqocWOWS7yemliWbjc8gAO2nMfRI0gLOrycCzqDtHw"
+"quF8bEyI1RBIRIDGCPM27y7GIOq0uNllD9wKDpmWyyFkcxxFVYgE2La2tQ4dUZwWYEAqARYG"
+"3I01lknlllKo+OZ5A5guVUiMcCSdT4UJnelO4eBQJCtpbi17fmHGpTbfuECsWABPE8qIiRWI"
+"5X4VxICV2kqT460XgYE+SzvGt4oLGU9gJsKtgkN+mdF6nLEWhl9GNuG24JNSyMPPw8hWmHqS"
+"L8sh4m/ZWrxGgxceISGyqoFgKNyFxpccOdpjIuCbD/irLWWaxXSDKPiHqUILqyzIvk1OxwD5"
+"7kD8aGcdOwplaNLzKw3XvcAdhPZVc/Usc5EsjSgBQ6Qxxk6sjHVwvFT30HAWzZDjw2ADF5H5"
+"WsVNr+NZPr8tqq1M7JbBy9dgml+n9O8Lki7G1u/dU3LQMTNKTjL8iKLlifMAe2hF6GyI+5rA"
+"DeP4vKOFW4+bO2GrSkBQ20AgD5jZSDU8euPiQMXyIZImRWUq6gAhS5NwbrtXnV2KIxisiq0q"
+"o1okf9PdfT5dWsOWtIsPbivJMxLM5dBbk4HDvverP6zlxIscR8yEjebNoeQuO6rrSJSqmvLK"
+"qs6D6VxLAsYBhksChisPNaxVbCho/llaIgtc75T3cr0ngyvuCYNJFLdV+VWRCL+xRV+J1SZr"
+"Q5USo48osCO6xHf20W67WeWmirUer0DYZJHjjkCXRvmO61wb+/XlXXijij9YlfUUsF2i+nyk"
+"ip7kEPkG3HUbgoFjuGvA0ow36tkbzBCMki9pLbVF++4F/ZS66cm+K+0j0SJ5eTLLAWZQWitc"
+"W118t7+HGlIVXkSRpFF9Ru1YEcqbTS5uHEwz4GETCzXGhJ4XZaAkbHEPk3B5G0HILWyo66rU"
+"UZK8Zgi2fzKHuwsSDpa48K5kPeUSAtZtNpve3ZTXGhh9IJpfkLgVHIjjVCtwG5XIuK04LzlF"
+"OuJKMMSmF013y+UOVc3HhbQjlTCXAgYeh6DSzFrliyqtiAl3vcjUcKqWUSrjSIQxSyzgX8hX"
+"UPR8OS9lKKFDOGlN76t3m5Otqws2i1BXjvnYUcfrH1sNbWMd3kiVANDcAstN4MmPMCTQaowN"
+"2uLNcC3hxoQkMgi3ek20h1U2bykpYbfjVGN05UAbClfEcAM23VWbQEtGbjjUc/OCoGuhY7Au"
+"xLGwc2W+vZQMxlx2EXrqsjkAA3fUG+oburkeRnY8ZXJiXJjA0yoiAf8AMj6+6hz137dOW+RL"
+"kKHNwPKxuRz0U2om1vtU+wPG8e4P1DMy4InkORG4QkIoXbua+ugNZ+GPHXYjvuMoLOttoRr9"
+"vPStRkf0/OR/pZI542tbbZit9T3i9Z2fprxdQy4Y1Lrjta3cRcVp1Ws8PUydXrMlvSQkPU40"
+"ckRSgqwGpOl7cadPDBHGXxWtA9gFfW4rOY0u3Nh/NdxuUG2p0rTgI6LeMwlCFZQRa3C/l7aq"
+"7h5UyaUqn9C+CLG+kkdnRYgh2JxJe3Lu769VCIzRslwpQk2bgQTay6V6oxEesyVwUTktZR6j"
+"Ri4MgLSdpOwjXu0rzYqPjPGhZg6IhQLc7YyTx7q4LDKlUNb1NxXUk7gpNeiLpiFySjnRWGut"
+"wPwBFZxG4gM4wWSZ3FmcsFY2ADjyj8KtyGcyaqQrhF4fMUHlNuVhUXLxzi3mgRxvB/MSDuP+"
+"7VWVLtyIg7XG1kBsR4WPhaqX9Bf+SFyygMN23yrrZb31Y+y1GRszxsEFp4yzoeIYrqPwtS6W"
+"QeYL5EV2uON7G1EtkxnGUC8ckNxre7a+cDvIIptMEdJWNkLeZtAqj+Aq11Ptq5Hgs87HcAOL"
+"aHzswbQ6aGg8zIhZfUuSzbWW3JWFnW3fUsff6iIbemoBkIs4523cL6m9OMZFOQqK0yNPLffK"
+"LhV1ATXu1tf3UEjyQ2xz54wG22/ML/l/xAUzhu7pISGChVW3ltfRrr22NBZCGKdSq2Qgbgdd"
+"WJ07amryN6SQiRQ25m3MwawXUbjw+FHTPGI44t1rEK4A4vwe3tNAOJU+TaRuBB5Dfx9x0tQR"
+"fqE2aIyhWGM+YXuLX1JPDdVqjtnYSf1D8uZA4RNVWylAOZVwzA8edSxiJUZi1kgZQGOm4HRT"
+"w0+WkbdQfFyzHO29Y2IVrX4Cw8RTKJ127omukhUoVN9NfbxpurSgUjFW/UM7nyMzRkjQsdF3"
+"bRwOv7aFYmJFZ/lO4kngGtof31dNPHLjrsaz7grJbbcBfm/fVCneqK7A3IFiBcW4HXSpQ5Fp"
+"hy87ID7QsQuQpuPKTa48K9lHGknlYSKBDtFmF1GwBdqjvotnkSfyG2oCHl2V7F6fgyLIsl3M"
+"pYgklb/3quSUXZXS4JcjBnxFWNGUvkJrYlTodh7RV+Bit9fPPlne0RtHpYekAQx2jhV0TIvy"
+"gp6YWMg/w2UV3Cnx1lyHw7PInp7kW7aszbt3bepUtwVGQ4xS5sTR4MTAcS7A6n/E3bSXqH2p"
+"1LFhOX9QGkHmKEacdK3c5yI8QnGQNNYWQ8L++s99z5ebixw47qrjIUmRhptYHUCtojQdYfj+"
+"ogTq+McdHnIjyopLSREaEbLXHLjTRvSmwpnSzvNEwYrY6xjdxHMBqyHUmaOdiPz2PstUoOqT"
+"/SjCjG1eZGhO7QjTlas317ol2y0SyovTsigFdgZ1Q7h7e+gHCqN40a9iL/Ci5Xia5jbUm2y9"
+"lt2DnVUOFNLvkVf5Yu+741Sfklts5FCzI0psigXsON+XHtp39vfTlmcjyu6IeZIHG3jS+fBZ"
+"VDmRWEiNJsF1UFOI8baitT9oQEzxZLRja+9L20BCp5h401bKGq/yUjnLzeqfTtHgdP2i1l9R"
+"QF9oJFYbrPTcv6lpS0TE3JELCwPHgOFfRJMWNZciSee++OxQmwX+9WSGN07+nCWOR2zQ+2RS"
+"fLxPAdlqqfYtVTXkRZ2YZceABzvMSJNf5fLy7j22pn9rdLx+ozPNkLux4QAI76Mx7fCkOWFa"
+"R4x+S5OnPhWs+08Wbp+Nk7zv2yD5eY2g0qwiYljPL+0uiThj6Hpu/wCdDYi3ZSnCxpvt/qpx"
+"mvkYfUEMSN+ZXW5G7tp7H1VZxIfSYLCNxYagjupH1Hr0Alwsxo2GOk9n4XsVIvbup2ygiGjV"
+"RQxvCpcC41FC5yKMZmf5IkdwvO668KuWeKNQrm8DaxuNRY6gaVm/uLrcTJNi4zeq7Ltcg6Kp"
+"4/hWSUo05QhQPTU2QFbk3LW3G4FxpQzZBxntjMYEI2uFHmPtrQfa+Fi5AkyMwA48AA3MbLu4"
+"60x6vH9szQGcmERk7BKg/Nbh5edX8UojlszNUdt43MunXHlIgnuR+Z11drDRbeNcR5ZIDHM6"
+"pEVuCBYyEElRSySFYs9Gx23Rl/03te9j2G1X+qIzeTzFH+S9/L/CvGotRbJLcmIlFy5L7jrd"
+"HuArakXG3cD20x6N0yDIVZ3O9b6r3igMh4YpWfGKhZkBCcdoPEHdwNNOn4eRDAscM5UqxJK8"
+"Dr30V0biC+pS3g0KJEsVo1AUC2lZrr6hZ0kA0PlLD+LiKaOsuVGiM7A2IaxIvbS9U5vT8Z8Q"
+"RSnd8tzYAmx7rUJ5k6LJtQUrN9cscFxbbeVk01OhX21osKFI4URFCqgsAOApF07HYTHeg2Qt"
+"siYG10B5+ym308yZKTCW8fD0xpcUUaj4+WY9axITkqkkbJIoMbCzA6gjvrC5+PDBvKLb0ZCL"
+"3/Lfyj2Vq9ue0rOz7oWJ04BR4WrMdbuRIq+Z5jt2gcbHQjvrWbNRE6Cu0mmVHDR41d5VCyHy"
+"iwBB8bcK9NixPO5glS72N7hrWGuutqXYMm9xFkSFIBpJyuvMd1T6j9FA1+mzFozfcOfvpJMH"
+"dcdBx05duMXU3O4h9up2i3xqzHTNzduPhJeNTctw+NLsMzrgAJGzFbySONRe1+IrY9BVMHpc"
+"Rm8rON7EC991Twau3Zb4kVWraCifE6rjkPKhcLdifmFzxOmtFdOynmj+piJkRFCyoxswYHWz"
+"a+6nsufiKiu7eV9FNuNZnq8ydLkmyII1MOUUK202vruO0doFHZ11tWVqgnj7Cn7m6rk52d/T"
+"sLcsCgXQeXe5FzuvyF6WN9v9SiTeyixGgGv7KZ9KkEvVZs+YWaQAgKDxJ4ADwrSx5+NMrqqs"
+"fTBLAixtVV+NUljBVaq2XufPU+qwpg67opFOjDlbt7RW16RMuVgZPUCyDMzAwcdjIu02tprQ"
+"GZNg5rSRrHtOo3XF+fIUnxvqMZipYxqrNrf83DSnfNJ3T1M7ri8FsuNkYzbpV2gm6uO6tRIu"
+"1fOdbcSOZseXjWfw40yIpPqXLya7E7+0mjYeqZUcgiyI/VBCgFRwHI258K57OcboOu6Q1kUG"
+"dDe4C7Sdey40r1DQ5rl5G9Bke5NiQQwF9B316lP+5ryXr/AkQRPMQwj9Jw40vYAMDqPZUIJb"
+"Y4jmO9Qu9CdOLWue216HWddshJuGbeAOQu4sag+x4YyzXkDPsKnnrIo15UcdCJL3lBZCw8iB"
+"SxXixLD83tqvqU2O88LBiA5kJYny3OhsO5hVUcp9KRGPygE7e5r0NnEerCSdCmo5BrcvEWq1"
+"XKE3g8jNIza6gi4/Lx/bRoUZEd5CA6rujFgLi5HKlsTEENqFY2PYQtX6yIo3bbC2n5bty99O"
+"yEmQybMhY2GqpYcgCPN8Kugbeq48J2s25XHCwvz8aFnkCb1e7FgoJ5qRcW92tW4+T5CiqAyi"
+"+7tO42vTawE5Hyyo49NiA0agsbaAnyNfnQs0jMdboLbmvxA7/dQ0MoaNw7fqyFrk6E7gLj2G"
+"vSuZZRcnRRz/AITWVaw2U7SjmTMYoocYHduk3Bv7t7ge+ttjR4i4CxOY77d0iXHHjqKwTv8A"
+"UdZgikNl3ongLitn9L0HGy3llazY0Y9XcSUG7tHbWy8ehSSjfWcGM+5Y8GTJlTFZWKi4K8Lj"
+"jrS7pEjmORQ2iMGVeev/AGUbL/TTPkmBy53MU00Ka0p6WSkjv+XQH33qmsQT2ayaMOkgJceQ"
+"mykkkjd83uoUSski7vOL/Mey/CqYMhwPNZVvdSSbk1x2BmNr7AbW4i54ioiJIkuLMMrYOBuN"
+"172a3dUDnTmZl9DzgFQb8Bfda+nZVUjESrf5dvz94HH2VXkOkiAoxsFuwBtrxuT7acB7EMnq"
+"mRMpjW8VmJYoTrftpx9mdWxem5c6ZjgRzILPYnzobjh23rOCTZ5VHzDUcbg1ZDHKXVUW7OwV"
+"F5lm0Ap6LAk8n1zNmmMSLjhmMjqGKWuE4ki5HZWW+7ch3yIY23Kq8ENja9r8DWoZZYYI3W29"
+"VXcDwJtWN6tntnTlnjRCjEXUa6aamiXubVhLCEXVRuniVFDdu7Qe+o9KwIJ2kXJlCLGCQguN"
+"zX+XdyuL1J2DncSCztcfuFdWWSJrlQ5vuYHgSDce6pdnEIh5bYQsOP6uUuzYY/JENGFge06l"
+"rcbVOCRRDJvXcs9gyMNbqRp4EUMMlHVzp60txLxDFe63bf4VwTRsDjXIQ8Ct/LYHQX5GiBFu"
+"XkyrjtB6fkv5JCLWOu/aewXtTpeqN0/oeF9GwWddxPPi17G9Z55A2LFFGNU3BiRqd/KnGNih"
+"4ooupmSFZCFi2RkhBa49Q8geXPnQ6WcQtyq2SbnwbOB8TKgTNJKHLiViN1gRa9j4XrJdVgjw"
+"8l2QrsYXCKxawGtarE6UknSMbGyBZ4ksGU22mkmf9sZDsYokLIfz7r6d541UWmFBVbV4vJhB"
+"+o0mvmck3vyvWy+1uozy4zRzKPUhIRiPzi17t30CvS+gQucP6h3zZTYSRL6kSHXyHUDcfhTP"
+"oHRJ0wJJoDuSSQtCTZWsPL5h2aVdqNJmVbZDsrOWBGEYjAe4ZW8ntrK/dmVGcfGx0RV8zSHb"
+"wOlr05zsvKEiwTYbNIpsGV9q+29Zj7jxcsdQ3yeYMgKa6W/MFHZelWWirWWBh0L7k9LAkwsx"
+"2PoDdjk3JK6Wiv48L0AVWGUtI25Dq/aToW48b2NAKnpxbPzGzNV52tCXBO5SLBjfy8aVq5JV"
+"tPQ+oRx9OGDJPHGrY86iVUjGh0sAAOdI/urGw8fpuNjLAI19T1CFI4lfNfvpX9ldQyFz/oL7"
+"op1LbTyKDd5fGmn3PPHM/wBOyPG6i92IVfG1talYcG1YeW53M/lx9PSVJsNW9BQGCubm9vNx"
+"pVJtJuvlsLkHtJJovMkAVFA/TFxfvoA7joTqNSTTS3M7vMFgtI4O0EfmHstWi6XlH6Yqp8yA"
+"ArzsBakUGFlyreONrEaMRZQPE0Z0wXknjRgZ4mv/AIh8p/276WHKQUtFkPYnIAKq5PiLC/8A"
+"mrmdKFjuTuKgn3VWuXZCBHaTgTfn4VRki2LLLIbWVtl+Je2gA560oN7XUYOdOzJJmLKbkMJG"
+"tfg7AAU/mbcoBUsvJg203pb0PomYmAuRJG0P8aS6EgG91Xj4XpqQ6L5AGHYamqab9zLreGVM"
+"xEW1QRcWCk34d9B9U6KBjSZMJIzJIyoa9hcgADsF6OjieSZLgXLDyip5nTsssfTmZBa3pt50"
+"+P767OiNW4nH0OfvbbjwfPBeFWdEuG04WKMNGW1V42/Iljj2ed5BqewG9rVp83psb5jK6mKa"
+"YXIALIxA+ZW/EGgMaCHGPqxRl5rtFGb2s50ZvYKqvVZdqTU1b1E+yro4cWS0HfT44IzNGrFv"
+"We6RqN22+jMeQFO44MZoUSVd4jsEJHZQ+Bgx40Koi62G49p76NVSLkcGsT7Rzp/ulVvknpgP"
+"2tmlxejyDt9O+2NkvtJuluApL9zqksKY0MQAA3KzHbttwt231p+ywcQo3DW9yayOV/UMzPZp"
+"IjAGCkq6/Kg5+YCuO7aqdF2mT6VgYihoJ33KUAZr21u+4A916N3dJ6duSO6rIrAkDduNJeqE"
+"4caPiqTsF5X1K2c2DX8aFwpsfJjZp5S1iwCMpawJ5bXXlTo5qn9CuuyiB/i/01ofWVQJCC2o"
+"vSDLWN3lcXDK7EAAjcCSTQuVkx484XHkbbtIIA2hddNtyfxp306PKfCikHyKC0pewuGJbn40"
+"dtuNE/8AsT2WnB6BIZcVcjDiH1B02sbHXTjfXWiIIcuRUlmTZsBXawswKEkEV5M7GhAjncKV"
+"baVAA19n5ajH1fGmO6QlQpsgJ+YDiSP31zQ238fWTNF4ZZVE7kbolMiEDixG6x8LV6ro8hVj"
+"aRoowpuVNu23sr1HKvnH9TT8iiIM88gRhtYlWsW76ugyFCBmX9RLbezhbhQJ+XtFtakj2U37"
+"dPEV0cSJLw5s1jqe3xvVMkplZBbUHQ9/CuMwJJ5cKpbiLcP2mnApCYjqFY6AE391eaTRypIs"
+"NT33B091V8Dcdw1rzXKEkaG2nfzogJJ5JtqOD2DjvtrVcbKCDxtx764+qC3EA3Hf/sKgjWt3"
+"iiMAHQ5BEgJttPmAPIm9/fepmZV3sra8PdQQWRnVhqRa1EJA6/zLDW57TTVJHJVk5MIlXKXc"
+"kwZbDkzKRr7q1GdlRxZb5mXj6ywr6LPcws1rlhbS5HbwrOrgwtOJXa6kbdltOFbBOs4uX076"
+"SdEScrsEbWCPYWDLfs7KLVayaVtsYDOnLSPLFaxBBK8PN2V7BTbjORa7a3I7KYdd6Rm4kREs"
+"W1eIK22nnp20khyZYdEPl5g8KayiL6hwcLx1twJ5VL1yADawNyfdQ65ayEBhtP41YSWAGl7a"
+"86UEkJX8q8RbUKar3kqbHQ6n28qsaxUeNN+iY+BhqvVepeeMNtxYrXDvrufwWmlIFfTvtzMy"
+"gkk9saFjZXkvuN+G1OJrU9O6V07p/pmNRJIh88z+ZgAN11C8KF/qq5ebNLit6308I9MXtdi5"
+"a53cbKKYRq4SNGJ8ylblgt/0+OlVxSAYQ56STP06QkOo/Rfk2gYp4resv1Lo2bG7ISI0bc7T"
+"H5UQcWbvphlxyTbJIWUNHtZdp81wL3uT3/Ckf3H9wZHU0i6fCSdgtklCdsr24WHHbS45kvlF"
+"RCk7xO4Q3UGwv2D99WwyqunG973N+NWr0bM9MOwCBpBEDcHzEMWNh2baa9S6JgxRQPDviaeY"
+"Qi53LtF7tY68qp1T1M8iUyqWO8kNcksBrcjnXI5WZioXduuFNtbnnUGBZA+3UjcP8JJ/dV2N"
+"cAubXbQdwpV65tAWtCk1v2bhQS5Es0sYd4kQgkXsxPH4Vr3hjdtzC7bSo7PNbX4Ui+ySP6bI"
+"pTaRJffb5wR291aLT3U7/c0sQC0yQVtAx07b/GkOV1DK6zO/T+msYcRDtyMscxwKpTPqsORk"
+"RJjQMUWdgs7jiIwPNbx4VfjYkGHAsOOmyNBoO88T3mknGdwAOn/b/Tem2aKP1Jhf9WTU68e4"
+"UU0irBKIvKsasECi1you1h2VOVtqqN2vfztSLO6m0ErRqysyQygW/jPl/bVJTlgc61KY4sTq"
+"EaiRZVF7m3EXUVh8/Lny8t5cgBXHlEa6hQOVbvqWNboyY3zNisqtbW17sPcDWGzISG9Uagkq"
+"1uTDh8K060tSLFBNxY60ZgdHz+ptsxITIBoW4IPFjpRP210f+r9REUlxjRDfMRoSOAUHv/Cv"
+"pcUEOLCsOOgjjSwVFFgBejttXSJYUT1M99ufaj9KnObkOrzlCqxpwW/HzGjeuYX9Rx02AXU3"
+"BIuw7RTDPXKlxmixbLJL5PUJtsU8W8aDCx9I6YwzshpdCLniSRbavOsOHJKHlvCNa24uWjJZ"
+"nRDj7MVv1pZrOY1B3L2Lp3UR0noU7l4lxxtc3aWZPltpYFhTr7dxJ/SOVkIROSEiZ739M6nj"
+"3c60Fq0u6cfxuqtCifUzSbfKYl6GI67g5XSMVskASoo/JoqAcCRpbWsTFLLFIJEdlkGoYH31"
+"9S+45klwZsQJ6gkAEt72t83L+HjWAQYkkXoFFjyYrqSFB3WNu/U1i6LrryVfu1HOYQ16Dk5f"
+"WJfp1xw0qjzzg7Y1Xhdh+wcfjW2wej4uIRIQJcgC3qsBoOxF4KKp+3OlR9M6ZFGqhZZR6kx0"
+"uWPI/wCEaU1ply9zlr8daHbp8DG4uvgaJrm7W1uVAKdiqHEghO5F83adTVpAI118a8GuL12g"
+"GBZ/TY8qBlRVWb/lufynt0rOQdE6i2bH60O1Ea8jC22/zG3+Jq2Ferbr/cXomlmfOxlfprZp"
+"6R4A48HQeodOwfvoloY2FiOVqnXqytZ21ZdaqugOMDHDbrX7jVeZ0rEzR+qpBtYlTa47DRle"
+"pJwN51M7kfaiy488HqhopEKRpttt5rrfka+dZnSOpdJyPRmHplhoSDqO616+z1lvv/HVulJk"
+"AfqQuAD3PoaSqlMKJyOT55HjxACSRmkm3Cy28tu886fRzTthtLksY4UssEOiglR2GlT5QTFj"
+"gjINjcsBqDe+lXpj9QyfT9TdIsh/Tu1+3keFRbKl4h7inUoyMx5xGrkBY1CIAOQ7TzqksUcr"
+"e6njTLHwIocoJJaSQEqY/wAvv4VTm46xMURAxHzMDu4/hSVqvCE3IVDnpLhyRSm7woUQ8NCu"
+"h9lepWpaK7AC0g2nstXqnguWmBSXWBvckDlYVzQHafl93GrGQra/AjT8DVTKb8eAsR4Gtijr"
+"EAacOdVgncByrragHlwrhuNtv8VMRO9wb6jT3Vy3lJ7OXtrqi6sDxHCuAmzX8aAJbrID23/G"
+"uBQpuTqNPfXPyi3sHjU4FMk4DcBqfZx+FAB+OoSPcRd7a/jaoSON4HEMCfcagZiBDy9UlifE"
+"3/CqoZPUmJ5RuV94rRYwMJJbbZTYjUHvoI48mQ/qZjlmBsqqbACjX08bXIqlnCspPC9j7aGA"
+"JJJ1GeNEM5ECgpFGWJCpc6c6HGAwUh2H90j9tHFAuOz21Uqb35btaryJAth2mlAC1kZCb6gc"
+"xVsMzA7TqCKpkZgzLfQmxrgazK3YalgMIVaaRYhoXYKCeAvzrmXltPKBuPox3WBTwVBoth3g"
+"a1GGb0w72821lXxYbL/Ghj2064QmEQTPDKkqHay6g37613TvuLFmjx45iIJ43W/l8pABW9zW"
+"NjNwP2VMH3acTVxIpg3ryt9DM8bElUOxgq2+VwLEeFCdLw4sZYYY1O7au5gouS6szatQ/Qky"
+"R07JjmB27f0SzWv2ge+mWOo+pgDW0W5uxPBZOVIopFxHAjBtskzkhlHMMOXjSnqmRs6bCQVL"
+"w5LOuhBKOpsaJy81IsePIjQXVjZVb/Ehas7nZHqwRrdv0wB5taBF7IfRVrkqqJELC3CPcT/v"
+"VVjtdWA/KK7G4HT491tzzOwvx2gItRjG2VlvbcDb2U6uBWUn1ToSxr0nEWPRRElx3lQx/Gjm"
+"bnSf7YnXJ6JiMlriMI3+KMbDTUqWfb+Vbe2oeoyLP5RrYnlU2Y8Bqa8wuVIt/ZVUj2lTvuG8"
+"O2gAXJmRWO61lJAJPaLisJ1HIdpJpWsCxYacNadZs74uXkY0hs3qBgxvqhtbTupL1KD0kkQ+"
+"bQ2NuIOorRLBJs2gfJgy438oeUFDa17IBesf9KZ16ljqt2iUTp/kYA/7rmtR9sZ0/UMCTIn8"
+"0lxG3ADyrbQDuNL8GL0/uiWH8uRDIq9mov8AsoraJ9Aa0GH2Pheh0k5LLZ8p92vHYvlX9tP5"
+"XsrHjt5d9xauwQpjwxwoLJGoVR3KKX9Synx5AoBKsoLG2gKuOPjeo+60laIZgWUChsjBhyMi"
+"GaYb/RuUQ/LuPOiq5bnUptDOGwI5cTVaS7ppI76rYAey5/GoZ0phxzMovsK3Hau4Bhr3UL05"
+"HlnfLdvmLbY+OjbQCf8ATVKvxdhN5SKusSwxRkyD9GM3Kf8AiynVU8Bxas/gdIwsnq8MzKWl"
+"b9WQg+TcP7tq1WfiCSCQjWTYwU23EbuO0drUp+1nx5JJ9rASxEIyX817atbsqbqa1hvFsiX3"
+"GjAsLV6vXqII3EdtIokagyk8DY8O2usbEChY3Z57a2JJN1I4d9DcDQSOzmND41OqL6lj+Y6V"
+"6edY1IB8xGlVxbiNweFkvuL2516gcF2adw7XO2456Xo6k1DgScnq9XgQeHLQ16kB6vV6vUAe"
+"rP8A3uP/AEKTn50/GtBSD71NuhSEcd6fE0AfP4EEUbuoUSKy2uAeRvxorDCSySZMkpEy6qL2"
+"H97TsoIOixvvPEi3dY6++q5HVyTFcKOHbY1m036eopDm6iZ3OPEoiilO0tw0vxNqYYmKyzEN"
+"HuiaMDdwRmTiTftrP4uT6cq3IVdwDaXO3n8K1cuV0+RFUsDGQABuK6e8Vl3TWFVOGswAkbGH"
+"1u10CJuBWIahjcWFepmE6cCGB3uWJ7Qq8O29eqPyPSLRECET3GoNzpxqIsd3aLgmoycBY8P3"
+"V3cnA9vxrsGSKElVGoN65JY3tytVqG+i6Hh4XqNuwfmB9goAjwa3b+2uAFbjXUWJqbAW3k6j"
+"S1RYndcaX7e+kB0gFRt1IGtWYq2WV+G1LD/NpVMi2tbgQdaKjTbiEk6ub27lqq6ggfKfbBCw"
+"4xta3cKswdjSTMeF1f3j+ygMhyUEZAJQnibmr+mK3oyyk6eWMDw837arcYfE+9HkP5ixv3LS"
+"1pTLjyycl228b0fMwhwGI4sNq+2hIcaV8JII1Jlne4XnqbCmARkf+RktxZf7aW5EhkhhfmQw"
+"bxBrQdSxhhR+k+1iou7H5bn8o7TSKbbNHYKEIOlhYGpkbUARNzXeyonRiDyqXHTj3UhBNgMd"
+"DzcngdQF0tVRNqgtxodK8SbdtPYRahIW3M0RjwvPKkEdt8rKq3HNjaqI1BANqfdB6VNkuMxZ"
+"DH6Ei7bcWKspa3sqloLc04HpR7CwOxSp8h5WH7KrjZvqw1+EbGwSx03dvjRWQrWcWe/n/N/f"
+"oPLnESSSkMCkR4tblQUZLLcvjY+vlVWRiR+bczamgZtIz49vO9Np0U45x0sq7gym9xdQ0Zv4"
+"0qy0ZLbuRv23pNigtxUeZ4oFPcD2X1NXZaLDKY2NyDobW0txoroeJiiCTqGXuAiIEKnVXJNj"
+"cA3NUZkpyMgyuBeTUhRZfYPZT0QG++y0Veh45Gu9pWP+sj9lPFPnOmpJ17hSP7LyY5eipEuj"
+"47Mj/wCZi4Pxpw0qxpLKx0RSb1IyXCRTprp7aB6pK0OM0qayRuLDtUnhRCF22MbaAEHvtelH"
+"XXGHlxZDgtBKCrLxAf8Ait7KaWRMD+5o1mTFz04SIAe/TcKRtIcqP0nF3RSoftH5b0+ndZui"
+"zQ3DjHZZI27YpGIHu1rOCQxvZfmuQAOJJ0FVOASlj37QyZ06VltjY7ZLJP5F3BRYoNdzdluV"
+"C5GbkvnxZmQghfGYEqtwQgN2BbwrTYWOnReiRY5tvRd0hHN21asR1zN8/oA/qTeaQ/3eS+2s"
+"lZzBpxSUv6H00MHQMh0cXVh2HWhsiKVriNA+7TzfLr291BfaucMzomOxN3hHovftTQfC1NGl"
+"Xdstc9lOJJTgjCzooWd1L8tv9tXAg8DegMnqGJjCyr6kzaLHGAxueFyNBS3L6zkY+S0buPUd"
+"dqRoNyo3dpdjVKjfoQ7JDXqGRjRRelOfLKGt3ldbVR0pzKC6RhIwAL9tU43SGyIY2z3YkHcq"
+"A2tf+Lv1pmWhgUJcRqBoLhR8aTUOE5KVvjlFPU5hDhyO+4oB5wnzEdl+VYbIyTj+nHFdHncE"
+"MhsQAbg343rTfcHUohiHHjlUySEAoh3Nt53PKsHG4k6rHckgyW7gB2UXqnRT+qRL7j6BgZ+S"
+"IgJH9Ts3DX3ip9F6hN1DM6g7ECKCVYI0HLau5j72oBn9OIFeG06d9X/a2J9HBOzOWORKX8w1"
+"LfmbSoroaXhPA8lYRqXPBRQ2KVdXkBvyFFkAjXhXBGiiwFhe9G6klPDXkpdkUAsL66CuyRKQ"
+"XYcda62OjOHNyRwHKvTeqyFVG2/PnWqekCsC4RvmOB+VLaeIphQWDEIQWb5mO29G1N/uFXQr"
+"hQLua2rkk1ZXvCuE24++pGdrhvbTjXgytwINdoA9SL7xifI6ScZNHkdbE8PL5qe1mPurqECO"
+"kTAuIxdlHBS3M1N7OtZWuiA+fkHGyAs6+p6TAul9Gsb29tGYOPjZspMshG7zCKPS9zwv3VPM"
+"xMOZPqUnCMw8sfzA+bX8aY4fTcLDdZi7SFFvuOi8ONqyt2J03Vn6biIx9O6UvqRFBtsd8pOg"
+"PLU86lh4uFC6LHJumdGCliNhPx17K5LL0yfHLqnqQggTemT5GbgSKKhhxYoRPdxCmqMLBlHf"
+"prWLtZJZup86CB26bKVUxkFh/Ma1mta+3bXqsXJwJBdJGYKxla7We41J9lq9U87+HMgZp73B"
+"Br2y9rkAdh/srxuF/A1wixDdl/hau8ZNZVDBgNb3BN9KmZLqbGwvahrlrGuBmB4870MAlCWX"
+"aBdtbntFSK7iL8RwqiNyvmBNx38jVvqEqSRYtqefGpjIErGwXsvXsTGXLyIoG0Mjqofmu9rX"
+"rxe5PAAAFvCiulMp6rhJbbedAR4MKY66hvW/t6TpZDThZY3PlcftFK8UK2KqRixaRgR7a3f3"
+"mm/ABP5SDWL6fGI8cS6WBcjxLVVS7aL1I5a7mWMfKlhanXQsJN31T2JQmOHuNrs3uNKEjLy9"
+"3E+N6YS5Yw4Y4Y3/AF5fKpvYKp4tRdwgopcl64kXWuvpiNc4cAO+2m4jU1b9zdO6fEI4MeFY"
+"r38y8dKG6P0PNaWCYTej6zEqQRuIBN+YNV9fhyx1maNpt6AhlsNLEDvNqhedjTTDX0Mq0Kmc"
+"o3IkH2G1GehDHjFwvmBBuOOhqmVQuawU3G46+2iZr/Tt4Vexl5AJYyjbtwZX8wYd/LxqJA4n"
+"41K902kajnXVXtpohnUHcLVuumCOPpeAqBfNHua6niXuxJrCEutgovfga032/lz5UDQ5GX6S"
+"xR7YRtBNr87lRVNhVZ9x1lzRo3CPUuOJGpbvpLntkTtsxo9sSgK7AGzt2X7KJyzFIy+plKSt"
+"5CNmpPZ5SRTLpOLJ1F5FjcRwoqM8gHAv5ti99qmzxgpLyY/JGQzLGSSWuNoFuBNC6spR0uqm"
+"zDsPbW/6n0DIZ3kgCnQlCoBbd+VeQA7TWJ6pi5OPkySuNtyBIo8LVKZVq7rKDYJmg6RHCt1L"
+"u5bZoxHBb34ilzPultb5Rx51P1gYoQCQ8alW7Nt7r+JqvEi+oyUjVgGmYLrwBY7dapvQg+j/"
+"AGj084fSUkYES5R9Rgezgnw1q7qkrNEmJEbyZMoQ2/h3XPwpkiCGJIl4RoFH+UWpbDDfN9aZ"
+"wzR3KqOROlNbsTGDFC2wWLKtwKSfdjIcXHTQuWJF+wCnJlVZlW+hsPZasz1XpnWMzNmkUerG"
+"DaIKwsE5eU066iegv6dkhMLqOObHfGjKOYO/bb40V9v9KGRnf1KYf9NjWKA/mlt/3alh/b4w"
+"Ek6j1cqmOg3fTg3LkDQNbQ68qLyuspIHxcOH08aOISmYWQWbXypaleX9pVI3wVfcXWo1Vtf0"
+"04D+NuysM0kk+T68mpY3J5AUR1eWc5W+Q+Qr+koPAd/fQSsdRrYa28KhKCrWn2Q46H9w5PSx"
+"NEh/SnYbiOKsPzLTXJyc0BcjIchZ1EiOWKl1bgbWB4cqy6qHRdvFyCB8K+mzdJxsqbFxZ1vH"
+"jwAWBtqLKK067f7GdkZKPqDEGFFYRkhi68SR4056MMiHKGV9LLM8g2epIrMVHaG7Kf43QumY"
+"zB44QXHAsd340faw05VT7Fsp9xKj8mZ6p17Og3KY3xl4BijX9jGs9l9Wmms8rSSngCxrW9Wy"
+"MmbIGFjQiZVF33LuG48Brpwpcn2jPInqTSrFIb2jC7gByFxVV4wm4pJLmXHyMdn58isIo7oS"
+"Lsx+bwobHe00JBIYMNT41f8AcGJJh9SeCW29FUEjUaigV8oQ31vp76x7NXuaVeEfRBaSAHup"
+"10lCuGhLiTdqGAtYfw1nOmZCzYSODe6gjx9lH9GyshYWjikQ+cgI/IjjwqOtNykadrShmir1"
+"LZs/KhUMyIRzIv7a6OoTcP0yeVr8O8Vp+Kxl+SvkY1FvlJva3E9lLpM/KUgBb8CbLpbu1oOf"
+"6vLi/wCokYKeCDyj21S6bPwJ9tUD/cnXY8WHHx+nzLJlPOgFiG4G53WpvH1jGkKIoZpX4oBw"
+"Nqw83SAnX0nWxjRd7WAFm4KP21ougSpJ1KSPZfYgYN/Ce+s+z434mtUnTkPlyQ3GOQW7hUwy"
+"sPke3O//AG1bXr0iSlolYWWO1+d7VQ+JOSdsu0dnH8aNvXqaYC3LXMx8SWWOW0iLcFhcW56V"
+"i5czF6hkOASuSwLB34hxpe3dxr6FMoeN0IuCpBvw1FfMc7H9TOxJpXCCZP1GDBlVgOF17bVn"
+"2w+MtrWICMk8TpjzyLK5h9CJyr6eVtv5lA/io/Lx8fJBhu4SIi4BA+YEbALfgaXzdSMEaYmI"
+"NvDbLcWfQMSR312PJXMzk3boyCCyr5gzWF9OVqxi7+TScTGBuX6k/TbCgfIiSNYAEZYTcNcr"
+"qTe5bX+KhpMmfIYySX2XBMZICm1WyCN+pDKHlxZSEXd+YqL7gvZpVfUIJIx6hQgDjcCxHK1a"
+"1rPytq/5egQRhnw4ciYyIdrqPTUanzaW7tDXqXE2Y25209t69T/FXlyz/ERw22heHMH21Ig2"
+"Y8bXFQJNrc+Aru+xLW0OlaCIhCov2i49tekS3411juJIFhwA8BXm3EDTUAAUgIxhmY7RqeA7"
+"auUHygjzcCBVIJDC2vIirHLoSpuhOtuHdQB13AXzC5sND2Vbgy+jm40wNljlQn2Fb0ExPO9W"
+"K6+mNLm+ooYLU+n/AHQhk6ewGoa341kMDp3UZ8CN8fGeWNSy7xwLAknTjWsklOZ9uY07as0U"
+"ZJ7xYGiftkKvR4UT5UaRbjS9nbWiryzW32r0wZGPEyIJtmTEYvLfzDm3CkObJeaQWPrBiFPY"
+"q8BW9+4OmZ0okyIlEjm+0LxCgGvn+ZE4lbf819fGob+WSscMG8+0vSysRMouRPGpRYwdNh1/"
+"Gs71gti5k87EjabEaG7Nw1FC9HM0KblYqb3UgkEVd1FGyYzG5uTrfv5VOmIK5YbnVGfBu+7n"
+"u19tFTtaA+yvDpuQsbMF3kG2ndUcrckQDAgg6g1stDGdQSxY6D2VOJSGG8ac7dlQZSrmx04j"
+"wIqyEebde4tzppNtIh4UhczQuqoikW50w6BHBJ1FIp1UxujghhfW1x20sXWi+mhz1DHEZs28"
+"ajkOfwrrVKxGvuYWs5nT2NDk/b3T/SkmTJeJY1LbCbgk8Pmp99swY8XSmWNg0LMW3X4javE0"
+"BmdPGThZCpLtuosW1AuR41b070+j4UWNkNfEydw9UiwV7ahu48qw76pQ0jbps7JptneoQ4GP"
+"0jKnxZ2LzfymZyPzWOwVjMyD/o2czeqZAC173U7rWPurQfcoxnx4PSYuNupuCAOy3KszNOhg"
+"WFW04knmeAFYLOiOizSTlz7gVnJXTysvl14gcaLiih2yysyxGNVEca6Et/bQ9yEUqDz0bttb"
+"3GuII2W5JJU6gc6Zl7H1fByJZemY8kn854kLntJANdjiCydpI2m19L60N05wnTcMnzAwR3/0"
+"jtpT1P7qk6dkGM4LFgSyPIwCv/eG1apPAmh/kG2SkSi50v4CrZMcsPIQDaxArIY/WPunqkwk"
+"giXHxn4uEG3TXRn41w533g2M8gWPapsSFTc3eNaJXkIBfuTqLMz4wYkI+0Em4JXjahIZyYNt"
+"rEWueI2jXb4UHkxZ/qepmxutybXTYtz2aCica22x4HT3025BSsCSd5WPqS6s2uvZVkTIxAJt"
+"cWIquX1DdNpKqdNOFqsRolWMFRvA8/K1uyoYB/Q8U5nUcHEI8rS7m7dtwT/w19XEX/U+r2pt"
+"+N6xH2RhRS9SbICt/wBHHs3HgWcWHwvW8pp4A9Xjwr1coA4QbXHHnVbPsQl2A7AKskNkOttD"
+"rQO2ILfazgC1yNKqqkluD5795Lu63KxPFVIHspE23YNdbcPbWk+640mzzK7GMs2xTa6iwvcj"
+"jWclieO275dQGGoOumtHZ9wV0RoftTKb9TGIJQD1Ax79LVo+m4yJPPcXbduW55MO41kPtqRo"
+"8709bSroOVwb/hW4RREyzHssxsDpU9Tjs9y+xcur2CtSCpW1+HGvQosbs4Q7jxNr1JX0LKQw"
+"tccjVkU8buwK20+a9dLeNDmqvUqnmTYbnbt9hod5/UhV4tQwtZtDRGS6qLmyqOLEE0JI423t"
+"bmq9g/ibsqL24pQa9VOTc5Qm6liB2aUyyRy2JOxiFt2WrPxZ06ZM82POyj1CEZGZfKOHtpz1"
+"rLhVfTmZ7OLOIyA+3tBYGs2kawD01O/mGuD82vLnWDbeW8s1cLCUQO4vuXrcY8uWx/xhX/4h"
+"Vo+8eugXEyN4xr+ykVyRqbeNQYsdF/H91KWEGiX7561dgRCQOBKH9jivN96dbJuGhA7BH/8A"
+"cazG1xuAN7i3dxqRBuN3GnLA0Mn3p1xkIEka30uIx+0mksDwekUl33JJhMXlCycjbgapJsNK"
+"I6dsbedoZo2DEHncWG3tN6m7mvsEFsKElk2I7Ag7kFrbtWb2cDamDtDiQZM8yFJJbRRbSBIU"
+"5lSTbla/GorHHYgkELpuUaG4uBrY1HqcQkV8w7W9QhBGfm3LxYD/AAis5Klx7CkZMjTJPIoC"
+"IAscYvtCgjRb1t8sdP6pC0bt6REaOhJ2jcL39mtYo4zNlssikRq3mJ0G0akU0zpnWHBkiY7J"
+"IlVh386010JXqBSdPmXKWB7K5YBCeB83bXqJOTC6KXnJcOVCEXIC3ZTpw10416lzzpb+AQaP"
+"/wCLdNjjYPCvqAgK25rAc+dJ+o9NixVBTGhcEX13Gx/1Vs5W3xhzoSASPdWb6plRCTYV8yhw"
+"dDbzbrfGsF29nJqZNuFOMwZiSO+noxoCL3Xd2d5oJWtr7NKaEb47202k/A0o00HOuilm5nYx"
+"vVKINV9p9Kx41Xree10jcrjxCxMjjQsb8hWl6yOj52Huy4jIy32rHZZLjUebkKq+2IQ3QcK4"
+"BO2Ui9jqZOIoyWNUBYICGPmBFwQwtTfYldVBUmsnzWbAlDsfTKx3Oy7Le3frVAxZlksq37AC"
+"D+Brb9XwYhCzlF1100+YLfhWejijXeUUXXcQeYteqcRJEbGt+2n+t+10iA1TdF42NwfjTP7f"
+"wZun4b40rblWQmLuVrG3vpL9g5MX9JlhLjfHKSV7FYC3xFafEkMsAkP5i1h3XIqVqaNvjpuS"
+"kBYpbkwv4cCKDyuhdOy9ZoRuAKh18pte4osuTMYxyIb2GrqFDkgzb/aSh7wTAR/3h5h7qtxu"
+"i9K3/TkfUzKCZHubL2U+PuqEUEUO701C7zdj2mnBXJiHqHQ8Mxt6P6LKrkW+UlFB5996yHWs"
+"B1SWF7etBZgV1DLa/uINbzrkyQ4xsf1HVkUf47XJ9grFyztPMN/JRH4qvlHwpNkYkzD7iBbi"
+"NPZVkQKi1WuBFc7QLH41C4I3cB8K1onyQrNQy1RpWg6P9vZjSx5c7HGRfMi8ZGHhyFDfbOPH"
+"JmPlSrvjw09TaeBc+VL/AI0Pn9bzcmZgZWVNxsFJAtfurqTMoNzEiQqY1JJbW5NybcKYxjGz"
+"MX0JkV1tZ42r5R9RMrhxI24cGub0fi9f6hA4JkZhwIJN/YajsorLwyquBh9wdHxsXLMMMr/T"
+"23emW0XX5b9lZnMZWm2x/Ig2i3D2U/6h6OfjDJXKebImYRxQaA725OTyqn/4vIZJVWYbIIPX"
+"d2Bu3z+VQP8ABWVelpzJpbsTUJCaN2XT4VNYldCVuNpuVHO3Gij0fOVkV0srqr7gRba4JB+F"
+"Mcro0eBjpIHLZGpdNNoVfnPgLhfGteCahozThmu6f6n9KxPUsH9FTYcLW8vwpd1ZVy/RgMbS"
+"qpO8CNm4jgCOGtH9Gl9bpWO7asimI/8A6zt/Cs91fNnjy5sZpJdLekqvsQjnfhXJGX6G2w5T"
+"dF9OuqJG8cccXc/lBOvKxq4oEwSt9A1gTSbp0on6mbOpUiJlVW3W9EgW/wB6tBkxn0XBPlF+"
+"HdSGK88B8YAkKCPM3lva396sypRA2wkqGspPH9laOdxs3MCTbyis5kl5BJfQhwbfspoTAJox"
+"acig4gLlmFwCO7hTGQfzgNLA/BaBHyoBqCdRzpLMjstPY232n13p+CZcHKtC8sjSCe42nkFb"
+"s4VtVkRxdGDA6ixvXxpyTky7v4iLc6+t4PpP0/GlK33Qob21ttFUSRlzplneGGISbLXJa3Ed"
+"lqF/quY0RIxlNw2m4305cK7Fs+rySilBuXjzui62NQO1Vfs9RiLdmi1z373W7rCw9zavWmk/"
+"QU5v3fnQs0RxEU8DctfWicDrpzOmZM+UUieJrKgYDcLBhbce2s/10/qM38bX7+JrmHhYuRh7"
+"isnrmQqHA3RqtlsDa5vW/V2cmsJGfZSEwPrDmfH3hgSJAxN+0EUocst2Gug3L+U343pz1CAx"
+"QSxH5lsfcaTHeLi/cPxq+zUzroOPtd8ZcyRnbYQoEKnXn5q18mZGsaFAXX1FRu7cbCvncDFJ"
+"FksFdG3LbhpyNfRIsJzHdH0axswvwqa1s3K2L/JVLjYtUlQwZtFJAuRwquCVfXkjMgMuhVb6"
+"2q9YdtyeZufGqDFfKVtq6qRf82luFdtdM+Djt9zjQNQB0If231oDJxZwbq4dCSxDcSeVyOIH"
+"ZRy+WwHAdlqhOLra17dvCo4pvJStZLDMhnYZnySjG7udXJA058eVA5uMMdFDqyyEmxbgyDy3"
+"A8RTbOdVyWRjtLgBX4d2238JpRnzTS+mJjdo9yKf7gsQCe69c3av8zVcKq/ob9bf403mWCa2"
+"t+6q3uO7xP7hUr1W7EcOfOoNCtr71F9CCT7PGrVIGnLwqhyDItzwBqYa/D8aGBae6iOlM0ck"
+"pBQbl2lnAIW4IuAeetDctdaN6UryJkRqtxYMWI0ULqam6mrAbdRaGUKYpDJjLt3K1kIa/BVH"
+"Z20E8rN+lIpbcRd38xBIB07DUcp5ItASzFgAeRFSEnpz+mPOr7fTbkb67rnn5ayScFE8rFCg"
+"qhJaZidg8xUAG3m58asmcp02CAnaSkoIK33EEWN+XCuOpuhswDHajNrqTYWI48zXsqCSPLSN"
+"H3oSEfbqqhhtPt406tzqJoWrHGM4pMSF3WVxYm5F07vmr1N8vAikaBVsFWQBhcb9i6X0/bXq"
+"vktZ2iJK4vSFrJtZhoSRfkb+NqzvUwQWZQNxRr6dlaCa8gIB043HfWe6rcLI44bND7RXHMXw"
+"b1XxEBXbE99fIb+6kTG5sOVP5f5Ml+Ow/hSBV83jXX05k5+5aH1D7fUr0zpsYtb6cuTrxLqf"
+"20ZmMqLFf+I7vAKxqnoUf/pvTrcRi27+K17rCMxx0AuDKQR2j03qO372yqbIT9acmN0B7Rfs"
+"AFIIdYiO1XJP+Umn3WyqhjbjwHiLVn4g3oSEcRFJ/wAJp1s3UVqpM59r5csXVYoodEyj6Lj4"
+"qfYa+n4n/l0023FyvYSbmvkv2+SnVcJ7/JPHp/mFfXybAnsreNzPk+PH1BWmCTTudCiAeN72"
+"oomwvSaXKQy5KahtquFIsSqNY06qOtzPuxCqXPyFdrxlVv5fKG/bVLdXaPVwbd0VvjuppkRK"
+"wuRSTqcYED24gGpcpwxMW9W6uM2RQukcYub6a0gicmQE8SL+81PNYiP0xo0hC+w6mqUJ9cj+"
+"Gw+FMBdOwE0i9jMNfGobhbje9RzUtmzi9vOfjrVca7XHmv3VvW2goNP00nE+358oaGaYrw4h"
+"V2j4k1nb61oc/ITH+3cXC09SVFkYcCNzGQN7eFZxTXS3CRHktvcV6og20qVPURKKV4pFkQ2d"
+"CGU9hFbDD6pj5fS8+UAJkegwkTuWPaLd16xtWxSyIHCGwdSj96niKcAavFmjKwFwWEMMJsBf"
+"zCJCg8dz6VVnpIu6WcArjqrSqNRuB/QxVP5vMdz1z7XkjyJJzJ88AhKLfiRH6e72babZUO5F"
+"W3mW8g0B/VbQNr/CCT40JiYN9qZDN0/Ihb54ZATf++P3ilX3LYzo5GhGhtrTDpW7EzXwgoWG"
+"WFvTF7sXjO4sx7WuaX9XkEyPCbF4muCT77Vydii79cm9XNUAdMyvps3GkNhGrbWYfwv5Tu8L"
+"1v5VJje/YbV8zclV08fdX03GmXKw4cheE0av7WUGsyhBPezXNrAnSs45uJD/ABEfjTrrbmFH"
+"ANjpb20iBvEb9op7CKGfzydhLE+wUImTGnlMSsL3JI19hvRFtJD2hj8KX211pVhyO2xeswMp"
+"k1uTf319i6Syv0vEZflMEdv9Ir4utr19f+2XL9AwWOv6QHuuv7KokslX/qJG/iCjv0FCemuo"
+"5bmJ8ASaNmsZn14WHwoWbyxE89ePZXD2/wD0t7nV1/avYyvXt2hKgJcKoOp5m/wp59nKD0ma"
+"63Pqk68/KtI+vSDeQza2YDTibr+6n/2WC3SJSeDSsB/pWt+nYy7QD7jiSQjaigWbdtFzbh5m"
+"vWNCx7d4a55KbVu+usIunAfmnfafCO5/GvnpK3BD2Pf/AGV09miMa7k9g3WWx01I7q+o438p"
+"b9gr5piYwkmjZ23RXG+3ceFfSsc/pJt4WHuqun+76Gfa9Cxx2Gl0hH9RhUHXa5+FHOaF2qc0"
+"SEahCo7rkV0V0MmGRgjn7K5OPKefdXk7OVem+Q2pf3BsYnrLKnUA7MCBe6X1Ite9AZuTBkiJ"
+"owUcA+oCNLmw09gq/r7Bc/1ABcC57+ylUjEaWFzXLd/5Lv1ak6aL4VW2p0Nu15VCQ615CBav"
+"ScagsHc2lHhpVik9utUuf1QO6rBpQwReL2pp0RJVDSekWjk3DeG2gW4E91zShW0NaPpWTt6Q"
+"LEBRuS7cA993xGlTZwvcNyOV6Ym9Jz8kYTzWPm5kcOJFV4cORjzQvARIs8hMcUi3UXJUO3gO"
+"fKix0zGnxhM2QVWRfNZN5V+OrX8ovpauRSR48rjHkZWhVRGSQ24ANcgW7eHdUPRwWo3Cs4S4"
+"yKEYyRzkoykFvTI85NzwGh9lVF45Xx5AWAX9NURLhCTZmPMkcB40Lj5GdkzuAzSjIUiddANt"
+"id0YvYGw40yedsJkiD7IVB2oANyuCBudWB7bjWo0/wCCsNPBa0WWFM0d0iYgPIdH23HaNd3Z"
+"Xqgz7coO+QrlnBRdfTWxA0J5DUmvVM19Y8hwc6I0GQL/ADX2rc7QbXuOdIepj/piqi1wo8Ba"
+"9q0GRbgNb2HvpD1hQBInZr8awUybL7TOyu1pNPKE0H40qVWNgFtf303lU+nKePlsaUjQlQbj"
+"lXb07nP3ao+ndLukOCg024aED/EVonMQs8R/gct7CCP21ThC2RAmt0wodPb/AGURlkDdfSxB"
+"rPv1f0H16ozXWzuidhx4X99IIL+jLb/w5Ln/ACtTvrRYwNdjY6nlzFZ8SBYci/ONlAHa1HXo"
+"vcd9WCYTlMyB/wCGVWPsYV9jNiLdtfGIjZgewg+6vsiuvorIxsu0G/da9dWxgIOpYz4ubFkB"
+"rwv+k4Nz/MZdbmtHQGVGcyK0aKYmFyzjUjkV7Kn03JaeArL/ADoT6cneRwb21l1wnZLfKGET"
+"ny1murZO3encyn/Nw/Gi+u9YyMLISGJVK7dzbr63uKz+bnDLu23axN2HgKdl8pJbFGUS2ZEo"
+"4WJ8LCqsQmSRpDpuJoiRT6suRptjVRfvfgB7qvg6bkwYkc8iFI5LBC2hYnsFAjP9SNuoT628"
+"w/AVTEGeRUX5mIUeJNhRE/pT5kjMp/ULf2GqISI5A0b7WUgqeYKm4IrRPQY7+4sQ4ue8TSX2"
+"KgjU3+QKFt7xSYcSK0MOBN1np+R1HJnZ5cZkQkgfIRcsx52vSTMx0x5fI+9ORtatn2JuFsLg"
+"4krqSm9RU3rvA3q09yCwVYANhNVKRTLp3S83qTCLFjLXI3PwVR2k0WukvBVahP2tP6PWUhYD"
+"blXhueTcV/Ctv1DERMdrSMrEfMtgRQvSug9P6NH6z2mzOJmI+W/8A5VdkQ5mbGwgAUHgzmw+"
+"Armt3XeKSb066L5WiPXcy3SUbI+4IRNLI/pxyOgLGxdfLr7DQXUycXqkrWuLm4PfTROl9Q6X"
+"1vCyZFV4STCzobgGQMLG9jzqv7qxSkkc9rB7g37RS+U/LWCW0/t09DPudwJPM30re/as7S9C"
+"x9xBMe6K/cjWHwrBhb+2tf8AY8rSdNyIf/Cn8v8AnUfupALfukbclFHC1yPbSTcApHEgE02+"
+"5Z1l6tMqG4i8ntHH40nI0bX8ppvQW5WTZHI5LY+0UDZORN6Ot+m/b/ZQKjT8amu5V9jwQXuD"
+"8K+nfYmV63QliPHHkaMeB84/4q+aJGbdlaz7R6icDpuW1r7Z0P8AqRh/3atKcEGxlYNNLbgC"
+"Bp3AUNlsBE4sOB48a9iZQyoGyF0V3Jt7bmvZQ48ybm/dbWuDtX+S3/sdVPtXsZL7gVfV33Lk"
+"kljwAvyFaP7KYDojXNh6zge5az/3EsnqMq/KDu7vNTv7QDHoOQF+ZZXK+IVa6ulYRl2vLB/u"
+"UzCeKNlAhTeVNxqWNzp7qwjwyCVkCX2Gw58DX0nrEUfUOmJlx6tGN4t/vD2WrGSgRzE7SwYA"
+"24V02+1GFdQXFVnmij2MfMAzAEAa9lfR8cbYVHYBWIhmjd41CkAEWNyB+NbPGcekATqBT6Ev"
+"kR27Fj8aHJtPt4nTX21YZCSbeyhQQJ3UnzkAjvHdXTGDEYRnXtrsgurDuqqN7GzaX51dIqxw"
+"s7NoBfTnUPDKR88z2hOdlyOOLEKDccDt0t2Urc3mIHAC4rXPmQbSxxYWdTtN0Bv43pH1DDnM"
+"xfYoK/NsAC/CuOz+T92diXxXsLAdfCvSV7UsQR/212UXTSkJ6AjEetVl2qlzaSrkNNgixTp3"
+"2rUdIwRP0qE72X1bAMOCkNoayvhW06Niyz9Iw0uXjCMfTVtt/O1wT2VFtBrUcWEKXDpJERub"
+"9O26UrqWUX7Lms/PAqTQz+kUtqdhB48F0JNhe9OJZch41hxCvqINjobbkbiGs3zXqqHFmjxB"
+"JnKvqPdY7+YqePnU6c6xq0vdlcdyvDgWKNZ1kEWQu6NlNtb3A4cKjj45GQJ7SZMMpZZkfUws"
+"NTu7P8XOi8SFgjNZCr/k46DTs5GipcRJAjbxGQTHIiXVZE0IGv5hyqonUegBkJ+pDG5tIW3p"
+"LbytELfhxr1EmNDGEAJCEi5FiN1wSPZXqjEaY/qE41Yzy4wykkXNtBw5WpF1UWjA2+Z9B4AV"
+"oss2XTs4Vn+rv+gbakCwt2HSsYi8G1XNTP5FhFL3KR8L0qxliM6LISsbMN5A1Ck6kU1kQOjI"
+"xsrDaWGtBHHxY3HpyOzAjQjv7a6/26lMw7tUfUYPpBkCKKxniiRWJ+b0/wAt6pziTvA0sOP4"
+"VTjadbzHI1+nx9f/APSrMsMxc20Nh8ay/cvb1H1LP0M51tVGOzXJItt1v/twrNlR6MzDgqE+"
+"+tL10SJjsxUchr48fjWbbTFn/wDxkD/UKOp4+pXZq/YAQEm3bX17pkiz9KxZHsQ8KFr8PlF6"
+"+RxEFgSbV9T6ajQ/b2NFJ5WMKJY8bvZR+NdRzoYRFZIkYCyFQQvcRQGZLF07KTKLAJINkyDj"
+"t5OB/dpkoVFCLwUAD2Vkfuud06igFxtiG0+JN7VLSw90Bf8AdaB2xslLNG6ldw1B/MNazhbb"
+"VsvUMk4QxhaSEOJFUk7kNiGAP8JvS1Z55ztVQt+PE2ppNkPUPwpIBkB8iL14EcO0d7biqlV1"
+"7i16J+4OsHMBljHppGm2JD/EfCgkARAg1PEntNCdRYhFUC9rtx5/7Gk0pQ6zAlRyGDcwbE1e"
+"cba5JNgCdeWlUkoDYai4LCiWckafJxAPI+NaLVFDPAzjH03MxUa3qvExHaq7rj8KEyo/UjNu"
+"PKhkbY2730wKOhMbqVccVPHWm1lvyNNOqXgUxtcW5ijcLDyM6ZcfGjMsr8FH4nuqeB0eXO6r"
+"HhReUzG+61wqgXY+yvpGJg9M+3cGRox/LUNLKfncnQa/sq/ycVGrJ4SxDH9odO6biHI6nPun"
+"tdEGiBrfL2tVuJ91KcILBjrCg0W1lFhp5gOdZ3r33DN1HKYwAhRouugApPGzhGEjXUaBAbeZ"
+"uB77VHF21KdlXCyfR+i5EvUQ2ZId0KMUTsLL8x8BTXEzoslnEZukbmPd2sONqR9OeSDoOJj4"
+"9hNJEqxm9gGe7km3dUehpJjfqyXWIXWFDxd3IMkxHK/BR2VqutKr/kYPtbtLYX905UaQLjKA"
+"Wk48iAO8c6yfWM7PzFikmQnGjUCIglraWJckXvpR33Dn+t1KeO9xGVVe7yi499dx5PS6fA6g"
+"y+oNV7SSbj2WrPsUVSNKat+TOCTsFr1q/stpBi9R9KwYtHsY8nIYUjy8YSA5EUXopYllPC4N"
+"rCnf2mywdOzZXNl9QXPDRU4/GsjQQdTjxYckrDO2TMCTLIQFTceSjWhY7kSE/wAJNVsw3WXm"
+"bDwvV5V4/WjfRlVlI7xVMW5FLEN2cPhVZ6dkAXuljrxsalDYA+NFr1GFrRkbSBYHlcd9Z11Z"
+"dtgI42UqcFI7QQaN6UzDFyon0JeJ1/y+oD+NRlyEK2W169hkF/Z+2taaoztobboPm6aVGhDN"
+"c95orKHla5to3DwNA/bzAYLjj+ofiFo3NBsVJI8pPZyrg7V/kt/7HVTRexlPuILdbcQb6n2U"
+"++xz/wClTIRp6xHvVaQ9dRAqPqzmwJPK4DU/+xv/AG6fs9b/ALq109WiMezcaTdNRcd4MYiJ"
+"GBAB1C39tY/rfTD0r0jJIriTcAeB0tbS9bvIkx8aJ8iY7UQXJrAyZiZedPO6+SRmYK/nsL6c"
+"a6Jbq/BluhdHkRvKiKQTewUHU61r4bRoqi97DSk2GuK067Y03X8rbQLU/VNmp1vxtxFaftoa"
+"szP9xiEcLaXGhoZo3mBBNirbkP8ACaJfTUMSKpv52vaxtXS/tMK6l6HcB6gtYa1RnytLAYYH"
+"uo1db6kdgq23qWuSFHEVI7I0ZraAaE0o08hL0MpLIfQlYldl2+U3IbdsXUc70ThKclX2E2YX"
+"OlxwI1A8b3ojB6VAC+Q7BhktuMUi3CkNpY0cMNIpHkDqEc3sABYWsEuK8vsfyt7s9Cv2r2ML"
+"OpjndSL2NqpmbatuZozO2pkyWOgYgWPZS+Q7jVokGdryEirUJ299U6bz2VfGQBeqYI6Cw4it"
+"j9r5TJ03TYFjmAD6bruQSLmsisgJsRpTzouL68QVUkf0pRIArBU0A+YHiayv9rKWpoxJhtOx"
+"jkSMhlaRW8jecaH92tTMyensmuSQwiK2YBr/AMQ/CoSYhjlf041XysSTYt5LuqnxJNhVmP6u"
+"Jhj1XaRtvE23bmOtgaiFgsCM029cYArpufgfmYlRZdOJq/Hmmc/Sypsdbm7MCw2m+7UcL1Iv"
+"NJIiHYqFl9R9ikso/NpawXxrzuglusilUK7t4BYg3GnOk14Bg65peU48gI2jap3aFeR4fGvV"
+"cIYXYBgCI7qGFt1jzb9lepQTnQ0GQRbTQWsBWd6lPAYZAw3SXAUXIXceG49lP8j5bDidB8az"
+"PXl/QDRptXdZ9NdeG721hVN2k3WKwKpCRA5PZQmFEs+VHFISFY6299GSgvAQuulA4BJzoEBs"
+"TIgv3E2rs/b6W9zDu+5H0dAF6nkldCYoQfZuqeTL+iRzsfwqI/8Ac8o9ixKPca5ORY29ntrm"
+"/cN/kefBp1JQjPfcMjPAFHE6tfuFZzazY0uurLYc/wAy9lP/ALglUxKpbzN2Dw/fSSJikTtc"
+"iy2v/mFadKwvcXZq/YGxMEs6yM+1QRfcpGnO16+pbxnY2LNjEegzJLdtDsXXhXy4NJLIoXzM"
+"xAUHtPjX07oBv0XC/wDxL8K6rJHOgqbzCwUt4Af2Ui+4cF58JZFVvUgJbz/MUPEC1+HGnz37"
+"vG9v2VmOtQJjTS5Chn3+bXI9MBjyC21rNqWWtDNSypALsQCeFU4c/lIZNl9dw4Nehcouz+o4"
+"37jbU628a8Y8gIm66Ky3QWtdeFxVJOCeNdw6aYRC/NtAKDnJKozHzA6a91dAZ23ObkaDurk4"
+"uqjS9yaaUCAGjVwNvlI4nuqYDhOB2jS57anFFqQ9yNp9hq6XauOEAvcg38BtpqZQnoDd1O8q"
+"T1IMCV4yJ54i00pYneEPprYctFpIFN7n3UxTIZlj9Ql1iQRpbkoN9Paa3SxZehKtDRt+h9Gi"
+"6asPUJ2/XdNrKbbU9S22lv3T1Iy4s+OG19RGIGnlAKlT4MKIn6p1DqXTyMLDlGJtEZYgbnAN"
+"tCSPbas112DJWTHaWKSNniG4OBuaRS25vKTfSsq0s7I1d6KryuWwpZrCw0vVI1arJBZbniOV"
+"VRcb1rd5MFobLoPU/qDh4LjzpvVm5WCkqfdpTNXMnVCn/Iw0uB2nt/ZWR6JlfT9RilIJCiQt"
+"bkNja+ytSXSPo+RngHfkQ7lvxC28v43rSrkysoZkJJmkyZJGNyzFj7TetFKfo+nYwtrtW47C"
+"/wD21msaxyBu1XcAQewm1avrW1AQRfaw2qO42UVzdjlnTRYF2XO0kM0MYvHEPO9tNzMNK70/"
+"Hzc3pkuHiOkatMGl3EgkFAFGg4aa0QpE2FNHxhjsciYcGmY32L3KulUfa8rHrBhU2SSB9y96"
+"EMDWZZR07oLM5ycwqYYz5UQ3Lsp1v2Ac6H6tEUypXIsJgXHLRv7b03x8hsPq2ThOPK7s8V+A"
+"Ju1vbel/Xn3OSz75QrBiPlUCxC37daYhVCV59tVuIwSW26nka7G2ulQeIk6DUmpWrKeiOFQf"
+"kb2Ci8AMhJN+VDBQNdtraUXj6XOmttK0rqiHobb7eF8EntfjR2aGYEm3yNbW3KgPtlv/AExz"
+"z9SxPu4UblEEH83kNr8OBrh7sdtl5sdPXmq9jK9daS6JoFt5gBxOnM1ovskr/TpgP/F/7q0g"
+"616nlL2VNugHFjf8KafYkxIy4D2o4+KmturYz7Nwv7uizXhjMZ/6ZQS6jiW76yDIwgewIJU7"
+"Tw1r6bkQrNEUYAg8jWF6rHJiM+AwvAbyY7EC+1tdp7r3rso5rBg9RHjTZsEiSC428zwIrb47"
+"h4klVrhwCDy1r58jbztEak8q2XQZN2AsbLseLysvxp/t21Z1e+Se9TVNbDJgNSvlPPsNCyFV"
+"ck6GworhpS7MJDqF4m4rr2ZzLUYDXaOQFU5bHYEXnqfCrFNkAPIVVKNGdr3tew5CnUNzmPu9"
+"ESEgWXyC3MCyHs43ofMdmZBEwXYwYhQflA1ub2tersSaVoWCjc6kWDaL5TtvpUMuZllljjx2"
+"JRDIXA8rDbqgtxY3rxG5tZerPSSwvYxOcQ2VIBqu4299L5rKdoOppj1HeMhmaNoiQDscWPCl"
+"bi53H210V0I3LplUYeOwGu5wzduo0qtOQHE1KRy2HGp5O1h412BCup402KuhP5dALt21pftQ"
+"OY5FAuzSWF+Go0PstWdLC1wLGn/2xmenBJuW9t5U25myan/NWd0+LKTyPc59jFgzKqgM7L5h"
+"sJ83tqjHeaWS/qXupeJWOhN9b+HZXHhSWMu8pihZtslx5dgJItzLV5p1CzGP+VCoQH5mudL2"
+"4XNQpbKLJPX1WNyTYXtYm/DS1qsEUAjjYkPIx272UX3e0crUEmVJJJzVl1XSwvU+p5bxYoQh"
+"TuEjiNj823XS3frVDDVfFAYs6iQ+YG3zHgrX22sK9WSPVMg5TFZrAqkLMtwpjUcxXqfEnkj6"
+"HJ/MUE86znWWaVnDyWUHdttr5joP21o5haRTzuLe6sz1NrEta5YjU93H4GuKqhnTqhdJpCwH"
+"Icaq6LjQZPV4YppvQTeCGIvuZTdUHjUpWBia/ZrQBnbHnWeO26Mq6gjS6ncL119GjMO7VH02"
+"JQ+dlMwNiUtcWOgPbXMpkjU6DQX17jQPR8uXLaeeQ6ybGtyG4HhReSR6TX1sDXN3v5tRuX1r"
+"Qzf3GymO47eQt/D+6kWPdhKvLYf9vhTzrnmhJPP91JMLjIR/A34Vr0aL3F26v2KIHEeRG55O"
+"hH+oV9J+3JFbo+MoI3RhlK8xZ2/ZWAxYk/SnsGNwmwi/KvpPTsU4+NGhUK20GSwFyx1Ndb1O"
+"daSEsL0o6tDHLAwkFwLkac6cbSABx76WdSH6bXHKs7al10PnWUg9MnsatN90rHH0zpsYQB9g"
+"1tYgKi6e81ns1SolXhtfn409+7mc/QoxuBDe/aTa5+FUtRMzYterVZPQuU3OrcSRt8LcaoJt"
+"XRjzuWIQsDqpBA/Gq3J2ItDPIQIhtjfQbdAx48+yq5EKkqdWXjaiZWZEWKVNgTW24HnfgL0N"
+"MC0a2a4OpFrWvyqqrKh5JbKCQTx9lGYpFgKDMehq7HkYEDT2ca263Fsmd1NcDqDq2figJBkM"
+"qroqcV/0mq8/qs+cuyXbE8llmnAJPpj8oHIdtuNB3vVcjBVux0rVuuuDNJgWVtVCF1BPZVEd"
+"72q7JDtIAgLDsUXo6GGH6cOi71NyX0HI6d2tct7TZnRSvxLvt/p8mbnLGbrEFJnbsj4Ef5uF"
+"az7gZY+lZAFgCgVR2ai1V/bGNhw9NbLUW9ZvPuIJ8htbTle9L/ufKaeHanliDAWHPib1r14r"
+"JjbN/Yzqq6+cW8rBzc2+U34Vo89JusdR+nxL+mpvK44KD2mhoegM0QachS632AXNjqDe4rRw"
+"YLwwo4ypY0Kq3pqqKt7DjprXNaNUzpqA9aTH6d0dcSHyoSFTtYjzMT3mk32oSPuGI3teKUH/"
+"AE3ov7nlEsuORMGiVSVU3uW3bW5UF9sf+/Y/97eunYUNTGBsK+6w0XVVkK2imQNFIBYhk8rC"
+"/cbUD1KaGXBRkZTJc+pbjdgLn4Ub94dawssjAgiLPiyH/qCbC9trBR7KzJlYowOmn41WwicR"
+"F9avuA7Br7e4d1BRm5tTvE6Lm5cIyItoRydpYnlp2doqYyOcAgCbhfW3aO2rNqIAVIJP+2tF"
+"ZPSMyCIswUhRckMDx7uNLSzg+bUga+FOv3IG8M2v2q2/CkTskU+/jTbNVU0PAr/ZSP7MYyY2"
+"QRraRbj/ACmnucB5STZitrey9c3dVc7v1NetuK+xk+turRoCCSq7t3Acbftq77MmMfVgp4TR"
+"sh8R5h+FVdZTbgoTqzaX8DS3pWacHNiyCGKxMrEDmBx+FV1bC7Nz6nWc+6sENgpMBdonIJ57"
+"ZBr8abnqeJ6SSI29ZVDJbmp4ULnucvCdZl9HHcDc7kLbW4NzXVWU0zFnzzFglRtzIGRTe2gO"
+"moOtaLozbGtt2h18w04jnpxuDSbJRos4hMhJMePb+rbRlAsSefwpp0fJh+kdsj9NVZiTft1u"
+"OdT1Nrur/Bh2JOjHMkq9h8aW5nzxsNdx2j3iijlYUcInMxWIi4Lnbp2+YcKTzdVxJ82FI23R"
+"q2+SQXC8ufCvRlcXk40nOmg9Z0WwJAPZeqMydIYmZiCSpsONEhYXQFWCKxsrAgXJ0telc0Ec"
+"mcU3GR1sX3AsAlwLcu2k71rVtvRBWrdko3C8PbJYwsA0qawm2j6HjbxNV9SiEcZlWRlKLcjh"
+"vJ4c/fV2MSzhRCW8wDcjGbXuLcRVsipkBYpQGYMGD2GtuAN/dXjxFpxqeltg+f8AVJmlzJLk"
+"tbaLnXlQRSwovqCyx9RyQy2HqG3+EaLw7qp3KRqQK3RkDot2Fx8osKvNhoKqBAkYX0sNatBU"
+"amhjRODHkyZVgQeZzx7BWyw+mw4eCIYbOwUO5Iv5ie7upB0WK2PkZwteIWUEjgdOHHvp0cpP"
+"TxtzNGFBuQR5ra317Le6s7tzAJaEMp3eED1GDs1gNmhsbabrVVNHNFEi32ytcgFbpa+l7EX4"
+"URn2KauZMpEWUomgjjtu3HdwY0KZndmjZ9ztZgW0J23v3UljL0KbOCbPQ6CBtbgedf2mgeoR"
+"dWzWR3WJRGpVVVjzN+dGsGBIPEVJfU2kgGw7K0haizoKIOl56s7OEB9Nth3cWK28a9TBMlSH"
+"lsbltvsAr1EZkNoNplSFbmxOtvgazGeS87XOigKPEHWneTmY/G7eXlsc6+b+7WfzMlnlZoYJ"
+"juJs/pOdtyGuBtHhXJWrb0OmUkAzeWGTl5TagJFBiLX1J4eyj2jyJSUXGm2tpcxtw91V/wBJ"
+"6jJ5Vx5SO9SPxro6UknLSMO6bNQmzW/a534shvawj/4TTWZbgi/HSlH2zj5ONjyJkRmNv0wN"
+"3OwN6bTk2OtrGuT9x/8ARtM26Z4qTKdfRQhfnYWuddSKU4RvLb+634U264P0yRxvb8RSzpMT"
+"z5ixJbcVbjwsBXR04SbejI7ZbaWrQ2+18E5XUIQwukJMj9ll+Ue+voAFqzP2xhSYWTL6pW8i"
+"ALY9960966JTyjnhrDOHt5Uu6gLxseVHudO7toXMF42AGlqixVTAdXi9MvItvOb7eeh40y+7"
+"Zt8mJGR5kgDFuTF+z3UqzQzPKrG5vtv7bU7+9ECHCHZGy/6dtUn8gehlSdaYwuFVIuAtYe2l"
+"bMAb8e6vQ5LRT2k3SIt9oUag+NUSOJOiwzN6ks1uNwB+NLpujdVynK4EUkuKpukhURq1uYJN"
+"M4JcrLWyYkhgY7WYkDQ6N8Kv6vNnzQ/T4uLOtrqvk02jgNGNS7Lz/Eri/E+xmJIMjFJjm8rq"
+"fMCb/GrUxw8MeQhu5LCw/umu/wBA61LoMZlBPFyFHxNMMT7f61FD6eyOwJYEvwv4ULsSebIH"
+"12axUDSQAWfQ9lUZMik7QL0xz+nZHTsdpeoqjRy+WNYyd3qDUG9tAKz3ruTbjrxq/wAnLMyi"
+"HTjiB50Hpz9SkyIo9WijDAXtck20o3/47n4YkGR+lhCxdwbpt7dLnSufacTHHypo13TB1UsD"
+"rtte1r61d1iPq+WCsOHPsNt1wtj4eaodvl9yRaT4xx+pDpOTizY+R03IcBDIZMW5IS4uCL6c"
+"bCqs3HC7scEk6FE3Xtb5r3pPsyfqHxRAzTRmzKupBHbRGRj5YlL5avFI58zNa/tsa6fyU4mH"
+"47cpNdLlY6qiySiNVjQbiCb+XThSbqHWUhmcxZEhZrAhiSGtY30OnDSuZ+IXb0zl488IUKv6"
+"vpsLDnpalZ6dZrHIxh3mUt+C1zK9djfhYpzOoSTyhlZpLCwBsbC96PwcpunQr1BGUZJQiLdY"
+"2drpcDuoVOmQqQr9QhF+aLI1vcoobqMIT00x5zlKoNyEKBTfgA3GhNSJpwQaRmcu5DMzFm9u"
+"vKq5WuALaX0NRjDgWZGv2jSrVVG0kjO3kAbG/uNU2oEpK4yOJNbrosrf0OHbe3mt/rasX6OP"
+"bSI372P7qISeWNBGhkVBwVXew9gIqRmiyOjdSdvKqqTcXZhpz76UdVhmwFHrTxSS8oVO5wD3"
+"AcPE0FPl5bxkCWUk/wB9j+LUGFnkJurMTzI1qpE0bn7Gn3YeQZCGJlQGwtbStJmWubjXZqe4"
+"isz9lRunT5FdShaa9jpwFaLKYsrMx/Ibj2Vx9l/lZPydFK4r7Gb61b6QcrKW17xwHurOMshB"
+"2EC/G9zWg66iukaq24ruLBeHK1zSKKNXJDQSzgW/lGxHj5Wq+p6SK61Rufth8OTpsMrsDPjR"
+"hZVI+QgtrbvoPrn3ViPBJixK4YG5cgWIGmmvG+tKOkRBHlvBNDHIux1kktvHHy7lXhaludl4"
+"8OQ8fouYzqFZx+ABFdKe6MWtmXwMcjLhiBEau4LytyHwrT5PSppcURRiGWF1vKzXDP8A3dw7"
+"ayEKRSRrIYFO651nC3F+w0XDJPj/AMhkiXs+rH4A0Vuk5YrUb0HHUocfHxxiQRqfKQLDzbSN"
+"Vu3KhE6VBNhxSxowVo9+0aCNjrdu6gpppcg/qCJj2+sxv7qpW4Nlx425aNMdOzymle7tEOEg"
+"p1pfdljqJHyukrCrmP09pUY+1iyqRbiDrei8iDKimjzoI3WUjY4YjaVOoJHceyk3T58vEnMm"
+"PjiNiu07Y5m0J76Mmk6zknccmcD/AMNMY7f95xTXYnWLsT63M1C8d3aRytmeQjyg2KbL30vU"
+"kaQmNtIQqvvQn5dSPLbjqL0rHSshiWWCRnbixhAJ8SZhUf6NkG98Z7/4UH4y1g6y9TbIm67h"
+"tHnPIpYxTElGbu4ilJWFdXO4++tJ1TpWVFgySvCyouoYldCT2KTWehgjc2kJAHC1a1Uoztgq"
+"vCZBe20CuloSdLr3i9V5EJR9LleWlFYuMrwlnjJa+jd1VCFIww45I+mnIWxjMmzbfzPuG73D"
+"bRkubjy/TTSY4RIVs20nzC9uBqPROhy5uPIfWWJYnsqtryBvx76ZD7WPBstP9P8A91ZtKXkt"
+"TGgLH1LoZZg0Uq7xZm9Ribe+i4s/oG/1AGDm+pLH5uNdH2p2ZaeAA/8AqqY+0W4mcexAf+9S"
+"heWVnwiUvUOiSuWc3JNyQWBv7hXBldIZDHFIyvY7Qbkaa3rv/wATUD+e3+kW/Guj7VgU7jNJ"
+"u7Qq0vjGrH8vCB1foyQec+lMQWAXcQ+7gWYHia9RH9AxGZllkkum1EtbhwHLtr1EqNwhzoO/"
+"VYjTXsvrXgwtrcHwpF/8gQcAR7TUf/ka3ta57zWXsjX6j0ut/KbHwru8tx/CkD/cS2/li9dT"
+"7kA19O9ON2g+po4SdQBepTXKnTkf20t6V1RMuf01FiVLEg8NvKmMzeQXF/jzrn7dSq6mX68H"
+"VCykAMRyueNB/bKl+qIijzFH+Aoz7hP6Q158eHAk1nEyp8VhNA5jkGm5dDZtDW/UppBn2OLS"
+"fRxjS8hY91eQ9Ugk/Rn3ILXhmUsOXBxY18/Xr3VF4ZMh/wAzfvrrdd6m3Gdj4k/vrRUstGS7"
+"1eqk+ly5DyxbWRo3FmDqbgMO7iRXMjMRcN5gNxCnQDn/AIeNfL26v1A/85veaLhyJSgaR2dj"
+"rqdKpp6tiSTwkW5oyXYhIpdxYMziNraa9lPvuDIi6pgxy29N413JvYb7nRgV5UiGRu02i/b/"
+"ALGoGUsdY1PiKJgrhIslk2naB5uBNGL13qgUKGUACwsijh7Ku9WxuI0A/wANdGY/AKoHctDu"
+"nqpEuprS0FLda6tINpmNjpoAv4VAZvUzwnm9jNRYzZ+RHutXvrckfmtQrL9KH+N/qZXjdT6t"
+"A24M8h5CTcwHson+uddceRB/ljNU/X5RPznWvHMyCLbzSbX6UHB/rZX1CXrPUo1iyY3ZUO5d"
+"sZU3tago+g50hskMl+Vxb8aOOTN/GffXGyGB1kvoNb01aNEkJ9aerbOQdI69jKyxJJGGN2Ac"
+"Lf8A3qm3TevH5i3+aUf/AF1X9T2yfGujJA/OPfQ7Pwhrrr+phvR+n5eB600sYklcjbaVOA11"
+"17ah1ODqubJu+nVeJuZUv/x0Mcxfl9Qa99cOXHw9RffS528B+Onk9F0bNYDf6aX+Ylwbe4mj"
+"R0BARuzYrd1z+JFLzlRX/mj31z6uAf8AMHvomwcKef5jI9ExAdc5bcyEP/1V0dEwDxzgf8n9"
+"tKzlwHjIPfXlzMca7gffRN/UfHr/ANMbHovS1GuYf9Iro6T0nnlO3gFpR9bjk6m/ZxrwyoP4"
+"rD20pv5Ycev0HX9L6JbWWS/iv7qj9F0QDR5D33H7qUHOxhoG+BqJzscC26/+WlN/Ucdfp/Ee"
+"DE6Dz3n/ADf2V44nRAAUVj4uf2UgOdBfifdViZ2IrAkte3IUPn5Yf4/Q1/Svp0ZcfHAVb+oA"
+"WJvY62pxlJo99V2+Udlqyf27lx5XVYPRBtGsm8kWsCtazKberqPzDaPabVz3blzqPEqNDPdc"
+"S0ComoCFvarbdffSPB62/SGcpEJPXAGpItsueXjT3rsV4SxvqNNdBc3/AGVjc4jyEd4rbpWM"
+"mfY4eBzlfdX1Q2z4kcijgGLH9tAv1PDc3+hiH+s/9+lO6vb+6t0ktjN2bHCdZhjt6eHAtuF4"
+"93/ETTCDreU67gIIVPACIfsrMb6ITM2qBs+Wk14HWy3NL/WMzlkqP8MQH7ai3WM0/NmOPBFr"
+"PjqNjfZXf6l2x39tTFi+VB6erSnRsyY37FQfsrg6qWP/AJvJHbYqB/w0h+uv/wAoD21360/w"
+"fGiGHKg8/qJtf6jKP/7APwFcPVTzlyj/APtP7KRjOb+D41IZz30jFEMOVf8ASHM3UIZAVcTO"
+"G+YNIxX3ULuwFJIjdfAg/soE5rkfy199R+rf+Ee+mpBuj2TDh/Tmb9WNpb8ATa3uq8Hp6Af9"
+"OSp1A9Rh+BpT9W9+A+NS+rlP5Vt260OfIlw8Icrl4SLtXDjt/e3Mfxr39SxV4YkQ/wAv76TD"
+"KfibVE5Tkg2FKH5ZXKuyQ9HVkUXGLD3HYKmv3Hkxi0SRoP7q2/CkRynPICuevJ2CiA5L/SNA"
+"fufP7Ft2Wrw+5s3sUeys968vd7q5683K3uogXJGpXrub9M+ULWVwliNfMN5H4Wr1JPVtgM4b"
+"9H1RGi2Fy+3dJKy9wsAK9U7/AFgcoF+s027CfbXPq+yP41XJE0LlWHgRUQ3IcTWnFGfKyeS/"
+"6oEeZbeGtdGbEBYqQapCNe9QZCTpQ6ofJs1P2dL9R1CQhAiRRm543Lmw/CtTNfaACTfjpWc+"
+"wIrfWMRr+kAT/nNaeZiFNuI9vbXH3/dg26299TK9fAERGxjxJPAcf7ay2SLRkjtFvfWs6+fU"
+"SRQCCBe5PJbXrJ5P8s+ytuj7TLt1BQz8b17fJ210Vy1dBkd3v21aMvKAsHsB3Cqq7akNNrRl"
+"n1mUdPUt7BXvqsr/AMQ/CqudWpFK4uqkiiF6BNvLOGbIPGU1z1JrayN76n9NPx2Gu/TTfw/h"
+"Sleg/l/2K/UmP/Mb31zdJzc+81b9JPyXjXBjTE2tr405XlBFvDKrvyY++veb+I++rvo5xbT4"
+"11sSbibe+lK8hFvDB7kcSffXr9pog4kw4299cGJIdQRbxpyvIcbeGD7b17bbjqKJGJJ2j310"
+"4kg5ijkvIcLeAcIvZXto8KvGK5Ntwqz6KTtFJ2XkFWz2BNo7KkFFuFEjCYcWFcOG1/nFHJeR"
+"8H4BiorwFqJ+jJ/5growz/GPdRyXkOFvANuN67cdgvRAw/7/AMK8cRR/zPhRKDiwfbfW1cKj"
+"sooYw/8AE+FeOMv8V/ZSlBxfgE291S291FDEXk58LV5cVObn3U+SDgzQfY6iMZUh4lo0HbqG"
+"rVZLMq7lOm7h7azv2jEI/WCkEbhe/E+U2rSva1zqAbmuXs+5vybUwkvBn+sR/pFnLMdt9dRq"
+"eAHtrHZeoXuNbjrbg4zFGVTtFja5rFZg079xrXq95M7gRArwAqe08Odd9Nuw1uZEAO6vEVcI"
+"n5KfdUlxpm1CMfAGkOAcLUrCr/pMjiI3/wBJorF6dkupJgcjt2mhsarIurppoOnSlyghbcOI"
+"2m9Wf0nIt/5d/wDQanmiuDE1q9qKdr0nJc2XGcn/AAGut0XNXzfSyAdvpmhXnYPxvyIiTz4V"
+"JStNZMCWJN8sLKhNtzKQL+Jqq0INtL9lHL0Dh6oBAubmpWT+yjQ0XDy3rzTQAEkqKUvwx8V5"
+"QAwHIGuW7qLORAeDrXfqMe3zrTl+BcV5A7G1ds96JE8F7mRRUhkYwP8ANBon0BL1BbNa9q55"
+"jyNGxyRyOEjYMzEBRrqTRAxZATfla4uL3YbgLd41pcvQfGdyjBgM8c6sQscMbzkniWClFA8W"
+"YV6rvUjTyksu8bT5WF9RblXqmXMwVCiJRMoDowuDyNRXFg/8MX9tB5DyqpdGJFyDcn82lBSy"
+"zBreo1+4mrSfkl3XiR6IIhoY1HsqXoxjgqj2UhhllvYufeaLEc0rJGhJdyFAvrcm1J9be8DX"
+"cq/2ybf7QjVhlgcbpc91jTfJWysL9v7aB+1ITj4k28FHaSxDCx8oHb40wyrEk2ub2Hwrn7ap"
+"Y1yVW7tZuIkzHWrGGQEgeU2v2isjkBjEbC/C1q1fXWQYtwAGOgvzH5jWcgb9QeB/CtehY+pH"
+"a8i7a4FypA8KmsMrGyoSe4UxlUtHYak2Hvq6DSXIJ47rD2V0RkwkVjFyCbCNifCuth5Q1aJh"
+"7Kexj9Q+FeyASLdlOA5MQDHlJtsN6PxYpFh8ykW7qgSwf31JGYbj28KiynBVbtOUW7gvzCwq"
+"TRkg6XAquS7Mi34sKvLk6DmaX41JX5rehUVbhbWobGU3CeY99Fbbk13ZblT4VQvy2BTuUhnH"
+"gKi0hOm21EyqSdulQkXUAAeNHBSH5bFETAllsSVFzepCInUEAHlU4kUvIfzaacqI2i2gpqiF"
+"+S3kCB2Msdr7ja/jRJwwTrIBUSn60ZI/MDV7kW3Dhc+2jgth/ktpJX9EVswe/dwqiUuoYgXt"
+"V7sx5k+JqmQuqMw7CeFLivAfkfkkmPuiSRvmYXPtr0eO8lztGhA0qWyT0QQddovROLG9g1+Y"
+"vT4rwL8lvJT/AE9raadh5XqONhPNkmLcQApYnvBAouUkFrNqovbvq7pBLZJZRc7D8SKmPQfJ"
+"+TMPmTKxAtxIGnfURlzXvp7qpl+du25/GohhTheBcn5CTkznmPcKuhE8rKAw1Njew40FvvTP"
+"pQWQ66kMLe2iB8n5CYYp1uDGrWNvNw+FW4wUF/UjV+FtwNhpRVx8o43vamPTMZZknDgGxWxP"
+"tqWhq3kM+2RG0sxRFUKUI2DQkq3bTSRrKbfma3vND9JgWDIk2C1wC594Fqvk00FrbrVz9nj1"
+"NqatinqokaNtxCwOu2wGoN/7KWfaPoN1ZlnRXVon2hwCLhlPOnHUAu3zoWTgV4A1n/t6Jsjq"
+"npqdpaN9R7O2r624km8SbeNunNmosccVtrHRVFiPZRxTEtfalu2wrKp0/Mx8ssD5mU27her5"
+"Is0YMszTDcmpjsSXH7+ytObmIJ4KJk0vpxWFlXu0FSVVA0AA7qyqdazhEvFFCi29CCSNKJw+"
+"vyKgSZbuzN5h2acqpXRLo/JorAcK8DckW4Uvh6tjySKpbbcNx7qMjyI3YqGDEHl4U1ZMl1aJ"
+"bQG3gWJ0JtqRU6qkkQcTw191WaGmhHALN414lSCL8RVckhWeFeT7r+wXrrfzFI5gj8KAM/8A"
+"dhROitF2yKR76+dnWVdeINjW/wDvVb4qm+1Qbbe03r56zfqWGluFFXj2YWWnqdUkZCjuPxqM"
+"pFmvwrm4/UoD3ioSt5nHK1UIFHzCpXHtqI+cVw8TSGdXjXVcg3rg41MJcW5mgAvCzRi5MWQ8"
+"YlWNgxQki4pxhZWLlZ6oBeMxiUsdXEqR7CATp8tZwta4q+KSSMhkYq1iLjTQiotWSq3a9jTT"
+"7Xjjgx5VI+nCTSrYINhLFtDbVeNeoOGL08GR9hN4CBqdo3L81epcHETgrmtTuVgZGGXgyYip"
+"IJAPDTsPA0lniZOPvr7IYsefSWNZF+WzAEeY99Zjr/2bAwM3TyIiQbwNfaT/AHTy9tNPclrM"
+"Hz2NrOCaaRqxnQKPzD8aW5OPPi5DQ5CGOVDZkbQinWDteeIj/F7LVTJNz9ueocJyTc+o2p1O"
+"gWictHAJ7eB9lQ+3E/8ATie12/ZRGSjSeTge2ubso9fU2pbMGS62B6TbRdrEX7OZFZuLR9Ow"
+"/hWm69HLeUK5GzzMRYLqe81m47b7dlX1JpC7HkKUAGO/JhdfA3q/ExmeJpNy2BLkFgGIvbQU"
+"MrAyX7Ln3CrIZBGg57bn31o7ZMkgpADIW5E2Hs417JsNoHPjVULhUVyTcliedSlbcyA8yPdT"
+"dnAQCxJjPKA5ZQTqxIAHuBoj6fBUXL70J1CElv8AeUCgwLNrRTJCqqEYsTxuLVK+o/oiMseM"
+"Z4hCXtck77ctRbbXUjvKByq3FOL64+puFAJVhyNjyuONFf8ApahTCZJJNd24BR3Wtem7R5Yk"
+"vYpEI41wxi9W/wBTwUYK0Ba1r3NTTJxZrbIyoN+Ivzpfkf6bFcV5QFKvmqDoLdreFMWkxA1t"
+"qkjiWXS3srsmZ01ACAgJ1IKkn20vyW/TYOK8oUxLqxtxNFen5QbVdJkdNMe9CSd1isaDUns3"
+"W4V1OoYKRgnGlkPPco4++muyy1pb6E8V5QG8Y9RT2H8K6yeUCjG6p0khWfHe63soW1yeZO6h"
+"peqdLOqY01+S3FvxpfltP2XHxXlFRSwqEsY9Br9lTHUMVxrBJfkARb8a4+ZjzR7PpzHY3BuS"
+"W7uNObPZhC8oNREEdiAfKBr4cqtxkRUt/eNVSMFNgCABXYpgFBsdSa0U7ks68amSQAcTa9Ed"
+"MVYsk30smvvFDLMC8lSxprzSkckqYzPqMyOQo9V7fxG3vqi1qulcF38T+NVEiqA8L09+3yVE"
+"hvpuW4tyN6RKwvTroUi2lB5lbfGpspUMEPRIq+b9lE4JOQJWDH9Mrw0437KVvINmh9tG9EyN"
+"seQCNXZAPZeodFOhSY+6UG9WUsSQUUC+pv5qJlIHD5g3Z3Go9HWOWSUqLWCaeBNHzY6Fge+5"
+"9oIpfiTyUrxgQdRMjQswUkXuT7L/ALKS/agZOuoJBrskBHftrVZ4SPGfdpbd48LcKy32+yp1"
+"2Jjfawddx0uWU2p1pEha0mzVR9YGI0KkXoiRVsbi456VGJAZQeQ4e6r3RSDVpEtgmTHjIoeV"
+"V2jUki+lCzdLx5cdnjUAsbqQORI/ZTQpoLGuKpCAHU60nUORnW6PKDZG1Aa1VSwZ+MxKkliA"
+"BtPZrr760tluCR21xUja7c1a9++1qjh4L5mTycjKCNt3HQasbN38KOTr+QkdjZtlgCdCeVM8"
+"jFga4ZVO/Th2muzdLxNgUIADxtS42lwPkt/5iyPq7nKgE1n2s4FjyKm4o09RRsmB7lY133v3"
+"ig5+lRR5MEam27ezN2bQOHvqjKxZY3jhja/qhiL93bUt2XsNKr9wf7smkmhmc/y1ZRHw4cz7"
+"6wWQ49QWPOtZ1w+ngyQSgExmzOL7r8OZrGP83GtqOVPkzvqiwt+uvbfjVbNctXjfeDUeZqyC"
+"INmBrhr3Oum2nLtoA8vzV67A8a8vzCvHiaAPXvRajcoPdQgomN7RgX4UAaXFlR+kzWA3rCQQ"
+"QRoE23r1BYeSBiSxHQGKSx7TtNeqQNZJ1GaOIOkzEkkm9j8vDhTb69MvH9Tbo6qyg8Qxteh5"
+"MKCSF0Cjcx2qQP4rrVEmNkYm+PdZIwNRpo3L2VlLWhvh66iX7kxosmFp5RudQWVh83lW3jSP"
+"o5ZZNrggxjUHjrwp31ElYiWckgHQ/hSjD2o0jgG7kHmT7zVdbnBF41PoP22wbpd7cXb9lHSI"
+"hu2y1xcGgPtdx/SEPa7/AI0zlkUAe/Tuq2kyE2ZH7hEe2Ubfmsp8Rdh7mFZInab2t31sOtyp"
+"HjMEivxBYkCxK3v2njWOmdT5bgnspwoE3k7HKLuxIG1SRfvsv7a4Z7KADzqkkhTY6ka1Vve1"
+"ialpAmMfqhtVSQB4241KTKWwO5QRw816WyOStuPsFVlmPIe4VUIQS+Ra1muSeVeXOYaE8KDu"
+"a5rSgBhJmqV0Bv21UuTIATuOnfQw1NifhUm0TvNEIZd9TuFjqe29W4mcYZt7ruABFv8AtoKP"
+"jU2XUngKIQDMdTicgEbb+FceWBvMJACeR00pWurW4jnUzcE21HfrRADOKeOMLd1PE8bcaKOX"
+"jGHSRL37RSEmy/jXt1kOl/bTQBuRMrsQOZtQQfUivb9KgvdQBYZyp0vVsWW7yomvmZV434nw"
+"oNzrVuEwGZCxNrOpueVjegDVZa2ZyO8VQrAxqNe/31yfOifd57991/fSyXJHJyLcdf3VSeAY"
+"zRSptobi5qGHIBJOG5gLy/bSxMn0zYnW3aT8aobIBcm2viaSEBSDztYcz+NQq1uJqFAyNO+g"
+"AnfYDQgfBqTACtB9uINsrdrqB7j++kAVNuSIjgT4VZ093WF5OyVR71q2ZEIIJF7VPFSJINpt"
+"rKpt7KTQ0aj7eL7JQQN1gfxplIZrgC5PM8udL+kSwJJJtYAFQL8OBo9p0JOvy0sRqVDnQWdQ"
+"fIcNCUOp0OmpIIH41kunl16vBuFgsn4AithlZSHcysDY6jTsrFY8ynq0Pm1OQB72tVJqNRNP"
+"wfRMVgSp8aJa1A4ps4H+3CjSRpQJkmNhXha3sqE7bV+FdU6nuFAjlhssK6IxYgaE1G/Be7Wp"
+"K4IJoGDeV3CcfN+FXSKSdOyhMWJlzJ3LEq7XUchYcqLkcBb9tqhaMp6oGMIkyopHvuVXW3Kx"
+"t+6ouIjkxKfyK9j4kD9tW4rGSVnPED8TXZYES8ii7BbfG9ESpQTDyYv7wiRN7rr6z7m8RpWK"
+"lA3i1bf7zBISTgpstu8C9Yplu+tVTQmzyUkeaonUmrdpMo9tVlTrVCIjVhXjxNetrXiDxPGg"
+"DnOumvWN69Y0AeFWA6VCxtwqQvQAxxDfHlYnhG+nfavVTiWYSI3D0pG9oQkfGvVP90FbG46X"
+"10z51p2WOBVLXcj5gfLVvWOv4wUiO0xGp2nS9ZMsFQ9pqh2vWYcgjM6hNmzl30DG+0cKlHIq"
+"jQ0Ig1B7KtFNQTJq+hdRmjxEhvtju5DHUXovM6nkqlhMCArcB/ZXvt3GSXosDFQTuluT/iNE"
+"ZnTccoBs12m5BpQ5NU1Bjep5mRLAzeqmrWK383DjakaFvUudTWk6lgQRg6cT39gpQ0Ea6/hV"
+"zCyZ2eQdtR41DaaK2R99cMcfKlyQgcqbVH0zRW1eyvBB2Wp8hAnpGuemaN2rao7B40cgBFjN"
+"6lJGbCiQADrXmUE8KfIAVEIqwqTx1q3Z5bWtXQtLkgKo4V1PPlUjCaIRdL1MpS5DQC8VVmLh"
+"pR7RiqinmFNWQMHEOludSEFqvANSNxRyABMFya6sFiDaiCDXgppywOGNQPKxB9w/GoGFiO2i"
+"ArX766Y5ORpcgBVgsNRXPp9b2or0n7RXtjW40cggEaAVz6aiSproU0uQQCjGFOOksmPjvcXJ"
+"e/G3K1BbKKhX9LiOPA8aOQQHS5Km25Rt5a1AZIWx2jRr/MKDkPdXlFDsM0XTsibJ9QQWugBY"
+"AnmbCmBedQQytyv5u6hvstNcxiPyxge9jTx0QMRYaj/sqYnJpW0KDJZ8m6UtErg6a30tfgbc"
+"6QxLIc+JiLkSoTa/Jga3GbCih0UAa/sNZN0AkJAsQSaaTqK95Npj50Affe4AJ3LfT3VfB1XH"
+"lyY4k3ElrKTa1/brWJSeZCSpIY/LY7beyr+nZcydQx5JHayyAm5tw76fIk3+VJawtfUa11Jg"
+"FZmsNedKZ+opKbrILXGga/8A3ajl5uxRsl2E8wR2d60csscYHCSpIC6kGw5d9cBNjUYSTjoT"
+"qWUEn2VFpEVTc8jRIFkfzHuX8alKt0A7KF+qjhDs5sLAXq1c7HlW6tp4Nb8KKwD1LcaMKWIH"
+"G1cznKQEjjU4GBDEUN1Rj6QUcTer2J3Mx91oj9Pxi3zs5P8Aumsj9OhfgdBWu+6GPoYkdtRu"
+"PuCis0qEsb8KltqED1BVxk9XgdBVr4aDD3hdfW0PPayE2/3KtVRuJvyq9mRcKMSLeMTBnUHb"
+"uBDG16m1nj3FApEC3qYWMR7NiHW9yvm8L0RJ6Zc+krKutlZtxHwFFYY6d6Z9ZN0/ISMVhtb/"
+"APrG6/jRyY4FnpxXv6a+wn99c9KE/k+NED5joOJsOI99cueG0eyjkBR6MP8ACR8ammNA3zMU"
+"8Vv+FT2c+FTCCwokUEoMeNCxDXUo6lrHgyleFeqyJLK/YVNepTmStoKXvcXqB41OTjUKSkln"
+"VFTHGopUudAjffbDFehQm19XJ9rmjJ3uB221HdQX23/7BDw/P/xnjRD33H+y/CqzGhpgzXVX"
+"bayNrbT4UhlW4p71f/mceI8eFJJKHyIZR6ffUtgHE1Kucx+2l8hHVTdwNdEP941ZF8p4VIW7"
+"qWRlXor21WyKOdEta35Pjeh29lPIELC971EkXualpblXB7KYjt9LV4A3rvOuDj+6gCwEjQe6"
+"ulmIqo8akeAowM8xNQvrXWqI+b91GBnrtXS1c5GvUIRy+tSr1cPHlTAmCO29XIAeP4VQKITh"
+"SY0RawBqtjpVx4HhVL8KAKy1eDVE12kGSW6r0ewA0obnVi/KKALXavKw7ag1++uLe9MDZfZy"
+"hsXLN7Hemv8AlP76bzQuHWx1/spN9l3+lyeP8xez+Gn0vzLx5/spqIKUiPqIkiVpN9yb29lZ"
+"oKfU760/Vv5B8G41mFtvPtpPQRNr6X41zQEbuHdXTbdy9te58qQBGMwDaEhRw0FGmQnnex56"
+"Uuj/ANu2jE5cePt9lQ5KRoIuoqoRSSbIOVwNPCqMzPZUurHXnYUKL3H875Rxtf2VDL/lD5rX"
+"/PVZjQZwZ0kwkjZ7qB2CqseV4N2xmsT5he9x2a1Vj/8AM4ezx51Jvl/2vxoUiNV0Ri+DvIA3"
+"O1vAV7qJ3NbsAHvqHQP/AGtOPztx8eVSy/5h/wAtar7V7E7iH7hx/VSJ/wCAEcbcTWcKvFdg"
+"SrciDW0z/wDyh48eVZPqPz8/bUMGULlZINy4YgfmAP76sbqD+jZ1SRmY3BFgtgLWsPGhR7ag"
+"1vZ31FuO41J55NxFolA4kAnX21M5XC+Oug011+NVNttpb2X/AG1WeNGPUMlk2Q8jswiUA6Dt"
+"H+mwqkPP/D8K6vGpjlxqlAjqlrWYVbbThVR486sX/a9AB0MQEDtbUoRXqIT/AMseHOvUbAf/"
+"2Q==";
+
+static const char *easter_egg_photo2 =
+"jpegphoto:: /9j/4AAQSkZJRgABAQAAAQABAAD//gBtQ1JFQVRPUjogWFYgVmVyc2lvbiAzLjEwYS"
+ "BSZXY6IDEyLzI5Lzk0IChqcC1leHRlbnNpb24gNS4zLjMgKyBQTkcgcGF0Y2ggMS4yZCkgIFF1YWx"
+ "pdHkgPSA1MSwgU21vb3RoaW5nID0gMAr/2wBDABALDA4MChAODQ4SERATGCcZGBYWGDAiJBwnOTI8"
+ "OzgyNzY/R1pMP0NVRDY3TmtPVV1gZWZlPUtvd25idlpjZWH/2wBDARESEhgVGC4ZGS5hQTdBYWFhY"
+ "WFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWH/wAARCAF+AYkDAS"
+ "IAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQ"
+ "AAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3"
+ "ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp"
+ "6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAw"
+ "EBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJ"
+ "BUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RV"
+ "VldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6w"
+ "sPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwDaR28tk5GF3M"
+ "T/AL2P5U2AO0sreYHVQShI9Rio7WXMt7I4LEQp07HcR0qvJqIjmFrCoMvTLdB+Fcyi9jf0Lt3HlSg"
+ "XcX9OOg4pHWWCBGZHaRiytnpg1Nalz87De3U5/nWjFIs42wnKg8sapQIuznbZpLZkgXO3zS5OcgdO"
+ "9W7G8eCQLK+6SUkEZyCMnoK2JbUGMrCqqcYUkVSt4IN/2shUYDy8E5AOf0qZQaHzEer3EVts8yINE"
+ "+U3jgg+mazysCopWXdG0p6nB7cfgQKv3KzymaAxq9u/KnGdp+tY11ZzSzhoY9sTY3I68E9zn1o9R2"
+ "NdhvXywB/eAzwc9R7VEAQ3mxhzksuCOhBz/jUPlkrHHFLmNf3bjb8zen5VegkeSNVU4jIBZnGO/wD"
+ "OpsDKZm2SJ+6ypLEg/eYEf41bYPK/zOkSMPlU8k0kkK24aVFMkrnBcDkD6VRZmjkSYhy24EZbt78U"
+ "rXEl3JXkltQIreB3GQGYDcRxxxUj3TSMpbJB3EbuwA54+tZgWa/BNruTbIcsGIA/GtmwdCqpMysYg"
+ "cM3Xk4PNWlZDbvsRmNlt55GAOQSn0/wwKr6jardzrOgQR8BXjbrxwP5/nWu8TO+2LDerb+lMuLa4i"
+ "jcwIAoO7aAOenSnysLnOeROs3znywGIwecZAq7Fvjg2fOJI34Kjtjj6fWpGu5YHV7htvOdpHJJq5G"
+ "sj7pJHZUz8q98etDugGwyiMRSNIWZ1JRmPQd+e/YVXuIkDLsUhfvZz93POPxqRQxOHKuifMg6ke2a"
+ "inefzGcsQnVVKjkVm0N7DyChiCqWQFlyOxyD/jTtSl22u4HiPaSwOOjDj8qh0ne5mt5Gy0kIljOO4"
+ "yDSaqXTR5wAo3INx9/akoiWrLuqSMJWjgCBxghm6jPOfpVX7QQ6tuZ1UEFiOSccmnRXiXsMF1Coll"
+ "KrG6kfcOOaSeXY4ijtmJYZLYwB2PP41TvfQV2Z14UN6wdGEc2D5mMHaF7+4zRqboFjVh+927ix6Dg"
+ "ZFaAt1kCIqBlKkZ6nPbr9KguNLYzO85YrsCcDk4GKEm2hSaMq0DXVoyy48tGyhz94cZx9OKRpP3m9"
+ "SCdm09uR1Na2n6bGMJFJvRFOFYbcZGP6VTvLUxqbxAJIW42pyFz/AI02hXL9rL59q8Yy21BvI+gOa"
+ "iaRd4lywXDbSehHSm6aH2xF/lV3xuXox9Ppilbi4MWwCKMqqY6HJ4/rWDiyi7csou2mJViYhsTrz3"
+ "J/OlhX7QivchopXX5tvBz3/kKgmGLuJmk+ZjsXjj72T+gH51Np9zHfkpE6lQxXgHOQec01oNk0ttC"
+ "LUQiRwWH3mAJJJA/lSjTDaRgxynj5QWH1x/OpXZHmjwNwQfw+n+RUu7DGNJDlCCMjsfX171roxJGS"
+ "tvJG0obcMSBkPUEn+nNTzQghlaQeU3zJt4wO/wCtPdwJGdtvloGOCOcjkZpj7gcNggRtk9MdM/yNZ"
+ "opdyN7h1EYdDsXlu20KCT9c/wBaoQ3kV7IkuW3MwwpHGev51q+aHilV1GCgUn3OM1mS2rfbxOgRYO"
+ "qrGOSRj8utWtmTd31HwO6ytBgw+VE5Yr0LMcfp1pSRJCV4EeBtI9OaJY5RM6AgFiAcdWOOfyH86VL"
+ "WQxqFPyg7mJI4wen5VkkIatxF54cttVsoV9CODmrIcK/lLuyxXcw7gf5/Wq15A0krPEIgWPLZHGep"
+ "qa1gl3bC0buyAEh+vStI6aiNPT547oSxzfOnQb+/+RWJ4j0iC10O5ktjvQyRypznaM4x+tJLbywyQ"
+ "o0iLDG2XcPk45yCPyrftxG1qkOxZbcQlc9c89K6VJNA43V0cLpEnlXTIXDDpnNdCJS6knsK5/WLUJ"
+ "qH/EtESIDhUD8/jmr6zXkWmZKjzJRk+wH/ANeq5hbosMcuVOMEc1W1G1llgiMJwQ21xnAPHFUIZLp"
+ "7lkcsuCQSw4rZkElxp6iHCtuO8PznPTAFLmvoL0MWC2u1D2tzCVVSCkhXI3ZHGar7j/s/rWrBIUk8"
+ "q42qMEhopWGMeoNP2Q/8/Y/77/8ArUnKwM0tNuVmn1L7NJkmAMjYHJXPOK5mB5pH+0Ehyct15zXV6"
+ "baQWevRLDGFEscgYBsg9Dmqh0pLe82QLjDEPvB6e1D0TLb0sW7GWSQrGitvYgYI6cVuP5enWQVQcD"
+ "0Gai0mzePM8xJdhhQRjAqvq0lw90YoFJ2qp+vJyP5UR1V2StWWotRjkKphlYjPTkD1qrdQRmcqcEO"
+ "ASvTJz1NQpbXKzpK00eQOC3JA9KiuXJuCkjtJlDgBT7c+3Shy0NEjShu7eZ/KRS20AnKjA9KnuLIT"
+ "I2JHUnnliRWRCYrd9vILNuGGyOueK3llVoc56jFCaZLutjEmDW0fluiySk84+6PT8aaZEmxKzGNSA"
+ "Fzxhvp9afqE6XLtCgDGNhlunPfmiO1hfDsFLhcEE57+lZSjZldCvJGY5BumkjMjE5Xv/wDWFE0jSE"
+ "QrbG4hVTvZ26Y9KsTAtC0kcfmYHygDv/kVlzadHcOrrI8EgPzkED67hmknYTdtzXgtBPBF9iUQwqc"
+ "PGRjt/PpWXdb4LyYSZyTtRyOFBOecVps8en2yJFyu4DOec+pxUaW738Czzpv3ufLZcgqvYNzzWi1Q"
+ "htvK9u6oil4CwJYOCcn0rY+04UsdvHYnFUnsxDbsyqrFT8qxjGOKzkXzTE0rMhU52t8xPNF2g3JNR"
+ "urJ9SVyEYhcyNg/KoqWK4+1K0qLsjz8pYHkVnX1q8KTtGm8FvN9M88DHoOSfwpNG1aCGMpcMqqzEr"
+ "np9KLofkjRuLK2e1aVZZd24FcNkA5p2GlEqPGcgbl34JosZY4jI+SLd3MiLj7owB/PNNa88mbIj3M"
+ "VxuA6gDjNTJ9BFB7xLLWLAg5UM8btn+8Rx+FGvMkNleLuXdI4jAx6Hk/lWbrz75IGEYiO5iB7DGM+"
+ "9ULm6nvHVp5CxAwKpR0Q7o0/DbyDUEhVsROd8gPovNWbiWeYu0TFlmm8pDnGAuWY8flWdphZJJpl6"
+ "xxkL7s3yj+ZP4VsMXszbwRBXECbn553GlN2AktSfKiMkp8zaM9OR1rWhk3kK7fLtLqO3Hr+dZJhWW"
+ "b5VLsvUk5K8f41J5ixQMhBJ2EE85AHas4ysydya2MSws8SHYZAXwOD16fkKpO/lW9zCxI3LlCPXGf"
+ "0xUkMhlXgyRKuCVwMDGOc1noZXlkeNc+UBtyMN054/EVXNbUDQglWGBotq7oFDEHj/wDVio1ERK7y"
+ "uHYP8p6Y/wA/rUFjE00ksSyLl1LSFuhznjNXV05YAk8sgPHyoO/tUN3KbRXkmD3BkYAhSDF6H/OKk"
+ "shFB5wt02sdzFgeMkiktvs7Tyx8tERjaR93NSQQeS33QwIJDL07Cs3oS9C0Zj5bRhdi7N24fXv+tI"
+ "9wLeSMAhjnkdSOvNQeYzPyu6NiUbnk8Y4FUbcym8b9w8hZuT+X8qcW+pSNC78u6iSTBJc5GRjrxz+"
+ "v5UnmpHbPLhyi9R1LZJPT8RTk2qrjqdwYgfwjr/n60iYjgUu7KXUFlHdjjipvqPqRPfwhWaRAsXKg"
+ "4zz1OfxIqG0LI0RmfjBGDzz657df0pShdGh6kn8M9cfyqMzxQhRLtA3YbHRe+f0rS+lgsXm2Rv5gD"
+ "Ybdgj3OKfa2c2wyyb9x42E5AFQyzGULFGxZlkVWI/ukZJ/D+takcwSVdvKLwcHqacY33ERPprfZ/J"
+ "VU2MOc5yOeazIYls72aNjsTaW3AZx06fka6cnBJ6+gqjeWMc6mQnE208A9RWsoK2hFzF1KK0uIjOP"
+ "OC3HB2gDYRjOfrxU2kahEkbpvTch+6GHA6AVdUCG2EJtyRIf3h69ehrEi0G3hEryzxfMzcbjtIPsK"
+ "laFJ26D9T8ma+WOK38iTBkmx1x7fWop4LW6T94/lofmCntjsTVR4J7HzRDNHLJIdm52JMagcDp61b"
+ "kt4TKss8nzgAqG4VsDn8KblYV10KFjayR4lMZljXcrNtzk4OOPQcc0tlLdHHlTv5EfLHYcMPTNWLk"
+ "6mJJJkKwxKo3sCFwp/WqNvfLbvtvIGlVTlUJIUn1qlsUi5qFk10ym0hf8A1ZIyM5ODnnuDWJ/Z+of"
+ "88H/74NdFa6i8twjsEVQcNtHqcc+g54/Gtz7dYf8APZf++jUttD5blKxtri31O0EgiO1jkoc8MD1r"
+ "pHt4ncOygtjGaybPQ/s+r/bBKWjAwq/5+tbdapGTdwxUbIrZ3DrwakqIODuwQxB7VQFK8t0jhCj7g"
+ "4A9KzH3IXZWcnIAJ5x+Fb8hQRky42AZOelZXmiUKFUt8+U2nkVnNFpshliRlDCM7sDYpA7en51Wl1"
+ "ERq0WMHJGDwa0FCypmZZYWUn5j2Gf/AK1UrywgvcypIsik43hef0rNKw0ymZFncqsjrsYEbl4JPfH"
+ "U1faEbZHVyZTgElCAo71AsBto2cKJOn+sG4/p0qWSWd4WbaGBBOewpN6lk4mKeWyEtjgZX2pIDG1n"
+ "JHIU8xm5AXkgeuaoxXKWzIlzlPMz5YbgMP8A9Zq/dIzLGRtj8w4G35g3tVJMWhnXNrOx8yz8ucjcM"
+ "hgNufWtOC6Gn6dAjNJK23LHbnHr0qrp8VrPfzFo5YGGBuLY3+/4VbNklncjySQshJ3AcKe+f8arVI"
+ "nQZHrDSTqhRgA3OAcFCMhunvV57S1uY95VDg7gVrOuNOb7Ys9tdssaj5o0PU/0FRXF3OkMV0u2I4O"
+ "6NmwAPX3pJsppPYtRC2kbYlypEZIId+tZ1xbxWqsZBbSf3dnUnNVJ9Un1FDHEipHkAvjDMR1plrbb"
+ "CCxJOehPNV7NW1IdiZyGLAPMFIwAW4HvUschWHZuKnOQ3vUqwjPTJ681MLXKfMOBz9KTUWOzOb1cg"
+ "XUcQbcETk56knJqnjnin3EomupZAOCxxn07U1eta2siepq+HgGvCkke6N+P+Bj5h/I/nV8tHK7TRZ"
+ "Vny+SueP4s+46fjTdPg+zz6TF/E5a4f8uKSZp4rxoizESMX3qPlA64rnlqNrQt210HTMjrCfujn71"
+ "WZkWKMTOo2NwCDmsWVgJd8TkhQQ2R0z3HP4Vt6fcQnT0jndSTwyk8/lUxj3HYzJZYrZXOQysAeDyR"
+ "xTLVZPMjkMZUNlGG7O1cYzn8agnQWl47mUyRjKqccBc9/ft+FaVtcRNbvGvA2cuB71TSsDKq3ToDD"
+ "bosf94gZZfqTTb4tKoO6RyFHsAQeTn6VbjVQ1wfMLyFxg568E85qtO6yRMkuEU5OB1Y9PwqLoExLS"
+ "LZGMyB3YFiR8ue4FaaBoYVhUHMb7W9wecj6E4/GsyBohOW+YAAKDuzwBzV+OR/PhcSDBfLgHO1Tzg"
+ "1MloDWhJHcCQRSYAULt2gc57/ANaqvcbJpPmZCAT8q9R71Irx4YBPkSYLFz1JGSamZ7Jk3zQjAbaz"
+ "qO/TrQl3BXaKUFxFIC6EkSFh6E5x0q1MhLxmMBzngHseuaqI8T3khhVljjBx83UirIlktYVeRA0jE"
+ "D0wMVnbXQa8xzxruXzY96k5cg45qlfMbWQiGMlXyiYXOPfnrVxZfMmwAqgZLA9Qe3tTHmt/McPvMp"
+ "OPlAU5x1zWkXYLkc8slvKY1ACqm922glvqe3ep7e4+cSopILiMjGMZ71Et3FvcHZGrLw7DJbtRb7p"
+ "SzuSDuG/B4LcjNKUnshNmubzBYSEYLcEelHnxFSWl2GTgYHPsBVVIIlU4DEdTk1HNDP8Aao5YwDFE"
+ "pVV6/wCe1VCfcSsXrnMkal4pAGO3hsH06Vz6qumXFwoiLRltygE8qRjkduTWrNM/kxSzM0ZD7iCMg"
+ "/WoGt4rmXc0+GIypwcHjj8KqUl0C9mVgfmHlsPlUK4ODn3PoalvLUG6jMYXcFKbj05WoYraWGfy5A"
+ "pV9zNN1ViOmfzqxdahDbx7pQBKHC7gc4BHJrON27CTRBexzu/2V5FERXJ2kbzgdh71Ld6Pbz6a0Uk"
+ "7xuADH5mM560s+n3Bg83TZow5O4vIMtjHb3qg5uPMt4LuUs4H7ve2Czc9V5xW7TjqJu46GwMcESCb"
+ "IDF2ITG454HPYYp/2WX/AJ7Sf9+xVlpkciORRlHAxu545PNUv+Eig/59G/Osk+bcqLZ1umSNJYxF8"
+ "7lGw59Rx/SrVUNIkD2zkdPMNXmbGPc4rqg7xuQ9xTXPvqCoXAuSrMxCqeK3zXI3ExW9lEjtmQYjVh"
+ "xnn+eaVR2Q4uyYl3qjG3+adpAGwQrDn2P5VGJGv4pHtJkSRQrKu0ghgef0rOu7fyhJKAwXhSCMAe/"
+ "45rLW9ksroOCSAc+4rK7karbU9A0/UUvl8qWKQSNHtZXwNxxziq1pbiCQuEeO3c7VVx93rWbpfiC2"
+ "crKVAl4UkjPWtcJcOGeG4DAkbo3GV688dR+FXe6sQ4kDOEjIGchiMgYFPWKGQjBbO7Jyc7sUuoWqb"
+ "2O8rFIACB6j3qKGPdCm11zgng4OMj/69YybT1GpdyV7aOXzdy+YjMSoK52Ent7U3ptT7Q4CDBUAA5"
+ "qrDdSvcFWBjRGznPJqeOGS8ndhGzbcn723nt9aqMr6CTRM8ivuYIuO2Bnmm3FwVi8pXUOeu44z7Cm"
+ "pcwCQ+bGyiEhcOcEtj09Kz9S1WER5WPdKOGweBTs9iiK7v2tSzEFZAMADuKpJa3GoSC5vCVhPRc80"
+ "62CR7r7UPuqfkX3x/wDqrPvdTmv5wQSsSjAUcYFUtNgXmdBb2iJEjQ5AY/xHmraQAHj+I8VU0u/Se"
+ "GKLuoxg98f/AK61BkLkEAClzNopJBHDs28k45Oe9RahMYdOuJCcEIQPqeBUu5lG1eQe9YevXf8Ao4"
+ "gBzvcZP0/yKUdWPZGGq4x7CrFpD9quo4Adu9gM+g7n8s1ADkUokaMkIfmYbQR15rd7GK3NuG7+2a8"
+ "9xED5MEZVB7Dgfn1rUF6JG+6BwMZGcGqekWZtdPxJxK53N9O1LNsbKn5WHSslZmkkWo7bzyY4oUBB"
+ "3YTAx9frT5tMd4i0uFCncyk8DH4cis+K5ntpmeJirdOOeKm/t67AKuynjuOarkRJE2lRvJG8kwMeC"
+ "rBU+U+9TRWVsrrCCSCezetRfb96YZRj3PHNH2xAC6qVPU4rCUJ9CWi79nE9yJJBhQwxnqewpjCJLd"
+ "riVCfmIVduSef8RUB1iFQqkbcjA3GpX1hWgPlOu9uOeAo9qhQmndjsZu2NZmea+CAsVLBGy2cEj6f"
+ "41rx6fFBOitdRqsnzBCCCwNRRX1vFB5caF2P3t2TUMuqBukK5ToxOSK6FC61GzWuLVb2zCFdstvID"
+ "8vQj1H4fyrJlS5g+b7O/lkHdHn3NVm1GXJLSsCewOKEvmbIMjcj14puN1qNLsXbSILI/7tthUsEK4"
+ "xx3q2YisoYp5jepPA9qzBeCMfMxywqX7Y4G5SPnGCM9axdNrVA0WJbWS6tnHllSOIyGGCM+naqz2U"
+ "ghjiuT5crnMcyjIHHc0qTEIyL/ABdwcH6e1RXVy4iKg+WojBKueWPOaTWhm0yOdPJVEmVGcAsuRnk"
+ "H+XSpre63FkUnChSBnAOeuPxzVGW4hvdzgFGCjAH4VNc4t4oMLiRwWGTgICe9ZNsV2aVveyYba3DH"
+ "CknofepRqIWSPIMrMRg54BNY0LiWBzJmH0Ytwxzz1/zzUtzOjM6iEDy4gHKnJU4BpWfQetjYmdpE8"
+ "uUZySCCelZzS43yKYn8s7Qu7GMepqWK7TySXkBMgPPbJ/h/LFQuPtLb0QCTqQvAP1pKVndi1TFe7k"
+ "SNraO2HlgZLM2Rgdh379qbM9hqcP2fzVQnIUjse/8AShrVp0mExc7TuQKNzZAycfyrCfT5H3eWki7"
+ "VLglduScYA/z2rRNSdyb66mzZ/b9NnO6RGtwSpKnJX86vTvYTvFPtU3KDIcjAXjqff0rGsjNLbGK4"
+ "jIMTq5znfnoAa7HT7YPbBriNfMYfMvUD2rpTlJWNHa1zDRLESiVnLqCW2AdTkdfpUO6P+7bfkK6O7"
+ "06OQFokUOevGAw9Kpf2SP8An1jqeTlFdGvB5ZQGLbtPPHSqt5ckahbWycuwZz7YHH61hWOoPpF4Le"
+ "4cyWsn3ZMcqferKXSy+LXwciOIKD69z/OtYyTjcdtR9r4jRN0OoI0UyHDEDIJp9832m3+QRyq2Cjk"
+ "HI/Kp9X0OHUT5qnypx/Fjg/Wq2lRT2C/ZrjAdR8rr0YUTHdGde6bMNLuGR8oASx/vdCPyrjJZNowT"
+ "ke9euo6vkdQeoNeXeK9NbTdUeMD9zJ88Z9j2/CnGCS0En0MoTbGymVrvtBvvtulJOrASRfu5hj8jX"
+ "nqbC48wlRnGetb+lXqwRmztWYrMw3H8fzqJrsOL1Ozug0sIEYXJ+8O7Vnr5sUOHdEyDyG6VDPqv2K"
+ "d8YkRMgg/nSvrdjdxI6SQxIwyUkHfuDisZRchyhfVEm9jMrO4bHADHt6j60r38tmFRm2BWLFweoIq"
+ "pNq+kJCPmJdCMeUDjjtzWHqGrJctKUlb5sgB0HA+tbRhdE2tuXNS8RCaTYrsF6M2OtPsPsl5dwRRs"
+ "ZMBpZOOoUZx+NcyY4j1lbdj+7Vvw/eCx1mCc52qcNgdjxVyVo6Am2X9bu3uJoY1VtxXcUC5/L1/+t"
+ "Wd548oqo47mtTXBBZ6hFqFnckSs4KRAYCgU/WbGKa0XVdNVfs0vM0Y/5ZN349KhbFO9yLw/Kftyc5"
+ "XIXnsCa66Zx8w9DgYrjPDQ8y7OAdq8k+npXVs8jIrFsY7bamS1Ki7k6uFKhzgMQCxPTP8A9eub1x9"
+ "+omPp5XBx696u6nfoiPANrO644/h96raopuhZ3kalmukAYD++vBqoRs9Qm9DNZgq1p6Pp+6UXVxjA"
+ "+6p9aLTRpJW+ccnqewrbMWwCNQNgGMU5O7siUrDDMUf5zwx7Cobl127wwUZ9KlmGEK4A9BWVeTFOo"
+ "yDS5SriyOZCQhP51Qm3I+4nJzURnCOwHHPpUTTeYME9DQr3G7FgXP73G4Y67vSpI7ocBy2HPzbf6V"
+ "lyHByMYParNtNKNjooJXjkVoRcfJK8gZ9+8n5SrDJH0qLzD5YLMQVPIJ/lUgjGFYttLcZHG0+9Ld2"
+ "/lRjd94nqehHtSC+g2O8kRvkLA9BUj3hGAD1HJx0NVIUcP8qkii8icHeoOD15oC5MHd9ybgCOTnji"
+ "nRTFernGcbRxVLIc5f6n3qUyK0rSYBJwMD6VLKRpo0bjqWI54NSeYI4wQM1UtGxwI8E9TnmpiWOfm"
+ "wPftU3KJ4rjDfO238auxyR3G3dHkr03GskAKvUHPerMLEEfP+dP1Jeprx2VuJPNjUszdVxnv2xTpH"
+ "t5ZgsjRg8/Kw649f0qtb3B/vAe4rb09re6g+yXMaSE5b5gDmp9lGRLirFGXTFlt8ypDFFjjPr9e1O"
+ "0zS7OeeSSKQSqGzIMZG76nrV660qO5uFiljV4UGU3E/L7cVbsLCPT0dYVIDckbsjNWqUUZ3sU59Cg"
+ "dSY5JY23buW3DP8ASsW2sbjzp2RiyBsEj5TVq812b7aoAEcSPhlBznB9a6IKrwAw7RlflOOKJUkwR"
+ "z0IL6kkcM5UIp3jr35H1o1tZYZvLhtJJo2UElRnB5qvrNvPZRLcqX8+aQiURjiuj0yY3WnxSHqVxk"
+ "jvUqirWG9Vc8+gnnWaZJdwIIO18/1+ldxpdyWso9x/eCPOPWuZOj2y6pKJJpraQu5Z3wyOM8AVcuo"
+ "rzTzFNbypPAIyU5wWx2xWi0ViltqdepBUEdKXFYtnrLC2zd2k0TgdMdRUv9v2fqaq5Li7mdqVtLNZ"
+ "vGIMsowEU9fc4rF0eR4NblSQMT2z1BGP6V3u1DztH5Vx3iiJdO1WDUINvzj51HYjjNZey0dik+h16"
+ "ShlBFR3KB1PY9j6VnWEq3SRypJtyM46g1pEOR1X86Sk2h8qTMwXBgl2N1zwe1U9fgTUrf7PceUXY/"
+ "unHymNv6j2rZkwB8zIPxqvvgBGZFJB470JyTHy3PL7vTpbeUpKhHOAwBwagikksZ1liJDL616fera"
+ "XoVZ2X5ehHBqk/hnSrpHLK+4jhkfofpVKaejJcGjG028sNSU/bMIWwXBPX6Vjy6VuYvbbmj3HaMdB"
+ "nitCw8PRxyTpdzY2v5aGNuCfX+VVZ7GSwunieTcMEDDEdelJWWzKtdaoqS6bNEiu7DazbeMmpJ9Fe"
+ "Ir/AKTDzzy2KvaOqAt5wyrNtG7n6mrkK6dITHLEoG/aGC+3WnzsXJc5eW2CEqZYyR/dbNXNNitvLe"
+ "WWXEiHIA5zWnPZ2MxYRQgtnrk81cm0DTo9JW5EjRu3OU/UYpOXNoHLY5q6ujf3TSSDpwAKvaTcXFo"
+ "/yxl4j95SMgr3B9qgBtrZyY4N754Z2z+lTJq92jAphfYKBVNaWQk9bnS22m26wmbSwPJlO4jPKe30"
+ "q3Lp1w1uR9rERPUqma5nSNXksrsBuImOSuOBmt6+8SWSRK1urSSddrDCis1e9jSytoZVxoslvayXT"
+ "SZVBkswwCfQVa0hkbSINwziVwCRyAQM1larrV3qm1ZCBGDxGvAFWbGdY0t4RkhQSee5qpXZK0OkO1"
+ "YcIcEDHFRmUsgB6iktJFkG2TBOMjmmSoQ2O1UlYGxZTvGQQSPWsXWSBCCAVNajvznb26is7U13xMW"
+ "79DmqRJgqHdiR2607yTuLHlT6daEyu7nnpVwKrJuRhnFAisturEhicg9fQVPHG0eUfBB6H0oiO84P"
+ "B9+9Wlw67T94dOaBBBErqY22tuGMkVL5IIMUgBA4U02EFQGAByeD2q1Hy2WHHqO1MCg9ltG6NsEdR"
+ "UF7h0HBB/iGK27q3ymFALkZHY1izxsjYYc+5pDMxg0fIwVPWlU8ZVckHOaklt225DD6VFCArYcZ+l"
+ "DQ0zQidXQSDKMP1qwhc4IAOeoquluyLvVSFPbNWUHyZ7VnYu5JsDEfJtXHWlaM54HT3qWBCeMZGPS"
+ "rIi3Lgr+dMRWgJzhSffNalqWAHHI6EGs8xYbJQg/WrEDhR8p5HrRsUmbdvqaW0RE74ywAY+9a6SK6"
+ "5VgR6g1xd8hurOWIMAWXg+nvVXTDc2qRbZnlDHL4zwBVc1kQ4ps1fFX2W0ntmUIpn3bgo64xz+taH"
+ "hu8862MYbcqEgHPSuR1u3lu3W4eby5YxhYWHY1Z8O3EljEcONzNjaBncaOfQIxWqNvxBI8+0WzsAf"
+ "vA9Dxwf6VT0nxE1nYrb3EeJY8Ag8ECi9uhMZVtTlhhwTwMdx+uaox2cWoXSttdmJClmNTzMIrozZF"
+ "5b3Mss0jOyNwYnQY/A9RTI5LMYaWNmQMVUK33AenHrWNdoINQuLdZmCo2AcbjRGz2tk6O2XeUSDjq"
+ "oB/xphdGz50STEZEy8qAxwfxp/mr/wA8YvyH+FctJfx+bJI0jKXZiigc9eK0Psl76n/vqjYNzd1ie"
+ "+tV/doBEoAVy3BPc/8A1qqaZaSTxxS3pEitG7tv5A56Y9KljN/p0CWwsxcRzMflmP3fxrQeIm3Nqk"
+ "b4lyhdACEFOXZElTQ9MjksluLaR4g+cxkZUHPb2rRlsZvLYmUFvRVxxU+n2/2GzWEksF5zjFTzSBY"
+ "+MEnoCcZ/GlyIOaRk3FoI5VjaRyZAdpyOw6YqC+sLU6fLKscsuEz+5lO7PsOhq1c4S4junjOYuvO4"
+ "YPWqyXKmW4ljkcwvjZkYC47UtEPU5uLTNTmw4juxnnlc7adfxapp9qZVnLIRhvlKMvvzXaJcgEbSC"
+ "cAkVDrEtvdaFdGR3WLYdxXqMVSSbC8kefW1+8gigXI2n73cknk1tXiMdjysJXx8vZjj29aytKsl8x"
+ "ZiTx94HsD3rX3xybS673PJI/hx71lJWZabZiSg20iAFigOfm5qrJcDzCISSMn+fausaGEwqJv3gzj"
+ "G0HqayprGGykkkGI0k6E8Yp3Q9RNIt2kUP1J6Zo1rU9tqumwkDyyd5HfnOM1Tl1v7MvkWZzj+PtVa"
+ "O0nvb6KJAxeYjJPp3NEY2d2JuysaGk6Ot0nnzOFiB9eWrSksIIciOIhf7w5q7bRQ2kTwIRtLDBIqK"
+ "WZEzvOcfmKqL1ItoZ0llFOu2QYA6OOtNXSYY8CSZn44wMZrTBSdQysCCOlDxhlGBkj8DV2EY+qwQ2"
+ "9uvlRKoJ/E1WsmXcu7GMj8KueJMBIFbryapWqoHDbsr60NDR0lriNiRliV7VYDsY8kZYnj0NUrWVh"
+ "IseRtK8HvmrwUGPHAHQGhCZCwJXd0H9aoX2DFsIxmtGQkdPXms68yMAjOTwfSmIwtm1yfyq5BGGGM"
+ "DB6Glnt9soC9/WpYYwASASBTAWKPJKlR7H1oMTbhhfmHP1qzHjnAye1SwxEk89OfzpAMKhoi4Xy2H"
+ "BA6H8KfbqzDbkED1p7cPzgpjB9aEQrnkDjII6GgCKWR4m8thkDo1PeBLmHBAVgODUW/z5AM5x156V"
+ "bBKoFyDjv3FMDAdHinKlRwcbfWnLCss6hYyDnp2rXu7bzT5i8P7dDUVvbOkmWB479qVgJFjQRmIrh"
+ "xVaVFVBkjjsTVvdmUuMNt5JHaqF3Lt3H5SG7UWBMmt3ZWwX2jtV5GxyGyaxYndmXC4+hrWijHl8jD"
+ "UrFkjgyKDgn0OagUGMgsCVJ5IomYqBtHXj8aiSUyAqeCRRYL2JYmK3QReuRtBrYh0CORhJLI28cnb"
+ "0zWGkm2dG3EEEDIHIrVmuXz8l7cr8ucFAMn8DUyaW4rmf4gtbdLiFUEhZcli4xn04p0W/yt3lQASn"
+ "aBGoBAxz0+tSGISSAzgvj+Jzk1KrOTMfNRjGvy7RwPwrJTTTEm+pUlhjjDxoyHomM55P8A+qkt9Vh"
+ "s5YLeyUcqTLIF+6e2M0xUJZw3f+IjtVTgOBHFGxQkA56VEZi5tSVAZGluZg3mMwGc4OTWjb20kjOI"
+ "ljldE2guM8Hr/Kq9t5jZBiDEHkdsetWnKqN+fLB6cdSOxx9atNlJEz6G0loy/ZrYMVwrKoBHHXPWs"
+ "jzJ/wC63/fVXvKhkLE3m0/e2hDxUflWv/Pyv/fo0XYjpbbTWU+ZPKZJD95jV5IgoxmolvYCmRImOg"
+ "wc04XUROA3P0roumTZk2KpXsKsczySeTwdqjgY9ana6RRnk/SqF5qOV2bAFbg55o0Gkytqdz9mtvM"
+ "hKlmQko4yGHbFctpF62pvNYGN2jlclMHBH41rXaiRFALdMEGs7SiljezxiMK6chqwlZpmnRJG3JdW"
+ "trbrHPLtUqFQZy3HGcisvVt91pEy2srMikOVHVsf0qVVgvbRJQvByec5HJzUunx2zE7UYZBUgZP1q"
+ "oaIT0ONtdSkt3I5YHA/CrMWsSRByIwd3Ymqmq2RsNSngOSEb5SRgle1R21vJcyCNCBnua0aRKbRcl"
+ "129kAXzAgH90D+dUpZpJxukkZ/qa17bw2JJdst1t9cLmtT/hGLS1h3vK8rehAApOyGm3ocpYWj3F7"
+ "GigkMwGSOK6dLF7fUZFiL7o48tLj5R6irEEI+yStEgWRTtT0BwapR3dzcXIhDkoxG49sDrUp82o7W"
+ "LU8n7rcG5J57cZqjJeEmMnjsTT7y4DzOBjaBgY9KihtmlKkEcevFO2o29DVtlV0JB5PZeMVJNOYrc"
+ "uSXb0x1qOMABRxuHfvTk+VSsjHB9atGdzE19zLNbjn7mcHsc0afC2CcZTGCKbMTdalvAJGePpWzDA"
+ "IYyGBUscYpsLgp2TxugPGOvpWixXYeQB6GqCwTZJIG0Hgj0q1KwYDbgkjOPUUgI5ZMSkAjHUVBOP3"
+ "e7OVHXHrSzxMsWc4I9aC7CJfl3ZO0+2elMCv5fmKJD2p8ceMnGcZBApEKrlcEEHp7GpASjK55JbDY"
+ "H60CAJhR3UnBz1FSAnkjnjGPWh0GDnO0jse9MilIU7hgg4P1FKw7jmdUkXByh4zT3UDAB6Dt6VGxQ"
+ "ds4OWU/zFI0qLhM844oEKsPlSb1IKng+ooeV1ICMWFQmUgbRyo56UhkUSADJ/2SeRTAtpKOnB9qgm"
+ "vvlCgYGPyqCRmMpC5zjsKSS1kjUO6nDe/SgBbNywkJ6bTyKzmdTKVb5gT3HStCAeRAzuQFcFRWS33"
+ "z1Jz1oA17WGPhhOmQPukYrTcRqoKHJPasfTUYOMgkex5rTuy6wk5I9sVJTKU7sYmIOQCCCD3pLYhy"
+ "DgnceMdqptOVYKO55q1HsXHOB7UxXHHcZ8HqGwBWg1tvfPmjnrl6zyv+kBScjgkkc1faFQwPnAHGe"
+ "lYVug0Si12xFgSy5zn0/wAahjlNxI55VW+UkL1FKICwyLhzxwMGo3gIYgs3sAaxVkGg2T/WuF+YYx"
+ "nOKje3jRQA79Ou6nG05JBbGM9KkeBUCg5Y9cZqlYVkVA4jJVQSD1JY1ZTU5oU+VYyBxyM1BNAVbhc"
+ "k+g6UqxuiZ8kt9Vqx3Jf7UlZv9VASeCdgFN/tL/phD/3zUcfmGUZgAHstS+fL/wA+4/75pXDUyLRN"
+ "URHk8shY8F89s1sxandYQPJzt5Cr0NasjwST+XkeU9tJyT1IfpVKEIsi7oFRSwBPXg1qotq472G/a"
+ "by4RdhK8DJPGT3pqwzswMkpPPT0rRvZPs1w8ccI2D7vriqy3jMhj2KFJ59afK9wuMljUMvUkj9akW"
+ "1Ej8RjPXNSoxBB8scf3u9LNKzD5dqnuUaocWgRSlWMRN5QAPTqak05pY2Obt0TtiMHFKZQij5CxJw"
+ "Cvb3q0kRm5+UL0z70k3sDOV8ZOX1VH3bj5K84Azyah0iPYynPPeq+qTG81qQKdyK2xcdwK17KBUxt"
+ "BBbqa26ak9TUhH7xSBjnNLdyO4IySB1BqRFVdxHamWk63E0m5QQnP1FJq5SdivDJjTpWPGWFUbcrF"
+ "5jAgAg1f1FN1osMLH5m3cDtWNN+7iZQeQetSlbQpsrPMQzdwwxn2rY0/ItFc4Kng1zm7zJgi101tG"
+ "yWG0dh0q0iGMlkIKoMMc8H0pLyUqiwbsvK2AfQcZqs4a2y7OSOufU+lEG2RXvWywQDbn1qiSzawL9"
+ "ulCgHYNoq9uLKw29CDVCy3qzSD/lo2eauxkbsOcE8UATMSI/0qYxoNnt0xWffTSwpGQuemfersMxZ"
+ "A45Ujt2oAjvseUcDOD+dZ0Vxuj5zuyelT3cwlnTZjHQ1mQM29gCDskOaBlrLSAZGD796WKVnMq5yO"
+ "q+o9RSopTKM25cnBqPAQsf4mHagRLPIApAzuHUe1RwS73bbngDPv61SeQlm5JK8H1q7aI2C4/LPWg"
+ "B29vNAzuJHUjqB2okceZnAOTT3jfcTH1IyRnpVeMFyWUMBnrQA8lzKyICRjtT/ACQPmIYnHHHNEat"
+ "54GxjnvVuJdgP3Q59e1ADrRGtYBI4AdjxntTZ545cowJ7gg1n3+oYQorliOAapw3/AJAMj85GMZoA"
+ "vSqJIEUsE2jPJzWYSPMIU5Hpikur8T8hBH64OaLZDIxYfMO9AG7py7YyWGQe2auXcgRAoLLGRhtp5"
+ "qrZfLACqYI5NFzPtUmVs+YegXpSKMwbHuejYHc1cVVCjLoNx4LZwPyqom0MzHcCehzU0gGQApUqOo"
+ "bNAiwsYFyhjK7TyDnIqw7yKwAmjyPaqUDCLBYkke3SpHvVDDAYcdkBrCpqxkz3MoOBKrr6AVCtwUb"
+ "IQZ9SKcupxhSpRjnvgCmx6hB5nz5VT3xnH5VlZ9gEkvJHXAIUZ6AUwXMxGMceuKfLeWyyny2Lrjgh"
+ "MUz7YJQMflimlqMYbqbI5PBz0p8eo3aDCzMPoKj8+EFt6SE+zYpDPZso/cuT7tVWAnOraimMXMg/G"
+ "l/tbUf+fl/zqoXhVs+V9Pmo+0r/AM8j+dAF+CC4njtUDANH5hb/AHd2c1pXqW7wFY2ZpGYYGMDqKR"
+ "H8phtO7arAbvUmmfaMuu9sgEEA961u0Fy3Myh3aSMSsTnJOPwpnmpjAhiTj+7Uvk3Ej58lj+OKV4n"
+ "iA8yIrn1bNKLtuJ6lZpCRgjJqAswHEaj3q3JcxDjBJ9lNR/K4+43J7jFX7SPYmz7lTfIBhFUUpZ/I"
+ "kc4+RCevHAqwY0QlgQy9MelZXiO4jt9LMUTAvMQvHYdTTjU1skHL1uc1p/N2D3FdNbFRHI4OOlc9p"
+ "JVHLHj3rXtJxJGU3DvUzlqXFGitwfIJyOR0psQVbK4Zc7tvOD0p6WazxqA2D9akuo/sdq6IMuRyTQ"
+ "noN7lGCZnZW3AFV2jPesjVpipKp0JqSWVoSFLHdwcfWm3USLCJ5j8zcgDuapITZW02FQxdzz1FdDF"
+ "JiEoXyGHAHUVzkFwAxJX5T+lWjeiEeZuHAOB60Lckl1LBulg34WMZb/aJ7fpVt5IpYjEOAME44APH"
+ "Fc/DctNM0rsS8jdP7vvWvbMiOqNyD09/f9KoRqW5zICw+6MmlUebOwGV2tjIqtHOQMZySgbP8/51b"
+ "TbDl2YZfkc+lAFiZQ0G2Trx17VWt22sVjJG3k1VmvCWf5s9xUdm+5yckL+ooAsTDzG3jgnnjpWbA/"
+ "l3Bk/vZDD1rWlG2Lb0JPHvWNAS8rgdwCM/XFAy9JKIZSOmcEccVELrzWGQFZf1pk28zqWwAQeOxxV"
+ "e0CvMHc4GT19aBFhV3xSTFDjHBHXNW7X50BVhkjJU8YqGOYnfFGvydDgdKmFwIRt4wvHHegCTy3Dl"
+ "gwCr+lSxhIhuP8XOBVP7S0jAH5hnoTTocuxOcgcikBdE5Y7gNqg4AqC9k2xZc/Mw6CpY9sfzNyc9C"
+ "OBWRql0rSfJ2GKAM25kBYgZGKrSs6qu4cdqV3O7mmzPvXGKYhI2LNggkVpwSm3P7tuSO4rKtZNr+1"
+ "a1rA1ychcAdyKBo3VdpLNCjKCeoPHNUpDM2fMPSrVvJCqLG6qdvVSOpovCvlLsUZycqBSAr+SFgXA"
+ "5J2j/AOvTJv3bqAct7fyp0fzDIPJOCuaYFO/rnJoGW45liUNu+ZucYzQt0ygsig+5UVKI5VQEQRfU"
+ "tzSJHeO/7sRrjnOa5W7saI21B8Y8pD9UxVc3bgk+SgB9quyPe9Hli/ErUXnzAndPGD7YNMCo1w2cm"
+ "GPP0pxuC0fESAj/AGakkkl6+crc9cCmB35JuET8DzQgK7zSY/1a/gtMFxIM4Q+3FTlgV5uW3+2cUq"
+ "xll5vAMdjnFVoGpXE8pI3Eg1J58v8AeNNMOckup989aPsyf3j/AN9CjQNTpGc4APAAI6evNVjGXcD"
+ "aze+2rYZQAFI/E0p89+Q4I/66YqnFPdoVx8FvMyf68IPdiKc1qVXLXq5/2cmkW23jL3KIOpA5p4jt"
+ "E5aUuOwGacYpBcgdUxjzX/DvUYEI/ickVO8lurAbD+AqOWRVz8wCnpheau6j0Yte5G0pzgA49K53x"
+ "VvzbM2QuGAz+FdGGGwsqjHrnBrC8UtutYVMbA7ydxOe1VzeQJeZzsMvlowB6+lW7W4IPXH41QjTfh"
+ "DxnvU0XycdTnGRUtJji7G1HfycKuc1pWuoz3N6kZG1F4bjrWZZRLIVYgkiuh0+3gkaOQZXy2O/jrg"
+ "VEbbGjuZN3aiS7knkOQzYQDsKzNXfasMRblRWteyFrhkX+9kD0FZHiVQHhbGDtxWpmZyuoHXiq8kp"
+ "kbAJwKiNAoJLEfUcn8KuJOyjAJI9+orPVjmrUMMkqfujuITe3PQZoA2LWbE3LBQyZAPp6Uy5u/MDE"
+ "OQvUZqnKylBszxzn/GmiCSRvL6sPegZILje2RyatR3TIMr0I9P0qq8IRY9rqxGeRxj2I9aryy7VIA"
+ "II7ZpAa6ag8hCFs4IxxU0aqJzHjrzWXpu2JhMckxnlSev+c1ZjvNsmTyOuaLjNWZB5boeoz2qmQkd"
+ "ttbDehX19ac16GTMedzkdjUNww2lVAHOSKYiKK4aF3wQM9aWWYsuecgVVcqp3MelPgmEjFsAgdqQE"
+ "9tI7MMY45yauLJtBBIz161jyTyCX5OBQZnYbRyxoA0brUSUKK2fp3rOZiVPy59acsYQhnIJHJAqGV"
+ "90h8teT+lADDFwWqJx8uM0kpkQ/eOD0pkatKevHfNAhIRh+Ohrft7kLCkaj5h3rn2BhlI647jvV+y"
+ "uAGB6UDR0DP+4Z5mAbHCkc1XTzUjXJJLnOKuyNbYXzG3yBckY6DFUp76PcmCOB+YpgJvwoBGGGeaI"
+ "uSp69/eoxKXJGBVq2Vt5I7DHapk9BokVkzho2wfU0NJGoyrOuO2Cf60OuznfL+FMBB6SMfUFQa53Y"
+ "pCCVd2d/J5HB/wAaGlcElChB9VApjMm7lQT9AKRtrH/V/qKVh3FLE5O0H+VN80Ff9WB+NNJKnCcUF"
+ "mIyR+tMBfMTuAPc80FYmHyyBSexIApMjAzGCPWm/LuyEBHvTESeQE5Mikezg/1puIv+ev8AKkwv90"
+ "fhS/J/dpAdNkIMllwfWkefPDFcegHX8arO+WIUqVPUZpUMZG3nP510RjDZszbY03SL8qpk9vm4p0c"
+ "kh+VwNx6AVGyL5hBAI/WnqjEjC7Rnkk809Y/CG+5YMEm3LYH409LYYB38n0H9agVwiAh2b8eKCu77"
+ "xP0FHPNrVhypdCRokP8Ay0DDuMZrnvE3lraqq5z5mRn6GtqeRuRDGDgdDxWL4hhlntI5PKKiM/N9D"
+ "Qld6lLTQ5Zc544q1BtIBBOc9KjjVk5B60QuyyYPc0COp0SESyhGHB4rWncx3ckYO1C2MVjaYsodHi"
+ "yWPJwO1N1LUXg1RjJhlGMEHr6/rmoitbmjehckjVrkuTjrWX4ij32KSY5U4pg1GR+cg5z+NWnhGoa"
+ "dIsknlsCcqR6DIrS5mckBxR3xR2GetGaBEiAbs+lW7eUwt5o7kqw7YNVYV3uByQSC2PQdasPGUumi"
+ "iV5FDHgDJIGaALUMzo5VURxINpDDIP8AhVpbciITgKN6FQGGNx9QfWqQVBG7xygMoBUE43fT3Ga1N"
+ "Ot7uW3bzlZ7ab5iY9pH4Dt+FIZnSkoDk7jkhs9RVQKzMGP3c4zWtd2IeBnR2JA+6eD9fcfyrOhimu"
+ "ALeEBv4iR2zxyfSgbJGnjHzIuAQR+OOtR28TzjaPvk4FXLbSJgUmbYyA4eMtzVxtLfyy0b/PnlSOM"
+ "HH8qnmQWZCUlsl8u4URyrk/NnIH4cVQuJX+Vh0I3A9jVn+zLhp3BkYRJ0ZurGq8unTsJDjaFYKBnl"
+ "icdPzp8yEZ88zyNyfyqWzn8uTDnAPepbjTnjGwffQ4f0HpipbbSWM+2ZW2k7Mr2PY/SmA9seYSuHU"
+ "DJ25o+YqGiUMG6evXH9auR6EYnjb7WOnzAdq07a2trYP5XzFup2571DkirE2n+EnmIF1MFAJLBDnI"
+ "xx9OapjS4La7nh3byrAZPoRWzBqAjjZNxy4wB+FaZW2mtriWaJELAFG7tgcUuYq3U4PW9MKwiaIZ8"
+ "sfMPb1rIs4/NfYWIB46V1sqSuxIBZT2GTxXJyq1rfOhyu1+4qou+hD0ZeuNHlW2MqndtXdjGOKq6W"
+ "0SymSYkIgz93P4Gumsb0lNhJ2NxwcqR6Vyl1G1peTQHgKxGPUZqkD7mpc3bM0jkFHY5A/wBk9qpF2"
+ "D7gMj09KIpWlZS33QMZJ7VaWAFwDj3x0oAi+1PlSoxgelbGm5mgZ2Ut82OuMVjMn748nGeK3LCHFs"
+ "vz8EknA71E9rFLYsfJnARj/utmnMkZGPIkZvc0gVhwpx77aBCx5Mh/I1lYBpsnxuKKg92qJ44xxkH"
+ "6ZpzooJyxJ+lR7GPTkUwE8tT2o8pT2NAUjsRSM2MZ7nApABRcY3EfhQEQ8bv0oBx1GKXPvQALGnXf"
+ "j/gNP8uL/np/47TM+1JuPpQBpSxtGMhkHrmiJJZhiO5iBPbft/pTXnVxjbIv0IFRrJFEcorE9ctLX"
+ "T9Xn2M/ax7l+PTp4yXdlc+okBqdYNmGlliUf3S+4msuS+lkwAqYHp1pouJx91wM1Sw0+5PtYmpNI7"
+ "fKgbaO6xgCo8vjJOPq1ZzvLIMSOx+hNIyg4/eEH3NH1drW4e1vsi9JMoTqpPsah37xySQRyuBjH51"
+ "UKqT05HdX604rnozj6gGqdJ20Yc6uVmsbQMQsb5P+0OBUS6TAXymR9TV9JADt3qe+MUySUB8/KB7k"
+ "rUeyfcfOuxLAZbewe3hIVn6y5GcdhXOarAyT4+Yqx45z9R+ea2XKynhifo+cVWu7UzQuiv8AMvzLm"
+ "hU2uoc6ZStULNlk6qStbUMhjiICcOOSQOc8Vn6SWkhcsBgEDJ7cVclDJ06fWpcJbj5kclMhjldD1V"
+ "iKjxitHWYGiu/MIwJRkfXvVFevPSmG4sTlDx3p0suWDIxVu+D0oEQb15qWXT5Y4Gl25VeCaAIhNK2"
+ "RuzuPPFdTpMM/2XNhIyjALwt1jfvj2IrlIlYyqE+9kbfrXXJeZubUyYjYptfbxtJ4yPoR0pMaE1YS"
+ "LAZSoD/dLA9DjvjpS2EUVlCo8tWcryxPXIFUtSuWIxuyXyTn0PrV3zPkEYjRiABwtHLfoNuxa81Cx"
+ "+Xvzg0jTJg/KcZzyarEchhCaZKMD5l4Pt0qHCIKTLgaFuWLUgWAkHJJBzk1Ujx0U5HrThhQfmH0pq"
+ "kwckWBawsDjaQTkk4p4i4G0Zx0waoMWY5UHH1o2zYwAfqD0pOD7hzF/wAkg8qx+tIWEZwFx9ap7p1"
+ "PDNj3NH2mRRjGT3OKThId0XVODkMw9cLip5r4yEB3OFGAA2KyjNM3Rc59jR5k69QTScWFzTFwpGN5"
+ "HFcz4lgxdpcp0lGDx3Faiytn+P6DFVtVQ3FoVO7cCCowOtEVYT1KOjeaCXVhtBwVp/iK1KmC7AP71"
+ "drE/wB4f/WqLT45oi26PPp9c1v6wi3eiSIwIeIb1/D/ACa02Y+hy9mGlcRp1PP610Z0+SCPzHKlGH"
+ "GOa53SXCXqEsAP9rpXbvEsljvbeMDJAPP/AOqmxI5wW5bcQM1rpH5UMUYBJC5bIzyasaNY+ddABMo"
+ "RzmjUoAt9OuCuHwPpWRpLRWIGLbR0UfWmeZnhSWPtTkjY9XHFOVSowXX8VNF0QM2EDJYj8RSGVlXA"
+ "diKbIATgOhqMgKcZqWA7zWB+8351DcqZkG3O9DuU56mn8ehpQyj+DJ+tCYxI5PNQP8oJHI9KduJP/"
+ "wBaq+7y5yCAI5DkY7GrAManlWP40MAJPekz7UNIgP3cA8daNw9BSAmNknck/U0xorWIfOwz6ZzSm1"
+ "Y5EsjZ9PSmpaQo2SuT65zXqc3eRy8ttkTlrXjbnGP7v/16a91GowsEhx3CinCFNvCihhkDNZvkvq2"
+ "UubsRfbDnAtpCO/OP5U8XcI+9asT74NIIcvljvHqOKkVAFAAB45JINDUHoC5houyzY8pUPpjrRJdM"
+ "xysaH2xSMiueDgg9qYE2jaEdgPaqSguhPvPqKuoSqCDboAfRaQ3oZQHgT8FxTShY/Llf97ilEYwMk"
+ "Z9jUXpdivf7ii6QdYVP1oSW1LbpIAO/WlKRgfe49etRSSwjjDH/AIDiqUab2Qm5LqJG1rDJMyr8rt"
+ "leenAzUou7YL82c+wzUKtG3bGfpSuoA5IH4Ueyj5hzyK+rrBe2LGNwWj+ZeME+ornIhlhmunYRZG7"
+ "JHoFrCuolt79lUfu2ORx2NRUhGK0KjJvctx2w2iQjAx3HWteaL/ilrgMc4QN06HcBVI3DGBBjIUcH"
+ "HWtVx52hXwUEK0XAPtz/AErDqbdDkrARteIko3KeOa0jOHuC2B97j1ArIgJEmcn8KvCVhl2OTjAzV"
+ "MlD7uTzJm6kDjNbnysAV344rnASfrXWogjRQoxwP5U436MUinJB3JbH0NJ5RCHbEx/HFXH3sOWoVf"
+ "lI70+W7vcVyglu5XmIjn1zinCDaD+7P4ir44AyKdmm3LuFkZ44GMD9abvk6Bf1xWgEVzjIppjU9qX"
+ "Mw5UUg0qjjr9aa7XB78HrV4IgHegp7/mKXN5BYziZcYDNn2pdxUZJ59xV5sA8j9KBtxT5vILFNJ+/"
+ "A/Cqmo3vygDacH0rSZ1XOVGPpVK8Eco+UZOfpUSl0GkUIb9ifuitNLkywkMhwy4qtBbqD8wHWtING"
+ "kfTpWbaNEchH+7uOoG1uprudInEy+TuGCOi5Nc2LYNIT5YOT3Fbmj23kyh/uFe4PNVcSRu6Y8cRJX"
+ "r1Ax1+tZmpszX8zEgEnJ28gGpdMB8wcnj3qHUGJvHbMR3H+Ht9aldipdyrvYdwaDOQff3FPMmBwo/"
+ "CoGDN8wBpOK6E3JPOd/4FOP8AZFG98fcT8RimAHHzBvwpuG/u1NkMeWOPuLTcbj93j2pOR1I+lByV"
+ "5IxRoAyaNHQq272471FE4YYbIdeGFTL8vOahut6p5sWNyjB75FACbg0nygtt6+maXzD/AHTUsMaiM"
+ "BW46896f5af3qQF3BI5YHPXNJuVe4z6A0R2+2IM0uD2VnBNKbeVUyFHr1ya7koPcxvJbDS0W4ELz3"
+ "ySab5mSSXA9sUwK+ed2e9ISVz97jsorVcvQzvIkeQ7dqlsdyFpvODyfpmoikknI81F/CnGGQN/rW2"
+ "jtmlyodx4yOvFKF2nocHvzTCJf9nHqTzSZdSBwf8AgRpKLHdCtGxyQuRnucVIOF4VR9DmmAuOCv5t"
+ "TtvfgfQ0crFdDGVmOdxGKQDHBJI61MAAQeR9aRhHnqSal3KIwFyGCqB704lV54P4UrBABhtv60jSx"
+ "KMu3H0oATCn74A+tZOvxJ5EUqqAyNt49P8AIrVa4hzyCfSs+/kjukCIBt3ZOetZylbdFJFXT5TcqE"
+ "DY2jcRnGcV06yxTaVcRJKNywsCMf7Nc9FDBDsKKCR3q9dXoFncuPlLIS3HU4xWV1ctHMW65ORV0Qh"
+ "yM9uTS6XbebFJITgpgD0PFSH5Vd2ODjCgirEQwqDLg8g/zrp1YqMEmubszm5TP94E10uR94Z5pxt1"
+ "BiZJ5GafnHftSck89KTcPr6VWiJFJ3dzS7cDOSaQFj1wBQ0qgZ3fpRcdgBIyQv0pM5HUk01pVcgZ6"
+ "U0uqkAECs3Idh+dvXrTHJHpio5J1U8sCffpSi4B4yBx2qOYdhwb1p+RjtmoTMCcb1z/AL1KuSCxK/"
+ "nR7RofKQSyLnBYDtVOdxvwpB9xVibodzJ+YFUZcAggqfpUc1x2J0lKAZWpZLhcADqfbFUVkw1Skhx"
+ "y35mgCyjYI9PrVxXCQ/e5NZaLGCMkZ+tWiAI/vYU+9MLFqCZlk/dyOp9mpWLK2CxJ65IqgshjbcAp"
+ "H0qRZvNbJO0+lSO1yyZMjAA/lTS7AEENj/eqNgir8zfypUZSM8n2AqkxCsxYYNG3jA3A08tGgBOR+"
+ "NOEyEZyv507CuQbSPX86TIH8JNPZk6BRn65pmcZyMVGwbi717hhR5nGMGmNJkcDmmhnbgAE/Si4DY"
+ "H2M0J/hOV9xUu7/ZNVpy/DKuHXpjv7U37b7SU7Jhc6ERnHKs35Uu0g8qR+AqTClcqWH0NCGQtjaXP"
+ "YFgK6/aX+JGPJpoyMZUkgkA+oprDadw6/SrZjYL0wT2zmon4IAKZ9DVc8Rcsit83+yR9aC248EZ+l"
+ "WAMsQVAI9DSmNV7En0ovFj1RWwDzx+VCqM8jB9cYqcpg9vp1xUbEDnBb6D/GncVhhQE/40bVC/MT+"
+ "HFPGWXO059yBQqiTdh8BVJOT/KpuOxHsTdkA/nTdmRjFTyQMiKxYfONwwc8VGFz0qvRiI/LOeTSSR"
+ "DdnGfaptgx701kB6E5+lJsaKUwAU8BfaqDxqDx39603t1PLt+JqjLGivhWzj2xXNOTb1NEhmxFTjv"
+ "71I0Ams5EDc7c4pRswAan8tFiJV+1TcZR0+zJQxCVkQ/McDqaszbXjEbKML32gE0+zXkvnA9Kc+GY"
+ "ninzMCtboizrtHeto4A6VlbBuytWlDuv3v1pKTuBZMhxgCmuQRk5B6VXMTjrLg/WomXJwZBx681Tk"
+ "Is748cyDj3qJmJH30x9ahxEPvOP50L5LuFV3JPYKM1LkMkdQVARxnvk0N5wUYRGqvOkcbkZlLehGK"
+ "asJxnbKvGc5FRdjJHjmb+ELSBBja6E++MUuREAd8nPuDSq8znKNn64pXbARfIHWNgKd5ltztgc+vN"
+ "O825UcLG2emGFOAunjIERDlsYpWKuQ77UHLW+D6E9Kry7ZXLBAFHvT7uC5hlMdxES4GcEZqNJTHG6"
+ "tBH8/AJXBWmkK41EwM7ePU8A05sugwOM5x3qLzGwFAZlB4XtTjJIRgxlV+lWh3JhCrKSFJcc49RUg"
+ "UsvYr7tiq8bY5jdgR3HWpOccDdnrmgCeIBjsMIZjwCrf/WqZ7dUBK8gdeRn8iKpxsw+9tI9CKd5rH"
+ "hdgJ7YqbXAk2RlsbZCT6YqRoY0i4Rt+epPIqKNpB1wfo1P3K5/iHt5nH8qaTQhpRjyqMR6kU6MyRE"
+ "OpjQ+4B/SnCRo+Imjz780wfaHb+LPsKT5luA13Zzywz1yFxSAkdCKvtbsbf5rZg//AD0aXH6GqZHR"
+ "TjPrUu7HsQ8s2M7c96VkwxUMDzgGrXkEtxt/xpDBg/MqH65qlTkTzIq/KuQxOfambIf7p/OrciIoy"
+ "wUfTNRZT1/ShxaFdM113qBuLE1MmHJABO3rmnTFI0LurqoGScVXtpE2bt+1pDvIIPGf/rYrq0XUjV"
+ "9C2VyOE2moXV0+aRUZf1qQM/8AC4P40F5O6mqeothwZXX5emOMU11dsNuwoHOBk1GT7SD6OaA2P4m"
+ "x74NQ7oZCZohISR8w6E07zWP3dpA5yDUhWFyNwzj2pjwQE5jIUj8RUcs+47xIxvYMzMv32AUjGAMV"
+ "XhkkN1NvlXyxgAds4qZ9tvaO7Nk5bbjuScCotPhYxeaxzuOQp9emapOQNIso2T9//voUblA+Zl4py"
+ "xjPzgc/jTSpU5QL/wB81fPJdCbIYSu7kgg9BScbsYXHpupWT5sug+uT/jQzRHH3eOe3+FQ6r7DUSn"
+ "clBK2XGT2Wq5A7irUpiYnBXn1XP9KpvF8+VbI9uKwlK5ew7jtS/KRyaUqMjacge1Skr5LKFwxHpSu"
+ "BDGCoBwcHpipFBbOAcio4oscuDntU8aPgnYv5U7jIwCpB28euKnUoePMQfUUxw7MAcbe+BR5UIP3p"
+ "PypNgSkQ9DKh+gNMaGJgD5yc+g6VH5SscB+PcYqQWvBHmx/iaVwGLFBG24ShsjoVzTUjtV5Z5Mjn5"
+ "VFPMH+2hHtmmNEw+6OapCIHG7LBnI9GxmlByACXwO1SFJDk0qxv1pMBgjjPVX/MU5BGP+Wefxpxjb"
+ "+8P5U5IyTglf8AvqkGohaELnyRn6D+tO89Nm0CdQeyACpktsqRuUmmvBIhyYg//AqNA1M25CmQlWk"
+ "H+8cmq3Poc/WtCWJy2WTA+tIpVRxESfpVICmit64NTY8oYcbiecqc4qwxZ+BGwHsKBBIf4KaQXI1w"
+ "eFUn6jFDI+MdKmFtJ3FP+zsO/wCtOz7BcpBGPJ61PGoHLK2fUYqyts/t+dOa2z/Ex/CjlbC5Ar+Xj"
+ "YCB74p8KRseVTrzk1MLRQSSSR9KNqR/d2j60eyfUOYWIRqWzsX0KjOaa0jgkhW+o4pCyn+NabvQdW"
+ "/KqUYrqS2xhkJOTGxPqaDM/ZMfUVIJ0HqfwppZW6Rke5OKJPTRgis0shPOR9BigkkDLk1OYyRn5f8"
+ "Avqos49c/WsbsojKE+9Gw+n6VJkk9TT/Kl/55t+tAzRu/nVYjtG9uflPQcmpk8tm6x+ud2MU4FTLk"
+ "k5UY6/59KSMqzSEt/FgZ+ldHsF3I9p5EqHGOpHsVNTOYWQqkTq3qRUCpCW52nP8As0CODts/KqVLz"
+ "BzXYQsoOGYfrSswxxgD88UnkwZzwD7E1IQjIF3naO2avll5E3RTuV82MqsyDPUginhEj3KoUqDwAw"
+ "6U9raE7cHPI79qdIkIXauzJ6ZUZFK0gujNlIkuVL8RRISBnqf8mrkKARIAD07U14rdVH3CrMEHH8I"
+ "6n9DT0VdoOVUnnAB4/WoXMim0KRjoD/Klxx0P51G0iIcGUfm3+NRtPERj52/4Ef603O24rDpY0fnz"
+ "APqwNVXiYHAw3uKkLoFx5fB9cGodkec4Yf8AAqwnJMpKw1gR95GH4U0sg705kQ9N34tUZhbPGKzKF"
+ "3J60oZOwppideNpx37090UQnIkL4+UYAFFhElvOInLAAnaQMjOKmkmmmTDSfJ6AYzWaqSZ5XH0qdG"
+ "cdVXPbNCSHcewUdTmk+isfwqOUOzfdQf7tS7lYDcZ8/Xim12AM46K2fpikd9oGVI+pppSNuNkhz6m"
+ "jZEgIKvz7iiwA04Hc0z7SD03UuIB/C/5ikxGfuqfzpiEM57Zo3se9LtXH3D/31SbR2XH1aiwDghP3"
+ "n/ClCDsB+VNwQP4f1pcnHABFAxwTHp+FPwgGf61EWYDIHPpimou4Eupz7U0ImLIo9PwpBMg70woq9"
+ "MFvQ0zapJ3bRVc1h2LH2hccMKat3GM5YsfZaqsmDwNw68UCQDHymlzMdi19rB6I38qcbkgcAfnUAL"
+ "Yzj8xSskezJcbvTbT5mTYl+0E8kqP1pBcP2zj6VWBUnjj61J5u37oH5UuZjsiRpWZfvPn0podQeUZ"
+ "z70qzv12rzTvObgBRn2zRePcBplbosYX8DUbNIepOPpUyyynICEmkMk38UZx9DRaL6i1GIMj5pdv4"
+ "VKsQAyJM1G1y5XDIPwWoWlYnoQPpQnFdAs2XPLGMHr64FL5K92I/KqYduu+nBxjDfN+NP2kewcpa2"
+ "Kv/AC0b/vql3L/z1f8A77NUeDwTSbfY1PtfIfKdEuCD8qgk0RqoUgoOpPBqRonPKT4X1Kg1CVnVd3"
+ "mxkAZJxiuz5GRbtVRXd9vKox6/h/Wq5ReAM0R+d5LN8p3ED8KT95/Egx/un+lSrJ3dx62AxjHQ/nR"
+ "5Y9/zpN3IGF/Mj+lMWQEFyF2nhR5g6etHNEVpDyijLZbCjkD3/wAmqFvgy3UuxwGfaD69hipJrkK7"
+ "4UkKoPDA88//AFqLZcCKMg7sl2wODzn/ABqZTXRlpPqTG3RphEAVSNck/j/9Y0445/dsfypkcgdn+"
+ "/8AO3GV6gcf40suxh/y1U+oBxSUutwaGNFGTzC4/GofLTnG8flQ0ZXkOzD3VhURHqKiUgSBwVOACa"
+ "jPmAY2fpT+Owpp2gdRWLsMj3SD+E/iKPNcHoKcPLPVhS7bfvilYYnmyd8CnAux6ZprRxq2Dx9eDTS"
+ "qnng49aLIQ9ZgT95fxpwl9x+VRBU/uD8qcCVP3aYDzMB1A/KnCTK5Cj8xUR+Y/Nmhoo+yD8aYEnme"
+ "oUfiKa0gB4CU1Yo/7qg/WkcbGwopgBk/2U/Ok80jtHSDdkZ6fyqeaCBIfMS5SRv7mw5p3DlK5uNx+"
+ "6v4Cjz8jAUflSNjkgAfpSEqMYI/OncVhSWI5GfrSDcCADigOueWH509SPUGpsOwoIJyz8/SnfPzg8"
+ "euKQH2z+FBfAxh8+y0WHYgZHzkuP8AvmmAPv5b/wAdq5IYEgDrLI0v9zyiMfjVc3KE8kn3xRYLEwu"
+ "JVwUVBgdMUyS482TdJFHnPYY4qJpUzkNx7cUxmTJI3tx1pWHcnihD7irkZPT0pWiC8Zz7moYZQCCM"
+ "D3qwZYmHzZb6CmmxaDRHD3bn6VMiwqeGH51Xd1JwufoRSpG7fcRie/y1aqW6CsWGKkf60j6UwuoHE"
+ "z/gaDbXAXm3fHrtqu8Mikkpg+mKTnfogsTeeuP9fL/30angmsyv75bh29RJVAxMyBgmPxo2svAcfn"
+ "U840W2lt85UuM9iab5sHq1V8zHqc4pQ7Y5x+VHtGFh8jIQMbse4pgwASAcU8+aU65UelQqgJ5HFQ3"
+ "cY8SLnnn8aXzx/d/WkCKGzn8xTsR/31/KlcDoWkAkdCcdOnPaoFMcrBS42KP++j/hU8kMYZ9i53Dq"
+ "TznFRtaqoz5jJxjIPSuu9XczaiWGQbE29xmm+WfemXUZMyqjkhEVTgccDnmiO2kkULFKFfsCeG/H1"
+ "pqpLawuRdxJkkKbEyGbj8O9KVMa8A4AwBioCt1G7BiuemGJFOiedX3yKpVD6kjPcn2FN1Gvshy+ZR"
+ "Zd2ojzVG9B93uTnpUocptLRKGfcFXr0+UfqaapuY1a4VDvlO7f356UwNKHgO07ohwPb3/H+VRzLqi"
+ "2n0LXkyQqFSFSAAM881E7ypwYgPzppvbrPp+FBvbg9T+lJuPZk6iGeQ8dB+NKpkY4DY+qio2nY8tE"
+ "h/DB/So95z2FYyLRZ8yVeRsOPaka6kI5WI/Vag8xugGSfQUwzYB+U/U1IEju8gwUh5/2altrAQp9p"
+ "n5/55Rn+I+p9hUumxx7WvLzi3j6D++3oKhvNUkupy7AKMYVR0UelAyGZZZGYybCxOScc0wIduCFIp"
+ "PPOeacJh3NO4hggb1J9qcNycHNP80f36B8x4INAhjLv65qVY8IPkU++KQjb97iniaPbjd+dAxAoP8"
+ "AyzX/AL5phXnhfyp6yRg8N+lOYKxwpNAEexmIxGePeneVKwx5YpDH3yaQZB5Y/nVK3UWo77KxHIUC"
+ "mRW4ZSPlypKkY9KUShf42/Oo0m2ztiQ4YA/j/nFaJx7E2ZaWFk+6UH/AadskxgyfpUH2n/ppn61J9"
+ "obH3l/Kq5qfYPeHqHXpIfyFDByTl2Oaj+0H+8tL9ox3T8qanT7CtIQwKw5GfqBURsoe+76ZqQ3Qx9"
+ "5B+FM+0n/nso+i0+eHYVpCfYof7p/Og2qDpkfjS+fjnzs1GbiQtw9L2kOw7S7j1tY+m2nG2APy8Uq"
+ "O5Gd/6U7zWA5Zv0pc8H0HaRE1qxOetMCKDhiVNTPKW43M1MI3dV49azk1f3UNX6jgqngSMfbNBtg3"
+ "dvzqFkI5XpRvK/xt+VP2i6xFZ9yQ2WB8pP0NQSxxwRF5AFUdak86XoGJFQXDPLGyONwPGDWcnGWyG"
+ "r9RYWilXMTEjp05qcRx45Jz71i2czwzeXhm5xgd61V3McGRVODgE4qZRaZVxxiUk4bntSMm1ep/Ck"
+ "VnBBDcippp7i4UCR9wHQYA/lU2HdFbGBzSfJ70/Bzik2H1FCEdLsRG3MrFc4BMhyfenrGsrAoAidx"
+ "94n/CorfzdoRjuZSFA4AIzjPHenSKyTt5rOY1zg5J+lQq0r6mvISZJkYPjqcFe1GTkCNW3noetQks"
+ "PllDzOPmU425/HqajnnkjucHdEgxgRr19ec11RxNlsZSo31LV1Kkdvm6XLjARgMsSeAD61W1NGgtv"
+ "s0aEMylfr61WyWkZ2n3KrZjVxjcR0Ofr/KmzXE6SsksoYoQmxhg5PJI/IVaxGpPsx10FjNvGqMZGY"
+ "N8nouM061dd00hLfNIVHHQD/6+aqPM5uZJUb5UGwt6cZx+Of0p1vdyxW0a71Axk5HOep/nWnt49ie"
+ "R2LNx9pLZgaPb7gf1qq0t8vUcf7KinNfy9FZGP+70pn2iZuhX8qidWMgjGS3I1Ys5ExYfU07EROBz"
+ "+Oaa0MsrfdBP1qT7BOgBC8n0Irn6mgjDH3M/jTo7VWhM04Kxr0x1c+gqaC2dFMl0jCMfdUclz7e3v"
+ "TJ5ZpWJeFwMYCqvCimMrXE73DKCQEUYRB0Uf571GkO7oKYvzsewHc9qe86hdkR49fWpAc8UaDHJf9"
+ "KQKvcCog2e9SqQVxmiwhQUOQACR14pwJHQY+lRwKYwSxBZjk+lShc9z9RVCDAccv8AnmnrZhh96o8"
+ "up64p63RUYIzilcZJ9mRBuy1IRzkZpv2rzP4aQTZbG3FMBzZxg1G2R83UUhmBO3nNPUHnCOfwzQA3"
+ "CkcgGkKR5B2jigHafuMB6FTTtykEYP5UAJ5ceB8opSdv3SQTxwaFlj25P8qaXRpVOThRkfWgQ9o1Z"
+ "sPk470fZo++aDIvc0olQdW/SgYhtY8cLmmeTGMgpj8al+1RD+KmfaI8k7gaYXE8qLoUNNeOMnjP40"
+ "G5APytkfSkEjMfWkA5VweDUoPrz+FRrzyTj8KmXbjqTS1AZhM424pMcfdNOZ17LmkDn6CnZgNYjON"
+ "ppm1R2qUkmopGIxSaAcsa7c5pNgHQ1EWOKillMSbu/apswM+cG2vVDuGzlt3TGac8peSJx8+3aSeh"
+ "5NJcqPnkkViSgVeO9IS7CFVQ/dG4jpxyP1rYRqRyJJnGdwPIJGRVC4acahH5ZOD1FNVvNVpVG35sE"
+ "k9wKTTop7q4yhDEBmG84zjsD+NJR6gajkhchh16H0pMe4qFJFdNjZViOjdahxJ6tWVhnVPBJFApj3"
+ "7VYEKRgq2Rkf1pWTdC6hy4kOR6r/8AWqSG6LRqyOTZudpUAlkPsT/nGarXrSLMYxhiDsA7n04HbHN"
+ "Yx1VzXmJ47poyYZ0Dpt2q7dR7H1xUEi4Yrbu4XITA6Hjnj25NMt7u2ikRLosJD8mQcoH9cduKkSJN"
+ "jtFMJGLlU+fOB3PrzV05KL2Fq1oJcxKsKNLKoRF2qMHDdj+NQFI5JYVlwYgrSlu/Pb8sUt9cZ0ufd"
+ "gKMEc4I/wA4qJHG6SJG3BmWJSf4l6n+dd0Yx6GTbC5skt7dVKtmZgCM925z/Oq0oijslkViGJwob+"
+ "LAHNX9QuhKlpA6hmaXg9CAAcj+VVpbR7tLRTjaQoI7qO9aWXVEXbsUI5GQhBFuY8896dLK8exCiq7"
+ "84B6D3qtdEC5aSM4Qn5VznA7CnxgZCqC0j9v6VyOKRp1J7mUCUIithQAW9T61Zt7byk8+5J5GY4wc"
+ "Fj6n0FTb4IvK3Rq1yqBCrdEI4yfX6VBPM8r5YByTySaWg2JJLNIxkZjn2OAB7Un78IWeSZQe27k/S"
+ "pSnlDe2MnkRjr9TUbsSC5OSeT7VLAqyCR+CpUelNED9sVbBbZytNAJX0+tCAriJhxg5oCOrdQPrUz"
+ "EjjNMII4JBH1qhDkZgRyuB2p4O4dTn0FQiME5DYoctEmdo47il1sBOiM7gENt9cVN9mTBOCabbuxT"
+ "+VOBbrzVBqILZf7hH40kkSKOOtSKx3d6SQFl4xmiwER9CopuBmkkZkUs2cD2p2G67T+VFmIcuR0LD"
+ "6MaXeyn774/3jTNw704OPTP40AI21iQzMwHI5qMRx47inkqHGeO1LlR1PNACIFB2qWJ9OtT7Gxgxt"
+ "/3zUI2Zzkj3p/m7eBM4+ppprqD8iKSFM8q4/CoTFF/t01r1jKYpGO7tz1qzDLEFwyjd/eNGlwuV/J"
+ "i9WqRBt47VIZQWHC8/QUjN3HSlp3C49XAGAdtOMiDAyCT7VA+OvGMetMQEsTnoKTY7lh2Uc5A/CmG"
+ "RS33qYQMfeJpu3jrzSbESMwxwxzUeCeTk0mKT5jU3YD+Fxt3E+9V7rmMyYGFI6/WpXcrGxAJYDpTJ"
+ "JEe2G87NwzjGe1NAFzF9ot2jJAJ5H1pLW7cwG3kCYXkAr909Dj9Km2M/zYI9qqXMLRP5pBwxwfYcD"
+ "NNS6AA221owGWHJPvmslOECjO5TkexrajYbZCWJAUY6YqlEySXDZU7mJBx046VcWA2SVvJIfAZcbR"
+ "7fWneZH/z1f86r6gqlF+bEoOxlH51F9jHo351VgO0tUlMChZWWMHa0YIbaRkg59+lRapPG9nFcRF/"
+ "NjGyVFONnPGfp0p2kzJK/kEEK24nccFTj/OKmkhSS8jhkxs2YuWXg8/dYkds4/EGuKG+pSZnoym3V"
+ "Ad8kmG3P2bB/xrV0yU29uFlUuMfuznDJ7c9etZS2KCXBmZFJKIrLwB9elX2YpsspCVb/AKadHHYfW"
+ "nLsUWdaVJbBJEKYmdYx9c5J/SoNMtlnjjiMmyaNd3J7t2/L+dVNQaCaIw2shbym+4x5UnC59xzSXc"
+ "ctnN9pjlLSscqqd1HHI/A1vTnZag1dEl/EU1JFlLFYkLkD1yKvtFGsPnI+SIv4D36Vlm4k1C+TIGf"
+ "KC9cFst1qZY0fzjAxhkiXeSfuu3cEfStnW1TIUOhQng82+KQJuKgA88Z7k+gFI08VqGjtzukb78xH"
+ "6KOw96fLKZogVGwHh8dWb3qEQ5IC8kngY5qJz5ncSVhkEZkOFByTn61ejt/szhmUNL2GeF+vvTAPs"
+ "gEYXdKPf7v/ANephLMcZjA29M8/nULcohdBGxdpCzH1NR/vm/u49aJiAxyDnvUDT7SyjBHrVWJuTt"
+ "5vfP4GnIM4DM1VFkX1NW0A2bvOX6d6kYkm4NwOKYgL9TU6xrIMmcZ7ACobtPItmkWYbs4C45NVcLM"
+ "R/kONppN7OCDgAjHSpILV5oYZHkUGQ42nqD71LNaGBM+bG5BwQKltBZkOnylEdDyVar6S+qVTgIUH"
+ "5ACT2pLmZraIuSu0euateQi+ZVAyVI/CkFzEf4wPqKoh3njVwNyHpimmMehFV7SSJcS3dSLcGGFGB"
+ "Dv8xHoOaukk9gRWEQoORkU5JWH3ZiPxq1WfVE8jNkqp/gH5UhiQ9UWs0XMwAzN+YqVL+XpujP4Vft"
+ "o9hcsizLbRbM7SDkd6RrRD8p6npz1qBrt5Bhtn4EioVuXaIBicjgYNS5wfQaUihqWUuAI3dAM7t3A"
+ "9vrVy0hnlGZWQcA7P4h9ap6mS481lLMBhQx6c1NZQyuUnlchlGF57e/rUe7bYrUZcW0sVzuLDexG0"
+ "etWIInlQtsPDFSM9xVW/knadHlYgQyDA/wA/SrdtczIzh8Dcd/A65p+49w1IraXzriWIwlHi75qby"
+ "5M9KijuWGozmNF+cDcSDyR3q4WxhtwyR/COlJxiHMyADkj26U+NQWcccGo53VBuCghgRkHofemRjl"
+ "9rZy3FZ8vYdyK8vhaz7PK3L3arClGh81DxjIB4zWbcod8jCMEM20E9SR1q1abxbqkrnczDB9utDjo"
+ "O5ZfC4AOT3pu8lSe2cUkjL5xJc8L3+v8A9aoBI6IPl3ZB/E1HKwLClN3zNwBUTRB5CnbYSCPWq6v+"
+ "96ny8jg8danLEXGM9F/rTtZgLFJKYVPDNj1x+dOkbNq5kG04OQTkCq8MrI0iscKHIyeabdyN5DrJg"
+ "gqcGlbUCCaVrQMvBDJsz6+hqpazATBXbCZBJFWdQjZrOOQ4xtBOO/FJp6xlGLD5gOlaq3KHUvG3hk"
+ "KgAkk5BHH41H5Enq1LHLmRgvXOAT6VLv8AepuwL+o2xhniuY8ROCS/OSGXH5juPrU+nh5LlZJdyPK"
+ "2AG5xDjg/n/On2l6mrRuDF5fmQgY6jr/Tb+vtUumS77gqdzu2USRjyqjtx9axeg1sNuYv9OeZkxEs"
+ "e8BwSCnTJx1/xAqr9saeQTmIMCuNq5HyL09wa1L2TzmnRR8yFSpP91uNp9s4Nc7OyRvMQGZZGV1BO"
+ "CAVOOfam11LvoSNcxTTRvbxPuTaFV8cvuGfrW9KYmhhSHayhchT95ADjGfzzXMZzcRPASkip5hz0z"
+ "kCtywlaPTtpY8nejADPY8/nUy0s0EWyhJJFaazHJE5kC5dcjGG9D7ZrWSFBcxyeYAsgOQRgEkfMPw"
+ "qgIUuNUfcqhhEGYgYG4k9vyrVtYJJLeW2kl3ZQlWxyrDv+VdEUmrie5imP7NdNCr+bn5GVRyf/r01"
+ "t1ocxsGZsgSZ6ew9/Wte8gcr+6dYi43llXk/jWGmAzWzElGOQe6t60Si7XJur2EQnOdw3Dn1qwpLD"
+ "cHJ+oxVaNEU/MCSD61LK6o4HzKvXApWaAjkjbdkk881TuECSHaDjFXTmQs6Hao7Hmob+B4okcuDu4"
+ "xitIxbJdiqoOQArZPSpfNK7VdG565NPn3RPFnBxVaSdpWA2gBeamwyUsgPKlQfWoJjG0ZbzNoJwBU"
+ "EskjOWbb8rVLKVaFFKLyewp8oieF/4RISVGc5piXn+kbCDj1qQW42hhwx4qIqY7hmO0kKR0qWkUaE"
+ "Ug7OuT6Uy/3eQxLggDG31pump5kG88YPam38oMUiY5BABP1oSswLenOzWq5IAXgbeAamdlKnJwR71"
+ "Fbo8SxxkgqFzimXALHAwO/Sk2FhSF4/eLg+tSC3jxnzkz9KpEc80/aCBnJoVwZL5RP3QH/OgRMDlo"
+ "uvtQi4wVZh+NT7pCAGkYj61aS6k6lcxkuMAhc4xjmnxKFkZQMH0prbo1XJzu46mmuds6MR1GDzRZA"
+ "JexxTApIpG1C2T2NR6XJJJbBcDEfy59ahuZVM0kbKfmG3g+g/+vTtGYC1PLBi3UGmloK5YvokliID"
+ "hXXlefvH0qaFkliVkJIYVHds6EAsX5BXJ6GpLcIlvH8g+7yaNAuUplP22IhtvDHn2I4qUsRwTxUhS"
+ "N1tpWHPmZOB1BzxUt4YoIxiMkb1AyexNNwC5TlXdEwyeBuH1x/9aktJSlqWkBDgjCgdfSo1jlnMwW"
+ "TaM7MewNOuA9vNJEG+YQ5Df5/GotYY+NfNeV35ZQRhei//AF6S1SRZWDtlR9zPbNV7WXYHQZPzjJP"
+ "csOtW1VlDkHnkc/h/9ekxj53XyZivLN8o4pksuUKbRu7ADvTpl2qq54DqP1pkR33DMScDgVNwK0qK"
+ "iAk5U8EjrTo5wGJ3kLs2HHc1akgD7lJ49hVKJPJvGSTDDnGB3xVppoRLFgPIhbdkBsn1qG4Yum1zz"
+ "0I21aaJYrpAv8QIPvWRMzSSnec7snilHUC1fTgW6RqBhhjA9sVDYsY5Sj9xgmqjtkgDORnJpdxTjO"
+ "atRA0I5BhYwPmJ3HB9zVryR7/nWbEAsaSSZO44GOO4/wAau4f+/UyKP//Z";
+
+static const char *easter_egg_photo3 =
+"jpegphoto:: /9j/4AAQSkZJRgABAQAAAQABAAD//gBtQ1JFQVRPUjogWFYgVmVyc2lvbiAzLjEwYS"
+ "BSZXY6IDEyLzI5Lzk0IChqcC1leHRlbnNpb24gNS4zLjMgKyBQTkcgcGF0Y2ggMS4yZCkgIFF1YWx"
+ "pdHkgPSA4NywgU21vb3RoaW5nID0gMAr/2wBDAAQDAwQDAwQEAwQFBAQFBgoHBgYGBg0JCggKDw0Q"
+ "EA8NDw4RExgUERIXEg4PFRwVFxkZGxsbEBQdHx0aHxgaGxr/2wBDAQQFBQYFBgwHBwwaEQ8RGhoaG"
+ "hoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhr/wAARCAEZAXcDAS"
+ "IAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQ"
+ "AAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3"
+ "ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp"
+ "6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAw"
+ "EBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJ"
+ "BUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RV"
+ "VldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6w"
+ "sPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD7+ooooAKKKK"
+ "ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK"
+ "KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo"
+ "oAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA"
+ "ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii"
+ "igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA"
+ "CiiigAoorC8TeM/D3g2ye88VazY6RbKMl7qdU/maAN2ivlPxt+378MPDTSQ+H11HxRcLkA2kPlxZ/"
+ "33xke4BrwrxH/wAFJPFVy7r4U8H6Rp0f8LX08ly35LsH86AP0hor8mdR/b0+NF6xNtq+l6aD0FvpU"
+ "TY/7+Bqyf8Ahtz46793/CbLj+7/AGNY4/8AROaAP18or8mtO/b0+NFiwN1q2l6kB1FxpUS5/wC/YW"
+ "vRfDn/AAUk8U2zovivwdpOox/xPYzyWzfXDbx/KgD9IKK+VfBP7fnwv8TNHDr/APaPhe5fAP2yHfF"
+ "n/fQnA9yBX0d4a8ZeH/GNkl54W1iy1a2cZD206v8AyoA3KKKKACiiigAooooAKKKKACiiigAooooA"
+ "KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK5fx38RfDPw10"
+ "WTV/GmrW+l2ig7fMb55D/dRerH6V4v+0d+1v4f+CltNpOiCLXvGUifu7QP+6tc9HmI/9BHJ9utfl9"
+ "8QfiX4o+KOuzaz411WbUruQnarHEcS/wB1EHCgegoA+s/jD/wUG1nV3uNN+E1kNHs+V/tG6UPOw9V"
+ "Xov618c+JfF2u+MdQe/8AFOrXmrXbkkyXMxfH0B4H4Vi0+KJ55FjhRpJGOFVRkk0DSbdkMoru9K+F"
+ "mp3sQkvpo7EMMhSN7fiO351oSfCGcD91qkbH0aEj+tcbxmHi7OR9DT4czarBTjRdvNpP7m7nmlFdr"
+ "d/C/XLfPkCC6H+xJg/riqA+H/iEvt/s9h7l1x/OtFiaL1Ul95yTybMqcuWVCX3N/kczRXoFl8JtSm"
+ "UNe3cFrn+EAuR/IVePwgbHGrDP/Xv/APZVm8bh07cx2w4azepHmVF/Npfg2eY1t+GfGGveDb9L/wA"
+ "LaveaTdoQQ9tMUz9QOD+Nb+pfCzVrRC9nLDegfwrlW/I/41xVxbS2kzQ3MbRSqcMrDBFb061Or8Du"
+ "eXi8uxeAdsRTcfy+/Y+3vg7/AMFBtX0t7fTfi1YjVbPhf7StVCzKPVl6N+GK+9fA3xC8NfEjRY9X8"
+ "Gatb6pZuBkxN80Z9GXqp+tfhPXX/Dv4n+KfhZrsWs+CtVm066QjegOY5l/uunRhWp55+59FfOf7OX"
+ "7Wnh7422selasItB8Yxp+9smf93c46vCx6+6nke45r6MoAKKKKACiiigAooooAKKKKACiiigAoooo"
+ "AKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK+RP2tv2sofhnbT+EPAdwk/iudMX"
+ "Fwp3LYqf/Z/btXbftYftEW/wP8GfZtIkSbxfq6NHp8PXyE6NOw9B0A7n2Br8kNS1K71e/ub/AFO4k"
+ "u7y5kMk00rbmdickk0AJqGoXWq3s97qVxJdXdw5klllYszsepJNVqKKACvTvhRoscn2nVJ0DMjeVC"
+ "SOhxkn+VeY17/4KsBpfhexRxtZ4/Of6tz/ACxXm5hUcKNl1PtOEMIsTmPtJLSCv89l/n8joaK43SP"
+ "iJp+o6lPZ3QFmVcrFI7/K+D69jXX+dHt3eYm3Gc7hivnqlKdJ2krH7DhcdhsbBzoTUkh9FV4b+1uG"
+ "K29zDKw6hJAcVYrNprc64yjNXi7jZE8xGTcy7hjKnBFcP4w0o6Zpk99ba1d20qDKI82Q59AK7qqV/"
+ "pFjqhT+0LWK52fd8xc4rWjU9nNN7HnZjg/rlCUIr3raNtq3npqeX+BvGOsXGsQWN1I97BKcHcMlPf"
+ "Ndj448KQ67p0k8MYW/gUsjAcuB/Ca6Gz0yy08YsbWG3/3EAq3W9TEJ1VUpLlsebg8nnHASweNqe1v"
+ "36el9dNz5fIwcHrRXR+OdG/sbxDcxou2CY+dF6YPUfgc1zlfUQmqkVJdT8LxWHnhK86E94totadqN"
+ "3pF9b32mXEtpeW7iSGaJirIw6EEV+n37Jf7WMHxRtIPCfjmdIPFtumIZ2IVb5R3/AN/1Hevy3q3pe"
+ "qXmiaja6jpVxJaXtrIssM0bbWRgcgg1ZzH750V8/wD7Kn7Qtt8cfBflanIkPi3SUWPUoAceavRZ1H"
+ "o3f0P4V9AUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFF"
+ "FFABWF4y8Wab4G8L6p4h12YQ2GnW7TSknrgcKPcnAH1rdr4B/4KG/F9l/sz4caRPgEC91PY3/AH7Q"
+ "/qaAPjj4u/EzVPi3491XxRrcjF7qQi3izlYIR9xB7AfrmuGopVUsQFBYnoAKAEorUt/DWsXQBg0y7"
+ "cHofJIFXF8EeIG6aXP+OB/WsnVpreS+87YYDF1FeNKT9Iv/ACMnTbQ3+oWtqvWaVU/M4r6TESrCIg"
+ "MIF2ge2MV4JYWV34W17TLjWrZ7ZBMG+bH3c4J49K98R1kRXjYMjDII6EV4uZS5nFrY/TuCqKpQrqa"
+ "tO6uno7W00+bPCfFnhC90O9mkWJpbN3LJIozjPY+lJp3gjX9TgV4rdo4W5XzX2gj6V7wyq4KuAwPY"
+ "jNL06VmsyqKCVlfudMuDMHLESqc8lF9F0+fY8is/hTqe4PNew25H90kkflXpHh7SJNE09bae8lvX3"
+ "Fi8hzj2HtWrRXJWxVWurTZ9Dl+R4HLJ89CLv3bb/wCB+AUUUVynuhRRRQBwfxR0f7Zo8d9GuZbRvm"
+ "x/cPX+leN19MX1ol9Zz20wykqFSPqK+cNQs30++uLWUYeGQqfwr6HLavNBwfQ/H+NMD7LFQxUVpNW"
+ "fqv8AgfkVqKKK9c/PTvPg58UNU+EHxA0rxRort/o77LqHOFngb78Z+o6ehAPav2o8JeKNO8a+GtL8"
+ "QaFMJ9P1G3WeFgexHQ+4PB9xX4N1+g//AATy+L7Twan8OdYuMmIG80vef4f+WiD+f50Afe9FFFABR"
+ "RRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFTVdRg0jTLzULxx"
+ "Hb2sLzSMTgBVGT/Kvw8+Kfje4+I3xC8Q+Jrx2c6hePJGCfuxg4QfgoFfqj+2Z40bwZ8AfEjwSeXda"
+ "oE06HBwT5pw2P+ABj+Ffj9QBoaJpE+ualDZWo+eQ8seigdSa900Dwpp3h6BVtYVefHzzOMsT/AEry"
+ "74Y3kNp4lCTkKZ4WjQn+9kH+le214GY1Z8/J0P1vg3AYV4Z4ppOd2vT09e4UUUV4x+jnjvxXZzrts"
+ "GzsFuNv5nNUPDXxAv8AQY0tpl+2Wa8KjHDIPY/0r0zxh4Si8T2qbXEN3Dny3I4PsfavFdY0K/0K4M"
+ "OowNGc/K/VW+hr6LCyo4iiqUt10PxzPaOY5TmU8dRbUZP4lt6P/gnsuk/EDRdU2q0/2WU/wTcfr0r"
+ "p45Y5lDwusinoVORXzFV+w1vUNMYNY3csOOwbj8qiplkXrTdvU68HxtVhaOKp83mtH9235H0jRXju"
+ "m/FTUrbauoQxXajqR8rV3nh/xxpniB1hic290ekUnf6HvXmVcHWpK7Wh9tgeIstzCShTnaT6PR/5f"
+ "idNRRRXGfRBRRRQAV4f8S7VbfxPKyDAljVz9cV7hXj3ju0k1vxtFYWhHmsiICegOMnNell75azb2s"
+ "z4rjCn7XL4xSvJzSXq7nAUVu614Q1bQsteWxaEf8tY/mX8fT8awq+jjOM1eLuj8Zr4ethpunWi4vs"
+ "1YK7X4SeObj4cfEbw94ltXKfYbxGmwfvRE4cH8Ca4qirMD99NNv4dU0+1vrRg8FzEssbA9VYZH86t"
+ "V4T+x94zbxr8BfDM88nmXWno1hMScnMZ2jP1GDXu1ABRRRQAUUUUAFFFFABRRRQAUUVwHjn42+A/h"
+ "pren6N478QwaHe6jCZrb7RHJ5boG2kmQKVXn+8RQB39FY/h3xXoPi6yN74V1rTtbtAQDNYXaToCex"
+ "Kk4NbFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAHwl/wAFKfELQ6B4F0BH+W6u7m9kXP8AzzRUX/0"
+ "a35V+d1faf/BSS/aT4m+EbAn5YNBMwHu88in/ANFiviygB0cjwyLJExR0IKsDgg17b4I8Zx6/brbX"
+ "rBNQjHPbzB6j3rxCpba5ls50ntpGjlQ5VlOCDXLicPHEQs9+h72TZxWyivzx1i/iXf8A4K6H03RXF"
+ "+DfHUGuolpfssOoAYGTgSfT39q7SvlalOVKXLJH7vgsbQx9FVqErp/h5PzCq95ZW2oQNBewpPE3VX"
+ "XIqxRUJtO6OuUYzTjJXTPM9e+FUblptBm8s9fIlOR+Df4153qeh6hpEhTULWSE+pHB+hr6QqOaCK5"
+ "jMdxGkqHqrLkV6VHMKtPSeq/E+IzHhDBYpudB+zl5ar7uny+4+Y6mtZnt7mGWNijo4YMD0INe1ar8"
+ "N9G1Dc0CNZyHvEePyrkL74UajExNhcw3C9g+VNerDHUKis3b1PhMTwtmuElzQhzpdYv9Nz1yGQTQx"
+ "yKcq6hgR7in1zXgzT9X0vTmtNbaNxGQISr7iF9DXS181UioSaTuftWErSxFCNScXFtap7phRRRUHU"
+ "Fcvo3hZrbXb7WNRdZbmZyIQOiL/jXUUVcZygml1OWthaWInCdRX5Hdevf5dBGVXUq4DKeoIzmuI8R"
+ "fDaw1PfNpeLG5PO1R+7Y/Tt+FdxRVU6s6TvB2M8ZgMNmFP2eIgpL8V6PofNmqaVdaNeSWl/GY5U/I"
+ "j1HtVKvXPizYRvpdpfBQJo5vLJ9VIJ/mK8jr6rDVvb0lNn4NnWXLK8bLDxd1uvRn6Mf8E2vELXHhb"
+ "xnoLvkWl9FdopPQSJtP6x19zV+bf/BNu/aLx94xsgfln0qKUj3SQj/2evsz9oX40/8ACh/AkPik6I"
+ "deWTUIrM24uvs+3ertu3bG6bMYx3610niHrFFfLnwb/bU0L4k6V4y1fxRoq+DtL8L2kN1PO9/9p80"
+ "SMyhVURqd2VAAGSSwFeVj/gojqGv+PdK0jwn4OtYdFvdRhtBPqFwzTsjyBd+1MKhwc4y31oA+96Kr"
+ "319a6ZZXF7qVxFaWdtG0s88zhEjRRkszHgAAZzXxV8Tv+Ciug6HqM+n/AAy8PP4jETFTqN7MbeBiO"
+ "6IAXZfc7fpQB9u0V+cmi/8ABSjxLHeofEXgjSbqzLfMtldSwyAexbeCfwFfafwb+OHhP44+Hn1bwb"
+ "dOJbchL2wuAFntXPQMoJBBwcMCQcHuCAAekUUV8m/Gz9u3wl8NdVutB8HWDeMNatWMdxJHcCK0gcc"
+ "FfMwS7A9Qox23ZyKAPrKvze/4KUf8j34I/wCwRN/6OqzpH/BSnxDHfKde8DaXPYlvmW0vJIpAPYsG"
+ "BP4CvOP2yfjB4a+Nd94F8ReDp5DENMmhurWdQs1rKJclHAJHQgggkEGgD3b/AIJp/wDItfED/r+s/"
+ "wD0XJXsn7Y/xQ8T/CP4W6f4g8CX66fqR1yC3d3gSZXiaKYlSrgjBKryMHjrXjf/AATT/wCRa+IH/X"
+ "9Z/wDouSu0/wCCiX/JCdO/7GO2/wDRM9AH1Nol3Jf6Lp11cEGae1ilcgYG5lBP6mr9eC+NP2kPDXw"
+ "s03w94et7LUPFvjO60+BrfQdHi86fBjBBkxnYD9C2OcY5rz3Uv2u/iL4Uj/tPxz8A/EGk+Hl+aW7S"
+ "6Z2hT+82YQo/4EV+tAH15RXE/C34r+F/jF4Xi8QeCL77ValvLnhkXZNbSYyY5E7H8wRyCRXak4BJ7"
+ "UALRXy7qX7Yc2u6ld2HwV+GXib4hC1kMUt8kLWtsHHUBijH/voKaybn9sbxV4HuLeT4zfBnX/CejT"
+ "SBDqUE5uEjJ9QUVT9N2fQGgD64qrqWo2uj6dd6jqc6WtlZwvPcTOcLHGgLMx9gATVPwz4m0nxloFh"
+ "r3hm+i1HSdQiE1tcRH5XU/qCDkEHkEEHkV84/tCfH7V9CsvHngyD4XeLNTsv7Kntf7dt7ZjZ7ZbbJ"
+ "k3bMbU3nPP8ACaAPfvAXxA8P/Ezw8mv+C706jpEk0kMdx5TRh2RtrYDAHGR1xzXTV+en7Lv7Q2s/D"
+ "z4QaboOnfCjxf4rghurmQajpdqzwOWkJKghDyOh5r7F+D/xPv8A4paPqF/qngzXPBUlpciBbbWITH"
+ "JMNobeoKj5ecfUUAejUUUUAfmH/wAFHkYfGvw85+6fC0AH1F1dZ/mK+Pa+3/8AgpRpjReOfBGp4+W"
+ "40ma3z7xy7v8A2rXxBQAUUUUAOR2jYMjFWU5BBwQa9M8J/EsqEs/ETZA4S57/APAv8a8xAycDrX3d"
+ "8Hf+CfkfiTwtYa58R9budPn1CBZ4rGzQbokYZXex74I4HSsK1CFeNpo9TLszxWV1faUJW7ro/VHls"
+ "M0dxEssDrJGwyrKcg1JXUfGv9lzxT8ANPfxH4J1CbxJ4ViObuGWP95bD+8QP4fcdO9eWaB4+0vWgs"
+ "cjizuj1jkOAT7Gvna+CqUdVqj9hyribBZilCb5J9ns/R/0zq6KAQRkciiuA+tCiiigAooooAKKKKA"
+ "CiiigAoopksqQRvJMwSNBlmJwAKBNpK7PPfi3ehNMsbMH55ZjIR7KMf8As1eSV0fjXXx4g1qSaIn7"
+ "NEPLh+g7/ia5yvrcJSdKiovc/n7iDGxx+ZVKsHeOy9Fp+O59kf8ABONGPxa8RMPujQmB/GaOvo7/A"
+ "IKCLu/Z/J/u63aH9JB/WvDv+Ca+mNL4r8cakR8sFhbwA+7uxP8A6AK9w/4KCkj4Acd9btM/98yV1n"
+ "z5+avgLQfEPjjXLTwR4TLSXHiC7hjMG7ajsm4hnP8AdQM7H0Az2Ffob4F/4J6eDvDb6TqWu+J9b1D"
+ "XbGeK5L2vlQ2/mIwYAIyM23Ix97J9q+Y/2B4I5v2iNOeRAzQ6ZePGT/C2zbn8mI/Gv1ioA+DP+CiX"
+ "xevNPg0b4baLcNBHfQjUdXKNgyR7ysMR9tyMxH+ylYf7EH7Mfhzxl4dm+IPxF02LWbeS5e30mwuBu"
+ "gIQ4eZ16P8ANlQDwNrEg5GPIv27ZJpP2kPECzk7I7OyWHP9z7Oh4/4EWrmPAPwo+OfibwrY6n8PLH"
+ "xFP4dmMgtXstT8qI7XZXwvmDHzBs8daAP0P+N/7KfgDx94G1WHw/4Y0vQPEVvbPLpt5ptqlsfNVSV"
+ "RwgAZWI2nIOM5GDX53fsrfEi7+GXxu8M3cczR6fqd0mmalHnCvDMwTLf7rFX/AOA+9dN/won9po9d"
+ "L8Xf+Dn/AO21m+Hv2TfjRb+INKnn8DahBHHeQu8rTQ4QBwSx+ft1oA+9/wBtL4sXfwt+Ddyuh3DW2"
+ "t+IJxptrKjYeFGUtLIp7EIpUHsXB7V+bXwD+D178cviRYeF7WdrO02NdajdhdxgtkI3MB3YllUe7D"
+ "PGa+t/+CmDzCz+GyDP2cy6iW9N2LfH6E1zf/BNVbb/AITLx2z7ftg0y3EXr5fmtv8A12fpQB9NW37"
+ "FHwVg0QaY/hNp38va17Jfz/aC39/cHAB74AA9q/OT9pT4ISfAf4jy6DDcyX2j3cC3mmXEgG9oWYrt"
+ "fHG5WUgkdRg4GcD9na/N7/gpOR/wnngkd/7Im/8AR1AHcf8ABNP/AJFr4gf9f1n/AOi5K7T/AIKJf"
+ "8kJ07/sY7b/ANEz1xf/AATT/wCRa+IH/X9Z/wDouSu0/wCCiX/JCdO/7GO2/wDRM9AHo37M/wAJLb"
+ "wD4Gs9d1lRf+NvEdvHfaxqUwDSkyKGWEH+FEBA2jjIJ9Me2yRpLG8cqK8bgqysMgg9QRWX4X/5FrR"
+ "v+vGD/wBFitagD4e+H2lR/Ar9uDVPBvh8fZPC/jTTWu4bNeI4m2PKuB/svFMq+ivivuGvjP4m/wDK"
+ "QX4Vf9i+3/oN9X114g1/TvC2h6jrevXSWWmadbvcXU79EjUZJ9+nQcmgC5a2lvYwiGygitoQSwjiQ"
+ "IoJOScD1JJ/GqfiDQNN8VaJf6Lr9pHfaZfwNBcwSLlXRhgj6+h7HmvkzRfiL8a/2np7q8+FE9r8Mv"
+ "h3HM0MOsXcAmvbzacEoDkf987QDkbyQa3T+xxquqjzPFvxu+IGq3J5Zor4wpn2VmfFAGJ+wbf3WjQ"
+ "/E/4e3Vw9xb+FNfKWxY9FdpI2A9Bug3Y9WPrX0d8Y/wDkkfj3/sXdQ/8ASd6+Vv2FNGXw78SPjpo6"
+ "XU96unarDai4uW3SyiOa6Xe57scZJ9TX1T8Y/wDkkfj3/sXdQ/8ASd6APH/2Dv8Ak3LRP+v+9/8AR"
+ "zV9K181fsHf8m5aJ/1/3v8A6OavpWgAooooA+Kv+Cj/AIZa/wDh54V1+NNzaXqjwOcfdSZOv/fUaj"
+ "8a/Nav2k/aZ8Dn4g/BHxdo8Mfm3Qszc2y45MsRDqB9SuPxr85f2Wf2ddG+P13r9rrOvXOj3GmJG6R"
+ "wQq5dWOCTkjoaAPnWiv0g/wCHbXhf/odNU/8AARP8aP8Ah214X/6HTVP/AAET/GgD84Y22SK390g1"
+ "+6Pwy8VWXjb4feG9e0mRXtr7T4ZAFOdjbAGQ+6sCPwr8xf2jP2P9b+ClouuaHdS+IfDOds1wItsls"
+ "f8AbUZ+U+tdF+xV+0fH8Ndck8I+NdQMPhbUW3W8spytpOe/srd/fmgD9Pbu0gvrWa1vYUuLaZCksU"
+ "ihldSMEEHqK/Mz42fsO+MrP4myr8J9I+3+GNUk862czqi2JP3o3JOQoP3TzxgdRX6Z2l3Bf20VzZT"
+ "R3FvKoaOSNgysD3BHWpqAPxw+IXw++Jn7PF9aWnjK3jksrlcwTRyGe3k9VD4BBHpxVXSPilpd6FTU"
+ "o3sJT3Pzp+Y5H5V+t/xE+Hmg/FDwteeHfFtmt1Y3K8HHzxP2dD2YV+QHx5+BuufAzxjLpGro1xpk5"
+ "MmnX4X5LiPP6MO4rjq4OjW1as/I+jwHEWY5faMJ80e0tV/mvkz0K01C1v4xJZXEU6Hujg1Zr5lt7u"
+ "e0kElrNJC4/iRiDXSWHxD12xwDci5UdpVz+teZUyya+CVz7jC8b4eatiabi+61X6P8z3aivK7T4uS"
+ "jAvdPVvUxvj9DWzb/ABV0iTHnw3EJ/wB3NcUsFiI/ZPo6PEuU1tqyXrdfmd3RXJR/EjQHHNy6/WM0"
+ "9viJ4fUf8fbH6Iay+r1v5X9x3LOMuav7eP8A4EjqqK4e5+KejQg+Qk859Am3+dcvq3xUv7pWj0yBL"
+ "RTxvPzN/hW0MFXm/ht6nnYnibKsNG/tOZ9o6/8AA/E9N1jX9P0KAy6jcLH/AHUHLN9BXkHivx3d+I"
+ "S1vbg2tjn7gPzP/vH+lcvdXc97M013K80rdWc5NQ17WHwMKPvS1Z+a5vxRisyTpU/cpvp1fq/0X4h"
+ "RRSqpdgqglicADua9E+OP0u/4Jy+GW0/4a+ItdlTa2qap5cZx1jiQD/0ItXTf8FBv+SAD/sOWn/oM"
+ "leq/s4eCT8P/AIL+E9GlTy7lbNZ7gY/5aSfO36mo/wBoj4NSfHX4e/8ACKQawmht9uhu/tL2xnHyB"
+ "ht27l67uue1AH59fsBf8nC2n/YJvP8A0Fa/V2vkr9nz9i+5+B3xFh8WzeMotbWOzmtvsq6YYCd4Az"
+ "u81umOmK+taAPz2/4KK/Ce9/tPRfiTpVu01i1uum6qUXPkurEwyN7MGKZ6Aqo7iuL/AGQf2ttN+EO"
+ "mTeDfiHHcHw3LcNcWV9BGZGs3bG9WQcmMkbvlyQSeDnj9MdW0mw17TLvTNas4L/T7uJori3njDpIh"
+ "GCrA8EV8V/Eb/gnNoOr30178NfEs3h5JGLf2ffQm5hQnskgIdR9d596APfY/2rfgzJai5X4g6QIyM"
+ "7WLq/8A3wV3fpU/w8/aV+HfxU8ZXHhbwJq02q38Fm940v2R4oSisqkAuAScuDwMYzzXxnB/wTa8bN"
+ "Ni48Y+Ho4c/eSOd2x9Co/nX0D+z5+xdY/BHxbb+LLrxbeazq8MEkKww2q29uVddrBgSzN6jleQKAL"
+ "n7c3wuu/iH8G31DRYGuNU8M3P9oLGgy0lvtKzKB7KQ/8A2zr87f2f/jJefA34kWXie2ga9sWja11G"
+ "0VtpntnILAH+8CqsPdQDwTX7WEBgQwBB4INfGnxm/wCCf/h/xpq1zrfw21VPCl5cuZJtPlgMloznk"
+ "lNpDRZPYBh6AUAejxftt/BSTRP7TbxVJHJs3GxbT5/tAb+5tC7c9s7se9fnL+0b8Zrv47/EO58TrZ"
+ "zWOi20a2OmwycmOFSzDeRxvYszEDpnHOM19B+Hv+CbPiWW/T/hK/Gmk2lgGy50+CWeVh6DeEAPvz9"
+ "DXuPxG/Yg8OeIvhx4b8GeBNTXwxDpF7Jdz3k9p9qmvJHQKzSEMnzfKvsAMAAUAcB/wTTI/wCEa+II"
+ "zz9us/8A0CSu1/4KJf8AJCdO/wCxjtv/AETPXb/sxfs33H7PFp4lt7jxJH4hXWZLeRdlibfyjGJAe"
+ "rtnO8emMV0H7R3wTl+PfgK28MQa0mhNDqUV79oe1NwCESRdu0MvXzM5z2oA9J8L/wDItaN/14wf+i"
+ "xWrVTSrI6bpllZF/MNtBHDvxjdtUDOPwq3QB8afE3/AJSC/Cr/ALF9v/Qb6vQv24ftx/Zv8Uf2bvK"
+ "+dZ/atnXyftCZ/DO3PtW/4o+A0viP9ofwn8V111LeLQdPNmdMNoWabInG7zd42/6/ptP3ffj1rXNE"
+ "0/xLo1/o+uWsd9pt/A9vcwSDKyRsMEH8DQB53+zVc6ZdfAT4ePoJjNquiW8b+XjAnVcTA+/mB8++a"
+ "7zxV4p0nwV4e1HX/Et5HYaVp8LTXE0hwAo7D1JPAA5JIAr5X039lv4q/CS/vYv2fvijDpvh27lMo0"
+ "vW7bzVhJ9DsdSenzBVJwM5rodL/Zf8U+ONWstS/aQ+IVx43trKUTQaDZQ/ZbDeOhkChd/02qfUkZF"
+ "AHm/7AmvnxV46+NWutEbc6tf2175R6p5st0+Pw3V9c/FWzl1D4YeNbS2UvNPoN9HGoGSWMDgD864n"
+ "4W/Ar/hWXxO+IXi201eGew8Wyxypp0dn5X2QqzHAbcQw+duiivY2UOpVgGUjBB7igD5h/YFv4Lv9n"
+ "mxggkVpbPVLyKZQeVYuHAP/AAF1P419P18gyfsqfET4aeKtY1P9nH4h23hnR9Xm82fSdSt/MiiOTw"
+ "uUdWAyQDtDAcZPWvb/AAT4a+I2g/DfV7Hxv4qg8U+MJzPJb3ttbrbrGGQBI14C5BDEMVAywyOKAPT"
+ "6K8p+Dml+K9N/tIeKZb+S2YL5Zvp2kYv3ChvmGOQx+6xwR3ooA9TliSaJ45VDI6lWB7g14h8Bfg14"
+ "X+Feu+NP7Ft5E1m5v2aZ5Hz/AKO53xhB2Xkj8K9yrjfFQPh/WLDxNEP9HUC01ID/AJ4sflc/7rfoa"
+ "AOyopFYOoZCGUjII7iloArahp9rq1jcWOpW8d3Z3EZjmhlUMrqRggg9RXwR8Z/+Ce11d6tPqnwbv7"
+ "SG1nYu2lX8hQRE9o5ADx7Hp61+gFFAHin7Lnwr8S/CL4ZxaF431JL/AFFrl5hHFMZY7dD0jViBn1+"
+ "pr2uiigArlPH/AMN/DPxP0J9G8baVDqdkxyocYaNv7yMOVPuK6uigD4v1r/gnF4HvLppdF8S61psL"
+ "HIhby5Qo9ASM/mal0z/gnH4At8HUvEev3p7gNFGD+SV9l013WJGeRgiKCWYnAA9aAPlUf8E+/hMI9"
+ "p/totj73245/lXNSf8ABOLwSdcS4j8S6yukAfPaERly3tJjgfhn3r3LQf2n/hZ4j8VTeG9M8VWp1K"
+ "OQxjzcxxSMDghHPDV12v8AxW8G+GNa0fRtb8Q2NtqesTLBZQGUFpHJwOnTJIAJ9aAPne9/4J4fDC4"
+ "gKWmoa9aSY4dblW5+hWuOf/gmtohuw0fjnUBaZ5RrJC+P97OP0r7qooA/Hb9qr4M+H/gd4907w74V"
+ "1G71CObTEurj7Wyl0dndeqgDBC5xXhVe1ftaeKz4v/aB8a3Svvgs7z+z4ecgLAojOP8AgSsfxrxWg"
+ "AooooAK9f8A2ZfhrJ8UPjD4f0oxF7G2mF5enHAijO7n6kAV5BX6j/sH/BtvA3w/l8Xazb+Xq/iIBo"
+ "Q64aO1H3f++jz+VAH1rHGsUaRxqFRAFUDsBTqKKACiiigAooooAKKKKACiiigAooooAKKKKACiiig"
+ "AooooAKKKKACiiigAooooAKKKKACorq1hvbaa2uo1lgmQpIjDIZSMEGpaKAOO8J3c2i30vhPVpGea"
+ "2jM2mzuebm0Bx17vGSFb6qe9djWH4o8PDxBZRfZ5jZ6nZyC4sLtRkwygEZ91IJVl7gkVH4X8SHWop"
+ "rbUIRZazZkJeWpOdrf3lPdD1B/rQB0FFFFABRRRQAUUUUAFVtQsYNTsbmyvFL29zE0Uqg4yrDBGfo"
+ "as0UAfHPjn/gnp4H1PTpG8Balf+H9UU7ommlM8RPoQeR9Qa5b4U/sE63ovj3SvEXxJ8UW+pWuk3Md"
+ "zDb2pd3maNgyBmf7q5AyBmvu+igArI8UeJNO8H+HtS13XbmO00/T7d55pHbAAUZx9T0A7k1rkgDJ4"
+ "Ar8wv24/2gW8d+J/+EH8MXhPh7RpD9raNvlubkdc+oXoPfNAHybrmpy61rWpancMXmvbqW4dj3Z2L"
+ "H+dXNH8G+I/ENu9xoGgarqtuhw8tpYyTKp9CVBFdN8Nvgl44+LF2sPgvQrm8h3bXumXZBH9XPFfqv"
+ "8AsyfBvUPgh8No/D2t6hDqF9LcvcymAHy4y2PlBPX60AfkLP4I8T2uftXhzWIMdfM0+Vf5rWfJoup"
+ "QkiXT7uMjrugYf0r978D0Fc74q19dJjhs9Pt0vtavSUs7Yjgnu7eiL1J/CgD8oP2V/gJefGX4jQR6"
+ "nbSxeGdHZbnVJWUqGGcpCPdiPwAJ9K/VGL4h+D9Nv00GDVIIZLZltgiRP5MTDAEZkC+Wp6DaWzWl4"
+ "Y8MR+HtMmiaTz9QvHM19dbcNNMwwW9gAAAOwAFfP0vwi8SReI5RHo8ExMbWiXBVBE8bF83DP97eN+"
+ "ceo6dDQB9QUVBY25tLK2t2cyNDEqFj/FgAZqegAooooAKKKKACiiigAooooAKKKKACiiigAooooAK"
+ "KKKACiiigAooooAKKKKACiiigAooooAK5zxJ4afUpYdS0eYWOuWg/cT4+V17xyDup/TtXR0UAc94c"
+ "8UprDy2F/CdO1u1ANzZSHkD++h/iQ9mH0ODXQ1ieIfC9n4ijheZpbS/tiWtL62bZPbt6q3Qj1UgqR"
+ "wQaxofFWoeG5UtPHcSLETti1i2Qi3l9PMXkxN9cqex7AA7SimRTRzxrJA6yRsMqynII+tPoAKKKKA"
+ "CiiigAooooA+TP2xv2m4Phlok/g/wncCTxZqMOJnRv+PKJh94/7RHQfjXzp+y9+x/f/E+eHxd8So5"
+ "7Pw0X82G3fKy35znJzyE9+9faOrfsofDLXviNdeO9d0q51PV7mVZpILm6Z7YyAABvL/AcEke1e1Qw"
+ "x28SQ28axRRqFREGAoHQAUAUdD0HTPDOl2+maBYwadYW6BIoIIwiqB7CtGmTTR28TSzyLFGgyzOcA"
+ "D61x03ijUPE0j2ngWNRBnbLrFwhMEfr5S8ea3/jo7k9KANLxH4pXSJYdP02A6lrl0ubazQ8henmSH"
+ "+BB3Y/QZNJ4a8Mtpck2o6tOL/W7sf6RcYwFHaNB/Cg/Xqas+HvDFl4cimNuZbm9uWD3d7cNvnuH9W"
+ "b+SjCgcAAVtUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUA"
+ "FFFFABRRRQAUUUUAFFFFABTJYo543jmRZI3GGVhkEehFPooA4+TwXPpEjT+CtQbSiTuazlBktXP+7"
+ "1T/AICfwpB4yvdIIj8XaLc2YHBu7NTcwH3O0b1+mD9a7GgjIweRQBnaTr+l67GZNH1C2vlX73kyhi"
+ "p9COoPsa0awdV8FeH9alE2oaVbPcL92dU2SL9HXBH4Gs//AIQee1/5A3inX9PX+49yl2v/AJMJIcf"
+ "QigDrqK5L+x/GUPFt4q06ZfW80Mu35xzxj9KUad457+I/Dv8A4Ts//wAm0AdZRXJ/2P4xm4ufFWnQ"
+ "r62ehlG/OSeQfpTT4Hmuv+Qz4o1/UF7ot0tov/kusZx9SaAN3Vtf0vQow+sahbWSt90TShSx9AOpP"
+ "sK58+Mb7Vzs8I6LcXanpeXqm2gHuAfnb6YH1rT0rwXoGiyNLp2lW0c7ffmZN8je5c5JP1Nb3TpQBx"
+ "8XgubVpFuPGl+2rMDuWzjHl2qH/c6v/wAC/KuujiSGNY4UWONBhVUYAHoBTqKACiiigAooooAKKKK"
+ "ACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK"
+ "KKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooo"
+ "oAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA"
+ "ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACii"
+ "igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKA"
+ "CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP//Z";
+
+static const char *easter_egg_photos[NUM_EASTER_EGG_PHOTOS + 1];
+
+/*
+ * fedse is based the general implementation in dse
+ */
+
+static struct dse *pfedse= NULL;
+
+static void
+internal_add_helper(Slapi_Entry *e, int dont_write_file)
+{
+ int plugin_actions = 0;
+ Slapi_PBlock newpb;
+ Slapi_Operation *op;
+
+ pblock_init(&newpb);
+ slapi_add_entry_internal_set_pb(&newpb, e, NULL,
+ plugin_get_default_component_id(),
+ plugin_actions);
+ slapi_pblock_set(&newpb, SLAPI_TARGET_DN, (void*)slapi_entry_get_dn_const(e));
+ slapi_pblock_set(&newpb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING,
+ (void *)&dont_write_file);
+ slapi_pblock_get(&newpb, SLAPI_OPERATION, &op);
+ operation_set_flag(op, OP_FLAG_ACTION_NOLOG);
+
+ slapi_add_internal_pb(&newpb);
+ pblock_done(&newpb);
+}
+
+/*
+ * Attempt to initialize the DSE file. First we attempt to read
+ * the file and convert it to the avl tree of DSEs. If the
+ * file doesn't exist, we try to create it and put a minimal
+ * root DSE into it.
+ *
+ * Returns 1 for OK, 0 for Fail.
+ */
+static int
+init_dse_file(const char *configdir, Slapi_DN *config)
+{
+ int rc= 1; /* OK */
+ Slapi_PBlock pb;
+
+ memset(&pb, 0, sizeof(pb));
+
+ if(pfedse==NULL)
+ {
+ pfedse= dse_new(DSE_FILENAME,DSE_TMPFILE,DSE_BACKFILE, DSE_STARTOKFILE, configdir);
+ rc= (pfedse!=NULL);
+ }
+ if(rc)
+ {
+ int dont_write = 1;
+ dse_register_callback(pfedse,DSE_OPERATION_READ,DSE_FLAG_PREOP,config,
+ LDAP_SCOPE_SUBTREE,"(objectclass=nsslapdPlugin)",
+ load_plugin_entry, NULL);
+ dse_register_callback(pfedse,DSE_OPERATION_READ,DSE_FLAG_PREOP,config,
+ LDAP_SCOPE_BASE,"(objectclass=*)",
+ load_config_dse,NULL);
+
+ slapi_pblock_set(&pb, SLAPI_CONFIG_DIRECTORY, (void*)configdir);
+ /* don't write out the file when reading */
+ slapi_pblock_set(&pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, (void*)&dont_write);
+ if(!(rc = dse_read_file(pfedse, &pb)))
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, "dse",
+ "Could not load config file [%s]\n",
+ DSE_FILENAME );
+ }
+ }
+ return rc;
+}
+
+void add_internal_entries()
+{
+ /* add the internal only entries */
+ int i;
+ for(i=0;i<NUM_INTERNAL_ENTRIES;i++)
+ {
+ Slapi_Entry *e;
+ char *p;
+ p= slapi_ch_strdup(internal_entries[i]);
+ e = slapi_str2entry( p, 0 );
+ internal_add_helper(e, 0); /* 0 writes file */
+ slapi_ch_free((void**)&p);
+ }
+}
+
+
+static int
+egg_char2nibble( unsigned char c )
+{
+ return ( c < 'A' ) ? c - '0' : 10 + c -'A';
+}
+
+/* decode in place (output is guaranteed to be smaller than input) */
+static void
+egg_decode( char *s )
+{
+ const char *pin;
+ char *pout;
+
+
+ pin = pout = s;
+ while ( *pin!='\0' ) {
+ *pout = egg_char2nibble(*pin++)<<4;
+ *pout |= egg_char2nibble(*pin++);
+ *pout^= 122;
+ pout++;
+ }
+ *pout= '\0';
+}
+
+static
+void add_easter_egg_entry()
+{
+ Slapi_Entry* e= NULL;
+ char *src;
+
+ easter_egg_photos[0] = easter_egg_photo1;
+ easter_egg_photos[1] = easter_egg_photo2;
+ easter_egg_photos[2] = easter_egg_photo3;
+ easter_egg_photos[NUM_EASTER_EGG_PHOTOS] = NULL;
+
+ src= slapi_ch_strdup(easter_egg_entry);
+ egg_decode( src ); /* twiddle bits */
+ e= slapi_str2entry (src, 0);
+ if ( NULL != e )
+ {
+ internal_add_helper(e, 1); /* 1 tells it to not write these entries to the dse file */
+ }
+ slapi_ch_free((void**)&src);
+}
+
+static int
+dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+/*This function takes care of the search on the attribute nssslsupportedciphers in cn=encryption,cn=config" entry. This would get the list of supported ciphers from the table in ssl.c and always return that value */
+int
+search_encryption( Slapi_PBlock *pb, Slapi_Entry *entry, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+
+ struct berval *vals[2];
+ struct berval val;
+ char ** cipherList = getSupportedCiphers(); /*Get the string array of supported ciphers here */
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ attrlist_delete ( &entry->e_attrs, "nsSSLSupportedCiphers");
+ while (*cipherList) /* iterarate thru each of them and add to the attr value */
+ {
+ char *cipher = *cipherList;
+ val.bv_val = (char* ) cipher;
+ val.bv_len = strlen ( val.bv_val );
+ attrlist_merge ( &entry->e_attrs, "nsSSLSupportedCiphers", vals);
+ cipherList++;
+ }
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/*
+ * This function protects the easter egg entry from being seen,
+ * unless you specifically ask for them.
+ */
+int
+search_easter_egg( Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ char *fstr= NULL;
+ int retmalloc= 0;
+ char eggfilter[64];
+ sprintf(eggfilter,"(objectclass=%s)",EGG_OBJECT_CLASS);
+ slapi_pblock_get( pb, SLAPI_SEARCH_STRFILTER, &fstr );
+ if(fstr!=NULL && strcasecmp(fstr,eggfilter)==0)
+ {
+ static int twiddle= -1;
+ char *type, *value, *copy;
+ char *errmsg = NULL;
+ int vlen;
+ struct berval bv;
+ struct berval *bvals[2];
+ if (twiddle < 0) {
+ twiddle = slapi_rand();
+ }
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+ copy= slapi_ch_strdup(easter_egg_photos[twiddle%NUM_EASTER_EGG_PHOTOS]);
+ if ( (retmalloc = ldif_parse_line(copy, &type, &value, &vlen, &errmsg)) < 0 ) {
+ if ( errmsg != NULL ) {
+ slapi_log_error( SLAPI_LOG_PARSE, "dse", "%s", errmsg );
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ slapi_ch_free( (void**)&errmsg );
+ }
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ bv.bv_val = value;
+ bv.bv_len = vlen;
+ slapi_entry_attr_delete(entryBefore, "jpegphoto");
+ slapi_entry_attr_merge(entryBefore, "jpegphoto", bvals);
+ slapi_ch_free((void**)&copy);
+ twiddle++;
+ /* the memory below was not allocated by the slapi_ch_ functions */
+ slapi_ch_free( (void**)&errmsg );
+ if (retmalloc) slapi_ch_free( (void**)&value );
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+int
+search_counters(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ counters_as_entry(entryBefore);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+int
+search_snmp(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ snmp_as_entry(entryBefore);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/*
+ * Called from config.c to install the internal backends
+ */
+int
+setup_internal_backends(char *configdir)
+{
+ int rc = init_schema_dse(configdir);
+ Slapi_DN config;
+
+ slapi_sdn_init_dn_byref(&config,"cn=config");
+
+ if (rc)
+ {
+ rc= init_dse_file(configdir, &config);
+ }
+
+ if(rc)
+ {
+ Slapi_DN monitor;
+ Slapi_DN counters;
+ Slapi_DN snmp;
+ Slapi_DN root;
+ Slapi_Backend *be;
+ Slapi_DN encryption;
+ Slapi_DN saslmapping;
+
+ slapi_sdn_init_dn_byref(&monitor,"cn=monitor");
+ slapi_sdn_init_dn_byref(&counters,"cn=counters,cn=monitor");
+ slapi_sdn_init_dn_byref(&snmp,"cn=snmp,cn=monitor");
+ slapi_sdn_init_dn_byref(&root,"");
+
+ slapi_sdn_init_dn_byref(&encryption,"cn=encryption,cn=config");
+ slapi_sdn_init_dn_byref(&saslmapping,"cn=mapping,cn=sasl,cn=config");
+
+ /* Search */
+ dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",read_config_dse,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_BASE,"(objectclass=*)",monitor_info,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",read_root_dse,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_SUBTREE,EGG_FILTER,search_easter_egg,NULL); /* Egg */
+ dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&counters,LDAP_SCOPE_BASE,"(objectclass=*)",search_counters,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&snmp,LDAP_SCOPE_BASE,"(objectclass=*)",search_snmp,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&encryption,LDAP_SCOPE_BASE,"(objectclass=*)",search_encryption,NULL);
+
+ /* Modify */
+ dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",modify_config_dse,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_POSTOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",postop_modify_config_dse,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",modify_root_dse,NULL);
+
+ /* Delete */
+ dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&config,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&counters,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&snmp,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&root,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+ dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&encryption,LDAP_SCOPE_BASE,"(objectclass=*)",dont_allow_that,NULL);
+
+ dse_register_callback(pfedse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&saslmapping,LDAP_SCOPE_SUBTREE,"(objectclass=nsSaslMapping)",sasl_map_config_delete,NULL);
+
+ /* Write */
+ dse_register_callback(pfedse,DSE_OPERATION_WRITE,DSE_FLAG_PREOP,&monitor,LDAP_SCOPE_SUBTREE,EGG_FILTER,dont_allow_that,NULL); /* Egg */
+
+ dse_register_callback(pfedse,SLAPI_OPERATION_ADD,DSE_FLAG_PREOP,&saslmapping,LDAP_SCOPE_SUBTREE,"(objectclass=nsSaslMapping)",sasl_map_config_add,NULL);
+
+ be= be_new_internal(pfedse, "DSE", DSE_BACKEND);
+ be_addsuffix(be,&root);
+ be_addsuffix(be,&monitor);
+ be_addsuffix(be,&config);
+
+ add_internal_entries();
+
+ add_easter_egg_entry();
+
+ slapi_sdn_done(&monitor);
+ slapi_sdn_done(&counters);
+ slapi_sdn_done(&snmp);
+ slapi_sdn_done(&root);
+ slapi_sdn_done(&saslmapping);
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, "dse",
+ "Please edit the file to correct the reported problems"
+ " and then restart the server.\n" );
+ exit( 1 );
+ }
+
+ slapi_sdn_done(&config);
+ return rc;
+}
+
+int fedse_create_startOK(char *filename, char *startokfilename, const char *configdir)
+{
+ const char *config_sub_dir = "config";
+ char *id = config_get_instancedir();
+ char *realconfigdir = NULL;
+ char *dse_filename = NULL;
+ char *dse_filestartOK = NULL;
+ int rc = -1;
+
+ if (configdir!=NULL) {
+ realconfigdir = slapi_ch_malloc(strlen(configdir)+1);
+ strcpy(realconfigdir, configdir);
+ } else if (id!=NULL) {
+ realconfigdir = slapi_ch_malloc(strlen(id)+strlen(config_sub_dir)+3);
+ sprintf(realconfigdir, "%s/%s", id, config_sub_dir);
+ }
+ slapi_ch_free_string(&id);
+ if(realconfigdir!=NULL)
+ {
+ /* Set the full path name for the config DSE entry */
+ if (!strstr(filename, realconfigdir))
+ {
+ dse_filename = slapi_ch_malloc( strlen( realconfigdir ) +
+ strlen( filename ) + 3 );
+ sprintf( dse_filename, "%s/%s", realconfigdir, filename );
+ }
+ else
+ dse_filename = slapi_ch_strdup(filename);
+
+ if (!strstr(startokfilename, realconfigdir)) {
+ dse_filestartOK = slapi_ch_malloc( strlen( realconfigdir ) +
+ strlen( startokfilename ) + 3 );
+ sprintf( dse_filestartOK, "%s/%s", realconfigdir, startokfilename );
+ }
+ else
+ dse_filestartOK = slapi_ch_strdup(startokfilename);
+
+ rc = slapi_copy(dse_filename, dse_filestartOK);
+ if ( rc != 0 )
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, "dse", "Cannot copy"
+ " DSE file \"%s\" to \"%s\" OS error %d (%s)\n",
+ dse_filename, dse_filestartOK,
+ rc, slapd_system_strerror(rc) );
+ }
+
+ slapi_ch_free_string(&dse_filename);
+ slapi_ch_free_string(&dse_filestartOK);
+ slapi_ch_free_string(&realconfigdir);
+ }
+
+ return rc;
+}
diff --git a/ldap/servers/slapd/fileio.c b/ldap/servers/slapd/fileio.c
new file mode 100644
index 00000000..f3e90b10
--- /dev/null
+++ b/ldap/servers/slapd/fileio.c
@@ -0,0 +1,336 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* fileio.c - layer to adjust EOL to use DOS format via PR_Read/Write on NT */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <stdlib.h>
+#ifndef _WIN32
+#include <sys/param.h>
+#include <unistd.h>
+#include <pwd.h>
+#endif
+#include "slap.h"
+#include "pw.h"
+#include <prio.h>
+
+#if defined( XP_WIN32 )
+
+#include <prinit.h> /* PR_CallOnce */
+#include <string.h> /* memmove, memcpy */
+
+#define g_EOF (-1)
+
+static PRInt32 PR_CALLBACK readText(PRFileDesc *f, void *buf, PRInt32 amount)
+{
+ auto PRInt32 size = *(signed char*)&(f->secret);
+ auto char* readAhead = ((char*)&(f->secret)) + 1;
+ if ( size == g_EOF ) {
+ f->secret = NULL;
+ return 0;
+ }
+ if ( size > amount ) {
+ return 0;
+ }
+ if ( size > 0 ) {
+ memcpy( buf, readAhead, size );
+ }
+ f->secret = NULL;
+ while (1) {
+ auto PRInt32 len = amount - size;
+ auto char* head;
+ auto PRInt32 rval;
+ if (len > 0) {
+ head = (char*)buf + size;
+ } else if (size > 0 && '\r' == ((char*)buf)[size-1]) {
+ head = readAhead;
+ len = 1;
+ } else {
+ break;
+ }
+ rval = PR_Read( f->lower, head, len );
+ if ( rval < 0 ) { /* error */
+ return rval;
+ }
+ if ( rval == 0 ) { /* EOF */
+ if ( size ) {
+ *(signed char*)&(f->secret) = g_EOF;
+ }
+ return size;
+ }
+ if (head == readAhead) {
+ if ( '\n' == *readAhead ) {
+ ((char*)buf)[size-1] = '\n';
+ } else {
+ *(signed char*)&(f->secret) = rval;
+ }
+ break;
+ } else {
+ auto char* tail = head + rval;
+ auto char* dest = NULL;
+ auto char* p;
+ for ( p = head; p < tail; p++ ) {
+ if ( *p == '\n' && p > (char*)buf && *(p - 1) == '\r' )
+ {
+ if ( dest == NULL ) { /* first CRLF */
+ dest = p - 1;
+ } else {
+ auto size_t len = (p - 1) - head;
+ memmove( dest, head, len );
+ dest += len;
+ }
+ head = p; /* '\n' */
+ --rval; /* ignore '\r' */
+ }
+ }
+ if ( dest != NULL ) {
+ auto size_t len = tail - head;
+ memmove( dest, head, len );
+ }
+ size += rval;
+ }
+ }
+ return size;
+}
+
+static PRInt32 PR_CALLBACK seekText(PRFileDesc *f, PRInt32 offset, PRSeekWhence how)
+{
+ f->secret = NULL;
+ return PR_Seek(f->lower, offset, how);
+}
+
+static PRInt64 PR_CALLBACK seek64Text(PRFileDesc *f, PRInt64 offset, PRSeekWhence how)
+{
+ f->secret = NULL;
+ return PR_Seek64(f->lower, offset, how);
+}
+
+static PRInt32 PR_CALLBACK writeText(PRFileDesc *f, const void *buf, PRInt32 amount)
+{
+ /* note: buf might not be null-terminated */
+ auto PRInt32 size = 0;
+ auto char* head = (char*)buf;
+ auto char* tail = head + amount;
+ auto char* p;
+ for ( p = head; p <= tail; ++p ) {
+ if ( p == tail || *p == '\n' ) {
+ auto PRInt32 len = p - head;
+ auto PRInt32 rval;
+ if ( len > 0 ) {
+ rval = PR_Write( f->lower, head, len );
+ if ( rval < 0 ) {
+ return rval;
+ }
+ size += rval;
+ if ( rval < len ) {
+ break;
+ }
+ }
+ if ( p == tail ) {
+ break;
+ }
+ rval = PR_Write( f->lower, "\r", 1 );
+ if ( rval < 0 ) {
+ return rval;
+ }
+ if ( rval < 1 ) {
+ break;
+ }
+ head = p;
+ }
+ }
+ return size;
+}
+
+static PRInt32 PR_CALLBACK writevText(PRFileDesc *fd, const PRIOVec *iov, PRInt32 size, PRIntervalTime timeout)
+{
+ auto PRInt32 i;
+ auto size_t total = 0;
+ for (i = 0; i < size; ++i) {
+ register PRInt32 rval = PR_Write(fd, iov[i].iov_base, iov[i].iov_len);
+ if (rval < 0) return rval;
+ total += rval;
+ if (rval < iov[i].iov_len) break;
+ }
+ return total;
+}
+
+/* ONREPL - this is bad because it allows only one thread to use this functionality.
+ Noriko said she would fix this before 5.0 ships.
+ */
+
+static const char* const g_LayerName = "MdsTextIO";
+static PRDescIdentity g_LayerID;
+static PRIOMethods g_IoMethods;
+
+static PRStatus PR_CALLBACK closeLayer(PRFileDesc* stack)
+{
+ auto PRFileDesc* layer = PR_PopIOLayer(stack, g_LayerID);
+ if (!layer)
+ return PR_FAILURE;
+ if (layer->dtor) {
+ layer->secret = NULL;
+ layer->dtor(layer);
+ }
+ return PR_Close(stack);
+}
+
+static PRStatus PR_CALLBACK initialize(void)
+{
+ g_LayerID = PR_GetUniqueIdentity(g_LayerName);
+ if (PR_INVALID_IO_LAYER == g_LayerID) {
+ return PR_FAILURE;
+ } else {
+ auto const PRIOMethods* defaults = PR_GetDefaultIOMethods();
+ if (!defaults) {
+ return PR_FAILURE;
+ } else {
+ memcpy (&g_IoMethods, defaults, sizeof(g_IoMethods));
+ }
+ }
+ /* Customize methods: */
+ g_IoMethods.read = readText;
+ g_IoMethods.seek = seekText;
+ g_IoMethods.seek64 = seek64Text;
+ g_IoMethods.write = writeText;
+ g_IoMethods.writev = writevText; /* ??? Is this necessary? */
+ g_IoMethods.close = closeLayer; /* ??? Is this necessary? */
+ return PR_SUCCESS;
+}
+
+static PRCallOnceType g_callOnce = {0,0};
+
+/* Push a layer that converts from "\n" to the local filesystem's
+ * end-of-line sequence on output, and vice-versa on input.
+ * The layer pops itself (if necessary) when the file is closed.
+ *
+ * This layer does not affect the behavior of PR_Seek or PR_Seek64;
+ * their parameters still measure bytes in the lower-level file,
+ * and consequently will not add up with the results of PR_Read
+ * or PR_Write. For example, if you add up PR_Read return values,
+ * and seek backward in the file that many bytes, the cursor will
+ * *not* be restored to its original position (unless the data you
+ * read didn't require conversion; that is, they didn't contain
+ * any newlines, or you're running on Unix).
+ *
+ * Likewise, the results of PR_Read or PR_Write won't add up to
+ * the 'size' field in the result of PRFileInfo or PRFileInfo64.
+ */
+static PRStatus pushTextIOLayer(PRFileDesc* stack)
+{
+ auto PRStatus rv = PR_CallOnce(&g_callOnce, initialize);
+ if (PR_SUCCESS == rv) {
+ auto PRFileDesc* layer = PR_CreateIOLayerStub(g_LayerID, &g_IoMethods);
+ layer->secret = NULL;
+ rv = PR_PushIOLayer(stack, PR_TOP_IO_LAYER, layer);
+ }
+ return rv;
+}
+
+static PRFileDesc *popTextIOLayer(PRFileDesc* stack)
+{
+ PRFileDesc *layer;
+ layer = PR_PopIOLayer(stack, g_LayerID);
+ if (layer && layer->dtor) {
+ layer->secret = NULL;
+ layer->dtor(layer);
+ }
+ return layer;
+}
+
+#endif /* XP_WIN32 */
+
+PRInt32
+slapi_read_buffer( PRFileDesc *fd, void *buf, PRInt32 amount )
+{
+ PRInt32 rval = 0;
+#if defined( XP_WIN32 )
+ PRStatus rv;
+
+ rv = pushTextIOLayer( fd );
+ if ( PR_SUCCESS != rv ) {
+ return -1;
+ }
+#endif
+
+ rval = PR_Read( fd, buf, amount );
+
+#if defined( XP_WIN32 )
+ popTextIOLayer( fd );
+#endif
+
+ return rval;
+}
+
+/*
+ * slapi_write_buffer -- same as PR_Write
+ * except '\r' is added before '\n'.
+ * Return value: written bytes not including '\r' characters.
+ */
+PRInt32
+slapi_write_buffer( PRFileDesc *fd, void *buf, PRInt32 amount )
+{
+ PRInt32 rval = 0;
+#if defined( XP_WIN32 )
+ PRStatus rv;
+
+ rv = pushTextIOLayer( fd );
+ if ( PR_SUCCESS != rv ) {
+ return -1;
+ }
+#endif
+
+ rval = PR_Write( fd, buf, amount );
+
+#if defined( XP_WIN32 )
+ popTextIOLayer( fd );
+#endif
+
+ return rval;
+}
+
+/*
+ * This function renames a file to a new name. Unlike PR_Rename or NT rename, this
+ * function can be used if the destfilename exists, and it will overwrite the dest
+ * file name
+ */
+int
+slapi_destructive_rename(const char *srcfilename, const char *destfilename)
+{
+ int rv = 0;
+#if defined( XP_WIN32 )
+ if (!MoveFileEx(srcfilename, destfilename, MOVEFILE_REPLACE_EXISTING)) {
+ rv = GetLastError();
+ }
+#else
+ if ( rename(srcfilename, destfilename) < 0 ) {
+ rv = errno;
+ }
+#endif
+ return rv;
+}
+
+/*
+ * This function copies the source into the dest
+ */
+int
+slapi_copy(const char *srcfilename, const char *destfilename)
+{
+ int rv = 0;
+#if defined( XP_WIN32 )
+ if (!CopyFile(srcfilename, destfilename, FALSE)) {
+ rv = GetLastError();
+ }
+#else
+ unlink(destfilename);
+ if ( link(srcfilename, destfilename) < 0 ) {
+ rv = errno;
+ }
+#endif
+ return rv;
+}
diff --git a/ldap/servers/slapd/filter.c b/ldap/servers/slapd/filter.c
new file mode 100644
index 00000000..2f22e317
--- /dev/null
+++ b/ldap/servers/slapd/filter.c
@@ -0,0 +1,1505 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* filter.c - routines for parsing and dealing with filters */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#include "slapi-plugin.h"
+
+static int
+get_filter_list( Connection *conn, BerElement *ber,
+ struct slapi_filter **f, char **fstr, int maxdepth, int curdepth,
+ int *subentry_dont_rewrite, int *has_tombstone_filter);
+static int get_substring_filter();
+static int get_extensible_filter( BerElement *ber, mr_filter_t* );
+
+static int get_filter_internal( Connection *conn, BerElement *ber,
+ struct slapi_filter **filt, char **fstr, int maxdepth, int curdepth,
+ int *subentry_dont_rewrite, int *has_tombstone_filter);
+static int tombstone_check_filter(Slapi_Filter *f);
+static void filter_optimize(Slapi_Filter *f);
+
+
+
+/*
+ * Read a filter off the wire and create a slapi_filter and string representation.
+ * Both filt and fstr are allocated by this function, so must be freed by the caller.
+ *
+ * If the scope is not base and (objectclass=ldapsubentry) does not occur
+ * in the filter then we add (!(objectclass=ldapsubentry)) to the filter
+ * so that subentries are not returned.
+ * If the scope is base or (objectclass=ldapsubentry) occurs in the filter,
+ * then the caller is explicitly handling subentries himself and so we leave
+ * the filter as is.
+ */
+int
+get_filter( Connection *conn, BerElement *ber, int scope,
+ struct slapi_filter **filt, char **fstr )
+{
+ int subentry_dont_rewrite = 0; /* Re-write unless we're told not to */
+ int has_tombstone_filter = 0; /* Check if nsTombstone appears */
+ int return_value = 0;
+ char *logbuf = NULL;
+ size_t logbufsize = 0;
+
+ return_value = get_filter_internal(conn, ber, filt, fstr,
+ config_get_max_filter_nest_level(), /* maximum depth */
+ 0, /* current depth */
+ &subentry_dont_rewrite, &has_tombstone_filter);
+
+ if (0 == return_value) { /* Don't try to re-write if there was an error */
+ if (subentry_dont_rewrite || scope == LDAP_SCOPE_BASE)
+ (*filt)->f_flags |= SLAPI_FILTER_LDAPSUBENTRY;
+ if (has_tombstone_filter)
+ (*filt)->f_flags |= SLAPI_FILTER_TOMBSTONE;
+ }
+
+ if (LDAPDebugLevelIsSet( LDAP_DEBUG_FILTER ) && *filt != NULL
+ && *fstr != NULL) {
+ logbufsize = strlen(*fstr) + 1;
+ logbuf = slapi_ch_malloc(logbufsize);
+ *logbuf = '\0';
+ slapi_log_error( SLAPI_LOG_FATAL, "get_filter", "before optimize: %s\n",
+ slapi_filter_to_string(*filt, logbuf, logbufsize), 0, 0 );
+ }
+
+ filter_optimize(*filt);
+
+ if (NULL != logbuf) {
+ slapi_log_error( SLAPI_LOG_FATAL, "get_filter", " after optimize: %s\n",
+ slapi_filter_to_string(*filt, logbuf, logbufsize), 0, 0 );
+ slapi_ch_free_string( &logbuf );
+ }
+
+ return return_value;
+}
+
+
+#define FILTER_EQ_FMT "(%s=%s)"
+#define FILTER_GE_FMT "(%s>=%s)"
+#define FILTER_LE_FMT "(%s<=%s)"
+#define FILTER_APROX_FMT "(%s~=%s)"
+#define FILTER_EXTENDED_FMT "(%s%s%s%s:=%s)"
+#define FILTER_EQ_LEN 4
+#define FILTER_GE_LEN 5
+#define FILTER_LE_LEN 5
+#define FILTER_APROX_LEN 5
+
+
+/* returns escaped filter string for extended filters only*/
+
+static char *
+filter_escape_filter_value_extended(struct slapi_filter *f)
+{
+ char ebuf[BUFSIZ], *ptr;
+ const char *estr;
+ size_t len = 9;
+
+ estr = escape_filter_value( f->f_mr_value.bv_val, f->f_mr_value.bv_len, ebuf );
+ if ( f->f_mr_type ) {
+ len += strlen( f->f_mr_type );
+ }
+ len += strlen(estr);
+ if ( f->f_mr_oid ) {
+ len += strlen( f->f_mr_oid );
+ }
+ ptr = slapi_ch_malloc( len );
+ sprintf( ptr, FILTER_EXTENDED_FMT,
+ f->f_mr_type ? f->f_mr_type : "",
+ f->f_mr_dnAttrs ? ":dn" : "",
+ f->f_mr_oid ? ":" : "",
+ f->f_mr_oid ? f->f_mr_oid : "",
+ estr );
+ return ptr;
+}
+
+/* returns escaped filter string for EQ, LE, GE and APROX filters */
+
+static char *
+filter_escape_filter_value(struct slapi_filter *f, const char *fmt, size_t len)
+{
+ char ebuf[BUFSIZ], *ptr;
+ const char *estr;
+
+ estr = escape_filter_value( f->f_avvalue.bv_val, f->f_avvalue.bv_len, ebuf );
+ filter_compute_hash(f);
+ ptr = slapi_ch_malloc( len + strlen(f->f_avtype) + strlen( estr ));
+ sprintf( ptr, fmt, f->f_avtype, estr );
+ return ptr;
+}
+
+
+/*
+ * get_filter_internal(): extract an LDAP filter from a BerElement and create
+ * a slapi_filter structure (*filt) and a string equivalent (*fstr).
+ *
+ * This function is recursive. It calls itself (to process NOT filters) and
+ * it calls get_filter_list() for AND and OR filters, and get_filter_list()
+ * calls this function again.
+ */
+static int
+get_filter_internal( Connection *conn, BerElement *ber,
+ struct slapi_filter **filt, char **fstr, int maxdepth, int curdepth,
+ int *subentry_dont_rewrite, int *has_tombstone_filter )
+{
+ unsigned long len;
+ int err;
+ struct slapi_filter *f;
+ char *ftmp, *type;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> get_filter_internal\n", 0, 0, 0 );
+
+ /*
+ * Track and check the depth of nesting. Use post-increment on
+ * current depth here because this function is called for the
+ * top-level filter (which does not count towards the maximum depth).
+ */
+ if ( ( curdepth++ > maxdepth ) && ( maxdepth > 0 )) {
+ *filt = NULL;
+ *fstr = NULL;
+ err = LDAP_UNWILLING_TO_PERFORM;
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= get_filter_internal %d"
+ " (maximum nesting level of %d exceeded)\n",
+ err, maxdepth, 0 );
+ return( err );
+ }
+
+ /*
+ * A filter looks like this coming in:
+ * Filter ::= CHOICE {
+ * and [0] SET OF Filter,
+ * or [1] SET OF Filter,
+ * not [2] Filter,
+ * equalityMatch [3] AttributeValueAssertion,
+ * substrings [4] SubstringFilter,
+ * greaterOrEqual [5] AttributeValueAssertion,
+ * lessOrEqual [6] AttributeValueAssertion,
+ * present [7] AttributeType,
+ * approxMatch [8] AttributeValueAssertion,
+ * extensibleMatch [9] MatchingRuleAssertion --v3 only
+ * }
+ *
+ * SubstringFilter ::= SEQUENCE {
+ * type AttributeType,
+ * SEQUENCE OF CHOICE {
+ * initial [0] IA5String,
+ * any [1] IA5String,
+ * final [2] IA5String
+ * }
+ * }
+ *
+ * The extensibleMatch was added in LDAPv3:
+ *
+ * MatchingRuleAssertion ::= SEQUENCE {
+ * matchingRule [1] MatchingRuleID OPTIONAL,
+ * type [2] AttributeDescription OPTIONAL,
+ * matchValue [3] AssertionValue,
+ * dnAttributes [4] BOOLEAN DEFAULT FALSE
+ * }
+ */
+
+ f = (struct slapi_filter *) slapi_ch_calloc( 1, sizeof(struct slapi_filter) );
+
+ err = 0;
+ *fstr = NULL;
+ f->f_choice = ber_peek_tag( ber, &len );
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ LDAPDebug( LDAP_DEBUG_FILTER, "EQUALITY\n", 0, 0, 0 );
+ if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
+
+ if ( 0 == strcasecmp ( f->f_avtype, "objectclass")) {
+ /* Process objectclass oid's here */
+ if (strchr (f->f_avvalue.bv_val, '.')) {
+ char *ocname = oc_find_name( f->f_avvalue.bv_val );
+
+ if ( NULL != ocname ) {
+ slapi_ch_free((void**)&f->f_avvalue.bv_val );
+ f->f_avvalue.bv_val = ocname;
+ f->f_avvalue.bv_len = strlen ( f->f_avvalue.bv_val );
+ }
+ }
+
+ /*
+ * Process subentry searches here.
+ * Only set (*subentry_dont_rewrite) if it's not already set.
+ */
+
+ if (!(*subentry_dont_rewrite)) {
+ *subentry_dont_rewrite = subentry_check_filter(f);
+ }
+ /*
+ * Check if it's a Tomstone filter.
+ * We need to do it once per filter, so if flag is already set,
+ * don't bother doing it
+ */
+ if (!(*has_tombstone_filter)) {
+ *has_tombstone_filter = tombstone_check_filter(f);
+ }
+ }
+ *fstr=filter_escape_filter_value(f, FILTER_EQ_FMT, FILTER_EQ_LEN);
+ }
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ LDAPDebug( LDAP_DEBUG_FILTER, "SUBSTRINGS\n", 0, 0, 0 );
+ err = get_substring_filter( conn, ber, f, fstr );
+ break;
+
+ case LDAP_FILTER_GE:
+ LDAPDebug( LDAP_DEBUG_FILTER, "GE\n", 0, 0, 0 );
+ if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
+ *fstr=filter_escape_filter_value(f, FILTER_GE_FMT, FILTER_GE_LEN);
+ }
+ break;
+
+ case LDAP_FILTER_LE:
+ LDAPDebug( LDAP_DEBUG_FILTER, "LE\n", 0, 0, 0 );
+ if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
+ *fstr=filter_escape_filter_value(f, FILTER_LE_FMT, FILTER_LE_LEN);
+ }
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ LDAPDebug( LDAP_DEBUG_FILTER, "PRESENT\n", 0, 0, 0 );
+ if ( ber_scanf( ber, "a", &type ) == LBER_ERROR ) {
+ err = LDAP_PROTOCOL_ERROR;
+ } else {
+ err = LDAP_SUCCESS;
+ f->f_type = slapi_attr_syntax_normalize( type );
+ free( type );
+ filter_compute_hash(f);
+ *fstr = slapi_ch_malloc( 5 + strlen( f->f_type ) );
+ sprintf( *fstr, "(%s=*)", f->f_type );
+ }
+ break;
+
+ case LDAP_FILTER_APPROX:
+ LDAPDebug( LDAP_DEBUG_FILTER, "APPROX\n", 0, 0, 0 );
+ if ( (err = get_ava( ber, &f->f_ava )) == 0 ) {
+ *fstr=filter_escape_filter_value(f, FILTER_APROX_FMT, FILTER_APROX_LEN);
+ }
+ break;
+
+ case LDAP_FILTER_EXTENDED:
+ LDAPDebug( LDAP_DEBUG_FILTER, "EXTENDED\n", 0, 0, 0 );
+ if ( conn->c_ldapversion < 3 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "extensible filter received from v2 client\n",
+ 0, 0, 0 );
+ err = LDAP_PROTOCOL_ERROR;
+ } else if ( (err = get_extensible_filter( ber, &f->f_mr )) == LDAP_SUCCESS ) {
+ *fstr=filter_escape_filter_value_extended(f);
+ LDAPDebug (LDAP_DEBUG_FILTER, "%s\n", *fstr, 0, 0);
+ if(f->f_mr_oid==NULL) {
+ /*
+ * We accept:
+ * A) attr ":=" value
+ * B) attr ":dn" ":=" value
+ */
+ err = LDAP_SUCCESS;
+ } else {
+ err = plugin_mr_filter_create (&f->f_mr);
+ }
+ }
+ break;
+
+ case LDAP_FILTER_AND:
+ LDAPDebug( LDAP_DEBUG_FILTER, "AND\n", 0, 0, 0 );
+ if ( (err = get_filter_list( conn, ber, &f->f_and, &ftmp, maxdepth,
+ curdepth, subentry_dont_rewrite, has_tombstone_filter ))
+ == 0 ) {
+ filter_compute_hash(f);
+ *fstr = slapi_ch_malloc( 4 + strlen( ftmp ) );
+ sprintf( *fstr, "(&%s)", ftmp );
+ slapi_ch_free((void**)&ftmp );
+ }
+ break;
+
+ case LDAP_FILTER_OR:
+ LDAPDebug( LDAP_DEBUG_FILTER, "OR\n", 0, 0, 0 );
+ if ( (err = get_filter_list( conn, ber, &f->f_or, &ftmp, maxdepth,
+ curdepth, subentry_dont_rewrite, has_tombstone_filter ))
+ == 0 ) {
+ filter_compute_hash(f);
+ *fstr = slapi_ch_malloc( 4 + strlen( ftmp ) );
+ sprintf( *fstr, "(|%s)", ftmp );
+ slapi_ch_free((void**)&ftmp );
+ }
+ break;
+
+ case LDAP_FILTER_NOT:
+ LDAPDebug( LDAP_DEBUG_FILTER, "NOT\n", 0, 0, 0 );
+ (void) ber_skip_tag( ber, &len );
+ if ( (err = get_filter_internal( conn, ber, &f->f_not, &ftmp, maxdepth,
+ curdepth, subentry_dont_rewrite, has_tombstone_filter ))
+ == 0 ) {
+ filter_compute_hash(f);
+ *fstr = slapi_ch_malloc( 4 + strlen( ftmp ) );
+ sprintf( *fstr, "(!%s)", ftmp );
+ slapi_ch_free((void**)&ftmp );
+ }
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY, "get_filter_internal: unknown type 0x%lX\n",
+ f->f_choice, 0, 0 );
+ err = LDAP_PROTOCOL_ERROR;
+ break;
+ }
+
+ if ( err != 0 ) {
+ slapi_filter_free( f, 1 );
+ f = NULL;
+ slapi_ch_free( (void**)fstr );
+ }
+ *filt = f;
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= get_filter_internal %d\n", err, 0, 0 );
+ return( err );
+}
+
+static int
+get_filter_list( Connection *conn, BerElement *ber,
+ struct slapi_filter **f, char **fstr, int maxdepth,
+ int curdepth, int *subentry_dont_rewrite,
+ int *has_tombstone_filter)
+{
+ struct slapi_filter **new;
+ int err;
+ unsigned long tag, len;
+ char *last;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> get_filter_list\n", 0, 0, 0 );
+
+ *fstr = NULL;
+ new = f;
+ for ( tag = ber_first_element( ber, &len, &last );
+ tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element( ber, &len, last ) ) {
+ char *ftmp;
+ if ( (err = get_filter_internal( conn, ber, new, &ftmp, maxdepth,
+ curdepth, subentry_dont_rewrite, has_tombstone_filter))
+ != 0 ) {
+ if ( *fstr != NULL ) {
+ slapi_ch_free((void**)fstr );
+ }
+ return( err );
+ }
+ if ( *fstr == NULL ) {
+ *fstr = ftmp;
+ } else {
+ *fstr = slapi_ch_realloc( *fstr, strlen( *fstr ) +
+ strlen( ftmp ) + 1 );
+ strcat( *fstr, ftmp );
+ slapi_ch_free((void**)&ftmp );
+ }
+ new = &(*new)->f_next;
+ }
+ *new = NULL;
+
+ if ( tag == LBER_ERROR && *fstr != NULL ) {
+ slapi_ch_free((void**)fstr );
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= get_filter_list\n", 0, 0, 0 );
+ return(( *fstr == NULL ) ? LDAP_PROTOCOL_ERROR : 0 );
+}
+
+static int
+get_substring_filter(
+ Connection *conn,
+ BerElement *ber,
+ struct slapi_filter *f,
+ char **fstr
+)
+{
+ unsigned long tag, len, rc;
+ char *val, *last, *type;
+ char ebuf[BUFSIZ];
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> get_substring_filter\n", 0, 0, 0 );
+
+ if ( ber_scanf( ber, "{a", &type ) == LBER_ERROR ) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+ f->f_sub_type = slapi_attr_syntax_normalize( type );
+ free( type );
+ f->f_sub_initial = NULL;
+ f->f_sub_any = NULL;
+ f->f_sub_final = NULL;
+
+ *fstr = slapi_ch_malloc( strlen( f->f_sub_type ) + 3 );
+ sprintf( *fstr, "(%s=", f->f_sub_type );
+ for ( tag = ber_first_element( ber, &len, &last );
+ tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element( ber, &len, last ) )
+ {
+ rc = ber_scanf( ber, "a", &val );
+ if ( rc == LBER_ERROR ) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+ if ( val == NULL || *val == '\0' ) {
+ if ( val != NULL ) {
+ free( val );
+ }
+ return( LDAP_INVALID_SYNTAX );
+ }
+
+ switch ( tag ) {
+ case LDAP_SUBSTRING_INITIAL:
+ LDAPDebug( LDAP_DEBUG_FILTER, " INITIAL\n", 0, 0, 0 );
+ if ( f->f_sub_initial != NULL ) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+ f->f_sub_initial = val;
+ /* jcm: Had to cast away a const */
+ val = (char*)escape_filter_value( val, -1, ebuf );
+ *fstr = slapi_ch_realloc( *fstr, strlen( *fstr ) +
+ strlen( val ) + 1 );
+ strcat( *fstr, val );
+ break;
+
+ case LDAP_SUBSTRING_ANY:
+ LDAPDebug( LDAP_DEBUG_FILTER, " ANY\n", 0, 0, 0 );
+ charray_add( &f->f_sub_any, val );
+ /* jcm: Had to cast away a const */
+ val = (char*)escape_filter_value( val, -1, ebuf );
+ *fstr = slapi_ch_realloc( *fstr, strlen( *fstr ) +
+ strlen( val ) + 2 );
+ strcat( *fstr, "*" );
+ strcat( *fstr, val );
+ break;
+
+ case LDAP_SUBSTRING_FINAL:
+ LDAPDebug( LDAP_DEBUG_FILTER, " FINAL\n", 0, 0, 0 );
+ if ( f->f_sub_final != NULL ) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+ f->f_sub_final = val;
+ /* jcm: Had to cast away a const */
+ val = (char*)escape_filter_value( val, -1, ebuf );
+ *fstr = slapi_ch_realloc( *fstr, strlen( *fstr ) +
+ strlen( val ) + 2 );
+ strcat( *fstr, "*" );
+ strcat( *fstr, val );
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_FILTER, " unknown tag 0x%lX\n", tag, 0, 0 );
+ return( LDAP_PROTOCOL_ERROR );
+ }
+ }
+
+ if ( tag == LBER_ERROR ) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+ if ( f->f_sub_initial == NULL && f->f_sub_any == NULL &&
+ f->f_sub_final == NULL ) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+
+ filter_compute_hash(f);
+ *fstr = slapi_ch_realloc( *fstr, strlen( *fstr ) + 3 );
+ if ( f->f_sub_final == NULL ) {
+ strcat( *fstr, "*" );
+ }
+ strcat( *fstr, ")" );
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= get_substring_filter\n", 0, 0, 0 );
+ return( 0 );
+}
+
+static int
+get_extensible_filter( BerElement *ber, mr_filter_t* mrf )
+{
+ int gotelem, gotoid, gotvalue;
+ unsigned long tag, len;
+ char *last;
+ int rc = LDAP_PROTOCOL_ERROR;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> get_extensible_filter\n", 0, 0, 0 );
+ memset (mrf, 0, sizeof (mr_filter_t));
+
+ gotelem = gotoid = gotvalue = 0;
+ for ( tag = ber_first_element( ber, &len, &last );
+ tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element( ber, &len, last ) ) {
+ /*
+ * order of elements goes like this:
+ *
+ * [oid][type]value[dnattr]
+ *
+ * where either oid or type is required.
+ */
+ switch ( tag ) {
+ case LDAP_TAG_MRA_OID:
+ if ( gotelem != 0 ) {
+ goto parsing_error;
+ }
+ rc = ber_scanf( ber, "a", &mrf->mrf_oid );
+ gotoid = 1;
+ gotelem++;
+ break;
+ case LDAP_TAG_MRA_TYPE:
+ if ( gotelem != 0 ) {
+ if ( gotelem != 1 || gotoid != 1 ) {
+ goto parsing_error;
+ }
+ }
+ {
+ char* type;
+ if (ber_scanf( ber, "a", &type ) == LBER_ERROR) {
+ rc = LDAP_PROTOCOL_ERROR;
+ } else {
+ mrf->mrf_type = slapi_attr_syntax_normalize(type);
+ free (type);
+ }
+ }
+ gotelem++;
+ break;
+ case LDAP_TAG_MRA_VALUE:
+ if ( gotelem != 1 && gotelem != 2 ) {
+ goto parsing_error;
+ }
+ rc = ber_scanf( ber, "o", &mrf->mrf_value );
+ gotvalue = 1;
+ gotelem++;
+ break;
+ case LDAP_TAG_MRA_DNATTRS:
+ if ( gotvalue != 1 ) {
+ goto parsing_error;
+ }
+ rc = ber_scanf( ber, "b", &mrf->mrf_dnAttrs );
+ gotelem++;
+ break;
+ default:
+ goto parsing_error;
+ }
+ if ( rc == -1 ) {
+ goto parsing_error;
+ }
+ rc = LDAP_SUCCESS;
+ }
+
+ if ( tag == LBER_ERROR ) {
+ goto parsing_error;
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= get_extensible_filter %i\n", rc, 0, 0 );
+ return rc;
+
+parsing_error:;
+ LDAPDebug( LDAP_DEBUG_ANY, "error parsing extensible filter\n",
+ 0, 0, 0 );
+ return( LDAP_PROTOCOL_ERROR );
+}
+
+
+Slapi_Filter *
+slapi_filter_dup(Slapi_Filter *f)
+{
+ Slapi_Filter *out = 0;
+ struct slapi_filter *fl = 0;
+ struct slapi_filter **outl = 0;
+ struct slapi_filter *lastout = 0;
+
+ if ( f == NULL ) {
+ return NULL;
+ }
+
+ out = (struct slapi_filter*)calloc(1, sizeof(struct slapi_filter));
+ if ( out == NULL ) {
+ LDAPDebug(LDAP_DEBUG_ANY, "slapi_filter_dup: memory allocation error\n",
+ 0, 0, 0 );
+ return NULL;
+ }
+
+ out->f_choice = f->f_choice;
+ out->f_hash = f->f_hash;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "slapi_filter_dup type 0x%lX\n", f->f_choice, 0, 0 );
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ out->f_ava.ava_type = slapi_ch_strdup(f->f_ava.ava_type);
+ out->f_ava.ava_value.bv_val = slapi_ch_malloc(f->f_ava.ava_value.bv_len+1);
+ memcpy(out->f_ava.ava_value.bv_val,f->f_ava.ava_value.bv_val,f->f_ava.ava_value.bv_len);
+ out->f_ava.ava_value.bv_val[f->f_ava.ava_value.bv_len] = 0; /* terminate */
+ out->f_ava.ava_value.bv_len = f->f_ava.ava_value.bv_len;
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+
+ out->f_sub_type = slapi_ch_strdup(f->f_sub_type);
+ out->f_sub_initial = slapi_ch_strdup(f->f_sub_initial );
+ out->f_sub_any = charray_dup( f->f_sub_any );
+ out->f_sub_final = slapi_ch_strdup(f->f_sub_final );
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ out->f_type = slapi_ch_strdup( f->f_type );
+ break;
+
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ outl = &out->f_list;
+
+/* out->f_list = slapi_filter_dup(f->f_list);
+*/
+ for (fl = f->f_list; fl != NULL; fl = fl->f_next) {
+ (*outl) = slapi_filter_dup( fl );
+ (*outl)->f_next = 0;
+ if(lastout)
+ lastout->f_next = *outl;
+ lastout = *outl;
+ outl = &((*outl)->f_next);
+ }
+ break;
+
+ case LDAP_FILTER_EXTENDED:
+ /* something needs to be done here, but Im not sure how to do it
+ slapi_ch_free((void**)&f->f_mr_oid);
+ slapi_ch_free((void**)&f->f_mr_type);
+ slapi_ch_free((void **)&f->f_mr_value.bv_val );
+ if (f->f_mr.mrf_destroy != NULL) {
+ Slapi_PBlock pb;
+ pblock_init (&pb);
+ if ( ! slapi_pblock_set (&pb, SLAPI_PLUGIN_OBJECT, f->f_mr.mrf_object)) {
+ f->f_mr.mrf_destroy (&pb);
+ }
+ }
+ */
+ break;
+
+ default:
+ LDAPDebug(LDAP_DEBUG_FILTER, "slapi_filter_dup: unknown type 0x%lX\n",
+ f->f_choice, 0, 0 );
+ break;
+ }
+
+ return out;
+}
+
+void
+slapi_filter_free( struct slapi_filter *f, int recurse )
+{
+ if ( f == NULL ) {
+ return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "slapi_filter_free type 0x%lX\n", f->f_choice, 0, 0 );
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ ava_done( &f->f_ava );
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ slapi_ch_free((void**)&f->f_sub_type );
+ slapi_ch_free((void**)&f->f_sub_initial );
+ charray_free( f->f_sub_any );
+ slapi_ch_free((void**)&f->f_sub_final );
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ slapi_ch_free((void**)&f->f_type );
+ break;
+
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ if ( recurse ) {
+ struct slapi_filter *fl, *next;
+
+ for (fl = f->f_list; fl != NULL; fl = next) {
+ next = fl->f_next;
+ fl->f_next = NULL;
+ slapi_filter_free( fl, recurse );
+ fl = next;
+ }
+ }
+ break;
+
+ case LDAP_FILTER_EXTENDED:
+ slapi_ch_free((void**)&f->f_mr_oid);
+ slapi_ch_free((void**)&f->f_mr_type);
+ slapi_ch_free((void **)&f->f_mr_value.bv_val );
+ if (f->f_mr.mrf_destroy != NULL) {
+ Slapi_PBlock pb;
+ pblock_init (&pb);
+ if ( ! slapi_pblock_set (&pb, SLAPI_PLUGIN_OBJECT, f->f_mr.mrf_object)) {
+ f->f_mr.mrf_destroy (&pb);
+ }
+ }
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY, "slapi_filter_free: unknown type 0x%lX\n",
+ f->f_choice, 0, 0 );
+ break;
+ }
+ slapi_ch_free((void**)&f);
+}
+
+#if 0
+static void
+filter_list_insert( struct slapi_filter **into, struct slapi_filter *from )
+{
+ struct slapi_filter *f;
+ if (into == NULL || from == NULL) return;
+ if (*into != NULL) {
+ for (f = from; f->f_next != NULL; f = f->f_next);
+ f->f_next = *into;
+ }
+ *into = from;
+}
+#endif
+
+
+struct slapi_filter *
+slapi_filter_join( int ftype, struct slapi_filter *f1, struct slapi_filter *f2)
+{
+ return slapi_filter_join_ex( ftype, f1, f2, 1 );
+
+}
+
+
+struct slapi_filter *
+slapi_filter_join_ex( int ftype, struct slapi_filter *f1, struct slapi_filter *f2, int recurse_always )
+{
+ struct slapi_filter *fjoin;
+ struct slapi_filter *add_to;
+ struct slapi_filter *add_this;
+ struct slapi_filter *return_this;
+ int insert = 0;
+
+ if(!recurse_always)
+ {
+ /* try to optimise the filter join */
+ switch(ftype)
+ {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ if(ftype == (int)f1->f_choice)
+ {
+ add_to = f1;
+ add_this = f2;
+ insert = 1;
+ }
+ else if(ftype == (int)f2->f_choice)
+ {
+ add_to = f2;
+ add_this = f1;
+ insert = 1;
+ }
+
+ default:
+ break;
+ }
+ }
+
+ if(insert)
+ {
+ /* try to avoid ! filters as the first arg */
+ if(add_to->f_list->f_choice == LDAP_FILTER_NOT)
+ {
+ add_this->f_next = add_to->f_list;
+ add_to->f_list = add_this;
+ filter_compute_hash(add_to);
+ return_this = add_to;
+ }
+ else
+ {
+ /* find end of list, add the filter */
+ for (fjoin = add_to->f_list; fjoin != NULL; fjoin = fjoin->f_next) {
+ if(fjoin->f_next == NULL)
+ {
+ fjoin->f_next = add_this;
+ filter_compute_hash(add_to);
+ return_this = add_to;
+ break;
+ }
+ }
+ }
+ }
+ else
+ {
+ fjoin = (struct slapi_filter *) slapi_ch_calloc( 1, sizeof(struct slapi_filter) );
+ fjoin->f_choice = ftype;
+ fjoin->f_next = NULL;
+ /* try to ensure ! filters dont cause allid search */
+ if(f1->f_choice == LDAP_FILTER_NOT && f2)
+ {
+ fjoin->f_list = f2;
+ f2->f_next = f1;
+ }
+ else
+ {
+ fjoin->f_list = f1;
+ f1->f_next = f2;
+ }
+ filter_compute_hash(fjoin);
+ return_this = fjoin;
+ }
+
+ return( return_this );
+}
+
+int
+slapi_filter_get_choice( struct slapi_filter *f )
+{
+ return( f->f_choice );
+}
+
+int
+slapi_filter_get_ava( struct slapi_filter *f, char **type, struct berval **bval )
+{
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ break;
+ default:
+ *type = NULL;
+ *bval = NULL;
+ return( -1 );
+ }
+ *type = f->f_avtype;
+ *bval = &f->f_avvalue;
+ return( 0 );
+}
+
+/* Deprecated--use slapi_filter_get_attribute_type() now */
+
+SLAPI_DEPRECATED int
+slapi_filter_get_type( struct slapi_filter *f, char **type )
+{
+ if ( f->f_choice != LDAP_FILTER_PRESENT ) {
+ return( -1 );
+ }
+ *type = f->f_type;
+
+ return( 0 );
+}
+
+/*
+ * Return the attribute type for all simple filter choices into type.
+ * ie. for all except LDAP_FILTER_AND, LDAP_FILTER_OR and LDAP_FILTER_NOT.
+ *
+ * The returned type is "as is" and so may not be normalized.
+ * Returns 0 for success, -1 otherwise.
+*/
+
+int
+slapi_filter_get_attribute_type( Slapi_Filter *f, char **type )
+{
+
+ if ( f == NULL ) {
+ return -1;
+ }
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ case LDAP_FILTER_EQUALITY:
+ *type = f->f_ava.ava_type;
+ break;
+ case LDAP_FILTER_SUBSTRINGS:
+ *type = f->f_sub_type;
+ break;
+ case LDAP_FILTER_PRESENT:
+ *type = f->f_type;
+ break;
+ case LDAP_FILTER_EXTENDED:
+ *type = f->f_mr_type;
+ break;
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ return(-1);
+ default:
+ /* Unknown filter choice */
+ return -1;
+ }
+
+ /* success */
+ return(0);
+}
+
+struct slapi_filter *
+slapi_filter_list_first( struct slapi_filter *f )
+{
+ if ( f->f_choice != LDAP_FILTER_AND && f->f_choice != LDAP_FILTER_OR
+ && f->f_choice != LDAP_FILTER_NOT ) {
+ return( NULL );
+ }
+ return( f->f_list );
+}
+
+struct slapi_filter *
+slapi_filter_list_next( struct slapi_filter *f, struct slapi_filter *fprev )
+{
+ return( fprev->f_next );
+}
+
+int
+slapi_filter_get_subfilt(
+ struct slapi_filter *f,
+ char **type,
+ char **initial,
+ char ***any,
+ char **final
+)
+{
+ if ( f->f_choice != LDAP_FILTER_SUBSTRINGS ) {
+ return( -1 );
+ }
+ *type = f->f_sub_type;
+ *initial = f->f_sub_initial;
+ *any = f->f_sub_any;
+ *final = f->f_sub_final;
+
+ return( 0 );
+}
+
+static void
+filter_normalize_ava( struct ava *ava, int ftype )
+{
+ char *tmp;
+
+ if ( ava == NULL ) {
+ return;
+ }
+ tmp = ava->ava_type;
+ ava->ava_type = slapi_attr_syntax_normalize(tmp);
+ slapi_ch_free((void**)&tmp );
+ /* value will be normalized later */
+}
+
+
+void filter_normalize( struct slapi_filter *f );
+
+static void
+filter_normalize_list( struct slapi_filter *flist )
+{
+ struct slapi_filter *f;
+
+ for ( f = flist; f != NULL; f = f->f_next ) {
+ filter_normalize( f );
+ }
+}
+
+
+
+/*
+ * Normalize all values and types in a filter. This isn't necessary
+ * when we've read the slapi_filter off the wire, but if we've hand-constructed
+ * a filter inside slapd (e.g. when calling the routines in wrapper.c),
+ * we've called slapi_str2filter on something which *didn't* come over the wire,
+ * so the attribute names and filters in the filter struct aren't
+ * normalized.
+ */
+void
+filter_normalize( struct slapi_filter *f )
+{
+ char *tmp;
+
+ if ( f == NULL ) {
+ return;
+ }
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ case LDAP_FILTER_EQUALITY:
+ filter_normalize_ava( &f->f_ava, f->f_choice );
+ break;
+ case LDAP_FILTER_SUBSTRINGS:
+ tmp = f->f_sub_type;
+ f->f_sub_type = slapi_attr_syntax_normalize(tmp);
+ slapi_ch_free((void**)&tmp );
+ /* value will be normalized later */
+ break;
+ case LDAP_FILTER_PRESENT:
+ tmp = f->f_type;
+ f->f_type = slapi_attr_syntax_normalize(tmp);
+ slapi_ch_free((void**)&tmp );
+ break;
+ case LDAP_FILTER_EXTENDED:
+ tmp = f->f_mr_type;
+ f->f_mr_type = slapi_attr_syntax_normalize(tmp);
+ slapi_ch_free((void**)&tmp );
+ break;
+ case LDAP_FILTER_AND:
+ filter_normalize_list( f->f_and );
+ break;
+ case LDAP_FILTER_OR:
+ filter_normalize_list( f->f_or );
+ break;
+ case LDAP_FILTER_NOT:
+ filter_normalize_list( f->f_not );
+ break;
+ default:
+ return;
+ }
+}
+
+void
+filter_print( struct slapi_filter *f )
+{
+ int i;
+ struct slapi_filter *p;
+
+ if ( f == NULL ) {
+ printf( "NULL" );
+ return;
+ }
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ printf( "(%s=%s)", f->f_ava.ava_type,
+ f->f_ava.ava_value.bv_val );
+ break;
+
+ case LDAP_FILTER_GE:
+ printf( "(%s>=%s)", f->f_ava.ava_type,
+ f->f_ava.ava_value.bv_val );
+ break;
+
+ case LDAP_FILTER_LE:
+ printf( "(%s<=%s)", f->f_ava.ava_type,
+ f->f_ava.ava_value.bv_val );
+ break;
+
+ case LDAP_FILTER_APPROX:
+ printf( "(%s~=%s)", f->f_ava.ava_type,
+ f->f_ava.ava_value.bv_val );
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ printf( "(%s=", f->f_sub_type );
+ if ( f->f_sub_initial != NULL ) {
+ printf( "%s", f->f_sub_initial );
+ }
+ if ( f->f_sub_any != NULL ) {
+ for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
+ printf( "*%s", f->f_sub_any[i] );
+ }
+ }
+ if ( f->f_sub_final != NULL ) {
+ printf( "*%s", f->f_sub_final );
+ }
+ printf( ")" );
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ printf( "(%s=*)", f->f_type );
+ break;
+
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ printf( "(%c", f->f_choice == LDAP_FILTER_AND ? '&' :
+ f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
+ for ( p = f->f_list; p != NULL; p = p->f_next ) {
+ filter_print( p );
+ }
+ printf( ")" );
+ break;
+
+ default:
+ printf( "unknown type 0x%lX", f->f_choice );
+ break;
+ }
+ fflush( stdout );
+}
+
+/* filter_to_string
+ * ----------------
+ * translates the supplied filter to
+ * the string representation and places
+ * the result in buf
+ *
+ * NOTE: intended for debug purposes, buffer must be
+ * large enough to contain filter string
+ */
+
+char *
+slapi_filter_to_string_internal( const struct slapi_filter *f, char *buf, size_t *bufsize )
+{
+ int i;
+ char *return_buf = buf;
+ struct slapi_filter *p;
+ size_t size;
+ char *operator = ""; /* for comparison operators */
+
+ if(buf == NULL)
+ return 0;
+ else
+ *buf = 0; /* make sure buf is null terminated */
+
+ if ( f == NULL ) {
+ sprintf( buf, "NULL" );
+ return 0;
+ }
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ operator = "=";
+ break;
+
+ case LDAP_FILTER_GE:
+ operator = ">=";
+ break;
+
+ case LDAP_FILTER_LE:
+ operator = "<=";
+ break;
+
+ case LDAP_FILTER_APPROX:
+ operator = "~=";
+ break;
+
+ default: break;
+ }
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ /* +3 -> 1 for (, 1 for ), and one for the trailing null */
+ size = strlen(f->f_ava.ava_type) + f->f_ava.ava_value.bv_len + strlen(operator) + 3;
+
+ if(size < *bufsize)
+ {
+ /* bv_val may not be null terminated, so use the max field width
+ specifier .* with the bv_len as the length to avoid reading
+ past bv_len in bv_val */
+ sprintf( buf, "(%s%s%.*s)", f->f_ava.ava_type, operator,
+ f->f_ava.ava_value.bv_len,
+ f->f_ava.ava_value.bv_val );
+ *bufsize -= size;
+ }
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ size = strlen(f->f_sub_type) + 2;
+
+ if(size < *bufsize)
+ {
+ sprintf( buf, "(%s=", f->f_sub_type );
+ *bufsize -= size;
+
+ if ( f->f_sub_initial != NULL ) {
+ size = strlen(f->f_sub_initial);
+
+ if(size < *bufsize)
+ {
+ buf += strlen(buf);
+ sprintf( buf, "%s", f->f_sub_initial );
+ *bufsize -= size;
+ }
+ }
+ if ( f->f_sub_any != NULL ) {
+ for ( i = 0; f->f_sub_any[i] != NULL; i++ ) {
+ size = strlen(f->f_sub_any[i]) + 1;
+
+ if(size < *bufsize)
+ {
+ buf += strlen(buf);
+ sprintf( buf, "*%s", f->f_sub_any[i] );
+ *bufsize -= size;
+ }
+ }
+ }
+ if ( f->f_sub_final != NULL ) {
+ size = strlen(f->f_sub_final) + 1;
+
+ if(size < *bufsize)
+ {
+ buf += strlen(buf);
+ sprintf( buf, "*%s", f->f_sub_final );
+ *bufsize -= size;
+ }
+ }
+ buf += strlen(buf);
+
+ if(1 < *bufsize)
+ {
+ sprintf( buf, ")" );
+ *bufsize--;
+ }
+ }
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ size = strlen(f->f_type) + 4;
+
+ if(size < *bufsize)
+ {
+ sprintf( buf, "(%s=*)", f->f_type );
+ *bufsize -= size;
+ }
+ break;
+
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ if(2 < *bufsize)
+ {
+ sprintf( buf, "(%c", f->f_choice == LDAP_FILTER_AND ? '&' :
+ f->f_choice == LDAP_FILTER_OR ? '|' : '!' );
+ *bufsize -= 2;
+
+ for ( p = f->f_list; p != NULL; p = p->f_next ) {
+ buf += strlen(buf);
+ slapi_filter_to_string_internal( p, buf, bufsize );
+ }
+ buf += strlen(buf);
+
+ if(1 < *bufsize)
+ {
+ sprintf( buf, ")" );
+ *bufsize--;
+ }
+ }
+ break;
+
+ default:
+ size = 25;
+
+ if(size < *bufsize)
+ {
+ sprintf( buf, "unsupported type 0x%lX", f->f_choice );
+ *bufsize -= 25;
+ }
+ break;
+ }
+
+ return return_buf;
+}
+
+char *
+slapi_filter_to_string( const struct slapi_filter *f, char *buf, size_t bufsize )
+{
+ size_t size = bufsize;
+
+ return slapi_filter_to_string_internal( f, buf, &size );
+}
+
+/* rbyrne */
+
+static int
+filter_apply_list( struct slapi_filter *flist, FILTER_APPLY_FN fn, caddr_t arg,
+ int *error_code )
+{
+ struct slapi_filter *f;
+ int rc;
+
+ for ( f = flist; f != NULL; f = f->f_next ) {
+ rc = slapi_filter_apply( f, fn, arg, error_code );
+ if ( rc == SLAPI_FILTER_SCAN_STOP || rc == SLAPI_FILTER_SCAN_ERROR) {
+ return(rc);
+ }
+ }
+
+ /* If we get here we've applied the whole list sucessfully so return 0 */
+
+ return(SLAPI_FILTER_SCAN_NOMORE);
+}
+
+/*
+ *
+ * The idea here is to apply, fn() to each "simple filter" in f as follows:
+ * fn( Slapi_Filter *simple_filter, caddr_t arg).
+ *
+ * A 'simple filter' is anything other than AND, OR or NOT.
+ *
+ * If fn() wants the seasrch to abort it returns FILTER_SCAN_STOP.
+ * In this case, FILTER_SCAN_STOP is returned by slapi_filter_apply().
+ * Otherwise fn() should return FILTER_SCAN_CONTINUE.
+ *
+ * If the whole filter is traversed, FILTER_SCAN_NO_MORE is returned.
+ * If an error occurred during the traverse, the scan is aborted and
+ * FILTER_SCAN_ERROR is returned, and in this case error_code can be checked
+ * for more details--right now the only error is
+ * SLAPI_FILTER_UNKNOWN_FILTER_TYPE.
+ *
+ *
+ */
+int
+slapi_filter_apply( struct slapi_filter *f, FILTER_APPLY_FN fn, void *arg,
+ int *error_code)
+{
+ int rc = SLAPI_FILTER_SCAN_ERROR;
+
+ if ( f == NULL ) {
+ return SLAPI_FILTER_SCAN_NOMORE;
+ }
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ case LDAP_FILTER_EQUALITY:
+ rc = (*fn)(f, arg );
+ break;
+ case LDAP_FILTER_SUBSTRINGS:
+ rc = (*fn)(f, arg);
+ /* value will be normalized later */
+ break;
+ case LDAP_FILTER_PRESENT:
+ rc = (*fn)(f, arg);
+ break;
+ case LDAP_FILTER_EXTENDED:
+ rc = (*fn)(f, arg);
+ break;
+ case LDAP_FILTER_AND:
+ rc = filter_apply_list( f->f_and, fn, arg, error_code );
+ break;
+ case LDAP_FILTER_OR:
+ rc = filter_apply_list( f->f_or, fn, arg, error_code );
+ break;
+ case LDAP_FILTER_NOT:
+ rc = filter_apply_list( f->f_not, fn, arg, error_code );
+ break;
+ default:
+ /* Unknown filter choice */
+ *error_code = SLAPI_FILTER_UNKNOWN_FILTER_TYPE;
+ rc = SLAPI_FILTER_SCAN_ERROR;
+ }
+
+ /*
+ * We propagate back FILTER_SCAN_ERROR and
+ * FILTER_SCAN_STOP, anything else is success.
+ */
+
+ if (rc != SLAPI_FILTER_SCAN_ERROR && rc != SLAPI_FILTER_SCAN_STOP) {
+ rc = SLAPI_FILTER_SCAN_NOMORE;
+ }
+
+ return(rc);
+}
+
+
+int
+filter_flag_is_set(const Slapi_Filter *f, unsigned char flag) {
+ return(f->f_flags & flag);
+}
+
+
+static int
+tombstone_check_filter(Slapi_Filter *f)
+{
+ if ( 0 == strcasecmp ( f->f_avvalue.bv_val, SLAPI_ATTR_VALUE_TOMBSTONE)) {
+ return 1; /* Contains a nsTombstone filter */
+ }
+ return 0; /* Not nsTombstone filter */
+}
+
+/* filter_optimize
+ * ---------------
+ * takes a filter and optimizes it for fast evaluation
+ * currently this merely ensures that any AND or OR
+ * does not start with a NOT sub-filter if possible
+ */
+static void
+filter_optimize(Slapi_Filter *f)
+{
+ if(!f)
+ return;
+
+ switch(f->f_choice)
+ {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ {
+ /* first optimize children */
+ filter_optimize(f->f_list);
+
+ /* optimize this */
+ if(f->f_list->f_choice == LDAP_FILTER_NOT)
+ {
+ Slapi_Filter *f_prev = 0;
+ Slapi_Filter *f_child = 0;
+
+ /* grab a non not filter to place at start */
+ for(f_child = f->f_list; f_child != 0; f_child = f_child->f_next)
+ {
+ if(f_child->f_choice != LDAP_FILTER_NOT)
+ {
+ /* we have a winner, do swap */
+ f_prev->f_next = f_child->f_next;
+ f_child->f_next = f->f_list;
+ f->f_list = f_child;
+ break;
+ }
+
+ f_prev = f_child;
+ }
+ }
+ }
+ default:
+ filter_optimize(f->f_next);
+ break;
+ }
+}
+
+
+/* slapi_filter_changetype
+ * ------------------------
+ * changes the type used in equality/>/</approx filters
+ * handy for features that do type mapping
+ */
+int slapi_filter_changetype(Slapi_Filter *f, const char *newtype)
+{
+ char **target = 0;
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ target = &f->f_ava.ava_type;
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ target = &f->f_sub_type;
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ target = &f->f_type;
+ break;
+
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ default:
+ goto bail;
+ break;
+ }
+
+ slapi_ch_free_string(target);
+ *target = slapi_ch_strdup(newtype);
+
+bail:
+ return (!target);
+}
+
diff --git a/ldap/servers/slapd/filter.h b/ldap/servers/slapd/filter.h
new file mode 100644
index 00000000..93b02ca5
--- /dev/null
+++ b/ldap/servers/slapd/filter.h
@@ -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 **/
+
+#ifndef _FILTER_H_
+#define _FILTER_H_
+
+#include "slapi-plugin.h" /* struct berval, Slapi_PBlock, mrFilterMatchFn */
+
+typedef Slapi_Attr* attr_ptr;
+
+typedef int (*mrf_plugin_fn) (Slapi_PBlock*);
+
+#define MRF_ANY_TYPE 1
+#define MRF_ANY_VALUE 2
+
+typedef struct mr_filter_t {
+ char* mrf_oid;
+ char* mrf_type;
+ struct berval mrf_value;
+ char mrf_dnAttrs;
+ struct slapdplugin* mrf_plugin;
+ mrFilterMatchFn mrf_match;
+ mrf_plugin_fn mrf_index;
+ unsigned int mrf_reusable; /* MRF_ANY_xxx */
+ mrf_plugin_fn mrf_reset;
+ void* mrf_object; /* whatever the implementation needs */
+ mrf_plugin_fn mrf_destroy;
+} mr_filter_t;
+
+#endif
diff --git a/ldap/servers/slapd/filtercmp.c b/ldap/servers/slapd/filtercmp.c
new file mode 100644
index 00000000..4275df94
--- /dev/null
+++ b/ldap/servers/slapd/filtercmp.c
@@ -0,0 +1,402 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* filtercmp.c - routines for comparing filters */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "slap.h"
+
+
+/* very simple hash function */
+static PRUint32 addhash(PRUint32 hash, unsigned char *data, int size)
+{
+ int i;
+
+ if (!data || !size)
+ return hash;
+ for (i = 0; i < size; i++)
+ hash = (hash << 5) + (hash >> 27) + data[i];
+ return hash;
+}
+#define addhash_long(h, l) addhash((h), (unsigned char *)&(l), sizeof(long))
+#define addhash_str(h, str) addhash((h), (unsigned char *)(str), strlen(str))
+#define addhash_bv(h, bv) addhash((h), (unsigned char *)(bv).bv_val, \
+ (bv).bv_len)
+
+static PRUint32 addhash_casestr(PRUint32 hash, char *data)
+{
+ unsigned char *normstr;
+
+ normstr = slapi_utf8StrToLower((unsigned char *)data);
+ hash = addhash(hash, normstr, strlen((char *)normstr));
+ if ((char *)normstr != data)
+ slapi_ch_free((void **)&normstr);
+ return hash;
+}
+
+static PRUint32 stir(PRUint32 hash, PRUint32 x)
+{
+ hash = (hash << 5) + (hash >> 27);
+ hash = hash ^ (x << 16);
+ hash = hash ^ (x >> 16);
+ return hash;
+}
+#define STIR(h) (h) = stir((h), 0x2EC6DEAD);
+
+static Slapi_Value **get_normalized_value(struct ava *ava)
+{
+ void *plugin;
+ Slapi_Value *svlist[2], **keylist, sv;
+
+ slapi_attr_type2plugin(ava->ava_type, &plugin);
+ sv.bv = ava->ava_value;
+ sv.v_csnset = NULL;
+ svlist[0] = &sv;
+ svlist[1] = NULL;
+ if ((slapi_call_syntax_values2keys_sv(plugin, svlist, &keylist,
+ LDAP_FILTER_EQUALITY) != 0) ||
+ !keylist || !keylist[0])
+ return NULL;
+ return keylist;
+}
+
+/* this is not pretty. matching rules seem to be pretty elaborate to use,
+ * so comparing these kind of filters may be undesirably slow just because
+ * of the overhead of normalizing the values. most of this code is stolen
+ * from the backend vlv code (matchrule.c)
+ */
+static Slapi_PBlock *get_mr_normval(char *oid, char *type,
+ struct berval **inval,
+ struct berval ***outval)
+{
+ Slapi_PBlock *pb = slapi_pblock_new();
+ unsigned int sort_indicator = SLAPI_PLUGIN_MR_USAGE_SORT;
+ IFP mrIndex = NULL;
+
+ if (!pb)
+ return NULL;
+ slapi_pblock_set(pb, SLAPI_PLUGIN_MR_OID, oid);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_MR_TYPE, type);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_MR_USAGE, (void *)&sort_indicator);
+ if (slapi_mr_indexer_create(pb) != 0) {
+ slapi_pblock_destroy(pb);
+ return NULL;
+ }
+ if ((slapi_pblock_get(pb, SLAPI_PLUGIN_MR_INDEX_FN, &mrIndex) != 0) ||
+ !mrIndex) {
+ /* shouldn't ever happen */
+ slapi_pblock_destroy(pb);
+ return NULL;
+ }
+
+ /* now, call the indexer */
+ slapi_pblock_set(pb, SLAPI_PLUGIN_MR_VALUES, inval);
+ (*mrIndex)(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_MR_KEYS, outval);
+ return pb;
+}
+
+/* the opposite of above: shut down the matching rule pblock and free
+ * the memory.
+ */
+static void done_mr_normval(Slapi_PBlock *pb)
+{
+ IFP mrDestroy = NULL;
+
+ if (slapi_pblock_get(pb, SLAPI_PLUGIN_DESTROY_FN, &mrDestroy) == 0) {
+ if (mrDestroy)
+ (*mrDestroy)(pb);
+ }
+ slapi_pblock_destroy(pb);
+}
+
+static int hash_filters = 0;
+
+void set_hash_filters(int i) { hash_filters = i; }
+
+/* calculate the hash value of a node in a filter (assumes that any sub-nodes
+ * of the filter have already had their hash value calculated).
+ * -- the annoying part of this is normalizing any values in the filter.
+ */
+void filter_compute_hash(struct slapi_filter *f)
+{
+ PRUint32 h;
+ char **a;
+ struct slapi_filter *fx;
+ Slapi_Value **keylist;
+ Slapi_PBlock *pb;
+ struct berval *inval[2], **outval;
+
+ if (! hash_filters)
+ return;
+
+ h = addhash_long(0, f->f_choice);
+ switch (f->f_choice) {
+ case LDAP_FILTER_EQUALITY:
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ keylist = get_normalized_value(&f->f_ava);
+ if (keylist) {
+ h = addhash_str(h, f->f_avtype);
+ STIR(h);
+ h = addhash_bv(h, *(slapi_value_get_berval(keylist[0])));
+ valuearray_free(&keylist);
+ }
+ break;
+ case LDAP_FILTER_SUBSTRINGS:
+ h = addhash_str(h, f->f_sub_type);
+ STIR(h);
+ if (f->f_sub_initial)
+ h = addhash_casestr(h, f->f_sub_initial);
+ if (f->f_sub_any) {
+ for (a = f->f_sub_any; *a; a++) {
+ STIR(h);
+ h = addhash_casestr(h, *a);
+ }
+ }
+ STIR(h);
+ if (f->f_sub_final)
+ h = addhash_casestr(h, f->f_sub_final);
+ break;
+ case LDAP_FILTER_PRESENT:
+ h = addhash_str(h, f->f_type);
+ break;
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ /* should be able to just mix in the hashes from lower levels */
+ for (fx = f->f_list; fx; fx = fx->f_next)
+ h = h ^ fx->f_hash;
+ break;
+ case LDAP_FILTER_EXTENDED:
+ if (f->f_mr_oid)
+ h = addhash_str(h, f->f_mr_oid);
+ STIR(h);
+ if (f->f_mr_type)
+ h = addhash_str(h, f->f_mr_type);
+ inval[0] = &f->f_mr_value;
+ inval[1] = NULL;
+ /* get the normalized value (according to the matching rule) */
+ pb = get_mr_normval(f->f_mr_oid, f->f_mr_type, inval, &outval);
+ if (pb && outval && outval[0]) {
+ STIR(h);
+ h = addhash_bv(h, *(outval[0]));
+ }
+ done_mr_normval(pb);
+ if (f->f_mr_dnAttrs)
+ STIR(h);
+ break;
+ default:
+ LDAPDebug(LDAP_DEBUG_ANY, "$$$ can't handle filter type %d !\n",
+ f->f_choice, 0, 0);
+ }
+
+ f->f_hash = h;
+}
+
+
+/* match compare: given two arrays of size N, determine if each item in
+ * the first array matches with each item in the second array, with a
+ * one-to-one correspondence. this will be DOG SLOW for large values of N
+ * (it scales as N^2) but we generally expect N < 5.
+ */
+static int filter_compare_substrings(struct slapi_filter *f1,
+ struct slapi_filter *f2)
+{
+ int buf[20], *tally;
+ char **a1, **a2;
+ int count1 = 0, count2 = 0, ret, i, j, ok;
+
+ /* ok to pass NULL to utf8casecmp */
+
+ if ((slapi_UTF8CASECMP(f1->f_sub_initial, f2->f_sub_initial) != 0) ||
+ (slapi_UTF8CASECMP(f1->f_sub_final, f2->f_sub_final) != 0))
+ return 1;
+ /* match compare (would be expensive for large numbers of 'any'
+ * substrings, which we don't expect to see)
+ */
+ for (a1 = f1->f_sub_any; a1 && *a1; a1++, count1++);
+ for (a2 = f2->f_sub_any; a2 && *a2; a2++, count2++);
+ if (count1 != count2)
+ return 1;
+ ret = 1; /* assume failure until done comparing */
+ if (count1 > 20)
+ tally = (int *)malloc(count1);
+ else
+ tally = buf;
+ if (!tally)
+ goto done; /* this is bad; out of memory */
+ for (i = 0; i < count1; i++)
+ tally[i] = 0;
+ /* ok. the theory is we tally up all the matched pairs we find,
+ * stopping if we can't find a match that hasn't already been paired.
+ */
+ a1 = f1->f_sub_any;
+ for (i = 0; i < count1; i++, a1++) {
+ a2 = f2->f_sub_any;
+ ok = 0;
+ for (j = 0; j < count1; j++, a2++) {
+ if (!tally[j] && (slapi_UTF8CASECMP(*a1, *a2) == 0)) {
+ tally[j] = ok = 1;
+ break;
+ }
+ }
+ if (!ok)
+ goto done; /* didn't find a match for that one */
+ }
+ /* done! matched */
+ ret = 0;
+
+done:
+ if ((count1 > 20) && tally)
+ free(tally);
+ return ret;
+}
+
+/* same as above, but this time for lists of filter nodes */
+static int filter_compare_lists(struct slapi_filter *f1,
+ struct slapi_filter *f2)
+{
+ int buf[20], *tally;
+ struct slapi_filter *fx1, *fx2;
+ int count1 = 0, count2 = 0, ret, i, j, ok;
+
+ for (fx1 = f1->f_list; fx1; fx1 = fx1->f_next, count1++);
+ for (fx2 = f2->f_list; fx2; fx2 = fx2->f_next, count2++);
+ if (count1 != count2)
+ return 1;
+ ret = 1;
+ if (count1 > 20)
+ tally = (int *)malloc(count1);
+ else
+ tally = buf;
+ if (!tally)
+ goto done; /* very bad */
+ for (i = 0; i < count1; i++)
+ tally[i] = 0;
+ /* brute-force match compare now */
+ fx1 = f1->f_list;
+ for (i = 0; i < count1; i++, fx1 = fx1->f_next) {
+ fx2 = f2->f_list;
+ ok = 0;
+ for (j = 0; j < count1; j++, fx2 = fx2->f_next) {
+ if (!tally[j] && (slapi_filter_compare(fx1, fx2) == 0)) {
+ tally[j] = ok = 1;
+ break;
+ }
+ }
+ if (!ok)
+ goto done; /* no match */
+ }
+ /* done! all matched */
+ ret = 0;
+
+done:
+ if ((count1 > 20) && tally)
+ free(tally);
+ return ret;
+}
+
+/* returns 0 if two filters are "identical"
+ * (items under AND/OR are allowed to be in different order)
+ */
+int slapi_filter_compare(struct slapi_filter *f1, struct slapi_filter *f2)
+{
+ Slapi_Value **key1, **key2;
+ Slapi_PBlock *pb1, *pb2;
+ struct berval *inval1[2], *inval2[2], **outval1, **outval2;
+ int ret;
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "=> filter compare\n", 0, 0, 0);
+
+ /* allow for the possibility that one of the filters hasn't had a hash
+ * computed (and is therefore 0). this means that a filter node whose
+ * hash is computed as 0 will always get compared the expensive way,
+ * but this should happen VERY rarely (if ever).
+ */
+ if ((f1->f_hash != f2->f_hash) && (f1->f_hash) && (f2->f_hash)) {
+ ret = 1;
+ goto done;
+ }
+
+ /* brute-force comparison now */
+ if (f1->f_choice != f2->f_choice) {
+ ret = 1;
+ goto done;
+ }
+ switch (f1->f_choice) {
+ case LDAP_FILTER_EQUALITY:
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ case LDAP_FILTER_APPROX:
+ if (slapi_UTF8CASECMP(f1->f_avtype, f2->f_avtype) != 0) {
+ ret = 1;
+ break;
+ }
+ key1 = get_normalized_value(&f1->f_ava);
+ if (key1) {
+ key2 = get_normalized_value(&f2->f_ava);
+ if (key2) {
+ ret = memcmp(slapi_value_get_string(key1[0]),
+ slapi_value_get_string(key2[0]),
+ slapi_value_get_length(key1[0]));
+ valuearray_free(&key1);
+ valuearray_free(&key2);
+ break;
+ }
+ valuearray_free(&key1);
+ }
+ ret = 1;
+ break;
+ case LDAP_FILTER_PRESENT:
+ ret = (slapi_UTF8CASECMP(f1->f_type, f2->f_type));
+ break;
+ case LDAP_FILTER_SUBSTRINGS:
+ ret = filter_compare_substrings(f1, f2);
+ break;
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ ret = filter_compare_lists(f1, f2);
+ break;
+ case LDAP_FILTER_EXTENDED:
+ if ((slapi_UTF8CASECMP(f1->f_mr_oid, f2->f_mr_oid) != 0) ||
+ (slapi_UTF8CASECMP(f1->f_mr_type, f2->f_mr_type) != 0) ||
+ (f1->f_mr_dnAttrs != f2->f_mr_dnAttrs)) {
+ ret = 1;
+ break;
+ }
+ /* painstakingly compare the values (using the matching rule) */
+ inval1[0] = &f1->f_mr_value;
+ inval2[0] = &f2->f_mr_value;
+ inval1[1] = inval2[1] = NULL;
+ pb1 = get_mr_normval(f1->f_mr_oid, f1->f_mr_type, inval1, &outval1);
+ pb2 = get_mr_normval(f2->f_mr_oid, f2->f_mr_type, inval2, &outval2);
+ if (!pb1 || !pb2 || !outval1 || !outval2 || !outval1[0] ||
+ !outval2[0] || (outval1[0]->bv_len != outval2[0]->bv_len) ||
+ (memcmp(outval1[0]->bv_val, outval2[0]->bv_val,
+ outval1[0]->bv_len) != 0)) {
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+ if (pb1)
+ done_mr_normval(pb1);
+ if (pb2)
+ done_mr_normval(pb2);
+ break;
+ default:
+ LDAPDebug(LDAP_DEBUG_ANY, "ERR can't handle filter %d\n", f1->f_choice,
+ 0, 0);
+ ret = 1;
+ }
+
+done:
+ LDAPDebug(LDAP_DEBUG_TRACE, "<= filter compare: %d\n", ret, 0, 0);
+ return ret;
+}
diff --git a/ldap/servers/slapd/filterentry.c b/ldap/servers/slapd/filterentry.c
new file mode 100644
index 00000000..6c6bc4b4
--- /dev/null
+++ b/ldap/servers/slapd/filterentry.c
@@ -0,0 +1,1000 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* filterentry.c - apply a filter to an entry */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+
+static int test_filter_list();
+static int test_extensible_filter();
+
+static int vattr_test_filter_list();
+static int test_filter_access( Slapi_PBlock *pb, Slapi_Entry*e,
+ char * attr_type, struct berval *attr_val);
+static int slapi_vattr_filter_test_ext_internal( Slapi_PBlock *pb, Slapi_Entry *e,
+ struct slapi_filter *f, int verify_access, int only_check_access, int *access_check_done);
+
+static char *opt_str = 0;
+static int opt = 0;
+
+static int optimise_filter_acl_tests()
+{
+ if(!opt_str)
+ {
+ opt_str = getenv( "NS_DS_OPT_FILT_ACL_EVAL" );
+ if(opt_str)
+ opt = !strcasecmp(opt_str, "false");
+ else
+ opt = 0;
+ if(!opt_str)
+ opt_str = "dummy";
+ }
+
+ return opt;
+}
+
+/*
+ * slapi_filter_test - test a filter against a single entry.
+ * returns 0 filter matched
+ * -1 filter did not match
+ * >0 an ldap error code
+ */
+
+int
+slapi_filter_test(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct slapi_filter *f,
+ int verify_access
+)
+{
+ return slapi_filter_test_ext(pb,e,f,verify_access,0);
+}
+
+/*
+ * slapi_filter_test_simple - test without checking access control
+ *
+ * returns 0 filter matched
+ * -1 filter did not match
+ * >0 an ldap error code
+ */
+int
+slapi_filter_test_simple(
+ Slapi_Entry *e,
+ struct slapi_filter *f
+)
+{
+ return slapi_vattr_filter_test_ext(NULL,e,f,0,0);
+}
+
+/*
+ * slapi_filter_test_ext - full-feature filter test function
+ *
+ * returns 0 filter matched
+ * -1 filter did not match
+ * >0 an ldap error code
+ */
+
+int
+slapi_filter_test_ext_internal(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct slapi_filter *f,
+ int verify_access,
+ int only_check_access,
+ int *access_check_done
+)
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> slapi_filter_test_ext\n", 0, 0, 0 );
+
+ /*
+ * RJP: Not sure if this is semantically right, but we have to
+ * return something if f is NULL. If there is no filter,
+ * then we say that it did match and return 0.
+ */
+ if ( f == NULL) {
+ return(0);
+ }
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ LDAPDebug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 );
+ rc = test_ava_filter( pb, e, e->e_attrs, &f->f_ava, LDAP_FILTER_EQUALITY,
+ verify_access , only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ LDAPDebug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 );
+ rc = test_substring_filter( pb, e, f, verify_access , only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_GE:
+ LDAPDebug( LDAP_DEBUG_FILTER, " GE\n", 0, 0, 0 );
+ rc = test_ava_filter( pb, e, e->e_attrs, &f->f_ava, LDAP_FILTER_GE,
+ verify_access , only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_LE:
+ LDAPDebug( LDAP_DEBUG_FILTER, " LE\n", 0, 0, 0 );
+ rc = test_ava_filter( pb, e, e->e_attrs, &f->f_ava, LDAP_FILTER_LE,
+ verify_access , only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ LDAPDebug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 );
+ rc = test_presence_filter( pb, e, f->f_type, verify_access , only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_APPROX:
+ LDAPDebug( LDAP_DEBUG_FILTER, " APPROX\n", 0, 0, 0 );
+ rc = test_ava_filter( pb, e, e->e_attrs, &f->f_ava, LDAP_FILTER_APPROX,
+ verify_access , only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_EXTENDED:
+ LDAPDebug( LDAP_DEBUG_FILTER, " EXTENDED\n", 0, 0, 0 );
+ rc = test_extensible_filter( pb, e, &f->f_mr, verify_access , only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_AND:
+ LDAPDebug( LDAP_DEBUG_FILTER, " AND\n", 0, 0, 0 );
+ rc = test_filter_list( pb, e, f->f_and,
+ LDAP_FILTER_AND , verify_access, only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_OR:
+ LDAPDebug( LDAP_DEBUG_FILTER, " OR\n", 0, 0, 0 );
+ rc = test_filter_list( pb, e, f->f_or,
+ LDAP_FILTER_OR , verify_access, only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_NOT:
+ LDAPDebug( LDAP_DEBUG_FILTER, " NOT\n", 0, 0, 0 );
+ rc = slapi_filter_test_ext_internal( pb, e, f->f_not , verify_access, only_check_access, access_check_done);
+ if(!(verify_access && only_check_access)) /* dont play with access control return codes */
+ {
+ if(verify_access && !rc && !(*access_check_done))
+ {
+ /* the filter failed so access control was not checked
+ * for NOT filters this is significant so we must ensure
+ * access control is checked
+ */
+ /* check access control only */
+ rc = slapi_filter_test_ext_internal( pb, e, f->f_not , verify_access, -1 /*only_check_access*/, access_check_done);
+ /* preserve error code if any */
+ if(!rc)
+ rc = !rc;
+ }
+ else
+ rc = !rc;
+ }
+
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY, " unknown filter type 0x%lX\n",
+ f->f_choice, 0, 0 );
+ rc = -1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= slapi_filter_test %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+int
+slapi_filter_test_ext(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct slapi_filter *f,
+ int verify_access,
+ int only_check_access
+)
+{
+ int rc = 0; /* a no op request succeeds */
+ int access_check_done = 0;
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ /*
+ * optimize acl checking by only doing it once it is
+ * known that the whole filter passes and so the entry
+ * is eligible to be returned.
+ * then we check the filter only for access
+ *
+ * complex filters really benefit from
+ * separate stages, filter eval, followed by acl check...
+ */
+ if(!only_check_access)
+ {
+ rc = slapi_filter_test_ext_internal(pb,e,f,0,0, &access_check_done);
+ }
+
+ if(rc == 0 && verify_access)
+ {
+ rc = slapi_filter_test_ext_internal(pb,e,f,-1,-1, &access_check_done);
+ }
+
+ break;
+
+ default:
+ /*
+ * ...but simple filters are better off doing eval and
+ * acl check at once
+ */
+ rc = slapi_filter_test_ext_internal(pb,e,f,verify_access,only_check_access, &access_check_done);
+ break;
+ }
+
+ return rc;
+}
+
+
+int test_ava_filter(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ Slapi_Attr *a,
+ struct ava *ava,
+ int ftype,
+ int verify_access,
+ int only_check_access,
+ int *access_check_done
+)
+{
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> test_ava_filter\n", 0, 0, 0 );
+
+ *access_check_done = 0;
+
+ if(optimise_filter_acl_tests())
+ {
+ rc = 0;
+
+ if(!only_check_access)
+ {
+ rc = -1;
+ for ( ; a != NULL; a = a->a_next ) {
+ if ( slapi_attr_type_cmp( ava->ava_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
+ rc = plugin_call_syntax_filter_ava( a, ftype, ava );
+ if ( rc == 0 ) {
+ break;
+ }
+ }
+ }
+ }
+
+ if ( rc == 0 && verify_access && pb != NULL ) {
+ char *attrs[2] = { NULL, NULL };
+ attrs[0] = ava->ava_type;
+ rc = plugin_call_acl_plugin( pb, e, attrs, &ava->ava_value,
+ SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
+ *access_check_done = -1;
+ }
+
+ }
+ else
+ {
+ if ( verify_access && pb != NULL ) {
+ char *attrs[2] = { NULL, NULL };
+ attrs[0] = ava->ava_type;
+ rc = plugin_call_acl_plugin( pb, e, attrs, &ava->ava_value,
+ SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
+ *access_check_done = -1;
+ if ( only_check_access || rc != LDAP_SUCCESS ) {
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= test_ava_filter %d\n",
+ rc, 0, 0 );
+ return( rc );
+ }
+ }
+
+ rc = -1;
+ for ( ; a != NULL; a = a->a_next ) {
+ if ( slapi_attr_type_cmp( ava->ava_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
+ rc = plugin_call_syntax_filter_ava( a, ftype, ava );
+ if ( rc == 0 ) {
+ break;
+ }
+ }
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= test_ava_filter %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+int
+test_presence_filter(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ char *type,
+ int verify_access,
+ int only_check_access,
+ int *access_check_done
+)
+{
+ int rc;
+ void *hint = NULL;
+
+ *access_check_done = 0;
+
+ if(optimise_filter_acl_tests())
+ {
+ rc = 0;
+ /* Use attrlist_find_ex to get subtype matching */
+ if(!only_check_access)
+ {
+ rc = attrlist_find_ex( e->e_attrs, type,
+ NULL, NULL, &hint ) != NULL ? 0 : -1;
+ }
+
+ if (rc == 0 && verify_access && pb != NULL) {
+ char *attrs[2] = { NULL, NULL };
+ attrs[0] = type;
+ rc = plugin_call_acl_plugin( pb, e, attrs, NULL, SLAPI_ACL_SEARCH,
+ ACLPLUGIN_ACCESS_DEFAULT, NULL );
+ *access_check_done = -1;
+ }
+ }
+ else
+ {
+ if (verify_access && pb != NULL) {
+ char *attrs[2] = { NULL, NULL };
+ attrs[0] = type;
+ rc = plugin_call_acl_plugin( pb, e, attrs, NULL, SLAPI_ACL_SEARCH,
+ ACLPLUGIN_ACCESS_DEFAULT, NULL );
+ *access_check_done = -1;
+ if ( only_check_access || rc != LDAP_SUCCESS ) {
+ return( rc );
+ }
+ }
+
+ /* Use attrlist_find_ex to get subtype matching */
+ rc = attrlist_find_ex( e->e_attrs, type,
+ NULL, NULL, &hint ) != NULL ? 0 : -1;
+ }
+
+ return rc;
+}
+
+/*
+ * Convert a DN into a list of attribute values.
+ * The caller must free the returned attributes.
+ */
+static Slapi_Attr*
+dn2attrs(const char *dn)
+{
+ int rc= 0;
+ Slapi_Attr* dnAttrs = NULL;
+ char** rdns = ldap_explode_dn (dn, 0);
+ if (rdns)
+ {
+ char** rdn = rdns;
+ for (; !rc && *rdn; ++rdn)
+ {
+ char** avas = ldap_explode_rdn (*rdn, 0);
+ if (avas)
+ {
+ char** ava = avas;
+ for (; !rc && *ava; ++ava)
+ {
+ char* val = strchr (*ava, '=');
+ if (val)
+ {
+ struct berval bv;
+ struct berval* bvec[] = {NULL, NULL};
+ size_t type_len = val - *ava;
+ char* type = slapi_ch_malloc (type_len + 1);
+ memcpy (type, *ava, type_len);
+ type[type_len] = '\0';
+ ++val; /* skip the '=' */
+ bv.bv_val = val;
+ bv.bv_len = strlen(val);
+ bvec[0] = &bv;
+ attrlist_merge (&dnAttrs, type, bvec);
+ }
+ }
+ ldap_value_free (avas);
+ }
+ }
+ ldap_value_free (rdns);
+ }
+ return dnAttrs;
+}
+
+static int
+test_extensible_filter(
+ Slapi_PBlock *callers_pb,
+ Slapi_Entry *e,
+ mr_filter_t *mrf,
+ int verify_access,
+ int only_check_access,
+ int *access_check_done
+)
+{
+ /*
+ * The ABNF for extensible filters is
+ *
+ * attr [":dn"] [":" matchingrule] ":=" value
+ * [":dn"] ":" matchingrule ":=" value
+ *
+ * So, sigh, there are six possible combinations:
+ *
+ * A) attr ":=" value
+ * B) attr ":dn" ":=" value
+ * C) attr ":" matchingrule ":=" value
+ * D) attr ":dn" ":" matchingrule ":=" value
+ * E) ":" matchingrule ":=" value
+ * F) ":dn" ":" matchingrule ":=" value
+ */
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> test_extensible_filter\n", 0, 0, 0 );
+
+ *access_check_done = 0;
+
+ if(optimise_filter_acl_tests())
+ {
+ rc = LDAP_SUCCESS;
+
+ if(!only_check_access)
+ {
+ if (mrf->mrf_match==NULL)
+ {
+ /*
+ * Could be A or B
+ * No matching function. So use a regular equality filter.
+ * Check the regular attributes for the attribute value.
+ */
+ struct ava a;
+ a.ava_type= mrf->mrf_type;
+ a.ava_value.bv_len= mrf->mrf_value.bv_len;
+ a.ava_value.bv_val = mrf->mrf_value.bv_val;
+ rc= test_ava_filter( callers_pb, e, e->e_attrs, &a, LDAP_FILTER_EQUALITY, 0 /* Don't Verify Access */ , 0 /* don't just verify access */, access_check_done );
+ if(rc!=LDAP_SUCCESS && mrf->mrf_dnAttrs)
+ {
+ /* B) Also check the DN attributes for the attribute value */
+ Slapi_Attr* dnattrs= dn2attrs(slapi_entry_get_dn_const(e));
+ rc= test_ava_filter( callers_pb, e, dnattrs, &a, LDAP_FILTER_EQUALITY, 0 /* Don't Verify Access */ , 0 /* don't just verify access */, access_check_done );
+ slapi_attr_free( &dnattrs );
+ }
+ }
+ else
+ {
+ /*
+ * Could be C, D, E, or F
+ * We have a matching rule.
+ */
+ rc = mrf->mrf_match (mrf->mrf_object, e, e->e_attrs);
+ if(rc!=LDAP_SUCCESS && mrf->mrf_dnAttrs)
+ {
+ /* D & F) Also check the DN attributes for the attribute value */
+ Slapi_Attr* dnattrs= dn2attrs(slapi_entry_get_dn_const(e));
+ mrf->mrf_match (mrf->mrf_object, e, dnattrs);
+ slapi_attr_free( &dnattrs );
+ }
+ }
+ }
+
+ if(rc == 0 && mrf->mrf_type!=NULL && verify_access)
+ {
+ char *attrs[2] = { NULL, NULL };
+ /* Could be A, B, C, or D */
+ /* Check we have access to this attribute on this entry */
+ attrs[0] = mrf->mrf_type;
+ rc= plugin_call_acl_plugin (callers_pb, e, attrs, &(mrf->mrf_value),
+ SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
+ *access_check_done = -1;
+ }
+ }
+ else
+ {
+ rc = LDAP_SUCCESS;
+
+ if(mrf->mrf_type!=NULL && verify_access)
+ {
+ char *attrs[2] = { NULL, NULL };
+ /* Could be A, B, C, or D */
+ /* Check we have access to this attribute on this entry */
+ attrs[0] = mrf->mrf_type;
+ rc= plugin_call_acl_plugin (callers_pb, e, attrs, &(mrf->mrf_value),
+ SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
+ *access_check_done = -1;
+
+ if ( only_check_access ) {
+ return rc;
+ }
+ }
+ if(rc==LDAP_SUCCESS)
+ {
+ if (mrf->mrf_match==NULL)
+ {
+ /*
+ * Could be A or B
+ * No matching function. So use a regular equality filter.
+ * Check the regular attributes for the attribute value.
+ */
+ struct ava a;
+ a.ava_type= mrf->mrf_type;
+ a.ava_value.bv_len= mrf->mrf_value.bv_len;
+ a.ava_value.bv_val = mrf->mrf_value.bv_val;
+ rc= test_ava_filter( callers_pb, e, e->e_attrs, &a, LDAP_FILTER_EQUALITY, 0 /* Don't Verify Access */ , 0 /* don't just verify access */, access_check_done );
+ if(rc!=LDAP_SUCCESS && mrf->mrf_dnAttrs)
+ {
+ /* B) Also check the DN attributes for the attribute value */
+ Slapi_Attr* dnattrs= dn2attrs(slapi_entry_get_dn_const(e));
+ rc= test_ava_filter( callers_pb, e, dnattrs, &a, LDAP_FILTER_EQUALITY, 0 /* Don't Verify Access */ , 0 /* don't just verify access */, access_check_done );
+ slapi_attr_free( &dnattrs );
+ }
+ }
+ else
+ {
+ /*
+ * Could be C, D, E, or F
+ * We have a matching rule.
+ */
+ rc = mrf->mrf_match (mrf->mrf_object, e, e->e_attrs);
+ if(rc!=LDAP_SUCCESS && mrf->mrf_dnAttrs)
+ {
+ /* D & F) Also check the DN attributes for the attribute value */
+ Slapi_Attr* dnattrs= dn2attrs(slapi_entry_get_dn_const(e));
+ mrf->mrf_match (mrf->mrf_object, e, dnattrs);
+ slapi_attr_free( &dnattrs );
+ }
+ }
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= test_extensible_filter %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+
+static int
+test_filter_list(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct slapi_filter *flist,
+ int ftype,
+ int verify_access,
+ int only_check_access,
+ int *access_check_done
+)
+{
+ int nomatch;
+ struct slapi_filter *f;
+ int access_check_tmp = -1;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> test_filter_list\n", 0, 0, 0 );
+
+ *access_check_done = -1;
+
+ nomatch = 1;
+ for ( f = flist; f != NULL; f = f->f_next ) {
+ if ( slapi_filter_test_ext_internal( pb, e, f, verify_access, only_check_access, &access_check_tmp ) != 0 ) {
+ /* optimize AND evaluation */
+ if ( ftype == LDAP_FILTER_AND ) {
+ /* one false is failure */
+ nomatch = 1;
+ break;
+ }
+ } else {
+ nomatch = 0;
+
+ /* optimize OR evaluation too */
+ if ( ftype == LDAP_FILTER_OR ) {
+ /* only one needs to be true */
+ break;
+ }
+ }
+
+ if(!access_check_tmp)
+ *access_check_done = 0;
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= test_filter_list %d\n", nomatch, 0, 0 );
+ return( nomatch );
+}
+
+void
+filter_strcpy_special( char *d, char *s )
+{
+ for ( ; *s; s++ ) {
+ switch ( *s ) {
+ case '.':
+ case '\\':
+ case '[':
+ case ']':
+ case '*':
+ case '+':
+ case '^':
+ case '$':
+ *d++ = '\\';
+ /* FALL */
+ default:
+ *d++ = *s;
+ }
+ }
+ *d = '\0';
+}
+
+int test_substring_filter(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct slapi_filter *f,
+ int verify_access,
+ int only_check_access,
+ int *access_check_done
+)
+{
+ Slapi_Attr *a;
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> test_substring_filter\n", 0, 0, 0 );
+
+ *access_check_done = 0;
+
+ if(optimise_filter_acl_tests())
+ {
+ rc = 0;
+
+ if(!only_check_access)
+ {
+ rc = -1;
+ for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+ if ( slapi_attr_type_cmp( f->f_sub_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
+ rc = plugin_call_syntax_filter_sub( a, &f->f_sub );
+ if ( rc == 0 ) {
+ break;
+ }
+ }
+ }
+ }
+
+ if ( rc == 0 && verify_access && pb != NULL) {
+ char *attrs[2] = { NULL, NULL };
+ attrs[0] = f->f_sub_type;
+ rc = plugin_call_acl_plugin( pb, e, attrs, NULL,
+ SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
+ *access_check_done = -1;
+ }
+ }
+ else
+ {
+ if ( verify_access && pb != NULL) {
+ char *attrs[2] = { NULL, NULL };
+ attrs[0] = f->f_sub_type;
+ rc = plugin_call_acl_plugin( pb, e, attrs, NULL,
+ SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
+ *access_check_done = -1;
+ if ( only_check_access || rc != LDAP_SUCCESS ) {
+ return( rc );
+ }
+ }
+
+
+ rc = -1;
+ for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+ if ( slapi_attr_type_cmp( f->f_sub_type, a->a_type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
+ rc = plugin_call_syntax_filter_sub( a, &f->f_sub );
+ if ( rc == 0 ) {
+ break;
+ }
+ }
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= test_substring_filter %d\n",
+ rc, 0, 0 );
+ return( rc );
+}
+
+/*
+ * Here's a duplicate vattr filter test code modified to support vattrs.
+*/
+
+/*
+ * slapi_vattr_filter_test - test a filter against a single entry.
+ *
+ * Supports the case where the filter mentions virtual attributes.
+ * Performance for a real attr only filter is same as for slapi_filter_test()
+ * No explicit support for vattrs in extended filters because:
+ * 1. the matching rules must support virtual attributes themselves.
+ * 2. if no matching rule is specified it defaults to equality so
+ * could just use a normal filter with equality.
+ * 3. virtual naming attributes are probably too complex to support.
+ *
+ * returns 0 filter matched
+ * -1 filter did not match
+ * >0 an ldap error code
+ */
+
+int
+slapi_vattr_filter_test(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct slapi_filter *f,
+ int verify_access
+)
+{
+ return slapi_vattr_filter_test_ext(pb,e,f,verify_access,0);
+}
+
+/*
+ * vattr_filter_test_ext - full-feature filter test function
+ *
+ * returns 0 filter matched
+ * -1 filter did not match
+ * >0 an ldap error code
+ */
+int
+slapi_vattr_filter_test_ext(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct slapi_filter *f,
+ int verify_access,
+ int only_check_access
+)
+{
+ int rc = 0; /* a no op request succeeds */
+ int access_check_done = 0;
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ /*
+ * optimize acl checking by only doing it once it is
+ * known that the whole filter passes and so the entry
+ * is eligible to be returned.
+ * then we check the filter only for access
+ *
+ * complex filters really benefit from
+ * separate stages, filter eval, followed by acl check...
+ */
+ if(!only_check_access)
+ {
+ rc = slapi_vattr_filter_test_ext_internal(pb,e,f,0,0, &access_check_done);
+ }
+
+ if(rc == 0 && verify_access)
+ {
+ rc = slapi_vattr_filter_test_ext_internal(pb,e,f,-1,-1, &access_check_done);
+ }
+
+ break;
+
+ default:
+ /*
+ * ...but simple filters are better off doing eval and
+ * acl check at once
+ */
+ rc = slapi_vattr_filter_test_ext_internal(pb,e,f,verify_access,only_check_access, &access_check_done);
+ break;
+ }
+
+ return rc;
+}
+
+static int
+slapi_vattr_filter_test_ext_internal(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct slapi_filter *f,
+ int verify_access,
+ int only_check_access,
+ int *access_check_done
+)
+{
+ int rc = LDAP_SUCCESS;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> slapi_vattr_filter_test_ext\n", 0, 0, 0 );
+
+ /*
+ * RJP: Not sure if this is semantically right, but we have to
+ * return something if f is NULL. If there is no filter,
+ * then we say that it did match and return 0.
+ */
+ if ( f == NULL) {
+ return(0);
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> test_substring_filter\n", 0, 0, 0 );
+
+ switch ( f->f_choice ) {
+ case LDAP_FILTER_EQUALITY:
+ LDAPDebug( LDAP_DEBUG_FILTER, " EQUALITY\n", 0, 0, 0 );
+ if ( verify_access ) {
+ rc = test_filter_access( pb, e, f->f_ava.ava_type,
+ &f->f_ava.ava_value);
+ *access_check_done = 1;
+ }
+ if ( only_check_access || rc != LDAP_SUCCESS ) {
+ return( rc );
+ }
+ rc = vattr_test_filter( e, f, FILTER_TYPE_AVA, f->f_ava.ava_type );
+ break;
+
+ case LDAP_FILTER_SUBSTRINGS:
+ LDAPDebug( LDAP_DEBUG_FILTER, " SUBSTRINGS\n", 0, 0, 0 );
+ if ( verify_access ) {
+ rc = test_filter_access( pb, e, f->f_sub_type, NULL);
+ *access_check_done = 1;
+ }
+ if ( only_check_access || rc != LDAP_SUCCESS ) {
+ return( rc );
+ }
+ rc = vattr_test_filter( e, f, FILTER_TYPE_SUBSTRING, f->f_sub_type);
+ break;
+
+ case LDAP_FILTER_GE:
+ LDAPDebug( LDAP_DEBUG_FILTER, " GE\n", 0, 0, 0 );
+ if ( verify_access ) {
+ rc = test_filter_access( pb, e, f->f_ava.ava_type,
+ &f->f_ava.ava_value);
+ *access_check_done = 1;
+ }
+ if ( only_check_access || rc != LDAP_SUCCESS ) {
+ return( rc );
+ }
+ rc = vattr_test_filter( e, f, FILTER_TYPE_AVA, f->f_ava.ava_type);
+ break;
+
+ case LDAP_FILTER_LE:
+ LDAPDebug( LDAP_DEBUG_FILTER, " LE\n", 0, 0, 0 );
+ if ( verify_access ) {
+ rc = test_filter_access( pb, e, f->f_ava.ava_type,
+ &f->f_ava.ava_value);
+ *access_check_done = 1;
+ }
+ if ( only_check_access || rc != LDAP_SUCCESS ) {
+ return( rc );
+ }
+ rc = vattr_test_filter( e, f, FILTER_TYPE_AVA, f->f_ava.ava_type);
+ break;
+
+ case LDAP_FILTER_PRESENT:
+ LDAPDebug( LDAP_DEBUG_FILTER, " PRESENT\n", 0, 0, 0 );
+ if ( verify_access ) {
+ rc = test_filter_access( pb, e, f->f_type, NULL);
+ *access_check_done = 1;
+ }
+ if ( only_check_access || rc != LDAP_SUCCESS ) {
+ return( rc );
+ }
+ rc = vattr_test_filter( e, f, FILTER_TYPE_PRES, f->f_type);
+ break;
+
+ case LDAP_FILTER_APPROX:
+ LDAPDebug( LDAP_DEBUG_FILTER, " APPROX\n", 0, 0, 0 );
+ if ( verify_access ) {
+ rc = test_filter_access( pb, e, f->f_ava.ava_type,
+ &f->f_ava.ava_value);
+ *access_check_done = 1;
+ }
+ if ( only_check_access || rc != LDAP_SUCCESS ) {
+ return( rc );
+ }
+ rc = vattr_test_filter( e, f, FILTER_TYPE_AVA, f->f_ava.ava_type);
+ break;
+
+ case LDAP_FILTER_EXTENDED:
+ LDAPDebug( LDAP_DEBUG_FILTER, " EXTENDED\n", 0, 0, 0 );
+ rc = test_extensible_filter( pb, e, &f->f_mr, verify_access ,
+ only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_AND:
+ LDAPDebug( LDAP_DEBUG_FILTER, " AND\n", 0, 0, 0 );
+ rc = vattr_test_filter_list( pb, e, f->f_and,
+ LDAP_FILTER_AND , verify_access, only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_OR:
+ LDAPDebug( LDAP_DEBUG_FILTER, " OR\n", 0, 0, 0 );
+ rc = vattr_test_filter_list( pb, e, f->f_or,
+ LDAP_FILTER_OR , verify_access, only_check_access, access_check_done);
+ break;
+
+ case LDAP_FILTER_NOT:
+ LDAPDebug( LDAP_DEBUG_FILTER, " NOT\n", 0, 0, 0 );
+ rc = slapi_vattr_filter_test_ext_internal( pb, e, f->f_not , verify_access, only_check_access, access_check_done);
+ if(!(verify_access && only_check_access)) /* dont play with access control return codes */
+ {
+ if(verify_access && !rc && !(*access_check_done))
+ {
+ /* the filter failed so access control was not checked
+ * for NOT filters this is significant so we must ensure
+ * access control is checked
+ */
+ /* check access control only */
+ rc = slapi_vattr_filter_test_ext_internal( pb, e, f->f_not , verify_access, -1 /*only_check_access*/, access_check_done);
+ /* preserve error code if any */
+ if(!rc)
+ rc = !rc;
+ }
+ else
+ rc = !rc;
+ }
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY, " unknown filter type 0x%lX\n",
+ f->f_choice, 0, 0 );
+ rc = -1;
+ }
+
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= slapi_vattr_filter_test %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+static int test_filter_access( Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ char *attr_type,
+ struct berval *attr_val) {
+ /*
+ * attr_type--attr_type to test for.
+ * attr_val--attr value to test for
+ */
+ int rc;
+ char *attrs[2] = { NULL, NULL };
+ attrs[0] = attr_type;
+
+ rc = plugin_call_acl_plugin( pb, e, attrs, attr_val,
+ SLAPI_ACL_SEARCH, ACLPLUGIN_ACCESS_DEFAULT, NULL );
+
+ return(rc);
+}
+
+static int
+vattr_test_filter_list(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct slapi_filter *flist,
+ int ftype,
+ int verify_access,
+ int only_check_access,
+ int *access_check_done
+)
+{
+ int nomatch;
+ struct slapi_filter *f;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> vattr_test_filter_list\n", 0, 0, 0 );
+
+ nomatch = 1;
+ for ( f = flist; f != NULL; f = f->f_next ) {
+ if ( slapi_vattr_filter_test_ext_internal( pb, e, f, verify_access, only_check_access, access_check_done ) != 0 ) {
+ /* optimize AND evaluation */
+ if ( ftype == LDAP_FILTER_AND ) {
+ /* one false is failure */
+ nomatch = 1;
+ break;
+ }
+ } else {
+ nomatch = 0;
+
+ /* optimize OR evaluation too */
+ if ( ftype == LDAP_FILTER_OR ) {
+ /* only one needs to be true */
+ break;
+ }
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= test_filter_list %d\n", nomatch, 0, 0 );
+ return( nomatch );
+}
diff --git a/ldap/servers/slapd/generation.c b/ldap/servers/slapd/generation.c
new file mode 100644
index 00000000..24988493
--- /dev/null
+++ b/ldap/servers/slapd/generation.c
@@ -0,0 +1,140 @@
+/** 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 <time.h>
+
+#include "rwlock.h"
+#include "slap.h"
+
+/*
+ * Create a new data version string.
+ */
+static const char *
+new_dataversion()
+{
+ struct tm t;
+ char* dataversion;
+ time_t curtime= current_time();
+#ifdef _WIN32
+ memcpy (&t, gmtime (&curtime), sizeof(t));
+#else
+ gmtime_r (&curtime, &t);
+#endif
+ dataversion = slapi_ch_malloc(16);
+ sprintf (dataversion, "0%.4li%.2i%.2i%.2i%.2i%.2i", 1900L + t.tm_year, 1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+ return dataversion;
+}
+
+/* ---------------- Database Data Version ---------------- */
+
+/*
+ * Return the generation ID for the database whose mapping tree node is "dn"
+ */
+char *
+get_database_dataversion(const char *dn)
+{
+ char *dataversion= NULL;
+ int r;
+ Slapi_PBlock *resultpb= NULL;
+ Slapi_Entry** entry = NULL;
+ resultpb= slapi_search_internal( dn, LDAP_SCOPE_BASE, "objectclass=*", NULL, NULL, 1);
+ slapi_pblock_get( resultpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry );
+ slapi_pblock_get( resultpb, SLAPI_PLUGIN_INTOP_RESULT, &r );
+ if(r==LDAP_SUCCESS && entry!=NULL && entry[0]!=NULL)
+ {
+ dataversion= slapi_entry_attr_get_charptr( entry[0], "nsslapd-dataversion"); /* JCMREPL - Shouldn't be a Netscape specific attribute name */
+ }
+ slapi_free_search_results_internal(resultpb);
+ slapi_pblock_destroy(resultpb);
+ return dataversion;
+}
+
+void
+set_database_dataversion(const char *dn, const char *dataversion)
+{
+ LDAPMod gen_mod;
+ LDAPMod *mods[2];
+ struct berval* gen_vals[2];
+ struct berval gen_val;
+ Slapi_PBlock *pb;
+
+ memset (&gen_mod, 0, sizeof(gen_mod));
+
+ gen_mod.mod_op = LDAP_MOD_REPLACE | LDAP_MOD_BVALUES;
+ gen_mod.mod_type = "nsslapd-dataversion"; /* JCMREPL - Shouldn't be a Netscape specific attribute name */
+ gen_mod.mod_bvalues = gen_vals;
+ gen_vals[0] = &gen_val;
+ gen_vals[1] = NULL;
+ gen_val.bv_val = (char *)dataversion;
+ gen_val.bv_len = strlen (gen_val.bv_val);
+ mods[0] = &gen_mod;
+ mods[1] = NULL;
+
+ pb = slapi_modify_internal (dn, mods, 0, 0 /* !log_change */);
+ if (NULL != pb)
+ {
+ Slapi_Entry *e;
+ slapi_pblock_get (pb, SLAPI_ENTRY_PRE_OP, &e);
+ slapi_entry_free(e);
+ }
+ slapi_pblock_destroy(pb);
+}
+
+/* ---------------- Server Data Version ---------------- */
+
+static char *server_dataversion_id= NULL;
+
+const char *
+get_server_dataversion()
+{
+ lenstr *l = NULL;
+ Slapi_Backend *be;
+ char *cookie;
+
+ /* we already cached the copy - just return it */
+ if(server_dataversion_id!=NULL)
+ {
+ return server_dataversion_id;
+ }
+
+ l= lenstr_new();
+
+ /* Loop over the backends collecting the backend data versions */
+ /* Combine them into a single blob */
+ be = slapi_get_first_backend(&cookie);
+ while ( be )
+ {
+ /* Don't generate dataversion for remote entries */
+ if((!be->be_private) && !(slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
+ {
+ const char * dataversion;
+ Slapi_DN be_configdn;
+ slapi_sdn_init(&be_configdn);
+ (void)be_getconfigdn(be, &be_configdn);
+ dataversion= get_database_dataversion(slapi_sdn_get_ndn(&be_configdn));
+ if(dataversion==NULL)
+ {
+ /* The database either doesn't support the storage of a dataverion, */
+ /* or has just been created, or has been reinitialised */
+ dataversion= new_dataversion();
+ set_database_dataversion(slapi_sdn_get_ndn(&be_configdn), dataversion);
+ }
+ addlenstr(l, dataversion);
+ slapi_ch_free((void**)&dataversion);
+ slapi_sdn_done(&be_configdn);
+ }
+
+ be = slapi_get_next_backend(cookie);
+ }
+ slapi_ch_free ((void **)&cookie);
+ if(l->ls_buf!=NULL)
+ {
+ server_dataversion_id= slapi_ch_strdup(l->ls_buf);
+ }
+ lenstr_free(&l);
+ return server_dataversion_id;
+}
diff --git a/ldap/servers/slapd/getfilelist.c b/ldap/servers/slapd/getfilelist.c
new file mode 100644
index 00000000..f24ed85a
--- /dev/null
+++ b/ldap/servers/slapd/getfilelist.c
@@ -0,0 +1,233 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/***********************************************************************
+** NAME
+** getfilelist.c
+**
+** DESCRIPTION
+**
+**
+** AUTHOR
+** Rich Megginson <richm@netscape.com>
+**
+***********************************************************************/
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+
+#include "prio.h"
+#include "slap.h"
+#include "avl.h"
+#if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX )
+#include "regex.h"
+#endif
+
+struct data_wrapper {
+ char **list;
+ int n;
+ int max;
+ const char *dirname;
+};
+
+static int
+add_file_to_list(caddr_t data, caddr_t arg)
+{
+ struct data_wrapper *dw = (struct data_wrapper *)arg;
+ if (dw) {
+ size_t size;
+ /* max is number of entries; the range of n is 0 - max-1 */
+ PR_ASSERT(dw->n <= dw->max);
+ PR_ASSERT(dw->list);
+ PR_ASSERT(data);
+ /* this strdup is free'd by free_filelist */
+ size = strlen(dw->dirname) + strlen(data) + 5;
+ dw->list[dw->n] = slapi_ch_calloc(size, 1);
+ sprintf(dw->list[dw->n++], "%s/%s", dw->dirname, data);
+ return 0;
+ }
+
+ return -1;
+}
+
+static void
+free_string(caddr_t data)
+{
+ slapi_ch_free((void **)&data);
+}
+
+static int
+file_is_type_x(const char *dirname, const char *filename, PRFileType x)
+{
+ struct PRFileInfo inf;
+ int status = 0;
+ size_t size = strlen(dirname) + strlen(filename) + 2; /* 1 for slash + 1 for null */
+ char *fullpath = slapi_ch_calloc(sizeof(char), size);
+
+ sprintf(fullpath, "%s/%s", dirname, filename);
+ if (PR_SUCCESS == PR_GetFileInfo(fullpath, &inf) &&
+ inf.type == x)
+ status = 1;
+
+ slapi_ch_free((void **)&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 int
+matches(const char *filename, const char *pattern)
+{
+ int match = 0;
+ char *s = 0;
+ if (!pattern)
+ return 1; /* null pattern matches everything */
+
+ slapd_re_lock();
+ s = slapd_re_comp((char *)pattern);
+ if (!s)
+ match = slapd_re_exec((char *)filename);
+ slapd_re_unlock();
+
+ return match;
+}
+
+/**
+ * getfilelist will return a list of all files and directories in the
+ * given directory matching the given pattern. If dirname is NULL, the
+ * current directory "." will be used. If the pattern is NULL, all files
+ * and directories will be returned. The additional integer arguments
+ * control which files and directories are selected. The default value
+ * for all of them is 0, which will not return hidden files (e.g. files
+ * beginning with . on unix), but will return both files and directories
+ * If nofiles is non-zero, only directory names will be returned. If
+ * nodirs is non-zero, only filenames will be returned.
+ * The pattern is a grep style regular expression, not a shell or command
+ * interpreter style regular expression. For example, to get all files ending
+ * in .ldif, use ".*\\.ldif" instead of "*.ldif"
+ * The return value is a NULL terminated array of names.
+ */
+char **
+get_filelist(
+ const char *dirname, /* directory path; if NULL, uses "." */
+ const char *pattern, /* grep (not shell!) file pattern regex */
+ int hiddenfiles, /* if true, return hidden files and directories too */
+ int nofiles, /* if true, do not return files */
+ int nodirs /* if true, do not return directories */
+)
+{
+ Avlnode *filetree = 0;
+ PRDir *dirptr = 0;
+ PRDirEntry *dirent = 0;
+ PRDirFlags dirflags = PR_SKIP_BOTH & PR_SKIP_HIDDEN;
+ char **retval = 0;
+ int num = 0;
+ struct data_wrapper dw;
+
+ if (!dirname)
+ dirname = ".";
+
+ if (hiddenfiles)
+ dirflags = PR_SKIP_BOTH;
+
+ if (!(dirptr = PR_OpenDir(dirname))) {
+ return NULL;
+ }
+
+ /* read the directory entries into an ascii sorted avl tree */
+ for (dirent = PR_ReadDir(dirptr, dirflags); dirent ;
+ dirent = PR_ReadDir(dirptr, dirflags)) {
+
+ if (nofiles && is_a_file(dirname, dirent->name))
+ continue;
+
+ if (nodirs && is_a_dir(dirname, dirent->name))
+ continue;
+
+ if (matches(dirent->name, pattern)) {
+ /* this strdup is free'd by free_string */
+ char *newone = slapi_ch_strdup(dirent->name);
+ avl_insert(&filetree, newone, strcmp, 0);
+ num++;
+ }
+ }
+ PR_CloseDir(dirptr);
+
+ /* allocate space for the list */
+ retval = (char **)slapi_ch_calloc(num+1, sizeof(char *));
+
+ /* traverse the avl tree and copy the filenames into the list */
+ dw.list = retval;
+ dw.n = 0;
+ dw.max = num;
+ dw.dirname = dirname;
+ (void)avl_apply(filetree, add_file_to_list, &dw, -1, AVL_INORDER);
+ retval[num] = 0; /* set last entry to null */
+
+ /* delete the avl tree and all its data */
+ avl_free(filetree, free_string);
+
+ return retval;
+}
+
+
+void
+free_filelist(char **filelist)
+{
+ int ii;
+ for (ii = 0; filelist && filelist[ii]; ++ii)
+ slapi_ch_free((void **)&filelist[ii]);
+
+ slapi_ch_free((void **)&filelist);
+}
+
+/**
+ * Returns a list of files in order of "priority" where priority is defined
+ * as:
+ * The filename must begin with the letter S. The next two characters in
+ * the filename are digits representing a number from 00 to 99. The lower the
+ * number the higher the priority. For example, S00 is in the list before S01,
+ * and S99 is the last item in the list. The ordering of files with the same
+ * priority cannot be guaranteed. The pattern is the grep style regular expression
+ * of filenames to match which is applied to the end of the string.
+ * If you are a Solaris person, you may recognize this as the rules for init level
+ * initialization using shell scripts under /etc/rcX.d/
+ */
+char **
+get_priority_filelist(const char *directory, const char *pattern)
+{
+ char *basepattern = "^[0-9][0-9]";
+ char *genericpattern = ".*"; /* used if pattern is null */
+ char *bigpattern = 0;
+ size_t len = 0;
+ char **retval = 0;
+
+ if (!pattern)
+ pattern = genericpattern;
+
+ len = strlen(basepattern) + strlen(pattern) + 1;
+ bigpattern = slapi_ch_calloc(sizeof(char), len);
+ sprintf(bigpattern, "%s%s", basepattern, pattern);
+
+ retval = get_filelist(directory, bigpattern, 0, 0, 1);
+
+ slapi_ch_free((void **)&bigpattern);
+
+ return retval;
+}
diff --git a/ldap/servers/slapd/getopt_ext.c b/ldap/servers/slapd/getopt_ext.c
new file mode 100644
index 00000000..97d2e6d3
--- /dev/null
+++ b/ldap/servers/slapd/getopt_ext.c
@@ -0,0 +1,236 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "getopt_ext.h"
+
+char *optarg_ext;
+int optind_ext=1;
+int optopt_ext;
+int opterr_ext;
+int optind_last;
+
+static int _getopt_ext_inited = 0;
+static int _optind_firstHandled = 0;
+static int _optind_firstRecognized = 0;
+static int _getopt_ext_done_long = 0;
+
+static
+int _getopt_ext_init(int argc)
+{
+ _getopt_ext_inited = 1;
+ /* optind_ext = 1;*/
+ optind_last = argc;
+ _optind_firstHandled = argc;
+ _optind_firstRecognized = argc;
+ /* optind = 1;*/
+ _getopt_ext_done_long = 0;
+ return(0);
+}
+
+#if 0
+static
+int _getopt_ext_done()
+{
+ _getopt_ext_done_long = 1;
+ return(0);
+}
+#endif
+
+static
+int _getopt_ext_find(int argc,
+ char **argv,
+ const struct opt_ext *longOpts)
+{
+ int i=0;
+ struct opt_ext *lopt;
+
+ i=0;
+ lopt = (struct opt_ext *)longOpts;
+ while(lopt->o_string) {
+ if(0 != strcmp(argv[optind_ext]+2,lopt->o_string)) {
+ i++;
+ lopt++;
+ continue;
+ }
+ /*
+ * found it
+ */
+ return(i);
+ }
+ /* should never come here */
+ return(-1);
+}
+
+static
+int _getopt_ext_tailit(int argc,
+ char **argv,
+ int hasArg,
+ int recognized)
+{
+ char *_optPtr=NULL;
+ char *_optArgPtr=NULL;
+ int _endIndex=optind_last;
+ int _nextDest=optind_ext;
+ int _nextSource=optind_ext;
+
+ _optPtr = argv[optind_ext];
+ if(hasArg) {
+ _nextSource = optind_ext + 2;
+ _endIndex = ((recognized)?_optind_firstRecognized:_optind_firstHandled);
+ _optArgPtr = argv[optind_ext + 1];
+ } else {
+ _nextSource = optind_ext + 1;
+ _endIndex = ((recognized)?_optind_firstRecognized:_optind_firstHandled);
+ _optArgPtr = NULL;
+ }
+
+ while(_nextSource < _endIndex) {
+ argv[_nextDest] = argv[_nextSource];
+ _nextSource++;
+ _nextDest++;
+ }
+
+ argv[_nextDest] = _optPtr;
+ /* argv[_nextDest] = NULL; */
+ if(hasArg) {
+ argv[_nextDest + 1] = _optArgPtr;
+ if(recognized) {
+ _optind_firstRecognized -=2;
+ }
+ _optind_firstHandled -=2;
+ } else {
+ if(recognized) {
+ _optind_firstRecognized -=1;
+ }
+ _optind_firstHandled -=1;
+ }
+ optind_last = _optind_firstRecognized;
+ return(0);
+}
+
+/*
+ * First process all the long options (using exact string matches)
+ * Then, follow up with regular option processing using good ol' getopt
+ *
+ * return the same return codes as getopt
+ *
+ */
+
+int getopt_ext(int argc,
+ char **argv,
+ const char *optstring,
+ const struct opt_ext *longOpts,
+ int *longOptIndex)
+{
+ int retVal;
+
+ if(!_getopt_ext_inited) {
+ _getopt_ext_init(argc);
+ }
+
+ if(_optind_firstHandled < optind_ext) {
+ /* we are not processing extended options anymore...
+ let getopt handle it.
+ */
+ goto _doneWithExtendedOptions;
+ }
+
+ /*
+ * if we are here, we are not done with extended options...
+ *
+ */
+ while(_optind_firstHandled > optind_ext) {
+ if(0 != strncmp(argv[optind_ext], "--", 2)) {
+ optind_ext++;
+ continue;
+ }
+ /*
+ * possibly an extended option
+ */
+ retVal = _getopt_ext_find(argc,argv,longOpts);
+ if(-1 == retVal) {
+ /*
+ * unrecognized long option...
+ * we will let getopt handle it later...
+ *
+ */
+ optind_ext++;
+ continue;
+ }
+ /*
+ * we found an extended option
+ * now find its arg...
+ */
+ switch((longOpts+retVal)->o_type) {
+ case ArgNone:
+ default:
+ {
+ /* send this option to the end of the arglist */
+ _getopt_ext_tailit(argc,argv,0,1);
+ optarg_ext = NULL;
+ *longOptIndex = retVal;
+ return((longOpts+retVal)->o_return);
+ }
+ case ArgRequired:
+ {
+ /*
+ * make sure the next arg is a "valid" argument
+ */
+ if(((optind_ext + 1) == _optind_firstHandled)) {
+ /*
+ * did not find the argument
+ * let getopt handle it
+ * we will just push it to the end and continue
+ * looking for more extended options
+ *
+ * _getopt_ext_tailit(argc,argv,0,0);
+ */
+ optind_ext++;
+ fprintf(stderr, "%s: option requires an argument -- %s\n",
+ argv[0],(longOpts+retVal)->o_string);
+ exit(0);
+ continue;
+ }
+ /* like getopt, we don't care what the arg looks like! */
+ /* send this option to the end of the arglist */
+ _getopt_ext_tailit(argc,argv,1,1);
+ optarg_ext = argv[_optind_firstRecognized + 1];
+ *longOptIndex = retVal;
+ return((longOpts+retVal)->o_return);
+ }
+ case ArgOptional:
+ {
+ if(((optind_ext + 1) == optind_last) ||
+ ('-' == argv[optind_ext + 1][0])){
+ /*
+ * did not find the argument
+ *
+ */
+ _getopt_ext_tailit(argc,argv,0,1);
+ optarg_ext = NULL;
+ *longOptIndex = retVal;
+ return((longOpts+retVal)->o_return);
+ }
+ /* send this option to the end of the arglist */
+ _getopt_ext_tailit(argc,argv,1,1);
+ optarg_ext = argv[optind_last + 1];
+ *longOptIndex = retVal;
+ return((longOpts+retVal)->o_return);
+ }
+ }
+
+ /* optind_ext++;*/
+ }
+
+_doneWithExtendedOptions:
+ retVal = getopt(optind_last,argv,optstring);
+ optarg_ext = optarg;
+ /* optopt_ext = optopt; */
+ optind_last = _optind_firstHandled;
+ return(retVal);
+
+}
+
diff --git a/ldap/servers/slapd/getopt_ext.h b/ldap/servers/slapd/getopt_ext.h
new file mode 100644
index 00000000..aab66728
--- /dev/null
+++ b/ldap/servers/slapd/getopt_ext.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 **/
+/*
+ * getopt_ext.h - long option names
+ *
+ *
+ *
+ */
+
+#ifndef _GETOPT_EXT_H
+#define _GETOPT_EXT_H
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+#if defined( _WIN32 )
+#include <io.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <ldap.h>
+#include "ntslapdmessages.h"
+#include "proto-ntutil.h"
+#endif
+
+#ifdef LINUX
+#include <getopt.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/*
+ * getopt_ext() is a rudimentary extension to getopt() to facilitate
+ * handling of long (wordier) option names.
+ *
+ * A long option is indicated by placing a "--" in front of the option
+ * name.
+ *
+ * Like getopt(), getopt_ext() also returns a single letter (actually an int)
+ * when an option is recognized. Therefore, the loop for processing long
+ * options and single letter options can be combined (see example in
+ * slapd/main.c)
+ *
+ * getopt_ext() first processes all the long options it can find. Currently,
+ * it does a "strcmp" to check for the validity of the option name (i.e.,
+ * the option name has to match exactly).
+ *
+ * Once all the long options are handled, getopt_ext() uses getopt() to
+ * process the remaining options.
+ *
+ * getopt_ext() rearranges "argv" when it finds long options that it
+ * recognizes. The recognized options (and their parameters) are pushed
+ * to the end.
+ *
+ * Single letter options are specified similar to getopt()
+ * Long options are specified using a list of "struct opt_ext". Each long
+ * option consists of string that identifies the option, a type that specifies
+ * if the option requires an argument and the single letter returned by
+ * getopt_ext() when the option is encountered. For example,
+ * {"verbose",ArgNone,'v'} specifies a long option (--verbose) that requires
+ * no arguments and for which, getopt_ext() returns a 'v' as the return value.
+ * {"instancedir",ArgRequired,'D'} specifies a long option (--instancedir dir)
+ * that requires an argument.
+ *
+ *
+ */
+
+
+extern char *optarg_ext;
+extern int optind_ext;
+extern int optopt_ext;
+extern int opterr_ext;
+extern int optind_last;
+
+extern int optind, opterr, optopt;
+extern char *optarg;
+
+typedef enum {
+ ArgNone,
+ ArgRequired,
+ ArgOptional
+} GetOptExtArgType;
+
+struct opt_ext {
+ const char *o_string;
+ const GetOptExtArgType o_type;
+ const char o_return;
+};
+
+int getopt_ext(int argc,
+ char **argv,
+ const char *optstring,
+ const struct opt_ext *longOpts,
+ int *longOptIndex);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
+
+
diff --git a/ldap/servers/slapd/globals.c b/ldap/servers/slapd/globals.c
new file mode 100644
index 00000000..08aae06d
--- /dev/null
+++ b/ldap/servers/slapd/globals.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 **/
+/*
+ * Copyright (c) 1996 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * SLAPD globals.c -- SLAPD library global variables
+ */
+
+#if defined(NET_SSL)
+#include "ldap.h"
+#include <sslproto.h> /* cipher suite names */
+#include <ldap_ssl.h>
+
+#undef OFF
+#undef LITTLE_ENDIAN
+
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#if defined( _WIN32 )
+#include "ntslapdmessages.h"
+#include "proto-ntutil.h"
+#else
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+#include "slap.h"
+#include "fe.h"
+
+/* On UNIX, there's only one copy of slapd_ldap_debug */
+/* On NT, each module keeps its own module_ldap_debug, which */
+/* points to the process' slapd_ldap_debug */
+#ifdef _WIN32
+int *module_ldap_debug;
+#endif
+
+int should_detach = 1;
+time_t starttime;
+PRThread *listener_tid;
+Slapi_PBlock *repl_pb = NULL;
+
+/*
+ * global variables that need mutex protection
+ */
+int active_threads;
+PRInt32 ops_initiated;
+PRInt32 ops_completed;
+PRLock *ops_mutex;
+int num_conns;
+PRLock *num_conns_mutex;
+
+
+/*
+ DEC/COMPAQ has released a patch for 4.0d (e?) which will speed up
+ malloc/free considerably in multithreaded multiprocessor
+ applications (like directory server!), sort of like SmartHeap but
+ not as snazzy. The last three parameters only take effect if the
+ patch is installed, otherwise they are ignored. The rest of the
+ parameters are included along with their default values, but they
+ are commented out except:
+ unsigned long __noshrink = 1; old - default is 0; apparently this is ignored for now
+ int __fast_free_max = INT_MAX; old - default is 13; may cause excessive memory consumption
+*/
+#if defined(OSF1) && defined(LDAP_DONT_USE_SMARTHEAP)
+/* From an email from Dave Long at DEC/Compaq:
+
+ The following is an example of how to tune for maximum speed on a
+ system with three or more CPUs and with no concern for memory used:
+
+ #include <limits.h>
+ #include <sys/types.h>
+*/
+unsigned long __noshrink = 1; /* old - default is 0; apparently this is ignored for now */
+/*
+ size_t __minshrink = 65536;
+ double __minshrinkfactor = 0.001;
+ size_t __mingrow = 65536;
+ double __mingrowfactor = 0.1;
+ unsigned long __madvisor = 0;
+ unsigned long __small_buff = 0;
+*/
+int __fast_free_max = INT_MAX; /* old - default is 13; may cause excessive memory consumption */
+/*
+ unsigned long __sbrk_override = 0;
+ unsigned long __taso_mode = 0;
+*/
+
+/*
+ These are the new parameters
+*/
+int __max_cache = 27;
+int __first_fit = 2;
+int __delayed_free = 1;
+/*
+ Note that the allowed values for the new __max_cache tuning variable
+ are: 15, 18, 21, 24, 27. Any other value is likely to actually harm
+ performance or even cause a core dump.
+*/
+#endif
+
+
+#if defined( _WIN32 )
+/* String constants (no change for international) */
+SERVICE_STATUS LDAPServerStatus;
+SERVICE_STATUS_HANDLE hLDAPServerServiceStatus;
+#endif
+
+Connection_Table *the_connection_table = NULL;
+
+char *pid_file = "/dev/null";
+char *start_pid_file = "/dev/null";
+
+char *attr_dataversion = ATTR_DATAVERSION;
+
+extern void set_dll_entry_points( slapdEntryPoints *sep );
+void
+set_entry_points()
+{
+ slapdEntryPoints *sep;
+
+ sep = (slapdEntryPoints *) slapi_ch_malloc( sizeof( slapdEntryPoints ));
+ sep->sep_ps_wakeup_all = (caddr_t)ps_wakeup_all;
+ sep->sep_ps_service = (caddr_t)ps_service_persistent_searches;
+ sep->sep_disconnect_server = (caddr_t)disconnect_server;
+ sep->sep_slapd_SSL_client_init = (caddr_t)slapd_SSL_client_init;
+ sep->sep_slapd_ssl_init = (caddr_t)slapd_ssl_init;
+ sep->sep_slapd_ssl_init2 = (caddr_t)slapd_ssl_init2;
+ set_dll_entry_points( sep );
+
+}
diff --git a/ldap/servers/slapd/house.c b/ldap/servers/slapd/house.c
new file mode 100644
index 00000000..25cdb435
--- /dev/null
+++ b/ldap/servers/slapd/house.c
@@ -0,0 +1,91 @@
+/** 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 <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "slap.h"
+
+#define SLAPD_HOUSEKEEPING_INTERVAL 30 /* seconds */
+
+static PRThread *housekeeping_tid = NULL;
+static PRLock *housekeeping_mutex = NULL;
+static PRCondVar *housekeeping_cvar = NULL;
+
+
+static void
+housecleaning(void *cur_time)
+{
+ int interval;
+
+ interval = PR_SecondsToInterval( SLAPD_HOUSEKEEPING_INTERVAL );
+ while ( !g_get_shutdown() ) {
+ /*
+ * Looks simple, but could potentially take a long time.
+ */
+ be_flushall();
+
+ log_access_flush();
+
+ if ( g_get_shutdown() ) {
+ break;
+ }
+ PR_Lock( housekeeping_mutex );
+ PR_WaitCondVar( housekeeping_cvar, interval );
+ PR_Unlock( housekeeping_mutex );
+ }
+}
+
+PRThread*
+housekeeping_start(time_t cur_time, void *arg)
+{
+ static time_t thread_start_time;
+
+ if ( housekeeping_tid ) {
+ return housekeeping_tid;
+ }
+
+ if ( ( housekeeping_mutex = PR_NewLock()) == NULL ) {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "housekeeping cannot create new lock. "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ PR_GetError(), slapd_pr_strerror( PR_GetError() ));
+ }
+ else if ( ( housekeeping_cvar = PR_NewCondVar( housekeeping_mutex )) == NULL ) {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "housekeeping cannot create new condition variable. "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ PR_GetError(), slapd_pr_strerror( PR_GetError() ));
+ }
+ else {
+ thread_start_time = cur_time;
+ if ((housekeeping_tid = PR_CreateThread(PR_USER_THREAD,
+ (VFP) housecleaning, (void*)&thread_start_time,
+ PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, PR_JOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE)) == NULL) {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "housekeeping PR_CreateThread failed. "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ PR_GetError(), slapd_pr_strerror( PR_GetError() ));
+ }
+ }
+
+ return housekeeping_tid;
+}
+
+void
+housekeeping_stop()
+{
+ if ( housekeeping_tid ) {
+ PR_Lock( housekeeping_mutex );
+ PR_NotifyCondVar( housekeeping_cvar );
+ PR_Unlock( housekeeping_mutex );
+ (void)PR_JoinThread( housekeeping_tid );
+ }
+}
diff --git a/ldap/servers/slapd/http.h b/ldap/servers/slapd/http.h
new file mode 100644
index 00000000..7c1654a5
--- /dev/null
+++ b/ldap/servers/slapd/http.h
@@ -0,0 +1,43 @@
+/**
+ * PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+ * license terms. Copyright 2001 Sun Microsystems, Inc.
+ * Some preexisting portions Copyright 2001 Netscape Communications Corp.
+ * All rights reserved.
+ */
+
+#ifndef _HTTP_H_
+#define _HTTP_H_
+
+/* mechanics */
+
+
+typedef void (*api_http_init)();
+typedef int (*api_get_http_text)(char *url, char *text_data);
+typedef int (*api_get_http_binary)(char *url, char* bin_data, int *len);
+typedef void (*api_http_shutdown)();
+
+/* API ID for http_apib_get_interface */
+
+#define HTTP_v1_0_GUID "0A340151-6FB3-11d3-80D2-006008A6EFF3"
+
+/* API */
+
+/* the api broker reserves api[0] for its use */
+
+#define http_init() \
+ ((api_http_init*)(api))[1]()
+
+#define get_http_text(url, text_data) \
+ ((api_get_http_text*)(api))[2]( url, text_data)
+
+#define get_http_binary(url, bin_data, len) \
+ ((api_get_http_binary*)(api))[3](url,bin_data, len)
+
+#define set_http_shutdown() \
+ ((api_http_shutdown*)(api))[4]()
+
+/* HTTP to be passed to http_register() by presence sps*/
+#define http_api(api) api[5]
+
+
+#endif /*_HTTP_H_*/
diff --git a/ldap/servers/slapd/index_subsys.h b/ldap/servers/slapd/index_subsys.h
new file mode 100644
index 00000000..190659c5
--- /dev/null
+++ b/ldap/servers/slapd/index_subsys.h
@@ -0,0 +1,47 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2002 Netscape Communications Corporation. All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _INDEX_SUBSYS_H_
+#define _INDEX_SUBSYS_H_
+
+#include "slapi-plugin.h"
+
+typedef void IndexEntryList;
+typedef unsigned int IndexEntryID;
+
+typedef int (*index_search_callback)(Slapi_Filter *filter, IndexEntryList **results, void *user_data );
+typedef int (*index_validate_callback)();
+
+typedef struct __indexed_item
+{
+ /* item that is indexed, an LDAP string filter description of the index
+ * x=* = presence
+ * x=** = equality
+ * x=?* = substrings
+ */
+ char *index_filter; /* item that is indexed, an LDAP string filter description of the index e.g. (presence=*) */
+ index_search_callback search_op; /* search call back */
+ char **associated_attrs; /* null terminated list of filter groupable attributes */
+ Slapi_DN *namespace_dn; /* the namespace this index is valid for */
+} indexed_item;
+
+
+#define INDEX_FILTER_EVALUTED 0
+#define INDEX_FILTER_UNEVALUATED 1
+
+
+/* prototypes */
+
+/* for index plugins */
+int slapi_index_entry_list_create(IndexEntryList **list);
+int slapi_index_entry_list_add(IndexEntryList **list, IndexEntryID id);
+int slapi_index_register_decoder(char *plugin_id, index_validate_callback validate_op);
+int slapi_index_register_index(char *plugin_id, indexed_item *registration_item, void *user_data);
+
+/* for backends */
+int index_subsys_assign_filter_decoders(Slapi_PBlock *pb);
+int index_subsys_filter_decoders_done(Slapi_PBlock *pb);
+int index_subsys_evaluate_filter(Slapi_Filter *f, Slapi_DN *namespace_dn, IndexEntryList **out);
+
+#endif /*_INDEX_SUBSYS_H_*/
diff --git a/ldap/servers/slapd/index_subsystem.c b/ldap/servers/slapd/index_subsystem.c
new file mode 100644
index 00000000..e696860e
--- /dev/null
+++ b/ldap/servers/slapd/index_subsystem.c
@@ -0,0 +1,1286 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2002 Netscape Communications Corporation. All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* The indexing subsystem
+ * ----------------------
+ *
+ * This provides support for indexing plugins and assigning
+ * those plugins to sub-filters of a search filter. Currently
+ * the old indexing code still exists and operates on those
+ * indexes which do not have a plugin assigned. This indexing
+ * abstraction is intended to eventually decouple the index mechanics
+ * from the back-end where that is possible. Hopefully, while
+ * supporting the needs of virtual attribute indexes, it will allow
+ * easier integration of other back ends.
+ *
+ */
+
+/* includes */
+#include "slap.h"
+#include "./back-ldbm/back-ldbm.h"
+#include "./back-ldbm/idlapi.h"
+#include "index_subsys.h"
+
+#define INDEX_IDLIST_INITIAL_SIZE 128 /* make this a good size to avoid constant reallocs */
+
+/* data */
+static void **idl_api;
+
+struct _indexLinkedList
+{
+ void *pNext;
+ void *pPrev;
+};
+typedef struct _indexLinkedList indexLinkedList;
+
+struct _indexEntry
+{
+ indexLinkedList list;
+ char *indexedAttribute;
+ Slapi_Filter *indexfilter;
+ char *indexfilterstr;
+ char **associated_attrs;
+ void *user_data;
+ Slapi_DN *namespace_dn;
+ index_search_callback lookup_func; /* search call back */
+};
+typedef struct _indexEntry indexEntry;
+
+struct _indexPlugin
+{
+ indexLinkedList list;
+ char *id;
+ indexEntry *indexes;
+ index_validate_callback validate_op;
+};
+typedef struct _indexPlugin indexPlugin;
+
+struct _globalIndexCache
+{
+ indexPlugin *pPlugins;
+ indexEntry **ppIndexIndex; /* sorted list with key: indexEntry.indexedAttribute */
+ int index_count;
+ PRRWLock *cache_lock;
+};
+typedef struct _globalIndexCache globalIndexCache;
+
+static globalIndexCache *theCache = 0;
+
+/* prototypes */
+static int index_subsys_decoder_done(Slapi_Filter *f);
+static int index_subsys_assign_decoders(Slapi_Filter *f);
+static int index_subsys_assign_decoder(Slapi_Filter *f);
+static int index_subsys_group_decoders(Slapi_Filter *f);
+static indexEntry *index_subsys_find_decoder(Slapi_Filter *f);
+static int index_subsys_unlink_subfilter(Slapi_Filter *fcomplex, Slapi_Filter *fsub);
+static int index_subsys_index_matches_associated(indexEntry *index, Slapi_Filter *f);
+
+/* matching alg - note : values 0/1/2/3 supported right now*/
+#define INDEX_MATCH_NONE 0
+#define INDEX_MATCH_EQUALITY 1
+#define INDEX_MATCH_PRESENCE 2
+#define INDEX_MATCH_SUBSTRING 3
+#define INDEX_MATCH_COMPLEX 4
+static int index_subsys_index_matches_filter(indexEntry *index, Slapi_Filter *f);
+
+static void index_subsys_read_lock()
+{
+ PR_RWLock_Rlock(theCache->cache_lock);
+}
+
+static void index_subsys_write_lock()
+{
+ PR_RWLock_Wlock(theCache->cache_lock);
+}
+
+static void index_subsys_unlock()
+{
+ PR_RWLock_Unlock(theCache->cache_lock);
+}
+
+int slapi_index_entry_list_create(IndexEntryList **list)
+{
+ if(idl_api)
+ *list = (IndexEntryList*)IDList_alloc(idl_api, INDEX_IDLIST_INITIAL_SIZE);
+ else
+ *list = 0;
+
+ return !(*list);
+}
+
+int slapi_index_entry_list_add(IndexEntryList **list, IndexEntryID id)
+{
+ if(idl_api)
+ IDList_insert(idl_api, (IDList **)list, (ID)id);
+
+ return 0; /* no way to tell failure */
+}
+
+
+static int index_subsys_index_matches_filter(indexEntry *index, Slapi_Filter *f)
+{
+ int ret = INDEX_MATCH_NONE;
+
+ /* simple filters only right now */
+ if(slapi_attr_types_equivalent(index->indexedAttribute, f->f_type))
+ {
+ /* ok we have some type of match, lets find out which */
+
+ switch(index->indexfilter->f_choice)
+ {
+ case LDAP_FILTER_PRESENT:
+ /* present means "x=*" */
+ if(f->f_choice == LDAP_FILTER_PRESENT)
+ ret = INDEX_MATCH_PRESENCE;
+ break;
+ case LDAP_FILTER_SUBSTRINGS:
+ /* our equality filters look like this "x=**"
+ * that means the filter will be assigned
+ * a substring f_choice by the filter code
+ * in str2filter.c
+ * but we need to differentiate so we take
+ * advantage of the fact that this creates a
+ * special substring filter with no substring
+ * to look for...
+ */
+ if( index->indexfilter->f_sub_initial == 0 &&
+ index->indexfilter->f_sub_any == 0 &&
+ index->indexfilter->f_sub_final == 0
+ )
+ {
+ /* this is an index equality filter */
+ if(f->f_choice == LDAP_FILTER_EQUALITY)
+ ret = INDEX_MATCH_EQUALITY;
+ }
+ else
+ {
+ /* this is a regualar substring filter */
+ if(f->f_choice == LDAP_FILTER_SUBSTRINGS)
+ ret = INDEX_MATCH_SUBSTRING;
+ }
+
+ break;
+
+ default:
+ /* we don't know about any other type yet */
+ break;
+ }
+ }
+
+ return ret;
+}
+
+/* index_subsys_assign_filter_decoders
+ * -----------------------------------
+ * assigns index plugins to sub-filters
+ */
+int index_subsys_assign_filter_decoders(Slapi_PBlock *pb)
+{
+ int rc;
+ Slapi_Filter *f;
+ char *subsystem = "index_subsys_assign_filter_decoders";
+ char logbuf[ 1024 ];
+
+ /* extract the filter */
+ slapi_pblock_get(pb, SLAPI_SEARCH_FILTER, &f);
+
+ if ( LDAPDebugLevelIsSet( LDAP_DEBUG_FILTER ) && NULL != f ) {
+ logbuf[0] = '\0';
+ slapi_log_error( SLAPI_LOG_FATAL, subsystem, "before: %s\n",
+ slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
+ }
+
+ /* find decoders */
+ rc = index_subsys_assign_decoders(f);
+
+ if ( LDAPDebugLevelIsSet( LDAP_DEBUG_FILTER ) && NULL != f ) {
+ logbuf[0] = '\0';
+ slapi_log_error( SLAPI_LOG_FATAL, subsystem, " after: %s\n",
+ slapi_filter_to_string(f, logbuf, sizeof(logbuf)));
+ }
+
+ return rc;
+}
+
+/* index_subsys_filter_decoders_done
+ * ---------------------------------
+ * removes assigned index plugins in
+ * sub-filters
+ */
+int index_subsys_filter_decoders_done(Slapi_PBlock *pb)
+{
+ Slapi_Filter *f;
+
+ /* extract the filter */
+ slapi_pblock_get(pb, SLAPI_SEARCH_FILTER, &f);
+
+ /* remove decoders */
+ return index_subsys_decoder_done(f);
+}
+
+
+/* index_subsys_unlink_subfilter
+ * -----------------------------
+ * removes the sub-filter from
+ * the complex filter list
+ * does NOT deallocate the sub-filter
+ */
+static int index_subsys_unlink_subfilter(Slapi_Filter *fcomplex, Slapi_Filter *fsub)
+{
+ int ret = -1;
+ Slapi_Filter *f;
+ Slapi_Filter *f_prev = 0;
+
+ for(f=fcomplex->f_list; f != NULL; f = f->f_next)
+ {
+ if(f == fsub)
+ {
+ if(f_prev)
+ {
+ f_prev->f_next = f->f_next;
+ f->f_next = 0;
+ ret = 0;
+ break;
+ }
+ else
+ {
+ /* was at the beginning of the list */
+ fcomplex->f_list = f->f_next;
+ f->f_next = 0;
+ ret = 0;
+ break;
+ }
+ }
+
+ f_prev = f;
+ }
+
+ return ret;
+}
+
+/* index_subsys_index_matches_associated
+ * -------------------------------------
+ * determines if there is any kind of match
+ * between the specified type and the index.
+ *
+ * matches could be on the indexed type or
+ * on any associated attribute
+ * returns:
+ * 0 when false
+ * non-zero when true
+ */
+static int index_subsys_index_matches_associated(indexEntry *index, Slapi_Filter *f)
+{
+ int ret = 0;
+ char **associated_attrs = index->associated_attrs;
+
+ if(INDEX_MATCH_NONE != index_subsys_index_matches_filter(index, f))
+ {
+ /* matched on indexed attribute */
+ ret = -1;
+ goto bail;
+ }
+
+ /* check associated attributes */
+ if(associated_attrs)
+ {
+ int i;
+ char *type = f->f_type;
+
+ for(i=0; associated_attrs[i]; i++)
+ {
+ if(slapi_attr_types_equivalent(associated_attrs[i], type))
+ {
+ /* matched on associated attribute */
+ ret = -1;
+ break;
+ }
+ }
+ }
+
+bail:
+ return ret;
+}
+
+
+/* index_subsys_flatten_filter
+ * ---------------------------
+ * takes a complex filter as argument (assumed)
+ * and merges all compatible complex sub-filters
+ * such that their list of sub-filters are moved
+ * to the main list of sub-filters in f.
+ *
+ * This "flattens" the filter so that there are
+ * the minimum number of nested complex filters
+ * possible.
+ *
+ * What is a "compatible complex sub-filter?"
+ * Answer: a complex sub-filter which is of the
+ * same type (AND or OR) as the containing complex
+ * filter and which is either assigned the same
+ * index decoder or no index decoder is assigned to
+ * either complex filter.
+ *
+ * This function assumes that it has already
+ * been called for every complex sub-filter of f
+ * i.e. it only looks one layer deep.
+ *
+ * Note that once a filter has been processed in
+ * this fashion, rearranging the filter based
+ * on the optimal evaluation order becomes very
+ * much simpler. It should also have benefits for
+ * performance when a filter is evaluated many
+ * times since a linear list traversal is faster than a
+ * context switch to recurse down into a complex
+ * filter structure.
+ *
+ */
+static void index_subsys_flatten_filter(Slapi_Filter *flist)
+{
+ struct slapi_filter *f = flist->f_list;
+ struct slapi_filter *fprev = 0;
+ struct slapi_filter *flast = 0;
+
+ while(f)
+ {
+ if(f->assigned_decoder == flist->assigned_decoder)
+ {
+ /* mmmk, but is the filter complex? */
+ if(f->f_choice == LDAP_FILTER_AND || f->f_choice == LDAP_FILTER_OR)
+ {
+ if(f->f_choice == flist->f_choice)
+ {
+ /* flatten this, and remember
+ * we expect that any complex sub-filters
+ * have already been flattened, so we
+ * simply transfer the contents of this
+ * sub-filter to the main sub-filter and
+ * remove this complex sub-filter
+ *
+ * take care not to change the filter
+ * ordering in any way (it may have been
+ * optimized)
+ */
+ struct slapi_filter *fnext = f->f_next;
+ struct slapi_filter *fsub = 0;
+
+ while(f->f_list)
+ {
+ fsub = f->f_list;
+ index_subsys_unlink_subfilter(f, f->f_list);
+ fsub->f_next = fnext;
+
+ if(flast)
+ {
+ /* we inserted something before - insert after */
+ flast->f_next = fsub;
+ }
+ else
+ {
+ /* first insertion */
+ if(fprev)
+ {
+ fprev->f_next = fsub;
+ }
+ else
+ {
+ /* insert at list start */
+ flist->f_list = fsub;
+ }
+
+ fprev = fsub;
+ }
+
+ flast = fsub;
+ }
+
+ /* zero for dont recurse - recursing would
+ * be bad since we have created a mutant
+ * complex filter with no children
+ */
+ slapi_filter_free(f, 0);
+ f = fnext;
+ }
+ else
+ {
+ fprev = f;
+ f = f->f_next;
+ }
+ }
+ else
+ {
+ fprev = f;
+ f = f->f_next;
+ }
+ }
+ else
+ {
+ fprev = f;
+ f = f->f_next;
+ }
+ }
+}
+
+/* index_subsys_group_decoders
+ * ---------------------------
+ * looks for grouping opportunities
+ * such that a complex filter may
+ * be assigned to a single index.
+ *
+ * it is assumed that any complex sub-filters
+ * have already been assigned decoders
+ * using this function if it
+ * was possible to do so
+ */
+static int index_subsys_group_decoders(Slapi_Filter *flist)
+{
+ int ret = 0;
+ struct slapi_filter *f = 0;
+ struct slapi_filter *f_indexed = 0;
+ struct slapi_filter *fhead = 0;
+ int index_count = 0;
+ int matched = 1;
+
+ switch(flist->f_choice)
+ {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ break;
+
+ default:
+ /* any other result not handled by this code */
+ goto bail;
+ }
+
+ /* make sure we start with an unassigned filter */
+ flist->assigned_decoder = 0;
+
+ /* Since this function is about optimal grouping of complex filters,
+ * lets explain what is happening here:
+ *
+ * Beyond detecting that what was passed in is already optimal,
+ * there are 4 basic problems we need to solve here:
+ *
+ * Input this function Output
+ * 1) (&(indexed)(other)(associated)) -> X -> (&(&(indexed)(associated))(other))
+ * 2) (&(&(indexed)(other))(associated)) -> X -> (&(&(indexed)(associated))(other))
+ * 3) (&(&(associated)(other))(indexed)) -> X -> (&(&(indexed)(associated))(other))
+ * 4) (&(&(indexed)(associated))(associated)) -> X -> (&(indexed)(associated)(associated))
+ *
+ * To avoid having special code for 2) and 3) we make them look like
+ * 1) by flattening the filter - note this will only flatten subfilters
+ * which have no decoder assigned since the filter we flatten has no
+ * decoder assigned - and this behaviour is exactly what we want.
+ * 4) is a special case of 1) and since that is the case, we can allow
+ * the code for 1) to process it but make sure we flatten the filter
+ * before exit. If 4) is exactly as stated without any other non-indexed
+ * or associated references then in fact it will be detected as a completely
+ * matching filter prior to reaching the code for 1).
+ */
+
+ index_subsys_flatten_filter(flist);
+ fhead = flist->f_list;
+
+ /* find the first index assigned */
+ for ( f_indexed = fhead; f_indexed != NULL; f_indexed = f_indexed->f_next )
+ {
+ if( f_indexed->assigned_decoder )
+ {
+ /* non-null decoder means assigned */
+ break;
+ }
+ }
+
+ if(NULL == f_indexed)
+ /* nothing to process */
+ goto bail;
+
+ /* determine if whole filter matches
+ * to avoid allocations where it is
+ * not necessary
+ */
+ for ( f = fhead; f != NULL; f = f->f_next )
+ {
+ if(f->assigned_decoder != f_indexed->assigned_decoder)
+ {
+ switch(f->f_choice)
+ {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ /*
+ * All complex subfilters are guaranteed to have the correct
+ * decoder assigned already, so this is a mismatch.
+ */
+
+ matched = 0;
+ break;
+
+ default:
+ if(!index_subsys_index_matches_associated(f_indexed->assigned_decoder, f))
+ {
+ matched = 0;
+ }
+ break;
+ }
+
+ if(!matched)
+ break;
+ }
+ }
+
+ if(matched)
+ {
+ /* whole filter matches - assign to this decoder */
+ flist->assigned_decoder = f_indexed->assigned_decoder;
+ /* finally lets flatten this filter if possible
+ * Didn't we do that already? No, we flattened the
+ * filter *prior* to assigning a decoder
+ */
+ index_subsys_flatten_filter(flist);
+ goto bail;
+ }
+
+ /* whole filter does not match so,
+ * if the sub-filter count is > 2
+ * for each assigned sub-filter,
+ * match other groupable filters
+ * and extract them into another sub-filter
+ */
+
+ /* count */
+ for ( f = fhead; f != NULL && index_count < 3; f = f->f_next )
+ {
+ index_count++;
+ }
+
+ if(index_count > 2)
+ {
+ /* this is where we start re-arranging the filter assertions
+ * into groups which can be serviced by a single plugin
+ * at this point we know that:
+ * a) the filter has at least 2 assertions that cannot be grouped
+ * b) there are more than 2 assertions and so grouping is still possible
+ */
+
+ struct slapi_filter *f_listposition=f_indexed; /* flist subfilter list iterator */
+ int main_iterate; /* controls whether to iterate to the next sub-filter of flist */
+
+ while(f_listposition)
+ {
+ /* the target grouping container - we move sub-filters here */
+ struct slapi_filter *targetf=0;
+
+ /* indicates we found an existing targetf */
+ int assigned = 0;
+
+ struct slapi_filter *f_last = 0; /* previos filter in list */
+
+ /* something to join with next compatible
+ * subfilter we find - this will be the
+ * first occurence of a filter assigned
+ * to a particular decoder
+ */
+ struct slapi_filter *saved_filter = 0;
+
+ struct slapi_filter *f_tmp = 0; /* save filter for list fixups */
+
+ /* controls whether to iterate to the
+ * next sub-filter of flist
+ * inner loop
+ */
+ int iterate = 1;
+
+ f_indexed = f_listposition;
+ main_iterate = 1;
+
+ /* finding a convenient existing sub-filter of the same
+ * type as the containing filter avoids allocation
+ * so lets look for one
+ */
+
+ for ( f = fhead; f != NULL; f = f->f_next)
+ {
+ switch(f->f_choice)
+ {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ if( f->f_choice == flist->f_choice &&
+ f->assigned_decoder == f_indexed->assigned_decoder)
+ {
+ targetf = f;
+ assigned = 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if(assigned)
+ break;
+ }
+
+ /* now look for grouping opportunities */
+ for ( f = fhead; f != NULL; (iterate && f) ? f = f->f_next : f )
+ {
+ iterate = 1;
+
+ if(f != targetf)
+ {
+ switch(f->f_choice)
+ {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ if( (targetf && f->f_choice == targetf->f_choice)
+ && f->assigned_decoder == f_indexed->assigned_decoder)
+ {
+ /* ok we have a complex filter we can group - group it
+ * it is worth noting that if we got here, then we must
+ * have found a complex filter suitable for for putting
+ * sub-filters in, so there is no need to add the newly
+ * merged complex filter to the main complex filter,
+ * since it is already there
+ */
+
+ /* main filter list fix ups */
+ f_tmp = f;
+ f = f->f_next;
+ iterate = 0;
+
+ if(f_tmp == f_listposition)
+ {
+ f_listposition = f;
+ main_iterate = 0;
+ }
+
+ /* remove f from the main complex filter */
+ index_subsys_unlink_subfilter(flist, f_tmp);
+
+
+ /* merge - note, not true merge since f gets
+ * added to targetf as a sub-filter
+ */
+ slapi_filter_join_ex(targetf->f_choice, targetf, f_tmp, 0);
+
+ /* since it was not a true merge, lets do the true merge now */
+ index_subsys_flatten_filter(targetf);
+ }
+ break;
+
+ default:
+ if(index_subsys_index_matches_associated(f_indexed->assigned_decoder, f))
+ {
+ if(targetf)
+ {
+ /* main filter list fix ups */
+ f_tmp = f;
+ f = f->f_next;
+ iterate = 0;
+
+ if(f_tmp == f_listposition)
+ {
+ f_listposition = f;
+ main_iterate = 0;
+ }
+
+ index_subsys_unlink_subfilter(flist, f_tmp);
+ targetf = slapi_filter_join_ex( targetf->f_choice, targetf, f_tmp, 0 );
+ }
+ else
+ {
+ if(saved_filter)
+ {
+ /* main filter list fix ups */
+ f_tmp = f;
+ f = f->f_next;
+ iterate = 0;
+
+ if(f_tmp == f_listposition)
+ {
+ f_listposition = f;
+ main_iterate = 0;
+ }
+
+ index_subsys_unlink_subfilter(flist, f_tmp);
+ index_subsys_unlink_subfilter(flist, saved_filter);
+ targetf = slapi_filter_join_ex( flist->f_choice, saved_filter, f_tmp, 0 );
+ targetf->assigned_decoder = f_indexed->assigned_decoder;
+ }
+ else
+ {
+ /* nothing to join so save this for
+ * when we find another compatible
+ * filter
+ */
+ saved_filter = f;
+ }
+ }
+
+ if(!assigned && targetf)
+ {
+ /* targetf has just been created, so
+ * we must add it to the main complex filter
+ */
+ targetf->f_next = flist->f_list;
+ flist->f_list = targetf;
+ assigned = 1;
+ }
+ }
+
+ break;
+ }
+ }
+
+ f_last = f;
+ }
+
+ /* iterate through the main list
+ * to the next indexed sub-filter
+ */
+ if( f_listposition &&
+ (main_iterate ||
+ (!main_iterate &&
+ !f_listposition->assigned_decoder)))
+ {
+ if(!f_listposition->f_next)
+ {
+ f_listposition = 0;
+ break;
+ }
+
+ for ( f_listposition = f_listposition->f_next; f_listposition != NULL; f_listposition = f_listposition->f_next )
+ {
+ if( f_listposition->assigned_decoder )
+ {
+ /* non-null decoder means assigned */
+ break;
+ }
+ }
+ }
+ }
+ }
+
+bail:
+
+ return ret;
+}
+
+
+/* index_subsys_assign_decoders
+ * ----------------------------
+ * recurses through complex filters
+ * assigning decoders
+ */
+static int index_subsys_assign_decoders(Slapi_Filter *f)
+{
+ int ret = 0;
+ Slapi_Filter *subf;
+
+ switch ( slapi_filter_get_choice( f ) )
+ {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ /* assign simple filters first */
+ f->assigned_decoder = 0;
+ for(subf=f->f_list; subf != NULL; subf = subf->f_next )
+ ret = index_subsys_assign_decoders(subf);
+
+ /* now check for filter grouping opportunities... */
+ if(slapi_filter_get_choice( f ) != LDAP_FILTER_NOT)
+ index_subsys_group_decoders(f);
+ else
+ {
+ /* LDAP_FILTER_NOT is a special case
+ * the contained sub-filter determines
+ * the assigned index - the index plugin has
+ * the option to refuse to service the
+ * NOT filter when it is presented
+ */
+ f->assigned_decoder = f->f_list->assigned_decoder;
+ }
+
+ break;
+
+ default:
+ /* find a decoder that fits this simple filter */
+ ret = index_subsys_assign_decoder(f);
+ }
+
+ return ret;
+}
+
+/* index_subsys_decoder_done
+ * -------------------------
+ * recurses through complex filters
+ * removing decoders
+ */
+static int index_subsys_decoder_done(Slapi_Filter *f)
+{
+ int ret = 0;
+ Slapi_Filter *subf;
+ indexEntry *index;
+ indexEntry *next_index;
+
+ switch ( slapi_filter_get_choice( f ) )
+ {
+ case LDAP_FILTER_AND:
+ case LDAP_FILTER_OR:
+ case LDAP_FILTER_NOT:
+ /* remove simple filters first */
+ for(subf=f->f_list; subf != NULL; subf = subf->f_next )
+ ret = index_subsys_decoder_done(subf);
+
+ break;
+
+ default:
+ /* free the decoders - shallow free */
+ index = f->assigned_decoder;
+
+ while(index)
+ {
+ next_index = index->list.pNext;
+ slapi_ch_free((void**)index);
+ index = next_index;
+ }
+
+ f->assigned_decoder = 0;
+ }
+
+ return ret;
+}
+
+/* index_subsys_evaluate_filter
+ * ----------------------------
+ * passes the filter to the correct plugin
+ * index_subsys_assign_filter_decoders() must
+ * have been called previously on this filter
+ * this function can be safely called on all
+ * filters post index_subsys_assign_filter_decoders()
+ * whether they are assigned to a plugin or not
+ *
+ * returns:
+ * INDEX_FILTER_EVALUTED: a candidate list is produced
+ * INDEX_FILTER_UNEVALUATED: filter not considered
+ */
+int index_subsys_evaluate_filter(Slapi_Filter *f, Slapi_DN *namespace_dn, IndexEntryList **out)
+{
+ int ret = INDEX_FILTER_UNEVALUATED;
+ indexEntry *index = (indexEntry*)f->assigned_decoder;
+
+ if(index && theCache)
+ {
+ index_subsys_read_lock();
+
+ /* there is a list of indexes which may
+ * provide an answer for this filter, we
+ * need to invoke the first one that matches
+ * the namespace requested
+ */
+ for(; index; index = index->list.pNext)
+ {
+ /* check namespace */
+ if(slapi_sdn_compare(index->namespace_dn, namespace_dn))
+ {
+ /* wrong namespace */
+ continue;
+ }
+
+ /* execute the search */
+ if(index->lookup_func)
+ {
+ ret = (index->lookup_func)(f, out, index->user_data);
+ break;
+ }
+ }
+
+ index_subsys_unlock();
+ }
+
+ return ret;
+}
+
+
+/* slapi_index_register_decoder
+ * ----------------------------
+ * This allows a decoder to register itself,
+ * it also builds the initial cache when first
+ * called. Note, there is no way to deregister
+ * once registered - this allows a lock free cache
+ * at the expense of a restart to clear old
+ * indexes, this shouldnt be a problem since it is
+ * not expected that indexes will be removed
+ * often.
+ */
+int slapi_index_register_decoder(char *plugin_id, index_validate_callback validate_op)
+{
+ static int firstTime = 1;
+ static int gotIDLapi = 0;
+ int ret = 0;
+ indexPlugin *plg;
+
+ if(firstTime)
+ {
+ /* create the cache */
+ theCache = (globalIndexCache*)slapi_ch_malloc(sizeof(globalIndexCache));
+ if(theCache)
+ {
+ theCache->pPlugins = 0;
+ theCache->ppIndexIndex = 0;
+ theCache->index_count = 0;
+ theCache->cache_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "Index Plugins");;
+ firstTime = 0;
+
+ if(!gotIDLapi)
+ {
+ if(slapi_apib_get_interface(IDL_v1_0_GUID, &idl_api))
+ {
+ gotIDLapi = 1;
+ }
+ }
+ }
+ else
+ {
+ ret = -1;
+ goto bail;
+ }
+ }
+
+ index_subsys_write_lock();
+
+ /* add the index decoder to the cache - no checks, better register once only*/
+ plg = (indexPlugin*)slapi_ch_malloc(sizeof(indexPlugin));
+ if(plg)
+ {
+ plg->id = slapi_ch_strdup(plugin_id);
+ plg->indexes = 0;
+ plg->validate_op = validate_op;
+
+ /* we always add to the start of the linked list */
+ plg->list.pPrev = 0;
+
+ if(theCache->pPlugins)
+ {
+ plg->list.pNext = theCache->pPlugins;
+ theCache->pPlugins->list.pPrev = plg;
+ }
+ else
+ plg->list.pNext = 0;
+
+
+ theCache->pPlugins = plg;
+ }
+ else
+ ret = -1;
+
+ index_subsys_unlock();
+
+bail:
+ return ret;
+}
+
+
+/* slapi_index_register_index
+ * --------------------------
+ * a plugin that has registered itself may
+ * then proceed to register individual indexes
+ * that it looks after. This function adds
+ * the indexes to the plugin cache.
+ */
+int slapi_index_register_index(char *plugin_id, indexed_item *registration_item, void *user_data)
+{
+ int ret = 0;
+ indexPlugin *plg;
+ indexEntry *index;
+ int a_matched_index = 0;
+ Slapi_Filter *tmp_f = slapi_str2filter(registration_item->index_filter);
+ int i = 0;
+ Slapi_Backend *be;
+
+ if(!theCache)
+ return -1;
+
+ index_subsys_write_lock();
+
+ /* first lets find the plugin */
+ plg = theCache->pPlugins;
+
+ while(plg)
+ {
+ if(!slapi_UTF8CASECMP(plugin_id, plg->id))
+ {
+ /* found plugin */
+ break;
+ }
+
+ plg = plg->list.pNext;
+ }
+
+ if(0 == plg)
+ {
+ /* not found */
+ ret = -1;
+ goto bail;
+ }
+
+ /* now add the new index - we shall assume indexes
+ * will not be registered twice by different plugins,
+ * in that event, the last one added wins
+ * the first matching index in the list is always
+ * the current one, other matching indexes are ignored
+ * therefore reregistering an index with NULL
+ * callbacks disables the index for that plugin
+ */
+
+ /* find the index if already registered */
+
+ index = plg->indexes;
+
+ while(index)
+ {
+ if(index_subsys_index_matches_filter(index, tmp_f))
+ {
+ /* found it - free what is currently there, it will be replaced */
+ slapi_ch_free((void**)&index->indexfilterstr);
+ slapi_filter_free(index->indexfilter, 1);
+ slapi_ch_free((void**)&index->indexedAttribute);
+
+ charray_free( index->associated_attrs );
+ index->associated_attrs = 0;
+
+ a_matched_index = 1;
+ break;
+ }
+
+ index = index->list.pNext;
+ }
+
+ if(!index)
+ index = (indexEntry*)slapi_ch_calloc(1,sizeof(indexEntry));
+
+ index->indexfilterstr = slapi_ch_strdup(registration_item->index_filter);
+ index->indexfilter = tmp_f;
+ index->lookup_func = registration_item->search_op;
+ index->user_data = user_data;
+
+ /* map the namespace dn to a backend dn */
+ be = slapi_be_select( registration_item->namespace_dn );
+
+ if(be == defbackend_get_backend())
+ {
+ ret = -1;
+ goto bail;
+ }
+
+ index->namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
+
+ /* for now, we support simple filters only */
+ index->indexedAttribute = slapi_ch_strdup(index->indexfilter->f_type);
+
+ /* add associated attributes */
+ if(registration_item->associated_attrs)
+ {
+ index->associated_attrs =
+ cool_charray_dup( registration_item->associated_attrs );
+ }
+
+ if(!a_matched_index)
+ {
+ if(plg->indexes)
+ {
+ index->list.pNext = plg->indexes;
+ plg->indexes->list.pPrev = plg;
+ }
+ else
+ index->list.pNext = 0;
+
+ index->list.pPrev = 0;
+
+ plg->indexes = index;
+
+ theCache->index_count++;
+ }
+
+ /* now we need to rebuild the index (onto the indexed items)
+ * this is a bit inefficient since
+ * every new index that is added triggers
+ * an index rebuild - but this is countered
+ * by the fact this will probably happen once
+ * at start up most of the time, and very rarely
+ * otherwise, so normal server performance should
+ * not be unduly effected effected
+ * we take care to build the index and only then swap it in
+ * for the old one
+ * PARPAR: we need to RW (or maybe a ref count) lock here
+ * only alternative would be to not have an index :(
+ * for few plugins with few indexes thats a possibility
+ * traditionally many indexes have not been a good idea
+ * anyway so...
+ */
+
+/* indexIndex = (indexEntry**)slapi_ch_malloc(sizeof(indexEntry*) * (theCache->index_count+1));
+*/
+ /* for now, lets see how fast things are without an index
+ * that should not be a problem at all to begin with since
+ * presence will be the only index decoder. Additionally,
+ * adding an index means we need locks - um, no.
+ * so no more to do
+ */
+
+bail:
+ index_subsys_unlock();
+
+ return ret;
+}
+
+/* index_subsys_index_matches_index
+ * --------------------------------
+ * criteria for a match is that the types
+ * are the same and that all the associated
+ * attributes that are configured for cmp_to
+ * are also in cmp_with.
+ */
+int index_subsys_index_matches_index(indexEntry *cmp_to, indexEntry *cmp_with)
+{
+ int ret = 0;
+
+ if(slapi_attr_types_equivalent(cmp_to->indexedAttribute, cmp_with->indexedAttribute))
+ {
+ /* now check associated */
+ if(cmp_to->associated_attrs)
+ {
+ if(cmp_with->associated_attrs)
+ {
+ int x,y;
+
+ ret = 1;
+
+ for(x=0; cmp_to->associated_attrs[x] && ret == 1; x++)
+ {
+ ret = 0;
+
+ for(y=0; cmp_with->associated_attrs[y]; y++)
+ {
+ if(slapi_attr_types_equivalent(
+ cmp_to->associated_attrs[x],
+ cmp_with->associated_attrs[y]
+ ))
+ {
+ /* matched on associated attribute */
+ ret = 1;
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ /* no associated is an auto match */
+ ret = 1;
+ }
+
+ }
+
+ return ret;
+}
+
+indexEntry *index_subsys_index_shallow_dup(indexEntry *dup_this)
+{
+ indexEntry *ret = (indexEntry *)slapi_ch_calloc(1,sizeof(indexEntry));
+
+ /* shallow copy - dont copy linked list pointers */
+ ret->indexedAttribute = dup_this->indexedAttribute;
+ ret->indexfilter = dup_this->indexfilter;
+ ret->indexfilterstr = dup_this->indexfilterstr;
+ ret->user_data = dup_this->user_data;
+ ret->namespace_dn = dup_this->namespace_dn;
+ ret->lookup_func = dup_this->lookup_func;
+ ret->associated_attrs = dup_this->associated_attrs;
+
+ return ret;
+}
+
+/* index_subsys_assign_decoder
+ * ---------------------------
+ * finds a decoder which will service
+ * the filter if one is available and assigns
+ * the decoder to the filter. Currently this
+ * function supports only simple filters, but
+ * may in the future support complex filter
+ * assignment (possibly including filter rewriting
+ * to make more matches possible)
+ *
+ * populates f->alternate_decoders if more than one
+ * index could deal with a filter - only filters that
+ * have a match with all associated attributes of the
+ * first found filter are said to match - their
+ * namespaces may be different
+ */
+static int index_subsys_assign_decoder(Slapi_Filter *f)
+{
+ int ret = 0; /* always succeed */
+ indexPlugin *plg;
+ indexEntry *index = 0;
+ indexEntry *last = 0;
+
+ f->assigned_decoder = 0;
+
+ if(!theCache)
+ return 0;
+
+ index_subsys_read_lock();
+
+ plg = theCache->pPlugins;
+
+ while(plg)
+ {
+ index = plg->indexes;
+
+ while(index)
+ {
+ if(INDEX_MATCH_NONE != index_subsys_index_matches_filter(index, f))
+ {
+ /* we have a match, assign this decoder if not disabled */
+ if(index->lookup_func)
+ {
+ if(!f->assigned_decoder)
+ {
+ f->assigned_decoder = index_subsys_index_shallow_dup(index);
+ last = f->assigned_decoder;
+ }
+ else
+ {
+ /* add to alternate list - we require that they all
+ * have the same associated attributes configuration for now
+ * though they may have different namespaces
+ */
+ if(index_subsys_index_matches_index(f->assigned_decoder, index))
+ {
+ /* add to end */
+ last->list.pNext = index_subsys_index_shallow_dup(index);
+ last = last->list.pNext;
+ }
+ }
+ }
+ else
+ {
+ /* index disabled, so we must allow another plugin to
+ * get a crack at servicing the index
+ */
+ break;
+ }
+ }
+
+ index = index->list.pNext;
+ }
+
+ plg = plg->list.pNext;
+ }
+
+ index_subsys_unlock();
+
+ return ret;
+}
+
diff --git a/ldap/servers/slapd/init.c b/ldap/servers/slapd/init.c
new file mode 100644
index 00000000..3bd4d934
--- /dev/null
+++ b/ldap/servers/slapd/init.c
@@ -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 **/
+/* init.c - initialize various things */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+#include "slap.h"
+#include "fe.h"
+#if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX )
+#include "regex.h"
+#endif
+
+void
+slapd_init()
+{
+#ifdef _WIN32
+ WSADATA wsadata;
+ int err;
+
+ if( err = WSAStartup(0x0101, &wsadata ) != 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Windows Sockets initialization failed, error %d (%s)\n",
+ err, slapd_system_strerror( err ), 0 );
+ exit( 1 );
+ }
+#endif /* _WIN32 */
+
+ ops_mutex = PR_NewLock();
+ num_conns_mutex = PR_NewLock();
+ g_set_num_sent_mutex( PR_NewLock() );
+ g_set_current_conn_count_mutex( PR_NewLock() );
+ slapd_re_init();
+
+ if ( ops_mutex == NULL ||
+ num_conns_mutex == NULL ||
+ g_get_num_sent_mutex() == NULL ||
+ g_get_current_conn_count_mutex() == NULL )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "init: PR_NewLock failed\n", 0, 0, 0 );
+ exit( -1 );
+ }
+
+#ifndef HAVE_TIME_R
+ if ((time_func_mutex = PR_NewLock()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "init: PR_NewLock failed\n", 0, 0, 0 );
+ exit(-1);
+ }
+
+#endif /* HAVE_TIME_R */
+}
diff --git a/ldap/servers/slapd/intrinsics.h b/ldap/servers/slapd/intrinsics.h
new file mode 100644
index 00000000..f0b63431
--- /dev/null
+++ b/ldap/servers/slapd/intrinsics.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 **/
+
+/* Header file used to declare functions which we beat on heavily as intrinsic */
+
+/* For NT ...*/
+
+#ifdef _WIN32
+__inline static int strcmpi_fast(const char * dst, const char * src)
+{
+ int f,l;
+ do {
+ if ( ((f = (unsigned char)(*(dst++))) >= 'A') && (f <= 'Z') )
+ f -= ('A' - 'a');
+ if ( ((l = (unsigned char)(*(src++))) >= 'A') && (l <= 'Z') )
+ l -= ('A' - 'a');
+ } while ( f && (f == l) );
+ return(f - l);
+}
+#ifdef strcasecmp
+#undef strcasecmp
+#endif
+#define strcasecmp(x,y) strcmpi_fast(x,y)
+#ifdef strcmpi
+#undef strcmpi
+#endif
+#define strcmpi(x,y) strcmpi_fast(x,y)
+
+__inline static int tolower_fast(int c)
+{
+ if ( (c >= 'A') && (c <= 'Z') )
+ c = c + ('a' - 'A');
+ return c;
+}
+#ifdef tolower
+#undef tolower
+#endif
+#define tolower(x) tolower_fast(x)
+
+#else
+
+#ifdef HPUX
+#pragma INLINE strcmpi_fast,tolower_fast,toupper_fast,strncasecmp_fast
+#endif
+#ifdef LINUX
+#define INLINE_DIRECTIVE __inline__
+#else
+#define INLINE_DIRECTIVE
+#endif
+
+INLINE_DIRECTIVE static int strcmpi_fast(const char * dst, const char * src)
+{
+ int f,l;
+ do {
+ if ( ((f = (unsigned char)(*(dst++))) >= 'A') && (f <= 'Z') )
+ f -= ('A' - 'a');
+ if ( ((l = (unsigned char)(*(src++))) >= 'A') && (l <= 'Z') )
+ l -= ('A' - 'a');
+ } while ( f && (f == l) );
+ return(f - l);
+}
+#ifdef strcasecmp
+#undef strcasecmp
+#endif
+#define strcasecmp(x,y) strcmpi_fast(x,y)
+#ifdef strcmpi
+#undef strcmpi
+#endif
+#define strcmpi(x,y) strcmpi_fast(x,y)
+
+INLINE_DIRECTIVE static int tolower_fast(int c)
+{
+ if ( (c >= 'A') && (c <= 'Z') )
+ c = c + ('a' - 'A');
+ return c;
+}
+#ifdef tolower
+#undef tolower
+#endif
+#define tolower(x) tolower_fast(x)
+
+INLINE_DIRECTIVE static int toupper_fast(int c)
+{
+ if ( (c >= 'a') && (c <= 'z') )
+ c = c - ('a' - 'A');
+ return c;
+}
+#ifdef toupper
+#undef toupper
+#endif
+#define toupper(x) toupper_fast(x)
+
+INLINE_DIRECTIVE static int strncasecmp_fast(const char * dst, const char * src, int n)
+{
+ int f,l,x=0;
+ do {
+ if ( ((f = (unsigned char)(*(dst++))) >= 'A') && (f <= 'Z') )
+ f -= ('A' - 'a');
+ if ( ((l = (unsigned char)(*(src++))) >= 'A') && (l <= 'Z') )
+ l -= ('A' - 'a');
+ } while ( f && (f == l) && ++x < n );
+ return(f - l);
+}
+
+#ifdef strncasecmp
+#undef strncasecmp
+#endif
+#define strncasecmp(x,y,z) strncasecmp_fast(x,y,z)
+#endif /* NT */
diff --git a/ldap/servers/slapd/ldbmlinktest.c b/ldap/servers/slapd/ldbmlinktest.c
new file mode 100644
index 00000000..a4df5bed
--- /dev/null
+++ b/ldap/servers/slapd/ldbmlinktest.c
@@ -0,0 +1,38 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#if 0
+int detached;
+int error_logfp;
+#endif
+
+main()
+{
+ ldbm_back_bind();
+ ldbm_back_unbind();
+ ldbm_back_search();
+ ldbm_back_compare();
+ ldbm_back_modify();
+ ldbm_back_modrdn();
+ ldbm_back_add();
+ ldbm_back_delete();
+ ldbm_back_abandon();
+ ldbm_back_config();
+ ldbm_back_init();
+ ldbm_back_close();
+ ldbm_back_flush();
+}
+
+#if 0
+slapi_access_allowed(){}
+send_ldap_result(){}
+slapi_op_abandoned(){}
+be_issuffix(){}
+slapi_pw_find(){}
+send_ldap_search_entry(){}
+slapi_pblock_get(){}
+slapi_pblock_set(){}
+slapi_acl_check_mods(){}
+#endif
diff --git a/ldap/servers/slapd/lenstr.c b/ldap/servers/slapd/lenstr.c
new file mode 100644
index 00000000..f7b19054
--- /dev/null
+++ b/ldap/servers/slapd/lenstr.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 **/
+
+#include <string.h>
+#include "slapi-private.h"
+
+#define LS_INCRSIZE 256
+
+/*
+ * Function: addlenstr
+ * Arguments: l - pointer to an allocated lenstr structure
+ * str - the (null-terminated) string to append
+ * Returns: nothing
+ * Description: Add "str" to the lenstr, increasing the size if needed.
+ */
+void
+addlenstr( lenstr *l, const char *str )
+{
+ size_t len = strlen( str );
+
+ if ( l->ls_buf == NULL ) {
+ /* string is empty */
+ l->ls_maxlen = ( len > LS_INCRSIZE ) ? len : LS_INCRSIZE;
+ l->ls_len = len;
+ l->ls_buf = slapi_ch_malloc( l->ls_maxlen + 1 );
+ memcpy( l->ls_buf, str, len + 1 );
+ } else {
+ if ( l->ls_len + len > l->ls_maxlen ) {
+ l->ls_maxlen *= 2;
+ if (l->ls_maxlen < l->ls_len + len) {
+ l->ls_maxlen += len;
+ }
+ l->ls_buf = slapi_ch_realloc( l->ls_buf, l->ls_maxlen + 1 );
+ }
+ memcpy( l->ls_buf + l->ls_len, str, len + 1 );
+ l->ls_len += len;
+ }
+}
+
+
+
+/*
+ * Function: lenstr_free
+ * Arguments: l - pointer to an allocated lenstr structure
+ * Returns: nothing
+ * Description: Free a lenstr.
+ */
+void
+lenstr_free( lenstr **l )
+{
+ if ( NULL != l && NULL != *l ) {
+ lenstr *tl = *l;
+ if ( tl->ls_buf != NULL ) {
+ slapi_ch_free((void **) &tl->ls_buf );
+ }
+ slapi_ch_free((void **) l );
+ }
+}
+
+
+
+/*
+ * Function: lenstr_new
+ * Returns: an empty, newly-allocated lenstr
+ */
+lenstr *
+lenstr_new()
+{
+ lenstr *l;
+
+ l = ( lenstr * ) slapi_ch_malloc( sizeof( lenstr ));
+ l->ls_buf = NULL;
+ l->ls_len = l->ls_maxlen = 0;
+ return l;
+}
+
+
diff --git a/ldap/servers/slapd/libglobs.c b/ldap/servers/slapd/libglobs.c
new file mode 100644
index 00000000..ac9ac10c
--- /dev/null
+++ b/ldap/servers/slapd/libglobs.c
@@ -0,0 +1,4051 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ *
+ * libglobs.c -- SLAPD library global variables
+ */
+/* for windows only
+ we define slapd_ldap_debug here, so we don't want to declare
+ it in any header file which might conflict with our definition
+*/
+#define DONT_DECLARE_SLAPD_LDAP_DEBUG /* see ldaplog.h */
+
+#if defined(NET_SSL)
+#include "ldap.h"
+#include <sslproto.h>
+#include <ldap_ssl.h>
+
+#undef OFF
+#undef LITTLE_ENDIAN
+
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#if defined( _WIN32 )
+#define R_OK 04
+#include "ntslapdmessages.h"
+#include "proto-ntutil.h"
+#else
+#include <sys/time.h>
+#include <sys/param.h> /* MAXPATHLEN */
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <unistd.h>
+#include <pwd.h> /* pwdnam */
+#endif
+#ifdef USE_SYSCONF
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+#include "slap.h"
+#include "plhash.h"
+
+#define REMOVE_CHANGELOG_CMD "remove"
+
+/* On UNIX, there's only one copy of slapd_ldap_debug */
+/* On NT, each module keeps its own module_ldap_debug, which */
+/* points to the process' slapd_ldap_debug */
+#ifdef _WIN32
+int *module_ldap_debug;
+int __declspec(dllexport) slapd_ldap_debug = LDAP_DEBUG_ANY;
+#else
+int slapd_ldap_debug = LDAP_DEBUG_ANY;
+#endif
+
+char *ldap_srvtab = "";
+
+/* Note that the 'attrname' arguments are used only for log messages */
+typedef int (*ConfigSetFunc)(const char *attrname, char *value,
+ char *errorbuf, int apply);
+typedef int (*LogSetFunc)(const char *attrname, char *value, int whichlog,
+ char *errorbuf, int apply);
+
+typedef enum {
+ CONFIG_INT, /* maps to int */
+ CONFIG_LONG, /* maps to long */
+ CONFIG_STRING, /* maps to char* */
+ CONFIG_CHARRAY, /* maps to char** */
+ CONFIG_ON_OFF, /* maps 0/1 to "off"/"on" */
+ CONFIG_STRING_OR_OFF, /* use "off" instead of null or an empty string */
+ CONFIG_STRING_OR_UNKNOWN, /* use "unknown" instead of an empty string */
+ CONFIG_CONSTANT_INT, /* for #define values, e.g. */
+ CONFIG_CONSTANT_STRING, /* for #define values, e.g. */
+ CONFIG_SPECIAL_REFERRALLIST, /* this is a berval list */
+ CONFIG_SPECIAL_SSLCLIENTAUTH, /* maps strings to an enumeration */
+ CONFIG_SPECIAL_ERRORLOGLEVEL, /* requires & with LDAP_DEBUG_ANY */
+ CONFIG_STRING_OR_EMPTY /* use an empty string */
+} ConfigVarType;
+
+static int config_set_onoff( const char *attrname, char *value,
+ int *configvalue, char *errorbuf, int apply );
+static int config_set_schemareplace ( const char *attrname, char *value,
+ char *errorbuf, int apply );
+
+static int
+isIntegralType(ConfigVarType type)
+{
+ return type == CONFIG_INT || type == CONFIG_LONG || type == CONFIG_ON_OFF;
+}
+
+/* the caller will typically have to cast the result based on the ConfigVarType */
+typedef void *(*ConfigGetFunc)(void);
+
+/* static Ref_Array global_referrals; */
+static slapdFrontendConfig_t global_slapdFrontendConfig;
+
+static struct config_get_and_set {
+ const char *attr_name; /* the name of the attribute */
+ ConfigSetFunc setfunc; /* the function to call to set the value */
+ LogSetFunc logsetfunc; /* log functions are special */
+ int whichlog; /* ACCESS, ERROR, AUDIT, etc. */
+ void** config_var_addr; /* address of member of slapdFrontendConfig struct */
+ ConfigVarType config_var_type; /* cast to this type when getting */
+ ConfigGetFunc getfunc; /* for special handling */
+} ConfigList[] = {
+ {CONFIG_AUDITLOG_MODE_ATTRIBUTE, NULL,
+ log_set_mode, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_mode, CONFIG_STRING, NULL},
+ {CONFIG_AUDITLOG_LOGROTATIONSYNCENABLED_ATTRIBUTE, NULL,
+ log_set_rotationsync_enabled, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_rotationsync_enabled, CONFIG_ON_OFF, NULL},
+ {CONFIG_AUDITLOG_LOGROTATIONSYNCHOUR_ATTRIBUTE, NULL,
+ log_set_rotationsynchour, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_rotationsynchour, CONFIG_INT, NULL},
+ {CONFIG_AUDITLOG_LOGROTATIONSYNCMIN_ATTRIBUTE, NULL,
+ log_set_rotationsyncmin, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_rotationsyncmin, CONFIG_INT, NULL},
+ {CONFIG_AUDITLOG_LOGROTATIONTIME_ATTRIBUTE, NULL,
+ log_set_rotationtime, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_rotationtime, CONFIG_INT, NULL},
+ {CONFIG_ACCESSLOG_MODE_ATTRIBUTE, NULL,
+ log_set_mode, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_mode, CONFIG_STRING, NULL},
+ {CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE, NULL,
+ log_set_numlogsperdir, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_maxnumlogs, CONFIG_INT, NULL},
+ {CONFIG_LOGLEVEL_ATTRIBUTE, config_set_errorlog_level,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.errorloglevel,
+ CONFIG_SPECIAL_ERRORLOGLEVEL, NULL},
+ {CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE, NULL,
+ log_set_logging, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_logging_enabled, CONFIG_ON_OFF, NULL},
+ {CONFIG_ERRORLOG_MODE_ATTRIBUTE, NULL,
+ log_set_mode, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_mode, CONFIG_STRING, NULL},
+ {CONFIG_ERRORLOG_LOGEXPIRATIONTIME_ATTRIBUTE, NULL,
+ log_set_expirationtime, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_exptime, CONFIG_INT, NULL},
+ {CONFIG_ACCESSLOG_LOGGING_ENABLED_ATTRIBUTE, NULL,
+ log_set_logging, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_logging_enabled, CONFIG_ON_OFF, NULL},
+ {CONFIG_PORT_ATTRIBUTE, config_set_port,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.port, CONFIG_INT, NULL},
+ {CONFIG_WORKINGDIR_ATTRIBUTE, config_set_workingdir,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.workingdir, CONFIG_STRING_OR_EMPTY, NULL},
+ {CONFIG_MAXTHREADSPERCONN_ATTRIBUTE, config_set_maxthreadsperconn,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.maxthreadsperconn, CONFIG_INT, NULL},
+ {CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_ATTRIBUTE, NULL,
+ log_set_expirationtime, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_exptime, CONFIG_INT, NULL},
+#ifndef _WIN32
+ {CONFIG_LOCALUSER_ATTRIBUTE, config_set_localuser,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.localuser, CONFIG_STRING, NULL},
+#endif
+ {CONFIG_ERRORLOG_LOGROTATIONSYNCENABLED_ATTRIBUTE, NULL,
+ log_set_rotationsync_enabled, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_rotationsync_enabled, CONFIG_ON_OFF, NULL},
+ {CONFIG_ERRORLOG_LOGROTATIONSYNCHOUR_ATTRIBUTE, NULL,
+ log_set_rotationsynchour, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_rotationsynchour, CONFIG_INT, NULL},
+ {CONFIG_ERRORLOG_LOGROTATIONSYNCMIN_ATTRIBUTE, NULL,
+ log_set_rotationsyncmin, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_rotationsyncmin, CONFIG_INT, NULL},
+ {CONFIG_ERRORLOG_LOGROTATIONTIME_ATTRIBUTE, NULL,
+ log_set_rotationtime, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_rotationtime, CONFIG_INT, NULL},
+ {CONFIG_PW_INHISTORY_ATTRIBUTE, config_set_pw_inhistory,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_inhistory, CONFIG_INT, NULL},
+ {CONFIG_PW_STORAGESCHEME_ATTRIBUTE, config_set_pw_storagescheme,
+ NULL, 0, NULL, CONFIG_STRING, (ConfigGetFunc)config_get_pw_storagescheme},
+ {CONFIG_PW_UNLOCK_ATTRIBUTE, config_set_pw_unlock,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_unlock, CONFIG_ON_OFF, NULL},
+ {CONFIG_PW_GRACELIMIT_ATTRIBUTE, config_set_pw_gracelimit,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_gracelimit, CONFIG_INT, NULL},
+ {CONFIG_ACCESSLOG_LOGROTATIONSYNCENABLED_ATTRIBUTE, NULL,
+ log_set_rotationsync_enabled, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_rotationsync_enabled, CONFIG_ON_OFF, NULL},
+ {CONFIG_ACCESSLOG_LOGROTATIONSYNCHOUR_ATTRIBUTE, NULL,
+ log_set_rotationsynchour, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_rotationsynchour, CONFIG_INT, NULL},
+ {CONFIG_ACCESSLOG_LOGROTATIONSYNCMIN_ATTRIBUTE, NULL,
+ log_set_rotationsyncmin, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_rotationsyncmin, CONFIG_INT, NULL},
+ {CONFIG_ACCESSLOG_LOGROTATIONTIME_ATTRIBUTE, NULL,
+ log_set_rotationtime, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_rotationtime, CONFIG_INT, NULL},
+ {CONFIG_PW_MUSTCHANGE_ATTRIBUTE, config_set_pw_must_change,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_must_change, CONFIG_ON_OFF, NULL},
+ {CONFIG_PWPOLICY_LOCAL_ATTRIBUTE, config_set_pwpolicy_local,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pwpolicy_local, CONFIG_ON_OFF, NULL},
+ {CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE, NULL,
+ log_set_maxdiskspace, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_maxdiskspace, CONFIG_INT, NULL},
+ {CONFIG_SIZELIMIT_ATTRIBUTE, config_set_sizelimit,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.sizelimit, CONFIG_INT, NULL},
+ {CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE, NULL,
+ log_set_logsize, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_maxlogsize, CONFIG_INT, NULL},
+ {CONFIG_PW_WARNING_ATTRIBUTE, config_set_pw_warning,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_warning, CONFIG_LONG, NULL},
+ {CONFIG_READONLY_ATTRIBUTE, config_set_readonly,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.readonly, CONFIG_ON_OFF, NULL},
+ {CONFIG_THREADNUMBER_ATTRIBUTE, config_set_threadnumber,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.threadnumber, CONFIG_INT, NULL},
+ {CONFIG_PW_LOCKOUT_ATTRIBUTE, config_set_pw_lockout,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_lockout, CONFIG_ON_OFF, NULL},
+ {CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE, config_set_enquote_sup_oc,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.enquote_sup_oc, CONFIG_ON_OFF, NULL},
+ {CONFIG_LOCALHOST_ATTRIBUTE, config_set_localhost,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.localhost, CONFIG_STRING, NULL},
+ {CONFIG_IOBLOCKTIMEOUT_ATTRIBUTE, config_set_ioblocktimeout,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.ioblocktimeout, CONFIG_INT, NULL},
+ {CONFIG_MAX_FILTER_NEST_LEVEL_ATTRIBUTE, config_set_max_filter_nest_level,
+ NULL, 0, (void**)&global_slapdFrontendConfig.max_filter_nest_level,
+ CONFIG_INT, NULL},
+ {CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE, NULL,
+ log_set_maxdiskspace, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_maxdiskspace, CONFIG_INT, NULL},
+ {CONFIG_PW_MINLENGTH_ATTRIBUTE, config_set_pw_minlength,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_minlength, CONFIG_INT, NULL},
+ {CONFIG_ERRORLOG_ATTRIBUTE, config_set_errorlog,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.errorlog, CONFIG_STRING_OR_EMPTY, NULL},
+ {CONFIG_AUDITLOG_LOGEXPIRATIONTIME_ATTRIBUTE, NULL,
+ log_set_expirationtime, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_exptime, CONFIG_INT, NULL},
+ {CONFIG_SCHEMACHECK_ATTRIBUTE, config_set_schemacheck,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.schemacheck, CONFIG_ON_OFF, NULL},
+ {CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE, config_set_ds4_compatible_schema,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.ds4_compatible_schema,
+ CONFIG_ON_OFF, NULL},
+ {CONFIG_SCHEMA_IGNORE_TRAILING_SPACES,
+ config_set_schema_ignore_trailing_spaces, NULL, 0,
+ (void**)&global_slapdFrontendConfig.schema_ignore_trailing_spaces,
+ CONFIG_ON_OFF, NULL},
+ {CONFIG_SCHEMAREPLACE_ATTRIBUTE, config_set_schemareplace, NULL, 0,
+ (void**)&global_slapdFrontendConfig.schemareplace,
+ CONFIG_STRING_OR_OFF, NULL},
+ {CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE, NULL,
+ log_set_maxdiskspace, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_maxdiskspace, CONFIG_INT, NULL},
+ {CONFIG_REFERRAL_ATTRIBUTE, (ConfigSetFunc)config_set_defaultreferral,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.defaultreferral,
+ CONFIG_SPECIAL_REFERRALLIST, NULL},
+ {CONFIG_PW_MAXFAILURE_ATTRIBUTE, config_set_pw_maxfailure,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_maxfailure, CONFIG_INT, NULL},
+ {CONFIG_ACCESSLOG_ATTRIBUTE, config_set_accesslog,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.accesslog, CONFIG_STRING_OR_EMPTY, NULL},
+ {CONFIG_LASTMOD_ATTRIBUTE, config_set_lastmod,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.lastmod, CONFIG_ON_OFF, NULL},
+ {CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE, config_set_rootpwstoragescheme,
+ NULL, 0, NULL, CONFIG_STRING, (ConfigGetFunc)config_get_rootpwstoragescheme},
+ {CONFIG_PW_HISTORY_ATTRIBUTE, config_set_pw_history,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_history, CONFIG_ON_OFF, NULL},
+ {CONFIG_SECURITY_ATTRIBUTE, config_set_security,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.security, CONFIG_ON_OFF, NULL},
+ {CONFIG_PW_MAXAGE_ATTRIBUTE, config_set_pw_maxage,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_maxage, CONFIG_LONG, NULL},
+ {CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE, NULL,
+ log_set_rotationtimeunit, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_rotationunit,
+ CONFIG_STRING_OR_UNKNOWN, NULL},
+ {CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE, config_set_pw_resetfailurecount,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_resetfailurecount, CONFIG_LONG, NULL},
+ {CONFIG_PW_ISGLOBAL_ATTRIBUTE, config_set_pw_is_global_policy,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_is_global_policy, CONFIG_ON_OFF, NULL},
+ {CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE, NULL,
+ log_set_numlogsperdir, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_maxnumlogs, CONFIG_INT, NULL},
+ {CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE, NULL,
+ log_set_expirationtimeunit, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_exptimeunit,
+ CONFIG_STRING_OR_UNKNOWN, NULL},
+ /* errorlog list is read only, so no set func and no config var addr */
+ {CONFIG_ERRORLOG_LIST_ATTRIBUTE, NULL, NULL, 0, NULL,
+ CONFIG_CHARRAY, (ConfigGetFunc)config_get_errorlog_list},
+ {CONFIG_GROUPEVALNESTLEVEL_ATTRIBUTE, config_set_groupevalnestlevel,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.groupevalnestlevel, CONFIG_INT, NULL},
+ {CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE, NULL,
+ log_set_expirationtimeunit, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_exptimeunit,
+ CONFIG_STRING_OR_UNKNOWN, NULL},
+ {CONFIG_ROOTPW_ATTRIBUTE, config_set_rootpw,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.rootpw, CONFIG_STRING, NULL},
+ {CONFIG_PW_CHANGE_ATTRIBUTE, config_set_pw_change,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_change, CONFIG_ON_OFF, NULL},
+ {CONFIG_ACCESSLOGLEVEL_ATTRIBUTE, config_set_accesslog_level,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.accessloglevel, CONFIG_INT, NULL},
+ {CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE, NULL,
+ log_set_rotationtimeunit, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_rotationunit,
+ CONFIG_STRING_OR_UNKNOWN, NULL},
+ {CONFIG_SECUREPORT_ATTRIBUTE, config_set_secureport,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.secureport, CONFIG_INT, NULL},
+ {CONFIG_BASEDN_ATTRIBUTE, config_set_basedn,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.certmap_basedn, CONFIG_STRING, NULL},
+ {CONFIG_TIMELIMIT_ATTRIBUTE, config_set_timelimit,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.timelimit, CONFIG_INT, NULL},
+ {CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE, NULL,
+ log_set_logsize, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_maxlogsize, CONFIG_INT, NULL},
+ {CONFIG_RESERVEDESCRIPTORS_ATTRIBUTE, config_set_reservedescriptors,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.reservedescriptors, CONFIG_INT, NULL},
+ /* access log list is read only, no set func, no config var addr */
+ {CONFIG_ACCESSLOG_LIST_ATTRIBUTE, NULL, NULL, 0,
+ NULL, CONFIG_CHARRAY, (ConfigGetFunc)config_get_accesslog_list},
+ {CONFIG_SVRTAB_ATTRIBUTE, config_set_srvtab,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.srvtab, CONFIG_STRING, NULL},
+ {CONFIG_PW_EXP_ATTRIBUTE, config_set_pw_exp,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_exp, CONFIG_ON_OFF, NULL},
+ {CONFIG_ACCESSCONTROL_ATTRIBUTE, config_set_accesscontrol,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.accesscontrol, CONFIG_ON_OFF, NULL},
+ {CONFIG_AUDITLOG_LIST_ATTRIBUTE, NULL, NULL, 0,
+ NULL, CONFIG_CHARRAY, (ConfigGetFunc)config_get_auditlog_list},
+ {CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE, NULL,
+ log_set_rotationtimeunit, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_rotationunit, CONFIG_STRING, NULL},
+ {CONFIG_PW_LOCKDURATION_ATTRIBUTE, config_set_pw_lockduration,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_lockduration, CONFIG_LONG, NULL},
+ {CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE, NULL,
+ log_set_logsize, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_maxlogsize, CONFIG_INT, NULL},
+ {CONFIG_IDLETIMEOUT_ATTRIBUTE, config_set_idletimeout,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.idletimeout, CONFIG_INT, NULL},
+ {CONFIG_NAGLE_ATTRIBUTE, config_set_nagle,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.nagle, CONFIG_ON_OFF, NULL},
+ {CONFIG_ERRORLOG_MINFREEDISKSPACE_ATTRIBUTE, NULL,
+ log_set_mindiskspace, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_minfreespace, CONFIG_INT, NULL},
+ {CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE, NULL,
+ log_set_logging, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_logging_enabled, CONFIG_ON_OFF, NULL},
+ {CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE, config_set_accesslogbuffering,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.accesslogbuffering, CONFIG_ON_OFF, NULL},
+ {CONFIG_CSNLOGGING_ATTRIBUTE, config_set_csnlogging,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.csnlogging, CONFIG_ON_OFF, NULL},
+ {CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE, NULL,
+ log_set_expirationtimeunit, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_exptimeunit,
+ CONFIG_STRING_OR_UNKNOWN, NULL},
+ {CONFIG_PW_SYNTAX_ATTRIBUTE, config_set_pw_syntax,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_syntax, CONFIG_ON_OFF, NULL},
+ {CONFIG_LISTENHOST_ATTRIBUTE, config_set_listenhost,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.listenhost, CONFIG_STRING, NULL},
+ {CONFIG_ACCESSLOG_MINFREEDISKSPACE_ATTRIBUTE, NULL,
+ log_set_mindiskspace, SLAPD_ACCESS_LOG,
+ (void**)&global_slapdFrontendConfig.accesslog_minfreespace, CONFIG_INT, NULL},
+ {CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE, NULL,
+ log_set_numlogsperdir, SLAPD_ERROR_LOG,
+ (void**)&global_slapdFrontendConfig.errorlog_maxnumlogs, CONFIG_INT, NULL},
+ {CONFIG_SECURELISTENHOST_ATTRIBUTE, config_set_securelistenhost,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.securelistenhost, CONFIG_STRING, NULL},
+ {CONFIG_AUDITLOG_MINFREEDISKSPACE_ATTRIBUTE, NULL,
+ log_set_mindiskspace, SLAPD_AUDIT_LOG,
+ (void**)&global_slapdFrontendConfig.auditlog_minfreespace, CONFIG_INT, NULL},
+ {CONFIG_ROOTDN_ATTRIBUTE, config_set_rootdn,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.rootdn, CONFIG_STRING, NULL},
+ {CONFIG_PW_MINAGE_ATTRIBUTE, config_set_pw_minage,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.pw_policy.pw_minage, CONFIG_LONG, NULL},
+ {CONFIG_AUDITFILE_ATTRIBUTE, config_set_auditlog,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.auditlog, CONFIG_STRING_OR_EMPTY, NULL},
+ {CONFIG_RETURN_EXACT_CASE_ATTRIBUTE, config_set_return_exact_case,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.return_exact_case, CONFIG_ON_OFF, NULL},
+ {CONFIG_RESULT_TWEAK_ATTRIBUTE, config_set_result_tweak,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.result_tweak, CONFIG_ON_OFF, NULL},
+ {CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE, config_set_attrname_exceptions,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.attrname_exceptions, CONFIG_ON_OFF, NULL},
+ {CONFIG_MAXBERSIZE_ATTRIBUTE, config_set_maxbersize,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.maxbersize, CONFIG_INT, NULL},
+ {CONFIG_VERSIONSTRING_ATTRIBUTE, config_set_versionstring,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.versionstring, CONFIG_STRING, NULL},
+ {CONFIG_REFERRAL_MODE_ATTRIBUTE, config_set_referral_mode,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.refer_url, CONFIG_STRING, NULL},
+#if !defined(_WIN32) && !defined(AIX)
+ {CONFIG_MAXDESCRIPTORS_ATTRIBUTE, config_set_maxdescriptors,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.maxdescriptors, CONFIG_INT, NULL},
+#endif
+ {CONFIG_CONNTABLESIZE_ATTRIBUTE, config_set_conntablesize,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.conntablesize, CONFIG_INT, NULL},
+ {CONFIG_SSLCLIENTAUTH_ATTRIBUTE, config_set_SSLclientAuth,
+ NULL, 0,
+ (void **)&global_slapdFrontendConfig.SSLclientAuth, CONFIG_SPECIAL_SSLCLIENTAUTH, NULL},
+ {CONFIG_SSL_CHECK_HOSTNAME_ATTRIBUTE, config_set_ssl_check_hostname,
+ NULL, 0, NULL, CONFIG_ON_OFF, (ConfigGetFunc)config_get_ssl_check_hostname},
+ {CONFIG_CONFIG_ATTRIBUTE, 0, NULL, 0, (void**)SLAPD_CONFIG_DN,
+ CONFIG_CONSTANT_STRING, NULL},
+ {CONFIG_HASH_FILTERS_ATTRIBUTE, config_set_hash_filters,
+ NULL, 0, NULL, CONFIG_ON_OFF, (ConfigGetFunc)config_get_hash_filters},
+ {CONFIG_INSTANCEDIR_ATTRIBUTE, NULL /* read only */,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.instancedir, CONFIG_STRING, NULL},
+ {CONFIG_REWRITE_RFC1274_ATTRIBUTE, config_set_rewrite_rfc1274,
+ NULL, 0,
+ (void**)&global_slapdFrontendConfig.rewrite_rfc1274, CONFIG_ON_OFF, NULL},
+ {CONFIG_OUTBOUND_LDAP_IO_TIMEOUT_ATTRIBUTE,
+ config_set_outbound_ldap_io_timeout,
+ NULL, 0,
+ (void **)&global_slapdFrontendConfig.outbound_ldap_io_timeout,
+ CONFIG_INT, NULL}
+};
+
+/*
+ * hashNocaseString - used for case insensitive hash lookups
+ */
+static PLHashNumber
+hashNocaseString(const void *key)
+{
+ PLHashNumber h = 0;
+ const unsigned char *s;
+
+ for (s = key; *s; s++)
+ h = (h >> 28) ^ (h << 4) ^ (tolower(*s));
+ return h;
+}
+
+/*
+ * hashNocaseCompare - used for case insensitive hash key comparisons
+ */
+static PRIntn
+hashNocaseCompare(const void *v1, const void *v2)
+{
+ return (strcasecmp((char *)v1, (char *)v2) == 0);
+}
+
+static PLHashTable *confighash = 0;
+
+static void
+init_config_get_and_set()
+{
+ if (!confighash) {
+ int ii = 0;
+ int tablesize = sizeof(ConfigList)/sizeof(ConfigList[0]);
+ confighash = PL_NewHashTable(tablesize+1, hashNocaseString,
+ hashNocaseCompare,
+ PL_CompareValues, 0, 0);
+ for (ii = 0; ii < tablesize; ++ii) {
+ if (PL_HashTableLookup(confighash, ConfigList[ii].attr_name))
+ printf("error: %s is already in the list\n",
+ ConfigList[ii].attr_name);
+ if (!PL_HashTableAdd(confighash, ConfigList[ii].attr_name, &ConfigList[ii]))
+ printf("error: could not add %s to the list\n",
+ ConfigList[ii].attr_name);
+ }
+ }
+}
+
+#if 0
+#define GOLDEN_RATIO 0x9E3779B9U
+
+PR_IMPLEMENT(PLHashEntry **)
+PL_HashTableRawLookup(PLHashTable *ht, PLHashNumber keyHash, const void *key)
+{
+ PLHashEntry *he, **hep, **hep0;
+ PLHashNumber h;
+
+#ifdef HASHMETER
+ ht->nlookups++;
+#endif
+ h = keyHash * GOLDEN_RATIO;
+ h >>= ht->shift;
+ hep = hep0 = &ht->buckets[h];
+ while ((he = *hep) != 0) {
+ if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) {
+ /* Move to front of chain if not already there */
+ if (hep != hep0) {
+ *hep = he->next;
+ he->next = *hep0;
+ *hep0 = he;
+ }
+ return hep0;
+ }
+ hep = &he->next;
+#ifdef HASHMETER
+ ht->nsteps++;
+#endif
+ }
+ return hep;
+}
+
+static void
+debugHashTable(const char *key)
+{
+ int ii = 0;
+ PLHashEntry **hep = PL_HashTableRawLookup(confighash, hashNocaseString(key),
+ key);
+ if (!hep || !*hep)
+ printf("raw lookup failed for %s\n", key);
+ else if (hep && *hep)
+ printf("raw lookup found %s -> %ul %s\n", key, (*hep)->keyHash, (*hep)->key);
+
+ printf("hash table has %d entries\n", confighash->nentries);
+ for (ii = 0; ii < confighash->nentries; ++ii)
+ {
+ PLHashEntry *he = confighash->buckets[ii];
+ if (!he)
+ printf("hash table entry %d is null\n", ii);
+ else {
+ printf("hash bucket %d:\n", ii);
+ while (he) {
+ int keys = !hashNocaseCompare(key, he->key);
+ int hash = (hashNocaseString(key) == he->keyHash);
+ printf("\thashval = %ul key = %s\n", he->keyHash, he->key);
+ if (keys && hash) {
+ printf("\t\tFOUND\n");
+ } else if (keys) {
+ printf("\t\tkeys match but hash vals do not\n");
+ } else if (hash) {
+ printf("\t\thash match but keys do not\n");
+ }
+ he = he->next;
+ }
+ }
+ }
+}
+#endif
+
+static void
+bervalarray_free(struct berval **bvec)
+{
+ int ii = 0;
+ for(ii = 0; bvec && bvec[ii]; ++ii) {
+ slapi_ch_free((void **)&bvec[ii]->bv_val);
+ slapi_ch_free((void **)&bvec[ii]);
+ }
+ slapi_ch_free((void**)&bvec);
+}
+
+static struct berval **
+strarray2bervalarray(const char **strarray)
+{
+ int ii = 0;
+ struct berval **newlist = 0;
+
+ /* first, count the number of items in the list */
+ for (ii = 0; strarray && strarray[ii]; ++ii);
+
+ /* if no items, return null */
+ if (!ii)
+ return newlist;
+
+ /* allocate the list */
+ newlist = (struct berval **)slapi_ch_malloc((ii+1) * sizeof(struct berval *));
+ newlist[ii] = 0;
+ for (; ii; --ii) {
+ newlist[ii-1] = (struct berval *)slapi_ch_malloc(sizeof(struct berval));
+ newlist[ii-1]->bv_val = slapi_ch_strdup(strarray[ii-1]);
+ newlist[ii-1]->bv_len = strlen(strarray[ii-1]);
+ }
+
+ return newlist;
+}
+
+/*
+** Setting this flag forces the server to shutdown.
+*/
+static int slapd_shutdown;
+
+void g_set_shutdown( int reason )
+{
+ slapd_shutdown = reason;
+}
+
+int g_get_shutdown()
+{
+ return slapd_shutdown;
+}
+
+
+static int cmd_shutdown;
+
+void c_set_shutdown()
+{
+ cmd_shutdown = SLAPI_SHUTDOWN_SIGNAL;
+}
+
+int c_get_shutdown()
+{
+ return cmd_shutdown;
+}
+
+slapdFrontendConfig_t *
+getFrontendConfig()
+{
+ return &global_slapdFrontendConfig;
+}
+
+/*
+ * FrontendConfig_init:
+ * Put all default values for config stuff here.
+ * If there's no default value, the value will be NULL if it's not set in dse.ldif
+ */
+
+void
+FrontendConfig_init () {
+ slapdFrontendConfig_t *cfg = getFrontendConfig();
+
+ /* initialize the read/write configuration lock */
+ if ( (cfg->cfg_rwlock = rwl_new()) == NULL ) {
+ LDAPDebug ( LDAP_DEBUG_ANY,
+ "FrontendConfig_init: failed to initialize cfg_rwlock. Exiting now.",
+ 0,0,0 );
+ exit(-1);
+ }
+
+ cfg->port = LDAP_PORT;
+ cfg->secureport = LDAPS_PORT;
+ cfg->threadnumber = SLAPD_DEFAULT_MAX_THREADS;
+ cfg->maxthreadsperconn = SLAPD_DEFAULT_MAX_THREADS_PER_CONN;
+ cfg->reservedescriptors = SLAPD_DEFAULT_RESERVE_FDS;
+ cfg->idletimeout = SLAPD_DEFAULT_IDLE_TIMEOUT;
+ cfg->ioblocktimeout = SLAPD_DEFAULT_IOBLOCK_TIMEOUT;
+ cfg->outbound_ldap_io_timeout = SLAPD_DEFAULT_OUTBOUND_LDAP_IO_TIMEOUT;
+ cfg->max_filter_nest_level = SLAPD_DEFAULT_MAX_FILTER_NEST_LEVEL;
+
+#ifdef _WIN32
+ cfg->conntablesize = SLAPD_DEFAULT_CONNTABLESIZE;
+#else
+#ifdef USE_SYSCONF
+ cfg->conntablesize = sysconf( _SC_OPEN_MAX );
+#else /* USE_SYSCONF */
+ cfg->conntablesize = getdtablesize();
+#endif /* USE_SYSCONF */
+#endif /* _WIN32 */
+
+ cfg->accesscontrol = LDAP_ON;
+ cfg->security = LDAP_OFF;
+ cfg->ssl_check_hostname = LDAP_ON;
+ cfg->return_exact_case = LDAP_ON;
+ cfg->result_tweak = LDAP_OFF;
+ cfg->reservedescriptors = SLAPD_DEFAULT_RESERVE_FDS;
+ cfg->useroc = slapi_ch_strdup ( "" );
+ cfg->userat = slapi_ch_strdup ( "" );
+/* kexcoff: should not be initialized by default here
+ cfg->rootpwstoragescheme = pw_name2scheme( SHA1_SCHEME_NAME );
+ cfg->pw_storagescheme = pw_name2scheme( SHA1_SCHEME_NAME );
+*/
+ cfg->slapd_type = 0;
+ cfg->versionstring = SLAPD_VERSION_STR;
+ cfg->sizelimit = SLAPD_DEFAULT_SIZELIMIT;
+ cfg->timelimit = SLAPD_DEFAULT_TIMELIMIT;
+ cfg->schemacheck = LDAP_ON;
+ cfg->ds4_compatible_schema = LDAP_OFF;
+ cfg->enquote_sup_oc = LDAP_OFF;
+ cfg->lastmod = LDAP_ON;
+ cfg->rewrite_rfc1274 = LDAP_OFF;
+ cfg->schemareplace = slapi_ch_strdup( CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY );
+ cfg->schema_ignore_trailing_spaces = SLAPD_DEFAULT_SCHEMA_IGNORE_TRAILING_SPACES;
+
+ cfg->pwpolicy_local = LDAP_OFF;
+ cfg->pw_policy.pw_change = LDAP_ON;
+ cfg->pw_policy.pw_must_change = LDAP_OFF;
+ cfg->pw_policy.pw_syntax = LDAP_OFF;
+ cfg->pw_policy.pw_exp = LDAP_OFF;
+ cfg->pw_policy.pw_minlength = 6;
+ cfg->pw_policy.pw_maxage = 8640000; /* 100 days */
+ cfg->pw_policy.pw_minage = 0;
+ cfg->pw_policy.pw_warning = 86400; /* 1 day */
+ cfg->pw_policy.pw_history = LDAP_OFF;
+ cfg->pw_policy.pw_inhistory = 6;
+ cfg->pw_policy.pw_lockout = LDAP_OFF;
+ cfg->pw_policy.pw_maxfailure = 3;
+ cfg->pw_policy.pw_unlock = LDAP_ON;
+ cfg->pw_policy.pw_lockduration = 3600; /* 60 minutes */
+ cfg->pw_policy.pw_resetfailurecount = 600; /* 10 minutes */
+ cfg->pw_policy.pw_gracelimit = 0;
+ cfg->pw_is_global_policy = LDAP_OFF;
+
+ cfg->accesslog_logging_enabled = LDAP_ON;
+ cfg->accesslog_mode = slapi_ch_strdup("600");
+ cfg->accesslog_maxnumlogs = 10;
+ cfg->accesslog_maxlogsize = 100;
+ cfg->accesslog_rotationtime = 1;
+ cfg->accesslog_rotationunit = slapi_ch_strdup("day");
+ cfg->accesslog_rotationsync_enabled = LDAP_OFF;
+ cfg->accesslog_rotationsynchour = 0;
+ cfg->accesslog_rotationsyncmin = 0;
+ cfg->accesslog_maxdiskspace = 500;
+ cfg->accesslog_minfreespace = 5;
+ cfg->accesslog_exptime = 1;
+ cfg->accesslog_exptimeunit = slapi_ch_strdup("month");
+ cfg->accessloglevel = 256;
+ cfg->accesslogbuffering = LDAP_ON;
+ cfg->csnlogging = LDAP_ON;
+
+ cfg->errorlog_logging_enabled = LDAP_ON;
+ cfg->errorlog_mode = slapi_ch_strdup("600");
+ cfg->errorlog_maxnumlogs = 1;
+ cfg->errorlog_maxlogsize = 100;
+ cfg->errorlog_rotationtime = 1;
+ cfg->errorlog_rotationunit = slapi_ch_strdup ("week");
+ cfg->errorlog_rotationsync_enabled = LDAP_OFF;
+ cfg->errorlog_rotationsynchour = 0;
+ cfg->errorlog_rotationsyncmin = 0;
+ cfg->errorlog_maxdiskspace = 100;
+ cfg->errorlog_minfreespace = 5;
+ cfg->errorlog_exptime = 1;
+ cfg->errorlog_exptimeunit = slapi_ch_strdup("month");
+ cfg->errorloglevel = 0;
+
+ cfg->auditlog_logging_enabled = LDAP_OFF;
+ cfg->auditlog_mode = slapi_ch_strdup("600");
+ cfg->auditlog_maxnumlogs = 1;
+ cfg->auditlog_maxlogsize = 100;
+ cfg->auditlog_rotationtime = 1;
+ cfg->auditlog_rotationunit = slapi_ch_strdup ("week");
+ cfg->auditlog_rotationsync_enabled = LDAP_OFF;
+ cfg->auditlog_rotationsynchour = 0;
+ cfg->auditlog_rotationsyncmin = 0;
+ cfg->auditlog_maxdiskspace = 100;
+ cfg->auditlog_minfreespace = 5;
+ cfg->auditlog_exptime = 1;
+ cfg->auditlog_exptimeunit = slapi_ch_strdup("month");
+
+ init_config_get_and_set();
+}
+
+int
+g_get_global_lastmod()
+{
+ return config_get_lastmod();
+}
+
+
+int g_get_slapd_security_on(){
+ return config_get_security();
+}
+
+
+
+#ifdef _WIN32
+void libldap_init_debug_level(int *val_ptr)
+{
+ module_ldap_debug = val_ptr;
+}
+#endif
+
+struct snmp_vars_t global_snmp_vars;
+
+struct snmp_vars_t * g_get_global_snmp_vars(){
+ return &global_snmp_vars;
+}
+
+static slapdEntryPoints *sep = NULL;
+void
+set_dll_entry_points( slapdEntryPoints *p )
+{
+ if ( NULL == sep )
+ {
+ sep = p;
+ }
+}
+
+
+int
+get_entry_point( int ep_name, caddr_t *ep_addr )
+{
+ int rc = 0;
+
+ if(sep!=NULL)
+ {
+ switch ( ep_name ) {
+ case ENTRY_POINT_PS_WAKEUP_ALL:
+ *ep_addr = sep->sep_ps_wakeup_all;
+ break;
+ case ENTRY_POINT_PS_SERVICE:
+ *ep_addr = sep->sep_ps_service;
+ break;
+ case ENTRY_POINT_DISCONNECT_SERVER:
+ *ep_addr = sep->sep_disconnect_server;
+ break;
+ case ENTRY_POINT_SLAPD_SSL_CLIENT_INIT:
+ *ep_addr = sep->sep_slapd_SSL_client_init;
+ break;
+ case ENTRY_POINT_SLAPD_SSL_INIT:
+ *ep_addr = sep->sep_slapd_ssl_init;
+ break;
+ case ENTRY_POINT_SLAPD_SSL_INIT2:
+ *ep_addr = sep->sep_slapd_ssl_init2;
+ break;
+ default:
+ rc = -1;
+ }
+ }
+ else
+ {
+ rc= -1;
+ }
+ return rc;
+}
+
+
+/*
+ * Utility function called by many of the config_set_XXX() functions.
+ * Returns a non-zero value if 'value' is NULL and zero if not.
+ * Also constructs an error message in 'errorbuf' if value is NULL.
+ * If or_zero_length is non-zero, zero length values are treated as
+ * equivalent to NULL (i.e., they will cause a non-zero value to be
+ * returned by this function).
+ */
+static int
+config_value_is_null( const char *attrname, const char *value, char *errorbuf,
+ int or_zero_length )
+{
+ if ( NULL == value || ( or_zero_length && *value == '\0' )) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "%s: NULL value",
+ attrname );
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+int
+config_set_port( const char *attrname, char *port, char *errorbuf, int apply ) {
+ int nPort;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal = LDAP_SUCCESS;
+
+ if ( config_value_is_null( attrname, port, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ nPort = atoi( port );
+
+ if ( nPort == 0 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Information: Non-Secure Port Disabled, server only contactable via secure port\n", 0, 0, 0 );
+ }
+ else if (nPort > LDAP_PORT_MAX || nPort < 0 ) {
+ retVal = LDAP_OPERATIONS_ERROR;
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: %d is invalid, ports must range from 1 to %d",
+ attrname, nPort, LDAP_PORT_MAX );
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapdFrontendConfig->port = nPort;
+ /* n_port = nPort; */
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_secureport( const char *attrname, char *port, char *errorbuf, int apply ) {
+ int nPort = atoi ( port );
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal = LDAP_SUCCESS;
+
+ if ( config_value_is_null( attrname, port, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (nPort > LDAP_PORT_MAX || nPort <= 0 ) {
+ retVal = LDAP_OPERATIONS_ERROR;
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: %d is invalid, ports must range from 1 to %d",
+ attrname, nPort, LDAP_PORT_MAX );
+ }
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapdFrontendConfig->secureport = nPort;
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+
+int
+config_set_SSLclientAuth( const char *attrname, char *value, char *errorbuf, int apply ) {
+
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ retVal = LDAP_OPERATIONS_ERROR;
+ }
+ /* first check the value, return an error if it's invalid */
+ else if ( strcasecmp (value, "off") != 0 &&
+ strcasecmp (value, "allowed") != 0 &&
+ strcasecmp (value, "required")!= 0 ) {
+ retVal = LDAP_OPERATIONS_ERROR;
+ if( errorbuf )
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: unsupported value: %s", attrname, value );
+ return retVal;
+ }
+ else if ( !apply ) {
+ /* return success now, if we aren't supposed to apply the change */
+ return retVal;
+ }
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ if ( !strcasecmp( value, "off" )) {
+ slapdFrontendConfig->SSLclientAuth = SLAPD_SSLCLIENTAUTH_OFF;
+ }
+ else if ( !strcasecmp( value, "allowed" )) {
+ slapdFrontendConfig->SSLclientAuth = SLAPD_SSLCLIENTAUTH_ALLOWED;
+ }
+ else if ( !strcasecmp( value, "required" )) {
+ slapdFrontendConfig->SSLclientAuth = SLAPD_SSLCLIENTAUTH_REQUIRED;
+ }
+ else {
+ retVal = LDAP_OPERATIONS_ERROR;
+ if( errorbuf )
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: unsupported value: %s", attrname, value );
+ }
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_set_ssl_check_hostname(const char *attrname, char *value,
+ char *errorbuf, int apply)
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff(attrname,
+ value,
+ &(slapdFrontendConfig->ssl_check_hostname),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+int
+config_set_localhost( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->localhost) );
+ slapdFrontendConfig->localhost = slapi_ch_strdup ( value );
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_listenhost( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->listenhost) );
+ slapdFrontendConfig->listenhost = slapi_ch_strdup ( value );
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_securelistenhost( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->securelistenhost) );
+ slapdFrontendConfig->securelistenhost = slapi_ch_strdup ( value );
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_srvtab( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->srvtab) );
+ ldap_srvtab = slapi_ch_strdup ( value );
+ slapdFrontendConfig->srvtab = slapi_ch_strdup ( value );
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_sizelimit( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ Slapi_Backend *be;
+ char *cookie;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ int sizelimit = atoi ( value );
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( sizelimit < -1 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "%s: %d is too small",
+ attrname, sizelimit );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if (apply) {
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapdFrontendConfig->sizelimit= sizelimit;
+ g_set_defsize (sizelimit);
+ cookie = NULL;
+ be = slapi_get_first_backend(&cookie);
+ while (be) {
+ be->be_sizelimit = slapdFrontendConfig->sizelimit;
+ be = slapi_get_next_backend(cookie);
+ }
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ((void **)&cookie);
+
+ }
+ return retVal;
+}
+
+int
+config_set_pw_storagescheme( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ struct pw_scheme *new_scheme = NULL;
+ char * scheme_list = NULL;
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ scheme_list = plugin_get_pwd_storage_scheme_list(PLUGIN_LIST_PWD_STORAGE_SCHEME);
+
+ new_scheme = pw_name2scheme(value);
+ if ( new_scheme == NULL) {
+ if ( scheme_list != NULL ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid scheme - %s. Valid schemes are: %s",
+ attrname, value, scheme_list );
+ } else {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid scheme - %s (no pwdstorage scheme"
+ " plugin loaded)",
+ attrname, value);
+ }
+ retVal = LDAP_OPERATIONS_ERROR;
+ slapi_ch_free_string(&scheme_list);
+ return retVal;
+ }
+ else if ( new_scheme->pws_enc == NULL )
+ {
+ /* For example: the NS-MTA-MD5 password scheme is for comparision only and for backward
+ compatibility with an Old Messaging Server that was setting passwords in the
+ directory already encrypted. The scheme cannot and don't encrypt password if
+ they are in clear. We don't take it */
+
+ if ( scheme_list != NULL ) {
+ sprintf( errorbuf,
+ "pw_storagescheme: invalid encoding scheme - %s\nValid values are: %s\n", value, scheme_list );
+ }
+ retVal = LDAP_UNWILLING_TO_PERFORM;
+ slapi_ch_free_string(&scheme_list);
+ return retVal;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ free_pw_scheme(slapdFrontendConfig->pw_storagescheme);
+ slapdFrontendConfig->pw_storagescheme = new_scheme;
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ slapi_ch_free_string(&scheme_list);
+
+ return retVal;
+}
+
+
+int
+config_set_pw_change( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->pw_policy.pw_change),
+ errorbuf,
+ apply);
+
+ if (retVal == LDAP_SUCCESS) {
+ /* LP: Update ACI to reflect the value ! */
+ if (apply)
+ pw_mod_allowchange_aci(!slapdFrontendConfig->pw_policy.pw_change &&
+ !slapdFrontendConfig->pw_policy.pw_must_change);
+ }
+
+ return retVal;
+}
+
+
+int
+config_set_pw_history( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->pw_policy.pw_history),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+
+int
+config_set_pw_must_change( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->pw_policy.pw_must_change),
+ errorbuf,
+ apply);
+
+ if (retVal == LDAP_SUCCESS) {
+ /* LP: Update ACI to reflect the value ! */
+ if (apply)
+ pw_mod_allowchange_aci(!slapdFrontendConfig->pw_policy.pw_change &&
+ !slapdFrontendConfig->pw_policy.pw_must_change);
+ }
+
+ return retVal;
+}
+
+
+int
+config_set_pwpolicy_local( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->pwpolicy_local),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+int
+config_set_pw_syntax( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->pw_policy.pw_syntax),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+
+int
+config_set_pw_minlength( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, minLength = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ minLength = atoi(value);
+ if ( minLength < 2 || minLength > 512 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "password minimum length \"%s\" is invalid. "
+ "The minimum length must range from 2 to 512.",
+ value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapdFrontendConfig->pw_policy.pw_minlength = minLength;
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+
+ return retVal;
+}
+
+int
+config_set_pw_maxfailure( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, maxFailure = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ maxFailure = atoi(value);
+ if ( maxFailure <= 0 || maxFailure > 32767 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "password maximum retry \"%s\" is invalid. "
+ "Password maximum failure must range from 1 to 32767",
+ value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapdFrontendConfig->pw_policy.pw_maxfailure = maxFailure;
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+
+ return retVal;
+}
+
+
+
+int
+config_set_pw_inhistory( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, history = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ history = atoi(value);
+ if ( history < 2 || history > 24 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "password history length \"%s\" is invalid. "
+ "The password history must range from 2 to 24",
+ value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapdFrontendConfig->pw_policy.pw_inhistory = history;
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+
+ return retVal;
+}
+
+
+int
+config_set_pw_lockduration( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ long duration = 0; /* in minutes */
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* in seconds */
+ duration = strtol (value, NULL, 0);
+
+ if ( duration <= 0 || duration > (MAX_ALLOWED_TIME_IN_SECS - current_time()) ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "password lockout duration \"%s\" seconds is invalid. ",
+ value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply ) {
+ slapdFrontendConfig->pw_policy.pw_lockduration = duration;
+ }
+
+ return retVal;
+}
+
+
+int
+config_set_pw_resetfailurecount( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ long duration = 0; /* in minutes */
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* in seconds */
+ duration = strtol (value, NULL, 0);
+ if ( duration < 0 || duration > (MAX_ALLOWED_TIME_IN_SECS - current_time()) ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "password reset count duration \"%s\" seconds is invalid. ",
+ value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply ) {
+ slapdFrontendConfig->pw_policy.pw_resetfailurecount = duration;
+ }
+
+ return retVal;
+}
+
+int
+config_set_pw_is_global_policy( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->pw_is_global_policy),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+int
+config_set_pw_exp( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ /* password policy is disabled in DirLite. */
+ if ( config_is_slapd_lite() ) {
+ if ( NULL != value && strcasecmp(value, "off") != 0 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, LITE_PW_EXP_ERR );
+ retVal = LDAP_UNWILLING_TO_PERFORM;
+ return retVal;
+ }
+ }
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->pw_policy.pw_exp),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+int
+config_set_pw_unlock( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->pw_policy.pw_unlock),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+int
+config_set_pw_lockout( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->pw_policy.pw_lockout),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+int
+config_set_pw_gracelimit( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, gracelimit = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ gracelimit = atoi(value);
+ if ( gracelimit < 0 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "password grace limit \"%s\" is invalid.",
+ value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapdFrontendConfig->pw_policy.pw_gracelimit = gracelimit;
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+
+ return retVal;
+}
+
+
+int
+config_set_lastmod( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ Slapi_Backend *be = NULL;
+ char *cookie;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->lastmod),
+ errorbuf,
+ apply);
+
+ if ( retVal == LDAP_SUCCESS && apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ cookie = NULL;
+ be = slapi_get_first_backend (&cookie);
+ while (be) {
+ be->be_lastmod = slapdFrontendConfig->lastmod;
+ be = slapi_get_next_backend (cookie);
+ }
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+
+ slapi_ch_free ((void **)&cookie);
+
+ }
+
+ return retVal;
+}
+
+
+int
+config_set_nagle( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->nagle),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+int
+config_set_accesscontrol( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->accesscontrol),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+
+int
+config_set_return_exact_case( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->return_exact_case),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+int
+config_set_result_tweak( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->result_tweak),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+int
+config_set_security( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->security),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+static int
+config_set_onoff ( const char *attrname, char *value, int *configvalue,
+ char *errorbuf, int apply )
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( strcasecmp ( value, "on" ) != 0 &&
+ strcasecmp ( value, "off") != 0 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid value \"%s\". Valid values are \"on\" or \"off\".",
+ attrname, value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ) {
+ /* we can return now if we aren't applying the changes */
+ return retVal;
+ }
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ if ( strcasecmp ( value, "on" ) == 0 ) {
+ *configvalue = LDAP_ON;
+ }
+ else if ( strcasecmp ( value, "off" ) == 0 ) {
+ *configvalue = LDAP_OFF;
+ }
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ return retVal;
+}
+
+int
+config_set_readonly( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->readonly),
+ errorbuf,
+ apply );
+
+ return retVal;
+}
+
+
+int
+config_set_schemacheck( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->schemacheck),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+int
+config_set_ds4_compatible_schema( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->ds4_compatible_schema),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+int
+config_set_schema_ignore_trailing_spaces( const char *attrname, char *value,
+ char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->schema_ignore_trailing_spaces),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+int
+config_set_enquote_sup_oc( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff ( attrname,
+ value,
+ &(slapdFrontendConfig->enquote_sup_oc),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+int
+config_set_rootdn( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->rootdn) );
+ slapdFrontendConfig->rootdn = slapi_dn_normalize (slapi_ch_strdup ( value ) );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_rootpw( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *hashedpw = NULL;
+ struct pw_scheme *is_hashed = NULL;
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (!apply) {
+ return retVal;
+ }
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->rootpw) );
+
+ is_hashed = pw_val2scheme ( value, NULL, 0 );
+
+ if ( is_hashed ) {
+ slapdFrontendConfig->rootpw = slapi_ch_strdup ( value );
+ free_pw_scheme(is_hashed);
+ }
+ else {
+ hashedpw = (slapdFrontendConfig->rootpwstoragescheme->pws_enc)(value);
+ slapdFrontendConfig->rootpw = slapi_ch_strdup ( hashedpw );
+ }
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ return retVal;
+}
+
+
+int
+config_set_rootpwstoragescheme( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ struct pw_scheme *new_scheme = NULL;
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ new_scheme = pw_name2scheme ( value );
+ if (new_scheme == NULL ) {
+ char * scheme_list = plugin_get_pwd_storage_scheme_list(PLUGIN_LIST_PWD_STORAGE_SCHEME);
+ if ( scheme_list != NULL ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid scheme - %s. Valid schemes are: %s",
+ attrname, value, scheme_list );
+ } else {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid scheme - %s (no pwdstorage scheme"
+ " plugin loaded)", attrname, value);
+ }
+ slapi_ch_free_string(&scheme_list);
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ free_pw_scheme(slapdFrontendConfig->rootpwstoragescheme);
+ slapdFrontendConfig->rootpwstoragescheme = new_scheme;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+
+ return retVal;
+}
+
+/*
+ * kexcoff: to replace default initialization in FrontendConfig_init()
+ */
+int config_set_storagescheme() {
+
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ struct pw_scheme *new_scheme = NULL;
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ new_scheme = pw_name2scheme("SSHA");
+ free_pw_scheme(slapdFrontendConfig->pw_storagescheme);
+ slapdFrontendConfig->pw_storagescheme = new_scheme;
+
+ new_scheme = pw_name2scheme("SSHA");
+ slapdFrontendConfig->rootpwstoragescheme = new_scheme;
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+
+ return ( new_scheme == NULL );
+
+}
+
+#ifndef _WIN32
+int
+config_set_localuser( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ( (void **) &slapdFrontendConfig->localuser );
+ slapdFrontendConfig->localuser = slapi_ch_strdup ( value );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+
+}
+#endif /* _WIN32 */
+
+int
+config_set_workingdir( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( PR_Access ( value, PR_ACCESS_EXISTS ) != 0 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Working directory \"%s\" does not exist.", value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+ if ( PR_Access ( value, PR_ACCESS_WRITE_OK ) != 0 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Working directory \"%s\" is not writeable.", value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->workingdir = slapi_ch_strdup ( value );
+#ifdef _WIN32
+ dostounixpath(slapdFrontendConfig->workingdir);
+#endif /* _WIN32 */
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_instancedir( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( PR_Access ( value, PR_ACCESS_READ_OK ) != 0 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Directory \"%s\" is not accessible.", value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->instancedir = slapi_ch_strdup ( value );
+#ifdef _WIN32
+ dostounixpath(slapdFrontendConfig->instancedir);
+#endif /* _WIN32 */
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+
+ /* Set the slapd type also */
+ config_set_slapd_type ();
+
+ /* Set the configdir if not set */
+ if (!slapdFrontendConfig->configdir)
+ {
+ char newdir[MAXPATHLEN+1];
+ PR_snprintf ( newdir, sizeof(newdir), "%s/%s",
+ slapdFrontendConfig->instancedir, CONFIG_SUBDIR_NAME);
+ retVal = config_set_configdir(attrname, newdir, errorbuf, apply);
+ }
+ }
+ return retVal;
+}
+
+/* alias of encryption key and certificate files is now retrieved through */
+/* calls to psetFullCreate() and psetGetAttrSingleValue(). See ssl.c, */
+/* where this function is still used to set the global variable */
+int
+config_set_encryptionalias( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->encryptionalias) );
+
+ slapdFrontendConfig->encryptionalias = slapi_ch_strdup ( value );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_threadnumber( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, threadnum = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ threadnum = atoi ( value );
+
+ if ( threadnum < 1 || threadnum > 65535 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "%s: invalid value %d, maximum thread number must range from 1 to 65535", attrname, threadnum );
+ retVal = LDAP_OPERATIONS_ERROR;
+ }
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ /* max_threads = threadnum; */
+ slapdFrontendConfig->threadnumber = threadnum;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_maxthreadsperconn( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, maxthreadnum = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ maxthreadnum = atoi ( value );
+
+ if ( maxthreadnum < 1 || maxthreadnum > 65535 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "%s: invalid value %d, maximum thread number per connection must range from 1 to 65535", attrname, maxthreadnum );
+ retVal = LDAP_OPERATIONS_ERROR;
+ }
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ /* max_threads_per_conn = maxthreadnum; */
+ slapdFrontendConfig->maxthreadsperconn = maxthreadnum;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+#if !defined(_WIN32) && !defined(AIX)
+#include <sys/resource.h>
+int
+config_set_maxdescriptors( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, nValue = 0;
+ int maxVal = 65535;
+ struct rlimit rlp;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ nValue = atoi ( value );
+ if ( 0 == getrlimit( RLIMIT_NOFILE, &rlp ) ) {
+ maxVal = (int)rlp.rlim_max;
+ }
+
+ /* DirLite: limit the number of concurent connections by limiting
+ * maxdescriptors.
+ */
+
+ if ( config_is_slapd_lite() && nValue > SLAPD_LITE_MAXDESCRIPTORS ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, LITE_MAXDESCRIPTORS_ERR );
+ retVal = LDAP_UNWILLING_TO_PERFORM;
+ nValue = SLAPD_LITE_MAXDESCRIPTORS;
+ }
+
+ if ( nValue < 1 || nValue > maxVal ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "%s: invalid value %d, maximum file descriptors must range from 1 to %d (the current process limit)",
+ attrname, nValue, maxVal );
+ if ( nValue < 1 ) {
+ retVal = LDAP_OPERATIONS_ERROR;
+ } else {
+ nValue = maxVal;
+ retVal = LDAP_UNWILLING_TO_PERFORM;
+ }
+ }
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->maxdescriptors = nValue;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+
+}
+#endif /* !_WIN32 && !AIX */
+
+int
+config_set_conntablesize( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, nValue = 0;
+ int maxVal = 65535;
+#ifndef _WIN32
+ struct rlimit rlp;
+#endif
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ nValue = atoi ( value );
+
+#ifdef _WIN32
+ if ( nValue < 1 || nValue > 0xfffffe ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "%s: invalid value %d, connection table size must range from 1 to 0xfffffe", attrname, nValue );
+ retVal = LDAP_OPERATIONS_ERROR;
+ }
+#elif !defined(AIX)
+ if ( 0 == getrlimit( RLIMIT_NOFILE, &rlp ) ) {
+ maxVal = (int)rlp.rlim_max;
+ }
+
+ if ( nValue < 1 || nValue > maxVal ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "%s: invalid value %d, connection table size must range from 1 to %d (the current process maxdescriptors limit)",
+ attrname, nValue, maxVal );
+ if ( nValue < 1 ) {
+ retVal = LDAP_OPERATIONS_ERROR;
+ } else {
+ nValue = maxVal;
+ retVal = LDAP_UNWILLING_TO_PERFORM;
+ }
+ }
+#endif
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->conntablesize = nValue;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+
+}
+
+int
+config_set_reservedescriptors( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, nValue = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ nValue = atoi ( value );
+
+ if ( nValue < 1 || nValue > 65535 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "%s: invalid value %d, reserved file descriptors must range from 1 to 65535", attrname, nValue );
+ retVal = LDAP_OPERATIONS_ERROR;
+ }
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->reservedescriptors = nValue;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+
+}
+
+
+
+int
+config_set_ioblocktimeout( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, nValue = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ nValue = atoi ( value );
+
+#if defined(IRIX)
+ /* on IRIX poll can only handle timeouts up to
+ 2147483 without failing, cap it at 30 minutes */
+
+ if ( nValue > SLAPD_DEFAULT_IOBLOCK_TIMEOUT ) {
+ nValue = SLAPD_DEFAULT_IOBLOCK_TIMEOUT;
+ }
+#endif /* IRIX */
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->ioblocktimeout = nValue;
+ /* g_ioblock_timeout= nValue; */
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+
+}
+
+
+int
+config_set_idletimeout( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, nValue = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ nValue = atoi ( value );
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->idletimeout = nValue;
+ /* g_idle_timeout= nValue; */
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+
+}
+
+
+int
+config_set_groupevalnestlevel( const char *attrname, char * value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, nValue = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ nValue = atoi ( value );
+
+ if ( nValue < 1 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid value %d, must be a positive number",
+ attrname, nValue );
+ }
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->groupevalnestlevel = nValue;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+
+}
+
+int
+config_set_defaultreferral( const char *attrname, struct berval **value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_is_slapd_lite() ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, LITE_DEFAULT_REFERRAL_ERR );
+ retVal = LDAP_UNWILLING_TO_PERFORM;
+ return retVal;
+ }
+
+ if ( config_value_is_null( attrname, (char *)value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ g_set_default_referral( value );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_userat( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free( (void **) &(slapdFrontendConfig->userat) );
+ slapdFrontendConfig->userat = slapi_ch_strdup(value);
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_timelimit( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, nVal = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ Slapi_Backend *be = NULL;
+ char *cookie;
+
+ *errorbuf = 0;
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ nVal = atoi(value);
+ if ( nVal < 0 ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid value %d", attrname, nVal );
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ g_set_deftime ( nVal );
+ slapdFrontendConfig->timelimit = nVal;
+ be = slapi_get_first_backend (&cookie);
+ while (be) {
+ be->be_timelimit = slapdFrontendConfig->timelimit;
+ be = slapi_get_next_backend (cookie);
+ }
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+
+ slapi_ch_free ((void **)&cookie);
+ }
+ return retVal;
+}
+
+int
+config_set_useroc( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->useroc) );
+ slapdFrontendConfig->useroc = slapi_ch_strdup( value );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+
+int
+config_set_accesslog( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ retVal = log_update_accesslogdir ( value, apply );
+
+ if ( retVal != LDAP_SUCCESS ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Cannot open accesslog directory \"%s\", client accesses will "
+ "not be logged.", value );
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->accesslog) );
+ slapdFrontendConfig->accesslog = slapi_ch_strdup ( value );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_errorlog( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ retVal = log_update_errorlogdir ( value, apply );
+
+ if ( retVal != LDAP_SUCCESS ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Cannot open errorlog directory \"%s\", errors will "
+ "not be logged.", value );
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->errorlog) );
+ slapdFrontendConfig->errorlog = slapi_ch_strdup ( value );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+int
+config_set_auditlog( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ retVal = log_update_auditlogdir ( value, apply );
+
+ if ( retVal != LDAP_SUCCESS ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "Cannot open auditlog directory \"%s\"", value );
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ( (void **) &(slapdFrontendConfig->auditlog) );
+ slapdFrontendConfig->auditlog = slapi_ch_strdup ( value );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+int
+config_set_pw_maxage( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ long age;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* age in seconds */
+ age = strtol(value, NULL, 0 );
+ if ( age <= 0 || age > (MAX_ALLOWED_TIME_IN_SECS - current_time()) ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "password maximum age \"%s\" seconds is invalid. ",
+ value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply ) {
+ slapdFrontendConfig->pw_policy.pw_maxage = age;
+ }
+ return retVal;
+}
+
+int
+config_set_pw_minage( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ long age;
+ char *endPtr = NULL;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* age in seconds */
+ age = strtol(value, &endPtr, 0 );
+ /* endPtr should never be NULL, but we check just in case; if the
+ value contains no digits, or a string that does not begin with
+ a valid digit (e.g. "z2"), the days will be 0, and endPtr will
+ point to the beginning of value; if days contains at least 1
+ valid digit string, endPtr will point to the character after
+ the end of the first valid digit string in value. Example:
+ value = " 2 3 " endPtr will point at the space character
+ between the 2 and the 3. So, we should be able to simply
+ check to see if the character at *(endPtr - 1) is a digit.
+ */
+ if ( (age < 0) ||
+ (age > (MAX_ALLOWED_TIME_IN_SECS - current_time())) ||
+ (endPtr == NULL) || (endPtr == value) || !isdigit(*(endPtr-1)) ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "password minimum age \"%s\" seconds is invalid. ",
+ value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+
+ if ( apply ) {
+ slapdFrontendConfig->pw_policy.pw_minage = age;
+ }
+ return retVal;
+}
+
+int
+config_set_pw_warning( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ long sec;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* in seconds */
+ sec = strtol(value, NULL, 0);
+ if (sec < 0) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "password warning age \"%s\" seconds is invalid, password warning "
+ "age must be >= 0 seconds",
+ value );
+ retVal = LDAP_OPERATIONS_ERROR;
+ return retVal;
+ }
+ /* translate to seconds */
+ if ( apply ) {
+ slapdFrontendConfig->pw_policy.pw_warning = sec;
+ }
+ return retVal;
+}
+
+
+
+int
+config_set_errorlog_level( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, level = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ level = atoi ( value );
+ level |= LDAP_DEBUG_ANY;
+
+#ifdef _WIN32
+ *module_ldap_debug = level;
+#else
+ slapd_ldap_debug = level;
+#endif
+ slapdFrontendConfig->errorloglevel = level;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+
+int
+config_set_accesslog_level( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS, level = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 1 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ level = atoi ( value );
+ g_set_accesslog_level ( level );
+ slapdFrontendConfig->accessloglevel = level;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return retVal;
+}
+
+/* set the referral-mode url (which puts us into referral mode) */
+int config_set_referral_mode(const char *attrname, char *url, char *errorbuf, int apply)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ slapdFrontendConfig->refer_mode=REFER_MODE_OFF;
+ if ( config_is_slapd_lite() ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, LITE_REFERRAL_MODE_ERR );
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ if ((!url) || (!url[0])) {
+ strcpy(errorbuf, "referral url must have a value");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->refer_url = slapi_ch_strdup(url);
+ slapdFrontendConfig->refer_mode = REFER_MODE_ON;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return LDAP_SUCCESS;
+}
+
+int
+config_set_versionstring( const char *attrname, char *version, char *errorbuf, int apply ) {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ((!version) || (!version[0])) {
+ strcpy(errorbuf, "versionstring must have a value");
+ return LDAP_OPERATIONS_ERROR;
+ }
+ if (apply) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->versionstring = slapi_ch_strdup(version);
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return LDAP_SUCCESS;
+}
+
+
+
+
+#define config_copy_strval( s ) s ? slapi_ch_strdup (s) : NULL;
+
+int
+config_get_port(){
+ int retVal;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->port;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+
+}
+
+char *
+config_get_workingdir() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapi_ch_strdup(slapdFrontendConfig->workingdir);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+char *
+config_get_versionstring() {
+
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapi_ch_strdup(slapdFrontendConfig->versionstring);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+
+}
+
+
+char *
+config_get_buildnum(void)
+{
+ return slapi_ch_strdup(BUILD_NUM);
+}
+
+int
+config_get_secureport() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->secureport;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_SSLclientAuth() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->SSLclientAuth;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_ssl_check_hostname()
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ return slapdFrontendConfig->ssl_check_hostname;
+}
+
+
+char *
+config_get_localhost() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval ( slapdFrontendConfig->localhost );
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+
+}
+
+char *
+config_get_listenhost() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval ( slapdFrontendConfig->listenhost );
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+char *
+config_get_securelistenhost() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval( slapdFrontendConfig->securelistenhost );
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+char *
+config_get_srvtab() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->srvtab);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_get_sizelimit() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->sizelimit;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+char *
+config_get_pw_storagescheme() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal = 0;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->pw_storagescheme->pws_name);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_pw_change() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_change;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_pw_history() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_history;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+
+int
+config_get_pw_must_change() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_must_change;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_pw_syntax() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_syntax;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+
+int
+config_get_pw_minlength() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_minlength;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_get_pw_maxfailure() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_maxfailure;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+ return retVal;
+
+}
+
+
+
+int
+config_get_pw_inhistory() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_inhistory;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+
+
+long
+config_get_pw_lockduration() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ long retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_lockduration;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+
+}
+
+
+long
+config_get_pw_resetfailurecount() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ long retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_resetfailurecount;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_get_pw_is_global_policy() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_is_global_policy;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_get_pw_exp() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_exp;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_pw_unlock() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_unlock;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_pw_lockout(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_lockout;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_pw_gracelimit() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal=0;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_gracelimit;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+
+}
+
+
+int
+config_get_lastmod(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->lastmod;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_enquote_sup_oc(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->enquote_sup_oc;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_nagle() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->nagle;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+return retVal; }
+
+
+int
+config_get_accesscontrol() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->accesscontrol;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_get_return_exact_case() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ retVal = slapdFrontendConfig->return_exact_case;
+
+ return retVal;
+}
+
+int
+config_get_result_tweak() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->result_tweak;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_get_security() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->security;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+ }
+
+int
+slapi_config_get_readonly() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->readonly;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+ }
+
+
+int
+config_get_schemacheck() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->schemacheck;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+ }
+
+int
+config_get_ds4_compatible_schema() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->ds4_compatible_schema;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+ }
+
+int
+config_get_schema_ignore_trailing_spaces() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->schema_ignore_trailing_spaces;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+ }
+
+char *
+config_get_rootdn() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval (slapdFrontendConfig->rootdn);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+char * slapi_get_rootdn() {
+ return config_get_rootdn();
+}
+
+char *
+config_get_rootpw() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval (slapdFrontendConfig->rootpw);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+char *
+config_get_rootpwstoragescheme() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->rootpwstoragescheme->pws_name);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+#ifndef _WIN32
+
+char *
+config_get_localuser() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->localuser);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+#endif /* _WIN32 */
+
+char *
+config_get_instancedir() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval( slapdFrontendConfig->instancedir );
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+/* alias of encryption key and certificate files is now retrieved through */
+/* calls to psetFullCreate() and psetGetAttrSingleValue(). See ssl.c, */
+/* where this function is still used to set the global variable */
+char *
+config_get_encryptionalias() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->encryptionalias);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_get_threadnumber() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->threadnumber;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_get_maxthreadsperconn(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->maxthreadsperconn;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+#if !defined(_WIN32) && !defined(AIX)
+int
+config_get_maxdescriptors() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->maxdescriptors;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+ return retVal;
+}
+
+#endif /* !_WIN32 && !AIX */
+
+int
+config_get_reservedescriptors(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->reservedescriptors;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+
+int
+config_get_ioblocktimeout(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->ioblocktimeout;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+ }
+
+
+int
+config_get_idletimeout(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->idletimeout;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_groupevalnestlevel(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->groupevalnestlevel;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+struct berval **
+config_get_defaultreferral() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ struct berval **refs;
+ int nReferrals = 0;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ /* count the number of referrals */
+ for ( nReferrals = 0;
+ slapdFrontendConfig->defaultreferral &&
+ slapdFrontendConfig->defaultreferral[nReferrals];
+ nReferrals++)
+ ;
+
+ refs = (struct berval **)
+ slapi_ch_malloc( (nReferrals + 1) * sizeof(struct berval *) );
+
+ /*terminate the end, and add the referrals backwards */
+ refs [nReferrals--] = NULL;
+
+ while ( nReferrals >= 0 ) {
+ refs[nReferrals] = (struct berval *) slapi_ch_malloc( sizeof(struct berval) );
+ refs[nReferrals]->bv_val =
+ config_copy_strval( slapdFrontendConfig->defaultreferral[nReferrals]->bv_val );
+ refs[nReferrals]->bv_len = slapdFrontendConfig->defaultreferral[nReferrals]->bv_len;
+ nReferrals--;
+ }
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return refs;
+}
+
+char *
+config_get_userat ( ){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval( slapdFrontendConfig->userat );
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_get_timelimit(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal= slapdFrontendConfig->timelimit;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+char*
+config_get_useroc(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->useroc );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+
+ return retVal;
+}
+
+char *
+config_get_accesslog(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->accesslog);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+char *
+config_get_errorlog( ){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->errorlog);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+
+}
+
+char *
+config_get_auditlog( ){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->auditlog);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+long
+config_get_pw_maxage() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ long retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_maxage;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+ return retVal;
+}
+
+long
+config_get_pw_minage(){
+
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ long retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_minage;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+long
+config_get_pw_warning() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ long retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->pw_policy.pw_warning;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+int
+config_get_errorlog_level(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->errorloglevel;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+
+/* return integer -- don't worry about locking similar to config_check_referral_mode
+ below */
+
+int
+config_get_accesslog_level(){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ retVal = slapdFrontendConfig->accessloglevel;
+
+ return retVal;
+}
+
+
+char *config_get_referral_mode(void)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *ret;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ ret = config_copy_strval(slapdFrontendConfig->refer_url);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return ret;
+}
+
+int
+config_get_conntablesize(void){
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->conntablesize;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+ }
+
+
+/* return yes/no without actually copying the referral url
+ we don't worry about another thread changing this value
+ since we now return an integer */
+int config_check_referral_mode(void)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ return(slapdFrontendConfig->refer_mode & REFER_MODE_ON);
+}
+
+
+int
+config_get_outbound_ldap_io_timeout(void)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->outbound_ldap_io_timeout;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+ return retVal;
+}
+
+int
+config_is_slapd_lite ()
+{
+ return ( SLAPD_FULL );
+}
+
+/* This function is called once at the startup time and no more */
+void
+config_set_slapd_type( )
+{
+ char *root = NULL;
+ char *s_root = NULL;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ if ( slapdFrontendConfig->instancedir )
+ s_root = root = slapi_ch_strdup ( slapdFrontendConfig->instancedir );
+
+ if ( (root = strrchr( root, '/' )) != NULL ) {
+ *root = '\0';
+ }
+ slapdFrontendConfig->slapd_type = 0;
+ slapdFrontendConfig->versionstring = SLAPD_VERSION_STR;
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ( (void **) &s_root );
+}
+
+int
+config_set_maxbersize( const char *attrname, char *value, char *errorbuf, int apply )
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ) {
+ return retVal;
+ }
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+
+ slapdFrontendConfig->maxbersize = atoi(value);
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ return retVal;
+}
+
+unsigned long
+config_get_maxbersize()
+{
+ unsigned long maxbersize;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ maxbersize = slapdFrontendConfig->maxbersize;
+ if(maxbersize==0)
+ maxbersize= 2 * 1024 * 1024; /* Default: 2Mb */
+ return maxbersize;
+
+}
+
+int
+config_set_max_filter_nest_level( const char *attrname, char *value,
+ char *errorbuf, int apply )
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ) {
+ return retVal;
+ }
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->max_filter_nest_level = atoi(value);
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ return retVal;
+}
+
+int
+config_get_max_filter_nest_level()
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = slapdFrontendConfig->max_filter_nest_level;
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+ return retVal;
+}
+
+
+char *
+config_get_basedn() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval ( slapdFrontendConfig->certmap_basedn );
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_set_basedn ( const char *attrname, char *value, char *errorbuf, int apply ) {
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ) {
+ return retVal;
+ }
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free ( (void **) &slapdFrontendConfig->certmap_basedn );
+
+ slapdFrontendConfig->certmap_basedn = slapi_dn_normalize( slapi_ch_strdup(value) );
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ return retVal;
+}
+
+char *
+config_get_configdir()
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *retVal;
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ retVal = config_copy_strval(slapdFrontendConfig->configdir);
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ return retVal;
+}
+
+int
+config_set_configdir(const char *attrname, char *value, char *errorbuf, int apply)
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (!apply) {
+ return retVal;
+ }
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free((void **)&slapdFrontendConfig->configdir);
+
+ slapdFrontendConfig->configdir = slapi_ch_strdup(value);
+
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ return retVal;
+}
+
+char **
+config_get_errorlog_list()
+{
+ return log_get_loglist(SLAPD_ERROR_LOG);
+}
+
+char **
+config_get_accesslog_list()
+{
+ return log_get_loglist(SLAPD_ACCESS_LOG);
+}
+
+char **
+config_get_auditlog_list()
+{
+ return log_get_loglist(SLAPD_AUDIT_LOG);
+}
+
+int
+config_set_accesslogbuffering(const char *attrname, char *value, char *errorbuf, int apply)
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff(attrname,
+ value,
+ &(slapdFrontendConfig->accesslogbuffering),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+int
+config_set_csnlogging(const char *attrname, char *value, char *errorbuf, int apply)
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff(attrname,
+ value,
+ &(slapdFrontendConfig->csnlogging),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+int
+config_get_csnlogging()
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ return slapdFrontendConfig->csnlogging;
+}
+
+int
+config_set_attrname_exceptions(const char *attrname, char *value, char *errorbuf, int apply)
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff(attrname,
+ value,
+ &(slapdFrontendConfig->attrname_exceptions),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+int
+config_get_attrname_exceptions()
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ return slapdFrontendConfig->attrname_exceptions;
+}
+
+int
+config_set_hash_filters(const char *attrname, char *value, char *errorbuf, int apply)
+{
+ int val = 0;
+ int retVal = LDAP_SUCCESS;
+
+ retVal = config_set_onoff(attrname,
+ value,
+ &val,
+ errorbuf,
+ apply);
+
+ if (retVal == LDAP_SUCCESS) {
+ set_hash_filters(val);
+ }
+
+ return retVal;
+}
+
+int
+config_get_hash_filters()
+{
+ return 0; /* for now */
+}
+
+int
+config_set_rewrite_rfc1274(const char *attrname, char *value, char *errorbuf, int apply)
+{
+ int retVal = LDAP_SUCCESS;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ retVal = config_set_onoff(attrname,
+ value,
+ &(slapdFrontendConfig->rewrite_rfc1274),
+ errorbuf,
+ apply);
+
+ return retVal;
+}
+
+
+/* we don't worry about another thread changing this flag since it is an
+ integer */
+int
+config_get_rewrite_rfc1274()
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int retVal;
+
+ retVal = slapdFrontendConfig->rewrite_rfc1274;
+ return retVal;
+}
+
+
+static int
+config_set_schemareplace( const char *attrname, char *value, char *errorbuf, int apply )
+{
+ int retVal = LDAP_SUCCESS;
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ retVal = LDAP_OPERATIONS_ERROR;
+ } else {
+ /*
+ * check that the value is one we allow.
+ */
+ if ( 0 != strcasecmp( value, CONFIG_SCHEMAREPLACE_STR_OFF ) &&
+ 0 != strcasecmp( value, CONFIG_SCHEMAREPLACE_STR_ON ) &&
+ 0 != strcasecmp( value, CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY )) {
+ retVal = LDAP_OPERATIONS_ERROR;
+ if( errorbuf ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "unsupported value: %s", value );
+ }
+ }
+ }
+
+ if ( LDAP_SUCCESS == retVal && apply ) {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapi_ch_free( (void **)&slapdFrontendConfig->schemareplace );
+ slapdFrontendConfig->schemareplace = slapi_ch_strdup( value );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+
+ return retVal;
+}
+
+
+int
+config_set_outbound_ldap_io_timeout( const char *attrname, char *value,
+ char *errorbuf, int apply )
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( config_value_is_null( attrname, value, errorbuf, 0 )) {
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( apply ) {
+ CFG_LOCK_WRITE(slapdFrontendConfig);
+ slapdFrontendConfig->outbound_ldap_io_timeout = atoi( value );
+ CFG_UNLOCK_WRITE(slapdFrontendConfig);
+ }
+ return LDAP_SUCCESS;
+}
+
+
+/*
+ * This function is intended to be used from the dse code modify callback. It
+ * is "optimized" for that case because it takes a berval** of values, which is
+ * currently what is used by ldapmod to hold the values. We could easily switch
+ * this to take a Slapi_Value array or even a Slapi_Attr. Most config params
+ * have simple config_set_XXX functions which take a char* argument holding the
+ * value. The log_set_XXX functions have an additional parameter which
+ * discriminates the log to use. The config parameters with types CONFIG_SPECIAL_XXX
+ * require special handling to set their values.
+ */
+int
+config_set(const char *attr, struct berval **values, char *errorbuf, int apply)
+{
+ int ii = 0;
+ int retval = LDAP_SUCCESS;
+ struct config_get_and_set *cgas = 0;
+ cgas = (struct config_get_and_set *)PL_HashTableLookup(confighash, attr);
+ if (!cgas)
+ {
+#if 0
+ debugHashTable(attr);
+#endif
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, "Unknown attribute %s will be ignored", attr);
+ slapi_log_error(SLAPI_LOG_FATAL, "config", "%s\n", errorbuf);
+ return retval;
+ }
+
+ switch (cgas->config_var_type)
+ {
+ case CONFIG_SPECIAL_REFERRALLIST:
+ if (NULL == values) /* special token which means to remove referrals */
+ {
+ struct berval val;
+ struct berval *vals[2] = {0, 0};
+ vals[0] = &val;
+ val.bv_val = REFERRAL_REMOVE_CMD;
+ val.bv_len = strlen(REFERRAL_REMOVE_CMD);
+ retval = config_set_defaultreferral(attr, vals, errorbuf, apply);
+ }
+ else
+ {
+ retval = config_set_defaultreferral(attr, values, errorbuf, apply);
+ }
+ break;
+
+ default:
+ for (ii = 0; !retval && values && values[ii]; ++ii)
+ {
+ if (cgas->setfunc)
+ retval = (cgas->setfunc)(cgas->attr_name,
+ (char *)values[ii]->bv_val, errorbuf, apply);
+ else if (cgas->logsetfunc)
+ retval = (cgas->logsetfunc)(cgas->attr_name,
+ (char *)values[ii]->bv_val, cgas->whichlog,
+ errorbuf, apply);
+ else
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "config_set: the attribute %s is read only; ignoring new value %s\n",
+ attr, values[ii]->bv_val, 0);
+ }
+ break;
+ }
+
+ return retval;
+}
+
+static void
+config_set_value(
+ Slapi_Entry *e,
+ struct config_get_and_set *cgas,
+ void **value
+)
+{
+ struct berval **values = 0;
+ char *sval = 0;
+
+ /* for null values, just set the attr value to the empty
+ string */
+ if (!value) {
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "");
+ return;
+ }
+
+ switch (cgas->config_var_type) {
+ case CONFIG_ON_OFF: /* convert 0,1 to "off","on" */
+ slapi_entry_attr_set_charptr(e, cgas->attr_name,
+ (value && *((int *)value)) ? "on" : "off");
+ break;
+
+ case CONFIG_INT:
+ if (value)
+ slapi_entry_attr_set_int(e, cgas->attr_name, *((int *)value));
+ else
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "");
+ break;
+
+ case CONFIG_LONG:
+ if (value)
+ slapi_entry_attr_set_long(e, cgas->attr_name, *((long *)value));
+ else
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "");
+ break;
+
+ case CONFIG_STRING:
+ slapi_entry_attr_set_charptr(e, cgas->attr_name,
+ (value && *((char **)value)) ?
+ *((char **)value) : "");
+ break;
+
+ case CONFIG_CHARRAY:
+ values = strarray2bervalarray((const char **)*((char ***)value));
+ if (!values) {
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "");
+ } else {
+ slapi_entry_attr_replace(e, cgas->attr_name, values);
+ bervalarray_free(values);
+ }
+ break;
+
+ case CONFIG_SPECIAL_REFERRALLIST:
+ /* referral list is already an array of berval* */
+ if (value)
+ slapi_entry_attr_replace(e, cgas->attr_name, (struct berval**)*value);
+ else
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "");
+ break;
+
+ case CONFIG_CONSTANT_STRING:
+ PR_ASSERT(value); /* should be a constant value */
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, (char*)value);
+ break;
+
+ case CONFIG_CONSTANT_INT:
+ PR_ASSERT(value); /* should be a constant value */
+ slapi_entry_attr_set_int(e, cgas->attr_name, (int)value);
+ break;
+
+ case CONFIG_SPECIAL_SSLCLIENTAUTH:
+ if (!value) {
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "off");
+ break;
+ }
+
+ if (*((int *)value) == SLAPD_SSLCLIENTAUTH_ALLOWED) {
+ sval = "allowed";
+ } else if (*((int *)value) == SLAPD_SSLCLIENTAUTH_REQUIRED) {
+ sval = "required";
+ } else {
+ sval = "off";
+ }
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, sval);
+ break;
+
+ case CONFIG_STRING_OR_OFF:
+ slapi_entry_attr_set_charptr(e, cgas->attr_name,
+ (value && *((char **)value)) ?
+ *((char **)value) : "off");
+ break;
+
+ case CONFIG_STRING_OR_EMPTY:
+ slapi_entry_attr_set_charptr(e, cgas->attr_name,
+ (value && *((char **)value)) ?
+ *((char **)value) : "");
+ break;
+
+ case CONFIG_STRING_OR_UNKNOWN:
+ slapi_entry_attr_set_charptr(e, cgas->attr_name,
+ (value && *((char **)value)) ?
+ *((char **)value) : "unknown");
+ break;
+
+ case CONFIG_SPECIAL_ERRORLOGLEVEL:
+ if (value) {
+ int ival = *(int *)value;
+ ival &= ~LDAP_DEBUG_ANY;
+ slapi_entry_attr_set_int(e, cgas->attr_name, ival);
+ }
+ else
+ slapi_entry_attr_set_charptr(e, cgas->attr_name, "");
+ break;
+
+ default:
+ PR_ASSERT(0); /* something went horribly wrong . . . */
+ break;
+ }
+
+ return;
+}
+
+/*
+ * Fill in the given slapi_entry with the config attributes and values
+ */
+int
+config_set_entry(Slapi_Entry *e)
+{
+ int ii = 0;
+ int tablesize = sizeof(ConfigList)/sizeof(ConfigList[0]);
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ /*
+ * Avoid recursive calls to the readers/writer
+ * lock as it causes deadlock under stress. Each
+ * individual config get function acquires a read
+ * lock where necessary.
+ */
+
+ /*
+ * Pass 1: Values which do not have a get function.
+ */
+
+ CFG_LOCK_READ(slapdFrontendConfig);
+ for (ii = 0; ii < tablesize; ++ii) {
+ struct config_get_and_set *cgas = &ConfigList[ii];
+ void **value = 0;
+
+ PR_ASSERT(cgas);
+ value = cgas->config_var_addr;
+ PR_ASSERT(cgas->attr_name);
+
+ /* Skip values handled in pass 2 */
+ if (NULL == value && cgas->getfunc) {
+ continue;
+ }
+
+ config_set_value(e, cgas, value);
+ }
+ CFG_UNLOCK_READ(slapdFrontendConfig);
+
+ /*
+ * Pass 2: Values which do have a get function.
+ */
+ for (ii = 0; ii < tablesize; ++ii) {
+ struct config_get_and_set *cgas = &ConfigList[ii];
+ void **value = 0;
+ void *alloc_val;
+ int needs_free = 0;
+
+ PR_ASSERT(cgas);
+ value = cgas->config_var_addr;
+ PR_ASSERT(cgas->attr_name);
+
+ /* Skip values handled in pass 1 */
+ if (NULL != value || cgas->getfunc == NULL) {
+ continue;
+ }
+
+ alloc_val = (cgas->getfunc)();
+
+ value = &alloc_val; /* value must be address of pointer */
+ if (!isIntegralType(cgas->config_var_type))
+ needs_free = 1; /* get funcs must return alloc'd memory except for get
+ funcs which return a simple integral type e.g. int */
+
+ config_set_value(e, cgas, value);
+
+ if (needs_free && value) { /* assumes memory allocated by slapi_ch_Xalloc */
+ if (CONFIG_CHARRAY == cgas->config_var_type) {
+ charray_free(*((char ***)value));
+ } else {
+ slapi_ch_free(value);
+ }
+ }
+ }
+
+ return 1;
+}
diff --git a/ldap/servers/slapd/libmakefile b/ldap/servers/slapd/libmakefile
new file mode 100644
index 00000000..8eaf4604
--- /dev/null
+++ b/ldap/servers/slapd/libmakefile
@@ -0,0 +1,174 @@
+#
+# 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 libslapd
+#
+
+FLAG_LDAP_4SLAPD=true
+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 = $(OBJDIR)/servers/obj
+BINDIR = $(LIB_RELDIR)
+LIBDIR = $(OBJDIR)/lib
+ifndef INSTDIR
+INSTDIR = /netscape/server4/
+endif
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+ifndef LDAP_USE_OLD_DB
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+_ldap_db_depend:=$(DB_LIB_DEP)
+INCLUDES+=-I$(DB_INCLUDE)
+endif
+include $(LDAP_SRC)/nsdeps.mk
+
+INCLUDES += -I. -I$(MCOM_ROOT)/ldapserver/lib
+# uncomment the following to include support in slapd for hacky echo control
+#CFLAGS += -DSLAPD_ECHO_CONTROL
+CFLAGS+=$(SLCFLAGS)
+
+LIBSLAPD_OBJS=plugin_role.o getfilelist.o libglobs.o log.o ch_malloc.o entry.o pblock.o \
+ modutil.o schema.o attr.o value.o time.o dn.o \
+ filter.o filtercmp.o filterentry.o operation.o schemaparse.o pw.o \
+ backend.o defbackend.o ava.o charray.o regex.o \
+ str2filter.o dynalib.o plugin.o plugin_syntax.o plugin_mr.o \
+ slapi2nspr.o rwlock.o control.o plugin_internal_op.o \
+ result.o pw_retry.o agtmmap.o referral.o snmp_collator.o util.o \
+ dse.o errormap.o computed.o match.o fileio.o \
+ generation.o localhost.o ssl.o factory.o auditlog.o \
+ lenstr.o eventq.o uuid.o uniqueid.o uniqueidgen.o \
+ csngen.o utf8compare.o ntuserpin.o entrywsi.o valueset.o \
+ attrsyntax.o opshared.o add.o modify.o modrdn.o delete.o dl.o\
+ plugin_acl.o counters.o subentry.o object.o objset.o apibroker.o \
+ csn.o csnset.o slapd_plhash.o attrlist.o vattr.o bitset.o rdn.o \
+ mapping_tree.o backend_manager.o task.o resourcelimit.o \
+ bulk_import.o security_wrappers.o index_subsystem.o sasl_map.o
+
+ifeq ($(ARCH), AIX)
+ifeq ($(DEBUG), optimize)
+TEMP_CFLAGS = $(subst -O,,$(CFLAGS))
+$(OBJDEST)/vattr.o: vattr.c
+ $(CC) -o $(OBJDEST)/vattr.o -c $(TEMP_CFLAGS) $(MCC_INCLUDE) vattr.c
+endif
+endif
+ifeq ($(ARCH), WINNT)
+#find out why this isn't needed on UNIX
+DLL_LDFLAGS += $(NSPRLINK) /IMPLIB:$(LIBSLAPD)
+DLL_LDFLAGS += -def:"libslapd.def"
+LIBSLAPD_DEF = $(LDAP_SRC)/servers/slapd/libslapd.def
+SUBSYSTEM=windows
+
+LDAP_COMMON_EXTRALIBSLIST = libsi18n
+LDAP_COMMON_EXTRALIBS = $(addsuffix .$(LIB_SUFFIX), \
+ $(addprefix $(LDAP_LIBDIR)/, $(LDAP_COMMON_EXTRALIBSLIST)))
+LDAP_COMMON_LINK += libbase.$(LIB_SUFFIX)
+
+EXTRA_LIBS_DEP = $(SECURITY_DEP) $(NSPR_DEP) \
+ $(LDAP_COMMON_LIBS_DEP) $(LDAPSDK_DEP) \
+ $(LDAP_SDK_LIBSSLDAP_LIB_DEP) $(LIBLDAPU_DEP) $(_ldap_db_depend) \
+ $(SVRCORE_DEP) \
+ $(LDAP_COMMON_EXTRALIBS)
+
+EXTRA_LIBS += $(LDAPLINK) $(LIBSVRCORE) $(LIBSECURITY) $(LIBNSPR) \
+ $(LDAP_COMMON_LINK) \
+ $(LIBLDAPU) \
+ $(LDAP_COMMON_EXTRALIBS)
+
+# JCM - Warnings as Errors!
+CFLAGS += /WX
+else
+LDFLAGS = $(SSLLIBFLAG)
+EXTRA_LIBS_DEP = $(SECURITY_DEP) \
+ $(NSPR_DEP) $(LDAPSDK_DEP) $(SVRCORE_DEP) \
+ $(LDAP_LIBLDBM_DEP) $(LDAP_LIBAVL_DEP) $(LDAP_LIBLDIF_DEP) \
+ $(_ldap_db_depend) $(SVRCORE_DEP)
+EXTRA_LIBS = $(LDAP_LIBLITEKEY) -lavl -lldif \
+ $(SVRCORELINK) $(LDAPLINK) \
+ $(SECURITYLINK) $(NSPRLINK) \
+ $(ALIBS) $(DYNALIBS) $(THREADSLIB)
+endif
+ifeq ($(ARCH), AIX)
+LD=ld
+EXTRA_LIBS = $(LDAPLINK) $(SVRCORELINK) $(SECURITYLINK) $(NSPRLINK) \
+ $(LDAP_COMMON_LINK) \
+ $(LIBLDAPU) \
+ $(DYNALIBS) $(THREADSLIB) \
+ $(DLL_EXTRA_LIBS) \
+ $(LDAP_LIBLITEKEY)
+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 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
+
+#ifeq ($(ARCH), OSF1)
+#DLL_LDFLAGS=-shared -all -error_unresolved -taso -ySVRCORE_RegisterPinObj
+#EXTRA_LIBS += -lc
+#endif
+
+OBJS = $(addprefix $(OBJDEST)/, $(LIBSLAPD_OBJS))
+ERRORMAP.O = $(addprefix $(OBJDEST)/, errormap.o)
+
+all: $(OBJDEST) $(LIBDIR) $(BINDIR) $(BUILD_DEP) $(LIBSLAPD_DLL) $(LIBSLAPD_RELDLLS)
+
+static: $(OBJDEST) $(LIBDIR) $(LIBSLAPD)
+
+dummy:
+ echo $(LINK_DLL)
+ echo $(EXTRA_LIBS)
+
+clientSDK: static
+
+$(LIBSLAPD_DLL): $(EXTRA_LIBS_DEP) $(OBJS) $(LIBSLAPD_DEF)
+ $(LINK_DLL) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ -$(RM) $(OBJS)
+ -$(RM) $(LIBSLAPD_DLL)
+
+# compilation dependencies:
+
+$(ERRORMAP.O): $(DIRVERDIR)/dberrstrs.h
+
+$(DIRVERDIR)/dberrstrs.h: $(DB_INCLUDE)/db.h
+ifeq ($(ARCH), WINNT)
+ $(PERL) mkDBErrStrs.pl -nt -i $(DB_INCLUDE) -o $(DIRVERDIR)
+else
+ $(PERL) mkDBErrStrs.pl -i $(DB_INCLUDE) -o $(DIRVERDIR)
+endif
+
+ifeq ($(ARCH), WINNT)
+$(OBJS): $(OBJDEST)/%.o : %.c
+endif
+
+# Target to push the built binary to an installed server
+LIBSLAPD_PUSH = $(addprefix $(INSTDIR)/, bin/slapd/server/libslapd.dll)
+push: $(LIBSLAPD_PUSH)
+
+$(LIBSLAPD_PUSH): $(LIBSLAPD_DLL)
+ cp $(LIBSLAPD_DLL) $(LIBSLAPD_PUSH)
+
diff --git a/ldap/servers/slapd/libsh_stub/Makefile b/ldap/servers/slapd/libsh_stub/Makefile
new file mode 100644
index 00000000..d82833c0
--- /dev/null
+++ b/ldap/servers/slapd/libsh_stub/Makefile
@@ -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
+#
+#
+# GNU Makefile for libsh_stub.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
+
+OBJDEST = $(OBJDIR)/lib/libsh_stub
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+include $(LDAP_SRC)/nsdeps.mk
+
+
+LIBSH_STUB_C= libsh_stub.c
+
+SHARE_LIB = $(addprefix $(OBJDEST)/, libsh_stub.so)
+
+# share lib
+CFLAGS = -G $(SLCFLAGS)
+
+# link libmtmalloc.so when built on 5.8 or 5.9
+ifeq ($(ARCH), SOLARIS)
+ ifeq ($(NSOS_RELEASE), 5.8)
+ LINKFLAGS = -lmtmalloc
+ endif
+ ifeq ($(NSOS_RELEASE), 5.9)
+ LINKFLAGS = -lmtmalloc
+ endif
+ LIBSH_STUB = libsh_stub
+else
+ # do nothing on non-SOLARIS platforms
+ LIBSH_STUB = no_op
+endif
+
+all: $(LIBSH_STUB)
+
+.PHONY: libsh_stub no_op
+
+libsh_stub: $(OBJDEST) $(SHARE_LIB)
+
+$(SHARE_LIB): $(LIBSH_STUB_C)
+ $(CC) -o $(SHARE_LIB) $(CFLAGS) $(LIBSH_STUB_C) $(LINKFLAGS)
+
+no_op:
+ -@echo libsh_stub.so is not built on $(ARCH) platform
+
+$(OBJDEST) :
+ $(MKDIR) $@
+
+veryclean: clean
+
+clean:
+ $(RM) $(SHARE_LIB)
diff --git a/ldap/servers/slapd/libsh_stub/libsh_stub.c b/ldap/servers/slapd/libsh_stub/libsh_stub.c
new file mode 100644
index 00000000..56a08c9f
--- /dev/null
+++ b/ldap/servers/slapd/libsh_stub/libsh_stub.c
@@ -0,0 +1,7 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+int MemRegisterTask(void) { return 0; }
diff --git a/ldap/servers/slapd/libslapd.def b/ldap/servers/slapd/libslapd.def
new file mode 100644
index 00000000..072439a9
--- /dev/null
+++ b/ldap/servers/slapd/libslapd.def
@@ -0,0 +1,1147 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Directory Server 7 Utility Library'
+EXPORTS
+ slapd_log_error_proc @2
+ slapd_log_audit_proc @3
+ ldapi_init_extended_ops @4
+ audit_log_openf @5
+ slapi_log_error @6
+ slapi_log_access @7
+ g_set_detached @8
+ access_log_openf @9
+ error_log_openf @10
+ slapi_ch_strdup @11
+ slapi_ch_malloc @12
+ slapi_ch_calloc @13
+ slapi_ch_realloc @14
+ slapi_ch_free @15
+ slapi_sdn_scope_test @16
+ slapi_pblock_get @17
+ slapi_pblock_set @18
+ slapi_str2entry @19
+ slapi_entry2str @20
+ slapi_entry_alloc @21
+ slapi_entry_free @22
+ slapi_entry_dup @23
+ slapi_entry_get_dn @24
+ slapi_entry_set_dn @25
+ slapi_entry_attr_find @26
+ slapi_entry_first_attr @27
+ slapi_entry_next_attr @28
+ slapi_entry_attr_merge @29
+ slapi_entry_schema_check @30
+ slapi_entry_add_values @31
+ slapi_entry_delete_values @32
+ g_get_global_oc_nolock @34
+ config_set_maxbersize @35
+ g_get_global_lastmod @36
+ current_time @37
+ slapi_attr_free @38
+ attr_syntax_create @39
+ valueset_get_valuearray @40
+ attrlist_merge @41
+ attrlist_find @42
+ attrlist_delete @43
+ slapi_register_plugin @44
+ csn_max @45
+ slapi_dn_normalize @46
+ slapi_dn_ignore_case @47
+ slapi_dn_normalize_case @48
+ slapi_dn_parent @49
+ slapi_dn_issuffix @50
+ slapi_attr_get_valueset @51
+ slapi_read_buffer @52
+ slapi_write_buffer @53
+ add_control @54
+ pblock_init @56
+ pblock_init_common @57
+ slapi_pblock_get_common @58
+ slapi_valueset_count @59
+ slapi_mtn_get_backend_name @60
+ get_timestring @61
+ free_timestring @62
+ slapi_op_abandoned @63
+ slapi_filter_get_choice @64
+ slapi_filter_get_ava @65
+ slapi_filter_get_type @66
+ slapi_filter_get_subfilt @67
+ slapi_filter_list_first @68
+ slapi_filter_list_next @69
+ slapi_filter_join @70
+ slapi_filter_free @71
+ slapi_filter_test @72
+ slapi_access_allowed @73
+ slapi_acl_check_mods @74
+ dse_search @75
+ slapi_pw_find @76
+ send_read_referrals @77
+ ref_array_dup @78
+ ref_array_dup_free @79
+ slapi_dn_beparent @80
+ slapi_ldap_init @81
+ slapi_ldap_unbind @82
+ slapi_dn_isroot @83
+ slapi_dn_isbesuffix @84
+ slapi_value_new_berval @85
+ plugin_call_plugins @86
+ slapi_mtn_be_disable @87
+ slapi_be_new @88
+ get_operation_object_type @89
+ be_flushall @90
+ slapi_be_select @91
+ charray_free @92
+ charray_dup @93
+ slapi_str2filter @94
+ charray_add @95
+ value_done @96
+ rdn2ava @97
+ pw_encodevals @98
+ slapi_valueset_set_from_smod @99
+ ava_done @100
+ pw_name2scheme @101
+ generate_componentid @102
+ g_set_deftime @103
+ g_set_defsize @104
+ plugin_setup @105
+ slapi_new_mutex @106
+ slapi_destroy_mutex @107
+ slapi_lock_mutex @108
+ slapi_unlock_mutex @109
+ slapi_valueset_set_valueset @110
+ dse_modify @111
+ plugin_call_acl_plugin @112
+ get_filter @113
+ be_unbindall @114
+ plugin_call_exop_plugins @115
+ filter_normalize @116
+ plugin_call_acl_mods_access @117
+ normalize_oc @118
+ ref_adjust @119
+ config_get_maxbersize @120
+ entry_replace_values @121
+ filter_strcpy_special @122
+ be_addsuffix @123
+ slapi_be_getsuffix @124
+ slapi_entry_attr_hasvalue @125
+ sym_load @126
+ str2charray @127
+ charray_merge @128
+ libldap_init_debug_level @129
+ slapi_seq_callback @130
+ slapi_be_getentrypoint @131
+ write_audit_log_entry @132
+ rwl_new @133
+ slapi_send_ldap_search_entry @134
+ slapi_send_ldap_result @135
+ slapi_send_ldap_referral @136
+ g_log_init @137
+ slapi_get_first_backend @138
+ slapi_get_next_backend @139
+ be_cleanupall @140
+ slapi_attr_new @141
+ slapi_acl_verify_aci_syntax @142
+ plugin_call_acl_mods_update @143
+ plugin_call_acl_verify_syntax @144
+ poll_current_time @145
+ slapi_dn_isparent @146
+ freepmods @147
+ get_ldapmessage_controls @148
+ init_controls @149
+ slapi_control_present @150
+ plugin_closeall @151
+ plugin_startall @152
+ internal_res_callback @153
+ internal_srch_entry_callback @154
+ internal_ref_entry_callback @155
+ slapi_search_internal_callback @156
+ slapi_search_internal @157
+ slapi_modify_internal @158
+ normalize_mods2bvals @159
+ slapi_add_internal @160
+ slapi_delete_internal @161
+ slapi_modrdn_internal @162
+ slapi_compare_internal @163
+ slapi_free_search_results_internal @164
+ send_ldap_result @165
+ send_ldapv3_referral @166
+ send_ldap_referral @167
+ send_ldap_search_entry @168
+ slapi_mtn_be_enable @169
+ slapi_attr_get_oid_copy @170
+ set_db_default_result_handlers @171
+ g_get_num_bytes_sent @172
+ g_set_num_bytes_sent @173
+ g_get_num_entries_sent @174
+ g_set_num_entries_sent @175
+ g_get_num_sent_mutex @176
+ g_set_num_sent_mutex @177
+ g_get_default_referral @178
+ g_set_default_referral @179
+ slapi_ch_bvdup @180
+ rwl_free @181
+ get_server_dataversion @182
+ get_localhost_DNS @183
+ get_localhost_DN @184
+ slapi_pblock_new @185
+ slapi_pblock_destroy @186
+ slapi_ch_bvecdup @187
+ slapi_mr_filter_index @188
+ slapi_mr_indexer_create @189
+ slapi_berval_cmp @190
+ filter_print @191
+ write_controls @192
+ modify_schema_dse @193
+ read_schema_dse @194
+ attr_syntax_add @195
+ addlenstr @196
+ config_set_versionstring @197
+ slapi_entry_attr_replace @198
+ slapi_be_select_by_instance_name @199
+ slapd_ssl_init @200
+ slapd_SSL_client_init @201
+ format_localTime @202
+ parse_localTime @203
+ strntoul @204
+ time_plus_sec @205
+ read_localTime @206
+ get_entry @207
+ slapi_get_supported_controls_copy @208
+ attrlist_replace @209
+ update_pw_retry @210
+ g_get_global_snmp_vars @211
+ snmp_collator_start @212
+ snmp_collator_stop @213
+ config_set_schema_ignore_trailing_spaces @214
+ send_nobackend_ldap_result @215
+ set_dll_entry_points @216
+ slapi_add_entry_internal @217
+ dse_register_callback @218
+ slapi_entry_init @219
+ slapd_ldap_debug @220 DATA
+ slapd_ssl_init2 @221
+ slapd_SSL_client_bind_s @222
+ slapd_ssl_getCipherSuiteInfo @223
+ slapi_mods_dump @224
+ g_get_slapd_security_on @225
+ slapi_register_supported_control @226
+ slapi_get_supported_controls @227
+ slapi_register_supported_saslmechanism @228
+ slapi_get_supported_saslmechanisms_copy @229
+ slapi_get_supported_saslmechanisms @230
+ bervalarray_add_berval_fast @231
+ slapi_get_supported_extended_ops_copy @232
+ slapi_get_supported_extended_ops @233
+ slapi_be_logchanges @234
+ slapi_rdn_remove_attr @235
+ slapd_security_library_is_initialized @236
+ slapi_ch_bvfree @237
+ slapi_config_register_callback @238
+ slapi_entry_has_children @239
+ slapi_config_remove_callback @240
+ entry_apply_mods @241
+ slapi_entry_set_flag @242
+ slapi_entry_clear_flag @243
+ write_localTime @244
+ get_entry_object_type @245
+ factory_create_extension @246
+ factory_destroy_extension @247
+ factory_register_type @248
+ g_get_access_log @249
+ g_get_error_log @250
+ get_entry_point @251
+ set_snmp_interaction_row @252
+ slapi_attr_get_type @254
+ slapi_attr_get_oid @255
+ slapi_attr_get_values @256
+ slapi_attr_get_flags @257
+ slapi_attr_flag_is_set @258
+ slapi_attr_value_cmp @259
+ plugin_syntax_find @260
+ plugin_syntax2oid @261
+ plugin_call_syntax_filter_ava @262
+ plugin_call_syntax_filter_sub @263
+ slapi_call_syntax_values2keys @264
+ slapi_call_syntax_assertion2keys_ava @265
+ slapi_call_syntax_assertion2keys_sub @266
+ slapi_attr_value_find @267
+ slapi_attr_type2plugin @268
+ slapd_re_comp @269
+ slapd_re_exec @270
+ slapd_re_modw @271
+ slapd_re_subs @272
+ FrontendConfig_init @273
+ slapi_entry_get_dn_const @274
+ slapi_register_object_extension @275
+ slapi_get_object_extension @276
+ slapi_be_delete_onexit @277
+ slapi_be_exist @278
+ slapi_sdn_add_rdn @279
+ slapi_mods_add_string @280
+ lenstr_free @281
+ lenstr_new @282
+ plugin_call_syntax_get_compare_fn @283
+ slapi_attr_type_cmp @284
+ slapi_attr_basetype @285
+ snmp_collator_update @286
+ escape_string @287
+ eq_start @288
+ eq_stop @289
+ slapi_rdn2typeval @290
+ slapi_entry_rdn_values_present @291
+ slapi_entry_attr_get_long @292
+ slapi_dn_plus_rdn @293
+ ref_array_replace @294
+ slapi_setbit_uchar @295
+ slapi_unsetbit_uchar @296
+ slapi_isbitset_uchar @297
+ slapi_setbit_int @298
+ slapi_unsetbit_int @299
+ referrals_free @300
+ slapi_isbitset_int @301
+ slapi_be_private @302
+ ref_array_moddn @304
+ g_set_current_conn_count_mutex @305
+ g_get_current_conn_count_mutex @306
+ g_get_current_conn_count @307
+ g_increment_current_conn_count @308
+ g_decrement_current_conn_count @309
+ g_set_accesslog_level @310
+ slapi_entry_add_rdn_values @311
+ slapd_re_init @312
+ slapd_re_lock @313
+ slapd_re_unlock @314
+ escape_string_with_punctuation @315
+ getFrontendConfig @316
+ log_set_numlogsperdir @317
+ log_set_logsize @318
+ log_set_rotationtime @319
+ log_set_rotationtimeunit @320
+ log_set_maxdiskspace @321
+ log_set_mindiskspace @322
+ log_set_expirationtime @323
+ log_set_expirationtimeunit @324
+ log_update_accesslogdir @325
+ log_update_errorlogdir @326
+ dse_remove_callback @327
+ log_get_loglist @328
+ log_update_auditlogdir @329
+ g_get_audit_log @330
+ dse_new @331
+ dse_deletedse @332
+ dse_read_file @333
+ slapi_attr_get_bervals_copy @334
+ strarray2str @335
+ operation_out_of_disk_space @336
+ dse_delete @337
+ oc_lock_read @338
+ oc_lock_write @339
+ oc_unlock @340
+ slapi_entry_attr_set_long @341
+ slapi_entry_attr_delete @342
+ slapi_entry_attr_get_charptr @343
+ slapi_entry_attr_set_charptr @344
+ slapi_entry_attr_get_int @345
+ slapi_get_global_syntax_plugins @346
+ slapi_get_global_mr_plugins @347
+ slapi_new_condvar @348
+ slapi_destroy_condvar @349
+ slapi_wait_condvar @350
+ slapi_notify_condvar @351
+ defbackend_init @352
+ defbackend_get_backend @353
+ log_set_logging @354
+ pwpolicy_make_response_control @355
+ delete_passwdPolicy @356
+ g_get_user_backend @357
+ new_passwdPolicy @358
+ slapi_dn_normalize_to_end @359
+ slapi_ch_free_string @360
+ send_ldap_search_entry_ext @361
+ send_ldap_result_ext @362
+ slapd_pr_strerror @363
+ slapd_system_strerror @364
+ cool_charray_free @365
+ cool_charray_dup @366
+ ldapi_register_extended_op @367
+ config_set_attrname_exceptions @368
+ g_get_deftime @369
+ g_get_defsize @370
+ pw_val2scheme @371
+ slapi_attr_add_value @372
+ be_getconfigdn @373
+ be_getmonitordn @374
+ be_nbackends_public @375
+ entry_add_rdn_csn @376
+ slapd_versatile_strerror @377
+ config_set_enquote_sup_oc @378
+ config_get_enquote_sup_oc @379
+ log_access_flush @380
+ be_writeconfig @381
+ plugin_extended_op_oid2string @382
+ slapi_eq_get_arg @383
+ g_set_shutdown @384
+ g_get_shutdown @385
+ compute_init @386
+ compute_terminate @387
+ slapi_compute_add_evaluator @388
+ be_new_internal @389
+ slapi_schema_expand_objectclasses @390
+ slapi_compute_add_search_rewriter @391
+ g_get_global_mrl @392
+ g_set_global_mrl @393
+ slapi_matchingrule_new @394
+ slapi_matchingrule_free @395
+ slapi_matchingrule_register @396
+ slapi_matchingrule_unregister @397
+ slapi_matchingrule_get @398
+ slapi_matchingrule_set @399
+ config_set_port @400
+; Available for reuse @401
+ config_set_secureport @402
+ config_set_SSLclientAuth @403
+ config_set_workingdir @404
+ config_set_localhost @405
+ config_set_listenhost @406
+ config_set_securelistenhost @407
+ config_set_srvtab @408
+ config_set_sizelimit @409
+ config_set_pw_storagescheme @410
+ slapi_filter_test_ext @411
+ config_set_pw_change @412
+ config_set_pw_history @413
+ config_set_pw_must_change @414
+ config_set_pw_syntax @415
+ config_set_pw_minlength @416
+ config_set_pw_maxfailure @417
+ config_set_pw_inhistory @418
+ config_set_pw_lockduration @419
+ config_set_pw_resetfailurecount @420
+ config_set_pw_exp @421
+ config_set_pw_unlock @422
+ config_set_pw_lockout @423
+ config_set_lastmod @424
+ config_set_nagle @425
+ config_set_accesscontrol @426
+ config_set_result_tweak @427
+ config_set_pw_gracelimit @428
+; Available for reuse @429
+ config_set_security @430
+ config_set_pwpolicy_local @431
+ config_set_readonly @432
+ config_set_schemacheck @433
+ config_set_rootdn @434
+ config_set_rootpw @435
+ config_set_rootpwstoragescheme @436
+ slapi_build_control @437
+ slapi_entry_get_ndn @438
+ dse_unset_dont_ever_write_dse_files @439
+ config_set_instancedir @440
+ config_set_encryptionalias @441
+ config_set_threadnumber @442
+ config_set_maxthreadsperconn @443
+ slapi_eq_repeat @444
+ config_set_reservedescriptors @445
+ config_set_ioblocktimeout @446
+ config_set_idletimeout @447
+ config_set_groupevalnestlevel @448
+ config_set_defaultreferral @449
+ config_set_userat @450
+ config_set_timelimit @451
+ config_set_useroc @452
+ config_set_accesslog @453
+ config_set_errorlog @454
+ config_set_auditlog @455
+ config_set_pw_maxage @456
+ config_set_pw_minage @457
+ config_set_pw_warning @458
+ config_set_errorlog_level @459
+ config_set_accesslog_level @460
+ compute_rewrite_search_filter @461
+ slapi_entry_get_sdn_const @462
+ dse_set_dont_ever_write_dse_files @463
+ slapi_eq_once @464
+ config_get_port @465
+ config_get_pw_is_global_policy @466
+ config_get_secureport @467
+ config_get_SSLclientAuth @468
+ config_get_workingdir @469
+ config_get_localhost @470
+ config_get_listenhost @471
+ config_get_securelistenhost @472
+ config_get_srvtab @473
+ config_get_sizelimit @474
+ config_get_pw_storagescheme @475
+ slapi_eq_cancel @476
+ config_get_pw_change @477
+ config_get_pw_history @478
+ config_get_pw_must_change @479
+ config_get_pw_syntax @480
+ config_get_pw_minlength @481
+ config_get_pw_maxfailure @482
+ config_get_pw_inhistory @483
+ config_get_pw_lockduration @484
+ config_get_pw_resetfailurecount @485
+ config_get_pw_exp @486
+ config_get_pw_unlock @487
+ config_get_pw_lockout @488
+ config_get_lastmod @489
+ config_get_nagle @490
+ config_get_accesscontrol @491
+ config_get_result_tweak @492
+ config_get_conntablesize @493
+ config_get_pw_gracelimit @494
+ config_get_security @495
+ slapi_config_get_readonly @496
+ config_get_schemacheck @497
+ config_get_rootdn @498
+ config_get_rootpw @499
+ config_get_rootpwstoragescheme @500
+ slapi_entry_set_sdn @501
+ slapi_sdn_copy @502
+ config_set_basedn @503
+ config_get_instancedir @504
+ config_get_encryptionalias @505
+ config_get_threadnumber @506
+ config_get_maxthreadsperconn @507
+ config_get_basedn @508
+ config_get_reservedescriptors @509
+ config_get_ioblocktimeout @510
+ config_get_idletimeout @511
+ config_get_groupevalnestlevel @512
+ config_get_defaultreferral @513
+ config_get_userat @514
+ config_get_timelimit @515
+ config_get_useroc @516
+ config_get_accesslog @517
+ config_get_errorlog @518
+ config_get_auditlog @519
+ config_get_pw_maxage @520
+ config_get_pw_minage @521
+ config_get_pw_warning @522
+ config_get_errorlog_level @523
+ config_get_accesslog_level @524
+ slapi_sdn_compare @525
+ slapi_sdn_dup @526
+ slapi_sdn_set_dn_passin @527
+ slapi_entry_get_sdn @528
+ slapi_sdn_get_ndn_len @529
+ charray_inlist @530
+ config_set_referral_mode @531
+ config_get_referral_mode @532
+ config_check_referral_mode @533
+ attr_set_deletion_csn @534
+ slapi_mod_dump @535
+ config_is_slapd_lite @536
+ config_set_slapd_type @537
+ config_get_versionstring @538
+ slapi_is_rootdse @539
+ slapi_find_matching_paren @540
+ str2simple @541
+ substr_dn_normalize @542
+ get_data_source @543
+ slapi_sdn_get_backend_parent @544
+ slapi_sdn_new_dn_passin @545
+ slapi_sdn_isempty @546
+ slapi_sdn_isparent @547
+ attr_value_find_wsi @548
+ entry_computed_attr_init @549
+ slapi_attr_init @550
+ slapi_value_init @551
+ valueset_isempty @552
+ valueset_add_string @553
+ attr_done @554
+ operation_clear_flag @555
+ operation_set_flag @556
+ slapi_sdn_get_rdn @557
+ slapi_sdn_set_rdn @558
+ slapi_sdn_set_parent @559
+ slapi_entry_delete_string @560
+ attr_get_deletion_csn @561
+ entry_add_present_attribute_wsi @562
+ slapi_value_get_length @563
+ operation_parameters_dup @564
+ operation_parameters_free @565
+ operation_is_flag_set @566
+ counters_as_entry @567
+ counters_to_errors_log @568
+ counters_as_entry @567
+ counters_to_errors_log @568
+ slapi_value_new_string @569
+ charray_utf8_inlist @570
+ charray_get_index @571
+; LDAPU ENTRY POINTS
+ ldapu_member_certificate_match @580
+ ref_register_callback @581
+ ref_remove_callback @582
+ slapi_is_encoded @583
+ slapi_encode @584
+; UniqueID ENTRY POINTS
+ slapi_uniqueIDNew @585
+ slapi_uniqueIDDestroy @586
+ slapi_uniqueIDCompare @587
+ slapi_uniqueIDFormat @588
+ slapi_uniqueIDScan @589
+ slapi_uniqueIDIsUUID @590
+ slapi_uniqueIDSize @591
+ slapi_uniqueIDDup @592
+ uniqueIDGenInit @593
+ uniqueIDGenCleanup @594
+ slapi_uniqueIDCompareString @595
+ slapi_uniqueIDGenerate @596
+ slapi_uniqueIDGenerateString @597
+ slapi_uniqueIDGenerateFromName @600
+ slapi_uniqueIDGenerateFromNameString @601
+; MORE ENTRY ENTRY POINTS
+ slapi_entry_get_uniqueid @602
+ slapi_entry_set_uniqueid @603
+ slapi_entry_merge_values_sv @604
+; Slapi_DN entry points
+ slapi_sdn_new @605
+ slapi_sdn_init @606
+ slapi_sdn_new_dn_byval @607
+ slapi_sdn_new_ndn_byval @608
+; slapi_sdn_new_cndn_byval @609
+ slapi_sdn_new_dn_byref @610
+ slapi_sdn_new_ndn_byref @611
+; slapi_sdn_new_cndn_byref @612
+ slapi_sdn_set_dn_byval @613
+ slapi_sdn_set_dn_byref @614
+ slapi_sdn_set_ndn_byval @615
+ slapi_sdn_set_ndn_byref @616
+; slapi_sdn_set_cndn_byval @617
+; slapi_sdn_set_cndn_byref @618
+ slapi_sdn_done @619
+ slapi_sdn_free @620
+ slapi_sdn_get_dn @621
+ slapi_sdn_get_ndn @622
+; slapi_sdn_get_cndn @623
+ slapi_sdn_get_parent @624
+; Slapi_Mod & Slapi_Mods entry points
+ slapi_mods_init @625
+ slapi_mods_insert_at @626
+ slapi_mods_insert_before @627
+ slapi_mods_insert_after @628
+ slapi_mods_add @629
+ slapi_mods_add_ldapmod @630
+ slapi_mods_add_modbvps @631
+ slapi_mods_remove @632
+ slapi_mods_get_first_mod @633
+ slapi_mods_get_next_mod @634
+ slapi_mods_iterator_backone @635
+ slapi_mods_get_ldapmods_byref @636
+ slapi_mods_get_num_mods @637
+ slapi_mod_init @638
+ slapi_mod_add_value @639
+ slapi_mod_remove_value @640
+ slapi_mod_get_first_value @641
+ slapi_mod_get_next_value @642
+ slapi_mod_get_num_values @643
+ entry_purge_state_information @644
+ attr_set_csn @645
+ entry_get_dncsn @646
+ entry_get_dncsnset @647
+ entry_add_dncsn @648
+ value_contains_csn @649
+ csnset_get_previous_csn @650
+ task_init @651
+ attrlist_merge_valuearray @652
+ slapi_value_new_value @653
+ entry_get_maxcsn @654
+ entry_set_maxcsn @655
+ entry_assign_operation_csn @656
+ slapi_operation_set_csngen_handler @657
+ slapi_operation_set_replica_attr_handler @658
+ slapi_operation_get_replica_attr @659
+ plugin_call_syntax_filter_sub_sv @664
+ plugin_call_syntax_filter_ava_sv @665
+ slapi_pw_find_sv @666
+ csn_new_by_string @667
+ csn_set_replicaid @668
+ valuearray_get_bervalarray @670
+ slapi_call_syntax_values2keys_sv @671
+ valuearray_init_bervalarray @672
+ slapi_valueset_free @673
+ slapi_entry_add_values_sv @674
+ entry_set_csn @675
+ csn_as_string @676
+ entry_attr_find_wsi @678
+ csn_get_time @679
+ csn_new @680
+ csn_set_time @681
+ csn_get_seqnum @682
+ csn_free @683
+ slapi_search_internal_get_entry @684
+ csn_compare @685
+ csn_set_seqnum @686
+ csn_dup @687
+ slapi_valueset_first_value @688
+ slapi_valueset_next_value @689
+ slapi_valueset_done @690
+ slapi_utf8StrToLower @691
+ slapi_utf8ToLower @692
+ slapi_utf8isUpper @693
+ slapi_utf8StrToUpper @694
+ slapi_utf8ToUpper @695
+ slapi_utf8isLower @696
+ slapi_utf8casecmp @697
+ slapi_utf8ncasecmp @698
+ slapi_has8thBit @699
+ slapi_sdn_init_dn_byref @700
+ slapi_sdn_init_dn_byval @701
+ slapi_sdn_init_dn_passin @702
+ slapi_attr_first_value @703
+ slapi_attr_next_value @704
+ slapi_value_get_berval @705
+ slapi_attr_get_numvalues @706
+ value_get_csn @707
+ value_update_csn @708
+ slapi_value_set_berval @709
+ slapi_mods_init_byref @711
+ slapi_mods_init_passin @712
+ slapi_value_new @713
+ slapi_value_free @714
+ value_add_csn @715
+ value_remove_csn @716
+ slapi_sdn_issuffix @717
+ slapi_mods_new @718
+ slapi_mods_free @719
+ slapi_mods_insert_smod_at @720
+ slapi_mods_insert_smod_before @721
+ slapi_mods_insert_smod_after @722
+ slapi_mods_add_smod @723
+ slapi_mods_get_first_smod @724
+ slapi_mods_get_next_smod @725
+ slapi_mod_new @726
+ slapi_mod_init_byref @727
+ slapi_mod_init_passin @728
+ slapi_value_init_string @729
+ slapi_mod_get_ldapmod_passout @730
+ slapi_mod_get_type @731
+ slapi_mod_get_operation @732
+ slapi_mod_set_type @733
+ slapi_mod_set_operation @734
+ slapi_mod_get_ldapmod_byref @735
+ slapi_mod_free @736
+ csn_time_difference @737
+ slapi_mod_isvalid @738
+ slapi_entry_size @739
+ attr_first_deleted_value @740
+ attr_next_deleted_value @741
+ slapi_mods_get_ldapmods_passout @742
+ slapi_value_init_berval @743
+ entry_add_dncsn_ext @744
+ slapi_value_set @745
+ operation_get_csn @750
+ entry_apply_mods_wsi @751
+ slapi_mod_done @752
+ slapi_mods_done @753
+ operation_set_csn @754
+; entry_update_deleted_attribute @755
+ entry_first_deleted_attribute @756
+ entry_next_deleted_attribute @757
+; config_get_storestateinfo @758
+; config_set_storestateinfo @759
+ slapi_value_set_string @760
+ slapi_is_loglevel_set @761
+ operation_set_target_spec @762
+ operation_set_target_spec_str @763
+ operation_get_target_spec @764
+ operation_set_abandoned_op @765
+ operation_get_abandoned_op @766
+ slapi_value_get_string @767
+ slapi_value_get_int @768
+ slapi_value_set_int @769
+ slapi_add_internal_pb @770
+ slapi_add_internal_set_pb @771
+ slapi_modify_internal_set_pb @772
+ slapi_modify_internal_pb @773
+ slapi_modrdn_internal_pb @774
+ slapi_rename_internal_set_pb @775
+ slapi_delete_internal_set_pb @776
+ slapi_delete_internal_pb @777
+ slapi_search_internal_pb @778
+ slapi_search_internal_set_pb @779
+ slapi_search_internal_callback_pb @780
+ plugin_build_operation_action_bitmap @781
+ plugin_get_server_plg @782
+ add_pwd_control @783
+ pw_mod_allowchange_aci @784
+ do_add @785
+ do_modify @786
+ do_delete @787
+ do_modrdn @788
+ op_shared_search @789
+ slapi_mod_init_byval @790
+ slapi_add_entry_internal_set_pb @792
+ config_set_return_exact_case @793
+ slapi_rdn_new @794
+ slapi_rdn_new_dn @795
+ slapi_rdn_new_sdn @796
+ slapi_rdn_new_rdn @797
+ slapi_rdn_init @798
+ slapi_rdn_init_dn @799
+ slapi_rdn_init_sdn @800
+ slapi_rdn_init_rdn @801
+ slapi_rdn_set_dn @802
+ slapi_rdn_set_sdn @803
+ slapi_rdn_set_rdn @804
+ slapi_rdn_free @805
+ slapi_rdn_done @806
+ slapi_rdn_get_first @807
+ slapi_rdn_get_next @808
+ slapi_rdn_get_index @809
+ slapi_rdn_contains @810
+ slapi_rdn_add @811
+ slapi_rdn_remove_index @812
+ slapi_rdn_remove @813
+ slapi_rdn_isempty @814
+ slapi_rdn_get_num_components @815
+ slapi_rdn_compare @816
+ slapi_rdn_get_rdn @817
+ slapi_rdn_get_nrdn @819
+ slapi_value_dup @820
+ slapi_value_set_value @821
+ rel2abspath @822
+ slapi_value_compare @823
+ attr_get_present_values @824
+ dl_get @825
+ dl_new @826
+ dl_free @827
+ dl_init @828
+ dl_cleanup @829
+ dl_add @830
+ dl_get_first @831
+ dl_get_next @832
+ dl_delete @833
+ dl_get_count @834
+ slapi_entry2mods @837
+ slapi_mods2entry @838
+ operation_parameters_new @839
+ operation_parameters_done @840
+ slapi_ch_start_recording @841
+ slapi_ch_stop_recording @842
+ snmp_as_entry @843
+ slapi_filter_compare @844
+; probably temporary:
+ set_hash_filters @845
+ operation_new @846
+ operation_free @847
+ operation_set_type @848
+ slapi_mods_add_mod_values @849
+ slapi_sdn_init_ndn_byref @850
+ slapi_sdn_init_ndn_byval @851
+ objset_new @852
+ objset_delete @853
+ objset_add_obj @854
+ objset_remove_obj @855
+ objset_find @856
+ objset_first_obj @857
+ objset_next_obj @858
+ objset_is_empty @859
+ object_new @860
+ object_acquire @861
+ object_release @862
+ object_get_data @863
+ slapi_UTF8STRTOLOWER @864
+ slapi_UTF8TOLOWER @865
+ slapi_UTF8ISUPPER @866
+ slapi_UTF8STRTOUPPER @867
+ slapi_UTF8TOUPPER @868
+ slapi_UTF8ISLOWER @869
+ slapi_UTF8CASECMP @870
+ slapi_UTF8NCASECMP @871
+ slapi_apib_get_interface @872
+ slapi_apib_unregister @873
+ slapi_apib_register @874
+ slapi_attr_types_equivalent @875
+ dse_read_next_entry @895
+ config_set_entry @896
+ config_set @897
+ init_schema_dse @898
+ PL_HashTableLookup_const @899
+; dse_add_entry_pb @900
+ vattr_init @901
+ vattr_cleanup @902
+ slapi_vattrspi_register @903
+ plugin_get_by_name @904
+ objset_size @905
+ slapi_attr_dup @906
+ slapi_entry_add_value @907
+ slapi_entry_add_string @908
+ be_create_instance @909
+ be_remove_instance @910
+ mapping_tree_init @911
+ slapi_mapping_tree_select @912
+ slapi_sdn_isgrandparent @913
+ config_set_storagescheme @914
+ slapi_berval_get_string_copy @918
+ slapi_vattr_value_compare @919
+ slapi_vattr_value_compare_sp @920
+ slapi_vattr_values_get_sp @921
+ slapi_vattr_values_get @922
+ slapi_vattr_values_free @923
+ slapi_vattr_list_attrs @924
+ slapi_vattr_attrs_free @925
+ slapi_vattrspi_regattr @926
+ slapi_be_get_instance_info @927
+ slapi_be_set_instance_info @928
+ slapi_be_setentrypoint @929
+ plugin_get_dn @930
+ operation_get_type @931
+ slapi_be_set_flag @932
+ slapi_be_is_flag_set @933
+ free_pw_scheme @934
+ slapi_vattrspi_add_type @935
+ mapping_tree_free @936
+ slapi_get_mapping_tree_node_by_dn @937
+ slapi_get_mapping_tree_node_configdn @938
+ slapi_valueset_init @939
+ slapi_valueset_add_value @940
+ slapi_filter_get_attribute_type @941
+ slapi_filter_apply @942
+ slapi_attr_syntax_normalize @943
+ charray_remove @946
+; csn_next_in_sequence @947
+ csngen_new @948
+ csngen_free @949
+ csngen_new_csn @950
+ csngen_abort_csn @951
+ csngen_adjust_time @952
+ csngen_is_local_csn @953
+ csngen_register_callbacks @954
+ csngen_unregister_callbacks @955
+ csngen_update_time @956
+ csngen_get_state @957
+ csn_init_by_csn @958
+ csn_init_by_string @959
+ csn_get_replicaid @960
+ csn_string_size @961
+ csn_as_attr_option_string @962
+ slapi_get_mapping_tree_node_root @963
+ slapi_get_mapping_tree_config_root @964
+ mapping_tree_get_extension_type @965
+ slapi_mapping_tree_node_is_set @966
+ slapi_entry_flag_is_set @967
+ slapi_task_status_changed @968
+ slapi_valueset_new @969
+ slapi_be_issuffix @970
+ slapi_be_addsuffix @971
+ slapi_reslimit_register @972
+ slapi_reslimit_get_integer_limit @973
+ reslimit_cleanup @974
+ search_register_reslimits @975
+ bind_credentials_set @976
+ bind_credentials_clear @977
+ pw_add_allowchange_aci @978
+ slapi_valueset_add_value_ext @979
+ is_abspath @980
+ slapi_dup_control @981
+ slapi_get_first_suffix @982
+ slapi_get_next_suffix @983
+ slapi_is_root_suffix @984
+ slapi_be_get_name @985
+ slapi_entry2str_with_options @986
+ slapi_destructive_rename @987
+ slapi_moddn_get_newdn @988
+ plugin_get_default_component_id @989
+ slapi_be_gettype @990
+ csnset_get_first_csn @991
+ csnset_get_next_csn @992
+ value_get_csnset @993
+ entry_add_deleted_attribute_wsi @994
+ attr_add_deleted_value @995
+ slapi_disconnect_server @996
+ eq_init @997
+ slapi_set_object_extension @998
+ task_shutdown @999
+ slapi_mtn_set_referral @1000
+ slapi_mtn_set_state @1001
+ slapi_mtn_get_referral @1002
+ slapi_mtn_get_state @1003
+ slapi_mtn_be_started @1004
+ slapi_mtn_be_stopping @1005
+ slapi_start_bulk_import @1006
+ slapi_stop_bulk_import @1007
+ slapi_import_entry @1008
+ slapi_entry_add_valueset @1009
+ vattr_typethang_get_flags @1010
+ vattr_typethang_get_name @1011
+ vattr_typethang_next @1012
+ vattr_typethang_first @1013
+ charray_subtract @1014
+ slapi_schema_list_attribute_names @1015
+ config_get_ds4_compatible_schema @1016
+ config_set_ds4_compatible_schema @1017
+ pw_apply_mods @1018
+ pw_set_componentID @1019
+ pw_get_componentID @1020
+ parse_genTime @1021
+ format_genTime @1022
+ be_set_sizelimit @1023
+ be_set_timelimit @1024
+ slapi_be_free @1025
+ slapi_be_Unlock @1026
+ slapi_task_log_status @1027
+ slapi_task_log_notice @1028
+ plugin_add_descriptive_attributes @1029
+
+ slapi_get_rootdn @1030
+ slapi_mtn_be_set_readonly @1031
+ slapi_be_set_readonly @1032
+ slapi_be_get_readonly @1033
+ slapi_op_get_type @1034
+ slapi_entry_attr_get_ulong @1035
+ slapi_entry_attr_get_uint @1036
+ slapi_entry_attr_set_int @1037
+ slapi_entry_attr_set_ulong @1038
+ slapi_entry_attr_set_uint @1039
+ slapi_value_get_ulong @1040
+ slapi_value_get_uint @1041
+
+ config_set_rewrite_rfc1274 @1042
+ config_get_rewrite_rfc1274 @1043
+ slapi_mapping_tree_find_backend_for_sdn @1044
+ slapi_register_backend_state_change @1045
+ slapi_unregister_backend_state_change @1046
+
+ slapd_ssl_handshakeCallback @1047
+ slapd_ssl_badCertHook @1048
+ slapd_ssl_peerCertificate @1049
+ slapd_ssl_getChannelInfo @1050
+ pblock_done @1051
+ pw_rever_decode @1052
+ slapd_ssl_listener_is_initialized @1053
+ op_shared_log_error_access @1054
+ slapd_ssl_importFD @1055
+ slapd_ssl_resetHandshake @1056
+ slapi_build_control_from_berval @1057
+; MORE ENTRY ENTRY POINTS
+ slapi_entry_delete_values_sv @1058
+ slapi_entry_attr_replace_sv @1059
+
+ valuearray_free @1061
+ slapd_Client_auth @1062
+ slapi_rand_r @1063
+ slapi_rand @1064
+ slapi_copy @1065
+ slapd_get_tmp_dir @1066
+ slapi_call_syntax_assertion2keys_ava_sv @1067
+ slapi_call_syntax_assertion2keys_sub_sv @1068
+ slapi_value_get_long @1069
+ valuearray_add_valuearray @1070
+ pw_rever_encode @1071
+
+ slapd_nss_init @1072
+ slapd_pk11_configurePKCS11 @1073
+ slapd_pk11_freeSlot @1074
+ slapd_pk11_freeSymKey @1075
+ slapd_pk11_findSlotByName @1076
+ slapd_pk11_createPBEAlgorithmID @1077
+ slapd_pk11_pbeKeyGen @1078
+ slapd_pk11_algtagToMechanism @1079
+ slapd_pk11_paramFromAlgid @1080
+ slapd_pk11_mapPBEMechanismToCryptoMechanism @1081
+ slapd_pk11_getBlockSize @1082
+ slapd_pk11_createContextBySymKey @1083
+ slapd_pk11_cipherOp @1084
+ slapd_pk11_finalize @1085
+ slapd_pk11_getInternalKeySlot @1086
+ slapd_pk11_getInternalSlot @1087
+ slapd_pk11_authenticate @1088
+ slapd_pk11_setSlotPWValues @1089
+ slapd_pk11_isFIPS @1090
+ slapd_pk11_findCertFromNickname @1091
+ slapd_pk11_findKeyByAnyCert @1092
+ slapd_pk11_fortezzaHasKEA @1093
+ filter_flag_is_set @1094
+ slapd_sasl_ext_client_bind @1095
+ checkPrefix @1096
+ DS_Sleep @1097
+ slapi_mtn_get_dn @1098
+ dl_add_index @1099
+ dl_replace @1100
+ send_referrals_from_entry @1101
+ escape_filter_value @1102
+ slapd_pk11_destroyContext @1103
+ secoid_destroyAlgorithmID @1104
+ op_shared_is_allowed_attr @1105
+ get_config_DN @1106
+ slapi_sdn_init_dn_ndn_byref @1107
+ check_log_max_size @1108
+ attrlist_find_ex @1109
+ slapi_entry_vattrcache_merge_sv @1110
+ slapi_entry_vattrcache_find_values_and_type_ex @1111
+ slapi_entry_vattrcache_watermark_isvalid @1112
+ slapi_entry_vattrcache_watermark_set @1113
+ slapi_entry_vattrcache_watermark_invalidate @1114
+ slapi_entrycache_vattrcache_watermark_invalidate @1115
+ slapi_filter_test_simple @1116
+ slapi_register_role_check @1117
+ slapi_role_check @1118
+ slapi_valueset_find @1119
+ slapi_vattr_filter_test @1120
+ slapi_attr_set_valueset @1121
+ slapi_vattrcache_iscacheable @1122
+ slapi_value_new_string_passin @1123
+ slapi_value_init_string_passin @1124
+ slapi_value_set_string_passin @1125
+ slapi_entry_attr_has_syntax_value @1126
+ plugin_call_entryfetch_plugins @1127
+ plugin_call_entrystore_plugins @1128
+ config_get_buildnum @1129
+ plugin_print_versions @1130
+ slapi_ch_array_free @1131
+ slapi_vattrcache_cache_all @1132
+ slapi_vattrcache_cache_none @1133
+ slapi_filter_dup @1134
+ slapi_filter_to_string @1135
+ slapi_filter_join_ex @1136
+ slapi_vattr_schema_check_type @1137
+ slapi_vattr_filter_test_ext @1138
+ index_subsys_evaluate_filter @1139
+ slapi_index_entry_list_create @1140
+ slapi_index_entry_list_add @1141
+ slapi_index_register_decoder @1142
+ slapi_index_register_index @1143
+ slapi_entry_attr_get_charray @1144
+ getSupportedCiphers @1145
+ slapi_operation_set_flag @1146
+ slapi_operation_clear_flag @1147
+ slapi_operation_is_flag_set @1148
+ slapi_op_reserved @1149
+ c_set_shutdown @1150
+ c_get_shutdown @1151
+ slapi_vattr_namespace_values_get @1152
+ slapi_vattr_namespace_value_compare @1153
+ slapi_vattr_namespace_values_get_sp @1154
+ slapi_vattr_namespace_value_compare_sp @1155
+ slapi_vattrspi_register_ex @1156
+ slapi_filter_changetype @1157
+ slapi_rand_array @1158
+ slapi_entries_diff @1159
+ dup_global_schema_csn @1160
+ slapd_pk11_CERT_DestroyCertificate @1161
+ slapd_CERT_ExtractPublicKey @1162
+ slapd_pk11_FindPrivateKeyFromCert @1163
+ slapd_pk11_GetInternalKeySlot @1164
+ slapd_pk11_PubWrapSymKey @1165
+ slapd_pk11_KeyGen @1166
+ slapd_pk11_FreeSlot @1167
+ slapd_pk11_FreeSymKey @1168
+ slapd_pk11_DestroyContext @1169
+ slapd_pk11_ParamFromIV @1170
+ slapd_pk11_PubUnwrapSymKey @1171
+ slapd_SECKEY_PublicKeyStrength @1172
+ slapd_pk11_Finalize @1173
+ slapd_pk11_DigestFinal @1174
+ sasl_map_config_add @1175
+ sasl_map_config_delete @1176
+ sasl_map_domap @1177
+ sasl_map_init @1178
+ sasl_map_done @1179
+ slapd_SECITEM_FreeItem @1180
diff --git a/ldap/servers/slapd/listConfigAttrs.pl b/ldap/servers/slapd/listConfigAttrs.pl
new file mode 100644
index 00000000..25b63293
--- /dev/null
+++ b/ldap/servers/slapd/listConfigAttrs.pl
@@ -0,0 +1,106 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# give several files on the command line
+# from the first file will be extracted the following mappings:
+# directive #define name to "real" name and vice versa
+# attr #define name to "real" name and vice versa
+# directive name to attr name and vice versa
+# this file will typically be slap.h
+#
+# from the second file will be extracted
+# the list of config var members of the slapd frontend config structure
+# this file will also usually be slap.h
+#
+# from the third file will be extracted
+# the mapping of directive #define name to the function which sets its value
+# this file will typically be config.c
+
+%DIRECTIVEDEF2NAME = ();
+%DIRECTIVENAME2DEF = ();
+%ATTRDEF2NAME = ();
+%ATTRNAME2DEF = ();
+%DIRECTIVE2ATTR = ();
+%ATTR2DIRECTIVE = ();
+%SETFUNC2VAR = ();
+
+# these are the ldbm specific attributes
+%LDBMATTRS = ();
+
+$filename = 'slap.h';
+open(F, $filename) or die "Error: could not open $filename: $!";
+while (<F>) {
+ if (/(CONFIG_.+?_ATTRIBUTE)\s+[\"](.+?)[\"]/) {
+ # "
+ $ATTRDEF2NAME{$1} = $2;
+ $ATTRNAME2DEF{$2} = $1;
+ }
+}
+close F;
+
+$filename = 'libglobs.c';
+open(F, $filename) or die "Error: could not open $filename: $!";
+while (<F>) {
+ if (/^\s*\{(CONFIG_.+?_ATTRIBUTE),/) {
+ $attrdef = $1;
+ $def = $_;
+ do {
+ $_ = <F>;
+ $def .= $_;
+ } until ($def =~ /\}[,]?\s*$/);
+ ($ignore, $setfunc, $logsetfunc, $whichlog, $varname, $type, $getfunc) =
+ split(/\s*\,\s*/, $def);
+# print "attrdef = $attrdef\n";
+# print "attrname = $ATTRDEF2NAME{$attrdef}\n";
+# print "type = $type\n";
+# print "setfunc = $setfunc\n";
+ print "$ATTRDEF2NAME{$attrdef} $type";
+ if ((($setfunc =~ /0/) || ($setfunc =~ /NULL/)) &&
+ (($logsetfunc =~ /0/) || ($logsetfunc =~ /NULL/))) {
+ print " is read only";
+ }
+ print "\n";
+ }
+}
+print "\nTypes:\n";
+print "\tCONFIG_INT\t\tan integer\n";
+print "\tCONFIG_LONG\t\tan integer\n";
+print "\tCONFIG_STRING\t\ta string\n";
+print "\tCONFIG_CHARRAY\t\ta list of strings\n";
+print "\tCONFIG_ON_OFF\t\tthe string \"on\" or \"off\"\n";
+print "\tCONFIG_STRING_OR_OFF\ta string or \"off\" if not applicable\n";
+print "\tCONFIG_STRING_OR_UNKNOWN\ta string or \"unknown\" if not applicable\n";
+print "\tCONFIG_CONSTANT_INT\tan integer\n";
+print "\tCONFIG_CONSTANT_STRING\ta string\n";
+print "\tCONFIG_SPECIAL_REFERRALLIST\ta list of strings\n";
+print "\tCONFIG_SPECIAL_STORESTATEINFO\tan integer\n";
+print "\tCONFIG_SPECIAL_SSLCLIENTAUTH\t\"off\" or \"allowed\" or \"required\"\n";
+print "\tCONFIG_SPECIAL_ERRORLOGLEVEL\tan integer\n";
+
+# get a list of ldbm attributes and directives
+$filename = 'back-ldbm/backldbm_configdse.c';
+open(F, $filename) or die "Error: could not open $filename: $!";
+while (<F>) {
+ if (/attr_replace[^"]+["]([^"]+)["]/) {
+ $LDBMATTRS{$1} = "\n";
+ }
+ if (/sprintf[^"]+["](\w+)\\t/) {
+ $LDBMDIRECTIVES{$1} = "\n";
+ }
+}
+close F;
+
+$filename = 'back-ldbm/dblayer.c';
+open(F, $filename) or die "Error: could not open $filename: $!";
+while (<F>) {
+ if (/dblayer_config_type_[^"]+["]([^"]+)["]/) {
+ $LDBMDIRECTIVES{$1} = "\n";
+ }
+}
+close F;
+
diff --git a/ldap/servers/slapd/lite_entries.c b/ldap/servers/slapd/lite_entries.c
new file mode 100644
index 00000000..980bf3fe
--- /dev/null
+++ b/ldap/servers/slapd/lite_entries.c
@@ -0,0 +1,106 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* lite_entries.c -
+ *
+ * These entries are added under cn=options,cn=features,cn=config for
+ * Directory Lite. These entries tell the console which modules ( ds features )
+ * are disabled, and which attributes in cn=config are disabled.
+ */
+
+
+
+
+#include "slap.h"
+
+static void del_dslite_entries();
+static void add_dslite_entries();
+static const char *lite_entries[] =
+{
+ "dn:" LITE_DISABLED_ATTRS_DN "\n"
+ "cn:attributes\n"
+ "objectclass:top\n"
+ "objectclass:extensibleObject\n"
+ "objectclass:directoryServerFeature\n"
+ "cn=config|nsslapd-referral:off\n"
+ "cn=config|nsslapd-maxdescriptors:off\n",
+
+ "dn:" LITE_DISABLED_MODULES_DN "\n"
+ "objectclass:top\n"
+ "objectclass:directoryServerFeature\n"
+ "objectclass:extensibleObject\n"
+ "cn:modules\n"
+ "replication:off\n"
+ "passwordpolicy:off\n"
+ "accountlockout:off\n"
+ "snmpsettings:off\n"
+ "backup:off\n",
+
+ NULL
+};
+
+/* add_dslite_entries:
+ *
+ * Add the DirLite specific entries.
+ * First we try to delete them in case they were already loaded from dse.ldif
+ * but are in some sort of invalid state.
+ * Then we add them back.
+ * It would have been better to make sure that these entries never get written
+ * to dse.ldif, but it doesn't look like we're able to add a dse_callback function
+ * on the DN's of these entries but they get added at the wrong time.
+ */
+
+
+
+static void
+add_dslite_entries() {
+ int i;
+
+ del_dslite_entries();
+ LDAPDebug( LDAP_DEBUG_TRACE, "Adding lite entries.\n",0,0,0);
+ for( i = 0; lite_entries[i]; i++ ) {
+ Slapi_PBlock *resultpb;
+ char *estr = slapi_ch_strdup ( lite_entries[i] );
+ Slapi_Entry *e = slapi_str2entry( estr, 0 );
+ if ( NULL != e ) {
+ resultpb = slapi_add_entry_internal( e, NULL, 0 );
+ slapi_ch_free ( (void **) &resultpb );
+ slapi_ch_free ( (void **) &estr );
+ }
+ }
+}
+
+
+/* del_dslite_entries: delete the DirLite specific entries */
+static void
+del_dslite_entries() {
+ Slapi_PBlock *resultpb;
+ LDAPDebug( LDAP_DEBUG_TRACE, "Deleting lite entries if they exist\n",0,0,0);
+ resultpb = slapi_delete_internal ( LITE_DISABLED_ATTRS_DN, NULL, 0 );
+ slapi_pblock_destroy ( resultpb );
+ resultpb = slapi_delete_internal ( LITE_DISABLED_MODULES_DN, NULL, 0 );
+ slapi_pblock_destroy ( resultpb );
+}
+
+/* lite_entries_init()
+ * Add the appropriate entries under cn=options,cn=features,cn=config if the
+ * server is running as Directory Lite.
+ *
+ * Otherwise, if the server is the Full Directory, try to delete the entries if
+ * they're already there.
+ */
+
+void
+lite_entries_init() {
+ if ( config_is_slapd_lite() ) {
+ add_dslite_entries();
+ }
+ else {
+ del_dslite_entries();
+ }
+}
+
+
+
diff --git a/ldap/servers/slapd/localhost.c b/ldap/servers/slapd/localhost.c
new file mode 100644
index 00000000..fedf8a19
--- /dev/null
+++ b/ldap/servers/slapd/localhost.c
@@ -0,0 +1,228 @@
+/** 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 <sys/types.h>
+#include <string.h>
+#ifdef _WIN32
+#define MAXHOSTNAMELEN 256
+#else
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <arpa/nameser.h>
+#include <resolv.h>
+#endif
+#include <errno.h>
+#include "slap.h"
+#if defined(USE_SYSCONF) || defined(LINUX)
+#include <unistd.h>
+#endif /* USE_SYSCONF */
+
+#if defined( NET_SSL )
+#include <ssl.h>
+#include "fe.h"
+#endif /* defined(NET_SSL) */
+
+#ifndef _PATH_RESCONF /* usually defined in <resolv.h> */
+#define _PATH_RESCONF "/etc/resolv.conf"
+#endif
+
+#if !defined(NO_DOMAINNAME) && defined(_WINDOWS)
+#define NO_DOMAINNAME 1
+#endif
+
+static char*
+find_localhost_DNS()
+{
+ /* This implementation could (and should) be entirely replaced by:
+ dns_ip2host ("127.0.0.1", 1); defined in ldapserver/lib/base/dns.c
+ */
+ char hostname [MAXHOSTNAMELEN + 1];
+ struct hostent *hp;
+#ifdef GETHOSTBYNAME_BUF_T
+ struct hostent hent;
+ GETHOSTBYNAME_BUF_T hbuf;
+ int err;
+#endif
+ char** alias;
+ FILE* f;
+ char* cp;
+ char* domain;
+ char line [MAXHOSTNAMELEN + 8];
+
+ if (gethostname (hostname, MAXHOSTNAMELEN)) {
+ int oserr = errno;
+
+ LDAPDebug (LDAP_DEBUG_ANY, "gethostname() failed, error %d (%s)\n",
+ oserr, slapd_system_strerror( oserr ), 0 );
+ return NULL;
+ }
+ hp = GETHOSTBYNAME (hostname, &hent, hbuf, sizeof(hbuf), &err);
+ if (hp == NULL) {
+ int oserr = errno;
+
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "gethostbyname(\"%s\") failed, error %d (%s)\n",
+ hostname, oserr, slapd_system_strerror( oserr ));
+ return NULL;
+ }
+ if (hp->h_name == NULL) {
+ LDAPDebug (LDAP_DEBUG_ANY, "gethostbyname(\"%s\")->h_name == NULL\n", hostname, 0, 0);
+ return NULL;
+ }
+ if (strchr (hp->h_name, '.') != NULL) {
+ LDAPDebug (LDAP_DEBUG_CONFIG, "h_name == %s\n", hp->h_name, 0, 0);
+ return slapi_ch_strdup (hp->h_name);
+ } else if (hp->h_aliases != NULL) {
+ for (alias = hp->h_aliases; *alias != NULL; ++alias) {
+ if (strchr (*alias, '.') != NULL &&
+ strncmp (*alias, hp->h_name, strlen (hp->h_name))) {
+ LDAPDebug (LDAP_DEBUG_CONFIG, "h_alias == %s\n", *alias, 0, 0);
+ return slapi_ch_strdup (*alias);
+ }
+ }
+ }
+ /* The following is copied from dns_guess_domain(),
+ in ldapserver/lib/base/dnsdmain.c */
+ domain = NULL;
+ f = fopen (_PATH_RESCONF, "r"); /* This fopen() will fail on NT, as expected */
+ if (f != NULL) {
+ while (fgets (line, sizeof(line), f)) {
+ if (strncasecmp (line, "domain", 6) == 0 && isspace (line[6])) {
+ LDAPDebug (LDAP_DEBUG_CONFIG, "%s: %s\n", _PATH_RESCONF, line, 0);
+ for (cp = &line[7]; *cp && isspace(*cp); ++cp);
+ if (*cp) {
+ domain = cp;
+ /* ignore subsequent whitespace: */
+ for (; *cp && ! isspace (*cp); ++cp);
+ if (*cp) {
+ *cp = '\0';
+ }
+ }
+ break;
+ }
+ }
+ fclose (f);
+ }
+#ifndef NO_DOMAINNAME
+ if (domain == NULL) {
+ /* No domain found. Try getdomainname. */
+ getdomainname (line, sizeof(line));
+ LDAPDebug (LDAP_DEBUG_CONFIG, "getdomainname(%s)\n", line, 0, 0);
+ if (line[0] != 0) {
+ domain = &line[0];
+ }
+ }
+#endif
+ if (domain == NULL) {
+ return NULL;
+ }
+ strcpy (hostname, hp->h_name);
+ if (domain[0] == '.') ++domain;
+ if (domain[0]) {
+ strcat (hostname, ".");
+ strcat (hostname, domain);
+ }
+ LDAPDebug (LDAP_DEBUG_CONFIG, "hostname == %s\n", hostname, 0, 0);
+ return slapi_ch_strdup (hostname);
+}
+
+static const char* const RDN = "dc=";
+
+static char*
+convert_DNS_to_DN (char* DNS)
+{
+ char* DN;
+ char* dot;
+ size_t components;
+ if (*DNS == '\0') {
+ return slapi_ch_strdup ("");
+ }
+ components = 1;
+ for (dot = strchr (DNS, '.'); dot != NULL; dot = strchr (dot + 1, '.')) {
+ ++components;
+ }
+ DN = slapi_ch_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);
+ slapi_dn_normalize (DN);
+ return DN;
+}
+
+static char* localhost_DN = NULL;
+
+char*
+get_localhost_DNS()
+{
+ char *retVal;
+ if ( (retVal = config_get_localhost()) == NULL) {
+ /* find_localhost_DNS() returns strdup result */
+ retVal = find_localhost_DNS();
+ }
+ return retVal;
+}
+
+static void
+set_localhost_DN()
+{
+ char *localhost_DNS = config_get_localhost();
+
+ if (localhost_DNS != NULL) {
+ localhost_DN = convert_DNS_to_DN (localhost_DNS);
+ LDAPDebug (LDAP_DEBUG_CONFIG, "DNS %s -> DN %s\n", localhost_DNS, localhost_DN, 0);
+ }
+ slapi_ch_free( (void **) &localhost_DNS );
+}
+
+
+char*
+get_localhost_DN()
+/* Return the Distinguished Name of the local host; that is,
+ its DNS name converted to a DN according to RFC 1279.
+ The caller should _not_ free this pointer. */
+{
+ if (localhost_DN == NULL) {
+ set_localhost_DN();
+ }
+ return localhost_DN;
+}
+
+static char* config_DN = NULL;
+
+char *
+get_config_DN()
+{
+ char *c;
+ char *host;
+
+ if ( config_DN == NULL )
+ {
+ host = get_localhost_DN();
+ if ( host )
+ c = slapi_ch_malloc (20 + strlen (host));
+ else {
+ LDAPDebug (LDAP_DEBUG_CONFIG, "get_locahost_DN() returned \"\"\n",
+ 0, 0, 0);
+ c = slapi_ch_malloc (20);
+ }
+ sprintf (c, "cn=ldap://%s:%lu", host ? host : "", config_get_port());
+ config_DN = c;
+ }
+
+ return config_DN;
+}
+
diff --git a/ldap/servers/slapd/lock.c b/ldap/servers/slapd/lock.c
new file mode 100644
index 00000000..d0f2fc48
--- /dev/null
+++ b/ldap/servers/slapd/lock.c
@@ -0,0 +1,82 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* lock.c - routines to open and apply an advisory lock to a file */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#ifdef USE_LOCKF
+#include <unistd.h>
+#endif
+
+FILE *
+lock_fopen( char *fname, char *type, FILE **lfp )
+{
+ FILE *fp;
+ char buf[MAXPATHLEN];
+
+ /* open the lock file */
+ strcpy( buf, fname );
+ strcat( buf, ".lock" );
+ if ( (*lfp = fopen( buf, "w" )) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "could not open \"%s\"\n", buf, 0, 0 );
+ return( NULL );
+ }
+
+ /* acquire the lock */
+#ifdef _WIN32
+ while ( _locking( _fileno( *lfp ), LK_NBLCK, 0xFFFFFFFF ) != 0 ) {
+#else
+#ifdef USE_LOCKF
+ while ( lockf( fileno( *lfp ), F_LOCK, 0 ) != 0 ) {
+#else /* _WIN32 */
+ while ( flock( fileno( *lfp ), LOCK_EX ) != 0 ) {
+#endif
+#endif /* _WIN32 */
+ ; /* NULL */
+ }
+
+ /* open the log file */
+ if ( (fp = fopen( fname, type )) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "could not open \"%s\"\n", fname, 0, 0 );
+#ifdef _WIN32
+ _locking( _fileno( *lfp ), LK_UNLCK, 0xFFFFFFFF );
+#else /* _WIN32 */
+#ifdef USE_LOCKF
+ lockf( fileno( *lfp ), F_ULOCK, 0 );
+#else
+ flock( fileno( *lfp ), LOCK_UN );
+#endif
+#endif /* _WIN32 */
+ return( NULL );
+ }
+
+ return( fp );
+}
+
+int
+lock_fclose( FILE *fp, FILE *lfp )
+{
+ /* unlock */
+#ifdef _WIN32
+ _locking( _fileno( lfp ), LK_UNLCK, 0xFFFFFFFF );
+#else /* _WIN32 */
+#ifdef USE_LOCKF
+ lockf( fileno( lfp ), F_ULOCK, 0 );
+#else
+ flock( fileno( lfp ), LOCK_UN );
+#endif
+#endif /* _WIN32 */
+ fclose( lfp );
+
+ return( fclose( fp ) );
+}
diff --git a/ldap/servers/slapd/log.c b/ldap/servers/slapd/log.c
new file mode 100644
index 00000000..32c0fa2f
--- /dev/null
+++ b/ldap/servers/slapd/log.c
@@ -0,0 +1,3664 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+**
+** log.c
+**
+** Routines for writing access and error/debug logs
+**
+**
+** History:
+** As of DS 4.0, we support log rotation for the ACCESS/ERROR/AUDIT log.
+*/
+
+#include "log.h"
+#include "fe.h"
+
+#if defined( XP_WIN32 )
+#include <fcntl.h>
+#include "ntslapdmessages.h"
+#include "proto-ntutil.h"
+extern HANDLE hSlapdEventSource;
+extern LPTSTR pszServerName;
+#endif
+/**************************************************************************
+ * GLOBALS, defines, and ...
+ *************************************************************************/
+/* main struct which contains all the information about logging */
+PRUintn logbuf_tsdindex;
+struct logbufinfo *logbuf_accum;
+static struct logging_opts loginfo;
+static int detached=0;
+
+/* used to lock the timestamp info used by vslapd_log_access */
+static PRLock *ts_time_lock = NULL;
+
+/*
+ * Note: the order of the values in the slapi_log_map array must exactly
+ * match that of the SLAPI_LOG_XXX #defines found in slapi-plugin.h (this is
+ * so we can use the SLAPI_LOG_XXX values to index directly into the array).
+ */
+static int slapi_log_map[] = {
+ LDAP_DEBUG_ANY, /* SLAPI_LOG_FATAL */
+ LDAP_DEBUG_TRACE, /* SLAPI_LOG_TRACE */
+ LDAP_DEBUG_PACKETS, /* SLAPI_LOG_PACKETS */
+ LDAP_DEBUG_ARGS, /* SLAPI_LOG_ARGS */
+ LDAP_DEBUG_CONNS, /* SLAPI_LOG_CONNS */
+ LDAP_DEBUG_BER, /* SLAPI_LOG_BER */
+ LDAP_DEBUG_FILTER, /* SLAPI_LOG_FILTER */
+ LDAP_DEBUG_CONFIG, /* SLAPI_LOG_CONFIG */
+ LDAP_DEBUG_ACL, /* SLAPI_LOG_ACL */
+ LDAP_DEBUG_SHELL, /* SLAPI_LOG_SHELL */
+ LDAP_DEBUG_PARSE, /* SLAPI_LOG_PARSE */
+ LDAP_DEBUG_HOUSE, /* SLAPI_LOG_HOUSE */
+ LDAP_DEBUG_REPL, /* SLAPI_LOG_REPL */
+ LDAP_DEBUG_CACHE, /* SLAPI_LOG_CACHE */
+ LDAP_DEBUG_PLUGIN, /* SLAPI_LOG_PLUGIN */
+ LDAP_DEBUG_TIMING, /* SLAPI_LOG_TIMING */
+ LDAP_DEBUG_ACLSUMMARY, /* SLAPI_LOG_ACLSUMMARY */
+};
+
+#define SLAPI_LOG_MIN SLAPI_LOG_FATAL /* from slapi-plugin.h */
+#define SLAPI_LOG_MAX SLAPI_LOG_ACLSUMMARY /* from slapi-plugin.h */
+#define TBUFSIZE 50 /* size for time buffers */
+#define SLAPI_LOG_BUFSIZ 2048 /* size for data buffers */
+/**************************************************************************
+ * PROTOTYPES
+ *************************************************************************/
+static int log__open_accesslogfile(int logfile_type, int locked);
+static int log__open_errorlogfile(int logfile_type, int locked);
+static int log__open_auditlogfile(int logfile_type, int locked);
+static int log__needrotation(LOGFD fp, int logtype);
+static int log__delete_access_logfile();
+static int log__delete_error_logfile();
+static int log__delete_audit_logfile();
+static int log__access_rotationinfof(char *pathname);
+static int log__error_rotationinfof(char *pathname);
+static int log__audit_rotationinfof(char *pathname);
+static int log__extract_logheader (FILE *fp, long *f_ctime, int *f_size);
+static int log__getfilesize(LOGFD fp);
+static int log__enough_freespace(char *path);
+
+static int vslapd_log_error(LOGFD fp, char *subsystem, char *fmt, va_list ap );
+static int vslapd_log_access(char *fmt, va_list ap );
+static void log_convert_time (time_t ctime, char *tbuf, int type);
+static LogBufferInfo *log_create_buffer(size_t sz);
+static void log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2);
+static void log_flush_buffer(LogBufferInfo *lbi, int type, int sync_now);
+static void log_write_title(LOGFD fp);
+
+
+static int
+slapd_log_error_proc_internal(
+ char *subsystem, /* omitted if NULL */
+ char *fmt,
+ va_list ap_err,
+ va_list ap_file);
+
+/*
+ * these macros are used for opening a log file, closing a log file, and
+ * writing out to a log file. we have to do this because currently NSPR
+ * is extremely under-performant on NT, while fopen/fwrite fail on several
+ * unix platforms if there are more than 128 files open.
+ *
+ * LOG_OPEN_APPEND(fd, filename, mode) returns true if successful. 'fd' should
+ * be of type LOGFD (check log.h). the file is open for appending to.
+ * LOG_OPEN_WRITE(fd, filename, mode) is the same but truncates the file and
+ * starts writing at the beginning of the file.
+ * LOG_WRITE(fd, buffer, size, headersize) writes into a LOGFD
+ * LOG_WRITE_NOW(fd, buffer, size, headersize) writes into a LOGFD and flushes the
+ * buffer if necessary
+ * LOG_CLOSE(fd) closes the logfile
+ */
+#ifdef XP_WIN32
+#define LOG_OPEN_APPEND(fd, filename, mode) \
+ (((fd) = fopen((filename), "a")) != NULL)
+#define LOG_OPEN_WRITE(fd, filename, mode) \
+ (((fd) = fopen((filename), "w")) != NULL)
+#define LOG_WRITE(fd, buffer, size, headersize) \
+ if ( fwrite((buffer), (size), 1, (fd)) != 1 ) \
+ {\
+ ReportSlapdEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVER_FAILED_TO_WRITE_LOG, 1, (buffer)); \
+ }
+#define LOG_WRITE_NOW(fd, buffer, size, headersize) do {\
+ if ( fwrite((buffer), (size), 1, (fd)) != 1 ) \
+ { \
+ ReportSlapdEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVER_FAILED_TO_WRITE_LOG, 1, (buffer)); \
+ }; \
+ fflush((fd)); \
+ } while (0)
+#define LOG_CLOSE(fd) \
+ fclose((fd))
+#else /* xp_win32 */
+#define LOG_OPEN_APPEND(fd, filename, mode) \
+ (((fd) = PR_Open((filename), PR_WRONLY | PR_APPEND | PR_CREATE_FILE , \
+ mode)) != NULL)
+#define LOG_OPEN_WRITE(fd, filename, mode) \
+ (((fd) = PR_Open((filename), PR_WRONLY | PR_TRUNCATE | \
+ PR_CREATE_FILE, mode)) != NULL)
+#define LOG_WRITE(fd, buffer, size, headersize) \
+ if ( slapi_write_buffer((fd), (buffer), (size)) != (size) ) \
+ { \
+ PRErrorCode prerr = PR_GetError(); \
+ syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer)+(headersize) ); \
+ }
+#define LOG_WRITE_NOW(fd, buffer, size, headersize) do {\
+ if ( slapi_write_buffer((fd), (buffer), (size)) != (size) ) \
+ { \
+ PRErrorCode prerr = PR_GetError(); \
+ syslog(LOG_ERR, "Failed to write log, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s): %s\n", prerr, slapd_pr_strerror(prerr), (buffer)+(headersize) ); \
+ } \
+ /* Should be a flush in here ?? Yes because PR_SYNC doesn't work ! */ \
+ PR_Sync(fd); \
+ } while (0)
+#define LOG_CLOSE(fd) \
+ PR_Close((fd))
+#endif
+
+
+/******************************************************************************
+* Set the access level
+******************************************************************************/
+void g_set_accesslog_level(int val)
+{
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_level = val;
+ LOG_ACCESS_UNLOCK_WRITE();
+}
+
+/******************************************************************************
+* Set whether the process is alive or dead
+* If it is detached, then we write the error in 'stderr'
+******************************************************************************/
+void g_set_detached(int val)
+{
+ detached = val;
+}
+
+/******************************************************************************
+* Tell me whether logging begins or not
+******************************************************************************/
+void g_log_init(int log_enabled)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char * instancedir = NULL;
+
+ ts_time_lock = PR_NewLock();
+ if (! ts_time_lock)
+ exit(-1);
+
+#if defined( XP_WIN32 )
+ pszServerName = slapi_ch_malloc( MAX_SERVICE_NAME );
+ instancedir = config_get_instancedir();
+ unixtodospath(instancedir);
+ if( !SlapdGetServerNameFromCmdline(pszServerName, instancedir, 1) )
+ {
+ MessageBox(GetDesktopWindow(), "Failed to get the Directory"
+ " Server name from the command-line argument.",
+ " ", MB_ICONEXCLAMATION | MB_OK);
+ exit( 1 );
+ }
+ slapi_ch_free((void **)&instancedir);
+
+ /* Register with the NT EventLog */
+ hSlapdEventSource = RegisterEventSource(NULL, pszServerName );
+ if( !hSlapdEventSource )
+ {
+ char szMessage[256];
+ sprintf( szMessage, "Directory Server %s is terminating. Failed "
+ "to set the EventLog source.", pszServerName);
+ MessageBox(GetDesktopWindow(), szMessage, " ",
+ MB_ICONEXCLAMATION | MB_OK);
+ exit( 1 );
+ }
+#endif
+
+ /* ACCESS LOG */
+ loginfo.log_access_state = 0;
+ loginfo.log_access_mode = SLAPD_DEFAULT_FILE_MODE;
+ loginfo.log_access_maxnumlogs = 1;
+ loginfo.log_access_maxlogsize = -1;
+ loginfo.log_access_rotationsync_enabled = 0;
+ loginfo.log_access_rotationsynchour = -1;
+ loginfo.log_access_rotationsyncmin = -1;
+ loginfo.log_access_rotationsyncclock = -1;
+ loginfo.log_access_rotationtime = -1;
+ loginfo.log_access_rotationunit = -1;
+ loginfo.log_access_rotationtime_secs = -1;
+ loginfo.log_access_maxdiskspace = -1;
+ loginfo.log_access_minfreespace = -1;
+ loginfo.log_access_exptime = -1;
+ loginfo.log_access_exptimeunit = -1;
+ loginfo.log_access_exptime_secs = -1;
+ loginfo.log_access_level = LDAP_DEBUG_STATS;
+ loginfo.log_access_ctime = 0L;
+ loginfo.log_access_fdes = NULL;
+ loginfo.log_access_file = NULL;
+ loginfo.log_numof_access_logs = 1;
+ loginfo.log_access_logchain = NULL;
+ loginfo.log_access_buffer = log_create_buffer(LOG_BUFFER_MAXSIZE);
+ if (loginfo.log_access_buffer == NULL)
+ exit(-1);
+ if ((loginfo.log_access_buffer->lock = PR_NewLock())== NULL )
+ exit (-1);
+ slapdFrontendConfig->accessloglevel = LDAP_DEBUG_STATS;
+
+ /* ERROR LOG */
+ loginfo.log_error_state = 0;
+ loginfo.log_error_mode = SLAPD_DEFAULT_FILE_MODE;
+ loginfo.log_error_maxnumlogs = 1;
+ loginfo.log_error_maxlogsize = -1;
+ loginfo.log_error_rotationsync_enabled = 0;
+ loginfo.log_error_rotationsynchour = -1;
+ loginfo.log_error_rotationsyncmin = -1;
+ loginfo.log_error_rotationsyncclock = -1;
+ loginfo.log_error_rotationtime = -1;
+ loginfo.log_error_rotationunit = -1;
+ loginfo.log_error_rotationtime_secs = -1;
+ loginfo.log_error_maxdiskspace = -1;
+ loginfo.log_error_minfreespace = -1;
+ loginfo.log_error_exptime = -1;
+ loginfo.log_error_exptimeunit = -1;
+ loginfo.log_error_exptime_secs = -1;
+ loginfo.log_error_ctime = 0L;
+ loginfo.log_error_file = NULL;
+ loginfo.log_error_fdes = NULL;
+ loginfo.log_numof_error_logs = 1;
+ loginfo.log_error_logchain = NULL;
+ if ((loginfo.log_error_rwlock =rwl_new())== NULL ) {
+ exit (-1);
+ }
+
+ /* AUDIT LOG */
+ loginfo.log_audit_state = 0;
+ loginfo.log_audit_mode = SLAPD_DEFAULT_FILE_MODE;
+ loginfo.log_audit_maxnumlogs = 1;
+ loginfo.log_audit_maxlogsize = -1;
+ loginfo.log_audit_rotationsync_enabled = 0;
+ loginfo.log_audit_rotationsynchour = -1;
+ loginfo.log_audit_rotationsyncmin = -1;
+ loginfo.log_audit_rotationsyncclock = -1;
+ loginfo.log_audit_rotationtime = -1;
+ loginfo.log_audit_rotationunit = -1;
+ loginfo.log_audit_rotationtime_secs = -1;
+ loginfo.log_audit_maxdiskspace = -1;
+ loginfo.log_audit_minfreespace = -1;
+ loginfo.log_audit_exptime = -1;
+ loginfo.log_audit_exptimeunit = -1;
+ loginfo.log_audit_exptime_secs = -1;
+ loginfo.log_audit_ctime = 0L;
+ loginfo.log_audit_file = NULL;
+ loginfo.log_numof_audit_logs = 1;
+ loginfo.log_audit_fdes = NULL;
+ loginfo.log_audit_logchain = NULL;
+ if ((loginfo.log_audit_rwlock =rwl_new())== NULL ) {
+ exit (-1);
+ }
+}
+
+/******************************************************************************
+* Tell me if log is enabled or disabled
+******************************************************************************/
+int
+log_set_logging(const char *attrname, char *value, int logtype, char *errorbuf, int apply)
+{
+ int v;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( NULL == value ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: NULL value; valid values "
+ "are \"on\" or \"off\"", attrname );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (strcasecmp(value, "on") == 0) {
+ v = LOGGING_ENABLED;
+ }
+ else if (strcasecmp(value, "off") == 0 ) {
+ v = 0;
+ }
+ else {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid value \"%s\", valid values "
+ "are \"on\" or \"off\"", attrname, value );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ){
+ return LDAP_SUCCESS;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ fe_cfg->accesslog_logging_enabled = v;
+ if(v) {
+ loginfo.log_access_state |= LOGGING_ENABLED;
+ }
+ else {
+ loginfo.log_access_state &= ~LOGGING_ENABLED;
+ }
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ fe_cfg->errorlog_logging_enabled = v;
+ if (v) {
+ loginfo.log_error_state |= LOGGING_ENABLED;
+ }
+ else {
+ loginfo.log_error_state &= ~LOGGING_ENABLED;
+ }
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ fe_cfg->auditlog_logging_enabled = v;
+ if (v) {
+ loginfo.log_audit_state |= LOGGING_ENABLED;
+ }
+ else {
+ loginfo.log_audit_state &= ~LOGGING_ENABLED;
+ }
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ }
+
+ return LDAP_SUCCESS;
+
+}
+/******************************************************************************
+* Tell me the access log file name inc path
+******************************************************************************/
+char *
+g_get_access_log () {
+ char *logfile = NULL;
+
+ LOG_ACCESS_LOCK_READ();
+ if ( loginfo.log_access_file)
+ logfile = slapi_ch_strdup (loginfo.log_access_file);
+ LOG_ACCESS_UNLOCK_READ();
+
+ return logfile;
+
+}
+/******************************************************************************
+* Point to a new access logdir
+*
+* Returns:
+* LDAP_SUCCESS -- success
+* LDAP_UNWILLING_TO_PERFORM -- when trying to open a invalid log file
+* LDAP_LOCAL_ERRO -- some error
+******************************************************************************/
+int
+log_update_accesslogdir(char *pathname, int apply)
+{
+ int rv = LDAP_SUCCESS;
+ LOGFD fp;
+
+ /* try to open the file, we may have a incorrect path */
+ if (! LOG_OPEN_APPEND(fp, pathname, loginfo.log_access_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ pathname, errno, slapd_system_strerror(errno));
+ /* stay with the current log file */
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+ LOG_CLOSE(fp);
+
+ /* skip the rest if we aren't doing this for real */
+ if ( !apply ) {
+ return LDAP_SUCCESS;
+ }
+
+ /*
+ ** The user has changed the access log directory. That means we
+ ** need to start fresh.
+ */
+ LOG_ACCESS_LOCK_WRITE ();
+ if (loginfo.log_access_fdes) {
+ LogFileInfo *logp, *d_logp;
+
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Closing the access log file. "
+ "Moving to a new access log file (%s)\n", pathname,0,0);
+
+ LOG_CLOSE(loginfo.log_access_fdes);
+ loginfo.log_access_fdes = 0;
+ loginfo.log_access_ctime = 0;
+ logp = loginfo.log_access_logchain;
+ while (logp) {
+ d_logp = logp;
+ logp = logp->l_next;
+ slapi_ch_free((void**)&d_logp);
+ }
+ loginfo.log_access_logchain = NULL;
+ slapi_ch_free((void**)&loginfo.log_access_file);
+ loginfo.log_access_file = NULL;
+ loginfo.log_numof_access_logs = 1;
+ }
+
+ /* Now open the new access log file */
+ if ( access_log_openf (pathname, 1 /* locked */)) {
+ rv = LDAP_LOCAL_ERROR; /* error Unable to use the new dir */
+ }
+ LOG_ACCESS_UNLOCK_WRITE();
+ return rv;
+}
+/******************************************************************************
+* Tell me the error log file name inc path
+******************************************************************************/
+char *
+g_get_error_log() {
+ char *logfile = NULL;
+
+ LOG_ERROR_LOCK_READ();
+ if ( loginfo.log_error_file)
+ logfile = slapi_ch_strdup (loginfo.log_error_file);
+ LOG_ERROR_UNLOCK_READ();
+
+ return logfile;
+}
+/******************************************************************************
+* Point to a new error logdir
+*
+* Returns:
+* LDAP_SUCCESS -- success
+* LDAP_UNWILLING_TO_PERFORM -- when trying to open a invalid log file
+* LDAP_LOCAL_ERRO -- some error
+******************************************************************************/
+int
+log_update_errorlogdir(char *pathname, int apply)
+{
+
+ int rv = LDAP_SUCCESS;
+ LOGFD fp;
+
+ /* try to open the file, we may have a incorrect path */
+ if (! LOG_OPEN_APPEND(fp, pathname, loginfo.log_error_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ pathname, errno, slapd_system_strerror(errno));
+ /* stay with the current log file */
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ /* skip the rest if we aren't doing this for real */
+ if ( !apply ) {
+ return LDAP_SUCCESS;
+ }
+ LOG_CLOSE(fp);
+
+ /*
+ ** The user has changed the error log directory. That means we
+ ** need to start fresh.
+ */
+ LOG_ERROR_LOCK_WRITE ();
+ if (loginfo.log_error_fdes) {
+ LogFileInfo *logp, *d_logp;
+
+ LOG_CLOSE(loginfo.log_error_fdes);
+ loginfo.log_error_fdes = 0;
+ loginfo.log_error_ctime = 0;
+ logp = loginfo.log_error_logchain;
+ while (logp) {
+ d_logp = logp;
+ logp = logp->l_next;
+ slapi_ch_free((void**)&d_logp);
+ }
+ loginfo.log_error_logchain = NULL;
+ slapi_ch_free((void**)&loginfo.log_error_file);
+ loginfo.log_error_file = NULL;
+ loginfo.log_numof_error_logs = 1;
+ }
+
+ /* Now open the new errorlog */
+ if ( error_log_openf (pathname, 1 /* obtained lock */)) {
+ rv = LDAP_LOCAL_ERROR; /* error: Unable to use the new dir */
+ }
+
+ LOG_ERROR_UNLOCK_WRITE();
+ return rv;
+}
+/******************************************************************************
+* Tell me the audit log file name inc path
+******************************************************************************/
+char *
+g_get_audit_log() {
+ char *logfile = NULL;
+
+ LOG_AUDIT_LOCK_READ();
+ if ( loginfo.log_audit_file)
+ logfile = slapi_ch_strdup (loginfo.log_audit_file);
+ LOG_AUDIT_UNLOCK_READ();
+
+ return logfile;
+}
+/******************************************************************************
+* Point to a new audit logdir
+*
+* Returns:
+* LDAP_SUCCESS -- success
+* LDAP_UNWILLING_TO_PERFORM -- when trying to open a invalid log file
+* LDAP_LOCAL_ERRO -- some error
+******************************************************************************/
+int
+log_update_auditlogdir(char *pathname, int apply)
+{
+ int rv = LDAP_SUCCESS;
+ LOGFD fp;
+
+ /* try to open the file, we may have a incorrect path */
+ if (! LOG_OPEN_APPEND(fp, pathname, loginfo.log_audit_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ pathname, errno, slapd_system_strerror(errno));
+ /* stay with the current log file */
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ /* skip the rest if we aren't doing this for real */
+ if ( !apply ) {
+ return LDAP_SUCCESS;
+ }
+ LOG_CLOSE(fp);
+
+ /*
+ ** The user has changed the audit log directory. That means we
+ ** need to start fresh.
+ */
+ LOG_AUDIT_LOCK_WRITE ();
+ if (loginfo.log_audit_fdes) {
+ LogFileInfo *logp, *d_logp;
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Closing the audit log file. "
+ "Moving to a new audit file (%s)\n", pathname,0,0);
+
+ LOG_CLOSE(loginfo.log_audit_fdes);
+ loginfo.log_audit_fdes = 0;
+ loginfo.log_audit_ctime = 0;
+ logp = loginfo.log_audit_logchain;
+ while (logp) {
+ d_logp = logp;
+ logp = logp->l_next;
+ slapi_ch_free((void**)&d_logp);
+ }
+ loginfo.log_audit_logchain = NULL;
+ slapi_ch_free((void**)&loginfo.log_audit_file);
+ loginfo.log_audit_file = NULL;
+ loginfo.log_numof_audit_logs = 1;
+ }
+
+ /* Now open the new errorlog */
+ if ( audit_log_openf (pathname, 1 /* locked */)) {
+ rv = LDAP_LOCAL_ERROR; /* error: Unable to use the new dir */
+ }
+ LOG_AUDIT_UNLOCK_WRITE();
+ return rv;
+}
+
+int
+log_set_mode (const char *attrname, char *value, int logtype, char *errorbuf, int apply)
+{
+ int v = 0;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( NULL == value ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: null value; valid values "
+ "are are of the format \"yz-yz-yz-\" where y could be 'r' or '-',"
+ " and z could be 'w' or '-'", attrname );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ){
+ return LDAP_SUCCESS;
+ }
+
+ v = strtol (value, NULL, 8);
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ slapi_ch_free ( (void **) &fe_cfg->accesslog_mode );
+ fe_cfg->accesslog_mode = slapi_ch_strdup (value);
+ loginfo.log_access_mode = v;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ slapi_ch_free ( (void **) &fe_cfg->errorlog_mode );
+ fe_cfg->errorlog_mode = slapi_ch_strdup (value);
+ loginfo.log_error_mode = v;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ slapi_ch_free ( (void **) &fe_cfg->auditlog_mode );
+ fe_cfg->auditlog_mode = slapi_ch_strdup (value);
+ loginfo.log_audit_mode = v;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ }
+ return LDAP_SUCCESS;
+}
+
+/******************************************************************************
+* MAX NUMBER OF LOGS
+******************************************************************************/
+int
+log_set_numlogsperdir(const char *attrname, char *numlogs_str, int logtype, char *returntext, int apply)
+{
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ int rv = LDAP_SUCCESS;
+ int numlogs;
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ rv = LDAP_OPERATIONS_ERROR;
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type %d", attrname, logtype );
+ }
+ if ( !apply || !numlogs_str || !*numlogs_str) {
+ return rv;
+ }
+
+ numlogs = atoi(numlogs_str);
+
+ if (numlogs >= 1) {
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_maxnumlogs = numlogs;
+ fe_cfg->accesslog_maxnumlogs = numlogs;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_maxnumlogs = numlogs;
+ fe_cfg->errorlog_maxnumlogs = numlogs;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_maxnumlogs = numlogs;
+ fe_cfg->auditlog_maxnumlogs = numlogs;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = LDAP_OPERATIONS_ERROR;
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "log_set_numlogsperdir: invalid log type %d", logtype,0,0 );
+ }
+ }
+ return rv;
+}
+
+/******************************************************************************
+* LOG SIZE
+* Return Values:
+* LDAP_OPERATIONS_ERROR -- fail
+* LDAP_SUCCESS -- success
+*
+* NOTE: The config struct should contain the maxlogsize in MB and not in bytes.
+******************************************************************************/
+int
+log_set_logsize(const char *attrname, char *logsize_str, int logtype, char *returntext, int apply)
+{
+ int rv = LDAP_SUCCESS;
+ int mdiskspace= 0;
+ int max_logsize;
+ int logsize;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if (!apply || !logsize_str || !*logsize_str)
+ return rv;
+
+ logsize = atoi(logsize_str);
+
+ /* convert it to bytes */
+ max_logsize = logsize * LOG_MB_IN_BYTES;
+
+ if (max_logsize <= 0) {
+ max_logsize = -1;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ mdiskspace = loginfo.log_access_maxdiskspace;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ mdiskspace = loginfo.log_error_maxdiskspace;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ mdiskspace = loginfo.log_audit_maxdiskspace;
+ break;
+ default:
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid logtype %d", attrname, logtype );
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+
+ if ((max_logsize > mdiskspace) && (mdiskspace != -1))
+ rv = 2;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ if (!rv && apply) {
+ loginfo.log_access_maxlogsize = max_logsize;
+ fe_cfg->accesslog_maxlogsize = logsize;
+ }
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ if (!rv && apply) {
+ loginfo.log_error_maxlogsize = max_logsize;
+ fe_cfg->errorlog_maxlogsize = logsize;
+ }
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ if (!rv && apply) {
+ loginfo.log_audit_maxlogsize = max_logsize;
+ fe_cfg->auditlog_maxlogsize = logsize;
+ }
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+ /* logsize will be in n MB. Convert it to bytes */
+ if (rv == 2) {
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "Invalid value for Maximum log size:"
+ "Maxlogsize:%d MB Maxdisksize:%d MB\n",
+ logsize, mdiskspace/LOG_MB_IN_BYTES,0);
+
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+ return rv;
+}
+
+time_t
+log_get_rotationsyncclock(int synchour, int syncmin)
+{
+ struct tm *currtm;
+ time_t currclock;
+ time_t syncclock;
+ int hours, minutes;
+
+ time( &currclock);
+ currtm = localtime( &currclock );
+
+ if ( syncmin < currtm->tm_min ) {
+ minutes = syncmin + 60 - currtm->tm_min;
+ hours = synchour - 1 - currtm->tm_hour;
+ } else {
+ minutes = syncmin - currtm->tm_min;
+ hours = synchour - currtm->tm_hour;
+ }
+ if ( hours < 0 ) hours += 24;
+
+ syncclock = currclock + hours * 3600 + minutes * 60;
+ return syncclock;
+}
+
+int
+log_set_rotationsync_enabled(const char *attrname, char *value, int logtype, char *errorbuf, int apply)
+{
+ int v;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( NULL == value ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: NULL value; valid values "
+ "are \"on\" or \"off\"", attrname );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (strcasecmp(value, "on") == 0) {
+ v = LDAP_ON;
+ }
+ else if (strcasecmp(value, "off") == 0 ) {
+ v = LDAP_OFF;
+ }
+ else {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid value \"%s\", valid values "
+ "are \"on\" or \"off\"", attrname, value );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( !apply ){
+ return LDAP_SUCCESS;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ fe_cfg->accesslog_rotationsync_enabled = v;
+ loginfo.log_access_rotationsync_enabled = v;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ fe_cfg->errorlog_rotationsync_enabled = v;
+ loginfo.log_error_rotationsync_enabled = v;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ fe_cfg->auditlog_rotationsync_enabled = v;
+ loginfo.log_audit_rotationsync_enabled = v;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ }
+ return LDAP_SUCCESS;
+}
+
+int
+log_set_rotationsynchour(const char *attrname, char *rhour_str, int logtype, char *returntext, int apply)
+{
+ int rhour = -1;
+ int rv = LDAP_SUCCESS;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply ) {
+ return rv;
+ }
+
+ if ( rhour_str && *rhour_str != '\0' )
+ rhour = atol( rhour_str );
+ if ( rhour > 23 )
+ rhour = rhour % 24;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_rotationsynchour = rhour;
+ loginfo.log_access_rotationsyncclock = log_get_rotationsyncclock( rhour, loginfo.log_access_rotationsyncmin );
+ fe_cfg->accesslog_rotationsynchour = rhour;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_rotationsynchour = rhour;
+ loginfo.log_error_rotationsyncclock = log_get_rotationsyncclock( rhour, loginfo.log_error_rotationsyncmin );
+ fe_cfg->errorlog_rotationsynchour = rhour;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_rotationsynchour = rhour;
+ loginfo.log_audit_rotationsyncclock = log_get_rotationsyncclock( rhour, loginfo.log_audit_rotationsyncmin );
+ fe_cfg->auditlog_rotationsynchour = rhour;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+
+ return rv;
+}
+
+int
+log_set_rotationsyncmin(const char *attrname, char *rmin_str, int logtype, char *returntext, int apply)
+{
+ int rmin = -1;
+ int rv = LDAP_SUCCESS;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply ) {
+ return rv;
+ }
+
+ if ( rmin_str && *rmin_str != '\0' )
+ rmin = atol( rmin_str );
+ if ( rmin > 59 )
+ rmin = rmin % 60;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_rotationsyncmin = rmin;
+ fe_cfg->accesslog_rotationsyncmin = rmin;
+ loginfo.log_access_rotationsyncclock = log_get_rotationsyncclock( loginfo.log_access_rotationsynchour, rmin );
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_rotationsyncmin = rmin;
+ loginfo.log_error_rotationsyncclock = log_get_rotationsyncclock( loginfo.log_error_rotationsynchour, rmin );
+ fe_cfg->errorlog_rotationsyncmin = rmin;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_rotationsyncmin = rmin;
+ fe_cfg->auditlog_rotationsyncmin = rmin;
+ loginfo.log_audit_rotationsyncclock = log_get_rotationsyncclock( loginfo.log_audit_rotationsynchour, rmin );
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+
+ return rv;
+}
+
+/******************************************************************************
+* ROTATION TIME
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int
+log_set_rotationtime(const char *attrname, char *rtime_str, int logtype, char *returntext, int apply)
+{
+
+ int runit= 0;
+ int value, rtime;
+ int rv = LDAP_SUCCESS;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply || !rtime_str || !*rtime_str) {
+ return rv;
+ }
+
+ rtime = atoi(rtime_str);
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_rotationtime = rtime;
+ runit = loginfo.log_access_rotationunit;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_rotationtime = rtime;
+ runit = loginfo.log_error_rotationunit;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_rotationtime = rtime;
+ runit = loginfo.log_audit_rotationunit;
+ break;
+ default:
+ rv = 1;
+ }
+
+ /* find out the rotation unit we have se right now */
+ if (runit == LOG_UNIT_MONTHS) {
+ value = 31 * 24 * 60 * 60 * rtime;
+ } else if (runit == LOG_UNIT_WEEKS) {
+ value = 7 * 24 * 60 * 60 * rtime;
+ } else if (runit == LOG_UNIT_DAYS ) {
+ value = 24 * 60 * 60 * rtime;
+ } else if (runit == LOG_UNIT_HOURS) {
+ value = 3600 * rtime;
+ } else if (runit == LOG_UNIT_MINS) {
+ value = 60 * rtime;
+ } else {
+ /* In this case we don't rotate */
+ value = -1;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ fe_cfg->accesslog_rotationtime = rtime;
+ loginfo.log_access_rotationtime_secs = value;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ fe_cfg->errorlog_rotationtime = rtime;
+ loginfo.log_error_rotationtime_secs = value;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ fe_cfg->auditlog_rotationtime = rtime;
+ loginfo.log_audit_rotationtime_secs = value;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+ return rv;
+}
+/******************************************************************************
+* ROTATION TIME UNIT
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int log_set_rotationtimeunit(const char *attrname, char *runit, int logtype, char *errorbuf, int apply)
+{
+ int value= 0;
+ int runitType;
+ int rv = 0;
+
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( (strcasecmp(runit, "month") == 0) ||
+ (strcasecmp(runit, "week") == 0) ||
+ (strcasecmp(runit, "day") == 0) ||
+ (strcasecmp(runit, "hour") == 0) ||
+ (strcasecmp(runit, "minute") == 0)) {
+ /* all good values */
+ } else {
+ PR_snprintf ( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: unknown unit \"%s\"", attrname, runit );
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply ) {
+ return rv;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ value = loginfo.log_access_rotationtime;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ value = loginfo.log_error_rotationtime;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ value = loginfo.log_audit_rotationtime;
+ break;
+ default:
+ rv = 1;
+ }
+
+ if (strcasecmp(runit, "month") == 0) {
+ runitType = LOG_UNIT_MONTHS;
+ value *= 31 * 24 * 60 * 60;
+ } else if (strcasecmp(runit, "week") == 0) {
+ runitType = LOG_UNIT_WEEKS;
+ value *= 7 * 24 * 60 * 60;
+ } else if (strcasecmp(runit, "day") == 0) {
+ runitType = LOG_UNIT_DAYS;
+ value *= 24 * 60 * 60;
+ } else if (strcasecmp(runit, "hour") == 0) {
+ runitType = LOG_UNIT_HOURS;
+ value *= 3600;
+ } else if (strcasecmp(runit, "minute") == 0) {
+ runitType = LOG_UNIT_MINS;
+ value *= 60;
+ } else {
+ /* In this case we don't rotate */
+ runitType = LOG_UNIT_UNKNOWN;
+ value = -1;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ loginfo.log_access_rotationtime_secs = value;
+ loginfo.log_access_rotationunit = runitType;
+ slapi_ch_free ( (void **) &fe_cfg->accesslog_rotationunit);
+ fe_cfg->accesslog_rotationunit = slapi_ch_strdup ( runit );
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ loginfo.log_error_rotationtime_secs = value;
+ loginfo.log_error_rotationunit = runitType;
+ slapi_ch_free ( (void **) &fe_cfg->errorlog_rotationunit) ;
+ fe_cfg->errorlog_rotationunit = slapi_ch_strdup ( runit );
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ loginfo.log_audit_rotationtime_secs = value;
+ loginfo.log_audit_rotationunit = runitType;
+ slapi_ch_free ( (void **) &fe_cfg->auditlog_rotationunit);
+ fe_cfg->auditlog_rotationunit = slapi_ch_strdup ( runit );
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+ return rv;
+}
+/******************************************************************************
+* MAXIMUM DISK SPACE
+* Return Values:
+* 1 -- fail
+* 0 -- success
+*
+* NOTE:
+* The config struct should contain the value in MB and not in bytes.
+******************************************************************************/
+int
+log_set_maxdiskspace(const char *attrname, char *maxdiskspace_str, int logtype, char *errorbuf, int apply)
+{
+ int rv = 0;
+ int mlogsize;
+ int maxdiskspace;
+ int s_maxdiskspace;
+
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (!apply || !maxdiskspace_str || !*maxdiskspace_str)
+ return rv;
+
+ maxdiskspace = atoi(maxdiskspace_str);
+ s_maxdiskspace = maxdiskspace;
+
+ /* Disk space are in MB but store in bytes */
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ mlogsize = loginfo.log_access_maxlogsize;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ mlogsize = loginfo.log_error_maxlogsize;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ mlogsize = loginfo.log_audit_maxlogsize;
+ break;
+ default:
+ rv = 1;
+ mlogsize = -1;
+ }
+ maxdiskspace *= LOG_MB_IN_BYTES;
+ if (maxdiskspace < 0) {
+ maxdiskspace = -1;
+ }
+ else if (maxdiskspace < mlogsize) {
+ rv = LDAP_OPERATIONS_ERROR;
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: maxdiskspace \"%d\" is less than max log size \"%d\"",
+ attrname, maxdiskspace, mlogsize );
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ if (rv== 0 && apply) {
+ loginfo.log_access_maxdiskspace = maxdiskspace;
+ fe_cfg->accesslog_maxdiskspace = s_maxdiskspace ;
+ }
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ if (rv== 0 && apply) {
+ loginfo.log_error_maxdiskspace = maxdiskspace;
+ fe_cfg->errorlog_maxdiskspace = s_maxdiskspace;
+ }
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ if (rv== 0 && apply) {
+ loginfo.log_audit_maxdiskspace = maxdiskspace;
+ fe_cfg->auditlog_maxdiskspace = s_maxdiskspace;
+ }
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid maximum log disk size:"
+ "Maxdiskspace:%d MB Maxlogsize:%d MB \n",
+ attrname, maxdiskspace, mlogsize);
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+ return rv;
+
+}
+/******************************************************************************
+* MINIMUM FREE SPACE
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int
+log_set_mindiskspace(const char *attrname, char *minfreespace_str, int logtype, char *errorbuf, int apply)
+{
+ int rv=LDAP_SUCCESS;
+ int minfreespaceB;
+ int minfreespace;
+
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply || !minfreespace_str || !*minfreespace_str) {
+ return rv;
+ }
+
+ minfreespace = atoi(minfreespace_str);
+
+ /* Disk space are in MB but store in bytes */
+ if (minfreespace >= 1 ) {
+ minfreespaceB = minfreespace * LOG_MB_IN_BYTES;
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_minfreespace = minfreespaceB;
+ fe_cfg->accesslog_minfreespace = minfreespace;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_minfreespace = minfreespaceB;
+ fe_cfg->errorlog_minfreespace = minfreespace;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_minfreespace = minfreespaceB;
+ fe_cfg->auditlog_minfreespace = minfreespace;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+ }
+ return rv;
+}
+/******************************************************************************
+* LOG EXPIRATION TIME
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int
+log_set_expirationtime(const char *attrname, char *exptime_str, int logtype, char *errorbuf, int apply)
+{
+
+ int eunit, value, exptime;
+ int rsec=0;
+ int rv = 0;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ rv = LDAP_OPERATIONS_ERROR;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply || !exptime_str || !*exptime_str) {
+ return rv;
+ }
+
+ exptime = atoi(exptime_str);
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ loginfo.log_access_exptime = exptime;
+ eunit = loginfo.log_access_exptimeunit;
+ rsec = loginfo.log_access_rotationtime_secs;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ loginfo.log_error_exptime = exptime;
+ eunit = loginfo.log_error_exptimeunit;
+ rsec = loginfo.log_error_rotationtime_secs;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ loginfo.log_audit_exptime = exptime;
+ eunit = loginfo.log_audit_exptimeunit;
+ rsec = loginfo.log_audit_rotationtime_secs;
+ break;
+ default:
+ rv = 1;
+ eunit = -1;
+ }
+
+ if (eunit == LOG_UNIT_MONTHS) {
+ value = 31 * 24 * 60 * 60 * exptime;
+ } else if (eunit == LOG_UNIT_WEEKS) {
+ value = 7 * 24 * 60 * 60 * exptime;
+ } else if (eunit == LOG_UNIT_DAYS) {
+ value = 24 * 60 * 60 * exptime;
+ } else {
+ /* In this case we don't expire */
+ value = -1;
+ }
+
+ if (value < rsec) {
+ value = rsec;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ loginfo.log_access_exptime_secs = value;
+ fe_cfg->accesslog_exptime = exptime;
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ loginfo.log_error_exptime_secs = value;
+ fe_cfg->errorlog_exptime = exptime;
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ loginfo.log_audit_exptime_secs = value;
+ fe_cfg->auditlog_exptime = exptime;
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+
+ return rv;
+}
+/******************************************************************************
+* LOG EXPIRATION TIME UNIT
+* Return Values:
+* 1 -- fail
+* 0 -- success
+******************************************************************************/
+int
+log_set_expirationtimeunit(const char *attrname, char *expunit, int logtype, char *errorbuf, int apply)
+{
+ int value = 0;
+ int rv = 0;
+ int eunit, etimeunit, rsecs;
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+
+ if ( logtype != SLAPD_ACCESS_LOG &&
+ logtype != SLAPD_ERROR_LOG &&
+ logtype != SLAPD_AUDIT_LOG ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid log type: %d", attrname, logtype );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( NULL == expunit ) {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: NULL value", attrname );
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( (strcasecmp(expunit, "month") == 0) ||
+ (strcasecmp(expunit, "week") == 0) ||
+ (strcasecmp(expunit, "day") == 0)) {
+ /* we have good values */
+ } else {
+ PR_snprintf( errorbuf, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: invalid time unit \"%s\"", attrname, expunit );
+ rv = LDAP_OPERATIONS_ERROR;;
+ }
+
+ /* return if we aren't doing this for real */
+ if ( !apply ) {
+ return rv;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_WRITE( );
+ etimeunit = loginfo.log_access_exptime;
+ rsecs = loginfo.log_access_rotationtime_secs;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_WRITE( );
+ etimeunit = loginfo.log_error_exptime;
+ rsecs = loginfo.log_error_rotationtime_secs;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_WRITE( );
+ etimeunit = loginfo.log_audit_exptime;
+ rsecs = loginfo.log_audit_rotationtime_secs;
+ break;
+ default:
+ rv = 1;
+ etimeunit = -1;
+ rsecs = -1;
+ }
+
+ if (strcasecmp(expunit, "month") == 0) {
+ eunit = LOG_UNIT_MONTHS;
+ value = 31 * 24 * 60 * 60 * etimeunit;
+ } else if (strcasecmp(expunit, "week") == 0) {
+ eunit = LOG_UNIT_WEEKS;
+ value = 7 * 24 * 60 * 60 * etimeunit;
+ } else if (strcasecmp(expunit, "day") == 0) {
+ eunit = LOG_UNIT_DAYS;
+ value = 24 * 60 * 60 * etimeunit;
+ } else {
+ eunit = LOG_UNIT_UNKNOWN;
+ value = -1;
+ }
+
+ if ((value> 0) && value < rsecs ) {
+ value = rsecs;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ loginfo.log_access_exptime_secs = value;
+ slapi_ch_free ( (void **) &(fe_cfg->accesslog_exptimeunit) );
+ fe_cfg->accesslog_exptimeunit = slapi_ch_strdup ( expunit );
+ LOG_ACCESS_UNLOCK_WRITE();
+ break;
+ case SLAPD_ERROR_LOG:
+ loginfo.log_error_exptime_secs = value;
+ slapi_ch_free ( (void **) &(fe_cfg->errorlog_exptimeunit) );
+ fe_cfg->errorlog_exptimeunit = slapi_ch_strdup ( expunit );
+ LOG_ERROR_UNLOCK_WRITE();
+ break;
+ case SLAPD_AUDIT_LOG:
+ loginfo.log_audit_exptime_secs = value;
+ slapi_ch_free ( (void **) &(fe_cfg->auditlog_exptimeunit) );
+ fe_cfg->auditlog_exptimeunit = slapi_ch_strdup ( expunit );
+ LOG_AUDIT_UNLOCK_WRITE();
+ break;
+ default:
+ rv = 1;
+ }
+
+ return rv;
+}
+
+/******************************************************************************
+ * Write title line in log file
+ *****************************************************************************/
+static void
+log_write_title (LOGFD fp)
+{
+ slapdFrontendConfig_t *fe_cfg = getFrontendConfig();
+ char *buildnum = config_get_buildnum();
+ char buff[512];
+ int bufflen = sizeof(buff);
+
+ PR_snprintf(buff, bufflen, "\t%s B%s\n",
+ fe_cfg->versionstring ? fe_cfg->versionstring : "Netscape-Directory",
+ buildnum ? buildnum : "");
+ LOG_WRITE_NOW(fp, buff, strlen(buff), 0);
+
+ if (fe_cfg->localhost) {
+ PR_snprintf(buff, bufflen, "\t%s:%d (%s)\n\n",
+ fe_cfg->localhost,
+ fe_cfg->security ? fe_cfg->secureport : fe_cfg->port,
+ fe_cfg->instancedir ? fe_cfg->instancedir : "");
+ }
+ else {
+ /* If fe_cfg->localhost is not set, ignore fe_cfg->port since
+ * it is the default and might be misleading.
+ */
+ PR_snprintf(buff, bufflen, "\t<host>:<port> (%s)\n\n",
+ fe_cfg->instancedir ? fe_cfg->instancedir : "");
+ }
+ LOG_WRITE_NOW(fp, buff, strlen(buff), 0);
+ slapi_ch_free((void **)&buildnum);
+}
+
+/******************************************************************************
+* init function for the error log
+* Returns:
+* 0 - success
+* 1 - fail
+******************************************************************************/
+int error_log_openf( char *pathname, int locked)
+{
+
+ int rv = 0;
+ int logfile_type =0;
+ char buf[BUFSIZ];
+
+ if (!locked) LOG_ERROR_LOCK_WRITE ();
+ /* save the file name */
+ slapi_ch_free ((void**)&loginfo.log_error_file);
+ loginfo.log_error_file = slapi_ch_strdup(pathname);
+
+ /* store the rotation info fiel path name */
+ sprintf (buf, "%s.rotationinfo",pathname);
+ slapi_ch_free ((void**)&loginfo.log_errorinfo_file);
+ loginfo.log_errorinfo_file = slapi_ch_strdup ( buf );
+
+ /*
+ ** Check if we have a log file already. If we have it then
+ ** we need to parse the header info and update the loginfo
+ ** struct.
+ */
+ logfile_type = log__error_rotationinfof(loginfo.log_errorinfo_file);
+
+ if (log__open_errorlogfile(logfile_type, 1/* got lock*/) != LOG_SUCCESS) {
+ rv = 1;
+ }
+
+ if (!locked) LOG_ERROR_UNLOCK_WRITE();
+ return rv;
+
+}
+/******************************************************************************
+* init function for the audit log
+* Returns:
+* 0 - success
+* 1 - fail
+******************************************************************************/
+int
+audit_log_openf( char *pathname, int locked)
+{
+
+ int rv=0;
+ int logfile_type = 0;
+ char buf[BUFSIZ];
+
+ if (!locked) LOG_AUDIT_LOCK_WRITE( );
+
+ /* store the path name */
+ loginfo.log_audit_file = slapi_ch_strdup ( pathname );
+
+ /* store the rotation info file path name */
+ sprintf (buf, "%s.rotationinfo",pathname);
+ loginfo.log_auditinfo_file = slapi_ch_strdup ( buf );
+
+ /*
+ ** Check if we have a log file already. If we have it then
+ ** we need to parse the header info and update the loginfo
+ ** struct.
+ */
+ logfile_type = log__audit_rotationinfof(loginfo.log_auditinfo_file);
+
+ if (log__open_auditlogfile(logfile_type, 1/* got lock*/) != LOG_SUCCESS) {
+ rv = 1;
+ }
+
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+
+ return rv;
+}
+/******************************************************************************
+* write in the audit log
+******************************************************************************/
+int
+slapd_log_audit_proc (
+ char *buffer,
+ int buf_len)
+{
+ if ( (loginfo.log_audit_state & LOGGING_ENABLED) && (loginfo.log_audit_file != NULL) ){
+ LOG_AUDIT_LOCK_WRITE( );
+ if (log__needrotation(loginfo.log_audit_fdes,
+ SLAPD_AUDIT_LOG) == LOG_ROTATE) {
+ if (log__open_auditlogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "LOGINFO: Unable to open audit file:%s\n",
+ loginfo.log_audit_file,0,0);
+ LOG_AUDIT_UNLOCK_WRITE();
+ return 0;
+ }
+ while (loginfo.log_audit_rotationsyncclock <= loginfo.log_audit_ctime) {
+ loginfo.log_audit_rotationsyncclock += loginfo.log_audit_rotationtime_secs;
+ }
+ }
+ if (loginfo.log_audit_state & LOGGING_NEED_TITLE) {
+ log_write_title( loginfo.log_audit_fdes);
+ loginfo.log_audit_state &= ~LOGGING_NEED_TITLE;
+ }
+ LOG_WRITE_NOW(loginfo.log_audit_fdes, buffer, buf_len, 0);
+ LOG_AUDIT_UNLOCK_WRITE();
+ return 0;
+ }
+ return 0;
+}
+/******************************************************************************
+* write in the error log
+******************************************************************************/
+int
+slapd_log_error_proc(
+ char *subsystem, /* omitted if NULL */
+ char *fmt,
+ ... )
+{
+ va_list ap_err;
+ va_list ap_file;
+ va_start( ap_err, fmt );
+ va_start( ap_file, fmt );
+ slapd_log_error_proc_internal(subsystem, fmt, ap_err, ap_file);
+ va_end(ap_err);
+ va_end(ap_file);
+ return 0;
+}
+
+static int
+slapd_log_error_proc_internal(
+ char *subsystem, /* omitted if NULL */
+ char *fmt,
+ va_list ap_err,
+ va_list ap_file)
+{
+ int rc = 0;
+
+ if ( (loginfo.log_error_state & LOGGING_ENABLED) && (loginfo.log_error_file != NULL) ) {
+ LOG_ERROR_LOCK_WRITE( );
+ if (log__needrotation(loginfo.log_error_fdes,
+ SLAPD_ERROR_LOG) == LOG_ROTATE) {
+ if (log__open_errorlogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) {
+ LOG_ERROR_UNLOCK_WRITE();
+ return 0;
+ }
+ while (loginfo.log_error_rotationsyncclock <= loginfo.log_error_ctime) {
+ loginfo.log_error_rotationsyncclock += loginfo.log_error_rotationtime_secs;
+ }
+ }
+
+ if (!(detached)) {
+ rc = vslapd_log_error( NULL, subsystem, fmt, ap_err );
+ }
+ if ( loginfo.log_error_fdes != NULL ) {
+ if (loginfo.log_error_state & LOGGING_NEED_TITLE) {
+ log_write_title(loginfo.log_error_fdes);
+ loginfo.log_error_state &= ~LOGGING_NEED_TITLE;
+ }
+ rc = vslapd_log_error( loginfo.log_error_fdes, subsystem, fmt, ap_file );
+ }
+ LOG_ERROR_UNLOCK_WRITE();
+ } else {
+ /* log the problem in the stderr */
+ rc = vslapd_log_error( NULL, subsystem, fmt, ap_err );
+ }
+ return( rc );
+}
+
+static int
+vslapd_log_error(
+ LOGFD fp,
+ char *subsystem, /* omitted if NULL */
+ char *fmt,
+ va_list ap )
+{
+ time_t tnl;
+ long tz;
+ struct tm *tmsp, tms;
+ char tbuf[ TBUFSIZE ];
+ char sign;
+ char buffer[SLAPI_LOG_BUFSIZ];
+ int blen;
+ char *vbuf;
+ int header_len = 0;
+
+ tnl = current_time();
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &tnl );
+ tmsp = &tms;
+ memcpy(&tms, pt, sizeof(struct tm) );
+ }
+#else
+ (void)localtime_r( &tnl, &tms );
+ tmsp = &tms;
+#endif
+#ifdef BSD_TIME
+ tz = tmsp->tm_gmtoff;
+#else /* BSD_TIME */
+ tz = - timezone;
+ if ( tmsp->tm_isdst ) {
+ tz += 3600;
+ }
+#endif /* BSD_TIME */
+ sign = ( tz >= 0 ? '+' : '-' );
+ if ( tz < 0 ) {
+ tz = -tz;
+ }
+ (void)strftime( tbuf, (size_t)TBUFSIZE, "%d/%b/%Y:%H:%M:%S", tmsp);
+ sprintf( buffer, "[%s %c%02d%02d]%s%s - ", tbuf, sign,
+ (int)( tz / 3600 ), (int)( tz % 3600 ),
+ subsystem ? " " : "",
+ subsystem ? subsystem : "");
+
+ /* Bug 561525: to be able to remove timestamp to not over pollute syslog, we may need
+ to skip the timestamp part of the message.
+ The size of the header is:
+ the size of the time string
+ + size of space
+ + size of one char (sign)
+ + size of 2 char
+ + size of 2 char
+ + size of [
+ + size of ]
+ */
+
+ header_len = strlen(tbuf) + 8;
+
+ if ((vbuf = PR_vsmprintf(fmt, ap)) == NULL) {
+ return -1;
+ }
+ blen = strlen(buffer);
+ if ((unsigned int)(SLAPI_LOG_BUFSIZ - blen ) < strlen(vbuf)) {
+ free (vbuf);
+ return -1;
+ }
+
+ sprintf (buffer+blen, "%s", vbuf);
+
+ if (fp)
+ LOG_WRITE_NOW(fp, buffer, strlen(buffer), header_len);
+
+
+ else /* stderr is always unbuffered */
+ fprintf(stderr, "%s", buffer);
+
+ free (vbuf);
+ return( 0 );
+}
+
+int
+slapi_log_error( int severity, char *subsystem, char *fmt, ... )
+{
+ va_list ap1;
+ va_list ap2;
+ int rc;
+
+ if ( severity < SLAPI_LOG_MIN || severity > SLAPI_LOG_MAX ) {
+ (void)slapd_log_error_proc( subsystem,
+ "slapi_log_error: invalid severity %d (message %s)\n",
+ severity, fmt );
+ return( -1 );
+ }
+
+
+#ifdef _WIN32
+ if ( *module_ldap_debug
+#else
+ if ( slapd_ldap_debug
+#endif
+ & slapi_log_map[ severity ] ) {
+ va_start( ap1, fmt );
+ va_start( ap2, fmt );
+ rc = slapd_log_error_proc_internal( subsystem, fmt, ap1, ap2 );
+ va_end( ap1 );
+ va_end( ap2 );
+ } else {
+ rc = 0; /* nothing to be logged --> always return success */
+ }
+
+ return( rc );
+}
+
+int
+slapi_is_loglevel_set ( const int loglevel )
+{
+
+ return (
+#ifdef _WIN32
+ *module_ldap_debug
+#else
+ slapd_ldap_debug
+#endif
+ & slapi_log_map[ loglevel ] ? 1 : 0);
+}
+
+
+/******************************************************************************
+* write in the access log
+******************************************************************************/
+static int vslapd_log_access(char *fmt, va_list ap)
+{
+ time_t tnl;
+ long tz;
+ struct tm *tmsp, tms;
+ char tbuf[ TBUFSIZE ];
+ char sign;
+ char buffer[SLAPI_LOG_BUFSIZ];
+ char vbuf[SLAPI_LOG_BUFSIZ];
+ int blen, vlen;
+ /* info needed to keep us from calling localtime/strftime so often: */
+ static time_t old_time = 0;
+ static char old_tbuf[TBUFSIZE];
+ static int old_blen = 0;
+
+ tnl = current_time();
+
+ /* check if we can use the old strftime buffer */
+ PR_Lock(ts_time_lock);
+ if (tnl == old_time) {
+ strcpy(buffer, old_tbuf);
+ blen = old_blen;
+ PR_Unlock(ts_time_lock);
+ } else {
+ /* nope... painstakingly create the new strftime buffer */
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &tnl );
+ tmsp = &tms;
+ memcpy(&tms, pt, sizeof(struct tm) );
+ }
+#else
+ (void)localtime_r( &tnl, &tms );
+ tmsp = &tms;
+#endif
+
+#ifdef BSD_TIME
+ tz = tmsp->tm_gmtoff;
+#else /* BSD_TIME */
+ tz = - timezone;
+ if ( tmsp->tm_isdst ) {
+ tz += 3600;
+ }
+#endif /* BSD_TIME */
+ sign = ( tz >= 0 ? '+' : '-' );
+ if ( tz < 0 ) {
+ tz = -tz;
+ }
+ (void)strftime( tbuf, (size_t)TBUFSIZE, "%d/%b/%Y:%H:%M:%S", tmsp);
+ sprintf( buffer, "[%s %c%02d%02d] ", tbuf, sign,
+ (int)( tz / 3600 ), (int)( tz % 3600));
+ old_time = tnl;
+ strcpy(old_tbuf, buffer);
+ blen = strlen(buffer);
+ old_blen = blen;
+ PR_Unlock(ts_time_lock);
+ }
+
+ vlen = PR_vsnprintf(vbuf, SLAPI_LOG_BUFSIZ, fmt, ap);
+ if (! vlen) {
+ return -1;
+ }
+
+ if (SLAPI_LOG_BUFSIZ - blen < vlen) {
+ return -1;
+ }
+
+ log_append_buffer2(tnl, loginfo.log_access_buffer, buffer, blen, vbuf, vlen);
+
+ return( 0 );
+}
+
+int
+slapi_log_access( int level,
+ char *fmt,
+ ... )
+{
+ va_list ap;
+ int rc=0;
+
+ if (!(loginfo.log_access_state & LOGGING_ENABLED)) {
+ return 0;
+ }
+ va_start( ap, fmt );
+ if (( level & loginfo.log_access_level ) &&
+ ( loginfo.log_access_fdes != NULL ) && (loginfo.log_access_file != NULL) ) {
+ rc = vslapd_log_access(fmt, ap);
+ }
+ va_end( ap );
+ return( rc );
+}
+
+/******************************************************************************
+* access_log_openf
+*
+* Open the access log file
+*
+* Returns:
+* 0 -- success
+* 1 -- fail
+******************************************************************************/
+int access_log_openf(char *pathname, int locked)
+{
+ int rv=0;
+ int logfile_type = 0;
+ char buf[BUFSIZ];
+
+ if (!locked) LOG_ACCESS_LOCK_WRITE( );
+
+ /* store the path name */
+ loginfo.log_access_file = slapi_ch_strdup ( pathname );
+
+ /* store the rotation info fiel path name */
+ sprintf (buf, "%s.rotationinfo",pathname);
+ loginfo.log_accessinfo_file = slapi_ch_strdup ( buf );
+
+ /*
+ ** Check if we have a log file already. If we have it then
+ ** we need to parse the header info and update the loginfo
+ ** struct.
+ */
+ logfile_type = log__access_rotationinfof(loginfo.log_accessinfo_file);
+
+ if (log__open_accesslogfile(logfile_type, 1/* got lock*/) != LOG_SUCCESS) {
+ rv = 1;
+ }
+
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE();
+
+
+ return rv;
+}
+
+/******************************************************************************
+* log__open_accesslogfile
+*
+* Open a new log file. If we have run out of the max logs we can have
+* then delete the oldest file.
+******************************************************************************/
+static int
+log__open_accesslogfile(int logfile_state, int locked)
+{
+
+ time_t now;
+ LOGFD fp;
+ LOGFD fpinfo = NULL;
+ char tbuf[TBUFSIZE];
+ struct logfileinfo *logp;
+ char buffer[BUFSIZ];
+
+ if (!locked) LOG_ACCESS_LOCK_WRITE( );
+
+ /*
+ ** Here we are trying to create a new log file.
+ ** If we alredy have one, then we need to rename it as
+ ** "filename.time", close it and update it's information
+ ** in the array stack.
+ */
+ if (loginfo.log_access_fdes != NULL) {
+ struct logfileinfo *log;
+ char newfile[BUFSIZ];
+ int f_size;
+
+ /* get rid of the old one */
+ if ((f_size = log__getfilesize(loginfo.log_access_fdes)) == -1) {
+ /* Then assume that we have the max size */
+ f_size = loginfo.log_access_maxlogsize;
+ }
+
+ /* Check if I have to delete any old file, delete it if it is required.
+ ** If there is just one file, then access and access.rotation files
+ ** are deleted. After that we start fresh
+ */
+ while (log__delete_access_logfile());
+
+ /* close the file */
+ LOG_CLOSE(loginfo.log_access_fdes);
+ /*
+ * loginfo.log_access_fdes is not set to NULL here, otherwise
+ * slapi_log_access() will not send a message to the access log
+ * if it is called between this point and where this field is
+ * set again after calling LOG_OPEN_APPEND.
+ */
+ if ( loginfo.log_access_maxnumlogs > 1 ) {
+ log = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ log->l_ctime = loginfo.log_access_ctime;
+ log->l_size = f_size;
+
+ log_convert_time (log->l_ctime, tbuf, 1 /*short */);
+ sprintf(newfile, "%s.%s", loginfo.log_access_file, tbuf);
+ if (PR_Rename (loginfo.log_access_file, newfile) != PR_SUCCESS) {
+ loginfo.log_access_fdes = NULL;
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE();
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+ /* add the log to the chain */
+ log->l_next = loginfo.log_access_logchain;
+ loginfo.log_access_logchain = log;
+ loginfo.log_numof_access_logs++;
+ }
+ }
+
+
+ /* open a new log file */
+ if (! LOG_OPEN_APPEND(fp, loginfo.log_access_file, loginfo.log_access_mode)) {
+ int oserr = errno;
+ loginfo.log_access_fdes = NULL;
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE();
+ LDAPDebug( LDAP_DEBUG_ANY, "access file open %s failed errno %d (%s)\n",
+ loginfo.log_access_file,
+ oserr, slapd_system_strerror(oserr));
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ loginfo.log_access_fdes = fp;
+ if (logfile_state == LOGFILE_REOPENED) {
+ /* we have all the information */
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+ }
+
+ loginfo.log_access_state |= LOGGING_NEED_TITLE;
+
+ if (! LOG_OPEN_WRITE(fpinfo, loginfo.log_accessinfo_file, loginfo.log_access_mode)) {
+ int oserr = errno;
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE();
+ LDAPDebug( LDAP_DEBUG_ANY, "accessinfo file open %s failed errno %d (%s)\n",
+ loginfo.log_accessinfo_file,
+ oserr, slapd_system_strerror(oserr));
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+
+ /* write the header in the log */
+ now = current_time();
+ log_convert_time (now, tbuf, 2 /* long */);
+ sprintf (buffer,"LOGINFO:Log file created at: %s (%lu)\n", tbuf, now);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+
+ logp = loginfo.log_access_logchain;
+ while ( logp) {
+ log_convert_time (logp->l_ctime, tbuf, 1 /*short*/);
+ sprintf(buffer, "LOGINFO:Previous Log File:%s.%s (%lu) (%u)\n",
+ loginfo.log_access_file, tbuf, logp->l_ctime, logp->l_size);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+ logp = logp->l_next;
+ }
+ /* Close the info file. We need only when we need to rotate to the
+ ** next log file.
+ */
+ if (fpinfo) LOG_CLOSE(fpinfo);
+
+ /* This is now the current access log */
+ loginfo.log_access_ctime = now;
+
+ if (!locked) LOG_ACCESS_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+}
+/******************************************************************************
+* log__needrotation
+*
+* Do we need to rotate the log file ?
+* Find out based on rotation time and the max log size;
+*
+* Return:
+* LOG_CONTINUE -- Use the same one
+* LOG_ROTATE -- log need to be rotated
+*
+* Note:
+* A READ LOCK is obtained.
+********************************************************************************/
+#define LOG_SIZE_EXCEEDED 1
+#define LOG_EXPIRED 2
+static int
+log__needrotation(LOGFD fp, int logtype)
+{
+ time_t curr_time;
+ time_t log_createtime= 0;
+ time_t syncclock;
+ int type = LOG_CONTINUE;
+ int f_size = 0;
+ int maxlogsize, nlogs;
+ int rotationtime_secs = -1;
+ int sync_enabled, synchour, syncmin, timeunit;
+
+ if (fp == NULL) {
+ return LOG_ROTATE;
+ }
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ nlogs = loginfo.log_access_maxnumlogs;
+ maxlogsize = loginfo.log_access_maxlogsize;
+ sync_enabled = loginfo.log_access_rotationsync_enabled;
+ synchour = loginfo.log_access_rotationsynchour;
+ syncmin = loginfo.log_access_rotationsyncmin;
+ syncclock = loginfo.log_access_rotationsyncclock;
+ timeunit = loginfo.log_access_rotationunit;
+ rotationtime_secs = loginfo.log_access_rotationtime_secs;
+ log_createtime = loginfo.log_access_ctime;
+ break;
+ case SLAPD_ERROR_LOG:
+ nlogs = loginfo.log_error_maxnumlogs;
+ maxlogsize = loginfo.log_error_maxlogsize;
+ sync_enabled = loginfo.log_error_rotationsync_enabled;
+ synchour = loginfo.log_error_rotationsynchour;
+ syncmin = loginfo.log_error_rotationsyncmin;
+ syncclock = loginfo.log_error_rotationsyncclock;
+ timeunit = loginfo.log_error_rotationunit;
+ rotationtime_secs = loginfo.log_error_rotationtime_secs;
+ log_createtime = loginfo.log_error_ctime;
+ break;
+ case SLAPD_AUDIT_LOG:
+ nlogs = loginfo.log_audit_maxnumlogs;
+ maxlogsize = loginfo.log_audit_maxlogsize;
+ sync_enabled = loginfo.log_audit_rotationsync_enabled;
+ synchour = loginfo.log_audit_rotationsynchour;
+ syncmin = loginfo.log_audit_rotationsyncmin;
+ syncclock = loginfo.log_audit_rotationsyncclock;
+ timeunit = loginfo.log_audit_rotationunit;
+ rotationtime_secs = loginfo.log_audit_rotationtime_secs;
+ log_createtime = loginfo.log_audit_ctime;
+ break;
+ default: /* error */
+ maxlogsize = -1;
+ nlogs = 1;
+
+ }
+
+ /* If we have one log then can't rotate at all */
+ if (nlogs == 1)
+ return LOG_CONTINUE;
+
+ if ((f_size = log__getfilesize(fp)) == -1) {
+ /* The next option is to rotate based on the rotation time */
+ f_size = 0;
+ }
+
+ /* If the log size is more than the limit, then it's time to rotate. */
+ if ((maxlogsize > 0) && (f_size >= maxlogsize)) {
+ type = LOG_SIZE_EXCEEDED;
+ goto log_rotate;
+ }
+
+ /* If rotation interval <= 0 then can't rotate by time */
+ if (rotationtime_secs <= 0)
+ return LOG_CONTINUE;
+
+ /*
+ ** If the log is older than the time allowed to be active,
+ ** then it's time to move on (i.e., rotate).
+ */
+ time (&curr_time);
+
+ if ( !sync_enabled || timeunit == LOG_UNIT_HOURS || timeunit == LOG_UNIT_MINS ) {
+ if (curr_time - log_createtime > rotationtime_secs) {
+ type = LOG_EXPIRED;
+ goto log_rotate;
+ }
+
+ } else if (curr_time > syncclock) {
+ type = LOG_EXPIRED;
+ goto log_rotate;
+ }
+
+log_rotate:
+ /*
+ ** Don't send messages to the error log whilst we're rotating it.
+ ** This'll lead to a recursive call to the logging function, and
+ ** an assertion trying to relock the write lock.
+ */
+ if (logtype!=SLAPD_ERROR_LOG)
+ {
+ if (type == LOG_SIZE_EXCEEDED) {
+ LDAPDebug (LDAP_DEBUG_TRACE,
+ "LOGINFO:End of Log because size exceeded(Max:%d bytes) (Is:%d bytes)\n", maxlogsize, f_size, 0);
+ } else if ( type == LOG_EXPIRED) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:End of Log because time exceeded(Max:%d secs) (Is:%d secs)\n",
+ rotationtime_secs, curr_time - log_createtime,0);
+ }
+ }
+ return (type == LOG_CONTINUE) ? LOG_CONTINUE : LOG_ROTATE;
+}
+
+/******************************************************************************
+* log__delete_access_logfile
+*
+* Do we need to delete a logfile. Find out if we need to delete the log
+* file based on expiration time, max diskspace, and minfreespace.
+* Delete the file if we need to.
+*
+* Assumption: A WRITE lock has been acquired for the ACCESS
+******************************************************************************/
+
+static int
+log__delete_access_logfile()
+{
+
+ struct logfileinfo *logp = NULL;
+ struct logfileinfo *delete_logp = NULL;
+ struct logfileinfo *p_delete_logp = NULL;
+ struct logfileinfo *prev_logp = NULL;
+ int total_size=0;
+ time_t cur_time;
+ int f_size;
+ int numoflogs=loginfo.log_numof_access_logs;
+ int rv = 0;
+ char *logstr;
+ char buffer[BUFSIZ];
+ char tbuf[TBUFSIZE];
+
+ /* If we have only one log, then will delete this one */
+ if (loginfo.log_access_maxnumlogs == 1) {
+ LOG_CLOSE(loginfo.log_access_fdes);
+ loginfo.log_access_fdes = NULL;
+ sprintf (buffer, "%s", loginfo.log_access_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s\n", loginfo.log_access_file,0,0);
+ }
+
+ /* Delete the rotation file also. */
+ sprintf (buffer, "%s.rotationinfo", loginfo.log_access_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_access_file,0,0);
+ }
+ return 0;
+ }
+
+ /* If we have already the maximum number of log files, we
+ ** have to delete one any how.
+ */
+ if (++numoflogs > loginfo.log_access_maxnumlogs) {
+ logstr = "Exceeded max number of logs allowed";
+ goto delete_logfile;
+ }
+
+ /* Now check based on the maxdiskspace */
+ if (loginfo.log_access_maxdiskspace > 0) {
+ logp = loginfo.log_access_logchain;
+ while (logp) {
+ total_size += logp->l_size;
+ logp = logp->l_next;
+ }
+ if ((f_size = log__getfilesize(loginfo.log_access_fdes)) == -1) {
+ /* then just assume the max size */
+ total_size += loginfo.log_access_maxlogsize;
+ } else {
+ total_size += f_size;
+ }
+
+ /* If we have exceeded the max disk space or we have less than the
+ ** minimum, then we have to delete a file.
+ */
+ if (total_size >= loginfo.log_access_maxdiskspace) {
+ logstr = "exceeded maximum log disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the free space */
+ if ( loginfo.log_access_minfreespace > 0) {
+ rv = log__enough_freespace(loginfo.log_access_file);
+ if ( rv == 0) {
+ /* Not enough free space */
+ logstr = "Not enough free disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the expiration time */
+ if ( loginfo.log_access_exptime_secs > 0 ) {
+ /* is the file old enough */
+ time (&cur_time);
+ prev_logp = logp = loginfo.log_access_logchain;
+ while (logp) {
+ if ((cur_time - logp->l_ctime) > loginfo.log_access_exptime_secs) {
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ logstr = "The file is older than the log expiration time";
+ goto delete_logfile;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ }
+
+ /* No log files to delete */
+ return 0;
+
+delete_logfile:
+ if (delete_logp == NULL) {
+ time_t oldest;
+
+ time(&oldest);
+
+ prev_logp = logp = loginfo.log_access_logchain;
+ while (logp) {
+ if (logp->l_ctime <= oldest) {
+ oldest = logp->l_ctime;
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ /* We might face this case if we have only one log file and
+ ** trying to delete it because of deletion requirement.
+ */
+ if (!delete_logp) {
+ return 0;
+ }
+ }
+
+ if (p_delete_logp == delete_logp) {
+ /* then we are deleteing the first one */
+ loginfo.log_access_logchain = delete_logp->l_next;
+ } else {
+ p_delete_logp->l_next = delete_logp->l_next;
+ }
+
+
+ /* Delete the access file */
+ log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
+ sprintf (buffer, "%s.%s", loginfo.log_access_file, tbuf);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.%s\n",
+ loginfo.log_access_file,tbuf,0);
+
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Removed file:%s.%s because of (%s)\n",
+ loginfo.log_access_file, tbuf,
+ logstr);
+ }
+ slapi_ch_free((void**)&delete_logp);
+ loginfo.log_numof_access_logs--;
+
+ return 1;
+}
+/******************************************************************************
+* log__access_rotationinfof
+*
+* Try to open the log file. If we have one already, then try to read the
+* header and update the information.
+*
+* Assumption: Lock has been acquired already
+******************************************************************************/
+static int
+log__access_rotationinfof( char *pathname)
+{
+ long f_ctime;
+ int f_size;
+ int main_log = 1;
+ time_t now;
+ FILE *fp;
+
+
+ /*
+ ** Okay -- I confess, we want to use NSPR calls but I want to
+ ** use fgets and not use PR_Read() and implement a complicated
+ ** parsing module. Since this will be called only during the startup
+ ** and never aftre that, we can live by it.
+ */
+
+ if ((fp = fopen (pathname, "r")) == NULL) {
+ return LOGFILE_NEW;
+ }
+
+ loginfo.log_numof_access_logs = 0;
+
+ /*
+ ** We have reopened the log access file. Now we need to read the
+ ** log file info and update the values.
+ */
+ while (log__extract_logheader(fp, &f_ctime, &f_size) == LOG_CONTINUE) {
+ /* first we would get the main log info */
+ if (f_ctime == 0 && f_size == 0)
+ continue;
+
+ time (&now);
+ if (main_log) {
+ if (f_ctime > 0L)
+ loginfo.log_access_ctime = f_ctime;
+ else {
+ loginfo.log_access_ctime = now;
+ }
+ main_log = 0;
+ } else {
+ struct logfileinfo *logp;
+
+ logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ if (f_ctime > 0L)
+ logp->l_ctime = f_ctime;
+ else
+ logp->l_ctime = now;
+ if (f_size > 0)
+ logp->l_size = f_size;
+ else {
+ /* make it the max log size */
+ logp->l_size = loginfo.log_access_maxlogsize;
+ }
+
+ logp->l_next = loginfo.log_access_logchain;
+ loginfo.log_access_logchain = logp;
+ }
+ loginfo.log_numof_access_logs++;
+ }
+
+ /* Check if there is a rotation overdue */
+ if (loginfo.log_access_rotationsync_enabled &&
+ loginfo.log_access_rotationunit != LOG_UNIT_HOURS &&
+ loginfo.log_access_rotationunit != LOG_UNIT_MINS &&
+ loginfo.log_access_ctime < loginfo.log_access_rotationsyncclock - loginfo.log_access_rotationtime_secs) {
+ loginfo.log_access_rotationsyncclock -= loginfo.log_access_rotationtime_secs;
+ }
+ fclose (fp);
+ return LOGFILE_REOPENED;
+}
+
+/******************************************************************************
+* log__extract_logheader
+*
+* Extract each LOGINFO heder line. From there extract the time and
+* size info of all the old log files.
+******************************************************************************/
+static int
+log__extract_logheader (FILE *fp, long *f_ctime, int *f_size)
+{
+
+ char buf[BUFSIZ];
+ char *p, *s, *next;
+
+ *f_ctime = 0L;
+ *f_size = 0;
+
+ if ( fp == NULL)
+ return LOG_ERROR;
+
+ if (fgets(buf, BUFSIZ, fp) == NULL) {
+ return LOG_ERROR;
+ }
+
+ if ((p=strstr(buf, "LOGINFO")) == NULL) {
+ return LOG_ERROR;
+ }
+
+ s = p;
+ if ((p = strchr(p, '(')) == NULL) {
+ return LOG_CONTINUE;
+ }
+ if ((next= strchr(p, ')')) == NULL) {
+ return LOG_CONTINUE;
+ }
+
+ p++;
+ s = next;
+ next++;
+ *s = '\0';
+
+ /* Now p must hold the ctime value */
+ *f_ctime = atoi(p);
+
+ if ((p = strchr(next, '(')) == NULL) {
+ /* that's fine -- it means we have no size info */
+ *f_size = 0;
+ return LOG_CONTINUE;
+ }
+
+ if ((next= strchr(p, ')')) == NULL) {
+ return LOG_CONTINUE;
+ }
+
+ p++;
+ *next = '\0';
+
+ /* Now p must hold the size value */
+ *f_size = atoi(p);
+
+ return LOG_CONTINUE;
+
+}
+
+/******************************************************************************
+* log__getfilesize
+* Get the file size
+*
+* Assumption: Lock has been acquired already.
+******************************************************************************/
+/* this kinda has to be diff't on each platform :( */
+/* using an int implies that all logfiles will be under 2G. this is
+ * probably a safe assumption for now.
+ */
+#ifdef XP_WIN32
+static int
+log__getfilesize(LOGFD fp)
+{
+ struct stat info;
+ int rv;
+
+ if ((rv = fstat(fileno(fp), &info)) != 0) {
+ return -1;
+ }
+ return info.st_size;
+}
+#else
+static int
+log__getfilesize(LOGFD fp)
+{
+ PRFileInfo info;
+ int rv;
+
+ if ((rv = PR_GetOpenFileInfo (fp, &info)) == PR_FAILURE) {
+ return -1;
+ }
+ return info.size;
+}
+#endif
+
+
+/******************************************************************************
+* log__enough_freespace
+*
+* Returns:
+* 1 - we have enough space
+* 0 - No the avialable space is less than recomended
+* Assumption: Lock has been acquired already.
+******************************************************************************/
+static int
+log__enough_freespace(char *path)
+{
+
+#ifdef _WIN32
+DWORD sectorsPerCluster, bytesPerSector, freeClusters, totalClusters;
+char rootpath[4];
+#else
+#ifdef LINUX
+ struct statfs buf;
+#else
+ struct statvfs buf;
+#endif /* LINUX */
+#endif
+ PRInt64 freeBytes;
+ PRInt64 tmpval;
+
+
+#ifdef _WIN32
+ strncpy(rootpath, path, 3);
+ rootpath[3] = '\0';
+ /* we should consider using GetDiskFreeSpaceEx here someday */
+ if ( !GetDiskFreeSpace(rootpath, &sectorsPerCluster, &bytesPerSector,
+ &freeClusters, &totalClusters)) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "log__enough_freespace: Unable to get the free space\n",0,0,0);
+ return 1;
+ } else {
+ LL_UI2L(freeBytes, freeClusters);
+ LL_UI2L(tmpval, sectorsPerCluster);
+ LL_MUL(freeBytes, freeBytes, tmpval);
+ LL_UI2L(tmpval, bytesPerSector);
+ LL_MUL(freeBytes, freeBytes, tmpval);
+/* freeBytes = freeClusters * sectorsPerCluster * bytesPerSector; */
+
+ }
+
+#else
+#ifdef LINUX
+ if (statfs(path, &buf) == -1)
+#else
+ if (statvfs(path, &buf) == -1)
+#endif
+ {
+ int oserr = errno;
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "log__enough_freespace: Unable to get the free space (errno:%d)\n",
+ oserr,0,0);
+ return 1;
+ } else {
+ LL_UI2L(freeBytes, buf.f_bavail);
+ LL_UI2L(tmpval, buf.f_bsize);
+ LL_MUL(freeBytes, freeBytes, tmpval);
+ /* freeBytes = buf.f_bavail * buf.f_bsize; */
+ }
+#endif
+ LL_UI2L(tmpval, loginfo.log_access_minfreespace);
+ if (LL_UCMP(freeBytes, <, tmpval)) {
+ /* if (freeBytes < loginfo.log_access_minfreespace) { */
+ return 0;
+ }
+ return 1;
+}
+/******************************************************************************
+* log__getaccesslist
+* Update the previous access files in the slapdFrontendConfig_t.
+* Returns:
+* num > 1 -- how many are there
+* 0 -- otherwise
+******************************************************************************/
+char **
+log_get_loglist(int logtype)
+{
+ char **list=NULL;
+ int num, i;
+ LogFileInfo *logp = NULL;
+ char buf[BUFSIZ];
+ char tbuf[TBUFSIZE];
+ char *file;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_LOCK_READ( );
+ num = loginfo.log_numof_access_logs;
+ logp = loginfo.log_access_logchain;
+ file = loginfo.log_access_file;
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_LOCK_READ( );
+ num = loginfo.log_numof_error_logs;
+ logp = loginfo.log_error_logchain;
+ file = loginfo.log_error_file;
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_LOCK_READ( );
+ num = loginfo.log_numof_audit_logs;
+ logp = loginfo.log_audit_logchain;
+ file = loginfo.log_audit_file;
+ break;
+ default:
+ return NULL;
+ }
+ list = (char **) slapi_ch_calloc(1, num * sizeof(char *));
+ i = 0;
+ while (logp) {
+ log_convert_time (logp->l_ctime, tbuf, 1 /*short */);
+ sprintf(buf, "%s.%s", file, tbuf);
+ list[i] = slapi_ch_strdup(buf);
+ i++;
+ logp = logp->l_next;
+ }
+ list[i] = NULL;
+
+ switch (logtype) {
+ case SLAPD_ACCESS_LOG:
+ LOG_ACCESS_UNLOCK_READ();
+ break;
+ case SLAPD_ERROR_LOG:
+ LOG_ERROR_UNLOCK_READ();
+ break;
+ case SLAPD_AUDIT_LOG:
+ LOG_AUDIT_UNLOCK_READ();
+ break;
+ }
+ return list;
+}
+
+/******************************************************************************
+* log__delete_error_logfile
+*
+* Do we need to delete a logfile. Find out if we need to delete the log
+* file based on expiration time, max diskspace, and minfreespace.
+* Delete the file if we need to.
+*
+* Assumption: A WRITE lock has been acquired for the error log.
+******************************************************************************/
+
+static int
+log__delete_error_logfile()
+{
+
+ struct logfileinfo *logp = NULL;
+ struct logfileinfo *delete_logp = NULL;
+ struct logfileinfo *p_delete_logp = NULL;
+ struct logfileinfo *prev_logp = NULL;
+ int total_size=0;
+ time_t cur_time;
+ int f_size;
+ int numoflogs=loginfo.log_numof_error_logs;
+ int rv = 0;
+ char *logstr;
+ char buffer[BUFSIZ];
+ char tbuf[TBUFSIZE];
+
+
+ /* If we have only one log, then will delete this one */
+ if (loginfo.log_error_maxnumlogs == 1) {
+ LOG_CLOSE(loginfo.log_error_fdes);
+ loginfo.log_error_fdes = NULL;
+ sprintf (buffer, "%s", loginfo.log_error_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s\n", loginfo.log_error_file,0,0);
+ }
+
+ /* Delete the rotation file also. */
+ sprintf (buffer, "%s.rotationinfo", loginfo.log_error_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_error_file,0,0);
+ }
+ return 0;
+ }
+
+ /* If we have already the maximum number of log files, we
+ ** have to delete one any how.
+ */
+ if (++numoflogs > loginfo.log_error_maxnumlogs) {
+ logstr = "Exceeded max number of logs allowed";
+ goto delete_logfile;
+ }
+
+ /* Now check based on the maxdiskspace */
+ if (loginfo.log_error_maxdiskspace > 0) {
+ logp = loginfo.log_error_logchain;
+ while (logp) {
+ total_size += logp->l_size;
+ logp = logp->l_next;
+ }
+ if ((f_size = log__getfilesize(loginfo.log_error_fdes)) == -1) {
+ /* then just assume the max size */
+ total_size += loginfo.log_error_maxlogsize;
+ } else {
+ total_size += f_size;
+ }
+
+ /* If we have exceeded the max disk space or we have less than the
+ ** minimum, then we have to delete a file.
+ */
+ if (total_size >= loginfo.log_error_maxdiskspace) {
+ logstr = "exceeded maximum log disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the free space */
+ if ( loginfo.log_error_minfreespace > 0) {
+ rv = log__enough_freespace(loginfo.log_error_file);
+ if ( rv == 0) {
+ /* Not enough free space */
+ logstr = "Not enough free disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the expiration time */
+ if ( loginfo.log_error_exptime_secs > 0 ) {
+ /* is the file old enough */
+ time (&cur_time);
+ prev_logp = logp = loginfo.log_error_logchain;
+ while (logp) {
+ if ((cur_time - logp->l_ctime) > loginfo.log_error_exptime_secs) {
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ logstr = "The file is older than the log expiration time";
+ goto delete_logfile;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ }
+
+ /* No log files to delete */
+ return 0;
+
+delete_logfile:
+ if (delete_logp == NULL) {
+ time_t oldest;
+
+ time(&oldest);
+
+ prev_logp = logp = loginfo.log_error_logchain;
+ while (logp) {
+ if (logp->l_ctime <= oldest) {
+ oldest = logp->l_ctime;
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ /* We might face this case if we have only one log file and
+ ** trying to delete it because of deletion requirement.
+ */
+ if (!delete_logp) {
+ return 0;
+ }
+ }
+
+ if (p_delete_logp == delete_logp) {
+ /* then we are deleteing the first one */
+ loginfo.log_error_logchain = delete_logp->l_next;
+ } else {
+ p_delete_logp->l_next = delete_logp->l_next;
+ }
+
+ /* Delete the error file */
+ log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
+ sprintf (buffer, "%s.%s", loginfo.log_error_file, tbuf);
+ PR_Delete(buffer);
+ slapi_ch_free((void**)&delete_logp);
+ loginfo.log_numof_error_logs--;
+
+ return 1;
+}
+
+/******************************************************************************
+* log__delete_audit_logfile
+*
+* Do we need to delete a logfile. Find out if we need to delete the log
+* file based on expiration time, max diskspace, and minfreespace.
+* Delete the file if we need to.
+*
+* Assumption: A WRITE lock has been acquired for the audit
+******************************************************************************/
+
+static int
+log__delete_audit_logfile()
+{
+ struct logfileinfo *logp = NULL;
+ struct logfileinfo *delete_logp = NULL;
+ struct logfileinfo *p_delete_logp = NULL;
+ struct logfileinfo *prev_logp = NULL;
+ int total_size=0;
+ time_t cur_time;
+ int f_size;
+ int numoflogs=loginfo.log_numof_audit_logs;
+ int rv = 0;
+ char *logstr;
+ char buffer[BUFSIZ];
+ char tbuf[TBUFSIZE];
+
+ /* If we have only one log, then will delete this one */
+ if (loginfo.log_audit_maxnumlogs == 1) {
+ LOG_CLOSE(loginfo.log_audit_fdes);
+ loginfo.log_audit_fdes = NULL;
+ sprintf (buffer, "%s", loginfo.log_audit_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s\n", loginfo.log_audit_file,0,0);
+ }
+
+ /* Delete the rotation file also. */
+ sprintf (buffer, "%s.rotationinfo", loginfo.log_audit_file);
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.rotationinfo\n", loginfo.log_audit_file,0,0);
+ }
+ return 0;
+ }
+
+ /* If we have already the maximum number of log files, we
+ ** have to delete one any how.
+ */
+ if (++numoflogs > loginfo.log_audit_maxnumlogs) {
+ logstr = "Exceeded max number of logs allowed";
+ goto delete_logfile;
+ }
+
+ /* Now check based on the maxdiskspace */
+ if (loginfo.log_audit_maxdiskspace > 0) {
+ logp = loginfo.log_audit_logchain;
+ while (logp) {
+ total_size += logp->l_size;
+ logp = logp->l_next;
+ }
+ if ((f_size = log__getfilesize(loginfo.log_audit_fdes)) == -1) {
+ /* then just assume the max size */
+ total_size += loginfo.log_audit_maxlogsize;
+ } else {
+ total_size += f_size;
+ }
+
+ /* If we have exceeded the max disk space or we have less than the
+ ** minimum, then we have to delete a file.
+ */
+ if (total_size >= loginfo.log_audit_maxdiskspace) {
+ logstr = "exceeded maximum log disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the free space */
+ if ( loginfo.log_audit_minfreespace > 0) {
+ rv = log__enough_freespace(loginfo.log_audit_file);
+ if ( rv == 0) {
+ /* Not enough free space */
+ logstr = "Not enough free disk space";
+ goto delete_logfile;
+ }
+ }
+
+ /* Now check based on the expiration time */
+ if ( loginfo.log_audit_exptime_secs > 0 ) {
+ /* is the file old enough */
+ time (&cur_time);
+ prev_logp = logp = loginfo.log_audit_logchain;
+ while (logp) {
+ if ((cur_time - logp->l_ctime) > loginfo.log_audit_exptime_secs) {
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ logstr = "The file is older than the log expiration time";
+ goto delete_logfile;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ }
+
+ /* No log files to delete */
+ return 0;
+
+delete_logfile:
+ if (delete_logp == NULL) {
+ time_t oldest;
+
+ time(&oldest);
+
+ prev_logp = logp = loginfo.log_audit_logchain;
+ while (logp) {
+ if (logp->l_ctime <= oldest) {
+ oldest = logp->l_ctime;
+ delete_logp = logp;
+ p_delete_logp = prev_logp;
+ }
+ prev_logp = logp;
+ logp = logp->l_next;
+ }
+ /* We might face this case if we have only one log file and
+ ** trying to delete it because of deletion requirement.
+ */
+ if (!delete_logp) {
+ return 0;
+ }
+ }
+
+ if (p_delete_logp == delete_logp) {
+ /* then we are deleteing the first one */
+ loginfo.log_audit_logchain = delete_logp->l_next;
+ } else {
+ p_delete_logp->l_next = delete_logp->l_next;
+ }
+
+ /* Delete the audit file */
+ log_convert_time (delete_logp->l_ctime, tbuf, 1 /*short */);
+ sprintf (buffer, "%s.%s", loginfo.log_audit_file, tbuf );
+ if (PR_Delete(buffer) != PR_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Unable to remove file:%s.%s\n",
+ loginfo.log_audit_file, tbuf,0);
+
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "LOGINFO:Removed file:%s.%s because of (%s)\n",
+ loginfo.log_audit_file, tbuf,
+ logstr);
+ }
+ slapi_ch_free((void**)&delete_logp);
+ loginfo.log_numof_audit_logs--;
+
+ return 1;
+}
+
+/******************************************************************************
+* log__error_rotationinfof
+*
+* Try to open the log file. If we have one already, then try to read the
+* header and update the information.
+*
+* Assumption: Lock has been acquired already
+******************************************************************************/
+static int
+log__error_rotationinfof( char *pathname)
+{
+ long f_ctime;
+ int f_size;
+ int main_log = 1;
+ time_t now;
+ FILE *fp;
+
+
+ /*
+ ** Okay -- I confess, we want to use NSPR calls but I want to
+ ** use fgets and not use PR_Read() and implement a complicated
+ ** parsing module. Since this will be called only during the startup
+ ** and never aftre that, we can live by it.
+ */
+
+ if ((fp = fopen (pathname, "r")) == NULL) {
+ return LOGFILE_NEW;
+ }
+
+ loginfo.log_numof_error_logs = 0;
+
+ /*
+ ** We have reopened the log error file. Now we need to read the
+ ** log file info and update the values.
+ */
+ while (log__extract_logheader(fp, &f_ctime, &f_size) == LOG_CONTINUE) {
+ /* first we would get the main log info */
+ if (f_ctime == 0 && f_size == 0)
+ continue;
+
+ time (&now);
+ if (main_log) {
+ if (f_ctime > 0L)
+ loginfo.log_error_ctime = f_ctime;
+ else {
+ loginfo.log_error_ctime = now;
+ }
+ main_log = 0;
+ } else {
+ struct logfileinfo *logp;
+
+ logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ if (f_ctime > 0L)
+ logp->l_ctime = f_ctime;
+ else
+ logp->l_ctime = now;
+ if (f_size > 0)
+ logp->l_size = f_size;
+ else {
+ /* make it the max log size */
+ logp->l_size = loginfo.log_error_maxlogsize;
+ }
+
+ logp->l_next = loginfo.log_error_logchain;
+ loginfo.log_error_logchain = logp;
+ }
+ loginfo.log_numof_error_logs++;
+ }
+
+ /* Check if there is a rotation overdue */
+ if (loginfo.log_error_rotationsync_enabled &&
+ loginfo.log_error_rotationunit != LOG_UNIT_HOURS &&
+ loginfo.log_error_rotationunit != LOG_UNIT_MINS &&
+ loginfo.log_error_ctime < loginfo.log_error_rotationsyncclock - loginfo.log_error_rotationtime_secs) {
+ loginfo.log_error_rotationsyncclock -= loginfo.log_error_rotationtime_secs;
+ }
+
+ fclose (fp);
+ return LOGFILE_REOPENED;
+}
+
+/******************************************************************************
+* log__audit_rotationinfof
+*
+* Try to open the log file. If we have one already, then try to read the
+* header and update the information.
+*
+* Assumption: Lock has been acquired already
+******************************************************************************/
+static int
+log__audit_rotationinfof( char *pathname)
+{
+ long f_ctime;
+ int f_size;
+ int main_log = 1;
+ time_t now;
+ FILE *fp;
+
+
+ /*
+ ** Okay -- I confess, we want to use NSPR calls but I want to
+ ** use fgets and not use PR_Read() and implement a complicated
+ ** parsing module. Since this will be called only during the startup
+ ** and never aftre that, we can live by it.
+ */
+
+ if ((fp = fopen (pathname, "r")) == NULL) {
+ return LOGFILE_NEW;
+ }
+
+ loginfo.log_numof_audit_logs = 0;
+
+ /*
+ ** We have reopened the log audit file. Now we need to read the
+ ** log file info and update the values.
+ */
+ while (log__extract_logheader(fp, &f_ctime, &f_size) == LOG_CONTINUE) {
+ /* first we would get the main log info */
+ if (f_ctime == 0 && f_size == 0)
+ continue;
+
+ time (&now);
+ if (main_log) {
+ if (f_ctime > 0L)
+ loginfo.log_audit_ctime = f_ctime;
+ else {
+ loginfo.log_audit_ctime = now;
+ }
+ main_log = 0;
+ } else {
+ struct logfileinfo *logp;
+
+ logp = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ if (f_ctime > 0L)
+ logp->l_ctime = f_ctime;
+ else
+ logp->l_ctime = now;
+ if (f_size > 0)
+ logp->l_size = f_size;
+ else {
+ /* make it the max log size */
+ logp->l_size = loginfo.log_audit_maxlogsize;
+ }
+
+ logp->l_next = loginfo.log_audit_logchain;
+ loginfo.log_audit_logchain = logp;
+ }
+ loginfo.log_numof_audit_logs++;
+ }
+
+ /* Check if there is a rotation overdue */
+ if (loginfo.log_audit_rotationsync_enabled &&
+ loginfo.log_audit_rotationunit != LOG_UNIT_HOURS &&
+ loginfo.log_audit_rotationunit != LOG_UNIT_MINS &&
+ loginfo.log_audit_ctime < loginfo.log_audit_rotationsyncclock - loginfo.log_audit_rotationtime_secs) {
+ loginfo.log_audit_rotationsyncclock -= loginfo.log_audit_rotationtime_secs;
+ }
+
+ fclose (fp);
+ return LOGFILE_REOPENED;
+}
+
+/******************************************************************************
+* log__open_errorlogfile
+*
+* Open a new log file. If we have run out of the max logs we can have
+* then delete the oldest file.
+******************************************************************************/
+static int
+log__open_errorlogfile(int logfile_state, int locked)
+{
+
+ time_t now;
+ LOGFD fp;
+ LOGFD fpinfo = NULL;
+ char tbuf[TBUFSIZE];
+ struct logfileinfo *logp;
+ char buffer[BUFSIZ];
+
+ if (!locked) LOG_ERROR_LOCK_WRITE( );
+
+ /*
+ ** Here we are trying to create a new log file.
+ ** If we alredy have one, then we need to rename it as
+ ** "filename.time", close it and update it's information
+ ** in the array stack.
+ */
+ if (loginfo.log_error_fdes != NULL) {
+ struct logfileinfo *log;
+ char newfile[BUFSIZ];
+ int f_size;
+
+ /* get rid of the old one */
+ if ((f_size = log__getfilesize(loginfo.log_error_fdes)) == -1) {
+ /* Then assume that we have the max size */
+ f_size = loginfo.log_error_maxlogsize;
+ }
+
+
+ /* Check if I have to delete any old file, delete it if it is required.*/
+ while (log__delete_error_logfile());
+
+ /* close the file */
+ if ( loginfo.log_error_fdes != NULL ) {
+ LOG_CLOSE(loginfo.log_error_fdes);
+ }
+ loginfo.log_error_fdes = NULL;
+
+ if ( loginfo.log_error_maxnumlogs > 1 ) {
+ log = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ log->l_ctime = loginfo.log_error_ctime;
+ log->l_size = f_size;
+
+ log_convert_time (log->l_ctime, tbuf, 1/*short */);
+ sprintf(newfile, "%s.%s", loginfo.log_error_file, tbuf);
+ if (PR_Rename (loginfo.log_error_file, newfile) != PR_SUCCESS) {
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ /* add the log to the chain */
+ log->l_next = loginfo.log_error_logchain;
+ loginfo.log_error_logchain = log;
+ loginfo.log_numof_error_logs++;
+ }
+ }
+
+
+ /* open a new log file */
+ if (! LOG_OPEN_APPEND(fp, loginfo.log_error_file, loginfo.log_error_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ loginfo.log_error_file, errno, slapd_system_strerror(errno));
+ if (!locked) LOG_ERROR_UNLOCK_WRITE();
+ /*if I have an old log file -- I should log a message
+ ** that I can't open the new file. Let the caller worry
+ ** about logging message.
+ */
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ loginfo.log_error_fdes = fp;
+ if (logfile_state == LOGFILE_REOPENED) {
+ /* we have all the information */
+ if (!locked) LOG_ERROR_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+ }
+
+ loginfo.log_error_state |= LOGGING_NEED_TITLE;
+
+ if (! LOG_OPEN_WRITE(fpinfo, loginfo.log_errorinfo_file, loginfo.log_error_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ loginfo.log_errorinfo_file, errno, slapd_system_strerror(errno));
+ if (!locked) LOG_ERROR_UNLOCK_WRITE();
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ /* write the header in the log */
+ now = current_time();
+ log_convert_time (now, tbuf, 2 /*long */);
+ sprintf (buffer,"LOGINFO:Log file created at: %s (%lu)\n", tbuf, now);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+
+ logp = loginfo.log_error_logchain;
+ while ( logp) {
+ log_convert_time (logp->l_ctime, tbuf, 1 /*short */);
+ sprintf(buffer, "LOGINFO:Previous Log File:%s.%s (%lu) (%u)\n",
+ loginfo.log_error_file, tbuf, logp->l_ctime, logp->l_size);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+ logp = logp->l_next;
+ }
+ /* Close the info file. We need only when we need to rotate to the
+ ** next log file.
+ */
+ if (fpinfo) LOG_CLOSE(fpinfo);
+
+ /* This is now the current error log */
+ loginfo.log_error_ctime = now;
+
+ if (!locked) LOG_ERROR_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+}
+
+/******************************************************************************
+* log__open_auditlogfile
+*
+* Open a new log file. If we have run out of the max logs we can have
+* then delete the oldest file.
+******************************************************************************/
+static int
+log__open_auditlogfile(int logfile_state, int locked)
+{
+
+ time_t now;
+ LOGFD fp;
+ LOGFD fpinfo = NULL;
+ char tbuf[TBUFSIZE];
+ struct logfileinfo *logp;
+ char buffer[BUFSIZ];
+
+ if (!locked) LOG_AUDIT_LOCK_WRITE( );
+
+ /*
+ ** Here we are trying to create a new log file.
+ ** If we alredy have one, then we need to rename it as
+ ** "filename.time", close it and update it's information
+ ** in the array stack.
+ */
+ if (loginfo.log_audit_fdes != NULL) {
+ struct logfileinfo *log;
+ char newfile[BUFSIZ];
+ int f_size;
+
+
+ /* get rid of the old one */
+ if ((f_size = log__getfilesize(loginfo.log_audit_fdes)) == -1) {
+ /* Then assume that we have the max size */
+ f_size = loginfo.log_audit_maxlogsize;
+ }
+
+
+ /* Check if I have to delete any old file, delete it if it is required. */
+ while (log__delete_audit_logfile());
+
+ /* close the file */
+ LOG_CLOSE(loginfo.log_audit_fdes);
+ loginfo.log_audit_fdes = NULL;
+
+ if ( loginfo.log_audit_maxnumlogs > 1 ) {
+ log = (struct logfileinfo *) slapi_ch_malloc (sizeof (struct logfileinfo));
+ log->l_ctime = loginfo.log_audit_ctime;
+ log->l_size = f_size;
+
+ log_convert_time (log->l_ctime, tbuf, 1 /*short */);
+ sprintf(newfile, "%s.%s", loginfo.log_audit_file, tbuf);
+ if (PR_Rename (loginfo.log_audit_file, newfile) != PR_SUCCESS) {
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ /* add the log to the chain */
+ log->l_next = loginfo.log_audit_logchain;
+ loginfo.log_audit_logchain = log;
+ loginfo.log_numof_audit_logs++;
+ }
+ }
+
+
+ /* open a new log file */
+ if (! LOG_OPEN_APPEND(fp, loginfo.log_audit_file, loginfo.log_audit_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ loginfo.log_audit_file, errno, slapd_system_strerror(errno));
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+ /*if I have an old log file -- I should log a message
+ ** that I can't open the new file. Let the caller worry
+ ** about logging message.
+ */
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ loginfo.log_audit_fdes = fp;
+ if (logfile_state == LOGFILE_REOPENED) {
+ /* we have all the information */
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+ return LOG_SUCCESS;
+ }
+
+ loginfo.log_audit_state |= LOGGING_NEED_TITLE;
+
+ if (! LOG_OPEN_WRITE(fpinfo, loginfo.log_auditinfo_file, loginfo.log_audit_mode)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't open file %s. "
+ "errno %d (%s)\n",
+ loginfo.log_auditinfo_file, errno, slapd_system_strerror(errno));
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE();
+ return LOG_UNABLE_TO_OPENFILE;
+ }
+
+ /* write the header in the log */
+ now = current_time();
+ log_convert_time (now, tbuf, 2 /*long */);
+ sprintf (buffer,"LOGINFO:Log file created at: %s (%lu)\n", tbuf, now);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+
+ logp = loginfo.log_audit_logchain;
+ while ( logp) {
+ log_convert_time (logp->l_ctime, tbuf, 1 /*short */);
+ sprintf(buffer, "LOGINFO:Previous Log File:%s.%s (%d) (%d)\n",
+ loginfo.log_audit_file, tbuf, (int)logp->l_ctime, logp->l_size);
+ LOG_WRITE(fpinfo, buffer, strlen(buffer), 0);
+ logp = logp->l_next;
+ }
+ /* Close the info file. We need only when we need to rotate to the
+ ** next log file.
+ */
+ if (fpinfo) LOG_CLOSE(fpinfo);
+
+ /* This is now the current audit log */
+ loginfo.log_audit_ctime = now;
+
+ if (!locked) LOG_AUDIT_UNLOCK_WRITE( );
+ return LOG_SUCCESS;
+}
+
+/*
+** Log Buffering
+** only supports access log at this time
+*/
+
+static LogBufferInfo *log_create_buffer(size_t sz)
+{
+ LogBufferInfo *lbi;
+
+ lbi = (LogBufferInfo *) slapi_ch_malloc(sizeof(LogBufferInfo));
+ lbi->top = (char *) slapi_ch_malloc(sz);
+ lbi->current = lbi->top;
+ lbi->maxsize = sz;
+ lbi->refcount = 0;
+ return lbi;
+}
+
+#if 0
+/* for some reason, we never call this. */
+static void log_destroy_buffer(LogBufferInfo *lbi)
+{
+ slapi_ch_free((void *)&(lbi->top));
+ slapi_ch_free((void *)&lbi);
+}
+#endif
+
+/*
+ Some notes about this function. It is written the
+ way it is for performance reasons.
+ Tests showed that on 4 processor systems, there is
+ significant contention for the
+ lbi->lock. This is because the lock was held for
+ the duration of the copy of the
+ log message into the buffer. Therefore the routine
+ was re-written to avoid holding
+ the lock for that time. Instead we gain the lock,
+ take a copy of the buffer pointer
+ where we need to copy our message, increase the
+ size, move the current pointer beyond
+ our portion of the buffer, then increment a reference
+ count.
+ Then we release the lock and do the actual copy
+ in to the reserved buffer area.
+ We then atomically decrement the reference count.
+ The reference count is used to ensure that when
+ the buffer is flushed to the
+ filesystem, there are no threads left copying
+ data into the buffer.
+ The wait on zero reference count is implemented
+ in the flush routine because
+ it is also called from log_access_flush().
+ Tests show this speeds up searches by 10% on 4-way systems.
+ */
+
+static void log_append_buffer2(time_t tnl, LogBufferInfo *lbi, char *msg1, size_t size1, char *msg2, size_t size2)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ size_t size = size1 + size2;
+ char* insert_point = NULL;
+
+ /* While holding the lock, we determine if there is space in the buffer for our payload,
+ and if we need to flush.
+ */
+ PR_Lock(lbi->lock);
+ if ( ((lbi->current - lbi->top) + size > lbi->maxsize) ||
+ (tnl >= loginfo.log_access_rotationsyncclock &&
+ loginfo.log_access_rotationsync_enabled) ) {
+
+ log_flush_buffer(lbi, SLAPD_ACCESS_LOG,
+ 0 /* do not sync to disk right now */ );
+
+ }
+ insert_point = lbi->current;
+ lbi->current += size;
+ /* Increment the copy refcount */
+ PR_AtomicIncrement(&(lbi->refcount));
+ PR_Unlock(lbi->lock);
+
+ /* Now we can copy without holding the lock */
+ memcpy(insert_point, msg1, size1);
+ memcpy(insert_point + size1, msg2, size2);
+
+ /* Decrement the copy refcount */
+ PR_AtomicDecrement(&(lbi->refcount));
+
+ /* If we are asked to sync to disk immediately, do so */
+ if (!slapdFrontendConfig->accesslogbuffering) {
+ PR_Lock(lbi->lock);
+ log_flush_buffer(lbi, SLAPD_ACCESS_LOG, 1 /* sync to disk now */ );
+ PR_Unlock(lbi->lock);
+ }
+
+}
+
+/* this function assumes the lock is already acquired */
+/* if sync_now is non-zero, data is flushed to physical storage */
+static void log_flush_buffer(LogBufferInfo *lbi, int type, int sync_now)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if (type == SLAPD_ACCESS_LOG) {
+
+ /* It is only safe to flush once any other threads which are copying are finished */
+ while (lbi->refcount > 0) {
+ /* It's ok to sleep for a while because we only flush every second or so */
+ DS_Sleep (PR_MillisecondsToInterval(1));
+ }
+
+ if ((lbi->current - lbi->top) == 0) return;
+
+ if (log__needrotation(loginfo.log_access_fdes,
+ SLAPD_ACCESS_LOG) == LOG_ROTATE) {
+ if (log__open_accesslogfile(LOGFILE_NEW, 1) != LOG_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "LOGINFO: Unable to open access file:%s\n",
+ loginfo.log_access_file,0,0);
+ lbi->current = lbi->top; /* reset counter to prevent overwriting rest of lbi struct */
+ return;
+ }
+ while (loginfo.log_access_rotationsyncclock <= loginfo.log_access_ctime) {
+ loginfo.log_access_rotationsyncclock += loginfo.log_access_rotationtime_secs;
+ }
+ }
+
+ if (loginfo.log_access_state & LOGGING_NEED_TITLE) {
+ log_write_title(loginfo.log_access_fdes);
+ loginfo.log_access_state &= ~LOGGING_NEED_TITLE;
+ }
+ if (!sync_now && slapdFrontendConfig->accesslogbuffering) {
+ LOG_WRITE(loginfo.log_access_fdes, lbi->top, lbi->current - lbi->top, 0);
+ } else {
+ LOG_WRITE_NOW(loginfo.log_access_fdes, lbi->top, lbi->current - lbi->top, 0);
+ }
+
+ lbi->current = lbi->top;
+ }
+}
+
+void log_access_flush()
+{
+ LOG_ACCESS_LOCK_WRITE();
+ log_flush_buffer(loginfo.log_access_buffer, SLAPD_ACCESS_LOG,
+ 1 /* sync to disk now */ );
+ LOG_ACCESS_UNLOCK_WRITE();
+}
+
+/*
+ *
+ * log_convert_time
+ * returns the time converted into the string format.
+ *
+ */
+static void
+log_convert_time (time_t ctime, char *tbuf, int type)
+{
+
+ struct tm *tmsp, tms;
+
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &ctime );
+ tmsp = &tms;
+ memcpy(&tms, pt, sizeof(struct tm) );
+ }
+#else
+ (void)localtime_r( &ctime, &tms );
+ tmsp = &tms;
+#endif
+ if (type == 1) /* get the short form */
+ (void) strftime (tbuf, (size_t) TBUFSIZE, "%Y%m%d-%H%M%S",tmsp);
+ else /* wants the long form */
+ (void) strftime (tbuf, (size_t) TBUFSIZE, "%d/%b/%Y:%H:%M:%S",tmsp);
+
+}
+
+int
+check_log_max_size( char *maxdiskspace_str,
+ char *mlogsize_str,
+ int maxdiskspace,
+ int mlogsize,
+ char * returntext,
+ int logtype)
+{
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int rc = LDAP_SUCCESS;
+ int current_mlogsize = -1;
+ int current_maxdiskspace = -1;
+
+ switch (logtype)
+ {
+ case SLAPD_ACCESS_LOG:
+ current_mlogsize = slapdFrontendConfig->accesslog_maxlogsize;
+ current_maxdiskspace = slapdFrontendConfig->accesslog_maxdiskspace;
+ break;
+ case SLAPD_ERROR_LOG:
+ current_mlogsize = slapdFrontendConfig->errorlog_maxlogsize;
+ current_maxdiskspace = slapdFrontendConfig->errorlog_maxdiskspace;
+ break;
+ case SLAPD_AUDIT_LOG:
+ current_mlogsize = slapdFrontendConfig->auditlog_maxlogsize;
+ current_maxdiskspace = slapdFrontendConfig->auditlog_maxdiskspace;
+ break;
+ default:
+ current_mlogsize = -1;
+ current_maxdiskspace = -1;
+ }
+
+ if ( maxdiskspace == -1 )
+ maxdiskspace = current_maxdiskspace;
+ if ( mlogsize == -1 )
+ mlogsize = current_mlogsize;
+
+ if ( maxdiskspace < mlogsize )
+ {
+ /* fail */
+ PR_snprintf ( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ "%s: maxdiskspace \"%d\" is less than max log size \"%d\"",
+ maxdiskspace_str, maxdiskspace*LOG_MB_IN_BYTES, mlogsize*LOG_MB_IN_BYTES );
+ rc = LDAP_OPERATIONS_ERROR;
+ }
+ switch (logtype)
+ {
+ case SLAPD_ACCESS_LOG:
+ loginfo.log_access_maxlogsize = mlogsize * LOG_MB_IN_BYTES;
+ loginfo.log_access_maxdiskspace = maxdiskspace * LOG_MB_IN_BYTES;
+ break;
+ case SLAPD_ERROR_LOG:
+ loginfo.log_error_maxlogsize = mlogsize * LOG_MB_IN_BYTES;
+ loginfo.log_error_maxdiskspace = maxdiskspace * LOG_MB_IN_BYTES;
+ break;
+ case SLAPD_AUDIT_LOG:
+ loginfo.log_audit_maxlogsize = mlogsize * LOG_MB_IN_BYTES;
+ loginfo.log_audit_maxdiskspace = maxdiskspace * LOG_MB_IN_BYTES;
+ break;
+ default:
+ break;
+ }
+
+ return rc;
+}
+
+/************************************************************************************/
+/* E N D */
+/************************************************************************************/
+
diff --git a/ldap/servers/slapd/log.h b/ldap/servers/slapd/log.h
new file mode 100644
index 00000000..b92b58f7
--- /dev/null
+++ b/ldap/servers/slapd/log.h
@@ -0,0 +1,186 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/***********************************************************************
+ * log.h
+ *
+ * structures related to logging facility.
+ *
+ *************************************************************************/
+#include <stdio.h>
+#include <time.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef _WIN32
+#include <errno.h>
+#ifdef LINUX
+#include <sys/statfs.h>
+#else
+#include <sys/statvfs.h>
+#endif
+#endif
+#include <fcntl.h>
+#include "prio.h"
+#include "prprf.h"
+#include "slap.h"
+#include "slapi-plugin.h"
+
+#define LOG_MB_IN_BYTES (1024 * 1024)
+
+#define LOG_SUCCESS 0 /* fine & dandy */
+#define LOG_CONTINUE LOG_SUCCESS
+#define LOG_ERROR 1 /* default error case */
+#define LOG_EXCEEDED 2 /*err: > max logs allowed */
+#define LOG_ROTATE 3 /*ok; go to the next log */
+#define LOG_UNABLE_TO_OPENFILE 4
+
+#define LOG_UNIT_UNKNOWN 0
+#define LOG_UNIT_MONTHS 1
+#define LOG_UNIT_WEEKS 2
+#define LOG_UNIT_DAYS 3
+#define LOG_UNIT_HOURS 4
+#define LOG_UNIT_MINS 5
+
+
+#define LOGFILE_NEW 0
+#define LOGFILE_REOPENED 1
+
+
+#define LOG_UNIT_TYPE_UNKNOWN "unknown"
+#define LOG_UNIT_TYPE_MONTHS "month"
+#define LOG_UNIT_TYPE_WEEKS "week"
+#define LOG_UNIT_TYPE_DAYS "day"
+#define LOG_UNIT_TYPE_HOURS "hour"
+#define LOG_UNIT_TYPE_MINUTES "minute"
+
+#define LOG_BUFFER_MAXSIZE 512 * 1024
+
+/* see log.c for why this is done */
+#ifdef XP_WIN32
+typedef FILE *LOGFD;
+#else
+typedef PRFileDesc *LOGFD;
+#endif
+
+
+struct logfileinfo {
+ int l_size; /* size is in KB */
+ time_t l_ctime; /* log creation time*/
+ struct logfileinfo *l_next; /* next log */
+};
+typedef struct logfileinfo LogFileInfo;
+
+struct logbufinfo {
+ char *top; /* beginning of the buffer */
+ char *current; /* current pointer into buffer */
+ size_t maxsize; /* size of buffer */
+ PRLock *lock; /* lock for access logging */
+ PRInt32 refcount; /* Reference count for buffer copies */
+};
+typedef struct logbufinfo LogBufferInfo;
+
+struct logging_opts {
+ /* These are access log specific */
+ int log_access_state;
+ int log_access_mode; /* access mode */
+ int log_access_maxnumlogs; /* Number of logs */
+ int log_access_maxlogsize; /* max log size in bytes*/
+ int log_access_rotationtime; /* time in units. */
+ int log_access_rotationunit; /* time in units. */
+ int log_access_rotationtime_secs; /* time in seconds */
+ int log_access_rotationsync_enabled;/* 0 or 1*/
+ int log_access_rotationsynchour; /* 0-23 */
+ int log_access_rotationsyncmin; /* 0-59 */
+ time_t log_access_rotationsyncclock; /* clock in seconds */
+ int log_access_maxdiskspace; /* space in bytes */
+ int log_access_minfreespace; /* free space in bytes */
+ int log_access_exptime; /* time */
+ int log_access_exptimeunit; /* unit time */
+ int log_access_exptime_secs; /* time in secs */
+
+ int log_access_level; /* access log level */
+ char *log_access_file; /* access log file path */
+ LOGFD log_access_fdes; /* fp for the cur access log */
+ unsigned int log_numof_access_logs; /* number of logs */
+ time_t log_access_ctime; /* log creation time */
+ LogFileInfo *log_access_logchain; /* all the logs info */
+ char *log_accessinfo_file; /* access log rotation info file */
+ LogBufferInfo *log_access_buffer; /* buffer for access log */
+
+ /* These are error log specific */
+ int log_error_state;
+ int log_error_mode; /* access mode */
+ int log_error_maxnumlogs; /* Number of logs */
+ int log_error_maxlogsize; /* max log size in bytes*/
+ int log_error_rotationtime; /* time in units. */
+ int log_error_rotationunit; /* time in units. */
+ int log_error_rotationtime_secs; /* time in seconds */
+ int log_error_rotationsync_enabled;/* 0 or 1*/
+ int log_error_rotationsynchour; /* 0-23 */
+ int log_error_rotationsyncmin; /* 0-59 */
+ time_t log_error_rotationsyncclock; /* clock in seconds */
+ int log_error_maxdiskspace; /* space in bytes */
+ int log_error_minfreespace; /* free space in bytes */
+ int log_error_exptime; /* time */
+ int log_error_exptimeunit; /* unit time */
+ int log_error_exptime_secs; /* time in secs */
+
+ char *log_error_file; /* error log file path */
+ LOGFD log_error_fdes; /* fp for the cur error log */
+ unsigned int log_numof_error_logs; /* number of logs */
+ time_t log_error_ctime; /* log creation time */
+ LogFileInfo *log_error_logchain; /* all the logs info */
+ char *log_errorinfo_file; /* error log rotation info file */
+ rwl *log_error_rwlock; /* lock on error*/
+
+ /* These are audit log specific */
+ int log_audit_state;
+ int log_audit_mode; /* access mode */
+ int log_audit_maxnumlogs; /* Number of logs */
+ int log_audit_maxlogsize; /* max log size in bytes*/
+ int log_audit_rotationtime; /* time in units. */
+ int log_audit_rotationunit; /* time in units. */
+ int log_audit_rotationtime_secs; /* time in seconds */
+ int log_audit_rotationsync_enabled;/* 0 or 1*/
+ int log_audit_rotationsynchour; /* 0-23 */
+ int log_audit_rotationsyncmin; /* 0-59 */
+ time_t log_audit_rotationsyncclock; /* clock in seconds */
+ int log_audit_maxdiskspace; /* space in bytes */
+ int log_audit_minfreespace; /* free space in bytes */
+ int log_audit_exptime; /* time */
+ int log_audit_exptimeunit; /* unit time */
+ int log_audit_exptime_secs; /* time in secs */
+
+ char *log_audit_file; /* aufit log name */
+ LOGFD log_audit_fdes; /* audit log fdes */
+ unsigned int log_numof_audit_logs; /* number of logs */
+ time_t log_audit_ctime; /* log creation time */
+ LogFileInfo *log_audit_logchain; /* all the logs info */
+ char *log_auditinfo_file; /* audit log rotation info file */
+ rwl *log_audit_rwlock; /* lock on audit*/
+
+};
+
+/* For log_state */
+#define LOGGING_ENABLED (int) 0x1 /* logging is enabled */
+#define LOGGING_NEED_TITLE 0x2 /* need to write title */
+
+#define LOG_ACCESS_LOCK_READ() PR_Lock(loginfo.log_access_buffer->lock)
+#define LOG_ACCESS_UNLOCK_READ() PR_Unlock(loginfo.log_access_buffer->lock)
+#define LOG_ACCESS_LOCK_WRITE() PR_Lock(loginfo.log_access_buffer->lock)
+#define LOG_ACCESS_UNLOCK_WRITE() PR_Unlock(loginfo.log_access_buffer->lock)
+
+#define LOG_ERROR_LOCK_READ() loginfo.log_error_rwlock->rwl_acquire_read_lock(loginfo.log_error_rwlock)
+#define LOG_ERROR_UNLOCK_READ() loginfo.log_error_rwlock->rwl_relinquish_read_lock(loginfo.log_error_rwlock)
+#define LOG_ERROR_LOCK_WRITE() loginfo.log_error_rwlock->rwl_acquire_write_lock(loginfo.log_error_rwlock)
+#define LOG_ERROR_UNLOCK_WRITE() loginfo.log_error_rwlock->rwl_relinquish_write_lock(loginfo.log_error_rwlock)
+
+#define LOG_AUDIT_LOCK_READ() loginfo.log_audit_rwlock->rwl_acquire_read_lock(loginfo.log_audit_rwlock)
+#define LOG_AUDIT_UNLOCK_READ() loginfo.log_audit_rwlock->rwl_relinquish_read_lock(loginfo.log_audit_rwlock)
+#define LOG_AUDIT_LOCK_WRITE() loginfo.log_audit_rwlock->rwl_acquire_write_lock(loginfo.log_audit_rwlock)
+#define LOG_AUDIT_UNLOCK_WRITE() loginfo.log_audit_rwlock->rwl_relinquish_write_lock(loginfo.log_audit_rwlock)
+
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
new file mode 100644
index 00000000..b52df26d
--- /dev/null
+++ b/ldap/servers/slapd/main.c
@@ -0,0 +1,2753 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#if defined(NET_SSL)
+#include <ldap.h>
+#undef OFF
+#undef LITTLE_ENDIAN
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#if !defined(_WIN32) && !defined(aix)
+#include <sys/fcntl.h>
+#else
+#include <fcntl.h>
+#endif
+#include <time.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <stdlib.h>
+#if defined( _WIN32 )
+#include "ntslapdmessages.h"
+#include "proto-ntutil.h"
+#else
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <pwd.h> /* getpwnam */
+#if !defined(IRIX) && !defined(LINUX)
+union semun {
+ int val;
+ struct semid_ds *buf;
+ ushort *array;
+};
+#endif
+#endif
+#if !defined(_WIN32)
+#include <unistd.h> /* dup2 */
+#include <sys/ipc.h>
+#include <sys/sem.h>
+#include <sys/param.h> /* MAXPATHLEN */
+#endif
+#if defined(__sun)
+#include <sys/utsname.h>
+#include <sys/systeminfo.h>
+#endif
+#include "slap.h"
+#include "slapi-plugin.h"
+#include "prinit.h"
+#include "snmp_collator.h"
+#include "fe.h" /* client_auth_init() */
+#include "protect_db.h"
+#include "getopt_ext.h"
+#include "fe.h"
+
+#ifndef LDAP_DONT_USE_SMARTHEAP
+#include "smrtheap.h"
+#endif
+
+#if defined( XP_WIN32 )
+void dostounixpath(char *szText);
+#endif
+
+/* Forward Declarations */
+static void register_objects();
+static void process_command_line(int argc, char **argv, char *myname, char **extraname);
+static int slapd_exemode_ldif2db();
+static int slapd_exemode_db2ldif(int argc, char **argv);
+static int slapd_exemode_db2index();
+static int slapd_exemode_archive2db();
+static int slapd_exemode_db2archive();
+#if defined(UPGRADEDB)
+static int slapd_exemode_upgradedb();
+#endif
+static int slapd_exemode_dbtest();
+static int slapd_exemode_suffix2instance();
+static int slapd_debug_level_string2level( const char *s );
+static void slapd_debug_level_log( int level );
+static void slapd_debug_level_usage( void );
+static void cmd_set_shutdown(int);
+/*
+ * global variables
+ */
+
+static int slapd_exemode = SLAPD_EXEMODE_UNKNOWN;
+
+static int init_cmd_shutdown_detect()
+{
+
+#ifndef _WIN32
+ /* First of all, we must reset the signal mask to get rid of any blockages
+ * the process may have inherited from its parent (such as the console), which
+ * might result in the process not delivering those blocked signals, and thus,
+ * misbehaving....
+ */
+ {
+ int rc;
+ sigset_t proc_mask;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "Reseting signal mask....\n", 0, 0, 0);
+ (void)sigemptyset( &proc_mask );
+ rc = pthread_sigmask( SIG_SETMASK, &proc_mask, NULL );
+ LDAPDebug( LDAP_DEBUG_TRACE, " %s \n",
+ rc ? "Failed to reset signal mask":"....Done (signal mask reset)!!", 0, 0 );
+ }
+#endif
+
+#if defined ( HPUX10 )
+ PR_CreateThread ( PR_USER_THREAD,
+ catch_signals,
+ NULL,
+ PR_PRIORITY_NORMAL,
+ PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD,
+ SLAPD_DEFAULT_THREAD_STACKSIZE);
+#elif defined ( HPUX11 )
+ /* In the optimized builds for HPUX, the signal handler doesn't seem
+ * to get set correctly unless the primordial thread gets a chance
+ * to run before we make the call to SIGNAL. (At this point the
+ * the primordial thread has spawned the daemon thread which called
+ * this function.) The call to DS_Sleep will give the primordial
+ * thread a chance to run. */
+ DS_Sleep(0);
+#endif
+#ifndef _WIN32
+ (void) SIGNAL( SIGPIPE, SIG_IGN );
+ (void) SIGNAL( SIGCHLD, slapd_wait4child );
+#ifndef LINUX
+ /* linux uses USR1/USR2 for thread synchronization, so we aren't
+ * allowed to mess with those.
+ */
+ (void) SIGNAL( SIGUSR1, slapd_do_nothing );
+ (void) SIGNAL( SIGUSR2, cmd_set_shutdown );
+#endif
+ (void) SIGNAL( SIGTERM, cmd_set_shutdown );
+ (void) SIGNAL( SIGHUP, cmd_set_shutdown );
+ (void) SIGNAL( SIGINT, cmd_set_shutdown );
+#endif /* _WIN32 */
+ return 0;
+}
+
+static void
+cmd_set_shutdown (int sig)
+{
+ /* don't log anything from a signal handler:
+ * you could be holding a lock when the signal was trapped. more
+ * specifically, you could be holding the logfile lock (and deadlock
+ * yourself).
+ */
+
+#if 0
+ LDAPDebug( LDAP_DEBUG_ANY, "slapd got shutdown signal\n", 0, 0, 0 );
+#endif
+ c_set_shutdown();
+#ifndef _WIN32
+#ifndef LINUX
+ /* don't mess with USR1/USR2 on linux, used by libpthread */
+ (void) SIGNAL( SIGUSR2, cmd_set_shutdown );
+#endif
+ (void) SIGNAL( SIGTERM, cmd_set_shutdown );
+ (void) SIGNAL( SIGHUP, cmd_set_shutdown );
+#endif
+}
+
+#ifdef HPUX10
+extern void collation_init();
+#endif
+
+#ifndef WIN32
+
+/* Changes the ownership of the given file/directory iff not
+ already the owner
+ Returns 0 upon success or non-zero otherwise, usually -1 if
+ some system error occurred
+*/
+static int
+chown_if_not_owner(const char *filename, uid_t uid, gid_t gid)
+{
+ struct stat statbuf;
+ int result = 1;
+ if (!filename)
+ return result;
+
+ memset(&statbuf, '\0', sizeof(statbuf));
+ if (!(result = stat(filename, &statbuf)))
+ {
+ if (((uid != -1) && (uid != statbuf.st_uid)) ||
+ ((gid != -1) && (gid != statbuf.st_gid)))
+ {
+ result = chown(filename, uid, gid);
+ }
+ }
+
+ return result;
+}
+
+/*
+ Four cases:
+ - change ownership of all files in directory (strip_fn=PR_FALSE)
+ - change ownership of all files in directory; but trailing fn needs to be stripped (strip_fn=PR_TRUE)
+ - fn is relative to root directory (/access); we print error message and let user shoot his foot
+ - fn is relative to current directory (access); we print error message and let user shoot his other foot
+
+ The docs say any valid filename.
+*/
+
+static void
+chown_dir_files(char *name, struct passwd *pw, PRBool strip_fn)
+{
+ PRDir *dir;
+ PRDirEntry *entry;
+ char dirname[MAXPATHLEN + 1], file[MAXPATHLEN + 1];
+ char *log=NULL, *ptr=NULL;
+ int rc=0;
+
+ log=strdup(name);
+ if(strip_fn)
+ {
+ if((ptr=strrchr(log,'/'))==NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Caution changing ownership of ./%s \n",name,0,0);
+ chown_if_not_owner(log, pw->pw_uid, -1 );
+ rc=1;
+ } else if(log==ptr) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Caution changing ownership of / directory and its contents to %s\n",pw->pw_name,0,0);
+ *(++ptr)='\0';
+ } else {
+ *ptr='\0';
+ }
+ }
+ if ((!rc) && ((dir = PR_OpenDir(log)) != NULL ))
+ {
+ /* change the owner for each of the files in the dir */
+ while( (entry = PR_ReadDir(dir , PR_SKIP_BOTH )) !=NULL )
+ {
+ sprintf(file,"%s/%s",log,entry->name);
+ chown_if_not_owner( file, pw->pw_uid, -1 );
+ }
+ PR_CloseDir( dir );
+ }
+ free(log);
+}
+
+/* Changes the owner of the files in the logs and
+ * config directorys to the user that the server runs as.
+*/
+
+static void
+fix_ownership()
+{
+ int len, n;
+ struct passwd* pw=NULL;
+ char dirname[MAXPATHLEN + 1];
+
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+
+ if ( slapdFrontendConfig->localuser != NULL ) {
+ if ( (pw = getpwnam( slapdFrontendConfig->localuser )) == NULL )
+ return;
+ }
+ else {
+ return;
+ }
+
+ /* The instance directory needs to be owned by the local user */
+ chown_if_not_owner( slapdFrontendConfig->instancedir, pw->pw_uid, -1 );
+ sprintf(dirname,"%s/config",slapdFrontendConfig->instancedir);
+ chown_dir_files(dirname, pw, PR_FALSE); /* config directory */
+ chown_dir_files(slapdFrontendConfig->accesslog, pw, PR_TRUE); /* do access log directory */
+ chown_dir_files(slapdFrontendConfig->auditlog, pw, PR_TRUE); /* do audit log directory */
+ chown_dir_files(slapdFrontendConfig->errorlog, pw, PR_TRUE); /* do error log directory */
+
+}
+#endif
+
+/* Changes identity to the named user
+ * If username == NULL, does nothing.
+ * Does nothing on NT regardless.
+ */
+static int main_setuid(char *username)
+{
+#ifndef _WIN32
+ if (username != NULL) {
+ struct passwd *pw;
+ /* Make sure everything in the log and config directory
+ * is owned by the correct user */
+ fix_ownership();
+ pw = getpwnam (username);
+ if (pw == NULL) {
+ int oserr = errno;
+
+ LDAPDebug (LDAP_DEBUG_ANY, "getpwnam(%s) == NULL, error %d (%s)\n",
+ username, oserr, slapd_system_strerror(oserr));
+ } else {
+ if (setgid (pw->pw_gid) != 0) {
+ int oserr = errno;
+
+ LDAPDebug (LDAP_DEBUG_ANY, "setgid(%li) != 0, error %d (%s)\n",
+ (long)pw->pw_gid, oserr, slapd_system_strerror(oserr));
+ return -1;
+ }
+ if (setuid (pw->pw_uid) != 0) {
+ int oserr = errno;
+
+ LDAPDebug (LDAP_DEBUG_ANY, "setuid(%li) != 0, error %d (%s)\n",
+ (long)pw->pw_uid, oserr, slapd_system_strerror(oserr));
+ return -1;
+ }
+ }
+ }
+#endif
+ return 0;
+}
+
+/* set good defaults for front-end config in referral mode */
+static void referral_set_defaults(void)
+{
+#if !defined(_WIN32) && !defined(AIX)
+ char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
+ config_set_maxdescriptors( CONFIG_MAXDESCRIPTORS_ATTRIBUTE, "1024", errorbuf, 1);
+#endif
+}
+
+static int
+name2exemode( char *progname, char *s, int exit_if_unknown )
+{
+ int exemode;
+
+ if ( strcmp( s, "db2ldif" ) == 0 ) {
+ exemode = SLAPD_EXEMODE_DB2LDIF;
+ } else if ( strcmp( s, "ldif2db" ) == 0 ) {
+ exemode = SLAPD_EXEMODE_LDIF2DB;
+ } else if ( strcmp( s, "archive2db" ) == 0 ) {
+ exemode = SLAPD_EXEMODE_ARCHIVE2DB;
+ } else if ( strcmp( s, "db2archive" ) == 0 ) {
+ exemode = SLAPD_EXEMODE_DB2ARCHIVE;
+ } else if ( strcmp( s, "server" ) == 0 ) {
+ exemode = SLAPD_EXEMODE_SLAPD;
+ } else if ( strcmp( s, "dbtest" ) == 0 ) {
+ exemode = SLAPD_EXEMODE_DBTEST;
+ } else if ( strcmp( s, "db2index" ) == 0 ) {
+ exemode = SLAPD_EXEMODE_DB2INDEX;
+ } else if ( strcmp( s, "refer" ) == 0 ) {
+ exemode = SLAPD_EXEMODE_REFERRAL;
+ } else if ( strcmp( s, "suffix2instance" ) == 0 ) {
+ exemode = SLAPD_EXEMODE_SUFFIX2INSTANCE;
+ }
+#if defined(UPGRADEDB)
+ else if ( strcmp( s, "upgradedb" ) == 0 )
+ {
+ exemode = SLAPD_EXEMODE_UPGRADEDB;
+ }
+#endif
+ else if ( exit_if_unknown ) {
+ fprintf( stderr, "usage: %s -D instancedir "
+ "[ldif2db | db2ldif | archive2db "
+ "| db2archive | db2index | refer | suffix2instance"
+#if defined(UPGRADEDB)
+ " | upgradedb] "
+#else
+ "] "
+#endif
+ "[options]\n", progname );
+ exit( 1 );
+ } else {
+ exemode = SLAPD_EXEMODE_UNKNOWN;
+ }
+
+ return( exemode );
+}
+
+
+static void
+usage( char *name, char *extraname )
+{
+ char *usagestr = NULL;
+ char *extraspace;
+
+ if ( extraname == NULL ) {
+ extraspace = extraname = "";
+ } else {
+ extraspace = " ";
+ }
+
+ switch( slapd_exemode ) {
+ case SLAPD_EXEMODE_DB2LDIF:
+ usagestr = "usage: %s %s%s-D instancedir [-n backend-instance-name] [-d debuglevel] "
+ "[-N] [-a outputfile] [-r] [-C] [{-s includesuffix}*] "
+ "[{-x excludesuffix}*] [-u] [-U] [-m] [-M] [-E]\n"
+ "Note: either \"-n backend_instance_name\" or \"-s includesuffix\" is required.\n";
+ break;
+ case SLAPD_EXEMODE_LDIF2DB:
+ usagestr = "usage: %s %s%s-D instancedir [-d debuglevel] "
+ "[-n backend_instance_name] [-O] [-g uniqueid_type] [--namespaceid uniqueID]"
+ "[{-s includesuffix}*] [{-x excludesuffix}*] [-E] {-i ldif-file}*\n"
+ "Note: either \"-n backend_instance_name\" or \"-s includesuffix\" is required.\n";
+ break;
+ case SLAPD_EXEMODE_DB2ARCHIVE:
+ usagestr = "usage: %s %s%s-D instancedir [-d debuglevel] -a archivedir\n";
+ break;
+ case SLAPD_EXEMODE_ARCHIVE2DB:
+ usagestr = "usage: %s %s%s-D instancedir [-d debuglevel] -a archivedir\n";
+ break;
+ case SLAPD_EXEMODE_DB2INDEX:
+ usagestr = "usage: %s %s%s-D instancedir -n backend-instance-name "
+ "[-d debuglevel] {-t attributetype}* {-T VLV Search Name}*\n";
+ /* JCM should say 'Address Book' or something instead of VLV */
+ break;
+ case SLAPD_EXEMODE_REFERRAL:
+ usagestr = "usage: %s %s%s-D instancedir -r referral-url [-p port]\n";
+ break;
+ case SLAPD_EXEMODE_DBTEST:
+ usagestr = "usage: %s %s%s-D instancedir -n backend-instance-name "
+ "[-d debuglevel] [-S] [-v]\n";
+ break;
+ case SLAPD_EXEMODE_SUFFIX2INSTANCE:
+ usagestr = "usage: %s %s%s -D instancedir {-s suffix}*\n";
+ break;
+#if defined(UPGRADEDB)
+ case SLAPD_EXEMODE_UPGRADEDB:
+ usagestr = "usage: %s %s%s-D instancedir [-d debuglevel] [-f] -a archivedir\n";
+ break;
+#endif
+
+ default: /* SLAPD_EXEMODE_SLAPD */
+ usagestr = "usage: %s %s%s-D instancedir [-d debuglevel] "
+ "[-i pidlogfile] [-v] [-V]\n";
+ }
+
+ fprintf( stderr, usagestr, name, extraname, extraspace );
+}
+
+
+/*
+ * These nasty globals are the settings collected from the
+ * command line by the process_command_line function. The
+ * various slapd_exemode functions read these to drive their
+ * execution.
+ */
+static char *extraname;
+static char *myname;
+static int n_port = 0;
+static int s_port = 0;
+static char **ldif_file = NULL;
+static int ldif_files = 0;
+static int ldif_backend = 0;
+static char *cmd_line_instance_name = NULL;
+static char **cmd_line_instance_names = NULL;
+static int skip_db_protect_check = 0;
+static char **db2ldif_include = NULL;
+static char **db2ldif_exclude = NULL;
+static int ldif2db_removedupvals = 1;
+static int ldif2db_noattrindexes = 0;
+static char **db2index_attrs = NULL;
+static int ldif_printkey = EXPORT_PRINTKEY|EXPORT_APPENDMODE;
+static char *archive_name = NULL;
+static int db2ldif_dump_replica = 0;
+static int db2ldif_dump_uniqueid = 1;
+static int ldif2db_generate_uniqueid = SLAPI_UNIQUEID_GENERATE_TIME_BASED;
+static int ldif2db_load_state= 1;
+static char *ldif2db_namespaceid = NULL;
+int importexport_encrypt = 0;
+#if defined(UPGRADEDB)
+static int upgradedb_force = 0;
+#endif
+
+/* taken from idsktune */
+#if defined(__sun)
+static void ids_get_platform_solaris(char *buf)
+{
+ struct utsname u;
+ char sbuf[128];
+ FILE *fp;
+
+#if defined(sparc) || defined(__sparc)
+ int is_u = 0;
+
+ sbuf[0] = '\0';
+ sysinfo(SI_MACHINE,sbuf,128);
+
+ if (strcmp(sbuf,"sun4u") == 0) {
+ is_u = 1;
+ }
+
+ sbuf[0] = '\0';
+ sysinfo(SI_PLATFORM,sbuf,128);
+
+ sprintf(buf,"%ssparc%s-%s-solaris",
+ is_u ? "u" : "",
+ sizeof(long) == 4 ? "" : "v9",
+ sbuf);
+#else
+#if defined(i386) || defined(__i386)
+ sprintf(buf,"i386-unknown-solaris");
+#else
+ sprintf(buf,"unknown-unknown-solaris");
+#endif /* not i386 */
+#endif /* not sparc */
+
+ uname(&u);
+ if (isascii(u.release[0]) && isdigit(u.release[0])) strcat(buf,u.release);
+
+ fp = fopen("/etc/release","r");
+
+ if (fp != NULL) {
+ char *rp;
+
+ sbuf[0] = '\0';
+ fgets(sbuf,128,fp);
+ fclose(fp);
+ rp = strstr(sbuf,"Solaris");
+ if (rp) {
+ rp += 8;
+ while(*rp != 's' && *rp != '\0') rp++;
+ if (*rp == 's') {
+ char *rp2;
+ rp2 = strchr(rp,' ');
+ if (rp2) *rp2 = '\0';
+ strcat(buf,"_");
+ strcat(buf,rp);
+ }
+ }
+ }
+}
+#endif
+
+static void slapd_print_version(int verbose)
+{
+#if defined(__sun)
+ char buf[8192];
+#endif
+ char *versionstring = config_get_versionstring();
+ char *buildnum = config_get_buildnum();
+
+ printf( SLAPD_VENDOR_NAME "\n%s B%s\n", versionstring, buildnum);
+
+ /* not here in Win32 */
+#if !defined(_WIN32)
+ if (strcmp(buildnum,BUILD_NUM) != 0) {
+ printf( "ns-slapd: B%s\n", BUILD_NUM);
+ }
+#endif
+
+ slapi_ch_free( (void **)&versionstring);
+ slapi_ch_free( (void **)&buildnum);
+
+ if (verbose == 0) return;
+
+#if defined(__sun)
+ ids_get_platform_solaris(buf);
+ printf("System: %s\n",buf);
+#endif
+
+ /* this won't print much with the -v flag as the dse.ldif file
+ * hasn't be read yet.
+ */
+ plugin_print_versions();
+}
+
+#if defined( _WIN32 )
+/* On Windows, we signal the SCM when we're still starting up */
+static int
+write_start_pid_file()
+{
+ if( SlapdIsAService() )
+ {
+ /* Initialization complete and successful. Set service to running */
+ LDAPServerStatus.dwCurrentState = SERVICE_START_PENDING;
+ LDAPServerStatus.dwCheckPoint = 1;
+ LDAPServerStatus.dwWaitHint = 1000;
+
+ if (!SetServiceStatus(hLDAPServerServiceStatus, &LDAPServerStatus)) {
+ ReportSlapdEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVER_START_FAILED, 1,
+ "Could not set Service status.");
+ exit(1);
+ }
+ }
+
+ ReportSlapdEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVER_STARTED, 0, NULL );
+ return 0;
+}
+#else /* WIN32 */
+/* On UNIX, we create a file with our PID in it */
+static int
+write_start_pid_file()
+{
+ FILE *fp = NULL;
+ /*
+ * The following section of code is closely coupled with the
+ * admin programs. Please do not make changes here without
+ * consulting the start/stop code for the admin code.
+ */
+ if ( (fp = fopen( start_pid_file, "w" )) != NULL ) {
+ fprintf( fp, "%d\n", getpid() );
+ fclose( fp );
+ return 0;
+ } else
+ {
+ return -1;
+ }
+}
+#endif /* WIN32 */
+
+int
+main( int argc, char **argv)
+{
+ int return_value = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ daemon_ports_t arg = {0};
+ Slapi_Backend *be = NULL;
+ int init_ssl;
+#ifndef __LP64__
+#if defined(__hpux)
+ /* for static constructors */
+ _main();
+#endif
+#endif
+ /*
+ * Initialize NSPR very early. NSPR supports implicit initialization,
+ * but it is not bulletproof -- so it is better to be explicit.
+ */
+ PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 0 );
+ FrontendConfig_init();
+
+#ifdef _WIN32
+ /* Break into the debugger if DEBUG_BREAK is set in the environment
+ to "slapd" */
+ {
+ char *s = getenv( "DEBUG_BREAK" );
+ if ( (s != NULL) && !stricmp(s, "slapd") )
+ DebugBreak();
+ }
+
+ /* do module debug level init for slapd, and libslapd */
+ module_ldap_debug = &slapd_ldap_debug;
+ libldap_init_debug_level(&slapd_ldap_debug);
+
+ dostounixpath( argv[0] );
+ _strlwr( argv[0] );
+
+#else /* _WIN32 */
+ /* Pause for the debugger if DEBUG_SLEEP is set in the environment */
+ {
+ char *s = getenv( "DEBUG_SLEEP" );
+ if ( (s != NULL) && isdigit(*s) ) {
+ int secs = atoi(s);
+ printf("slapd pid is %d\n", getpid());
+ sleep(secs);
+ }
+ }
+
+
+/* used to set configfile to the default config file name here */
+
+#endif /* _WIN32 */
+
+ if ( (myname = strrchr( argv[0], '/' )) == NULL ) {
+ myname = slapi_ch_strdup( argv[0] );
+ } else {
+ myname = slapi_ch_strdup( myname + 1 );
+ }
+
+#if defined( XP_WIN32 )
+ /* Strip ".exe" if it's there */
+ {
+ char *pdot;
+ if ( (pdot = strrchr( myname, '.' )) != NULL ) {
+ *pdot = '\0';
+ }
+ }
+#endif
+
+ process_command_line(argc,argv,myname,&extraname);
+
+ if (!slapdFrontendConfig->instancedir ||
+ !slapdFrontendConfig->configdir) {
+ usage( myname, extraname );
+ exit( 1 );
+ }
+
+
+ /* display debugging level if it is anything other than the default */
+ if ( 0 != ( slapd_ldap_debug & ~LDAP_DEBUG_ANY )) {
+ slapd_debug_level_log( slapd_ldap_debug );
+ }
+
+#ifndef LDAP_DONT_USE_SMARTHEAP
+ MemRegisterTask();
+#endif
+
+ slapd_init();
+ g_log_init(1);
+ vattr_init();
+
+ if (slapd_exemode == SLAPD_EXEMODE_REFERRAL) {
+ /* make up the config stuff */
+ referral_set_defaults();
+ n_port = config_get_port();
+ s_port = config_get_secureport();
+ register_objects();
+
+ } else {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ /* The 2 calls below have been moved to this place to make sure that they
+ * are called before setup_internal_backends to avoid bug 524439 */
+ /*
+ * The 2 calls below where being sometimes called AFTER ldapi_register_extended_op
+ * (such fact was being stated and reproducible for some optimized installations
+ * at startup (bug 524439)... Such bad call was happening in the context of
+ * setup_internal_backends -> dse_read_file -> load_plugin_entry ->
+ * plugin_setup -> replication_multimaster_plugin_init ->
+ * slapi_register_plugin -> plugin_setup -> multimaster_start_extop_init ->
+ * slapi_pblock_set -> ldapi_register_extended_op... Unfortunately, the server
+ * design is such that it is assumed that ldapi_init_extended_ops is always
+ * called first.
+ * THE FIX: Move the two calls below before a call to setup_internal_backends
+ * (down in this same function)
+ */
+ init_saslmechanisms();
+ ldapi_init_extended_ops();
+
+
+ /*
+ * Initialize the default backend. This should be done before we
+ * process the config. files
+ */
+ defbackend_init();
+
+ /*
+ * Register the extensible objects with the factory.
+ */
+ register_objects();
+ /*
+ * Register the controls that we support.
+ */
+ init_controls();
+
+ /*
+ * Process the config files.
+ */
+ if (0 == slapd_bootstrap_config(slapdFrontendConfig->configdir)) {
+ slapi_log_error(SLAPI_LOG_FATAL, "startup",
+ "The configuration files in directory %s could not be read or were not found. Please refer to the error log or output for more information.\n",
+ slapdFrontendConfig->configdir);
+ exit(1);
+ }
+
+ /* -sduloutre: must be done before any internal search */
+ /* do it before splitting off to other modes too -robey */
+ /* -richm: must be done before reading config files */
+ if (0 != (return_value = compute_init())) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Initialization Failed 0 %d\n",return_value,0,0);
+ exit (1);
+ }
+ entry_computed_attr_init();
+
+ if (0 == setup_internal_backends(slapdFrontendConfig->configdir)) {
+ slapi_log_error(SLAPI_LOG_FATAL, "startup",
+ "The configuration files in directory %s could not be read or were not found. Please refer to the error log or output for more information.\n",
+ slapdFrontendConfig->configdir);
+ exit(1);
+ }
+
+ n_port = config_get_port();
+ s_port = config_get_secureport();
+ }
+
+ raise_process_limits(); /* should be done ASAP once config file read */
+
+#ifdef PUMPKIN_HOUR
+ if ( time( NULL ) > (PUMPKIN_HOUR - 10) ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: ** This beta software has expired **\n", 0, 0, 0 );
+ exit( 1 );
+ }
+#endif
+
+ /* Set entry points in libslapd */
+ set_entry_points();
+
+ /*
+ * Initialise NSS once for the whole slapd process, whether SSL
+ * is enabled or not. We use NSS for random number generation and
+ * other things even if we are not going to accept SSL connections.
+ * We also need NSS for attribute encryption/decryption on import and export.
+ */
+ init_ssl = ( (slapd_exemode == SLAPD_EXEMODE_SLAPD) || importexport_encrypt)
+ && config_get_security()
+ && (0 != s_port) && (s_port <= LDAP_PORT_MAX);
+ /* As of DS 6.1, always do a full initialization so that other
+ * modules can assume NSS is available
+ */
+ if ( slapd_nss_init((slapd_exemode == SLAPD_EXEMODE_SLAPD),
+ (slapd_exemode != SLAPD_EXEMODE_REFERRAL) /* have config? */ )) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: NSS Initialization Failed.\n", 0, 0, 0);
+ exit (1);
+ }
+
+ if (slapd_exemode == SLAPD_EXEMODE_SLAPD) {
+ client_auth_init();
+ }
+
+ if ( init_ssl && ( 0 != slapd_ssl_init())) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: SSL Initialization Failed.\n", 0, 0, 0 );
+ exit( 1 );
+ }
+
+ /*
+ * if we were called upon to do special database stuff, do it and be
+ * done.
+ */
+ switch ( slapd_exemode ) {
+ case SLAPD_EXEMODE_LDIF2DB:
+ return slapd_exemode_ldif2db();
+
+ case SLAPD_EXEMODE_DB2LDIF:
+ return slapd_exemode_db2ldif(argc,argv);
+
+ case SLAPD_EXEMODE_DB2INDEX:
+ return slapd_exemode_db2index();
+
+ case SLAPD_EXEMODE_ARCHIVE2DB:
+ return slapd_exemode_archive2db();
+
+ case SLAPD_EXEMODE_DB2ARCHIVE:
+ return slapd_exemode_db2archive();
+
+ case SLAPD_EXEMODE_DBTEST:
+ return slapd_exemode_dbtest();
+
+ case SLAPD_EXEMODE_REFERRAL:
+ /* check that all the necessary info was given, then go on */
+ if (! config_check_referral_mode()) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: No referral URL supplied\n", 0, 0, 0);
+ usage( myname, extraname );
+ exit(1);
+ }
+ break;
+
+ case SLAPD_EXEMODE_SUFFIX2INSTANCE:
+ return slapd_exemode_suffix2instance();
+
+#if defined(UPGRADEDB)
+ case SLAPD_EXEMODE_UPGRADEDB:
+ return slapd_exemode_upgradedb();
+#endif
+
+ case SLAPD_EXEMODE_PRINTVERSION:
+ slapd_print_version(1);
+ exit(1);
+ }
+
+#if defined( XP_WIN32 )
+ /* Register with the NT EventLog */
+ hSlapdEventSource = RegisterEventSource(NULL, pszServerName );
+ if( !hSlapdEventSource )
+ {
+ char szMessage[256];
+ sprintf( szMessage, "Directory Server %s is terminating. Failed "
+ "to set the EventLog source.", pszServerName);
+ MessageBox(GetDesktopWindow(), szMessage, " ",
+ MB_ICONEXCLAMATION | MB_OK);
+ exit( 1 );
+ }
+
+ /* Check to ensure there isn't a copy of this server already running. */
+ if( MultipleInstances() )
+ exit( 1 );
+#endif
+
+ /*
+ * Detach ourselves from the terminal (unless running in debug mode).
+ * We must detach before we start any threads since detach forks() on
+ * UNIX.
+ */
+ detach();
+
+ /*
+ * Now write our PID to the startup PID file.
+ * This is used by the start up script to determine our PID quickly
+ * after we fork, without needing to wait for the 'real' pid file to be
+ * written. That could take minutes. And the start script will wait
+ * that long looking for it. With this new 'early pid' file, it can avoid
+ * doing that, by detecting the pid and watching for the process exiting.
+ * This removes the blank stares all round from start-slapd when the server
+ * fails to start for some reason
+ */
+ write_start_pid_file();
+
+ /* Make sure we aren't going to run slapd in
+ * a mode that is going to conflict with other
+ * slapd processes that are currently running
+ */
+ if ((slapd_exemode != SLAPD_EXEMODE_REFERRAL) &&
+ ( add_new_slapd_process(slapd_exemode, db2ldif_dump_replica,
+ skip_db_protect_check) == -1 )) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Shutting down due to possible conflicts with other slapd processes\n",
+ 0, 0, 0 );
+ exit(1);
+ }
+
+
+ /*
+ * Now it is safe to log our first startup message. If we were to
+ * log anything earlier than now it would appear on the admin startup
+ * screen twice because before we detach everything is sent to both
+ * stderr and our error log. Yuck.
+ */
+ if (1) {
+ char *versionstring = config_get_versionstring();
+ char *buildnum = config_get_buildnum();
+ LDAPDebug( LDAP_DEBUG_ANY, "%s B%s starting up\n",
+ versionstring, buildnum, 0 );
+ slapi_ch_free((void **)&buildnum);
+ slapi_ch_free((void **)&versionstring);
+ }
+
+ /*
+ * After we read the config file we should make
+ * sure that everything we needed to read in has
+ * been read in and we'll start whatever threads,
+ * etc the backends need to start
+ */
+
+
+ /* Important: up 'till here we could be running as root (on unix).
+ * we believe that we've not created any files before here, otherwise
+ * they'd be owned by root, which is bad. We're about to change identity
+ * to some non-root user, but before we do, we call the daemon code
+ * to let it open the listen sockets. If these sockets are low-numbered,
+ * we need to be root in order to open them.
+ */
+
+ {
+ arg.n_port = (unsigned short)n_port;
+ if ( slapd_listenhost2addr( config_get_listenhost(),
+ &arg.n_listenaddr ) != 0 ) {
+ return(1);
+ }
+
+ arg.s_port = (unsigned short)s_port;
+ if ( slapd_listenhost2addr( config_get_securelistenhost(),
+ &arg.s_listenaddr ) != 0 ) {
+ return(1);
+ }
+
+ return_value = daemon_pre_setuid_init(&arg);
+ if (0 != return_value) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Failed to init daemon\n",
+ 0, 0, 0 );
+ exit(1);
+ }
+ }
+
+ /* Now, sockets are open, so we can safely change identity now */
+
+#ifndef _WIN32
+ return_value = main_setuid(slapdFrontendConfig->localuser);
+ if (0 != return_value) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Failed to change user and group identity to that of %s\n",
+ slapdFrontendConfig->localuser, 0, 0 );
+ exit(1);
+ }
+#endif
+
+
+ /* -sduloutre: compute_init() and entry_computed_attr_init() moved up */
+
+ if (slapd_exemode != SLAPD_EXEMODE_REFERRAL) {
+ int rc;
+ Slapi_DN *sdn;
+
+ fedse_create_startOK(DSE_FILENAME, DSE_STARTOKFILE,
+ slapdFrontendConfig->configdir);
+
+ eq_init(); /* must be done before plugins started */
+ snmp_collator_start();
+ ps_init_psearch_system(); /* must come before plugin_startall() */
+
+ /* Initailize the mapping tree */
+
+ if (mapping_tree_init())
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Failed to init mapping tree\n",
+ 0, 0, 0 );
+ exit(1);
+ }
+
+
+ /* initialize UniqueID generator - must be done once backends are started
+ and event queue is initialized but before plugins are started */
+ sdn = slapi_sdn_new_dn_byval ("cn=uniqueid generator,cn=config");
+ rc = uniqueIDGenInit (NULL, sdn, slapd_exemode == SLAPD_EXEMODE_SLAPD);
+ slapi_sdn_free (&sdn);
+ if (rc != UID_SUCCESS)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Fatal Error---Failed to initialize uniqueid generator; error = %d. "
+ "Exiting now.\n", rc, 0, 0 );
+ exit( 1 );
+ }
+
+ /* --ugaston: register the start-tls plugin */
+#ifndef _WIN32
+ if ( slapd_security_library_is_initialized() != 0 ) {
+ start_tls_register_plugin();
+ LDAPDebug( LDAP_DEBUG_PLUGIN,
+ "Start TLS plugin registered.\n",
+ 0, 0, 0 );
+ }
+#endif
+
+ plugin_startall(argc, argv, 1 /* Start Backends */, 1 /* Start Globals */);
+ if (housekeeping_start((time_t)0, NULL) == NULL) {
+ exit (1);
+ }
+
+ eq_start(); /* must be done after plugins started */
+
+#ifdef HPUX10
+ /* HPUX linker voodoo */
+ if (collation_init == NULL) {
+ exit (1);
+ }
+
+#endif /* HPUX */
+
+ normalize_oc();
+
+ if (n_port) {
+#if defined(NET_SSL)
+ } else if ( config_get_security()) {
+#endif
+ } else {
+#ifdef _WIN32
+ if( SlapdIsAService() )
+ {
+ LDAPServerStatus.dwCurrentState = SERVICE_STOPPED;
+ LDAPServerStatus.dwCheckPoint = 0;
+ LDAPServerStatus.dwWaitHint = 0;
+ LDAPServerStatus.dwWin32ExitCode = 1;
+ LDAPServerStatus.dwServiceSpecificExitCode = 1;
+
+ SetServiceStatus(hLDAPServerServiceStatus, &LDAPServerStatus);
+
+ /* Log this event */
+ ReportSlapdEvent(EVENTLOG_INFORMATION_TYPE, MSG_SERVER_START_FAILED, 1,
+ "Check server port specification");
+ }
+ else
+ {
+ char szMessage[256];
+ sprintf( szMessage, "The Directory Server %s is terminating due to an error. Check server port specification", pszServerName);
+ MessageBox(GetDesktopWindow(), szMessage, " ", MB_ICONEXCLAMATION | MB_OK);
+ }
+#endif
+ exit(1);
+ }
+ }
+
+ {
+ Slapi_PBlock pb;
+ memset( &pb, '\0', sizeof(pb) );
+ pb.pb_backend = be;
+ }
+
+ if (slapd_exemode != SLAPD_EXEMODE_REFERRAL) {
+ /* else do this after seteuid() */
+ lite_entries_init();
+
+ /* setup cn=tasks tree */
+ task_init();
+
+ /* pw_init() needs to be here since it uses aci function calls. */
+ pw_init();
+ /* Initialize the sasl mapping code */
+ if (sasl_map_init()) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Failed to initialize sasl mapping code\n", 0, 0, 0 );
+ }
+ }
+
+ /*
+ * search_register_reslimits() and daemon_register_reslimits() can
+ * be called any time before we start accepting client connections.
+ * We call these even when running in referral mode because they
+ * do little harm and registering at least one resource limit forces
+ * the reslimit subsystem to initialize itself... which prevents
+ * strange error messages from being logged to the error log for
+ * the first LDAP connection.
+ */
+ if ( search_register_reslimits() != SLAPI_RESLIMIT_STATUS_SUCCESS ||
+ daemon_register_reslimits() != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ exit( 1 );
+ }
+
+ {
+ time( &starttime );
+
+ slapd_daemon(&arg);
+ }
+ LDAPDebug( LDAP_DEBUG_ANY, "slapd stopped.\n", 0, 0, 0 );
+ reslimit_cleanup();
+ compute_terminate();
+ vattr_cleanup();
+ sasl_map_done();
+ PR_Cleanup();
+#ifdef _WIN32
+ /* Clean up the mutex used to interlock processes, before we exit */
+ remove_slapd_process();
+#endif
+#if ( defined( hpux ) || defined( irix ) || defined( aix ) || defined( OSF1 ))
+ exit( 0 );
+#else
+ return 0;
+#endif
+}
+
+
+#if ( defined( hpux ) || defined( irix ))
+void *
+signal2sigaction( int s, void *a )
+{
+ struct sigaction act;
+
+ memset(&act, 0, sizeof(struct sigaction));
+ act.sa_handler = (VFP)a;
+ act.sa_flags = 0;
+ (void)sigemptyset( &act.sa_mask );
+ (void)sigaddset( &act.sa_mask, s );
+ (void)sigaction( s, &act, NULL );
+}
+#endif /* hpux || irix */
+
+static void
+register_objects()
+{
+ get_operation_object_type();
+ daemon_register_connection();
+ get_entry_object_type();
+ mapping_tree_get_extension_type ();
+}
+
+static void
+process_command_line(int argc, char **argv, char *myname,
+ char **extraname)
+{
+ int i;
+ char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE];
+ char *opts;
+ static struct opt_ext *long_opts;
+ int longopt_index=0;
+
+ /*
+ * Refer to the file getopt_ext.h for an overview of how to use the
+ * long option names
+ *
+ */
+
+
+ /*
+ * when a new option letter is used, please move it from the "available"
+ * list to the "used" list.
+ *
+ */
+ /*
+ * single-letter options already in use:
+ *
+ * a C c D E d f G g i
+ * L l N m n O o P p r S s T t
+ * u v V w x Z z
+ *
+ * 1
+ *
+ */
+
+ /*
+ * single-letter options still available:
+ *
+ * A B b e F H h I J j
+ * K k M Q q R
+ * W X Y y
+ *
+ * 2 3 4 5 6 7 8 9 0
+ *
+ */
+
+ char *opts_dbtest = "vd:n:SD:";
+ struct opt_ext long_options_dbtest[] = {
+ {"version",ArgNone,'v'},
+ {"debug",ArgRequired,'d'},
+ {"backend",ArgRequired,'n'},
+ {"allowMultipleProcesses",ArgNone,'S'},
+ {"instanceDir",ArgRequired,'D'},
+ {0,0,0}};
+
+
+ char *opts_db2ldif = "vd:D:ENa:rs:x:CSut:n:UmMo1";
+ struct opt_ext long_options_db2ldif[] = {
+ {"version",ArgNone,'v'},
+ {"debug",ArgRequired,'d'},
+ {"dontPrintKey",ArgNone,'n'},
+ {"archive",ArgRequired,'a'},
+ {"replica",ArgNone,'r'},
+ {"include",ArgRequired,'s'},
+ {"exclude",ArgRequired,'x'},
+ /*{"whatshouldwecallthis",ArgNone,'C'},*/
+ {"allowMultipleProcesses",ArgNone,'S'},
+ {"noUniqueIds",ArgNone,'u'},
+ {"instanceDir",ArgRequired,'D'},
+ {"encrypt",ArgOptional,'E'},
+ {"nowrap",ArgNone,'U'},
+ {"minimalEncode",ArgNone,'m'},
+ {"oneOutputFile",ArgNone,'o'},
+ {"multipleOutputFile",ArgNone,'M'},
+ {"noVersionNum",ArgNone,'1'},
+ {0,0,0}};
+
+ char *opts_ldif2db = "vd:i:g:G:n:s:x:NOCc:St:D:E";
+ struct opt_ext long_options_ldif2db[] = {
+ {"version",ArgNone,'v'},
+ {"debug",ArgRequired,'d'},
+ {"ldiffile",ArgRequired,'i'},
+ {"generateUniqueId",ArgOptional,'g'},
+ {"backend",ArgRequired,'n'},
+ {"include",ArgRequired,'s'},
+ {"exclude",ArgRequired,'x'},
+ {"noindex",ArgNone,'O'},
+ /*{"whatshouldwecallthis",ArgNone,'C'},*/
+ /*{"whatshouldwecallthis",ArgRequired,'c'},*/
+ {"allowMultipleProcesses",ArgNone,'S'},
+ {"namespaceid", ArgRequired, 'G'},
+ {"nostate",ArgNone,'Z'},
+ {"instanceDir",ArgRequired,'D'},
+ {"encrypt",ArgOptional,'E'},
+ {0,0,0}};
+
+ char *opts_archive2db = "vd:i:a:SD:";
+ struct opt_ext long_options_archive2db[] = {
+ {"version",ArgNone,'v'},
+ {"debug",ArgRequired,'d'},
+ {"pidfile",ArgRequired,'i'},
+ {"archive",ArgRequired,'a'},
+ {"allowMultipleProcesses",ArgNone,'S'},
+ {"instanceDir",ArgRequired,'D'},
+ {0,0,0}};
+
+
+ char *opts_db2archive = "vd:i:a:SD:";
+ struct opt_ext long_options_db2archive[] = {
+ {"version",ArgNone,'v'},
+ {"debug",ArgRequired,'d'},
+ {"pidfile",ArgRequired,'i'},
+ {"archive",ArgRequired,'a'},
+ {"allowMultipleProcesses",ArgNone,'S'},
+ {"instanceDir",ArgRequired,'D'},
+ {0,0,0}};
+
+ char *opts_db2index = "vd:a:t:T:SD:n:s:x:";
+ struct opt_ext long_options_db2index[] = {
+ {"version",ArgNone,'v'},
+ {"debug",ArgRequired,'d'},
+ {"backend",ArgRequired,'n'},
+ {"archive",ArgRequired,'a'},
+ {"indexAttribute",ArgRequired,'t'},
+ {"vlvIndex",ArgRequired,'T'},
+ {"allowMultipleProcesses",ArgNone,'S'},
+ {"instanceDir",ArgRequired,'D'},
+ {"include",ArgRequired,'s'},
+ {"exclude",ArgRequired,'x'},
+ {0,0,0}};
+
+#if defined(UPGRADEDB)
+ char *opts_upgradedb = "vfd:a:D:";
+ struct opt_ext long_options_upgradedb[] = {
+ {"version",ArgNone,'v'},
+ {"debug",ArgRequired,'d'},
+ {"force",ArgNone,'f'},
+ {"archive",ArgRequired,'a'},
+ {"instanceDir",ArgRequired,'D'},
+ {0,0,0}};
+#endif
+
+ char *opts_referral = "vd:p:r:SD:";
+ struct opt_ext long_options_referral[] = {
+ {"version",ArgNone,'v'},
+ {"debug",ArgRequired,'d'},
+ {"port",ArgRequired,'p'},
+ {"referralMode",ArgRequired,'r'},
+ {"allowMultipleProcesses",ArgNone,'S'},
+ {"instanceDir",ArgRequired,'D'},
+ {0,0,0}};
+
+ char *opts_suffix2instance = "s:D:";
+ struct opt_ext long_options_suffix2instance[] = {
+ {"suffix",ArgRequired,'s'},
+ {"instanceDir",ArgRequired,'D'},
+ {0,0,0}};
+
+ char *opts_slapd = "vVd:i:SD:w:";
+ struct opt_ext long_options_slapd[] = {
+ {"version",ArgNone,'v'},
+ {"versionFull",ArgNone,'V'},
+ {"debug",ArgRequired,'d'},
+ {"pidfile",ArgRequired,'i'},
+ {"allowMultipleProcesses",ArgNone,'S'},
+ {"instanceDir",ArgRequired,'D'},
+ {"startpidfile",ArgRequired,'w'},
+ {0,0,0}};
+
+ /*
+ * determine which of serveral modes we are executing in.
+ */
+ *extraname = NULL;
+ if (( slapd_exemode = name2exemode( myname, myname, 0 ))
+ == SLAPD_EXEMODE_UNKNOWN ) {
+
+
+ if ( argv[1] != NULL && argv[1][0] != '-' ) {
+ slapd_exemode = name2exemode( myname, argv[1], 1 );
+ *extraname = argv[1];
+ optind_ext = 2; /* make getopt() skip argv[1] */
+ optind = 2;
+ }
+ }
+ if ( slapd_exemode == SLAPD_EXEMODE_UNKNOWN ) {
+ slapd_exemode = SLAPD_EXEMODE_SLAPD; /* default */
+ }
+ /*
+ * richm: If running in regular slapd server mode, allow the front
+ * end dse files (dse.ldif and ldbm.ldif) to be written in case of
+ * additions or modifications. In all other modes, these files
+ * should only be read and never written.
+ */
+
+ if (slapd_exemode == SLAPD_EXEMODE_SLAPD ||
+ slapd_exemode == SLAPD_EXEMODE_ARCHIVE2DB || /* bak2db adjusts config */
+ slapd_exemode == SLAPD_EXEMODE_UPGRADEDB) /* update idl-switch */
+ dse_unset_dont_ever_write_dse_files();
+
+ /* maintain compatibility with pre-5.x options */
+ switch( slapd_exemode ) {
+ case SLAPD_EXEMODE_DBTEST:
+ opts = opts_dbtest;
+ long_opts = long_options_dbtest;
+ break;
+ case SLAPD_EXEMODE_DB2LDIF:
+ opts = opts_db2ldif;
+ long_opts = long_options_db2ldif;
+ break;
+ case SLAPD_EXEMODE_LDIF2DB:
+ opts = opts_ldif2db;
+ long_opts = long_options_ldif2db;
+ break;
+ case SLAPD_EXEMODE_ARCHIVE2DB:
+ opts = opts_archive2db;
+ long_opts = long_options_archive2db;
+ break;
+ case SLAPD_EXEMODE_DB2ARCHIVE:
+ init_cmd_shutdown_detect();
+ opts = opts_db2archive;
+ long_opts = long_options_db2archive;
+ break;
+ case SLAPD_EXEMODE_DB2INDEX:
+ opts = opts_db2index;
+ long_opts = long_options_db2index;
+ break;
+ case SLAPD_EXEMODE_REFERRAL:
+ opts = opts_referral;
+ long_opts = long_options_referral;
+ break;
+ case SLAPD_EXEMODE_SUFFIX2INSTANCE:
+ opts = opts_suffix2instance;
+ long_opts = long_options_suffix2instance;
+ break;
+#if defined(UPGRADEDB)
+ case SLAPD_EXEMODE_UPGRADEDB:
+ opts = opts_upgradedb;
+ long_opts = long_options_upgradedb;
+ break;
+#endif
+ default: /* SLAPD_EXEMODE_SLAPD */
+ opts = opts_slapd;
+ long_opts = long_options_slapd;
+ }
+
+ while ( (i = getopt_ext( argc, argv, opts,
+ long_opts, &longopt_index)) != EOF ) {
+ char *instancedir = 0;
+ switch ( i ) {
+#ifdef LDAP_DEBUG
+ case 'd': /* turn on debugging */
+ if ( optarg_ext[0] == '?'
+ || 0 == strcasecmp( optarg_ext, "help" )) {
+ slapd_debug_level_usage();
+ exit( 1 );
+ } else {
+ should_detach = 0;
+ slapd_ldap_debug = slapd_debug_level_string2level( optarg_ext );
+ if ( slapd_ldap_debug < 0 ) {
+ slapd_debug_level_usage();
+ exit( 1 );
+ }
+ slapd_ldap_debug |= LDAP_DEBUG_ANY;
+ }
+ break;
+#else
+ case 'd': /* turn on debugging */
+ fprintf( stderr,
+ "must compile with LDAP_DEBUG for debugging\n" );
+ break;
+#endif
+
+ case 'D': /* config dir */
+ instancedir = rel2abspath( optarg_ext );
+
+#if defined( XP_WIN32 )
+ pszServerName = slapi_ch_malloc( MAX_SERVICE_NAME );
+ if( !SlapdGetServerNameFromCmdline(pszServerName, instancedir, 1) )
+ {
+ MessageBox(GetDesktopWindow(), "Failed to get the Directory"
+ " Server name from the command-line argument.",
+ " ", MB_ICONEXCLAMATION | MB_OK);
+ exit( 1 );
+ }
+#endif
+ if ( config_set_instancedir( "instancedir (-D)",
+ instancedir, errorbuf, 1) != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s: aborting now\n", errorbuf );
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ slapi_ch_free((void **)&instancedir);
+
+ break;
+
+ case 'p': /* port on which to listen (referral mode only) */
+ if ( config_set_port ( "portnumber (-p)", optarg_ext,
+ errorbuf, CONFIG_APPLY ) != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s: aborting now\n", errorbuf );
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ break;
+
+ case 'i': /* set pid log file or ldif2db LDIF file */
+ if ( slapd_exemode == SLAPD_EXEMODE_LDIF2DB ) {
+ char *p;
+ /* if LDIF comes through standard input, skip path checking */
+ if ( optarg_ext[0] != '-' || strlen(optarg_ext) != 1) {
+#if defined( XP_WIN32 )
+ if ( optarg_ext[0] != '/' && optarg_ext[0] != '\\'
+ && (!isalpha( optarg_ext[0] ) || (optarg_ext[1] != ':')) ) {
+ fprintf( stderr, "%s file could not be opened: absolute path "
+ " required.\n", optarg_ext );
+ break;
+ }
+#else
+ if ( optarg_ext[ 0 ] != '/' ) {
+ fprintf( stderr, "%s file could not be opened: absolute path "
+ " required.\n", optarg_ext );
+ break;
+ }
+#endif
+ }
+ p = (char *) slapi_ch_malloc(strlen(optarg_ext) + 1);
+
+ strcpy(p, optarg_ext);
+ charray_add(&ldif_file, p);
+ ldif_files++;
+ } else {
+ pid_file = rel2abspath( optarg_ext );
+ }
+ break;
+ case 'w': /* set startup pid file */
+ start_pid_file = rel2abspath( optarg_ext );
+ break;
+ case 'n': /* which backend to do ldif2db for */
+ if (slapd_exemode == SLAPD_EXEMODE_LDIF2DB ||
+ slapd_exemode == SLAPD_EXEMODE_DBTEST ||
+ slapd_exemode == SLAPD_EXEMODE_DB2INDEX) {
+ /* The -n argument will give the name of a backend instance. */
+ cmd_line_instance_name = optarg_ext;
+ } else if (slapd_exemode == SLAPD_EXEMODE_DB2LDIF) {
+ char *s = slapi_ch_strdup(optarg_ext);
+ charray_add(&cmd_line_instance_names, s);
+ } else {
+ ldif_backend = atoi( optarg_ext );
+ }
+ break;
+ case 's': /* which suffix to include in import/export */
+ {
+ char *s= slapi_dn_normalize ( slapi_ch_strdup(optarg_ext) );
+ charray_add(&db2ldif_include,s);
+ }
+ break;
+ case 'x': /* which suffix to exclude in import/export */
+ {
+ char *s= slapi_dn_normalize ( slapi_ch_strdup(optarg_ext) );
+ charray_add(&db2ldif_exclude,s);
+ }
+ break;
+ case 'r': /* db2ldif for replication */
+ if (slapd_exemode == SLAPD_EXEMODE_REFERRAL) {
+ if (config_set_referral_mode( "referral (-r)", optarg_ext,
+ errorbuf, CONFIG_APPLY) != LDAP_SUCCESS) {
+ fprintf(stderr, "%s: aborting now\n",
+ errorbuf);
+ usage(myname, *extraname);
+ exit(1);
+ }
+ break;
+ }
+ if (slapd_exemode != SLAPD_EXEMODE_DB2LDIF ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ db2ldif_dump_replica = 1;
+ break;
+ case 'N': /* do not do ldif2db duplicate value check */
+ if ( slapd_exemode != SLAPD_EXEMODE_LDIF2DB &&
+ slapd_exemode != SLAPD_EXEMODE_DB2LDIF) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ /*
+ * -N flag is obsolete, but we silently accept it
+ * so we don't break customer's scripts.
+ */
+
+ /* The -N flag now does what the -n flag used to do for db2ldif.
+ * This is so -n cane be used for the instance name just like
+ * with ldif2db. */
+ if ( slapd_exemode == SLAPD_EXEMODE_DB2LDIF ) {
+ ldif_printkey &= ~EXPORT_PRINTKEY;
+ }
+
+ break;
+
+ case 'U': /* db2ldif only */
+ if ( slapd_exemode != SLAPD_EXEMODE_DB2LDIF ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+
+ /*
+ * don't fold (wrap) long lines (default is to fold),
+ * as of ldapsearch -T
+ */
+ ldif_printkey |= EXPORT_NOWRAP;
+
+ break;
+
+ case 'm': /* db2ldif only */
+ if ( slapd_exemode != SLAPD_EXEMODE_DB2LDIF ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+
+ /* minimal base64 encoding */
+ ldif_printkey |= EXPORT_MINIMAL_ENCODING;
+
+ break;
+
+ case 'M': /* db2ldif only */
+ if ( slapd_exemode != SLAPD_EXEMODE_DB2LDIF ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+
+ /*
+ * output ldif is stored in several file called intance_filename.
+ * by default, all instances are stored in the single filename.
+ */
+ ldif_printkey &= ~EXPORT_APPENDMODE;
+
+ break;
+
+ case 'o': /* db2ldif only */
+ if ( slapd_exemode != SLAPD_EXEMODE_DB2LDIF ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+
+ /*
+ * output ldif is stored in one file.
+ * by default, each instance is stored in instance_filename.
+ */
+ ldif_printkey |= EXPORT_APPENDMODE;
+
+ break;
+
+ case 'C':
+ if (slapd_exemode == SLAPD_EXEMODE_LDIF2DB) {
+ /* used to mean "Cool new import" (which is now
+ * the default) -- ignore
+ */
+ break;
+ }
+ if (slapd_exemode == SLAPD_EXEMODE_DB2LDIF) {
+ /* possibly corrupted db -- don't look at any
+ * file except id2entry. yet another overloaded
+ * flag.
+ */
+ ldif_printkey |= EXPORT_ID2ENTRY_ONLY;
+ break;
+ }
+ usage( myname, *extraname );
+ exit( 1 );
+
+ case 'c': /* merge chunk size for Cool new import */
+ if ( slapd_exemode != SLAPD_EXEMODE_LDIF2DB ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ ldif2db_removedupvals = atoi(optarg_ext); /* We overload this flag---ok since we always check for dupes in the new code */
+ break;
+
+ case 'O': /* only create core db, no attr indexes */
+ if ( slapd_exemode != SLAPD_EXEMODE_LDIF2DB ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ ldif2db_noattrindexes = 1;
+ break;
+
+ case 't': /* attribute type to index - may be repeated */
+ case 'T': /* VLV Search to index - may be repeated */
+ if ( slapd_exemode == SLAPD_EXEMODE_DB2INDEX ) {
+ char *p= slapi_ch_malloc(strlen(optarg_ext) + 2);
+ sprintf(p,"%c%s",i,optarg_ext);
+ charray_add( &db2index_attrs, p);
+ break;
+ }
+ usage( myname, *extraname );
+ exit(1);
+
+ case 'v': /* print version and exit */
+ slapd_print_version(0);
+ exit( 1 );
+ break;
+
+ case 'V':
+ slapd_exemode = SLAPD_EXEMODE_PRINTVERSION;
+ break;
+
+ case 'a': /* archive pathname for db */
+ archive_name = optarg_ext;
+ break;
+
+ case 'Z':
+ if (slapd_exemode == SLAPD_EXEMODE_LDIF2DB)
+ {
+ ldif2db_load_state= 0;
+ break;
+ }
+ usage( myname, *extraname );
+ exit(1);
+ case 'S': /* skip the check for slad running in conflicting modes */
+ skip_db_protect_check = 1;
+ break;
+ case 'u': /* do not dump uniqueid for db2ldif */
+ if ( slapd_exemode != SLAPD_EXEMODE_DB2LDIF ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ db2ldif_dump_uniqueid = 0;
+ break;
+ case 'g': /* generate uniqueid for ldif2db */
+ if ( slapd_exemode != SLAPD_EXEMODE_LDIF2DB ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ if (optarg_ext == NULL){
+ printf ("ldif2db: generation type is not specified for -g; "
+ "random generation is used\n");
+ ldif2db_generate_uniqueid = SLAPI_UNIQUEID_GENERATE_TIME_BASED;
+ }
+ else if (strcasecmp (optarg_ext, "none") == 0)
+ ldif2db_generate_uniqueid = SLAPI_UNIQUEID_GENERATE_NONE;
+ else if (strcasecmp (optarg_ext, "deterministic") == 0) /* name based */
+ ldif2db_generate_uniqueid = SLAPI_UNIQUEID_GENERATE_NAME_BASED;
+ else /* default - time based */
+ ldif2db_generate_uniqueid = SLAPI_UNIQUEID_GENERATE_TIME_BASED;
+ break;
+ case 'G': /* namespace id for name based uniqueid generation for ldif2db */
+ if ( slapd_exemode != SLAPD_EXEMODE_LDIF2DB ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+
+ ldif2db_namespaceid = optarg_ext;
+ break;
+ case 'E': /* encrypt data if importing, decrypt if exporting */
+ if ( (slapd_exemode != SLAPD_EXEMODE_LDIF2DB) && (slapd_exemode != SLAPD_EXEMODE_DB2LDIF)) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ importexport_encrypt = 1;
+ break;
+#if defined(UPGRADEDB)
+ case 'f': /* upgradedb only */
+ if ( slapd_exemode != SLAPD_EXEMODE_UPGRADEDB ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ upgradedb_force = SLAPI_UPGRADEDB_FORCE;
+ break;
+#endif
+ case '1': /* db2ldif only */
+ if ( slapd_exemode != SLAPD_EXEMODE_DB2LDIF ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+
+ /*
+ * do not output "version: 1" to the ldif file
+ */
+ ldif_printkey |= EXPORT_NOVERSION;
+
+ break;
+ default:
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+ }
+
+ if ((NULL != cmd_line_instance_names)
+ && (NULL != cmd_line_instance_names[1])
+ && (ldif_printkey & EXPORT_APPENDMODE))
+ {
+ fprintf(stderr, "WARNING: several backends are being"
+ " exported to a single ldif file\n");
+ fprintf(stderr, " use option -M to export to"
+ " multiple ldif files\n");
+ }
+ /* Any leftover arguments? */
+ if ( optind_last > optind ) {
+ usage( myname, *extraname );
+ exit( 1 );
+ }
+
+ return;
+}
+
+static int
+lookup_instance_name_by_suffix(char *suffix,
+ char ***suffixes, char ***instances, int isexact)
+{
+ Slapi_PBlock *pb = slapi_pblock_new();
+ Slapi_Entry **entries = NULL, **ep;
+ char *query;
+ char *backend;
+ char *fullsuffix;
+ int rval = -1;
+
+ if (pb == NULL)
+ goto done;
+
+ query = slapi_ch_malloc(strlen((const char *)suffix) + 80); /* round up */
+
+ if (query == NULL)
+ goto done;
+
+ if (isexact)
+ sprintf(query, "(&(objectclass=nsmappingtree)(|(cn=\"%s\")(cn=%s)))", suffix, suffix);
+ else
+ sprintf(query, "(&(objectclass=nsmappingtree)(|(cn=*%s\")(cn=*%s)))", suffix, suffix);
+
+ slapi_search_internal_set_pb(pb, "cn=mapping tree,cn=config",
+ LDAP_SCOPE_SUBTREE, query, NULL, 0, NULL, NULL,
+ (void *)plugin_get_default_component_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_ch_free((void **)&query);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &rval);
+ if (rval != LDAP_SUCCESS)
+ goto done;
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if ((entries == NULL) || (entries[0] == NULL))
+ goto done;
+
+ rval = 0;
+ for (ep = entries; *ep; ep++) {
+ backend = slapi_entry_attr_get_charptr(*ep, "nsslapd-backend");
+ if (backend) {
+ charray_add(instances, backend);
+ if (suffixes) {
+ fullsuffix = slapi_entry_attr_get_charptr(*ep, "cn");
+ charray_add(suffixes, fullsuffix); /* NULL is ok */
+ }
+ }
+ }
+
+done:
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return rval;
+}
+
+int
+lookup_instance_name_by_suffixes(char **included, char **excluded,
+ char ***instances)
+{
+ char **incl_instances, **excl_instances;
+ char **p;
+ int rval = -1;
+
+ incl_instances = NULL;
+ for (p = included; p && *p; p++) {
+ if (lookup_instance_name_by_suffix(*p, NULL, &incl_instances, 0) < 0)
+ return rval;
+ }
+
+ excl_instances = NULL;
+ for (p = excluded; p && *p; p++) {
+ if (lookup_instance_name_by_suffix(*p, NULL, &excl_instances, 0) < 0)
+ return rval;
+ }
+
+ rval = 0;
+ charray_subtract(incl_instances, excl_instances, NULL);
+ charray_free(excl_instances);
+ *instances = incl_instances;
+ return rval;
+}
+
+/* helper function for ldif2db & friends -- given an instance name, lookup
+ * the plugin name in the DSE. this assumes the DSE has already been loaded.
+ */
+static struct slapdplugin *lookup_plugin_by_instance_name(const char *name)
+{
+ Slapi_Entry **entries = NULL;
+ Slapi_PBlock *pb = slapi_pblock_new();
+ struct slapdplugin *plugin;
+ char *query, *dn, *cn;
+ int ret = 0;
+
+ if (pb == NULL)
+ return NULL;
+
+ query = slapi_ch_malloc(strlen(name) + 80); /* round up */
+ if (query == NULL) {
+ slapi_pblock_destroy(pb);
+ return NULL;
+ }
+ sprintf(query, "(&(cn=%s)(objectclass=nsBackendInstance))", name);
+
+ slapi_search_internal_set_pb(pb, "cn=plugins,cn=config",
+ LDAP_SCOPE_SUBTREE, query, NULL, 0, NULL, NULL,
+ (void *)plugin_get_default_component_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_ch_free((void **)&query);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != LDAP_SUCCESS) {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return NULL;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if ((entries == NULL) || (entries[0] == NULL)) {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return NULL;
+ }
+
+ /* okay -- have the entry for this instance, now let's chop up the dn */
+ /* parent dn is the plugin */
+ dn = slapi_dn_parent(slapi_entry_get_dn(entries[0]));
+
+ /* clean up */
+ slapi_free_search_results_internal(pb);
+ entries = NULL;
+ slapi_pblock_destroy(pb);
+ pb = NULL; /* this seems redundant . . . until we add code after this line */
+
+ /* now... look up the parent */
+ pb = slapi_pblock_new();
+ slapi_search_internal_set_pb(pb, dn, LDAP_SCOPE_BASE,
+ "(objectclass=nsSlapdPlugin)", NULL, 0, NULL, NULL,
+ (void *)plugin_get_default_component_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_ch_free((void **)&dn);
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != LDAP_SUCCESS) {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return NULL;
+ }
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if ((entries == NULL) || (entries[0] == NULL)) {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ return NULL;
+ }
+
+ cn = slapi_entry_attr_get_charptr(entries[0], "cn");
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+
+ plugin = plugin_get_by_name(cn);
+ slapi_ch_free((void **)&cn);
+
+ return plugin;
+}
+
+static int
+slapd_exemode_ldif2db()
+{
+ int return_value= 0;
+ Slapi_PBlock pb;
+ struct slapdplugin *plugin;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( ldif_file == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: Required argument -i <ldiffile> missing\n",
+ 0, 0, 0 );
+ usage( myname, extraname );
+ exit( 1 );
+ }
+
+ /* this should be the first time this are called! if the init order
+ * is ever changed, these lines should be changed (or erased)!
+ */
+ mapping_tree_init();
+
+ /*
+ * if instance is given, just use it to get the backend.
+ * otherwise, we use included/excluded suffix list to specify a backend.
+ */
+ if (NULL == cmd_line_instance_name) {
+ char **instances, **ip;
+ int counter;
+
+ if (lookup_instance_name_by_suffixes(db2ldif_include, db2ldif_exclude,
+ &instances) < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: backend instances name [-n <name>] or "
+ "included suffix [-s <suffix>] need to be specified.\n",
+ 0, 0, 0);
+ exit(1);
+ }
+
+ if (instances) {
+ for (ip = instances, counter = 0; ip && *ip; ip++, counter++)
+ ;
+
+ if (counter == 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR 1: There is no backend instance to import to.\n",
+ 0, 0, 0);
+ exit(1);
+ } else if (counter > 1) {
+ int i;
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: There are multiple backend instances specified:\n",
+ 0, 0, 0);
+ for (i = 0; i < counter; i++)
+ LDAPDebug(LDAP_DEBUG_ANY, " : %s\n",
+ instances[i], 0, 0);
+ exit(1);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "Backend Instance: %s\n",
+ *instances, 0, 0);
+ cmd_line_instance_name = *instances;
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR 2: There is no backend instance to import to.\n",
+ 0, 0, 0);
+ exit(1);
+ }
+ }
+
+ plugin = lookup_plugin_by_instance_name(cmd_line_instance_name);
+ if (plugin == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: Could not find backend '%s'.\n",
+ cmd_line_instance_name, 0, 0);
+ exit(1);
+ }
+
+ /* Make sure we aren't going to run slapd in
+ * a mode that is going to conflict with other
+ * slapd processes that are currently running
+ */
+ if ( add_new_slapd_process(slapd_exemode, db2ldif_dump_replica,
+ skip_db_protect_check) == -1 ) {
+
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Shutting down due to possible conflicts with other slapd processes\n",
+ 0, 0, 0 );
+ exit(1);
+ }
+ /* check for slapi v2 support */
+ if (! SLAPI_PLUGIN_IS_V2(plugin)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: %s is too old to do imports.\n",
+ plugin->plg_name, 0, 0);
+ exit(1);
+ }
+
+ memset( &pb, '\0', sizeof(pb) );
+ pb.pb_backend = NULL;
+ pb.pb_plugin = plugin;
+ pb.pb_removedupvals = ldif2db_removedupvals;
+ pb.pb_ldif2db_noattrindexes = ldif2db_noattrindexes;
+ pb.pb_ldif_generate_uniqueid = ldif2db_generate_uniqueid;
+ pb.pb_ldif_namespaceid = ldif2db_namespaceid;
+ pb.pb_ldif_encrypt = importexport_encrypt;
+/* pb.pb_ldif_load_state = ldif2db_load_state; */
+ pb.pb_instance_name = cmd_line_instance_name;
+ pb.pb_ldif_files = ldif_file;
+ pb.pb_ldif_include = db2ldif_include;
+ pb.pb_ldif_exclude = db2ldif_exclude;
+ pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE;
+#ifndef _WIN32
+ main_setuid(slapdFrontendConfig->localuser);
+#endif
+ if ( plugin->plg_ldif2db != NULL ) {
+ return_value = (*plugin->plg_ldif2db)( &pb );
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: no ldif2db function defined for "
+ "%s\n", plugin->plg_name, 0, 0 );
+ return_value = -1;
+ }
+ slapi_ch_free((void**)&myname );
+ charray_free( db2index_attrs );
+ charray_free(ldif_file);
+ return( return_value );
+}
+
+static int
+slapd_exemode_db2ldif(int argc, char** argv)
+{
+ int return_value= 0;
+ Slapi_PBlock pb;
+ struct slapdplugin *plugin;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *my_ldiffile;
+ char **instp;
+
+ /* this should be the first time this are called! if the init order
+ * is ever changed, these lines should be changed (or erased)!
+ */
+ mapping_tree_init();
+
+ /*
+ * if instance is given, just pass it to the backend.
+ * otherwise, we use included/excluded suffix list to specify a backend.
+ */
+ if (NULL == cmd_line_instance_names) {
+ char **instances, **ip;
+ int counter;
+
+ if (lookup_instance_name_by_suffixes(db2ldif_include, db2ldif_exclude,
+ &instances) < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: backend instances name [-n <name>] or "
+ "included suffix [-s <suffix>] need to be specified.\n",
+ 0, 0, 0);
+ exit(1);
+ }
+
+ if (instances) {
+ for (ip = instances, counter = 0; ip && *ip; ip++, counter++)
+ ;
+
+ if (counter == 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR 1: There is no backend instance to export from.\n",
+ 0, 0, 0);
+ exit(1);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "Backend Instance: %s\n",
+ *instances, 0, 0);
+ cmd_line_instance_names = instances;
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR 2: There is no backend instance to export from.\n",
+ 0, 0, 0);
+ exit(1);
+ }
+ }
+
+#ifndef _WIN32
+ /* [622984] db2lidf -r changes database file ownership
+ * should call setuid before "db2ldif_dump_replica" */
+ main_setuid(slapdFrontendConfig->localuser);
+#endif
+ for (instp = cmd_line_instance_names; instp && *instp; instp++) {
+ int release_me = 0;
+
+ plugin = lookup_plugin_by_instance_name(*instp);
+ if (plugin == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: Could not find backend '%s'.\n",
+ *instp, 0, 0);
+ exit(1);
+ }
+
+ if (plugin->plg_db2ldif == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: no db2ldif function defined for "
+ "backend %s - cannot export\n", *instp, 0, 0);
+ exit(1);
+ }
+
+ /* Make sure we aren't going to run slapd in
+ * a mode that is going to conflict with other
+ * slapd processes that are currently running
+ */
+ if ( add_new_slapd_process(slapd_exemode, db2ldif_dump_replica,
+ skip_db_protect_check) == -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Shutting down due to possible conflicts "
+ "with other slapd processes\n",
+ 0, 0, 0 );
+ exit(1);
+ }
+ if ( config_is_slapd_lite () &&
+ !slapi_config_get_readonly () && is_slapd_running() ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "%s\n", LITE_BACKUP_ERR, 0, 0);
+ exit ( 1 );
+ }
+
+ if (! (SLAPI_PLUGIN_IS_V2(plugin))) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: %s is too old to do exports.\n",
+ plugin->plg_name, 0, 0);
+ exit(1);
+ }
+
+ memset( &pb, '\0', sizeof(pb) );
+ pb.pb_backend = NULL;
+ pb.pb_plugin = plugin;
+ pb.pb_ldif_include = db2ldif_include;
+ pb.pb_ldif_exclude = db2ldif_exclude;
+ pb.pb_ldif_dump_replica = db2ldif_dump_replica;
+ pb.pb_ldif_dump_uniqueid = db2ldif_dump_uniqueid;
+ pb.pb_ldif_encrypt = importexport_encrypt;
+ pb.pb_instance_name = *instp;
+ pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE;
+ if (is_slapd_running())
+ pb.pb_server_running = 1;
+ else
+ pb.pb_server_running = 0;
+
+ if (db2ldif_dump_replica) {
+ eq_init(); /* must be done before plugins started */
+ ps_init_psearch_system(); /* must come before plugin_startall() */
+ plugin_startall(argc, argv, 1 /* Start Backends */,
+ 1 /* Start Globals */);
+ eq_start(); /* must be done after plugins started */
+ }
+
+ pb.pb_ldif_file = NULL;
+ if ( archive_name ) { /* redirect stdout to this file: */
+ char *p, *q;
+#if defined( XP_WIN32 )
+ char sep = '\\';
+ if (NULL != strchr(archive_name, '/'))
+ sep = '/';
+#else
+ char sep = '/';
+#endif
+ my_ldiffile = archive_name;
+ if (ldif_printkey & EXPORT_APPENDMODE) {
+ if (instp == cmd_line_instance_names) { /* first export */
+ ldif_printkey |= EXPORT_APPENDMODE_1;
+ } else {
+ ldif_printkey &= ~EXPORT_APPENDMODE_1;
+ }
+ } else { /* not APPENDMODE */
+ if (strcmp(archive_name, "-")) { /* not '-' */
+ my_ldiffile =
+ (char *)slapi_ch_malloc((unsigned long)(strlen(archive_name)
+ + strlen(*instp) + 2));
+ p = strrchr(archive_name, sep);
+ if (NULL == p) {
+ sprintf(my_ldiffile, "%s_%s", *instp, archive_name);
+ } else {
+ q = p + 1;
+ *p = '\0';
+ sprintf(my_ldiffile, "%s%c%s_%s",
+ archive_name, sep, *instp, q);
+ *p = sep;
+ }
+ release_me = 1;
+ }
+ }
+
+ fprintf(stderr, "ldiffile: %s\n", my_ldiffile);
+ /* just send the filename to the backend and let
+ * the backend open it (so they can do special
+ * stuff for 64-bit fs)
+ */
+ pb.pb_ldif_file = my_ldiffile;
+ pb.pb_ldif_printkey = ldif_printkey;
+ }
+
+ return_value = (plugin->plg_db2ldif)( &pb );
+
+ if (release_me) {
+ slapi_ch_free((void **)&my_ldiffile);
+ }
+ }
+ slapi_ch_free( (void**)&myname );
+ if (db2ldif_dump_replica) {
+ plugin_closeall( 1 /* Close Backends */, 1 /* Close Globals */);
+ }
+ return( return_value );
+}
+
+static int
+slapd_exemode_suffix2instance()
+{
+ int return_value = 0;
+ char **instances = NULL;
+ char **suffixes = NULL;
+ char **p, **q, **r;
+
+ /* this should be the first time this are called! if the init order
+ * is ever changed, these lines should be changed (or erased)!
+ */
+ mapping_tree_init();
+
+ for (p = db2ldif_include; p && *p; p++) {
+ if (lookup_instance_name_by_suffix(*p, &suffixes, &instances, 0) < 0)
+ continue;
+ fprintf(stderr, "Suffix, Instance name pair(s) under \"%s\":\n", *p);
+ if (instances)
+ for (q = suffixes, r = instances; *r; q++, r++)
+ fprintf(stderr, "\tsuffix %s; instance name \"%s\"\n",
+ *q?*q:"-", *r);
+ else
+ fprintf(stderr, "\tNo instance\n");
+ charray_free(suffixes);
+ suffixes = NULL;
+ charray_free(instances);
+ instances = NULL;
+ }
+ return (return_value);
+}
+
+static int slapd_exemode_db2index()
+{
+ int return_value= 0;
+ struct slapdplugin *plugin;
+ Slapi_PBlock pb;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ mapping_tree_init();
+
+ /*
+ * if instance is given, just use it to get the backend.
+ * otherwise, we use included/excluded suffix list to specify a backend.
+ */
+ if (NULL == cmd_line_instance_name) {
+ char **instances, **ip;
+ int counter;
+
+ if (lookup_instance_name_by_suffixes(db2ldif_include, db2ldif_exclude,
+ &instances) < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: backend instances name [-n <name>] or "
+ "included suffix [-s <suffix>] need to be specified.\n",
+ 0, 0, 0);
+ exit(1);
+ }
+
+ if (instances) {
+ for (ip = instances, counter = 0; ip && *ip; ip++, counter++)
+ ;
+
+ if (counter == 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR 1: There is no backend instance to import to.\n",
+ 0, 0, 0);
+ exit(1);
+ } else if (counter > 1) {
+ int i;
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: There are multiple backend instances specified:\n",
+ 0, 0, 0);
+ for (i = 0; i < counter; i++)
+ LDAPDebug(LDAP_DEBUG_ANY, " : %s\n",
+ instances[i], 0, 0);
+ exit(1);
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY, "Backend Instance: %s\n",
+ *instances, 0, 0);
+ cmd_line_instance_name = *instances;
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR 2: There is no backend instance to import to.\n",
+ 0, 0, 0);
+ exit(1);
+ }
+ }
+
+ plugin = lookup_plugin_by_instance_name(cmd_line_instance_name);
+ if (plugin == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: Could not find backend '%s'.\n",
+ cmd_line_instance_name, 0, 0);
+ exit(1);
+ }
+
+ /* make sure nothing else is running */
+ if (add_new_slapd_process(slapd_exemode, db2ldif_dump_replica,
+ skip_db_protect_check) == -1) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Shutting down due to possible conflicts with other "
+ "slapd processes.\n", 0, 0, 0);
+ exit(1);
+ }
+
+ if ( db2index_attrs == NULL ) {
+ usage( myname, extraname );
+ exit( 1 );
+ }
+ memset( &pb, '\0', sizeof(pb) );
+ pb.pb_backend = NULL;
+ pb.pb_plugin = plugin;
+ pb.pb_db2index_attrs = db2index_attrs;
+ pb.pb_instance_name = cmd_line_instance_name;
+ pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE;
+#ifndef _WIN32
+ main_setuid(slapdFrontendConfig->localuser);
+#endif
+ return_value = (*plugin->plg_db2index)( &pb );
+
+ slapi_ch_free( (void**)&myname );
+ return( return_value );
+}
+
+
+static int
+slapd_exemode_db2archive()
+{
+ int return_value= 0;
+ Slapi_Backend *be = NULL;
+ Slapi_PBlock pb;
+ struct slapdplugin *backend_plugin;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ((backend_plugin = plugin_get_by_name("ldbm database")) == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: Could not find the ldbm backend plugin.\n",
+ 0, 0, 0);
+ exit(1);
+ }
+ if (NULL == archive_name) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: no archive directory supplied\n",
+ 0, 0, 0 );
+ exit( 1 );
+ }
+
+ if ( config_is_slapd_lite () && !slapi_config_get_readonly () && is_slapd_running ()) {
+ LDAPDebug( LDAP_DEBUG_ANY, "%s\n", LITE_BACKUP_ERR, 0, 0);
+ exit ( 1 );
+ }
+
+ /* Make sure we aren't going to run slapd in
+ * a mode that is going to conflict with other
+ * slapd processes that are currently running
+ */
+ if ( add_new_slapd_process(slapd_exemode, db2ldif_dump_replica,
+ skip_db_protect_check) == -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Shutting down due to possible conflicts with other slapd processes\n",
+ 0, 0, 0 );
+ exit(1);
+ }
+ if (compute_init()) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Initialization Failed 0 %d\n",return_value,0,0);
+ exit (1);
+ }
+
+ memset( &pb, '\0', sizeof(pb) );
+ pb.pb_backend = NULL;
+ pb.pb_plugin = backend_plugin;
+ pb.pb_instance_name = cmd_line_instance_name;
+ pb.pb_seq_val = archive_name;
+ pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE;
+#ifndef _WIN32
+ main_setuid(slapdFrontendConfig->localuser);
+#endif
+ return_value = (backend_plugin->plg_db2archive)( &pb );
+ return return_value;
+}
+
+static int
+slapd_exemode_archive2db()
+{
+ int return_value= 0;
+ Slapi_Backend *be = NULL;
+ Slapi_PBlock pb;
+ struct slapdplugin *backend_plugin;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ((backend_plugin = plugin_get_by_name("ldbm database")) == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: Could not find the ldbm backend plugin.\n",
+ 0, 0, 0);
+ exit(1);
+ }
+ if (NULL == archive_name) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: no archive directory supplied\n",
+ 0, 0, 0 );
+ exit( 1 );
+ }
+
+ /* Make sure we aren't going to run slapd in
+ * a mode that is going to conflict with other
+ * slapd processes that are currently running
+ */
+ if ( add_new_slapd_process(slapd_exemode, db2ldif_dump_replica,
+ skip_db_protect_check) == -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Shutting down due to possible conflicts with other slapd processes\n",
+ 0, 0, 0 );
+ exit(1);
+ }
+ if (compute_init()) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Initialization Failed 0 %d\n",return_value,0,0);
+ exit (1);
+ }
+
+ memset( &pb, '\0', sizeof(pb) );
+ pb.pb_backend = NULL;
+ pb.pb_plugin = backend_plugin;
+ pb.pb_instance_name = cmd_line_instance_name;
+ pb.pb_seq_val = archive_name;
+ pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE;
+#ifndef _WIN32
+ main_setuid(slapdFrontendConfig->localuser);
+#endif
+ return_value = (backend_plugin->plg_archive2db)( &pb );
+ return return_value;
+}
+
+#if defined(UPGRADEDB)
+/*
+ * functions to convert idl from the old format to the new one
+ * (604921) Support a database uprev process any time post-install
+ */
+static int
+slapd_exemode_upgradedb()
+{
+ int return_value= 0;
+ Slapi_PBlock pb;
+ struct slapdplugin *backend_plugin;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if ( archive_name == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: Required argument -a <backup_dir> missing\n",
+ 0, 0, 0 );
+ usage( myname, extraname );
+ exit( 1 );
+ }
+
+ /* this should be the first time this are called! if the init order
+ * is ever changed, these lines should be changed (or erased)!
+ */
+ mapping_tree_init();
+
+ if ((backend_plugin = plugin_get_by_name("ldbm database")) == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: Could not find the ldbm backend plugin.\n",
+ 0, 0, 0);
+ exit(1);
+ }
+
+ /* Make sure we aren't going to run slapd in
+ * a mode that is going to conflict with other
+ * slapd processes that are currently running
+ */
+ if (add_new_slapd_process(slapd_exemode, 0, skip_db_protect_check) == -1) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Shutting down due to possible conflicts with other slapd processes\n",
+ 0, 0, 0 );
+ exit(1);
+ }
+ /* check for slapi v2 support */
+ if (! SLAPI_PLUGIN_IS_V2(backend_plugin)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: %s is too old to do convert idl.\n",
+ backend_plugin->plg_name, 0, 0);
+ exit(1);
+ }
+
+ memset( &pb, '\0', sizeof(pb) );
+ pb.pb_backend = NULL;
+ pb.pb_plugin = backend_plugin;
+ pb.pb_seq_val = archive_name;
+ pb.pb_seq_type = upgradedb_force;
+ pb.pb_task_flags = TASK_RUNNING_FROM_COMMANDLINE;
+ /* borrowing import code, so need to set up the import variables */
+ pb.pb_ldif_generate_uniqueid = ldif2db_generate_uniqueid;
+ pb.pb_ldif_namespaceid = ldif2db_namespaceid;
+ pb.pb_ldif2db_noattrindexes = 0;
+ pb.pb_removedupvals = 0;
+#ifndef _WIN32
+ main_setuid(slapdFrontendConfig->localuser);
+#endif
+ if ( backend_plugin->plg_upgradedb != NULL ) {
+ return_value = (*backend_plugin->plg_upgradedb)( &pb );
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ERROR: no upgradedb function defined for "
+ "%s\n", backend_plugin->plg_name, 0, 0 );
+ return_value = -1;
+ }
+ slapi_ch_free((void**)&myname );
+ return( return_value );
+}
+#endif
+
+
+static int
+slapd_exemode_dbtest()
+{
+ int return_value= 0;
+ Slapi_PBlock pb;
+ struct slapdplugin *plugin;
+
+ if (NULL == cmd_line_instance_name) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "dbtest: Required argument -n <instance name> missing\n", 0, 0, 0);
+ usage( myname, extraname );
+ exit(1);
+ }
+
+ mapping_tree_init();
+
+ plugin = lookup_plugin_by_instance_name(cmd_line_instance_name);
+ if (plugin == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: Could not find backend '%s'.\n",
+ cmd_line_instance_name, 0, 0);
+ exit(1);
+ }
+
+ /* Make sure we aren't going to run slapd in
+ * a mode that is going to conflict with other
+ * slapd processes that are currently running
+ */
+ if ( add_new_slapd_process(slapd_exemode, db2ldif_dump_replica,
+ skip_db_protect_check) == -1 ) {
+
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Shutting down due to possible conflicts with other slapd processes\n",
+ 0, 0, 0 );
+ exit(1);
+ }
+
+ pb.pb_backend = NULL;
+ pb.pb_plugin = plugin;
+ pb.pb_instance_name = cmd_line_instance_name;
+ /* For dbtest, we do _not_ change identity (no setuid()) */
+ return_value= (*plugin->plg_dbtest)( &pb );
+ return return_value;
+}
+
+
+
+#ifdef LDAP_DEBUG
+/*
+ * Table to associate a string with a debug level.
+ */
+static struct slapd_debug_level_entry {
+ int dle_level; /* LDAP_DEBUG_XXX value */
+ const char *dle_string; /* string equivalent; NULL marks end of list */
+ char dle_hide;
+} slapd_debug_level_map[] = {
+ { LDAP_DEBUG_TRACE, "trace", 0 },
+ { LDAP_DEBUG_PACKETS, "packets", 0 },
+ { LDAP_DEBUG_ARGS, "arguments", 0 },
+ { LDAP_DEBUG_ARGS, "args", 1 },
+ { LDAP_DEBUG_CONNS, "connections", 0 },
+ { LDAP_DEBUG_CONNS, "conn", 1 },
+ { LDAP_DEBUG_CONNS, "conns", 1 },
+ { LDAP_DEBUG_BER, "ber", 0 },
+ { LDAP_DEBUG_FILTER, "filters", 0 },
+ { LDAP_DEBUG_CONFIG, "config", 0 },
+ { LDAP_DEBUG_ACL, "accesscontrol", 0 },
+ { LDAP_DEBUG_ACL, "acl", 1 },
+ { LDAP_DEBUG_ACL, "acls", 1 },
+ { LDAP_DEBUG_STATS, "stats", 0 },
+ { LDAP_DEBUG_STATS2, "stats2", 0 },
+ { LDAP_DEBUG_SHELL, "shell", 1 },
+ { LDAP_DEBUG_PARSE, "parsing", 0 },
+ { LDAP_DEBUG_HOUSE, "housekeeping", 0 },
+ { LDAP_DEBUG_REPL, "replication", 0 },
+ { LDAP_DEBUG_REPL, "repl", 1 },
+ { LDAP_DEBUG_ANY, "errors", 0 },
+ { LDAP_DEBUG_ANY, "ANY", 1 },
+ { LDAP_DEBUG_ANY, "error", 1 },
+ { LDAP_DEBUG_CACHE, "caches", 0 },
+ { LDAP_DEBUG_CACHE, "cache", 1 },
+ { LDAP_DEBUG_PLUGIN, "plugins", 0 },
+ { LDAP_DEBUG_PLUGIN, "plugin", 1 },
+ { LDAP_DEBUG_TIMING, "timing", 0 },
+ { LDAP_DEBUG_ACLSUMMARY,"accesscontrolsummary", 0 },
+ { LDAP_DEBUG_ALL_LEVELS,"ALL", 0 },
+ { 0, NULL, 0 }
+};
+
+
+
+/*
+ * Given a string represention of a debug level, map it to a integer value
+ * and return that value. -1 is returned upon error, with a message
+ * printed to stderr.
+ */
+static int
+slapd_debug_level_string2level( const char *s )
+{
+ int level, i;
+ char *cur, *next, *scopy;
+
+ level = 0;
+ cur = scopy = slapi_ch_strdup( s );
+
+ for ( cur = scopy; cur != NULL; cur = next ) {
+ if (( next = strchr( cur, '+' )) != NULL ) {
+ *next++ = '\0';
+ }
+
+ if ( isdigit( *cur )) {
+ level |= atoi( cur );
+ } else {
+ for ( i = 0; NULL != slapd_debug_level_map[i].dle_string; ++i ) {
+ if ( strcasecmp( cur, slapd_debug_level_map[i].dle_string )
+ == 0 ) {
+ level |= slapd_debug_level_map[i].dle_level;
+ break;
+ }
+ }
+
+ if ( NULL == slapd_debug_level_map[i].dle_string ) {
+ fprintf( stderr, "Unrecognized debug level \"%s\"\n", cur );
+ return -1;
+ }
+ }
+ }
+
+ slapi_ch_free( (void **)&scopy );
+
+ return level;
+}
+
+
+/*
+ * Print to stderr the string equivalent of level.
+ * The ANY level is omitted because it is always present.
+ */
+static void
+slapd_debug_level_log( int level )
+{
+ int i, count, len;
+ char *msg, *p;
+
+ level &= ~LDAP_DEBUG_ANY;
+
+ /* first pass: determine space needed for the debug level string */
+ len = 1; /* room for '\0' terminator */
+ count = 0;
+ for ( i = 0; NULL != slapd_debug_level_map[i].dle_string; ++i ) {
+ if ( !slapd_debug_level_map[i].dle_hide &&
+ slapd_debug_level_map[i].dle_level != LDAP_DEBUG_ALL_LEVELS
+ && 0 != ( level & slapd_debug_level_map[i].dle_level )) {
+ if ( count > 0 ) {
+ ++len; /* room for '+' character */
+ }
+ len += strlen( slapd_debug_level_map[i].dle_string );
+ ++count;
+ }
+ }
+
+ /* second pass: construct the debug level string */
+ p = msg = slapi_ch_malloc( len );
+ count = 0;
+ for ( i = 0; NULL != slapd_debug_level_map[i].dle_string; ++i ) {
+ if ( !slapd_debug_level_map[i].dle_hide &&
+ slapd_debug_level_map[i].dle_level != LDAP_DEBUG_ALL_LEVELS
+ && 0 != ( level & slapd_debug_level_map[i].dle_level )) {
+ if ( count > 0 ) {
+ *p++ = '+';
+ }
+ strcpy( p, slapd_debug_level_map[i].dle_string );
+ p += strlen( p );
+ ++count;
+ }
+ }
+
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPD_VERSION_STR,
+ "%s: %s (%d)\n", "debug level", msg, level );
+ slapi_ch_free( (void **)&msg );
+}
+
+
+/*
+ * Display usage/help for the debug level flag (-d)
+ */
+static void
+slapd_debug_level_usage( void )
+{
+ int i;
+
+ fprintf( stderr, "Debug levels:\n" );
+ for ( i = 0; NULL != slapd_debug_level_map[i].dle_string; ++i ) {
+ if ( !slapd_debug_level_map[i].dle_hide
+ && slapd_debug_level_map[i].dle_level
+ != LDAP_DEBUG_ALL_LEVELS) {
+ fprintf( stderr, " %6d - %s%s\n",
+ slapd_debug_level_map[i].dle_level,
+ slapd_debug_level_map[i].dle_string,
+ ( 0 == ( slapd_debug_level_map[i].dle_level &
+ LDAP_DEBUG_ANY )) ? "" :
+ " (always logged)" );
+ }
+ }
+ fprintf( stderr, "To activate multiple levels, add the numeric"
+ " values together or separate the\n"
+ "values with a + character, e.g., all of the following"
+ " have the same effect:\n"
+ " -d connections+filters\n"
+ " -d 8+32\n"
+ " -d 40\n" );
+}
+#endif /* LDAP_DEBUG */
+
diff --git a/ldap/servers/slapd/mapping_tree.c b/ldap/servers/slapd/mapping_tree.c
new file mode 100644
index 00000000..797ea14d
--- /dev/null
+++ b/ldap/servers/slapd/mapping_tree.c
@@ -0,0 +1,3436 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* mapping_tree.c - Maps the DIT onto backends and/or referrals. */
+
+
+#include "slap.h"
+
+/* distribution plugin prototype */
+typedef int (* mtn_distrib_fct) (Slapi_PBlock *pb, Slapi_DN * target_dn,
+ char **mtn_be_names, int be_count, Slapi_DN * mtn_node_dn, int *mtn_be_states);
+
+struct mt_node
+{
+ Slapi_DN *mtn_subtree; /* dn for the node's subtree */
+ Slapi_Backend **mtn_be; /* backend pointer - the list of backends implementing this
+ * node usually there is only one back-end here, there can
+ * be several only when distribution is done on this node
+ */
+ int *mtn_be_states; /* states for the backends in table mtn_be */
+ char **mtn_backend_names; /* list of backend names */
+ int mtn_be_list_size; /* size of the previous three tables */
+ int mtn_be_count; /* number of backends implementing this node */
+ char **mtn_referral; /* referral or list of referrals */
+ Slapi_Entry *mtn_referral_entry; /* referral or list of referrals */
+ struct mt_node *mtn_children;
+ struct mt_node *mtn_parent;
+ struct mt_node *mtn_brother; /* list of other nodes with the same parent */
+ int mtn_state;
+ int mtn_private; /* Never show this node to the user. only used for
+ * cn=config, cn=schema and root node */
+ char * mtn_dstr_plg_lib; /* distribution plugin library name */
+ char * mtn_dstr_plg_name; /* distribution plugin function name */
+ mtn_distrib_fct mtn_dstr_plg; /* pointer to the actual ditribution function */
+ void *mtn_extension; /* plugins can extend a mapping tree node */
+};
+
+#define BE_LIST_INIT_SIZE 10
+#define BE_LIST_INCREMENT 10
+
+/* Mapping tree locking strategy
+ *
+ * There are two goals for the mapping tree locking
+ * - protect the mapping tree structures
+ * - prevent stop or re-initialisation of a backend which is currently
+ * used by an LDAP operation
+ * This must be done without preventing parallelisation of LDAP operations
+ *
+ * we use
+ * - one RW lock will be used to protect access to mapping tree structures
+ * accessed throuh mtn_lock(), mtn_unlock(), mtn_wlock()
+ * - one RW lock for each backend. This lock is taken in READ for each
+ * LDAP operation in progree on the backend
+ * and is taken in write for administrative operations like stop or
+ * disable the backend
+ * accessed through slapi_be_Rlock(), slapi_be_Wlock(), slapi_be_Unlock()
+ * - a state flag for each backend : mtn_be_states[]
+ * this state is set to SLAPI_BE_STATE_DELETE or SLAPI_BE_STATE_OFFLINE at the beginning
+ * of stop/disable operation to ensure that no new operation starts
+ * while the backend is stopped/disabled
+ *
+ * The algorithme for LDAP OPERATIONS is :
+ *
+ * lock mapping tree in read mode
+ * get backend
+ * check that backend is not in SLAPI_BE_STATE_DELETE or SLAPI_BE_STATE_OFFLINE state
+ * lock backend in read mode
+ * unlock mapping tree
+ * do LDAP operation
+ * release backend lock
+ *
+ * The algorithme for maintenance operation is
+ * lock mapping tree in write mode
+ * set state to SLAPI_BE_STATE_DELETE or SLAPI_BE_STATE_OFFLINE
+ * unlock mapping tree
+ * get backend lock in write mode
+ * release backend lock
+ *
+ */
+static PRRWLock *myLock; /* global lock on the mapping tree structures */
+
+
+static mapping_tree_node *mapping_tree_root = NULL;
+static int mapping_tree_inited = 0;
+static int mapping_tree_freed = 0;
+static int extension_type = -1; /* type returned from the factory */
+
+/* The different states a mapping tree node can be in. */
+#define MTN_DISABLED 0 /* The server acts like the node isn't there. */
+#define MTN_BACKEND 1 /* This node represents a backend. */
+#define MTN_REFERRAL 2 /* A referral is returned instead of a backend. */
+#define MTN_REFERRAL_ON_UPDATE 3 /* A referral is returned for update operations. */
+#define MTN_CONTAINER 4 /* This node represents a container for backends. */
+
+/* Need to add a modifier flag to the state - such as round robin */
+
+#define MAPPING_TREE_BASE_DN "cn=mapping tree,cn=config"
+#define MAPPING_TREE_PARENT_ATTRIBUTE "nsslapd-parent-suffix"
+
+void mtn_wlock();
+void mtn_lock();
+void mtn_unlock();
+
+static mapping_tree_node * mtn_get_mapping_tree_node_by_entry(
+ mapping_tree_node* node, const Slapi_DN *dn);
+static void mtn_remove_node(mapping_tree_node * node);
+static void mtn_free_node (mapping_tree_node **node);
+static int mtn_get_be_distributed(Slapi_PBlock *pb,
+ mapping_tree_node * target_node, Slapi_DN *target_sdn, int * flag_stop);
+static int mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb,
+ Slapi_Backend **be, int * index, Slapi_Entry **referral, char *errorbuf);
+static mapping_tree_node * mtn_get_next_node(mapping_tree_node * node,
+ mapping_tree_node * node_list, int scope);
+static mapping_tree_node * mtn_get_first_node(mapping_tree_node * node,
+ int scope);
+static mapping_tree_node *
+ get_mapping_tree_node_by_name(mapping_tree_node * node, char * be_name);
+
+#ifdef DEBUG
+static void dump_mapping_tree(mapping_tree_node *parent, int depth);
+#endif
+
+/* structure and static local variable used to store the
+ * list of plugins that have registered to a callback when backend state
+ * change
+ */
+struct mtn_be_ch_list {
+ void * handle;
+ struct mtn_be_ch_list * next;
+ slapi_backend_state_change_fnptr fnct;
+ };
+
+static struct mtn_be_ch_list * mtn_plug_list = NULL;
+
+/* API for registering to a callback when backend state change */
+void slapi_register_backend_state_change(void * handle, slapi_backend_state_change_fnptr funct)
+{
+ struct mtn_be_ch_list * new_be_ch_plg;
+ new_be_ch_plg = (struct mtn_be_ch_list *)
+ slapi_ch_malloc(sizeof(struct mtn_be_ch_list));
+ new_be_ch_plg->next = mtn_plug_list;
+ new_be_ch_plg->handle = handle;
+ new_be_ch_plg->fnct = funct;
+ mtn_plug_list = new_be_ch_plg;
+}
+
+/* To unregister all the state change callbacks registered on the mapping tree */
+int slapi_unregister_backend_state_change_all()
+{
+ struct mtn_be_ch_list *cur_be_ch_plg;
+ while (mtn_plug_list)
+ {
+ cur_be_ch_plg = mtn_plug_list;
+ mtn_plug_list = mtn_plug_list->next;
+ slapi_ch_free((void **) &cur_be_ch_plg);
+ }
+ return 1;
+}
+
+
+int slapi_unregister_backend_state_change(void * handle)
+{
+ struct mtn_be_ch_list * cur_be_ch_plg = mtn_plug_list;
+ struct mtn_be_ch_list * prev_be_ch_plg = mtn_plug_list;
+ while (cur_be_ch_plg)
+ {
+ if (cur_be_ch_plg->handle == handle)
+ {
+ if (cur_be_ch_plg == mtn_plug_list)
+ {
+ mtn_plug_list = mtn_plug_list->next;
+ slapi_ch_free((void **) &cur_be_ch_plg);
+ return 0;
+ }
+ else
+ {
+ prev_be_ch_plg->next = cur_be_ch_plg->next;
+ slapi_ch_free((void **) &cur_be_ch_plg);
+ return 0;
+ }
+ }
+ prev_be_ch_plg = cur_be_ch_plg;
+ cur_be_ch_plg = cur_be_ch_plg->next;
+ }
+ return 1;
+}
+
+void mtn_be_state_change(char * be_name, int old_state, int new_state)
+{
+ struct mtn_be_ch_list * cur_be_ch_plg = mtn_plug_list;
+
+ while (cur_be_ch_plg)
+ {
+ (* (cur_be_ch_plg->fnct))(cur_be_ch_plg->handle, be_name,
+ old_state, new_state);
+ cur_be_ch_plg = cur_be_ch_plg->next;
+ }
+}
+
+
+Slapi_DN* slapi_mtn_get_dn(mapping_tree_node *node)
+{
+ return (node->mtn_subtree);
+}
+
+/* this will turn an array of url into a referral entry */
+static Slapi_Entry *
+referral2entry(char ** url_array, const char *target)
+{
+ int i;
+ struct berval bv0,bv1,*bvals[3];
+ Slapi_Entry *anEntry;
+
+ if (url_array == NULL)
+ return NULL;
+
+ anEntry = slapi_entry_alloc();
+ slapi_entry_set_dn(anEntry,slapi_ch_strdup(target));
+
+ bvals[2]=NULL;
+ bvals[1]=&bv1;
+ bv1.bv_val="referral";
+ bv1.bv_len=strlen(bv1.bv_val);
+ bvals[0]=&bv0;
+ bv0.bv_val="top";
+ bv0.bv_len=strlen(bv0.bv_val);
+ slapi_entry_add_values( anEntry, "objectClass", bvals);
+
+ bvals[1]=NULL;
+ for (i=0; url_array[i]; i++) {
+ bv0.bv_val=url_array[i];
+ bv0.bv_len=strlen(bv0.bv_val);
+ slapi_entry_attr_merge( anEntry, "ref", bvals);
+ }
+ return anEntry;
+}
+
+
+/* mapping tree node extension */
+int
+mapping_tree_get_extension_type ()
+{
+ if(extension_type==-1)
+ {
+ /* The factory is given the name of the object type, in
+ * return for a type handle. Whenever the object is created
+ * or destroyed the factory is called with the handle so
+ * that it may call the constructors or destructors registered
+ * with it.
+ */
+ extension_type= factory_register_type(SLAPI_EXT_MTNODE,
+ offsetof(mapping_tree_node, mtn_extension));
+ }
+ return extension_type;
+}
+
+static mapping_tree_node *
+mapping_tree_node_new(Slapi_DN *dn, Slapi_Backend **be, char **backend_names, int *be_states,
+ int count, int size,
+ char **referral, mapping_tree_node *parent,
+ int state, int private, char *plg_lib, char *plg_fct,
+ mtn_distrib_fct plg)
+{
+ Slapi_RDN rdn;
+ mapping_tree_node *node;
+ node = (mapping_tree_node *) slapi_ch_calloc(1, sizeof(mapping_tree_node));
+ node->mtn_subtree = dn;
+ node->mtn_be = be;
+ node->mtn_be_states = be_states;
+ node->mtn_backend_names = backend_names;
+ node->mtn_referral = referral;
+ node->mtn_referral_entry = referral2entry(referral, slapi_sdn_get_dn(dn)) ;
+ node->mtn_parent = parent;
+ node->mtn_children = NULL;
+ node->mtn_brother = NULL;
+ node->mtn_state = state;
+ node->mtn_private = private;
+ node->mtn_be_list_size = size;
+ node->mtn_be_count = count;
+ /* We use this count of the rdn components in the mapping tree to help
+ * when selecting a mapping tree node for a dn. */
+ slapi_rdn_init_sdn(&rdn,dn);
+ slapi_rdn_done(&rdn);
+ node->mtn_dstr_plg_lib = plg_lib;
+ node->mtn_dstr_plg_name = plg_fct;
+ node->mtn_dstr_plg = plg;
+
+ return node;
+}
+
+/*
+ * Description:
+ * Adds a mapping tree node to the child list of another mapping tree node.
+ *
+ * Arguments:
+ * parent and child are pointers to mapping tree nodes. child will be added
+ * to parent's child list. For now, the child is added to the head of the
+ * linked list. Later we may come up a way to ordering the entries in the
+ * list.
+ *
+ * Returns:
+ * nothing
+ */
+static void
+mapping_tree_node_add_child(mapping_tree_node *parent, mapping_tree_node* child)
+{
+ /* WARNING:
+ * As for now the mapping tree is not locked when a child is added
+ * this is possible only because the child is added into the mapping
+ * the structure by a single operation after being fully initialized
+ * should this be changed, the lock policy would have to be checked
+ * see mapping_tree_entry_add_callback()
+ */
+ child->mtn_brother = parent->mtn_children;
+ parent->mtn_children = child;
+ /* for debugging: dump_mapping_tree(mapping_tree_root, 0); */
+}
+
+static Slapi_DN *
+get_parent_from_entry(Slapi_Entry * entry)
+{
+ Slapi_Attr *attr = NULL;
+ char * parent;
+ Slapi_Value *val = NULL;
+ Slapi_DN *parent_sdn;
+
+ if (slapi_entry_attr_find(entry, MAPPING_TREE_PARENT_ATTRIBUTE, &attr))
+ return NULL;
+
+ slapi_attr_first_value(attr, &val);
+
+ parent = slapi_ch_strdup(slapi_value_get_string(val));
+ if(parent[0]=='\"')
+ {
+ parent[strlen(parent) - 1] = '\0';
+ parent_sdn = slapi_sdn_new_dn_byval(parent+1);
+ }
+ else
+ parent_sdn = slapi_sdn_new_dn_byval(parent);
+ slapi_ch_free((void **) &parent);
+
+ return parent_sdn;
+}
+
+/* extract the subtree managed by a mapping tree entry from the entry
+ */
+static Slapi_DN *
+get_subtree_from_entry(Slapi_Entry * entry)
+{
+ Slapi_Attr *attr = NULL;
+ char * cn;
+ Slapi_Value *val = NULL;
+ Slapi_DN *subtree;
+
+ if (slapi_entry_attr_find(entry, "cn", &attr))
+ return NULL;
+
+ /* should check that there is only one value for cn attribute */
+ slapi_attr_first_value(attr, &val);
+
+ /* The value of cn is the dn of the subtree for this node.
+ * There is a slight problem though. The cn value is
+ * quoted. We have to remove the quotes here. I'm sure
+ * there is a proper way to do this, but for now we'll
+ * just assume that the first and last chars are ". Later
+ * we'll have to revisit this because things could be a
+ * lot more complicated. Especially if there are quotes
+ * in the dn of the subtree root dn! */
+ /* JCM - Need to dequote correctly. */
+ /* GB : I think removing the first and last " in the cn value
+ * is the right stuff to do
+ */
+ cn = slapi_ch_strdup(slapi_value_get_string(val));
+ if(cn[0]=='\"')
+ {
+ cn[strlen(cn) - 1] = '\0';
+ subtree = slapi_sdn_new_dn_byval(cn+1);
+ }
+ else
+ subtree = slapi_sdn_new_dn_byval(cn);
+ slapi_ch_free((void **) &cn);
+
+ return subtree;
+}
+
+static int
+mtn_state_to_int(const char * state_string, Slapi_Entry *entry)
+{
+ if (!strcasecmp(state_string, "disabled")) {
+ return MTN_DISABLED;
+ } else if (!strcasecmp(state_string, "backend")) {
+ return MTN_BACKEND;
+ } else if (!strcasecmp(state_string, "referral")) {
+ return MTN_REFERRAL;
+ } else if (!strcasecmp(state_string, "referral on update")) {
+ return MTN_REFERRAL_ON_UPDATE;
+ } else if (!strcasecmp(state_string, "container")) {
+ return MTN_CONTAINER;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: Unknown state, %s, for mapping tree node %s."
+ " Defaulting to DISABLED\n",
+ state_string, slapi_entry_get_dn(entry), 0);
+ return MTN_DISABLED;
+ }
+}
+
+static char **
+mtn_get_referral_from_entry(Slapi_Entry * entry)
+{
+ int nb;
+ int hint;
+ char ** referral;
+ Slapi_Attr * attr;
+ Slapi_Value *val = NULL;
+
+ if (slapi_entry_attr_find(entry, "nsslapd-referral", &attr))
+ return NULL;
+
+ slapi_attr_get_numvalues(attr, &nb);
+ referral = (char **) slapi_ch_malloc(sizeof(char *) * (nb+1));
+ hint = slapi_attr_first_value(attr, &val);
+ if (NULL == val) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: The nsslapd-referral attribute has no value for the mapping tree node %s\n", slapi_entry_get_dn(entry), 0, 0);
+ return NULL;
+ }
+
+ nb = 0;
+ while (val)
+ {
+ referral[nb++] = slapi_ch_strdup(slapi_value_get_string(val));
+ hint = slapi_attr_next_value(attr, hint, &val);
+ }
+ referral[nb] = NULL;
+
+ return referral;
+}
+
+static int
+get_backends_from_attr(Slapi_Attr *attr, backend ***be_list, char ***be_names,
+ int ** be_states, int *be_list_count, int *be_list_size,
+ mapping_tree_node * node)
+{
+ Slapi_Value *val = NULL;
+ backend *tmp_be = NULL;
+ char * tmp_backend_name;
+ int hint;
+ mapping_tree_node* new_node;
+
+ *be_list_size = BE_LIST_INIT_SIZE;
+ *be_list_count = 0;
+
+ *be_list = (backend **) slapi_ch_malloc(sizeof(backend *) * BE_LIST_INIT_SIZE);
+ *be_names = (char **) slapi_ch_malloc(sizeof(char *) * BE_LIST_INIT_SIZE);
+ *be_states = (int *) slapi_ch_malloc(sizeof(int) * BE_LIST_INIT_SIZE);
+
+ hint = slapi_attr_first_value(attr, &val);
+ if (NULL == val) {
+ slapi_ch_free ((void **)be_list);
+ *be_list = NULL;
+ return 0;
+ }
+
+ while (val)
+ {
+ tmp_backend_name = (char *) slapi_ch_strdup(slapi_value_get_string(val));
+ if (*be_list_count >= *be_list_size)
+ {
+ (*be_list_size) += BE_LIST_INCREMENT;
+ *be_names = (char **) slapi_ch_realloc((char *) (*be_names),
+ sizeof(char *) * (*be_list_size));
+ *be_list = (backend **) slapi_ch_realloc((char *) (*be_list),
+ sizeof(backend *) * (*be_list_size));
+ *be_states = (int *) slapi_ch_realloc((char *) (*be_states),
+ sizeof(int) * (*be_list_size));
+ }
+ (*be_names)[*be_list_count] = tmp_backend_name;
+
+ /* set backend as started by default */
+ (*be_states)[*be_list_count] = SLAPI_BE_STATE_ON;
+
+ /* We now need to find the backend with name backend_name. */
+ tmp_be= slapi_be_select_by_instance_name(tmp_backend_name);
+ new_node = get_mapping_tree_node_by_name(mapping_tree_root,
+ tmp_backend_name);
+ if (new_node && (new_node != node))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: backend %s is already pointed to by a mapping tree"
+ " node. Only one mapping tree node can point to a backend\n",
+ tmp_backend_name, 0, 0);
+ tmp_be = NULL;
+ return -1;
+ }
+ if(tmp_be!=NULL)
+ {
+ tmp_be->be_mapped = 1;
+ (*be_list)[*be_list_count] = tmp_be;
+ }
+ else
+ {
+ /* It's just not here yet. That's OK. We'll fix it up at runtime. */
+ (*be_list)[*be_list_count] = NULL;
+ }
+ (*be_list_count) ++;
+ hint = slapi_attr_next_value(attr, hint, &val);
+ }
+
+ return 0;
+}
+
+/*
+ * Description:
+ * Release the memory allocated by the routine above.
+ * Call this when the backend not put into structure and need to cleanup these tmp allocations
+ */
+static void
+free_get_backends_from_attr(backend ***be_list, char ***be_names,
+ int ** be_states, int *be_list_count)
+{
+ int i;
+
+ /* sanity check */
+ PR_ASSERT (be_list != NULL && be_names != NULL && be_states != NULL && be_list_count != NULL);
+
+ if (*be_names != NULL) for (i = 0; i < *be_list_count; ++i) {
+ slapi_ch_free ((void **)&((*be_names)[i]));
+ }
+ slapi_ch_free ((void **)be_names);
+ slapi_ch_free ((void **)be_list);
+ slapi_ch_free ((void **)be_states);
+ *be_list_count = 0;
+}
+
+/*
+ * Description:
+ * Takes an entry and creates a mapping tree node from it. Loops through the
+ * attributes, pulling needed info from them. Right now, each node can only
+ * have one backend and one referral. Once we move to supporting more than
+ * one node and more than one referral, this function will need to be
+ * massaged a little.
+ *
+ * We should make a objectclass for a mapping tree node entry. That way
+ * schema checking would make this function more robust.
+ *
+ * Arguments:
+ * A mapping tree node entry read in from the DIT.
+ *
+ * Returns:
+ * An LDAP result code (LDAP_SUCCESS if all goes well).
+ * If the return value is LDAP_SUCCESS, *newnodep is set to the new mapping
+ * tree node (guaranteed to be non-NULL).
+ */
+static int
+mapping_tree_entry_add(Slapi_Entry *entry, mapping_tree_node **newnodep )
+{
+ Slapi_DN *subtree = NULL;
+ const char *tmp_ndn;
+ int be_list_count = 0;
+ int be_list_size;
+ backend **be_list = NULL;
+ char **be_names = NULL;
+ int * be_states = NULL;
+ char * plugin_funct = NULL;
+ char * plugin_lib = NULL;
+ mtn_distrib_fct plugin = NULL;
+
+ char **referral = NULL;
+ int state = MTN_DISABLED;
+ Slapi_Attr *attr = NULL;
+ mapping_tree_node *node = NULL;
+ mapping_tree_node *parent_node = mapping_tree_root;
+ int rc;
+ int lderr = LDAP_UNWILLING_TO_PERFORM; /* our default result code */
+ char *tmp_backend_name;
+ Slapi_Backend *be;
+
+ PR_ASSERT(newnodep != NULL);
+ *newnodep = NULL;
+
+ subtree = get_subtree_from_entry(entry);
+ /* Make sure we know the root dn of the subtree for this node. */
+ if (NULL == subtree) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: Unable to determine the subtree represented by the mapping tree node %s\n",
+ slapi_entry_get_dn(entry), 0, 0);
+ return lderr;
+ }
+
+ tmp_ndn = slapi_sdn_get_ndn( subtree );
+ if (tmp_ndn && ( '\0' == *tmp_ndn)) {
+
+ /* This entry is associated with the "" subtree. Treat this is
+ * a special case (no parent; will replace the internal root
+ * node (mapping_tree_root) with data from this entry).
+ */
+ slapi_log_error( SLAPI_LOG_ARGS, "mapping_tree_entry_add", "NULL suffix\n" );
+ parent_node = NULL;
+ }
+
+
+ /* Make sure a node does not already exist for this subtree */
+ if ( parent_node != NULL && NULL != mtn_get_mapping_tree_node_by_entry(mapping_tree_root,
+ subtree)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: a mapping tree node for the"
+ " subtree %s already exists; unable to add the node %s\n",
+ slapi_sdn_get_dn(subtree), slapi_entry_get_dn(entry), 0);
+ slapi_sdn_free(&subtree);
+ return LDAP_ALREADY_EXISTS;
+ }
+
+ /* Loop through the attributes and handle the ones we care about. */
+ for (rc = slapi_entry_first_attr(entry, &attr);
+ !rc && attr;
+ rc = slapi_entry_next_attr(entry, attr, &attr)) {
+
+ char *type = NULL;
+ Slapi_Value *val = NULL;
+
+ slapi_attr_get_type(attr, &type);
+ if (NULL == type) {
+ /* strange... I wonder if we should give a warning here? */
+ continue;
+ }
+
+ if (!strcasecmp(type, "nsslapd-backend")) {
+
+ if (get_backends_from_attr(attr, &be_list, &be_names, &be_states,
+ &be_list_count, &be_list_size, NULL)) {
+ free_get_backends_from_attr(&be_list, &be_names, &be_states, &be_list_count);
+ slapi_sdn_free(&subtree);
+ return lderr;
+ }
+
+ if (NULL == be_list)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: The nsslapd-backend attribute has no value for the mapping tree node %s\n",
+ slapi_entry_get_dn(entry), 0, 0);
+ continue;
+ }
+
+ } else if (!strcasecmp(type, "nsslapd-referral")) {
+ referral = mtn_get_referral_from_entry(entry);
+
+ } else if (!strcasecmp(type, "nsslapd-state")) {
+ const char *state_string;
+
+ slapi_attr_first_value(attr, &val);
+ if (NULL == val) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: Can't determine the state of the mapping tree node %s\n",
+ slapi_entry_get_dn(entry), 0, 0);
+ continue;
+ }
+ /* Convert the string representation for the state to an int */
+ state_string = slapi_value_get_string(val);
+ state = mtn_state_to_int(state_string, entry);
+
+ } else if (!strcasecmp(type, "nsslapd-distribution-plugin")) {
+ slapi_attr_first_value(attr, &val);
+ if (NULL == val) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: The nsslapd-distribution-plugin attribute has no value for the mapping tree node %s\n",
+ slapi_entry_get_dn(entry), 0, 0);
+ continue;
+ }
+ plugin_lib = slapi_ch_strdup(slapi_value_get_string(val));
+ } else if (!strcasecmp(type, "nsslapd-distribution-funct")) {
+ slapi_attr_first_value(attr, &val);
+ if (NULL == val) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Warning: The nsslapd-distribution-plugin attribute has no value for the mapping tree node %s\n",
+ slapi_entry_get_dn(entry), 0, 0);
+ continue;
+ }
+ plugin_funct = slapi_ch_strdup(slapi_value_get_string(val));
+ } else if (!strcasecmp(type, MAPPING_TREE_PARENT_ATTRIBUTE)) {
+ Slapi_DN *parent_node_dn = get_parent_from_entry(entry);
+ parent_node = mtn_get_mapping_tree_node_by_entry(
+ mapping_tree_root, parent_node_dn);
+
+ if (parent_node == NULL)
+ {
+ parent_node = mapping_tree_root;
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: could not find parent for %s defaulting to root\n",
+ slapi_entry_get_dn(entry), 0, 0);
+ }
+ slapi_sdn_free(&parent_node_dn);
+ }
+ }
+
+ if (state == MTN_CONTAINER)
+ {
+ /* this can be extended later to include the general
+ null suffix, */
+ /* The "default" backend is used by the container node */
+ be = defbackend_get_backend();
+ if(be == NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: default container has not been created for the NULL SUFFIX node.\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ be_list_size = 1;
+ be_list_count = 0;
+
+ be_list = (backend **) slapi_ch_calloc(1, sizeof(backend *) );
+ be_names = (char **) slapi_ch_calloc(1, sizeof(char *) );
+ be_states = (int *) slapi_ch_calloc(1, sizeof(int) );
+
+ tmp_backend_name = (char *) slapi_ch_strdup("default"); /* "NULL_CONTAINER" */
+ (be_names)[be_list_count] = tmp_backend_name;
+
+ /* set backend as started by default */
+ (be_states)[be_list_count] = SLAPI_BE_STATE_ON;
+
+ be->be_mapped = 1;
+ (be_list)[be_list_count] = be;
+ be_list_count++;
+
+ }
+ /* check that all required attributes for the givene state are there :
+ * state backend -> need nsslapd-backend attribute
+ * state referral or referral on update -> need nsslapd-referral attribute
+ */
+
+ if (((state == MTN_BACKEND) || (state == MTN_REFERRAL_ON_UPDATE))
+ && (be_names == NULL))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: node %s must define a backend\n",
+ slapi_entry_get_dn(entry), 0, 0);
+ slapi_sdn_free(&subtree);
+ free_get_backends_from_attr(&be_list, &be_names, &be_states, &be_list_count);
+ return lderr;
+ }
+ if (((state == MTN_REFERRAL) || (state == MTN_REFERRAL_ON_UPDATE))
+ && (referral == NULL))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: node %s must define referrals to be in referral state\n",
+ slapi_entry_get_dn(entry), 0, 0);
+ slapi_sdn_free(&subtree);
+ free_get_backends_from_attr(&be_list, &be_names, &be_states, &be_list_count);
+ return lderr;
+ }
+
+ if (plugin_lib && plugin_funct)
+ {
+ PRLibrary *lib = PR_LoadLibrary(plugin_lib);
+ if (lib)
+ {
+ plugin = (mtn_distrib_fct) PR_FindSymbol(lib, plugin_funct);
+ }
+ else
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: can't load plugin lib %s. "
+ SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
+ plugin_lib, PR_GetError(), slapd_pr_strerror(PR_GetError()));
+ }
+
+ if (plugin == NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: node %s cannot find distribution plugin. "
+ SLAPI_COMPONENT_NAME_NSPR " %d (%s)\n",
+ slapi_entry_get_dn(entry), PR_GetError(), slapd_pr_strerror(PR_GetError()));
+ slapi_sdn_free(&subtree);
+ slapi_ch_free((void **) &plugin_funct);
+ slapi_ch_free((void **) &plugin_lib);
+ free_get_backends_from_attr(&be_list, &be_names, &be_states, &be_list_count);
+ return lderr;
+ }
+ }
+ else if ((plugin_lib == NULL) && (plugin_funct == NULL))
+ {
+ /* nothing configured -> OK */
+ plugin = NULL;
+ }
+ else
+ {
+ /* only one parameter configured -> ERROR */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: node %s must define both lib and funct"
+ " for distribution plugin\n",
+ slapi_entry_get_dn(entry), 0, 0);
+ slapi_sdn_free(&subtree);
+ slapi_ch_free((void **) &plugin_funct);
+ slapi_ch_free((void **) &plugin_lib);
+ free_get_backends_from_attr(&be_list, &be_names, &be_states, &be_list_count);
+ return lderr;
+ }
+
+ /* Now we can create the node for this mapping tree entry. */
+ node= mapping_tree_node_new(subtree, be_list, be_names, be_states, be_list_count,
+ be_list_size, referral, parent_node, state,
+ 0 /* Normal node. People can see and change it. */,
+ plugin_lib, plugin_funct, plugin);
+
+ tmp_ndn = slapi_sdn_get_ndn( subtree );
+ if ( NULL != node && NULL == parent_node && tmp_ndn
+ && ('\0' == *tmp_ndn )) {
+ /* The new node is actually the "" node. Replace the root
+ * node with this new one by copying all information (we can't
+ * free the root node completely because children of the root
+ * node hold pointers to it in their mtn_parent field).
+ */
+
+ slapi_log_error( SLAPI_LOG_ARGS, "mapping_tree_entry_add", "fix up NULL suffix\n" );
+
+ node->mtn_children = mapping_tree_root->mtn_children;
+ node->mtn_brother = mapping_tree_root->mtn_brother;
+ *mapping_tree_root = *node; /* struct copy */
+ slapi_ch_free( (void **)&node );
+ node = mapping_tree_root;
+ }
+
+
+ if ( NULL != node ) {
+ lderr = LDAP_SUCCESS;
+ *newnodep = node;
+ }
+
+ return lderr;
+}
+
+/*
+ * Recursive procedure used to create node extensions once the mapping tree
+ * is fully initialized
+ * This is done after full init of the mapping tree so that the extensions can do
+ * searches
+ */
+void mtn_create_extension(mapping_tree_node *node)
+{
+ if (node == NULL)
+ return;
+
+ node->mtn_extension = factory_create_extension(mapping_tree_get_extension_type(),
+ node, NULL /* parent */);
+
+ mtn_create_extension(node->mtn_children);
+ mtn_create_extension(node->mtn_brother);
+}
+
+
+/*
+ * Description:
+ * Does the main work of building the in memory mapping tree form the entries
+ * in the DIT. This function is called recursively on all the given nodes
+ * children to build up the tree. Basically it does an internal search for
+ * all the entries who have the target node as a parent.
+ *
+ * Arguments:
+ * The target node and a flag that tells if it's the root of the tree.
+ *
+ * Returns:
+ * Nothing
+ */
+static int
+mapping_tree_node_get_children(mapping_tree_node *target, int is_root)
+{
+ Slapi_PBlock *pb;
+ char * filter = NULL;
+ int res;
+ Slapi_Entry **entries = NULL;
+ int x;
+ int result = 0;
+
+ pb = slapi_pblock_new();
+
+ /* Remember that the root node of the mapping tree is the NULL suffix.
+ * Since we don't really support it, children of the root node won't
+ * have a MAPPING_TREE_PARENT_ATTRIBUTE. */
+ if (is_root) {
+ filter = slapi_ch_malloc(strlen(MAPPING_TREE_PARENT_ATTRIBUTE)+38);
+ sprintf(filter, "(&(objectclass=nsMappingTree)(!(%s=*)))",
+ MAPPING_TREE_PARENT_ATTRIBUTE);
+ } else {
+ filter = slapi_ch_malloc(strlen(slapi_sdn_get_dn(target->mtn_subtree))
+ + strlen(MAPPING_TREE_PARENT_ATTRIBUTE) + 36);
+ sprintf(filter, "(&(objectclass=nsMappingTree)(%s=\"%s\"))",
+ MAPPING_TREE_PARENT_ATTRIBUTE,
+ slapi_sdn_get_dn(target->mtn_subtree));
+ }
+
+ slapi_search_internal_set_pb(pb, MAPPING_TREE_BASE_DN, LDAP_SCOPE_ONELEVEL,
+ filter, NULL, 0, NULL, NULL, (void *) plugin_get_default_component_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if (res != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: Mapping tree unable to read %s: %d\n",
+ MAPPING_TREE_BASE_DN, res, 0);
+ result = -1;
+ goto done;
+ }
+
+ /* We now create the mapping tree node and call this function for each
+ * of the target's children. */
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: No mapping tree node entries found under %s\n",
+ MAPPING_TREE_BASE_DN, 0, 0);
+ result = -1;
+ goto done;
+ }
+
+ for(x = 0; entries[x] != NULL; x++) {
+ mapping_tree_node *child = NULL;
+
+ if (LDAP_SUCCESS != mapping_tree_entry_add(entries[x], &child)) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: could not add mapping tree node %s\n",
+ slapi_entry_get_dn(entries[x]), 0, 0);
+ result = -1;
+ goto done;
+ }
+ if(target == child){
+ /* the mapping tree root got replaced
+ * nothing to do
+ */
+ } else {
+
+ child->mtn_parent = target;
+ mapping_tree_node_add_child(target, child);
+ }
+
+
+ if (mapping_tree_node_get_children(child, 0 /* not the root node */))
+ {
+ result = -1;
+ goto done;
+ }
+ }
+ slapi_free_search_results_internal(pb);
+
+done:
+ slapi_pblock_destroy(pb);
+ if (filter)
+ slapi_ch_free((void **) &filter);
+ return result;
+}
+
+/*
+ * Description:
+ * A first attempt at walking over the mapping tree and making sure things
+ * make sense. Right now it just makes sure that each parent node has a
+ * subtree that is the suffix of its children's subtrees. This function
+ * is called recursively.
+ *
+ * Arguments:
+ * The root node of the mapping tree.
+ *
+ * Returns:
+ * Nothing - it just prints warnings. This should probably change.
+ */
+static void
+mapping_tree_node_validate(mapping_tree_node *node)
+{
+ mapping_tree_node *child_entry;
+
+ /* Call this function for all of nodes children */
+ for (child_entry = node->mtn_children; child_entry; child_entry = child_entry->mtn_brother) {
+ mapping_tree_node_validate(child_entry);
+ }
+
+ if (node->mtn_parent) {
+ if (!slapi_sdn_issuffix(node->mtn_subtree, node->mtn_parent->mtn_subtree)) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: Invalid mapping tree. %s can not be a child of %s\n",
+ slapi_sdn_get_ndn(node->mtn_subtree),
+ slapi_sdn_get_ndn(node->mtn_parent->mtn_subtree), 0);
+ }
+ }
+}
+
+static void
+mtn_free_referral_in_node (mapping_tree_node *node)
+{
+ char ** referral = node->mtn_referral;
+
+ if (referral)
+ {
+ int i;
+
+ for (i=0; referral[i]; i++)
+ slapi_ch_free((void **) &(referral[i]));
+ slapi_ch_free((void **) &referral);
+ }
+ if (node->mtn_referral_entry)
+ slapi_entry_free(node->mtn_referral_entry);
+
+ node->mtn_referral = NULL;
+ node->mtn_referral_entry = NULL;
+}
+
+int mapping_tree_entry_modify_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ LDAPMod **mods;
+ int i;
+ mapping_tree_node * node;
+ Slapi_DN * subtree;
+ Slapi_Attr * attr;
+ Slapi_Value *val = NULL;
+ int be_list_count = 0;
+ int be_list_size = 0;
+ backend **backends = NULL;
+ char **be_names = NULL;
+ int * be_states = NULL;
+ char * plugin_fct = NULL;
+ char * plugin_lib = NULL;
+ int plugin_flag = 0;
+ mtn_distrib_fct plugin = NULL;
+
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ subtree = get_subtree_from_entry(entryAfter);
+ node = mtn_get_mapping_tree_node_by_entry(mapping_tree_root, subtree);
+ if (node == NULL)
+ {
+ /* should never happen */
+ *returncode = LDAP_OPERATIONS_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ for (i = 0; mods[i] != NULL; i++) {
+ if ( (strcasecmp(mods[i]->mod_type, "cn") == 0) ||
+ (strcasecmp(mods[i]->mod_type,
+ MAPPING_TREE_PARENT_ATTRIBUTE) == 0) )
+ {
+ mapping_tree_node * parent_node;
+ /* if we are deleting this attribute the new parent
+ * node will be mapping_tree_root
+ */
+ if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE)
+ {
+ parent_node = mapping_tree_root;
+ }
+ else
+ {
+ /* we have to find the new parent node */
+ Slapi_DN *parent_node_dn;
+ parent_node_dn = get_parent_from_entry(entryAfter);
+ parent_node = mtn_get_mapping_tree_node_by_entry(
+ mapping_tree_root, parent_node_dn);
+ if (parent_node == NULL)
+ {
+ parent_node = mapping_tree_root;
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Error: could not find parent for %s\n",
+ slapi_entry_get_dn(entryAfter), 0, 0);
+ slapi_sdn_free(&subtree);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ slapi_sdn_free(&parent_node_dn);
+ }
+
+ mtn_wlock();
+ /* modifying the parent of a node means moving it to an
+ * other place of the tree
+ * this can be done simply by removing it from its old place and
+ * moving it to the new one
+ */
+ mtn_remove_node(node);
+ mapping_tree_node_add_child(parent_node, node);
+ node->mtn_parent = parent_node;
+ mtn_unlock();
+
+ }
+ else if (strcasecmp(mods[i]->mod_type, "nsslapd-backend" ) == 0)
+ {
+ slapi_entry_attr_find(entryAfter, "nsslapd-backend", &attr);
+ if (NULL == attr)
+ {
+ /* if nsslapd-backend attribute is empty all backends have
+ * been suppressed, set backend list to NULL
+ * checks on the state are done a bit later
+ */
+ backends = NULL;
+ be_names = NULL;
+ be_states = NULL;
+ be_list_count = 0;
+ be_list_size = 0;
+ }
+ else if (get_backends_from_attr(attr, &backends, &be_names,
+ &be_states, &be_list_count, &be_list_size, node))
+ {
+ free_get_backends_from_attr(&backends, &be_names, &be_states, &be_list_count);
+ slapi_sdn_free(&subtree);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ mtn_wlock();
+
+ if ((backends == NULL) && (node->mtn_state == MTN_BACKEND))
+ {
+ sprintf(returntext, "mapping tree entry need at least one nsslapd-backend\n");
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ mtn_unlock();
+ free_get_backends_from_attr(&backends, &be_names, &be_states, &be_list_count);
+ slapi_sdn_free(&subtree);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ node->mtn_be_states = be_states;
+ node->mtn_be = backends;
+ node->mtn_backend_names = be_names;
+ node->mtn_be_count = be_list_count;
+ node->mtn_be_list_size = be_list_size;
+
+ mtn_unlock();
+
+ }
+ else if (strcasecmp(mods[i]->mod_type, "nsslapd-state" ) == 0)
+ {
+ Slapi_Value * val;
+ const char * new_state;
+ Slapi_Attr * attr;
+
+ /* state change
+ * for now only allow replace
+ */
+ if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) != LDAP_MOD_REPLACE)
+ {
+ sprintf(returntext, "must use replace operation to change state\n");
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ slapi_sdn_free(&subtree);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ if ((mods[i]->mod_bvalues == NULL) || (mods[i]->mod_bvalues[0] == NULL))
+ {
+ slapi_sdn_free(&subtree);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ slapi_entry_attr_find(entryAfter, "nsslapd-state", &attr);
+ slapi_attr_first_value(attr, &val);
+ new_state = slapi_value_get_string(val);
+
+ if (mtn_state_to_int(new_state, entryAfter) == MTN_BACKEND)
+ {
+ if (slapi_entry_attr_find(entryAfter, "nsslapd-backend", &attr))
+ {
+ sprintf(returntext, "need to set nsslapd-backend before moving to backend state\n");
+ slapi_sdn_free(&subtree);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+
+ if ((mtn_state_to_int(new_state, entryAfter) == MTN_REFERRAL) ||
+ (mtn_state_to_int(new_state, entryAfter) == MTN_REFERRAL_ON_UPDATE))
+ {
+ if (slapi_entry_attr_find(entryAfter, "nsslapd-referral", &attr))
+ {
+ sprintf(returntext, "need to set nsslapd-referral before moving to referral state\n");
+ slapi_sdn_free(&subtree);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+
+ mtn_wlock();
+
+ node->mtn_state = mtn_state_to_int(new_state, entryAfter);
+
+ mtn_unlock();
+ }
+ else if (strcasecmp(mods[i]->mod_type, "nsslapd-referral" ) == 0)
+ {
+ char ** referral;
+
+ mtn_wlock();
+
+ if (((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_REPLACE)
+ || ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD))
+ {
+ /* delete old referrals, set new ones */
+ mtn_free_referral_in_node(node);
+ referral = mtn_get_referral_from_entry(entryAfter);
+ node->mtn_referral = referral;
+ node->mtn_referral_entry =
+ referral2entry(referral, slapi_sdn_get_dn(subtree));
+ } else if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE)
+ {
+ /* it is not OK to delete the referrals if they are still
+ * used
+ */
+ if ((node->mtn_state == MTN_REFERRAL) ||
+ (node->mtn_state == MTN_REFERRAL_ON_UPDATE))
+ {
+ sprintf(returntext,
+ "cannot delete referrals in this state\n");
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ mtn_unlock();
+ slapi_sdn_free(&subtree);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ mtn_free_referral_in_node(node);
+
+ } else
+ {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ mtn_unlock();
+ slapi_sdn_free(&subtree);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ mtn_unlock();
+ slapi_sdn_free(&subtree);
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+ else if (strcasecmp(mods[i]->mod_type,
+ "nsslapd-distribution-funct" ) == 0)
+ {
+ if (((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_REPLACE)
+ || ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD))
+ {
+ slapi_entry_attr_find(entryAfter,
+ "nsslapd-distribution-funct", &attr);
+ slapi_attr_first_value(attr, &val);
+ if (NULL == val) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: The nsslapd-distribution-funct attribute"
+ " has no value for the mapping tree node %s\n",
+ slapi_entry_get_dn(entryAfter), 0, 0);
+ plugin_fct = NULL;
+ }
+ plugin_fct = slapi_ch_strdup(slapi_value_get_string(val));
+ }
+ else if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE)
+ {
+ plugin_fct = NULL;
+ }
+ plugin_flag = 1;
+ }
+ else if (strcasecmp(mods[i]->mod_type,
+ "nsslapd-distribution-plugin" ) == 0)
+ {
+ if (((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_REPLACE)
+ || ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD))
+ {
+ slapi_entry_attr_find(entryAfter,
+ "nsslapd-distribution-plugin", &attr);
+ slapi_attr_first_value(attr, &val);
+ if (NULL == val) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: The nsslapd-distribution-plugin attribute"
+ " has no value for the mapping tree node %s\n",
+ slapi_entry_get_dn(entryAfter), 0, 0);
+ plugin_lib = NULL;
+ }
+ plugin_lib = slapi_ch_strdup(slapi_value_get_string(val));
+ }
+ else if ((mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE)
+ {
+ plugin_lib = NULL;
+ }
+ plugin_flag = 1;
+
+ }
+ }
+
+ /* if distribution plugin has been configured or modified
+ * check that the library and function exist
+ * and if yes apply the modifications
+ */
+ if (plugin_flag)
+ {
+ if (plugin_lib && plugin_fct)
+ {
+ PRLibrary *lib = PR_LoadLibrary(plugin_lib);
+ if (lib)
+ plugin = (mtn_distrib_fct) PR_FindSymbol(lib, plugin_fct);
+
+ if (plugin == NULL)
+ {
+ sprintf(returntext, "cannot find distribution plugin\n");
+ slapi_ch_free((void **) &plugin_fct);
+ slapi_ch_free((void **) &plugin_lib);
+ slapi_sdn_free(&subtree);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ else if ((plugin_lib == NULL) && (plugin_fct == NULL))
+ {
+ /* nothing configured -> OK */
+ plugin = NULL;
+ }
+ else
+ {
+ /* only one parameter configured -> ERROR */
+ sprintf(returntext,
+ "must define distribution function and library\n");
+ slapi_ch_free((void **) &plugin_fct);
+ slapi_ch_free((void **) &plugin_lib);
+ slapi_sdn_free(&subtree);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ mtn_wlock();
+ if (node->mtn_dstr_plg_lib)
+ slapi_ch_free((void **) &node->mtn_dstr_plg_lib);
+ node->mtn_dstr_plg_lib = plugin_lib;
+ if (node->mtn_dstr_plg_name)
+ slapi_ch_free((void **) &node->mtn_dstr_plg_name);
+ node->mtn_dstr_plg_name = plugin_fct;
+ node->mtn_dstr_plg = plugin;
+ mtn_unlock();
+ }
+
+ slapi_sdn_free(&subtree);
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+int mapping_tree_entry_add_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ mapping_tree_node *node;
+ int i;
+ backend * be;
+
+ /* WARNING
+ * for adds we don't need to grab the mapping tree global lock,
+ * because the add operation in the tree is atomic because
+ * only one pointer is updated in the tree.
+ * Should the mapping tree stucture change, this would have to
+ * be checked again
+ */
+ *returncode = mapping_tree_entry_add(entryBefore, &node);
+ if (LDAP_SUCCESS != *returncode)
+ {
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ if(node && node->mtn_parent != NULL && node != mapping_tree_root )
+ {
+ /* If the node has a parent and the node is not the mapping tree root,
+ * then add it as a child node. Note that the special case when the
+ * node is the mapping tree root and has no parent is handled inside
+ * the mapping_tree_entry_add() function by replacing the contents of
+ * the mapping tree root node with information from the add request.
+ */
+ mapping_tree_node_add_child(node->mtn_parent, node);
+ }
+
+ for (i = 0; ((i < node->mtn_be_count) && (node->mtn_backend_names) &&
+ (node->mtn_backend_names[i])); i++)
+ {
+ if ((be = slapi_be_select_by_instance_name(node->mtn_backend_names[i]))
+ && (be->be_state == BE_STATE_STARTED))
+ {
+ mtn_be_state_change(node->mtn_backend_names[i], SLAPI_BE_STATE_DELETE,
+ node->mtn_be_states[i]);
+ }
+ }
+
+ node->mtn_extension = factory_create_extension(mapping_tree_get_extension_type(), node, NULL);
+
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* utility function to remove a node from the tree of mapping_tree_node
+ */
+static void mtn_remove_node(mapping_tree_node * node)
+{
+ if (node->mtn_parent->mtn_children == node)
+ node->mtn_parent->mtn_children = node->mtn_brother;
+ else
+ {
+ mapping_tree_node * tmp_node = node->mtn_parent->mtn_children;
+ while (tmp_node && (tmp_node->mtn_brother != node))
+ tmp_node = tmp_node->mtn_brother;
+
+ PR_ASSERT(tmp_node != NULL);
+
+ tmp_node->mtn_brother = node->mtn_brother;
+ }
+ node->mtn_brother = NULL;
+}
+
+int mapping_tree_entry_delete_callback(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ int result;
+ mapping_tree_node *node = NULL;
+ Slapi_DN * subtree;
+ int i;
+ int removed = 0;
+
+ mtn_wlock();
+ subtree = get_subtree_from_entry(entryBefore);
+
+ if (subtree == NULL)
+ {
+ /* there is no cn attribute in this entry
+ * -> this is not a mapping tree node
+ * -> nothing to do
+ */
+ result = SLAPI_DSE_CALLBACK_OK;
+ goto done;
+ }
+
+ node = slapi_get_mapping_tree_node_by_dn(subtree);
+ if (node == NULL)
+ {
+ /* should never happen */
+ *returncode = LDAP_OPERATIONS_ERROR;
+ result = SLAPI_DSE_CALLBACK_ERROR;
+ goto done;
+ }
+
+ if (slapi_sdn_compare(subtree, node->mtn_subtree))
+ {
+ /* There is no node associated to this entry
+ * -> nothing to do
+ */
+ result = SLAPI_DSE_CALLBACK_OK;
+ goto done;
+ }
+
+ /* if node has children we must refuse the delete */
+ if (node->mtn_children)
+ {
+ result = SLAPI_DSE_CALLBACK_ERROR;
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ sprintf(returntext, "this node has some children");
+ goto done;
+ }
+
+ /* at this point the node should be different from mapping_tree_root
+ * and therefore have a parent
+ */
+ PR_ASSERT(node->mtn_parent != NULL);
+
+ /* lets get the node out of the mapping tree */
+ mtn_remove_node(node);
+
+ result = SLAPI_DSE_CALLBACK_OK;
+ removed = 1;
+
+done:
+ mtn_unlock();
+ slapi_sdn_free(&subtree);
+ if (SLAPI_DSE_CALLBACK_OK == result && removed)
+ {
+ /* Signal the plugins that a new backend-suffix has been deleted
+ * rq : we have to unlock the mapping tree in that case because
+ * most of the plugins will try to search upon this notification
+ * and should we keep the lock we would end with a dead-lock
+ */
+ for (i = 0; ((i < node->mtn_be_count) && (node->mtn_backend_names) &&
+ (node->mtn_backend_names[i])); i++)
+ {
+ if ((node->mtn_be_states[i] != SLAPI_BE_STATE_DELETE) &&
+ (NULL != slapi_be_select_by_instance_name(
+ node->mtn_backend_names[i])))
+ {
+ mtn_be_state_change(node->mtn_backend_names[i],
+ node->mtn_be_states[i], SLAPI_BE_STATE_DELETE);
+ }
+ }
+
+ /* at this point the node is out of the mapping tree,
+ * we can now free the structure
+ */
+ mtn_free_node(&node);
+ }
+ return result;
+}
+
+/*
+ * Add an internal mapping tree node.
+ */
+static mapping_tree_node *
+add_internal_mapping_tree_node(const char *subtree, Slapi_Backend *be, mapping_tree_node *parent)
+{
+ Slapi_DN *dn;
+ mapping_tree_node *node;
+ backend ** be_list = (backend **) slapi_ch_malloc(sizeof(backend **));
+
+ be_list[0] = be;
+
+ dn = slapi_sdn_new_dn_byval(subtree);
+ node= mapping_tree_node_new(
+ dn,
+ be_list,
+ NULL, /* backend_name */
+ NULL,
+ 1, /* number of backends at this node */
+ 1, /* size of backend list structure */
+ NULL, /* referral */
+ parent,
+ MTN_BACKEND,
+ 1, /* The config node is a private node.
+ * People can't see or change it. */
+ NULL, NULL, NULL);
+ return node;
+}
+
+/*
+ * Description:
+ * Inits the mapping tree. The mapping tree is rooted at a node with
+ * subtree "". Think of this node as the node for the NULL suffix
+ * even though we don't really support it. This function will
+ * create the root node and then consult the DIT for the rest of
+ * the nodes. It will also add the node for cn=config.
+ *
+ * One thing to note... Until the mapping tree is inited. We use
+ * slapi_be_select for all our selection needs. To read in the mapping
+ * tree from the DIT, we need to some internal operations. These
+ * operations need to use slapi_be_select.
+ *
+ * Arguments:
+ * Nothing
+ *
+ * Returns:
+ * Right now it always returns 0. This will most likely change. Right
+ * now, we just log warnings when ever something goes wrong.
+ */
+int
+mapping_tree_init()
+{
+ Slapi_Backend *be;
+ mapping_tree_node *node;
+ /* Create the root of the mapping tree. */
+
+ /* The root of the mapping tree is the NULL suffix. It's always there,
+ * but, because we don't really support it, we won't have an entry in
+ * the dit for the NULL suffix mapping tree node. */
+
+ /* Once we support the NULL suffix we should do something more clever here.
+ * For now will use the current backend we use for "" */
+
+ /* I'm not really sure what the state of the root node should be. The root
+ * node will end up being selected if none of the suffices for the backends
+ * would work with the target. For now when the root node is selected,
+ * the default backend will be returned. (The special case where the
+ * target dn is "" is handled differently.) */
+
+ /* we call this function from a single thread, so it should be ok */
+
+ if(mapping_tree_freed){
+ /* shutdown has been detected */
+ return 0;
+ }
+
+ if (mapping_tree_inited)
+ return 0;
+
+ /* ONREPL - I have moved this up because otherwise we can endup calling this
+ * function recursively */
+
+ mapping_tree_inited = 1;
+
+ slapi_register_supported_control(MTN_CONTROL_USE_ONE_BACKEND_OID,
+ SLAPI_OPERATION_SEARCH);
+ slapi_register_supported_control(MTN_CONTROL_USE_ONE_BACKEND_EXT_OID,
+ SLAPI_OPERATION_SEARCH);
+
+ myLock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "mapping tree");
+
+ be= slapi_be_select_by_instance_name(DSE_BACKEND);
+ mapping_tree_root= add_internal_mapping_tree_node("", be, NULL);
+
+ /* We also need to add the config and schema backends to the mapping tree.
+ * They are special in that users will not know about it's node in the
+ * mapping tree. This is to prevent them from disableing it or
+ * returning a referral for it. */
+ node= add_internal_mapping_tree_node("cn=config", be, mapping_tree_root);
+ mapping_tree_node_add_child(mapping_tree_root, node);
+ node= add_internal_mapping_tree_node("cn=monitor", be, mapping_tree_root);
+ mapping_tree_node_add_child(mapping_tree_root, node);
+ be= slapi_be_select_by_instance_name( "schema-internal" );
+ node= add_internal_mapping_tree_node("cn=schema", be, mapping_tree_root);
+ mapping_tree_node_add_child(mapping_tree_root, node);
+
+ /*
+ * Now we need to look under cn=mapping tree, cn=config to find the rest
+ * of the mapping tree entries.
+ * Builds the mapping tree from entries in the DIT. This function just
+ * calls mapping_tree_node_get_children with the special case for the
+ * root node.
+ */
+ if (mapping_tree_node_get_children(mapping_tree_root, 1))
+ return -1;
+
+ mtn_create_extension(mapping_tree_root);
+
+ /* setup the dse callback functions for the ldbm instance config entry */
+ {
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY,
+ DSE_FLAG_PREOP, MAPPING_TREE_BASE_DN, LDAP_SCOPE_SUBTREE,
+ "(objectclass=nsMappingTree)",
+ mapping_tree_entry_modify_callback, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_ADD,
+ DSE_FLAG_PREOP, MAPPING_TREE_BASE_DN, LDAP_SCOPE_SUBTREE,
+ "(objectclass=nsMappingTree)", mapping_tree_entry_add_callback,
+ NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE,
+ DSE_FLAG_PREOP, MAPPING_TREE_BASE_DN, LDAP_SCOPE_SUBTREE,
+ "(objectclass=nsMappingTree)", mapping_tree_entry_delete_callback,
+ NULL);
+ }
+ return 0;
+}
+
+static void
+mtn_free_node (mapping_tree_node **node)
+{
+ mapping_tree_node *child = (*node)->mtn_children;
+
+ /* free children first */
+ while (child)
+ {
+ mapping_tree_node * tmp_child = child->mtn_brother;
+ mtn_free_node (&child);
+ child = tmp_child;
+ }
+ (*node)->mtn_children = NULL;
+ (*node)->mtn_parent = NULL;
+
+ /* free this node */
+ /* ONREPL - not quite sure which fields should be freed. For now,
+ only freeing fields explicitely allocated in the new_node function */
+ factory_destroy_extension (mapping_tree_get_extension_type(), *node, NULL,
+ &((*node)->mtn_extension));
+
+ slapi_sdn_free(&((*node)->mtn_subtree));
+
+ mtn_free_referral_in_node(*node);
+
+ if ((*node)->mtn_be_count > 0)
+ {
+ if ((*node)->mtn_be)
+ slapi_ch_free((void **) &((*node)->mtn_be));
+
+ if ((*node)->mtn_backend_names)
+ slapi_ch_free((void **) &((*node)->mtn_backend_names));
+
+ if ((*node)->mtn_be_states)
+ slapi_ch_free((void **) &((*node)->mtn_be_states));
+ }
+
+ slapi_ch_free ((void**) node);
+}
+
+/* Description: frees the tree; should be called when the server shuts down
+ */
+void
+mapping_tree_free ()
+{
+ /* unregister dse callbacks */
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, MAPPING_TREE_BASE_DN, LDAP_SCOPE_BASE, "(objectclass=*)", mapping_tree_entry_modify_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, MAPPING_TREE_BASE_DN, LDAP_SCOPE_BASE, "(objectclass=*)", mapping_tree_entry_add_callback);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, MAPPING_TREE_BASE_DN, LDAP_SCOPE_BASE, "(objectclass=*)", mapping_tree_entry_delete_callback);
+
+ /* The state change plugins registered on the mapping tree
+ * should not get any state change information
+ * - unregister all those callbacks
+ */
+ slapi_unregister_backend_state_change_all();
+ /* recursively free tree nodes */
+ mtn_free_node (&mapping_tree_root);
+ mapping_tree_freed = 1;
+}
+
+/* This function returns the first node to parse when a search is done
+ * on a given node in the mapping tree
+ */
+static mapping_tree_node *
+mtn_get_first_node(mapping_tree_node * node, int scope)
+{
+ if (node == NULL)
+ return NULL;
+
+ /* never climb down the tree from base "" */
+ if (node == mapping_tree_root)
+ {
+ return node;
+ }
+
+ if (scope == LDAP_SCOPE_BASE)
+ return node;
+
+ if (scope == LDAP_SCOPE_ONELEVEL)
+ {
+ if (node->mtn_children)
+ return node->mtn_children;
+ else
+ return node;
+ }
+
+ while (node->mtn_children)
+ node = node->mtn_children;
+
+ return node;
+}
+
+int slapi_mtn_get_first_be(mapping_tree_node * node_list,
+ mapping_tree_node ** node, Slapi_PBlock *pb, Slapi_Backend **be,
+ int * be_index, Slapi_Entry **referral, char *errorbuf, int scope)
+{
+ *node = mtn_get_first_node(node_list, scope);
+ if (scope == LDAP_SCOPE_BASE)
+ *be_index = -1;
+ else
+ *be_index = 0;
+
+ return mtn_get_be(*node, pb, be, be_index, referral, errorbuf);
+}
+
+int slapi_mtn_get_next_be(mapping_tree_node * node_list,
+ mapping_tree_node ** node, Slapi_PBlock *pb, Slapi_Backend **be,
+ int * be_index, Slapi_Entry **referral, char *errorbuf, int scope)
+{
+ int rc;
+
+ if (((*node)->mtn_parent == NULL) || /* -> node has been deleted */
+ (scope == LDAP_SCOPE_BASE))
+
+ {
+ *node = NULL;
+ *be = NULL;
+ *referral = NULL;
+ return 0;
+ }
+
+ /* never climb down the tree from the rootDSE */
+ if (node_list == mapping_tree_root)
+ {
+ *node = NULL;
+ *be = NULL;
+ *referral = NULL;
+ return 0;
+ }
+
+ rc = mtn_get_be(*node, pb, be, be_index, referral, errorbuf);
+
+ if (rc != LDAP_SUCCESS)
+ {
+ *node = mtn_get_next_node(*node, node_list, scope);
+ return rc;
+ }
+
+ if ((*be == NULL) && (*referral == NULL))
+ {
+ *node = mtn_get_next_node(*node, node_list, scope);
+ if (*node == NULL)
+ {
+ *be = NULL;
+ return 0;
+ }
+ *be_index = 0;
+ return mtn_get_be(*node, pb, be, be_index, referral, errorbuf);
+ }
+
+ return LDAP_SUCCESS;
+}
+
+/* This function returns the next node to parse when a subtree search is done
+ * on a given node in the mapping tree
+ */
+static mapping_tree_node *
+mtn_get_next_node(mapping_tree_node * node, mapping_tree_node * node_list, int scope)
+{
+ if (scope == LDAP_SCOPE_BASE)
+ return NULL;
+
+ /* if we are back to the top of the subtree searched then we have finished */
+ if (node == node_list)
+ node = NULL;
+
+ else if (node->mtn_brother)
+ {
+ node = node->mtn_brother;
+ if (scope == LDAP_SCOPE_SUBTREE)
+ while (node->mtn_children)
+ node = node->mtn_children;
+ }
+ else
+ node = node->mtn_parent;
+
+ return node;
+}
+
+/* Description :
+ * return 0 if the given entry does not have any child node in the mapping tree
+ * != otherwise
+ *
+ */
+int
+mtn_sdn_has_child(Slapi_DN *target_sdn)
+{
+ mapping_tree_node *node;
+
+ /* algo : get the target node for the given dn
+ * then loop through all its child to check if one of them is below
+ * the target dn
+ */
+ node = slapi_get_mapping_tree_node_by_dn(target_sdn);
+
+ /* if there is no node for this dn then there is no child either */
+ if (node == NULL)
+ return 0;
+
+ node = node->mtn_children;
+ while (node)
+ {
+ if (slapi_sdn_issuffix(node->mtn_subtree, target_sdn))
+ return 1;
+ node = node->mtn_brother;
+ }
+ return 0;
+}
+
+
+/* Description:
+ * Find the backend that would be used to store a dn.
+ */
+Slapi_Backend *slapi_mapping_tree_find_backend_for_sdn(Slapi_DN *sdn)
+{
+ mapping_tree_node *target_node;
+ Slapi_Backend *be;
+ int flag_stop = 0, index;
+ Slapi_PBlock *pb;
+ Slapi_Operation *op;
+
+ mtn_lock();
+ target_node = slapi_get_mapping_tree_node_by_dn(sdn);
+
+ if ((target_node == mapping_tree_root) &&
+ (slapi_sdn_get_ndn_len(sdn) > 0)) {
+ /* couldn't find a matching node */
+ be = defbackend_get_backend();
+ goto done;
+ }
+
+ if ((target_node == NULL) || (target_node->mtn_be_count == 0)) {
+ /* no backend configured for this node */
+ be = NULL;
+ goto done;
+ }
+
+ if (target_node->mtn_be_count == 1) {
+ /* not distributed, so we've already found it */
+ if (target_node->mtn_be[0] == NULL) {
+ target_node->mtn_be[0] = slapi_be_select_by_instance_name(
+ target_node->mtn_backend_names[0]);
+ }
+ be = target_node->mtn_be[0];
+ goto done;
+ }
+
+ /* have to call the distribution plugin */
+ be = defbackend_get_backend();
+ pb = slapi_pblock_new();
+ if (!pb) {
+ goto done;
+ }
+ op = internal_operation_new(SLAPI_OPERATION_ADD, 0);
+ if (!op) {
+ slapi_pblock_destroy(pb);
+ goto done;
+ }
+ operation_set_target_spec(op, sdn);
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ index = mtn_get_be_distributed(pb, target_node, sdn, &flag_stop);
+ slapi_pblock_destroy(pb); /* also frees the operation */
+
+ if (target_node->mtn_be[index] == NULL) {
+ target_node->mtn_be[index] = slapi_be_select_by_instance_name(
+ target_node->mtn_backend_names[index]);
+ }
+ be = target_node->mtn_be[index];
+
+done:
+ mtn_unlock();
+ return be;
+}
+
+/* Check if the target dn is '\0' - the null dn */
+static int sdn_is_nulldn(const Slapi_DN *sdn){
+
+ if(sdn){
+ const char *dn= slapi_sdn_get_ndn(sdn);
+ if(dn && ( '\0' == *dn)){
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Description:
+ * The reason we have a mapping tree. This function selects a backend or
+ * referral to handle a given request. Uses the target of the operation to
+ * find a mapping tree node, then based on the operation type, bind dn, state
+ * of the node, etc. it selects a backend or referral.
+ *
+ * In this initial implementation of the mapping tree, each node can only have
+ * one backend and one referral. Later we should change this so each node has
+ * a list of backends and a list of referrals. Then we should add a modifier
+ * to the state of the node. For example, MTN_MODIFIER_ROUND_ROBIN could be a
+ * modifer on the way a backend or referral is returned from the lists.
+ *
+ * Arguments:
+ * pb is the pblock being used to service the operation.
+ * be is an output param that will be set to the selected backend.
+ * referral is an output param that will be set to the selected referral.
+ * errorbuf is a pointer to a buffer that an error string will be written to
+ * if there is an error. The caller is responsible for passing in a big
+ * enough chunk of memory. BUFSIZ should be fine. If errorbuf is NULL,
+ * no error string is written to it. The string returned in errorbuf
+ * would be a good candidate for sending back to the client to describe the
+ * error.
+ *
+ * Returns:
+ * LDAP_SUCCESS on success, other LDAP result codes if there is a problem.
+ */
+int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry **referral, char *errorbuf)
+{
+ Slapi_DN *target_sdn = NULL;
+ mapping_tree_node *target_node;
+ Slapi_Operation *op;
+ int index;
+ int ret;
+ int scope=LDAP_SCOPE_BASE;
+ int op_type;
+
+
+ if(mapping_tree_freed){
+ /* shutdown detected */
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+
+ if (errorbuf) {
+ errorbuf[0] = '\0';
+ }
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
+ slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
+
+ /* Get the target for this op */
+ target_sdn = operation_get_target_spec (op);
+
+ if(!mapping_tree_inited) {
+ mapping_tree_init();
+ }
+
+ be[0] = NULL;
+ referral[0] = NULL;
+
+ mtn_lock();
+
+ /* Get the mapping tree node that is the best match for the target dn. */
+ target_node = slapi_get_mapping_tree_node_by_dn(target_sdn);
+ if (target_node == NULL)
+ target_node = mapping_tree_root;
+
+ /* The processing of the base scope root DSE search and all other LDAP operations on ""
+ * will be transferred to the internal DSE backend
+ */
+ if( sdn_is_nulldn(target_sdn) &&
+ ((op_type == SLAPI_OPERATION_SEARCH) && (scope == LDAP_SCOPE_BASE) ||
+ (op_type != SLAPI_OPERATION_SEARCH)) ) {
+
+ mtn_unlock();
+ *be = slapi_be_select_by_instance_name(DSE_BACKEND);
+ if(*be != NULL)
+ {
+ ret = LDAP_SUCCESS;
+ slapi_be_Rlock(*be); /* also done inside mtn_get_be() below */
+ } else {
+ ret = LDAP_OPERATIONS_ERROR;
+ }
+ return ret;
+ }
+
+ /* index == -1 is used to specify that we want only one backend not a list
+ * used for BASE search, ADD, DELETE, MODIFY
+ */
+ index = -1;
+ ret = mtn_get_be(target_node, pb, be, &index, referral, errorbuf);
+ slapi_pblock_set(pb, SLAPI_BACKEND_COUNT, &index);
+
+ mtn_unlock();
+
+ /* if a backend was returned, make sure that all non-search operations
+ * fail if the backend is read-only,
+ * or if the whole server is readonly AND backend is public (!private)
+ */
+ if ((ret == LDAP_SUCCESS) && *be &&
+ ((*be)->be_readonly ||
+ (slapi_config_get_readonly() && !slapi_be_private(*be)))) {
+ unsigned long op_type = operation_get_type(op);
+
+ if ((op_type != SLAPI_OPERATION_SEARCH) &&
+ (op_type != SLAPI_OPERATION_COMPARE) &&
+ (op_type != SLAPI_OPERATION_BIND) &&
+ (op_type != SLAPI_OPERATION_UNBIND)) {
+ ret = LDAP_UNWILLING_TO_PERFORM;
+ strcpy(errorbuf, slapi_config_get_readonly() ?
+ "Server is read-only" :
+ "database is read-only");
+ slapi_be_Unlock(*be);
+ *be = NULL;
+ }
+ }
+
+ return ret;
+}
+
+int slapi_mapping_tree_select_all(Slapi_PBlock *pb, Slapi_Backend **be_list,
+ Slapi_Entry **referral_list, char *errorbuf)
+{
+ Slapi_DN *target_sdn = NULL;
+ mapping_tree_node *node_list;
+ mapping_tree_node *node;
+ Slapi_Operation *op;
+ int index;
+ int ret;
+ int ret_code = LDAP_SUCCESS;
+ int be_index = 0 ;
+ int referral_index = 0 ;
+ int be_list_size = 0;
+ int referral_list_size = 0;
+ Slapi_Backend * be;
+ Slapi_Entry * referral;
+ int scope = LDAP_SCOPE_BASE;
+ Slapi_DN sdn;
+ char *base;
+ int flag_partial_result = 0;
+ int op_type;
+
+ if(mapping_tree_freed){
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if (errorbuf) {
+ errorbuf[0] = '\0';
+ }
+
+ /* get the operational parameters */
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &base);
+ slapi_sdn_init_dn_ndn_byref(&sdn, base); /* normalized in opshared.c */
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ target_sdn = operation_get_target_spec (op);
+ slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
+ slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
+
+ if(!mapping_tree_inited){
+ mapping_tree_init();
+ }
+
+ mtn_lock();
+
+ be_list_size = BE_LIST_SIZE;
+ referral_list_size = BE_LIST_SIZE;
+ be_list[0] = NULL;
+ referral_list[0] = NULL;
+
+ /* Get the mapping tree node that is the best match for the target dn. */
+ node_list = slapi_get_mapping_tree_node_by_dn(target_sdn);
+ if (node_list == NULL)
+ node_list = mapping_tree_root;
+
+ if( sdn_is_nulldn(target_sdn) && ( op_type == SLAPI_OPERATION_SEARCH)
+ && (scope == LDAP_SCOPE_BASE) ) {
+ mtn_unlock();
+ be = slapi_be_select_by_instance_name(DSE_BACKEND);
+ if(be != NULL)
+ {
+ be_list[0]=be;
+ be_list[1] = NULL;
+ ret_code = LDAP_SUCCESS;
+ slapi_be_Rlock(be); /* also done inside mtn_get_be() below */
+ } else {
+ ret_code = LDAP_OPERATIONS_ERROR;
+ }
+ return ret_code;
+ }
+
+ ret = slapi_mtn_get_first_be(node_list, &node, pb, &be, &index, &referral, errorbuf, scope);
+
+ while ((node) &&(index < BE_LIST_SIZE))
+ {
+ if (ret != LDAP_SUCCESS)
+ {
+ /* flag we have problems at least on part of the tree */
+ flag_partial_result = 1;
+ }
+ else if ( ( ((!slapi_sdn_issuffix(&sdn, slapi_mtn_get_dn(node))
+ && !slapi_sdn_issuffix(slapi_mtn_get_dn(node), &sdn)))
+ || ((node_list == mapping_tree_root) && node->mtn_private
+ && (scope != LDAP_SCOPE_BASE)) )
+ && (!be || strncmp(be->be_name, "default", 8)))
+ {
+ if (be)
+ {
+ /* wrong backend or referall, ignore it */
+ slapi_log_error(SLAPI_LOG_ARGS, NULL,
+ "mapping tree release backend : %s\n",
+ slapi_be_get_name(be));
+ slapi_be_Unlock(be);
+ }
+ }
+ else
+ {
+ if (be)
+ {
+ be_list[be_index++]=be;
+ }
+
+ if (referral)
+ {
+ referral_list[referral_index++] = referral;
+
+ /* if we hit a referral at the base of the search
+ * we must return a REFERRAL error with only this referral
+ * all backend or referral below this node are ignored
+ */
+ if (slapi_sdn_issuffix(target_sdn, slapi_mtn_get_dn(node)))
+ {
+ ret_code = LDAP_REFERRAL;
+ break; /* get out of the while loop */
+ }
+ }
+ }
+
+ ret = slapi_mtn_get_next_be(node_list, &node, pb, &be, &index,
+ &referral, errorbuf, scope);
+ }
+ mtn_unlock();
+ slapi_sdn_done(&sdn);
+ be_list[be_index] = NULL;
+ referral_list[referral_index] = NULL;
+
+ if (flag_partial_result)
+ {
+ /* if no node in active has been found -> return LDAP_OPERATIONS_ERROR
+ * but if only part of the nodes are disabled
+ * do not return an error to allow directory browser to work OK
+ * in the console
+ * It would be better to return a meaningfull error
+ * unfortunately LDAP_PARTIAL_RESULTS is not usable because
+ * it is already used for V2 referrals
+ * leave no error for now and fix this later
+ */
+ if ((be_index == 0) && (referral_index == 0))
+ return LDAP_OPERATIONS_ERROR;
+ else
+ return ret_code;
+ }
+ else
+ return ret_code;
+}
+
+void slapi_mapping_tree_free_all(Slapi_Backend **be_list, Slapi_Entry **referral_list)
+{
+ int index = 0;
+
+ /* go through the list of all backends that was used for the operation
+ * and unlock them
+ * go through the list of referrals and free them
+ * free the two tables that were used to store the two lists
+ */
+ if (be_list[index] != NULL)
+ {
+ Slapi_Backend * be;
+
+ while (be = be_list[index++])
+ {
+ slapi_log_error(SLAPI_LOG_ARGS, NULL, "mapping tree release backend : %s\n", slapi_be_get_name(be));
+ slapi_be_Unlock(be);
+ }
+ }
+
+ index = 0;
+ if (referral_list[index] != NULL)
+ {
+ Slapi_Entry * referral;
+ while (referral = referral_list[index++])
+ {
+ slapi_entry_free(referral);
+ }
+ }
+}
+
+
+/* same as slapi_mapping_tree_select() but will also check that the supplied
+ * newdn is in the same backend
+ */
+int slapi_mapping_tree_select_and_check(Slapi_PBlock *pb,char *newdn, Slapi_Backend **be, Slapi_Entry **referral, char *errorbuf)
+{
+ Slapi_DN *target_sdn = NULL;
+ Slapi_DN dn_newdn;
+ Slapi_Backend * new_be = NULL;
+ Slapi_Entry * new_referral = NULL;
+ mapping_tree_node *target_node;
+ int index;
+ Slapi_Operation *op;
+ int ret;
+
+ if(mapping_tree_freed){
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ slapi_sdn_init(&dn_newdn);
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ target_sdn = operation_get_target_spec (op);
+
+ mtn_lock();
+
+ * referral = NULL;
+ ret = slapi_mapping_tree_select(pb, be, referral, errorbuf);
+ if (ret)
+ goto unlock_and_return;
+
+ slapi_sdn_init_dn_byref(&dn_newdn,newdn);
+ target_node = slapi_get_mapping_tree_node_by_dn(&dn_newdn);
+ if (target_node == NULL)
+ target_node = mapping_tree_root;
+ index = -1;
+ ret = mtn_get_be(target_node, pb, &new_be, &index, &new_referral, errorbuf);
+ if (ret)
+ goto unlock_and_return;
+
+ if ((*be) && ((*be != new_be) || mtn_sdn_has_child(target_sdn)))
+ {
+ ret = LDAP_UNWILLING_TO_PERFORM;
+ sprintf(errorbuf, "Cannot move entries accross backends\n");
+ goto unlock_and_return;
+ }
+
+unlock_and_return:
+ slapi_sdn_done(&dn_newdn);
+
+ if (new_be)
+ slapi_be_Unlock(new_be);
+
+ if (new_referral)
+ slapi_entry_free(new_referral);
+
+ if (ret != LDAP_SUCCESS)
+ {
+ if (*be)
+ {
+ slapi_be_Unlock(*be);
+ *be = NULL;
+ }
+ if (*referral)
+ {
+ slapi_entry_free(*referral);
+ *referral = NULL;
+ }
+ }
+
+ mtn_unlock();
+
+ return ret;
+}
+
+/*
+ * allow to solve the distribution problem when several back-ends are defined
+ */
+static int
+mtn_get_be_distributed(Slapi_PBlock *pb, mapping_tree_node * target_node,
+ Slapi_DN *target_sdn, int * flag_stop)
+{
+ int index;
+ *flag_stop = 0;
+
+ if (target_node->mtn_dstr_plg)
+ {
+ index = (*target_node->mtn_dstr_plg)(pb, target_sdn,
+ target_node->mtn_backend_names, target_node->mtn_be_count,
+ target_node->mtn_subtree, target_node->mtn_be_states);
+
+ if (index == SLAPI_BE_ALL_BACKENDS)
+ {
+ /* special value to indicate all backends must be scanned
+ * start with first one
+ */
+ index = 0;
+ }
+ /* paranoid check, never trust another programmer */
+ else if ((index >= target_node->mtn_be_count) || (index < 0))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: distribution plugin returned wrong backend"
+ " : %d for entry %s at node %s\n",
+ index, slapi_sdn_get_ndn(target_sdn),
+ slapi_sdn_get_ndn(target_node->mtn_subtree));
+ index = 0;
+ }
+ else
+ {
+ /* only one backend to scan
+ * set flag_stop to indicate we must stop the search here
+ */
+ *flag_stop = 1;
+ }
+ }
+ else
+ {
+ /* there is several backends but no distribution function
+ * return the first backend
+ */
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: distribution plugin not configured at node : %s\n",
+ slapi_sdn_get_ndn(target_node->mtn_subtree), 0, 0);
+ index = 0;
+ }
+
+ return index;
+}
+/*
+ * this function is in charge of choosing the right backend for a given
+ * mapping tree node
+ * In case when several backends are used it is in charge of the spanning the
+ * request among all the backend or choosing the only backend to use depending
+ * on the type and scope of the LDAP operation
+ *
+ * index == -1 is used to specify that we want only the one best backend
+ * used for BASE search, ADD, DELETE, MODIFY
+ * index >0 means we are doing a SUBTREE or ONELEVEL search and that the be in
+ * that position must be returned
+ */
+static int mtn_get_be(mapping_tree_node *target_node, Slapi_PBlock *pb,
+ Slapi_Backend **be, int * index, Slapi_Entry **referral, char *errorbuf)
+{
+ Slapi_DN *target_sdn;
+ Slapi_Operation *op;
+ int result = LDAP_SUCCESS;
+ int override_referral = 0;
+ unsigned long op_type;
+ int flag_stop = 0;
+ struct slapi_componentid *cid = NULL;
+
+ if(mapping_tree_freed){
+ /* shut down detected */
+ return LDAP_OPERATIONS_ERROR;
+ }
+ /* Get usefull stuff like the type of operation, target dn */
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op_type = operation_get_type(op);
+ target_sdn = operation_get_target_spec (op);
+
+ if (target_node->mtn_state == MTN_DISABLED) {
+ if (errorbuf)
+ sprintf(errorbuf,
+ "Warning: Operation attempted on a disabled node : %s\n",
+ slapi_sdn_get_dn(target_node->mtn_subtree));
+ result = LDAP_OPERATIONS_ERROR;
+ return result;
+ }
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &cid);
+
+ override_referral =
+ ((cid != NULL) && (pw_get_componentID() != NULL) && (pw_get_componentID() == cid)) ||
+ operation_is_flag_set(op, OP_FLAG_LEGACY_REPLICATION_DN) || /* 4.0 lgacy update */
+ operation_is_flag_set(op, OP_FLAG_REPLICATED) || /* 5.0 replication update */
+ operation_is_flag_set(op, OP_FLAG_TOMBSTONE_ENTRY); /* 5.1 fix to enable tombstone delete on a R-O consumer */
+ if ((target_node->mtn_state == MTN_BACKEND) ||
+ (target_node->mtn_state == MTN_CONTAINER ) ||
+ ((target_node->mtn_state == MTN_REFERRAL_ON_UPDATE) &&
+ ((SLAPI_OPERATION_SEARCH == op_type)||(SLAPI_OPERATION_BIND == op_type) ||
+ (SLAPI_OPERATION_UNBIND == op_type) || (SLAPI_OPERATION_COMPARE == op_type))) ||
+ override_referral) {
+ if ((target_node == mapping_tree_root) ){
+ /* If we got here, then we couldn't find a matching node
+ * for the target. We'll use the default backend. Once
+ * we fully support the NULL suffix, we should do something more
+ * clever here.
+ */
+ *be = defbackend_get_backend();
+
+ } else {
+ if ((*index == -1) || (*index == 0)) {
+ /* In this case, we are doing
+ * a READ, ADD, MODIDY or DELETE on a single entry
+ * or we are starting a SEARCH
+ * if there is several possible backend we want to apply
+ * the distribution plugin
+ */
+ if (target_node->mtn_be_count <= 1) {
+ /* there is only one backend no choice possible */
+ *index = 0;
+ } else {
+ *index = mtn_get_be_distributed(pb, target_node,
+ target_sdn, &flag_stop);
+ }
+ }
+
+ if ((*index == -2) || (*index >= target_node->mtn_be_count)) {
+ /* we have already returned all backends -> return NULL */
+ *be = NULL;
+ *referral = NULL;
+ } else {
+ /* return next backend, increment index */
+ *be = target_node->mtn_be[*index];
+ if(*be==NULL) {
+ if (target_node->mtn_be_states[*index] == SLAPI_BE_STATE_DELETE) {
+ /* This MTN is being deleted */
+ *be = defbackend_get_backend();
+ } else {
+ /* This MTN has not been linked to its backend
+ * instance yet. */
+ target_node->mtn_be[*index] =
+ slapi_be_select_by_instance_name(
+ target_node->mtn_backend_names[*index]);
+ *be = target_node->mtn_be[*index];
+ if(*be==NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Warning: Mapping tree node entry for %s point to "
+ "an unknown backend : %s\n",
+ slapi_sdn_get_dn(target_node->mtn_subtree),
+ target_node->mtn_backend_names[*index], 0);
+ /* Well there's still not backend instance for
+ * this MTN, so let's have the default backend
+ * deal with this.
+ */
+ *be = defbackend_get_backend();
+ }
+ }
+ }
+ if ((target_node->mtn_be_states) &&
+ (target_node->mtn_be_states[*index] == SLAPI_BE_STATE_OFFLINE)) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "Warning: Operation attempted on backend in OFFLINE "
+ "state : %s\n",
+ target_node->mtn_backend_names[*index], 0, 0);
+ result = LDAP_OPERATIONS_ERROR;
+ *be = defbackend_get_backend();
+ }
+ if (flag_stop)
+ *index = -2;
+ else
+ (*index)++;
+ }
+ }
+ *referral = NULL;
+ } else {
+ /* otherwise we must return the referral
+ * if ((target_node->mtn_state == MTN_REFERRAL) ||
+ * (target_node->mtn_state == MTN_REFERRAL_ON_UPDATE)) */
+
+ if (*index > 0) {
+ /* we have already returned this referral
+ * send back NULL to jump to next node
+ */
+ *be = NULL;
+ *referral = NULL;
+ result = LDAP_SUCCESS;
+ } else {
+ /* first time we hit this referral -> return it
+ * set the be variable to NULL to indicate we use a referral
+ * and increment index to rememeber later that we already
+ * returned this referral
+ */
+ *be = NULL;
+ *referral = (target_node->mtn_referral_entry ?
+ slapi_entry_dup(target_node->mtn_referral_entry) :
+ NULL);
+ (*index)++;
+ if (NULL == *referral) {
+ if (errorbuf) {
+ sprintf(errorbuf,
+ "Mapping tree node for %s is set to return a referral,"
+ " but no referral is configured for it",
+ slapi_sdn_get_ndn(target_node->mtn_subtree));
+ }
+ result = LDAP_OPERATIONS_ERROR;
+ } else {
+ result = LDAP_SUCCESS;
+ }
+ }
+ }
+
+ if (result == LDAP_SUCCESS) {
+ if (*be) {
+ slapi_log_error(SLAPI_LOG_ARGS, NULL,
+ "mapping tree selected backend : %s\n",
+ slapi_be_get_name(*be));
+ slapi_be_Rlock(*be);
+ } else if (*referral) {
+ slapi_log_error(SLAPI_LOG_ARGS, NULL,
+ "mapping tree selected referral at node : %s\n",
+ slapi_sdn_get_dn(target_node->mtn_subtree));
+ }
+ }
+
+ return result;
+}
+
+/*
+ * Description:
+ * Finds the best match for the targetdn from the children of parent. Uses
+ * slapi_sdn_issuffix and the number of rdns to pick the best node.
+ *
+ * Arguments:
+ * parent is a pointer to a mapping tree node.
+ * targetdn is the dn we're trying to find the best match for.
+ *
+ * Returns:
+ * A pointer to the child of parent that best matches the targetdn. NULL
+ * if there were no good matches.
+ */
+static mapping_tree_node *best_matching_child(mapping_tree_node *parent,
+ const Slapi_DN *targetdn)
+{
+ mapping_tree_node *highest_match_node = NULL;
+ mapping_tree_node *current;
+
+ if(mapping_tree_freed){
+ /* shutdown detected */
+ return NULL;
+ }
+ for (current = parent->mtn_children; current;
+ current = current->mtn_brother) {
+ if (slapi_sdn_issuffix(targetdn, current->mtn_subtree)) {
+ if ( (highest_match_node == NULL) ||
+ ((slapi_sdn_get_ndn_len(current->mtn_subtree)) >
+ slapi_sdn_get_ndn_len(highest_match_node->mtn_subtree)) ) {
+ highest_match_node = current;
+ }
+ }
+ }
+
+ return highest_match_node;
+}
+
+
+/*
+ * look for the exact mapping tree node corresponding to a given entry dn
+ */
+static mapping_tree_node *
+mtn_get_mapping_tree_node_by_entry(mapping_tree_node* node, const Slapi_DN *dn)
+{
+ mapping_tree_node *found_node = NULL;
+
+ if(mapping_tree_freed){
+ /* shutdown detected */
+ return NULL;
+ }
+
+ if (slapi_sdn_compare(node->mtn_subtree, dn) == 0)
+ {
+ return node;
+ }
+
+ if (node->mtn_children)
+ {
+ found_node = mtn_get_mapping_tree_node_by_entry(node->mtn_children, dn);
+ if (found_node)
+ return found_node;
+ }
+
+ if (node->mtn_brother)
+ {
+ found_node = mtn_get_mapping_tree_node_by_entry(node->mtn_brother, dn);
+ }
+ return found_node;
+}
+/*
+ * Description:
+ * Gets a mapping tree node that best matches the given dn. If the root
+ * node is returned and the target dn is not "", then no match was found.
+ *
+ * Arguments:
+ * dn is the target of the search.
+ *
+ * Returns:
+ * The best matching node for the dn
+ * if nothing match, NULL is returned
+ */
+mapping_tree_node *
+slapi_get_mapping_tree_node_by_dn(const Slapi_DN *dn)
+{
+ mapping_tree_node *current_best_match = mapping_tree_root;
+ mapping_tree_node *next_best_match = mapping_tree_root;
+
+ if(mapping_tree_freed){
+ /* shutdown detected */
+ return NULL;
+ }
+ /* Handle special case where the dn is "" and the mapping root
+ * does not belong to the frontend-internal (DSE_BACKEND);
+ * it has been assigned to a different backend.
+ * e.g: a container backend
+ */
+ if ( sdn_is_nulldn(dn) && mapping_tree_root && mapping_tree_root->mtn_be[0] &&
+ mapping_tree_root->mtn_be[0] != slapi_be_select_by_instance_name(DSE_BACKEND)) {
+ return( mapping_tree_root );
+ }
+
+ /* Start at the root and walk down the tree to find the best match. */
+ while (next_best_match) {
+ current_best_match = next_best_match;
+ next_best_match = best_matching_child(current_best_match, dn);
+ }
+
+ if (current_best_match == mapping_tree_root)
+ return NULL;
+ else
+ return current_best_match;
+}
+
+
+static mapping_tree_node *
+get_mapping_tree_node_by_name(mapping_tree_node * node, char * be_name)
+{
+ int i;
+ mapping_tree_node *found_node = NULL;
+
+ if(mapping_tree_freed){
+ /* shutdown detected */
+ return NULL;
+ }
+ /* now search the backend in this node */
+ i = 0;
+ while ( ( i < node->mtn_be_count) &&
+ (node->mtn_backend_names) &&
+ (node->mtn_backend_names[i]) &&
+ (strcmp(node->mtn_backend_names[i],be_name)))
+ {
+ i++;
+ }
+
+ if ((i < node->mtn_be_count) &&
+ (node->mtn_backend_names != NULL) &&
+ (node->mtn_backend_names[i] != NULL))
+ {
+ return node;
+ }
+
+ if (node->mtn_children)
+ {
+ found_node = get_mapping_tree_node_by_name(node->mtn_children, be_name);
+ if (found_node)
+ return found_node;
+ }
+
+ if (node->mtn_brother)
+ {
+ found_node = get_mapping_tree_node_by_name(node->mtn_brother, be_name);
+ }
+ return found_node;
+}
+
+/*
+ * Description: construct the dn of the configuration entry for the
+ * node originated at the root. The function just constructs
+ * the dn it does not verify that the entry actually exist.
+ * The format of the dn is
+ * cn="<normalized root>",cn=mapping tree,cn=config
+ *
+ * Arguments: root - root of the node
+ *
+ * Returns: dn of the configuration entry if successful and null otherwise.
+ */
+char*
+slapi_get_mapping_tree_node_configdn (const Slapi_DN *root)
+{
+ int len;
+ char *dn;
+
+ if(mapping_tree_freed){
+ /* shutdown detected */
+ return NULL;
+ }
+ if (root == NULL)
+ return NULL;
+
+ len = strlen (slapi_sdn_get_dn(root)) + strlen (MAPPING_TREE_BASE_DN) + 7; /* cn= + " + " + , + \0 */
+ dn = (char*)slapi_ch_malloc (len);
+ sprintf (dn, "cn=\"%s\",%s", slapi_sdn_get_dn(root), MAPPING_TREE_BASE_DN);
+
+ return dn;
+}
+
+/*
+ * Description: this function returns root of the subtree to which the node applies
+ *
+ * Arguments: node - mapping tree node
+ *
+ * Returns: root of the subtree if function is successful and NULL otherwise.
+ */
+
+const Slapi_DN* slapi_get_mapping_tree_node_root (const mapping_tree_node *node)
+{
+ if (node)
+ return node->mtn_subtree;
+ else
+ return NULL;
+}
+
+/* GB : there is a potential problems with this function
+ * when several backends are used
+ */
+PRBool slapi_mapping_tree_node_is_set (const mapping_tree_node *node, PRUint32 flag)
+{
+ if (flag & SLAPI_MTN_LOCAL)
+ return PR_TRUE;
+
+ if (flag & SLAPI_MTN_PRIVATE)
+ return ((node->mtn_be_count>0) && node->mtn_be && node->mtn_be[0] && node->mtn_private);
+
+ if (flag & SLAPI_MTN_READONLY)
+ return ((node->mtn_be_count>0) && node->mtn_be && node->mtn_be[0] && node->mtn_be[0]->be_readonly);
+
+ return PR_FALSE;
+}
+
+/*
+ * Description: this function returns root of the subtree to which the node applies
+ *
+ * Arguments: node
+ *
+ * Returns: dn of the parent of mapping tree node configuration entry.
+ */
+
+const char* slapi_get_mapping_tree_config_root ()
+{
+ return MAPPING_TREE_BASE_DN;
+}
+
+/*
+ * slapi_be_select() finds the backend that should be used to service dn.
+ * If no backend with an appropriate suffix is configured, the default backend
+ * is returned. This function never returns NULL.
+ */
+Slapi_Backend *
+slapi_be_select( const Slapi_DN *sdn ) /* JCM - The name of this should change??? */
+{
+ Slapi_Backend *be;
+ mapping_tree_node *node= slapi_get_mapping_tree_node_by_dn(sdn);
+ if(node!=NULL)
+ be= node->mtn_be[0];
+ else
+ be = NULL;
+
+ if(be==NULL)
+ be= defbackend_get_backend();
+
+ return be;
+}
+
+/* Check if the dn targets an internal reserved backends */
+int
+slapi_on_internal_backends(const Slapi_DN *sdn)
+{
+ char *backend_names[] = {"frontend-internal", "schema-internal"};
+ int internal = 1;
+ int numOfInternalBackends = 2;
+ int count;
+
+ Slapi_Backend *internal_be;
+
+ Slapi_Backend *be = slapi_be_select(sdn);
+
+
+ for (count=0; count < numOfInternalBackends ; ++count){
+ /* the internal backends are always in the begining of the list
+ * so should not be very inefficient
+ */
+ internal_be = slapi_be_select_by_instance_name(backend_names[count]);
+ if(be == internal_be){
+ return internal;
+ }
+ }
+ return 0;
+}
+
+/* Some of the operations are not allowed from the plugins
+ * but default to specialized use of those operations
+ * e.g rootDse search, NetscapeRoot searches
+ * cn=config, cn=schema etc
+ */
+
+int slapi_op_reserved(Slapi_PBlock *pb)
+{
+ int scope=LDAP_SCOPE_BASE;
+ int reservedOp=0;
+ int op_type;
+ Slapi_Operation *op = NULL;
+ Slapi_DN *target_sdn=NULL;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ slapi_pblock_get(pb, SLAPI_OPERATION_TYPE, &op_type);
+ /* Get the target for this op */
+ target_sdn = operation_get_target_spec (op);
+
+ if( op_type == SLAPI_OPERATION_SEARCH){
+ slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
+ if( sdn_is_nulldn(target_sdn) && (scope == LDAP_SCOPE_BASE) ){
+ reservedOp = 1;
+ }
+
+ }
+
+ if(slapi_on_internal_backends(target_sdn)){
+ reservedOp = 1;
+ }
+
+ return reservedOp;
+}
+
+
+
+/*
+ * Returns the name of the Backend that contains specified DN,
+ * if only one matches. Otherwise returns NULL
+ * The name is pointing to the mapping tree structure
+ * and should not be altered.
+ */
+const char *
+slapi_mtn_get_backend_name( const Slapi_DN *sdn)
+{
+ mapping_tree_node *node= slapi_get_mapping_tree_node_by_dn(sdn);
+ if ((node != NULL) &&
+ (node->mtn_be_count == 1) &&
+ (node->mtn_backend_names != NULL))
+ /* There's only one name, return it */
+ return node->mtn_backend_names[0];
+ else
+ return NULL;
+}
+
+/* Check if the backend that contains specified DN exists */
+int
+slapi_be_exist(const Slapi_DN *sdn) /* JCM - The name of this should change??? */
+{
+ Slapi_Backend *def_be = defbackend_get_backend();
+ Slapi_Backend *be = slapi_be_select (sdn);
+
+ return (be != def_be);
+}
+
+/* The two following functions can be used to
+ * parse the list of the root suffix of the DIT
+ * Using
+ */
+Slapi_DN *
+slapi_get_first_suffix(void ** node, int show_private)
+{
+ mapping_tree_node * first_node = mapping_tree_root->mtn_children;
+ *node = (void * ) first_node ;
+ while (first_node && (first_node->mtn_private && (show_private == 0)))
+ first_node = first_node->mtn_brother;
+ return (first_node ? first_node->mtn_subtree : NULL);
+}
+
+Slapi_DN *
+slapi_get_next_suffix(void ** node, int show_private)
+{
+ mapping_tree_node * next_node = *node;
+
+ if (next_node == NULL)
+ return NULL;
+
+ next_node = next_node->mtn_brother;
+ while (next_node && (next_node->mtn_private && (show_private == 0)))
+ next_node = next_node->mtn_brother;
+ *node = next_node;
+ return (next_node ? next_node->mtn_subtree : NULL);
+}
+
+/* check if a suffix is a root of the DIT
+ * return 1 if yes, 0 if no
+ */
+int slapi_is_root_suffix(Slapi_DN * dn)
+{
+ void * node;
+ Slapi_DN * suffix = slapi_get_first_suffix (&node, 1);
+
+ while (suffix)
+ {
+ if ( slapi_sdn_compare(dn, suffix) == 0 )
+ return 1;
+ suffix = slapi_get_next_suffix(&node, 1);
+ }
+ return 0 ;
+}
+
+/*
+ * set referrals for the node
+ * notes :
+ * - referral is consumed by this function
+ * - node must exist before calling this function
+ * - mapping tree node state is not changed by this function
+ */
+int
+slapi_mtn_set_referral(const Slapi_DN *sdn, char ** referral)
+{
+ Slapi_PBlock pb;
+ Slapi_Mods smods;
+ int rc = LDAP_SUCCESS,i = 0, j = 0;
+ char * node_dn;
+ char **values = NULL;
+ int do_modify = 0;
+
+ slapi_mods_init (&smods, 0);
+ node_dn = slapi_get_mapping_tree_node_configdn(sdn);
+ if(!node_dn){
+ /* shutdown has been detected */
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ((referral == NULL) || (referral[0] == NULL))
+ {
+ /* NULL referral means we want to delete existing referral
+ */
+ slapi_mods_add(&smods, LDAP_MOD_DELETE, "nsslapd-referral", 0, NULL);
+ do_modify = 1;
+ }
+ else
+ {
+ int changes = 1;
+ int referralCount = 0;
+
+ for(; referral[referralCount]; referralCount++);
+ if ( (values = slapi_mtn_get_referral(sdn)) != NULL )
+ {
+ /* Check if there are differences between current values and values to be set */
+
+ for (i=0; values[i]; i++);
+ if (i == referralCount) {
+ changes = 0;
+ for (i=0;values[i];i++){
+ int found = 0;
+ for (j=0;referral[j];j++){
+ if (strcmp(values[i], referral[j]) == 0){
+ found = 1;
+ break;
+ }
+ }
+ if (!found) {
+ changes = 1;
+ break;
+ }
+ }
+ }
+
+ i=0;
+ while(values[i])
+ slapi_ch_free((void**)&values[i++]);
+ slapi_ch_free((void**)&values);
+
+ }
+ if (changes){
+ Slapi_Value *val;
+ Slapi_Value ** svals = NULL;
+
+ do_modify = 1;
+ for (j =0; referral[j];j++) {
+ val = slapi_value_new_string(referral[j]);
+ valuearray_add_value(&svals, val);
+ slapi_value_free(&val);
+ }
+ slapi_mods_add_mod_values(&smods, LDAP_MOD_REPLACE, "nsslapd-referral", svals);
+ valuearray_free(&svals);
+ }
+ }
+
+ if ( do_modify )
+ {
+ pblock_init (&pb);
+ slapi_modify_internal_set_pb (&pb, node_dn,
+ slapi_mods_get_ldapmods_byref(&smods), NULL,
+ NULL, (void *) plugin_get_default_component_id(), 0);
+ slapi_modify_internal_pb (&pb);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ pblock_done(&pb);
+ }
+
+ slapi_mods_done(&smods);
+ slapi_ch_free((void **) &node_dn);
+
+ return rc;
+}
+
+/*
+ * Change the state of a mapping tree node entry
+ * notes :
+ * - sdn argument is the dn of the subtree of the DIT managed by this node
+ * not the dn of the mapping tree entry
+ * - mapping tree node must exist before calling this function
+ */
+int
+slapi_mtn_set_state(const Slapi_DN *sdn, char *state)
+{
+ Slapi_PBlock pb;
+ Slapi_Mods smods;
+ int rc = LDAP_SUCCESS;
+ char * node_dn;
+ char * value;
+
+ node_dn = slapi_get_mapping_tree_node_configdn(sdn);
+ if(!node_dn){
+ /* shutdown has been detected */
+ return LDAP_OPERATIONS_ERROR;
+ }
+
+ if ( (value = slapi_mtn_get_state(sdn)) != NULL )
+ {
+ if ( strcasecmp(value, state) == 0 )
+ {
+ /* Same state, don't change anything */
+ slapi_ch_free((void **) &value);
+ slapi_ch_free((void **) &node_dn);
+ return rc;
+ }
+ }
+
+ /* Otherwise, means that the state has changed, modify it */
+ slapi_mods_init (&smods, 1);
+ slapi_mods_add(&smods, LDAP_MOD_REPLACE, "nsslapd-state", strlen(state), state);
+ pblock_init (&pb);
+ slapi_modify_internal_set_pb (&pb, node_dn,
+ slapi_mods_get_ldapmods_byref(&smods), NULL,
+ NULL, (void *) plugin_get_default_component_id(), 0);
+ slapi_modify_internal_pb (&pb);
+
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+
+ slapi_mods_done(&smods);
+ slapi_ch_free((void **) &node_dn);
+ pblock_done(&pb);
+ slapi_ch_free((void **) &value);
+
+ return rc;
+}
+
+/*
+ returns a copy of the attr - the caller must slapi_attr_free it
+*/
+Slapi_Attr *
+mtn_get_attr(char* node_dn, char * type)
+{
+ Slapi_PBlock pb;
+ int res = 0;
+ Slapi_Entry **entries = NULL;
+ Slapi_Attr *attr = NULL;
+ Slapi_Attr *ret_attr = NULL;
+ char **attrs = NULL;
+
+ attrs = (char **)slapi_ch_calloc(2, sizeof(char *));
+ attrs[0] = slapi_ch_strdup(type);
+ pblock_init(&pb);
+ slapi_search_internal_set_pb(&pb, node_dn, LDAP_SCOPE_BASE,
+ "objectclass=nsMappingTree", attrs, 0, NULL, NULL,
+ (void *) plugin_get_default_component_id(), 0);
+ slapi_search_internal_pb(&pb);
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if (res != LDAP_SUCCESS) {
+ goto done;
+ }
+
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries || NULL == entries[0]) {
+ goto done;
+ }
+
+ /* always at most one entry entries[0] */
+ res = slapi_entry_attr_find(entries[0], type, &attr);
+ if (res == 0)
+ /* we need to make a copy here so we can free the search results */
+ ret_attr = slapi_attr_dup(attr);
+
+ slapi_free_search_results_internal(&pb);
+
+done:
+ slapi_ch_free((void **)&attrs[0]);
+ slapi_ch_free((void **)&attrs);
+ pblock_done(&pb);
+ return ret_attr;
+}
+
+/*
+ * Get the referral associated to the mapping tree node entry
+ * notes :
+ * - sdn argument is the dn of the subtree of the DIT managed by this node
+ * not the dn of the mapping tree entry
+ * - return NULL if no referral
+ * - caller is reponsible for freeing the returned referrals
+ */
+char **
+slapi_mtn_get_referral(const Slapi_DN *sdn)
+{
+ int i, hint, nb;
+ char * node_dn;
+ Slapi_Attr *attr;
+ char ** referral = NULL;
+ Slapi_Value *val = NULL;
+
+ node_dn = slapi_get_mapping_tree_node_configdn(sdn);
+ if(!node_dn){
+ /* shutdown has been detected */
+ return NULL;
+ }
+
+ attr = mtn_get_attr(node_dn, "nsslapd-referral");
+
+ if (attr)
+ {
+ /* if there are some referrals set in the entry build a list
+ * to be returned to the caller
+ */
+ slapi_attr_get_numvalues(attr, &nb);
+ referral = (char**) slapi_ch_malloc(sizeof(char*) * (nb+1));
+ hint = slapi_attr_first_value(attr, &val);
+ i = 0;
+
+ while (val)
+ {
+ referral[i++] = slapi_ch_strdup(slapi_value_get_string(val));
+ hint = slapi_attr_next_value(attr, hint, &val);
+ }
+ referral[i] = NULL;
+ slapi_attr_free(&attr);
+ }
+
+ slapi_ch_free((void **) &node_dn);
+ return referral;
+}
+
+/*
+ * Get the state of a mapping tree node entry
+ * notes :
+ * - sdn argument is the dn of the subtree of the DIT managed by this node
+ * not the dn of the mapping tree entry
+ * - the state is return in a newly allocated string that must be freed by
+ * the caller
+ */
+char *
+slapi_mtn_get_state(const Slapi_DN *sdn)
+{
+ int hint;
+ char * node_dn;
+ Slapi_Attr *attr;
+ char * state = NULL;
+ Slapi_Value *val = NULL;
+
+ node_dn = slapi_get_mapping_tree_node_configdn(sdn);
+ if(!node_dn){
+ /* shutdown has been detected */
+ return NULL;
+ }
+
+ attr = mtn_get_attr(node_dn, "nsslapd-state");
+
+ if (attr)
+ {
+ /* entry state was found */
+ hint = slapi_attr_first_value(attr, &val);
+ state = slapi_ch_strdup(slapi_value_get_string(val));
+ slapi_attr_free(&attr);
+ }
+
+ slapi_ch_free((void **) &node_dn);
+ return state;
+}
+
+static void
+mtn_internal_be_set_state(Slapi_Backend *be, int state)
+{
+ mapping_tree_node * node;
+ char * be_name;
+ int i;
+ int change_callback = 0;
+ int old_state;
+
+ mtn_wlock();
+ be_name = slapi_ch_strdup(slapi_be_get_name(be));
+ node = get_mapping_tree_node_by_name(mapping_tree_root, be_name);
+ if (node == NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "Warning: backend %s is not declared in mapping tree\n",
+ be_name, 0 ,0);
+ goto done;
+ }
+
+
+ /* now search the backend in this node */
+ i = 0;
+ while ( (i < node->mtn_be_count) &&
+ (node->mtn_backend_names) &&
+ (node->mtn_backend_names[i]) &&
+ (strcmp(node->mtn_backend_names[i],be_name)))
+ {
+ i++;
+ }
+
+ if ( (i >= node->mtn_be_count) || (node->mtn_backend_names == NULL) ||
+ (node->mtn_backend_names[i] == NULL) )
+ {
+ /* backend is not declared in the mapping tree node
+ * print out a warning
+ */
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "Warning: backend %s is not declared in mapping node entry\n",
+ be_name, 0 ,0);
+ goto done;
+ }
+
+ change_callback = 1;
+ old_state = node->mtn_be_states[i];
+
+ /* OK we found the backend at last, now do the real job: set the state */
+ switch (state)
+ {
+ case SLAPI_BE_STATE_OFFLINE:
+ node->mtn_be[i] = be;
+ node->mtn_be_states[i] = SLAPI_BE_STATE_OFFLINE;
+ break;
+
+ case SLAPI_BE_STATE_ON:
+ node->mtn_be[i] = be;
+ node->mtn_be_states[i] = SLAPI_BE_STATE_ON;
+ break;
+
+ case SLAPI_BE_STATE_DELETE:
+ node->mtn_be[i] = NULL;
+ node->mtn_be_states[i] = SLAPI_BE_STATE_DELETE;
+ break;
+ }
+
+done:
+ mtn_unlock();
+ if (change_callback)
+ mtn_be_state_change(be_name, old_state, state);
+ slapi_ch_free( (void **) &be_name);
+}
+
+/*
+ * This procedure must be called by previously stopped backends
+ * to signal that they have started and are ready to process requests
+ * The backend must be fully ready to handle requests before calling this
+ * procedure
+ * At startup tiem it is not mandatory for the backends to
+ * call this procedure: backends are assumed on by default
+ */
+void
+slapi_mtn_be_started(Slapi_Backend *be)
+{
+ /* Find the node where this backend stay
+ * then update the backend structure
+ * In the long term, the backend should have only one suffix and
+ * stay in only one node as for now, check all suffixes
+ * Rq : since mapping tree is initiatized very soon in the server
+ * startup, we can be sure at that time that the mapping
+ * tree is initialized
+ */
+
+ mtn_internal_be_set_state(be, SLAPI_BE_STATE_ON);
+}
+
+/* these procedure can be called when backends need to be put in maintenance mode
+ * after call to slapi_mtn_be_disable, the backend will still be known
+ * by a server but the mapping tree won't route requests to it anymore
+ * The slapi_mtn_be_enable function enable to route requests to the backend
+ * again
+ * the slapi_mtn_be_disable function only returns when there is no more
+ * request in progress in the backend
+ */
+void
+slapi_mtn_be_disable(Slapi_Backend *be)
+{
+ mtn_internal_be_set_state(be, SLAPI_BE_STATE_OFFLINE);
+
+ /* the two following lines can seem weird, but they allow to check that no
+ * LDAP operation is in progress on the backend
+ */
+ slapi_be_Wlock(be);
+ slapi_be_Unlock(be);
+}
+
+void
+slapi_mtn_be_enable(Slapi_Backend *be)
+{
+ mtn_internal_be_set_state(be, SLAPI_BE_STATE_ON);
+}
+
+/*
+ * This procedure must be called by backends before stopping
+ * if some operations are in progress when this procedure
+ * is called, this procedure will block until completion
+ * of these operations
+ * The backend must wait return from this procedure before stopping operation
+ * Backends must serve operation until the return from this procedure.
+ * Once this procedure return they will not be issued request anymore
+ * and they have been removed from the server list of backends
+ * It is also the bakend responsability to free the Slapi_Backend structures
+ * that was given by slapi_be_new at startup time.
+ * Should the backend start again, it would need to issue slapi_be_new again
+ */
+void
+slapi_mtn_be_stopping(Slapi_Backend *be)
+{
+ mtn_internal_be_set_state(be, SLAPI_BE_STATE_DELETE);
+
+ /* the two following lines can seem weird, but they allow to check that no
+ * LDAP operation is in progress on the backend
+ */
+ slapi_be_Wlock(be);
+ slapi_be_Unlock(be);
+
+ slapi_be_stopping(be);
+}
+
+/*
+ * Switch a backend into read-only mode, or back to read-write mode.
+ * To switch to read-only mode, we need to wait for all pending operations
+ * to finish.
+ */
+void
+slapi_mtn_be_set_readonly(Slapi_Backend *be, int readonly)
+{
+ if (readonly) {
+ slapi_be_Wlock(be);
+ slapi_be_set_readonly(be, 1);
+ slapi_be_Unlock(be);
+ } else {
+ slapi_be_set_readonly(be, 0);
+ }
+}
+
+
+#ifdef DEBUG
+static int lock_count = 0;
+#endif
+
+void mtn_wlock()
+{
+ PR_RWLock_Wlock(myLock);
+#ifdef DEBUG
+ lock_count--;
+ LDAPDebug(LDAP_DEBUG_ARGS, "mtn_wlock : lock count : %d\n", lock_count, 0, 0);
+#endif
+}
+
+void mtn_lock()
+{
+ PR_RWLock_Rlock(myLock);
+#ifdef DEBUG
+ lock_count++;
+ LDAPDebug(LDAP_DEBUG_ARGS, "mtn_lock : lock count : %d\n", lock_count, 0, 0);
+#endif
+}
+
+void mtn_unlock()
+{
+
+#ifdef DEBUG
+ if (lock_count > 0)
+ lock_count--;
+ else if (lock_count < 0)
+ lock_count++;
+ else
+ lock_count = (int) 11111111; /* this happening means problems */
+ LDAPDebug(LDAP_DEBUG_ARGS, "mtn_unlock : lock count : %d\n", lock_count, 0, 0);
+#endif
+ PR_RWLock_Unlock(myLock);
+}
+
+#ifdef TEST_FOR_REGISTER_CHANGE
+void my_test_fnct1(void *handle, char *be_name, int old_state, int new_state)
+{
+ slapi_log_error(SLAPI_LOG_ARGS, NULL,
+ "my_test_fnct1 : handle %d, be %s, old state %d, new state %d\n",
+ handle,be_name, old_state, new_state);
+
+ if (old_state == 2)
+ slapi_unregister_backend_state_change(handle);
+}
+
+void my_test_fnct2(void *handle, char *be_name, int old_state, int new_state)
+{
+ slapi_log_error(SLAPI_LOG_ARGS, NULL,
+ "my_test_fnct2 : handle %d, be %s, old state %d, new state %d\n",
+ handle, be_name, old_state, new_state);
+}
+
+void test_register()
+{
+ slapi_register_backend_state_change((void *) 1234, my_test_fnct1);
+ slapi_register_backend_state_change((void *) 4321, my_test_fnct2);
+}
+#endif
+
+#ifdef DEBUG
+static void dump_mapping_tree(mapping_tree_node *parent, int depth)
+{
+ mapping_tree_node *current = NULL;
+ static char dump_indent[256];
+ int i;
+
+ if (depth == 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "dump_mapping_tree\n", 0, 0, 0);
+ }
+ dump_indent[0] = '\0';
+ for (i = 0; i < depth; i++)
+ strcat(dump_indent, " ");
+ for (current = parent->mtn_children; current;
+ current = current->mtn_brother)
+ {
+ if (strlen(current->mtn_subtree->dn) == 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "MT_DUMP: %s%s (0x%x)\n",
+ dump_indent, "none", current);
+ }
+ else
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "MT_DUMP: %s%s (0x%x)\n",
+ dump_indent, current->mtn_subtree->dn, current);
+ }
+ dump_mapping_tree(current, depth+1);
+ }
+ return;
+}
+#endif
diff --git a/ldap/servers/slapd/match.c b/ldap/servers/slapd/match.c
new file mode 100644
index 00000000..9ff2305e
--- /dev/null
+++ b/ldap/servers/slapd/match.c
@@ -0,0 +1,237 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * match.c
+ *
+ * routines to "register" matching rules with the server
+ *
+ *
+ *
+ *
+ */
+
+#include "slap.h"
+
+
+struct matchingRuleList *g_get_global_mrl(void);
+void g_set_global_mrl(struct matchingRuleList *newglobalmrl);
+int slapi_matchingrule_register(Slapi_MatchingRuleEntry *mrule);
+int slapi_matchingrule_unregister(char *oid);
+Slapi_MatchingRuleEntry *slapi_matchingrule_new(void);
+void slapi_matchingrule_free(Slapi_MatchingRuleEntry **mrEntry,
+ int freeMembers);
+int slapi_matchingrule_get(Slapi_MatchingRuleEntry *mr, int arg, void *value);
+int slapi_matchingrule_set(Slapi_MatchingRuleEntry *mr, int arg, void *value);
+
+
+static int _mr_alloc_new(struct matchingRuleList **mrl);
+
+static struct matchingRuleList *global_mrl=NULL;
+
+struct matchingRuleList*
+g_get_global_mrl(void)
+{
+ return global_mrl;
+}
+
+void
+g_set_global_mrl(struct matchingRuleList *newglobalmrl)
+{
+ global_mrl = newglobalmrl;
+}
+
+int
+slapi_matchingrule_set(Slapi_MatchingRuleEntry *mr, int arg, void *value)
+{
+ if(NULL == mr) {
+ return(-1);
+ }
+ switch(arg) {
+ case SLAPI_MATCHINGRULE_NAME:
+ {
+ mr->mr_name = (char *)value;
+ break;
+ }
+ case SLAPI_MATCHINGRULE_OID:
+ {
+ mr->mr_oid = (char *)value;
+ break;
+ }
+ case SLAPI_MATCHINGRULE_DESC:
+ {
+ mr->mr_desc = (char *)value;
+ break;
+ }
+ case SLAPI_MATCHINGRULE_SYNTAX:
+ {
+ mr->mr_syntax = (char *)value;
+ break;
+ }
+ case SLAPI_MATCHINGRULE_OBSOLETE:
+ {
+ mr->mr_obsolete = *((int *)value);
+ break;
+ }
+ default:
+ {
+ break;
+ }
+ }
+ return(0);
+}
+
+int
+slapi_matchingrule_get(Slapi_MatchingRuleEntry *mr, int arg, void *value)
+{
+ if((NULL == mr) || (NULL == value)) {
+ return(-1);
+ }
+ switch(arg) {
+ case SLAPI_MATCHINGRULE_NAME:
+ {
+ (*(char **)value) = mr->mr_name;
+ break;
+ }
+ case SLAPI_MATCHINGRULE_OID:
+ {
+ (*(char **)value) = mr->mr_oid;
+ break;
+ }
+ case SLAPI_MATCHINGRULE_DESC:
+ {
+ (*(char **)value) = mr->mr_desc;
+ break;
+ }
+ case SLAPI_MATCHINGRULE_SYNTAX:
+ {
+ (*(char **)value) = mr->mr_syntax;
+ break;
+ }
+ case SLAPI_MATCHINGRULE_OBSOLETE:
+ {
+ (*(int *)value) = mr->mr_obsolete;
+ break;
+ }
+ default:
+ {
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+Slapi_MatchingRuleEntry *
+slapi_matchingrule_new(void)
+{
+ Slapi_MatchingRuleEntry *mrEntry=NULL;
+ mrEntry = (Slapi_MatchingRuleEntry *)
+ slapi_ch_calloc(1, sizeof(Slapi_MatchingRuleEntry));
+ return(mrEntry);
+}
+
+void
+slapi_matchingrule_free(Slapi_MatchingRuleEntry **mrEntry,
+ int freeMembers)
+{
+ if((NULL == mrEntry) || (NULL == *mrEntry)) {
+ return;
+ }
+ if(freeMembers) {
+ slapi_ch_free((void **)&((*mrEntry)->mr_name));
+ slapi_ch_free((void **)&((*mrEntry)->mr_oid));
+ slapi_ch_free((void **)&((*mrEntry)->mr_desc));
+ slapi_ch_free((void **)&((*mrEntry)->mr_syntax));
+ slapi_ch_free((void **)&((*mrEntry)->mr_oidalias));
+ }
+ slapi_ch_free((void **)mrEntry);
+ return;
+}
+
+static int
+_mr_alloc_new(struct matchingRuleList **mrl)
+{
+ if(!mrl) {
+ return(-1);
+ }
+ *mrl = NULL;
+ *mrl = (struct matchingRuleList *)
+ slapi_ch_calloc(1, sizeof(struct matchingRuleList));
+
+
+ (*mrl)->mr_entry = (Slapi_MatchingRuleEntry *)
+ slapi_ch_calloc(1, sizeof(Slapi_MatchingRuleEntry));
+ return(0);
+}
+
+#if 0
+static int
+_mr_free(struct matchingRuleList **mrl /*, int freeEntry */)
+{
+ slapi_ch_free((void **)mrl);
+ return(0);
+}
+#endif
+
+int slapi_matchingrule_register(Slapi_MatchingRuleEntry *mrule)
+{
+ struct matchingRuleList *mrl=NULL;
+ struct matchingRuleList *newmrl=NULL;
+ int rc=0;
+
+ if(NULL == mrule) {
+ return(-1);
+ }
+ if((rc = _mr_alloc_new(&newmrl)) != 0) {
+ return(-1);
+ }
+ if(NULL != mrule->mr_name) {
+ newmrl->mr_entry->mr_name =
+ slapi_ch_strdup((char *) mrule->mr_name);
+ }
+ if(NULL != mrule->mr_oid) {
+ newmrl->mr_entry->mr_oid =
+ slapi_ch_strdup((char *) mrule->mr_oid);
+ }
+ if(NULL != mrule->mr_oidalias) {
+ newmrl->mr_entry->mr_oidalias =
+ slapi_ch_strdup((char *) mrule->mr_oidalias);
+ }
+ if(NULL != mrule->mr_desc) {
+ newmrl->mr_entry->mr_desc =
+ slapi_ch_strdup((char *) mrule->mr_desc);
+ }
+ if(NULL != mrule->mr_syntax) {
+ newmrl->mr_entry->mr_syntax =
+ slapi_ch_strdup((char *) mrule->mr_syntax);
+ }
+ newmrl->mr_entry->mr_obsolete = mrule->mr_obsolete;
+
+ for(mrl = g_get_global_mrl();
+ ((NULL != mrl) && (NULL != mrl->mrl_next));
+ mrl = mrl->mrl_next);
+
+ if(NULL == mrl) {
+ g_set_global_mrl(newmrl);
+ mrl = newmrl;
+ }
+ mrl->mrl_next = newmrl;
+ newmrl->mrl_next = NULL;
+ return(LDAP_SUCCESS);
+}
+
+int slapi_matchingrule_unregister(char *oid)
+{
+ /*
+ * Currently, not implemented.
+ * For now, the matching rules are read at startup and cannot be modified.
+ * If and when, we do allow dynamic modifications, this routine will
+ * have to do some work.
+ */
+ return(0);
+}
+
+
+
diff --git a/ldap/servers/slapd/mkDBErrStrs.pl b/ldap/servers/slapd/mkDBErrStrs.pl
new file mode 100755
index 00000000..c93cf261
--- /dev/null
+++ b/ldap/servers/slapd/mkDBErrStrs.pl
@@ -0,0 +1,83 @@
+#!/usr/local/bin/perl
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Perl script to generate dberrstrs.h, which is used in errormap.c.
+#
+
+sub numerically { $a <=> $b; }
+
+$dbdir = "";
+$isNT = 0;
+$i = 0;
+$outdir = "";
+
+while ($i <= $#ARGV) {
+ if ("$ARGV[$i]" eq "-nt" || "$ARGV[$i]" eq "-NT") { # NT
+ $isNT = 1;
+ } elsif ("$ARGV[$i]" eq "-o" || "$ARGV[$i]" eq "-O") { # output dir
+ $i++;
+ $outdir = $ARGV[$i];
+ } elsif ("$ARGV[$i]" eq "-i" || "$ARGV[$i]" eq "-I") { # input db dir
+ $i++;
+ $dbdir = $ARGV[$i];
+ }
+ $i++;
+}
+
+if ($dbdir eq "") {
+ print(STDERR "Usage: $0 [-nt] <db_dir_path>\n");
+ exit(1);
+}
+
+if ($isNT == 1) {
+ $dirsep = "\\";
+} else {
+ $dirsep = "/";
+}
+
+$dbh = sprintf("%s%sdb.h", $dbdir, $dirsep);
+
+open(FOO, $dbh) || die "Cannot open $dbh\n";
+@lines = <FOO>;
+close(FOO);
+
+$i = 0;
+$j = 0;
+while ($i < $#lines) {
+ chop($lines[$i]);
+ if ($lines[$i] =~ /^#define[ ][_A-Z]*[ ]*\(-[0-9]*/) {
+ ($h, $t) = split(/\(/, $lines[$i], 2);
+ ($num[$j], $tt) = split(/\)/, $t, 2);
+ ($h, $ttt) = split(/\/\* /, $tt, 2);
+ ($errstr, $tttt) = split(/ \*\//, $ttt, 2);
+ if ($errstr ne "") {
+ $errstr =~ s/\"/\\\"/g; # Escape quotes
+ $numStrPair{$num[$j]} = $errstr;
+ }
+ $j++;
+ }
+ $i++;
+}
+
+sort numerically num;
+
+if ($outdir eq "") {
+ $myheader = "dberrstrs.h";
+} else {
+ $myheader = sprintf("%s%sdberrstrs.h", $outdir, $dirsep);
+}
+
+open(FOO, "> $myheader") || die "Cannot open $myheader\n";
+print( FOO "/* DO NOT EDIT: This is an automatically generated file by $0 */\n" );
+$i = 0;
+while ($i < $j) {
+ print( FOO "{$num[$i],\t\"$numStrPair{$num[$i]}\"},\n" );
+ $i++;
+}
+close(FOO);
diff --git a/ldap/servers/slapd/modify.c b/ldap/servers/slapd/modify.c
new file mode 100644
index 00000000..56c4de7c
--- /dev/null
+++ b/ldap/servers/slapd/modify.c
@@ -0,0 +1,966 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#include "pratom.h"
+#if defined(irix) || defined(aix) || defined(_WIN32)
+#include <time.h>
+#endif
+
+/* Forward declarations */
+static int modify_internal_pb (Slapi_PBlock *pb);
+static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw);
+static void remove_mod (Slapi_Mods *smods, const char *type, Slapi_Mods *smod_unhashed);
+static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw);
+
+#ifdef LDAP_DEBUG
+static const char*
+mod_op_image (int op)
+{
+ switch (op & ~LDAP_MOD_BVALUES) {
+ case LDAP_MOD_ADD: return "add";
+ case LDAP_MOD_DELETE: return "delete";
+ case LDAP_MOD_REPLACE: return "replace";
+ default: break;
+ }
+ return "???";
+}
+#endif
+
+/* an AttrCheckFunc function should return an LDAP result code (LDAP_SUCCESS if all goes well). */
+typedef int (*AttrCheckFunc)(const char *attr_name, char *value, long minval, long maxval, char *errorbuf);
+
+static struct attr_value_check {
+ const char *attr_name; /* the name of the attribute */
+ AttrCheckFunc checkfunc;
+ long minval;
+ long maxval;
+} AttrValueCheckList[] = {
+ {CONFIG_PW_SYNTAX_ATTRIBUTE, attr_check_onoff, 0, 0},
+ {CONFIG_PW_CHANGE_ATTRIBUTE, attr_check_onoff, 0, 0},
+ {CONFIG_PW_LOCKOUT_ATTRIBUTE, attr_check_onoff, 0, 0},
+ {CONFIG_PW_MUSTCHANGE_ATTRIBUTE, attr_check_onoff, 0, 0},
+ {CONFIG_PW_EXP_ATTRIBUTE, attr_check_onoff, 0, 0},
+ {CONFIG_PW_UNLOCK_ATTRIBUTE, attr_check_onoff, 0, 0},
+ {CONFIG_PW_HISTORY_ATTRIBUTE, attr_check_onoff, 0, 0},
+ {CONFIG_PW_MINAGE_ATTRIBUTE, check_pw_minage_value, -1, -1},
+ {CONFIG_PW_WARNING_ATTRIBUTE, attr_check_minmax, 0, -1},
+ {CONFIG_PW_MINLENGTH_ATTRIBUTE, attr_check_minmax, 2, 512},
+ {CONFIG_PW_MAXFAILURE_ATTRIBUTE, attr_check_minmax, 1, 32767},
+ {CONFIG_PW_INHISTORY_ATTRIBUTE, attr_check_minmax, 2, 24},
+ {CONFIG_PW_LOCKDURATION_ATTRIBUTE, check_pw_lockduration_value, -1, -1},
+ {CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE, check_pw_resetfailurecount_value, -1, -1},
+ {CONFIG_PW_GRACELIMIT_ATTRIBUTE, attr_check_minmax, 0, -1},
+ {CONFIG_PW_STORAGESCHEME_ATTRIBUTE, check_pw_storagescheme_value, -1, -1}
+};
+
+/* This function is called to process operation that come over external connections */
+void
+do_modify( Slapi_PBlock *pb )
+{
+ Slapi_Operation *operation;
+ BerElement *ber;
+ char *last, *type;
+ unsigned long tag, len;
+ LDAPMod *mod;
+ LDAPMod **mods;
+ Slapi_Mods smods;
+ int err;
+ int pw_change = 0; /* 0= no password change */
+ int ignored_some_mods = 0;
+ char *old_pw = NULL; /* remember the old password */
+ char *dn;
+ LDAPControl **ctrlp = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_modify\n", 0, 0, 0 );
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ ber = operation->o_ber;
+
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
+
+ /* count the modify request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsModifyEntryOps);
+
+ /*
+ * Parse the modify request. It looks like this:
+ *
+ * ModifyRequest := [APPLICATION 6] SEQUENCE {
+ * name DistinguishedName,
+ * mods SEQUENCE OF SEQUENCE {
+ * operation ENUMERATED {
+ * add (0),
+ * delete (1),
+ * replace (2)
+ * },
+ * modification SEQUENCE {
+ * type AttributeType,
+ * values SET OF AttributeValue
+ * }
+ * }
+ * }
+ */
+
+ {
+ if ( ber_scanf( ber, "{a", &dn ) == LBER_ERROR )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=Modify; params=DN)\n", 0, 0, 0 );
+ op_shared_log_error_access (pb, "MOD", "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
+ NULL );
+ return;
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_ARGS, "do_modify: dn (%s)\n", dn, 0, 0 );
+
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot);
+ slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, dn );
+
+ /* collect modifications & save for later */
+ slapi_mods_init(&smods, 0);
+ for ( tag = ber_first_element( ber, &len, &last );
+ tag != LBER_ERROR && tag != LBER_END_OF_SEQORSET;
+ tag = ber_next_element( ber, &len, last ) )
+ {
+ long long_mod_op;
+ mod = (LDAPMod *) slapi_ch_malloc( sizeof(LDAPMod) );
+ mod->mod_bvalues = NULL;
+
+ if ( ber_scanf( ber, "{i{a[V]}}", &long_mod_op, &type,
+ &mod->mod_bvalues ) == LBER_ERROR )
+ {
+ op_shared_log_error_access (pb, "MOD", dn, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "decoding error", 0, NULL );
+ slapi_ch_free((void **)&mod);
+ goto free_and_return;
+ }
+ mod->mod_op = long_mod_op;
+ mod->mod_type = slapi_attr_syntax_normalize(type);
+ if ( !mod->mod_type || !*mod->mod_type ) {
+ char ebuf[BUFSIZ];
+ PR_snprintf (ebuf, BUFSIZ, "invalid type '%s'", type);
+ ebuf[BUFSIZ-1] = '\0';
+ op_shared_log_error_access (pb, "MOD", dn, ebuf);
+ send_ldap_result( pb, LDAP_INVALID_SYNTAX, NULL, ebuf, 0, NULL );
+ slapi_ch_free((void **)&type);
+ ber_bvecfree(mod->mod_bvalues);
+ slapi_ch_free((void **)&mod);
+ goto free_and_return;
+ }
+ slapi_ch_free((void **)&type);
+
+ if ( mod->mod_op != LDAP_MOD_ADD &&
+ mod->mod_op != LDAP_MOD_DELETE &&
+ mod->mod_op != LDAP_MOD_REPLACE )
+ {
+ op_shared_log_error_access (pb, "MOD", dn, "unrecognized modify operation");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "unrecognized modify operation", 0, NULL );
+ ber_bvecfree(mod->mod_bvalues);
+ slapi_ch_free((void **)&(mod->mod_type));
+ slapi_ch_free((void **)&mod);
+ goto free_and_return;
+ }
+
+ if ( mod->mod_bvalues == NULL
+ && mod->mod_op != LDAP_MOD_DELETE
+ && mod->mod_op != LDAP_MOD_REPLACE )
+ {
+ op_shared_log_error_access (pb, "MOD", dn, "no values given");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "no values given", 0, NULL );
+ ber_bvecfree(mod->mod_bvalues);
+ slapi_ch_free((void **)&(mod->mod_type));
+ slapi_ch_free((void **)&mod);
+ goto free_and_return;
+ }
+
+ /* check if user is allowed to modify the specified attribute */
+ if (!op_shared_is_allowed_attr (mod->mod_type, pb->pb_conn->c_isreplication_session))
+ {
+ /* for now we just ignore attributes that client is not allowed
+ to modify so not to break existing clients */
+ ++ignored_some_mods;
+ ber_bvecfree(mod->mod_bvalues);
+ slapi_ch_free((void **)&(mod->mod_type));
+ slapi_ch_free((void **)&mod);
+ continue;
+ /* send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, NULL, 0, NULL );
+ goto free_and_return; */
+ }
+
+ /* check for password change */
+ if ( mod->mod_bvalues != NULL &&
+ strcasecmp( mod->mod_type, SLAPI_USERPWD_ATTR ) == 0 ){
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ op_shared_log_error_access (pb, "MOD", dn, "failed to decode LDAP controls");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+ pw_change = op_shared_allow_pw_change (pb, mod, &old_pw);
+ if (pw_change == -1)
+ {
+ ber_bvecfree(mod->mod_bvalues);
+ slapi_ch_free((void **)&(mod->mod_type));
+ slapi_ch_free((void **)&mod);
+ goto free_and_return;
+ }
+ }
+
+ mod->mod_op |= LDAP_MOD_BVALUES;
+ slapi_mods_add_ldapmod (&smods, mod);
+ }
+
+ if ( tag == LBER_ERROR && !ctrlp )
+ {
+ op_shared_log_error_access (pb, "MOD", dn, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, "decoding error", 0, NULL );
+ goto free_and_return;
+ }
+
+ if ( slapi_mods_get_num_mods (&smods) == 0 )
+ {
+ int lderr;
+ char *emsg;
+
+ if ( ignored_some_mods ) {
+ lderr = LDAP_UNWILLING_TO_PERFORM;
+ emsg = "no modifiable attributes specified";
+ } else {
+ lderr = LDAP_PROTOCOL_ERROR;
+ emsg = "no modifications specified";
+ }
+ op_shared_log_error_access (pb, "MOD", dn, emsg);
+ send_ldap_result( pb, lderr, NULL, emsg, 0, NULL );
+ goto free_and_return;
+ }
+
+ if (!pb->pb_conn->c_isreplication_session &&
+ pb->pb_conn->c_needpw && pw_change == 0 )
+ {
+ (void)add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
+ op_shared_log_error_access (pb, "MOD", dn, "need new password");
+ send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend.
+ */
+ if ( !ctrlp ) {
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 )
+ {
+ op_shared_log_error_access (pb, "MOD", dn, "failed to decode LDAP controls");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+ }
+
+#ifdef LDAP_DEBUG
+ LDAPDebug( LDAP_DEBUG_ARGS, "modifications:\n", 0, 0, 0 );
+ for (mod = slapi_mods_get_first_mod(&smods); mod != NULL;
+ mod = slapi_mods_get_next_mod(&smods))
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS, "\t%s: %s\n",
+ mod_op_image( mod->mod_op ), mod->mod_type, 0 );
+ }
+#endif
+
+ mods = slapi_mods_get_ldapmods_passout (&smods);
+
+ slapi_pblock_set( pb, SLAPI_MODIFY_MODS, mods);
+
+ op_shared_modify ( pb, pw_change, old_pw );
+
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ ldap_mods_free (mods, 1 /* Free the Array and the Elements */);
+
+free_and_return:;
+ slapi_ch_free ((void**)&dn);
+ slapi_mods_done(&smods);
+}
+
+/* This function is used to issue internal modify operation
+ This is an old style API. Its use is discoraged because it is not extendable and
+ because it does not allow to check whether plugin has right to access part of the
+ tree it is trying to modify. Use slapi_modify_internal_pb instead */
+Slapi_PBlock*
+slapi_modify_internal(const char *idn,
+ LDAPMod **mods,
+ LDAPControl **controls,
+ int dummy)
+{
+ Slapi_PBlock pb;
+ Slapi_PBlock *result_pb = NULL;
+ int opresult;
+
+ pblock_init(&pb);
+
+ slapi_modify_internal_set_pb (&pb, idn, (LDAPMod**)mods, controls, NULL,
+ (void *)plugin_get_default_component_id(), 0);
+
+ modify_internal_pb (&pb);
+
+ result_pb = slapi_pblock_new();
+ if (result_pb)
+ {
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ slapi_pblock_set(result_pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ }
+ pblock_done(&pb);
+
+ return result_pb;
+}
+
+/* This is new style API to issue internal modify operation.
+ pblock should contain the following data (can be set via call to slapi_modify_internal_set_pb):
+ For uniqueid based operation:
+ SLAPI_TARGET_DN set to dn that allows to select right backend, can be stale
+ SLAPI_TARGET_UNIQUEID set to the uniqueid of the entry we are looking for
+ SLAPI_MODIFY_MODS set to the mods
+ SLAPI_CONTROLS_ARG set to request controls if present
+
+ For dn based search:
+ SLAPI_TARGET_DN set to the entry dn
+ SLAPI_MODIFY_MODS set to the mods
+ SLAPI_CONTROLS_ARG set to request controls if present
+ */
+int slapi_modify_internal_pb (Slapi_PBlock *pb)
+{
+ if (pb == NULL)
+ return -1;
+
+ if (!allow_operation (pb))
+ {
+ slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "This plugin is not configured to access operation target data", 0, NULL );
+ return 0;
+ }
+
+ return modify_internal_pb (pb);
+}
+
+/* Initialize a pblock for a call to slapi_modify_internal_pb() */
+void slapi_modify_internal_set_pb (Slapi_PBlock *pb, const char *dn, LDAPMod **mods, LDAPControl **controls,
+ const char *uniqueid, Slapi_ComponentId *plugin_identity, int operation_flags)
+{
+ Operation *op;
+ PR_ASSERT (pb != NULL);
+ if (pb == NULL || dn == NULL || mods == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_modify_internal_set_pb: NULL parameter\n");
+ return;
+ }
+
+ op= internal_operation_new(SLAPI_OPERATION_MODIFY,operation_flags);
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ slapi_pblock_set(pb, SLAPI_ORIGINAL_TARGET, (void*)dn);
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods);
+ slapi_pblock_set(pb, SLAPI_CONTROLS_ARG, controls);
+ if (uniqueid)
+ {
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, (void*)uniqueid);
+ }
+ slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, plugin_identity);
+}
+
+/* Helper functions */
+
+static int modify_internal_pb (Slapi_PBlock *pb)
+{
+ LDAPControl **controls;
+ Operation *op;
+ int opresult = 0;
+ LDAPMod **normalized_mods = NULL;
+ LDAPMod **mods;
+ LDAPMod **mod;
+ int pw_change = 0;
+ char *old_pw = NULL;
+
+ PR_ASSERT (pb != NULL);
+
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
+
+ if(mods == NULL)
+ {
+ opresult = LDAP_PARAM_ERROR;
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ return 0;
+ }
+
+ /* first normalize the mods so they are bvalue
+ * Note: We don't add any special
+ * attributes such as "creatorsname".
+ * for CIR we don't want to change them, for other
+ * plugins the writer should change these if it wants too by explicitly
+ * adding them to the mods
+ */
+ normalized_mods = normalize_mods2bvals((const LDAPMod**)mods);
+ if (normalized_mods == NULL)
+ {
+ opresult = LDAP_PARAM_ERROR;
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ return 0;
+ }
+
+ /* check for password change */
+ mod = normalized_mods;
+ while (*mod)
+ {
+ if ((*mod)->mod_bvalues != NULL && strcasecmp((*mod)->mod_type, SLAPI_USERPWD_ATTR) == 0)
+ {
+ pw_change = op_shared_allow_pw_change (pb, *mod, &old_pw);
+ if (pw_change == -1)
+ {
+ opresult = LDAP_PARAM_ERROR;
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ return 0;
+ }
+ }
+
+ mod ++;
+ }
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op->o_handler_data = &opresult;
+ op->o_result_handler = internal_getresult_callback;
+
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, normalized_mods);
+ slapi_pblock_set(pb, SLAPI_REQCONTROLS, controls);
+
+ /* set parameters common for all internal operations */
+ set_common_params (pb);
+
+ /* set actions taken to process the operation */
+ set_config_params (pb);
+
+ /* perform modify operation */
+ op_shared_modify (pb, pw_change, old_pw);
+
+ /* free the normalized_mods don't forget to add this*/
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &normalized_mods);
+ if (normalized_mods != NULL)
+ {
+ ldap_mods_free(normalized_mods, 1);
+ }
+
+ /* return original mods here */
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, mods);
+ /* set result */
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+
+ return 0;
+}
+
+static void op_shared_modify (Slapi_PBlock *pb, int pw_change, char *old_pw)
+{
+ Slapi_Backend *be = NULL;
+ Slapi_Entry *pse;
+ Slapi_Entry *referral;
+ Slapi_Entry *ecopy = NULL;
+ Slapi_Entry *e = NULL;
+ char ebuf[BUFSIZ];
+ char *dn;
+ Slapi_DN sdn;
+ LDAPMod **mods, *pw_mod, **tmpmods = NULL;
+ Slapi_Mods smods;
+ Slapi_Mods unhashed_pw_smod;
+ int repl_op, internal_op, lastmod;
+ char *unhashed_pw_attr = NULL;
+ Slapi_Operation *operation;
+ char errorbuf[BUFSIZ];
+ int err;
+ LDAPMod *lc_mod = NULL;
+ struct slapdplugin *p = NULL;
+ int numattr, i;
+
+ slapi_pblock_get (pb, SLAPI_ORIGINAL_TARGET, &dn);
+ slapi_pblock_get (pb, SLAPI_MODIFY_MODS, &mods);
+ slapi_pblock_get (pb, SLAPI_MODIFY_MODS, &tmpmods);
+ slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+ internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
+
+ if (dn == NULL)
+ {
+ slapi_sdn_init_dn_byref (&sdn, "");
+ }
+ else
+ {
+ slapi_sdn_init_dn_byref (&sdn, dn);
+ }
+
+ slapi_pblock_set(pb, SLAPI_MODIFY_TARGET, (void*)slapi_sdn_get_ndn (&sdn));
+
+ slapi_mods_init_passin (&smods, mods);
+
+ slapi_mods_init(&unhashed_pw_smod, 0);
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ operation_set_target_spec (pb->pb_op, &sdn);
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ if ( !internal_op )
+ {
+ slapi_log_access(LDAP_DEBUG_STATS, "conn=%d op=%d MOD dn=\"%s\"\n",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ escape_string(slapi_sdn_get_dn(&sdn), ebuf));
+ }
+ else
+ {
+ slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d MOD dn=\"%s\"\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ escape_string(slapi_sdn_get_dn(&sdn), ebuf));
+ }
+ }
+
+ /*
+ * We could be serving multiple database backends. Select the
+ * appropriate one.
+ */
+ if ((err = slapi_mapping_tree_select(pb, &be, &referral, errorbuf)) != LDAP_SUCCESS) {
+ send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
+ be = NULL;
+ goto free_and_return;
+ }
+
+ if (referral)
+ {
+ int managedsait;
+
+ slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ if (managedsait)
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "cannot update referral", 0, NULL);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ send_referrals_from_entry(pb,referral);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+
+ /* The following section checks the valid values of fine-grained
+ * password policy attributes.
+ * 1. First, it checks if the entry has "passwordpolicy" objectclass.
+ * 2. If yes, then if the mods contain any passwdpolicy specific attributes.
+ * 3. If yes, then it invokes corrosponding checking function.
+ */
+ if ( !repl_op && !internal_op && dn &&
+ (e = get_entry(pb, slapi_dn_normalize(dn))) )
+ {
+ Slapi_Value target;
+ slapi_value_init(&target);
+ slapi_value_set_string(&target,"passwordpolicy");
+ if ((slapi_entry_attr_has_syntax_value(e, "objectclass", &target)) == 1)
+ {
+ numattr = sizeof(AttrValueCheckList)/sizeof(AttrValueCheckList[0]);
+ while ( tmpmods && *tmpmods )
+ {
+ if ((*tmpmods)->mod_bvalues != NULL &&
+ (((*tmpmods)->mod_op & ~LDAP_MOD_BVALUES) != LDAP_MOD_DELETE))
+ {
+ for (i=0; i < numattr; i++)
+ {
+ if (slapi_attr_type_cmp((*tmpmods)->mod_type,
+ AttrValueCheckList[i].attr_name, SLAPI_TYPE_CMP_SUBTYPE) == 0)
+ {
+ /* The below function call is good for
+ * single-valued attrs only
+ */
+ if ( (err = AttrValueCheckList[i].checkfunc (AttrValueCheckList[i].attr_name,
+ (*tmpmods)->mod_bvalues[0]->bv_val, AttrValueCheckList[i].minval,
+ AttrValueCheckList[i].maxval, errorbuf))
+ != LDAP_SUCCESS)
+ {
+ /* return error */
+ send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
+ goto free_and_return;
+ }
+ }
+ }
+ }
+ tmpmods++;
+ } /* end of (while */
+ } /* end of if (found */
+ value_done (&target);
+ } /* end of if (!repl_op */
+
+ /* can get lastmod only after backend is selected */
+ slapi_pblock_get(pb, SLAPI_BE_LASTMOD, &lastmod);
+
+ /* if this is replication session - leave mod attributes alone */
+ if (!repl_op && lastmod)
+ {
+ modify_update_last_modified_attr(pb, &smods);
+ }
+
+ /*
+ * Add the unhashed password pseudo-attribute before
+ * calling the preop plugins
+ */
+
+ if (pw_change)
+ {
+ Slapi_Value **va= NULL;
+
+ unhashed_pw_attr = slapi_attr_syntax_normalize(PSEUDO_ATTR_UNHASHEDUSERPASSWORD);
+
+ for ( pw_mod = slapi_mods_get_first_mod(&smods); pw_mod;
+ pw_mod = slapi_mods_get_next_mod(&smods) )
+ {
+ if (strcasecmp (pw_mod->mod_type, SLAPI_USERPWD_ATTR) != 0)
+ continue;
+
+ /* add pseudo password attribute */
+ valuearray_init_bervalarray(pw_mod->mod_bvalues, &va);
+ slapi_mods_add_mod_values(&smods, pw_mod->mod_op, unhashed_pw_attr, va);
+ valuearray_free(&va);
+
+ /* Init new value array for hashed value */
+ valuearray_init_bervalarray(pw_mod->mod_bvalues, &va);
+
+ /* encode password */
+ pw_encodevals(va);
+
+ /* remove current clear value of userpassword */
+ ber_bvecfree(pw_mod->mod_bvalues);
+ /* add the cipher in the structure */
+ valuearray_get_bervalarray(va, &pw_mod->mod_bvalues);
+
+ valuearray_free(&va);
+ }
+ }
+ for ( p = get_plugin_list(PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME); p != NULL; p = p->plg_next )
+ {
+ char *L_attr = NULL;
+ int i = 0;
+
+ /* Get the appropriate encoding function */
+ for ( L_attr = p->plg_argv[i]; i<p->plg_argc; L_attr = p->plg_argv[++i])
+ {
+ char *L_normalized = slapi_attr_syntax_normalize(L_attr);
+
+ for ( lc_mod = slapi_mods_get_first_mod(&smods); lc_mod;
+ lc_mod = slapi_mods_get_next_mod(&smods) )
+ {
+ Slapi_Value **va= NULL;
+
+ if (strcasecmp (lc_mod->mod_type, L_normalized) != 0)
+ continue;
+
+ switch (lc_mod->mod_op & ~LDAP_MOD_BVALUES)
+ {
+ case LDAP_MOD_ADD:
+ case LDAP_MOD_REPLACE:
+
+ /* Init new value array for hashed value */
+ valuearray_init_bervalarray(lc_mod->mod_bvalues, &va);
+ if ( va )
+ {
+ /* encode local credentials */
+ pw_rever_encode(va, L_normalized);
+ /* remove current clear value of userpassword */
+ ber_bvecfree(lc_mod->mod_bvalues);
+ /* add the cipher in the structure */
+ valuearray_get_bervalarray(va, &lc_mod->mod_bvalues);
+
+ valuearray_free(&va);
+ }
+ break;
+ default:
+ /* for LDAP_MOD_DELETE, don't do anything */
+ /* for LDAP_MOD_BVALUES, don't do anything */
+ ;
+ }
+ }
+ if (L_normalized)
+ slapi_ch_free ((void**)&L_normalized);
+ }
+ }
+
+ /*
+ * call the pre-mod plugins. if they succeed, call
+ * the backend mod function. then call the post-mod
+ * plugins.
+ */
+ slapi_pblock_set (pb, SLAPI_MODIFY_MODS, (void*)slapi_mods_get_ldapmods_passout (&smods));
+ if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN :
+ SLAPI_PLUGIN_PRE_MODIFY_FN) == 0)
+ {
+ int rc;
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
+ set_db_default_result_handlers(pb);
+
+ /* Remove the unhashed password pseudo-attribute prior */
+ /* to db access */
+ if (pw_change)
+ {
+ slapi_pblock_get (pb, SLAPI_MODIFY_MODS, &mods);
+ slapi_mods_init_passin (&smods, mods);
+ remove_mod (&smods, unhashed_pw_attr, &unhashed_pw_smod);
+ slapi_pblock_set (pb, SLAPI_MODIFY_MODS,
+ (void*)slapi_mods_get_ldapmods_passout (&smods));
+ }
+
+ if (be->be_modify != NULL)
+ {
+ if ((rc = (*be->be_modify)(pb)) == 0)
+ {
+ /* acl is not used for internal operations */
+ /* don't update aci store for remote acis */
+ if ((!internal_op) &&
+ (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
+ {
+ plugin_call_acl_mods_update (pb, SLAPI_OPERATION_MODIFY);
+ }
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
+ write_audit_log_entry(pb); /* Record the operation in the audit log */
+
+ if (pw_change && (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
+ {
+ /* update the password info */
+ update_pw_info (pb, old_pw);
+ }
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
+ do_ps_service(pse, NULL, LDAP_CHANGETYPE_MODIFY, 0);
+ }
+ else
+ {
+ if (rc == SLAPI_FAIL_DISKFULL)
+ {
+ operation_out_of_disk_space();
+ goto free_and_return;
+ }
+ }
+ }
+ else
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Function not implemented", 0, NULL);
+ }
+ /* Add the pseudo-attribute prior to calling the postop plugins */
+ if (pw_change)
+ {
+ LDAPMod *lc_mod = NULL;
+
+ slapi_pblock_get (pb, SLAPI_MODIFY_MODS, &mods);
+ slapi_mods_init_passin (&smods, mods);
+ for ( lc_mod = slapi_mods_get_first_mod(&unhashed_pw_smod); lc_mod;
+ lc_mod = slapi_mods_get_next_mod(&unhashed_pw_smod) )
+ {
+ Slapi_Mod lc_smod;
+ slapi_mod_init_byval(&lc_smod, lc_mod); /* copies lc_mod */
+ /* this extracts the copy of lc_mod and finalizes lc_smod too */
+ slapi_mods_add_ldapmod(&smods,
+ slapi_mod_get_ldapmod_passout(&lc_smod));
+ }
+ slapi_pblock_set (pb, SLAPI_MODIFY_MODS,
+ (void*)slapi_mods_get_ldapmods_passout (&smods));
+ slapi_mods_done(&unhashed_pw_smod); /* can finalize now */
+ }
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN :
+ SLAPI_PLUGIN_POST_MODIFY_FN);
+
+ }
+
+free_and_return:
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
+ slapi_entry_free(ecopy);
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &ecopy);
+ slapi_entry_free(ecopy);
+ slapi_entry_free(e);
+
+ if (be)
+ slapi_be_Unlock(be);
+ slapi_sdn_done(&sdn);
+
+ if (unhashed_pw_attr)
+ slapi_ch_free ((void**)&unhashed_pw_attr);
+}
+
+static void remove_mod (Slapi_Mods *smods, const char *type, Slapi_Mods *smod_unhashed)
+{
+ LDAPMod *mod;
+ Slapi_Mod smod;
+
+ for (mod = slapi_mods_get_first_mod(smods); mod; mod = slapi_mods_get_next_mod(smods))
+ {
+ if (strcasecmp (mod->mod_type, type) == 0)
+ {
+ slapi_mod_init_byval (&smod, mod);
+ slapi_mods_add_smod(smod_unhashed, &smod);
+ slapi_mods_remove (smods);
+ }
+ }
+}
+
+static int op_shared_allow_pw_change (Slapi_PBlock *pb, LDAPMod *mod, char **old_pw)
+{
+ int isroot, internal_op, repl_op, pwresponse_req = 0;
+ char *dn;
+ Slapi_DN sdn;
+ passwdPolicy *pwpolicy;
+ int rc = 0;
+ char ebuf[BUFSIZ];
+ Slapi_Value **values= NULL;
+ Slapi_Operation *operation;
+
+ slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ if (repl_op) {
+ /* Treat like there's no password */
+ return (0);
+ }
+
+ *old_pw = NULL;
+
+ slapi_pblock_get (pb, SLAPI_ORIGINAL_TARGET, &dn);
+ slapi_pblock_get (pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+ slapi_pblock_get (pb, SLAPI_PWPOLICY, &pwresponse_req);
+ internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
+
+
+ slapi_sdn_init_dn_byref (&sdn, dn);
+ pwpolicy = new_passwdPolicy(pb, (char *)slapi_sdn_get_ndn(&sdn));
+
+ /* internal operation has root permisions for subtrees it is allowed to access */
+ if (!internal_op)
+ {
+ /* Check first if password policy allows users to change their passwords.*/
+ if (!pb->pb_op->o_isroot && slapi_sdn_compare(&sdn, &pb->pb_op->o_sdn)==0 &&
+ !pb->pb_conn->c_needpw && !pwpolicy->pw_change)
+ {
+ if ( pwresponse_req == 1 ) {
+ pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDMODNOTALLOWED );
+ }
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "user is not allowed to change password", 0, NULL);
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ slapi_log_access(LDAP_DEBUG_STATS, "conn=%d op=%d MOD dn=\"%s\", %s\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid,
+ escape_string(slapi_sdn_get_dn(&sdn), ebuf),
+ "user is not allowed to change password");
+ }
+
+ rc = -1;
+ goto done;
+ }
+ }
+
+ /* check if password is within password minimum age;
+ error result is sent directly from check_pw_minage */
+ if ((internal_op || !pb->pb_conn->c_needpw) &&
+ check_pw_minage(pb, &sdn, mod->mod_bvalues) == 1)
+ {
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ if ( !internal_op )
+ {
+ slapi_log_access(LDAP_DEBUG_STATS, "conn=%d op=%d MOD dn=\"%s\", %s\n",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ escape_string(slapi_sdn_get_dn(&sdn), ebuf),
+ "within password minimum age");
+ }
+ else
+ {
+ slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d MOD dn=\"%s\", %s\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ escape_string(slapi_sdn_get_dn(&sdn), ebuf),
+ "within password minimum age");
+ }
+ }
+
+ rc = -1;
+ goto done;
+ }
+
+
+ /* check password syntax; remember the old password;
+ error sent directly from check_pw_syntax function */
+ valuearray_init_bervalarray(mod->mod_bvalues, &values);
+ switch (check_pw_syntax (pb, &sdn, values, old_pw, NULL, 1))
+ {
+ case 0: /* success */
+ rc = 1;
+ break;
+
+ case 1: /* failed checking */
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ if ( !internal_op )
+ {
+ slapi_log_access(LDAP_DEBUG_STATS, "conn=%d op=%d MOD dn=\"%s\", %s\n",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ escape_string(slapi_sdn_get_dn(&sdn), ebuf), "invalid password syntax");
+ }
+ else
+ {
+ slapi_log_access(LDAP_DEBUG_ARGS, "conn=%s op=%d MOD dn=\"%s\", %s\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ escape_string(slapi_sdn_get_dn(&sdn), ebuf), "invalid password syntax");
+ }
+ }
+ rc = -1;
+ break;
+
+ case -1: /* The entry is not found. No password checking is done. Countinue execution
+ and it should get caught later and send "no such object back. */
+ rc = 0;
+ break;
+
+ default: break;
+ }
+ valuearray_free(&values);
+
+done:
+ slapi_sdn_done (&sdn);
+ delete_passwdPolicy(&pwpolicy);
+ return rc;
+}
diff --git a/ldap/servers/slapd/modrdn.c b/ldap/servers/slapd/modrdn.c
new file mode 100644
index 00000000..3e6c4bf6
--- /dev/null
+++ b/ldap/servers/slapd/modrdn.c
@@ -0,0 +1,501 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#include "pratom.h"
+
+/* Forward declarations */
+static int rename_internal_pb (Slapi_PBlock *pb);
+static void op_shared_rename (Slapi_PBlock *pb, int passin_args );
+
+/* This function is called to process operation that come over external connections */
+void
+do_modrdn( Slapi_PBlock *pb )
+{
+ Slapi_Operation *operation;
+ BerElement *ber;
+ char *dn, *newsuperior = NULL;
+ char *newrdn = NULL;
+ int err, deloldrdn;
+ unsigned long len;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_modrdn\n", 0, 0, 0 );
+
+ /* count the modrdn request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps);
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ ber = operation->o_ber;
+
+ /*
+ * Parse the modrdn request. It looks like this:
+ *
+ * ModifyRDNRequest := SEQUENCE {
+ * entry DistinguishedName,
+ * newrdn RelativeDistinguishedName,
+ * deleteoldrdn BOOLEAN,
+ * newSuperior [0] LDAPDN OPTIONAL -- v3 only
+ * }
+ */
+
+ if ( ber_scanf( ber, "{aab", &dn, &newrdn, &deloldrdn )
+ == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=ModRDN; params=DN,newRDN,deleteOldRDN)\n",
+ 0, 0, 0 );
+ op_shared_log_error_access (pb, "MODRDN", "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "unable to decode DN, newRDN, or deleteOldRDN parameters",
+ 0, NULL );
+ return;
+ }
+
+ if ( ber_peek_tag( ber, &len ) == LDAP_TAG_NEWSUPERIOR ) {
+ if ( pb->pb_conn->c_ldapversion < LDAP_VERSION3 ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "got newSuperior in LDAPv2 modrdn op\n", 0, 0, 0 );
+ op_shared_log_error_access (pb, "MODRDN", dn, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "received newSuperior in LDAPv2 modrdn", 0, NULL );
+ goto free_and_return;
+ }
+ if ( ber_scanf( ber, "a", &newsuperior ) == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_scanf failed (op=ModRDN; params=newSuperior)\n",
+ 0, 0, 0 );
+ op_shared_log_error_access (pb, "MODRDN", dn, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "unable to decode newSuperior parameter", 0, NULL );
+ goto free_and_return;
+ }
+ }
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ op_shared_log_error_access (pb, "MODRDN", dn, "failed to decode LDAP controls");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+
+ LDAPDebug( LDAP_DEBUG_ARGS,
+ "do_moddn: dn (%s) newrdn (%s) deloldrdn (%d)\n", dn, newrdn,
+ deloldrdn );
+
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &pb->pb_op->o_isroot );
+ slapi_pblock_set( pb, SLAPI_ORIGINAL_TARGET, dn );
+ slapi_pblock_set( pb, SLAPI_MODRDN_NEWRDN, newrdn );
+ slapi_pblock_set( pb, SLAPI_MODRDN_NEWSUPERIOR, newsuperior );
+ slapi_pblock_set( pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn );
+
+ op_shared_rename(pb, 1 /* pass in ownership of string arguments */ );
+ return;
+
+free_and_return:;
+ slapi_ch_free((void **) &dn );
+ slapi_ch_free((void **) &newrdn );
+ slapi_ch_free((void **) &newsuperior );
+}
+
+/* This function is used to issue internal modrdn operation
+ This is an old style API. Its use is discoraged because it is not extendable and
+ because it does not allow to check whether plugin has right to access part of the
+ tree it is trying to modify. Use slapi_modrdn_internal_pb instead */
+Slapi_PBlock *
+slapi_modrdn_internal(const char *iodn, const char *inewrdn, int deloldrdn, LDAPControl **controls, int dummy)
+{
+ return slapi_rename_internal(iodn, inewrdn, NULL, deloldrdn, controls, dummy);
+}
+
+Slapi_PBlock *
+slapi_rename_internal(const char *iodn, const char *inewrdn, const char *inewsuperior, int deloldrdn, LDAPControl **controls, int dummy)
+{
+ Slapi_PBlock pb;
+ Slapi_PBlock *result_pb = NULL;
+ int opresult= 0;
+
+ pblock_init (&pb);
+
+ slapi_rename_internal_set_pb (&pb, iodn, inewrdn, inewsuperior, deloldrdn,
+ controls, NULL, plugin_get_default_component_id(), 0);
+ rename_internal_pb (&pb);
+
+ result_pb = slapi_pblock_new();
+ if (result_pb)
+ {
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ slapi_pblock_set(result_pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ }
+ pblock_done(&pb);
+
+ return result_pb;
+}
+
+/* This is new style API to issue internal add operation.
+ pblock should contain the following data (can be set via call to slapi_rename_internal_set_pb):
+ For uniqueid based operation:
+ SLAPI_TARGET_DN set to dn that allows to select right backend, can be stale
+ SLAPI_TARGET_UNIQUEID set to the uniqueid of the entry we are looking for
+ SLAPI_MODRDN_NEWRDN set to new rdn of the entry
+ SLAPI_MODRDN_DELOLDRDN tells whether old rdn should be kept in the entry
+ LAPI_CONTROLS_ARG set to request controls if present
+
+ For dn based search:
+ SLAPI_TARGET_DN set to the entry dn
+ SLAPI_MODRDN_NEWRDN set to new rdn of the entry
+ SLAPI_MODRDN_DELOLDRDN tells whether old rdn should be kept in the entry
+ SLAPI_CONTROLS_ARG set to request controls if present
+ */
+int slapi_modrdn_internal_pb (Slapi_PBlock *pb)
+{
+ if (pb == NULL)
+ return -1;
+
+ return rename_internal_pb (pb);
+}
+
+/* Initialize a pblock for a call to slapi_modrdn_internal_pb() */
+void slapi_rename_internal_set_pb (Slapi_PBlock *pb, const char *olddn, const char *newrdn, const char *newsuperior, int deloldrdn,
+ LDAPControl **controls, const char *uniqueid, Slapi_ComponentId *plugin_identity, int operation_flags)
+{
+ Operation *op;
+ PR_ASSERT (pb != NULL);
+ if (pb == NULL || olddn == NULL || newrdn == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_rename_internal_set_pb: NULL parameter\n");
+ return;
+ }
+
+ op= internal_operation_new(SLAPI_OPERATION_MODRDN,operation_flags);
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ slapi_pblock_set(pb, SLAPI_ORIGINAL_TARGET, (void*)olddn);
+ slapi_pblock_set(pb, SLAPI_MODRDN_NEWRDN, (void*)newrdn);
+ slapi_pblock_set(pb, SLAPI_MODRDN_NEWSUPERIOR, (void*)newsuperior);
+ slapi_pblock_set(pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn);
+ slapi_pblock_set(pb, SLAPI_CONTROLS_ARG, controls);
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, NULL);
+ if (uniqueid)
+ {
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, (void*)uniqueid);
+ }
+ slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, plugin_identity);
+}
+
+/* Helper functions */
+
+static int rename_internal_pb (Slapi_PBlock *pb)
+{
+ LDAPControl **controls;
+ Operation *op;
+ int opresult = 0;
+
+ PR_ASSERT (pb != NULL);
+
+ slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op->o_handler_data = &opresult;
+ op->o_result_handler = internal_getresult_callback;
+
+ slapi_pblock_set(pb, SLAPI_REQCONTROLS, controls);
+
+ /* set parameters common for all internal operations */
+ set_common_params (pb);
+
+ /* set actions taken to process the operation */
+ set_config_params (pb);
+
+ op_shared_rename (pb, 0 /* not passing ownership of args */ );
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+
+ return 0;
+}
+
+
+/*
+ * op_shared_rename() -- common frontend code for modDN operations.
+ *
+ * Beware: this function resets the following pblock elements that were
+ * set by the caller:
+ *
+ * SLAPI_MODRDN_TARGET
+ * SLAPI_MODRDN_NEWRDN
+ * SLAPI_MODRDN_NEWSUPERIOR
+ */
+static void
+op_shared_rename(Slapi_PBlock *pb, int passin_args)
+{
+ char *dn, *newsuperior, *newrdn, *newdn = NULL;
+ char **rdns;
+ int deloldrdn;
+ Slapi_Backend *be = NULL;
+ Slapi_DN sdn;
+ Slapi_Mods smods;
+ char dnbuf[BUFSIZ];
+ char newrdnbuf[BUFSIZ];
+ char newsuperiorbuf[BUFSIZ];
+ int internal_op, repl_op, lastmod;
+ Slapi_Operation *operation;
+ Slapi_Entry *referral;
+ char errorbuf[BUFSIZ];
+ int err;
+
+ slapi_pblock_get(pb, SLAPI_ORIGINAL_TARGET, &dn);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &newrdn);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &newsuperior);
+ slapi_pblock_get(pb, SLAPI_MODRDN_DELOLDRDN, &deloldrdn);
+ slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+ internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
+
+ /*
+ * If ownership has not been passed to this function, we replace the
+ * string input fields within the pblock with strdup'd copies. Why?
+ * Because some pre- and post-op plugins may change them, and the
+ * convention is that plugins should place a malloc'd string in the
+ * pblock. Therefore, we need to be able to retrieve and free them
+ * later. But the callers of the internal modrdn calls are promised
+ * that we will not free these parameters... so if passin_args is
+ * zero, we need to make copies.
+ *
+ * In the case of SLAPI_MODRDN_TARGET and SLAPI_MODRDN_NEWSUPERIOR, we
+ * replace the existing values with normalized values (because plugins
+ * expect these DNs to be normalized).
+ */
+ if ( passin_args ) {
+ slapi_sdn_init_dn_passin(&sdn,dn); /* freed by slapi_sdn_done() */
+ } else {
+ slapi_sdn_init_dn_byref(&sdn,dn);
+ }
+ if ( !passin_args ) {
+ newrdn = slapi_ch_strdup( newrdn );
+ newsuperior = slapi_ch_strdup( newsuperior );
+ }
+ if ( NULL != newsuperior ) {
+ slapi_dn_normalize_case( newsuperior ); /* normalize in place */
+ }
+ slapi_pblock_set (pb, SLAPI_MODRDN_TARGET,
+ (void*)slapi_ch_strdup(slapi_sdn_get_ndn (&sdn)));
+ slapi_pblock_set(pb, SLAPI_MODRDN_NEWRDN, (void *)newrdn );
+ slapi_pblock_set(pb, SLAPI_MODRDN_NEWSUPERIOR, (void *)newsuperior);
+
+ /*
+ * first, log the operation to the access log,
+ * then check rdn and newsuperior,
+ * and - if applicable - log reason of any error to the errors log
+ */
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ if ( !internal_op )
+ {
+ slapi_log_access(LDAP_DEBUG_STATS,
+ "conn=%d op=%d MODRDN dn=\"%s\" newrdn=\"%s\" newsuperior=\"%s\"\n",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ escape_string(dn, dnbuf),
+ (NULL == newrdn) ? "(null)" : escape_string(newrdn, newrdnbuf),
+ (NULL == newsuperior) ? "(null)" : escape_string(newsuperior, newsuperiorbuf));
+ }
+ else
+ {
+ slapi_log_access(LDAP_DEBUG_ARGS,
+ "conn=%s op=%d MODRDN dn=\"%s\" newrdn=\"%s\" newsuperior=\"%s\"\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ escape_string(dn, dnbuf),
+ (NULL == newrdn) ? "(null)" : escape_string(newrdn, newrdnbuf),
+ (NULL == newsuperior) ? "(null)" : escape_string(newsuperior, newsuperiorbuf));
+ }
+ }
+
+ /* check that the rdn is formatted correctly */
+ if ((rdns = ldap_explode_rdn(newrdn, 0)) == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "conn=%d op=%d MODRDN invalid new RDN (\"%s\")\n",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ (NULL == newrdn) ? "(null)" : newrdn);
+ send_ldap_result(pb, LDAP_INVALID_DN_SYNTAX, NULL, "invalid RDN", 0, NULL);
+ goto free_and_return_nolock;
+ }
+ else
+ {
+ ldap_value_free(rdns);
+ }
+
+ /* check that the dn is formatted correctly */
+ if ((rdns = ldap_explode_dn(newsuperior, 0)) == NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ARGS, "ldap_explode_dn of newSuperior failed\n", 0, 0, 0);
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "conn=%d op=%d MODRDN invalid new superior (\"%s\")",
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ (NULL == newsuperior) ? "(null)" : newsuperiorbuf);
+ send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL,
+ "newSuperior does not look like a DN", 0, NULL);
+ goto free_and_return_nolock;
+ }
+ else
+ {
+ ldap_value_free(rdns);
+ }
+
+ if (newsuperior != NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ARGS, "do_moddn: newsuperior (%s)\n", newsuperior, 0, 0);
+ }
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ operation_set_target_spec (pb->pb_op, &sdn);
+
+ /*
+ * Construct the new DN (code copied from backend
+ * and modified to handle newsuperior)
+ */
+ newdn = slapi_moddn_get_newdn(&sdn,newrdn,newsuperior);
+
+ /*
+ * We could be serving multiple database backends. Select the
+ * appropriate one, or send a referral to our "referral server"
+ * if we don't hold it.
+ */
+ if ((err = slapi_mapping_tree_select_and_check(pb, newdn, &be, &referral, errorbuf)) != LDAP_SUCCESS)
+ {
+ send_ldap_result(pb, err, NULL, errorbuf, 0, NULL);
+ goto free_and_return_nolock;
+ }
+
+ if (referral)
+ {
+ int managedsait;
+
+ slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ if (managedsait)
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "cannot update referral", 0, NULL);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ send_referrals_from_entry(pb,referral);
+ slapi_entry_free(referral);
+ goto free_and_return;
+ }
+
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+
+ /* can get lastmod only after backend is selected */
+ slapi_pblock_get(pb, SLAPI_BE_LASTMOD, &lastmod);
+
+ /* if it is a replicated operation - leave lastmod attributes alone */
+ slapi_mods_init (&smods, 2);
+ if (!repl_op && lastmod)
+ {
+ modify_update_last_modified_attr(pb, &smods);
+ slapi_pblock_set(pb, SLAPI_MODIFY_MODS, (void*)slapi_mods_get_ldapmods_passout(&smods));
+ }
+ else {
+ slapi_mods_done (&smods);
+ }
+
+ /*
+ * call the pre-modrdn plugins. if they succeed, call
+ * the backend modrdn function. then call the
+ * post-modrdn plugins.
+ */
+ if (plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN :
+ SLAPI_PLUGIN_PRE_MODRDN_FN) == 0)
+ {
+ int rc= LDAP_OPERATIONS_ERROR;
+ slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
+ set_db_default_result_handlers(pb);
+ if (be->be_modrdn != NULL)
+ {
+ if ((rc = (*be->be_modrdn)(pb)) == 0)
+ {
+ Slapi_Entry *pse;
+ Slapi_Entry *ecopy;
+ /* we don't perform acl check for internal operations */
+ /* dont update aci store for remote acis */
+ if ((!internal_op) &&
+ (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
+ plugin_call_acl_mods_update (pb, SLAPI_OPERATION_MODRDN);
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_AUDIT))
+ write_audit_log_entry(pb); /* Record the operation in the audit log */
+
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
+ /* GGOODREPL persistent search system needs the changenumber, oops. */
+ do_ps_service(pse, ecopy, LDAP_CHANGETYPE_MODDN, 0UL);
+ }
+ }
+ else
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Function not implemented", 0, NULL);
+ }
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ plugin_call_plugins(pb, internal_op ? SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN :
+ SLAPI_PLUGIN_POST_MODRDN_FN);
+ }
+
+free_and_return:
+ if (be)
+ slapi_be_Unlock(be);
+free_and_return_nolock:
+ {
+ /* Free up everything left in the PBlock */
+ Slapi_Entry *pse;
+ Slapi_Entry *ecopy;
+ LDAPMod **mods;
+ char *s;
+
+ slapi_ch_free((void **) &newdn);
+ slapi_sdn_done(&sdn);
+ slapi_pblock_get(pb, SLAPI_ENTRY_PRE_OP, &ecopy);
+ slapi_entry_free(ecopy);
+ slapi_pblock_get(pb, SLAPI_ENTRY_POST_OP, &pse);
+ slapi_entry_free(pse);
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ ldap_mods_free( mods, 1 );
+
+ /* retrieve these in case a pre- or post-op plugin has changed them */
+ slapi_pblock_get(pb, SLAPI_MODRDN_TARGET, &s);
+ slapi_ch_free((void **)&s);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWRDN, &s);
+ slapi_ch_free((void **)&s);
+ slapi_pblock_get(pb, SLAPI_MODRDN_NEWSUPERIOR, &s);
+ slapi_ch_free((void **)&s);
+ slapi_pblock_get(pb, SLAPI_URP_NAMING_COLLISION_DN, &s);
+ slapi_ch_free((void **)&s);
+ }
+}
diff --git a/ldap/servers/slapd/modutil.c b/ldap/servers/slapd/modutil.c
new file mode 100644
index 00000000..ac5d2c5d
--- /dev/null
+++ b/ldap/servers/slapd/modutil.c
@@ -0,0 +1,774 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* modutil.c - modify utility routine */
+
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif /* _WIN32 */
+#include "slap.h"
+
+#define SIZE_INIT 4 /* initial element size */
+#define SIZE_INC 2 /* size increment */
+/*
+ * Free an array of LDAPMod structures. Just like ldap_mods_free,
+ * except that it assumes that the mods are expressed as a bervec.
+ */
+void
+freepmods( LDAPMod **pmods )
+{
+ int i;
+
+ for ( i = 0; pmods[ i ] != NULL; ++i ) {
+ if ( pmods[ i ]->mod_bvalues != NULL ) {
+ ber_bvecfree( pmods[ i ]->mod_bvalues );
+ }
+ if ( pmods[ i ]->mod_type != NULL ) {
+ slapi_ch_free((void**)&pmods[ i ]->mod_type );
+ }
+ slapi_ch_free((void**)&pmods[ i ] );
+ }
+ slapi_ch_free((void**)&pmods );
+}
+
+/* ======= Utility functions for manipulating a list of LDAPMods ======= */
+
+/*
+ * Slapi_Mods can be used in two ways:
+ * 1) To wrap an existing array of LDAPMods, or
+ * 2) To create a new array of LDAPMods.
+ *
+ * Slapi_Mods provides memory management and array manipulation
+ * functions to make using (LDAPMod**) easier.
+ *
+ */
+
+Slapi_Mods*
+slapi_mods_new()
+{
+ Slapi_Mods *mods;
+ mods = (Slapi_Mods*) slapi_ch_calloc (1, sizeof (Slapi_Mods));
+ return mods;
+}
+
+/*
+ * Initialise a Slapi_Mod suggesting how big an LDAPMod array is needed.
+ * It will be free'd when the Slapi_Mods is destroyed.
+ */
+void
+slapi_mods_init(Slapi_Mods *smods, int initCount)
+{
+ memset (smods, 0, sizeof (*smods));
+ smods->free_mods = 1;
+ if (initCount > 0)
+ {
+ smods->num_elements= initCount + 1; /* one for NULL element */
+ smods->mods = (LDAPMod **) slapi_ch_calloc( 1, smods->num_elements * sizeof(LDAPMod *) );
+ }
+}
+
+/*
+ * Initialise a Slapi_Mod passing in responsibility for the (LDAPMod **).
+ * It will be free'd when the Slapi_Mods is destroyed.
+ */
+void
+slapi_mods_init_passin(Slapi_Mods *smods, LDAPMod **mods)
+{
+ slapi_mods_init_byref(smods, mods);
+ smods->free_mods = 1;
+}
+
+/*
+ * Initialise a Slapi_Mod passing in a reference to the (LDAPMod **)
+ * It will *not* be free'd when the Slapi_Mods is destroyed.
+ */
+void
+slapi_mods_init_byref(Slapi_Mods *smods, LDAPMod **mods)
+{
+ memset (smods, 0, sizeof (*smods));
+ if(mods!=NULL)
+ {
+ smods->mods = mods;
+ for ( smods->num_mods = 0; mods[smods->num_mods] != NULL; smods->num_mods++ );
+ smods->num_elements= smods->num_mods+1; /* We assume there's nothing spare on the end. */
+ }
+}
+
+void
+slapi_mods_free(Slapi_Mods **smods)
+{
+ if(smods!=NULL && *smods!=NULL)
+ {
+ slapi_mods_done(*smods);
+ slapi_ch_free ((void**)smods);
+ *smods= NULL;
+ }
+}
+
+void
+slapi_mods_done(Slapi_Mods *smods)
+{
+ PR_ASSERT(smods!=NULL);
+ if (smods->mods!=NULL)
+ {
+ if(smods->free_mods)
+ {
+ ldap_mods_free (smods->mods, 1 /* Free the Array and the Elements */);
+ }
+ }
+ memset (smods, 0, sizeof(smods));
+}
+
+static void
+slapi_mods_add_one_element(Slapi_Mods *smods)
+{
+ int need = smods->num_mods + 2;
+ if ( smods->num_elements == 0 )
+ {
+ PR_ASSERT(smods->mods==NULL);
+ smods->num_elements = SIZE_INIT;
+ smods->mods = (LDAPMod **) slapi_ch_malloc( smods->num_elements * sizeof(LDAPMod *) );
+ smods->free_mods= 1;
+ }
+ if ( smods->num_elements < need )
+ {
+ PR_ASSERT(smods->free_mods);
+ smods->num_elements *= SIZE_INC;
+ smods->mods = (LDAPMod **) slapi_ch_realloc( (char *) smods->mods, smods->num_elements * sizeof(LDAPMod *) );
+ }
+}
+
+/*
+ * Shift everything down to make room to insert the new mod.
+ */
+void
+slapi_mods_insert_at(Slapi_Mods *smods, LDAPMod *mod, int pos)
+{
+ int i;
+ slapi_mods_add_one_element(smods);
+ for( i=smods->num_mods-1; i>=pos; i--)
+ {
+ smods->mods[i+1]= smods->mods[i];
+ }
+ smods->mods[pos]= mod;
+ smods->num_mods++;
+ smods->mods[smods->num_mods]= NULL;
+}
+
+void
+slapi_mods_insert_smod_at(Slapi_Mods *smods, Slapi_Mod *smod, int pos)
+{
+ slapi_mods_insert_at (smods, smod->mod, pos);
+}
+
+/*
+ * Shift everything down to make room to insert the new mod.
+ */
+void
+slapi_mods_insert_before(Slapi_Mods *smods, LDAPMod *mod)
+{
+ slapi_mods_insert_at(smods, mod, smods->iterator);
+ smods->iterator++;
+}
+
+void
+slapi_mods_insert_smod_before(Slapi_Mods *smods, Slapi_Mod *smod)
+{
+ slapi_mods_insert_before(smods, smod->mod);
+}
+
+/*
+ * Shift everything down to make room to insert the new mod.
+ */
+void
+slapi_mods_insert_after(Slapi_Mods *smods, LDAPMod *mod)
+{
+ slapi_mods_insert_at(smods, mod, smods->iterator+1);
+}
+
+void slapi_mods_insert_smod_after(Slapi_Mods *smods, Slapi_Mod *smod)
+{
+ slapi_mods_insert_after(smods, smod->mod);
+}
+
+/*
+ * Add the LDAPMod to the end of the array.
+ * Does NOT copy the mod.
+ */
+void
+slapi_mods_add_ldapmod(Slapi_Mods *smods, LDAPMod *mod)
+{
+ slapi_mods_insert_at(smods,mod,smods->num_mods);
+}
+
+void
+slapi_mods_add_smod(Slapi_Mods *smods, Slapi_Mod *smod)
+{
+ slapi_mods_add_ldapmod(smods, smod->mod);
+}
+
+/*
+ * Makes a copy of everything.
+ */
+void
+slapi_mods_add_modbvps( Slapi_Mods *smods, int modtype, const char *type, struct berval **bvps )
+{
+ LDAPMod *mod;
+
+ mod = (LDAPMod *) slapi_ch_malloc(sizeof(LDAPMod));
+ mod->mod_type = slapi_ch_strdup( type );
+ mod->mod_op = modtype | LDAP_MOD_BVALUES;
+ mod->mod_bvalues = NULL;
+
+ if (NULL != bvps)
+ {
+ int num_values, i;
+ num_values = 0;
+ /* Count mods */
+ while (NULL != bvps[num_values])
+ {
+ num_values++;
+ }
+ mod->mod_bvalues = (struct berval **)slapi_ch_malloc((num_values + 1) *
+ sizeof(struct berval *));
+ for (i = 0; i < num_values; i++)
+ {
+ mod->mod_bvalues[i] = ber_bvdup((struct berval *)bvps[i]); /* jcm had to cast away const */
+ }
+ mod->mod_bvalues[num_values] = NULL;
+ }
+ slapi_mods_add_ldapmod(smods, mod);
+}
+
+/*
+ * Makes a copy of everything.
+ */
+void
+slapi_mods_add_mod_values( Slapi_Mods *smods, int modtype, const char *type, Slapi_Value **va )
+{
+ LDAPMod *mod= (LDAPMod *) slapi_ch_malloc( sizeof(LDAPMod) );
+ mod->mod_type = slapi_ch_strdup( type );
+ mod->mod_op = modtype | LDAP_MOD_BVALUES;
+ mod->mod_bvalues= NULL;
+ valuearray_get_bervalarray(va,&mod->mod_bvalues);
+ slapi_mods_add_ldapmod(smods, mod);
+}
+
+/*
+ * Makes a copy of everything.
+ */
+void
+slapi_mods_add( Slapi_Mods *smods, int modtype, const char *type, unsigned long len, const char *val)
+{
+ struct berval bv;
+ struct berval *bvps[2];
+ if(len>0)
+ {
+ bv.bv_len= len;
+ bv.bv_val= (void*)val; /* We cast away the const, but we're not going to change anything */
+ bvps[0] = &bv;
+ bvps[1] = NULL;
+ }
+ else
+ {
+ bvps[0]= NULL;
+ }
+ slapi_mods_add_modbvps( smods, modtype, type, bvps );
+}
+
+/*
+ * Makes a copy of everything.
+ */
+void
+slapi_mods_add_string( Slapi_Mods *smods, int modtype, const char *type, const char *val)
+{
+ slapi_mods_add( smods, modtype, type, strlen(val), val);
+}
+
+void
+slapi_mods_remove(Slapi_Mods *smods)
+{
+ smods->mods[smods->iterator]->mod_op= LDAP_MOD_IGNORE;
+}
+
+LDAPMod *
+slapi_mods_get_first_mod(Slapi_Mods *smods)
+{
+ /* Reset the iterator in the mod structure */
+ smods->iterator= -1;
+ return slapi_mods_get_next_mod(smods);
+}
+
+LDAPMod *
+slapi_mods_get_next_mod(Slapi_Mods *smods)
+{
+ /* Move the iterator forward */
+ LDAPMod *r= NULL;
+ smods->iterator++;
+
+ PR_ASSERT (smods->iterator >= 0);
+
+ /* skip deleted mods if any */
+ while (smods->iterator < smods->num_mods && smods->mods[smods->iterator]->mod_op == LDAP_MOD_IGNORE)
+ smods->iterator ++;
+
+ if(smods->iterator<smods->num_mods)
+ {
+ r= smods->mods[smods->iterator];
+ }
+ return r;
+}
+
+static void
+mod2smod (LDAPMod *mod, Slapi_Mod *smod)
+{
+ smod->mod = mod;
+ smod->iterator = 0;
+ smod->num_values = 0;
+
+ if (mod->mod_op & LDAP_MOD_BVALUES)
+ {
+ while (mod->mod_bvalues[smod->num_values])
+ {
+ smod->num_values ++;
+ }
+ }
+ else
+ {
+ PR_ASSERT(0); /* ggood shouldn't ever use string values in server */
+ while (mod->mod_values[smod->num_values])
+ {
+ smod->num_values ++;
+ }
+ }
+
+ smod->num_elements = smod->num_values + 1; /* 1- for null char */
+}
+
+Slapi_Mod *
+slapi_mods_get_first_smod(Slapi_Mods *smods, Slapi_Mod *smod)
+{
+ LDAPMod *mod = slapi_mods_get_first_mod (smods);
+
+ if (mod == NULL)
+ return NULL;
+
+ mod2smod (mod, smod);
+
+ return smod;
+}
+
+Slapi_Mod *
+slapi_mods_get_next_smod(Slapi_Mods *smods, Slapi_Mod *smod)
+{
+ LDAPMod *mod = slapi_mods_get_next_mod(smods);
+
+ if (mod == NULL)
+ {
+ return NULL;
+ }
+ else
+ {
+ mod2smod(mod, smod);
+ }
+ return smod;
+}
+
+void
+slapi_mods_iterator_backone(Slapi_Mods *smods)
+{
+ smods->iterator--;
+}
+
+
+static void
+pack_mods(LDAPMod ***modsp)
+{
+ LDAPMod **mods = NULL;
+ if (NULL != modsp && NULL != *modsp)
+ {
+ int i;
+ int num_slots;
+ int src_index, dst_index;
+ mods = *modsp;
+
+ /* Make a pass through the array, freeing any marked LDAP_MODS_IGNORE */
+ i = 0;
+ while (NULL != mods[i])
+ {
+ if (LDAP_MOD_IGNORE == (mods[i]->mod_op & ~LDAP_MOD_BVALUES))
+ {
+ /* Free current slot */
+ slapi_ch_free((void**)&mods[i]->mod_type);
+ ber_bvecfree(mods[i]->mod_bvalues);
+ slapi_ch_free((void **)&mods[i]);
+ }
+ i++;
+ }
+ num_slots = i + 1; /* Remember total number of slots */
+
+ /* Make another pass, packing the array */
+ dst_index = src_index = 0;
+ while (src_index < num_slots)
+ {
+ if (NULL != mods[src_index])
+ {
+ mods[dst_index] = mods[src_index];
+ dst_index++;
+ }
+ src_index++;
+ }
+ mods[dst_index] = NULL;
+ if (NULL == mods[0])
+ {
+ /* Packed it down to size zero - deallocate */
+ slapi_ch_free((void **)modsp);
+ }
+ }
+}
+
+
+LDAPMod **
+slapi_mods_get_ldapmods_byref(Slapi_Mods *smods)
+{
+ pack_mods(&smods->mods); /* XXXggood const gets in the way of this */
+ return smods->mods;
+}
+
+LDAPMod **
+slapi_mods_get_ldapmods_passout(Slapi_Mods *smods)
+{
+ LDAPMod **mods;
+ pack_mods(&smods->mods);
+ mods = smods->mods;
+ smods->free_mods = 0;
+ slapi_mods_done(smods);
+ return mods;
+}
+
+int
+slapi_mods_get_num_mods(const Slapi_Mods *smods)
+{
+ return smods->num_mods;
+}
+
+void
+slapi_mods_dump(const Slapi_Mods *smods, const char *text)
+{
+ int i;
+ LDAPDebug( LDAP_DEBUG_ANY, "smod - %s\n", text, 0, 0);
+ for(i=0;i<smods->num_mods;i++)
+ {
+ slapi_mod_dump(smods->mods[i],i);
+ }
+}
+
+/* ======== Utility functions for manipulating an LDAPMod ======= */
+
+/*
+ * Slapi_Mod can be used in two ways:
+ * 1) To wrap an existing array of LDAPMods, or
+ * 2) To create a new array of LDAPMods.
+ *
+ * Slapi_Mods provides memory management and array manipulation
+ * functions to make using (LDAPMod**) easier.
+ *
+ */
+
+Slapi_Mod *
+slapi_mod_new ()
+{
+ Slapi_Mod *mod = (Slapi_Mod*)slapi_ch_calloc (1, sizeof (Slapi_Mod));
+ return mod;
+}
+
+void
+slapi_mod_init(Slapi_Mod *smod, int initCount)
+{
+ PR_ASSERT(smod!=NULL);
+ memset (smod, 0, sizeof (*smod));
+ smod->free_mod= 1;
+ smod->num_elements = initCount + 1;
+ smod->mod = (LDAPMod *)slapi_ch_calloc (1, sizeof (LDAPMod));
+ if (smod->num_elements)
+ smod->mod->mod_bvalues = (struct berval**)slapi_ch_calloc (smod->num_elements, sizeof (struct berval*));
+}
+
+void
+slapi_mod_init_passin(Slapi_Mod *smod, LDAPMod *mod)
+{
+ PR_ASSERT(smod!=NULL);
+ memset (smod, 0, sizeof (*smod));
+ smod->free_mod= 1;
+ if (mod!=NULL)
+ {
+ smod->mod= mod;
+ if(smod->mod->mod_bvalues!=NULL)
+ {
+ while (smod->mod->mod_bvalues[smod->num_values]!=NULL)
+ smod->num_values++;
+ smod->num_elements= smod->num_values +1; /* We assume there's nothing spare on the end. */
+ }
+ }
+}
+
+void
+slapi_mod_init_byref(Slapi_Mod *smod, LDAPMod *mod)
+{
+ PR_ASSERT(smod!=NULL);
+ memset (smod, 0, sizeof (*smod));
+ if (mod!=NULL)
+ {
+ smod->mod= mod;
+ if(smod->mod->mod_bvalues!=NULL)
+ {
+ while (smod->mod->mod_bvalues[smod->num_values]!=NULL)
+ smod->num_values++;
+ smod->num_elements= smod->num_values +1; /* We assume there's nothing spare on the end. */
+ }
+ }
+}
+
+void
+slapi_mod_init_byval (Slapi_Mod *smod, const LDAPMod *mod)
+{
+ PR_ASSERT(smod!=NULL);
+ memset (smod, 0, sizeof (*smod));
+ if (mod!=NULL)
+ {
+ smod->mod = (LDAPMod *)slapi_ch_calloc (1, sizeof (LDAPMod));
+ smod->free_mod = 1;
+ slapi_mod_set_operation (smod, mod->mod_op);
+ slapi_mod_set_type (smod, mod->mod_type);
+ if(mod->mod_bvalues!=NULL)
+ {
+ while (mod->mod_bvalues[smod->num_values]!=NULL)
+ {
+ slapi_mod_add_value (smod, mod->mod_bvalues[smod->num_values]);
+ }
+ }
+ }
+}
+
+void
+slapi_mod_free (Slapi_Mod **smod)
+{
+ slapi_mod_done(*smod);
+ slapi_ch_free((void**)smod);
+ *smod= NULL;
+}
+
+void
+slapi_mod_done(Slapi_Mod *smod)
+{
+ PR_ASSERT(smod!=NULL);
+ if(smod->free_mod)
+ {
+ ber_bvecfree(smod->mod->mod_bvalues);
+ slapi_ch_free((void**)&(smod->mod->mod_type));
+ slapi_ch_free((void**)&(smod->mod));
+ }
+ memset (smod, 0, sizeof(smod));
+}
+
+/*
+ * Add a value to the list of values in the modification.
+ */
+void
+slapi_mod_add_value(Slapi_Mod *smod, const struct berval *val)
+{
+ PR_ASSERT(smod!=NULL);
+ PR_ASSERT(val!=NULL);
+/* PR_ASSERT(slapi_mod_get_operation(smod) & LDAP_MOD_BVALUES);*/
+
+ bervalarray_add_berval_fast(&(smod->mod->mod_bvalues),(struct berval*)val,smod->num_values,&smod->num_elements);
+ smod->num_values++;
+}
+
+/*
+ * Remove the value at the iterator from the list of values in
+ * the LDAP modification.
+ */
+void
+slapi_mod_remove_value(Slapi_Mod *smod)
+{
+ /* loop over the mod values moving them down to cover up the value to be removed */
+ struct berval **vals;
+ int i, k;
+ PR_ASSERT(smod!=NULL);
+ PR_ASSERT(smod->mod!=NULL);
+ vals= smod->mod->mod_bvalues;
+ i= smod->iterator-1;
+ ber_bvfree( vals[i] );
+ for ( k = i + 1; vals[k] != NULL; k++ ) {
+ vals[k - 1] = vals[k];
+ }
+ vals[k - 1] = NULL;
+ /* Reset the iterator */
+ smod->num_values--;
+ smod->iterator--;
+}
+
+struct berval *
+slapi_mod_get_first_value(Slapi_Mod *smod)
+{
+ PR_ASSERT(smod!=NULL);
+ /* Reset the iterator in the mod structure */
+ smod->iterator= 0;
+ return slapi_mod_get_next_value(smod);
+}
+
+struct berval *
+slapi_mod_get_next_value(Slapi_Mod *smod)
+{
+ /* Move the iterator forward */
+ struct berval *r= NULL;
+ PR_ASSERT(smod!=NULL);
+ PR_ASSERT(smod->mod!=NULL);
+ if(smod->iterator<smod->num_values)
+ {
+ r= smod->mod->mod_bvalues[smod->iterator];
+ smod->iterator++;
+ }
+ return r;
+}
+
+int
+slapi_mod_get_num_values(const Slapi_Mod *smod)
+{
+ PR_ASSERT(smod!=NULL);
+ return smod->num_values;
+}
+
+const char *
+slapi_mod_get_type (const Slapi_Mod *smod)
+{
+ PR_ASSERT(smod!=NULL);
+ PR_ASSERT(smod->mod!=NULL);
+ return smod->mod->mod_type;
+}
+
+int
+slapi_mod_get_operation (const Slapi_Mod *smod)
+{
+ PR_ASSERT(smod!=NULL);
+ PR_ASSERT(smod->mod!=NULL);
+ return smod->mod->mod_op;
+}
+
+void
+slapi_mod_set_type (Slapi_Mod *smod, const char *type)
+{
+ PR_ASSERT(smod!=NULL);
+ PR_ASSERT(smod->mod!=NULL);
+ if(smod->mod->mod_type!=NULL)
+ {
+ slapi_ch_free((void**)&smod->mod->mod_type);
+ }
+ smod->mod->mod_type = slapi_ch_strdup (type);
+}
+
+void
+slapi_mod_set_operation (Slapi_Mod *smod, int op)
+{
+ PR_ASSERT(smod!=NULL);
+ PR_ASSERT(smod->mod!=NULL);
+ smod->mod->mod_op = op;
+}
+
+const LDAPMod *
+slapi_mod_get_ldapmod_byref(const Slapi_Mod *smod)
+{
+ PR_ASSERT(smod!=NULL);
+ return smod->mod;
+}
+
+LDAPMod *
+slapi_mod_get_ldapmod_passout(Slapi_Mod *smod)
+{
+ LDAPMod *mod;
+ PR_ASSERT(smod!=NULL);
+ mod= smod->mod;
+ smod->free_mod= 0;
+ slapi_mod_done(smod);
+ return mod;
+}
+
+/* a valid LDAPMod is one with operation of LDAP_MOD_ADD, *_DELETE, *_REPLACE
+ ored with LDAP_MOD_BVALUES; non-null type and at list one value
+ for add and replace operations
+ */
+int
+slapi_mod_isvalid (const Slapi_Mod *mod)
+{
+ int op;
+
+ if (mod == NULL || mod->mod == NULL)
+ return 0;
+
+ op = mod->mod->mod_op && ~LDAP_MOD_BVALUES;
+
+ if (op != LDAP_MOD_ADD && op != LDAP_MOD_DELETE && op != LDAP_MOD_REPLACE)
+ return 0;
+
+ if (mod->mod->mod_type == NULL)
+ return 0;
+
+ if (op != LDAP_MOD_DELETE && mod->num_values == 0)
+ return 0;
+
+ return 1;
+}
+
+void
+slapi_mod_dump(LDAPMod *mod, int n)
+{
+ if(mod!=NULL)
+ {
+ int operationtype= mod->mod_op & ~LDAP_MOD_BVALUES;
+ switch ( operationtype )
+ {
+ case LDAP_MOD_ADD:
+ LDAPDebug( LDAP_DEBUG_ANY, "smod %d - add: %s\n", n, mod->mod_type, 0);
+ break;
+
+ case LDAP_MOD_DELETE:
+ LDAPDebug( LDAP_DEBUG_ANY, "smod %d - delete: %s\n", n, mod->mod_type, 0);
+ break;
+
+ case LDAP_MOD_REPLACE:
+ LDAPDebug( LDAP_DEBUG_ANY, "smod %d - replace: %s\n", n, mod->mod_type, 0);
+ break;
+
+ case LDAP_MOD_IGNORE:
+ LDAPDebug( LDAP_DEBUG_ANY, "smod %d - ignore: %s\n", n, mod->mod_type, 0);
+ break;
+ }
+ if(operationtype!=LDAP_MOD_IGNORE)
+ {
+ int i;
+ for ( i = 0; mod->mod_bvalues != NULL && mod->mod_bvalues[i] != NULL; i++ )
+ {
+ char *buf, *bufp;
+ int len = strlen( mod->mod_type );
+ len = LDIF_SIZE_NEEDED( len, mod->mod_bvalues[i]->bv_len ) + 1;
+ buf = slapi_ch_malloc( len );
+ bufp = buf;
+ ldif_put_type_and_value( &bufp, mod->mod_type, mod->mod_bvalues[i]->bv_val, mod->mod_bvalues[i]->bv_len );
+ *bufp = '\0';
+ LDAPDebug( LDAP_DEBUG_ANY, "smod %d - value: %s", n, buf, 0);
+ slapi_ch_free( (void**)&buf );
+ }
+ }
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "smod - null\n", 0, 0, 0);
+ }
+}
diff --git a/ldap/servers/slapd/monitor.c b/ldap/servers/slapd/monitor.c
new file mode 100644
index 00000000..f877e679
--- /dev/null
+++ b/ldap/servers/slapd/monitor.c
@@ -0,0 +1,176 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+#include "fe.h"
+
+#if defined( SLAPD_MONITOR_DN )
+
+
+int
+monitor_info(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg)
+{
+ char buf[BUFSIZ];
+ struct berval val;
+ struct berval *vals[2];
+ time_t curtime = current_time();
+ struct tm utm;
+ Slapi_Backend *be;
+ char *cookie;
+ PRUint32 len;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* "version" value */
+ val.bv_val = slapd_get_version_value();
+ val.bv_len = strlen( val.bv_val );
+ attrlist_replace( &e->e_attrs, "version", vals );
+ slapi_ch_free( (void **) &val.bv_val );
+
+ sprintf( buf, "%d", active_threads );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "threads", vals );
+
+ connection_table_as_entry(the_connection_table, e);
+
+ PR_Lock( ops_mutex );
+ sprintf( buf, "%ld", (long) ops_initiated );
+ PR_Unlock( ops_mutex );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "opsinitiated", vals );
+
+ PR_Lock( ops_mutex );
+ sprintf( buf, "%ld", (long) ops_completed );
+ PR_Unlock( ops_mutex );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "opscompleted", vals );
+
+ PR_Lock( g_get_num_sent_mutex() );
+ len = PR_snprintf ( buf, BUFSIZ, "%llu", g_get_num_entries_sent() );
+ PR_Unlock( g_get_num_sent_mutex() );
+ val.bv_val = buf;
+ val.bv_len = ( unsigned long ) len;
+ attrlist_replace( &e->e_attrs, "entriessent", vals );
+
+ PR_Lock( g_get_num_sent_mutex() );
+ len = PR_snprintf ( buf, BUFSIZ, "%llu", g_get_num_bytes_sent() );
+ PR_Unlock( g_get_num_sent_mutex() );
+ val.bv_val = buf;
+ val.bv_len = ( unsigned long ) len;
+ attrlist_replace( &e->e_attrs, "bytessent", vals );
+
+#ifdef _WIN32
+ {
+ struct tm *pt;
+ pt = gmtime( &curtime );
+ memcpy(&utm, pt, sizeof(struct tm) );
+ }
+#else
+ gmtime_r( &curtime, &utm );
+#endif
+ strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", &utm );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "currenttime", vals );
+
+#ifdef _WIN32
+ {
+ struct tm *pt;
+ pt = gmtime( &starttime );
+ memcpy(&utm, pt, sizeof(struct tm) );
+ }
+#else
+ gmtime_r( &starttime, &utm );
+#endif
+ strftime( buf, sizeof(buf), "%Y%m%d%H%M%SZ", &utm );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "starttime", vals );
+
+ sprintf( buf, "%d", be_nbackends_public() );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "nbackends", vals );
+
+#ifdef THREAD_SUNOS5_LWP
+ sprintf( buf, "%d", thr_getconcurrency() );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "concurrency", vals );
+#endif
+
+ /*Loop through the backends, and stuff the monitordns
+ into the entry we're sending back*/
+ attrlist_delete( &e->e_attrs, "backendmonitordn");
+ cookie = NULL;
+ be = slapi_get_first_backend(&cookie);
+ while (be)
+ {
+ if ( !be->be_private )
+ {
+ Slapi_DN dn;
+ slapi_sdn_init(&dn);
+ be_getmonitordn(be,&dn);
+ val.bv_val = (char*)slapi_sdn_get_dn(&dn);
+ val.bv_len = strlen( val.bv_val );
+ attrlist_merge( &e->e_attrs, "backendmonitordn", vals );
+ slapi_sdn_done(&dn);
+ }
+ be = slapi_get_next_backend(cookie);
+ }
+
+ slapi_ch_free((void **)&cookie);
+
+ *returncode= LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+#endif /* SLAPD_MONITOR_DN */
+
+
+/*
+ * Return a malloc'd version value.
+ * Used for the monitor entry's 'version' attribute.
+ * Used for the root DSE's 'vendorVersion' attribute.
+ */
+char *
+slapd_get_version_value( void )
+{
+ char *versionstring, *buildnum, *vs;
+
+ versionstring = config_get_versionstring();
+ buildnum = config_get_buildnum();
+
+ vs = slapi_ch_malloc( strlen(versionstring) + strlen( buildnum) + 3 );
+ sprintf( vs, "%s B%s", versionstring, buildnum );
+
+ slapi_ch_free( (void **) &buildnum);
+ slapi_ch_free( (void **) &versionstring);
+
+ return vs;
+}
diff --git a/ldap/servers/slapd/ntmsgdll/Makefile b/ldap/servers/slapd/ntmsgdll/Makefile
new file mode 100644
index 00000000..06b7a1bc
--- /dev/null
+++ b/ldap/servers/slapd/ntmsgdll/Makefile
@@ -0,0 +1,62 @@
+#
+# 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 NT messages DLL
+#
+
+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 = $(OBJDIR)/ntmsgdll/obj
+BINDIR = $(LDAP_SERVER_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+MSGFILE = slapdmessages30
+
+MSG_SRC = ntslapdmessages
+
+NTMSGDLL = $(addprefix $(BINDIR)/, $(MSGFILE).$(DLL_SUFFIX))
+
+LDAP_MSG_OBJS= $(MSG_SRC).o $(MSG_SRC).res
+
+OBJS = $(addprefix $(OBJDEST)/, $(LDAP_MSG_OBJS))
+
+clientSDK: all
+
+all: $(OBJDEST) $(BINDIR) $(NTMSGDLL)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ $(RM) $(OBJDEST)/msg00001.bin
+ $(RM) $(LDAP_HDIR)/$(MSG_SRC).h
+ $(RM) $(OBJDEST)/$(MSG_SRC).rc
+ $(RM) $(NTMSGDLL)
+
+$(OBJDEST):
+ $(MKDIR) $@
+
+$(NTMSGDLL): $(OBJS) $(LDAP_HDIR)/$(MSG_SRC).h
+ $(LINK_DLL)
+
+$(LDAP_HDIR)/$(MSG_SRC).h: $(MSG_SRC).mc
+
+$(OBJDEST)/msg0001.bin: $(MSG_SRC).mc
+
+$(OBJDEST)/$(MSG_SRC).rc: $(MSG_SRC).mc
+ $(MC) $< -h $(LDAP_HDIR) -r $(OBJDEST)
+
+$(OBJDEST)/$(MSG_SRC).res: $(OBJDEST)/$(MSG_SRC).rc
+ $(RSC) -fo $(OBJDEST)/$(MSG_SRC).res $<
diff --git a/ldap/servers/slapd/ntmsgdll/ntslapdmessages.c b/ldap/servers/slapd/ntmsgdll/ntslapdmessages.c
new file mode 100644
index 00000000..9d8e9ab5
--- /dev/null
+++ b/ldap/servers/slapd/ntmsgdll/ntslapdmessages.c
@@ -0,0 +1,16 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* This is the required stub entry point for the message-table DLL */
+#if defined( _WIN32 )
+#include <windows.h>
+
+BOOL WINAPI DllMain(HINSTANCE hDLL, DWORD dwReason, LPVOID lpReserved)
+{
+ return(TRUE);
+}
+
+#endif /* _WIN32 */
diff --git a/ldap/servers/slapd/ntmsgdll/ntslapdmessages.mc b/ldap/servers/slapd/ntmsgdll/ntslapdmessages.mc
new file mode 100644
index 00000000..242df822
--- /dev/null
+++ b/ldap/servers/slapd/ntmsgdll/ntslapdmessages.mc
@@ -0,0 +1,283 @@
+; /*
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+; Microsoft Developer Support
+; Copyright (c) 1992 Microsoft Corporation
+;
+; This file contains the message definitions for the Win32
+; messages.exe sample program.
+
+
+;-------------------------------------------------------------------------
+; HEADER SECTION
+;
+; The header section defines names and language identifiers for use
+; by the message definitions later in this file. The MessageIdTypedef,
+; SeverityNames, FacilityNames, and LanguageNames keywords are
+; optional and not required.
+;
+;
+;
+; The MessageIdTypedef keyword gives a typedef name that is used in a
+; type cast for each message code in the generated include file. Each
+; message code appears in the include file with the format: #define
+; name ((type) 0xnnnnnnnn) The default value for type is empty, and no
+; type cast is generated. It is the programmer's responsibility to
+; specify a typedef statement in the application source code to define
+; the type. The type used in the typedef must be large enough to
+; accomodate the entire 32-bit message code.
+;
+MessageIdTypedef=DWORD
+;
+; The SeverityNames keyword defines the set of names that are allowed
+; as the value of the Severity keyword in the message definition. The
+; set is delimited by left and right parentheses. Associated with each
+; severity name is a number that, when shifted left by 30, gives the
+; bit pattern to logical-OR with the Facility value and MessageId
+; value to form the full 32-bit message code. The default value of
+; this keyword is:
+;
+; SeverityNames=(
+; Success=0x0
+; Informational=0x1
+; Warning=0x2
+; Error=0x3
+; )
+;
+; Severity values occupy the high two bits of a 32-bit message code.
+; Any severity value that does not fit in two bits is an error. The
+; severity codes can be given symbolic names by following each value
+; with :name
+;
+SeverityNames=(Success=0x0:STATUS_SEVERITY_SUCCESS
+ Informational=0x1:STATUS_SEVERITY_INFORMATIONAL
+ Warning=0x2:STATUS_SEVERITY_WARNING
+ Error=0x3:STATUS_SEVERITY_ERROR
+ )
+;
+; The FacilityNames keyword defines the set of names that are allowed
+; as the value of the Facility keyword in the message definition. The
+; set is delimited by left and right parentheses. Associated with each
+; facility name is a number that, when shift it left by 16 bits, gives
+; the bit pattern to logical-OR with the Severity value and MessageId
+; value to form the full 32-bit message code. The default value of
+; this keyword is:
+;
+; FacilityNames=(
+; System=0x0FF
+; Application=0xFFF
+; )
+;
+; Facility codes occupy the low order 12 bits of the high order
+; 16-bits of a 32-bit message code. Any facility code that does not
+; fit in 12 bits is an error. This allows for 4,096 facility codes.
+; The first 256 codes are reserved for use by the system software. The
+; facility codes can be given symbolic names by following each value
+; with :name
+;
+FacilityNames=(System=0x0FF:FACILITY_SYSTEM
+ Runtime=0x200:FACILITY_RUNTIME
+ Cgi=0x201:FACILITY_CGI
+ Slapd=0x202:FACILITY_SERVICE
+ Network=0x203:FACILITY_NETWORK
+ Startup=0x204:FACILITY_STARTUP
+ Filesytem=0x205:FACILITY_FILESYSTEM
+ Registry=0x206:FACILITY_REGISTRY
+ )
+;
+; The LanguageNames keyword defines the set of names that are allowed
+; as the value of the Language keyword in the message definition. The
+; set is delimited by left and right parentheses. Associated with each
+; language name is a number and a file name that are used to name the
+; generated resource file that contains the messages for that
+; language. The number corresponds to the language identifier to use
+; in the resource table. The number is separated from the file name
+; with a colon. The initial value of LanguageNames is:
+;
+; LanguageNames=(English=1:MSG00001)
+;
+; Any new names in the source file which don't override the built-in
+; names are added to the list of valid languages. This allows an
+; application to support private languages with descriptive names.
+;
+;
+;-------------------------------------------------------------------------
+; MESSAGE DEFINITION SECTION
+;
+; Following the header section is the body of the Message Compiler
+; source file. The body consists of zero or more message definitions.
+; Each message definition begins with one or more of the following
+; statements:
+;
+; MessageId = [number|+number]
+; Severity = severity_name
+; Facility = facility_name
+; SymbolicName = name
+;
+; The MessageId statement marks the beginning of the message
+; definition. A MessageID statement is required for each message,
+; although the value is optional. If no value is specified, the value
+; used is the previous value for the facility plus one. If the value
+; is specified as +number then the value used is the previous value
+; for the facility, plus the number after the plus sign. Otherwise, if
+; a numeric value is given, that value is used. Any MessageId value
+; that does not fit in 16 bits is an error.
+;
+; The Severity and Facility statements are optional. These statements
+; specify additional bits to OR into the final 32-bit message code. If
+; not specified they default to the value last specified for a message
+; definition. The initial values prior to processing the first message
+; definition are:
+;
+; Severity=Success
+; Facility=Application
+;
+; The value associated with Severity and Facility must match one of
+; the names given in the FacilityNames and SeverityNames statements in
+; the header section. The SymbolicName statement allows you to
+; associate a C/C++ symbolic constant with the final 32-bit message
+; code.
+; */
+
+MessageId=0x1
+Severity=Success
+Facility=Startup
+SymbolicName=MSG_SERVER_STARTED
+Language=English
+Netscape Directory Server: %1.
+The directory server has successfully started.
+.
+MessageId=0x2
+Severity=Success
+Facility=Slapd
+SymbolicName=MSG_SERVER_SHUTDOWN
+Language=English
+Netscape Directory Server: %1.
+The directory server has shutdown.
+.
+MessageId=0x3
+Severity=Success
+Facility=Slapd
+SymbolicName=MSG_SERVER_STOPPED
+Language=English
+Netscape Directory Server: %1.
+The directory server has stopped.
+.
+MessageId=0x4
+Severity=Success
+Facility=Startup
+SymbolicName=MSG_SERVER_STARTING
+Language=English
+Netscape Directory Server: %1.
+The directory server is starting.
+.
+MessageId=0x5
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_SERVER_START_FAILED
+Language=English
+Netscape Directory Server: %1.
+The directory server has failed on startup. %2
+.
+MessageId=0x6
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_SERVER_START_FAILED_CTRL_HANDLER
+Language=English
+Netscape Directory Server: %1.
+The directory server has failed on startup. Failed to Register with Service Control handler.
+.
+MessageId=0x7
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_SERVER_PASSWORD_DIALOG_FAILED
+Language=English
+Netscape Directory Server: %1.
+The directory server failed to create the Key Database Passphrase dialog.
+.
+MessageId=0x8
+Severity=Error
+Facility=Registry
+SymbolicName=MSG_WD_REGISTRY
+Language=English
+Netscape Directory Server: %1.
+Could not open registry key: %2
+.
+MessageId=0x9
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_WD_BADCMDLINE
+Language=English
+Netscape Directory Server: %1
+Invalid command line specified: %2
+.
+MessageId=0xA
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_WD_BADPASSWORD
+Language=English
+Netscape Directory Server: %1.
+Incorrect SSL password entered.
+.
+MessageId=0xB
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_WD_STRING
+Language=English
+Netscape Directory Server: %1.
+%2
+.
+MessageId=0xC
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_WD_STARTFAILED
+Language=English
+Netscape Directory Server: %1.
+The directory server could not be started.
+Command line used: %2
+.
+MessageId=0xD
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_WD_RESTART
+Language=English
+Netscape Directory Server: %1.
+The directory server terminated abnormally with error code %2.
+An attempt will be made to restart it.
+.
+MessageId=0xE
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_CRON_STARTFAILED
+Language=English
+Netscape Directory Server: %1.
+The scheduled job (%2) could not be started.
+.
+MessageId=0xF
+Severity=Error
+Facility=Slapd
+SymbolicName=MSG_SERVER_SHUTDOWN_STARTING
+Language=English
+Netscape Directory Server: %1.
+The directory server is shutting down.
+.
+MessageId=0x10
+Severity=Error
+Facility=Startup
+SymbolicName=MSG_SERVER_KEYDB_PASSPHRASE_WRONG
+Language=English
+Netscape Directory Server: %1.
+The specified key database passphrase is incorrect.
+.
+MessageId=0x11
+Severity=Error
+Facility=Slapd
+SymbolicName=MSG_SERVER_FAILED_TO_WRITE_LOG
+Language=English
+Netscape Directory Server: %1.
+Failed to write log: %2.
+.
diff --git a/ldap/servers/slapd/ntperfdll/Makefile b/ldap/servers/slapd/ntperfdll/Makefile
new file mode 100644
index 00000000..bed046a6
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/Makefile
@@ -0,0 +1,52 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+MCOM_ROOT = ../../../../..
+LDAP_SRC = ../../..
+
+OBJDEST = $(OBJDIR)/servers/obj
+BINDIR = $(LDAP_SERVER_RELDIR)
+ALLDIRS = $(BINDIR) $(OBJDEST)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+LINK32=link.exe
+
+MC=mc #message compiler?
+
+DLLS = nsldapctr
+
+# -D's get all screwed up: we need to fix them:
+CFLAGS+= -UNS_PERSONAL -DNS_DS
+# this lets us pickup regparms.h
+CFLAGS += -I $(MCOM_ROOT)/ldapserver/include
+
+MCS = nsldapctrmc
+DEPMC = $(addsuffix .h, $(MCS))
+
+OBJS = $(OBJDEST)/nsldapctr.o $(OBJDEST)/nsldapctrutil.o
+
+RELFILES = nsldapctrs.ini nsldapctrdef.h
+
+DESTRELFILES = $(addprefix $(LDAP_INSTALL_BIN_RELDIR)/, $(RELFILES))
+
+all: $(ALLDIRS) $(addprefix $(BINDIR)/, $(addsuffix .dll, $(DLLS) ) ) $(DESTRELFILES)
+
+nsldapctrmc.h:
+ $(MC) -s -v $*.mc
+
+$(OBJDEST)/%.o: %.cpp
+ cl -nologo -c $(CFLAGS) $(MCC_INCLUDE) /Tp $< -Fo$@
+
+$(BINDIR)/nsldapctr.dll: $(DEPMC) $(OBJS)
+ $(LINK_DLL) /OUT:$@ /DEF:exports.def
+
+$(LDAP_INSTALL_BIN_RELDIR)/%: % $(LDAP_INSTALL_BIN_RELDIR)
+ $(CP) $< $(dir $@)
diff --git a/ldap/servers/slapd/ntperfdll/exports.def b/ldap/servers/slapd/ntperfdll/exports.def
new file mode 100644
index 00000000..c5805d9d
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/exports.def
@@ -0,0 +1,9 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+EXPORTS OpenNSPerformanceData
+EXPORTS CollectNSPerformanceData
+EXPORTS CloseNSPerformanceData
diff --git a/ldap/servers/slapd/ntperfdll/nsldapctr.cpp b/ldap/servers/slapd/ntperfdll/nsldapctr.cpp
new file mode 100644
index 00000000..21bf429d
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapctr.cpp
@@ -0,0 +1,985 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ nsctr.c
+
+ Netscape server performance monitor hooks.
+
+
+ ***********************************************************************
+ HOW TO ADD A NEW PERFMON STATISTIC
+ 1. add to StatSlot or StatHeader struct
+ 2. add new counter definition to NS_DATA_DEFINITION in nsctrs.h
+ 3. define the offset of your new counter in nsctrdef.h
+ 4. add your counter initialization to NSDataDefinition in nsctr.cpp
+ 5. update CollectNSPerformanceData to collect your data
+ 6. modify nsctrs.ini to contain the text info for your counter
+ these are keyed off the "tag" you used in step 3
+ ***********************************************************************
+ HOW TO UPDATE THE REGISTRY
+ 1. run regini nsreg.ini
+ 2. run lodctr nsctrs.ini
+ ***********************************************************************
+ */
+
+#define UNICODE
+
+#include <windows.h>
+#include <string.h>
+#include <winperf.h>
+#include <stdio.h>
+#include <regstr.h>
+#include "nsldapctrs.h"
+#include "nsldapctrmsg.h"
+#include "nsldapctrutil.h"
+#include "nsldapctrmc.h"
+#include "nsldapctrdef.h"
+
+#include "nt/regparms.h"
+
+#include "../agtmmap.h"
+
+#define NUM_INSTANCES 0
+#define MAGT_MAX_LINELEN 255
+
+
+/* --- Constant Performance Counter Declaration --------------------------------------------*/
+
+NS_DATA_DEFINITION NSDataDefinition = {
+
+ { sizeof(NS_DATA_DEFINITION) + SIZE_OF_NS_PERFORMANCE_DATA,
+ sizeof(NS_DATA_DEFINITION),
+ sizeof(PERF_OBJECT_TYPE),
+ NS_OBJ,
+ 0,
+ NS_OBJ,
+ 0,
+ PERF_DETAIL_NOVICE,
+ (sizeof(NS_DATA_DEFINITION)-sizeof(PERF_OBJECT_TYPE))/
+ sizeof(PERF_COUNTER_DEFINITION),
+ 4L,
+ NUM_INSTANCES,
+ 0,
+ 0,
+ 0
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ CONN_RATE,
+ 0,
+ CONN_RATE,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ NUM_CONN_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ THROUGHPUT,
+ 0,
+ THROUGHPUT,
+ 0,
+ -3,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ NUM_THROUGHPUT_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ TOTAL_BYTES_WRITTEN,
+ 0,
+ TOTAL_BYTES_WRITTEN,
+ 0,
+ -3,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ NUM_TOTAL_BYTES_WRITTEN_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ TOTAL_BYTES_READ,
+ 0,
+ TOTAL_BYTES_READ,
+ 0,
+ -3,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ NUM_TOTAL_BYTES_READ_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ OP_RATE,
+ 0,
+ OP_RATE,
+ 0,
+ -1,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ NUM_OP_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ TOTAL_ERRORS,
+ 0,
+ TOTAL_ERRORS,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ NUM_TOTAL_ERRORS_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ SEARCH_RATE,
+ 0,
+ SEARCH_RATE,
+ 0,
+ -1,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ NUM_SEARCH_RATE_OFFSET
+ } ,
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ ADD_RATE,
+ 0,
+ ADD_RATE,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ ADD_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ DELETE_RATE,
+ 0,
+ DELETE_RATE,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ DELETE_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ MODIFY_RATE,
+ 0,
+ MODIFY_RATE,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ MODIFY_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ COMPARE_RATE,
+ 0,
+ COMPARE_RATE,
+ 0,
+ -1,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ COMPARE_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ MODDN_RATE,
+ 0,
+ MODDN_RATE,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ MODDN_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ CONNECTIONS,
+ 0,
+ CONNECTIONS,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ CONNECTIONS_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ BIND_RATE,
+ 0,
+ BIND_RATE,
+ 0,
+ -1,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ BIND_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ ENTRIES_RETURNED,
+ 0,
+ ENTRIES_RETURNED,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ ENTRIES_RETURNED_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ ENTRIES_RETURNED_RATE,
+ 0,
+ ENTRIES_RETURNED_RATE,
+ 0,
+ -1,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ ENTRIES_RETURNED_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ REFERRALS_RETURNED,
+ 0,
+ REFERRALS_RETURNED,
+ 0,
+ 0,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_RAWCOUNT,
+ sizeof(DWORD),
+ REFERRALS_RETURNED_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ REFERRALS_RETURNED_RATE,
+ 0,
+ REFERRALS_RETURNED_RATE,
+ 0,
+ -1,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ REFERRALS_RETURNED_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ BYTES_READ_RATE,
+ 0,
+ BYTES_READ_RATE,
+ 0,
+ -3,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ BYTES_READ_RATE_OFFSET
+ },
+ {
+ sizeof(PERF_COUNTER_DEFINITION),
+ BYTES_WRITTEN_RATE,
+ 0,
+ BYTES_WRITTEN_RATE,
+ 0,
+ -3,
+ PERF_DETAIL_NOVICE,
+ PERF_COUNTER_COUNTER,
+ sizeof(DWORD),
+ BYTES_WRITTEN_RATE_OFFSET
+ }
+
+
+};
+
+/* --- Data structs ----------------------------------------------------------------------- */
+typedef struct instance_list_t {
+ PERF_INSTANCE_DEFINITION instance;
+ PWSTR pInstanceName;
+ PWSTR pConfPath;
+ agt_stats_t * pData;
+ struct instance_list_t * pNext;
+} instance_list_t;
+
+
+/* --- Globals ---------------------------------------------------------------------------- */
+static BOOL bInitialized = FALSE;
+static DWORD dwOpenCount = 0; /* Count of threads holding DLL open */
+static DWORD dwInstanceCount = 0;
+static instance_list_t *pInstanceList = NULL;
+
+#define export extern "C"
+
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtReadLine: Reads one line of text (up to n chars) from specified
+ * file.
+ *
+ * Returns: Len read - No error
+ * -1 - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+int MagtReadLine(char *buf, int n, FILE *fp)
+{
+ if (fgets(buf, n, fp) != NULL)
+ {
+ return(strlen(buf));
+ }
+ else
+ {
+ return(-1);
+ }
+}
+
+
+
+/* --- strips quotes off of a quoted string -------------------------------------- */
+
+
+char *dequote(char *quoted_string)
+{
+ char *return_string = (char *)malloc((strlen(quoted_string) - 2) * sizeof(char) );
+ char *pQuo = quoted_string;
+ char *pRet = return_string;
+
+ for(; *pQuo; pQuo++) {
+ if (*pQuo != '\"')
+ *(pRet++) = *pQuo;
+ }
+ *pRet = '\0';
+
+ return return_string;
+
+}
+
+/* --- gets the instance dir from conf file ------------------------------------- */
+
+
+/*
+ * The body of this function is pretty much copied from
+ * ldapserver/ldap/servers/snmp/ntagt/nsldapagt_nt.c
+ *
+ */
+char *getRootDirFromConfFile(PWSTR confpath)
+{
+ char *rootDir = NULL;
+ const char *config = "\\config\0" ;
+ char instanceDir[MAGT_MAX_LINELEN + 1] = "";
+ size_t len ;
+ char filename[256];
+
+ if (confpath) {
+ sprintf(filename, "%S", confpath);
+ len = strlen(filename) - strlen(config) ;
+ strncpy(instanceDir, filename, len);
+ rootDir = _strdup(instanceDir) ; // allocate memory for rootDir and set up to value pointed by instanceDir
+ return rootDir ;
+ }
+ else return NULL ;
+}
+
+static DWORD MapSharedMem(char* path, agt_stats_t **ptr)
+{
+ HANDLE hFile = NULL;
+ HANDLE hMapFile = NULL;
+ LPVOID memory = NULL;
+
+ *ptr = NULL;
+ /* Open existing disk file for read */
+ hFile = CreateFileA(path,
+ GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if ( hFile == INVALID_HANDLE_VALUE || hFile == NULL ) return GetLastError();
+
+ /* Create mapped file handle for reading */
+ hMapFile = CreateFileMapping( hFile, NULL, PAGE_READONLY, 0,
+ sizeof(struct agt_stats_t),
+ NULL);
+ if ( hMapFile == NULL ) {
+ CloseHandle( hFile );
+ return GetLastError();
+ }
+
+ /* Create addr ptr to the start of the file */
+ memory = MapViewOfFileEx( hMapFile, FILE_MAP_READ, 0, 0,
+ sizeof(struct agt_stats_t), NULL );
+ CloseHandle( hMapFile );
+ CloseHandle( hFile );
+ if ( memory == NULL ) {
+ return GetLastError();
+ }
+ *ptr = (agt_stats_t *)memory;
+ return 0;
+}
+
+static DWORD UnmapSharedMem(agt_stats_t **ptr)
+{
+ return UnmapViewOfFile( (LPVOID)*ptr) ? 0 : -1;
+}
+
+/* --- Open Function --------------------------------------------------------------------- */
+
+
+/* _FindNetscapeServers()
+ * Function to loop through registry looking for netscape servers
+ * Stores them into pInstanceList as it finds them.
+ */
+
+#define MAX_KEY_SIZE 128
+DWORD
+_FindNetscapeServers()
+{
+ LONG regStatus,
+ status;
+ HKEY hKeyNetscape = NULL,
+ hKeyNetscapeConf;
+ DWORD dwKey,
+ type,
+ dwServerKeySize,
+ size,
+ dwServerCount = 0;
+ WCHAR szServerKeyName[MAX_KEY_SIZE],
+ szConfKeyName[MAX_KEY_SIZE + sizeof(KEY_SOFTWARE_NETSCAPE)],
+ szPath[MAX_KEY_SIZE];
+ FILETIME fileTime;
+ instance_list_t *pNew;
+ DWORD iUniqueID = 0;
+
+ regStatus = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ TEXT(KEY_SOFTWARE_NETSCAPE) TEXT("\\") TEXT(DS_KEY_ROOT),
+ 0L,
+ KEY_ALL_ACCESS,
+ &hKeyNetscape);
+
+ if (regStatus != ERROR_SUCCESS) {
+ goto ExitPoint;
+ }
+
+ dwKey = 0;
+ do {
+ dwServerKeySize = MAX_KEY_SIZE;
+ regStatus = RegEnumKeyEx(
+ hKeyNetscape,
+ dwKey,
+ szServerKeyName,
+ &dwServerKeySize,
+ NULL,
+ 0,
+ 0,
+ &fileTime);
+ dwKey++;
+
+ if (regStatus == ERROR_SUCCESS) {
+
+ regStatus = RegOpenKeyEx(
+ hKeyNetscape,
+ szServerKeyName,
+ 0L,
+ KEY_ALL_ACCESS,
+ &hKeyNetscapeConf);
+
+ if (regStatus != ERROR_SUCCESS) {
+ continue;
+ }
+
+ /* Now look for "ConfigurationPath" to find 3.0 netscape servers */
+ size = MAX_KEY_SIZE;
+ status = RegQueryValueEx(
+ hKeyNetscapeConf,
+ TEXT(VALUE_CONFIG_PATH),
+ 0L,
+ &type,
+ (LPBYTE)szPath,
+ &size);
+ if ( status == ERROR_SUCCESS ) {
+ /* this is a netscape server */
+ if ( (pNew = (instance_list_t *)malloc(sizeof(instance_list_t))) == NULL) {
+ status = (unsigned long)-1;
+ RegCloseKey(hKeyNetscapeConf);
+ goto ExitPoint;
+ }
+ if ( (pNew->pInstanceName = (PWCH)malloc(sizeof(WCHAR) *(dwServerKeySize+1))) == NULL) {
+ status = (unsigned long)-1;
+ RegCloseKey(hKeyNetscapeConf);
+ goto ExitPoint;
+ }
+
+ if ( (pNew->pConfPath = (PWCH)malloc(sizeof(WCHAR) *(size+1))) == NULL) {
+ status = (unsigned long)-1;
+ RegCloseKey(hKeyNetscapeConf);
+ goto ExitPoint;
+ }
+
+
+ pNew->pData = NULL;
+
+ pNew->instance.ParentObjectTitleIndex = 0;
+ pNew->instance.ParentObjectInstance = 0;
+ pNew->instance.UniqueID = -1;
+ pNew->instance.NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
+ lstrcpy(pNew->pInstanceName, szServerKeyName);
+ lstrcpy(pNew->pConfPath, szPath);
+
+ pNew->instance.NameLength = (dwServerKeySize+1) * sizeof(WCHAR);
+ pNew->instance.ByteLength = sizeof(PERF_INSTANCE_DEFINITION) +
+ (((pNew->instance.NameLength + sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD));
+ pNew->instance.UniqueID = iUniqueID++;
+
+ pNew->pNext = pInstanceList;
+ pInstanceList = pNew;
+
+ dwServerCount++;
+ }
+
+ RegCloseKey(hKeyNetscapeConf);
+ }
+
+ } while ( regStatus != ERROR_NO_MORE_ITEMS );
+
+ExitPoint:
+ if (hKeyNetscape)
+ RegCloseKey (hKeyNetscape);
+
+ return dwServerCount;
+}
+
+/* _OpenNetscapeServers()
+ * Once the pInstanceList has been created, this routine will open the instances
+ * of the netscape servers;
+ */
+#define MAX_FILE_LEN 128
+DWORD
+_OpenNetscapeServers()
+{
+ LONG status;
+ DWORD dwServerCount = 0;
+ instance_list_t *pInstance;
+ char *szRootDir;
+ char tmpstatsfile[MAX_FILE_LEN];
+ int err;
+
+ for (pInstance = pInstanceList; pInstance; pInstance = pInstance->pNext) {
+
+ /* open the memory map */
+
+ /*
+ * Get directory for our stats file
+ */
+
+ szRootDir = getRootDirFromConfFile(pInstance->pConfPath);
+ if( szRootDir == NULL){
+ status = GetLastError();
+ continue ;
+ }
+ wsprintfA(tmpstatsfile, "%s/logs/%s", szRootDir, AGT_STATS_FILE);
+ err = MapSharedMem(tmpstatsfile,&pInstance->pData);
+ if ( 0 != err ) {
+ REPORT_ERROR (NSPERF_UNABLE_MAP_VIEW_OF_FILE, LOG_USER);
+ status = GetLastError(); // return error
+ continue;
+ } else {
+ dwServerCount++;
+ }
+
+ if(szRootDir != NULL){
+ free(szRootDir);
+ }
+
+ }
+
+ return dwServerCount;
+}
+
+export DWORD APIENTRY
+OpenNSPerformanceData(LPWSTR lpDeviceNames)
+{
+ LONG status;
+ TCHAR szMappedObject[] = TEXT(SVR_ID_SERVICE) TEXT("Statistics");
+ HKEY hKeyDriverPerf;
+ DWORD size;
+ DWORD type;
+ DWORD dwFirstCounter;
+ DWORD dwFirstHelp;
+
+ if (!dwOpenCount) {
+
+ hEventLog = MonOpenEventLog();
+
+
+ if ( !_FindNetscapeServers() ) {
+ /* No netscape servers found */
+ status = (unsigned long)-1;
+ goto OpenExitPoint;
+ }
+
+ if ( !(dwInstanceCount = _OpenNetscapeServers()) ) {
+ /* No netscape servers are active */
+ status = (unsigned long)-1;
+ goto OpenExitPoint;
+ }
+
+ /* Now load help keys from registry */
+
+ status = RegOpenKeyEx (
+ HKEY_LOCAL_MACHINE,
+ TEXT("System\\CurrentControlSet\\Services") TEXT("\\") TEXT(SVR_ID_SERVICE) TEXT(SVR_VERSION) TEXT("\\") TEXT(KEY_PERFORMANCE),
+ 0L,
+ KEY_ALL_ACCESS,
+ &hKeyDriverPerf);
+
+ if (status != ERROR_SUCCESS) {
+ REPORT_ERROR_DATA (NSPERF_UNABLE_OPEN_DRIVER_KEY, LOG_USER,
+ &status, sizeof(status));
+ goto OpenExitPoint;
+ }
+
+ size = sizeof (DWORD);
+ status = RegQueryValueEx(
+ hKeyDriverPerf,
+ TEXT("First Counter"),
+ 0L,
+ &type,
+ (LPBYTE)&dwFirstCounter,
+ &size);
+
+ if (status != ERROR_SUCCESS) {
+ REPORT_ERROR_DATA (NSPERF_UNABLE_READ_FIRST_COUNTER, LOG_USER,
+ &status, sizeof(status));
+ goto OpenExitPoint;
+ }
+
+ size = sizeof (DWORD);
+ status = RegQueryValueEx(
+ hKeyDriverPerf,
+ TEXT("First Help"),
+ 0L,
+ &type,
+ (LPBYTE)&dwFirstHelp,
+ &size);
+
+ if (status != ERROR_SUCCESS) {
+ REPORT_ERROR_DATA (NSPERF_UNABLE_READ_FIRST_HELP, LOG_USER,
+ &status, sizeof(status));
+ goto OpenExitPoint;
+ }
+
+ NSDataDefinition.NS_ObjectType.ObjectNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.NS_ObjectType.ObjectHelpTitleIndex += dwFirstHelp;
+
+ NSDataDefinition.connection_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.connection_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.throughput.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.throughput.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.total_bytes_written.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.total_bytes_written.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.total_bytes_read.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.total_bytes_read.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.operation_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.operation_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.total_errors.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.total_errors.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.search_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.search_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.add_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.add_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.delete_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.delete_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.modify_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.modify_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.compare_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.compare_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.moddn_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.moddn_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.connections.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.connections.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.bind_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.bind_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.entries_returned.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.entries_returned.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.entries_returned_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.entries_returned_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.referrals_returned.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.referrals_returned.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.referrals_returned_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.referrals_returned_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.bytes_read_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.bytes_read_rate.CounterHelpTitleIndex += dwFirstHelp;
+ NSDataDefinition.bytes_written_rate.CounterNameTitleIndex += dwFirstCounter;
+ NSDataDefinition.bytes_written_rate.CounterHelpTitleIndex += dwFirstHelp;
+
+ RegCloseKey (hKeyDriverPerf);
+
+ bInitialized = TRUE;
+ }
+
+ dwOpenCount++;
+
+ status = ERROR_SUCCESS;
+
+OpenExitPoint:
+
+ return status;
+}
+
+/* --- Close Function -------------------------------------------------------------------- */
+export DWORD APIENTRY
+CloseNSPerformanceData()
+{
+ instance_list_t *pInstance, *pDead;
+
+ if (!(--dwOpenCount)) {
+
+ for (pDead = NULL, pInstance = pInstanceList; pInstance; pInstance=pInstance->pNext) {
+ if (pDead)
+ free(pDead);
+
+ /* I probably need to free stats too... make sure to add that later */
+ if (pInstance->pData)
+ UnmapSharedMem(&pInstance->pData);
+
+ free(pInstance->pInstanceName);
+ free(pInstance->pConfPath);
+ pDead = pInstance;
+ }
+ if (pDead) /* cleanup last instance */
+ free(pDead);
+
+ MonCloseEventLog();
+
+ bInitialized = FALSE;
+ }
+
+ return ERROR_SUCCESS;
+}
+
+struct _status_struct_s {
+ DWORD connection_rate;
+ DWORD throughput;
+ DWORD tot_bytes_written;
+ DWORD tot_bytes_read;
+ DWORD op_rate;
+ DWORD tot_errs;
+ DWORD search_rate;
+ DWORD add_rate;
+ DWORD delete_rate;
+ DWORD modify_rate;
+ DWORD compare_rate;
+ DWORD moddn_rate;
+ DWORD connections;
+ DWORD bind_rate;
+ DWORD entries_returned;
+ DWORD entries_returned_rate;
+ DWORD referrals_returned;
+ DWORD referrals_returned_rate;
+ DWORD bytes_read_rate;
+ DWORD bytes_written_rate;
+};
+
+void
+Get_Actual_Data(agt_stats_t *smem,
+ struct _status_struct_s *results)
+{
+ /* Copy over the counters from the shared memory region */
+ struct ops_stats_t *pOpsStats = &(smem->ops_stats);
+
+ results->search_rate = pOpsStats->dsSearchOps;
+ results->modify_rate = pOpsStats->dsModifyEntryOps;
+ results->add_rate = pOpsStats->dsAddEntryOps ;
+ results->compare_rate = pOpsStats->dsCompareOps ;
+ results->moddn_rate = pOpsStats->dsModifyRDNOps ;
+ results->delete_rate = pOpsStats->dsRemoveEntryOps ;
+ results->bind_rate = pOpsStats->dsAnonymousBinds + pOpsStats->dsStrongAuthBinds + pOpsStats->dsSimpleAuthBinds ;
+ results->op_rate = results->search_rate + results->add_rate + results->delete_rate +
+ results->modify_rate + results->compare_rate + results->moddn_rate + results->bind_rate;
+ results->connections = 0;
+ results->tot_errs = pOpsStats->dsErrors ;
+ results->connections = pOpsStats->dsConnections ;
+ results->tot_bytes_written = pOpsStats->dsBytesSent ;
+ results->tot_bytes_read = pOpsStats->dsBytesRecv ;
+ results->throughput = pOpsStats->dsBytesSent + pOpsStats->dsBytesRecv;
+ results->connection_rate = pOpsStats->dsConnectionSeq ;
+ results->entries_returned = pOpsStats->dsEntriesReturned ;
+ results->entries_returned_rate = pOpsStats->dsEntriesReturned ;
+ results->referrals_returned = pOpsStats->dsReferralsReturned ;
+ results->referrals_returned_rate = pOpsStats->dsReferralsReturned ;
+ results->bytes_read_rate = pOpsStats->dsBytesRecv ;
+ results->bytes_written_rate = pOpsStats->dsBytesSent ;
+ /* Still to do : connections, throughput, db hit ratio, entry cache hit ratio */
+}
+
+/* --- Collect Function ------------------------------------------------------------------- */
+export DWORD APIENTRY
+CollectNSPerformanceData(
+ IN LPWSTR lpValueName,
+ IN OUT LPVOID *lppData,
+ IN OUT LPDWORD lpcbTotalBytes,
+ IN OUT LPDWORD lpNumObjectTypes
+)
+{
+ ULONG SpaceNeeded;
+ PDWORD pdwCounter;
+ PERF_COUNTER_BLOCK *pPerfCounterBlock;
+ NS_DATA_DEFINITION *pNSDataDefinition;
+ DWORD dwQueryType;
+ instance_list_t *pInstance;
+
+ if (!bInitialized) {
+ *lpcbTotalBytes = (DWORD) 0;
+ *lpNumObjectTypes = (DWORD) 0;
+ return ERROR_SUCCESS;
+ }
+
+ dwQueryType = GetQueryType (lpValueName);
+
+ if (dwQueryType == QUERY_FOREIGN) {
+ // this routine does not service requests for data from
+ // Non-NT computers
+ *lpcbTotalBytes = (DWORD) 0;
+ *lpNumObjectTypes = (DWORD) 0;
+ return ERROR_SUCCESS;
+ }
+
+ if (dwQueryType == QUERY_ITEMS){
+ if ( !(IsNumberInUnicodeList (NSDataDefinition.NS_ObjectType.ObjectNameTitleIndex, lpValueName))) {
+ // request received for data object not provided by this routine
+ *lpcbTotalBytes = (DWORD) 0;
+ *lpNumObjectTypes = (DWORD) 0;
+ return ERROR_SUCCESS;
+ }
+ }
+ /* -------- OK DO THE REAL WORK HERE ---------- */
+
+
+ /* -------------------------------------------- */
+ /* | PERF_DATA_BLOCK (header) | */
+ /* -------------------------------------------- */
+ /* | PERF_OBJECT_TYPE 1 | */
+ /* -------------------------------------------- */
+ /* | PERF_OBJECT_TYPE 2 | */
+ /* -------------------------------------------- */
+ /* | . | */
+ /* | . | */
+ /* | . | */
+ /* | | */
+ /* | | */
+ /* -------------------------------------------- */
+
+
+ /* -------------------------------------------- */
+ /* | PERF_OBJECT_TYPE (header) | */
+ /* -------------------------------------------- */
+ /* | PERF_COUNTER_DEFINITION 1 | */
+ /* -------------------------------------------- */
+ /* | PERF_COUNTER_DEFINITION 2 | */
+ /* -------------------------------------------- */
+ /* | . | */
+ /* | . | */
+ /* | . | */
+ /* | | */
+ /* -------------------------------------------- */
+ /* | PERF_INSTANCE_DEFINITION 1 | */
+ /* -------------------------------------------- */
+ /* | PERF_INSTANCE_DEFINITION 2 | */
+ /* -------------------------------------------- */
+ /* | . | */
+ /* | . | */
+ /* | . | */
+ /* | | */
+ /* | | */
+ /* -------------------------------------------- */
+
+
+ /* -------------------------------------------- */
+ /* | PERF_INSTANCE_DEFINITION (header) | */
+ /* -------------------------------------------- */
+ /* | Instance Name (variable) | */
+ /* -------------------------------------------- */
+ /* | PERF_COUNTER_BLOCK (header) | */
+ /* -------------------------------------------- */
+ /* | Counter Data (variable) | */
+ /* -------------------------------------------- */
+
+
+
+ /* Check to see if there is enough space in caller's buffer */
+
+ pNSDataDefinition = (NS_DATA_DEFINITION *) *lppData;
+
+ SpaceNeeded = sizeof(NS_DATA_DEFINITION) + (dwInstanceCount *
+ (SIZE_OF_NS_PERFORMANCE_DATA + MAX_KEY_SIZE + sizeof(PERF_COUNTER_BLOCK) +
+ sizeof(PERF_INSTANCE_DEFINITION)));
+
+ if ( *lpcbTotalBytes < SpaceNeeded ) {
+ *lpcbTotalBytes = (DWORD) 0;
+ *lpNumObjectTypes = (DWORD) 0;
+ return ERROR_MORE_DATA;
+ }
+
+ /* Set the PERF_OBJECT_TYPE definition and PERF_COUNTER_DEFINITIONs */
+ NSDataDefinition.NS_ObjectType.NumInstances = dwInstanceCount;
+ memmove(pNSDataDefinition, &NSDataDefinition, sizeof(NS_DATA_DEFINITION));
+
+ pdwCounter = (PDWORD) &(pNSDataDefinition[1]);
+
+ for ( pInstance = pInstanceList; pInstance; pInstance=pInstance->pNext) {
+
+ if ( pInstance->pData ) {
+
+ /* Set the PERF_INSTANCE_DEFINITION */
+ memmove(pdwCounter, &(pInstance->instance), sizeof(PERF_INSTANCE_DEFINITION));
+ pdwCounter += ((sizeof(PERF_INSTANCE_DEFINITION))/sizeof(DWORD));
+
+ /* Set the Instance Name */
+ memmove(pdwCounter, pInstance->pInstanceName, pInstance->instance.NameLength);
+ pdwCounter = pdwCounter + ((pInstance->instance.NameLength + sizeof(DWORD)-1)/sizeof(DWORD));
+
+ /* Set the PERF_COUNTER_BLOCK */
+ pPerfCounterBlock = (PERF_COUNTER_BLOCK *) pdwCounter;
+ pPerfCounterBlock->ByteLength = SIZE_OF_NS_PERFORMANCE_DATA + sizeof(PERF_COUNTER_BLOCK);
+ pdwCounter = (PDWORD) (&pPerfCounterBlock[1]);
+
+ /* Set the Instance Data */
+ Get_Actual_Data(pInstance->pData,(struct _status_struct_s*)pdwCounter);
+
+ {
+ DWORD x = (SIZE_OF_NS_PERFORMANCE_DATA) / sizeof(DWORD);
+
+ pdwCounter += x;
+ }
+ }
+ }
+
+ *lppData = (PVOID)(pdwCounter);
+ *lpNumObjectTypes = 1;
+ *lpcbTotalBytes = (PBYTE) pdwCounter - (PBYTE) pNSDataDefinition;
+ pNSDataDefinition->NS_ObjectType.TotalByteLength = *lpcbTotalBytes;
+
+ return ERROR_SUCCESS;
+}
+
diff --git a/ldap/servers/slapd/ntperfdll/nsldapctrdef.h b/ldap/servers/slapd/ntperfdll/nsldapctrdef.h
new file mode 100644
index 00000000..77b5d279
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapctrdef.h
@@ -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 **/
+/*
+ * nsctrdef.h
+ *
+ * Defines offsets of netscape server performance monitor counters.
+ */
+
+#define NS_OBJ 0
+#define CONN_RATE 2
+#define THROUGHPUT 4
+#define TOTAL_BYTES_WRITTEN 6
+#define TOTAL_BYTES_READ 8
+#define OP_RATE 10
+#define TOTAL_ERRORS 12
+#define SEARCH_RATE 14
+#define ADD_RATE 16
+#define DELETE_RATE 18
+#define MODIFY_RATE 20
+#define COMPARE_RATE 22
+#define MODDN_RATE 24
+#define CONNECTIONS 26
+#define BIND_RATE 28
+#define ENTRIES_RETURNED 30
+#define ENTRIES_RETURNED_RATE 32
+#define REFERRALS_RETURNED 34
+#define REFERRALS_RETURNED_RATE 36
+#define BYTES_READ_RATE 38
+#define BYTES_WRITTEN_RATE 40
+
diff --git a/ldap/servers/slapd/ntperfdll/nsldapctrmc.h b/ldap/servers/slapd/ntperfdll/nsldapctrmc.h
new file mode 100644
index 00000000..2178d6be
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapctrmc.h
@@ -0,0 +1,122 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * nsctrs.h
+ */
+//
+#ifndef _NSCTRMC_H_
+#define _NSCTRMC_H_
+//
+//
+// Perfutil messages
+//
+//
+// Values are 32 bit values layed out as follows:
+//
+// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
+// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
+// +---+-+-+-----------------------+-------------------------------+
+// |Sev|C|R| Facility | Code |
+// +---+-+-+-----------------------+-------------------------------+
+//
+// where
+//
+// Sev - is the severity code
+//
+// 00 - Success
+// 01 - Informational
+// 10 - Warning
+// 11 - Error
+//
+// C - is the Customer code flag
+//
+// R - is a reserved bit
+//
+// Facility - is the facility code
+//
+// Code - is the facility's status code
+//
+//
+// Define the facility codes
+//
+
+
+//
+// Define the severity codes
+//
+
+
+//
+// MessageId: UTIL_LOG_OPEN
+//
+// MessageText:
+//
+// An extensible counter has opened the Event Log for NSCTRS.DLL
+//
+#define UTIL_LOG_OPEN ((DWORD)0x4000076CL)
+
+//
+//
+// MessageId: UTIL_CLOSING_LOG
+//
+// MessageText:
+//
+// An extensible counter has closed the Event Log for NSCTRS.DLL
+//
+#define UTIL_CLOSING_LOG ((DWORD)0x400007CFL)
+
+//
+//
+// MessageId: NSPERF_OPEN_FILE_MAPPING_ERROR
+//
+// MessageText:
+//
+// Unable to open mapped file containing NS driver performance data.
+//
+#define NSPERF_OPEN_FILE_MAPPING_ERROR ((DWORD)0xC00007D0L)
+
+//
+//
+// MessageId: NSPERF_UNABLE_MAP_VIEW_OF_FILE
+//
+// MessageText:
+//
+// Unable to map to shared memory file containing NS driver performance data.
+//
+#define NSPERF_UNABLE_MAP_VIEW_OF_FILE ((DWORD)0xC00007D1L)
+
+//
+//
+// MessageId: NSPERF_UNABLE_OPEN_DRIVER_KEY
+//
+// MessageText:
+//
+// Unable open "Performance" key of NS driver in registry. Status code is returned in data.
+//
+#define NSPERF_UNABLE_OPEN_DRIVER_KEY ((DWORD)0xC00007D2L)
+
+//
+//
+// MessageId: NSPERF_UNABLE_READ_FIRST_COUNTER
+//
+// MessageText:
+//
+// Unable to read the "First Counter" value under the NS\Performance Key. Status codes returned in data.
+//
+#define NSPERF_UNABLE_READ_FIRST_COUNTER ((DWORD)0xC00007D3L)
+
+//
+//
+// MessageId: NSPERF_UNABLE_READ_FIRST_HELP
+//
+// MessageText:
+//
+// Unable to read the "First Help" value under the NS\Performance Key. Status codes returned in data.
+//
+#define NSPERF_UNABLE_READ_FIRST_HELP ((DWORD)0xC00007D4L)
+
+//
+#endif // _NSCTRMC_H_
diff --git a/ldap/servers/slapd/ntperfdll/nsldapctrmc.mc b/ldap/servers/slapd/ntperfdll/nsldapctrmc.mc
new file mode 100644
index 00000000..10c8341f
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapctrmc.mc
@@ -0,0 +1,74 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+;/*
+; * nsctrs.h
+; */
+;//
+;#ifndef _NSCTRMC_H_
+;#define _NSCTRMC_H_
+;//
+MessageIdTypedef=DWORD
+;//
+;// Perfutil messages
+;//
+MessageId=1900
+Severity=Informational
+Facility=Application
+SymbolicName=UTIL_LOG_OPEN
+Language=English
+An extensible counter has opened the Event Log for NSCTRS.DLL
+.
+;//
+MessageId=1999
+Severity=Informational
+Facility=Application
+SymbolicName=UTIL_CLOSING_LOG
+Language=English
+An extensible counter has closed the Event Log for NSCTRS.DLL
+.
+;//
+MessageId=2000
+Severity=Error
+Facility=Application
+SymbolicName=NSPERF_OPEN_FILE_MAPPING_ERROR
+Language=English
+Unable to open mapped file containing NS driver performance data.
+.
+;//
+MessageId=+1
+Severity=Error
+Facility=Application
+SymbolicName=NSPERF_UNABLE_MAP_VIEW_OF_FILE
+Language=English
+Unable to map to shared memory file containing NS driver performance data.
+.
+;//
+MessageId=+1
+Severity=Error
+Facility=Application
+SymbolicName=NSPERF_UNABLE_OPEN_DRIVER_KEY
+Language=English
+Unable open "Performance" key of NS driver in registry. Status code is returned in data.
+.
+;//
+MessageId=+1
+Severity=Error
+Facility=Application
+SymbolicName=NSPERF_UNABLE_READ_FIRST_COUNTER
+Language=English
+Unable to read the "First Counter" value under the NS\Performance Key. Status codes returned in data.
+.
+;//
+MessageId=+1
+Severity=Error
+Facility=Application
+SymbolicName=NSPERF_UNABLE_READ_FIRST_HELP
+Language=English
+Unable to read the "First Help" value under the NS\Performance Key. Status codes returned in data.
+.
+;//
+;#endif // _NSCTRMC_H_
diff --git a/ldap/servers/slapd/ntperfdll/nsldapctrmsg.h b/ldap/servers/slapd/ntperfdll/nsldapctrmsg.h
new file mode 100644
index 00000000..684ed821
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapctrmsg.h
@@ -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 **/
+/*
+ * nsctrmsg.h
+ *
+ * Defines EventLog error handling stuff for performance monitor dll.
+ *
+ */
+
+
+#ifndef _NSCTRMSG_H_
+#define _NSCTRMSG_H_
+//
+// Report error message ID's for Counters
+//
+
+#define APP_NAME "nsctrs"
+
+/* Levels: LOG_NONE = No event log messages ever
+ * LOG_USER = User event log messages (e.g. errors)
+ * LOG_DEBUG = Minimum Debugging
+ * LOG_VERBOSE = Maximum Debugging
+ */
+
+#define LOG_NONE 0
+#define LOG_USER 1
+#define LOG_DEBUG 2
+#define LOG_VERBOSE 3
+
+#define MESSAGE_LEVEL_DEFAULT LOG_USER
+
+#define REPORT_SUCCESS(i,l) (MESSAGE_LEVEL >= l ? ReportEvent (hEventLog, EVENTLOG_INFORMATION_TYPE, \
+ 0, i, (PSID)NULL, 0, 0, NULL, (PVOID)NULL) : FALSE)
+
+#define REPORT_INFORMATION(i,l) (MESSAGE_LEVEL >= l ? ReportEvent (hEventLog, EVENTLOG_INFORMATION_TYPE, \
+ 0, i, (PSID)NULL, 0, 0, NULL, (PVOID)NULL) : FALSE)
+
+#define REPORT_WARNING(i,l) (MESSAGE_LEVEL >= l ? ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, \
+ 0, i, (PSID)NULL, 0, 0, NULL, (PVOID)NULL) : FALSE)
+
+#define REPORT_ERROR(i,l) (MESSAGE_LEVEL >= l ? ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, \
+ 0, i, (PSID)NULL, 0, 0, NULL, (PVOID)NULL) : FALSE)
+
+#define REPORT_INFORMATION_DATA(i,l,d,s) (MESSAGE_LEVEL >= l ? ReportEvent (hEventLog, EVENTLOG_INFORMATION_TYPE, \
+ 0, i, (PSID)NULL, 0, s, NULL, (PVOID)(d)) : FALSE)
+
+#define REPORT_WARNING_DATA(i,l,d,s) (MESSAGE_LEVEL >= l ? ReportEvent (hEventLog, EVENTLOG_WARNING_TYPE, \
+ 0, i, (PSID)NULL, 0, s, NULL, (PVOID)(d)) : FALSE)
+
+#define REPORT_ERROR_DATA(i,l,d,s) (MESSAGE_LEVEL >= l ? ReportEvent (hEventLog, EVENTLOG_ERROR_TYPE, \
+ 0, i, (PSID)NULL, 0, s, NULL, (PVOID)(d)) : FALSE)
+
+extern HANDLE hEventLog; /* handle to event log */
+extern DWORD dwLogUsers; /* counter of event log using routines */
+extern DWORD MESSAGE_LEVEL; /* event logging detail level */
+
+#endif /* _NSCTRMSG_H_ */
diff --git a/ldap/servers/slapd/ntperfdll/nsldapctrs.h b/ldap/servers/slapd/ntperfdll/nsldapctrs.h
new file mode 100644
index 00000000..3bd4c70a
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapctrs.h
@@ -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 **/
+/*
+
+ nsctrs.h
+
+ */
+
+#ifndef _NSCTRS_H_
+#define _NSCTRS_H_
+
+#pragma pack (4)
+
+#define NS_NUM_PERF_OBJECT_TYPES 1
+#define NUM_CONN_RATE_OFFSET sizeof(DWORD)
+#define NUM_THROUGHPUT_OFFSET NUM_CONN_RATE_OFFSET + sizeof(DWORD)
+#define NUM_TOTAL_BYTES_WRITTEN_OFFSET NUM_THROUGHPUT_OFFSET + sizeof(DWORD)
+#define NUM_TOTAL_BYTES_READ_OFFSET NUM_TOTAL_BYTES_WRITTEN_OFFSET + sizeof(DWORD)
+#define NUM_OP_RATE_OFFSET NUM_TOTAL_BYTES_READ_OFFSET + sizeof(DWORD)
+#define NUM_TOTAL_ERRORS_OFFSET NUM_OP_RATE_OFFSET + sizeof(DWORD)
+#define NUM_SEARCH_RATE_OFFSET NUM_TOTAL_ERRORS_OFFSET + sizeof(DWORD)
+#define ADD_RATE_OFFSET NUM_SEARCH_RATE_OFFSET + sizeof(DWORD)
+#define DELETE_RATE_OFFSET ADD_RATE_OFFSET + sizeof(DWORD)
+#define MODIFY_RATE_OFFSET DELETE_RATE_OFFSET + sizeof(DWORD)
+#define COMPARE_RATE_OFFSET MODIFY_RATE_OFFSET + sizeof(DWORD)
+#define MODDN_RATE_OFFSET COMPARE_RATE_OFFSET + sizeof(DWORD)
+#define CONNECTIONS_OFFSET MODDN_RATE_OFFSET + sizeof(DWORD)
+#define BIND_RATE_OFFSET CONNECTIONS_OFFSET + sizeof(DWORD)
+#define ENTRIES_RETURNED_OFFSET BIND_RATE_OFFSET + sizeof(DWORD)
+#define ENTRIES_RETURNED_RATE_OFFSET ENTRIES_RETURNED_OFFSET + sizeof(DWORD)
+#define REFERRALS_RETURNED_OFFSET ENTRIES_RETURNED_RATE_OFFSET + sizeof(DWORD)
+#define REFERRALS_RETURNED_RATE_OFFSET REFERRALS_RETURNED_OFFSET + sizeof(DWORD)
+#define BYTES_READ_RATE_OFFSET REFERRALS_RETURNED_RATE_OFFSET + sizeof(DWORD)
+#define BYTES_WRITTEN_RATE_OFFSET BYTES_READ_RATE_OFFSET + sizeof(DWORD)
+#define SIZE_OF_NS_PERFORMANCE_DATA BYTES_WRITTEN_RATE_OFFSET + sizeof(DWORD)
+
+typedef struct _NS_DATA_DEFINITION {
+ PERF_OBJECT_TYPE NS_ObjectType;
+ PERF_COUNTER_DEFINITION connection_rate;
+ PERF_COUNTER_DEFINITION throughput;
+ PERF_COUNTER_DEFINITION total_bytes_written;
+ PERF_COUNTER_DEFINITION total_bytes_read;
+ PERF_COUNTER_DEFINITION operation_rate;
+ PERF_COUNTER_DEFINITION total_errors;
+ PERF_COUNTER_DEFINITION search_rate;
+ PERF_COUNTER_DEFINITION add_rate;
+ PERF_COUNTER_DEFINITION delete_rate;
+ PERF_COUNTER_DEFINITION modify_rate;
+ PERF_COUNTER_DEFINITION compare_rate;
+ PERF_COUNTER_DEFINITION moddn_rate;
+ PERF_COUNTER_DEFINITION connections;
+ PERF_COUNTER_DEFINITION bind_rate;
+ PERF_COUNTER_DEFINITION entries_returned;
+ PERF_COUNTER_DEFINITION entries_returned_rate;
+ PERF_COUNTER_DEFINITION referrals_returned;
+ PERF_COUNTER_DEFINITION referrals_returned_rate;
+ PERF_COUNTER_DEFINITION bytes_read_rate;
+ PERF_COUNTER_DEFINITION bytes_written_rate;
+} NS_DATA_DEFINITION;
+
+#pragma pack ()
+
+#endif /* _NSCTRS_H_ */
+
diff --git a/ldap/servers/slapd/ntperfdll/nsldapctrs.ini b/ldap/servers/slapd/ntperfdll/nsldapctrs.ini
new file mode 100644
index 00000000..82db3140
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapctrs.ini
@@ -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
+#
+[info]
+drivername=slapd7
+symbolfile=nsldapctrdef.h
+
+[languages]
+009=English
+
+[text]
+NS_OBJ_009_NAME=Netscape Directory Server 7.0
+NS_OBJ_009_HELP=Netscape Directory Server
+CONN_RATE_009_NAME=Client Connections/sec
+CONN_RATE_009_HELP=Rate of incoming client connections
+THROUGHPUT_009_NAME=Server Network Throughput (bytes/sec)
+THROUGHPUT_009_HELP=Number of bytes both sent and received per second on client connections
+TOTAL_BYTES_WRITTEN_009_NAME=Total Bytes Sent
+TOTAL_BYTES_WRITTEN_009_HELP=Total number of Bytes sent by the server since startup
+TOTAL_BYTES_READ_009_NAME=Total Bytes Received
+TOTAL_BYTES_READ_009_HELP=Total number of Bytes received by the server since startup
+OP_RATE_009_NAME=Operations/sec
+OP_RATE_009_HELP=Number of Operations (total of search, bind, modify, compare, modDN, delete) serviced per second
+SEARCH_RATE_009_NAME=Searches/sec
+SEARCH_RATE_009_HELP=Number of Search operations performed per second
+TOTAL_ERRORS_009_NAME=Total Number of Errors
+TOTAL_ERRORS_009_HELP=Total number of Errors seen by the server since startup
+ADD_RATE_009_NAME=Adds/sec
+ADD_RATE_009_HELP=Number of Add operations performed per second
+DELETE_RATE_009_NAME=Deletes/sec
+DELETE_RATE_009_HELP=Number of Delete operations performed per second
+MODIFY_RATE_009_NAME=Modifies/sec
+MODIFY_RATE_009_HELP=Number of Modify operations performed per second
+COMPARE_RATE_009_NAME=Compares/sec
+COMPARE_RATE_009_HELP=Number of Compare operations performed per second
+MODDN_RATE_009_NAME=ModDNs/sec
+MODDN_RATE_009_HELP=Number of ModDN operations performed per second
+CONNECTIONS_009_NAME=Connected Clients
+CONNECTIONS_009_HELP=Number of client sessions currently connected
+BIND_RATE_009_NAME=Binds/sec
+BIND_RATE_009_HELP=Number of Bind operations performed per second
+ENTRIES_RETURNED_009_NAME=Entries Returned
+ENTRIES_RETURNED_009_HELP=Number of entries returned to clients since startup
+ENTRIES_RETURNED_RATE_009_NAME=Entries Returned/sec
+ENTRIES_RETURNED_RATE_009_HELP=Number of entries returned to clients per second
+REFERRALS_RETURNED_009_NAME=Referrals Returned
+REFERRALS_RETURNED_009_HELP=Number of referrals returned to clients since startup
+REFERRALS_RETURNED_RATE_009_NAME=Referrals Returned/sec
+REFERRALS_RETURNED_RATE_009_HELP=Number of referrals returned to clients per second
+BYTES_READ_RATE_009_NAME=Network Bytes Read/sec
+BYTES_READ_RATE_009_HELP=Number of bytes per second read from connected clients
+BYTES_WRITTEN_RATE_009_NAME=Network Bytes Written/sec
+BYTES_WRITTEN_RATE_009_HELP=Number of bytes per second written to connected clients
diff --git a/ldap/servers/slapd/ntperfdll/nsldapctrutil.cpp b/ldap/servers/slapd/ntperfdll/nsldapctrutil.cpp
new file mode 100644
index 00000000..1783aee2
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapctrutil.cpp
@@ -0,0 +1,364 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+
+ nsctrutil.c
+
+ Performance Monitor utility functions
+
+ This file implements the utility routines used to construct the
+ common parts of a PERF_INSTANCE_DEFINITION (see winperf.h) and
+ perform event logging functions.
+
+ */
+
+#include <windows.h>
+#include <string.h>
+#include <winperf.h>
+#include "nsldapctrmc.h"
+#include "nsldapctrmsg.h"
+#include "nsldapctrutil.h"
+
+#define INITIAL_SIZE 1024L
+#define EXTEND_SIZE 1024L
+
+//
+// Global data definitions.
+//
+
+ULONG ulInfoBufferSize = 0;
+
+HANDLE hEventLog; // handle to event log
+
+DWORD dwLogUsers = 0; // count of functions using event log
+
+DWORD MESSAGE_LEVEL = 0;
+
+WCHAR GLOBAL_STRING[] = L"Global";
+WCHAR FOREIGN_STRING[] = L"Foreign";
+WCHAR COSTLY_STRING[] = L"Costly";
+
+WCHAR NULL_STRING[] = L"\0"; // pointer to null string
+
+// test for delimiter, end of line and non-digit characters
+// used by IsNumberInUnicodeList routine
+//
+#define DIGIT 1
+#define DELIMITER 2
+#define INVALID 3
+
+#define EvalThisChar(c,d) ( \
+ (c == d) ? DELIMITER : \
+ (c == 0) ? DELIMITER : \
+ (c < (WCHAR)'0') ? INVALID : \
+ (c > (WCHAR)'9') ? INVALID : \
+ DIGIT)
+
+HANDLE
+MonOpenEventLog (
+)
+/*++
+
+Routine Description:
+
+ Reads the level of event logging from the registry and opens the
+ channel to the event logger for subsequent event log entries.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ Handle to the event log for reporting events.
+ NULL if open not successful.
+
+--*/
+
+
+{
+
+
+ HKEY hAppKey;
+
+
+ TCHAR LogLevelKeyName[] = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib";
+
+
+ TCHAR LogLevelValueName[] = "EventLogLevel";
+
+ LONG lStatus;
+
+ DWORD dwLogLevel;
+ DWORD dwValueType;
+ DWORD dwValueSize;
+
+ // if global value of the logging level not initialized or is disabled,
+ // check the registry to see if it should be updated.
+
+ if (!MESSAGE_LEVEL) {
+
+ lStatus = RegOpenKeyEx (HKEY_LOCAL_MACHINE,
+ LogLevelKeyName,
+ 0,
+ KEY_READ,
+ &hAppKey);
+
+ dwValueSize = sizeof (dwLogLevel);
+
+ if (lStatus == ERROR_SUCCESS) {
+ lStatus = RegQueryValueEx (hAppKey,
+ LogLevelValueName,
+ (LPDWORD)NULL,
+ &dwValueType,
+ (LPBYTE)&dwLogLevel,
+ &dwValueSize);
+
+ if (lStatus == ERROR_SUCCESS) {
+ MESSAGE_LEVEL = dwLogLevel;
+ } else {
+ MESSAGE_LEVEL = MESSAGE_LEVEL_DEFAULT;
+ }
+ RegCloseKey (hAppKey);
+ } else {
+
+
+ MESSAGE_LEVEL = MESSAGE_LEVEL_DEFAULT;
+ }
+ }
+
+ if (hEventLog == NULL){
+ hEventLog = RegisterEventSource (
+ (LPTSTR)NULL, // Use Local Machine
+ APP_NAME); // event log app name to find in registry
+ }
+
+ if (hEventLog != NULL) {
+ dwLogUsers++; // increment count of perfctr log users
+ }
+ return (hEventLog);
+}
+
+VOID
+MonCloseEventLog (
+)
+/*++
+
+Routine Description:
+
+ Closes the handle to the event logger if this is the last caller
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+{
+ if (hEventLog != NULL) {
+ dwLogUsers--; // decrement usage
+ if (dwLogUsers <= 0) { // and if we're the last, then close up log
+ DeregisterEventSource (hEventLog);
+ }
+ }
+}
+
+DWORD
+GetQueryType (
+ IN LPWSTR lpValue
+)
+/*++
+
+GetQueryType
+
+ returns the type of query described in the lpValue string so that
+ the appropriate processing method may be used
+
+Arguments
+
+ IN lpValue
+ string passed to PerfRegQuery Value for processing
+
+Return Value
+
+ QUERY_GLOBAL
+ if lpValue == 0 (null pointer)
+ lpValue == pointer to Null string
+ lpValue == pointer to "Global" string
+
+ QUERY_FOREIGN
+ if lpValue == pointer to "Foreign" string
+
+ QUERY_COSTLY
+ if lpValue == pointer to "Costly" string
+
+ otherwise:
+
+ QUERY_ITEMS
+
+--*/
+{
+ WCHAR *pwcArgChar, *pwcTypeChar;
+ BOOL bFound;
+
+ if (lpValue == 0) {
+ return QUERY_GLOBAL;
+ } else if (*lpValue == 0) {
+ return QUERY_GLOBAL;
+ }
+
+ // check for "Global" request
+
+ pwcArgChar = lpValue;
+ pwcTypeChar = GLOBAL_STRING;
+ bFound = TRUE; // assume found until contradicted
+
+ // check to the length of the shortest string
+
+ while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
+ if (*pwcArgChar++ != *pwcTypeChar++) {
+ bFound = FALSE; // no match
+ break; // bail out now
+ }
+ }
+
+ if (bFound) return QUERY_GLOBAL;
+
+ // check for "Foreign" request
+
+ pwcArgChar = lpValue;
+ pwcTypeChar = FOREIGN_STRING;
+ bFound = TRUE; // assume found until contradicted
+
+ // check to the length of the shortest string
+
+ while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
+ if (*pwcArgChar++ != *pwcTypeChar++) {
+ bFound = FALSE; // no match
+ break; // bail out now
+ }
+ }
+
+ if (bFound) return QUERY_FOREIGN;
+
+ // check for "Costly" request
+
+ pwcArgChar = lpValue;
+ pwcTypeChar = COSTLY_STRING;
+ bFound = TRUE; // assume found until contradicted
+
+ // check to the length of the shortest string
+
+ while ((*pwcArgChar != 0) && (*pwcTypeChar != 0)) {
+ if (*pwcArgChar++ != *pwcTypeChar++) {
+ bFound = FALSE; // no match
+ break; // bail out now
+ }
+ }
+
+ if (bFound) return QUERY_COSTLY;
+
+ // if not Global and not Foreign and not Costly,
+ // then it must be an item list
+
+ return QUERY_ITEMS;
+
+}
+
+BOOL
+IsNumberInUnicodeList (
+ IN DWORD dwNumber,
+ IN LPWSTR lpwszUnicodeList
+)
+/*++
+
+IsNumberInUnicodeList
+
+Arguments:
+
+ IN dwNumber
+ DWORD number to find in list
+
+ IN lpwszUnicodeList
+ Null terminated, Space delimited list of decimal numbers
+
+Return Value:
+
+ TRUE:
+ dwNumber was found in the list of unicode number strings
+
+ FALSE:
+ dwNumber was not found in the list.
+
+--*/
+{
+ DWORD dwThisNumber;
+ WCHAR *pwcThisChar;
+ BOOL bValidNumber;
+ BOOL bNewItem;
+ //BOOL bReturnValue;
+ WCHAR wcDelimiter; // could be an argument to be more flexible
+
+ if (lpwszUnicodeList == 0) return FALSE; // null pointer, # not found
+
+ pwcThisChar = lpwszUnicodeList;
+ dwThisNumber = 0;
+ wcDelimiter = (WCHAR)' ';
+ bValidNumber = FALSE;
+ bNewItem = TRUE;
+
+ while (TRUE) {
+ switch (EvalThisChar (*pwcThisChar, wcDelimiter)) {
+ case DIGIT:
+ // if this is the first digit after a delimiter, then
+ // set flags to start computing the new number
+ if (bNewItem) {
+ bNewItem = FALSE;
+ bValidNumber = TRUE;
+ }
+ if (bValidNumber) {
+ dwThisNumber *= 10;
+ dwThisNumber += (*pwcThisChar - (WCHAR)'0');
+ }
+ break;
+
+ case DELIMITER:
+ // a delimiter is either the delimiter character or the
+ // end of the string ('\0') if when the delimiter has been
+ // reached a valid number was found, then compare it to the
+ // number from the argument list. if this is the end of the
+ // string and no match was found, then return.
+ //
+ if (bValidNumber) {
+ if (dwThisNumber == dwNumber) return TRUE;
+ bValidNumber = FALSE;
+ }
+ if (*pwcThisChar == 0) {
+ return FALSE;
+ } else {
+ bNewItem = TRUE;
+ dwThisNumber = 0;
+ }
+ break;
+
+ case INVALID:
+ // if an invalid character was encountered, ignore all
+ // characters up to the next delimiter and then start fresh.
+ // the invalid number is not compared.
+ bValidNumber = FALSE;
+ break;
+
+ default:
+ break;
+
+ }
+ pwcThisChar++;
+ }
+
+} // IsNumberInUnicodeList
diff --git a/ldap/servers/slapd/ntperfdll/nsldapctrutil.h b/ldap/servers/slapd/ntperfdll/nsldapctrutil.h
new file mode 100644
index 00000000..37384b3a
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapctrutil.h
@@ -0,0 +1,120 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ perfutil.h
+
+Abstract:
+
+
+
+ This file supports routines used to parse and create Performance Monitor Data
+ Structures. It actually supports Performance Object types with multiple instances
+
+
+
+Revision History:
+
+--*/
+#ifndef _PERFUTIL_H_
+#define _PERFUTIL_H_
+
+// enable this define to log process heap data to the event log
+#ifdef PROBE_HEAP_USAGE
+#undef PROBE_HEAP_USAGE
+#endif
+//
+
+
+// Utility macro. This is used to reserve a DWORD multiple of bytes for Unicode strings
+// embedded in the definitional data, viz., object instance names.
+
+
+//
+
+
+#define DWORD_MULTIPLE(x) (((x+sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD))
+
+
+
+// (assumes dword is 4 bytes long and pointer is a dword in size)
+
+
+#define ALIGN_ON_DWORD(x) ((VOID *)( ((DWORD) x & 0x00000003) ? ( ((DWORD) x & 0xFFFFFFFC) + 4 ) : ( (DWORD) x ) ))
+
+
+
+extern WCHAR GLOBAL_STRING[]; // Global command (get all local ctrs)
+extern WCHAR FOREIGN_STRING[]; // get data from foreign computers
+extern WCHAR COSTLY_STRING[];
+
+
+extern WCHAR NULL_STRING[];
+
+
+
+#define QUERY_GLOBAL 1
+#define QUERY_ITEMS 2
+#define QUERY_FOREIGN 3
+#define QUERY_COSTLY 4
+
+//
+
+
+// The definition of the only routine of perfutil.c, It builds part of a performance data
+// instance (PERF_INSTANCE_DEFINITION) as described in winperf.h
+
+
+//
+
+HANDLE MonOpenEventLog ();
+VOID MonCloseEventLog ();
+DWORD GetQueryType (IN LPWSTR);
+BOOL IsNumberInUnicodeList (DWORD, LPWSTR);
+
+typedef struct _LOCAL_HEAP_INFO_BLOCK {
+ DWORD AllocatedEntries;
+ DWORD AllocatedBytes;
+ DWORD FreeEntries;
+ DWORD FreeBytes;
+} LOCAL_HEAP_INFO, *PLOCAL_HEAP_INFO;
+
+
+//
+// Memory Probe macro
+//
+#ifdef PROBE_HEAP_USAGE
+
+#define HEAP_PROBE() { \
+ DWORD dwHeapStatus[5]; \
+ NTSTATUS CallStatus; \
+ dwHeapStatus[4] = __LINE__; \
+ if (!(CallStatus = memprobe (dwHeapStatus, 16L, NULL))) { \
+ REPORT_INFORMATION_DATA (VGA_HEAP_STATUS, LOG_DEBUG, \
+ &dwHeapStatus, sizeof(dwHeapStatus)); \
+ } else { \
+ REPORT_ERROR_DATA (VGA_HEAP_STATUS_ERROR, LOG_DEBUG, \
+ &CallStatus, sizeof (DWORD)); \
+ } \
+}
+
+#else
+
+#define HEAP_PROBE() ;
+
+
+
+
+
+#endif
+
+#endif //_PERFUTIL_H_
diff --git a/ldap/servers/slapd/ntperfdll/nsldapreg.ini b/ldap/servers/slapd/ntperfdll/nsldapreg.ini
new file mode 100644
index 00000000..6ca7a2c2
--- /dev/null
+++ b/ldap/servers/slapd/ntperfdll/nsldapreg.ini
@@ -0,0 +1,18 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+\Registry\Machine
+ System
+ CurrentControlSet
+ Services
+ slapd7
+ Performance
+ Close = REG_SZ CloseNSPerformanceData
+ Collect = REG_SZ CollectNSPerformanceData
+ Library = REG_SZ nsctr.dll
+ Open = REG_SZ OpenNSPerformanceData
+
diff --git a/ldap/servers/slapd/ntuserpin.c b/ldap/servers/slapd/ntuserpin.c
new file mode 100644
index 00000000..6e0de7d4
--- /dev/null
+++ b/ldap/servers/slapd/ntuserpin.c
@@ -0,0 +1,178 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/******************************************************
+ *
+ * ntuserpin.c - Prompts for the key
+ * database passphrase.
+ *
+ ******************************************************/
+
+#if defined( _WIN32 ) && defined ( NET_SSL )
+
+#include <windows.h>
+#include "ntwatchdog.h"
+#include "slapi-plugin.h"
+#include "fe.h"
+
+#undef Debug
+#undef OFF
+#undef LITTLE_ENDIAN
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "slap.h"
+#include "fe.h"
+
+static int i=0;
+static int cbRemotePassword = 0;
+
+extern char* NT_PromptForPin(const char *tokenName);
+
+static const char nt_retryWarning[] =
+"Warning: You entered an incorrect PIN. Incorrect PIN may result in disabling the token";
+
+struct SVRCORENTUserPinObj
+{
+ SVRCOREPinObj base;
+};
+static const struct SVRCOREPinMethods vtable;
+
+/* ------------------------------------------------------------ */
+SVRCOREError
+SVRCORE_CreateNTUserPinObj(SVRCORENTUserPinObj **out)
+{
+ SVRCOREError err = 0;
+ SVRCORENTUserPinObj *obj = 0;
+
+ do {
+ obj = (SVRCORENTUserPinObj*)malloc(sizeof (SVRCORENTUserPinObj));
+ if (!obj) { err = 1; break; }
+
+ obj->base.methods = &vtable;
+
+ } while(0);
+
+ if (err)
+ {
+ SVRCORE_DestroyNTUserPinObj(obj);
+ obj = 0;
+ }
+
+ *out = obj;
+ return err;
+}
+
+void
+SVRCORE_DestroyNTUserPinObj(SVRCORENTUserPinObj *obj)
+{
+ if (obj) free(obj);
+}
+
+static void destroyObject(SVRCOREPinObj *obj)
+{
+ SVRCORE_DestroyNTUserPinObj((SVRCORENTUserPinObj*)obj);
+}
+
+/* First try to retrieve the password from the watchdog,
+ if this is not available, prompt for the passphrase. */
+
+static char *getPin(SVRCOREPinObj *obj, const char *tokenName, PRBool retry)
+{
+ HWND hwndRemote;
+ char *szRemotePassword = NULL;
+ HANDLE hRemoteProcess;
+ DWORD dwNumberOfBytesRead=0;
+ DWORD dwNumberOfBytesWritten=0;
+ PK11_PIN *buf= NULL;
+ char *password = NULL;
+ char pin[MAX_PASSWORD];
+ BOOL ret;
+ DWORD err = 0;
+
+ // Find Watchdog application window
+ if( pszServerName && (hwndRemote = FindWindow("slapd", pszServerName)) &&
+ (hRemoteProcess = (HANDLE)GetWindowLong( hwndRemote,
+ GWL_PROCESS_HANDLE)))
+ {
+ cbRemotePassword = GetWindowLong(hwndRemote, GWL_PASSWORD_LENGTH);
+ szRemotePassword = (HANDLE)GetWindowLong(hwndRemote, GWL_PASSWORD_ADDR);
+
+ // if retry, don't get the pin from watchdog
+ if (retry)
+ {
+ MessageBox(GetDesktopWindow(), nt_retryWarning,
+ "Netscape Server", MB_ICONEXCLAMATION | MB_OK);
+ } else {
+ if((cbRemotePassword != 0) && (szRemotePassword != 0))
+ {
+ buf = (PK11_PIN *)slapi_ch_malloc(sizeof
+ (PK11_PIN)*cbRemotePassword);
+ if(ReadProcessMemory(hRemoteProcess, szRemotePassword,
+ (LPVOID)buf,sizeof(PK11_PIN)*cbRemotePassword ,
+ &dwNumberOfBytesRead))
+ {
+
+ for (i=0; i < cbRemotePassword; i++) {
+ if (strncmp (tokenName, buf[i].TokenName,
+ buf[i].TokenLength)==0)
+ {
+ memset(pin, '\0', MAX_PASSWORD);
+ strncpy (pin, buf[i].Password,
+ buf[i].PasswordLength);
+ slapi_ch_free ((void **) &buf);
+ return slapi_ch_strdup(pin);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /* Didn't get the password from Watchdog, or this is a retry,
+ prompt the user. */
+
+ password = NT_PromptForPin(tokenName);
+
+ /* Store the password back to nt watchdog */
+ if (password != NULL && hwndRemote && hRemoteProcess)
+ {
+ slapi_ch_free ((void **) &buf);
+ buf = (PK11_PIN *)slapi_ch_malloc(sizeof(PK11_PIN));
+ strcpy (buf[0].TokenName, tokenName);
+ buf[0].TokenLength=strlen(tokenName);
+ strcpy (buf[0].Password, password);
+ buf[0].PasswordLength=strlen(password);
+ if (i== cbRemotePassword)
+ {
+ /* Add a new token and password to the end of the table.*/
+
+ SetWindowLong(hwndRemote, GWL_PASSWORD_LENGTH,
+ (LONG)cbRemotePassword+1);
+ ret = WriteProcessMemory(hRemoteProcess,
+ szRemotePassword+cbRemotePassword*sizeof(PK11_PIN),
+ (LPVOID)buf, sizeof(PK11_PIN), &dwNumberOfBytesWritten);
+ if( !ret )
+ err = GetLastError();
+ } else {
+ /* This is a retry due to a wrong password stored in watchdog. */
+ ret = WriteProcessMemory(hRemoteProcess,
+ szRemotePassword+i*sizeof(PK11_PIN),(LPVOID)buf,
+ sizeof(PK11_PIN), &dwNumberOfBytesWritten);
+ if( !ret )
+ err = GetLastError();
+ }
+ }
+ slapi_ch_free ((void **) &buf);
+ return (password);
+}
+
+/*
+ * VTable
+ */
+static const SVRCOREPinMethods vtable =
+{ 0, 0, destroyObject, getPin };
+#endif /* defined( _WIN32 ) && defined ( NET_SSL ) */
diff --git a/ldap/servers/slapd/ntwdog/Makefile b/ldap/servers/slapd/ntwdog/Makefile
new file mode 100644
index 00000000..f727232c
--- /dev/null
+++ b/ldap/servers/slapd/ntwdog/Makefile
@@ -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
+#
+#
+# GNU Makefile for LDAP Server NT Service watchdog
+#
+
+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 = $(OBJDIR)/ntwdog/obj
+SLAPD_OBJDEST= $(OBJDIR)/obj
+BINDIR = $(LDAP_SERVER_RELDIR)
+LDAP_LIBDIR = $(OBJDIR)/lib
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), WINNT)
+SUBSYSTEM=windows
+endif
+
+#INCLUDES += -I$(MCOM_ROOT)/ldapserver/include/libadmin
+
+DS_SERVER_DEFS = -DNS_DS
+
+NTWDOG_OBJS= ntwatchdog.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(NTWDOG_OBJS))
+
+LIBS_DEP = $(LDAP_LIBUTIL_DEP) $(LIBADMIN_DEP)
+
+LIBS = $(LDAP_LIBUTIL)
+
+EXTRA_LIBS += $(LIBS)
+
+NTWDOG = $(addprefix $(BINDIR)/, ns-slapd.exe)
+
+all: $(OBJDEST) $(BINDIR) $(NTWDOG)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(NTWDOG): $(OBJS) $(LIBS_DEP)
+ $(LINK_EXE)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ $(RM) $(NTWDOG)
+
diff --git a/ldap/servers/slapd/ntwdog/cron_conf.c b/ldap/servers/slapd/ntwdog/cron_conf.c
new file mode 100644
index 00000000..8d60191a
--- /dev/null
+++ b/ldap/servers/slapd/ntwdog/cron_conf.c
@@ -0,0 +1,654 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <process.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include "cron_conf.h"
+
+#define NSAPI_PUBLIC
+
+#ifndef BUF_SIZE
+#define BUF_SIZE 4096
+#endif
+
+#ifndef S_BUF_SIZE
+#define S_BUF_SIZE 1024
+#endif
+
+#ifdef XP_WIN32
+#pragma warning (disable: 4005) // macro redifinition //
+#define MALLOC(size) malloc(size)
+#define REALLOC(x, size) realloc(x, size)
+#define FREE(x) free((void*) x)
+#define STRDUP(x) strdup(x)
+#define strcasecmp(x, y) stricmp(x, y)
+#pragma warning (default: 4005) // macro redifinition //
+#endif
+
+static char *admroot;
+static char *nsroot;
+
+#define DAILY "Sun Mon Tue Wed Thu Fri Sat"
+
+static cron_conf_list *cclist = NULL;
+static cron_conf_list *cctail = NULL;
+static char *conffile = NULL;
+
+#ifndef CRON_CONF_STAND_ALONE
+static void set_roots()
+{
+ char *ar = ADMCONFDIR;
+ if(ar)
+ admroot = STRDUP(ar);
+}
+#endif
+
+/* General note: strtok() is not MT safe on Unix , but it is okay to call
+ here because this file is NT only and strtok() is MT safe on NT */
+
+static char *nocr(char *buf)
+{
+ if (buf)
+ {
+ if(buf[strlen(buf) - 1] == '\n')
+ buf[strlen(buf) - 1] = '\0';
+ }
+
+ return buf;
+}
+
+static int debug(char *fmt, ...)
+{
+ va_list args;
+ char buf[BUF_SIZE];
+
+ va_start(args, fmt);
+ vsprintf(buf, fmt, args);
+ va_end(args);
+
+ fprintf(stdout, "<<DEBUG>> %s <<DEBUG>>\n", buf);
+ fflush(stdout);
+
+ return 1;
+}
+
+static char *get_conf_file()
+{
+ static char conffile [S_BUF_SIZE];
+ char nsconfile[S_BUF_SIZE];
+ char buf [BUF_SIZE];
+ char *r, *p;
+ FILE *fp;
+ int flag = 0;
+
+ if (admroot)
+ sprintf(nsconfile, "%s/ns-cron.conf", admroot);
+ else
+ sprintf(nsconfile, "%s/admin-serv/config/ns-cron.conf", nsroot);
+
+ if (!(fp = fopen(nsconfile, "r")))
+ return NULL;
+
+ while(fgets(buf, sizeof(buf), fp))
+ {
+ r = strtok(buf, " \t\n");
+ if (!r) /* bad line, ignore */
+ continue;
+
+ p = strtok(NULL, " \t\n");
+ if (!p) /* bad line, ignore */
+ continue;
+
+ if (!strcasecmp(r, "ConfFile"))
+ {
+ /* if filename without path is specified, default to admin svr dir */
+ if((strchr(p, '\\') == NULL) &&
+ (strchr(p, '/') == NULL))
+ sprintf(conffile, "%s/%s", admroot, p);
+ else
+ sprintf(conffile, "%s", p);
+ flag++;
+ break;
+ }
+ }
+
+ fclose(fp);
+
+ if (!flag)
+ return NULL;
+
+ return conffile;
+}
+
+
+#ifndef CRON_CONF_STAND_ALONE
+NSAPI_PUBLIC
+#endif
+cron_conf_obj *cron_conf_create_obj(char *name, char *command, char *dir,
+ char *user, char *start_time, char *days)
+{
+ cron_conf_obj *object;
+ char *d = NULL;
+
+ object = (cron_conf_obj*)MALLOC(sizeof(cron_conf_obj));
+
+ object->name = (name) ? STRDUP(name) : NULL;
+ object->command = (command) ? STRDUP(command) : NULL;
+ object->dir = (dir) ? STRDUP(dir) : NULL;
+ object->user = (user) ? STRDUP(user) : NULL;
+ object->start_time = (start_time) ? STRDUP(start_time) : NULL;
+
+#if 1
+ if (days)
+ {
+ if (!(strcasecmp(days, "Daily")))
+ d = STRDUP(DAILY);
+ else
+ d = STRDUP(days);
+ }
+#else
+ d = STRDUP("Wed Thu");
+#endif
+
+ object->days = d;
+
+ return object;
+}
+
+
+static void cron_conf_free_listobj(cron_conf_list *lobj)
+{
+ cron_conf_obj *obj = lobj->obj;
+
+
+ if (obj)
+ {
+ if(obj->name) FREE(obj->name);
+ if(obj->command) FREE(obj->command);
+ if(obj->dir) FREE(obj->dir);
+ if(obj->user) FREE(obj->user);
+ if(obj->start_time) FREE(obj->start_time);
+ if(obj->days) FREE(obj->days);
+
+ FREE(obj);
+ }
+
+ FREE(lobj);
+}
+
+
+static cron_conf_obj *get_object(FILE *fp)
+{
+ cron_conf_obj *object;
+ char name [S_BUF_SIZE];
+ char command [S_BUF_SIZE];
+ char dir [S_BUF_SIZE];
+ char user [S_BUF_SIZE];
+ char start_time[S_BUF_SIZE];
+ char days [S_BUF_SIZE];
+ char buf [BUF_SIZE];
+ char *p, *q;
+ int flag = 0;
+ int hascom, hasdir, hasuser, hastime, hasdays;
+
+ p = fgets(buf, sizeof(buf), fp);
+
+ if (!p)
+ return NULL;
+ /* else debug("Read line '%s'", nocr(buf)); */
+
+ if (strncmp(buf, "<Object", 7))
+ return NULL;
+
+ hascom = hasdir = hasuser = hastime = hasdays = 0;
+
+ p = strtok(buf, "<=>\n\t ");
+ if (!p)
+ return NULL;
+
+ p = strtok(NULL, "<=>\n\t ");
+ if (!p)
+ return NULL;
+
+ p = strtok(NULL, "<=>\n\t ");
+ if (!p)
+ return NULL;
+
+ sprintf(name, "%s", p);
+ /* debug("Setting name to '%s'", name); */
+
+ while(fgets(buf, sizeof(buf), fp))
+ {
+ /* debug("Read line '%s'", nocr(buf)); */
+
+ p = strtok(buf, " \t\n");
+
+ if (!p)
+ continue;
+
+ if (!strcasecmp(p, "</Object>"))
+ {
+ flag++;
+ break;
+ }
+
+ if(!strcasecmp(p, "Command"))
+ {
+ q = strtok(NULL, "\n");
+
+ if (q)
+ q = strchr(q, '\"');
+
+ if (q)
+ q++;
+
+ if (q)
+ {
+ if (!hascom)
+ {
+ /* get rid of quotes */
+ p = strrchr(q, '\"');
+
+ if (p)
+ *p = '\0';
+
+ if (q)
+ {
+ sprintf(command, "%s", q);
+ /* debug("Setting command to '%s'", command); */
+ hascom++;
+ }
+ }
+ else /* already has a command */
+ ; /* ignore */
+ }
+ continue;
+ }
+
+ if(!strcasecmp(p, "Dir"))
+ {
+ q = strtok(NULL, "\n");
+
+ if (q)
+ q = strchr(q, '\"');
+
+ if (q)
+ q++;
+
+ if (q)
+ {
+ if (!hasdir)
+ {
+ /* get rid of quotes */
+ p = strrchr(q, '\"');
+
+ if (p)
+ *p = '\0';
+
+ if (q)
+ {
+ sprintf(dir, "%s", q);
+ /* debug("Setting dir to '%s'", dir); */
+ hasdir++;
+ }
+ }
+ else /* already has a dir */
+ ; /* ignore */
+ }
+ continue;
+ }
+
+ else if(!strcasecmp(p, "User"))
+ {
+ q = strtok(NULL, " \t\n");
+
+ if (q)
+ {
+ if (!hasuser)
+ {
+ sprintf(user, "%s", q);
+ /* debug("Setting user to '%s'", user); */
+ hasuser++;
+ }
+ else /* already has a user */
+ ; /* ignore */
+ }
+ continue;
+ }
+
+ else if(!strcasecmp(p, "Time"))
+ {
+ q = strtok(NULL, "\n");
+
+ if (q)
+ {
+ if (!hastime)
+ {
+ sprintf(start_time, "%s", q);
+ /* debug("Setting time to '%s'", start_time); */
+ hastime++;
+ }
+ else /* already has a time */
+ ; /* ignore */
+ }
+ continue;
+ }
+
+ else if(!strcasecmp(p, "Days"))
+ {
+ q = strtok(NULL, "\n");
+
+ if (q)
+ {
+ if (!hasdays)
+ {
+ sprintf(days, "%s", q);
+ /* debug("Setting days to '%s'", days); */
+ hasdays++;
+ }
+ else /* already has days */
+ ; /* ignore */
+ }
+ continue;
+ }
+
+ else
+ {
+ /* gibberish... ignore... will be fixed when
+ file is rewritten */
+ continue;
+ }
+ }
+
+ object = cron_conf_create_obj(name,
+ (hascom) ? command : NULL,
+ (hasdir) ? dir : NULL,
+ (hasuser) ? user : NULL,
+ (hastime) ? start_time : NULL,
+ (hasdays) ? days : NULL);
+
+ return object;
+}
+
+
+static void cron_conf_write_stream(FILE *fp)
+{
+ cron_conf_obj *obj;
+ cron_conf_list *lobj;
+
+ for(lobj = cclist; lobj; lobj = lobj->next)
+ {
+ obj = lobj->obj;
+
+ fprintf(fp, "<Object name=%s>\n", (obj->name) ? obj->name : "?");
+ fprintf(fp, " Command \"%s\"\n", (obj->command) ? obj->command : "?");
+ if (obj->dir)
+ fprintf(fp, " Dir \"%s\"\n", obj->dir);
+ if (obj->user)
+ fprintf(fp, " User %s\n", obj->user);
+ fprintf(fp, " Time %s\n", (obj->start_time) ? obj->start_time : "?");
+ fprintf(fp, " Days %s\n", (obj->days) ? obj->days : "?");
+ fprintf(fp, "</Object>\n");
+ }
+}
+
+
+static void cron_conf_delete(char *name, cron_conf_obj *cco)
+{
+ cron_conf_list *lobj = NULL;
+ cron_conf_list *pobj = NULL;
+
+ if (!cclist)
+ return;
+
+ if (!strcmp(cclist->name, name))
+ {
+ lobj = cclist;
+ cclist = cclist->next;
+ if (cctail == lobj)
+ cctail = cclist;
+
+ cron_conf_free_listobj(lobj);
+ }
+ else
+ {
+ pobj = cclist;
+
+ for(lobj = cclist->next; lobj; lobj = lobj->next)
+ {
+ if(!strcmp(lobj->name, name))
+ {
+ if (lobj == cctail)
+ cctail = pobj;
+
+ pobj->next = lobj->next;
+ cron_conf_free_listobj(lobj);
+
+ break;
+ }
+
+ pobj = lobj;
+ }
+ }
+
+ return;
+}
+
+#ifndef CRON_CONF_STAND_ALONE
+NSAPI_PUBLIC
+#endif
+int cron_conf_read()
+{
+ FILE *fp;
+ cron_conf_obj *obj;
+ cron_conf_list *lobj;
+
+#ifndef CRON_CONF_STAND_ALONE
+ set_roots();
+#endif
+
+ if (!(conffile = get_conf_file()))
+ {
+ /* debug("Conffile is null"); */
+ return 0;
+ }
+ /* else debug("Conffile: '%s'", conffile); */
+
+ if (!(fp = fopen(conffile, "r")))
+ {
+ /* debug("Couldn't open conffile"); */
+ return 0;
+ }
+
+ while((obj = get_object(fp)))
+ {
+ lobj = (cron_conf_list*)MALLOC(sizeof(struct cron_conf_list));
+ lobj->name = obj->name;
+ lobj->obj = obj;
+ lobj->next = NULL;
+
+ /* debug("Created a list object named '%s'", lobj->name); */
+
+ if(cclist == NULL) /* first object */
+ {
+ cclist = cctail = lobj;
+ }
+ else
+ {
+ cctail->next = lobj;
+ cctail = lobj;
+ }
+
+ /* debug("List now, head: '%s', tail: '%s'",
+ cclist->name, cctail->name); */
+ }
+
+ fclose(fp);
+
+ return 1;
+}
+
+#ifndef CRON_CONF_STAND_ALONE
+NSAPI_PUBLIC
+#endif
+cron_conf_obj *cron_conf_get(char *name)
+{
+ cron_conf_obj *obj = NULL;
+ cron_conf_list *lobj = NULL;
+
+ /* find object */
+ for(lobj = cclist; lobj; lobj = lobj->next)
+ {
+ if(!strcmp(lobj->name, name))
+ {
+ obj = lobj->obj;
+ break;
+ }
+ }
+
+#if 0
+ if (obj)
+ {
+ debug("Found object %s", obj->name);
+ debug("obj->command = %s", (obj->command) ? obj->command : "NULL");
+ debug("obj->dir = %s", (obj->dir) ? obj->dir : "NULL");
+ debug("obj->user = %s", (obj->user) ? obj->user : "NULL");
+ debug("obj->start_time = %s", (obj->start_time) ? obj->start_time : "NULL");
+ debug("obj->days = %s", (obj->days) ? obj->days : "NULL");
+ }
+#endif
+
+ return obj;
+}
+
+
+#ifndef CRON_CONF_STAND_ALONE
+NSAPI_PUBLIC
+#endif
+cron_conf_list *cron_conf_get_list()
+{
+ return cclist;
+}
+
+#ifndef CRON_CONF_STAND_ALONE
+NSAPI_PUBLIC
+#endif
+cron_conf_obj *cron_conf_set(char *name, cron_conf_obj *cco)
+{
+ cron_conf_obj *obj = NULL;
+ cron_conf_list *lobj = NULL;
+
+ if (!name)
+ return NULL;
+
+ if (!cco)
+ {
+ cron_conf_delete(name, cco);
+ return NULL;
+ }
+ else /* cco exists */
+ {
+ /* find object */
+ obj = cron_conf_get(name);
+
+
+ if (obj) /* found it */
+ {
+ if (cco->command)
+ {
+ FREE(obj->command);
+ obj->command = cco->command;
+ }
+
+ if (cco->dir)
+ {
+ FREE(obj->dir);
+ obj->dir = cco->dir;
+ }
+
+ if (cco->user)
+ {
+ FREE(obj->user);
+ obj->user = cco->user;
+ }
+
+ if (cco->start_time)
+ {
+ FREE(obj->start_time);
+ obj->start_time = cco->start_time;
+ }
+
+ if (cco->days)
+ {
+ FREE(obj->days);
+ obj->days = cco->days;
+ }
+
+ FREE(cco);
+ }
+ else /* couldn't find it */
+ {
+ obj = cco;
+
+ lobj = (cron_conf_list*)MALLOC(sizeof(cron_conf_list));
+ lobj->name = obj->name;
+ lobj->obj = obj;
+ lobj->next = NULL;
+
+ if(cclist == NULL) /* first object */
+ {
+ cclist = cctail = lobj;
+ }
+ else
+ {
+ cctail->next = lobj;
+ cctail = lobj;
+ }
+ }
+ }
+
+ return obj;
+}
+
+void cron_conf_write()
+{
+ FILE *fp;
+
+ if (!conffile)
+ conffile = get_conf_file();
+
+ if(!(fp = fopen(conffile, "w")))
+ return;
+
+ cron_conf_write_stream(fp);
+
+ fclose(fp);
+}
+
+
+#ifndef CRON_CONF_STAND_ALONE
+NSAPI_PUBLIC
+#endif
+void cron_conf_free()
+{
+ cron_conf_list *lobj = NULL;
+
+ /* find object */
+ while(cclist)
+ {
+ lobj = cclist;
+ cclist = cclist->next;
+
+ cron_conf_free_listobj(lobj);
+ }
+
+ cclist = cctail = NULL;
+}
+
diff --git a/ldap/servers/slapd/ntwdog/cron_conf.h b/ldap/servers/slapd/ntwdog/cron_conf.h
new file mode 100644
index 00000000..23a32463
--- /dev/null
+++ b/ldap/servers/slapd/ntwdog/cron_conf.h
@@ -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 **/
+/***********************************************************************
+** $Id: cron_conf.h,v 1.1 2005/01/21 00:40:52 cvsadm Exp $
+**
+**
+** NAME
+** cron_conf.h
+**
+** DESCRIPTION
+**
+**
+** AUTHOR
+** <robw@netscape.com>
+**
+***********************************************************************/
+
+#ifndef _CRON_CONF_H_
+#define _CRON_CONF_H_
+
+/***********************************************************************
+** Includes
+***********************************************************************/
+/* read and write to cron.conf, cron_conf.c */
+/* Alex Feygin, 3/22/96 */
+typedef struct cron_conf_obj
+{
+ char *name;
+ char *command;
+ char *dir;
+ char *user;
+ char *start_time;
+ char *days;
+}
+cron_conf_obj;
+
+typedef struct cron_conf_list
+{
+ char *name;
+ cron_conf_obj *obj;
+ struct cron_conf_list *next;
+}
+cron_conf_list;
+
+/* Reads cron.conf to a null terminated list of cron_conf_objects; returns
+ 0 if unable to do a read; 1 otherwise */
+int cron_conf_read();
+
+/* gets a cron object, NULL if it doesnt exist */
+cron_conf_obj *cron_conf_get(char *name);
+
+/* returns a NULL-terminated cron_conf_list of all the cron conf objects */
+cron_conf_list *cron_conf_get_list();
+
+/* Creates a cron conf object; all these args get STRDUP'd in the function
+ so make sure to free up the space later if need be */
+cron_conf_obj *cron_conf_create_obj(char *name, char *command,
+ char *dir, char *user,
+ char *start_time, char *days);
+
+/* Puts a cron conf object into list or updates it if it already in there.
+ Returns either the object passed or the object in there already;
+ cco may be FREE'd during this operation so if you need the object
+ back, call it like so:
+
+ cco = cron_conf_set(cco->name, cco);
+
+ calling cron_conf_set with a NULL cco will cause the 'name' object
+ to be deleted.
+*/
+cron_conf_obj *cron_conf_set(char *name, cron_conf_obj *cco);
+
+/* write out current list of cron_conf_objects to cron.conf file */
+void cron_conf_write();
+
+/* free all cron conf data structures */
+void cron_conf_free();
+
+#define MAGNUS_CONF "magnus.conf"
+#define ADMCONFDIR "../config/"
+
+
+#endif /* _CRON_CONF_H_ */
diff --git a/ldap/servers/slapd/ntwdog/ntcron.c b/ldap/servers/slapd/ntwdog/ntcron.c
new file mode 100644
index 00000000..98b4cae3
--- /dev/null
+++ b/ldap/servers/slapd/ntwdog/ntcron.c
@@ -0,0 +1,156 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+// //
+// Name: NTCRON //
+// Platforms: WIN32 //
+// Description: unix cron functionality in a separate thread //
+// Notes: //
+// The following assumptions are made: //
+// - gszServerRoot is set to c:\netscape\server //
+// - ns-cron.conf and cron.conf are available //
+// Todo: //
+// - handle time format variations of hh:mm //
+// - keep track of children //
+// ...................................................................... //
+// Revision History: //
+// 03-26-96 Initial Version, Andy Hakim (ahakim@netscape.com) //
+// 07-10-96 Modified for Directory Server, pkennedy@netscape.com //
+//--------------------------------------------------------------------------//
+#include <windows.h>
+#include "ntwatchdog.h"
+#include "ntslapdmessages.h" // event log msgs constants //
+#include "cron_conf.h"
+
+static cron_conf_list *cclist = NULL;
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL CRON_CheckDay(LPSYSTEMTIME lpstNow, char *szDays)
+{
+ BOOL bReturn = FALSE;
+ char szToday[16];
+ if(GetDateFormat((LCID)NULL, 0, lpstNow, "ddd", szToday, sizeof(szToday)) != 0)
+ {
+ strlwr(szDays);
+ strlwr(szToday);
+ if(strstr(szDays, szToday) != NULL)
+ bReturn = TRUE;
+ }
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL CRON_CheckTime(LPSYSTEMTIME lpstNow, char *szTime)
+{
+ BOOL bReturn = FALSE;
+ char szCurrentTime[16];
+ char szStartTime[16];
+
+ strcpy(szStartTime, szTime);
+
+ if(szTime[1] == ':')
+ wsprintf(szStartTime, "0%s", szTime);
+
+ if(GetTimeFormat((LCID)LOCALE_SYSTEM_DEFAULT, TIME_FORCE24HOURFORMAT, lpstNow, "hh:mm", szCurrentTime, sizeof(szCurrentTime)) != 0)
+ {
+ if(strcmp(szCurrentTime, szStartTime) == 0)
+ bReturn = TRUE;
+ }
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL CRON_StartJob(PROCESS_INFORMATION *pi, cron_conf_obj *cco)
+{
+ BOOL bReturn = FALSE;
+ STARTUPINFO sui;
+
+ sui.cb = sizeof(STARTUPINFO);
+ sui.lpReserved = 0;
+ sui.lpDesktop = NULL;
+ sui.lpTitle = NULL;
+ sui.dwX = 0;
+ sui.dwY = 0;
+ sui.dwXSize = 0;
+ sui.dwYSize = 0;
+ sui.dwXCountChars = 0;
+ sui.dwYCountChars = 0;
+ sui.dwFillAttribute = 0;
+ sui.dwFlags = STARTF_USESHOWWINDOW;
+ sui.wShowWindow = SW_SHOWMINIMIZED;
+ sui.cbReserved2 = 0;
+ sui.lpReserved2 = 0;
+ sui.hStdInput = 0;
+ sui.hStdOutput = 0;
+ sui.hStdError = 0;
+
+ bReturn = CreateProcess(NULL, cco->command, NULL, NULL,
+ TRUE, 0, NULL, cco->dir, &sui, pi );
+ if(!bReturn)
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_CRON_STARTFAILED, cco->name);
+
+ return(bReturn);
+}
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL CRON_CheckConfFile()
+{
+ BOOL bReturn = FALSE;
+ PROCESS_INFORMATION pi;
+ SYSTEMTIME stNow;
+
+ GetLocalTime(&stNow); // note: this provides time adjusted for local time zone
+
+ if(cron_conf_read())
+ cclist = cron_conf_get_list();
+
+ while((cclist) && (cclist->obj))
+ {
+ cron_conf_obj *cco = cclist->obj;
+ if((cco->days) && (cco->start_time) && (cco->command))
+ {
+ if(CRON_CheckDay(&stNow, cco->days) && CRON_CheckTime(&stNow, cco->start_time))
+ {
+ bReturn = CRON_StartJob(&pi, cco);
+ CLOSEHANDLE(pi.hProcess);
+ CLOSEHANDLE(pi.hThread);
+ }
+ }
+ cclist = cclist->next;
+ }
+ cron_conf_free();
+ return bReturn;
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+LPTHREAD_START_ROUTINE CRON_ThreadProc(HANDLE hevWatchDogExit)
+{
+ BOOL bExit = FALSE;
+ while(!bExit)
+ {
+ CRON_CheckConfFile();
+ if(WaitForSingleObject(hevWatchDogExit, 1000*DEFAULT_CRON_TIME) != WAIT_TIMEOUT)
+ bExit = TRUE;
+ }
+ return 0;
+}
diff --git a/ldap/servers/slapd/ntwdog/ntwatchdog.c b/ldap/servers/slapd/ntwdog/ntwatchdog.c
new file mode 100644
index 00000000..ef8e795c
--- /dev/null
+++ b/ldap/servers/slapd/ntwdog/ntwatchdog.c
@@ -0,0 +1,1163 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#pragma warning(disable : 4001)
+// disable warning C4001: nonstandard extension 'single line comment' was used
+
+// //
+// Name: NTWATCHDOG //
+// Platforms: WIN32 //
+// Description: shell for nt directory server, runs as service, launches //
+// server, monitors it, re-launches if server crashes, //
+// Notes: //
+// ...................................................................... //
+// Watchdog can be run as an application or a service. When run as a //
+// service, it uses the service name from the SCM for the server name. //
+// When run as an application, it uses the command line to determine //
+// the server name. The command line can be one of two formats: //
+// c:\navgold\server\slapd-kennedy\config //
+// or //
+// slapd-kennedy //
+// ...................................................................... //
+// server file "lib\base\servssl.c" was changed //
+// - added code to get password from WatchDog process //
+// ...................................................................... //
+// server file "httpd\src\ntmain.c" was changed //
+// - server always runs as an application //
+// - changed hServerDoneEvent global name to "NS_service_name" //
+// this was necessary so that WatchDog can trap the "service_name" event //
+// - above changes were also made in MultipleInstances() //
+// ...................................................................... //
+// server file "lib\libmessages\messages.mc" was changed //
+// - added a couple of extra messages for watchdog event logging //
+// - watchdog is dependent on the server's eventlog source name //
+// ...................................................................... //
+// Revision History: //
+// 01-12-96 Initial Version, Andy Hakim (ahakim@netscape.com) //
+// 02-01-96 changed restart logic, now based on infant mortality time //
+// instead of server exit code //
+// 07-10-96 Modified for Directory Server, pkennedy@netscape.com //
+// //
+//--------------------------------------------------------------------------//
+#include <windows.h>
+#include <stdio.h>
+#include <string.h>
+#include <process.h>
+#include "ntslapdmessages.h" // event log msgs constants //
+#include "regparms.h" // product name, etc //
+#include "ntwatchdog.h"
+#include "version.h"
+#include "ntresource.h"
+#include "proto-ntutil.h"
+
+#ifdef PUMPKIN_HOUR
+#include <time.h>
+#endif
+
+//--------------------------------------------------------------------------//
+// global variables //
+//--------------------------------------------------------------------------//
+SERVICE_STATUS_HANDLE gsshServiceStatus = 0L;
+HWND ghWndMain = NULL;
+HANDLE ghevWatchDogExit = NULL;
+HINSTANCE ghInstance = NULL;
+HANDLE ghdlgPassword = NULL; // handle to password dialog window
+HANDLE ghDuplicateProcess = NULL; // process handle with PROCESS_VM_READ access
+HANDLE ghServerProcess = NULL; // used by app window in TerminateProcess()
+HANDLE ghServerThread0 = NULL; // used by app window in Suspend/ResumeThread()
+HANDLE ghWdogProcess = NULL;
+char gszServerConfig[MAX_LINE]; // ex: c:\netscape\server\slapd-kennedy\config
+char gszServerName[MAX_LINE]; // ex: slapd-kennedy
+char gszServerRoot[MAX_LINE]; // ex: c:\netscape\server
+char gszPassword[2048];
+DWORD gdwServiceError = NO_ERROR; // return error code for service
+DWORD gdwLastStatus = SERVICE_RUNNING;
+
+//--------------------------------------------------------------------------//
+// This is the shutdown handler we register via SetConsoleCtrlHandler()
+// It is really the only guaranteed means we have of shutting down gracefully
+// when the sytem is shutting down. The Service Manager mechanism is not
+// guaranteed to work.
+//--------------------------------------------------------------------------//
+
+BOOL WINAPI WD_ControlHandler(DWORD dwCtrlType)
+{
+ if (dwCtrlType == CTRL_SHUTDOWN_EVENT) {
+ SetEvent(ghevWatchDogExit);
+ WaitForSingleObject(ghWdogProcess, 1000 * DEFAULT_KILL_TIME);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+//--------------------------------------------------------------------------//
+// calc szServerRoot given szServerName //
+//--------------------------------------------------------------------------//
+BOOL WD_GetServerConfig(char *szServerId, char *szServerRoot, LPDWORD cbServerRoot)
+{
+ BOOL bReturn = FALSE;
+ HANDLE hSlapdKey = 0;
+ char szSlapdKey[MAX_PATH];
+ DWORD dwValueType;
+ DWORD dwResult = 0;
+
+ // don't want to monitor Admin server
+ if(strcmp(ADM_KEY_ROOT, szServerId) == 0)
+ return(bReturn);
+
+ // query registry key to figure out config directory
+ sprintf(szSlapdKey, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT,
+ szServerId);
+
+ dwResult = RegOpenKey(HKEY_LOCAL_MACHINE, szSlapdKey, &hSlapdKey);
+ if(dwResult == ERROR_SUCCESS)
+ {
+ dwResult = RegQueryValueEx(hSlapdKey, VALUE_CONFIG_PATH, NULL,
+ &dwValueType, (LPBYTE)szServerRoot, cbServerRoot);
+ if(dwResult == ERROR_SUCCESS)
+ bReturn = TRUE;
+ RegCloseKey(hSlapdKey);
+ }
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// get server's id based on index value that corresponds to the order in //
+// which it is listed under the the registry \SOFTWARE\Netscape\.. //
+//--------------------------------------------------------------------------//
+BOOL WD_GetServerId(IN DWORD dwSubKey, OUT char *szServerId, IN OUT LPDWORD cbServerId)
+{
+ BOOL bReturn = FALSE;
+ static HANDLE hSlapdKey = 0;
+ DWORD dwResult = ERROR_SUCCESS;
+ FILETIME ftLastWrite;
+ char szSlapdKey[MAX_LINE];
+
+ if(dwSubKey == 0) {
+ sprintf(szSlapdKey, "%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT);
+ dwResult = RegOpenKey(HKEY_LOCAL_MACHINE, szSlapdKey,
+ &hSlapdKey);
+ }
+
+ if(dwResult == ERROR_SUCCESS)
+ {
+ dwResult = RegEnumKeyEx(hSlapdKey, dwSubKey, szServerId,
+ cbServerId, NULL, NULL, NULL, &ftLastWrite);
+ if(dwResult == ERROR_SUCCESS)
+ {
+ bReturn = TRUE;
+ }
+ else
+ {
+ RegCloseKey(hSlapdKey);
+ hSlapdKey = 0;
+ }
+ }
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL WD_IsServiceRunning(char *szServerId)
+{
+ BOOL bReturn = FALSE;
+ SC_HANDLE hscManager;
+ SC_HANDLE hscService;
+ SERVICE_STATUS ssServiceStatus;
+
+ if(hscManager = OpenSCManager(NULL, NULL, GENERIC_READ))
+ {
+ if(hscService = OpenService(hscManager, szServerId, SERVICE_QUERY_STATUS))
+ {
+ if(QueryServiceStatus(hscService, &ssServiceStatus))
+ {
+ if(ssServiceStatus.dwCurrentState != SERVICE_STOPPED)
+ {
+ bReturn = TRUE;
+ }
+ }
+ CloseServiceHandle(hscService);
+ }
+ CloseServiceHandle(hscManager);
+ }
+ return(bReturn);
+}
+
+
+
+
+
+//--------------------------------------------------------------------------//
+// get a list of installed servers //
+//--------------------------------------------------------------------------//
+int WD_GetRunningServerCount(void)
+{
+ int nServerCount = 0;
+ int nEnumIndex = 0;
+ char szServerId[MAX_PATH];
+ DWORD cbServerId = sizeof(szServerId);
+ char szServerRoot[MAX_PATH];
+ DWORD cbServerRoot = sizeof(szServerRoot);
+
+ while(WD_GetServerId(nEnumIndex++, szServerId, &cbServerId))
+ {
+ cbServerId = sizeof(szServerId);
+ // we have an entry that MIGHT be a server, but check to see if it really is one
+ if(WD_GetServerConfig(szServerId, szServerRoot, &cbServerRoot))
+ {
+ if(WD_IsServiceRunning(szServerId))
+ nServerCount++;
+ }
+ cbServerRoot = sizeof(szServerRoot);
+ }
+
+ return(nServerCount);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+DWORD WD_GetDefaultKeyValue(char *szServerName, char *szKeyName, DWORD dwDefault)
+{
+ HANDLE hSlapdKey = 0;
+ char szSlapdKey[MAX_LINE];
+ DWORD dwValueType;
+ DWORD dwValue = dwDefault;
+ DWORD cbValue = sizeof(dwValue);
+
+ // query registry key to figure out config directory
+ sprintf(szSlapdKey, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT,
+ szServerName);
+ if(RegOpenKey(HKEY_LOCAL_MACHINE, szSlapdKey, &hSlapdKey) == ERROR_SUCCESS)
+ {
+ RegQueryValueEx(hSlapdKey, szKeyName, NULL, &dwValueType,
+ (LPBYTE)&dwValue, &cbValue);
+ RegCloseKey(hSlapdKey);
+ }
+
+ return(dwValue);
+}
+
+
+//--------------------------------------------------------------------------//
+// figure out if we are running under Windows NT //
+//--------------------------------------------------------------------------//
+BOOL WD_IsWindowsNT(void)
+{
+ BOOL bReturn = FALSE;
+ OSVERSIONINFO osVersionInfo;
+
+ osVersionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ if(GetVersionEx(&osVersionInfo))
+ {
+ bReturn = (osVersionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT);
+ }
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// figure out if we have enough physical memory to operate server //
+//--------------------------------------------------------------------------//
+BOOL WD_IsEnoughResources(void)
+{
+ BOOL bReturn = TRUE;
+ MEMORYSTATUS ms;
+ DWORD dwMinRamFree = 0;
+ DWORD dwMinRamTotal = DEFAULT_MINRAMTOTAL;
+ DWORD dwMinRamPerServer = DEFAULT_MINRAMPERSERVER;
+
+ dwMinRamFree = WD_GetDefaultKeyValue(gszServerName, MINRAMFREE_KEY, DEFAULT_MINRAMFREE);
+ dwMinRamTotal = WD_GetDefaultKeyValue(gszServerName, MINRAMTOTAL_KEY, DEFAULT_MINRAMTOTAL);
+ dwMinRamPerServer = WD_GetDefaultKeyValue(gszServerName, MINRAMPERSERVER_KEY, DEFAULT_MINRAMPERSERVER);
+
+ ZeroMemory((PVOID)&ms, sizeof(ms));
+ GlobalMemoryStatus(&ms);
+
+ if((ms.dwTotalPhys < (dwMinRamTotal * 1024)) || (ms.dwAvailPhys < (dwMinRamFree * 1024)))
+ bReturn = FALSE;
+
+ if(ms.dwTotalPhys < (WD_GetRunningServerCount() * dwMinRamPerServer * 1024))
+ bReturn = FALSE;
+
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// write error to EventLog service //
+//--------------------------------------------------------------------------//
+BOOL WD_SysLog(WORD fwEventType, DWORD IDEvent, char *szData)
+{
+ BOOL bReturn = FALSE;
+ HANDLE hEventSource;
+ WORD fwCategory = 0; // event category
+ PSID pUserSid = NULL; // user security identifier (optional)
+ WORD cStrings = 1; // number of strings to merge with message
+ DWORD cbData = 0; // size of binary data, in bytes
+ LPCTSTR lpszStrings[64]; // array of strings to merge with message
+ LPVOID lpvData = 0; // address of binary data
+
+ hEventSource = RegisterEventSource(NULL, TEXT(EVENTLOG_APPNAME));
+ if( hEventSource != NULL)
+ {
+ lpszStrings[0] = (LPCTSTR)gszServerName;
+ if(szData != NULL)
+ {
+ lpszStrings[1] = (LPCTSTR)szData;
+ cStrings++;
+ }
+
+ bReturn = ReportEvent(hEventSource, fwEventType, fwCategory,
+ IDEvent, pUserSid, cStrings, cbData,
+ lpszStrings, lpvData);
+ DeregisterEventSource(hEventSource);
+ }
+
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// converts '/' chars to '\' //
+//--------------------------------------------------------------------------//
+void WD_UnixToDosPath(char *szText)
+{
+ if(szText)
+ {
+ while(*szText)
+ {
+ if(*szText == '/')
+
+ *szText = '\\';
+ szText++;
+ }
+ }
+}
+
+
+
+//--------------------------------------------------------------------------//
+// calc szServerRoot given szServerConfig, and store szServerRoot in //
+// SLAPD_ROOT environment variable. //
+//--------------------------------------------------------------------------//
+BOOL WD_GetServerRoot(char *szServerRoot, char *szServerConfig)
+{
+ char szTemp[MAX_LINE], szServerRootEnvVar[MAX_LINE];
+ BOOL bReturn = FALSE;
+ char *szChar = NULL;
+
+ strcpy(szTemp, szServerConfig);
+ // szTemp should be something like c:\navgold\server\slapd-kennedy\config
+ if(szChar = strrchr(szTemp,'\\'))
+ {
+ *szChar = 0;
+ // szTemp should be c:\navgold\server\slapd-kennedy
+ if(szChar = strrchr(szTemp, '\\'))
+ {
+ *szChar = 0;
+ // szTemp should be c:\navgold\server
+ strcpy( szServerRoot, szTemp );
+ wsprintf(szServerRootEnvVar, "%s=%s", SLAPD_ROOT, szTemp);
+ putenv(szServerRootEnvVar);
+ bReturn = TRUE;
+ }
+ }
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// calc szServerConfig given szServerName //
+//--------------------------------------------------------------------------//
+BOOL WD_GetConfigFromRegistry(char *szServerConfig, char *szServerName)
+{
+ BOOL bReturn = FALSE;
+ HANDLE hSlapdKey = 0;
+ char szSlapdKey[MAX_LINE];
+ DWORD dwValueType;
+ char szValueString[MAX_LINE];
+ DWORD cbValueString = sizeof(szValueString);
+ DWORD dwResult = 0;
+
+ // query registry key to figure out config directory
+ sprintf(szSlapdKey, "%s\\%s\\%s", KEY_SOFTWARE_NETSCAPE, SVR_KEY_ROOT,
+ szServerName);
+
+ dwResult = RegOpenKey(HKEY_LOCAL_MACHINE, szSlapdKey, &hSlapdKey);
+ if(dwResult != ERROR_SUCCESS)
+ {
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_REGISTRY, szSlapdKey);
+ return(bReturn);
+ }
+
+ dwResult = RegQueryValueEx(hSlapdKey, VALUE_CONFIG_PATH, NULL,
+ &dwValueType, szValueString, &cbValueString);
+ if(dwResult != ERROR_SUCCESS)
+ {
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_REGISTRY, szSlapdKey);
+ }
+ else
+ {
+ strcpy(szServerConfig, szValueString);
+ WD_UnixToDosPath(szServerConfig);
+ WD_GetServerRoot(gszServerRoot, szServerConfig);
+ bReturn = TRUE;
+ }
+ RegCloseKey(hSlapdKey);
+ return(bReturn);
+}
+
+
+//--------------------------------------------------------------------------//
+// calc szServerConfig and szServerName given szCmdLine //
+//--------------------------------------------------------------------------//
+BOOL WD_GetConfigFromCmdline(char *szServerConfig, char *szServerName, char *szCmdLine)
+{
+ BOOL bReturn = FALSE;
+ char *szChar = NULL;
+
+ if(!szCmdLine || !(strcmp(szCmdLine, "")) )
+ {
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_BADCMDLINE, szCmdLine);
+ return(bReturn);
+ }
+
+ strcpy(szServerConfig, szCmdLine);
+ WD_UnixToDosPath(szCmdLine);
+ WD_GetServerRoot(gszServerRoot, szCmdLine);
+
+ // szCmdLine should be something like c:\navgold\server\slapd-kennedy\config
+ if(szChar = strrchr(szCmdLine, '\\'))
+ {
+ *szChar = 0;
+ // szCmdLine should be c:\navgold\server\slapd-kennedy
+ if(szChar = strrchr(szCmdLine, '\\'))
+ {
+ szChar++;
+ // szChar should point to slapd-kennedy
+ strcpy(szServerName, szChar);
+ WD_GetConfigFromRegistry(szServerConfig, szServerName);
+ bReturn = TRUE;
+
+ }
+ }
+ else
+ {
+ // szCmdLine should be something like slapd-kennedy
+ strcpy(szServerName, szCmdLine);
+ bReturn = WD_GetConfigFromRegistry(szServerConfig, szServerName);
+ }
+
+ if(strlen(szServerName) == 0)
+ {
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_BADCMDLINE, szCmdLine);
+ bReturn = FALSE;
+ }
+
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// parse server config file to see if it security is enabled //
+//--------------------------------------------------------------------------//
+BOOL WD_IsServerSecure(void)
+{
+ BOOL bReturn = FALSE;
+ char szFileName[MAX_PATH];
+ char szText[MAX_LINE];
+ char szSeperators[] = " \t\n";
+ char *szTemp;
+ FILE *fh = NULL;
+
+ sprintf(szFileName, "%s\\%s", gszServerConfig, SLAPD_CONF);
+ if(fh = fopen(szFileName, "r"))
+ {
+ while(!feof(fh))
+ {
+ if(fgets(szText, sizeof(szText), fh))
+ {
+ strlwr(szText);
+
+ /* strtok() is not MT safe on Unix , but it is okay to call
+ here because this file is NT only and strtok() is MT safe on NT */
+
+ if(szTemp = strtok(szText, szSeperators))
+ {
+ if(strcmp(szTemp, "security") == 0)
+ {
+ if(szTemp = strtok(NULL, szSeperators))
+ {
+ if(strcmp(szTemp, "on") == 0)
+ bReturn = TRUE;
+ }
+ break;
+ }
+ }
+ }
+ }
+ fclose(fh);
+ }
+
+ return(bReturn);
+}
+
+//--------------------------------------------------------------------------//
+// message proc window for app window //
+//--------------------------------------------------------------------------//
+LONG APIENTRY WD_MainWndProc(HWND hWnd, UINT message, UINT wParam, LONG lParam)
+{
+ switch(message)
+ {
+ case WM_CREATE:
+ break;
+
+ case WM_CLOSE:
+ SetEvent(ghevWatchDogExit);
+ break;
+
+ case WM_COMMAND:
+ {
+ switch(LOWORD(wParam))
+ {
+ case ID_SERVER_SHUTDOWN:
+ {
+ HANDLE hevShutdown = NULL;
+ char szShutdownEvent[MAX_LINE];
+
+ // shutdown web server, it should exit with 0, WatchDog won't restart it
+ sprintf(szShutdownEvent, "NS_%s", gszServerName);
+ hevShutdown = OpenEvent(EVENT_MODIFY_STATE, FALSE, szShutdownEvent);
+ if(hevShutdown)
+ {
+ SetEvent(hevShutdown); // try to exit gracefully
+ CLOSEHANDLE(hevShutdown);
+ }
+ break;
+ }
+
+ case ID_SERVER_RESTART:
+ {
+ // shutdown web server, it should exit with 2, WatchDog will restart it
+ if(ghServerProcess)
+ {
+ CLOSEHANDLE(ghServerProcess);
+ TerminateProcess(ghServerProcess, 2);
+ }
+ break;
+ }
+
+ case ID_SERVER_SUSPEND:
+ {
+ if(ghServerThread0)
+ SuspendThread(ghServerThread0);
+ break;
+ }
+
+ case ID_SERVER_RESUME:
+ {
+ if(ghServerThread0)
+ ResumeThread(ghServerThread0);
+ break;
+ }
+
+ case ID_FILE_EXIT:
+ PostMessage(hWnd, WM_CLOSE, 0, 0);
+ break;
+ }
+ break;
+ }
+
+ default:
+ return(DefWindowProc(hWnd, message, wParam, lParam));
+ }
+ return(0);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// This window serves as an IPC method with the server process. It has //
+// pointers in it's storage area that the server uses to access the SSL //
+// password. Quite strange, but it works perfectly well. //
+//--------------------------------------------------------------------------//
+HWND WD_CreateWindow()
+{
+ HWND hWndMain = NULL;
+ WNDCLASS wc;
+
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC)WD_MainWndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = sizeof(LONG) * 4;
+ wc.hIcon = LoadIcon(ghInstance, MAKEINTRESOURCE(IDI_LOGO));
+ wc.hInstance = ghInstance;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = GetStockObject(GRAY_BRUSH);
+ wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU);
+ wc.lpszClassName = "slapd";
+
+ RegisterClass(&wc); // class may be registered if more than one instance
+
+ hWndMain = CreateWindow(
+ wc.lpszClassName, /* See RegisterClass() call. */
+ gszServerName, /* Text for window title bar. */
+ WS_OVERLAPPEDWINDOW | /* Window style. */
+ WS_POPUP, /* Window style. */
+ CW_USEDEFAULT, /* Default horizontal position. */
+ CW_USEDEFAULT, /* Default vertical position. */
+ 320, /* Default width. */
+ 0, /* Default height. */
+ NULL, /* Overlapped windows have no parent. */
+ NULL, /* Use the window class menu. */
+ ghInstance, /* This instance owns this window. */
+ NULL /* Pointer not needed. */
+ );
+
+ if(hWndMain)
+ {
+#ifdef SHOW_DEBUG_WINDOW
+ ShowWindow(hWndMain, SW_SHOWDEFAULT);
+#else
+ ShowWindow(hWndMain, SW_HIDE);
+#endif
+ UpdateWindow(hWndMain);
+ }
+ return hWndMain;
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+void WD_WindowThreadProc(LPDWORD lpdwParam)
+{
+ HANDLE hevWindowCreated = (HANDLE)lpdwParam;
+ MSG msg;
+
+ // the ghWndMain global is used all over the place
+ ghWndMain = WD_CreateWindow();
+
+ // inform parent that window creation is complete because it is waiting on us
+ SetEvent(hevWindowCreated);
+
+ if(ghWndMain)
+ {
+ while(GetMessage(&msg, ghWndMain, 0, 0) == TRUE)
+ {
+ TranslateMessage(&msg); // Translates virtual key codes
+ DispatchMessage(&msg); // Dispatches message to window
+ }
+ }
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+void WD_PasswordThreadProc(LPDWORD lpdwParam)
+{
+ // app window must be created sometime during initialization
+ if(ghWndMain)
+ {
+ ZeroMemory(gszPassword, sizeof(gszPassword));
+ SetWindowLong(ghWndMain, GWL_PASSWORD_ADDR, (LONG)gszPassword);
+ SetWindowLong(ghWndMain, GWL_PASSWORD_LENGTH, (LONG)0);
+ }
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL WD_StartServer(PROCESS_INFORMATION *pi)
+{
+ BOOL bReturn = FALSE;
+ char szCmdLine[MAX_LINE];
+ char szServerPath[MAX_PATH];
+ char szInstancePath [MAX_PATH];
+ char *szChar;
+ STARTUPINFO sui;
+ DWORD fdwCreate = DETACHED_PROCESS; /* flags for CreateProcess */
+ int i;
+ char *posfile;
+ UNALIGNED long *posfhnd;
+
+ if(!WD_IsEnoughResources())
+ {
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_STRING, MSG_RESOURCES);
+ gdwServiceError = ERROR_SERVICE_NOT_ACTIVE;
+ return(FALSE);
+ }
+
+ strcpy(szServerPath, gszServerConfig);
+ WD_UnixToDosPath(szServerPath);
+
+ // szServerPath should now be something similar to
+ // c:\navgold\server\slapd-kennedy\config
+ if(szChar = strrchr(szServerPath, '\\'))
+ {
+ *szChar = 0;
+ strcpy (szInstancePath, szServerPath);
+ if(szChar = strrchr(szServerPath, '\\'))
+ {
+ *szChar = 0;
+ }
+ }
+
+ // For Directory Server, service-name is defined as slapd.exe,
+ // in ldapserver/include/nt/regpargms.h
+ sprintf( szCmdLine, "%s\\bin\\%s\\server\\%s -D \"%s\"", szServerPath,
+ PRODUCT_NAME, SERVICE_EXE, szInstancePath );
+ // szCmdLine ex: c:\navgold\server\bin\slapd\slapd.exe
+ // -f c:\navgold\server\slapd-kennedy\config
+
+ memset(&sui,0,sizeof(sui));
+ sui.cb = sizeof(STARTUPINFO);
+
+ /* All of this, to CreateProcess(), allows us to run a console
+ app (slapd.exe) from the service (ns-slapd.exe), without a
+ new console being opened for the app.
+ See dospawn.c in the crt src for more details.
+ */
+ sui.cbReserved2 = (WORD)(sizeof( int ) + (3 *
+ (sizeof( char ) + sizeof( long ))));
+
+ sui.lpReserved2 = calloc( sui.cbReserved2, 1 );
+
+ *((UNALIGNED int *)(sui.lpReserved2)) = 3;
+
+ posfile = (char *)(sui.lpReserved2 + sizeof( int ));
+
+ posfhnd = (UNALIGNED long *)(sui.lpReserved2 + sizeof( int ) +
+ (3 * sizeof( char )));
+
+ for ( i = 0,
+ posfile = (char *)(sui.lpReserved2 + sizeof( int )),
+ posfhnd = (UNALIGNED long *)(sui.lpReserved2 + sizeof( int )
+ + (3 * sizeof( char ))) ;
+ i < 3 ;
+ i++, posfile++, posfhnd++ )
+ {
+ *posfile = 0;
+ *posfhnd = (long)INVALID_HANDLE_VALUE;
+ }
+
+ fdwCreate |= CREATE_SUSPENDED;
+ bReturn = CreateProcess(NULL, szCmdLine, NULL, NULL,
+ TRUE, fdwCreate, NULL, NULL, &sui, pi );
+ if(bReturn)
+ {
+ ghServerProcess = pi->hProcess; // used by app window
+ ghServerThread0 = pi->hThread; // used by app window
+ if(DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(),
+ pi->hProcess, (LPHANDLE)&ghDuplicateProcess,
+ (DWORD)PROCESS_VM_READ | PROCESS_VM_WRITE |
+ PROCESS_ALL_ACCESS, FALSE, (DWORD)0))
+ {
+ SetWindowLong(ghWndMain, GWL_PROCESS_HANDLE,
+ (LONG)ghDuplicateProcess);
+ }
+ ResumeThread(pi->hThread);
+ }
+ else
+ {
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_STARTFAILED, szCmdLine);
+ }
+
+ free( sui.lpReserved2 );
+
+ return(bReturn);
+}
+
+
+
+
+//------------------------------------------------------z--------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL WD_CreatePasswordThread(void)
+{
+ #define NUM_WAIT_OBJECTS 2
+ enum { CHILD_PROCESS, EXIT_EVENT };
+
+ BOOL bReturn = FALSE;
+ HANDLE lphObject[NUM_WAIT_OBJECTS];
+ HANDLE hPasswordThread;
+ DWORD dwThreadID;
+ DWORD dwResult;
+
+ lphObject[EXIT_EVENT] = ghevWatchDogExit;
+
+ hPasswordThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0,
+ (LPTHREAD_START_ROUTINE)WD_PasswordThreadProc, NULL, 0, &dwThreadID);
+ if(hPasswordThread)
+ {
+ lphObject[CHILD_PROCESS] = hPasswordThread;
+ dwResult = WaitForMultipleObjects(NUM_WAIT_OBJECTS, lphObject, FALSE, INFINITE);
+ CLOSEHANDLE(hPasswordThread);
+ if(dwResult == WAIT_OBJECT_0 + EXIT_EVENT) // user stopped service
+ {
+ EndDialog(ghdlgPassword, 1);
+ }
+ bReturn = TRUE;
+ }
+ else
+ {
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_BADPASSWORD, NULL);
+ }
+ return(bReturn);
+}
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL WD_CreateWindowThread(void)
+{
+ BOOL bReturn = FALSE;
+ DWORD dwThreadID;
+ HANDLE hWindowThread;
+ HANDLE hevWindowCreated = NULL;
+
+ if(hevWindowCreated = CreateEvent(NULL, FALSE, FALSE, NULL))
+ {
+ if(hWindowThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0,
+ (LPTHREAD_START_ROUTINE)WD_WindowThreadProc, (LPVOID)hevWindowCreated, 0, &dwThreadID))
+ {
+ // make sure ghHwndMain is created otherwise
+ // SetWindowLong(ghWndMain) will fail in other threads
+ WaitForSingleObject(hevWindowCreated, INFINITE);
+ CLOSEHANDLE(hWindowThread);
+ bReturn = TRUE;
+ }
+ }
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL WD_CreateCronThread(HANDLE hevWatchDogExit)
+{
+ BOOL bReturn = FALSE;
+ DWORD dwThreadID = 0;
+ HANDLE hWindowThread = NULL;
+#if 0
+ if(hWindowThread = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0,
+ (LPTHREAD_START_ROUTINE)CRON_ThreadProc, (LPVOID)hevWatchDogExit, 0, &dwThreadID))
+ {
+ CLOSEHANDLE(hWindowThread);
+ bReturn = TRUE;
+ }
+#endif
+ return(bReturn);
+}
+
+
+//--------------------------------------------------------------------------//
+// signals event create by SNMP agent for notification of server shutdown //
+//--------------------------------------------------------------------------//
+#if 0
+BOOL WS_SendSNMPTrapSignal(void)
+{
+ BOOL bReturn = FALSE;
+ HANDLE hevShutdown = NULL;
+ char szShutdownEvent[MAX_LINE];
+
+ sprintf(szShutdownEvent, NSEV_SNMPTRAP_HTTP);
+ hevShutdown = OpenEvent(EVENT_MODIFY_STATE, FALSE, szShutdownEvent);
+ if(hevShutdown)
+ {
+ SetEvent(hevShutdown);
+ CLOSEHANDLE(hevShutdown);
+ bReturn = TRUE;
+ }
+ return(bReturn);
+}
+#endif
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL WD_MonitorServer(void)
+{
+ #define NUM_WAIT_OBJECTS 2
+ enum { SERVER_PROCESS, WATCHDOG_EXIT };
+
+ BOOL bReturn = FALSE;
+ HANDLE lphObject[NUM_WAIT_OBJECTS];
+ DWORD dwResult = 0;
+ DWORD dwExitCode = 0;
+ PROCESS_INFORMATION pi;
+ HANDLE hevServerDone = NULL;
+ char szServerDoneEvent[MAX_LINE];
+ char szText[MAX_LINE];
+ DWORD dwTickCount = 0;
+
+ lphObject[WATCHDOG_EXIT] = ghevWatchDogExit;
+
+ while(WD_StartServer(&pi))
+ {
+ dwTickCount = GetTickCount();
+ lphObject[SERVER_PROCESS] = pi.hProcess;
+ dwResult = WaitForMultipleObjects(NUM_WAIT_OBJECTS, lphObject, FALSE, INFINITE);
+
+ //WS_SendSNMPTrapSignal();
+
+ if(dwResult == WAIT_OBJECT_0 + WATCHDOG_EXIT)
+ {
+ // shutdown web server
+ //CLOSEHANDLE(pi.hProcess); // XXXahakim close them after TerminateProcess()
+ //CLOSEHANDLE(pi.hThread);
+ sprintf(szServerDoneEvent, "NS_%s", gszServerName);
+ hevServerDone = OpenEvent(EVENT_MODIFY_STATE, FALSE, szServerDoneEvent);
+ if(hevServerDone)
+ {
+ SetEvent(hevServerDone); // try to exit gracefully
+ CLOSEHANDLE(hevServerDone);
+ WaitForSingleObject(lphObject[SERVER_PROCESS], 1000 * DEFAULT_KILL_TIME);
+ }
+ // but just in case it's still alive, swat it again, harder!
+ TerminateProcess(lphObject[SERVER_PROCESS], 1);
+ CLOSEHANDLE(pi.hProcess); // XXXahakim moved from above 03/06/96
+ CLOSEHANDLE(pi.hThread);
+ bReturn = TRUE;
+ }
+ else
+ if(dwResult == WAIT_OBJECT_0 + SERVER_PROCESS)
+ {
+ // why did web server shutdown?
+ // GetExitCodeProcess(lphObject[SERVER_PROCESS], &dwExitCode);
+ // if(dwExitCode != 0)
+ // checking the exit code is bogus because a crashed process can return
+ // anything, including 0, so we use another method to determine if the
+ // server shutdown legitimately, which is similar to how unix works
+ // according to robm.
+
+ // check to see if a specified amount of time has elapsed since the server
+ // started. If it's "infant mortality" don't bother restarting it
+ // because chances are it will continue to fail (such as when the password
+ // is bad, or if there is some other severe startup problem)
+ if(GetTickCount() - dwTickCount > 1000 * WD_GetDefaultKeyValue(gszServerName, MORTALITY_KEY, DEFAULT_MORTALITY_TIME))
+ {
+ sprintf(szText, "%d", dwExitCode);
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_RESTART, szText);
+ CLOSEHANDLE(pi.hProcess);
+ CLOSEHANDLE(pi.hThread);
+ CLOSEHANDLE(ghDuplicateProcess);
+ Sleep(DEFAULT_RESTART_TIME * 1000);
+ continue;
+ }
+ // server closed legitimately
+ else
+ bReturn = TRUE;
+ }
+ CLOSEHANDLE(pi.hProcess);
+ CLOSEHANDLE(pi.hThread);
+ CLOSEHANDLE(ghDuplicateProcess);
+ break;
+ }
+
+ return(bReturn);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+BOOL WD_SetServiceStatus(DWORD dwCurrentState, DWORD dwError)
+{
+ BOOL bReturn = FALSE;
+ SERVICE_STATUS ssStatus;
+
+ if(gsshServiceStatus)
+ {
+ gdwLastStatus = dwCurrentState;
+ ssStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ ssStatus.dwCurrentState = dwCurrentState;
+ ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+ SERVICE_ACCEPT_PAUSE_CONTINUE |
+ SERVICE_ACCEPT_SHUTDOWN;
+ ssStatus.dwWin32ExitCode = dwError;
+ ssStatus.dwServiceSpecificExitCode = (NO_ERROR ? 0 : 1);
+ ssStatus.dwCheckPoint = 0;
+ ssStatus.dwWaitHint = (1000 * ((dwCurrentState==SERVICE_STOP_PENDING)?600:DEFAULT_KILL_TIME + 1));
+ bReturn = SetServiceStatus(gsshServiceStatus, &ssStatus);
+ }
+ return(FALSE);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+VOID WINAPI WD_ServiceHandler(DWORD fdwControl)
+{
+ switch(fdwControl)
+ {
+ case SERVICE_CONTROL_STOP:
+ case SERVICE_CONTROL_SHUTDOWN:
+ WD_SetServiceStatus(SERVICE_STOP_PENDING, gdwServiceError);
+ SetEvent(ghevWatchDogExit);
+ return;
+
+ case SERVICE_CONTROL_PAUSE:
+ if(ghServerThread0)
+ {
+ WD_SetServiceStatus(SERVICE_PAUSE_PENDING, gdwServiceError);
+ SuspendThread(ghServerThread0);
+ WD_SetServiceStatus(SERVICE_PAUSED, gdwServiceError);
+ return;
+ }
+ break;
+
+ case SERVICE_CONTROL_CONTINUE:
+ if(ghServerThread0)
+ {
+ WD_SetServiceStatus(SERVICE_CONTINUE_PENDING, gdwServiceError);
+ ResumeThread(ghServerThread0);
+ WD_SetServiceStatus(SERVICE_RUNNING, gdwServiceError);
+ return;
+ }
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE:
+ WD_SetServiceStatus(gdwLastStatus, gdwServiceError);
+ return;
+
+ default:
+ WD_SysLog(EVENTLOG_ERROR_TYPE, MSG_WD_RESTART, "unknown service event");
+ return;
+ }
+ WD_SetServiceStatus(SERVICE_RUNNING, gdwServiceError);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+VOID WD_ServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
+{
+ BOOL bOkToProceed = TRUE;
+ // if SCM calls us lpszArgv will not be NULL
+ BOOL bIsService = (lpszArgv != NULL);
+
+ // register our custom control handler to handle shutdown
+ ghWdogProcess = GetCurrentProcess();
+ SetConsoleCtrlHandler(WD_ControlHandler, TRUE);
+
+ if(bIsService)
+ {
+ gsshServiceStatus = RegisterServiceCtrlHandler(lpszArgv[0],
+ (LPHANDLER_FUNCTION)WD_ServiceHandler);
+ bOkToProceed = (gsshServiceStatus != (SERVICE_STATUS_HANDLE)NULL);
+ if(bOkToProceed)
+ {
+ strcpy(gszServerName, lpszArgv[0]);
+ bOkToProceed = WD_GetConfigFromRegistry(gszServerConfig,
+ gszServerName);
+ }
+ }
+
+ WD_SetServiceStatus(SERVICE_START_PENDING, gdwServiceError);
+
+ if(bOkToProceed)
+ {
+ if(ghevWatchDogExit = CreateEvent(NULL, TRUE, FALSE, gszServerName))
+ {
+ WD_SetServiceStatus(SERVICE_RUNNING, gdwServiceError);
+ WD_CreateWindowThread();
+#if 0
+ WD_CreateCronThread(ghevWatchDogExit);
+#endif
+
+ if(WD_IsServerSecure())
+ {
+ bOkToProceed = WD_CreatePasswordThread();
+ }
+
+ if(bOkToProceed)
+ {
+ WD_MonitorServer();
+ }
+ CLOSEHANDLE(ghevWatchDogExit);
+ }
+ }
+ WD_SetServiceStatus(SERVICE_STOPPED, gdwServiceError);
+}
+
+
+
+//--------------------------------------------------------------------------//
+// //
+//--------------------------------------------------------------------------//
+WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,
+ int nCmdShow)
+{
+ SERVICE_TABLE_ENTRY steServiceTable[2];
+
+#ifdef PUMPKIN_HOUR
+ if(time(NULL) > (PUMPKIN_HOUR - 10))
+ {
+ char szMessage[256];
+ sprintf( szMessage, " ** This beta software has expired **\n");
+ MessageBox(GetDesktopWindow(), szMessage,
+ DS_NAME_FULL_VERSION, MB_ICONEXCLAMATION | MB_OK);
+ exit(1);
+ }
+#endif
+
+ if(!hPrevInstance) // other instances of app running?
+ {
+ ghInstance = hInstance;
+ memset(gszPassword, 0, sizeof(gszPassword));
+ memset(gszServerConfig, 0, sizeof(gszServerConfig));
+ memset(gszServerName, 0, sizeof(gszServerName));
+ if(WD_IsWindowsNT() && (lpCmdLine) && (strlen(lpCmdLine) == 0))
+ {
+ // run as service
+ steServiceTable[0].lpServiceName = TEXT(PRODUCT_NAME);
+ steServiceTable[0].lpServiceProc =
+ (LPSERVICE_MAIN_FUNCTION)WD_ServiceMain;
+ steServiceTable[1].lpServiceName = NULL;
+ steServiceTable[1].lpServiceProc = NULL;
+ StartServiceCtrlDispatcher(steServiceTable);
+ }
+ else
+ {
+ // run as application
+ if(WD_GetConfigFromCmdline(gszServerConfig,
+ gszServerName, lpCmdLine))
+ {
+ WD_ServiceMain(0, (LPTSTR *)NULL);
+ }
+ }
+ }
+ return(FALSE);
+}
diff --git a/ldap/servers/slapd/object.c b/ldap/servers/slapd/object.c
new file mode 100644
index 00000000..7fb90164
--- /dev/null
+++ b/ldap/servers/slapd/object.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 **/
+
+/* Implementation note:
+ PR_AtomicIncrement and PR_AtomicDecrement both return a value whose
+ sign is the same sign (or zero) as the variable *after* it was updated.
+ They do not return the previous value.
+*/
+
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+
+typedef struct object
+{
+ PRInt32 refcnt; /* reference count for the object */
+ FNFree destructor; /* Destructor for the object */
+ void *data; /* pointer to actual node data */
+} object;
+
+
+/*
+ * Create a new object.
+ * The object is created with refcnt set to 1. The caller implicitly gets
+ * a reference to the object, to prevent a race condition where the object
+ * is destroyed immediately after contruction.
+ * The provided destructor function will be called when all references to
+ * the object have been released.
+ *
+ * Returns a pointer to the new object.
+ */
+Object *
+object_new(void *user_data, FNFree destructor)
+{
+ Object *o;
+ o = (object *)slapi_ch_malloc(sizeof(object));
+ o->refcnt = 1;
+ o->destructor = destructor;
+ o->data = user_data;
+ return o;
+}
+
+
+/*
+ * Acquire a reference object. The caller must hold a reference
+ * to the object, or know for certain that a reference is held
+ * and will continue to be held while this call is in progress.
+ */
+void
+object_acquire(Object *o)
+{
+ PR_ASSERT(NULL != o);
+ PR_AtomicIncrement(&o->refcnt);
+}
+
+
+/*
+ * Release a reference to an object. The pointer to the object
+ * should not be referenced after this call is made, since the
+ * object may be destroyed if this is the last reference to it.
+ */
+void
+object_release(Object *o)
+{
+ PRInt32 refcnt_after_release;
+
+ PR_ASSERT(NULL != o);
+ refcnt_after_release = PR_AtomicDecrement(&o->refcnt);
+ PR_ASSERT(refcnt_after_release >= 0);
+ if (refcnt_after_release == 0)
+ {
+ /* Object can be destroyed */
+ if (o->destructor)
+ o->destructor(&o->data);
+ /* Make it harder to reuse a dangling pointer */
+ o->data = NULL;
+ o->destructor = NULL;
+ o->refcnt = -9999;
+ slapi_ch_free((void **)&o);
+ }
+}
+
+/*
+ * Get the data pointer from an object.
+ * Results are undefined if the caller does not hold a reference
+ * to the object.
+ */
+void *
+object_get_data(Object *o)
+{
+ PR_ASSERT(NULL != o);
+ return o->data;
+}
diff --git a/ldap/servers/slapd/objset.c b/ldap/servers/slapd/objset.c
new file mode 100644
index 00000000..ceb5f225
--- /dev/null
+++ b/ldap/servers/slapd/objset.c
@@ -0,0 +1,380 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slapi-plugin.h"
+#include "slapi-private.h"
+
+/*
+ * The "wrapper" placed around objects in our object set.
+ */
+typedef struct objset_object
+{
+ Object *obj; /* pointer to actual object */
+ struct objset_object *next; /* pointer to next object in list */
+} objset_object;
+
+/*
+ * The object set itself.
+ */
+typedef struct objset
+{
+ objset_object *head; /* pointer to linked list of objects */
+ objset_object *tail; /* pointer to tail of linked list */
+ PRLock *lock; /* Lock - protects addition/deletion from list */
+ FNFree destructor; /* Destructor callback for objset itself */
+} objset;
+
+/* Forward declarations */
+static void unlinkObjsetObjectNoLock(Objset *o, objset_object *obj_to_unlink);
+
+
+/*
+ * Create a new, empty object set.
+ * Returns a pointer to the new object set, or NULL if an error occurred.
+ */
+Objset *
+objset_new(FNFree objset_destructor)
+{
+ objset *set;
+
+ set = (objset *)slapi_ch_malloc(sizeof(objset));
+ set->lock = PR_NewLock();
+ if (NULL == set->lock)
+ {
+ slapi_ch_free((void **)&set);
+ }
+ else
+ {
+ set->head = set->tail = NULL;
+ set->destructor = objset_destructor;
+ }
+ return set;
+}
+
+
+/*
+ * Delete an object set. All references to contained objects
+ * are released, and the objset is deleted.
+ */
+void
+objset_delete(Objset **setp)
+{
+ objset_object *o, *o_next;
+ Objset *set;
+
+ PR_ASSERT(NULL != setp);
+ set = *setp;
+ PR_ASSERT(NULL != set);
+ PR_Lock(set->lock);
+ o = set->head;
+ while (NULL != o)
+ {
+ o_next = o->next;
+ object_release(o->obj); /* release our reference */
+ slapi_ch_free((void **)&o); /* Free wrapper */
+ o = o_next;
+ }
+ PR_Unlock(set->lock);
+ PR_DestroyLock(set->lock);
+ if (NULL != set->destructor)
+ {
+ set->destructor((void **)setp);
+ }
+ slapi_ch_free((void **)setp);
+}
+
+
+
+/*
+ * Add a new object to an object set.
+ * Return values:
+ * OBJSET_SUCCESS: the insertion was succesful.
+ * OBJSET_ALREADY_EXISTS: the object already exists in the set.
+ */
+int
+objset_add_obj(Objset *set, Object *object)
+{
+ objset_object *p;
+ int exists = 0;
+ int rc = OBJSET_SUCCESS;
+
+ PR_ASSERT(NULL != set);
+ PR_ASSERT(NULL != object);
+
+ PR_Lock(set->lock);
+ /* Make sure this object isn't already in the set */
+ p = set->head;
+ while (NULL != p)
+ {
+ if (p->obj == object)
+ {
+ exists = 1;
+ break;
+ }
+ p = p->next;
+ }
+ if (exists)
+ {
+ rc = OBJSET_ALREADY_EXISTS;
+ }
+ else
+ {
+ objset_object *new_node = (objset_object *)slapi_ch_malloc(sizeof(objset_object));
+ object_acquire(object); /* Record our reference */
+ new_node->obj = object;
+ new_node->next = NULL;
+
+ if (NULL == set->head)
+ {
+ set->head = set->tail = new_node;
+ }
+ else
+ {
+ set->tail->next = new_node;
+ set->tail = new_node;
+ }
+ }
+ PR_Unlock(set->lock);
+ return rc;
+}
+
+
+/*
+ * Locate an object in an object set.
+ *
+ * Arguments:
+ * set: the object set to search
+ * compare_fn: a caller-provided function used to compare the
+ * name against an object. This function should return
+ * a negtive value, zero, or a positive value if the
+ * object's name is, respectively, less that, equal
+ * to, or greater than the provided name.
+ * name: the name (value) to find.
+ *
+ * The returned object, if any, is referenced. The caller must
+ * call object_release() when finished with the object.
+ *
+ * Returns the object, if found. Otherwise, returns NULL.
+ * Implementation note: since we store objects in an unordered
+ * linked list, all that's really important is that the compare_fn
+ * return 0 when a match is found, and non-zero otherwise.
+ * Other types of implementations might try to optimize the
+ * storage, e.g. binary search.
+ */
+Object *
+objset_find(Objset *set, CMPFn compare_fn, const void *name)
+{
+ objset_object *found = NULL;
+
+ PR_ASSERT(NULL != set);
+ PR_ASSERT(NULL != name);
+ PR_ASSERT(NULL != compare_fn);
+
+ PR_Lock(set->lock);
+ found = set->head;
+ while (NULL != found)
+ {
+ if (compare_fn(found->obj, name) == 0)
+ {
+ break;
+ }
+ found = found->next;
+ }
+ if (NULL != found)
+ {
+ /* acquire object */
+ object_acquire(found->obj);
+ }
+ PR_Unlock(set->lock);
+ return found == NULL ? NULL : found->obj;
+}
+
+
+
+
+/*
+ * Remove an object from an objset.
+ * Returns OBJSET_SUCCESS if the object was found and removed, or
+ * OBJSET_NO_SUCH_OBJECT if the object was not found in the list.
+ */
+int
+objset_remove_obj(Objset *set, Object *object)
+{
+ int rc = OBJSET_SUCCESS;
+ objset_object *found;
+
+ PR_ASSERT(NULL != set);
+ PR_ASSERT(NULL != object);
+
+ PR_Lock(set->lock);
+ found = set->head;
+ while (NULL != found)
+ {
+ if (found->obj == object)
+ {
+ break;
+ }
+ found = found->next;
+ }
+ if (NULL == found)
+ {
+ rc = OBJSET_NO_SUCH_OBJECT;
+ }
+ else
+ {
+ Object *saved = found->obj;
+
+ /* Unlink from list */
+ unlinkObjsetObjectNoLock(set, found);
+
+ /* Release reference on object */
+ object_release(saved);
+ }
+ PR_Unlock(set->lock);
+ return rc;
+}
+
+
+
+/*
+ * Prepare for iteration across an object set. Returns the first
+ * object in the set. The returned object is referenced, therefore
+ * the caller must either release the object, or
+ * pass it to an objset_next_obj call, which will
+ * implicitly release the object.
+ * Returns the first object, or NULL if the objset contains no
+ * objects.
+ */
+Object *
+objset_first_obj(Objset *set)
+{
+ Object *return_object;
+
+ /* Be tolerant (for the replication plugin) */
+ if (set == NULL) return NULL;
+
+ PR_Lock(set->lock);
+ if (NULL == set->head)
+ {
+ return_object = NULL;
+ }
+ else
+ {
+ object_acquire(set->head->obj);
+ return_object = set->head->obj;
+ }
+ PR_Unlock(set->lock);
+ return return_object;
+}
+
+
+/*
+ * Return the next object in an object set, or NULL if there are
+ * no more objects.
+ * The returned object is referenced, therefore
+ * the caller must either release the object, or
+ * pass it to an objset_next_ob call, which will
+ * implicitly release the object.
+ */
+Object *
+objset_next_obj(Objset *set, Object *previous)
+{
+ Object *return_object = NULL;
+ objset_object *p;
+
+ PR_ASSERT(NULL != set);
+ PR_Lock(set->lock);
+
+ /* First, find the current object */
+ p = set->head;
+ while (NULL != p && p->obj != previous)
+ {
+ p = p->next;
+ }
+ /* Find the next object */
+ if (NULL != p && NULL != p->next)
+ {
+ return_object = p->next->obj;
+ object_acquire(return_object);
+ }
+ PR_Unlock(set->lock);
+ object_release(previous); /* Release the previous object */
+ return return_object;
+}
+
+
+
+/*
+ * Return a non-zero value if the object set is empty, or
+ * zero if the object set is empty.
+ */
+int
+objset_is_empty(Objset *set)
+{
+ int return_value;
+
+ PR_ASSERT(NULL != set);
+
+ PR_Lock(set->lock);
+ return_value = (set->head == NULL);
+ PR_Unlock(set->lock);
+ return return_value;
+}
+
+
+
+/*
+ * Return the count of objects in the object set.
+ */
+int objset_size(Objset *set)
+{
+ int count = 0;
+ objset_object *p;
+
+ PR_ASSERT(NULL != set);
+ PR_Lock(set->lock);
+ for (p = set->head; p; p = p->next)
+ count++;
+ PR_Unlock(set->lock);
+ return count;
+}
+
+
+
+/*
+ * Utility function: remove object from list.
+ * This needs to be called with the objset locked.
+ */
+static void
+unlinkObjsetObjectNoLock(Objset *o, objset_object *obj_to_unlink)
+{
+
+ objset_object *p = o->head;
+
+ PR_ASSERT(NULL != o->head);
+ /* Unlink from list */
+ if (o->head == obj_to_unlink) {
+ /* Object to unlink was at head of list */
+ p = o->head->next;
+ o->head = obj_to_unlink->next;
+ } else {
+ while (NULL != p->next && p->next != obj_to_unlink) {
+ p = p->next;
+ }
+ if (NULL != p->next)
+ {
+ /* p points to object prior to one being removed */
+ p->next = p->next->next;
+ }
+ }
+ if (o->tail == obj_to_unlink)
+ {
+ o->tail = p;
+ }
+
+ /* Free the wrapper */
+ slapi_ch_free((void **)&obj_to_unlink);
+}
diff --git a/ldap/servers/slapd/operation.c b/ldap/servers/slapd/operation.c
new file mode 100644
index 00000000..a049e382
--- /dev/null
+++ b/ldap/servers/slapd/operation.c
@@ -0,0 +1,410 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* operation.c - routines to deal with pending ldap operations */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+
+int
+slapi_op_abandoned( Slapi_PBlock *pb )
+{
+ int op_status;
+
+ op_status = pb->pb_op->o_status;
+
+ return( op_status == SLAPI_OP_STATUS_ABANDONED );
+}
+
+void
+operation_out_of_disk_space()
+{
+ LDAPDebug(LDAP_DEBUG_ANY, "*** DISK FULL ***\n", 0, 0, 0);
+ LDAPDebug(LDAP_DEBUG_ANY, "Attempting to shut down gracefully.\n", 0, 0, 0);
+ g_set_shutdown( SLAPI_SHUTDOWN_DISKFULL );
+}
+
+/* Setting the flags on the operation allows more control to the plugin
+ * to disable and enable checks
+ * Flags that we support for setting in the operation from the plugin are
+ * SLAPI_OP_FLAG_NO_ACCESS_CHECK - do not check for access control
+ * This function can be extended to support other flag setting as well
+ */
+
+void slapi_operation_set_flag(Slapi_Operation *op, unsigned long flag)
+{
+
+ operation_set_flag(op, flag);
+
+}
+
+void slapi_operation_clear_flag(Slapi_Operation *op, unsigned long flag)
+{
+ operation_clear_flag(op, flag);
+
+}
+
+int slapi_operation_is_flag_set(Slapi_Operation *op, unsigned long flag)
+{
+ return operation_is_flag_set(op, flag);
+}
+
+
+
+static int operation_type = -1; /* The type number assigned by the Factory for 'Operation' */
+
+int
+get_operation_object_type()
+{
+ if(operation_type==-1)
+ {
+ /* The factory is given the name of the object type, in
+ * return for a type handle. Whenever the object is created
+ * or destroyed the factory is called with the handle so
+ * that it may call the constructors or destructors registered
+ * with it.
+ */
+ operation_type= factory_register_type(SLAPI_EXT_OPERATION,offsetof(Operation,o_extension));
+ }
+ return operation_type;
+}
+
+/*
+ * Allocate a new Slapi_Operation.
+ * The flag parameter indicates whether the the operation is
+ * external (from an LDAP Client), or internal (from a plugin).
+ */
+Slapi_Operation *
+operation_new(int flags)
+{
+ /* To improve performance, we allocate the Operation, BerElement and
+ * ber buffer in one block, instead of a separate malloc() for each.
+ * Subsequently, ber_special_free() frees them all; we're careful
+ * not to free the Operation separately, and the ber software knows
+ * not to free the buffer separately.
+ */
+ BerElement *ber = NULL;
+ Slapi_Operation *o;
+ if(flags & OP_FLAG_INTERNAL)
+ {
+ o = (Slapi_Operation *) slapi_ch_malloc(sizeof(Slapi_Operation));
+ }
+ else
+ {
+ o= (Slapi_Operation *) ber_special_alloc( sizeof(Slapi_Operation), &ber );
+ }
+ if (NULL != o)
+ {
+ memset(o,0,sizeof(Slapi_Operation));
+ o->o_ber = ber;
+ o->o_msgid = -1;
+ o->o_tag = LBER_DEFAULT;
+ o->o_status = SLAPI_OP_STATUS_PROCESSING;
+ slapi_sdn_init(&(o->o_sdn));
+ o->o_authtype = NULL;
+ o->o_isroot = 0;
+ o->o_time = current_time();
+ o->o_opid = 0;
+ o->o_connid = 0;
+ o->o_next = NULL;
+ o->o_flags= flags;
+ if ( config_get_accesslog_level() & LDAP_DEBUG_TIMING ) {
+ o->o_interval = PR_IntervalNow();
+ } else {
+ o->o_interval = (PRIntervalTime)0;
+ }
+ }
+ return o;
+}
+
+void
+operation_free( Slapi_Operation **op, Connection *conn )
+{
+ if(op!=NULL && *op!=NULL)
+ {
+ /* Call the plugin extension destructors */
+ factory_destroy_extension(get_operation_object_type(),*op,conn,&((*op)->o_extension));
+ slapi_sdn_done(&(*op)->o_sdn);
+ slapi_sdn_free(&(*op)->o_target_spec);
+ free( (*op)->o_authtype );
+ if ( (*op)->o_searchattrs != NULL ) {
+ cool_charray_free( (*op)->o_searchattrs );
+ }
+ if ( NULL != (*op)->o_params.request_controls ) {
+ ldap_controls_free( (*op)->o_params.request_controls );
+ }
+ if ( NULL != (*op)->o_results.result_controls ) {
+ ldap_controls_free( (*op)->o_results.result_controls );
+ }
+ if(operation_is_flag_set(*op, OP_FLAG_INTERNAL))
+ {
+ slapi_ch_free((void**)op);
+ }
+ else
+ {
+ ber_special_free( *op , (*op)->o_ber);
+ }
+ /* counters_to_errors_log("after operation"); */
+ }
+}
+
+void
+slapi_operation_set_csngen_handler ( Slapi_Operation *op, void *callback )
+{
+ op->o_csngen_handler = (csngen_handler) callback;
+}
+
+void
+slapi_operation_set_replica_attr_handler ( Slapi_Operation *op, void *callback )
+{
+ op->o_replica_attr_handler = (replica_attr_handler) callback;
+}
+
+int
+slapi_operation_get_replica_attr ( Slapi_PBlock *pb, Slapi_Operation *op, const char *type, void *value )
+{
+ int rc = -1;
+
+ if (op->o_replica_attr_handler)
+ {
+ rc = op->o_replica_attr_handler ( pb, type, value );
+ }
+
+ return rc;
+}
+
+CSN *
+operation_get_csn(Slapi_Operation *op)
+{
+ return op->o_params.csn;
+}
+
+void
+operation_set_csn(Slapi_Operation *op,CSN *csn)
+{
+ op->o_params.csn= csn;
+}
+
+unsigned long
+slapi_op_get_type(Slapi_Operation *op)
+{
+ return op->o_params.operation_type;
+}
+
+/* DEPRECATED : USE FUNCTION ABOVE FOR NEW DVLPT */
+unsigned long
+operation_get_type(Slapi_Operation *op)
+{
+ return op->o_params.operation_type;
+}
+
+void
+operation_set_type(Slapi_Operation *op, unsigned long type)
+{
+ op->o_params.operation_type= type;
+}
+
+void
+operation_set_flag(Slapi_Operation *op, int flag)
+{
+ op->o_flags|= flag;
+}
+
+void
+operation_clear_flag(Slapi_Operation *op, int flag)
+{
+ op->o_flags &= ~flag;
+}
+
+int
+operation_is_flag_set(Slapi_Operation *op, int flag)
+{
+ return op->o_flags & flag;
+}
+
+Slapi_DN*
+operation_get_target_spec (Slapi_Operation *op)
+{
+ return op->o_target_spec;
+}
+
+void
+operation_set_target_spec (Slapi_Operation *op, const Slapi_DN *target_spec)
+{
+ PR_ASSERT (op);
+ PR_ASSERT (target_spec);
+
+ op->o_target_spec = slapi_sdn_dup(target_spec);
+}
+
+void
+operation_set_target_spec_str (Slapi_Operation *op, const char *target_spec)
+{
+ PR_ASSERT (op);
+
+ op->o_target_spec = slapi_sdn_new_dn_byval (target_spec);
+}
+
+unsigned long operation_get_abandoned_op (const Slapi_Operation *op)
+{
+ PR_ASSERT (op);
+
+ return op->o_abandoned_op;
+}
+
+void operation_set_abandoned_op (Slapi_Operation *op, unsigned long abandoned_op)
+{
+ PR_ASSERT (op);
+
+ op->o_abandoned_op = abandoned_op;
+}
+
+/* slapi_operation_parameters manipulation functions */
+
+struct slapi_operation_parameters *operation_parameters_new()
+{
+ return (slapi_operation_parameters *)slapi_ch_calloc (1, sizeof (slapi_operation_parameters));
+}
+
+static LDAPMod **
+copy_mods(LDAPMod **orig_mods)
+{
+ LDAPMod **new_mods = NULL;
+ LDAPMod *mod;
+ Slapi_Mods smods_old;
+ Slapi_Mods smods_new;
+ slapi_mods_init_byref(&smods_old,orig_mods);
+ slapi_mods_init_passin(&smods_new,new_mods);
+ mod= slapi_mods_get_first_mod(&smods_old);
+ while(mod!=NULL)
+ {
+ slapi_mods_add_modbvps(&smods_new,mod->mod_op,mod->mod_type,mod->mod_bvalues);
+ mod= slapi_mods_get_next_mod(&smods_old);
+ }
+ new_mods= slapi_mods_get_ldapmods_passout(&smods_new);
+ slapi_mods_done(&smods_old);
+ slapi_mods_done(&smods_new);
+ return new_mods;
+}
+
+struct slapi_operation_parameters *
+operation_parameters_dup(struct slapi_operation_parameters *sop)
+{
+ struct slapi_operation_parameters *sop_new= (struct slapi_operation_parameters *)
+ slapi_ch_malloc(sizeof(struct slapi_operation_parameters));
+ memcpy(sop_new,sop,sizeof(struct slapi_operation_parameters));
+ if(sop->target_address.dn!=NULL)
+ {
+ sop_new->target_address.dn= slapi_ch_strdup(sop->target_address.dn);
+ }
+ if(sop->target_address.uniqueid!=NULL)
+ {
+ sop_new->target_address.uniqueid= slapi_ch_strdup(sop->target_address.uniqueid);
+ }
+
+ sop_new->csn= csn_dup(sop->csn);
+ switch(sop->operation_type)
+ {
+ case SLAPI_OPERATION_ADD:
+ sop_new->p.p_add.target_entry= slapi_entry_dup(sop->p.p_add.target_entry);
+ sop_new->p.p_add.parentuniqueid = slapi_ch_strdup(sop->p.p_add.parentuniqueid);
+ break;
+ case SLAPI_OPERATION_MODIFY:
+ sop_new->p.p_modify.modify_mods= NULL;
+ if (sop->p.p_modify.modify_mods!=NULL)
+ {
+ sop_new->p.p_modify.modify_mods = copy_mods(sop->p.p_modify.modify_mods);
+ }
+ break;
+ case SLAPI_OPERATION_MODRDN:
+ if(sop->p.p_modrdn.modrdn_newrdn!=NULL)
+ {
+ sop_new->p.p_modrdn.modrdn_newrdn= slapi_ch_strdup(sop->p.p_modrdn.modrdn_newrdn);
+ }
+ if(sop->p.p_modrdn.modrdn_newsuperior_address.dn!=NULL)
+ {
+ sop_new->p.p_modrdn.modrdn_newsuperior_address.dn =
+ slapi_ch_strdup(sop->p.p_modrdn.modrdn_newsuperior_address.dn);
+ }
+ if(sop->p.p_modrdn.modrdn_newsuperior_address.uniqueid!=NULL)
+ {
+ sop_new->p.p_modrdn.modrdn_newsuperior_address.uniqueid =
+ slapi_ch_strdup(sop->p.p_modrdn.modrdn_newsuperior_address.uniqueid);
+ }
+ sop_new->p.p_modrdn.modrdn_mods= NULL;
+ if (sop->p.p_modrdn.modrdn_mods!=NULL)
+ {
+ sop_new->p.p_modrdn.modrdn_mods = copy_mods(sop->p.p_modrdn.modrdn_mods);
+ }
+ break;
+ case SLAPI_OPERATION_DELETE:
+ /* Has no extra parameters. */
+ case SLAPI_OPERATION_BIND:
+ case SLAPI_OPERATION_COMPARE:
+ case SLAPI_OPERATION_SEARCH:
+ default:
+ /* We are not interested in these. */
+ break;
+ }
+ return sop_new;
+}
+
+void
+operation_parameters_done (struct slapi_operation_parameters *sop)
+{
+ if(sop!=NULL)
+ {
+ slapi_ch_free((void **)&sop->target_address.dn);
+ slapi_ch_free((void **)&sop->target_address.uniqueid);
+ csn_free(&sop->csn);
+
+ switch(sop->operation_type)
+ {
+ case SLAPI_OPERATION_ADD:
+ slapi_entry_free(sop->p.p_add.target_entry);
+ sop->p.p_add.target_entry= NULL;
+ slapi_ch_free((void **)&(sop->p.p_add.parentuniqueid));
+ break;
+ case SLAPI_OPERATION_MODIFY:
+ ldap_mods_free(sop->p.p_modify.modify_mods, 1 /* Free the Array and the Elements */);
+ sop->p.p_modify.modify_mods= NULL;
+ break;
+ case SLAPI_OPERATION_MODRDN:
+ slapi_ch_free((void **)&(sop->p.p_modrdn.modrdn_newrdn));
+ slapi_ch_free((void **)&(sop->p.p_modrdn.modrdn_newsuperior_address.dn));
+ slapi_ch_free((void **)&(sop->p.p_modrdn.modrdn_newsuperior_address.uniqueid));
+ ldap_mods_free(sop->p.p_modrdn.modrdn_mods, 1 /* Free the Array and the Elements */);
+ sop->p.p_modrdn.modrdn_mods= NULL;
+ break;
+ case SLAPI_OPERATION_DELETE:
+ /* Has no extra parameters. */
+ case SLAPI_OPERATION_BIND:
+ case SLAPI_OPERATION_COMPARE:
+ case SLAPI_OPERATION_SEARCH:
+ default:
+ /* We are not interested in these */
+ break;
+ }
+ }
+}
+
+void operation_parameters_free(struct slapi_operation_parameters **sop)
+{
+ if (sop)
+ {
+ operation_parameters_done (*sop);
+ slapi_ch_free ((void**)sop);
+ }
+}
+
+
+
+
+
diff --git a/ldap/servers/slapd/opshared.c b/ldap/servers/slapd/opshared.c
new file mode 100644
index 00000000..e265d420
--- /dev/null
+++ b/ldap/servers/slapd/opshared.c
@@ -0,0 +1,1163 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* opshared.c - functions shared between regular and internal operations */
+
+#include "slap.h"
+#include "index_subsys.h"
+
+/* helper functions */
+static void compute_limits (Slapi_PBlock *pb);
+
+/* attributes that no clients are allowed to add or modify */
+static char *protected_attrs_all [] = { PSEUDO_ATTR_UNHASHEDUSERPASSWORD,
+ NULL
+ };
+static char *pwpolicy_lock_attrs_all [] = { "passwordRetryCount",
+ "retryCountResetTime",
+ "accountUnlockTime",
+ NULL};
+/* Forward declarations */
+static void compute_limits (Slapi_PBlock *pb);
+static int send_results (Slapi_PBlock *pb, int send_result, int *nentries);
+static int process_entry(Slapi_PBlock *pb, Slapi_Entry *e, int send_result);
+
+int op_shared_is_allowed_attr (const char *attr_name, int replicated_op)
+{
+ int i;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ /* check list of attributes that no client is allowed to specify */
+ for (i = 0; protected_attrs_all[i]; i ++)
+ {
+ if (strcasecmp (attr_name, protected_attrs_all[i]) == 0)
+ {
+ /* this attribute is not allowed */
+ return 0;
+ }
+ }
+
+ /* ONREPL - should allow backends to plugin here to specify
+ attributes that are not allowed */
+
+ if (!replicated_op)
+ {
+ /*
+ * check to see if attribute is marked as one clients can't modify
+ */
+ struct asyntaxinfo *asi;
+ int no_user_mod = 0;
+
+ asi = attr_syntax_get_by_name( attr_name );
+ if ( NULL != asi &&
+ 0 != ( asi->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD ))
+ {
+ /* this attribute is not allowed */
+ no_user_mod = 1;
+ }
+ attr_syntax_return( asi );
+
+ if ( no_user_mod ) {
+ return( 0 );
+ }
+ } else if (!slapdFrontendConfig->pw_is_global_policy) {
+ /* check list of password policy attributes for locking accounts */
+ for (i = 0; pwpolicy_lock_attrs_all[i]; i ++)
+ {
+ if (strcasecmp (attr_name, pwpolicy_lock_attrs_all[i]) == 0)
+ {
+ /* this attribute is not allowed */
+ return 0;
+ }
+ }
+ }
+
+ /* this attribute is ok */
+ return 1;
+}
+
+
+static ps_service_fn_ptr ps_service_fn = NULL;
+
+void
+do_ps_service(Slapi_Entry *e, Slapi_Entry *eprev, int chgtype, int chgnum)
+{
+ if (NULL == ps_service_fn) {
+ if (get_entry_point(ENTRY_POINT_PS_SERVICE, (caddr_t *)(&ps_service_fn)) < 0) {
+ return;
+ }
+ }
+ (ps_service_fn)(e, eprev, chgtype, chgnum);
+}
+
+void modify_update_last_modified_attr(Slapi_PBlock *pb, Slapi_Mods *smods)
+{
+ char buf[20];
+ struct berval bv;
+ struct berval *bvals[2];
+ time_t curtime;
+ struct tm utm;
+ Operation *op;
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "modify_update_last_modified_attr\n", 0, 0, 0);
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+
+ /* fill in modifiersname */
+ if (slapi_sdn_isempty(&op->o_sdn)) {
+ bv.bv_val = "";
+ bv.bv_len = strlen(bv.bv_val);
+ } else {
+ bv.bv_val = (char*)slapi_sdn_get_dn(&op->o_sdn);
+ bv.bv_len = strlen(bv.bv_val);
+ }
+
+ slapi_mods_add_modbvps(smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
+ "modifiersname", bvals);
+
+ /* fill in modifytimestamp */
+ curtime = current_time();
+#ifdef _WIN32
+{
+ struct tm *pt;
+ pt = gmtime(&curtime);
+ memcpy(&utm, pt, sizeof(struct tm));
+}
+#else
+ gmtime_r(&curtime, &utm);
+#endif
+ strftime(buf, sizeof(buf), "%Y%m%d%H%M%SZ", &utm);
+ bv.bv_val = buf;
+ bv.bv_len = strlen(bv.bv_val);
+ slapi_mods_add_modbvps(smods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
+ "modifytimestamp", bvals);
+}
+
+/*
+ * Returns: 0 - if the operation is successful
+ * < 0 - if operation fails.
+ * Note that an operation is considered "failed" if a result is sent
+ * directly to the client when send_result is 0.
+ */
+void
+op_shared_search (Slapi_PBlock *pb, int send_result)
+{
+ char *base, *fstr;
+ int scope;
+ Slapi_Backend *be = NULL;
+ Slapi_Backend *be_single = NULL;
+ Slapi_Backend *be_list[BE_LIST_SIZE];
+ Slapi_Entry *referral_list[BE_LIST_SIZE];
+ char ebuf[ BUFSIZ ];
+ char attrlistbuf[ 1024 ], *attrliststr, **attrs = NULL;
+ int rc = 0;
+ int internal_op;
+ Slapi_DN sdn;
+ Slapi_Operation *operation;
+ Slapi_Entry *referral = NULL;
+
+ char errorbuf[BUFSIZ];
+ int nentries,pnentries;
+ int flag_search_base_found = 0;
+ int flag_no_such_object = 0;
+ int flag_referral = 0;
+ int flag_psearch = 0;
+ int err_code = LDAP_SUCCESS;
+ LDAPControl **ctrlp;
+ struct berval *ctl_value = NULL;
+ int iscritical = 0;
+ char * be_name = NULL;
+ int index = 0;
+
+ be_list[0] = NULL;
+ referral_list[0] = NULL;
+
+ /* get search parameters */
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &base);
+ slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
+ slapi_pblock_get(pb, SLAPI_SEARCH_STRFILTER, &fstr);
+ slapi_pblock_get(pb, SLAPI_SEARCH_ATTRS, &attrs);
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+ internal_op= operation_is_flag_set(operation, OP_FLAG_INTERNAL);
+ flag_psearch = operation_is_flag_set(operation, OP_FLAG_PS);
+
+ slapi_sdn_init_dn_byref(&sdn, base);
+
+ if (operation_is_flag_set(operation,OP_FLAG_ACTION_LOG_ACCESS))
+ {
+ char *fmtstr;
+
+#define SLAPD_SEARCH_FMTSTR_BASE "conn=%d op=%d SRCH base=\"%s\" scope=%d "
+#define SLAPD_SEARCH_FMTSTR_BASE_INT "conn=%s op=%d SRCH base=\"%s\" scope=%d "
+#define SLAPD_SEARCH_FMTSTR_REMAINDER " attrs=%s%s\n"
+
+ if ( strlen(fstr) > 1024 )
+ {
+ /*
+ * slapi_log_access() throws away log lines that are longer than
+ * 2048 characters, so we limit the filter string to 1024 (better
+ * to log something rather than nothing)
+ */
+ if ( !internal_op )
+ {
+ fmtstr = SLAPD_SEARCH_FMTSTR_BASE "filter=\"%.1024s...\"" SLAPD_SEARCH_FMTSTR_REMAINDER;
+ }
+ else
+ {
+ fmtstr = SLAPD_SEARCH_FMTSTR_BASE_INT "filter=\"%.1024s...\"" SLAPD_SEARCH_FMTSTR_REMAINDER;
+ }
+ } else {
+ if ( !internal_op )
+ {
+ fmtstr = SLAPD_SEARCH_FMTSTR_BASE "filter=\"%s\"" SLAPD_SEARCH_FMTSTR_REMAINDER;
+ }
+ else
+ {
+ fmtstr = SLAPD_SEARCH_FMTSTR_BASE_INT "filter=\"%s\"" SLAPD_SEARCH_FMTSTR_REMAINDER;
+ }
+ }
+
+ if ( NULL == attrs ) {
+ attrliststr = "ALL";
+ } else {
+ strarray2str( attrs, attrlistbuf, sizeof( attrlistbuf ),
+ 1 /* include quotes */ );
+ attrliststr = attrlistbuf;
+ }
+
+ if ( !internal_op )
+ {
+ slapi_log_access(LDAP_DEBUG_STATS, fmtstr,
+ pb->pb_conn->c_connid,
+ pb->pb_op->o_opid,
+ escape_string(slapi_sdn_get_dn (&sdn), ebuf),
+ scope, fstr, attrliststr,
+ flag_psearch ? " options=persistent" : "");
+ }
+ else
+ {
+ slapi_log_access(LDAP_DEBUG_ARGS, fmtstr,
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ escape_string(slapi_sdn_get_dn (&sdn), ebuf),
+ scope, fstr, attrliststr,
+ flag_psearch ? " options=persistent" : "");
+ }
+ }
+
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET, (void*)slapi_sdn_get_ndn (&sdn));
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ operation_set_target_spec (pb->pb_op, &sdn);
+
+ /* this is time to check if mapping tree specific control
+ * was used to specify that we want to parse only
+ * one backend
+ */
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
+ if (NULL != ctrlp)
+ {
+ if (slapi_control_present(ctrlp, MTN_CONTROL_USE_ONE_BACKEND_EXT_OID,
+ &ctl_value, &iscritical))
+ {
+ /* this control is the smart version of MTN_CONTROL_USE_ONE_BACKEND_OID,
+ * it works out for itself what back end is required (thereby relieving
+ * the client of working out which backend it needs) by looking at the
+ * base of the search if no value is supplied
+ */
+
+ if((ctl_value->bv_len != 0) && ctl_value->bv_val)
+ {
+ be_name = ctl_value->bv_val;
+ }
+ else
+ {
+ /* we don't need no steenkin values */
+ Slapi_Backend *searchbe = slapi_be_select( &sdn );
+
+ if(searchbe && searchbe != defbackend_get_backend())
+ {
+ be_name = slapi_be_get_name(searchbe);
+ }
+ }
+ }
+ else
+ {
+ if (slapi_control_present(ctrlp, MTN_CONTROL_USE_ONE_BACKEND_OID,
+ &ctl_value, &iscritical))
+ {
+ if ((ctl_value->bv_len == 0) || (ctl_value->bv_val == NULL))
+ {
+ rc = -1;
+ send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL);
+ goto free_and_return_nolock;
+ }
+ else
+ {
+ be_name = ctl_value->bv_val;
+ if (be_name == NULL)
+ {
+ rc = -1;
+ send_ldap_result(pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL);
+ goto free_and_return_nolock;
+ }
+ }
+ }
+ }
+
+ if ( slapi_control_present (ctrlp, LDAP_CONTROL_GET_EFFECTIVE_RIGHTS,
+ &ctl_value, &iscritical) )
+ {
+ operation->o_flags |= OP_FLAG_GET_EFFECTIVE_RIGHTS;
+ }
+ }
+
+ if (be_name == NULL)
+ {
+ /* no specific backend was requested, use the mapping tree
+ */
+ err_code = slapi_mapping_tree_select_all(pb, be_list, referral_list, errorbuf);
+ if (((err_code != LDAP_SUCCESS) && (err_code != LDAP_OPERATIONS_ERROR) && (err_code != LDAP_REFERRAL))
+ || ((err_code == LDAP_OPERATIONS_ERROR) && ((be_list == NULL) || be_list[0] == NULL)))
+
+ {
+ send_ldap_result(pb, err_code, NULL, errorbuf, 0, NULL);
+ rc = -1;
+ goto free_and_return;
+ }
+ if (be_list[0] != NULL)
+ {
+ index = 0;
+ while (be_list[index] && be_list[index+1])
+ index++;
+ be = be_list[index];
+ }
+ else
+ be = NULL;
+ }
+ else
+ {
+ /* specific backend be_name was requested, use slapi_be_select_by_instance_name
+ */
+ be_single = be = slapi_be_select_by_instance_name(be_name);
+ if (be_single)
+ slapi_be_Rlock(be_single);
+ be_list[0] = NULL;
+ referral_list[0] = NULL;
+ referral = NULL;
+ }
+
+ slapi_pblock_set(pb, SLAPI_BACKEND_COUNT, &index);
+
+ if (be)
+ {
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+
+ /* adjust time and size limits */
+ compute_limits (pb);
+
+ /* call the pre-search plugins. if they succeed, call the backend
+ search function. then call the post-search plugins. */
+
+ /* ONREPL - should regular plugin be called for internal searches ? */
+ if (plugin_call_plugins(pb, SLAPI_PLUGIN_PRE_SEARCH_FN) == 0)
+ {
+ slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
+ set_db_default_result_handlers(pb);
+
+ /* Now would be a good time to call the search rewriters for computed attrs */
+ rc = compute_rewrite_search_filter(pb);
+ switch (rc)
+ {
+ case 1: /* A rewriter says that we should refuse to perform this search.
+ The potential exists that we will refuse to perform a search
+ which we were going to refer, perhaps to a server which would
+ be willing to perform the search. That's bad. The rewriter
+ could be clever enough to spot this and do the right thing though. */
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Search not supported", 0, NULL);
+ rc = -1;
+ goto free_and_return;
+
+ case -2: /* memory was allocated */
+ /* take note of any changes */
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &base);
+ slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
+
+ slapi_sdn_set_dn_byref(&sdn, base);
+ break;
+
+ case -1:
+ case 0: /* OK */
+ break;
+
+ case 2: /* Operations error */
+ send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL, "search rewriter", 0, NULL);
+ rc = -1;
+ goto free_and_return;
+ }
+
+ } else {
+ /*
+ * A pre-operation plugin handled this search. Grab the return code
+ * (it may have been set by a plugin) and return.
+ *
+ * In DS 5.x, the following two lines of code did not exist, which
+ * means a pre-search function might return a non-zero value (which
+ * indicates that a result was returned to the client) but the code
+ * below would execute the search anyway. This was a regression from
+ * the documented plugin API behavior (and from DS 3.x and 4.x).
+ */
+ slapi_pblock_get(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ goto free_and_return;
+ }
+ }
+
+ /* PAR: now filters have been rewritten, we can assign plugins to work on them */
+ index_subsys_assign_filter_decoders(pb);
+
+ nentries = 0;
+ rc = -1; /* zero backends would mean failure */
+ while (be)
+ {
+ const Slapi_DN * be_suffix;
+
+ if (be->be_search == NULL)
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Function not implemented", 0, NULL);
+ rc = -1;
+ goto free_and_return;
+ }
+
+ pnentries = 0;
+
+ /* the backends returns no such object when a
+ * search is attempted in a node above their nsslapd-suffix
+ * this is correct but a bit annoying when a backends
+ * is below another backend because in that case the
+ * such searches should sometimes succeed
+ * To allow this we therefore have to change the
+ * SLAPI_SEARCH_TARGET parameter in the pblock
+ *
+ * Also when we climb down the mapping tree we have to
+ * change ONE-LEVEL searches to BASE
+ */
+
+ /* that's mean we only support one suffix per backend */
+ be_suffix = slapi_be_getsuffix(be, 0);
+
+ /* be_suffix null means that we are searching the default backend
+ * -> don't change the search parameters in pblock
+ */
+ if (be_suffix != NULL)
+ {
+ if ((be_name == NULL) && (scope == LDAP_SCOPE_ONELEVEL))
+ {
+ /* one level searches
+ * - depending on the suffix of the backend we might have to
+ * do a one level search or a base search
+ * - we might also have to change the search target
+ */
+ if (slapi_sdn_isparent(&sdn, be_suffix)
+ || (slapi_sdn_get_ndn_len(&sdn) == 0))
+ {
+ int tmp_scope = LDAP_SCOPE_BASE;
+ slapi_pblock_set(pb, SLAPI_SEARCH_SCOPE, &tmp_scope);
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET,
+ (void *)slapi_sdn_get_ndn(be_suffix));
+ }
+ else if (slapi_sdn_issuffix(&sdn, be_suffix))
+ {
+ int tmp_scope = LDAP_SCOPE_ONELEVEL;
+ slapi_pblock_set(pb, SLAPI_SEARCH_SCOPE, &tmp_scope);
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET,
+ (void *)slapi_sdn_get_ndn (&sdn));
+ }
+ else
+ goto next_be;
+ }
+
+ /* subtree searches :
+ * if the search was started above the backend suffix
+ * - temporarily set the SLAPI_SEARCH_TARGET to the
+ * base of the node so that we don't get a NO SUCH OBJECT error
+ * - do not change the scope
+ */
+ if (scope == LDAP_SCOPE_SUBTREE)
+ {
+ if (slapi_sdn_issuffix(be_suffix, &sdn))
+ {
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET,
+ (void *)slapi_sdn_get_ndn(be_suffix));
+ }
+ else
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET, (void *)slapi_sdn_get_ndn(&sdn));
+ }
+ }
+
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
+ slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_SET, NULL);
+
+ /* ONREPL - we need to be able to tell the backend not to send results directly */
+ rc = (*be->be_search)(pb);
+ switch (rc)
+ {
+ int err;
+ case 1: /* backend successfully sent result to the client */
+ rc = SLAPI_FAIL_GENERAL;
+ /* fall through */
+
+ case -1: /* an error occurred */
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &err);
+ if (err == LDAP_NO_SUCH_OBJECT)
+ {
+ /* may be the object exist somewhere else
+ * wait the end of the loop to send back this error
+ */
+ flag_no_such_object = 1;
+ break;
+ }
+ else
+ {
+ /* for error other than LDAP_NO_SUCH_OBJECT
+ * the error has already been sent
+ * stop the search here
+ */
+ goto free_and_return;
+ }
+
+ /* when rc == SLAPI_FAIL_DISKFULL this case is executed */
+
+ case SLAPI_FAIL_DISKFULL:
+ operation_out_of_disk_space();
+ goto free_and_return;
+
+ case 0: /* search was successful and we need to send the result */
+ flag_search_base_found++;
+ rc = send_results (pb, 1, &pnentries);
+
+ /* if rc != 0 an error occurred while sending back the entries
+ * to the LDAP client
+ * LDAP error should already have been sent to the client
+ * stop the search, free and return
+ */
+ if (rc != 0)
+ goto free_and_return;
+ break;
+ }
+
+ nentries += pnentries;
+
+ next_be:
+ if (be_list[0] == NULL)
+ {
+ be = NULL;
+ }
+ else
+ {
+ index--;
+ if (index>=0)
+ be = be_list[index];
+ else
+ be = NULL;
+ }
+ }
+
+ /* if referrals were sent back by the mapping tree
+ * add them to the list of referral in the pblock instead
+ * of searching the backend
+ */
+ index = 0;
+ while ((referral = referral_list[index++]) != NULL)
+ {
+ slapi_pblock_set(pb, SLAPI_BACKEND, NULL);
+ if (err_code == LDAP_REFERRAL)
+ {
+ send_referrals_from_entry(pb,referral);
+ goto free_and_return;
+ }
+ else
+ {
+ if (process_entry(pb, referral, 1))
+ {
+ flag_referral++;
+ }
+ else
+ {
+ /* Manage DSA was set, referral must be sent as an entry */
+ int attrsonly;
+ char **attrs = NULL;
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_ATTRS, &attrs);
+ slapi_pblock_get(pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly);
+ slapi_pblock_set(pb, SLAPI_SEARCH_RESULT_ENTRY, referral);
+ switch (send_ldap_search_entry(pb, referral, NULL, attrs, attrsonly))
+ {
+ case 0:
+ flag_search_base_found++;
+ nentries++;
+ break;
+ case 1: /* entry not sent */
+ case -1: /* connection closed */
+ break;
+ }
+ }
+ }
+ }
+
+ if (flag_search_base_found || flag_referral) {
+ rc = 0;
+ }
+
+ /* ONREPL - we currently call postop only if operation is successful;
+ We should always send result and pass error code to the plugin */
+ if (rc == 0) {
+ plugin_call_plugins(pb, SLAPI_PLUGIN_POST_SEARCH_FN);
+ }
+ else
+ {
+ plugin_call_plugins(pb, SLAPI_PLUGIN_POST_SEARCH_FAIL_FN);
+ }
+
+ if (send_result) {
+ if (rc == 0)
+ {
+ /* at least one backend returned something and there was no critical error
+ * from the LDAP client point of view the search was successful
+ */
+ struct berval **urls = NULL;
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_REFERRALS, &urls);
+ send_ldap_result(pb, err_code, NULL, NULL, nentries, urls);
+ }
+ else if (flag_no_such_object)
+ {
+ /* there was at least 1 backend that was called to process
+ * the operation and all backends returned NO SUCH OBJECTS
+ */
+ slapi_send_ldap_result_from_pb(pb);
+ }
+ else
+ {
+ /* No backend was found in the mapping tree to process
+ * the operation : return NO SUCH OBJECT
+ */
+ send_ldap_result(pb, LDAP_NO_SUCH_OBJECT, NULL, NULL, 0, NULL);
+ }
+ } else {
+ /* persistent search: ignore error locating base entry */
+ rc = 0;
+ }
+
+ free_and_return:
+ if ((be_list[0] != NULL) || (referral_list[0] != NULL))
+ slapi_mapping_tree_free_all(be_list, referral_list);
+ else if (be_single)
+ slapi_be_Unlock(be_single);
+
+ free_and_return_nolock:
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET, base);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ index_subsys_filter_decoders_done(pb);
+ slapi_sdn_done(&sdn);
+}
+
+/* Returns 1 if this processing on this entry is finished
+ * and doesn't need to be sent.
+ */
+static int
+process_entry(Slapi_PBlock *pb, Slapi_Entry *e, int send_result)
+{
+ int managedsait;
+ Slapi_Attr *a=NULL;
+ int numValues=0, i;
+
+ if (!send_result)
+ {
+ /* server requested that we don't send results to the client,
+ for instance, in case of a persistent search
+ */
+ return 1;
+ }
+
+ /* ONREPL - check if the entry should be referred (because of the copyingFrom) */
+
+ /*
+ * If this is a referral, and the managedsait control is not present,
+ * arrange for a referral to be sent. For v2 connections,
+ * the referrals are just squirreled away and sent with the
+ * final result. For v3, the referrals are sent in separate LDAP messages.
+ */
+ slapi_pblock_get(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ if (!managedsait && slapi_entry_attr_find(e, "ref", &a)== 0)
+ {
+ /* to fix 522189: when rootDSE, don't interpret attribute ref as a referral entry */
+
+ if ( slapi_is_rootdse(slapi_entry_get_dn_const(e)) )
+ return 0; /* more to do for this entry, e.g., send it back to the client */
+
+ /* end fix */
+ slapi_attr_get_numvalues(a, &numValues );
+ if (numValues == 0)
+ {
+ char ebuf[ BUFSIZ ];
+ LDAPDebug(LDAP_DEBUG_ANY, "null ref in (%s)\n",
+ escape_string(slapi_entry_get_dn_const(e), ebuf), 0, 0);
+ }
+ else
+ {
+ Slapi_Value *val=NULL;
+ struct berval **refscopy=NULL;
+ struct berval **urls, **tmpUrls=NULL;
+ tmpUrls=(struct berval **) slapi_ch_malloc((numValues + 1) * sizeof(struct berval*));
+ for ( i = slapi_attr_first_value(a, &val); i != -1;
+ i = slapi_attr_next_value(a, i, &val)) {
+ tmpUrls[i]=(struct berval*)slapi_value_get_berval(val);
+ }
+ tmpUrls[numValues]=NULL;
+ refscopy = ref_adjust(pb, tmpUrls, slapi_entry_get_sdn_const(e), 1);
+ slapi_pblock_get(pb, SLAPI_SEARCH_REFERRALS, &urls);
+ send_ldap_referral(pb, e, refscopy, &urls);
+ slapi_pblock_set(pb, SLAPI_SEARCH_REFERRALS, urls);
+ if (NULL != refscopy)
+ {
+ ber_bvecfree(refscopy);
+ refscopy = NULL;
+ }
+ if( NULL != tmpUrls) {
+ slapi_ch_free( (void **)&tmpUrls );
+ }
+ }
+
+ return 1; /* done with this entry */
+ }
+
+ return 0;
+}
+
+
+/* Loops through search entries and sends them to the client.
+ * returns -1 on error, 0 if result packet was sent or 1 if
+ * result packet wasn't sent
+ */
+static int
+iterate_with_lookahead(Slapi_PBlock *pb, Slapi_Backend *be, int send_result, int *pnentries)
+{
+ int rc;
+ int attrsonly;
+ int done = 0;
+ Slapi_Entry *e;
+ void *backend_info_ptr;
+ Slapi_Entry *next_e;
+ void *next_backend_info_ptr;
+ char **attrs = NULL;
+ int send_result_status = 0;
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_ATTRS, &attrs);
+ slapi_pblock_get(pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly);
+
+ /* setup for the loop */
+ rc = be->be_next_search_entry_ext(pb, 1);
+ if (rc < 0)
+ {
+ /*
+ * Some exceptional condition occurred. Results
+ * have been sent, so we're finished.
+ */
+ if (rc == SLAPI_FAIL_DISKFULL)
+ {
+ operation_out_of_disk_space();
+ }
+ return -1;
+ }
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_ENTRY, &next_e);
+ slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, &next_backend_info_ptr);
+ if (NULL == next_e)
+ {
+ /* no entries */
+ done = 1;
+ }
+
+ backend_info_ptr = NULL;
+
+ /* Done setting up the loop, now here it comes */
+
+ while (!done)
+ {
+ /* Allow the backend to free the entry we just finished using */
+ /* It is ok to call this when backend_info_ptr is NULL */
+ be->be_entry_release(pb, backend_info_ptr);
+ e = next_e;
+ backend_info_ptr = next_backend_info_ptr;
+
+ rc = be->be_next_search_entry_ext(pb, 1);
+ if (rc < 0)
+ {
+ /*
+ * Some exceptional condition occurred. Results
+ * have been sent, so we're finished.
+ */
+ if (rc == SLAPI_FAIL_DISKFULL)
+ {
+ operation_out_of_disk_space();
+ }
+ return -1;
+ }
+ else
+ {
+ slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_ENTRY, &next_e);
+ slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_ENTRY_EXT, &next_backend_info_ptr);
+ if (next_e == NULL)
+ {
+ /* no more entries */
+ done = 1;
+ }
+ }
+
+ if (process_entry(pb, e, send_result))
+ {
+ /* shouldn't send this entry */
+ continue;
+ }
+
+ /*
+ * It's a regular entry, or it's a referral and
+ * managedsait control is on. In either case, send the entry.
+ */
+ if (done)
+ {
+ struct berval **urls = NULL;
+ /* Send the entry and the result at the same time */
+ slapi_pblock_get(pb, SLAPI_SEARCH_REFERRALS, &urls);
+ rc = send_ldap_search_entry_ext(pb, e, NULL, attrs, attrsonly, 1,
+ (*pnentries)+1, urls);
+ if (rc == 1)
+ {
+ /* this means we didn't have access to the entry. Since the
+ * entry was not sent, we need to send the done packet.
+ */
+ send_result_status = 1;
+ }
+ }
+ else
+ {
+ /* Send the entry */
+ rc = send_ldap_search_entry(pb, e, NULL, attrs,
+ attrsonly);
+ }
+ switch (rc)
+ {
+ case 0: /* entry sent ok */
+ (*pnentries)++;
+ slapi_pblock_set(pb, SLAPI_NENTRIES, pnentries);
+ break;
+ case 1: /* entry not sent */
+ break;
+ case -1: /* connection closed */
+ /*
+ * mark the operation as abandoned so the backend
+ * next entry function gets called again and has
+ * a chance to clean things up.
+ */
+ pb->pb_op->o_status = SLAPI_OP_STATUS_ABANDONED;
+ break;
+ }
+ }
+
+ be->be_entry_release(pb, backend_info_ptr);
+ if (*pnentries == 0 || send_result_status)
+ {
+ /* We didn't send the result done message so the caller
+ * must send it */
+ return 1;
+ }
+ else
+ {
+ /* The result message has been sent */
+ return 0;
+ }
+}
+
+/* Loops through search entries and sends them to the client.
+ * returns -1 on error or 1 if result packet wasn't sent.
+ * This function never returns 0 because it doesn't send
+ * the result packet back with the last entry like
+ * iterate_with_lookahead trys to do.
+ */
+static int
+iterate(Slapi_PBlock *pb, Slapi_Backend *be, int send_result, int *pnentries)
+{
+ int rc;
+ int attrsonly;
+ int done = 0;
+ Slapi_Entry *e;
+ char **attrs = NULL;
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_ATTRS, &attrs);
+ slapi_pblock_get(pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly);
+
+ *pnentries = 0;
+
+ while (!done)
+ {
+ rc = be->be_next_search_entry(pb);
+ if (rc < 0)
+ {
+ /*
+ * Some exceptional condition occurred. Results have been sent, so we're finished.
+ */
+ if (rc == SLAPI_FAIL_DISKFULL)
+ {
+ operation_out_of_disk_space();
+ }
+ return -1;
+ }
+ else
+ {
+ slapi_pblock_get(pb, SLAPI_SEARCH_RESULT_ENTRY, &e);
+ if (e == NULL)
+ {
+ /* no more entries */
+ done = 1;
+ continue;
+ }
+ }
+
+ if (process_entry(pb, e, send_result))
+ {
+ /* shouldn't send this entry */
+ continue;
+ }
+
+ /*
+ * It's a regular entry, or it's a referral and
+ * managedsait control is on. In either case, send
+ * the entry.
+ */
+ switch (send_ldap_search_entry(pb, e, NULL, attrs, attrsonly))
+ {
+ case 0: /* entry sent ok */
+ (*pnentries)++;
+ slapi_pblock_set(pb, SLAPI_NENTRIES, pnentries);
+ break;
+ case 1: /* entry not sent */
+ break;
+ case -1: /* connection closed */
+ /*
+ * mark the operation as abandoned so the backend
+ * next entry function gets called again and has
+ * a chance to clean things up.
+ */
+ pb->pb_op->o_status = SLAPI_OP_STATUS_ABANDONED;
+ break;
+ }
+ }
+
+ return 1;
+}
+
+
+static int timelimit_reslimit_handle = -1;
+static int sizelimit_reslimit_handle = -1;
+
+/*
+ * Register size and time limit with the binder-based resource limits
+ * subsystem. A SLAPI_RESLIMIT_STATUS_... code is returned.
+ */
+int
+search_register_reslimits( void )
+{
+ int rc1, rc2;
+
+ rc1 = slapi_reslimit_register( SLAPI_RESLIMIT_TYPE_INT,
+ "nsSizeLimit" , &sizelimit_reslimit_handle );
+ rc2 = slapi_reslimit_register( SLAPI_RESLIMIT_TYPE_INT,
+ "nsTimeLimit", &timelimit_reslimit_handle );
+
+ if ( rc1 != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ return( rc1 );
+ } else {
+ return( rc2 );
+ }
+}
+
+
+/*
+ * Compute size and time limits based on the connection (bind identity).
+ * Binder-based resource limits get top priority, followed by those associated
+ * with the backend we are using.
+ *
+ * If the binder is the root DN and there is nothing in the root DN's entry
+ * to say otherwise, no limits are used. Otherwise, the lower of the limit
+ * that was sent in the LDAP request and that available based on the
+ * connection bind identity or configured backend limit is used.
+ */
+static void
+compute_limits (Slapi_PBlock *pb)
+{
+ int timelimit, sizelimit;
+ int requested_timelimit, max_timelimit, requested_sizelimit, max_sizelimit;
+ int isroot;
+ int isCertAuth;
+ Slapi_ComponentId *component_id = NULL;
+ Slapi_Backend *be;
+
+ slapi_pblock_get (pb, SLAPI_SEARCH_TIMELIMIT, &requested_timelimit);
+ slapi_pblock_get (pb, SLAPI_SEARCH_SIZELIMIT, &requested_sizelimit);
+ slapi_pblock_get (pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+ slapi_pblock_get (pb, SLAPI_BACKEND, &be);
+
+
+ /* If the search belongs to the client authentication process, take the value at
+ * nsslapd-timelimit as the actual time limit.
+ */
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &component_id);
+ if (component_id) {
+ isCertAuth = (! strcasecmp(component_id->sci_component_name, COMPONENT_CERT_AUTH) ) ? 1 : 0;
+ if (isCertAuth) {
+ timelimit = config_get_timelimit();
+ goto set_timelimit;
+ }
+ }
+
+ /*
+ * Compute the time limit.
+ */
+ if ( slapi_reslimit_get_integer_limit( pb->pb_conn,
+ timelimit_reslimit_handle, &max_timelimit )
+ != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ /*
+ * no limit associated with binder/connection or some other error
+ * occurred. use the default maximum.
+ */
+ if ( isroot ) {
+ max_timelimit = -1; /* no limit */
+ } else {
+ max_timelimit = be->be_timelimit;
+ }
+ }
+
+ if ( requested_timelimit == 0 ) {
+ timelimit = ( max_timelimit == -1 ) ? -1 : max_timelimit;
+ } else if ( max_timelimit == -1 || requested_timelimit < max_timelimit ) {
+ timelimit = requested_timelimit;
+ } else {
+ timelimit = max_timelimit;
+ }
+
+ set_timelimit:
+ slapi_pblock_set(pb, SLAPI_SEARCH_TIMELIMIT, &timelimit);
+
+
+ /*
+ * Compute the size limit.
+ */
+ if ( slapi_reslimit_get_integer_limit( pb->pb_conn,
+ sizelimit_reslimit_handle, &max_sizelimit )
+ != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ /*
+ * no limit associated with binder/connection or some other error
+ * occurred. use the default maximum.
+ */
+ if ( isroot ) {
+ max_sizelimit = -1; /* no limit */
+ } else {
+ max_sizelimit = be->be_sizelimit;
+ }
+ }
+
+ if ( requested_sizelimit == 0 ) {
+ sizelimit = ( max_sizelimit == -1 ) ? -1 : max_sizelimit;
+ } else if ( max_sizelimit == -1 || requested_sizelimit < max_sizelimit ) {
+ sizelimit = requested_sizelimit;
+ } else {
+ sizelimit = max_sizelimit;
+ }
+ slapi_pblock_set(pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit);
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "=> compute_limits: sizelimit=%d, timelimit=%d\n",
+ sizelimit, timelimit, 0 );
+}
+
+
+/* Iterates through results and send them to the client.
+ * Returns 0 if successful and -1 otherwise
+ */
+static int send_results (Slapi_PBlock *pb, int send_result, int * nentries)
+{
+ Slapi_Backend *be;
+ int rc;
+ struct berval **urls = NULL;
+
+ slapi_pblock_get (pb, SLAPI_BACKEND, &be);
+
+ if (be->be_next_search_entry == NULL)
+ {
+ /* we need to send the result, but the function to iterate through
+ the result set is not implemented */
+ /* ONREPL - log error */
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Search not supported", 0, NULL);
+ return -1;
+ }
+
+ /* Iterate through the returned result set */
+ if (be->be_next_search_entry_ext != NULL)
+ {
+ /* The iterate look ahead is causing a whole mess with the ACL.
+ ** the entries are now visiting the ACL land in a random way
+ ** and not the ordered way it was before. Until we figure out
+ ** let's not change the behavior.
+ **
+ ** Don't use iterate_with_lookahead because it sends the result
+ * in the same times as the entry and this can cause failure
+ * of the mapping tree scanning algorithme
+ * if (getFrontendConfig()->result_tweak)
+ * {
+ * rc = iterate_with_lookahead(pb, be, send_result, nentries);
+ * }
+ * else
+ */
+ rc = iterate(pb, be, send_result, nentries);
+ }
+ else
+ {
+ rc = iterate(pb, be, send_result, nentries);
+ }
+
+ switch(rc)
+ {
+ case -1: /* an error occured */
+
+ case 0 : /* everything is ok - result is sent */
+ /* If this happens we are dead but hopefully iterate
+ * never sends the result itself
+ */
+ break;
+
+ case 1: /* everything is ok - don't send the result */
+ rc = 0;
+ }
+
+ return rc;
+}
+
+void op_shared_log_error_access (Slapi_PBlock *pb, const char *type, const char *dn, const char *msg)
+{
+ char ebuf[BUFSIZ];
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d %s dn=\"%s\", %s\n",
+ ( pb->pb_conn ? pb->pb_conn->c_connid : 0),
+ ( pb->pb_op ? pb->pb_op->o_opid : 0),
+ type,
+ escape_string( dn, ebuf ),
+ msg ? msg : "" );
+
+}
+
diff --git a/ldap/servers/slapd/pblock.c b/ldap/servers/slapd/pblock.c
new file mode 100644
index 00000000..d4431ddb
--- /dev/null
+++ b/ldap/servers/slapd/pblock.c
@@ -0,0 +1,2930 @@
+/** 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 <string.h>
+#include <sys/types.h>
+#include "slap.h"
+#include "cert.h"
+
+void
+pblock_init( Slapi_PBlock *pb )
+{
+ memset( pb, '\0', sizeof(Slapi_PBlock) );
+}
+
+void
+pblock_init_common(
+ Slapi_PBlock *pb,
+ Slapi_Backend *be,
+ Connection *conn,
+ Operation *op
+)
+{
+ PR_ASSERT( NULL != pb );
+ memset( pb, '\0', sizeof(Slapi_PBlock) );
+ pb->pb_backend = be;
+ pb->pb_conn = conn;
+ pb->pb_op = op;
+}
+
+void
+slapi_pblock_get_common(
+ Slapi_PBlock *pb,
+ Slapi_Backend **be,
+ Connection **conn,
+ Operation **op
+)
+{
+ PR_ASSERT( NULL != pb );
+ PR_ASSERT( NULL != be );
+ PR_ASSERT( NULL != conn );
+ PR_ASSERT( NULL != op );
+ *be = pb->pb_backend;
+ *conn = pb->pb_conn;
+ *op = pb->pb_op;
+}
+
+Slapi_PBlock *
+slapi_pblock_new()
+{
+ Slapi_PBlock *pb;
+
+ pb = (Slapi_PBlock *) slapi_ch_calloc( 1, sizeof(Slapi_PBlock) );
+ return pb;
+}
+
+void
+pblock_done( Slapi_PBlock *pb )
+{
+ if(pb->pb_op!=NULL)
+ {
+ operation_free(&pb->pb_op,pb->pb_conn);
+ }
+ slapi_ch_free((void**)&(pb->pb_result_text));
+}
+
+void
+slapi_pblock_destroy( Slapi_PBlock* pb )
+{
+ if(pb!=NULL)
+ {
+ pblock_done(pb);
+ slapi_ch_free((void**)&pb);
+ }
+}
+
+/* JCM - when pb_o_params is used, check the operation type. */
+/* JCM - when pb_o_results is used, check the operation type. */
+
+#define SLAPI_PLUGIN_TYPE_CHECK(PBLOCK,TYPE) \
+if ( PBLOCK ->pb_plugin->plg_type != TYPE) return( -1 )
+
+
+/*
+ * Macro used to safely retrieve a plugin related pblock value (if the
+ * pb_plugin element is NULL, NULL is returned).
+ */
+#define SLAPI_PBLOCK_GET_PLUGIN_RELATED_POINTER( pb, element ) \
+ ((pb)->pb_plugin == NULL ? NULL : (pb)->pb_plugin->element)
+
+
+int
+slapi_pblock_get( Slapi_PBlock *pblock, int arg, void *value )
+{
+ char *authtype;
+ Slapi_Backend *be;
+
+ PR_ASSERT( NULL != pblock );
+ PR_ASSERT( NULL != value );
+ be = pblock->pb_backend;
+
+ switch ( arg ) {
+ case SLAPI_BACKEND:
+ (*(Slapi_Backend **)value) = be;
+ break;
+ case SLAPI_BACKEND_COUNT:
+ (*(int *)value) = pblock->pb_backend_count;
+ break;
+ case SLAPI_BE_TYPE:
+ if ( NULL == be ) {
+ return( -1 );
+ }
+ (*(char **)value) = be->be_type;
+ break;
+ case SLAPI_BE_READONLY:
+ if ( NULL == be ) {
+ (*(int *)value) = 0; /* default value */
+ } else {
+ (*(int *)value) = be->be_readonly;
+ }
+ break;
+ case SLAPI_BE_LASTMOD:
+ if ( NULL == be ) {
+ (*(int *)value) = (g_get_global_lastmod() == LDAP_ON);
+ } else {
+ (*(int *)value) = (be->be_lastmod == LDAP_ON || (be->be_lastmod
+ == LDAP_UNDEFINED && g_get_global_lastmod() == LDAP_ON));
+ }
+ break;
+ case SLAPI_CONNECTION:
+ (*(Connection **)value) = pblock->pb_conn;
+ break;
+ case SLAPI_CONN_ID:
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_ID \n", 0, 0, 0 );
+ return (-1);
+ }
+ (*(int *)value) = pblock->pb_conn->c_connid;
+ break;
+ case SLAPI_CONN_DN:
+ /*
+ * NOTE: we have to make a copy of this that the caller
+ * is responsible for freeing. otherwise, they would get
+ * a pointer that could be freed out from under them.
+ */
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_DN \n", 0, 0, 0 );
+ return (-1);
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ (*(char **)value) = (NULL == pblock->pb_conn->c_dn ? NULL :
+ slapi_ch_strdup( pblock->pb_conn->c_dn ));
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+ case SLAPI_CONN_AUTHTYPE:/* deprecated */
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_AUTHTYPE \n", 0, 0, 0 );
+ return (-1);
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ authtype = pblock->pb_conn->c_authtype;
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ if (authtype == NULL) {
+ (*(char **)value) = NULL;
+ } else if (strcasecmp(authtype, SLAPD_AUTH_NONE) == 0) {
+ (*(char **)value) = SLAPD_AUTH_NONE;
+ } else if (strcasecmp(authtype, SLAPD_AUTH_SIMPLE) == 0) {
+ (*(char **)value) = SLAPD_AUTH_SIMPLE;
+ } else if (strcasecmp(authtype, SLAPD_AUTH_SSL) == 0) {
+ (*(char **)value) = SLAPD_AUTH_SSL;
+ } else if (strncasecmp(authtype, SLAPD_AUTH_SASL,
+ strlen(SLAPD_AUTH_SASL)) == 0) {
+ (*(char **)value) = SLAPD_AUTH_SASL;
+ } else {
+ (*(char **)value) = "unknown";
+ }
+ break;
+ case SLAPI_CONN_AUTHMETHOD:
+ /* returns a copy */
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_AUTHMETHOD \n", 0, 0, 0 );
+ return (-1);
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ (*(char **)value) = pblock->pb_conn->c_authtype ?
+ slapi_ch_strdup(pblock->pb_conn->c_authtype) : NULL;
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+ case SLAPI_CONN_CLIENTNETADDR:
+ if (pblock->pb_conn == NULL)
+ {
+ memset( value, 0, sizeof( PRNetAddr ));
+ break;
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ if ( pblock->pb_conn->cin_addr == NULL ) {
+ memset( value, 0, sizeof( PRNetAddr ));
+ } else {
+ (*(PRNetAddr *)value) =
+ *(pblock->pb_conn->cin_addr);
+ }
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+ case SLAPI_CONN_SERVERNETADDR:
+ if (pblock->pb_conn == NULL)
+ {
+ memset( value, 0, sizeof( PRNetAddr ));
+ break;
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ if ( pblock->pb_conn->cin_destaddr == NULL ) {
+ memset( value, 0, sizeof( PRNetAddr ));
+ } else {
+ (*(PRNetAddr *)value) =
+ *(pblock->pb_conn->cin_destaddr);
+ }
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+ case SLAPI_CONN_CLIENTIP:
+ if (pblock->pb_conn == NULL)
+ {
+ memset( value, 0, sizeof( struct in_addr ));
+ break;
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ if ( pblock->pb_conn->cin_addr == NULL ) {
+ memset( value, 0, sizeof( struct in_addr ));
+ } else {
+
+ if ( PR_IsNetAddrType(pblock->pb_conn->cin_addr,
+ PR_IpAddrV4Mapped) ) {
+
+ (*(struct in_addr *)value).s_addr =
+ (*(pblock->pb_conn->cin_addr)).ipv6.ip.pr_s6_addr32[3];
+
+ } else {
+ memset( value, 0, sizeof( struct in_addr ));
+ }
+ }
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+ case SLAPI_CONN_SERVERIP:
+ if (pblock->pb_conn == NULL)
+ {
+ memset( value, 0, sizeof( struct in_addr ));
+ break;
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ if ( pblock->pb_conn->cin_destaddr == NULL ) {
+ memset( value, 0, sizeof( PRNetAddr ));
+ } else {
+
+ if ( PR_IsNetAddrType(pblock->pb_conn->cin_destaddr,
+ PR_IpAddrV4Mapped) ) {
+
+ (*(struct in_addr *)value).s_addr =
+ (*(pblock->pb_conn->cin_destaddr)).ipv6.ip.pr_s6_addr32[3];
+
+ } else {
+ memset( value, 0, sizeof( struct in_addr ));
+ }
+
+ }
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+ case SLAPI_CONN_IS_REPLICATION_SESSION:
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_IS_REPLICATION_SESSION \n", 0, 0, 0 );
+ return (-1);
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ (*(int *)value) = pblock->pb_conn->c_isreplication_session;
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+ case SLAPI_CONN_IS_SSL_SESSION:
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_IS_SSL_SESSION \n", 0, 0, 0 );
+ return (-1);
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ (*(int *)value) = pblock->pb_conn->c_flags & CONN_FLAG_SSL;
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+ case SLAPI_CONN_CERT:
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_CERT \n", 0, 0, 0 );
+ return (-1);
+ }
+ ( *(CERTCertificate **) value) = pblock->pb_conn->c_client_cert;
+ break;
+ case SLAPI_OPERATION:
+ (*(Operation **)value) = pblock->pb_op;
+ break;
+ case SLAPI_OPERATION_TYPE:
+ (*(int *)value) = pblock->pb_op->o_params.operation_type;
+ break;
+ case SLAPI_OPINITIATED_TIME:
+ (*(int *)value) = pblock->pb_op->o_time;
+ break;
+ case SLAPI_REQUESTOR_ISROOT:
+ (*(int *)value) = pblock->pb_requestor_isroot;
+ break;
+ case SLAPI_IS_REPLICATED_OPERATION:
+ if(pblock->pb_op==NULL)
+ {
+ (*(int *)value) = 0; /* No Operation -> Not Replicated */
+ }
+ else
+ {
+ (*(int *)value) = (pblock->pb_op->o_flags & (OP_FLAG_REPLICATED | OP_FLAG_LEGACY_REPLICATION_DN));
+ }
+ break;
+ case SLAPI_IS_MMR_REPLICATED_OPERATION:
+ if(pblock->pb_op==NULL)
+ {
+ (*(int *)value) = 0; /* No Operation -> Not Replicated */
+ }
+ else
+ {
+ (*(int *)value) = (pblock->pb_op->o_flags & OP_FLAG_REPLICATED);
+ }
+ break;
+ case SLAPI_IS_LEGACY_REPLICATED_OPERATION:
+ if(pblock->pb_op==NULL)
+ {
+ (*(int *)value) = 0; /* No Operation -> Not Replicated */
+ }
+ else
+ {
+ (*(int *)value) = (pblock->pb_op->o_flags & OP_FLAG_LEGACY_REPLICATION_DN);
+ }
+ break;
+
+ case SLAPI_OPERATION_PARAMETERS:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(struct slapi_operation_parameters **)value) = &pblock->pb_op->o_params;
+ }
+ break;
+
+ /* stuff related to config file processing */
+ case SLAPI_CONFIG_FILENAME:
+ case SLAPI_CONFIG_LINENO:
+ case SLAPI_CONFIG_ARGC:
+ case SLAPI_CONFIG_ARGV:
+ return (-1); /* deprecated since DS 5.0 (no longer useful) */
+
+ /* pblock memory management */
+ case SLAPI_DESTROY_CONTENT:
+ (*(int *)value) = pblock->pb_destroy_content;
+ break;
+
+ /* stuff related to the current plugin */
+ case SLAPI_PLUGIN:
+ (*(struct slapdplugin **)value) = pblock->pb_plugin;
+ break;
+ case SLAPI_PLUGIN_PRIVATE:
+ (*(void **)value) = pblock->pb_plugin->plg_private;
+ break;
+ case SLAPI_PLUGIN_TYPE:
+ (*(int *)value) = pblock->pb_plugin->plg_type;
+ break;
+ case SLAPI_PLUGIN_ARGV:
+ (*(char ***)value) = pblock->pb_plugin->plg_argv;
+ break;
+ case SLAPI_PLUGIN_ARGC:
+ (*(int *)value) = pblock->pb_plugin->plg_argc;
+ break;
+ case SLAPI_PLUGIN_VERSION:
+ (*(char **)value) = pblock->pb_plugin->plg_version;
+ break;
+ case SLAPI_PLUGIN_OPRETURN:
+ (*(int *)value) = pblock->pb_opreturn;
+ break;
+ case SLAPI_PLUGIN_OBJECT:
+ (*(void **)value) = pblock->pb_object;
+ break;
+ case SLAPI_PLUGIN_DESTROY_FN:
+ (*(IFP*)value) = pblock->pb_destroy_fn;
+ break;
+ case SLAPI_PLUGIN_DESCRIPTION:
+ (*(Slapi_PluginDesc *)value) = pblock->pb_plugin->plg_desc;
+ break;
+ case SLAPI_PLUGIN_IDENTITY:
+ (*(void**)value) = pblock->pb_plugin_identity;
+ break;
+ case SLAPI_PLUGIN_INTOP_RESULT:
+ (*(int *)value) = pblock->pb_internal_op_result;
+ break;
+ case SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES:
+ (*(Slapi_Entry ***)value) = pblock->pb_plugin_internal_search_op_entries;
+ break;
+ case SLAPI_PLUGIN_INTOP_SEARCH_REFERRALS:
+ (*(char ***)value) = pblock->pb_plugin_internal_search_op_referrals;
+ break;
+
+ /* database plugin functions */
+ case SLAPI_PLUGIN_DB_BIND_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_bind;
+ break;
+ case SLAPI_PLUGIN_DB_UNBIND_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_unbind;
+ break;
+ case SLAPI_PLUGIN_DB_SEARCH_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_search;
+ break;
+ case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_next_search_entry;
+ break;
+ case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_next_search_entry_ext;
+ break;
+ case SLAPI_PLUGIN_DB_ENTRY_RELEASE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_entry_release;
+ break;
+ case SLAPI_PLUGIN_DB_COMPARE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_compare;
+ break;
+ case SLAPI_PLUGIN_DB_MODIFY_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_modify;
+ break;
+ case SLAPI_PLUGIN_DB_MODRDN_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_modrdn;
+ break;
+ case SLAPI_PLUGIN_DB_ADD_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_add;
+ break;
+ case SLAPI_PLUGIN_DB_DELETE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_delete;
+ break;
+ case SLAPI_PLUGIN_DB_ABANDON_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_abandon;
+ break;
+ case SLAPI_PLUGIN_DB_CONFIG_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_config;
+ break;
+ case SLAPI_PLUGIN_CLOSE_FN:
+ (*(IFP *)value) = pblock->pb_plugin->plg_close;
+ break;
+ case SLAPI_PLUGIN_CLEANUP_FN:
+ (*(IFP *)value) = pblock->pb_plugin->plg_cleanup;
+ break;
+ case SLAPI_PLUGIN_DB_FLUSH_FN:
+ (*(IFP *)value) = pblock->pb_plugin->plg_flush;
+ break;
+ case SLAPI_PLUGIN_START_FN:
+ (*(IFP *)value) = pblock->pb_plugin->plg_start;
+ break;
+ case SLAPI_PLUGIN_POSTSTART_FN:
+ (*(IFP *)value) = pblock->pb_plugin->plg_poststart;
+ break;
+ case SLAPI_PLUGIN_DB_WIRE_IMPORT_FN:
+ (*(IFP *)value) = pblock->pb_plugin->plg_wire_import;
+ break;
+ case SLAPI_PLUGIN_DB_SEQ_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_seq;
+ break;
+ case SLAPI_PLUGIN_DB_ENTRY_FN:
+ (*(IFP *)value) = SLAPI_PBLOCK_GET_PLUGIN_RELATED_POINTER( pblock,
+ plg_entry );
+ break;
+ case SLAPI_PLUGIN_DB_REFERRAL_FN:
+ (*(IFP *)value) = SLAPI_PBLOCK_GET_PLUGIN_RELATED_POINTER( pblock,
+ plg_referral );
+ break;
+ case SLAPI_PLUGIN_DB_RESULT_FN:
+ (*(IFP *)value) = SLAPI_PBLOCK_GET_PLUGIN_RELATED_POINTER( pblock,
+ plg_result );
+ break;
+ case SLAPI_PLUGIN_DB_RMDB_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_rmdb;
+ break;
+ case SLAPI_PLUGIN_DB_INIT_INSTANCE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_init_instance;
+ break;
+ case SLAPI_PLUGIN_DB_LDIF2DB_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_ldif2db;
+ break;
+ case SLAPI_PLUGIN_DB_DB2LDIF_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_db2ldif;
+ break;
+ case SLAPI_PLUGIN_DB_DB2INDEX_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_db2index;
+ break;
+ case SLAPI_PLUGIN_DB_ARCHIVE2DB_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_archive2db;
+ break;
+ case SLAPI_PLUGIN_DB_DB2ARCHIVE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_db2archive;
+ break;
+#if defined(UPGRADEDB)
+ case SLAPI_PLUGIN_DB_UPGRADEDB_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_upgradedb;
+ break;
+#endif
+ case SLAPI_PLUGIN_DB_BEGIN_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_begin;
+ break;
+ case SLAPI_PLUGIN_DB_COMMIT_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_commit;
+ break;
+ case SLAPI_PLUGIN_DB_ABORT_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_abort;
+ break;
+ case SLAPI_PLUGIN_DB_SIZE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_dbsize;
+ break;
+ case SLAPI_PLUGIN_DB_TEST_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_dbtest;
+ break;
+ /* database plugin-specific parameters */
+ case SLAPI_PLUGIN_DB_NO_ACL:
+ if ( pblock->pb_plugin && pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ if ( NULL == be ) {
+ (*(int *)value) = 0; /* default value */
+ } else {
+ (*(int *)value) = be->be_noacl;
+ }
+ break;
+
+ /* extendedop plugin functions */
+ case SLAPI_PLUGIN_EXT_OP_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_EXTENDEDOP ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_exhandler;
+ break;
+ case SLAPI_PLUGIN_EXT_OP_OIDLIST:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_EXTENDEDOP ) {
+ return( -1 );
+ }
+ (*(char ***)value) = pblock->pb_plugin->plg_exoids;
+ break;
+ case SLAPI_PLUGIN_EXT_OP_NAMELIST:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_EXTENDEDOP ) {
+ return( -1 );
+ }
+ (*(char ***)value) = pblock->pb_plugin->plg_exnames;
+ break;
+
+ /* preoperation plugin functions */
+ case SLAPI_PLUGIN_PRE_BIND_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_prebind;
+ break;
+ case SLAPI_PLUGIN_PRE_UNBIND_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_preunbind;
+ break;
+ case SLAPI_PLUGIN_PRE_SEARCH_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_presearch;
+ break;
+ case SLAPI_PLUGIN_PRE_COMPARE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_precompare;
+ break;
+ case SLAPI_PLUGIN_PRE_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_premodify;
+ break;
+ case SLAPI_PLUGIN_PRE_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_premodrdn;
+ break;
+ case SLAPI_PLUGIN_PRE_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_preadd;
+ break;
+ case SLAPI_PLUGIN_PRE_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_predelete;
+ break;
+ case SLAPI_PLUGIN_PRE_ABANDON_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_preabandon;
+ break;
+ case SLAPI_PLUGIN_PRE_ENTRY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_preentry;
+ break;
+ case SLAPI_PLUGIN_PRE_REFERRAL_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_prereferral;
+ break;
+ case SLAPI_PLUGIN_PRE_RESULT_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_preresult;
+ break;
+
+ /* postoperation plugin functions */
+ case SLAPI_PLUGIN_POST_BIND_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postbind;
+ break;
+ case SLAPI_PLUGIN_POST_UNBIND_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postunbind;
+ break;
+ case SLAPI_PLUGIN_POST_SEARCH_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postsearch;
+ break;
+ case SLAPI_PLUGIN_POST_SEARCH_FAIL_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postsearchfail;
+ break;
+ case SLAPI_PLUGIN_POST_COMPARE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postcompare;
+ break;
+ case SLAPI_PLUGIN_POST_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postmodify;
+ break;
+ case SLAPI_PLUGIN_POST_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postmodrdn;
+ break;
+ case SLAPI_PLUGIN_POST_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postadd;
+ break;
+ case SLAPI_PLUGIN_POST_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postdelete;
+ break;
+ case SLAPI_PLUGIN_POST_ABANDON_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postabandon;
+ break;
+ case SLAPI_PLUGIN_POST_ENTRY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postentry;
+ break;
+ case SLAPI_PLUGIN_POST_REFERRAL_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postreferral;
+ break;
+ case SLAPI_PLUGIN_POST_RESULT_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_postresult;
+ break;
+
+ case SLAPI_ENTRY_PRE_OP:
+ (*(Slapi_Entry **)value) = pblock->pb_pre_op_entry;
+ break;
+ case SLAPI_ENTRY_POST_OP:
+ (*(Slapi_Entry **)value) = pblock->pb_post_op_entry;
+ break;
+
+ /* backend preoperation plugin */
+ case SLAPI_PLUGIN_BE_PRE_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_bepremodify;
+ break;
+ case SLAPI_PLUGIN_BE_PRE_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_bepremodrdn;
+ break;
+ case SLAPI_PLUGIN_BE_PRE_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_bepreadd;
+ break;
+ case SLAPI_PLUGIN_BE_PRE_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_bepredelete;
+ break;
+
+ /* backend postoperation plugin */
+ case SLAPI_PLUGIN_BE_POST_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPOSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_bepostmodify;
+ break;
+ case SLAPI_PLUGIN_BE_POST_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPOSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_bepostmodrdn;
+ break;
+ case SLAPI_PLUGIN_BE_POST_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPOSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_bepostadd;
+ break;
+ case SLAPI_PLUGIN_BE_POST_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPOSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_bepostdelete;
+ break;
+
+ /* internal preoperation plugin */
+ case SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_internal_pre_modify;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_internal_pre_modrdn;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_internal_pre_add;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_internal_pre_delete;
+ break;
+
+ /* internal postoperation plugin */
+ case SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_internal_post_modify;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_internal_post_modrdn;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_POST_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_internal_post_add;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_POSTOPERATION) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_internal_post_delete;
+ break;
+
+ /* target address & controls for all operations should be normalized */
+ case SLAPI_TARGET_ADDRESS:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(entry_address **)value) = &(pblock->pb_op->o_params.target_address);
+ }
+ break;
+ /* should be normalized */
+ case SLAPI_TARGET_DN:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **)value) = pblock->pb_op->o_params.target_address.dn;
+ }
+ break;
+ case SLAPI_ORIGINAL_TARGET_DN:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **)value) = pblock->pb_op->o_params.target_address.udn;
+ }
+ break;
+ case SLAPI_TARGET_UNIQUEID:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **)value) = pblock->pb_op->o_params.target_address.uniqueid;
+ }
+ break;
+ case SLAPI_REQCONTROLS:
+ (*(LDAPControl ***)value) = pblock->pb_op->o_params.request_controls;
+ break;
+ case SLAPI_RESCONTROLS:
+ (*(LDAPControl ***)value) = pblock->pb_op->o_results.result_controls;
+ break;
+ case SLAPI_CONTROLS_ARG: /* used to pass control argument before operation is created */
+ (*(LDAPControl ***)value) = pblock->pb_ctrls_arg;
+ break;
+ /* notes to be added to the access log RESULT line for this op. */
+ case SLAPI_OPERATION_NOTES:
+ (*(unsigned int *)value) = pblock->pb_operation_notes;
+ break;
+
+ /* syntax plugin functions */
+ case SLAPI_PLUGIN_SYNTAX_FILTER_AVA:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_syntax_filter_ava;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_FILTER_SUB:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_syntax_filter_sub;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_VALUES2KEYS:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_syntax_values2keys;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_syntax_assertion2keys_ava;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_syntax_assertion2keys_sub;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_NAMES:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ (*(char ***)value) = pblock->pb_plugin->plg_syntax_names;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_OID:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ (*(char **)value) = pblock->pb_plugin->plg_syntax_oid;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_FLAGS:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ (*(int *)value) = pblock->pb_plugin->plg_syntax_flags;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_COMPARE:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ (*(IFP *)value) = pblock->pb_plugin->plg_syntax_compare;
+ break;
+
+ /* controls we know about */
+ case SLAPI_MANAGEDSAIT:
+ (*(int *)value) = pblock->pb_managedsait;
+ break;
+ case SLAPI_PWPOLICY:
+ (*(int *)value) = pblock->pb_pwpolicy_ctrl;
+ break;
+
+ /* add arguments */
+ case SLAPI_ADD_ENTRY:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(Slapi_Entry **)value) = pblock->pb_op->o_params.p.p_add.target_entry;
+ }
+ break;
+ case SLAPI_ADD_EXISTING_DN_ENTRY:
+ (*(Slapi_Entry **)value) = pblock->pb_existing_dn_entry;
+ break;
+ case SLAPI_ADD_EXISTING_UNIQUEID_ENTRY:
+ (*(Slapi_Entry **)value) = pblock->pb_existing_uniqueid_entry;
+ break;
+ case SLAPI_ADD_PARENT_ENTRY:
+ (*(Slapi_Entry **)value) = pblock->pb_parent_entry;
+ break;
+ case SLAPI_ADD_PARENT_UNIQUEID:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **)value) = pblock->pb_op->o_params.p.p_add.parentuniqueid;
+ }
+ break;
+
+ /* bind arguments */
+ case SLAPI_BIND_METHOD:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_params.p.p_bind.bind_method;
+ }
+ break;
+ case SLAPI_BIND_CREDENTIALS:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(struct berval **)value) = pblock->pb_op->o_params.p.p_bind.bind_creds;
+ }
+ break;
+ case SLAPI_BIND_SASLMECHANISM:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **)value) = pblock->pb_op->o_params.p.p_bind.bind_saslmechanism;
+ }
+ break;
+ /* bind return values */
+ case SLAPI_BIND_RET_SASLCREDS:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(struct berval **)value) = pblock->pb_op->o_results.r.r_bind.bind_ret_saslcreds;
+ }
+ break;
+
+ /* compare arguments */
+ case SLAPI_COMPARE_TYPE:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **)value) = pblock->pb_op->o_params.p.p_compare.compare_ava.ava_type;
+ }
+ break;
+ case SLAPI_COMPARE_VALUE:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(struct berval **)value) = &pblock->pb_op->o_params.p.p_compare.compare_ava.ava_value;
+ }
+ break;
+
+ /* modify arguments */
+ case SLAPI_MODIFY_MODS:
+ PR_ASSERT(pblock->pb_op);
+ if(pblock->pb_op!=NULL)
+ {
+ if(pblock->pb_op->o_params.operation_type==SLAPI_OPERATION_MODIFY)
+ {
+ (*(LDAPMod ***)value) = pblock->pb_op->o_params.p.p_modify.modify_mods;
+ }
+ else if(pblock->pb_op->o_params.operation_type==SLAPI_OPERATION_MODRDN)
+ {
+ (*(LDAPMod ***)value) = pblock->pb_op->o_params.p.p_modrdn.modrdn_mods;
+ }
+ else
+ {
+ PR_ASSERT(0); /* JCM */
+ }
+ }
+ break;
+
+ /* modrdn arguments */
+ case SLAPI_MODRDN_NEWRDN:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **)value) = pblock->pb_op->o_params.p.p_modrdn.modrdn_newrdn;
+ }
+ break;
+ case SLAPI_MODRDN_DELOLDRDN:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_params.p.p_modrdn.modrdn_deloldrdn;
+ }
+ break;
+ case SLAPI_MODRDN_NEWSUPERIOR:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **)value) =
+ pblock->pb_op->o_params.p.p_modrdn.modrdn_newsuperior_address.dn;
+ }
+ break;
+ case SLAPI_MODRDN_PARENT_ENTRY:
+ (*(Slapi_Entry **)value) = pblock->pb_parent_entry;
+ break;
+ case SLAPI_MODRDN_NEWPARENT_ENTRY:
+ (*(Slapi_Entry **)value) = pblock->pb_newparent_entry;
+ break;
+ case SLAPI_MODRDN_TARGET_ENTRY:
+ (*(Slapi_Entry **)value) = pblock->pb_target_entry;
+ break;
+ case SLAPI_MODRDN_NEWSUPERIOR_ADDRESS:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(entry_address **)value) = &(pblock->pb_op->o_params.p.p_modrdn.modrdn_newsuperior_address);
+ break;
+ }
+
+ /* search arguments */
+ case SLAPI_SEARCH_SCOPE:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_params.p.p_search.search_scope;
+ }
+ break;
+ case SLAPI_SEARCH_DEREF:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_params.p.p_search.search_deref;
+ }
+ break;
+ case SLAPI_SEARCH_SIZELIMIT:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_params.p.p_search.search_sizelimit;
+ }
+ break;
+ case SLAPI_SEARCH_TIMELIMIT:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_params.p.p_search.search_timelimit;
+ }
+ break;
+ case SLAPI_SEARCH_FILTER:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(struct slapi_filter **)value) = pblock->pb_op->o_params.p.p_search.search_filter;
+ }
+ break;
+ case SLAPI_SEARCH_STRFILTER:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **)value) = pblock->pb_op->o_params.p.p_search.search_strfilter;
+ }
+ break;
+ case SLAPI_SEARCH_ATTRS:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char ***)value) = pblock->pb_op->o_params.p.p_search.search_attrs;
+ }
+ break;
+ case SLAPI_SEARCH_ATTRSONLY:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_params.p.p_search.search_attrsonly;
+ }
+ break;
+ case SLAPI_SEARCH_IS_AND:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_params.p.p_search.search_is_and;
+ }
+ break;
+
+ case SLAPI_ABANDON_MSGID:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_params.p.p_abandon.abandon_targetmsgid;
+ }
+ break;
+
+ /* extended operation arguments */
+ case SLAPI_EXT_OP_REQ_OID:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **) value) = pblock->pb_op->o_params.p.p_extended.exop_oid;
+ }
+ break;
+ case SLAPI_EXT_OP_REQ_VALUE:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(struct berval **)value) = pblock->pb_op->o_params.p.p_extended.exop_value;
+ }
+ break;
+ /* extended operation return values */
+ case SLAPI_EXT_OP_RET_OID:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(char **) value) = pblock->pb_op->o_results.r.r_extended.exop_ret_oid;
+ }
+ break;
+ case SLAPI_EXT_OP_RET_VALUE:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(struct berval **)value) = pblock->pb_op->o_results.r.r_extended.exop_ret_value;
+ }
+ break;
+
+ /* matching rule plugin functions */
+ case SLAPI_PLUGIN_MR_FILTER_CREATE_FN:
+ SLAPI_PLUGIN_TYPE_CHECK (pblock, SLAPI_PLUGIN_MATCHINGRULE);
+ (*(IFP *)value) = pblock->pb_plugin->plg_mr_filter_create;
+ break;
+ case SLAPI_PLUGIN_MR_INDEXER_CREATE_FN:
+ SLAPI_PLUGIN_TYPE_CHECK (pblock, SLAPI_PLUGIN_MATCHINGRULE);
+ (*(IFP *)value) = pblock->pb_plugin->plg_mr_indexer_create;
+ break;
+ case SLAPI_PLUGIN_MR_FILTER_MATCH_FN:
+ (*(mrFilterMatchFn *)value) = pblock->pb_mr_filter_match_fn;
+ break;
+ case SLAPI_PLUGIN_MR_FILTER_INDEX_FN:
+ (*(IFP *)value) = pblock->pb_mr_filter_index_fn;
+ break;
+ case SLAPI_PLUGIN_MR_FILTER_RESET_FN:
+ (*(IFP *)value) = pblock->pb_mr_filter_reset_fn;
+ break;
+ case SLAPI_PLUGIN_MR_INDEX_FN:
+ (*(IFP *)value) = pblock->pb_mr_index_fn;
+ break;
+
+ /* matching rule plugin arguments */
+ case SLAPI_PLUGIN_MR_OID:
+ (*(char **) value) = pblock->pb_mr_oid;
+ break;
+ case SLAPI_PLUGIN_MR_TYPE:
+ (*(char **) value) = pblock->pb_mr_type;
+ break;
+ case SLAPI_PLUGIN_MR_VALUE:
+ (*(struct berval **) value) = pblock->pb_mr_value;
+ break;
+ case SLAPI_PLUGIN_MR_VALUES:
+ (*(struct berval ***) value) = pblock->pb_mr_values;
+ break;
+ case SLAPI_PLUGIN_MR_KEYS:
+ (*(struct berval ***) value) = pblock->pb_mr_keys;
+ break;
+ case SLAPI_PLUGIN_MR_FILTER_REUSABLE:
+ (*(unsigned int *) value) = pblock->pb_mr_filter_reusable;
+ break;
+ case SLAPI_PLUGIN_MR_QUERY_OPERATOR:
+ (*(int *) value) = pblock->pb_mr_query_operator;
+ break;
+ case SLAPI_PLUGIN_MR_USAGE:
+ (*(unsigned int *) value) = pblock->pb_mr_usage;
+ break;
+
+ /* seq arguments */
+ case SLAPI_SEQ_TYPE:
+ (*(int *)value) = pblock->pb_seq_type;
+ break;
+ case SLAPI_SEQ_ATTRNAME:
+ (*(char **)value) = pblock->pb_seq_attrname;
+ break;
+ case SLAPI_SEQ_VAL:
+ (*(char **)value) = pblock->pb_seq_val;
+ break;
+
+ /* ldif2db arguments */
+ case SLAPI_LDIF2DB_FILE:
+ (*(char ***)value) = pblock->pb_ldif_files;
+ break;
+ case SLAPI_LDIF2DB_REMOVEDUPVALS:
+ (*(int *)value) = pblock->pb_removedupvals;
+ break;
+ case SLAPI_DB2INDEX_ATTRS:
+ (*(char ***)value) = pblock->pb_db2index_attrs;
+ break;
+ case SLAPI_LDIF2DB_NOATTRINDEXES:
+ (*(int *)value) = pblock->pb_ldif2db_noattrindexes;
+ break;
+ case SLAPI_LDIF2DB_INCLUDE:
+ (*(char ***)value) = pblock->pb_ldif_include;
+ break;
+ case SLAPI_LDIF2DB_EXCLUDE:
+ (*(char ***)value) = pblock->pb_ldif_exclude;
+ break;
+ case SLAPI_LDIF2DB_GENERATE_UNIQUEID:
+ (*(int *)value) = pblock->pb_ldif_generate_uniqueid;
+ break;
+ case SLAPI_LDIF2DB_ENCRYPT:
+ case SLAPI_DB2LDIF_DECRYPT:
+ (*(int *)value) = pblock->pb_ldif_encrypt;
+ break;
+ case SLAPI_LDIF2DB_NAMESPACEID:
+ (*(char **)value) = pblock->pb_ldif_namespaceid;
+ break;
+
+ /* db2ldif arguments */
+ case SLAPI_DB2LDIF_PRINTKEY:
+ (*(int *)value) = pblock->pb_ldif_printkey;
+ break;
+ case SLAPI_DB2LDIF_DUMP_UNIQUEID:
+ (*(int *)value) = pblock->pb_ldif_dump_uniqueid;
+ break;
+ case SLAPI_DB2LDIF_FILE:
+ (*(char **)value) = pblock->pb_ldif_file;
+ break;
+
+ /* db2ldif/ldif2db/db2bak/bak2db arguments */
+ case SLAPI_BACKEND_INSTANCE_NAME:
+ (*(char **)value) = pblock->pb_instance_name;
+ break;
+ case SLAPI_BACKEND_TASK:
+ (*(Slapi_Task **)value) = pblock->pb_task;
+ break;
+ case SLAPI_TASK_FLAGS:
+ (*(int *)value) = pblock->pb_task_flags;
+ break;
+ case SLAPI_DB2LDIF_SERVER_RUNNING:
+ (*(int *)value) = pblock->pb_server_running;
+ break;
+ case SLAPI_BULK_IMPORT_ENTRY:
+ (*(Slapi_Entry **)value) = pblock->pb_import_entry;
+ break;
+ case SLAPI_BULK_IMPORT_STATE:
+ (*(int *)value) = pblock->pb_import_state;
+ break;
+
+ /* transaction arguments */
+ case SLAPI_PARENT_TXN:
+ (*(void **)value) = pblock->pb_parent_txn;
+ break;
+ case SLAPI_TXN:
+ (*(void **)value) = pblock->pb_txn;
+ break;
+
+ /* Search results set */
+ case SLAPI_SEARCH_RESULT_SET:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(void **)value) = pblock->pb_op->o_results.r.r_search.search_result_set;
+ }
+ break;
+ /* Entry returned from iterating over results set */
+ case SLAPI_SEARCH_RESULT_ENTRY:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(void **)value) = pblock->pb_op->o_results.r.r_search.search_result_entry;
+ }
+ break;
+ case SLAPI_SEARCH_RESULT_ENTRY_EXT:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(void **)value) = pblock->pb_op->o_results.r.r_search.opaque_backend_ptr;
+ }
+ break;
+ /* Number of entries returned from search */
+ case SLAPI_NENTRIES:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(int *)value) = pblock->pb_op->o_results.r.r_search.nentries;
+ }
+ break;
+ /* Referrals encountered while iterating over result set */
+ case SLAPI_SEARCH_REFERRALS:
+ if(pblock->pb_op!=NULL)
+ {
+ (*(struct berval ***)value) = pblock->pb_op->o_results.r.r_search.search_referrals;
+ }
+ break;
+
+ case SLAPI_RESULT_CODE:
+ if (pblock->pb_op != NULL)
+ * ((int *) value) = pblock->pb_op->o_results.result_code;
+ break;
+ case SLAPI_RESULT_MATCHED:
+ if (pblock->pb_op != NULL)
+ * ((char **) value) = pblock->pb_op->o_results.result_matched;
+ break;
+ case SLAPI_RESULT_TEXT:
+ if (pblock->pb_op != NULL)
+ * ((char **) value) = pblock->pb_op->o_results.result_text;
+ break;
+ case SLAPI_PB_RESULT_TEXT:
+ * ((char **) value) = pblock->pb_result_text;
+ break;
+
+ /* Size of the database, in kb */
+ case SLAPI_DBSIZE:
+ (*(unsigned int *)value) = pblock->pb_dbsize;
+ break;
+
+ /* ACL Plugin */
+ case SLAPI_PLUGIN_ACL_INIT:
+ (*(IFP *)value) = pblock->pb_plugin->plg_acl_init;
+ break;
+ case SLAPI_PLUGIN_ACL_SYNTAX_CHECK:
+ (*(IFP *)value) = pblock->pb_plugin->plg_acl_syntax_check;
+ break;
+ case SLAPI_PLUGIN_ACL_ALLOW_ACCESS:
+ (*(IFP *)value) = pblock->pb_plugin->plg_acl_access_allowed;
+ break;
+ case SLAPI_PLUGIN_ACL_MODS_ALLOWED:
+ (*(IFP *)value) = pblock->pb_plugin->plg_acl_mods_allowed;
+ break;
+ case SLAPI_PLUGIN_ACL_MODS_UPDATE:
+ (*(IFP *)value) = pblock->pb_plugin->plg_acl_mods_update;
+ break;
+
+ case SLAPI_REQUESTOR_DN:
+ /* NOTE: It's not a copy of the DN */
+ {
+ char *dn= (char*)slapi_sdn_get_dn(&pblock->pb_op->o_sdn);
+ if(dn==NULL)
+ (*( char **)value ) = "";
+ else
+ (*( char **)value ) = dn;
+ }
+ break;
+
+ case SLAPI_OPERATION_AUTHTYPE:
+ if(pblock->pb_op->o_authtype==NULL)
+ (*( char **)value ) = "";
+ else
+ (*( char **)value ) = pblock->pb_op->o_authtype;
+ break;
+
+ case SLAPI_CLIENT_DNS:
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CLIENT_DNS \n", 0, 0, 0 );
+ return (-1);
+ }
+ (*(struct berval ***)value ) = pblock->pb_conn->c_domain;
+ break;
+
+ case SLAPI_BE_MAXNESTLEVEL:
+ if ( NULL == be ) {
+ return( -1 );
+ }
+ (*(int *)value ) = be->be_maxnestlevel;
+ break;
+ case SLAPI_OPERATION_ID:
+ (*(int *)value ) = pblock->pb_op->o_opid;
+ break;
+ /* Command line arguments */
+ case SLAPI_ARGC:
+ (*(int *)value) = pblock->pb_slapd_argc;
+ break;
+ case SLAPI_ARGV:
+ (*(char ***)value) = pblock->pb_slapd_argv;
+ break;
+
+ /* Config file directory */
+ case SLAPI_CONFIG_DIRECTORY:
+ (*(char **)value) = pblock->pb_slapd_configdir;
+ break;
+
+ /* password storage scheme (kexcoff */
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME:
+ (*(char **)value) = pblock->pb_plugin->plg_pwdstorageschemename;
+ break;
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_USER_PWD:
+ (*(char **)value) = pblock->pb_pwd_storage_scheme_user_passwd;
+ break;
+
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_DB_PWD:
+ (*(char **)value) = pblock->pb_pwd_storage_scheme_db_passwd;
+ break;
+
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN:
+ (*(CFP *)value) = pblock->pb_plugin->plg_pwdstorageschemeenc;
+ break;
+
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_DEC_FN:
+ (*(IFP *)value) = pblock->pb_plugin->plg_pwdstorageschemedec;
+ break;
+
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN:
+ (*(IFP *)value) = pblock->pb_plugin->plg_pwdstorageschemecmp;
+ break;
+
+ /* entry fetch/store plugin */
+ case SLAPI_PLUGIN_ENTRY_FETCH_FUNC:
+ (*(IFP *)value) = pblock->pb_plugin->plg_entryfetchfunc;
+ break;
+
+ case SLAPI_PLUGIN_ENTRY_STORE_FUNC:
+ (*(IFP *)value) = pblock->pb_plugin->plg_entrystorefunc;
+ break;
+
+ /* DSE add parameters */
+ case SLAPI_DSE_DONT_WRITE_WHEN_ADDING:
+ (*(int *)value) = pblock->pb_dse_dont_add_write;
+ break;
+
+ /* DSE add parameters */
+ case SLAPI_DSE_MERGE_WHEN_ADDING:
+ (*(int *)value) = pblock->pb_dse_add_merge;
+ break;
+
+ /* DSE add parameters */
+ case SLAPI_DSE_DONT_CHECK_DUPS:
+ (*(int *)value) = pblock->pb_dse_dont_check_dups;
+ break;
+
+ /* DSE modify parameters */
+ case SLAPI_DSE_REAPPLY_MODS:
+ (*(int *)value) = pblock->pb_dse_reapply_mods;
+ break;
+
+ /* DSE read parameters */
+ case SLAPI_DSE_IS_PRIMARY_FILE:
+ (*(int *)value) = pblock->pb_dse_is_primary_file;
+ break;
+
+ /* used internally by schema code */
+ case SLAPI_SCHEMA_USER_DEFINED_ONLY:
+ (*(int *)value) = pblock->pb_schema_user_defined_only;
+ break;
+
+ case SLAPI_URP_NAMING_COLLISION_DN:
+ (*(char **)value) = pblock->pb_urp_naming_collision_dn;
+ break;
+
+ case SLAPI_URP_TOMBSTONE_UNIQUEID:
+ (*(char **)value) = pblock->pb_urp_tombstone_uniqueid;
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Unknown parameter block argument %d\n", arg, 0, 0 );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+int
+slapi_pblock_set( Slapi_PBlock *pblock, int arg, void *value )
+{
+ char *authtype;
+
+ PR_ASSERT( NULL != pblock );
+
+ switch ( arg ) {
+ case SLAPI_BACKEND:
+ pblock->pb_backend = (Slapi_Backend *) value;
+ break;
+ case SLAPI_BACKEND_COUNT:
+ pblock->pb_backend_count = *((int *) value);
+ break;
+ case SLAPI_CONNECTION:
+ pblock->pb_conn = (Connection *) value;
+ break;
+ case SLAPI_OPERATION:
+ pblock->pb_op = (Operation *) value;
+ break;
+ case SLAPI_OPINITIATED_TIME:
+ pblock->pb_op->o_time = *((time_t *) value);
+ break;
+ case SLAPI_REQUESTOR_ISROOT:
+ pblock->pb_requestor_isroot = *((int *) value);
+ break;
+ case SLAPI_IS_REPLICATED_OPERATION:
+ PR_ASSERT(0);
+ break;
+ case SLAPI_OPERATION_PARAMETERS:
+ PR_ASSERT(0);
+ break;
+ case SLAPI_CONN_ID:
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_ID \n", 0, 0, 0 );
+ return (-1);
+ }
+ pblock->pb_conn->c_connid = *((int *) value);
+ break;
+ case SLAPI_CONN_DN:
+ /*
+ * Slightly crazy but we must pass a copy of the current
+ * authtype into bind_credentials_set() since it will
+ * free the current authtype.
+ */
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_DN \n", 0, 0, 0 );
+ return (-1);
+ }
+ slapi_pblock_get(pblock, SLAPI_CONN_AUTHMETHOD, &authtype);
+ bind_credentials_set( pblock->pb_conn, authtype,
+ (char *)value, NULL, NULL, NULL , NULL);
+ slapi_ch_free((void**)&authtype);
+ break;
+ case SLAPI_CONN_AUTHTYPE: /* deprecated */
+ case SLAPI_CONN_AUTHMETHOD:
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_AUTHMETHOD \n", 0, 0, 0 );
+ return (-1);
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ slapi_ch_free((void**)&pblock->pb_conn->c_authtype);
+ pblock->pb_conn->c_authtype = slapi_ch_strdup((char *) value);
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+ case SLAPI_CONN_IS_REPLICATION_SESSION:
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CONN_IS_REPLICATION_SESSION \n", 0, 0, 0 );
+ return (-1);
+ }
+ PR_Lock( pblock->pb_conn->c_mutex );
+ pblock->pb_conn->c_isreplication_session = *((int *) value);
+ PR_Unlock( pblock->pb_conn->c_mutex );
+ break;
+
+ /* stuff related to config file processing */
+ case SLAPI_CONFIG_FILENAME:
+ case SLAPI_CONFIG_LINENO:
+ case SLAPI_CONFIG_ARGC:
+ case SLAPI_CONFIG_ARGV:
+ return (-1); /* deprecated since DS 5.0 (no longer useful) */
+
+ /* pblock memory management */
+ case SLAPI_DESTROY_CONTENT:
+ pblock->pb_destroy_content = *((int *) value);
+ break;
+
+ /* stuff related to the current plugin */
+ case SLAPI_PLUGIN:
+ pblock->pb_plugin = (struct slapdplugin *) value;
+ break;
+ case SLAPI_PLUGIN_PRIVATE:
+ pblock->pb_plugin->plg_private = (void *) value;
+ break;
+ case SLAPI_PLUGIN_TYPE:
+ pblock->pb_plugin->plg_type = *((int *) value);
+ break;
+ case SLAPI_PLUGIN_ARGV:
+ pblock->pb_plugin->plg_argv = (char **) value;
+ break;
+ case SLAPI_PLUGIN_ARGC:
+ pblock->pb_plugin->plg_argc = *((int *) value);
+ break;
+ case SLAPI_PLUGIN_VERSION:
+ pblock->pb_plugin->plg_version = (char *) value;
+ break;
+ case SLAPI_PLUGIN_OPRETURN:
+ pblock->pb_opreturn = *((int *) value);
+ break;
+ case SLAPI_PLUGIN_OBJECT:
+ pblock->pb_object = (void *) value;
+ break;
+ case SLAPI_PLUGIN_IDENTITY:
+ pblock->pb_plugin_identity = (void*)value;
+ break;
+ case SLAPI_PLUGIN_DESTROY_FN:
+ pblock->pb_destroy_fn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DESCRIPTION:
+ pblock->pb_plugin->plg_desc = *((Slapi_PluginDesc *)value);
+ break;
+ case SLAPI_PLUGIN_INTOP_RESULT:
+ pblock->pb_internal_op_result = *((int *) value);
+ break;
+ case SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES:
+ pblock->pb_plugin_internal_search_op_entries = (Slapi_Entry **) value;
+ break;
+ case SLAPI_PLUGIN_INTOP_SEARCH_REFERRALS:
+ pblock->pb_plugin_internal_search_op_referrals = (char **) value;
+ break;
+ /* database plugin functions */
+ case SLAPI_PLUGIN_DB_BIND_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_bind = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_UNBIND_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_unbind = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_SEARCH_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_search = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_next_search_entry = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_next_search_entry_ext = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_ENTRY_RELEASE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_entry_release = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_COMPARE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_compare = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_MODIFY_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_modify = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_MODRDN_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_modrdn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_ADD_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_add = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_DELETE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_delete = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_ABANDON_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_abandon = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_CONFIG_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_config = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_CLOSE_FN:
+ pblock->pb_plugin->plg_close = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_CLEANUP_FN:
+ pblock->pb_plugin->plg_cleanup = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_FLUSH_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_flush = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_START_FN:
+ pblock->pb_plugin->plg_start = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POSTSTART_FN:
+ pblock->pb_plugin->plg_poststart = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_WIRE_IMPORT_FN:
+ pblock->pb_plugin->plg_wire_import = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_SEQ_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_seq = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_ENTRY_FN:
+ pblock->pb_plugin->plg_entry = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_REFERRAL_FN:
+ pblock->pb_plugin->plg_referral = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_RESULT_FN:
+ pblock->pb_plugin->plg_result = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_RMDB_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_rmdb = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_INIT_INSTANCE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_init_instance = (IFP) value;
+ break;
+
+ case SLAPI_PLUGIN_DB_LDIF2DB_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_ldif2db = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_DB2LDIF_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_db2ldif = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_DB2INDEX_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_db2index = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_ARCHIVE2DB_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_archive2db = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_DB2ARCHIVE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_db2archive = (IFP) value;
+ break;
+#if defined(UPGRADEDB)
+ case SLAPI_PLUGIN_DB_UPGRADEDB_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_upgradedb = (IFP) value;
+ break;
+#endif
+ case SLAPI_PLUGIN_DB_BEGIN_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_begin = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_COMMIT_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_commit = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_ABORT_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_abort = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_SIZE_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_dbsize = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_DB_TEST_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_un.plg_un_db.plg_un_db_dbtest = (IFP) value;
+ break;
+ /* database plugin-specific parameters */
+ case SLAPI_PLUGIN_DB_NO_ACL:
+ if ( pblock->pb_plugin && pblock->pb_plugin->plg_type != SLAPI_PLUGIN_DATABASE ) {
+ return( -1 );
+ }
+ if ( NULL == pblock->pb_backend ) {
+ return( -1 );
+ }
+ pblock->pb_backend->be_noacl = *((int *)value);
+ break;
+
+
+ /* extendedop plugin functions */
+ case SLAPI_PLUGIN_EXT_OP_FN:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_EXTENDEDOP ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_exhandler = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_EXT_OP_OIDLIST:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_EXTENDEDOP ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_exoids = (char **) value;
+ ldapi_register_extended_op( (char **)value );
+ break;
+ case SLAPI_PLUGIN_EXT_OP_NAMELIST:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_EXTENDEDOP ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_exnames = (char **) value;
+ break;
+
+ /* preoperation plugin functions */
+ case SLAPI_PLUGIN_PRE_BIND_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_prebind = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_UNBIND_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_preunbind = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_SEARCH_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_presearch = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_COMPARE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_precompare = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_premodify = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_premodrdn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_preadd = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_predelete = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_ABANDON_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_preabandon = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_ENTRY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_preentry = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_REFERRAL_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_prereferral = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_PRE_RESULT_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_preresult = (IFP) value;
+ break;
+
+ /* postoperation plugin functions */
+ case SLAPI_PLUGIN_POST_BIND_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postbind = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_UNBIND_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postunbind = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_SEARCH_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postsearch = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_SEARCH_FAIL_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postsearchfail = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_COMPARE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postcompare = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postmodify = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postmodrdn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postadd = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postdelete = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_ABANDON_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postabandon = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_ENTRY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postentry = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_REFERRAL_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postreferral = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_POST_RESULT_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_postresult = (IFP) value;
+ break;
+
+ /* backend preoperation plugin */
+ case SLAPI_PLUGIN_BE_PRE_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_bepremodify = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_BE_PRE_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_bepremodrdn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_BE_PRE_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_bepreadd = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_BE_PRE_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_bepredelete = (IFP) value;
+ break;
+
+ /* backend postoperation plugin */
+ case SLAPI_PLUGIN_BE_POST_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPOSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_bepostmodify = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_BE_POST_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPOSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_bepostmodrdn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_BE_POST_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPOSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_bepostadd = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_BE_POST_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_BEPOSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_bepostdelete = (IFP) value;
+ break;
+
+
+ /* internal preoperation plugin */
+ case SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_internal_pre_modify = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_internal_pre_modrdn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_internal_pre_add = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_PREOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_internal_pre_delete = (IFP) value;
+ break;
+
+ /* internal postoperation plugin */
+ case SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_internal_post_modify = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_internal_post_modrdn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_POST_ADD_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_internal_post_add = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN:
+ if (pblock->pb_plugin->plg_type != SLAPI_PLUGIN_INTERNAL_POSTOPERATION) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_internal_post_delete = (IFP) value;
+ break;
+
+ /* syntax plugin functions */
+ case SLAPI_PLUGIN_SYNTAX_FILTER_AVA:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_syntax_filter_ava = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_FILTER_SUB:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_syntax_filter_sub = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_VALUES2KEYS:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_syntax_values2keys = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_syntax_assertion2keys_ava = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_syntax_assertion2keys_sub = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_NAMES:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_syntax_names = (char **) value;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_OID:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_syntax_oid = (char *) value;
+ break;
+ case SLAPI_PLUGIN_SYNTAX_FLAGS:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_syntax_flags = *((int *) value);
+ break;
+ case SLAPI_PLUGIN_SYNTAX_COMPARE:
+ if ( pblock->pb_plugin->plg_type != SLAPI_PLUGIN_SYNTAX ) {
+ return( -1 );
+ }
+ pblock->pb_plugin->plg_syntax_compare = (IFP) value;
+ break;
+ case SLAPI_ENTRY_PRE_OP:
+ pblock->pb_pre_op_entry = (Slapi_Entry *) value;
+ break;
+ case SLAPI_ENTRY_POST_OP:
+ pblock->pb_post_op_entry = (Slapi_Entry *) value;
+ break;
+
+ /* target address for all operations */
+ case SLAPI_TARGET_ADDRESS:
+ PR_ASSERT (PR_FALSE); /* can't do this */
+ break;
+ case SLAPI_TARGET_DN:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.target_address.dn = (char *)value;
+ }
+ break;
+ case SLAPI_ORIGINAL_TARGET_DN:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.target_address.udn = (char *)value;
+ }
+ break;
+ case SLAPI_TARGET_UNIQUEID:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.target_address.uniqueid = (char *) value;
+ }
+ break;
+ case SLAPI_REQCONTROLS:
+ pblock->pb_op->o_params.request_controls = (LDAPControl **) value;
+ break;
+ case SLAPI_RESCONTROLS:
+ pblock->pb_op->o_results.result_controls = (LDAPControl **) value;
+ break;
+ case SLAPI_CONTROLS_ARG: /* used to pass control argument before operation is created */
+ pblock->pb_ctrls_arg = (LDAPControl **) value;
+ break;
+ case SLAPI_ADD_RESCONTROL:
+ add_control( &pblock->pb_op->o_results.result_controls, (LDAPControl *)value );
+ break;
+
+ /* notes to be added to the access log RESULT line for this op. */
+ case SLAPI_OPERATION_NOTES:
+ if ( value == NULL ) {
+ pblock->pb_operation_notes = 0; /* cleared */
+ } else {
+ pblock->pb_operation_notes |= *((unsigned int *)value );
+ }
+ break;
+
+ /* controls we know about */
+ case SLAPI_MANAGEDSAIT:
+ pblock->pb_managedsait = *((int *) value);
+ break;
+ case SLAPI_PWPOLICY:
+ pblock->pb_pwpolicy_ctrl = *((int *) value);
+ break;
+
+ /* add arguments */
+ case SLAPI_ADD_ENTRY:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_add.target_entry = (Slapi_Entry *) value;
+ }
+ break;
+ case SLAPI_ADD_EXISTING_DN_ENTRY:
+ pblock->pb_existing_dn_entry = (Slapi_Entry *) value;
+ break;
+ case SLAPI_ADD_EXISTING_UNIQUEID_ENTRY:
+ pblock->pb_existing_uniqueid_entry = (Slapi_Entry *) value;
+ break;
+ case SLAPI_ADD_PARENT_ENTRY:
+ pblock->pb_parent_entry = (Slapi_Entry *) value;
+ break;
+ case SLAPI_ADD_PARENT_UNIQUEID:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_add.parentuniqueid = (char *) value;
+ }
+ break;
+
+ /* bind arguments */
+ case SLAPI_BIND_METHOD:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_bind.bind_method = *((int *) value);
+ }
+ break;
+ case SLAPI_BIND_CREDENTIALS:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_bind.bind_creds = (struct berval *) value;
+ }
+ break;
+ case SLAPI_BIND_SASLMECHANISM:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_bind.bind_saslmechanism = (char *) value;
+ }
+ break;
+ /* bind return values */
+ case SLAPI_BIND_RET_SASLCREDS:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_results.r.r_bind.bind_ret_saslcreds = (struct berval *) value;
+ }
+ break;
+
+ /* compare arguments */
+ case SLAPI_COMPARE_TYPE:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_compare.compare_ava.ava_type = (char *) value;
+ }
+ break;
+ case SLAPI_COMPARE_VALUE:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_compare.compare_ava.ava_value = *((struct berval *) value);
+ }
+ break;
+
+ /* modify arguments */
+ case SLAPI_MODIFY_MODS:
+ PR_ASSERT(pblock->pb_op);
+ if(pblock->pb_op!=NULL)
+ {
+ if(pblock->pb_op->o_params.operation_type==SLAPI_OPERATION_MODIFY)
+ {
+ pblock->pb_op->o_params.p.p_modify.modify_mods = (LDAPMod **) value;
+ }
+ else if(pblock->pb_op->o_params.operation_type==SLAPI_OPERATION_MODRDN)
+ {
+ pblock->pb_op->o_params.p.p_modrdn.modrdn_mods = (LDAPMod **) value;
+ }
+ else
+ {
+ PR_ASSERT(0);
+ }
+ }
+ break;
+
+ /* modrdn arguments */
+ case SLAPI_MODRDN_NEWRDN:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_modrdn.modrdn_newrdn = (char *) value;
+ }
+ break;
+ case SLAPI_MODRDN_DELOLDRDN:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_modrdn.modrdn_deloldrdn = *((int *) value);
+ }
+ break;
+ case SLAPI_MODRDN_NEWSUPERIOR:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_modrdn.modrdn_newsuperior_address.dn = (char *) value;
+ }
+ break;
+ case SLAPI_MODRDN_PARENT_ENTRY:
+ pblock->pb_parent_entry = (Slapi_Entry *) value;
+ break;
+ case SLAPI_MODRDN_NEWPARENT_ENTRY:
+ pblock->pb_newparent_entry = (Slapi_Entry *) value;
+ break;
+ case SLAPI_MODRDN_TARGET_ENTRY:
+ pblock->pb_target_entry = (Slapi_Entry *) value;
+ break;
+ case SLAPI_MODRDN_NEWSUPERIOR_ADDRESS:
+ PR_ASSERT (PR_FALSE); /* can't do this */
+
+ /* search arguments */
+ case SLAPI_SEARCH_SCOPE:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_search.search_scope = *((int *) value);
+ }
+ break;
+ case SLAPI_SEARCH_DEREF:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_search.search_deref = *((int *) value);
+ }
+ break;
+ case SLAPI_SEARCH_SIZELIMIT:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_search.search_sizelimit = *((int *) value);
+ }
+ break;
+ case SLAPI_SEARCH_TIMELIMIT:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_search.search_timelimit = *((int *) value);
+ }
+ break;
+ case SLAPI_SEARCH_FILTER:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_search.search_filter = (struct slapi_filter *) value;
+ }
+ break;
+ case SLAPI_SEARCH_STRFILTER:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_search.search_strfilter = (char *) value;
+ }
+ break;
+ case SLAPI_SEARCH_ATTRS:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_search.search_attrs = (char **) value;
+ }
+ break;
+ case SLAPI_SEARCH_ATTRSONLY:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_search.search_attrsonly = *((int *) value);
+ }
+ break;
+ case SLAPI_SEARCH_IS_AND:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_search.search_is_and = *((int *) value);
+ }
+ break;
+
+ /* abandon operation arguments */
+ case SLAPI_ABANDON_MSGID:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_abandon.abandon_targetmsgid = *((int *) value);
+ }
+ break;
+
+ /* extended operation arguments */
+ case SLAPI_EXT_OP_REQ_OID:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_extended.exop_oid = (char *) value;
+ }
+ break;
+ case SLAPI_EXT_OP_REQ_VALUE:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_params.p.p_extended.exop_value = (struct berval *) value;
+ }
+ break;
+ /* extended operation return values */
+ case SLAPI_EXT_OP_RET_OID:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_results.r.r_extended.exop_ret_oid = (char *) value;
+ }
+ break;
+ case SLAPI_EXT_OP_RET_VALUE:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_results.r.r_extended.exop_ret_value = (struct berval *) value;
+ }
+ break;
+
+ /* matching rule plugin functions */
+ case SLAPI_PLUGIN_MR_FILTER_CREATE_FN:
+ SLAPI_PLUGIN_TYPE_CHECK (pblock, SLAPI_PLUGIN_MATCHINGRULE);
+ pblock->pb_plugin->plg_mr_filter_create = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_MR_INDEXER_CREATE_FN:
+ SLAPI_PLUGIN_TYPE_CHECK (pblock, SLAPI_PLUGIN_MATCHINGRULE);
+ pblock->pb_plugin->plg_mr_indexer_create = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_MR_FILTER_MATCH_FN:
+ pblock->pb_mr_filter_match_fn = (mrFilterMatchFn) value;
+ break;
+ case SLAPI_PLUGIN_MR_FILTER_INDEX_FN:
+ pblock->pb_mr_filter_index_fn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_MR_FILTER_RESET_FN:
+ pblock->pb_mr_filter_reset_fn = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_MR_INDEX_FN:
+ pblock->pb_mr_index_fn = (IFP) value;
+ break;
+
+ /* matching rule plugin arguments */
+ case SLAPI_PLUGIN_MR_OID:
+ pblock->pb_mr_oid = (char *) value;
+ break;
+ case SLAPI_PLUGIN_MR_TYPE:
+ pblock->pb_mr_type = (char *) value;
+ break;
+ case SLAPI_PLUGIN_MR_VALUE:
+ pblock->pb_mr_value = (struct berval *) value;
+ break;
+ case SLAPI_PLUGIN_MR_VALUES:
+ pblock->pb_mr_values = (struct berval **) value;
+ break;
+ case SLAPI_PLUGIN_MR_KEYS:
+ pblock->pb_mr_keys = (struct berval **) value;
+ break;
+ case SLAPI_PLUGIN_MR_FILTER_REUSABLE:
+ pblock->pb_mr_filter_reusable = *(unsigned int *) value;
+ break;
+ case SLAPI_PLUGIN_MR_QUERY_OPERATOR:
+ pblock->pb_mr_query_operator = *(int *) value;
+ break;
+ case SLAPI_PLUGIN_MR_USAGE:
+ pblock->pb_mr_usage = *(unsigned int *) value;
+ break;
+
+ /* seq arguments */
+ case SLAPI_SEQ_TYPE:
+ pblock->pb_seq_type = *((int *)value);
+ break;
+ case SLAPI_SEQ_ATTRNAME:
+ pblock->pb_seq_attrname = (char *) value;
+ break;
+ case SLAPI_SEQ_VAL:
+ pblock->pb_seq_val = (char *) value;
+ break;
+
+ /* ldif2db arguments */
+ case SLAPI_LDIF2DB_FILE:
+ pblock->pb_ldif_file = (char *) value;
+ break;
+ case SLAPI_LDIF2DB_REMOVEDUPVALS:
+ pblock->pb_removedupvals = *((int *)value);
+ break;
+ case SLAPI_DB2INDEX_ATTRS:
+ pblock->pb_db2index_attrs = (char **) value;
+ break;
+ case SLAPI_LDIF2DB_NOATTRINDEXES:
+ pblock->pb_ldif2db_noattrindexes = *((int *)value);
+ break;
+ case SLAPI_LDIF2DB_GENERATE_UNIQUEID:
+ pblock->pb_ldif_generate_uniqueid = *((int *)value);
+ break;
+ case SLAPI_LDIF2DB_NAMESPACEID:
+ pblock->pb_ldif_namespaceid = (char *)value;
+ break;
+
+ /* db2ldif arguments */
+ case SLAPI_DB2LDIF_PRINTKEY:
+ pblock->pb_ldif_printkey = *((int *)value);
+ break;
+ case SLAPI_DB2LDIF_DUMP_UNIQUEID:
+ pblock->pb_ldif_dump_uniqueid = *((int *)value);
+ break;
+
+ /* db2ldif/ldif2db/db2bak/bak2db arguments */
+ case SLAPI_BACKEND_INSTANCE_NAME:
+ pblock->pb_instance_name = (char *) value;
+ break;
+ case SLAPI_BACKEND_TASK:
+ pblock->pb_task = (Slapi_Task *)value;
+ break;
+ case SLAPI_TASK_FLAGS:
+ pblock->pb_task_flags = *((int *)value);
+ break;
+ case SLAPI_DB2LDIF_SERVER_RUNNING:
+ pblock->pb_server_running = *((int *)value);
+ break;
+ case SLAPI_BULK_IMPORT_ENTRY:
+ pblock->pb_import_entry = (Slapi_Entry *)value;
+ break;
+ case SLAPI_BULK_IMPORT_STATE:
+ pblock->pb_import_state = *((int *)value);
+ break;
+
+ /* transaction arguments */
+ case SLAPI_PARENT_TXN:
+ pblock->pb_parent_txn = (void *)value;
+ break;
+ case SLAPI_TXN:
+ pblock->pb_txn = (void *)value;
+ break;
+
+ /* Search results set */
+ case SLAPI_SEARCH_RESULT_SET:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_results.r.r_search.search_result_set = (void *)value;
+ }
+ break;
+ /* Search result - entry returned from iterating over result set */
+ case SLAPI_SEARCH_RESULT_ENTRY:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_results.r.r_search.search_result_entry = (void *)value;
+ }
+ break;
+ case SLAPI_SEARCH_RESULT_ENTRY_EXT:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_results.r.r_search.opaque_backend_ptr = (void *)value;
+ }
+ break;
+ /* Number of entries returned from search */
+ case SLAPI_NENTRIES:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_results.r.r_search.nentries = *((int *)value);
+ }
+ break;
+ /* Referrals encountered while iterating over the result set */
+ case SLAPI_SEARCH_REFERRALS:
+ if(pblock->pb_op!=NULL)
+ {
+ pblock->pb_op->o_results.r.r_search.search_referrals = (struct berval **)value;
+ }
+ break;
+
+ case SLAPI_RESULT_CODE:
+ if (pblock->pb_op != NULL)
+ pblock->pb_op->o_results.result_code = (* (int *) value);
+ break;
+ case SLAPI_RESULT_MATCHED:
+ if (pblock->pb_op != NULL)
+ pblock->pb_op->o_results.result_matched = (char *) value;
+ break;
+ case SLAPI_RESULT_TEXT:
+ if (pblock->pb_op != NULL)
+ pblock->pb_op->o_results.result_text = (char *) value;
+ break;
+ case SLAPI_PB_RESULT_TEXT:
+ slapi_ch_free((void**)&(pblock->pb_result_text));
+ pblock->pb_result_text = slapi_ch_strdup ((char *) value);
+ break;
+
+ /* Size of the database, in kb */
+ case SLAPI_DBSIZE:
+ pblock->pb_dbsize = *((unsigned int *)value);
+ break;
+
+ /* ACL Plugin */
+ case SLAPI_PLUGIN_ACL_INIT:
+ pblock->pb_plugin->plg_acl_init = (IFP) value;
+ break;
+
+ case SLAPI_PLUGIN_ACL_SYNTAX_CHECK:
+ pblock->pb_plugin->plg_acl_syntax_check = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_ACL_ALLOW_ACCESS:
+ pblock->pb_plugin->plg_acl_access_allowed = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_ACL_MODS_ALLOWED:
+ pblock->pb_plugin->plg_acl_mods_allowed = (IFP) value;
+ break;
+ case SLAPI_PLUGIN_ACL_MODS_UPDATE:
+ pblock->pb_plugin->plg_acl_mods_update = (IFP) value;
+ break;
+ case SLAPI_CLIENT_DNS:
+ if (pblock->pb_conn == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Connection is NULL and hence cannot access SLAPI_CLIENT_DNS \n", 0, 0, 0 );
+ return (-1);
+ }
+ pblock->pb_conn->c_domain = *((struct berval ***) value );
+ break;
+ /* Command line arguments */
+ case SLAPI_ARGC:
+ pblock->pb_slapd_argc= *((int *)value);
+ break;
+ case SLAPI_ARGV:
+ pblock->pb_slapd_argv = *((char***)value);
+ break;
+
+ /* Config file directory */
+ case SLAPI_CONFIG_DIRECTORY:
+ pblock->pb_slapd_configdir = (char *)value;
+ break;
+
+ /* password storage scheme (kexcoff) */
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME:
+ pblock->pb_plugin->plg_pwdstorageschemename = (char *)value;
+ break;
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_USER_PWD:
+ pblock->pb_pwd_storage_scheme_user_passwd = (char *)value;
+ break;
+
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_DB_PWD:
+ pblock->pb_pwd_storage_scheme_db_passwd = (char *)value;
+ break;
+
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN:
+ pblock->pb_plugin->plg_pwdstorageschemeenc = (CFP)value;
+ break;
+
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_DEC_FN:
+ pblock->pb_plugin->plg_pwdstorageschemedec = (IFP)value;
+ break;
+
+ case SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN:
+ /* must provide a comparison function */
+ if ( value == NULL )
+ {
+ return(-1);
+ }
+ pblock->pb_plugin->plg_pwdstorageschemecmp = (IFP)value;
+ break;
+
+ /* entry fetch store */
+ case SLAPI_PLUGIN_ENTRY_FETCH_FUNC:
+ pblock->pb_plugin->plg_entryfetchfunc = (IFP) value;
+ break;
+
+ case SLAPI_PLUGIN_ENTRY_STORE_FUNC:
+ pblock->pb_plugin->plg_entrystorefunc = (IFP) value;
+ break;
+
+ /* DSE add parameters */
+ case SLAPI_DSE_DONT_WRITE_WHEN_ADDING:
+ pblock->pb_dse_dont_add_write = *((int *)value);
+ break;
+
+ /* DSE add parameters */
+ case SLAPI_DSE_MERGE_WHEN_ADDING:
+ pblock->pb_dse_add_merge = *((int *)value);
+ break;
+
+ /* DSE add parameters */
+ case SLAPI_DSE_DONT_CHECK_DUPS:
+ pblock->pb_dse_dont_check_dups = *((int *)value);
+ break;
+
+ /* DSE modify parameters */
+ case SLAPI_DSE_REAPPLY_MODS:
+ pblock->pb_dse_reapply_mods = *((int *)value);
+ break;
+
+ /* DSE read parameters */
+ case SLAPI_DSE_IS_PRIMARY_FILE:
+ pblock->pb_dse_is_primary_file = *((int *)value);
+ break;
+
+ /* used internally by schema code only */
+ case SLAPI_SCHEMA_USER_DEFINED_ONLY:
+ pblock->pb_schema_user_defined_only = *((int *)value);
+ break;
+
+ case SLAPI_URP_NAMING_COLLISION_DN:
+ pblock->pb_urp_naming_collision_dn = (char *)value;
+ break;
+
+ case SLAPI_URP_TOMBSTONE_UNIQUEID:
+ pblock->pb_urp_tombstone_uniqueid = (char *)value;
+ break;
+
+ case SLAPI_LDIF2DB_ENCRYPT:
+ case SLAPI_DB2LDIF_DECRYPT:
+ pblock->pb_ldif_encrypt = (int)value;
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Unknown parameter block argument %d\n", arg, 0, 0 );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+
+/*
+ * Clears (and free's as appropriate) the bind DN and related credentials
+ * for the connection `conn'.
+ *
+ * If `lock_conn' is true, 'conn' is locked before touching it; otherwise
+ * this function assumes that conn->c_mutex is ALREADY locked.
+ *
+ * If `clear_externalcreds' is true, the external DN, external authtype,
+ * and client certificate are also cleared and free'd.
+ *
+ * Connection structure members that are potentially changed by this function:
+ * c_dn, c_isroot, c_authtype
+ * c_external_dn, c_external_authtype, c_client_cert
+ *
+ * This function might better belong on bind.c or perhaps connection.c but
+ * it needs to be in libslapd because FE code and libslapd code calls it.
+ */
+void
+bind_credentials_clear( Connection *conn, PRBool lock_conn,
+ PRBool clear_externalcreds )
+{
+ if ( lock_conn ) {
+ PR_Lock( conn->c_mutex );
+ }
+
+ if ( conn->c_dn != NULL ) { /* a non-anonymous bind has occurred */
+ reslimit_update_from_entry( conn, NULL ); /* clear resource limits */
+
+ if ( conn->c_dn != conn->c_external_dn ) {
+ slapi_ch_free((void**)&conn->c_dn);
+ }
+ conn->c_dn = NULL;
+ }
+ slapi_ch_free((void**)&conn->c_authtype);
+ conn->c_isroot = 0;
+ conn->c_authtype = slapi_ch_strdup(SLAPD_AUTH_NONE);
+
+ if ( clear_externalcreds ) {
+ slapi_ch_free( (void**)&conn->c_external_dn );
+ conn->c_external_dn = NULL;
+ conn->c_external_authtype = SLAPD_AUTH_NONE;
+ if ( conn->c_client_cert ) {
+ CERT_DestroyCertificate (conn->c_client_cert);
+ conn->c_client_cert = NULL;
+ }
+ }
+
+ if ( lock_conn ) {
+ PR_Unlock( conn->c_mutex );
+ }
+
+}
+
+
+/*
+ * Clear and then set the bind DN and related credentials for the
+ * connection `conn'.
+ *
+ * `authtype' should be one of the SLAPD_AUTH_... constants defined in
+ * slapu-plugin.h or NULL.
+ *
+ * `normdn' must be a normalized DN and it must be malloc'd memory (it
+ * is consumed by this function). If there is an existing DN value
+ * associated with the connection, it is free'd. Pass NULL for `normdn'
+ * to clear the DN.
+ *
+ * If `extauthtype' is non-NULL we also clear and then set the
+ * external (e.g., SSL) credentials from the `externaldn' and `clientcert'.
+ * Note that it is okay for `externaldn' and 'normdn' to have the same
+ * (pointer) value. This code and that in bind_credentials_clear()
+ * is smart enough to know to only free the memory once. Like `normdn',
+ * `externaldn' and `clientcert' should be NULL or point to malloc'd memory
+ * as they are both consumed by this function.
+ *
+ * We also:
+ *
+ * 1) Test to see if the DN is the root DN and set the c_isroot flag
+ * appropriately.
+ * And
+ *
+ * 2) Call the binder-based resource limits subsystem so it can
+ * update the per-connection resource limit data it maintains.
+ *
+ * Note that this function should ALWAYS be used instead of manipulating
+ * conn->c_dn directly; otherwise, subsystems like the binder-based resource
+ * limits (see resourcelimit.c) won't be called.
+ *
+ * It is also acceptable to set the DN via a call slapi_pblock_set(), e.g.,
+ *
+ * slapi_pblock_set( pb, SLAPI_CONN_DN, ndn );
+ *
+ * because it calls this function.
+ *
+ * Connection structure members that are potentially changed by this function:
+ * c_dn, c_isroot, c_authtype
+ * c_external_dn, c_external_authtype, c_client_cert
+ *
+ * This function might better belong on bind.c or perhaps connection.c but
+ * it needs to be in libslapd because FE code and libslapd code calls it.
+ */
+void
+bind_credentials_set( Connection *conn, char *authtype, char *normdn,
+ char *extauthtype, char *externaldn, CERTCertificate *clientcert, Slapi_Entry * bind_target_entry )
+{
+ PR_Lock( conn->c_mutex );
+
+ /* clear credentials */
+ bind_credentials_clear( conn, PR_FALSE /* conn is already locked */,
+ ( extauthtype != NULL ) /* clear external creds. if requested */ );
+
+ /* set primary credentials */
+ slapi_ch_free((void**)&conn->c_authtype);
+ conn->c_authtype = slapi_ch_strdup(authtype);
+ conn->c_dn = normdn;
+ conn->c_isroot = slapi_dn_isroot( normdn );
+
+
+ /* set external credentials if requested */
+ if ( extauthtype != NULL ) {
+ conn->c_external_authtype = extauthtype;
+ conn->c_external_dn = externaldn;
+ conn->c_client_cert = clientcert;
+ }
+
+
+ /* notify binder-based resource limit subsystem about the change in DN */
+ if ( !conn->c_isroot )
+ {
+ if ( conn->c_dn != NULL ) {
+ if ( bind_target_entry == NULL )
+ {
+ Slapi_DN *sdn;
+
+ sdn = slapi_sdn_new_dn_byref( conn->c_dn ); /* set */
+ reslimit_update_from_dn( conn, sdn );
+ slapi_sdn_free( &sdn );
+ }
+ else
+ reslimit_update_from_entry( conn, bind_target_entry );
+ }
+ }
+
+ PR_Unlock( conn->c_mutex );
+}
diff --git a/ldap/servers/slapd/plugin.c b/ldap/servers/slapd/plugin.c
new file mode 100644
index 00000000..5477f3e2
--- /dev/null
+++ b/ldap/servers/slapd/plugin.c
@@ -0,0 +1,2833 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* plugin.c - routines for setting up and calling plugins */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <plhash.h>
+#include "slap.h"
+
+/* this defines are used for plugin configuration */
+#define LOCAL_DATA "local data"
+#define REMOTE_DATA "remote data"
+#define ALL_DATA "*"
+#define ROOT_BIND "directory manager"
+#define ANONYMOUS_BIND "anonymous"
+
+/* Forward Declarations */
+static int plugin_call_list (struct slapdplugin *list, int operation, Slapi_PBlock *pb);
+static int plugin_call_one (struct slapdplugin *list, int operation, Slapi_PBlock *pb);
+static int plugin_call_func (struct slapdplugin *list, int operation, Slapi_PBlock *pb, int call_one);
+
+static PRBool plugin_invoke_plugin_pb (struct slapdplugin *plugin, int operation, Slapi_PBlock *pb);
+static PRBool plugin_matches_operation (Slapi_DN *target_spec, PluginTargetData *ptd,
+ PRBool bindop, PRBool isroot, PRBool islocal, int method);
+static int isApprovedPlugin( struct slapdplugin *plugin );
+
+static void plugin_config_init (struct pluginconfig *config);
+static void plugin_config_cleanup (struct pluginconfig *config);
+static int plugin_config_set_action (int *action, char *value);
+static struct pluginconfig* plugin_get_config (struct slapdplugin *plugin);
+static void default_plugin_init();
+static void ptd_init (PluginTargetData *ptd);
+static void ptd_cleanup (PluginTargetData *ptd);
+static void ptd_add_subtree (PluginTargetData *ptd, Slapi_DN *subtree);
+static void ptd_set_special_data (PluginTargetData *ptd, int type);
+static Slapi_DN *ptd_get_first_subtree (const PluginTargetData *ptd, int *cookie);
+static Slapi_DN *ptd_get_next_subtree (const PluginTargetData *ptd, int *cookie);
+static PRBool ptd_is_special_data_set (const PluginTargetData *ptd, int type);
+int ptd_get_subtree_count (const PluginTargetData *ptd);
+static void plugin_set_global (PluginTargetData *ptd);
+static PRBool plugin_is_global (const PluginTargetData *ptd);
+static void plugin_set_default_access (struct pluginconfig *config);
+
+static PLHashTable *global_plugin_dns = NULL;
+
+/* The global plugin list is indexed by the PLUGIN_LIST_* constants defined in slap.h */
+static struct slapdplugin *global_plugin_list[PLUGIN_LIST_GLOBAL_MAX];
+
+/* plugin structure used to configure internal operation issued by the core server */
+static int global_server_plg_initialised= 0;
+struct slapdplugin global_server_plg;
+
+/* plugin structure used to configure internal operation issued by the core server */
+static int global_server_plg_id_initialised= 0;
+struct slapi_componentid global_server_id_plg;
+
+/* plugin structure used to configure operations issued by the old plugins that
+ do not pass their identity in the operation */
+static struct slapdplugin global_default_plg;
+
+/* Enable/disable plugin callbacks for clean startup */
+static int global_plugin_callbacks_enabled = 0;
+
+
+static void
+add_plugin_to_list(struct slapdplugin **list, struct slapdplugin *plugin)
+{
+ struct slapdplugin **tmp;
+ for ( tmp = list; *tmp; tmp = &(*tmp)->plg_next )
+ {
+ ; /* NULL */
+ }
+ *tmp = plugin;
+}
+
+struct slapdplugin *
+get_plugin_list(int plugin_list_index)
+{
+ return global_plugin_list[plugin_list_index];
+}
+
+/*
+ * As the plugin configuration information is read an array of
+ * entries is built which reflect the plugins. The entries
+ * are added after the syntax plugins are started so that the
+ * nodes in the attribute tree are initialised correctly.
+ */
+typedef struct entry_and_plugin {
+ Slapi_Entry *e;
+ struct slapdplugin *plugin;
+ struct entry_and_plugin *next;
+} entry_and_plugin_t;
+
+static entry_and_plugin_t *plugin_entries = NULL;
+static entry_and_plugin_t *dep_plugin_entries = NULL; /* for dependencies */
+
+#if 0
+static void
+add_plugin_entries()
+{
+ entry_and_plugin_t *ep = plugin_entries;
+ entry_and_plugin_t *deleteep = 0;
+ while (ep)
+ {
+ int plugin_actions = 0;
+ Slapi_PBlock newpb;
+ pblock_init(&newpb);
+ slapi_add_entry_internal_set_pb(&newpb, ep->e, NULL,
+ ep->plugin, plugin_actions);
+ slapi_pblock_set(&newpb, SLAPI_TARGET_DN, (void*)slapi_entry_get_dn_const(ep->e));
+ slapi_add_internal_pb(&newpb);
+ deleteep = ep;
+ ep = ep->next;
+ slapi_ch_free((void**)&deleteep);
+ pblock_done(&newpb);
+ }
+
+ plugin_entries = NULL;
+}
+#endif
+
+static void
+new_plugin_entry(entry_and_plugin_t **ep, Slapi_Entry *e, struct slapdplugin *plugin)
+{
+ entry_and_plugin_t *oldep = 0;
+ entry_and_plugin_t *iterep = *ep;
+
+ entry_and_plugin_t *newep =
+ (entry_and_plugin_t*)slapi_ch_calloc(1,sizeof(entry_and_plugin_t));
+ newep->e = e;
+ newep->plugin = plugin;
+
+ while(iterep)
+ {
+ oldep = iterep;
+ iterep = iterep->next;
+ }
+
+ newep->next = 0;
+
+ if(oldep)
+ oldep->next = newep;
+ else
+ *ep = newep;
+}
+
+
+static void
+add_plugin_entry_dn(const Slapi_DN *plugin_dn)
+{
+ if (!global_plugin_dns)
+ {
+ global_plugin_dns = PL_NewHashTable(20, PL_HashString,
+ PL_CompareStrings,
+ PL_CompareValues, 0, 0);
+ }
+
+ PL_HashTableAdd(global_plugin_dns,
+ slapi_sdn_get_ndn(plugin_dn),
+ (void*)plugin_dn);
+}
+
+#define SLAPI_PLUGIN_NONE_IF_NULL( s ) ((s) == NULL ? "none" : (s))
+
+/*
+ * Allows a plugin to register a plugin.
+ * This was added so that 'object' plugins could register all
+ * the plugin interfaces that it supports.
+ */
+int
+slapi_register_plugin(
+ const char *plugintype,
+ int enabled,
+ const char *initsymbol,
+ slapi_plugin_init_fnptr initfunc,
+ const char *name,
+ char **argv,
+ void *group_identity
+)
+{
+ int ii = 0;
+ int rc = 0;
+ Slapi_Entry *e = slapi_entry_alloc();
+ char *dn = slapi_ch_calloc(1, strlen(name) + strlen(PLUGIN_BASE_DN) + 10);
+
+ sprintf(dn, "cn=%s, %s", name, PLUGIN_BASE_DN);
+ /* this function consumes dn */
+ slapi_entry_init(e, dn, NULL);
+
+ slapi_entry_attr_set_charptr(e, "cn", name);
+ slapi_entry_attr_set_charptr(e, ATTR_PLUGIN_TYPE, plugintype);
+ if (!enabled)
+ slapi_entry_attr_set_charptr(e, ATTR_PLUGIN_ENABLED, "off");
+
+ slapi_entry_attr_set_charptr(e, ATTR_PLUGIN_INITFN, initsymbol);
+
+ for (ii = 0; argv && argv[ii]; ++ii) {
+ char argname[64];
+ sprintf(argname, "%s%d", ATTR_PLUGIN_ARG, ii);
+ slapi_entry_attr_set_charptr(e, argname, argv[ii]);
+ }
+
+ /* plugin_setup copies the given entry */
+ plugin_setup(e, group_identity, initfunc, 0);
+ slapi_entry_free(e);
+
+ return rc;
+}
+
+int
+plugin_call_plugins( Slapi_PBlock *pb, int whichfunction )
+{
+ int plugin_list_number= -1;
+ int rc= 0;
+ int do_op = global_plugin_callbacks_enabled;
+
+ if ( pb == NULL )
+ {
+ return( 0 );
+ }
+
+ switch ( whichfunction ) {
+ case SLAPI_PLUGIN_PRE_BIND_FN:
+ case SLAPI_PLUGIN_PRE_UNBIND_FN:
+ case SLAPI_PLUGIN_PRE_SEARCH_FN:
+ case SLAPI_PLUGIN_PRE_COMPARE_FN:
+ case SLAPI_PLUGIN_PRE_MODIFY_FN:
+ case SLAPI_PLUGIN_PRE_MODRDN_FN:
+ case SLAPI_PLUGIN_PRE_ADD_FN:
+ case SLAPI_PLUGIN_PRE_DELETE_FN:
+ case SLAPI_PLUGIN_PRE_ABANDON_FN:
+ case SLAPI_PLUGIN_PRE_ENTRY_FN:
+ case SLAPI_PLUGIN_PRE_REFERRAL_FN:
+ case SLAPI_PLUGIN_PRE_RESULT_FN:
+ plugin_list_number= PLUGIN_LIST_PREOPERATION;
+ break;
+ case SLAPI_PLUGIN_POST_BIND_FN:
+ case SLAPI_PLUGIN_POST_UNBIND_FN:
+ case SLAPI_PLUGIN_POST_SEARCH_FN:
+ case SLAPI_PLUGIN_POST_SEARCH_FAIL_FN:
+ case SLAPI_PLUGIN_POST_COMPARE_FN:
+ case SLAPI_PLUGIN_POST_MODIFY_FN:
+ case SLAPI_PLUGIN_POST_MODRDN_FN:
+ case SLAPI_PLUGIN_POST_ADD_FN:
+ case SLAPI_PLUGIN_POST_DELETE_FN:
+ case SLAPI_PLUGIN_POST_ABANDON_FN:
+ case SLAPI_PLUGIN_POST_ENTRY_FN:
+ case SLAPI_PLUGIN_POST_REFERRAL_FN:
+ case SLAPI_PLUGIN_POST_RESULT_FN:
+ plugin_list_number= PLUGIN_LIST_POSTOPERATION;
+ break;
+ case SLAPI_PLUGIN_BE_PRE_MODIFY_FN:
+ case SLAPI_PLUGIN_BE_PRE_MODRDN_FN:
+ case SLAPI_PLUGIN_BE_PRE_ADD_FN:
+ case SLAPI_PLUGIN_BE_PRE_DELETE_FN:
+ plugin_list_number= PLUGIN_LIST_BEPREOPERATION;
+ do_op = 1; /* always allow backend callbacks (even during startup) */
+ break;
+ case SLAPI_PLUGIN_BE_POST_MODIFY_FN:
+ case SLAPI_PLUGIN_BE_POST_MODRDN_FN:
+ case SLAPI_PLUGIN_BE_POST_ADD_FN:
+ case SLAPI_PLUGIN_BE_POST_DELETE_FN:
+ plugin_list_number= PLUGIN_LIST_BEPOSTOPERATION;
+ do_op = 1; /* always allow backend callbacks (even during startup) */
+ break;
+ case SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN:
+ case SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN:
+ case SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN:
+ case SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN:
+ plugin_list_number= PLUGIN_LIST_INTERNAL_PREOPERATION;
+ break;
+ case SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN:
+ case SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN:
+ case SLAPI_PLUGIN_INTERNAL_POST_ADD_FN:
+ case SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN:
+ plugin_list_number= PLUGIN_LIST_INTERNAL_POSTOPERATION;
+ break;
+ }
+ if(plugin_list_number!=-1 && do_op)
+ {
+ /* We stash the pblock plugin pointer to preserve the callers context */
+ struct slapdplugin *p;
+ slapi_pblock_get(pb, SLAPI_PLUGIN, &p);
+ /* Call the operation on the Global Plugins */
+ rc= plugin_call_list(global_plugin_list[plugin_list_number], whichfunction, pb);
+
+ slapi_pblock_set(pb, SLAPI_PLUGIN, p);
+ }
+ else
+ {
+ /* Programmer error! or the callback is denied during startup */
+ }
+ return rc;
+}
+
+
+void
+plugin_call_entrystore_plugins(char **entrystr, uint *size)
+{
+ struct slapdplugin *p;
+ for (p = global_plugin_list[PLUGIN_LIST_LDBM_ENTRY_FETCH_STORE];
+ p != NULL; p = p->plg_next )
+ {
+ if (p->plg_entrystorefunc)
+ (*p->plg_entrystorefunc)(entrystr, size);
+ }
+}
+
+void
+plugin_call_entryfetch_plugins(char **entrystr, uint *size)
+{
+ struct slapdplugin *p;
+ for (p = global_plugin_list[PLUGIN_LIST_LDBM_ENTRY_FETCH_STORE];
+ p != NULL; p = p->plg_next )
+ {
+ if (p->plg_entryfetchfunc)
+ (*p->plg_entryfetchfunc)(entrystr, size);
+ }
+}
+
+/*
+ * call extended operation plugins
+ *
+ * return SLAPI_PLUGIN_EXTENDED_SENT_RESULT if one of the extended operation
+ * plugins sent a result.
+ * return SLAPI_PLUGIN_EXTENDED_NOT_HANDLED if no extended operation plugins
+ * handled the operation.
+ * otherwise, return an LDAP error code (possibly a merge of the errors
+ * returned by the plugins we called).
+ */
+int
+plugin_call_exop_plugins( Slapi_PBlock *pb, char *oid )
+{
+ struct slapdplugin *p;
+ int i, rc;
+ int lderr = SLAPI_PLUGIN_EXTENDED_NOT_HANDLED;
+
+ for ( p = global_plugin_list[PLUGIN_LIST_EXTENDED_OPERATION]; p != NULL; p = p->plg_next ) {
+ if ( p->plg_exhandler != NULL ) {
+ if ( p->plg_exoids != NULL ) {
+ for ( i = 0; p->plg_exoids[i] != NULL; i++ ) {
+ if ( strcasecmp( oid, p->plg_exoids[i] )
+ == 0 ) {
+ break;
+ }
+ }
+ if ( p->plg_exoids[i] == NULL ) {
+ continue;
+ }
+ }
+
+ slapi_pblock_set( pb, SLAPI_PLUGIN, p );
+ set_db_default_result_handlers( pb );
+ if ( (rc = (*p->plg_exhandler)( pb ))
+ == SLAPI_PLUGIN_EXTENDED_SENT_RESULT ) {
+ return( rc ); /* result sent */
+ } else if ( rc != SLAPI_PLUGIN_EXTENDED_NOT_HANDLED ) {
+ /*
+ * simple merge: report last real error
+ */
+ if ( lderr == SLAPI_PLUGIN_EXTENDED_NOT_HANDLED
+ || rc != LDAP_SUCCESS ) {
+ lderr = rc;
+ }
+ }
+ }
+ }
+
+ return( lderr );
+}
+
+
+/*
+ * Attempt to convert the extended operation 'oid' to a string by
+ * examining the registered plugins. Returns NULL if no plugin is
+ * registered for this OID.
+ *
+ * Our first choice is to use an OID-specific name that has been
+ * registered by a plugin via the SLAPI_PLUGIN_EXT_OP_NAMELIST pblock setting.
+ * Our second choice is to use the plugin's ID (short name).
+ * Our third choice is to use the plugin's RDN (under cn=config).
+ */
+const char *
+plugin_extended_op_oid2string( const char *oid )
+{
+ struct slapdplugin *p;
+ int i, j;
+ const char *rval = NULL;
+
+ for ( p = global_plugin_list[PLUGIN_LIST_EXTENDED_OPERATION]; p != NULL;
+ p = p->plg_next ) {
+ if ( p->plg_exhandler != NULL && p->plg_exoids != NULL ) {
+ for ( i = 0; p->plg_exoids[i] != NULL; i++ ) {
+ if ( strcasecmp( oid, p->plg_exoids[i] ) == 0 ) {
+ if ( NULL != p->plg_exnames ) {
+ for ( j = 0; j < i && p->plg_exnames[j] != NULL; ++j ) {
+ ;
+ }
+ rval = p->plg_exnames[j]; /* OID-related name */
+ }
+
+ if ( NULL == rval ) {
+ if ( NULL != p->plg_desc.spd_id ) {
+ rval = p->plg_desc.spd_id; /* short name */
+ } else {
+ rval = p->plg_name; /* RDN */
+ }
+ }
+ break;
+ }
+ if ( p->plg_exoids[i] != NULL ) {
+ break;
+ }
+ }
+ }
+ }
+
+ return( rval );
+}
+
+
+/*
+ * kexcoff: return the slapdplugin structure
+ */
+struct slapdplugin *
+plugin_get_pwd_storage_scheme(char *name, int len, int index)
+{
+ /* index could be PLUGIN_LIST_PWD_STORAGE_SCHEME or PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME */
+ struct slapdplugin *p;
+
+ for ( p = global_plugin_list[index]; p != NULL; p = p->plg_next ) {
+ if (strncasecmp(p->plg_pwdstorageschemename, name, len) == 0)
+ return( p );
+ }
+ return( NULL );
+}
+
+char *
+plugin_get_pwd_storage_scheme_list(int index)
+{
+ /* index could be PLUGIN_LIST_PWD_STORAGE_SCHEME or PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME */
+
+ struct slapdplugin *p = NULL;
+ char *names_list = NULL;
+ int len = 0;
+
+ /* first pass - calculate space needed for comma delimited list */
+ for ( p = global_plugin_list[index]; p != NULL; p = p->plg_next ) {
+ if ( p->plg_pwdstorageschemeenc != NULL )
+ {
+ /* + 1 for comma, 1 for space, 1 for null */
+ len += strlen(p->plg_pwdstorageschemename) + 3;
+ }
+ }
+
+ /* no plugins? */
+ if (!len)
+ return NULL;
+
+ /* next, allocate the space */
+ names_list = (char *)slapi_ch_malloc(len+1);
+ *names_list = 0;
+
+ /* second pass - write the string */
+ for ( p = global_plugin_list[index]; p != NULL; p = p->plg_next ) {
+ if ( p->plg_pwdstorageschemeenc != NULL )
+ {
+ strcat(names_list, p->plg_pwdstorageschemename);
+ if (p->plg_next != NULL)
+ strcat(names_list, ", ");
+ }
+ }
+ return( names_list );
+}
+
+int
+slapi_send_ldap_search_entry( Slapi_PBlock *pb, Slapi_Entry *e, LDAPControl **ectrls,
+ char **attrs, int attrsonly )
+{
+ IFP fn = NULL;
+ slapi_pblock_get(pb,SLAPI_PLUGIN_DB_ENTRY_FN,(void*)&fn);
+ if (NULL == fn)
+ {
+ return -1;
+ }
+ return (*fn)(pb,e,ectrls,attrs,attrsonly);
+}
+
+void
+slapi_set_ldap_result( Slapi_PBlock *pb, int err, char *matched, char *text,
+ int nentries, struct berval **urls )
+{
+ char * old_matched = NULL;
+ char * old_text = NULL;
+ char * matched_copy = slapi_ch_strdup(matched);
+ char * text_copy = slapi_ch_strdup(text);
+
+ /* free the old matched and text, if any */
+ slapi_pblock_get(pb, SLAPI_RESULT_MATCHED, &old_matched);
+ slapi_ch_free_string(&old_matched);
+
+ slapi_pblock_get(pb, SLAPI_RESULT_TEXT, &old_text);
+ slapi_ch_free_string(&old_text);
+
+ /* set the new stuff */
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &err);
+ slapi_pblock_set(pb, SLAPI_RESULT_MATCHED, matched_copy);
+ slapi_pblock_set(pb, SLAPI_RESULT_TEXT, text_copy);
+}
+
+void
+slapi_send_ldap_result_from_pb( Slapi_PBlock *pb)
+{
+ int err;
+ char *matched;
+ char *text;
+ IFP fn = NULL;
+
+ slapi_pblock_get(pb, SLAPI_RESULT_CODE, &err);
+ slapi_pblock_get(pb, SLAPI_RESULT_TEXT, &text);
+ slapi_pblock_get(pb, SLAPI_RESULT_MATCHED, &matched);
+
+ slapi_pblock_get(pb,SLAPI_PLUGIN_DB_RESULT_FN,(void*)&fn);
+ if (NULL != fn)
+ {
+ (*fn)(pb,err,matched,text,0,NULL);
+ }
+
+ slapi_pblock_set(pb, SLAPI_RESULT_TEXT, NULL);
+ slapi_pblock_set(pb, SLAPI_RESULT_MATCHED, NULL);
+ slapi_ch_free((void **)&matched);
+ slapi_ch_free((void **)&text);
+}
+
+void
+slapi_send_ldap_result( Slapi_PBlock *pb, int err, char *matched, char *text,
+ int nentries, struct berval **urls )
+{
+ IFP fn = NULL;
+ Slapi_Operation *operation;
+ long op_type;
+
+ /* GB : for spanning requests over multiple backends */
+ if (err == LDAP_NO_SUCH_OBJECT)
+ {
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+ op_type = operation_get_type(operation);
+ if (op_type == SLAPI_OPERATION_SEARCH)
+ {
+ if (urls || nentries)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "ERROR : urls or nentries set"
+ "in sendldap_result while NO_SUCH_OBJECT returned\n",0,0,0);
+ }
+
+ slapi_set_ldap_result(pb, err, matched, text, 0, NULL);
+ return;
+ }
+ }
+
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &err);
+
+ slapi_pblock_get(pb,SLAPI_PLUGIN_DB_RESULT_FN,(void*)&fn);
+ if (NULL == fn)
+ {
+ return ;
+ }
+
+ /*
+ * Call the result function. It should set pb->pb_op->o_status to
+ * SLAPI_OP_STATUS_RESULT_SENT right after sending the result to
+ * the client or otherwise consuming it.
+ */
+ (*fn)(pb,err,matched,text,nentries,urls);
+}
+
+int
+slapi_send_ldap_referral( Slapi_PBlock *pb, Slapi_Entry *e, struct berval **refs,
+ struct berval ***urls )
+{
+ IFP fn = NULL;
+ slapi_pblock_get(pb,SLAPI_PLUGIN_DB_REFERRAL_FN,(void*)&fn);
+ if (NULL == fn)
+ {
+ return -1;
+ }
+ return (*fn)(pb,e,refs,urls);
+}
+
+
+/***********************************************************
+ start of plugin dependency code
+************************************************************/
+
+/* struct _plugin_dep_type
+ * we shall not presume to know all plugin types
+ * so as to allow new types to be added without
+ * requiring changes to this code (hopefully)
+ * so we need to dynamically keep track of them
+ */
+
+typedef struct _plugin_dep_type{
+ char *type; /* the string descriptor */
+ int num_not_started; /* the count of plugins which have yet to be started for this type */
+ struct _plugin_dep_type *next;
+} *plugin_dep_type;
+
+/* _plugin_dep_config
+ * we need somewhere to collect the plugin configurations
+ * prior to attempting to resolve dependencies
+ */
+
+typedef struct _plugin_dep_config {
+ char *name;
+ char *type;
+ Slapi_PBlock pb;
+ struct slapdplugin *plugin;
+ Slapi_Entry *e;
+ int entry_created;
+ int op_done;
+ char **depends_type_list;
+ int total_type;
+ char **depends_named_list;
+ int total_named;
+} plugin_dep_config;
+
+/* list of plugins which should be shutdown in reverse order */
+static plugin_dep_config *global_plugin_shutdown_order = 0;
+static int global_plugins_started = 0;
+
+/*
+ * find_plugin_type
+ *
+ * searches the list for the plugin type
+ * and returns the plugin_dep_type if found
+ */
+
+static plugin_dep_type
+find_plugin_type(plugin_dep_type head, char *type)
+{
+ plugin_dep_type ret = 0;
+ plugin_dep_type iter = head;
+
+ while(iter)
+ {
+ if(!slapi_UTF8CASECMP(iter->type, type))
+ {
+ ret = iter;
+ break;
+ }
+
+ iter = iter->next;
+ }
+
+ return ret;
+}
+
+
+/*
+ * increment_plugin_type
+ *
+ * searches the list for the plugin type
+ * and increments its not started value
+ * returns the current type count on success -1 on failure
+ * to find the type
+ */
+
+static int
+increment_plugin_type(plugin_dep_type head, char *type)
+{
+ int ret = -1;
+ plugin_dep_type the_type;
+
+ if ((the_type = find_plugin_type(head, type)) != NULL)
+ ret = ++the_type->num_not_started;
+
+ return ret;
+}
+
+
+/*
+ * decrement_plugin_type
+ *
+ * searches the list for the plugin type
+ * and decrements its not started value
+ * returns the current type count on success -1 on failure
+ * to find the type
+ */
+
+static int
+decrement_plugin_type(plugin_dep_type head, char *type)
+{
+ int ret = -1;
+ plugin_dep_type the_type;
+
+ if ((the_type = find_plugin_type(head, type)) != NULL)
+ ret = --the_type->num_not_started;
+
+ return ret;
+}
+
+/*
+ * add_plugin_type
+ *
+ * Either increments the count of the plugin type
+ * or when it does not exist, adds it to the list
+ */
+
+static int
+add_plugin_type(plugin_dep_type *head, char *type)
+{
+ int ret = -1;
+
+ if(*head)
+ {
+ if(0 < increment_plugin_type(*head, type))
+ {
+ ret = 0;
+ }
+ }
+
+ if(ret)
+ {
+ /* create new head */
+ plugin_dep_type tmp_head;
+
+ tmp_head = (plugin_dep_type)slapi_ch_malloc(sizeof(struct _plugin_dep_type));
+ tmp_head->num_not_started = 1;
+ tmp_head->type = slapi_ch_strdup(type);
+ ret = 0;
+ tmp_head->next = *head;
+ (*head) = tmp_head;
+ }
+
+ return ret;
+}
+
+
+/*
+ * plugin_create_stringlist
+ *
+ * Creates a string list from values of the entries
+ * attribute passed in as args - used to track dependencies
+ *
+ */
+
+int
+plugin_create_stringlist( Slapi_Entry *plugin_entry, char *attr_name,
+ int *total_strings, char ***list)
+{
+ Slapi_Attr *attr = 0;
+ int hint =0;
+ int num_vals = 0;
+ int val_index = 0;
+ Slapi_Value *val;
+
+ if(0 == slapi_entry_attr_find( plugin_entry, attr_name, &attr ))
+ {
+ /* allocate memory for the string array */
+ slapi_attr_get_numvalues( attr, &num_vals);
+
+ if(num_vals)
+ {
+ *total_strings = num_vals;
+ *list = (char **)slapi_ch_malloc(sizeof(char*) * num_vals);
+ }
+ else
+ goto bail; /* if this ever happens, then they are running on a TSR-80 */
+
+ val_index = 0;
+
+ hint = slapi_attr_first_value( attr, &val );
+ while(val_index < num_vals)
+ {
+ /* add the value to the array */
+ (*list)[val_index] = (char*)slapi_ch_strdup(slapi_value_get_string(val));
+
+ hint = slapi_attr_next_value( attr, hint, &val );
+ val_index++;
+ }
+ }
+ else
+ *total_strings = num_vals;
+
+bail:
+ return num_vals;
+}
+
+
+
+/*
+ * plugin_dependency_startall()
+ *
+ * Starts all plugins (apart from syntax and matching rule) in order
+ * of dependency.
+ *
+ * Dependencies will be determined by these multi-valued attributes:
+ *
+ * nsslapd-plugin-depends-on-type : all plugins whose type value matches one of these values must
+ * be started prior to this plugin
+ *
+ * nsslapd-plugin-depends-on-named : the plugin whose cn value matches one of these values must
+ * be started prior to this plugin
+ */
+
+static int
+plugin_dependency_startall(int argc, char** argv, char *errmsg, int operation)
+{
+ int ret = 0;
+ Slapi_PBlock pb;
+ int total_plugins = 0;
+ plugin_dep_config *config = 0;
+ plugin_dep_type plugin_head = 0;
+ int plugin_index = 0;
+ Slapi_Entry *plugin_entry;
+ int i = 0; /* general index iterator */
+ plugin_dep_type the_plugin_type;
+ int index = 0;
+ char * value;
+ int plugins_started;
+ int num_plg_started;
+ struct slapdplugin *plugin;
+ entry_and_plugin_t *ep = dep_plugin_entries;
+ int shutdown_index = 0;
+
+ /*
+ * Disable registered plugin functions so preops/postops/etc
+ * dont get called prior to the plugin being started (due to
+ * plugins performing ops on the DIT)
+ */
+
+ global_plugin_callbacks_enabled = 0;
+
+ /* Count the plugins so we can allocate memory for the config array */
+ while(ep)
+ {
+ total_plugins++;
+
+ ep = ep->next;
+ }
+
+ /* allocate the config array */
+ config = (plugin_dep_config*)slapi_ch_malloc(sizeof(plugin_dep_config) * total_plugins);
+
+ if(config)
+ memset(config, 0, sizeof(plugin_dep_config) * total_plugins);
+ else
+ {
+ ret = -1;
+ goto bail;
+ }
+
+ ep = dep_plugin_entries;
+
+ /* Collect relevant config */
+ while(ep)
+ {
+ plugin = ep->plugin;
+
+ if(plugin == 0)
+ continue;
+
+ pblock_init(&pb);
+ slapi_pblock_set( &pb, SLAPI_ARGC, &argc);
+ slapi_pblock_set( &pb, SLAPI_ARGV, &argv);
+
+ config[plugin_index].pb = pb;
+ config[plugin_index].e = ep->e;
+
+ /* add type */
+ plugin_entry = ep->e;
+ ep->e = NULL; /* consumed by the operation above, and eventually by the
+ slapi_internal_add operation below */
+
+ if(plugin_entry)
+ {
+ /*
+ * Pass the plugin DN in SLAPI_TARGET_DN and the plugin entry
+ * in SLAPI_ADD_ENTRY. For this to actually work, we need to
+ * create an operation and include that in the pblock as well,
+ * because these two items are stored in the operation parameters.
+ */
+ Operation *op = internal_operation_new(SLAPI_OPERATION_ADD, 0);
+ slapi_pblock_set(&(config[plugin_index].pb), SLAPI_OPERATION, op);
+ slapi_pblock_set(&(config[plugin_index].pb), SLAPI_TARGET_DN,
+ (void*)(slapi_entry_get_dn_const(plugin_entry)));
+ slapi_pblock_set(&(config[plugin_index].pb), SLAPI_ADD_ENTRY,
+ plugin_entry );
+
+ value = slapi_entry_attr_get_charptr(plugin_entry, "nsslapd-plugintype");
+ if(value)
+ {
+ add_plugin_type( &plugin_head, value);
+ config[plugin_index].type = value;
+ value = NULL;
+ }
+
+ /* now the name */
+ value = slapi_entry_attr_get_charptr(plugin_entry, "cn");
+ if(value)
+ {
+ config[plugin_index].name = value;
+ value = NULL;
+ }
+
+
+ config[plugin_index].plugin = plugin;
+
+ /* now add dependencies */
+ plugin_create_stringlist( plugin_entry, "nsslapd-plugin-depends-on-named",
+ &(config[plugin_index].total_named), &(config[plugin_index].depends_named_list));
+
+ plugin_create_stringlist( plugin_entry, "nsslapd-plugin-depends-on-type",
+ &(config[plugin_index].total_type), &(config[plugin_index].depends_type_list));
+ }
+
+ plugin_index++;
+ ep = ep->next;
+ }
+
+ /* prepare list of shutdown order (we need nothing fancier right now
+ * than the reverse startup order) The list may include NULL entries,
+ * these will be plugins which were never started
+ */
+ shutdown_index = total_plugins - 1;
+
+ global_plugin_shutdown_order = (plugin_dep_config*)slapi_ch_malloc(sizeof(plugin_dep_config) * total_plugins);
+ if(global_plugin_shutdown_order)
+ memset(global_plugin_shutdown_order, 0, sizeof(plugin_dep_config) * total_plugins);
+ else
+ {
+ ret = -1;
+ goto bail;
+ }
+
+ /* now resolve dependencies
+ * cycle through list, if a plugin has no dependencies then start it
+ * then remove it from the dependency lists of all other plugins
+ * and decrement the corresponding element of the plugin types array
+ * for depends_type we will need to check the array of plugin types
+ * to see if all type dependencies are at zero prior to start
+ * if one cycle fails to load any plugins we have failed, however
+ * we shall continue loading plugins in case a configuration error
+ * can correct itself
+ */
+
+ plugins_started = 1;
+ num_plg_started = 0;
+
+ while(plugins_started && num_plg_started < total_plugins)
+ {
+ plugins_started = 0;
+
+ for(plugin_index=0; plugin_index < total_plugins; plugin_index++)
+ {
+ /* perform op on plugins only once */
+ if(config[plugin_index].op_done == 0)
+ {
+ int enabled = 0;
+ int satisfied = 0;
+ int break_out = 0;
+
+ /*
+ * determine if plugin is enabled
+ * some processing is necessary even
+ * if it is not
+ */
+ if ( NULL != config[plugin_index].e && (value = slapi_entry_attr_get_charptr(config[plugin_index].e,
+ ATTR_PLUGIN_ENABLED)) &&
+ !strcasecmp(value, "on"))
+ {
+ enabled = 1;
+ }
+ else
+ enabled = 0;
+
+ slapi_ch_free((void**)&value);
+
+ /*
+ * make sure named dependencies have been satisfied
+ * that means that the list of names should contain all
+ * null entries
+ */
+
+ if(enabled && config[plugin_index].total_named)
+ {
+ i = 0;
+
+ while(break_out == 0 && i < config[plugin_index].total_named)
+ {
+ satisfied = 1;
+
+ if((config[plugin_index].depends_named_list)[i] != 0)
+ {
+ satisfied = 0;
+ break_out = 1;
+ }
+
+ i++;
+ }
+
+ if(!satisfied)
+ continue;
+ }
+
+ /*
+ * make sure the type dependencies have been satisfied
+ * that means for each type in the list, it's number of
+ * plugins left not started is zero
+ *
+ */
+ satisfied = 0;
+ break_out = 0;
+
+ if(enabled && config[plugin_index].total_type)
+ {
+ i = 0;
+
+ while(break_out == 0 && i < config[plugin_index].total_type)
+ {
+ satisfied = 1;
+
+ the_plugin_type = find_plugin_type(plugin_head, (config[plugin_index].depends_type_list)[i]);
+
+ if(the_plugin_type && the_plugin_type->num_not_started != 0)
+ {
+ satisfied = 0;
+ break_out = 1;
+ }
+
+ i++;
+ }
+
+ if(!satisfied)
+ continue;
+ }
+
+ /**** This plugins dependencies have now been satisfied ****/
+
+ satisfied = 1; /* symbolic only */
+
+ /*
+ * Add the plugins entry to the DSE so the plugin can get
+ * its config (both enabled and disabled have entries
+ */
+
+ if(!config[plugin_index].entry_created)
+ {
+ int plugin_actions = 0;
+ Slapi_PBlock newpb;
+ Slapi_Entry *newe;
+
+ pblock_init(&newpb);
+ /*
+ * config[plugin_index].e is freed up by
+ * below function calls, but we may need
+ * it later, so create a copy
+ */
+ newe = slapi_entry_dup( config[plugin_index].e );
+ slapi_add_entry_internal_set_pb(&newpb, newe, NULL,
+ plugin_get_default_component_id(), plugin_actions);
+ slapi_pblock_set(&newpb, SLAPI_TARGET_DN, (void*)slapi_entry_get_dn_const(newe));
+ slapi_add_internal_pb(&newpb);
+ pblock_done(&newpb);
+ config[plugin_index].entry_created = 1;
+ }
+
+ /*
+ * only actually start plugin and remove from lists if its enabled
+ * we do remove from plugin type list however - rule is dependency on
+ * zero or more for type
+ */
+
+ if (enabled)
+ {
+ /* finally, perform the op on the plugin */
+
+ LDAPDebug( LDAP_DEBUG_PLUGIN, "Starting %s plugin %s\n" , config[plugin_index].type, config[plugin_index].name, 0 );
+
+ ret = plugin_call_one( config[plugin_index].plugin, operation, &(config[plugin_index].pb));
+
+ pblock_done(&(config[plugin_index].pb));
+
+ if(ret)
+ {
+ /*
+ * We will not exit here. If we allow plugins to load normally it is
+ * possible that a configuration error (dependedncies which were not
+ * configured properly) can be recovered from. If there really is a
+ * problem then the plugin will never start and eventually it will
+ * trigger an exit anyway.
+ */
+ LDAPDebug( LDAP_DEBUG_ANY, "Failed to start %s plugin %s\n" , config[plugin_index].type, config[plugin_index].name, 0 );
+ continue;
+ }
+
+ /* Add this plugin to the shutdown list */
+
+ global_plugin_shutdown_order[shutdown_index] = config[plugin_index];
+ shutdown_index--;
+ global_plugins_started++;
+
+ /* remove this named plugin from other plugins lists */
+
+ for(i=0; i<total_plugins; i++)
+ {
+ index = 0;
+
+ while(index < config[i].total_named)
+ {
+ if((config[i].depends_named_list)[index] != 0 && !slapi_UTF8CASECMP((config[i].depends_named_list)[index], config[plugin_index].name))
+ {
+ slapi_ch_free((void**)&((config[i].depends_named_list)[index]));
+ (config[i].depends_named_list)[index] = 0;
+ }
+
+ index++;
+ }
+ }
+ }
+
+ /* decrement the type counter for this plugin type */
+
+ decrement_plugin_type(plugin_head, config[plugin_index].type);
+ config[plugin_index].op_done = 1;
+ num_plg_started++;
+ plugins_started = 1;
+ }
+
+ }
+ }
+
+ if(plugins_started == 0)
+ {
+ /* a dependency was not resolved - error */
+ LDAPDebug( LDAP_DEBUG_ANY, "Error: Failed to resolve plugin dependencies\n" , 0, 0, 0 );
+
+ /* list the plugins yet to perform op */
+ index = 0;
+
+ while(i < total_plugins)
+ {
+ if(config[i].op_done == 0)
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "Error: %s plugin %s is not started\n" , config[i].type, config[i].name, 0 );
+ }
+
+ i++;
+ }
+
+ exit(1);
+ }
+
+bail:
+
+ /*
+ * need the details in config to hang around for shutdown
+ * config itself may be deleted since its contents have been
+ * copied by value to the shutdown list
+ */
+
+ if(config)
+ {
+ /*
+ index = 0;
+
+ while(index < total_plugins)
+ {
+ if(config[index].depends_named_list)
+ {
+ slapi_ch_free((void**)&(config[index].depends_named_list));
+ }
+
+ if(config[index].depends_type_list)
+ {
+ i = 0;
+
+ while(i < config[index].total_type)
+ {
+ slapi_ch_free((void**)&(config[index].depends_type_list)[i]);
+
+ i++;
+ }
+
+ slapi_ch_free((void**)&(config[index].depends_type_list));
+ }
+
+ slapi_ch_free((void**)&(config[index].name));
+ slapi_ch_free((void**)&(config[index].type));
+
+ index++;
+ }
+ */
+
+ slapi_ch_free((void**)&config);
+ }
+
+ /* Finally enable registered plugin functions */
+
+ global_plugin_callbacks_enabled = 1;
+
+ return ret;
+}
+
+/*
+ * plugin_dependency_closeall
+ *
+ * uses the shutdown list created at startup to close
+ * plugins in the correct order
+ *
+ * For now this leaks the list and contents, but since
+ * it hangs around until shutdown anyway, we don't care
+ *
+ */
+void
+plugin_dependency_closeall()
+{
+ Slapi_PBlock pb;
+ int plugins_closed = 0;
+ int index = 0;
+
+ while(plugins_closed<global_plugins_started)
+ {
+ /*
+ * the first few entries may not be valid
+ * since the list was created in the reverse
+ * order and some plugins may have been counted
+ * for the purpose of list allocation but are
+ * disabled and so were never started
+ *
+ * we check that here
+ */
+ if(global_plugin_shutdown_order[index].name)
+ {
+ pblock_init(&pb);
+ plugin_call_one( global_plugin_shutdown_order[index].plugin, SLAPI_PLUGIN_CLOSE_FN, &pb );
+ plugins_closed++;
+ }
+
+ index++;
+ }
+}
+
+/***********************************************************
+ end of plugin dependency code
+************************************************************/
+
+
+/*
+ * Function: plugin_startall
+ *
+ * Returns: squat
+ *
+ * Description: Some plugins may need to do some stuff after all the config
+ * stuff is done with. So this function goes through and starts all plugins
+ */
+void
+plugin_startall(int argc, char** argv, int start_backends, int start_global)
+{
+ /* initialize special plugin structures */
+ default_plugin_init ();
+
+ plugin_dependency_startall(argc, argv, "plugin startup failed\n", SLAPI_PLUGIN_START_FN);
+}
+
+/*
+ * Function: plugin_close_all
+ *
+ * Returns: squat
+ *
+ * Description: cleanup routine, allows plugins to kill threads, free memory started in start fn
+ *
+ */
+void
+plugin_closeall(int close_backends, int close_globals)
+{
+ plugin_dependency_closeall();
+}
+
+
+static int
+plugin_call_list (struct slapdplugin *list, int operation, Slapi_PBlock *pb)
+{
+ return plugin_call_func(list, operation, pb, 0);
+}
+
+static int
+plugin_call_one (struct slapdplugin *list, int operation, Slapi_PBlock *pb)
+{
+ return plugin_call_func(list, operation, pb, 1);
+}
+
+
+/*
+ * Return codes:
+ * - For preoperation plugins, returns the return code passed back from the first
+ * plugin that fails, or zero if all plugins succeed.
+ * - For bepreop and bepostop plugins, returns a bitwise OR of the return codes
+ * returned by all the plugins called (there's only one bepreop and one bepostop
+ * in DS 5.0 anyway).
+ * - For postoperation plugins, returns 0.
+ */
+static int
+plugin_call_func (struct slapdplugin *list, int operation, Slapi_PBlock *pb, int call_one)
+{
+ /* Invoke the operation on the plugins that are registered for the subtree effected by the operation. */
+ int rc;
+ int return_value = 0;
+ int count= 0;
+ for (; list != NULL; list = list->plg_next)
+ {
+ IFP func = NULL;
+
+ slapi_pblock_set (pb, SLAPI_PLUGIN, list);
+ set_db_default_result_handlers (pb); /* JCM: What's this do? Is it needed here? */
+ if (slapi_pblock_get (pb, operation, &func) == 0 && func != NULL &&
+ plugin_invoke_plugin_pb (list, operation, pb))
+ {
+ char *n= list->plg_name;
+ LDAPDebug( LDAP_DEBUG_TRACE, "Calling plugin '%s' #%d type %d\n", (n==NULL?"noname":n), count, operation );
+ /* counters_to_errors_log("before plugin call"); */
+ if (( rc = func (pb)) != 0 )
+ {
+ if (SLAPI_PLUGIN_PREOPERATION == list->plg_type ||
+ SLAPI_PLUGIN_INTERNAL_PREOPERATION == list->plg_type ||
+ SLAPI_PLUGIN_START_FN == operation )
+ {
+ /*
+ * We bail out of plugin processing for preop plugins
+ * that return a non-zero return code. This allows preop
+ * plugins to cause further preop processing to terminate, and
+ * causes the operation to be vetoed.
+ */
+ return_value = rc;
+ break;
+ } else if (SLAPI_PLUGIN_BEPREOPERATION == list->plg_type ||
+ SLAPI_PLUGIN_BEPOSTOPERATION == list->plg_type)
+ {
+ /* OR the result into the return value for be pre/postops */
+ return_value |= rc;
+ }
+ }
+ /* counters_to_errors_log("after plugin call"); */
+ }
+
+ count++;
+
+ if(call_one)
+ break;
+ }
+ return( return_value );
+}
+
+int
+slapi_berval_cmp (const struct berval* L, const struct berval* R) /* JCM - This does not belong here. But, where should it go? */
+{
+ int result = 0;
+ if (L->bv_len < R->bv_len) {
+ result = memcmp (L->bv_val, R->bv_val, L->bv_len);
+ if (result == 0)
+ result = -1;
+ } else {
+ result = memcmp (L->bv_val, R->bv_val, R->bv_len);
+ if (result == 0 && (L->bv_len > R->bv_len))
+ result = 1;
+ }
+ return result;
+}
+
+
+static char **supported_saslmechanisms = NULL;
+static PRRWLock *supported_saslmechanisms_lock = NULL;
+
+/*
+ * register a supported SASL mechanism so it will be returned as part of the
+ * root DSE.
+ */
+void
+slapi_register_supported_saslmechanism( char *mechanism )
+{
+ if ( mechanism != NULL ) {
+ if (NULL == supported_saslmechanisms_lock) {
+ /* This is thread safe, as it gets executed by
+ * a single thread at init time (main->init_saslmechanisms) */
+ supported_saslmechanisms_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE,
+ "supported saslmechanisms rwlock");
+ if (NULL == supported_saslmechanisms_lock) {
+ /* Out of resources */
+ slapi_log_error(SLAPI_LOG_FATAL, "startup",
+ "slapi_register_supported_saslmechanism: failed to create lock.\n");
+ exit (1);
+ }
+ }
+ PR_RWLock_Wlock(supported_saslmechanisms_lock);
+ charray_add( &supported_saslmechanisms, slapi_ch_strdup( mechanism ));
+ PR_RWLock_Unlock(supported_saslmechanisms_lock);
+ }
+}
+
+
+/*
+ * return pointer to NULL-terminated array of supported SASL mechanisms.
+ * This function is not MTSafe and should be deprecated.
+ * slapi_get_supported_saslmechanisms_copy should be used instead.
+ */
+char **
+slapi_get_supported_saslmechanisms( void )
+{
+ return( supported_saslmechanisms );
+}
+
+
+/*
+ * return pointer to NULL-terminated array of supported SASL mechanisms.
+ */
+char **
+slapi_get_supported_saslmechanisms_copy( void )
+{
+ char ** ret = NULL;
+ PR_RWLock_Rlock(supported_saslmechanisms_lock);
+ ret = charray_dup(supported_saslmechanisms);
+ PR_RWLock_Unlock(supported_saslmechanisms_lock);
+ return( ret );
+}
+
+
+static char **supported_extended_ops = NULL;
+static PRRWLock *extended_ops_lock = NULL;
+
+/*
+ * register all of the LDAPv3 extended operations we know about.
+ */
+void
+ldapi_init_extended_ops( void )
+{
+ extended_ops_lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE,
+ "supported extended ops rwlock");
+ if (NULL == extended_ops_lock) {
+ /* Out of resources */
+ slapi_log_error(SLAPI_LOG_FATAL, "startup",
+ "ldapi_init_extended_ops: failed to create lock.\n");
+ exit (1);
+ }
+
+ PR_RWLock_Wlock(extended_ops_lock);
+ charray_add(&supported_extended_ops,
+ slapi_ch_strdup(EXTOP_BULK_IMPORT_START_OID));
+ charray_add(&supported_extended_ops,
+ slapi_ch_strdup(EXTOP_BULK_IMPORT_DONE_OID));
+ /* add future supported extops here... */
+ PR_RWLock_Unlock(extended_ops_lock);
+}
+
+
+/*
+ * register an extended op. so it can be returned as part of the root DSE.
+ */
+void
+ldapi_register_extended_op( char **opoids )
+{
+ int i;
+
+ PR_RWLock_Wlock(extended_ops_lock);
+ for ( i = 0; opoids != NULL && opoids[i] != NULL; ++i ) {
+ if ( !charray_inlist( supported_extended_ops, opoids[i] )) {
+ charray_add( &supported_extended_ops, slapi_ch_strdup( opoids[i] ));
+ }
+ }
+ PR_RWLock_Unlock(extended_ops_lock);
+}
+
+
+/*
+ * retrieve supported extended operation OIDs
+ * return 0 if successful and -1 if not.
+ * This function is not MTSafe and should be deprecated.
+ * slapi_get_supported_extended_ops_copy should be used instead.
+ */
+char **
+slapi_get_supported_extended_ops( void )
+{
+ return( supported_extended_ops );
+}
+
+
+/*
+ * retrieve supported extended operation OIDs
+ * return 0 if successful and -1 if not.
+ */
+char **
+slapi_get_supported_extended_ops_copy( void )
+{
+ char ** ret = NULL;
+ PR_RWLock_Rlock(extended_ops_lock);
+ ret = charray_dup(supported_extended_ops);
+ PR_RWLock_Unlock(extended_ops_lock);
+ return( ret );
+}
+
+
+/* isApprovedPlugin:
+ * returns 1 if the plugin is approved to be loaded, 0 otherwise.
+ *
+ * If the server is running as the Full version, all plugins are approved,
+ * otherwise, if the server is running as DirectoryLite, only plugins from
+ * Netscape are approved.
+ *
+ * We have a special case for the NT Synch plugin, which is disabled for DLite.
+ */
+static int
+isApprovedPlugin( struct slapdplugin *plugin )
+{
+ if ( config_is_slapd_lite() == 0 ) {
+ /* All the plugins are approved for Directory Full */
+ return 1;
+ }
+
+ if ( plugin == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "isApprovedPlugin: plugin is NULL\n", 0,0,0 );
+ return 0;
+ }
+ if (plugin->plg_desc.spd_vendor == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "isApprovedPlugin: plugin vendor is NULL\n",0,0,0 );
+ return 0;
+ }
+
+ LDAPDebug ( LDAP_DEBUG_TRACE, "isApprovedPlugin() looking at plugin \"%s\" from vendor %s\n",
+ plugin->plg_name, plugin->plg_desc.spd_vendor, 0 );
+
+ /*
+ * approved plugins must have their vendor string set to PLUGIN_MAGIC VENDOR_STR. External
+ * plugins are not allowed for Lite.
+ */
+ if ( strcmp( plugin->plg_desc.spd_vendor, PLUGIN_MAGIC_VENDOR_STR ) == 0)
+ return 1;
+
+ LDAPDebug ( LDAP_DEBUG_ANY, "isApprovedPlugin() plugin \"%s\" is not approved for Directory Lite\n",
+ plugin->plg_name, 0,0 );
+ return 0;
+}
+
+
+/*
+ looks up the given string type to convert to the internal integral type; also
+ returns the plugin list associated with the plugin type
+ returns 0 upon success and non-zero upon failure
+*/
+static int
+plugin_get_type_and_list(
+ const char *plugintype,
+ int *type,
+ struct slapdplugin ***plugin_list
+)
+{
+ int plugin_list_index = -1;
+ if ( strcasecmp( plugintype, "database" ) == 0 ) {
+ *type = SLAPI_PLUGIN_DATABASE;
+ plugin_list_index= PLUGIN_LIST_DATABASE;
+ } else if ( strcasecmp( plugintype, "extendedop" ) == 0 ) {
+ *type = SLAPI_PLUGIN_EXTENDEDOP;
+ plugin_list_index= PLUGIN_LIST_EXTENDED_OPERATION;
+ } else if ( strcasecmp( plugintype, "preoperation" ) == 0 ) {
+ *type = SLAPI_PLUGIN_PREOPERATION;
+ plugin_list_index= PLUGIN_LIST_PREOPERATION;
+ } else if ( strcasecmp( plugintype, "postoperation" ) == 0 ) {
+ *type = SLAPI_PLUGIN_POSTOPERATION;
+ plugin_list_index= PLUGIN_LIST_POSTOPERATION;
+ } else if ( strcasecmp( plugintype, "matchingrule" ) == 0 ) {
+ *type = SLAPI_PLUGIN_MATCHINGRULE;
+ plugin_list_index= PLUGIN_LIST_MATCHINGRULE;
+ } else if ( strcasecmp( plugintype, "syntax" ) == 0 ) {
+ *type = SLAPI_PLUGIN_SYNTAX;
+ plugin_list_index= PLUGIN_LIST_SYNTAX;
+ } else if ( strcasecmp( plugintype, "accesscontrol" ) == 0 ) {
+ *type = SLAPI_PLUGIN_ACL;
+ plugin_list_index= PLUGIN_LIST_ACL;
+ } else if ( strcasecmp( plugintype, "bepreoperation" ) == 0 ) {
+ *type = SLAPI_PLUGIN_BEPREOPERATION;
+ plugin_list_index= PLUGIN_LIST_BEPREOPERATION;
+ } else if ( strcasecmp( plugintype, "bepostoperation" ) == 0 ) {
+ *type = SLAPI_PLUGIN_BEPOSTOPERATION;
+ plugin_list_index= PLUGIN_LIST_BEPOSTOPERATION;
+ } else if ( strcasecmp( plugintype, "internalpreoperation" ) == 0 ) {
+ *type = SLAPI_PLUGIN_INTERNAL_PREOPERATION;
+ plugin_list_index= PLUGIN_LIST_INTERNAL_PREOPERATION;
+ } else if ( strcasecmp( plugintype, "internalpostoperation" ) == 0 ) {
+ *type = SLAPI_PLUGIN_INTERNAL_POSTOPERATION;
+ plugin_list_index= PLUGIN_LIST_INTERNAL_POSTOPERATION;
+ } else if ( strcasecmp( plugintype, "entry" ) == 0 ) {
+ *type = SLAPI_PLUGIN_ENTRY;
+ plugin_list_index= PLUGIN_LIST_ENTRY;
+ } else if ( strcasecmp( plugintype, "object" ) == 0 ) {
+ *type = SLAPI_PLUGIN_TYPE_OBJECT;
+ plugin_list_index= PLUGIN_LIST_OBJECT;
+ } else if ( strcasecmp( plugintype, "pwdstoragescheme" ) == 0 ) {
+ *type = SLAPI_PLUGIN_PWD_STORAGE_SCHEME;
+ plugin_list_index= PLUGIN_LIST_PWD_STORAGE_SCHEME;
+ } else if ( strcasecmp( plugintype, "reverpwdstoragescheme" ) == 0 ) {
+ *type = SLAPI_PLUGIN_REVER_PWD_STORAGE_SCHEME;
+ plugin_list_index= PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME;
+ } else if ( strcasecmp( plugintype, "vattrsp" ) == 0 ) {
+ *type = SLAPI_PLUGIN_VATTR_SP;
+ plugin_list_index= PLUGIN_LIST_VATTR_SP;
+ } else if ( strcasecmp( plugintype, "ldbmentryfetchstore" ) == 0 ) {
+ *type = SLAPI_PLUGIN_LDBM_ENTRY_FETCH_STORE;
+ plugin_list_index= PLUGIN_LIST_LDBM_ENTRY_FETCH_STORE;
+ } else if ( strcasecmp( plugintype, "index" ) == 0 ) {
+ *type = SLAPI_PLUGIN_INDEX;
+ plugin_list_index= PLUGIN_LIST_INDEX;
+ } else {
+ return( 1 ); /* unknown plugin type - pass to backend */
+ }
+
+ if (plugin_list_index >= 0)
+ *plugin_list = &global_plugin_list[plugin_list_index];
+
+ return 0;
+}
+
+static const char *
+plugin_exists(const Slapi_DN *plugin_dn)
+{
+ /* check to see if the plugin name is unique */
+ const char *retval = 0;
+ if (global_plugin_dns && PL_HashTableLookup(global_plugin_dns,
+ slapi_sdn_get_ndn(plugin_dn)))
+ {
+ retval = slapi_sdn_get_dn(plugin_dn);
+ }
+
+ return retval;
+}
+
+static int
+plugin_set_subtree_config(PluginTargetData *subtree_config, const char *val)
+{
+ int status = 0;
+
+ if (strcasecmp (val, ALL_DATA) == 0) /* allow access to both local and remote data */
+ {
+ plugin_set_global (subtree_config);
+ }
+ else if (strcasecmp (val, LOCAL_DATA) == 0) /* allow access to all locally hosted data */
+ {
+ ptd_set_special_data (subtree_config, PLGC_DATA_LOCAL);
+ }
+ else if (strcasecmp (val, REMOTE_DATA) == 0)/* allow access to requests for remote data */
+ {
+ ptd_set_special_data (subtree_config, PLGC_DATA_REMOTE);
+ }
+ else /* dn */
+ {
+ ptd_add_subtree (subtree_config, slapi_sdn_new_dn_byval(val));
+ }
+ /* I suppose we could check the val at this point to make sure
+ its a valid DN . . . */
+
+ return status;
+}
+
+static int
+set_plugin_config_from_entry(
+ const Slapi_Entry *plugin_entry,
+ struct slapdplugin *plugin
+)
+{
+ struct pluginconfig *config = &plugin->plg_conf;
+ char *value = 0;
+ int status = 0;
+ PRBool target_seen = PR_FALSE;
+ PRBool bind_seen = PR_FALSE;
+
+ if ((value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_SCHEMA_CHECK)) != NULL)
+ {
+ if (plugin_config_set_action(&config->plgc_schema_check, value))
+ {
+ LDAPDebug(LDAP_DEBUG_PLUGIN, "Error: invalid value %s for attribute %s "
+ "from entry %s\n", value, ATTR_PLUGIN_SCHEMA_CHECK,
+ slapi_entry_get_dn_const(plugin_entry));
+ status = 1;
+ }
+ slapi_ch_free((void**)&value);
+ }
+
+ if ((value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_LOG_ACCESS)) != NULL)
+ {
+ if (plugin_config_set_action(&config->plgc_log_access, value))
+ {
+ LDAPDebug(LDAP_DEBUG_PLUGIN, "Error: invalid value %s for attribute %s "
+ "from entry %s\n", value, ATTR_PLUGIN_LOG_ACCESS,
+ slapi_entry_get_dn_const(plugin_entry));
+ status = 1;
+ }
+ slapi_ch_free((void**)&value);
+ }
+
+ if ((value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_LOG_AUDIT)) != NULL)
+ {
+ if (plugin_config_set_action(&config->plgc_log_audit, value))
+ {
+ LDAPDebug(LDAP_DEBUG_PLUGIN, "Error: invalid value %s for attribute %s "
+ "from entry %s\n", value, ATTR_PLUGIN_LOG_AUDIT,
+ slapi_entry_get_dn_const(plugin_entry));
+ status = 1;
+ }
+ slapi_ch_free((void**)&value);
+ }
+
+ if ((value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_INVOKE_FOR_REPLOP)) != NULL)
+ {
+ if (plugin_config_set_action(&config->plgc_invoke_for_replop, value))
+ {
+ LDAPDebug(LDAP_DEBUG_PLUGIN, "Error: invalid value %s for attribute %s "
+ "from entry %s\n", value, ATTR_PLUGIN_INVOKE_FOR_REPLOP,
+ slapi_entry_get_dn_const(plugin_entry));
+ status = 1;
+ }
+ slapi_ch_free((void**)&value);
+ }
+
+ if ((value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_TARGET_SUBTREE)) != NULL)
+ {
+ if (plugin_set_subtree_config(&(config->plgc_target_subtrees), value))
+ {
+ LDAPDebug(LDAP_DEBUG_PLUGIN, "Error: invalid value %s for attribute %s "
+ "from entry %s\n", value, ATTR_PLUGIN_TARGET_SUBTREE,
+ slapi_entry_get_dn_const(plugin_entry));
+ status = 1;
+ }
+ else
+ {
+ target_seen = PR_TRUE;
+ }
+ slapi_ch_free((void**)&value);
+ }
+
+ if ((value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_BIND_SUBTREE)) != NULL)
+ {
+ if (plugin_set_subtree_config(&(config->plgc_bind_subtrees), value))
+ {
+ LDAPDebug(LDAP_DEBUG_PLUGIN, "Error: invalid value %s for attribute %s "
+ "from entry %s\n", value, ATTR_PLUGIN_BIND_SUBTREE,
+ slapi_entry_get_dn_const(plugin_entry));
+ status = 1;
+ }
+ else
+ {
+ bind_seen = PR_TRUE;
+ }
+ slapi_ch_free((void**)&value);
+ }
+
+ /* set target subtree default - allow access to all data */
+ if (!target_seen)
+ {
+ plugin_set_global(&(config->plgc_target_subtrees));
+ }
+
+ /* set bind subtree default - allow access to local data only */
+ if (!bind_seen)
+ {
+ ptd_set_special_data(&(config->plgc_bind_subtrees), PLGC_DATA_LOCAL);
+ ptd_set_special_data(&(config->plgc_bind_subtrees), PLGC_DATA_REMOTE);
+ }
+
+ return status;
+}
+
+#if 0
+static PRBool
+plugin_matches_key (char *arg, char *key)
+{
+ PRBool haveVal = strlen (arg) > strlen (key);
+ return (haveVal && strncasecmp (arg, key, strlen (key)) == 0);
+}
+
+static char*
+plugin_get_str_val (char *arg, char *key)
+{
+ return &(arg[strlen (key)]);
+}
+
+static PRBool
+plugin_get_bool_val (char*arg, char *key, char *true_val)
+{
+ return (strcasecmp (&(arg[strlen (key)]), true_val) == 0);
+}
+#endif
+
+/* This function is called after the plugin init function has been called
+ which fills in the desc part of the plugin
+*/
+static int
+add_plugin_description(Slapi_Entry *e, const char *attrname, char *val)
+{
+ struct berval desc;
+ struct berval *newval[2] = {0, 0};
+ int status = 0;
+
+ desc.bv_val = SLAPI_PLUGIN_NONE_IF_NULL( val );
+ desc.bv_len = strlen(desc.bv_val);
+ newval[0] = &desc;
+ if ((status = entry_replace_values(e, attrname, newval)) != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_PLUGIN, "Error: failed to add value %s to "
+ "attribute %s of entry %s\n", val, attrname,
+ slapi_entry_get_dn_const(e));
+ status = 1;
+ }
+
+ return status;
+}
+
+
+/*
+ * The plugin initfunc sets some vendor and version information in the plugin.
+ * This function extracts that and adds it as attributes to `e'. If
+ * `plugin' is NULL, the plugin is located based on the DN in `e'.
+ *
+ * Returns 0 if all goes well and 1 if not.
+ */
+int
+plugin_add_descriptive_attributes( Slapi_Entry *e, struct slapdplugin *plugin )
+{
+ int status = 0;
+
+ if ( NULL == plugin ) {
+ int i;
+ const Slapi_DN *ednp = slapi_entry_get_sdn_const( e );
+ Slapi_DN pdn;
+ struct slapdplugin *plugtmp;
+
+ for( i = 0; NULL == plugin && i < PLUGIN_LIST_GLOBAL_MAX; ++i )
+ {
+ for ( plugtmp = global_plugin_list[i]; NULL == plugin && plugtmp;
+ plugtmp = plugtmp->plg_next)
+ {
+ slapi_sdn_init_dn_byref( &pdn, plugtmp->plg_dn );
+ if ( 0 == slapi_sdn_compare( &pdn, ednp ))
+ {
+ plugin = plugtmp;
+ }
+ slapi_sdn_done( &pdn );
+ }
+ }
+
+ if ( NULL == plugin )
+ {
+ LDAPDebug(LDAP_DEBUG_PLUGIN,
+ "Error: failed to add descriptive values for plugin %s"
+ " (could not find plugin entry)\n",
+ slapi_entry_get_dn_const(e), 0, 0 );
+ return 1; /* failure */
+ }
+ }
+
+
+ if (add_plugin_description(e, ATTR_PLUGIN_PLUGINID,
+ plugin->plg_desc.spd_id))
+ {
+ status = 1;
+ }
+
+ if (add_plugin_description(e, ATTR_PLUGIN_VERSION,
+ plugin->plg_desc.spd_version))
+ {
+ status = 1;
+ }
+
+ if (add_plugin_description(e, ATTR_PLUGIN_VENDOR,
+ plugin->plg_desc.spd_vendor))
+ {
+ status = 1;
+ }
+
+ if (add_plugin_description(e, ATTR_PLUGIN_DESC,
+ plugin->plg_desc.spd_description))
+ {
+ status = 1;
+ }
+
+ return status;
+}
+
+
+/*
+ clean up the memory associated with the plugin
+*/
+static void
+plugin_free(struct slapdplugin *plugin)
+{
+ charray_free(plugin->plg_argv);
+ slapi_ch_free((void**)&plugin->plg_libpath);
+ slapi_ch_free((void**)&plugin->plg_initfunc);
+ slapi_ch_free((void**)&plugin->plg_name);
+ slapi_ch_free((void**)&plugin->plg_dn);
+ if (!plugin->plg_group)
+ plugin_config_cleanup(&plugin->plg_conf);
+ slapi_ch_free((void**)&plugin);
+}
+
+/***********************************
+This is the main entry point for plugin configuration. The plugin_entry argument
+should already contain the necessary fields required to initialize the plugin and
+to give it a proper name in the plugin configuration DIT.
+
+Argument:
+Slapi_Entry *plugin_entry - the required attributes are
+ dn: the dn of the plugin entry
+ cn: the unique name of the plugin
+ nsslapd-pluginType: one of the several recognized plugin types e.g. "postoperation"
+
+if p_initfunc is given, pluginPath and pluginInitFunc are optional
+ nsslapd-pluginPath: full path and file name of the dll implementing the plugin
+ nsslapd-pluginInitFunc: the name of the plugin initialization function
+
+the optional attributes are:
+ nsslapd-pluginArg0
+ ...
+ nsslapd-pluginArg[N-1] - the (old style) arguments to the plugin, where N varies
+ from 0 to the number of arguments. The numbers must be consecutive i.e. no
+ skipping
+
+ Instead of using nsslapd-pluginArgN, it is encouraged for you to use named
+ parameters e.g.
+ nsslapd-tweakThis: 1
+ nsslapd-tweakThat: 2
+ etc.
+
+ nsslapd-pluginEnabled: "on"|"off" - by default, the plugin will be enabled unless
+ this attribute is present and has the value "off"
+
+ for other known attributes, see set_plugin_config_from_entry() above
+
+ all other attributes will be ignored
+
+ The reason this parameter is not const is because it may be modified. This
+ function will modify it if the plugin init function is called successfully
+ to add the description attributes, and the plugin init function may modify
+ it as well.
+
+Argument:
+group - the group to which this plugin will belong - each member of a plugin group
+ shares the pluginconfig of the group leader; refer to the function plugin_get_config
+ for more information
+
+Argument:
+add_entry - if true, the entry will be added to the DIT using the given
+ DN in the plugin_entry - this is the default behavior; if false, the
+ plugin entry will not show up in the DIT
+************************************/
+int
+plugin_setup(Slapi_Entry *plugin_entry, struct slapi_componentid *group,
+ slapi_plugin_init_fnptr p_initfunc, int add_entry)
+{
+ int ii = 0;
+ char attrname[BUFSIZ];
+ char *value = 0;
+ struct slapdplugin *plugin = NULL;
+ struct slapdplugin **plugin_list = NULL;
+ struct slapi_componentid *cid=NULL;
+ const char *existname = 0;
+ slapi_plugin_init_fnptr initfunc = p_initfunc;
+ Slapi_PBlock pb;
+ int status = 0;
+ int approved = 1;
+ int enabled = 1;
+ char *configdir = 0;
+
+ attrname[0] = '\0';
+
+ if (!slapi_entry_get_sdn_const(plugin_entry))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: DN is missing from the plugin.\n",
+ 0, 0, 0);
+ return -1;
+ }
+
+ if ((existname = plugin_exists(slapi_entry_get_sdn_const(plugin_entry))) != NULL)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: the plugin named %s "
+ "already exists.\n", existname, 0, 0);
+ return -1;
+ }
+
+ /*
+ * create a new plugin structure, fill it in, and prepare to
+ * call the plugin's init function. the init function will
+ * set the plugin function pointers.
+ */
+ plugin = (struct slapdplugin *)slapi_ch_calloc(1, sizeof(struct slapdplugin));
+
+ plugin->plg_dn = slapi_ch_strdup(slapi_entry_get_dn_const(plugin_entry));
+
+ if (!(value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_TYPE)))
+ {
+ /* error: required attribute %s missing */
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: required attribute %s is missing "
+ "from entry \"%s\"\n", ATTR_PLUGIN_TYPE,
+ slapi_entry_get_dn_const(plugin_entry), 0);
+ status = -1;
+ goto PLUGIN_CLEANUP;
+ }
+ else
+ {
+ status = plugin_get_type_and_list(value, &plugin->plg_type,
+ &plugin_list);
+
+ if ( status != 0 ) {
+ /* error: unknown plugin type */
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: unknown plugin type \"%s\" "
+ "in entry \"%s\"\n",
+ value, slapi_entry_get_dn_const(plugin_entry), 0);
+ slapi_ch_free((void**)&value);
+ status = -1;
+ goto PLUGIN_CLEANUP;
+ }
+ slapi_ch_free((void**)&value);
+ }
+
+ if (!status &&
+ !(value = slapi_entry_attr_get_charptr(plugin_entry, "cn")))
+ {
+ /* error: required attribute %s missing */
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: required attribute %s is missing "
+ "from entry \"%s\"\n", "cn",
+ slapi_entry_get_dn_const(plugin_entry), 0);
+ status = -1;
+ goto PLUGIN_CLEANUP;
+ }
+ else
+ {
+ plugin->plg_name = value; /* plugin owns value's memory now, don't free */
+ }
+
+ if (!(value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_INITFN)))
+ {
+ if (!initfunc)
+ {
+ /* error: required attribute %s missing */
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: required attribute %s is missing "
+ "from entry \"%s\"\n", ATTR_PLUGIN_INITFN,
+ slapi_entry_get_dn_const(plugin_entry), 0);
+ status = -1;
+ goto PLUGIN_CLEANUP;
+ }
+ }
+ else
+ {
+ plugin->plg_initfunc = value; /* plugin owns value's memory now, don't free */
+ }
+
+ if (!initfunc)
+ {
+ if (!(value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_PATH)))
+ {
+ /* error: required attribute %s missing */
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: required attribute %s is missing "
+ "from entry \"%s\"\n", ATTR_PLUGIN_PATH,
+ slapi_entry_get_dn_const(plugin_entry), 0);
+ status = -1;
+ goto PLUGIN_CLEANUP;
+ }
+ else
+ {
+ plugin->plg_libpath = value; /* plugin owns value's memory now, don't free */
+ }
+
+ /*
+ * load the plugin's init function
+ */
+ if ((initfunc = (slapi_plugin_init_fnptr)sym_load(plugin->plg_libpath,
+ plugin->plg_initfunc, plugin->plg_name, 1 /* report errors */
+ )) == NULL)
+ {
+ status = -1;
+ goto PLUGIN_CLEANUP;
+ }
+#ifdef _WIN32
+ {
+ set_debug_level_fn_t fn;
+ /* for Win32 only, attempt to get its debug level init function */
+ if ((fn = (set_debug_level_fn_t)sym_load(plugin->plg_libpath,
+ "plugin_init_debug_level", plugin->plg_name,
+ 0 /* do not report errors */ )) != NULL) {
+ /* we hooked the function, so call it */
+ (*fn)(module_ldap_debug);
+ }
+ }
+#endif
+ }
+
+ if (!status && group) /* uses group's config; see plugin_get_config */
+ {
+ struct slapi_componentid * cid = (struct slapi_componentid *) group;
+ plugin->plg_group = (struct slapdplugin *) cid->sci_plugin;
+ }
+ else if (!status) /* using own config */
+ {
+ plugin_config_init(&(plugin->plg_conf));
+ set_plugin_config_from_entry(plugin_entry, plugin);
+ }
+
+ /* add the plugin arguments */
+ value = 0;
+ ii = 0;
+ sprintf(attrname, "%s%d", ATTR_PLUGIN_ARG, ii);
+ while ((value = slapi_entry_attr_get_charptr(plugin_entry, attrname)) != NULL)
+ {
+ charray_add(&plugin->plg_argv, value);
+ plugin->plg_argc++;
+ ++ii;
+ sprintf(attrname, "%s%d", ATTR_PLUGIN_ARG, ii);
+ }
+
+ memset((char *)&pb, '\0', sizeof(pb));
+ slapi_pblock_set(&pb, SLAPI_PLUGIN, plugin);
+ slapi_pblock_set(&pb, SLAPI_PLUGIN_VERSION, (void *)SLAPI_PLUGIN_CURRENT_VERSION);
+
+ cid = generate_componentid (plugin,NULL);
+ slapi_pblock_set(&pb, SLAPI_PLUGIN_IDENTITY, (void*)cid);
+
+ configdir = config_get_configdir();
+ slapi_pblock_set(&pb, SLAPI_CONFIG_DIRECTORY, configdir);
+
+ if ((*initfunc)(&pb) != 0)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "Init function \"%s\" for \"%s\" plugin"
+ " in library \"%s\" failed\n",
+ plugin->plg_initfunc, plugin->plg_name,
+ plugin->plg_libpath);
+ status = -1;
+ goto PLUGIN_CLEANUP;
+ }
+
+ if ( !status ) {
+ status = plugin_add_descriptive_attributes( plugin_entry, plugin );
+ }
+
+ /* see if the plugin is approved or not */
+ if ((approved = isApprovedPlugin(plugin)) != 0)
+ {
+ if ((!plugin->plg_version) ||
+ (!SLAPI_PLUGIN_IS_COMPAT(plugin->plg_version))) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Plugin \"%s\" from library \"%s\""
+ " has wrong version (supported versions: %s)\n",
+ plugin->plg_name, plugin->plg_libpath,
+ SLAPI_PLUGIN_SUPPORTED_VERSIONS);
+ approved = 0;
+ }
+ }
+
+ /* see if the plugin is enabled or not */
+ if ((value = slapi_entry_attr_get_charptr(plugin_entry,
+ ATTR_PLUGIN_ENABLED)) &&
+ !strcasecmp(value, "off"))
+ {
+ enabled = 0;
+ }
+ else
+ {
+ enabled = 1;
+ }
+
+ if (value)
+ slapi_ch_free((void**)&value);
+
+ if (!approved) {
+ enabled = 0;
+ LDAPDebug(LDAP_DEBUG_ANY, "Plugin \"%s\" is disabled.\n",
+ plugin->plg_name,0,0);
+ }
+
+ if (approved)
+ {
+ if(enabled)
+ {
+ /* don't use raw pointer from plugin_entry because it
+ will be freed later by the caller */
+ Slapi_DN *dn_copy = slapi_sdn_dup(slapi_entry_get_sdn_const(plugin_entry));
+ add_plugin_to_list(plugin_list, plugin);
+ add_plugin_entry_dn(dn_copy);
+ }
+
+ if (add_entry)
+ {
+ /* make a copy of the plugin entry for our own use because it will
+ be freed later by the caller */
+ Slapi_Entry *e_copy = slapi_entry_dup(plugin_entry);
+ /* new_plugin_entry(&plugin_entries, plugin_entry, plugin); */
+ new_plugin_entry(&dep_plugin_entries, e_copy, plugin);
+ }
+ }
+
+
+PLUGIN_CLEANUP:
+ if (status)
+ plugin_free(plugin);
+ slapi_ch_free((void **)&configdir);
+
+ return status;
+}
+
+/* set default configuration parameters */
+static void
+plugin_config_init (struct pluginconfig *config)
+{
+ PR_ASSERT (config);
+
+ ptd_init (&config->plgc_target_subtrees);
+ ptd_init (&config->plgc_bind_subtrees);
+ config->plgc_schema_check = PLGC_ON;
+ config->plgc_invoke_for_replop = PLGC_ON;
+ /* currently, we leave it up to plugin, but don't actually tell plugins that they can choose.
+ We want changes to always be logged by regular plugins to avoid data inconsistency, but we
+ want to allow internal plugins like replication to make the decision.*/
+ config->plgc_log_change = PLGC_UPTOPLUGIN;
+ config->plgc_log_access = PLGC_OFF;
+ config->plgc_log_audit = PLGC_OFF;
+}
+
+static int
+plugin_config_set_action (int *action, char *value)
+{
+ PR_ASSERT (action);
+ PR_ASSERT (value);
+
+ if (strcasecmp (value, "on") == 0)
+ {
+ *action = PLGC_ON;
+ }
+ else if (strcasecmp (value, "off") == 0)
+ {
+ *action = PLGC_OFF;
+ }
+ else if (strcasecmp (value, "uptoplugin") == 0)
+ {
+ *action = PLGC_UPTOPLUGIN;
+ }
+ else
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "plugin_config_set_action: invalid action %s\n", value);
+ return -1;
+ }
+
+ return 0;
+}
+
+static void
+plugin_config_cleanup (struct pluginconfig *config)
+{
+ PR_ASSERT (config);
+
+ ptd_cleanup (&config->plgc_target_subtrees);
+ ptd_cleanup (&config->plgc_bind_subtrees);
+}
+
+#if 0
+static char*
+plugin_config_action_to_string (int action)
+{
+ switch (action)
+ {
+ case PLGC_ON: return "on";
+ case PLGC_OFF: return "off";
+ case PLGC_UPTOPLUGIN: return "uptoplugin";
+ default: return NULL;
+ }
+}
+#endif
+
+static struct pluginconfig*
+plugin_get_config (struct slapdplugin *plugin)
+{
+ struct slapdplugin *temp = plugin;
+
+ PR_ASSERT (plugin);
+
+ while (temp->plg_group)
+ {
+ temp = temp->plg_group;
+ }
+
+ return &(temp->plg_conf);
+}
+
+static PRBool
+plugin_invoke_plugin_pb (struct slapdplugin *plugin, int operation, Slapi_PBlock *pb)
+{
+ Slapi_DN *target_spec;
+ PRBool rc;
+
+ PR_ASSERT (plugin);
+ PR_ASSERT (pb);
+
+ /* we always allow initialization and cleanup operations */
+ if (operation == SLAPI_PLUGIN_START_FN || operation == SLAPI_PLUGIN_POSTSTART_FN ||
+ operation == SLAPI_PLUGIN_CLOSE_FN || operation == SLAPI_PLUGIN_CLEANUP_FN)
+ return PR_TRUE;
+
+ PR_ASSERT (pb->pb_op);
+
+ target_spec = operation_get_target_spec (pb->pb_op);
+
+ PR_ASSERT (target_spec);
+
+ rc = plugin_invoke_plugin_sdn (plugin, operation, pb, target_spec);
+
+ return rc;
+}
+
+PRBool
+plugin_invoke_plugin_sdn (struct slapdplugin *plugin, int operation, Slapi_PBlock *pb, Slapi_DN *target_spec)
+{
+ PluginTargetData *ptd;
+ struct pluginconfig *config;
+ Slapi_Backend *be;
+ int isroot;
+ PRBool islocal;
+ PRBool bindop;
+ unsigned long op;
+ PRBool rc;
+ int method = -1;
+
+ PR_ASSERT (plugin);
+
+ /* get configuration from the group plugin if necessary */
+ config = plugin_get_config (plugin);
+ slapi_pblock_get(pb, SLAPI_BIND_METHOD, &method);
+ /* check if plugin is configured to service replicated operations */
+ if (!config->plgc_invoke_for_replop)
+ {
+ int repl_op;
+
+ /* if pb is NULL we assume it is not a replicated operation */
+ if (pb)
+ {
+ slapi_pblock_get (pb, SLAPI_IS_REPLICATED_OPERATION, &repl_op);
+ if (repl_op)
+ return PR_FALSE;
+ }
+ }
+
+ if (pb)
+ {
+ if (pb->pb_op)
+ {
+ op = operation_get_type(pb->pb_op);
+
+ if (op == SLAPI_OPERATION_BIND || op == SLAPI_OPERATION_UNBIND)
+ {
+ bindop = PR_TRUE;
+ }
+ else
+ {
+ bindop = PR_FALSE;
+ }
+
+ slapi_pblock_get (pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+ }
+ else
+ {
+ bindop = PR_FALSE;
+ isroot = 1;
+ }
+
+ slapi_pblock_get (pb, SLAPI_BACKEND, &be);
+
+ /* determine whether data are local or remote */
+ /* remote if chaining backend or default backend */
+
+ if ( be!=NULL ) {
+ islocal=!(slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA));
+ } else {
+ islocal = be != defbackend_get_backend();
+ }
+
+ }
+ else
+ {
+ bindop = PR_FALSE;
+ islocal = PR_TRUE;
+ isroot = 1;
+ }
+
+ if (bindop)
+ {
+ ptd = &(config->plgc_bind_subtrees);
+ }
+ else
+ {
+ ptd = &(config->plgc_target_subtrees);
+ }
+
+ rc = plugin_matches_operation (target_spec, ptd, bindop, isroot, islocal, method);
+
+ return rc;
+}
+
+/* this interface is exposed to be used by internal operations.
+ */
+char* plugin_get_dn (const struct slapdplugin *plugin)
+{
+ char *plugindn;
+ char *pattern = "cn=%s," PLUGIN_BASE_DN;
+
+ if (plugin == NULL) /* old plugin that does not pass identity - use default */
+ plugin = &global_default_plg;
+
+ if (plugin->plg_name == NULL)
+ return NULL;
+
+ plugindn = (char*)slapi_ch_malloc (strlen (pattern) + strlen (plugin->plg_name));
+ if (plugindn)
+ sprintf (plugindn, pattern, plugin->plg_name);
+
+ return plugindn;
+}
+
+static PRBool plugin_is_global (const PluginTargetData *ptd)
+{
+ /* plugin is considered to be global if it is invoked for
+ global data, local data and anonymous bind (bind target
+ data only). We don't include directory manager here
+ as it is considered to be part of local data */
+ return (ptd_is_special_data_set (ptd, PLGC_DATA_LOCAL) &&
+ ptd_is_special_data_set (ptd, PLGC_DATA_REMOTE) &&
+ ptd_is_special_data_set (ptd, PLGC_DATA_BIND_ANONYMOUS) &&
+ ptd_is_special_data_set (ptd, PLGC_DATA_BIND_ROOT));
+}
+
+static void plugin_set_global (PluginTargetData *ptd)
+{
+ PR_ASSERT (ptd);
+
+ /* plugin is global if it is allowed access to all data */
+ ptd_set_special_data (ptd, PLGC_DATA_LOCAL);
+ ptd_set_special_data (ptd, PLGC_DATA_REMOTE);
+ ptd_set_special_data (ptd, PLGC_DATA_BIND_ANONYMOUS);
+ ptd_set_special_data (ptd, PLGC_DATA_BIND_ROOT);
+}
+
+static void plugin_set_default_access (struct pluginconfig *config)
+{
+ /* by default, plugins are invoked if dn is local for bind operations,
+ and for all requests for all other operations */
+ PR_ASSERT (config);
+
+ plugin_set_global (&config->plgc_target_subtrees);
+ ptd_set_special_data (&config->plgc_bind_subtrees, PLGC_DATA_LOCAL);
+ ptd_set_special_data (&config->plgc_bind_subtrees, PLGC_DATA_REMOTE);
+}
+
+/* determine whether operation should be allowed based on plugin configuration */
+PRBool plugin_allow_internal_op (Slapi_DN *target_spec, struct slapdplugin *plugin)
+{
+ struct pluginconfig *config = plugin_get_config (plugin);
+ Slapi_Backend *be;
+ int islocal;
+
+ if (plugin_is_global (&config->plgc_target_subtrees))
+ return PR_TRUE;
+
+ /* ONREPL - we do be_select to decide whether the request is for local
+ or remote data. We might need to reconsider how to do this
+ for performance reasons since be_select will be done again
+ once the operation goes through */
+ be = slapi_be_select(target_spec);
+
+ /* determine whether data are local or remote */
+ /* remote if chaining backend or default backend */
+
+ if ( be!=NULL ) {
+ islocal=!(slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA));
+ } else {
+ islocal = be != defbackend_get_backend();
+ }
+ /* SIMPLE auth method sends us through original code path in plugin_mathches_operation */
+ return plugin_matches_operation (target_spec, &config->plgc_target_subtrees,
+ PR_FALSE, PR_FALSE, islocal, LDAP_AUTH_SIMPLE);
+}
+
+static PRBool plugin_matches_operation (Slapi_DN *target_spec, PluginTargetData *ptd,
+ PRBool bindop, PRBool isroot, PRBool islocal, int method)
+{
+ int cookie;
+ Slapi_DN *subtree;
+
+ /* check for special cases */
+
+ if (plugin_is_global (ptd))
+ return PR_TRUE;
+
+ /* if method is SASL we can have a null DN so bypass this check*/
+ if(method != LDAP_AUTH_SASL) {
+ if (bindop && target_spec && (slapi_sdn_get_dn (target_spec) == NULL ||
+ slapi_sdn_get_dn (target_spec)[0] == '\0'))
+ {
+ return (ptd_is_special_data_set (ptd, PLGC_DATA_BIND_ANONYMOUS));
+ }
+ }
+
+ /* check for root bind */
+ if (bindop && isroot)
+ {
+ return (ptd_is_special_data_set (ptd, PLGC_DATA_BIND_ROOT));
+ }
+
+ /* check for local data */
+ if (ptd_is_special_data_set (ptd, PLGC_DATA_LOCAL) && islocal)
+ {
+ return PR_TRUE;
+ }
+
+ /* check for remote data */
+ if (ptd_is_special_data_set (ptd, PLGC_DATA_REMOTE) && !islocal)
+ {
+ return (PR_TRUE);
+ }
+
+ subtree = ptd_get_first_subtree (ptd, &cookie);
+ while (subtree)
+ {
+ if (slapi_sdn_issuffix (target_spec, subtree))
+ return (PR_TRUE);
+
+ subtree = ptd_get_next_subtree (ptd, &cookie);
+ }
+
+ return PR_FALSE;
+
+}
+
+/* build operation action bitmap based on plugin configuration and actions specified for the operation */
+int plugin_build_operation_action_bitmap (int input_actions, const struct slapdplugin *plugin)
+{
+ int result_actions = 0;
+
+ /* old plugin that does not pass its identity to the operation */
+ if (plugin == NULL)
+ plugin = &global_default_plg;
+
+ if (plugin->plg_conf.plgc_log_access)
+ result_actions |= OP_FLAG_ACTION_LOG_ACCESS;
+
+ if (plugin->plg_conf.plgc_log_audit)
+ result_actions |= OP_FLAG_ACTION_LOG_AUDIT;
+
+ /*
+ * OP_FLAG_ACTION_INVOKE_FOR_REPLOP is now used only by URP code.
+ * If someday this code needs to reclaim the flag, it has to use
+ * another flag to avoid the conflict with URP code.
+ *
+ * if (plugin->plg_conf.plgc_invoke_for_replop)
+ * result_actions |= OP_FLAG_ACTION_INVOKE_FOR_REPLOP;
+ */
+
+ switch (plugin->plg_conf.plgc_schema_check)
+ {
+ case PLGC_OFF: result_actions &= ~OP_FLAG_ACTION_SCHEMA_CHECK;
+ break;
+
+ case PLGC_ON: result_actions |= OP_FLAG_ACTION_SCHEMA_CHECK;
+ break;
+
+ case PLGC_UPTOPLUGIN: break;
+
+ default: PR_ASSERT (PR_FALSE);
+ }
+
+ switch (plugin->plg_conf.plgc_log_change)
+ {
+ case PLGC_OFF: result_actions &= ~OP_FLAG_ACTION_LOG_CHANGES;
+ break;
+
+ case PLGC_ON: result_actions |= OP_FLAG_ACTION_LOG_CHANGES;
+ break;
+
+ case PLGC_UPTOPLUGIN: break;
+
+ default: PR_ASSERT (PR_FALSE);
+ }
+
+ return result_actions;
+}
+
+const struct slapdplugin*
+plugin_get_server_plg()
+{
+ if(!global_server_plg_initialised)
+ {
+ global_server_plg.plg_name = "server";
+ plugin_set_global (&global_server_plg.plg_conf.plgc_target_subtrees);
+ global_server_plg.plg_conf.plgc_log_access = 1;
+ global_server_plg.plg_conf.plgc_log_audit = 1;
+ global_server_plg.plg_conf.plgc_schema_check = 1;
+ global_server_plg.plg_conf.plgc_log_change = 1;
+ global_server_plg_initialised= 1;
+ global_server_plg_initialised= 1;
+ }
+ return &global_server_plg;
+}
+
+struct slapi_componentid * plugin_get_default_component_id() {
+
+ if(!global_server_plg_id_initialised) {
+ global_server_id_plg.sci_plugin=plugin_get_server_plg();
+ global_server_id_plg.sci_component_name=
+ plugin_get_dn(global_server_id_plg.sci_plugin);
+ global_server_plg_id_initialised=1;
+ }
+ return &global_server_id_plg;
+}
+
+static void
+default_plugin_init()
+{
+ global_default_plg.plg_name = "old plugin";
+ plugin_config_init (&global_default_plg.plg_conf);
+ plugin_set_default_access (&global_default_plg.plg_conf);
+}
+
+#if 0
+static void trace_plugin_invocation (Slapi_DN *target_spec, PluginTargetData *ptd,
+ PRBool bindop, PRBool isroot, PRBool islocal, int invoked)
+{
+ int cookie, i = 0;
+ Slapi_DN *sdn;
+
+
+ slapi_log_error (SLAPI_LOG_FATAL, NULL,
+ "Invocation parameters: target_spec = %s, bindop = %d, isroot=%d, islocal=%d\n"
+ "Plugin configuration: local_data=%d, remote_data=%d, anonymous_bind=%d, root_bind=%d\n",
+ slapi_sdn_get_ndn (target_spec), bindop, isroot, islocal, ptd->special_data[0],
+ ptd->special_data[1], ptd->special_data[2], ptd->special_data[3]);
+
+ sdn = ptd_get_first_subtree (ptd, &cookie);
+ while (sdn)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, "target_subtree%d: %s\n", i, slapi_sdn_get_ndn (sdn));
+ sdn = ptd_get_next_subtree (ptd, &cookie);
+ }
+
+ slapi_log_error (SLAPI_LOG_FATAL, NULL, invoked ? "Plugin is invoked\n" : "Plugin is not invoked\n");
+}
+#endif
+
+/* functions to manipulate PluginTargetData type */
+static void ptd_init (PluginTargetData *ptd)
+{
+ PR_ASSERT (ptd);
+
+ dl_init (&ptd->subtrees, 0 /* initial count */);
+ memset (&ptd->special_data, 0, sizeof (ptd->special_data));
+}
+
+static void ptd_cleanup (PluginTargetData *ptd)
+{
+ PR_ASSERT (ptd);
+
+ dl_cleanup (&ptd->subtrees, (FREEFN)slapi_sdn_free);
+ memset (&ptd->special_data, 0, sizeof (ptd->special_data));
+}
+
+static void ptd_add_subtree (PluginTargetData *ptd, Slapi_DN *subtree)
+{
+ PR_ASSERT (ptd);
+ PR_ASSERT (subtree);
+
+ dl_add (&ptd->subtrees, subtree);
+}
+
+static void ptd_set_special_data (PluginTargetData *ptd, int type)
+{
+ PR_ASSERT (ptd);
+ PR_ASSERT (type >= 0 && type < PLGC_DATA_MAX);
+
+ ptd->special_data [type] = PR_TRUE;
+}
+
+#if 0
+static void ptd_clear_special_data (PluginTargetData *ptd, int type)
+{
+ PR_ASSERT (ptd);
+ PR_ASSERT (type >= 0 && type < PLGC_DATA_MAX);
+
+ ptd->special_data [type] = PR_FALSE;
+}
+#endif
+
+static Slapi_DN *ptd_get_first_subtree (const PluginTargetData *ptd, int *cookie)
+{
+ PR_ASSERT (ptd);
+
+ return dl_get_first (&ptd->subtrees, cookie);
+}
+
+static Slapi_DN *ptd_get_next_subtree (const PluginTargetData *ptd, int *cookie)
+{
+ PR_ASSERT (ptd);
+
+ return dl_get_next (&ptd->subtrees, cookie);
+}
+
+static PRBool ptd_is_special_data_set (const PluginTargetData *ptd, int type)
+{
+ PR_ASSERT (ptd);
+ PR_ASSERT (type >= 0 && type < PLGC_DATA_MAX);
+
+ return ptd->special_data [type];
+}
+
+#if 0
+static Slapi_DN* ptd_delete_subtree (PluginTargetData *ptd, Slapi_DN *subtree)
+{
+ PR_ASSERT (ptd);
+ PR_ASSERT (subtree);
+
+ return (Slapi_DN*)dl_delete (&ptd->subtrees, subtree, (CMPFN)slapi_sdn_compare, NULL);
+}
+#endif
+
+int ptd_get_subtree_count (const PluginTargetData *ptd)
+{
+ PR_ASSERT (ptd);
+
+ return dl_get_count (&ptd->subtrees);
+}
+
+/* needed by command-line tasks to find an instance's plugin */
+struct slapdplugin *plugin_get_by_name(char *name)
+{
+ int x;
+ struct slapdplugin *plugin;
+
+ for(x = 0; x < PLUGIN_LIST_GLOBAL_MAX; x++) {
+ for(plugin = global_plugin_list[x]; plugin; plugin = plugin->plg_next) {
+ if (!strcmp(name, plugin->plg_name)) {
+ return plugin;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+struct slapi_componentid *
+generate_componentid ( struct slapdplugin * pp , char * name )
+{
+ struct slapi_componentid * idp;
+
+ idp = (struct slapi_componentid *) slapi_ch_calloc(1, sizeof( *idp ));
+ if ( pp )
+ idp->sci_plugin=pp;
+ else
+ idp->sci_plugin=(struct slapdplugin *) plugin_get_server_plg();
+
+ if ( name )
+ idp->sci_component_name = slapi_ch_strdup(name);
+ else
+ /* Use plugin dn */
+ idp->sci_component_name = plugin_get_dn( idp->sci_plugin );
+
+ if (idp->sci_component_name)
+ slapi_dn_normalize(idp->sci_component_name);
+ return idp;
+}
+
+void release_componentid ( struct slapi_componentid * id )
+{
+ if ( id ) {
+ if ( id->sci_component_name ) {
+ slapi_ch_free((void **)&id->sci_component_name);
+ id->sci_component_name=NULL;
+ }
+ slapi_ch_free((void **)&id);
+ }
+}
+
+/* used in main.c if -V flag is given */
+
+static void slapd_print_plugin_version (
+ struct slapdplugin *plg,
+ struct slapdplugin *prev
+)
+{
+ if (plg == NULL || plg->plg_libpath == NULL) return;
+
+ /* same library as previous - don't print twice */
+ if (prev != NULL && prev->plg_libpath != NULL) {
+ if (strcmp(prev->plg_libpath,plg->plg_libpath) == 0) {
+ return;
+ }
+ }
+
+ printf("%s: %s\n",
+ plg->plg_libpath,
+ plg->plg_desc.spd_version ? plg->plg_desc.spd_version : "");
+}
+
+static void slapd_print_pluginlist_versions(struct slapdplugin *plg)
+{
+ struct slapdplugin *p,*prev = NULL;
+
+ for (p = plg; p != NULL; p = p->plg_next) {
+ slapd_print_plugin_version(p,prev);
+ prev = p;
+ }
+}
+
+void plugin_print_versions(void)
+{
+ int i;
+
+ for (i = 0; i < PLUGIN_LIST_GLOBAL_MAX; i++) {
+ slapd_print_pluginlist_versions(get_plugin_list(i));
+ }
+
+}
diff --git a/ldap/servers/slapd/plugin_acl.c b/ldap/servers/slapd/plugin_acl.c
new file mode 100644
index 00000000..2115dfbd
--- /dev/null
+++ b/ldap/servers/slapd/plugin_acl.c
@@ -0,0 +1,192 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * plugin_acl.c - routines for calling access control plugins
+ */
+
+#include "slap.h"
+
+static int
+acl_default_access ( Slapi_PBlock *pb , Slapi_Entry *e, int access)
+{
+
+ int isRoot, rootdse, accessCheckDisabled;
+ int rc;
+
+ slapi_pblock_get ( pb, SLAPI_REQUESTOR_ISROOT, &isRoot);
+ if ( isRoot ) return LDAP_SUCCESS;
+
+ rc = slapi_pblock_get ( pb, SLAPI_PLUGIN_DB_NO_ACL, &accessCheckDisabled );
+ if ( rc != -1 && accessCheckDisabled ) return LDAP_SUCCESS;
+
+ rootdse = slapi_is_rootdse ( slapi_entry_get_ndn ( e ) );
+ if ( rootdse && (access & (SLAPI_ACL_READ | SLAPI_ACL_SEARCH) ) )
+ return LDAP_SUCCESS;
+
+ return LDAP_INSUFFICIENT_ACCESS;
+}
+
+int
+plugin_call_acl_plugin ( Slapi_PBlock *pb, Slapi_Entry *e, char **attrs,
+ struct berval *val, int access , int flags, char **errbuf)
+{
+ struct slapdplugin *p;
+ int rc = LDAP_INSUFFICIENT_ACCESS;
+ int aclplugin_initialized = 0;
+ Operation *operation;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+ /* we don't perform acl check for internal operations and if the plugin has set it not to be checked */
+ if (operation_is_flag_set(operation, SLAPI_OP_FLAG_NO_ACCESS_CHECK|OP_FLAG_INTERNAL|OP_FLAG_REPLICATED|OP_FLAG_LEGACY_REPLICATION_DN))
+ return LDAP_SUCCESS;
+
+ /* call the global plugins first and then the backend specific */
+ for ( p = get_plugin_list(PLUGIN_LIST_ACL); p != NULL; p = p->plg_next ) {
+ if (plugin_invoke_plugin_sdn (p, SLAPI_PLUGIN_ACL_ALLOW_ACCESS, pb,
+ (Slapi_DN*)slapi_entry_get_sdn_const (e))){
+ aclplugin_initialized = 1;
+ rc = (*p->plg_acl_access_allowed)(pb, e, attrs, val, access, flags, errbuf);
+ if ( rc != LDAP_SUCCESS ) break;
+ }
+ }
+
+ if (! aclplugin_initialized ) {
+ rc = acl_default_access ( pb, e, access);
+ }
+ return rc;
+}
+
+int
+plugin_call_acl_mods_access ( Slapi_PBlock *pb, Slapi_Entry *e, LDAPMod **mods, char **errbuf )
+{
+
+ struct slapdplugin *p;
+ int aclplugin_initialized = 0;
+ int rc = LDAP_INSUFFICIENT_ACCESS;
+ Operation *operation;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+ /* we don't perform acl check for internal operations and if the plugin has set it not to be checked */
+ if (operation_is_flag_set(operation, SLAPI_OP_FLAG_NO_ACCESS_CHECK|OP_FLAG_INTERNAL|OP_FLAG_REPLICATED|OP_FLAG_LEGACY_REPLICATION_DN))
+ return LDAP_SUCCESS;
+
+ /* call the global plugins first and then the backend specific */
+ for ( p = get_plugin_list(PLUGIN_LIST_ACL); p != NULL; p = p->plg_next ) {
+ if (plugin_invoke_plugin_sdn (p, SLAPI_PLUGIN_ACL_MODS_ALLOWED, pb,
+ (Slapi_DN*)slapi_entry_get_sdn_const (e))){
+ aclplugin_initialized = 1;
+ rc = (*p->plg_acl_mods_allowed)( pb, e, mods, errbuf );
+ if ( rc != LDAP_SUCCESS ) break;
+ }
+ }
+ if (! aclplugin_initialized ) {
+ rc = acl_default_access ( pb, e, SLAPI_ACL_WRITE);
+ }
+ return rc;
+}
+
+/* This plugin should be called immediatly after the changes have been comitted */
+/* This function is now fully executed for internal and replicated ops. */
+int
+plugin_call_acl_mods_update ( Slapi_PBlock *pb, int optype )
+{
+ struct slapdplugin *p;
+ char *dn;
+ int rc = 0;
+ void *change = NULL;
+ Slapi_Entry *te = NULL;
+ Slapi_DN sdn;
+ Operation *operation;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+ (void)slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn );
+
+ switch ( optype ) {
+ case SLAPI_OPERATION_MODIFY:
+ (void)slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &change );
+ break;
+ case SLAPI_OPERATION_ADD:
+ (void)slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &change );
+ te = (Slapi_Entry *)change;
+ if(!slapi_sdn_isempty(slapi_entry_get_sdn(te)))
+ {
+ dn= (char*)slapi_sdn_get_ndn(slapi_entry_get_sdn(te)); /* jcm - Had to cast away const */
+ }
+ break;
+ case SLAPI_OPERATION_MODRDN:
+ (void)slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &change );
+ break;
+ }
+
+ slapi_sdn_init_dn_byref (&sdn, dn);
+ /* call the global plugins first and then the backend specific */
+ for ( p = get_plugin_list(PLUGIN_LIST_ACL); p != NULL; p = p->plg_next ) {
+ if (plugin_invoke_plugin_sdn (p, SLAPI_PLUGIN_ACL_MODS_UPDATE, pb, &sdn)){
+ rc = (*p->plg_acl_mods_update)(pb, optype, dn, change );
+ if ( rc != LDAP_SUCCESS ) break;
+ }
+ }
+
+ slapi_sdn_done (&sdn);
+ return rc;
+}
+
+int
+plugin_call_acl_verify_syntax ( Slapi_PBlock *pb, Slapi_Entry *e, char **errbuf )
+{
+
+ struct slapdplugin *p;
+ int rc = 0;
+ int plugin_called = 0;
+ Operation *operation;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+ /* we don't perform acl check for internal operations and if the plugin has set it not to be checked */
+ if (operation_is_flag_set(operation, SLAPI_OP_FLAG_NO_ACCESS_CHECK|OP_FLAG_INTERNAL|OP_FLAG_REPLICATED|OP_FLAG_LEGACY_REPLICATION_DN))
+ return LDAP_SUCCESS;
+
+ /* call the global plugins first and then the backend specific */
+ for ( p = get_plugin_list(PLUGIN_LIST_ACL); p != NULL; p = p->plg_next ) {
+ if (plugin_invoke_plugin_sdn (p, SLAPI_PLUGIN_ACL_SYNTAX_CHECK, pb,
+ (Slapi_DN*)slapi_entry_get_sdn_const (e))){
+ plugin_called = 1;
+ rc = (*p->plg_acl_syntax_check)( e, errbuf );
+ if ( rc != LDAP_SUCCESS ) break;
+ }
+ }
+
+ if ( !plugin_called ) {
+ LDAPDebug ( LDAP_DEBUG_ANY, "The ACL plugin is not initialized. The aci syntax cannot be verified\n",0,0,0);
+ }
+ return rc;
+}
+
+int slapi_access_allowed( Slapi_PBlock *pb, Slapi_Entry *e, char *attr,
+ struct berval *val, int access )
+{
+ char *attrs[2] = { NULL, NULL };
+
+ attrs[0] = attr;
+ return ( plugin_call_acl_plugin ( pb, e, attrs, val, access, ACLPLUGIN_ACCESS_DEFAULT, NULL ) );
+}
+
+int slapi_acl_check_mods( Slapi_PBlock *pb, Slapi_Entry *e, LDAPMod **mods, char **errbuf )
+{
+
+ return ( plugin_call_acl_mods_access ( pb, e, mods, errbuf ) );
+
+
+}
+
+int slapi_acl_verify_aci_syntax (Slapi_PBlock *pb, Slapi_Entry *e, char **errbuf)
+{
+ return ( plugin_call_acl_verify_syntax ( pb, e, errbuf ) );
+}
diff --git a/ldap/servers/slapd/plugin_internal_op.c b/ldap/servers/slapd/plugin_internal_op.c
new file mode 100644
index 00000000..63a46e1b
--- /dev/null
+++ b/ldap/servers/slapd/plugin_internal_op.c
@@ -0,0 +1,864 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* stevross@netscape.com June 13 1997 */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include "slapi-plugin.h"
+#include "slap.h"
+
+#if defined(NET_SSL)
+#include <ssl.h>
+#endif
+
+/* entry list node */
+typedef struct Entry_Node{
+ Slapi_Entry *data;
+ struct Entry_Node *next;
+} Entry_Node;
+
+/* referral list node */
+typedef struct Referral_Node{
+ char *data;
+ struct Referral_Node *next;
+} Referral_Node;
+
+/* data that must be passed to slapi_search_internal_callback */
+typedef struct plugin_search_internal_data{
+ int rc;
+ int num_entries;
+ int num_referrals;
+ Entry_Node *entry_list_head;
+ Referral_Node *referral_list_head;
+} plugin_search_internal_data;
+
+/* callback functions */
+typedef struct callback_fn_ptrs{
+ plugin_result_callback p_res_callback;
+ plugin_search_entry_callback p_srch_entry_callback;
+ plugin_referral_entry_callback p_ref_entry_callback;
+ void *callback_data;
+}callback_fn_ptrs;
+
+/* forward declarations */
+static int seq_internal_callback_pb (Slapi_PBlock *pb, void *callback_data,
+ plugin_result_callback prc,
+ plugin_search_entry_callback psec,
+ plugin_referral_entry_callback prec);
+static int search_internal_pb (Slapi_PBlock *pb);
+static int search_internal_callback_pb (Slapi_PBlock *pb, void *callback_data, plugin_result_callback prc,
+ plugin_search_entry_callback psec, plugin_referral_entry_callback prec);
+
+void
+internal_getresult_callback(struct conn *unused1,
+ struct op *op,
+ int err,
+ char *unused2,
+ char *unused3,
+ int unused4,
+ struct berval **unused5)
+{
+
+ if (op != NULL)
+ {
+ *((int *)op->o_handler_data) = err;
+ }
+
+}
+
+void
+internal_res_callback(struct conn *unused1, struct op *op, int err, char *unused2,
+ char *unused3, int unused4, struct berval **unused5)
+{
+ /* make sure the user has a callback defined, if so do it, otherwise do nothing */
+ if( ((callback_fn_ptrs *)op->o_handler_data) != NULL
+ && ((callback_fn_ptrs *)op->o_handler_data)->p_res_callback != NULL
+ )
+ {
+ ((callback_fn_ptrs *)op->o_handler_data)->p_res_callback
+ (err, ((callback_fn_ptrs *)op->o_handler_data)->callback_data);
+ }
+
+}
+
+int
+internal_srch_entry_callback(Slapi_Backend* be, Connection* conn,
+ Operation* op, Slapi_Entry* e)
+{
+ /* make sure the user has a callback defined, if so do it, otherwise do nothing */
+ if( ((callback_fn_ptrs *)op->o_handler_data) != NULL
+ && ((callback_fn_ptrs *)op->o_handler_data)->p_srch_entry_callback != NULL
+ )
+ {
+ return(((callback_fn_ptrs *)op->o_handler_data)->p_srch_entry_callback
+ (e, ((callback_fn_ptrs *)op->o_handler_data)->callback_data));
+ }
+
+ return(0);
+}
+
+int
+internal_ref_entry_callback(Slapi_Backend * be, Connection *conn,
+ Operation *op, struct berval **ireferral)
+{
+
+ int i;
+
+ /* make sure the user has a callback defined, if so do it, otherwise do nothing */
+ if( ((callback_fn_ptrs *)op->o_handler_data) != NULL
+ && ((callback_fn_ptrs *)op->o_handler_data)->p_ref_entry_callback != NULL
+ && ireferral != NULL
+ )
+ {
+ /* loop over referrals calling callback for each one */
+ for(i=0; ireferral[i] != NULL; i++)
+ {
+ ((callback_fn_ptrs *)op->o_handler_data)->p_ref_entry_callback(ireferral[i]->bv_val,
+ ((callback_fn_ptrs *)op->o_handler_data)->callback_data);
+ }
+ }
+ return(0);
+}
+
+Slapi_Operation*
+internal_operation_new(unsigned long op_type, int flags)
+{
+ Slapi_Operation *op= operation_new(flags | OP_FLAG_INTERNAL /*Internal*/);
+ /* set operation type: add, delete, etc */
+ operation_set_type(op,op_type);
+ /* Call the plugin extension constructors */
+ op->o_extension = factory_create_extension(get_operation_object_type(),op,NULL /* Parent */);
+ return op;
+}
+
+/******************************************************************************
+*
+* do_disconnect_server
+*
+*
+*
+*
+*******************************************************************************/
+
+/* this is just a wrapper exposed to the plugins */
+void
+slapi_disconnect_server(Slapi_Connection *conn)
+{
+ do_disconnect_server(conn, conn->c_connid, -1);
+}
+
+static get_disconnect_server_fn_ptr disconnect_server_fn = NULL;
+
+void
+do_disconnect_server(Connection *conn, int opconnid, int opid)
+{
+ if (NULL == disconnect_server_fn) {
+ if (get_entry_point(ENTRY_POINT_DISCONNECT_SERVER, (caddr_t *)(&disconnect_server_fn)) < 0) {
+ return;
+ }
+ }
+ /* It seems that we only call this from result.c when the ber_flush fails. */
+ (disconnect_server_fn)(conn, opconnid, opid, SLAPD_DISCONNECT_BER_FLUSH, 0);
+}
+
+
+/******************************************************************************
+*
+* slapi_compare_internal
+*
+* no plans to implement this, but placeholder incase we change our mind
+*
+*
+*******************************************************************************/
+
+
+Slapi_PBlock *
+slapi_compare_internal(char * dn,
+ char *attr,
+ char *value,
+ LDAPControl **controls)
+{
+ printf("slapi_compare_internal not yet implemented \n");
+ return(0);
+}
+
+int
+slapi_seq_callback( const char *ibase,
+ int type,
+ char *attrname,
+ char *val,
+ char **attrs,
+ int attrsonly,
+ void *callback_data,
+ LDAPControl **controls,
+ plugin_result_callback res_callback,
+ plugin_search_entry_callback srch_callback,
+ plugin_referral_entry_callback ref_callback)
+{
+ int r;
+ Slapi_PBlock pb;
+
+ if (ibase == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_seq_callback: NULL parameter\n");
+ return -1;
+ }
+
+ pblock_init(&pb);
+
+ slapi_seq_internal_set_pb(&pb, (char *)ibase, type, attrname, val, attrs, attrsonly, controls,
+ plugin_get_default_component_id(), 0);
+
+ r= seq_internal_callback_pb (&pb, callback_data, res_callback, srch_callback, ref_callback);
+ pblock_done(&pb);
+ return r;
+}
+
+
+
+/* pblock should contain the following data (can be set via call to slapi_seq_internal_set_pb):
+ SLAPI_SEARCH_TARGET set to search base
+ SAPI_SEQ_TYPE set to sequential access type (SLAPI_SEQ_FIRST, SLAPI_SEQ_NEXT, etc.
+ SLAPI_SEQ_ATTRNAME the next two fields define attribute value assertion
+ SLAPI_SEQ_VAL relative to which access is performed.
+ SLAPI_CONTROLS_ARG set to request controls if present
+ SLAPI_SEARCH_ATTRS set to the list of attributes to return
+ SLAPI_SEARCH_ATTRSONLY tells whether attribute values should be returned.
+ */
+
+int slapi_seq_internal_callback_pb (Slapi_PBlock *pb, void *callback_data, plugin_result_callback res_callback,
+ plugin_search_entry_callback srch_callback,
+ plugin_referral_entry_callback ref_callback)
+{
+ if (pb == NULL)
+ return -1;
+
+ if (!allow_operation (pb))
+ {
+ send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "This plugin is not configured to access operation target data", 0, NULL );
+ return 0;
+ }
+
+ return (seq_internal_callback_pb (pb, callback_data, res_callback, srch_callback, ref_callback));
+}
+
+void slapi_search_internal_set_pb (Slapi_PBlock *pb, const char *base, int scope, const char *filter, char **attrs,
+ int attrsonly, LDAPControl **controls, const char *uniqueid,
+ Slapi_ComponentId *plugin_identity, int operation_flags)
+{
+ Operation *op;
+ if (pb == NULL || base == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_search_internal_set_pb: NULL parameter\n");
+ return;
+ }
+
+ op= internal_operation_new(SLAPI_OPERATION_SEARCH,operation_flags);
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET, (void*)base);
+ slapi_pblock_set(pb, SLAPI_SEARCH_SCOPE, &scope);
+ slapi_pblock_set(pb, SLAPI_SEARCH_STRFILTER, (void*)filter);
+ slapi_pblock_set(pb, SLAPI_CONTROLS_ARG, controls);
+ slapi_pblock_set(pb, SLAPI_SEARCH_ATTRS, attrs);
+ slapi_pblock_set(pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly);
+ if (uniqueid)
+ {
+ slapi_pblock_set(pb, SLAPI_TARGET_UNIQUEID, (void*)uniqueid);
+ }
+ slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, (void*)plugin_identity);
+}
+
+void slapi_seq_internal_set_pb(Slapi_PBlock *pb, char *base, int type, char *attrname, char *val,
+ char **attrs, int attrsonly, LDAPControl **controls,
+ Slapi_ComponentId *plugin_identity, int operation_flags)
+{
+ Operation *op;
+ if (pb == NULL || base == NULL)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, NULL,
+ "slapi_seq_internal_set_pb: NULL parameter\n");
+ return;
+ }
+
+ op= internal_operation_new(SLAPI_OPERATION_SEARCH,operation_flags);
+ slapi_pblock_set(pb, SLAPI_OPERATION, op);
+ slapi_pblock_set(pb, SLAPI_SEARCH_TARGET, base);
+ slapi_pblock_set(pb, SLAPI_SEQ_TYPE, &type);
+ slapi_pblock_set(pb, SLAPI_SEQ_ATTRNAME, attrname);
+ slapi_pblock_set(pb, SLAPI_SEQ_VAL, val);
+ slapi_pblock_set(pb, SLAPI_SEARCH_ATTRS, attrs);
+ slapi_pblock_set(pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly);
+ slapi_pblock_set(pb, SLAPI_CONTROLS_ARG, controls);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_IDENTITY, plugin_identity);
+}
+
+static int seq_internal_callback_pb (Slapi_PBlock *pb, void *callback_data,
+ plugin_result_callback prc,
+ plugin_search_entry_callback psec,
+ plugin_referral_entry_callback prec)
+{
+ int rc;
+ LDAPControl **controls;
+ Operation *op;
+ struct callback_fn_ptrs callback_handler_data;
+ Slapi_Backend *be;
+ Slapi_DN sdn;
+ char *base;
+ char *attrname, *val;
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &base);
+ slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
+
+ if (base == NULL) {
+ slapi_sdn_init_dn_byval(&sdn,"");
+ } else {
+ slapi_sdn_init_dn_byval(&sdn, base);
+ }
+ be = slapi_be_select(&sdn);
+
+ callback_handler_data.p_res_callback = prc;
+ callback_handler_data.p_srch_entry_callback = psec;
+ callback_handler_data.p_ref_entry_callback = prec;
+ callback_handler_data.callback_data = callback_data;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op->o_handler_data = (void *)&callback_handler_data;
+ op->o_result_handler = internal_res_callback;
+ op->o_search_entry_handler = internal_srch_entry_callback;
+ op->o_search_referral_handler = internal_ref_entry_callback;
+
+ /* set target specification of the operation used to decide which plugins are called for the operation */
+ operation_set_target_spec (op, &sdn);
+
+
+ /* Normalize the attribute type and value */
+ slapi_pblock_get (pb, SLAPI_SEQ_ATTRNAME, &attrname);
+ slapi_pblock_get (pb, SLAPI_SEQ_VAL, &val);
+ attrname = slapi_attr_syntax_normalize(attrname);
+ val = ( NULL == val ) ? NULL : slapi_ch_strdup( val );
+
+ slapi_pblock_set(pb, SLAPI_BACKEND, be);
+ slapi_pblock_set(pb, SLAPI_PLUGIN, be->be_database);
+ slapi_pblock_set(pb, SLAPI_SEQ_ATTRNAME, attrname);
+ slapi_pblock_set(pb, SLAPI_SEQ_VAL, val);
+ slapi_pblock_set(pb, SLAPI_REQCONTROLS, controls);
+
+ /* set actions taken to process the operation */
+ set_config_params (pb);
+
+ /* set common parameters */
+ set_common_params (pb);
+
+ if (be->be_seq != NULL)
+ {
+ rc = (*be->be_seq)(pb);
+ }
+ else
+ {
+ send_ldap_result(pb, LDAP_UNWILLING_TO_PERFORM, NULL, "Function not implemented", 0, NULL);
+ rc = 0;
+ }
+
+ slapi_ch_free((void **) &attrname);
+ slapi_ch_free((void **) &val);
+
+ slapi_sdn_done(&sdn);
+
+ return rc;
+}
+
+int
+slapi_search_internal_callback(const char *ibase,
+ int scope,
+ const char *ifstr,
+ char **attrs,
+ int attrsonly,
+ void *callback_data,
+ LDAPControl **controls,
+ plugin_result_callback res_callback,
+ plugin_search_entry_callback srch_callback,
+ plugin_referral_entry_callback ref_callback)
+{
+ Slapi_PBlock pb;
+ int rc = 0;
+
+ pblock_init(&pb);
+
+ slapi_search_internal_set_pb (&pb, ibase, scope, ifstr, attrs, attrsonly,
+ controls, NULL, plugin_get_default_component_id(), 0);
+
+ rc = search_internal_callback_pb (&pb, callback_data, res_callback,
+ srch_callback, ref_callback);
+ pblock_done(&pb);
+ return (rc);
+}
+
+Slapi_PBlock *
+slapi_search_internal(const char *base,
+ int scope,
+ const char *filter,
+ LDAPControl **controls,
+ char **attrs,
+ int attrsonly)
+{
+
+ Slapi_PBlock *pb;
+
+ /* initialize pb */
+ pb = slapi_pblock_new();
+ if (pb)
+ {
+ slapi_search_internal_set_pb (pb, base, scope, filter, attrs, attrsonly, controls,
+ NULL, plugin_get_default_component_id(), 0);
+
+ search_internal_pb (pb);
+ }
+
+ return pb;
+}
+
+/* This function free searchs result or referral set on internal_ops in pblocks */
+void
+slapi_free_search_results_internal(Slapi_PBlock *pb)
+{
+ int i;
+
+ if(pb->pb_plugin_internal_search_op_entries != NULL)
+ {
+ for(i=0; pb->pb_plugin_internal_search_op_entries[i] != NULL; i++)
+ {
+ slapi_entry_free(pb->pb_plugin_internal_search_op_entries[i]);
+ }
+ slapi_ch_free((void**)&(pb->pb_plugin_internal_search_op_entries));
+ }
+
+ /* free v3 referrals made from result handler */
+ if(pb->pb_plugin_internal_search_op_referrals != NULL)
+ {
+ for(i=0; pb->pb_plugin_internal_search_op_referrals[i] != NULL; i++)
+ {
+ slapi_ch_free((void**)&(pb->pb_plugin_internal_search_op_referrals[i]));
+ }
+ slapi_ch_free((void**)&(pb->pb_plugin_internal_search_op_referrals));
+ }
+}
+
+/* this functions can be used for dn as well as uniqueid based operations */
+
+/* pblock should contain the following data (can be set via call to slapi_search_internal_set_pb):
+ For uniqueid based search:
+ SLAPI_TARGET_DN set to dn that allows to select right backend
+ SLAPI_TARGET_UNIQUEID set to the uniqueid of the entry we are looking for
+
+ For dn based search:
+ SLAPI_TARGET_DN set to search base
+ SLAPI_SEARCH_SCOPE set to search scope
+ SLAPI_SEARCH_STRFILTER set to search filter
+ SLAPI_CONTROLS_ARG set to request controls if present
+ SLAPI_SEARCH_ATTRS set to the list of attributes to return
+ SLAPI_SEARCH_ATTRSONLY tells whether attribute values should be returned.
+ */
+int slapi_search_internal_pb (Slapi_PBlock *pb)
+{
+ if (pb == NULL)
+ return -1;
+
+ if (!allow_operation (pb))
+ {
+ slapi_send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "This plugin is not configured to access operation target data", 0, NULL );
+ return 0;
+ }
+
+ return search_internal_pb (pb);
+}
+
+/* pblock should contain the same data as for slapi_search_internal_pb */
+int slapi_search_internal_callback_pb (Slapi_PBlock *pb, void *callback_data,
+ plugin_result_callback prc,
+ plugin_search_entry_callback psec,
+ plugin_referral_entry_callback prec)
+{
+ if (pb == NULL)
+ return -1;
+
+ if (!allow_operation (pb))
+ {
+ send_ldap_result( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "This plugin is not configured to access operation target data", 0, NULL );
+ return 0;
+ }
+
+ return (search_internal_callback_pb (pb, callback_data, prc, psec, prec));
+}
+
+static int
+internal_plugin_search_entry_callback(Slapi_Entry *e, void *callback_data)
+{
+ Entry_Node *this_entry;
+
+ /* add this entry to the list of entries we are making */
+ this_entry = (Entry_Node *)slapi_ch_calloc(1,sizeof(Entry_Node));
+
+ if ((this_entry->data = slapi_entry_dup(e)) == NULL)
+ {
+ return(0);
+ }
+
+ this_entry->next = ((plugin_search_internal_data *) callback_data)->entry_list_head;
+
+ ((plugin_search_internal_data *) callback_data)->entry_list_head = this_entry;
+ ((plugin_search_internal_data *) callback_data)->num_entries++;
+
+ return(0);
+}
+
+static int
+internal_plugin_search_referral_callback(char *referral, void *callback_data)
+{
+ Referral_Node *this_referral;
+
+ /* add this to the list of referrals we are making */
+ this_referral = (Referral_Node *)slapi_ch_calloc(1,sizeof(Referral_Node));
+
+ if ((this_referral->data = slapi_ch_strdup(referral)) == NULL)
+ {
+ return(0);
+ }
+
+ this_referral->next = ((plugin_search_internal_data *) callback_data)->referral_list_head;
+
+ ((plugin_search_internal_data *) callback_data)->referral_list_head = this_referral;
+ ((plugin_search_internal_data *) callback_data)->num_referrals++;
+
+ return(0);
+}
+
+static void internal_plugin_result_callback(int rc, void *callback_data)
+{
+ /* put the result into pb_op_result */
+ ((plugin_search_internal_data *) callback_data)->rc = rc;
+}
+
+static int search_internal_pb (Slapi_PBlock *pb)
+{
+ plugin_search_internal_data psid;
+ Entry_Node *iterator, *tmp;
+ Referral_Node *ref_iterator, *ref_tmp;
+ int i;
+ int opresult = 0;
+ Slapi_Entry **pb_search_entries = NULL;
+ char **pb_search_referrals = NULL;
+ int rc;
+
+ PR_ASSERT (pb);
+
+ /* initialize psid */
+ psid.rc = -1;
+ psid.num_entries =0;
+ psid.num_referrals =0;
+ psid.entry_list_head = NULL;
+ psid.referral_list_head = NULL;
+
+ /* setup additional pb data */
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, pb_search_entries);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_SEARCH_REFERRALS, pb_search_referrals);
+
+ /* call internal search callback, define search_entry_callback, and result_callback such
+ that the results of the search are stuffed into pb */
+ rc = search_internal_callback_pb (pb, &psid, internal_plugin_result_callback,
+ internal_plugin_search_entry_callback,
+ internal_plugin_search_referral_callback);
+ opresult = psid.rc;
+
+ /* stuff search entry pointers from linked list to contiguous array for pblock */
+ pb_search_entries = (Slapi_Entry **)slapi_ch_calloc((psid.num_entries + 1), sizeof(Slapi_Entry *));
+
+ for(i=0,iterator = psid.entry_list_head; iterator !=NULL; iterator=iterator->next, i++)
+ {
+ pb_search_entries[i]= iterator->data;
+ }
+ pb_search_entries[i]=NULL;
+
+ /* free the linked list now that data has been put in the array */
+ iterator=psid.entry_list_head;
+ while(iterator != NULL)
+ {
+ /* free the data held in this node */
+ tmp = iterator;
+ iterator = iterator->next;
+
+ /* free the node */
+ if(tmp != NULL)
+ {
+ slapi_ch_free((void **) &tmp);
+ }
+ }
+ psid.entry_list_head = NULL;
+
+ /* stuff referrals list into an array if we got any to put into the pblock */
+ if(psid.num_referrals != 0)
+ {
+ pb_search_referrals = (char **)slapi_ch_calloc((psid.num_referrals + 1), sizeof(char *));
+
+ for(i=0, ref_iterator = psid.referral_list_head; ref_iterator !=NULL; ref_iterator=ref_iterator->next, i++)
+ {
+ pb_search_referrals[i]= ref_iterator->data;
+ }
+ pb_search_referrals[i]=NULL;
+
+ /* free the linked list now that data has been put in the array */
+ ref_iterator=psid.referral_list_head;
+ while(ref_iterator != NULL)
+ {
+
+ ref_tmp = ref_iterator;
+ ref_iterator = ref_iterator->next;
+
+ /* free the node */
+ if(ref_tmp != NULL)
+ {
+ slapi_ch_free((void **) &ref_tmp);
+ }
+ }
+ psid.referral_list_head = NULL;
+ }
+
+ /* set the result, the array of entries, and the array of referrals in pb */
+ slapi_pblock_set(pb, SLAPI_NENTRIES, &psid.num_entries);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, pb_search_entries);
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_SEARCH_REFERRALS, pb_search_referrals);
+
+ return 0;
+}
+
+static int search_internal_callback_pb (Slapi_PBlock *pb, void *callback_data,
+ plugin_result_callback prc,
+ plugin_search_entry_callback psec,
+ plugin_referral_entry_callback prec)
+{
+ LDAPControl **controls;
+ Operation *op;
+ struct slapi_filter *filter = NULL;
+ char *fstr = NULL;
+ struct callback_fn_ptrs callback_handler_data;
+ int scope;
+ char *ifstr;
+ int opresult;
+ int rc = 0;
+ char *original_base = 0;
+ char *new_base = 0;
+
+ PR_ASSERT (pb);
+
+ /* retrieve search parameters */
+ slapi_pblock_get(pb, SLAPI_SEARCH_SCOPE, &scope);
+ slapi_pblock_get(pb, SLAPI_SEARCH_STRFILTER, &ifstr);
+ slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
+
+ /* data validation */
+ if (ifstr == NULL || (scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL
+ && scope != LDAP_SCOPE_SUBTREE))
+ {
+ opresult = LDAP_PARAM_ERROR;
+ slapi_pblock_set(pb, SLAPI_PLUGIN_INTOP_RESULT, &opresult);
+ return -1;
+ }
+
+ callback_handler_data.p_res_callback = prc;
+ callback_handler_data.p_srch_entry_callback = psec;
+ callback_handler_data.p_ref_entry_callback = prec;
+ callback_handler_data.callback_data = callback_data;
+
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ op->o_handler_data = (void *)&callback_handler_data;
+ op->o_result_handler = internal_res_callback;
+ op->o_search_entry_handler = internal_srch_entry_callback;
+ op->o_search_referral_handler = internal_ref_entry_callback;
+
+ filter = slapi_str2filter(ifstr ? (fstr = slapi_ch_strdup(ifstr)) : "");
+ if(scope == LDAP_SCOPE_BASE) filter->f_flags |= (SLAPI_FILTER_LDAPSUBENTRY | SLAPI_FILTER_TOMBSTONE);
+ if (NULL == filter)
+ {
+ send_ldap_result(pb, LDAP_FILTER_ERROR, NULL, NULL, 0, NULL);
+ rc = -1;
+ goto done;
+ }
+ filter_normalize(filter);
+
+ slapi_pblock_set(pb, SLAPI_SEARCH_FILTER, filter);
+ slapi_pblock_set(pb, SLAPI_REQCONTROLS, controls);
+
+ /* set actions taken to process the operation */
+ set_config_params (pb);
+
+ /* set parameters common for all internal operations */
+ set_common_params (pb);
+ {
+ int timelimit = -1;
+ int sizelimit = -1;
+ int deref = LDAP_DEREF_ALWAYS;
+ slapi_pblock_set(pb, SLAPI_SEARCH_DEREF, &deref);
+ slapi_pblock_set(pb, SLAPI_SEARCH_TIMELIMIT, &timelimit);
+ slapi_pblock_set(pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit);
+ }
+
+ /* plugins which play with the search may
+ * change the search params may allocate
+ * memory so we need to keep track of
+ * changed base search strings
+ */
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &original_base);
+
+ op_shared_search (pb, 1);
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &new_base);
+ slapi_pblock_get(pb, SLAPI_SEARCH_FILTER, &filter);
+
+done:
+ slapi_ch_free((void **) & fstr);
+ if (filter != NULL)
+ {
+ slapi_filter_free(filter, 1 /* recurse */);
+ }
+
+ if(original_base != new_base)
+ slapi_ch_free((void**)new_base);
+
+ return(rc);
+}
+
+/* allow/disallow operation based of the plugin configuration */
+PRBool allow_operation (Slapi_PBlock *pb)
+{
+ char *dn = NULL;
+ struct slapdplugin *plugin = NULL;
+ Slapi_DN sdn;
+ PRBool allow;
+ struct slapi_componentid * cid=NULL;
+
+ PR_ASSERT (pb);
+
+ /* make sure that users of new API provide plugin identity */
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &cid);
+ if (cid == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, NULL, "allow_operation: component identity is NULL\n");
+ return PR_FALSE;
+ }
+ plugin=(struct slapdplugin *) cid->sci_plugin;
+ if (plugin == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, NULL, "allow_operation: plugin identity is NULL\n");
+ return PR_FALSE;
+ }
+
+ slapi_pblock_get (pb, SLAPI_TARGET_DN, &dn);
+ if (dn == NULL) {
+ slapi_sdn_init_dn_byval(&sdn,"");
+ } else {
+ slapi_sdn_init_dn_byval(&sdn, dn);
+ }
+
+ allow = plugin_allow_internal_op (&sdn, plugin);
+
+ slapi_sdn_done (&sdn);
+
+ return allow;
+}
+
+/* set operation configuration based on the plugin configuration */
+void set_config_params (Slapi_PBlock *pb)
+{
+ Slapi_Operation *operation;
+ struct slapdplugin *plugin = NULL;
+ char *dn;
+ struct slapi_componentid * cid=NULL;
+
+ slapi_pblock_get (pb, SLAPI_PLUGIN_IDENTITY, &cid);
+ if (cid)
+ plugin=(struct slapdplugin *) cid->sci_plugin;
+
+ /* set actions */
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ operation_set_flag(operation,plugin_build_operation_action_bitmap(operation->o_flags, plugin));
+
+ /* Check if we have a flag to keep the operation secret */
+ if (operation_is_flag_set(operation, OP_FLAG_ACTION_NOLOG)) {
+ /* Clear the LOG_AUDIT and LOG_CHANGES flag */
+ operation_clear_flag(operation, OP_FLAG_ACTION_LOG_AUDIT | OP_FLAG_ACTION_LOG_CHANGES);
+ }
+
+ /* set name to be used for creator's and modifiers attributes */
+ dn = plugin_get_dn (plugin);
+ if (dn)
+ slapi_sdn_init_dn_passin(&operation->o_sdn, dn);
+}
+
+/* set parameters common for all internal operations */
+void set_common_params (Slapi_PBlock *pb)
+{
+ int isroot = 1;
+ LDAPControl **controls;
+
+ slapi_pblock_get(pb, SLAPI_CONTROLS_ARG, &controls);
+
+ if (NULL != controls)
+ {
+ int managedsait = slapi_control_present(controls,
+ LDAP_CONTROL_MANAGEDSAIT, NULL, NULL);
+ int pwpolicy_ctrl = slapi_control_present(controls,
+ LDAP_X_CONTROL_PWPOLICY_REQUEST, NULL, NULL);
+
+ slapi_pblock_set(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ slapi_pblock_set(pb, SLAPI_PWPOLICY, &pwpolicy_ctrl);
+ }
+
+ slapi_pblock_set(pb, SLAPI_REQUESTOR_ISROOT, &isroot);
+}
+
+
+/*
+ * Given a DN, find an entry by doing an internal search. An LDAP error
+ * code is returned.
+ */
+int
+slapi_search_internal_get_entry( Slapi_DN *dn, char ** attrs, Slapi_Entry **ret_entry , void * component_identity)
+{
+ Slapi_Entry **entries = NULL;
+ Slapi_PBlock *int_search_pb = NULL;
+ int rc = 0;
+
+ *ret_entry = NULL;
+ int_search_pb = slapi_pblock_new ();
+ slapi_search_internal_set_pb ( int_search_pb, slapi_sdn_get_dn(dn), LDAP_SCOPE_BASE, "(|(objectclass=*)(objectclass=ldapsubentry))",
+ attrs ,
+ 0 /* attrsonly */, NULL /* controls */,
+ NULL /* uniqueid */,
+ component_identity, 0 /* actions */ );
+ slapi_search_internal_pb ( int_search_pb );
+ slapi_pblock_get( int_search_pb, SLAPI_PLUGIN_INTOP_RESULT, &rc );
+ if ( LDAP_SUCCESS == rc ) {
+ slapi_pblock_get( int_search_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries );
+ if ( NULL != entries && NULL != entries[ 0 ]) {
+ Slapi_Entry *temp_entry = NULL;
+ temp_entry = entries[ 0 ];
+ *ret_entry = slapi_entry_dup(temp_entry);
+ } else {
+ /* No entry there */
+ rc = LDAP_NO_SUCH_OBJECT;
+ }
+ }
+ slapi_free_search_results_internal(int_search_pb);
+ slapi_pblock_destroy(int_search_pb);
+ int_search_pb = NULL;
+ return rc;
+}
diff --git a/ldap/servers/slapd/plugin_mr.c b/ldap/servers/slapd/plugin_mr.c
new file mode 100644
index 00000000..2579ff64
--- /dev/null
+++ b/ldap/servers/slapd/plugin_mr.c
@@ -0,0 +1,181 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * plugin_mr.c - routines for calling matching rule plugins
+ */
+
+#include "slap.h"
+
+static oid_item_t* global_mr_oids = NULL;
+static PRLock* global_mr_oids_lock = NULL;
+
+static void
+init_global_mr_lock()
+{
+ if(global_mr_oids_lock==NULL)
+ {
+ global_mr_oids_lock = PR_NewLock();
+ }
+}
+
+struct slapdplugin *
+slapi_get_global_mr_plugins()
+{
+ return get_plugin_list(PLUGIN_LIST_MATCHINGRULE);
+}
+
+static struct slapdplugin*
+plugin_mr_find (char* oid)
+{
+ oid_item_t* i;
+ init_global_mr_lock();
+ PR_Lock (global_mr_oids_lock);
+ i = global_mr_oids;
+ PR_Unlock (global_mr_oids_lock);
+ for (; i != NULL; i = i->oi_next)
+ {
+ if (!strcasecmp (oid, i->oi_oid))
+ {
+ LDAPDebug (LDAP_DEBUG_FILTER, "plugin_mr_find(%s) != NULL\n", oid, 0, 0);
+ return i->oi_plugin;
+ }
+ }
+ LDAPDebug (LDAP_DEBUG_FILTER, "plugin_mr_find(%s) == NULL\n", oid, 0, 0);
+ return NULL;
+}
+
+static void
+plugin_mr_bind (char* oid, struct slapdplugin* plugin)
+{
+ oid_item_t* i = (oid_item_t*) slapi_ch_malloc (sizeof (oid_item_t));
+ LDAPDebug (LDAP_DEBUG_FILTER, "=> plugin_mr_bind(%s)\n", oid, 0, 0);
+ init_global_mr_lock();
+ i->oi_oid = slapi_ch_strdup (oid);
+ i->oi_plugin = plugin;
+ PR_Lock (global_mr_oids_lock);
+ i->oi_next = global_mr_oids;
+ global_mr_oids = i;
+ PR_Unlock (global_mr_oids_lock);
+ LDAPDebug (LDAP_DEBUG_FILTER, "<= plugin_mr_bind\n", 0, 0, 0);
+}
+
+int /* an LDAP error code, hopefully LDAP_SUCCESS */
+slapi_mr_indexer_create (Slapi_PBlock* opb)
+{
+ int rc;
+ char* oid;
+ if (!(rc = slapi_pblock_get (opb, SLAPI_PLUGIN_MR_OID, &oid)))
+ {
+ IFP createFn = NULL;
+ struct slapdplugin* mrp = plugin_mr_find (oid);
+ if (mrp != NULL)
+ {
+ if (!(rc = slapi_pblock_set (opb, SLAPI_PLUGIN, mrp)) &&
+ !(rc = slapi_pblock_get (opb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, &createFn)) &&
+ createFn != NULL)
+ {
+ rc = createFn (opb);
+ }
+ }
+ else
+ {
+ /* call each plugin, until one is able to handle this request. */
+ rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ for (mrp = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); mrp != NULL; mrp = mrp->plg_next)
+ {
+ IFP indexFn = NULL;
+ Slapi_PBlock pb;
+ memcpy (&pb, opb, sizeof(Slapi_PBlock));
+ if (!(rc = slapi_pblock_set (&pb, SLAPI_PLUGIN, mrp)) &&
+ !(rc = slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_INDEXER_CREATE_FN, &createFn)) &&
+ createFn != NULL &&
+ !(rc = createFn (&pb)) &&
+ !(rc = slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_INDEX_FN, &indexFn)) &&
+ indexFn != NULL)
+ {
+ /* Success: this plugin can handle it. */
+ memcpy (opb, &pb, sizeof(Slapi_PBlock));
+ plugin_mr_bind (oid, mrp); /* for future reference */
+ break;
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+static int
+attempt_mr_filter_create (mr_filter_t* f, struct slapdplugin* mrp, Slapi_PBlock* pb)
+{
+ int rc;
+ IFP mrf_create = NULL;
+ f->mrf_match = NULL;
+ pblock_init (pb);
+ if (!(rc = slapi_pblock_set (pb, SLAPI_PLUGIN, mrp)) &&
+ !(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_CREATE_FN, &mrf_create)) &&
+ mrf_create != NULL &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_OID, f->mrf_oid)) &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_TYPE, f->mrf_type)) &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_MR_VALUE, &(f->mrf_value))) &&
+ !(rc = mrf_create (pb)) &&
+ !(rc = slapi_pblock_get (pb, SLAPI_PLUGIN_MR_FILTER_MATCH_FN, &(f->mrf_match)))) {
+ if (f->mrf_match == NULL)
+ {
+ rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ }
+ }
+ return rc;
+}
+
+int /* an LDAP error code, hopefully LDAP_SUCCESS */
+plugin_mr_filter_create (mr_filter_t* f)
+{
+ int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ struct slapdplugin* mrp = plugin_mr_find (f->mrf_oid);
+ Slapi_PBlock pb;
+
+ if (mrp != NULL)
+ {
+ rc = attempt_mr_filter_create (f, mrp, &pb);
+ }
+ else
+ {
+ /* call each plugin, until one is able to handle this request. */
+ for (mrp = get_plugin_list(PLUGIN_LIST_MATCHINGRULE); mrp != NULL; mrp = mrp->plg_next)
+ {
+ if (!(rc = attempt_mr_filter_create (f, mrp, &pb)))
+ {
+ plugin_mr_bind (f->mrf_oid, mrp); /* for future reference */
+ break;
+ }
+ }
+ }
+ if (!rc)
+ {
+ /* This plugin has created the desired filter. */
+ f->mrf_plugin = mrp;
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_INDEX_FN, &(f->mrf_index));
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_REUSABLE, &(f->mrf_reusable));
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_MR_FILTER_RESET_FN, &(f->mrf_reset));
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_OBJECT, &(f->mrf_object));
+ slapi_pblock_get (&pb, SLAPI_PLUGIN_DESTROY_FN, &(f->mrf_destroy));
+ }
+ return rc;
+}
+
+int /* an LDAP error code, hopefully LDAP_SUCCESS */
+slapi_mr_filter_index (Slapi_Filter* f, Slapi_PBlock* pb)
+{
+ int rc = LDAP_UNAVAILABLE_CRITICAL_EXTENSION;
+ if (f->f_choice == LDAP_FILTER_EXTENDED && f->f_mr.mrf_index != NULL &&
+ !(rc = slapi_pblock_set (pb, SLAPI_PLUGIN_OBJECT, f->f_mr.mrf_object)))
+ {
+ rc = f->f_mr.mrf_index (pb);
+ }
+ return rc;
+}
+
diff --git a/ldap/servers/slapd/plugin_role.c b/ldap/servers/slapd/plugin_role.c
new file mode 100644
index 00000000..362b08cc
--- /dev/null
+++ b/ldap/servers/slapd/plugin_role.c
@@ -0,0 +1,30 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * plugin_role.c - routines for calling roles plugins
+ */
+
+#include "slap.h"
+
+static roles_check_fn_type roles_check_exported = NULL;
+
+int slapi_role_check(Slapi_Entry *entry_to_check, Slapi_DN *role_dn, int *present)
+{
+ int rc = 0;
+
+ if ( roles_check_exported != NULL )
+ {
+ rc = (roles_check_exported)(entry_to_check, role_dn, present);
+ }
+
+ return rc;
+}
+
+void slapi_register_role_check(roles_check_fn_type check_fn)
+{
+ roles_check_exported = check_fn;
+}
diff --git a/ldap/servers/slapd/plugin_syntax.c b/ldap/servers/slapd/plugin_syntax.c
new file mode 100644
index 00000000..caace965
--- /dev/null
+++ b/ldap/servers/slapd/plugin_syntax.c
@@ -0,0 +1,360 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * plugin_syntax.c - routines for calling syntax plugins
+ */
+
+
+#include "slap.h"
+
+
+struct slapdplugin *
+plugin_syntax_find( const char *nameoroid )
+{
+ struct slapdplugin *pi;
+
+ /* LDAPDebug( LDAP_DEBUG_FILTER, "=> plugin_syntax_find (%s)\n", nameoroid, 0, 0 ); */
+ for ( pi = get_plugin_list(PLUGIN_LIST_SYNTAX); pi != NULL; pi = pi->plg_next ) {
+ if ( charray_inlist( pi->plg_syntax_names, (char *)nameoroid ) ) {
+ break;
+ }
+ }
+ /* LDAPDebug( LDAP_DEBUG_FILTER, "<= plugin_syntax_find %d\n", pi, 0, 0 ); */
+ return ( pi );
+}
+
+
+/*
+ * Enumerate all the syntax plugins, calling (*sef)() for each one.
+ */
+void
+plugin_syntax_enumerate( SyntaxEnumFunc sef, void *arg )
+{
+ struct slapdplugin *pi;
+
+ for ( pi = get_plugin_list(PLUGIN_LIST_SYNTAX); pi != NULL;
+ pi = pi->plg_next ) {
+ (*sef)( pi->plg_syntax_names, &pi->plg_desc, arg );
+ }
+}
+
+
+struct slapdplugin *
+slapi_get_global_syntax_plugins()
+{
+ return get_plugin_list(PLUGIN_LIST_SYNTAX);
+}
+
+char *
+plugin_syntax2oid( struct slapdplugin *pi )
+{
+ return( pi->plg_syntax_oid );
+}
+
+int
+plugin_call_syntax_get_compare_fn(
+ void *vpi,
+ value_compare_fn_type *compare_fn
+)
+{
+ struct slapdplugin *pi = vpi;
+ *compare_fn = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "=> plugin_call_syntax_get_compare_fn\n",0,0, 0 );
+
+ if ( pi == NULL ) {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= plugin_syntax no plugin for attribute type\n",
+ 0, 0, 0 );
+ return( LDAP_PROTOCOL_ERROR ); /* syntax unkonwn */
+ }
+
+ if ( (pi->plg_syntax_flags & SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING) == 0 ) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+
+ if (pi->plg_syntax_filter_ava == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY, "<= plugin_call_syntax_get_compare_fn: "
+ "no filter_ava found for attribute type\n", 0, 0, 0 );
+ return( LDAP_PROTOCOL_ERROR );
+ }
+
+ if (pi->plg_syntax_compare == NULL) {
+ return( LDAP_PROTOCOL_ERROR );
+ }
+
+ *compare_fn = (value_compare_fn_type) pi->plg_syntax_compare;
+
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= plugin_call_syntax_get_compare_fn \n", 0, 0, 0 );
+ return( 0 );
+}
+
+int
+plugin_call_syntax_filter_ava(
+ const Slapi_Attr *a,
+ int ftype,
+ struct ava *ava
+)
+{
+ return(plugin_call_syntax_filter_ava_sv(a,ftype,ava,NULL,0 /*Present*/));
+}
+
+int
+plugin_call_syntax_filter_ava_sv(
+ const Slapi_Attr *a,
+ int ftype,
+ struct ava *ava,
+ Slapi_Value **retVal,
+ int useDeletedValues
+)
+{
+ int rc;
+ Slapi_PBlock pipb;
+
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "=> plugin_call_syntax_filter_ava %s=%s\n", ava->ava_type,
+ ava->ava_value.bv_val, 0 );
+
+ if ( a->a_plugin == NULL ) {
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "<= plugin_syntax no plugin for attr (%s)\n",
+ a->a_type, 0, 0 );
+ return( LDAP_PROTOCOL_ERROR ); /* syntax unkonwn */
+ }
+
+ pblock_init( &pipb );
+ slapi_pblock_set( &pipb, SLAPI_PLUGIN, (void *) a->a_plugin );
+
+ rc = -1; /* does not match by default */
+ switch ( ftype ) {
+ case LDAP_FILTER_GE:
+ case LDAP_FILTER_LE:
+ if ( (a->a_plugin->plg_syntax_flags &
+ SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING) == 0 ) {
+ rc = LDAP_PROTOCOL_ERROR;
+ break;
+ }
+ /* FALL */
+ case LDAP_FILTER_EQUALITY:
+ case LDAP_FILTER_APPROX:
+ if ( a->a_plugin->plg_syntax_filter_ava != NULL )
+ {
+ /* JCM - Maybe the plugin should use the attr value iterator too... */
+ Slapi_Value **va;
+ if(useDeletedValues)
+ va= valueset_get_valuearray(&a->a_deleted_values);
+ else
+ va= valueset_get_valuearray(&a->a_present_values);
+ if(va!=NULL)
+ {
+ rc = a->a_plugin->plg_syntax_filter_ava( &pipb,
+ &ava->ava_value,
+ va,
+ ftype, retVal );
+ }
+ }
+ break;
+ default:
+ LDAPDebug( LDAP_DEBUG_ANY, "plugin_call_syntax_filter: "
+ "unknown filter type %d\n", ftype, 0, 0 );
+ rc = LDAP_PROTOCOL_ERROR;
+ break;
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "<= plugin_call_syntax_filter_ava %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+int
+plugin_call_syntax_filter_sub(
+ Slapi_Attr *a,
+ struct subfilt *fsub
+)
+{
+ return(plugin_call_syntax_filter_sub_sv(a,fsub));
+}
+
+int
+plugin_call_syntax_filter_sub_sv(
+ Slapi_Attr *a,
+ struct subfilt *fsub
+)
+{
+ Slapi_PBlock pipb;
+ int rc;
+
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "=> plugin_call_syntax_filter_sub\n", 0, 0, 0 );
+
+ if ( a->a_plugin == NULL ) {
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "<= plugin_call_syntax_filter no plugin\n", 0, 0, 0 );
+ return( -1 ); /* syntax unkonwn - does not match */
+ }
+
+ if ( a->a_plugin->plg_syntax_filter_sub != NULL )
+ {
+ Slapi_Value **va= valueset_get_valuearray(&a->a_present_values);
+ pblock_init( &pipb );
+ slapi_pblock_set( &pipb, SLAPI_PLUGIN, (void *) a->a_plugin );
+ rc = a->a_plugin->plg_syntax_filter_sub( &pipb,
+ fsub->sf_initial, fsub->sf_any, fsub->sf_final, va);
+ } else {
+ rc = -1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "<= plugin_call_syntax_filter_sub_sv %d\n",
+ rc, 0, 0 );
+ return( rc );
+}
+
+SLAPI_DEPRECATED int
+slapi_call_syntax_values2keys( /* JCM SLOW FUNCTION */
+ void *vpi,
+ struct berval **vals,
+ struct berval ***ivals,
+ int ftype
+)
+{
+ int rc;
+ Slapi_Value **svin= NULL;
+ Slapi_Value **svout= NULL;
+ valuearray_init_bervalarray(vals,&svin); /* JCM SLOW FUNCTION */
+ rc= slapi_call_syntax_values2keys_sv(vpi,svin,&svout,ftype);
+ valuearray_get_bervalarray(svout,ivals); /* JCM SLOW FUNCTION */
+ valuearray_free(&svout);
+ valuearray_free(&svin);
+ return rc;
+}
+
+int
+slapi_call_syntax_values2keys_sv(
+ void *vpi,
+ Slapi_Value **vals,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ int rc;
+ Slapi_PBlock pipb;
+ struct slapdplugin *pi = vpi;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "=> slapi_call_syntax_values2keys\n",
+ 0, 0, 0 );
+
+ pblock_init( &pipb );
+ slapi_pblock_set( &pipb, SLAPI_PLUGIN, vpi );
+
+ *ivals = NULL;
+ rc = -1; /* means no values2keys function */
+ if ( pi != NULL && pi->plg_syntax_values2keys != NULL ) {
+ rc = pi->plg_syntax_values2keys( &pipb, vals, ivals, ftype );
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "<= slapi_call_syntax_values2keys %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+SLAPI_DEPRECATED int
+slapi_call_syntax_assertion2keys_ava( /* JCM SLOW FUNCTION */
+ void *vpi,
+ struct berval *val,
+ struct berval ***ivals,
+ int ftype
+)
+{
+ int rc;
+ Slapi_Value svin;
+ Slapi_Value **svout= NULL;
+ slapi_value_init_berval(&svin, val);
+ rc= slapi_call_syntax_assertion2keys_ava_sv(vpi,&svin,&svout,ftype);
+ valuearray_get_bervalarray(svout,ivals); /* JCM SLOW FUNCTION */
+ valuearray_free(&svout);
+ value_done(&svin);
+ return rc;
+}
+
+SLAPI_DEPRECATED int
+slapi_call_syntax_assertion2keys_ava_sv(
+ void *vpi,
+ Slapi_Value *val,
+ Slapi_Value ***ivals,
+ int ftype
+)
+{
+ int rc;
+ Slapi_PBlock pipb;
+ struct slapdplugin *pi = vpi;
+
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "=> slapi_call_syntax_assertion2keys_ava\n", 0, 0, 0 );
+
+ pblock_init( &pipb );
+ slapi_pblock_set( &pipb, SLAPI_PLUGIN, vpi );
+
+ rc = -1; /* means no assertion2keys function */
+ if ( pi->plg_syntax_assertion2keys_ava != NULL ) {
+ rc = pi->plg_syntax_assertion2keys_ava( &pipb, val, ivals, ftype );
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "<= slapi_call_syntax_assertion2keys_ava %d\n", rc, 0, 0 );
+ return( rc );
+}
+
+SLAPI_DEPRECATED int
+slapi_call_syntax_assertion2keys_sub( /* JCM SLOW FUNCTION */
+ void *vpi,
+ char *initial,
+ char **any,
+ char *final,
+ struct berval ***ivals
+)
+{
+ int rc;
+ Slapi_Value **svout= NULL;
+ rc= slapi_call_syntax_assertion2keys_sub_sv(vpi,initial,any,final,&svout);
+ valuearray_get_bervalarray(svout,ivals); /* JCM SLOW FUNCTION */
+ valuearray_free(&svout);
+ return rc;
+}
+
+int
+slapi_call_syntax_assertion2keys_sub_sv(
+ void *vpi,
+ char *initial,
+ char **any,
+ char *final,
+ Slapi_Value ***ivals
+)
+{
+ int rc;
+ Slapi_PBlock pipb;
+ struct slapdplugin *pi = vpi;
+
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "=> slapi_call_syntax_assertion2keys_sub\n", 0, 0, 0 );
+
+ pblock_init( &pipb );
+ slapi_pblock_set( &pipb, SLAPI_PLUGIN, vpi );
+
+ rc = -1; /* means no assertion2keys function */
+ *ivals = NULL;
+ if ( pi->plg_syntax_assertion2keys_sub != NULL ) {
+ rc = pi->plg_syntax_assertion2keys_sub( &pipb, initial, any,
+ final, ivals );
+ }
+
+ LDAPDebug( LDAP_DEBUG_FILTER,
+ "<= slapi_call_syntax_assertion2keys_sub %d\n", rc, 0, 0 );
+ return( rc );
+}
+
diff --git a/ldap/servers/slapd/poll_using_select.c b/ldap/servers/slapd/poll_using_select.c
new file mode 100644
index 00000000..5c25a57b
--- /dev/null
+++ b/ldap/servers/slapd/poll_using_select.c
@@ -0,0 +1,122 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * poll_using_select.c
+ *
+ * poll_using_select() is an implementation of poll using select.
+ * I borrowed this code from the client source, ns/nspr/src/mdunix.c
+ * from the Nav404_OEM_BRANCH
+ *
+ * The reason we need this is on Linux 2.0 (and possibly other platforms)
+ * there is no poll. ldapserver/ldap/servers/slapd/daemon.c calls poll
+ *
+ * In Linux 2.1 there will be a native poll, so this will go away for Linux
+ * but other platforms may need it.
+ *
+ * 1-30-98
+ * sspitzer
+ */
+#include "poll_using_select.h"
+
+int
+poll_using_select(struct my_pollfd *filed, int nfds, int timeout)
+{
+ int width;
+ fd_set rd;
+ fd_set wr;
+ fd_set ex;
+ struct timeval tv;
+ int a, b, retval;
+
+#ifdef DEBUG_POLL_AS_SELECT
+ LDAPDebug(LDAP_DEBUG_ANY, "poll convert nfds=%d, timeout=%d\n", nfds, timeout,0);
+#endif /* DEBUG_POLL_AS_SELECT */
+
+ FD_ZERO( &rd );
+ FD_ZERO( &wr );
+ FD_ZERO( &ex );
+
+ /*
+ * If the fd member of all pollfd structures is less than 0,
+ * the poll() function will return 0 and have no other results.
+ */
+ for(a=0, b=0; a<nfds; a++){
+ if( filed[a].fd >= 0 ) b++;
+ }
+ if( b == 0 ){ return 0; }
+
+ for( width=0,a=0; a<nfds; a++ ){
+ short temp_events;
+
+#ifdef DEBUG_POLL_AS_SELECT
+ if (filed[a].events != 0) {
+ LDAPDebug(LDAP_DEBUG_ANY, "poll events = %d for fd=%d\n", filed[a].events, filed[a].fd,0);
+ }
+#endif /* DEBUG_POLL_AS_SELECT */
+
+ temp_events = filed[a].events;
+
+ filed[a].revents = 0;
+
+ if( temp_events & POLLIN ) FD_SET( filed[a].fd, &rd );
+ if( temp_events & POLLOUT ) FD_SET( filed[a].fd, &wr );
+ if( temp_events & POLLPRI ) FD_SET( filed[a].fd, &ex );
+
+ temp_events &= ~(POLLIN|POLLOUT|POLLPRI);
+
+#ifdef DEBUG_POLL_AS_SELECT
+ if( temp_events != 0 ){
+ LDAPDebug(LDAP_DEBUG_ANY, "Unhandled poll event type=0x%x on FD(%d)\n",filed[a].events,filed[a].fd,0);
+ }
+#endif /* DEBUG_POLL_AS_SELECT */
+
+ width = width>(filed[a].fd+1)?width:(filed[a].fd+1);
+ }
+
+ if( timeout != -1 ){
+ tv.tv_sec = timeout/MSECONDS;
+ tv.tv_usec= timeout%MSECONDS;
+
+ retval = select ( width, &rd, &wr, &ex, &tv );
+ }
+ else
+ {
+ retval = select ( width, &rd, &wr, &ex, 0 );
+ }
+
+ if( retval <= 0 ) return( retval );
+
+#ifdef DEBUG_POLL_AS_SELECT
+ LDAPDebug(LDAP_DEBUG_ANY, "For\n",0,0,0);
+#endif /* DEBUG_POLL_AS_SELECT */
+
+ for( b=0; b<nfds;b++){
+
+ if( filed[b].fd >= 0 ){
+ a = filed[b].fd;
+
+ if( FD_ISSET( a, &rd )) filed[b].revents |= POLLIN;
+ if( FD_ISSET( a, &wr )) filed[b].revents |= POLLOUT;
+ if( FD_ISSET( a, &ex )) filed[b].revents |= POLLPRI;
+
+#ifdef DEBUG_POLL_AS_SELECT
+ if ((filed[b].events != 0) || (filed[b].revents != 0)) {
+ LDAPDebug(LDAP_DEBUG_ANY, " file des=%d, events=0x%x, revents=0x%x\n", filed[b].fd, filed[b].events ,filed[b].revents);
+ }
+#endif /* DEBUG_POLL_AS_SELECT */
+ }
+ }
+
+ for( a=0, retval=0 ; a<nfds; a++ ){
+ if( filed[a].revents ) retval++;
+ }
+
+#ifdef DEBUG_POLL_AS_SELECT
+ LDAPDebug(LDAP_DEBUG_ANY, "poll returns %d (converted poll)\n",retval,0,0);
+#endif /* DEBUG_POLL_AS_SELECT */
+
+ return( retval );
+}
diff --git a/ldap/servers/slapd/poll_using_select.h b/ldap/servers/slapd/poll_using_select.h
new file mode 100644
index 00000000..de117729
--- /dev/null
+++ b/ldap/servers/slapd/poll_using_select.h
@@ -0,0 +1,43 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _POLL_USING_SELECT_H
+#define _POLL_USING_SELECT_H
+
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include "slap.h"
+
+/* uncomment for debugging info
+#define DEBUG_POLL_AS_SELECT
+*/
+#define MSECONDS 1000
+
+struct my_pollfd {
+ int fd;
+ short events;
+ short revents;
+};
+
+/* poll events */
+
+#define POLLIN 0x0001 /* fd is readable */
+#define POLLPRI 0x0002 /* high priority info at fd */
+#define POLLOUT 0x0004 /* fd is writeable (won't block) */
+#define POLLRDNORM 0x0040 /* normal data is readable */
+#define POLLWRNORM POLLOUT
+#define POLLRDBAND 0x0080 /* out-of-band data is readable */
+#define POLLWRBAND 0x0100 /* out-of-band data is writeable */
+
+#define POLLNORM POLLRDNORM
+
+#define POLLERR 0x0008 /* fd has error condition */
+#define POLLHUP 0x0010 /* fd has been hung up on */
+#define POLLNVAL 0x0020 /* invalid pollfd entry */
+
+int poll_using_select(struct my_pollfd *filedes, int nfds, int timeout);
+
+#endif /* _POLL_USING_SELECT_H */
diff --git a/ldap/servers/slapd/prerrstrs.h b/ldap/servers/slapd/prerrstrs.h
new file mode 100644
index 00000000..3f34f277
--- /dev/null
+++ b/ldap/servers/slapd/prerrstrs.h
@@ -0,0 +1,121 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * pserrstrs.h - map NSPR errors to strings (used by errormap.c)
+ *
+ */
+
+/*
+ ****************************************************************************
+ * The code below this point was provided by Nelson Bolyard <nelsonb> of the
+ * Netscape Certificate Server team on 27-March-1998.
+ * Taken from the file ns/security/cmd/lib/NSPRerrs.h on NSS_1_BRANCH.
+ * Last updated from there: 24-July-1998 by Mark Smith <mcs>
+ *
+ * All of the Directory Server specific changes are enclosed inside
+ * #ifdef NS_DS.
+ ****************************************************************************
+ */
+/* General NSPR 2.0 errors */
+/* Caller must #include "prerror.h" */
+
+ER2( PR_OUT_OF_MEMORY_ERROR, "Memory allocation attempt failed." )
+ER2( PR_BAD_DESCRIPTOR_ERROR, "Invalid file descriptor." )
+ER2( PR_WOULD_BLOCK_ERROR, "The operation would have blocked." )
+ER2( PR_ACCESS_FAULT_ERROR, "Invalid memory address argument." )
+ER2( PR_INVALID_METHOD_ERROR, "Invalid function for file type." )
+ER2( PR_ILLEGAL_ACCESS_ERROR, "Invalid memory address argument." )
+ER2( PR_UNKNOWN_ERROR, "Some unknown error has occurred." )
+ER2( PR_PENDING_INTERRUPT_ERROR,"Operation interrupted by another thread." )
+ER2( PR_NOT_IMPLEMENTED_ERROR, "function not implemented." )
+ER2( PR_IO_ERROR, "I/O function error." )
+ER2( PR_IO_TIMEOUT_ERROR, "I/O operation timed out." )
+ER2( PR_IO_PENDING_ERROR, "I/O operation on busy file descriptor." )
+ER2( PR_DIRECTORY_OPEN_ERROR, "The directory could not be opened." )
+ER2( PR_INVALID_ARGUMENT_ERROR, "Invalid function argument." )
+ER2( PR_ADDRESS_NOT_AVAILABLE_ERROR, "Network address not available (in use?)." )
+ER2( PR_ADDRESS_NOT_SUPPORTED_ERROR, "Network address type not supported." )
+ER2( PR_IS_CONNECTED_ERROR, "Already connected." )
+ER2( PR_BAD_ADDRESS_ERROR, "Network address is invalid." )
+ER2( PR_ADDRESS_IN_USE_ERROR, "Local Network address is in use." )
+ER2( PR_CONNECT_REFUSED_ERROR, "Connection refused by peer." )
+ER2( PR_NETWORK_UNREACHABLE_ERROR, "Network address is presently unreachable." )
+ER2( PR_CONNECT_TIMEOUT_ERROR, "Connection attempt timed out." )
+ER2( PR_NOT_CONNECTED_ERROR, "Network file descriptor is not connected." )
+ER2( PR_LOAD_LIBRARY_ERROR, "Failure to load dynamic library." )
+ER2( PR_UNLOAD_LIBRARY_ERROR, "Failure to unload dynamic library." )
+ER2( PR_FIND_SYMBOL_ERROR,
+"Symbol not found in any of the loaded dynamic libraries." )
+ER2( PR_INSUFFICIENT_RESOURCES_ERROR, "Insufficient system resources." )
+ER2( PR_DIRECTORY_LOOKUP_ERROR,
+"A directory lookup on a network address has failed." )
+ER2( PR_TPD_RANGE_ERROR,
+"Attempt to access a TPD key that is out of range." )
+ER2( PR_PROC_DESC_TABLE_FULL_ERROR, "Process open FD table is full." )
+ER2( PR_SYS_DESC_TABLE_FULL_ERROR, "System open FD table is full." )
+ER2( PR_NOT_SOCKET_ERROR,
+"Network operation attempted on non-network file descriptor." )
+ER2( PR_NOT_TCP_SOCKET_ERROR,
+"TCP-specific function attempted on a non-TCP file descriptor." )
+ER2( PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "TCP file descriptor is already bound." )
+ER2( PR_NO_ACCESS_RIGHTS_ERROR, "Access Denied." )
+ER2( PR_OPERATION_NOT_SUPPORTED_ERROR,
+"The requested operation is not supported by the platform." )
+ER2( PR_PROTOCOL_NOT_SUPPORTED_ERROR,
+"The host operating system does not support the protocol requested." )
+ER2( PR_REMOTE_FILE_ERROR, "Access to the remote file has been severed." )
+ER2( PR_BUFFER_OVERFLOW_ERROR,
+"The value requested is too large to be stored in the data buffer provided." )
+ER2( PR_CONNECT_RESET_ERROR, "TCP connection reset by peer." )
+ER2( PR_RANGE_ERROR, "Unused." )
+ER2( PR_DEADLOCK_ERROR, "The operation would have deadlocked." )
+ER2( PR_FILE_IS_LOCKED_ERROR, "The file is already locked." )
+ER2( PR_FILE_TOO_BIG_ERROR,
+"Write would result in file larger than the system allows." )
+ER2( PR_NO_DEVICE_SPACE_ERROR, "The device for storing the file is full." )
+ER2( PR_PIPE_ERROR, "Unused." )
+ER2( PR_NO_SEEK_DEVICE_ERROR, "Unused." )
+ER2( PR_IS_DIRECTORY_ERROR,
+"Cannot perform a normal file operation on a directory." )
+ER2( PR_LOOP_ERROR, "Symbolic link loop." )
+ER2( PR_NAME_TOO_LONG_ERROR, "File name is too long." )
+ER2( PR_FILE_NOT_FOUND_ERROR, "File not found." )
+ER2( PR_NOT_DIRECTORY_ERROR,
+"Cannot perform directory operation on a normal file." )
+ER2( PR_READ_ONLY_FILESYSTEM_ERROR,
+"Cannot write to a read-only file system." )
+ER2( PR_DIRECTORY_NOT_EMPTY_ERROR,
+"Cannot delete a directory that is not empty." )
+ER2( PR_FILESYSTEM_MOUNTED_ERROR,
+"Cannot delete or rename a file object while the file system is busy." )
+ER2( PR_NOT_SAME_DEVICE_ERROR,
+"Cannot rename a file to a file system on another device." )
+ER2( PR_DIRECTORY_CORRUPTED_ERROR,
+"The directory object in the file system is corrupted." )
+ER2( PR_FILE_EXISTS_ERROR,
+"Cannot create or rename a filename that already exists." )
+ER2( PR_MAX_DIRECTORY_ENTRIES_ERROR,
+"Directory is full. No additional filenames may be added." )
+ER2( PR_INVALID_DEVICE_STATE_ERROR,
+"The required device was in an invalid state." )
+ER2( PR_DEVICE_IS_LOCKED_ERROR, "The device is locked." )
+ER2( PR_NO_MORE_FILES_ERROR, "No more entries in the directory." )
+ER2( PR_END_OF_FILE_ERROR, "Encountered end of file." )
+ER2( PR_FILE_SEEK_ERROR, "Seek error." )
+ER2( PR_FILE_IS_BUSY_ERROR, "The file is busy." )
+ER2( PR_OPERATION_ABORTED_ERROR, "The I/O operation was aborted" )
+ER2( PR_IN_PROGRESS_ERROR,
+"Operation is still in progress (probably a non-blocking connect)." )
+ER2( PR_ALREADY_INITIATED_ERROR,
+"Operation has already been initiated (probably a non-blocking connect)." )
+ER2( PR_GROUP_EMPTY_ERROR, "The wait group is empty." )
+ER2( PR_INVALID_STATE_ERROR, "Object state improper for request." )
+ER2( PR_NETWORK_DOWN_ERROR, "Network is down" )
+ER2( PR_SOCKET_SHUTDOWN_ERROR, "Socket shutdown" )
+ER2( PR_CONNECT_ABORTED_ERROR, "Connection aborted" )
+ER2( PR_HOST_UNREACHABLE_ERROR, "Host is unreachable" )
+
+ER2( PR_MAX_ERROR, "Placeholder for the end of the list" )
diff --git a/ldap/servers/slapd/protect_db.c b/ldap/servers/slapd/protect_db.c
new file mode 100644
index 00000000..34a63e80
--- /dev/null
+++ b/ldap/servers/slapd/protect_db.c
@@ -0,0 +1,758 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* protect_db.c
+ * Used to police access to the db. Prevents different instances of
+ * slapd from clobbering each other
+ */
+
+
+
+#ifndef _WIN32
+
+#define LOCK_DIR "locks"
+#define LOCK_FILE "lock"
+#define IMPORT_DIR "imports"
+#define EXPORT_DIR "exports"
+#define SERVER_DIR "server"
+#define NUM_TRIES 20
+#define WAIT_TIME 250
+
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <fcntl.h> /* open */
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include <sys/param.h> /* MAXPATHLEN */
+#include <dirent.h>
+#include <pwd.h>
+#endif
+
+#include "protect_db.h"
+
+#include "slap.h"
+
+
+#ifndef _WIN32
+/* This is the unix version of the code to protect the db. */
+
+static int
+grab_lockfile()
+{
+ pid_t pid, owning_pid;
+ char lockfile[MAXPATHLEN];
+ int fd, x;
+ int removed_lockfile = 0;
+ struct timeval t;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+
+ /* Don't use anything that makes a NSPR call here (like LDAPDebug)! This function
+ gets called by an atexit function, and NSPR is long gone by then. */
+
+ /* Get the name of the lockfile */
+ sprintf(lockfile, "%s/%s", slapdFrontendConfig->instancedir, LOCK_FILE);
+ /* Get our pid */
+ pid = getpid();
+
+ /* Try to grab it */
+ if ((fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0664)) != -1) {
+ /* We got the lock, write our pid to the file */
+ write(fd, (void *) &pid, sizeof(pid_t));
+ close(fd);
+ return 0;
+ }
+
+ /* We weren't able to get the lock. Find out why. */
+ if (errno != EEXIST) {
+ /* Hmm, something happened that we weren't prepared to handle */
+ fprintf(stderr, ERROR_ACCESSING_LOCKFILE, lockfile);
+ return -1;
+ }
+
+ while(1) {
+ /* Try to grab the lockfile NUM_TRIES times waiting WAIT_TIME milliseconds after each try */
+ t.tv_sec = 0;
+ t.tv_usec = WAIT_TIME * 1000;
+ for(x = 0; x < NUM_TRIES; x++) {
+ if ((fd = open(lockfile, O_RDWR | O_CREAT | O_EXCL)) != -1) {
+ /* Got the lock */
+ write(fd, (void *) &pid, sizeof(pid_t));
+ close(fd);
+ return 0;
+ }
+ select(0, NULL, NULL, NULL, &t);
+ }
+
+ /* We still haven't got the lockfile. Find out who owns it and see if they are still up */
+ if ((fd = open(lockfile, O_RDONLY)) != -1) {
+ size_t nb_bytes=0;
+
+ nb_bytes = read(fd, (void *) &owning_pid, sizeof(pid_t));
+ if ( (nb_bytes != (size_t)(sizeof(pid_t)) ) || (owning_pid == 0) || (kill(owning_pid, 0) != 0 && errno == ESRCH) ) {
+ /* The process that owns the lock is dead. Try to remove the old lockfile. */
+ if (unlink(lockfile) != 0) {
+ /* Unable to remove the stale lockfile. */
+ fprintf(stderr, LOCKFILE_DEAD_OWNER, lockfile, owning_pid);
+ return -1;
+ }
+ if (removed_lockfile) {
+ /* We already removed the lockfile once. Best thing to do is give up. */
+ /* I'm not sure what should be given as an error here */
+ fprintf(stderr, UNABLE_TO_GET_LOCKFILE, lockfile);
+ return -1;
+ } else {
+ removed_lockfile = 1;
+ }
+ } else {
+ /* It looks like the owner of the lockfile is still up and running. */
+ fprintf(stderr, LOCKFILE_ALREADY_OWNED, owning_pid);
+ return -1;
+ }
+ }
+ }
+}
+
+static void
+release_lockfile()
+{
+ char lockfile[MAXPATHLEN];
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ /* This function assumes that the caller owns the lock, it doesn't check to make sure! */
+
+ sprintf(lockfile, "%s/%s", slapdFrontendConfig->instancedir, LOCK_FILE);
+ unlink(lockfile);
+}
+
+
+/* Takes the pid of a process. Returns 1 if the process seems
+ * to be up, otherwise it returns 0.
+ */
+static int
+is_process_up(pid_t pid)
+{
+ if (kill(pid, 0) == -1 && errno == ESRCH) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+/* Make sure the directory 'dir' exists and is owned bye the user
+ * the server runs as. Returns 0 if everything is ok.
+ */
+static int
+make_sure_dir_exists(char *dir)
+{
+ struct passwd* pw;
+ struct stat stat_buffer;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ /* Make sure it exists */
+ if (PR_MkDir(dir, 0755) != PR_SUCCESS) {
+ PRErrorCode prerr = PR_GetError();
+ if (prerr != PR_FILE_EXISTS_ERROR) {
+ LDAPDebug(LDAP_DEBUG_ANY, FILE_CREATE_ERROR, dir, prerr, slapd_pr_strerror(prerr));
+ return 1;
+ }
+ }
+
+ /* Make sure it's owned by the correct user */
+ if (slapdFrontendConfig->localuser != NULL) {
+ if ( (pw = getpwnam(slapdFrontendConfig->localuser)) == NULL ) {
+ LDAPDebug(LDAP_DEBUG_ANY, GETPWNAM_WARNING, slapdFrontendConfig->localuser, errno, strerror(errno));
+ } else {
+ if (chown(dir, pw->pw_uid, -1) == -1) {
+ stat(dir, &stat_buffer);
+ if (stat_buffer.st_uid != pw->pw_uid) {
+ LDAPDebug(LDAP_DEBUG_ANY, CHOWN_WARNING, dir, 0, 0);
+ }
+ }
+ } /* else */
+ }
+
+ return 0;
+}
+
+/* Creates a file in the directory 'dir_name' whose name is the
+ * pid for this process.
+ */
+static void
+add_this_process_to(char *dir_name)
+{
+ char file_name[MAXPATHLEN];
+ struct passwd* pw;
+ struct stat stat_buffer;
+ PRFileDesc* prfd;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ sprintf(file_name, "%s/%d", dir_name, getpid());
+
+ if ((prfd = PR_Open(file_name, PR_RDWR | PR_CREATE_FILE, 0666)) == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, FILE_CREATE_WARNING, file_name, 0, 0);
+ return;
+ }
+
+ /* Make sure the owner is of the file is the user the server
+ * runs as. */
+ if (slapdFrontendConfig->localuser != NULL) {
+ if ( (pw = getpwnam(slapdFrontendConfig->localuser)) == NULL ) {
+ LDAPDebug(LDAP_DEBUG_ANY, GETPWNAM_WARNING, slapdFrontendConfig->localuser, errno, strerror(errno));
+ } else {
+ if (chown(file_name, pw->pw_uid, -1) == -1) {
+ stat(file_name, &stat_buffer);
+ if (stat_buffer.st_uid != pw->pw_uid) {
+ LDAPDebug(LDAP_DEBUG_ANY, CHOWN_WARNING, file_name, 0, 0);
+ }
+ }
+ } /* else */
+ }
+ PR_Close(prfd);
+}
+
+
+/* The directory 'dir_name' is expected to contain files whose
+ * names are the pid of running slapd processes. This
+ * function will check each entry in the directory and remove
+ * any files that represent processes that don't exist.
+ * Returns 0 if there are no processes represented, or
+ * the pid of one of the processes.
+ */
+static long
+sample_and_update(char *dir_name)
+{
+ PRDir *dir;
+ PRDirEntry *entry;
+ pid_t pid;
+ long result = 0;
+ char *endp;
+ char file_name[MAXPATHLEN];
+
+ if ((dir = PR_OpenDir(dir_name)) == NULL) {
+ return 0;
+ }
+
+ while((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) {
+ pid = (pid_t) strtol(entry->name, &endp, 0);
+ if (*endp != '\0') {
+ /* not quite sure what this file was, but we
+ * didn't put it there */
+ continue;
+ }
+ if (is_process_up(pid)) {
+ result = (long) pid;
+ } else {
+ sprintf(file_name, "%s/%s", dir_name, entry->name);
+ PR_Delete(file_name);
+ }
+ }
+ PR_CloseDir(dir);
+ return result;
+}
+
+
+/* Removes any stale pid entries and the pid entry for this
+ * process from the directory 'dir_name'.
+ */
+static void
+remove_and_update(char *dir_name)
+{
+ /* since this is called from an atexit function, we can't use
+ * NSPR. */
+
+ DIR *dir;
+ struct dirent *entry;
+ pid_t pid;
+ pid_t our_pid;
+ char *endp;
+ char file_name[MAXPATHLEN];
+
+ /* get our pid */
+ our_pid = getpid();
+
+ if ((dir = opendir(dir_name)) == NULL) {
+ return;
+ }
+
+ while((entry = readdir(dir)) != NULL) {
+
+ /* skip dot and dot-dot */
+ if (strcmp(entry->d_name, ".") == 0 ||
+ strcmp(entry->d_name, "..") == 0)
+ continue;
+
+ pid = (pid_t) strtol(entry->d_name, &endp, 0);
+ if (*endp != '\0') {
+ /* not quite sure what this file was, but we
+ * didn't put it there */
+ continue;
+ }
+ if (!is_process_up(pid) || pid == our_pid) {
+ sprintf(file_name, "%s/%s", dir_name, entry->d_name);
+ unlink(file_name);
+ }
+ }
+ closedir(dir);
+}
+
+
+
+/* Walks through all the pid directories and clears any stale
+ * pids. It also removes the files for this process.
+ */
+void
+remove_slapd_process()
+{
+ char lock_dir[MAXPATHLEN];
+ char import_dir[MAXPATHLEN];
+ char export_dir[MAXPATHLEN];
+ char server_dir[MAXPATHLEN];
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+
+ /* Create the name of the directories that hold the pids of the currently running
+ * ns-slapd processes */
+ sprintf(lock_dir, "%s/%s", slapdFrontendConfig->instancedir, LOCK_DIR);
+ sprintf(import_dir, "%s/%s/%s", slapdFrontendConfig->instancedir, LOCK_DIR, IMPORT_DIR);
+ sprintf(export_dir, "%s/%s/%s", slapdFrontendConfig->instancedir, LOCK_DIR, EXPORT_DIR);
+ sprintf(server_dir, "%s/%s/%s", slapdFrontendConfig->instancedir, LOCK_DIR, SERVER_DIR);
+
+ /* Grab the lockfile */
+ if (grab_lockfile() != 0) {
+ /* Unable to grab the lockfile */
+ return;
+ }
+
+
+ remove_and_update(import_dir);
+ remove_and_update(export_dir);
+ remove_and_update(server_dir);
+
+ release_lockfile();
+}
+
+int
+add_new_slapd_process(int exec_mode, int r_flag, int skip_flag)
+{
+ char lock_dir[MAXPATHLEN];
+ char import_dir[MAXPATHLEN];
+ char export_dir[MAXPATHLEN];
+ char server_dir[MAXPATHLEN];
+ int running, importing, exporting;
+ int result = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if (skip_flag) {
+ return 0;
+ }
+
+ /* Create the name of the directories that hold the pids of the currently running
+ * ns-slapd processes */
+ sprintf(lock_dir, "%s/%s", slapdFrontendConfig->instancedir, LOCK_DIR);
+ sprintf(import_dir, "%s/%s/%s", slapdFrontendConfig->instancedir, LOCK_DIR, IMPORT_DIR);
+ sprintf(export_dir, "%s/%s/%s", slapdFrontendConfig->instancedir, LOCK_DIR, EXPORT_DIR);
+ sprintf(server_dir, "%s/%s/%s", slapdFrontendConfig->instancedir, LOCK_DIR, SERVER_DIR);
+
+ /* Grab the lockfile */
+ if (grab_lockfile() != 0) {
+ /* Unable to grab the lockfile */
+ return -1;
+ }
+
+ /* Make sure the directories exist */
+ if (make_sure_dir_exists(lock_dir) != 0 ||
+ make_sure_dir_exists(import_dir) != 0 ||
+ make_sure_dir_exists(export_dir) != 0 ||
+ make_sure_dir_exists(server_dir) != 0) {
+ release_lockfile();
+ return -1;
+ }
+
+ /* Go through the directories and find out what's going on.
+ * Clear any stale pids encountered. */
+ importing = sample_and_update(import_dir);
+ exporting = sample_and_update(export_dir);
+ running = sample_and_update(server_dir);
+
+ switch (exec_mode) {
+ case SLAPD_EXEMODE_SLAPD:
+ if (running) {
+ result = -1;
+ LDAPDebug(LDAP_DEBUG_ANY, NO_SERVER_DUE_TO_SERVER, running, 0, 0);
+ } else if (importing) {
+ result = -1;
+ LDAPDebug(LDAP_DEBUG_ANY, NO_SERVER_DUE_TO_IMPORT, importing, 0, 0);
+ } else {
+ add_this_process_to(server_dir);
+ result = 0;
+ }
+ break;
+ case SLAPD_EXEMODE_DB2LDIF:
+ if (r_flag) {
+ /* When the -r flag is used in db2ldif we need to make sure
+ * we get a consistent snapshot of the server. As a result
+ * it needs to run by itself, so no other slapd process can
+ * change the database while it is running. */
+ if (running || importing) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_DB2LDIFR_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ /* Even though this is really going to export code, we will
+ * but it in the importing dir so no other process can change
+ * things while we are doing ldif2db with the -r flag. */
+ add_this_process_to(import_dir);
+ result = 0;
+ }
+ } else {
+ if (importing) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_DB2LDIF_DUE_TO_IMPORT, importing, 0, 0);
+ result = -1;
+ } else {
+ add_this_process_to(export_dir);
+ result = 0;
+ }
+ }
+ break;
+ case SLAPD_EXEMODE_DB2ARCHIVE:
+ if (importing) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_DB2BAK_DUE_TO_IMPORT, importing, 0, 0);
+ result = -1;
+ } else {
+ add_this_process_to(export_dir);
+ result = 0;
+ }
+ break;
+ case SLAPD_EXEMODE_ARCHIVE2DB:
+ case SLAPD_EXEMODE_LDIF2DB:
+ if (running || importing || exporting) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_IMPORT_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ add_this_process_to(import_dir);
+ result = 0;
+ }
+ break;
+ case SLAPD_EXEMODE_DB2INDEX:
+ if (running || importing || exporting) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_DB2INDEX_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ add_this_process_to(import_dir);
+ result = 0;
+ }
+ break;
+#if defined(UPGRADEDB)
+ case SLAPD_EXEMODE_UPGRADEDB:
+ if (running || importing || exporting) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_UPGRADEDB_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ add_this_process_to(import_dir);
+ result = 0;
+ }
+ break;
+#endif
+ case SLAPD_EXEMODE_DBTEST:
+ if (running || importing || exporting) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_DBTEST_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ add_this_process_to(import_dir);
+ result = 0;
+ }
+ break;
+ }
+
+ release_lockfile();
+
+ if (result == 0) {
+ atexit(remove_slapd_process);
+ }
+
+ return result;
+}
+
+
+
+/* is_slapd_running()
+ * returns 1 if slapd is running, 0 if not, -1 on error
+ */
+
+
+int
+is_slapd_running() {
+ char server_dir[MAXPATHLEN];
+ char lock_dir[MAXPATHLEN];
+ slapdFrontendConfig_t *cfg = getFrontendConfig();
+ int running = 0;
+
+ sprintf(lock_dir, "%s/%s", cfg->instancedir, LOCK_DIR);
+ sprintf( server_dir, "%s/%s/%s", cfg->instancedir, LOCK_DIR, SERVER_DIR);
+
+ /* Grab the lockfile */
+ if (grab_lockfile() != 0) {
+ /* Unable to grab the lockfile */
+ return -1;
+ }
+
+ /* Make sure the directories exist */
+ if (make_sure_dir_exists(lock_dir) != 0 ||
+ make_sure_dir_exists(server_dir) != 0) {
+ release_lockfile();
+ return -1;
+ }
+
+ running = sample_and_update(server_dir);
+ release_lockfile();
+ return running;
+}
+
+
+#else /* _WIN32 */
+
+/* The NT version of this code */
+
+/* Returns 1 if the mutex named 'mutexName' otherwise it
+ * returns 0
+ */
+int
+mutex_exists( char *mutexName )
+{
+ if ( OpenMutex( SYNCHRONIZE, FALSE, mutexName ) == NULL ) {
+ return( 0 );
+ } else {
+ return( 1 );
+ }
+}
+
+/* is_slapd_running():
+ * returns 1 if slapd is running, 0 if not
+ */
+
+int
+is_slapd_running() {
+ char mutexName[ MAXPATHLEN + 1 ];
+ char serverMutexName[ MAXPATHLEN + 1 ];
+ int result = 0;
+ slapdFrontendConfig_t *cfg = getFrontendConfig();
+
+ strncpy( mutexName, cfg->instancedir, MAXPATHLEN );
+ strncpy( serverMutexName, cfg->instancedir, MAXPATHLEN );
+ mutexName[ MAXPATHLEN ] = '\0';
+
+ serverMutexName[ MAXPATHLEN ] = '\0';
+ strcat( serverMutexName, "/server" );
+
+ return mutex_exists ( serverMutexName );
+}
+
+static void fix_mutex_name(char *name)
+{
+ /* On NT mutex names cannot contain the '\' character.
+ * This functions replaces '\' with '/' in the supplied
+ * name. */
+ int x;
+
+ for (x = 0; name[x] != '\0'; x++) {
+ if ('\\' == name[x]) {
+ name[x] = '/';
+ }
+ }
+}
+
+/*
+ * We retain any opened handle to the mutex we create here,
+ * to use when we shutdown, to delete the mutex prior to
+ * signaling that we've exited.
+ */
+static HANDLE open_mutex = NULL;
+
+/*
+ * Call this to clean up the locks, before signaling
+ * that the server is down.
+ */
+void
+remove_slapd_process()
+{
+ if (open_mutex) {
+ CloseHandle(open_mutex);
+ }
+}
+
+/* This function makes sure different instances of slapd don't
+ * run in conflicting modes at the same time. The WIN32 version
+ * uses mutexes as names that the kernel handles. Basically there
+ * is a server mutex, and import mutex, and an export mutex. If
+ * the server mutex exists, then the server is running. If the
+ * import mutex exists, then either ldif2db or bak2db is running.
+ * If the export mutex exists, then one or more of db2ldif or db2bak
+ * are running. There is also a mutex that is actually locked when
+ * checking the existence of the other mutexes. The OS will
+ * automatically remove a mutex if no process has a handle on it.
+ * returns a 0 if it is ok for the process to run
+ * returns a -1 if the process can't run do to a conflict with other
+ * slapd processes
+ */
+int
+add_new_slapd_process(int exec_mode, int r_flag, int skip_flag)
+{
+ char mutexName[ MAXPATHLEN + 1 ];
+ char serverMutexName[ MAXPATHLEN + 1 ];
+ char importMutexName[ MAXPATHLEN + 1 ];
+ char exportMutexName[ MAXPATHLEN + 1 ];
+
+ HANDLE mutex;
+ SECURITY_ATTRIBUTES mutexAttributes;
+ PSECURITY_DESCRIPTOR pSD;
+ LPVOID lpMsgBuf;
+
+ int result = 0;
+
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+
+ if (skip_flag) {
+ return 0;
+ }
+
+ /* Create the names for the mutexes */
+ strcpy(mutexName, slapdFrontendConfig->instancedir);
+
+ /* Make sure the name of the mutex is legal. */
+ fix_mutex_name(mutexName);
+
+ sprintf(serverMutexName, "%s/server", mutexName);
+ sprintf(importMutexName, "%s/import", mutexName);
+ sprintf(exportMutexName, "%s/export", mutexName);
+
+ /* Fill in the security crap for the mutex */
+ pSD = (PSECURITY_DESCRIPTOR)slapi_ch_malloc( sizeof( SECURITY_DESCRIPTOR ) );
+ InitializeSecurityDescriptor( pSD, SECURITY_DESCRIPTOR_REVISION );
+ SetSecurityDescriptorDacl( pSD, TRUE, NULL, FALSE );
+ mutexAttributes.nLength = sizeof( mutexAttributes );
+ mutexAttributes.lpSecurityDescriptor = pSD;
+ mutexAttributes.bInheritHandle = FALSE;
+
+ /* Get a handle to the main mutex */
+ if ( ( mutex = CreateMutex( &mutexAttributes, FALSE, mutexName ) ) == NULL ) {
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ LDAPDebug( LDAP_DEBUG_ANY, CREATE_MUTEX_ERROR, lpMsgBuf, 0, 0 );
+ LocalFree( lpMsgBuf );
+ exit( 1 );
+ }
+
+ /* Lock the main mutex */
+ if ( WaitForSingleObject( mutex, INFINITE ) == WAIT_FAILED ) {
+ FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL,
+ GetLastError(),
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL
+ );
+
+ LDAPDebug( LDAP_DEBUG_ANY, WAIT_ERROR, lpMsgBuf, 0, 0 );
+ LocalFree( lpMsgBuf );
+ exit( 1 );
+ }
+
+
+ switch (exec_mode) {
+ case SLAPD_EXEMODE_SLAPD:
+ if ( mutex_exists( serverMutexName ) ||
+ mutex_exists( importMutexName ) ) {
+ LDAPDebug( LDAP_DEBUG_ANY, NO_SERVER_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ open_mutex = CreateMutex( &mutexAttributes, FALSE, serverMutexName );
+ result = 0;
+ }
+ break;
+ case SLAPD_EXEMODE_DB2LDIF:
+ if (r_flag) {
+ /* When the -r flag is used in db2ldif we need to make sure
+ * we get a consistent snapshot of the server. As a result
+ * it needs to run by itself, so no other slapd process can
+ * change the database while it is running. */
+ if ( mutex_exists( serverMutexName ) ||
+ mutex_exists( importMutexName ) ||
+ mutex_exists( exportMutexName ) ) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_DB2LDIFR_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ CreateMutex( &mutexAttributes, FALSE, exportMutexName );
+ result = 0;
+ }
+ break;
+ }
+ case SLAPD_EXEMODE_DB2ARCHIVE:
+ if ( mutex_exists( importMutexName ) ) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_EXPORT_DUE_TO_IMPORT, 0, 0, 0);
+ result = -1;
+ } else {
+ CreateMutex( &mutexAttributes, FALSE, exportMutexName );
+ result = 0;
+ }
+ break;
+ case SLAPD_EXEMODE_ARCHIVE2DB:
+ case SLAPD_EXEMODE_LDIF2DB:
+ if ( mutex_exists( serverMutexName ) ||
+ mutex_exists( importMutexName ) ||
+ mutex_exists( exportMutexName ) ) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_IMPORT_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ CreateMutex( &mutexAttributes, FALSE, importMutexName );
+ result = 0;
+ }
+ break;
+#if defined(UPGRADEDB)
+ case SLAPD_EXEMODE_UPGRADEDB:
+ if ( mutex_exists( serverMutexName ) ||
+ mutex_exists( importMutexName ) ||
+ mutex_exists( exportMutexName ) ) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_UPGRADEDB_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ CreateMutex( &mutexAttributes, FALSE, importMutexName );
+ result = 0;
+ }
+ break;
+#endif
+ case SLAPD_EXEMODE_DBTEST:
+ if ( mutex_exists( serverMutexName ) ||
+ mutex_exists( importMutexName ) ||
+ mutex_exists( exportMutexName ) ) {
+ LDAPDebug(LDAP_DEBUG_ANY, NO_DBTEST_DUE_TO_USE, 0, 0, 0);
+ result = -1;
+ } else {
+ CreateMutex( &mutexAttributes, FALSE, importMutexName );
+ result = 0;
+ }
+ break;
+ }
+
+ /* release the main mutex */
+ ReleaseMutex( mutex );
+
+ slapi_ch_free((void**)&pSD );
+
+ return( result );
+}
+#endif /* _WIN32 */
+
diff --git a/ldap/servers/slapd/protect_db.h b/ldap/servers/slapd/protect_db.h
new file mode 100644
index 00000000..6d6d59d0
--- /dev/null
+++ b/ldap/servers/slapd/protect_db.h
@@ -0,0 +1,75 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Header file for protect_db.c */
+
+int add_new_slapd_process(int exec_mode, int r_flag, int skip_flag);
+int is_slapd_running();
+void remove_slapd_process();
+
+/*
+ * These are the format strings used in the error messages in protect_db.c.
+ * After each string is a short description of what gets inserted into the
+ * string.
+ */
+
+#define ERROR_ACCESSING_LOCKFILE "Error - Problem accessing the lockfile %s\n"
+ /* name of lockfile */
+
+#define LOCKFILE_DEAD_OWNER "Error - The lockfile, %s, is held by process %d,\nwhich no longer seems to be running. If this is\nthe case, please remove the lockfile\n"
+ /* name of lockfile, pid of owning process */
+
+#define UNABLE_TO_GET_LOCKFILE "Error - Unable to acquire the lockfile, %s.\nPlease make sure no instances of the ns-slapd process are running, remove the lockfile and try again\n"
+ /* name of lockfile */
+
+#define LOCKFILE_ALREADY_OWNED "Error - Unable to start because process %d holds a lock.\nPlease make sure that the process is running correctly\nIf it is not, kill it and try again.\n"
+ /* pid of owning process */
+
+#define FILE_CREATE_ERROR "Error - Unable to create %s, " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n"
+ /* name of file */
+
+#define FILE_CREATE_WARNING "Warning - Unable to create %s\n"
+ /* name of file */
+
+#define GETPWNAM_WARNING "Warning - Unable to find user %s in system account database, errno %d (%s)\n"
+ /* user name, error code, error message */
+
+#define CHOWN_WARNING "Warning - couldn't set the ownership for %s\n"
+ /* file name */
+
+#define NO_SERVER_DUE_TO_SERVER "Unable to start slapd because it is already running as process %d\n"
+ /* pid of running slapd process */
+
+#define NO_SERVER_DUE_TO_IMPORT "Unable to start slapd because a database is being imported by process %d\n"
+ /* pid of importing process */
+
+#define NO_SERVER_DUE_TO_USE "Unable to start slapd because the database is in use\nby another slapd process\n"
+
+#define NO_DB2LDIFR_DUE_TO_USE "Unable to run db2ldif with the -r flag because the database is being used by another slapd process.\n"
+
+#define NO_DB2LDIF_DUE_TO_IMPORT "Unable to run db2ldif because the process %d is importing the database.\n"
+ /* pid of importing process */
+
+#define NO_DB2BAK_DUE_TO_IMPORT "Unable to run db2bak because the process %d is importing the database.\n"
+ /* pid of importing process */
+
+#define NO_EXPORT_DUE_TO_IMPORT "Unable to export the database because it is being imported.\n"
+
+#define NO_IMPORT_DUE_TO_USE "Unable to import the database because it is being used by another slapd process.\n"
+
+#define NO_DBTEST_DUE_TO_USE "Unable to test the database because it is being used by another slapd process.\n"
+
+#define NO_DB2INDEX_DUE_TO_USE "Unable to create an index because the database is being used by another slapd process.\n"
+
+#if defined(UPGRADEDB)
+#define NO_UPGRADEDB_DUE_TO_USE "Unable to recreate index files because the database is being used by another slapd process.\n"
+#endif
+
+#define CREATE_MUTEX_ERROR "Error - CreateMutex failed: %s\n"
+ /* reason for failure */
+
+#define WAIT_ERROR "Error - wait failed: %s\n"
+ /* reason for failure */
+
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
new file mode 100644
index 00000000..06d718eb
--- /dev/null
+++ b/ldap/servers/slapd/proto-slap.h
@@ -0,0 +1,1163 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _PROTO_SLAP
+#define _PROTO_SLAP
+
+/*
+ * Forward structure declarations
+ */
+struct dse;
+struct dsecallback;
+
+/*
+ * abandon.c
+ */
+void do_abandon( Slapi_PBlock *pb );
+
+
+/*
+ * add.c
+ */
+void do_add( Slapi_PBlock *pb );
+
+
+/*
+ * attr.c
+ */
+void attr_done(Slapi_Attr *a);
+int attr_add_valuearray(Slapi_Attr *a, Slapi_Value **vals, const char *dn);
+void attr_replace(Slapi_Attr *a, Slapi_Value **vals);
+int attr_check_onoff ( const char *attr_name, char *value, long minval, long maxval, char *errorbuf );
+int attr_check_minmax ( const char *attr_name, char *value, long minval, long maxval, char *errorbuf );
+
+/*
+ * attrlist.c
+ */
+
+void attrlist_free(Slapi_Attr *alist);
+int attrlist_find_or_create(Slapi_Attr **alist, const char *type, Slapi_Attr ***a);
+int attrlist_find_or_create_locking_optional(Slapi_Attr **alist, const char *type, Slapi_Attr ***a, PRBool use_lock, PRBool ref_count);
+void attrlist_merge( Slapi_Attr **alist, const char *type, struct berval **vals );
+void attrlist_merge_valuearray( Slapi_Attr **alist, const char *type, Slapi_Value **vals );
+int attrlist_delete( Slapi_Attr **attrs, const char *type );
+Slapi_Attr *attrlist_find( Slapi_Attr *a, const char *type );
+Slapi_Attr *attrlist_remove(Slapi_Attr **attrs, const char *type);
+void attrlist_add(Slapi_Attr **attrs, Slapi_Attr *a);
+int attrlist_count_subtypes(Slapi_Attr *a, const char *type);
+Slapi_Attr *attrlist_find_ex( Slapi_Attr *a, const char *type, int *type_name_disposition, char** actual_type_name, void **hint );
+void attrlist_replace(Slapi_Attr **alist, const char *type, struct berval **vals);
+
+/*
+ * attrsyntax.c
+ */
+void attr_syntax_read_lock(void);
+void attr_syntax_unlock_read(void);
+int attr_syntax_exists (const char *attr_name);
+void attr_syntax_delete ( struct asyntaxinfo *asip );
+#define SLAPI_SYNTAXLENGTH_NONE (-1) /* for syntaxlength parameter */
+int attr_syntax_create( const char *attr_oid, char *const*attr_names,
+ int num_names, const char *attr_desc, const char *attr_superior,
+ const char *mr_equality, const char *mr_ordering,
+ const char *mr_substring, char *const *attr_origins,
+ const char *attr_syntax, int syntaxlength, unsigned long flags,
+ struct asyntaxinfo **asip );
+void attr_syntax_free( struct asyntaxinfo *a );
+int attr_syntax_add( struct asyntaxinfo *asip );
+char *attr_syntax_normalize_no_lookup( const char *s );
+void attr_syntax_enumerate_attrs(AttrEnumFunc aef, void *arg, PRBool writelock);
+void attr_syntax_all_clear_flag( unsigned long flag );
+void attr_syntax_delete_all_not_flagged( unsigned long flag );
+struct asyntaxinfo *attr_syntax_get_by_oid ( const char *oid );
+struct asyntaxinfo *attr_syntax_get_by_name ( const char *name );
+struct asyntaxinfo *attr_syntax_get_by_name_locking_optional ( const char *name, PRBool use_lock, PRBool ref_count );
+/*
+ * Call attr_syntax_return() when you are done using a value returned
+ * by attr_syntax_get_by_oid() or attr_syntax_get_by_name().
+ */
+void attr_syntax_return( struct asyntaxinfo *asi );
+void attr_syntax_return_locking_optional( struct asyntaxinfo *asi, PRBool use_lock );
+
+/*
+ * value.c
+ */
+size_t value_size(const Slapi_Value *v);
+
+/*
+ * valueset.c
+ */
+int valuearray_init_bervalarray(struct berval **bvals, Slapi_Value ***cvals);
+int valuearray_get_bervalarray(Slapi_Value **cvals, struct berval ***bvals); /* JCM SLOW FUNCTION */
+void valuearray_free(Slapi_Value ***va);
+Slapi_Value *valuearray_remove_value(const Slapi_Attr *a, Slapi_Value **va, const Slapi_Value *v);
+void valuearray_remove_value_atindex(Slapi_Value **va, int index);
+int valuearray_isempty( Slapi_Value **va);
+void valuearray_update_csn(Slapi_Value **va, CSNType t, const CSN *csn);
+int valuearray_count( Slapi_Value **va);
+int valuearray_next_value( Slapi_Value **va, int index, Slapi_Value **v);
+int valuearray_first_value( Slapi_Value **va, Slapi_Value **v );
+
+void valuearrayfast_init(struct valuearrayfast *vaf,Slapi_Value **va);
+void valuearrayfast_done(struct valuearrayfast *vaf);
+void valuearrayfast_add_value(struct valuearrayfast *vaf,const Slapi_Value *v);
+void valuearrayfast_add_value_passin(struct valuearrayfast *vaf,Slapi_Value *v);
+void valuearrayfast_add_valuearrayfast(struct valuearrayfast *vaf,const struct valuearrayfast *vaf_add);
+
+int valuetree_add_value( const char *type, struct slapdplugin *pi, const Slapi_Value *va, Avlnode **valuetreep);
+int valuetree_add_valuearray( const char *type, struct slapdplugin *pi, Slapi_Value **va, Avlnode **valuetreep, int *duplicate_index);
+void valuetree_free( Avlnode **valuetreep );
+
+/* Valueset functions */
+
+int valueset_isempty( const Slapi_ValueSet *vs);
+Slapi_Value *valueset_find(const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_Value *v);
+Slapi_Value *valueset_remove_value(const Slapi_Attr *a, Slapi_ValueSet *vs, const Slapi_Value *v);
+int valueset_remove_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestodelete, int flags, Slapi_Value ***va_out);
+int valueset_purge(Slapi_ValueSet *vs, const CSN *csn);
+Slapi_Value **valueset_get_valuearray(const Slapi_ValueSet *vs);
+size_t valueset_size(const Slapi_ValueSet *vs);
+void valueset_add_valuearray(Slapi_ValueSet *vs, Slapi_Value **addvals);
+void valueset_add_valuearray_ext(Slapi_ValueSet *vs, Slapi_Value **addvals, PRUint32 flags);
+void valueset_add_string(Slapi_ValueSet *vs, const char *s, CSNType t, const CSN *csn);
+void valueset_update_csn(Slapi_ValueSet *vs, CSNType t, const CSN *csn);
+void valueset_add_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2);
+int valueset_intersectswith_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **values, int *duplicate_index);
+Slapi_ValueSet *valueset_dup(const Slapi_ValueSet *dupee);
+void valueset_remove_string(const Slapi_Attr *a, Slapi_ValueSet *vs, const char *s);
+void valueset_replace(Slapi_ValueSet *vs, Slapi_Value **vals);
+void valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestoupdate, CSNType t, const CSN *csn, Slapi_Value ***valuesupdated);
+void valueset_set_valuearray_byval(Slapi_ValueSet *vs, Slapi_Value **addvals);
+void valueset_set_valuearray_passin(Slapi_ValueSet *vs, Slapi_Value **addvals);
+
+
+/*
+ * ava.c
+ */
+int get_ava( BerElement *ber, struct ava *ava );
+void ava_done( struct ava *ava );
+int rdn2ava( char *rdn, struct ava *ava );
+
+/*
+ * backend.c
+ */
+void be_init(Slapi_Backend *be, const char *type, const char *name, int isprivate, int logchanges, int sizelimit, int timelimit );
+void be_done(Slapi_Backend *be);
+void be_addsuffix(Slapi_Backend *be,const Slapi_DN *suffix);
+Slapi_DN *be_getconfigdn(Slapi_Backend *be,Slapi_DN *dn);
+Slapi_DN *be_getmonitordn(Slapi_Backend *be,Slapi_DN *dn);
+int be_writeconfig (Slapi_Backend *be);
+
+/*
+ * backend_manager.c
+ */
+Slapi_Backend *be_new_internal(struct dse *pdse, const char *type, const char *name);
+int fedse_create_startOK(char *filename, char *startokfilename, const char *configdir);
+void be_cleanupall();
+void be_flushall();
+int be_remove( Slapi_Backend *be );
+void g_set_defsize(int val);
+void g_set_deftime(int val);
+Slapi_Backend *g_get_user_backend( int n );
+int g_get_defsize();
+int g_get_deftime();
+void be_unbindall( Connection *conn, Operation *op);
+int be_nbackends_public();
+
+/*
+ * bind.c
+ */
+void do_bind( Slapi_PBlock *pb );
+void init_saslmechanisms( void );
+
+
+/*
+ * compare.c
+ */
+void do_compare( Slapi_PBlock *pb );
+
+/*
+ * computed.c
+ */
+int compute_attribute(char *type, Slapi_PBlock *pb,BerElement *ber,Slapi_Entry *e,int attrsonly,char *requested_type);
+int compute_init();
+int compute_terminate();
+
+
+/*
+ * config.c
+ */
+int slapd_bootstrap_config(const char *configdir);
+int config_set_storagescheme();
+int get_netsite_root_path(char *pathname);
+int slapd_write_config ();
+int config_set_port( const char *attrname, char *port, char *errorbuf, int apply );
+int config_set_secureport( const char *attrname, char *port, char *errorbuf, int apply );
+int config_set_SSLclientAuth( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_ssl_check_hostname( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_SSL3ciphers( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_localhost( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_listenhost( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_securelistenhost( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_srvtab( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_sizelimit( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_lastmod( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_nagle( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_accesscontrol( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_security( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_readonly( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_schemacheck( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_ds4_compatible_schema( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_schema_ignore_trailing_spaces( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_rootdn( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_rootpw( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_rootpwstoragescheme( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_workingdir( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_instancedir( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_encryptionalias( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_threadnumber( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_maxthreadsperconn( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_reservedescriptors( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_ioblocktimeout( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_idletimeout( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_max_filter_nest_level( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_groupevalnestlevel( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_defaultreferral( const char *attrname, struct berval **value, char *errorbuf, int apply );
+int config_set_timelimit(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_errorlog_level(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_accesslog_level(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_auditlog(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_userat(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_accesslog(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_errorlog(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_change(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_must_change(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pwpolicy_local(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_syntax(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_minlength(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_exp(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_maxage(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_minage(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_warning(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_history(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_inhistory(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_lockout(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_storagescheme(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_maxfailure(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_unlock(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_lockduration(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_resetfailurecount(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_is_global_policy(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_pw_gracelimit(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_useroc(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_return_exact_case(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_result_tweak(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_referral_mode(const char *attrname, char *url, char *errorbuf, int apply);
+int config_set_conntablesize(const char *attrname, char *url, char *errorbuf, int apply);
+int config_set_maxbersize(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_versionstring(const char *attrname, char *versionstring, char *errorbuf, int apply );
+int config_set_enquote_sup_oc(const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_basedn( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_configdir( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_attrname_exceptions( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_hash_filters( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_rewrite_rfc1274( const char *attrname, char *value, char *errorbuf, int apply );
+int config_set_outbound_ldap_io_timeout( const char *attrname, char *value,
+ char *errorbuf, int apply );
+int config_set_accesslogbuffering(const char *attrname, char *value, char *errorbuf, int apply);
+int config_set_csnlogging(const char *attrname, char *value, char *errorbuf, int apply);
+
+#if !defined(_WIN32) && !defined(AIX)
+int config_set_maxdescriptors( const char *attrname, char *value, char *errorbuf, int apply );
+#endif /* !_WIN_32 && !AIX */
+
+#ifndef _WIN32
+int config_set_localuser( const char *attrname, char *value, char *errorbuf, int apply );
+#endif /* !_WIN32 */
+
+int config_get_SSLclientAuth();
+int config_get_ssl_check_hostname();
+char *config_get_SSL3ciphers();
+char *config_get_localhost();
+char *config_get_listenhost();
+char *config_get_securelistenhost();
+char *config_get_srvtab();
+int config_get_sizelimit();
+char *config_get_pw_storagescheme();
+int config_get_pw_change();
+int config_get_pw_history();
+int config_get_pw_must_change();
+int config_get_pw_syntax();
+int config_get_pw_minlength();
+int config_get_pw_maxfailure();
+int config_get_pw_inhistory();
+long config_get_pw_lockduration();
+long config_get_pw_resetfailurecount();
+int config_get_pw_exp();
+int config_get_pw_unlock();
+int config_get_pw_lockout();
+int config_get_pw_gracelimit();
+int config_get_lastmod();
+int config_get_nagle();
+int config_get_accesscontrol();
+int config_get_return_exact_case();
+int config_get_result_tweak();
+int config_get_security();
+int config_get_schemacheck();
+int config_get_ds4_compatible_schema();
+int config_get_schema_ignore_trailing_spaces();
+char *config_get_rootdn();
+char *config_get_rootpw();
+char *config_get_rootpwstoragescheme();
+#ifndef _WIN32
+char *config_get_localuser();
+#endif /* _WIN32 */
+char *config_get_workingdir();
+char *config_get_instancedir();
+char *config_get_encryptionalias();
+int config_get_threadnumber();
+int config_get_maxthreadsperconn();
+#if !defined(_WIN32) && !defined(AIX)
+int config_get_maxdescriptors();
+#endif /* !_WIN32 && !AIX */
+int config_get_reservedescriptors();
+int config_get_ioblocktimeout();
+int config_get_idletimeout();
+int config_get_max_filter_nest_level();
+int config_get_groupevalnestlevel();
+struct berval **config_get_defaultreferral();
+char *config_get_userat();
+int config_get_timelimit();
+char* config_get_useroc();
+char *config_get_accesslog();
+char *config_get_errorlog();
+char *config_get_auditlog();
+long config_get_pw_maxage();
+long config_get_pw_minage();
+long config_get_pw_warning();
+int config_get_errorlog_level();
+int config_get_accesslog_level();
+char *config_get_referral_mode(void);
+int config_get_conntablesize(void);
+int config_check_referral_mode(void);
+unsigned long config_get_maxbersize();
+char *config_get_versionstring();
+char *config_get_buildnum(void);
+int config_get_enquote_sup_oc();
+char *config_get_basedn();
+char *config_get_configdir();
+char **config_get_errorlog_list();
+char **config_get_accesslog_list();
+char **config_get_auditlog_list();
+int config_get_attrname_exceptions();
+int config_get_hash_filters();
+int config_get_rewrite_rfc1274();
+int config_get_outbound_ldap_io_timeout(void);
+int config_get_csnlogging();
+int is_abspath(const char *);
+char* rel2abspath( char * );
+
+/*
+ * configdse.c
+ */
+int read_config_dse (Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int load_config_dse(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int modify_config_dse(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int postop_modify_config_dse(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+int add_root_dse( Slapi_PBlock *pb );
+int load_plugin_entry(Slapi_PBlock *pb, Slapi_Entry* e, Slapi_Entry* entryAfter, int *returncode, char *returntext, void *arg);
+
+
+/*
+ * controls.c
+ */
+void init_controls( void );
+int get_ldapmessage_controls( Slapi_PBlock *pb, BerElement *ber,
+ LDAPControl ***controls );
+int write_controls( BerElement *ber, LDAPControl **ctrls );
+void add_control( LDAPControl ***ctrlsp, LDAPControl *newctrl );
+
+
+/*
+ * delete.c
+ */
+void do_delete( Slapi_PBlock *pb );
+
+
+/*
+ * detach.c
+ */
+void detach( void );
+#ifndef _WIN32
+void close_all_files( void );
+#endif
+void raise_process_limits( void );
+
+
+/*
+ * dn.c
+ */
+char *substr_dn_normalize( char *dn, char *end );
+int hexchar2int( char c );
+
+
+/*
+ * dynalib.c
+ */
+void *sym_load( char *libpath, char *symbol, char *plugin, int report_errors );
+
+
+/*
+ * filter.c
+ */
+int get_filter( Connection *conn, BerElement *ber, int scope,
+ struct slapi_filter **filt, char **fstr );
+void filter_print( struct slapi_filter *f );
+void filter_normalize( struct slapi_filter *f );
+
+
+/*
+ * filtercmp.c
+ */
+void filter_compute_hash(struct slapi_filter *f);
+void set_hash_filters(int i);
+
+
+/*
+ * filterentry.c
+ */
+void filter_strcpy_special( char *d, char *s );
+
+
+/*
+ * entry.c
+ */
+int is_rootdse( const char *dn );
+int get_entry_object_type();
+int entry_computed_attr_init();
+void send_referrals_from_entry(Slapi_PBlock *pb, Slapi_Entry *referral);
+
+
+/*
+ * dse.c
+ */
+#define DSE_OPERATION_READ 0x100
+#define DSE_OPERATION_WRITE 0x200
+
+#define DSE_BACKEND "frontend-internal"
+
+#define SLAPI_DSE_RETURNTEXT_SIZE 512 /* for use by callback functions */
+
+struct dse *dse_new( char *filename, char *tmpfilename, char *backfilename, char *startokfilename, const char *configdir);
+struct dse *dse_new_with_filelist(char *filename, char *tmpfilename, char *backfilename, char *startokfilename, const char *configdir, char **filelist);
+int dse_deletedse(Slapi_PBlock *pb);
+int dse_read_file(struct dse *pdse, Slapi_PBlock *pb);
+int dse_bind( Slapi_PBlock *pb );
+int dse_unbind( Slapi_PBlock *pb );
+int dse_search(Slapi_PBlock *pb);
+int dse_modify(Slapi_PBlock *pb);
+int dse_add(Slapi_PBlock *pb);
+int dse_delete(Slapi_PBlock *pb);
+struct dse_callback *dse_register_callback(struct dse* pdse, int operation, int flags, const Slapi_DN *base, int scope, const char *filter, dseCallbackFn fn, void *fn_arg);
+void dse_remove_callback(struct dse* pdse, int operation, int flags, const Slapi_DN *base, int scope, const char *filter, dseCallbackFn fn);
+void dse_set_dont_ever_write_dse_files(void);
+void dse_unset_dont_ever_write_dse_files(void);
+int dse_next_search_entry (Slapi_PBlock *pb);
+char *dse_read_next_entry( char *buf, char **lastp );
+
+
+/*
+ * fedse.c
+ */
+
+int setup_internal_backends();
+
+
+/*
+ * extendedop.c
+ */
+void ldapi_init_extended_ops( void );
+void ldapi_register_extended_op( char **opoids );
+void do_extended( Slapi_PBlock *pb );
+
+
+/*
+ * house.c
+ */
+PRThread* housekeeping_start(time_t cur_time, void *arg);
+void housekeeping_stop();
+
+/*
+ * lock.c
+ */
+FILE * lock_fopen( char *fname, char *type, FILE **lfp );
+int lock_fclose( FILE *fp, FILE *lfp );
+
+
+/*
+ * log.c
+ */
+int slapd_log_error_proc( char *subsystem, char *fmt, ... );
+int slapi_log_access( int level, char *fmt, ... );
+int slapd_log_audit_proc(char *buffer, int buf_len);
+void log_access_flush();
+
+
+int access_log_openf( char *pathname, int locked);
+int error_log_openf( char *pathname, int locked);
+int audit_log_openf( char *pathname, int locked);
+
+void g_set_detached(int);
+void g_log_init(int log_enabled);
+char *g_get_access_log();
+char *g_get_error_log();
+char *g_get_audit_log();
+void g_set_accesslog_level(int val);
+
+int log_set_mode(const char *attrname, char *mode_str, int logtype, char *errorbuf, int apply);
+int log_set_numlogsperdir(const char *attrname, char *numlogs_str, int logtype, char *errorbuf, int apply);
+int log_set_logsize(const char *attrname, char *logsize_str, int logtype, char *errorbuf, int apply);
+int log_set_rotationsync_enabled(const char *attrname, char *rsync_str, int logtype, char *errorbuf, int apply);
+int log_set_rotationsynchour(const char *attrname, char *rhour_str, int logtype, char *errorbuf, int apply);
+int log_set_rotationsyncmin(const char *attrname, char *rmin_str, int logtype, char *errorbuf, int apply);
+int log_set_rotationtime(const char *attrname, char *rtime_str, int logtype, char *errorbuf, int apply);
+int log_set_rotationtimeunit(const char *attrname, char *runit, int logtype, char *errorbuf, int apply);
+int log_set_maxdiskspace(const char *attrname, char *maxdiskspace_str, int logtype, char *errorbuf, int apply);
+int log_set_mindiskspace(const char *attrname, char *minfreespace_str, int logtype, char *errorbuf, int apply);
+int log_set_expirationtime(const char *attrname, char *exptime_str , int logtype, char *errorbuf, int apply);
+int log_set_expirationtimeunit(const char *attrname, char *expunit, int logtype, char *errorbuf, int apply);
+char **log_get_loglist(int logtype);
+int log_update_accesslogdir(char *pathname, int apply);
+int log_update_errorlogdir(char *pathname, int apply);
+int log_update_auditlogdir(char *pathname, int apply);
+int log_set_logging (const char *attrname, char *value, int logtype, char *errorbuf, int apply);
+int check_log_max_size(
+ char *maxdiskspace_str,
+ char *mlogsize_str,
+ int maxdiskspace,
+ int mlogsize,
+ char * returntext,
+ int logtype);
+
+
+void g_set_accesslog_level(int val);
+
+
+/*
+ * util.c
+ */
+void slapd_nasty(char* str, int c, int err);
+int strarray2str( char **a, char *buf, size_t buflen, int include_quotes );
+
+/*
+ * modify.c
+ */
+void do_modify( Slapi_PBlock *pb );
+
+/*
+ * modrdn.c
+ */
+void do_modrdn( Slapi_PBlock *pb );
+
+
+/*
+ * modutil.c
+ */
+int entry_replace_values( Slapi_Entry *e, const char *type, struct berval **vals );
+int entry_apply_mods( Slapi_Entry *e, LDAPMod **mods );
+int entry_apply_mod( Slapi_Entry *e, const LDAPMod *mod );
+void freepmods( LDAPMod **pmods );
+
+
+/*
+ * monitor.c
+ */
+int monitor_info( Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
+char *slapd_get_version_value( void );
+
+
+
+/*
+ * operation.c
+ */
+Slapi_Operation *operation_new(int flags);
+void operation_free( Slapi_Operation **op, Connection *conn );
+int slapi_op_abandoned( Slapi_PBlock *pb );
+void operation_out_of_disk_space();
+int get_operation_object_type();
+Slapi_DN* operation_get_target_spec (Slapi_Operation *op);
+void operation_set_target_spec (Slapi_Operation *op, const Slapi_DN *target_spec);
+void operation_set_target_spec_str (Slapi_Operation *op, const char *target_spec);
+unsigned long operation_get_abandoned_op (const Slapi_Operation *op);
+void operation_set_abandoned_op (Slapi_Operation *op, unsigned long abndoned_op);
+void operation_set_type(Slapi_Operation *op, unsigned long type);
+
+
+/*
+ * plugin.c
+ */
+int plugin_call_plugins( Slapi_PBlock *, int );
+int plugin_setup(Slapi_Entry *plugin_entry, struct slapi_componentid *group,
+ slapi_plugin_init_fnptr initfunc, int add_to_dit);
+int plugin_call_exop_plugins( Slapi_PBlock *pb, char *oid );
+const char *plugin_extended_op_oid2string( const char *oid );
+void plugin_closeall(int close_backends, int close_globals);
+void plugin_startall(int argc,char **argv,int start_backends, int start_global);
+struct slapdplugin *get_plugin_list(int plugin_list_index);
+PRBool plugin_invoke_plugin_sdn (struct slapdplugin *plugin, int operation, Slapi_PBlock *pb, Slapi_DN *target_spec);
+struct slapdplugin *plugin_get_by_name(char *name);
+struct slapdplugin *plugin_get_pwd_storage_scheme(char *name, int len, int index);
+char *plugin_get_pwd_storage_scheme_list(int index);
+int plugin_add_descriptive_attributes( Slapi_Entry *e,
+ struct slapdplugin *plugin );
+void plugin_call_entryfetch_plugins(char **entrystr, uint *size);
+void plugin_call_entrystore_plugins(char **entrystr, uint *size);
+void plugin_print_versions(void);
+
+/*
+ * plugin_mr.c
+ */
+struct slapdplugin *slapi_get_global_mr_plugins();
+int plugin_mr_filter_create (mr_filter_t* f);
+
+/*
+ * plugin_syntax.c
+ */
+struct slapdplugin *slapi_get_global_syntax_plugins();
+int plugin_call_syntax_filter_ava( const Slapi_Attr *a, int ftype, struct ava *ava );
+int plugin_call_syntax_filter_ava_sv( const Slapi_Attr *a, int ftype, struct ava *ava, Slapi_Value **retVal, int useDeletedValues );
+int plugin_call_syntax_filter_sub( Slapi_Attr *a, struct subfilt *fsub );
+int plugin_call_syntax_filter_sub_sv( Slapi_Attr *a, struct subfilt *fsub );
+int plugin_call_syntax_get_compare_fn(void *vpi, value_compare_fn_type *compare_fn);
+struct slapdplugin *plugin_syntax_find( const char *nameoroid );
+void plugin_syntax_enumerate( SyntaxEnumFunc sef, void *arg );
+char *plugin_syntax2oid( struct slapdplugin *pi );
+
+/*
+ * plugin_acl.c
+ */
+int plugin_call_acl_plugin ( Slapi_PBlock *pb, Slapi_Entry *e,
+ char **attrs, struct berval *val, int access, int flags, char **errbuf);
+int plugin_call_acl_mods_access ( Slapi_PBlock *pb, Slapi_Entry *e, LDAPMod **mods, char **errbuf );
+int plugin_call_acl_mods_update ( Slapi_PBlock *pb, int optype );
+int plugin_call_acl_verify_syntax ( Slapi_PBlock *pb, Slapi_Entry *e, char **errbuf );
+
+/*
+ * pw_mgmt.c
+ */
+void pw_init( void );
+int need_new_pw( Slapi_PBlock *pb, long *t, Slapi_Entry *e, int pwresponse_req );
+int update_pw_info( Slapi_PBlock *pb , char *old_pw );
+int check_pw_syntax( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
+ char **old_pw, Slapi_Entry *e, int mod_op );
+int check_account_lock( Slapi_PBlock *pb, Slapi_Entry * bind_target_entry, int pwresponse_req);
+int check_pw_minage( Slapi_PBlock *pb, const Slapi_DN *sdn, struct berval **vals) ;
+int add_pwd_control( Slapi_PBlock *pb, char *arg, long time );
+void add_password_attrs( Slapi_PBlock *pb, Operation *op, Slapi_Entry *e );
+void mod_allowchange_aci(char *val);
+void pw_mod_allowchange_aci(int pw_prohibit_change);
+void pw_add_allowchange_aci(Slapi_Entry *e, int pw_prohibit_change);
+
+/*
+ * pw_retry.c
+ */
+int update_pw_retry ( Slapi_PBlock *pb );
+void pw_apply_mods(const char *dn, Slapi_Mods *mods);
+void pw_set_componentID(struct slapi_componentid * cid);
+struct slapi_componentid * pw_get_componentID();
+
+/*
+ * referral.c
+ */
+void referrals_free ();
+Ref_Array * ref_array_dup();
+void ref_array_dup_free(Ref_Array *the_copy);
+void update_global_referrals( Slapi_PBlock *pb );
+struct berval **ref_adjust( Slapi_PBlock *pb, struct berval **urls, const Slapi_DN *refcontainerdn, int is_reference );
+/* GGOODREPL temporarily in slapi-plugin.h struct berval **get_data_source( char *dn, int orc, Ref_Array * ); */
+
+
+/*
+ * resourcelimit.c
+ */
+int reslimit_update_from_dn( Slapi_Connection *conn, Slapi_DN *dn );
+int reslimit_update_from_entry( Slapi_Connection *conn, Slapi_Entry *e );
+void reslimit_cleanup( void );
+
+
+/*
+ * result.c
+ */
+void g_set_num_entries_sent( PRUint64 val );
+PRUint64 g_get_num_entries_sent();
+void g_set_num_bytes_sent( PRUint64 val );
+PRUint64 g_get_num_bytes_sent();
+void g_set_num_sent_mutex( PRLock *plock );
+void g_set_default_referral( struct berval **ldap_url );
+struct berval **g_get_default_referral();
+PRLock *g_get_num_sent_mutex();
+void disconnect_server( Connection *conn, int opconnid, int opid, PRErrorCode reason, PRInt32 error );
+int send_ldap_search_entry( Slapi_PBlock *pb, Slapi_Entry *e, LDAPControl **ectrls,
+ char **attrs, int attrsonly );
+void send_ldap_result( Slapi_PBlock *pb, int err, char *matched, char *text,
+ int nentries, struct berval **urls );
+int send_ldap_search_entry_ext( Slapi_PBlock *pb, Slapi_Entry *e, LDAPControl **ectrls,
+ char **attrs, int attrsonly, int send_result, int nentries, struct berval **urls );
+void send_ldap_result_ext( Slapi_PBlock *pb, int err, char *matched, char *text,
+ int nentries, struct berval **urls, BerElement *ber );
+void send_nobackend_ldap_result( Slapi_PBlock *pb );
+int send_ldap_referral( Slapi_PBlock *pb, Slapi_Entry *e, struct berval **refs,
+ struct berval ***urls );
+int send_ldapv3_referral( Slapi_PBlock *pb, struct berval **urls );
+int set_db_default_result_handlers(Slapi_PBlock *pb);
+void disconnect_server_nomutex( Connection *conn, int opconnid, int opid, PRErrorCode reason, PRInt32 error );
+long g_get_current_conn_count();
+void g_increment_current_conn_count();
+void g_decrement_current_conn_count();
+void g_set_current_conn_count_mutex( PRLock *plock );
+PRLock *g_get_current_conn_count_mutex();
+int encode_attr(Slapi_PBlock *pb,BerElement *ber,Slapi_Entry *e,Slapi_Attr *a,int attrsonly,char *type);
+
+
+/*
+ * schema.c
+ */
+int init_schema_dse(const char *configdir);
+char *oc_find_name( const char *name_or_oid );
+int oc_schema_check( Slapi_Entry *e );
+int modify_schema_dse (Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
+int read_schema_dse ( Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg);
+void oc_lock_read( void );
+void oc_lock_write( void );
+void oc_unlock( void );
+/* Note: callers of g_get_global_oc_nolock() must hold a read or write lock */
+struct objclass* g_get_global_oc_nolock();
+/* Note: callers of g_set_global_oc_nolock() must hold a write lock */
+void g_set_global_oc_nolock(struct objclass *newglobaloc);
+/* Note: callers of g_get_global_schema_csn() must hold a read lock */
+const CSN *g_get_global_schema_csn();
+/* Note: callers of g_set_global_schema_csn() must hold a write lock. */
+/* csn is consumed. */
+void g_set_global_schema_csn(CSN *csn);
+void slapi_schema_expand_objectclasses( Slapi_Entry *e );
+
+/*
+ * schemaparse.c
+ */
+void normalize_oc( void );
+/* Note: callers of oc_update_inheritance_nolock() must hold a write lock */
+void oc_update_inheritance_nolock( struct objclass *oc );
+
+/*
+ * search.c
+ */
+void do_search( Slapi_PBlock *pb );
+
+
+/*
+ * ssl.c
+ */
+int slapd_SSL_client_init();
+int slapd_SSL_client_bind_s( LDAP* ld, char* DN, char* pw, int use_SSL, int LDAPv);
+int slapd_sasl_ext_client_bind( LDAP* ld, int **msgid);
+int slapd_nss_init(int init_ssl, int config_available);
+int slapd_ssl_init();
+int slapd_ssl_init2(PRFileDesc **fd, int startTLS);
+int slapd_security_library_is_initialized();
+int slapd_ssl_listener_is_initialized();
+int sasl_io_cleanup(Connection *c);
+
+
+/*
+ * security_wrappers.c
+ */
+int slapd_ssl_handshakeCallback(PRFileDesc *fd, void * callback, void * client_data);
+int slapd_ssl_badCertHook(PRFileDesc *fd, void * callback, void * client_data);
+CERTCertificate * slapd_ssl_peerCertificate(PRFileDesc *fd);
+SECStatus slapd_ssl_getChannelInfo(PRFileDesc *fd, SSLChannelInfo *sinfo, PRUintn len);
+SECStatus slapd_ssl_getCipherSuiteInfo(PRUint16 ciphersuite, SSLCipherSuiteInfo *cinfo, PRUintn len);
+PRFileDesc * slapd_ssl_importFD(PRFileDesc *model, PRFileDesc *fd);
+SECStatus slapd_ssl_resetHandshake(PRFileDesc *fd, PRBool asServer);
+void slapd_pk11_configurePKCS11(char *man, char *libdes, char *tokdes, char *ptokdes,
+ char *slotdes, char *pslotdes, char *fslotdes,
+ char *fpslotdes, int minPwd,
+ int pwdRequired);
+void slapd_pk11_freeSlot(PK11SlotInfo *slot);
+void slapd_pk11_freeSymKey(PK11SymKey *key);
+PK11SlotInfo *slapd_pk11_findSlotByName(char *name);
+SECAlgorithmID *slapd_pk11_createPBEAlgorithmID(SECOidTag algorithm, int iteration, SECItem *salt);
+PK11SymKey *slapd_pk11_pbeKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem,
+ PRBool faulty3DES, void *wincx);
+CK_MECHANISM_TYPE slapd_pk11_algtagToMechanism(SECOidTag algTag);
+SECItem *slapd_pk11_paramFromAlgid(SECAlgorithmID *algid);
+CK_RV slapd_pk11_mapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism,
+ CK_MECHANISM_PTR pCryptoMechanism,
+ SECItem *pbe_pwd, PRBool bad3DES);
+int slapd_pk11_getBlockSize(CK_MECHANISM_TYPE type,SECItem *params);
+PK11Context * slapd_pk11_createContextBySymKey(CK_MECHANISM_TYPE type,
+ CK_ATTRIBUTE_TYPE operation,
+ PK11SymKey *symKey, SECItem *param);
+SECStatus slapd_pk11_cipherOp(PK11Context *context, unsigned char * out, int *outlen,
+ int maxout, unsigned char *in, int inlen);
+SECStatus slapd_pk11_finalize(PK11Context *context);
+PK11SlotInfo *slapd_pk11_getInternalKeySlot();
+PK11SlotInfo *slapd_pk11_getInternalSlot();
+SECStatus slapd_pk11_authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx);
+void slapd_pk11_setSlotPWValues(PK11SlotInfo *slot,int askpw, int timeout);
+PRBool slapd_pk11_isFIPS();
+CERTCertificate *slapd_pk11_findCertFromNickname(char *nickname, void *wincx);
+SECKEYPrivateKey *slapd_pk11_findKeyByAnyCert(CERTCertificate *cert, void *wincx);
+PRBool slapd_pk11_fortezzaHasKEA(CERTCertificate *cert);
+void slapd_pk11_destroyContext(PK11Context *context, PRBool freeit);
+void secoid_destroyAlgorithmID(SECAlgorithmID *algid, PRBool freeit);
+void slapd_pk11_CERT_DestroyCertificate(CERTCertificate *cert);
+SECKEYPublicKey *slapd_CERT_ExtractPublicKey(CERTCertificate *cert);
+SECKEYPrivateKey * slapd_pk11_FindPrivateKeyFromCert(PK11SlotInfo *slot,CERTCertificate *cert, void *wincx);
+PK11SlotInfo *slapd_pk11_GetInternalKeySlot(void);
+SECStatus slapd_pk11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,PK11SymKey *symKey, SECItem *wrappedKey);
+PK11SymKey *slapd_pk11_KeyGen(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,SECItem *param, int keySize,void *wincx);
+void slapd_pk11_FreeSlot(PK11SlotInfo *slot);
+void slapd_pk11_FreeSymKey(PK11SymKey *key);
+void slapd_pk11_DestroyContext(PK11Context *context, PRBool freeit);
+SECItem *slapd_pk11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv);
+PK11SymKey *slapd_pk11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize);
+unsigned slapd_SECKEY_PublicKeyStrength(SECKEYPublicKey *pubk);
+SECStatus slapd_pk11_Finalize(PK11Context *context);
+SECStatus slapd_pk11_DigestFinal(PK11Context *context, unsigned char *data,unsigned int *outLen, unsigned int length);
+void slapd_SECITEM_FreeItem (SECItem *zap, PRBool freeit);
+
+/*
+ * start_tls_extop.c
+ */
+int start_tls( Slapi_PBlock *pb );
+int start_tls_graceful_closure( Connection *conn, Slapi_PBlock *pb, int is_initiator );
+int start_tls_register_plugin();
+int start_tls_init( Slapi_PBlock *pb );
+
+/*
+ * slapi_str2filter.c
+ */
+struct slapi_filter *slapi_str2filter( char *str );
+char *slapi_find_matching_paren( const char *str);
+struct slapi_filter *str2simple();
+
+
+/*
+ * time.c
+ */
+char *get_timestring(time_t *t);
+void free_timestring(char *timestr);
+time_t current_time();
+time_t poll_current_time();
+char* format_localTime (time_t from);
+time_t parse_localTime (char* from);
+
+#ifndef HAVE_TIME_R
+int gmtime_r( const time_t *timer, struct tm *result );
+int localtime_r( const time_t *timer, struct tm *result );
+int ctime_r( const time_t *timer, char *buffer, int buflen );
+#endif
+
+char *format_genTime (time_t from);
+time_t parse_genTime (char *from);
+
+/*
+ * unbind.c
+ */
+void do_unbind( Slapi_PBlock *pb );
+
+
+/*
+ * pblock.c
+ */
+void pblock_init( Slapi_PBlock *pb );
+void pblock_init_common( Slapi_PBlock *pb, Slapi_Backend *be, Connection *conn, Operation *op );
+void pblock_done( Slapi_PBlock *pb );
+void bind_credentials_set( Connection *conn,
+ char *authtype, char *normdn,
+ char *extauthtype, char *externaldn, CERTCertificate *clientcert , Slapi_Entry * binded);
+void bind_credentials_clear( Connection *conn, PRBool lock_conn,
+ PRBool clear_externalcreds );
+
+
+/*
+ * libglobs.c
+ */
+void g_set_shutdown( int reason );
+int g_get_shutdown();
+void c_set_shutdown();
+int c_get_shutdown();
+int g_get_global_lastmod();
+/* Ref_Array *g_get_global_referrals(void); */
+struct snmp_vars_t * g_get_global_snmp_vars();
+void FrontendConfig_init();
+int g_get_slapd_security_on();
+void config_set_slapd_type ();
+char *config_get_versionstring();
+
+void libldap_init_debug_level(int *);
+int get_entry_point( int, caddr_t* );
+
+int config_set_entry(Slapi_Entry *e);
+int config_set(const char *attr_name, struct berval **values, char *errorbuf, int apply);
+
+void free_pw_scheme(struct pw_scheme *pwsp);
+
+/*
+ * rootdse.c
+ */
+int read_root_dse( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg );
+int modify_root_dse( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg );
+
+/*
+ * psearch.c
+ */
+void ps_init_psearch_system();
+void ps_stop_psearch_system();
+void ps_add( Slapi_PBlock *pb, int changetypes, int send_entchg_controls );
+void ps_wakeup_all();
+void ps_service_persistent_searches( Slapi_Entry *e, Slapi_Entry *eprev, int chgtype,
+ int chgnum );
+int ps_parse_control_value( struct berval *psbvp, int *changetypesp,
+ int *changesonlyp, int *returnecsp );
+
+/*
+ * globals.c
+ */
+void set_entry_points();
+
+/*
+ * defbackend.c
+ */
+void defbackend_init( void );
+Slapi_Backend *defbackend_get_backend( void );
+
+/*
+ * plugin_internal_op.c
+ */
+void do_disconnect_server( Connection *conn, int opconnid, int opid );
+
+/*
+ * regex.c
+ */
+int re_init( void );
+
+/*
+ * secpwd.c
+ */
+char* getPassword();
+
+/*
+ * match.c
+ */
+struct matchingRuleList *g_get_global_mrl();
+void g_set_global_mrl(struct matchingRuleList *newglobalmrl);
+
+/*
+ * lite_entries.c
+ */
+void lite_entries_init();
+
+/*
+ * generation.c
+ */
+
+/*
+ * factory.c
+ */
+
+int factory_register_type(const char *name,size_t offset);
+void *factory_create_extension(int type,void *object,void *parent);
+void factory_destroy_extension(int type,void *object,void *parent,void **extension);
+
+/*
+ * auditlog.c
+ */
+
+void write_audit_log_entry( Slapi_PBlock *pb);
+
+/*
+ * eventq.c
+ */
+void eq_init();
+void eq_start();
+void eq_stop();
+
+/*
+ * uniqueidgen.c
+ */
+
+/* Function: uniqueIDGenInit
+ Description: this function initializes the generator
+ Parameters: configDir - directory in which generators state is stored
+ configDN - DIT entry with state information
+ mtGen - indicates whether multiple threads will use generator
+ Return: UID_SUCCESS if function succeeds
+ UID_BADDATA if invalif directory is passed
+ UID_SYSTEM_ERROR if any other failure occurs
+*/
+int uniqueIDGenInit (const char *configDir, const Slapi_DN *configDN, PRBool mtGen);
+
+/* Function: uniqueIDGenCleanup
+ Description: cleanup
+ Parameters: none
+ Return: none
+*/
+void uniqueIDGenCleanup ();
+
+/*
+ * init.c
+ */
+void slapd_init();
+
+/*
+ * plugin.c
+ */
+
+/* this interface is exposed to be used by internal operations. It assumes no dynamic
+ plugin configuration as it provides no data locking. The interface will change once
+ we decide to support dynamic configuration
+ */
+const char* plugin_get_name (const struct slapdplugin *plugin);
+const DataList* plugin_get_target_subtrees (const struct slapdplugin *plugin);
+const DataList* plugin_get_bind_subtrees (const struct slapdplugin *plugin);
+int plugin_get_schema_check (const struct slapdplugin *plugin);
+int plugin_get_log_access (const struct slapdplugin *plugin);
+int plugin_get_log_audit (const struct slapdplugin *plugin);
+
+/*
+ * getfilelist.c
+ */
+char **get_filelist(
+ const char *dirname, /* directory path; if NULL, uses "." */
+ const char *pattern, /* grep (not shell!) file pattern regex */
+ int hiddenfiles, /* if true, return hidden files and directories too */
+ int nofiles, /* if true, do not return files */
+ int nodirs /* if true, do not return directories */
+);
+void free_filelist(char **filelist);
+char **get_priority_filelist(const char *directory, const char *pattern);
+
+/* this interface is exposed to be used by internal operations.
+ */
+char* plugin_get_dn (const struct slapdplugin *plugin);
+/* determine whether operation should be allowed based on plugin configuration */
+PRBool plugin_allow_internal_op (Slapi_DN *target, struct slapdplugin *plugin);
+/* build operation action bitmap based on plugin configuration and actions specified for the operation */
+int plugin_build_operation_action_bitmap (int input_actions, const struct slapdplugin *plugin);
+const struct slapdplugin* plugin_get_server_plg ();
+
+/* opshared.c - functions shared between regular and internal operations */
+void op_shared_search (Slapi_PBlock *pb, int send_result);
+int op_shared_is_allowed_attr (const char *attr_name, int replicated_op);
+void op_shared_log_error_access (Slapi_PBlock *pb, const char *type, const char *dn, const char *msg);
+int search_register_reslimits( void );
+
+
+/* plugin_internal_op.c - functions shared by several internal operations */
+LDAPMod **normalize_mods2bvals(const LDAPMod **mods);
+Slapi_Operation* internal_operation_new(unsigned long op_type, int flags);
+void internal_getresult_callback(struct conn *unused1, struct op *op, int err, char *unused2,
+ char *unused3, int unused4, struct berval **unused5);
+/* allow/disallow operation based of the plugin configuration */
+PRBool allow_operation (Slapi_PBlock *pb);
+/* set operation configuration based on the plugin configuration */
+void set_config_params (Slapi_PBlock *pb);
+/* set parameters common for all internal operations */
+void set_common_params (Slapi_PBlock *pb);
+void do_ps_service(Slapi_Entry *e, Slapi_Entry *eprev, int chgtype, int chgnum);
+void modify_update_last_modified_attr(Slapi_PBlock *pb, Slapi_Mods *smods);
+
+/*
+ * debugdump.cpp
+ */
+void debug_thread_wrapper(void *thread_start_function);
+
+/*
+ * counters.c
+ */
+void counters_as_entry(Slapi_Entry* e);
+void counters_to_errors_log(const char *text);
+
+/*
+ * ch_malloc.c
+ */
+void slapi_ch_start_recording();
+void slapi_ch_stop_recording();
+
+/*
+ * snmpcollator.c
+ */
+void snmp_as_entry(Slapi_Entry* e);
+
+/*
+ * subentry.c
+ */
+int subentry_check_filter(Slapi_Filter *f);
+void subentry_create_filter(Slapi_Filter** filter);
+
+/*
+ * vattr.c
+ */
+void vattr_init();
+void vattr_cleanup();
+void vattrcache_entry_READ_LOCK(const Slapi_Entry *e);
+void vattrcache_entry_READ_UNLOCK(const Slapi_Entry *e);
+void vattrcache_entry_WRITE_LOCK(const Slapi_Entry *e);
+void vattrcache_entry_WRITE_UNLOCK(const Slapi_Entry *e);
+
+/*
+ * slapd_plhash.c - supplement to NSPR plhash
+ */
+void *PL_HashTableLookup_const(
+ void *ht, /* really a PLHashTable */
+ const void *key);
+
+/*
+ * mapping_tree.c
+ */
+int mapping_tree_init();
+void mapping_tree_free ();
+int mapping_tree_get_extension_type ();
+
+/*
+ * connection.c
+ */
+int connection_acquire_nolock (Connection *conn);
+int connection_release_nolock (Connection *conn);
+int connection_is_free (Connection *conn);
+int connection_is_active_nolock (Connection *conn);
+
+/*
+ * bind.c
+ */
+void add_auth_response_control( Slapi_PBlock *pb, const char *binddn );
+
+/*
+ * saslbind.c
+ */
+int ids_sasl_init(void);
+char **ids_sasl_listmech(Slapi_PBlock *pb);
+void ids_sasl_check_bind(Slapi_PBlock *pb);
+void ids_sasl_server_new(Connection *conn);
+
+/*
+ * daemon.c
+ */
+#ifndef LINUX
+void slapd_do_nothing(int);
+#endif
+#ifndef _WIN32
+void slapd_wait4child (int);
+#else
+void *slapd_service_exit_wait();
+#endif
+
+/*
+ * main.c
+ */
+#if ( defined( hpux ) || defined( irix ))
+void * signal2sigaction( int s, void *a );
+#endif
+#endif /* _PROTO_SLAP */
diff --git a/ldap/servers/slapd/psearch.c b/ldap/servers/slapd/psearch.c
new file mode 100644
index 00000000..f1df43a6
--- /dev/null
+++ b/ldap/servers/slapd/psearch.c
@@ -0,0 +1,723 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ *
+ * psearch.c - persistent search
+ * August 1997, ggood@netscape.com
+ *
+ * Open issues:
+ * - we increment and decrement active_threads in here. Are there
+ * conditions under which this can prevent a server shutdown?
+ */
+
+#include "slap.h"
+#include "fe.h"
+
+/*
+ * A structure used to create a linked list
+ * of entries being sent by a particular persistent
+ * search result thread.
+ * The ctrl is an "Entry Modify Notification" control
+ * which we may send back with entries.
+ */
+typedef struct _ps_entry_queue_node {
+ Slapi_Entry *pe_entry;
+ LDAPControl *pe_ctrls[2];
+ struct _ps_entry_queue_node *pe_next;
+} PSEQNode;
+
+/*
+ * Information about a single persistent search
+ */
+typedef struct _psearch {
+ Slapi_PBlock *ps_pblock;
+ PRLock *ps_lock;
+ PRThread *ps_tid;
+ PRInt32 ps_complete;
+ PSEQNode *ps_eq_head;
+ PSEQNode *ps_eq_tail;
+ time_t ps_lasttime;
+ int ps_changetypes;
+ int ps_send_entchg_controls;
+ struct _psearch *ps_next;
+} PSearch;
+
+/*
+ * A list of outstanding persistent searches.
+ */
+typedef struct _psearch_list {
+ rwl *pl_rwlock; /* R/W lock struct to serialize access */
+ PSearch *pl_head; /* Head of list */
+ PRLock *pl_cvarlock; /* Lock for cvar */
+ PRCondVar *pl_cvar; /* ps threads sleep on this */
+} PSearch_List;
+
+/*
+ * Convenience macros for locking the list of persistent searches
+ */
+#define PSL_LOCK_READ() psearch_list->pl_rwlock->rwl_acquire_read_lock( psearch_list->pl_rwlock)
+#define PSL_UNLOCK_READ() psearch_list->pl_rwlock->rwl_relinquish_read_lock( psearch_list->pl_rwlock )
+#define PSL_LOCK_WRITE() psearch_list->pl_rwlock->rwl_acquire_write_lock( psearch_list->pl_rwlock )
+#define PSL_UNLOCK_WRITE() psearch_list->pl_rwlock->rwl_relinquish_write_lock( psearch_list->pl_rwlock )
+
+
+/*
+ * Convenience macro for checking if the Persistent Search subsystem has
+ * been initialized.
+ */
+#define PS_IS_INITIALIZED() (psearch_list != NULL)
+
+/* Main list of outstanding persistent searches */
+static PSearch_List *psearch_list = NULL;
+
+/* Forward declarations */
+static void ps_send_results( void *arg );
+static PSearch *psearch_alloc();
+static void ps_add_ps( PSearch *ps );
+static void ps_remove( PSearch *dps );
+static void pe_ch_free( PSEQNode **pe );
+static int create_entrychange_control( int chgtype, int chgnum,
+ const char *prevdn, LDAPControl **ctrlp );
+
+
+/*
+ * Initialize the list structure which contains the list
+ * of outstanding persistent searches. This must be
+ * called early during server startup.
+ */
+void
+ps_init_psearch_system()
+{
+ if ( !PS_IS_INITIALIZED()) {
+ psearch_list = (PSearch_List *) slapi_ch_calloc( 1, sizeof( PSearch_List ));
+ if (( psearch_list->pl_rwlock = rwl_new()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "init_psearch_list: cannot initialize lock structure. "
+ "The server is terminating.\n", 0, 0, 0 );
+ exit( -1 );
+ }
+ if (( psearch_list->pl_cvarlock = PR_NewLock()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "init_psearch_list: cannot create new lock. "
+ "The server is terminating.\n", 0, 0, 0 );
+ exit( -1 );
+ }
+ if (( psearch_list->pl_cvar = PR_NewCondVar( psearch_list->pl_cvarlock )) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "init_psearch_list: cannot create new condition variable. "
+ "The server is terminating.\n", 0, 0, 0 );
+ exit( -1 );
+ }
+ psearch_list->pl_head = NULL;
+ }
+}
+
+
+
+
+/*
+ * Close all outstanding persistent searches.
+ * To be used when the server is shutting down.
+ */
+void
+ps_stop_psearch_system()
+{
+ PSearch *ps;
+
+ if ( PS_IS_INITIALIZED()) {
+ PSL_LOCK_WRITE();
+ for ( ps = psearch_list->pl_head; NULL != ps; ps = ps->ps_next ) {
+ PR_AtomicIncrement( &ps->ps_complete );
+ }
+ PSL_UNLOCK_WRITE();
+ ps_wakeup_all();
+ }
+}
+
+
+
+
+/*
+ * Add the given pblock to the list of outstanding persistent searches.
+ * Then, start a thread to send the results to the client as they
+ * are dispatched by add, modify, and modrdn operations.
+ */
+void
+ps_add( Slapi_PBlock *pb, int changetypes, int send_entchg_controls )
+{
+ PSearch *ps;
+
+ if ( PS_IS_INITIALIZED() && NULL != pb ) {
+ /* Create the new node */
+ ps = psearch_alloc();
+ ps->ps_pblock = pb;
+ ps->ps_changetypes = changetypes;
+ ps->ps_send_entchg_controls = send_entchg_controls;
+
+ /* Add it to the head of the list of persistent searches */
+ ps_add_ps( ps );
+
+ /* Start a thread to send the results */
+ ps->ps_tid = PR_CreateThread( PR_USER_THREAD, ps_send_results,
+ (void *) ps, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE );
+
+ /* Checking if the thread is succesfully created and
+ * if the thread is not created succesfully.... we send
+ * error messages to the Log file
+ */
+ if(NULL == (ps->ps_tid)){
+ int prerr;
+ prerr = PR_GetError();
+ LDAPDebug(LDAP_DEBUG_ANY,"persistent search PR_CreateThread()failed in the "
+ "ps_add function: " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ prerr, slapd_pr_strerror(prerr), 0);
+
+ /* Now remove the ps from the list so call the function ps_remove */
+ ps_remove(ps);
+ PR_DestroyLock ( ps->ps_lock );
+ ps->ps_lock = NULL;
+ slapi_ch_free((void **) &ps->ps_pblock );
+ slapi_ch_free((void **) &ps );
+ }
+ }
+}
+
+
+
+/*
+ * Remove the given PSearch from the list of outstanding persistent
+ * searches and delete its resources.
+ */
+static void
+ps_remove( PSearch *dps )
+{
+ PSearch *ps;
+
+ if ( PS_IS_INITIALIZED() && NULL != dps ) {
+ PSL_LOCK_WRITE();
+ if ( dps == psearch_list->pl_head ) {
+ /* Remove from head */
+ psearch_list->pl_head = psearch_list->pl_head->ps_next;
+ } else {
+ /* Find and remove from list */
+ ps = psearch_list->pl_head;
+ while ( NULL != ps->ps_next ) {
+ if ( ps->ps_next == dps ) {
+ ps->ps_next = ps->ps_next->ps_next;
+ break;
+ } else {
+ ps = ps->ps_next;
+ }
+ }
+ }
+ PSL_UNLOCK_WRITE();
+ }
+}
+
+/*
+ * Free a persistent search node (and everything it holds).
+ */
+static void
+pe_ch_free( PSEQNode **pe )
+{
+ if ( pe != NULL && *pe != NULL ) {
+ if ( (*pe)->pe_entry != NULL ) {
+ slapi_entry_free( (*pe)->pe_entry );
+ (*pe)->pe_entry = NULL;
+ }
+
+ if ( (*pe)->pe_ctrls[0] != NULL ) {
+ ldap_control_free( (*pe)->pe_ctrls[0] );
+ (*pe)->pe_ctrls[0] = NULL;
+ }
+
+ slapi_ch_free( (void **)pe );
+ }
+}
+
+
+/*
+ * Thread routine for sending search results to a client
+ * which is persistently waiting for them.
+ *
+ * This routine will terminate when either (a) the ps_complete
+ * flag is set, or (b) the associated operation is abandoned.
+ * In any case, the thread won't notice until it wakes from
+ * sleeping on the ps_list condition variable, so it needs
+ * to be awakened.
+ */
+static void
+ps_send_results( void *arg )
+{
+ PSearch *ps = (PSearch *)arg;
+ PSEQNode *peq, *peqnext;
+ struct slapi_filter *filter = 0;
+ char *base = NULL;
+ char *fstr = NULL;
+ char **pbattrs = NULL;
+ int conn_acq_flag = 0;
+
+ PR_AtomicIncrement( &active_threads );
+
+ /* need to acquire a reference to this connection so that it will not
+ be released or cleaned up out from under us */
+ PR_Lock( ps->ps_pblock->pb_conn->c_mutex );
+ conn_acq_flag = connection_acquire_nolock(ps->ps_pblock->pb_conn);
+ PR_Unlock( ps->ps_pblock->pb_conn->c_mutex );
+
+ if (conn_acq_flag) {
+ slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
+ "conn=%d op=%d Could not acquire the connection - psearch aborted\n",
+ ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid);
+ }
+
+ PR_Lock( psearch_list->pl_cvarlock );
+
+ while ( (conn_acq_flag == 0) && !ps->ps_complete ) {
+ /* Check for an abandoned operation */
+ if ( ps->ps_pblock->pb_op == NULL || slapi_op_abandoned( ps->ps_pblock ) ) {
+ slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
+ "conn=%d op=%d The operation has been abandoned\n",
+ ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid);
+ break;
+ }
+ if ( NULL == ps->ps_eq_head ) {
+ /* Nothing to do */
+ PR_WaitCondVar( psearch_list->pl_cvar, PR_INTERVAL_NO_TIMEOUT );
+ } else {
+ /* dequeue the item */
+ int attrsonly;
+ char **attrs;
+ LDAPControl **ectrls;
+ Slapi_Entry *ec;
+ Slapi_Filter *f = NULL;
+
+ PR_Lock( ps->ps_lock );
+
+ peq = ps->ps_eq_head;
+ ps->ps_eq_head = peq->pe_next;
+ if ( NULL == ps->ps_eq_head ) {
+ ps->ps_eq_tail = NULL;
+ }
+
+ PR_Unlock( ps->ps_lock );
+
+ /* Get all the information we need to send the result */
+ ec = peq->pe_entry;
+ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_ATTRS, &attrs );
+ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
+ if ( !ps->ps_send_entchg_controls || peq->pe_ctrls[0] == NULL ) {
+ ectrls = NULL;
+ } else {
+ ectrls = peq->pe_ctrls;
+ }
+
+ /*
+ * Send the result. Since send_ldap_search_entry can block for
+ * up to 30 minutes, we relinquish all locks before calling it.
+ */
+ PR_Unlock(psearch_list->pl_cvarlock);
+
+ /*
+ * The entry is in the right scope and matches the filter
+ * but we need to redo the filter test here to check access
+ * controls. See the comments at the slapi_filter_test()
+ * call in ps_service_persistent_searches().
+ */
+ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_FILTER, &f );
+
+ /* See if the entry meets the filter and ACL criteria */
+ if ( slapi_vattr_filter_test( ps->ps_pblock, ec, f,
+ 1 /* verify_access */ ) == 0 ) {
+ int rc = 0;
+ slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_RESULT_ENTRY, ec );
+ rc = send_ldap_search_entry( ps->ps_pblock, ec,
+ ectrls, attrs, attrsonly );
+ if (rc) {
+ slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
+ "conn=%d op=%d Error %d sending entry %s with op status %d\n",
+ ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid,
+ rc, slapi_entry_get_dn_const(ec), ps->ps_pblock->pb_op->o_status);
+ }
+ }
+
+ PR_Lock(psearch_list->pl_cvarlock);
+
+ /* Deallocate our wrapper for this entry */
+ pe_ch_free( &peq );
+ }
+ }
+ PR_Unlock( psearch_list->pl_cvarlock );
+ ps_remove( ps );
+
+ /* indicate the end of search */
+ plugin_call_plugins( ps->ps_pblock , SLAPI_PLUGIN_POST_SEARCH_FN );
+
+ /* free things from the pblock that were not free'd in do_search() */
+ /* Free SLAPI_SEARCH_* before deleting op since those are held by op */
+ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_TARGET, &base );
+ slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_TARGET, NULL );
+ slapi_ch_free_string(&base);
+
+ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_STRFILTER, &fstr );
+ slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_STRFILTER, NULL );
+ slapi_ch_free_string(&fstr);
+
+ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_ATTRS, &pbattrs );
+ slapi_pblock_set( ps->ps_pblock, SLAPI_SEARCH_ATTRS, NULL );
+ if ( pbattrs != NULL )
+ {
+ charray_free( pbattrs );
+ }
+
+ slapi_pblock_get(ps->ps_pblock, SLAPI_SEARCH_FILTER, &filter );
+ slapi_pblock_set(ps->ps_pblock, SLAPI_SEARCH_FILTER, NULL );
+ slapi_filter_free(filter, 1);
+
+ /* Clean up the connection structure */
+ PR_Lock( ps->ps_pblock->pb_conn->c_mutex );
+
+ slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
+ "conn=%d op=%d Releasing the connection and operation\n",
+ ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid);
+ /* Delete this op from the connection's list */
+ connection_remove_operation( ps->ps_pblock->pb_conn, ps->ps_pblock->pb_op );
+ operation_free(&(ps->ps_pblock->pb_op),ps->ps_pblock->pb_conn);
+ ps->ps_pblock->pb_op=NULL;
+
+ /* Decrement the connection refcnt */
+ if (conn_acq_flag == 0) { /* we acquired it, so release it */
+ connection_release_nolock (ps->ps_pblock->pb_conn);
+ }
+ PR_Unlock( ps->ps_pblock->pb_conn->c_mutex );
+
+ PR_DestroyLock ( ps->ps_lock );
+ ps->ps_lock = NULL;
+
+ slapi_ch_free((void **) &ps->ps_pblock );
+ for ( peq = ps->ps_eq_head; peq; peq = peqnext) {
+ peqnext = peq->pe_next;
+ pe_ch_free( &peq );
+ }
+ slapi_ch_free((void **) &ps );
+ PR_AtomicDecrement(&active_threads);
+}
+
+
+
+/*
+ * Allocate and initialize an empty PSearch node.
+ */
+static PSearch *
+psearch_alloc()
+{
+ PSearch *ps;
+
+ ps = (PSearch *) slapi_ch_calloc( 1, sizeof( PSearch ));
+
+ ps->ps_pblock = NULL;
+ if (( ps->ps_lock = PR_NewLock()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "psearch_add: cannot create new lock. "
+ "Persistent search abandoned.\n", 0, 0, 0 );
+ return( NULL );
+ }
+ ps->ps_tid = (PRThread *) NULL;
+ ps->ps_complete = 0;
+ ps->ps_eq_head = ps->ps_eq_tail = (PSEQNode *) NULL;
+ ps->ps_lasttime = (time_t) 0L;
+ ps->ps_next = NULL;
+ return ps;
+}
+
+
+
+/*
+ * Add the given persistent search to the
+ * head of the list of persistent searches.
+ */
+static void
+ps_add_ps( PSearch *ps )
+{
+ if ( PS_IS_INITIALIZED() && NULL != ps ) {
+ PSL_LOCK_WRITE();
+ ps->ps_next = psearch_list->pl_head;
+ psearch_list->pl_head = ps;
+ PSL_UNLOCK_WRITE();
+ }
+}
+
+
+
+/*
+ * Wake up all threads sleeping on
+ * the psearch_list condition variable.
+ */
+void
+ps_wakeup_all()
+{
+ if ( PS_IS_INITIALIZED()) {
+ PR_Lock( psearch_list->pl_cvarlock );
+ PR_NotifyAllCondVar( psearch_list->pl_cvar );
+ PR_Unlock( psearch_list->pl_cvarlock );
+ }
+}
+
+
+/*
+ * Check if there are any persistent searches. If so,
+ * the check to see if the chgtype is one of those the
+ * client is interested in. If so, then check to see if
+ * the entry matches any of the filters the searches.
+ * If so, then enqueue the entry on that persistent search's
+ * ps_entryqueue and signal it to wake up and send the entry.
+ *
+ * Note that if eprev is NULL we assume that the entry's DN
+ * was not changed by the op. that called this function. If
+ * chgnum is 0 it is unknown so we won't ever send it to a
+ * client in the EntryChangeNotification control.
+ */
+void
+ps_service_persistent_searches( Slapi_Entry *e, Slapi_Entry *eprev, int chgtype,
+ int chgnum )
+{
+ LDAPControl *ctrl = NULL;
+ PSearch *ps = NULL;
+ PSEQNode *pe = NULL;
+ int matched = 0;
+ const char *edn;
+
+ if ( !PS_IS_INITIALIZED()) {
+ return;
+ }
+
+ if ( NULL == e ) {
+ /* For now, some backends such as the chaining backend do not provide a post-op entry */
+ return;
+ }
+
+ PSL_LOCK_READ();
+ edn = slapi_entry_get_dn_const(e);
+
+ for ( ps = psearch_list ? psearch_list->pl_head : NULL; NULL != ps; ps = ps->ps_next ) {
+ Slapi_DN base;
+ Slapi_Filter *f;
+ char *basedn;
+ int scope;
+
+ /* Skip the node that doesn't meet the changetype,
+ * or is unable to use the change in ps_send_results()
+ */
+ if (( ps->ps_changetypes & chgtype ) == 0 ||
+ ps->ps_pblock->pb_op == NULL ||
+ slapi_op_abandoned( ps->ps_pblock ) ) {
+ continue;
+ }
+
+ slapi_log_error(SLAPI_LOG_CONNS, "Persistent Search",
+ "conn=%d op=%d entry %s with chgtype %d "
+ "matches the ps changetype %d\n",
+ ps->ps_pblock->pb_conn->c_connid, ps->ps_pblock->pb_op->o_opid,
+ edn, chgtype, ps->ps_changetypes);
+
+ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_FILTER, &f );
+ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_TARGET, &basedn );
+ slapi_pblock_get( ps->ps_pblock, SLAPI_SEARCH_SCOPE, &scope );
+ slapi_sdn_init_dn_byref(&base,basedn);
+
+
+ /*
+ * See if the entry meets the scope and filter criteria.
+ * We cannot do the acl check here as this thread
+ * would then potentially clash with the ps_send_results()
+ * thread on the aclpb in ps->ps_pblock.
+ * By avoiding the acl check in this thread, and leaving all the acl
+ * checking to the ps_send_results() thread we avoid
+ * the ps_pblock contention problem.
+ * The lesson here is "Do not give multiple threads arbitary access
+ * to the same pblock" this kind of muti-threaded access
+ * to the same pblock must be done carefully--there is currently no
+ * generic satisfactory way to do this.
+ */
+ if ( slapi_sdn_scope_test( slapi_entry_get_sdn_const(e), &base, scope ) &&
+ slapi_vattr_filter_test( ps->ps_pblock, e, f, 0 /* verify_access */ ) == 0 ) {
+ PSEQNode *pOldtail;
+
+ /* The scope and the filter match - enqueue it */
+
+ matched++;
+ pe = (PSEQNode *)slapi_ch_calloc( 1, sizeof( PSEQNode ));
+ pe->pe_entry = slapi_entry_dup( e );
+ if ( ps->ps_send_entchg_controls ) {
+ /* create_entrychange_control() is more
+ * expensive than slapi_dup_control()
+ */
+ if ( ctrl == NULL ) {
+ int rc;
+ rc = create_entrychange_control( chgtype, chgnum,
+ eprev ? slapi_entry_get_dn_const(eprev) : NULL,
+ &ctrl );
+ if ( rc != LDAP_SUCCESS ) {
+ char ebuf[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY, "ps_service_persistent_searches:"
+ " unable to create EntryChangeNotification control for"
+ " entry \"%s\" -- control won't be sent.\n",
+ escape_string( slapi_entry_get_dn_const(e), ebuf), 0, 0 );
+ }
+ }
+ if ( ctrl ) {
+ pe->pe_ctrls[0] = slapi_dup_control( ctrl );
+ }
+ }
+
+ /* Put it on the end of the list for this pers search */
+ PR_Lock( ps->ps_lock );
+ pOldtail = ps->ps_eq_tail;
+ ps->ps_eq_tail = pe;
+ if ( NULL == ps->ps_eq_head ) {
+ ps->ps_eq_head = ps->ps_eq_tail;
+ }
+ else {
+ pOldtail->pe_next = ps->ps_eq_tail;
+ }
+ PR_Unlock( ps->ps_lock );
+ }
+ slapi_sdn_done(&base);
+ }
+
+ PSL_UNLOCK_READ();
+
+ /* Were there any matches? */
+ if ( matched ) {
+ ldap_control_free( ctrl );
+ /* Turn 'em loose */
+ ps_wakeup_all();
+ LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: enqueued entry "
+ "\"%s\" on %d persistent search lists\n", slapi_entry_get_dn_const(e), matched, 0 );
+ } else {
+ LDAPDebug( LDAP_DEBUG_TRACE, "ps_service_persistent_searches: entry "
+ "\"%s\" not enqueued on any persistent search lists\n", slapi_entry_get_dn_const(e), 0, 0 );
+ }
+
+}
+
+/*
+ * Parse the value from an LDAPv3 "Persistent Search" control. They look
+ * like this:
+ *
+ * PersistentSearch ::= SEQUENCE {
+ * changeTypes INTEGER,
+ * -- the changeTypes field is the logical OR of
+ * -- one or more of these values: add (1), delete (2),
+ * -- modify (4), modDN (8). It specifies which types of
+ * -- changes will cause an entry to be returned.
+ * changesOnly BOOLEAN, -- skip initial search?
+ * returnECs BOOLEAN, -- return "Entry Change" controls?
+ * }
+ *
+ * Return an LDAP error code (LDAP_SUCCESS if all goes well).
+ *
+ * This function is standalone; it does not require initialization of
+ * the PS subsystem.
+ */
+int
+ps_parse_control_value( struct berval *psbvp, int *changetypesp, int *changesonlyp, int *returnecsp )
+{
+ int rc= LDAP_SUCCESS;
+ long long_changetypesp;
+
+ if ( psbvp->bv_len == 0 || psbvp->bv_val == NULL )
+ {
+ rc= LDAP_PROTOCOL_ERROR;
+ }
+ else
+ {
+ BerElement *ber= ber_init( psbvp );
+ if ( ber == NULL )
+ {
+ rc= LDAP_OPERATIONS_ERROR;
+ }
+ else
+ {
+ if ( ber_scanf( ber, "{ibb}", &long_changetypesp, changesonlyp, returnecsp ) == LBER_ERROR )
+ {
+ rc= LDAP_PROTOCOL_ERROR;
+ }
+ *changetypesp = (int) long_changetypesp;
+ /* the ber encoding is no longer needed */
+ ber_free(ber,1);
+ }
+ }
+
+ return( rc );
+}
+
+
+/*
+ * Create an LDAPv3 "Entry Change Notification" control. They look like this:
+ *
+ * EntryChangeNotification ::= SEQUENCE {
+ * changeType ENUMERATED {
+ * add (1), -- LDAP_CHANGETYPE_ADD
+ * delete (2), -- LDAP_CHANGETYPE_DELETE
+ * modify (4), -- LDAP_CHANGETYPE_MODIFY
+ * moddn (8), -- LDAP_CHANGETYPE_MODDN
+ * },
+ * previousDN LDAPDN OPTIONAL, -- included for MODDN ops. only
+ * changeNumber INTEGER OPTIONAL, -- included if supported by DSA
+ * }
+ *
+ * This function returns an LDAP error code (LDAP_SUCCESS if all goes well).
+ * The value returned in *ctrlp should be free'd use ldap_control_free().
+ * If chgnum is 0 we omit it from the control.
+ */
+static int
+create_entrychange_control( int chgtype, int chgnum, const char *dn,
+ LDAPControl **ctrlp )
+{
+ int rc;
+ BerElement *ber;
+ struct berval *bvp;
+ const char *prevdn= dn;
+
+ if ( prevdn == NULL ) {
+ prevdn = "";
+ }
+
+ if ( ctrlp == NULL || ( ber = der_alloc()) == NULL ) {
+ return( LDAP_OPERATIONS_ERROR );
+ }
+
+ *ctrlp = NULL;
+
+ if (( rc = ber_printf( ber, "{e", chgtype )) != -1 ) {
+ if ( chgtype == LDAP_CHANGETYPE_MODDN ) {
+ rc = ber_printf( ber, "s", prevdn );
+ }
+ if ( rc != -1 && chgnum != 0 ) {
+ rc = ber_printf( ber, "i", chgnum );
+ }
+ if ( rc != -1 ) {
+ rc = ber_printf( ber, "}" );
+ }
+ }
+
+ if ( rc != -1 ) {
+ rc = ber_flatten( ber, &bvp );
+ }
+ ber_free( ber, 1 );
+
+ if ( rc == -1 ) {
+ return( LDAP_OPERATIONS_ERROR );
+ }
+
+ *ctrlp = (LDAPControl *)slapi_ch_malloc( sizeof( LDAPControl ));
+ (*ctrlp)->ldctl_iscritical = 0;
+ (*ctrlp)->ldctl_oid = slapi_ch_strdup( LDAP_CONTROL_ENTRYCHANGE );
+ (*ctrlp)->ldctl_value = *bvp; /* struct copy */
+
+ bvp->bv_val = NULL;
+ ber_bvfree( bvp );
+
+ return( LDAP_SUCCESS );
+}
diff --git a/ldap/servers/slapd/pw.c b/ldap/servers/slapd/pw.c
new file mode 100644
index 00000000..ab026de7
--- /dev/null
+++ b/ldap/servers/slapd/pw.c
@@ -0,0 +1,1540 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * slapd hashed password routines
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#if defined(NET_SSL)
+#include <sechash.h>
+#if defined( _WIN32 )
+#undef DEBUG
+#endif /* _WIN32 */
+#if defined( _WIN32 )
+#undef LDAPDebug
+#endif /* _WIN32 */
+
+#endif /* NET_SSL */
+
+#include "slap.h"
+
+
+#define DENY_PW_CHANGE_ACI "(targetattr = \"userPassword\") ( version 3.0; acl \"disallow_pw_change_aci\"; deny (write ) userdn = \"ldap:///self\";)"
+#define GENERALIZED_TIME_LENGTH 15
+
+static int pw_in_history(Slapi_Value **history_vals, const Slapi_Value *pw_val);
+static int update_pw_history( Slapi_PBlock *pb, char *dn, char *old_pw );
+static int check_trivial_words (Slapi_PBlock *, Slapi_Entry *, Slapi_Value **, char *attrtype );
+static int pw_boolean_str2value (const char *str);
+/* static LDAPMod* pw_malloc_mod (char* name, char* value, int mod_op); */
+
+
+/*
+ * Like slapi_value_find, except for passwords.
+ * returns 0 if password "v" is found in "vals"; non-zero otherwise
+ */
+SLAPI_DEPRECATED int
+slapi_pw_find(
+ struct berval **vals,
+ struct berval *v
+)
+{
+ int rc;
+ Slapi_Value **svin_vals= NULL;
+ Slapi_Value svin_v;
+ slapi_value_init_berval(&svin_v,v);
+ valuearray_init_bervalarray(vals,&svin_vals); /* JCM SLOW FUNCTION */
+ rc= slapi_pw_find_sv(svin_vals,&svin_v);
+ valuearray_free(&svin_vals);
+ value_done(&svin_v);
+ return rc;
+}
+
+/*
+ * Like slapi_value_find, except for passwords.
+ * returns 0 if password "v" is found in "vals"; non-zero otherwise
+ */
+
+int
+slapi_pw_find_sv(
+ Slapi_Value **vals,
+ const Slapi_Value *v
+)
+{
+ struct pw_scheme *pwsp;
+ char *valpwd;
+ int i;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> slapi_pw_find value: \"%s\"\n", slapi_value_get_string(v), 0, 0 ); /* JCM Innards */
+
+ for ( i = 0; vals[i] != NULL; i++ )
+ {
+ pwsp = pw_val2scheme( (char*)slapi_value_get_string(vals[i]), &valpwd, 1 ); /* JCM Innards*/
+ if ( pwsp != NULL &&
+ (*(pwsp->pws_cmp))( (char*)slapi_value_get_string(v), valpwd ) == 0 ) /* JCM Innards*/
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "<= slapi_pw_find matched \"%s\" using scheme \"%s\"\n",
+ valpwd, pwsp->pws_name, 0 );
+ free_pw_scheme( pwsp );
+ return( 0 ); /* found it */
+ }
+ free_pw_scheme( pwsp );
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= slapi_pw_find no matching password\n", 0, 0, 0 );
+
+ return( 1 ); /* no match */
+}
+
+/* Checks if the specified value is encoded.
+ Returns 1 if it is and 0 otherwise
+ */
+int slapi_is_encoded (char *value)
+{
+ struct pw_scheme *is_hashed = NULL;
+ int is_encoded = 0;
+
+ is_hashed = pw_val2scheme ( value, NULL, 0 );
+ if ( is_hashed != NULL )
+ {
+ free_pw_scheme( is_hashed );
+ is_encoded = 1;
+ }
+ return (is_encoded);
+}
+
+
+char* slapi_encode (char *value, char *alg)
+{
+ struct pw_scheme *enc_scheme = NULL;
+ char *hashedval = NULL;
+ int need_to_free = 0;
+
+ if (alg == NULL) /* use server encoding scheme */
+ {
+ slapdFrontendConfig_t * slapdFrontendConfig = getFrontendConfig();
+
+ enc_scheme = slapdFrontendConfig->pw_storagescheme;
+
+ if (enc_scheme == NULL)
+ {
+ slapi_log_error( SLAPI_LOG_FATAL, NULL,
+ "slapi_encode: no server scheme\n" );
+ return NULL;
+ }
+ }
+ else
+ {
+ enc_scheme = pw_name2scheme(alg);
+ if ( enc_scheme == NULL)
+ {
+ char * scheme_list = plugin_get_pwd_storage_scheme_list(PLUGIN_LIST_PWD_STORAGE_SCHEME);
+ if ( scheme_list != NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, NULL,
+ "slapi_encode: invalid scheme - %s\n"
+ "Valid values are: %s\n", alg, scheme_list );
+ slapi_ch_free((void **)&scheme_list);
+ } else {
+ slapi_log_error( SLAPI_LOG_FATAL, NULL,
+ "slapi_encode: invalid scheme - %s\n"
+ "no pwdstorage scheme plugin loaded", alg);
+ }
+ return NULL;
+ }
+ need_to_free = 1;
+ }
+
+ hashedval = enc_scheme->pws_enc(value);
+ if (need_to_free)
+ free_pw_scheme(enc_scheme);
+
+ return hashedval;
+}
+
+/*
+ * Return a pointer to the pw_scheme struct for scheme "name"
+ * NULL is returned is no matching scheme is found.
+ */
+
+struct pw_scheme *
+pw_name2scheme( char *name )
+{
+ struct pw_scheme *pwsp;
+ struct slapdplugin *p;
+
+ if ( (p = plugin_get_pwd_storage_scheme(name, strlen(name), PLUGIN_LIST_PWD_STORAGE_SCHEME)) != NULL ) {
+ pwsp = (struct pw_scheme *) slapi_ch_malloc (sizeof(struct pw_scheme));
+ if ( pwsp != NULL ) {
+ typedef int (*CMPFP)(char *, char *);
+ typedef char * (*ENCFP)(char *);
+ pwsp->pws_name = slapi_ch_strdup( p->plg_pwdstorageschemename );
+ pwsp->pws_cmp = (CMPFP)p->plg_pwdstorageschemecmp;
+ pwsp->pws_enc = (ENCFP)p->plg_pwdstorageschemeenc;
+ pwsp->pws_len = strlen(pwsp->pws_name) ;
+ return(pwsp);
+ }
+ }
+
+ return( NULL );
+}
+
+void free_pw_scheme(struct pw_scheme *pwsp)
+{
+ if ( pwsp != NULL )
+ {
+ slapi_ch_free( (void**)&pwsp->pws_name );
+ slapi_ch_free( (void**)&pwsp );
+ }
+}
+
+/*
+ * Return the password scheme for value "val". This is determined by
+ * checking "val" against our scheme prefixes.
+ *
+ * If "valpwdp" is not NULL, it is set to point to the value with any
+ * prefix removed.
+ *
+ * If no matching scheme is found and first_is_default is non-zero, the
+ * first scheme is returned. If no matching scheme is found and
+ * first_is_default is zero, NULL is returned.
+ */
+
+struct pw_scheme *
+pw_val2scheme( char *val, char **valpwdp, int first_is_default )
+{
+ struct pw_scheme *pwsp;
+ int namelen, prefixlen;
+ char *end, buf[ PWD_MAX_NAME_LEN + 1 ];
+
+ if ( *val != PWD_HASH_PREFIX_START ||
+ ( end = strchr( val, PWD_HASH_PREFIX_END )) == NULL ||
+ ( namelen = end - val - 1 ) > PWD_MAX_NAME_LEN ) {
+ if ( !first_is_default ) {
+ return( NULL );
+ }
+ pwsp = pw_name2scheme("CLEAR"); /* default to first scheme */
+ prefixlen = 0;
+ } else {
+ memcpy( buf, val + 1, namelen );
+ buf[ namelen ] = '\0';
+ pwsp = pw_name2scheme(buf);
+ if ( pwsp == NULL ) {
+ if ( !first_is_default ) {
+ return( NULL );
+ }
+ pwsp = pw_name2scheme("CLEAR");
+ prefixlen = 0;
+ } else {
+ prefixlen = pwsp->pws_len + 2;
+ }
+ }
+
+ if ( valpwdp != NULL ) {
+ *valpwdp = val + prefixlen;
+ }
+
+ return( pwsp );
+}
+
+
+/*
+ * re-encode the password values in "vals" using a hashing algorithm
+ * vals[n] is assumed to be an alloc'd Slapi_Value that can be free'd and
+ * replaced. If a value is already encoded, we do not re-encode it.
+ * Return 0 if all goes well and < 0 if an error occurs.
+ */
+
+int
+pw_encodevals( Slapi_Value **vals )
+{
+ int i;
+ char *enc;
+ slapdFrontendConfig_t * slapdFrontendConfig = getFrontendConfig();
+
+
+ if ( vals == NULL || slapdFrontendConfig->pw_storagescheme == NULL ||
+ slapdFrontendConfig->pw_storagescheme->pws_enc == NULL ) {
+ return( 0 );
+ }
+
+ for ( i = 0; vals[ i ] != NULL; ++i ) {
+ struct pw_scheme *pwsp;
+ if ( (pwsp=pw_val2scheme( (char*)slapi_value_get_string(vals[ i ]), NULL, 0)) != NULL ) { /* JCM Innards */
+ free_pw_scheme( pwsp );
+ continue; /* don't touch pre-encoded values */
+ }
+ if (( enc = (*slapdFrontendConfig->pw_storagescheme->pws_enc)( (char*)slapi_value_get_string(vals[ i ]) )) /* JCM Innards */
+ == NULL ) {
+ free_pw_scheme( pwsp );
+ return( -1 );
+ }
+ slapi_value_free(&vals[ i ]);
+ vals[ i ] = slapi_value_new_string_passin(enc);
+ free_pw_scheme( pwsp );
+ }
+
+ return( 0 );
+}
+
+/*
+ * Check if the prefix of the cipher is the one that is supposed to be
+ * Extract from the whole cipher the encrypted password (remove the prefix)
+ */
+int checkPrefix(char *cipher, char *schemaName, char **encrypt)
+{
+ int namelen;
+ /* buf contains the extracted schema name */
+ char *end, buf[ 3*PWD_MAX_NAME_LEN + 1 ];
+
+ if ( (*cipher == PWD_HASH_PREFIX_START) &&
+ ((end = strchr(cipher, PWD_HASH_PREFIX_END)) != NULL) &&
+ ((namelen = end - cipher - 1 ) <= (3*PWD_MAX_NAME_LEN)) )
+ {
+ memcpy( buf, cipher + 1, namelen );
+ buf[ namelen ] = '\0';
+ if ( strcasecmp( buf, schemaName) != 0 )
+ {
+ /* schema names are different, error */
+ return 1;
+ }
+ else
+ {
+ /* extract the encrypted password */
+ *encrypt = cipher + strlen(schemaName) + 2;
+ return 0;
+ }
+ }
+ /* cipher is not prefixed, already in clear ? */
+ return -1;
+}
+
+/*
+* Decode the attribute "attr_name" with one of the reversible encryption mechanism
+* Returns -1 on error
+* Returns 0 on success with strdup'ed plain
+* Returns 1 on success with *plain=cipher
+*/
+int
+pw_rever_decode(char *cipher, char **plain, const char * attr_name)
+{
+ char *dec = NULL;
+ struct pw_scheme *pwsp = NULL;
+ struct slapdplugin *p = NULL;
+
+ int ret_code = 1;
+
+ for ( p = get_plugin_list(PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME); p != NULL; p = p->plg_next )
+ {
+ char *L_attr = NULL;
+ int i = 0;
+ char *encrypt = NULL;
+ int prefixOK = -1;
+
+ /* Get the appropriate decoding function */
+ for ( L_attr = p->plg_argv[i]; i<p->plg_argc; L_attr = p->plg_argv[++i] )
+ {
+ if (slapi_attr_types_equivalent(L_attr, attr_name))
+ {
+ typedef int (*CMPFP)(char *, char *);
+ typedef char * (*ENCFP)(char *);
+
+ pwsp = (struct pw_scheme *) slapi_ch_calloc (1, sizeof(struct pw_scheme));
+
+ pwsp->pws_dec = (ENCFP)p->plg_pwdstorageschemedec;
+ pwsp->pws_name = slapi_ch_strdup( p->plg_pwdstorageschemename );
+ pwsp->pws_len = strlen(pwsp->pws_name) ;
+ if ( pwsp->pws_dec != NULL )
+ {
+ /* check that the prefix of the cipher is the same name
+ as the schema name */
+ prefixOK = checkPrefix(cipher, pwsp->pws_name, &encrypt);
+ if ( prefixOK == -1 )
+ {
+ /* no prefix, already in clear ? */
+ *plain = cipher;
+ ret_code = 1;
+ goto free_and_return;
+ }
+ else if ( prefixOK == 1 )
+ {
+ /* schema names are different */
+ ret_code = -1;
+ goto free_and_return;
+ }
+ else
+ {
+ if ( ( *plain = (pwsp->pws_dec)( encrypt )) == NULL )
+ {
+ /* pb during decoding */
+ ret_code = -1;
+ goto free_and_return;
+ }
+ /* decoding is OK */
+ ret_code = 0;
+ goto free_and_return;
+ }
+ }
+ free_pw_scheme( pwsp );
+ pwsp = NULL;
+ }
+ }
+ }
+free_and_return:
+ if ( pwsp != NULL )
+ {
+ free_pw_scheme( pwsp );
+ }
+ return(ret_code);
+}
+
+/*
+ * Encode the attribute "attr_name" with one of the reversible encryption mechanism
+ */
+int
+pw_rever_encode(Slapi_Value **vals, char * attr_name)
+{
+ char *enc;
+ struct pw_scheme *pwsp = NULL;
+ struct slapdplugin *p;
+
+ if (vals == NULL){
+ return (0);
+ }
+
+ for ( p = get_plugin_list(PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME); p != NULL; p = p->plg_next )
+ {
+ char *L_attr = NULL;
+ int i = 0;
+
+ /* Get the appropriate encoding function */
+ for ( L_attr = p->plg_argv[i]; i<p->plg_argc; L_attr = p->plg_argv[++i] )
+ {
+ if (slapi_attr_types_equivalent(L_attr, attr_name))
+ {
+ typedef int (*CMPFP)(char *, char *);
+ typedef char * (*ENCFP)(char *);
+
+ pwsp = (struct pw_scheme *) slapi_ch_calloc (1, sizeof(struct pw_scheme));
+
+ pwsp->pws_enc = (ENCFP)p->plg_pwdstorageschemeenc;
+ pwsp->pws_name = slapi_ch_strdup( p->plg_pwdstorageschemename );
+ if ( pwsp->pws_enc != NULL )
+ {
+ for ( i = 0; vals[i] != NULL; ++i )
+ {
+ char *encrypt = NULL;
+ int prefixOK;
+
+ prefixOK = checkPrefix((char*)slapi_value_get_string(vals[i]),
+ pwsp->pws_name,
+ &encrypt);
+ if ( prefixOK == 0 )
+ {
+ /* Don't touch already encoded value */
+ continue; /* don't touch pre-encoded values */
+ }
+ else if (prefixOK == 1 )
+ {
+ /* credential is already encoded, but not with this schema. Error */
+ free_pw_scheme( pwsp );
+ return( -1 );
+ }
+
+
+ if ( ( enc = (pwsp->pws_enc)( (char*)slapi_value_get_string(vals[ i ]) )) == NULL )
+ {
+ free_pw_scheme( pwsp );
+ return( -1 );
+ }
+ slapi_value_free(&vals[ i ]);
+ vals[ i ] = slapi_value_new_string_passin(enc);
+ free_pw_scheme( pwsp );
+ return (0);
+ }
+ }
+ }
+ }
+ }
+
+ free_pw_scheme( pwsp );
+ return(-1);
+}
+
+/* ONREPL - below are the functions moved from pw_mgmt.c.
+ this is done to allow the functions to be used
+ by functions linked into libslapd.
+ */
+
+/* update_pw_info is called after password is modified successfully */
+/* it should update passwordHistory, and passwordExpirationTime */
+/* SLAPI_ENTRY_POST_OP must be set */
+
+int
+update_pw_info ( Slapi_PBlock *pb , char *old_pw) {
+
+ Slapi_Mods smods;
+ char *timestr;
+ Slapi_PBlock *mod_result_pb = NULL;
+ time_t pw_exp_date;
+ time_t cur_time;
+ char *dn;
+ passwdPolicy *pwpolicy = NULL;
+
+ cur_time = current_time();
+ slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn );
+
+ pwpolicy = new_passwdPolicy(pb, dn);
+
+ /* update passwordHistory */
+ if ( old_pw != NULL && pwpolicy->pw_history == 1 ) {
+ update_pw_history(pb, dn, old_pw);
+ slapi_ch_free ( (void**)&old_pw );
+ }
+
+ slapi_mods_init(&smods, 0);
+
+ /* update password allow change time */
+ if ( pwpolicy->pw_minage != 0) {
+ timestr = format_genTime( time_plus_sec( cur_time,
+ pwpolicy->pw_minage ));
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordAllowChangeTime", timestr);
+ slapi_ch_free((void **)&timestr);
+ }
+
+ /* Fix for Bug 560707
+ Removed the restriction that the lock variables (retry count) will
+ be set only when root resets the passwd.
+ Now admins will also have these privileges.
+ */
+ if (pwpolicy->pw_lockout) {
+ set_retry_cnt_mods (pb, &smods, 0 );
+ }
+
+ /* Clear the passwordgraceusertime from the user entry */
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordgraceusertime", "0");
+
+ /* if the password is reset by root, mark it the first time logon */
+
+ if ( pb->pb_requestor_isroot == 1 &&
+ pwpolicy->pw_must_change){
+ pw_exp_date = NO_TIME;
+
+ } else if ( pwpolicy->pw_exp == 1 ) {
+ Slapi_Entry *pse = NULL;
+
+ /* update password expiration date */
+ pw_exp_date = time_plus_sec ( cur_time,
+ pwpolicy->pw_maxage );
+
+ slapi_pblock_get(pb,SLAPI_ENTRY_POST_OP,&pse);
+
+ if (pse) {
+ char *prev_exp_date_str;
+
+ /* if the password expiry time is SLAPD_END_TIME,
+ * don't roll it back
+ */
+ prev_exp_date_str = slapi_entry_attr_get_charptr(pse,"passwordExpirationTime");
+
+ if (prev_exp_date_str) {
+ time_t prev_exp_date;
+
+ prev_exp_date = parse_genTime(prev_exp_date_str);
+
+ if (prev_exp_date == NO_TIME ||
+ prev_exp_date == NOT_FIRST_TIME) {
+ /* ignore as will replace */
+ } else if (prev_exp_date == SLAPD_END_TIME) {
+ /* Special entries' passwords never expire */
+ slapi_ch_free((void**)&prev_exp_date_str);
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ delete_passwdPolicy(&pwpolicy);
+ return 0;
+ }
+
+ slapi_ch_free((void**)&prev_exp_date_str);
+ }
+ } /* post op entry */
+
+ } else if (pwpolicy->pw_must_change) {
+ /*
+ * pw is not changed by root, and must change pw first time
+ * log on
+ */
+ pw_exp_date = NOT_FIRST_TIME;
+ } else {
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ delete_passwdPolicy(&pwpolicy);
+ return 0;
+ }
+
+ delete_passwdPolicy(&pwpolicy);
+
+ timestr = format_genTime ( pw_exp_date );
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestr);
+ slapi_ch_free((void **)&timestr);
+
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "0");
+
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ /* reset c_needpw to 0 */
+ pb->pb_conn->c_needpw = 0;
+ return 0;
+}
+
+int
+check_pw_minage ( Slapi_PBlock *pb, const Slapi_DN *sdn, struct berval **vals)
+{
+ char *dn= (char*)slapi_sdn_get_ndn(sdn); /* jcm - Had to cast away const */
+ passwdPolicy *pwpolicy=NULL;
+ int pwresponse_req = 0;
+
+ pwpolicy = new_passwdPolicy(pb, dn);
+ slapi_pblock_get ( pb, SLAPI_PWPOLICY, &pwresponse_req );
+
+ if ( !pb->pb_op->o_isroot &&
+ pwpolicy->pw_minage != 0 ) {
+
+ Slapi_Entry *e;
+ char *passwordAllowChangeTime;
+
+ /* retrieve the entry */
+ e = get_entry ( pb, dn );
+ if ( e == NULL ) {
+ delete_passwdPolicy(&pwpolicy);
+ return ( -1 );
+ }
+ /* get passwordAllowChangeTime attribute */
+ passwordAllowChangeTime= slapi_entry_attr_get_charptr(e, "passwordAllowChangeTime");
+
+ if (passwordAllowChangeTime!=NULL)
+ {
+ time_t pw_allowchange_date;
+ char *cur_time_str = NULL;
+
+ pw_allowchange_date = parse_genTime(passwordAllowChangeTime);
+ slapi_ch_free((void **) &passwordAllowChangeTime );
+
+ /* check if allow to change the password */
+ cur_time_str = format_genTime ( current_time() );
+ if ( difftime ( pw_allowchange_date,
+ parse_genTime ( cur_time_str )) > 0 )
+ {
+ if ( pwresponse_req == 1 ) {
+ pwpolicy_make_response_control ( pb, -1, -1,
+ LDAP_PWPOLICY_PWDTOOYOUNG );
+ }
+ send_ldap_result ( pb,
+ LDAP_CONSTRAINT_VIOLATION, NULL,
+ "within password minimum age", 0, NULL );
+ slapi_entry_free( e );
+ slapi_ch_free((void **) &cur_time_str );
+ delete_passwdPolicy(&pwpolicy);
+ return ( 1 );
+ }
+ slapi_ch_free((void **) &cur_time_str );
+ }
+ slapi_entry_free( e );
+ }
+ delete_passwdPolicy(&pwpolicy);
+ return ( 0 );
+}
+
+/* check_pw_syntax is called before add or modify operation on userpassword attribute*/
+
+int
+check_pw_syntax ( Slapi_PBlock *pb, const Slapi_DN *sdn, Slapi_Value **vals,
+ char **old_pw, Slapi_Entry *e, int mod_op)
+{
+ Slapi_Attr* attr;
+ int i, pwresponse_req = 0;
+ char *dn= (char*)slapi_sdn_get_ndn(sdn); /* jcm - Had to cast away const */
+ passwdPolicy *pwpolicy = NULL;
+
+ pwpolicy = new_passwdPolicy(pb, dn);
+ slapi_pblock_get ( pb, SLAPI_PWPOLICY, &pwresponse_req );
+
+ if ( pwpolicy->pw_syntax == 1 ) {
+ /* check for the minimum password lenght */
+ for ( i = 0; vals[ i ] != NULL; ++i ) {
+ if ( pwpolicy->pw_minlength
+ > (int)slapi_value_get_length(vals[ i ]) ) { /* jcm: had to cast unsigned int to signed int */
+ if ( pwresponse_req == 1 ) {
+ pwpolicy_make_response_control ( pb, -1, -1,
+ LDAP_PWPOLICY_PWDTOOSHORT );
+ }
+ send_ldap_result ( pb,
+ LDAP_CONSTRAINT_VIOLATION, NULL,
+ "invalid password syntax", 0, NULL );
+ delete_passwdPolicy(&pwpolicy);
+ return ( 1 );
+ }
+ }
+ }
+
+ /* get the entry and check for the password history and syntax if this is called by a modify operation */
+ if ( mod_op ) {
+ /* retrieve the entry */
+ e = get_entry ( pb, dn );
+ if ( e == NULL ) {
+ delete_passwdPolicy(&pwpolicy);
+ return ( -1 );
+ }
+
+ /* check for password history */
+ if ( pwpolicy->pw_history == 1 ) {
+ attr = attrlist_find(e->e_attrs, "passwordHistory");
+ if (attr &&
+ !valueset_isempty(&attr->a_present_values))
+ {
+ Slapi_Value **va= attr_get_present_values(attr);
+ if ( pw_in_history( va, vals[0] ) == 0 ) {
+ if ( pwresponse_req == 1 ) {
+ pwpolicy_make_response_control ( pb, -1, -1,
+ LDAP_PWPOLICY_PWDINHISTORY );
+ }
+ send_ldap_result ( pb,
+ LDAP_CONSTRAINT_VIOLATION, NULL,
+ "password in history", 0, NULL );
+ slapi_entry_free( e );
+ delete_passwdPolicy(&pwpolicy);
+ return ( 1 );
+ }
+ }
+
+ /* get current password. check it and remember it */
+ attr = attrlist_find(e->e_attrs, "userpassword");
+ if (attr && !valueset_isempty(&attr->a_present_values))
+ {
+ Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
+ if (slapi_is_encoded((char*)slapi_value_get_string(vals[0])))
+ {
+ if (slapi_attr_value_find(attr, (struct berval *)slapi_value_get_berval(vals[0])) == 0 )
+ {
+ send_ldap_result ( pb,
+ LDAP_CONSTRAINT_VIOLATION ,NULL,
+ "password in history", 0, NULL);
+ slapi_entry_free( e );
+ delete_passwdPolicy(&pwpolicy);
+ return ( 1 );
+ }
+ } else
+ {
+ if ( slapi_pw_find_sv ( va, vals[0] ) == 0 )
+ {
+ send_ldap_result ( pb,
+ LDAP_CONSTRAINT_VIOLATION ,NULL,
+ "password in history", 0, NULL);
+ slapi_entry_free( e );
+ delete_passwdPolicy(&pwpolicy);
+ return ( 1 );
+ }
+ }
+ /* We copy the 1st value of the userpassword attribute.
+ * This is because password policy assumes that there's only one
+ * password in the userpassword attribute.
+ */
+ *old_pw = slapi_ch_strdup(slapi_value_get_string(va[0]));
+ } else {
+ *old_pw = NULL;
+ }
+ }
+
+ if ( pwpolicy->pw_syntax == 1 ) {
+ /* check for trivial words */
+ if ( check_trivial_words ( pb, e, vals, "uid" ) == 1 ||
+ check_trivial_words ( pb, e, vals, "cn" ) == 1 ||
+ check_trivial_words ( pb, e, vals, "sn" ) == 1 ||
+ check_trivial_words ( pb, e, vals, "givenname" ) == 1 ||
+ check_trivial_words ( pb, e, vals, "ou" ) == 1 ||
+ check_trivial_words ( pb, e, vals, "mail" ) == 1) {
+ slapi_entry_free( e );
+ delete_passwdPolicy(&pwpolicy);
+ return 1;
+ }
+ }
+ }
+
+ delete_passwdPolicy(&pwpolicy);
+
+ if ( mod_op ) {
+ /* free e only when called by modify operation */
+ slapi_entry_free( e );
+ }
+ return 0; /* success */
+
+}
+
+static
+int update_pw_history( Slapi_PBlock *pb, char *dn, char *old_pw ) {
+
+ time_t t, old_t, cur_time;
+ int i = 0, oldest = 0;
+ int res;
+ Slapi_Entry *e;
+ Slapi_Attr *attr;
+ LDAPMod attribute;
+ char *values_replace[25]; /* 2-24 passwords in history */
+ LDAPMod *list_of_mods[2];
+ Slapi_PBlock mod_pb;
+ char *history_str;
+ char *str;
+ passwdPolicy *pwpolicy = NULL;
+
+ pwpolicy = new_passwdPolicy(pb, dn);
+
+ /* retrieve the entry */
+ e = get_entry ( pb, dn );
+ if ( e == NULL ) {
+ delete_passwdPolicy(&pwpolicy);
+ return ( 1 );
+ }
+
+ history_str = (char *)slapi_ch_malloc(GENERALIZED_TIME_LENGTH + strlen(old_pw) + 1);
+ /* get password history, and find the oldest password in history */
+ cur_time = current_time ();
+ old_t = cur_time;
+ str = format_genTime ( cur_time );
+ attr = attrlist_find(e->e_attrs, "passwordHistory");
+ if (attr && !valueset_isempty(&attr->a_present_values))
+ {
+ Slapi_Value **va= valueset_get_valuearray(&attr->a_present_values);
+ for ( i = oldest = 0 ;
+ (va[i] != NULL) && (slapi_value_get_length(va[i]) > 0) ;
+ i++ ) {
+
+ values_replace[i] = (char*)slapi_value_get_string(va[i]);
+ strncpy( history_str, values_replace[i], GENERALIZED_TIME_LENGTH);
+ history_str[GENERALIZED_TIME_LENGTH] = '\0';
+ if (history_str[GENERALIZED_TIME_LENGTH - 1] != 'Z'){
+ /* The time is not a generalized Time. Probably a password history from 4.x */
+ history_str[GENERALIZED_TIME_LENGTH - 1] = '\0';
+ }
+ t = parse_genTime ( history_str );
+ if ( difftime ( t, old_t ) < 0 ) {
+ oldest = i;
+ old_t = t;
+ }
+ }
+ }
+ strcpy ( history_str, str );
+ strcat ( history_str, old_pw );
+ if ( i == pwpolicy->pw_inhistory ) {
+ /* replace the oldest password in history */
+ values_replace [oldest] = history_str;
+ values_replace[i]=NULL;
+ } else {
+ /* add old_pw at the end of password history */
+ values_replace[i] = history_str;
+ values_replace[++i]=NULL;
+ }
+
+ /* modify the attribute */
+ attribute.mod_type = "passwordHistory";
+ attribute.mod_op = LDAP_MOD_REPLACE;
+ attribute.mod_values = values_replace;
+
+ list_of_mods[0] = &attribute;
+ list_of_mods[1] = NULL;
+
+ pblock_init(&mod_pb);
+ slapi_modify_internal_set_pb(&mod_pb, dn, list_of_mods, NULL, NULL,
+ pw_get_componentID(), 0);
+ slapi_modify_internal_pb(&mod_pb);
+ slapi_pblock_get(&mod_pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ if (res != LDAP_SUCCESS){
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: passwordPolicy modify error %d on entry '%s'\n",
+ res, dn, 0);
+ }
+
+ pblock_done(&mod_pb);
+
+ slapi_ch_free((void **) &str );
+ slapi_ch_free((void **) &history_str );
+ slapi_entry_free( e );
+ delete_passwdPolicy(&pwpolicy);
+ return 0;
+}
+
+static
+int pw_in_history( Slapi_Value **history_vals, const Slapi_Value *pw_val)
+{
+ Slapi_Value *history[25];
+ Slapi_Value historycv[25];
+ int i;
+ int ret = -1;
+ const char *pw_str = slapi_value_get_string(pw_val);
+
+ if (slapi_is_encoded((char*)pw_str)){
+ /* If the password is encoded, we just do a string match with all previous passwords */
+ for ( i = 0; history_vals[i] != NULL; i++){
+ const char * h_val = slapi_value_get_string(history_vals[i]);
+
+ if ( h_val != NULL &&
+ slapi_value_get_length(history_vals[i]) >= 14 )
+ {
+ int pos = 14;
+ if (h_val[pos] == 'Z')
+ pos++;
+ if (strcmp(&(h_val[pos]), pw_str) == 0){
+ /* Password found */
+ /* Let's just return */
+ return (0);
+ }
+ }
+ }
+ }
+ else { /* Password is in clear */
+ /* strip the timestamps */
+ for ( i = 0; history_vals[i] != NULL; i++ )
+ {
+ char *h_val = (char *)slapi_value_get_string(history_vals[i]);
+ size_t h_len = slapi_value_get_length(history_vals[i]);
+
+ historycv[i].v_csnset = NULL; /* JCM - I don't understand this */
+ history[i] = &historycv[i];
+ if ( h_val != NULL &&
+ h_len >= 14 )
+ {
+ /* LP: With the new genTime, the password history format has changed */
+ int pos = 14;
+ if (h_val[pos] == 'Z')
+ pos++;
+ historycv[i].bv.bv_val = &(h_val[pos]);
+ historycv[i].bv.bv_len = h_len - pos;
+ } else {
+ historycv[i].bv.bv_val = NULL;
+ historycv[i].bv.bv_len = 0;
+ }
+ }
+ history[i] = NULL;
+ ret = slapi_pw_find_sv( history, pw_val);
+ }
+
+ return ( ret );
+}
+
+int
+add_pwd_control ( Slapi_PBlock *pb, char *arg, long time) {
+ LDAPControl new_ctrl;
+ char buf[12];
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> add_pwd_control\n", 0, 0, 0 );
+
+ sprintf( buf, "%ld", time );
+ new_ctrl.ldctl_oid = arg;
+ new_ctrl.ldctl_value.bv_val = buf;
+ new_ctrl.ldctl_value.bv_len = strlen( buf );
+ new_ctrl.ldctl_iscritical = 0; /* 0 = false. */
+
+ if ( slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, &new_ctrl ) != 0 ) {
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+void
+pw_mod_allowchange_aci(int pw_prohibit_change) {
+ const Slapi_DN *base;
+ char *values_mod[2];
+ LDAPMod mod;
+ LDAPMod *mods[2];
+ char *aci_pw = NULL;
+ Slapi_Backend *be;
+ char *cookie = NULL;
+
+ mods[0] = &mod;
+ mods[1] = NULL;
+ mod.mod_type = "aci";
+ mod.mod_values = values_mod;
+
+ if (pw_prohibit_change) {
+ mod.mod_op = LDAP_MOD_ADD;
+ }
+ else
+ {
+ /* Allow change password by default */
+ /* remove the aci if it is there. it is ok to fail */
+ mod.mod_op = LDAP_MOD_DELETE;
+ }
+
+ be = slapi_get_first_backend (&cookie);
+ /* Foreach backend... */
+ while (be)
+ {
+ /* Don't add aci on a chaining backend holding remote entries */
+ if((!be->be_private) && (!slapi_be_is_flag_set(be,SLAPI_BE_FLAG_REMOTE_DATA)))
+ {
+ /* There's only One suffix per DB now. No need to loop */
+ base = slapi_be_getsuffix(be, 0);
+ if (base != NULL)
+ {
+ Slapi_PBlock pb;
+ int rc;
+
+ pblock_init (&pb);
+ values_mod[0] = DENY_PW_CHANGE_ACI;
+ values_mod[1] = NULL;
+ slapi_modify_internal_set_pb(&pb, slapi_sdn_get_dn(base), mods, NULL, NULL, pw_get_componentID(), 0);
+ slapi_modify_internal_pb(&pb);
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &rc);
+ if (rc == LDAP_SUCCESS){
+ /*
+ ** Since we modified the acl
+ ** successfully, let's update the
+ ** in-memory acl list
+ */
+ slapi_pblock_set(&pb, SLAPI_TARGET_DN, (char*)slapi_sdn_get_dn(base) ); /* jcm: cast away const */
+ plugin_call_acl_mods_update (&pb, LDAP_REQ_MODIFY );
+ }
+ pblock_done(&pb);
+ }
+ }
+ be = slapi_get_next_backend (cookie);
+ }
+ slapi_ch_free((void **) &cookie);
+}
+
+void
+add_password_attrs( Slapi_PBlock *pb, Operation *op, Slapi_Entry *e )
+{
+ struct berval bv;
+ struct berval *bvals[2];
+ Slapi_Attr **a, **next;
+ passwdPolicy *pwpolicy = NULL;
+ char *dn = slapi_entry_get_ndn(e);
+
+ pwpolicy = new_passwdPolicy(pb, dn);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "add_password_attrs\n", 0, 0, 0 );
+
+ bvals[0] = &bv;
+ bvals[1] = NULL;
+
+ if ( pwpolicy->pw_must_change) {
+ /* must change password when first time logon */
+ bv.bv_val = format_genTime ( NO_TIME );
+ } else {
+ /* If passwordexpirationtime is specified by the user, don't
+ try to assign the initial value */
+ for ( a = &e->e_attrs; *a != NULL; a = next ) {
+ if ( strcasecmp( (*a)->a_type,
+ "passwordexpirationtime" ) == 0) {
+ delete_passwdPolicy(&pwpolicy);
+ return;
+ }
+ next = &(*a)->a_next;
+ }
+
+ bv.bv_val = format_genTime ( time_plus_sec ( current_time (),
+ pwpolicy->pw_maxage ) );
+ }
+ if ( pwpolicy->pw_exp || pwpolicy->pw_must_change ) {
+ bv.bv_len = strlen( bv.bv_val );
+ slapi_entry_attr_merge( e, "passwordexpirationtime", bvals );
+ }
+ slapi_ch_free((void **) &bv.bv_val );
+
+ /*
+ * If the password minimum age is not 0, calculate when the password
+ * is allowed to be changed again and store the result
+ * in passwordallowchangetime in the user's entry.
+ */
+ if ( pwpolicy->pw_minage != 0 ) {
+ bv.bv_val = format_genTime ( time_plus_sec ( current_time (),
+ pwpolicy->pw_minage ) );
+ bv.bv_len = strlen( bv.bv_val );
+
+ slapi_entry_attr_merge( e, "passwordallowchangetime", bvals );
+ slapi_ch_free((void **) &bv.bv_val );
+ }
+
+ delete_passwdPolicy(&pwpolicy);
+}
+
+static int
+check_trivial_words (Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Value **vals, char *attrtype )
+{
+ Slapi_Attr *attr;
+ int i, pwresponse_req = 0;
+
+ slapi_pblock_get ( pb, SLAPI_PWPOLICY, &pwresponse_req );
+ attr = attrlist_find(e->e_attrs, attrtype);
+ if (attr && !valueset_isempty(&attr->a_present_values))
+ {
+ Slapi_Value **va= attr_get_present_values(attr);
+ for ( i = 0; va[i] != NULL; i++ )
+ {
+ if( strcasecmp( slapi_value_get_string(va[i]), slapi_value_get_string(vals[0])) == 0) /* JCM Innards */
+ {
+ if ( pwresponse_req == 1 ) {
+ pwpolicy_make_response_control ( pb, -1, -1,
+ LDAP_PWPOLICY_INVALIDPWDSYNTAX );
+ }
+ send_ldap_result ( pb,
+ LDAP_CONSTRAINT_VIOLATION, NULL,
+ "Password failed triviality check."
+ " Please choose a different password.",
+ 0, NULL );
+ return ( 1 );
+ }
+ }
+ }
+ return ( 0 );
+}
+
+
+void
+pw_add_allowchange_aci(Slapi_Entry *e, int pw_prohibit_change) {
+ char *aci_pw = NULL;
+ const char *aciattr = "aci";
+
+ aci_pw = slapi_ch_strdup(DENY_PW_CHANGE_ACI);
+
+ if (pw_prohibit_change) {
+ /* Add ACI */
+ slapi_entry_add_string(e, aciattr, aci_pw);
+ } else {
+ /* Remove ACI */
+ slapi_entry_delete_string(e, aciattr, aci_pw);
+ }
+ slapi_ch_free((void **) &aci_pw);
+}
+
+/* This function creates a passwdPolicy structure, loads it from either
+ * slapdFrontendconfig or the entry pointed by pwdpolicysubentry and
+ * returns the structure.
+ */
+passwdPolicy *
+new_passwdPolicy(Slapi_PBlock *pb, char *dn)
+{
+ Slapi_ValueSet *values = NULL;
+ Slapi_Entry *e = NULL, *pw_entry = NULL;
+ int type_name_disposition = 0;
+ char *actual_type_name = NULL;
+ int attr_free_flags = 0;
+ int rc=0;
+ passwdPolicy *pwdpolicy = NULL;
+ Slapi_Attr *attr;
+ char *attr_name;
+ Slapi_Value **sval;
+ slapdFrontendConfig_t *slapdFrontendConfig;
+ Slapi_Operation *op;
+ char ebuf[ BUFSIZ ];
+ int optype = -1;
+
+ slapdFrontendConfig = getFrontendConfig();
+ pwdpolicy = (passwdPolicy *)slapi_ch_calloc(1, sizeof(passwdPolicy));
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op);
+ slapi_pblock_get( pb, SLAPI_OPERATION_TYPE, &optype );
+
+ if (slapdFrontendConfig->pwpolicy_local == 1) {
+ if ( !operation_is_flag_set( op, OP_FLAG_INTERNAL ) && dn ) {
+
+ /* If we're doing an add, COS does not apply yet so we check
+ parents for the pwdpolicysubentry. We look only for virtual
+ attributes, because real ones are for single-target policy. */
+ if (optype == SLAPI_OPERATION_ADD) {
+ char *parentdn = slapi_ch_strdup(dn);
+ char *nextdn = NULL;
+ while ((nextdn = slapi_dn_parent( parentdn )) != NULL) {
+ if (((e = get_entry( pb, nextdn )) != NULL)) {
+ if ((slapi_vattr_values_get(e, "pwdpolicysubentry",
+ &values, &type_name_disposition, &actual_type_name,
+ SLAPI_VIRTUALATTRS_REQUEST_POINTERS |
+ SLAPI_VIRTUALATTRS_ONLY,
+ &attr_free_flags)) == 0) {
+ /* pwdpolicysubentry found! */
+ break;
+ } else {
+ /* Parent didn't have it, check grandparent... */
+ slapi_ch_free_string( &parentdn );
+ parentdn = nextdn;
+ slapi_entry_free( e );
+ e = NULL;
+ }
+ } else {
+ /* Reached the top without finding a pwdpolicysubentry. */
+ break;
+ }
+ }
+
+ slapi_ch_free_string( &parentdn );
+ slapi_ch_free_string( &nextdn );
+
+ /* If we're not doing an add, we look for the pwdpolicysubentry
+ attribute in the target entry itself. */
+ } else {
+ if ( (e = get_entry( pb, dn )) != NULL ) {
+ rc = slapi_vattr_values_get(e, "pwdpolicysubentry", &values,
+ &type_name_disposition, &actual_type_name,
+ SLAPI_VIRTUALATTRS_REQUEST_POINTERS, &attr_free_flags);
+ if (rc) {
+ values = NULL;
+ }
+ }
+ }
+
+ if (values != NULL) {
+ Slapi_Value *v = NULL;
+ const struct berval *bvp = NULL;
+
+ if ( ((rc = slapi_valueset_first_value( values, &v )) != -1) &&
+ ( bvp = slapi_value_get_berval( v )) != NULL ) {
+ if ( bvp != NULL ) {
+ /* we got the pwdpolicysubentry value */
+ pw_entry = get_entry ( pb, bvp->bv_val);
+ }
+ }
+
+ slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
+
+ slapi_entry_free( e );
+
+ if ( pw_entry == NULL ) {
+ LDAPDebug(LDAP_DEBUG_ANY, "loading global password policy for %s"
+ "--local policy entry not found\n", escape_string(dn, ebuf),0,0);
+ goto done;
+ }
+
+ for (slapi_entry_first_attr(pw_entry, &attr); attr;
+ slapi_entry_next_attr(pw_entry, attr, &attr))
+ {
+ slapi_attr_get_type(attr, &attr_name);
+ if (!strcasecmp(attr_name, "passwordminage")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_minage = slapi_value_get_long(*sval);
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordmaxage")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_maxage = slapi_value_get_long(*sval);
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordwarning")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_warning = slapi_value_get_long(*sval);
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordhistory")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_history =
+ pw_boolean_str2value(slapi_value_get_string(*sval));
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordinhistory")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_inhistory = slapi_value_get_int(*sval);
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordlockout")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_lockout =
+ pw_boolean_str2value(slapi_value_get_string(*sval));
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordmaxfailure")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_maxfailure = slapi_value_get_int(*sval);
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordunlock")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_unlock =
+ pw_boolean_str2value(slapi_value_get_string(*sval));
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordlockoutduration")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_lockduration = slapi_value_get_long(*sval);
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordresetfailurecount")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_resetfailurecount = slapi_value_get_long(*sval);
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordchange")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_change =
+ pw_boolean_str2value(slapi_value_get_string(*sval));
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordmustchange")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_must_change =
+ pw_boolean_str2value(slapi_value_get_string(*sval));
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordchecksyntax")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_syntax =
+ pw_boolean_str2value(slapi_value_get_string(*sval));
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordminlength")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_minlength = slapi_value_get_int(*sval);
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordexp")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_exp =
+ pw_boolean_str2value(slapi_value_get_string(*sval));
+ }
+ }
+ else
+ if (!strcasecmp(attr_name, "passwordgracelimit")) {
+ if (sval = attr_get_present_values(attr)) {
+ pwdpolicy->pw_gracelimit = slapi_value_get_int(*sval);
+ }
+ }
+
+ } /* end of for() loop */
+ return pwdpolicy;
+ }
+ }
+ }
+
+done:
+ /* If we are here, that means we need to load the passwdPolicy
+ * structure from slapdFrontendconfig
+ */
+
+ *pwdpolicy = slapdFrontendConfig->pw_policy;
+ return pwdpolicy;
+
+} /* End of new_passwdPolicy() */
+
+void
+delete_passwdPolicy( passwdPolicy **pwpolicy)
+{
+ slapi_ch_free((void **)pwpolicy);
+}
+
+/*
+ * Encode the PWPOLICY RESPONSE control.
+ *
+ * Create a password policy response control,
+ * and add it to the PBlock to be returned to the client.
+ *
+ * Returns:
+ * success ( 0 )
+ * operationsError (1),
+ */
+int
+pwpolicy_make_response_control (Slapi_PBlock *pb, int seconds, int logins, int error)
+{
+ BerElement *ber= NULL;
+ struct berval *bvp = NULL;
+ int rc = -1;
+
+ /*
+ PasswordPolicyResponseValue ::= SEQUENCE {
+ warning [0] CHOICE OPTIONAL {
+ timeBeforeExpiration [0] INTEGER (0 .. maxInt),
+ graceLoginsRemaining [1] INTEGER (0 .. maxInt) }
+ error [1] ENUMERATED OPTIONAL {
+ passwordExpired (0),
+ accountLocked (1),
+ changeAfterReset (2),
+ passwordModNotAllowed (3),
+ mustSupplyOldPassword (4),
+ invalidPasswordSyntax (5),
+ passwordTooShort (6),
+ passwordTooYoung (7),
+ passwordInHistory (8) } }
+ */
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> pwpolicy_make_response_control", 0, 0, 0 );
+ if ( ( ber = ber_alloc()) == NULL )
+ {
+ return rc;
+ }
+
+ rc = ber_printf( ber, "{" );
+ if ( seconds >= 0 || logins >= 0 ) {
+ if ( seconds >= 0 ) {
+ rc = ber_printf( ber, "t{ti}", LDAP_TAG_PWP_WARNING,
+ LDAP_TAG_PWP_SECSLEFT,
+ seconds );
+ }
+ else {
+ rc = ber_printf( ber, "t{ti}", LDAP_TAG_PWP_WARNING,
+ LDAP_TAG_PWP_GRCLOGINS,
+ logins );
+ }
+ }
+ if ( error >= 0 ) {
+ rc = ber_printf( ber, "te", LDAP_TAG_PWP_ERROR, error );
+ }
+ rc = ber_printf( ber, "}" );
+
+ if ( rc != -1 )
+ {
+ rc = ber_flatten( ber, &bvp );
+ }
+
+ ber_free( ber, 1 );
+
+ if ( rc != -1 )
+ {
+ LDAPControl new_ctrl = {0};
+ new_ctrl.ldctl_oid = LDAP_X_CONTROL_PWPOLICY_RESPONSE;
+ new_ctrl.ldctl_value = *bvp;
+ new_ctrl.ldctl_iscritical = 0;
+ rc= slapi_pblock_set( pb, SLAPI_ADD_RESCONTROL, &new_ctrl );
+ ber_bvfree(bvp);
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= pwpolicy_make_response_control", 0, 0, 0 );
+
+ return (rc==-1?LDAP_OPERATIONS_ERROR:LDAP_SUCCESS);
+}
+
+static int
+pw_boolean_str2value (const char *str)
+{
+ if ( !strcasecmp(str, "true") ||
+ !strcasecmp(str, "on") ||
+ !strcasecmp(str, "1") ) {
+ return ( LDAP_ON );
+ }
+
+ if ( !strcasecmp(str, "false") ||
+ !strcasecmp(str, "off") ||
+ !strcasecmp(str, "0") ) {
+ return ( LDAP_OFF );
+ }
+
+ return (-1);
+}
+
+int
+check_pw_minage_value( const char *attr_name, char *value, long minval, long maxval, char *errorbuf )
+{
+ int retVal = LDAP_SUCCESS;
+ int age;
+ char *endPtr = NULL;
+
+ age = strtol(value, &endPtr, 0 );
+ if ( (age < 0) ||
+ (age > (MAX_ALLOWED_TIME_IN_SECS - current_time())) ||
+ (endPtr == NULL) || (endPtr == value) || !isdigit(*(endPtr-1)) )
+ {
+ PR_snprintf ( errorbuf, BUFSIZ,
+ "password minimum age \"%s\" seconds is invalid. ",
+ value );
+ retVal = LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ return retVal;
+}
+
+int
+check_pw_lockduration_value( const char *attr_name, char *value, long minval, long maxval, char *errorbuf )
+{
+ int retVal = LDAP_SUCCESS;
+ long duration = 0; /* in minutes */
+
+ /* in seconds */
+ duration = strtol (value, NULL, 0);
+
+ if ( duration <= 0 || duration > (MAX_ALLOWED_TIME_IN_SECS - current_time()) ) {
+ PR_snprintf ( errorbuf, BUFSIZ,
+ "password lockout duration \"%s\" seconds is invalid. ",
+ value );
+ retVal = LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ return retVal;
+}
+
+int
+check_pw_resetfailurecount_value( const char *attr_name, char *value, long minval, long maxval, char *errorbuf )
+{
+ int retVal = LDAP_SUCCESS;
+ long duration = 0; /* in minutes */
+
+ /* in seconds */
+ duration = strtol (value, NULL, 0);
+ if ( duration < 0 || duration > (MAX_ALLOWED_TIME_IN_SECS - current_time()) ) {
+ PR_snprintf ( errorbuf, BUFSIZ,
+ "password reset count duration \"%s\" seconds is invalid. ",
+ value );
+ retVal = LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ return retVal;
+}
+
+int
+check_pw_storagescheme_value( const char *attr_name, char *value, long minval, long maxval, char *errorbuf )
+{
+ int retVal = LDAP_SUCCESS;
+ struct pw_scheme *new_scheme = NULL;
+ char * scheme_list = NULL;
+
+ scheme_list = plugin_get_pwd_storage_scheme_list(PLUGIN_LIST_PWD_STORAGE_SCHEME);
+ new_scheme = pw_name2scheme(value);
+ if ( new_scheme == NULL) {
+ if ( scheme_list != NULL ) {
+ PR_snprintf ( errorbuf, BUFSIZ,
+ "%s: invalid scheme - %s. Valid schemes are: %s",
+ CONFIG_PW_STORAGESCHEME_ATTRIBUTE, value, scheme_list );
+ } else {
+ PR_snprintf ( errorbuf, BUFSIZ,
+ "%s: invalid scheme - %s (no pwdstorage scheme"
+ " plugin loaded)",
+ CONFIG_PW_STORAGESCHEME_ATTRIBUTE, value);
+ }
+ retVal = LDAP_CONSTRAINT_VIOLATION;
+ }
+ else if ( new_scheme->pws_enc == NULL )
+ {
+ /* For example: the NS-MTA-MD5 password scheme is for comparision only
+ and for backward compatibility with an Old Messaging Server that was
+ setting passwords in the directory already encrypted. The scheme cannot
+ and won't encrypt passwords if they are in clear. We don't take it
+ */
+
+ if ( scheme_list != NULL ) {
+ sprintf( errorbuf,
+ "%s: invalid encoding scheme - %s\nValid values are: %s\n",
+ CONFIG_PW_STORAGESCHEME_ATTRIBUTE, value, scheme_list );
+ }
+
+ retVal = LDAP_CONSTRAINT_VIOLATION;
+ }
+
+ slapi_ch_free_string(&scheme_list);
+
+ return retVal;
+}
+
diff --git a/ldap/servers/slapd/pw.h b/ldap/servers/slapd/pw.h
new file mode 100644
index 00000000..b74bbd66
--- /dev/null
+++ b/ldap/servers/slapd/pw.h
@@ -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 **/
+#ifndef _SLAPD_PW_H_
+#define _SLAPD_PW_H_
+
+#define PWD_MAX_NAME_LEN 10
+
+#define PWD_HASH_PREFIX_START '{'
+#define PWD_HASH_PREFIX_END '}'
+
+/* Password Policy Response Control stuff */
+#define LDAP_PWPOLICY_PWDEXPIRED 0
+#define LDAP_PWPOLICY_ACCTLOCKED 1
+#define LDAP_PWPOLICY_CHGAFTERRESET 2
+#define LDAP_PWPOLICY_PWDMODNOTALLOWED 3
+#define LDAP_PWPOLICY_MUSTSUPPLYOLDPWD 4
+#define LDAP_PWPOLICY_INVALIDPWDSYNTAX 5
+#define LDAP_PWPOLICY_PWDTOOSHORT 6
+#define LDAP_PWPOLICY_PWDTOOYOUNG 7
+#define LDAP_PWPOLICY_PWDINHISTORY 8
+
+/*
+ *
+ * structure for holding password scheme info.
+ */
+struct pw_scheme {
+ /* case-insensitive name used in prefix of passwords that use scheme */
+ char *pws_name;
+
+ /* length of pws_name */
+ int pws_len;
+
+ /* thread-safe comparison function; returns 0 for positive matches */
+ /* userpwd is value sent over LDAP bind; dbpwd is from the database */
+ int (*pws_cmp)( char *userpwd, char *dbpwd );
+
+ /* thread-safe encoding function (returns pointer to malloc'd string) */
+ char *(*pws_enc)( char *pwd );
+
+ /* thread-safe decoding function (returns pointer to malloc'd string) */
+ char *(*pws_dec)( char *pwd );
+};
+
+/*
+ * Public functions from pw.c:
+ */
+struct pw_scheme *pw_name2scheme( char *name );
+struct pw_scheme *pw_val2scheme( char *val, char **valpwdp, int first_is_default );
+int pw_encodevals( Slapi_Value **vals );
+int checkPrefix(char *cipher, char *schemaName, char **encrypt);
+struct passwordpolicyarray *new_passwdPolicy ( Slapi_PBlock *pb, char *dn );
+void delete_passwdPolicy( struct passwordpolicyarray **pwpolicy);
+int pwpolicy_make_response_control (Slapi_PBlock *pb, int seconds, int logins, int error);
+
+/* function for checking the values of fine grained password policy attributes */
+int check_pw_minage_value( const char *attr_name, char *value, long minval, long maxval, char *errorbuf );
+int check_pw_lockduration_value( const char *attr_name, char *value, long minval, long maxval, char *errorbuf );
+int check_pw_resetfailurecount_value( const char *attr_name, char *value, long minval, long maxval, char *errorbuf );
+int check_pw_storagescheme_value( const char *attr_name, char *value, long minval, long maxval, char *errorbuf );
+
+/*
+ * Public functions from pw_retry.c:
+ */
+Slapi_Entry *get_entry ( Slapi_PBlock *pb, const char *dn );
+void set_retry_cnt_mods ( Slapi_PBlock *pb, Slapi_Mods *smods, int count);
+
+#endif /* _SLAPD_PW_H_ */
diff --git a/ldap/servers/slapd/pw_mgmt.c b/ldap/servers/slapd/pw_mgmt.c
new file mode 100644
index 00000000..b400efab
--- /dev/null
+++ b/ldap/servers/slapd/pw_mgmt.c
@@ -0,0 +1,398 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* pw_mgmt.c
+*/
+
+#include <time.h>
+#include <string.h>
+#include "slap.h"
+
+/****************************************************************************/
+/* prototypes */
+/****************************************************************************/
+
+/* need_new_pw() is called when non rootdn bind operation succeeds with authentication */
+int
+need_new_pw( Slapi_PBlock *pb, long *t, Slapi_Entry *e, int pwresponse_req )
+{
+ time_t cur_time, pw_exp_date;
+ LDAPMod *mod;
+ Slapi_Mods smods;
+ double diff_t = 0;
+ char *cur_time_str = NULL;
+ char *passwordExpirationTime;
+ char *timestring;
+ char *dn;
+ passwdPolicy *pwpolicy = NULL;
+ int pwdGraceUserTime = 0;
+ char graceUserTime[8];
+
+ slapi_mods_init (&smods, 0);
+ dn = slapi_entry_get_ndn( e );
+ pwpolicy = new_passwdPolicy(pb, dn);
+
+ /* after the user binds with authentication, clear the retry count */
+ if ( pwpolicy->pw_lockout == 1)
+ {
+ if(slapi_entry_attr_get_int( e, "passwordRetryCount") > 0)
+ {
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordRetryCount", "0");
+ }
+ }
+
+ cur_time = current_time();
+
+ /* get passwordExpirationTime attribute */
+ passwordExpirationTime= slapi_entry_attr_get_charptr(e, "passwordExpirationTime");
+
+ if (passwordExpirationTime == NULL)
+ {
+ /* password expiration date is not set.
+ * This is ok for data that has been loaded via ldif2ldbm
+ * Set expiration time if needed,
+ * don't do further checking and return 0 */
+ if ( pwpolicy->pw_exp == 1) {
+ pw_exp_date = time_plus_sec ( cur_time,
+ pwpolicy->pw_maxage );
+
+ timestring = format_genTime (pw_exp_date);
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
+ slapi_ch_free((void **)&timestring);
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "0");
+
+ pw_apply_mods(dn, &smods);
+ }
+ slapi_mods_done(&smods);
+ delete_passwdPolicy(&pwpolicy);
+ return ( 0 );
+ }
+
+ pw_exp_date = parse_genTime(passwordExpirationTime);
+
+ slapi_ch_free((void**)&passwordExpirationTime);
+
+ /* Check if password has been reset */
+ if ( pw_exp_date == NO_TIME ) {
+
+ /* check if changing password is required */
+ if ( pwpolicy->pw_must_change ) {
+ /* set c_needpw for this connection to be true. this client
+ now can only change its own password */
+ pb->pb_conn->c_needpw = 1;
+ *t=0;
+ /* We need to include "changeafterreset" error in
+ * passwordpolicy response control. So, we will not be
+ * done here. We remember this scenario by (c_needpw=1)
+ * and check it before sending the control from various
+ * places. We will also add LDAP_CONTROL_PWEXPIRED control
+ * as the return value used to be (1).
+ */
+ goto skip;
+ }
+ /* Mark that first login occured */
+ pw_exp_date = NOT_FIRST_TIME;
+ timestring = format_genTime(pw_exp_date);
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
+ slapi_ch_free((void **)&timestring);
+ }
+
+skip:
+ /* if password never expires, don't need to go on; return 0 */
+ if ( pwpolicy->pw_exp == 0 ) {
+ /* check for "changeafterreset" condition */
+ if (pb->pb_conn->c_needpw == 1) {
+ if (pwresponse_req) {
+ pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_CHGAFTERRESET );
+ }
+ add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
+ }
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ delete_passwdPolicy(&pwpolicy);
+ return ( 0 );
+ }
+
+ /* check if password expired. If so, abort bind. */
+ cur_time_str = format_genTime ( cur_time );
+ if ( pw_exp_date != NO_TIME &&
+ pw_exp_date != NOT_FIRST_TIME &&
+ (diff_t = difftime ( pw_exp_date,
+ parse_genTime ( cur_time_str ))) <= 0 ) {
+
+ /* password has expired. Check the value of
+ * passwordGraceUserTime and compare it
+ * against the value of passwordGraceLimit */
+ pwdGraceUserTime = slapi_entry_attr_get_int( e, "passwordGraceUserTime");
+ if ( pwpolicy->pw_gracelimit > pwdGraceUserTime ) {
+ pwdGraceUserTime++;
+ sprintf ( graceUserTime, "%d", pwdGraceUserTime );
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE,
+ "passwordGraceUserTime", graceUserTime);
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ if (pwresponse_req) {
+ /* check for "changeafterreset" condition */
+ if (pb->pb_conn->c_needpw == 1) {
+ pwpolicy_make_response_control( pb, -1,
+ ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
+ LDAP_PWPOLICY_CHGAFTERRESET);
+ } else {
+ pwpolicy_make_response_control( pb, -1,
+ ((pwpolicy->pw_gracelimit) - pwdGraceUserTime),
+ -1);
+ }
+ }
+
+ if (pb->pb_conn->c_needpw == 1) {
+ add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
+ }
+ delete_passwdPolicy(&pwpolicy);
+ return ( 0 );
+ }
+
+ /* password expired and user exceeded limit of grace attemps.
+ * Send result and also the control */
+ add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
+ if (pwresponse_req) {
+ pwpolicy_make_response_control ( pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED );
+ }
+ slapi_send_ldap_result ( pb, LDAP_INVALID_CREDENTIALS, NULL,
+ "password expired!", 0, NULL );
+
+ /* abort bind */
+ /* pass pb to do_unbind(). pb->pb_op->o_opid and
+ pb->pb_op->o_tag are not right but I don't see
+ do_unbind() checking for those. We might need to
+ create a pb for unbind operation. Also do_unbind calls
+ pre and post ops. Maybe we don't want to call them */
+ if (pb->pb_conn && (LDAP_VERSION2 == pb->pb_conn->c_ldapversion)) {
+ /* We close the connection only with LDAPv2 connections */
+ do_unbind( pb );
+ }
+ /* Apply current modifications */
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ slapi_ch_free((void **) &cur_time_str );
+ delete_passwdPolicy(&pwpolicy);
+ return (-1);
+ }
+ slapi_ch_free((void **) &cur_time_str );
+
+ /* check if password is going to expire within "passwordWarning" */
+ /* Note that if pw_exp_date is NO_TIME or NOT_FIRST_TIME,
+ * we must send warning first and this changes the expiration time.
+ * This is done just below since diff_t is 0
+ */
+ if ( diff_t <= pwpolicy->pw_warning ) {
+ int pw_exp_warned = 0;
+
+ pw_exp_warned= slapi_entry_attr_get_int( e, "passwordExpWarned");
+ if ( !pw_exp_warned ){
+ /* first time send out a warning */
+ /* reset the expiration time to current + warning time
+ * and set passwordExpWarned to true
+ */
+ if (pb->pb_conn->c_needpw != 1) {
+ pw_exp_date = time_plus_sec ( cur_time,
+ pwpolicy->pw_warning );
+ }
+
+ timestring = format_genTime(pw_exp_date);
+ /* At this time passwordExpirationTime may already be
+ * in the list of mods: Remove it */
+ for (mod = slapi_mods_get_first_mod(&smods); mod != NULL;
+ mod = slapi_mods_get_next_mod(&smods))
+ {
+ if (!strcmp(mod->mod_type, "passwordExpirationTime"))
+ slapi_mods_remove(&smods);
+ }
+
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpirationTime", timestring);
+ slapi_ch_free((void **)&timestring);
+
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "passwordExpWarned", "1");
+
+ *t = pwpolicy->pw_warning;
+
+ } else {
+ *t = (long)diff_t; /* jcm: had to cast double to long */
+ }
+
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ if (pwresponse_req) {
+ /* check for "changeafterreset" condition */
+ if (pb->pb_conn->c_needpw == 1) {
+ pwpolicy_make_response_control( pb, *t, -1,
+ LDAP_PWPOLICY_CHGAFTERRESET);
+ } else {
+ pwpolicy_make_response_control( pb, *t, -1,
+ -1);
+ }
+ }
+
+ if (pb->pb_conn->c_needpw == 1) {
+ add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
+ }
+ delete_passwdPolicy(&pwpolicy);
+ return (2);
+ }
+
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ /* Leftover from "changeafterreset" condition */
+ if (pb->pb_conn->c_needpw == 1) {
+ add_pwd_control ( pb, LDAP_CONTROL_PWEXPIRED, 0);
+ }
+ delete_passwdPolicy(&pwpolicy);
+ /* passes checking, return 0 */
+ return( 0 );
+}
+
+/* check_account_lock is called before bind opeation; this could be a pre-op. */
+int
+check_account_lock ( Slapi_PBlock *pb, Slapi_Entry * bind_target_entry, int pwresponse_req) {
+
+ time_t unlock_time;
+ time_t cur_time;
+ double diff_t;
+ char *cur_time_str = NULL;
+ char *accountUnlockTime;
+ passwdPolicy *pwpolicy = NULL;
+ char *dn = NULL;
+
+ /* kexcoff: account inactivation */
+ int rc = 0;
+ Slapi_ValueSet *values = NULL;
+ int type_name_disposition = 0;
+ char *actual_type_name = NULL;
+ int attr_free_flags = 0;
+ /* kexcoff - end */
+
+ if ( bind_target_entry == NULL )
+ return -1;
+
+ dn = slapi_entry_get_ndn(bind_target_entry);
+ pwpolicy = new_passwdPolicy(pb, dn);
+
+ /* kexcoff: account inactivation */
+ /* check if the entry is locked by nsAccountLock attribute - account inactivation feature */
+
+ rc = slapi_vattr_values_get(bind_target_entry, "nsAccountLock",
+ &values,
+ &type_name_disposition, &actual_type_name,
+ SLAPI_VIRTUALATTRS_REQUEST_POINTERS,
+ &attr_free_flags);
+ if ( rc == 0 )
+ {
+ Slapi_Value *v = NULL;
+ const struct berval *bvp = NULL;
+
+ if ( (slapi_valueset_first_value( values, &v ) != -1) &&
+ ( bvp = slapi_value_get_berval( v )) != NULL )
+ {
+ if ( (bvp != NULL) && (strcasecmp(bvp->bv_val, "true") == 0) )
+ {
+ /* account inactivated */
+ if (pwresponse_req) {
+ pwpolicy_make_response_control ( pb, -1, -1,
+ LDAP_PWPOLICY_ACCTLOCKED );
+ }
+ send_ldap_result ( pb, LDAP_UNWILLING_TO_PERFORM, NULL,
+ "Account inactivated. Contact system administrator.",
+ 0, NULL );
+ slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
+ goto locked;
+ }
+ } /* else, account "activated", keep on the process */
+
+ if ( values != NULL )
+ slapi_vattr_values_free(&values, &actual_type_name, attr_free_flags);
+ }
+ /* kexcoff - end */
+
+ /*
+ * Check if the password policy has to be checked or not
+ */
+ if ( pwpolicy->pw_lockout == 0 ) {
+ goto notlocked;
+ }
+
+ /*
+ * Check the attribute of the password policy
+ */
+
+ /* check if account is locked out. If so, send result and return 1 */
+ {
+ unsigned int maxfailure= pwpolicy->pw_maxfailure;
+ /* It's locked if passwordRetryCount >= maxfailure */
+ if ( slapi_entry_attr_get_uint(bind_target_entry,"passwordRetryCount") < maxfailure )
+ {
+ /* Not locked */
+ goto notlocked;
+ }
+ }
+
+ /* locked but maybe it's time to unlock it */
+ accountUnlockTime= slapi_entry_attr_get_charptr(bind_target_entry, "accountUnlockTime");
+ if (accountUnlockTime != NULL)
+ {
+ unlock_time = parse_genTime(accountUnlockTime);
+ slapi_ch_free((void **) &accountUnlockTime );
+
+ if ( pwpolicy->pw_unlock == 0 &&
+ unlock_time == NO_TIME ) {
+
+ /* account is locked forever. contact admin to reset */
+ if (pwresponse_req) {
+ pwpolicy_make_response_control ( pb, -1, -1,
+ LDAP_PWPOLICY_ACCTLOCKED );
+ }
+ send_ldap_result ( pb, LDAP_CONSTRAINT_VIOLATION, NULL,
+ "Exceed password retry limit. Contact system administrator to reset."
+ , 0, NULL );
+ goto locked;
+ }
+ cur_time = current_time();
+ cur_time_str = format_genTime( cur_time);
+ if ( ( diff_t = difftime ( parse_genTime( cur_time_str ),
+ unlock_time ) ) < 0 ) {
+
+ /* account is locked, cannot do anything */
+ if (pwresponse_req) {
+ pwpolicy_make_response_control ( pb, -1, -1,
+ LDAP_PWPOLICY_ACCTLOCKED );
+ }
+ send_ldap_result ( pb, LDAP_CONSTRAINT_VIOLATION, NULL,
+ "Exceed password retry limit. Please try later." , 0, NULL );
+ slapi_ch_free((void **) &cur_time_str );
+ goto locked;
+ }
+ slapi_ch_free((void **) &cur_time_str );
+ }
+
+notlocked:
+ /* account is not locked. */
+ delete_passwdPolicy(&pwpolicy);
+ return ( 0 );
+locked:
+ delete_passwdPolicy(&pwpolicy);
+ return (1);
+
+}
+
+void
+pw_init ( void ) {
+ slapdFrontendConfig_t *slapdFrontendConfig;
+
+ pw_set_componentID(generate_componentid(NULL, COMPONENT_PWPOLICY));
+
+ slapdFrontendConfig = getFrontendConfig();
+ pw_mod_allowchange_aci (!slapdFrontendConfig->pw_policy.pw_change &&
+ !slapdFrontendConfig->pw_policy.pw_must_change);
+}
+
+
diff --git a/ldap/servers/slapd/pw_retry.c b/ldap/servers/slapd/pw_retry.c
new file mode 100644
index 00000000..3fda4421
--- /dev/null
+++ b/ldap/servers/slapd/pw_retry.c
@@ -0,0 +1,253 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* pw_retry.c
+*/
+
+#include <time.h>
+#include "slap.h"
+
+/****************************************************************************/
+/* prototypes */
+/****************************************************************************/
+/* Slapi_Entry *get_entry ( Slapi_PBlock *pb, const char *dn ); */
+static void set_reset_time ( Slapi_PBlock *pb, time_t cur_time );
+static void set_retry_cnt ( Slapi_PBlock *pb, int count);
+static void set_retry_cnt_and_time ( Slapi_PBlock *pb, int count, time_t cur_time);
+
+/*
+ * update_pw_retry() is called when bind operation fails
+ * with LDAP_INVALID_CREDENTIALS (in backend bind.c ).
+ * It checks to see if the retry count can be reset,
+ * increments retry count, and then check if need to lock the acount.
+ * To have a global password policy, these mods should be chained to the
+ * master, and not applied locally. If they are applied locally, they should
+ * not get replicated from master...
+ */
+
+int update_pw_retry ( Slapi_PBlock *pb )
+{
+ Slapi_Entry *e;
+ int retry_cnt=0;
+ time_t reset_time;
+ time_t cur_time;
+ char *cur_time_str = NULL;
+ char *retryCountResetTime;
+ int passwordRetryCount;
+
+ /* get the entry */
+ e = get_entry ( pb, NULL );
+ if ( e == NULL ) {
+ return ( 1 );
+ }
+
+ cur_time = current_time();
+
+ /* check if the retry count can be reset. */
+ retryCountResetTime= slapi_entry_attr_get_charptr(e, "retryCountResetTime");
+ if(retryCountResetTime!=NULL)
+ {
+ reset_time = parse_genTime (retryCountResetTime);
+ slapi_ch_free((void **) &retryCountResetTime );
+
+ cur_time_str = format_genTime ( cur_time );
+ if ( difftime ( parse_genTime( cur_time_str ), reset_time) >= 0 )
+ {
+ /* set passwordRetryCount to 1 */
+ /* reset retryCountResetTime */
+ set_retry_cnt_and_time ( pb, 1, cur_time );
+ slapi_ch_free((void **) &cur_time_str );
+ slapi_entry_free( e );
+ return ( 0 ); /* success */
+ } else {
+ slapi_ch_free((void **) &cur_time_str );
+ }
+ } else {
+ /* initialize passwordRetryCount and retryCountResetTime */
+ set_retry_cnt_and_time ( pb, 1, cur_time );
+ slapi_entry_free( e );
+ return ( 0 ); /* success */
+ }
+ passwordRetryCount = slapi_entry_attr_get_int(e, "passwordRetryCount");
+ if (passwordRetryCount >= 0)
+ {
+ retry_cnt = passwordRetryCount + 1;
+ if ( retry_cnt == 1 ) {
+ /* set retryCountResetTime */
+ set_retry_cnt_and_time ( pb, retry_cnt, cur_time );
+ } else {
+ /* set passwordRetryCount to retry_cnt */
+ set_retry_cnt ( pb, retry_cnt );
+ }
+ }
+ slapi_entry_free( e );
+ return 0; /* success */
+}
+
+static
+void set_retry_cnt_and_time ( Slapi_PBlock *pb, int count, time_t cur_time ) {
+ char *dn;
+ Slapi_Mods smods;
+ time_t reset_time;
+ char *timestr;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ passwdPolicy *pwpolicy = NULL;
+
+ slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn );
+ pwpolicy = new_passwdPolicy(pb, dn);
+
+ slapi_mods_init(&smods, 0);
+
+ reset_time = time_plus_sec ( cur_time,
+ pwpolicy->pw_resetfailurecount );
+
+ timestr = format_genTime ( reset_time );
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "retryCountResetTime", timestr);
+ slapi_ch_free((void **)&timestr);
+
+ set_retry_cnt_mods(pb, &smods, count);
+
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ delete_passwdPolicy(&pwpolicy);
+}
+
+void set_retry_cnt_mods(Slapi_PBlock *pb, Slapi_Mods *smods, int count)
+{
+ char *timestr;
+ time_t unlock_time;
+ char retry_cnt[8]; /* 1-65535 */
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ char *dn = NULL;
+ passwdPolicy *pwpolicy = NULL;
+
+ slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn );
+ pwpolicy = new_passwdPolicy(pb, dn);
+
+ if (smods) {
+ sprintf ( retry_cnt, "%d", count );
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE, "passwordRetryCount", retry_cnt);
+ /* lock account if reache retry limit */
+ if ( count >= pwpolicy->pw_maxfailure ) {
+ /* Remove lock_account function to perform all mods at once */
+ /* lock_account ( pb ); */
+ /* reach the retry limit, lock the account */
+ if ( pwpolicy->pw_unlock == 0 ) {
+ /* lock until admin reset password */
+ unlock_time = NO_TIME;
+ } else {
+ unlock_time = time_plus_sec ( current_time(),
+ pwpolicy->pw_lockduration );
+ }
+ timestr= format_genTime ( unlock_time );
+ slapi_mods_add_string(smods, LDAP_MOD_REPLACE, "accountUnlockTime", timestr);
+ slapi_ch_free((void **)&timestr);
+ }
+ }
+ delete_passwdPolicy(&pwpolicy);
+ return;
+}
+
+static
+void set_retry_cnt ( Slapi_PBlock *pb, int count) {
+ char *dn;
+ Slapi_Mods smods;
+
+ slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn );
+ slapi_mods_init(&smods, 0);
+ set_retry_cnt_mods(pb, &smods, count);
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+}
+
+static
+void set_reset_time ( Slapi_PBlock *pb, time_t cur_time ) {
+ char *dn;
+ Slapi_Mods smods;
+ time_t reset_time;
+ char *timestr;
+ int resetfailurecount;
+ passwdPolicy *pwpolicy = NULL;
+
+ slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn );
+
+ pwpolicy = new_passwdPolicy(pb, dn);
+ resetfailurecount = pwpolicy->pw_resetfailurecount;
+
+ slapi_mods_init(&smods, 0);
+
+ reset_time = time_plus_sec ( cur_time, resetfailurecount );
+
+ timestr = format_genTime ( reset_time );
+ slapi_mods_add_string(&smods, LDAP_MOD_REPLACE, "retryCountResetTime", timestr);
+ slapi_ch_free((void **)&timestr);
+
+ pw_apply_mods(dn, &smods);
+ slapi_mods_done(&smods);
+ delete_passwdPolicy(&pwpolicy);
+}
+
+Slapi_Entry *get_entry ( Slapi_PBlock *pb, const char *dn)
+{
+ int search_result = 0;
+ Slapi_Entry *retentry = NULL;
+ Slapi_DN sdn;
+
+ if ( dn == NULL ) {
+ char *t;
+ slapi_pblock_get( pb, SLAPI_TARGET_DN, &t );
+ dn= t;
+ }
+
+ slapi_sdn_init_dn_byref(&sdn, dn);
+
+ if ((search_result = slapi_search_internal_get_entry(&sdn, NULL, &retentry, pw_get_componentID())) != LDAP_SUCCESS){
+ LDAPDebug (LDAP_DEBUG_TRACE, "WARNING: 'get_entry' can't find entry '%s', err %d\n", dn, search_result, 0);
+ }
+ slapi_sdn_done(&sdn);
+ return retentry;
+}
+
+void pw_apply_mods(const char *dn, Slapi_Mods *mods)
+{
+ Slapi_PBlock pb;
+ int res;
+
+ if (mods && (slapi_mods_get_num_mods(mods) > 0))
+ {
+ pblock_init(&pb);
+ slapi_modify_internal_set_pb (&pb, dn,
+ slapi_mods_get_ldapmods_byref(mods),
+ NULL, /* Controls */
+ NULL, /* UniqueID */
+ pw_get_componentID(), /* PluginID */
+ 0); /* Flags */
+ slapi_modify_internal_pb (&pb);
+
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ if (res != LDAP_SUCCESS){
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: passwordPolicy modify error %d on entry '%s'\n",
+ res, dn, 0);
+ }
+
+ pblock_done(&pb);
+ }
+
+ return;
+}
+
+/* Handle the component ID for the password policy */
+
+static struct slapi_componentid * pw_componentid = NULL;
+
+void pw_set_componentID(struct slapi_componentid *cid)
+{
+ pw_componentid = cid;
+}
+
+struct slapi_componentid * pw_get_componentID()
+{
+ return pw_componentid;
+}
diff --git a/ldap/servers/slapd/rdn.c b/ldap/servers/slapd/rdn.c
new file mode 100644
index 00000000..1eeb75ee
--- /dev/null
+++ b/ldap/servers/slapd/rdn.c
@@ -0,0 +1,410 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slap.h"
+
+#define FLAG_RDNS 0
+
+Slapi_RDN *
+slapi_rdn_new()
+{
+ Slapi_RDN *rdn= (Slapi_RDN *)slapi_ch_malloc(sizeof(struct slapi_rdn));
+ slapi_rdn_init(rdn);
+ return rdn;
+}
+
+Slapi_RDN *
+slapi_rdn_new_dn(const char *dn)
+{
+ Slapi_RDN *rdn= slapi_rdn_new();
+ slapi_rdn_init_dn(rdn,dn);
+ return rdn;
+}
+
+Slapi_RDN *
+slapi_rdn_new_sdn(const Slapi_DN *sdn)
+{
+ Slapi_RDN *rdn= slapi_rdn_new();
+ slapi_rdn_init_sdn(rdn,sdn);
+ return rdn;
+}
+
+Slapi_RDN *
+slapi_rdn_new_rdn(const Slapi_RDN *fromrdn)
+{
+ Slapi_RDN *rdn= slapi_rdn_new();
+ slapi_rdn_init_rdn(rdn,fromrdn);
+ return rdn;
+}
+
+void
+slapi_rdn_init(Slapi_RDN *rdn)
+{
+ rdn->flag= 0;
+ rdn->rdn= NULL;
+ rdn->rdns= NULL;
+ rdn->butcheredupto= -1; /* Means we haven't started converting '=' to '\0' in rdns */
+}
+
+void
+slapi_rdn_init_dn(Slapi_RDN *rdn,const char *dn)
+{
+ slapi_rdn_init(rdn);
+ if(dn!=NULL)
+ {
+ char **dns= ldap_explode_dn(dn, 0);
+ if(dns!=NULL)
+ {
+ rdn->rdn= slapi_ch_strdup(dns[0]);
+ ldap_value_free(dns);
+ }
+ }
+}
+
+void
+slapi_rdn_init_sdn(Slapi_RDN *rdn,const Slapi_DN *sdn)
+{
+ if(sdn!=NULL)
+ {
+ slapi_rdn_init_dn(rdn,slapi_sdn_get_dn(sdn));
+ }
+ else
+ {
+ slapi_rdn_init(rdn);
+ }
+}
+
+void
+slapi_rdn_init_rdn(Slapi_RDN *rdn,const Slapi_RDN *fromrdn)
+{
+ slapi_rdn_init(rdn);
+ rdn->rdn= slapi_ch_strdup(fromrdn->rdn);
+}
+
+void
+slapi_rdn_set_dn(Slapi_RDN *rdn,const char *dn)
+{
+ slapi_rdn_done(rdn);
+ slapi_rdn_init_dn(rdn,dn);
+}
+
+void
+slapi_rdn_set_sdn(Slapi_RDN *rdn,const Slapi_DN *sdn)
+{
+ slapi_rdn_done(rdn);
+ slapi_rdn_init_sdn(rdn,sdn);
+}
+
+void
+slapi_rdn_set_rdn(Slapi_RDN *rdn,const Slapi_RDN *fromrdn)
+{
+ slapi_rdn_done(rdn);
+ slapi_rdn_init_rdn(rdn,fromrdn);
+}
+
+static char **
+slapi_rdn_get_rdns(Slapi_RDN *rdn)
+{
+ char **rdns= NULL;
+ /* Check if rdns is upto date */
+ if(!slapi_isbitset_uchar(rdn->flag,FLAG_RDNS))
+ {
+ if(rdn->rdns!=NULL)
+ {
+ ldap_value_free(rdn->rdns);
+ rdn->rdns= NULL;
+ }
+ if(rdn->rdn!=NULL)
+ {
+ rdn->rdns = ldap_explode_rdn( rdn->rdn, 0 );
+ rdns= rdn->rdns;
+ }
+ slapi_setbit_uchar(rdn->flag,FLAG_RDNS);
+ rdn->butcheredupto= -1;
+ }
+ return rdns;
+}
+
+
+void
+slapi_rdn_free(Slapi_RDN **rdn)
+{
+ if(rdn!=NULL)
+ {
+ slapi_rdn_done(*rdn);
+ slapi_ch_free((void**)rdn);
+ }
+}
+
+void
+slapi_rdn_done(Slapi_RDN *rdn)
+{
+ if(rdn!=NULL)
+ {
+ slapi_ch_free((void**)&(rdn->rdn));
+ ldap_value_free(rdn->rdns);
+ slapi_rdn_init(rdn);
+ }
+}
+
+int
+slapi_rdn_get_first(Slapi_RDN *rdn, char **type, char **value)
+{
+ return slapi_rdn_get_next(rdn, 0, type, value);
+}
+
+int
+slapi_rdn_get_next(Slapi_RDN *rdn, int index, char **type, char **value)
+{
+ int returnindex;
+ PR_ASSERT(index>=0);
+ if(rdn->rdns==NULL)
+ {
+ rdn->rdns= slapi_rdn_get_rdns(rdn);
+ }
+
+ if (rdn->rdns == NULL || rdn->rdns[index]==NULL)
+ {
+ *type= NULL;
+ *value= NULL;
+ returnindex= -1;
+ }
+ else
+ {
+ if(rdn->butcheredupto>=index)
+ {
+ /* the '=' has already been converted to a '\0' */
+ *type= rdn->rdns[index];
+ *value= *type + strlen(*type) + 1;
+ returnindex= ++index;
+ }
+ else
+ {
+ *type= strchr(rdn->rdns[index],'=');
+ if(*type==NULL)
+ {
+ /* This just shouldn't happen... */
+ *type= NULL;
+ *value= NULL;
+ returnindex= -1;
+ }
+ else
+ {
+ **type = '\0';
+ *value= *type;
+ (*value)++; /* Skip the '\0' */
+ *type = rdn->rdns[index];
+ rdn->butcheredupto= index;
+ returnindex= ++index;
+ }
+ }
+ }
+ return returnindex;
+}
+
+int
+slapi_rdn_get_index(Slapi_RDN *rdn, const char *type, const char *value, size_t length)
+{
+ int result;
+ char *theValue;
+ result= slapi_rdn_get_index_attr(rdn, type, &theValue);
+ if(result!=-1)
+ {
+ if(theValue==NULL || (strncasecmp(value,theValue,length)!=0))
+ {
+ result= -1;
+ }
+ }
+ return result;
+}
+
+int
+slapi_rdn_get_index_attr(Slapi_RDN *rdn, const char *type, char **value)
+{
+ int result= -1;
+ int index;
+ char *theType;
+ index= slapi_rdn_get_first(rdn, &theType, value);
+ while(index!=-1)
+ {
+ if(theType!=NULL && value!=NULL &&
+ (strcasecmp(type,theType)==0))
+ {
+ result= index;
+ index= -1;
+ }
+ else
+ {
+ index= slapi_rdn_get_next(rdn, index, &theType, value);
+ }
+ }
+ return result;
+}
+
+int
+slapi_rdn_contains_attr(Slapi_RDN *rdn, const char *type, char **value)
+{
+ return (slapi_rdn_get_index_attr(rdn,type,value)!=-1);
+}
+
+int
+slapi_rdn_contains(Slapi_RDN *rdn, const char *type, const char *value, size_t length)
+{
+ return (slapi_rdn_get_index(rdn,type,value,length)!=-1);
+}
+
+int
+slapi_rdn_add(Slapi_RDN *rdn, const char *type, const char *value)
+{
+ PR_ASSERT(NULL != type);
+ PR_ASSERT(NULL != value);
+ if(rdn->rdn==NULL)
+ {
+ /* type=value '\0' */
+ rdn->rdn= slapi_ch_malloc(strlen(type)+1+strlen(value)+1);
+ strcpy( rdn->rdn, type );
+ strcat( rdn->rdn, "=" );
+ strcat( rdn->rdn, value );
+ }
+ else
+ {
+ /* type=value+rdn '\0' */
+ char *newrdn= slapi_ch_malloc(strlen(type)+1+strlen(value)+1+strlen(rdn->rdn)+1);
+ strcpy( newrdn, type );
+ strcat( newrdn, "=" );
+ strcat( newrdn, value );
+ strcat( newrdn, "+" );
+ strcat( newrdn, rdn->rdn );
+ slapi_ch_free((void**)&rdn->rdn);
+ rdn->rdn= newrdn;
+ }
+ slapi_unsetbit_uchar(rdn->flag,FLAG_RDNS);
+ return 1;
+}
+
+int
+slapi_rdn_remove_index(Slapi_RDN *rdn, int atindex)
+{
+ Slapi_RDN newrdn;
+ int result= 0;
+ int index;
+ char *theType;
+ char *theValue;
+ slapi_rdn_init(&newrdn);
+ index= slapi_rdn_get_first(rdn, &theType, &theValue);
+ while(index!=-1)
+ {
+ if(index!=atindex)
+ {
+ slapi_rdn_add(&newrdn,theType,theValue);
+ }
+ else
+ {
+ result= 1;
+ }
+ index= slapi_rdn_get_next(rdn, index, &theType, &theValue);
+ }
+ if(result)
+ {
+ slapi_rdn_set_rdn(rdn,&newrdn);
+ }
+ slapi_rdn_done(&newrdn);
+ return result;
+}
+
+int
+slapi_rdn_remove(Slapi_RDN *rdn, const char *type, const char *value, size_t length)
+{
+ int result= 0;
+ if(rdn->rdn!=NULL)
+ {
+ int atindex= slapi_rdn_get_index(rdn, type, value, length);
+ if(atindex!=-1)
+ {
+ result= slapi_rdn_remove_index(rdn, atindex);
+ }
+ }
+ return result;
+}
+
+int
+slapi_rdn_remove_attr(Slapi_RDN *rdn, const char *type)
+{
+ int result= 0;
+ if(rdn->rdn!=NULL)
+ {
+ char *value;
+ int atindex= slapi_rdn_get_index_attr(rdn, type, &value);
+ if(atindex!=-1)
+ {
+ result= slapi_rdn_remove_index(rdn, atindex);
+ }
+ }
+ return result;
+}
+
+int
+slapi_rdn_isempty(const Slapi_RDN *rdn)
+{
+ return (rdn->rdn==NULL || rdn->rdn[0]=='\0');
+}
+
+int
+slapi_rdn_get_num_components(Slapi_RDN *rdn)
+{
+ int i= 0;
+ char **rdns= slapi_rdn_get_rdns(rdn);
+ if(rdns!=NULL)
+ {
+ for(i=0; rdns[i]!=NULL; i++);
+ }
+ return i;
+}
+
+int
+slapi_rdn_compare(Slapi_RDN *rdn1, Slapi_RDN *rdn2)
+{
+ int r= 1;
+ int n1= slapi_rdn_get_num_components(rdn1);
+ int n2= slapi_rdn_get_num_components(rdn2);
+ if (n1==n2)
+ {
+ char *type, *value;
+ int i= slapi_rdn_get_first(rdn1, &type, &value);
+ while(r==1 && i!=-1)
+ {
+ r= slapi_rdn_contains(rdn2, type, value, strlen(value));
+ i= slapi_rdn_get_next(rdn1, i, &type, &value);
+ }
+ if(r==1) /* All rdn1's rdn components were in rdn2 */
+ {
+ r= 0; /* SAME */
+ }
+ else
+ {
+ r= -1; /* NOT SAME */
+ }
+ }
+ else
+ {
+ r= -1; /* NOT SAME */
+ }
+ return r;
+}
+
+const char *
+slapi_rdn_get_rdn(const Slapi_RDN *rdn)
+{
+ return rdn->rdn;
+}
+
+const char *
+slapi_rdn_get_nrdn(const Slapi_RDN *rdn)
+{
+ /* JCM - Normalised RDN? */
+ PR_ASSERT(0);
+ return NULL;
+}
diff --git a/ldap/servers/slapd/referral.c b/ldap/servers/slapd/referral.c
new file mode 100644
index 00000000..98fedadf
--- /dev/null
+++ b/ldap/servers/slapd/referral.c
@@ -0,0 +1,1205 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * referrals.c - LDAP referral-related routines.
+ * a) manage in-memory copiedfrom and copyingfrom referrals.
+ * b) function to adjust smart referrals to match operation parameters.
+ */
+#include <stdio.h>
+#include "slap.h"
+
+/* Forward Decls */
+static int ref_array_del(Ref **target, int write, int read);
+static int ref_array_add(const char *dn, struct berval *referral, int write, int read);
+static Ref **ref_array_find(const char *dn);
+static int ref_array_mod(Ref **target, struct berval *referral, int write, int read);
+static void strcat_escaped( char *s1, char *s2 );
+static void adjust_referral_basedn( char **urlp, const Slapi_DN *refcontainerdn, char *opdn_norm, int isreference );
+static int dn_is_below( const char *dn_norm, const char *ancestor_norm );
+static Ref_Array *g_get_global_referrals(void);
+static void ref_free (Ref **goner);
+static Ref_Array global_referrals;
+
+struct refCb {
+ int type;
+ char *cbName;
+ void (*cb)(Slapi_PBlock *, void *);
+ void *cbData;
+ struct refCb *next;
+};
+
+struct refCb *refCbList=NULL;
+
+int
+ref_register_callback(int type, char *description,
+ void (*cb)(Slapi_PBlock *, void *), void *cbData);
+int
+ref_remove_callback(char *description);
+static
+int ref_call_cbs(int type, Slapi_PBlock *pb);
+
+
+#define SLAPD_DEFAULT_REFARRAY_SIZE 10
+
+/*
+ * Function: g_get_global_referrals
+ *
+ * Returns: nothing
+ *
+ * Description: Fills the global_referrals referral array.
+ * The size is set to "size". The mutex is created.
+ * The array is calloc'd.
+ */
+static Ref_Array *
+g_get_global_referrals(void)
+{
+ if (global_referrals.ra_rwlock == NULL)
+ {
+ /* Make a new lock */
+ global_referrals.ra_rwlock = rwl_new();
+
+ if (global_referrals.ra_rwlock == NULL) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ref_array_init: new lock creation failed\n", 0, 0, 0);
+ exit (-1);
+ }
+
+ /* Initialize all the fields. */
+ global_referrals.ra_size = SLAPD_DEFAULT_REFARRAY_SIZE;
+ global_referrals.ra_nextindex = 0;
+ global_referrals.ra_readcount = 0;
+ global_referrals.ra_refs = (Ref **) slapi_ch_calloc(SLAPD_DEFAULT_REFARRAY_SIZE, sizeof( Ref * ));
+ }
+ return( &global_referrals );
+}
+
+/*
+ * Function: ref_array_del
+ *
+ * Returns: 0 good, -1 bad.
+ *
+ * Description: finds "dn" in the list and unsets the read or write
+ * flag(s). If both are then zero, then it frees up that entry.
+ * target should point to the referral that is to be deleted.
+ * Note: This does NOT lock global_referrals.ra_rwlock.
+ *
+ * Author: RJP
+ */
+static int
+ref_array_del(Ref **target, int write, int read)
+{
+ Ref **lastref = NULL;
+ Ref_Array *grefs = NULL;
+
+ grefs = g_get_global_referrals();
+
+ if (target == NULL) {
+ return(-1);
+ }
+
+ /*Unset either or both flags*/
+ if (write) {
+ (*target)->ref_writes = 0;
+ }
+ if (read) {
+ (*target)->ref_reads = 0;
+ grefs->ra_readcount--;
+ }
+
+ /*If there is a flag set, then don't delete the referral*/
+ if (((*target)->ref_writes == 1) || (*target)->ref_reads == 1){
+ return(0);
+ }
+
+ /* Free up target */
+ ref_free(target);
+
+
+ /*
+ * Okay, we want to maintain our array's compactedness,
+ * so we take the referral that's in the last position, and
+ * put that in target's place. If they are one and the
+ * same, then no problem. This shouldn't ever seg fault.
+ * (famous last words).
+ */
+ lastref = &grefs->ra_refs[grefs->ra_nextindex - 1];
+
+ *target = *lastref;
+
+ grefs->ra_refs[grefs->ra_nextindex - 1] = NULL;
+
+ /*reset the next_index*/
+ grefs->ra_nextindex--;
+
+ return(0);
+
+}
+
+
+/*
+ * Function: ref_array_replace
+ *
+ * Returns: 0 good, -1 bad.
+ *
+ * Description: Locks the mutex associated with global_referrals,
+ * adds that referral and "dn" to the global_referrals if it
+ * doesn't exist already. If it does exist, and the new
+ * referral is different, then the old one gets clobbered.
+ * If referral is NULL, then it deletes the referral
+ * associated with dn.
+ * Note: This locks global_referrals.ra_rwlock.
+ *
+ * Author: RJP
+ */
+int
+ref_array_replace(const char *dn, struct berval *referral, int write, int read)
+{
+ Ref **target = NULL;
+ int err;
+ Ref_Array *grefs = NULL;
+
+ grefs = g_get_global_referrals();
+
+ if (dn == NULL) {
+ return(0);
+ }
+
+ GR_LOCK_WRITE();
+
+ /* Find the referral, if any. */
+ target = ref_array_find(dn);
+
+ /* If datasource is NULL, then delete target. */
+ if ( referral == NULL ){
+
+ /* If target is null, then there is nothing to do. */
+ if (target == NULL) {
+ GR_UNLOCK_WRITE();
+ return(0);
+ }
+ err = ref_array_del(target, write, read);
+
+ GR_UNLOCK_WRITE();
+
+ return(err);
+ }
+
+ /* If target is NULL, then add target to the end. */
+ if ( target == NULL) {
+ err = ref_array_add(dn, referral, write, read);
+ GR_UNLOCK_WRITE();
+ return(err);
+ }
+
+ /* Else, the referral already exists and we should modify it. */
+ err = ref_array_mod(target, referral, write, read);
+ GR_UNLOCK_WRITE();
+ return(err);
+}
+
+
+/*
+ * Function: ref_array_mod
+ *
+ * Returns: 0 good, -1 bad.
+ *
+ * Description: modifies the existing referral.
+ * First it checks the host:port in datasource
+ * against the host:port in the existing referral.
+ * If they don't match, then it replaces the referral
+ *
+ * Note: This does NOT lock global_referrals.ra_rwlock.
+ *
+ * Author: RJP
+ */
+static int
+ref_array_mod(Ref **target, struct berval *referral, int write, int read)
+{
+ Ref_Array *grefs = NULL;
+
+ grefs = g_get_global_referrals();
+
+ if (referral == NULL || target == NULL) {
+ return(0);
+ }
+
+ /* Actually, instead of comparing them, we might as well just swap */
+ ber_bvfree( (*target)->ref_referral );
+
+ (*target)->ref_referral = referral ;
+
+ /*
+ * We have to update the read/write flags which
+ * refer reads and writes, respectively
+ */
+ if (write) {
+ (*target)->ref_writes = 1;
+ }
+ if (read) {
+ /*Don't update the readcount unnecessarily*/
+ if ((*target)->ref_reads == 0) {
+ grefs->ra_readcount++;
+ }
+
+ (*target)->ref_reads = 1;
+ }
+
+ return(0);
+
+}
+
+
+
+/*
+ * Function: ref_array_add
+ *
+ * Returns: 0 good, -1 bad.
+ *
+ * Description: adds that referral and "dn" to the global_referrals
+ * Note: This does NOT lock global_referrals.ra_rwlock.
+ *
+ * Author: RJP
+ */
+static int
+ref_array_add(const char *dn, struct berval *referral, int write, int read)
+{
+ Ref **target = NULL;
+ Ref_Array *grefs = NULL;
+
+ grefs = g_get_global_referrals();
+
+ if (dn == NULL || referral == NULL) {
+ return(0);
+ }
+
+
+ /* We may have to realloc if we are about to index an out-of-range slot */
+ if (grefs->ra_nextindex >= grefs->ra_size){
+ /* reset the size */
+ grefs->ra_size += 10;
+
+ /* reallocate */
+ grefs->ra_refs = (Ref **) slapi_ch_realloc((char *) grefs->ra_refs,
+ grefs->ra_size * (sizeof(Ref *)));
+ }
+
+ /* Tack the new referral to the end. */
+ target = &(grefs->ra_refs[grefs->ra_nextindex]);
+
+ /* Malloc and fill the fields of the new referral */
+ (*target) = (Ref *) slapi_ch_malloc( sizeof(Ref));
+ (*target)->ref_dn = slapi_dn_normalize_case(slapi_ch_strdup(dn));
+ (*target)->ref_referral = referral;
+
+ /* Update the next available index */
+ grefs->ra_nextindex++;
+
+ (*target)->ref_writes = 0;
+ (*target)->ref_reads = 0;
+
+ /*
+ * We have to update the read/write flags which
+ * refer reads and writes, respectively
+ */
+ if (write) {
+ (*target)->ref_writes = 1;
+ }
+ if (read) {
+ (*target)->ref_reads = 1;
+ grefs->ra_readcount++;
+ }
+
+ return(0);
+}
+
+/*
+ * Function: ref_array_find
+ *
+ * Returns: a pointer to a pointer to a Ref, or NULL
+ *
+ * Description: Traverses the array of referrals, until
+ * it either finds a match or gets to the end.
+ * Note: This DOES NOT lock global_referrals.ra_rwlock.
+ *
+ * Author: RJP
+ *
+ */
+static Ref **
+ref_array_find(const char *dn)
+{
+ int walker;
+ Ref_Array *grefs = NULL;
+
+ grefs = g_get_global_referrals();
+
+ if (dn == NULL) {
+ return(NULL);
+ }
+
+ /* Walk down the array, testing for a match */
+ for (walker = 0; walker < grefs->ra_nextindex; walker++){
+
+ if (strcasecmp (grefs->ra_refs[walker]->ref_dn, dn) == 0) {
+ return(&grefs->ra_refs[walker]);
+ }
+ }
+ return(NULL);
+}
+
+/*
+ * Function: send_read_referrals
+ *
+ * Returns: A copy of global_referrals
+ *
+ * Description: Given a dn, this function sends all the copyingfrom
+ * referrals beneath "dn" that are within "scope."
+ * returns a copy of the global_referrals array
+ * that it makes for use later. This is to avoid
+ * any race conditions of ORC ending in the middle
+ * of the search and scewing things up. NULL is returned
+ * if there are no copyingfrom referrals in there.
+ *
+ * If "dn" does not exactly match a referral's dn, we append
+ * "/referralDN" to the referral itself, i.e, we send a
+ * referral like this:
+ * ldap://host:port/dn
+ * instead of one like this:
+ * ldap://host:port
+ * We do not append the referral DN to the referrals present
+ * in the copy of the global_referrals array that we return.
+ *
+ * Author: RJP
+ *
+ */
+Ref_Array *
+send_read_referrals(Slapi_PBlock *pb, int scope, char *dn,
+ struct berval ***urls)
+{
+ int walker, urllen, dnlen;
+ struct berval *refs[2], refcopy;
+ char *urlcopy;
+ Ref_Array *grefs = NULL;
+ Ref_Array *the_copy = NULL;
+ int found_one = 0;
+
+ /* Get a pointer to global_referrals */
+ grefs = g_get_global_referrals();
+
+ GR_LOCK_READ();
+
+ /*If no copyingfroms, just return*/
+ if (grefs->ra_readcount <= 0) {
+ GR_UNLOCK_READ();
+ return(NULL);
+ }
+
+ refs[1] = NULL;
+
+ /*
+ * Walk through the refs in the_copy and send any referrals
+ * that are below "dn". Take "scope" into account as well.
+ */
+ for (walker = 0; walker < grefs->ra_nextindex; walker++) {
+ if ( grefs->ra_refs[walker]->ref_reads &&
+ (( scope == LDAP_SCOPE_BASE &&
+ strcasecmp(grefs->ra_refs[walker]->ref_dn, dn) == 0 ) ||
+ ( scope == LDAP_SCOPE_ONELEVEL &&
+ slapi_dn_isparent(dn, grefs->ra_refs[walker]->ref_dn)) ||
+ ( scope == LDAP_SCOPE_SUBTREE &&
+ slapi_dn_issuffix(grefs->ra_refs[walker]->ref_dn, dn)))) {
+ found_one = 1;
+
+ /*
+ * Make an array of 1 referral. If the referral DN is below "dn",
+ * i.e, it is not the same as "dn", we make a copy and append a
+ * URL-escaped version of the referral DN to the original referral.
+ */
+ if ( scope == LDAP_SCOPE_BASE ||
+ strcasecmp( grefs->ra_refs[walker]->ref_dn, dn ) == 0 ) {
+ refs[0] = grefs->ra_refs[walker]->ref_referral;
+ urlcopy = NULL;
+ } else {
+ urllen = strlen( grefs->ra_refs[walker]->ref_referral->bv_val );
+ dnlen = strlen( grefs->ra_refs[walker]->ref_dn );
+ /* space for worst-case expansion due to escape plus room for '/' */
+ urlcopy = slapi_ch_malloc( urllen + 3 * dnlen + 2 );
+
+ strcpy( urlcopy, grefs->ra_refs[walker]->ref_referral->bv_val );
+ urlcopy[urllen] = '/';
+ ++urllen;
+ urlcopy[urllen] = '\0';
+ strcat_escaped( urlcopy + urllen, grefs->ra_refs[walker]->ref_dn );
+
+ refcopy.bv_val = urlcopy;
+ refcopy.bv_len = strlen( urlcopy );
+ refs[0] = &refcopy;
+ }
+
+ send_ldap_referral( pb, NULL, refs, urls );
+ slapi_pblock_set( pb, SLAPI_SEARCH_REFERRALS, *urls );
+
+ if ( urlcopy != NULL ) {
+ slapi_ch_free( (void **)&urlcopy );
+ }
+ }
+ }
+
+ /* Make a copy of global_referrals to avoid any race conditions */
+ if (found_one) {
+ the_copy = ref_array_dup();
+ }
+
+ GR_UNLOCK_READ();
+
+ /*
+ * After we sent all the referrals, return the copy of
+ * global_referrals for use later. If there were none found, return
+ * NULL
+ */
+ return(the_copy);
+}
+
+/*
+ * Function: ref_array_dup
+ *
+ * Returns: a copy of global_referrals
+ *
+ * Description: Makes a copy of global_referrals and returns that puppy
+ * Note: Does not lock global_referrals.
+ *
+ * Author: RJP
+ *
+ */
+Ref_Array *
+ref_array_dup(void)
+{
+ Ref_Array *grefs = NULL;
+ Ref_Array *the_copy = NULL;
+ int walker;
+
+ /*Allocate the first structure*/
+ the_copy = (Ref_Array *) slapi_ch_calloc(1, sizeof(Ref_Array));
+
+ /* Don't bother with the lock, it's only a local copy. */
+ the_copy->ra_rwlock = NULL;
+
+ /*Grab a reference to the global_referrals*/
+ grefs = g_get_global_referrals();
+
+ /* Initialize all the fields of the copy. */
+ the_copy->ra_size = grefs->ra_size;
+ the_copy->ra_nextindex = grefs->ra_nextindex;
+ the_copy->ra_readcount = grefs->ra_readcount;
+ the_copy->ra_refs = (Ref **) slapi_ch_calloc(the_copy->ra_size, sizeof( Ref * ));
+
+ /*Walk down grefs, copying each Ref struct */
+ for (walker = 0; walker < grefs->ra_nextindex; walker++) {
+ the_copy->ra_refs[walker] = (Ref *)slapi_ch_calloc(1, sizeof(Ref));
+ the_copy->ra_refs[walker]->ref_dn = slapi_ch_strdup(grefs->ra_refs[walker]->ref_dn);
+ the_copy->ra_refs[walker]->ref_referral = slapi_ch_bvdup(grefs->ra_refs[walker]->ref_referral);
+ the_copy->ra_refs[walker]->ref_reads = grefs->ra_refs[walker]->ref_reads;
+ the_copy->ra_refs[walker]->ref_writes = grefs->ra_refs[walker]->ref_writes;
+ }
+
+ return(the_copy);
+
+}
+
+
+/*
+ * Function: ref_free
+ *
+ * Returns: nothing
+ *
+ * Description: frees up "goner"
+ *
+ * Author: RJP
+ *
+ */
+static void
+ref_free (Ref **goner)
+{
+ slapi_ch_free((void**) &((*goner)->ref_dn));
+ ber_bvfree( (*goner)->ref_referral );
+ slapi_ch_free((void**) goner);
+}
+
+/*
+ * Function: ref_array_dup_free
+ *
+ * Returns: nothingness
+ *
+ * Description: takes a Ref_Array dup and frees that puppy
+ *
+ * Author: RJP
+ *
+ */
+void
+ref_array_dup_free(Ref_Array *the_copy)
+{
+ int walker;
+
+ if (the_copy == NULL) {
+ return;
+ }
+
+ /* Walk down the array, deleting each referral */
+ for (walker = 0; walker < the_copy->ra_nextindex; walker++)
+ {
+ ref_free (&the_copy->ra_refs[walker]);
+ }
+
+ /* free the array of pointers */
+ slapi_ch_free((void **) &the_copy->ra_refs);
+ slapi_ch_free((void **) &the_copy);
+
+ return;
+}
+
+
+
+/*
+ * Function: referrals_free
+ *
+ * Returns: nothing
+ *
+ * Description: frees up everything.
+ *
+ * Author: RJP
+ *
+ */
+void
+referrals_free (void)
+{
+ int walker;
+ Ref_Array *grefs = NULL;
+
+ grefs = g_get_global_referrals();
+
+ GR_LOCK_WRITE();
+
+ /* Walk down the array, deleting each referral */
+ for (walker = 0; walker < grefs->ra_nextindex; walker++){
+ ref_free (&grefs->ra_refs[walker]);
+
+ }
+
+ slapi_ch_free ((void **) &grefs->ra_refs);
+
+ GR_UNLOCK_WRITE();
+
+ rwl_free( &grefs->ra_rwlock );
+}
+
+/*
+ * Function: ref_array_moddn
+ *
+ * Returns: 0 good, -1 bad.
+ *
+ * Description: modifies the existing referral's dn.
+ * First it locks global_referrals.ra_rwlock.
+ * Then it clobbers the existing dn.
+ * Then it replaces it with a new dn constructed
+ * from newrdn.
+ * Note: This locks global_referrals.ra_rwlock.
+ *
+ * Author: RJP
+ */
+void
+ref_array_moddn(const char *dn, char *newrdn, Slapi_PBlock *pb)
+{
+ char *pdn = NULL;
+ char *newdn = NULL;
+ Ref **target = NULL;
+ Ref_Array *grefs = NULL;
+
+ grefs = g_get_global_referrals();
+
+ if (dn == NULL) {
+ return;
+ }
+
+ GR_LOCK_WRITE();
+
+ /* Find the referral. */
+ target = ref_array_find(dn);
+
+ /*
+ * If we can't find it, then we're done. This is okay, because this
+ * is the only check that is made to see if the entry has a
+ * copiedfrom in it.
+ */
+ if (target == NULL) {
+ GR_UNLOCK_WRITE();
+ return;
+ }
+ /* construct the new dn */
+ if ( (pdn = slapi_dn_beparent( pb, dn )) != NULL ) {
+ /* parent + rdn + separator(s) + null */
+ newdn = (char *) slapi_ch_malloc( strlen( pdn ) + strlen( newrdn ) + 3 );
+ strcpy( newdn, newrdn );
+ strcat( newdn, ", " );
+ strcat( newdn, pdn );
+ } else {
+ newdn = (char *) slapi_ch_strdup( newrdn );
+ }
+ slapi_ch_free((void **) &pdn );
+ (void) slapi_dn_normalize_case( newdn );
+
+
+ /* We have found the referral. blow away the dn*/
+ slapi_ch_free((void**) &((*target)->ref_dn));
+
+ /* stick in the new one. */
+ (*target)->ref_dn = newdn;
+
+ GR_UNLOCK_WRITE();
+
+ return;
+}
+
+
+/*
+ * HREF_CHAR_ACCEPTABLE was copied from libldap/tmplout.c
+ */
+/* Note: an identical function is in ../plugins/replication/replutil.c */
+#define HREF_CHAR_ACCEPTABLE( c ) (( c >= '-' && c <= '9' ) || \
+ ( c >= '@' && c <= 'Z' ) || \
+ ( c == '_' ) || \
+ ( c >= 'a' && c <= 'z' ))
+
+/*
+ * Function: strcat_escaped
+ *
+ * Returns: nothing
+ *
+ * Description: Appends string s2 to s1, URL-escaping (%HH) unsafe
+ * characters in s2 as appropriate. This function was
+ * copied from libldap/tmplout.c.
+ *
+ * Author: MCS
+ */
+/*
+ * append s2 to s1, URL-escaping (%HH) unsafe characters
+ */
+/* Note: an identical function is in ../plugins/replication/replutil.c */
+static void
+strcat_escaped( char *s1, char *s2 )
+{
+ char *p, *q;
+ char *hexdig = "0123456789ABCDEF";
+
+ p = s1 + strlen( s1 );
+ for ( q = s2; *q != '\0'; ++q ) {
+ if ( HREF_CHAR_ACCEPTABLE( *q )) {
+ *p++ = *q;
+ } else {
+ *p++ = '%';
+ *p++ = hexdig[ 0x0F & ((*(unsigned char*)q) >> 4) ];
+ *p++ = hexdig[ 0x0F & *q ];
+ }
+ }
+
+ *p = '\0';
+}
+
+void
+update_global_referrals(Slapi_PBlock *pb)
+{
+ ref_call_cbs(0,pb);
+ return;
+}
+
+/*
+ * ref_adjust() -- adjust referrals based on operation-specific data.
+ * The general idea is for us (the server) to be smart so LDAP clients
+ * can be as dumb as possible.
+ *
+ * XXXmcs: We always duplicate the referrals even if no adjustments need to
+ * be made. It would be more efficient but more complicated to avoid making
+ * a copy if we don't need to change anything. If that were done, the
+ * interface to this function would need to change since the caller would
+ * need to know whether the returned memory needed to be freed or not.
+ *
+ * Parameters:
+ * pb is the pblock for the operation we are working on.
+ * urls is a list of referrals.
+ * refsdn is the Slapi_DN of the entry where the referral is stored.
+ * is_reference is true if a searchResultReference is being returned.
+ *
+ * Returns:
+ * a (possibly modified) copy of the urls. It should be freed by
+ * calling ber_bvecfree().
+ *
+ *
+ * First we strip off any labels from the referral URLs. For example, a
+ * referral like this:
+ *
+ * ldap://directory.airius.com/ou=people,o=airius.com Ref to people tree
+ *
+ * is changed to:
+ *
+ * ldap://directory.airius.com/ou=people,o=airius.com
+ *
+ * Next, if the referral includes a baseDN we potentially modify it or strip
+ * it off entirely. If the referral doesn't include a baseDN and we're
+ * processing a continuation reference, we add a baseDN.
+ *
+ * Finally, if we are processing a continuation reference that resulted from
+ * a one-level search, we append "??base" to the referral so the client will
+ * use the correct scope when chasing the reference.
+ */
+struct berval **
+ref_adjust( Slapi_PBlock *pb, struct berval **urls, const Slapi_DN *refsdn,
+ int is_reference )
+{
+ int i, len, scope;
+ char *p, *opdn_norm;
+ struct berval **urlscopy;
+ Operation *op;
+
+ if ( NULL == urls || NULL == urls[0] ) {
+ return( NULL );
+ }
+
+ PR_ASSERT( pb != NULL );
+
+ /*
+ * grab the operation target DN and operation structure.
+ * if the operation is a search, get the scope as well.
+ */
+ if ( slapi_pblock_get( pb, SLAPI_TARGET_DN, &p ) != 0 || p == NULL ||
+ slapi_pblock_get( pb, SLAPI_OPERATION, &op ) != 0 || op == NULL ||
+ ( operation_get_type(op) == SLAPI_OPERATION_SEARCH && slapi_pblock_get( pb,
+ SLAPI_SEARCH_SCOPE, &scope ) != 0 )) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ref_adjust: referrals suppressed "
+ "(could not get target DN, operation, or scope from pblock)\n",
+ 0, 0, 0 );
+ return( NULL );
+ }
+
+ /*
+ * normalize the DNs we plan to compare with others later.
+ */
+ opdn_norm = slapi_dn_normalize( slapi_ch_strdup( p ));
+
+
+ /*
+ * count referrals and duplicate the array
+ */
+ for ( i = 0; urls[i] != NULL; ++i ) {
+ ;
+ }
+ urlscopy = (struct berval **) slapi_ch_malloc(( i + 1 ) *
+ sizeof( struct berval * ));
+
+ for ( i = 0; urls[i] != NULL; ++i ) {
+ /*
+ * duplicate the URL, stripping off the label if there is one and
+ * leaving extra room for "??base" in case we need to append that.
+ */
+ urlscopy[i] = (struct berval *)slapi_ch_malloc(
+ sizeof( struct berval ));
+ if (( p = strchr( urls[i]->bv_val, ' ' )) == NULL ) {
+ len = strlen( urls[i]->bv_val );
+ } else {
+ len = p - urls[i]->bv_val;
+ }
+ urlscopy[i]->bv_val = (char *)slapi_ch_malloc( len + 7 );
+ memcpy( urlscopy[i]->bv_val, urls[i]->bv_val, len );
+ urlscopy[i]->bv_val[len] = '\0';
+
+ /*
+ * adjust the baseDN as needed and set the length
+ */
+ adjust_referral_basedn( &urlscopy[i]->bv_val, refsdn,
+ opdn_norm, is_reference );
+ urlscopy[i]->bv_len = strlen( urlscopy[i]->bv_val );
+
+ /*
+ * if we are dealing with a continuation reference that resulted
+ * from a one-level search, add a scope of base to the URL.
+ */
+ if ( is_reference && operation_get_type(op) == SLAPI_OPERATION_SEARCH &&
+ scope == LDAP_SCOPE_ONELEVEL ) {
+ strcat( urlscopy[i]->bv_val, "??base" );
+ urlscopy[i]->bv_len += 6;
+ }
+ }
+
+ urlscopy[i] = NULL; /* NULL terminate the new referrals array */
+
+ /*
+ * log what we did (for debugging purposes)
+ */
+ if ( LDAPDebugLevelIsSet( LDAP_DEBUG_ARGS )) {
+ for ( i = 0; urlscopy[i] != NULL; ++i ) {
+ LDAPDebug( LDAP_DEBUG_ARGS, "ref_adjust: \"%s\" -> \"%s\"\n",
+ urls[i]->bv_val, urlscopy[i]->bv_val, 0 );
+ }
+ }
+
+ /*
+ * done -- clean up and return the new referrals array
+ */
+ slapi_ch_free( (void **)&opdn_norm );
+
+ return( urlscopy );
+}
+
+
+
+/*
+ * adjust_referral_basedn() -- pull the referral apart and modify the
+ * baseDN contained in the referral if appropriate not.
+ * If the referral does not have baseDN and we're not processing a
+ * continuation reference, we do not need to do anything. If we're
+ * processing a continuation reference, we need to add a baseDN.
+ *
+ * If it does have one, there are two special cases we deal with:
+ *
+ * 1) The referral's baseDN is an ancestor of the operation's baseDN,
+ * which means that the LDAP client already has a more specific
+ * baseDN than is contained in the referral. If so, we strip off
+ * the baseDN so the client will re-use its operation DN when
+ * chasing the referral.
+ *
+ * 2) The referral's baseDN is not an ancestor of the operation's
+ * baseDN and the DN of the entry that contains the referral is
+ * an ancestor of the operation DN. If so, we remove the portion
+ * of the operation DN that matches the DN of the entry containing
+ * the referral and prepend what's left to the referral base DN.
+ *
+ * We assume that the baseDN is the right-most piece of the URL, i.e., there
+ * is no attribute list, scope, or options after the baseDN.
+ *
+ * The code also assumes that the baseDN doesn't contain any '/' character.
+ * This later assumption NEED to be removed and code changed appropriately.
+ */
+static void
+adjust_referral_basedn( char **urlp, const Slapi_DN *refsdn,
+ char *opdn_norm, int isreference )
+{
+ LDAPURLDesc *ludp = NULL;
+ char *p, *refdn_norm;
+ int rc = 0;
+
+ PR_ASSERT( urlp != NULL );
+ PR_ASSERT( *urlp != NULL );
+ PR_ASSERT( refsdn != NULL );
+ PR_ASSERT( opdn_norm != NULL );
+
+ if (opdn_norm == NULL){
+ /* Be safe but this should never ever happen */
+ return;
+ }
+
+ rc = ldap_url_parse( *urlp, &ludp );
+
+ if ((rc != 0) &&
+ (rc != LDAP_URL_ERR_NODN))
+ /*
+ * rc != LDAP_URL_ERR_NODN is to circumvent a pb in the C-SDK
+ * in ldap_url_parse. The function will return an error if the
+ * URL contains no DN (though it is a valid URL according to
+ * RFC 2255.
+ */
+ {
+ /* Nothing to do, just return */
+ return;
+ }
+
+ if (ludp && (ludp->lud_dn != NULL)) {
+
+ refdn_norm = slapi_dn_normalize( slapi_ch_strdup( ludp->lud_dn ));
+
+ if ( dn_is_below( opdn_norm, refdn_norm )) {
+ /*
+ * Strip off the baseDN.
+ */
+ if (( p = strrchr( *urlp, '/' )) != NULL ) {
+ *p = '\0';
+ }
+
+ } else if ( dn_is_below( opdn_norm, slapi_sdn_get_ndn(refsdn) )) {
+ int cur_len, add_len;
+
+ /*
+ * Prepend the portion of the operation DN that does not match
+ * the ref container DN to the referral baseDN.
+ */
+ add_len = strlen( opdn_norm ) - strlen( slapi_sdn_get_ndn(refsdn) );
+ cur_len = strlen( *urlp );
+ /* + 7 because we keep extra space in case we add ??base */
+ *urlp = slapi_ch_realloc( *urlp, cur_len + add_len + 7 );
+
+ if (( p = strrchr( *urlp, '/' )) != NULL ) {
+ ++p;
+ memmove( p + add_len, p, strlen( p ) + 1 );
+ memmove( p, opdn_norm, add_len );
+ }
+
+ } /* else: leave the original referral baseDN intact. */
+
+ slapi_ch_free( (void **)&refdn_norm );
+ } else if (isreference) {
+ int cur_len, add_len;
+
+ /* If ludp->lud_dn == NULL and isreference : Add the DN of the ref entry*/
+ if ( dn_is_below( opdn_norm, slapi_sdn_get_ndn(refsdn) )){
+ add_len = strlen(opdn_norm);
+ p = opdn_norm;
+ } else {
+ add_len = strlen(slapi_sdn_get_ndn(refsdn));
+ p = (char *)slapi_sdn_get_ndn(refsdn);
+ }
+
+ cur_len = strlen( *urlp );
+ /* + 8 because we keep extra space in case we add a / and/or ??base */
+ *urlp = slapi_ch_realloc( *urlp, cur_len + add_len + 8 );
+ if ((*urlp)[cur_len - 1] != '/'){
+ /* The URL is not ending with a /, let's add one */
+ strcat(*urlp, "/");
+ }
+ strcat(*urlp, p);
+ }
+
+ if ( ludp != NULL ) {
+ ldap_free_urldesc( ludp );
+ }
+ return;
+}
+
+
+/*
+ * dn_is_below(): return non-zero if "dn_norm" is below "ancestor_norm" in
+ * the DIT and return zero if not.
+ */
+static int
+dn_is_below( const char *dn_norm, const char *ancestor_norm )
+{
+ PR_ASSERT( dn_norm != NULL );
+ PR_ASSERT( ancestor_norm != NULL );
+
+ if ( 0 == strcasecmp( dn_norm, ancestor_norm )) {
+ return( 0 ); /* same DN --> not an ancestor relationship */
+ }
+
+ return( slapi_dn_issuffix( dn_norm, ancestor_norm ));
+}
+
+
+
+/*
+ * This function is useful to discover the source of data and provide
+ * this as a referral. It is also useful if someone simply wants
+ * to know if a dn is mastered somewhere else.
+ *
+ * For a given dn, traverse the referral list and look for the copiedFrom
+ * attribute. If such an attribute is found get the server hostname
+ * and port in the form "ldap://hostname:port".
+ * Else return NULL.
+ *
+ * ORC extension: if orc == 1, this function will search for copyingFrom
+ * which will refer searches and compares on trees that are half-baked.
+ *
+ * ORC extension: if cf_refs is NULL, then global_referrals is consulted,
+ * otherwise, cf_refs is consulted.
+ */
+struct berval **
+get_data_source(Slapi_PBlock *pb, const Slapi_DN *sdn, int orc, void *cfrp)
+{
+ int walker;
+ struct berval **bvp;
+ struct berval *bv;
+ int found_it;
+ Ref_Array *grefs = NULL;
+ Ref_Array *the_refs = NULL;
+ Ref_Array *cf_refs = (Ref_Array *)cfrp;
+
+ /* If no Ref_Array is given, use global_referrals */
+ if (cf_refs == NULL) {
+ grefs = g_get_global_referrals();
+ the_refs = grefs;
+ GR_LOCK_READ();
+ } else {
+ the_refs = cf_refs;
+ }
+
+ /* optimization: if orc is 1 (a read), then check the readcount*/
+ if (orc && the_refs->ra_readcount == 0) {
+ if (cf_refs == NULL) {
+ GR_UNLOCK_READ();
+ }
+ return (NULL);
+ }
+
+
+ bvp = NULL;
+ bv = NULL;
+ found_it = 0;
+
+ /* Walk down the array, testing each dn to make see if it's a parent of "dn" */
+ for (walker = 0; walker < the_refs->ra_nextindex; walker++){
+
+ if ( slapi_dn_issuffix(slapi_sdn_get_ndn(sdn), the_refs->ra_refs[walker]->ref_dn)) {
+ found_it = 1;
+ break;
+
+ }
+ }
+
+ /* no referral, so return NULL */
+ if (!found_it) {
+ if (cf_refs == NULL) {
+ GR_UNLOCK_READ();
+ }
+ return (NULL);
+ }
+
+ /*
+ * Gotta make sure we're returning the right one. If orc is 1, then
+ * only return a read referral. if orc is 0, then only return a
+ * write referral.
+ */
+ if (orc && the_refs->ra_refs[walker]->ref_reads != 1) {
+ if (cf_refs == NULL) {
+ GR_UNLOCK_READ();
+ }
+ return (NULL);
+ }
+
+ if (!orc && the_refs->ra_refs[walker]->ref_writes != 1) {
+ if (cf_refs == NULL) {
+ GR_UNLOCK_READ();
+ }
+ return (NULL);
+ }
+
+
+ /* Fix for 310968 --- return an SSL referral to an SSL client */
+ if ( 0 != ( pb->pb_conn->c_flags & CONN_FLAG_SSL )) {
+ /* SSL connection */
+ char * old_referral_string = NULL;
+ char * new_referral_string = NULL;
+ char *p = NULL;
+ /* Get the basic referral */
+ bv = slapi_ch_bvdup(the_refs->ra_refs[walker]->ref_referral);
+ old_referral_string = bv->bv_val;
+ /* The longest new string will be one character longer than the old one */
+ new_referral_string = slapi_ch_malloc(bv->bv_len + 1);
+ /* Re-write it to replace ldap with ldaps, and remove the port information */
+ /* The original string will look like this: ldap://host:port */
+ /* We need to make it look like this: ldaps://host */
+ /* Potentially the ":port" part might be missing from the original */
+ sprintf(new_referral_string, "%s%s" , LDAPS_URL_PREFIX, old_referral_string + strlen(LDAP_URL_PREFIX) );
+ /* Go looking for the port */
+ p = new_referral_string + (strlen(LDAPS_URL_PREFIX) + 1);
+ while (*p != '\0' && *p != ':') p++;
+ if (':' == *p) {
+ /* It had a port, zap it */
+ *p = '\0';
+ }
+ /* Fix the bv to point to this new string */
+ bv->bv_val = new_referral_string;
+ /* Fix its length */
+ bv->bv_len = strlen(bv->bv_val);
+ /* Free the copy we made of the original */
+ slapi_ch_free((void**)&old_referral_string);
+ } else {
+ /* regular connection */
+ bv = (struct berval *) slapi_ch_bvdup(the_refs->ra_refs[walker]->ref_referral);
+ }
+
+ /* Package it up and send that puppy. */
+ bvp = (struct berval **) slapi_ch_malloc( 2 * sizeof(struct berval *) );
+ bvp[0] = bv;
+ bvp[1] = NULL;
+
+ if (cf_refs == NULL) {
+ GR_UNLOCK_READ();
+ }
+
+ return(bvp);
+
+}
+
+
+int
+ref_register_callback(int type, char *description,
+ void (*cb)(Slapi_PBlock *, void *), void *cbData)
+{
+ struct refCb *cbPtr;
+ struct refCb *newCb;
+
+ if(NULL == (newCb =
+ (struct refCb *)slapi_ch_calloc(1,sizeof(struct refCb)))) {
+ /* out of memory? */
+ return(-1);
+ }
+ newCb->type = type;
+ newCb->next = NULL;
+ newCb->cb = cb;
+ newCb->cbData = cbData;
+ newCb->cbName = slapi_ch_strdup(description);
+
+ if(NULL == refCbList) {
+ refCbList = newCb;
+ return(0);
+ }
+ cbPtr = refCbList;
+ while(NULL != cbPtr->next) cbPtr = cbPtr->next;
+ cbPtr->next=newCb;
+
+ return(0);
+}
+
+int
+ref_remove_callback(char *description)
+{
+ struct refCb *cbPtr = refCbList;
+ struct refCb *cbPrev = refCbList;
+
+ if((NULL == description) || (NULL == cbPtr))
+ return(-1);
+
+ while(cbPtr) {
+ if(!strcmp(description,cbPtr->cbName)) {
+ if(cbPrev == refCbList) {
+ refCbList = cbPtr->next;
+ } else {
+ cbPrev->next = cbPtr->next;
+ }
+ slapi_ch_free((void **)&cbPtr->cbName);
+ /* we don't know how the cbData was allocated...we won't attempt
+ to free it */
+ slapi_ch_free((void **)&cbPtr);
+ break;
+ }
+ cbPrev = cbPtr;
+ cbPtr = cbPtr->next;
+ }
+
+ return(0);
+}
+
+static
+int ref_call_cbs(int type, Slapi_PBlock *pb)
+{
+ struct refCb *cbPtr = refCbList;
+
+ if(NULL == cbPtr) {
+ return(0);
+ }
+
+ while(cbPtr) {
+ (*cbPtr->cb)(pb, cbPtr->cbData);
+ cbPtr = cbPtr->next;
+ }
+
+ return(0);
+}
+
diff --git a/ldap/servers/slapd/regex.c b/ldap/servers/slapd/regex.c
new file mode 100644
index 00000000..d9382b24
--- /dev/null
+++ b/ldap/servers/slapd/regex.c
@@ -0,0 +1,1045 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "slap.h" /* must come before regex.h */
+#include "portable.h"
+
+static PRLock *regex_mutex = NULL;
+
+int
+slapd_re_init( void )
+{
+ if ( NULL == regex_mutex ) {
+ regex_mutex = PR_NewLock();
+ }
+ return( NULL == regex_mutex ? -1 : 0 );
+}
+
+void
+slapd_re_lock( void )
+{
+ PR_ASSERT( NULL != regex_mutex );
+ PR_Lock( regex_mutex );
+}
+
+int
+slapd_re_unlock( void )
+{
+ PR_ASSERT( NULL != regex_mutex );
+ return( PR_Unlock( regex_mutex ) );
+}
+
+#if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX )
+#include "regex.h"
+
+/*
+ * regex - Regular expression pattern matching and replacement
+ *
+ * By: Ozan S. Yigit (oz)
+ * Dept. of Computer Science
+ * York University
+ *
+ * These routines are the PUBLIC DOMAIN equivalents of regex
+ * routines as found in 4.nBSD UN*X, with minor extensions.
+ *
+ * These routines are derived from various implementations found
+ * in software tools books, and Conroy's grep. They are NOT derived
+ * from licensed/restricted software.
+ * For more interesting/academic/complicated implementations,
+ * see Henry Spencer's regexp routines, or GNU Emacs pattern
+ * matching module.
+ *
+ * Modification history:
+ *
+ * $Log: regex.c,v $
+ * Revision 1.1 2005/01/21 00:40:51 cvsadm
+ * Initial revision
+ *
+ * Revision 1.3.20.1.2.11 2005/01/14 01:22:12 nhosoi
+ * For the open-source project.
+ * 1) eliminated 'netsite' level
+ * 2) moved ns/config one level lower
+ * 3) moved fasttime to lib/base
+ *
+ * Revision 1.3.20.1.2.10 2004/10/01 18:46:09 dboreham
+ * Rename the built in regex functions to avoid colliding with the native OS versions, where presnet
+ *
+ * Revision 1.2 2004/10/01 06:29:11 david
+ * rename regex functions to avoid collision with native OS functions on Solaris
+ *
+ * Revision 1.1.1.1 2004/06/03 22:32:48 telackey
+ * Initial import Thu Jun 3 15:32:43 PDT 2004
+ *
+ * Revision 1.3.20.1.2.9 2003/09/22 19:42:12 ulfw
+ * Update copyright years from 2001 to 2001-2003
+ *
+ * Revision 1.3.20.1.2.8 2001/11/03 00:13:55 richm
+ * XXX use new copyright XXX
+ *
+ * Revision 1.3.20.1.2.7 2001/10/07 00:59:03 richm
+ * ldapserver/ldap/servers/slapd/regex.c
+ * 1.3.20.1.2.7
+ * 20010918
+ *
+ * Remove copyright caracter form copyright
+ *
+ *
+ * ====================================================
+ *
+ * Revision 1.3.20.1.2.7 2001/09/18 11:43:06 rmarco
+ * Remove copyright caracter form copyright
+ *
+ * Revision 1.3.20.1.2.6 2001/02/13 09:45:16 rmarco
+ * copyrights
+ *
+ * Revision 1.3.20.1.2.5 1999/12/06 10:49:33 robey
+ * fix gcc warning
+ *
+ * Revision 1.3.20.1.2.4 1999/11/18 01:26:26 robey
+ * fix gcc warnings
+ *
+ * Revision 1.3.20.1.2.3 1999/08/20 23:13:33 merrells
+ * tidy up extern things
+ *
+ * Revision 1.3.20.1.2.2 1999/05/19 23:41:58 merrells
+ * Keep the Solaris compiler quiet
+ *
+ * Revision 1.3.20.1.2.1 1999/05/14 18:39:50 merrells
+ * value manipulation code extraction and reworking.
+ *
+ * Revision 1.3.20.1 1998/10/10 02:28:25 ggood
+ * Copy from Directory40RtmBranchpoint to DirectoryBranch
+ *
+ * Revision 1.3.10.5 1997/12/11 23:12:01 kristian
+ * fix bugs 97502, 97504 & 96569: handle 8-bit char's (especially UTF-8) correctly.
+ *
+ * Revision 1.3.10.4 1997/12/07 22:13:08 howes
+ * Always compile re_init(), re_lock(), and re_unlock(), even
+ * on platforms where we use the native regex stuff.
+ *
+ * Revision 1.3.10.3 1997/12/07 00:01:16 howes
+ * Add re_init(), re_lock(), and re_unlock() routines, to avoid race
+ * between acl and syntax code.
+ *
+ * Revision 1.3.10.2 1997/07/17 07:49:13 mcs
+ * merge changes made on ldapsdk_10_branch into server3_directory_branch
+ *
+ * Revision 1.3.10.1 1997/03/27 06:39:33 ggood
+ * Fix up more compiler warnings.
+ *
+ * Revision 1.3 1996/11/07 00:44:44 mcs
+ * eliminate a few compiler warnings
+ *
+ * Revision 1.2 1996/11/05 21:38:05 kristian
+ * copied from Directory_1996_11_04
+ *
+ * Revision 1.1.1.1.2.1 1996/05/07 19:54:53 kristian
+ * Merged UMich ldap-3_3 into Dogbert
+ *
+ * Revision 1.1.1.2 1996/05/04 19:11:02 kristian
+ * UMich version 3.3
+ *
+ * Revision 1.2 1996/04/25 16:24:11 mcs
+ * make re_exec() match "" with ".*" and similar patterns
+ * hopefully this change doesn't break anything else!
+ *
+ * Revision 1.1 1995/02/03 15:56:52 tim
+ * Initial revision
+ *
+ * Revision 1.11 1994/12/14 21:33:45 mcs
+ * use new NEED_BSDREGEX
+ * fix pmatch() prototype
+ *
+ * Revision 1.10 1994/12/12 18:16:39 mcs
+ * use on NetBSD
+ *
+ * Revision 1.9 1994/11/15 19:16:35 mcs
+ * add (CHAR) cast to make VisualC++ happy
+ *
+ * Revision 1.8 1994/11/08 21:14:32 mcs
+ * WIN32 changes
+ *
+ * Revision 1.7 1994/07/23 19:51:24 mcs
+ * use ANSI-style inline function parameters
+ *
+ * Revision 1.6 1993/10/18 01:52:32 tim
+ * include for VMS
+ *
+ * Revision 1.5 1993/09/28 21:37:54 mcs
+ * HP/UX needs the regex we include (not in its libc)
+ *
+ * Revision 1.4 1993/08/27 15:59:52 mcs
+ * use CHAR for deftab
+ *
+ * Revision 1.3 1993/08/27 15:49:47 mcs
+ * added missing 0 to octal constants
+ * use unsigned char for CHAR under DOS
+ *
+ * Revision 1.2 1993/08/27 14:57:48 mcs
+ * add proto. for pmatch
+ *
+ * Revision 1.1 1993/08/18 21:20:02 mcs
+ * Initial revision
+ *
+ * Revision 1.4 1991/10/17 03:56:42 oz
+ * miscellaneous changes, small cleanups etc.
+ *
+ * Revision 1.3 1989/04/01 14:18:09 oz
+ * Change all references to a dfa: this is actually an nfa.
+ *
+ * Revision 1.2 88/08/28 15:36:04 oz
+ * Use a complement bitmap to represent NCL.
+ * This removes the need to have seperate
+ * code in the pmatch case block - it is
+ * just CCL code now.
+ *
+ * Use the actual CCL code in the CLO
+ * section of pmatch. No need for a recursive
+ * pmatch call.
+ *
+ * Use a bitmap table to set char bits in an
+ * 8-bit chunk.
+ *
+ * Interfaces:
+ * The following three interfaces were added to avoid a race
+ * condition in slapd. The better long-term solution is to make
+ * the regex code thread-safe, by passing in the buffers needed.
+ *
+ * re_init: initializes the regex system. must be called
+ * before any other regex calls are made.
+ *
+ * re_lock: locks the regex system. must be called to avoid
+ * races between calls to re_comp and re_exec.
+ *
+ * re_unlock unlocks the regex system. must be called after
+ * a set of calls to re_comp and re_exec.
+ *
+ * re_comp: compile a regular expression into a NFA.
+ *
+ * char *re_comp(s)
+ * char *s;
+ *
+ * re_exec: execute the NFA to match a pattern.
+ *
+ * int re_exec(s)
+ * char *s;
+ *
+ * re_modw change re_exec's understanding of what a "word"
+ * looks like (for \< and \>) by adding into the
+ * hidden word-syntax table.
+ *
+ * void re_modw(s)
+ * char *s;
+ *
+ * re_subs: substitute the matched portions in a new string.
+ *
+ * int re_subs(src, dst)
+ * char *src;
+ * char *dst;
+ *
+ * re_fail: failure routine for re_exec.
+ *
+ * void re_fail(msg, op)
+ * char *msg;
+ * char op;
+ *
+ * Regular Expressions:
+ *
+ * [1] char matches itself, unless it is a special
+ * character (metachar): . \ [ ] * + ^ $
+ *
+ * [2] . matches any character.
+ *
+ * [3] \ matches the character following it, except
+ * when followed by a left or right round bracket,
+ * a digit 1 to 9 or a left or right angle bracket.
+ * (see [7], [8] and [9])
+ * It is used as an escape character for all
+ * other meta-characters, and itself. When used
+ * in a set ([4]), it is treated as an ordinary
+ * character.
+ *
+ * [4] [set] matches one of the characters in the set.
+ * If the first character in the set is "^",
+ * it matches a character NOT in the set, i.e.
+ * complements the set. A shorthand S-E is
+ * used to specify a set of characters S upto
+ * E, inclusive. The special characters "]" and
+ * "-" have no special meaning if they appear
+ * as the first chars in the set.
+ * examples: match:
+ *
+ * [a-z] any lowercase alpha
+ *
+ * [^]-] any char except ] and -
+ *
+ * [^A-Z] any char except uppercase
+ * alpha
+ *
+ * [a-zA-Z] any alpha
+ *
+ * [5] * any regular expression form [1] to [4], followed by
+ * closure char (*) matches zero or more matches of
+ * that form.
+ *
+ * [6] + same as [5], except it matches one or more.
+ *
+ * [7] a regular expression in the form [1] to [10], enclosed
+ * as \(form\) matches what form matches. The enclosure
+ * creates a set of tags, used for [8] and for
+ * pattern substution. The tagged forms are numbered
+ * starting from 1.
+ *
+ * [8] a \ followed by a digit 1 to 9 matches whatever a
+ * previously tagged regular expression ([7]) matched.
+ *
+ * [9] \< a regular expression starting with a \< construct
+ * \> and/or ending with a \> construct, restricts the
+ * pattern matching to the beginning of a word, and/or
+ * the end of a word. A word is defined to be a character
+ * string beginning and/or ending with the characters
+ * A-Z a-z 0-9 and _. It must also be preceded and/or
+ * followed by any character outside those mentioned.
+ *
+ * [10] a composite regular expression xy where x and y
+ * are in the form [1] to [10] matches the longest
+ * match of x followed by a match for y.
+ *
+ * [11] ^ a regular expression starting with a ^ character
+ * $ and/or ending with a $ character, restricts the
+ * pattern matching to the beginning of the line,
+ * or the end of line. [anchors] Elsewhere in the
+ * pattern, ^ and $ are treated as ordinary characters.
+ *
+ *
+ * Acknowledgements:
+ *
+ * HCR's Hugh Redelmeier has been most helpful in various
+ * stages of development. He convinced me to include BOW
+ * and EOW constructs, originally invented by Rob Pike at
+ * the University of Toronto.
+ *
+ * References:
+ * Software tools Kernighan & Plauger
+ * Software tools in Pascal Kernighan & Plauger
+ * Grep [rsx-11 C dist] David Conroy
+ * ed - text editor Un*x Programmer's Manual
+ * Advanced editing on Un*x B. W. Kernighan
+ * RegExp routines Henry Spencer
+ *
+ * Notes:
+ *
+ * This implementation uses a bit-set representation for character
+ * classes for speed and compactness. Each character is represented
+ * by one bit in a 128-bit block. Thus, CCL always takes a
+ * constant 16 bytes in the internal nfa, and re_exec does a single
+ * bit comparison to locate the character in the set.
+ *
+ * Examples:
+ *
+ * pattern: foo*.*
+ * compile: CHR f CHR o CLO CHR o END CLO ANY END END
+ * matches: fo foo fooo foobar fobar foxx ...
+ *
+ * pattern: fo[ob]a[rz]
+ * compile: CHR f CHR o CCL bitset CHR a CCL bitset END
+ * matches: fobar fooar fobaz fooaz
+ *
+ * pattern: foo\\+
+ * compile: CHR f CHR o CHR o CHR \ CLO CHR \ END END
+ * matches: foo\ foo\\ foo\\\ ...
+ *
+ * pattern: \(foo\)[1-3]\1 (same as foo[1-3]foo)
+ * compile: BOT 1 CHR f CHR o CHR o EOT 1 CCL bitset REF 1 END
+ * matches: foo1foo foo2foo foo3foo
+ *
+ * pattern: \(fo.*\)-\1
+ * compile: BOT 1 CHR f CHR o CLO ANY END EOT 1 CHR - REF 1 END
+ * matches: foo-foo fo-fo fob-fob foobar-foobar ...
+ */
+
+#define MAXNFA 1024
+#define MAXTAG 10
+
+#define OKP 1
+#define NOP 0
+
+#define CHR 1
+#define ANY 2
+#define CCL 3
+#define BOL 4
+#define EOL 5
+#define BOT 6
+#define EOT 7
+#define BOW 8
+#define EOW 9
+#define REF 10
+#define CLO 11
+
+#define END 0
+
+/*
+ * The following defines are not meant to be changeable.
+ * They are for readability only.
+ */
+#define MAXCHR 128
+#define CHRBIT 8
+#define BITBLK MAXCHR/CHRBIT
+#define BLKIND 0170
+#define BITIND 07
+
+#define ASCIIB 0177
+
+typedef unsigned char UCHAR;
+/* char, on the other hand, may be signed or unsigned;
+ * it's platform-dependent. A hard fact of life, in C.
+ */
+
+static int tagstk[MAXTAG]; /* subpat tag stack..*/
+static UCHAR nfa[MAXNFA]; /* automaton.. */
+static int sta = NOP; /* status of lastpat */
+
+static UCHAR bittab[BITBLK]; /* bit table for CCL */
+ /* pre-set bits... */
+static UCHAR bitarr[] = {1,2,4,8,16,32,64,128};
+
+#ifdef DEBUG
+static void nfadump( UCHAR *ap);
+#endif
+
+static void
+chset(UCHAR c)
+{
+ bittab[((c) & (unsigned)BLKIND) >> 3] |= bitarr[(c) & BITIND];
+}
+
+#define badpat(x) (*nfa = END, x)
+#define store(x) *mp++ = x
+
+char *
+slapd_re_comp( char *pat )
+{
+ register UCHAR *p; /* pattern pointer */
+ register UCHAR *mp=nfa; /* nfa pointer */
+ register UCHAR *lp; /* saved pointer.. */
+ register UCHAR *sp=nfa; /* another one.. */
+
+ register int tagi = 0; /* tag stack index */
+ register int tagc = 1; /* actual tag count */
+
+ register int n;
+ register UCHAR mask; /* xor mask -CCL/NCL */
+ int c1, c2;
+
+ if (!pat || !*pat) {
+ if (sta)
+ return 0;
+ else
+ return badpat("No previous regular expression");
+ }
+ sta = NOP;
+
+ for (p = (UCHAR*)pat; *p; p++) {
+ lp = mp;
+ switch(*p) {
+
+ case '.': /* match any char.. */
+ store(ANY);
+ break;
+
+ case '^': /* match beginning.. */
+ if (p == (UCHAR*)pat)
+ store(BOL);
+ else {
+ store(CHR);
+ store(*p);
+ }
+ break;
+
+ case '$': /* match endofline.. */
+ if (!*(p+1))
+ store(EOL);
+ else {
+ store(CHR);
+ store(*p);
+ }
+ break;
+
+ case '[': /* match char class..*/
+ store(CCL);
+
+ if (*++p == '^') {
+ mask = 0377;
+ p++;
+ }
+ else
+ mask = 0;
+
+ if (*p == '-') /* real dash */
+ chset(*p++);
+ if (*p == ']') /* real brac */
+ chset(*p++);
+ while (*p && *p != ']') {
+ if (*p == '-' && *(p+1) && *(p+1) != ']') {
+ p++;
+ c1 = *(p-2) + 1;
+ c2 = *p++;
+ while (c1 <= c2)
+ chset((UCHAR)c1++);
+ }
+#ifdef EXTEND
+ else if (*p == '\\' && *(p+1)) {
+ p++;
+ chset(*p++);
+ }
+#endif
+ else
+ chset(*p++);
+ }
+ if (!*p)
+ return badpat("Missing ]");
+
+ for (n = 0; n < BITBLK; bittab[n++] = (UCHAR) 0)
+ store(mask ^ bittab[n]);
+
+ break;
+
+ case '*': /* match 0 or more.. */
+ case '+': /* match 1 or more.. */
+ if (p == (UCHAR*)pat)
+ return badpat("Empty closure");
+ lp = sp; /* previous opcode */
+ if (*lp == CLO) /* equivalence.. */
+ break;
+ switch(*lp) {
+
+ case BOL:
+ case BOT:
+ case EOT:
+ case BOW:
+ case EOW:
+ case REF:
+ return badpat("Illegal closure");
+ default:
+ break;
+ }
+
+ if (*p == '+')
+ for (sp = mp; lp < sp; lp++)
+ store(*lp);
+
+ store(END);
+ store(END);
+ sp = mp;
+ while (--mp > lp)
+ *mp = mp[-1];
+ store(CLO);
+ mp = sp;
+ break;
+
+ case '\\': /* tags, backrefs .. */
+ switch(*++p) {
+
+ case '(':
+ if (tagc < MAXTAG) {
+ tagstk[++tagi] = tagc;
+ store(BOT);
+ store(tagc++);
+ }
+ else
+ return badpat("Too many \\(\\) pairs");
+ break;
+ case ')':
+ if (*sp == BOT)
+ return badpat("Null pattern inside \\(\\)");
+ if (tagi > 0) {
+ store(EOT);
+ store(tagstk[tagi--]);
+ }
+ else
+ return badpat("Unmatched \\)");
+ break;
+ case '<':
+ store(BOW);
+ break;
+ case '>':
+ if (*sp == BOW)
+ return badpat("Null pattern inside \\<\\>");
+ store(EOW);
+ break;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ n = *p-'0';
+ if (tagi > 0 && tagstk[tagi] == n)
+ return badpat("Cyclical reference");
+ if (tagc > n) {
+ store(REF);
+ store(n);
+ }
+ else
+ return badpat("Undetermined reference");
+ break;
+#ifdef EXTEND
+ case 'b':
+ store(CHR);
+ store('\b');
+ break;
+ case 'n':
+ store(CHR);
+ store('\n');
+ break;
+ case 'f':
+ store(CHR);
+ store('\f');
+ break;
+ case 'r':
+ store(CHR);
+ store('\r');
+ break;
+ case 't':
+ store(CHR);
+ store('\t');
+ break;
+#endif
+ default:
+ store(CHR);
+ store(*p);
+ }
+ break;
+
+ default : /* an ordinary char */
+ store(CHR);
+ store(*p);
+ break;
+ }
+ sp = lp;
+ }
+ if (tagi > 0)
+ return badpat("Unmatched \\(");
+ store(END);
+ sta = OKP;
+ return 0;
+}
+
+
+static UCHAR *bol;
+static UCHAR *bopat[MAXTAG];
+static UCHAR *eopat[MAXTAG];
+#ifdef NEEDPROTOS
+static UCHAR *pmatch( UCHAR *lp, UCHAR *ap );
+#else /* NEEDPROTOS */
+static UCHAR *pmatch();
+#endif /* NEEDPROTOS */
+
+/*
+ * re_exec:
+ * execute nfa to find a match.
+ *
+ * special cases: (nfa[0])
+ * BOL
+ * Match only once, starting from the
+ * beginning.
+ * CHR
+ * First locate the character without
+ * calling pmatch, and if found, call
+ * pmatch for the remaining string.
+ * END
+ * re_comp failed, poor luser did not
+ * check for it. Fail fast.
+ *
+ * If a match is found, bopat[0] and eopat[0] are set
+ * to the beginning and the end of the matched fragment,
+ * respectively.
+ *
+ */
+
+int
+slapd_re_exec( char *lp )
+{
+ register UCHAR c;
+ register UCHAR *ep = 0;
+ register UCHAR *ap = nfa;
+
+ bol = (UCHAR*)lp;
+
+ bopat[0] = 0;
+ bopat[1] = 0;
+ bopat[2] = 0;
+ bopat[3] = 0;
+ bopat[4] = 0;
+ bopat[5] = 0;
+ bopat[6] = 0;
+ bopat[7] = 0;
+ bopat[8] = 0;
+ bopat[9] = 0;
+
+ switch(*ap) {
+
+ case BOL: /* anchored: match from BOL only */
+ ep = pmatch((UCHAR*)lp,ap);
+ break;
+ case CHR: /* ordinary char: locate it fast */
+ c = *(ap+1);
+ while (*lp && *(UCHAR*)lp != c)
+ lp++;
+ if (!*lp) /* if EOS, fail, else fall thru. */
+ return 0;
+ default: /* regular matching all the way. */
+ do {
+ if ((ep = pmatch((UCHAR*)lp,ap)))
+ break;
+ lp++;
+ } while (*lp);
+
+ break;
+ case END: /* munged automaton. fail always */
+ return 0;
+ }
+ if (!ep)
+ return 0;
+
+ bopat[0] = (UCHAR*)lp;
+ eopat[0] = ep;
+ return 1;
+}
+
+/*
+ * pmatch: internal routine for the hard part
+ *
+ * This code is partly snarfed from an early grep written by
+ * David Conroy. The backref and tag stuff, and various other
+ * innovations are by oz.
+ *
+ * special case optimizations: (nfa[n], nfa[n+1])
+ * CLO ANY
+ * We KNOW .* will match everything upto the
+ * end of line. Thus, directly go to the end of
+ * line, without recursive pmatch calls. As in
+ * the other closure cases, the remaining pattern
+ * must be matched by moving backwards on the
+ * string recursively, to find a match for xy
+ * (x is ".*" and y is the remaining pattern)
+ * where the match satisfies the LONGEST match for
+ * x followed by a match for y.
+ * CLO CHR
+ * We can again scan the string forward for the
+ * single char and at the point of failure, we
+ * execute the remaining nfa recursively, same as
+ * above.
+ *
+ * At the end of a successful match, bopat[n] and eopat[n]
+ * are set to the beginning and end of subpatterns matched
+ * by tagged expressions (n = 1 to 9).
+ *
+ */
+
+#ifndef re_fail
+void re_fail();
+#endif /* re_fail */
+
+/*
+ * character classification table for word boundary operators BOW
+ * and EOW. the reason for not using ctype macros is that we can
+ * let the user add into our own table. see re_modw. This table
+ * is not in the bitset form, since we may wish to extend it in the
+ * future for other character classifications.
+ *
+ * TRUE for 0-9 A-Z a-z _
+ */
+static char chrtyp[MAXCHR] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 0, 0,
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 0, 0, 0, 0, 1, 0, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 0, 0, 0, 0, 0
+ };
+
+#define inascii(x) (0177&(x))
+#define iswordc(x) chrtyp[inascii(x)]
+#define isinset(x,y) ((x)[((y)&BLKIND)>>3] & bitarr[(y)&BITIND])
+
+/*
+ * skip values for CLO XXX to skip past the closure
+ */
+
+#define ANYSKIP 2 /* [CLO] ANY END ... */
+#define CHRSKIP 3 /* [CLO] CHR chr END ... */
+#define CCLSKIP 18 /* [CLO] CCL 16bytes END ... */
+
+static UCHAR *
+pmatch( UCHAR *lp, UCHAR *ap)
+{
+ register int op, c, n;
+ register UCHAR *e; /* extra pointer for CLO */
+ register UCHAR *bp; /* beginning of subpat.. */
+ register UCHAR *ep; /* ending of subpat.. */
+ UCHAR *are; /* to save the line ptr. */
+
+ while ((op = *ap++) != END)
+ switch(op) {
+
+ case CHR:
+ if (*lp++ != *ap++)
+ return 0;
+ break;
+ case ANY:
+ if (!*lp++)
+ return 0;
+ break;
+ case CCL:
+ c = *lp++;
+ if (!isinset(ap,c))
+ return 0;
+ ap += BITBLK;
+ break;
+ case BOL:
+ if (lp != bol)
+ return 0;
+ break;
+ case EOL:
+ if (*lp)
+ return 0;
+ break;
+ case BOT:
+ bopat[*ap++] = lp;
+ break;
+ case EOT:
+ eopat[*ap++] = lp;
+ break;
+ case BOW:
+ if ((lp!=bol && iswordc(lp[-1])) || !iswordc(*lp))
+ return 0;
+ break;
+ case EOW:
+ if (lp==bol || !iswordc(lp[-1]) || iswordc(*lp))
+ return 0;
+ break;
+ case REF:
+ n = *ap++;
+ bp = bopat[n];
+ ep = eopat[n];
+ while (bp < ep)
+ if (*bp++ != *lp++)
+ return 0;
+ break;
+ case CLO:
+ are = lp;
+ switch(*ap) {
+
+ case ANY:
+ while (*lp)
+ lp++;
+ n = ANYSKIP;
+ break;
+ case CHR:
+ c = *(ap+1);
+ while (*lp && c == *lp)
+ lp++;
+ n = CHRSKIP;
+ break;
+ case CCL:
+ while ((c = *lp) && isinset(ap+1,c))
+ lp++;
+ n = CCLSKIP;
+ break;
+ default:
+ re_fail("closure: bad nfa.", *ap);
+ return 0;
+ }
+
+ ap += n;
+
+ while (lp >= are) {
+ if ((e = pmatch(lp, ap)) != NULL)
+ return e;
+ --lp;
+ }
+ return 0;
+ default:
+ re_fail("re_exec: bad nfa.", op);
+ return 0;
+ }
+ return lp;
+}
+
+/*
+ * re_modw:
+ * add new characters into the word table to change re_exec's
+ * understanding of what a word should look like. Note that we
+ * only accept additions into the word definition.
+ *
+ * If the string parameter is 0 or null string, the table is
+ * reset back to the default containing A-Z a-z 0-9 _. [We use
+ * the compact bitset representation for the default table]
+ */
+
+static UCHAR deftab[16] = {
+ 0, 0, 0, 0, 0, 0, 0377, 003, 0376, 0377, 0377, 0207,
+ 0376, 0377, 0377, 007
+};
+
+void
+slapd_re_modw( char *s )
+{
+ register int i;
+
+ if (!s || !*s) {
+ for (i = 0; i < MAXCHR; i++)
+ if (!isinset(deftab,i))
+ iswordc(i) = 0;
+ }
+ else
+ while(*s)
+ iswordc(*s++) = 1;
+}
+
+/*
+ * re_subs:
+ * substitute the matched portions of the src in dst.
+ *
+ * & substitute the entire matched pattern.
+ *
+ * \digit substitute a subpattern, with the given tag number.
+ * Tags are numbered from 1 to 9. If the particular
+ * tagged subpattern does not exist, null is substituted.
+ */
+int
+slapd_re_subs( char *src, char *dst)
+{
+ register char c;
+ register int pin;
+ register UCHAR *bp;
+ register UCHAR *ep;
+
+ if (!*src || !bopat[0])
+ return 0;
+
+ while ((c = *src++) != 0) {
+ switch(c) {
+
+ case '&':
+ pin = 0;
+ break;
+
+ case '\\':
+ c = *src++;
+ if (c >= '0' && c <= '9') {
+ pin = c - '0';
+ break;
+ }
+
+ default:
+ *dst++ = c;
+ continue;
+ }
+
+ if ((bp = bopat[pin]) && (ep = eopat[pin])) {
+ while (*bp && bp < ep)
+ *dst++ = *(char*)bp++;
+ if (bp < ep)
+ return 0;
+ }
+ }
+ *dst = (char) 0;
+ return 1;
+}
+
+#ifdef DEBUG
+/*
+ * symbolic - produce a symbolic dump of the nfa
+ */
+void
+symbolic( char *s )
+{
+ printf("pattern: %s\n", s);
+ printf("nfacode:\n");
+ nfadump(nfa);
+}
+
+static void
+nfadump( UCHAR *ap)
+{
+ register int n;
+
+ while (*ap != END)
+ switch(*ap++) {
+ case CLO:
+ printf("CLOSURE");
+ nfadump(ap);
+ switch(*ap) {
+ case CHR:
+ n = CHRSKIP;
+ break;
+ case ANY:
+ n = ANYSKIP;
+ break;
+ case CCL:
+ n = CCLSKIP;
+ break;
+ }
+ ap += n;
+ break;
+ case CHR:
+ printf("\tCHR %c\n",*ap++);
+ break;
+ case ANY:
+ printf("\tANY .\n");
+ break;
+ case BOL:
+ printf("\tBOL -\n");
+ break;
+ case EOL:
+ printf("\tEOL -\n");
+ break;
+ case BOT:
+ printf("BOT: %d\n",*ap++);
+ break;
+ case EOT:
+ printf("EOT: %d\n",*ap++);
+ break;
+ case BOW:
+ printf("BOW\n");
+ break;
+ case EOW:
+ printf("EOW\n");
+ break;
+ case REF:
+ printf("REF: %d\n",*ap++);
+ break;
+ case CCL:
+ printf("\tCCL [");
+ for (n = 0; n < MAXCHR; n++)
+ if (isinset(ap,(UCHAR)n)) {
+ if (n < ' ')
+ printf("^%c", n ^ 0x040);
+ else
+ printf("%c", n);
+ }
+ printf("]\n");
+ ap += BITBLK;
+ break;
+ default:
+ printf("bad nfa. opcode %o\n", ap[-1]);
+ exit(1);
+ break;
+ }
+}
+#endif
+#endif /* MACOS or DOS or NEED_BSDREGEX */
diff --git a/ldap/servers/slapd/resourcelimit.c b/ldap/servers/slapd/resourcelimit.c
new file mode 100644
index 00000000..3f0d3840
--- /dev/null
+++ b/ldap/servers/slapd/resourcelimit.c
@@ -0,0 +1,653 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* resourcelimit.c - binder-based resource limits implementation */
+
+
+/*
+ * Implementation notes:
+ *
+ * At present this code only provides support for integer-based
+ * resource limits.
+ *
+ * When a successful bind occurs (i.e., when bind_credentials_set() is
+ * called), reslimit_update_from_dn() or reslimit_update_from_entry()
+ * must be called. These functions look in the binder entry and pull
+ * out attribute values that correspond to resource limits. Typically
+ * operational attributes are used, e.g., nsSizeLimit to hold a
+ * binder-specific search size limit. The attributes should be single
+ * valued; if not, this code ignores all but the first value it finds.
+ * The virtual attribute interface is used to retrieve the binder entry
+ * values, so they can be based on COS, etc.
+ *
+ * Any resource limits found in the binder entry are cached in the
+ * connection structure. A connection object extension is used for this
+ * purpose. This means that if the attributes that correspond to binder
+ * entry are changed the resource limit won't be affected until the next
+ * bind occurs as that entry. The data in the connection extension is
+ * protected using a single writer/multiple reader locking scheme.
+ *
+ * A plugin or server subsystem that wants to use the resource limit
+ * subsystem should call slapi_reslimit_register() once for each limit it
+ * wants tracked. Note that slapi_reslimit_register() should be called
+ * early, i.e., before any client connections are accepted.
+ * slapi_reslimit_register() gives back an integer handle that is used
+ * later to refer to the limit in question. Here's a sample call:
+ */
+#if SLAPI_RESLIMIT_SAMPLE_CODE
+ static int sizelimit_reslimit_handle = -1;
+
+ if ( slapi_reslimit_register( SLAPI_RESLIMIT_TYPE_INT, "nsSizeLimit",
+ &sizelimit_reslimit_handle ) != SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ /* limit could not be registered -- fatal error? */
+ }
+ ...
+#endif
+
+/*
+ * A successful call to slapi_reslimit_register() results in a new
+ * entry in the reslimit_map, which is private to this source file.
+ * The map data structure is protected using a single writer/multiple
+ * reader locking scheme.
+ *
+ * To retrieve a binder-based limit, simple call
+ * slapi_reslimit_get_integer_limit(). If a value was present in the
+ * binder entry, it will be given back to the caller and
+ * SLAPI_RESLIMIT_STATUS_SUCCESS will be returned. If no value was
+ * present or the connection is NULL, SLAPI_RESLIMIT_STATUS_NOVALUE is
+ * returned. Other errors may be returned also. Here's a sample call:
+ */
+#if SLAPI_RESLIMIT_SAMPLE_CODE
+ int rc, sizelimit;
+
+ rc = slapi_reslimit_get_integer_limit( conn, sizelimit_reslimit_handle,
+ &sizelimit );
+
+ switch( rc ) {
+ case SLAPI_RESLIMIT_STATUS_SUCCESS: /* got a value */
+ break;
+ case SLAPI_RESLIMIT_STATUS_NOVALUE: /* no limit value available */
+ sizelimit = 500; /* use a default value */
+ break;
+ default: /* some other error occurred */
+ sizelimit = 500; /* use a default value */
+ }
+#endif
+
+/*
+ * The function reslimit_cleanup() is called from main() to dispose of
+ * memory, locks, etc. so tools like Purify() don't report leaks at exit.
+ */
+/* End of implementation notes */
+
+#include "slap.h"
+
+
+/*
+ * Macros.
+ */
+#define SLAPI_RESLIMIT_MODULE "binder-based resource limits"
+/* #define SLAPI_RESLIMIT_DEBUG */ /* define this to enable extra logging */
+ /* also forces trace log messages to */
+ /* always be logged */
+
+#ifdef SLAPI_RESLIMIT_DEBUG
+#define SLAPI_RESLIMIT_TRACELEVEL LDAP_DEBUG_ANY
+#else /* SLAPI_RESLIMIT_DEBUG */
+#define SLAPI_RESLIMIT_TRACELEVEL LDAP_DEBUG_TRACE
+#endif /* SLAPI_RESLIMIT_DEBUG */
+
+
+/*
+ * Structures and types.
+ */
+/* Per-connection resource limits data */
+typedef struct slapi_reslimit_conndata {
+ PRRWLock *rlcd_rwlock; /* to serialize access to the rest */
+ int rlcd_integer_count; /* size of rlcd_integer_limit array */
+ PRBool *rlcd_integer_available; /* array that says whether each */
+ /* value is available */
+ int *rlcd_integer_value; /* array that holds limit values */
+} SLAPIResLimitConnData;
+
+/* Mapping between attribute and limit */
+typedef struct slapi_reslimit_map {
+ int rlmap_type; /* always SLAPI_RESLIMIT_TYPE_INT for now */
+ char *rlmap_at; /* attribute type name */
+} SLAPIResLimitMap;
+
+
+/*
+ * Static variables (module globals).
+ */
+static int reslimit_inited = 0;
+static int reslimit_connext_objtype = 0;
+static int reslimit_connext_handle = 0;
+static struct slapi_reslimit_map *reslimit_map = NULL;
+static int reslimit_map_count = 0;
+static struct slapi_componentid *reslimit_componentid=NULL;
+
+/*
+ * reslimit_map_rwlock is used to serialize access to
+ * reslimit_map and reslimit_map_count
+ */
+static PRRWLock *reslimit_map_rwlock = NULL;
+
+/*
+ * Static functions.
+ */
+static int reslimit_init( void );
+static void *reslimit_connext_constructor( void *object, void *parent );
+static void reslimit_connext_destructor( void *extension, void *object,
+ void *parent );
+static int reslimit_get_ext( Slapi_Connection *conn, const char *logname,
+ SLAPIResLimitConnData **rlcdpp );
+static int reslimit_bv2int( const struct berval *bvp );
+static char ** reslimit_get_registered_attributes();
+
+
+/*
+ * reslimit_init() must be called before any resource related work
+ * is done. It is safe to call this more than once, but reslimit_inited
+ * can be tested to avoid a call.
+ *
+ * Returns zero if all goes well and non-zero if not.
+ */
+static int
+reslimit_init( void )
+{
+ if ( reslimit_inited == 0 ) {
+ if ( slapi_register_object_extension( SLAPI_RESLIMIT_MODULE,
+ SLAPI_EXT_CONNECTION, reslimit_connext_constructor,
+ reslimit_connext_destructor,
+ &reslimit_connext_objtype, &reslimit_connext_handle )
+ != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "reslimit_init: slapi_register_object_extension()"
+ " failed\n" );
+ return( -1 );
+ }
+
+ if (( reslimit_map_rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
+ "resourcelimit map rwlock" )) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "reslimit_init: PR_NewRWLock() failed\n" );
+ return( -1 );
+ }
+
+ reslimit_inited = 1;
+ }
+
+ reslimit_componentid=generate_componentid(NULL,COMPONENT_RESLIMIT);
+
+ return( 0 );
+}
+
+
+
+
+/*
+ * Dispose of any allocated memory, locks, other resources. Called when
+ * server is shutting down.
+ */
+void
+reslimit_cleanup( void )
+{
+ int i;
+
+ if ( reslimit_map != NULL ) {
+ for ( i = 0; i < reslimit_map_count; ++i ) {
+ if ( reslimit_map[ i ].rlmap_at != NULL ) {
+ slapi_ch_free( (void **)&reslimit_map[ i ].rlmap_at );
+ }
+ }
+ slapi_ch_free( (void **)&reslimit_map );
+ }
+
+ if ( reslimit_map_rwlock != NULL ) {
+ PR_DestroyRWLock( reslimit_map_rwlock );
+ }
+
+ if ( reslimit_componentid != NULL ) {
+ release_componentid( reslimit_componentid );
+ }
+}
+
+
+/*
+ * constructor for the connection object extension.
+ */
+static void *
+reslimit_connext_constructor( void *object, void *parent )
+{
+ SLAPIResLimitConnData *rlcdp;
+ PRRWLock *rwlock;
+
+ if (( rwlock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
+ "resource limit connection data rwlock" )) == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "reslimit_connext_constructor: PR_NewRWLock() failed\n" );
+ return( NULL );
+ }
+
+ rlcdp = (SLAPIResLimitConnData *)slapi_ch_calloc( 1,
+ sizeof( SLAPIResLimitConnData ));
+ rlcdp->rlcd_rwlock = rwlock;
+
+ return( rlcdp );
+}
+
+
+/*
+ * destructor for the connection object extension.
+ */
+static void
+reslimit_connext_destructor( void *extension, void *object, void *parent )
+{
+ SLAPIResLimitConnData *rlcdp = (SLAPIResLimitConnData *)extension;
+
+ if ( rlcdp->rlcd_integer_available != NULL ) {
+ slapi_ch_free( (void **)&rlcdp->rlcd_integer_available );
+ }
+ if ( rlcdp->rlcd_integer_value != NULL ) {
+ slapi_ch_free( (void **)&rlcdp->rlcd_integer_value );
+ }
+ PR_DestroyRWLock( rlcdp->rlcd_rwlock );
+ slapi_ch_free( (void **)&rlcdp );
+}
+
+
+/*
+ * utility function to retrieve the connection object extension.
+ *
+ * if logname is non-NULL, errors are logged.
+ */
+static int
+reslimit_get_ext( Slapi_Connection *conn, const char *logname,
+ SLAPIResLimitConnData **rlcdpp )
+{
+ if ( !reslimit_inited && reslimit_init() != 0 ) {
+ if ( NULL != logname ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "%s: reslimit_init() failed\n", logname );
+ }
+ return( SLAPI_RESLIMIT_STATUS_INIT_FAILURE );
+ }
+
+ if (( *rlcdpp = (SLAPIResLimitConnData *)slapi_get_object_extension(
+ reslimit_connext_objtype, conn,
+ reslimit_connext_handle )) == NULL ) {
+ if ( NULL != logname ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "%s: slapi_get_object_extension() returned NULL\n", logname );
+ }
+ return( SLAPI_RESLIMIT_STATUS_INTERNAL_ERROR );
+ }
+
+ return( SLAPI_RESLIMIT_STATUS_SUCCESS );
+}
+
+
+/*
+ * utility function to convert a string-represented integer to an int.
+ *
+ * XXXmcs: wouldn't need this if slapi_value_get_int() returned a signed int!
+ */
+static int
+reslimit_bv2int( const struct berval *bvp )
+{
+ int rc = 0;
+ char smallbuf[ 25 ], *buf;
+
+ if ( bvp != NULL ) {
+ /* make a copy to ensure it is zero-terminated */
+ if ( bvp->bv_len < sizeof( smallbuf )) {
+ buf = smallbuf;
+ } else {
+ buf = slapi_ch_malloc( bvp->bv_len + 1 );
+ }
+ memcpy( buf, bvp->bv_val, bvp->bv_len);
+ buf[ bvp->bv_len ] = '\0';
+
+ rc = atoi( buf );
+
+ if ( buf != smallbuf ) {
+ slapi_ch_free( (void **)&smallbuf );
+ }
+ }
+
+ return( rc );
+}
+
+
+/**** Semi-public functions start here ***********************************/
+/*
+ * These functions are exposed to other parts of the server only, i.e.,
+ * they are NOT part of the official SLAPI API.
+ */
+
+/*
+ * Set the resource limits associated with connection `conn' based on the
+ * entry named by `dn'. If `dn' is NULL, limits are returned to their
+ * default state.
+ *
+ * A SLAPI_RESLIMIT_STATUS_... code is returned.
+ */
+int
+reslimit_update_from_dn( Slapi_Connection *conn, Slapi_DN *dn )
+{
+ Slapi_Entry *e;
+ int rc;
+
+ e = NULL;
+ if ( dn != NULL ) {
+
+ char ** attrs = reslimit_get_registered_attributes();
+ (void) slapi_search_internal_get_entry( dn, attrs, &e , reslimit_componentid);
+ charray_free(attrs);
+ }
+
+ rc = reslimit_update_from_entry( conn, e );
+
+ if ( NULL != e ) {
+ slapi_entry_free( e );
+ }
+
+ return( rc );
+}
+
+
+/*
+ * Set the resource limits associated with connection `conn' based on the
+ * entry `e'. If `e' is NULL, limits are returned to their default state.
+ * If `conn' is NULL, nothing is done.
+ *
+ * A SLAPI_RESLIMIT_STATUS_... code is returned.
+ */
+int
+reslimit_update_from_entry( Slapi_Connection *conn, Slapi_Entry *e )
+{
+ char *fnname = "reslimit_update_from_entry()";
+ char *actual_type_name, *get_ext_logname;
+ int i, rc, type_name_disposition, free_flags;
+ SLAPIResLimitConnData *rlcdp;
+ Slapi_ValueSet *vs;
+
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "=> %s conn=0x%x, entry=0x%x\n",
+ fnname, conn, e );
+
+ rc = SLAPI_RESLIMIT_STATUS_SUCCESS; /* optimistic */
+
+ /* if conn is NULL, there is nothing to be done */
+ if ( conn == NULL ) {
+ goto log_and_return;
+ }
+
+
+ if ( NULL == e ) {
+ get_ext_logname = NULL; /* do not log errors if resetting limits */
+ } else {
+ get_ext_logname = fnname;
+ }
+ if (( rc = reslimit_get_ext( conn, get_ext_logname, &rlcdp )) !=
+ SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ goto log_and_return;
+ }
+
+ /* LOCK FOR READ -- map lock */
+ PR_RWLock_Rlock( reslimit_map_rwlock );
+ /* LOCK FOR WRITE -- conn. data lock */
+ PR_RWLock_Wlock( rlcdp->rlcd_rwlock );
+
+ if ( rlcdp->rlcd_integer_value == NULL ) {
+ rlcdp->rlcd_integer_count = reslimit_map_count;
+ if ( rlcdp->rlcd_integer_count > 0 ) {
+ rlcdp->rlcd_integer_available = (PRBool *)slapi_ch_calloc(
+ rlcdp->rlcd_integer_count, sizeof( PRBool ));
+ rlcdp->rlcd_integer_value = (int *)slapi_ch_calloc(
+ rlcdp->rlcd_integer_count, sizeof( int ));
+ }
+ }
+
+ for ( i = 0; i < rlcdp->rlcd_integer_count; ++i ) {
+ if ( reslimit_map[ i ].rlmap_type != SLAPI_RESLIMIT_TYPE_INT ) {
+ continue;
+ }
+
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
+ "%s: setting limit for handle %d (based on %s)\n",
+ fnname, i, reslimit_map[ i ].rlmap_at );
+
+ rlcdp->rlcd_integer_available[ i ] = PR_FALSE;
+
+ if ( NULL != e && 0 == slapi_vattr_values_get( e,
+ reslimit_map[ i ].rlmap_at, &vs, &type_name_disposition,
+ &actual_type_name, 0, &free_flags )) {
+ Slapi_Value *v;
+ int index;
+ const struct berval *bvp;
+
+ if (( index = slapi_valueset_first_value( vs, &v )) != -1 &&
+ ( bvp = slapi_value_get_berval( v )) != NULL ) {
+ rlcdp->rlcd_integer_value[ i ] = reslimit_bv2int( bvp );
+ rlcdp->rlcd_integer_available[ i ] = PR_TRUE;
+
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
+ "%s: set limit based on %s to %d\n",
+ fnname, reslimit_map[ i ].rlmap_at,
+ rlcdp->rlcd_integer_value[ i ] );
+
+ if ( slapi_valueset_next_value( vs, index, &v ) != -1 ) {
+ char ebuf[ BUFSIZ ];
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "%s: ignoring multiple values for %s in entry \n",
+ fnname, reslimit_map[ i ].rlmap_at,
+ escape_string( slapi_entry_get_dn_const( e ),
+ ebuf ));
+ }
+ }
+
+ slapi_vattr_values_free( &vs, &actual_type_name, free_flags);
+ }
+ }
+
+ PR_RWLock_Unlock( rlcdp->rlcd_rwlock );
+ /* UNLOCKED -- conn. data lock */
+ PR_RWLock_Unlock( reslimit_map_rwlock );
+ /* UNLOCKED -- map lock */
+
+log_and_return:
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "<= %s returning status %d\n",
+ fnname, rc, 0 );
+
+ return( rc );
+}
+
+/* return the list of registered attributes */
+
+static char ** reslimit_get_registered_attributes()
+{
+
+ int i;
+ char **attrs=NULL;
+
+ /* LOCK FOR READ -- map lock */
+ PR_RWLock_Rlock( reslimit_map_rwlock );
+
+ for ( i = 0; i < reslimit_map_count; ++i ) {
+ if ( reslimit_map[ i ].rlmap_at != NULL ) {
+ charray_add(&attrs, slapi_ch_strdup(reslimit_map[ i ].rlmap_at));
+ }
+ }
+
+ PR_RWLock_Unlock( reslimit_map_rwlock );
+
+ return attrs;
+}
+
+
+/**** Public functions can be found below this point *********************/
+/*
+ * These functions are exposed to plugins, i.e., they are part of the
+ * official SLAPI API.
+ */
+
+/*
+ * Register a new resource to be tracked. `type' must be
+ * SLAPI_RESLIMIT_TYPE_INT and `attrname' is an LDAP attribute type that
+ * is consulted in the bound entry to determine the limit's value.
+ *
+ * A SLAPI_RESLIMIT_STATUS_... code is returned. If it is ...SUCCESS, then
+ * `*handlep' is set to an opaque integer value that should be used in
+ * subsequent calls to slapi_reslimit_get_integer_limit().
+ */
+int
+slapi_reslimit_register( int type, const char *attrname, int *handlep )
+{
+ char *fnname = "slapi_reslimit_register()";
+ int i, rc;
+
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "=> %s attrname=%s\n",
+ fnname, attrname, 0 );
+
+ rc = SLAPI_RESLIMIT_STATUS_SUCCESS; /* optimistic */
+
+ /* initialize if necessary */
+ if ( !reslimit_inited && reslimit_init() != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "%s: reslimit_init() failed\n", fnname );
+ rc = SLAPI_RESLIMIT_STATUS_INIT_FAILURE;
+ goto log_and_return;
+ }
+
+ /* sanity check parameters */
+ if ( type != SLAPI_RESLIMIT_TYPE_INT || attrname == NULL
+ || handlep == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "%s: parameter error\n", fnname );
+ rc = SLAPI_RESLIMIT_STATUS_PARAM_ERROR;
+ goto log_and_return;
+ }
+
+ /* LOCK FOR WRITE -- map lock */
+ PR_RWLock_Wlock( reslimit_map_rwlock );
+
+ /*
+ * check that attrname is not already registered
+ */
+ for ( i = 0; i < reslimit_map_count; ++i ) {
+ if ( 0 == slapi_attr_type_cmp( reslimit_map[ i ].rlmap_at,
+ attrname, SLAPI_TYPE_CMP_EXACT )) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "%s: parameter error (%s already registered)\n",
+ attrname, fnname );
+ rc = SLAPI_RESLIMIT_STATUS_PARAM_ERROR;
+ goto unlock_and_return;
+ }
+ }
+
+ /*
+ * expand the map array and add the new element
+ */
+ reslimit_map = (SLAPIResLimitMap *)slapi_ch_realloc(
+ (char *)reslimit_map,
+ (1 + reslimit_map_count) * sizeof( SLAPIResLimitMap ));
+ reslimit_map[ reslimit_map_count ].rlmap_type = type;
+ reslimit_map[ reslimit_map_count ].rlmap_at
+ = slapi_ch_strdup( attrname );
+ *handlep = reslimit_map_count;
+ ++reslimit_map_count;
+
+unlock_and_return:
+ PR_RWLock_Unlock( reslimit_map_rwlock );
+ /* UNLOCKED -- map lock */
+
+log_and_return:
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
+ "<= %s returning status=%d, handle=%d\n", fnname, rc,
+ (handlep == NULL) ? -1 : *handlep );
+
+ return( rc );
+}
+
+
+/*
+ * Retrieve the integer limit associated with connection `conn' for
+ * the resource identified by `handle'.
+ *
+ * A SLAPI_RESLIMIT_STATUS_... code is returned:
+ *
+ * SLAPI_RESLIMIT_STATUS_SUCCESS -- `*limitp' is set to the limit value.
+ * SLAPI_RESLIMIT_STATUS_NOVALUE -- no limit value is available (use default).
+ * Another SLAPI_RESLIMIT_STATUS_... code -- some more fatal error occurred.
+ *
+ * If `conn' is NULL, SLAPI_RESLIMIT_STATUS_NOVALUE is returned.
+ */
+int
+slapi_reslimit_get_integer_limit( Slapi_Connection *conn, int handle,
+ int *limitp )
+{
+ char *fnname = "slapi_reslimit_get_integer_limit()";
+ int rc;
+ SLAPIResLimitConnData *rlcdp;
+
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "=> %s conn=0x%x, handle=%d\n",
+ fnname, conn, handle );
+
+ rc = SLAPI_RESLIMIT_STATUS_SUCCESS; /* optimistic */
+
+ /* sanity check parameters */
+ if ( limitp == NULL ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "%s: parameter error\n", fnname );
+ rc = SLAPI_RESLIMIT_STATUS_PARAM_ERROR;
+ goto log_and_return;
+ }
+
+ if ( conn == NULL ) {
+ rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
+ goto log_and_return;
+ }
+
+ if (( rc = reslimit_get_ext( conn, fnname, &rlcdp )) !=
+ SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ goto log_and_return;
+ }
+ if(rlcdp->rlcd_integer_count==0) { /* peek at it to avoid lock */
+ rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
+ } else {
+ PR_RWLock_Rlock( rlcdp->rlcd_rwlock );
+ if(rlcdp->rlcd_integer_count==0) {
+ rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
+ } else if ( handle < 0 || handle >= rlcdp->rlcd_integer_count ) {
+ slapi_log_error( SLAPI_LOG_FATAL, SLAPI_RESLIMIT_MODULE,
+ "%s: unknown handle %d\n", fnname, handle );
+ rc = SLAPI_RESLIMIT_STATUS_UNKNOWN_HANDLE;
+ } else if ( rlcdp->rlcd_integer_available[ handle ] ) {
+ *limitp = rlcdp->rlcd_integer_value[ handle ];
+ } else {
+ rc = SLAPI_RESLIMIT_STATUS_NOVALUE;
+ }
+ PR_RWLock_Unlock( rlcdp->rlcd_rwlock );
+ }
+
+
+log_and_return:
+ if ( LDAPDebugLevelIsSet( LDAP_DEBUG_TRACE )) {
+ if ( rc == SLAPI_RESLIMIT_STATUS_SUCCESS ) {
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL,
+ "<= %s returning SUCCESS, value=%d\n", fnname, *limitp, 0 );
+ } else if ( rc == SLAPI_RESLIMIT_STATUS_NOVALUE ) {
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "<= %s returning NO VALUE\n",
+ fnname, 0, 0 );
+ } else {
+ LDAPDebug( SLAPI_RESLIMIT_TRACELEVEL, "<= %s returning ERROR %d\n",
+ fnname, rc, 0 );
+ }
+ }
+
+ return( rc );
+}
+/**** Public functions END ***********************************************/
diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c
new file mode 100644
index 00000000..b8be99f7
--- /dev/null
+++ b/ldap/servers/slapd/result.c
@@ -0,0 +1,1794 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* result.c - routines to send ldap results, errors, and referrals */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <unistd.h>
+#endif
+#include <errno.h>
+#include <signal.h>
+#include "slap.h"
+#include "pratom.h"
+#include "fe.h"
+#include "vattr_spi.h"
+
+
+#if defined( NET_SSL )
+#include <ssl.h>
+#endif
+
+PRUint64 num_entries_sent;
+PRUint64 num_bytes_sent;
+PRLock *num_sent_mutex;
+
+static long current_conn_count;
+static PRLock *current_conn_count_mutex;
+
+static int flush_ber( Slapi_PBlock *pb, Connection *conn,
+ Operation *op, BerElement *ber, int type );
+static char *notes2str( unsigned int notes, char *buf, size_t buflen );
+static void log_result( Slapi_PBlock *pb, Operation *op, int err,
+ unsigned long tag, int nentries );
+static void log_entry( Operation *op, Slapi_Entry *e );
+static void log_referral( Operation *op );
+
+#define _LDAP_SEND_RESULT 0
+#define _LDAP_SEND_REFERRAL 1
+#define _LDAP_SEND_ENTRY 2
+
+#define SLAPI_SEND_VATTR_FLAG_REALONLY 0x01
+#define SLAPI_SEND_VATTR_FLAG_VIRTUALONLY 0x02
+
+void g_set_num_entries_sent( PRUint64 val )
+{
+ num_entries_sent = val;
+}
+
+PRUint64 g_get_num_entries_sent()
+{
+ return( num_entries_sent );
+}
+
+void g_set_num_bytes_sent( PRUint64 val )
+{
+ num_bytes_sent = val;
+}
+
+PRUint64 g_get_num_bytes_sent()
+{
+ return( num_bytes_sent );
+}
+
+void g_set_num_sent_mutex( PRLock *plock )
+{
+ num_sent_mutex = plock;
+}
+
+PRLock *g_get_num_sent_mutex()
+{
+ return( num_sent_mutex );
+}
+
+static void
+delete_default_referral(struct berval **referrals)
+{
+ if (referrals)
+ {
+ int ii = 0;
+ for (ii = 0; referrals[ii]; ++ii)
+ ber_bvfree(referrals[ii]);
+ slapi_ch_free((void**)&referrals);
+ }
+}
+
+void
+g_set_default_referral( struct berval **ldap_url ) {
+ struct berval **default_referral;
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ int nReferrals;
+
+ /* check to see if we want to delete all referrals */
+ if ( ldap_url && ldap_url[0] &&
+ strcasecmp ( (char *)ldap_url[0]->bv_val, REFERRAL_REMOVE_CMD) == 0 ) {
+ delete_default_referral(slapdFrontendConfig->defaultreferral);
+ slapdFrontendConfig->defaultreferral = NULL;
+ return;
+ }
+
+ /* count the number of referrals */
+ for ( nReferrals = 0; ldap_url && ldap_url[nReferrals]; nReferrals++ )
+ ;
+
+ default_referral = (struct berval **)
+ slapi_ch_malloc( (nReferrals + 1) * sizeof(struct berval *) );
+
+ /* terminate the end, and add the referrals backwards */
+ default_referral[nReferrals--] = NULL;
+
+ while ( nReferrals >= 0 ) {
+ default_referral[nReferrals] = ber_bvdup(ldap_url[nReferrals]);
+ nReferrals--;
+ }
+
+ delete_default_referral(slapdFrontendConfig->defaultreferral);
+ slapdFrontendConfig->defaultreferral = default_referral;
+}
+
+struct berval**
+g_get_default_referral() {
+ slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
+ return slapdFrontendConfig->defaultreferral;
+}
+
+/*
+ * routines to manage keeping track of the current number of connections
+ * to the server. this information is used by the listener thread to
+ * determine when to stop listening for new connections, which it does
+ * when the total number of descriptors available minus the number of
+ * current connections drops below the reservedescriptors mark.
+ */
+
+void g_set_current_conn_count_mutex( PRLock *plock )
+{
+ PR_ASSERT( NULL != plock );
+
+ current_conn_count_mutex = plock;
+}
+
+PRLock *g_get_current_conn_count_mutex()
+{
+ return( current_conn_count_mutex );
+}
+
+long g_get_current_conn_count()
+{
+ long tmp;
+
+ PR_ASSERT( NULL != current_conn_count_mutex );
+
+ PR_Lock( current_conn_count_mutex );
+ tmp = current_conn_count;
+ PR_Unlock( current_conn_count_mutex );
+
+ return( tmp );
+}
+
+void g_increment_current_conn_count()
+{
+ PR_ASSERT( NULL != current_conn_count_mutex );
+
+ PR_Lock( current_conn_count_mutex );
+ current_conn_count++;
+ PR_Unlock( current_conn_count_mutex );
+}
+
+void g_decrement_current_conn_count()
+{
+ PR_ASSERT( NULL != current_conn_count_mutex );
+
+ PR_Lock( current_conn_count_mutex );
+ current_conn_count--;
+/* PR_ASSERT( current_conn_count >= 0 ); JCM BASTARD */
+ PR_Unlock( current_conn_count_mutex );
+}
+
+
+void
+send_ldap_result(
+ Slapi_PBlock *pb,
+ int err,
+ char *matched,
+ char *text,
+ int nentries,
+ struct berval **urls
+)
+{
+ send_ldap_result_ext(pb, err, matched, text, nentries, urls, NULL);
+}
+
+
+static int
+check_and_send_extended_result(Slapi_PBlock *pb, unsigned long tag, BerElement *ber)
+{
+ /*
+ * if this is an LDAPv3 ExtendedResponse to an ExtendedRequest,
+ * check to see if the optional responseName and response OCTET
+ * STRING need to be appended.
+ */
+ int rc= 0;
+ char *exop_oid;
+ struct berval *exop_value;
+ slapi_pblock_get(pb, SLAPI_EXT_OP_RET_OID, &exop_oid);
+ slapi_pblock_get(pb, SLAPI_EXT_OP_RET_VALUE, &exop_value);
+ if ( LDAP_RES_EXTENDED == tag ) {
+ if (exop_oid != NULL) {
+ rc = ber_printf( ber, "ts",
+ LDAP_TAG_EXOP_RES_OID, exop_oid);
+ }
+ if (rc != LBER_ERROR && exop_value != NULL) {
+ rc = ber_printf( ber, "to",
+ LDAP_TAG_EXOP_RES_VALUE,
+ exop_value->bv_val,
+ exop_value->bv_len );
+ }
+ }
+ return rc;
+}
+
+static int
+check_and_send_SASL_response(Slapi_PBlock *pb, unsigned long tag, BerElement *ber, Connection *conn)
+{
+ /*
+ * if this is an LDAPv3 BindResponse, check to see if the
+ * optional serverSaslCreds OCTET STRING is present and needs
+ * to be appended.
+ */
+ int rc= 0;
+ if ( LDAP_RES_BIND == tag && conn->c_ldapversion >= LDAP_VERSION3 )
+ {
+ struct berval *bind_ret_saslcreds; /* v3 serverSaslCreds */
+ slapi_pblock_get(pb, SLAPI_BIND_RET_SASLCREDS, &bind_ret_saslcreds);
+ if ( bind_ret_saslcreds != NULL ) {
+ rc = ber_printf( ber, "to",
+ LDAP_TAG_SASL_RES_CREDS,
+ bind_ret_saslcreds->bv_val,
+ bind_ret_saslcreds->bv_len );
+ }
+ }
+ return rc;
+}
+
+
+/*
+ * the input ber, if present, is not consumed
+ */
+void
+send_ldap_result_ext(
+ Slapi_PBlock *pb,
+ int err,
+ char *matched,
+ char *text,
+ int nentries,
+ struct berval **urls,
+ BerElement *ber
+)
+{
+ Connection *conn = pb->pb_conn;
+ int i, rc, logit = 0;
+ unsigned long tag;
+ int flush_ber_element = 1;
+ Slapi_Operation *operation;
+ char *dn;
+ passwdPolicy *pwpolicy = NULL;
+
+
+ slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn );
+ pwpolicy = new_passwdPolicy(pb, dn);
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+ if ( ber != NULL ) {
+ flush_ber_element = 0;
+ }
+
+
+ if(err != LDAP_SUCCESS){
+ /* count the error for snmp */
+ /* first check for security errors */
+ if( err == LDAP_INVALID_CREDENTIALS
+ || err == LDAP_INAPPROPRIATE_AUTH
+ || err == LDAP_AUTH_METHOD_NOT_SUPPORTED
+ || err == LDAP_STRONG_AUTH_NOT_SUPPORTED
+ || err == LDAP_STRONG_AUTH_REQUIRED
+ || err == LDAP_CONFIDENTIALITY_REQUIRED
+ || err == LDAP_INSUFFICIENT_ACCESS
+ || err == LDAP_AUTH_UNKNOWN )
+ {
+ if(g_get_global_snmp_vars()->ops_tbl.dsSecurityErrors!=NULL)
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsSecurityErrors);
+ }else if( err != LDAP_REFERRAL
+ && err != LDAP_OPT_REFERRALS
+ && err != LDAP_PARTIAL_RESULTS)
+ {
+ /*madman man spec says not to count as normal errors
+ --security errors
+ --referrals
+ -- partially seviced operations will not be conted as an error
+ */
+ if(g_get_global_snmp_vars()->ops_tbl.dsErrors!=NULL)
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsErrors);
+ }
+
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> send_ldap_result %d:%s:%s\n", err,
+ matched ? matched : "", text ? text : "" );
+
+ switch ( operation->o_tag ) {
+ case LBER_DEFAULT:
+ tag = LBER_SEQUENCE;
+ break;
+
+ case LDAP_REQ_SEARCH:
+ tag = LDAP_RES_SEARCH_RESULT;
+ break;
+
+ case LDAP_REQ_DELETE:
+ tag = LDAP_RES_DELETE;
+ break;
+
+ case LDAP_REFERRAL:
+ if ( conn->c_ldapversion > LDAP_VERSION2 ) {
+ tag = LDAP_TAG_REFERRAL;
+ break;
+ }
+ /* fallthru */
+
+ default:
+ tag = operation->o_tag + 1;
+ break;
+ }
+
+ if ( conn == NULL ) {
+ if ( operation->o_result_handler != NULL ) {
+ operation->o_result_handler( conn, operation, err,
+ matched, text, nentries, urls );
+ logit = 1;
+ }
+ goto log_and_return;
+ }
+
+ /* invalid password. Update the password retry here */
+ /* put this here for now. It could be a send_result pre-op plugin. */
+ if ( err == LDAP_INVALID_CREDENTIALS &&
+ pwpolicy->pw_lockout == 1 ) {
+
+ update_pw_retry ( pb );
+ }
+
+ if ( ber == NULL ) {
+ if ( (ber = der_alloc()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
+ goto log_and_return;
+ }
+ }
+
+ /* there is no admin limit exceeded in v2 - change to size limit XXX */
+ if ( err == LDAP_ADMINLIMIT_EXCEEDED &&
+ conn->c_ldapversion < LDAP_VERSION3 ) {
+ err = LDAP_SIZELIMIT_EXCEEDED;
+ }
+
+ if ( conn->c_ldapversion < LDAP_VERSION3 || urls == NULL ) {
+ char *save, *buf = NULL;
+
+ /*
+ * if there are v2 referrals to send, construct
+ * the v2 referral string.
+ */
+ if ( urls != NULL ) {
+ int len;
+
+ /* count the referral */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsReferrals);
+
+ /*
+ * figure out how much space we need
+ */
+ len = 10; /* strlen("Referral:") + NULL */
+ for ( i = 0; urls[i] != NULL; i++ ) {
+ len += urls[i]->bv_len + 1; /* newline + ref */
+ }
+ if ( text != NULL ) {
+ len += strlen( text ) + 1; /* text + newline */
+ }
+ /*
+ * allocate buffer and fill it in with the error
+ * message plus v2-style referrals.
+ */
+ buf = slapi_ch_malloc( len );
+ *buf = '\0';
+ if ( text != NULL ) {
+ strcpy( buf, text );
+ strcat( buf, "\n" );
+ }
+ strcat( buf, "Referral:" );
+ for ( i = 0; urls[i] != NULL; i++ ) {
+ strcat( buf, "\n" );
+ strcat( buf, urls[i]->bv_val );
+ }
+ save = text;
+ text = buf;
+ }
+
+ if ( (conn->c_ldapversion < LDAP_VERSION3 &&
+ err == LDAP_REFERRAL) || urls != NULL ) {
+ err = LDAP_PARTIAL_RESULTS;
+ }
+ rc = ber_printf( ber, "{it{ess", operation->o_msgid, tag, err,
+ matched ? matched : "", text ? text : "" );
+
+ /*
+ * if this is an LDAPv3 ExtendedResponse to an ExtendedRequest,
+ * check to see if the optional responseName and response OCTET
+ * STRING need to be appended.
+ */
+ if ( rc != LBER_ERROR )
+ {
+ rc= check_and_send_extended_result(pb, tag, ber);
+ }
+
+ /*
+ * if this is an LDAPv3 BindResponse, check to see if the
+ * optional serverSaslCreds OCTET STRING is present and needs
+ * to be appended.
+ */
+ if ( rc != LBER_ERROR )
+ {
+ rc= check_and_send_SASL_response(pb, tag, ber, conn);
+/* XXXmcs: should we also check for a missing auth response control? */
+ }
+
+ if ( rc != LBER_ERROR ) {
+ rc = ber_printf( ber, "}" ); /* one more } to come */
+ }
+
+ if ( buf != NULL ) {
+ text = save;
+ slapi_ch_free( (void**)&buf );
+ }
+ } else {
+ /*
+ * there are v3 referrals to add to the result
+ */
+ /* count the referral */
+ if (! config_check_referral_mode())
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsReferrals);
+ rc = ber_printf( ber, "{it{esst{s", operation->o_msgid, tag, err,
+ matched ? matched : "", text ? text : "", LDAP_TAG_REFERRAL,
+ urls[0]->bv_val );
+ for ( i = 1 ; urls[i] != NULL && rc != LBER_ERROR; i++ ) {
+ rc = ber_printf( ber, "s", urls[i]->bv_val );
+ }
+ if ( rc != LBER_ERROR ) {
+ rc = ber_printf( ber, "}" ); /* two more } to come */
+ }
+
+ /*
+ * if this is an LDAPv3 ExtendedResponse to an ExtendedRequest,
+ * check to see if the optional responseName and response OCTET
+ * STRING need to be appended.
+ */
+ if ( rc != LBER_ERROR )
+ {
+ rc= check_and_send_extended_result(pb, tag, ber);
+ }
+
+ /*
+ * if this is an LDAPv3 BindResponse, check to see if the
+ * optional serverSaslCreds OCTET STRING is present and needs
+ * to be appended.
+ */
+ if ( rc != LBER_ERROR )
+ {
+ rc= check_and_send_SASL_response(pb, tag, ber, conn);
+ }
+
+ if ( rc != LBER_ERROR ) {
+ rc = ber_printf( ber, "}" ); /* one more } to come */
+ }
+ }
+ if ( operation->o_results.result_controls != NULL
+ && conn->c_ldapversion >= LDAP_VERSION3
+ && write_controls( ber, operation->o_results.result_controls ) != 0 ) {
+ rc = LBER_ERROR;
+ }
+
+ if ( rc != LBER_ERROR ) { /* end the LDAPMessage sequence */
+ rc = ber_put_seq( ber );
+ }
+
+ if ( rc == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+ if (flush_ber_element == 1) {
+ /* we alloced the ber */
+ ber_free( ber, 1 /* freebuf */ );
+ }
+ goto log_and_return;
+ }
+
+ if ( flush_ber_element ) {
+ /* write only one pdu at a time - wait til it's our turn */
+ if ( flush_ber( pb, conn, operation, ber, _LDAP_SEND_RESULT ) == 0 ) {
+ logit = 1;
+ }
+ }
+
+log_and_return:
+ operation->o_status = SLAPI_OP_STATUS_RESULT_SENT; /* in case this has not yet been set */
+
+ if ( logit && operation_is_flag_set( operation,
+ OP_FLAG_ACTION_LOG_ACCESS )) {
+ log_result( pb, operation, err, tag, nentries );
+ }
+
+ delete_passwdPolicy (&pwpolicy);
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= send_ldap_result\n", 0, 0, 0 );
+}
+
+
+void
+send_nobackend_ldap_result( Slapi_PBlock *pb )
+{
+ struct berval **refurls;
+ int err;
+
+ refurls = g_get_default_referral();
+ err = ( refurls == NULL ) ? LDAP_NO_SUCH_OBJECT : LDAP_REFERRAL;
+ /* richm 20010831 - bug 556992 - the post op code needs to know what the
+ ldap error sent to the client was - slapi_send_ldap_result sets the
+ err in the pblock, so this function needs to also */
+ slapi_pblock_set(pb, SLAPI_RESULT_CODE, &err);
+
+ send_ldap_result( pb, err, NULL, NULL, 0, refurls );
+}
+
+
+int
+send_ldapv3_referral(
+ Slapi_PBlock *pb,
+ struct berval **urls
+)
+{
+ Connection *conn = pb->pb_conn;
+ BerElement *ber;
+ int i, rc, logit = 0;
+ Slapi_Operation *operation;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> send_ldapv3_referral\n", 0, 0, 0 );
+
+ if ( conn == NULL ) {
+ if ( operation->o_search_referral_handler != NULL ) {
+ if (( rc = (*operation->o_search_referral_handler)(
+ pb->pb_backend, conn, operation, urls )) == 0 ) {
+ logit = 1;
+ }
+ goto log_and_return;
+ }
+ return( 0 );
+ }
+ if ( urls == NULL ) {
+ return( 0 );
+ }
+
+ if ( (ber = der_alloc()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "ber_alloc", 0, NULL );
+ return( -1 );
+ }
+
+ /*
+ * send the ldapv3 SearchResultReference. it looks like this:
+ *
+ * SearchResultReference ::= [APPLICATION 19] SEQUENCE OF LDAPURL
+ *
+ * all wrapped up in an LDAPMessage sequence which looks like this:
+ * LDAPMessage ::= SEQUENCE {
+ * messageID MessageID,
+ * SearchResultReference
+ * controls [0] Controls OPTIONAL
+ * }
+ */
+
+ for ( i = 0, rc = ber_printf( ber, "{it{", operation->o_msgid,
+ LDAP_RES_SEARCH_REFERENCE );
+ rc != LBER_ERROR && urls[i] != NULL; i++ ) {
+ rc = ber_printf( ber, "s", urls[i]->bv_val );
+ }
+ if ( rc == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "ber_printf", 0, NULL );
+ return( -1 );
+ }
+ if ( ber_printf( ber, "}}" ) == LBER_ERROR ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "ber_printf", 0, NULL );
+ return( -1 );
+ }
+
+ /* write only one pdu at a time - wait til it's our turn */
+ if ( (rc = flush_ber( pb, conn, operation, ber, _LDAP_SEND_REFERRAL
+ )) == 0 ) {
+ logit = 1;
+ }
+
+log_and_return:
+ if ( logit && operation_is_flag_set( operation,
+ OP_FLAG_ACTION_LOG_ACCESS)){
+ log_referral( operation );
+ }
+
+ return( rc );
+}
+
+/*
+ * send_ldap_referral - called to send a referral (SearchResultReference)
+ * to a v3 client during a search. for v2 clients, it just adds the
+ * referral(s) to the url list passed in the third parameter. this list
+ * is then returned to v2 clients when it is passed to send_ldap_result().
+ */
+int
+send_ldap_referral (
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ struct berval **refs,
+ struct berval ***urls
+)
+{
+ char *refAttr = "ref";
+ char *attrs[2] = { NULL, NULL };
+
+ /* count the referral */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsReferrals);
+
+ attrs[0] = refAttr;
+ if ( e != NULL &&
+ plugin_call_acl_plugin (pb, e, attrs, NULL,
+ SLAPI_ACL_READ, ACLPLUGIN_ACCESS_DEFAULT, NULL)
+ != LDAP_SUCCESS ) {
+ return( 0 );
+ }
+ if ( pb->pb_conn && pb->pb_conn->c_ldapversion > LDAP_VERSION2 ) {
+ /*
+ * v3 connection - send the referral(s) in a
+ * SearchResultReference packet right now.
+ */
+ return( send_ldapv3_referral( pb, refs ) );
+ } else {
+ /*
+ * v2 connection - add the referral(s) to the
+ * list being maintained in urls. they will be
+ * sent to the client later when send_ldap_result()
+ * is called.
+ */
+ int i, need, have;
+
+ if ( refs == NULL && urls == NULL ) {
+ return( 0 );
+ }
+
+ for ( have = 0; *urls != NULL && (*urls)[have] != NULL;
+ have++ ) {
+ ; /* NULL */
+ }
+ for ( need = 0; refs != NULL && refs[need] != NULL; need++ ) {
+ ; /* NULL */
+ }
+
+ *urls = (struct berval **) slapi_ch_realloc( (char *) *urls,
+ (need + have + 1) * sizeof(struct berval *) );
+ for ( i = have; i < have + need; i++ ) {
+ (*urls)[i] = ber_bvdup( refs[i - have] );
+ }
+ (*urls)[i] = NULL;
+ }
+
+ return( 0 );
+}
+
+int
+encode_attr_2(
+ Slapi_PBlock *pb,
+ BerElement *ber,
+ Slapi_Entry *e,
+ Slapi_ValueSet *vs,
+ int attrsonly,
+ const char *attribute_type,
+ const char *returned_type
+)
+{
+
+ char *attrs[2] = { NULL, NULL };
+
+ attrs[0] = (char*)attribute_type;
+
+#if !defined(DISABLE_ACL_CHECK)
+ if ( plugin_call_acl_plugin (pb, e, attrs, NULL, SLAPI_ACL_READ,
+ ACLPLUGIN_ACCESS_READ_ON_ATTR, NULL ) != LDAP_SUCCESS ) {
+ return( 0 );
+ }
+#endif
+
+ if ( ber_printf( ber, "{s[", returned_type ) == -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+ ber_free( ber, 1 );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "ber_printf type", 0, NULL );
+ return( -1 );
+ }
+
+ if ( ! attrsonly )
+ {
+ Slapi_Value *v;
+ int i= slapi_valueset_first_value(vs,&v);
+ while(i!=-1)
+ {
+ if ( ber_printf( ber, "o", v->bv.bv_val,v->bv.bv_len ) == -1 )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "ber_printf failed\n", 0, 0, 0 );
+ ber_free( ber, 1 );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR,
+ NULL, "ber_printf value", 0, NULL );
+ return( -1 );
+ }
+ i= slapi_valueset_next_value(vs,i,&v);
+ }
+ }
+
+ if ( ber_printf( ber, "]}" ) == -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+ ber_free( ber, 1 );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "ber_printf type end", 0, NULL );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
+int
+encode_attr(
+ Slapi_PBlock *pb,
+ BerElement *ber,
+ Slapi_Entry *e,
+ Slapi_Attr *a,
+ int attrsonly,
+ char *type
+)
+{
+ return encode_attr_2(pb,ber,e,&(a->a_present_values),attrsonly,a->a_type,type);
+}
+
+#define LASTMODATTR( x ) (strcasecmp( x, "modifytimestamp" ) == 0 \
+ || strcasecmp( x, "modifiersname" ) == 0 \
+ || strcasecmp( x, "createtimestamp" ) == 0 \
+ || strcasecmp( x, "creatorsname" ) == 0)
+
+/*
+ * send_ldap_search_entry:
+ * return 0 if OK
+ * return 1 if this entry not sent
+ * return -1 if error result sent or fatal error
+ */
+int
+send_ldap_search_entry(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ LDAPControl **ectrls,
+ char **attrs,
+ int attrsonly
+)
+{
+ return send_ldap_search_entry_ext(pb, e, ectrls, attrs, attrsonly, 0, 0, NULL);
+}
+
+/*
+ * LDAPv2 attr names from RFC1274 and their LDAPv3 equivalent.
+ *
+ * The ;binary attrs are deliberately reversed.
+ */
+static const char *idds_v2_attrt[][2] = {
+ {"commonName","cn"},
+ {"surname","sn"},
+ {"userCertificate;binary","userCertificate"},
+ {"caCertificate;binary","caCertificate"},
+ {"countryName","c"},
+ {"localityName","l"},
+ {"stateOrProvinceName","st"},
+ {"streetAddress","street"},
+ {"organizationName","o"},
+ {"organizationalUnitName","ou"},
+ {"userid","uid"},
+ {"rfc822Mailbox","mail"},
+ {"domainComponent","dc"},
+ {"mobileTelephoneNumber","mobile"},
+ {"pagerTelephoneNumber","pager"},
+ {"friendlyCountryName","co"},
+ {NULL,NULL}
+};
+
+/*
+ * Map an LDAPv3 attribute name to its LDAPv2 equivalent.
+ */
+static const char *idds_map_attrt_v3(
+ const char *atin
+)
+{
+ int i;
+
+ for (i = 0; idds_v2_attrt[i][0] != NULL; i++) {
+ if (strcasecmp(atin, idds_v2_attrt[i][1]) == 0) {
+ return (idds_v2_attrt[i][0]);
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * RFC: 2251 Page: 29
+ *
+ * attributes: A list of the attributes to be returned from each entry
+ * which matches the search filter. There are two special values which
+ * may be used: an empty list with no attributes, and the attribute
+ * description string "*". Both of these signify that all user
+ * attributes are to be returned. (The "*" allows the client to
+ * request all user attributes in addition to specific operational
+ * attributes).
+ *
+ * Attributes MUST be named at most once in the list, and are returned
+ * at most once in an entry. If there are attribute descriptions in
+ * the list which are not recognized, they are ignored by the server.
+ *
+ * If the client does not want any attributes returned, it can specify
+ * a list containing only the attribute with OID "1.1". This OID was
+ * chosen arbitrarily and does not correspond to any attribute in use.
+ */
+
+
+/* Helper functions */
+
+static int send_all_attrs(Slapi_Entry *e,char **attrs,Slapi_Operation *op,Slapi_PBlock *pb,BerElement *ber,int attrsonly,int ldapversion,int *dontsendattr, int real_attrs_only, int some_named_attrs)
+{
+ int i = 0;
+ int rc = 0;
+
+ int typelist_flags = 0;
+ vattr_type_thang *typelist = NULL;
+ vattr_type_thang *current_type = NULL;
+ char *current_type_name = NULL;
+ int rewrite_rfc1274 = 0;
+ int vattr_flags = 0;
+
+ if(real_attrs_only == SLAPI_SEND_VATTR_FLAG_REALONLY)
+ vattr_flags = SLAPI_REALATTRS_ONLY;
+ else
+ {
+ vattr_flags = SLAPI_VIRTUALATTRS_REQUEST_POINTERS;
+ if(real_attrs_only == SLAPI_SEND_VATTR_FLAG_VIRTUALONLY)
+ vattr_flags |= SLAPI_VIRTUALATTRS_ONLY;
+ }
+
+ if (some_named_attrs) {
+ /*
+ * If the client listed some attribute types by name, one or
+ * more of the requested types MAY be operational. Inform the
+ * virtual attributes subsystem (certain optimizations are done
+ * by the vattrs code and vattr service providers if operational
+ * attributes are NOT requested).
+ */
+ vattr_flags |= SLAPI_VIRTUALATTRS_LIST_OPERATIONAL_ATTRS;
+ }
+
+ rc = slapi_vattr_list_attrs(e,&typelist,vattr_flags,&typelist_flags);
+ if (0 != rc) {
+ goto exit;
+ }
+
+ if (typelist_flags & SLAPI_VIRTUALATTRS_REALATTRS_ONLY) {
+ /*
+ * There is no point in consulting the vattr service providers
+ * for every attr if they didn't contribute to the attr list.
+ */
+ vattr_flags |= SLAPI_REALATTRS_ONLY;
+ }
+
+ rewrite_rfc1274 = config_get_rewrite_rfc1274();
+
+ /* Send the attrs back to the client */
+ for (current_type = vattr_typethang_first(typelist); current_type; current_type = vattr_typethang_next(current_type) ) {
+
+ Slapi_ValueSet **values = NULL;
+ int attr_free_flags = 0;
+ unsigned long current_type_flags = 0;
+ int sendit = 0;
+ char *name_to_return = NULL;
+ int *type_name_disposition = 0;
+ char **actual_type_name = NULL;
+ const char *v2name = NULL;
+
+ current_type_name = vattr_typethang_get_name(current_type);
+ current_type_flags = vattr_typethang_get_flags(current_type);
+
+ name_to_return = current_type_name;
+ /* We only return operational attributes if the client is LDAPv2 and the attribute is one of a special set,
+ OR if the client also requested the attribute by name. If it did, we use the specified name rather than
+ the base name.
+ */
+ if ( current_type_flags & SLAPI_ATTR_FLAG_OPATTR ) {
+ if ( LDAP_VERSION2 == ldapversion && LASTMODATTR( current_type_name) ) {
+ sendit = 1;
+ } else {
+ for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
+ if ( slapi_attr_type_cmp( attrs[i], current_type_name, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
+ sendit = 1;
+ name_to_return = op->o_searchattrs[i];
+ break;
+ }
+ }
+ }
+ /*
+ * it's a user attribute. send it.
+ */
+ } else {
+ sendit = 1;
+ }
+ /* Now send to the client */
+ if (sendit) {
+ /**********************************************/
+ int item_count = 0;
+ int iter = 0;
+ int j = 0;
+ Slapi_DN *namespace_dn;
+ Slapi_Backend *backend=0;
+ vattr_context *ctx;
+
+ /* get the namespace dn */
+ slapi_pblock_get( pb, SLAPI_BACKEND, (void *)&backend);
+ namespace_dn = (Slapi_DN*)slapi_be_getsuffix(backend, 0);
+
+ /* Get the attribute value from the vattr service */
+ /* ctx will be freed by attr_context_ungrok() */
+ ctx = vattr_context_new ( pb );
+ rc = slapi_vattr_namespace_values_get_sp(
+ ctx,
+ e,
+ namespace_dn,
+ current_type_name,
+ &values,
+ &type_name_disposition,
+ &actual_type_name,
+ vattr_flags | SLAPI_VIRTUALATTRS_SUPPRESS_SUBTYPES,
+ &attr_free_flags,
+ &item_count
+ );
+ if (0 == rc && item_count > 0) {
+
+ for(iter=0; iter<item_count; iter++)
+ {
+ if (SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE == type_name_disposition[iter]) {
+ name_to_return = actual_type_name[iter];
+ }
+
+ /*
+ * The dontsendattr array is used to track whether attributes
+ * that were explicitly requested by the client have been
+ * returned. Check here to see if the attribute we just
+ * arranged to send back was explicitly requested, and if so,
+ * set its dontsendattr flag so the send_specific_attrs()
+ * function does not return it a second time.
+ */
+ for ( i = 0; attrs != NULL && attrs[i] != NULL; i++ ) {
+ if ( !dontsendattr[i] && slapi_attr_type_cmp( current_type_name, attrs[i], SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
+ /* Client is also asking for an attr which is in '*', zap it. */
+ dontsendattr[i]= 1;
+ }
+ }
+
+ rc = encode_attr_2( pb, ber, e, values[iter], attrsonly, current_type_name, name_to_return );
+
+ if (rewrite_rfc1274 != 0) {
+ v2name = idds_map_attrt_v3(current_type_name);
+ if (v2name != NULL) {
+ /* also return values with RFC1274 attr name */
+ rc = encode_attr_2(pb, ber, e, values[iter],
+ attrsonly,
+ current_type_name,
+ v2name);
+ }
+ }
+
+ slapi_vattr_values_free(&(values[iter]), &(actual_type_name[iter]), attr_free_flags);
+ if ( rc != 0 ) {
+ goto exit;
+ }
+ }
+
+ slapi_ch_free((void**)&actual_type_name);
+ slapi_ch_free((void**)&type_name_disposition);
+ slapi_ch_free((void**)&values);
+
+ } else {
+ rc = 0;
+ }
+ }
+ }
+exit:
+ if (NULL != typelist) {
+ slapi_vattr_attrs_free(&typelist,typelist_flags);
+ }
+ return rc;
+}
+
+int send_specific_attrs(Slapi_Entry *e,char **attrs,Slapi_Operation *op,Slapi_PBlock *pb,BerElement *ber,int attrsonly,int ldapversion,int *dontsendattr, int real_attrs_only)
+{
+ int i,j = 0;
+ int rc = 0;
+ int vattr_flags = 0;
+ vattr_context *ctx;
+
+ if(real_attrs_only == SLAPI_SEND_VATTR_FLAG_REALONLY)
+ vattr_flags = SLAPI_REALATTRS_ONLY;
+ else
+ {
+ vattr_flags = SLAPI_VIRTUALATTRS_REQUEST_POINTERS;
+ if(real_attrs_only == SLAPI_SEND_VATTR_FLAG_VIRTUALONLY)
+ vattr_flags |= SLAPI_VIRTUALATTRS_ONLY;
+ }
+
+ for ( i = 0; attrs[i] != NULL; i++ )
+ {
+ char *current_type_name = attrs[i];
+ if(!dontsendattr[i]) {
+ Slapi_ValueSet **values = NULL;
+ int attr_free_flags = 0;
+ char *name_to_return = NULL;
+ char **actual_type_name= NULL;
+ int *type_name_disposition = 0;
+ int item_count = 0;
+ int iter = 0;
+ Slapi_DN *namespace_dn;
+ Slapi_Backend *backend=0;
+
+ /*
+ * Here we call the computed attribute code to see whether
+ * the requested attribute is to be computed.
+ * The subroutine compute_attribute calls encode_attr on our behalf, in order
+ * to avoid the inefficiency of returning a complex structure
+ * which we'd have to free
+ */
+ rc = compute_attribute(attrs[i],pb,ber,e,attrsonly,op->o_searchattrs[i]);
+ if (0 == rc) {
+ continue; /* Means this was a computed attr and we prcessed it OK. */
+ }
+ if (-1 != rc) {
+ /* Means that some error happened */
+ return rc;
+ }
+ else {
+ rc = 0; /* Means that we just didn't recognize this as a computed attr */
+ }
+
+ /* get the namespace dn */
+ slapi_pblock_get( pb, SLAPI_BACKEND, (void *)&backend);
+ namespace_dn = (Slapi_DN*)slapi_be_getsuffix(backend, 0);
+
+ /* Get the attribute value from the vattr service */
+ /* ctx will be freed by attr_context_ungrok() */
+ ctx = vattr_context_new ( pb );
+ rc = slapi_vattr_namespace_values_get_sp(
+ ctx,
+ e,
+ namespace_dn,
+ current_type_name,
+ &values,
+ &type_name_disposition,
+ &actual_type_name,
+ vattr_flags,
+ &attr_free_flags,
+ &item_count
+ );
+ if (0 == rc && item_count > 0) {
+
+ for(iter=0; iter<item_count; iter++)
+ {
+ if (SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE == type_name_disposition[iter]) {
+ name_to_return = actual_type_name[iter];
+ } else {
+ name_to_return = op->o_searchattrs[i];
+ }
+
+ /*
+ * The client may have specified a list of attributes
+ * with duplicates, 'cn cn cn'.
+ * We need to determine which of any duplicates take precedence
+ * For subtypes, the attribute which is most generic should be
+ * returned (since it will also trigger the return of the less
+ * generic attribute subtypes.
+ */
+ for ( j = i+1; attrs != NULL && attrs[j] != NULL && dontsendattr[i]==0; j++ )
+ {
+ if ( !dontsendattr[j] && slapi_attr_type_cmp( attrs[j], actual_type_name[iter], SLAPI_TYPE_CMP_SUBTYPE ) == 0 )
+ {
+ /* discover which is the more generic attribute and cancel the other*/
+ int attrbase = slapi_attr_type_cmp( attrs[j], current_type_name, SLAPI_TYPE_CMP_EXACT );
+
+ if(attrbase >= 0)
+ dontsendattr[j]= 1;
+ else
+ dontsendattr[i]= 1; /* the current value is superceeded later */
+ }
+ }
+
+ /* we may have just cancelled ourselves so check */
+ if(!dontsendattr[i])
+ rc = encode_attr_2( pb, ber, e, values[iter], attrsonly, current_type_name, name_to_return );
+
+ slapi_vattr_values_free(&(values[iter]), &(actual_type_name[iter]), attr_free_flags);
+ if ( rc != 0 ) {
+ goto exit;
+ }
+ }
+
+ slapi_ch_free((void**)&actual_type_name);
+ slapi_ch_free((void**)&type_name_disposition);
+ slapi_ch_free((void**)&values);
+
+ } else {
+ rc = 0;
+ }
+ }
+ }
+exit:
+ return rc;
+
+}
+
+
+int
+send_ldap_search_entry_ext(
+ Slapi_PBlock *pb,
+ Slapi_Entry *e,
+ LDAPControl **ectrls,
+ char **attrs,
+ int attrsonly,
+ int send_result,
+ int nentries,
+ struct berval **urls
+)
+{
+ Connection *conn = pb->pb_conn;
+ Operation *op = pb->pb_op;
+ BerElement *ber;
+ int i, rc = 0, logit = 0;
+ int alluserattrs, noattrs, some_named_attrs;
+ int *dontsendattr= NULL;
+ Slapi_Operation *operation;
+ int real_attrs_only = 0;
+ LDAPControl **ctrlp = 0;
+
+ slapi_pblock_get (pb, SLAPI_OPERATION, &operation);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> send_ldap_search_entry (%s)\n",
+ slapi_entry_get_dn_const(e), 0, 0 );
+
+ if ( conn == NULL ) {
+ if ( op->o_search_entry_handler != NULL ) {
+ if (( rc = (*op->o_search_entry_handler)(
+ pb->pb_backend, conn, op, e )) == 0 ) {
+ logit = 1;
+ goto log_and_return;
+ } else {
+ return rc;
+ }
+ }
+ return 0;
+ }
+
+#if !defined(DISABLE_ACL_CHECK)
+ if ( plugin_call_acl_plugin (pb, e, attrs, NULL,
+ SLAPI_ACL_READ, ACLPLUGIN_ACCESS_READ_ON_ENTRY, NULL ) != LDAP_SUCCESS ) {
+ LDAPDebug( LDAP_DEBUG_ACL, "acl: access to entry not allowed\n",
+ 0, 0, 0 );
+ return( 1 );
+ }
+#endif
+
+ /* Check for possible get_effective_rights control */
+ if ( operation->o_flags & OP_FLAG_GET_EFFECTIVE_RIGHTS ) {
+ char *errbuf = NULL;
+ rc = plugin_call_acl_plugin (pb, e, attrs, NULL, SLAPI_ACL_ALL,
+ ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS, &errbuf);
+ if ( rc != LDAP_SUCCESS ) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Failed to get effective rights for entry (%s), rc=%d\n",
+ slapi_entry_get_dn_const(e), rc, 0 );
+ /* Send error result and abort op if the control is critical */
+ send_ldap_result( pb, rc, NULL, errbuf, 0, NULL );
+ slapi_ch_free ( (void**)&errbuf );
+ return( -1 );
+ }
+ slapi_ch_free ( (void**)&errbuf );
+ }
+
+ if ( (ber = der_alloc()) == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_alloc failed\n", 0, 0, 0 );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "ber_alloc", 0, NULL );
+ return( -1 );
+ }
+
+ rc = ber_printf( ber, "{it{s{", op->o_msgid,
+ LDAP_RES_SEARCH_ENTRY, slapi_entry_get_dn_const(e) );
+
+ if ( rc == -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+ ber_free( ber, 1 );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "ber_printf dn", 0, NULL );
+ return( -1 );
+ }
+
+ /*
+ * in ldapv3, the special attribute "*" means all user attributes,
+ * NULL means all user attributes, and "1.1" means no attributes.
+ * operational attributes are only retrieved if they are named
+ * specifically.
+ */
+
+ /* figure out if we want all user attributes or no attributes at all */
+ alluserattrs = 0;
+ noattrs = 0;
+ some_named_attrs = 0;
+ if ( attrs == NULL ) {
+ alluserattrs = 1;
+ } else {
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ if ( strcmp( LDAP_ALL_USER_ATTRS, attrs[i] ) == 0 ) {
+ alluserattrs = 1;
+ } else if ( strcmp( LDAP_NO_ATTRS, attrs[i] ) == 0 ) {
+ noattrs = 1;
+ } else {
+ some_named_attrs = 1;
+ }
+ }
+ if ( i > 1 && noattrs ) {
+ /*
+ * user has specified the special "1.1" noattrs attr
+ * and some other stuff. this is not allowed, but
+ * what should we do? we'll allow them to keep going.
+ */
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "Accepting illegal other attributes specified with "
+ "special \"1.1\" attribute\n", 0, 0, 0 );
+ }
+ /*
+ * We maintain a flag array so that we can remove requests
+ * for duplicate attributes.
+ */
+ dontsendattr= (int*) slapi_ch_calloc( i+1, sizeof(int) );
+ }
+
+
+ /* determine whether we are to return virtual attributes */
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrlp);
+ if(slapi_control_present(ctrlp, LDAP_CONTROL_REAL_ATTRS_ONLY, NULL, NULL))
+ real_attrs_only = SLAPI_SEND_VATTR_FLAG_REALONLY;
+
+ if(slapi_control_present(ctrlp, LDAP_CONTROL_VIRT_ATTRS_ONLY, NULL, NULL))
+ {
+ if(real_attrs_only != SLAPI_SEND_VATTR_FLAG_REALONLY)
+ real_attrs_only = SLAPI_SEND_VATTR_FLAG_VIRTUALONLY;
+ else
+ {
+ /* we cannot service a request for virtual only and real only */
+ ber_free( ber, 1 );
+ slapi_ch_free( (void **) &dontsendattr );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "Both real and virtual attributes only controls", 0, NULL );
+ return( -1 );
+ }
+ }
+
+ /* look through each attribute in the entry */
+ if ( alluserattrs ) {
+ rc = send_all_attrs(e,attrs,op,pb,ber,attrsonly,conn->c_ldapversion,dontsendattr, real_attrs_only, some_named_attrs);
+ }
+
+ /* if the client explicitly specified a list of attributes look through each attribute requested */
+ if( (rc == 0) && (attrs!=NULL)) {
+ rc = send_specific_attrs(e,attrs,op,pb,ber,attrsonly,conn->c_ldapversion,dontsendattr,real_attrs_only);
+ }
+
+ /* Append effective rights to the stream of attribute list */
+ if ( operation->o_flags & OP_FLAG_GET_EFFECTIVE_RIGHTS )
+ {
+ char *gerstr;
+ char *entryrights;
+ char *attributerights;
+ char *p;
+
+ slapi_pblock_get (pb, SLAPI_PB_RESULT_TEXT, &gerstr);
+
+ /* Syntax check - see acleffectiverights.c */
+ if (gerstr && (p = strchr(gerstr, '\n')) != NULL &&
+ strncasecmp (gerstr, "entryLevelRights: ",
+ strlen("entryLevelRights: ")) == 0 &&
+ strncasecmp (p+1, "attributeLevelRights: ",
+ strlen("attributeLevelRights: ")) == 0 )
+ {
+ entryrights = gerstr + strlen ("entryLevelRights: ");
+ *p = '\0';
+ attributerights = p + 1 + strlen ("attributeLevelRights: ");
+ ber_printf( ber, "{s[o]}", "entryLevelRights", entryrights, strlen(entryrights) );
+ ber_printf( ber, "{s[o]}", "attributeLevelRights", attributerights, strlen(attributerights) );
+ }
+ }
+
+ slapi_ch_free( (void **) &dontsendattr ); /* I know it looks like we could free this when it wasn't allocated, the function ignores null pointers */
+
+ if (rc != 0) {
+ ber_free( ber, 1 );
+ goto exit;
+ }
+
+ rc = ber_printf( ber, "}}" );
+
+ if ( conn->c_ldapversion >= LDAP_VERSION3 ) {
+ if ( ectrls != NULL ) {
+ rc = write_controls( ber, ectrls );
+ }
+ /*
+ * The get-effective-rights control is called within
+ * the current function. Hence it can't be already in
+ * ectrls
+ */
+ if ( operation->o_flags & OP_FLAG_GET_EFFECTIVE_RIGHTS ) {
+ LDAPControl *gerctrl[2];
+ slapi_pblock_get (pb, SLAPI_RESCONTROLS, &ctrlp);
+ for ( i = 0; ctrlp != NULL && ctrlp[i] != NULL; i++ ) {
+ if (strcmp(ctrlp[i]->ldctl_oid, LDAP_CONTROL_GET_EFFECTIVE_RIGHTS ) == 0 ) {
+ gerctrl[0] = ctrlp[i];
+ gerctrl[1] = NULL;
+ rc = write_controls( ber, gerctrl );
+ break;
+ }
+ }
+ }
+ }
+
+ if ( rc != -1 ) {
+ rc = ber_printf( ber, "}" );
+ }
+
+ if ( rc == -1 ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "ber_printf failed\n", 0, 0, 0 );
+ ber_free( ber, 1 );
+ send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "ber_printf entry end", 0, NULL );
+ return( -1 );
+ }
+
+ if (send_result) {
+ send_ldap_result_ext( pb, LDAP_SUCCESS, NULL, NULL, nentries, urls, ber);
+ }
+
+ /* write only one pdu at a time - wait til it's our turn */
+ if ( (rc = flush_ber( pb, conn, op, ber, _LDAP_SEND_ENTRY )) == 0 ) {
+ logit = 1;
+ }
+
+log_and_return:
+ if ( logit && operation_is_flag_set(operation,
+ OP_FLAG_ACTION_LOG_ACCESS)){
+
+ log_entry( op, e );
+
+ if (send_result) {
+ unsigned long tag;
+
+ switch ( op->o_tag ) {
+ case LBER_DEFAULT:
+ tag = LBER_SEQUENCE;
+ break;
+
+ case LDAP_REQ_SEARCH:
+ tag = LDAP_RES_SEARCH_RESULT;
+ break;
+
+ case LDAP_REQ_DELETE:
+ tag = LDAP_RES_DELETE;
+ break;
+
+ case LDAP_REFERRAL:
+ if ( conn != NULL && conn->c_ldapversion > LDAP_VERSION2 ) {
+ tag = LDAP_TAG_REFERRAL;
+ break;
+ }
+ /* fallthru */
+
+ default:
+ tag = op->o_tag + 1;
+ break;
+ }
+
+ log_result( pb, op, LDAP_SUCCESS, tag, nentries );
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= send_ldap_search_entry\n", 0, 0, 0 );
+exit:
+ return( rc );
+}
+
+
+
+
+/*
+ * always frees the ber
+ */
+static int
+flush_ber(
+ Slapi_PBlock *pb,
+ Connection *conn,
+ Operation *op,
+ BerElement *ber,
+ int type
+)
+{
+ unsigned long bytes;
+ int rc = 0;
+
+ switch ( type ) {
+ case _LDAP_SEND_RESULT:
+ rc = plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_RESULT_FN );
+ break;
+ case _LDAP_SEND_REFERRAL:
+ rc = plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_REFERRAL_FN );
+ break;
+ case _LDAP_SEND_ENTRY:
+ rc = plugin_call_plugins( pb, SLAPI_PLUGIN_PRE_ENTRY_FN );
+ break;
+ }
+
+ if ( rc != 0 ) {
+ ber_free( ber, 1 );
+ return( rc );
+ }
+
+ if ((conn->c_flags & CONN_FLAG_CLOSING) || slapi_op_abandoned(pb)) {
+ LDAPDebug(LDAP_DEBUG_CONNS, "ber_flush skipped because the "
+ "connection was marked to be closed or abandoned\n", 0, 0, 0);
+ ber_free( ber, 1 );
+ /* One of the failure can be because the client has reset the connection ( closed )
+ * and the status needs to be updated to reflect it */
+ op->o_status = SLAPI_OP_STATUS_ABANDONED;
+ rc = -1;
+ } else {
+ ber_get_option( ber, LBER_OPT_BYTES_TO_WRITE, &bytes );
+
+ PR_Lock( conn->c_pdumutex );
+ rc = ber_flush( conn->c_sb, ber, 1 );
+ PR_Unlock( conn->c_pdumutex );
+
+ if ( rc != 0 ) {
+ int oserr = errno;
+ /* One of the failure can be because the client has reset the connection ( closed )
+ * and the status needs to be updated to reflect it */
+ op->o_status = SLAPI_OP_STATUS_ABANDONED;
+
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "ber_flush failed, error %d (%s)\n",
+ oserr, slapd_system_strerror( oserr ), 0 );
+ if (op->o_flags & OP_FLAG_PS) {
+ /* We need to tell disconnect_server() not to ding
+ * all the psearches if one if them disconnected
+ * But we do need to terminate all persistent searches that are using
+ * this connection
+ * op->o_flags |= OP_FLAG_PS_SEND_FAILED;
+ */
+ }
+ do_disconnect_server( conn, op->o_connid, op->o_opid );
+ ber_free( ber, 1 );
+ } else {
+ PRUint64 b;
+ LDAPDebug( LDAP_DEBUG_BER,
+ "flush_ber() wrote %lu bytes to socket %d\n",
+ bytes, conn->c_sd, 0 );
+ LL_I2L ( b, bytes ) ;
+ LL_ADD ( num_bytes_sent, num_bytes_sent, b);
+
+ if ( type == _LDAP_SEND_ENTRY ) {
+ LL_I2L ( b, 1 );
+ LL_ADD ( num_entries_sent, num_entries_sent, b );
+ }
+ if (! config_check_referral_mode())
+ (*(g_get_global_snmp_vars()->ops_tbl.dsBytesSent))+= bytes;
+ }
+ }
+
+ switch ( type ) {
+ case _LDAP_SEND_RESULT:
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_RESULT_FN );
+ break;
+ case _LDAP_SEND_REFERRAL:
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsReferralsReturned);
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_REFERRAL_FN );
+ break;
+ case _LDAP_SEND_ENTRY:
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsEntriesReturned);
+ plugin_call_plugins( pb, SLAPI_PLUGIN_POST_ENTRY_FN );
+ break;
+ }
+
+ return( rc );
+}
+
+/*
+ Puts the default result handlers into the pblock.
+ This routine is called before any server call to a
+ database backend.
+ Returns : 0 on success, -1 on failure.
+*/
+int set_db_default_result_handlers(Slapi_PBlock *pb)
+{
+ int rc = -1;
+ if (0 != pb)
+ {
+ rc = slapi_pblock_set( pb, SLAPI_PLUGIN_DB_ENTRY_FN,
+ (void *) send_ldap_search_entry );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_RESULT_FN,
+ (void *) send_ldap_result );
+ rc |= slapi_pblock_set( pb, SLAPI_PLUGIN_DB_REFERRAL_FN,
+ (void *) send_ldap_referral );
+ }
+ return rc;
+}
+
+
+struct slapi_note_map {
+ unsigned int snp_noteid;
+ char *snp_string;
+};
+
+static struct slapi_note_map notemap[] = {
+ { SLAPI_OP_NOTE_UNINDEXED, "U" },
+};
+
+#define SLAPI_NOTEMAP_COUNT ( sizeof(notemap) / sizeof(struct slapi_note_map))
+
+
+/*
+ * fill buf with a string representation of the bits present in notes.
+ *
+ * each bit is mapped to a character string (see table above).
+ * the result looks like "notes=U,Z" or similar.
+ * if no known notes are present, a zero-length string is generated.
+ * if buflen is too small, the output is truncated.
+ *
+ * Return value: buf itself.
+ */
+static char *
+notes2str( unsigned int notes, char *buf, size_t buflen )
+{
+ char *p;
+ int i;
+ size_t len;
+
+ *buf = '\0';
+ --buflen;
+ if ( buflen < 7 ) { /* must be room for "notes=X" at least */
+ return( buf );
+ }
+
+ p = buf;
+ for ( i = 0; i < SLAPI_NOTEMAP_COUNT; ++i ) {
+ if (( notemap[i].snp_noteid & notes ) != 0 ) {
+ if ( p > buf && buflen > 0 ) {
+ *p++ = ',';
+ *p = '\0';
+ --buflen;
+ } else {
+ strcpy( p, "notes=" );
+ p += 6;
+ buflen -= 6;
+ }
+ len = strlen( notemap[i].snp_string );
+ if ( buflen < len ) {
+ break; /* bail out (result is truncated) */
+ }
+ memcpy( p, notemap[i].snp_string, len );
+ buflen -= len;
+ p += len;
+ *p ='\0';
+ }
+ }
+
+ return( buf );
+}
+
+
+#define ETIME_BUFSIZ 16 /* room for 99999999.999999 */
+
+static void
+log_result( Slapi_PBlock *pb, Operation *op, int err, unsigned long tag,
+ int nentries )
+{
+ char *notes_str, notes_buf[ 256 ];
+ int internal_op;
+ CSN *operationcsn = NULL;
+ char csn_str[CSN_STRSIZE + 5];
+ char etime[ETIME_BUFSIZ];
+
+ internal_op = operation_is_flag_set( op, OP_FLAG_INTERNAL );
+
+ if ( (config_get_accesslog_level() & LDAP_DEBUG_TIMING) &&
+ (op->o_interval != (PRIntervalTime) 0) ) {
+ PRIntervalTime delta = PR_IntervalNow() - op->o_interval;
+ PR_snprintf(etime, ETIME_BUFSIZ, "%f",
+ (PRFloat64)delta/PR_TicksPerSecond());
+ } else {
+ PR_snprintf(etime, ETIME_BUFSIZ, "%d", current_time() - op->o_time);
+ }
+
+ if ( 0 == pb->pb_operation_notes ) {
+ notes_str = "";
+ } else {
+ notes_str = notes_buf;
+ *notes_buf = ' ';
+ notes2str( pb->pb_operation_notes, notes_buf + 1,
+ sizeof( notes_buf ) - 1 );
+ }
+
+ csn_str[0] = '\0';
+ if (config_get_csnlogging() == LDAP_ON)
+ {
+ operationcsn = operation_get_csn(op);
+ if (NULL != operationcsn)
+ {
+ char tmp_csn_str[CSN_STRSIZE];
+ sprintf(csn_str, " csn=%s", csn_as_string(operationcsn, PR_FALSE, tmp_csn_str));
+ }
+ }
+
+ if (op->o_tag == LDAP_REQ_BIND && err == LDAP_SASL_BIND_IN_PROGRESS) {
+ /*
+ * Not actually an error.
+ * Make that clear in the log.
+ */
+ if ( !internal_op )
+ {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d RESULT err=%d"
+ " tag=%d nentries=%d etime=%s%s%s"
+ ", SASL bind in progress\n",
+ op->o_connid,
+ op->o_opid,
+ err, tag, nentries,
+ etime,
+ notes_str, csn_str );
+ }
+ else
+ {
+ slapi_log_access( LDAP_DEBUG_ARGS,
+ "conn=%s op=%d RESULT err=%d"
+ " tag=%d nentries=%d etime=%s%s%s"
+ ", SASL bind in progress\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ err, tag, nentries,
+ etime,
+ notes_str, csn_str );
+ }
+ } else if (op->o_tag == LDAP_REQ_BIND && err == LDAP_SUCCESS) {
+ char *dn = NULL;
+
+ /*
+ * For methods other than simple, the dn in the bind request
+ * may be irrelevant. Log the actual authenticated dn.
+ */
+ slapi_pblock_get(pb, SLAPI_CONN_DN, &dn);
+ if ( !internal_op )
+ {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d RESULT err=%d"
+ " tag=%d nentries=%d etime=%s%s%s"
+ " dn=\"%s\"\n",
+ op->o_connid,
+ op->o_opid,
+ err, tag, nentries,
+ etime,
+ notes_str, csn_str, dn ? dn : "");
+ }
+ else
+ {
+ slapi_log_access( LDAP_DEBUG_ARGS,
+ "conn=%s op=%d RESULT err=%d"
+ " tag=%d nentries=%d etime=%s%s%s"
+ " dn=\"%s\"\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ err, tag, nentries,
+ etime,
+ notes_str, csn_str, dn ? dn : "");
+ }
+ slapi_ch_free((void**)&dn);
+ } else {
+ if ( !internal_op )
+ {
+ slapi_log_access( LDAP_DEBUG_STATS,
+ "conn=%d op=%d RESULT err=%d"
+ " tag=%d nentries=%d etime=%s%s%s\n",
+ op->o_connid,
+ op->o_opid,
+ err, tag, nentries,
+ etime,
+ notes_str, csn_str );
+ }
+ else
+ {
+ slapi_log_access( LDAP_DEBUG_ARGS,
+ "conn=%s op=%d RESULT err=%d"
+ " tag=%d nentries=%d etime=%s%s%s\n",
+ LOG_INTERNAL_OP_CON_ID,
+ LOG_INTERNAL_OP_OP_ID,
+ err, tag, nentries,
+ etime,
+ notes_str, csn_str );
+ }
+ }
+}
+
+
+static void
+log_entry( Operation *op, Slapi_Entry *e )
+{
+ int internal_op;
+ char ebuf[ BUFSIZ ];
+
+ internal_op = operation_is_flag_set( op, OP_FLAG_INTERNAL );
+
+ if ( !internal_op )
+ {
+ slapi_log_access( LDAP_DEBUG_STATS2, "conn=%d op=%d ENTRY dn=\"%s\"\n",
+ op->o_connid, op->o_opid,
+ escape_string( slapi_entry_get_dn_const(e), ebuf ));
+ }
+ else
+ {
+ if ( config_get_accesslog_level() & LDAP_DEBUG_STATS2 )
+ {
+ slapi_log_access( LDAP_DEBUG_ARGS, "conn=%s op=%d ENTRY dn=\"%s\"\n",
+ LOG_INTERNAL_OP_CON_ID, LOG_INTERNAL_OP_OP_ID,
+ escape_string( slapi_entry_get_dn_const(e), ebuf ));
+ }
+ }
+}
+
+
+static void
+log_referral( Operation *op )
+{
+ int internal_op;
+
+ internal_op = operation_is_flag_set( op, OP_FLAG_INTERNAL );
+
+ if ( !internal_op )
+ {
+ slapi_log_access( LDAP_DEBUG_STATS2, "conn=%d op=%d REFERRAL\n",
+ op->o_connid, op->o_opid );
+ }
+ else
+ {
+ if ( config_get_accesslog_level() & LDAP_DEBUG_STATS2 )
+ {
+ slapi_log_access( LDAP_DEBUG_ARGS, "conn=%s op=%d REFERRAL\n",
+ LOG_INTERNAL_OP_CON_ID, LOG_INTERNAL_OP_OP_ID );
+ }
+ }
+}
diff --git a/ldap/servers/slapd/rootdse.c b/ldap/servers/slapd/rootdse.c
new file mode 100644
index 00000000..f438cceb
--- /dev/null
+++ b/ldap/servers/slapd/rootdse.c
@@ -0,0 +1,331 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* rootdse.c - routines to manage the root DSE */
+
+#include <stdio.h>
+#include "slap.h"
+#include "fe.h"
+
+/* XXXmcs: why not look at the NO-USER-MODIFICATION flag instead? */
+static char *readonly_attributes[] = {
+ "namingcontexts",
+ "nsBackendSuffix",
+ "subschemasubentry",
+ "supportedldapversion",
+ "supportedcontrol",
+ "supportedextension",
+ "supportedsaslmechanisms",
+ "dataversion",
+ "ref",
+ "vendorName",
+ "vendorVersion",
+ ATTR_NETSCAPEMDSUFFIX,
+ NULL
+};
+
+
+static char *writable_attributes[] = {
+ "copiedfrom",
+ "copyingfrom",
+ "aci",
+ NULL
+};
+
+
+/*
+ * function: is_readonly_attr
+ * args: attr - candidate attribute name
+ * returns: 0 if this attribute may be written to the root DSE
+ * 1 if it may not be written.
+ * notes: should probably be integrated into syntax AVL tree, so that
+ * this list can be configured at runtime.
+ */
+static int
+rootdse_is_readonly_attr( char *attr )
+{
+ int i;
+
+ if ( NULL == attr ) {
+ return 1; /* I guess. It's not really an attribute at all */
+ }
+
+ if ( NULL == readonly_attributes ) {
+ return 0;
+ }
+
+ /*
+ * optimization: check for attributes we're likely to be writing
+ * frequently.
+ */
+ for ( i = 0; NULL != writable_attributes[ i ]; i++ ) {
+ if ( strncasecmp( attr, writable_attributes[ i ],
+ strlen( writable_attributes[ i ])) == 0 ) {
+ return 0;
+ }
+ }
+
+ for ( i = 0; NULL != readonly_attributes[ i ]; i++ ) {
+ if ( strncasecmp( attr, readonly_attributes[ i ],
+ strlen( readonly_attributes[ i ])) == 0 ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
+
+
+/*
+ * Handle a read operation on the root DSE (the entry with DN "");
+ * Note: we're copying a lot of attributes here. It might be better
+ * to keep track of which we really need to free, and arrange that
+ * the others are unlinked from the attribute list of the entry
+ * before calling slapi_entry_free().
+ */
+int
+read_root_dse( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg )
+{
+ int i;
+ struct berval *vals[2];
+ struct berval val;
+ struct berval **bvals;
+ Slapi_Backend *be;
+ char *cookie = NULL;
+ char **strs;
+ void *node;
+ Slapi_DN *sdn;
+
+ /*
+ * Check that we were doing a base search on the root dse.
+ */
+ {
+ int scope;
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope );
+ if(scope!=LDAP_SCOPE_BASE)
+ {
+ *returncode= LDAP_NO_SUCH_OBJECT;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ /* loop through backend suffixes to get namingcontexts attr */
+ attrlist_delete( &e->e_attrs, "namingcontexts");
+
+ sdn = slapi_get_first_suffix(&node, 0);
+ while (sdn)
+ {
+ val.bv_val = (char*)slapi_sdn_get_dn(sdn); /* jcm: had to cast away const */
+ val.bv_len = strlen( val.bv_val );
+ attrlist_merge( &e->e_attrs, "namingcontexts", vals );
+ sdn = slapi_get_next_suffix(&node, 0);
+ }
+
+ attrlist_delete( &e->e_attrs, "nsBackendSuffix");
+ for (be = slapi_get_first_backend(&cookie); be != NULL;
+ be = slapi_get_next_backend(cookie)) {
+
+ char * base;
+ char * be_name;
+ const Slapi_DN *be_suffix;
+
+ if (slapi_be_private(be)) continue;
+
+ /* tolerate a backend under construction containing no suffix */
+ if ((be_suffix = slapi_be_getsuffix(be, 0)) == NULL) continue;
+
+ if ((base = (char *)slapi_sdn_get_dn(be_suffix)) == NULL) continue;
+ if ((be_name = slapi_be_get_name(be)) == NULL) continue;
+
+ val.bv_len = strlen(base)+strlen(be_name)+1;
+ val.bv_val = slapi_ch_malloc(val.bv_len+1);
+ sprintf(val.bv_val, "%s:%s", be_name, base);
+ attrlist_merge(&e->e_attrs, "nsBackendSuffix", vals);
+ slapi_ch_free((void **) &val.bv_val);
+ }
+ slapi_ch_free((void **)&cookie);
+
+ /* schema entry */
+ val.bv_val = SLAPD_SCHEMA_DN;
+ val.bv_len = sizeof( SLAPD_SCHEMA_DN ) - 1;
+ attrlist_replace( &e->e_attrs, "subschemasubentry", vals );
+
+ /* supported extended operations */
+ attrlist_delete( &e->e_attrs, "supportedExtension");
+ if (( strs = slapi_get_supported_extended_ops_copy()) != NULL ) {
+ for ( i = 0; strs[i] != NULL; ++i ) {
+ val.bv_val = strs[i];
+ val.bv_len = strlen( strs[i] );
+ attrlist_merge( &e->e_attrs, "supportedExtension", vals );
+ }
+ charray_free(strs);
+ }
+
+ /* supported controls */
+ attrlist_delete( &e->e_attrs, "supportedControl");
+ if ( slapi_get_supported_controls_copy( &strs, NULL ) == 0
+ && strs != NULL ) {
+ for ( i = 0; strs[i] != NULL; ++i ) {
+ val.bv_val = strs[i];
+ val.bv_len = strlen( strs[i] );
+ attrlist_merge( &e->e_attrs, "supportedControl", vals );
+ }
+ charray_free(strs);
+ }
+
+ /* supported sasl mechanisms */
+ attrlist_delete( &e->e_attrs, "supportedSASLMechanisms");
+ if (( strs = ids_sasl_listmech (pb)) != NULL ) {
+ for ( i = 0; strs[i] != NULL; ++i ) {
+ val.bv_val = strs[i];
+ val.bv_len = strlen( strs[i] );
+ attrlist_merge( &e->e_attrs, "supportedSASLMechanisms", vals );
+ }
+ charray_free(strs);
+ }
+
+
+ /* supported LDAP versions */
+ val.bv_val = "2";
+ val.bv_len = 1;
+ attrlist_replace( &e->e_attrs, "supportedldapversion", vals );
+ val.bv_val = "3";
+ val.bv_len = 1;
+ attrlist_merge( &e->e_attrs, "supportedldapversion", vals );
+
+ /* superior references (ref attribute) */
+ attrlist_delete( &e->e_attrs, "ref");
+ if (( bvals = g_get_default_referral()) != NULL ) {
+ for ( i = 0; bvals[i] != NULL; ++i ) {
+ val.bv_val = bvals[i]->bv_val;
+ val.bv_len = bvals[i]->bv_len;
+ attrlist_merge( &e->e_attrs, "ref", vals );
+ }
+ }
+
+ /* RFC 3045 attributes: vendorName and vendorVersion */
+ val.bv_val = SLAPD_VENDOR_NAME;
+ val.bv_len = strlen( val.bv_val );
+ attrlist_replace( &e->e_attrs, "vendorName", vals );
+ val.bv_val = slapd_get_version_value();
+ val.bv_len = strlen( val.bv_val );
+ attrlist_replace( &e->e_attrs, "vendorVersion", vals );
+ slapi_ch_free( (void **)&val.bv_val );
+
+ /* Server Data Version */
+ if (( val.bv_val = (char*)get_server_dataversion()) != NULL ) { /* jcm cast away const */
+ val.bv_len = strlen( val.bv_val );
+ attrlist_replace( &e->e_attrs, attr_dataversion, vals );
+ }
+
+ /* machine data suffix
+ * this has been added in 4.0 for replication purpose
+ * and since 5.0 is now unused by the core server,
+ * however some functionalities of the console framework 5.01
+ * still depend on this
+ */
+ if (( val.bv_val = get_config_DN()) != NULL ) {
+ val.bv_len = strlen( val.bv_val );
+ attrlist_replace( &e->e_attrs, ATTR_NETSCAPEMDSUFFIX, vals );
+ }
+
+#ifdef notdef
+ /* XXXggood testing - print the size of the changelog db */
+ {
+ unsigned int clsize;
+ clsize = get_changelog_size();
+ sprintf( buf, "%u", clsize );
+ val.bv_val = buf;
+ val.bv_len = strlen( buf );
+ attrlist_replace( &e->e_attrs, "changelogsize", vals );
+ slapi_ch_free((void**)&val.bv_val );
+ }
+#endif /* notdef */
+
+ /* vlvsearch is list of dns to VLV Search Specifications */
+ attrlist_delete( &e->e_attrs, "vlvsearch");
+ cookie = NULL;
+ be = slapi_get_first_backend(&cookie);
+ while (be)
+ {
+ if(!be->be_private)
+ {
+ /* Generate searches to find the VLV Search Specifications */
+ int r;
+ Slapi_PBlock *resultpb= NULL;
+ Slapi_Entry** entry = NULL;
+ Slapi_DN dn;
+ slapi_sdn_init(&dn);
+ be_getconfigdn(be,&dn);
+ resultpb= slapi_search_internal( slapi_sdn_get_ndn(&dn), LDAP_SCOPE_ONELEVEL, "objectclass=vlvsearch", NULL, NULL, 1);
+ slapi_sdn_done(&dn);
+ slapi_pblock_get( resultpb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entry );
+ slapi_pblock_get( resultpb, SLAPI_PLUGIN_INTOP_RESULT, &r );
+ if(r==LDAP_SUCCESS)
+ {
+ for (; *entry; ++entry)
+ {
+ val.bv_val = slapi_entry_get_dn(*entry);
+ val.bv_len = strlen( val.bv_val );
+ attrlist_merge( &e->e_attrs, "vlvsearch", vals );
+ }
+ }
+ slapi_free_search_results_internal(resultpb);
+ slapi_pblock_destroy(resultpb);
+ }
+
+ be = slapi_get_next_backend (cookie);
+ }
+ slapi_ch_free ((void **)&cookie);
+ *returncode= LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+
+
+/*
+ * Handle a modification request on the root DSE. Only certain
+ * attributes are writable. If an attempt to modify an attribute
+ * which is not allowed, return LDAP_UNWILLING_TO_PERFORM, unless
+ * the modification is disallowed because of ACL checking, in which
+ * case LDAP_INSUFFICIENT_ACCESS is returned.
+ */
+int
+modify_root_dse( Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *e, int *returncode, char *returntext, void *arg )
+{
+ LDAPMod **mods;
+
+ /*
+ * Make a pass through the attributes and check them
+ * to make sure none are computed. Also check for
+ * reflected attributes and reject those as well.
+ * Eventually, some reflected attributes might be
+ * writable, but for now, none are.
+ */
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ if ( NULL != mods )
+ {
+ int i;
+ for ( i = 0; NULL != mods[ i ]; i++ )
+ {
+ if ( rootdse_is_readonly_attr( mods[ i ]->mod_type ))
+ {
+ /* The modification is disallowed */
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ strcpy(returntext,"Modification of these root DSE attributes not allowed");
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+ }
+
+ *returncode= LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK; /* success -- apply the changes */
+}
diff --git a/ldap/servers/slapd/rwlock.c b/ldap/servers/slapd/rwlock.c
new file mode 100644
index 00000000..8642a9ea
--- /dev/null
+++ b/ldap/servers/slapd/rwlock.c
@@ -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 **/
+/*
+ * rwlock.c - generic multiple reader, single-writer locking routines.
+ *
+ * The general idea is:
+ *
+ * If you have a data structure which you'd like to allow multiple threads
+ * to read, but only one thread at a time to write, you include in your
+ * data structure a pointer to an rwl structure, and call rwl_new() to
+ * obtain an allocated and initialized rwl structure.
+ *
+ * Then, call the appropriate functions via the provided function pointers
+ * to acquire/relinquish read or write locks on your data structure. You
+ * may want to provide some convenience macros to make the code prettier.
+ *
+ * The semantics are:
+ * - a thread attempting to obtain a read lock will succeed immediately as
+ * long as there are no threads with write locks.
+ * - a thread attempting to obtain a write lock will wait until all readers
+ * have relinquished their read locks.
+ * - a thread attempting to obtain a write lock blocks other threads from
+ * obtaining read locks. As long as all readers release their locks,
+ * the write will eventually get the lock.
+ */
+
+#include "slap.h"
+
+#include <prlock.h>
+#include <prcvar.h>
+#include "rwlock.h"
+
+/*
+ * Function: __rwl_acquire_read_lock
+ *
+ * Description: acquire a read lock.
+ *
+ * Arguments: rp: pointer to an rwl stucture
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+static int
+__rwl_acquire_read_lock( rwl *rp )
+{
+ if ( rp == NULL ) {
+ return -1;
+ }
+ PR_Lock( rp->rwl_writers_mutex );
+ PR_Lock( rp->rwl_readers_mutex );
+ rp->rwl_num_readers++;
+ (void)PR_Unlock( rp->rwl_readers_mutex );
+ (void)PR_Unlock( rp->rwl_writers_mutex );
+ return 0;
+}
+
+
+
+
+/*
+ * Function: __rwl_acquire_write_lock
+ *
+ * Description: acquire a write lock.
+ *
+ * Arguments: rp: pointer to an rwl stucture
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+static int
+__rwl_acquire_write_lock( rwl *rp )
+{
+ if ( rp == NULL ) {
+ return -1;
+ }
+ PR_Lock( rp->rwl_writers_mutex );
+ PR_Lock( rp->rwl_readers_mutex );
+ rp->rwl_writer_waiting = 1;
+ while ( rp->rwl_num_readers > 0 ) {
+ if ( PR_WaitCondVar( rp->rwl_writer_waiting_cv, PR_INTERVAL_NO_TIMEOUT ) != 0 ) {
+ (void)PR_Unlock( rp->rwl_writers_mutex );
+ (void)PR_Unlock( rp->rwl_readers_mutex );
+ return -1;
+ }
+ }
+ /* XXXggood should rwl_writer_waiting be set zero here? */
+ return 0;
+}
+
+
+
+
+/*
+ * Function: __rwl_relinquish_read_lock
+ *
+ * Description: relinquish a read lock.
+ *
+ * Arguments: rp: pointer to an rwl stucture
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+static int
+__rwl_relinquish_read_lock( rwl *rp )
+{
+ if ( rp == NULL ) {
+ return -1;
+ }
+ PR_Lock( rp->rwl_readers_mutex );
+ if ( --rp->rwl_num_readers == 0 && rp->rwl_writer_waiting ) {
+ PR_NotifyCondVar( rp->rwl_writer_waiting_cv );
+ }
+ (void)PR_Unlock( rp->rwl_readers_mutex );
+ return 0;
+}
+
+
+
+
+/*
+ * Function: __rwl_relinquish_write_lock
+ *
+ * Description: relinquish a write lock.
+ *
+ * Arguments: rp: pointer to an rwl stucture
+ *
+ * Returns: 0 on success, -1 on failure.
+ */
+static int
+__rwl_relinquish_write_lock( rwl *rp )
+{
+ if ( rp == NULL ) {
+ return -1;
+ }
+ rp->rwl_writer_waiting = 0;
+ (void)PR_Unlock( rp->rwl_readers_mutex );
+ (void)PR_Unlock( rp->rwl_writers_mutex );
+ return 0;
+}
+
+
+
+/*
+ * Function: rwl_new
+ *
+ * Description: allocate and initialize a wrl structure.
+ *
+ * Arguments: none
+ *
+ * Returns: on success, returns a pointer to an allocated, initialized rwl structure.
+ * on failure, returns NULL.
+ *
+ */
+rwl *
+rwl_new()
+{
+ rwl *rp;
+
+ if (( rp = (rwl *)malloc( sizeof( rwl ))) == NULL ) {
+ return NULL;
+ }
+
+ if (( rp->rwl_readers_mutex = PR_NewLock()) == NULL ) {
+ free( rp );
+ return NULL;
+ }
+ if (( rp->rwl_writers_mutex = PR_NewLock()) == NULL ) {
+ PR_DestroyLock( rp->rwl_readers_mutex );
+ free( rp );
+ return NULL;
+ }
+ if (( rp->rwl_writer_waiting_cv = PR_NewCondVar( rp->rwl_readers_mutex )) == NULL ) {
+ PR_DestroyLock( rp->rwl_readers_mutex );
+ PR_DestroyLock( rp->rwl_writers_mutex );
+ free( rp );
+ }
+ rp->rwl_num_readers = rp->rwl_writer_waiting = 0;
+
+ rp->rwl_acquire_read_lock = __rwl_acquire_read_lock;
+ rp->rwl_relinquish_read_lock = __rwl_relinquish_read_lock;
+
+ rp->rwl_acquire_write_lock = __rwl_acquire_write_lock;
+ rp->rwl_relinquish_write_lock = __rwl_relinquish_write_lock;
+
+ return rp;
+}
+
+
+
+
+/*
+ * Function: rwl_free
+ *
+ * Description: deallocates and frees an rwl structure.
+ *
+ * Arguments: rh: handle to an rwl structure.
+ *
+ * Returns: nothing
+ */
+void
+rwl_free( rwl **rh )
+{
+ rwl *rp;
+
+ if ( rh == NULL || *rh == NULL ) {
+ return;
+ }
+ rp = *rh;
+
+ if ( rp->rwl_readers_mutex != NULL ) {
+ PR_DestroyLock( rp->rwl_readers_mutex );
+ }
+ if ( rp->rwl_writers_mutex != NULL ) {
+ PR_DestroyLock( rp->rwl_writers_mutex );
+ }
+ if ( rp->rwl_writer_waiting_cv != NULL ) {
+ PR_DestroyCondVar( rp->rwl_writer_waiting_cv );
+ }
+ memset( rp, '\0', sizeof( rwl ));
+ free( rp );
+ *rh = NULL;
+}
diff --git a/ldap/servers/slapd/rwlock.h b/ldap/servers/slapd/rwlock.h
new file mode 100644
index 00000000..112f1de6
--- /dev/null
+++ b/ldap/servers/slapd/rwlock.h
@@ -0,0 +1,28 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _RWLOCK_H_
+#define _RWLOCK_H_
+
+#include <prlock.h>
+#include <prcvar.h>
+
+typedef struct _rwl {
+ PRLock *rwl_readers_mutex;
+ PRLock *rwl_writers_mutex;
+ PRCondVar *rwl_writer_waiting_cv;
+ int rwl_num_readers;
+ int rwl_writer_waiting;
+
+ int (*rwl_acquire_read_lock)( struct _rwl * );
+ int (*rwl_relinquish_read_lock)( struct _rwl * );
+
+ int (*rwl_acquire_write_lock)( struct _rwl * );
+ int (*rwl_relinquish_write_lock)( struct _rwl * );
+} rwl;
+
+extern rwl *rwl_new();
+extern void rwl_free( rwl **rh );
+#endif /* _RWLOCK_H_ */
diff --git a/ldap/servers/slapd/sasl_io.c b/ldap/servers/slapd/sasl_io.c
new file mode 100644
index 00000000..7345be35
--- /dev/null
+++ b/ldap/servers/slapd/sasl_io.c
@@ -0,0 +1,334 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slap.h"
+#include "slapi-plugin.h"
+#include "fe.h"
+#include <sasl.h>
+
+/*
+ * I/O Shim Layer for SASL Encryption
+ * The 'handle' is a pointer to a sasl_connection structure.
+ */
+
+#define SASL_IO_BUFFER_SIZE 1024
+
+/*
+ * SASL sends its encrypted PDU's with an embedded 4-byte length
+ * at the beginning (in network byte order). We peek inside the
+ * received data off the wire to find this length, and use it
+ * to determine when we have read an entire SASL PDU.
+ * So when we have that there is no need for the SASL layer
+ * to do any fancy buffering with it, we always hand it
+ * a full packet.
+ */
+
+struct _sasl_io_private {
+ struct lextiof_socket_private *real_handle;
+ struct lber_x_ext_io_fns *real_iofns;
+ char *decrypted_buffer;
+ size_t decrypted_buffer_size;
+ size_t decrypted_buffer_count;
+ size_t decrypted_buffer_offset;
+ char *encrypted_buffer;
+ size_t encrypted_buffer_size;
+ size_t encrypted_buffer_count;
+ size_t encrypted_buffer_offset;
+ Connection *conn;
+};
+
+int
+sasl_io_enable(Connection *c)
+{
+ int ret = 0;
+
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "sasl_io_enable for connection %d\n", c->c_connid, 0, 0 );
+ /* Flag that we should enable SASL I/O for the next read operation on this connection */
+ c->c_enable_sasl_io = 1;
+
+ return ret;
+}
+
+static void
+sasl_io_init_buffers(sasl_io_private *sp)
+{
+ sp->decrypted_buffer = slapi_ch_malloc(SASL_IO_BUFFER_SIZE);
+ sp->decrypted_buffer_size = SASL_IO_BUFFER_SIZE;
+ sp->encrypted_buffer = slapi_ch_malloc(SASL_IO_BUFFER_SIZE);
+ sp->encrypted_buffer_size = SASL_IO_BUFFER_SIZE;
+}
+
+/* This function should be called under the connection mutex */
+int
+sasl_io_setup(Connection *c)
+{
+ int ret = 0;
+ struct lber_x_ext_io_fns *func_pointers = NULL;
+ sasl_io_private *sp = (sasl_io_private*) slapi_ch_calloc(1, sizeof(sasl_io_private));
+
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "sasl_io_setup for connection %d\n", c->c_connid, 0, 0 );
+ /* Get the current functions and store them for later */
+ ber_sockbuf_get_option( c->c_sb, LBER_SOCKBUF_OPT_EXT_IO_FNS, &func_pointers);
+ sp->real_iofns = func_pointers;
+ func_pointers = NULL;
+
+ /* Set up the private structure */
+ sp->real_handle = (struct lextiof_socket_private*) c->c_prfd;
+ sp->conn = c;
+ /* Store the private structure in the connection */
+ c->c_sasl_io_private = sp;
+ /* Insert the sasl i/o functions into the ber layer */
+ func_pointers = (struct lber_x_ext_io_fns *) slapi_ch_malloc(LBER_X_EXTIO_FNS_SIZE);
+ func_pointers->lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ func_pointers->lbextiofn_read = sasl_read_function;
+ func_pointers->lbextiofn_write = sasl_write_function;
+ func_pointers->lbextiofn_writev = NULL;
+ func_pointers->lbextiofn_socket_arg = (struct lextiof_socket_private *) sp;
+ ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_EXT_IO_FNS, func_pointers);
+ /* Setup the data buffers for the fast read path */
+ sasl_io_init_buffers(sp);
+ /* Reset the enable flag, so we don't process it again */
+ c->c_enable_sasl_io = 0;
+ /* Mark the connection as having SASL I/O */
+ c->c_sasl_io = 1;
+ return ret;
+}
+
+int
+sasl_io_cleanup(Connection *c)
+{
+ int ret = 0;
+ sasl_io_private *sp = c->c_sasl_io_private;
+ if (sp) {
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "sasl_io_cleanup for connection %d\n", c->c_connid, 0, 0 );
+ /* Free the buffers */
+ slapi_ch_free((void**)&(sp->encrypted_buffer));
+ slapi_ch_free((void**)&(sp->decrypted_buffer));
+ /* Put the I/O functions back how they were */
+ ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_EXT_IO_FNS, sp->real_iofns);
+ slapi_ch_free((void**)&sp);
+ c->c_sasl_io_private = NULL;
+ c->c_enable_sasl_io = 0;
+ c->c_sasl_io = 0;
+ }
+ return ret;
+}
+
+
+static void sasl_io_resize_encrypted_buffer(sasl_io_private *sp, size_t requested_size)
+{
+ if (requested_size > sp->encrypted_buffer_size) {
+ sp->encrypted_buffer = slapi_ch_realloc(sp->encrypted_buffer, requested_size);
+ sp->encrypted_buffer_size = requested_size;
+ }
+}
+
+static void sasl_io_resize_decrypted_buffer(sasl_io_private *sp, size_t requested_size)
+{
+ if (requested_size > sp->decrypted_buffer_size) {
+ sp->decrypted_buffer = slapi_ch_realloc(sp->decrypted_buffer, requested_size);
+ sp->decrypted_buffer_size = requested_size;
+ }
+}
+
+static int
+sasl_io_reading_packet(sasl_io_private *sp)
+{
+ return (sp->encrypted_buffer_count > 0);
+}
+
+static int
+sasl_io_finished_packet(sasl_io_private *sp)
+{
+ return (sp->encrypted_buffer_count && (sp->encrypted_buffer_offset == sp->encrypted_buffer_count) );
+}
+
+static int
+sasl_io_start_packet(Connection *c, PRInt32 *err)
+{
+ int ret = 0;
+ unsigned char buffer[4];
+ size_t packet_length = 0;
+
+ ret = PR_Recv(c->c_prfd,buffer,sizeof(buffer),0,PR_INTERVAL_NO_WAIT);
+ if (ret < 0) {
+ *err = PR_GetError();
+ return -1;
+ }
+ if (ret != 0 && ret < sizeof(buffer)) {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "failed to read sasl packet length on connection %d\n", c->c_connid, 0, 0 );
+ return -1;
+
+ }
+ if (ret == sizeof(buffer)) {
+ /* Decode the length (could use ntohl here ??) */
+ packet_length = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "read sasl packet length %ld on connection %d\n", packet_length, c->c_connid, 0 );
+ sasl_io_resize_encrypted_buffer(c->c_sasl_io_private, packet_length);
+ c->c_sasl_io_private->encrypted_buffer_count = packet_length;
+ c->c_sasl_io_private->encrypted_buffer_offset = 0;
+ }
+ return 0;
+}
+static int
+sasl_io_read_packet(Connection *c, PRInt32 *err)
+{
+ size_t ret = 0;
+ sasl_io_private *sp = c->c_sasl_io_private;
+ size_t bytes_remaining_to_read = sp->encrypted_buffer_count - sp->encrypted_buffer_offset;
+
+ ret = PR_Recv(c->c_prfd,sp->encrypted_buffer + sp->encrypted_buffer_offset,bytes_remaining_to_read,0,PR_INTERVAL_NO_WAIT);
+ if (ret < 0) {
+ *err = PR_GetError();
+ return -1;
+ }
+ if (ret > 0) {
+ sp->encrypted_buffer_offset += ret;
+ }
+ return ret;
+}
+
+/* Special recv function for the server connection code */
+/* Here, we return bytes to the caller, either the bytes
+ remaining in the decrypted data buffer, from 'before',
+ or the number of bytes we get decrypted from sasl,
+ or the requested number of bytes whichever is lower.
+ */
+int
+sasl_recv_connection(Connection *c, char *buffer, size_t count,PRInt32 *err)
+{
+ int ret = 0;
+ size_t bytes_in_buffer = 0;
+ sasl_io_private *sp = c->c_sasl_io_private;
+
+ *err = 0;
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "sasl_recv_connection for connection %d\n", c->c_connid, 0, 0 );
+ /* Do we have decrypted data buffered from 'before' ? */
+ bytes_in_buffer = sp->decrypted_buffer_count - sp->decrypted_buffer_offset;
+ if (0 == bytes_in_buffer) {
+ /* If there wasn't buffered decrypted data, we need to get some... */
+ if (!sasl_io_reading_packet(sp)) {
+ /* First read the packet length and so on */
+ ret = sasl_io_start_packet(c, err);
+ if (0 != ret) {
+ /* Most likely the i/o timed out */
+ return ret;
+ }
+ }
+ /* We now have the packet length
+ * we now must read more data off the wire until we have the complete packet
+ */
+ ret = sasl_io_read_packet(c,err);
+ if (0 == ret || -1 == ret) {
+ return ret;
+ }
+ /* Are we there yet ? */
+ if (sasl_io_finished_packet(sp)) {
+ const char *output_buffer = NULL;
+ unsigned int output_length = 0;
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "sasl_recv_connection finished reading packet for connection %d\n", c->c_connid, 0, 0 );
+ /* Now decode it */
+ ret = sasl_decode(c->c_sasl_conn,sp->encrypted_buffer,sp->encrypted_buffer_count,&output_buffer,&output_length);
+ if (SASL_OK == ret) {
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "sasl_recv_connection decoded packet length %d for connection %d\n", output_length, c->c_connid, 0 );
+ if (output_length) {
+ sasl_io_resize_decrypted_buffer(sp,output_length);
+ memcpy(sp->decrypted_buffer,output_buffer,output_length);
+ sp->decrypted_buffer_count = output_length;
+ sp->decrypted_buffer_offset = 0;
+ sp->encrypted_buffer_offset = 0;
+ sp->encrypted_buffer_count = 0;
+ }
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "sasl_recv_connection failed to decode packet for connection %d\n", c->c_connid, 0, 0 );
+ }
+ }
+ }
+ /* Finally, return data from the buffer to the caller */
+ {
+ size_t bytes_to_return = sp->decrypted_buffer_count - sp->decrypted_buffer_offset;
+ if (bytes_to_return > count) {
+ bytes_to_return = count;
+ }
+ memcpy(buffer, sp->decrypted_buffer, bytes_to_return);
+ if (bytes_in_buffer == bytes_to_return) {
+ sp->decrypted_buffer_offset = 0;
+ sp->decrypted_buffer_count = 0;
+ } else {
+ sp->decrypted_buffer_offset += bytes_to_return;
+ }
+ ret = bytes_to_return;
+ }
+ return ret;
+}
+
+int
+sasl_read_function(int ignore, void *buffer, int count, struct lextiof_socket_private *handle )
+{
+ int ret = 0;
+ sasl_io_private *sp = (sasl_io_private*) handle;
+
+ /* First we look to see if we have buffered data that we can return to the caller */
+ if ( (NULL == sp->decrypted_buffer) || ((sp->decrypted_buffer_count - sp->decrypted_buffer_offset) <= 0) ) {
+ /* If we didn't have buffered data, we need to perform I/O and decrypt */
+ PRUint32 buffer_length = 0;
+ /* Read the packet length */
+ ret = read_function(0, &buffer_length, sizeof(buffer_length), sp->real_handle);
+ if (ret) {
+ }
+ /* Read the payload */
+ ret = read_function(0, sp->encrypted_buffer, buffer_length, sp->real_handle);
+ if (ret) {
+ }
+ /* Now we can call sasl to decrypt */
+ /* ret = sasl_decode(sp->conn->c_sasl_conn,sp->encrypted_buffer, buffer_length, sp->decrypted_buffer, &sp->decrypted_buffer_count ); */
+ }
+ /* If things went well, copy the payload for the caller */
+ if ( 0 == ret ) {
+/* size_t real_count = 0;
+
+ if (count >= (sp->buffer_count - sp->buffer_offset) ) {
+ real_count = count;
+ } else {
+ real_count = (sp->buffer_count - sp->buffer_offset);
+ }
+ memcpy(buffer, sp->buffer, real_count);
+ sp->buffer_offset += real_count; */
+ }
+
+ return ret;
+}
+
+int
+sasl_write_function(int ignore, const void *buffer, int count, struct lextiof_socket_private *handle)
+{
+ int ret = 0;
+ sasl_io_private *sp = (sasl_io_private*) handle;
+ const char *crypt_buffer = NULL;
+ unsigned crypt_buffer_size = 0;
+
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "sasl_write_function writing %d bytes\n", count, 0, 0 );
+ /* Get SASL to encrypt the buffer */
+ ret = sasl_encode(sp->conn->c_sasl_conn, buffer, count, &crypt_buffer, &crypt_buffer_size);
+ LDAPDebug( LDAP_DEBUG_CONNS,
+ "sasl_write_function encoded as %d bytes\n", crypt_buffer_size, 0, 0 );
+
+ ret = write_function(0, crypt_buffer, crypt_buffer_size, sp->real_handle);
+ if (ret) {
+ }
+
+ return ret;
+}
+
diff --git a/ldap/servers/slapd/sasl_map.c b/ldap/servers/slapd/sasl_map.c
new file mode 100644
index 00000000..b9f9fbcf
--- /dev/null
+++ b/ldap/servers/slapd/sasl_map.c
@@ -0,0 +1,472 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "slap.h"
+#include "slapi-plugin.h"
+#include "fe.h"
+#if defined( MACOS ) || defined( DOS ) || defined( _WIN32 ) || defined( NEED_BSDREGEX )
+#include "regex.h"
+#endif
+
+/*
+ * Map SASL identities to LDAP searches
+ */
+
+/*
+ * We maintain a list of mappings to consult
+ */
+
+typedef struct sasl_map_data_ sasl_map_data;
+struct sasl_map_data_ {
+ char *name;
+ char *regular_expression;
+ char *template_base_dn;
+ char *template_search_filter;
+ sasl_map_data *next; /* For linked list */
+};
+
+typedef struct _sasl_map_private {
+ PRLock *lock;
+ sasl_map_data *map_data_list;
+} sasl_map_private;
+
+static char * configDN = "cn=mapping,cn=sasl,cn=config";
+
+/*
+ * DBDB: this is ugly, but right now there is _no_ server-wide
+ * dynamic structure (like a Slapi_Server * type thing). All the code
+ * that needs such a thing instead maintains a static or global variable.
+ * Until we implement the 'right thing', we'll just follow suit here :(
+ */
+
+static sasl_map_private *sasl_map_static_priv = NULL;
+
+static
+sasl_map_private *sasl_map_get_global_priv()
+{
+ /* ASSERT(sasl_map_static_priv) */
+ return sasl_map_static_priv;
+}
+
+static
+sasl_map_private *sasl_map_new_private()
+{
+ PRLock *new_lock = PR_NewLock();
+ sasl_map_private *new_priv = NULL;
+ if (NULL == new_lock) {
+ return NULL;
+ }
+ new_priv = (sasl_map_private *)slapi_ch_calloc(1,sizeof(sasl_map_private));
+ new_priv->lock = new_lock;
+ if (NULL == new_lock) {
+ slapi_ch_free((void**)new_priv);
+ return NULL;
+ }
+ return new_priv;
+}
+
+static void
+sasl_map_free_private(sasl_map_private **priv)
+{
+ PR_DestroyLock((*priv)->lock);
+ slapi_ch_free((void**)priv);
+ *priv = NULL;
+}
+
+/* This function does a shallow copy on the payload data supplied, so the caller should not free it, and it needs to be allocated using slapi_ch_malloc() */
+static
+sasl_map_data *sasl_map_new_data(char *name, char *regex, char *dntemplate, char *filtertemplate)
+{
+ sasl_map_data *new_dp = (sasl_map_data *) slapi_ch_calloc(1,sizeof(sasl_map_data));
+ new_dp->name = name;
+ new_dp->regular_expression = regex;
+ new_dp->template_base_dn = dntemplate;
+ new_dp->template_search_filter = filtertemplate;
+ return new_dp;
+}
+
+static
+sasl_map_data *sasl_map_next(sasl_map_data *dp)
+{
+ return dp->next;
+}
+
+static void
+sasl_map_free_data(sasl_map_data **dp)
+{
+ slapi_ch_free((void**)dp);
+}
+
+static int
+sasl_map_remove_list_entry(sasl_map_private *priv, char *removeme)
+{
+ int ret = 0;
+ int foundit = 0;
+ sasl_map_data *current = NULL;
+ sasl_map_data *previous = NULL;
+ PR_Lock(priv->lock);
+ current = priv->map_data_list;
+ while (current) {
+ if (0 == strcmp(current->name,removeme)) {
+ foundit = 1;
+ if (previous) {
+ /* Unlink it */
+ previous->next = current->next;
+ } else {
+ /* That was the only entry, and now there are none */
+ priv->map_data_list = NULL;
+ }
+ /* Payload free */
+ sasl_map_free_data(&current);
+ /* And no need to look further */
+ break;
+ }
+ previous = current;
+ current = current->next;
+ }
+ if (!foundit) {
+ ret = -1;
+ }
+ PR_Unlock(priv->lock);
+ return ret;
+}
+
+static int
+sasl_map_insert_list_entry(sasl_map_private *priv, sasl_map_data *dp)
+{
+ int ret = 0;
+ int ishere = 0;
+ sasl_map_data *current = NULL;
+ PR_Lock(priv->lock);
+ /* Check to see if it's here already */
+ current = priv->map_data_list;
+ while (current && current->next) {
+ current = current->next;
+ }
+ if (ishere) {
+ return -1;
+ }
+ /* current now points to the end of the list or NULL */
+ if (NULL == priv->map_data_list) {
+ priv->map_data_list = dp;
+ } else {
+ current->next = dp;
+ }
+ PR_Unlock(priv->lock);
+ return ret;
+}
+
+/*
+ * Functions to handle config operations
+ */
+
+/**
+ * Get a list of child DNs
+ * DBDB these functions should be folded into libslapd because it's a copy of a function in ssl.c
+ */
+static char **
+getChildren( char *dn ) {
+ Slapi_PBlock *new_pb = NULL;
+ Slapi_Entry **e;
+ int search_result = 1;
+ int nEntries = 0;
+ char **list = NULL;
+
+ new_pb = slapi_search_internal ( dn, LDAP_SCOPE_ONELEVEL,
+ "(objectclass=nsSaslMapping)",
+ NULL, NULL, 0);
+
+ slapi_pblock_get( new_pb, SLAPI_NENTRIES, &nEntries);
+ if ( nEntries > 0 ) {
+ slapi_pblock_get( new_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
+ slapi_pblock_get( new_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &e);
+ if ( e != NULL ) {
+ int i;
+ list = (char **)slapi_ch_malloc( sizeof(*list) * (nEntries + 1));
+ for ( i = 0; e[i] != NULL; i++ ) {
+ list[i] = slapi_ch_strdup(slapi_entry_get_dn(e[i]));
+ }
+ list[nEntries] = NULL;
+ }
+ }
+ slapi_free_search_results_internal(new_pb);
+ slapi_pblock_destroy(new_pb );
+ return list;
+}
+
+/**
+ * Free a list of child DNs
+ */
+static void
+freeChildren( char **list ) {
+ if ( list != NULL ) {
+ int i;
+ for ( i = 0; list[i] != NULL; i++ ) {
+ slapi_ch_free( (void **)(&list[i]) );
+ }
+ slapi_ch_free( (void **)(&list) );
+ }
+}
+
+
+/**
+ * Get a particular entry
+ */
+static Slapi_Entry *
+getConfigEntry( const char *dn, Slapi_Entry **e2 ) {
+ Slapi_DN sdn;
+
+ slapi_sdn_init_dn_byref( &sdn, dn );
+ slapi_search_internal_get_entry( &sdn, NULL, e2,
+ plugin_get_default_component_id());
+ slapi_sdn_done( &sdn );
+ return *e2;
+}
+
+/**
+ * Free an entry
+ */
+static void
+freeConfigEntry( Slapi_Entry ** e ) {
+ if ( (e != NULL) && (*e != NULL) ) {
+ slapi_entry_free( *e );
+ *e = NULL;
+ }
+}
+
+static int
+sasl_map_config_parse_entry(Slapi_Entry *entry, sasl_map_data **new_dp)
+{
+ int ret = 0;
+ char *regex = NULL;
+ char *basedntemplate = NULL;
+ char *filtertemplate = NULL;
+ char *map_name = NULL;
+
+ *new_dp = NULL;
+ regex = slapi_entry_attr_get_charptr( entry, "nsSaslMapRegexString" );
+ basedntemplate = slapi_entry_attr_get_charptr( entry, "nsSaslMapBaseDNTemplate" );
+ filtertemplate = slapi_entry_attr_get_charptr( entry, "nsSaslMapFilterTemplate" );
+ map_name = slapi_entry_attr_get_charptr( entry, "cn" );
+
+ if ( (NULL == regex) || (NULL == basedntemplate) || (NULL == filtertemplate) ) {
+ /* Invalid entry */
+ ret = -1;
+ } else {
+ /* Make the new dp */
+ *new_dp = sasl_map_new_data(map_name, regex, basedntemplate, filtertemplate);
+ }
+
+ if (ret) {
+ slapi_ch_free((void **) &regex);
+ slapi_ch_free((void **) &basedntemplate);
+ slapi_ch_free((void **) &filtertemplate);
+ }
+ return ret;
+}
+
+static int
+sasl_map_read_config_startup(sasl_map_private *priv)
+{
+ char **map_entry_list = NULL;
+ int ret = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "-> sasl_map_read_config_startup\n", 0, 0, 0 );
+ if((map_entry_list = getChildren(configDN))) {
+ char **map_entry = NULL;
+ Slapi_Entry *entry = NULL;
+ sasl_map_data *dp = NULL;
+
+ for (map_entry = map_entry_list; *map_entry && !ret; map_entry++) {
+ getConfigEntry( *map_entry, &entry );
+ if ( entry == NULL ) {
+ continue;
+ }
+ ret = sasl_map_config_parse_entry(entry,&dp);
+ if (ret) {
+ LDAPDebug( LDAP_DEBUG_ANY, "sasl_map_read_config_startup failed to parse entry\n", 0, 0, 0 );
+ } else {
+ ret = sasl_map_insert_list_entry(priv,dp);
+ if (ret) {
+ LDAPDebug( LDAP_DEBUG_ANY, "sasl_map_read_config_startup failed to insert entry\n", 0, 0, 0 );
+ }
+ }
+ freeConfigEntry( &entry );
+ }
+ freeChildren( map_entry_list );
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<- sasl_map_read_config_startup\n", 0, 0, 0 );
+ return ret;
+}
+
+int
+sasl_map_config_add(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ int ret = 0;
+ sasl_map_data *dp = NULL;
+ sasl_map_private *priv = sasl_map_get_global_priv();
+ LDAPDebug( LDAP_DEBUG_TRACE, "-> sasl_map_config_add\n", 0, 0, 0 );
+ ret = sasl_map_config_parse_entry(entryBefore,&dp);
+ if (!ret && dp) {
+ ret = sasl_map_insert_list_entry(priv,dp);
+ }
+ if (0 == ret) {
+ ret = SLAPI_DSE_CALLBACK_OK;
+ } else {
+ returntext = "sasl map entry rejected";
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ ret = SLAPI_DSE_CALLBACK_ERROR;
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<- sasl_map_config_add\n", 0, 0, 0 );
+ return ret;
+}
+
+int
+sasl_map_config_delete(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ int ret = 0;
+ sasl_map_private *priv = sasl_map_get_global_priv();
+ char *entry_name = NULL;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "-> sasl_map_config_delete\n", 0, 0, 0 );
+ entry_name = slapi_entry_attr_get_charptr( entryBefore, "cn" );
+ if (entry_name) {
+ /* remove this entry from the list */
+ ret = sasl_map_remove_list_entry(priv,entry_name);
+ slapi_ch_free((void **) &entry_name);
+ }
+ if (ret) {
+ ret = SLAPI_DSE_CALLBACK_ERROR;
+ returntext = "can't delete sasl map entry";
+ *returncode = LDAP_OPERATIONS_ERROR;
+ } else {
+ ret = SLAPI_DSE_CALLBACK_OK;
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<- sasl_map_config_delete\n", 0, 0, 0 );
+ return ret;
+}
+
+/* Start and stop the sasl mapping code */
+int sasl_map_init()
+{
+ int ret = 0;
+ sasl_map_private *priv = NULL;
+ /* Make the private structure */
+ priv = sasl_map_new_private();
+ if (priv) {
+ /* Store in the static var */
+ sasl_map_static_priv = priv;
+ /* Read the config on startup */
+ ret = sasl_map_read_config_startup(priv);
+ } else {
+ ret = -1;
+ }
+ return ret;
+}
+
+int sasl_map_done()
+{
+ int ret = 0;
+ /* Free the map list */
+ /* Free the private structure */
+ return ret;
+}
+
+static sasl_map_data*
+sasl_map_first(sasl_map_private *priv)
+{
+ sasl_map_data *result = NULL;
+ PR_Lock(priv->lock);
+ result = priv->map_data_list;
+ PR_Unlock(priv->lock);
+ return result;
+}
+
+static int
+sasl_map_check(sasl_map_data *dp, char *sasl_user_and_realm, char **ldap_search_base, char **ldap_search_filter)
+{
+ int ret = 0;
+ int matched = 0;
+ char *recomp_result = NULL;
+ LDAPDebug( LDAP_DEBUG_TRACE, "-> sasl_map_check\n", 0, 0, 0 );
+ /* DBDB: currently using the rather old internal slapd regex library, which is not thread-safe */
+ /* So lock it first */
+ slapd_re_lock();
+ /* Compile the regex */
+ recomp_result = slapd_re_comp(dp->regular_expression);
+ if (recomp_result) {
+ LDAPDebug( LDAP_DEBUG_ANY, "sasl_map_check : re_comp failed for expression (%s)\n", dp->regular_expression, 0, 0 );
+ }
+ matched = slapd_re_exec(sasl_user_and_realm);
+ LDAPDebug( LDAP_DEBUG_TRACE, "regex: %s, id: %s, %s\n", dp->regular_expression, sasl_user_and_realm, matched ? "matched" : "didn't match" );
+ if (matched) {
+ if (matched == 1) {
+ /* Allocate buffers for the returned strings */
+ /* We already computed this, so we could pass it in to speed up a little */
+ size_t userrealmlen = strlen(sasl_user_and_realm);
+ /* These lengths could be precomputed and stored in the dp */
+ *ldap_search_base = (char *) slapi_ch_malloc(userrealmlen + strlen(dp->template_base_dn) + 1);
+ *ldap_search_filter = (char *) slapi_ch_malloc(userrealmlen + strlen(dp->template_search_filter) + 1);
+ slapd_re_subs(dp->template_base_dn,*ldap_search_base);
+ slapd_re_subs(dp->template_search_filter,*ldap_search_filter);
+ LDAPDebug( LDAP_DEBUG_TRACE, "mapped base dn: %s, filter: %s\n", ldap_search_base, ldap_search_filter, 0 );
+ ret = 1;
+ } else {
+ LDAPDebug( LDAP_DEBUG_ANY, "sasl_map_check : re_exec failed\n", 0, 0, 0 );
+ }
+ }
+ slapd_re_unlock();
+ LDAPDebug( LDAP_DEBUG_TRACE, "<- sasl_map_check\n", 0, 0, 0 );
+ return ret;
+}
+
+static char *
+sasl_map_str_concat(char *s1, char *s2)
+{
+ if (NULL == s2) {
+ return (slapi_ch_strdup(s1));
+ } else {
+ size_t s1len = strlen(s1);
+ size_t length = s1len + + strlen(s2);
+ char *newstr = slapi_ch_malloc(length + 2);
+ sprintf(newstr,"%s@%s",s1,s2);
+ return newstr;
+ }
+}
+
+/* Actually perform a mapping
+ * Takes a sasl identity string, and returns an LDAP search spec to be used to find the entry
+ * returns 1 if matched, 0 otherwise
+ */
+int
+sasl_map_domap(char *sasl_user, char *sasl_realm, char **ldap_search_base, char **ldap_search_filter)
+{
+ int ret = 0;
+ sasl_map_data *this_map = NULL;
+ char *sasl_user_and_realm = NULL;
+ sasl_map_private *priv = sasl_map_get_global_priv();
+ *ldap_search_base = NULL;
+ *ldap_search_filter = NULL;
+ LDAPDebug( LDAP_DEBUG_TRACE, "-> sasl_map_domap\n", 0, 0, 0 );
+ sasl_user_and_realm = sasl_map_str_concat(sasl_user,sasl_realm);
+ /* Walk the list of maps */
+ this_map = sasl_map_first(priv);
+ while (this_map) {
+ int matched = 0;
+ /* If one matches, then make the search params */
+ matched = sasl_map_check(this_map, sasl_user_and_realm, ldap_search_base, ldap_search_filter);
+ if (1 == matched) {
+ ret = 1;
+ break;
+ }
+ this_map = sasl_map_next(this_map);
+ }
+ if (sasl_user_and_realm) {
+ slapi_ch_free((void**)&sasl_user_and_realm);
+ }
+ LDAPDebug( LDAP_DEBUG_TRACE, "<- sasl_map_domap (%s)\n", (1 == ret) ? "mapped" : "not mapped", 0, 0 );
+ return ret;
+}
+
diff --git a/ldap/servers/slapd/saslbind.c b/ldap/servers/slapd/saslbind.c
new file mode 100644
index 00000000..6a488d4f
--- /dev/null
+++ b/ldap/servers/slapd/saslbind.c
@@ -0,0 +1,908 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <slap.h>
+#include <fe.h>
+#include <sasl.h>
+#include <saslplug.h>
+#include <saslmod.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+/* No GSSAPI on Windows */
+#if !defined(_WIN32)
+#define BUILD_GSSAPI 1
+#endif
+
+static char *serverfqdn;
+
+/*
+ * utility functions needed by the sasl library
+ */
+
+int sasl_os_gethost(char *buf, int len)
+{
+ int rc;
+
+ rc = gethostname(buf, len);
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl_os_gethost %s\n", buf, 0, 0);
+ return ( rc == 0 ? SASL_OK : SASL_FAIL );
+}
+
+void *sasl_mutex_alloc(void)
+{
+ return PR_NewLock();
+}
+
+int sasl_mutex_lock(void *mutex)
+{
+ PR_Lock(mutex);
+ return SASL_OK;
+}
+
+int sasl_mutex_unlock(void *mutex)
+{
+ if (PR_Unlock(mutex) == PR_SUCCESS) return SASL_OK;
+ return SASL_FAIL;
+}
+
+void sasl_mutex_free(void *mutex)
+{
+ PR_DestroyLock(mutex);
+}
+
+/*
+ * sasl library callbacks
+ */
+
+static int ids_sasl_getopt(
+ void *context,
+ const char *plugin_name,
+ const char *option,
+ const char **result,
+ unsigned *len
+)
+{
+ unsigned tmplen;
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "ids_sasl_getopt: plugin=%s option=%s\n",
+ plugin_name ? plugin_name : "", option, 0);
+
+ if (len == NULL) len = &tmplen;
+
+ *result = NULL;
+ *len = 0;
+
+ if (strcasecmp(option, "enable") == 0) {
+ *result = "USERDB/DIGEST-MD5,GSSAPI/GSSAPI";
+ } else if (strcasecmp(option, "has_plain_passwords") == 0) {
+ *result = "yes";
+ } else if (strcasecmp(option, "LOG_LEVEL") == 0) {
+ if (LDAPDebugLevelIsSet(LDAP_DEBUG_TRACE)) {
+ *result = "6"; /* SASL_LOG_TRACE */
+ }
+ }
+
+ if (*result) *len = strlen(*result);
+
+ return SASL_OK;
+}
+
+static int ids_sasl_log(
+ void *context,
+ int level,
+ const char *message
+)
+{
+ switch (level) {
+ case SASL_LOG_ERR: /* log unusual errors (default) */
+ slapi_log_error(SLAPI_LOG_FATAL, "sasl", "%s", message);
+ break;
+
+ case SASL_LOG_FAIL: /* log all authentication failures */
+ case SASL_LOG_WARN: /* log non-fatal warnings */
+ case SASL_LOG_NOTE: /* more verbose than LOG_WARN */
+ case SASL_LOG_DEBUG: /* more verbose than LOG_NOTE */
+ case SASL_LOG_TRACE: /* traces of internal protocols */
+ case SASL_LOG_PASS: /* traces of internal protocols, including
+ * passwords */
+ LDAPDebug(LDAP_DEBUG_ANY, "sasl(%d): %s", level, message, 0);
+ break;
+
+ case SASL_LOG_NONE: /* don't log anything */
+ default:
+ break;
+ }
+ return SASL_OK;
+}
+
+static int ids_sasl_proxy_policy(
+ sasl_conn_t *conn,
+ void *context,
+ const char *requested_user, int rlen,
+ const char *auth_identity, int alen,
+ const char *def_realm, int urlen,
+ struct propctx *propctx
+)
+{
+ int retVal = SASL_OK;
+ /* do not permit sasl proxy authorization */
+ /* if the auth_identity is null or empty string, allow the sasl request to go thru */
+ if ( (auth_identity != NULL ) && ( strlen(auth_identity) > 0 ) ) {
+ Slapi_DN authId , reqUser;
+ slapi_sdn_init_dn_byref(&authId,auth_identity);
+ slapi_sdn_init_dn_byref(&reqUser,requested_user);
+ if (slapi_sdn_compare((const Slapi_DN *)&reqUser,(const Slapi_DN *) &authId) != 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "sasl proxy auth not permitted authid=%s user=%s\n",
+ auth_identity, requested_user, 0);
+ retVal = SASL_NOAUTHZ;
+ }
+ slapi_sdn_done(&authId);
+ slapi_sdn_done(&reqUser);
+ }
+ return retVal;
+}
+
+static void ids_sasl_user_search(
+ char *basedn,
+ int scope,
+ char *filter,
+ LDAPControl **ctrls,
+ char **attrs,
+ int attrsonly,
+ Slapi_Entry **ep,
+ int *foundp
+)
+{
+ Slapi_Entry **entries = NULL;
+ Slapi_PBlock *pb;
+ int i, ret;
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search basedn=\"%s\" filter=\"%s\"\n", basedn, filter, 0);
+
+ /* TODO: set size and time limits */
+
+ pb = slapi_search_internal(basedn, scope, filter,
+ ctrls, attrs, attrsonly);
+ if (pb == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "null pblock from slapi_search_internal\n", 0, 0, 0);
+ goto out;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search failed basedn=\"%s\" "
+ "filter=\"%s\": %s\n",
+ basedn, filter, ldap_err2string(ret));
+ goto out;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (entries == NULL) goto out;
+
+ for (i = 0; entries[i]; i++) {
+ (*foundp)++;
+ if (*ep != NULL) {
+ slapi_entry_free(*ep);
+ }
+ *ep = slapi_entry_dup(entries[i]);
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found dn=%s\n",
+ slapi_entry_get_dn(*ep), 0, 0);
+ }
+
+ out:
+
+ if (pb) slapi_free_search_results_internal(pb);
+ return;
+}
+
+/*
+ * Search for an entry representing the sasl user.
+ */
+static Slapi_Entry *ids_sasl_user_to_entry(
+ sasl_conn_t *conn,
+ void *context,
+ const char *user,
+ const char *user_realm
+)
+{
+ int found = 0;
+ unsigned fsize = 0, ulen, rlen = 0;
+ int attrsonly = 0, scope = LDAP_SCOPE_SUBTREE;
+ char filter[1024], *fptr = filter;
+ LDAPControl **ctrls = NULL;
+ Slapi_Entry *entry = NULL;
+ Slapi_DN *sdn;
+ char **attrs = NULL;
+ char *userattr = "uid", *realmattr = NULL, *ufilter = NULL;
+ void *node;
+ int regexmatch = 0;
+ char *regex_ldap_search_base = NULL;
+ char *regex_ldap_search_filter = NULL;
+
+ /* TODO: userattr & realmattr should be configurable */
+
+ /*
+ * Check for dn: prefix. See RFC 2829 section 9.
+ */
+ if (strncasecmp(user, "dn:", 3) == 0) {
+ sprintf(fptr, "(objectclass=*)");
+ scope = LDAP_SCOPE_BASE;
+ ids_sasl_user_search((char*)user+3, scope, filter,
+ ctrls, attrs, attrsonly,
+ &entry, &found);
+ } else {
+ int offset = 0;
+ if (strncasecmp(user,"u:",2) == 0 )
+ offset = 2;
+ /* TODO: quote the filter values */
+
+ /* New regex-based identity mapping : we call it here before the old code.
+ * If there's a match, we skip the old way, otherwise we plow ahead for backwards compatibility reasons
+ */
+
+ regexmatch = sasl_map_domap((char*)user, (char*)user_realm, &regex_ldap_search_base, &regex_ldap_search_filter);
+ if (regexmatch) {
+
+ ids_sasl_user_search(regex_ldap_search_base, scope, regex_ldap_search_filter,
+ ctrls, attrs, attrsonly,
+ &entry, &found);
+
+ /* Free the filter etc */
+ slapi_ch_free((void**)&regex_ldap_search_base);
+ slapi_ch_free((void**)&regex_ldap_search_filter);
+ } else {
+
+ /* Ensure no buffer overflow. */
+ /* We don't know what the upper limits on username and
+ * realm lengths are. There don't seem to be any defined
+ * in the relevant standards. We may find in the future
+ * that a 1K buffer is insufficient for some mechanism,
+ * but it seems unlikely given that the values are exposed
+ * to the end user.
+ */
+ ulen = strlen(user+offset);
+ fsize += strlen(userattr) + ulen;
+ if (realmattr && user_realm) {
+ rlen = strlen(user_realm);
+ fsize += strlen(realmattr) + rlen;
+ }
+ if (ufilter) fsize += strlen(ufilter);
+ fsize += 100; /* includes a good safety margin */
+ if (fsize > 1024) {
+ LDAPDebug(LDAP_DEBUG_ANY, "sasl user name and/or realm too long"
+ " (ulen=%u, rlen=%u)\n", ulen, rlen, 0);
+ return NULL;
+ }
+
+ /* now we can safely write the filter */
+ sprintf(fptr, "(&(%s=%s)", userattr, user+offset);
+ fptr += strlen(fptr);
+ if (realmattr && user_realm) {
+ sprintf(fptr, "(%s=%s)", realmattr, user_realm);
+ fptr += strlen(fptr);
+ }
+ if (ufilter) {
+ if (*ufilter == '(') {
+ sprintf(fptr, "%s", ufilter);
+ } else {
+ sprintf(fptr, "(%s)", ufilter);
+ }
+ fptr += strlen(fptr);
+ }
+ sprintf(fptr, ")");
+
+ /* iterate through the naming contexts */
+ for (sdn = slapi_get_first_suffix(&node, 0); sdn != NULL;
+ sdn = slapi_get_next_suffix(&node, 0)) {
+
+ ids_sasl_user_search((char*)slapi_sdn_get_dn(sdn), scope, filter,
+ ctrls, attrs, attrsonly,
+ &entry, &found);
+ }
+ }
+ }
+
+ if (found == 1) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found this entry: dn:%s, matching filter=%s\n", entry->e_sdn.dn, filter, 0);
+ return entry;
+ }
+
+ if (found == 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found no entries matching filter=%s\n", filter, 0, 0);
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl user search found more than one entry matching filter=%s\n", filter, 0, 0);
+ }
+
+ if (entry) slapi_entry_free(entry);
+ return NULL;
+}
+
+static char *buf2str(const char *buf, unsigned buflen)
+{
+ char *ret;
+
+ ret = (char*)slapi_ch_malloc(buflen+1);
+ memcpy(ret, buf, buflen);
+ ret[buflen] = '\0';
+
+ return ret;
+}
+
+/* Note that in this sasl1 API, when it says 'authid' it really means 'authzid'. */
+static int ids_sasl_canon_user(
+ sasl_conn_t *conn,
+ void *context,
+ const char *userbuf, unsigned ulen,
+ const char *authidbuf, unsigned alen,
+ unsigned flags, const char *user_realm,
+ char *out_user, unsigned out_umax, unsigned *out_ulen,
+ char *out_authid, unsigned out_amax, unsigned *out_alen
+)
+{
+ struct propctx *propctx = sasl_auxprop_getctx(conn);
+ Slapi_Entry *entry = NULL;
+ Slapi_DN *sdn = NULL;
+ char *pw = NULL;
+ char *user = NULL;
+ char *authid = NULL;
+ const char *dn;
+ int isroot = 0;
+ char *clear = NULL;
+
+ user = buf2str(userbuf, ulen);
+ if (user == NULL) {
+ goto fail;
+ }
+ authid = buf2str(authidbuf, alen);
+
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "ids_sasl_canon_user(user=%s, authzid=%s, realm=%s)\n",
+ user, authid, user_realm ? user_realm : "");
+
+ if (strncasecmp(user, "dn:", 3) == 0) {
+ sdn = slapi_sdn_new();
+ slapi_sdn_set_dn_byval(sdn, user+3);
+ isroot = slapi_dn_isroot(slapi_sdn_get_ndn(sdn));
+ }
+
+ if (isroot) {
+ /* special case directory manager */
+ dn = slapi_sdn_get_ndn(sdn);
+ pw = config_get_rootpw();
+ } else {
+ /* map the sasl username into an entry */
+ entry = ids_sasl_user_to_entry(conn, context, user, user_realm);
+ if (entry == NULL) {
+ goto fail;
+ }
+ dn = slapi_entry_get_ndn(entry);
+ pw = slapi_entry_attr_get_charptr(entry, "userpassword");
+ }
+
+ if (prop_set(propctx, "dn", dn, -1) != 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "prop_set(dn) failed\n", 0, 0, 0);
+ goto fail;
+ }
+
+ clear = pw;
+ if (clear) {
+ if (prop_set(propctx, "userpassword", clear, -1) != 0) {
+ /* Failure is benign here because some mechanisms don't support this property */
+ /*LDAPDebug(LDAP_DEBUG_TRACE, "prop_set(userpassword) failed\n", 0, 0, 0);
+ goto fail */ ;
+ }
+ }
+
+ /* TODO: canonicalize */
+ strcpy(out_user, dn);
+ if (authid )
+ {
+ int offset = 0;
+ /* The authid can start with dn:. In such case remove it */
+ if (strncasecmp(authid,"dn:",3) == 0 )
+ offset = 3;
+ strcpy(out_authid, authid+offset);
+ }
+ *out_ulen = -1;
+ *out_alen = -1;
+
+ slapi_entry_free(entry);
+ slapi_ch_free((void**)&user);
+ slapi_ch_free((void**)&authid);
+ slapi_ch_free((void**)&pw);
+ slapi_sdn_free(&sdn);
+
+ return SASL_OK;
+
+ fail:
+ slapi_entry_free(entry);
+ slapi_ch_free((void**)&user);
+ slapi_ch_free((void**)&authid);
+ slapi_ch_free((void**)&pw);
+ slapi_sdn_free(&sdn);
+
+ return SASL_FAIL;
+}
+
+static sasl_callback_t ids_sasl_callbacks[5] =
+{
+ SASL_CB_GETOPT,
+ (IFP) ids_sasl_getopt,
+ NULL,
+ SASL_CB_LOG,
+ (IFP) ids_sasl_log,
+ NULL,
+ SASL_CB_PROXY_POLICY,
+ (IFP) ids_sasl_proxy_policy,
+ NULL,
+ SASL_CB_SERVER_CANON_USER,
+ (IFP) ids_sasl_canon_user,
+ NULL,
+ SASL_CB_LIST_END,
+ (IFP) NULL,
+ NULL
+};
+
+static const char *dn_propnames[] = { "dn", 0 };
+
+/*
+ * initialize the sasl library
+ */
+int ids_sasl_init(void)
+{
+ static int inited = 0;
+ int result;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_init\n", 0, 0, 0 );
+
+ PR_ASSERT(inited == 0);
+ inited = 1;
+
+ serverfqdn = get_localhost_DNS();
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl service fqdn is: %s\n",
+ serverfqdn, 0, 0);
+
+ result = sasl_server_init(ids_sasl_callbacks, "iDS");
+
+ if (result != SASL_OK) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "failed to initialize sasl library\n",
+ 0, 0, 0);
+ return result;
+ }
+
+ result = sasl_server_add_plugin("USERDB", sasl_userdb_init);
+
+ if (result != SASL_OK) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "failed to add LDAP sasl plugin\n",
+ 0, 0, 0);
+ return result;
+ }
+
+#if defined(BUILD_GSSAPI)
+ result = sasl_server_add_plugin("GSSAPI", sasl_gssapi_init);
+
+ if (result != SASL_OK) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "failed to add LDAP gssapi plugin\n",
+ 0, 0, 0);
+ }
+#endif
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ids_sasl_init\n", 0, 0, 0 );
+
+ return result;
+}
+
+/*
+ * create a sasl server connection
+ */
+void ids_sasl_server_new(Connection *conn)
+{
+ int rc;
+ sasl_conn_t *sasl_conn = NULL;
+ struct propctx *propctx;
+ sasl_security_properties_t secprops = {0};
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_server_new (%s)\n", serverfqdn, 0, 0 );
+
+ rc = sasl_server_new("ldap",
+ serverfqdn,
+ NULL, /* user_realm */
+ NULL, /* iplocalport */
+ NULL, /* ipremoteport */
+ ids_sasl_callbacks,
+ SASL_SUCCESS_DATA,
+ &sasl_conn);
+
+ if (rc != SASL_OK) {
+ LDAPDebug(LDAP_DEBUG_ANY, "sasl_server_new: %s\n",
+ sasl_errstring(rc, NULL, NULL), 0, 0);
+ }
+
+ if (rc == SASL_OK) {
+ propctx = sasl_auxprop_getctx(sasl_conn);
+ if (propctx != NULL) {
+ prop_request(propctx, dn_propnames);
+ }
+ }
+
+ /* Enable security for this connection */
+ secprops.maxbufsize = 2048; /* DBDB: hack */
+ secprops.max_ssf = 0xffffffff;
+ rc = sasl_setprop(sasl_conn, SASL_SEC_PROPS, &secprops);
+ if (rc != SASL_OK) {
+ LDAPDebug(LDAP_DEBUG_ANY, "sasl_setprop: %s\n",
+ sasl_errstring(rc, NULL, NULL), 0, 0);
+ }
+
+ conn->c_sasl_conn = sasl_conn;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ids_sasl_server_new\n", 0, 0, 0 );
+
+ return;
+}
+
+/*
+ * return sasl mechanisms available on this connection.
+ * caller must free returned charray.
+ */
+char **ids_sasl_listmech(Slapi_PBlock *pb)
+{
+ char **ret, **others;
+ const char *str;
+ char *dupstr;
+ sasl_conn_t *sasl_conn;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_listmech\n", 0, 0, 0 );
+
+ PR_ASSERT(pb);
+
+ /* hard-wired mechanisms and slapi plugin registered mechanisms */
+ ret = slapi_get_supported_saslmechanisms_copy();
+
+ if (pb->pb_conn == NULL) return ret;
+
+ sasl_conn = (sasl_conn_t*)pb->pb_conn->c_sasl_conn;
+ if (sasl_conn == NULL) return ret;
+
+ /* sasl library mechanisms are connection dependent */
+ PR_Lock(pb->pb_conn->c_mutex);
+ if (sasl_listmech(sasl_conn,
+ NULL, /* username */
+ "", ",", "",
+ &str, NULL, NULL) == SASL_OK) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl library mechs: %s\n", str, 0, 0);
+ /* merge into result set */
+ dupstr = slapi_ch_strdup(str);
+ others = str2charray(dupstr, ",");
+ charray_merge(&ret, others, 1);
+ charray_free(others);
+ slapi_ch_free((void**)&dupstr);
+ }
+ PR_Unlock(pb->pb_conn->c_mutex);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, ">= ids_sasl_listmech\n", 0, 0, 0 );
+
+ return ret;
+}
+
+/*
+ * Determine whether a given sasl mechanism is supported by
+ * this sasl connection. Returns true/false.
+ */
+static int
+ids_sasl_mech_supported(Slapi_PBlock *pb, sasl_conn_t *sasl_conn, const char *mech)
+{
+ int i, ret = 0;
+ char **mechs;
+ char *dupstr;
+ const char *str;
+ int sasl_result = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_mech_supported\n", 0, 0, 0 );
+
+
+ /* sasl_listmech is not thread-safe, so we lock here */
+ PR_Lock(pb->pb_conn->c_mutex);
+ sasl_result = sasl_listmech(sasl_conn,
+ NULL, /* username */
+ "", ",", "",
+ &str, NULL, NULL);
+ PR_Unlock(pb->pb_conn->c_mutex);
+ if (sasl_result != SASL_OK) {
+ return 0;
+ }
+
+ dupstr = slapi_ch_strdup(str);
+ mechs = str2charray(dupstr, ",");
+
+ for (i = 0; mechs[i] != NULL; i++) {
+ if (strcasecmp(mech, mechs[i]) == 0) {
+ ret = 1;
+ break;
+ }
+ }
+
+ charray_free(mechs);
+ slapi_ch_free((void**)&dupstr);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ids_sasl_mech_supported\n", 0, 0, 0 );
+
+ return ret;
+}
+
+/*
+ * do a sasl bind and return a result
+ */
+void ids_sasl_check_bind(Slapi_PBlock *pb)
+{
+ int rc, isroot;
+ long t;
+ sasl_conn_t *sasl_conn;
+ struct propctx *propctx;
+ sasl_ssf_t *ssfp;
+ char *activemech = NULL, *mech = NULL;
+ char *username, *dn = NULL;
+ const char *sdata, *errstr;
+ unsigned slen;
+ int continuing = 0;
+ int pwresponse_requested = 0;
+ LDAPControl **ctrls;
+ struct berval bvr, *cred;
+ struct propval dnval[2];
+ char authtype[256]; /* >26 (strlen(SLAPD_AUTH_SASL)+SASL_MECHNAMEMAX+1) */
+ Slapi_Entry *bind_target_entry = NULL, *referral = NULL;
+ Slapi_Backend *be = NULL;
+ char errorbuf[BUFSIZ];
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_check_bind\n", 0, 0, 0 );
+
+ PR_ASSERT(pb);
+ PR_ASSERT(pb->pb_conn);
+
+ continuing = pb->pb_conn->c_flags & CONN_FLAG_SASL_CONTINUE;
+ pb->pb_conn->c_flags &= ~CONN_FLAG_SASL_CONTINUE; /* reset flag */
+
+ sasl_conn = (sasl_conn_t*)pb->pb_conn->c_sasl_conn;
+ if (sasl_conn == NULL) {
+ send_ldap_result( pb, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL,
+ "sasl library unavailable", 0, NULL );
+ return;
+ }
+
+ slapi_pblock_get(pb, SLAPI_BIND_SASLMECHANISM, &mech);
+ slapi_pblock_get(pb, SLAPI_BIND_CREDENTIALS, &cred);
+ slapi_pblock_get(pb, SLAPI_PWPOLICY, &pwresponse_requested);
+ PR_ASSERT(mech);
+ PR_ASSERT(cred);
+
+ /* Work around a bug in the sasl library. We've told the
+ * library that CRAM-MD5 is disabled, but it gives us a
+ * different error code to SASL_NOMECH.
+ */
+ if (!ids_sasl_mech_supported(pb, sasl_conn, mech)) {
+ rc = SASL_NOMECH;
+ goto sasl_check_result;
+ }
+
+ /* can't do any harm */
+ if (cred->bv_len == 0) cred->bv_val = NULL;
+
+ if (continuing) {
+ /*
+ * RFC 2251: a client may abort a sasl bind negotiation by
+ * sending a bindrequest with a different value in the
+ * mechanism field.
+ */
+ sasl_getprop(sasl_conn, SASL_MECHNAME, (const void**)&activemech);
+ if (activemech == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "could not get active sasl mechanism\n", 0, 0, 0);
+ goto sasl_start;
+ }
+ if (strcasecmp(activemech, mech) != 0) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl mechanisms differ: active=%s current=%s\n", 0, 0, 0);
+ goto sasl_start;
+ }
+
+ rc = sasl_server_step(sasl_conn,
+ cred->bv_val, cred->bv_len,
+ &sdata, &slen);
+ goto sasl_check_result;
+ }
+
+ sasl_start:
+
+ rc = sasl_server_start(sasl_conn, mech,
+ cred->bv_val, cred->bv_len,
+ &sdata, &slen);
+
+ sasl_check_result:
+
+ switch (rc) {
+ case SASL_OK: /* complete */
+
+ /* retrieve the authenticated username */
+ if (sasl_getprop(sasl_conn, SASL_USERNAME,
+ (const void**)&username) != SASL_OK) {
+ send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
+ "could not obtain sasl username", 0, NULL);
+ break;
+ }
+
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl authenticated mech=%s user=%s\n",
+ mech, username, 0);
+
+ /*
+ * Retrieve the DN corresponding to the authenticated user.
+ * This should have been set by the user canon callback
+ * in an auxiliary property called "dn".
+ */
+ propctx = sasl_auxprop_getctx(sasl_conn);
+ if (prop_getnames(propctx, dn_propnames, dnval) == 1) {
+ if (dnval[0].values && dnval[0].values[0]) {
+ dn = slapi_ch_strdup(dnval[0].values[0]);
+ }
+ }
+ if (dn == NULL) {
+ send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
+ "could not get auth dn from sasl", 0, NULL);
+ break;
+ }
+
+ isroot = slapi_dn_isroot(dn);
+
+ if (!isroot )
+ {
+ /* check if the account is locked */
+ bind_target_entry = get_entry(pb, dn);
+ if ( bind_target_entry == NULL )
+ {
+ break;
+ }
+ if ( check_account_lock(pb, bind_target_entry, pwresponse_requested) == 1) {
+ slapi_entry_free(bind_target_entry);
+ break;
+ }
+ }
+
+ /* see if we negotiated a security layer */
+ if ((sasl_getprop(sasl_conn, SASL_SSF,
+ (const void**)&ssfp) == SASL_OK) && (*ssfp > 0)) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "sasl ssf=%u\n", (unsigned)*ssfp, 0, 0);
+
+ if (pb->pb_conn->c_flags & CONN_FLAG_SSL) {
+ send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
+ "sasl encryption not supported over ssl",
+ 0, NULL);
+ if ( bind_target_entry != NULL )
+ slapi_entry_free(bind_target_entry);
+ break;
+ } else {
+ /* Enable SASL I/O on the connection now */
+ /* Note that this doesn't go into effect until the next _read_ operation is done */
+ if (0 != sasl_io_enable(pb->pb_conn) ) {
+ send_ldap_result(pb, LDAP_OPERATIONS_ERROR, NULL,
+ "failed to enable sasl i/o",
+ 0, NULL);
+ }
+ }
+ }
+
+ /* set the connection bind credentials */
+ sprintf(authtype, "%s%s", SLAPD_AUTH_SASL, mech);
+ bind_credentials_set(pb->pb_conn, authtype, dn,
+ NULL, NULL, NULL, bind_target_entry);
+
+ /* set the auth response control if requested */
+ slapi_pblock_get(pb, SLAPI_REQCONTROLS, &ctrls);
+ if (slapi_control_present(ctrls, LDAP_CONTROL_AUTH_REQUEST,
+ NULL, NULL)) {
+ add_auth_response_control(pb, dn);
+ }
+
+ if (slapi_mapping_tree_select(pb, &be, &referral, errorbuf) != LDAP_SUCCESS) {
+ send_nobackend_ldap_result( pb );
+ be = NULL;
+ LDAPDebug( LDAP_DEBUG_TRACE, "<= ids_sasl_check_bind\n", 0, 0, 0 );
+ return;
+ }
+
+ if (referral) {
+ send_referrals_from_entry(pb,referral);
+ goto out;
+ }
+
+ slapi_pblock_set( pb, SLAPI_BACKEND, be );
+
+ slapi_pblock_set( pb, SLAPI_PLUGIN, be->be_database );
+ set_db_default_result_handlers(pb);
+
+ /* check password expiry */
+ if (!isroot) {
+ int pwrc;
+
+ pwrc = need_new_pw (pb, &t, bind_target_entry, pwresponse_requested);
+ if ( bind_target_entry != NULL ) {
+ slapi_entry_free(bind_target_entry);
+ bind_target_entry = NULL;
+ }
+
+ switch (pwrc) {
+ case 1:
+ add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0);
+ break;
+ case 2:
+ add_pwd_control(pb, LDAP_CONTROL_PWEXPIRING, t);
+ break;
+ case -1:
+ goto out;
+ default:
+ break;
+ }
+ }
+
+ /* attach the sasl data */
+ if (slen != 0) {
+ bvr.bv_val = (char*)sdata;
+ bvr.bv_len = slen;
+ slapi_pblock_set(pb, SLAPI_BIND_RET_SASLCREDS, &bvr);
+ }
+
+ /* send successful result */
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+
+ /* TODO: enable sasl security layer */
+
+ /* remove the sasl data from the pblock */
+ slapi_pblock_set(pb, SLAPI_BIND_RET_SASLCREDS, NULL);
+
+ break;
+
+ case SASL_CONTINUE: /* another step needed */
+ pb->pb_conn->c_flags |= CONN_FLAG_SASL_CONTINUE;
+
+ /* attach the sasl data */
+ bvr.bv_val = (char*)sdata;
+ bvr.bv_len = slen;
+ slapi_pblock_set(pb, SLAPI_BIND_RET_SASLCREDS, &bvr);
+
+ /* send continuation result */
+ send_ldap_result( pb, LDAP_SASL_BIND_IN_PROGRESS, NULL,
+ NULL, 0, NULL );
+
+ /* remove the sasl data from the pblock */
+ slapi_pblock_set(pb, SLAPI_BIND_RET_SASLCREDS, NULL);
+
+ break;
+
+ case SASL_NOMECH:
+
+ send_ldap_result(pb, LDAP_AUTH_METHOD_NOT_SUPPORTED, NULL,
+ "sasl mechanism not supported", 0, NULL);
+ break;
+
+ default: /* other error */
+ errstr = sasl_errdetail(sasl_conn);
+
+ send_ldap_result(pb, LDAP_INVALID_CREDENTIALS, NULL,
+ (char*)errstr, 0, NULL);
+ break;
+ }
+
+ out:
+ if (referral)
+ slapi_entry_free(referral);
+ if (be)
+ slapi_be_Unlock(be);
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "=> ids_sasl_check_bind\n", 0, 0, 0 );
+
+ return;
+}
+
diff --git a/ldap/servers/slapd/schema.c b/ldap/servers/slapd/schema.c
new file mode 100644
index 00000000..9404dccb
--- /dev/null
+++ b/ldap/servers/slapd/schema.c
@@ -0,0 +1,4664 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* schema.c - routines to enforce schema definitions */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <prio.h>
+#include <plstr.h>
+#include <plhash.h>
+#include "slap.h"
+
+typedef struct sizedbuffer
+{
+ char *buffer;
+ size_t size;
+} sizedbuffer;
+
+
+typedef char *(*schema_strstr_fn_t)( const char *big, const char *little);
+
+
+
+/*
+ * The schema_oc_kind_strings array is indexed by oc_kind values, i.e.,
+ * OC_KIND_STRUCTURAL (0), OC_KIND_AUXILIARY (1), or OC_KIND_ABSTRACT (2).
+ * The leading and trailing spaces are intentional.
+ */
+#define SCHEMA_OC_KIND_COUNT 3
+static char *schema_oc_kind_strings_with_spaces[] = {
+ " STRUCTURAL ",
+ " AUXILIARY ",
+ " ABSTRACT ",
+};
+
+/* constant strings (used in a few places) */
+static const char *schema_obsolete_with_spaces = " OBSOLETE ";
+static const char *schema_collective_with_spaces = " COLLECTIVE ";
+static const char *schema_nousermod_with_spaces = " NO-USER-MODIFICATION ";
+
+/* user defined origin array */
+static char *schema_user_defined_origin[] = {
+ "user defined",
+ NULL
+};
+
+/*
+ * pschemadse is based on the general implementation in dse
+ */
+
+static struct dse *pschemadse= NULL;
+
+static void oc_add_nolock(struct objclass *newoc);
+static int oc_delete_nolock (char *ocname);
+static int oc_replace_nolock(const char *ocname, struct objclass *newoc);
+static int oc_check_required(Slapi_PBlock *, Slapi_Entry *,struct objclass *);
+static int oc_check_allowed_sv(Slapi_PBlock *, Slapi_Entry *e, const char *type, struct objclass **oclist );
+static char **read_dollar_values ( char *vals);
+static int schema_delete_objectclasses ( Slapi_Entry *entryBefore,
+ LDAPMod *mod, char *errorbuf, size_t errorbufsize,
+ int schema_ds4x_compat );
+static int schema_delete_attributes ( Slapi_Entry *entryBefore,
+ LDAPMod *mod, char *errorbuf, size_t errorbufsize);
+static int schema_add_attribute ( Slapi_PBlock *pb, LDAPMod *mod,
+ char *errorbuf, size_t errorbufsize, int schema_ds4x_compat );
+static int schema_add_objectclass ( Slapi_PBlock *pb, LDAPMod *mod,
+ char *errorbuf, size_t errorbufsize, int schema_ds4x_compat );
+static int schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod,
+ char *errorbuf, size_t errorbufsize );
+static int schema_replace_objectclasses ( Slapi_PBlock *pb, LDAPMod *mod,
+ char *errorbuf, size_t errorbufsize );
+static int read_oc_ldif ( const char *input, struct objclass **oc,
+ char *errorbuf, size_t errorbufsize, int nolock, int is_user_defined,
+ int schema_ds4x_compat );
+static int schema_check_name(char *name, PRBool isAttribute, char *errorbuf,
+ size_t errorbufsize );
+static int schema_check_oid(const char *name, const char *oid,
+ PRBool isAttribute, char *errorbuf, size_t errorbufsize);
+static int has_smart_referral( Slapi_Entry *e );
+static int isExtensibleObjectclass(const char *objectclass);
+static int strip_oc_options ( struct objclass *poc );
+static char *stripOption (char *attr);
+static int read_at_ldif(const char *input, struct asyntaxinfo **asipp,
+ char *errorbuf, size_t errorbufsize, int nolock, int is_user_defined,
+ int schema_ds4x_compat, int is_remote);
+static char **parse_qdlist(const char *s, int *n, int strip_options);
+static void free_qdlist(char **vals, int n);
+static char **parse_qdescrs(const char *s, int *n);
+static char **parse_qdstrings(const char *s, int *n);
+static int get_flag_keyword( const char *keyword, int flag_value,
+ const char **inputp, schema_strstr_fn_t strstr_fn );
+static char *get_tagged_oid( const char *tag, const char **inputp,
+ schema_strstr_fn_t strstr_fn );
+static int put_tagged_oid( char *outp, const char *tag, const char *oid,
+ const char *suffix, int enquote );
+static void strcat_oids( char *buf, char *prefix, char **oids,
+ int schema_ds4x_compat );
+static size_t strcat_qdlist( char *buf, char *prefix, char **qdlist );
+static size_t strlen_null_ok(const char *s);
+static int strcpy_count( char *dst, const char *src );
+static int element_is_user_defined( char * const * origins );
+static char **parse_origin_list( const char *schema_value, int *num_originsp,
+ char **default_list );
+static int refresh_user_defined_schema(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg);
+static int schema_check_oc_attrs ( struct objclass *poc, char *errorbuf,
+ size_t errorbufsize, int stripOptions );
+static struct objclass *oc_find_nolock( const char *ocname_or_oid );
+static struct objclass *oc_find_oid_nolock( const char *ocoid );
+static void oc_free( struct objclass **ocp );
+static PRBool oc_equal( struct objclass *oc1, struct objclass *oc2 );
+static PRBool attr_syntax_equal( struct asyntaxinfo *asi1,
+ struct asyntaxinfo *asi2 );
+static int schema_strcmp( const char *s1, const char *s2 );
+static int schema_strcmp_array( char **sa1, char **sa2,
+ const char *ignorestr );
+static PRBool schema_type_is_interesting( const char *type );
+static void schema_create_errormsg( char *errorbuf, size_t errorbufsize,
+ const char *prefix, const char *name, const char *fmt, ... );
+
+/* Some utility functions for dealing with a dynamic buffer */
+
+static struct sizedbuffer *sizedbuffer_construct(size_t size);
+static void sizedbuffer_destroy(struct sizedbuffer *p);
+static void sizedbuffer_allocate(struct sizedbuffer *p, size_t sizeneeded);
+
+
+/*
+ * Constant strings that we pass to schema_create_errormsg().
+ */
+static const char *schema_errprefix_oc = "object class %s: ";
+static const char *schema_errprefix_at = "attribute type %s: ";
+static const char *schema_errprefix_generic = "%s: ";
+
+
+/*
+ * A "cached" copy of the "ignore trailing spaces" config. setting.
+ * This is set during initialization only (server restart required for
+ * changes to take effect). We do things this way to avoid lock/unlock
+ * mutex sequences inside performance critical code.
+ */
+static int schema_ignore_trailing_spaces =
+ SLAPD_DEFAULT_SCHEMA_IGNORE_TRAILING_SPACES;
+
+/* R/W lock used to serialize access to the schema DSE */
+static PRRWLock *schema_dse_lock = NULL;
+
+/*
+ * The schema_dse_mandatory_init_callonce structure is used by NSPR to ensure
+ * that schema_dse_mandatory_init() is called at most once.
+ */
+static PRCallOnceType schema_dse_mandatory_init_callonce = { 0, 0, 0 };
+
+
+/* Essential initialization. Returns PRSuccess if successful */
+static PRStatus
+schema_dse_mandatory_init( void )
+{
+ if ( NULL == ( schema_dse_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
+ "schema DSE rwlock" ))) {
+ slapi_log_error( SLAPI_LOG_FATAL, "schema_dse_mandatory_init",
+ "PR_NewRWLock() for schema DSE lock failed\n" );
+ return PR_FAILURE;
+ }
+
+ schema_ignore_trailing_spaces = config_get_schema_ignore_trailing_spaces();
+ return PR_SUCCESS;
+}
+
+
+static void
+schema_dse_lock_read( void )
+{
+ if ( NULL != schema_dse_lock ||
+ PR_SUCCESS == PR_CallOnce( &schema_dse_mandatory_init_callonce,
+ schema_dse_mandatory_init )) {
+ PR_RWLock_Rlock( schema_dse_lock );
+ }
+}
+
+
+static void
+schema_dse_lock_write( void )
+{
+ if ( NULL != schema_dse_lock ||
+ PR_SUCCESS == PR_CallOnce( &schema_dse_mandatory_init_callonce,
+ schema_dse_mandatory_init )) {
+ PR_RWLock_Wlock( schema_dse_lock );
+ }
+}
+
+
+static void
+schema_dse_unlock( void )
+{
+ if ( schema_dse_lock != NULL ) {
+ PR_RWLock_Unlock( schema_dse_lock );
+ }
+}
+
+
+static int
+dont_allow_that(Slapi_PBlock *pb, Slapi_Entry* entryBefore, Slapi_Entry* e, int *returncode, char *returntext, void *arg)
+{
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+#if 0
+/*
+ * hashNocaseString - used for case insensitive hash lookups
+ */
+static PLHashNumber
+hashNocaseString(const void *key)
+{
+ PLHashNumber h = 0;
+ const unsigned char *s;
+
+ for (s = key; *s; s++)
+ h = (h >> 28) ^ (h << 4) ^ (tolower(*s));
+ return h;
+}
+#endif
+
+static const char *
+skipWS(const char *s)
+{
+ while (s && isascii(*s) && isspace(*s) )
+ ++s;
+
+ if ((isascii(*s)) == 0) {
+ return NULL;
+ }
+ return s;
+}
+
+
+/*
+ * like strchr() but strings within single quotes are skipped.
+ */
+static char *
+strchr_skip_quoted_strings( char *s, int c )
+{
+ int in_quote = 0;
+
+ while ( *s != '\0' ) {
+ if ( *s == '\'' ) {
+ in_quote = 1 - in_quote; /* toggle */
+ } else if ( !in_quote && *s == c ) {
+ return s;
+ }
+ ++s;
+ }
+
+ return( NULL );
+}
+
+
+/**
+ * parses a string containing a qdescrs or qdstrings (as described by
+ * RFC 2252, section 4.1) into an array of strings; the second parameter
+ * will hold the actual number of strings in the array. The returned array
+ * is NULL terminated.
+ *
+ * This function can handle qdescrs or qdstrings because the only
+ * difference between the two is that fewer characters are allowed in
+ * a qdescr (our parsing code does not check anyway) and we want to
+ * strip attribute options when parsing qdescrs (indicated by a non-zero
+ * strip_options parameter).
+ */
+static char **
+parse_qdlist(const char *s, int *n, int strip_options)
+{
+ char **retval = 0;
+ char *work = 0;
+ char *start = 0, *end = 0;
+ int num = 0;
+ int in_quote = 0;
+
+ if (n)
+ *n = 0;
+
+ if (!s || !*s || !n) {
+ return retval;
+ }
+
+ /* make a working copy of the given string */
+ work = slapi_ch_strdup(s);
+
+ /* count the number of qdescr items in the string e.g. just count
+ the number of spaces */
+ /* for a single qdescr, the terminal character will be the final
+ single quote; for a qdesclist, the terminal will be the close
+ parenthesis */
+ end = strrchr(work, '\'');
+ if ((start = strchr_skip_quoted_strings(work, '(')) != NULL)
+ end = strchr_skip_quoted_strings(work, ')');
+ else
+ start = strchr(work, '\'');
+
+ if (!end) /* already nulled out */
+ end = work + strlen(work);
+
+ if (start) {
+ num = 1;
+ /* first pass: count number of items and zero out non useful tokens */
+ for (; *start && (start != end); ++start) {
+ if (*start == '\'' ) {
+ in_quote = 1 - in_quote; /* toggle */
+ *start = 0;
+ } else if ( !in_quote && ((*start == ' ') || (*start == '(') ||
+ (*start == ')'))) {
+ if (*start == ' ') {
+ num++;
+ }
+ *start = 0;
+ }
+ }
+ *start = 0;
+
+ /* allocate retval; num will be >= actual number of items */
+ retval = (char**)slapi_ch_calloc(num+1, sizeof(char *));
+
+ /* second pass: copy strings into the return value and set the
+ actual number of items returned */
+ start = work;
+ while (start != end) {
+ /* skip over nulls */
+ while (!*start && (start != end))
+ ++start;
+ if (start == end)
+ break;
+ retval[*n] = slapi_ch_strdup(start);
+ /*
+ * A qdescr list may contain attribute options; we just strip
+ * them here. In the future, we may want to support them or do
+ * something really fancy with them
+ */
+ if ( strip_options ) {
+ stripOption(retval[*n]);
+ }
+ (*n)++;
+ start += strlen(start);
+ }
+ PR_ASSERT( *n <= num ); /* sanity check */
+ retval[*n] = NULL;
+ } else {
+ /* syntax error - no start and/or end delimiters */
+ }
+
+ /* free the working string */
+ slapi_ch_free((void **)&work);
+
+ return retval;
+}
+
+
+static void
+free_qdlist(char **vals, int n)
+{
+ int ii;
+ for (ii = 0; ii < n; ++ii)
+ slapi_ch_free((void **)&(vals[ii]));
+ slapi_ch_free((void **)&vals);
+}
+
+
+/**
+ * parses a string containing a qdescrs (as described by RFC 2252, section 4.1)
+ * into an array of strings; the second parameter will hold the actual number
+ * of strings in the array. The returned array is NULL terminated.
+ */
+static char **
+parse_qdescrs(const char *s, int *n)
+{
+ return parse_qdlist( s, n, 1 /* strip attribute options */ );
+}
+
+
+/*
+ * Parses a string containing a qdstrings (see RFC 2252, section 4.1) into
+ * an array of strings; the second parameter will hold the actual number
+ * of strings in the array.
+ */
+static char **
+parse_qdstrings(const char *s, int *n)
+{
+ return parse_qdlist( s, n, 0 /* DO NOT strip attribute options */ );
+}
+
+
+/*
+ * slapi_entry_schema_check - check that entry e conforms to the schema
+ * required by its object class(es). returns 0 if so, non-zero otherwise.
+ * [ the pblock is only used to check if this is a replicated operation.
+ * you may pass in NULL if this isn't part of an operation. ]
+ */
+int
+slapi_entry_schema_check( Slapi_PBlock *pb, Slapi_Entry *e )
+{
+ struct objclass **oclist;
+ struct objclass *oc;
+ const char *ocname;
+ Slapi_Attr *a, *aoc;
+ Slapi_Value *v;
+ int ret = 0;
+ int schemacheck = config_get_schemacheck();
+ int is_replicated_operation = 0;
+ int is_extensible_object = 0;
+ int i, oc_count = 0;
+ int unknown_class = 0;
+ char errtext[ BUFSIZ ];
+
+ /* smart referrals are not allowed in Directory Lite */
+ if ( config_is_slapd_lite() ) {
+ if ( has_smart_referral(e) ) {
+ return 1;
+ }
+ }
+
+ /*
+ * say the schema checked out ok if we're not checking schema at
+ * all, or if this is a replication update.
+ */
+ if (pb != NULL)
+ slapi_pblock_get(pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
+ if ( schemacheck == 0 || is_replicated_operation ) {
+ return( 0 );
+ }
+
+ /* find the object class attribute - could error out here */
+ if ( (aoc = attrlist_find( e->e_attrs, "objectclass" )) == NULL ) {
+ char ebuf[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Entry \"%s\" required attribute \"objectclass\" missing\n",
+ escape_string( slapi_entry_get_dn_const(e), ebuf ), 0, 0 );
+ if (pb) {
+ PR_snprintf( errtext, sizeof( errtext ),
+ "missing required attribute \"objectclass\"\n" );
+ slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
+ }
+ return( 1 );
+ }
+
+ /*
+ * Create an array of pointers to the objclass definitions.
+ */
+
+ i= slapi_attr_first_value(aoc,&v);
+ while (i != -1) {
+ oc_count++;
+ i= slapi_attr_next_value(aoc,i,&v);
+ }
+
+ oclist = (struct objclass**)
+ slapi_ch_malloc((oc_count+1)*sizeof(struct objclass*));
+
+ /*
+ * Need the read lock to create the oc array and while we use it.
+ */
+ oc_lock_read();
+
+ oc_count = 0;
+ for (i= slapi_attr_first_value(aoc,&v); i != -1;
+ i= slapi_attr_next_value(aoc,i,&v)) {
+
+ ocname = slapi_value_get_string(v);
+
+ if ( isExtensibleObjectclass( ocname )) {
+ /*
+ * if the entry is an extensibleObject, just check to see if
+ * the required attributes for whatever other objectclasses the
+ * entry might be are present. All other attributes are allowed
+ */
+ is_extensible_object = 1;
+ continue;
+ }
+
+ if ((oc = oc_find_nolock( ocname )) != NULL ) {
+ oclist[oc_count++] = oc;
+ } else {
+ /* we don't know about the oc; return an appropriate error message */
+ char ebuf[ BUFSIZ ];
+ char ebuf2[ BUFSIZ ];
+ size_t ocname_len = ( ocname == NULL ) ? 0 : strlen( ocname );
+ const char *extra_msg = "";
+
+ if ( ocname_len > 0 && isspace( ocname[ ocname_len-1 ] )) {
+ if ( ocname_len > 1 && isspace( ocname[ ocname_len-2 ] )) {
+ extra_msg = " (remove the trailing spaces)";
+ } else {
+ extra_msg = " (remove the trailing space)";
+ }
+ }
+
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Entry \"%s\" has unknown object class \"%s\"%s\n",
+ escape_string( slapi_entry_get_dn_const(e), ebuf ),
+ escape_string(ocname, ebuf2), extra_msg );
+ if (pb) {
+ PR_snprintf( errtext, sizeof( errtext ),
+ "unknown object class \"%s\"%s\n",
+ escape_string(ocname, ebuf2), extra_msg );
+ slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
+ }
+ unknown_class = 1;
+ }
+
+ }
+ oclist[oc_count] = NULL;
+
+ if (unknown_class) {
+ /* failure */
+ ret = 1;
+ goto out;
+ }
+
+ /*
+ * go through all the checking so we can log everything
+ * wrong with the entry. some day, we might want to return
+ * this information to the client as an error message.
+ */
+
+ /*
+ * check that the entry has required attrs for each oc
+ */
+ for (i = 0; oclist[i] != NULL; i++) {
+ if ( oc_check_required( pb, e, oclist[i] ) != 0 ) {
+ ret = 1;
+ goto out;
+ }
+ }
+
+ /*
+ * check that each attr in the entry is allowed by some oc,
+ * and that single-valued attrs only have one value
+ */
+
+ {
+ Slapi_Attr *prevattr;
+ i = slapi_entry_first_attr(e, &a);
+ while (-1 != i && 0 == ret)
+ {
+ if (is_extensible_object == 0 &&
+ unknown_class == 0 &&
+ !slapi_attr_flag_is_set(a, SLAPI_ATTR_FLAG_OPATTR))
+ {
+ char *attrtype;
+ slapi_attr_get_type(a, &attrtype);
+ if (oc_check_allowed_sv(pb, e, attrtype, oclist) != 0)
+ {
+ ret = 1;
+ }
+ }
+
+ if ( slapi_attr_flag_is_set( a, SLAPI_ATTR_FLAG_SINGLE ) ) {
+ if (slapi_valueset_count(&a->a_present_values) > 1)
+ {
+ char ebuf[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Entry \"%s\" single-valued attribute \"%s\" has multiple values\n",
+ escape_string( slapi_entry_get_dn_const(e), ebuf ),
+ a->a_type, 0 );
+ if (pb) {
+ PR_snprintf( errtext, sizeof( errtext ),
+ "single-valued attribute \"%s\" has multiple values\n",
+ a->a_type );
+ slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
+ }
+ ret = 1;
+ }
+ }
+ prevattr = a;
+ i = slapi_entry_next_attr(e, prevattr, &a);
+ }
+ }
+
+ out:
+ /* Done with the oc array so can release the lock */
+ oc_unlock();
+ slapi_ch_free((void**)&oclist);
+
+ return( ret );
+}
+
+/*
+ * The caller must obtain a read lock first by calling oc_lock_read().
+ */
+static int
+oc_check_required( Slapi_PBlock *pb, Slapi_Entry *e, struct objclass *oc )
+{
+ int i;
+ int rc = 0; /* success, by default */
+ Slapi_Attr *a;
+
+ if (oc == NULL || oc->oc_required == NULL || oc->oc_required[0] == NULL) {
+ return 0; /* success, as none required */
+ }
+
+ /* for each required attribute */
+ for ( i = 0; oc->oc_required[i] != NULL; i++ ) {
+ /* see if it's in the entry */
+ for ( a = e->e_attrs; a != NULL; a = a->a_next ) {
+ if ( slapi_attr_type_cmp( oc->oc_required[i], a->a_type,
+ SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
+ break;
+ }
+ }
+
+ /* not there => schema violation */
+ if ( a == NULL ) {
+ char errtext[ BUFSIZ ];
+ char ebuf[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Entry \"%s\" missing attribute \"%s\" required"
+ " by object class \"%s\"\n",
+ escape_string( slapi_entry_get_dn_const(e), ebuf ),
+ oc->oc_required[i], oc->oc_name);
+ if (pb) {
+ PR_snprintf( errtext, sizeof( errtext ),
+ "missing attribute \"%s\" required"
+ " by object class \"%s\"\n",
+ oc->oc_required[i], oc->oc_name );
+ slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
+ }
+ rc = 1; /* failure */
+ }
+ }
+
+ return rc;
+}
+
+
+
+/*
+ * The caller must obtain a read lock first by calling oc_lock_read().
+ */
+static int
+oc_check_allowed_sv(Slapi_PBlock *pb, Slapi_Entry *e, const char *type, struct objclass **oclist )
+{
+ struct objclass *oc;
+ int i, j;
+ int rc = 1; /* failure */
+
+ /* always allow objectclass and entryid attributes */
+ /* MFW XXX THESE SHORTCUTS SHOULD NOT BE NECESSARY BUT THEY MASK
+ * MFW XXX OTHER BUGS IN THE SERVER.
+ */
+ if ( slapi_attr_type_cmp( type, "objectclass", SLAPI_TYPE_CMP_EXACT ) == 0 ) {
+ return( 0 );
+ } else if ( slapi_attr_type_cmp( type, "entryid", SLAPI_TYPE_CMP_EXACT ) == 0 ) {
+ return( 0 );
+ }
+
+ /* check that the type appears as req or opt in at least one oc */
+ for (i = 0; rc != 0 && oclist[i] != NULL; i++) {
+ oc = oclist[i];
+
+ /* does it require the type? */
+ for ( j = 0; oc->oc_required && oc->oc_required[j] != NULL; j++ ) {
+ if ( slapi_attr_type_cmp( oc->oc_required[j],
+ type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ) {
+ rc = 0;
+ break;
+ }
+ }
+
+ if ( 0 != rc ) {
+ /* does it allow the type? */
+ for ( j = 0; oc->oc_allowed && oc->oc_allowed[j] != NULL; j++ ) {
+ if ( slapi_attr_type_cmp( oc->oc_allowed[j],
+ type, SLAPI_TYPE_CMP_SUBTYPE ) == 0 ||
+ strcmp( oc->oc_allowed[j],"*" ) == 0 ) {
+ rc = 0;
+ break;
+ }
+ }
+ /* maybe the next oc allows it */
+ }
+ }
+
+ if ( 0 != rc ) {
+ char errtext[ BUFSIZ ];
+ char ebuf[ BUFSIZ ];
+ char ebuf2[ BUFSIZ ];
+ LDAPDebug( LDAP_DEBUG_ANY,
+ "Entry \"%s\" -- attribute \"%s\" not allowed\n",
+ escape_string( slapi_entry_get_dn_const(e), ebuf ),
+ escape_string( type, ebuf2 ),
+ 0);
+
+ if (pb) {
+ PR_snprintf( errtext, sizeof( errtext ),
+ "attribute \"%s\" not allowed\n",
+ escape_string( type, ebuf2 ) );
+ slapi_pblock_set( pb, SLAPI_PB_RESULT_TEXT, errtext );
+ }
+ }
+
+ return rc;
+}
+
+
+
+
+/*
+ * oc_find_name() will return a strdup'd string or NULL if the objectclass
+ * could not be found.
+ */
+char *
+oc_find_name( const char *name_or_oid )
+{
+ struct objclass *oc;
+ char *ocname = NULL;
+
+ oc_lock_read();
+ if ( NULL != ( oc = oc_find_nolock( name_or_oid ))) {
+ ocname = slapi_ch_strdup( oc->oc_name );
+ }
+ oc_unlock();
+
+ return ocname;
+}
+
+
+/*
+ * oc_find_nolock will return a pointer to the objectclass which has the
+ * same name OR oid.
+ * NULL is returned if no match is found or `name_or_oid' is NULL.
+ */
+static struct objclass *
+oc_find_nolock( const char *ocname_or_oid )
+{
+ struct objclass *oc;
+
+ if ( NULL != ocname_or_oid ) {
+ if ( !schema_ignore_trailing_spaces ) {
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
+ if ( ( strcasecmp( oc->oc_name, ocname_or_oid ) == 0 )
+ || ( oc->oc_oid &&
+ strcasecmp( oc->oc_oid, ocname_or_oid ) == 0 )) {
+ return( oc );
+ }
+ }
+ } else {
+ const char *p;
+ size_t len;
+
+ /*
+ * Ignore trailing spaces when comparing object class names.
+ */
+ for ( p = ocname_or_oid, len = 0; (*p != '\0') && (*p != ' ');
+ p++, len++ ) {
+ ; /* NULL */
+ }
+
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
+ if ( ( (strncasecmp( oc->oc_name, ocname_or_oid, len ) == 0)
+ && (len == strlen(oc->oc_name)) )
+ ||
+ ( oc->oc_oid &&
+ ( strncasecmp( oc->oc_oid, ocname_or_oid, len ) == 0)
+ && (len == strlen(oc->oc_oid)) ) ) {
+ return( oc );
+ }
+ }
+ }
+ }
+
+ return( NULL );
+}
+
+/*
+ * oc_find_oid_nolock will return a pointer to the objectclass which has
+ * the same oid.
+ * NULL is returned if no match is found or `ocoid' is NULL.
+ */
+static struct objclass *
+oc_find_oid_nolock( const char *ocoid )
+{
+ struct objclass *oc;
+
+ if ( NULL != ocoid ) {
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
+ if ( ( oc->oc_oid &&
+ ( strcasecmp( oc->oc_oid, ocoid ) == 0)) ){
+ return( oc );
+ }
+ }
+ }
+
+ return( NULL );
+}
+
+
+/*
+ We need to keep the objectclasses in the same order as defined in the ldif files. If not
+ SUP dependencies will break. When the user redefines an existing objectclass this code
+ makes sure it is put back in the same order it was read to from the ldif file. It also
+ verifies that the entries oc_superior value preceeds it in the chain. If not it will not
+ allow the entry to be added. This makes sure that the ldif will be written back correctly.
+*/
+
+static int
+oc_replace_nolock(const char *ocname, struct objclass *newoc) {
+ struct objclass *oc, *pnext;
+ int rc = LDAP_SUCCESS;
+ PRBool saw_sup=PR_FALSE;
+
+ oc = g_get_global_oc_nolock();
+
+ if(newoc->oc_superior == NULL)
+ {
+ saw_sup=PR_TRUE;
+ }
+ /* don't check SUP dependency for first one because it always/should be top */
+ if (strcasecmp (oc->oc_name, ocname) == 0) {
+ newoc->oc_next=oc->oc_next;
+ g_set_global_oc_nolock ( newoc );
+ oc_free( &oc );
+ } else {
+ for (pnext = oc ; pnext != NULL;
+ oc = pnext, pnext = pnext->oc_next) {
+ if((pnext->oc_name != NULL) && (newoc->oc_superior != NULL)) {
+ if(strcasecmp( pnext->oc_name, newoc->oc_superior) == 0)
+ {
+ saw_sup=PR_TRUE;
+ }
+ }
+ if (strcasecmp ( pnext->oc_name, ocname ) == 0) {
+ if(saw_sup)
+ {
+ oc->oc_next=newoc;
+ newoc->oc_next=pnext->oc_next;
+ oc_free( &pnext );
+ break;
+
+ } else
+ {
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ break;
+ }
+
+ }
+ }
+ }
+ return rc;
+}
+
+
+static int
+oc_delete_nolock (char *ocname)
+{
+ struct objclass *oc, *pnext;
+ int rc = 0; /* failure */
+
+ oc = g_get_global_oc_nolock();
+
+ /* special case if we're removing the first oc */
+ if (strcasecmp (oc->oc_name, ocname) == 0) {
+ g_set_global_oc_nolock ( oc->oc_next );
+ oc_free( &oc );
+ rc = 1;
+ } else {
+ for (pnext = oc->oc_next ; pnext != NULL;
+ oc = pnext, pnext = pnext->oc_next) {
+ if (strcasecmp ( pnext->oc_name, ocname ) == 0) {
+ oc->oc_next = pnext->oc_next;
+ oc_free( &pnext );
+ rc = 1;
+ break;
+ }
+ }
+ }
+
+ return rc;
+}
+
+
+/*
+ * Compare two objectclass definitions for equality. Return PR_TRUE if
+ * they are equivalent and PR_FALSE if not.
+ *
+ * The oc_required and oc_allowed arrays are ignored.
+ * The string "user defined" is ignored within the origins array.
+ * The following flags are ignored:
+ * OC_FLAG_STANDARD_OC
+ * OC_FLAG_USER_OC
+ * OC_FLAG_REDEFINED_OC
+ */
+static PRBool
+oc_equal( struct objclass *oc1, struct objclass *oc2 )
+{
+ PRUint8 flagmask;
+
+ if ( schema_strcmp( oc1->oc_name, oc2->oc_name ) != 0
+ || schema_strcmp( oc1->oc_desc, oc2->oc_desc ) != 0
+ || schema_strcmp( oc1->oc_oid, oc2->oc_oid ) != 0
+ || schema_strcmp( oc1->oc_superior, oc2->oc_superior ) != 0 ) {
+ return PR_FALSE;
+ }
+
+ flagmask = ~(OC_FLAG_STANDARD_OC | OC_FLAG_USER_OC | OC_FLAG_REDEFINED_OC);
+ if ( oc1->oc_kind != oc2->oc_kind
+ || ( oc1->oc_flags & flagmask ) != ( oc2->oc_flags & flagmask )) {
+ return PR_FALSE;
+ }
+
+ if ( schema_strcmp_array( oc1->oc_orig_required, oc2->oc_orig_required,
+ NULL ) != 0
+ || schema_strcmp_array( oc1->oc_orig_allowed, oc2->oc_orig_allowed,
+ NULL ) != 0
+ || schema_strcmp_array( oc1->oc_origin, oc2->oc_origin,
+ schema_user_defined_origin[0] ) != 0 ) {
+ return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+
+#ifdef OC_DEBUG
+
+static int
+oc_print( struct objclass *oc )
+{
+ int i;
+
+ printf( "object class %s\n", oc->oc_name );
+ if ( oc->oc_required != NULL ) {
+ printf( "\trequires %s", oc->oc_required[0] );
+ for ( i = 1; oc->oc_required[i] != NULL; i++ ) {
+ printf( ",%s", oc->oc_required[i] );
+ }
+ printf( "\n" );
+ }
+ if ( oc->oc_allowed != NULL ) {
+ printf( "\tallows %s", oc->oc_allowed[0] );
+ for ( i = 1; oc->oc_allowed[i] != NULL; i++ ) {
+ printf( ",%s", oc->oc_allowed[i] );
+ }
+ printf( "\n" );
+ }
+ return 0;
+}
+#endif
+
+
+/*
+ * Compare two attrsyntax definitions for equality. Return PR_TRUE if
+ * they are equivalent and PR_FALSE if not.
+ *
+ * The string "user defined" is ignored within the origins array.
+ * The following flags are ignored:
+ * SLAPI_ATTR_FLAG_STD_ATTR
+ * SLAPI_ATTR_FLAG_NOLOCKING
+ * SLAPI_ATTR_FLAG_OVERRIDE
+ */
+static PRBool
+attr_syntax_equal( struct asyntaxinfo *asi1, struct asyntaxinfo *asi2 )
+{
+ unsigned long flagmask;
+
+ flagmask = ~( SLAPI_ATTR_FLAG_STD_ATTR | SLAPI_ATTR_FLAG_NOLOCKING
+ | SLAPI_ATTR_FLAG_OVERRIDE );
+
+ if ( schema_strcmp( asi1->asi_oid, asi2->asi_oid ) != 0
+ || schema_strcmp( asi1->asi_name, asi2->asi_name ) != 0
+ || schema_strcmp( asi1->asi_desc, asi2->asi_desc ) != 0
+ || schema_strcmp( asi1->asi_superior, asi2->asi_superior ) != 0
+ || schema_strcmp( asi1->asi_mr_equality, asi2->asi_mr_equality )
+ != 0
+ || schema_strcmp( asi1->asi_mr_ordering, asi2->asi_mr_ordering )
+ != 0
+ || schema_strcmp( asi1->asi_mr_substring,
+ asi2->asi_mr_substring ) != 0 ) {
+ return PR_FALSE;
+ }
+
+ if ( schema_strcmp_array( asi1->asi_aliases, asi2->asi_aliases, NULL ) != 0
+ || schema_strcmp_array( asi1->asi_origin, asi2->asi_origin,
+ schema_user_defined_origin[0] ) != 0
+ || asi1->asi_plugin != asi2->asi_plugin
+ || ( asi1->asi_flags & flagmask ) !=
+ ( asi2->asi_flags & flagmask )
+ || asi1->asi_syntaxlength != asi2->asi_syntaxlength ) {
+ return PR_FALSE;
+ }
+
+ return PR_TRUE;
+}
+
+
+
+/*
+ * Like strcmp(), but a NULL string pointer is treated as equivalent to
+ * another NULL one and NULL is treated as "less than" all non-NULL values.
+ */
+static int
+schema_strcmp( const char *s1, const char *s2 )
+{
+ if ( s1 == NULL ) {
+ if ( s2 == NULL ) {
+ return 0; /* equal */
+ }
+ return -1; /* s1 < s2 */
+ }
+
+ if ( s2 == NULL ) {
+ return 1; /* s1 > s2 */
+ }
+
+ return strcmp( s1, s2 );
+}
+
+
+/*
+ * Invoke strcmp() on each string in an array. If one array has fewer elements
+ * than the other, it is treated as "less than" the other. Two NULL or
+ * empty arrays (or one NULL and one empty) are considered to be equivalent.
+ *
+ * If ignorestr is non-NULL, occurrences of that string are ignored.
+ */
+static int
+schema_strcmp_array( char **sa1, char **sa2, const char *ignorestr )
+{
+ int i1, i2, rc;
+
+ if ( sa1 == NULL || *sa1 == NULL ) {
+ if ( sa2 == NULL || *sa2 == NULL ) {
+ return 0; /* equal */
+ }
+ return -1; /* sa1 < sa2 */
+ }
+
+ if ( sa2 == NULL || *sa2 == NULL ) {
+ return 1; /* sa1 > sa2 */
+ }
+
+ rc = 0;
+ i1 = i2 = 0;
+ while ( sa1[i1] != NULL && sa2[i2] != NULL ) {
+ if ( NULL != ignorestr ) {
+ if ( 0 == strcmp( sa1[i1], ignorestr )) {
+ ++i1;
+ continue;
+ }
+ if ( 0 == strcmp( sa2[i2], ignorestr )) {
+ ++i2;
+ continue;
+ }
+ }
+ rc = strcmp( sa1[i1], sa2[i2] );
+ ++i1;
+ ++i2;
+ }
+
+ if ( rc == 0 ) { /* all matched so far */
+ /* get rid of trailing ignored strings (if any) */
+ if ( NULL != ignorestr ) {
+ if ( sa1[i1] != NULL && 0 == strcmp( sa1[i1], ignorestr )) {
+ ++i1;
+ }
+ if ( sa2[i2] != NULL && 0 == strcmp( sa2[i2], ignorestr )) {
+ ++i2;
+ }
+ }
+
+ /* check for differing array lengths */
+ if ( sa2[i2] != NULL ) {
+ rc = -1; /* sa1 < sa2 -- fewer elements */
+ } else if ( sa1[i1] != NULL ) {
+ rc = 1; /* sa1 > sa2 -- more elements */
+ }
+ }
+
+ return rc;
+}
+
+
+struct attr_enum_wrapper {
+ Slapi_Attr **attrs;
+ int enquote_sup_oc;
+ struct sizedbuffer *psbAttrTypes;
+ int user_defined_only;
+ int schema_ds4x_compat;
+};
+
+static int
+schema_attr_enum_callback(struct asyntaxinfo *asip, void *arg)
+{
+ struct attr_enum_wrapper *aew = (struct attr_enum_wrapper *)arg;
+ int aliaslen = 0;
+ struct berval val;
+ struct berval *vals[2] = {0, 0};
+ const char *attr_desc, *syntaxoid;
+ char *outp, syntaxlengthbuf[ 128 ];
+ int i;
+
+ vals[0] = &val;
+
+ if (!asip) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Error: no attribute types in schema_attr_enum_callback\n",
+ 0, 0, 0);
+ return ATTR_SYNTAX_ENUM_NEXT;
+ }
+
+ if (aew->user_defined_only &&
+ (asip->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR)) {
+ return ATTR_SYNTAX_ENUM_NEXT; /* not user defined */
+ }
+
+ if ( aew->schema_ds4x_compat ) {
+ attr_desc = ( asip->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR)
+ ? ATTR_STANDARD_STRING : ATTR_USERDEF_STRING;
+ } else {
+ attr_desc = asip->asi_desc;
+ }
+
+ if ( asip->asi_aliases != NULL ) {
+ for ( i = 0; asip->asi_aliases[i] != NULL; ++i ) {
+ aliaslen += strlen( asip->asi_aliases[i] );
+ }
+ }
+
+ syntaxoid = plugin_syntax2oid(asip->asi_plugin);
+
+ if ( !aew->schema_ds4x_compat &&
+ asip->asi_syntaxlength != SLAPI_SYNTAXLENGTH_NONE ) {
+ /* sprintf() is safe because syntaxlengthbuf is large enough */
+ sprintf( syntaxlengthbuf, "{%d}", asip->asi_syntaxlength );
+ } else {
+ *syntaxlengthbuf = '\0';
+ }
+
+ /*
+ * XXX: 256 is a magic number... it must be big enough to account for
+ * all of the fixed sized items we output.
+ */
+ sizedbuffer_allocate(aew->psbAttrTypes,256+strlen(asip->asi_oid)+
+ strlen(asip->asi_name) +
+ aliaslen + strlen_null_ok(attr_desc) +
+ strlen(syntaxoid) +
+ strlen_null_ok(asip->asi_superior) +
+ strlen_null_ok(asip->asi_mr_equality) +
+ strlen_null_ok(asip->asi_mr_ordering) +
+ strlen_null_ok(asip->asi_mr_substring) +
+ strcat_qdlist( NULL, "X-ORIGIN", asip->asi_origin ));
+
+ /*
+ * Overall strategy is to maintain a pointer to the next location in
+ * the output buffer so we can do simple strcpy's, sprintf's, etc.
+ * That pointer is `outp'. Each item that is output includes a trailing
+ * space, so there is no need to include a leading one in the next item.
+ */
+ outp = aew->psbAttrTypes->buffer;
+ outp += sprintf(outp, "( %s NAME ", asip->asi_oid);
+ if ( asip->asi_aliases == NULL || asip->asi_aliases[0] == NULL ) {
+ /* only one name */
+ outp += sprintf(outp, "'%s' ", asip->asi_name);
+ } else {
+ /* several names */
+ outp += sprintf(outp, "( '%s' ", asip->asi_name);
+ for ( i = 0; asip->asi_aliases[i] != NULL; ++i ) {
+ outp += sprintf(outp, "'%s' ", asip->asi_aliases[i]);
+ }
+ outp += strcpy_count(outp, ") ");
+ }
+
+ /* DESC is optional */
+ if (attr_desc && *attr_desc) {
+ outp += sprintf( outp, "DESC '%s'", attr_desc );
+ }
+ if ( !aew->schema_ds4x_compat &&
+ ( asip->asi_flags & SLAPI_ATTR_FLAG_OBSOLETE )) {
+ outp += strcpy_count( outp, schema_obsolete_with_spaces );
+ } else {
+ outp += strcpy_count( outp, " " );
+ }
+
+ if ( !aew->schema_ds4x_compat ) {
+ outp += put_tagged_oid( outp, "SUP ",
+ asip->asi_superior, NULL, aew->enquote_sup_oc );
+ outp += put_tagged_oid( outp, "EQUALITY ",
+ asip->asi_mr_equality, NULL, aew->enquote_sup_oc );
+ outp += put_tagged_oid( outp, "ORDERING ",
+ asip->asi_mr_ordering, NULL, aew->enquote_sup_oc );
+ outp += put_tagged_oid( outp, "SUBSTR ",
+ asip->asi_mr_substring, NULL, aew->enquote_sup_oc );
+ }
+
+ outp += put_tagged_oid( outp, "SYNTAX ", syntaxoid, syntaxlengthbuf,
+ aew->enquote_sup_oc );
+
+ if (asip->asi_flags & SLAPI_ATTR_FLAG_SINGLE) {
+ outp += strcpy_count(outp, "SINGLE-VALUE ");
+ }
+ if ( !aew->schema_ds4x_compat ) {
+ if (asip->asi_flags & SLAPI_ATTR_FLAG_COLLECTIVE ) {
+ outp += strcpy_count( outp, 1 + schema_collective_with_spaces );
+ }
+ if (asip->asi_flags & SLAPI_ATTR_FLAG_NOUSERMOD ) {
+ outp += strcpy_count( outp, 1 + schema_nousermod_with_spaces );
+ }
+ if (asip->asi_flags & SLAPI_ATTR_FLAG_OPATTR) {
+ outp += strcpy_count(outp, "USAGE directoryOperation ");
+ }
+
+ outp += strcat_qdlist( outp, "X-ORIGIN", asip->asi_origin );
+ }
+
+ outp += strcpy_count(outp, ")");
+
+ val.bv_val = aew->psbAttrTypes->buffer;
+ val.bv_len = outp - aew->psbAttrTypes->buffer;
+ attrlist_merge(aew->attrs, "attributetypes", vals);
+
+ return ATTR_SYNTAX_ENUM_NEXT;
+}
+
+
+struct syntax_enum_wrapper {
+ Slapi_Attr **attrs;
+ struct sizedbuffer *psbSyntaxDescription;
+};
+
+static int
+schema_syntax_enum_callback(char **names, Slapi_PluginDesc *plugindesc,
+ void *arg)
+{
+ struct syntax_enum_wrapper *sew = (struct syntax_enum_wrapper *)arg;
+ char *oid, *desc;
+ int i;
+ struct berval val;
+ struct berval *vals[2] = {0, 0};
+ vals[0] = &val;
+
+ oid = NULL;
+ if ( names != NULL ) {
+ for ( i = 0; names[i] != NULL; ++i ) {
+ if ( isdigit( names[i][0] )) {
+ oid = names[i];
+ break;
+ }
+ }
+ }
+
+ if ( oid == NULL ) { /* must have an OID */
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: no OID found in"
+ " schema_syntax_enum_callback for syntax %s\n",
+ ( names == NULL ) ? "unknown" : names[0], 0, 0);
+ return 1;
+ }
+
+ desc = names[0]; /* by convention, the first name is the "official" one */
+
+ /*
+ * RFC 2252 section 4.3.3 Syntax Description says:
+ *
+ * The following BNF may be used to associate a short description with a
+ * syntax OBJECT IDENTIFIER. Implementors should note that future
+ * versions of this document may expand this definition to include
+ * additional terms. Terms whose identifier begins with "X-" are
+ * reserved for private experiments, and MUST be followed by a
+ * <qdstrings>.
+ *
+ * SyntaxDescription = "(" whsp
+ * numericoid whsp
+ * [ "DESC" qdstring ]
+ * whsp ")"
+ *
+ * And section 5.3.1 ldapSyntaxes says:
+ *
+ * Servers MAY use this attribute to list the syntaxes which are
+ * implemented. Each value corresponds to one syntax.
+ *
+ * ( 1.3.6.1.4.1.1466.101.120.16 NAME 'ldapSyntaxes'
+ * EQUALITY objectIdentifierFirstComponentMatch
+ * SYNTAX 1.3.6.1.4.1.1466.115.121.1.54 USAGE directoryOperation )
+ */
+ if ( desc == NULL ) {
+ /* allocate enough room for "( )" and '\0' at end */
+ sizedbuffer_allocate(sew->psbSyntaxDescription, strlen(oid) + 5);
+ sprintf(sew->psbSyntaxDescription->buffer, "( %s )", oid );
+ } else {
+ /* allocate enough room for "( ) DESC '' " and '\0' at end */
+ sizedbuffer_allocate(sew->psbSyntaxDescription,
+ strlen(oid) + strlen(desc) + 13);
+ sprintf(sew->psbSyntaxDescription->buffer, "( %s DESC '%s' )",
+ oid, desc );
+ }
+
+ val.bv_val = sew->psbSyntaxDescription->buffer;
+ val.bv_len = strlen(sew->psbSyntaxDescription->buffer);
+ attrlist_merge(sew->attrs, "ldapSyntaxes", vals);
+
+ return 1;
+}
+
+struct listargs{
+ char **attrs;
+ unsigned long flag;
+};
+
+static int
+schema_list_attributes_callback(struct asyntaxinfo *asi, void *arg)
+{
+ struct listargs *aew = (struct listargs *)arg;
+
+ if (!asi) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: no attribute types in schema_list_attributes_callback\n",
+ 0, 0, 0);
+ return ATTR_SYNTAX_ENUM_NEXT;
+ }
+ if (aew->flag && (asi->asi_flags & aew->flag)) {
+ charray_add(&aew->attrs, slapi_ch_strdup(asi->asi_name));
+ if (NULL != asi->asi_aliases) {
+ int i;
+
+ for ( i = 0; asi->asi_aliases[i] != NULL; ++i ) {
+ charray_add(&aew->attrs,
+ slapi_ch_strdup(asi->asi_aliases[i]));
+ }
+ }
+ }
+ return ATTR_SYNTAX_ENUM_NEXT;
+}
+
+/* Return the list of attributes names matching attribute flags */
+
+char ** slapi_schema_list_attribute_names(unsigned long flag)
+{
+ struct listargs aew;
+ memset(&aew,0,sizeof(struct listargs));
+ aew.flag=flag;
+
+ attr_syntax_enumerate_attrs(schema_list_attributes_callback, &aew,
+ PR_FALSE);
+ return aew.attrs;
+}
+
+
+/*
+ * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
+ */
+int
+read_schema_dse(
+ Slapi_PBlock *pb,
+ Slapi_Entry *pschema_info_e,
+ Slapi_Entry *entryAfter,
+ int *returncode,
+ char *returntext /* not used */,
+ void *arg /* not used */ )
+{
+ struct berval val;
+ struct berval *vals[2];
+ int i;
+ struct objclass *oc;
+ struct matchingRuleList *mrl=NULL;
+ struct sizedbuffer *psbObjectClasses= sizedbuffer_construct(BUFSIZ);
+ struct sizedbuffer *psbAttrTypes= sizedbuffer_construct(BUFSIZ);
+ struct sizedbuffer *psbMatchingRule= sizedbuffer_construct(BUFSIZ);
+ struct sizedbuffer *psbSyntaxDescription = sizedbuffer_construct(BUFSIZ);
+ struct attr_enum_wrapper aew;
+ struct syntax_enum_wrapper sew;
+ int enquote_sup_oc = config_get_enquote_sup_oc();
+ int user_defined_only = 0;
+ char **allowed, **required;
+ char *mr_desc, *mr_name, *oc_description;
+ int schema_ds4x_compat = config_get_ds4_compatible_schema();
+ const CSN *csn;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ slapi_pblock_get(pb, SLAPI_SCHEMA_USER_DEFINED_ONLY, (void*)&user_defined_only);
+
+ attrlist_delete (&pschema_info_e->e_attrs, "objectclasses");
+ attrlist_delete (&pschema_info_e->e_attrs, "attributetypes");
+ attrlist_delete (&pschema_info_e->e_attrs, "matchingRules");
+ attrlist_delete (&pschema_info_e->e_attrs, "ldapSyntaxes");
+ /*
+ attrlist_delete (&pschema_info_e->e_attrs, "matchingRuleUse");
+ */
+
+ schema_dse_lock_read();
+
+ /* return the objectclasses */
+ oc_lock_read();
+ for (oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next)
+ {
+ size_t size= 0;
+ int need_extra_space = 1;
+
+ if (user_defined_only &&
+ !(oc->oc_flags & OC_FLAG_USER_OC ||
+ oc->oc_flags & OC_FLAG_REDEFINED_OC)) {
+ continue;
+ }
+
+ /*
+ * XXX: 256 is a magic number... it must be large enough to fit
+ * all of the fixed size items including description (DESC),
+ * kind (STRUCTURAL, AUXILIARY, or ABSTRACT), and the OBSOLETE flag.
+ */
+ if ( schema_ds4x_compat ) {
+ oc_description = (oc->oc_flags & OC_FLAG_STANDARD_OC) ?
+ OC_STANDARD_STRING : OC_USERDEF_STRING;
+ } else {
+ oc_description = oc->oc_desc;
+ }
+
+ size= 256+strlen_null_ok(oc->oc_oid) + strlen(oc->oc_name) +
+ strlen_null_ok(oc_description) +
+ strcat_qdlist( NULL, "X-ORIGIN", oc->oc_origin );
+ required = schema_ds4x_compat ? oc->oc_required : oc->oc_orig_required;
+ if (required && required[0]) {
+ for (i = 0 ; required[i]; i++)
+ size+= 16 + strlen(required[i]);
+ }
+ allowed = schema_ds4x_compat ? oc->oc_allowed : oc->oc_orig_allowed;
+ if (allowed && allowed[0]) {
+ for (i = 0 ; allowed[i]; i++)
+ size+= 16 + strlen(allowed[i]);
+ }
+ sizedbuffer_allocate(psbObjectClasses,size);
+ /* put the OID and the NAME */
+ sprintf (psbObjectClasses->buffer,
+ "( %s NAME '%s'",
+ (oc->oc_oid) ? oc->oc_oid : "",
+ oc->oc_name);
+ /* The DESC (description) is OPTIONAL */
+ if (oc_description && *oc_description) {
+ strcat(psbObjectClasses->buffer, " DESC '");
+ strcat(psbObjectClasses->buffer, oc_description);
+ strcat(psbObjectClasses->buffer, "'");
+ need_extra_space = 1;
+ }
+ /* put the OBSOLETE keyword */
+ if (!schema_ds4x_compat && (oc->oc_flags & OC_FLAG_OBSOLETE)) {
+ strcat(psbObjectClasses->buffer, schema_obsolete_with_spaces);
+ need_extra_space = 0;
+ }
+ /* put the SUP superior objectclass */
+ if (0 != strcasecmp(oc->oc_name, "top")) { /* top has no SUP */
+ /* some AUXILIARY AND ABSTRACT objectclasses may not have a SUP either */
+ /* for compatability, every objectclass other than top must have a SUP */
+ if (schema_ds4x_compat || (oc->oc_superior && *oc->oc_superior)) {
+ if (need_extra_space) {
+ strcat(psbObjectClasses->buffer, " ");
+ }
+ strcat(psbObjectClasses->buffer, "SUP ");
+ strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : ""));
+ strcat(psbObjectClasses->buffer,
+ ((oc->oc_superior && *oc->oc_superior) ?
+ oc->oc_superior : "top"));
+ strcat(psbObjectClasses->buffer, (enquote_sup_oc ? "'" : ""));
+ need_extra_space = 1;
+ }
+ }
+ /* put the kind of objectclass */
+ if (schema_ds4x_compat) {
+ if (need_extra_space) {
+ strcat(psbObjectClasses->buffer, " ");
+ }
+ } else {
+ strcat(psbObjectClasses->buffer, schema_oc_kind_strings_with_spaces[oc->oc_kind]);
+ }
+
+ strcat_oids( psbObjectClasses->buffer, "MUST", required,
+ schema_ds4x_compat );
+ strcat_oids( psbObjectClasses->buffer, "MAY", allowed,
+ schema_ds4x_compat );
+ if ( !schema_ds4x_compat ) {
+ strcat_qdlist( psbObjectClasses->buffer, "X-ORIGIN", oc->oc_origin );
+ }
+ strcat( psbObjectClasses->buffer, ")");
+
+ val.bv_val = psbObjectClasses->buffer;
+ val.bv_len = strlen (psbObjectClasses->buffer);
+ attrlist_merge (&pschema_info_e->e_attrs, "objectclasses", vals);
+ }
+ oc_unlock();
+
+ /* now return the attrs */
+
+ aew.attrs = &pschema_info_e->e_attrs;
+ aew.enquote_sup_oc = enquote_sup_oc;
+ aew.psbAttrTypes = psbAttrTypes;
+ aew.user_defined_only = user_defined_only;
+ aew.schema_ds4x_compat = schema_ds4x_compat;
+ attr_syntax_enumerate_attrs(schema_attr_enum_callback, &aew, PR_FALSE);
+
+ /* return the set of matching rules we support */
+ for (mrl = g_get_global_mrl(); !user_defined_only && mrl != NULL; mrl = mrl->mrl_next) {
+ mr_name = mrl->mr_entry->mr_name ? mrl->mr_entry->mr_name : "";
+ mr_desc = mrl->mr_entry->mr_desc ? mrl->mr_entry->mr_desc : "";
+ sizedbuffer_allocate(psbMatchingRule,128+
+ strlen_null_ok(mrl->mr_entry->mr_oid) +
+ strlen(mr_name)+ strlen(mr_desc)+
+ strlen_null_ok(mrl->mr_entry->mr_syntax));
+ if ( schema_ds4x_compat ) {
+ sprintf(psbMatchingRule->buffer,
+ "( %s NAME '%s' DESC '%s' SYNTAX %s%s%s )",
+ (mrl->mr_entry->mr_oid ? mrl->mr_entry->mr_oid : ""),
+ mr_name, mr_desc,
+ enquote_sup_oc ? "'" : "",
+ mrl->mr_entry->mr_syntax ? mrl->mr_entry->mr_syntax : "" ,
+ enquote_sup_oc ? "'" : "");
+ } else if ( NULL != mrl->mr_entry->mr_oid &&
+ NULL != mrl->mr_entry->mr_syntax ) {
+ char *p;
+
+ sprintf(psbMatchingRule->buffer, "( %s ", mrl->mr_entry->mr_oid );
+ p = psbMatchingRule->buffer + strlen(psbMatchingRule->buffer);
+ if ( *mr_name != '\0' ) {
+ sprintf(p, "NAME '%s' ", mr_name );
+ p += strlen(p);
+ }
+
+ if ( *mr_desc != '\0' ) {
+ sprintf(p, "DESC '%s' ", mr_desc );
+ p += strlen(p);
+ }
+ sprintf(p, "SYNTAX %s )", mrl->mr_entry->mr_syntax );
+ }
+
+ val.bv_val = psbMatchingRule->buffer;
+ val.bv_len = strlen (psbMatchingRule->buffer);
+ attrlist_merge (&pschema_info_e->e_attrs, "matchingRules", vals);
+ }
+
+ if ( !schema_ds4x_compat && !user_defined_only ) {
+ /* return the set of syntaxes we support */
+ sew.attrs = &pschema_info_e->e_attrs;
+ sew.psbSyntaxDescription = psbSyntaxDescription;
+ plugin_syntax_enumerate(schema_syntax_enum_callback, &sew);
+ }
+
+ csn = g_get_global_schema_csn();
+ if (NULL != csn) {
+ char csn_str[CSN_STRSIZE + 1];
+ csn_as_string(csn, PR_FALSE, csn_str);
+ slapi_entry_attr_delete(pschema_info_e, "nsschemacsn");
+ slapi_entry_add_string(pschema_info_e, "nsschemacsn", csn_str);
+ }
+
+ schema_dse_unlock();
+
+ sizedbuffer_destroy(psbObjectClasses);
+ sizedbuffer_destroy(psbAttrTypes);
+ sizedbuffer_destroy(psbMatchingRule);
+ sizedbuffer_destroy(psbSyntaxDescription);
+ *returncode= LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+/* helper for deleting mods (we do not want to be applied) from the mods array */
+static void
+mod_free(LDAPMod *mod)
+{
+ ber_bvecfree(mod->mod_bvalues);
+ slapi_ch_free((void**)&(mod->mod_type));
+ slapi_ch_free((void**)&mod);
+}
+
+/*
+ * modify_schema_dse: called by do_modify() when target is cn=schema
+ *
+ * Add/Delete attributes and objectclasses from the schema
+ * Supported mod_ops are LDAP_MOD_DELETE and LDAP_MOD_ADD
+ *
+ * Note that the in-memory DSE Slapi_Entry object does NOT hold the
+ * attributeTypes and objectClasses attributes -- it only holds
+ * non-schema related attributes such as aci.
+ *
+ * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
+ */
+int
+modify_schema_dse (Slapi_PBlock *pb, Slapi_Entry *entryBefore, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg)
+{
+ int i, rc= SLAPI_DSE_CALLBACK_OK; /* default is to apply changes to the DSE */
+ char *schema_dse_attr_name;
+ LDAPMod **mods = NULL;
+ int num_mods = 0; /* count the number of mods */
+ int schema_ds4x_compat = config_get_ds4_compatible_schema();
+ int reapply_mods = 0;
+ int is_replicated_operation = 0;
+
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods );
+ slapi_pblock_get( pb, SLAPI_IS_REPLICATED_OPERATION, &is_replicated_operation);
+ schema_dse_lock_write();
+
+ /*
+ * Process each modification. Stop as soon as we hit an error.
+ *
+ * XXXmcs: known bugs: we don't operate on a copy of the schema, so it
+ * is possible for some schema changes to be made but not all of them.
+ * True for DS 4.x as well, although it tried to keep going even after
+ * an error was detected (which was very wrong).
+ */
+ for (i = 0; rc == SLAPI_DSE_CALLBACK_OK && mods[i]; i++) {
+ schema_dse_attr_name = (char *) mods[i]->mod_type;
+ num_mods++; /* incr the number of mods */
+
+ /*
+ * skip attribute types that we do not recognize (the DSE code will
+ * handle them).
+ */
+ if ( !schema_type_is_interesting( schema_dse_attr_name )) {
+ continue;
+ }
+
+ /*
+ * Delete an objectclass or attribute
+ */
+ if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_DELETE) {
+ if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
+ *returncode = schema_delete_objectclasses (entryBefore, mods[i],
+ returntext, SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat );
+ }
+ else if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
+ *returncode = schema_delete_attributes (entryBefore, mods[i],
+ returntext, SLAPI_DSE_RETURNTEXT_SIZE );
+ }
+ else {
+ *returncode= LDAP_NO_SUCH_ATTRIBUTE;
+ schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ schema_errprefix_generic, mods[i]->mod_type,
+ "Only object classes and attribute types may be deleted" );
+ }
+
+ if ( LDAP_SUCCESS != *returncode ) {
+ rc= SLAPI_DSE_CALLBACK_ERROR;
+ } else {
+ reapply_mods = 1;
+ }
+ }
+
+ /*
+ * Replace an objectclass,attribute, or schema CSN
+ */
+ else if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_REPLACE) {
+ int replace_allowed = 0;
+ slapdFrontendConfig_t *slapdFrontendConfig;
+
+ slapdFrontendConfig = getFrontendConfig();
+ CFG_LOCK_READ( slapdFrontendConfig );
+ if ( 0 == strcasecmp( slapdFrontendConfig->schemareplace,
+ CONFIG_SCHEMAREPLACE_STR_ON )) {
+ replace_allowed = 1;
+ } else if ( 0 == strcasecmp( slapdFrontendConfig->schemareplace,
+ CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY )) {
+ replace_allowed = is_replicated_operation;
+ }
+ CFG_UNLOCK_READ( slapdFrontendConfig );
+
+ if ( !replace_allowed ) {
+ *returncode= LDAP_UNWILLING_TO_PERFORM;
+ schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ schema_errprefix_generic, mods[i]->mod_type,
+ "Replace is not allowed on the subschema subentry" );
+ rc = SLAPI_DSE_CALLBACK_ERROR;
+ } else {
+ if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
+ /*
+ * Replace all attribute types
+ */
+ *returncode = schema_replace_attributes( pb, mods[i], returntext,
+ SLAPI_DSE_RETURNTEXT_SIZE );
+ } else if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
+ /*
+ * Replace all objectclasses
+ */
+ *returncode = schema_replace_objectclasses( pb, mods[i],
+ returntext, SLAPI_DSE_RETURNTEXT_SIZE );
+ } else if (strcasecmp (mods[i]->mod_type, "nsschemacsn") == 0) {
+ if (is_replicated_operation) {
+ /* Update the schema CSN */
+ if (mods[i]->mod_bvalues && mods[i]->mod_bvalues[0] &&
+ mods[i]->mod_bvalues[0]->bv_val &&
+ mods[i]->mod_bvalues[0]->bv_len > 0) {
+ char new_csn_string[CSN_STRSIZE + 1];
+ CSN *new_schema_csn;
+ memcpy(new_csn_string, mods[i]->mod_bvalues[0]->bv_val,
+ mods[i]->mod_bvalues[0]->bv_len);
+ new_csn_string[mods[i]->mod_bvalues[0]->bv_len] = '\0';
+ new_schema_csn = csn_new_by_string(new_csn_string);
+ if (NULL != new_schema_csn) {
+ g_set_global_schema_csn(new_schema_csn); /* csn is consumed */
+ }
+ }
+ }
+ } else {
+ *returncode= LDAP_UNWILLING_TO_PERFORM; /* XXXmcs: best error? */
+ schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ schema_errprefix_generic, mods[i]->mod_type,
+ "Only object classes and attribute types may be replaced" );
+ }
+ }
+
+ if ( LDAP_SUCCESS != *returncode ) {
+ rc= SLAPI_DSE_CALLBACK_ERROR;
+ } else {
+ reapply_mods = 1; /* we have at least some modifications we need to reapply */
+ }
+ }
+
+
+ /*
+ * Add an objectclass or attribute
+ */
+ else if ( (mods[i]->mod_op & ~LDAP_MOD_BVALUES) == LDAP_MOD_ADD) {
+ if (strcasecmp (mods[i]->mod_type, "attributetypes") == 0) {
+ /*
+ * Add a new attribute
+ */
+ *returncode = schema_add_attribute ( pb, mods[i], returntext,
+ SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat );
+ }
+ else if (strcasecmp (mods[i]->mod_type, "objectclasses") == 0) {
+ /*
+ * Add a new objectclass
+ */
+ *returncode = schema_add_objectclass ( pb, mods[i], returntext,
+ SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat );
+ }
+ else {
+ if ( schema_ds4x_compat ) {
+ *returncode= LDAP_NO_SUCH_ATTRIBUTE;
+ } else {
+ *returncode= LDAP_UNWILLING_TO_PERFORM; /* XXXmcs: best error? */
+ }
+ schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ schema_errprefix_generic, mods[i]->mod_type,
+ "Only object classes and attribute types may be added" );
+ }
+
+ if ( LDAP_SUCCESS != *returncode ) {
+ rc= SLAPI_DSE_CALLBACK_ERROR;
+ } else {
+ reapply_mods = 1; /* we have at least some modifications we need to reapply */
+ }
+ }
+
+ /*
+ ** No value was specified to modify, the user probably tried
+ ** to delete all attributetypes or all objectclasses, which
+ ** isn't allowed
+ */
+ if (!mods[i]->mod_vals.modv_strvals)
+ {
+ if ( schema_ds4x_compat ) {
+ *returncode= LDAP_INVALID_SYNTAX;
+ } else {
+ *returncode= LDAP_UNWILLING_TO_PERFORM; /* XXXmcs: best error? */
+ }
+ schema_create_errormsg( returntext, SLAPI_DSE_RETURNTEXT_SIZE,
+ schema_errprefix_generic, mods[i]->mod_type,
+ "No target attribute type or object class specified" );
+ rc= SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+
+ if(rc==SLAPI_DSE_CALLBACK_OK && reapply_mods)
+ {
+ CSN *new_schema_csn;
+ int newindex = 0; /* mods array index */
+
+ /* tell the "unholy" dse_modify code to reapply the mods and use
+ that result instead of the initial result; we must remove the attributes
+ we manage in this code from the mods
+ */
+ slapi_pblock_set(pb, SLAPI_DSE_REAPPLY_MODS, (void *)&reapply_mods);
+
+ /* because we are reapplying the mods, we want the entryAfter to
+ look just like the entryBefore, except that "our" attributes
+ will have been removed
+ */
+ /* delete the mods from the mods array */
+ for (i = 0; i < num_mods ; i++) {
+ const char *attrname = mods[i]->mod_type;
+
+ /* delete this attr from the entry */
+ slapi_entry_attr_delete(entryAfter, attrname);
+
+ if ( schema_type_is_interesting( attrname )) {
+ mod_free(mods[i]);
+ mods[i] = NULL;
+ } else {
+ /* add the original value of the attr back to the entry after */
+ Slapi_Attr *origattr = NULL;
+ Slapi_ValueSet *origvalues = NULL;
+ slapi_entry_attr_find(entryBefore, attrname, &origattr);
+ if (NULL != origattr) {
+ slapi_attr_get_valueset(origattr, &origvalues);
+ if (NULL != origvalues) {
+ slapi_entry_add_valueset(entryAfter, attrname, origvalues);
+ slapi_valueset_free(origvalues);
+ }
+ }
+ mods[newindex++] = mods[i];
+ }
+ }
+ mods[newindex] = NULL;
+
+ /*
+ * Since we successfully updated the schema, we need to generate
+ * a new schema CSN for non-replicated operations.
+ */
+ /* XXXmcs: I wonder if we should update the schema CSN even when no
+ * attribute types or OCs were changed? That way, an administrator
+ * could force schema replication to occur by submitting a modify
+ * operation that did not really do anything, such as:
+ *
+ * dn:cn=schema
+ * changetype:modify
+ * replace:cn
+ * cn:schema
+ */
+ if (!is_replicated_operation)
+ {
+ new_schema_csn = csn_new();
+ if (NULL != new_schema_csn) {
+ char csn_str[CSN_STRSIZE + 1];
+ csn_set_replicaid(new_schema_csn, 0);
+ csn_set_time(new_schema_csn, current_time());
+ g_set_global_schema_csn(new_schema_csn);
+ slapi_entry_attr_delete(entryBefore, "nsschemacsn");
+ csn_as_string(new_schema_csn, PR_FALSE, csn_str);
+ slapi_entry_add_string(entryBefore, "nsschemacsn", csn_str);
+ }
+ }
+ }
+
+ schema_dse_unlock();
+
+ return rc;
+}
+
+CSN *
+dup_global_schema_csn()
+{
+ CSN *schema_csn;
+
+ schema_dse_lock_read();
+ schema_csn = csn_dup ( g_get_global_schema_csn() );
+ schema_dse_unlock();
+ return schema_csn;
+}
+
+/*
+ * Remove all attribute types and objectclasses from the entry and
+ * then add back the user defined ones based on the contents of the
+ * schema hash tables.
+ *
+ * Returns SLAPI_DSE_CALLBACK_OK is all goes well.
+ *
+ * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
+ */
+static int
+refresh_user_defined_schema( Slapi_PBlock *pb, Slapi_Entry *pschema_info_e, Slapi_Entry *entryAfter, int *returncode, char *returntext, void *arg /* not used */ )
+{
+ int user_defined_only = 1;
+ int rc;
+ Slapi_PBlock *mypbptr = pb;
+ Slapi_PBlock mypb;
+ const CSN *schema_csn;
+
+ pblock_init(&mypb);
+
+ slapi_entry_attr_delete( pschema_info_e, "objectclasses");
+ slapi_entry_attr_delete( pschema_info_e, "attributetypes");
+
+ /* for write callbacks, no pb is supplied, so use our own */
+ if (!mypbptr) {
+ mypbptr = &mypb;
+ }
+
+ slapi_pblock_set(mypbptr, SLAPI_SCHEMA_USER_DEFINED_ONLY, &user_defined_only);
+ rc = read_schema_dse(mypbptr, pschema_info_e, NULL, returncode, returntext, NULL);
+ schema_csn = g_get_global_schema_csn();
+ if (NULL != schema_csn) {
+ char csn_str[CSN_STRSIZE + 1];
+ slapi_entry_attr_delete(pschema_info_e, "nsschemacsn");
+ csn_as_string(schema_csn, PR_FALSE, csn_str);
+ slapi_entry_add_string(pschema_info_e, "nsschemacsn", csn_str);
+ }
+ pblock_done(&mypb);
+
+ return rc;
+}
+
+
+/* oc_add_nolock
+ * Add the objectClass newoc to the global list of objectclasses
+ */
+static void
+oc_add_nolock(struct objclass *newoc)
+{
+ struct objclass *poc;
+
+ poc = g_get_global_oc_nolock();
+
+ if ( NULL == poc ) {
+ g_set_global_oc_nolock(newoc);
+ } else {
+ for ( ; (poc != NULL) && (poc->oc_next != NULL); poc = poc->oc_next) {
+ ;
+ }
+ poc->oc_next = newoc;
+ newoc->oc_next = NULL;
+ }
+}
+
+
+static char **read_dollar_values ( char *vals) {
+ int i,k;
+ char **retVal;
+ static const char *charsToRemove = " ()";
+
+ /* get rid of all the parens and spaces */
+ for ( i = 0, k = 0; vals[i]; i++) {
+ if (!strchr(charsToRemove, vals[i])) {
+ vals[k++] = vals[i];
+ }
+ }
+ vals[k] = '\0';
+ retVal = str2charray (vals, "$");
+ return retVal;
+}
+
+/*
+ * Delete one or more objectClasses from our internal data structure.
+ *
+ * Return an LDAP error code (LDAP_SUCCESS if all goes well).
+ * If an error occurs, explanatory text is copied into 'errorbuf'.
+ *
+ * This function should not send an LDAP result; that is the caller's
+ * responsibility.
+ */
+static int
+schema_delete_objectclasses( Slapi_Entry *entryBefore, LDAPMod *mod,
+ char *errorbuf, size_t errorbufsize, int schema_ds4x_compat )
+{
+ int i;
+ int rc = LDAP_SUCCESS; /* optimistic */
+ struct objclass *poc, *poc2, *delete_oc = NULL;
+
+ if ( NULL == mod->mod_bvalues ) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ NULL, "Cannot remove all schema object classes" );
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ for (i = 0; mod->mod_bvalues[i]; i++) {
+ if ( LDAP_SUCCESS != ( rc = read_oc_ldif (
+ (const char *)mod->mod_bvalues[i]->bv_val, &delete_oc,
+ errorbuf, errorbufsize, 0, 0, schema_ds4x_compat))) {
+ return rc;
+ }
+
+ oc_lock_write();
+
+ if ((poc = oc_find_nolock(delete_oc->oc_name)) != NULL) {
+
+ /* check to see if any objectclasses inherit from this oc */
+ for (poc2 = g_get_global_oc_nolock(); poc2 != NULL; poc2 = poc2->oc_next) {
+ if (poc2->oc_superior &&
+ (strcasecmp (poc2->oc_superior, delete_oc->oc_name) == 0)) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ delete_oc->oc_name, "Cannot delete an object class"
+ " which has child object classes" );
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ goto unlock_and_return;
+ }
+ }
+
+ if ( (poc->oc_flags & OC_FLAG_STANDARD_OC) == 0) {
+ oc_delete_nolock (poc->oc_name);
+ }
+
+ else {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ delete_oc->oc_name, "Cannot delete a standard object class" );
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ goto unlock_and_return;
+ }
+ }
+ else {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ delete_oc->oc_name, "Is unknown. Cannot delete." );
+ rc = schema_ds4x_compat ? LDAP_NO_SUCH_OBJECT : LDAP_NO_SUCH_ATTRIBUTE;
+ goto unlock_and_return;
+ }
+
+ oc_free( &delete_oc );
+ oc_unlock();
+ }
+
+ return rc;
+
+unlock_and_return:
+ oc_free( &delete_oc );
+ oc_unlock();
+ return rc;
+}
+
+
+static int
+schema_return(int rc,struct sizedbuffer * psb1,struct sizedbuffer *psb2,struct sizedbuffer *psb3,struct sizedbuffer *psb4)
+{
+ sizedbuffer_destroy(psb1);
+ sizedbuffer_destroy(psb2);
+ sizedbuffer_destroy(psb3);
+ sizedbuffer_destroy(psb4);
+ return rc;
+}
+
+/*
+ * Delete one or more attributeTypes from our internal data structure.
+ *
+ * Return an LDAP error code (LDAP_SUCCESS if all goes well).
+ * If an error occurs, explanatory text is copied into 'errorbuf'.
+ *
+ * This function should not send an LDAP result; that is the caller's
+ * responsibility.
+ */
+static int
+schema_delete_attributes ( Slapi_Entry *entryBefore, LDAPMod *mod,
+ char *errorbuf, size_t errorbufsize)
+{
+ char *attr_ldif, *oc_list_type = "";
+ asyntaxinfo *a;
+ struct objclass *oc = NULL;
+ int i, k, attr_in_use_by_an_oc = 0;
+ struct sizedbuffer *psbAttrName= sizedbuffer_construct(BUFSIZ);
+ struct sizedbuffer *psbAttrOid= sizedbuffer_construct(BUFSIZ);
+ struct sizedbuffer *psbAttrSyntax= sizedbuffer_construct(BUFSIZ);
+
+ if (NULL == mod->mod_bvalues) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ NULL, "Cannot remove all schema attribute types" );
+ return schema_return(LDAP_UNWILLING_TO_PERFORM,psbAttrOid,psbAttrName,
+ psbAttrSyntax,NULL);
+ }
+
+ for (i = 0; mod->mod_bvalues[i]; i++) {
+ attr_ldif =(char *) mod->mod_bvalues[i]->bv_val;
+
+ /* normalize the attr ldif */
+ for ( k = 0; attr_ldif[k]; k++) {
+ if (attr_ldif[k] == '\'' ||
+ attr_ldif[k] == '(' ||
+ attr_ldif[k] == ')' ) {
+ attr_ldif[k] = ' ';
+ }
+ attr_ldif[k] = tolower (attr_ldif[k]);
+
+ }
+
+ sizedbuffer_allocate(psbAttrName,strlen(attr_ldif));
+ sizedbuffer_allocate(psbAttrOid,strlen(attr_ldif));
+ sizedbuffer_allocate(psbAttrSyntax,strlen(attr_ldif));
+
+ sscanf (attr_ldif, "%s name %s syntax %s",
+ psbAttrOid->buffer, psbAttrName->buffer, psbAttrSyntax->buffer);
+ if ((a = attr_syntax_get_by_name ( psbAttrName->buffer)) != NULL ) {
+ /* only modify attrs which were user defined */
+ if (a->asi_flags & SLAPI_ATTR_FLAG_STD_ATTR) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ psbAttrName->buffer,
+ "Cannot delete a standard attribute type" );
+ attr_syntax_return( a );
+ return schema_return(LDAP_UNWILLING_TO_PERFORM,psbAttrOid,psbAttrName,
+ psbAttrSyntax,NULL);
+ }
+
+ /* Do not allow deletion if referenced by an object class. */
+ oc_lock_read();
+ attr_in_use_by_an_oc = 0;
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
+ if (NULL != oc->oc_required) {
+ for ( k = 0; oc->oc_required[k] != NULL; k++ ) {
+ if ( 0 == slapi_attr_type_cmp( oc->oc_required[k], a->asi_name,
+ SLAPI_TYPE_CMP_EXACT )) {
+ oc_list_type = "MUST";
+ attr_in_use_by_an_oc = 1;
+ break;
+ }
+ }
+ }
+
+ if (!attr_in_use_by_an_oc && NULL != oc->oc_allowed) {
+ for ( k = 0; oc->oc_allowed[k] != NULL; k++ ) {
+ if ( 0 == slapi_attr_type_cmp( oc->oc_allowed[k], a->asi_name,
+ SLAPI_TYPE_CMP_EXACT )) {
+ oc_list_type = "MAY";
+ attr_in_use_by_an_oc = 1;
+ break;
+ }
+ }
+ }
+
+ if (attr_in_use_by_an_oc) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ psbAttrName->buffer, "Is included in the %s list for object class %s. Cannot delete.",
+ oc_list_type, oc->oc_name );
+ break;
+ }
+ }
+ oc_unlock();
+ if (attr_in_use_by_an_oc) {
+ attr_syntax_return( a );
+ return schema_return(LDAP_UNWILLING_TO_PERFORM,psbAttrOid,psbAttrName,
+ psbAttrSyntax,NULL);
+ }
+
+ /* Delete it. */
+ attr_syntax_delete( a );
+ attr_syntax_return( a );
+ }
+ else {
+ /* unknown attribute */
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ psbAttrName->buffer, "Is unknown. Cannot delete." );
+ return schema_return(LDAP_NO_SUCH_ATTRIBUTE,psbAttrOid,psbAttrName,
+ psbAttrSyntax,NULL);
+ }
+ }
+
+ return schema_return(LDAP_SUCCESS,psbAttrOid,psbAttrName,psbAttrSyntax,
+ NULL);
+}
+
+static int
+schema_add_attribute ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
+ size_t errorbufsize, int schema_ds4x_compat )
+{
+ int i;
+ char *attr_ldif;
+/* LPXXX: Eventually, we should not allocate the buffers in read_at_ldif
+ * for each attribute, but use the same buffer for all.
+ * This is not done yet, so it's useless to allocate buffers for nothing.
+ */
+/* struct sizedbuffer *psbAttrName= sizedbuffer_construct(BUFSIZ); */
+/* struct sizedbuffer *psbAttrOid= sizedbuffer_construct(BUFSIZ); */
+/* struct sizedbuffer *psbAttrDesc= sizedbuffer_construct(BUFSIZ); */
+/* struct sizedbuffer *psbAttrSyntax= sizedbuffer_construct(BUFSIZ); */
+ int status = 0;
+
+ for (i = 0; LDAP_SUCCESS == status && mod->mod_bvalues[i]; i++) {
+ int nolock = 0; /* lock global resources during normal operation */
+ attr_ldif = (char *) mod->mod_bvalues[i]->bv_val;
+
+ status = read_at_ldif(attr_ldif, NULL, errorbuf, errorbufsize,
+ nolock, 1 /* user defined */, schema_ds4x_compat, 1);
+ if ( LDAP_SUCCESS != status ) {
+ break; /* stop on first error */
+ }
+ }
+
+ /* free everything */
+/* sizedbuffer_destroy(psbAttrOid); */
+/* sizedbuffer_destroy(psbAttrName); */
+/* sizedbuffer_destroy(psbAttrDesc); */
+/* sizedbuffer_destroy(psbAttrSyntax); */
+
+ return status;
+}
+
+/*
+ * Returns an LDAP error code (LDAP_SUCCESS if all goes well)
+ */
+static int
+add_oc_internal(struct objclass *pnew_oc, char *errorbuf, size_t errorbufsize,
+ int schema_ds4x_compat )
+{
+ struct objclass *oldoc_by_name, *oldoc_by_oid, *psup_oc = NULL;
+ int redefined_oc = 0, rc=0;
+ asyntaxinfo *pasyntaxinfo = 0;
+
+ oc_lock_write();
+
+ oldoc_by_name = oc_find_nolock (pnew_oc->oc_name);
+ oldoc_by_oid = oc_find_nolock (pnew_oc->oc_oid);
+
+ /* Check to see if the objectclass name and the objectclass oid are already
+ * in use by an existing objectclass. If an existing objectclass is already
+ * using the name or oid, the name and the oid should map to the same objectclass.
+ * Otherwise, return an error.
+ */
+ if ( oldoc_by_name != oldoc_by_oid ) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ pnew_oc->oc_name, "The name does not match the OID \"%s\". "
+ "Another object class is already using the name or OID.",
+ pnew_oc->oc_oid);
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+
+ /*
+ * Set a flag so we know if we are updating an existing OC definition.
+ */
+ if ( !rc ) {
+ if ( NULL != oldoc_by_name ) {
+ redefined_oc = 1;
+ } else {
+ /*
+ * If we are not updating an existing OC, check that the new
+ * oid is not already in use.
+ */
+ if ( NULL != oldoc_by_oid ) {
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_oc, pnew_oc->oc_name,
+ "The OID \"%s\" is already used by the object class \"%s\"",
+ pnew_oc->oc_oid, oldoc_by_oid->oc_name);
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+ }
+ }
+
+ /* check to see if the superior oc exists */
+ if (!rc && pnew_oc->oc_superior &&
+ ((psup_oc = oc_find_nolock (pnew_oc->oc_superior)) == NULL)) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ pnew_oc->oc_name, "Superior object class \"%s\" does not exist",
+ pnew_oc->oc_superior);
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+
+ /* inherit the attributes from the superior oc */
+ if (!rc && psup_oc ) {
+ if ( psup_oc->oc_required ) {
+ charray_merge( &pnew_oc->oc_required, psup_oc->oc_required, 1 );
+ }
+ if ( psup_oc->oc_allowed ) {
+ charray_merge ( &pnew_oc->oc_allowed, psup_oc->oc_allowed, 1 );
+ }
+ }
+
+ /* check to see if the oid is already in use by an attribute */
+ if (!rc && (pasyntaxinfo = attr_syntax_get_by_oid(pnew_oc->oc_oid))) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ pnew_oc->oc_name,
+ "The OID \"%s\" is also used by the attribute type \"%s\"",
+ pnew_oc->oc_oid, pasyntaxinfo->asi_name);
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ attr_syntax_return( pasyntaxinfo );
+ }
+
+ /* check to see if the objectclass name is valid */
+ if (!rc && schema_check_name ( pnew_oc->oc_name, PR_FALSE,
+ errorbuf, errorbufsize ) == 0 ) {
+ rc = schema_ds4x_compat ? LDAP_OPERATIONS_ERROR : LDAP_INVALID_SYNTAX;
+ }
+
+ /* check to see if the oid is valid */
+ if (!rc)
+ {
+ struct sizedbuffer *psbOcOid, *psbOcName;
+
+ psbOcName = sizedbuffer_construct(strlen(pnew_oc->oc_name) + 1);
+ psbOcOid = sizedbuffer_construct(strlen(pnew_oc->oc_oid) + 1);
+ strcpy(psbOcName->buffer, pnew_oc->oc_name);
+ strcpy(psbOcOid->buffer, pnew_oc->oc_oid);
+
+ if (!schema_check_oid ( psbOcName->buffer, psbOcOid->buffer, PR_FALSE,
+ errorbuf, errorbufsize))
+ rc = schema_ds4x_compat ? LDAP_OPERATIONS_ERROR : LDAP_INVALID_SYNTAX;
+
+ sizedbuffer_destroy(psbOcName);
+ sizedbuffer_destroy(psbOcOid);
+ }
+
+ /* check to see if the oc's attributes are valid */
+ if (!rc && schema_check_oc_attrs ( pnew_oc, errorbuf, errorbufsize,
+ 0 /* don't strip options */ ) == 0 ) {
+ rc = schema_ds4x_compat ? LDAP_OPERATIONS_ERROR : LDAP_INVALID_SYNTAX;
+ }
+ /* insert new objectclass exactly where the old one one in the linked list*/
+ if ( !rc && redefined_oc ) {
+ pnew_oc->oc_flags |= OC_FLAG_REDEFINED_OC;
+ rc=oc_replace_nolock( pnew_oc->oc_name, pnew_oc);
+ }
+
+ if (!rc && !redefined_oc ) {
+ oc_add_nolock(pnew_oc);
+ }
+
+ if (!rc && redefined_oc ) {
+ oc_update_inheritance_nolock( pnew_oc );
+ }
+
+ oc_unlock();
+ return rc;
+}
+
+
+/*
+ * Process a replace modify suboperation for attributetypes.
+ *
+ * XXXmcs: At present, readonly (bundled) schema definitions can't be
+ * removed. If that is attempted, we just keep them without generating
+ * an error.
+ *
+ * Our algorithm is:
+ *
+ * Clear the "keep" flags on the all existing attr. definitions.
+ *
+ * For each replacement value:
+ * If the value exactly matches an existing schema definition,
+ * set that definition's keep flag.
+ *
+ * Else if the OID in the replacement value matches an existing
+ * definition, delete the old definition and add the new one. Set
+ * the keep flag on the newly added definition.
+ *
+ * Else add the new definition. Set the keep flag on the newly
+ * added definition.
+ *
+ * For each definition that is not flagged keep, delete.
+ *
+ * Clear all remaining "keep" flags.
+ *
+ * Note that replace was not supported at all before iDS 5.0.
+ */
+static int
+schema_replace_attributes ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
+ size_t errorbufsize )
+{
+ int i, rc = LDAP_SUCCESS;
+ struct asyntaxinfo *newasip, *oldasip;
+
+ if ( NULL == mod->mod_bvalues ) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ NULL, "Cannot remove all schema attribute types" );
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ /* clear all of the "keep" flags */
+ attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
+
+ for ( i = 0; mod->mod_bvalues[i] != NULL; ++i ) {
+ if ( LDAP_SUCCESS != ( rc = read_at_ldif( mod->mod_bvalues[i]->bv_val,
+ &newasip, errorbuf, errorbufsize, 0, 1, 0, 0 ))) {
+ goto clean_up_and_return;
+ }
+
+ /*
+ * Check for a match with an existing type and
+ * handle the various cases.
+ */
+ if ( NULL == ( oldasip =
+ attr_syntax_get_by_oid( newasip->asi_oid ))) {
+ /* new attribute type */
+ LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_attributes:"
+ " new type %s (OID %s)\n",
+ newasip->asi_name, newasip->asi_oid, 0 );
+ } else {
+ /* the name matches -- check the rest */
+ if ( attr_syntax_equal( newasip, oldasip )) {
+ /* unchanged attribute type -- just mark it as one to keep */
+ oldasip->asi_flags |= SLAPI_ATTR_FLAG_KEEP;
+ attr_syntax_free( newasip );
+ newasip = NULL;
+ } else {
+ /* modified attribute type */
+ LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_attributes:"
+ " replacing type %s (OID %s)\n",
+ newasip->asi_name, newasip->asi_oid, 0 );
+ attr_syntax_delete( oldasip );
+ }
+
+ attr_syntax_return( oldasip );
+ }
+
+ if ( NULL != newasip ) { /* add new or replacement definition */
+ rc = attr_syntax_add( newasip );
+ if ( LDAP_SUCCESS != rc ) {
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_at, newasip->asi_name,
+ "Could not be added (OID is \"%s\")",
+ newasip->asi_oid );
+ attr_syntax_free( newasip );
+ goto clean_up_and_return;
+ }
+
+ newasip->asi_flags |= SLAPI_ATTR_FLAG_KEEP;
+ }
+ }
+
+ /*
+ * Delete all of the definitions that are not marked "keep" or "standard".
+ *
+ * XXXmcs: we should consider reporting an error if any read only types
+ * remain....
+ */
+ attr_syntax_delete_all_not_flagged( SLAPI_ATTR_FLAG_KEEP
+ | SLAPI_ATTR_FLAG_STD_ATTR );
+
+clean_up_and_return:
+ /* clear all of the "keep" flags */
+ attr_syntax_all_clear_flag( SLAPI_ATTR_FLAG_KEEP );
+
+ return rc;
+}
+
+
+static int
+schema_add_objectclass ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
+ size_t errorbufsize, int schema_ds4x_compat )
+{
+ struct objclass *pnew_oc;
+ char *newoc_ldif;
+ int j, rc=0;
+
+ for (j = 0; mod->mod_bvalues[j]; j++) {
+ newoc_ldif = (char *) mod->mod_bvalues[j]->bv_val;
+ if ( LDAP_SUCCESS != (rc = read_oc_ldif ( newoc_ldif, &pnew_oc,
+ errorbuf, errorbufsize, 0, 1 /* user defined */,
+ schema_ds4x_compat))) {
+ return rc;
+ }
+
+ if ( LDAP_SUCCESS != (rc = add_oc_internal(pnew_oc, errorbuf,
+ errorbufsize, schema_ds4x_compat))) {
+ oc_free( &pnew_oc );
+ return rc;
+ }
+
+ normalize_oc();
+ }
+
+ return LDAP_SUCCESS;
+}
+
+
+
+/*
+ * Process a replace modify suboperation for objectclasses.
+ *
+ * XXXmcs: At present, readonly (bundled) schema definitions can't be
+ * removed. If that is attempted, we just keep them without generating
+ * an error.
+ *
+ * Our algorithm is:
+ *
+ * Lock the global objectclass linked list.
+ *
+ * Create a new empty (temporary) linked list, initially empty.
+ *
+ * For each replacement value:
+ * If the value exactly matches an existing schema definition,
+ * move the existing definition from the current global list to the
+ * temporary list
+ *
+ * Else if the OID in the replacement value matches an existing
+ * definition, delete the old definition from the current global
+ * list and add the new one to the temporary list.
+ *
+ * Else add the new definition to the temporary list.
+ *
+ * Delete all definitions that remain on the current global list.
+ *
+ * Make the temporary list the current global list.
+ *
+ * Note that since the objectclass definitions are stored in a linked list,
+ * this algorithm is O(N * M) where N is the number of existing objectclass
+ * definitions and M is the number of replacement definitions.
+ * XXXmcs: Yuck. We should use a hash table for the OC definitions.
+ *
+ * Note that replace was not supported at all by DS versions prior to 5.0
+ */
+
+static int
+schema_replace_objectclasses ( Slapi_PBlock *pb, LDAPMod *mod, char *errorbuf,
+ size_t errorbufsize )
+{
+ struct objclass *newocp, *curlisthead, *prevocp, *tmpocp;
+ struct objclass *newlisthead = NULL, *newlistend = NULL;
+ int i, rc = LDAP_SUCCESS;
+
+ if ( NULL == mod->mod_bvalues ) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ NULL, "Cannot remove all schema object classes" );
+ return LDAP_UNWILLING_TO_PERFORM;
+ }
+
+ oc_lock_write();
+
+ curlisthead = g_get_global_oc_nolock();
+
+ for ( i = 0; mod->mod_bvalues[i] != NULL; ++i ) {
+ struct objclass *addocp = NULL;
+
+ if ( LDAP_SUCCESS != ( rc = read_oc_ldif( mod->mod_bvalues[i]->bv_val,
+ &newocp, errorbuf, errorbufsize, 1 /* no locking */,
+ 1 /* user defined */, 0 /* no DS 4.x compat issues */ ))) {
+ rc = LDAP_INVALID_SYNTAX;
+ goto clean_up_and_return;
+ }
+
+ prevocp = NULL;
+ for ( tmpocp = curlisthead; tmpocp != NULL; tmpocp = tmpocp->oc_next ) {
+ if ( 0 == strcasecmp( tmpocp->oc_oid, newocp->oc_oid ) ) {
+ /* the names match -- remove from the current list */
+ if ( tmpocp == curlisthead ) {
+ curlisthead = tmpocp->oc_next;
+ } else {
+ prevocp->oc_next = tmpocp->oc_next;
+ }
+ tmpocp->oc_next = NULL;
+
+ /* check for a full match */
+ if ( oc_equal( tmpocp, newocp )) {
+ /* no changes: keep existing definition and discard new */
+ oc_free( &newocp );
+ addocp = tmpocp;
+ } else {
+ /* some differences: discard old and keep the new one */
+ oc_free( &tmpocp );
+ LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_objectclasses:"
+ " replacing object class %s (OID %s)\n",
+ newocp->oc_name, newocp->oc_oid, 0 );
+ addocp = newocp;
+ }
+ break; /* we found it -- exit the loop */
+
+ }
+ prevocp = tmpocp;
+ }
+
+ if ( NULL == addocp ) {
+ LDAPDebug( LDAP_DEBUG_TRACE, "schema_replace_objectclasses:"
+ " new object class %s (OID %s)\n",
+ newocp->oc_name, newocp->oc_oid, 0 );
+ addocp = newocp;
+ }
+
+ /* add the objectclass to the end of the new list */
+ if ( NULL != addocp ) {
+ if ( NULL == newlisthead ) {
+ newlisthead = addocp;
+ } else {
+ newlistend->oc_next = addocp;
+ }
+ newlistend = addocp;
+ }
+ }
+
+clean_up_and_return:
+ if ( LDAP_SUCCESS == rc ) {
+ /*
+ * Delete all remaining OCs that are on the old list AND are not
+ * "standard" classes.
+ */
+ struct objclass *nextocp;
+
+ prevocp = NULL;
+ for ( tmpocp = curlisthead; tmpocp != NULL; tmpocp = nextocp ) {
+ if ( 0 == ( tmpocp->oc_flags & OC_FLAG_STANDARD_OC )) {
+ /* not a standard definition -- remove it */
+ if ( tmpocp == curlisthead ) {
+ curlisthead = tmpocp->oc_next;
+ } else {
+ prevocp->oc_next = tmpocp->oc_next;
+ }
+ nextocp = tmpocp->oc_next;
+ oc_free( &tmpocp );
+ } else {
+ /*
+ * XXXmcs: we could generate an error, but for now we do not.
+ */
+ nextocp = tmpocp->oc_next;
+ prevocp = tmpocp;
+
+#if 0
+
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_oc, tmpocp->oc_name,
+ "Cannot delete a standard object class" );
+ rc = LDAP_UNWILLING_TO_PERFORM;
+ break;
+#endif
+ }
+ }
+ }
+
+ /*
+ * Combine the two lists by adding the new list to the end of the old
+ * one.
+ */
+ if ( NULL != curlisthead ) {
+ for ( tmpocp = curlisthead; tmpocp->oc_next != NULL;
+ tmpocp = tmpocp->oc_next ) {
+ ;/*NULL*/
+ }
+ tmpocp->oc_next = newlisthead;
+ newlisthead = curlisthead;
+ }
+
+ /*
+ * Install the new list as the global one, replacing the old one.
+ */
+ g_set_global_oc_nolock( newlisthead );
+
+ oc_unlock();
+ return rc;
+}
+
+
+/*
+ * read_oc_ldif_return
+ * Free all the memory that read_oc_ldif() allocated, and return the retVal
+ *
+ * It's nice to do all the freeing in one spot, as read_oc_ldif() returns sideways
+ */
+
+static int
+read_oc_ldif_return( int retVal,
+ char *oid,
+ struct sizedbuffer *name,
+ char *sup,
+ char **origins,
+ int num_origins,
+ char *desc )
+{
+ slapi_ch_free((void **)&oid);
+ sizedbuffer_destroy( name );
+ slapi_ch_free((void **)&sup);
+ free_qdlist( origins, num_origins );
+ slapi_ch_free((void **)&desc);
+ return retVal;
+}
+
+/*
+ * read_oc_ldif
+ * Read the value of the objectclasses attribute in cn=schema, convert it
+ * into an objectclass struct.
+ *
+ * Arguments:
+ *
+ * input : value of objectclasses attribute to read
+ * oc : pointer write the objectclass to
+ * errorbuf : buffer to write any errors to
+ * is_user_defined : if non-zero, force objectclass to be user defined
+ * nolock : if non-zero, assume oc_lock_*() has been called.
+ * schema_ds4x_compat: if non-zero, act like Netscape DS 4.x
+ *
+ * Returns: an LDAP error code
+ *
+ * LDAP_SUCCESS if the objectclass was sucessfully read, the new
+ * objectclass will be written to oc
+ *
+ * All others: there was an error, an error message will
+ * be written to errorbuf
+ */
+static int
+read_oc_ldif ( const char *input, struct objclass **oc, char *errorbuf,
+ size_t errorbufsize, int nolock, int is_user_defined,
+ int schema_ds4x_compat ) {
+ int i, j, num_origins;
+ const char *pstart, *nextinput;
+ struct objclass *pnew_oc, *psup_oc;
+ char **RequiredAttrsArray, **AllowedAttrsArray;
+ char **OrigRequiredAttrsArray, **OrigAllowedAttrsArray;
+ char **oc_origins;
+ char *pend, *pOcOid, *pOcSup, *pOcDesc;
+ struct sizedbuffer *psbOcName= sizedbuffer_construct(BUFSIZ);
+ PRUint8 kind, flags;
+ int invalid_syntax_error;
+ schema_strstr_fn_t keyword_strstr_fn;
+
+ /*
+ * From RFC 2252 section 4.4:
+ *
+ * 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 ")"
+ *
+ * XXXmcs: Our parsing technique is poor. In (Netscape) DS 4.12 and earlier
+ * releases, parsing was mostly done by looking anywhere within the input
+ * string for various keywords such as "MUST". But if, for example, a
+ * description contains the word "must", the parser would take assume that
+ * the tokens following the word were attribute types or OIDs. Bad news.
+ *
+ * In iDS 5.0 and later, we parse in order left to right and advance a
+ * pointer as we consume the input string (the nextinput variable). We
+ * also use a case-insensitive search when looking for keywords such as
+ * DESC. But the parser will still be fooled by sequences like:
+ *
+ * ( 1.2.3.4 NAME 'testOC' MUST ( DESC cn ) )
+ *
+ * Someday soon we will need to write a real parser.
+ *
+ * Compatibility notes: if schema_ds4x_compat is set, we:
+ * 1. always parse from the beginning of the string
+ * 2. use a case-insensitive compare when looking for keywords, e.g., MUST
+ */
+
+ if ( schema_ds4x_compat ) {
+ keyword_strstr_fn = PL_strcasestr;
+ invalid_syntax_error = LDAP_OPERATIONS_ERROR;
+ } else {
+ keyword_strstr_fn = PL_strstr;
+ invalid_syntax_error = LDAP_INVALID_SYNTAX;
+ }
+
+ flags = 0;
+ num_origins = 0;
+ oc_origins = NULL;
+ pOcOid = pOcSup = pOcDesc = NULL;
+
+ if ( NULL == input || '\0' == input[0] ) {
+
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc, NULL,
+ "One or more values are required for the objectClasses attribute" );
+ LDAPDebug ( LDAP_DEBUG_ANY, "NULL args passed to read_oc_ldif\n",0,0,0);
+ return read_oc_ldif_return( LDAP_OPERATIONS_ERROR, pOcOid, psbOcName,
+ pOcSup, oc_origins, num_origins, pOcDesc );
+ }
+
+
+ nextinput = input;
+
+ /* look for the OID */
+ if ( NULL == ( pOcOid = get_tagged_oid( "(", &nextinput,
+ keyword_strstr_fn ))) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ input, "Value is malformed. It must include a \"(\"");
+ return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName,
+ pOcSup, oc_origins, num_origins, pOcDesc );
+ }
+
+ if ( schema_ds4x_compat || ( strcasecmp(pOcOid, "NAME") == 0))
+ nextinput = input;
+
+ /* look for the NAME */
+ if ( (pstart = (*keyword_strstr_fn)(nextinput, "NAME '")) != NULL ) {
+ pstart += 6;
+ sizedbuffer_allocate(psbOcName,strlen(pstart));
+ if ( sscanf ( pstart, "%s", psbOcName->buffer ) > 0 ) {
+ /* strip the trailing single quote */
+ if ( psbOcName->buffer[strlen(psbOcName->buffer)-1] == '\'' ) {
+ psbOcName->buffer[strlen(psbOcName->buffer)-1] = '\0';
+ nextinput = pstart + strlen(psbOcName->buffer) + 1;
+ } else {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ input, "Value is malformed. It must include a single quote around"
+ " the name" );
+ return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName,
+ pOcSup, oc_origins, num_origins, pOcDesc );
+ }
+ }
+ }
+ else {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ input, "Value is malformed. It must include a \"NAME '\"");
+ return read_oc_ldif_return( invalid_syntax_error, pOcOid, psbOcName,
+ pOcSup, oc_origins, num_origins, pOcDesc );
+ }
+
+ /*
+ ** if the objectclass ldif doesn't have an OID, we'll make the oid
+ ** ocname-oid
+ */
+ if ( strcasecmp ( pOcOid, "NAME" ) == 0 ) {
+ free( pOcOid );
+ pOcOid = slapi_ch_malloc( 8 + strlen(psbOcName->buffer));
+ sprintf(pOcOid, "%s-oid", psbOcName->buffer );
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for an optional DESCription */
+ if ( (pstart = (*keyword_strstr_fn) ( nextinput, " DESC '")) != NULL ) {
+ pstart += 7;
+ if (( pend = strchr( pstart, '\'' )) == NULL ) {
+ pend = (char *)(pstart + strlen(pstart));
+ }
+ pOcDesc = slapi_ch_malloc( pend - pstart + 1 );
+ memcpy( pOcDesc, pstart, pend - pstart );
+ pOcDesc[ pend - pstart ] = '\0';
+ nextinput = pend + 1;
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional OBSOLETE marker */
+ flags |= get_flag_keyword( schema_obsolete_with_spaces,
+ OC_FLAG_OBSOLETE, &nextinput, keyword_strstr_fn );
+
+ if (!nolock) {
+ oc_lock_read(); /* needed because we access the superior oc */
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /*
+ * Look for the superior objectclass. We first look for a parenthesized
+ * list and if not found we look for a simple OID.
+ *
+ * XXXmcs: Since we do not yet support multiple superior objectclasses, we
+ * just grab the first OID in a parenthesized list.
+ */
+ if ( NULL == ( pOcSup = get_tagged_oid( " SUP ( ", &nextinput,
+ keyword_strstr_fn ))) {
+ pOcSup = get_tagged_oid( " SUP ", &nextinput, keyword_strstr_fn );
+ }
+ psup_oc = oc_find_nolock ( pOcSup );
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional kind (ABSTRACT, STRUCTURAL, AUXILIARY) */
+ for ( i = 0; i < SCHEMA_OC_KIND_COUNT; ++i ) {
+ if ( NULL != ( pstart = (*keyword_strstr_fn)( nextinput,
+ schema_oc_kind_strings_with_spaces[i] ))) {
+ kind = i;
+ nextinput = pstart + strlen( schema_oc_kind_strings_with_spaces[i] ) - 1;
+ break;
+ }
+ }
+ if ( i >= SCHEMA_OC_KIND_COUNT ) { /* not found */
+ if ( NULL != psup_oc && OC_KIND_ABSTRACT != psup_oc->oc_kind ) {
+ /* inherit kind from superior class if not ABSTRACT */
+ kind = psup_oc->oc_kind;
+ } else {
+ /* according to RFC 2252, the default is structural */
+ kind = OC_KIND_STRUCTURAL;
+ }
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for required attributes (MUST) */
+ if ( (pstart = (*keyword_strstr_fn) (nextinput, " MUST ")) != NULL ) {
+ char *pRequiredAttrs;
+ int saw_open_paren = 0;
+
+ pstart += 6;
+ pstart = skipWS( pstart ); /* skip past any extra white space */
+ if ( *pstart == '(' ) {
+ saw_open_paren = 1;
+ ++pstart;
+ }
+ pRequiredAttrs = slapi_ch_strdup ( pstart );
+ if ( saw_open_paren && (pend = strchr (pRequiredAttrs, ')')) != NULL ) {
+ *pend = '\0';
+ } else if ((pend = strchr (pRequiredAttrs, ' ' )) != NULL ) {
+ *pend = '\0';
+ } else {
+ pend = pRequiredAttrs + strlen(pRequiredAttrs); /* at end of string */
+ }
+ nextinput = pstart + ( pend - pRequiredAttrs );
+ RequiredAttrsArray = read_dollar_values (pRequiredAttrs);
+ slapi_ch_free((void**)&pRequiredAttrs);
+ } else {
+ RequiredAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
+ RequiredAttrsArray[0] = NULL;
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for allowed attributes (MAY) */
+ if ( (pstart = (*keyword_strstr_fn) (nextinput, " MAY ")) != NULL ) {
+ char *pAllowedAttrs;
+ int saw_open_paren = 0;
+
+ pstart += 5;
+ pstart = skipWS( pstart ); /* skip past any extra white space */
+ if ( *pstart == '(' ) {
+ saw_open_paren = 1;
+ ++pstart;
+ }
+ pAllowedAttrs = slapi_ch_strdup ( pstart );
+ if ( saw_open_paren && (pend = strchr (pAllowedAttrs, ')')) != NULL ) {
+ *pend = '\0';
+ } else if ((pend = strchr (pAllowedAttrs, ' ' )) != NULL ) {
+ *pend = '\0';
+ } else {
+ pend = pAllowedAttrs + strlen(pAllowedAttrs); /* at end of string */
+ }
+ nextinput = pstart + ( pend - pAllowedAttrs );
+ AllowedAttrsArray = read_dollar_values (pAllowedAttrs);
+ slapi_ch_free((void**)&pAllowedAttrs);
+ } else {
+ AllowedAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
+ AllowedAttrsArray[0] = NULL;
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for X-ORIGIN list */
+ oc_origins = parse_origin_list( nextinput, &num_origins,
+ schema_user_defined_origin );
+
+ /* set remaining flags */
+ if ( element_is_user_defined( oc_origins )) {
+ flags |= OC_FLAG_USER_OC;
+ } else if ( is_user_defined ) {
+ flags |= OC_FLAG_USER_OC;
+ /* add missing user defined origin string */
+ charray_add( &oc_origins, slapi_ch_strdup( schema_user_defined_origin[0] ));
+ ++num_origins;
+ } else {
+ flags |= OC_FLAG_STANDARD_OC;
+ }
+
+ /* generate OrigRequiredAttrsArray and OrigAllowedAttrsArray */
+
+ if (psup_oc) {
+ int found_it;
+
+ OrigRequiredAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
+ OrigRequiredAttrsArray[0] = NULL;
+ OrigAllowedAttrsArray = (char **) slapi_ch_malloc (1 * sizeof(char *)) ;
+ OrigAllowedAttrsArray[0] = NULL;
+
+ if (psup_oc->oc_required) {
+ for (i = 0; RequiredAttrsArray[i]; i++) {
+ for (j = 0, found_it = 0; psup_oc->oc_required[j]; j++) {
+ if (strcasecmp (psup_oc->oc_required[j], RequiredAttrsArray[i]) == 0) {
+ found_it = 1;
+ }
+ }
+ if (!found_it) {
+ charray_add (&OrigRequiredAttrsArray, slapi_ch_strdup ( RequiredAttrsArray[i] ) );
+ }
+ }
+ }
+ if (psup_oc->oc_allowed) {
+ for (i = 0; AllowedAttrsArray[i]; i++) {
+ for (j = 0, found_it=0; psup_oc->oc_allowed[j]; j++) {
+ if (strcasecmp (psup_oc->oc_allowed[j], AllowedAttrsArray[i]) == 0) {
+ found_it = 1;
+ }
+ }
+ if (!found_it) {
+ charray_add (&OrigAllowedAttrsArray, slapi_ch_strdup (AllowedAttrsArray[i]) );
+ }
+ }
+ }
+ }
+ else {
+ /* if no parent oc */
+ OrigRequiredAttrsArray = charray_dup ( RequiredAttrsArray );
+ OrigAllowedAttrsArray = charray_dup ( AllowedAttrsArray );
+ }
+
+ if (!nolock) {
+ oc_unlock(); /* we are done accessing superior oc (psup_oc) */
+ }
+
+ /* finally -- create new objclass structure */
+ pnew_oc = (struct objclass *) slapi_ch_malloc (1 * sizeof (struct objclass));
+ pnew_oc->oc_name = slapi_ch_strdup ( psbOcName->buffer );
+ pnew_oc->oc_superior = pOcSup;
+ pOcSup = NULL; /* don't free this later */
+ pnew_oc->oc_oid = pOcOid;
+ pOcOid = NULL; /* don't free this later */
+ pnew_oc->oc_desc = pOcDesc;
+ pOcDesc = NULL; /* don't free this later */
+ pnew_oc->oc_required = RequiredAttrsArray;
+ pnew_oc->oc_allowed = AllowedAttrsArray;
+ pnew_oc->oc_orig_required = OrigRequiredAttrsArray;
+ pnew_oc->oc_orig_allowed = OrigAllowedAttrsArray;
+ pnew_oc->oc_origin = cool_charray_dup( oc_origins );
+ pnew_oc->oc_next = NULL;
+ pnew_oc->oc_flags = flags;
+ pnew_oc->oc_kind = kind;
+
+ *oc = pnew_oc;
+ return read_oc_ldif_return( LDAP_SUCCESS, pOcOid, psbOcName, pOcSup,
+ oc_origins, num_origins, pOcDesc );
+}
+
+
+static void
+oc_free( struct objclass **ocp )
+{
+ struct objclass *oc;
+
+ if ( NULL != ocp && NULL != *ocp ) {
+ oc = *ocp;
+ slapi_ch_free( (void **)&oc->oc_name );
+ slapi_ch_free( (void **)&oc->oc_desc );
+ slapi_ch_free( (void **)&oc->oc_oid );
+ slapi_ch_free( (void **)&oc->oc_superior );
+ charray_free( oc->oc_required );
+ charray_free( oc->oc_allowed );
+ charray_free( oc->oc_orig_required );
+ charray_free( oc->oc_orig_allowed );
+ cool_charray_free( oc->oc_origin );
+ slapi_ch_free( (void **)&oc );
+ *ocp = NULL;
+ }
+}
+
+struct supargs{
+ char *sup, *oid;
+ unsigned long rc;
+};
+
+static int
+at_sup_dependency_callback(struct asyntaxinfo *asi, void *arg)
+{
+ struct supargs *aew = (struct supargs *)arg;
+ int rc=ATTR_SYNTAX_ENUM_NEXT;
+
+ if (!asi) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Error: no attribute types in at_schema_attributes_callback\n",
+ 0, 0, 0);
+ }
+ else
+ {
+ if (strcasecmp (asi->asi_oid, aew->oid ) == 0) {
+ rc=ATTR_SYNTAX_ENUM_STOP;
+ } else {
+ if(asi->asi_name != NULL) {
+ if (strcasecmp (asi->asi_name, aew->sup ) == 0) {
+ aew->rc=0;
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+/* walks down attribute types and makes sure that the superior value is found in an attribute type
+ preceeding in the hash table. I have concerns about collisions messing with the order here but this
+ may be the best we can do.
+*/
+
+static int
+slapi_check_at_sup_dependency(char *sup, char *oid)
+{
+ struct supargs aew;
+
+ memset(&aew,0,sizeof(struct supargs));
+ aew.rc=LDAP_TYPE_OR_VALUE_EXISTS;
+ aew.sup=sup;
+ aew.oid=oid;
+ attr_syntax_enumerate_attrs(at_sup_dependency_callback, &aew, PR_FALSE);
+ return aew.rc;
+}
+
+
+
+/*
+ * if asipp is NULL, the attribute type is added to the global set of schema.
+ * if asipp is not NULL, the AT is not added but *asipp is set.
+ *
+ * if nolock is true, locking of global resources is turned off; this saves
+ * time during initialization since the server operates in single threaded
+ * mode at that time.
+ *
+ * if is_user_defined is true, force attribute type to be user defined.
+ *
+ * returns an LDAP error code (LDAP_SUCCESS if all goes well)
+*/
+static int
+read_at_ldif(const char *input, struct asyntaxinfo **asipp, char *errorbuf,
+ size_t errorbufsize, int nolock, int is_user_defined,
+ int schema_ds4x_compat, int is_remote)
+{
+ char *pStart, *pEnd;
+ char *pOid, *pSyntax, *pSuperior, *pMREquality, *pMROrdering, *pMRSubstring;
+ const char *nextinput;
+ struct sizedbuffer *psbAttrName= sizedbuffer_construct(BUFSIZ);
+ struct sizedbuffer *psbAttrDesc= sizedbuffer_construct(BUFSIZ);
+ int status = 0;
+ int syntaxlength;
+ char **attr_names = NULL;
+ char *first_attr_name = NULL;
+ char **attr_origins = NULL;
+ int num_names = 0;
+ int num_origins = 0;
+ unsigned long flags = SLAPI_ATTR_FLAG_OVERRIDE;
+ const char *ss = 0;
+ struct asyntaxinfo *tmpasip;
+ int invalid_syntax_error;
+ schema_strstr_fn_t keyword_strstr_fn;
+
+ /*
+ * From RFC 2252 section 4.2:
+ *
+ * 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 userApplications
+ * whsp ")"
+ *
+ * AttributeUsage =
+ * "userApplications" /
+ * "directoryOperation" /
+ * "distributedOperation" / ; DSA-shared
+ * "dSAOperation" ; DSA-specific, value depends on server
+ *
+ * XXXmcs: Our parsing technique is poor. In (Netscape) DS 4.12 and earlier
+ * releases, parsing was mostly done by looking anywhere within the input
+ * string for various keywords such as "EQUALITY". But if, for example, a
+ * description contains the word "equality", the parser would take assume
+ * that the token following the word was a matching rule. Bad news.
+ *
+ * In iDS 5.0 and later, we parse in order left to right and advance a
+ * pointer as we consume the input string (the nextinput variable). We
+ * also use a case-insensitive search when looking for keywords such as
+ * DESC. This is still less than ideal.
+ *
+ * Someday soon we will need to write a real parser.
+ *
+ * Compatibility notes: if schema_ds4x_compat is set, we:
+ * 1. always parse from the beginning of the string
+ * 2. use a case-insensitive compare when looking for keywords, e.g., DESC
+ */
+
+ if ( schema_ds4x_compat ) {
+ keyword_strstr_fn = PL_strcasestr;
+ invalid_syntax_error = LDAP_OPERATIONS_ERROR;
+ } else {
+ keyword_strstr_fn = PL_strstr;
+ invalid_syntax_error = LDAP_INVALID_SYNTAX;
+ }
+
+ if (nolock)
+ flags |= SLAPI_ATTR_FLAG_NOLOCKING;
+
+ psbAttrName->buffer[0] = '\0';
+ psbAttrDesc->buffer[0] = '\0';
+ pOid = pSyntax = pSuperior = NULL;
+ pMREquality = pMROrdering = pMRSubstring = NULL;
+ syntaxlength = SLAPI_SYNTAXLENGTH_NONE;
+
+ nextinput = input;
+
+ /* get the OID */
+ pOid = get_tagged_oid( "(", &nextinput, keyword_strstr_fn );
+
+ if (NULL == pOid) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ input, "Missing or invalid OID" );
+ status = invalid_syntax_error;
+ goto done;
+ }
+
+ if ( schema_ds4x_compat || (strcasecmp(pOid, "NAME") == 0))
+ nextinput = input;
+
+ /* look for the NAME (single or list of names) */
+ if ( (pStart = (*keyword_strstr_fn) ( nextinput, "NAME ")) != NULL ) {
+ pStart += 5;
+ sizedbuffer_allocate(psbAttrName,strlen(pStart)+1);
+ strcpy ( psbAttrName->buffer, pStart);
+ if (*pStart == '(')
+ pEnd = strchr(psbAttrName->buffer, ')');
+ else
+ pEnd = strchr(psbAttrName->buffer+1, '\'');
+ if (pEnd)
+ *(pEnd+1) = 0;
+ nextinput = pStart + strlen(psbAttrName->buffer) + 1;
+ attr_names = parse_qdescrs(psbAttrName->buffer, &num_names);
+ if ( NULL != attr_names ) {
+ first_attr_name = attr_names[0];
+ }
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /*
+ * if the attribute ldif doesn't have an OID, we'll make the oid
+ * attrname-oid
+ */
+ if ( strcasecmp ( pOid, "NAME" ) == 0 ) {
+ free( pOid );
+ pOid = slapi_ch_malloc( 8 + strlen(first_attr_name));
+ sprintf(pOid, "%s-oid", first_attr_name );
+ }
+
+ /* look for the optional DESCription */
+ if ( (pStart = (*keyword_strstr_fn) ( nextinput, "DESC '")) != NULL ) {
+ pStart += 6;
+ sizedbuffer_allocate(psbAttrDesc,strlen(pStart));
+ strcpy ( psbAttrDesc->buffer, pStart);
+ if ( (pEnd = strchr (psbAttrDesc->buffer, '\'' )) != NULL ){
+ *pEnd ='\0';
+ }
+ nextinput = pStart + strlen(psbAttrDesc->buffer) + 1;
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional OBSOLETE marker */
+ flags |= get_flag_keyword( schema_obsolete_with_spaces,
+ SLAPI_ATTR_FLAG_OBSOLETE, &nextinput, keyword_strstr_fn );
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional SUPerior type */
+ pSuperior = get_tagged_oid( "SUP ", &nextinput, keyword_strstr_fn );
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional matching rules */
+ pMREquality = get_tagged_oid( "EQUALITY ", &nextinput, keyword_strstr_fn );
+ if ( schema_ds4x_compat ) nextinput = input;
+ pMROrdering = get_tagged_oid( "ORDERING ", &nextinput, keyword_strstr_fn );
+ if ( schema_ds4x_compat ) nextinput = input;
+ pMRSubstring = get_tagged_oid( "SUBSTR ", &nextinput, keyword_strstr_fn );
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional SYNTAX */
+ if ( NULL != ( pSyntax = get_tagged_oid( "SYNTAX ", &nextinput,
+ keyword_strstr_fn ))) {
+ /*
+ * Check for an optional {LEN}, which if present indicates a
+ * suggested maximum size for values of this attribute type.
+ *
+ * XXXmcs: we do not enforce length restrictions, but we do read
+ * and include them in the subschemasubentry.
+ */
+ if ( (pEnd = strchr ( pSyntax, '{')) != NULL /* balance } */ ) {
+ *pEnd = '\0';
+ syntaxlength = atoi( pEnd + 1 );
+ }
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional SINGLE-VALUE marker */
+ flags |= get_flag_keyword( " SINGLE-VALUE ",
+ SLAPI_ATTR_FLAG_SINGLE, &nextinput, keyword_strstr_fn );
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional COLLECTIVE marker */
+ flags |= get_flag_keyword( schema_collective_with_spaces,
+ SLAPI_ATTR_FLAG_COLLECTIVE, &nextinput, keyword_strstr_fn );
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional NO-USER-MODIFICATION marker */
+ flags |= get_flag_keyword( schema_nousermod_with_spaces,
+ SLAPI_ATTR_FLAG_NOUSERMOD, &nextinput, keyword_strstr_fn );
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* look for the optional USAGE */
+ if (NULL != (ss = (*keyword_strstr_fn)(nextinput, " USAGE "))) {
+ ss += 7;
+ ss = skipWS(ss);
+ if (ss) {
+ if ( !PL_strncmp(ss, "directoryOperation",
+ strlen("directoryOperation"))) {
+ flags |= SLAPI_ATTR_FLAG_OPATTR;
+ }
+ if ( NULL == ( nextinput = strchr( ss, ' ' ))) {
+ nextinput = ss + strlen(ss);
+ }
+ }
+ }
+
+ if ( schema_ds4x_compat ) nextinput = input;
+
+ /* X-ORIGIN list */
+ attr_origins = parse_origin_list( nextinput, &num_origins,
+ schema_user_defined_origin );
+
+ /* Do some sanity checking to make sure everything was read correctly */
+
+ if (NULL == pOid) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ first_attr_name, "Missing OID" );
+ status = invalid_syntax_error;
+ }
+ if (!status && (!attr_names || !num_names)) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ first_attr_name,
+ "Missing name (OID is \"%s\")", pOid );
+ status = invalid_syntax_error;
+ }
+
+ if (!status && (NULL != pSuperior)) {
+ struct asyntaxinfo *asi_parent;
+
+ asi_parent = attr_syntax_get_by_name(pSuperior);
+ /* if we find no match then server won't start or add the attribute type */
+ if (asi_parent == NULL) {
+ LDAPDebug (LDAP_DEBUG_PARSE,
+ "Cannot find parent attribute type \"%s\"\n",pSuperior,
+ NULL,NULL);
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_at, first_attr_name,
+ "Missing parent attribute syntax OID");
+ status = invalid_syntax_error;
+ } else {
+ char *pso = plugin_syntax2oid(asi_parent->asi_plugin);
+
+ if (pso) {
+ slapi_ch_free ((void **)&pSyntax);
+ pSyntax = slapi_ch_strdup(pso);
+ LDAPDebug (LDAP_DEBUG_TRACE,
+ "Inheriting syntax %s from parent type %s\n",
+ pSyntax, pSuperior,NULL);
+ } else {
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_at, first_attr_name,
+ "Missing parent attribute syntax OID");
+ status = invalid_syntax_error;
+ }
+ }
+ }
+ /*
+ if we are remote (via modify_schema_dse) then check sup dependencies. Locally
+ was done in if statement above
+ */
+
+ if(!status)
+ {
+ if(is_remote && (pSuperior != NULL))
+ {
+ status=slapi_check_at_sup_dependency(pSuperior, pOid);
+ }
+ if(LDAP_SUCCESS != status) {
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_at, first_attr_name,
+ "Missing parent attribute syntax OID");
+ status = LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+ }
+
+ if (!status && (NULL == pSyntax)) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ first_attr_name, "Missing attribute syntax OID");
+ status = invalid_syntax_error;
+
+ }
+
+ if (!status && (plugin_syntax_find ( pSyntax ) == NULL) ) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ first_attr_name, "Unknown attribute syntax OID \"%s\"",
+ pSyntax );
+ status = invalid_syntax_error;
+ }
+
+ if (!status) {
+ struct objclass *poc;
+ /* check to make sure that the OID isn't being used by an objectclass */
+ oc_lock_read();
+ poc = oc_find_oid_nolock( pOid );
+ if ( poc != NULL) {
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_at, first_attr_name,
+ "The OID \"%s\" is also used by the object class \"%s\"",
+ pOid, poc->oc_name);
+ status = LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+ oc_unlock();
+ }
+
+ if (!status && !element_is_user_defined( attr_origins )) {
+ if ( is_user_defined ) {
+ /* add missing user defined origin string */
+ charray_add( &attr_origins,
+ slapi_ch_strdup( schema_user_defined_origin[0] ));
+ ++num_origins;
+ } else {
+ flags |= SLAPI_ATTR_FLAG_STD_ATTR;
+ }
+ }
+
+ if (!status) {
+ int ii;
+ /* check to see if the attribute name is valid */
+ for (ii = 0; !status && (ii < num_names); ++ii) {
+ if ( schema_check_name(attr_names[ii], PR_TRUE, errorbuf,
+ errorbufsize) == 0 ) {
+ status = invalid_syntax_error;
+ }
+ else if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
+ attr_syntax_exists(attr_names[ii])) {
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_at, attr_names[ii],
+ "Could not be added because it already exists" );
+ status = LDAP_TYPE_OR_VALUE_EXISTS;
+ }
+ }
+ }
+
+ if (!status) {
+ if ( schema_check_oid ( first_attr_name, pOid, PR_TRUE, errorbuf,
+ errorbufsize ) == 0 ) {
+ status = invalid_syntax_error;
+ }
+ }
+
+ if (!status) {
+ struct asyntaxinfo *tmpasi;
+
+ if (!(flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
+ ( NULL != ( tmpasi = attr_syntax_get_by_oid(pOid)))) {
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_at, first_attr_name,
+ "Could not be added because the OID \"%s\" is already in use",
+ pOid);
+ status = LDAP_TYPE_OR_VALUE_EXISTS;
+ attr_syntax_return( tmpasi );
+ }
+ }
+
+
+ if (!status) {
+ status = attr_syntax_create( pOid, attr_names, num_names,
+ *psbAttrDesc->buffer == '\0' ? NULL : psbAttrDesc->buffer,
+ pSuperior,
+ pMREquality, pMROrdering, pMRSubstring, attr_origins,
+ pSyntax, syntaxlength, flags, &tmpasip );
+ }
+
+ if (!status) {
+ if ( NULL != asipp ) {
+ *asipp = tmpasip; /* just return it */
+ } else { /* add the new attribute to the global store */
+ status = attr_syntax_add( tmpasip );
+ if ( LDAP_SUCCESS != status ) {
+ if ( 0 != (flags & SLAPI_ATTR_FLAG_OVERRIDE) &&
+ LDAP_TYPE_OR_VALUE_EXISTS == status ) {
+ /*
+ * This can only occur if the name and OID don't match the
+ * attribute we are trying to override (all other cases of
+ * "type or value exists" were trapped above).
+ */
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_at, first_attr_name,
+ "Does not match the OID \"%s\". Another attribute"
+ " type is already using the name or OID.", pOid);
+ } else {
+ schema_create_errormsg( errorbuf, errorbufsize,
+ schema_errprefix_at, first_attr_name,
+ "Could not be added (OID is \"%s\")", pOid );
+ }
+ attr_syntax_free( tmpasip );
+ }
+ }
+ }
+
+ done:
+ /* free everything */
+ free_qdlist(attr_names, num_names);
+ free_qdlist(attr_origins, num_origins);
+ sizedbuffer_destroy(psbAttrName);
+ sizedbuffer_destroy(psbAttrDesc);
+ slapi_ch_free((void **)&pOid);
+ slapi_ch_free((void **)&pSuperior);
+ slapi_ch_free((void **)&pMREquality);
+ slapi_ch_free((void **)&pMROrdering);
+ slapi_ch_free((void **)&pMRSubstring);
+ slapi_ch_free((void **)&pSyntax);
+
+ return status;
+}
+
+
+/*
+ * schema_check_oc_attrs:
+ * Check to see if the required and allowed attributes are valid attributes
+ *
+ * arguments: poc : pointer to the objectclass to check
+ * errorbuf : buffer to write any error messages to
+ * stripOptions: 1 if you want to silently strip any options
+ * 0 if options should cause an error
+ *
+ * Returns:
+ *
+ * 0 if there's a unknown attribute, and errorbuf will contain an
+ * error message.
+ *
+ * 1 if everything is ok
+ *
+ * Note: no locking of poc is needed because poc is always a newly allocated
+ * objclass struct (this function is only called by add_oc_internal).
+ */
+static int
+schema_check_oc_attrs ( struct objclass *poc,
+ char *errorbuf, size_t errorbufsize,
+ int stripOptions )
+{
+ int i;
+
+ if ( errorbuf == NULL || poc == NULL || poc->oc_name == NULL) {
+ /* error */
+ LDAPDebug (LDAP_DEBUG_PARSE,
+ "Null args passed to schema_check_oc_attrs\n",
+ NULL, NULL, NULL);
+ return -1;
+ }
+
+ /* remove any options like ;binary from the oc's attributes */
+ if ( strip_oc_options( poc ) && !stripOptions) {
+ /* there were options present, this oc should be rejected */
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ poc->oc_name, "Contains attribute options. "
+ "Attribute options, such as \";binary\" are not allowed in "
+ "object class definitions." );
+ return 0;
+ }
+
+ for ( i = 0; poc->oc_allowed && poc->oc_allowed[i]; i++ ) {
+ if ( attr_syntax_exists ( poc->oc_allowed[i] ) == 0 ) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ poc->oc_name, "Unknown allowed attribute type \"%s\"",
+ poc->oc_allowed[i]);
+ return 0;
+ }
+ }
+
+
+ for ( i = 0; poc->oc_required && poc->oc_required[i]; i++ ) {
+ if ( attr_syntax_exists ( poc->oc_required[i] ) == 0 ) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_oc,
+ poc->oc_name, "Unknown required attribute type \"%s\"",
+ poc->oc_required[i]);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * schema_check_name:
+ * Check if the attribute or objectclass name is valid. Names can only contain
+ * characters, digits, and hyphens. In addition, names must begin with
+ * a character. If the nsslapd-attribute-name-exceptions attribute in cn=config
+ * is true, then we also allow underscores.
+ *
+ * XXX We're also supposed to allow semicolons, but we already use them to deal
+ * with attribute options XXX
+ *
+ * returns 1 if the attribute has a legal name
+ * 0 if not
+ *
+ * If the attribute name is invalid, an error message will be written to msg
+ */
+
+static int
+schema_check_name(char *name, PRBool isAttribute, char *errorbuf,
+ size_t errorbufsize )
+{
+ int i;
+
+ /* allowed characters */
+ static char allowed[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-";
+
+ /* additional characters to allow if allow_exceptions is true */
+ static char allowedExceptions[] = "_";
+ int allow_exceptions = config_get_attrname_exceptions();
+
+ if ( name == NULL || errorbuf == NULL) {
+ /* this is bad */
+ return 0;
+ }
+
+ /* attribute names must begin with a letter */
+ if ( (isascii (name[0]) == 0) || (isalpha (name[0]) == 0)) {
+ if ( (strlen(name) + 80) < BUFSIZ ) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ name, "The name is invalid. Names must begin with a letter" );
+ }
+ else {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ name, "The name is invalid, and probably too long. "
+ "Names must begin with a letter" );
+ }
+ return 0;
+ }
+
+ for (i = 1; name[i]; i++ ) {
+ if ( (NULL == strchr( allowed, name[i] )) &&
+ (!allow_exceptions ||
+ (NULL == strchr(allowedExceptions, name[i])) ) ) {
+ if ( (strlen(name) + 80) < BUFSIZ ) {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ name, "The name contains the invalid character \"%c\"", name[i] );
+ }
+ else {
+ schema_create_errormsg( errorbuf, errorbufsize, schema_errprefix_at,
+ name, "The name contains the invalid character \"%c\". The name"
+ " is also probably too long.", name[i] );
+ }
+ return 0;
+ }
+ }
+ return 1;
+}
+
+
+
+/*
+ * schema_check_oid:
+ * Check if the oid is valid.
+ *
+ * returns 1 if the attribute has a legal oid
+ * 0 if not
+ *
+ * If the oid is invalid, an error message will be written to errorbuf
+ *
+ * Oids can either have the form <attr/oc name>-oid or
+ * start and end with a digit, and contain only digits and periods
+ */
+
+static int
+schema_check_oid( const char *name, const char *oid, PRBool isAttribute,
+ char *errorbuf, size_t errorbufsize ) {
+
+ int i = 0, length_oid = 0, rc = 0;
+ char *namePlusOid = NULL;
+
+ if ( name == NULL || oid == NULL) {
+ /* this is bad */
+ LDAPDebug (LDAP_DEBUG_ANY, "NULL passed to schema_check_oid\n",0,0,0);
+ return 0;
+ }
+
+ /* check to see if the OID is <name>-oid */
+ namePlusOid = (char *) slapi_ch_malloc( strlen(name) + 256);
+ sprintf(namePlusOid, "%s-oid", name );
+ rc = strcasecmp( oid, namePlusOid );
+ slapi_ch_free( (void **) &namePlusOid );
+
+ if ( 0 == rc ) {
+ return 1;
+ }
+
+ /* If not, the OID must begin and end with a digit, and contain only
+ digits and dots */
+
+ /* check to see that it begins and ends with a digit */
+ length_oid = strlen(oid);
+ if ( !isdigit(oid[0]) ||
+ !isdigit(oid[length_oid-1]) ) {
+ schema_create_errormsg( errorbuf, errorbufsize,
+ isAttribute ? schema_errprefix_at : schema_errprefix_oc,
+ name,
+ "The OID \"%s\" must begin and end with a digit, or be \"%s-oid\"",
+ oid, name );
+ return 0;
+ }
+
+ /* check to see that it contains only digits and dots */
+ for ( i = 0; i < length_oid; i++ ) {
+ if ( !isdigit(oid[i]) && oid[i] != '.' ){
+ schema_create_errormsg( errorbuf, errorbufsize,
+ isAttribute ? schema_errprefix_at : schema_errprefix_oc,
+ name,
+ "The OID \"%s\" contains an invalid character: \"%c\"; the"
+ " OID must contain only digits and periods, or be \"%s-oid\"",
+ oid, oid[i], name );
+ return 0;
+ }
+ }
+
+ /* The oid is OK if we're here */
+ return 1;
+
+
+}
+
+
+/*
+ * Some utility functions for dealing with a dynamically
+ * allocated buffer.
+ */
+
+static struct sizedbuffer *sizedbuffer_construct(size_t size)
+{
+ struct sizedbuffer *p= (struct sizedbuffer *)slapi_ch_malloc(sizeof(struct sizedbuffer));
+ p->size= size;
+ if(size>0)
+ {
+ p->buffer= (char*)slapi_ch_malloc(size);
+ p->buffer[0]= '\0';
+ }
+ else
+ {
+ p->buffer= NULL;
+ }
+ return p;
+}
+
+static void sizedbuffer_destroy(struct sizedbuffer *p)
+{
+ if(p!=NULL)
+ {
+ slapi_ch_free((void**)&p->buffer);
+ }
+ slapi_ch_free((void**)&p);
+}
+
+static void sizedbuffer_allocate(struct sizedbuffer *p, size_t sizeneeded)
+{
+ if(p!=NULL)
+ {
+ if(sizeneeded>p->size)
+ {
+ if(p->buffer!=NULL)
+ {
+ slapi_ch_free((void**)&p->buffer);
+ }
+ p->buffer= (char*)slapi_ch_malloc(sizeneeded);
+ p->buffer[0]= '\0';
+ p->size= sizeneeded;
+ }
+ }
+}
+
+/*
+ * has_smart_referral: returns 1 if the entry contains a ref attribute,
+ * or a referral objectclass.
+ *
+ * Returns 0 If not.
+ */
+
+
+static int
+has_smart_referral( Slapi_Entry *e ) {
+
+ Slapi_Attr *aoc;
+ char ebuf[BUFSIZ];
+
+ /* Look for the ref attribute */
+ if ( (aoc = attrlist_find( e->e_attrs, "ref" )) != NULL ) {
+ LDAPDebug ( LDAP_DEBUG_ANY, "Entry \"%s\" contains a ref attrbute. Smart referrals are disabled in Directory Lite.\n", escape_string(slapi_entry_get_dn_const(e), ebuf),0,0 );
+ return 1;
+ }
+
+ /* Look for the referral objectclass */
+ if ( (aoc = attrlist_find( e->e_attrs, "objectclass" )) != NULL ) {
+ Slapi_Value target, *found;
+ slapi_value_init(&target);
+ slapi_value_set_string(&target,"referral");
+ found= slapi_valueset_find(aoc, &aoc->a_present_values, &target);
+ value_done(&target);
+ if(found!=NULL)
+ {
+ LDAPDebug ( LDAP_DEBUG_ANY, "Entry \"%s\" is a referral object class. Smart referrals are disabled in Directory Lite.\n", escape_string(slapi_entry_get_dn_const(e), ebuf),0,0 );
+ return 1;
+ }
+ }
+
+ /* No smart referral here */
+ return 0;
+}
+
+/*
+ * Check if the object class is extensible
+ */
+static int isExtensibleObjectclass(const char *objectclass)
+{
+ if ( strcasecmp( objectclass, "extensibleobject" ) == 0 ) {
+ return( 1 );
+ }
+ /* The Easter Egg is based on a special object class */
+ if ( strcasecmp( objectclass, EGG_OBJECT_CLASS ) == 0 ) {
+ return( 1 );
+ }
+ return 0;
+}
+
+
+
+/*
+ * strip_oc_options: strip any attribute options from the objectclass'
+ * attributes (remove things like ;binary from the attrs)
+ *
+ * argument: pointer to an objectclass, attributes will have their
+ * options removed in place
+ *
+ * returns: number of options removed
+ *
+ * Note: no locking of poc is needed because poc is always a newly allocated
+ * objclass struct (this function is only called by schema_check_oc_attrs,
+ * which is only called by add_oc_internal).
+ */
+
+static int
+strip_oc_options( struct objclass *poc ) {
+ int i, numRemoved = 0;
+ char *mod = NULL;
+
+ for ( i = 0; poc->oc_allowed && poc->oc_allowed[i]; i++ ) {
+ if ( (mod = stripOption( poc->oc_allowed[i] )) != NULL ){
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "Removed option \"%s\" from allowed attribute type "
+ "\"%s\" in object class \"%s\".\n",
+ mod, poc->oc_allowed[i], poc->oc_name );
+ numRemoved++;
+ }
+ }
+
+ for ( i = 0; poc->oc_required && poc->oc_required[i]; i++ ) {
+ if ( (mod = stripOption( poc->oc_required[i] )) != NULL ){
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "Removed option \"%s\" from required attribute type "
+ "\"%s\" in object class \"%s\".\n",
+ mod, poc->oc_required[i], poc->oc_name );
+ numRemoved++;
+ }
+ }
+ return numRemoved;
+}
+
+
+/*
+ * stripOption:
+ * removes options such as ";binary" from attribute names
+ *
+ * argument: pointer to an attribute name, such as "userCertificate;binary"
+ *
+ * returns: pointer to the option, such as "binary"
+ * NULL if there's no option
+ *
+ */
+
+static char *
+stripOption(char *attr) {
+ char *pSemiColon = strchr( attr, ';' );
+
+ if (pSemiColon) {
+ *pSemiColon = '\0';
+ }
+
+ return pSemiColon ? pSemiColon + 1 : NULL;
+}
+
+
+/*
+ * load_schema_dse: called by dse_read_file() when target is cn=schema
+ *
+ * Initialize attributes and objectclasses from the schema
+ *
+ * Note that this function removes all values for `attributetypes'
+ * and `objectclasses' attributes from the entry `e'.
+ *
+ * returntext is always at least SLAPI_DSE_RETURNTEXT_SIZE bytes in size.
+ */
+int
+load_schema_dse(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *ignored,
+ int *returncode, char *returntext, void *arg)
+{
+ Slapi_Attr *attr = 0;
+ int nolock = 1; /* don't lock global resources during initialization */
+ int primary_file = 0; /* this is the primary (writeable) schema file */
+ int schema_ds4x_compat = config_get_ds4_compatible_schema();
+
+ *returncode = 0;
+
+ /*
+ * Note: there is no need to call schema_lock_write() here because this
+ * function is only called during server startup.
+ */
+
+ slapi_pblock_get( pb, SLAPI_DSE_IS_PRIMARY_FILE, &primary_file );
+
+ if (!slapi_entry_attr_find(e, "attributetypes", &attr) && attr)
+ {
+ /* enumerate the values in attr */
+ Slapi_Value *v = 0;
+ int index = 0;
+ for (index = slapi_attr_first_value(attr, &v);
+ v && (index != -1);
+ index = slapi_attr_next_value(attr, index, &v))
+ {
+ const char *s = slapi_value_get_string(v);
+ if (!s)
+ continue;
+ if ((*returncode = read_at_ldif(s, NULL, returntext,
+ SLAPI_DSE_RETURNTEXT_SIZE, nolock,
+ primary_file /* force user defined? */,
+ schema_ds4x_compat, 0)) != 0)
+ break;
+ }
+ slapi_entry_attr_delete(e, "attributetypes");
+ }
+
+ if (*returncode)
+ return SLAPI_DSE_CALLBACK_ERROR;
+
+ if (!slapi_entry_attr_find(e, "objectclasses", &attr) && attr)
+ {
+ /* enumerate the values in attr */
+ Slapi_Value *v = 0;
+ int index = 0;
+ for (index = slapi_attr_first_value(attr, &v);
+ v && (index != -1);
+ index = slapi_attr_next_value(attr, index, &v))
+ {
+ struct objclass *oc = 0;
+ const char *s = slapi_value_get_string(v);
+ if (!s)
+ continue;
+ if ( LDAP_SUCCESS != (*returncode = read_oc_ldif(s, &oc, returntext,
+ SLAPI_DSE_RETURNTEXT_SIZE, nolock,
+ primary_file /* force user defined? */,
+ schema_ds4x_compat))) {
+ break;
+ }
+ if ( LDAP_SUCCESS != (*returncode = add_oc_internal(oc, returntext,
+ SLAPI_DSE_RETURNTEXT_SIZE, schema_ds4x_compat))) {
+ oc_free( &oc );
+ break;
+ }
+ }
+ slapi_entry_attr_delete(e, "objectclasses");
+ }
+
+ /* Set the schema CSN */
+ if (!slapi_entry_attr_find(e, "nsschemacsn", &attr) && attr)
+ {
+ Slapi_Value *v = NULL;
+ slapi_attr_first_value(attr, &v);
+ if (NULL != v) {
+ const char *s = slapi_value_get_string(v);
+ if (NULL != s) {
+ CSN *csn = csn_new_by_string(s);
+ g_set_global_schema_csn(csn);
+ }
+ }
+ }
+
+ return (*returncode == LDAP_SUCCESS) ? SLAPI_DSE_CALLBACK_OK
+ : SLAPI_DSE_CALLBACK_ERROR;
+}
+
+/*
+ * Try to initialize the schema from the LDIF file. Read
+ * the file and convert it to the avl tree of DSEs. If the
+ * file doesn't exist, we try to create it and put a minimal
+ * schema entry into it.
+ *
+ * Returns 1 for OK, 0 for Fail.
+ */
+int
+init_schema_dse(const char *configdir)
+{
+ int rc= 1; /* OK */
+ char *schemadir = 0;
+ char *userschemafile = 0;
+ char *userschematmpfile = 0;
+ char **filelist = 0;
+ Slapi_DN schema;
+
+ slapi_sdn_init_dn_byref(&schema,"cn=schema");
+
+ schemadir = slapi_ch_calloc(1, strlen(configdir)
+ + strlen(SCHEMA_SUBDIR_NAME) + 5);
+ sprintf(schemadir, "%s/%s", configdir, SCHEMA_SUBDIR_NAME);
+
+ filelist = get_priority_filelist(schemadir, ".*ldif$");
+ if (!filelist || !*filelist)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "schema",
+ "No schema files were found in the directory %s\n", schemadir);
+ free_filelist(filelist);
+ rc = 0;
+ }
+ else
+ {
+ /* figure out the last file in the list; it is the user schema */
+ int ii = 0;
+ while (filelist[ii]) ++ii;
+ userschemafile = filelist[ii-1];
+ userschematmpfile = slapi_ch_calloc(1, strlen(userschemafile) + 5);
+ sprintf(userschematmpfile, "%s.tmp", userschemafile);
+ }
+
+ if(rc && (pschemadse==NULL))
+ {
+ pschemadse= dse_new_with_filelist(userschemafile,userschematmpfile, NULL, NULL,
+ schemadir,filelist);
+ PR_ASSERT(pschemadse);
+ if ((rc= (pschemadse!=NULL)) != 0)
+ dse_register_callback(pschemadse,DSE_OPERATION_READ,DSE_FLAG_PREOP,&schema,
+ LDAP_SCOPE_BASE,NULL,
+ load_schema_dse,NULL);
+ slapi_ch_free((void**)&userschematmpfile);
+ }
+ slapi_ch_free((void**)&schemadir);
+
+ if(rc)
+ {
+ char errorbuf[SLAPI_DSE_RETURNTEXT_SIZE] = {0};
+ int dont_write = 1;
+ int merge = 1;
+ int dont_dup_check = 1;
+ Slapi_PBlock pb;
+ memset(&pb, 0, sizeof(pb));
+ /* don't write out the file when reading */
+ slapi_pblock_set(&pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, (void*)&dont_write);
+ /* duplicate entries are allowed */
+ slapi_pblock_set(&pb, SLAPI_DSE_MERGE_WHEN_ADDING, (void*)&merge);
+ /* use the non duplicate checking str2entry */
+ slapi_pblock_set(&pb, SLAPI_DSE_DONT_CHECK_DUPS, (void*)&dont_dup_check);
+
+ /* add the objectclass attribute so we can do some basic schema
+ checking during initialization; this will be overridden when
+ its "real" definition is read from the schema conf files */
+ rc = read_at_ldif("attributeTypes: ( 2.5.4.0 NAME 'objectClass' "
+ "DESC 'Standard schema for LDAP' SYNTAX "
+ "1.3.6.1.4.1.1466.115.121.1.15 X-ORIGIN 'RFC 2252' )",
+ NULL, errorbuf, SLAPI_DSE_RETURNTEXT_SIZE, 1, 0, 0, 0);
+ if (rc)
+ {
+ slapi_log_error(SLAPI_LOG_FATAL, "schema", "Could not add"
+ " attribute type \"objectClass\" to the schema: %s\n",
+ errorbuf, 0, 0);
+ }
+
+ rc = dse_read_file(pschemadse, &pb);
+ }
+
+ if (rc)
+ {
+ /* make sure the schema is normalized */
+ normalize_oc();
+
+ /* register callbacks */
+ dse_register_callback(pschemadse,SLAPI_OPERATION_SEARCH,DSE_FLAG_PREOP,&schema,
+ LDAP_SCOPE_BASE,NULL,read_schema_dse,NULL);
+ dse_register_callback(pschemadse,SLAPI_OPERATION_MODIFY,DSE_FLAG_PREOP,&schema,
+ LDAP_SCOPE_BASE,NULL,modify_schema_dse,NULL);
+ dse_register_callback(pschemadse,SLAPI_OPERATION_DELETE,DSE_FLAG_PREOP,&schema,
+ LDAP_SCOPE_BASE,NULL,dont_allow_that,NULL);
+ dse_register_callback(pschemadse,DSE_OPERATION_WRITE,DSE_FLAG_PREOP,&schema,
+ LDAP_SCOPE_BASE,NULL,refresh_user_defined_schema,
+ NULL);
+
+ if (rc) {
+ Slapi_Backend *be;
+
+ /* add as a backend */
+ be= be_new_internal(pschemadse,"DSE", "schema-internal"); /* JCM - should be a #define */
+ be_addsuffix(be,&schema);
+ }
+ }
+
+ slapi_sdn_done(&schema);
+ return rc;
+}
+
+
+
+/*
+ * Look for `keyword' within `*inputp' and return the flag_value if found
+ * (zero if returned if not found).
+ *
+ * If the keyword is found, `*inputp' is set to point just beyond the end of
+ * the keyword. If the keyword is not found, `*inputp' is not changed.
+ *
+ * The `strstr_fn' function pointer is used to search for `keyword', e.g., it
+ * could be PL_strcasestr().
+ *
+ * The string passed in `keyword' MUST include a trailing space, e.g.,
+ *
+ * flag |= get_flag_keyword( " COLLECTIVE ", SLAPI_ATTR_FLAG_COLLECTIVE,
+ * &input, PL_strcasestr );
+ *
+ */
+static int
+get_flag_keyword( const char *keyword, int flag_value, const char **inputp,
+ schema_strstr_fn_t strstr_fn )
+{
+ const char *kw;
+
+ PR_ASSERT( NULL != inputp );
+ PR_ASSERT( NULL != *inputp );
+ PR_ASSERT( ' ' == keyword[ strlen( keyword ) - 1 ] );
+
+ if ( NULL == strstr_fn ) {
+ strstr_fn = PL_strcasestr;
+ }
+
+ kw = (*strstr_fn)( *inputp, keyword );
+ if ( NULL == kw ) {
+ flag_value = 0; /* not found -- return no value */
+ } else {
+ *inputp = kw + strlen( keyword ) - 1; /* advance input */
+ }
+
+ return flag_value;
+}
+
+/*
+ * Look for `tag' within `*inputp' and return the OID string following `tag'.
+ * If the OID has single quotes around it they are removed (they are allowed
+ * for compatibility with DS 3.x and 4.x).
+ *
+ * If the tag is found, `*inputp' is set to point just beyond the end of
+ * the OID that was extracted and returned. If the tag is not found,
+ * `*inputp' is not changed.
+ *
+ * The `strstr_fn' function pointer is used to search for `tag', e.g., it
+ * could be PL_strcasestr().
+ *
+ * The string passed in `tag' MUST include a trailing space, e.g.,
+ *
+ * pSuperior = get_tagged_oid( "SUP ", &input, PL_strcasestr );
+ *
+ * A malloc'd string is returned if `tag; is found and NULL if not.
+ */
+static char *
+get_tagged_oid( const char *tag, const char **inputp,
+ schema_strstr_fn_t strstr_fn )
+{
+ const char *startp, *endp;
+ char *oid;
+
+ PR_ASSERT( NULL != inputp );
+ PR_ASSERT( NULL != *inputp );
+ PR_ASSERT( NULL != tag );
+ PR_ASSERT( '\0' != tag[ 0 ] );
+ if('(' !=tag[0])
+ PR_ASSERT( ' ' == tag[ strlen( tag ) - 1 ] );
+
+ if ( NULL == strstr_fn ) {
+ strstr_fn = PL_strcasestr;
+ }
+
+ oid = NULL;
+ if ( NULL != ( startp = (*strstr_fn)( *inputp, tag ))) {
+ startp += strlen( tag );
+
+ /* skip past any extra white space */
+ if ( NULL == ( startp = skipWS( startp ))) {
+ return( NULL );
+ }
+
+ /* skip past the leading single quote, if present */
+ if ( *startp == '\'' ) {
+ ++startp;
+ /* skip past any extra white space */
+ startp = skipWS( startp );
+ }
+
+ /* locate the end of the OID */
+ if ((NULL != ( endp = strchr( startp, ' '))) ||
+ (NULL != (endp = strchr( startp, ')'))) ) {
+ if ( '\'' == *(endp-1) && endp > startp ) {
+ --endp; /* ignore trailing quote */
+ }
+ } else {
+ endp = startp + strlen( startp ); /* remainder of input */
+ }
+
+ oid = slapi_ch_malloc( endp - startp + 1 );
+ memcpy( oid, startp, endp - startp );
+ oid[ endp - startp ] = '\0';
+ *inputp = endp;
+ }
+
+ return( oid );
+}
+
+
+/*
+ * sprintf to `outp' the contents of `tag' followed by `oid' followed by a
+ * trailing space. If enquote is non-zero, single quotes are included
+ * around the `oid' string. If `suffix' is not NULL, it is output directly
+ * after the `oid' (before the trailing space).
+ * Note that `tag' should typically include a trailing space, e.g.,
+ *
+ * outp += put_tagged_oid( outp, "SUP ", "1.2.3.4", NULL, enquote_oids );
+ *
+ * Returns the number of bytes copied to `outp' or 0 if `oid' is NULL.
+ */
+static int
+put_tagged_oid( char *outp, const char *tag, const char *oid,
+ const char *suffix, int enquote )
+{
+ int count = 0;
+
+ if ( NULL == suffix ) {
+ suffix = "";
+ }
+
+ if ( NULL != oid ) {
+ if ( enquote ) {
+ count = sprintf( outp, "%s'%s%s' ", tag, oid, suffix );
+ } else {
+ count = sprintf( outp, "%s%s%s ", tag, oid, suffix );
+ }
+ }
+
+ return( count );
+}
+
+
+/*
+ * Add to `buf' a string of the form:
+ *
+ * prefix SPACE ( oid1 $ oid2 ... ) SPACE
+ * OR
+ * prefix SPACE oid SPACE
+ *
+ * The part after <prefix> matches the `oids' definition
+ * from RFC 2252 section 4.1.
+ *
+ * If oids is NULL or an empty array, `buf' is not touched.
+ */
+static void
+strcat_oids( char *buf, char *prefix, char **oids, int schema_ds4x_compat )
+{
+ char *p;
+ int i;
+
+ if ( NULL != oids && NULL != oids[0] ) {
+ p = buf + strlen(buf); /* skip past existing content */
+ if ( NULL == oids[1] && !schema_ds4x_compat ) {
+ sprintf( p, "%s %s ", prefix, oids[0] ); /* just one oid */
+ } else {
+ sprintf( p, "%s ( ", prefix ); /* oidlist */
+ for ( i = 0; oids[i] != NULL; ++i ) {
+ if ( i > 0 ) {
+ strcat( p, " $ " );
+ }
+ strcat( p, oids[i] );
+ }
+ strcat( p, " ) " );
+ }
+ }
+}
+
+
+/*
+ * Add to `buf' a string of the form:
+ *
+ * prefix SPACE ( 's1' 's2' ... ) SPACE
+ * OR
+ * prefix SPACE 's1' SPACE
+ *
+ * The part after <prefix> matches the qdescs definition
+ * from RFC 2252 section 4.1.
+ *
+ * A count of the number of bytes added to buf or needed is returned.
+ *
+ * If buf is NULL, no copying is done but the number of bytes needed
+ * is calculated and returned. This is useful if you need to allocate
+ * space before calling this function will a buffer.
+ *
+ * If qdlist is NULL or an empty array, `buf' is not touched and zero
+ * is returned.
+ */
+static size_t
+strcat_qdlist( char *buf, char *prefix, char **qdlist )
+{
+ int i;
+ char *start, *p;
+ size_t len = 0;
+
+ if ( NULL != qdlist && NULL != qdlist[0] ) {
+ if ( NULL == buf ) { /* calculate length only */
+ len += strlen( prefix );
+ if ( NULL != qdlist[1] ) {
+ len += 4; /* surrounding spaces and '(' and ')' */
+ }
+ for ( i = 0; NULL != qdlist[i]; ++i ) {
+ len += 3; /* leading space and quote marks */
+ len += strlen(qdlist[i]);
+ }
+ ++len; /* trailing space */
+
+ } else {
+ p = start = buf + strlen(buf); /* skip past existing content */
+ if ( NULL == qdlist[1] ) { /* just one string */
+ p += sprintf( p, "%s '%s' ", prefix, qdlist[0] );
+ } else { /* a list of strings */
+ p += sprintf( p, "%s (", prefix );
+ for ( i = 0; qdlist[i] != NULL; ++i ) {
+ p += sprintf( p, " '%s'", qdlist[i] );
+ }
+ *p++ = ' ';
+ *p++ = ')';
+ *p++ = ' ';
+ *p = '\0';
+ }
+ len = p - start;
+ }
+ }
+
+ return( len );
+}
+
+
+/*
+ * Just like strlen() except that 0 is returned if `s' is NULL.
+ */
+static size_t
+strlen_null_ok(const char *s)
+{
+ if ( NULL == s ) {
+ return( 0 );
+ }
+
+ return( strlen( s ));
+}
+
+
+
+/*
+ * Like strcpy() except a count of the number of bytes copied is returned.
+ */
+static int
+strcpy_count( char *dst, const char *src )
+{
+ char *p;
+
+ p = dst;
+ while ( *src != '\0' ) {
+ *p++ = *src++;
+ }
+
+ *p = '\0';
+ return( p - dst );
+}
+
+
+/*
+ * Look for an X-ORIGIN list in `schema_value' and return a
+ * qdstrings array (or NULL if no list is present). *num_originsp is
+ * set to a count of the number of origin strings returned.
+ *
+ * If no X-ORIGIN list is found and `default_list' is non-NULL, a copy
+ * of default list is returned.
+ */
+static char **
+parse_origin_list( const char *schema_value, int *num_originsp,
+ char **default_list )
+{
+ char *start, *end, *origin_tmp;
+ char **origins = NULL;
+
+ if (( start = PL_strstr ( schema_value, "X-ORIGIN ")) != NULL ) {
+ start += 9;
+ origin_tmp = slapi_ch_strdup( start );
+ if ( *start == '(' ) {
+ end = strchr( origin_tmp, ')' );
+ } else {
+ end = strchr( origin_tmp + 1, '\'' );
+ }
+ if (end) {
+ *(end+1) = 0;
+ }
+ origins = parse_qdstrings( origin_tmp, num_originsp );
+ slapi_ch_free( (void **)&origin_tmp );
+ } else {
+ origins = NULL;
+ *num_originsp = 0;
+ }
+
+ if ( NULL == origins && NULL != default_list ) {
+ int i;
+
+ for ( i = 0; default_list[i] != NULL; ++i ) {
+ ;
+ }
+ *num_originsp = i;
+ origins = (char **)slapi_ch_malloc( (i+1) * sizeof(char *));
+ for ( i = 0; default_list[i] != NULL; ++i ) {
+ origins[i] = slapi_ch_strdup( default_list[i] );
+ }
+ origins[i] = NULL;
+ }
+
+if ( origins == NULL || origins[0] == NULL ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "no origin (%s)\n", schema_value, 0, 0 );
+}
+
+ return origins;
+}
+
+
+/*
+ * Determine based on origin whether a schema element is standard or
+ * user-defined. Algorithm: perform a case insensitive search for
+ * "user defined". If found, return 1 (user defined); if not, return 0.
+ */
+static int
+element_is_user_defined( char * const *origins )
+{
+ int i;
+
+ if ( origins != NULL ) {
+ for ( i = 0; origins[i] != NULL; ++i ) {
+ if ( 0 == strcasecmp( schema_user_defined_origin[0], origins[i] )) {
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+ * Return PR_TRUE if the attribute type named 'type' is one of those that
+ * we handle directly in this file (in the scheme DSE callbacks).
+ * Other types are handled by the generic DSE code in dse.c.
+ */
+/* subschema DSE attribute types we handle within the DSE callback */
+static char *schema_interesting_attr_types[] = {
+ "dITStructureRules",
+ "nameForms",
+ "dITContentRules",
+ "objectClasses",
+ "attributeTypes",
+ "matchingRules",
+ "matchingRuleUse",
+ "ldapSyntaxes",
+ "nsschemacsn",
+ NULL
+};
+
+
+static PRBool
+schema_type_is_interesting( const char *type )
+{
+ int i;
+
+ for ( i = 0; schema_interesting_attr_types[i] != NULL; ++i ) {
+ if ( 0 == strcasecmp( type, schema_interesting_attr_types[i] )) {
+ return PR_TRUE;
+ }
+ }
+
+ return PR_FALSE;
+}
+
+
+static void
+schema_create_errormsg(
+ char *errorbuf,
+ size_t errorbufsize,
+ const char *prefix,
+ const char *name,
+ const char *fmt,
+ ...
+)
+{
+ if ( NULL != errorbuf ) {
+ va_list ap;
+ int rc = 0;
+
+ va_start( ap, fmt );
+
+ if ( NULL != name ) {
+ rc = PR_snprintf( errorbuf, errorbufsize, prefix, name );
+ }
+ if ( rc >= 0 ) {
+ (void)PR_vsnprintf( errorbuf + rc, errorbufsize - rc, fmt, ap );
+ }
+ va_end( ap );
+ }
+}
+
+
+/*
+ * va_locate_oc_val finds an objectclass within the array of values in va.
+ * First oc_name is used, falling back to oc_oid. oc_oid can be NULL.
+ * oc_name and oc_oid should be official names (no trailing spaces). But
+ * trailing spaces within the va are ignored if appropriate.
+ *
+ * Returns >=0 if found (index into va) and -1 if not found.
+ */
+static int
+va_locate_oc_val( Slapi_Value **va, const char *oc_name, const char *oc_oid )
+{
+ int i;
+ const char *strval;
+
+ if ( NULL == va || oc_name == NULL ) { /* nothing to look for */
+ return -1;
+ }
+
+ if ( !schema_ignore_trailing_spaces ) {
+ for ( i = 0; va[i] != NULL; i++ ) {
+ strval = slapi_value_get_string(va[i]);
+ if ( NULL != strval ) {
+ if ( 0 == strcasecmp(strval, oc_name)) {
+ return i;
+ }
+
+ if ( NULL != oc_oid
+ && 0 == strcasecmp( strval, oc_oid )) {
+ return i;
+ }
+ }
+ }
+ } else {
+ /*
+ * Ignore trailing spaces when comparing object class names.
+ */
+ size_t len;
+ const char *p;
+
+ for ( i = 0; va[i] != NULL; i++ ) {
+ strval = slapi_value_get_string(va[i]);
+ if ( NULL != strval ) {
+ for ( p = strval, len = 0; (*p != '\0') && (*p != ' ');
+ p++, len++ ) {
+ ; /* NULL */
+ }
+
+ if ( 0 == strncasecmp(oc_name, strval, len )
+ && ( len == strlen(oc_name))) {
+ return i;
+ }
+
+ if ( NULL != oc_oid
+ && ( 0 == strncasecmp( oc_oid, strval, len ))
+ && ( len == strlen(oc_oid))) {
+ return i;
+ }
+ }
+ }
+ }
+
+ return -1; /* not found */
+}
+
+
+/*
+ * va_expand_one_oc is used to add missing superclass values to the
+ * objectclass attribute when an entry is added or modified.
+ *
+ * missing values are always added to the end of the 'vap' array.
+ *
+ * Note: calls to this function MUST be bracketed by lock()/unlock(), i.e.,
+ *
+ * oc_lock_read();
+ * va_expand_one_oc( b, o );
+ * oc_unlock();
+ */
+static void
+va_expand_one_oc( const char *dn, Slapi_Value ***vap, const char *ocs )
+{
+ struct objclass *this_oc, *sup_oc;
+ int p,i;
+ Slapi_Value **newva;
+ char ebuf[BUFSIZ];
+
+ this_oc = oc_find_nolock( ocs );
+
+ if ( this_oc == NULL ) {
+ return; /* skip unknown object classes */
+ }
+
+ if ( this_oc->oc_superior == NULL ) {
+ return; /* no superior */
+ }
+
+ sup_oc = oc_find_nolock( this_oc->oc_superior );
+ if ( sup_oc == NULL ) {
+ return; /* superior is unknown -- ignore */
+ }
+
+ p = va_locate_oc_val( *vap, sup_oc->oc_name, sup_oc->oc_oid );
+
+ if ( p != -1 ) {
+ return; /* value already present -- done! */
+ }
+
+ /* parent was not found. add to the end */
+ for ( i = 0; (*vap)[i] != NULL; i++ ) {
+ ;
+ }
+
+ /* prevent loops: stop if more than 1000 OC values are present */
+ if ( i > 1000 ) {
+ return;
+ }
+
+ newva = (Slapi_Value **)slapi_ch_realloc( (char *)*vap,
+ ( i + 2 )*sizeof(Slapi_Value **));
+
+ newva[i] = slapi_value_new_string(sup_oc->oc_name);
+ newva[i+1] = NULL;
+
+ *vap = newva;
+ LDAPDebug( LDAP_DEBUG_TRACE,
+ "Entry \"%s\": added missing objectClass value %s\n",
+ escape_string( dn, ebuf ), sup_oc->oc_name, 0 );
+}
+
+
+/*
+ * Expand the objectClass values in 'e' to take superior classes into account.
+ * All missing superior classes are added to the objectClass attribute, as
+ * is 'top' if it is missing.
+ */
+void
+slapi_schema_expand_objectclasses( Slapi_Entry *e )
+{
+ Slapi_Attr *sa;
+ Slapi_Value **va;
+ const char *dn = slapi_entry_get_dn_const( e );
+ int i;
+
+ if ( 0 != slapi_entry_attr_find( e, SLAPI_ATTR_OBJECTCLASS, &sa )) {
+ return; /* no OC values -- nothing to do */
+ }
+
+ va = attr_get_present_values( sa );
+
+ if ( va == NULL || va[0] == NULL ) {
+ return; /* no OC values -- nothing to do */
+ }
+
+ oc_lock_read();
+
+ /*
+ * This loop relies on the fact that bv_expand_one_oc()
+ * always adds to the end
+ */
+ for ( i = 0; va[i] != NULL; ++i ) {
+ if ( NULL != slapi_value_get_string(va[i]) ) {
+ va_expand_one_oc( dn, &va, slapi_value_get_string(va[i]) );
+ }
+ }
+
+ /* top must always be present */
+ va_expand_one_oc( dn, &va, "top" );
+
+ /*
+ * Reset the present values in the set because we may have realloc'd it.
+ * Note that this is the counterpart to the attr_get_present_values()
+ * call we made above... nothing new has been allocated, but sa holds
+ * a pointer to the original (pre realloc) va.
+ */
+ sa->a_present_values.va = va;
+
+ oc_unlock();
+}
diff --git a/ldap/servers/slapd/schemaparse.c b/ldap/servers/slapd/schemaparse.c
new file mode 100644
index 00000000..c6fb51fe
--- /dev/null
+++ b/ldap/servers/slapd/schemaparse.c
@@ -0,0 +1,262 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* schemaparse.c - routines to support objectclass definitions */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "slap.h"
+
+
+/* global_oc and global_schema_csn are both protected by oc locks */
+struct objclass *global_oc;
+CSN *global_schema_csn = NULL; /* Timestamp for last update CSN. NULL = epoch */
+
+static int is_duplicate( char *target, char **list, int list_max );
+static void normalize_list( char **list );
+
+
+
+/* R/W lock used to protect the global objclass linked list. */
+static PRRWLock *oc_lock = NULL;
+
+/*
+ * The oc_init_lock_callonce structure is used by NSPR to ensure
+ * that oc_init_lock() is called at most once.
+ */
+static PRCallOnceType oc_init_lock_callonce = { 0, 0, 0 };
+
+
+/* Create the objectclass read/write lock. Returns PRSuccess if successful */
+static PRStatus
+oc_init_lock( void )
+{
+ if ( NULL == ( oc_lock = PR_NewRWLock( PR_RWLOCK_RANK_NONE,
+ "objectclass rwlock" ))) {
+ slapi_log_error( SLAPI_LOG_FATAL, "oc_init_lock",
+ "PR_NewRWLock() for objectclass lock failed\n" );
+ return PR_FAILURE;
+ }
+
+ return PR_SUCCESS;
+}
+
+
+void
+oc_lock_read( void )
+{
+ if ( NULL != oc_lock ||
+ PR_SUCCESS == PR_CallOnce( &oc_init_lock_callonce, oc_init_lock )) {
+ PR_RWLock_Rlock( oc_lock );
+ }
+}
+
+
+void
+oc_lock_write( void )
+{
+ if ( NULL != oc_lock ||
+ PR_SUCCESS == PR_CallOnce( &oc_init_lock_callonce, oc_init_lock )) {
+ PR_RWLock_Wlock( oc_lock );
+ }
+}
+
+
+void
+oc_unlock( void )
+{
+ if ( oc_lock != NULL ) {
+ PR_RWLock_Unlock( oc_lock );
+ }
+}
+
+
+/*
+ * Note: callers of g_get_global_oc_nolock() must hold a read or write lock
+ */
+struct objclass* g_get_global_oc_nolock()
+{
+ return global_oc;
+}
+
+/*
+ * Note: callers of g_set_global_oc_nolock() must hold a write lock
+ */
+void
+g_set_global_oc_nolock( struct objclass *newglobaloc )
+{
+ global_oc = newglobaloc;
+}
+
+/*
+ * Note: callers of g_get_global_schema_csn() must hold a read lock
+ */
+const CSN *
+g_get_global_schema_csn()
+{
+ return global_schema_csn;
+}
+
+/*
+ * Note: callers of g_set_global_schema_csn() must hold a write lock.
+ * csn is consumed.
+ */
+void
+g_set_global_schema_csn(CSN *csn)
+{
+ CSN *tmp = NULL;
+ if (NULL != global_schema_csn)
+ {
+ tmp = global_schema_csn;
+ }
+ global_schema_csn = csn;
+ if (NULL != tmp)
+ {
+ csn_free(&tmp);
+ }
+}
+
+/*
+ * There are two kinds of objectclasses:
+ * Standard Objectclasses and User Defined Objectclasses
+ *
+ * Standard Objectclasses are the objectclasses which come with the Directory Server.
+ * These objectclasses are always expected to be there and shouldn't be accidentally
+ * changed by the end user. We dont' allow these objectclasses to be deleted, and the
+ * admin CGIs will not allow the end user to change their definitions. However, we
+ * will allow these objectclasses to be redefined via ldap_modify, by doing an LDAP_MOD_ADD.
+ * The new definition will override the previous definition. The updated objectclass
+ * will be written out the 00user.ldif and the original definition will stay
+ * whereever it was originally defined. At startup, slapd will use the last definition
+ * read as the real definition of an objectclass.
+ *
+ * User Defined ObjectClasses are objectclasses which were added to the Directory Server
+ * by the end user. These objectclasses are also kept in 99user.ldif. These objectclasses
+ * can be deleted by the end user.
+ *
+ * Every objectclass contains an array of attributes called oc_orig_required,
+ * which are the required attributes for that objectclass which were not inherited from
+ * any other objectclass. Likewise, there's also an array called oc_orig_allowed which
+ * contains the allowed attributes which were not inherited from any other objectclass.
+ *
+ * The arrays oc_required and oc_allowed contain all the required and allowed attributes for
+ * that objectclass, including the ones inherited from its parent and also the ones in
+ * oc_orig_required and oc_orig_allowed.
+ *
+ * When an oc is updated, we go through the global list of objectclasses and see if
+ * any ocs inherited from it. If so, we delete its oc_required and oc_allowed arrays,
+ * copy the oc_orig_required and oc_orig_allowed arrays to oc_required and oc_allowed,
+ * and then merge the parent's oc_required and oc_allowed onto oc_required and oc_allowed.
+ *
+ *
+ */
+
+
+static int
+is_duplicate( char *target, char **list, int list_size ) {
+ int i;
+ for ( i = 0; i < list_size; i++ ) {
+ if ( !strcasecmp( target, list[i] ) ) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Make normalized copies of all non-duplicate values in a list; free all old
+ * values. The list is not resized.
+ */
+static void
+normalize_list( char **list ) {
+ int i, j;
+
+ for ( i = 0, j = 0; list != NULL && list[i] != NULL; i++ ) {
+ char *norm = slapi_attr_syntax_normalize( list[i] );
+ char *save = list[i];
+ if ( !is_duplicate( norm, list, j ) ) {
+ list[j++] = norm;
+ } else {
+ slapi_ch_free((void **)&norm );
+ }
+ slapi_ch_free((void**)&save );
+ }
+ for ( ; j < i; j++ ) {
+ list[j] = NULL;
+ }
+}
+
+/*
+ * normalize types contained in object class definitions. do this
+ * after the whole config file is read so there is no order dependency
+ * on inclusion of attributes and object classes.
+ */
+
+void
+normalize_oc( void )
+{
+ struct objclass *oc;
+
+ oc_lock_write();
+
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
+ LDAPDebug (LDAP_DEBUG_PARSE,
+ "normalize_oc: normalizing '%s'\n", oc->oc_name, 0, 0);
+ /* required attributes */
+ normalize_list( oc->oc_required );
+ normalize_list( oc->oc_orig_required );
+
+ /* optional attributes */
+ normalize_list( oc->oc_allowed );
+ normalize_list( oc->oc_orig_allowed );
+ }
+
+ oc_unlock();
+}
+
+/*
+ * oc_update_inheritance_nolock:
+ * If an objectclass is redefined, we need to make sure that any objectclasses
+ * which inherit from the redefined objectclass have their required and allowed
+ * attributes updated.
+ *
+ * Every objectclass contains an array of attributes called oc_orig_required,
+ * which are the required attributes for that objectclass which were not inherited from
+ * any other objectclass. Likewise, there's also an array called oc_orig_allowed which
+ * contains the allowed attributes which were not inherited from any other objectclass.
+ *
+ * The arrays oc_required and oc_allowed contain all the required and allowed attributes for
+ * that objectclass, including the ones inherited from its parent and also the ones in
+ * oc_orig_required and oc_orig_allowed.
+ *
+ * When an oc is updated, we go through the global list of objectclasses and see if
+ * any ocs inherited from it. If so, we delete its oc_requried and oc_allowed arrays,
+ * copy the oc_orig_required and oc_orig_allowed arrays to oc_required and oc_allowed,
+ * and then merge the parent's oc_required and oc_allowed onto oc_required and oc_allowed.
+ */
+
+void
+oc_update_inheritance_nolock( struct objclass *psuperior_oc )
+{
+ struct objclass *oc;
+
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next ) {
+ if ( oc->oc_superior &&
+ (strcasecmp( oc->oc_superior, psuperior_oc->oc_name ) == 0) ) {
+ if (oc->oc_required ) {
+ charray_free (oc->oc_required);
+ }
+ if (oc->oc_allowed) {
+ charray_free (oc->oc_allowed);
+ }
+ oc->oc_required = charray_dup ( oc->oc_orig_required );
+ oc->oc_allowed = charray_dup ( oc->oc_orig_allowed );
+ charray_merge ( &(oc->oc_required), psuperior_oc->oc_required, 1 );
+ charray_merge ( &(oc->oc_allowed), psuperior_oc->oc_allowed, 1 );
+ oc_update_inheritance_nolock ( oc );
+ }
+ }
+}
diff --git a/ldap/servers/slapd/search.c b/ldap/servers/slapd/search.c
new file mode 100644
index 00000000..471d3157
--- /dev/null
+++ b/ldap/servers/slapd/search.c
@@ -0,0 +1,283 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "slap.h"
+#include "pratom.h"
+#include "snmp_collator.h"
+
+static void log_search_access (Slapi_PBlock *pb, const char *base, int scope, const char *filter, const char *msg);
+
+void
+do_search( Slapi_PBlock *pb )
+{
+ Slapi_Operation *operation;
+ BerElement *ber;
+ int i, err;
+ int scope, deref, attrsonly;
+ int sizelimit, timelimit;
+ long long_scope,long_deref,long_sizelimit,long_timelimit;
+ char *base = NULL, *fstr = NULL;
+ struct slapi_filter *filter = NULL;
+ char **attrs = NULL;
+ int psearch = 0;
+ struct berval *psbvp;
+ int changetypes;
+ int send_entchg_controls;
+ int changesonly = 0;
+ int rc = -1;
+ char *original_base = 0;
+ char *new_base = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_search\n", 0, 0, 0 );
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ ber = operation->o_ber;
+
+ /* count the search request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsSearchOps);
+
+ /*
+ * Parse the search request. It looks like this:
+ *
+ * SearchRequest := [APPLICATION 3] SEQUENCE {
+ * baseObject DistinguishedName,
+ * scope ENUMERATED {
+ * baseObject (0),
+ * singleLevel (1),
+ * wholeSubtree (2)
+ * },
+ * derefAliases ENUMERATED {
+ * neverDerefaliases (0),
+ * derefInSearching (1),
+ * derefFindingBaseObj (2),
+ * alwaysDerefAliases (3)
+ * },
+ * sizelimit INTEGER (0 .. 65535),
+ * timelimit INTEGER (0 .. 65535),
+ * attrsOnly BOOLEAN,
+ * filter Filter,
+ * attributes SEQUENCE OF AttributeType
+ * }
+ */
+
+ /* baseObject, scope, derefAliases, sizelimit, timelimit, attrsOnly */
+ if ( ber_scanf( ber, "{aiiiib", &base, &long_scope, &long_deref, &long_sizelimit, &long_timelimit, &attrsonly ) == LBER_ERROR ){
+ slapi_ch_free((void**)&base );
+ log_search_access (pb, "???", -1, "???", "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0, NULL );
+ return;
+ }
+ scope = long_scope;
+ deref = long_deref;
+ sizelimit = long_sizelimit;
+ timelimit = long_timelimit;
+
+ /*
+ * ignore negative time and size limits since they make no sense
+ */
+ if ( timelimit < 0 ) {
+ timelimit = 0;
+ }
+ if ( sizelimit < 0 ) {
+ sizelimit = 0;
+ }
+
+ if ( scope != LDAP_SCOPE_BASE && scope != LDAP_SCOPE_ONELEVEL
+ && scope != LDAP_SCOPE_SUBTREE ) {
+ log_search_access (pb, base, scope, "???", "Unknown search scope");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "Unknown search scope", 0, NULL );
+ goto free_and_return;
+ }
+ /* check and record the scope for snmp */
+ if ( scope == LDAP_SCOPE_ONELEVEL) {
+ /* count the one level search request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps);
+
+ } else if (scope == LDAP_SCOPE_SUBTREE) {
+ /* count the subtree search request */
+ PR_AtomicIncrement(g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps);
+ }
+
+ /* filter - returns a "normalized" version */
+ filter = NULL;
+ fstr = NULL;
+ if ( (err = get_filter( pb->pb_conn, ber, scope, &filter, &fstr )) != 0 ) {
+ char *errtxt;
+
+ if ( LDAP_UNWILLING_TO_PERFORM == err ) {
+ errtxt = "The search filter is too deeply nested";
+ } else {
+ errtxt = "Bad search filter";
+ }
+ log_search_access( pb, base, scope, "???", errtxt );
+ send_ldap_result( pb, err, NULL, errtxt, 0, NULL );
+ goto free_and_return;
+ }
+
+ /* attributes */
+ attrs = NULL;
+ if ( ber_scanf( ber, "{v}}", &attrs ) == LBER_ERROR ) {
+ log_search_access (pb, base, scope, fstr, "decoding error");
+ send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL, NULL, 0,
+ NULL );
+ goto free_and_return;
+ }
+
+ /*
+ * This search is performed against the legacy consumer, so ask explicitly
+ * for the aci attribute as it is an operational in 5.0
+ */
+ if ( operation->o_flags & OP_FLAG_LEGACY_REPLICATION_DN )
+ {
+ /* If attrs==NULL in a 4.x request, means that we want all the attributes, as aci is
+ * now operational, we need to ask it explicilty as well as all the attributes
+ */
+ if ( (attrs == NULL) || (attrs[0] == NULL) )
+ {
+ charray_add(&attrs, slapi_attr_syntax_normalize("aci"));
+ charray_add(&attrs, slapi_attr_syntax_normalize(LDAP_ALL_USER_ATTRS));
+ }
+ else
+ {
+ for ( i = 0; attrs[i] != NULL; i++ )
+ {
+ if ( strcasecmp(attrs[i], LDAP_ALL_USER_ATTRS) == 0 )
+ {
+ charray_add(&attrs, slapi_attr_syntax_normalize("aci"));
+ break;
+ }
+ }
+ }
+ }
+
+ if ( attrs != NULL ) {
+ operation->o_searchattrs = cool_charray_dup( attrs );
+ for ( i = 0; attrs[i] != NULL; i++ ) {
+ char *type;
+
+ type = slapi_attr_syntax_normalize(attrs[i]);
+ slapi_ch_free( (void**)&(attrs[i]) );
+ attrs[i] = type;
+ }
+ }
+ if ( slapd_ldap_debug & LDAP_DEBUG_ARGS ) {
+ char abuf[ 1024 ], *astr;
+
+ if ( NULL == attrs ) {
+ astr = "ALL";
+ } else {
+ strarray2str( attrs, abuf, sizeof( abuf ), 1 /* include quotes */);
+ astr = abuf;
+ }
+ slapi_log_error( SLAPI_LOG_ARGS, NULL, "SRCH base=\"%s\" "
+ "scope=%d deref=%d "
+ "sizelimit=%d timelimit=%d attrsonly=%d filter=\"%s\" "
+ "attrs=%s\n", base, scope, deref, sizelimit, timelimit,
+ attrsonly, fstr, astr );
+ }
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend. get_ldapmessage_controls()
+ * reads the controls and sets any we know about in the pb.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ log_search_access (pb, base, scope, fstr, "failed to decode LDAP controls");
+ send_ldap_result( pb, err, NULL, NULL, 0, NULL );
+ goto free_and_return;
+ }
+
+ /* we support persistent search for regular operations only */
+ if ( slapi_control_present( operation->o_params.request_controls,
+ LDAP_CONTROL_PERSISTENTSEARCH, &psbvp, NULL )){
+ operation_set_flag(operation, OP_FLAG_PS);
+ psearch = 1;
+ if ( ps_parse_control_value( psbvp, &changetypes,
+ &changesonly, &send_entchg_controls ) != LDAP_SUCCESS )
+ {
+ changetypes = LDAP_CHANGETYPE_ANY;
+ send_entchg_controls = 0;
+ }
+ else if ( changesonly )
+ {
+ operation_set_flag(operation, OP_FLAG_PS_CHANGESONLY);
+ }
+ }
+
+ slapi_pblock_set( pb, SLAPI_SEARCH_TARGET, base );
+ slapi_pblock_set( pb, SLAPI_SEARCH_SCOPE, &scope );
+ slapi_pblock_set( pb, SLAPI_SEARCH_DEREF, &deref );
+ slapi_pblock_set( pb, SLAPI_SEARCH_FILTER, filter );
+ slapi_pblock_set( pb, SLAPI_SEARCH_STRFILTER, fstr );
+ slapi_pblock_set( pb, SLAPI_SEARCH_ATTRS, attrs );
+ slapi_pblock_set( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly );
+ slapi_pblock_set( pb, SLAPI_REQUESTOR_ISROOT, &operation->o_isroot );
+ slapi_pblock_set( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit );
+ slapi_pblock_set( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit );
+
+ /* plugins which play with the search may
+ * change the search params may allocate
+ * memory so we need to keep track of
+ * changed base search strings
+ */
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &original_base);
+
+ op_shared_search (pb, psearch ? 0 : 1/* send result */);
+
+ slapi_pblock_get(pb, SLAPI_SEARCH_TARGET, &new_base);
+ slapi_pblock_get (pb, SLAPI_PLUGIN_OPRETURN, &rc);
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter );
+
+ if ( psearch && rc == 0 ) {
+ ps_add( pb, changetypes, send_entchg_controls );
+ }
+
+free_and_return:;
+ if ( !psearch || rc < 0 ) {
+ if(original_base != new_base) {
+ slapi_ch_free_string(&new_base);
+ }
+ slapi_ch_free_string(&base);
+ slapi_ch_free_string(&fstr);
+ slapi_filter_free( filter, 1 );
+ if ( attrs != NULL ) {
+ charray_free( attrs );
+ }
+ /*
+ * Fix for defect 526719 / 553356 : Persistent search op failed.
+ * Marking it as non-persistent so that operation resources get freed
+ */
+ if (psearch){
+ operation->o_flags &= ~OP_FLAG_PS;
+ }
+ }
+}
+
+static void log_search_access (Slapi_PBlock *pb, const char *base, int scope, const char *fstr, const char *msg)
+{
+ char ebuf[BUFSIZ];
+ slapi_log_access(LDAP_DEBUG_STATS,
+ "conn=%d op=%d SRCH base=\"%s\" scope=%d filter=\"%s\", %s\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid,
+ escape_string(base, ebuf), scope, fstr, msg ? msg : "");
+
+}
diff --git a/ldap/servers/slapd/secerrstrs.h b/ldap/servers/slapd/secerrstrs.h
new file mode 100644
index 00000000..05be8170
--- /dev/null
+++ b/ldap/servers/slapd/secerrstrs.h
@@ -0,0 +1,431 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * secerrstrs.h - map security errors to strings (used by errormap.c)
+ *
+ */
+
+/*
+ ****************************************************************************
+ * The code below this point was provided by Nelson Bolyard <nelsonb> of the
+ * Netscape Certificate Server team on 27-March-1998.
+ * Taken from the file ns/security/cmd/lib/SECerrs.h on NSS_1_BRANCH.
+ * Last updated from there: 24-July-1998 by Mark Smith <mcs>
+ *
+ * All of the Directory Server specific changes are enclosed inside
+ * #ifdef NS_DS.
+ ****************************************************************************
+ */
+
+/* General security error codes */
+/* Caller must #include "secerr.h" */
+
+
+ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0,
+"An I/O error occurred during security authorization.")
+
+ER3(SEC_ERROR_LIBRARY_FAILURE, SEC_ERROR_BASE + 1,
+"security library failure.")
+
+ER3(SEC_ERROR_BAD_DATA, SEC_ERROR_BASE + 2,
+"security library: received bad data.")
+
+ER3(SEC_ERROR_OUTPUT_LEN, SEC_ERROR_BASE + 3,
+"security library: output length error.")
+
+ER3(SEC_ERROR_INPUT_LEN, SEC_ERROR_BASE + 4,
+"security library has experienced an input length error.")
+
+ER3(SEC_ERROR_INVALID_ARGS, SEC_ERROR_BASE + 5,
+"security library: invalid arguments.")
+
+ER3(SEC_ERROR_INVALID_ALGORITHM, SEC_ERROR_BASE + 6,
+"security library: invalid algorithm.")
+
+ER3(SEC_ERROR_INVALID_AVA, SEC_ERROR_BASE + 7,
+"security library: invalid AVA.")
+
+ER3(SEC_ERROR_INVALID_TIME, SEC_ERROR_BASE + 8,
+"Improperly formatted time string.")
+
+ER3(SEC_ERROR_BAD_DER, SEC_ERROR_BASE + 9,
+"security library: improperly formatted DER-encoded message.")
+
+ER3(SEC_ERROR_BAD_SIGNATURE, SEC_ERROR_BASE + 10,
+"Peer's certificate has an invalid signature.")
+
+ER3(SEC_ERROR_EXPIRED_CERTIFICATE, SEC_ERROR_BASE + 11,
+"Peer's Certificate has expired.")
+
+ER3(SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_BASE + 12,
+"Peer's Certificate has been revoked.")
+
+ER3(SEC_ERROR_UNKNOWN_ISSUER, SEC_ERROR_BASE + 13,
+"Peer's Certificate issuer is not recognized.")
+
+ER3(SEC_ERROR_BAD_KEY, SEC_ERROR_BASE + 14,
+"Peer's public key is invalid.")
+
+ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15,
+"The security password entered is incorrect.")
+
+ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16,
+"New password entered incorrectly. Please try again.")
+
+ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17,
+"security library: no nodelock.")
+
+ER3(SEC_ERROR_BAD_DATABASE, SEC_ERROR_BASE + 18,
+"security library: bad database.")
+
+ER3(SEC_ERROR_NO_MEMORY, SEC_ERROR_BASE + 19,
+"security library: memory allocation failure.")
+
+ER3(SEC_ERROR_UNTRUSTED_ISSUER, SEC_ERROR_BASE + 20,
+"Peer's certificate issuer has been marked as not trusted by the user.")
+
+ER3(SEC_ERROR_UNTRUSTED_CERT, SEC_ERROR_BASE + 21,
+"Peer's certificate has been marked as not trusted by the user.")
+
+ER3(SEC_ERROR_DUPLICATE_CERT, (SEC_ERROR_BASE + 22),
+"Certificate already exists in your database.")
+
+ER3(SEC_ERROR_DUPLICATE_CERT_NAME, (SEC_ERROR_BASE + 23),
+"Downloaded certificate's name duplicates one already in your database.")
+
+ER3(SEC_ERROR_ADDING_CERT, (SEC_ERROR_BASE + 24),
+"Error adding certificate to database.")
+
+ER3(SEC_ERROR_FILING_KEY, (SEC_ERROR_BASE + 25),
+"Error refiling the key for this certificate.")
+
+ER3(SEC_ERROR_NO_KEY, (SEC_ERROR_BASE + 26),
+"The private key for this certificate cannot be found in key database")
+
+ER3(SEC_ERROR_CERT_VALID, (SEC_ERROR_BASE + 27),
+"This certificate is valid.")
+
+ER3(SEC_ERROR_CERT_NOT_VALID, (SEC_ERROR_BASE + 28),
+"This certificate is not valid.")
+
+ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29),
+"Cert Library: No Response")
+
+ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30),
+"The certificate issuer's certificate has expired. Check your system date and time.")
+
+ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31),
+"The CRL for the certificate's issuer has expired. Update it or check your system data and time.")
+
+ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32),
+"The CRL for the certificate's issuer has an invalid signature.")
+
+ER3(SEC_ERROR_CRL_INVALID, (SEC_ERROR_BASE + 33),
+"New CRL has an invalid format.")
+
+ER3(SEC_ERROR_EXTENSION_VALUE_INVALID, (SEC_ERROR_BASE + 34),
+"Certificate extension value is invalid.")
+
+ER3(SEC_ERROR_EXTENSION_NOT_FOUND, (SEC_ERROR_BASE + 35),
+"Certificate extension not found.")
+
+ER3(SEC_ERROR_CA_CERT_INVALID, (SEC_ERROR_BASE + 36),
+"Issuer certificate is invalid.")
+
+ER3(SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, (SEC_ERROR_BASE + 37),
+"Certificate path length constraint is invalid.")
+
+ER3(SEC_ERROR_CERT_USAGES_INVALID, (SEC_ERROR_BASE + 38),
+"Certificate usages field is invalid.")
+
+ER3(SEC_INTERNAL_ONLY, (SEC_ERROR_BASE + 39),
+"**Internal ONLY module**")
+
+ER3(SEC_ERROR_INVALID_KEY, (SEC_ERROR_BASE + 40),
+"The key does not support the requested operation.")
+
+ER3(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 41),
+"Certificate contains unknown critical extension.")
+
+ER3(SEC_ERROR_OLD_CRL, (SEC_ERROR_BASE + 42),
+"New CRL is not later than the current one.")
+
+ER3(SEC_ERROR_NO_EMAIL_CERT, (SEC_ERROR_BASE + 43),
+"Not encrypted or signed: you do not yet have an email certificate.")
+
+ER3(SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, (SEC_ERROR_BASE + 44),
+"Not encrypted: you do not have certificates for each of the recipients.")
+
+ER3(SEC_ERROR_NOT_A_RECIPIENT, (SEC_ERROR_BASE + 45),
+"Cannot decrypt: you are not a recipient, or matching certificate and \
+private key not found.")
+
+ER3(SEC_ERROR_PKCS7_KEYALG_MISMATCH, (SEC_ERROR_BASE + 46),
+"Cannot decrypt: key encryption algorithm does not match your certificate.")
+
+ER3(SEC_ERROR_PKCS7_BAD_SIGNATURE, (SEC_ERROR_BASE + 47),
+"Signature verification failed: no signer found, too many signers found, \
+or improper or corrupted data.")
+
+ER3(SEC_ERROR_UNSUPPORTED_KEYALG, (SEC_ERROR_BASE + 48),
+"Unsupported or unknown key algorithm.")
+
+ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49),
+"Cannot decrypt: encrypted using a disallowed algorithm or key size.")
+
+
+/* Fortezza Alerts */
+ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50),
+"Fortezza card has not been properly initialized. \
+Please remove it and return it to your issuer.")
+
+ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51),
+"No Fortezza cards Found")
+
+ER3(XP_SEC_FORTEZZA_NONE_SELECTED, (SEC_ERROR_BASE + 52),
+"No Fortezza card selected")
+
+ER3(XP_SEC_FORTEZZA_MORE_INFO, (SEC_ERROR_BASE + 53),
+"Please select a personality to get more info on")
+
+ER3(XP_SEC_FORTEZZA_PERSON_NOT_FOUND, (SEC_ERROR_BASE + 54),
+"Personality not found")
+
+ER3(XP_SEC_FORTEZZA_NO_MORE_INFO, (SEC_ERROR_BASE + 55),
+"No more information on that Personality")
+
+ER3(XP_SEC_FORTEZZA_BAD_PIN, (SEC_ERROR_BASE + 56),
+"Invalid Pin")
+
+ER3(XP_SEC_FORTEZZA_PERSON_ERROR, (SEC_ERROR_BASE + 57),
+"Couldn't initialize Fortezza personalities.")
+/* end fortezza alerts. */
+
+ER3(SEC_ERROR_NO_KRL, (SEC_ERROR_BASE + 58),
+"No KRL for this site's certificate has been found.")
+
+ER3(SEC_ERROR_KRL_EXPIRED, (SEC_ERROR_BASE + 59),
+"The KRL for this site's certificate has expired.")
+
+ER3(SEC_ERROR_KRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 60),
+"The KRL for this site's certificate has an invalid signature.")
+
+ER3(SEC_ERROR_REVOKED_KEY, (SEC_ERROR_BASE + 61),
+"The key for this site's certificate has been revoked.")
+
+ER3(SEC_ERROR_KRL_INVALID, (SEC_ERROR_BASE + 62),
+"New KRL has an invalid format.")
+
+ER3(SEC_ERROR_NEED_RANDOM, (SEC_ERROR_BASE + 63),
+"security library: need random data.")
+
+ER3(SEC_ERROR_NO_MODULE, (SEC_ERROR_BASE + 64),
+"security library: no security module can perform the requested operation.")
+
+ER3(SEC_ERROR_NO_TOKEN, (SEC_ERROR_BASE + 65),
+"The security card or token does not exist, needs to be initialized, or has been removed.")
+
+ER3(SEC_ERROR_READ_ONLY, (SEC_ERROR_BASE + 66),
+"security library: read-only database.")
+
+ER3(SEC_ERROR_NO_SLOT_SELECTED, (SEC_ERROR_BASE + 67),
+"No slot or token was selected.")
+
+ER3(SEC_ERROR_CERT_NICKNAME_COLLISION, (SEC_ERROR_BASE + 68),
+"A certificate with the same nickname already exists.")
+
+ER3(SEC_ERROR_KEY_NICKNAME_COLLISION, (SEC_ERROR_BASE + 69),
+"A key with the same nickname already exists.")
+
+ER3(SEC_ERROR_SAFE_NOT_CREATED, (SEC_ERROR_BASE + 70),
+"error while creating safe object")
+
+ER3(SEC_ERROR_BAGGAGE_NOT_CREATED, (SEC_ERROR_BASE + 71),
+"error while creating baggage object")
+
+ER3(XP_JAVA_REMOVE_PRINCIPAL_ERROR, (SEC_ERROR_BASE + 72),
+"Couldn't remove the principal")
+
+ER3(XP_JAVA_DELETE_PRIVILEGE_ERROR, (SEC_ERROR_BASE + 73),
+"Couldn't delete the privilege")
+
+ER3(XP_JAVA_CERT_NOT_EXISTS_ERROR, (SEC_ERROR_BASE + 74),
+"This principal doesn't have a certificate")
+
+ER3(SEC_ERROR_BAD_EXPORT_ALGORITHM, (SEC_ERROR_BASE + 75),
+"Required algorithm is not allowed.")
+
+ER3(SEC_ERROR_EXPORTING_CERTIFICATES, (SEC_ERROR_BASE + 76),
+"Error attempting to export certificates.")
+
+ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77),
+"Error attempting to import certificates.")
+
+ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78),
+"Unable to import. Decoding error. File not valid.")
+
+ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79),
+"Unable to import. Invalid MAC. Incorrect password or corrupt file.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80),
+"Unable to import. MAC algorithm not supported.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE,(SEC_ERROR_BASE + 81),
+"Unable to import. Only password integrity and privacy modes supported.")
+
+ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82),
+"Unable to import. File structure is corrupt.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83),
+"Unable to import. Encryption algorithm not supported.")
+
+ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84),
+"Unable to import. File version not supported.")
+
+ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT,(SEC_ERROR_BASE + 85),
+"Unable to import. Incorrect privacy password.")
+
+ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86),
+"Unable to import. Same nickname already exists in database.")
+
+ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87),
+"The user pressed cancel.")
+
+ER3(SEC_ERROR_PKCS12_DUPLICATE_DATA, (SEC_ERROR_BASE + 88),
+"Not imported, already in database.")
+
+ER3(SEC_ERROR_MESSAGE_SEND_ABORTED, (SEC_ERROR_BASE + 89),
+"Message not sent.")
+
+ER3(SEC_ERROR_INADEQUATE_KEY_USAGE, (SEC_ERROR_BASE + 90),
+"Certificate key usage inadequate for attempted operation.")
+
+ER3(SEC_ERROR_INADEQUATE_CERT_TYPE, (SEC_ERROR_BASE + 91),
+"Certificate type not approved for application.")
+
+ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92),
+"Address in signing certificate does not match address in message headers.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93),
+"Unable to import. Error attempting to import private key.")
+
+ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94),
+"Unable to import. Error attempting to import certificate chain.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95),
+"Unable to export. Unable to locate certificate or key by nickname.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96),
+"Unable to export. Private Key could not be located and exported.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97),
+"Unable to export. Unable to write the export file.")
+
+ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98),
+"Unable to import. Unable to read the import file.")
+
+ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99),
+"Unable to export. Key database corrupt or deleted.")
+
+ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100),
+"Unable to generate public/private key pair.")
+
+ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101),
+"Password entered is invalid. Please pick a different one.")
+
+ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102),
+"Old password entered incorrectly. Please try again.")
+
+ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103),
+"Certificate nickname already in use.")
+
+ER3(SEC_ERROR_NOT_FORTEZZA_ISSUER, (SEC_ERROR_BASE + 104),
+"Peer FORTEZZA chain has a non-FORTEZZA Certificate.")
+
+/* ER3(SEC_ERROR_UNKNOWN, (SEC_ERROR_BASE + 105), */
+
+ER3(SEC_ERROR_JS_INVALID_MODULE_NAME, (SEC_ERROR_BASE + 106),
+"Invalid module name.")
+
+ER3(SEC_ERROR_JS_INVALID_DLL, (SEC_ERROR_BASE + 107),
+"Invalid module path/filename")
+
+ER3(SEC_ERROR_JS_ADD_MOD_FAILURE, (SEC_ERROR_BASE + 108),
+"Unable to add module")
+
+ER3(SEC_ERROR_JS_DEL_MOD_FAILURE, (SEC_ERROR_BASE + 109),
+"Unable to delete module")
+
+ER3(SEC_ERROR_OLD_KRL, (SEC_ERROR_BASE + 110),
+"New KRL is not later than the current one.")
+
+ER3(SEC_ERROR_CKL_CONFLICT, (SEC_ERROR_BASE + 111),
+"New CKL has different issuer than current CKL. Delete current CKL.")
+
+ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112),
+"The Certifying Authority for this certificate is not permitted to issue a \
+certificate with this name.")
+
+ER3(SEC_ERROR_KRL_NOT_YET_VALID, (SEC_ERROR_BASE + 113),
+"The key revocation list for this certificate is not yet valid.")
+
+ER3(SEC_ERROR_CRL_NOT_YET_VALID, (SEC_ERROR_BASE + 114),
+"The certificate revocation list for this certificate is not yet valid.")
+
+ER3(SEC_ERROR_UNKNOWN_CERT, (SEC_ERROR_BASE + 115),
+"The requested certificate could not be found.")
+
+ER3(SEC_ERROR_UNKNOWN_SIGNER, (SEC_ERROR_BASE + 116),
+"The signer's certificate could not be found.")
+
+ER3(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, (SEC_ERROR_BASE + 117),
+"The location for the certificate status server has invalid format.")
+
+ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, (SEC_ERROR_BASE + 118),
+"The OCSP response cannot be fully decoded; it is of an unknown type.")
+
+ER3(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 119),
+"The OCSP server returned unexpected/invalid HTTP data.")
+
+ER3(SEC_ERROR_OCSP_MALFORMED_REQUEST, (SEC_ERROR_BASE + 120),
+"The OCSP server found the request to be corrupted or improperly formed.")
+
+ER3(SEC_ERROR_OCSP_SERVER_ERROR, (SEC_ERROR_BASE + 121),
+"The OCSP server experienced an internal error.")
+
+ER3(SEC_ERROR_OCSP_TRY_SERVER_LATER, (SEC_ERROR_BASE + 122),
+"The OCSP server suggests trying again later.")
+
+ER3(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, (SEC_ERROR_BASE + 123),
+"The OCSP server requires a signature on this request.")
+
+ER3(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, (SEC_ERROR_BASE + 124),
+"The OCSP server has refused this request as unauthorized.")
+
+ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, (SEC_ERROR_BASE + 125),
+"The OCSP server returned an unrecognizable status.")
+
+ER3(SEC_ERROR_OCSP_UNKNOWN_CERT, (SEC_ERROR_BASE + 126),
+"The OCSP server has no status for the certificate.")
+
+ER3(SEC_ERROR_OCSP_NOT_ENABLED, (SEC_ERROR_BASE + 127),
+"You must enable OCSP before performing this operation.")
+
+ER3(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, (SEC_ERROR_BASE + 128),
+"You must set the OCSP default responder before performing this operation.")
+
+ER3(SEC_ERROR_OCSP_MALFORMED_RESPONSE, (SEC_ERROR_BASE + 129),
+"The response from the OCSP server was corrupted or improperly formed.")
+
+ER3(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, (SEC_ERROR_BASE + 130),
+"The signer of the OCSP response is not authorized to give status for \
+this certificate.")
+
+ER3(SEC_ERROR_OCSP_FUTURE_RESPONSE, (SEC_ERROR_BASE + 131),
+"The OCSP response is not yet valid (contains a date in the future).")
+
+ER3(SEC_ERROR_OCSP_OLD_RESPONSE, (SEC_ERROR_BASE + 132),
+"The OCSP response contains out-of-date information.")
diff --git a/ldap/servers/slapd/security_wrappers.c b/ldap/servers/slapd/security_wrappers.c
new file mode 100644
index 00000000..d4b898d8
--- /dev/null
+++ b/ldap/servers/slapd/security_wrappers.c
@@ -0,0 +1,339 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <ssl.h>
+#include <nss.h>
+#include <key.h>
+#include <certdb.h>
+#include <cert.h>
+#include <sslproto.h>
+#include <secoid.h>
+#include <secmod.h>
+#include <secmodt.h>
+#include <prtypes.h>
+#include <seccomon.h>
+#include <pkcs11.h>
+#include <pk11func.h>
+
+#include "slap.h"
+
+
+
+/*
+ * Set of security wrapper functions, aimed at forcing every security-related call
+ * pass through libslapd library.
+ * Thus, we avoid finding any ambiguity or data inconsistency (which we would,
+ * otherwise, have to face on NT.
+ */
+
+
+/*
+ * Note: slapd_ssl_handshakeCallback() is called with a Connection * in
+ * client_data. That connection must have its c_mutex locked.
+ */
+int
+slapd_ssl_handshakeCallback(PRFileDesc *fd, void * callback, void * client_data)
+{
+ return SSL_HandshakeCallback(fd, (SSLHandshakeCallback) callback, client_data);
+}
+
+
+/*
+ * Note: slapd_ssl_badCertHook() is called with a Connection * in
+ * client_data. That connection must have its c_mutex locked.
+ */
+int
+slapd_ssl_badCertHook(PRFileDesc *fd, void * callback, void * client_data)
+{
+ return SSL_BadCertHook(fd, (SSLBadCertHandler) callback, client_data);
+}
+
+
+CERTCertificate *
+slapd_ssl_peerCertificate(PRFileDesc *fd)
+{
+ return SSL_PeerCertificate(fd);
+}
+
+
+SECStatus
+slapd_ssl_getChannelInfo(PRFileDesc *fd, SSLChannelInfo *sinfo, PRUintn len)
+{
+ return SSL_GetChannelInfo(fd, sinfo, len);
+}
+
+
+SECStatus
+slapd_ssl_getCipherSuiteInfo(PRUint16 ciphersuite, SSLCipherSuiteInfo *cinfo, PRUintn len)
+{
+ return SSL_GetCipherSuiteInfo(ciphersuite, cinfo, len);
+}
+
+PRFileDesc *
+slapd_ssl_importFD(PRFileDesc *model, PRFileDesc *fd)
+{
+ return SSL_ImportFD(model, fd);
+}
+
+
+SECStatus
+slapd_ssl_resetHandshake(PRFileDesc *fd, PRBool asServer)
+{
+ return SSL_ResetHandshake(fd, asServer);
+}
+
+
+void
+slapd_pk11_configurePKCS11(char *man, char *libdes, char *tokdes, char *ptokdes,
+ char *slotdes, char *pslotdes, char *fslotdes,
+ char *fpslotdes, int minPwd,
+ int pwdRequired)
+{
+ PK11_ConfigurePKCS11(man, libdes, tokdes, ptokdes,
+ slotdes, pslotdes, fslotdes, fpslotdes, minPwd,
+ pwdRequired);
+ return;
+}
+
+
+void
+slapd_pk11_freeSlot(PK11SlotInfo *slot)
+{
+ PK11_FreeSlot(slot);
+ return;
+}
+
+
+void
+slapd_pk11_freeSymKey(PK11SymKey *key)
+{
+ PK11_FreeSymKey(key);
+ return;
+}
+
+
+PK11SlotInfo *
+slapd_pk11_findSlotByName(char *name)
+{
+ return PK11_FindSlotByName(name);
+}
+
+
+SECAlgorithmID *
+slapd_pk11_createPBEAlgorithmID(SECOidTag algorithm, int iteration, SECItem *salt)
+{
+ return PK11_CreatePBEAlgorithmID(algorithm, iteration, salt);
+}
+
+
+PK11SymKey *
+slapd_pk11_pbeKeyGen(PK11SlotInfo *slot, SECAlgorithmID *algid, SECItem *pwitem,
+ PRBool faulty3DES, void *wincx)
+{
+ return PK11_PBEKeyGen(slot, algid, pwitem,
+ faulty3DES, wincx);
+}
+
+
+CK_MECHANISM_TYPE
+slapd_pk11_algtagToMechanism(SECOidTag algTag)
+{
+ return PK11_AlgtagToMechanism(algTag);
+}
+
+
+SECItem *
+slapd_pk11_paramFromAlgid(SECAlgorithmID *algid)
+{
+ return PK11_ParamFromAlgid(algid);
+}
+
+
+CK_RV
+slapd_pk11_mapPBEMechanismToCryptoMechanism(CK_MECHANISM_PTR pPBEMechanism,
+ CK_MECHANISM_PTR pCryptoMechanism,
+ SECItem *pbe_pwd, PRBool bad3DES)
+{
+ return PK11_MapPBEMechanismToCryptoMechanism(pPBEMechanism,
+ pCryptoMechanism,
+ pbe_pwd, bad3DES);
+}
+
+
+int
+slapd_pk11_getBlockSize(CK_MECHANISM_TYPE type,SECItem *params)
+{
+ return PK11_GetBlockSize(type,params);
+}
+
+
+PK11Context *
+slapd_pk11_createContextBySymKey(CK_MECHANISM_TYPE type,
+ CK_ATTRIBUTE_TYPE operation,
+ PK11SymKey *symKey, SECItem *param)
+{
+ return PK11_CreateContextBySymKey(type,
+ operation, symKey, param);
+}
+
+
+SECStatus
+slapd_pk11_cipherOp(PK11Context *context, unsigned char * out, int *outlen,
+ int maxout, unsigned char *in, int inlen)
+{
+ return PK11_CipherOp(context, out, outlen, maxout, in, inlen);
+}
+
+
+SECStatus
+slapd_pk11_finalize(PK11Context *context)
+{
+ return PK11_Finalize(context);
+}
+
+
+PK11SlotInfo *
+slapd_pk11_getInternalKeySlot()
+{
+ return PK11_GetInternalKeySlot();
+}
+
+
+PK11SlotInfo *
+slapd_pk11_getInternalSlot()
+{
+ return PK11_GetInternalSlot();
+}
+
+
+SECStatus
+slapd_pk11_authenticate(PK11SlotInfo *slot, PRBool loadCerts, void *wincx)
+{
+ return PK11_Authenticate(slot, loadCerts, wincx);
+}
+
+
+void
+slapd_pk11_setSlotPWValues(PK11SlotInfo *slot,int askpw, int timeout)
+{
+ PK11_SetSlotPWValues(slot, askpw, timeout);
+ return;
+}
+
+
+PRBool
+slapd_pk11_isFIPS()
+{
+ return PK11_IsFIPS();
+}
+
+
+CERTCertificate *
+slapd_pk11_findCertFromNickname(char *nickname, void *wincx)
+{
+ return PK11_FindCertFromNickname(nickname, wincx);
+}
+
+
+SECKEYPrivateKey *
+slapd_pk11_findKeyByAnyCert(CERTCertificate *cert, void *wincx)
+{
+ return PK11_FindKeyByAnyCert(cert, wincx);
+}
+
+
+PRBool
+slapd_pk11_fortezzaHasKEA(CERTCertificate *cert)
+{
+ return PK11_FortezzaHasKEA(cert);
+}
+
+void
+slapd_pk11_destroyContext(PK11Context *context, PRBool freeit)
+{
+ PK11_DestroyContext(context, freeit);
+}
+
+void secoid_destroyAlgorithmID(SECAlgorithmID *algid, PRBool freeit)
+{
+ SECOID_DestroyAlgorithmID(algid, freeit);
+}
+
+void slapd_pk11_CERT_DestroyCertificate(CERTCertificate *cert)
+{
+ CERT_DestroyCertificate(cert);
+}
+
+SECKEYPublicKey *slapd_CERT_ExtractPublicKey(CERTCertificate *cert)
+{
+ return CERT_ExtractPublicKey(cert);
+}
+
+SECKEYPrivateKey * slapd_pk11_FindPrivateKeyFromCert(PK11SlotInfo *slot,CERTCertificate *cert, void *wincx)
+{
+ return PK11_FindPrivateKeyFromCert(slot,cert,wincx);
+}
+
+PK11SlotInfo *slapd_pk11_GetInternalKeySlot(void)
+{
+ return PK11_GetInternalKeySlot();
+}
+
+SECStatus slapd_pk11_PubWrapSymKey(CK_MECHANISM_TYPE type, SECKEYPublicKey *pubKey,PK11SymKey *symKey, SECItem *wrappedKey)
+{
+ return PK11_PubWrapSymKey(type,pubKey,symKey,wrappedKey);
+}
+
+PK11SymKey *slapd_pk11_KeyGen(PK11SlotInfo *slot,CK_MECHANISM_TYPE type,SECItem *param, int keySize,void *wincx)
+{
+ return PK11_KeyGen(slot,type,param,keySize,wincx);
+}
+
+void slapd_pk11_FreeSlot(PK11SlotInfo *slot)
+{
+ PK11_FreeSlot(slot);
+}
+
+void slapd_pk11_FreeSymKey(PK11SymKey *key)
+{
+ PK11_FreeSymKey(key);
+}
+
+void slapd_pk11_DestroyContext(PK11Context *context, PRBool freeit)
+{
+ PK11_DestroyContext(context,freeit);
+}
+
+SECItem *slapd_pk11_ParamFromIV(CK_MECHANISM_TYPE type,SECItem *iv)
+{
+ return PK11_ParamFromIV(type,iv);
+}
+
+PK11SymKey *slapd_pk11_PubUnwrapSymKey(SECKEYPrivateKey *wrappingKey, SECItem *wrappedKey,CK_MECHANISM_TYPE target, CK_ATTRIBUTE_TYPE operation, int keySize)
+{
+ return PK11_PubUnwrapSymKey(wrappingKey,wrappedKey,target,operation,keySize);
+}
+
+unsigned slapd_SECKEY_PublicKeyStrength(SECKEYPublicKey *pubk)
+{
+ return SECKEY_PublicKeyStrength(pubk);
+}
+
+SECStatus slapd_pk11_Finalize(PK11Context *context)
+{
+ return PK11_Finalize(context);
+}
+
+SECStatus slapd_pk11_DigestFinal(PK11Context *context, unsigned char *data,unsigned int *outLen, unsigned int length)
+{
+ return PK11_DigestFinal(context, data, outLen, length);
+}
+
+void
+slapd_SECITEM_FreeItem (SECItem *zap, PRBool freeit)
+{
+ SECITEM_FreeItem(zap,freeit);
+}
+
diff --git a/ldap/servers/slapd/slap.h b/ldap/servers/slapd/slap.h
new file mode 100644
index 00000000..ad1ccdda
--- /dev/null
+++ b/ldap/servers/slapd/slap.h
@@ -0,0 +1,1944 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* slap.h - stand alone ldap server include file */
+
+#ifndef _SLDAPD_H_
+#define _SLDAPD_H_
+
+
+/* Used by SSL and DES plugin */
+#ifndef _TOK
+#define _TOK
+static char tokDes[34] = "Communicator Generic Crypto Svcs";
+static char ptokDes[34] = "Internal (Software) Token ";
+#endif
+
+/*
+ * The slapd executable can function in on of several modes.
+ */
+#define SLAPD_EXEMODE_UNKNOWN 0
+#define SLAPD_EXEMODE_SLAPD 1
+#define SLAPD_EXEMODE_DB2LDIF 2
+#define SLAPD_EXEMODE_LDIF2DB 3
+#define SLAPD_EXEMODE_DB2ARCHIVE 4
+#define SLAPD_EXEMODE_ARCHIVE2DB 5
+#define SLAPD_EXEMODE_DBTEST 6
+#define SLAPD_EXEMODE_DB2INDEX 7
+#define SLAPD_EXEMODE_REFERRAL 8
+#define SLAPD_EXEMODE_SUFFIX2INSTANCE 9
+#define SLAPD_EXEMODE_PRINTVERSION 10
+#if defined(UPGRADEDB)
+#define SLAPD_EXEMODE_UPGRADEDB 11
+#endif
+
+#ifdef _WIN32
+#ifndef DONT_DECLARE_SLAPD_LDAP_DEBUG
+extern __declspec(dllimport) int slapd_ldap_debug; /* XXXmcs: should eliminate this */
+#endif /* DONT_DECLARE_SLAPD_LDAP_DEBUG */
+typedef char *caddr_t;
+void *dlsym(void *a, char *b);
+#define LOG_PID 0x01
+#define LOG_NOWAIT 0x10
+#define LOG_DEBUG 7
+#define POLL_STRUCT PRPollDesc
+#define POLL_FN PR_Poll
+#define RLIM_TYPE int
+#else /* _WIN32 */
+#define LDAP_SYSLOG
+#include <syslog.h>
+#define RLIM_TYPE int
+#include <poll.h>
+#define POLL_STRUCT PRPollDesc
+#define POLL_FN PR_Poll
+#endif /* _WIN32 */
+
+#include <stdio.h> /* for FILE */
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+
+/* there's a bug in the dbm code we import (from where?) -- FIXME */
+#ifdef LINUX
+#define LITTLE_ENDIAN __LITTLE_ENDIAN
+#endif
+#include <cert.h>
+
+#ifndef _WIN32
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#endif /* _WIN32 */
+
+#ifdef _WIN32
+#define LDAP_IOCP
+#endif
+
+#define LOG_INTERNAL_OP_CON_ID "Internal"
+#define LOG_INTERNAL_OP_OP_ID -1
+
+#define MAX_SERVICE_NAME 25
+
+#define SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH 256
+
+#if defined(NET_SSL)
+typedef struct symbol_t {
+ const char* name;
+ unsigned number;
+} symbol_t;
+
+#define SLAPD_SSLCLIENTAUTH_OFF 0
+#define SLAPD_SSLCLIENTAUTH_ALLOWED 1 /* server asks for cert, but client need not send one */
+#define SLAPD_SSLCLIENTAUTH_REQUIRED 2 /* server will refuse SSL session unless client sends cert */
+#define SLAPD_SSLCLIENTAUTH_DEFAULT SLAPD_SSLCLIENTAUTH_ALLOWED
+#endif /* NET_SSL */
+
+#define SLAPD_LOGGING 1
+#define NUM_SNMP_INT_TBL_ROWS 5
+
+/* include NSPR header files */
+#include "nspr.h"
+#include "plhash.h"
+
+/* include NSS header files */
+#include "ssl.h"
+
+#include <sys/types.h> /* this should be moved into avl.h */
+
+#include "avl.h"
+#include "ldap.h"
+#include "ldaprot.h"
+#include "ldif.h"
+#include "ldaplog.h"
+#include "portable.h"
+#include "rwlock.h"
+#include "litekey.h"
+#include "disconnect_errors.h"
+
+#include "dirver.h"
+#include "csngen.h"
+#include "uuid.h"
+
+#if defined(OS_solaris)
+# include <thread.h>
+# define GET_THREAD_ID() thr_self()
+#else
+# if defined(_WIN32)
+# define GET_THREAD_ID() GetCurrentThreadId()
+# else
+# include <pthread.h>
+# define GET_THREAD_ID() pthread_self()
+# endif
+#endif
+
+
+/*
+ * XXXmcs: these are defined by ldap.h or ldap-extension.h,
+ * but only in a newer release than we use with DS today.
+ */
+#ifndef LDAP_CONTROL_AUTH_REQUEST
+#define LDAP_CONTROL_AUTH_REQUEST "2.16.840.1.113730.3.4.16"
+#endif
+#ifndef LDAP_CONTROL_AUTH_RESPONSE
+#define LDAP_CONTROL_AUTH_RESPONSE "2.16.840.1.113730.3.4.15"
+#endif
+#ifndef LDAP_CONTROL_REAL_ATTRS_ONLY
+#define LDAP_CONTROL_REAL_ATTRS_ONLY "2.16.840.1.113730.3.4.17"
+#endif
+#ifndef LDAP_CONTROL_VIRT_ATTRS_ONLY
+#define LDAP_CONTROL_VIRT_ATTRS_ONLY "2.16.840.1.113730.3.4.19"
+#endif
+#ifndef LDAP_CONTROL_GET_EFFECTIVE_RIGHTS
+#define LDAP_CONTROL_GET_EFFECTIVE_RIGHTS "1.3.6.1.4.1.42.2.27.9.5.2"
+#endif
+
+#define SLAPD_VENDOR_NAME "Netscape Communications Corp."
+#define SLAPD_VERSION_STR "Netscape-Directory/" PRODUCTTEXT
+#define SLAPD_SHORT_VERSION_STR PRODUCTTEXT
+
+typedef void (*VFP)(void *);
+typedef void (*VFP0)();
+#define LDAPI_INTERNAL 1
+#include "slapi-private.h"
+#include "pw.h"
+/*
+ * call the appropriate signal() function.
+ */
+#if ( defined( hpux ) || defined ( irix ))
+/*
+ * we should not mix POSIX signal library function (sigaction)
+ * with SYSV's (sigset) on IRIX. nspr uses POSIX internally.
+ */
+#define SIGNAL( s, a ) signal2sigaction( s, (void *) a )
+#elif ( defined( SYSV ) || defined( aix ))
+#define SIGNAL sigset
+#else
+#define SIGNAL signal
+#endif
+
+/*
+ * SLAPD_PR_WOULD_BLOCK_ERROR() returns non-zero if prerrno is an NSPR
+ * error code that indicates a temporary non-blocking I/O error,
+ * e.g., PR_WOULD_BLOCK_ERROR.
+ */
+#define SLAPD_PR_WOULD_BLOCK_ERROR( prerrno ) \
+ ((prerrno) == PR_WOULD_BLOCK_ERROR || (prerrno) == PR_IO_TIMEOUT_ERROR)
+
+/*
+ * SLAPD_SYSTEM_WOULD_BLOCK_ERROR() returns non-zero if syserrno is an OS
+ * error code that indicates a temporary non-blocking I/O error,
+ * e.g., EAGAIN.
+ */
+#define SLAPD_SYSTEM_WOULD_BLOCK_ERROR( syserrno ) \
+ ((syserrno)==EAGAIN || (syserrno)==EWOULDBLOCK)
+
+
+#define LDAP_ON 1
+#define LDAP_OFF 0
+#define LDAP_UNDEFINED (-1)
+
+#ifndef SLAPD_INVALID_SOCKET
+#ifdef _WIN32
+#define SLAPD_INVALID_SOCKET 0
+#else
+#define SLAPD_INVALID_SOCKET 0
+#endif
+#endif
+
+#define SLAPD_INVALID_SOCKET_INDEX (-1)
+
+#ifdef _WIN32
+#define SLAPD_DEFAULT_FILE_MODE S_IREAD | S_IWRITE
+#define SLAPD_DEFAULT_DIR_MODE 0
+#else /* _WIN32 */
+#define SLAPD_DEFAULT_FILE_MODE S_IRUSR | S_IWUSR
+#define SLAPD_DEFAULT_DIR_MODE S_IRWXU
+#endif
+
+#define SLAPD_DEFAULT_IDLE_TIMEOUT 0 /* seconds - 0 == never */
+#define SLAPD_DEFAULT_SIZELIMIT 2000 /* use -1 for no limit */
+#define SLAPD_DEFAULT_TIMELIMIT 3600 /* use -1 for no limit */
+#define SLAPD_DEFAULT_LOOKTHROUGHLIMIT 5000 /* use -1 for no limit */
+#define SLAPD_DEFAULT_GROUPNESTLEVEL 5
+#define SLAPD_DEFAULT_MAX_FILTER_NEST_LEVEL 40 /* use -1 for no limit */
+#define SLAPD_DEFAULT_IOBLOCK_TIMEOUT 1800000 /* half hour in ms */
+#define SLAPD_DEFAULT_OUTBOUND_LDAP_IO_TIMEOUT 300000 /* 5 minutes in ms */
+#define SLAPD_DEFAULT_RESERVE_FDS 64
+#define SLAPD_DEFAULT_MAX_THREADS 30 /* connection pool threads */
+#define SLAPD_DEFAULT_MAX_THREADS_PER_CONN 5 /* allowed per connection */
+#define SLAPD_DEFAULT_SCHEMA_IGNORE_TRAILING_SPACES LDAP_OFF
+
+ /* We'd like this number to be prime for
+ the hash into the Connection table */
+#define SLAPD_DEFAULT_CONNTABLESIZE 4093 /* connection table size */
+
+#define SLAPD_MONITOR_DN "cn=monitor"
+#define SLAPD_SCHEMA_DN "cn=schema"
+#define SLAPD_CONFIG_DN "cn=config"
+
+#define EGG_OBJECT_CLASS "directory~team~extensible~object"
+#define EGG_FILTER "(objectclass=directory~team~extensible~object)"
+
+#define BE_LIST_SIZE 100 /* used by mapping tree code to hold be_list stuff */
+
+#define REPL_DBTYPE "ldbm"
+#define REPL_DBTAG "repl"
+
+#define ATTR_NETSCAPEMDSUFFIX "netscapemdsuffix"
+
+/* Used to make unhashed passwords available to plugins. */
+#define PSEUDO_ATTR_UNHASHEDUSERPASSWORD "unhashed#user#password"
+
+#define REFERRAL_REMOVE_CMD "remove"
+
+/* Filenames for DSE storage */
+#define DSE_FILENAME "dse.ldif"
+#define DSE_TMPFILE "dse.ldif.tmp"
+#define DSE_BACKFILE "dse.ldif.bak"
+#define DSE_STARTOKFILE "dse.ldif.startOK"
+#define DSE_LDBM_FILENAME "ldbm.ldif"
+#define DSE_LDBM_TMPFILE "ldbm.ldif.tmp"
+/* for now, we are using the dse file for the base config file */
+#define CONFIG_FILENAME DSE_FILENAME
+/* the default configuration sub directory of the instance directory */
+#define CONFIG_SUBDIR_NAME "config"
+/* the default schema sub directory of the config sub directory */
+#define SCHEMA_SUBDIR_NAME "schema"
+
+struct subfilt {
+ char *sf_type;
+ char *sf_initial;
+ char **sf_any;
+ char *sf_final;
+ void *sf_private; /* data private to syntax handler */
+};
+
+#include "filter.h" /* mr_filter_t */
+
+/*
+ * represents a search filter
+ */
+struct slapi_filter {
+ int f_flags;
+ unsigned long f_choice; /* values taken from ldap.h */
+ PRUint32 f_hash; /* for quick comparisons */
+ void *assigned_decoder;
+
+ union {
+ /* present */
+ char *f_un_type;
+
+ /* equality, lessorequal, greaterorequal, approx */
+ struct ava f_un_ava;
+
+ /* and, or, not */
+ struct slapi_filter *f_un_complex;
+
+ /* substrings */
+ struct subfilt f_un_sub;
+
+ /* extended -- v3 only */
+ mr_filter_t f_un_extended;
+ } f_un;
+#define f_type f_un.f_un_type
+#define f_ava f_un.f_un_ava
+#define f_avtype f_un.f_un_ava.ava_type
+#define f_avvalue f_un.f_un_ava.ava_value
+#define f_and f_un.f_un_complex
+#define f_or f_un.f_un_complex
+#define f_not f_un.f_un_complex
+#define f_list f_un.f_un_complex
+#define f_sub f_un.f_un_sub
+#define f_sub_type f_un.f_un_sub.sf_type
+#define f_sub_initial f_un.f_un_sub.sf_initial
+#define f_sub_any f_un.f_un_sub.sf_any
+#define f_sub_final f_un.f_un_sub.sf_final
+#define f_mr f_un.f_un_extended
+#define f_mr_oid f_un.f_un_extended.mrf_oid
+#define f_mr_type f_un.f_un_extended.mrf_type
+#define f_mr_value f_un.f_un_extended.mrf_value
+#define f_mr_dnAttrs f_un.f_un_extended.mrf_dnAttrs
+
+ struct slapi_filter *f_next;
+};
+
+struct csn
+{
+ time_t tstamp;
+ PRUint16 seqnum;
+ ReplicaId rid;
+ PRUint16 subseqnum;
+};
+
+struct csnset_node
+{
+ CSNType type;
+ CSN csn;
+ CSNSet *next;
+};
+
+struct slapi_value
+{
+ struct berval bv;
+ CSNSet *v_csnset;
+};
+
+/*
+ * JCM: This structure, slapi_value_set, seems useless,
+ * but in the future we could:
+ *
+ * {
+ * unsigned char flag;
+ * union single
+ * {
+ * struct slapi_value *va;
+ * };
+ * union multiple_array
+ * {
+ * short num;
+ * short max;
+ * struct slapi_value **va;
+ * };
+ * union multiple_tree
+ * {
+ * struct slapi_value_tree *vt;
+ * };
+ */
+struct slapi_value_set
+{
+ struct slapi_value **va;
+};
+
+struct valuearrayfast
+{
+ int num; /* The number of values in the array */
+ int max; /* The number of slots in the array */
+ struct slapi_value **va;
+};
+
+struct bervals2free {
+ struct berval **bvals;
+ struct bervals2free *next;
+};
+
+/*
+ * represents an attribute instance (type + values + syntax)
+ */
+
+struct slapi_attr {
+ char *a_type;
+ struct slapi_value_set a_present_values;
+ unsigned long a_flags; /* SLAPI_ATTR_FLAG_... */
+ struct slapdplugin *a_plugin;
+ struct slapi_value_set a_deleted_values;
+ struct bervals2free *a_listtofree; /* JCM: EVIL... For DS4 Slapi compatibility. */
+ struct slapi_attr *a_next;
+ CSN *a_deletioncsn; /* The point in time at which this attribute was last deleted */
+};
+
+typedef struct oid_item {
+ char *oi_oid;
+ struct slapdplugin *oi_plugin;
+ struct oid_item *oi_next;
+} oid_item_t;
+
+/* attribute description (represents an attribute, but not the value) */
+typedef struct asyntaxinfo {
+ char *asi_oid; /* OID */
+ char *asi_name; /* normalized name */
+ char **asi_aliases; /* alternative names */
+ char *asi_desc; /* textual description */
+ char *asi_superior; /* derived from */
+ char *asi_mr_equality; /* equality matching rule */
+ char *asi_mr_ordering; /* ordering matching rule */
+ char *asi_mr_substring; /* substring matching rule */
+ char **asi_origin; /* X-ORIGIN extension */
+ struct slapdplugin *asi_plugin; /* syntax */
+ unsigned long asi_flags; /* SLAPI_ATTR_FLAG_... */
+ int asi_syntaxlength; /* length associated w/syntax */
+ int asi_refcnt; /* outstanding references */
+ PRBool asi_marked_for_delete; /* delete at next opportunity */
+} asyntaxinfo;
+
+/*
+ * Note: most of the asi_flags values are defined in slapi-plugin.h, but
+ * these ones are private to the DS.
+ */
+#define SLAPI_ATTR_FLAG_OVERRIDE 0x0010 /* when adding a new attribute,
+ override the existing attribute,
+ if any */
+#define SLAPI_ATTR_FLAG_NOLOCKING 0x0020 /* the init code doesn't lock the
+ tables */
+#define SLAPI_ATTR_FLAG_CMP_BITBYBIT 0x4000 /* do memcmp, not syntax cmp */
+#define SLAPI_ATTR_FLAG_KEEP 0x8000 /* keep when replacing all */
+
+/* This is the type of the function passed into attr_syntax_enumerate_attrs */
+typedef int (*AttrEnumFunc)(struct asyntaxinfo *asi, void *arg);
+/* Possible return values for an AttrEnumFunc */
+#define ATTR_SYNTAX_ENUM_NEXT 0 /* continue */
+#define ATTR_SYNTAX_ENUM_STOP 1 /* halt the enumeration */
+#define ATTR_SYNTAX_ENUM_REMOVE 2 /* unhash current node and continue */
+
+/* This is the type of the function passed into plugin_syntax_enumerate */
+typedef int (*SyntaxEnumFunc)(char **names, Slapi_PluginDesc *plugindesc,
+ void *arg);
+
+/* OIDs for some commonly used syntaxes */
+#define BINARY_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.5"
+#define BOOLEAN_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.7"
+#define COUNTRYSTRING_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.11"
+#define DN_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.12"
+#define DIRSTRING_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.15"
+#define GENERALIZEDTIME_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.24"
+#define IA5STRING_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.26"
+#define INTEGER_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.27"
+#define JPEG_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.28"
+#define OCTETSTRING_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.40"
+#define OID_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.38"
+#define POSTALADDRESS_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.41"
+#define TELEPHONE_SYNTAX_OID "1.3.6.1.4.1.1466.115.121.1.50"
+#define SPACE_INSENSITIVE_STRING_SYNTAX_OID "2.16.840.1.113730.3.7.1"
+
+/* OIDs for some commonly used matching rules */
+#define DNMATCH_OID "2.5.13.1" /* distinguishedNameMatch */
+#define CASEIGNOREMATCH_OID "2.5.13.2" /* caseIgnoreMatch */
+#define INTFIRSTCOMPMATCH_OID "2.5.13.29" /* integerFirstComponentMatch */
+#define OIDFIRSTCOMPMATCH_OID "2.5.13.30" /* objectIdentifierFirstComponentMatch */
+
+/* Names for some commonly used matching rules */
+#define DNMATCH_NAME "distinguishedNameMatch"
+#define CASEIGNOREMATCH_NAME "caseIgnoreMatch"
+#define INTFIRSTCOMPMATCH_NAME "integerFirstComponentMatch"
+#define OIDFIRSTCOMPMATCH_NAME "objectIdentifierFirstComponentMatch"
+
+#define ATTR_STANDARD_STRING "Standard Attribute"
+#define ATTR_USERDEF_STRING "User Defined Attribute"
+#define OC_STANDARD_STRING "Standard ObjectClass"
+#define OC_USERDEF_STRING "User Defined ObjectClass"
+
+/* modifiers used to define attributes */
+#define ATTR_MOD_OPERATIONAL "operational"
+#define ATTR_MOD_OVERRIDE "override"
+#define ATTR_MOD_SINGLE "single"
+
+/* extended operations supported by the server */
+#define EXTOP_BULK_IMPORT_START_OID "2.16.840.1.113730.3.5.7"
+#define EXTOP_BULK_IMPORT_DONE_OID "2.16.840.1.113730.3.5.8"
+
+/*
+ * Represents a Distinguished Name of an entry
+ * WARNING, if you change this stucture you MUST update dn_size()
+ * function in entry.c
+ */
+struct slapi_dn
+{
+ unsigned char flag;
+ const char *dn; /* DN */
+ const char *ndn; /* Case Normalised DN */
+ int ndn_len; /* normalize dn len */
+};
+
+/*
+ * Represents a Relative Distinguished Name.
+ */
+
+struct slapi_rdn
+{
+ unsigned char flag;
+ char *rdn;
+ char **rdns; /* Valid when FLAG_RDNS is set. */
+ int butcheredupto; /* How far through rdns we've gone converting '=' to '\0' */
+};
+
+/*
+ * representation of uniqueID. Defined in uuid.h
+ */
+#define UID_SIZE 16 /* size of unique id in bytes */
+
+/*
+ * max 1G attr values per entry
+ * in case, libdb returned bogus entry string from db (blackflag #623569)
+ */
+#define ENTRY_MAX_ATTRIBUTE_VALUE_COUNT 1073741824
+
+/*
+ * represents an entry in core
+ * WARNING, if you change this stucture you MUST update slapi_entry_size()
+ * function
+ */
+struct slapi_entry {
+ struct slapi_dn e_sdn; /* DN of this entry */
+ char *e_uniqueid; /* uniqueID of this entry */
+ CSNSet *e_dncsnset; /* The set of DN CSNs for this entry */
+ CSN *e_maxcsn; /* maximum CSN of the entry */
+ Slapi_Attr *e_attrs; /* list of attributes and values */
+ Slapi_Attr *e_deleted_attrs; /* deleted list of attributes and values */
+ Slapi_Attr *e_virtual_attrs; /* list of virtual attributes */
+ time_t e_virtual_watermark; /* indicates cache consistency when compared to global watermark */
+ PRRWLock *e_virtual_lock; /* for access to cached vattrs */
+ void *e_extension; /* A list of entry object extensions */
+ unsigned char e_flags;
+};
+
+/*
+ * represents schema information for a database
+ */
+/* values for oc_flags (only space for 8 of these right now!) */
+#define OC_FLAG_STANDARD_OC 1
+#define OC_FLAG_USER_OC 2
+#define OC_FLAG_REDEFINED_OC 4
+#define OC_FLAG_OBSOLETE 8
+
+/* values for oc_kind */
+#define OC_KIND_STRUCTURAL 0
+#define OC_KIND_AUXILIARY 1
+#define OC_KIND_ABSTRACT 2
+
+
+/* XXXmcs: ../plugins/cos/cos_cache.c has its own copy of this definition! */
+struct objclass {
+ char *oc_name; /* NAME */
+ char *oc_desc; /* DESC */
+ char *oc_oid; /* object identifier */
+ char *oc_superior; /* SUP -- XXXmcs: should be an array */
+ PRUint8 oc_kind; /* ABSTRACT/STRUCTURAL/AUXILIARY */
+ PRUint8 oc_flags; /* misc. flags, e.g., OBSOLETE */
+ char **oc_required;
+ char **oc_allowed;
+ char **oc_orig_required; /* MUST */
+ char **oc_orig_allowed; /* MAY */
+ char **oc_origin; /* X-ORIGIN extension */
+ struct objclass *oc_next;
+};
+
+typedef struct slapi_matchingRuleEntry {
+ char *mr_oid;
+ char *mr_oidalias;
+ char *mr_name;
+ char *mr_desc;
+ char *mr_syntax;
+ int mr_obsolete;
+} slapi_matchingRuleEntry;
+
+struct matchingRuleList {
+ Slapi_MatchingRuleEntry *mr_entry;
+ struct matchingRuleList *mrl_next;
+};
+
+/* List of the plugin index numbers */
+
+/* Backend & Global Plugins */
+#define PLUGIN_LIST_DATABASE 0
+#define PLUGIN_LIST_PREOPERATION 1
+#define PLUGIN_LIST_POSTOPERATION 2
+#define PLUGIN_LIST_BEPREOPERATION 3
+#define PLUGIN_LIST_BEPOSTOPERATION 4
+#define PLUGIN_LIST_INTERNAL_PREOPERATION 5
+#define PLUGIN_LIST_INTERNAL_POSTOPERATION 6
+#define PLUGIN_LIST_EXTENDED_OPERATION 7
+#define PLUGIN_LIST_BACKEND_MAX 8
+
+/* Global Plugins */
+#define PLUGIN_LIST_ACL 9
+#define PLUGIN_LIST_MATCHINGRULE 10
+#define PLUGIN_LIST_SYNTAX 11
+#define PLUGIN_LIST_ENTRY 12
+#define PLUGIN_LIST_OBJECT 13
+#define PLUGIN_LIST_PWD_STORAGE_SCHEME 14
+#define PLUGIN_LIST_VATTR_SP 15 /* DBDB */
+#define PLUGIN_LIST_REVER_PWD_STORAGE_SCHEME 16
+#define PLUGIN_LIST_LDBM_ENTRY_FETCH_STORE 17
+#define PLUGIN_LIST_INDEX 18
+#define PLUGIN_LIST_GLOBAL_MAX 19
+
+/* plugin configuration attributes */
+#define ATTR_PLUGIN_PATH "nsslapd-pluginPath"
+#define ATTR_PLUGIN_INITFN "nsslapd-pluginInitFunc"
+#define ATTR_PLUGIN_TYPE "nsslapd-pluginType"
+#define ATTR_PLUGIN_PLUGINID "nsslapd-pluginId"
+#define ATTR_PLUGIN_VERSION "nsslapd-pluginVersion"
+#define ATTR_PLUGIN_VENDOR "nsslapd-pluginVendor"
+#define ATTR_PLUGIN_DESC "nsslapd-pluginDescription"
+#define ATTR_PLUGIN_ENABLED "nsslapd-pluginEnabled"
+#define ATTR_PLUGIN_ARG "nsslapd-pluginArg"
+#define ATTR_PLUGIN_BACKEND "nsslapd-backend"
+#define ATTR_PLUGIN_SCHEMA_CHECK "nsslapd-schemaCheck"
+#define ATTR_PLUGIN_LOG_ACCESS "nsslapd-logAccess"
+#define ATTR_PLUGIN_LOG_AUDIT "nsslapd-logAudit"
+#define ATTR_PLUGIN_TARGET_SUBTREE "nsslapd-targetSubtree"
+#define ATTR_PLUGIN_BIND_SUBTREE "nsslapd-bindSubtree"
+#define ATTR_PLUGIN_INVOKE_FOR_REPLOP "nsslapd-invokeForReplOp"
+
+/* plugin action states */
+enum
+{
+ PLGC_OFF, /* internal operation action is on */
+ PLGC_ON, /* internal operation action is off */
+ PLGC_UPTOPLUGIN /* internal operation action is left up to plugin */
+};
+
+/* special data specifications */
+enum
+{
+ PLGC_DATA_LOCAL, /* plugin has access to all data hosted by this server */
+ PLGC_DATA_REMOTE, /* plugin has access to all requests for data not hosted by this server */
+ PLGC_DATA_BIND_ANONYMOUS, /* plugin bind function should be invoked for anonymous binds */
+ PLGC_DATA_BIND_ROOT, /* plugin bind function should be invoked for directory manager binds */
+ PLGC_DATA_MAX
+};
+
+/* DataList definition */
+struct datalist
+{
+ void **elements; /* array of elements */
+ int element_count; /* number of elements in the array */
+ int alloc_count; /* number of allocated nodes in the array */
+}datalist;
+
+/* data available to plugins */
+typedef struct target_data
+{
+ DataList subtrees; /* regular DIT subtrees acessible to the plugin */
+ PRBool special_data [PLGC_DATA_MAX]; /* array of special data specification */
+}PluginTargetData;
+
+struct pluginconfig{
+ PluginTargetData plgc_target_subtrees; /* list of subtrees accessible by the plugin */
+ PluginTargetData plgc_bind_subtrees; /* the list of subtrees for which plugin in invoked during bind operation */
+ PRBool plgc_schema_check; /* inidcates whether schema check is performed during internal op */
+ PRBool plgc_log_change; /* indicates whether changes are logged during internal op */
+ PRBool plgc_log_access; /* indicates whether internal op is recorded in access log */
+ PRBool plgc_log_audit; /* indicates whether internal op is recorded in audit log */
+ PRBool plgc_invoke_for_replop;/* indicates that plugin should be invoked for internal operations */
+};
+
+struct slapdplugin {
+ void *plg_private; /* data private to plugin */
+ char *plg_version; /* version of this plugin */
+ int plg_argc; /* argc from config file */
+ char **plg_argv; /* args from config file */
+ char *plg_libpath; /* library path for dll/so */
+ char *plg_initfunc; /* init symbol */
+ IFP plg_close; /* close function */
+ Slapi_PluginDesc plg_desc; /* vendor's info */
+ char *plg_name; /* used for plugin rdn in cn=config */
+ struct slapdplugin *plg_next; /* for plugin lists */
+ int plg_type; /* discriminates union */
+ char *plg_dn; /* config dn for this plugin */
+ struct slapdplugin *plg_group; /* pointer to the group to which this plugin belongs */
+ struct pluginconfig plg_conf; /* plugin configuration parameters */
+ IFP plg_cleanup; /* cleanup function */
+ IFP plg_start; /* start function */
+ IFP plg_poststart; /* poststart function */
+
+/* NOTE: These LDIF2DB and DB2LDIF fn pointers are internal only for now.
+ I don't believe you can get these functions from a plug-in and
+ then call them without knowing what IFP or VFP0 are. (These aren't
+ declared in slapi-plugin.h.) More importantly, it's a pretty ugly
+ way to get to these functions. (Do we want people to get locked into
+ this?)
+
+ The correct way to do this would be to expose these functions as
+ front-end API functions. We can fix this for the next release.
+ (No one has the time right now.)
+ */
+ union { /* backend database plugin structure */
+ struct plg_un_database_backend {
+ IFP plg_un_db_bind; /* bind */
+ IFP plg_un_db_unbind; /* unbind */
+ IFP plg_un_db_search; /* search */
+ IFP plg_un_db_next_search_entry; /* iterate */
+ IFP plg_un_db_next_search_entry_ext;
+ IFP plg_un_db_entry_release;
+ IFP plg_un_db_compare; /* compare */
+ IFP plg_un_db_modify; /* modify */
+ IFP plg_un_db_modrdn; /* modrdn */
+ IFP plg_un_db_add; /* add */
+ IFP plg_un_db_delete; /* delete */
+ IFP plg_un_db_abandon; /* abandon */
+ IFP plg_un_db_config; /* config */
+ IFP plg_un_db_flush; /* close */
+ IFP plg_un_db_seq; /* sequence */
+ IFP plg_un_db_entry; /* entry send */
+ IFP plg_un_db_referral; /* referral send */
+ IFP plg_un_db_result; /* result send */
+ IFP plg_un_db_ldif2db; /* ldif 2 database */
+ IFP plg_un_db_db2ldif; /* database 2 ldif */
+ IFP plg_un_db_db2index; /* database 2 index */
+ IFP plg_un_db_archive2db; /* ldif 2 database */
+ IFP plg_un_db_db2archive; /* database 2 ldif */
+#if defined(UPGRADEDB)
+ IFP plg_un_db_upgradedb; /* convert old idl to new */
+#endif
+ IFP plg_un_db_begin; /* dbase txn begin */
+ IFP plg_un_db_commit; /* dbase txn commit */
+ IFP plg_un_db_abort; /* dbase txn abort */
+ IFP plg_un_db_dbsize; /* database size */
+ IFP plg_un_db_dbtest; /* database size */
+ IFP plg_un_db_rmdb; /* database remove */
+ IFP plg_un_db_register_dn_callback; /* Register a function to call when a operation is applied to a given DN */
+ IFP plg_un_db_register_oc_callback; /* Register a function to call when a operation is applied to a given ObjectClass */
+ IFP plg_un_db_init_instance; /* initializes new db instance */
+ IFP plg_un_db_wire_import; /* fast replica update */
+ } plg_un_db;
+#define plg_bind plg_un.plg_un_db.plg_un_db_bind
+#define plg_unbind plg_un.plg_un_db.plg_un_db_unbind
+#define plg_search plg_un.plg_un_db.plg_un_db_search
+#define plg_next_search_entry plg_un.plg_un_db.plg_un_db_next_search_entry
+#define plg_next_search_entry_ext plg_un.plg_un_db.plg_un_db_next_search_entry_ext
+#define plg_entry_release plg_un.plg_un_db.plg_un_db_entry_release
+#define plg_compare plg_un.plg_un_db.plg_un_db_compare
+#define plg_modify plg_un.plg_un_db.plg_un_db_modify
+#define plg_modrdn plg_un.plg_un_db.plg_un_db_modrdn
+#define plg_add plg_un.plg_un_db.plg_un_db_add
+#define plg_delete plg_un.plg_un_db.plg_un_db_delete
+#define plg_abandon plg_un.plg_un_db.plg_un_db_abandon
+#define plg_config plg_un.plg_un_db.plg_un_db_config
+#define plg_flush plg_un.plg_un_db.plg_un_db_flush
+#define plg_seq plg_un.plg_un_db.plg_un_db_seq
+#define plg_entry plg_un.plg_un_db.plg_un_db_entry
+#define plg_referral plg_un.plg_un_db.plg_un_db_referral
+#define plg_result plg_un.plg_un_db.plg_un_db_result
+#define plg_ldif2db plg_un.plg_un_db.plg_un_db_ldif2db
+#define plg_db2ldif plg_un.plg_un_db.plg_un_db_db2ldif
+#define plg_db2index plg_un.plg_un_db.plg_un_db_db2index
+#define plg_archive2db plg_un.plg_un_db.plg_un_db_archive2db
+#define plg_db2archive plg_un.plg_un_db.plg_un_db_db2archive
+#if defined(UPGRADEDB)
+#define plg_upgradedb plg_un.plg_un_db.plg_un_db_upgradedb
+#endif
+#define plg_dbsize plg_un.plg_un_db.plg_un_db_dbsize
+#define plg_dbtest plg_un.plg_un_db.plg_un_db_dbtest
+#define plg_rmdb plg_un.plg_un_db.plg_un_db_rmdb
+#define plg_init_instance plg_un.plg_un_db.plg_un_db_init_instance
+#define plg_wire_import plg_un.plg_un_db.plg_un_db_wire_import
+
+ /* extended operation plugin structure */
+ struct plg_un_protocol_extension {
+ char **plg_un_pe_exoids; /* exop oids */
+ char **plg_un_pe_exnames; /* exop names (may be NULL) */
+ IFP plg_un_pe_exhandler; /* handler */
+ } plg_un_pe;
+#define plg_exoids plg_un.plg_un_pe.plg_un_pe_exoids
+#define plg_exnames plg_un.plg_un_pe.plg_un_pe_exnames
+#define plg_exhandler plg_un.plg_un_pe.plg_un_pe_exhandler
+
+
+ /* pre-operation plugin structure */
+ struct plg_un_pre_operation {
+ IFP plg_un_pre_bind; /* bind */
+ IFP plg_un_pre_unbind; /* unbind */
+ IFP plg_un_pre_search; /* search */
+ IFP plg_un_pre_compare; /* compare */
+ IFP plg_un_pre_modify; /* modify */
+ IFP plg_un_pre_modrdn; /* modrdn */
+ IFP plg_un_pre_add; /* add */
+ IFP plg_un_pre_delete; /* delete */
+ IFP plg_un_pre_abandon; /* abandon */
+ IFP plg_un_pre_entry; /* entry send */
+ IFP plg_un_pre_referral; /* referral send */
+ IFP plg_un_pre_result; /* result send */
+ } plg_un_pre;
+#define plg_prebind plg_un.plg_un_pre.plg_un_pre_bind
+#define plg_preunbind plg_un.plg_un_pre.plg_un_pre_unbind
+#define plg_presearch plg_un.plg_un_pre.plg_un_pre_search
+#define plg_precompare plg_un.plg_un_pre.plg_un_pre_compare
+#define plg_premodify plg_un.plg_un_pre.plg_un_pre_modify
+#define plg_premodrdn plg_un.plg_un_pre.plg_un_pre_modrdn
+#define plg_preadd plg_un.plg_un_pre.plg_un_pre_add
+#define plg_predelete plg_un.plg_un_pre.plg_un_pre_delete
+#define plg_preabandon plg_un.plg_un_pre.plg_un_pre_abandon
+#define plg_preentry plg_un.plg_un_pre.plg_un_pre_entry
+#define plg_prereferral plg_un.plg_un_pre.plg_un_pre_referral
+#define plg_preresult plg_un.plg_un_pre.plg_un_pre_result
+
+ /* post-operation plugin structure */
+ struct plg_un_post_operation {
+ IFP plg_un_post_bind; /* bind */
+ IFP plg_un_post_unbind; /* unbind */
+ IFP plg_un_post_search; /* search */
+ IFP plg_un_post_searchfail; /* failed search */
+ IFP plg_un_post_compare; /* compare */
+ IFP plg_un_post_modify; /* modify */
+ IFP plg_un_post_modrdn; /* modrdn */
+ IFP plg_un_post_add; /* add */
+ IFP plg_un_post_delete; /* delete */
+ IFP plg_un_post_abandon; /* abandon */
+ IFP plg_un_post_entry; /* entry send */
+ IFP plg_un_post_referral; /* referral send */
+ IFP plg_un_post_result; /* result send */
+ } plg_un_post;
+#define plg_postbind plg_un.plg_un_post.plg_un_post_bind
+#define plg_postunbind plg_un.plg_un_post.plg_un_post_unbind
+#define plg_postsearch plg_un.plg_un_post.plg_un_post_search
+#define plg_postsearchfail plg_un.plg_un_post.plg_un_post_searchfail
+#define plg_postcompare plg_un.plg_un_post.plg_un_post_compare
+#define plg_postmodify plg_un.plg_un_post.plg_un_post_modify
+#define plg_postmodrdn plg_un.plg_un_post.plg_un_post_modrdn
+#define plg_postadd plg_un.plg_un_post.plg_un_post_add
+#define plg_postdelete plg_un.plg_un_post.plg_un_post_delete
+#define plg_postabandon plg_un.plg_un_post.plg_un_post_abandon
+#define plg_postentry plg_un.plg_un_post.plg_un_post_entry
+#define plg_postreferral plg_un.plg_un_post.plg_un_post_referral
+#define plg_postresult plg_un.plg_un_post.plg_un_post_result
+
+ /* backend pre-operation plugin structure */
+ struct plg_un_bepre_operation {
+ IFP plg_un_bepre_modify; /* modify */
+ IFP plg_un_bepre_modrdn; /* modrdn */
+ IFP plg_un_bepre_add; /* add */
+ IFP plg_un_bepre_delete; /* delete */
+ } plg_un_bepre;
+#define plg_bepremodify plg_un.plg_un_bepre.plg_un_bepre_modify
+#define plg_bepremodrdn plg_un.plg_un_bepre.plg_un_bepre_modrdn
+#define plg_bepreadd plg_un.plg_un_bepre.plg_un_bepre_add
+#define plg_bepredelete plg_un.plg_un_bepre.plg_un_bepre_delete
+
+ /* backend post-operation plugin structure */
+ struct plg_un_bepost_operation {
+ IFP plg_un_bepost_modify; /* modify */
+ IFP plg_un_bepost_modrdn; /* modrdn */
+ IFP plg_un_bepost_add; /* add */
+ IFP plg_un_bepost_delete; /* delete */
+ } plg_un_bepost;
+#define plg_bepostmodify plg_un.plg_un_bepost.plg_un_bepost_modify
+#define plg_bepostmodrdn plg_un.plg_un_bepost.plg_un_bepost_modrdn
+#define plg_bepostadd plg_un.plg_un_bepost.plg_un_bepost_add
+#define plg_bepostdelete plg_un.plg_un_bepost.plg_un_bepost_delete
+
+ /* internal pre-operation plugin structure */
+ struct plg_un_internal_pre_operation {
+ IFP plg_un_internal_pre_modify; /* modify */
+ IFP plg_un_internal_pre_modrdn; /* modrdn */
+ IFP plg_un_internal_pre_add; /* add */
+ IFP plg_un_internal_pre_delete; /* delete */
+ } plg_un_internal_pre;
+#define plg_internal_pre_modify plg_un.plg_un_internal_pre.plg_un_internal_pre_modify
+#define plg_internal_pre_modrdn plg_un.plg_un_internal_pre.plg_un_internal_pre_modrdn
+#define plg_internal_pre_add plg_un.plg_un_internal_pre.plg_un_internal_pre_add
+#define plg_internal_pre_delete plg_un.plg_un_internal_pre.plg_un_internal_pre_delete
+
+ /* internal post-operation plugin structure */
+ struct plg_un_internal_post_operation {
+ IFP plg_un_internal_post_modify; /* modify */
+ IFP plg_un_internal_post_modrdn; /* modrdn */
+ IFP plg_un_internal_post_add; /* add */
+ IFP plg_un_internal_post_delete; /* delete */
+ } plg_un_internal_post;
+#define plg_internal_post_modify plg_un.plg_un_internal_post.plg_un_internal_post_modify
+#define plg_internal_post_modrdn plg_un.plg_un_internal_post.plg_un_internal_post_modrdn
+#define plg_internal_post_add plg_un.plg_un_internal_post.plg_un_internal_post_add
+#define plg_internal_post_delete plg_un.plg_un_internal_post.plg_un_internal_post_delete
+
+ /* matching rule plugin structure */
+ struct plg_un_matching_rule {
+ IFP plg_un_mr_filter_create; /* factory function */
+ IFP plg_un_mr_indexer_create; /* factory function */
+ } plg_un_mr;
+#define plg_mr_filter_create plg_un.plg_un_mr.plg_un_mr_filter_create
+#define plg_mr_indexer_create plg_un.plg_un_mr.plg_un_mr_indexer_create
+
+ /* syntax plugin structure */
+ struct plg_un_syntax_struct {
+ IFP plg_un_syntax_filter_ava;
+ IFP plg_un_syntax_filter_ava_sv;
+ IFP plg_un_syntax_filter_sub;
+ IFP plg_un_syntax_filter_sub_sv;
+ IFP plg_un_syntax_values2keys;
+ IFP plg_un_syntax_values2keys_sv;
+ IFP plg_un_syntax_assertion2keys_ava;
+ IFP plg_un_syntax_assertion2keys_sub;
+ int plg_un_syntax_flags;
+/*
+ from slapi-plugin.h
+#define SLAPI_PLUGIN_SYNTAX_FLAG_ORKEYS 1
+#define SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING 2
+*/
+ char **plg_un_syntax_names;
+ char *plg_un_syntax_oid;
+ IFP plg_un_syntax_compare;
+ } plg_un_syntax;
+#define plg_syntax_filter_ava plg_un.plg_un_syntax.plg_un_syntax_filter_ava
+#define plg_syntax_filter_sub plg_un.plg_un_syntax.plg_un_syntax_filter_sub
+#define plg_syntax_values2keys plg_un.plg_un_syntax.plg_un_syntax_values2keys
+#define plg_syntax_assertion2keys_ava plg_un.plg_un_syntax.plg_un_syntax_assertion2keys_ava
+#define plg_syntax_assertion2keys_sub plg_un.plg_un_syntax.plg_un_syntax_assertion2keys_sub
+#define plg_syntax_flags plg_un.plg_un_syntax.plg_un_syntax_flags
+#define plg_syntax_names plg_un.plg_un_syntax.plg_un_syntax_names
+#define plg_syntax_oid plg_un.plg_un_syntax.plg_un_syntax_oid
+#define plg_syntax_compare plg_un.plg_un_syntax.plg_un_syntax_compare
+
+ struct plg_un_acl_struct {
+ IFP plg_un_acl_init;
+ IFP plg_un_acl_syntax_check;
+ IFP plg_un_acl_access_allowed;
+ IFP plg_un_acl_mods_allowed;
+ IFP plg_un_acl_mods_update;
+ } plg_un_acl;
+#define plg_acl_init plg_un.plg_un_acl.plg_un_acl_init
+#define plg_acl_syntax_check plg_un.plg_un_acl.plg_un_acl_syntax_check
+#define plg_acl_access_allowed plg_un.plg_un_acl.plg_un_acl_access_allowed
+#define plg_acl_mods_allowed plg_un.plg_un_acl.plg_un_acl_mods_allowed
+#define plg_acl_mods_update plg_un.plg_un_acl.plg_un_acl_mods_update
+
+ /* password storage scheme (kexcoff) */
+ struct plg_un_pwd_storage_scheme_struct {
+ char *plg_un_pwd_storage_scheme_name; /* SHA, SSHA...*/
+ CFP plg_un_pwd_storage_scheme_enc;
+ IFP plg_un_pwd_storage_scheme_dec;
+ IFP plg_un_pwd_storage_scheme_cmp;
+ } plg_un_pwd_storage_scheme;
+#define plg_pwdstorageschemename plg_un.plg_un_pwd_storage_scheme.plg_un_pwd_storage_scheme_name
+#define plg_pwdstorageschemeenc plg_un.plg_un_pwd_storage_scheme.plg_un_pwd_storage_scheme_enc
+#define plg_pwdstorageschemedec plg_un.plg_un_pwd_storage_scheme.plg_un_pwd_storage_scheme_dec
+#define plg_pwdstorageschemecmp plg_un.plg_un_pwd_storage_scheme.plg_un_pwd_storage_scheme_cmp
+
+ /* entry fetch/store */
+ struct plg_un_entry_fetch_store_struct {
+ IFP plg_un_entry_fetch_func;
+ IFP plg_un_entry_store_func;
+ } plg_un_entry_fetch_store;
+#define plg_entryfetchfunc plg_un.plg_un_entry_fetch_store.plg_un_entry_fetch_func
+#define plg_entrystorefunc plg_un.plg_un_entry_fetch_store.plg_un_entry_store_func
+ } plg_un;
+};
+
+/*
+ * represents a "database"
+ */
+
+typedef struct backend {
+ Slapi_DN **be_suffix; /* the DN suffixes of data in this backend */
+ PRLock *be_suffixlock;
+ int be_suffixcount;
+ char *be_basedn; /* The base dn for the config & monitor dns */
+ char *be_configdn; /* The config dn for this backend */
+ char *be_monitordn; /* The monitor dn for this backend */
+ int be_readonly; /* 1 => db is in "read only" mode */
+ int be_sizelimit; /* size limit for this backend */
+ int be_timelimit; /* time limit for this backend */
+ int be_maxnestlevel; /* Max nest level for acl group evaluation */
+ int be_noacl; /* turn off front end acl for this be */
+ int be_lastmod; /* keep track of lastmodified{by,time} */
+ char *be_type; /* type of database */
+ char *be_backendconfig; /* backend config filename */
+ char **be_include; /* include files within this db definition */
+ int be_private; /* Internal backends use this to hide from the user */
+ int be_logchanges; /* changes to this backend should be logged in the changelog */
+ int (*be_writeconfig)(Slapi_PBlock *pb); /* function to call to make this
+ backend write its conf file */
+ /*
+ * backend database api function ptrs and args (to do operations)
+ */
+ struct slapdplugin *be_database; /* single plugin */
+#define be_bind be_database->plg_bind
+#define be_unbind be_database->plg_unbind
+#define be_search be_database->plg_search
+#define be_next_search_entry be_database->plg_next_search_entry
+#define be_next_search_entry_ext be_database->plg_next_search_entry_ext
+#define be_entry_release be_database->plg_entry_release
+#define be_compare be_database->plg_compare
+#define be_modify be_database->plg_modify
+#define be_modrdn be_database->plg_modrdn
+#define be_add be_database->plg_add
+#define be_delete be_database->plg_delete
+#define be_abandon be_database->plg_abandon
+#define be_config be_database->plg_config
+#define be_close be_database->plg_close
+#define be_flush be_database->plg_flush
+#define be_start be_database->plg_start
+#define be_poststart be_database->plg_poststart
+#define be_seq be_database->plg_seq
+#define be_ldif2db be_database->plg_ldif2db
+#if defined(UPGRADEDB)
+#define be_upgradedb be_database->plg_upgradedb
+#endif
+#define be_db2ldif be_database->plg_db2ldif
+#define be_db2index be_database->plg_db2index
+#define be_archive2db be_database->plg_archive2db
+#define be_db2archive be_database->plg_db2archive
+#define be_dbsize be_database->plg_dbsize
+#define be_dbtest be_database->plg_dbtest
+#define be_rmdb be_database->plg_rmdb
+#define be_result be_database->plg_result
+#define be_init_instance be_database->plg_init_instance
+#define be_cleanup be_database->plg_cleanup
+#define be_wire_import be_database->plg_wire_import
+
+ void *be_instance_info; /* If the database plugin pointed to by
+ * be_database supports more than one instance,
+ * it can use this to keep track of the
+ * multiple instances. */
+
+ char *be_name; /* The mapping tree and command line utils
+ * refer to backends by name. */
+ int be_mapped; /* True if the be is represented by a node
+ * in the mapping tree. */
+
+ /*struct slapdplugin *be_plugin_list[PLUGIN_LIST_BACKEND_MAX]; list of plugins */
+
+ int be_delete_on_exit; /* marks db for deletion - used to remove changelog*/
+ int be_state; /* indicates current database state */
+ PRLock *be_state_lock; /* lock under which to modify the state */
+
+ int be_flags; /* misc properties. See BE_FLAG_xxx defined in slapi-private.h */
+ PRRWLock *be_lock;
+ PRRWLock *vlvSearchList_lock;
+ void *vlvSearchList;
+} backend;
+
+enum
+{
+ BE_STATE_STOPPED = 1, /* backend is initialized but not started */
+ BE_STATE_STARTED, /* backend is started */
+ BE_STATE_CLEANED, /* backend was cleaned up */
+ BE_STATE_DELETED /* backend is removed */
+};
+
+struct conn;
+struct op;
+
+typedef void (*result_handler)( struct conn *, struct op *, int, char *,
+ char *, int, struct berval ** );
+typedef int (*search_entry_handler)( Slapi_Backend *, struct conn *, struct op *,
+ struct slapi_entry * );
+typedef int (*search_referral_handler)( Slapi_Backend *, struct conn *, struct op *,
+ struct berval ** );
+typedef CSN * (*csngen_handler)( Slapi_PBlock *pb, const CSN *basecsn );
+typedef int (*replica_attr_handler)( Slapi_PBlock *pb, const char *type, void **value );
+
+/*
+ * LDAP Operation results.
+ */
+typedef struct slapi_operation_results
+{
+ unsigned long operation_type;
+
+ int opreturn;
+
+ LDAPControl **result_controls;/* ctrls to be returned w/result */
+
+ int result_code;
+ char* result_text;
+ char* result_matched;
+
+ union
+ {
+ struct bind_results
+ {
+ struct berval *bind_ret_saslcreds; /* v3 serverSaslCreds */
+ } r_bind;
+
+ struct search_results
+ {
+ /*
+ * Search results set - opaque cookie passed between backend
+ * and frontend to iterate over search results.
+ */
+ void *search_result_set;
+ /* Next entry returned from iterating */
+ Slapi_Entry *search_result_entry;
+ /* opaque pointer owned by the backend. Used in searches with
+ * lookahead */
+ void *opaque_backend_ptr;
+ /* number of entries sent in response to this search request */
+ int nentries;
+ /* Any referrals encountered during the search */
+ struct berval **search_referrals;
+ } r_search;
+
+ struct extended_results
+ {
+ char *exop_ret_oid;
+ struct berval *exop_ret_value;
+ } r_extended;
+ } r;
+} slapi_operation_results;
+
+/*
+ * represents an operation pending from an ldap client
+ */
+typedef struct op {
+ BerElement *o_ber; /* ber of the request */
+ long o_msgid; /* msgid of the request */
+ unsigned long o_tag; /* tag of the request */
+ time_t o_time; /* time op was initiated */
+ PRIntervalTime o_interval; /* precise time op was initiated */
+ int o_isroot; /* requestor is manager */
+ Slapi_DN o_sdn; /* dn bound when op was initiated */
+ char *o_authtype; /* auth method used to bind dn */
+ int o_opid; /* id of this operation */
+ int o_connid; /* id of conn initiating this op; for logging only */
+ void *o_handler_data;
+ result_handler o_result_handler;
+ search_entry_handler o_search_entry_handler;
+ search_referral_handler o_search_referral_handler;
+ csngen_handler o_csngen_handler;
+ replica_attr_handler o_replica_attr_handler;
+ struct op *o_next; /* next operation pending */
+ int o_status; /* status (see SLAPI_OP_STATUS_... below */
+ char **o_searchattrs;/* original attr names requested */ /* JCM - Search Param */
+ unsigned long o_flags; /* flags for this operation */
+ void *o_extension; /* plugins are able to extend the Operation object */
+ Slapi_DN *o_target_spec; /* used to decide which plugins should be called for the operation */
+ unsigned long o_abandoned_op; /* operation abandoned by this operation - used to decide which plugins to invoke */
+ struct slapi_operation_parameters o_params;
+ struct slapi_operation_results o_results;
+} Operation;
+
+/*
+ * Operation status (o_status) values.
+ * The normal progression is from PROCESSING to RESULT_SENT, with
+ * WILL_COMPLETE as an optional intermediate state.
+ * For operations that are abandoned, the progression is from PROCESSING
+ * to ABANDONED.
+ */
+#define SLAPI_OP_STATUS_PROCESSING 0 /* the normal state */
+#define SLAPI_OP_STATUS_ABANDONED 1 /* op. has been abandoned */
+#define SLAPI_OP_STATUS_WILL_COMPLETE 2 /* no more abandon checks
+ will be done */
+#define SLAPI_OP_STATUS_RESULT_SENT 3 /* result has been sent to the
+ client (or we tried to do
+ so and failed) */
+
+/*
+ * represents a connection from an ldap client
+ */
+
+struct Conn_Private;
+typedef struct Conn_private Conn_private;
+struct _sasl_io_private;
+typedef struct _sasl_io_private sasl_io_private;
+
+typedef struct conn {
+ Sockbuf *c_sb; /* ber connection stuff */
+ int c_sd; /* the actual socket descriptor */
+ int c_ldapversion; /* version of LDAP protocol */
+ char *c_dn; /* current DN bound to this conn */
+ int c_isroot; /* c_dn was rootDN at time of bind? */
+ int c_isreplication_session; /* this connection is a replication session */
+ char *c_authtype; /* auth method used to bind c_dn */
+ char *c_external_dn; /* client DN of this SSL session */
+ char *c_external_authtype; /* used for c_external_dn */
+ PRNetAddr *cin_addr; /* address of client on this conn */
+ PRNetAddr *cin_destaddr; /* address client connected to */
+ struct berval **c_domain; /* DNS names of client */
+ Operation *c_ops; /* list of pending operations */
+ int c_gettingber; /* in the middle of ber_get_next */
+ BerElement *c_currentber; /* ber we're getting */
+ time_t c_starttime; /* when the connection was opened */
+ int c_connid; /* id of this connection for stats*/
+ int c_opsinitiated; /* # ops initiated/next op id */
+ PRInt32 c_opscompleted; /* # ops completed */
+ PRInt32 c_threadnumber; /* # threads used in this conn */
+ int c_refcnt; /* # ops refering to this conn */
+ PRLock *c_mutex; /* protect each conn structure */
+ PRLock *c_pdumutex; /* only write one pdu at a time */
+ time_t c_idlesince; /* last time of activity on conn */
+ Conn_private *c_private; /* data which is not shared outside*/
+ /* connection.c */
+ int c_flags; /* Misc flags used only for SSL */
+ /* status currently */
+ int c_needpw; /* need new password */
+ CERTCertificate *c_client_cert; /* Client's Cert */
+ PRFileDesc * c_prfd; /* NSPR 2.1 FileDesc */
+ int c_ci; /* An index into the Connection array. For printing. */
+ int c_fdi; /* An index into the FD array. The FD this connection is using. */
+ struct conn * c_next; /* Pointer to the next and previous */
+ struct conn * c_prev; /* active connections in the table*/
+ Slapi_Backend *c_bi_backend; /* which backend is doing the import */
+ void *c_extension; /* plugins are able to extend the Connection object */
+ void *c_sasl_conn; /* sasl library connection sasl_conn_t */
+ sasl_io_private *c_sasl_io_private; /* Private data for SASL I/O Layer */
+ int c_enable_sasl_io; /* Flag to tell us to enable SASL I/O on the next read */
+ int c_sasl_io; /* Flag to tell us to enable SASL I/O on the next read */
+} Connection;
+#define CONN_FLAG_SSL 1 /* Is this connection an SSL connection or not ?
+ * Used to direct I/O code when SSL is handled differently
+ */
+#define CONN_FLAG_CLOSING 2 /* If this flag is set, then the connection has
+ * been marked for closing by a worker thread
+ * and the listener thread should close it. */
+#define CONN_FLAG_IMPORT 4 /* This connection has begun a bulk import
+ * (aka "fast replica init" aka "wire import"),
+ * so it can only accept adds & ext-ops.
+ */
+
+
+#define CONN_FLAG_SASL_CONTINUE 8 /* We're in a multi-stage sasl bind */
+
+#define CONN_FLAG_START_TLS 16 /* Flag set when an SSL connection is so after an
+ * Start TLS request operation.
+ */
+
+
+
+#define START_TLS_OID "1.3.6.1.4.1.1466.20037"
+
+
+#ifndef _WIN32
+#define SLAPD_POLL_FLAGS (POLLIN)
+#else
+#define SLAPD_POLL_FLAGS (PR_POLL_READ)
+#endif
+
+typedef struct slapi_pblock {
+ /* common */
+ Slapi_Backend *pb_backend;
+ Connection *pb_conn;
+ Operation *pb_op;
+ struct slapdplugin *pb_plugin; /* plugin being called */
+ int pb_opreturn;
+ void* pb_object; /* points to data private to plugin */
+ IFP pb_destroy_fn;
+ int pb_requestor_isroot;
+ /* config file */
+ char *pb_config_fname;
+ int pb_config_lineno;
+ int pb_config_argc;
+ char **pb_config_argv;
+
+ /* [pre|post]add arguments */
+ struct slapi_entry *pb_target_entry; /* JCM - Duplicated */
+ struct slapi_entry *pb_existing_dn_entry;
+ struct slapi_entry *pb_existing_uniqueid_entry;
+ struct slapi_entry *pb_parent_entry;
+ struct slapi_entry *pb_newparent_entry;
+
+ /* state of entry before and after add/delete/modify/moddn/modrdn */
+ struct slapi_entry *pb_pre_op_entry;
+ struct slapi_entry *pb_post_op_entry;
+ /* seq access arguments */
+ int pb_seq_type;
+ char *pb_seq_attrname;
+ char *pb_seq_val;
+ /* ldif2db arguments */
+ char *pb_ldif_file;
+ int pb_removedupvals;
+ char **pb_db2index_attrs;
+ int pb_ldif2db_noattrindexes;
+ /* db2ldif arguments */
+ int pb_ldif_printkey;
+ /* ldif2db/db2ldif/db2bak/bak2db args */
+ char *pb_instance_name;
+ Slapi_Task *pb_task;
+ int pb_task_flags;
+ /* matching rule arguments */
+ mrFilterMatchFn pb_mr_filter_match_fn;
+ IFP pb_mr_filter_index_fn;
+ IFP pb_mr_filter_reset_fn;
+ IFP pb_mr_index_fn;
+ char* pb_mr_oid;
+ char* pb_mr_type;
+ struct berval* pb_mr_value;
+ struct berval** pb_mr_values;
+ struct berval** pb_mr_keys;
+ unsigned int pb_mr_filter_reusable;
+ int pb_mr_query_operator;
+ unsigned int pb_mr_usage;
+
+ /* arguments for password storage scheme (kexcoff) */
+ char *pb_pwd_storage_scheme_user_passwd;
+ char *pb_pwd_storage_scheme_db_passwd;
+
+ /* controls we know about */
+ int pb_managedsait;
+
+ /* additional fields for plugin_internal_ldap_ops */
+ /* result code of internal ldap_operation */
+ int pb_internal_op_result;
+ /* pointer to array of results returned on search */
+ Slapi_Entry **pb_plugin_internal_search_op_entries;
+ char **pb_plugin_internal_search_op_referrals;
+ void *pb_plugin_identity; /* identifies plugin for internal operation */
+ void *pb_parent_txn; /* parent transaction ID */
+ void *pb_txn; /* transaction ID */
+
+ /* Size of the database on disk, in kilobytes */
+ unsigned int pb_dbsize;
+
+ /* THINGS BELOW THIS LINE EXIST ONLY IN SLAPI v2 (slapd 4.0+) */
+
+ /* ldif2db: array of files to import all at once */
+ char **pb_ldif_files;
+
+ char **pb_ldif_include;
+ char **pb_ldif_exclude;
+ int pb_ldif_dump_replica;
+ int pb_ldif_dump_uniqueid; /* dump uniqueid during db2ldif */
+ int pb_ldif_generate_uniqueid; /* generate uniqueid during db2ldif */
+/* JCMREPL int pb_ldif_load_state; */
+ char* pb_ldif_namespaceid; /* used for name based uniqueid generation */
+ int pb_ldif_encrypt; /* used to enable encrypt/decrypt on import and export */
+ /*
+ * notes to log with RESULT line in the access log
+ * these are actually stored as a bitmap; see slapi-plugin.h for
+ * defined notes.
+ */
+ unsigned int pb_operation_notes;
+ /*
+ * slapd command line arguments
+ */
+ int pb_slapd_argc;
+ char** pb_slapd_argv;
+ char *pb_slapd_configdir; /* the config directory passed to slapd on the command line */
+ LDAPControl **pb_ctrls_arg; /* allows to pass controls as arguments before
+ operation object is created */
+ int pb_dse_dont_add_write; /* if true, the dse is not written when an entry is added */
+ int pb_dse_add_merge; /* if true, if a duplicate entry is found when adding, the
+ new values are merged into the old entry */
+ int pb_dse_dont_check_dups; /* if false, use the "enhanced" version of str2entry to catch
+ more errors when adding dse entries; this can only be done
+ after the schema and syntax and matching rule plugins are
+ running */
+ int pb_dse_is_primary_file; /* for read callbacks: non-zero for primary file */
+ int pb_schema_user_defined_only; /* return user defined schema only */
+
+ /* NEW in 5.0 for getting back the backend result in frontend */
+ int pb_result_code; /* operation result code */
+ char * pb_result_text; /* result text when available */
+ char * pb_result_matched; /* macthed dn when NO SUCH OBJECT error */
+ int pb_nentries; /* number of entries to be returned */
+ struct berval **urls; /* urls of referrals to be returned */
+
+ /*
+ * wire import (fast replica init) arguments
+ */
+ struct slapi_entry *pb_import_entry;
+ int pb_import_state;
+
+ int pb_destroy_content; /* flag to indicate that pblock content should be
+ destroyed when pblock is destroyed */
+ int pb_dse_reapply_mods; /* if true, dse_modify will reapply mods after modify callback */
+ char * pb_urp_naming_collision_dn; /* replication naming conflict removal */
+ char * pb_urp_tombstone_uniqueid; /* replication change tombstone */
+ int pb_server_running; /* indicate that server is running */
+ int pb_backend_count; /* instance count involved in the op */
+
+ /* For password policy control */
+ int pb_pwpolicy_ctrl;
+} slapi_pblock;
+
+/* The referral element */
+typedef struct ref {
+ char *ref_dn; /* The DN of the entry that contains the referral */
+ struct berval *ref_referral; /* The referral. It looks like: ldap://host:port */
+ int ref_reads; /* 1 if refer searches, 0 else */
+ int ref_writes; /* 1 if refer modifications, 0 else */
+} Ref;
+
+/* The head of the referral array. */
+typedef struct ref_array {
+ rwl *ra_rwlock; /* Read-write lock struct to protect this thing */
+ int ra_size; /* The size of this puppy (NOT the number of entries)*/
+ int ra_nextindex; /* The next free index */
+ int ra_readcount; /* The number of copyingfroms in the list */
+ Ref **ra_refs; /* The array of referrals*/
+} Ref_Array;
+
+#define GR_LOCK_READ() grefs->ra_rwlock->rwl_acquire_read_lock( grefs->ra_rwlock)
+#define GR_UNLOCK_READ() grefs->ra_rwlock->rwl_relinquish_read_lock( grefs->ra_rwlock )
+#define GR_LOCK_WRITE() grefs->ra_rwlock->rwl_acquire_write_lock( grefs->ra_rwlock )
+#define GR_UNLOCK_WRITE() grefs->ra_rwlock->rwl_relinquish_write_lock( grefs->ra_rwlock )
+
+/*
+ * This structure is used to pass a pair of port numbers to the daemon
+ * function. The daemon is the root of a forked thread.
+ */
+
+typedef struct daemon_ports_s {
+ int n_port;
+ int s_port;
+ PRNetAddr n_listenaddr;
+ PRNetAddr s_listenaddr;
+#if defined( XP_WIN32 )
+ int n_socket;
+ int s_socket_native;
+#else
+ PRFileDesc *n_socket;
+#endif
+ PRFileDesc *s_socket;
+} daemon_ports_t;
+
+
+/* Definition for plugin syntax compare routine */
+typedef int (*value_compare_fn_type)(const struct berval *,const struct berval *);
+
+#include "pw.h"
+
+#include "proto-slap.h"
+LDAPMod** entry2mods(Slapi_Entry *, LDAPMod **, int *, int);
+
+/* SNMP Variables */
+struct snmp_ops_tbl_t{
+ PRInt32 *dsAnonymousBinds;
+ PRInt32 *dsUnAuthBinds;
+ PRInt32 *dsSimpleAuthBinds;
+ PRInt32 *dsStrongAuthBinds;
+ PRInt32 *dsBindSecurityErrors;
+ PRInt32 *dsInOps;
+ PRInt32 *dsReadOps;
+ PRInt32 *dsCompareOps;
+ PRInt32 *dsAddEntryOps;
+ PRInt32 *dsRemoveEntryOps;
+ PRInt32 *dsModifyEntryOps;
+ PRInt32 *dsModifyRDNOps;
+ PRInt32 *dsListOps;
+ PRInt32 *dsSearchOps;
+ PRInt32 *dsOneLevelSearchOps;
+ PRInt32 *dsWholeSubtreeSearchOps;
+ PRInt32 *dsReferrals;
+ PRInt32 *dsChainings;
+ PRInt32 *dsSecurityErrors;
+ PRInt32 *dsErrors;
+ PRInt32 *dsConnections; /* Number of currently connected clients */
+ PRInt32 *dsConnectionSeq; /* Monotonically increasing number bumped on each new conn est */
+ PRInt32 *dsBytesRecv; /* Count of bytes read from clients */
+ PRInt32 *dsBytesSent; /* Count of bytes sent to clients */
+ PRInt32 *dsEntriesReturned;
+ PRInt32 *dsReferralsReturned;
+};
+
+struct snmp_entries_tbl_t{
+ /* entries table */
+ PRInt32 *dsMasterEntries;
+ PRInt32 *dsCopyEntries;
+ PRInt32 *dsCacheEntries;
+ PRInt32 *dsCacheHits;
+ PRInt32 *dsSlaveHits;
+};
+
+struct snmp_int_tbl_t{
+
+ /* interaction table */
+ PRInt32 *dsIntIndex;
+ char *dsName;
+ time_t *dsTimeOfCreation;
+ time_t *dsTimeOfLastAttempt;
+ time_t *dsTimeOfLastSuccess;
+ PRInt32 *dsFailuresSinceLastSuccess;
+ PRInt32 *dsFailures;
+ PRInt32 *dsSuccesses;
+ char *dsURL;
+};
+
+/* operation statistics */
+struct snmp_vars_t{
+ struct snmp_ops_tbl_t ops_tbl;
+ struct snmp_entries_tbl_t entries_tbl;
+ struct snmp_int_tbl_t int_tbl[NUM_SNMP_INT_TBL_ROWS];
+};
+
+#define ENTRY_POINT_PS_WAKEUP_ALL 102
+#define ENTRY_POINT_PS_SERVICE 105
+#define ENTRY_POINT_DISCONNECT_SERVER 107
+#define ENTRY_POINT_SLAPD_SSL_CLIENT_INIT 108
+#define ENTRY_POINT_SLAPD_SSL_INIT 109
+#define ENTRY_POINT_SLAPD_SSL_INIT2 110
+
+typedef void (*ps_wakeup_all_fn_ptr)( void );
+typedef void (*ps_service_fn_ptr)(Slapi_Entry *, Slapi_Entry *, int, int );
+typedef char *(*get_config_dn_fn_ptr)();
+typedef void (*get_disconnect_server_fn_ptr)(Connection *conn, int opconnid, int opid, PRErrorCode reason, PRInt32 error );
+typedef int (*slapd_SSL_client_init_fn_ptr)( void );
+typedef int (*modify_config_dse_fn_ptr)( Slapi_PBlock *pb );
+typedef int (*slapd_ssl_init_fn_ptr)( void );
+typedef int (*slapd_ssl_init_fn_ptr2)( PRFileDesc **s, int StartTLS);
+
+/*
+ * A structure of entry points in the NT exe which need
+ * to be available to DLLs.
+ */
+typedef struct _slapdEntryPoints {
+ caddr_t sep_ps_wakeup_all;
+ caddr_t sep_ps_service;
+ caddr_t sep_disconnect_server;
+ caddr_t sep_slapd_SSL_client_init;
+ caddr_t sep_slapd_ssl_init;
+ caddr_t sep_slapd_ssl_init2;
+} slapdEntryPoints;
+
+#if defined( XP_WIN32 )
+#define DLL_IMPORT_DATA _declspec( dllimport )
+#else
+#define DLL_IMPORT_DATA
+#endif
+
+/* Log types */
+#define SLAPD_ACCESS_LOG 0x1
+#define SLAPD_ERROR_LOG 0x2
+#define SLAPD_AUDIT_LOG 0x4
+
+#define CONFIG_DATABASE_ATTRIBUTE "nsslapd-database"
+#define CONFIG_PLUGIN_ATTRIBUTE "nsslapd-plugin"
+#define CONFIG_SIZELIMIT_ATTRIBUTE "nsslapd-sizelimit"
+#define CONFIG_TIMELIMIT_ATTRIBUTE "nsslapd-timelimit"
+#define CONFIG_SUFFIX_ATTRIBUTE "nsslapd-suffix"
+#define CONFIG_READONLY_ATTRIBUTE "nsslapd-readonly"
+#define CONFIG_REFERRAL_ATTRIBUTE "nsslapd-referral"
+#define CONFIG_OBJECTCLASS_ATTRIBUTE "nsslapd-objectclass"
+#define CONFIG_ATTRIBUTE_ATTRIBUTE "nsslapd-attribute"
+#define CONFIG_SCHEMACHECK_ATTRIBUTE "nsslapd-schemacheck"
+#define CONFIG_DS4_COMPATIBLE_SCHEMA_ATTRIBUTE "nsslapd-ds4-compatible-schema"
+#define CONFIG_SCHEMA_IGNORE_TRAILING_SPACES "nsslapd-schema-ignore-trailing-spaces"
+#define CONFIG_SCHEMAREPLACE_ATTRIBUTE "nsslapd-schemareplace"
+#define CONFIG_LOGLEVEL_ATTRIBUTE "nsslapd-errorlog-level"
+#define CONFIG_ACCESSLOGLEVEL_ATTRIBUTE "nsslapd-accesslog-level"
+#define CONFIG_ACCESSLOG_MODE_ATTRIBUTE "nsslapd-accesslog-mode"
+#define CONFIG_ERRORLOG_MODE_ATTRIBUTE "nsslapd-errorlog-mode"
+#define CONFIG_AUDITLOG_MODE_ATTRIBUTE "nsslapd-auditlog-mode"
+#define CONFIG_ACCESSLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-accesslog-maxlogsperdir"
+#define CONFIG_ERRORLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-errorlog-maxlogsperdir"
+#define CONFIG_AUDITLOG_MAXNUMOFLOGSPERDIR_ATTRIBUTE "nsslapd-auditlog-maxlogsperdir"
+#define CONFIG_ACCESSLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-accesslog-maxlogsize"
+#define CONFIG_ERRORLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-errorlog-maxlogsize"
+#define CONFIG_AUDITLOG_MAXLOGSIZE_ATTRIBUTE "nsslapd-auditlog-maxlogsize"
+#define CONFIG_ACCESSLOG_LOGROTATIONSYNCENABLED_ATTRIBUTE "nsslapd-accesslog-logrotationsync-enabled"
+#define CONFIG_ERRORLOG_LOGROTATIONSYNCENABLED_ATTRIBUTE "nsslapd-errorlog-logrotationsync-enabled"
+#define CONFIG_AUDITLOG_LOGROTATIONSYNCENABLED_ATTRIBUTE "nsslapd-auditlog-logrotationsync-enabled"
+#define CONFIG_ACCESSLOG_LOGROTATIONSYNCHOUR_ATTRIBUTE "nsslapd-accesslog-logrotationsynchour"
+#define CONFIG_ERRORLOG_LOGROTATIONSYNCHOUR_ATTRIBUTE "nsslapd-errorlog-logrotationsynchour"
+#define CONFIG_AUDITLOG_LOGROTATIONSYNCHOUR_ATTRIBUTE "nsslapd-auditlog-logrotationsynchour"
+#define CONFIG_ACCESSLOG_LOGROTATIONSYNCMIN_ATTRIBUTE "nsslapd-accesslog-logrotationsyncmin"
+#define CONFIG_ERRORLOG_LOGROTATIONSYNCMIN_ATTRIBUTE "nsslapd-errorlog-logrotationsyncmin"
+#define CONFIG_AUDITLOG_LOGROTATIONSYNCMIN_ATTRIBUTE "nsslapd-auditlog-logrotationsyncmin"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-accesslog-logrotationtime"
+#define CONFIG_ERRORLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-errorlog-logrotationtime"
+#define CONFIG_AUDITLOG_LOGROTATIONTIME_ATTRIBUTE "nsslapd-auditlog-logrotationtime"
+#define CONFIG_ACCESSLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logrotationtimeunit"
+#define CONFIG_ERRORLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logrotationtimeunit"
+#define CONFIG_AUDITLOG_LOGROTATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logrotationtimeunit"
+#define CONFIG_ACCESSLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logmaxdiskspace"
+#define CONFIG_ERRORLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logmaxdiskspace"
+#define CONFIG_AUDITLOG_MAXLOGDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logmaxdiskspace"
+#define CONFIG_ACCESSLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-accesslog-logminfreediskspace"
+#define CONFIG_ERRORLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-errorlog-logminfreediskspace"
+#define CONFIG_AUDITLOG_MINFREEDISKSPACE_ATTRIBUTE "nsslapd-auditlog-logminfreediskspace"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-accesslog-logexpirationtime"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-errorlog-logexpirationtime"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIME_ATTRIBUTE "nsslapd-auditlog-logexpirationtime"
+#define CONFIG_ACCESSLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-accesslog-logexpirationtimeunit"
+#define CONFIG_ERRORLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-errorlog-logexpirationtimeunit"
+#define CONFIG_AUDITLOG_LOGEXPIRATIONTIMEUNIT_ATTRIBUTE "nsslapd-auditlog-logexpirationtimeunit"
+#define CONFIG_ACCESSLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-accesslog-logging-enabled"
+#define CONFIG_ERRORLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-errorlog-logging-enabled"
+#define CONFIG_AUDITLOG_LOGGING_ENABLED_ATTRIBUTE "nsslapd-auditlog-logging-enabled"
+#define CONFIG_ROOTDN_ATTRIBUTE "nsslapd-rootdn"
+#define CONFIG_ROOTPW_ATTRIBUTE "nsslapd-rootpw"
+#define CONFIG_ROOTPWSTORAGESCHEME_ATTRIBUTE "nsslapd-rootpwstoragescheme"
+#define CONFIG_AUDITFILE_ATTRIBUTE "nsslapd-auditlog"
+#define CONFIG_LASTMOD_ATTRIBUTE "nsslapd-lastmod"
+#define CONFIG_INCLUDE_ATTRIBUTE "nsslapd-include"
+#define CONFIG_DYNAMICCONF_ATTRIBUTE "nsslapd-dynamicconf"
+#define CONFIG_USEROC_ATTRIBUTE "nsslapd-useroc"
+#define CONFIG_USERAT_ATTRIBUTE "nsslapd-userat"
+#define CONFIG_SVRTAB_ATTRIBUTE "nsslapd-svrtab"
+#ifndef _WIN32
+#define CONFIG_LOCALUSER_ATTRIBUTE "nsslapd-localuser"
+#endif /* !_WIN32 */
+#define CONFIG_LOCALHOST_ATTRIBUTE "nsslapd-localhost"
+#define CONFIG_PORT_ATTRIBUTE "nsslapd-port"
+#define CONFIG_WORKINGDIR_ATTRIBUTE "nsslapd-workingdir"
+#define CONFIG_LISTENHOST_ATTRIBUTE "nsslapd-listenhost"
+#define CONFIG_SECURITY_ATTRIBUTE "nsslapd-security"
+#define CONFIG_SSL3CIPHERS_ATTRIBUTE "nsslapd-SSL3ciphers"
+#define CONFIG_ACCESSLOG_ATTRIBUTE "nsslapd-accesslog"
+#define CONFIG_ERRORLOG_ATTRIBUTE "nsslapd-errorlog"
+#define CONFIG_INSTANCEDIR_ATTRIBUTE "nsslapd-instancedir"
+#define CONFIG_SECUREPORT_ATTRIBUTE "nsslapd-securePort"
+#define CONFIG_SECURELISTENHOST_ATTRIBUTE "nsslapd-securelistenhost"
+#define CONFIG_THREADNUMBER_ATTRIBUTE "nsslapd-threadnumber"
+#define CONFIG_MAXTHREADSPERCONN_ATTRIBUTE "nsslapd-maxthreadsperconn"
+#if !defined(_WIN32) && !defined(AIX)
+#define CONFIG_MAXDESCRIPTORS_ATTRIBUTE "nsslapd-maxdescriptors"
+#endif /* !_WIN32 && ! AIX */
+#define CONFIG_CONNTABLESIZE_ATTRIBUTE "nsslapd-conntablesize"
+#define CONFIG_RESERVEDESCRIPTORS_ATTRIBUTE "nsslapd-reservedescriptors"
+#define CONFIG_IDLETIMEOUT_ATTRIBUTE "nsslapd-idletimeout"
+#define CONFIG_IOBLOCKTIMEOUT_ATTRIBUTE "nsslapd-ioblocktimeout"
+#define CONFIG_ACCESSCONTROL_ATTRIBUTE "nsslapd-accesscontrol"
+#define CONFIG_GROUPEVALNESTLEVEL_ATTRIBUTE "nsslapd-groupevalnestlevel"
+#define CONFIG_NAGLE_ATTRIBUTE "nsslapd-nagle"
+#define CONFIG_PWPOLICY_LOCAL_ATTRIBUTE "nsslapd-pwpolicy-local"
+#define CONFIG_PW_CHANGE_ATTRIBUTE "passwordChange"
+#define CONFIG_PW_MUSTCHANGE_ATTRIBUTE "passwordMustChange"
+#define CONFIG_PW_SYNTAX_ATTRIBUTE "passwordCheckSyntax"
+#define CONFIG_PW_MINLENGTH_ATTRIBUTE "passwordMinLength"
+#define CONFIG_PW_EXP_ATTRIBUTE "passwordExp"
+#define CONFIG_PW_MAXAGE_ATTRIBUTE "passwordMaxAge"
+#define CONFIG_PW_MINAGE_ATTRIBUTE "passwordMinAge"
+#define CONFIG_PW_WARNING_ATTRIBUTE "passwordWarning"
+#define CONFIG_PW_HISTORY_ATTRIBUTE "passwordHistory"
+#define CONFIG_PW_INHISTORY_ATTRIBUTE "passwordInHistory"
+#define CONFIG_PW_LOCKOUT_ATTRIBUTE "passwordLockout"
+#define CONFIG_PW_STORAGESCHEME_ATTRIBUTE "passwordStorageScheme"
+#define CONFIG_PW_MAXFAILURE_ATTRIBUTE "passwordMaxFailure"
+#define CONFIG_PW_UNLOCK_ATTRIBUTE "passwordUnlock"
+#define CONFIG_PW_LOCKDURATION_ATTRIBUTE "passwordLockoutDuration"
+#define CONFIG_PW_RESETFAILURECOUNT_ATTRIBUTE "passwordResetFailureCount"
+#define CONFIG_PW_ISGLOBAL_ATTRIBUTE "passwordIsGlobalPolicy"
+#define CONFIG_PW_GRACELIMIT_ATTRIBUTE "passwordGraceLimit"
+#define CONFIG_ACCESSLOG_BUFFERING_ATTRIBUTE "nsslapd-accesslog-logbuffering"
+#define CONFIG_CSNLOGGING_ATTRIBUTE "nsslapd-csnlogging"
+#define CONFIG_RETURN_EXACT_CASE_ATTRIBUTE "nsslapd-return-exact-case"
+#define CONFIG_RESULT_TWEAK_ATTRIBUTE "nsslapd-result-tweak"
+#define CONFIG_REFERRAL_MODE_ATTRIBUTE "nsslapd-referralmode"
+#define CONFIG_ATTRIBUTE_NAME_EXCEPTION_ATTRIBUTE "nsslapd-attribute-name-exceptions"
+#define CONFIG_MAXBERSIZE_ATTRIBUTE "nsslapd-maxbersize"
+#define CONFIG_MAX_FILTER_NEST_LEVEL_ATTRIBUTE "nsslapd-max-filter-nest-level"
+#define CONFIG_VERSIONSTRING_ATTRIBUTE "nsslapd-versionstring"
+#define CONFIG_ENQUOTE_SUP_OC_ATTRIBUTE "nsslapd-enquote-sup-oc"
+#define CONFIG_BASEDN_ATTRIBUTE "nsslapd-certmap-basedn"
+#define CONFIG_ACCESSLOG_LIST_ATTRIBUTE "nsslapd-accesslog-list"
+#define CONFIG_ERRORLOG_LIST_ATTRIBUTE "nsslapd-errorlog-list"
+#define CONFIG_AUDITLOG_LIST_ATTRIBUTE "nsslapd-auditlog-list"
+#define CONFIG_REWRITE_RFC1274_ATTRIBUTE "nsslapd-rewrite-rfc1274"
+
+#define CONFIG_CONFIG_ATTRIBUTE "nsslapd-config"
+#define CONFIG_SSLCLIENTAUTH_ATTRIBUTE "nsslapd-SSLclientAuth"
+#define CONFIG_SSL_CHECK_HOSTNAME_ATTRIBUTE "nsslapd-ssl-check-hostname"
+#define CONFIG_HASH_FILTERS_ATTRIBUTE "nsslapd-hash-filters"
+#define CONFIG_OUTBOUND_LDAP_IO_TIMEOUT_ATTRIBUTE "nsslapd-outbound-ldap-io-timeout"
+
+/* flag used to indicate that the change to the config parameter should be saved */
+#define CONFIG_APPLY 1
+
+#define CFG_LOCK_READ(cfg) cfg->cfg_rwlock->rwl_acquire_read_lock( cfg->cfg_rwlock )
+#define CFG_UNLOCK_READ(cfg) cfg->cfg_rwlock->rwl_relinquish_read_lock( cfg->cfg_rwlock )
+#define CFG_LOCK_WRITE(cfg) cfg->cfg_rwlock->rwl_acquire_write_lock( cfg->cfg_rwlock )
+#define CFG_UNLOCK_WRITE(cfg) cfg->cfg_rwlock->rwl_relinquish_write_lock( cfg->cfg_rwlock )
+
+#define REFER_MODE_OFF 0
+#define REFER_MODE_ON 1
+
+#define MAX_ALLOWED_TIME_IN_SECS 2147483647
+
+typedef struct passwordpolicyarray {
+ int pw_change; /* 1 - indicates that users are allowed to change the pwd */
+ int pw_must_change; /* 1 - indicates that users must change pwd upon reset */
+ int pw_syntax;
+ int pw_minlength;
+ int pw_exp;
+ long pw_maxage;
+ long pw_minage;
+ long pw_warning;
+ int pw_history;
+ int pw_inhistory;
+ int pw_lockout;
+ int pw_maxfailure;
+ int pw_unlock;
+ long pw_lockduration;
+ long pw_resetfailurecount;
+ int pw_gracelimit;
+} passwdPolicy;
+
+typedef struct _slapdFrontendConfig {
+ rwl *cfg_rwlock; /* read/write lock to serialize access */
+ struct pw_scheme *rootpwstoragescheme;
+ int accesscontrol;
+ int groupevalnestlevel;
+ int idletimeout;
+ int ioblocktimeout;
+ int lastmod;
+#if !defined(_WIN32) && !defined(AIX)
+ int maxdescriptors;
+#endif /* !_WIN32 && !AIX */
+ int conntablesize;
+ int maxthreadsperconn;
+ int outbound_ldap_io_timeout;
+ int nagle;
+ int port;
+ int readonly;
+ int reservedescriptors;
+ int schemacheck;
+ int ds4_compatible_schema;
+ int schema_ignore_trailing_spaces;
+ int secureport;
+ int security;
+ int SSLclientAuth;
+ int ssl_check_hostname;
+ int sizelimit;
+ int SNMPenabled;
+ char *SNMPdescription;
+ char *SNMPorganization;
+ char *SNMPlocation;
+ char *SNMPcontact;
+ int threadnumber;
+ int timelimit;
+ char *accesslog;
+ struct berval **defaultreferral;
+ char *encryptionalias;
+ char *errorlog;
+ char *listenhost;
+ char *instancedir;
+#ifndef _WIN32
+ char *localuser;
+#endif /* _WIN32 */
+ char *localhost;
+ char *rootdn;
+ char *rootpw;
+ char *securelistenhost;
+ char *srvtab;
+ char *SSL3ciphers;
+ char *userat;
+ char *useroc;
+ char *versionstring;
+ char **backendconfig;
+ char **include;
+ char **plugin;
+ struct pw_scheme *pw_storagescheme;
+
+ int pwpolicy_local;
+ int pw_is_global_policy;
+ passwdPolicy pw_policy;
+
+ /* ACCESS LOG */
+ int accesslog_logging_enabled;
+ char *accesslog_mode;
+ int accesslog_maxnumlogs;
+ int accesslog_maxlogsize;
+ int accesslog_rotationsync_enabled;
+ int accesslog_rotationsynchour;
+ int accesslog_rotationsyncmin;
+ int accesslog_rotationtime;
+ char *accesslog_rotationunit;
+ int accesslog_maxdiskspace;
+ int accesslog_minfreespace;
+ int accesslog_exptime;
+ char *accesslog_exptimeunit;
+ int accessloglevel;
+ int accesslogbuffering;
+ int csnlogging;
+
+ /* ERROR LOG */
+ int errorlog_logging_enabled;
+ char *errorlog_mode;
+ int errorlog_maxnumlogs;
+ int errorlog_maxlogsize;
+ int errorlog_rotationsync_enabled;
+ int errorlog_rotationsynchour;
+ int errorlog_rotationsyncmin;
+ int errorlog_rotationtime;
+ char *errorlog_rotationunit;
+ int errorlog_maxdiskspace;
+ int errorlog_minfreespace;
+ int errorlog_exptime;
+ char *errorlog_exptimeunit;
+ int errorloglevel;
+
+ /* AUDIT LOG */
+ char *auditlog; /* replication audit file */
+ int auditloglevel;
+ int auditlog_logging_enabled;
+ char *auditlog_mode;
+ int auditlog_maxnumlogs;
+ int auditlog_maxlogsize;
+ int auditlog_rotationsync_enabled;
+ int auditlog_rotationsynchour;
+ int auditlog_rotationsyncmin;
+ int auditlog_rotationtime;
+ char *auditlog_rotationunit;
+ int auditlog_maxdiskspace;
+ int auditlog_minfreespace;
+ int auditlog_exptime;
+ char *auditlog_exptimeunit;
+
+ int return_exact_case; /* Return attribute names with the same case
+ * as they appear in at.conf */
+
+ int result_tweak;
+ char *refer_url; /* for referral mode */
+ int refer_mode; /* for quick test */
+ int slapd_type; /* Directory type; Full or Lite */
+
+ unsigned long maxbersize; /* Maximum BER element size we'll accept */
+ int max_filter_nest_level;/* deepest nested filter we will accept */
+ int enquote_sup_oc; /* put single quotes around an oc's
+ superior oc in cn=schema */
+
+ char *certmap_basedn; /* Default Base DN for certmap */
+
+ char *workingdir; /* full path of directory before detach */
+ char *configdir; /* full path name of directory containing configuration files */
+ int attrname_exceptions; /* if true, allow questionable attribute names */
+ int rewrite_rfc1274; /* return attrs for both v2 and v3 names */
+ char *schemareplace; /* see CONFIG_SCHEMAREPLACE_* #defines below */
+} slapdFrontendConfig_t;
+
+#define SLAPD_FULL 0
+#define SLAPD_LITE 1
+
+/* possible values for slapdFrontendConfig_t.schemareplace */
+#define CONFIG_SCHEMAREPLACE_STR_OFF "off"
+#define CONFIG_SCHEMAREPLACE_STR_ON "on"
+#define CONFIG_SCHEMAREPLACE_STR_REPLICATION_ONLY "replication-only"
+
+
+slapdFrontendConfig_t *getFrontendConfig();
+
+/* LP: NO_TIME cannot be -1, it generates wrong GeneralizedTime
+ * And causes some errors on AIX also
+ */
+/* #if defined( XP_WIN32 ) */
+#define NO_TIME (time_t)0 /* cannot be -1, NT's localtime( -1 ) returns NULL */
+/* #else */
+/* #define NO_TIME (time_t)-1 / * a value that time() does not return */
+/* #endif */
+#define NOT_FIRST_TIME (time_t)1 /* not the first logon */
+#define SLAPD_END_TIME (time_t)2147483647 /* (2^31)-1, in 2038 */
+
+extern char *attr_dataversion;
+#define ATTR_DATAVERSION "dataVersion"
+#define ATTR_WITH_DIRSTRING_SYNTAX "cn"
+
+#define SLAPD_SNMP_UPDATE_INTERVAL (10 * 1000) /* 10 seconds */
+
+#define LDAP_AUTH_KRBV41 0x81L
+#define LDAP_AUTH_KRBV42 0x82L
+
+/* for timing certain operations */
+#ifdef USE_TIMERS
+
+#ifndef _WIN32
+#include <sys/time.h>
+#ifdef LINUX
+#define GTOD(t) gettimeofday(t, NULL)
+#else
+#define GTOD(t) gettimeofday(t)
+#endif
+#define TIMER_DECL(x) struct timeval x##_start, x##_end
+#define TIMER_START(x) GTOD(&(x##_start))
+#define TIMER_STOP(x) GTOD(&(x##_end))
+#define TIMER_GET_US(x) (unsigned)(((x##_end).tv_sec - (x##_start).tv_sec) * 100000L + \
+ ((x##_end).tv_usec - (x##_start).tv_usec))
+#else
+#define TIMER_DECL(x) LARGE_INTEGER x##_freq, x##_start, x##_end
+#define TIMER_START(x) do { \
+ QueryPerformanceFrequency(&(x##_freq)); \
+ QueryPerformanceCounter(&(x##_start)); \
+} while(0)
+#define TIMER_STOP(x) QueryPerformanceCounter(&(x##_end))
+#define TIMER_GET_US(x) (unsigned int)((x##_end.QuadPart - x##_start.QuadPart) / x##_freq.QuadPart)
+#endif /* _WIN32 */
+
+#define TIMER_AVG_DECL(x) \
+ TIMER_DECL(x); static unsigned int x##_total, x##_count
+#define TIMER_AVG_START(x) \
+ TIMER_START(x)
+#define TIMER_AVG_STOP(x) do { \
+ TIMER_STOP(x); \
+ if (TIMER_GET_US(x) < 10000) { \
+ x##_count++; \
+ x##_total += TIMER_GET_US(x); \
+ } \
+} while (0)
+#define TIMER_AVG_GET_US(x) (unsigned int)(x##_total / x##_count)
+#define TIMER_AVG_CHECK(x) do { \
+ if (x##_count >= 1000) { \
+ printf("timer %s: %d\n", #x, TIMER_AVG_GET_US(x)); \
+ x##_total = x##_count = 0; \
+ } \
+} while (0)
+
+#else
+
+#define TIMER_DECL(x)
+#define TIMER_START(x)
+#define TIMER_STOP(x)
+#define TIMER_GET_US(x) 0L
+
+#endif /* USE_TIMERS */
+
+#define LDIF_CSNPREFIX_MAXLENGTH 6 /* sizeof(xxcsn-) */
+
+#include "intrinsics.h"
+
+/* task flag (pb_task_flags)*/
+#define TASK_RUNNING_AS_TASK 0x0
+#define TASK_RUNNING_FROM_COMMANDLINE 0x1
+
+/* printkey: import & export */
+#define EXPORT_PRINTKEY 0x1
+#define EXPORT_NOWRAP 0x2
+#define EXPORT_APPENDMODE 0x4
+#define EXPORT_MINIMAL_ENCODING 0x8
+#define EXPORT_ID2ENTRY_ONLY 0x10
+#define EXPORT_NOVERSION 0x20
+#define EXPORT_APPENDMODE_1 0x40
+#define EXPORT_INTERNAL 0x100
+
+#define MTN_CONTROL_USE_ONE_BACKEND_OID "2.16.840.1.113730.3.4.14"
+#define MTN_CONTROL_USE_ONE_BACKEND_EXT_OID "2.16.840.1.113730.3.4.20"
+
+/* virtualListViewError is a relatively new concept that was added long
+ * after we implemented VLV. Until added to LDAP SDK, we define
+ * virtualListViewError here. Once it's added, this define would go away. */
+#ifndef LDAP_VIRTUAL_LIST_VIEW_ERROR
+#define LDAP_VIRTUAL_LIST_VIEW_ERROR 0x4C /* 76 */
+#endif
+
+#endif /* _slap_h_ */
diff --git a/ldap/servers/slapd/slapd.lite.key b/ldap/servers/slapd/slapd.lite.key
new file mode 100644
index 00000000..0ff28a14
--- /dev/null
+++ b/ldap/servers/slapd/slapd.lite.key
@@ -0,0 +1,8 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+key:1877108
diff --git a/ldap/servers/slapd/slapd.normal.key b/ldap/servers/slapd/slapd.normal.key
new file mode 100644
index 00000000..0f1ce157
--- /dev/null
+++ b/ldap/servers/slapd/slapd.normal.key
@@ -0,0 +1,9 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+key:2003722
+
diff --git a/ldap/servers/slapd/slapd_plhash.c b/ldap/servers/slapd/slapd_plhash.c
new file mode 100644
index 00000000..0206440e
--- /dev/null
+++ b/ldap/servers/slapd/slapd_plhash.c
@@ -0,0 +1,59 @@
+/** 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 a function which augments the standard nspr PL_HashTable
+ api. The problem is that the hash table lookup function in the standard NSPR
+ actually modifies the hash table being searched, which means that it cannot be
+ used with read locks in a multi threaded environment. This function is a
+ lookup function which is guaranteed not to modify the hash table passed in,
+ so that it can be used with read locks.
+*/
+
+#include "plhash.h"
+
+/*
+** Multiplicative hash, from Knuth 6.4.
+*/
+#define GOLDEN_RATIO 0x9E3779B9U
+
+PR_IMPLEMENT(PLHashEntry **)
+PL_HashTableRawLookup_const(PLHashTable *ht, PLHashNumber keyHash, const void *key)
+{
+ PLHashEntry *he, **hep;
+ PLHashNumber h;
+
+#ifdef HASHMETER
+ ht->nlookups++;
+#endif
+ h = keyHash * GOLDEN_RATIO;
+ h >>= ht->shift;
+ hep = &ht->buckets[h];
+ while ((he = *hep) != 0) {
+ if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) {
+ return hep;
+ }
+ hep = &he->next;
+#ifdef HASHMETER
+ ht->nsteps++;
+#endif
+ }
+ return hep;
+}
+
+PR_IMPLEMENT(void *)
+PL_HashTableLookup_const(PLHashTable *ht, const void *key)
+{
+ PLHashNumber keyHash;
+ PLHashEntry *he, **hep;
+
+ keyHash = (*ht->keyHash)(key);
+ hep = PL_HashTableRawLookup_const(ht, keyHash, key);
+ if ((he = *hep) != 0) {
+ return he->value;
+ }
+ return 0;
+}
diff --git a/ldap/servers/slapd/slapi-plugin-compat4.h b/ldap/servers/slapd/slapi-plugin-compat4.h
new file mode 100644
index 00000000..198a72c0
--- /dev/null
+++ b/ldap/servers/slapd/slapi-plugin-compat4.h
@@ -0,0 +1,132 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Netscape Directory Server 4.x plugin API backwards compatible header file.
+ */
+#ifndef _SLAPIPLUGINCOMPAT4
+#define _SLAPIPLUGINCOMPAT4
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+/******* Deprecated (obsolete) macros ****************************************/
+/*
+ * The SLAPI_BIND_FAIL_OR_ANONYMOUS bind function return code is deprecated.
+ * Use SLAPI_BIND_FAIL or SLAPI_BIND_ANONYMOUS instead.
+ */
+#define SLAPI_BIND_FAIL_OR_ANONYMOUS 1 /* back end should send result */
+
+
+/******* Deprecated (obsolete) pblock arg identifiers ************************/
+#define SLAPI_CONFIG_FILENAME 40 /* use config. entries instead */
+#define SLAPI_CONFIG_LINENO 41 /* use config. entries instead */
+#define SLAPI_CONFIG_ARGC 42 /* use config. entries instead */
+#define SLAPI_CONFIG_ARGV 43 /* use config. entries instead */
+#define SLAPI_CONN_AUTHTYPE 144 /* use SLAPI_CONN_AUTHTYPE */
+#define SLAPI_REQUESTOR_ISUPDATEDN SLAPI_IS_REPLICATED_OPERATION
+#define SLAPI_CONN_CLIENTIP 145 /* use SLAPI_CONN_CLIENTNETADDR */
+#define SLAPI_CONN_SERVERIP 146 /* use SLAPI_CONN_SERVERNETADDR */
+
+/******* Deprecated (obsolete) functions *************************************/
+/*
+ * Please use the new functions in slapi-plugin.h instead of the ones
+ * below that are marked SLAPI_DEPRECATED.
+ */
+#define SLAPI_DEPRECATED
+
+
+/*
+ *
+ * The following functions that deal with bervals are deprecated
+ * and their use is not recommended. For each deprecated function, you
+ * will find in slapi-plugin.h a corresponding function with a _sv
+ * extension that uses Slapi_Values instead of bervals. The new
+ * functions are more efficient than the old ones, and some of the old
+ * functions are much less efficient than they were previously.
+ */
+SLAPI_DEPRECATED int slapi_entry_attr_merge( Slapi_Entry *e, const char *type,
+ struct berval **vals );
+SLAPI_DEPRECATED int slapi_entry_add_values( Slapi_Entry *e, const char *type,
+ struct berval **vals );
+SLAPI_DEPRECATED int slapi_entry_delete_values( Slapi_Entry *e,
+ const char *type, struct berval **vals );
+SLAPI_DEPRECATED int slapi_entry_attr_replace( Slapi_Entry *e,
+ const char *type, struct berval **vals );
+SLAPI_DEPRECATED int slapi_attr_get_values( Slapi_Attr *attr,
+ struct berval ***vals );
+SLAPI_DEPRECATED int slapi_attr_get_oid( const Slapi_Attr *attr, char **oid );
+SLAPI_DEPRECATED int slapi_filter_get_type( Slapi_Filter *f, char **type );
+SLAPI_DEPRECATED int slapi_pw_find( struct berval **vals, struct berval *v );
+SLAPI_DEPRECATED int slapi_call_syntax_values2keys( void *vpi,
+ struct berval **vals, struct berval ***ivals, int ftype );
+SLAPI_DEPRECATED int slapi_call_syntax_assertion2keys_ava( void *vpi,
+ struct berval *val, struct berval ***ivals, int ftype );
+SLAPI_DEPRECATED int slapi_call_syntax_assertion2keys_sub( void *vpi,
+ char *initial, char **any, char *final, struct berval ***ivals );
+
+/*
+ * slapi_entry_attr_hasvalue() has been deprecated in favor of
+ * slapi_entry_attr_has_syntax_value() which respects the syntax of the
+ * attribute type (slapi_entry_attr_hasvalue() assumes the value is a
+ * caseIgnore ASCII string).
+ */
+SLAPI_DEPRECATED int slapi_entry_attr_hasvalue(const Slapi_Entry *e,
+ const char *type, const char *value);
+
+/*
+ * The following "internal operation" calls are deprecated. The new internal
+ * operation functions that are defined in slapi-plugin.h take a Slapi_PBlock
+ * for extensibility and support the new plugin configuration capabilities
+ * as well.
+ */
+SLAPI_DEPRECATED int slapi_search_internal_callback( const char *ibase,
+ int scope, const char *ifstr, char **attrs, int attrsonly,
+ void *callback_data, LDAPControl **controls,
+ plugin_result_callback prc, plugin_search_entry_callback psec,
+ plugin_referral_entry_callback prec );
+SLAPI_DEPRECATED int slapi_seq_callback( const char *ibase, int type,
+ char *attrname, char *val, char **attrs, int attrsonly,
+ void *callback_data, LDAPControl **controls,
+ plugin_result_callback res_callback,
+ plugin_search_entry_callback srch_callback,
+ plugin_referral_entry_callback ref_callback);
+SLAPI_DEPRECATED Slapi_PBlock *slapi_search_internal( const char *base,
+ int scope, const char *filter, LDAPControl **controls, char **attrs,
+ int attrsonly );
+SLAPI_DEPRECATED Slapi_PBlock *slapi_modify_internal( const char *dn,
+ LDAPMod **mods, LDAPControl **controls, int dummy );
+SLAPI_DEPRECATED Slapi_PBlock *slapi_add_internal( const char * dn,
+ LDAPMod **attrs, LDAPControl **controls, int dummy );
+SLAPI_DEPRECATED Slapi_PBlock *slapi_add_entry_internal( Slapi_Entry *e,
+ LDAPControl **controls, int dummy );
+SLAPI_DEPRECATED Slapi_PBlock *slapi_delete_internal( const char * dn,
+ LDAPControl **controls, int dummy );
+SLAPI_DEPRECATED Slapi_PBlock *slapi_modrdn_internal( const char * olddn,
+ const char * newrdn, int deloldrdn, LDAPControl **controls, int dummy);
+SLAPI_DEPRECATED Slapi_PBlock *slapi_rename_internal( const char *iodn,
+ const char *inewrdn, const char *inewsuperior, int deloldrdn,
+ LDAPControl **controls, int dummy);
+
+/*
+ * These following three functions are not multi-thread (MT) safe (they return
+ * a pointer to unprotected data). Use the new functions from slapi-plugin.h
+ * that end in _copy() instead, e.g., use slapi_get_supported_controls_copy()
+ * instead of slapi_get_supported_controls().
+ */
+SLAPI_DEPRECATED int slapi_get_supported_controls( char ***ctrloidsp,
+ unsigned long **ctrlopsp );
+SLAPI_DEPRECATED char **slapi_get_supported_extended_ops( void );
+SLAPI_DEPRECATED char **slapi_get_supported_saslmechanisms( void );
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SLAPIPLUGINCOMPAT4 */
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
new file mode 100644
index 00000000..52c437aa
--- /dev/null
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -0,0 +1,1652 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* slapi-plugin.h - public Directory Server plugin interface */
+
+#ifndef _SLAPIPLUGIN
+#define _SLAPIPLUGIN
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ldap.h"
+
+/*
+ * The slapi_attr_get_flags() routine returns a bitmap that contains one or
+ * more of these values.
+ *
+ * Note that the flag values 0x0010, 0x0020, 0x4000, and 0x8000 are reserved.
+ */
+#define SLAPI_ATTR_FLAG_SINGLE 0x0001 /* single-valued attribute */
+#define SLAPI_ATTR_FLAG_OPATTR 0x0002 /* operational attribute */
+#define SLAPI_ATTR_FLAG_READONLY 0x0004 /* read from shipped config file */
+#define SLAPI_ATTR_FLAG_STD_ATTR SLAPI_ATTR_FLAG_READONLY /* alias for read only */
+#define SLAPI_ATTR_FLAG_OBSOLETE 0x0040 /* an outdated definition */
+#define SLAPI_ATTR_FLAG_COLLECTIVE 0x0080 /* collective (not supported) */
+#define SLAPI_ATTR_FLAG_NOUSERMOD 0x0100 /* can't be modified over LDAP */
+
+/* operation flags */
+#define SLAPI_OP_FLAG_NEVER_CHAIN 0x00800 /* Do not chain the operation */
+#define SLAPI_OP_FLAG_NO_ACCESS_CHECK 0x10000 /* Do not check for access control - bypass them */
+
+/*
+ * access control levels
+ */
+#define SLAPI_ACL_COMPARE 0x01
+#define SLAPI_ACL_SEARCH 0x02
+#define SLAPI_ACL_READ 0x04
+#define SLAPI_ACL_WRITE 0x08
+#define SLAPI_ACL_DELETE 0x10
+#define SLAPI_ACL_ADD 0x20
+#define SLAPI_ACL_SELF 0x40
+#define SLAPI_ACL_PROXY 0x80
+#define SLAPI_ACL_ALL 0x7f
+
+
+/*
+ * filter types
+ */
+#define LDAP_FILTER_AND 0xa0L
+#define LDAP_FILTER_OR 0xa1L
+#define LDAP_FILTER_NOT 0xa2L
+#define LDAP_FILTER_EQUALITY 0xa3L
+#define LDAP_FILTER_SUBSTRINGS 0xa4L
+#define LDAP_FILTER_GE 0xa5L
+#define LDAP_FILTER_LE 0xa6L
+#define LDAP_FILTER_PRESENT 0x87L
+#define LDAP_FILTER_APPROX 0xa8L
+#define LDAP_FILTER_EXTENDED 0xa9L
+
+
+/*
+ * Sequential access types
+ */
+#define SLAPI_SEQ_FIRST 1
+#define SLAPI_SEQ_LAST 2
+#define SLAPI_SEQ_PREV 3
+#define SLAPI_SEQ_NEXT 4
+
+
+/*
+ * return codes from a backend API call
+ */
+#define SLAPI_FAIL_GENERAL -1
+#define SLAPI_FAIL_DISKFULL -2
+
+
+/*
+ * return codes used by BIND functions
+ */
+#define SLAPI_BIND_SUCCESS 0 /* front end will send result */
+#define SLAPI_BIND_FAIL 2 /* back end should send result */
+#define SLAPI_BIND_ANONYMOUS 3 /* front end will send result */
+
+
+/* commonly used attributes names */
+#define SLAPI_ATTR_UNIQUEID "nsuniqueid"
+#define SLAPI_ATTR_OBJECTCLASS "objectclass"
+#define SLAPI_ATTR_VALUE_TOMBSTONE "nsTombstone"
+#define SLAPI_ATTR_VALUE_PARENT_UNIQUEID "nsParentUniqueID"
+#define SLAPI_ATTR_NSCP_ENTRYDN "nscpEntryDN"
+
+
+/* opaque structures */
+typedef struct slapi_pblock Slapi_PBlock;
+typedef struct slapi_entry Slapi_Entry;
+typedef struct slapi_attr Slapi_Attr;
+typedef struct slapi_value Slapi_Value;
+typedef struct slapi_value_set Slapi_ValueSet;
+typedef struct slapi_filter Slapi_Filter;
+typedef struct slapi_matchingRuleEntry Slapi_MatchingRuleEntry;
+typedef struct backend Slapi_Backend;
+typedef struct _guid_t Slapi_UniqueID;
+typedef struct op Slapi_Operation;
+typedef struct conn Slapi_Connection;
+typedef struct slapi_dn Slapi_DN;
+typedef struct slapi_rdn Slapi_RDN;
+typedef struct slapi_mod Slapi_Mod;
+typedef struct slapi_mods Slapi_Mods;
+typedef struct slapi_componentid Slapi_ComponentId;
+
+
+/*
+ * The default thread stacksize for nspr21 is 64k (except on IRIX! It's 32k!).
+ * For OSF, we require a larger stacksize as actual storage allocation is
+ * higher i.e pointers are allocated 8 bytes but lower 4 bytes are used.
+ * The value 0 means use the default stacksize.
+ *
+ * larger stacksize (256KB) is needed on IRIX due to its 4KB BUFSIZ.
+ * (@ pthread IRIX porting -- 01/11/99)
+ *
+ * Don't know why HP was defined as follows up until DS6.1x. HP BUFSIZ is 1KB
+ #elif ( defined( hpux ))
+ #define SLAPD_DEFAULT_THREAD_STACKSIZE 262144L
+ */
+#if ( defined( irix ))
+#define SLAPD_DEFAULT_THREAD_STACKSIZE 262144L
+#elif ( defined ( OSF1 ))
+#define SLAPD_DEFAULT_THREAD_STACKSIZE 262144L
+#elif ( defined ( AIX ))
+#define SLAPD_DEFAULT_THREAD_STACKSIZE 262144L
+/* All 64-bit builds get a bigger stack size */
+#elif ( defined ( __LP64__ )) || defined (_LP64)
+#define SLAPD_DEFAULT_THREAD_STACKSIZE 262144L
+#else
+#define SLAPD_DEFAULT_THREAD_STACKSIZE 0
+#endif
+
+/*
+ * parameter block routines
+ */
+Slapi_PBlock *slapi_pblock_new( void ); /* allocate and initialize */
+int slapi_pblock_get( Slapi_PBlock *pb, int arg, void *value );
+int slapi_pblock_set( Slapi_PBlock *pb, int arg, void *value );
+void slapi_pblock_destroy( Slapi_PBlock *pb );
+
+
+/*
+ * entry routines
+ */
+Slapi_Entry *slapi_str2entry( char *s, int flags );
+/* Flags for slapi_str2entry() */
+/* Remove duplicate values */
+#define SLAPI_STR2ENTRY_REMOVEDUPVALS 1
+/* Add any missing values from RDN */
+#define SLAPI_STR2ENTRY_ADDRDNVALS 2
+/* Provide a hint that the entry is large; this enables some optimizations
+ related to large entries. */
+#define SLAPI_STR2ENTRY_BIGENTRY 4
+/* Check to see if the entry is a tombstone; if so, set the tombstone flag
+ (SLAPI_ENTRY_FLAG_TOMBSTONE) */
+#define SLAPI_STR2ENTRY_TOMBSTONE_CHECK 8
+/* Ignore entry state information if present */
+#define SLAPI_STR2ENTRY_IGNORE_STATE 16
+/* Return entries that have a "version: 1" line as part of the LDIF
+ representation */
+#define SLAPI_STR2ENTRY_INCLUDE_VERSION_STR 32
+/* Add any missing ancestor values based on the object class hierarchy */
+#define SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES 64
+/* Inform slapi_str2entry() that the LDIF input is not well formed.
+ Well formed LDIF has no duplicate attribute values, already
+ has the RDN as an attribute of the entry, and has all values for a
+ given attribute type listed contiguously. */
+#define SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF 128
+
+char *slapi_entry2str_with_options( Slapi_Entry *e, int *len, int options );
+/* Options for slapi_entry2str_with_options() */
+#define SLAPI_DUMP_STATEINFO 1 /* replication state */
+#define SLAPI_DUMP_UNIQUEID 2 /* unique ID */
+#define SLAPI_DUMP_NOOPATTRS 4 /* suppress operational attrs */
+#define SLAPI_DUMP_NOWRAP 8 /* no line breaks */
+#define SLAPI_DUMP_MINIMAL_ENCODING 16 /* use less base64 encoding */
+
+char *slapi_entry2str( Slapi_Entry *e, int *len );
+Slapi_Entry *slapi_entry_alloc(void);
+void slapi_entry_init(Slapi_Entry *e, char *dn, Slapi_Attr *a);
+void slapi_entry_free( Slapi_Entry *e );
+Slapi_Entry *slapi_entry_dup( const Slapi_Entry *e );
+char *slapi_entry_get_dn( Slapi_Entry *e );
+char *slapi_entry_get_ndn( Slapi_Entry *e );
+const Slapi_DN *slapi_entry_get_sdn_const( const Slapi_Entry *e );
+Slapi_DN *slapi_entry_get_sdn( Slapi_Entry *e );
+const char *slapi_entry_get_dn_const( const Slapi_Entry *e );
+void slapi_entry_set_dn( Slapi_Entry *e, char *dn );
+void slapi_entry_set_sdn( Slapi_Entry *e, const Slapi_DN *sdn );
+int slapi_entry_attr_find( const Slapi_Entry *e, const char *type, Slapi_Attr **attr );
+int slapi_entry_first_attr( const Slapi_Entry *e, Slapi_Attr **attr );
+int slapi_entry_next_attr( const Slapi_Entry *e, Slapi_Attr *prevattr, Slapi_Attr **attr );
+const char *slapi_entry_get_uniqueid( const Slapi_Entry *e );
+void slapi_entry_set_uniqueid( Slapi_Entry *e, char *uniqueid );
+int slapi_entry_schema_check( Slapi_PBlock *pb, Slapi_Entry *e );
+int slapi_entry_rdn_values_present( const Slapi_Entry *e );
+int slapi_entry_add_rdn_values( Slapi_Entry *e );
+int slapi_entry_attr_delete( Slapi_Entry *e, const char *type );
+ char **slapi_entry_attr_get_charray(const Slapi_Entry* e, const char *type);
+char *slapi_entry_attr_get_charptr(const Slapi_Entry* e, const char *type);
+int slapi_entry_attr_get_int(const Slapi_Entry* e, const char *type);
+unsigned int slapi_entry_attr_get_uint(const Slapi_Entry* e, const char *type);
+long slapi_entry_attr_get_long( const Slapi_Entry* e, const char *type);
+unsigned long slapi_entry_attr_get_ulong( const Slapi_Entry* e, const char *type);
+void slapi_entry_attr_set_charptr(Slapi_Entry* e, const char *type, const char *value);
+void slapi_entry_attr_set_int( Slapi_Entry* e, const char *type, int l);
+void slapi_entry_attr_set_uint( Slapi_Entry* e, const char *type, unsigned int l);
+void slapi_entry_attr_set_long(Slapi_Entry* e, const char *type, long l);
+void slapi_entry_attr_set_ulong(Slapi_Entry* e, const char *type, unsigned long l);
+int slapi_entry_attr_has_syntax_value(const Slapi_Entry *e, const char *type, const Slapi_Value *value);
+int slapi_entry_has_children(const Slapi_Entry *e);
+int slapi_is_rootdse( const char *dn );
+size_t slapi_entry_size(Slapi_Entry *e);
+int slapi_entry_attr_merge_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals );
+int slapi_entry_add_values_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals );
+int slapi_entry_add_valueset(Slapi_Entry *e, const char *type, Slapi_ValueSet *vs);
+int slapi_entry_delete_values_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals );
+int slapi_entry_merge_values_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals );
+int slapi_entry_attr_replace_sv( Slapi_Entry *e, const char *type, Slapi_Value **vals );
+int slapi_entry_add_value(Slapi_Entry *e, const char *type, const Slapi_Value *value);
+int slapi_entry_add_string(Slapi_Entry *e, const char *type, const char *value);
+int slapi_entry_delete_string(Slapi_Entry *e, const char *type, const char *value);
+void slapi_entry_diff(Slapi_Mods *smods, Slapi_Entry *e1, Slapi_Entry *e2, int diff_ctrl);
+
+
+/*
+ * Entry flags.
+ */
+#define SLAPI_ENTRY_FLAG_TOMBSTONE 1
+int slapi_entry_flag_is_set( const Slapi_Entry *e, unsigned char flag );
+void slapi_entry_set_flag( Slapi_Entry *e, unsigned char flag);
+void slapi_entry_clear_flag( Slapi_Entry *e, unsigned char flag);
+
+/* exported vattrcache routines */
+
+int slapi_entry_vattrcache_watermark_isvalid(const Slapi_Entry *e);
+void slapi_entry_vattrcache_watermark_set(Slapi_Entry *e);
+void slapi_entry_vattrcache_watermark_invalidate(Slapi_Entry *e);
+void slapi_entrycache_vattrcache_watermark_invalidate();
+
+
+
+
+/*
+ * Slapi_DN routines
+ */
+Slapi_DN *slapi_sdn_new( void );
+Slapi_DN *slapi_sdn_new_dn_byval(const char *dn);
+Slapi_DN *slapi_sdn_new_ndn_byval(const char *ndn);
+Slapi_DN *slapi_sdn_new_dn_byref(const char *dn);
+Slapi_DN *slapi_sdn_new_ndn_byref(const char *ndn);
+Slapi_DN *slapi_sdn_new_dn_passin(const char *dn);
+Slapi_DN *slapi_sdn_set_dn_byval(Slapi_DN *sdn, const char *dn);
+Slapi_DN *slapi_sdn_set_dn_byref(Slapi_DN *sdn, const char *dn);
+Slapi_DN *slapi_sdn_set_dn_passin(Slapi_DN *sdn, const char *dn);
+Slapi_DN *slapi_sdn_set_ndn_byval(Slapi_DN *sdn, const char *ndn);
+Slapi_DN *slapi_sdn_set_ndn_byref(Slapi_DN *sdn, const char *ndn);
+void slapi_sdn_done(Slapi_DN *sdn);
+void slapi_sdn_free(Slapi_DN **sdn);
+const char * slapi_sdn_get_dn(const Slapi_DN *sdn);
+const char * slapi_sdn_get_ndn(const Slapi_DN *sdn);
+void slapi_sdn_get_parent(const Slapi_DN *sdn,Slapi_DN *sdn_parent);
+void slapi_sdn_get_backend_parent(const Slapi_DN *sdn,Slapi_DN *sdn_parent,const Slapi_Backend *backend);
+Slapi_DN * slapi_sdn_dup(const Slapi_DN *sdn);
+void slapi_sdn_copy(const Slapi_DN *from, Slapi_DN *to);
+int slapi_sdn_compare( const Slapi_DN *sdn1, const Slapi_DN *sdn2 );
+int slapi_sdn_isempty( const Slapi_DN *sdn);
+int slapi_sdn_issuffix(const Slapi_DN *sdn, const Slapi_DN *suffixsdn);
+int slapi_sdn_isparent( const Slapi_DN *parent, const Slapi_DN *child );
+int slapi_sdn_isgrandparent( const Slapi_DN *parent, const Slapi_DN *child );
+int slapi_sdn_get_ndn_len(const Slapi_DN *sdn);
+int slapi_sdn_scope_test( const Slapi_DN *dn, const Slapi_DN *base, int scope );
+void slapi_sdn_get_rdn(const Slapi_DN *sdn,Slapi_RDN *rdn);
+Slapi_DN *slapi_sdn_set_rdn(Slapi_DN *sdn, const Slapi_RDN *rdn);
+Slapi_DN *slapi_sdn_set_parent(Slapi_DN *sdn, const Slapi_DN *parentdn);
+int slapi_sdn_is_rdn_component(const Slapi_DN *rdn, const Slapi_Attr *a, const Slapi_Value *v);
+char * slapi_moddn_get_newdn(Slapi_DN *dn_olddn, char *newrdn, char *newsuperiordn);
+
+
+/*
+ * Slapi_RDN functions
+ */
+Slapi_RDN *slapi_rdn_new( void );
+Slapi_RDN *slapi_rdn_new_dn(const char *dn);
+Slapi_RDN *slapi_rdn_new_sdn(const Slapi_DN *sdn);
+Slapi_RDN *slapi_rdn_new_rdn(const Slapi_RDN *fromrdn);
+void slapi_rdn_init(Slapi_RDN *rdn);
+void slapi_rdn_init_dn(Slapi_RDN *rdn,const char *dn);
+void slapi_rdn_init_sdn(Slapi_RDN *rdn,const Slapi_DN *sdn);
+void slapi_rdn_init_rdn(Slapi_RDN *rdn,const Slapi_RDN *fromrdn);
+void slapi_rdn_set_dn(Slapi_RDN *rdn,const char *dn);
+void slapi_rdn_set_sdn(Slapi_RDN *rdn,const Slapi_DN *sdn);
+void slapi_rdn_set_rdn(Slapi_RDN *rdn,const Slapi_RDN *fromrdn);
+void slapi_rdn_free(Slapi_RDN **rdn);
+void slapi_rdn_done(Slapi_RDN *rdn);
+int slapi_rdn_get_first(Slapi_RDN *rdn, char **type, char **value);
+int slapi_rdn_get_next(Slapi_RDN *rdn, int index, char **type, char **value);
+int slapi_rdn_get_index(Slapi_RDN *rdn, const char *type, const char *value,size_t length);
+int slapi_rdn_get_index_attr(Slapi_RDN *rdn, const char *type, char **value);
+int slapi_rdn_contains(Slapi_RDN *rdn, const char *type, const char *value,size_t length);
+int slapi_rdn_contains_attr(Slapi_RDN *rdn, const char *type, char **value);
+int slapi_rdn_add(Slapi_RDN *rdn, const char *type, const char *value);
+int slapi_rdn_remove_index(Slapi_RDN *rdn, int atindex);
+int slapi_rdn_remove(Slapi_RDN *rdn, const char *type, const char *value, size_t length);
+int slapi_rdn_remove_attr(Slapi_RDN *rdn, const char *type);
+int slapi_rdn_isempty(const Slapi_RDN *rdn);
+int slapi_rdn_get_num_components(Slapi_RDN *rdn);
+int slapi_rdn_compare(Slapi_RDN *rdn1, Slapi_RDN *rdn2);
+const char *slapi_rdn_get_rdn(const Slapi_RDN *rdn);
+const char *slapi_rdn_get_nrdn(const Slapi_RDN *rdn);
+Slapi_DN *slapi_sdn_add_rdn(Slapi_DN *sdn, const Slapi_RDN *rdn);
+
+
+/*
+ * utility routines for dealing with DNs
+ */
+char *slapi_dn_normalize( char *dn );
+char *slapi_dn_normalize_to_end( char *dn, char *end );
+char *slapi_dn_ignore_case( char *dn );
+char *slapi_dn_normalize_case( char *dn );
+char *slapi_dn_beparent( Slapi_PBlock *pb, const char *dn );
+char *slapi_dn_parent( const char *dn );
+int slapi_dn_issuffix( const char *dn, const char *suffix );
+int slapi_dn_isparent( const char *parentdn, const char *childdn );
+int slapi_dn_isroot( const char *dn );
+int slapi_dn_isbesuffix( Slapi_PBlock *pb, const char *dn );
+int slapi_rdn2typeval( char *rdn, char **type, struct berval *bv );
+char *slapi_dn_plus_rdn(const char *dn, const char *rdn);
+
+
+/*
+ * thread safe random functions
+ */
+int slapi_rand_r(unsigned int * seed);
+void slapi_rand_array(void *randx, size_t len);
+int slapi_rand();
+
+
+/*
+ * attribute routines
+ */
+Slapi_Attr *slapi_attr_new( void );
+Slapi_Attr *slapi_attr_init(Slapi_Attr *a, const char *type);
+void slapi_attr_free( Slapi_Attr **a );
+Slapi_Attr *slapi_attr_dup(const Slapi_Attr *attr);
+int slapi_attr_add_value(Slapi_Attr *a, const Slapi_Value *v);
+int slapi_attr_type2plugin( const char *type, void **pi );
+int slapi_attr_get_type( Slapi_Attr *attr, char **type );
+int slapi_attr_get_oid_copy( const Slapi_Attr *attr, char **oidp );
+int slapi_attr_get_flags( const Slapi_Attr *attr, unsigned long *flags );
+int slapi_attr_flag_is_set( const Slapi_Attr *attr, unsigned long flag );
+int slapi_attr_value_cmp( const Slapi_Attr *attr, const struct berval *v1, const struct berval *v2 );
+int slapi_attr_value_find( const Slapi_Attr *a, const struct berval *v );
+
+int slapi_attr_type_cmp( const char *t1, const char *t2, int opt );
+/* Mode of operation (opt) values for slapi_attr_type_cmp() */
+#define SLAPI_TYPE_CMP_EXACT 0
+#define SLAPI_TYPE_CMP_BASE 1
+#define SLAPI_TYPE_CMP_SUBTYPE 2
+
+int slapi_attr_types_equivalent(const char *t1, const char *t2);
+char *slapi_attr_basetype( const char *type, char *buf, size_t bufsiz );
+int slapi_attr_first_value( Slapi_Attr *a, Slapi_Value **v );
+int slapi_attr_next_value( Slapi_Attr *a, int hint, Slapi_Value **v );
+int slapi_attr_get_numvalues( const Slapi_Attr *a, int *numValues);
+int slapi_attr_get_valueset(const Slapi_Attr *a, Slapi_ValueSet **vs);
+/* Make the valuset in Slapi_Attr be *vs--not a copy */
+int slapi_attr_set_valueset(Slapi_Attr *a, const Slapi_ValueSet *vs);
+int slapi_attr_get_bervals_copy( Slapi_Attr *a, struct berval ***vals );
+char * slapi_attr_syntax_normalize( const char *s );
+void slapi_valueset_set_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2);
+void slapi_valueset_set_from_smod(Slapi_ValueSet *vs, Slapi_Mod *smod);
+
+
+/*
+ * value routines
+ */
+Slapi_Value *slapi_value_new( void );
+Slapi_Value *slapi_value_new_berval(const struct berval *bval);
+Slapi_Value *slapi_value_new_value(const Slapi_Value *v);
+Slapi_Value *slapi_value_new_string(const char *s);
+Slapi_Value *slapi_value_new_string_passin(char *s);
+Slapi_Value *slapi_value_init(Slapi_Value *v);
+Slapi_Value *slapi_value_init_berval(Slapi_Value *v, struct berval *bval);
+Slapi_Value *slapi_value_init_string(Slapi_Value *v,const char *s);
+Slapi_Value *slapi_value_init_string_passin(Slapi_Value *v, char *s);
+Slapi_Value *slapi_value_dup(const Slapi_Value *v);
+void slapi_value_free(Slapi_Value **value);
+const struct berval *slapi_value_get_berval( const Slapi_Value *value );
+Slapi_Value *slapi_value_set_berval( Slapi_Value *value, const struct berval *bval );
+Slapi_Value *slapi_value_set_value( Slapi_Value *value, const Slapi_Value *vfrom);
+Slapi_Value *slapi_value_set( Slapi_Value *value, void *val, unsigned long len);
+int slapi_value_set_string(Slapi_Value *value, const char *strVal);
+int slapi_value_set_string_passin(Slapi_Value *value, char *strVal);
+int slapi_value_set_int(Slapi_Value *value, int intVal);
+const char*slapi_value_get_string(const Slapi_Value *value);
+int slapi_value_get_int(const Slapi_Value *value);
+unsigned int slapi_value_get_uint(const Slapi_Value *value);
+long slapi_value_get_long(const Slapi_Value *value);
+unsigned long slapi_value_get_ulong(const Slapi_Value *value);
+size_t slapi_value_get_length(const Slapi_Value *value);
+int slapi_value_compare(const Slapi_Attr *a,const Slapi_Value *v1,const Slapi_Value *v2);
+
+
+/*
+ * Valueset functions.
+ */
+#define SLAPI_VALUE_FLAG_PASSIN 0x1
+#define SLAPI_VALUE_FLAG_IGNOREERROR 0x2
+#define SLAPI_VALUE_FLAG_PRESERVECSNSET 0x4
+Slapi_ValueSet *slapi_valueset_new( void );
+void slapi_valueset_free(Slapi_ValueSet *vs);
+void slapi_valueset_init(Slapi_ValueSet *vs);
+void slapi_valueset_done(Slapi_ValueSet *vs);
+void slapi_valueset_add_value(Slapi_ValueSet *vs, const Slapi_Value *addval);
+void slapi_valueset_add_value_ext(Slapi_ValueSet *vs, Slapi_Value *addval, unsigned long flags);
+int slapi_valueset_first_value( Slapi_ValueSet *vs, Slapi_Value **v );
+int slapi_valueset_next_value( Slapi_ValueSet *vs, int index, Slapi_Value **v);
+int slapi_valueset_count( const Slapi_ValueSet *vs);
+void slapi_valueset_set_from_smod(Slapi_ValueSet *vs, Slapi_Mod *smod);
+void slapi_valueset_set_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2);
+Slapi_Value *slapi_valueset_find(const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_Value *v);
+
+
+/*
+ * operation routines
+ */
+int slapi_op_abandoned( Slapi_PBlock *pb );
+unsigned long slapi_op_get_type(Slapi_Operation * op);
+void slapi_operation_set_flag(Slapi_Operation *op, unsigned long flag);
+void slapi_operation_clear_flag(Slapi_Operation *op, unsigned long flag);
+int slapi_operation_is_flag_set(Slapi_Operation *op, unsigned long flag);
+int slapi_op_reserved(Slapi_PBlock *pb);
+void slapi_operation_set_csngen_handler ( Slapi_Operation *op, void *callback );
+void slapi_operation_set_replica_attr_handler ( Slapi_Operation *op, void *callback );
+int slapi_operation_get_replica_attr ( Slapi_PBlock *pb, Slapi_Operation *op, const char *type, void *value );
+
+
+/*
+ * LDAPMod manipulation routines
+ */
+Slapi_Mods* slapi_mods_new( void );
+void slapi_mods_init(Slapi_Mods *smods, int initCount);
+void slapi_mods_init_byref(Slapi_Mods *smods, LDAPMod **mods);
+void slapi_mods_init_passin(Slapi_Mods *smods, LDAPMod **mods);
+void slapi_mods_free(Slapi_Mods **smods);
+void slapi_mods_done(Slapi_Mods *smods);
+void slapi_mods_insert_at(Slapi_Mods *smods, LDAPMod *mod, int pos);
+void slapi_mods_insert_smod_at(Slapi_Mods *smods, Slapi_Mod *smod, int pos);
+void slapi_mods_insert_before(Slapi_Mods *smods, LDAPMod *mod);
+void slapi_mods_insert_smod_before(Slapi_Mods *smods, Slapi_Mod *smod);
+void slapi_mods_insert_after(Slapi_Mods *smods, LDAPMod *mod);
+void slapi_mods_insert_after(Slapi_Mods *smods, LDAPMod *mod);
+void slapi_mods_add( Slapi_Mods *smods, int modtype, const char *type, unsigned long len, const char *val);
+void slapi_mods_add_ldapmod(Slapi_Mods *smods, LDAPMod *mod);
+void slapi_mods_add_modbvps( Slapi_Mods *smods, int modtype, const char *type, struct berval **bvps );
+void slapi_mods_add_mod_values( Slapi_Mods *smods, int modtype, const char *type, Slapi_Value **va );
+void slapi_mods_add_smod(Slapi_Mods *smods, Slapi_Mod *smod);
+void slapi_mods_add_string( Slapi_Mods *smods, int modtype, const char *type, const char *val);
+void slapi_mods_remove(Slapi_Mods *smods);
+LDAPMod *slapi_mods_get_first_mod(Slapi_Mods *smods);
+LDAPMod *slapi_mods_get_next_mod(Slapi_Mods *smods);
+Slapi_Mod *slapi_mods_get_first_smod(Slapi_Mods *smods, Slapi_Mod *smod);
+Slapi_Mod *slapi_mods_get_next_smod(Slapi_Mods *smods, Slapi_Mod *smod);
+void slapi_mods_iterator_backone(Slapi_Mods *smods);
+LDAPMod **slapi_mods_get_ldapmods_byref(Slapi_Mods *smods);
+LDAPMod **slapi_mods_get_ldapmods_passout(Slapi_Mods *smods);
+int slapi_mods_get_num_mods(const Slapi_Mods *smods);
+void slapi_mods_dump(const Slapi_Mods *smods, const char *text);
+
+Slapi_Mod* slapi_mod_new( void );
+void slapi_mod_init(Slapi_Mod *smod, int initCount);
+void slapi_mod_init_byval(Slapi_Mod *smod, const LDAPMod *mod);
+void slapi_mod_init_byref(Slapi_Mod *smod, LDAPMod *mod);
+void slapi_mod_init_passin(Slapi_Mod *smod, LDAPMod *mod);
+void slapi_mod_add_value(Slapi_Mod *smod, const struct berval *val);
+void slapi_mod_remove_value(Slapi_Mod *smod);
+struct berval *slapi_mod_get_first_value(Slapi_Mod *smod);
+struct berval *slapi_mod_get_next_value(Slapi_Mod *smod);
+const char *slapi_mod_get_type(const Slapi_Mod *smod);
+int slapi_mod_get_operation(const Slapi_Mod *smod);
+void slapi_mod_set_type(Slapi_Mod *smod, const char *type);
+void slapi_mod_set_operation(Slapi_Mod *smod, int op);
+int slapi_mod_get_num_values(const Slapi_Mod *smod);
+const LDAPMod *slapi_mod_get_ldapmod_byref(const Slapi_Mod *smod);
+LDAPMod *slapi_mod_get_ldapmod_passout(Slapi_Mod *smod);
+void slapi_mod_free(Slapi_Mod **smod);
+void slapi_mod_done(Slapi_Mod *mod);
+int slapi_mod_isvalid(const Slapi_Mod *mod);
+void slapi_mod_dump(LDAPMod *mod, int n);
+
+
+/* helper functions to translate between entry and a set of mods */
+int slapi_mods2entry(Slapi_Entry **e, const char *dn, LDAPMod **attrs);
+int slapi_entry2mods(const Slapi_Entry *e, char **dn, LDAPMod ***attrs);
+
+
+/*
+ * routines for dealing with filters
+ */
+int slapi_filter_get_choice( Slapi_Filter *f );
+int slapi_filter_get_ava( Slapi_Filter *f, char **type, struct berval **bval );
+int slapi_filter_get_attribute_type( Slapi_Filter *f, char **type );
+int slapi_filter_get_subfilt( Slapi_Filter *f, char **type, char **initial,
+ char ***any, char **final );
+Slapi_Filter *slapi_filter_list_first( Slapi_Filter *f );
+Slapi_Filter *slapi_filter_list_next( Slapi_Filter *f, Slapi_Filter *fprev );
+Slapi_Filter *slapi_str2filter( char *str );
+Slapi_Filter *slapi_filter_join( int ftype, Slapi_Filter *f1,
+ Slapi_Filter *f2 );
+Slapi_Filter *slapi_filter_join_ex( int ftype, Slapi_Filter *f1,
+ Slapi_Filter *f2, int recurse_always );
+
+void slapi_filter_free( Slapi_Filter *f, int recurse );
+int slapi_filter_test( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Filter *f,
+ int verify_access );
+int slapi_vattr_filter_test( Slapi_PBlock *pb, Slapi_Entry *e,
+ struct slapi_filter *f, int verify_access);
+int slapi_filter_test_simple( Slapi_Entry *e, Slapi_Filter *f);
+char *slapi_find_matching_paren( const char *str );
+int slapi_filter_test_ext( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Filter *f,
+ int verify_access , int only_test_access);
+int slapi_vattr_filter_test_ext( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Filter *f,
+ int verify_access , int only_test_access);
+int slapi_filter_compare(struct slapi_filter *f1, struct slapi_filter *f2);
+Slapi_Filter *slapi_filter_dup(Slapi_Filter *f);
+int slapi_filter_changetype(Slapi_Filter *f, const char *newtype);
+
+
+/*
+ * slapi_filter_apply() is used to apply a function to each simple filter
+ * component within a complex filter. A 'simple filter' is anything other
+ * than AND, OR or NOT.
+ */
+typedef int (*FILTER_APPLY_FN)( Slapi_Filter *f, void *arg);
+int slapi_filter_apply( struct slapi_filter *f, FILTER_APPLY_FN fn, void *arg,
+ int *error_code );
+/*
+ * Possible return values for slapi_filter_apply() and FILTER_APPLY_FNs.
+ * Note that a FILTER_APPLY_FN should return _STOP or _CONTINUE only.
+ */
+#define SLAPI_FILTER_SCAN_STOP -1 /* premature abort */
+#define SLAPI_FILTER_SCAN_ERROR -2 /* an error occurred */
+#define SLAPI_FILTER_SCAN_NOMORE 0 /* success */
+#define SLAPI_FILTER_SCAN_CONTINUE 1 /* continue scanning */
+/* Error codes that slapi_filter_apply() may set in *error_code */
+#define SLAPI_FILTER_UNKNOWN_FILTER_TYPE 2
+
+
+/*
+ * Bit-Twiddlers
+ */
+unsigned char slapi_setbit_uchar(unsigned char f,unsigned char bitnum);
+unsigned char slapi_unsetbit_uchar(unsigned char f,unsigned char bitnum);
+int slapi_isbitset_uchar(unsigned char f,unsigned char bitnum);
+unsigned int slapi_setbit_int(unsigned int f,unsigned int bitnum);
+unsigned int slapi_unsetbit_int(unsigned int f,unsigned int bitnum);
+int slapi_isbitset_int(unsigned int f,unsigned int bitnum);
+
+
+/*
+ * routines for sending entries and results to the client
+ */
+int slapi_send_ldap_search_entry( Slapi_PBlock *pb, Slapi_Entry *e,
+ LDAPControl **ectrls, char **attrs, int attrsonly );
+void slapi_send_ldap_result( Slapi_PBlock *pb, int err, char *matched,
+ char *text, int nentries, struct berval **urls );
+int slapi_send_ldap_referral( Slapi_PBlock *pb, Slapi_Entry *e,
+ struct berval **refs, struct berval ***urls );
+typedef int (*send_ldap_search_entry_fn_ptr_t)( Slapi_PBlock *pb,
+ Slapi_Entry *e, LDAPControl **ectrls, char **attrs, int attrsonly );
+typedef void (*send_ldap_result_fn_ptr_t)( Slapi_PBlock *pb, int err,
+ char *matched, char *text, int nentries, struct berval **urls );
+typedef int (*send_ldap_referral_fn_ptr_t)( Slapi_PBlock *pb,
+ Slapi_Entry *e, struct berval **refs, struct berval ***urls );
+
+
+/*
+ * matching rule
+ */
+typedef int (*mrFilterMatchFn) (void* filter, Slapi_Entry*, Slapi_Attr* vals);
+/* returns: 0 filter matched
+ * -1 filter did not match
+ * >0 an LDAP error code
+ */
+int slapi_mr_indexer_create(Slapi_PBlock* opb);
+int slapi_mr_filter_index(Slapi_Filter* f, Slapi_PBlock* pb);
+int slapi_berval_cmp(const struct berval* L, const struct berval* R);
+#define SLAPI_BERVAL_EQ(L,R) ((L)->bv_len == (R)->bv_len && \
+ ! memcmp ((L)->bv_val, (R)->bv_val, (L)->bv_len))
+
+Slapi_MatchingRuleEntry *slapi_matchingrule_new(void);
+void slapi_matchingrule_free(Slapi_MatchingRuleEntry **mrEntry,
+ int freeMembers);
+int slapi_matchingrule_get(Slapi_MatchingRuleEntry *mr, int arg, void *value);
+int slapi_matchingrule_set(Slapi_MatchingRuleEntry *mr, int arg, void *value);
+int slapi_matchingrule_register(Slapi_MatchingRuleEntry *mrEntry);
+int slapi_matchingrule_unregister(char *oid);
+
+/*
+ * access control
+ */
+int slapi_access_allowed( Slapi_PBlock *pb, Slapi_Entry *e, char *attr,
+ struct berval *val, int access );
+int slapi_acl_check_mods( Slapi_PBlock *pb, Slapi_Entry *e,
+ LDAPMod **mods, char **errbuf );
+int slapi_acl_verify_aci_syntax(Slapi_PBlock *pb, Slapi_Entry *e, char **errbuf);
+
+
+/*
+ * attribute stuff
+ */
+int slapi_value_find( void *plugin, struct berval **vals, struct berval *v );
+
+
+/*
+ * password handling
+ */
+#define SLAPI_USERPWD_ATTR "userpassword"
+int slapi_pw_find_sv( Slapi_Value **vals, const Slapi_Value *v );
+
+/* value encoding encoding */
+/* checks if the value is encoded with any known algorithm*/
+int slapi_is_encoded(char *value);
+/* encode value with the specified algorithm */
+char* slapi_encode(char *value, char *alg);
+
+
+/* UTF8 related */
+int slapi_has8thBit(unsigned char *s);
+unsigned char *slapi_utf8StrToLower(unsigned char *s);
+void slapi_utf8ToLower(unsigned char *s, unsigned char *d, int *ssz, int *dsz);
+int slapi_utf8isUpper(unsigned char *s);
+unsigned char *slapi_utf8StrToUpper(unsigned char *s);
+void slapi_utf8ToUpper(unsigned char *s, unsigned char *d, int *ssz, int *dsz);
+int slapi_utf8isLower(unsigned char *s);
+int slapi_utf8casecmp(unsigned char *s0, unsigned char *s1);
+int slapi_utf8ncasecmp(unsigned char *s0, unsigned char *s1, int n);
+
+unsigned char *slapi_UTF8STRTOLOWER(char *s);
+void slapi_UTF8TOLOWER(char *s, char *d, int *ssz, int *dsz);
+int slapi_UTF8ISUPPER(char *s);
+unsigned char *slapi_UTF8STRTOUPPER(char *s);
+void slapi_UTF8TOUPPER(char *s, char *d, int *ssz, int *dsz);
+int slapi_UTF8ISLOWER(char *s);
+int slapi_UTF8CASECMP(char *s0, char *s1);
+int slapi_UTF8NCASECMP(char *s0, char *s1, int n);
+
+
+
+/*
+ * Interface to the API broker service
+ *
+ * The API broker allows plugins to publish an API that may be discovered
+ * and used dynamically at run time by other subsystems e.g. other plugins.
+ */
+
+/* Function: slapi_apib_register
+ Description: this function allows publication of an interface
+ Parameters: guid - a string constant that uniquely identifies the
+ interface (must exist for the life of the server)
+ api - a vtable for the published api (must exist for the
+ life of the server or until the reference count,
+ if it exists, reaches zero)
+ Return: 0 if function succeeds
+ non-zero otherwise
+*/
+int slapi_apib_register(char *guid, void **api); /* publish an interface */
+
+/* Function: slapi_apib_unregister
+ Description: this function allows removal of a published interface
+ Parameters: guid - a string constant that uniquely identifies the interface
+ Return: 0 if function succeeds
+ non-zero otherwise
+*/
+int slapi_apib_unregister(char *guid); /* remove interface from published list */
+
+
+/* Function: slapi_apib_get_interface
+ Description: this function allows retrieval of a published interface,
+ if the api reference counted, then the reference
+ count is incremented
+ Parameters: guid - a string constant that uniquely identifies the
+ interface requested
+ api - the retrieved vtable for the published api (must NOT
+ be freed)
+ Return: 0 if function succeeds
+ non-zero otherwise
+*/
+int slapi_apib_get_interface(char *guid, void ***api); /* retrieve an interface for use */
+
+
+/* Function: slapi_apib_make_reference_counted
+ Description: this function makes an interface a reference counted interface
+ it must be called prior to registering the interface
+ Parameters: api - the api to make a reference counted api
+ callback - if non-zero, this must be a pointer to a function
+ which the api broker will call when the ref count for
+ the api reaches zero. This function must return 0 if
+ it deregisters the api, non-zero otherwise
+ api - the retrieved vtable for the published api (must NOT
+ be freed)
+ Return: 0 if function succeeds
+ non-zero otherwise
+*/
+typedef int (*slapi_apib_callback_on_zero)(void **api);
+
+int slapi_apib_make_reference_counted(void **api,
+ slapi_apib_callback_on_zero callback);
+
+
+/* Function: slapi_apib_addref
+ Description: this function adds to the reference count of an api - a
+ call to this function should be paired with a call
+ to slapi_apib_release
+ - ONLY FOR REFERENCE COUNTED APIS
+ Parameters: api - the api to add a reference to
+ Return: the new reference count
+*/
+int slapi_apib_addref(void **api);
+
+
+/* Function: slapi_apib_release
+ Description: this function adds to the reference count of an api - a
+ call to this function should be paired with a prior call
+ to slapi_apib_addref or slapi_apib_get_interface
+ - ONLY FOR REFERENCE COUNTED APIS
+ Parameters: api - the api to add a reference to
+ Return: the new reference count
+*/
+int slapi_apib_release(void **api);
+
+/**** End of API broker interface. *******************************************/
+
+
+/*
+ * routines for dealing with controls
+ */
+int slapi_control_present( LDAPControl **controls, char *oid,
+ struct berval **val, int *iscritical );
+void slapi_register_supported_control( char *controloid,
+ unsigned long controlops );
+LDAPControl * slapi_dup_control( LDAPControl *ctrl );
+
+#define SLAPI_OPERATION_BIND 0x00000001UL
+#define SLAPI_OPERATION_UNBIND 0x00000002UL
+#define SLAPI_OPERATION_SEARCH 0x00000004UL
+#define SLAPI_OPERATION_MODIFY 0x00000008UL
+#define SLAPI_OPERATION_ADD 0x00000010UL
+#define SLAPI_OPERATION_DELETE 0x00000020UL
+#define SLAPI_OPERATION_MODDN 0x00000040UL
+#define SLAPI_OPERATION_MODRDN SLAPI_OPERATION_MODDN
+#define SLAPI_OPERATION_COMPARE 0x00000080UL
+#define SLAPI_OPERATION_ABANDON 0x00000100UL
+#define SLAPI_OPERATION_EXTENDED 0x00000200UL
+#define SLAPI_OPERATION_ANY 0xFFFFFFFFUL
+#define SLAPI_OPERATION_NONE 0x00000000UL
+int slapi_get_supported_controls_copy( char ***ctrloidsp,
+ unsigned long **ctrlopsp );
+int slapi_build_control( char *oid, BerElement *ber,
+ char iscritical, LDAPControl **ctrlp );
+int slapi_build_control_from_berval( char *oid, struct berval *bvp,
+ char iscritical, LDAPControl **ctrlp );
+
+
+/*
+ * routines for dealing with extended operations
+ */
+char **slapi_get_supported_extended_ops_copy( void );
+
+
+/*
+ * bind, including SASL
+ */
+void slapi_register_supported_saslmechanism( char *mechanism );
+char ** slapi_get_supported_saslmechanisms_copy( void );
+
+/*
+ * routine for freeing the ch_arrays returned by the slapi_get*_copy functions above
+ */
+void slapi_ch_array_free( char **array );
+
+
+/*
+ * checking routines for allocating and freeing memory
+ */
+char * slapi_ch_malloc( unsigned long size );
+char * slapi_ch_realloc( char *block, unsigned long size );
+char * slapi_ch_calloc( unsigned long nelem, unsigned long size );
+char * slapi_ch_strdup( const char *s );
+void slapi_ch_free( void **ptr );
+void slapi_ch_free_string( char **s );
+struct berval* slapi_ch_bvdup(const struct berval*);
+struct berval** slapi_ch_bvecdup(struct berval**);
+void slapi_ch_bvfree(struct berval** v);
+
+
+/*
+ * syntax plugin routines
+ */
+int slapi_call_syntax_values2keys_sv( void *vpi, Slapi_Value **vals,
+ Slapi_Value ***ivals, int ftype );
+int slapi_call_syntax_assertion2keys_ava_sv( void *vpi, Slapi_Value *val,
+ Slapi_Value ***ivals, int ftype );
+int slapi_call_syntax_assertion2keys_sub_sv( void *vpi, char *initial,
+ char **any, char *final, Slapi_Value ***ivals );
+
+
+/*
+ * internal operation and plugin callback routines
+ */
+typedef void (*plugin_result_callback)(int rc, void *callback_data);
+typedef int (*plugin_referral_entry_callback)(char * referral,
+ void *callback_data);
+typedef int (*plugin_search_entry_callback)(Slapi_Entry *e,
+ void *callback_data);
+void slapi_free_search_results_internal(Slapi_PBlock *pb);
+
+
+/*
+ * The following functions can be used for internal operations based on DN
+ * as well as on uniqueid. These functions should be used by all new plugins
+ * and preferrably old plugins should be changed to use them to take
+ * advantage of new plugin configuration capabilities and to use an
+ * extensible interface.
+ *
+ * These functions return -1 if pb is NULL and 0 otherwise.
+ * The SLAPI_PLUGIN_INTOP_RESULT pblock parameter should be checked to
+ * check if the operation was successful.
+ *
+ * Helper functions are provided to set up pblock parameters currently used
+ * by the functions, e.g., slapi_search_internal_set_pb().
+ * Additional parameters may be set directly in the pblock.
+ */
+
+int slapi_search_internal_pb(Slapi_PBlock *pb);
+int slapi_search_internal_callback_pb(Slapi_PBlock *pb, void *callback_data,
+ plugin_result_callback prc, plugin_search_entry_callback psec,
+ plugin_referral_entry_callback prec);
+int slapi_add_internal_pb(Slapi_PBlock *pb);
+int slapi_modify_internal_pb(Slapi_PBlock *pb);
+int slapi_modrdn_internal_pb(Slapi_PBlock *pb);
+int slapi_delete_internal_pb(Slapi_PBlock *pb);
+
+
+int slapi_seq_internal_callback_pb(Slapi_PBlock *pb, void *callback_data,
+ plugin_result_callback res_callback,
+ plugin_search_entry_callback srch_callback,
+ plugin_referral_entry_callback ref_callback);
+
+void slapi_search_internal_set_pb(Slapi_PBlock *pb, const char *base,
+ int scope, const char *filter, char **attrs, int attrsonly,
+ LDAPControl **controls, const char *uniqueid,
+ Slapi_ComponentId *plugin_identity, int operation_flags);
+void slapi_add_entry_internal_set_pb(Slapi_PBlock *pb, Slapi_Entry *e,
+ LDAPControl **controls, Slapi_ComponentId *plugin_identity,
+ int operation_flags);
+int slapi_add_internal_set_pb(Slapi_PBlock *pb, const char *dn,
+ LDAPMod **attrs, LDAPControl **controls,
+ Slapi_ComponentId *plugin_identity, int operation_flags);
+void slapi_modify_internal_set_pb(Slapi_PBlock *pb, const char *dn,
+ LDAPMod **mods, LDAPControl **controls, const char *uniqueid,
+ Slapi_ComponentId *plugin_identity, int operation_flags);
+void slapi_rename_internal_set_pb(Slapi_PBlock *pb, const char *olddn,
+ const char *newrdn, const char *newsuperior, int deloldrdn,
+ LDAPControl **controls, const char *uniqueid,
+ Slapi_ComponentId *plugin_identity, int operation_flags);
+void slapi_delete_internal_set_pb(Slapi_PBlock *pb, const char *dn,
+ LDAPControl **controls, const char *uniqueid,
+ Slapi_ComponentId *plugin_identity, int operation_flags);
+void slapi_seq_internal_set_pb(Slapi_PBlock *pb, char *ibase, int type,
+ char *attrname, char *val, char **attrs, int attrsonly,
+ LDAPControl **controls, Slapi_ComponentId *plugin_identity,
+ int operation_flags);
+
+/*
+ * slapi_search_internal_get_entry() finds an entry given a dn. It returns
+ * an LDAP error code (LDAP_SUCCESS if all goes well).
+ */
+int slapi_search_internal_get_entry( Slapi_DN *dn, char ** attrlist,
+ Slapi_Entry **ret_entry , void *caller_identity);
+
+/*
+ * interface for registering object extensions.
+ */
+typedef void *(*slapi_extension_constructor_fnptr)(void *object, void *parent);
+
+typedef void (*slapi_extension_destructor_fnptr)(void *extension,
+ void *object, void *parent);
+
+int slapi_register_object_extension( const char *pluginname,
+ const char *objectname, slapi_extension_constructor_fnptr constructor,
+ slapi_extension_destructor_fnptr destructor, int *objecttype,
+ int *extensionhandle);
+
+/* objects that can be extended (possible values for the objectname param.) */
+#define SLAPI_EXT_CONNECTION "Connection"
+#define SLAPI_EXT_OPERATION "Operation"
+#define SLAPI_EXT_ENTRY "Entry"
+#define SLAPI_EXT_MTNODE "Mapping Tree Node"
+
+void *slapi_get_object_extension(int objecttype, void *object,
+ int extensionhandle);
+void slapi_set_object_extension(int objecttype, void *object,
+ int extensionhandle, void *extension);
+
+/*
+ * interface to allow a plugin to register additional plugins.
+ */
+typedef int (*slapi_plugin_init_fnptr)( Slapi_PBlock *pb );
+int slapi_register_plugin( const char *plugintype, int enabled,
+ const char *initsymbol, slapi_plugin_init_fnptr initfunc,
+ const char *name, char **argv, void *group_identity);
+
+
+/*
+ * logging
+ */
+int slapi_log_error( int severity, char *subsystem, char *fmt, ... );
+/* allowed values for the "severity" parameter */
+#define SLAPI_LOG_FATAL 0
+#define SLAPI_LOG_TRACE 1
+#define SLAPI_LOG_PACKETS 2
+#define SLAPI_LOG_ARGS 3
+#define SLAPI_LOG_CONNS 4
+#define SLAPI_LOG_BER 5
+#define SLAPI_LOG_FILTER 6
+#define SLAPI_LOG_CONFIG 7
+#define SLAPI_LOG_ACL 8
+#define SLAPI_LOG_SHELL 9
+#define SLAPI_LOG_PARSE 10
+#define SLAPI_LOG_HOUSE 11
+#define SLAPI_LOG_REPL 12
+#define SLAPI_LOG_CACHE 13
+#define SLAPI_LOG_PLUGIN 14
+#define SLAPI_LOG_TIMING 15
+#define SLAPI_LOG_ACLSUMMARY 16
+
+int slapi_is_loglevel_set( const int loglevel );
+
+
+/*
+ * locks and synchronization
+ */
+typedef struct slapi_mutex Slapi_Mutex;
+typedef struct slapi_condvar Slapi_CondVar;
+Slapi_Mutex *slapi_new_mutex( void );
+void slapi_destroy_mutex( Slapi_Mutex *mutex );
+void slapi_lock_mutex( Slapi_Mutex *mutex );
+int slapi_unlock_mutex( Slapi_Mutex *mutex );
+Slapi_CondVar *slapi_new_condvar( Slapi_Mutex *mutex );
+void slapi_destroy_condvar( Slapi_CondVar *cvar );
+int slapi_wait_condvar( Slapi_CondVar *cvar, struct timeval *timeout );
+int slapi_notify_condvar( Slapi_CondVar *cvar, int notify_all );
+
+
+/*
+ * thread-safe LDAP connections
+ */
+LDAP *slapi_ldap_init( char *ldaphost, int ldapport, int secure, int shared );
+void slapi_ldap_unbind( LDAP *ld );
+
+
+/*
+ * computed attributes
+ */
+struct _computed_attr_context;
+typedef struct _computed_attr_context computed_attr_context;
+typedef int (*slapi_compute_output_t)(computed_attr_context *c,Slapi_Attr *a , Slapi_Entry *e);
+typedef int (*slapi_compute_callback_t)(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_compute_output_t outputfn);
+typedef int (*slapi_search_rewrite_callback_t)(Slapi_PBlock *pb);
+int slapi_compute_add_evaluator(slapi_compute_callback_t function);
+int slapi_compute_add_search_rewriter(slapi_search_rewrite_callback_t function);
+int compute_rewrite_search_filter(Slapi_PBlock *pb);
+
+
+/*
+ * routines for dealing with backends
+ */
+Slapi_Backend *slapi_be_new( const char *type, const char *name,
+ int isprivate, int logchanges );
+void slapi_be_free(Slapi_Backend **be);
+Slapi_Backend *slapi_be_select( const Slapi_DN *sdn );
+Slapi_Backend *slapi_be_select_by_instance_name( const char *name );
+int slapi_be_exist(const Slapi_DN *sdn);
+void slapi_be_delete_onexit(Slapi_Backend *be);
+void slapi_be_set_readonly(Slapi_Backend *be, int readonly);
+int slapi_be_get_readonly(Slapi_Backend *be);
+int slapi_be_getentrypoint(Slapi_Backend *be, int entrypoint, void **ret_fnptr,
+ Slapi_PBlock *pb);
+int slapi_be_setentrypoint(Slapi_Backend *be, int entrypoint, void *ret_fnptr,
+ Slapi_PBlock *pb);
+int slapi_be_logchanges(Slapi_Backend *be);
+int slapi_be_issuffix(const Slapi_Backend *be, const Slapi_DN *suffix );
+void slapi_be_addsuffix(Slapi_Backend *be,const Slapi_DN *suffix);
+char * slapi_be_get_name(Slapi_Backend * be);
+const Slapi_DN *slapi_be_getsuffix(Slapi_Backend *be, int n);
+Slapi_Backend* slapi_get_first_backend(char **cookie);
+Slapi_Backend* slapi_get_next_backend(char *cookie);
+int slapi_be_private( Slapi_Backend *be );
+void * slapi_be_get_instance_info(Slapi_Backend * be);
+void slapi_be_set_instance_info(Slapi_Backend * be, void * data);
+Slapi_DN * slapi_get_first_suffix(void ** node, int show_private);
+Slapi_DN * slapi_get_next_suffix(void ** node, int show_private);
+int slapi_is_root_suffix(Slapi_DN * dn);
+const char * slapi_be_gettype(Slapi_Backend *be);
+
+int slapi_be_is_flag_set(Slapi_Backend * be, int flag);
+void slapi_be_set_flag(Slapi_Backend * be, int flag);
+#define SLAPI_BE_FLAG_REMOTE_DATA 0x1 /* entries held by backend are remote */
+#define SLAPI_BE_FLAG_DONT_BYPASS_FILTERTEST 0x10 /* force to call filter_test (search only) */
+
+
+/* These functions allow a plugin to register for callback when
+ * a backend state change
+ */
+typedef void (*slapi_backend_state_change_fnptr)(void *handle, char *be_name,
+ int old_be_state, int new_be_state);
+void slapi_register_backend_state_change(void * handle, slapi_backend_state_change_fnptr funct);
+int slapi_unregister_backend_state_change(void * handle);
+#define SLAPI_BE_STATE_ON 1 /* backend is ON */
+#define SLAPI_BE_STATE_OFFLINE 2 /* backend is OFFLINE (import process) */
+#define SLAPI_BE_STATE_DELETE 3 /* backend has been deleted */
+
+/*
+ * Distribution.
+ */
+/* SLAPI_BE_ALL_BACKENDS is a special value that is returned by
+ * a distribution plugin function to indicate that all backends
+ * should be searched (it is only used for search operations).
+ */
+#define SLAPI_BE_ALL_BACKENDS -1
+
+
+
+/*
+ * virtual attribute service
+ */
+
+/* General flags (flags parameter) */
+#define SLAPI_REALATTRS_ONLY 1
+#define SLAPI_VIRTUALATTRS_ONLY 2
+#define SLAPI_VIRTUALATTRS_REQUEST_POINTERS 4 /* I want to receive pointers into the entry, if possible */
+#define SLAPI_VIRTUALATTRS_LIST_OPERATIONAL_ATTRS 8 /* Include operational attributes in attribute lists */
+#define SLAPI_VIRTUALATTRS_SUPPRESS_SUBTYPES 16 /* I want only the requested attribute */
+
+/* Buffer disposition flags (buffer_flags parameter) */
+#define SLAPI_VIRTUALATTRS_RETURNED_POINTERS 1
+#define SLAPI_VIRTUALATTRS_RETURNED_COPIES 2
+#define SLAPI_VIRTUALATTRS_REALATTRS_ONLY 4
+
+/* Attribute type name disposition values (type_name_disposition parameter) */
+#define SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS 1
+#define SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE 2
+#define SLAPI_VIRTUALATTRS_NOT_FOUND -1
+#define SLAPI_VIRTUALATTRS_LOOP_DETECTED -2
+
+typedef struct _vattr_type_thang vattr_type_thang;
+typedef struct _vattr_get_thang vattr_get_thang;
+vattr_get_thang *slapi_vattr_getthang_first(vattr_get_thang *t);
+vattr_get_thang *slapi_vattr_getthang_next(vattr_get_thang *t);
+
+int slapi_vattr_values_type_thang_get(
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* attr type */ vattr_type_thang *type_thang,
+ /* pointer to result set */ Slapi_ValueSet** results,
+ int *type_name_disposition, char **actual_type_name, int flags,
+ int *buffer_flags);
+int slapi_vattr_values_get(
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* attr type name */ char *type,
+ /* pointer to result set */ Slapi_ValueSet** results,
+ int *type_name_disposition, char **actual_type_name, int flags,
+ int *buffer_flags);
+int slapi_vattr_values_get_ex(
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* attr type name */ char *type,
+ /* pointer to result set */ Slapi_ValueSet*** results,
+ int **type_name_disposition, char ***actual_type_name, int flags,
+ int *buffer_flags, int *subtype_count);
+int slapi_vattr_namespace_values_get(
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* backend namespace dn */ Slapi_DN *namespace_dn,
+ /* attr type name */ char *type,
+ /* pointer to result set */ Slapi_ValueSet*** results,
+ int **type_name_disposition, char ***actual_type_name, int flags,
+ int *buffer_flags, int *subtype_count);
+void slapi_vattr_values_free(Slapi_ValueSet **value, char **actual_type_name,
+ int flags);
+int slapi_vattr_value_compare(
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* attr type name */ char *type,
+ Slapi_Value *test_this,/* pointer to result */ int *result,
+ int flags);
+int slapi_vattr_namespace_value_compare(
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* backend namespace dn */ Slapi_DN *namespace_dn,
+ /* attr type name */ const char *type,
+ Slapi_Value *test_this,/* pointer to result */ int *result,
+ int flags);
+int slapi_vattr_list_attrs(
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* pointer to receive the list */ vattr_type_thang **types,
+ int flags, int *buffer_flags);
+void slapi_vattr_attrs_free(vattr_type_thang **types, int flags);
+char *vattr_typethang_get_name(vattr_type_thang *t);
+unsigned long vattr_typethang_get_flags(vattr_type_thang *t);
+vattr_type_thang *vattr_typethang_next(vattr_type_thang *t);
+vattr_type_thang *vattr_typethang_first(vattr_type_thang *t);
+int slapi_vattr_schema_check_type(Slapi_Entry *e, char *type);
+
+
+/* roles */
+typedef int (*roles_check_fn_type)(Slapi_Entry *entry_to_check, Slapi_DN *role_dn, int *present);
+
+int slapi_role_check(Slapi_Entry *entry_to_check, Slapi_DN *role_dn, int *present);
+void slapi_register_role_check(roles_check_fn_type check_fn);
+
+
+
+/* Binder-based (connection centric) resource limits */
+/*
+ * Valid values for `type' parameter to slapi_reslimit_register().
+ */
+#define SLAPI_RESLIMIT_TYPE_INT 0
+
+/*
+ * Status codes returned by all functions.
+ */
+#define SLAPI_RESLIMIT_STATUS_SUCCESS 0 /* goodness */
+#define SLAPI_RESLIMIT_STATUS_NOVALUE 1 /* no value is available */
+#define SLAPI_RESLIMIT_STATUS_INIT_FAILURE 2 /* initialization failed */
+#define SLAPI_RESLIMIT_STATUS_PARAM_ERROR 3 /* bad parameter */
+#define SLAPI_RESLIMIT_STATUS_UNKNOWN_HANDLE 4 /* unregistered handle */
+#define SLAPI_RESLIMIT_STATUS_INTERNAL_ERROR 5 /* unexpected error */
+
+/*
+ * Functions.
+ */
+int slapi_reslimit_register( int type, const char *attrname, int *handlep );
+int slapi_reslimit_get_integer_limit( Slapi_Connection *conn, int handle,
+ int *limitp );
+/* END of Binder-based resource limits API */
+
+
+
+/*
+ * Plugin and parameter block related macros (remainder of this file).
+ */
+
+/*
+ * Plugin version. Note that the Directory Server will load version 01
+ * and 02 plugins, but some server features require 03 plugins.
+ */
+#define SLAPI_PLUGIN_VERSION_01 "01"
+#define SLAPI_PLUGIN_VERSION_02 "02"
+#define SLAPI_PLUGIN_VERSION_03 "03"
+#define SLAPI_PLUGIN_CURRENT_VERSION SLAPI_PLUGIN_VERSION_03
+#define SLAPI_PLUGIN_IS_COMPAT(x) \
+ ((strcmp((x), SLAPI_PLUGIN_VERSION_01) == 0) || \
+ (strcmp((x), SLAPI_PLUGIN_VERSION_02) == 0) || \
+ (strcmp((x), SLAPI_PLUGIN_VERSION_03) == 0))
+#define SLAPI_PLUGIN_IS_V2(x) \
+ ((strcmp((x)->plg_version, SLAPI_PLUGIN_VERSION_02) == 0) || \
+ (strcmp((x)->plg_version, SLAPI_PLUGIN_VERSION_03) == 0))
+#define SLAPI_PLUGIN_IS_V3(x) \
+ (strcmp((x)->plg_version, SLAPI_PLUGIN_VERSION_03) == 0)
+
+/* this one just has to be human readable */
+#define SLAPI_PLUGIN_SUPPORTED_VERSIONS "01,02,03"
+
+/*
+ * types of plugin interfaces
+ */
+#define SLAPI_PLUGIN_EXTENDEDOP 2
+#define SLAPI_PLUGIN_PREOPERATION 3
+#define SLAPI_PLUGIN_POSTOPERATION 4
+#define SLAPI_PLUGIN_MATCHINGRULE 5
+#define SLAPI_PLUGIN_SYNTAX 6
+#define SLAPI_PLUGIN_ACL 7
+#define SLAPI_PLUGIN_BEPREOPERATION 8
+#define SLAPI_PLUGIN_BEPOSTOPERATION 9
+#define SLAPI_PLUGIN_ENTRY 10
+#define SLAPI_PLUGIN_TYPE_OBJECT 11
+#define SLAPI_PLUGIN_INTERNAL_PREOPERATION 12
+#define SLAPI_PLUGIN_INTERNAL_POSTOPERATION 13
+#define SLAPI_PLUGIN_PWD_STORAGE_SCHEME 14
+#define SLAPI_PLUGIN_VATTR_SP 15
+#define SLAPI_PLUGIN_REVER_PWD_STORAGE_SCHEME 16
+#define SLAPI_PLUGIN_LDBM_ENTRY_FETCH_STORE 17
+#define SLAPI_PLUGIN_INDEX 18
+
+/*
+ * special return values for extended operation plugins (zero or positive
+ * return values should be LDAP error codes as defined in ldap.h)
+ */
+#define SLAPI_PLUGIN_EXTENDED_SENT_RESULT -1
+#define SLAPI_PLUGIN_EXTENDED_NOT_HANDLED -2
+
+/*
+ * the following can be used as the second argument to the
+ * slapi_pblock_get() and slapi_pblock_set() calls.
+ */
+
+/* backend, connection, operation */
+#define SLAPI_BACKEND 130
+#define SLAPI_CONNECTION 131
+#define SLAPI_OPERATION 132
+#define SLAPI_REQUESTOR_ISROOT 133
+#define SLAPI_BE_TYPE 135
+#define SLAPI_BE_READONLY 136
+#define SLAPI_BE_LASTMOD 137
+#define SLAPI_CONN_ID 139
+#define SLAPI_BACKEND_COUNT 860
+
+/* operation */
+#define SLAPI_OPINITIATED_TIME 140
+#define SLAPI_REQUESTOR_DN 141
+#define SLAPI_OPERATION_PARAMETERS 138
+#define SLAPI_OPERATION_TYPE 590
+#define SLAPI_OPERATION_AUTHTYPE 741
+#define SLAPI_OPERATION_ID 744
+#define SLAPI_IS_REPLICATED_OPERATION 142
+#define SLAPI_IS_MMR_REPLICATED_OPERATION 153
+#define SLAPI_IS_LEGACY_REPLICATED_OPERATION 154
+
+/* connection */
+#define SLAPI_CONN_DN 143
+#define SLAPI_CONN_CLIENTNETADDR 850
+#define SLAPI_CONN_SERVERNETADDR 851
+#define SLAPI_CONN_IS_REPLICATION_SESSION 149
+#define SLAPI_CONN_IS_SSL_SESSION 747
+#define SLAPI_CONN_CERT 743
+#define SLAPI_CONN_AUTHMETHOD 746
+
+/*
+ * Types of authentication for SLAPI_CONN_AUTHMETHOD
+ * (and deprecated SLAPI_CONN_AUTHTYPE)
+ */
+#define SLAPD_AUTH_NONE "none"
+#define SLAPD_AUTH_SIMPLE "simple"
+#define SLAPD_AUTH_SSL "SSL"
+#define SLAPD_AUTH_SASL "SASL " /* followed by the mechanism name */
+
+
+/* Command Line Arguments */
+#define SLAPI_ARGC 147
+#define SLAPI_ARGV 148
+
+/* Slapd config file directory */
+#define SLAPI_CONFIG_DIRECTORY 281
+
+/* DSE flags */
+#define SLAPI_DSE_DONT_WRITE_WHEN_ADDING 282
+#define SLAPI_DSE_MERGE_WHEN_ADDING 283
+#define SLAPI_DSE_DONT_CHECK_DUPS 284
+#define SLAPI_DSE_REAPPLY_MODS 287
+#define SLAPI_DSE_IS_PRIMARY_FILE 289
+
+/* internal schema flags */
+#define SLAPI_SCHEMA_USER_DEFINED_ONLY 285
+
+/* urp flags */
+#define SLAPI_URP_NAMING_COLLISION_DN 286
+#define SLAPI_URP_TOMBSTONE_UNIQUEID 288
+
+/* common to all plugins */
+#define SLAPI_PLUGIN 3
+#define SLAPI_PLUGIN_PRIVATE 4
+#define SLAPI_PLUGIN_TYPE 5
+#define SLAPI_PLUGIN_ARGV 6
+#define SLAPI_PLUGIN_ARGC 7
+#define SLAPI_PLUGIN_VERSION 8
+
+#define SLAPI_PLUGIN_OPRETURN 9
+#define SLAPI_PLUGIN_OBJECT 10
+#define SLAPI_PLUGIN_DESTROY_FN 11
+
+#define SLAPI_PLUGIN_DESCRIPTION 12
+typedef struct slapi_plugindesc {
+ char *spd_id;
+ char *spd_vendor;
+ char *spd_version;
+ char *spd_description;
+} Slapi_PluginDesc;
+
+#define SLAPI_PLUGIN_IDENTITY 13
+
+/* common for internal plugin_ops */
+#define SLAPI_PLUGIN_INTOP_RESULT 15
+#define SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES 16
+#define SLAPI_PLUGIN_INTOP_SEARCH_REFERRALS 17
+
+/* miscellaneous plugin functions */
+#define SLAPI_PLUGIN_CLOSE_FN 210
+#define SLAPI_PLUGIN_START_FN 212
+#define SLAPI_PLUGIN_CLEANUP_FN 232
+#define SLAPI_PLUGIN_POSTSTART_FN 233
+
+
+/* extendedop plugin functions */
+#define SLAPI_PLUGIN_EXT_OP_FN 300
+#define SLAPI_PLUGIN_EXT_OP_OIDLIST 301
+#define SLAPI_PLUGIN_EXT_OP_NAMELIST 302
+
+/* preoperation plugin functions */
+#define SLAPI_PLUGIN_PRE_BIND_FN 401
+#define SLAPI_PLUGIN_PRE_UNBIND_FN 402
+#define SLAPI_PLUGIN_PRE_SEARCH_FN 403
+#define SLAPI_PLUGIN_PRE_COMPARE_FN 404
+#define SLAPI_PLUGIN_PRE_MODIFY_FN 405
+#define SLAPI_PLUGIN_PRE_MODRDN_FN 406
+#define SLAPI_PLUGIN_PRE_ADD_FN 407
+#define SLAPI_PLUGIN_PRE_DELETE_FN 408
+#define SLAPI_PLUGIN_PRE_ABANDON_FN 409
+#define SLAPI_PLUGIN_PRE_ENTRY_FN 410
+#define SLAPI_PLUGIN_PRE_REFERRAL_FN 411
+#define SLAPI_PLUGIN_PRE_RESULT_FN 412
+
+/* internal preoperation plugin functions */
+#define SLAPI_PLUGIN_INTERNAL_PRE_ADD_FN 420
+#define SLAPI_PLUGIN_INTERNAL_PRE_MODIFY_FN 421
+#define SLAPI_PLUGIN_INTERNAL_PRE_MODRDN_FN 422
+#define SLAPI_PLUGIN_INTERNAL_PRE_DELETE_FN 423
+
+/* preoperation plugin to the backend */
+#define SLAPI_PLUGIN_BE_PRE_ADD_FN 450
+#define SLAPI_PLUGIN_BE_PRE_MODIFY_FN 451
+#define SLAPI_PLUGIN_BE_PRE_MODRDN_FN 452
+#define SLAPI_PLUGIN_BE_PRE_DELETE_FN 453
+
+/* postoperation plugin functions */
+#define SLAPI_PLUGIN_POST_BIND_FN 501
+#define SLAPI_PLUGIN_POST_UNBIND_FN 502
+#define SLAPI_PLUGIN_POST_SEARCH_FN 503
+#define SLAPI_PLUGIN_POST_COMPARE_FN 504
+#define SLAPI_PLUGIN_POST_MODIFY_FN 505
+#define SLAPI_PLUGIN_POST_MODRDN_FN 506
+#define SLAPI_PLUGIN_POST_ADD_FN 507
+#define SLAPI_PLUGIN_POST_DELETE_FN 508
+#define SLAPI_PLUGIN_POST_ABANDON_FN 509
+#define SLAPI_PLUGIN_POST_ENTRY_FN 510
+#define SLAPI_PLUGIN_POST_REFERRAL_FN 511
+#define SLAPI_PLUGIN_POST_RESULT_FN 512
+#define SLAPI_PLUGIN_POST_SEARCH_FAIL_FN 513
+
+/* internal preoperation plugin functions */
+#define SLAPI_PLUGIN_INTERNAL_POST_ADD_FN 520
+#define SLAPI_PLUGIN_INTERNAL_POST_MODIFY_FN 521
+#define SLAPI_PLUGIN_INTERNAL_POST_MODRDN_FN 522
+#define SLAPI_PLUGIN_INTERNAL_POST_DELETE_FN 523
+
+/* postoperation plugin to the backend */
+#define SLAPI_PLUGIN_BE_POST_ADD_FN 550
+#define SLAPI_PLUGIN_BE_POST_MODIFY_FN 551
+#define SLAPI_PLUGIN_BE_POST_MODRDN_FN 552
+#define SLAPI_PLUGIN_BE_POST_DELETE_FN 553
+
+/* matching rule plugin functions */
+#define SLAPI_PLUGIN_MR_FILTER_CREATE_FN 600
+#define SLAPI_PLUGIN_MR_INDEXER_CREATE_FN 601
+#define SLAPI_PLUGIN_MR_FILTER_MATCH_FN 602
+#define SLAPI_PLUGIN_MR_FILTER_INDEX_FN 603
+#define SLAPI_PLUGIN_MR_FILTER_RESET_FN 604
+#define SLAPI_PLUGIN_MR_INDEX_FN 605
+
+/* matching rule plugin arguments */
+#define SLAPI_PLUGIN_MR_OID 610
+#define SLAPI_PLUGIN_MR_TYPE 611
+#define SLAPI_PLUGIN_MR_VALUE 612
+#define SLAPI_PLUGIN_MR_VALUES 613
+#define SLAPI_PLUGIN_MR_KEYS 614
+#define SLAPI_PLUGIN_MR_FILTER_REUSABLE 615
+#define SLAPI_PLUGIN_MR_QUERY_OPERATOR 616
+#define SLAPI_PLUGIN_MR_USAGE 617
+
+
+/* Defined values of SLAPI_PLUGIN_MR_QUERY_OPERATOR: */
+#define SLAPI_OP_LESS 1
+#define SLAPI_OP_LESS_OR_EQUAL 2
+#define SLAPI_OP_EQUAL 3
+#define SLAPI_OP_GREATER_OR_EQUAL 4
+#define SLAPI_OP_GREATER 5
+#define SLAPI_OP_SUBSTRING 6
+
+/* Defined values of SLAPI_PLUGIN_MR_USAGE: */
+#define SLAPI_PLUGIN_MR_USAGE_INDEX 0
+#define SLAPI_PLUGIN_MR_USAGE_SORT 1
+
+/* Defined values for matchingRuleEntry accessor functions */
+#define SLAPI_MATCHINGRULE_NAME 1
+#define SLAPI_MATCHINGRULE_OID 2
+#define SLAPI_MATCHINGRULE_DESC 3
+#define SLAPI_MATCHINGRULE_SYNTAX 4
+#define SLAPI_MATCHINGRULE_OBSOLETE 5
+
+/* syntax plugin functions and arguments */
+#define SLAPI_PLUGIN_SYNTAX_FILTER_AVA 700
+#define SLAPI_PLUGIN_SYNTAX_FILTER_SUB 701
+#define SLAPI_PLUGIN_SYNTAX_VALUES2KEYS 702
+#define SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_AVA 703
+#define SLAPI_PLUGIN_SYNTAX_ASSERTION2KEYS_SUB 704
+#define SLAPI_PLUGIN_SYNTAX_NAMES 705
+#define SLAPI_PLUGIN_SYNTAX_OID 706
+#define SLAPI_PLUGIN_SYNTAX_FLAGS 707
+#define SLAPI_PLUGIN_SYNTAX_COMPARE 708
+
+/* ACL plugin functions and arguments */
+#define SLAPI_PLUGIN_ACL_INIT 730
+#define SLAPI_PLUGIN_ACL_SYNTAX_CHECK 731
+#define SLAPI_PLUGIN_ACL_ALLOW_ACCESS 732
+#define SLAPI_PLUGIN_ACL_MODS_ALLOWED 733
+#define SLAPI_PLUGIN_ACL_MODS_UPDATE 734
+
+
+#define ACLPLUGIN_ACCESS_DEFAULT 0
+#define ACLPLUGIN_ACCESS_READ_ON_ENTRY 1
+#define ACLPLUGIN_ACCESS_READ_ON_ATTR 2
+#define ACLPLUGIN_ACCESS_READ_ON_VLV 3
+#define ACLPLUGIN_ACCESS_MODRDN 4
+#define ACLPLUGIN_ACCESS_GET_EFFECTIVE_RIGHTS 5
+
+/* Authorization types */
+#define SLAPI_BE_MAXNESTLEVEL 742
+#define SLAPI_CLIENT_DNS 745
+
+/* Password storage scheme functions and arguments */
+#define SLAPI_PLUGIN_PWD_STORAGE_SCHEME_ENC_FN 800
+#define SLAPI_PLUGIN_PWD_STORAGE_SCHEME_DEC_FN 801 /* only meaningfull for reversible encryption */
+#define SLAPI_PLUGIN_PWD_STORAGE_SCHEME_CMP_FN 802
+
+#define SLAPI_PLUGIN_PWD_STORAGE_SCHEME_NAME 810 /* name of the method: SHA, SSHA... */
+#define SLAPI_PLUGIN_PWD_STORAGE_SCHEME_USER_PWD 811 /* value sent over LDAP */
+#define SLAPI_PLUGIN_PWD_STORAGE_SCHEME_DB_PWD 812 /* value from the DB */
+
+/* entry fetch and entry store values */
+#define SLAPI_PLUGIN_ENTRY_FETCH_FUNC 813
+#define SLAPI_PLUGIN_ENTRY_STORE_FUNC 814
+
+/*
+ * Defined values of SLAPI_PLUGIN_SYNTAX_FLAGS:
+ */
+#define SLAPI_PLUGIN_SYNTAX_FLAG_ORKEYS 1
+#define SLAPI_PLUGIN_SYNTAX_FLAG_ORDERING 2
+
+/* controls we know about */
+#define SLAPI_MANAGEDSAIT 1000
+#define SLAPI_PWPOLICY 1001
+
+/* arguments that are common to all operation */
+#define SLAPI_TARGET_ADDRESS 48 /* target address (dn + uniqueid) should be normalized */
+#define SLAPI_TARGET_UNIQUEID 49 /* target uniqueid of the operation */
+#define SLAPI_TARGET_DN 50 /* target dn of the operation should be normalized */
+#define SLAPI_REQCONTROLS 51 /* request controls */
+
+/* Copies of entry before and after add, mod, mod[r]dn operations */
+#define SLAPI_ENTRY_PRE_OP 52
+#define SLAPI_ENTRY_POST_OP 53
+
+/* LDAPv3 controls to be sent with the operation result */
+#define SLAPI_RESCONTROLS 55
+#define SLAPI_ADD_RESCONTROL 56 /* add result control */
+
+/* Extra notes to be logged within access log RESULT lines */
+#define SLAPI_OPERATION_NOTES 57
+#define SLAPI_OP_NOTE_UNINDEXED 0x01
+
+/* Allows controls to be passed before operation object is created */
+#define SLAPI_CONTROLS_ARG 58
+
+/* specify whether pblock content should be destroyed when the pblock is destroyed */
+#define SLAPI_DESTROY_CONTENT 59
+
+/* add arguments */
+#define SLAPI_ADD_TARGET SLAPI_TARGET_DN
+#define SLAPI_ADD_ENTRY 60
+#define SLAPI_ADD_EXISTING_DN_ENTRY 61
+#define SLAPI_ADD_PARENT_ENTRY 62
+#define SLAPI_ADD_PARENT_UNIQUEID 63
+#define SLAPI_ADD_EXISTING_UNIQUEID_ENTRY 64
+
+/* bind arguments */
+#define SLAPI_BIND_TARGET SLAPI_TARGET_DN
+#define SLAPI_BIND_METHOD 70
+#define SLAPI_BIND_CREDENTIALS 71 /* v3 only */
+#define SLAPI_BIND_SASLMECHANISM 72 /* v3 only */
+/* bind return values */
+#define SLAPI_BIND_RET_SASLCREDS 73 /* v3 only */
+
+/* compare arguments */
+#define SLAPI_COMPARE_TARGET SLAPI_TARGET_DN
+#define SLAPI_COMPARE_TYPE 80
+#define SLAPI_COMPARE_VALUE 81
+
+/* delete arguments */
+#define SLAPI_DELETE_TARGET SLAPI_TARGET_DN
+#define SLAPI_DELETE_EXISTING_ENTRY SLAPI_ADD_EXISTING_DN_ENTRY
+#define SLAPI_DELETE_GLUE_PARENT_ENTRY SLAPI_ADD_PARENT_ENTRY
+
+/* modify arguments */
+#define SLAPI_MODIFY_TARGET SLAPI_TARGET_DN
+#define SLAPI_MODIFY_MODS 90
+#define SLAPI_MODIFY_EXISTING_ENTRY SLAPI_ADD_EXISTING_DN_ENTRY
+
+/* modrdn arguments */
+#define SLAPI_MODRDN_TARGET SLAPI_TARGET_DN
+#define SLAPI_MODRDN_NEWRDN 100
+#define SLAPI_MODRDN_DELOLDRDN 101
+#define SLAPI_MODRDN_NEWSUPERIOR 102 /* v3 only */
+#define SLAPI_MODRDN_EXISTING_ENTRY SLAPI_ADD_EXISTING_DN_ENTRY
+#define SLAPI_MODRDN_PARENT_ENTRY 104
+#define SLAPI_MODRDN_NEWPARENT_ENTRY 105
+#define SLAPI_MODRDN_TARGET_ENTRY 106
+#define SLAPI_MODRDN_NEWSUPERIOR_ADDRESS 107
+
+/*
+ * unnormalized dn argument (useful for MOD, MODRDN and DEL operations to carry
+ * the original non-escaped dn as introduced by the client application)
+ */
+#define SLAPI_ORIGINAL_TARGET_DN 109
+#define SLAPI_ORIGINAL_TARGET SLAPI_ORIGINAL_TARGET_DN
+
+/* search arguments */
+#define SLAPI_SEARCH_TARGET SLAPI_TARGET_DN
+#define SLAPI_SEARCH_SCOPE 110
+#define SLAPI_SEARCH_DEREF 111
+#define SLAPI_SEARCH_SIZELIMIT 112
+#define SLAPI_SEARCH_TIMELIMIT 113
+#define SLAPI_SEARCH_FILTER 114
+#define SLAPI_SEARCH_STRFILTER 115
+#define SLAPI_SEARCH_ATTRS 116
+#define SLAPI_SEARCH_ATTRSONLY 117
+#define SLAPI_SEARCH_IS_AND 118
+
+/* abandon arguments */
+#define SLAPI_ABANDON_MSGID 120
+
+/* seq access arguments */
+#define SLAPI_SEQ_TYPE 150
+#define SLAPI_SEQ_ATTRNAME 151
+#define SLAPI_SEQ_VAL 152
+
+/* extended operation arguments */
+#define SLAPI_EXT_OP_REQ_OID 160 /* v3 only */
+#define SLAPI_EXT_OP_REQ_VALUE 161 /* v3 only */
+/* extended operation return values */
+#define SLAPI_EXT_OP_RET_OID 162 /* v3 only */
+#define SLAPI_EXT_OP_RET_VALUE 163 /* v3 only */
+
+/* extended filter arguments */
+#define SLAPI_MR_FILTER_ENTRY 170 /* v3 only */
+#define SLAPI_MR_FILTER_TYPE 171 /* v3 only */
+#define SLAPI_MR_FILTER_VALUE 172 /* v3 only */
+#define SLAPI_MR_FILTER_OID 173 /* v3 only */
+#define SLAPI_MR_FILTER_DNATTRS 174 /* v3 only */
+
+/* ldif2db arguments */
+/* ldif file to convert to db */
+#define SLAPI_LDIF2DB_FILE 180
+/* check for duplicate values or not */
+#define SLAPI_LDIF2DB_REMOVEDUPVALS 185
+/* index only this attribute from existing database */
+#define SLAPI_DB2INDEX_ATTRS 186
+/* do not generate attribute indexes */
+#define SLAPI_LDIF2DB_NOATTRINDEXES 187
+/* list if DNs to include */
+#define SLAPI_LDIF2DB_INCLUDE 188
+/* list of DNs to exclude */
+#define SLAPI_LDIF2DB_EXCLUDE 189
+/* generate uniqueid */
+#define SLAPI_LDIF2DB_GENERATE_UNIQUEID 175
+#define SLAPI_LDIF2DB_NAMESPACEID 177
+#define SLAPI_LDIF2DB_ENCRYPT 303
+#define SLAPI_DB2LDIF_DECRYPT 304
+/* uniqueid generation options */
+#define SLAPI_UNIQUEID_GENERATE_NONE 0 /* do not generate */
+#define SLAPI_UNIQUEID_GENERATE_TIME_BASED 1 /* generate time based id */
+#define SLAPI_UNIQUEID_GENERATE_NAME_BASED 2 /* generate name based id */
+
+/* db2ldif arguments */
+/* print keys or not in ldif */
+#define SLAPI_DB2LDIF_PRINTKEY 183
+/* filename to export */
+#define SLAPI_DB2LDIF_FILE 184
+/* dump uniqueid */
+#define SLAPI_DB2LDIF_DUMP_UNIQUEID 176
+#define SLAPI_DB2LDIF_SERVER_RUNNING 197
+
+/* db2ldif/ldif2db/bak2db/db2bak arguments */
+#define SLAPI_BACKEND_INSTANCE_NAME 178
+#define SLAPI_BACKEND_TASK 179
+#define SLAPI_TASK_FLAGS 181
+
+/* bulk import (online wire import) */
+#define SLAPI_BULK_IMPORT_ENTRY 182
+#define SLAPI_BULK_IMPORT_STATE 192
+/* the actual states (these are not pblock args) */
+#define SLAPI_BI_STATE_START 1
+#define SLAPI_BI_STATE_DONE 2
+#define SLAPI_BI_STATE_ADD 3
+/* possible error codes from a bulk import */
+#define SLAPI_BI_ERR_BUSY -23 /* backend is busy; try later */
+
+/* transaction arguments */
+#define SLAPI_PARENT_TXN 190
+#define SLAPI_TXN 191
+
+/*
+ * The following are used to pass information back and forth
+ * between the front end and the back end. The backend
+ * creates a search result set as an opaque structure and
+ * passes a reference to this back to the front end. The
+ * front end uses the backend's iterator entry point to
+ * step through the results. The entry, nentries, and
+ * referrals options, below, are set/read by both the
+ * front end and back end while stepping through the
+ * search results.
+ */
+/* Search result set */
+#define SLAPI_SEARCH_RESULT_SET 193
+/* Search result - next entry returned from search result set */
+#define SLAPI_SEARCH_RESULT_ENTRY 194
+#define SLAPI_SEARCH_RESULT_ENTRY_EXT 1944
+/* Number of entries returned from search */
+#define SLAPI_NENTRIES 195
+/* Any referrals encountered during the search */
+#define SLAPI_SEARCH_REFERRALS 196
+
+#define SLAPI_RESULT_CODE 881
+#define SLAPI_RESULT_TEXT 882
+#define SLAPI_RESULT_MATCHED 883
+
+#define SLAPI_PB_RESULT_TEXT 885
+
+/* Size of the database, in kilobytes */
+#define SLAPI_DBSIZE 199
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SLAPIPLUGIN */
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
new file mode 100644
index 00000000..506ab38d
--- /dev/null
+++ b/ldap/servers/slapd/slapi-private.h
@@ -0,0 +1,1212 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* slapi-private.h - external header file for some special plugins */
+
+#ifndef _SLAPISTATE
+#define _SLAPISTATE
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <time.h> /* for time_t */
+#include "nspr.h"
+#include "slapi-plugin.h"
+/*
+ * XXXmcs: we can stop including slapi-plugin-compat4.h once we stop using
+ * deprecated functions internally.
+ */
+#include "slapi-plugin-compat4.h"
+
+/*
+ * server shutdown status
+ */
+#define SLAPI_SHUTDOWN_SIGNAL 1
+#define SLAPI_SHUTDOWN_DISKFULL 2
+#define SLAPI_SHUTDOWN_EXIT 3
+
+/* filter */
+#define SLAPI_FILTER_LDAPSUBENTRY 1
+#define SLAPI_FILTER_TOMBSTONE 2
+#define SLAPI_ENTRY_LDAPSUBENTRY 2
+
+/*
+ Optimized filter path. For example the following code was lifted from int.c (syntaxes plugin):
+
+ if(ftype == LDAP_FILTER_EQUALITY_FAST) {
+ tmp=(char *)slapi_ch_calloc(1,(sizeof(Slapi_Value)+sizeof(struct berval)+len+1));
+ tmpval=(Slapi_Value *)tmp;
+ tmpbv=(struct berval *)(tmp + sizeof(Slapi_Value));
+ tmpbv->bv_val=(char *)tmp + sizeof(Slapi_Value) + (sizeof(struct berval));
+ tmpbv->bv_len=len;
+ tmpval->bvp=tmpbv;
+ b = (unsigned char *)&num;
+ memcpy(tmpbv->bv_val,b,len);
+ (*ivals)=(Slapi_Value **)tmpval;
+ }
+
+ The following diagram helps explain the strategy.
+
+ +---------------------------------------------------------------+
+ | Single contiguous allocated block |
+ +------------------------+------------------------+-------------+
+ | Slapi_Value | struct berval | octetstring |
+ +----------------+-------+------------------------+-------------+
+ | struct berval* | ... | ... | char *bv_val | <value> |
+ | v | | | v | |
+ +-------+--------+-------+---------+------+-------+-------------+
+ | ^ | ^
+ |_________________| |________|
+
+ The goal is to malloc one large chunk of memory up front and then manipulate the pointers to point
+ into this chunk. We then can free the whole block at once by calling a single slapi_ch_free (see filterindex.c).
+
+ */
+#define LDAP_FILTER_EQUALITY_FAST 0xaaL
+/*
+ * Slapi_Mods and Slapi_Mod base structures.
+ * Ideally, these would be moved to modutil.c and the structures would be
+ * completely opaque to users of the slapi_mods_...() API. But today some
+ * plugins such as replication use these directly for efficiency reasons.
+ */
+typedef struct slapi_mods
+{
+ LDAPMod **mods;
+ int num_elements;
+ int num_mods;
+ int iterator;
+ int free_mods; /* flag to indicate that the mods were dynamically allocated and needs to be freed */
+}slapi_mods;
+
+typedef struct slapi_mod
+{
+ LDAPMod *mod;
+ int num_elements;
+ int num_values;
+ int iterator;
+ int free_mod; /* flag to inidicate that the mod was dynamically allocated and needs to be freed */
+}slapi_mod;
+
+void slapi_ch_free_ref(void *ptr);
+
+/*
+ * file I/O
+ */
+PRInt32 slapi_read_buffer( PRFileDesc *fd, void *buf, PRInt32 amount );
+PRInt32 slapi_write_buffer( PRFileDesc *fd, void *buf, PRInt32 amount );
+/* rename a file, overwriting the destfilename if it exists */
+int slapi_destructive_rename( const char *srcfilename,
+ const char *destfilename );
+/* make a copy of a file */
+int slapi_copy( const char *srcfilename, const char *destfile );
+
+/* CSN */
+
+typedef struct csn CSN;
+typedef unsigned char CSNType;
+typedef struct csnset_node CSNSet;
+
+#define _CSN_TSTAMP_STRSIZE 8
+#define _CSN_SEQNUM_STRSIZE 4
+#define _CSN_REPLID_STRSIZE 4
+#define _CSN_SUBSEQNUM_STRSIZE 4
+#define _CSN_VALIDCSN_STRLEN (_CSN_TSTAMP_STRSIZE + _CSN_SEQNUM_STRSIZE + \
+ _CSN_REPLID_STRSIZE + _CSN_SUBSEQNUM_STRSIZE)
+#define CSN_STRSIZE (_CSN_VALIDCSN_STRLEN + 1)
+
+#define CSN_TYPE_UNKNOWN 0x00
+#define CSN_TYPE_NONE 0x01
+#define CSN_TYPE_ATTRIBUTE_DELETED 0x03
+#define CSN_TYPE_VALUE_UPDATED 0x04
+#define CSN_TYPE_VALUE_DELETED 0x05
+#define CSN_TYPE_VALUE_DISTINGUISHED 0x06
+
+#define VALUE_NOTFOUND 1
+#define VALUE_PRESENT 2
+#define VALUE_DELETED 3
+
+#define ATTRIBUTE_NOTFOUND 1
+#define ATTRIBUTE_PRESENT 2
+#define ATTRIBUTE_DELETED 3
+
+/*
+ * csn.c
+ */
+typedef PRUint16 ReplicaId;
+/* max 2 byte unsigned int value */
+#define MAX_REPLICA_ID 65535
+/* we will use this value for the replica ID of read only replicas */
+#define READ_ONLY_REPLICA_ID MAX_REPLICA_ID
+CSN *csn_new();
+CSN *csn_new_by_string(const char *s);
+void csn_init_by_csn(CSN *csn1,const CSN *csn2);
+void csn_init_by_string(CSN *csn, const char *s);
+CSN *csn_dup(const CSN *csn);
+void csn_free(CSN **csn);
+void csn_set_replicaid(CSN *csn, ReplicaId rid);
+void csn_set_time(CSN *csn, time_t csntime);
+void csn_set_seqnum(CSN *csn, PRUint16 seqnum);
+ReplicaId csn_get_replicaid(const CSN *csn);
+time_t csn_get_time(const CSN *csn);
+PRUint16 csn_get_seqnum(const CSN *csn);
+char *csn_as_string(const CSN *csn, PRBool replicaIdOrder, char *ss); /* WARNING: ss must be CSN_STRSIZE bytes, or NULL. */
+int csn_compare(const CSN *csn1, const CSN *csn2);
+time_t csn_time_difference(const CSN *csn1, const CSN *csn2);
+size_t csn_string_size();
+char *csn_as_attr_option_string(CSNType t,const CSN *csn,char *ss);
+const CSN *csn_max(const CSN *csn1,const CSN *csn2);
+/* this function allows to expand a csn into a set of csns.
+ The sequence is derived by adding a sequence number to the base csn
+ passed to it. This is useful when a single client operation needs to be
+ expanded into multiple operations. For instance, subtree move operation
+ is split into a sequence of adds and deletes with each add and delete assigned
+ a csn from the set.*/
+int csn_increment_subsequence (CSN *csn);
+
+/*
+ * csnset.c
+ */
+void csnset_add_csn(CSNSet **csnset, CSNType t, const CSN *csn);
+void csnset_insert_csn(CSNSet **csnset, CSNType t, const CSN *csn);
+void csnset_update_csn(CSNSet **csnset, CSNType t, const CSN *csn);
+void csnset_free(CSNSet **csnset);
+const CSN *csnset_get_csn_of_type(const CSNSet *csnset, CSNType t);
+void csnset_purge(CSNSet **csnset, const CSN *csnUpTo);
+size_t csnset_string_size(CSNSet *csnset);
+size_t csnset_size(CSNSet *csnset);
+CSNSet *csnset_dup(const CSNSet *csnset);
+void csnset_as_string(const CSNSet *csnset,char *s);
+void csnset_remove_csn(CSNSet **csnset, CSNType t);
+const CSN *csnset_get_last_csn(const CSNSet *csnset);
+int csnset_contains(const CSNSet *csnset, const CSN *csn);
+const CSN *csnset_get_previous_csn(const CSNSet *csnset, const CSN *csn);
+void* csnset_get_first_csn (const CSNSet *csnset, CSN **csn, CSNType *t);
+void* csnset_get_next_csn (const CSNSet *csnset, void *cookie, CSN **csn, CSNType *t);
+
+/*
+ * csngen.c
+ */
+
+/* error codes returned from CSN generation routines */
+enum {
+ CSN_SUCCESS = 0,
+ CSN_MEMORY_ERROR, /* memory allocation failed */
+ CSN_LIMIT_EXCEEDED, /* timestamp is way out of sync */
+ CSN_INVALID_PARAMETER, /* invalid function argument */
+ CSN_INVALID_FORMAT, /* invalid state format */
+ CSN_LDAP_ERROR, /* LDAP operation failed */
+ CSN_NSPR_ERROR /* NSPR API failure */
+};
+
+typedef struct csngen CSNGen;
+
+/* allocates new csn generator */
+CSNGen *csngen_new (ReplicaId rid, Slapi_Attr *state);
+/* frees csn generator data structure */
+void csngen_free (CSNGen **gen);
+/* generates new csn. If notify is non-zero, the generator calls
+ "generate" functions registered through csngen_register_callbacks call */
+int csngen_new_csn (CSNGen *gen, CSN **csn, PRBool notify);
+/* this function should be called for csns generated with non-zero notify
+ that were unused because the corresponding operation was aborted.
+ The function calls "abort" functions registered through
+ csngen_register_callbacks call */
+void csngen_abort_csn (CSNGen *gen, const CSN *csn);
+/* this function should be called when a remote CSN for the same part of
+ the dit becomes known to the server (for instance, as part of RUV during
+ replication session. In response, the generator would adjust its notion
+ of time so that it does not generate smaller csns */
+int csngen_adjust_time (CSNGen *gen, const CSN* csn);
+/* returns PR_TRUE if the csn was generated by this generator and
+ PR_FALSE otherwise. */
+PRBool csngen_is_local_csn(const CSNGen *gen, const CSN *csn);
+
+/* returns current state of the generator so that it can be saved in the DIT */
+int csngen_get_state (const CSNGen *gen, Slapi_Mod *state);
+
+typedef void (*GenCSNFn)(const CSN *newCsn, void *cbData);
+typedef void (*AbortCSNFn)(const CSN *delCsn, void *cbData);
+/* registers callbacks to be called when csn is created or aborted */
+void* csngen_register_callbacks(CSNGen *gen, GenCSNFn genFn, void *genArg,
+ AbortCSNFn abortFn, void *abortArg);
+/* unregisters callbacks registered via call to csngenRegisterCallbacks */
+void csngen_unregister_callbacks(CSNGen *gen, void *cookie);
+
+/* this functions is periodically called from daemon.c to
+ update time used by all generators */
+void csngen_update_time ();
+
+/* debugging function */
+void csngen_dump_state (const CSNGen *gen);
+
+/* this function tests csn generator */
+void csngen_test ();
+
+/*
+ * State storage management routines
+ *
+ *
+ */
+
+/*
+ * attr_value_find_wsi looks for a particular value (rather, the berval
+ * part of the slapi_value v) and returns it in "value". The function
+ * returns VALUE_PRESENT, VALUE_DELETED, or VALUE_NOTFOUND.
+ */
+int attr_value_find_wsi(Slapi_Attr *a, const struct berval *bval, Slapi_Value **value);
+
+/*
+ * entry_attr_find_wsi takes an entry and a type and looks for the
+ * attribute. If the attribute is found on the list of existing attributes,
+ * it is returned in "a" and the function returns ATTRIBUTE_PRESENT. If the attribute is
+ * found on the deleted list, "a" is set and the function returns ATTRIBUTE_DELETED.
+ * If the attribute is not found on either list, the function returns ATTRIBUTE_NOTFOUND.
+ */
+int entry_attr_find_wsi(Slapi_Entry *e, const char *type, Slapi_Attr **a);
+
+/*
+ * entry_add_present_attribute_wsi adds an attribute to the entry.
+ */
+int entry_add_present_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a);
+
+/*
+ * entry_add_deleted_attribute_wsi adds a deleted attribute to the entry.
+ */
+int entry_add_deleted_attribute_wsi(Slapi_Entry *e, Slapi_Attr *a);
+
+/*
+ * slapi_entry_apply_mods_wsi is similar to slapi_entry_apply_mods. It also
+ * handles the state storage information. "csn" is the CSN associated with
+ * this modify operation.
+ */
+int entry_apply_mods_wsi(Slapi_Entry *e, Slapi_Mods *smods, const CSN *csn, int urp);
+int entry_first_deleted_attribute( const Slapi_Entry *e, Slapi_Attr **a);
+int entry_next_deleted_attribute( const Slapi_Entry *e, Slapi_Attr **a);
+
+/* entry.c */
+int entry_apply_mods( Slapi_Entry *e, LDAPMod **mods );
+
+int slapi_entries_diff(Slapi_Entry **old_entries, Slapi_Entry **new_entries, int testall, const char *logging_prestr, const int force_update, void *plg_id);
+
+/* entrywsi.c */
+CSN* entry_assign_operation_csn ( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *parententry );
+const CSN *entry_get_maxcsn ( const Slapi_Entry *entry );
+void entry_set_maxcsn ( Slapi_Entry *entry, const CSN *csn );
+const CSN *entry_get_dncsn(const Slapi_Entry *entry);
+const CSNSet *entry_get_dncsnset(const Slapi_Entry *entry);
+int entry_add_dncsn(Slapi_Entry *entry, const CSN *csn);
+int entry_set_csn(Slapi_Entry *entry, const CSN *csn);
+void entry_purge_state_information(Slapi_Entry *entry, const CSN *csnUpto);
+void entry_add_rdn_csn(Slapi_Entry *e, const CSN *csn);
+/* this adds a csn to the entry's e_dncsnset but makes sure the set is in increasing csn order */
+#define ENTRY_DNCSN_INCREASING 0x1 /* for flags below */
+int entry_add_dncsn_ext(Slapi_Entry *entry, const CSN *csn, PRUint32 flags);
+
+/* attr.c */
+Slapi_Attr *slapi_attr_init_locking_optional(Slapi_Attr *a, const char *type, PRBool use_lock, PRBool ref_count);
+int attr_set_csn( Slapi_Attr *a, const CSN *csn);
+int attr_set_deletion_csn( Slapi_Attr *a, const CSN *csn);
+const CSN *attr_get_deletion_csn(const Slapi_Attr *a);
+int attr_first_deleted_value( Slapi_Attr *a, Slapi_Value **v );
+int attr_next_deleted_value( Slapi_Attr *a, int hint, Slapi_Value **v);
+void attr_purge_state_information(Slapi_Entry *entry, Slapi_Attr *attr, const CSN *csnUpto);
+Slapi_Value **attr_get_present_values(const Slapi_Attr *a);
+int attr_add_deleted_value(Slapi_Attr *a, const Slapi_Value *v);
+
+/* value.c */
+Slapi_Value *value_new(const struct berval *bval, CSNType t, const CSN *csn);
+Slapi_Value *value_init(Slapi_Value *v, const struct berval *bval, CSNType t, const CSN *csn);
+void value_done(Slapi_Value *v);
+Slapi_Value *value_update_csn( Slapi_Value *value, CSNType t, const CSN *csn);
+Slapi_Value *value_add_csn( Slapi_Value *value, CSNType t, const CSN *csn);
+const CSN *value_get_csn( const Slapi_Value *value, CSNType t );
+const CSNSet *value_get_csnset ( const Slapi_Value *value);
+Slapi_Value *value_remove_csn( Slapi_Value *value, CSNType t);
+int value_contains_csn( const Slapi_Value *value, CSN *csn);
+
+/* dn.c */
+/* this functions should only be used for dns allocated on the stack */
+Slapi_DN *slapi_sdn_init(Slapi_DN *sdn);
+Slapi_DN *slapi_sdn_init_dn_byref(Slapi_DN *sdn,const char *dn);
+Slapi_DN *slapi_sdn_init_dn_byval(Slapi_DN *sdn,const char *dn);
+Slapi_DN *slapi_sdn_init_dn_passin(Slapi_DN *sdn,const char *dn);
+Slapi_DN *slapi_sdn_init_ndn_byref(Slapi_DN *sdn,const char *dn);
+Slapi_DN *slapi_sdn_init_ndn_byval(Slapi_DN *sdn,const char *dn);
+Slapi_DN *slapi_sdn_init_dn_ndn_byref(Slapi_DN *sdn,const char *dn);
+
+/* filter.c */
+int filter_flag_is_set(const Slapi_Filter *f,unsigned char flag);
+char *slapi_filter_to_string(const Slapi_Filter *f, char *buffer, size_t bufsize);
+
+/* operation.c */
+
+#define OP_FLAG_PS 0x0001
+#define OP_FLAG_PS_CHANGESONLY 0x0002
+#define OP_FLAG_GET_EFFECTIVE_RIGHTS 0x0004
+#define OP_FLAG_REPLICATED 0x0008 /* A Replicated Operation */
+#define OP_FLAG_REPL_FIXUP 0x0010 /* A Fixup Operation, generated as a consequence of a Replicated Operation. */
+#define OP_FLAG_INTERNAL 0x0020 /* An operation generated by the core server or a plugin. */
+#define OP_FLAG_ACTION_LOG_ACCESS 0x0040
+#define OP_FLAG_ACTION_LOG_AUDIT 0x0080
+#define OP_FLAG_ACTION_SCHEMA_CHECK 0x0100
+#define OP_FLAG_ACTION_LOG_CHANGES 0x0200
+#define OP_FLAG_ACTION_INVOKE_FOR_REPLOP 0x0400
+#define OP_FLAG_NEVER_CHAIN SLAPI_OP_FLAG_NEVER_CHAIN /* 0x0800 */
+#define OP_FLAG_TOMBSTONE_ENTRY 0x1000
+#define OP_FLAG_RESURECT_ENTRY 0x2000
+#define OP_FLAG_LEGACY_REPLICATION_DN 0x4000 /* Operation done by legacy replication DN */
+#define OP_FLAG_ACTION_NOLOG 0x8000 /* Do not log the entry in audit log or change log */
+
+CSN *operation_get_csn(Slapi_Operation *op);
+void operation_set_csn(Slapi_Operation *op,CSN *csn);
+void operation_set_flag(Slapi_Operation *op,int flag);
+void operation_clear_flag(Slapi_Operation *op,int flag);
+int operation_is_flag_set(Slapi_Operation *op,int flag);
+unsigned long operation_get_type(Slapi_Operation *op);
+
+/*
+ * From ldap.h
+ * #define LDAP_MOD_ADD 0x00
+ * #define LDAP_MOD_DELETE 0x01
+ * #define LDAP_MOD_REPLACE 0x02
+ */
+#define LDAP_MOD_IGNORE 0x09
+
+
+/* dl.c */
+typedef struct datalist DataList;
+
+typedef int (*CMPFN) (const void *el1, const void *el2);
+typedef void (*FREEFN) (void **);
+DataList* dl_new ();
+void dl_free (DataList **dl);
+void dl_init (DataList *dl, int init_alloc);
+void dl_cleanup (DataList *dl, FREEFN freefn);
+void dl_add (DataList *dl, void *element);
+void dl_add_index(DataList *dl, void *element, int index);
+void *dl_replace(const DataList *dl, const void *elementOld, void *elementNew, CMPFN cmpfn, FREEFN freefn);
+void *dl_get_first (const DataList *dl, int *cookie);
+void *dl_get_next (const DataList *dl, int *cookie);
+void *dl_get (const DataList *dl, const void *element, CMPFN cmpfn);
+void *dl_delete (DataList *dl, const void *element, CMPFN cmpfn, FREEFN freefn);
+int dl_get_count (const DataList *dl);
+
+struct ava {
+ char *ava_type;
+ struct berval ava_value; /* JCM SLAPI_VALUE! */
+ void *ava_private; /* data private to syntax handler */
+};
+
+typedef enum{
+ FILTER_TYPE_SUBSTRING,
+ FILTER_TYPE_AVA,
+ FILTER_TYPE_PRES
+}filter_type_t;
+
+/*
+ * vattr entry routines.
+ * vattrcache private (for the moment)
+ */
+#define SLAPI_ENTRY_VATTR_NOT_RESOLVED -1
+#define SLAPI_ENTRY_VATTR_RESOLVED_ABSENT -2
+#define SLAPI_ENTRY_VATTR_RESOLVED_EXISTS 0
+
+int slapi_entry_vattrcache_merge_sv(Slapi_Entry *e, const char *type, Slapi_ValueSet *vals);
+int slapi_entry_vattrcache_find_values_and_type_ex( const Slapi_Entry *e,
+ const char *type,
+ Slapi_ValueSet ***results,
+ char ***actual_type_name);
+SLAPI_DEPRECATED int
+slapi_entry_vattrcache_find_values_and_type( const Slapi_Entry *e,
+ const char *type,
+ Slapi_ValueSet **results,
+ char **actual_type_name);
+int slapi_entry_vattrcache_findAndTest(const Slapi_Entry *e, const char *type,
+ Slapi_Filter *f,
+ filter_type_t filter_type,
+ int *rc);
+
+int slapi_vattrcache_iscacheable( const char * type );
+void slapi_vattrcache_cache_all();
+void slapi_vattrcache_cache_none();
+
+int vattr_test_filter(/* Entry we're interested in */ Slapi_Entry *e,
+ Slapi_Filter *f,
+ filter_type_t filter_type,
+ char *type);
+
+/* filter routines */
+
+int test_substring_filter( Slapi_PBlock *pb, Slapi_Entry *e,
+ struct slapi_filter *f,
+ int verify_access,int only_check_access, int *access_check_done);
+int test_ava_filter( Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Attr *a,
+ struct ava *ava, int ftype, int verify_access,
+ int only_check_access, int *access_check_done);
+int test_presence_filter( Slapi_PBlock *pb, Slapi_Entry *e, char *type,
+ int verify_access, int only_check_access, int *access_check_done);
+
+/* this structure allows to address entry by dn or uniqueid */
+typedef struct entry_address
+{
+ char *dn;
+ char *udn; /* unnormalized dn */
+ char *uniqueid;
+}entry_address;
+
+/*
+ * LDAP Operation input parameters.
+ */
+typedef struct slapi_operation_parameters
+{
+ unsigned long operation_type; /* SLAPI_OPERATION_ADD, SLAPI_OPERATION_MODIFY ... */
+ entry_address target_address; /* address of target entry */
+ CSN *csn; /* The Change Sequence Number assigned to this operation. */
+
+ LDAPControl **request_controls;/* array v3 LDAPMessage controls */
+
+ union
+ {
+ struct add_parameters
+ {
+ struct slapi_entry *target_entry;
+ char *parentuniqueid;
+ } p_add;
+
+ struct bind_parameters
+ {
+ int bind_method;
+ struct berval *bind_creds;
+ char *bind_saslmechanism; /* v3 sasl mechanism name */
+ struct berval *bind_ret_saslcreds; /* v3 serverSaslCreds */
+ } p_bind;
+
+ struct compare_parameters
+ {
+ struct ava compare_ava;
+ } p_compare;
+
+ struct modify_parameters
+ {
+ LDAPMod **modify_mods;
+ } p_modify;
+
+ struct modrdn_parameters
+ {
+ char *modrdn_newrdn;
+ int modrdn_deloldrdn;
+ entry_address modrdn_newsuperior_address; /* address of the superior entry */
+ LDAPMod **modrdn_mods; /* modifiers name and timestamp */
+ } p_modrdn;
+
+ struct search_parameters
+ {
+ int search_scope;
+ int search_deref;
+ int search_sizelimit;
+ int search_timelimit;
+ struct slapi_filter *search_filter;
+ char *search_strfilter;
+ char **search_attrs;
+ int search_attrsonly;
+ int search_is_and;
+ } p_search;
+
+ struct abandon_parameters
+ {
+ int abandon_targetmsgid;
+ } p_abandon;
+
+ struct extended_parameters
+ {
+ char *exop_oid;
+ struct berval *exop_value;
+ } p_extended;
+ } p;
+} slapi_operation_parameters;
+
+struct slapi_operation_parameters *operation_parameters_new();
+struct slapi_operation_parameters *operation_parameters_dup(struct slapi_operation_parameters *sop);
+void operation_parameters_done(struct slapi_operation_parameters *sop);
+void operation_parameters_free(struct slapi_operation_parameters **sop);
+
+
+/*
+ * errormap.c
+ */
+char *slapd_pr_strerror( const PRErrorCode prerrno );
+const char *slapd_system_strerror( const int syserrno );
+const char *slapd_versatile_strerror( const PRErrorCode prerrno );
+
+
+/*
+ * localhost.c
+ */
+char* get_localhost_DNS();
+/* Return the fully-qualified DNS name of this machine.
+ The caller should _not_ free this pointer. */
+char* get_localhost_DN();
+
+/*
+ * Reference-counted objects
+ */
+typedef void (*FNFree) (void **);
+typedef struct object Object;
+Object *object_new(void *user_data, FNFree destructor);
+void object_acquire(Object *o);
+void object_release(Object *o);
+void *object_get_data(Object *o);
+
+/* Sets of reference-counted objects */
+#define OBJSET_SUCCESS 0
+#define OBJSET_ALREADY_EXISTS 1
+#define OBJSET_NO_SUCH_OBJECT 2
+typedef int (*CMPFn) (Object *set, const void *name);
+typedef struct objset Objset;
+Objset *objset_new(FNFree objset_destructor);
+void objset_delete(Objset **set);
+int objset_add_obj(Objset *set, Object *object);
+Object *objset_find(Objset *set, CMPFn compare_fn, const void *name);
+int objset_remove_obj(Objset *set, Object *object);
+Object *objset_first_obj(Objset *set);
+Object *objset_next_obj(Objset *set, Object *previous);
+int objset_is_empty(Objset *set);
+int objset_size(Objset *set);
+
+/* backend management */
+typedef struct index_config
+{
+ char *attr_name; /* attr name: dn, cn, etc. */
+ char *index_type; /* space terminated list of indexes;
+ possible types: "eq" "sub" "pres" "approx" */
+ int system; /* marks this index as system */
+}IndexConfig;
+
+int be_create_instance (const char *type, /* for now, must be "ldbm" */
+ const char *name, /* gloably unique instance name */
+ const char *root, /* backend root, i.e. o=mcom.com */
+ int cache_size, /* cache size in bytes; 0 for default */
+ IndexConfig *indexes, /* indexes in addition to standard */
+ int index_count, /* number of elements in indexes */
+ void *plugin_identity /* identity of the calling plugin */
+ );
+int be_remove_instance (const char *type, /* for now, must be "ldbm" */
+ const char *name, /* gloably unique instance name */
+ void *plugin_identity /* identity of the calling plugin */
+ );
+
+void be_set_sizelimit(Slapi_Backend * be, int sizelimit);
+void be_set_timelimit(Slapi_Backend * be, int timelimit);
+
+/* used by mapping tree to delay sending of result code when several
+ * backend are parsed
+ */
+void slapi_set_ldap_result( Slapi_PBlock *pb, int err, char *matched,
+ char *text, int nentries, struct berval **urls );
+void slapi_send_ldap_result_from_pb( Slapi_PBlock *pb);
+
+/* mapping tree utility functions */
+typedef struct mt_node mapping_tree_node;
+mapping_tree_node *slapi_get_mapping_tree_node_by_dn(const Slapi_DN *dn);
+char* slapi_get_mapping_tree_node_configdn(const Slapi_DN *root);
+const Slapi_DN* slapi_get_mapping_tree_node_root(const mapping_tree_node *node);
+const char* slapi_get_mapping_tree_config_root ();
+Slapi_Backend *slapi_mapping_tree_find_backend_for_sdn(Slapi_DN *sdn);
+/* possible flags to check for */
+#define SLAPI_MTN_LOCAL 0x1
+#define SLAPI_MTN_PRIVATE 0x2
+#define SLAPI_MTN_READONLY 0x4
+PRBool slapi_mapping_tree_node_is_set (const mapping_tree_node *node,
+ PRUint32 flag);
+Slapi_DN* slapi_mtn_get_dn(mapping_tree_node *node);
+int slapi_mapping_tree_select_and_check(Slapi_PBlock *pb,char *newdn,
+ Slapi_Backend **be, Slapi_Entry **referral, char *errorbuf);
+int slapi_mapping_tree_select_all(Slapi_PBlock *pb, Slapi_Backend **be_list,
+ Slapi_Entry **referral_list, char *errorbuf);
+void slapi_mapping_tree_free_all(Slapi_Backend **be_list,
+ Slapi_Entry **referral_list);
+
+/* Mapping Tree */
+int slapi_mapping_tree_select(Slapi_PBlock *pb, Slapi_Backend **be, Slapi_Entry **referral, char *error_string);
+char ** slapi_mtn_get_referral(const Slapi_DN *sdn);
+int slapi_mtn_set_referral(const Slapi_DN *sdn, char ** referral);
+int slapi_mtn_set_state(const Slapi_DN *sdn, char *state);
+char * slapi_mtn_get_state(const Slapi_DN *sdn);
+void slapi_mtn_be_set_readonly(Slapi_Backend *be, int readonly);
+void slapi_mtn_be_stopping(Slapi_Backend *be);
+void slapi_mtn_be_started(Slapi_Backend *be);
+void slapi_mtn_be_disable(Slapi_Backend *be);
+void slapi_mtn_be_enable(Slapi_Backend *be);
+const char *slapi_mtn_get_backend_name(const Slapi_DN *sdn);
+
+void slapi_be_stopping (Slapi_Backend *be);
+void slapi_be_free (Slapi_Backend **be);
+void slapi_be_Rlock (Slapi_Backend *be);
+void slapi_be_Wlock (Slapi_Backend *be);
+void slapi_be_Unlock (Slapi_Backend *be);
+
+/* components */
+struct slapi_componentid {
+ char * sci_magic;
+ const struct slapdplugin * sci_plugin;
+ char * sci_component_name;
+};
+
+struct slapi_componentid *
+generate_componentid ( struct slapdplugin * pp , char * name );
+void release_componentid ( struct slapi_componentid * id );
+struct slapi_componentid * plugin_get_default_component_id();
+
+/* interface for component mgmt */
+/* Well-known components DNs */
+/* Should be documented somehow for the chaining backend */
+
+#define COMPONENT_BASE_DN "cn=components,cn=config"
+#define COMPONENT_ROLES "cn=roles,"COMPONENT_BASE_DN
+#define COMPONENT_RESLIMIT "cn=resource limits,"COMPONENT_BASE_DN
+#define COMPONENT_PWPOLICY "cn=password policy,"COMPONENT_BASE_DN
+#define COMPONENT_CERT_AUTH "cn=certificate-based authentication,"COMPONENT_BASE_DN
+
+/* Component names for logging */
+#define SLAPI_COMPONENT_NAME_NSPR "Netscape runtime"
+#define SLAPI_COMPONENT_NAME_LDAPSDK "LDAP sdk"
+
+/* return the list of attr defined in the schema matching the attr flags */
+char ** slapi_schema_list_attribute_names(unsigned long flag);
+CSN *dup_global_schema_csn();
+
+/* misc function for the chaining backend */
+char * slapi_get_rootdn(); /* return the directory manager dn in use */
+
+/* plugin interface to bulk import */
+/* This function initiates bulk import. The pblock must contain
+ SLAPI_LDIF2DB_GENERATE_UNIQUEID -- currently always set to TIME_BASED
+ SLAPI_CONNECTION -- connection over which bulk import is coming
+ SLAPI_BACKEND -- the backend being imported
+ or
+ SLAPI_TARGET_DN that contains root of the imported area.
+ The function returns LDAP_SUCCESS or LDAP error code
+*/
+int slapi_start_bulk_import (Slapi_PBlock *pb);
+
+/* This function adds an entry to the bulk import. The pblock must contain
+ SLAPI_CONNECTION -- connection over which bulk import is coming
+ SLAPI_BACKEND -- optional backend pointer; if missing computed based on entry dn
+ The function returns LDAP_SUCCESS or LDAP error code
+*/
+int slapi_import_entry (Slapi_PBlock *pb, Slapi_Entry *e);
+
+/* This function stops bulk import. The pblock must contain
+ SLAPI_CONNECTION -- connection over which bulk import is coming
+ SLAPI_BACKEND -- the backend being imported
+ or
+ SLAPI_TARGET_DN that contains root of the imported area.
+ The function returns LDAP_SUCCESS or LDAP error code
+*/
+int slapi_stop_bulk_import (Slapi_PBlock *pb);
+
+/* allows plugins to close inbound connection */
+void slapi_disconnect_server(Slapi_Connection *conn);
+
+/* functions to look up instance names by suffixes (backend_manager.c) */
+int slapi_lookup_instance_name_by_suffixes(char **included,
+ char **excluded, char ***instances);
+int slapi_lookup_instance_name_by_suffix(char *suffix,
+ char ***suffixes, char ***instances, int isexact);
+
+/* begin and end the task subsystem */
+void task_init(void);
+void task_shutdown(void);
+
+/* for reversible encyrption */
+#define SLAPI_MB_CREDENTIALS "nsmultiplexorcredentials"
+#define SLAPI_REP_CREDENTIALS "nsds5ReplicaCredentials"
+int pw_rever_encode(Slapi_Value **vals, char * attr_name);
+int pw_rever_decode(char *cipher, char **plain, const char * attr_name);
+
+/* config routines */
+
+int slapi_config_get_readonly();
+
+/*
+ * charray.c
+ */
+void charray_add( char ***a, char *s );
+void charray_merge( char ***a, char **s, int copy_strs );
+void charray_free( char **array );
+int charray_inlist( char **a, char *s );
+int charray_utf8_inlist( char **a, char *s );
+char ** charray_dup( char **a );
+char ** str2charray( char *str, char *brkstr );
+int charray_remove(char **a,const char *s);
+char ** cool_charray_dup( char **a );
+void cool_charray_free( char **array );
+void charray_subtract( char **a, char **b, char ***c );
+int charray_get_index(char **array, char *s);
+
+
+/******************************************************************************
+ * value array routines.
+ *
+ * It is unclear if these should ever be public, but today they are used by
+ * some plugins. They would need to be renamed to have a slapi_ prefix at
+ * the very least before we make them public.
+ */
+void valuearray_add_value(Slapi_Value ***vals, const Slapi_Value *addval);
+void valuearray_add_value_fast(Slapi_Value ***vals, Slapi_Value *addval, int nvals, int *maxvals, int exact, int passin);
+void valuearray_add_valuearray( Slapi_Value ***vals, Slapi_Value **addvals, PRUint32 flags );
+void valuearray_add_valuearray_fast( Slapi_Value ***vals, Slapi_Value **addvals, int nvals, int naddvals, int *maxvals, int exact, int passin );
+
+
+/******************************************************************************
+ * Database plugin interface.
+ *
+ * Prior to the 5.0 release, this was a public interface that lived in
+ * slapi-plugin.h, so it is still a good idea to avoid making changes to it
+ * that are not backwards compatible.
+ */
+
+/* plugin type */
+#define SLAPI_PLUGIN_DATABASE 1
+
+/* database plugin functions */
+#define SLAPI_PLUGIN_DB_BIND_FN 200
+#define SLAPI_PLUGIN_DB_UNBIND_FN 201
+#define SLAPI_PLUGIN_DB_SEARCH_FN 202
+#define SLAPI_PLUGIN_DB_COMPARE_FN 203
+#define SLAPI_PLUGIN_DB_MODIFY_FN 204
+#define SLAPI_PLUGIN_DB_MODRDN_FN 205
+#define SLAPI_PLUGIN_DB_ADD_FN 206
+#define SLAPI_PLUGIN_DB_DELETE_FN 207
+#define SLAPI_PLUGIN_DB_ABANDON_FN 208
+#define SLAPI_PLUGIN_DB_CONFIG_FN 209
+#define SLAPI_PLUGIN_DB_FLUSH_FN 211
+#define SLAPI_PLUGIN_DB_SEQ_FN 213
+#define SLAPI_PLUGIN_DB_ENTRY_FN 214
+#define SLAPI_PLUGIN_DB_REFERRAL_FN 215
+#define SLAPI_PLUGIN_DB_RESULT_FN 216
+#define SLAPI_PLUGIN_DB_LDIF2DB_FN 217
+#define SLAPI_PLUGIN_DB_DB2LDIF_FN 218
+#define SLAPI_PLUGIN_DB_BEGIN_FN 219
+#define SLAPI_PLUGIN_DB_COMMIT_FN 220
+#define SLAPI_PLUGIN_DB_ABORT_FN 221
+#define SLAPI_PLUGIN_DB_ARCHIVE2DB_FN 222
+#define SLAPI_PLUGIN_DB_DB2ARCHIVE_FN 223
+#define SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_FN 224
+#define SLAPI_PLUGIN_DB_FREE_RESULT_SET_FN 225
+#define SLAPI_PLUGIN_DB_SIZE_FN 226
+#define SLAPI_PLUGIN_DB_TEST_FN 227
+#define SLAPI_PLUGIN_DB_DB2INDEX_FN 228
+#define SLAPI_PLUGIN_DB_NEXT_SEARCH_ENTRY_EXT_FN 229
+#define SLAPI_PLUGIN_DB_ENTRY_RELEASE_FN 230
+#define SLAPI_PLUGIN_DB_INIT_INSTANCE_FN 231
+#define SLAPI_PLUGIN_DB_WIRE_IMPORT_FN 234
+#if defined(UPGRADEDB)
+#define SLAPI_PLUGIN_DB_UPGRADEDB_FN 235
+#endif
+/* database plugin-specific parameters */
+#define SLAPI_PLUGIN_DB_NO_ACL 250
+#define SLAPI_PLUGIN_DB_RMDB_FN 280
+
+/**** End of database plugin interface. **************************************/
+
+
+/******************************************************************************
+ * Interface to the UniqueID generator (uniqueid.c)
+ *
+ * This could be made public someday, although it is a large interface and
+ * not all of the elements follow the SLAPI_ naming convention.
+ */
+ /* error codes */
+#define UID_UPDATE_SHUTDOWN -1 /* update state information only during server shutdown */
+#define UID_UPDATE_INTERVAL 600000 /* 10 minutes */
+
+enum {UID_SUCCESS, /* operation was successfull */
+ UID_ERROR_BASE=10,/* start of the error codes */
+ UID_BADDATA, /* invalid parameter passed to a function */
+ UID_MEMORY_ERROR, /* memory allocation failed */
+ UID_SYSTEM_ERROR, /* I/O failed (currently, further details
+ can be obtained using PR_GetError */
+ UID_TIME_ERROR, /* UUID can't be generated because system
+ time has not been update */
+ UID_ERROR_END /* end of the error codes */
+ };
+
+/* Function: slapi_uniqueIDNew
+ Description: allocates new id
+ Paramters: none
+ Return: pointer to the newly allocated id if successful
+ NULL if the system is out of memory
+ */
+Slapi_UniqueID* slapi_uniqueIDNew( void );
+
+/* Function: slapi_uniqueIDDestroy
+ Description: destroys UniqueID object and sets its pointer to NULL
+ Parameters: uId - id to destroy
+ Return: none
+ */
+void slapi_uniqueIDDestroy(Slapi_UniqueID **uId);
+
+/* Function: slapi_uniqueIDCompare
+ Description: this function compares two ids (byte by byte).
+ Parameters: uId1, uId2 - ids to compare
+ Return: -1 if uId1 < uId2
+ 0 if uId2 == uId2
+ 1 if uId2 > uId2
+ UID_BADDATA if invalid pointer passed to the function
+*/
+int slapi_uniqueIDCompare(const Slapi_UniqueID *uId1, const Slapi_UniqueID *uId2);
+
+int slapi_uniqueIDCompareString(const char *uuid1, const char *uuid2);
+
+/* Function: slapi_uniqueIDFormat
+ Description: this function converts entryId to its string representation.
+ The id format is HH-HHHHHHHH-HHHHHHHH-HHHHHHHH-HHHHHHHH
+ where H is a hex digit.
+ Parameters: uId - unique id
+ buff - buffer in which id is returned;
+ Return: UID_SUCCESS - function was successfull
+ UID_BADDATA - invalid parameter passed to the function
+*/
+int slapi_uniqueIDFormat(const Slapi_UniqueID *uId, char **buff);
+
+/* Function: slapi_uniqueIDScan
+ Description: this function converts a string buffer into uniqueID.
+ Currently, it only supports
+ HH-HHHHHHHH-HHHHHHHH-HHHHHHHH-HHHHHHHH data format.
+ Parameters: uId - unique id to be returned
+ buff - buffer with uniqueID.
+ Return: UID_SUCCESS - function was successfull
+ UID_BADDATA - null parameter(s) or bad format
+*/
+int slapi_uniqueIDScan(Slapi_UniqueID *uId, const char *buff);
+
+
+/* Function: slapi_uniqueIDIsUUID
+ Description: tests if given entry id is of UUID type
+ Parameters: uId - unique id to test
+ Return UID_SUCCESS - function was successfull
+ UID_BADDATA - invalid data passed to the function
+ */
+int slapi_uniqueIDIsUUID(const Slapi_UniqueID *uId);
+
+/* Name: slapi_uniqueIDSize
+ Description: returns size of the string version of uniqueID in bytes
+ Parameters: none
+ Return: size of the string version of uniqueID in bytes
+ */
+int slapi_uniqueIDSize( void );
+
+/* Name: slapi_uniqueIDDup
+ Description: duplicates an UniqueID object
+ Parameters: uId - id to duplicate
+ Return: duplicate of the Id
+ */
+Slapi_UniqueID* slapi_uniqueIDDup(Slapi_UniqueID *uId);
+
+/*
+ * interface to UniqueID generator - uniqueidgen.c
+ */
+
+/* Function: slapi_uniqueIDGenerate
+ Description: this function generates uniqueid in a singlethreaded
+ environment.
+ Parameters: uId - buffer to receive the ID.
+ Return: UID_SUCCESS if function succeeds;
+ UID_BADDATA if invalid pointer passed to the function;
+ UID_SYSTEM_ERROR update to persistent storage failed.
+*/
+
+int slapi_uniqueIDGenerate(Slapi_UniqueID *uId);
+
+/* Function: slapi_uniqueIDGenerateString
+ Description: this function generates uniqueid an returns it as a string
+ in a singlethreaded environment. This function returns the
+ data in the format generated by slapi_uniqueIDFormat.
+ Parameters: uId - buffer to receive the ID. Caller is responsible for
+ freeing uId buffer.
+ Return: UID_SUCCESS if function succeeds;
+ UID_BADDATA if invalid pointer passed to the function;
+ UID_MEMORY_ERROR if malloc fails;
+ UID_SYSTEM_ERROR update to persistent storage failed.
+*/
+
+int slapi_uniqueIDGenerateString(char **uId);
+
+/* Function: slapi_uniqueIDGenerateMT
+ Description: this function generates entry id in a multithreaded
+ environment. Used in conjunction with
+ uniqueIDUpdateState function.
+ Parameters: uId - structure in which new id will be returned.
+ Return: UID_SUCCESS if function succeeds;
+ UID_BADDATA if invalid pointer passed to the function;
+ UID_TIME_ERROR uniqueIDUpdateState must be called
+ before the id can be generated.
+*/
+
+int slapi_uniqueIDGenerateMT(Slapi_UniqueID *uId);
+
+/* Function: slapi_uniqueIDGenerateMTString
+ Description: this function generates uniqueid and returns it as a
+ string in a multithreaded environment. Used in conjunction
+ with uniqueIDUpdateState function.
+ Parameters: uId - buffer in which new id will be returned. Caller is
+ responsible for freeing uId buffer.
+ Return: UID_SUCCESS if function succeeds;
+ UID_BADDATA if invalid pointer passed to the function;
+ UID_MEMORY_ERROR if malloc fails;
+ UID_TIME_ERROR uniqueIDUpdateState must be called
+ before the id can be generated.
+*/
+
+int slapi_uniqueIDGenerateMTString(char **uId);
+
+/* Function: slapi_uniqueIDGenerateFromName
+ Description: this function generates an id from a name. See uuid
+ draft for more details. This function can be used in
+ both a singlethreaded and a multithreaded environments.
+ Parameters: uId - generated id
+ uIDBase - uid used for generation to distinguish among
+ different name spaces
+ name - buffer containing name from which to generate the id
+ namelen - length of the name buffer
+ Return: UID_SUCCESS if function succeeds
+ UID_BADDATA if invalid argument is passed to the
+ function.
+*/
+
+int slapi_uniqueIDGenerateFromName(Slapi_UniqueID *uId,
+ const Slapi_UniqueID *uIdBase,
+ const void *name, int namelen);
+
+/* Function: slapi_uniqueIDGenerateFromName
+ Description: this function generates an id from a name and returns
+ it in the string format. See uuid draft for more
+ details. This function can be used in both a
+ singlethreaded and a multithreaded environments.
+ Parameters: uId - generated id in string form
+ uIDBase - uid used for generation to distinguish among
+ different name spaces in string form. NULL means to use
+ empty id as the base.
+ name - buffer containing name from which to generate the id
+ namelen - length of the name buffer
+ Return: UID_SUCCESS if function succeeds
+ UID_BADDATA if invalid argument is passed to the
+ function.
+*/
+
+int slapi_uniqueIDGenerateFromNameString(char **uId,
+ const char *uIdBase,
+ const void *name, int namelen);
+
+/**** End of UniqueID generator interface. ***********************************/
+
+
+/*****************************************************************************
+ * JCMREPL - Added for the replication plugin.
+ */
+
+/* Front end configuration */
+
+typedef int (*dseCallbackFn)(Slapi_PBlock *, Slapi_Entry *, Slapi_Entry *,
+ int *, char*, void *);
+
+/*
+ * Note: DSE callback functions MUST return one of these three values:
+ *
+ * SLAPI_DSE_CALLBACK_OK -- no errors occurred; apply changes.
+ * SLAPI_DSE_CALLBACK_ERROR -- an error occurred; don't apply changes.
+ * SLAPI_DSE_CALLBACK_DO_NOT_APPLY -- no error, but do not apply changes.
+ *
+ * SLAPI_DSE_CALLBACK_DO_NOT_APPLY should only be returned by modify
+ * callbacks (i.e., those registered with operation==SLAPI_OPERATION_MODIFY).
+ * A return value of SLAPI_DSE_CALLBACK_DO_NOT_APPLY is treated the same as
+ * SLAPI_DSE_CALLBACK_ERROR for all other operations.
+ */
+#define SLAPI_DSE_CALLBACK_OK (1)
+#define SLAPI_DSE_CALLBACK_ERROR (-1)
+#define SLAPI_DSE_CALLBACK_DO_NOT_APPLY (0)
+
+/*
+ * Flags for slapi_config_register_callback() and
+ * slapi_config_remove_callback()
+ */
+#define DSE_FLAG_PREOP 0x0001
+#define DSE_FLAG_POSTOP 0x0002
+
+int slapi_config_register_callback(int operation, int flags, const char *base, int scope, const char *filter, dseCallbackFn fn, void *fn_arg);
+int slapi_config_remove_callback(int operation, int flags, const char *base, int scope, const char *filter, dseCallbackFn fn);
+int config_is_slapd_lite( void );
+
+#define SLAPI_RTN_BIT_FETCH_EXISTING_DN_ENTRY 0
+#define SLAPI_RTN_BIT_FETCH_PARENT_ENTRY 1
+#define SLAPI_RTN_BIT_FETCH_NEWPARENT_ENTRY 2
+#define SLAPI_RTN_BIT_FETCH_TARGET_ENTRY 3
+#define SLAPI_RTN_BIT_FETCH_EXISTING_UNIQUEID_ENTRY 4
+
+/* Attribute use to mark entries that had a replication conflict on the DN */
+#define ATTR_NSDS5_REPLCONFLICT "nsds5ReplConflict"
+
+/* Time */
+#include <time.h> /* difftime, localtime_r, mktime */
+/* Duplicated: time_t read_localTime (struct berval* from); */
+time_t time_plus_sec(time_t l, long r);
+char* format_localTime(time_t from);
+time_t read_localTime(struct berval* from);
+time_t parse_localTime(char* from);
+void write_localTime(time_t from, struct berval* into);
+time_t current_time( void );
+char* format_genTime(time_t from);
+void write_genTime(time_t from, struct berval* into);
+time_t read_genTime(struct berval* from);
+time_t parse_genTime(char* from);
+
+/* Client SSL code */
+int slapd_SSL_client_init( void );
+int slapd_security_library_is_initialized( void );
+int slapd_SSL_client_bind_s(LDAP* ld, char* DN, char* pw, int use_SSL, int LDAPv);
+int slapd_sasl_ext_client_bind(LDAP* ld, int **msgid);
+int slapd_Client_auth(LDAP* ld);
+char* slapd_get_tmp_dir( void );
+
+/* Misc crrrrrrap */
+#include <stdio.h> /* GGOODREPL - For BUFSIZ, below, gak */
+const char* escape_string (const char* str, char buf[BUFSIZ]);
+const char* escape_string_with_punctuation(const char* str, char buf[BUFSIZ]);
+const char* escape_filter_value(const char* str, int len, char buf[BUFSIZ]);
+void charray_add( char ***a, char *s );
+void charray_free(char **array);
+int charray_remove(char **a,const char *s);
+int charray_inlist( char **a, char *s );
+
+char *slapi_berval_get_string_copy(const struct berval *bval);
+
+/* lenstr stuff */
+
+typedef struct _lenstr {
+ char *ls_buf;
+ size_t ls_len;
+ size_t ls_maxlen;
+} lenstr;
+#define LS_INCRSIZE 256
+
+void addlenstr( lenstr *l, const char *str );
+void lenstr_free( lenstr ** );
+lenstr *lenstr_new(void);
+
+/* event queue routines and data types */
+typedef void* Slapi_Eq_Context;
+typedef void (*slapi_eq_fn_t)(time_t when, void *arg);
+Slapi_Eq_Context slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when);
+Slapi_Eq_Context slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval);
+int slapi_eq_cancel(Slapi_Eq_Context ctx);
+void *slapi_eq_get_arg (Slapi_Eq_Context ctx);
+
+/* config DN */
+char *get_config_DN(void);
+
+/* Data Version */
+const char *get_server_dataversion( void );
+
+/* Configuration Parameters */
+int config_get_port( void );
+int config_get_secureport( void );
+
+/* Local host information */
+char* get_localhost_DN( void );
+char* get_localhost_DNS( void );
+
+int ref_array_replace(const char *dn, struct berval *referral, int write, int read);
+void ref_array_moddn(const char *dn, char *newrdn, Slapi_PBlock *pb);
+int ref_register_callback(int type, char *description,
+ void (*cb)(Slapi_PBlock *, void *), void *cbData);
+int ref_remove_callback(char *description);
+/* GGOODREPL get_data_source definition should move into repl DLL */
+struct berval **get_data_source(Slapi_PBlock *pb, const Slapi_DN *sdn, int orc, void *cf_refs);
+/* Ref_Array *send_read_referrals(Slapi_PBlock *pb, int scope, char *dn, struct berval ***urls); */
+
+/* JCMREPL - IFP and CFP should be defined centrally */
+#ifndef _IFP
+#define _IFP
+typedef int (*IFP)();
+#endif
+
+#ifndef _CFP
+#define _CFP
+typedef char*(*CFP)();
+#endif
+
+void bervalarray_add_berval_fast(struct berval ***vals, const struct berval *addval, int nvals, int *maxvals);
+
+int re_exec( char *lp );
+char *re_comp( char *pat );
+void re_lock( void );
+int re_unlock( void );
+
+
+/* this is the root configuration entry beneath which all plugin
+ configuration entries will be found */
+#define PLUGIN_BASE_DN "cn=plugins,cn=config"
+
+/***** End of items added for the replication plugin. ***********************/
+
+
+/******************************************************************************
+ * Online tasks interface (to support import, export, etc)
+ * After some cleanup, we could consider making these public.
+ */
+typedef struct _slapi_task Slapi_Task;
+typedef int (*TaskCallbackFn)(Slapi_Task *task);
+
+/* task states */
+#define SLAPI_TASK_SETUP 0
+#define SLAPI_TASK_RUNNING 1
+#define SLAPI_TASK_FINISHED 2
+#define SLAPI_TASK_CANCELLED 3
+
+/* task flags (set by the task-control code) */
+#define SLAPI_TASK_DESTROYING 0x01 /* queued event for destruction */
+
+struct _slapi_task {
+ struct _slapi_task *next;
+ char *task_dn;
+ int task_exitcode; /* for the end user */
+ int task_state; /* (see above) */
+ int task_progress; /* number between 0 and task_work */
+ int task_work; /* "units" of work to be done */
+ int task_flags; /* (see above) */
+
+ /* it is the task's responsibility to allocate this memory & free it: */
+ char *task_status; /* transient status info */
+ char *task_log; /* appended warnings, etc */
+
+ void *task_private; /* for use by backends */
+ TaskCallbackFn cancel; /* task has been cancelled by user */
+ TaskCallbackFn destructor; /* task entry is being destroyed */
+ int task_refcount;
+};
+
+int slapi_task_register_handler(const char *name, dseCallbackFn func);
+void slapi_task_status_changed(Slapi_Task *task);
+void slapi_task_log_status(Slapi_Task *task, char *format, ...);
+void slapi_task_log_notice(Slapi_Task *task, char *format, ...);
+
+/* End of interface to support online tasks **********************************/
+
+
+void DS_Sleep(PRIntervalTime ticks);
+
+#if defined(UPGRADEDB)
+/* macro to specify the behavior of upgradedb */
+#define SLAPI_UPGRADEDB_FORCE 0x1 /* reindex all (no check w/ idl switch) */
+#define SLAPI_UPGRADEDB_SKIPINIT 0x2 /* call upgradedb as part of other op */
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/ldap/servers/slapd/slapi2nspr.c b/ldap/servers/slapd/slapi2nspr.c
new file mode 100644
index 00000000..17f4896f
--- /dev/null
+++ b/ldap/servers/slapd/slapi2nspr.c
@@ -0,0 +1,274 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * slapi2nspr.c - expose a subset of the NSPR20/21 API to SLAPI plugin writers
+ *
+ */
+
+#include "slap.h"
+#include "snmp_collator.h"
+#include <ldap_ssl.h>
+#include <ldappr.h>
+#include <nspr.h>
+
+/*
+ * Note that Slapi_Mutex and Slapi_CondVar are defined like this in
+ * slapi-plugin.h:
+ *
+ * typedef struct slapi_mutex Slapi_Mutex;
+ * typedef struct slapi_condvar Slapi_CondVar;
+ *
+ * but there is no definition for struct slapi_mutex or struct slapi_condvar.
+ * This seems to work okay since we always use them in pointer form and cast
+ * directly to their NSPR equivalents. Clever, huh?
+ */
+
+
+/*
+ * ---------------- SLAPI API Functions --------------------------------------
+ */
+
+/*
+ * Function: slapi_new_mutex
+ * Description: behaves just like PR_NewLock().
+ * Returns: a pointer to the new mutex (NULL if a mutex can't be created).
+ */
+Slapi_Mutex *
+slapi_new_mutex( void )
+{
+ return( (Slapi_Mutex *)PR_NewLock());
+}
+
+
+/*
+ * Function: slapi_destroy_mutex
+ * Description: behaves just like PR_DestroyLock().
+ */
+void
+slapi_destroy_mutex( Slapi_Mutex *mutex )
+{
+ if ( mutex != NULL ) {
+ PR_DestroyLock( (PRLock *)mutex );
+ }
+}
+
+
+/*
+ * Function: slapi_lock_mutex
+ * Description: behaves just like PR_Lock().
+ */
+void
+slapi_lock_mutex( Slapi_Mutex *mutex )
+{
+ if ( mutex != NULL ) {
+ PR_Lock( (PRLock *)mutex );
+ }
+}
+
+
+/*
+ * Function: slapi_unlock_mutex
+ * Description: behaves just like PR_Unlock().
+ * Returns:
+ * non-zero if mutex was successfully unlocked.
+ * 0 if mutex is NULL or is not locked by the calling thread.
+ */
+int
+slapi_unlock_mutex( Slapi_Mutex *mutex )
+{
+ if ( mutex == NULL || PR_Unlock( (PRLock *)mutex ) == PR_FAILURE ) {
+ return( 0 );
+ } else {
+ return( 1 );
+ }
+}
+
+
+/*
+ * Function: slapi_new_condvar
+ * Description: behaves just like PR_NewCondVar().
+ * Returns: pointer to a new condition variable (NULL if one can't be created).
+ */
+Slapi_CondVar *
+slapi_new_condvar( Slapi_Mutex *mutex )
+{
+ if ( mutex == NULL ) {
+ return( NULL );
+ }
+
+ return( (Slapi_CondVar *)PR_NewCondVar( (PRLock *)mutex ));
+}
+
+
+/*
+ * Function: slapi_destroy_condvar
+ * Description: behaves just like PR_DestroyCondVar().
+ */
+void
+slapi_destroy_condvar( Slapi_CondVar *cvar )
+{
+ if ( cvar != NULL ) {
+ PR_DestroyCondVar( (PRCondVar *)cvar );
+ }
+}
+
+
+/*
+ * Function: slapi_wait_condvar
+ * Description: behaves just like PR_WaitCondVar() except timeout is
+ * in seconds and microseconds instead of PRIntervalTime units.
+ * If timeout is NULL, this call blocks indefinitely.
+ * Returns:
+ * non-zero is all goes well.
+ * 0 if cvar is NULL, the caller has not locked the mutex associated
+ * with cvar, or the waiting thread was interrupted.
+ */
+int
+slapi_wait_condvar( Slapi_CondVar *cvar, struct timeval *timeout )
+{
+ PRIntervalTime prit;
+
+ if ( cvar == NULL ) {
+ return( 0 );
+ }
+
+ if ( timeout == NULL ) {
+ prit = PR_INTERVAL_NO_TIMEOUT;
+ } else {
+ prit = PR_SecondsToInterval( timeout->tv_sec )
+ + PR_MicrosecondsToInterval( timeout->tv_usec );
+ }
+
+ if ( PR_WaitCondVar( (PRCondVar *)cvar, prit ) != PR_SUCCESS ) {
+ return( 0 );
+ }
+
+ return( 1 );
+}
+
+
+/*
+ * Function: slapi_notify_condvar
+ * Description: if notify_all is zero, behaves just like PR_NotifyCondVar().
+ * if notify_all is non-zero, behaves just like PR_NotifyAllCondVar().
+ * Returns:
+ * non-zero if all goes well.
+ * 0 if cvar is NULL or the caller has not locked the mutex associated
+ * with cvar.
+ */
+int
+slapi_notify_condvar( Slapi_CondVar *cvar, int notify_all )
+{
+ PRStatus prrc;
+
+ if ( cvar == NULL ) {
+ return( 0 );
+ }
+
+ if ( notify_all ) {
+ prrc = PR_NotifyAllCondVar( (PRCondVar *)cvar );
+ } else {
+ prrc = PR_NotifyCondVar( (PRCondVar *)cvar );
+ }
+
+ return( prrc == PR_SUCCESS ? 1 : 0 );
+}
+
+
+/*
+ * Function: slapi_ldap_init()
+ * Description: just like ldap_ssl_init() but also arranges for the LDAP
+ * session handle returned to be safely shareable by multiple threads
+ * if "shared" is non-zero.
+ * Returns:
+ * an LDAP session handle (NULL if some local error occurs).
+ */
+LDAP *
+slapi_ldap_init( char *ldaphost, int ldapport, int secure, int shared )
+{
+ LDAP *ld;
+ int io_timeout_ms;
+
+
+ if ( secure && slapd_SSL_client_init() != 0 ) {
+ return( NULL );
+ }
+
+ /*
+ * Leverage the libprldap layer to take care of all the NSPR integration.
+ * Note that ldapssl_init() uses libprldap implicitly.
+ */
+
+ if ( secure ) {
+ ld = ldapssl_init( ldaphost, ldapport, secure );
+ } else {
+ ld = prldap_init( ldaphost, ldapport, shared );
+ }
+
+ /* Update snmp interaction table */
+ if ( ld == NULL) {
+ set_snmp_interaction_row( ldaphost, ldapport, -1);
+ } else {
+ set_snmp_interaction_row( ldaphost, ldapport, 0);
+ }
+
+ if ( ld != NULL ) {
+ /*
+ * Set the outbound LDAP I/O timeout based on the server config.
+ */
+ io_timeout_ms = config_get_outbound_ldap_io_timeout();
+ if ( io_timeout_ms > 0 ) {
+ if ( prldap_set_session_option( ld, NULL, PRLDAP_OPT_IO_MAX_TIMEOUT,
+ io_timeout_ms ) != LDAP_SUCCESS ) {
+ slapi_log_error( SLAPI_LOG_FATAL, "slapi_ldap_init",
+ "failed: unable to set outbound I/O timeout to %dms\n",
+ io_timeout_ms );
+ slapi_ldap_unbind( ld );
+ return( NULL );
+ }
+ }
+
+ /*
+ * Set SSL strength (server certificate validity checking).
+ */
+ if ( secure ) {
+ int ssl_strength;
+
+ if ( config_get_ssl_check_hostname()) {
+ /* check hostname against name in certificate */
+ ssl_strength = LDAPSSL_AUTH_CNCHECK;
+ } else {
+ /* verify certificate only */
+ ssl_strength = LDAPSSL_AUTH_CERT;
+ }
+
+ if ( ldapssl_set_strength( ld, ssl_strength ) != 0 ) {
+ int prerr = PR_GetError();
+
+ slapi_log_error( SLAPI_LOG_FATAL, "slapi_ldap_init",
+ "failed: unable to set SSL strength to %d ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ ssl_strength, prerr, slapd_pr_strerror( prerr ));
+
+ }
+ }
+ }
+
+ return( ld );
+}
+
+
+/*
+ * Function: slapi_ldap_unbind()
+ * Purpose: release an LDAP session obtained from a call to slapi_ldap_init().
+ */
+void
+slapi_ldap_unbind( LDAP *ld )
+{
+ if ( ld != NULL ) {
+ ldap_unbind( ld );
+ }
+}
diff --git a/ldap/servers/slapd/snmp_collator.c b/ldap/servers/slapd/snmp_collator.c
new file mode 100644
index 00000000..320c7fe9
--- /dev/null
+++ b/ldap/servers/slapd/snmp_collator.c
@@ -0,0 +1,617 @@
+/** 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 <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#ifndef _WIN32
+#include <sys/ipc.h>
+#include <sys/msg.h>
+#include <dirent.h>
+#endif
+#include <time.h>
+#include <signal.h>
+#include <string.h>
+#include <errno.h>
+
+#include "agtmmap.h"
+#include "slap.h"
+#include "prthread.h"
+#include "prlock.h"
+#include "prerror.h"
+#include "prcvar.h"
+
+#include "snmp_collator.h"
+#include "../snmp/ntagt/nslagtcom_nt.h"
+
+/* stevross: safe to assume port should be at most 5 digits ? */
+#define PORT_LEN 5
+/* strlen of url portions ie "ldap://:/" */
+#define URL_CHARS_LEN 9
+
+char *make_ds_url(char *host, int port);
+void print_snmp_interaction_table();
+int search_interaction_table(char *dsURL, int *isnew);
+
+/* snmp stats stuff */
+struct agt_stats_t *stats=NULL;
+
+/* mmap stuff */
+static int hdl;
+
+/* collator stuff */
+static char *tmpstatsfile = AGT_STATS_FILE;
+#ifdef _WIN32
+static TCHAR szStatsFile[_MAX_PATH];
+static TCHAR szTempDir[_MAX_PATH];
+static HANDLE hParentProcess = NULL;
+static HANDLE hStatSlot = NULL;
+static HANDLE hLogFile = INVALID_HANDLE_VALUE;
+static TCHAR szSpoolRootDir[_MAX_PATH];
+#else
+static char szStatsFile[_MAX_PATH];
+#endif /* _WIN32*/
+static Slapi_Eq_Context snmp_eq_ctx;
+static int snmp_collator_stopped = 0;
+
+/* lock stuff */
+static PRLock *interaction_table_mutex;
+
+
+/***********************************************************************************
+*
+* int snmp_collator_init()
+*
+* initializes the global variables used by snmp
+*
+************************************************************************************/
+
+int snmp_collator_init(){
+ int i;
+
+ /*
+ * Initialize the mmap structure
+ */
+ memset((void *) stats, 0, sizeof(*stats));
+ stats->hdr_stats.hdrVersionMjr = AGT_MJR_VERSION;
+ stats->hdr_stats.hdrVersionMnr = AGT_MNR_VERSION;
+ stats->hdr_stats.restarted = 0;
+ stats->hdr_stats.startTime = time(0); /* This is a bit off, hope it's ok */
+
+ /* point these at the mmaped data */
+ g_get_global_snmp_vars()->ops_tbl.dsAnonymousBinds = &(stats->ops_stats.dsAnonymousBinds);
+ g_get_global_snmp_vars()->ops_tbl.dsUnAuthBinds = &(stats->ops_stats.dsUnAuthBinds);
+ g_get_global_snmp_vars()->ops_tbl.dsSimpleAuthBinds = &(stats->ops_stats.dsSimpleAuthBinds);
+ g_get_global_snmp_vars()->ops_tbl.dsStrongAuthBinds = &(stats->ops_stats.dsStrongAuthBinds);
+ g_get_global_snmp_vars()->ops_tbl.dsBindSecurityErrors = &(stats->ops_stats.dsBindSecurityErrors);
+ g_get_global_snmp_vars()->ops_tbl.dsInOps = &(stats->ops_stats.dsInOps);
+ g_get_global_snmp_vars()->ops_tbl.dsReadOps = &(stats->ops_stats.dsReadOps);
+ g_get_global_snmp_vars()->ops_tbl.dsCompareOps = &(stats->ops_stats.dsCompareOps);
+ g_get_global_snmp_vars()->ops_tbl.dsAddEntryOps = &(stats->ops_stats.dsAddEntryOps);
+ g_get_global_snmp_vars()->ops_tbl.dsRemoveEntryOps = &(stats->ops_stats.dsRemoveEntryOps);
+ g_get_global_snmp_vars()->ops_tbl.dsModifyEntryOps = &(stats->ops_stats.dsModifyEntryOps);
+ g_get_global_snmp_vars()->ops_tbl.dsModifyRDNOps = &(stats->ops_stats.dsModifyRDNOps);
+ g_get_global_snmp_vars()->ops_tbl.dsListOps = &(stats->ops_stats.dsListOps);
+ g_get_global_snmp_vars()->ops_tbl.dsSearchOps = &(stats->ops_stats.dsSearchOps);
+ g_get_global_snmp_vars()->ops_tbl.dsOneLevelSearchOps = &(stats->ops_stats.dsOneLevelSearchOps);
+ g_get_global_snmp_vars()->ops_tbl.dsWholeSubtreeSearchOps = &(stats->ops_stats.dsWholeSubtreeSearchOps);
+ g_get_global_snmp_vars()->ops_tbl.dsReferrals = &(stats->ops_stats.dsReferrals);
+ g_get_global_snmp_vars()->ops_tbl.dsChainings = &(stats->ops_stats.dsChainings);
+ g_get_global_snmp_vars()->ops_tbl.dsSecurityErrors = &(stats->ops_stats.dsSecurityErrors);
+ g_get_global_snmp_vars()->ops_tbl.dsErrors = &(stats->ops_stats.dsErrors);
+ g_get_global_snmp_vars()->ops_tbl.dsConnections = &(stats->ops_stats.dsConnections);
+ g_get_global_snmp_vars()->ops_tbl.dsConnectionSeq = &(stats->ops_stats.dsConnectionSeq);
+ g_get_global_snmp_vars()->ops_tbl.dsBytesRecv = &(stats->ops_stats.dsBytesRecv);
+ g_get_global_snmp_vars()->ops_tbl.dsBytesSent = &(stats->ops_stats.dsBytesSent);
+ g_get_global_snmp_vars()->ops_tbl.dsEntriesReturned = &(stats->ops_stats.dsEntriesReturned);
+ g_get_global_snmp_vars()->ops_tbl.dsReferralsReturned = &(stats->ops_stats.dsReferralsReturned);
+
+ /* entries table */
+
+ g_get_global_snmp_vars()->entries_tbl.dsMasterEntries = &(stats->entries_stats.dsMasterEntries);
+ g_get_global_snmp_vars()->entries_tbl.dsCopyEntries = &(stats->entries_stats.dsCopyEntries);
+ g_get_global_snmp_vars()->entries_tbl.dsCacheEntries = &(stats->entries_stats.dsCacheEntries);
+ g_get_global_snmp_vars()->entries_tbl.dsCacheHits = &(stats->entries_stats.dsCacheHits);
+ g_get_global_snmp_vars()->entries_tbl.dsSlaveHits = &(stats->entries_stats.dsSlaveHits);
+
+ /* interaction table */
+
+ /* set pointers to table */
+ for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++)
+ {
+ stats->int_stats[i].dsIntIndex=i;
+ g_get_global_snmp_vars()->int_tbl[i].dsIntIndex = &(stats->int_stats[i].dsIntIndex);
+ g_get_global_snmp_vars()->int_tbl[i].dsName = stats->int_stats[i].dsName;
+ g_get_global_snmp_vars()->int_tbl[i].dsTimeOfCreation = &(stats->int_stats[i].dsTimeOfCreation);
+ g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt = &(stats->int_stats[i].dsTimeOfLastAttempt);
+ g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastSuccess = &(stats->int_stats[i].dsTimeOfLastSuccess);
+ g_get_global_snmp_vars()->int_tbl[i].dsFailuresSinceLastSuccess
+ = &(stats->int_stats[i].dsFailuresSinceLastSuccess);
+ g_get_global_snmp_vars()->int_tbl[i].dsFailures = &(stats->int_stats[i].dsFailures);
+ g_get_global_snmp_vars()->int_tbl[i].dsSuccesses = &(stats->int_stats[i].dsSuccesses);
+ g_get_global_snmp_vars()->int_tbl[i].dsURL = stats->int_stats[i].dsURL;
+ }
+
+ /* initialize table contents */
+ for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++)
+ {
+ *(g_get_global_snmp_vars()->int_tbl[i].dsIntIndex) = i + 1;
+ strcpy(g_get_global_snmp_vars()->int_tbl[i].dsName, "Not Available");
+ *(g_get_global_snmp_vars()->int_tbl[i].dsTimeOfCreation) = 0;
+ *(g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt) = 0;
+ *(g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastSuccess) = 0;
+ *(g_get_global_snmp_vars()->int_tbl[i].dsFailuresSinceLastSuccess) = 0;
+ *(g_get_global_snmp_vars()->int_tbl[i].dsFailures) = 0;
+ *(g_get_global_snmp_vars()->int_tbl[i].dsSuccesses) = 0;
+ strcpy(g_get_global_snmp_vars()->int_tbl[i].dsURL, "Not Available");
+ }
+
+ /* create lock for interaction table */
+ interaction_table_mutex = PR_NewLock();
+
+ return 0;
+}
+
+
+
+/***********************************************************************************
+ * given the name, wether or not it was successfull and the URL updates snmp
+ * interaction table appropriately
+ *
+ *
+************************************************************************************/
+
+void set_snmp_interaction_row(char *host, int port, int error)
+{
+ int index;
+ int isnew;
+ char *dsName;
+ char *dsURL;
+
+ /* stevross: our servers don't have a concept of dsName as a distinguished name
+ as specified in the MIB. Make this "Not Available" for now waiting for
+ sometime in the future when we do
+ */
+
+
+ dsName = "Not Available";
+
+ dsURL= make_ds_url(host, port);
+
+ /* lock around here to avoid race condition of two threads trying to update table at same time */
+ PR_Lock(interaction_table_mutex);
+ index = search_interaction_table(dsURL, &isnew);
+
+ if(isnew){
+ /* fillin the new row from scratch*/
+ *(g_get_global_snmp_vars()->int_tbl[index].dsIntIndex) = index;
+ strcpy(g_get_global_snmp_vars()->int_tbl[index].dsName, dsName);
+ *(g_get_global_snmp_vars()->int_tbl[index].dsTimeOfCreation) = time(0);
+ *(g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastAttempt) = time(0);
+ if(error == 0){
+ *(g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastSuccess) = time(0);
+ *(g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess) = 0;
+ *(g_get_global_snmp_vars()->int_tbl[index].dsFailures) = 0;
+ *(g_get_global_snmp_vars()->int_tbl[index].dsSuccesses) = 1;
+ }else{
+ *(g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastSuccess) = 0;
+ *(g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess) = 1;
+ *(g_get_global_snmp_vars()->int_tbl[index].dsFailures) = 1;
+ *(g_get_global_snmp_vars()->int_tbl[index].dsSuccesses) = 0;
+ }
+ strcpy(g_get_global_snmp_vars()->int_tbl[index].dsURL, dsURL);
+ }else{
+ /* just update the appropriate fields */
+ *(g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastAttempt) = time(0);
+ if(error == 0){
+ *(g_get_global_snmp_vars()->int_tbl[index].dsTimeOfLastSuccess) = time(0);
+ *(g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess) = 0;
+ *(g_get_global_snmp_vars()->int_tbl[index].dsSuccesses) += 1;
+ }else{
+ *(g_get_global_snmp_vars()->int_tbl[index].dsFailuresSinceLastSuccess) +=1;
+ *(g_get_global_snmp_vars()->int_tbl[index].dsFailures) +=1;
+ }
+
+ }
+ PR_Unlock(interaction_table_mutex);
+ /* free the memory allocated for dsURL in call to ds_make_url */
+ if(dsURL != NULL){
+ slapi_ch_free( (void**)&dsURL );
+ }
+}
+
+/***********************************************************************************
+ * Given: host and port
+ * Returns: ldapUrl in form of
+ * ldap://host.mcom.com:port/
+ *
+ * this should point to root DSE
+************************************************************************************/
+char *make_ds_url(char *host, int port){
+
+ char *url;
+
+ url = (char *)slapi_ch_malloc( (strlen(host) + PORT_LEN + URL_CHARS_LEN + 1) * sizeof(char));
+
+ sprintf(url,"ldap://%s:%d/",host, port);
+
+ return url;
+}
+
+
+/***********************************************************************************
+ * searches the table for the url specified
+ * If there, returns index to update stats
+ * if, not there returns index of oldest interaction, and isnew flag is set
+ * so caller can rewrite this row
+************************************************************************************/
+
+int search_interaction_table(char *dsURL, int *isnew)
+{
+ int i;
+ int index = 0;
+ time_t oldestattempt;
+ time_t currentattempt;
+
+ oldestattempt = *(g_get_global_snmp_vars()->int_tbl[0].dsTimeOfLastAttempt);
+ *isnew = 1;
+
+ for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++){
+ if(!strcmp(g_get_global_snmp_vars()->int_tbl[i].dsURL, "Not Available"))
+ {
+ /* found it -- this is new, first time for this row */
+ index = i;
+ break;
+ }else if(!strcmp(g_get_global_snmp_vars()->int_tbl[i].dsURL, dsURL)){
+ /* found it -- it was already there*/
+ *isnew = 0;
+ index = i;
+ break;
+ }else{
+ /* not found so figure out oldest row */
+ currentattempt = *(g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt);
+
+ if(currentattempt <= oldestattempt){
+ index=i;
+ oldestattempt = currentattempt;
+ }
+ }
+
+ }
+
+ return index;
+
+}
+/* for debuging until subagent part working, print contents of interaction table */
+void print_snmp_interaction_table()
+{
+ int i;
+ for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++)
+ {
+ fprintf(stderr, " dsIntIndex: %d \n", *(g_get_global_snmp_vars()->int_tbl[i].dsIntIndex));
+ fprintf(stderr, " dsName: %s \n", g_get_global_snmp_vars()->int_tbl[i].dsName);
+ fprintf(stderr, " dsTimeOfCreation: %ld \n", *(g_get_global_snmp_vars()->int_tbl[i].dsTimeOfCreation));
+ fprintf(stderr, " dsTimeOfLastAttempt: %ld \n", *(g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastAttempt));
+ fprintf(stderr, " dsTimeOfLastSuccess: %ld \n", *(g_get_global_snmp_vars()->int_tbl[i].dsTimeOfLastSuccess));
+ fprintf(stderr, "dsFailuresSinceLastSuccess: %d \n", *(g_get_global_snmp_vars()->int_tbl[i].dsFailuresSinceLastSuccess));
+ fprintf(stderr, " dsFailures: %d \n", *(g_get_global_snmp_vars()->int_tbl[i].dsFailures));
+ fprintf(stderr, " dsSuccesses: %d \n", *(g_get_global_snmp_vars()->int_tbl[i].dsSuccesses));
+ fprintf(stderr, " dsURL: %s \n", g_get_global_snmp_vars()->int_tbl[i].dsURL);
+ fprintf(stderr, "\n");
+ }
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * sc_setevent: Sets the specified event (NT only). The input event has
+ * to be created by the subagent during its initialization.
+ *
+ * Returns: None
+ *
+ *-----------------------------------------------------------------------*/
+
+#ifdef _WIN32
+void sc_setevent(char *ev)
+{
+ HANDLE hTrapEvent;
+ DWORD err = NO_ERROR;
+
+ /*
+ * Set the event handle to force NT SNMP service to call the subagent
+ * DLL to generate a trap. Any error will be ignored as the subagent
+ * may not have been loaded.
+ */
+ if ((hTrapEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE,
+ (LPCTSTR) ev)) != NULL)
+ {
+ if (SetEvent(hTrapEvent) == FALSE)
+ err = GetLastError();
+ }
+ else
+ err = GetLastError();
+
+ if (err != NO_ERROR)
+ {
+ fprintf(stderr, "Failed to set trap (error = %d).\n", err);
+ }
+}
+#endif
+
+
+
+/***********************************************************************************
+*
+* int snmp_collator_start()
+*
+* open the memory map and initialize the variables
+* initializes the global variables used by snmp
+*
+* starts the collator thread
+************************************************************************************/
+
+int snmp_collator_start()
+{
+
+ int err;
+ char *instancedir = config_get_instancedir();
+
+ /*
+ * Get directory for our stats file
+ */
+
+ sprintf(szStatsFile, "%s/logs/%s", instancedir,
+ AGT_STATS_FILE);
+ tmpstatsfile = szStatsFile;
+
+ slapi_ch_free((void **) &instancedir);
+
+
+ /* open the memory map */
+
+ if ((err = agt_mopen_stats(tmpstatsfile, O_RDWR, &hdl) != 0))
+ {
+ if (err != EEXIST) /* Ignore if file already exists */
+ {
+ printf("Failed to open stats file (%s) (error %d).\n",
+ AGT_STATS_FILE, err);
+
+ exit(1);
+ }
+ }
+
+
+
+/* point stats struct at mmap data */
+ stats = (struct agt_stats_t *) mmap_tbl [hdl].fp;
+
+/* initialize stats data */
+
+ snmp_collator_init();
+/*
+* now that memmap is open and things point the right way
+* an atomic set or increment anywhere in slapd should set
+* the snmp memmap vars correctly and be able to be polled by snmp
+*/
+
+ /* Arrange to be called back periodically */
+ snmp_eq_ctx = slapi_eq_repeat(snmp_collator_update, NULL, (time_t)0,
+ SLAPD_SNMP_UPDATE_INTERVAL);
+
+
+return 0;
+
+}
+
+
+/***********************************************************************************
+*
+* int snmp_collator_stop()
+*
+* stops the collator thread
+* closes the memory map
+* cleans up any needed memory
+*
+************************************************************************************/
+
+int snmp_collator_stop()
+{
+ int err;
+
+ /* Abort any pending events */
+ slapi_eq_cancel(snmp_eq_ctx);
+ snmp_collator_stopped = 1;
+
+ /* close the memory map */
+ if ((err = agt_mclose_stats(hdl)) != 0)
+ {
+ fprintf(stderr, "Failed to close stats file (%s) (error = %d).",
+ AGT_STATS_FILE, err);
+ }
+
+ if (remove(tmpstatsfile) != 0)
+ {
+ fprintf(stderr, "Failed to remove (%s) (error = %d).\n",
+ tmpstatsfile, errno);
+ }
+
+ /* delete lock */
+ PR_DestroyLock(interaction_table_mutex);
+
+#ifdef _WIN32
+ /* send the event so server down trap gets set on NT */
+ sc_setevent(MAGT_NSEV_SNMPTRAP);
+
+#endif
+ /* stevross: I probably need to free stats too... make sure to add that later */
+
+return 0;
+}
+
+
+
+/***********************************************************************************
+*
+* int snmp_collator_update()
+*
+* our architecture changed from mail server and we right to mmapped
+* area as soon as operation completed, rather than maintining the same data twice
+* and doing a polled update. However, to keep traps working correctly (as they depend)
+* on the time in the header, it is more efficient to write the header info
+* in a polled fashion (ever 1 sec)
+*
+************************************************************************************/
+
+void
+snmp_collator_update(time_t start_time, void *arg)
+{
+ Slapi_Backend *be, *be_next;
+ char *cookie = NULL;
+ Slapi_PBlock *search_result_pb = NULL;
+ Slapi_Entry **search_entries;
+ Slapi_Attr *attr = NULL;
+ Slapi_Value *sval = NULL;
+ int search_result;
+
+ if (snmp_collator_stopped) {
+ return;
+ }
+
+ /* just update the update time in the header */
+ if( stats != NULL){
+ stats->hdr_stats.updateTime = time(0);
+ }
+
+ /* set the cache hits/cache entries info */
+ be = slapi_get_first_backend(&cookie);
+ if (!be)
+ return;
+
+ be_next = slapi_get_next_backend(cookie);
+
+ slapi_ch_free ((void **) &cookie);
+
+ /* for now, only do it if there is only 1 backend, otherwise don't know
+ which backend to pick */
+ if(be_next == NULL)
+ {
+ Slapi_DN monitordn;
+ slapi_sdn_init(&monitordn);
+ be_getmonitordn(be,&monitordn);
+
+ /* do a search on the monitor dn to get info */
+ search_result_pb = slapi_search_internal( slapi_sdn_get_dn(&monitordn),
+ LDAP_SCOPE_BASE,
+ "objectclass=*",
+ NULL,
+ NULL,
+ 0);
+ slapi_sdn_done(&monitordn);
+
+ slapi_pblock_get( search_result_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
+
+ if(search_result == 0)
+ {
+ const struct berval *val = NULL;
+ /* get the entrycachehits */
+ slapi_pblock_get( search_result_pb,SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES,
+ &search_entries);
+ if(slapi_entry_attr_find( search_entries[0], "entrycachehits", &attr) == 0 )
+ {
+ /* get the values out of the attribute */
+ val = NULL;
+ slapi_attr_first_value( attr, &sval );
+ if(NULL != sval)
+ {
+ val= slapi_value_get_berval( sval );
+ }
+ }
+
+ /* if we got a value for entrycachehits, then set it */
+ if(val != NULL)
+ {
+ PR_AtomicSet(g_get_global_snmp_vars()->entries_tbl.dsCacheHits, atoi(val->bv_val));
+
+ }
+
+ /* get the currententrycachesize */
+ attr = NULL;
+ val = NULL;
+ sval = NULL;
+ if(slapi_entry_attr_find( search_entries[0], "currententrycachesize", &attr) == 0 )
+ {
+ /* get the values out of the attribute */
+ slapi_attr_first_value( attr,&sval );
+ if(NULL != sval) {
+ val= slapi_value_get_berval( sval );
+ }
+ }
+
+ /* if we got a value for currententrycachesize, then set it */
+ if(val != NULL)
+ {
+ PR_AtomicSet(g_get_global_snmp_vars()->entries_tbl.dsCacheEntries, atoi(val->bv_val));
+
+ }
+
+ }
+
+ slapi_free_search_results_internal(search_result_pb);
+ slapi_pblock_destroy(search_result_pb);
+ }
+}
+
+static void
+add_counter_to_value(Slapi_Entry *e, const char *type, int countervalue)
+{
+ char value[40];
+ sprintf(value,"%d",countervalue);
+ slapi_entry_attr_set_charptr( e, type, value);
+}
+
+void
+snmp_as_entry(Slapi_Entry *e)
+{
+ add_counter_to_value(e,"AnonymousBinds",stats->ops_stats.dsAnonymousBinds);
+ add_counter_to_value(e,"UnAuthBinds",stats->ops_stats.dsUnAuthBinds);
+ add_counter_to_value(e,"SimpleAuthBinds",stats->ops_stats.dsSimpleAuthBinds);
+ add_counter_to_value(e,"StrongAuthBinds",stats->ops_stats.dsStrongAuthBinds);
+ add_counter_to_value(e,"BindSecurityErrors",stats->ops_stats.dsBindSecurityErrors);
+ add_counter_to_value(e,"InOps",stats->ops_stats.dsInOps);
+ add_counter_to_value(e,"ReadOps",stats->ops_stats.dsReadOps);
+ add_counter_to_value(e,"CompareOps",stats->ops_stats.dsCompareOps);
+ add_counter_to_value(e,"AddEntryOps",stats->ops_stats.dsAddEntryOps);
+ add_counter_to_value(e,"RemoveEntryOps",stats->ops_stats.dsRemoveEntryOps);
+ add_counter_to_value(e,"ModifyEntryOps",stats->ops_stats.dsModifyEntryOps);
+ add_counter_to_value(e,"ModifyRDNOps",stats->ops_stats.dsModifyRDNOps);
+ add_counter_to_value(e,"ListOps",stats->ops_stats.dsListOps);
+ add_counter_to_value(e,"SearchOps",stats->ops_stats.dsSearchOps);
+ add_counter_to_value(e,"OneLevelSearchOps",stats->ops_stats.dsOneLevelSearchOps);
+ add_counter_to_value(e,"WholeSubtreeSearchOps",stats->ops_stats.dsWholeSubtreeSearchOps);
+ add_counter_to_value(e,"Referrals",stats->ops_stats.dsReferrals);
+ add_counter_to_value(e,"Chainings",stats->ops_stats.dsChainings);
+ add_counter_to_value(e,"SecurityErrors",stats->ops_stats.dsSecurityErrors);
+ add_counter_to_value(e,"Errors",stats->ops_stats.dsErrors);
+ add_counter_to_value(e,"Connections",stats->ops_stats.dsConnections);
+ add_counter_to_value(e,"ConnectionSeq",stats->ops_stats.dsConnectionSeq);
+ add_counter_to_value(e,"BytesRecv",stats->ops_stats.dsBytesRecv);
+ add_counter_to_value(e,"BytesSent",stats->ops_stats.dsBytesSent);
+ add_counter_to_value(e,"EntriesReturned",stats->ops_stats.dsEntriesReturned);
+ add_counter_to_value(e,"ReferralsReturned",stats->ops_stats.dsReferralsReturned);
+ add_counter_to_value(e,"MasterEntries",stats->entries_stats.dsMasterEntries);
+ add_counter_to_value(e,"CopyEntries",stats->entries_stats.dsCopyEntries);
+ add_counter_to_value(e,"CacheEntries",stats->entries_stats.dsCacheEntries);
+ add_counter_to_value(e,"CacheHits",stats->entries_stats.dsCacheHits);
+ add_counter_to_value(e,"SlaveHits",stats->entries_stats.dsSlaveHits);
+}
+
+
+
+
+
+
+
+
+
diff --git a/ldap/servers/slapd/snmp_collator.h b/ldap/servers/slapd/snmp_collator.h
new file mode 100644
index 00000000..d6eec840
--- /dev/null
+++ b/ldap/servers/slapd/snmp_collator.h
@@ -0,0 +1,15 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/******************************************************************************
+*
+* function prototypes
+*
+******************************************************************************/
+
+ int snmp_collator_start();
+ int snmp_collator_stop();
+ void set_snmp_interaction_row(char *host, int port, int error);
+ void snmp_collator_update(time_t, void *);
diff --git a/ldap/servers/slapd/snoop.c b/ldap/servers/slapd/snoop.c
new file mode 100644
index 00000000..d6841aa2
--- /dev/null
+++ b/ldap/servers/slapd/snoop.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 **/
+
+/* Operation Snooping Function.
+ Used by server internal code (and plugins if they fancy)
+ to detect state changes in the server.
+ Works by snooping the operation stream (as a postop plugin)
+ and calling back all the affected registered parties.
+*/
+
+/* Insert code here ... */
+
+
+int statechange_register(callback *func, char *dns)
+{
+ int ret = -1;
+
+ /* create register cache */
+
+ return ret;
+}
+
+int statechange_unregister(callback *func, char *dns)
+{
+ int ret = -1;
+
+ return ret;
+}
+
+
+int postop()
+{
+ /* state change, evaluate who it effects and notify */
+
+}
+
diff --git a/ldap/servers/slapd/ssl.c b/ldap/servers/slapd/ssl.c
new file mode 100644
index 00000000..49eea76a
--- /dev/null
+++ b/ldap/servers/slapd/ssl.c
@@ -0,0 +1,1499 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* SSL-related stuff for slapd */
+
+#if defined(NET_SSL)
+
+#if defined( _WINDOWS )
+#include <windows.h>
+#include <winsock.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include "proto-ntutil.h"
+#include <string.h>
+#include <stdlib.h>
+#include <direct.h>
+#include <io.h>
+#endif
+
+#ifdef LINUX
+#include <sys/param.h>
+#endif
+
+#include <ssl.h>
+#include <nss.h>
+#include <key.h>
+#include <sslproto.h>
+#include "secmod.h"
+#include <string.h>
+#include <errno.h>
+
+#include "slap.h"
+
+#include "svrcore.h"
+#include "fe.h"
+#include <ldap_ssl.h> /* ldapssl_client_init */
+#include "certdb.h"
+
+/* For IRIX... */
+#ifndef MAXPATHLEN
+#define MAXPATHLEN 1024
+#endif
+
+extern char* slapd_SSL3ciphers;
+extern symbol_t supported_ciphers[];
+
+/* dongle_file_name is set in slapd_nss_init when we set the path for the
+ key, cert, and secmod files - the dongle file must be in the same directory
+ and use the same naming scheme
+*/
+static char* dongle_file_name = NULL;
+
+static int _security_library_initialized = 0;
+static int _ssl_listener_initialized = 0;
+
+/* Our name for the internal token, must match PKCS-11 config data below */
+static char *internalTokenName = "Internal (Software) Token";
+
+static int stimeout;
+static char *ciphers = NULL;
+static char * configDN = "cn=encryption,cn=config";
+
+/* Copied from libadmin/libadmin.h public/nsapi.h */
+#define SERVER_KEY_NAME "Server-Key"
+#define MAGNUS_ERROR_LEN 1024
+#define LOG_WARN 0
+#define LOG_FAILURE 3
+#define FILE_PATHSEP '/'
+
+/* ----------------------- Multiple cipher support ------------------------ */
+
+
+#ifdef NET_SSL
+
+static char **cipher_names = NULL;
+typedef struct {
+ char *version;
+ char *name;
+ int num;
+} cipherstruct;
+
+
+static cipherstruct _conf_ciphers[] = {
+ {"SSL3","rc4", SSL_EN_RC4_128_WITH_MD5},
+ {"SSL3","rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5},
+ {"SSL3","rc2", SSL_EN_RC2_128_CBC_WITH_MD5},
+ {"SSL3","rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
+ /*{"idea", SSL_EN_IDEA_128_CBC_WITH_MD5}, */
+ {"SSL3","des", SSL_EN_DES_64_CBC_WITH_MD5},
+ {"SSL3","desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
+ {"SSL3","rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5},
+ {"SSL3","rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"SSL3","rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA},
+ {"SSL3","rsa_fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
+ {"SSL3","rsa_fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA},
+ {"SSL3","rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5},
+ {"SSL3","rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
+ {"SSL3","rsa_null_md5", SSL_RSA_WITH_NULL_MD5},
+ {"TLS","tls_rsa_export1024_with_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
+ {"TLS","tls_rsa_export1024_with_des_cbc_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
+ {"SSL3","fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
+ {"SSL3","fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
+ {"SSL3","fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
+
+
+ /*{"SSL3","dhe_dss_40_sha", SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA}, */
+ {"SSL3","dhe_dss_des_sha", SSL_DHE_DSS_WITH_DES_CBC_SHA},
+ {"SSL3","dhe_dss_3des_sha", SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA},
+ /*{"SSL3","dhe_rsa_40_sha", SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA}, */
+ {"SSL3","dhe_rsa_des_sha", SSL_DHE_RSA_WITH_DES_CBC_SHA},
+ {"SSL3","dhe_rsa_3des_sha", SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA},
+
+ {"TLS","tls_rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA},
+ {"TLS","tls_dhe_dss_aes_128_sha", TLS_DHE_DSS_WITH_AES_128_CBC_SHA},
+ {"TLS","tls_dhe_rsa_aes_128_sha", TLS_DHE_RSA_WITH_AES_128_CBC_SHA},
+
+ {"TLS","tls_rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA},
+ {"TLS","tls_dhe_dss_aes_256_sha", TLS_DHE_DSS_WITH_AES_256_CBC_SHA},
+ {"TLS","tls_dhe_rsa_aes_256_sha", TLS_DHE_RSA_WITH_AES_256_CBC_SHA},
+ /*{"TLS","tls_dhe_dss_1024_des_sha", TLS_DHE_DSS_EXPORT1024_WITH_DES_CBC_SHA}, */
+ {"TLS","tls_dhe_dss_1024_rc4_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
+ {"TLS","tls_dhe_dss_rc4_128_sha", TLS_DHE_DSS_WITH_RC4_128_SHA},
+ {NULL, NULL, 0}
+};
+
+char ** getSupportedCiphers()
+{
+ SSLCipherSuiteInfo info;
+ char *sep = "::";
+ int number_of_ciphers = sizeof (_conf_ciphers) /sizeof(cipherstruct);
+ int i;
+ if (cipher_names == NULL ) {
+ cipher_names = (char **) slapi_ch_calloc ((number_of_ciphers +1 ) , sizeof(char *));
+ for (i = 0 ; _conf_ciphers[i].name != NULL; i++ ) {
+ SSL_GetCipherSuiteInfo((PRUint16)_conf_ciphers[i].num,&info,sizeof(info));
+ cipher_names[i] = PR_smprintf("%s%s%s%s%s%s%s%s%d\0",_conf_ciphers[i].version,sep,_conf_ciphers[i].name,sep,info.symCipherName,sep,info.macAlgorithmName,sep,info.symKeyBits);
+ }
+ cipher_names[i] = NULL;
+ }
+ return cipher_names;
+}
+void
+_conf_setallciphers(int active)
+{
+ int x;
+
+ /* MLM - change: Because null_md5 is NOT encrypted at all, force
+ * them to activate it by name. */
+ for(x = 0; _conf_ciphers[x].name; x++) {
+ if(active && !strcmp(_conf_ciphers[x].name, "rsa_null_md5")) {
+ continue;
+ }
+#ifdef NET_SSL
+ SSL_CipherPrefSetDefault(_conf_ciphers[x].num, active ? PR_TRUE : PR_FALSE);
+#endif
+ }
+}
+
+char *
+_conf_setciphers(char *ciphers)
+{
+ char *t, err[MAGNUS_ERROR_LEN];
+ int x, active;
+ char *raw = ciphers;
+
+ /* Default is to activate all of them */
+ if(!ciphers || ciphers[0] == '\0') {
+ _conf_setallciphers(1);
+ return NULL;
+ }
+/* Enable all the ciphers by default and the following while loop would disable the user disabled ones This is needed becuase we added a new set of ciphers in the table . Right now there is no support for this from the console */
+ _conf_setallciphers(1);
+
+ t = ciphers;
+ while(t) {
+ while((*ciphers) && (isspace(*ciphers))) ++ciphers;
+
+ switch(*ciphers++) {
+ case '+':
+ active = 1; break;
+ case '-':
+ active = 0; break;
+ default:
+ sprintf(err, "invalid ciphers <%s>: format is "
+ "+cipher1,-cipher2...", raw);
+ return slapi_ch_strdup(err);
+ }
+ if( (t = strchr(ciphers, ',')) )
+ *t++ = '\0';
+
+ if(!strcasecmp(ciphers, "all"))
+ _conf_setallciphers(active);
+ else {
+ for(x = 0; _conf_ciphers[x].name; x++) {
+ if(!strcasecmp(ciphers, _conf_ciphers[x].name)) {
+ SSL_CipherPrefSetDefault(_conf_ciphers[x].num, active ? PR_TRUE : PR_FALSE);
+ break;
+ }
+ }
+ if(!_conf_ciphers[x].name) {
+ sprintf(err, "unknown cipher %s", ciphers);
+ return slapi_ch_strdup(err);
+ }
+ }
+ if(t)
+ ciphers = t;
+ }
+ return NULL;
+}
+
+/* SSL Policy stuff */
+
+/*
+ * Policy table
+ */
+static struct policy
+{
+ long ciphersuite;
+ int exportPolicy;
+} policy_table[] = {
+ { SSL_EN_RC4_128_WITH_MD5, SSL_NOT_ALLOWED },
+ { SSL_EN_RC4_128_EXPORT40_WITH_MD5, SSL_ALLOWED },
+ { SSL_EN_RC2_128_CBC_WITH_MD5, SSL_NOT_ALLOWED },
+ { SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, SSL_ALLOWED },
+ { SSL_EN_IDEA_128_CBC_WITH_MD5, SSL_NOT_ALLOWED },
+ { SSL_EN_DES_64_CBC_WITH_MD5, SSL_NOT_ALLOWED },
+ { SSL_EN_DES_192_EDE3_CBC_WITH_MD5, SSL_NOT_ALLOWED },
+
+ /* SSL v3 Cipher Suites */
+ { SSL_RSA_WITH_NULL_MD5, SSL_ALLOWED },
+#if 0
+ { SSL_RSA_WITH_NULL_SHA, SSL_ALLOWED },
+#endif
+ { SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_ALLOWED },
+ { SSL_RSA_WITH_RC4_128_MD5, SSL_RESTRICTED },
+#if 0
+ { SSL_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED },
+#endif
+ { SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_ALLOWED },
+
+#if 0
+ { SSL_RSA_WITH_IDEA_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_ALLOWED },
+#endif
+
+ { SSL_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_RESTRICTED },
+
+#if 0
+ { SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_ALLOWED },
+ { SSL_DH_DSS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_ALLOWED },
+ { SSL_DH_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED },
+
+ { SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA, SSL_ALLOWED },
+ { SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA, SSL_ALLOWED },
+ { SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED },
+
+ { SSL_DH_ANON_EXPORT_WITH_RC4_40_MD5, SSL_ALLOWED },
+ { SSL_DH_ANON_WITH_RC4_128_MD5, SSL_NOT_ALLOWED },
+ { SSL_DH_ANON_EXPORT_WITH_DES40_CBC_SHA, SSL_ALLOWED },
+ { SSL_DH_ANON_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_DH_ANON_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED },
+#endif
+
+ { SSL_FORTEZZA_DMS_WITH_NULL_SHA, SSL_NOT_ALLOWED },
+ { SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, SSL_NOT_ALLOWED },
+ { SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, SSL_NOT_ALLOWED },
+
+ { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_RESTRICTED },
+ { SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED },
+};
+
+
+/*
+ * SSLPLCY_Install
+ *
+ * Call the SSL_CipherPolicySet function for each ciphersuite.
+ */
+PRStatus
+SSLPLCY_Install(void)
+{
+
+ SECStatus s = 0;
+
+
+#ifdef NS_DOMESTIC
+
+ s = NSS_SetDomesticPolicy();
+
+#else
+ s = NSS_SetExportPolicy();
+
+#endif
+
+
+ return s?PR_FAILURE:PR_SUCCESS;
+
+}
+
+
+#endif /* NET_SSL */
+
+static void
+slapd_SSL_report(int degree, char *fmt, va_list args)
+{
+ char buf[2048];
+ vsprintf( buf, fmt, args );
+ LDAPDebug( LDAP_DEBUG_ANY, "SSL %s: %s\n",
+ (degree == LOG_FAILURE) ? "failure" : "alert",
+ buf, 0 );
+}
+
+void
+slapd_SSL_error(char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ slapd_SSL_report(LOG_FAILURE, fmt, args);
+ exit(1);
+}
+
+void
+slapd_SSL_warn(char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ slapd_SSL_report(LOG_WARN, fmt, args);
+ va_end(args);
+}
+
+
+static void
+server_free_alias_dir(char *s)
+{
+ void *mem = s;
+
+ slapi_ch_free(&mem);
+}
+
+
+/**
+ * Get a particular entry
+ */
+static Slapi_Entry *
+getConfigEntry( const char *dn, Slapi_Entry **e2 ) {
+ Slapi_DN sdn;
+
+ slapi_sdn_init_dn_byref( &sdn, dn );
+ slapi_search_internal_get_entry( &sdn, NULL, e2,
+ plugin_get_default_component_id());
+ slapi_sdn_done( &sdn );
+ return *e2;
+}
+
+/**
+ * Free an entry
+ */
+static void
+freeConfigEntry( Slapi_Entry ** e ) {
+ if ( (e != NULL) && (*e != NULL) ) {
+ slapi_entry_free( *e );
+ *e = NULL;
+ }
+}
+
+/**
+ * Get a list of child DNs
+ */
+static char **
+getChildren( char *dn ) {
+ Slapi_PBlock *new_pb = NULL;
+ Slapi_Entry **e;
+ int search_result = 1;
+ int nEntries = 0;
+ char **list = NULL;
+
+ new_pb = slapi_search_internal ( dn, LDAP_SCOPE_ONELEVEL,
+ "(objectclass=nsEncryptionModule)",
+ NULL, NULL, 0);
+
+ slapi_pblock_get( new_pb, SLAPI_NENTRIES, &nEntries);
+ if ( nEntries > 0 ) {
+ slapi_pblock_get( new_pb, SLAPI_PLUGIN_INTOP_RESULT, &search_result);
+ slapi_pblock_get( new_pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &e);
+ if ( e != NULL ) {
+ int i;
+ list = (char **)slapi_ch_malloc( sizeof(*list) * (nEntries + 1));
+ for ( i = 0; e[i] != NULL; i++ ) {
+ list[i] = slapi_ch_strdup(slapi_entry_get_dn(e[i]));
+ }
+ list[nEntries] = NULL;
+ }
+ }
+ slapi_free_search_results_internal(new_pb);
+ slapi_pblock_destroy(new_pb );
+ return list;
+}
+
+/**
+ * Free a list of child DNs
+ */
+static void
+freeChildren( char **list ) {
+ if ( list != NULL ) {
+ int i;
+ for ( i = 0; list[i] != NULL; i++ ) {
+ slapi_ch_free( (void **)(&list[i]) );
+ }
+ slapi_ch_free( (void **)(&list) );
+ }
+}
+
+
+/*
+ * slapd_nss_init() is always called from main(), even if we do not
+ * plan to listen on a secure port. If config_available is 0, the
+ * config. entries from dse.ldif are NOT available (used only when
+ * running in referral mode).
+ * As of DS6.1, the init_ssl flag passed is ignored.
+ */
+int
+slapd_nss_init(int init_ssl, int config_available)
+{
+ SECStatus secStatus;
+ PRErrorCode errorCode;
+ char *keyfn = NULL;
+ char *certfn = NULL;
+ char *val = NULL;
+ char certPref[1024];
+ char keyPref[1024];
+ char path[1024];
+ int rv = 0;
+ int len = 0;
+ PRUint32 nssFlags = 0;
+ Slapi_Entry *ec = NULL;
+ char *instancedir;
+
+ if (config_available) {
+ getConfigEntry( configDN, &ec );
+ }
+
+ if ( ec != NULL ) {
+ certfn = slapi_entry_attr_get_charptr( ec, "nscertfile" );
+ keyfn = slapi_entry_attr_get_charptr( ec, "nskeyfile" );
+ slapi_entry_free (ec);
+ ec = NULL;
+ }
+
+ instancedir = config_get_instancedir();
+ strcpy(path, instancedir);
+ slapi_ch_free_string(&instancedir);
+
+ /* make sure path does not end in the path separator character */
+ len = strlen(path);
+ if (path[len-1] == '/' || path[len-1] == '\\') {
+ path[len-1] = '\0';
+ }
+
+ /* get the server root from the path */
+ val = strrchr(path, '/');
+ if (!val) {
+ val = strrchr(path, '\\');
+ }
+ val++;
+
+ if(keyfn && certfn) {
+ if (is_abspath(certfn)) {
+ /* first, initialize path from the certfn */
+ strcpy(path, certfn);
+ /* extract path from cert db filename */
+ val = strrchr(path, '/');
+ if (!val) {
+ val = strrchr(path, '\\');
+ }
+ *val = 0; /* path is initialized */
+ /* next, init the cert db prefix */
+ val++;
+ strcpy(certPref, val);
+ } else {
+ strcpy(val, certfn);
+ val = strrchr(path, '/');
+ if (!val) {
+ val = strrchr(path, '\\');
+ }
+ val++;
+ strcpy(certPref, val);
+ *val = '\0';
+ }
+ /* path represents now the base directory where cert, key, pin, and module db live */
+ /* richm - use strrstr to get the last occurance of -cert in the string, in case
+ the instance is named slapd-cert - the certdb name will be slapd-cert-cert7.db
+ */
+ val = PL_strrstr(certPref, "-cert");
+ val++;
+ *val = '\0';
+ /* certPref keeps the prefix added to the cert db, usually "slapd-myserver-" */
+
+ /* now find the key db prefix */
+ val = strrchr(keyfn, '/');
+ if (!val) {
+ val = strrchr(keyfn, '\\');
+ }
+ if (val != NULL) {
+ val++;
+ } else {
+ val = keyfn;
+ }
+ strcpy(keyPref, val);
+ /* richm - use strrstr to get the last occurance of -key in the string, in case
+ the instance is named slapd-key - the keydb name will be slapd-key-key3.db
+ */
+ val = PL_strrstr(keyPref, "-key");
+ val++;
+ *val = '\0';
+ /* keypref keeps the prefix added to the key db, usually "slapd-myserver-" */
+ } else {
+ if ( config_get_security() ) {
+ /* Have to have the key and cert file names to enable an SSL port */
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to retrieve SSL "
+ "configuration information ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s): "
+ "nskeyfile: %s, nscertfile: %s ",
+ errorCode, slapd_pr_strerror(errorCode),
+ (keyfn ? "found" : "not found"),
+ (certfn ? "found" : "not found"));
+ }
+ sprintf(certPref, "%s-", val);
+ strcpy(keyPref, certPref);
+ strcpy(val, "alias/");
+ }
+
+ slapi_ch_free((void **) &certfn);
+ slapi_ch_free((void **) &keyfn);
+
+ /******** Initialise NSS *********/
+
+ nssFlags &= (~NSS_INIT_READONLY);
+ slapd_pk11_configurePKCS11(NULL, NULL, tokDes, ptokDes, NULL, NULL, NULL, NULL, 0, 0 );
+ secStatus = NSS_Initialize(path, certPref, keyPref, "secmod.db", nssFlags);
+
+ dongle_file_name = PR_smprintf("%s/%spin.txt", path, certPref);
+
+ if (secStatus != SECSuccess) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: NSS initialization failed ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s): "
+ "path: %s, certdb prefix: %s, keydb prefix: %s.",
+ errorCode, slapd_pr_strerror(errorCode), path, certPref, keyPref);
+ rv = -1;
+ }
+
+ /****** end of NSS Initialization ******/
+
+ return rv;
+}
+
+
+
+
+
+/*
+ * slapd_ssl_init() is called from main() if we plan to listen
+ * on a secure port.
+ */
+int
+slapd_ssl_init() {
+ PRErrorCode errorCode;
+ char ** family_list;
+ char *val = NULL;
+ char cipher_string[1024];
+ int rv = 0;
+ PK11SlotInfo *slot;
+#ifndef _WIN32
+ SVRCOREStdPinObj *StdPinObj;
+#else
+ SVRCOREFilePinObj *FilePinObj;
+ SVRCOREAltPinObj *AltPinObj;
+ SVRCORENTUserPinObj *NTUserPinObj;
+#endif
+ Slapi_Entry *entry = NULL;
+
+ /* Get general information */
+
+ getConfigEntry( configDN, &entry );
+
+ val = slapi_entry_attr_get_charptr( entry, "nssslSessionTimeout" );
+ ciphers = slapi_entry_attr_get_charptr( entry, "nsssl3ciphers" );
+
+ /* We are currently using the value of sslSessionTimeout
+ for ssl3SessionTimeout, see SSL_ConfigServerSessionIDCache() */
+ /* Note from Tom Weinstein on the meaning of the timeout:
+
+ Timeouts are in seconds. '0' means use the default, which is
+ 24hrs for SSL3 and 100 seconds for SSL2.
+ */
+
+ if(!val) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to retrieve SSL "
+ "configuration information ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s): "
+ "nssslSessionTimeout: %s ",
+ errorCode, slapd_pr_strerror(errorCode),
+ (val ? "found" : "not found"));
+ slapi_ch_free((void **) &val);
+ slapi_ch_free((void **) &ciphers);
+ return -1;
+ }
+
+ stimeout = atoi(val);
+ slapi_ch_free((void **) &val);
+
+#ifndef _WIN32
+ if ( SVRCORE_CreateStdPinObj(&StdPinObj, dongle_file_name, PR_TRUE) !=
+ SVRCORE_Success) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to create PinObj ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+ SVRCORE_RegisterPinObj((SVRCOREPinObj *)StdPinObj);
+#else
+ if (SVRCORE_CreateFilePinObj(&FilePinObj, dongle_file_name) !=
+ SVRCORE_Success) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to create FilePinObj ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+ if (SVRCORE_CreateNTUserPinObj(&NTUserPinObj) != SVRCORE_Success){
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to create NTUserPinObj ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+ if (SVRCORE_CreateAltPinObj(&AltPinObj, (SVRCOREPinObj *)FilePinObj,
+ (SVRCOREPinObj *)NTUserPinObj) != SVRCORE_Success) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to create AltPinObj ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+ SVRCORE_RegisterPinObj((SVRCOREPinObj *)AltPinObj);
+
+#endif /* _WIN32 */
+
+ if((family_list = getChildren(configDN))) {
+ char **family;
+ char *token;
+ char *activation;
+
+ for (family = family_list; *family; family++) {
+
+ token = NULL;
+ activation = NULL;
+
+ freeConfigEntry( &entry );
+
+ getConfigEntry( *family, &entry );
+ if ( entry == NULL ) {
+ continue;
+ }
+
+ activation = slapi_entry_attr_get_charptr( entry, "nssslactivation" );
+ if((!activation) || (!strcasecmp(activation, "off"))) {
+ /* this family was turned off, goto next */
+ slapi_ch_free((void **) &activation);
+ continue;
+ }
+
+ slapi_ch_free((void **) &activation);
+
+ token = slapi_entry_attr_get_charptr( entry, "nsssltoken" );
+ if( token ) {
+ if( !strcasecmp(token, "internal") ||
+ !strcasecmp(token, "internal (software)"))
+ slot = slapd_pk11_getInternalKeySlot();
+ else
+ slot = slapd_pk11_findSlotByName(token);
+ } else {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to get token ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+
+ slapi_ch_free((void **) &token);
+
+ if (!slot) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to find slot ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+ /* authenticate */
+ if(slapd_pk11_authenticate(slot, PR_TRUE, NULL) != SECSuccess)
+ {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to authenticate ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+ }
+ freeChildren( family_list );
+ }
+ freeConfigEntry( &entry );
+
+ if(SSLPLCY_Install() != PR_SUCCESS) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to set SSL export policy ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+
+
+ /* ugaston- Cipher preferences must be set before any sslSocket is created
+ * for such sockets to take preferences into account.
+ */
+
+ /* Step Three.5: Set SSL cipher preferences */
+ *cipher_string = 0;
+ if(ciphers && (*ciphers) && strcmp(ciphers, "blank"))
+ strcpy(cipher_string, ciphers);
+ slapi_ch_free((void **) &ciphers);
+
+ if( NULL != (val = _conf_setciphers(cipher_string)) ) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to set SSL cipher "
+ "preference information: %s (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ val, errorCode, slapd_pr_strerror(errorCode));
+ rv = 3;
+ slapi_ch_free((void **) &val);
+ }
+
+ freeConfigEntry( &entry );
+
+
+ /* Introduce a way of knowing whether slapd_ssl_init has
+ * already been executed. */
+ _security_library_initialized = 1;
+
+
+ if ( rv != 0 )
+ return rv;
+
+
+ return 0;
+
+}
+
+
+int slapd_ssl_init2(PRFileDesc **fd, int startTLS)
+{
+ PRFileDesc *pr_sock, *sock = (*fd);
+ PRErrorCode errorCode;
+ SECStatus rv = SECFailure;
+ char ** family_list;
+ CERTCertificate *cert = NULL;
+ SECKEYPrivateKey *key = NULL;
+ char errorbuf[BUFSIZ];
+ char *val = NULL;
+ int nFamilies = 0;
+ SECStatus sslStatus;
+ int slapd_SSLclientAuth;
+ char* tmpDir;
+ Slapi_Entry *e = NULL;
+
+ /* turn off the PKCS11 pin interactive mode */
+#ifndef _WIN32
+ SVRCOREStdPinObj *StdPinObj;
+
+ StdPinObj = (SVRCOREStdPinObj *)SVRCORE_GetRegisteredPinObj();
+ SVRCORE_SetStdPinInteractive(StdPinObj, PR_FALSE);
+#endif
+
+ errorbuf[0] = '\0';
+
+ /* Import pr fd into SSL */
+ pr_sock = SSL_ImportFD( NULL, sock );
+ if( pr_sock == (PRFileDesc *)NULL ) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to import NSPR "
+ "fd into SSL (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return 1;
+ }
+
+ (*fd) = pr_sock;
+
+ /* Step / Three.6 /
+ * - If in FIPS mode, authenticate to the token before
+ * doing anything else
+ */
+ {
+ PK11SlotInfo *slot = slapd_pk11_getInternalSlot();
+ if (!slot) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to get internal slot ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+
+ if(slapd_pk11_isFIPS()) {
+ if(slapd_pk11_authenticate(slot, PR_TRUE, NULL) != SECSuccess) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to authenticate ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+ }
+
+ slapd_pk11_setSlotPWValues(slot, 0, 0);
+ }
+
+
+
+ /*
+ * Now, get the complete list of cipher families. Each family
+ * has a token name and personality name which we'll use to find
+ * appropriate keys and certs, and call SSL_ConfigSecureServer
+ * with.
+ */
+
+ if((family_list = getChildren(configDN))) {
+ char **family;
+ char cert_name[1024];
+ char *token;
+ char *personality;
+ char *activation;
+
+ for (family = family_list; *family; family++) {
+ token = NULL;
+ personality = NULL;
+ activation = NULL;
+
+ getConfigEntry( *family, &e );
+ if ( e == NULL ) {
+ continue;
+ }
+
+ activation = slapi_entry_attr_get_charptr( e, "nssslactivation" );
+ if((!activation) || (!strcasecmp(activation, "off"))) {
+ /* this family was turned off, goto next */
+ slapi_ch_free((void **) &activation);
+ freeConfigEntry( &e );
+ continue;
+ }
+
+ slapi_ch_free((void **) &activation);
+
+ token = slapi_entry_attr_get_charptr( e, "nsssltoken" );
+ personality = slapi_entry_attr_get_charptr( e, "nssslpersonalityssl" );
+ if( token && personality ) {
+ if( !strcasecmp(token, "internal") ||
+ !strcasecmp(token, "internal (software)") )
+ strcpy(cert_name, personality);
+ else
+ /* external PKCS #11 token - attach token name */
+ sprintf(cert_name, "%s:%s", token, personality);
+ }
+ else {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to get cipher "
+ "family information. Missing nsssltoken or"
+ "nssslpersonalityssl in %s ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ *family, errorCode, slapd_pr_strerror(errorCode));
+ slapi_ch_free((void **) &token);
+ slapi_ch_free((void **) &personality);
+ freeConfigEntry( &e );
+ continue;
+ }
+
+ slapi_ch_free((void **) &token);
+
+ /* Step Four -- Locate the server certificate */
+ cert = slapd_pk11_findCertFromNickname(cert_name, NULL);
+
+ if (cert == NULL) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Can't find "
+ "certificate (%s) for family %s ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ cert_name, *family,
+ errorCode, slapd_pr_strerror(errorCode));
+ }
+ /* Step Five -- Get the private key from cert */
+ if( cert != NULL )
+ key = slapd_pk11_findKeyByAnyCert(cert, NULL);
+
+ if (key == NULL) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Unable to retrieve "
+ "private key for cert %s of family %s ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ cert_name, *family,
+ errorCode, slapd_pr_strerror(errorCode));
+ slapi_ch_free((void **) &personality);
+ CERT_DestroyCertificate(cert);
+ cert = NULL;
+ freeConfigEntry( &e );
+ continue;
+ }
+
+ /* Step Six -- Configure Secure Server Mode */
+ if(pr_sock) {
+ SECCertificateUsage returnedUsages;
+ rv = CERT_VerifyCertificateNow(
+ CERT_GetDefaultCertDB(), cert, PR_TRUE,
+ certificateUsageSSLServer,
+ SSL_RevealPinArg(pr_sock),
+ &returnedUsages);
+ if (SECSuccess == rv) {
+ if( slapd_pk11_fortezzaHasKEA(cert) == PR_TRUE ) {
+ rv = SSL_ConfigSecureServer(*fd, cert, key, kt_fortezza);
+ }
+ else {
+ rv = SSL_ConfigSecureServer(*fd, cert, key, kt_rsa);
+ }
+ if (SECSuccess != rv) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("ConfigSecureServer: "
+ "Server key/certificate is "
+ "bad for cert %s of family %s ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ cert_name, *family, errorCode,
+ slapd_pr_strerror(errorCode));
+ }
+ } else {
+ /* verify certificate failed */
+ /* If the common name in the subject DN for the certificate
+ * is not identical to the domain name passed in the
+ * hostname parameter, SECFailure. */
+ errorCode = PR_GetError();
+ slapd_SSL_warn("CERT_VerifyCertificateNow: "
+ "verify certificate failed "
+ "for cert %s of family %s ("
+ SLAPI_COMPONENT_NAME_NSPR
+ " error %d - %s)",
+ cert_name, *family, errorCode,
+ slapd_pr_strerror(errorCode));
+ }
+ }
+ if (cert) {
+ CERT_DestroyCertificate(cert);
+ cert = NULL;
+ }
+ if (SECSuccess != rv) {
+ slapi_ch_free((void **) &personality);
+ freeConfigEntry( &e );
+ continue;
+ }
+ nFamilies++;
+ freeConfigEntry( &e );
+ }
+ freeChildren( family_list );
+ }
+
+
+ if ( !nFamilies ) {
+ slapd_SSL_error("None of the cipher are valid");
+ return -1;
+ }
+
+ /* Step Seven -- Configure Server Session ID Cache */
+
+ tmpDir = slapd_get_tmp_dir();
+
+ slapi_log_error(
+ SLAPI_LOG_TRACE,
+ "slapd_ssl_init2",
+ "tmp dir = %s\n", tmpDir);
+
+ rv = SSL_ConfigServerSessionIDCache(0, stimeout, stimeout, tmpDir);
+ if (rv) {
+ errorCode = PR_GetError();
+ if (errorCode == ENOSPC) {
+ slapd_SSL_error("Config of server nonce cache failed, "
+ "out of disk space! Make more room in /tmp "
+ "and try again. (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ }
+ else {
+ slapd_SSL_error("Config of server nonce cache failed (error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ }
+ return rv;
+ }
+
+ sslStatus = SSL_OptionSet(pr_sock, SSL_SECURITY, PR_TRUE);
+ if (sslStatus != SECSuccess) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to enable security "
+ "on the imported socket (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ return -1;
+ }
+
+ sslStatus = SSL_OptionSet(pr_sock, SSL_ENABLE_SSL3, PR_TRUE);
+ if (sslStatus != SECSuccess) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to enable SSLv3 "
+ "on the imported socket (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ }
+
+ sslStatus = SSL_OptionSet(pr_sock, SSL_ENABLE_TLS, PR_TRUE);
+ if (sslStatus != SECSuccess) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to enable TLS "
+ "on the imported socket (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ }
+/* Explicitly disabling SSL2 - NGK */
+ sslStatus = SSL_OptionSet(pr_sock, SSL_ENABLE_SSL2, PR_FALSE);
+
+ /* Retrieve the SSL Client Authentication status from cn=config */
+ /* Set a default value if no value found */
+ getConfigEntry( configDN, &e );
+ val = NULL;
+ if ( e != NULL ) {
+ val = slapi_entry_attr_get_charptr( e, "nssslclientauth" );
+ }
+
+ if( !val ) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Cannot get SSL Client "
+ "Authentication status. No nsslclientauth in %s ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ configDN, errorCode, slapd_pr_strerror(errorCode));
+ switch( SLAPD_SSLCLIENTAUTH_DEFAULT ) {
+ case SLAPD_SSLCLIENTAUTH_OFF:
+ val = "off";
+ break;
+ case SLAPD_SSLCLIENTAUTH_ALLOWED:
+ val = "allowed";
+ break;
+ case SLAPD_SSLCLIENTAUTH_REQUIRED:
+ val = "required";
+ break;
+ default:
+ val = "allowed";
+ break;
+ }
+ }
+ if( config_set_SSLclientAuth( "nssslclientauth", val, errorbuf,
+ CONFIG_APPLY ) != LDAP_SUCCESS ) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Cannot set SSL Client "
+ "Authentication status to \"%s\", error (%s). "
+ "Supported values are \"off\", \"allowed\" "
+ "and \"required\". (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ val, errorbuf, errorCode, slapd_pr_strerror(errorCode));
+ }
+
+ freeConfigEntry( &e );
+
+ if(( slapd_SSLclientAuth = config_get_SSLclientAuth()) != SLAPD_SSLCLIENTAUTH_OFF ) {
+ int err;
+ switch (slapd_SSLclientAuth) {
+ case SLAPD_SSLCLIENTAUTH_ALLOWED:
+#ifdef SSL_REQUIRE_CERTIFICATE /* new feature */
+ if ((err = SSL_OptionSet (pr_sock, SSL_REQUIRE_CERTIFICATE, PR_FALSE)) < 0) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "SSL_OptionSet(SSL_REQUIRE_CERTIFICATE,PR_FALSE) %d "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ err, prerr, slapd_pr_strerror(prerr));
+ }
+#endif
+ /* Give the client a clear opportunity to send her certificate: */
+ case SLAPD_SSLCLIENTAUTH_REQUIRED:
+ if ((err = SSL_OptionSet (pr_sock, SSL_REQUEST_CERTIFICATE, PR_TRUE)) < 0) {
+ PRErrorCode prerr = PR_GetError();
+ LDAPDebug (LDAP_DEBUG_ANY,
+ "SSL_OptionSet(SSL_REQUEST_CERTIFICATE,PR_TRUE) %d "
+ SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ err, prerr, slapd_pr_strerror(prerr));
+ }
+ default: break;
+ }
+ }
+
+ /* Introduce a way of knowing whether slapd_ssl_init2 has
+ * already been executed.
+ * The cases in which slapd_ssl_init2 is executed during an
+ * Start TLS operation are not taken into account, for it is
+ * the fact of being executed by the server's SSL listener socket
+ * that matters. */
+
+ if (!startTLS)
+ _ssl_listener_initialized = 1; /* --ugaston */
+
+ return 0;
+}
+
+/* richm 20020227
+ To do LDAP client SSL init, we need to do
+
+ static void
+ ldapssl_basic_init( void )
+ {
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0);
+
+ PR_SetConcurrency( 4 );
+ }
+ NSS_Init(certdbpath);
+ SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE);
+ SSL_OptionSetDefault(SSL_ENABLE_SSLdirs
+3, PR_TRUE);
+#ifdef NS_DOMESTIC
+ s = NSS_SetDomesticPolicy();
+#elif NS_EXPORT
+ s = NSS_SetExportPolicy();
+
+We already do pr_init, we don't need pr_setconcurrency, we already do nss_init and the rest
+
+*/
+
+int
+slapd_SSL_client_init()
+{
+ return 0;
+}
+
+static int
+slapd_SSL_client_auth (LDAP* ld)
+{
+ int rc = 0;
+ PRErrorCode errorCode;
+ char* pw = NULL;
+ char ** family_list;
+ Slapi_Entry *entry = NULL;
+ char cert_name[1024];
+ char *token = NULL;
+#ifndef _WIN32
+ SVRCOREStdPinObj *StdPinObj;
+#else
+ SVRCOREAltPinObj *AltPinObj;
+#endif
+ SVRCOREError err = SVRCORE_Success;
+
+ if((family_list = getChildren(configDN))) {
+ char **family;
+ char *personality = NULL;
+ char *activation = NULL;
+ char *cipher = NULL;
+
+ for (family = family_list; *family; family++) {
+ getConfigEntry( *family, &entry );
+ if ( entry == NULL ) {
+ continue;
+ }
+
+ activation = slapi_entry_attr_get_charptr( entry, "nssslactivation" );
+ if((!activation) || (!strcasecmp(activation, "off"))) {
+ /* this family was turned off, goto next */
+ slapi_ch_free((void **) &activation);
+ freeConfigEntry( &entry );
+ continue;
+ }
+
+ slapi_ch_free((void **) &activation);
+
+ personality = slapi_entry_attr_get_charptr( entry, "nssslpersonalityssl" );
+ cipher = slapi_entry_attr_get_charptr( entry, "cn" );
+ if ( cipher && !strcasecmp(cipher, "RSA" )) {
+ char *ssltoken;
+
+ /* If there already is a token name, use it */
+ if (token) {
+ slapi_ch_free((void **) &personality);
+ slapi_ch_free((void **) &cipher);
+ freeConfigEntry( &entry );
+ continue;
+ }
+
+ ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" );
+ if( ssltoken && personality ) {
+ if( !strcasecmp(ssltoken, "internal") ||
+ !strcasecmp(ssltoken, "internal (software)") ) {
+
+ /* Translate config internal name to more
+ * readable form. Certificate name is just
+ * the personality for internal tokens.
+ */
+ token = slapi_ch_strdup(internalTokenName);
+ strcpy(cert_name, personality);
+ slapi_ch_free((void **) &ssltoken);
+ } else {
+ /* external PKCS #11 token - attach token name */
+ /*ssltoken was already dupped and we don't need it anymore*/
+ token = ssltoken;
+ sprintf(cert_name, "%s:%s", token, personality);
+ }
+ } else {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to get cipher "
+ "family information. Missing nsssltoken or"
+ "nssslpersonalityssl in %s ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ *family, errorCode, slapd_pr_strerror(errorCode));
+ slapi_ch_free((void **) &ssltoken);
+ slapi_ch_free((void **) &personality);
+ slapi_ch_free((void **) &cipher);
+ freeConfigEntry( &entry );
+ continue;
+ }
+ } else { /* external PKCS #11 cipher */
+ char *ssltoken;
+
+ ssltoken = slapi_entry_attr_get_charptr( entry, "nsssltoken" );
+ if( token && personality ) {
+
+ /* free the old token and remember the new one */
+ if (token) slapi_ch_free((void **)&token);
+ token = ssltoken; /*ssltoken was already dupped and we don't need it anymore*/
+
+ /* external PKCS #11 token - attach token name */
+ sprintf(cert_name, "%s:%s", token, personality);
+ } else {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("Security Initialization: Failed to get cipher "
+ "family information. Missing nsssltoken or"
+ "nssslpersonalityssl in %s ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ *family, errorCode, slapd_pr_strerror(errorCode));
+ slapi_ch_free((void **) &ssltoken);
+ slapi_ch_free((void **) &personality);
+ slapi_ch_free((void **) &cipher);
+ freeConfigEntry( &entry );
+ continue;
+ }
+
+ }
+ slapi_ch_free((void **) &personality);
+ slapi_ch_free((void **) &cipher);
+ freeConfigEntry( &entry );
+ } /* end of for */
+
+ freeChildren( family_list );
+ }
+
+ /* Free config data */
+
+ /* We cannot allow NSS to cache outgoing client auth connections -
+ each client auth connection must have it's own non-shared SSL
+ connection to the peer so that it will go through the
+ entire handshake protocol every time including the use of its
+ own unique client cert - see bug 605457
+ */
+
+ ldapssl_set_option(ld, SSL_NO_CACHE, PR_TRUE);
+
+#ifndef _WIN32
+ StdPinObj = (SVRCOREStdPinObj *)SVRCORE_GetRegisteredPinObj();
+ err = SVRCORE_StdPinGetPin( &pw, StdPinObj, token );
+#else
+ AltPinObj = (SVRCOREAltPinObj *)SVRCORE_GetRegisteredPinObj();
+ pw = SVRCORE_GetPin( (SVRCOREPinObj *)AltPinObj, token, PR_FALSE);
+#endif
+ if ( err != SVRCORE_Success || pw == NULL) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("SSL client authentication cannot be used "
+ "(no password). (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ errorCode, slapd_pr_strerror(errorCode));
+ } else {
+ rc = ldapssl_enable_clientauth (ld, SERVER_KEY_NAME, pw, cert_name);
+ if (rc != 0) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("ldapssl_enable_clientauth(%s, %s) %i ("
+ SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ SERVER_KEY_NAME, cert_name, rc,
+ errorCode, slapd_pr_strerror(errorCode));
+ }
+ }
+
+ if (token) slapi_ch_free((void**)&token);
+ slapi_ch_free((void**)&pw);
+
+ LDAPDebug (LDAP_DEBUG_TRACE, "slapd_SSL_client_auth() %i\n", rc, 0, 0);
+ return rc;
+}
+
+int
+slapd_simple_client_bind_s(LDAP* ld, char* DN, char* pw, int LDAPv)
+{
+ int rc;
+ PRErrorCode errorCode;
+
+ ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void *) &LDAPv);
+ rc = ldap_simple_bind_s (ld, DN, pw);
+ if (rc != 0) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("ldap_simple_bind_s(%s, %s) %i (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ DN, pw, rc, errorCode, slapd_pr_strerror(errorCode));
+ }
+ LDAPDebug (LDAP_DEBUG_TRACE, "slapd_simple_client_bind_s(%s, %i) %i\n", DN, LDAPv, rc);
+ return rc;
+}
+
+int
+slapd_SSL_client_bind_s (LDAP* ld, char* DN, char* pw, int use_SSL, int LDAPv)
+{
+ int rc;
+ struct berval noCred = {0, 0};
+
+ if (!use_SSL || LDAPv == LDAP_VERSION2) {
+ rc = slapd_simple_client_bind_s(ld, DN, pw, LDAPv);
+ } else {
+
+ LDAPDebug (
+ LDAP_DEBUG_TRACE,
+ "slapd_SSL_client_bind_s: Trying SSL Client Authentication\n",
+ 0, 0, 0);
+
+ rc = slapd_SSL_client_auth(ld);
+
+ if(rc != 0)
+ {
+ LDAPDebug (
+ LDAP_DEBUG_TRACE,
+ "slapd_SSL_client_bind_s: SSL Client Auth Failed during replication Bind\n",
+ 0, 0, 0);
+ return rc;
+ }
+
+ rc = ldap_sasl_bind_s (ld, "", LDAP_SASL_EXTERNAL, &noCred,
+ NULL /* LDAPControl **serverctrls */,
+ NULL /* LDAPControl **clientctrls */,
+ NULL /* struct berval **servercredp */);
+
+ }
+ LDAPDebug (
+ LDAP_DEBUG_TRACE,
+ "slapd_SSL_client_bind_s(%i,%i) %i\n", use_SSL, LDAPv, rc);
+ return rc;
+}
+
+int
+slapd_sasl_ext_client_bind (LDAP* ld, int **msgid)
+{
+ int rc;
+ PRErrorCode errorCode;
+ struct berval noCred = {0, 0};
+
+ LDAPDebug (
+ LDAP_DEBUG_TRACE,
+ "slapd_sasl_ext_client_bind: Trying SSL Client Authentication\n",
+ 0, 0, 0);
+
+ rc = slapd_SSL_client_auth(ld);
+ if(rc != 0)
+ {
+ LDAPDebug (
+ LDAP_DEBUG_TRACE,
+ "slapd_sasl_ext_client_bind: SSL Client Auth Failed during replication Bind\n",
+ 0, 0, 0);
+ return rc;
+ }
+
+ rc = ldap_sasl_bind (ld, "", LDAP_SASL_EXTERNAL, &noCred,
+ NULL,
+ NULL,
+ *msgid);
+ if (rc != 0) {
+ errorCode = PR_GetError();
+ slapd_SSL_warn("ldap_sasl_bind(\"\",LDAP_SASL_EXTERNAL) %i (" SLAPI_COMPONENT_NAME_NSPR " error %d - %s)",
+ rc, errorCode, slapd_pr_strerror(errorCode));
+ }
+
+ LDAPDebug (
+ LDAP_DEBUG_TRACE,
+ "slapd_sasl_ext_client_bind %i\n", rc, 0, 0);
+
+ return rc;
+}
+
+
+int slapd_Client_auth(LDAP* ld)
+{
+ int rc=0;
+
+ rc = slapd_SSL_client_auth (ld);
+
+ return rc;
+}
+
+
+/* Function for keeping track of the SSL initialization status:
+ * - returns 1: when slapd_ssl_init has been executed
+ */
+int
+slapd_security_library_is_initialized()
+{
+ return _security_library_initialized;
+}
+
+
+/* Function for keeping track of the SSL listener socket initialization status:
+ * - returns 1: when slapd_ssl_init2 has been executed
+ */
+int
+slapd_ssl_listener_is_initialized()
+{
+ return _ssl_listener_initialized;
+}
+
+
+char* slapd_get_tmp_dir()
+{
+ static char tmpdir[] = "/tmp";
+ static char tmp[256];
+ char* instanceDir;
+#if defined( XP_WIN32 )
+ unsigned ilen;
+ char pch;
+#endif
+ struct stat ffinfo;
+
+ tmp[0] = '\0';
+
+ if((instanceDir = config_get_instancedir()) == NULL)
+ {
+ slapi_log_error(
+ SLAPI_LOG_FATAL,
+ "slapd_get_tmp_dir",
+ "config_get_instancedir returns NULL Setting tmp dir to default\n");
+
+#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(stat(tmp,&ffinfo) == -1)
+#if defined( XP_WIN32 )
+ if(CreateDirectory(tmp, NULL) == 0)
+ {
+ slapi_log_error(
+ SLAPI_LOG_FATAL,
+ "slapd_get_tmp_dir",
+ "CreateDirectory(%s, NULL) Error: %s\n",
+ tmp, strerror(errno));
+ return ( tmpdir );
+ }
+#else
+ if(mkdir(tmp, 00770) == -1)
+ {
+ slapi_log_error(
+ SLAPI_LOG_FATAL,
+ "slapd_get_tmp_dir",
+ "mkdir(%s, 00770) Error: %s\n",
+ tmp, strerror(errno));
+ return ( tmpdir );
+ }
+#endif
+
+ return ( tmp );
+
+}
+
+#endif /* NET_SSL */
diff --git a/ldap/servers/slapd/sslerrstrs.h b/ldap/servers/slapd/sslerrstrs.h
new file mode 100644
index 00000000..5b63e3a7
--- /dev/null
+++ b/ldap/servers/slapd/sslerrstrs.h
@@ -0,0 +1,355 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * sslerrstrs.h - map SSL errors to strings (used by errormap.c)
+ *
+ */
+
+/*
+ ****************************************************************************
+ * The code below this point was provided by Nelson Bolyard <nelsonb> of the
+ * Netscape Certificate Server team on 27-March-1998.
+ * Taken from the file ns/security/cmd/lib/SSLerrs.h on NSS_1_BRANCH.
+ * Last updated from there: 24-July-1998 by Mark Smith <mcs>
+ *
+ * All of the Directory Server specific changes are enclosed inside
+ * #ifdef NS_DS.
+ ****************************************************************************
+ */
+
+/* SSL-specific security error codes */
+/* caller must include "sslerr.h" */
+
+ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0,
+"Unable to communicate securely. Peer does not support high-grade encryption.")
+
+ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1,
+"Unable to communicate securely. Peer requires high-grade encryption which is not supported.")
+
+ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2,
+"Cannot communicate securely with peer: no common encryption algorithm(s).")
+
+ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3,
+"Unable to find the certificate or key necessary for authentication.")
+
+ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4,
+"Unable to communicate securely with peer: peers's certificate was rejected.")
+
+/* unused (SSL_ERROR_BASE + 5),*/
+
+ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6,
+"The server has encountered bad data from the client.")
+
+ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7,
+"The client has encountered bad data from the server.")
+
+ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8,
+"Unsupported certificate type.")
+
+ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9,
+"Peer using unsupported version of security protocol.")
+
+/* unused (SSL_ERROR_BASE + 10),*/
+
+ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11,
+"Client authentication failed: private key in key database does not match public key in certificate database.")
+
+ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12,
+"Unable to communicate securely with peer: requested domain name does not match the server's certificate.")
+
+/* SSL_ERROR_POST_WARNING (SSL_ERROR_BASE + 13),
+ defined in sslerr.h
+*/
+
+ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14),
+"Peer only supports SSL version 2, which is locally disabled.")
+
+
+ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15),
+"SSL received a record with an incorrect Message Authentication Code.")
+
+ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16),
+"SSL peer reports incorrect Message Authentication Code.")
+
+ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17),
+"SSL peer cannot verify your certificate.")
+
+ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18),
+"SSL peer rejected your certificate as revoked.")
+
+ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19),
+"SSL peer rejected your certificate as expired.")
+
+ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20),
+"Cannot connect: SSL is disabled.")
+
+ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21),
+"Cannot connect: SSL peer is in another FORTEZZA domain.")
+
+
+ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE , (SSL_ERROR_BASE + 22),
+"An unknown SSL cipher suite has been requested.")
+
+ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED , (SSL_ERROR_BASE + 23),
+"No cipher suites are present and enabled in this program.")
+
+ER3(SSL_ERROR_BAD_BLOCK_PADDING , (SSL_ERROR_BASE + 24),
+"SSL received a record with bad block padding.")
+
+ER3(SSL_ERROR_RX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 25),
+"SSL received a record that exceeded the maximum permissible length.")
+
+ER3(SSL_ERROR_TX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 26),
+"SSL attempted to send a record that exceeded the maximum permissible length.")
+
+/*
+ * Received a malformed (too long or short or invalid content) SSL handshake.
+ */
+ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST , (SSL_ERROR_BASE + 27),
+"SSL received a malformed Hello Request handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO , (SSL_ERROR_BASE + 28),
+"SSL received a malformed Client Hello handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO , (SSL_ERROR_BASE + 29),
+"SSL received a malformed Server Hello handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE , (SSL_ERROR_BASE + 30),
+"SSL received a malformed Certificate handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 31),
+"SSL received a malformed Server Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST , (SSL_ERROR_BASE + 32),
+"SSL received a malformed Certificate Request handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE , (SSL_ERROR_BASE + 33),
+"SSL received a malformed Server Hello Done handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY , (SSL_ERROR_BASE + 34),
+"SSL received a malformed Certificate Verify handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 35),
+"SSL received a malformed Client Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_MALFORMED_FINISHED , (SSL_ERROR_BASE + 36),
+"SSL received a malformed Finished handshake message.")
+
+/*
+ * Received a malformed (too long or short) SSL record.
+ */
+ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER , (SSL_ERROR_BASE + 37),
+"SSL received a malformed Change Cipher Spec record.")
+
+ER3(SSL_ERROR_RX_MALFORMED_ALERT , (SSL_ERROR_BASE + 38),
+"SSL received a malformed Alert record.")
+
+ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE , (SSL_ERROR_BASE + 39),
+"SSL received a malformed Handshake record.")
+
+ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA , (SSL_ERROR_BASE + 40),
+"SSL received a malformed Application Data record.")
+
+/*
+ * Received an SSL handshake that was inappropriate for the state we're in.
+ * E.g. Server received message from server, or wrong state in state machine.
+ */
+ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST , (SSL_ERROR_BASE + 41),
+"SSL received an unexpected Hello Request handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO , (SSL_ERROR_BASE + 42),
+"SSL received an unexpected Client Hello handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO , (SSL_ERROR_BASE + 43),
+"SSL received an unexpected Server Hello handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE , (SSL_ERROR_BASE + 44),
+"SSL received an unexpected Certificate handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 45),
+"SSL received an unexpected Server Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST , (SSL_ERROR_BASE + 46),
+"SSL received an unexpected Certificate Request handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE , (SSL_ERROR_BASE + 47),
+"SSL received an unexpected Server Hello Done handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY , (SSL_ERROR_BASE + 48),
+"SSL received an unexpected Certificate Verify handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 49),
+"SSL received an unexpected Cllient Key Exchange handshake message.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED , (SSL_ERROR_BASE + 50),
+"SSL received an unexpected Finished handshake message.")
+
+/*
+ * Received an SSL record that was inappropriate for the state we're in.
+ */
+ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER , (SSL_ERROR_BASE + 51),
+"SSL received an unexpected Change Cipher Spec record.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 52),
+"SSL received an unexpected Alert record.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE , (SSL_ERROR_BASE + 53),
+"SSL received an unexpected Handshake record.")
+
+ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54),
+"SSL received an unexpected Application Data record.")
+
+/*
+ * Received record/message with unknown discriminant.
+ */
+ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE , (SSL_ERROR_BASE + 55),
+"SSL received a record with an unknown content type.")
+
+ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE , (SSL_ERROR_BASE + 56),
+"SSL received a handshake message with an unknown message type.")
+
+ER3(SSL_ERROR_RX_UNKNOWN_ALERT , (SSL_ERROR_BASE + 57),
+"SSL received an alert record with an unknown alert description.")
+
+/*
+ * Received an alert reporting what we did wrong. (more alerts above)
+ */
+ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT , (SSL_ERROR_BASE + 58),
+"SSL peer has closed this connection.")
+
+ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 59),
+"SSL peer was not expecting a handshake message it received.")
+
+ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT , (SSL_ERROR_BASE + 60),
+"SSL peer was unable to succesfully decompress an SSL record it received.")
+
+ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT , (SSL_ERROR_BASE + 61),
+"SSL peer was unable to negotiate an acceptable set of security parameters.")
+
+ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT , (SSL_ERROR_BASE + 62),
+"SSL peer rejected a handshake message for unacceptable content.")
+
+ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT , (SSL_ERROR_BASE + 63),
+"SSL peer does not support certificates of the type it received.")
+
+ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT , (SSL_ERROR_BASE + 64),
+"SSL peer had some unspecified issue with the certificate it received.")
+
+
+ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE , (SSL_ERROR_BASE + 65),
+"SSL experienced a failure of its random number generator.")
+
+ER3(SSL_ERROR_SIGN_HASHES_FAILURE , (SSL_ERROR_BASE + 66),
+"Unable to digitally sign data required to verify your certificate.")
+
+ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE , (SSL_ERROR_BASE + 67),
+"SSL was unable to extract the public key from the peer's certificate.")
+
+ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 68),
+"Unspecified failure while processing SSL Server Key Exchange handshake.")
+
+ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 69),
+"Unspecified failure while processing SSL Client Key Exchange handshake.")
+
+ER3(SSL_ERROR_ENCRYPTION_FAILURE , (SSL_ERROR_BASE + 70),
+"Bulk data encryption algorithm failed in selected cipher suite.")
+
+ER3(SSL_ERROR_DECRYPTION_FAILURE , (SSL_ERROR_BASE + 71),
+"Bulk data decryption algorithm failed in selected cipher suite.")
+
+ER3(SSL_ERROR_SOCKET_WRITE_FAILURE , (SSL_ERROR_BASE + 72),
+"Attempt to write encrypted data to underlying socket failed.")
+
+ER3(SSL_ERROR_MD5_DIGEST_FAILURE , (SSL_ERROR_BASE + 73),
+"MD5 digest function failed.")
+
+ER3(SSL_ERROR_SHA_DIGEST_FAILURE , (SSL_ERROR_BASE + 74),
+"SHA-1 digest function failed.")
+
+ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE , (SSL_ERROR_BASE + 75),
+"MAC computation failed.")
+
+ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE , (SSL_ERROR_BASE + 76),
+"Failure to create Symmetric Key context.")
+
+ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE , (SSL_ERROR_BASE + 77),
+"Failure to unwrap the Symmetric key in Client Key Exchange message.")
+
+ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED , (SSL_ERROR_BASE + 78),
+"SSL Server attempted to use domestic-grade public key with export cipher suite.")
+
+ER3(SSL_ERROR_IV_PARAM_FAILURE , (SSL_ERROR_BASE + 79),
+"PKCS11 code failed to translate an IV into a param.")
+
+ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE , (SSL_ERROR_BASE + 80),
+"Failed to initialize the selected cipher suite.")
+
+ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE , (SSL_ERROR_BASE + 81),
+"Client failed to generate session keys for SSL session.")
+
+ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG , (SSL_ERROR_BASE + 82),
+"Server has no key for the attempted key exchange algorithm.")
+
+ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL , (SSL_ERROR_BASE + 83),
+"PKCS#11 token was inserted or removed while operation was in progress.")
+
+ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND , (SSL_ERROR_BASE + 84),
+"No PKCS#11 token could be found to do a required operation.")
+
+ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP , (SSL_ERROR_BASE + 85),
+"Cannot communicate securely with peer: no common compression algorithm(s).")
+
+ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED , (SSL_ERROR_BASE + 86),
+"Cannot initiate another SSL handshake until current handshake is complete.")
+
+ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE , (SSL_ERROR_BASE + 87),
+"Received incorrect handshakes hash values from peer.")
+
+ER3(SSL_ERROR_CERT_KEA_MISMATCH , (SSL_ERROR_BASE + 88),
+"The certificate provided cannot be used with the selected key exchange algorithm.")
+
+ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA , (SSL_ERROR_BASE + 89),
+"No certificate authority is trusted for SSL client authentication.")
+
+ER3(SSL_ERROR_SESSION_NOT_FOUND , (SSL_ERROR_BASE + 90),
+"Client's SSL session ID not found in server's session cache.")
+
+ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT , (SSL_ERROR_BASE + 91),
+"Peer was unable to decrypt an SSL record it received.")
+
+ER3(SSL_ERROR_RECORD_OVERFLOW_ALERT , (SSL_ERROR_BASE + 92),
+"Peer received an SSL record that was longer than is permitted.")
+
+ER3(SSL_ERROR_UNKNOWN_CA_ALERT , (SSL_ERROR_BASE + 93),
+"Peer does not recognize and trust the CA that issued your certificate.")
+
+ER3(SSL_ERROR_ACCESS_DENIED_ALERT , (SSL_ERROR_BASE + 94),
+"Peer received a valid certificate, but access was denied.")
+
+ER3(SSL_ERROR_DECODE_ERROR_ALERT , (SSL_ERROR_BASE + 95),
+"Peer could not decode an SSL handshake message.")
+
+ER3(SSL_ERROR_DECRYPT_ERROR_ALERT , (SSL_ERROR_BASE + 96),
+"Peer reports failure of signature verification or key exchange.")
+
+ER3(SSL_ERROR_EXPORT_RESTRICTION_ALERT , (SSL_ERROR_BASE + 97),
+"Peer reports negotiation not in compliance with export regulations.")
+
+ER3(SSL_ERROR_PROTOCOL_VERSION_ALERT , (SSL_ERROR_BASE + 98),
+"Peer reports incompatible or unsupported protocol version.")
+
+ER3(SSL_ERROR_INSUFFICIENT_SECURITY_ALERT , (SSL_ERROR_BASE + 99),
+"Server requires ciphers more secure than those supported by client.")
+
+ER3(SSL_ERROR_INTERNAL_ERROR_ALERT , (SSL_ERROR_BASE + 100),
+"Peer reports it experienced an internal error.")
+
+ER3(SSL_ERROR_USER_CANCELED_ALERT , (SSL_ERROR_BASE + 101),
+"Peer user canceled handshake.")
+
+ER3(SSL_ERROR_NO_RENEGOTIATION_ALERT , (SSL_ERROR_BASE + 102),
+"Peer does not permit renegotiation of SSL security parameters.")
+
diff --git a/ldap/servers/slapd/start_tls_extop.c b/ldap/servers/slapd/start_tls_extop.c
new file mode 100644
index 00000000..523805f0
--- /dev/null
+++ b/ldap/servers/slapd/start_tls_extop.c
@@ -0,0 +1,479 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Start TLS - LDAP Extended Operation.
+ *
+ *
+ * This plugin implements the "Start TLS (Transport Layer Security)"
+ * extended operation for LDAP. The plugin function is called by
+ * the server if an LDAP client request contains the OID:
+ * "1.3.6.1.4.1.1466.20037".
+ *
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <private/pprio.h>
+
+
+#include <prio.h>
+#include <ssl.h>
+#include "slap.h"
+#include "slapi-plugin.h"
+#include "fe.h"
+
+
+
+
+/* OID of the extended operation handled by this plug-in */
+/* #define START_TLS_OID "1.3.6.1.4.1.1466.20037" */
+
+
+Slapi_PluginDesc exopdesc = { "start_tls_plugin", "Netscape", "0.1",
+ "Start TLS extended operation plugin" };
+
+
+
+
+/* Start TLS Extended operation plugin function */
+int
+start_tls( Slapi_PBlock *pb )
+{
+
+ char *oid;
+ Connection *conn;
+ PRFileDesc *oldsocket, *newsocket;
+ int secure;
+ int ns, oldnativesocket;
+ int rv;
+
+ /* Get the pb ready for sending Start TLS Extended Responses back to the client.
+ * The only requirement is to set the LDAP OID of the extended response to the START_TLS_OID. */
+
+ if ( slapi_pblock_set( pb, SLAPI_EXT_OP_RET_OID, START_TLS_OID ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Could not set extended response oid.\n" );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "Could not set extended response oid.", 0, NULL );
+ return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+ }
+
+
+ /* Before going any further, we'll make sure that the right extended operation plugin
+ * has been called: i.e., the OID shipped whithin the extended operation request must
+ * match this very plugin's OID: START_TLS_OID. */
+
+ if ( slapi_pblock_get( pb, SLAPI_EXT_OP_REQ_OID, &oid ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Could not get OID value from request.\n" );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "Could not get OID value from request.", 0, NULL );
+ return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Received extended operation request with OID %s\n", oid );
+ }
+
+ if ( strcasecmp( oid, START_TLS_OID ) != 0) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Request OID does not match Start TLS OID.\n" );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "Request OID does not match Start TLS OID.", 0, NULL );
+ return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Start TLS extended operation request confirmed.\n" );
+ }
+
+
+ /* At least we know that the request was indeed an Start TLS one. */
+
+ conn = pb->pb_conn;
+ PR_Lock( conn->c_mutex );
+#ifndef _WIN32
+ oldsocket = conn->c_prfd;
+ if ( oldsocket == (PRFileDesc *) NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Connection socket not available.\n" );
+ slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
+ "Connection socket not available.", 0, NULL );
+ goto unlock_and_return;
+ }
+#else
+ oldnativesocket = conn->c_sd;
+ oldsocket = PR_ImportTCPSocket(oldnativesocket);
+ if ( oldsocket == (PRFileDesc *) NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Failed to import NT native socket into NSPR.\n" );
+ slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
+ "Failed to import NT native socket into NSPR.", 0, NULL );
+ goto unlock_and_return;
+ }
+#endif
+
+ /* Check whether the Start TLS request can be accepted. */
+
+ if ( connection_operations_pending( conn, pb->pb_op,
+ 1 /* check for ops where result not yet sent */ )) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Other operations are still pending on the connection.\n" );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "Other operations are still pending on the connection.", 0, NULL );
+ goto unlock_and_return;
+ }
+
+
+ if ( !config_get_security() ) {
+ /* if any, here is where the referral to another SSL supporting server should be done: */
+ /* slapi_send_ldap_result( pb, LDAP_REFERRAL, NULL, msg, 0, url ); */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "SSL not supported by this server.\n" );
+ slapi_send_ldap_result( pb, LDAP_PROTOCOL_ERROR, NULL,
+ "SSL not supported by this server.", 0, NULL );
+ goto unlock_and_return;
+ }
+
+
+ if ( conn->c_flags & CONN_FLAG_SSL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "SSL connection already established.\n" );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "SSL connection already established.", 0, NULL );
+ goto unlock_and_return;
+ }
+
+ if ( conn->c_flags & CONN_FLAG_SASL_CONTINUE ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "SASL multi-stage bind in progress.\n" );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ "SASL multi-stage bind in progress.", 0, NULL );
+ goto unlock_and_return;
+ }
+
+
+ if ( conn->c_flags & CONN_FLAG_CLOSING ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Connection being closed at this moment.\n" );
+ slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
+ "Connection being closed at this moment.", 0, NULL );
+ goto unlock_and_return;
+ }
+
+
+
+ /* At first sight, there doesn't seem to be any major impediment to start TLS.
+ * So, we may as well try initialising SSL. */
+
+ if ( slapd_security_library_is_initialized() == 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "NSS libraries not initialised.\n" );
+ slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
+ "NSS libraries not initialised.", 0, NULL );
+ goto unlock_and_return;
+ }
+
+
+
+ /* Since no specific argument for denying the Start TLS request has been found,
+ * we send a success response back to the client. */
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Start TLS request accepted.Server willing to negotiate SSL.\n" );
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL,
+ "Start TLS request accepted.Server willing to negotiate SSL.", 0, NULL );
+
+
+ /* So far we have set up the environment for deploying SSL. It's now time to import the socket
+ * into SSL and to configure it consequently. */
+
+ if ( slapd_ssl_listener_is_initialized() != 0 ) {
+ PRFileDesc * ssl_listensocket;
+
+ ssl_listensocket = get_ssl_listener_fd();
+ if ( ssl_listensocket == (PRFileDesc *) NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "SSL listener socket not found.\n" );
+ slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
+ "SSL listener socket not found.", 0, NULL );
+ goto unlock_and_return;
+ }
+ newsocket = slapd_ssl_importFD( ssl_listensocket, oldsocket );
+ if ( newsocket == (PRFileDesc *) NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "SSL socket import failed.\n" );
+ slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
+ "SSL socket import failed.", 0, NULL );
+ goto unlock_and_return;
+ }
+ } else {
+ if ( slapd_ssl_init2( &oldsocket, 1 ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "SSL socket import or configuration failed.\n" );
+ slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
+ "SSL socket import or configuration failed.", 0, NULL );
+ goto unlock_and_return;
+ }
+ newsocket = oldsocket;
+ }
+
+
+ rv = slapd_ssl_resetHandshake( newsocket, 1 );
+ if ( rv != SECSuccess ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Unable to set socket ready for SSL handshake.\n" );
+ slapi_send_ldap_result( pb, LDAP_UNAVAILABLE, NULL,
+ "Unable to set socket ready for SSL handshake.", 0, NULL );
+ goto unlock_and_return;
+ }
+
+
+
+ /* From here on, messages will be sent through the SSL layer, so we need to get our
+ * connection ready. */
+
+ secure = 1;
+ ns = configure_pr_socket( &newsocket, secure );
+
+ /*
+ ber_sockbuf_set_option( conn->c_sb, LBER_SOCKBUF_OPT_DESC, &newsocket );
+ ber_sockbuf_set_option( conn->c_sb, LBER_SOCKBUF_OPT_READ_FN, (void *)secure_read_function );
+ ber_sockbuf_set_option( conn->c_sb, LBER_SOCKBUF_OPT_WRITE_FN, (void *)secure_write_function );
+ */
+
+ /*changed to */
+ {
+ struct lber_x_ext_io_fns *func_pointers = malloc(LBER_X_EXTIO_FNS_SIZE);
+ func_pointers->lbextiofn_size = LBER_X_EXTIO_FNS_SIZE;
+ func_pointers->lbextiofn_read = secure_read_function;
+ func_pointers->lbextiofn_write = secure_write_function;
+ func_pointers->lbextiofn_writev = NULL;
+ func_pointers->lbextiofn_socket_arg = (struct lextiof_socket_private *) newsocket;
+ ber_sockbuf_set_option( conn->c_sb,
+ LBER_SOCKBUF_OPT_EXT_IO_FNS, func_pointers);
+ free(func_pointers);
+ }
+ conn->c_flags |= CONN_FLAG_SSL;
+ conn->c_flags |= CONN_FLAG_START_TLS;
+ conn->c_sd = ns;
+ conn->c_prfd = newsocket;
+
+
+ rv = slapd_ssl_handshakeCallback (conn->c_prfd, (void *)handle_handshake_done, conn);
+
+ if ( rv < 0 ) {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error( SLAPI_LOG_FATAL, "start_tls",
+ "SSL_HandshakeCallback() %d " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ rv, prerr, slapd_pr_strerror( prerr ) );
+ }
+
+ if ( config_get_SSLclientAuth() != SLAPD_SSLCLIENTAUTH_OFF ) {
+ rv = slapd_ssl_badCertHook (conn->c_prfd, (void *)handle_bad_certificate, conn);
+ if ( rv < 0 ) {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error( SLAPI_LOG_FATAL, "start_tls",
+ "SSL_BadCertHook(%i) %i " SLAPI_COMPONENT_NAME_NSPR " error %d (%s)\n",
+ conn->c_sd, rv, prerr, slapd_pr_strerror( prerr ) );
+ }
+ }
+
+
+ /* Once agreed in starting TLS, the handshake must be carried out. */
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Starting SSL Handshake.\n" );
+
+ unlock_and_return:
+ PR_Unlock( conn->c_mutex );
+
+ return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+
+}/* start_tls */
+
+
+/* TLS Graceful Closure function.
+ * The function below kind of "resets" the connection to its state previous
+ * to receiving the Start TLS operation request. But it also sets the
+ * authorization and authentication credentials to "anonymous". Finally,
+ * it sends a closure alert message to the client.
+ *
+ * Note: start_tls_graceful_closure() must be called with c->c_mutex locked.
+ */
+int
+start_tls_graceful_closure( Connection *c, Slapi_PBlock * pb, int is_initiator )
+{
+ int ns;
+ Slapi_PBlock *pblock = pb;
+ struct slapdplugin *plugin;
+ int secure = 0;
+ PRFileDesc *ssl_fd;
+
+ if ( pblock == NULL ) {
+ pblock = slapi_pblock_new();
+ plugin = (struct slapdplugin *) slapi_ch_calloc( 1, sizeof( struct slapdplugin ) );
+ pblock->pb_plugin = plugin;
+ pblock->pb_conn = c;
+ pblock->pb_op = c->c_ops;
+ set_db_default_result_handlers( pblock );
+ if ( slapi_pblock_set( pblock, SLAPI_EXT_OP_RET_OID, START_TLS_OID ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Could not set extended response oid.\n" );
+ slapi_send_ldap_result( pblock, LDAP_OPERATIONS_ERROR, NULL,
+ "Could not set extended response oid.", 0, NULL );
+ return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+ }
+ slapi_ch_free( (void **) &plugin );
+ }
+
+ /* First thing to do is to finish with whatever operation may be hanging on the
+ * encrypted session.
+ */
+
+ while ( connection_operations_pending( c, pblock->pb_op,
+ 0 /* wait for all other ops to full complete */ )) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls",
+ "Still %d operations to be completed before closing the SSL connection.\n",
+ c->c_refcnt - 1 );
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_graceful_closure", "SSL_CLOSE_NOTIFY_ALERT\n" );
+
+ /* An SSL close_notify alert should be sent to the client. However, the NSS API
+ * doesn't provide us with anything alike.
+ */
+ slapi_send_ldap_result( pblock, LDAP_OPERATIONS_ERROR, NULL,
+ "SSL_CLOSE_NOTIFY_ALERT", 0, NULL );
+
+
+ if ( is_initiator ) {
+ /* if this call belongs to the initiator of the SSL connection closure, it must first
+ * wait for the peer to send another close_notify alert back.
+ */
+ }
+
+
+ PR_Lock( c->c_mutex );
+
+ /* "Unimport" the socket from SSL, i.e. get rid of the upper layer of the
+ * file descriptor stack, which represents SSL.
+ * The ssl socket assigned to c->c_prfd should also be closed and destroyed.
+ * Should find a way of getting that ssl socket.
+ */
+ /*
+ rc = strcasecmp( "SSL", PR_GetNameForIdentity( c->c_prfd->identity ) );
+ if ( rc == 0 ) {
+ sslSocket * ssl_socket;
+
+ ssl_socket = (sslSocket *) c->c_prfd->secret;
+ ssl_socket->fd = NULL;
+ }
+ */
+ ssl_fd = PR_PopIOLayer( c->c_prfd, PR_TOP_IO_LAYER );
+ ssl_fd->dtor( ssl_fd );
+
+
+#ifndef _WIN32
+ secure = 0;
+ ns = configure_pr_socket( &(c->c_prfd), secure );
+
+ ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_DESC, &(c->c_prfd) );
+
+#else
+ ns = PR_FileDesc2NativeHandle( c->c_prfd );
+ c->c_prfd = NULL;
+
+ configure_ns_socket( &ns );
+
+ ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_DESC, &ns );
+
+#endif
+
+ c->c_sd = ns;
+ c->c_flags &= ~CONN_FLAG_SSL;
+ c->c_flags &= ~CONN_FLAG_START_TLS;
+
+ ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_READ_FN, (void *)read_function );
+ ber_sockbuf_set_option( c->c_sb, LBER_SOCKBUF_OPT_WRITE_FN, (void *)write_function );
+
+
+ /* authentication & authorization credentials must be set to "anonymous". */
+
+ bind_credentials_clear( c, PR_FALSE, PR_TRUE );
+
+ PR_Unlock( c->c_mutex );
+
+
+
+ return ( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+}
+
+
+static char *start_tls_oid_list[] = {
+ START_TLS_OID,
+ NULL
+};
+static char *start_tls_name_list[] = {
+ "startTLS",
+ NULL
+};
+
+int start_tls_register_plugin()
+{
+ slapi_register_plugin( "extendedop", 1 /* Enabled */, "start_tls_init",
+ start_tls_init, "Start TLS extended operation",
+ start_tls_oid_list, NULL );
+
+ return 0;
+}
+
+
+/* Initialization function */
+
+int start_tls_init( Slapi_PBlock *pb )
+{
+ char **argv;
+ char *oid;
+
+ /* Get the arguments appended to the plugin extendedop directive. The first argument
+ * (after the standard arguments for the directive) should contain the OID of the
+ * extended operation.
+ */
+
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init", "Could not get argv\n" );
+ return( -1 );
+ }
+
+ /* Compare the OID specified in the configuration file against the Start TLS OID. */
+
+ if ( argv == NULL || strcmp( argv[0], START_TLS_OID ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init",
+ "OID is missing or is not %s\n", START_TLS_OID );
+ return( -1 );
+ } else {
+ oid = slapi_ch_strdup( argv[0] );
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init",
+ "Registering plug-in for Start TLS extended op %s.\n", oid );
+ }
+
+ /* Register the plug-in function as an extended operation
+ * plug-in function that handles the operation identified by
+ * OID 1.3.6.1.4.1.1466.20037. Also specify the version of the server
+ * plug-in */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&exopdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN, (void *) start_tls ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, start_tls_oid_list ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, start_tls_name_list ) != 0 ) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "start_tls_init",
+ "Failed to set plug-in version, function, and OID.\n" );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
diff --git a/ldap/servers/slapd/statechange.h b/ldap/servers/slapd/statechange.h
new file mode 100644
index 00000000..70ec3ab8
--- /dev/null
+++ b/ldap/servers/slapd/statechange.h
@@ -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 **/
+
+#ifndef _STATE_NOTIFY_H_
+#define _STATE_NOTIFY_H_
+
+/* mechanics */
+
+typedef void (*notify_callback)(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data);
+typedef void (*caller_data_free_callback)(void *caller_data);
+
+typedef int (*api_statechange_register)(char *caller_id, char *dn, char *filter, void *caller_data, notify_callback func);
+/* returns pointer to caller data passed to api_statechange_register */
+typedef void *(*api_statechange_unregister)(char *dn, char *filter, notify_callback func);
+typedef void (*api_statechange_unregister_all)(char *caller_id, caller_data_free_callback callback);
+
+/* API ID for slapi_apib_get_interface */
+
+#define StateChange_v1_0_GUID "0A340151-6FB3-11d3-80D2-006008A6EFF3"
+
+/* API */
+
+/* the api broker reserves api[0] for its use */
+
+#define statechange_register(api, caller_id, dn, filter, caller, func) \
+ ((api_statechange_register*)(api))[1]( caller_id, dn, filter, caller, func)
+
+#define statechange_unregister(api, dn, filter, func) \
+ ((api_statechange_unregister*)(api))[2]( dn, filter, func)
+
+#define statechange_unregister_all(api, caller_id, callback) \
+ ((api_statechange_unregister*)(api))[3](caller_id, callback)
+
+/* Vattr state change handler to be passed to statechange_register() by va sps*/
+#define statechange_vattr_cache_invalidator_callback(api) api[4]
+
+#define STATECHANGE_VATTR_GLOBAL_INVALIDATE 1
+#define STATECHANGE_VATTR_ENTRY_INVALIDATE 2
+
+/* Vattr api caller data to be passed to statechange_register() */
+static int vattr_global_invalidate = STATECHANGE_VATTR_GLOBAL_INVALIDATE;
+static int vattr_entry_invalidate = STATECHANGE_VATTR_ENTRY_INVALIDATE;
+
+#endif /*_STATE_NOTIFY_H_*/
diff --git a/ldap/servers/slapd/str2filter.c b/ldap/servers/slapd/str2filter.c
new file mode 100644
index 00000000..c3cb2e31
--- /dev/null
+++ b/ldap/servers/slapd/str2filter.c
@@ -0,0 +1,380 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* slapi_str2filter.c - parse an rfc 1588 string filter */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+
+static struct slapi_filter *str2list();
+static int str2subvals();
+
+struct slapi_filter *
+slapi_str2filter( char *str )
+{
+ struct slapi_filter *f = NULL;
+ char *end;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "slapi_str2filter \"%s\"\n", str, 0, 0 );
+
+ if ( str == NULL || *str == '\0' ) {
+ return( NULL );
+ }
+
+ switch ( *str ) {
+ case '(':
+ if ( (end = slapi_find_matching_paren( str )) == NULL ) {
+ slapi_filter_free( f, 1 );
+ return( NULL );
+ }
+ *end = '\0';
+
+ str++;
+ switch ( *str ) {
+ case '&':
+ LDAPDebug( LDAP_DEBUG_FILTER, "slapi_str2filter: AND\n",
+ 0, 0, 0 );
+
+ str++;
+ f = str2list( str, LDAP_FILTER_AND );
+ break;
+
+ case '|':
+ LDAPDebug( LDAP_DEBUG_FILTER, "put_filter: OR\n",
+ 0, 0, 0 );
+
+ str++;
+ f = str2list( str, LDAP_FILTER_OR );
+ break;
+
+ case '!':
+ LDAPDebug( LDAP_DEBUG_FILTER, "put_filter: NOT\n",
+ 0, 0, 0 );
+
+ str++;
+ f = str2list( str, LDAP_FILTER_NOT );
+ break;
+
+ default:
+ LDAPDebug( LDAP_DEBUG_FILTER, "slapi_str2filter: simple\n",
+ 0, 0, 0 );
+
+ f = str2simple( str , 1 /* unescape_filter */);
+ break;
+ }
+ *end = ')';
+ break;
+
+ default: /* assume it's a simple type=value filter */
+ LDAPDebug( LDAP_DEBUG_FILTER, "slapi_str2filter: default\n", 0, 0,
+ 0 );
+
+ f = str2simple( str , 1 /* unescape_filter */);
+ break;
+ }
+
+ return( f );
+}
+
+/*
+ * Put a list of filters like this "(filter1)(filter2)..."
+ */
+
+static struct slapi_filter *
+str2list( char *str, unsigned long ftype )
+{
+ struct slapi_filter *f;
+ struct slapi_filter **fp;
+ char *next;
+ char save;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "str2list \"%s\"\n", str, 0, 0 );
+
+ f = (struct slapi_filter *) slapi_ch_calloc( 1, sizeof(struct slapi_filter) );
+ f->f_choice = ftype;
+ fp = &f->f_list;
+
+ while ( *str ) {
+ while ( *str && ldap_utf8isspace( str ) )
+ LDAP_UTF8INC( str );
+ if ( *str == '\0' )
+ break;
+
+ if ( (next = slapi_find_matching_paren( str )) == NULL ) {
+ slapi_filter_free( f, 1 );
+ return( NULL );
+ }
+ save = *++next;
+ *next = '\0';
+
+ /* now we have "(filter)" with str pointing to it */
+ if ( (*fp = slapi_str2filter( str )) == NULL ) {
+ slapi_filter_free( f, 1 );
+ *next = save;
+ return( NULL );
+ }
+ *next = save;
+
+ str = next;
+ f->f_flags |= ((*fp)->f_flags & SLAPI_FILTER_LDAPSUBENTRY);
+ f->f_flags |= ((*fp)->f_flags & SLAPI_FILTER_TOMBSTONE);
+ fp = &(*fp)->f_next;
+ }
+ *fp = NULL;
+ filter_compute_hash(f);
+
+ return( f );
+}
+
+static char*
+str_find_star (char* s)
+ /* Like strchr(s, '*'), except ignore "\*" */
+{
+ char* r;
+ if (s == NULL) return s;
+ r = strchr (s, '*');
+ if (r != s) while (r != NULL && r[-1] == '\\') {
+ r = strchr (r+1, '*');
+ }
+ return r;
+}
+
+
+/*
+ * unescape a string into another buffer -- note that an unescaped ldap
+ * string may contain nulls if 'binary' is set! this is sort of a mix
+ * between the LDAP SDK version and terry hayes' version. optimally it
+ * would be nice if the LDAP SDK exported something like this.
+ *
+ * if 'binary' is set, "\00" is allowed, otherwise it's not.
+ *
+ * returns: 0 on error, 1 on success
+ * (*outlen) is the actual length of the unescaped string
+ */
+static int
+filt_unescape_str(const char *instr, char *outstr, size_t outsize, size_t* outlen, int binary)
+{
+ const char *inp;
+ char *outp;
+ int ival;
+ *outlen = 0;
+
+ if (!outstr) return -1;
+ for (inp = instr, outp = outstr; *inp; inp++)
+ {
+ if (! outsize)
+ return 0; /* fail */
+ if (*inp == '\\')
+ {
+ if (! *(++inp))
+ return 0; /* fail */
+ if (((ival = hexchar2int(inp[0])) < 0) || (hexchar2int(inp[1]) < 0))
+ {
+ /* LDAPv2 (RFC1960) escape sequence */
+ *outp++ = *inp;
+ (*outlen)++, outsize--;
+ }
+ else
+ {
+ /* LDAPv3 hex escape sequence */
+ if (! *(++inp))
+ return 0; /* fail */
+ *outp = (ival << 4) | hexchar2int(*inp);
+ if ((!binary) && (!*outp))
+ return 0; /* fail: "\00" not allowed unless it's binary */
+ outp++;
+ (*outlen)++, outsize--;
+ }
+ }
+ else
+ {
+ *outp++ = *inp;
+ (*outlen)++, outsize--;
+ }
+ }
+ return 1; /* ok */
+}
+
+
+/*
+ * The caller unescapes it if unescape_filter == 0.
+ */
+struct slapi_filter *
+str2simple( char *str , int unescape_filter)
+{
+ struct slapi_filter *f;
+ char *s;
+ char *value, savechar;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "str2simple \"%s\"\n", str, 0, 0 );
+
+ if ( (s = strchr( str, '=' )) == NULL ) {
+ return( NULL );
+ }
+ value = s;
+ LDAP_UTF8INC(value);
+ LDAP_UTF8DEC(s);
+
+ f = (struct slapi_filter *) slapi_ch_calloc( 1, sizeof(struct slapi_filter) );
+
+ switch ( *s ) {
+ case '<':
+ f->f_choice = LDAP_FILTER_LE;
+ break;
+ case '>':
+ f->f_choice = LDAP_FILTER_GE;
+ break;
+ case '~':
+ f->f_choice = LDAP_FILTER_APPROX;
+ break;
+ default:
+ LDAP_UTF8INC(s);
+ if ( str_find_star( value ) == NULL ) {
+ f->f_choice = LDAP_FILTER_EQUALITY;
+ } else if ( strcmp( value, "*" ) == 0 ) {
+ f->f_choice = LDAP_FILTER_PRESENT;
+ } else {
+ f->f_choice = LDAP_FILTER_SUBSTRINGS;
+ savechar = *s;
+ *s = 0;
+ f->f_sub_type = slapi_ch_strdup( str );
+ *s = savechar;
+ if ( str2subvals( value, f , unescape_filter) != 0 ) {
+ slapi_filter_free( f, 1 );
+ return( NULL );
+ }
+ filter_compute_hash(f);
+ return( f );
+ }
+ break;
+ }
+
+ if ( f->f_choice == LDAP_FILTER_PRESENT ) {
+ savechar = *s;
+ *s = 0;
+ f->f_type = slapi_ch_strdup( str );
+ *s = savechar;
+ } else if ( unescape_filter ) {
+ int r;
+ char *unqstr;
+ size_t len = strlen(value), len2;
+
+ /* dup attr */
+ savechar = *s;
+ *s = 0;
+ f->f_avtype = slapi_ch_strdup( str );
+ *s = savechar;
+
+ /* dup value */
+ savechar = value[len];
+ value[len] = 0;
+ unqstr = slapi_ch_calloc( 1, len+1);
+ r= filt_unescape_str(value, unqstr, len, &len2, 1);
+ value[len] = savechar;
+ if (!r) {
+ slapi_filter_free(f, 1);
+ return NULL;
+ }
+ f->f_avvalue.bv_val = unqstr;
+ f->f_avvalue.bv_len = len2;
+
+ if((f->f_choice == LDAP_FILTER_EQUALITY) &&
+ (0 == strncasecmp (str,"objectclass",strlen("objectclass")))) {
+ if (0 == strcasecmp (unqstr,"ldapsubentry"))
+ f->f_flags |= SLAPI_FILTER_LDAPSUBENTRY;
+ if (0 == strcasecmp (unqstr,SLAPI_ATTR_VALUE_TOMBSTONE))
+ f->f_flags |= SLAPI_FILTER_TOMBSTONE;
+ }
+ } if ( !unescape_filter ) {
+ f->f_avtype = slapi_ch_strdup( str );
+ f->f_avvalue.bv_val = slapi_ch_strdup ( value );
+ f->f_avvalue.bv_len = strlen ( f->f_avvalue.bv_val );
+ }
+
+ filter_compute_hash(f);
+ return( f );
+}
+
+static int
+str2subvals( char *val, struct slapi_filter *f, int unescape_filter )
+{
+ char *nextstar, *unqval;
+ int gotstar;
+ size_t len, outlen;
+
+ LDAPDebug( LDAP_DEBUG_FILTER, "str2subvals \"%s\"\n", val, 0, 0 );
+
+ gotstar = 0;
+ while ( val != NULL && *val ) {
+ if ( (nextstar = str_find_star( val )) != NULL )
+ *nextstar = '\0';
+
+ if ( unescape_filter ) {
+ len = strlen(val);
+ unqval = slapi_ch_malloc(len+1);
+ if (!filt_unescape_str(val, unqval, len, &outlen, 0)) {
+ slapi_ch_free((void **)&unqval);
+ return -1;
+ }
+ unqval[outlen]= '\0';
+ } else {
+ unqval = slapi_ch_strdup ( val );
+ }
+ if (unqval && unqval[0]) {
+ if (gotstar == 0) {
+ f->f_sub_initial = unqval;
+ } else if ( nextstar == NULL ) {
+ f->f_sub_final = unqval;
+ } else {
+ charray_add( &f->f_sub_any, unqval );
+ }
+ } else {
+ slapi_ch_free((void **)&unqval);
+ }
+
+ gotstar = 1;
+ if ( nextstar != NULL )
+ *nextstar++ = '*';
+ val = nextstar;
+ }
+
+ return( 0 );
+}
+
+/*
+ * find_matching_paren - return a pointer to the right paren in s matching
+ * the left paren to which *s currently points
+ */
+
+char *
+slapi_find_matching_paren( const char *s )
+{
+ int balance, escape;
+
+ balance = 0;
+ escape = 0;
+ for ( ; *s; s++ ) {
+ if ( escape == 0 ) {
+ if ( *s == '(' )
+ balance++;
+ else if ( *s == ')' )
+ balance--;
+ }
+ if ( balance == 0 ) {
+ return( (char *)s );
+ }
+ if ( *s == '\\' && ! escape )
+ escape = 1;
+ else
+ escape = 0;
+ }
+
+ return( NULL );
+}
diff --git a/ldap/servers/slapd/strdup.c b/ldap/servers/slapd/strdup.c
new file mode 100644
index 00000000..b25d6485
--- /dev/null
+++ b/ldap/servers/slapd/strdup.c
@@ -0,0 +1,25 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#if defined( ultrix ) || defined( nextstep )
+
+#include <string.h>
+
+
+char *strdup( char *s )
+{
+ char *p;
+
+ if ( (p = (char *) malloc( strlen( s ) + 1 )) == NULL )
+ return( NULL );
+
+ strcpy( p, s );
+
+ return( p );
+}
+
+#else
+typedef int SHUT_UP_DAMN_COMPILER;
+#endif /* ultrix || nextstep */
diff --git a/ldap/servers/slapd/stubrepl.c b/ldap/servers/slapd/stubrepl.c
new file mode 100644
index 00000000..83607bc6
--- /dev/null
+++ b/ldap/servers/slapd/stubrepl.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 **/
+/* stubrepl.c - stubs of functions required for the evil stuff in the tools directory */
+
+#include "slap.h"
+
+int connection_type = -1;
+
+void
+ps_service_persistent_searches( Slapi_Entry *e, Slapi_Entry *eprev, int chgtype, int chgnum )
+{
+}
+
+void
+ps_wakeup_all( void )
+{
+}
+
+int
+slapd_ssl_init()
+{
+ return( -1 );
+}
+
+int
+slapd_ssl_init2(PRFileDesc **fd, int startTLS)
+{
+ return( -1 );
+}
+
+void
+connection_abandon_operations( Connection *conn )
+{
+}
+
+void
+disconnect_server( Connection *conn, int opconnid, int opid, PRErrorCode reason, PRInt32 error )
+{
+}
diff --git a/ldap/servers/slapd/stubs.c b/ldap/servers/slapd/stubs.c
new file mode 100644
index 00000000..0440cedf
--- /dev/null
+++ b/ldap/servers/slapd/stubs.c
@@ -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 **/
+
+/* Needed because not all functions are currently defined for server3_branch */
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include "slap.h"
+
+#if defined( XP_WIN32 ) /* PK*/
+void *dlsym(void *a, char *b)
+{
+ return 0;
+}
+#endif
+
+int type_to_ACCESS_bit( char *p )
+{
+ return 0;
+}
+
+void *PT_Lock( PRLock *x_mutex )
+{
+ return NULL;
+}
+
+int lcache_init(LDAP *ld, void *arg)
+{
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "lcache_init: Shouldn't have been called\n", 0,0,0);
+ return -1;
+}
diff --git a/ldap/servers/slapd/subentry.c b/ldap/servers/slapd/subentry.c
new file mode 100644
index 00000000..b178115c
--- /dev/null
+++ b/ldap/servers/slapd/subentry.c
@@ -0,0 +1,56 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* Code to implement subentries
+*/
+
+/* This is the plan for subentries :
+
+ For updates, they're like regular entries.
+
+ For searches, we need to do special stuff:
+ We need to examine the search filter.
+ If it contains a branch of the form "objectclass=ldapsubentry",
+ then we don't need to do anything special.
+ If it does not, we need to do special stuff:
+ We need to and a filter clause "!objectclass=ldapsubentry"
+ to the filter.
+ The intention is that no entries having objectclass "ldapsubentry"
+ should be returned to the client.
+
+ Now, I feel confident that this will all work, but it poses some
+ performance problems. Looking for the filter branch could be
+ inefficient. Adding an extra filter test to every operation
+ is likely to slow the very operations we care about most.
+
+ Need to think about the best way to optimize this, perhaps using an IDL cache.
+
+ */
+
+#include "slap.h"
+
+/* Function intended to be called only from inside get_filter, so look for subentry search filters */
+int subentry_check_filter(Slapi_Filter *f)
+{
+ if ( 0 == strcasecmp ( f->f_avvalue.bv_val, "ldapsubentry")) {
+ /* Need to remember this so we avoid rewriting the filter later */
+ return 1; /* Clear the re-write flag, since we've seen the subentry filter element */
+ }
+ return 0; /* Set the rewrite flag */
+}
+
+/* Function which wraps a filter with (AND !(objectclass=ldapsubentry)) */
+void subentry_create_filter(Slapi_Filter** filter)
+{
+ Slapi_Filter *sub_filter = NULL;
+ Slapi_Filter *new_filter = NULL;
+ char *buf = slapi_ch_strdup("(!(objectclass=ldapsubentry))");
+ sub_filter = slapi_str2filter( buf );
+ new_filter = slapi_filter_join( LDAP_FILTER_AND, *filter, sub_filter );
+ *filter = new_filter;
+ slapi_ch_free((void **)&buf);
+}
+
diff --git a/ldap/servers/slapd/task.c b/ldap/servers/slapd/task.c
new file mode 100644
index 00000000..7e4bd423
--- /dev/null
+++ b/ldap/servers/slapd/task.c
@@ -0,0 +1,1703 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * directory online tasks (import, export, backup, restore)
+ */
+
+#include "slap.h"
+
+
+/* don't panic, this is only used when creating new tasks or removing old
+ * ones...
+ */
+static Slapi_Task *global_task_list = NULL;
+static PRLock *global_task_lock = NULL;
+static int shutting_down = 0;
+
+
+#define TASK_BASE_DN "cn=tasks, cn=config"
+#define TASK_IMPORT_DN "cn=import, cn=tasks, cn=config"
+#define TASK_EXPORT_DN "cn=export, cn=tasks, cn=config"
+#define TASK_BACKUP_DN "cn=backup, cn=tasks, cn=config"
+#define TASK_RESTORE_DN "cn=restore, cn=tasks, cn=config"
+#define TASK_INDEX_DN "cn=index, cn=tasks, cn=config"
+#if defined(UPGRADEDB)
+#define TASK_UPGRADEDB_DN "cn=upgradedb, cn=tasks, cn=config"
+#endif
+
+#define TASK_LOG_NAME "nsTaskLog"
+#define TASK_STATUS_NAME "nsTaskStatus"
+#define TASK_EXITCODE_NAME "nsTaskExitCode"
+#define TASK_PROGRESS_NAME "nsTaskCurrentItem"
+#define TASK_WORK_NAME "nsTaskTotalItems"
+
+#define DEFAULT_TTL "120" /* seconds */
+
+
+static int task_modify(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
+static int task_deny(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg);
+static int task_generic_destructor(Slapi_Task *task);
+
+/* create new task, fill in DN, and setup modify callback */
+static Slapi_Task *new_task(const char *dn)
+{
+ Slapi_Task *task = (Slapi_Task *)slapi_ch_calloc(1, sizeof(Slapi_Task));
+
+ if (task == NULL)
+ return NULL;
+ PR_Lock(global_task_lock);
+ task->next = global_task_list;
+ global_task_list = task;
+ PR_Unlock(global_task_lock);
+
+ task->task_dn = slapi_ch_strdup(dn);
+ task->destructor = task_generic_destructor;
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", task_modify, (void *)task);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_BASE, "(objectclass=*)", task_deny, NULL);
+ /* don't add entries under this one */
+#if 0
+ /* don't know why, but this doesn't work. it makes the current add
+ * operation fail. :(
+ */
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP, dn,
+ LDAP_SCOPE_SUBTREE, "(objectclass=*)", task_deny, NULL);
+#endif
+
+ return task;
+}
+
+/* called by the event queue to destroy a task */
+static void destroy_task(time_t when, void *arg)
+{
+ Slapi_Task *task = (Slapi_Task *)arg;
+ Slapi_Task *t1;
+ Slapi_PBlock *pb = slapi_pblock_new();
+
+ if (task->destructor != NULL)
+ (*task->destructor)(task);
+
+ /* if when == 0, we're already locked (called during shutdown) */
+ if (when != 0) {
+ PR_Lock(global_task_lock);
+ }
+ if (global_task_list == task) {
+ global_task_list = task->next;
+ } else {
+ for (t1 = global_task_list; t1; t1 = t1->next) {
+ if (t1->next == task) {
+ t1->next = task->next;
+ break;
+ }
+ }
+ }
+ if (when != 0) {
+ PR_Unlock(global_task_lock);
+ }
+
+ slapi_config_remove_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP,
+ task->task_dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_modify);
+ slapi_config_remove_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP,
+ task->task_dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_deny);
+ slapi_delete_internal_set_pb(pb, task->task_dn, NULL, NULL,
+ (void *)plugin_get_default_component_id(), 0);
+
+ slapi_delete_internal_pb(pb);
+ slapi_pblock_destroy(pb);
+
+ slapi_ch_free((void **)&task->task_dn);
+ slapi_ch_free((void **)&task);
+}
+
+
+/********** some useful helper functions **********/
+
+
+/* extract a single value from the entry (as a string) -- if it's not in the
+ * entry, the default will be returned (which can be NULL).
+ * you do not need to free anything returned by this.
+ */
+static const char *fetch_attr(Slapi_Entry *e, const char *attrname,
+ const char *default_val)
+{
+ Slapi_Attr *attr;
+ Slapi_Value *val = NULL;
+
+ if (slapi_entry_attr_find(e, attrname, &attr) != 0)
+ return default_val;
+ slapi_attr_first_value(attr, &val);
+ return slapi_value_get_string(val);
+}
+
+/* supply the pblock, destroy it when you're done */
+static Slapi_Entry *get_internal_entry(Slapi_PBlock *pb, char *dn)
+{
+ Slapi_Entry **entries = NULL;
+ int ret = 0;
+
+ slapi_search_internal_set_pb(pb, dn, LDAP_SCOPE_BASE, "(objectclass=*)",
+ NULL, 0, NULL, NULL, (void *)plugin_get_default_component_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't find task entry '%s'\n",
+ dn, 0, 0);
+ return NULL;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if ((NULL == entries) || (NULL == entries[0])) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't find task entry '%s'\n",
+ dn, 0, 0);
+ return NULL;
+ }
+ return entries[0];
+}
+
+static void modify_internal_entry(char *dn, LDAPMod **mods)
+{
+ Slapi_PBlock pb;
+ Slapi_Operation *op;
+ int ret = 0;
+ int tries = 0;
+ int dont_write_file = 1;
+
+ do {
+
+ pblock_init(&pb);
+
+ slapi_modify_internal_set_pb(&pb, dn, mods, NULL, NULL,
+ (void *)plugin_get_default_component_id(), 0);
+
+ /* all modifications to the cn=tasks subtree are transient --
+ * we erase them all when the server starts up next time, so there's
+ * no need to save them in the dse file.
+ */
+
+ slapi_pblock_set(&pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &dont_write_file);
+ /* Make sure these mods are not logged in audit or changelog */
+ slapi_pblock_get(&pb, SLAPI_OPERATION, &op);
+ operation_set_flag(op, OP_FLAG_ACTION_NOLOG);
+
+ slapi_modify_internal_pb(&pb);
+ slapi_pblock_get(&pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != LDAP_SUCCESS) {
+ /* could be waiting for another thread to finish adding this
+ * entry -- try at least 3 times before giving up.
+ */
+ tries++;
+ if (tries == 3) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: can't modify task "
+ "entry '%s'; %s (%d)\n", dn, ldap_err2string(ret), ret);
+ pblock_done(&pb);
+ return;
+ }
+ DS_Sleep(PR_SecondsToInterval(1));
+ }
+
+ pblock_done(&pb);
+
+ } while (ret != LDAP_SUCCESS);
+}
+
+
+/********** helper functions for dealing with task logging **********/
+
+#define LOG_BUFFER 256
+/* if the cumul. log gets larger than this, it's truncated: */
+#define MAX_SCROLLBACK_BUFFER 8192
+
+/* this changes the 'nsTaskStatus' value, which is transient (anything logged
+ * here wipes out any previous status)
+ */
+void slapi_task_log_status(Slapi_Task *task, char *format, ...)
+{
+ va_list ap;
+
+ if (! task->task_status)
+ task->task_status = (char *)slapi_ch_malloc(10 * LOG_BUFFER);
+ if (! task->task_status)
+ return; /* out of memory? */
+
+ va_start(ap, format);
+ PR_vsnprintf(task->task_status, (10 * LOG_BUFFER), format, ap);
+ va_end(ap);
+ slapi_task_status_changed(task);
+}
+
+/* this adds a line to the 'nsTaskLog' value, which is cumulative (anything
+ * logged here is added to the end)
+ */
+void slapi_task_log_notice(Slapi_Task *task, char *format, ...)
+{
+ va_list ap;
+ char buffer[LOG_BUFFER];
+ size_t len;
+
+ va_start(ap, format);
+ PR_vsnprintf(buffer, LOG_BUFFER, format, ap);
+ va_end(ap);
+
+ len = 2 + strlen(buffer) + (task->task_log ? strlen(task->task_log) : 0);
+ if (len > MAX_SCROLLBACK_BUFFER) {
+ size_t i;
+ char *newbuf;
+
+ /* start from middle of buffer, and find next linefeed */
+ i = strlen(task->task_log)/2;
+ while (task->task_log[i] && (task->task_log[i] != '\n'))
+ i++;
+ if (task->task_log[i])
+ i++;
+ len = strlen(task->task_log) - i + 2 + strlen(buffer);
+ newbuf = (char *)slapi_ch_malloc(len);
+ if (! newbuf)
+ return; /* out of memory? */
+ strcpy(newbuf, task->task_log + i);
+ slapi_ch_free((void **)&task->task_log);
+ task->task_log = newbuf;
+ } else {
+ if (! task->task_log) {
+ task->task_log = (char *)slapi_ch_malloc(len);
+ task->task_log[0] = 0;
+ } else {
+ task->task_log = (char *)slapi_ch_realloc(task->task_log, len);
+ }
+ if (! task->task_log)
+ return; /* out of memory? */
+ }
+
+ if (task->task_log[0])
+ strcat(task->task_log, "\n");
+ strcat(task->task_log, buffer);
+
+ slapi_task_status_changed(task);
+}
+
+static int task_generic_destructor(Slapi_Task *task)
+{
+ if (task->task_log) {
+ slapi_ch_free((void **)&task->task_log);
+ }
+ if (task->task_status) {
+ slapi_ch_free((void **)&task->task_status);
+ }
+ task->task_log = task->task_status = NULL;
+ return 0;
+}
+
+
+/********** actual task callbacks **********/
+
+
+static int task_deny(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg)
+{
+ /* internal operations (conn=NULL) are allowed to do whatever they want */
+ if (pb->pb_conn == NULL) {
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+}
+
+static int task_modify(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg)
+{
+ Slapi_Task *task = (Slapi_Task *)arg;
+ LDAPMod **mods;
+ int i;
+
+ /* the connection block will be NULL for internal operations */
+ if (pb->pb_conn == NULL) {
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+ }
+
+ /* ignore eAfter, just scan the mods for anything unacceptable */
+ slapi_pblock_get(pb, SLAPI_MODIFY_MODS, &mods);
+ for (i = 0; mods[i] != NULL; i++) {
+ /* for some reason, "modifiersName" and "modifyTimestamp" are
+ * stuck in by the server */
+ if ((strcasecmp(mods[i]->mod_type, "ttl") != 0) &&
+ (strcasecmp(mods[i]->mod_type, "nsTaskCancel") != 0) &&
+ (strcasecmp(mods[i]->mod_type, "modifiersName") != 0) &&
+ (strcasecmp(mods[i]->mod_type, "modifyTimestamp") != 0)) {
+ /* you aren't allowed to change this! */
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+
+ /* okay, we've decided to accept these changes. now look at the new
+ * entry and absorb any new values.
+ */
+ if (strcasecmp(fetch_attr(eAfter, "nsTaskCancel", "false"), "true") == 0) {
+ /* cancel this task, if not already */
+ if (task->task_state != SLAPI_TASK_CANCELLED) {
+ task->task_state = SLAPI_TASK_CANCELLED;
+ if (task->cancel) {
+ (*task->cancel)(task);
+ LDAPDebug(LDAP_DEBUG_ANY, "Cancelling task '%s'\n",
+ fetch_attr(eAfter, "cn", "?"), 0, 0);
+ }
+ }
+ }
+ /* we fetch ttl from the entry when it's needed */
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static int task_import_add(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg)
+{
+ Slapi_Attr *attr;
+ Slapi_Value *val = NULL;
+ Slapi_Backend *be = NULL;
+ const char *cn, *instance_name;
+ char **ldif_file = NULL, **include = NULL, **exclude = NULL;
+ int idx, rv = 0;
+ const char *do_attr_indexes, *uniqueid_kind_str;
+ int uniqueid_kind = SLAPI_UNIQUEID_GENERATE_TIME_BASED;
+ Slapi_PBlock mypb;
+ Slapi_Task *task;
+ char *nameFrombe_name = NULL;
+ const char *encrypt_on_import = NULL;
+
+ if ((cn = fetch_attr(e, "cn", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ instance_name = fetch_attr(e, "nsInstance", NULL);
+
+ encrypt_on_import = fetch_attr(e, "nsImportEncrypt", NULL);
+
+ /* include/exclude suffixes */
+ if (slapi_entry_attr_find(e, "nsIncludeSuffix", &attr) == 0) {
+ for (idx = slapi_attr_first_value(attr, &val);
+ idx >= 0; idx = slapi_attr_next_value(attr, idx, &val)) {
+ charray_add(&include, slapi_ch_strdup(slapi_value_get_string(val)));
+ }
+ }
+ if (slapi_entry_attr_find(e, "nsExcludeSuffix", &attr) == 0) {
+ for (idx = slapi_attr_first_value(attr, &val);
+ idx >= 0; idx = slapi_attr_next_value(attr, idx, &val)) {
+ charray_add(&exclude, slapi_ch_strdup(slapi_value_get_string(val)));
+ }
+ }
+
+ /*
+ * if instance is given, just use it to get the backend.
+ * otherwise, we use included/excluded suffix list to specify a backend.
+ */
+ if (NULL == instance_name) {
+ char **instances, **ip;
+ int counter;
+
+ if (slapi_lookup_instance_name_by_suffixes(include, exclude,
+ &instances) < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: No backend instance is specified.\n", 0, 0, 0);
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ if (instances) {
+ for (ip = instances, counter = 0; ip && *ip; ip++, counter++)
+ ;
+
+ if (counter == 1){
+ instance_name = *instances;
+ nameFrombe_name = *instances;
+
+ }
+ else if (counter == 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: No backend instance is specified.\n", 0, 0, 0);
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: Multiple backend instances are specified: "
+ "%s, %s, ...\n", instances[0], instances[1], 0);
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ } else {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ }
+
+ /* lookup the backend */
+ be = slapi_be_select_by_instance_name(instance_name);
+ if (be == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "can't import to nonexistent backend %s\n",
+ instance_name, 0, 0);
+ slapi_ch_free_string(&nameFrombe_name);
+ *returncode = LDAP_NO_SUCH_OBJECT;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* refuse to do an import on pre-V3 plugins. plugin api V3 is the one
+ * for DS 5.0 where the import/export stuff changed a lot.
+ */
+ if (! SLAPI_PLUGIN_IS_V3(be->be_database)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "can't perform an import with pre-V3 "
+ "backend plugin %s\n", be->be_database->plg_name, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ slapi_ch_free_string(&nameFrombe_name);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ if (be->be_database->plg_ldif2db == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: no ldif2db function defined for "
+ "backend %s\n", be->be_database->plg_name, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ slapi_ch_free_string(&nameFrombe_name);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* get ldif filenames -- from here on, memory has been allocated */
+ if (slapi_entry_attr_find(e, "nsFilename", &attr) != 0) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ slapi_ch_free_string(&nameFrombe_name);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ for (idx = slapi_attr_first_value(attr, &val);
+ idx >= 0; idx = slapi_attr_next_value(attr, idx, &val)) {
+ charray_add(&ldif_file, slapi_ch_strdup(slapi_value_get_string(val)));
+ }
+
+ do_attr_indexes = fetch_attr(e, "nsImportIndexAttrs", "true");
+ uniqueid_kind_str = fetch_attr(e, "nsUniqueIdGenerator", NULL);
+ if (uniqueid_kind_str != NULL) {
+ if (strcasecmp(uniqueid_kind_str, "none") == 0) {
+ uniqueid_kind = SLAPI_UNIQUEID_GENERATE_NONE;
+ } else if (strcasecmp(uniqueid_kind_str, "deterministic") == 0) {
+ uniqueid_kind = SLAPI_UNIQUEID_GENERATE_NAME_BASED;
+ } else {
+ /* default - time based */
+ uniqueid_kind = SLAPI_UNIQUEID_GENERATE_TIME_BASED;
+ }
+ }
+
+ /* allocate new task now */
+ task = new_task(slapi_entry_get_ndn(e));
+ if (task == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0);
+ rv = LDAP_OPERATIONS_ERROR;
+ goto out;
+ }
+ task->task_state = SLAPI_TASK_SETUP;
+
+ memset(&mypb, 0, sizeof(mypb));
+ mypb.pb_backend = be;
+ mypb.pb_plugin = be->be_database;
+ mypb.pb_removedupvals = atoi(fetch_attr(e, "nsImportChunkSize", "0"));
+ mypb.pb_ldif2db_noattrindexes =
+ !(strcasecmp(do_attr_indexes, "true") == 0);
+ mypb.pb_ldif_generate_uniqueid = uniqueid_kind;
+ mypb.pb_ldif_namespaceid =
+ (char *)fetch_attr(e, "nsUniqueIdGeneratorNamespace", NULL);
+ mypb.pb_instance_name = (char *)instance_name;
+ mypb.pb_ldif_files = ldif_file;
+ mypb.pb_ldif_include = include;
+ mypb.pb_ldif_exclude = exclude;
+ mypb.pb_task = task;
+ mypb.pb_task_flags = TASK_RUNNING_AS_TASK;
+ if (NULL != encrypt_on_import && 0 == strcasecmp(encrypt_on_import, "true") ) {
+ mypb.pb_ldif_encrypt = 1;
+ }
+
+ rv = (*mypb.pb_plugin->plg_ldif2db)(&mypb);
+ if (rv == 0) {
+ slapi_entry_attr_set_charptr(e, TASK_LOG_NAME, "");
+ slapi_entry_attr_set_charptr(e, TASK_STATUS_NAME, "");
+ slapi_entry_attr_set_int(e, TASK_PROGRESS_NAME, task->task_progress);
+ slapi_entry_attr_set_int(e, TASK_WORK_NAME, task->task_work);
+ }
+
+out:
+ slapi_ch_free_string(&nameFrombe_name);
+ charray_free(ldif_file);
+ charray_free(include);
+ charray_free(exclude);
+ if (rv != 0) {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ destroy_task(1, task);
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+
+static void task_export_thread(void *arg)
+{
+ Slapi_PBlock *pb = (Slapi_PBlock *)arg;
+ char **instance_names = (char **)pb->pb_instance_name;
+ char **inp;
+ char *ldif_file = pb->pb_ldif_file;
+ char *this_ldif_file = NULL;
+ Slapi_Backend *be = NULL;
+ int rv = -1;
+ int count;
+ Slapi_Task *task = pb->pb_task;
+
+ for (count = 0, inp = instance_names; *inp; inp++, count++)
+ ;
+ task->task_work = count;
+ task->task_progress = 0;
+ task->task_state = SLAPI_TASK_RUNNING;
+ slapi_task_status_changed(task);
+
+ for (inp = instance_names; *inp; inp++) {
+ int release_me = 0;
+ /* lookup the backend */
+ be = slapi_be_select_by_instance_name((const char *)*inp);
+ if (be == NULL) {
+ /* shouldn't happen */
+ LDAPDebug(LDAP_DEBUG_ANY, "ldbm2ldif: backend '%s' is AWOL!\n",
+ (const char *)*inp, 0, 0);
+ continue;
+ }
+
+ pb->pb_backend = be;
+ pb->pb_plugin = be->be_database;
+ pb->pb_instance_name = (char *)*inp;
+
+ /* ldif_file name for each? */
+ if (pb->pb_ldif_printkey & EXPORT_APPENDMODE) {
+ if (inp == instance_names) { /* first export */
+ pb->pb_ldif_printkey |= EXPORT_APPENDMODE_1;
+ } else {
+ pb->pb_ldif_printkey &= ~EXPORT_APPENDMODE_1;
+ }
+ } else {
+ if (strcmp(ldif_file, "-")) { /* not '-' */
+ char *p;
+#if defined( _WIN32 )
+ char sep = '\\';
+ if (NULL != strchr(ldif_file, '/'))
+ sep = '/';
+#else
+ char sep = '/';
+#endif
+ this_ldif_file = (char *)slapi_ch_malloc(strlen(ldif_file) +
+ strlen(*inp) + 2);
+ p = strrchr(ldif_file, sep);
+ if (NULL == p) {
+ sprintf(this_ldif_file, "%s_%s", *inp, ldif_file);
+ } else {
+ char *q;
+
+ q = p + 1;
+ *p = '\0';
+ sprintf(this_ldif_file, "%s%c%s_%s",
+ ldif_file, sep, *inp, q);
+ *p = sep;
+ }
+ pb->pb_ldif_file = this_ldif_file;
+ release_me = 1;
+ }
+ }
+
+ slapi_task_log_notice(task, "Beginning export of '%s'", *inp);
+ LDAPDebug(LDAP_DEBUG_ANY, "Beginning export of '%s'\n", *inp, 0, 0);
+
+ rv = (*pb->pb_plugin->plg_db2ldif)(pb);
+ if (rv != 0) {
+ slapi_task_log_notice(task, "backend '%s' export failed (%d)",
+ *inp, rv);
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ldbm2ldif: backend '%s' export failed (%d)\n",
+ (const char *)*inp, rv, 0);
+ }
+
+ if (release_me) {
+ slapi_ch_free((void **)&this_ldif_file);
+ }
+
+ if (rv != 0)
+ break;
+
+ task->task_progress++;
+ slapi_task_status_changed(task);
+ }
+
+ /* free the memory now */
+ charray_free(instance_names);
+ slapi_ch_free((void **)&ldif_file);
+ charray_free(pb->pb_ldif_include);
+ charray_free(pb->pb_ldif_exclude);
+ slapi_pblock_destroy(pb);
+
+ if (rv == 0) {
+ slapi_task_log_notice(task, "Export finished.");
+ LDAPDebug(LDAP_DEBUG_ANY, "Export finished.\n", 0, 0, 0);
+ } else {
+ slapi_task_log_notice(task, "Export failed.");
+ LDAPDebug(LDAP_DEBUG_ANY, "Export failed.\n", 0, 0, 0);
+ }
+
+ task->task_exitcode = rv;
+ task->task_state = SLAPI_TASK_FINISHED;
+ slapi_task_status_changed(task);
+}
+
+static int task_export_add(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg)
+{
+ Slapi_Attr *attr;
+ Slapi_Value *val = NULL;
+ Slapi_Backend *be = NULL;
+ const char *cn;
+ char *ldif_file = NULL;
+ char **instance_names = NULL, **inp;
+ char **include = NULL, **exclude = NULL;
+ int idx, rv = SLAPI_DSE_CALLBACK_OK;
+ int export_replica_flag = 0;
+ int ldif_printkey_flag = 0;
+ int dump_uniqueid_flag = 0;
+ int instance_cnt = 0;
+ const char *my_ldif_file;
+ const char *use_one_file;
+ const char *export_replica;
+ const char *ldif_printkey;
+ const char *dump_uniqueid;
+ Slapi_PBlock *mypb = NULL;
+ Slapi_Task *task = NULL;
+ PRThread *thread;
+ const char *decrypt_on_export = NULL;
+
+ *returncode = LDAP_SUCCESS;
+ if ((cn = fetch_attr(e, "cn", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ decrypt_on_export = fetch_attr(e, "nsExportDecrypt", NULL);
+
+ /* nsInstances -- from here on, memory has been allocated */
+ if (slapi_entry_attr_find(e, "nsInstance", &attr) == 0) {
+ for (idx = slapi_attr_first_value(attr, &val);
+ idx >= 0; idx = slapi_attr_next_value(attr, idx, &val)) {
+ charray_add(&instance_names,
+ slapi_ch_strdup(slapi_value_get_string(val)));
+ instance_cnt++;
+ }
+ }
+
+ /* include/exclude suffixes */
+ if (slapi_entry_attr_find(e, "nsIncludeSuffix", &attr) == 0) {
+ for (idx = slapi_attr_first_value(attr, &val);
+ idx >= 0; idx = slapi_attr_next_value(attr, idx, &val)) {
+ charray_add(&include, slapi_ch_strdup(slapi_value_get_string(val)));
+ }
+ }
+ if (slapi_entry_attr_find(e, "nsExcludeSuffix", &attr) == 0) {
+ for (idx = slapi_attr_first_value(attr, &val);
+ idx >= 0; idx = slapi_attr_next_value(attr, idx, &val)) {
+ charray_add(&exclude, slapi_ch_strdup(slapi_value_get_string(val)));
+ }
+ }
+
+ if (NULL == instance_names) {
+ char **ip;
+
+ if (slapi_lookup_instance_name_by_suffixes(include, exclude,
+ &instance_names) < 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: No backend instance is specified.\n", 0, 0, 0);
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ if (instance_names) {
+ for (ip = instance_names, instance_cnt = 0; ip && *ip;
+ ip++, instance_cnt++)
+ ;
+
+ if (instance_cnt == 0) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: No backend instance is specified.\n", 0, 0, 0);
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ } else {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: No backend instance is specified.\n", 0, 0, 0);
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ }
+
+ /* ldif file name */
+ if ((my_ldif_file = fetch_attr(e, "nsFilename", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ ldif_file = slapi_ch_strdup(my_ldif_file);
+ /* if true, multiple backends are dumped into one ldif file */
+ use_one_file = fetch_attr(e, "nsUseOneFile", "true");
+ if (strcasecmp(use_one_file, "true") == 0) {
+ ldif_printkey_flag |= EXPORT_APPENDMODE;
+ }
+
+ /* -r: export replica */
+ export_replica = fetch_attr(e, "nsExportReplica", "false");
+ if (!strcasecmp(export_replica, "true")) /* true */
+ export_replica_flag = 1;
+
+ /* -N: eq "false" ==> does not print out key value */
+ ldif_printkey = fetch_attr(e, "nsPrintKey", "true");
+ if (!strcasecmp(ldif_printkey, "true")) /* true */
+ ldif_printkey_flag |= EXPORT_PRINTKEY;
+
+ /* -C: eq "true" ==> use only id2entry file */
+ ldif_printkey = fetch_attr(e, "nsUseId2Entry", "false");
+ if (!strcasecmp(ldif_printkey, "true")) /* true */
+ ldif_printkey_flag |= EXPORT_ID2ENTRY_ONLY;
+
+ /* if "true" ==> 8-bit strings are not base64 encoded */
+ ldif_printkey = fetch_attr(e, "nsMinimalEncoding", "false");
+ if (!strcasecmp(ldif_printkey, "true")) /* true */
+ ldif_printkey_flag |= EXPORT_MINIMAL_ENCODING;
+
+ /* -U: eq "true" ==> does not fold the output */
+ ldif_printkey = fetch_attr(e, "nsNoWrap", "false");
+ if (!strcasecmp(ldif_printkey, "true")) /* true */
+ ldif_printkey_flag |= EXPORT_NOWRAP;
+
+ /* -1: eq "true" ==> does not print version line */
+ ldif_printkey = fetch_attr(e, "nsNoVersionLine", "false");
+ if (!strcasecmp(ldif_printkey, "true")) /* true */
+ ldif_printkey_flag |= EXPORT_NOVERSION;
+
+ /* -u: eq "false" ==> does not dump unique id */
+ dump_uniqueid = fetch_attr(e, "nsDumpUniqId", "true");
+ if (!strcasecmp(dump_uniqueid, "true")) /* true */
+ dump_uniqueid_flag = 1;
+
+ /* check that all the backends are ok */
+ for (inp = instance_names; *inp; inp++) {
+ /* lookup the backend */
+ be = slapi_be_select_by_instance_name((const char *)*inp);
+ if (be == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "can't export to nonexistent backend %s\n", *inp, 0, 0);
+ *returncode = LDAP_NO_SUCH_OBJECT;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* refuse to do an export on pre-V3 plugins. plugin api V3 is the one
+ * for DS 5.0 where the import/export stuff changed a lot.
+ */
+ if (! SLAPI_PLUGIN_IS_V3(be->be_database)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "can't perform an export with pre-V3 "
+ "backend plugin %s\n", be->be_database->plg_name, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ if (be->be_database->plg_db2ldif == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: no db2ldif function defined for "
+ "backend %s\n", be->be_database->plg_name, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ }
+
+ /* allocate new task now */
+ task = new_task(slapi_entry_get_ndn(e));
+ if (task == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ task->task_state = SLAPI_TASK_SETUP;
+ task->task_work = instance_cnt;
+ task->task_progress = 0;
+
+ mypb = slapi_pblock_new();
+ if (mypb == NULL) {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ mypb->pb_ldif_include = include;
+ mypb->pb_ldif_exclude = exclude;
+ mypb->pb_ldif_printkey = ldif_printkey_flag;
+ mypb->pb_ldif_dump_replica = export_replica_flag;
+ mypb->pb_ldif_dump_uniqueid = dump_uniqueid_flag;
+ mypb->pb_ldif_file = ldif_file;
+ /* horrible hack */
+ mypb->pb_instance_name = (char *)instance_names;
+ mypb->pb_task = task;
+ mypb->pb_task_flags = TASK_RUNNING_AS_TASK;
+ if (NULL != decrypt_on_export && 0 == strcasecmp(decrypt_on_export, "true") ) {
+ mypb->pb_ldif_encrypt = 1;
+ }
+
+ /* start the export as a separate thread */
+ thread = PR_CreateThread(PR_USER_THREAD, task_export_thread,
+ (void *)mypb, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "unable to create ldbm2ldif thread!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ slapi_pblock_destroy(mypb);
+ goto out;
+ }
+
+ /* thread successful -- don't free the pb, let the thread do that. */
+ return SLAPI_DSE_CALLBACK_OK;
+
+out:
+ charray_free(instance_names);
+ charray_free(include);
+ charray_free(exclude);
+ if (ldif_file != NULL) {
+ slapi_ch_free((void **)&ldif_file);
+ }
+ if (task) {
+ destroy_task(1, task);
+ }
+
+ return rv;
+}
+
+
+static void task_backup_thread(void *arg)
+{
+ Slapi_PBlock *pb = (Slapi_PBlock *)arg;
+ Slapi_Task *task = pb->pb_task;
+ int rv;
+
+ task->task_work = 1;
+ task->task_progress = 0;
+ task->task_state = SLAPI_TASK_RUNNING;
+ slapi_task_status_changed(task);
+
+ slapi_task_log_notice(task, "Beginning backup of '%s'",
+ pb->pb_plugin->plg_name);
+ LDAPDebug(LDAP_DEBUG_ANY, "Beginning backup of '%s'\n",
+ pb->pb_plugin->plg_name, 0, 0);
+
+ rv = (*pb->pb_plugin->plg_db2archive)(pb);
+ if (rv != 0) {
+ slapi_task_log_notice(task, "Backup failed (error %d)", rv);
+ slapi_task_log_status(task, "Backup failed (error %d)", rv);
+ LDAPDebug(LDAP_DEBUG_ANY, "Backup failed (error %d)\n", rv, 0, 0);
+ } else {
+ slapi_task_log_notice(task, "Backup finished.");
+ slapi_task_log_status(task, "Backup finished.");
+ LDAPDebug(LDAP_DEBUG_ANY, "Backup finished.\n", 0, 0, 0);
+ }
+
+ task->task_progress = 1;
+ task->task_exitcode = rv;
+ task->task_state = SLAPI_TASK_FINISHED;
+ slapi_task_status_changed(task);
+
+ slapi_ch_free((void **)&pb->pb_seq_val);
+ slapi_pblock_destroy(pb);
+}
+
+static int task_backup_add(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg)
+{
+ Slapi_Backend *be = NULL;
+ PRThread *thread = NULL;
+ const char *cn;
+ const char *archive_dir = NULL;
+ const char *my_database_type = NULL;
+ const char *database_type = "ldbm database";
+ char *cookie = NULL;
+ int rv = SLAPI_DSE_CALLBACK_OK;
+ Slapi_PBlock *mypb = NULL;
+ Slapi_Task *task = NULL;
+
+ *returncode = LDAP_SUCCESS;
+ if ((cn = fetch_attr(e, "cn", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* archive dir name */
+ if ((archive_dir = fetch_attr(e, "nsArchiveDir", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* database type */
+ my_database_type = fetch_attr(e, "nsDatabaseType", NULL);
+ if (NULL != my_database_type)
+ database_type = my_database_type;
+
+ /* get backend that has db2archive and the database type matches. */
+ cookie = NULL;
+ be = slapi_get_first_backend(&cookie);
+ while (be) {
+ if (NULL != be->be_database->plg_db2archive &&
+ !strcasecmp(database_type, be->be_database->plg_name))
+ break;
+
+ be = (backend *)slapi_get_next_backend (cookie);
+ }
+ if (NULL == be || NULL == be->be_database->plg_db2archive) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: no db2archive function defined.\n", 0, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ if (! SLAPI_PLUGIN_IS_V3(be->be_database)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "can't perform an backup with pre-V3 "
+ "backend plugin %s\n", be->be_database->plg_name, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* allocate new task now */
+ task = new_task(slapi_entry_get_ndn(e));
+ if (task == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ task->task_state = SLAPI_TASK_SETUP;
+ task->task_work = 1;
+ task->task_progress = 0;
+
+ mypb = slapi_pblock_new();
+ if (mypb == NULL) {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ mypb->pb_seq_val = slapi_ch_strdup(archive_dir);
+ mypb->pb_plugin = be->be_database;
+ mypb->pb_task = task;
+ mypb->pb_task_flags = TASK_RUNNING_AS_TASK;
+
+ /* start the backup as a separate thread */
+ thread = PR_CreateThread(PR_USER_THREAD, task_backup_thread,
+ (void *)mypb, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "unable to create backup thread!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ slapi_ch_free((void **)&mypb->pb_seq_val);
+ slapi_pblock_destroy(mypb);
+ goto out;
+ }
+
+ /* thread successful -- don't free the pb, let the thread do that. */
+ return SLAPI_DSE_CALLBACK_OK;
+
+out:
+ if (task) {
+ destroy_task(1, task);
+ }
+ return rv;
+}
+
+
+static void task_restore_thread(void *arg)
+{
+ Slapi_PBlock *pb = (Slapi_PBlock *)arg;
+ Slapi_Task *task = pb->pb_task;
+ int rv;
+
+ task->task_work = 1;
+ task->task_progress = 0;
+ task->task_state = SLAPI_TASK_RUNNING;
+ slapi_task_status_changed(task);
+
+ slapi_task_log_notice(task, "Beginning restore to '%s'",
+ pb->pb_plugin->plg_name);
+ LDAPDebug(LDAP_DEBUG_ANY, "Beginning restore to '%s'\n",
+ pb->pb_plugin->plg_name, 0, 0);
+
+ rv = (*pb->pb_plugin->plg_archive2db)(pb);
+ if (rv != 0) {
+ slapi_task_log_notice(task, "Restore failed (error %d)", rv);
+ slapi_task_log_status(task, "Restore failed (error %d)", rv);
+ LDAPDebug(LDAP_DEBUG_ANY, "Restore failed (error %d)\n", rv, 0, 0);
+ } else {
+ slapi_task_log_notice(task, "Restore finished.");
+ slapi_task_log_status(task, "Restore finished.");
+ LDAPDebug(LDAP_DEBUG_ANY, "Restore finished.\n", 0, 0, 0);
+ }
+
+ task->task_progress = 1;
+ task->task_exitcode = rv;
+ task->task_state = SLAPI_TASK_FINISHED;
+ slapi_task_status_changed(task);
+
+ slapi_ch_free((void **)&pb->pb_seq_val);
+ slapi_pblock_destroy(pb);
+}
+
+static int task_restore_add(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg)
+{
+ Slapi_Backend *be = NULL;
+ const char *cn;
+ const char *archive_dir = NULL;
+ const char *my_database_type = NULL;
+ const char *database_type = "ldbm database";
+ char *cookie = NULL;
+ int rv = SLAPI_DSE_CALLBACK_OK;
+ Slapi_PBlock *mypb = NULL;
+ Slapi_Task *task = NULL;
+ PRThread *thread = NULL;
+
+ *returncode = LDAP_SUCCESS;
+ if ((cn = fetch_attr(e, "cn", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* archive dir name */
+ if ((archive_dir = fetch_attr(e, "nsArchiveDir", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* database type */
+ my_database_type = fetch_attr(e, "nsDatabaseType", NULL);
+ if (NULL != my_database_type)
+ database_type = my_database_type;
+
+ /* get backend that has archive2db and the database type matches. */
+ cookie = NULL;
+ be = slapi_get_first_backend (&cookie);
+ while (be) {
+ if (NULL != be->be_database->plg_archive2db &&
+ !strcasecmp(database_type, be->be_database->plg_name))
+ break;
+
+ be = (backend *)slapi_get_next_backend (cookie);
+ }
+ if (NULL == be || NULL == be->be_database->plg_archive2db) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: no db2archive function defined.\n", 0, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* refuse to do an export on pre-V3 plugins. plugin api V3 is the one
+ * for DS 5.0 where the import/export stuff changed a lot.
+ */
+ if (! SLAPI_PLUGIN_IS_V3(be->be_database)) {
+ LDAPDebug(LDAP_DEBUG_ANY, "can't perform an restore with pre-V3 "
+ "backend plugin %s\n", be->be_database->plg_name, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* allocate new task now */
+ task = new_task(slapi_entry_get_ndn(e));
+ if (task == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ task->task_state = SLAPI_TASK_SETUP;
+ task->task_work = 1;
+ task->task_progress = 0;
+
+ mypb = slapi_pblock_new();
+ if (mypb == NULL) {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ mypb->pb_seq_val = slapi_ch_strdup(archive_dir);
+ mypb->pb_plugin = be->be_database;
+ mypb->pb_task = task;
+ mypb->pb_task_flags = TASK_RUNNING_AS_TASK;
+
+ /* start the restore as a separate thread */
+ thread = PR_CreateThread(PR_USER_THREAD, task_restore_thread,
+ (void *)mypb, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "unable to create restore thread!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ slapi_ch_free((void **)&mypb->pb_seq_val);
+ slapi_pblock_destroy(mypb);
+ goto out;
+ }
+
+ /* thread successful -- don't free the pb, let the thread do that. */
+ return SLAPI_DSE_CALLBACK_OK;
+
+out:
+ if (task) {
+ destroy_task(1, task);
+ }
+ return rv;
+}
+
+
+static void task_index_thread(void *arg)
+{
+ Slapi_PBlock *pb = (Slapi_PBlock *)arg;
+ Slapi_Task *task = pb->pb_task;
+ int rv;
+
+ task->task_work = 1;
+ task->task_progress = 0;
+ task->task_state = SLAPI_TASK_RUNNING;
+ slapi_task_status_changed(task);
+
+ rv = (*pb->pb_plugin->plg_db2index)(pb);
+ if (rv != 0) {
+ slapi_task_log_notice(task, "Index failed (error %d)", rv);
+ slapi_task_log_status(task, "Index failed (error %d)", rv);
+ LDAPDebug(LDAP_DEBUG_ANY, "Index failed (error %d)\n", rv, 0, 0);
+ }
+
+ task->task_progress = task->task_work;
+ task->task_exitcode = rv;
+ task->task_state = SLAPI_TASK_FINISHED;
+ slapi_task_status_changed(task);
+
+ charray_free(pb->pb_db2index_attrs);
+ slapi_ch_free((void **)&pb->pb_instance_name);
+ slapi_pblock_destroy(pb);
+}
+
+static int task_index_add(Slapi_PBlock *pb, Slapi_Entry *e,
+ Slapi_Entry *eAfter, int *returncode, char *returntext, void *arg)
+{
+ const char *instance_name;
+ const char *cn;
+ int rv = SLAPI_DSE_CALLBACK_OK;
+ Slapi_Backend *be = NULL;
+ Slapi_Task *task = NULL;
+ Slapi_Attr *attr;
+ Slapi_Value *val = NULL;
+ char **indexlist = NULL;
+ int idx;
+ Slapi_PBlock *mypb = NULL;
+ PRThread *thread = NULL;
+
+ *returncode = LDAP_SUCCESS;
+ if ((cn = fetch_attr(e, "cn", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ if ((instance_name = fetch_attr(e, "nsInstance", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* lookup the backend */
+ be = slapi_be_select_by_instance_name(instance_name);
+ if (be == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "can't import to nonexistent backend %s\n",
+ instance_name, 0, 0);
+ *returncode = LDAP_NO_SUCH_OBJECT;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+ if (be->be_database->plg_db2index == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "ERROR: no db2index function defined for "
+ "backend %s\n", be->be_database->plg_name, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ /* normal indexes */
+ if (slapi_entry_attr_find(e, "nsIndexAttribute", &attr) == 0) {
+ for (idx = slapi_attr_first_value(attr, &val);
+ idx >= 0; idx = slapi_attr_next_value(attr, idx, &val)) {
+ const char *indexname = slapi_value_get_string(val);
+ char *index = (char *)slapi_ch_malloc(strlen(indexname) + 2);
+
+ if (index != NULL) {
+ sprintf(index, "t%s", indexname);
+ charray_add(&indexlist, index);
+ }
+ }
+ }
+
+ /* vlv indexes */
+ if (slapi_entry_attr_find(e, "nsIndexVlvAttribute", &attr) == 0) {
+ for (idx = slapi_attr_first_value(attr, &val);
+ idx >= 0; idx = slapi_attr_next_value(attr, idx, &val)) {
+ const char *indexname = slapi_value_get_string(val);
+ char *index = (char *)slapi_ch_malloc(strlen(indexname) + 2);
+
+ if (index != NULL) {
+ sprintf(index, "T%s", indexname);
+ charray_add(&indexlist, index);
+ }
+ }
+ }
+
+ if (NULL == indexlist) {
+ LDAPDebug(LDAP_DEBUG_ANY, "no index is specified!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_OK;
+ goto out;
+ }
+
+ /* allocate new task now */
+ task = new_task(slapi_entry_get_ndn(e));
+ if (task == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ task->task_state = SLAPI_TASK_SETUP;
+ task->task_work = 1;
+ task->task_progress = 0;
+
+ mypb = slapi_pblock_new();
+ if (mypb == NULL) {
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ mypb->pb_backend = be;
+ mypb->pb_plugin = be->be_database;
+ mypb->pb_instance_name = slapi_ch_strdup(instance_name);
+ mypb->pb_db2index_attrs = indexlist;
+ mypb->pb_task = task;
+ mypb->pb_task_flags = TASK_RUNNING_AS_TASK;
+
+ /* start the db2index as a separate thread */
+ thread = PR_CreateThread(PR_USER_THREAD, task_index_thread,
+ (void *)mypb, PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD,
+ PR_UNJOINABLE_THREAD, SLAPD_DEFAULT_THREAD_STACKSIZE);
+ if (thread == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "unable to create index thread!\n", 0, 0, 0);
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ slapi_ch_free((void **)&mypb->pb_instance_name);
+ slapi_pblock_destroy(mypb);
+ goto out;
+ }
+
+ /* thread successful -- don't free the pb, let the thread do that. */
+ return SLAPI_DSE_CALLBACK_OK;
+
+out:
+ if (task) {
+ destroy_task(1, task);
+ }
+ if (indexlist) {
+ charray_free(indexlist);
+ }
+ return rv;
+}
+
+#if defined(UPGRADEDB)
+static int
+task_upgradedb_add(Slapi_PBlock *pb, Slapi_Entry *e, Slapi_Entry *eAfter,
+ int *returncode, char *returntext, void *arg)
+{
+ const char *cn;
+ int rv = SLAPI_DSE_CALLBACK_OK;
+ Slapi_Backend *be = NULL;
+ Slapi_Task *task = NULL;
+ Slapi_PBlock mypb;
+ PRThread *thread = NULL;
+ const char *archive_dir = NULL;
+ const char *force = NULL;
+ const char *database_type = "ldbm database";
+ const char *my_database_type = NULL;
+ char *cookie = NULL;
+
+ *returncode = LDAP_SUCCESS;
+ if ((cn = fetch_attr(e, "cn", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* archive dir name */
+ if ((archive_dir = fetch_attr(e, "nsArchiveDir", NULL)) == NULL) {
+ *returncode = LDAP_OBJECT_CLASS_VIOLATION;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* database type */
+ my_database_type = fetch_attr(e, "nsDatabaseType", NULL);
+ if (NULL != my_database_type)
+ database_type = my_database_type;
+
+ /* force to reindex? */
+ force = fetch_attr(e, "nsForceToReindex", NULL);
+
+ /* get backend that has db2archive and the database type matches. */
+ cookie = NULL;
+ be = slapi_get_first_backend(&cookie);
+ while (be) {
+ if (NULL != be->be_database->plg_upgradedb)
+ break;
+
+ be = (backend *)slapi_get_next_backend (cookie);
+ }
+ if (NULL == be || NULL == be->be_database->plg_upgradedb ||
+ strcasecmp(database_type, be->be_database->plg_name)) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "ERROR: no upgradedb is defined in %s.\n",
+ be->be_database->plg_name, 0, 0);
+ *returncode = LDAP_UNWILLING_TO_PERFORM;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+
+ /* allocate new task now */
+ task = new_task(slapi_entry_get_ndn(e));
+ if (task == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to allocate new task!\n", 0, 0, 0);
+ *returncode = LDAP_OPERATIONS_ERROR;
+ rv = SLAPI_DSE_CALLBACK_ERROR;
+ goto out;
+ }
+ task->task_state = SLAPI_TASK_SETUP;
+ task->task_work = 1;
+ task->task_progress = 0;
+
+ memset(&mypb, 0, sizeof(mypb));
+ mypb.pb_backend = be;
+ mypb.pb_plugin = be->be_database;
+ if (force && 0 == strcasecmp(force, "true"))
+ mypb.pb_seq_type = SLAPI_UPGRADEDB_FORCE; /* force; reindex all regardless the dbversion */
+ mypb.pb_seq_val = slapi_ch_strdup(archive_dir);
+ mypb.pb_task = task;
+ mypb.pb_task_flags = TASK_RUNNING_AS_TASK;
+
+ rv = (mypb.pb_plugin->plg_upgradedb)(&mypb);
+ if (rv == 0) {
+ slapi_entry_attr_set_charptr(e, TASK_LOG_NAME, "");
+ slapi_entry_attr_set_charptr(e, TASK_STATUS_NAME, "");
+ slapi_entry_attr_set_int(e, TASK_PROGRESS_NAME, task->task_progress);
+ slapi_entry_attr_set_int(e, TASK_WORK_NAME, task->task_work);
+ }
+
+out:
+ if (rv != 0) {
+ if (task)
+ destroy_task(1, task);
+
+ *returncode = LDAP_OPERATIONS_ERROR;
+ return SLAPI_DSE_CALLBACK_ERROR;
+ }
+
+ *returncode = LDAP_SUCCESS;
+ return SLAPI_DSE_CALLBACK_OK;
+}
+#endif
+
+/* update attributes in the entry under "cn=tasks" to match the current
+ * status of the task.
+ */
+#define NEXTMOD(_type, _val) do { \
+ modlist[cur].mod_op = LDAP_MOD_REPLACE; \
+ modlist[cur].mod_type = (_type); \
+ modlist[cur].mod_values = (char **)slapi_ch_malloc(2*sizeof(char *)); \
+ modlist[cur].mod_values[0] = (_val); \
+ modlist[cur].mod_values[1] = NULL; \
+ mod[cur] = &modlist[cur]; \
+ cur++; \
+} while (0)
+void slapi_task_status_changed(Slapi_Task *task)
+{
+ LDAPMod modlist[20];
+ LDAPMod *mod[20];
+ int cur = 0, i;
+ char s1[20], s2[20], s3[20];
+
+ if (shutting_down) {
+ /* don't care about task status updates anymore */
+ return;
+ }
+
+ NEXTMOD(TASK_LOG_NAME, task->task_log);
+ NEXTMOD(TASK_STATUS_NAME, task->task_status);
+ sprintf(s1, "%d", task->task_exitcode);
+ sprintf(s2, "%d", task->task_progress);
+ sprintf(s3, "%d", task->task_work);
+ NEXTMOD(TASK_PROGRESS_NAME, s2);
+ NEXTMOD(TASK_WORK_NAME, s3);
+ /* only add the exit code when the job is done */
+ if ((task->task_state == SLAPI_TASK_FINISHED) ||
+ (task->task_state == SLAPI_TASK_CANCELLED)) {
+ NEXTMOD(TASK_EXITCODE_NAME, s1);
+ /* make sure the console can tell the task has ended */
+ if (task->task_progress != task->task_work) {
+ task->task_progress = task->task_work;
+ }
+ }
+
+ mod[cur] = NULL;
+ modify_internal_entry(task->task_dn, mod);
+
+ for (i = 0; i < cur; i++)
+ slapi_ch_free((void **)&modlist[i].mod_values);
+
+ if ((task->task_state == SLAPI_TASK_FINISHED) &&
+ !(task->task_flags & SLAPI_TASK_DESTROYING)) {
+ /* queue an event to destroy the state info */
+ Slapi_Eq_Context event;
+ Slapi_PBlock *pb = slapi_pblock_new();
+ Slapi_Entry *e;
+ int ttl;
+ time_t expire;
+
+ e = get_internal_entry(pb, task->task_dn);
+ if (e == NULL)
+ return;
+ ttl = atoi(fetch_attr(e, "ttl", DEFAULT_TTL));
+ if (ttl > 3600)
+ ttl = 3600; /* be reasonable. */
+ expire = time(NULL) + ttl;
+ task->task_flags |= SLAPI_TASK_DESTROYING;
+ event = slapi_eq_once(destroy_task, (void *)task, expire);
+
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ }
+}
+
+
+/* cleanup old tasks that may still be in the DSE from a previous session
+ * (this can happen if the server crashes [no matter how unlikely we like
+ * to think that is].)
+ */
+static void cleanup_old_tasks(void)
+{
+ Slapi_PBlock *pb = slapi_pblock_new();
+ Slapi_Entry **entries = NULL;
+ int ret = 0, i, x;
+ Slapi_DN *rootDN;
+
+ slapi_search_internal_set_pb(pb, TASK_BASE_DN, LDAP_SCOPE_SUBTREE,
+ "(objectclass=*)", NULL, 0, NULL, NULL,
+ (void *)plugin_get_default_component_id(), 0);
+ slapi_search_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &ret);
+ if (ret != LDAP_SUCCESS) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: entire cn=tasks tree seems to "
+ "be AWOL!\n", 0, 0, 0);
+ slapi_pblock_destroy(pb);
+ return;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (NULL == entries) {
+ LDAPDebug(LDAP_DEBUG_ANY, "WARNING: entire cn=tasks tree seems to "
+ "be AWOL!\n", 0, 0, 0);
+ slapi_pblock_destroy(pb);
+ return;
+ }
+
+ rootDN = slapi_sdn_new_dn_byval(TASK_BASE_DN);
+
+ /* rotate through entries, skipping the base dn */
+ for (i = 0; entries[i] != NULL; i++) {
+ const Slapi_DN *sdn = slapi_entry_get_sdn_const(entries[i]);
+ Slapi_PBlock *mypb;
+ Slapi_Operation *op;
+
+ if (slapi_sdn_compare(sdn, rootDN) == 0)
+ continue;
+
+ mypb = slapi_pblock_new();
+ if (mypb == NULL) {
+ continue;
+ }
+ slapi_delete_internal_set_pb(mypb, slapi_sdn_get_dn(sdn), NULL, NULL,
+ plugin_get_default_component_id(), 0);
+
+ /* Make sure these deletes don't appear in the audit and change logs */
+ slapi_pblock_get(mypb, SLAPI_OPERATION, &op);
+ operation_set_flag(op, OP_FLAG_ACTION_NOLOG);
+
+ x = 1;
+ slapi_pblock_set(mypb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &x);
+ slapi_delete_internal_pb(mypb);
+ slapi_pblock_destroy(mypb);
+ }
+
+ slapi_sdn_free(&rootDN);
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+}
+
+/* name is, for exmaple, "import" */
+int slapi_task_register_handler(const char *name, dseCallbackFn func)
+{
+ char *dn = NULL;
+ Slapi_PBlock *pb = NULL;
+ Slapi_Operation *op;
+ LDAPMod *mods[3];
+ LDAPMod mod[3];
+ const char *objectclass[3];
+ const char *cnvals[2];
+ int ret = -1;
+ int x;
+
+ dn = slapi_ch_malloc(strlen(name) + strlen(TASK_BASE_DN) + 20);
+ if (dn == NULL) {
+ goto out;
+ }
+ sprintf(dn, "cn=%s, %s", name, TASK_BASE_DN);
+
+ pb = slapi_pblock_new();
+ if (pb == NULL) {
+ goto out;
+ }
+
+ /* this is painful :( */
+ mods[0] = &mod[0];
+ mod[0].mod_op = LDAP_MOD_ADD;
+ mod[0].mod_type = "objectClass";
+ mod[0].mod_values = (char **)objectclass;
+ objectclass[0] = "top";
+ objectclass[1] = "extensibleObject";
+ objectclass[2] = NULL;
+ mods[1] = &mod[1];
+ mod[1].mod_op = LDAP_MOD_ADD;
+ mod[1].mod_type = "cn";
+ mod[1].mod_values = (char **)cnvals;
+ cnvals[0] = name;
+ cnvals[1] = NULL;
+ mods[2] = NULL;
+ slapi_add_internal_set_pb(pb, dn, mods, NULL,
+ plugin_get_default_component_id(), 0);
+ x = 1;
+ slapi_pblock_set(pb, SLAPI_DSE_DONT_WRITE_WHEN_ADDING, &x);
+ /* Make sure these adds don't appear in the audit and change logs */
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+ operation_set_flag(op, OP_FLAG_ACTION_NOLOG);
+
+ slapi_add_internal_pb(pb);
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &x);
+ if ((x != LDAP_SUCCESS) && (x != LDAP_ALREADY_EXISTS)) {
+ LDAPDebug(LDAP_DEBUG_ANY,
+ "Can't create task node '%s' (error %d)\n",
+ name, x, 0);
+ ret = x;
+ goto out;
+ }
+
+ /* register add callback */
+ slapi_config_register_callback(SLAPI_OPERATION_ADD, DSE_FLAG_PREOP,
+ dn, LDAP_SCOPE_SUBTREE, "(objectclass=*)", func, NULL);
+ /* deny modify/delete of the root task entry */
+ slapi_config_register_callback(SLAPI_OPERATION_MODIFY, DSE_FLAG_PREOP,
+ dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_deny, NULL);
+ slapi_config_register_callback(SLAPI_OPERATION_DELETE, DSE_FLAG_PREOP,
+ dn, LDAP_SCOPE_BASE, "(objectclass=*)", task_deny, NULL);
+
+ ret = 0;
+
+out:
+ if (dn) {
+ slapi_ch_free((void **)&dn);
+ }
+ if (pb) {
+ slapi_pblock_destroy(pb);
+ }
+ return ret;
+}
+
+
+void task_init(void)
+{
+ global_task_lock = PR_NewLock();
+ if (global_task_lock == NULL) {
+ LDAPDebug(LDAP_DEBUG_ANY, "unable to create global tasks lock! "
+ "(that's bad)\n", 0, 0, 0);
+ return;
+ }
+
+ cleanup_old_tasks();
+
+ slapi_task_register_handler("import", task_import_add);
+ slapi_task_register_handler("export", task_export_add);
+ slapi_task_register_handler("backup", task_backup_add);
+ slapi_task_register_handler("restore", task_restore_add);
+ slapi_task_register_handler("index", task_index_add);
+#if defined(UPGRADEDB)
+ slapi_task_register_handler("upgradedb", task_upgradedb_add);
+#endif
+}
+
+/* called when the server is shutting down -- abort all existing tasks */
+void task_shutdown(void)
+{
+ Slapi_Task *task;
+ int found_any = 0;
+
+ /* first, cancel all tasks */
+ PR_Lock(global_task_lock);
+ shutting_down = 1;
+ for (task = global_task_list; task; task = task->next) {
+ if ((task->task_state != SLAPI_TASK_CANCELLED) &&
+ (task->task_state != SLAPI_TASK_FINISHED)) {
+ task->task_state = SLAPI_TASK_CANCELLED;
+ if (task->cancel) {
+ LDAPDebug(LDAP_DEBUG_ANY, "Cancelling task '%s'\n",
+ task->task_dn, 0, 0);
+ (*task->cancel)(task);
+ found_any = 1;
+ }
+ }
+ }
+
+ if (found_any) {
+ /* give any tasks 1 second to say their last rites */
+ DS_Sleep(PR_SecondsToInterval( 1 ));
+ }
+
+ while (global_task_list) {
+ destroy_task(0, global_task_list);
+ }
+ PR_Unlock(global_task_lock);
+}
diff --git a/ldap/servers/slapd/tempnam.c b/ldap/servers/slapd/tempnam.c
new file mode 100644
index 00000000..00c7c2fc
--- /dev/null
+++ b/ldap/servers/slapd/tempnam.c
@@ -0,0 +1,44 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#if defined( nextstep )
+
+#include <string.h>
+
+char *tempnam( char *dir, char *pfx );
+
+char *tempnam( char *dir, char *pfx )
+{
+ char *s;
+
+ if ( dir == NULL ) {
+ dir = "/tmp";
+ }
+
+/*
+ * allocate space for dir + '/' + pfx (up to 5 chars) + 6 trailing 'X's + 0 byte
+ */
+ if (( s = (char *)slapi_ch_malloc( strlen( dir ) + 14 )) == NULL ) {
+ return( NULL );
+ }
+
+ strcpy( s, dir );
+ strcat( s, "/" );
+ if ( pfx != NULL ) {
+ strcat( s, pfx );
+ }
+ strcat( s, "XXXXXX" );
+ mktemp( s );
+
+ if ( *s == '\0' ) {
+ slapi_ch_free( (void**)&s );
+ }
+
+ return( s );
+}
+
+#else /* nextstep */
+typedef int SHUT_UP_DAMN_COMPILER;
+#endif /* nextstep */
diff --git a/ldap/servers/slapd/test-plugins/Makefile b/ldap/servers/slapd/test-plugins/Makefile
new file mode 100644
index 00000000..8b78aada
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile
@@ -0,0 +1,51 @@
+#
+# 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 test-plugin
+#
+
+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 = $(OBJDIR)/servers/obj
+BINDIR = $(OBJDIR)/bin
+LIBDIR = $(OBJDIR)/lib
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+include $(MCOM_ROOT)/ldapserver/ns_usepurify.mk
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+
+
+EXTRA_INCLUDES=-I.. -I../../../include $(NSPR_INCLUDE) -I$(LDAP_INCLUDE) -I$(DB_INCLUDE) -I../../../servers/slapd -g
+INCLUDE_FLAGS=-I../include $(EXTRA_INCLUDES)
+EXTRA_LIBS = $(DB_LIB)
+
+ifdef USE_64
+MAKEFILE_FILE=Makefile.$(BUILD_ARCH)64
+else
+MAKEFILE_FILE=Makefile.$(BUILD_ARCH)
+endif
+
+all:
+ $(MAKE) -f $(MAKEFILE_FILE) all INCLUDE_FLAGS="$(INCLUDE_FLAGS)" EXTRA_LIBS="$(EXTRA_LIBS)"
+
+libtest-plugin.so:
+ $(MAKE) -f $(MAKEFILE_FILE) libtest-plugin.so \
+ INCLUDE_FLAGS="$(INCLUDE_FLAGS)"
+
+clean:
+ $(MAKE) -f $(MAKEFILE_FILE) clean INCLUDE_FLAGS="$(INCLUDE_FLAGS)"
+
+veryclean: clean
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.AIX b/ldap/servers/slapd/test-plugins/Makefile.AIX
new file mode 100644
index 00000000..31a64146
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.AIX
@@ -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
+#
+# AIX Makefile for Directory Server plug-in examples
+
+INCLUDE_FLAGS= -I../include
+CFLAGS= $(INCLUDE_FLAGS) -D_THREAD_SAFE -qansialias -langlvl=ansi -qro -qroconst -qarch=com
+LIBPATH=/usr/lib/threads:/usr/lpp/xlC/lib:/usr/lib:/lib:..:../../../../lib
+EXTRA_LIBS= -bI:/usr/lib/lowsys.exp -lC_r -lC -lpthreads -lc_r -lm \
+ /usr/lib/libc.a
+LDFLAGS= -bE:libtest-plugin_shr.exp -G -bnoentry -blibpath:$(LIBPATH) \
+ $(EXTRA_LIBS)
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ rm -f libtest-plugin_shr.exp
+ echo "#!" > libtest-plugin_shr.exp
+ nm -B -C -g $(OBJS) | \
+ awk '/ [B,T,D] / {print $$3}' | \
+ sed -e 's/^\.//' | sort -u >> libtest-plugin_shr.exp
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so libtest-plugin_shr.exp
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.BSDI b/ldap/servers/slapd/test-plugins/Makefile.BSDI
new file mode 100644
index 00000000..0433e752
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.BSDI
@@ -0,0 +1,31 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.HPUX b/ldap/servers/slapd/test-plugins/Makefile.HPUX
new file mode 100644
index 00000000..06df5a21
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.HPUX
@@ -0,0 +1,25 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# HPUX Makefile for Directory Server plug-in examples
+
+INCLUDE = -I../include
+CFLAGS=$(INCLUDE) -D_HPUX_SOURCE -Aa +z +DAportable -Ae
+LDFLAGS = -b
+
+OBJS = testsaslbind.o testpreop.o testpostop.o testextendedop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.sl
+
+libtest-plugin.sl: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.sl
diff --git a/ldap/servers/slapd/test-plugins/Makefile.HPUX64 b/ldap/servers/slapd/test-plugins/Makefile.HPUX64
new file mode 100644
index 00000000..2e9fc329
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.HPUX64
@@ -0,0 +1,24 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# HPUX Makefile for Directory Server plug-in examples
+
+CFLAGS=$(INCLUDE_FLAGS) -D_HPUX_SOURCE -Aa +z +DA2.0W -Ae
+LDFLAGS = +k -b +s $(EXTRA_LIBS)
+
+OBJS = testsaslbind.o testpreop.o testpostop.o testextendedop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.sl
+
+libtest-plugin.sl: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.sl
diff --git a/ldap/servers/slapd/test-plugins/Makefile.IRIX b/ldap/servers/slapd/test-plugins/Makefile.IRIX
new file mode 100644
index 00000000..820e5d1b
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.IRIX
@@ -0,0 +1,31 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# IRIX Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../include
+CFLAGS = $(INCLUDE_FLAGS) -D_SGI_MP_SOURCE -fullwarn
+LDFLAGS = -32 -shared
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.Linux b/ldap/servers/slapd/test-plugins/Makefile.Linux
new file mode 100644
index 00000000..1e3de457
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.Linux
@@ -0,0 +1,31 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Linux Makefile for Directory Server plug-in examples
+#
+
+CC = gcc
+LD = ld
+
+INCLUDE_FLAGS = -I../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -fPIC
+LDFLAGS = -G
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.OSF1 b/ldap/servers/slapd/test-plugins/Makefile.OSF1
new file mode 100644
index 00000000..a1765d2e
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.OSF1
@@ -0,0 +1,30 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# OSF1 Makefile for Directory Server plug-in examples
+
+CC = cc
+LD = ld
+
+INCLUDE = -I../include
+CFLAGS = $(INCLUDE) -DIS_64 -ieee_with_inexact -pthread -DOSF1
+LDFLAGS = -shared -all -expect_unresolved "*" -taso
+
+
+OBJS = testsaslbind.o testpreop.o testpostop.o testextendedop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.ReliantUNIX b/ldap/servers/slapd/test-plugins/Makefile.ReliantUNIX
new file mode 100644
index 00000000..0433e752
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.ReliantUNIX
@@ -0,0 +1,31 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.SOLARIS b/ldap/servers/slapd/test-plugins/Makefile.SOLARIS
new file mode 100644
index 00000000..1914f3b2
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.SOLARIS
@@ -0,0 +1,28 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+INCLUDE_FLAGS = -I../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.SOLARIS64 b/ldap/servers/slapd/test-plugins/Makefile.SOLARIS64
new file mode 100644
index 00000000..151ea5b1
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.SOLARIS64
@@ -0,0 +1,28 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+INCLUDE_FLAGS = -I../include
+CFLAGS = $(INCLUDE_FLAGS) -xarch=v9 -D_REENTRANT -KPIC
+LDFLAGS = -G -xarch=v9
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.SOLARISx86 b/ldap/servers/slapd/test-plugins/Makefile.SOLARISx86
new file mode 100644
index 00000000..0433e752
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.SOLARISx86
@@ -0,0 +1,31 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.UnixWare b/ldap/servers/slapd/test-plugins/Makefile.UnixWare
new file mode 100644
index 00000000..0433e752
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.UnixWare
@@ -0,0 +1,31 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.UnixWareUDK b/ldap/servers/slapd/test-plugins/Makefile.UnixWareUDK
new file mode 100644
index 00000000..0433e752
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.UnixWareUDK
@@ -0,0 +1,31 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# SOLARIS Makefile for Directory Server plug-in examples
+#
+
+CC = cc
+LD = ld
+
+INCLUDE_FLAGS = -I../include
+CFLAGS = $(INCLUDE_FLAGS) -D_REENTRANT -KPIC
+LDFLAGS = -G
+
+OBJS = testsaslbind.o testextendedop.o testpreop.o testpostop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+all: libtest-plugin.so
+
+
+libtest-plugin.so: $(OBJS)
+ $(LD) $(LDFLAGS) -o $@ $(OBJS)
+
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+clean:
+ -rm -f $(OBJS) libtest-plugin.so
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.WINNT b/ldap/servers/slapd/test-plugins/Makefile.WINNT
new file mode 100644
index 00000000..d18d7ea7
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.WINNT
@@ -0,0 +1,45 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Makefile for Directory Server plug-in
+#
+
+CC = cl
+LD = link
+
+
+TARGET=testplugin
+
+OBJS=testsaslbind.obj testextendedop.obj testpreop.obj testpostop.obj testentry.obj testbind.obj testgetip.obj testdatainterop.obj testdbinterop.obj
+
+
+INC = ../include
+CFLAGS = /nologo -I $(INC) /c
+LDFLAGS = /dll /nologo
+LIBS=/DEFAULTLIB:kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib ../lib/libslapd.lib ../lib/libnspr4.lib ./lib/libdb42.lib
+
+
+all: \
+ init \
+ $(TARGET).dll
+
+init:
+ "c:\program files\microsoft visual studio\vc98\bin\vcvars32.bat"
+
+
+$(TARGET).dll: $(OBJS)
+ $(LD) $(LDFLAGS) /def:$(TARGET).def /out:$(TARGET).dll $(EXTRA_LIBS) $(LIBS) $(OBJS)
+ -rm -f $(OBJS2) *~
+
+%.obj:%.c
+ $(CC) $(CFLAGS) $<
+
+clean:
+ del -f $(OBJS) $(TARGET).dll *~
+
+
+
diff --git a/ldap/servers/slapd/test-plugins/Makefile.server b/ldap/servers/slapd/test-plugins/Makefile.server
new file mode 100644
index 00000000..4923aa38
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/Makefile.server
@@ -0,0 +1,107 @@
+#
+# PROPRIETARY/CONFIDENTIAL. Use of this product is subject to
+# license terms. Copyright 2001 Sun Microsystems, Inc.
+# Some preexisting portions Copyright 2001 Netscape Communications Corp.
+# All rights reserved.
+#
+#
+# GNU Makefile for Directory Server distribution plugin
+#
+
+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 = $(OBJDIR)/lib/libtestplug
+LIBDIR = $(LIB_RELDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+
+ifeq ($(ARCH), WINNT)
+DEF_FILE:=./libdistrib.def
+endif
+
+CFLAGS+=$(SLCFLAGS)
+
+INCLUDES += -I$(LDAP_SRC)/servers/slapd -I$(DB_INCLUDE)
+
+DIS_OBJS= \
+ testsaslbind.o testpreop.o testpostop.o testextendedop.o testentry.o testbind.o testgetip.o testdatainterop.o testdbinterop.o
+
+OBJS = $(addprefix $(OBJDEST)/, $(DIS_OBJS))
+
+ifeq ($(ARCH), WINNT)
+LIBDIS_DLL_OBJ = $(addprefix $(OBJDEST)/, dllmain.o)
+endif
+
+# The sample distribution plugin is not part of DS.
+# So we generate the shared library outside of $(LIBDIR)
+# so that it's not retreived by the packaging makefiles.
+#LIBDIS = $(addprefix $(LIBDIR)/, $(DIS_DLL).$(DLL_SUFFIX))
+LIBDIS = $(addprefix $(OBJDEST)/, $(TEST_PLUGIN_DLL).$(DLL_SUFFIX))
+
+ifeq ($(ARCH), WINNT)
+EXTRA_LIBS_DEP += \
+ $(LIBSLAPD_DEP) \
+ $(LDAP_LIBUTIL_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP) \
+ $(SECURITY_DEP)
+EXTRA_LIBS += \
+ $(LIBSLAPD) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LIBUTIL) \
+ $(NSPRLINK) \
+ $(LDAP_COMMON_LIBS)
+endif
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS_DEP += \
+ $(LIBSLAPD_DEP) \
+ $(LDAP_LIBUTIL_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+EXTRA_LIBS_DEP += \
+ $(LDAPSDK_DEP)
+EXTRA_LIBS += \
+ $(LIBSLAPDLINK) \
+ $(LDAP_SDK_LIBLDAP_DLL) \
+ $(LIBUTIL) \
+ $(NSPRLINK) \
+ $(LDAP_COMMON_LIBS)
+endif
+
+EXTRA_LIBS_DEP += $(LIBSLAPD_DEP) $(LDAPSDK_DEP) $(NSPR_DEP) $(DB_LIB_DEP)
+EXTRA_LIBS += $(DYN_NSHTTPD) $(ADMINUTIL_LINK) $(LDAPLINK) $(NSPRLINK) $(ICULINK) $(DB_LIB)
+
+ifeq ($(ARCH), WINNT)
+DLL_LDFLAGS += -def:"./libdistrib.def"
+CFLAGS+= /WX
+endif # WINNT
+
+ifeq ($(ARCH), AIX)
+LD=ld
+endif
+
+clientSDK:
+
+all: $(OBJDEST) $(LIBDIR) $(LIBDIS)
+
+$(LIBDIS): $(OBJS) $(LIBDIS_DLL_OBJ) $(DEF_FILE)
+ $(LINK_DLL) $(LIBDIS_DLL_OBJ) $(EXTRA_LIBS)
+
+veryclean: clean
+
+clean:
+ $(RM) $(OBJS)
+ifeq ($(ARCH), WINNT)
+ $(RM) $(LIBDIS_DLL_OBJ)
+endif
+ $(RM) $(LIBDIS)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
diff --git a/ldap/servers/slapd/test-plugins/README b/ldap/servers/slapd/test-plugins/README
new file mode 100644
index 00000000..ecdcac58
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/README
@@ -0,0 +1,149 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+ ----------------------------
+ Sample Server Plug-Ins
+ for Directory Server 7
+ ----------------------------
+
+This directory contains code for some sample server plug-ins intended for
+use with the Netscape Directory Server 7.
+
+ NOTE: Before you compile and run these examples, make sure
+ to change any server-specific data in the examples to
+ values applicable to your Directory Server.
+
+testbind.c
+----------
+This is an example of a pre-operation bind plug-in function that
+handles authentication. When processing an LDAP bind request, the
+server calls this plug-in function before calling the database bind
+function.
+
+testentry.c
+-----------
+This is an example of an entry store plug-in function and an entry fetch
+plug-in function. You must be using the default database (not your own
+back-end database) in order for these plug-in functions to work.
+
+testextendedop.c
+----------------
+This is an example of an extended operation plug-in function that
+handles requests for the extended operation with the OID 1.2.3.4.
+The example should be used in conjunction with the reqextop.c and
+ReqExtOp.java clients (the source code for these clients is located
+in the clients subdirectory). These clients are capable of requesting
+the extended operation with the OID 1.2.3.4.
+
+testpostop.c
+------------
+This contains examples of post-operation plug-in functions. These
+functions are called after the server processes LDAP operations.
+The functions log changes to the directory in a change log file.
+
+testpreop.c
+-----------
+This contains examples of pre-operation plug-in functions. These
+functions are called before the server processes LDAP operations.
+
+testsaslbind.c
+--------------
+This is an example of a pre-operation plug-in function that
+implements a SASL mechanism.
+
+clients
+-------
+This directory contains the C and Java source code for clients
+that you can use to test the server plug-ins. See the README
+file in that directory for details.
+
+
+ ----------------------------
+ How To Create
+ A Server Plug-In
+ ----------------------------
+
+Text between brackets ([]) should be replaced with values specific to
+your situation.
+
+
+Creating the Plug-In Library
+----------------------------
+Server plug-ins are built as libraries available to the server.
+
+1. Include the Plug-In API. For example:
+
+ #include "[serverRoot]/plugins/slapd/slapi/include/slapi-plugin.h"
+
+2. Write your plug-in, including a top level initialization function
+ used by the server to start the plug-in. For example:
+
+ /* Plug-in functions defined here */
+
+ int my_plugin_init( Slapi_PBlock *pb ) /* initialize param. block */
+ {
+ /* Set or get the parameters in pb */
+ slapi_pblock_set();
+ slapi_pblock_get();
+
+ /* Plug-in functions registered here */
+
+ if (error)
+ {
+ slapi_log_error();
+ return error_code;
+ }
+ else return 0;
+
+ } /* my_plugin_init() */
+
+ See the Parameter Block Reference in the Netscape Directory Server
+ Plug-In Programmer's Guide for hints on plug-in types.
+
+3. Build the plug-in as a library.
+
+ We recommend you copy and adapt the Makefile in
+ [serverRoot]/plugins/slapd/slapi/examples.
+
+
+Plugging the Library Into the Server
+------------------------------------
+When started, the server loads plug-ins.
+
+1. Stop the server.
+
+ Console: Select the server; Object > Stop Server
+ Command Line: cd [serverRoot]/slapd-[serverID] ; ./stop-slapd
+
+2. Add the entry for the server plug-in to
+ [serverRoot]/slapd-[serverID]/config/dse.ldif. For example:
+
+ dn: cn=[My Server Plugin],cn=plugins,cn=config
+ objectClass: top
+ objectClass: nsSlapdPlugin
+ objectClass: extensibleObject
+ cn: [My Server Plugin]
+ nsslapd-pluginPath: [[serverRoot]/myPlugins/myveryown-plugin.so]
+ nsslapd-pluginInitfunc: [my_plugin_init]
+ nsslapd-pluginType: [myPluginType]
+ nsslapd-pluginEnabled: on
+ nsslapd-pluginarg0: [uid]
+ nsslapd-pluginarg1: [mail]
+ nsslapd-pluginarg2: [...]
+ nsslapd-plugin-depends-on-type: [anotherPluginType]
+ nsslapd-pluginId: [MyFirstServerPlugin]
+ nsslapd-pluginVersion: [0.1]
+ nsslapd-pluginVendor: [Fictional Software Company Incorporated]
+ nsslapd-pluginDescription: [Add lots of cool functionality]
+
+ See the Parameter Block Reference in the Netscape Directory Server
+ Plug-In Programmer's Guide for hints on plug-in types.
+
+3. Restart the server.
+
+ Console: Object > Start Server
+ Command Line: cd [serverRoot]/slapd-[serverID] ; ./restart-slapd
diff --git a/ldap/servers/slapd/test-plugins/clients/README b/ldap/servers/slapd/test-plugins/clients/README
new file mode 100644
index 00000000..a2aac49d
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/clients/README
@@ -0,0 +1,45 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+ ---------------------------
+ Sample LDAP Clients That
+ Work with Server Plug-Ins
+ ---------------------------
+
+This directory contains code for some sample LDAP clients intended for
+use with the sample server plug-ins. For example, one of the server
+plug-ins handles requests for an extended operation with the OID 1.2.3.4.
+In order to test this sample plug-in, you need an LDAP v3 client that is
+capable of requesting this extended operation.
+
+ NOTE: Before you compile and run these examples, make sure
+ to change the server name, port number, root DN, and root DN
+ password to values applicable to your Directory Server.
+
+reqextop.c
+----------
+This is an example of an LDAP client that requests extended operations.
+The example should be used in conjunction with the testexop.c server
+plug-in, which handles the extended operation with the OID 1.2.3.4.
+
+This example requires a version of the Netscape Directory SDK that supports
+the LDAP v3 protocol. The 3.0 Beta version of the Directory SDK for C
+supports LDAP v3 and is available at the following location:
+
+ http://developer.netscape.com/tech/directory/
+
+ReqExtOp.java
+-------------
+This is an example of an LDAP client that requests extended operations.
+The example should be used in conjunction with the testexop.c server
+plug-in, which handles the extended operation with the OID 1.2.3.4.
+
+This example requires a version of the Netscape Directory SDK that supports
+the LDAP v3 protocol. The Netscape Directory SDK for Java 3.0 supports
+LDAP v3 and is available at the following location:
+
+ http://developer.netscape.com/tech/directory/
+
diff --git a/ldap/servers/slapd/test-plugins/clients/ReqExtOp.java b/ldap/servers/slapd/test-plugins/clients/ReqExtOp.java
new file mode 100644
index 00000000..cf29ea21
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/clients/ReqExtOp.java
@@ -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 **/
+/*
+ *
+ * Requests an extended operation with the OID 1.2.3.4.
+ * Use this client in conjunction with a server that can process
+ * this extended operation.
+ *
+ */
+
+import netscape.ldap.*;
+import java.util.*;
+import java.io.*;
+
+public class ReqExtOp {
+ public static void main( String[] args )
+ {
+ LDAPConnection ld = null;
+ int status = -1;
+ try {
+ ld = new LDAPConnection();
+
+ /* Connect to server */
+ String MY_HOST = "localhost";
+ int MY_PORT = 389;
+ ld.connect( MY_HOST, MY_PORT );
+ System.out.println( "Connected to server." );
+
+ /* Authenticate to the server as directory manager */
+ String MGR_DN = "cn=Directory Manager";
+ String MGR_PW = "23skidoo";
+ if ( ld.LDAP_VERSION < 3 ) {
+ ld.authenticate( 3, MGR_DN, MGR_PW );
+ } else {
+ System.out.println( "Specified LDAP server does not support v3 of the LDAP protocol." );
+ ld.disconnect();
+ System.exit(1);
+ }
+ System.out.println( "Authenticated to directory." );
+
+ /* Create an extended operation object */
+ String myval = "My Value";
+ byte vals[] = myval.getBytes( "UTF8" );
+ LDAPExtendedOperation exop = new LDAPExtendedOperation( "1.2.3.4", vals );
+ System.out.println( "Created LDAPExtendedOperation object." );
+
+ /* Request the extended operation from the server. */
+ LDAPExtendedOperation exres = ld.extendedOperation( exop );
+
+ System.out.println( "Performed extended operation." );
+
+ /* Get data from the response sent by the server. */
+ System.out.println( "OID: " + exres.getID() );
+ String retValue = new String( exres.getValue(), "UTF8" );
+ System.out.println( "Value: " + retValue );
+ }
+ catch( LDAPException e ) {
+ System.out.println( "Error: " + e.toString() );
+ }
+ catch( UnsupportedEncodingException e ) {
+ System.out.println( "Error: UTF8 not supported" );
+ }
+
+ /* Done, so disconnect */
+ if ( (ld != null) && ld.isConnected() ) {
+ try {
+ ld.disconnect();
+ } catch ( LDAPException e ) {
+ System.out.println( "Error: " + e.toString() );
+ }
+ }
+ System.exit(status);
+ }
+}
diff --git a/ldap/servers/slapd/test-plugins/clients/reqextop.c b/ldap/servers/slapd/test-plugins/clients/reqextop.c
new file mode 100644
index 00000000..f23bcf38
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/clients/reqextop.c
@@ -0,0 +1,85 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Requests an extended operation with the OID 1.2.3.4.
+ * Use this client in conjunction with a server that can process
+ * this extended operation.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include <ldap.h>
+
+/* Name and port of the LDAP server you want to connect to. */
+#define MY_HOST "localhost"
+#define MY_PORT 389
+
+/* DN of user (and password of user) who you want to authenticate as */
+#define MGR_DN "cn=Directory Manager"
+#define MGR_PW "23skidoo"
+
+int
+main( int argc, char **argv )
+{
+
+ /* OID of the extended operation that you are requesting */
+ const char *oidrequest = "1.2.3.4";
+ char *oidresult;
+ struct berval valrequest;
+ struct berval *valresult;
+ LDAP *ld;
+ int rc, version;
+
+ /* Set up the value that you want to pass to the server */
+ printf( "Setting up value to pass to server...\n" );
+ valrequest.bv_val = "My Value";
+ valrequest.bv_len = strlen( "My Value" );
+
+ /* Get a handle to an LDAP connection */
+ printf( "Getting the handle to the LDAP connection...\n" );
+ if ( (ld = ldap_init( MY_HOST, MY_PORT )) == NULL ) {
+ perror( "ldap_init" );
+ ldap_unbind( ld );
+ return( 1 );
+ }
+
+ /* Set the LDAP protocol version supported by the client
+ to 3. (By default, this is set to 2. Extended operations
+ are part of version 3 of the LDAP protocol.) */
+ ldap_get_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
+ printf( "Resetting version %d to 3.0...\n", version );
+ version = LDAP_VERSION3;
+ ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
+
+ /* Authenticate to the directory as the Directory Manager */
+ printf( "Binding to the directory...\n" );
+ if ( ldap_simple_bind_s( ld, MGR_DN, MGR_PW ) != LDAP_SUCCESS ) {
+ ldap_perror( ld, "ldap_simple_bind_s" );
+ ldap_unbind( ld );
+ return( 1 );
+ }
+
+ /* Initiate the extended operation */
+ printf( "Initiating the extended operation...\n" );
+ if ( ( rc = ldap_extended_operation_s( ld, oidrequest, &valrequest, NULL, NULL, &oidresult, &valresult ) ) != LDAP_SUCCESS ) {
+ ldap_perror( ld, "ldap_extended failed: " );
+ ldap_unbind( ld );
+ return( 1 );
+ }
+
+ /* Get the OID and the value from the result returned by the server. */
+ printf( "Operation successful.\n" );
+ printf( "\tReturned OID: %s\n", oidresult );
+ printf( "\tReturned value: %s\n", valresult->bv_val );
+
+ /* Disconnect from the server. */
+ ldap_unbind( ld );
+ return 0;
+}
+
diff --git a/ldap/servers/slapd/test-plugins/dllmain.c b/ldap/servers/slapd/test-plugins/dllmain.c
new file mode 100644
index 00000000..f50f3595
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/dllmain.c
@@ -0,0 +1,109 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Microsoft Windows specifics for sample plug-ins DLL
+ */
+#include "ldap.h"
+#include "lber.h"
+
+#ifdef _WIN32
+/* Lifted from Q125688
+ * How to Port a 16-bit DLL to a Win32 DLL
+ * on the MSVC 4.0 CD
+ */
+BOOL WINAPI DllMain (HANDLE hModule, DWORD fdwReason, LPVOID lpReserved)
+{
+ WSADATA wsadata;
+
+ switch (fdwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ /* Code from LibMain inserted here. Return TRUE to keep the
+ DLL loaded or return FALSE to fail loading the DLL.
+
+ You may have to modify the code in your original LibMain to
+ account for the fact that it may be called more than once.
+ You will get one DLL_PROCESS_ATTACH for each process that
+ loads the DLL. This is different from LibMain which gets
+ called only once when the DLL is loaded. The only time this
+ is critical is when you are using shared data sections.
+ If you are using shared data sections for statically
+ allocated data, you will need to be careful to initialize it
+ only once. Check your code carefully.
+
+ Certain one-time initializations may now need to be done for
+ each process that attaches. You may also not need code from
+ your original LibMain because the operating system may now
+ be doing it for you.
+ */
+ /*
+ * 16 bit code calls UnlockData()
+ * which is mapped to UnlockSegment in windows.h
+ * in 32 bit world UnlockData is not defined anywhere
+ * UnlockSegment is mapped to GlobalUnfix in winbase.h
+ * and the docs for both UnlockSegment and GlobalUnfix say
+ * ".. function is oboslete. Segments have no meaning
+ * in the 32-bit environment". So we do nothing here.
+ */
+
+ if( errno = WSAStartup(0x0101, &wsadata ) != 0 )
+ return FALSE;
+
+ break;
+
+ case DLL_THREAD_ATTACH:
+ /* Called each time a thread is created in a process that has
+ already loaded (attached to) this DLL. Does not get called
+ for each thread that exists in the process before it loaded
+ the DLL.
+
+ Do thread-specific initialization here.
+ */
+ break;
+
+ case DLL_THREAD_DETACH:
+ /* Same as above, but called when a thread in the process
+ exits.
+
+ Do thread-specific cleanup here.
+ */
+ break;
+
+ case DLL_PROCESS_DETACH:
+ /* Code from _WEP inserted here. This code may (like the
+ LibMain) not be necessary. Check to make certain that the
+ operating system is not doing it for you.
+ */
+ WSACleanup();
+
+ break;
+ }
+ /* The return value is only used for DLL_PROCESS_ATTACH; all other
+ conditions are ignored.
+ */
+ return TRUE; // successful DLL_PROCESS_ATTACH
+}
+#else
+int CALLBACK
+LibMain( HINSTANCE hinst, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine )
+{
+ /*UnlockData( 0 );*/
+ return( 1 );
+}
+#endif
+
+#ifndef _WIN32
+/* The 16-bit version of the RTL does not implement perror() */
+#include <stdio.h>
+
+void perror( const char *msg )
+{
+ char buf[128];
+ wsprintf( buf, "%s: error %d\n", msg, WSAGetLastError()) ;
+ OutputDebugString( buf );
+}
+
+#endif
diff --git a/ldap/servers/slapd/test-plugins/installDse.pl b/ldap/servers/slapd/test-plugins/installDse.pl
new file mode 100755
index 00000000..6b827ab4
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/installDse.pl
@@ -0,0 +1,129 @@
+# The script is used to load the config mapping tree node for the null suffix
+# and to load the test sample plugin node into the Directory Server used to
+# demonstrate the Data Interoperability feature for Verisign.
+
+# The dse.ldif configuration file used as the default configuration by the
+# Server gets edited for adding the above mentioned two config nodes and the
+# server is restarted to load the plugin.
+
+# The loading of the DataInterop test plugin is only to demostrate the use
+# of the test plugin and can be replaced with Verisign's database plugin for use.
+
+# Written by binduk@netscape.com
+
+# Edits to be done for use
+# $host = Hostname of the Directory Server
+# $port = port used by the Server
+# $mgrdn = Bind Dn
+# $mgrpass = Password
+# $installDir = Installation root of the Server <server-root>
+
+
+###### Begin Edits ##################################
+
+$host = "trika.nscp.aoltw.net";
+$instance = "trika2";
+$port = "7775";
+$mgrdn = "cn=directory manager";
+$mgrpass = "password";
+$installDir = "/export/msyBuild/install"; # Installation root of the Server <server-root>
+
+###### End of Edits ##################################
+
+
+$dseOrgFile = "$installDir/slapd-$instance/config/dse.ldif"; # default configuration file to be edited
+$dseFile = "$installDir/slapd-$instance/config/load_dse.ldif"; # additional configuration file to be added
+$pidFile = "$installDir/slapd-$instance/logs/pid"; # pid file for the running server
+my $editedNode = 0;
+my $editedPlugin = 0;
+my $serverStatus = 1;
+
+
+ if(!(-e $pidFile)){
+ open( START_SERVER, "| $installDir/slapd-$instance/start-slapd ") || die "Can't Start the Server \n";
+ close(START_SERVER);
+
+ if(-e $pidFile){
+ print " ######## Started the Server \n";
+ }
+ else {
+ print " ######## Unable to Start the Server \n";
+ $serverStatus = 0;
+ }
+ }
+
+
+open(DSE_ORG, "$dseOrgFile") || die "Can't open $dseOrgFile for checks \n";
+ while(<DSE_ORG>){
+ $isEditedNode = 1 if (/^dn: cn=\"\",cn=mapping tree,cn=config/);
+ $isEditedPlugin = 1 if (/^dn: cn=datainterop,cn=plugins,cn=config/);
+ }
+close(DSE_ORG);
+
+open(DSE, ">$dseFile") || die "Can't open $dseFile for editing \n";
+
+ my $changesMade = 0;
+ unless($isEditedNode){
+ print DSE "dn: cn=\"\",cn=mapping tree,cn=config\n";
+ print DSE "objectClass: top\n";
+ print DSE "objectClass: extensibleObject\n";
+ print DSE "objectClass: nsMappingTree\n";
+ print DSE "cn: \"\"\n";
+ print DSE "nsslapd-state: container\n";
+ print DSE "\n";
+ $changesMade = 1;
+ }
+
+ unless($isEditedPlugin){
+ print DSE "dn: cn=datainterop,cn=plugins,cn=config\n";
+ print DSE "objectClass: top\n";
+ print DSE "objectClass: nsSlapdPlugin\n";
+ print DSE "cn: datainterop\n";
+ print DSE "nsslapd-pluginPath: $installDir/plugins/slapd/slapi/examples/libtest-plugin.so\n";
+ print DSE "nsslapd-pluginInitfunc: nullsuffix_init\n";
+ print DSE "nsslapd-pluginType: preoperation\n";
+ print DSE "nsslapd-pluginEnabled: on\n";
+ print DSE "nsslapd-pluginId: nullsuffix-preop\n";
+ print DSE "nsslapd-pluginVersion: 6.2\n";
+ print DSE "nsslapd-pluginVendor: Netscape\n";
+ print DSE "nsslapd-pluginDescription: sample pre-operation null suffix search plugin\n";
+ $changesMade = 1;
+ }
+close(DSE);
+
+
+if($changesMade){
+ chdir "$installDir/shared/bin" or die "cannot cd over error=$! \n";
+
+ open(LDAPMODIFY, "|ldapmodify -p \"${port}\" -h \"${host}\" -D \"${mgrdn}\" -w \"${mgrpass}\" -v -c -a -f $dseFile " ) || die "Can't modify the configuration of the Server \n";
+
+ close(LDAPMODIFY);
+
+ print " Modifications to the dse.ldif file have been done....restarting the server to load plugin \n";
+
+ open( STOP_SERVER, "| $installDir/slapd-$instance/stop-slapd ") || die "Can't Stop the Server \n";;
+ close(STOP_SERVER);
+
+ print " Now stopped the Server to load the plugin \n";
+
+ open( START_SERVER, "| $installDir/slapd-$instance/start-slapd ") || die "Can't Start the Server \n";
+ close(START_SERVER);
+
+ if(-e $pidFile){
+ print " Started the Server Successfully\n";
+ }
+ else{
+ $serverStatus = 0;
+ print "Failure in starting the Server - Check to see if the sample plugin has been compiled \n";
+ }
+
+}
+else {
+ if($serverStatus){
+ print " Nothing needs to be done \n";
+ }
+ else {
+ print " The Server did not Start Successfully \n";
+ }
+
+}
diff --git a/ldap/servers/slapd/test-plugins/nicknames b/ldap/servers/slapd/test-plugins/nicknames
new file mode 100644
index 00000000..1d7a2515
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/nicknames
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+Timothy Tim Timbo Timmy
+Barbara Babs Buddah
+Robert Rob Bob Rob-bob Robby Bobby
diff --git a/ldap/servers/slapd/test-plugins/testbind.c b/ldap/servers/slapd/test-plugins/testbind.c
new file mode 100644
index 00000000..4d080a0f
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testbind.c
@@ -0,0 +1,252 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/************************************************************
+
+ testbind.c
+
+ This source file provides an example of a pre-operation plug-in
+ function that handles authentication.
+
+ Note that the Directory Server front-end handles bind
+ operations requested by the root DN. The server does not
+ invoke your plug-in function if the client is authenicating
+ as the root DN.
+
+ To test this plug-in function, stop the server, edit the dse.ldif file
+ (in the <server_root>/slapd-<server_id>/config directory)
+ and add the following lines before restarting the server :
+
+ dn: cn=Test Bind,cn=plugins,cn=config
+ objectClass: top
+ objectClass: nsSlapdPlugin
+ objectClass: extensibleObject
+ cn: Test Bind
+ nsslapd-pluginPath: <server_root>/plugins/slapd/slapi/examples/libtest-plugin.so
+ nsslapd-pluginInitfunc: testbind_init
+ nsslapd-pluginType: preoperation
+ nsslapd-pluginEnabled: on
+ nsslapd-plugin-depends-on-type: database
+ nsslapd-pluginId: test-bind
+
+ ************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include "slapi-plugin.h"
+
+Slapi_PluginDesc bindpdesc = { "test-bind", "Netscape", "0.5",
+ "sample bind pre-operation plugin" };
+
+static Slapi_ComponentId *plugin_id = NULL;
+
+
+
+
+/* Pre-operation plug-in function */
+int
+test_bind( Slapi_PBlock *pb )
+{
+ char *dn, *attrs[2] = { SLAPI_USERPWD_ATTR, NULL };
+ int method, rc = LDAP_SUCCESS;
+ struct berval *credentials;
+ struct berval **pwvals;
+ Slapi_DN *sdn = NULL;
+ Slapi_Entry *e = NULL;
+ Slapi_Attr *attr = NULL;
+
+ /* Log a message to the server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Pre-operation bind function called.\n" );
+
+ /* Gets parameters available when processing an LDAP bind
+ operation. */
+ if ( slapi_pblock_get( pb, SLAPI_BIND_TARGET, &dn ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &credentials ) != 0 ) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Could not get parameters for bind operation\n" );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR,
+ NULL, NULL, 0, NULL );
+ return( 1 );
+ }
+
+ /* Check the authentication method */
+ switch( method ) {
+ case LDAP_AUTH_SIMPLE:
+ /* First, get the entry specified by the DN. */
+ sdn = slapi_sdn_new_dn_byref( dn );
+ rc = slapi_search_internal_get_entry( sdn, attrs, &e,
+ plugin_id );
+ slapi_sdn_free( &sdn );
+
+ if ( rc != LDAP_SUCCESS ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Could not find entry %s (error %d)\n",
+ dn, rc );
+ break;
+ }
+
+ /* Next, check credentials against the userpassword attribute
+ of that entry. */
+ if ( e != NULL ) {
+ Slapi_Value *credval, **pwvals;
+ int i, hint, valcount;
+
+
+ if ( slapi_entry_attr_find( e, SLAPI_USERPWD_ATTR,
+ &attr ) != 0 || slapi_attr_get_numvalues( attr,
+ &valcount ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Entry has no %s attribute values\n",
+ SLAPI_USERPWD_ATTR );
+ rc = LDAP_INAPPROPRIATE_AUTH;
+ break;
+ }
+
+ credval = slapi_value_new_berval( credentials );
+ pwvals = (Slapi_Value **)slapi_ch_calloc( valcount,
+ sizeof( Slapi_Value * ));
+ i = 0;
+ for ( hint = slapi_attr_first_value( attr, &pwvals[i] );
+ hint != -1; hint = slapi_attr_next_value( attr,
+ hint, &pwvals[i] )) {
+ ++i;
+ }
+
+ if ( slapi_pw_find_sv( pwvals, credval ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Credentials are not correct\n" );
+ rc = LDAP_INVALID_CREDENTIALS;
+ }
+
+ slapi_value_free( &credval );
+ slapi_ch_free( (void **)&pwvals );
+
+ if ( LDAP_SUCCESS != rc ) {
+ break;
+ }
+ } else {
+ /* This should not happen. The previous section of code
+ already checks for this case. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Could find entry for %s\n", dn );
+ rc = LDAP_NO_SUCH_OBJECT;
+ break;
+ }
+
+ /* Set the DN and authentication method for the connection. */
+ if ( slapi_pblock_set( pb, SLAPI_CONN_DN,
+ slapi_ch_strdup( dn ) ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_CONN_AUTHMETHOD,
+ SLAPD_AUTH_SIMPLE ) != 0 ) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Failed to set DN and method for connection\n" );
+ rc = LDAP_OPERATIONS_ERROR;
+ break;
+ }
+
+ /* Send a "success" result code back to the client. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Authenticated: %s\n", dn );
+ rc = LDAP_SUCCESS;
+ break;
+
+ /* If NONE is specified, the client is requesting to bind anonymously.
+ Normally, this case should be handled by the server's front-end
+ before it calls this plug-in function. Just in case this does
+ get through to the plug-in function, you can handle this by
+ sending a successful result code back to the client and returning
+ 1.
+ */
+ case LDAP_AUTH_NONE:
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Authenticating anonymously\n" );
+ rc = LDAP_SUCCESS;
+ break;
+
+ /* This plug-in does not support any other method of authentication */
+ case LDAP_AUTH_SASL:
+ default:
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_bind",
+ "Unsupported authentication method requested: %d\n",
+ method );
+ rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
+ break;
+ }
+
+ slapi_send_ldap_result( pb, rc, NULL, NULL, 0, NULL );
+ return( 1 );
+}
+
+/* Pre-operation plug-in function */
+int
+test_search( Slapi_PBlock *pb )
+{
+ char *reqdn;
+
+ /* Log a message to the server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_search",
+ "Pre-operation search function called.\n" );
+
+ /* Get requestor of search operation. This is not critical
+ to performing the search (this plug-in just serves as
+ confirmation that the bind plug-in works), so return 0
+ if this fails. */
+ if ( slapi_pblock_get( pb, SLAPI_REQUESTOR_DN, &reqdn ) != 0 ) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_search",
+ "Could not get requestor parameter for search operation\n" );
+ return( 0 );
+ }
+
+ /* Indicate who is requesting the search */
+ if ( reqdn != NULL && *reqdn != '\0' ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_search",
+ "Search requested by %s\n", reqdn );
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "test_search",
+ "Search requested by anonymous client\n" );
+ }
+ return( 0 );
+}
+
+/* Initialization function */
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int
+testbind_init( Slapi_PBlock *pb )
+{
+
+ /* Retrieve and save the plugin identity to later pass to
+ internal operations */
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_IDENTITY, &plugin_id ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testbind_init",
+ "Failed to retrieve SLAPI_PLUGIN_IDENTITY\n" );
+ return( -1 );
+ }
+
+ /* Register the pre-operation bind function and specify
+ the server plug-in version. */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&bindpdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN,
+ (void *) test_bind ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN,
+ (void *) test_search ) != 0 ) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testbind_init",
+ "Failed to set version and functions\n" );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
diff --git a/ldap/servers/slapd/test-plugins/testdatainterop.c b/ldap/servers/slapd/test-plugins/testdatainterop.c
new file mode 100644
index 00000000..19b171c1
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testdatainterop.c
@@ -0,0 +1,312 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2002 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/******** testdatainterop.c *******************
+
+ This source file provides an example of a plug-in function
+ that implements an datainteroprability functionality.
+ The plug-in function is called by the server
+ when the server is configured to use the null dn.
+ meaning dn:
+ The server uses the null dn or the root suffix opnly when
+ the configuration for the server has the following
+ node in the dse.ldif of the server instance
+ (in the <server_root>/slapd-<server_id>/config directory).
+
+ dn: cn="",cn=mapping tree,cn=config
+ objectClass: top
+ objectClass: extensibleObject
+ objectClass: nsMappingTree
+ cn: ""
+ nsslapd-state: container
+
+ The plugin below is a pre-operation plugin which
+ provides alternate functionality for the LDAP operations
+ of search, modify, add etc. that are targeted at the root-suffix
+ or the null-dn to be serviced by an alternate data source or
+ alternate access methods allowing datainteroperability.
+
+ The example below creates a berkely db and modifies or adds data
+ to the db demonstarting the use of an alternate data source seperate
+ from the Directory Server. Also, the results of a search operation
+ are completely in the control of the pre-operation plugin. In this
+ example a fake entry is returned to express the functionality
+
+
+ To test this plug-in function, stop the server, edit the dse.ldif file
+ (in the <server_root>/slapd-<server_id>/config directory)
+ and add the following lines before restarting the server :
+
+ dn: cn="",cn=mapping tree,cn=config
+ objectClass: top
+ objectClass: extensibleObject
+ objectClass: nsMappingTree
+ cn: ""
+ nsslapd-state: container
+
+
+ dn: cn=datainterop,cn=plugins,cn=config
+ objectClass: top
+ objectClass: nsSlapdPlugin
+ cn: datainterop
+ nsslapd-pluginPath: <server-root>/plugins/slapd/slapi/examples/libtest-plugin.so
+ nsslapd-pluginInitfunc: nullsuffix_init
+ nsslapd-pluginType: preoperation
+ nsslapd-pluginEnabled: on
+ nsslapd-pluginId: nullsuffix-preop
+ nsslapd-pluginVersion: 6.2
+ nsslapd-pluginVendor: Netscape
+ nsslapd-pluginDescription: sample pre-operation null suffix plugin
+
+ ******************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "slapi-plugin.h"
+
+/*
+ * Macros.
+ */
+#define PLUGIN_NAME "nullsuffix-preop"
+
+#define PLUGIN_OPERATION_HANDLED 1
+#define PLUGIN_OPERATION_IGNORED 0
+
+#define SEARCH_SCOPE_ANY (-1)
+
+
+
+/*
+ * Static variables.
+ */
+static Slapi_PluginDesc plugindesc = { PLUGIN_NAME, "Netscape", "0.5",
+ "sample pre-operation null suffix plugin" };
+
+static Slapi_ComponentId *plugin_id = NULL;
+
+
+/*
+ * Function prototypes.
+ */
+static int nullsuffix_search( Slapi_PBlock *pb );
+static int nullsuffix_add( Slapi_PBlock *pb );
+static int nullsuffix_close( Slapi_PBlock *pb );
+static int nullsuffix_modify( Slapi_PBlock *pb );
+static int nullsuffix_delete( Slapi_PBlock *pb );
+static int nullsuffix_modrdn( Slapi_PBlock *pb );
+static int nullsuffix_bind( Slapi_PBlock *pb );
+
+
+/*
+ * Initialization function.
+ */
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int
+nullsuffix_init( Slapi_PBlock *pb )
+{
+ int i;
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_init\n" );
+
+ /* retrieve plugin identity to later pass to internal operations */
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_IDENTITY, &plugin_id ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME,
+ "unable to get SLAPI_PLUGIN_IDENTITY\n" );
+ return -1;
+ }
+
+ /* register the pre-operation search function, etc. */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01
+ ) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&plugindesc ) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN,
+ (void *)nullsuffix_search ) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_CLOSE_FN,
+ (void *)nullsuffix_close ) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_ADD_FN,
+ (void *)nullsuffix_add) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_MODIFY_FN,
+ (void *)nullsuffix_modify) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_DELETE_FN,
+ (void *)nullsuffix_delete) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN,
+ (void *)nullsuffix_bind) != 0
+ || slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_MODRDN_FN,
+ (void *)nullsuffix_modrdn) != 0) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME,
+ "failed to set version and function\n" );
+ return -1;
+ }
+
+
+
+ return 0;
+}
+
+static int
+nullsuffix_bind( Slapi_PBlock *pb )
+{
+ if( slapi_op_reserved(pb) ){
+ return PLUGIN_OPERATION_IGNORED;
+ }
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_bind\n" );
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ return PLUGIN_OPERATION_HANDLED;
+
+}
+
+static int
+nullsuffix_add( Slapi_PBlock *pb )
+{
+ char *dn;
+ if( slapi_op_reserved(pb) ){
+ return PLUGIN_OPERATION_IGNORED;
+ }
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_add\n" );
+ slapi_pblock_get( pb, SLAPI_ADD_TARGET, &dn );
+ db_put_dn(dn);
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ return PLUGIN_OPERATION_HANDLED;
+}
+
+static int
+nullsuffix_modify( Slapi_PBlock *pb )
+{
+ Slapi_Entry *entry;
+ int i;
+ int j;
+ char *dn;
+ if( slapi_op_reserved(pb) ){
+ return PLUGIN_OPERATION_IGNORED;
+ }
+ slapi_pblock_get( pb, SLAPI_MODIFY_TARGET, &dn );
+ slapi_pblock_get( pb, SLAPI_ENTRY_PRE_OP, &entry);
+ db_put_dn(dn);
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_modify\n" );
+ return PLUGIN_OPERATION_HANDLED;
+
+}
+
+static int
+nullsuffix_delete( Slapi_PBlock *pb )
+{
+ if( slapi_op_reserved(pb) ){
+ return PLUGIN_OPERATION_IGNORED;
+ }
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_delete\n" );
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ return PLUGIN_OPERATION_HANDLED;
+}
+
+static int
+nullsuffix_modrdn( Slapi_PBlock *pb )
+{
+ if( slapi_op_reserved(pb) ){
+ return PLUGIN_OPERATION_IGNORED;
+ }
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_modrdn\n" );
+ send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+ return PLUGIN_OPERATION_HANDLED;
+}
+
+static int
+nullsuffix_search( Slapi_PBlock *pb )
+{
+ char *dn_base, **attrs, *newStr;
+ int scope, sizelimit, timelimit, deref, attrsonly;
+ Slapi_Filter *filter;
+ Slapi_DN *sdn_base;
+ int ldaperr = LDAP_SUCCESS; /* optimistic */
+ int nentries = 0; /* entry count */
+ int i;
+ Slapi_Operation *op;
+ Slapi_Entry *e;
+
+ const char *entrystr =
+ "dn:cn=Joe Smith,o=Example\n"
+ "objectClass: top\n"
+ "objectClass: person\n"
+ "objectClass: organizationalPerson\n"
+ "objectClass: inetOrgPerson\n"
+ "cn:Joe Smith\n"
+ "sn:Smith\n"
+ "uid:jsmith\n"
+ "mail:jsmith@example.com\n";
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_search\n" );
+ if( slapi_op_reserved(pb) ){
+ return PLUGIN_OPERATION_IGNORED;
+ }
+
+ /* get essential search parameters */
+ if ( slapi_pblock_get( pb, SLAPI_SEARCH_TARGET, &dn_base ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_SCOPE, &scope ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME,
+ "could not get base DN and scope search parameters\n" );
+ }
+ if ( dn_base == NULL ) {
+ dn_base = "";
+ }
+ sdn_base = slapi_sdn_new_dn_byval( dn_base );
+ slapi_pblock_get(pb, SLAPI_OPERATION, &op);
+
+ /* get remaining search parameters */
+ if ( slapi_pblock_get( pb, SLAPI_SEARCH_DEREF, &deref ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_SIZELIMIT, &sizelimit ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_TIMELIMIT, &timelimit ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_FILTER, &filter ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRS, &attrs ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_SEARCH_ATTRSONLY, &attrsonly ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME,
+ "could not get remaining search parameters\n" );
+ }
+
+ if ( slapi_pblock_get( pb, SLAPI_OPERATION, &op ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME,
+ "could not get operation\n" );
+ } else {
+ slapi_operation_set_flag(op, SLAPI_OP_FLAG_NO_ACCESS_CHECK );
+ }
+
+ /* create a fake entry and send it along */
+ newStr = slapi_ch_strdup( entrystr );
+ if ( NULL == ( e = slapi_str2entry( newStr,
+ SLAPI_STR2ENTRY_ADDRDNVALS
+ | SLAPI_STR2ENTRY_EXPAND_OBJECTCLASSES ))) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME,
+ "nullsuffix_search: slapi_str2entry() failed\n" );
+ } else {
+ slapi_send_ldap_search_entry( pb, e, NULL /* controls */,
+ attrs, attrsonly );
+ ++nentries;
+ slapi_entry_free( e );
+ }
+
+ slapi_send_ldap_result( pb, ldaperr, NULL, "kilroy was here",
+ nentries, NULL );
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_search:"
+ " handled search based at %s with scope %d; ldaperr=%d\n",
+ dn_base, scope, ldaperr );
+
+ slapi_ch_free_string(&newStr);
+ slapi_sdn_free(&sdn_base);
+
+ return PLUGIN_OPERATION_HANDLED;
+}
+
+
+/*
+ * Shutdown function.
+ */
+static int
+nullsuffix_close( Slapi_PBlock *pb )
+{
+ slapi_log_error( SLAPI_LOG_PLUGIN, PLUGIN_NAME, "nullsuffix_close\n" );
+ return 0;
+}
diff --git a/ldap/servers/slapd/test-plugins/testdbinterop.c b/ldap/servers/slapd/test-plugins/testdbinterop.c
new file mode 100644
index 00000000..7da3e72f
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testdbinterop.c
@@ -0,0 +1,102 @@
+#include <sys/types.h>
+#include <stdio.h>
+#include "db.h"
+#include "testdbinterop.h"
+#include "slapi-plugin.h"
+
+#define DATABASE "access.db"
+static int number_of_keys=100;
+static int key_buffer_size = 8000;
+
+#define DB_PLUGIN_NAME "nullsuffix-preop"
+
+static PRLock *db_lock=NULL;
+
+#if 1000*DB_VERSION_MAJOR + 100*DB_VERSION_MINOR >= 4100
+#define DB_OPEN(db, txnid, file, database, type, flags, mode) \
+ (db)->open((db), (txnid), (file), (database), (type), (flags), (mode))
+#else
+ (db)->open((db), (file), (database), (type), (flags), (mode))
+#endif
+
+
+DB *dbp=NULL;
+
+void
+create_db()
+{
+ int ret;
+ DBT key, data;
+
+ if ((ret = db_create(&dbp, NULL, 0)) != 0) {
+ fprintf(stderr, "db_create: %s\n", db_strerror(ret));
+ exit (1);
+ }
+
+}
+
+void make_key(DBT *key)
+{
+ char *key_string = (char*)(key->data);
+ unsigned int seed = (unsigned int)time( (time_t*) 0);
+ long int key_long = slapi_rand_r(&seed) % number_of_keys;
+ sprintf(key_string,"key%ld",key_long);
+ slapi_log_error(SLAPI_LOG_PLUGIN, DB_PLUGIN_NAME,"generated key: %s\n", key_string);
+ key->size = strlen(key_string);
+}
+
+
+void
+db_put_dn(char *data_dn)
+{
+ int ret;
+ DBT key = {0};
+ DBT data = {0};
+
+ if(db_lock == NULL){
+ db_lock = PR_NewLock();
+ }
+ PR_Lock(db_lock);
+ create_db();
+
+ if ((ret = DB_OPEN(dbp, NULL, DATABASE, NULL, DB_BTREE, DB_CREATE, 0664)) != 0) {
+ dbp->err(dbp, ret, "%s", DATABASE);
+ }
+ memset(&key, 0, sizeof(key));
+ memset(&data, 0, sizeof(data));
+
+
+ key.data = (char *)malloc(key_buffer_size);
+ /* make_key will set up the key and the data */
+ make_key(&key);
+
+ data.data = slapi_ch_strdup(data_dn);
+ data.size = strlen(data_dn);
+
+
+ switch (ret =
+ dbp->put(dbp, NULL, &key, &data, DB_NOOVERWRITE)) {
+ case 0:
+ slapi_log_error(SLAPI_LOG_PLUGIN, DB_PLUGIN_NAME, "db: %s: key stored.\n", (char *)key.data);
+ break;
+ case DB_KEYEXIST:
+ slapi_log_error(SLAPI_LOG_PLUGIN, DB_PLUGIN_NAME, "db: %s: key previously stored.\n",
+ (char *)key.data);
+ break;
+ default:
+ dbp->err(dbp, ret, "DB->put");
+ goto err;
+ }
+
+ err:
+ if(ret){
+ slapi_log_error(SLAPI_LOG_PLUGIN, DB_PLUGIN_NAME, "db: Error detected in db_put \n");
+ }
+ free(key.data);
+ if (dbp){
+ dbp->close(dbp,0);
+ dbp=NULL;
+ }
+ PR_Unlock(db_lock);
+
+}
diff --git a/ldap/servers/slapd/test-plugins/testdbinterop.h b/ldap/servers/slapd/test-plugins/testdbinterop.h
new file mode 100644
index 00000000..4fe46347
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testdbinterop.h
@@ -0,0 +1,22 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2002 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/******** testdbinterop.h *******************
+
+ The header file is for access to a Berkeley DB
+ that is being created by the testdbinterop.c
+ and used by testdatainterop.c ( plugin ); to allow
+ creation of a DB and adding DN's to the DB.
+ A simple example to show how external databases can
+ be accessed through the datainterop plugin of
+ testdatainterop.c
+
+**********************************************/
+
+#include "nspr.h"
+
+void create_db();
+void db_put_dn(char *data);
+
diff --git a/ldap/servers/slapd/test-plugins/testentry.c b/ldap/servers/slapd/test-plugins/testentry.c
new file mode 100644
index 00000000..893c6955
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testentry.c
@@ -0,0 +1,133 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/************************************************************
+
+ testentry.c
+
+ This source file provides examples of entry store and
+ entry fetch plug-in functions. These plug-in functions are
+ called by the server before writing an entry to disk and
+ after reading an entry from disk.
+
+ Entry store and entry fetch plug-in functions are passed
+ the string representation (in LDIF -- LDAP Data Interchange
+ Format) of the entry.
+
+ In this example, the entry store function performs a bitwise
+ exclusive-OR operation on each character in the entry
+ against the value 0xaa (10101010). The entry fetch
+ function performs this again to revert each character
+ back to its initial value.
+
+ NOTE: The Directory Server caches recently added and retrieved
+ entries in memory. The entry fetch plug-in function is called
+ only when reading the entry from the disk, *not* when reading
+ the entry from the cache.
+
+ For example, if you add an entry and search for it, you will
+ not see a message in the server error log indicating that
+ the entry fetch plug-in function was called. In the process
+ of adding the entry to the directory, the server also added
+ the entry to the cache; the server then reads the entry from
+ the cache instead of from the disk and does not need to call
+ the entry fetch plug-in function.
+
+ You can flush the cache by shutting down the server.
+
+ To test this plug-in function, stop the server, edit the dse.ldif file
+ (in the <server_root>/slapd-<server_id>/config directory)
+ and add the following lines before restarting the server :
+
+dn: cn=Test entry,cn=plugins,cn=config
+objectClass: top
+objectClass: nsSlapdPlugin
+objectClass: extensibleObject
+cn: Test entry
+nsslapd-pluginPath: <server_root>/plugins/slapd/slapi/examples/libtest-plugin.so
+nsslapd-pluginInitfunc: testentry_init
+nsslapd-pluginType: ldbmentryfetchstore
+nsslapd-pluginEnabled: on
+nsslapd-pluginId: test-entry
+
+ ************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "slapi-plugin.h"
+
+Slapi_PluginDesc entrypdesc = { "test-entry", "Netscape", "0.5",
+ "sample entry modification plugin" };
+
+/* Entry store plug-in function */
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int
+testentry_scramble( char **entry, unsigned long *len )
+{
+ unsigned long i;
+
+ /* Log an entry to the server's error log file whenever
+ this function is called. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testentry_scramble",
+ "Entry data scrambled.\n" );
+
+ /* Perform a bitwise exclusive-OR operation on each
+ character in the entry. */
+ for ( i = 0; i < *len - 1; i++ ) {
+ (*entry)[i] ^= 0xaa;
+ }
+
+ return( 0 );
+}
+
+/* Entry fetch plug-in function */
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int
+testentry_unscramble( char **entry, unsigned long *len )
+{
+ unsigned long i;
+
+ /* Some entries will not be scrambled, so check if the entry is
+ scrambled before attempting to unscramble the entry. */
+ if ( !strncmp( *entry, "dn:", 3 ) ) {
+ return( 0 );
+ }
+
+ /* Perform a bitwise exclusive-OR operation on each
+ character in the entry. */
+ for ( i = 0; i < *len - 1; i++ ) {
+ (*entry)[i] ^= 0xaa;
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testentry_unscramble",
+ "Entry data unscrambled.\n");
+ return( 0 );
+}
+
+int
+testentry_init(Slapi_PBlock *pb)
+{
+ /* Register the store/fetch functions and specify
+ the server plug-in version. */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&entrypdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_ENTRY_FETCH_FUNC,
+ (void *) testentry_unscramble ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_ENTRY_STORE_FUNC,
+ (void *) testentry_scramble ) != 0 ) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testentry_init",
+ "Failed to set version and functions\n" );
+ return( -1 );
+ }
+
+ return 0;
+}
diff --git a/ldap/servers/slapd/test-plugins/testextendedop.c b/ldap/servers/slapd/test-plugins/testextendedop.c
new file mode 100644
index 00000000..fad462a7
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testextendedop.c
@@ -0,0 +1,188 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/************************************************************
+
+ testextendedop.c
+
+ This source file provides an example of a plug-in function
+ that implements an extended operation. The plug-in function
+ is called by the server if an LDAP client request contains
+ the OID "1.2.3.4" (which identifies this operation).
+
+ To test this plug-in function, you need to write an LDAP
+ v3 client that can send requests for extended operations.
+ You can use the Netscape Directory SDK for C 3.0 or the
+ Netscape Directory SDK for Java 3.0 to build these clients.
+ (These SDKs are available from DevEdge Online at
+ http://developer.netscape.com/tech/directory/)
+
+ The LDAP client should send an extended operation request
+ with the OID 1.2.3.4. To verify that the operation completed
+ successfully, your client should check the OID and value
+ returned in the LDAP response.
+
+ To test this plug-in function, stop the server, edit the dse.ldif file
+ (in the <server_root>/slapd-<server_id>/config directory)
+ and add the following lines before restarting the server :
+
+ dn: cn=Test ExtendedOp,cn=plugins,cn=config
+ objectClass: top
+ objectClass: nsSlapdPlugin
+ objectClass: extensibleObject
+ cn: Test ExtendedOp
+ nsslapd-pluginPath: <server_root>/plugins/slapd/slapi/examples/libtest-plugin.so
+ nsslapd-pluginInitfunc: testexop_init
+ nsslapd-pluginType: extendedop
+ nsslapd-pluginEnabled: on
+ nsslapd-plugin-depends-on-type: database
+ nsslapd-pluginId: test-extendedop
+ nsslapd-pluginarg0: 1.2.3.4
+
+ ************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "slapi-plugin.h"
+
+/* OID of the extended operation handled by this plug-in */
+#define MY_OID "1.2.3.4"
+
+Slapi_PluginDesc expdesc = { "test-extendedop", "Netscape", "0.5",
+ "sample extended operation plugin" };
+
+
+/* Extended operation plug-in */
+int
+testexop_babs( Slapi_PBlock *pb )
+{
+ char *oid;
+ struct berval *bval;
+ char *retval, *msg;
+ struct berval retbval;
+
+ /* Get the OID and the value included in the request */
+ if ( slapi_pblock_get( pb, SLAPI_EXT_OP_REQ_OID, &oid ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_EXT_OP_REQ_VALUE, &bval ) != 0 ) {
+ msg = "Could not get OID and value from request.";
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testexop_babs", "%s\n",
+ msg );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ msg, 0, NULL );
+ return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+ } else {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testexop_babs",
+ "Received extended operation request with OID %s\n",
+ oid );
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testexop_babs",
+ "Value from client: %s\n", bval->bv_val );
+ }
+
+ /* Set up the value that you want returned to the client.
+ In this case, it's just the value sent from the client,
+ preceded by the string "Value from client: " */
+
+ msg = "Value from client: ";
+ retval = ( char * )slapi_ch_malloc( bval->bv_len + strlen( msg ) + 1 );
+ sprintf( retval, "%s%s", msg, bval->bv_val );
+ retbval.bv_val = retval;
+ retbval.bv_len = strlen( retbval.bv_val );
+
+ /* Prepare to return the OID and value back to the client.
+ Note that if you want, you can return a different OID to
+ the client (for example, if you want to use the OID as
+ an indicator of something). */
+ if ( slapi_pblock_set( pb, SLAPI_EXT_OP_RET_OID, "5.6.7.8" ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_EXT_OP_RET_VALUE, &retbval ) != 0 ) {
+ slapi_ch_free( ( void ** ) &retval );
+ msg = "Could not set return values";
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testexop_babs", "%s\n",
+ msg );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ msg, 0, NULL );
+ return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+ }
+
+ /* Send the response (containing the OID and value you set)
+ back to the client. */
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL,
+ "operation babs successful!", 0, NULL );
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testexop_babs",
+ "OID sent to client: %s\n", "5.6.7.8" );
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testexop_babs",
+ "Value sent to client: %s\n", retval );
+
+ /* Free any memory allocated by this plug-in. */
+ slapi_ch_free( ( void ** ) &retval );
+
+ /* Let front end know we sent the result */
+ return( SLAPI_PLUGIN_EXTENDED_SENT_RESULT );
+}
+
+/* Initialization function */
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int
+testexop_init( Slapi_PBlock *pb )
+{
+ char **argv;
+ char *oid;
+ char **oidlist, **namelist;
+
+ /* Get the arguments appended to the plugin extendedop directive
+ in the plugin entry. The first argument
+ (after the standard arguments for the directive) should
+ contain the OID of the extended op.
+ */
+
+ if ( slapi_pblock_get( pb, SLAPI_PLUGIN_ARGV, &argv ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testexop_init", "Could not get argv\n" );
+ return( -1 );
+ }
+
+ /* Compare the OID specified in the configuration file
+ against the OID supported by this plug-in function. */
+
+ if ( argv == NULL || strcmp( argv[0], MY_OID ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testexop_init", "OID is missing or is not %s\n", MY_OID );
+ return( -1 );
+ } else {
+ oid = slapi_ch_strdup( argv[0] );
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testexop_init",
+ "Registering plug-in for extended op %s.\n", oid );
+ }
+
+ oidlist = (char **) slapi_ch_malloc( 2 * sizeof( char * ) );
+ oidlist[0] = oid;
+ oidlist[1] = NULL;
+ namelist = (char **) slapi_ch_malloc( 2 * sizeof( char * ) );
+ namelist[0] = "test extended op";
+ namelist[1] = NULL;
+
+ /* Register the plug-in function as an extended operation
+ plug-in function that handles the operation identified by
+ OID 1.2.3.4. Also specify the version of the server
+ plug-in */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&expdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_FN,
+ (void *) testexop_babs ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_OIDLIST, oidlist ) ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_EXT_OP_NAMELIST, namelist ) != 0 ) {
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testexop_init",
+ "Failed to set plug-in version, function, and OID.\n" );
+ return( -1 );
+ }
+
+ return( 0 );
+}
+
diff --git a/ldap/servers/slapd/test-plugins/testgetip.c b/ldap/servers/slapd/test-plugins/testgetip.c
new file mode 100644
index 00000000..b8d08a52
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testgetip.c
@@ -0,0 +1,141 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/************************************************************
+
+ testgetip.c
+
+ This source file provides an example of a pre-operation plug-in
+ function that gets the IP address of the client and the IP
+ address of the server.
+
+ testgetip logs this information to the server error log.
+
+ To test this plug-in function, stop the server, edit the dse.ldif file
+ (in the <server_root>/slapd-<server_id>/config directory)
+ and add the following lines before restarting the server :
+
+ dn: cn=Test GetIP,cn=plugins,cn=config
+ objectClass: top
+ objectClass: nsSlapdPlugin
+ objectClass: extensibleObject
+ cn: Test GetIP
+ nsslapd-pluginPath: <server_root>/plugins/slapd/slapi/examples/libtest-plugin.so
+ nsslapd-pluginInitfunc: testgetip_init
+ nsslapd-pluginType: preoperation
+ nsslapd-pluginEnabled: on
+ nsslapd-plugin-depends-on-type: database
+ nsslapd-pluginId: test-getip
+
+ ************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+#include "slapi-plugin.h"
+#include "nspr.h"
+
+Slapi_PluginDesc getippdesc = { "test-getip", "Netscape", "0.5",
+ "sample pre-operation plugin" };
+
+static char *netaddr2str( PRNetAddr *addrp, char *buf, size_t buflen );
+
+int
+testgetip( Slapi_PBlock *pb )
+{
+ void *conn;
+ PRNetAddr client_addr, server_addr;
+ char addrbuf[ 512 ], *addrstr;
+
+ /*
+ * Don't do anything for internal operations (NULL connection).
+ */
+ if ( slapi_pblock_get( pb, SLAPI_CONNECTION, &conn ) != 0 ||
+ ( conn == NULL )) {
+ return( 0 );
+ }
+
+ /*
+ * Get the client's IP address and log it
+ */
+ if ( slapi_pblock_get( pb, SLAPI_CONN_CLIENTNETADDR, &client_addr )
+ != 0 || ( client_addr.raw.family == 0 )) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testgetip",
+ "Could not get client IP.\n" );
+ } else if (( addrstr = netaddr2str( &client_addr, addrbuf,
+ sizeof(addrbuf))) != NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testgetip",
+ "Client's IP address is %s\n", addrstr );
+ }
+
+ /*
+ * Get the destination (server) IP address and log it
+ */
+ if ( slapi_pblock_get( pb, SLAPI_CONN_SERVERNETADDR, &server_addr )
+ != 0 || ( server_addr.raw.family == 0 )) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testgetip",
+ "Could not get server IP.\n" );
+ } else if (( addrstr = netaddr2str( &server_addr, addrbuf,
+ sizeof(addrbuf))) != NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testgetip",
+ "Client sent request to server IP %s\n", addrstr );
+ }
+
+ return( 0 );
+}
+
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int
+testgetip_init( Slapi_PBlock *pb )
+{
+ /* Register the pre-operation plug-in function. */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&getippdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_SEARCH_FN,
+ (void *) testgetip ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, "testgetip_init",
+ "Failed to set version and functions.\n" );
+ return( -1 );
+ }
+
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testgetip_init",
+ "Registered preop plugins.\n" );
+ return( 0 );
+}
+
+
+/*
+ * Utility function to convert a PRNetAddr to a human readable string.
+ */
+static char *
+netaddr2str( PRNetAddr *addrp, char *buf, size_t buflen )
+{
+ char *addrstr;
+
+ *buf = '\0';
+ if ( PR_NetAddrToString( addrp, buf, buflen ) != PR_SUCCESS ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testgetip",
+ "PR_NetAddrToString failed.\n" );
+ return( NULL );
+ }
+
+ /* skip past leading ::ffff: if IPv4 address */
+ if ( strlen( buf ) > 7 && strncmp( buf, "::ffff:", 7 ) == 0 ) {
+ addrstr = buf + 7;
+ } else {
+ addrstr = buf;
+ }
+
+ return( addrstr );
+}
diff --git a/ldap/servers/slapd/test-plugins/testplugin.def b/ldap/servers/slapd/test-plugins/testplugin.def
new file mode 100644
index 00000000..b14c082e
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testplugin.def
@@ -0,0 +1,16 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+DESCRIPTION 'Netscape Directory Server 7 test plugin'
+EXPORTS
+ testentry_scramble @2
+ testentry_unscramble @3
+ testexop_init @4
+ testpostop_init @5
+ testpreop_init @6
+ testsasl_init @7
+ testbind_init @8
+ nullsuffix_init @9
diff --git a/ldap/servers/slapd/test-plugins/testplugin.dsp b/ldap/servers/slapd/test-plugins/testplugin.dsp
new file mode 100644
index 00000000..d956bcd3
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testplugin.dsp
@@ -0,0 +1,143 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Microsoft Developer Studio Project File - Name="testplugin" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 5.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=testplugin - Win32 Release
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "testplugin.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "testplugin.mak" CFG="testplugin - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "testplugin - Win32 Release" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "testplugin - Win32 Debug" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "testplugin - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir ".\Release"
+# PROP BASE Intermediate_Dir ".\Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir ".\Release"
+# PROP Intermediate_Dir ".\Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MD /W3 /GX /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_WIN32" /YX /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib ..\lib\libslapd.lib /nologo /subsystem:windows /dll /machine:I386
+
+!ELSEIF "$(CFG)" == "testplugin - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir ".\Debug"
+# PROP BASE Intermediate_Dir ".\Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir ".\Debug"
+# PROP Intermediate_Dir ".\Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MD /W3 /Gm /GX /Zi /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_WIN32" /YX /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib wsock32.lib ..\lib\libslapd.lib /nologo /subsystem:windows /dll /debug /machine:I386
+
+!ENDIF
+
+# Begin Target
+
+# Name "testplugin - Win32 Release"
+# Name "testplugin - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90"
+# Begin Source File
+
+SOURCE=.\dllmain.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testbind.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testentry.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testextendedop.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testplugin.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\testpostop.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testpreop.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\testsaslbind.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd"
+# End Group
+# Begin Group "Resource Files"
+
+# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe"
+# End Group
+# End Target
+# End Project
diff --git a/ldap/servers/slapd/test-plugins/testplugin.mak b/ldap/servers/slapd/test-plugins/testplugin.mak
new file mode 100644
index 00000000..ca48774c
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testplugin.mak
@@ -0,0 +1,431 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Microsoft Developer Studio Generated NMAKE File, Based on testplugin.dsp
+!IF "$(CFG)" == ""
+CFG=testplugin - Win32 Release
+!MESSAGE No configuration specified. Defaulting to testplugin - Win32 Release.
+!ENDIF
+
+!IF "$(CFG)" != "testplugin - Win32 Release" && "$(CFG)" !=\
+ "testplugin - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "testplugin.mak" CFG="testplugin - Win32 Release"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "testplugin - Win32 Release" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "testplugin - Win32 Debug" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "testplugin - Win32 Release"
+
+OUTDIR=.\Release
+INTDIR=.\Release
+# Begin Custom Macros
+OutDir=.\.\Release
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\testplugin.dll"
+
+!ELSE
+
+ALL : "$(OUTDIR)\testplugin.dll"
+
+!ENDIF
+
+CLEAN :
+ -@erase "$(INTDIR)\dllmain.obj"
+ -@erase "$(INTDIR)\testbind.obj"
+ -@erase "$(INTDIR)\testentry.obj"
+ -@erase "$(INTDIR)\testextendedop.obj"
+ -@erase "$(INTDIR)\testpostop.obj"
+ -@erase "$(INTDIR)\testpreop.obj"
+ -@erase "$(INTDIR)\testsaslbind.obj"
+ -@erase "$(INTDIR)\vc50.idb"
+ -@erase "$(OUTDIR)\testplugin.dll"
+ -@erase "$(OUTDIR)\testplugin.exp"
+ -@erase "$(OUTDIR)\testplugin.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MD /W3 /GX /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D\
+ "_WINDOWS" /D "_WIN32" /Fp"$(INTDIR)\testplugin.pch" /YX /Fo"$(INTDIR)\\"\
+ /Fd"$(INTDIR)\\" /FD /c
+CPP_OBJS=.\Release/
+CPP_SBRS=.
+MTL_PROJ=/nologo /D "NDEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\testplugin.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib wsock32.lib ..\lib\libslapd.lib /nologo /subsystem:windows /dll\
+ /incremental:no /pdb:"$(OUTDIR)\testplugin.pdb" /machine:I386\
+ /def:".\testplugin.def" /out:"$(OUTDIR)\testplugin.dll"\
+ /implib:"$(OUTDIR)\testplugin.lib"
+DEF_FILE= \
+ ".\testplugin.def"
+LINK32_OBJS= \
+ "$(INTDIR)\dllmain.obj" \
+ "$(INTDIR)\testbind.obj" \
+ "$(INTDIR)\testentry.obj" \
+ "$(INTDIR)\testextendedop.obj" \
+ "$(INTDIR)\testpostop.obj" \
+ "$(INTDIR)\testpreop.obj" \
+ "$(INTDIR)\testsaslbind.obj"
+
+"$(OUTDIR)\testplugin.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "testplugin - Win32 Debug"
+
+OUTDIR=.\Debug
+INTDIR=.\Debug
+# Begin Custom Macros
+OutDir=.\.\Debug
+# End Custom Macros
+
+!IF "$(RECURSE)" == "0"
+
+ALL : "$(OUTDIR)\testplugin.dll"
+
+!ELSE
+
+ALL : "$(OUTDIR)\testplugin.dll"
+
+!ENDIF
+
+CLEAN :
+ -@erase "$(INTDIR)\dllmain.obj"
+ -@erase "$(INTDIR)\testbind.obj"
+ -@erase "$(INTDIR)\testentry.obj"
+ -@erase "$(INTDIR)\testextendedop.obj"
+ -@erase "$(INTDIR)\testpostop.obj"
+ -@erase "$(INTDIR)\testpreop.obj"
+ -@erase "$(INTDIR)\testsaslbind.obj"
+ -@erase "$(INTDIR)\vc50.idb"
+ -@erase "$(INTDIR)\vc50.pdb"
+ -@erase "$(OUTDIR)\testplugin.dll"
+ -@erase "$(OUTDIR)\testplugin.exp"
+ -@erase "$(OUTDIR)\testplugin.ilk"
+ -@erase "$(OUTDIR)\testplugin.lib"
+ -@erase "$(OUTDIR)\testplugin.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+CPP_PROJ=/nologo /MD /W3 /Gm /GX /Zi /Od /I "..\include" /D "WIN32" /D "_DEBUG"\
+ /D "_WINDOWS" /D "_WIN32" /Fp"$(INTDIR)\testplugin.pch" /YX /Fo"$(INTDIR)\\"\
+ /Fd"$(INTDIR)\\" /FD /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=.
+MTL_PROJ=/nologo /D "_DEBUG" /mktyplib203 /win32
+BSC32=bscmake.exe
+BSC32_FLAGS=/nologo /o"$(OUTDIR)\testplugin.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib wsock32.lib ..\lib\libslapd.lib /nologo /subsystem:windows /dll\
+ /incremental:yes /pdb:"$(OUTDIR)\testplugin.pdb" /debug /machine:I386\
+ /def:".\testplugin.def" /out:"$(OUTDIR)\testplugin.dll"\
+ /implib:"$(OUTDIR)\testplugin.lib"
+DEF_FILE= \
+ ".\testplugin.def"
+LINK32_OBJS= \
+ "$(INTDIR)\dllmain.obj" \
+ "$(INTDIR)\testbind.obj" \
+ "$(INTDIR)\testentry.obj" \
+ "$(INTDIR)\testextendedop.obj" \
+ "$(INTDIR)\testpostop.obj" \
+ "$(INTDIR)\testpreop.obj" \
+ "$(INTDIR)\testsaslbind.obj"
+
+"$(OUTDIR)\testplugin.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_OBJS)}.obj::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.c{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cpp{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+.cxx{$(CPP_SBRS)}.sbr::
+ $(CPP) @<<
+ $(CPP_PROJ) $<
+<<
+
+
+!IF "$(CFG)" == "testplugin - Win32 Release" || "$(CFG)" ==\
+ "testplugin - Win32 Debug"
+SOURCE=.\dllmain.c
+
+!IF "$(CFG)" == "testplugin - Win32 Release"
+
+DEP_CPP_DLLMA=\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+
+
+"$(INTDIR)\dllmain.obj" : $(SOURCE) $(DEP_CPP_DLLMA) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "testplugin - Win32 Debug"
+
+DEP_CPP_DLLMA=\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_DLLMA=\
+ "..\include\macsock.h"\
+ "..\include\os2sock.h"\
+
+
+"$(INTDIR)\dllmain.obj" : $(SOURCE) $(DEP_CPP_DLLMA) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\testbind.c
+
+!IF "$(CFG)" == "testplugin - Win32 Release"
+
+DEP_CPP_TESTB=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+
+
+"$(INTDIR)\testbind.obj" : $(SOURCE) $(DEP_CPP_TESTB) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "testplugin - Win32 Debug"
+
+DEP_CPP_TESTB=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_TESTB=\
+ "..\include\macsock.h"\
+ "..\include\os2sock.h"\
+
+
+"$(INTDIR)\testbind.obj" : $(SOURCE) $(DEP_CPP_TESTB) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\testentry.c
+
+!IF "$(CFG)" == "testplugin - Win32 Release"
+
+DEP_CPP_TESTE=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+
+
+"$(INTDIR)\testentry.obj" : $(SOURCE) $(DEP_CPP_TESTE) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "testplugin - Win32 Debug"
+
+DEP_CPP_TESTE=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_TESTE=\
+ "..\include\macsock.h"\
+ "..\include\os2sock.h"\
+
+
+"$(INTDIR)\testentry.obj" : $(SOURCE) $(DEP_CPP_TESTE) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\testextendedop.c
+
+!IF "$(CFG)" == "testplugin - Win32 Release"
+
+DEP_CPP_TESTEX=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+
+
+"$(INTDIR)\testextendedop.obj" : $(SOURCE) $(DEP_CPP_TESTEX) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "testplugin - Win32 Debug"
+
+DEP_CPP_TESTEX=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_TESTEX=\
+ "..\include\macsock.h"\
+ "..\include\os2sock.h"\
+
+
+"$(INTDIR)\testextendedop.obj" : $(SOURCE) $(DEP_CPP_TESTEX) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\testpostop.c
+
+!IF "$(CFG)" == "testplugin - Win32 Release"
+
+DEP_CPP_TESTP=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+
+
+"$(INTDIR)\testpostop.obj" : $(SOURCE) $(DEP_CPP_TESTP) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "testplugin - Win32 Debug"
+
+DEP_CPP_TESTP=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_TESTP=\
+ "..\include\macsock.h"\
+ "..\include\os2sock.h"\
+
+
+"$(INTDIR)\testpostop.obj" : $(SOURCE) $(DEP_CPP_TESTP) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\testpreop.c
+
+!IF "$(CFG)" == "testplugin - Win32 Release"
+
+DEP_CPP_TESTPR=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+
+
+"$(INTDIR)\testpreop.obj" : $(SOURCE) $(DEP_CPP_TESTPR) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "testplugin - Win32 Debug"
+
+DEP_CPP_TESTPR=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_TESTPR=\
+ "..\include\macsock.h"\
+ "..\include\os2sock.h"\
+
+
+"$(INTDIR)\testpreop.obj" : $(SOURCE) $(DEP_CPP_TESTPR) "$(INTDIR)"
+
+
+!ENDIF
+
+SOURCE=.\testsaslbind.c
+
+!IF "$(CFG)" == "testplugin - Win32 Release"
+
+DEP_CPP_TESTS=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+
+
+"$(INTDIR)\testsaslbind.obj" : $(SOURCE) $(DEP_CPP_TESTS) "$(INTDIR)"
+
+
+!ELSEIF "$(CFG)" == "testplugin - Win32 Debug"
+
+DEP_CPP_TESTS=\
+ "..\include\slapi-plugin.h"\
+ {$(INCLUDE)}"lber.h"\
+ {$(INCLUDE)}"ldap.h"\
+ {$(INCLUDE)}"sys\types.h"\
+
+NODEP_CPP_TESTS=\
+ "..\include\macsock.h"\
+ "..\include\os2sock.h"\
+
+
+"$(INTDIR)\testsaslbind.obj" : $(SOURCE) $(DEP_CPP_TESTS) "$(INTDIR)"
+
+
+!ENDIF
+
+
+!ENDIF
+
diff --git a/ldap/servers/slapd/test-plugins/testpostop.c b/ldap/servers/slapd/test-plugins/testpostop.c
new file mode 100644
index 00000000..5dbf18d1
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testpostop.c
@@ -0,0 +1,386 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/************************************************************
+
+ testpostop.c
+
+ This source file provides examples of post-operation plug-in
+ functions. The server calls these plug-in functions after
+ executing certain LDAP operations:
+
+ * testpostop_add (called after an LDAP add operation)
+ * testpostop_mod (called after an LDAP modify operation)
+ * testpostop_del (called after an LDAP delete operation)
+ * testpostop_modrdn (called after an LDAP modify RDN operation)
+ * testpostop_abandon (called after an LDAP abandon operation)
+
+ After the server processes an LDAP add, modify, delete, or
+ modify RDN operation, these post-operation plug-in functions
+ log information about the operation to a change log file.
+
+ The post-abandon plugin simply logs some information to the error
+ log to demonstrate that it was called.
+
+ To test this plug-in function, stop the server, edit the dse.ldif file
+ (in the <server_root>/slapd-<server_id>/config directory)
+ and add the following lines before restarting the server :
+
+ dn: cn=Test PostOp,cn=plugins,cn=config
+ objectClass: top
+ objectClass: nsSlapdPlugin
+ objectClass: extensibleObject
+ cn: Test PostOp
+ nsslapd-pluginPath: <server_root>/plugins/slapd/slapi/examples/libtest-plugin.so
+ nsslapd-pluginInitfunc: testpostop_init
+ nsslapd-pluginType: postoperation
+ nsslapd-pluginEnabled: on
+ nsslapd-plugin-depends-on-type: database
+ nsslapd-pluginId: test-postop
+
+ ************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <time.h>
+#include "slapi-plugin.h"
+
+#define SLAPD_LOGGING 1
+#define _ADD 0
+#define _MOD 1
+#define _DEL 2
+#define _MODRDN 3
+
+#ifdef _WIN32
+static char changelogfile[MAX_PATH+1];
+#else
+static char *changelogfile = "/tmp/changelog";
+#endif
+
+Slapi_PluginDesc postoppdesc = { "test-postop", "Netscape", "0.5",
+ "sample post-operation plugin" };
+
+static void write_changelog( int optype, char *dn, void *change, int flag );
+
+/* Current time is a function defined in the server. */
+time_t current_time( void );
+
+/* Post-operation plug-in function */
+int
+testpostop_add( Slapi_PBlock *pb )
+{
+ Slapi_Entry *e;
+ char *dn;
+
+ /* Get the entry that has been added and the DN of
+ that entry. */
+ if ( slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_ADD_TARGET, &dn ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testpostop_add", "Could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* Log the DN of the newly added entry in the server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testpostop_add",
+ "Added entry (%s)\n", dn );
+
+ /* Log the DN and the entry to the change log file. */
+ write_changelog( _ADD, dn, (void *) e, 0 );
+
+ return( 0 ); /* allow the operation to continue */
+}
+
+/* Post-operation plug-in function. */
+int
+testpostop_mod( Slapi_PBlock *pb )
+{
+ char *dn;
+ LDAPMod **mods;
+
+ /* Get the DN of the modified entry and the modifications made. */
+ if ( slapi_pblock_get( pb, SLAPI_MODIFY_TARGET, &dn ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_MODIFY_MODS, &mods ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testpostop_mod", "Could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* Log the DN of the modified entry to the server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testpostop_mod",
+ "Modified entry (%s)\n", dn );
+
+ /* Log the DN and the modifications made to the change log file. */
+ write_changelog( _MOD, dn, (void *) mods, 0 );
+
+ return( 0 ); /* allow the operation to continue */
+}
+
+/* Post-operation plug-in function */
+int
+testpostop_del( Slapi_PBlock *pb )
+{
+ char *dn;
+
+ /* Get the DN of the entry that was removed from the directory. */
+ if ( slapi_pblock_get( pb, SLAPI_DELETE_TARGET, &dn ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testpostop_del", "Could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* Log the DN of the deleted entry to the server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testpostop_del",
+ "Deleted entry (%s)\n", dn );
+
+ /* Log the DN of the deleted entry to the change log. */
+ write_changelog( _DEL, dn, NULL, 0 );
+
+ return( 0 ); /* allow the operation to continue */
+}
+
+/* Post-operation plug-in function */
+int
+testpostop_modrdn( Slapi_PBlock *pb )
+{
+ char *dn;
+ char *newrdn;
+ int dflag;
+
+ /* Get the DN of the renamed entry, the new RDN of the entry,
+ and the flag indicating whether or not the old RDN was
+ removed from the entry. */
+ if ( slapi_pblock_get( pb, SLAPI_MODRDN_TARGET, &dn ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_MODRDN_NEWRDN, &newrdn ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_MODRDN_DELOLDRDN, &dflag ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testpostop_modrdn", "Could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* Log the DN of the renamed entry to the server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testpostop_modrdn",
+ "modrdn entry (%s)\n", dn );
+
+ /* Log the DN of the renamed entry, its new RDN, and the
+ flag (the one indicating whether or not the old RDN was
+ removed from the entry) to the change log. */
+ write_changelog( _MODRDN, dn, (void *) newrdn, dflag );
+
+ return( 0 ); /* allow the operation to continue */
+}
+
+/* Post-operation plug-in function */
+int
+testpostop_abandon( Slapi_PBlock *pb )
+{
+ int msgid;
+
+ /* Get the LDAP message ID of the abandoned operation */
+ if ( slapi_pblock_get( pb, SLAPI_ABANDON_MSGID, &msgid ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testpostop_abandon", "Could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* Log information about the abandon operation to the
+ server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testpostop_abandon",
+ "Postoperation abandon function called.\n"
+ "\tTarget MsgID: %d\n",
+ msgid );
+
+ return( 0 ); /* allow the operation to continue */
+}
+
+/* Initialization function */
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int
+testpostop_init( Slapi_PBlock *pb )
+{
+ /* Register the four post-operation plug-in functions,
+ and specify the server plug-in version. */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&postoppdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_ADD_FN,
+ (void *) testpostop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODIFY_FN,
+ (void *) testpostop_mod ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_DELETE_FN,
+ (void *) testpostop_del ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_MODRDN_FN,
+ (void *) testpostop_modrdn ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_POST_ABANDON_FN,
+ (void *) testpostop_abandon ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testpostop_init",
+ "Failed to set version and functions\n" );
+ return( -1 );
+ }
+ return( 0 );
+}
+
+/* Function for generating a newly allocated string that contains the
+ specified time. The time is expressed as generalizedTime, except
+ without the time zone. */
+static char*
+format_localTime( time_t timeval )
+{
+ char* into;
+ struct tm t;
+#ifdef _WIN32
+ memcpy (&t, localtime (&timeval), sizeof(t));
+#else
+ localtime_r (&timeval, &t);
+#endif
+
+ /* Allocate memory for the formatted string. (slapi_ch_malloc()
+ should be used in server plug-ins instead of malloc().)
+ This string is freed by the calling function write_changelog(). */
+ into = slapi_ch_malloc(15);
+ sprintf (into, "%.4li%.2i%.2i%.2i%.2i%.2i",
+ 1900L + t.tm_year, 1 + t.tm_mon, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+ return into;
+}
+
+/* Logs information on an operation to a change log file.
+ Parameters;
+ - optype is type of LDAP operation to record:
+ - _ADD for LDAP add operations
+ - _MOD for LDAP modify operations
+ - _DEL for LDAP delete operations
+ - _MODRDN for LDAP modify RDN operations
+ - dn is DN of the entry affected by the operation.
+ - change is information about the operation performed.
+ The type of information depends on the value of optype:
+ - For _ADD, it is the newly added entry (Slapi_Entry).
+ - For _MOD, it is the list of modifications made (array of
+ LDAPMod).
+ - For _DEL, it is NULL.
+ - For _MODRDN, it is the new RDN of the entry.
+ - flag is only used for LDAP modify RDN operations.
+ It represents the flag that indicates whether or not
+ the old RDN has been removed.
+*/
+static void
+write_changelog(
+ int optype,
+ char *dn,
+ void *change,
+ int flag
+)
+{
+ LDAPMod **mods;
+ Slapi_Entry *e;
+ char *newrdn, *tmp, *tmpsave;
+ FILE *fp;
+ int len, i, j;
+ char* timestr;
+#ifdef _WIN32
+ char szTmpPath[MAX_PATH+1];
+#endif
+
+ /* Open the change log file */
+#ifdef _WIN32
+ GetTempPath( MAX_PATH, szTmpPath );
+ strcpy( changelogfile, szTmpPath );
+ strcat( changelogfile, "\\" );
+ strcat( changelogfile, "changelog.txt" );
+#endif
+ if ( changelogfile == NULL ) {
+ return;
+ }
+ if ( (fp = fopen( changelogfile, "ab" )) == NULL ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "write_changelog",
+ "Could not open log file %s\n", changelogfile );
+ return;
+ }
+
+ /* Log the current time of the operation in generalizedTime form */
+ timestr = format_localTime( current_time() );
+ fprintf( fp, "time: %s\n", timestr );
+ slapi_ch_free( ( void ** ) &timestr);
+ timestr = NULL;
+
+ /* Print the DN of the entry affected by the operation. */
+ fprintf( fp, "dn: %s\n", dn );
+
+ /* Log information about the operation */
+ switch ( optype ) {
+ case _MOD:
+ /* For modify operations, log the attribute type
+ that has been added, replaced, or deleted. */
+ fprintf( fp, "changetype: modify\n" );
+ mods = (LDAPMod **)change;
+ for ( j = 0; mods[j] != NULL; j++ ) {
+ switch ( mods[j]->mod_op & ~LDAP_MOD_BVALUES ) {
+ case LDAP_MOD_ADD:
+ fprintf( fp, "add: %s\n", mods[j]->mod_type );
+ break;
+
+ case LDAP_MOD_DELETE:
+ fprintf( fp, "delete: %s\n", mods[j]->mod_type );
+ break;
+
+ case LDAP_MOD_REPLACE:
+ fprintf( fp, "replace: %s\n", mods[j]->mod_type );
+ break;
+ }
+
+ for ( i = 0; mods[j]->mod_bvalues != NULL &&
+ mods[j]->mod_bvalues[i] != NULL; i++ ) {
+ /* XXX should handle binary values XXX */
+ fprintf( fp, "%s: %s\n", mods[j]->mod_type,
+ mods[j]->mod_bvalues[i]->bv_val );
+ }
+ fprintf( fp, "-\n" );
+ }
+ break;
+
+ case _ADD:
+ /* For LDAP add operations, log the newly added entry. */
+ e = (Slapi_Entry *)change;
+ fprintf( fp, "changetype: add\n" );
+ /* Get the LDIF string representation of the entry. */
+ tmp = slapi_entry2str( e, &len );
+ tmpsave = tmp;
+ /* Skip the first line, which is the dn: line */
+ while (( tmp = strchr( tmp, '\n' )) != NULL ) {
+ tmp++;
+ if ( !isspace( *tmp )) {
+ break;
+ }
+ }
+ fprintf( fp, "%s", tmp );
+ slapi_ch_free( (void **)&tmpsave );
+ break;
+
+ case _DEL:
+ /* For the LDAP delete operation, log the DN of the
+ removed entry. (Since this is already done earlier,
+ the plug-in just needs to note the type of operation
+ performed. */
+ fprintf( fp, "changetype: delete\n" );
+ break;
+
+ case _MODRDN:
+ /* For the LDAP modify RDN operation, log the new RDN
+ and the flag indicating whether or not the old RDN
+ was removed. */
+ newrdn = (char *)change;
+ fprintf( fp, "changetype: modrdn\n" );
+ fprintf( fp, "newrdn: %s\n", newrdn );
+ fprintf( fp, "deleteoldrdn: %d\n", flag ? 1 : 0 );
+ }
+ fprintf( fp, "\n" );
+
+ fclose( fp );
+}
+
diff --git a/ldap/servers/slapd/test-plugins/testpreop.c b/ldap/servers/slapd/test-plugins/testpreop.c
new file mode 100644
index 00000000..54a08b53
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testpreop.c
@@ -0,0 +1,215 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/************************************************************
+
+ testpreop.c
+
+ This source file provides examples of pre-operation plug-in
+ functions. The server calls these plug-in functions before
+ executing certain LDAP operations:
+
+ * testpreop_bind (called before an LDAP bind operation)
+ * testpreop_add (called before an LDAP add operation)
+ * testpreop_abandon (called before an LDAP abandon operation)
+
+ testpreop_bind logs information about the LDAP bind operation
+ to the server error log. testpreop_add prepends the name "BOB"
+ to the value of the cn attribute before an entry is added.
+
+ Note that the Directory Server front-end handles bind
+ operations requested by the root DN. The server does not
+ invoke your plug-in function if the client is authenticating
+ as the root DN.
+
+ To test this plug-in function, stop the server, edit the dse.ldif file
+ (in the <server_root>/slapd-<server_id>/config directory)
+ and add the following lines before restarting the server :
+
+ dn: cn=Test Preop,cn=plugins,cn=config
+ objectClass: top
+ objectClass: nsSlapdPlugin
+ objectClass: extensibleObject
+ cn: Test Preop
+ nsslapd-pluginPath: <server_root>/plugins/slapd/slapi/examples/libtest-plugin.so
+ nsslapd-pluginInitfunc: testpreop_init
+ nsslapd-pluginType: preoperation
+ nsslapd-pluginEnabled: on
+ nsslapd-plugin-depends-on-type: database
+ nsslapd-pluginId: test-preop
+
+ ************************************************************/
+
+#include <stdio.h>
+#include <string.h>
+#include "slapi-plugin.h"
+
+Slapi_PluginDesc preoppdesc = { "test-preop", "Netscape", "0.5",
+ "sample pre-operation plugin" };
+
+/* Pre-operation plug-in function */
+int
+testpreop_bind( Slapi_PBlock *pb )
+{
+ char *dn;
+ int method;
+ char *auth;
+
+ /* Get the DN that the client is binding as and the method
+ of authentication used. */
+ if ( slapi_pblock_get( pb, SLAPI_BIND_TARGET, &dn ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testpreop_bind", "Could not get parameters\n" );
+ return( -1 );
+ }
+
+ switch( method ) {
+ case LDAP_AUTH_NONE:
+ auth = "No authentication";
+ break;
+ case LDAP_AUTH_SIMPLE:
+ auth = "Simple authentication";
+ break;
+ case LDAP_AUTH_SASL:
+ auth = "SASL authentication";
+ break;
+ default:
+ auth = "Unknown method of authentication";
+ break;
+ }
+
+ /* Log information about the bind operation to the
+ server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testpreop_bind",
+ "Preoperation bind function called.\n"
+ "\tTarget DN: %s\n\tAuthentication method: %s\n",
+ dn, auth );
+
+ return( 0 ); /* allow the operation to continue */
+}
+
+/* Pre-operation plug-in function */
+int
+testpreop_add( Slapi_PBlock *pb )
+{
+ Slapi_Entry *e;
+ Slapi_Attr *a;
+ Slapi_Value *v;
+ struct berval **bvals;
+ int i, hint;
+ char *tmp;
+ const char *s;
+
+ /* Get the entry that is about to be added. */
+ if ( slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testpreop_add", "Could not get entry\n" );
+ return( -1 );
+ }
+
+ /* Prepend the name "BOB" to the value of the cn attribute
+ in the entry. */
+ if ( slapi_entry_attr_find( e, "cn", &a ) == 0 ) {
+ for ( hint = slapi_attr_first_value( a, &v ); hint != -1;
+ hint = slapi_attr_next_value( a, hint, &v )) {
+ s = slapi_value_get_string( v );
+ tmp = (char *) malloc( 5 + strlen( s ));
+ strcpy( tmp, "BOB " );
+ strcat( tmp + 4, s );
+ slapi_value_set_string( v, tmp );
+ free( tmp );
+ }
+ }
+
+ return( 0 ); /* allow the operation to continue */
+}
+
+
+/* Pre-operation plug-in function */
+int
+testpreop_abandon( Slapi_PBlock *pb )
+{
+ int msgid;
+
+ /* Get the LDAP message ID of the abandon target */
+ if ( slapi_pblock_get( pb, SLAPI_ABANDON_MSGID, &msgid ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN,
+ "testpreop_abandon", "Could not get parameters\n" );
+ return( -1 );
+ }
+
+ /* Log information about the abandon operation to the
+ server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testpreop_bind",
+ "Preoperation abandon function called.\n"
+ "\tTarget MsgID: %d\n",
+ msgid );
+
+ return( 0 ); /* allow the operation to continue */
+}
+
+
+static void
+get_plugin_config_dn_and_entry( char *msg, Slapi_PBlock *pb )
+{
+ char *dn = NULL;
+ Slapi_Entry *e = NULL;
+ int loglevel = SLAPI_LOG_PLUGIN;
+
+ if ( slapi_pblock_get( pb, SLAPI_TARGET_DN, &dn ) != 0 || dn == NULL ) {
+ slapi_log_error( loglevel, msg, "failed to get plugin config DN\n" );
+ } else {
+ slapi_log_error( loglevel, msg, "this plugin's config DN is \"%s\"\n",
+ dn );
+ }
+
+ if ( slapi_pblock_get( pb, SLAPI_ADD_ENTRY, &e ) != 0 || e == NULL ) {
+ slapi_log_error( loglevel, msg, "failed to get plugin config entry\n" );
+ } else {
+ char *ldif;
+
+ ldif = slapi_entry2str_with_options( e, NULL, 0 );
+ slapi_log_error( loglevel, msg,
+ "this plugin's config entry is \"\n%s\"\n", ldif );
+ slapi_ch_free_string( &ldif );
+ }
+}
+
+static int
+testpreop_start( Slapi_PBlock *pb )
+{
+ get_plugin_config_dn_and_entry( "testpreop_start", pb );
+ return( 0 );
+}
+
+/* Initialization function */
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int
+testpreop_init( Slapi_PBlock *pb )
+{
+ /* Register the two pre-operation plug-in functions,
+ and specify the server plug-in version. */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION,
+ SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION,
+ (void *)&preoppdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_START_FN,
+ (void *) testpreop_start ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN,
+ (void *) testpreop_bind ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_ADD_FN,
+ (void *) testpreop_add ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_ABANDON_FN,
+ (void *) testpreop_abandon ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testpreop_init",
+ "Failed to set version and function\n" );
+ return( -1 );
+ }
+
+ return( 0 );
+}
diff --git a/ldap/servers/slapd/test-plugins/testsaslbind.c b/ldap/servers/slapd/test-plugins/testsaslbind.c
new file mode 100644
index 00000000..3d265f4d
--- /dev/null
+++ b/ldap/servers/slapd/test-plugins/testsaslbind.c
@@ -0,0 +1,145 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/************************************************************
+
+ testsaslbind.c
+
+ This source file provides an example of a pre-operation plug-in
+ function for SASL authentication with LDAP bind operations.
+ The function demonstrates how to send credentials back to the
+ client in cases where mutual authentication is required.
+
+ This plugin responds to SASL bind requests with a mechanism
+ name of "babsmechanism". Simple binds and other SASL mechanisms
+ should not be affected by the presence of this plugin.
+
+ Binds with our mechanism always succeed (which is not very secure!)
+
+ Note that the Directory Server front-end handles bind
+ operations requested by the root DN. The server does not
+ invoke your plug-in function if the client is authenticating
+ as the root DN.
+
+ To test this plug-in function, stop the server, edit the dse.ldif file
+ (in the <server_root>/slapd-<server_id>/config directory)
+ and add the following lines before restarting the server :
+
+dn: cn=test-saslbind,cn=plugins,cn=config
+objectclass: top
+objectclass: nsSlapdPlugin
+objectclass: extensibleObject
+cn: test-saslbind
+nsslapd-pluginpath: /usr/netscape/servers/plugins/slapd/slapi/examples/libtest-plugin.so
+nsslapd-plugininitfunc: testsasl_init
+nsslapd-plugintype: preoperation
+nsslapd-pluginenabled: on
+nsslapd-pluginid: test-saslbind
+nsslapd-pluginversion: 5.0
+nsslapd-pluginvendor: Netscape Communications Corp.
+nsslapd-plugindescription: sample SASL bind pre-operation plugin
+
+
+ ************************************************************/
+#include <stdio.h>
+#include <string.h>
+#include "slapi-plugin.h"
+
+Slapi_PluginDesc saslpdesc = { "test-saslbind", "Netscape Communications Corp.", "7.0",
+ "sample SASL bind pre-operation plugin" };
+
+
+#define TEST_SASL_MECHANISM "babsmechanism"
+#define TEST_SASL_AUTHMETHOD SLAPD_AUTH_SASL TEST_SASL_MECHANISM
+
+/* Pre-operation plug-in function */
+int
+testsasl_bind( Slapi_PBlock *pb )
+{
+ char *target;
+ int method;
+ char *mechanism;
+ struct berval *credentials;
+ struct berval svrcreds;
+
+ /* Log a message to the server error log. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testsasl_bind",
+ "Pre-operation bind function called.\n" );
+
+ /* Gets parameters available when processing an LDAP bind
+ operation. */
+ if ( slapi_pblock_get( pb, SLAPI_BIND_TARGET, &target ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_METHOD, &method ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_CREDENTIALS, &credentials ) != 0 ||
+ slapi_pblock_get( pb, SLAPI_BIND_SASLMECHANISM, &mechanism )
+ != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, "testsasl_bind",
+ "Could not get parameters for bind operation\n" );
+ return( 0 ); /* let the server try other mechanisms */
+ }
+
+ /* Check to see if the mechanism being used is ours. */
+ if ( mechanism == NULL
+ || strcmp( mechanism, TEST_SASL_MECHANISM ) != 0 ) {
+ return( 0 ); /* let the server try other mechanisms */
+ }
+
+ /*
+ * Set the DN and authentication method for the connection.
+ * Binds with our mechanism always succeed (which is not very secure!)
+ */
+ if ( slapi_pblock_set( pb, SLAPI_CONN_DN, slapi_ch_strdup( target ) )
+ != 0 || slapi_pblock_set( pb, SLAPI_CONN_AUTHMETHOD,
+ TEST_SASL_AUTHMETHOD ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_FATAL, "testsasl_bind",
+ "Failed to set DN and method for connection\n" );
+ slapi_send_ldap_result( pb, LDAP_OPERATIONS_ERROR, NULL,
+ NULL, 0, NULL );
+ return( 1 ); /* done -- sent result to client */
+ }
+
+ /* Set the credentials that should be returned to the client. */
+ svrcreds.bv_val = "my credentials";
+ svrcreds.bv_len = sizeof("my credentials") - 1;
+ if ( slapi_pblock_set( pb, SLAPI_BIND_RET_SASLCREDS, &svrcreds )
+ != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testsasl_bind",
+ "Could not set credentials to return to client\n" );
+ slapi_pblock_set( pb, SLAPI_CONN_DN, NULL );
+ slapi_pblock_set( pb, SLAPI_CONN_AUTHMETHOD, SLAPD_AUTH_NONE );
+ return( 0 ); /* let the server try other mechanisms */
+ }
+
+ /* Send the credentials back to the client. */
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testsasl_bind",
+ "Authenticated: %s\n", target );
+ slapi_send_ldap_result( pb, LDAP_SUCCESS, NULL, NULL, 0, NULL );
+
+ return( 1 ); /* done -- sent result to client */
+}
+
+/* Initialization function */
+#ifdef _WIN32
+__declspec(dllexport)
+#endif
+int
+testsasl_init( Slapi_PBlock *pb )
+{
+ /* Register the pre-operation bind function and specify
+ the server plug-in version. */
+ if ( slapi_pblock_set( pb, SLAPI_PLUGIN_VERSION, SLAPI_PLUGIN_VERSION_01 ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_DESCRIPTION, (void *)&saslpdesc ) != 0 ||
+ slapi_pblock_set( pb, SLAPI_PLUGIN_PRE_BIND_FN, (void *) testsasl_bind ) != 0 ) {
+ slapi_log_error( SLAPI_LOG_PLUGIN, "testsasl_init",
+ "Failed to set version and function\n" );
+ return( -1 );
+ }
+
+ /* Register the SASL mechanism. */
+ slapi_register_supported_saslmechanism( TEST_SASL_MECHANISM );
+ return( 0 );
+}
+
diff --git a/ldap/servers/slapd/time.c b/ldap/servers/slapd/time.c
new file mode 100644
index 00000000..ebb279e8
--- /dev/null
+++ b/ldap/servers/slapd/time.c
@@ -0,0 +1,367 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* time.c - various time routines */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#ifdef AIX
+#include <time.h>
+#else
+#include <sys/time.h>
+#endif
+#endif /* _WIN32 */
+
+#include "slap.h"
+#include "fe.h"
+
+LDAP_API(unsigned long) strntoul( char *from, size_t len, int base );
+#define mktime_r(from) mktime (from) /* possible bug: is this thread-safe? */
+
+static time_t currenttime;
+static int currenttime_set = 0;
+/* XXX currenttime and currenttime_set are used by multiple threads,
+ * concurrently (one thread sets them, many threads read them),
+ * WITHOUT SYNCHRONIZATION. If assignment to currenttime especially
+ * is not atomic, current_time() will return bogus values, and
+ * bogus behavior may ensue. We think this isn't a problem, because
+ * currenttime is a static variable, and defined first in this module;
+ * consequently it's aligned, and doesn't cross cache lines or
+ * otherwise run afoul of multiprocessor weirdness that might make
+ * assignment to it non-atomic.
+ */
+
+#ifndef HAVE_TIME_R
+PRLock *time_func_mutex;
+
+int gmtime_r(
+ const time_t *timer,
+ struct tm *result
+)
+{
+ if ( result == NULL ) {
+ return -1;
+ }
+ PR_Lock( time_func_mutex );
+ memcpy( (void *) result, (const void *) gmtime( timer ),
+ sizeof( struct tm ));
+ PR_Unlock( time_func_mutex );
+ return 0;
+}
+
+int localtime_r(
+ const time_t *timer,
+ struct tm *result
+)
+{
+ if ( result == NULL ) {
+ return -1;
+ }
+ PR_Lock( time_func_mutex );
+ memcpy( (void *) result, (const void *) localtime( timer ),
+ sizeof( struct tm ));
+ PR_Unlock( time_func_mutex );
+ return 0;
+}
+
+
+int ctime_r(
+ const time_t *timer,
+ char *buffer,
+ int buflen
+)
+{
+ if (( buffer == NULL ) || ( buflen < 26)) {
+ return -1;
+ }
+ PR_Lock( time_func_mutex );
+ memset( buffer, 0, buflen );
+ memcpy( buffer, ctime( timer ), 26 );
+ PR_Unlock( time_func_mutex );
+ return 0;
+}
+#endif /* HAVE_TIME_R */
+
+
+char *
+get_timestring(time_t *t)
+{
+ char *timebuf;
+
+#if defined( _WIN32 )
+ timebuf = ctime( t );
+#else
+ if ( (timebuf = slapi_ch_malloc(32)) == NULL )
+ return("No memory for get_timestring");
+ CTIME(t, timebuf, 32);
+#endif
+ timebuf[strlen(timebuf) - 1] = '\0'; /* strip out return */
+ return(timebuf);
+}
+
+void
+free_timestring(char *timestr)
+{
+#if defined( _WIN32 )
+ return;
+#else
+ if ( timestr != NULL )
+ slapi_ch_free((void**)&timestr);
+#endif
+}
+
+/*
+ * poll_current_time() is called at least once every second by the time
+ * thread (see daemon.c:time_thread()). current_time() returns the time
+ * that poll_current_time() last stored. This approach is used to avoid
+ * calling the time() system call many times per second.
+ *
+ * Note: during server startup, poll_current_time() is not called at all so
+ * current_time() just calls through to time() until poll_current_time() starts
+ * to be called.
+ */
+time_t
+poll_current_time()
+{
+ if ( !currenttime_set ) {
+ currenttime_set = 1;
+ }
+
+ time( &currenttime );
+ return( currenttime );
+}
+
+time_t
+current_time( void )
+{
+ if ( currenttime_set ) {
+ return( currenttime );
+ } else {
+ return( time( (time_t *)0 ));
+ }
+}
+
+time_t
+time_plus_sec (time_t l, long r)
+ /* return the point in time 'r' seconds after 'l'. */
+{
+ /* On many (but not all) platforms this is simply l + r;
+ perhaps it would be better to implement it that way. */
+ struct tm t;
+ if (r == 0) return l; /* performance optimization */
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &l );
+ memcpy(&t, pt, sizeof(struct tm) );
+ }
+#else
+ localtime_r (&l, &t);
+#endif
+ /* Conceptually, we want to do: t.tm_sec += r;
+ but to avoid overflowing fields: */
+ r += t.tm_sec; t.tm_sec = r % 60; r /= 60;
+ r += t.tm_min; t.tm_min = r % 60; r /= 60;
+ r += t.tm_hour; t.tm_hour = r % 24; r /= 24;
+ t.tm_mday += r; /* may be > 31; mktime_r() must handle this */
+
+ /* These constants are chosen to work when the maximum
+ field values are 127 (the worst case) or more.
+ Perhaps this is excessively conservative. */
+ return mktime_r (&t);
+}
+
+char*
+format_localTime (time_t from)
+ /* return a newly-allocated string containing the given time, expressed
+ in the syntax of a generalizedTime, except without the time zone. */
+{
+ char* into;
+ struct tm t;
+#ifdef _WIN32
+ {
+ struct tm *pt = localtime( &from );
+ memcpy(&t, pt, sizeof(struct tm) );
+ }
+#else
+ localtime_r (&from, &t);
+#endif
+ into = slapi_ch_malloc (15);
+ sprintf (into, "%.4li%.2i%.2i%.2i%.2i%.2i",
+ 1900L + t.tm_year, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.
+tm_sec);
+ return into;
+}
+
+time_t
+read_localTime (struct berval* from)
+/* the inverse of write_localTime */
+{
+ return (read_genTime(from));
+}
+
+
+time_t
+parse_localTime (char* from)
+ /* the inverse of format_localTime */
+{
+ return (parse_genTime(from));
+}
+
+void
+write_localTime (time_t from, struct berval* into)
+ /* like format_localTime, except it returns a berval */
+{
+ into->bv_val = format_localTime (from);
+ into->bv_len = 14; /* strlen (into->bv_val) */
+}
+
+/*
+ * Function: strntoul
+ *
+ * Returns: the value of "from", converted to an unsigned long integer.
+ *
+ * Arguments: from - a pointer to the string to be converted.
+ * len - the maximum number of characters to process.
+ * base - the base to use for conversion. See strtoul(3).
+ *
+ * Returns: See strtoul(3).
+ */
+LDAP_API(unsigned long) strntoul( char *from, size_t len, int base )
+{
+ unsigned long result;
+ char c = from[ len ];
+
+ from[ len ] = '\0';
+ result = strtoul( from, NULL, base );
+ from[ len ] = c;
+ return result;
+}
+
+/*
+ * New time functions.
+ * The format and write functions, express time as
+ * generalizedTime (in the Z form).
+ * The parse and read functions, can read either
+ * localTime or generalizedTime.
+ */
+
+char *
+format_genTime (time_t from)
+ /* return a newly-allocated string containing the given time, expressed
+ in the syntax of a generalizedTime. */
+{
+ char* into;
+ struct tm t;
+#ifdef _WIN32
+ {
+ struct tm *pt = gmtime( &from );
+ memcpy(&t, pt, sizeof(struct tm) );
+ }
+#else
+ gmtime_r (&from, &t);
+#endif
+ into = slapi_ch_malloc (20);
+ strftime(into, 20, "%Y%m%d%H%M%SZ", &t);
+ return into;
+}
+
+void
+write_genTime (time_t from, struct berval* into)
+ /* like format_localTime, except it returns a berval */
+{
+ into->bv_val = format_genTime (from);
+ into->bv_len = strlen (into->bv_val);
+}
+
+time_t
+read_genTime(struct berval*from)
+{
+ struct tm t;
+ time_t retTime;
+ time_t diffsec = 0;
+ int i, gflag = 0, havesec = 0;
+
+ memset (&t, 0, sizeof(t));
+ t.tm_isdst = -1;
+ t.tm_year = strntoul (from->bv_val , 4, 10) - 1900L;
+ t.tm_mon = strntoul (from->bv_val + 4, 2, 10) - 1;
+ t.tm_mday = strntoul (from->bv_val + 6, 2, 10);
+ t.tm_hour = strntoul (from->bv_val + 8, 2, 10);
+ t.tm_min = strntoul (from->bv_val + 10, 2, 10);
+ i =12;
+ /*
+ * the string can end with Z or -xxxx or +xxxx
+ * or before to have the Z/+/- we may have two digits for the seconds.
+ * If there's no Z/+/-, it means it's been expressed as local time
+ * (not standard).
+ */
+ while (from->bv_val[i]) {
+ switch (from->bv_val[i]) {
+ case 'Z':
+ case 'z':
+ gflag = 1;
+ ++i;
+ break;
+ case '+': /* Offset from GMT is on 4 digits */
+ i++;
+ diffsec -= strntoul (from->bv_val + i, 4, 10);
+ gflag = 1;
+ i += 4;
+ break;
+ case '-': /* Offset from GMT is on 4 digits */
+ i++;
+ diffsec += strntoul (from->bv_val + i, 4, 10);
+ gflag = 1;
+ i += 4;
+ break;
+ default:
+ if (havesec){
+ /* Ignore milliseconds */
+ i++;
+ } else {
+ t.tm_sec = strntoul (from->bv_val + i, 2, 10);
+ havesec = 1;
+ i += 2;
+ }
+ } /* end switch */
+ }
+ if (gflag){
+ PRTime pt;
+ PRExplodedTime expt = {0};
+ unsigned long year = strntoul (from->bv_val , 4, 10);
+
+ expt.tm_year = (PRInt16)year;
+ expt.tm_month = t.tm_mon;
+ expt.tm_mday = t.tm_mday;
+ expt.tm_hour = t.tm_hour;
+ expt.tm_min = t.tm_min;
+ expt.tm_sec = t.tm_sec;
+ /* This is a GMT time */
+ expt.tm_params.tp_gmt_offset = 0;
+ expt.tm_params.tp_dst_offset = 0;
+ /* PRTime is expressed in microseconds */
+ pt = PR_ImplodeTime(&expt) / 1000000L;
+ retTime = (time_t)pt;
+ return (retTime + diffsec);
+ } else {
+ return mktime_r (&t);
+ }
+}
+
+time_t
+parse_genTime (char* from)
+/* the inverse of format_genTime
+ * Because read_localTime has been rewriten to take into
+ * account generalizedTime, parse_time is similar to parse_localTime.
+ * The new call is
+ */
+{
+ struct berval tbv;
+ tbv.bv_val = from;
+ tbv.bv_len = strlen (from);
+
+ return read_genTime(&tbv);
+}
diff --git a/ldap/servers/slapd/tools/Makefile b/ldap/servers/slapd/tools/Makefile
new file mode 100644
index 00000000..abd9fda1
--- /dev/null
+++ b/ldap/servers/slapd/tools/Makefile
@@ -0,0 +1,168 @@
+#
+# 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 LDAP Server tools.
+#
+
+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 = $(OBJDIR)/servers/tools/obj
+BINDIR = $(LDAP_SERVER_RELDIR)
+
+SLAPD_OBJDIR = $(LDAP_OBJDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+ifndef LDAP_USE_OLD_DB
+include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+INCLUDES+=-I$(DB_INCLUDE)
+else
+CFLAGS+=-DLDAP_USE_DB185
+endif
+
+SLAPDHDIR = ../
+
+ifeq ($(ARCH), OSF1)
+PLATFORM_SPECIFIC_EXTRA_LIBRARY = -lcxx
+else # OSF1
+# oems might need to edit this for their platform
+PLATFORM_SPECIFIC_EXTRA_LIBRARY =
+endif # OSF1
+
+INCLUDES += $(SSLINCLUDE)
+DEFS += $(SSL)
+
+OBJS1 += $(OBJDEST)/pwenc.o
+
+ifeq ($(USE_64), 1)
+ifeq ($(ARCH), HPUX)
+LDFLAGS += -lpthread +DA2.0W +DS2.0 +Z
+endif
+ifeq ($(ARCH), SOLARIS)
+LDFLAGS += -xarch=v9
+endif
+endif
+
+
+INCLUDES += -I$(SLAPDHDIR) -I$(LDAP_ADMINCDIR)
+INCLUDES += -I$(ACLINC)
+INCLUDES += -I ../../plugins/rever
+LDFLAGS += $(EXLDFLAGS) $(SSLLIBFLAG)
+
+ifeq ($(ARCH), WINNT)
+SUBSYSTEM=console
+endif
+
+DEPLIBS=
+
+EXTRA_LIBS_DEP = $(LDAPSDK_DEP) \
+ $(LDAP_LIBLDIF_DEP) \
+ $(LDAP_SLIBLCACHE_DEP) $(DB_LIB_DEP) $(LIBSLAPD_DEP) \
+ $(LDAP_COMMON_LIBS_DEP)
+
+EXTRA_LIBS = $(LDAPLINK) \
+ $(LDAP_SLIBLCACHE) $(DB_LIB) \
+ $(PLATFORM_SPECIFIC_EXTRA_LIBRARY) $(LIBSLAPD) $(LDAP_LIBLITEKEY) \
+ $(ALIBS) \
+ $(SECURITYLINK) $(DBMLINK) \
+ $(THREADSLIB) $(LDAP_COMMON_LIBS) $(NSPRLINK) $(SVRCORELINK)
+
+ifeq ($(ARCH), Linux)
+EXTRA_LIBS += -lcrypt
+endif
+
+
+KEYUPG_LIBS_DEP=
+KEYUPG_LIBS=$(LDAP_LIBLITEKEY)
+
+ifeq ($(ARCH), WINNT)
+KEYUPG_LIBS_DEP=$(LDAP_LIBUTIL_DEP)
+KEYUPG_LIBS += $(LDAP_LIBUTIL)
+endif
+
+ifdef HEAPAGENT
+CFLAGS+=-DPURIFYING
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+
+# It looks like all of the latest versions of Unix that we ship on
+# have a good enough heap implementations that they don't need
+# SmartHeap. We still need it on NT.
+ifneq ($(ARCH), WINNT)
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+
+# Don't use smartheap for debug builds on NT
+ifeq ($(ARCH), WINNT)
+ifeq ($(DEBUG), full)
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+endif
+
+ifndef LDAP_DONT_USE_SMARTHEAP
+include $(MCOM_ROOT)/ldapserver/ns_usesh.mk
+_smartheap_depend = $(SH_LIB_DEP)
+else
+CFLAGS+=-DLDAP_DONT_USE_SMARTHEAP
+endif
+
+
+TOOL_OBJS = ldif.o keyupg.o pwenc.o mmldif.o migratecred.o eggencode.o
+ALL_OBJS = $(addprefix $(OBJDEST)/, $(TOOL_OBJS))
+
+LDIF = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, ldif))
+PWDHASH = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, pwdhash))
+MIGRATECRED = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, migratecred))
+KEYUPG = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, keyupg))
+MMLDIF = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, mmldif))
+EGGENCODE = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, eggencode))
+
+BINS= $(LDIF) $(PWDHASH) $(KEYUPG) $(MMLDIF) $(MIGRATECRED)
+EXTRABINS= $(EGGENCODE)
+
+all: $(OBJDEST) $(BINDIR) $(LDAP_ADMIN_BIN_RELDIR) $(BINS)
+
+extras: $(OBJDEST) $(BINDIR) $(EGGENCODE)
+
+$(LDIF): $(OBJDEST)/ldif.o $(LDAP_LIBLDIF_DEP)
+ $(LINK_EXE) $< $(LDAP_LIBLDIF)
+
+$(PWDHASH): $(OBJS1) $(EXTRA_LIBS_DEP)
+ $(LINK_EXE) $(OBJS1) $(EXTRA_LIBS)
+
+$(MIGRATECRED): $(OBJDEST)/migratecred.o $(EXTRA_LIBS_DEP)
+ $(LINK_EXE) $(OBJDEST)/migratecred.o $(EXTRA_LIBS)
+
+$(KEYUPG): $(OBJDEST)/keyupg.o $(KEYUPG_LIBS_DEP)
+ $(LINK_EXE_NOLIBSOBJS) $< $(KEYUPG_LIBS)
+
+$(MMLDIF): $(OBJDEST)/mmldif.o $(EXTRA_LIBS_DEP)
+ $(LINK_EXE_NOLIBSOBJS) $(OBJDEST)/mmldif.o $(EXTRA_LIBS)
+
+$(EGGENCODE): $(OBJDEST)/eggencode.o
+ $(LINK_EXE_NOLIBSOBJS) $(OBJDEST)/eggencode.o
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+clean:
+ -$(RM) $(ALL_OBJS)
+ -$(RM) $(BINS) $(EXTRABINS)
+
diff --git a/ldap/servers/slapd/tools/eggencode.c b/ldap/servers/slapd/tools/eggencode.c
new file mode 100644
index 00000000..92b098ca
--- /dev/null
+++ b/ldap/servers/slapd/tools/eggencode.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 **/
+
+/*
+ * Easter egg encoder. See ../fedse.c:egg_decode() for the mirror image.
+ */
+#include <stdio.h>
+
+static unsigned char egg_nibble2char( int nibble );
+
+int
+main( int argc, char *argv[] )
+{
+ int c, colcount;
+ char outc;
+
+ if ( argc > 1 ) {
+ fprintf( stderr, "usage: %s < in > out\n", argv[0] );
+ return 2;
+ }
+
+ colcount = 0;
+ while (( c = getchar()) != EOF ) {
+ if ( 0 == colcount ) {
+ putchar( '"' );
+ }
+ c ^= 122;
+ outc = egg_nibble2char( (c & 0xF0) >> 4 );
+ putchar( outc );
+ ++colcount;
+ outc = egg_nibble2char( c & 0x0F );
+ putchar( outc );
+ ++colcount;
+ if ( colcount > 72 ) {
+ colcount = 0;
+ putchar( '"' );
+ putchar( '\n' );
+ }
+ }
+
+ if ( colcount > 0 ) {
+ putchar( '"' );
+ putchar( '\n' );
+ }
+
+ return 0;
+}
+
+
+static unsigned char
+egg_nibble2char( int nibble )
+{
+ return ( nibble < 10 ) ? nibble + '0' : ( nibble - 10 ) + 'A';
+}
diff --git a/ldap/servers/slapd/tools/keyupg.c b/ldap/servers/slapd/tools/keyupg.c
new file mode 100644
index 00000000..f1d9adc1
--- /dev/null
+++ b/ldap/servers/slapd/tools/keyupg.c
@@ -0,0 +1,85 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ *
+ * keyupg.c
+ *
+ * Upgrade the Key from Lite to normal ( only one way )
+ *
+ */
+
+
+#include <stdio.h>
+#include <string.h>
+#ifdef hpux
+#include <strings.h>
+#endif /* hpux */
+#ifdef LINUX
+#include <unistd.h> /* needed for getopt */
+#endif
+#if defined( _WIN32 )
+#include <windows.h>
+#include "proto-ntutil.h"
+#endif
+#include <stdlib.h>
+#include "litekey.h"
+
+
+#define BUFSIZE 800
+#define FILE_PATHSEP '/'
+
+int
+main (int argc, char **argv )
+{
+
+
+ char *keyfile = NULL;
+ int i, ikey, nkey;
+ FILE *fp = NULL;
+ int debug =0;
+
+
+ while ( (i = getopt( argc, argv, "k:f:dh" )) != EOF ) {
+ switch (i){
+ case 'f':
+ keyfile = strdup( optarg );
+ break;
+ case 'k':
+ ikey = atoi ( optarg );
+ break;
+ case 'd':
+ debug = 1;
+ break;
+ }
+ }
+
+ if ( (NULL == keyfile ) || (!ikey)) {
+ fprintf (stderr, "usage:%s -k key -f key_file_path\n", argv[0]);
+ exit(1);
+
+ }
+
+ if (debug) printf ( "Key is :%d and file is in :%s\n", ikey, keyfile);
+
+ if ( ! is_key_validNormalKey ( ikey )) {
+ printf ( "Sorry. The input key is invalid\n" );
+ exit (1);
+ }
+
+
+ nkey = generate_directory_key ( DS_NORMAL_TYPE );
+
+ if ( (fp = fopen ( keyfile, "r+b")) == NULL ) {
+ printf ("KEYUPG Error: Could not open the the key file:%s\n", keyfile );
+ exit ( 1 );
+ }
+ fprintf (fp, "key: %d\n", nkey );
+ fclose ( fp );
+
+ printf ("Success: Your Directory Servers have been upgraded to the full version.\n");
+
+ return 0;
+}
diff --git a/ldap/servers/slapd/tools/ldif.c b/ldap/servers/slapd/tools/ldif.c
new file mode 100644
index 00000000..aa90a178
--- /dev/null
+++ b/ldap/servers/slapd/tools/ldif.c
@@ -0,0 +1,128 @@
+/** 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 <string.h>
+#include <memory.h>
+#include <sys/types.h>
+#if defined( _WINDOWS ) || defined( _WIN32 )
+#include <windows.h>
+#include <io.h>
+#include <fcntl.h>
+#else
+#include <unistd.h> /* for read() */
+#include <sys/socket.h>
+#endif
+#include "ldap.h"
+#include "ldif.h"
+
+int ldap_syslog;
+int ldap_syslog_level;
+
+
+static void
+display_usage( char *name )
+{
+ fprintf( stderr, "usage: %s [-b] <attrtype>\n", name );
+}
+
+int main( int argc, char **argv )
+{
+ char *type, *out;
+ int binary = 0;
+
+ if (argc < 2 || argc > 3 ) {
+ display_usage( argv[0] );
+ return( 1 );
+ }
+ if ( argc == 3 ) {
+ if ( strcmp( argv[1], "-b" ) != 0 ) {
+ display_usage( argv[0] );
+ return( 1 );
+ } else {
+ binary = 1;
+ type = argv[2];
+ }
+ } else {
+ if ( strcmp( argv[1], "-b" ) == 0 ) {
+ display_usage( argv[0] );
+ return( 1 );
+ }
+ type = argv[1];
+ }
+
+ /* if the -b flag was used, read single binary value from stdin */
+ if ( binary ) {
+ char buf[BUFSIZ];
+ char *val;
+ int nread, max, cur;
+#if defined( _WINDOWS ) || defined( _WIN32 )
+ _setmode( _fileno( stdin ), _O_BINARY );
+#endif
+
+ if (( val = (char *) malloc( BUFSIZ )) == NULL ) {
+ perror( "malloc" );
+ return( 1 );
+ }
+ max = BUFSIZ;
+ cur = 0;
+ while ( (nread = read( 0, buf, BUFSIZ )) != 0 ) {
+ if ( nread + cur > max ) {
+ max += BUFSIZ;
+ if (( val = (char *) realloc( val, max )) ==
+ NULL ) {
+ perror( "realloc" );
+ return( 1 );
+ }
+ }
+ memcpy( val + cur, buf, nread );
+ cur += nread;
+ }
+
+ if (( out = ldif_type_and_value( type, val, cur )) == NULL ) {
+ perror( "ldif_type_and_value" );
+ return( 1 );
+ }
+
+ fputs( out, stdout );
+ free( out );
+ free( val );
+ return( 0 );
+ } else {
+ /* not binary: one value per line... */
+ char *buf;
+ int curlen, maxlen = BUFSIZ;
+
+ if( (buf = malloc(BUFSIZ)) == NULL ) {
+ perror( "malloc" );
+ return( 1 );
+ }
+ while ( buf = fgets(buf, maxlen, stdin) ) {
+ /* if buffer was filled, expand and keep reading unless last char
+ is linefeed, in which case it is OK for buffer to be full */
+ while( ((curlen = strlen(buf)) == (maxlen - 1)) && buf[curlen-1] != '\n' ) {
+ maxlen *= 2;
+ if( (buf = (char *)realloc(buf, maxlen)) == NULL ) {
+ perror( "realloc" );
+ return( 1 );
+ }
+ fgets(buf+curlen, maxlen/2 + 1, stdin);
+ }
+ /* we have a full line, chop potential newline and turn into ldif */
+ if( buf[curlen-1] == '\n' )
+ buf[curlen-1]='\0';
+ if (( out = ldif_type_and_value( type, buf, strlen( buf ) ))
+ == NULL ) {
+ perror( "ldif_type_and_value" );
+ return( 1 );
+ }
+ fputs( out, stdout );
+ free( out );
+
+ }
+ free( buf );
+ }
+ return( 0 );
+}
diff --git a/ldap/servers/slapd/tools/migratecred.c b/ldap/servers/slapd/tools/migratecred.c
new file mode 100644
index 00000000..9d0d2c66
--- /dev/null
+++ b/ldap/servers/slapd/tools/migratecred.c
@@ -0,0 +1,154 @@
+/** 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 <string.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <sys/param.h> /* MAXPATHLEN */
+#endif
+
+#include "../plugins/rever/rever.h"
+#include "getopt_ext.h"
+
+static void usage(char *name)
+{
+ fprintf(stderr, "usage: %s -o 5.0InstancePath -n 5.1InstancePath -c 5.0Credential\n", name);
+ exit(1);
+}
+
+#ifdef _WIN32
+/* converts '\' chars to '/' */
+static void dostounixpath(char *szText)
+{
+ if(szText)
+ {
+ while(*szText)
+ {
+ if( *szText == '\\' )
+ *szText = '/';
+ szText++;
+ }
+ }
+}
+#endif
+
+/* Script used during 5.0 to 5.1 migration: replication and
+ chaining backend credentials must be converted.
+
+ Assumption: the built-in des-plugin.so lib has been used
+ in 5.0 and is used in 5.1
+
+ Usage: migrateCred
+ -o <5.0 instance path>
+ -n <5.1 instance path>
+ -c <5.0 credential, with prefix>
+
+ Return 5.1 credential with prefix
+*/
+
+int
+main( int argc, char **argv)
+{
+ char *cmd = argv[0];
+ char *oldpath = NULL;
+ char *newpath = NULL;
+ char *prefixCred = NULL;
+ char *cred = NULL;
+
+ char *newcred = NULL;
+ migrate_fn_type fct = NULL;
+ char libpath[MAXPATHLEN];
+ char *shared_lib;
+
+ char *opts = "o:n:c:";
+ int i;
+
+ while (( i = getopt( argc, argv, opts )) != EOF )
+ {
+ switch (i)
+ {
+ case 'o':
+ oldpath = strdup(optarg);
+#ifdef _WIN32
+ dostounixpath(oldpath);
+#endif /* _WIN32 */
+
+ break;
+ case 'n':
+ newpath = strdup(optarg);
+#ifdef _WIN32
+ dostounixpath(newpath);
+#endif /* _WIN32 */
+ break;
+ case 'c':
+ {
+ char *end = NULL;
+ int namelen;
+
+ /* cred has the prefix, remove it before decoding */
+ prefixCred = strdup(optarg);
+
+ if ((*prefixCred == PWD_HASH_PREFIX_START) &&
+ ((end = strchr(prefixCred, PWD_HASH_PREFIX_END)) != NULL) &&
+ ((namelen = end - prefixCred - 1 ) <= (3*PWD_MAX_NAME_LEN)) )
+ {
+ cred = prefixCred + namelen + 2;
+ }
+ else
+ {
+ fprintf(stderr, "Invalid -c argument: %s (wrong prefix?).\n", prefixCred);
+ }
+ }
+ break;
+ default:
+ usage(cmd);
+ }
+ }
+
+ if ( !oldpath || !newpath || !cred )
+ {
+ usage(cmd);
+ }
+
+
+#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
+
+ sprintf(libpath, "%s/../lib/des-plugin%s", newpath, shared_lib);
+
+ fct = (migrate_fn_type)sym_load(libpath, "migrateCredentials",
+ "DES Plugin", 1 /* report errors */ );
+ if ( fct == NULL )
+ {
+ return(1);
+ }
+
+ newcred = (fct)(oldpath, newpath, cred);
+
+ fprintf(stdout, "%s", newcred);
+
+ return(0);
+
+}
diff --git a/ldap/servers/slapd/tools/mkdep.c b/ldap/servers/slapd/tools/mkdep.c
new file mode 100644
index 00000000..469194fe
--- /dev/null
+++ b/ldap/servers/slapd/tools/mkdep.c
@@ -0,0 +1,335 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Originally by Linus Torvalds.
+ * Smart CONFIG_* processing by Werner Almesberger, Michael Chastain.
+ * Lobotomized by Robey Pointer.
+ *
+ * Usage: mkdep file ...
+ *
+ * Read source files and output makefile dependency lines for them.
+ * I make simple dependency lines for #include "*.h".
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef WINNT
+#include <windows.h>
+#include <winbase.h>
+#include <io.h>
+#else
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#endif
+
+
+char __depname[512] = "\n\t@touch ";
+#define depname (__depname+9)
+int hasdep;
+
+char *outdir = ".";
+
+struct path_struct {
+ int len;
+ char buffer[256-sizeof(int)];
+} path = { 0, "" };
+
+
+#ifdef WINNT
+#define EXISTS(_fn) _access(_fn, 00)
+#else
+#define EXISTS(_fn) access(_fn, F_OK)
+#endif
+
+/*
+ * Handle an #include line.
+ */
+void handle_include(const char * name, int len)
+{
+ memcpy(path.buffer+path.len, name, len);
+ path.buffer[path.len+len] = '\0';
+ if (EXISTS(path.buffer))
+ return;
+
+ if (!hasdep) {
+ hasdep = 1;
+ /* don't use outdir if it's a .h file */
+ if ((strlen(depname) > 2) &&
+ (strcmp(depname + strlen(depname) - 2, ".h") == 0)) {
+ /* skip using the outdir */
+ } else {
+ if (outdir)
+ printf("%s/", outdir);
+ }
+ printf("%s:", depname);
+ }
+ printf(" \\\n %s", path.buffer);
+}
+
+
+/* --- removed weird functions to try to emulate asm ---
+ * (turns out it's faster just to scan thru a char*)
+ */
+
+#define GETNEXT { current = *next++; if (next >= end) break; }
+
+/*
+ * State machine macros.
+ */
+#define CASE(c,label) if (current == c) goto label
+#define NOTCASE(c,label) if (current != c) goto label
+
+/*
+ * Yet another state machine speedup.
+ */
+#define MAX2(a,b) ((a)>(b)?(a):(b))
+#define MIN2(a,b) ((a)<(b)?(a):(b))
+#define MAX4(a,b,c,d) (MAX2(a,MAX2(b,MAX2(c,d))))
+#define MIN4(a,b,c,d) (MIN2(a,MIN2(b,MIN2(c,d))))
+
+
+
+/*
+ * The state machine looks for (approximately) these Perl regular expressions:
+ *
+ * m|\/\*.*?\*\/|
+ * m|'.*?'|
+ * m|".*?"|
+ * m|#\s*include\s*"(.*?)"|
+ *
+ * About 98% of the CPU time is spent here, and most of that is in
+ * the 'start' paragraph. Because the current characters are
+ * in a register, the start loop usually eats 4 or 8 characters
+ * per memory read. The MAX6 and MIN6 tests dispose of most
+ * input characters with 1 or 2 comparisons.
+ */
+void state_machine(const char * map, const char * end)
+{
+ register const char * next = map;
+ register const char * map_dot;
+ register unsigned char current;
+
+ for (;;) {
+start:
+ GETNEXT
+__start:
+ if (current > MAX4('/','\'','"','#')) goto start;
+ if (current < MIN4('/','\'','"','#')) goto start;
+ CASE('/', slash);
+ CASE('\'', squote);
+ CASE('"', dquote);
+ CASE('#', pound);
+ goto start;
+
+/* / */
+slash:
+ GETNEXT
+ NOTCASE('*', __start);
+slash_star_dot_star:
+ GETNEXT
+__slash_star_dot_star:
+ NOTCASE('*', slash_star_dot_star);
+ GETNEXT
+ NOTCASE('/', __slash_star_dot_star);
+ goto start;
+
+/* '.*?' */
+squote:
+ GETNEXT
+ CASE('\'', start);
+ NOTCASE('\\', squote);
+ GETNEXT
+ goto squote;
+
+/* ".*?" */
+dquote:
+ GETNEXT
+ CASE('"', start);
+ NOTCASE('\\', dquote);
+ GETNEXT
+ goto dquote;
+
+/* #\s* */
+pound:
+ GETNEXT
+ CASE(' ', pound);
+ CASE('\t', pound);
+ CASE('i', pound_i);
+ goto __start;
+
+/* #\s*i */
+pound_i:
+ GETNEXT NOTCASE('n', __start);
+ GETNEXT NOTCASE('c', __start);
+ GETNEXT NOTCASE('l', __start);
+ GETNEXT NOTCASE('u', __start);
+ GETNEXT NOTCASE('d', __start);
+ GETNEXT NOTCASE('e', __start);
+ goto pound_include;
+
+/* #\s*include\s* */
+pound_include:
+ GETNEXT
+ CASE(' ', pound_include);
+ CASE('\t', pound_include);
+ map_dot = next;
+ CASE('"', pound_include_dquote);
+ goto __start;
+
+/* #\s*include\s*"(.*)" */
+pound_include_dquote:
+ GETNEXT
+ CASE('\n', start);
+ NOTCASE('"', pound_include_dquote);
+ handle_include(map_dot, next - map_dot - 1);
+ goto start;
+
+ }
+}
+
+
+#ifdef WINNT
+
+/*
+ * Alternate implementation of do_depend() for NT
+ * (NT has its own wacky versions of open/mmap/close)
+ */
+void do_depend(const char *filename, const char *command)
+{
+ HANDLE fd, mapfd;
+ BY_HANDLE_FILE_INFORMATION st;
+ char *map;
+
+ fd = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, NULL,
+ OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
+ if (fd == INVALID_HANDLE_VALUE) {
+ fprintf(stderr, "NT error opening '%s'\n", filename);
+ return;
+ }
+ if (! GetFileInformationByHandle(fd, &st)) {
+ fprintf(stderr, "NT error getting stat on '%s'\n", filename);
+ CloseHandle(fd);
+ return;
+ }
+ if (st.nFileSizeLow == 0) {
+ fprintf(stderr, "%s is empty\n", filename);
+ CloseHandle(fd);
+ return;
+ }
+
+ mapfd = CreateFileMapping(fd, NULL, PAGE_READONLY, st.nFileSizeHigh,
+ st.nFileSizeLow, NULL);
+ if (mapfd == NULL) {
+ fprintf(stderr, "NT error creating file mapping of '%s'\n",
+ filename);
+ CloseHandle(fd);
+ return;
+ }
+ map = MapViewOfFile(mapfd, FILE_MAP_READ, 0, 0, 0);
+ if (map == NULL) {
+ fprintf(stderr, "NT error creating mapped view of '%s'\n",
+ filename);
+ CloseHandle(mapfd);
+ CloseHandle(fd);
+ return;
+ }
+
+ hasdep = 0;
+ state_machine(map, map+st.nFileSizeLow);
+ if (hasdep)
+ puts(command);
+
+ UnmapViewOfFile(map);
+ CloseHandle(mapfd);
+ CloseHandle(fd);
+}
+
+#else
+
+/*
+ * Generate dependencies for one file.
+ */
+void do_depend(const char * filename, const char * command)
+{
+ int mapsize;
+ int pagesizem1 = getpagesize()-1;
+ int fd;
+ struct stat st;
+ char * map;
+
+ fd = open(filename, O_RDONLY);
+ if (fd < 0) {
+ perror(filename);
+ return;
+ }
+
+ fstat(fd, &st);
+ if (st.st_size == 0) {
+ fprintf(stderr,"%s is empty\n",filename);
+ close(fd);
+ return;
+ }
+
+ mapsize = st.st_size;
+ mapsize = (mapsize+pagesizem1) & ~pagesizem1;
+ map = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, fd, 0);
+ if ((long) map == -1) {
+ perror("mkdep: mmap");
+ close(fd);
+ return;
+ }
+ if ((unsigned long) map % sizeof(unsigned long) != 0)
+ {
+ fprintf(stderr, "do_depend: map not aligned\n");
+ exit(1);
+ }
+
+ hasdep = 0;
+ state_machine(map, map+st.st_size);
+ if (hasdep)
+ puts(command);
+
+ munmap(map, mapsize);
+ close(fd);
+}
+
+#endif
+
+
+/*
+ * Generate dependencies for all files.
+ */
+int main(int argc, char **argv)
+{
+ int len;
+
+ while (--argc > 0) {
+ const char *filename = *++argv;
+ const char *command = __depname;
+
+ if (strcmp(filename, "-o") == 0) {
+ outdir = *++argv;
+ argc--;
+ continue;
+ }
+ len = strlen(filename);
+ memcpy(depname, filename, len+1);
+ if (len > 2 && filename[len-2] == '.') {
+ if (filename[len-1] == 'c' || filename[len-1] == 'S') {
+ depname[len-1] = 'o';
+ command = "";
+ }
+ }
+ do_depend(filename, command);
+ }
+ return 0;
+}
diff --git a/ldap/servers/slapd/tools/mmldif.c b/ldap/servers/slapd/tools/mmldif.c
new file mode 100644
index 00000000..413c1b7d
--- /dev/null
+++ b/ldap/servers/slapd/tools/mmldif.c
@@ -0,0 +1,1742 @@
+/** 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 <ctype.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <ldap.h>
+#ifndef _WIN32
+# define stricmp strcasecmp
+#else
+# include <io.h>
+#endif
+
+#include <pk11func.h>
+
+#include <slap.h>
+#include <getopt_ext.h>
+#include <ldaplog.h>
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifdef _WIN32
+int slapd_ldap_debug = 0;
+int *module_ldap_debug;
+#endif
+
+/*
+ * VSTRING was defined in PMDF headers.
+ */
+typedef struct vstring {
+ int length;
+ char body[252];
+} MM_VSTRING;
+
+/*
+ * Base64 declarations.
+ */
+
+typedef struct Enc64_s {
+ struct Enc64_s * next;
+ unsigned char * source;
+ int slen;
+} Enc64_t;
+
+typedef struct Dec64_s {
+ struct Dec64_s * next;
+ unsigned char * dest;
+ int maxlen;
+ int curlen;
+ int nextra;
+ unsigned char extra[3];
+} Dec64_t;
+
+Enc64_t * initEnc64(unsigned char * source, int slen);
+int Enc64(Enc64_t * this, unsigned char *dest, int maxlen, int *len);
+void freeEnc64(Enc64_t *this);
+Dec64_t * initDec64(unsigned char * dest, int maxlen);
+int freeDec64(Dec64_t *this);
+int Dec64(Dec64_t * this, unsigned char *source);
+
+/*
+ * License check declarations.
+ */
+
+int license_limit = -1;
+int license_count;
+
+/*
+ * Public declarations.(potentially).
+ */
+
+#define IDDS_MM_OK 0
+#define IDDS_MM_EOF -1
+#define IDDS_MM_ABSENT -2
+#define IDDS_MM_FIO -3
+#define IDDS_MM_BAD -4
+
+/* attrib_t is used to hold each record in memory. The emphasis here is
+ * on size, although compromising simplicity rather than speed. In reality
+ * the way this is used is that there is a block of bytes defined. within
+ * that block are a sequence of records each alligned on whatever is needed
+ * to read shorts happilly. each record consists of a name, a value and
+ * their lengths. The value length is first, because it has to be aligned
+ * then the name value, because we need it first, then the name, null
+ * terminated, then the value, null terminated. Thus if "thing" is a pointer
+ * to one of these things,
+ * thing->data is the name
+ * (thing->data + namelen + 1) is the value,
+ * (thing->data + ((namelen + 1 + valuelen + 1 + 3) & ~3) is the next one
+ * (if we're aligned on 4 byte boundaries)
+ */
+typedef int Boolean;
+typedef struct {
+ int valuelen;
+ char namelen;
+ char data[1];
+} attrib_t;
+
+#define attribname(thing) (thing)->data
+#define attribvalue(thing) ((thing)->data + (thing)->namelen + 1)
+#define attribalign 4
+#define attribsize(thing) (((thing)->namelen + (thing)->valuelen + 1 \
+ + attribalign) & ~(attribalign-1))
+#define attribnext(thing) (attrib_t *)(((char *)thing) \
+ + (((thing)->namelen + (thing)->valuelen \
+ + sizeof(int) + 2 + attribalign) & ~(attribalign-1)))
+
+/* record_t is used to hold a record once it had been squeezed
+ * obviously it has to be allocated carefully so that it is the right size
+ */
+typedef struct {
+ short nattrs;
+ attrib_t data;
+} record_t;
+
+/* attrib1_t is used to read in and sort a record */
+typedef struct attrib1_s {
+ struct attrib1_s *next;
+ char namelen;
+ char name[64];
+ int valuelen;
+ char value[0x20000];
+} attrib1_t;
+
+typedef struct ignore_s {
+ struct ignore_s *next;
+ char name[65];
+} ignore_t;
+
+/* entry_t is the structure used to carry the fingerprint in the hash table */
+typedef struct entry_s {
+ struct entry_s *overflow; /* we hash into buckets. This
+ * is the chain of entries */
+ char key[20]; /* this is the hash of the DN */
+ int present[4]; /* actually treated as a 128 bit array*/
+ /* this is the bitmap of which
+ * directories contain this DN */
+ int db; /* this is the directory number which
+ * provided the data for this entry */
+ record_t * first; /* this it the actual data */
+ char fingerprint[20];/* this is the hash of the data */
+ char flags; /* the status of this entry */
+#define EMPTY 0
+#define IDENTITY 1
+#define MODIFIED 2
+#define LOADED 0x10
+} entry_t;
+
+typedef struct {
+ time_t start_time;
+ int records;
+ int records_away;
+ time_t end_time;
+} cookstats_t;
+
+typedef struct {
+ cookstats_t cook;
+
+ time_t comb_start_time;
+ int authoritative_records;
+ time_t comb_end_time;
+
+ time_t diff_start_time;
+ int num_identities;
+ int num_unchanged;
+ int num_deletes;
+ int num_adds;
+ int num_modifies;
+ time_t diff_end_time;
+
+ cookstats_t uncook;
+} stats_t;
+
+extern int mm_init(int argc, char * argv[]);
+extern int mm_diff(stats_t *statsp);
+
+extern int mm_getvalue(
+ record_t *first,
+ attrib1_t *a,
+ int directory,
+ char *name,
+ char **value,
+ int *length
+);
+
+extern int mm_is_deleted(
+ record_t *first,
+ attrib1_t *a,
+ int directory
+);
+
+extern int mm_get_winner(record_t *first, attrib1_t *a);
+extern void mm_init_winner(void);
+extern void mm_fin_winner(void);
+
+/*
+ * Private declarations.
+ */
+
+#define log_write_error() fprintf(stderr, "error writing record\n")
+
+/*
+ * We need to maintain the order of entries read from input, so that
+ * we can maintain hierarchical ordering. The entryblock structure
+ * is used for that purpose. Memory for blocks of entries are allocated
+ * and strung in a linked list.
+ */
+struct entryblock {
+ entry_t *eb_block;
+ unsigned n;
+ struct entryblock *next;
+};
+
+static struct entryblock *eb_head = NULL, *eb_cur = NULL;
+
+entry_t *entryalloc(void)
+{
+ if (eb_head == NULL || eb_cur->n == 0x1000) {
+ struct entryblock *newblock;
+ newblock =
+ (struct entryblock *)calloc(1, sizeof(struct entryblock));
+ newblock->eb_block = (entry_t*)calloc(0x1000, sizeof(entry_t));
+ if (eb_head == NULL) {
+ eb_cur = eb_head = newblock;
+ } else {
+ eb_cur = eb_cur->next = newblock;
+ }
+ }
+ return &eb_cur->eb_block[eb_cur->n++];
+}
+
+typedef struct {
+ FILE * fp;
+ int end;
+} edfFILE;
+
+static int ndirectories;
+static edfFILE edfin[128];
+static FILE * edfout[128];
+static FILE * ofp;
+static char line[2048];
+static char seed;
+static int hashmask;
+static entry_t **hashtable;
+static int maxcount;
+static int emitchanges;
+
+static int readrec(edfFILE * edf1, attrib1_t ** attrib);
+static void freefreelist(attrib1_t * freelist);
+static void hashname(char seed, attrib1_t * attrib, char * hashkey);
+static void hashvalue(char seed, attrib1_t * attrib, char * fingerprint);
+static record_t * newrecord(attrib1_t * big);
+static int adddelete(FILE * edf3, attrib1_t * attrib);
+static int addnew(FILE * edf3, const char *changetype, record_t * first);
+static int addmodified(FILE * edf3, attrib1_t * attrib, record_t * first);
+static int simpletext(unsigned char * body, int length);
+static int simpletextbody(unsigned char * body, int length);
+static int putvalue(
+ FILE * fh,
+ const char *tag,
+ char * name,
+ int namelen,
+ char * value,
+ int valuelen
+);
+static int signedmemcmp(
+ unsigned char * a,
+ int lena,
+ unsigned char * b,
+ int lenb
+);
+static void makeupper(MM_VSTRING * v, char * body, int len);
+
+static void commententry(FILE *fp, attrib1_t *attrib);
+
+int mm_diff(stats_t *statsp)
+{
+ unsigned int h;
+ entry_t * overflow;
+ int i;
+ int pindex;
+ int pmask;
+ attrib1_t * attrib = 0;
+ entry_t * hashentry;
+ entry_t * hashentry2;
+ char fingerprint[16];
+ int stat;
+ int count;
+ int firsttime = TRUE;
+ int records = 0;
+ int added;
+ struct entryblock *block, *next;
+
+ union {
+ unsigned int key;
+ char data[16];
+ } hashkey;
+
+ unsigned int key;
+
+ time(&statsp->diff_start_time);
+ license_count = 0;
+
+/*
+ * read all entries from all directories hashing name and value, and make
+ * a bitmaps of who has each entry. Flag those entries where at least
+ * one directory differs from any other.
+ */
+ for (i = 0; i < ndirectories; i++) {
+ pindex = i / 32;
+ pmask = 1 << (i % 32);
+ LDAPDebug(LDAP_DEBUG_TRACE, "finger printing directory %d\n", i, 0, 0);
+ while (TRUE) {
+ stat = readrec(&edfin[i], &attrib);
+ if (stat == IDDS_MM_ABSENT) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "ignored: %s: %s\n",
+ attrib->name, attrib->value, 0);
+ continue;
+ }
+ if (stat == IDDS_MM_EOF)
+ break;
+ if (stat != IDDS_MM_OK) {
+ free(hashtable);
+ return stat;
+ }
+ records++;
+ LDAPDebug(LDAP_DEBUG_TRACE, "db%d: %s: %s\n",
+ i, attrib->name, attrib->value);
+ hashname(seed, attrib, hashkey.data);
+ key = hashkey.key & hashmask;
+ if (!hashtable[key]) {
+ hashentry = hashtable[key] = entryalloc();
+ } else {
+ hashentry = hashtable[key];
+ while (hashentry &&
+ memcmp(hashkey.data, hashentry->key, 16))
+ hashentry = hashentry->overflow;
+ if (hashentry != NULL) {
+ if (hashentry->present[pindex] & pmask) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "duplicate DN <%s=%s> (ignored)\n",
+ attrib->name, attrib->value, 0);
+ if (emitchanges) {
+ fprintf(edfout[i], "\n# Duplicate DN:\n");
+ commententry(edfout[i], attrib);
+ }
+ if (ofp != NULL) {
+ fprintf(ofp, "\n# Duplicate DN (in database %d):\n",
+ i);
+ commententry(ofp, attrib);
+ }
+ } else {
+ hashentry->present[pindex] |= pmask;
+ hashvalue(seed, attrib, fingerprint);
+ if (memcmp(fingerprint, hashentry->fingerprint, 16)) {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "...data modified\n", key, 0, 0);
+ hashentry->flags = MODIFIED;
+ }
+ }
+ continue;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE, "overflow in key %u\n", key, 0, 0);
+ hashentry2 = entryalloc();
+ hashentry2->overflow = hashtable[key];
+ hashentry = hashtable[key] = hashentry2;
+ }
+ hashentry->present[pindex] |= pmask;
+ memcpy(hashentry->key, hashkey.data, 16);
+ hashentry->flags = IDENTITY;
+ statsp->num_identities++;
+ hashvalue(seed, attrib, hashentry->fingerprint);
+ }
+ if ((license_limit > 0) && (records > license_limit)) {
+ fprintf(stderr, "license exceeded\n");
+ free(hashtable);
+ return IDDS_MM_BAD;
+ }
+ if (records > license_count)
+ license_count = records;
+ records = 0;
+ }
+
+/*
+ * read all the directories again. This time we load the data into memory
+ * We use a fairly tight (and ugly) structure to hold the data.
+ * There are three possibilities to consider:
+ * 1. no data has yet been loaded for this entry (load it)
+ * 2. data is present, and the data is marked as an identity
+ * (skip it)
+ * 3. data is present, and the data differs in at least one
+ * directory. call out to see who wins.
+ */
+ for (i = 0; i < ndirectories; i++) {
+ rewind(edfin[i].fp);
+ edfin[i].end = FALSE;
+ pindex = i / 32;
+ pmask = 1 << (i % 32);
+
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "loading authoritative data from directory %d\n", i, 0, 0);
+ count = 0;
+ while (TRUE) {
+ stat = readrec(&edfin[i], &attrib);
+ if (stat == IDDS_MM_ABSENT) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "ignored: %s: %s\n",
+ attrib->name, attrib->value, 0);
+ continue;
+ }
+ if (stat == IDDS_MM_EOF)
+ break;
+ if (stat != IDDS_MM_OK) {
+ free(hashtable);
+ return stat;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE, "db%d: %s: %s\n",
+ i, attrib->name, attrib->value);
+ hashname(seed, attrib, hashkey.data);
+ key = hashkey.key & hashmask;
+ hashentry = hashtable[key];
+ while (hashentry &&
+ memcmp(hashentry->key, hashkey.data, 16))
+ hashentry = hashentry->overflow;
+ if (hashentry == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "...hash entry not found\n", 0, 0, 0);
+ continue;
+ }
+ if (!(hashentry->flags & LOADED))
+ {
+ count++;
+ hashentry->first = newrecord(attrib);
+ hashentry->flags |= LOADED;
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...data loaded\n", 0, 0, 0);
+ hashentry->db = i;
+ continue;
+ }
+ if (hashentry->flags & IDENTITY)
+ continue;
+ if (mm_get_winner(hashentry->first, attrib)) {
+ hashentry->flags |= LOADED;
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...winner data loaded\n", 0, 0, 0);
+ hashentry->db = i;
+ free(hashentry->first);
+ hashentry->first = newrecord(attrib);
+ hashvalue(seed, attrib, hashentry->fingerprint);
+ /* must take new fingerprint */
+ continue;
+ }
+ }
+ }
+
+ if (!emitchanges) goto afterchanges;
+
+/*
+ * Now we have the "authoritative" data in memory. Hey, that's what
+ * VM is for. Now we are able to go through each directory (again)
+ * and generate the differences. There are a number of possibilities
+ * 1. the entry is marked as an identity. skip it
+ * 2. the entry is marked as originating from this directory
+ * skip it
+ * 3. the entry's finger print is unchanged. skip it
+ * 4. the entry has isDeleted set. emit a delete
+ * 5. otherwise emit a change record.
+ */
+ for (i = 0; i < ndirectories; i++) {
+ rewind(edfin[i].fp);
+ edfin[i].end = FALSE;
+ pindex = i / 32;
+ pmask = 1 << (i % 32);
+
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "generating differences for directory %d\n", i, 0, 0);
+ count = 0;
+ while (TRUE) {
+ stat = readrec(&edfin[i], &attrib);
+ if (stat == IDDS_MM_ABSENT) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "ignored: %s: %s\n",
+ attrib->name, attrib->value, 0);
+ continue;
+ }
+ if (stat == IDDS_MM_EOF)
+ break;
+ if (stat != IDDS_MM_OK) {
+ free(hashtable);
+ return stat;
+ }
+ LDAPDebug(LDAP_DEBUG_TRACE, "db%d: %s: %s\n",
+ i, attrib->name, attrib->value);
+ hashname(seed, attrib, hashkey.data);
+ key = hashkey.key & hashmask;
+ hashentry = hashtable[key];
+ while (hashentry &&
+ memcmp(hashentry->key, hashkey.data, 16))
+ hashentry = hashentry->overflow;
+ if (hashentry == NULL) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "...hash entry not found\n", 0, 0, 0);
+ continue;
+ }
+ if (hashentry->flags & IDENTITY)
+ continue;
+ if (hashentry->db == i)
+ continue;
+ hashvalue(seed, attrib, fingerprint);
+ if (memcmp(fingerprint, hashentry->fingerprint, 16)) {
+ if (mm_is_deleted(hashentry->first, attrib, 0)) {
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...deleted\n", 0, 0, 0);
+ adddelete(edfout[i], attrib);
+ } else {
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...modified\n", 0, 0, 0);
+ addmodified(edfout[i], attrib, hashentry->first);
+ }
+ }
+ }
+ }
+
+ afterchanges:
+
+/*
+ * Nearly done. Now we need to go through each entry in the hash table
+ * and for each directory check the "present" bit. If this is set
+ * no action is needed here. Otherwise we emit an add.
+ * we take this opportunity to free the memory.
+ */
+ LDAPDebug(LDAP_DEBUG_TRACE, "scanning db for new entries\n", 0, 0, 0);
+ for (h = 0; h < 0x1000; h++) {
+ for (hashentry = hashtable[h]; hashentry; hashentry = overflow) {
+ if (!hashentry->flags)
+ break;
+
+ for (i = 0, added = 0; i < ndirectories; i++) {
+ pindex = i / 32;
+ pmask = 1 << (i % 32);
+ if (hashentry->present[pindex] & pmask)
+ continue;
+ if (mm_is_deleted(hashentry->first, NULL, 0)) continue;
+ added++;
+ if (!emitchanges) continue;
+ LDAPDebug(LDAP_DEBUG_TRACE, " ...add new\n", 0, 0, 0);
+ addnew(edfout[i], "add", hashentry->first);
+ }
+
+ if (added) {
+ statsp->num_adds++;
+ } else if (hashentry->flags & MODIFIED) {
+ statsp->num_modifies++;
+ } else {
+ statsp->num_unchanged++;
+ }
+
+ overflow = hashentry->overflow;
+ }
+ }
+
+ /* output authoritative data and free data */
+ for (block = eb_head; block != NULL; block = next) {
+ entry_t *entry;
+ for (h = 0; h < block->n; h++) {
+ entry = &block->eb_block[h];
+ if (ofp != NULL) {
+ if (!mm_is_deleted(entry->first, NULL, 0)) {
+ addnew(ofp, NULL, entry->first);
+ }
+ }
+ free(entry->first);
+ }
+ next = block->next;
+ free(block->eb_block);
+ free(block);
+ }
+
+ free(hashtable);
+ time(&statsp->diff_end_time);
+ return IDDS_MM_OK;
+}
+
+static void usage(char *m)
+{
+ fprintf(stderr,"usage: mmldif [-c] [-D] [-o out.ldif] in1.ldif in2.ldif ...\n\n", m);
+ fprintf(stderr,"-c\tWrite a change file (.delta) for each input file\n");
+ fprintf(stderr,"-D\tPrint debugging information\n");
+ fprintf(stderr,"-o\tWrite authoritative data to this file\n");
+ fprintf(stderr,"\n");
+ exit(1);
+}
+
+int mm_init(int argc, char * argv[])
+{
+ char deltaname[255];
+ time_t tl;
+ int c;
+ char *ofn = NULL;
+ char *prog = argv[0];
+ char *tailorfile = NULL;
+
+ time(&tl);
+ seed = (char)tl;
+ maxcount = 10;
+ ndirectories = 0;
+ emitchanges = 0;
+ ofp = NULL;
+
+ mm_init_winner();
+
+ slapd_ldap_debug = 0;
+
+ while ((c = getopt(argc, argv, "cDho:")) != EOF) {
+ switch (c) {
+ case 'c':
+ emitchanges = 1;
+ break;
+ case 'D':
+ slapd_ldap_debug = 65535;
+ break;
+ case 'o':
+ ofn = strdup(optarg);
+ break;
+ case 'h':
+ default:
+ usage(prog);
+ break;
+ }
+ }
+
+#ifdef _WIN32
+ module_ldap_debug = &slapd_ldap_debug;
+ libldap_init_debug_level(&slapd_ldap_debug);
+#endif
+
+ if (ofn != NULL) {
+ ofp = fopen(ofn, "w");
+ if (ofp == NULL) {
+ perror(ofn);
+ return -1;
+ }
+ free(ofn);
+ ofn = NULL;
+ }
+
+ for (argv += optind; optind < argc; optind++, argv++) {
+ edfin[ndirectories].fp = fopen(*argv, "r");
+ if (edfin[ndirectories].fp == NULL) {
+ perror(*argv);
+ return -1;
+ }
+ edfin[ndirectories].end = FALSE;
+
+ if (emitchanges) {
+ strcpy(deltaname, *argv);
+ strcat(deltaname, ".delta");
+ edfout[ndirectories] = fopen(deltaname, "w");
+ if (edfout[ndirectories] == NULL) {
+ perror(deltaname);
+ return -1;
+ }
+ }
+ ndirectories++;
+ }
+
+ if (ndirectories == 0) {
+ fprintf(stderr, "\nno input files\n\n");
+ usage(prog);
+ return 0;
+ }
+
+ hashmask = 0xfff;
+ hashtable = (entry_t **)calloc(0x1000, sizeof(entry_t*));
+ if (tailorfile) free(tailorfile);
+ return 0;
+}
+
+/* this clears the attrib structure if there is one, and reads in the data
+ * sorting lines 2 to n by name, and eliminating comments
+ */
+static int
+readrec(edfFILE * edf1, attrib1_t ** attrib)
+{
+ Dec64_t * b64;
+ char * vptr;
+ char * lptr;
+ char * ptr;
+ int len;
+ int lookahead = 0;
+ int toolong = FALSE;
+ int rc;
+ int cmp;
+ attrib1_t * att;
+ attrib1_t ** prev;
+ attrib1_t * freelist = *attrib;
+ attrib1_t * newlist = NULL;
+ attrib1_t * a;
+ int ignore_rec = FALSE;
+
+ *attrib = NULL;
+ if (edf1->end) {
+ freefreelist(freelist);
+ return IDDS_MM_EOF;
+ }
+
+ while (TRUE) {
+ if (lookahead) {
+ if (lookahead == '\n') {
+ break; /* return */
+ }
+ line[0] = lookahead;
+ lptr = line+1;
+ lookahead = 0;
+ }
+ else
+ lptr = line;
+ if (!fgets(lptr, sizeof(line)-1, edf1->fp)) {
+ edf1->end = TRUE;
+ if (!newlist) {
+ /* that's for the case where the file */
+ /* has a trailing blank line */
+ freefreelist(freelist);
+ return IDDS_MM_EOF;
+ }
+ break; /* return */
+ }
+ if (line[0] == '\n') {
+ /* ignore empty lines at head of LDIF file */
+ if (newlist == NULL) {
+ continue;
+ }
+ break; /* an empty line terminates a record */
+ }
+ if (line[0] == '#')
+ continue; /* skip comment lines */
+
+ len = strlen(line);
+ for (lptr = line+len-1; len; len--, lptr--) {
+ if ((*lptr != '\n') && (*lptr != '\r'))
+ break;
+ *lptr = 0;
+ }
+ vptr = strchr(line, ':');
+ if (!vptr) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "%s\n invalid input line\n",
+ line, 0, 0);
+ continue; /* invalid line, but we'll just skip it */
+ }
+ *vptr = 0;
+ if (!stricmp(line, "authoritative"))
+ continue;
+ if (!freelist) {
+ att = (attrib1_t *)malloc(sizeof(attrib1_t));
+ } else {
+ att = freelist;
+ freelist = freelist->next;
+ }
+ att->namelen = vptr-line;
+
+ if (att->namelen > 63) {
+ att->namelen = 63;
+ *(line+64) = 0;
+ }
+
+ memcpy(att->name, line, att->namelen+1);
+ vptr++;
+ if (*vptr == ':') {
+ vptr++;
+ while (*vptr == ' ') vptr++; /* skip optional spaces */
+ b64 = initDec64((unsigned char *)att->value, 0x20000);
+ if (Dec64(b64, (unsigned char *) vptr)) {
+ LDAPDebug(LDAP_DEBUG_TRACE, "%s\n invalid input line\n",
+ line, 0, 0);
+ continue; /* invalid line, but we'll just skip it */
+ }
+ toolong = FALSE;
+ while (TRUE) {
+ lookahead = fgetc(edf1->fp);
+ if (lookahead != ' ')
+ break;
+ fgets(line, sizeof(line), edf1->fp);
+ len = strlen(line);
+ for (lptr = line+len-1; len; len--, lptr--) {
+ if ((*lptr != '\n') && (*lptr != '\r'))
+ break;
+ *lptr = 0;
+ }
+ rc = Dec64(b64, (unsigned char *)line);
+ if (rc == -1)
+ {
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "%s\n invalid input line\n", line, 0, 0);
+ continue; /* invalid line, but we'll just skip it */
+ }
+
+ if (rc) {
+ if (!toolong) {
+ toolong = TRUE;
+ LDAPDebug(LDAP_DEBUG_TRACE,
+ "%s\n line too long\n", line, 0, 0);
+ }
+ continue;
+ }
+ }
+ att->valuelen = freeDec64(b64);
+ } else {
+ if (!*vptr) {
+ att->valuelen = 0;
+ }
+ while (*vptr == ' ') vptr++; /* skip optional spaces */
+
+ att->valuelen = strlen(vptr);
+ memcpy(att->value, vptr, att->valuelen);
+ ptr = att->value + att->valuelen;
+ while (TRUE) {
+ lookahead = fgetc(edf1->fp);
+ if (lookahead != ' ')
+ break;
+ fgets(line, sizeof(line), edf1->fp);
+ len = strlen(line);
+ for (lptr = line+len-1; len; len--, lptr--) {
+ if ((*lptr != '\n') && (*lptr != '\r'))
+ break;
+ *lptr = 0;
+ }
+ memcpy(ptr, line, len);
+ att->valuelen += len;
+ ptr += len;
+ }
+ *ptr = 0;
+ }
+
+ if (newlist) {
+ if (newlist->next) {
+ for (a = newlist->next, prev = &(newlist->next);
+ a; prev=&(a->next), a = a->next) {
+ cmp = stricmp(a->name, att->name);
+ if (cmp > 0) {
+ att->next = *prev;
+ *prev = att;
+ goto f1;
+ }
+ if (cmp == 0) {
+ cmp = signedmemcmp((unsigned char *)a->value,
+ a->valuelen,
+ (unsigned char *)att->value,
+ att->valuelen);
+ if (cmp > 0) {
+ att->next = *prev;
+ *prev = att;
+ goto f1;
+ }
+ }
+ }
+ *prev = att;
+ att->next = NULL;
+ f1: ;
+ } else {
+ newlist->next = att;
+ att->next = NULL;
+ }
+ } else {
+ newlist = att;
+ att->next = NULL;
+ }
+ }
+ *attrib = newlist;
+ freefreelist(freelist);
+ if (ignore_rec)
+ return IDDS_MM_ABSENT;
+ return IDDS_MM_OK;
+}
+
+static void
+freefreelist(attrib1_t * freelist)
+{
+ attrib1_t * next;
+ for (;freelist; freelist = next) {
+ next = freelist->next;
+ free(freelist);
+ }
+}
+
+static void
+hashname(char seed, attrib1_t * attrib, char * hashkey)
+{
+ MM_VSTRING upper;
+ PK11Context *context;
+ unsigned int hashLen;
+
+/* we want the name to be case insensitive, and if the name DN, we want
+ * the value to be case insensitive. */
+/* this creates a hash key based on the first line in attrib */
+ makeupper(&upper, attrib->name, attrib->namelen);
+ context = PK11_CreateDigestContext(SEC_OID_MD5);
+ if (context != NULL) {
+ PK11_DigestBegin(context);
+ PK11_DigestOp(context, (unsigned char *)&seed, 1);
+ PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
+ PK11_DigestOp(context, (unsigned char *)"=", 1);
+ if (!memcmp(upper.body, "DN", 2)) {
+ makeupper(&upper, attrib->value, attrib->valuelen);
+ PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
+ } else
+ PK11_DigestOp(context, (unsigned char *)attrib->value, attrib->valuelen);
+ PK11_DigestFinal(context, (unsigned char *)hashkey, &hashLen, 16);
+ PK11_DestroyContext(context, PR_TRUE);
+ }
+ else { /* Probably desesperate but at least deterministic... */
+ memset(hashkey, 0, 16);
+ }
+}
+
+/* this creates a hash key base on all but the first line in attrib */
+static void
+hashvalue(char seed, attrib1_t * attrib, char * fingerprint)
+{
+ MM_VSTRING upper;
+ attrib1_t * a;
+ PK11Context *context;
+ unsigned int fgLen;
+
+ context = PK11_CreateDigestContext(SEC_OID_MD5);
+ if (context != NULL) {
+ PK11_DigestBegin(context);
+ PK11_DigestOp(context, (unsigned char *)&seed, 1);
+ for (a = attrib->next; a; a = a->next) {
+ if (!stricmp(a->name, "authoritative"))
+ continue;
+ /* we want the name to be case insensitive, and if the name DN, we want
+ * the value to be case insensitive. */
+ makeupper(&upper, a->name, a->namelen);
+ PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
+ PK11_DigestOp(context, (unsigned char *)"=", 1);
+ if (!memcmp(upper.body, "DN", 2)) {
+ makeupper(&upper, a->value, a->valuelen);
+ PK11_DigestOp(context, (unsigned char *)upper.body, upper.length);
+ } else
+ PK11_DigestOp(context, (unsigned char *)a->value, a->valuelen);
+ PK11_DigestOp(context, (unsigned char *)";", 1);
+ }
+ PK11_DigestFinal(context, (unsigned char *)fingerprint, &fgLen, 16);
+ PK11_DestroyContext(context, PR_TRUE);
+ }
+ else { /* Probably desesperate but at least deterministic... */
+ memset(fingerprint, 0, 16);
+ }
+}
+
+/* this writes a record deletion record based on the first line in attrib */
+static int
+adddelete(FILE * edf3, attrib1_t * attrib)
+{
+ if (!putvalue(edf3, NULL, attrib->name, attrib->namelen,
+ attrib->value, attrib->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ fprintf(edf3, "changetype: delete\n\n");
+ return IDDS_MM_OK;
+}
+
+/* this writes a record addition record based on attrib */
+static int
+addnew(FILE * edf3, const char *changetype, record_t * first)
+{
+ attrib_t * att;
+ int attnum;
+
+ for (attnum = 1, att = &first->data;
+ attnum <= first->nattrs;
+ attnum++, att = attribnext(att)) {
+ if (!stricmp(attribname(att), "modifytimestamp"))
+ continue;
+ if (!stricmp(attribname(att), "modifiersname"))
+ continue;
+ if (!putvalue(edf3, NULL, attribname(att), att->namelen,
+ attribvalue(att), att->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ if (attnum == 1 && changetype != NULL) {
+ fprintf(edf3, "changetype: %s\n", changetype);
+ }
+ }
+ if (fputs("\n", edf3) < 0) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ return IDDS_MM_OK;
+}
+
+/* this writes a record modification record based on the information in
+ * first and attrib
+ */
+static int
+addmodified(FILE * edf3, attrib1_t * attrib, record_t * first)
+{
+ attrib_t *b;
+ attrib1_t *a;
+ int num_b;
+ int tot_b;
+ int cmp;
+ char *attrname;
+
+ if (!putvalue(edf3, NULL, attrib->name, attrib->namelen,
+ attrib->value, attrib->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ if (fputs("changetype: modify\n", edf3) < 0) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+
+ tot_b = first->nattrs;
+ num_b = 1;
+ b = &first->data;
+
+ /* advance past dn attrs */
+ a = attrib->next;
+ b = attribnext(b); num_b++;
+
+ /*
+ * Lock-step through the two attr lists while there are still
+ * attrs remaining in either.
+ */
+ while (a != NULL || num_b <= tot_b) {
+ /* ignore operational attrs */
+ if (num_b <= tot_b &&
+ (stricmp(attribname(b), "modifytimestamp") == 0 ||
+ stricmp(attribname(b), "modifiersname") == 0)) {
+ b = attribnext(b); num_b++;
+ continue;
+ }
+ if (a != NULL &&
+ (stricmp(a->name, "modifytimestamp") == 0 ||
+ stricmp(a->name, "modifiersname") == 0)) {
+ a = a->next;
+ continue;
+ }
+
+ if (num_b > tot_b) {
+ cmp = -1;
+ } else if (a == NULL) {
+ cmp = 1;
+ } else {
+ cmp = stricmp(a->name, attribname(b));
+ }
+ if (cmp < 0) {
+ /* a < b: a is deleted */
+ attrname = a->name;
+ fprintf(edf3, "delete: %s\n-\n", attrname);
+ do {
+ a = a->next;
+ } while (a != NULL && stricmp(a->name, attrname) == 0);
+ continue;
+ } else if (cmp > 0) {
+ /* a > b: b is added */
+ attrname = attribname(b);
+ fprintf(edf3, "add: %s\n", attrname);
+ do {
+ if (!putvalue(edf3, NULL, attribname(b), b->namelen,
+ attribvalue(b), b->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ b = attribnext(b); num_b++;
+ } while (num_b <= tot_b && stricmp(attribname(b), attrname) == 0);
+ fprintf(edf3, "-\n");
+ continue;
+ } else {
+ /* a == b */
+ int nmods = 0;
+ attrib_t *begin_b = b;
+ attrib1_t *v_del = NULL;
+ attrib_t *v_add = NULL;
+ int begin_num_b = num_b;
+
+ /*
+ * Lock-step through the ordered values.
+ * Remember a maximum of one changed value.
+ * If we encounter more than one change then
+ * just issue a replace of the whole value.
+ */
+ attrname = a->name;
+ do {
+ if (num_b > tot_b || stricmp(attribname(b), attrname) != 0) {
+ cmp = -1;
+ } else if (a == NULL || stricmp(a->name, attrname) != 0) {
+ cmp = 1;
+ } else {
+ cmp = signedmemcmp((unsigned char *)a->value,
+ a->valuelen,
+ (unsigned char *)attribvalue(b),
+ b->valuelen);
+ }
+ if (cmp < 0) {
+ nmods++;
+ v_del = a;
+ a = a->next;
+ } else if (cmp > 0) {
+ nmods++;
+ v_add = b;
+ b = attribnext(b); num_b++;
+ } else {
+ a = a->next;
+ b = attribnext(b); num_b++;
+ }
+ } while ((a != NULL &&
+ stricmp(a->name, attrname) == 0) ||
+ (num_b <= tot_b &&
+ stricmp(attribname(b), attrname) == 0));
+ if (nmods == 1) {
+ if (v_add != NULL) {
+ if (!putvalue(edf3, "add",
+ attribname(v_add), v_add->namelen,
+ attribvalue(v_add), v_add->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ } else {
+ if (!putvalue(edf3, "delete",
+ v_del->name, v_del->namelen,
+ v_del->value, v_del->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ }
+ } else if (nmods > 1) {
+ fprintf(edf3, "replace: %s\n", attrname);
+ do {
+ if (!putvalue(edf3, NULL,
+ attribname(begin_b), begin_b->namelen,
+ attribvalue(begin_b), begin_b->valuelen)) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ begin_b = attribnext(begin_b); begin_num_b++;
+ } while (begin_num_b <= tot_b && begin_b != b);
+ fprintf(edf3, "-\n");
+ }
+ }
+ }
+
+ if (fputs("\n", edf3) < 0) {
+ log_write_error();
+ return IDDS_MM_FIO;
+ }
+ return IDDS_MM_OK;
+}
+
+static record_t * newrecord(attrib1_t * big)
+{
+ record_t * smll;
+ attrib_t * b;
+ attrib1_t * a;
+ int len = 0;
+ int count = 0;
+
+ for (a=big; a; a = a->next) {
+ count++;
+ len += (a->namelen + a->valuelen + sizeof(attrib_t) + attribalign) &
+ ~ (attribalign-1);
+ }
+ len += sizeof(short);
+ smll = (record_t *)malloc(len);
+
+ for (a=big, b=&smll->data; a; a = a->next, b = attribnext(b)) {
+ b->valuelen = a->valuelen;
+ b->namelen = a->namelen;
+ memcpy(attribname(b), a->name, a->namelen+1);
+ memcpy(attribvalue(b), a->value, a->valuelen+1);
+ }
+ smll->nattrs = count;
+ return smll;
+}
+
+static int
+simpletextbody(unsigned char * body, int length)
+{
+ int i;
+ for (i = length; --i >= 0; body++) {
+ if ((*body < ' ') || (*body >= 0x7f))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static int
+simpletext(unsigned char * body, int length)
+{
+ if ((*body == ':') || (*body == '<') || (*body == ' '))
+ return FALSE;
+ return simpletextbody(body, length);
+}
+
+/* output a string value */
+static int
+putvalue(
+ FILE * fh,
+ const char * tag,
+ char * name,
+ int namelen,
+ char * value,
+ int valuelen
+)
+{
+ Enc64_t * b64;
+ char * lptr;
+ char line[255];
+ int return_code;
+ int len;
+ char * sptr;
+ int rc;
+ int simpletxt = TRUE;
+
+ lptr = line;
+ if (tag != NULL) {
+ sprintf(lptr, "%s: ", tag);
+ lptr += strlen(lptr);
+ memcpy(lptr, name, namelen);
+ lptr += namelen;
+ *lptr++ = '\n';
+ }
+
+ memcpy(lptr, name, namelen);
+ lptr += namelen;
+ *lptr++ = ':';
+
+ if (!valuelen) {
+ *lptr = '\n';
+ *(lptr+1) = 0;
+ return_code = fputs(line, fh);
+ goto return_bit;
+ }
+
+ if (simpletext((unsigned char *)value, valuelen)) {
+ *lptr = ' ';
+ if (valuelen + (lptr+1 - line) < 80) {
+ strcpy(lptr+1, value);
+ strcpy(lptr+1 + valuelen, "\n");
+ return_code = fputs(line, fh);
+ goto return_bit;
+ }
+ len = 80 - (lptr+1 - line);
+ memcpy(lptr+1, value, len);
+ line[80] = '\n';
+ line[81] = 0;
+ return_code = fputs(line, fh);
+ if (return_code < 0)
+ goto return_bit;
+ sptr = value + len;
+ len = valuelen - len;
+ line[0] = ' ';
+ while (len > 79) {
+ memcpy(line+1, sptr, 79);
+ return_code = fputs(line, fh);
+ if (return_code < 0)
+ goto return_bit;
+ sptr += 79;
+ len -= 79;
+ }
+ if (len) {
+ memcpy(line+1, sptr, len);
+ line[len+1] = '\n';
+ line[len+2] = 0;
+ return_code = fputs(line, fh);
+ }
+ goto return_bit;
+ }
+
+ b64 = initEnc64((unsigned char *)value, valuelen);
+ *lptr = ':';
+ *(lptr+1) = ' ';
+ rc = Enc64(b64, (unsigned char *)(lptr+2), 80-(lptr-line), &len);
+ *(lptr +len+2) = '\n';
+ *(lptr + len +3) = 0;
+ return_code = fputs(line, fh);
+ if (return_code < 0)
+ goto return_bit;
+ while (TRUE) {
+ line[0] = ' ';
+ rc = Enc64(b64, (unsigned char *)line+1, 79, &len);
+ if (rc)
+ break;
+ line[len+1] = '\n';
+ line[len+2] = 0;
+ return_code = fputs(line, fh);
+ if (return_code < 0)
+ goto return_bit;
+ }
+
+ return_bit:
+ if (tag != NULL) {
+ fputs("-\n", fh);
+ }
+ if (return_code < 0)
+ return FALSE;
+ return TRUE;
+}
+
+static int
+signedmemcmp(unsigned char * a, int lena, unsigned char * b, int lenb)
+{
+ int c;
+
+ for (;; a++, b++) {
+ if (!lenb)
+ return lena;
+ if (!lena)
+ return -1;
+ if (c=(int)*a - (int)*b)
+ return c;
+ lena--;
+ lenb--;
+ }
+}
+
+static void
+makeupper(MM_VSTRING * v, char * body, int len)
+{
+ char * vp;
+ v->length = len;
+ for (vp = v->body; len > 0; len--, vp++, body++)
+ *vp = toupper(*body);
+}
+
+int
+mm_getvalue(
+ record_t *first,
+ attrib1_t *a,
+ int directory,
+ char *name,
+ char **value,
+ int *length
+)
+{
+ int attnum;
+ attrib_t * att;
+ if (directory) {
+ for ( ; a; a = a->next) {
+ if (!stricmp(a->name, name)) {
+ if (!*value) {
+ *value = a->value;
+ *length = a->valuelen;
+ return TRUE;
+ } else {
+ if (*value == a->value)
+ *value = NULL;
+ }
+ }
+ }
+ return FALSE;
+ }
+
+ att = &first->data;
+
+ for (attnum = 1, att = &first->data;
+ attnum <= first->nattrs;
+ attnum++, att = attribnext(att)) {
+ if (!stricmp(attribname(att), name)) {
+ if (!*value) {
+ *value = attribvalue(att);
+ *length = att->valuelen;
+ return TRUE;
+ } else {
+ if (*value == attribvalue(att))
+ *value = NULL;
+ }
+ }
+ }
+ return FALSE;
+}
+
+int mm_is_deleted(
+ record_t *first,
+ attrib1_t *attrib,
+ int directory
+)
+{
+ char * value = NULL;
+ int len;
+
+ while (mm_getvalue(first, attrib, directory,
+ "objectclass",
+ &value, &len)) {
+ if (stricmp(value, "nsTombstone") == 0) {
+ return 1;
+ }
+ }
+
+ if (mm_getvalue(first, attrib, directory, "isdeleted", &value, &len)) {
+ if ((len == 1 && *value == '1') ||
+ (len == 4 && stricmp(value, "true") == 0)) {
+ return 1;
+ }
+ }
+
+ if (mm_getvalue(first, attrib, directory, "zombi", &value, &len)) {
+ return 1;
+ }
+
+ return 0;
+}
+
+static void commententry(FILE *fp, attrib1_t *attrib)
+{
+ attrib1_t *a;
+
+ if (attrib == NULL) return;
+
+ fprintf(fp, "# %s: %s\n", attrib->name, attrib->value);
+ for (a = attrib->next; a; a = a->next) {
+ if (simpletext((unsigned char *)a->value,
+ a->valuelen)) {
+ fprintf(fp, "# %*.*s: %*.*s\n",
+ a->namelen, a->namelen,
+ a->name,
+ a->valuelen, a->valuelen,
+ a->value);
+ }
+ }
+ fprintf(fp, "\n");
+}
+
+int main(int argc, char *argv[])
+{
+ stats_t stats;
+ int rc;
+ float difftime;
+
+ memset(&stats, 0, sizeof(stats));
+
+ if (rc = mm_init(argc, argv))
+ return rc;
+
+ if ((mm_diff(&stats) == IDDS_MM_OK)
+ && (license_limit > 0)) {
+ if (license_count > license_limit * 98.0 / 100)
+ fprintf(stderr, "That was over 98% of your license limit.\n");
+ else if (license_count > license_limit * 95.0 / 100)
+ fprintf(stderr, "That was over 95% of your license limit.\n");
+ else if (license_count > license_limit * 90.0 / 100)
+ fprintf(stderr, "That was over 90% of your license limit.\n");
+ }
+ mm_fin_winner();
+ printf("start time %s", ctime(&stats.diff_start_time));
+ printf("\nentry counts: unchanged=%d changed=%d new=%d total=%d\n\n",
+ stats.num_unchanged,
+ stats.num_modifies,
+ stats.num_adds,
+ stats.num_identities);
+ printf("end time %s", ctime(&stats.diff_end_time));
+
+ difftime = stats.diff_end_time - stats.diff_start_time;
+ if (difftime <= 1)
+ printf("differencing took <= 1 second\n");
+ else
+ printf("differencing took %u seconds, %u records per second\n",
+ (unsigned int)difftime,
+ (unsigned int)(stats.num_identities / difftime));
+ exit(0);
+}
+
+/*
+ * Conflict resolution.
+ */
+
+void mm_init_winner()
+{
+}
+
+void mm_fin_winner()
+{
+}
+
+int mm_get_winner(record_t * first, attrib1_t * a)
+{
+ int len;
+ char * modified0 = NULL;
+ char * modified1 = NULL;
+
+ mm_getvalue(first, a, 0, "modifytimestamp", &modified0, &len);
+ mm_getvalue(first, a, 1, "modifytimestamp", &modified1, &len);
+
+ if (!modified0) {
+ mm_getvalue(first, a, 0, "createtimestamp", &modified0, &len);
+ }
+
+ if (!modified1) {
+ mm_getvalue(first, a, 1, "createtimestamp", &modified1, &len);
+ }
+
+ if (!modified0) {
+ mm_getvalue(first, a, 0, "deletetimestamp", &modified0, &len);
+ }
+
+ if (!modified1) {
+ mm_getvalue(first, a, 1, "deletetimestamp", &modified1, &len);
+ }
+
+ if (!modified0)
+ return 1;
+ if (!modified1)
+ return 0;
+ return strcmp(modified0, modified1) <= 0;
+}
+
+/*
+ * Base64 Implementation.
+ */
+
+ /* 0123456789ABCDEF */
+static unsigned char b64[] = "ABCDEFGHIJKLMNOP"
+ "QRSTUVWXYZabcdef"
+ "ghijklmnopqrstuv"
+ "wxyz0123456789+/";
+
+static unsigned char ub64[] = {
+/* 0 1 2 3 4 5 6 7
+ * 8 9 A B C C E F
+ */
+/*0-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*0-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*1-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*1-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*2-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*2-*/ 0xFF, 0xFF, 0xFF, 62, 0xFF, 0xFF, 0xFF, 63,
+/*3-*/ 52, 53, 54, 55, 56, 57, 58, 59,
+/*3-*/ 60, 61, 0xFF, 0xFF, 0xFF, 64, 0xFF, 0xFF,
+/*4-*/ 0xFF, 0, 1, 2, 3, 4, 5, 6,
+/*4-*/ 7, 8, 9, 10, 11, 12, 13, 14,
+/*5-*/ 15, 16, 17, 18, 19, 20, 21, 22,
+/*5-*/ 23, 24, 25, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*6-*/ 0xFF, 26, 27, 28, 29, 30, 31, 32,
+/*6-*/ 33, 34, 35, 36, 37, 38, 39, 40,
+/*7-*/ 41, 42, 43, 44, 45, 46, 47, 48,
+/*7-*/ 49, 50, 51, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*8-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*8-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*9-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*9-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*A-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*A-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*B-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*B-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*C-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*C-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*D-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*D-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*E-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*E-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*F-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+/*F-*/ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
+
+
+static Enc64_t * freeEnc64List = NULL;
+static Dec64_t * freeDec64List = NULL;
+
+Enc64_t *
+initEnc64(unsigned char * source, int slen)
+{
+ Enc64_t * this = freeEnc64List;
+ if (this)
+ freeEnc64List = freeEnc64List->next;
+ else
+ this = (Enc64_t *)malloc(sizeof(Enc64_t));
+ this->source = source;
+ this->slen = slen;
+ return this;
+ }
+
+int
+Enc64(Enc64_t * this, unsigned char *dest, int maxlen, int *len)
+{
+ /* returns 0 normally
+ * +1 on end of string
+ * -1 on badi
+ */
+ int l;
+ unsigned char * s;
+ unsigned char * d;
+ int reml;
+ int i;
+
+ if (!this->slen)
+ return 1;
+ l = this->slen / 3;
+ s = this->source;
+ if (l > maxlen / 4)
+ {
+ l = maxlen / 4;
+ this->slen -= l*3;
+ reml = 0;
+ this->source += l*3;
+ }
+ else
+ {
+ reml = this->slen % 3;
+ this->slen = 0;
+ }
+ for (d = dest, i = 0; i < l; i++)
+ {
+ *d++ = b64[(*s >> 2) & 0x3f];
+ *d++ = b64[((*s << 4) & 0x30) + ((*(s+1) >> 4) & 0x0f)];
+ s++;
+ *d++ = b64[((*s << 2) & 0x3c) + ((*(s+1) >> 6) & 0x03)];
+ s++;
+ *d++ = b64[*s & 0x3f];
+ s++;
+ }
+ if (reml--)
+ *d++ = b64[(*s >> 2) & 0x3f];
+ else
+ {
+ *d = 0;
+ *len = l*4;
+ return 0;
+ }
+ if (reml)
+ {
+ *d++ = b64[((*s << 4) & 0x30) + ((*(s+1) >> 4) & 0x0f)];
+ s++;
+ *d++ = b64[((*s << 2) & 0x3c)];
+ }
+ else
+ {
+ *d++ = b64[((*s << 4) & 0x30) + ((*(s+1) >> 4) & 0x0f)];
+ *d++ = '=';
+ }
+ *d++ = '=';
+ *d = 0;
+ *len = (l+1)*4;
+ return 0;
+ }
+
+void
+freeEnc64(Enc64_t *this)
+{
+ this->next = freeEnc64List;
+ freeEnc64List = this;
+ }
+
+Dec64_t *
+initDec64(unsigned char * dest, int maxlen)
+{
+ Dec64_t * this = freeDec64List;
+ if (this)
+ freeDec64List = freeDec64List->next;
+ else
+ this = (Dec64_t *)malloc(sizeof(Dec64_t));
+ this->dest = dest;
+ this->maxlen = maxlen;
+ this->curlen = 0;
+ this->nextra = 0;
+ return this;
+ }
+
+int
+freeDec64(Dec64_t *this)
+{
+ this->next = freeDec64List;
+ freeDec64List = this;
+ return this->curlen;
+ }
+
+int
+Dec64(Dec64_t * this, unsigned char *source)
+{
+ /* returns 0 normally
+ * -1 on badi
+ * 1 on too long
+ */
+ unsigned char * s;
+ unsigned char * d;
+ unsigned char * e;
+ unsigned char s1, s2, s3, s4;
+ int i;
+ int slen;
+ int len;
+ int nextra;
+ int newnextra;
+ unsigned char newextra[3];
+
+ nextra = this->nextra;
+ slen = strlen((char *)source);
+ len = (slen + nextra) / 4;
+ newnextra = (slen + nextra) - len * 4;
+ for (i = 0; i < newnextra; i++)
+ {
+ newextra[i] = source[slen-newnextra+i];
+ }
+
+ if (len * 3 > this->maxlen - this->curlen)
+ return 1;
+ for (d = this->dest + this->curlen, s = source, e = this->extra, i = 0;
+ i < len; i++)
+ {
+ if (nextra)
+ {
+ nextra--;
+ s1 = ub64[*e++];
+ }
+ else
+ s1 = ub64[*s++];
+ if (nextra)
+ {
+ nextra--;
+ s2 = ub64[*e++];
+ }
+ else
+ s2 = ub64[*s++];
+ if (nextra)
+ {
+ nextra--;
+ s3 = ub64[*e++];
+ }
+ else
+ s3 = ub64[*s++];
+ s4 = ub64[*s++];
+ if ((s1 | s2 | s3 | s4) & 0x80)
+ return -1;
+ *d++ = (s1 << 2) + (s2 >> 4);
+ this->curlen++;
+ if (s3 == 64)
+ break;
+ *d++ = (s2 << 4) + (s3 >> 2);
+ this->curlen++;
+ if (s4 == 64)
+ break;
+ *d++ = (s3 << 6) + s4;
+ this->curlen++;
+ }
+ this->nextra = newnextra;
+ memcpy(this->extra, newextra, 3);
+ return 0;
+ }
diff --git a/ldap/servers/slapd/tools/pwenc.c b/ldap/servers/slapd/tools/pwenc.c
new file mode 100644
index 00000000..7a150860
--- /dev/null
+++ b/ldap/servers/slapd/tools/pwenc.c
@@ -0,0 +1,400 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#if defined( _WIN32 )
+#include <sys/stat.h> /* for S_IREAD and S_IWRITE */
+#include <windows.h>
+#include <time.h>
+#include "proto-ntutil.h"
+#else
+#include <sys/socket.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#if defined(LINUX) /* I bet other Unix would like
+ * this flag. But don't want to
+ * break other builds so far */
+#include <unistd.h>
+#endif
+#endif
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include "ldap.h"
+#include "ldif.h"
+#include "../slapi-plugin.h"
+#include "../slap.h"
+#include <nspr.h>
+#include <nss.h>
+#include "../../plugins/pwdstorage/pwdstorage.h"
+
+int ldap_syslog;
+int ldap_syslog_level;
+int slapd_ldap_debug = LDAP_DEBUG_ANY;
+#ifdef _WIN32
+int *module_ldap_debug;
+#endif
+int detached;
+FILE *error_logfp;
+FILE *access_logfp;
+struct pw_scheme *pwdhashscheme;
+int heflag = 0;
+
+static int slapd_config(const char *configdir);
+static int entry_has_attr_and_value(Slapi_Entry *e, const char *attrname, char *value);
+
+static void
+usage( name )
+char *name;
+{
+ fprintf( stderr, "usage: %s -D instance-dir [-H] [-s scheme | -c comparepwd ] password...\n", name );
+ exit( 1 );
+}
+
+
+/*
+ * If global "heflag" is non-zero, un-hex-encode the string
+ * and return a decoded copy. Otherwise return a copy of the
+ * string.
+ */
+static char *
+decode( char *orig )
+{
+ char *r;
+
+ if ( NULL == orig ) {
+ return NULL;
+ }
+ r = calloc( 1, strlen( orig ) + 2 );
+ strcpy( r, orig );
+
+ if ( heflag ) {
+ char *s;
+
+ for ( s = r; *s != '\0'; ++s ) {
+ if ( *s == '%' && ldap_utf8isxdigit( s+1 ) && ldap_utf8isxdigit( s+2 )) {
+ memmove( s, s + 1, 2 );
+ s[ 2 ] = '\0';
+ *s = strtoul( s, NULL, 16 );
+ memmove( s + 1, s + 3, strlen( s + 3 ) + 1 );
+ }
+ }
+ }
+ return r;
+}
+
+
+int
+main( argc, argv )
+ int argc;
+ char *argv[];
+{
+ int i, rc;
+ char *enc, *cmp, *name;
+ struct pw_scheme *pwsp, *cmppwsp;
+ extern int optind;
+ char *cpwd = NULL; /* candidate password for comparison */
+ char errorbuf[BUFSIZ];
+ slapdFrontendConfig_t *slapdFrontendConfig = NULL;
+
+ char *opts = "Hs:c:D:";
+ char *instancedir = NULL;
+ name = argv[ 0 ];
+ pwsp = cmppwsp = NULL;
+
+#ifdef _WIN32
+ module_ldap_debug = &slapd_ldap_debug;
+ libldap_init_debug_level(&slapd_ldap_debug);
+#endif
+
+ PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 0 );
+
+ /* Initialize NSS to make ds_salted_sha1_pw_enc() work */
+ if (NSS_NoDB_Init(NULL) != SECSuccess) {
+ fprintf( stderr, "Fatal error: unable to initialize the NSS subcomponent." );
+ return( 1 );
+ }
+
+
+ while (( i = getopt( argc, argv, opts )) != EOF ) {
+ switch ( i ) {
+ case 'D':
+ /* kexcoff: quite the same as slapd_bootstrap_config */
+ FrontendConfig_init();
+
+ instancedir = rel2abspath( optarg );
+ if ( config_set_instancedir( "configdir (-D)", instancedir,
+ errorbuf, 1) != LDAP_SUCCESS ) {
+ fprintf( stderr, "%s\n", errorbuf );
+ return( 1 );
+ }
+ slapi_ch_free((void **)&instancedir);
+
+
+ slapdFrontendConfig = getFrontendConfig();
+ if (0 == slapd_config(slapdFrontendConfig->configdir)) {
+ fprintf(stderr,
+ "The configuration files in directory %s could not be read or were not found. Please refer to the error log or output for more information.\n",
+ slapdFrontendConfig->configdir);
+ return(1);
+ }
+ break;
+
+ case 's': /* set hash scheme */
+ if (!slapdFrontendConfig) {
+ usage( name );
+ return( 1 );
+ }
+ if (( pwsp = pw_name2scheme( optarg )) == NULL ) {
+ fprintf( stderr, "%s: unknown hash scheme \"%s\"\n", name,
+ optarg );
+ return( 1 );
+ }
+ break;
+
+ case 'c': /* compare encoded password to password */
+ if (!slapdFrontendConfig) {
+ usage( name );
+ return( 1 );
+ }
+ cpwd = optarg;
+ break;
+
+ case 'H': /* password(s) is(are) hex-encoded */
+ if (!slapdFrontendConfig) {
+ usage( name );
+ return( 1 );
+ }
+ heflag = 1;
+ break;
+
+ default:
+ usage( name );
+ }
+ }
+
+ if (!slapdFrontendConfig) {
+ usage( name );
+ return( 1 );
+ }
+
+ if ( cpwd != NULL ) {
+ cmppwsp = pw_val2scheme( decode( cpwd ), &cmp, 1 );
+ }
+
+ if ( cmppwsp != NULL && pwsp != NULL ) {
+ fprintf( stderr, "%s: do not use -s with -c\n", name );
+ usage( name );
+ }
+
+ if ( cmppwsp == NULL && pwsp == NULL ) {
+ pwsp = pw_name2scheme( SALTED_SHA1_SCHEME_NAME );
+ }
+
+ if ( argc <= optind ) {
+ usage( name );
+ }
+
+ if ( cmppwsp == NULL && pwsp->pws_enc == NULL ) {
+ fprintf( stderr,
+ "The scheme \"%s\" does not support password encoding.\n",
+ pwsp->pws_name );
+ return( 1 );
+ }
+
+ srand((int)time(NULL)); /* schemes such as crypt use random salt */
+
+ for ( rc = 0; optind < argc && rc == 0; ++optind ) {
+ if ( cmppwsp == NULL ) { /* encode passwords */
+ if (( enc = (*pwsp->pws_enc)( decode( argv[ optind ] ))) == NULL ) {
+ perror( name );
+ return( 1 );
+ }
+
+ puts( enc );
+ free( enc );
+ } else { /* compare passwords */
+ if (( rc = (*(cmppwsp->pws_cmp))( decode( argv[ optind ]), cmp )) == 0 ) {
+ printf( "%s: password ok.\n", name );
+ } else {
+ printf( "%s: password does not match.\n", name );
+ }
+ }
+ }
+
+ return( rc == 0 ? 0 : 1 );
+}
+
+/* -------------------------------------------------------------- */
+
+/*
+ kexcoff: quite similar to slapd_bootstrap_config() from the server,
+ but it only loads password storage scheme plugins
+ */
+static int
+slapd_config(const char *configdir)
+{
+ char configfile[MAXPATHLEN+1];
+ PRFileInfo prfinfo;
+ int rc = 0; /* Fail */
+ int done = 0;
+ PRInt32 nr = 0;
+ PRFileDesc *prfd = 0;
+ char *buf = 0;
+ char *lastp = 0;
+ char *entrystr = 0;
+
+ sprintf(configfile, "%s/%s", configdir, CONFIG_FILENAME);
+ if ( (rc = PR_GetFileInfo( configfile, &prfinfo )) != PR_SUCCESS )
+ {
+ fprintf(stderr,
+ "The given config file %s could not be accessed, error %d\n",
+ configfile, rc);
+ exit( 1 );
+ }
+ else if (( prfd = PR_Open( configfile, PR_RDONLY,
+ SLAPD_DEFAULT_FILE_MODE )) == NULL )
+ {
+ fprintf(stderr,
+ "The given config file %s could not be read\n",
+ configfile);
+ exit( 1 );
+ }
+ else
+ {
+ /* read the entire file into core */
+ buf = slapi_ch_malloc( prfinfo.size + 1 );
+ if (( nr = slapi_read_buffer( prfd, buf, prfinfo.size )) < 0 )
+ {
+ fprintf(stderr,
+ "Could only read %d of %d bytes from config file %s\n",
+ nr, prfinfo.size, configfile);
+ exit( 1 );
+ }
+
+ (void)PR_Close(prfd);
+ buf[ nr ] = '\0';
+
+ if(!done)
+ {
+ /* Convert LDIF to entry structures */
+ Slapi_DN plug_dn;
+ slapi_sdn_init_dn_byref(&plug_dn, PLUGIN_BASE_DN);
+ while ((entrystr = dse_read_next_entry(buf, &lastp)) != NULL)
+ {
+ /*
+ * XXXmcs: it would be better to also pass
+ * SLAPI_STR2ENTRY_REMOVEDUPVALS in the flags, but
+ * duplicate value checking requires that the syntax
+ * and schema subsystems be initialized... and they
+ * are not yet.
+ */
+ Slapi_Entry *e = slapi_str2entry(entrystr,
+ SLAPI_STR2ENTRY_NOT_WELL_FORMED_LDIF);
+ if (e == NULL)
+ {
+ fprintf(stderr,
+ "The entry [%s] in the configfile %s was empty or could not be parsed\n",
+ entrystr, configfile);
+ continue;
+ }
+
+ /* see if the entry is a child of the plugin base dn */
+ if (slapi_sdn_isgrandparent(&plug_dn,
+ slapi_entry_get_sdn_const(e)))
+ {
+ if ( entry_has_attr_and_value(e, ATTR_PLUGIN_TYPE, "pwdstoragescheme"))
+ {
+ /* add the syntax/matching/pwd storage scheme rule plugin */
+ if (plugin_setup(e, 0, 0, 1))
+ {
+ fprintf(stderr,
+ "The plugin entry [%s] in the configfile %s was invalid\n",
+ slapi_entry_get_dn(e), configfile);
+ exit(1); /* yes this sucks, but who knows what else would go on if I did the right thing */
+ }
+ else
+ {
+ e = 0; /* successful plugin_setup consumes entry */
+ }
+ }
+ }
+
+ if (e)
+ slapi_entry_free(e);
+ }
+
+ /* kexcoff: initialize rootpwstoragescheme and pw_storagescheme
+ * if not explicilty set in the config file
+ */
+ config_set_storagescheme();
+
+ slapi_sdn_done(&plug_dn);
+ rc= 1; /* OK */
+ }
+
+ slapi_ch_free((void **)&buf);
+ }
+
+ return rc;
+}
+
+/*
+ kexcoff: direclty copied fron the server code
+ See if the given entry has an attribute with the given name and the
+ given value; if value is NULL, just test for the presence of the given
+ attribute; if value is an empty string (i.e. value[0] == 0),
+ the first value in the attribute will be copied into the given buffer
+ and returned
+*/
+static int
+entry_has_attr_and_value(Slapi_Entry *e, const char *attrname,
+ char *value)
+{
+ int retval = 0;
+ Slapi_Attr *attr = 0;
+ if (!e || !attrname)
+ return retval;
+
+ /* see if the entry has the specified attribute name */
+ if (!slapi_entry_attr_find(e, attrname, &attr) && attr)
+ {
+ /* if value is not null, see if the attribute has that
+ value */
+ if (!value)
+ {
+ retval = 1;
+ }
+ else
+ {
+ Slapi_Value *v = 0;
+ int index = 0;
+ for (index = slapi_attr_first_value(attr, &v);
+ v && (index != -1);
+ index = slapi_attr_next_value(attr, index, &v))
+ {
+ const char *s = slapi_value_get_string(v);
+ if (!s)
+ continue;
+
+ if (!*value)
+ {
+ strcpy(value, s);
+ retval = 1;
+ break;
+ }
+ else if (!strcasecmp(s, value))
+ {
+ retval = 1;
+ break;
+ }
+ }
+ }
+ }
+
+ return retval;
+}
+
diff --git a/ldap/servers/slapd/unbind.c b/ldap/servers/slapd/unbind.c
new file mode 100644
index 00000000..5f7d9057
--- /dev/null
+++ b/ldap/servers/slapd/unbind.c
@@ -0,0 +1,83 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* unbind.c - decode an ldap unbind operation and pass it to a backend db */
+
+/*
+ * Copyright (c) 1995 Regents of the University of Michigan.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted
+ * provided that this notice is preserved and that due credit is given
+ * to the University of Michigan at Ann Arbor. The name of the University
+ * may not be used to endorse or promote products derived from this
+ * software without specific prior written permission. This software
+ * is provided ``as is'' without express or implied warranty.
+ *
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#ifndef _WIN32
+#include <sys/socket.h>
+#endif
+#include "slap.h"
+
+void
+do_unbind( Slapi_PBlock *pb )
+{
+ Slapi_Operation *operation;
+ BerElement *ber;
+ int err;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "do_unbind\n", 0, 0, 0 );
+
+ slapi_pblock_get( pb, SLAPI_OPERATION, &operation);
+ ber = operation->o_ber;
+ /*
+ * Parse the unbind request. It looks like this:
+ *
+ * UnBindRequest ::= NULL
+ */
+ if ( ber_get_null( ber ) == LBER_ERROR ) {
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d UNBIND,"
+ " decoding error: UnBindRequest not null\n",
+ pb->pb_conn->c_connid, operation->o_opid );
+ /* LDAPv3 does not allow a response to an unbind... so just return. */
+ goto free_and_return;
+ }
+
+ /*
+ * in LDAPv3 there can be optional control extensions on
+ * the end of an LDAPMessage. we need to read them in and
+ * pass them to the backend.
+ */
+ if ( (err = get_ldapmessage_controls( pb, ber, NULL )) != 0 ) {
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d UNBIND,"
+ " error processing controls - error %d (%s)\n",
+ pb->pb_conn->c_connid, operation->o_opid,
+ err, ldap_err2string( err ));
+ /* LDAPv3 does not allow a response to an unbind... so just return. */
+ goto free_and_return;
+ }
+
+ /* target spec is used to decide which plugins are applicable for the operation */
+ PR_Lock( pb->pb_conn->c_mutex );
+ operation_set_target_spec_str (operation, pb->pb_conn->c_dn);
+ PR_Unlock( pb->pb_conn->c_mutex );
+
+ /* ONREPL - plugins should be called and passed bind dn and, possibly, other data */
+
+ slapi_log_access( LDAP_DEBUG_STATS, "conn=%d op=%d UNBIND\n",
+ pb->pb_conn->c_connid, operation->o_opid );
+
+ /* pass the unbind to all backends */
+ be_unbindall( pb->pb_conn, operation );
+
+ /* close the connection to the client */
+ disconnect_server( pb->pb_conn, operation->o_connid, operation->o_opid, SLAPD_DISCONNECT_UNBIND, 0);
+
+free_and_return:;
+}
diff --git a/ldap/servers/slapd/uniqueid.c b/ldap/servers/slapd/uniqueid.c
new file mode 100644
index 00000000..0c7439f0
--- /dev/null
+++ b/ldap/servers/slapd/uniqueid.c
@@ -0,0 +1,295 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* uniqueid.c implementation of entryid functionality */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "slap.h"
+
+#define UIDSTR_SIZE 35 /* size of the string representation of the id */
+#define MODULE "uniqueid" /* for logging */
+
+static int isValidFormat (const char * buff);
+static PRUint8 str2Byte (const char *str);
+
+/* All functions that strat with slapi_ are exposed to the plugins */
+
+/* Function: slapi_uniqueIDNew
+ Description: creates new Slapi_UniqueID object
+ Parameters: none
+ Return: pointer to the new uId object if successful
+ NULL if memory allocation failed
+ */
+
+Slapi_UniqueID *slapi_uniqueIDNew ()
+{
+ Slapi_UniqueID *uId;
+ uId = (Slapi_UniqueID*)slapi_ch_malloc (sizeof (Slapi_UniqueID));
+
+ if (uId == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDNew: "
+ "failed to allocate new id.\n");
+ return NULL;
+ }
+
+ memset (uId, 0, sizeof (Slapi_UniqueID));
+
+ return uId;
+}
+
+/* Function: slapi_uniqueIDDestroy
+ Description: destroys Slapi_UniqueID objects and sets the pointer to NULL
+ Parameters: uId - id to destroy
+ Return: none
+ */
+
+void slapi_uniqueIDDestroy (Slapi_UniqueID **uId)
+{
+ if (uId && *uId)
+ {
+ slapi_ch_free ((void**)uId);
+ *uId = NULL;
+ }
+}
+
+/* Function: slapi_uniqueIDCompare
+ Description: this function lexically compares two entry ids.
+ both Ids must have UUID type.
+ Parameters: uId1, uId2 - ids to compare
+ Return: -1 if uId1 < uId2
+ 0 if uId2 == uId2
+ 1 if uId2 > uId2
+ UID_BADDATA if invalid pointer passed to the function
+*/
+int slapi_uniqueIDCompare (const Slapi_UniqueID *uId1, const Slapi_UniqueID *uId2){
+ if (uId1 == NULL || uId2 == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDCompare: "
+ "NULL argument passed to the function.\n");
+ return UID_BADDATA;
+ }
+
+ return(uuid_compare(uId1, uId2));
+}
+
+/* Function: slapi_uniqueIDCompareString
+ Description: this function compares two uniqueids, represented as strings
+ Parameters: uuid1, uuid2 - ids to compare
+ Return: 0 if uuid1 == uuid2
+ non-zero if uuid1 != uuid2 or uuid1 == NULL or uuid2 == NULL
+*/
+int slapi_uniqueIDCompareString(const char *uuid1, const char *uuid2)
+{
+ int return_value = 0; /* assume not equal */
+ if (NULL != uuid1)
+ {
+ if (NULL != uuid2)
+ {
+ if (strcmp(uuid1, uuid2) == 0)
+ {
+ return_value = 1;
+ }
+ }
+ }
+ return return_value;
+}
+
+/* Function: slapi_uniqueIDFormat
+ Description: this function converts Slapi_UniqueID to its string representation.
+ The id format is HHHHHHHH-HHHHHHHH-HHHHHHHH-HHHHHHHH
+ where H is a hex digit. The data will be outputed in the
+ network byte order.
+ Parameters: uId - entry id
+ buff - buffer in which id is returned; caller must free this
+ buffer
+ Return: UID_SUCCESS - function was successfull
+ UID_BADDATA - invalid parameter passed to the function
+ UID_MEMORY_ERROR - failed to allocate the buffer
+*/
+int slapi_uniqueIDFormat (const Slapi_UniqueID *uId, char **buff){
+ guid_t uuid_tmp;
+
+ if (uId == NULL || buff == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDFormat: "
+ "NULL argument passed to the function.\n");
+ return UID_BADDATA;
+ }
+
+ *buff = (char*)slapi_ch_malloc (UIDSTR_SIZE + 1);
+ if (*buff == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDFormat: "
+ "failed to allocate buffer.\n");
+ return UID_MEMORY_ERROR;
+ }
+
+ uuid_tmp = *uId;
+ uuid_tmp.time_low = htonl(uuid_tmp.time_low);
+ uuid_tmp.time_mid = htons(uuid_tmp.time_mid);
+ uuid_tmp.time_hi_and_version = htons(uuid_tmp.time_hi_and_version);
+
+ sprintf (*buff, "%2.2x%2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x-"
+ "%2.2x%2.2x%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x",
+ ((PRUint8 *) &uuid_tmp.time_low)[0], ((PRUint8 *) &uuid_tmp.time_low)[1],
+ ((PRUint8 *) &uuid_tmp.time_low)[2], ((PRUint8 *) &uuid_tmp.time_low)[3],
+ ((PRUint8 *) &uuid_tmp.time_mid)[0], ((PRUint8 *) &uuid_tmp.time_mid)[1],
+ ((PRUint8 *) &uuid_tmp.time_hi_and_version)[0],
+ ((PRUint8 *) &uuid_tmp.time_hi_and_version)[1],
+ uuid_tmp.clock_seq_hi_and_reserved, uuid_tmp.clock_seq_low,
+ uuid_tmp.node[0], uuid_tmp.node[1], uuid_tmp.node[2],
+ uuid_tmp.node[3], uuid_tmp.node[4], uuid_tmp.node[5]);
+
+ return UID_SUCCESS;
+}
+
+/* Function: slapi_uniqueIDScan
+ Description: this function converts a string buffer into uniqueID.
+ Parameters: uId - unique id to be returned
+ buff - buffer with uniqueID in the format returned by
+ uniqueIDFormat function
+ Return: UID_SUCCESS - function was successfull
+ UID_BADDATA - null parameter(s) or bad format
+*/
+int slapi_uniqueIDScan (Slapi_UniqueID *uId, const char *buff){
+ if (uId == NULL || buff == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDScan: "
+ "NULL argument passed to the function.\n");
+ return UID_BADDATA;
+ }
+
+ if (!isValidFormat (buff))
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDScan: "
+ "invalid data format.\n");
+ return UID_BADDATA;
+ }
+
+ ((PRUint8 *) &uId->time_low)[0] = str2Byte (&(buff[0]));
+ ((PRUint8 *) &uId->time_low)[1] = str2Byte (&(buff[2]));
+ ((PRUint8 *) &uId->time_low)[2] = str2Byte (&(buff[4]));
+ ((PRUint8 *) &uId->time_low)[3] = str2Byte (&(buff[6]));
+ /* next field is at 9 because we skip the - */
+ ((PRUint8 *) &uId->time_mid)[0] = str2Byte (&(buff[9]));
+ ((PRUint8 *) &uId->time_mid)[1] = str2Byte (&(buff[11]));
+ ((PRUint8 *) &uId->time_hi_and_version)[0] = str2Byte (&(buff[13]));
+ ((PRUint8 *) &uId->time_hi_and_version)[1] = str2Byte (&(buff[15]));
+ /* next field is at 18 because we skip the - */
+ uId->clock_seq_hi_and_reserved = str2Byte (&(buff[18]));
+ uId->clock_seq_low = str2Byte (&(buff[20]));
+ uId->node[0] = str2Byte (&(buff[22]));
+ uId->node[1] = str2Byte (&(buff[24]));
+ /* next field is at 27 because we skip the - */
+ uId->node[2] = str2Byte (&(buff[27]));
+ uId->node[3] = str2Byte (&(buff[29]));
+ uId->node[4] = str2Byte (&(buff[31]));
+ uId->node[5] = str2Byte (&(buff[33]));
+
+ uId->time_low = ntohl(uId->time_low);
+ uId->time_mid = ntohs(uId->time_mid);
+ uId->time_hi_and_version = ntohs(uId->time_hi_and_version);
+
+ return UID_SUCCESS;
+}
+
+/* Function: slapi_uniqueIDIsUUID
+ Description: tests if given entry id is in UUID format
+ Parameters: uId - id to test
+ Return 0 - it is UUID
+ 1 - it is not UUID
+ UID_BADDATA - invalid data passed to the function
+ Note: LPXXX - This call is not used currently. Keep it ???
+ */
+int slapi_uniqueIDIsUUID (const Slapi_UniqueID *uId){
+ if (uId == NULL)
+ return UID_BADDATA;
+ /* Shortening Slapi_UniqueID: This call does nothing */
+ return (0);
+}
+
+/* Name: slapi_uniqueIDSize
+ Description: returns size of the string version of uniqueID in bytes
+ Parameters: none
+ Return: size of the string version of uniqueID in bytes
+ */
+int slapi_uniqueIDSize ()
+{
+ return (UIDSTR_SIZE);
+}
+
+/* Name: slapi_uniqueIDDup
+ Description: duplicates an UniqueID object
+ Parameters: uId - id to duplicate
+ Return: duplicate of the Id
+ */
+Slapi_UniqueID* slapi_uniqueIDDup (Slapi_UniqueID *uId)
+{
+ Slapi_UniqueID *uIdDup = slapi_uniqueIDNew ();
+ memcpy (uIdDup, uId, sizeof (Slapi_UniqueID));
+
+ return uIdDup;
+}
+
+/* helper functions */
+
+static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', '\0'};
+/* this function converts a string representation of a byte in hex into
+ an actual byte. For instance: "AB" -> 171 */
+static PRUint8 str2Byte (const char *str)
+{
+ char letter1 = str[0];
+ char letter2 = str[1];
+ PRUint8 num = 0;
+ int i = 0;
+
+ while (hexDigits[i] != '\0')
+ {
+ if (letter1 == hexDigits[i] || toupper (letter1) == hexDigits[i])
+ {
+ num |= (i << 4);
+ }
+
+ if (letter2 == hexDigits[i] || toupper (letter2) == hexDigits[i])
+ {
+ num |= i;
+ }
+
+ i++;
+ }
+
+ return num;
+}
+
+static char* format = "XXXXXXXX-XXXXXXXX-XXXXXXXX-XXXXXXXX";
+/* This function verifies that buff contains data in the correct
+ format (specified above). */
+static int isValidFormat (const char * buff)
+{
+ int len;
+ int i;
+
+ if (strlen (buff) != strlen (format))
+ return UID_BADDATA;
+
+ len = strlen (format);
+
+ for (i = 0; i < len; i++)
+ {
+ if (format[i] == '-' && buff [i] != '-')
+ return 0;
+ else if (format[i] == 'X' && ! isxdigit (buff[i]))
+ return 0;
+ }
+
+ return 1;
+}
+
diff --git a/ldap/servers/slapd/uniqueidgen.c b/ldap/servers/slapd/uniqueidgen.c
new file mode 100644
index 00000000..1765b78d
--- /dev/null
+++ b/ldap/servers/slapd/uniqueidgen.c
@@ -0,0 +1,219 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* uniqueidgen.c - implementation for uniqueID generator */
+
+#include <string.h>
+
+#ifndef _WIN32 /* for ntoh* functions */
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/sysinfo.h>
+#include <sys/utsname.h>
+#endif
+
+#include "nspr.h"
+#include "slap.h"
+#include "uuid.h"
+
+#define MODULE "uniqueid generator"
+
+/* converts from guid -> UniqueID */
+/* static void uuid2UniqueID (const guid_t *uuid, Slapi_UniqueID *uId); */
+/* converts from UniqueID -> guid */
+/* static void uniqueID2uuid (const Slapi_UniqueID *uId, guid_t *uuid); */
+/* validates directory */
+static int validDir (const char *configDir);
+
+/* Function: uniqueIDGenInit
+ Description: this function initializes the generator
+ Parameters: configDir - directory in which generators state is stored
+ configDN - DIT entry with state information
+ mtGen - indicates whether multiple threads will use generator
+ Return: UID_SUCCESS if function succeeds
+ UID_BADDATA if invalif directory is passed
+ UID_SYSTEM_ERROR if any other failure occurs
+*/
+int uniqueIDGenInit (const char *configDir, const Slapi_DN *configDN, PRBool mtGen)
+{
+ int rt;
+ if ((configDN == NULL && (configDir == NULL || !validDir(configDir))) ||
+ (configDN && configDir))
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDGenInit: invalid arguments\n");
+
+ return UID_BADDATA;
+ }
+
+ rt = uuid_init (configDir, configDN, mtGen);
+
+ if (rt == UUID_SUCCESS)
+ return UID_SUCCESS;
+ else
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDGenInit: "
+ "generator initialization failed\n");
+ return UID_SYSTEM_ERROR;
+ }
+}
+
+/* Function: uniqueIDGenCleanup
+ Description: cleanup
+ Parameters: none
+ Return: none
+*/
+void uniqueIDGenCleanup (){
+ uuid_cleanup ();
+}
+
+/* Function: slapi_uniqueIDGenerate
+ Description: this function generates UniqueID; exposed to the plugins.
+ Parameters: uId - structure in which new id will be return
+ Return: UID_SUCCESS, if operation is successful
+ UID_BADDATA, if null pointer is passed to the function
+ UID_SYSTEM_ERROR, if update to persistent storage failed
+*/
+
+int slapi_uniqueIDGenerate (Slapi_UniqueID *uId){
+ int rt;
+
+ if (uId == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDGenerate: "
+ "NULL paramter is passed to the function.\n");
+ return UID_BADDATA;
+ }
+
+ rt = uuid_create(uId);
+ if (rt != UUID_SUCCESS)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDGenerate: "
+ "id generation failed.\n");
+ return UID_SYSTEM_ERROR;
+ }
+ return UID_SUCCESS;
+}
+
+/* Function: slapi_uniqueIDGenerateString
+ Description: this function generates uniqueid an returns it as a string
+ This function returns the data in the format generated by
+ slapi_uniqueIDFormat.
+ Parameters: uId - buffer to receive the ID. Caller is responsible for
+ freeing uId buffer.
+ Return: UID_SUCCESS if function succeeds;
+ UID_BADDATA if invalid pointer passed to the function;
+ UID_MEMORY_ERROR if malloc fails;
+ UID_SYSTEM_ERROR update to persistent storage failed.
+*/
+
+int slapi_uniqueIDGenerateString (char **uId)
+{
+ Slapi_UniqueID uIdTemp;
+ int rc;
+
+ rc = slapi_uniqueIDGenerate (&uIdTemp);
+
+ if (rc != UID_SUCCESS)
+ return rc;
+
+ rc = slapi_uniqueIDFormat (&uIdTemp, uId);
+
+ return rc;
+}
+
+/* Function: slapi_uniqueIDGenerateFromName
+ Description: this function generates an id from name. See uuid
+ draft for more details. This function is thread safe.
+ Parameters: uId - generated id
+ uIDBase - uid used for generation to distinguish different
+ name - buffer containing name from which to generate the id
+ namelen - length of the name buffer
+ name spaces
+ Return: UID_SUCCESS if function succeeds
+ UID_BADDATA if invalid argument is passed to the
+ function.
+*/
+
+int slapi_uniqueIDGenerateFromName (Slapi_UniqueID *uId, const Slapi_UniqueID *uIdBase,
+ const void *name, int namelen)
+{
+ if (uId == NULL || uIdBase == NULL || name == NULL || namelen <= 0)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uniqueIDGenerateMT: "
+ "invalid paramter is passed to the function.\n");
+ return UID_BADDATA;
+ }
+
+ uuid_create_from_name(uId, *uIdBase, name, namelen);
+
+ return UID_SUCCESS;
+}
+
+/* Function: slapi_uniqueIDGenerateFromName
+ Description: this function generates an id from a name and returns
+ it in the string format. See uuid draft for more
+ details. This function can be used in both a
+ singlethreaded and a multithreaded environments.
+ Parameters: uId - generated id in string form
+ uIDBase - uid used for generation to distinguish among
+ different name spaces in string form; NULL means to use
+ empty id as the base.
+ name - buffer containing name from which to generate the id
+ namelen - length of the name buffer
+ Return: UID_SUCCESS if function succeeds
+ UID_BADDATA if invalid argument is passed to the
+ function.
+*/
+
+int slapi_uniqueIDGenerateFromNameString (char **uId,
+ const char *uIdBase,
+ const void *name, int namelen)
+{
+ int rc;
+ Slapi_UniqueID idBase;
+ Slapi_UniqueID idGen;
+
+ /* just use Id of all 0 as base id */
+ if (uIdBase == NULL)
+ {
+ memset (&idBase, 0, sizeof (idBase));
+ memset (&idGen, 0, sizeof (idGen));
+ }
+ else
+ {
+ rc = slapi_uniqueIDScan (&idBase, uIdBase);
+ if (rc != UID_SUCCESS)
+ {
+ return rc;
+ }
+ }
+
+ rc = slapi_uniqueIDGenerateFromName (&idGen, &idBase, name, namelen);
+ if (rc != UID_SUCCESS)
+ {
+ return rc;
+ }
+
+ rc = slapi_uniqueIDFormat (&idGen, uId);
+
+ return rc;
+}
+
+/* helper fumctions */
+
+static int validDir(const char *configDir){
+ PRDir* dir;
+
+ /* empty string means this directory */
+ if (strlen(configDir) == 0)
+ return 1;
+ dir = PR_OpenDir(configDir);
+ if (dir){
+ PR_CloseDir (dir);
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/ldap/servers/slapd/utf8compare.c b/ldap/servers/slapd/utf8compare.c
new file mode 100644
index 00000000..f011472a
--- /dev/null
+++ b/ldap/servers/slapd/utf8compare.c
@@ -0,0 +1,2287 @@
+/** 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 <string.h>
+#include <ctype.h>
+#include "ldap.h"
+#include "slap.h"
+#include "slapi-plugin.h"
+
+typedef struct sUpperLowerTbl {
+ char *upper, *lower;
+ int tsz; /* target size */
+} UpperLowerTbl_t;
+
+/*
+ * slapi_has8thBit: check the input string
+ * return 1 if the string contains 8-bit character
+ * return 0 otherwise
+ */
+int
+slapi_has8thBit(unsigned char *s)
+{
+ unsigned char *p, *tail;
+ tail = s + strlen((char *)s);
+ for (p = s; p < tail; p++) {
+ if (0x80 & *p) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/*
+ * UpperToLower Tables: sorted by upper characters
+ */
+UpperLowerTbl_t Upper2LowerTbl20[] = {
+ /* upper, lower */
+ {"\303\200", "\303\240", 2},
+ {"\303\201", "\303\241", 2},
+ {"\303\202", "\303\242", 2},
+ {"\303\203", "\303\243", 2},
+ {"\303\204", "\303\244", 2},
+ {"\303\205", "\303\245", 2},
+ {"\303\206", "\303\246", 2},
+ {"\303\207", "\303\247", 2},
+ {"\303\210", "\303\250", 2},
+ {"\303\211", "\303\251", 2},
+ {"\303\212", "\303\252", 2},
+ {"\303\213", "\303\253", 2},
+ {"\303\214", "\303\254", 2},
+ {"\303\215", "\303\255", 2},
+ {"\303\216", "\303\256", 2},
+ {"\303\217", "\303\257", 2},
+ {"\303\220", "\303\260", 2},
+ {"\303\221", "\303\261", 2},
+ {"\303\222", "\303\262", 2},
+ {"\303\223", "\303\263", 2},
+ {"\303\224", "\303\264", 2},
+ {"\303\225", "\303\265", 2},
+ {"\303\226", "\303\266", 2},
+ {"\303\230", "\303\270", 2},
+ {"\303\231", "\303\271", 2},
+ {"\303\232", "\303\272", 2},
+ {"\303\233", "\303\273", 2},
+ {"\303\234", "\303\274", 2},
+ {"\303\235", "\303\275", 2},
+ {"\303\236", "\303\276", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl21[] = {
+ {"\304\200", "\304\201", 2},
+ {"\304\202", "\304\203", 2},
+ {"\304\204", "\304\205", 2},
+ {"\304\206", "\304\207", 2},
+ {"\304\210", "\304\211", 2},
+ {"\304\212", "\304\213", 2},
+ {"\304\214", "\304\215", 2},
+ {"\304\216", "\304\217", 2},
+ {"\304\220", "\304\221", 2},
+ {"\304\222", "\304\223", 2},
+ {"\304\224", "\304\225", 2},
+ {"\304\226", "\304\227", 2},
+ {"\304\230", "\304\231", 2},
+ {"\304\232", "\304\233", 2},
+ {"\304\234", "\304\235", 2},
+ {"\304\236", "\304\237", 2},
+ {"\304\240", "\304\241", 2},
+ {"\304\242", "\304\243", 2},
+ {"\304\244", "\304\245", 2},
+ {"\304\246", "\304\247", 2},
+ {"\304\250", "\304\251", 2},
+ {"\304\252", "\304\253", 2},
+ {"\304\254", "\304\255", 2},
+ {"\304\256", "\304\257", 2},
+ {"\304\260", "\151", 1},
+ {"\304\262", "\304\263", 2},
+ {"\304\264", "\304\265", 2},
+ {"\304\266", "\304\267", 2},
+ {"\304\271", "\304\272", 2},
+ {"\304\273", "\304\274", 2},
+ {"\304\275", "\304\276", 2},
+ {"\304\277", "\305\200", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl22[] = {
+ {"\305\201", "\305\202", 2},
+ {"\305\203", "\305\204", 2},
+ {"\305\205", "\305\206", 2},
+ {"\305\207", "\305\210", 2},
+ {"\305\212", "\305\213", 2},
+ {"\305\214", "\305\215", 2},
+ {"\305\216", "\305\217", 2},
+ {"\305\220", "\305\221", 2},
+ {"\305\222", "\305\223", 2},
+ {"\305\224", "\305\225", 2},
+ {"\305\226", "\305\227", 2},
+ {"\305\230", "\305\231", 2},
+ {"\305\232", "\305\233", 2},
+ {"\305\234", "\305\235", 2},
+ {"\305\236", "\305\237", 2},
+ {"\305\240", "\305\241", 2},
+ {"\305\242", "\305\243", 2},
+ {"\305\244", "\305\245", 2},
+ {"\305\246", "\305\247", 2},
+ {"\305\250", "\305\251", 2},
+ {"\305\252", "\305\253", 2},
+ {"\305\254", "\305\255", 2},
+ {"\305\256", "\305\257", 2},
+ {"\305\260", "\305\261", 2},
+ {"\305\262", "\305\263", 2},
+ {"\305\264", "\305\265", 2},
+ {"\305\266", "\305\267", 2},
+ {"\305\270", "\303\277", 2},
+ {"\305\271", "\305\272", 2},
+ {"\305\273", "\305\274", 2},
+ {"\305\275", "\305\276", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl23[] = {
+ {"\306\201", "\311\223", 2},
+ {"\306\202", "\306\203", 2},
+ {"\306\204", "\306\205", 2},
+ {"\306\206", "\311\224", 2},
+ {"\306\207", "\306\210", 2},
+ {"\306\211", "\311\226", 2},
+ {"\306\212", "\311\227", 2},
+ {"\306\213", "\306\214", 2},
+ {"\306\216", "\311\230", 2},
+ {"\306\217", "\311\231", 2},
+ {"\306\220", "\311\233", 2},
+ {"\306\221", "\306\222", 2},
+ {"\306\223", "\311\240", 2},
+ {"\306\224", "\311\243", 2},
+ {"\306\226", "\311\251", 2},
+ {"\306\227", "\311\250", 2},
+ {"\306\230", "\306\231", 2},
+ {"\306\234", "\311\257", 2},
+ {"\306\235", "\311\262", 2},
+ {"\306\237", "\306\237", 2},
+ {"\306\240", "\306\241", 2},
+ {"\306\242", "\306\243", 2},
+ {"\306\244", "\306\245", 2},
+ {"\306\246", "\306\246", 2},
+ {"\306\247", "\306\250", 2},
+ {"\306\251", "\312\203", 2},
+ {"\306\254", "\306\255", 2},
+ {"\306\256", "\312\210", 2},
+ {"\306\257", "\306\260", 2},
+ {"\306\261", "\312\212", 2},
+ {"\306\262", "\312\213", 2},
+ {"\306\263", "\306\264", 2},
+ {"\306\265", "\306\266", 2},
+ {"\306\267", "\312\222", 2},
+ {"\306\270", "\306\271", 2},
+ {"\306\274", "\306\275", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl24[] = {
+ {"\307\204", "\307\205", 2},
+ {"\307\205", "\307\204", 2},
+ {"\307\207", "\307\210", 2},
+ {"\307\210", "\307\207", 2},
+ {"\307\212", "\307\213", 2},
+ {"\307\213", "\307\212", 2},
+ {"\307\215", "\307\216", 2},
+ {"\307\217", "\307\220", 2},
+ {"\307\221", "\307\222", 2},
+ {"\307\223", "\307\224", 2},
+ {"\307\225", "\307\226", 2},
+ {"\307\227", "\307\230", 2},
+ {"\307\231", "\307\232", 2},
+ {"\307\233", "\307\234", 2},
+ {"\307\236", "\307\237", 2},
+ {"\307\240", "\307\241", 2},
+ {"\307\242", "\307\243", 2},
+ {"\307\244", "\307\245", 2},
+ {"\307\246", "\307\247", 2},
+ {"\307\250", "\307\251", 2},
+ {"\307\252", "\307\253", 2},
+ {"\307\254", "\307\255", 2},
+ {"\307\256", "\307\257", 2},
+ {"\307\261", "\307\262", 2},
+ {"\307\262", "\307\261", 2},
+ {"\307\264", "\307\265", 2},
+ {"\307\272", "\307\273", 2},
+ {"\307\274", "\307\275", 2},
+ {"\307\276", "\307\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl25[] = {
+ {"\310\200", "\310\201", 2},
+ {"\310\202", "\310\203", 2},
+ {"\310\204", "\310\205", 2},
+ {"\310\206", "\310\207", 2},
+ {"\310\210", "\310\211", 2},
+ {"\310\212", "\310\213", 2},
+ {"\310\214", "\310\215", 2},
+ {"\310\216", "\310\217", 2},
+ {"\310\220", "\310\221", 2},
+ {"\310\222", "\310\223", 2},
+ {"\310\224", "\310\225", 2},
+ {"\310\226", "\310\227", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl26[] = {
+ {"\316\206", "\316\254", 2},
+ {"\316\210", "\316\255", 2},
+ {"\316\211", "\316\256", 2},
+ {"\316\212", "\316\257", 2},
+ {"\316\214", "\317\214", 2},
+ {"\316\216", "\317\215", 2},
+ {"\316\217", "\317\216", 2},
+ {"\316\221", "\316\261", 2},
+ {"\316\222", "\316\262", 2},
+ {"\316\223", "\316\263", 2},
+ {"\316\224", "\316\264", 2},
+ {"\316\225", "\316\265", 2},
+ {"\316\226", "\316\266", 2},
+ {"\316\227", "\316\267", 2},
+ {"\316\230", "\316\270", 2},
+ {"\316\231", "\316\271", 2},
+ {"\316\232", "\316\272", 2},
+ {"\316\233", "\316\273", 2},
+ {"\316\234", "\316\274", 2},
+ {"\316\235", "\316\275", 2},
+ {"\316\236", "\316\276", 2},
+ {"\316\237", "\316\277", 2},
+ {"\316\240", "\317\200", 2},
+ {"\316\241", "\317\201", 2},
+ {"\316\243", "\317\203", 2},
+ {"\316\244", "\317\204", 2},
+ {"\316\245", "\317\205", 2},
+ {"\316\246", "\317\206", 2},
+ {"\316\247", "\317\207", 2},
+ {"\316\250", "\317\210", 2},
+ {"\316\251", "\317\211", 2},
+ {"\316\252", "\317\212", 2},
+ {"\316\253", "\317\213", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl27[] = {
+ {"\317\222", "\317\222", 2},
+ {"\317\223", "\317\223", 2},
+ {"\317\224", "\317\224", 2},
+ {"\317\232", "\317\232", 2},
+ {"\317\234", "\317\234", 2},
+ {"\317\236", "\317\236", 2},
+ {"\317\240", "\317\240", 2},
+ {"\317\242", "\317\243", 2},
+ {"\317\244", "\317\245", 2},
+ {"\317\246", "\317\247", 2},
+ {"\317\250", "\317\251", 2},
+ {"\317\252", "\317\253", 2},
+ {"\317\254", "\317\255", 2},
+ {"\317\256", "\317\257", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl28[] = {
+ {"\320\201", "\321\221", 2},
+ {"\320\202", "\321\222", 2},
+ {"\320\203", "\321\223", 2},
+ {"\320\204", "\321\224", 2},
+ {"\320\205", "\321\225", 2},
+ {"\320\206", "\321\226", 2},
+ {"\320\207", "\321\227", 2},
+ {"\320\210", "\321\230", 2},
+ {"\320\211", "\321\231", 2},
+ {"\320\212", "\321\232", 2},
+ {"\320\213", "\321\233", 2},
+ {"\320\214", "\321\234", 2},
+ {"\320\216", "\321\236", 2},
+ {"\320\217", "\321\237", 2},
+ {"\320\220", "\320\260", 2},
+ {"\320\221", "\320\261", 2},
+ {"\320\222", "\320\262", 2},
+ {"\320\223", "\320\263", 2},
+ {"\320\224", "\320\264", 2},
+ {"\320\225", "\320\265", 2},
+ {"\320\226", "\320\266", 2},
+ {"\320\227", "\320\267", 2},
+ {"\320\230", "\320\270", 2},
+ {"\320\231", "\320\271", 2},
+ {"\320\232", "\320\272", 2},
+ {"\320\233", "\320\273", 2},
+ {"\320\234", "\320\274", 2},
+ {"\320\235", "\320\275", 2},
+ {"\320\236", "\320\276", 2},
+ {"\320\237", "\320\277", 2},
+ {"\320\240", "\321\200", 2},
+ {"\320\241", "\321\201", 2},
+ {"\320\242", "\321\202", 2},
+ {"\320\243", "\321\203", 2},
+ {"\320\244", "\321\204", 2},
+ {"\320\245", "\321\205", 2},
+ {"\320\246", "\321\206", 2},
+ {"\320\247", "\321\207", 2},
+ {"\320\250", "\321\210", 2},
+ {"\320\251", "\321\211", 2},
+ {"\320\252", "\321\212", 2},
+ {"\320\253", "\321\213", 2},
+ {"\320\254", "\321\214", 2},
+ {"\320\255", "\321\215", 2},
+ {"\320\256", "\321\216", 2},
+ {"\320\257", "\321\217", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl29[] = {
+ {"\321\240", "\321\241", 2},
+ {"\321\242", "\321\243", 2},
+ {"\321\244", "\321\245", 2},
+ {"\321\246", "\321\247", 2},
+ {"\321\250", "\321\251", 2},
+ {"\321\252", "\321\253", 2},
+ {"\321\254", "\321\255", 2},
+ {"\321\256", "\321\257", 2},
+ {"\321\260", "\321\261", 2},
+ {"\321\262", "\321\263", 2},
+ {"\321\264", "\321\265", 2},
+ {"\321\266", "\321\267", 2},
+ {"\321\270", "\321\271", 2},
+ {"\321\272", "\321\273", 2},
+ {"\321\274", "\321\275", 2},
+ {"\321\276", "\321\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl2a[] = {
+ {"\322\200", "\322\201", 2},
+ {"\322\220", "\322\221", 2},
+ {"\322\222", "\322\223", 2},
+ {"\322\224", "\322\225", 2},
+ {"\322\226", "\322\227", 2},
+ {"\322\230", "\322\231", 2},
+ {"\322\232", "\322\233", 2},
+ {"\322\234", "\322\235", 2},
+ {"\322\236", "\322\237", 2},
+ {"\322\240", "\322\241", 2},
+ {"\322\242", "\322\243", 2},
+ {"\322\244", "\322\245", 2},
+ {"\322\246", "\322\247", 2},
+ {"\322\250", "\322\251", 2},
+ {"\322\252", "\322\253", 2},
+ {"\322\254", "\322\255", 2},
+ {"\322\256", "\322\257", 2},
+ {"\322\260", "\322\261", 2},
+ {"\322\262", "\322\263", 2},
+ {"\322\264", "\322\265", 2},
+ {"\322\266", "\322\267", 2},
+ {"\322\270", "\322\271", 2},
+ {"\322\272", "\322\273", 2},
+ {"\322\274", "\322\275", 2},
+ {"\322\276", "\322\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl2b[] = {
+ {"\323\201", "\323\202", 2},
+ {"\323\203", "\323\204", 2},
+ {"\323\207", "\323\210", 2},
+ {"\323\213", "\323\214", 2},
+ {"\323\220", "\323\221", 2},
+ {"\323\222", "\323\223", 2},
+ {"\323\224", "\323\225", 2},
+ {"\323\226", "\323\227", 2},
+ {"\323\230", "\323\231", 2},
+ {"\323\232", "\323\233", 2},
+ {"\323\234", "\323\235", 2},
+ {"\323\236", "\323\237", 2},
+ {"\323\240", "\323\241", 2},
+ {"\323\242", "\323\243", 2},
+ {"\323\244", "\323\245", 2},
+ {"\323\246", "\323\247", 2},
+ {"\323\250", "\323\251", 2},
+ {"\323\252", "\323\253", 2},
+ {"\323\256", "\323\257", 2},
+ {"\323\260", "\323\261", 2},
+ {"\323\262", "\323\263", 2},
+ {"\323\264", "\323\265", 2},
+ {"\323\270", "\323\271", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl2c[] = {
+ {"\324\261", "\325\241", 2},
+ {"\324\262", "\325\242", 2},
+ {"\324\263", "\325\243", 2},
+ {"\324\264", "\325\244", 2},
+ {"\324\265", "\325\245", 2},
+ {"\324\266", "\325\246", 2},
+ {"\324\267", "\325\247", 2},
+ {"\324\270", "\325\250", 2},
+ {"\324\271", "\325\251", 2},
+ {"\324\272", "\325\252", 2},
+ {"\324\273", "\325\253", 2},
+ {"\324\274", "\325\254", 2},
+ {"\324\275", "\325\255", 2},
+ {"\324\276", "\325\256", 2},
+ {"\324\277", "\325\257", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl2d[] = {
+ {"\325\200", "\325\260", 2},
+ {"\325\201", "\325\261", 2},
+ {"\325\202", "\325\262", 2},
+ {"\325\203", "\325\263", 2},
+ {"\325\204", "\325\264", 2},
+ {"\325\205", "\325\265", 2},
+ {"\325\206", "\325\266", 2},
+ {"\325\207", "\325\267", 2},
+ {"\325\210", "\325\270", 2},
+ {"\325\211", "\325\271", 2},
+ {"\325\212", "\325\272", 2},
+ {"\325\213", "\325\273", 2},
+ {"\325\214", "\325\274", 2},
+ {"\325\215", "\325\275", 2},
+ {"\325\216", "\325\276", 2},
+ {"\325\217", "\325\277", 2},
+ {"\325\220", "\326\200", 2},
+ {"\325\221", "\326\201", 2},
+ {"\325\222", "\326\202", 2},
+ {"\325\223", "\326\203", 2},
+ {"\325\224", "\326\204", 2},
+ {"\325\225", "\326\205", 2},
+ {"\325\226", "\326\206", 2},
+ {NULL, NULL, 0}
+ /* upper, lower */
+};
+
+UpperLowerTbl_t Upper2LowerTbl30[] = {
+ /* upper, lower */
+ {"\341\202\240", "\341\203\220", 3},
+ {"\341\202\241", "\341\203\221", 3},
+ {"\341\202\242", "\341\203\222", 3},
+ {"\341\202\243", "\341\203\223", 3},
+ {"\341\202\244", "\341\203\224", 3},
+ {"\341\202\245", "\341\203\225", 3},
+ {"\341\202\246", "\341\203\226", 3},
+ {"\341\202\247", "\341\203\227", 3},
+ {"\341\202\250", "\341\203\230", 3},
+ {"\341\202\251", "\341\203\231", 3},
+ {"\341\202\252", "\341\203\232", 3},
+ {"\341\202\253", "\341\203\233", 3},
+ {"\341\202\254", "\341\203\234", 3},
+ {"\341\202\255", "\341\203\235", 3},
+ {"\341\202\256", "\341\203\236", 3},
+ {"\341\202\257", "\341\203\237", 3},
+ {"\341\202\260", "\341\203\240", 3},
+ {"\341\202\261", "\341\203\241", 3},
+ {"\341\202\262", "\341\203\242", 3},
+ {"\341\202\263", "\341\203\243", 3},
+ {"\341\202\264", "\341\203\244", 3},
+ {"\341\202\265", "\341\203\245", 3},
+ {"\341\202\266", "\341\203\246", 3},
+ {"\341\202\267", "\341\203\247", 3},
+ {"\341\202\270", "\341\203\250", 3},
+ {"\341\202\271", "\341\203\251", 3},
+ {"\341\202\272", "\341\203\252", 3},
+ {"\341\202\273", "\341\203\253", 3},
+ {"\341\202\274", "\341\203\254", 3},
+ {"\341\202\275", "\341\203\255", 3},
+ {"\341\202\276", "\341\203\256", 3},
+ {"\341\202\277", "\341\203\257", 3},
+ {"\341\203\200", "\341\203\260", 3},
+ {"\341\203\201", "\341\203\261", 3},
+ {"\341\203\202", "\341\203\262", 3},
+ {"\341\203\203", "\341\203\263", 3},
+ {"\341\203\204", "\341\203\264", 3},
+ {"\341\203\205", "\341\203\265", 3},
+ {"\341\270\200", "\341\270\201", 3},
+ {"\341\270\202", "\341\270\203", 3},
+ {"\341\270\204", "\341\270\205", 3},
+ {"\341\270\206", "\341\270\207", 3},
+ {"\341\270\210", "\341\270\211", 3},
+ {"\341\270\212", "\341\270\213", 3},
+ {"\341\270\214", "\341\270\215", 3},
+ {"\341\270\216", "\341\270\217", 3},
+ {"\341\270\220", "\341\270\221", 3},
+ {"\341\270\222", "\341\270\223", 3},
+ {"\341\270\224", "\341\270\225", 3},
+ {"\341\270\226", "\341\270\227", 3},
+ {"\341\270\230", "\341\270\231", 3},
+ {"\341\270\232", "\341\270\233", 3},
+ {"\341\270\234", "\341\270\235", 3},
+ {"\341\270\236", "\341\270\237", 3},
+ {"\341\270\240", "\341\270\241", 3},
+ {"\341\270\242", "\341\270\243", 3},
+ {"\341\270\244", "\341\270\245", 3},
+ {"\341\270\246", "\341\270\247", 3},
+ {"\341\270\250", "\341\270\251", 3},
+ {"\341\270\252", "\341\270\253", 3},
+ {"\341\270\254", "\341\270\255", 3},
+ {"\341\270\256", "\341\270\257", 3},
+ {"\341\270\260", "\341\270\261", 3},
+ {"\341\270\262", "\341\270\263", 3},
+ {"\341\270\264", "\341\270\265", 3},
+ {"\341\270\266", "\341\270\267", 3},
+ {"\341\270\270", "\341\270\271", 3},
+ {"\341\270\272", "\341\270\273", 3},
+ {"\341\270\274", "\341\270\275", 3},
+ {"\341\270\276", "\341\270\277", 3},
+ {"\341\271\200", "\341\271\201", 3},
+ {"\341\271\202", "\341\271\203", 3},
+ {"\341\271\204", "\341\271\205", 3},
+ {"\341\271\206", "\341\271\207", 3},
+ {"\341\271\210", "\341\271\211", 3},
+ {"\341\271\212", "\341\271\213", 3},
+ {"\341\271\214", "\341\271\215", 3},
+ {"\341\271\216", "\341\271\217", 3},
+ {"\341\271\220", "\341\271\221", 3},
+ {"\341\271\222", "\341\271\223", 3},
+ {"\341\271\224", "\341\271\225", 3},
+ {"\341\271\226", "\341\271\227", 3},
+ {"\341\271\230", "\341\271\231", 3},
+ {"\341\271\232", "\341\271\233", 3},
+ {"\341\271\234", "\341\271\235", 3},
+ {"\341\271\236", "\341\271\237", 3},
+ {"\341\271\240", "\341\271\241", 3},
+ {"\341\271\242", "\341\271\243", 3},
+ {"\341\271\244", "\341\271\245", 3},
+ {"\341\271\246", "\341\271\247", 3},
+ {"\341\271\250", "\341\271\251", 3},
+ {"\341\271\252", "\341\271\253", 3},
+ {"\341\271\254", "\341\271\255", 3},
+ {"\341\271\256", "\341\271\257", 3},
+ {"\341\271\260", "\341\271\261", 3},
+ {"\341\271\262", "\341\271\263", 3},
+ {"\341\271\264", "\341\271\265", 3},
+ {"\341\271\266", "\341\271\267", 3},
+ {"\341\271\270", "\341\271\271", 3},
+ {"\341\271\272", "\341\271\273", 3},
+ {"\341\271\274", "\341\271\275", 3},
+ {"\341\271\276", "\341\271\277", 3},
+ {"\341\272\200", "\341\272\201", 3},
+ {"\341\272\202", "\341\272\203", 3},
+ {"\341\272\204", "\341\272\205", 3},
+ {"\341\272\206", "\341\272\207", 3},
+ {"\341\272\210", "\341\272\211", 3},
+ {"\341\272\212", "\341\272\213", 3},
+ {"\341\272\214", "\341\272\215", 3},
+ {"\341\272\216", "\341\272\217", 3},
+ {"\341\272\220", "\341\272\221", 3},
+ {"\341\272\222", "\341\272\223", 3},
+ {"\341\272\224", "\341\272\225", 3},
+ {"\341\272\240", "\341\272\241", 3},
+ {"\341\272\242", "\341\272\243", 3},
+ {"\341\272\244", "\341\272\245", 3},
+ {"\341\272\246", "\341\272\247", 3},
+ {"\341\272\250", "\341\272\251", 3},
+ {"\341\272\252", "\341\272\253", 3},
+ {"\341\272\254", "\341\272\255", 3},
+ {"\341\272\256", "\341\272\257", 3},
+ {"\341\272\260", "\341\272\261", 3},
+ {"\341\272\262", "\341\272\263", 3},
+ {"\341\272\264", "\341\272\265", 3},
+ {"\341\272\266", "\341\272\267", 3},
+ {"\341\272\270", "\341\272\271", 3},
+ {"\341\272\272", "\341\272\273", 3},
+ {"\341\272\274", "\341\272\275", 3},
+ {"\341\272\276", "\341\272\277", 3},
+ {"\341\273\200", "\341\273\201", 3},
+ {"\341\273\202", "\341\273\203", 3},
+ {"\341\273\204", "\341\273\205", 3},
+ {"\341\273\206", "\341\273\207", 3},
+ {"\341\273\210", "\341\273\211", 3},
+ {"\341\273\212", "\341\273\213", 3},
+ {"\341\273\214", "\341\273\215", 3},
+ {"\341\273\216", "\341\273\217", 3},
+ {"\341\273\220", "\341\273\221", 3},
+ {"\341\273\222", "\341\273\223", 3},
+ {"\341\273\224", "\341\273\225", 3},
+ {"\341\273\226", "\341\273\227", 3},
+ {"\341\273\230", "\341\273\231", 3},
+ {"\341\273\232", "\341\273\233", 3},
+ {"\341\273\234", "\341\273\235", 3},
+ {"\341\273\236", "\341\273\237", 3},
+ {"\341\273\240", "\341\273\241", 3},
+ {"\341\273\242", "\341\273\243", 3},
+ {"\341\273\244", "\341\273\245", 3},
+ {"\341\273\246", "\341\273\247", 3},
+ {"\341\273\250", "\341\273\251", 3},
+ {"\341\273\252", "\341\273\253", 3},
+ {"\341\273\254", "\341\273\255", 3},
+ {"\341\273\256", "\341\273\257", 3},
+ {"\341\273\260", "\341\273\261", 3},
+ {"\341\273\262", "\341\273\263", 3},
+ {"\341\273\264", "\341\273\265", 3},
+ {"\341\273\266", "\341\273\267", 3},
+ {"\341\273\270", "\341\273\271", 3},
+ {"\341\274\210", "\341\274\200", 3},
+ {"\341\274\211", "\341\274\201", 3},
+ {"\341\274\212", "\341\274\202", 3},
+ {"\341\274\213", "\341\274\203", 3},
+ {"\341\274\214", "\341\274\204", 3},
+ {"\341\274\215", "\341\274\205", 3},
+ {"\341\274\216", "\341\274\206", 3},
+ {"\341\274\217", "\341\274\207", 3},
+ {"\341\274\230", "\341\274\220", 3},
+ {"\341\274\231", "\341\274\221", 3},
+ {"\341\274\232", "\341\274\222", 3},
+ {"\341\274\233", "\341\274\223", 3},
+ {"\341\274\234", "\341\274\224", 3},
+ {"\341\274\235", "\341\274\225", 3},
+ {"\341\274\250", "\341\274\240", 3},
+ {"\341\274\251", "\341\274\241", 3},
+ {"\341\274\252", "\341\274\242", 3},
+ {"\341\274\253", "\341\274\243", 3},
+ {"\341\274\254", "\341\274\244", 3},
+ {"\341\274\255", "\341\274\245", 3},
+ {"\341\274\256", "\341\274\246", 3},
+ {"\341\274\257", "\341\274\247", 3},
+ {"\341\274\270", "\341\274\260", 3},
+ {"\341\274\271", "\341\274\261", 3},
+ {"\341\274\272", "\341\274\262", 3},
+ {"\341\274\273", "\341\274\263", 3},
+ {"\341\274\274", "\341\274\264", 3},
+ {"\341\274\275", "\341\274\265", 3},
+ {"\341\274\276", "\341\274\266", 3},
+ {"\341\274\277", "\341\274\267", 3},
+ {"\341\275\210", "\341\275\200", 3},
+ {"\341\275\211", "\341\275\201", 3},
+ {"\341\275\212", "\341\275\202", 3},
+ {"\341\275\213", "\341\275\203", 3},
+ {"\341\275\214", "\341\275\204", 3},
+ {"\341\275\215", "\341\275\205", 3},
+ {"\341\275\231", "\341\275\221", 3},
+ {"\341\275\233", "\341\275\223", 3},
+ {"\341\275\235", "\341\275\225", 3},
+ {"\341\275\237", "\341\275\227", 3},
+ {"\341\275\250", "\341\275\240", 3},
+ {"\341\275\251", "\341\275\241", 3},
+ {"\341\275\252", "\341\275\242", 3},
+ {"\341\275\253", "\341\275\243", 3},
+ {"\341\275\254", "\341\275\244", 3},
+ {"\341\275\255", "\341\275\245", 3},
+ {"\341\275\256", "\341\275\246", 3},
+ {"\341\275\257", "\341\275\247", 3},
+ {"\341\276\210", "\341\276\200", 3},
+ {"\341\276\211", "\341\276\201", 3},
+ {"\341\276\212", "\341\276\202", 3},
+ {"\341\276\213", "\341\276\203", 3},
+ {"\341\276\214", "\341\276\204", 3},
+ {"\341\276\215", "\341\276\205", 3},
+ {"\341\276\216", "\341\276\206", 3},
+ {"\341\276\217", "\341\276\207", 3},
+ {"\341\276\230", "\341\276\220", 3},
+ {"\341\276\231", "\341\276\221", 3},
+ {"\341\276\232", "\341\276\222", 3},
+ {"\341\276\233", "\341\276\223", 3},
+ {"\341\276\234", "\341\276\224", 3},
+ {"\341\276\235", "\341\276\225", 3},
+ {"\341\276\236", "\341\276\226", 3},
+ {"\341\276\237", "\341\276\227", 3},
+ {"\341\276\250", "\341\276\240", 3},
+ {"\341\276\251", "\341\276\241", 3},
+ {"\341\276\252", "\341\276\242", 3},
+ {"\341\276\253", "\341\276\243", 3},
+ {"\341\276\254", "\341\276\244", 3},
+ {"\341\276\255", "\341\276\245", 3},
+ {"\341\276\256", "\341\276\246", 3},
+ {"\341\276\257", "\341\276\247", 3},
+ {"\341\276\270", "\341\276\260", 3},
+ {"\341\276\271", "\341\276\261", 3},
+ {"\341\276\272", "\341\275\260", 3},
+ {"\341\276\273", "\341\275\261", 3},
+ {"\341\276\274", "\341\276\263", 3},
+ {"\341\276\276", "\341\276\276", 3},
+ {"\341\277\210", "\341\275\262", 3},
+ {"\341\277\211", "\341\275\263", 3},
+ {"\341\277\212", "\341\275\264", 3},
+ {"\341\277\213", "\341\275\265", 3},
+ {"\341\277\214", "\341\277\203", 3},
+ {"\341\277\230", "\341\277\220", 3},
+ {"\341\277\231", "\341\277\221", 3},
+ {"\341\277\232", "\341\275\266", 3},
+ {"\341\277\233", "\341\275\267", 3},
+ {"\341\277\250", "\341\277\240", 3},
+ {"\341\277\251", "\341\277\241", 3},
+ {"\341\277\252", "\341\275\272", 3},
+ {"\341\277\253", "\341\275\273", 3},
+ {"\341\277\254", "\341\277\245", 3},
+ {"\341\277\270", "\341\275\270", 3},
+ {"\341\277\271", "\341\275\271", 3},
+ {"\341\277\272", "\341\275\274", 3},
+ {"\341\277\273", "\341\275\275", 3},
+ {"\341\277\274", "\341\277\263", 3},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Upper2LowerTbl31[] = {
+ {"\357\274\241", "\357\275\201", 3},
+ {"\357\274\242", "\357\275\202", 3},
+ {"\357\274\243", "\357\275\203", 3},
+ {"\357\274\244", "\357\275\204", 3},
+ {"\357\274\245", "\357\275\205", 3},
+ {"\357\274\246", "\357\275\206", 3},
+ {"\357\274\247", "\357\275\207", 3},
+ {"\357\274\250", "\357\275\210", 3},
+ {"\357\274\251", "\357\275\211", 3},
+ {"\357\274\252", "\357\275\212", 3},
+ {"\357\274\253", "\357\275\213", 3},
+ {"\357\274\254", "\357\275\214", 3},
+ {"\357\274\255", "\357\275\215", 3},
+ {"\357\274\256", "\357\275\216", 3},
+ {"\357\274\257", "\357\275\217", 3},
+ {"\357\274\260", "\357\275\220", 3},
+ {"\357\274\261", "\357\275\221", 3},
+ {"\357\274\262", "\357\275\222", 3},
+ {"\357\274\263", "\357\275\223", 3},
+ {"\357\274\264", "\357\275\224", 3},
+ {"\357\274\265", "\357\275\225", 3},
+ {"\357\274\266", "\357\275\226", 3},
+ {"\357\274\267", "\357\275\227", 3},
+ {"\357\274\270", "\357\275\230", 3},
+ {"\357\274\271", "\357\275\231", 3},
+ {"\357\274\272", "\357\275\232", 3},
+ {NULL, NULL, 0}
+ /* upper, lower */
+};
+
+UpperLowerTbl_t *Upper2LowerTbl2[] = {
+ Upper2LowerTbl20, /* \303 */
+ Upper2LowerTbl21, /* \304 */
+ Upper2LowerTbl22, /* \305 */
+ Upper2LowerTbl23, /* \306 */
+ Upper2LowerTbl24, /* \307 */
+ Upper2LowerTbl25, /* \310 */
+ NULL, /* \311 */
+ NULL, /* \312 */
+ NULL, /* \313 */
+ NULL, /* \314 */
+ NULL, /* \315 */
+ Upper2LowerTbl26, /* \316 */
+ Upper2LowerTbl27, /* \317 */
+ Upper2LowerTbl28, /* \320 */
+ Upper2LowerTbl29, /* \321 */
+ Upper2LowerTbl2a, /* \322 */
+ Upper2LowerTbl2b, /* \323 */
+ Upper2LowerTbl2c, /* \324 */
+ Upper2LowerTbl2d /* \325 */
+};
+
+UpperLowerTbl_t *Upper2LowerTbl3[] = {
+ Upper2LowerTbl30, /* \341 */
+ NULL, /* \342 */
+ NULL, /* \343 */
+ NULL, /* \344 */
+ NULL, /* \345 */
+ NULL, /* \346 */
+ NULL, /* \347 */
+ NULL, /* \350 */
+ NULL, /* \351 */
+ NULL, /* \352 */
+ NULL, /* \353 */
+ NULL, /* \354 */
+ NULL, /* \355 */
+ NULL, /* \356 */
+ Upper2LowerTbl31 /* \357 */
+};
+
+#define UL2S (unsigned char)'\303'
+#define UL2E (unsigned char)'\325'
+#define UL3S (unsigned char)'\341'
+#define UL3E (unsigned char)'\357'
+
+/*
+ * slapi_utf8StrToLower: translate upper-case string to lower-case
+ *
+ * input: a null terminated UTF-8 string
+ * output: a null terminated UTF-8 string which characters are
+ * converted to lower-case; characters which are not
+ * upper-case are copied as is. If it's not considered
+ * a UTF-8 string, NULL is returned.
+ *
+ * Notes: This function takes a string (made of multiple UTF-8 characters)
+ * for the input (not one character as in "tolower").
+ * Output string is allocated in this function, which needs to be
+ * released when it's not needed any more.
+ */
+unsigned char *
+slapi_UTF8STRTOLOWER(char *s)
+{
+ return slapi_utf8StrToLower((unsigned char *)s);
+}
+
+unsigned char *
+slapi_utf8StrToLower(unsigned char *s)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *p, *np, *tail;
+ unsigned char *lp, *lphead;
+ int len, sz;
+
+ if (s == NULL || *s == '\0') {
+ return s;
+ }
+ len = strlen((char *)s);
+ tail = s + len;
+ lphead = lp = (unsigned char *)slapi_ch_malloc(len + 1);
+ p = s;
+ while ((np = (unsigned char *)ldap_utf8next((char *)p)) <= tail) {
+ switch(sz = np - p) {
+ case 1:
+ sprintf((char *)lp, "%c", tolower(*p));
+ break;
+ case 2:
+ if (*p < UL2S || *p > UL2E) { /* out of range */
+ memcpy(lp, p, sz);
+ break;
+ }
+ for (ultp = Upper2LowerTbl2[*p - UL2S];
+ ultp && ultp->upper && memcmp(p, ultp->upper, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memcpy(lp, p, sz);
+ } else if (ultp->upper) { /* matched */
+ memcpy(lp, ultp->lower, ultp->tsz);
+ sz = ultp->tsz;
+ } else {
+ memcpy(lp, p, sz);
+ }
+ break;
+ case 3:
+ if (*p != UL3S && *p != UL3E) { /* out of range */
+ memcpy(lp, p, sz);
+ break;
+ }
+ for (ultp = Upper2LowerTbl3[*p - UL3S];
+ ultp && ultp->upper && memcmp(p, ultp->upper, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memcpy(lp, p, sz);
+ } else if (ultp->upper) { /* matched */
+ memcpy(lp, ultp->lower, sz);
+ } else {
+ memcpy(lp, p, sz);
+ }
+ break;
+ case 4:
+ memcpy(lp, p, sz);
+ break;
+ default: /* not UTF-8 */
+ slapi_ch_free((void **)&lphead);
+ return NULL;
+ }
+ lp += sz;
+ p = np;
+ if (p == tail) {
+ break;
+ }
+ }
+ *lp = '\0';
+ return lphead;
+}
+
+/*
+ * slapi_utf8ToLower: translate upper-case character to lower-case
+ *
+ * input: a UTF-8 character (s)
+ * output: a UTF-8 character which is converted to lower-case (d)
+ * length (in bytes) of input character (ssz) and
+ * output character (dsz)
+ *
+ * Notes: This function takes a UTF-8 character (could be multiple bytes)
+ * for the input. Memory for the output character is NOT allocated
+ * in this function, caller should have allocated it (d).
+ * "memmove" is used since (s) and (d) are overlapped.
+ */
+void
+slapi_UTF8TOLOWER(char *s, char *d, int *ssz, int *dsz)
+{
+ slapi_utf8ToLower((unsigned char *)s, (unsigned char *)d, ssz, dsz);
+ return;
+}
+
+void
+slapi_utf8ToLower(unsigned char *s, unsigned char *d, int *ssz, int *dsz)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *tail;
+
+ if (s == NULL || *s == '\0') {
+ *ssz = *dsz = 0;
+ return;
+ }
+ if (!(*s & 0x80)) { /* ASCII */
+ *dsz = *ssz = 1;
+ *d = tolower(*s);
+ return;
+ }
+ tail = (unsigned char *)ldap_utf8next((char *)s);
+ *dsz = *ssz = tail - s;
+ switch(*ssz) {
+ case 1: /* ASCII */
+ *d = tolower(*s);
+ break;
+ case 2: /* 2 bytes */
+ if (*s < UL2S || *s > UL2E) { /* out of range */
+ memmove(d, s, *ssz);
+ break;
+ }
+ for (ultp = Upper2LowerTbl2[*s - UL2S];
+ ultp && ultp->upper && memcmp(s, ultp->upper, *ssz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memmove(d, s, *ssz);
+ } else if (ultp->upper) { /* matched */
+ memmove(d, ultp->lower, ultp->tsz);
+ *dsz = ultp->tsz;
+ } else {
+ memmove(d, s, *ssz);
+ }
+ break;
+ case 3: /* 3 bytes */
+ if (*s != UL3S && *s != UL3E) { /* out of range */
+ memmove(d, s, *ssz);
+ break;
+ }
+ for (ultp = Upper2LowerTbl3[*s - UL3S];
+ ultp && ultp->upper && memcmp(s, ultp->upper, *ssz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memmove(d, s, *ssz);
+ } else if (ultp->upper) { /* matched */
+ memmove(d, ultp->lower, *ssz);
+ } else {
+ memmove(d, s, *ssz);
+ }
+ break;
+ }
+ return;
+}
+
+/*
+ * slapi_utf8isUpper: tests for a character that is a upper-case letter in
+ * UTF-8
+ *
+ * input: a UTF-8 character (could be multi-byte)
+ * output: 1 if the character is a upper-case letter
+ * 0 if the character is not a upper-case letter
+ */
+int
+slapi_UTF8ISUPPER(char *s)
+{
+ return slapi_utf8isUpper((unsigned char *)s);
+}
+
+int
+slapi_utf8isUpper(unsigned char *s)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *next;
+ int sz;
+
+ if (s == NULL || *s == '\0') {
+ return 0;
+ }
+ if (!(*s & 0x80)) { /* ASCII */
+ return isupper(*s);
+ }
+ next = (unsigned char *)ldap_utf8next((char *)s);
+ switch(sz = next - s) {
+ case 1: /* ASCII */
+ return isupper(*s);
+ case 2:
+ if (*s < UL2S || *s > UL2E) { /* out of range */
+ return 0;
+ }
+ for (ultp = Upper2LowerTbl2[*s - UL2S];
+ ultp && ultp->upper && memcmp(s, ultp->upper, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ return 0;
+ } else if (ultp->upper) { /* matched */
+ return 1;
+ } else {
+ return 0;
+ }
+ case 3:
+ if (*s < UL3S || *s > UL3E) { /* out of range */
+ return 0;
+ }
+ for (ultp = Upper2LowerTbl3[*s - UL3S];
+ ultp && ultp->upper && memcmp(s, ultp->upper, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ return 0;
+ } else if (ultp->upper) { /* matched */
+ return 1;
+ } else {
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+/*
+ * Lower2Upper Tables: sorted by lower characters
+ */
+UpperLowerTbl_t Lower2UpperTbl20[] = {
+ /* upper, lower */
+ {"\303\200", "\303\240", 2},
+ {"\303\201", "\303\241", 2},
+ {"\303\202", "\303\242", 2},
+ {"\303\203", "\303\243", 2},
+ {"\303\204", "\303\244", 2},
+ {"\303\205", "\303\245", 2},
+ {"\303\206", "\303\246", 2},
+ {"\303\207", "\303\247", 2},
+ {"\303\210", "\303\250", 2},
+ {"\303\211", "\303\251", 2},
+ {"\303\212", "\303\252", 2},
+ {"\303\213", "\303\253", 2},
+ {"\303\214", "\303\254", 2},
+ {"\303\215", "\303\255", 2},
+ {"\303\216", "\303\256", 2},
+ {"\303\217", "\303\257", 2},
+ {"\303\220", "\303\260", 2},
+ {"\303\221", "\303\261", 2},
+ {"\303\222", "\303\262", 2},
+ {"\303\223", "\303\263", 2},
+ {"\303\224", "\303\264", 2},
+ {"\303\225", "\303\265", 2},
+ {"\303\226", "\303\266", 2},
+ {"\303\230", "\303\270", 2},
+ {"\303\231", "\303\271", 2},
+ {"\303\232", "\303\272", 2},
+ {"\303\233", "\303\273", 2},
+ {"\303\234", "\303\274", 2},
+ {"\303\235", "\303\275", 2},
+ {"\303\236", "\303\276", 2},
+ {"\305\270", "\303\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl21[] = {
+ {"\304\200", "\304\201", 2},
+ {"\304\202", "\304\203", 2},
+ {"\304\204", "\304\205", 2},
+ {"\304\206", "\304\207", 2},
+ {"\304\210", "\304\211", 2},
+ {"\304\212", "\304\213", 2},
+ {"\304\214", "\304\215", 2},
+ {"\304\216", "\304\217", 2},
+ {"\304\220", "\304\221", 2},
+ {"\304\222", "\304\223", 2},
+ {"\304\224", "\304\225", 2},
+ {"\304\226", "\304\227", 2},
+ {"\304\230", "\304\231", 2},
+ {"\304\232", "\304\233", 2},
+ {"\304\234", "\304\235", 2},
+ {"\304\236", "\304\237", 2},
+ {"\304\240", "\304\241", 2},
+ {"\304\242", "\304\243", 2},
+ {"\304\244", "\304\245", 2},
+ {"\304\246", "\304\247", 2},
+ {"\304\250", "\304\251", 2},
+ {"\304\252", "\304\253", 2},
+ {"\304\254", "\304\255", 2},
+ {"\304\256", "\304\257", 2},
+ {"\111", "\304\261", 1},
+ {"\304\262", "\304\263", 2},
+ {"\304\264", "\304\265", 2},
+ {"\304\266", "\304\267", 2},
+ {"\304\271", "\304\272", 2},
+ {"\304\273", "\304\274", 2},
+ {"\304\275", "\304\276", 2},
+ {NULL, NULL}
+};
+
+UpperLowerTbl_t Lower2UpperTbl22[] = {
+ {"\304\277", "\305\200", 2},
+ {"\305\201", "\305\202", 2},
+ {"\305\203", "\305\204", 2},
+ {"\305\205", "\305\206", 2},
+ {"\305\207", "\305\210", 2},
+ {"\305\212", "\305\213", 2},
+ {"\305\214", "\305\215", 2},
+ {"\305\216", "\305\217", 2},
+ {"\305\220", "\305\221", 2},
+ {"\305\222", "\305\223", 2},
+ {"\305\224", "\305\225", 2},
+ {"\305\226", "\305\227", 2},
+ {"\305\230", "\305\231", 2},
+ {"\305\232", "\305\233", 2},
+ {"\305\234", "\305\235", 2},
+ {"\305\236", "\305\237", 2},
+ {"\305\240", "\305\241", 2},
+ {"\305\242", "\305\243", 2},
+ {"\305\244", "\305\245", 2},
+ {"\305\246", "\305\247", 2},
+ {"\305\250", "\305\251", 2},
+ {"\305\252", "\305\253", 2},
+ {"\305\254", "\305\255", 2},
+ {"\305\256", "\305\257", 2},
+ {"\305\260", "\305\261", 2},
+ {"\305\262", "\305\263", 2},
+ {"\305\264", "\305\265", 2},
+ {"\305\266", "\305\267", 2},
+ {"\305\271", "\305\272", 2},
+ {"\305\273", "\305\274", 2},
+ {"\305\275", "\305\276", 2},
+ {"\123", "\305\277", 1},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl23[] = {
+ {"\306\202", "\306\203", 2},
+ {"\306\204", "\306\205", 2},
+ {"\306\207", "\306\210", 2},
+ {"\306\213", "\306\214", 2},
+ {"\306\221", "\306\222", 2},
+ {"\306\230", "\306\231", 2},
+ {"\306\240", "\306\241", 2},
+ {"\306\242", "\306\243", 2},
+ {"\306\244", "\306\245", 2},
+ {"\306\247", "\306\250", 2},
+ {"\306\254", "\306\255", 2},
+ {"\306\257", "\306\260", 2},
+ {"\306\263", "\306\264", 2},
+ {"\306\265", "\306\266", 2},
+ {"\306\270", "\306\271", 2},
+ {"\306\274", "\306\275", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl24[] = {
+ {"\307\204", "\307\206", 2},
+ {"\307\207", "\307\211", 2},
+ {"\307\212", "\307\214", 2},
+ {"\307\215", "\307\216", 2},
+ {"\307\217", "\307\220", 2},
+ {"\307\221", "\307\222", 2},
+ {"\307\223", "\307\224", 2},
+ {"\307\225", "\307\226", 2},
+ {"\307\227", "\307\230", 2},
+ {"\307\231", "\307\232", 2},
+ {"\307\233", "\307\234", 2},
+ {"\307\236", "\307\237", 2},
+ {"\307\240", "\307\241", 2},
+ {"\307\242", "\307\243", 2},
+ {"\307\244", "\307\245", 2},
+ {"\307\246", "\307\247", 2},
+ {"\307\250", "\307\251", 2},
+ {"\307\252", "\307\253", 2},
+ {"\307\254", "\307\255", 2},
+ {"\307\256", "\307\257", 2},
+ {"\307\261", "\307\263", 2},
+ {"\307\264", "\307\265", 2},
+ {"\307\272", "\307\273", 2},
+ {"\307\274", "\307\275", 2},
+ {"\307\276", "\307\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl25[] = {
+ {"\310\200", "\310\201", 2},
+ {"\310\202", "\310\203", 2},
+ {"\310\204", "\310\205", 2},
+ {"\310\206", "\310\207", 2},
+ {"\310\210", "\310\211", 2},
+ {"\310\212", "\310\213", 2},
+ {"\310\214", "\310\215", 2},
+ {"\310\216", "\310\217", 2},
+ {"\310\220", "\310\221", 2},
+ {"\310\222", "\310\223", 2},
+ {"\310\224", "\310\225", 2},
+ {"\310\226", "\310\227", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl26[] = {
+ {"\306\201", "\311\223", 2},
+ {"\306\206", "\311\224", 2},
+ {"\306\211", "\311\226", 2},
+ {"\306\212", "\311\227", 2},
+ {"\306\216", "\311\230", 2},
+ {"\306\217", "\311\231", 2},
+ {"\306\220", "\311\233", 2},
+ {"\306\223", "\311\240", 2},
+ {"\306\224", "\311\243", 2},
+ {"\306\227", "\311\250", 2},
+ {"\306\226", "\311\251", 2},
+ {"\306\234", "\311\257", 2},
+ {"\306\235", "\311\262", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl27[] = {
+ {"\306\251", "\312\203", 2},
+ {"\306\256", "\312\210", 2},
+ {"\306\261", "\312\212", 2},
+ {"\306\262", "\312\213", 2},
+ {"\306\267", "\312\222", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl28[] = {
+ {"\316\206", "\316\254", 2},
+ {"\316\210", "\316\255", 2},
+ {"\316\211", "\316\256", 2},
+ {"\316\212", "\316\257", 2},
+ {"\316\221", "\316\261", 2},
+ {"\316\222", "\316\262", 2},
+ {"\316\223", "\316\263", 2},
+ {"\316\224", "\316\264", 2},
+ {"\316\225", "\316\265", 2},
+ {"\316\226", "\316\266", 2},
+ {"\316\227", "\316\267", 2},
+ {"\316\230", "\316\270", 2},
+ {"\316\231", "\316\271", 2},
+ {"\316\232", "\316\272", 2},
+ {"\316\233", "\316\273", 2},
+ {"\316\234", "\316\274", 2},
+ {"\316\235", "\316\275", 2},
+ {"\316\236", "\316\276", 2},
+ {"\316\237", "\316\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl29[] = {
+ {"\316\240", "\317\200", 2},
+ {"\316\241", "\317\201", 2},
+ {"\316\243", "\317\202", 2},
+ {"\316\243", "\317\203", 2},
+ {"\316\244", "\317\204", 2},
+ {"\316\245", "\317\205", 2},
+ {"\316\246", "\317\206", 2},
+ {"\316\247", "\317\207", 2},
+ {"\316\250", "\317\210", 2},
+ {"\316\251", "\317\211", 2},
+ {"\316\252", "\317\212", 2},
+ {"\316\253", "\317\213", 2},
+ {"\316\214", "\317\214", 2},
+ {"\316\216", "\317\215", 2},
+ {"\316\217", "\317\216", 2},
+ {"\316\222", "\317\220", 2},
+ {"\316\230", "\317\221", 2},
+ {"\316\246", "\317\225", 2},
+ {"\316\240", "\317\226", 2},
+ {"\317\242", "\317\243", 2},
+ {"\317\244", "\317\245", 2},
+ {"\317\246", "\317\247", 2},
+ {"\317\250", "\317\251", 2},
+ {"\317\252", "\317\253", 2},
+ {"\317\254", "\317\255", 2},
+ {"\317\256", "\317\257", 2},
+ {"\316\232", "\317\260", 2},
+ {"\316\241", "\317\261", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2a[] = {
+ {"\320\220", "\320\260", 2},
+ {"\320\221", "\320\261", 2},
+ {"\320\222", "\320\262", 2},
+ {"\320\223", "\320\263", 2},
+ {"\320\224", "\320\264", 2},
+ {"\320\225", "\320\265", 2},
+ {"\320\226", "\320\266", 2},
+ {"\320\227", "\320\267", 2},
+ {"\320\230", "\320\270", 2},
+ {"\320\231", "\320\271", 2},
+ {"\320\232", "\320\272", 2},
+ {"\320\233", "\320\273", 2},
+ {"\320\234", "\320\274", 2},
+ {"\320\235", "\320\275", 2},
+ {"\320\236", "\320\276", 2},
+ {"\320\237", "\320\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2b[] = {
+ {"\320\240", "\321\200", 2},
+ {"\320\241", "\321\201", 2},
+ {"\320\242", "\321\202", 2},
+ {"\320\243", "\321\203", 2},
+ {"\320\244", "\321\204", 2},
+ {"\320\245", "\321\205", 2},
+ {"\320\246", "\321\206", 2},
+ {"\320\247", "\321\207", 2},
+ {"\320\250", "\321\210", 2},
+ {"\320\251", "\321\211", 2},
+ {"\320\252", "\321\212", 2},
+ {"\320\253", "\321\213", 2},
+ {"\320\254", "\321\214", 2},
+ {"\320\255", "\321\215", 2},
+ {"\320\256", "\321\216", 2},
+ {"\320\257", "\321\217", 2},
+ {"\320\201", "\321\221", 2},
+ {"\320\202", "\321\222", 2},
+ {"\320\203", "\321\223", 2},
+ {"\320\204", "\321\224", 2},
+ {"\320\205", "\321\225", 2},
+ {"\320\206", "\321\226", 2},
+ {"\320\207", "\321\227", 2},
+ {"\320\210", "\321\230", 2},
+ {"\320\211", "\321\231", 2},
+ {"\320\212", "\321\232", 2},
+ {"\320\213", "\321\233", 2},
+ {"\320\214", "\321\234", 2},
+ {"\320\216", "\321\236", 2},
+ {"\320\217", "\321\237", 2},
+ {"\321\240", "\321\241", 2},
+ {"\321\242", "\321\243", 2},
+ {"\321\244", "\321\245", 2},
+ {"\321\246", "\321\247", 2},
+ {"\321\250", "\321\251", 2},
+ {"\321\252", "\321\253", 2},
+ {"\321\254", "\321\255", 2},
+ {"\321\256", "\321\257", 2},
+ {"\321\260", "\321\261", 2},
+ {"\321\262", "\321\263", 2},
+ {"\321\264", "\321\265", 2},
+ {"\321\266", "\321\267", 2},
+ {"\321\270", "\321\271", 2},
+ {"\321\272", "\321\273", 2},
+ {"\321\274", "\321\275", 2},
+ {"\321\276", "\321\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2c[] = {
+ {"\322\200", "\322\201", 2},
+ {"\322\220", "\322\221", 2},
+ {"\322\222", "\322\223", 2},
+ {"\322\224", "\322\225", 2},
+ {"\322\226", "\322\227", 2},
+ {"\322\230", "\322\231", 2},
+ {"\322\232", "\322\233", 2},
+ {"\322\234", "\322\235", 2},
+ {"\322\236", "\322\237", 2},
+ {"\322\240", "\322\241", 2},
+ {"\322\242", "\322\243", 2},
+ {"\322\244", "\322\245", 2},
+ {"\322\246", "\322\247", 2},
+ {"\322\250", "\322\251", 2},
+ {"\322\252", "\322\253", 2},
+ {"\322\254", "\322\255", 2},
+ {"\322\256", "\322\257", 2},
+ {"\322\260", "\322\261", 2},
+ {"\322\262", "\322\263", 2},
+ {"\322\264", "\322\265", 2},
+ {"\322\266", "\322\267", 2},
+ {"\322\270", "\322\271", 2},
+ {"\322\272", "\322\273", 2},
+ {"\322\274", "\322\275", 2},
+ {"\322\276", "\322\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2d[] = {
+ {"\323\201", "\323\202", 2},
+ {"\323\203", "\323\204", 2},
+ {"\323\207", "\323\210", 2},
+ {"\323\213", "\323\214", 2},
+ {"\323\220", "\323\221", 2},
+ {"\323\222", "\323\223", 2},
+ {"\323\224", "\323\225", 2},
+ {"\323\226", "\323\227", 2},
+ {"\323\230", "\323\231", 2},
+ {"\323\232", "\323\233", 2},
+ {"\323\234", "\323\235", 2},
+ {"\323\236", "\323\237", 2},
+ {"\323\240", "\323\241", 2},
+ {"\323\242", "\323\243", 2},
+ {"\323\244", "\323\245", 2},
+ {"\323\246", "\323\247", 2},
+ {"\323\250", "\323\251", 2},
+ {"\323\252", "\323\253", 2},
+ {"\323\256", "\323\257", 2},
+ {"\323\260", "\323\261", 2},
+ {"\323\262", "\323\263", 2},
+ {"\323\264", "\323\265", 2},
+ {"\323\270", "\323\271", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2e[] = {
+ {"\324\261", "\325\241", 2},
+ {"\324\262", "\325\242", 2},
+ {"\324\263", "\325\243", 2},
+ {"\324\264", "\325\244", 2},
+ {"\324\265", "\325\245", 2},
+ {"\324\266", "\325\246", 2},
+ {"\324\267", "\325\247", 2},
+ {"\324\270", "\325\250", 2},
+ {"\324\271", "\325\251", 2},
+ {"\324\272", "\325\252", 2},
+ {"\324\273", "\325\253", 2},
+ {"\324\274", "\325\254", 2},
+ {"\324\275", "\325\255", 2},
+ {"\324\276", "\325\256", 2},
+ {"\324\277", "\325\257", 2},
+ {"\325\200", "\325\260", 2},
+ {"\325\201", "\325\261", 2},
+ {"\325\202", "\325\262", 2},
+ {"\325\203", "\325\263", 2},
+ {"\325\204", "\325\264", 2},
+ {"\325\205", "\325\265", 2},
+ {"\325\206", "\325\266", 2},
+ {"\325\207", "\325\267", 2},
+ {"\325\210", "\325\270", 2},
+ {"\325\211", "\325\271", 2},
+ {"\325\212", "\325\272", 2},
+ {"\325\213", "\325\273", 2},
+ {"\325\214", "\325\274", 2},
+ {"\325\215", "\325\275", 2},
+ {"\325\216", "\325\276", 2},
+ {"\325\217", "\325\277", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl2f[] = {
+ {"\325\220", "\326\200", 2},
+ {"\325\221", "\326\201", 2},
+ {"\325\222", "\326\202", 2},
+ {"\325\223", "\326\203", 2},
+ {"\325\224", "\326\204", 2},
+ {"\325\225", "\326\205", 2},
+ {"\325\226", "\326\206", 2},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl30[] = {
+ {"\341\202\240", "\341\203\220", 3},
+ {"\341\202\241", "\341\203\221", 3},
+ {"\341\202\242", "\341\203\222", 3},
+ {"\341\202\243", "\341\203\223", 3},
+ {"\341\202\244", "\341\203\224", 3},
+ {"\341\202\245", "\341\203\225", 3},
+ {"\341\202\246", "\341\203\226", 3},
+ {"\341\202\247", "\341\203\227", 3},
+ {"\341\202\250", "\341\203\230", 3},
+ {"\341\202\251", "\341\203\231", 3},
+ {"\341\202\252", "\341\203\232", 3},
+ {"\341\202\253", "\341\203\233", 3},
+ {"\341\202\254", "\341\203\234", 3},
+ {"\341\202\255", "\341\203\235", 3},
+ {"\341\202\256", "\341\203\236", 3},
+ {"\341\202\257", "\341\203\237", 3},
+ {"\341\202\260", "\341\203\240", 3},
+ {"\341\202\261", "\341\203\241", 3},
+ {"\341\202\262", "\341\203\242", 3},
+ {"\341\202\263", "\341\203\243", 3},
+ {"\341\202\264", "\341\203\244", 3},
+ {"\341\202\265", "\341\203\245", 3},
+ {"\341\202\266", "\341\203\246", 3},
+ {"\341\202\267", "\341\203\247", 3},
+ {"\341\202\270", "\341\203\250", 3},
+ {"\341\202\271", "\341\203\251", 3},
+ {"\341\202\272", "\341\203\252", 3},
+ {"\341\202\273", "\341\203\253", 3},
+ {"\341\202\274", "\341\203\254", 3},
+ {"\341\202\275", "\341\203\255", 3},
+ {"\341\202\276", "\341\203\256", 3},
+ {"\341\202\277", "\341\203\257", 3},
+ {"\341\203\200", "\341\203\260", 3},
+ {"\341\203\201", "\341\203\261", 3},
+ {"\341\203\202", "\341\203\262", 3},
+ {"\341\203\203", "\341\203\263", 3},
+ {"\341\203\204", "\341\203\264", 3},
+ {"\341\203\205", "\341\203\265", 3},
+ {"\341\270\200", "\341\270\201", 3},
+ {"\341\270\202", "\341\270\203", 3},
+ {"\341\270\204", "\341\270\205", 3},
+ {"\341\270\206", "\341\270\207", 3},
+ {"\341\270\210", "\341\270\211", 3},
+ {"\341\270\212", "\341\270\213", 3},
+ {"\341\270\214", "\341\270\215", 3},
+ {"\341\270\216", "\341\270\217", 3},
+ {"\341\270\220", "\341\270\221", 3},
+ {"\341\270\222", "\341\270\223", 3},
+ {"\341\270\224", "\341\270\225", 3},
+ {"\341\270\226", "\341\270\227", 3},
+ {"\341\270\230", "\341\270\231", 3},
+ {"\341\270\232", "\341\270\233", 3},
+ {"\341\270\234", "\341\270\235", 3},
+ {"\341\270\236", "\341\270\237", 3},
+ {"\341\270\240", "\341\270\241", 3},
+ {"\341\270\242", "\341\270\243", 3},
+ {"\341\270\244", "\341\270\245", 3},
+ {"\341\270\246", "\341\270\247", 3},
+ {"\341\270\250", "\341\270\251", 3},
+ {"\341\270\252", "\341\270\253", 3},
+ {"\341\270\254", "\341\270\255", 3},
+ {"\341\270\256", "\341\270\257", 3},
+ {"\341\270\260", "\341\270\261", 3},
+ {"\341\270\262", "\341\270\263", 3},
+ {"\341\270\264", "\341\270\265", 3},
+ {"\341\270\266", "\341\270\267", 3},
+ {"\341\270\270", "\341\270\271", 3},
+ {"\341\270\272", "\341\270\273", 3},
+ {"\341\270\274", "\341\270\275", 3},
+ {"\341\270\276", "\341\270\277", 3},
+ {"\341\271\200", "\341\271\201", 3},
+ {"\341\271\202", "\341\271\203", 3},
+ {"\341\271\204", "\341\271\205", 3},
+ {"\341\271\206", "\341\271\207", 3},
+ {"\341\271\210", "\341\271\211", 3},
+ {"\341\271\212", "\341\271\213", 3},
+ {"\341\271\214", "\341\271\215", 3},
+ {"\341\271\216", "\341\271\217", 3},
+ {"\341\271\220", "\341\271\221", 3},
+ {"\341\271\222", "\341\271\223", 3},
+ {"\341\271\224", "\341\271\225", 3},
+ {"\341\271\226", "\341\271\227", 3},
+ {"\341\271\230", "\341\271\231", 3},
+ {"\341\271\232", "\341\271\233", 3},
+ {"\341\271\234", "\341\271\235", 3},
+ {"\341\271\236", "\341\271\237", 3},
+ {"\341\271\240", "\341\271\241", 3},
+ {"\341\271\242", "\341\271\243", 3},
+ {"\341\271\244", "\341\271\245", 3},
+ {"\341\271\246", "\341\271\247", 3},
+ {"\341\271\250", "\341\271\251", 3},
+ {"\341\271\252", "\341\271\253", 3},
+ {"\341\271\254", "\341\271\255", 3},
+ {"\341\271\256", "\341\271\257", 3},
+ {"\341\271\260", "\341\271\261", 3},
+ {"\341\271\262", "\341\271\263", 3},
+ {"\341\271\264", "\341\271\265", 3},
+ {"\341\271\266", "\341\271\267", 3},
+ {"\341\271\270", "\341\271\271", 3},
+ {"\341\271\272", "\341\271\273", 3},
+ {"\341\271\274", "\341\271\275", 3},
+ {"\341\271\276", "\341\271\277", 3},
+ {"\341\272\200", "\341\272\201", 3},
+ {"\341\272\202", "\341\272\203", 3},
+ {"\341\272\204", "\341\272\205", 3},
+ {"\341\272\206", "\341\272\207", 3},
+ {"\341\272\210", "\341\272\211", 3},
+ {"\341\272\212", "\341\272\213", 3},
+ {"\341\272\214", "\341\272\215", 3},
+ {"\341\272\216", "\341\272\217", 3},
+ {"\341\272\220", "\341\272\221", 3},
+ {"\341\272\222", "\341\272\223", 3},
+ {"\341\272\224", "\341\272\225", 3},
+ {"\341\272\240", "\341\272\241", 3},
+ {"\341\272\242", "\341\272\243", 3},
+ {"\341\272\244", "\341\272\245", 3},
+ {"\341\272\246", "\341\272\247", 3},
+ {"\341\272\250", "\341\272\251", 3},
+ {"\341\272\252", "\341\272\253", 3},
+ {"\341\272\254", "\341\272\255", 3},
+ {"\341\272\256", "\341\272\257", 3},
+ {"\341\272\260", "\341\272\261", 3},
+ {"\341\272\262", "\341\272\263", 3},
+ {"\341\272\264", "\341\272\265", 3},
+ {"\341\272\266", "\341\272\267", 3},
+ {"\341\272\270", "\341\272\271", 3},
+ {"\341\272\272", "\341\272\273", 3},
+ {"\341\272\274", "\341\272\275", 3},
+ {"\341\272\276", "\341\272\277", 3},
+ {"\341\273\200", "\341\273\201", 3},
+ {"\341\273\202", "\341\273\203", 3},
+ {"\341\273\204", "\341\273\205", 3},
+ {"\341\273\206", "\341\273\207", 3},
+ {"\341\273\210", "\341\273\211", 3},
+ {"\341\273\212", "\341\273\213", 3},
+ {"\341\273\214", "\341\273\215", 3},
+ {"\341\273\216", "\341\273\217", 3},
+ {"\341\273\220", "\341\273\221", 3},
+ {"\341\273\222", "\341\273\223", 3},
+ {"\341\273\224", "\341\273\225", 3},
+ {"\341\273\226", "\341\273\227", 3},
+ {"\341\273\230", "\341\273\231", 3},
+ {"\341\273\232", "\341\273\233", 3},
+ {"\341\273\234", "\341\273\235", 3},
+ {"\341\273\236", "\341\273\237", 3},
+ {"\341\273\240", "\341\273\241", 3},
+ {"\341\273\242", "\341\273\243", 3},
+ {"\341\273\244", "\341\273\245", 3},
+ {"\341\273\246", "\341\273\247", 3},
+ {"\341\273\250", "\341\273\251", 3},
+ {"\341\273\252", "\341\273\253", 3},
+ {"\341\273\254", "\341\273\255", 3},
+ {"\341\273\256", "\341\273\257", 3},
+ {"\341\273\260", "\341\273\261", 3},
+ {"\341\273\262", "\341\273\263", 3},
+ {"\341\273\264", "\341\273\265", 3},
+ {"\341\273\266", "\341\273\267", 3},
+ {"\341\273\270", "\341\273\271", 3},
+ {"\341\274\210", "\341\274\200", 3},
+ {"\341\274\211", "\341\274\201", 3},
+ {"\341\274\212", "\341\274\202", 3},
+ {"\341\274\213", "\341\274\203", 3},
+ {"\341\274\214", "\341\274\204", 3},
+ {"\341\274\215", "\341\274\205", 3},
+ {"\341\274\216", "\341\274\206", 3},
+ {"\341\274\217", "\341\274\207", 3},
+ {"\341\274\230", "\341\274\220", 3},
+ {"\341\274\231", "\341\274\221", 3},
+ {"\341\274\232", "\341\274\222", 3},
+ {"\341\274\233", "\341\274\223", 3},
+ {"\341\274\234", "\341\274\224", 3},
+ {"\341\274\235", "\341\274\225", 3},
+ {"\341\274\250", "\341\274\240", 3},
+ {"\341\274\251", "\341\274\241", 3},
+ {"\341\274\252", "\341\274\242", 3},
+ {"\341\274\253", "\341\274\243", 3},
+ {"\341\274\254", "\341\274\244", 3},
+ {"\341\274\255", "\341\274\245", 3},
+ {"\341\274\256", "\341\274\246", 3},
+ {"\341\274\257", "\341\274\247", 3},
+ {"\341\274\270", "\341\274\260", 3},
+ {"\341\274\271", "\341\274\261", 3},
+ {"\341\274\272", "\341\274\262", 3},
+ {"\341\274\273", "\341\274\263", 3},
+ {"\341\274\274", "\341\274\264", 3},
+ {"\341\274\275", "\341\274\265", 3},
+ {"\341\274\276", "\341\274\266", 3},
+ {"\341\274\277", "\341\274\267", 3},
+ {"\341\275\210", "\341\275\200", 3},
+ {"\341\275\211", "\341\275\201", 3},
+ {"\341\275\212", "\341\275\202", 3},
+ {"\341\275\213", "\341\275\203", 3},
+ {"\341\275\214", "\341\275\204", 3},
+ {"\341\275\215", "\341\275\205", 3},
+ {"\341\275\231", "\341\275\221", 3},
+ {"\341\275\233", "\341\275\223", 3},
+ {"\341\275\235", "\341\275\225", 3},
+ {"\341\275\237", "\341\275\227", 3},
+ {"\341\275\250", "\341\275\240", 3},
+ {"\341\275\251", "\341\275\241", 3},
+ {"\341\275\252", "\341\275\242", 3},
+ {"\341\275\253", "\341\275\243", 3},
+ {"\341\275\254", "\341\275\244", 3},
+ {"\341\275\255", "\341\275\245", 3},
+ {"\341\275\256", "\341\275\246", 3},
+ {"\341\275\257", "\341\275\247", 3},
+ {"\341\276\272", "\341\275\260", 3},
+ {"\341\276\273", "\341\275\261", 3},
+ {"\341\277\210", "\341\275\262", 3},
+ {"\341\277\211", "\341\275\263", 3},
+ {"\341\277\212", "\341\275\264", 3},
+ {"\341\277\213", "\341\275\265", 3},
+ {"\341\277\232", "\341\275\266", 3},
+ {"\341\277\233", "\341\275\267", 3},
+ {"\341\277\270", "\341\275\270", 3},
+ {"\341\277\271", "\341\275\271", 3},
+ {"\341\277\252", "\341\275\272", 3},
+ {"\341\277\253", "\341\275\273", 3},
+ {"\341\277\272", "\341\275\274", 3},
+ {"\341\277\273", "\341\275\275", 3},
+ {"\341\276\210", "\341\276\200", 3},
+ {"\341\276\211", "\341\276\201", 3},
+ {"\341\276\212", "\341\276\202", 3},
+ {"\341\276\213", "\341\276\203", 3},
+ {"\341\276\214", "\341\276\204", 3},
+ {"\341\276\215", "\341\276\205", 3},
+ {"\341\276\216", "\341\276\206", 3},
+ {"\341\276\217", "\341\276\207", 3},
+ {"\341\276\230", "\341\276\220", 3},
+ {"\341\276\231", "\341\276\221", 3},
+ {"\341\276\232", "\341\276\222", 3},
+ {"\341\276\233", "\341\276\223", 3},
+ {"\341\276\234", "\341\276\224", 3},
+ {"\341\276\235", "\341\276\225", 3},
+ {"\341\276\236", "\341\276\226", 3},
+ {"\341\276\237", "\341\276\227", 3},
+ {"\341\276\250", "\341\276\240", 3},
+ {"\341\276\251", "\341\276\241", 3},
+ {"\341\276\252", "\341\276\242", 3},
+ {"\341\276\253", "\341\276\243", 3},
+ {"\341\276\254", "\341\276\244", 3},
+ {"\341\276\255", "\341\276\245", 3},
+ {"\341\276\256", "\341\276\246", 3},
+ {"\341\276\257", "\341\276\247", 3},
+ {"\341\276\270", "\341\276\260", 3},
+ {"\341\276\271", "\341\276\261", 3},
+ {"\341\276\274", "\341\276\263", 3},
+ {"\341\277\214", "\341\277\203", 3},
+ {"\341\277\230", "\341\277\220", 3},
+ {"\341\277\231", "\341\277\221", 3},
+ {"\341\277\250", "\341\277\240", 3},
+ {"\341\277\251", "\341\277\241", 3},
+ {"\341\277\254", "\341\277\245", 3},
+ {"\341\277\274", "\341\277\263", 3},
+ {NULL, NULL, 0}
+};
+
+UpperLowerTbl_t Lower2UpperTbl31[] = {
+ {"\357\274\241", "\357\275\201", 3},
+ {"\357\274\242", "\357\275\202", 3},
+ {"\357\274\243", "\357\275\203", 3},
+ {"\357\274\244", "\357\275\204", 3},
+ {"\357\274\245", "\357\275\205", 3},
+ {"\357\274\246", "\357\275\206", 3},
+ {"\357\274\247", "\357\275\207", 3},
+ {"\357\274\250", "\357\275\210", 3},
+ {"\357\274\251", "\357\275\211", 3},
+ {"\357\274\252", "\357\275\212", 3},
+ {"\357\274\253", "\357\275\213", 3},
+ {"\357\274\254", "\357\275\214", 3},
+ {"\357\274\255", "\357\275\215", 3},
+ {"\357\274\256", "\357\275\216", 3},
+ {"\357\274\257", "\357\275\217", 3},
+ {"\357\274\260", "\357\275\220", 3},
+ {"\357\274\261", "\357\275\221", 3},
+ {"\357\274\262", "\357\275\222", 3},
+ {"\357\274\263", "\357\275\223", 3},
+ {"\357\274\264", "\357\275\224", 3},
+ {"\357\274\265", "\357\275\225", 3},
+ {"\357\274\266", "\357\275\226", 3},
+ {"\357\274\267", "\357\275\227", 3},
+ {"\357\274\270", "\357\275\230", 3},
+ {"\357\274\271", "\357\275\231", 3},
+ {"\357\274\272", "\357\275\232", 3},
+ {NULL, NULL, 0}
+ /* upper, lower */
+};
+
+UpperLowerTbl_t *Lower2UpperTbl2[] = {
+ Lower2UpperTbl20, /* \303 */
+ Lower2UpperTbl21, /* \304 */
+ Lower2UpperTbl22, /* \305 */
+ Lower2UpperTbl23, /* \306 */
+ Lower2UpperTbl24, /* \307 */
+ Lower2UpperTbl25, /* \310 */
+ Lower2UpperTbl26, /* \311 */
+ Lower2UpperTbl27, /* \312 */
+ NULL, /* \313 */
+ NULL, /* \314 */
+ NULL, /* \315 */
+ Lower2UpperTbl28, /* \316 */
+ Lower2UpperTbl29, /* \317 */
+ Lower2UpperTbl2a, /* \320 */
+ Lower2UpperTbl2b, /* \321 */
+ Lower2UpperTbl2c, /* \322 */
+ Lower2UpperTbl2d, /* \323 */
+ NULL, /* \324 */
+ Lower2UpperTbl2e, /* \325 */
+ Lower2UpperTbl2f /* \326 */
+};
+
+UpperLowerTbl_t *Lower2UpperTbl3[] = {
+ Lower2UpperTbl30, /* \341 */
+ NULL, /* \342 */
+ NULL, /* \343 */
+ NULL, /* \344 */
+ NULL, /* \345 */
+ NULL, /* \346 */
+ NULL, /* \347 */
+ NULL, /* \350 */
+ NULL, /* \351 */
+ NULL, /* \352 */
+ NULL, /* \353 */
+ NULL, /* \354 */
+ NULL, /* \355 */
+ NULL, /* \356 */
+ Lower2UpperTbl31 /* \357 */
+};
+
+#define LU2S (unsigned char)'\303'
+#define LU2E (unsigned char)'\326'
+#define LU3S (unsigned char)'\341'
+#define LU3E (unsigned char)'\357'
+
+/*
+ * slapi_utf8StrToUpper: translate lower-case string to upper-case
+ *
+ * input: a null terminated UTF-8 string
+ * output: a null terminated UTF-8 string which characters are
+ * converted to upper-case; characters which are not
+ * lower-case are copied as is. If it's not considered
+ * a UTF-8 string, NULL is returned.
+ *
+ * Notes: This function takes a string (made of multiple UTF-8 characters)
+ * for the input (not one character as in "toupper").
+ * Output string is allocated in this function, which needs to be
+ * released when it's not needed any more.
+ */
+unsigned char *
+slapi_UTF8STRTOUPPER(char *s)
+{
+ return slapi_utf8StrToUpper((unsigned char *)s);
+}
+
+unsigned char *
+slapi_utf8StrToUpper(unsigned char *s)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *p, *np, *tail;
+ unsigned char *up, *uphead;
+ int len, sz;
+
+ if (s == NULL || *s == '\0') {
+ return s;
+ }
+ len = strlen((char *)s);
+ tail = s + len;
+ uphead = up = (unsigned char *)slapi_ch_malloc(len + 1);
+ p = s;
+ while ((np = (unsigned char *)ldap_utf8next((char *)p)) <= tail) {
+ switch(sz = np - p) {
+ case 1: /* ASCII */
+ sprintf((char *)up, "%c", toupper(*p));
+ break;
+ case 2: /* 2 bytes */
+ if (*p < LU2S || *p > LU2E) { /* out of range */
+ memcpy(up, p, sz);
+ break;
+ }
+ for (ultp = Lower2UpperTbl2[*p - LU2S];
+ ultp && ultp->lower && memcmp(p, ultp->lower, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memcpy(up, p, sz);
+ } else if (ultp->lower) { /* matched */
+ memcpy(up, ultp->upper, ultp->tsz);
+ sz = ultp->tsz;
+ } else {
+ memcpy(up, p, sz);
+ }
+ break;
+ case 3: /* 3 bytes */
+ if (*p != LU3S && *p != LU3E) { /* out of range */
+ memcpy(up, p, sz);
+ break;
+ }
+ for (ultp = Lower2UpperTbl3[*p - LU3S];
+ ultp && ultp->lower && memcmp(p, ultp->lower, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memcpy(up, p, sz);
+ } else if (ultp->lower) { /* matched */
+ memcpy(up, ultp->upper, sz);
+ } else {
+ memcpy(up, p, sz);
+ }
+ break;
+ case 4:
+ memcpy(up, p, sz);
+ break;
+ default: /* not UTF-8 */
+ slapi_ch_free((void **)&uphead);
+ return NULL;
+ }
+ up += sz;
+ p = np;
+ if (p == tail) {
+ break;
+ }
+ }
+ *up = '\0';
+ return uphead;
+}
+
+/*
+ * slapi_utf8ToUpper: translate lower-case character to upper-case
+ *
+ * input: a UTF-8 character (s)
+ * output: a UTF-8 character which is converted to upper-case (d)
+ * length (in bytes) of input character (ssz) and
+ * output character (dsz)
+ *
+ * Notes: This function takes a UTF-8 character (could be multiple bytes)
+ * for the input. Memory for the output character is NOT allocated
+ * in this function, caller should have allocated it (d).
+ * "memmove" is used since (s) and (d) are overlapped.
+ */
+void
+slapi_UTF8TOUPPER(char *s, char *d, int *ssz, int *dsz)
+{
+ slapi_utf8ToUpper((unsigned char *)s, (unsigned char *)d, ssz, dsz);
+ return;
+}
+
+void
+slapi_utf8ToUpper(unsigned char *s, unsigned char *d, int *ssz, int *dsz)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *tail;
+
+ if (s == NULL || *s == '\0') {
+ *ssz = *dsz = 0;
+ return;
+ }
+ if (!(*s & 0x80)) { /* ASCII */
+ *dsz = *ssz = 1;
+ *d = toupper(*s);
+ return;
+ }
+ tail = (unsigned char *)ldap_utf8next((char *)s);
+ *dsz = *ssz = tail - s;
+ switch(*ssz) {
+ case 1: /* ASCII */
+ *d = toupper(*s);
+ break;
+ case 2: /* 2 bytes */
+ if (*s < LU2S || *s > LU2E) { /* out of range */
+ memmove(d, s, *ssz);
+ break;
+ }
+ for (ultp = Lower2UpperTbl2[*s - LU2S];
+ ultp && ultp->lower && memcmp(s, ultp->lower, *ssz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memmove(d, s, *ssz);
+ } else if (ultp->lower) { /* matched */
+ memmove(d, ultp->upper, ultp->tsz);
+ *dsz = ultp->tsz;
+ } else {
+ memmove(d, s, *ssz);
+ }
+ break;
+ case 3: /* 3 bytes */
+ if (*s != LU3S && *s != LU3E) { /* out of range */
+ memmove(d, s, *ssz);
+ break;
+ }
+ for (ultp = Lower2UpperTbl3[*s - LU3S];
+ ultp && ultp->lower && memcmp(s, ultp->lower, *ssz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ memmove(d, s, *ssz);
+ } else if (ultp->lower) { /* matched */
+ memmove(d, ultp->upper, *ssz);
+ } else {
+ memmove(d, s, *ssz);
+ }
+ break;
+ }
+ return;
+}
+
+/*
+ * slapi_utf8isLower: tests for a character that is a lower-case letter in
+ * UTF-8
+ *
+ * input: a UTF-8 character (could be multi-byte)
+ * output: 1 if the character is a lower-case letter
+ * 0 if the character is not a lower-case letter
+ */
+int
+slapi_UTF8ISLOWER(char *s)
+{
+ return slapi_utf8isLower((unsigned char *)s);
+}
+
+int
+slapi_utf8isLower(unsigned char *s)
+{
+ UpperLowerTbl_t *ultp;
+ unsigned char *next;
+ int sz;
+
+ if (s == NULL || *s == '\0') {
+ return 0;
+ }
+ if (!(*s & 0x80)) { /* ASCII */
+ return islower(*s);
+ }
+ next = (unsigned char *)ldap_utf8next((char *)s);
+ switch(sz = next - s) {
+ case 1: /* ASCII */
+ return islower(*s);
+ case 2:
+ if (*s < LU2S || *s > LU2E) { /* out of range */
+ return 0;
+ }
+ for (ultp = Lower2UpperTbl2[*s - LU2S];
+ ultp && ultp->lower && memcmp(s, ultp->lower, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ return 0;
+ } else if (ultp->lower) { /* matched */
+ return 1;
+ } else {
+ return 0;
+ }
+ case 3:
+ if (*s < LU3S || *s > LU3E) { /* out of range */
+ return 0;
+ }
+ for (ultp = Lower2UpperTbl3[*s - LU3S];
+ ultp && ultp->lower && memcmp(s, ultp->lower, sz);
+ ultp++)
+ ;
+ if (!ultp) { /* out of range */
+ return 0;
+ } else if (ultp->lower) { /* matched */
+ return 1;
+ } else {
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+/*
+ * slapi_utf8casecmp: case-insensitive string compare for UTF-8 strings
+ *
+ * input: two UTF-8 strings (s0, s1) to be compared
+ * output: positive number, if s0 is after s1
+ * 0, if the two strings are identical ignoring the case
+ * negative number, if s1 is after s0
+ *
+ * Rules: If both UTF-8 strings are NULL or 0-length, 0 is returned.
+ * If one of the strings is NULL or 0-length, the NULL/0-length
+ * string is smaller.
+ * If one or both of the strings are not UTF-8, system provided
+ * strcasecmp is used.
+ * If one of the two strings contains no 8-bit characters,
+ * strcasecmp is used.
+ * The strings are compared after converted to lower-case UTF-8.
+ * Each character is compared from the beginning.
+ * Evaluation goes in this order:
+ * If the length of one character is shorter then the other,
+ * the difference of the two lengths is returned.
+ * If the length of the corresponsing characters is same,
+ * each byte in the characters is compared.
+ * If there's a difference between two bytes,
+ * the diff is returned.
+ * If one string is shorter then the other, the diff is returned.
+ *
+ * Notes: Don't use this function for collation
+ * 1) there's no notion of locale in this function.
+ * 2) it's UTF-8 code order, which is different from the locale
+ * based collation.
+ */
+int
+slapi_UTF8CASECMP(char *s0, char *s1)
+{
+ return slapi_utf8casecmp((unsigned char *)s0, (unsigned char *)s1);
+}
+
+int
+slapi_utf8casecmp(unsigned char *s0, unsigned char *s1)
+{
+ unsigned char *d0, *d1; /* store lower-case strings */
+ unsigned char *p0, *p1; /* current UTF-8 char */
+ unsigned char *n0, *n1; /* next UTF-8 char */
+ unsigned char *t0, *t1; /* tail of the strings */
+ unsigned char *x0, *x1; /* current byte in a char */
+ int i0, i1; /* length of characters */
+ int l0, l1; /* length of leftover */
+ int rval;
+ int has8_s0;
+ int has8_s1;
+
+ d0 = d1 = NULL;
+ if (s0 == NULL || *s0 == '\0') {
+ if (s1 == NULL || *s1 == '\0') {
+ rval = 0;
+ } else {
+ rval = -1; /* regardless s1, s0 < s1 */
+ }
+ goto end;
+ } else if (s1 == NULL || *s1 == '\0') {
+ rval = 1; /* regardless s0, s0 > s1 */
+ goto end;
+ }
+
+ has8_s0 = slapi_has8thBit(s0);
+ has8_s1 = slapi_has8thBit(s1);
+ if (has8_s0 == has8_s1) { /* both has-8th-bit or both do not */
+ if (has8_s0 == 0) { /* neither has-8th-bit */
+ rval = strcasecmp((char *)s0, (char *)s1);
+ goto end;
+ }
+ } else { /* one has and the other do not */
+ rval = strcasecmp((char *)s0, (char *)s1);
+ goto end;
+ }
+
+ d0 = slapi_utf8StrToLower(s0);
+ d1 = slapi_utf8StrToLower(s1);
+ if (d0 == NULL || d1 == NULL || /* either is not a UTF-8 string */
+ (d0 && *d0 == '\0') || (d1 && *d1 == '\0')) {
+ rval = strcasecmp((char *)s0, (char *)s1);
+ goto end;
+ }
+
+ p0 = d0;
+ p1 = d1;
+
+ t0 = d0 + strlen((char *)d0);
+ t1 = d1 + strlen((char *)d1);
+
+ rval = 0;
+ while (1) {
+ n0 = (unsigned char *)ldap_utf8next((char *)p0);
+ n1 = (unsigned char *)ldap_utf8next((char *)p1);
+ if (n0 > t0 || n1 > t1) {
+ break;
+ }
+
+ i0 = n0 - p0;
+ i1 = n1 - p1;
+ rval = i0 - i1;
+ if (rval) { /* length is different */
+ goto end;
+ }
+
+ /* i0 == i1: same length */
+ for (x0 = p0, x1 = p1; x0 < n0; x0++, x1++) {
+ rval = *x0 - *x1;
+ if (rval) {
+ goto end;
+ }
+ }
+
+ p0 = n0; p1 = n1; /* goto next */
+ }
+ /* finished scanning the shared part and check the leftover */
+ l0 = t0 - n0;
+ l1 = t1 - n1;
+ rval = l0 - l1;
+
+end:
+ if (d0)
+ slapi_ch_free((void **)&d0);
+ if (d1)
+ slapi_ch_free((void **)&d1);
+
+ return rval;
+}
+
+/*
+ * slapi_utf8ncasecmp: case-insensitive string compare (n chars) for UTF-8
+ * strings
+ *
+ * input: two UTF-8 strings (s0, s1) to be compared
+ * number or characters
+ * output: positive number, if s0 is after s1
+ * 0, if the two strings are identical ignoring the case
+ * negative number, if s1 is after s0
+ *
+ * Rules: Same as slapi_utf8casecmp except the n characters limit.
+ *
+ * Notes: Don't use this function for collation
+ * 1) there's no notion of locale in this function.
+ * 2) it's UTF-8 code order, which is different from the locale
+ * based collation.
+ * n characters, NOT n bytes
+ */
+int
+slapi_UTF8NCASECMP(char *s0, char *s1, int n)
+{
+ return slapi_utf8ncasecmp((unsigned char *)s0, (unsigned char *)s1, n);
+}
+
+int
+slapi_utf8ncasecmp(unsigned char *s0, unsigned char *s1, int n)
+{
+ unsigned char *d0, *d1; /* store lower-case strings */
+ unsigned char *p0, *p1; /* current UTF-8 char */
+ unsigned char *n0, *n1; /* next UTF-8 char */
+ unsigned char *t0, *t1; /* tail of the strings */
+ unsigned char *x0, *x1; /* current byte in a char */
+ int i0, i1; /* length of characters */
+ int l0, l1; /* length of leftover */
+ int cnt;
+ int rval;
+ int has8_s0;
+ int has8_s1;
+
+ d0 = d1 = NULL;
+ if (s0 == NULL || *s0 == '\0') {
+ if (s1 == NULL || *s1 == '\0') {
+ rval = 0;
+ } else {
+ rval = -1; /* regardless s1, s0 < s1 */
+ }
+ goto end;
+ } else if (s1 == NULL || *s1 == '\0') {
+ rval = 1; /* regardless s0, s0 > s1 */
+ goto end;
+ }
+
+ has8_s0 = slapi_has8thBit(s0);
+ has8_s1 = slapi_has8thBit(s1);
+ if (has8_s0 == has8_s1) { /* both has-8th-bit or both do not */
+ if (has8_s0 == 0) { /* neither has-8th-bit */
+ rval = strncasecmp((char *)s0, (char *)s1, n);
+ goto end;
+ }
+ } else { /* one has and the other do not */
+ rval = strncasecmp((char *)s0, (char *)s1, n);
+ goto end;
+ }
+
+ d0 = slapi_utf8StrToLower(s0);
+ d1 = slapi_utf8StrToLower(s1);
+
+ if (d0 == NULL || d1 == NULL || /* either is not a UTF-8 string */
+ (d0 && *d0 == '\0') || (d1 && *d1 == '\0')) {
+ rval = strncasecmp((char *)s0, (char *)s1, n);
+ goto end;
+ }
+
+ p0 = d0;
+ p1 = d1;
+
+ t0 = d0 + strlen((char *)d0);
+ t1 = d1 + strlen((char *)d1);
+
+ rval = 0;
+ cnt = 0;
+ while (1) {
+ n0 = (unsigned char *)ldap_utf8next((char *)p0);
+ n1 = (unsigned char *)ldap_utf8next((char *)p1);
+ if (n0 > t0 || n1 > t1 || cnt == n) {
+ break;
+ }
+
+ i0 = n0 - p0;
+ i1 = n1 - p1;
+ rval = i0 - i1;
+ if (rval) /* length is different */
+ goto end;
+
+ /* i0 == i1: same length */
+ for (x0 = p0, x1 = p1; x0 < n0; x0++, x1++) {
+ rval = *x0 - *x1;
+ if (rval)
+ goto end;
+ }
+
+ p0 = n0; p1 = n1; /* goto next */
+ cnt++;
+ }
+ if (cnt == n)
+ rval = 0;
+ else {
+ /* finished scanning the shared part and check the leftover */
+ l0 = t0 - n0;
+ l1 = t1 - n1;
+ rval = l0 - l1;
+ }
+
+end:
+ if (d0)
+ slapi_ch_free((void **)&d0);
+ if (d1)
+ slapi_ch_free((void **)&d1);
+
+ return rval;
+}
+
diff --git a/ldap/servers/slapd/util.c b/ldap/servers/slapd/util.c
new file mode 100644
index 00000000..6b6a5b0c
--- /dev/null
+++ b/ldap/servers/slapd/util.c
@@ -0,0 +1,601 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* util.c -- utility functions -- functions available form libslapd */
+#ifdef _WIN32
+#include <direct.h> /* for getcwd */
+#else
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <pwd.h>
+#endif
+#include <pk11func.h>
+#include "slap.h"
+#include "prtime.h"
+#include "prinrval.h"
+
+#define UTIL_ESCAPE_NONE 0
+#define UTIL_ESCAPE_HEX 1
+#define UTIL_ESCAPE_BACKSLASH 2
+
+static int special_np(unsigned char c)
+{
+ if(c < 32 || c > 126) {
+ return UTIL_ESCAPE_HEX;
+ } else if ((c== '"') || (c=='\\'))
+ {
+ return UTIL_ESCAPE_HEX;
+ }
+ return UTIL_ESCAPE_NONE;
+}
+
+static int special_np_and_punct(unsigned char c)
+{
+ if (c < 32 || c > 126 || c == '*') return UTIL_ESCAPE_HEX;
+ if (c == '\\' || c == '"') return UTIL_ESCAPE_BACKSLASH;
+ return UTIL_ESCAPE_NONE;
+}
+
+static int special_filter(unsigned char c)
+{
+ /*
+ * Escape all non-printing chars and double-quotes in addition
+ * to those required by RFC 2254 so that we can use the string
+ * in log files.
+ */
+ return (c < 32 ||
+ c > 126 ||
+ c == '*' ||
+ c == '(' ||
+ c == ')' ||
+ c == '\\' ||
+ c == '"') ? UTIL_ESCAPE_HEX : UTIL_ESCAPE_NONE;
+}
+
+static const char*
+do_escape_string (
+ const char* str,
+ int len, /* -1 means str is nul-terminated */
+ char buf[BUFSIZ],
+ int (*special)(unsigned char)
+)
+{
+ const char* s;
+ const char* last;
+ int esc;
+
+ if (str == NULL) {
+ *buf = '\0';
+ return buf;
+ }
+
+ if (len == -1) len = strlen (str);
+ if (len == 0) return str;
+
+ last = str + len - 1;
+ for (s = str; s <= last; ++s) {
+ if ( esc = (*special)((unsigned char)*s)) {
+ const char* first = str;
+ char* bufNext = buf;
+ int bufSpace = BUFSIZ - 4;
+ while (1) {
+ if (bufSpace < (s - first)) s = first + bufSpace - 1;
+ if (s > first) {
+ memcpy (bufNext, first, s - first);
+ bufNext += (s - first);
+ bufSpace -= (s - first);
+ }
+ if (s > last) {
+ break;
+ }
+ do {
+ *bufNext++ = '\\'; --bufSpace;
+ if (bufSpace < 2) {
+ memcpy (bufNext, "..", 2);
+ bufNext += 2;
+ goto bail;
+ }
+ if (esc == UTIL_ESCAPE_BACKSLASH) {
+ *bufNext++ = *s; --bufSpace;
+ } else { /* UTIL_ESCAPE_HEX */
+ sprintf (bufNext, "%02x", (unsigned)*(unsigned char*)s);
+ bufNext += 2; bufSpace -= 2;
+ }
+ } while (++s <= last &&
+ (esc = (*special)((unsigned char)*s)));
+ if (s > last) break;
+ first = s;
+ while ( (esc = (*special)((unsigned char)*s)) == UTIL_ESCAPE_NONE && s <= last) ++s;
+ }
+ bail:
+ *bufNext = '\0';
+ return buf;
+ }
+ }
+ return str;
+}
+
+/*
+ * Function: escape_string
+ * Arguments: str: string
+ * buf: a char array of BUFSIZ length, in which the escaped string will
+ * be returned.
+ * Returns: a pointer to buf, if str==NULL or it needed to be escaped, or
+ * str itself otherwise.
+ *
+ * This function should only be used for generating loggable strings.
+ */
+const char*
+escape_string (const char* str, char buf[BUFSIZ])
+{
+ return do_escape_string(str,-1,buf,special_np);
+}
+
+const char*
+escape_string_with_punctuation(const char* str, char buf[BUFSIZ])
+{
+ return do_escape_string(str,-1,buf,special_np_and_punct);
+}
+
+const char*
+escape_filter_value(const char* str, int len, char buf[BUFSIZ])
+{
+ return do_escape_string(str,len,buf,special_filter);
+}
+
+/* functions to convert between an entry and a set of mods */
+int slapi_mods2entry (Slapi_Entry **e, const char *idn, LDAPMod **iattrs)
+{
+ int i, rc = LDAP_SUCCESS;
+ LDAPMod **attrs= NULL;
+
+ PR_ASSERT (idn);
+ PR_ASSERT (iattrs);
+ PR_ASSERT (e);
+
+ attrs = normalize_mods2bvals((const LDAPMod **)iattrs);
+ PR_ASSERT (attrs);
+
+ /* Construct an entry */
+ *e = slapi_entry_alloc();
+ PR_ASSERT (*e);
+ slapi_entry_init(*e, slapi_ch_strdup(idn), NULL);
+
+ for (i = 0; rc==LDAP_SUCCESS && attrs[ i ]!=NULL; i++)
+ {
+ char *normtype;
+ Slapi_Value **vals;
+
+ normtype = slapi_attr_syntax_normalize(attrs[ i ]->mod_type);
+ valuearray_init_bervalarray(attrs[ i ]->mod_bvalues, &vals);
+ if (strcasecmp(normtype, SLAPI_USERPWD_ATTR) == 0)
+ {
+ pw_encodevals(vals);
+ }
+
+ /* set entry uniqueid - also adds attribute to the list */
+ if (strcasecmp(normtype, SLAPI_ATTR_UNIQUEID) == 0)
+ slapi_entry_set_uniqueid (*e, slapi_ch_strdup (slapi_value_get_string(vals[0])));
+ else
+ rc = slapi_entry_add_values_sv(*e, normtype, vals);
+
+ valuearray_free(&vals);
+ if (rc != LDAP_SUCCESS)
+ {
+ LDAPDebug(LDAP_DEBUG_ANY, "slapi_add_internal: add_values for type %s failed\n", normtype, 0, 0 );
+ slapi_entry_free (*e);
+ *e = NULL;
+ }
+ slapi_ch_free((void **) &normtype);
+ }
+ freepmods(attrs);
+
+ return rc;
+}
+
+int slapi_entry2mods (const Slapi_Entry *e, char **dn, LDAPMod ***attrs)
+{
+ Slapi_Mods smods;
+ Slapi_Attr *attr;
+ Slapi_Value **va;
+ char *type;
+ int rc;
+
+ PR_ASSERT (e && attrs);
+
+ if (dn)
+ *dn = slapi_ch_strdup (slapi_entry_get_dn ((Slapi_Entry *)e));
+ slapi_mods_init (&smods, 0);
+
+ rc = slapi_entry_first_attr(e, &attr);
+ while (rc == 0)
+ {
+ if ( NULL != ( va = attr_get_present_values( attr ))) {
+ slapi_attr_get_type(attr, &type);
+ slapi_mods_add_mod_values(&smods, LDAP_MOD_ADD, type, va );
+ }
+ rc = slapi_entry_next_attr(e, attr, &attr);
+ }
+
+ *attrs = slapi_mods_get_ldapmods_passout (&smods);
+ slapi_mods_done (&smods);
+
+ return 0;
+}
+
+/******************************************************************************
+*
+* normalize_mods2bvals
+*
+*
+*
+*
+*******************************************************************************/
+
+LDAPMod **
+normalize_mods2bvals(const LDAPMod **mods)
+{
+ int w, x, vlen, num_values, num_mods;
+ LDAPMod **normalized_mods;
+
+ if (mods == NULL)
+ {
+ return NULL;
+ }
+
+ /* first normalize the mods so they are bvalues */
+ /* count the number of mods -- sucks but should be small */
+ num_mods = 1;
+ for (w=0; mods[w] != NULL; w++) num_mods++;
+
+ normalized_mods = (LDAPMod **) slapi_ch_calloc(num_mods, sizeof(LDAPMod *));
+
+ for (w = 0; mods[w] != NULL; w++)
+ {
+ /* copy each mod into a normalized modbvalue */
+ normalized_mods[w] = (LDAPMod *) slapi_ch_calloc(1, sizeof(LDAPMod));
+ normalized_mods[w]->mod_op = mods[w]->mod_op | LDAP_MOD_BVALUES;
+
+ normalized_mods[w]->mod_type = slapi_ch_strdup(mods[w]->mod_type);
+
+ /*
+ * count the number of values -- kinda sucks but probably
+ * less expensive then reallocing, and num_values
+ * should typically be very small
+ */
+ num_values = 0;
+ if (mods[w]->mod_op & LDAP_MOD_BVALUES)
+ {
+ for (x = 0; mods[w]->mod_bvalues != NULL &&
+ mods[w]->mod_bvalues[x] != NULL; x++)
+ {
+ num_values++;
+ }
+ } else {
+ for (x = 0; mods[w]->mod_values[x] != NULL &&
+ mods[w]->mod_values[x] != NULL; x++)
+ {
+ num_values++;
+ }
+ }
+
+ if (num_values > 0)
+ {
+ normalized_mods[w]->mod_bvalues = (struct berval **)
+ slapi_ch_calloc(num_values + 1, sizeof(struct berval *));
+ } else {
+ normalized_mods[w]->mod_bvalues = NULL;
+ }
+
+ if (mods[w]->mod_op & LDAP_MOD_BVALUES)
+ {
+ for (x = 0; mods[w]->mod_bvalues != NULL &&
+ mods[w]->mod_bvalues[x] != NULL; x++)
+ {
+ normalized_mods[w]->mod_bvalues[x] = ber_bvdup(mods[w]->mod_bvalues[x]);
+ }
+ } else {
+ for (x = 0; mods[w]->mod_values != NULL &&
+ mods[w]->mod_values[x] != NULL; x++)
+ {
+ normalized_mods[w]->mod_bvalues[ x ] = (struct berval *)
+ slapi_ch_calloc(1, sizeof(struct berval));
+
+ vlen = strlen(mods[w]->mod_values[x]);
+ normalized_mods[w]->mod_bvalues[ x ]->bv_val =
+ slapi_ch_calloc(vlen + 1, sizeof(char));
+ memcpy(normalized_mods[w]->mod_bvalues[ x ]->bv_val,
+ mods[w]->mod_values[x], vlen);
+ normalized_mods[w]->mod_bvalues[ x ]->bv_val[vlen] = '\0';
+ normalized_mods[w]->mod_bvalues[ x ]->bv_len = vlen;
+ }
+ }
+
+ /* don't forget to null terminate it */
+ if (num_values > 0)
+ {
+ normalized_mods[w]->mod_bvalues[ x ] = NULL;
+ }
+ }
+
+ /* don't forget to null terminate the normalize list of mods */
+ normalized_mods[w] = NULL;
+
+ return(normalized_mods);
+}
+
+/*
+ * Return true if the given path is an absolute path, false otherwise
+ */
+int
+is_abspath(const char *path)
+{
+ if (path == NULL || *path == '\0') {
+ return 0; /* empty path is not absolute? */
+ }
+
+#if defined( XP_WIN32 )
+ if (path[0] == '/' || path[0] == '\\' ||
+ (isalpha(path[0]) && (path[1] == ':'))) {
+ return 1; /* Windows abs path */
+ }
+#else
+ if (path[0] == '/') {
+ return 1; /* unix abs path */
+ }
+#endif
+
+ return 0; /* not an abs path */
+}
+
+
+/*
+ * Take "relpath" and prepend the current working directory to it
+ * if it isn't an absolute pathname already. The caller is responsible
+ * for freeing the returned string.
+ */
+char *
+rel2abspath( char *relpath )
+{
+ char abspath[ MAXPATHLEN + 1 ];
+
+#if defined( _WIN32 )
+ CHAR szDrive[_MAX_DRIVE];
+ CHAR szDir[_MAX_DIR];
+ CHAR szFname[_MAX_FNAME];
+ CHAR szExt[_MAX_EXT];
+#define _PSEP "\\"
+#else
+#define _PSEP "/"
+#endif
+
+ if ( relpath == NULL ) {
+ return NULL;
+ }
+
+#if defined( _WIN32 )
+ memset (&szDrive, 0, sizeof (szDrive));
+ memset (&szDir, 0, sizeof (szDir));
+ memset (&szFname, 0, sizeof (szFname));
+ memset (&szExt, 0, sizeof (szExt));
+ _splitpath( relpath, szDrive, szDir, szFname, szExt );
+ if( szDrive[0] && szDir[0] )
+ return( slapi_ch_strdup( relpath ));
+ if ( relpath[ 0 ] == '/' || relpath[ 0 ] == '\\' ) {
+ return( slapi_ch_strdup( relpath ));
+#else
+ if ( relpath[ 0 ] == '/' ) {
+ return( slapi_ch_strdup( relpath ));
+ }
+#endif
+
+ if ( getcwd( abspath, MAXPATHLEN ) == NULL ) {
+ perror( "getcwd" );
+ LDAPDebug( LDAP_DEBUG_ANY, "Cannot determine current directory\n",
+ 0, 0, 0 );
+ exit( 1 );
+ }
+
+ if ( strlen( relpath ) + strlen( abspath ) + 1 > MAXPATHLEN ) {
+ LDAPDebug( LDAP_DEBUG_ANY, "Pathname \"%s" _PSEP "%s\" too long\n",
+ abspath, relpath, 0 );
+ exit( 1 );
+ }
+
+ if ( strcmp( relpath, "." )) {
+#if defined( _WIN32 )
+ if ( abspath[ 0 ] != '\0' && abspath[ strlen( abspath ) - 1 ] != '/' && abspath[ strlen( abspath ) - 1 ] != '\\' )
+#else
+ if ( abspath[ 0 ] != '\0' && abspath[ strlen( abspath ) - 1 ] != '/' ) {
+#endif
+ strcat( abspath, "/" );
+ }
+ strcat( abspath, relpath );
+ }
+ return( slapi_ch_strdup( abspath ));
+}
+
+
+/*
+ * Allocate a buffer large enough to hold a berval's
+ * value and a terminating null byte. The returned buffer
+ * is null-terminated. Returns NULL if bval is NULL or if
+ * bval->bv_val is NULL.
+ */
+char *
+slapi_berval_get_string_copy(const struct berval *bval)
+{
+ char *return_value = NULL;
+ if (NULL != bval && NULL != bval->bv_val)
+ {
+ return_value = slapi_ch_malloc(bval->bv_len + 1);
+ memcpy(return_value, bval->bv_val, bval->bv_len);
+ return_value[bval->bv_len] = '\0';
+ }
+ return return_value;
+}
+
+
+ /* Takes a return code supposed to be errno or from a plugin
+ which we don't expect to see and prints a handy log message */
+void slapd_nasty(char* str, int c, int err)
+{
+ char *msg = NULL;
+ char buffer[100];
+ sprintf(buffer,"%s BAD %d",str,c);
+ LDAPDebug(LDAP_DEBUG_ANY,"%s, err=%d %s\n",buffer,err,(msg = strerror( err )) ? msg : "");
+}
+
+/* ***************************************************
+ Random function (very similar to rand_r())
+ *************************************************** */
+int
+slapi_rand_r(unsigned int *randx)
+{
+ if (*randx)
+ {
+ PK11_RandomUpdate(randx, sizeof(*randx));
+ }
+ PK11_GenerateRandom((unsigned char *)randx, (int)sizeof(*randx));
+ return (int)(*randx & 0x7FFFFFFF);
+}
+
+/* ***************************************************
+ Random function (very similar to rand_r() but takes and returns an array)
+ Note: there is an identical function in plugins/pwdstorage/ssha_pwd.c.
+ That module can't use a libslapd function because the module is included
+ in libds_admin, which doesn't link to libslapd. Eventually, shared
+ functions should be moved to a shared library.
+ *************************************************** */
+void
+slapi_rand_array(void *randx, size_t len)
+{
+ PK11_RandomUpdate(randx, len);
+ PK11_GenerateRandom((unsigned char *)randx, (int)len);
+}
+
+/* ***************************************************
+ Random function (very similar to rand()...)
+ *************************************************** */
+int
+slapi_rand()
+{
+ unsigned int randx = 0;
+ return slapi_rand_r(&randx);
+}
+
+
+
+/************************************************************************
+Function: DS_Sleep(PRIntervalTime ticks)
+
+Purpose: To replace PR_Sleep()
+
+Author: Scott Hopson <shopson@netscape.com>
+
+Description:
+ Causes the current thread to wait for ticks number of intervals.
+
+ In UNIX this is accomplished by using select()
+ which should be supported across all UNIX platforms.
+
+ In WIN32 we simply use the Sleep() function which yields
+ for the number of milliseconds specified.
+
+************************************************************************/
+
+
+#if defined(_WIN32)
+
+#include "windows.h"
+
+
+void DS_Sleep(PRIntervalTime ticks)
+{
+DWORD mSecs = PR_IntervalToMilliseconds(ticks);
+
+ Sleep(mSecs);
+}
+
+#else /*** UNIX ***/
+
+
+#include <sys/time.h>
+
+
+void DS_Sleep(PRIntervalTime ticks)
+{
+long mSecs = PR_IntervalToMilliseconds(ticks);
+struct timeval tm;
+
+ tm.tv_sec = mSecs / 1000;
+ tm.tv_usec = (mSecs % 1000) * 1000;
+
+ select(0,NULL,NULL,NULL,&tm);
+}
+
+#endif
+
+
+/*****************************************************************************
+ * strarray2str(): convert the array of strings in "a" into a single
+ * space-separated string like:
+ * str1 str2 str3
+ * If buf is too small, the result will be truncated and end with "...".
+ * If include_quotes is non-zero, double quote marks are included around
+ * the string, e.g.,
+ * "str2 str2 str3"
+ *
+ * Returns: 0 if completely successful and -1 if result is truncated.
+ */
+int
+strarray2str( char **a, char *buf, size_t buflen, int include_quotes )
+{
+ int rc = 0; /* optimistic */
+ char *p = buf;
+ size_t totlen = 0;
+
+
+ if ( include_quotes ) {
+ if ( buflen < 3 ) {
+ return -1; /* not enough room for the quote marks! */
+ }
+ *p++ = '"';
+ ++totlen;
+ }
+
+ if ( NULL != a ) {
+ int ii;
+ size_t len = 0;
+ for ( ii = 0; a[ ii ] != NULL; ii++ ) {
+ if ( ii > 0 ) {
+ *p++ = ' ';
+ totlen++;
+ }
+ len = strlen( a[ ii ]);
+ if ( totlen + len > buflen - 5 ) {
+ strcpy ( p, "..." );
+ p += 3;
+ totlen += 3;
+ rc = -1;
+ break; /* result truncated */
+ } else {
+ strcpy( p, a[ ii ]);
+ p += len;
+ totlen += len;
+ }
+ }
+ }
+
+ if ( include_quotes ) {
+ *p++ = '"';
+ ++totlen;
+ }
+ buf[ totlen ] = '\0';
+
+ return( rc );
+}
+/*****************************************************************************/
diff --git a/ldap/servers/slapd/uuid.c b/ldap/servers/slapd/uuid.c
new file mode 100644
index 00000000..47576559
--- /dev/null
+++ b/ldap/servers/slapd/uuid.c
@@ -0,0 +1,893 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* uuid.c */
+
+/*
+** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
+** Digital Equipment Corporation, Maynard, Mass.
+** Copyright (c) 1998 Microsoft.
+** To anyone who acknowledges that this file is provided "AS IS"
+** without any express or implied warranty: permission to use, copy,
+** modify, and distribute this file for any purpose is hereby
+** granted without fee, provided that the above copyright notices and
+** this notice appears in all source code copies, and that none of
+** the names of Open Software Foundation, Inc., Hewlett-Packard
+** Company, or Digital Equipment Corporation be used in advertising
+** or publicity pertaining to distribution of the software without
+** specific, written prior permission. Neither Open Software
+** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
+* Corporation makes any representations about the suitability of
+** this software for any purpose.
+*/
+
+
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <pk11func.h>
+
+#ifdef _WIN32
+#include <sys/stat.h> /* for S_IREAD and S_IWRITE */
+#else
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/sysinfo.h>
+#include <sys/utsname.h>
+#include <unistd.h> /* gethostname() */
+#endif
+
+
+#include "slap.h"
+#include "uuid.h"
+#include "sechash.h"
+
+#define SEQ_PER_SEC 10000000 /* number of 100ns intervals in a sec */
+#define STATE_FILE "state" /* file that contains generator's state */
+#define STATE_ATTR "nsState" /* attribute that stores state info */
+#define MODULE "uuid" /* for logging */
+#define UPDATE_INTERVAL 60000 /* 1 minute */
+#define NEED_TIME_UPDATE -1
+
+/* generates uuid in singlethreaded environment */
+static int uuid_create_st(guid_t *uuid);
+/* generates uuid in multithreaded environment */
+static int uuid_create_mt(guid_t *uuid);
+/* periodically called to update generator's state - mt case only */
+static void uuid_update_state (time_t when, void *arg);
+/* creates uuid in v1 format using current state info */
+static void format_uuid_v1(guid_t *uuid, uuid_time_t timestamp, unsigned16 clock_seq);
+/* generates uuid in v3 format */
+static void format_uuid_v3(guid_t *uuid, unsigned char hash[16]);
+/* reads state from a file or DIT entry */
+static int read_state (const char *configDir, const Slapi_DN *configDN, PRBool *newState);
+/* reads state from a file */
+static int read_state_from_file (const char *configDir);
+/* read state information from DIT */
+static int read_state_from_entry (const Slapi_DN *configDN);
+/* writes state to persistent store: file or dit */
+static int write_state(PRBool newState);
+/* writes state to a file */
+static int write_state_to_file();
+/* writes state to dit */
+static int write_state_to_entry(PRBool newState);
+/* add state entry to the dit */
+static int add_state_entry ();
+/* modify state entry in the dit */
+static int modify_state_entry ();
+/* generates timestamp for the next uuid - single threaded */
+static uuid_time_t update_time();
+/* generates timestamp for the next uuid - multithreaded threaded */
+static int update_time_mt(uuid_time_t *timestamp, unsigned16 *clock_seq);
+/* retrieves or generates nodeid */
+static int get_node_identifier(uuid_node_t *node);
+/* returns current time in the UTC format */
+static void get_system_time(uuid_time_t *uuid_time);
+/* generates random value - used to set clock sequence */
+static unsigned16 true_random(void);
+/* generate random info buffer to generate nodeid */
+static void get_random_info(unsigned char seed[16]);
+
+/* UUID generator state stored persistently */
+typedef struct
+{
+ uuid_time_t timestamp; /* saved timestamp */
+ uuid_node_t node; /* saved node ID */
+ unsigned16 clockseq; /* saved clock sequence */
+ unsigned8 last_update;/* flags the update made during server sutdown */
+} uuid_gen_state;
+
+/* generator state plus data to support it */
+typedef struct
+{
+ uuid_gen_state genstate; /* generator state */
+ int time_seq; /* sequence number to account for clock
+ granularity; not written to disk */
+ PRBool initialized; /* uniqueid successfully initialized */
+ PRBool mtGen; /* multithreaded generation */
+ PRLock *lock; /* lock to protect state */
+ PRFileDesc *fd; /* fd for the state file */
+ Slapi_DN *configDN; /* db entry that contains state info */
+} uuid_state;
+
+static unsigned int uuid_seed = 0; /* seed for the random generator */
+
+ uuid_state _state; /* generator's state */
+
+/* uuid_init -- initializes uuid layer */
+int uuid_init (const char *configDir, const Slapi_DN *configDN, PRBool mtGen)
+{
+ int rt;
+ PRBool newState = PR_FALSE;
+
+ if (_state.initialized)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE,
+ "uuid_init: generator is already initialized\n");
+ return UUID_SUCCESS;
+ }
+
+ memset (&_state, 0, sizeof (_state));
+
+ /* get saved state */
+ rt = read_state(configDir, configDN, &newState);
+ if (rt != UUID_SUCCESS)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE,
+ "uuid_init: failed to get generator's state\n");
+ uuid_cleanup ();
+ return rt;
+ }
+
+ _state.mtGen = mtGen;
+
+ /* this is multithreaded generation - create lock */
+ if (_state.mtGen)
+ {
+ _state.lock = PR_NewLock();
+ if (!_state.lock)
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uuid_init: "
+ "failed to create state lock; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
+ prerr, slapd_pr_strerror(prerr));
+ uuid_cleanup ();
+ return UUID_LOCK_ERROR;
+ }
+ }
+
+ /* save the state */
+ rt = write_state(newState);
+ /* can't proceede if the state can't be written */
+ if (rt != UUID_SUCCESS)
+ {
+ if (slapi_config_get_readonly() &&
+ (rt == UUID_LDAP_ERROR)) {
+ /*
+ * If server is readonly and error is UUID_LDAP_ERROR
+ * we can continue.
+ */
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "Warning: "
+ "The server is in read-only mode, therefore the unique ID generator cannot be used. "
+ "Do not use this server in any replication agreement\n");
+ }
+ else {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uuid_init: "
+ "failed to save generator's state.\n");
+ uuid_cleanup ();
+ return rt;
+ }
+ }
+
+ /* schedule update task for multithreaded generation */
+ if (_state.mtGen)
+ slapi_eq_repeat(uuid_update_state, NULL, (time_t)0, UPDATE_INTERVAL);
+
+ _state.initialized = PR_TRUE;
+ return UUID_SUCCESS;
+}
+
+/* uuid_cleanup -- saves state, destroys generator data */
+void uuid_cleanup ()
+{
+ if (_state.initialized)
+ {
+ _state.genstate.last_update = 1;
+ write_state (PR_FALSE);
+ }
+
+ if (_state.lock)
+ PR_DestroyLock (_state.lock);
+
+ if (_state.fd)
+ PR_Close (_state.fd);
+
+ if (_state.configDN)
+ slapi_sdn_free(&_state.configDN);
+
+ memset (&_state, 0, sizeof (_state));
+}
+
+/* uuid_create - main generating function */
+int uuid_create(guid_t *uuid)
+{
+ if (_state.mtGen)
+ return uuid_create_mt(uuid);
+ else
+ return uuid_create_st(uuid);
+}
+
+/* uuid_compare -- Compare two UUID's "lexically" and return
+ -1 u1 is lexically before u2
+ 0 u1 is equal to u2
+ 1 u1 is lexically after u2
+
+ Note: lexical ordering is not temporal ordering!
+*/
+#define CHECK(f1, f2) if (f1 != f2) return f1 < f2 ? -1 : 1;
+int uuid_compare(const guid_t *u1, const guid_t *u2)
+{
+ int i;
+
+ CHECK(u1->time_low, u2->time_low);
+ CHECK(u1->time_mid, u2->time_mid);
+ CHECK(u1->time_hi_and_version, u2->time_hi_and_version);
+ CHECK(u1->clock_seq_hi_and_reserved, u2->clock_seq_hi_and_reserved);
+ CHECK(u1->clock_seq_low, u2->clock_seq_low)
+ for (i = 0; i < 6; i++)
+ {
+ if (u1->node[i] < u2->node[i])
+ return -1;
+ if (u1->node[i] > u2->node[i])
+ return 1;
+ }
+ return 0;
+}
+
+/* uuid_format -- converts UUID to its string representation
+ buffer should be at list 40 bytes long
+*/
+
+void uuid_format(const guid_t *u, char *buff)
+{
+ sprintf(buff, "%8.8lx-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x",
+ u->time_low, u->time_mid, u->time_hi_and_version,
+ u->clock_seq_hi_and_reserved, u->clock_seq_low, u->node[0],
+ u->node[1], u->node[2], u->node[3], u->node[4], u->node[5]);
+}
+
+/* uuid_create_from_name -- create a UUID using a "name" from a "name space"
+ */
+void uuid_create_from_name(guid_t * uuid, /* resulting UUID */
+ const guid_t nsid, /* UUID to serve as context, so identical
+ names from different name spaces generate
+ different UUIDs */
+ const void * name, /* the name from which to generate a UUID */
+ int namelen) /* the length of the name */
+{
+ PK11Context *c = NULL;
+
+ unsigned char hash[16];
+ unsigned int hashLen;
+ guid_t net_nsid; /* context UUID in network byte order */
+
+ memset(hash, 0, 16);
+
+ /* put name space ID in network byte order so it hashes the same
+ no matter what endian machine we're on */
+
+ memset(&net_nsid, 0, sizeof(guid_t));
+ net_nsid.time_low = PR_htonl(nsid.time_low);
+ net_nsid.time_mid = PR_htons(nsid.time_mid);
+ net_nsid.time_hi_and_version = PR_htons(nsid.time_hi_and_version);
+ net_nsid.clock_seq_hi_and_reserved=nsid.clock_seq_hi_and_reserved;
+ net_nsid.clock_seq_low=nsid.clock_seq_low;
+ strncpy((char *)net_nsid.node, (char *)nsid.node, 6);
+
+ c = PK11_CreateDigestContext(SEC_OID_MD5);
+ if (c != NULL) {
+ PK11_DigestBegin(c);
+ PK11_DigestOp(c, (unsigned char *)&net_nsid, sizeof(net_nsid));
+ PK11_DigestOp(c, (unsigned char *)name, namelen);
+ PK11_DigestFinal(c, hash, &hashLen, 16);
+
+ /* the hash is in network byte order at this point */
+ format_uuid_v3(uuid, hash);
+
+ PK11_DestroyContext(c, PR_TRUE);
+ }
+ else { /* Probably desesperate but at least deterministic... */
+ memset(&uuid, 0, sizeof(uuid));
+ }
+}
+
+/* Helper Functions */
+
+/* uuid_create_st -- singlethreaded generation */
+static int uuid_create_st(guid_t *uuid)
+{
+ uuid_time_t timestamp;
+
+ /* generate new time and save it in the state */
+ timestamp = update_time ();
+
+ /* stuff fields into the UUID */
+ format_uuid_v1(uuid, timestamp, _state.genstate.clockseq);
+
+ return UUID_SUCCESS;
+}
+
+/* uuid_create -- multithreaded generation */
+static int uuid_create_mt(guid_t *uuid)
+{
+ uuid_time_t timestamp;
+ unsigned16 clock_seq;
+
+ /* just bumps time sequence number. the actual
+ time calls are made by a uuid_update_state */
+ update_time_mt (&timestamp, &clock_seq);
+
+ if (timestamp == NEED_TIME_UPDATE)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "uuid_create_mt: generator ran "
+ "out of sequence numbers.\n");
+ return UUID_TIME_ERROR;
+ }
+
+ /* stuff fields into UUID */
+ format_uuid_v1(uuid, timestamp, clock_seq);
+
+ return UUID_SUCCESS;
+}
+
+/* uuid_update_state -- called periodically to update generator's state
+ (multithreaded case only)
+ */
+static void uuid_update_state (time_t when, void *arg)
+{
+ uuid_time_t timestamp;
+
+ get_system_time (&timestamp);
+
+ /* time has not changed since last call - return */
+ if (timestamp == _state.genstate.timestamp)
+ return;
+
+ PR_Lock (_state.lock);
+ /* clock was set backward - insure uuid uniquness by incrementing clock sequence */
+ if (timestamp < _state.genstate.timestamp)
+ _state.genstate.clockseq ++;
+
+ _state.genstate.timestamp = timestamp;
+ _state.time_seq = 0;
+
+ PR_Unlock (_state.lock);
+}
+
+/* read_state -- read UUID generator state from non-volatile store.
+*/
+static int read_state(const char *configDir, const Slapi_DN *configDN, PRBool *newState)
+{
+ uuid_time_t timestamp;
+ int rt;
+
+ if (configDN)
+ rt = read_state_from_entry (configDN);
+ else
+ rt = read_state_from_file (configDir);
+
+ if (rt == UUID_NOTFOUND)
+ *newState = PR_TRUE;
+ else
+ *newState = PR_FALSE;
+
+ if (rt != UUID_SUCCESS && rt != UUID_NOTFOUND) /* fatal error - bail out */
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE,
+ "read_state: failed to get generator's state\n");
+ return rt;
+ }
+
+ /* get current time and nodeid */
+ get_system_time(&timestamp);
+ if (*newState) /* state info is missing - generate */
+ {
+ get_node_identifier (&_state.genstate.node);
+ _state.genstate.clockseq = true_random();
+ }
+ else if(_state.genstate.last_update != 1)
+ {
+ /* clock sequence should be randomized and not just incremented
+ because server's clock could have been set back before the
+ server crashed in which case clock sequence was incremented */
+ _state.genstate.clockseq = true_random();
+ }
+ else if (timestamp <= _state.genstate.timestamp)
+ {
+ _state.genstate.clockseq ++;
+ }
+
+ _state.genstate.timestamp = timestamp;
+ _state.time_seq = 0;
+ /* need to clear this field so that we know if the state information
+ is written during shutdown (in which case this flag is set to 1 */
+ _state.genstate.last_update = 0;
+
+ return UUID_SUCCESS;
+}
+
+/* read_state_from_file -- read generator state from file.
+*/
+static int read_state_from_file (const char *configDir)
+{
+ char *path;
+ int rt;
+
+ if (configDir == NULL || configDir[0] == '\0')
+ { /* this directory */
+ path = (char*)slapi_ch_malloc(strlen (STATE_FILE) + 1);
+ if (path == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
+ "memory allocation failed.\n");
+ return (UUID_MEMORY_ERROR);
+ }
+
+ strcpy (path, STATE_FILE);
+ }
+ else
+ {
+ path = (char*)slapi_ch_malloc(strlen(configDir) + strlen(STATE_FILE) + 2);
+ if (path == NULL)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
+ "memory allocation failed.\n");
+ return (UUID_MEMORY_ERROR);
+ }
+ sprintf (path, "%s/%s", configDir, STATE_FILE);
+ }
+
+ /* open or create state file for read/write and keep it in sync */
+ _state.fd = PR_Open(path, PR_RDWR | PR_CREATE_FILE | PR_SYNC,
+ SLAPD_DEFAULT_FILE_MODE);
+ slapi_ch_free ((void**)&path);
+ if (!_state.fd)
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
+ "failed to open state file - %s; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
+ path, prerr, slapd_pr_strerror(prerr));
+ return (UUID_IO_ERROR);
+ }
+
+ rt = PR_Read (_state.fd, &_state.genstate, sizeof(uuid_gen_state));
+ if (rt == 0) /* new state */
+ {
+ return UUID_NOTFOUND;
+ }
+
+ if (rt == -1)
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state: "
+ "failed to read state information; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
+ prerr, slapd_pr_strerror(prerr));
+ return (UUID_IO_ERROR);
+ }
+
+ return(UUID_SUCCESS);
+}
+
+/* read_state_from_entry -- read generator state from DIT.
+*/
+static int read_state_from_entry (const Slapi_DN *configDN)
+{
+ Slapi_PBlock *pb;
+ int res, rt;
+ Slapi_Entry **entries;
+ Slapi_Attr *attr;
+ Slapi_Value *value;
+ const struct berval *bv;
+
+ _state.configDN = slapi_sdn_dup (configDN);
+ pb = slapi_search_internal(slapi_sdn_get_ndn (configDN), LDAP_SCOPE_BASE,
+ "objectclass=*", NULL, NULL, 0);
+
+ if (pb == NULL)
+ {
+ /* the only time NULL pb is returned is when memory allocation fails */
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state_from_entry: "
+ "NULL pblock returned from search\n");
+ return UUID_MEMORY_ERROR;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+
+ if (res == LDAP_NO_SUCH_OBJECT)
+ {
+ rt = UUID_NOTFOUND;
+ goto done;
+ }
+
+ if (res != LDAP_SUCCESS)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "read_state_from_entry: "
+ "search operation failed; LDAP error - %d\n", res);
+ rt = UUID_LDAP_ERROR;
+ goto done;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_SEARCH_ENTRIES, &entries);
+ if (entries == NULL || entries[0] == NULL)
+ {
+ rt = UUID_UNKNOWN_ERROR;
+ goto done;
+ }
+
+ /* get state info */
+ rt = slapi_entry_attr_find (entries[0], STATE_ATTR, &attr);
+ if (rt != LDAP_SUCCESS)
+ {
+ rt = UUID_FORMAT_ERROR;
+ goto done;
+ }
+
+ slapi_attr_first_value(attr,&value);
+ if (value == NULL)
+ {
+ rt = UUID_FORMAT_ERROR;
+ goto done;
+ }
+
+ bv = slapi_value_get_berval(value);
+ if (bv == NULL || bv->bv_val == NULL || bv->bv_len != sizeof (_state.genstate))
+ {
+ rt = UUID_FORMAT_ERROR;
+ goto done;
+ }
+
+ memcpy (&(_state.genstate), bv->bv_val, bv->bv_len);
+
+done:;
+ if (pb)
+ {
+ slapi_free_search_results_internal(pb);
+ slapi_pblock_destroy(pb);
+ }
+
+ return rt;
+}
+
+/* write_state -- save UUID generator state back to non-volatile
+ storage. Writes immediately to the disk
+*/
+
+static int write_state (PRBool newState)
+{
+ if (_state.configDN) /* write to DIT */
+ return write_state_to_entry (newState);
+ else /* write to a file */
+ return write_state_to_file ();
+}
+
+/* write_state_to_file -- stores state to state file
+*/
+static int write_state_to_file()
+{
+ int rt;
+
+ rt = PR_Seek (_state.fd, 0, PR_SEEK_SET);
+ if (rt == -1)
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "write_state: "
+ "failed to rewind state file; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
+ prerr, slapd_pr_strerror(prerr));
+ return UUID_IO_ERROR;
+ }
+
+ rt = PR_Write (_state.fd, &_state.genstate, sizeof (uuid_gen_state));
+ if (rt == -1)
+ {
+ PRErrorCode prerr = PR_GetError();
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "write_state: "
+ "failed to update state file; " SLAPI_COMPONENT_NAME_NSPR " error %d (%s).\n",
+ prerr, slapd_pr_strerror(prerr));
+
+ return (UUID_IO_ERROR);
+ }
+
+ return (UUID_SUCCESS);
+}
+
+/* write_state_to_entry -- stores state to state file
+*/
+static int write_state_to_entry(PRBool newState) {
+ if (newState)
+ return add_state_entry ();
+ else
+ return modify_state_entry ();
+}
+
+/* add_state_entry -- add state entry to the dit */
+static int add_state_entry ()
+{
+ struct berval *vals[2];
+ struct berval val;
+ Slapi_Entry *e;
+ Slapi_PBlock *pb = NULL;
+ const char *dn = slapi_sdn_get_ndn (_state.configDN);
+ int rt;
+
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ e = slapi_entry_alloc();
+ slapi_entry_set_dn(e, slapi_ch_strdup(dn));
+
+ /* Set the objectclass attribute */
+ val.bv_val = "top";
+ val.bv_len = strlen (val.bv_val);
+ slapi_entry_add_values(e, "objectclass", vals);
+
+ val.bv_val = "extensibleObject";
+ val.bv_len = strlen (val.bv_val);
+ slapi_entry_add_values(e, "objectclass", vals);
+
+ /* Set state attribute */
+ val.bv_val = (char*)&(_state.genstate);
+ val.bv_len = sizeof (_state.genstate);
+ slapi_entry_add_values(e, STATE_ATTR, vals);
+
+ /* this operation frees the entry */
+ pb = slapi_add_entry_internal(e, 0, 0 /* log_change */);
+ if (pb == NULL)
+ {
+ /* the only time NULL pb is returned is when memory allocation fails */
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "add_state_entry: "
+ "NULL pblock returned from search\n");
+ return UUID_MEMORY_ERROR;
+ }
+ else
+ {
+ slapi_pblock_get( pb, SLAPI_PLUGIN_INTOP_RESULT, &rt);
+ slapi_ch_free((void **) &pb);
+ }
+
+ if (rt != LDAP_SUCCESS)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "add_state_entry: "
+ "add operation failed; LDAP error - %d.\n", rt);
+ return UUID_LDAP_ERROR;
+ }
+
+ slapi_log_error (SLAPI_LOG_HOUSE, MODULE, "add_state_entry: "
+ "successfully added generator's state entry");
+
+ return UUID_SUCCESS;
+}
+
+/* modify_state_entry -- modify state entry in the dit */
+static int modify_state_entry ()
+{
+ int res;
+ Slapi_Mods mods;
+ struct berval *vals[2];
+ struct berval val;
+ Slapi_PBlock *pb;
+
+ val.bv_val = (char*)&(_state.genstate);
+ val.bv_len = sizeof (_state.genstate);
+ vals[0] = &val;
+ vals[1] = NULL;
+
+ slapi_mods_init (&mods, 1);
+ slapi_mods_add_modbvps(&mods, LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, STATE_ATTR, vals);
+ pb = slapi_modify_internal(slapi_sdn_get_ndn (_state.configDN),
+ slapi_mods_get_ldapmods_byref(&mods), NULL, 0);
+ slapi_mods_done(&mods);
+
+ if (pb == NULL)
+ {
+ /* the only time NULL pb is returned is when memory allocation fails */
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "modify_state_entry: "
+ "NULL pblock returned from search\n");
+ return UUID_MEMORY_ERROR;
+ }
+
+ slapi_pblock_get(pb, SLAPI_PLUGIN_INTOP_RESULT, &res);
+ slapi_pblock_destroy(pb);
+ if (res != LDAP_SUCCESS)
+ {
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "modify_state_entry: "
+ "update operation failed; LDAP error - %d.\n", res);
+
+ return UUID_LDAP_ERROR;
+ }
+
+ slapi_log_error (SLAPI_LOG_HOUSE, MODULE, "modify_state_entry: "
+ "successfully updated generator's state entry");
+ return UUID_SUCCESS;
+}
+
+/* update_time -- updates time portion of the generators state
+ for singlethreaded generation
+*/
+static uuid_time_t update_time()
+{
+ uuid_time_t time_now;
+
+ get_system_time(&time_now);
+
+ /* time was turned back - need to change clocksequence */
+ if (time_now < _state.genstate.timestamp)
+ {
+ _state.genstate.clockseq ++;
+ _state.genstate.timestamp = time_now;
+ _state.time_seq = 0;
+ return _state.genstate.timestamp;
+ }
+
+ /* go into loop if the time has not changed since last call */
+ while (time_now == _state.genstate.timestamp)
+ {
+ /* if we still have sequence numbers to give to the
+ timestamp, use it and get out of the loop */
+ if (_state.time_seq < SEQ_PER_SEC - 1)
+ {
+ _state.time_seq ++;
+ break;
+ }
+
+ /* this should never happen because we don't generate more that 10 mln ids/sec */
+ DS_Sleep (PR_MillisecondsToInterval(500));
+ get_system_time(&time_now);
+ }
+
+ /* system time has changed - clear sequence number and
+ update last time */
+ if (time_now > _state.genstate.timestamp)
+ {
+ _state.time_seq = 0;
+ _state.genstate.timestamp = time_now;
+ }
+
+ return _state.genstate.timestamp + _state.time_seq;
+}
+
+/* update_time_mt -- this function updates time sequence part of generators state.
+ This function should be used in the multithreaded environment
+ only.
+*/
+static int update_time_mt (uuid_time_t *timestamp, unsigned16 *clock_seq)
+{
+
+ PR_Lock (_state.lock);
+
+ /* we ran out time sequence numbers because
+ uuid_update_state function is not called
+ frequently enough */
+ if (_state.time_seq >= SEQ_PER_SEC - 1)
+ {
+ _state.time_seq = NEED_TIME_UPDATE;
+ slapi_log_error (SLAPI_LOG_FATAL, MODULE, "update_time_mt: "
+ "ran out of time sequence numbers; "
+ "uuid_update_state must be called\n");
+
+ PR_Unlock (_state.lock);
+ return (UUID_TIME_ERROR);
+ }
+
+ _state.time_seq++;
+
+ *timestamp = _state.genstate.timestamp + _state.time_seq;
+ *clock_seq = _state.genstate.clockseq;
+
+ PR_Unlock (_state.lock);
+
+ return UUID_SUCCESS;
+}
+
+/* format_uuid_v1 -- make a UUID from the timestamp, clockseq,
+ and node ID
+*/
+static void format_uuid_v1(guid_t * uuid, uuid_time_t timestamp, unsigned16 clock_seq)
+{
+ /* Construct a version 1 uuid with the information we've gathered
+ * plus a few constants. */
+
+ uuid->time_low = (unsigned32)(timestamp & 0xFFFFFFFF);
+ uuid->time_mid = (unsigned16)((timestamp >> 32) & 0xFFFF);
+ uuid->time_hi_and_version = (unsigned16)
+ ((timestamp >> 48) & 0x0FFF);
+ uuid->time_hi_and_version |= (1 << 12);
+ uuid->clock_seq_low = clock_seq & 0xFF;
+ uuid->clock_seq_hi_and_reserved = (unsigned8)(clock_seq & 0x3F00) >> 8;
+ uuid->clock_seq_hi_and_reserved |= 0x80;
+ memcpy(&uuid->node, &_state.genstate.node, sizeof (uuid->node));
+}
+
+/* format_uuid_v3 -- make a UUID from a (pseudo)random 128 bit number
+*/
+static void format_uuid_v3(guid_t * uuid, unsigned char hash[16])
+{
+ /* Construct a version 3 uuid with the (pseudo-)random number
+ * plus a few constants. */
+
+ memcpy(uuid, hash, sizeof(guid_t));
+
+ /* convert UUID to local byte order */
+ ntohl(uuid->time_low);
+ ntohs(uuid->time_mid);
+ ntohs(uuid->time_hi_and_version);
+
+ /* put in the variant and version bits */
+ uuid->time_hi_and_version &= 0x0FFF;
+ uuid->time_hi_and_version |= (3 << 12);
+ uuid->clock_seq_hi_and_reserved &= 0x3F;
+ uuid->clock_seq_hi_and_reserved |= 0x80;
+}
+
+/* system dependent call to get IEEE node ID.
+ This sample implementation generates a random node ID
+ Assumes that configDir was tested for validity by
+ the higher layer
+*/
+static int get_node_identifier (uuid_node_t *node)
+{
+ unsigned char seed[16]= {0};
+
+#ifdef USE_NIC
+ /* ONREPL - code to use NIC address would go here; Currently, we use
+ cryptographic random number to avoid state sharing among
+ servers running on the same host. See UniqueID Generator
+ docs for more info.
+ */
+#endif
+ get_random_info(seed);
+ seed[0] |= 0x80;
+ memcpy (node, seed, sizeof (uuid_node_t));
+
+ return UUID_SUCCESS;
+}
+
+/* call to get the current system time. Returned as 100ns ticks
+ since Oct 15, 1582, but resolution may be less than 100ns.
+*/
+
+static void get_system_time(uuid_time_t *uuid_time)
+{
+ time_t cur_time;
+
+ cur_time = current_time ();
+
+ /* Offset between UUID formatted times and time() formatted times.
+ UUID UTC base time is October 15, 1582. time() base time is January 1, 1970.*/
+ *uuid_time = cur_time * SEQ_PER_SEC + I64(0x01B21DD213814000);
+}
+
+/* ONREPL */
+
+/* true_random -- generate a crypto-quality random number.
+*/
+static unsigned16 true_random(void)
+{
+ static int inited = 0;
+
+ if (!inited)
+ {
+ uuid_seed = slapi_rand();
+ inited = 1;
+ }
+
+ return (slapi_rand_r(&uuid_seed));
+}
+
+static void get_random_info(unsigned char seed[16])
+{
+ slapi_rand_array(seed, sizeof(seed));
+}
diff --git a/ldap/servers/slapd/uuid.h b/ldap/servers/slapd/uuid.h
new file mode 100644
index 00000000..403b8ed7
--- /dev/null
+++ b/ldap/servers/slapd/uuid.h
@@ -0,0 +1,116 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* uuid.h - interface to uuid layer. UUID is generated in accordance
+ with UUIDs and GUIDs IETF draft
+ */
+
+/*
+** Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
+** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
+** Digital Equipment Corporation, Maynard, Mass.
+** Copyright (c) 1998 Microsoft.
+** To anyone who acknowledges that this file is provided "AS IS"
+** without any express or implied warranty: permission to use, copy,
+** modify, and distribute this file for any purpose is hereby
+** granted without fee, provided that the above copyright notices and
+** this notice appears in all source code copies, and that none of
+** the names of Open Software Foundation, Inc., Hewlett-Packard
+** Company, or Digital Equipment Corporation be used in advertising
+** or publicity pertaining to distribution of the software without
+** specific, written prior permission. Neither Open Software
+** Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital Equipment
+** Corporation makes any representations about the suitability of
+** this software for any purpose.
+*/
+
+
+#ifndef UUID_H
+#define UUID_H
+
+/* Set this to what your compiler uses for 64 bit data type */
+#ifdef _WIN32
+#define unsigned64_t unsigned __int64
+#define I64(C) C
+#else
+#define unsigned64_t unsigned long long
+#define I64(C) C##LL
+#endif
+
+/***** uuid related data types *****/
+/*
+ * DBDB These types were broken on 64-bit architectures
+ * This file has been modified to fix that problem.
+ */
+#if defined(__LP64__) || defined (_LP64)
+typedef unsigned int unsigned32;
+#else
+typedef unsigned long unsigned32;
+#endif
+typedef unsigned short unsigned16;
+typedef unsigned char unsigned8;
+typedef unsigned64_t uuid_time_t;
+typedef struct
+{
+ char nodeID[6];
+} uuid_node_t;
+
+typedef struct _guid_t
+{
+ unsigned32 time_low;
+ unsigned16 time_mid;
+ unsigned16 time_hi_and_version;
+ unsigned8 clock_seq_hi_and_reserved;
+ unsigned8 clock_seq_low;
+ PRUint8 node[6];
+} guid_t;
+
+enum
+{
+ UUID_SUCCESS, /* operation succeded */
+ UUID_IO_ERROR, /* file I/O failed */
+ UUID_LOCK_ERROR, /* lock creation failed */
+ UUID_TIME_ERROR, /* ran out of time sequence numbers, need
+ time update to generate the id */
+ UUID_BAD_FORMAT, /* data in a string buffer is not in UUID format */
+ UUID_MEMORY_ERROR, /* memory allocation failed */
+ UUID_LDAP_ERROR, /* LDAP operation failed */
+ UUID_NOTFOUND, /* generator state is missing */
+ UUID_FORMAT_ERROR, /* state entry does not contain right data */
+ UUID_UNKNOWN_ERROR
+};
+
+/***** uuid interface *****/
+
+/* uuid_init -- initialize uuid layer */
+int uuid_init (const char *configDir, const Slapi_DN *configDN, PRBool mtGen);
+
+/* uuid_cleanup -- cleanup of uuid layer */
+void uuid_cleanup ();
+
+/* uuid_create -- generate a UUID */
+int uuid_create(guid_t *uuid);
+
+/* uuid_compare -- Compare two UUID's "lexically" and return
+ -1 u1 is lexically before u2
+ 0 u1 is equal to u2
+ 1 u1 is lexically after u2
+ Note: lexical ordering is not temporal ordering!
+*/
+int uuid_compare(const guid_t *u1, const guid_t *u2);
+
+/* uuid_format -- converts UUID to its string representation and stores it
+ in the buff. buff must be at list 40 bytes long
+*/
+void uuid_format(const guid_t *u, char *buff);
+
+/* uuid_create_from_name -- create a UUID using a "name" from a "name space" */
+void uuid_create_from_name(guid_t * uuid, /* resulting UUID */
+ const guid_t nsid, /* UUID to serve as context, so identical
+ names from different name spaces generate
+ different UUIDs */
+ const void * name, /* the name from which to generate a UUID */
+ int namelen); /* the length of the name */
+#endif
diff --git a/ldap/servers/slapd/value.c b/ldap/servers/slapd/value.c
new file mode 100644
index 00000000..8e2a31ef
--- /dev/null
+++ b/ldap/servers/slapd/value.c
@@ -0,0 +1,460 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* value.c - routines for dealing with values */
+
+#undef DEBUG /* disable counters */
+#include <prcountr.h>
+#include "slap.h"
+#include "slapi-private.h"
+
+/*
+ * Functions needed when a berval is embedded in a struct or
+ * allocated on the stack rather than the heap.
+ */
+
+static void ber_bvdone(struct berval *bvp)
+{
+ if (bvp == NULL) return;
+
+ slapi_ch_free_string(&bvp->bv_val);
+ bvp->bv_len = 0;
+
+ return;
+}
+
+static void ber_bvcpy(struct berval *bvd, const struct berval *bvs)
+{
+ size_t len;
+
+ if (bvd == NULL || bvs == NULL) return;
+
+ len = bvs->bv_len;
+ bvd->bv_val = slapi_ch_malloc(len+1);
+ bvd->bv_len = len;
+ memcpy(bvd->bv_val, bvs->bv_val, len);
+ bvd->bv_val[len] = '\0';
+
+ return;
+}
+
+/* <=========================== Slapi_Value ==========================> */
+
+#ifdef VALUE_DEBUG
+static void value_dump( const Slapi_Value *value, const char *text);
+#define VALUE_DUMP(value,name) value_dump(value,name)
+#else
+#define VALUE_DUMP(value,name) ((void)0)
+#endif
+
+static int counters_created= 0;
+PR_DEFINE_COUNTER(slapi_value_counter_created);
+PR_DEFINE_COUNTER(slapi_value_counter_deleted);
+PR_DEFINE_COUNTER(slapi_value_counter_exist);
+
+Slapi_Value *
+slapi_value_new()
+{
+ return value_new(NULL,CSN_TYPE_NONE,NULL);
+}
+
+Slapi_Value *
+slapi_value_new_berval(const struct berval *bval)
+{
+ return value_new(bval,CSN_TYPE_NONE,NULL);
+}
+
+Slapi_Value *
+slapi_value_new_value(const Slapi_Value *v)
+{
+ return slapi_value_dup(v);
+}
+
+Slapi_Value *
+slapi_value_new_string(const char *s)
+{
+ Slapi_Value *v= value_new(NULL,CSN_TYPE_UNKNOWN,NULL);
+ slapi_value_set_string(v, s);
+ return v;
+}
+
+Slapi_Value *
+slapi_value_new_string_passin(char *s)
+{
+ Slapi_Value *v= value_new(NULL,CSN_TYPE_UNKNOWN,NULL);
+ slapi_value_set_string_passin(v, s);
+ return v;
+}
+
+Slapi_Value *
+slapi_value_init(Slapi_Value *v)
+{
+ return value_init(v,NULL,CSN_TYPE_NONE,NULL);
+}
+
+Slapi_Value *
+slapi_value_init_berval(Slapi_Value *v, struct berval *bval)
+{
+ return value_init(v,bval,CSN_TYPE_NONE,NULL);
+}
+
+Slapi_Value *
+slapi_value_init_string(Slapi_Value *v,const char *s)
+{
+ value_init(v,NULL,CSN_TYPE_UNKNOWN,NULL);
+ slapi_value_set_string(v,s);
+ return v;
+}
+
+Slapi_Value *
+slapi_value_init_string_passin(Slapi_Value *v, char *s)
+{
+ value_init(v,NULL,CSN_TYPE_UNKNOWN,NULL);
+ slapi_value_set_string_passin(v,s);
+ return v;
+}
+
+Slapi_Value *
+slapi_value_dup(const Slapi_Value *v)
+{
+ Slapi_Value *newvalue= value_new(&v->bv,CSN_TYPE_UNKNOWN,NULL);
+ newvalue->v_csnset= csnset_dup(v->v_csnset);
+ return newvalue;
+
+}
+
+Slapi_Value *
+value_new(const struct berval *bval,CSNType t,const CSN *csn)
+{
+ Slapi_Value *v;
+ v = (Slapi_Value *)slapi_ch_malloc(sizeof(Slapi_Value));
+ value_init(v, bval, t, csn);
+ if(!counters_created)
+ {
+ PR_CREATE_COUNTER(slapi_value_counter_created,"Slapi_Value","created","");
+ PR_CREATE_COUNTER(slapi_value_counter_deleted,"Slapi_Value","deleted","");
+ PR_CREATE_COUNTER(slapi_value_counter_exist,"Slapi_Value","exist","");
+ counters_created= 1;
+ }
+ PR_INCREMENT_COUNTER(slapi_value_counter_created);
+ PR_INCREMENT_COUNTER(slapi_value_counter_exist);
+ VALUE_DUMP(v,"value_new");
+ return v;
+}
+
+Slapi_Value *
+value_init(Slapi_Value *v, const struct berval *bval,CSNType t,const CSN *csn)
+{
+ PR_ASSERT(v!=NULL);
+ memset(v,0,sizeof(Slapi_Value));
+ if(csn!=NULL)
+ {
+ value_update_csn(v,t,csn);
+ }
+ slapi_value_set_berval(v,bval);
+ return v;
+}
+
+void
+slapi_value_free(Slapi_Value **v)
+{
+ if(v!=NULL && *v!=NULL)
+ {
+ VALUE_DUMP(*v,"value_free");
+ value_done(*v);
+ slapi_ch_free((void **)v);
+ *v= NULL;
+ PR_INCREMENT_COUNTER(slapi_value_counter_deleted);
+ PR_DECREMENT_COUNTER(slapi_value_counter_exist);
+ }
+}
+
+void
+value_done(Slapi_Value *v)
+{
+ if(v!=NULL)
+ {
+ if(NULL != v->v_csnset)
+ {
+ csnset_free(&(v->v_csnset));
+ }
+ ber_bvdone(&v->bv);
+ }
+}
+
+const CSNSet *
+value_get_csnset ( const Slapi_Value *value)
+{
+ if (value)
+ return value->v_csnset;
+ else
+ return NULL;
+}
+
+const CSN *
+value_get_csn( const Slapi_Value *value, CSNType t)
+{
+ const CSN *csn= NULL;
+ if(NULL!=value)
+ {
+ csn= csnset_get_csn_of_type(value->v_csnset, t);
+ }
+ return csn;
+}
+
+int
+value_contains_csn( const Slapi_Value *value, CSN *csn)
+{
+ int r= 0;
+ if(NULL!=value)
+ {
+ r= csnset_contains(value->v_csnset, csn);
+ }
+ return r;
+}
+
+Slapi_Value *
+value_update_csn( Slapi_Value *value, CSNType t, const CSN *csn)
+{
+ if(value!=NULL)
+ {
+ csnset_update_csn(&value->v_csnset,t,csn);
+ }
+ return value;
+}
+
+Slapi_Value *
+value_add_csn( Slapi_Value *value, CSNType t, const CSN *csn)
+{
+ if(value!=NULL)
+ {
+ csnset_add_csn(&value->v_csnset,t,csn);
+ }
+ return value;
+}
+
+const struct berval *
+slapi_value_get_berval( const Slapi_Value *value )
+{
+ const struct berval *bval= NULL;
+ if(NULL != value)
+ {
+ bval = &value->bv;
+ }
+ return bval;
+}
+
+Slapi_Value *
+slapi_value_set( Slapi_Value *value, void *val, unsigned long len)
+{
+ struct berval bv;
+ bv.bv_len= len;
+ bv.bv_val= (void*)val; /* We cast away the const, but we're not going to change anything */
+ slapi_value_set_berval( value, &bv);
+ return value;
+}
+
+Slapi_Value *
+slapi_value_set_value( Slapi_Value *value, const Slapi_Value *vfrom)
+{
+ slapi_value_set_berval( value, &vfrom->bv );
+ csnset_free(&value->v_csnset);
+ value->v_csnset= csnset_dup(vfrom->v_csnset);
+ return value;
+}
+
+Slapi_Value *
+value_remove_csn( Slapi_Value *value, CSNType t)
+{
+ if(value!=NULL)
+ {
+ csnset_remove_csn(&value->v_csnset,t);
+ }
+ return value;
+}
+
+Slapi_Value *
+slapi_value_set_berval( Slapi_Value *value, const struct berval *bval )
+{
+ if(value!=NULL)
+ {
+ ber_bvdone(&value->bv);
+ if(bval!=NULL)
+ {
+ ber_bvcpy(&value->bv, bval);
+ }
+ }
+ return value;
+}
+
+int
+slapi_value_set_string(Slapi_Value *value, const char *strVal)
+{
+ return slapi_value_set_string_passin(value, slapi_ch_strdup(strVal));
+}
+
+int
+slapi_value_set_string_passin(Slapi_Value *value, char *strVal)
+{
+ int rc= -1;
+ if(NULL != value)
+ {
+ ber_bvdone(&value->bv);
+ value->bv.bv_val = strVal;
+ value->bv.bv_len = strlen(strVal);
+ rc= 0;
+ }
+ return rc;
+}
+
+int
+slapi_value_set_int(Slapi_Value *value, int intVal)
+{
+ int rc= -1;
+ if(NULL != value)
+ {
+ char valueBuf[80];
+ ber_bvdone(&value->bv);
+ sprintf(valueBuf,"%d",intVal);
+ value->bv.bv_val = slapi_ch_strdup(valueBuf);
+ value->bv.bv_len = strlen(value->bv.bv_val);
+ rc= 0;
+ }
+ return rc;
+}
+
+/*
+ * Warning: The value may not be '\0' terminated!
+ * Make sure that you know this is a C string.
+ */
+const char *
+slapi_value_get_string(const Slapi_Value *value)
+{
+ const char *r= NULL;
+ if(value!=NULL)
+ {
+ r= (const char*)value->bv.bv_val;
+ }
+ return r;
+}
+
+size_t
+slapi_value_get_length(const Slapi_Value *value)
+{
+ size_t r= 0;
+ if(NULL!=value)
+ {
+ r= value->bv.bv_len;
+ }
+ return r;
+}
+
+int
+slapi_value_get_int(const Slapi_Value *value)
+{
+ int r= 0;
+ if(NULL!=value)
+ {
+ char *p;
+ p = slapi_ch_malloc(value->bv.bv_len + 1);
+ memcpy (p, value->bv.bv_val, value->bv.bv_len);
+ p [value->bv.bv_len] = '\0';
+ r= atoi(p);
+ slapi_ch_free((void **)&p);
+ }
+ return r;
+}
+
+unsigned int
+slapi_value_get_uint(const Slapi_Value *value)
+{
+ unsigned int r= 0;
+ if(NULL!=value)
+ {
+ char *p;
+ p = slapi_ch_malloc(value->bv.bv_len + 1);
+ memcpy (p, value->bv.bv_val, value->bv.bv_len);
+ p [value->bv.bv_len] = '\0';
+ r= (unsigned int)atoi(p);
+ slapi_ch_free((void **)&p);
+ }
+ return r;
+}
+
+long
+slapi_value_get_long(const Slapi_Value *value)
+{
+ long r= 0;
+ if(NULL!=value)
+ {
+ char *p;
+ p = slapi_ch_malloc(value->bv.bv_len + 1);
+ memcpy (p, value->bv.bv_val, value->bv.bv_len);
+ p [value->bv.bv_len] = '\0';
+ r = atol(p);
+ slapi_ch_free((void **)&p);
+ }
+ return r;
+}
+
+unsigned long
+slapi_value_get_ulong(const Slapi_Value *value)
+{
+ unsigned long r= 0;
+ if(NULL!=value)
+ {
+ char *p;
+ p = slapi_ch_malloc(value->bv.bv_len + 1);
+ memcpy (p, value->bv.bv_val, value->bv.bv_len);
+ p [value->bv.bv_len] = '\0';
+ r = (unsigned long)atol(p);
+ slapi_ch_free((void **)&p);
+ }
+ return r;
+}
+
+int
+slapi_value_compare(const Slapi_Attr *a,const Slapi_Value *v1,const Slapi_Value *v2)
+{
+ int r= 0;
+ if(v1!=NULL && v2!=NULL)
+ {
+ r= slapi_attr_value_cmp( a, &v1->bv, &v2->bv);
+ }
+ else if(v1!=NULL && v2==NULL)
+ {
+ r= 1; /* v1>v2 */
+ }
+ else if (v1==NULL && v2!=NULL)
+ {
+ r= -1; /* v1<v2 */
+ }
+ else /* (v1==NULL && v2==NULL) */
+ {
+ r= 0; /* The same */
+ }
+ return r;
+}
+
+size_t
+value_size(const Slapi_Value *v)
+{
+ size_t s= v->bv.bv_len;
+ s += csnset_size(v->v_csnset);
+ s += sizeof(Slapi_Value);
+ return s;
+}
+
+
+#ifdef VALUE_DEBUG
+static void
+value_dump( const Slapi_Value *value, const char *text)
+{
+ LDAPDebug( LDAP_DEBUG_ANY, "Slapi_Value %s ptr=%lx\n", text, value, 0);
+ /* JCM - Dump value contents... */
+}
+#endif
+
diff --git a/ldap/servers/slapd/valueset.c b/ldap/servers/slapd/valueset.c
new file mode 100644
index 00000000..a388fc38
--- /dev/null
+++ b/ldap/servers/slapd/valueset.c
@@ -0,0 +1,1303 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* valueset.c - routines for dealing with value sets */
+
+#include "slap.h"
+#include "slapi-private.h"
+
+/* <=========================== Berval Array ==========================> */
+
+/*
+ * vals - The existing values.
+ * addval - The value to add.
+ * nvals - The number of existing values.
+ * maxvals - The number of elements in the existing values array.
+ */
+void
+bervalarray_add_berval_fast(
+ struct berval ***vals,
+ const struct berval *addval,
+ int nvals,
+ int *maxvals
+)
+{
+ int need = nvals + 2;
+ if(need>*maxvals)
+ {
+ if (*maxvals==0)
+ {
+ *maxvals = 2;
+ }
+ while ( *maxvals < need )
+ {
+ *maxvals *= 2;
+ }
+ if(*vals==NULL)
+ {
+ *vals = (struct berval **) slapi_ch_malloc( *maxvals * sizeof(struct berval *));
+ }
+ else
+ {
+ *vals = (struct berval **) slapi_ch_realloc( (char *) *vals, *maxvals * sizeof(struct berval *));
+ }
+ }
+ (*vals)[nvals] = ber_bvdup( (struct berval *)addval );
+ (*vals)[nvals+1] = NULL;
+}
+
+/* <=========================== Value Array ==========================> */
+
+/*
+ * vals - The existing values.
+ * addval - The value to add.
+ * nvals - The number of existing values.
+ * maxvals - The number of elements in the existing values array.
+ */
+void
+valuearray_add_value_fast(Slapi_Value ***vals,
+ Slapi_Value *addval,
+ int nvals,
+ int *maxvals,
+ int exact, /* Don't create an array bigger than needed */
+ int passin) /* The values are being passed in */
+{
+ Slapi_Value *oneval[2];
+ oneval[0]= addval;
+ oneval[1]= NULL;
+ valuearray_add_valuearray_fast(vals,oneval,nvals,1,maxvals,exact,passin);
+}
+
+void
+valuearray_add_valuearray_fast(Slapi_Value ***vals,
+ Slapi_Value **addvals,
+ int nvals,
+ int naddvals,
+ int *maxvals,
+ int exact, /* Don't create an array bigger than needed */
+ int passin) /* The values are being passed in */
+{
+ int i, j;
+ int allocate= 0;
+ int need = nvals + naddvals + 1;
+ if(exact)
+ {
+ /* Create an array exactly the right size. */
+ if(need>*maxvals)
+ {
+ allocate= need;
+ }
+ }
+ else
+ {
+ if (*maxvals==0) /* empty; create with 4 by default */
+ {
+ allocate= 4;
+ }
+ else if (need > *maxvals)
+ {
+ /* Exponentially expand the array */
+ allocate= *maxvals;
+
+ while ( allocate < need )
+ {
+ allocate *= 2;
+ }
+ }
+ }
+ if(allocate>0)
+ {
+ if(*vals==NULL)
+ {
+ *vals = (Slapi_Value **) slapi_ch_malloc( allocate * sizeof(Slapi_Value *));
+ }
+ else
+ {
+ *vals = (Slapi_Value **) slapi_ch_realloc( (char *) *vals, allocate * sizeof(Slapi_Value *));
+ }
+ *maxvals= allocate;
+ }
+ for ( i = 0, j = 0; i < naddvals; i++)
+ {
+ if ( addvals[i]!=NULL )
+ {
+ if(passin)
+ {
+ /* We consume the values */
+ (*vals)[nvals + j] = addvals[i];
+ }
+ else
+ {
+ /* We copy the values */
+ (*vals)[nvals + j] = slapi_value_dup(addvals[i]);
+ }
+ j++;
+ }
+ }
+ (*vals)[nvals + j] = NULL;
+}
+
+void
+valuearray_add_value(Slapi_Value ***vals, const Slapi_Value *addval)
+{
+ Slapi_Value *oneval[2];
+ oneval[0]= (Slapi_Value*)addval;
+ oneval[1]= NULL;
+ valuearray_add_valuearray(vals,oneval,0);
+}
+
+void
+valuearray_add_valuearray(Slapi_Value ***vals, Slapi_Value **addvals, PRUint32 flags)
+{
+ int valslen;
+ int addvalslen;
+ int maxvals;
+
+ addvalslen= valuearray_count(addvals);
+ if(*vals == NULL)
+ {
+ valslen= 0;
+ maxvals= 0;
+ }
+ else
+ {
+ valslen= valuearray_count(*vals);
+ maxvals= valslen+1;
+ }
+ valuearray_add_valuearray_fast(vals,addvals,valslen,addvalslen,&maxvals,1/*Exact*/,flags & SLAPI_VALUE_FLAG_PASSIN);
+}
+
+int
+valuearray_count( Slapi_Value **va)
+{
+ int i=0;
+ if(va!=NULL)
+ {
+ while(NULL != va[i]) i++;
+ }
+ return(i);
+}
+
+int
+valuearray_isempty( Slapi_Value **va)
+{
+ return va==NULL || va[0]==NULL;
+}
+
+/*
+ * JCM SLOW FUNCTION
+ *
+ * WARNING: Use only if you absolutley need to...
+ * This function mostly exists to map from the old slapi berval
+ * based interface to the new Slapi_Value based interfaces.
+ */
+int
+valuearray_init_bervalarray(struct berval **bvals, Slapi_Value ***cvals)
+{
+ int n;
+ for(n=0; bvals != NULL && bvals[n] != NULL; n++);
+ if(n==0)
+ {
+ *cvals = NULL;
+ }
+ else
+ {
+ int i;
+ *cvals = (Slapi_Value **) slapi_ch_malloc((n + 1) * sizeof(Slapi_Value *));
+ for(i=0;i<n;i++)
+ {
+ (*cvals)[i] = slapi_value_new_berval(bvals[i]);
+ }
+ (*cvals)[i] = NULL;
+ }
+ return n;
+}
+
+/*
+ * JCM SLOW FUNCTION
+ *
+ * Use only if you absolutley need to...
+ * This function mostly exists to map from the old slapi berval
+ * based interface to the new Slapi_Value based interfaces.
+ */
+int
+valuearray_get_bervalarray(Slapi_Value **cvals,struct berval ***bvals)
+{
+ int i,n;
+ n= valuearray_count(cvals);
+ if (0 == n)
+ {
+ *bvals = NULL;
+ }
+ else
+ {
+ *bvals = (struct berval **)slapi_ch_malloc((n + 1) * sizeof(struct berval *));
+ for(i=0;i<n;i++)
+ {
+ (*bvals)[i] = ber_bvdup(slapi_value_get_berval(cvals[i]));
+ }
+ (*bvals)[i] = NULL;
+ }
+ return(0);
+}
+
+void
+valuearray_free(Slapi_Value ***va)
+{
+ if(va!=NULL && *va!=NULL)
+ {
+ int i;
+ for(i=0; (*va)[i]!=NULL; i++)
+ {
+ slapi_value_free(&(*va)[i]);
+ }
+ slapi_ch_free((void **)va);
+ *va = NULL;
+ }
+}
+
+int
+valuearray_next_value( Slapi_Value **va, int index, Slapi_Value **v)
+{
+ int r= -1;
+ if(va!=NULL && va[0]!=NULL)
+ {
+ r= index+1;
+ *v= va[r];
+ if(*v==NULL)
+ {
+ r= -1;
+ }
+ }
+ else
+ {
+ *v= NULL;
+ }
+ return r;
+}
+
+int
+valuearray_first_value( Slapi_Value **va, Slapi_Value **v )
+{
+ return valuearray_next_value( va, -1, v);
+}
+
+/*
+ * Find the value and return an index number to it.
+ */
+int
+valuearray_find(const Slapi_Attr *a, Slapi_Value **va, const Slapi_Value *v)
+{
+ int i= 0;
+ int found= -1;
+ while(found==-1 && va!=NULL && va[i]!=NULL)
+ {
+ if(slapi_value_compare( a, v, va[i])==0)
+ {
+ found= i;
+ }
+ else
+ {
+ i++;
+ }
+ }
+ return found;
+}
+
+/*
+ * Shunt up the array to cover the value to remove.
+ */
+void
+valuearray_remove_value_atindex(Slapi_Value **va, int index)
+{
+ if(va!=NULL && va[0]!=NULL)
+ {
+ int k;
+ for ( k = index + 1; va[k] != NULL; k++ )
+ {
+ va[k - 1] = va[k];
+ }
+ va[k - 1] = NULL;
+ }
+}
+
+/*
+ * Find the value in the array,
+ * shunt up the array to cover it,
+ * return a ptr to the value.
+ */
+Slapi_Value *
+valuearray_remove_value(const Slapi_Attr *a, Slapi_Value **va, const Slapi_Value *v)
+{
+ Slapi_Value *r= NULL;
+ int i= 0;
+ i= valuearray_find(a, va, v);
+ if(i!=-1)
+ {
+ r= va[i];
+ valuearray_remove_value_atindex(va,i);
+ }
+ return r;
+}
+
+/*
+ * Remove any values older than the CSN.
+ */
+int
+valuearray_purge(Slapi_Value ***va, const CSN *csn)
+{
+ int numValues=0;
+ int i=0;
+ int nextValue=0;
+
+ PR_ASSERT(va!=NULL && *va!=NULL);
+
+ /* Loop over all the values freeing the old ones. */
+ for(i=0; (*va)[i]; i++)
+ {
+ csnset_purge(&((*va)[i]->v_csnset),csn);
+ if ((*va)[i]->v_csnset == NULL)
+ {
+ slapi_value_free(&(*va)[i]);
+ (*va)[i] = NULL;
+ }
+ }
+ /* Now compact the value list. */
+ numValues=i;
+ nextValue = 0;
+ i = 0;
+ for(i=0;i<numValues;i++)
+ {
+ while((nextValue < numValues) && (NULL == (*va)[nextValue]))
+ {
+ nextValue++;
+ }
+ if(nextValue < numValues)
+ {
+ (*va)[i] = (*va)[nextValue];
+ nextValue++;
+ }
+ else
+ {
+ break;
+ }
+ }
+ (*va)[i] = NULL;
+
+ /* All the values were deleted, we can discard the whole array. */
+ if(NULL == (*va)[0])
+ {
+ slapi_ch_free((void**)va);
+ *va= NULL;
+ }
+
+ return(0);
+}
+
+size_t
+valuearray_size(Slapi_Value **va)
+{
+ size_t s= 0;
+ if(va!=NULL && va[0]!=NULL)
+ {
+ int i;
+ for (i = 0; va[i]; i++)
+ {
+ s += value_size(va[i]);
+ }
+ s += (i + 1) * sizeof(Slapi_Value*);
+ }
+ return s;
+}
+
+void
+valuearray_update_csn(Slapi_Value **va, CSNType t, const CSN *csn)
+{
+ int i;
+ for (i = 0; va!=NULL && va[i]; i++)
+ {
+ value_update_csn(va[i],t,csn);
+ }
+}
+
+/*
+ * Shunt up the values to cover the empty slots.
+ *
+ * "compressed" means "contains no NULL's"
+ *
+ * Invariant for the outer loop:
+ * va[0..i] is compressed &&
+ * va[n..numvalues] contains just NULL's
+ *
+ * Invariant for the inner loop:
+ * i<j<=k<=n && va[j..k] has been shifted left by (j-i) places &&
+ * va[k..n] remains to be shifted left by (j-i) places
+ *
+ */
+void
+valuearray_compress(Slapi_Value **va,int numvalues)
+{
+ int i = 0;
+ int n= numvalues;
+ while(i<n)
+ {
+ if ( va[i] != NULL ) {
+ i++;
+ } else {
+ int k,j;
+ j = i + 1;
+ /* Find the length of the next run of NULL's */
+ while( j<n && va[j] == NULL) { j++; }
+ /* va[i..j] is all NULL && j<= n */
+ for ( k = j; k<n; k++ )
+ {
+ va[k - (j-i)] = va[k];
+ va[k] = NULL;
+ }
+ /* va[i..n] has been shifted down by j-i places */
+ n = n - (j-i);
+ /*
+ * If va[i] in now non null, then bump i,
+ * if not then we are done anyway (j==n) so can bump it.
+ */
+ i++;
+ }
+ }
+}
+
+/* <=========================== Value Array Fast ==========================> */
+
+void
+valuearrayfast_init(struct valuearrayfast *vaf,Slapi_Value **va)
+{
+ vaf->num= valuearray_count(va);
+ vaf->max= vaf->num;
+ vaf->va= va;
+}
+
+void
+valuearrayfast_done(struct valuearrayfast *vaf)
+{
+ if(vaf->va!=NULL)
+ {
+ int i;
+ for(i=0; i<vaf->num; i++)
+ {
+ slapi_value_free(&vaf->va[i]);
+ }
+ slapi_ch_free((void **)&vaf->va);
+ vaf->num= 0;
+ vaf->max= 0;
+ }
+}
+
+void
+valuearrayfast_add_value(struct valuearrayfast *vaf,const Slapi_Value *v)
+{
+ valuearray_add_value_fast(&vaf->va,(Slapi_Value *)v,vaf->num,&vaf->max,0/*Exact*/,0/*!PassIn*/);
+ vaf->num++;
+}
+
+void
+valuearrayfast_add_value_passin(struct valuearrayfast *vaf,Slapi_Value *v)
+{
+ valuearray_add_value_fast(&vaf->va,v,vaf->num,&vaf->max,0/*Exact*/,1/*PassIn*/);
+ vaf->num++;
+}
+
+void
+valuearrayfast_add_valuearrayfast(struct valuearrayfast *vaf,const struct valuearrayfast *vaf_add)
+{
+ valuearray_add_valuearray_fast(&vaf->va,vaf_add->va,vaf->num,vaf_add->num,&vaf->max,0/*Exact*/,0/*!PassIn*/);
+ vaf->num+= vaf_add->num;
+}
+
+/* <=========================== ValueArrayIndexTree =======================> */
+
+static int valuetree_dupvalue_disallow( caddr_t d1, caddr_t d2 );
+static int valuetree_node_cmp( caddr_t d1, caddr_t d2 );
+static int valuetree_node_free( caddr_t data );
+
+/*
+ * structure used within AVL value trees.
+ */
+typedef struct valuetree_node
+{
+ int index; /* index into the value array */
+ Slapi_Value *sval; /* the actual value */
+} valuetree_node;
+
+/*
+ * Create or update an AVL tree of values that can be used to speed up value
+ * lookups. We store the index keys for the values in the AVL tree so
+ * we can use a trivial comparison function.
+ *
+ * Returns:
+ * LDAP_SUCCESS on success,
+ * LDAP_TYPE_OR_VALUE_EXISTS if the value already exists,
+ * LDAP_OPERATIONS_ERROR for some unexpected failure.
+ *
+ * Sets *valuetreep to the root of the AVL tree that was created. If a
+ * non-zero value is returned, the tree is freed if free_on_error is non-zero
+ * and *valuetreep is set to NULL.
+ */
+int
+valuetree_add_valuearray( const char *type, struct slapdplugin *pi, Slapi_Value **va, Avlnode **valuetreep, int *duplicate_index )
+{
+ int rc= LDAP_SUCCESS;
+
+ PR_ASSERT(type!=NULL);
+ PR_ASSERT(pi!=NULL);
+ PR_ASSERT(valuetreep!=NULL);
+
+ if ( duplicate_index ) {
+ *duplicate_index = -1;
+ }
+
+ if ( !valuearray_isempty(va) )
+ {
+ Slapi_Value **keyvals;
+ /* Convert the value array into key values */
+ if ( slapi_call_syntax_values2keys_sv( pi, (Slapi_Value**)va, &keyvals, LDAP_FILTER_EQUALITY ) != 0 ) /* jcm cast */
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,"slapi_call_syntax_values2keys for attribute %s failed\n", type, 0, 0 );
+ rc= LDAP_OPERATIONS_ERROR;
+ }
+ else
+ {
+ int i;
+ valuetree_node *vaip;
+ for ( i = 0; rc==LDAP_SUCCESS && va[i] != NULL; ++i )
+ {
+ if ( keyvals[i] == NULL )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,"slapi_call_syntax_values2keys for attribute %s did not return enough key values\n", type, 0, 0 );
+ rc= LDAP_OPERATIONS_ERROR;
+ }
+ else
+ {
+ vaip = (valuetree_node *)slapi_ch_malloc( sizeof( valuetree_node ));
+ vaip->index = i;
+ vaip->sval = keyvals[i];
+ if (( rc = avl_insert( valuetreep, vaip, valuetree_node_cmp, valuetree_dupvalue_disallow )) != 0 )
+ {
+ slapi_ch_free( (void **)&vaip );
+ /* Value must already be in there */
+ rc= LDAP_TYPE_OR_VALUE_EXISTS;
+ if ( duplicate_index ) {
+ *duplicate_index = i;
+ }
+ }
+ else
+ {
+ keyvals[i]= NULL;
+ }
+ }
+ }
+ valuearray_free( &keyvals );
+ }
+ }
+ if(rc!=0)
+ {
+ valuetree_free( valuetreep );
+ }
+
+ return rc;
+}
+
+int
+valuetree_add_value( const char *type, struct slapdplugin *pi, const Slapi_Value *v, Avlnode **valuetreep)
+{
+ Slapi_Value *va[2];
+ va[0]= (Slapi_Value*)v;
+ va[1]= NULL;
+ return valuetree_add_valuearray( type, pi, va, valuetreep, NULL);
+}
+
+
+/*
+ *
+ * Find value "v" using AVL tree "valuetree"
+ *
+ * returns LDAP_SUCCESS if "v" was found, LDAP_NO_SUCH_ATTRIBUTE
+ * if "v" was not found and LDAP_OPERATIONS_ERROR if some unexpected error occurs.
+ */
+static int
+valuetree_find( const struct slapi_attr *a, const Slapi_Value *v, Avlnode *valuetree, int *index)
+{
+ const Slapi_Value *oneval[2];
+ Slapi_Value **keyvals;
+ valuetree_node *vaip, tmpvain;
+
+ PR_ASSERT(a!=NULL);
+ PR_ASSERT(a->a_plugin!=NULL);
+ PR_ASSERT(v!=NULL);
+ PR_ASSERT(valuetree!=NULL);
+ PR_ASSERT(index!=NULL);
+
+ if ( a == NULL || a->a_plugin == NULL || v == NULL || valuetree == NULL )
+ {
+ return( LDAP_OPERATIONS_ERROR );
+ }
+
+ keyvals = NULL;
+ oneval[0] = v;
+ oneval[1] = NULL;
+ if ( slapi_call_syntax_values2keys_sv( a->a_plugin, (Slapi_Value**)oneval, &keyvals, LDAP_FILTER_EQUALITY ) != 0 /* jcm cast */
+ || keyvals == NULL
+ || keyvals[0] == NULL )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "valuetree_find_and_replace: "
+ "slapi_call_syntax_values2keys failed for type %s\n",
+ a->a_type, 0, 0 );
+ return( LDAP_OPERATIONS_ERROR );
+ }
+
+ tmpvain.index = 0;
+ tmpvain.sval = keyvals[0];
+ vaip = (valuetree_node *)avl_find( valuetree, &tmpvain, valuetree_node_cmp );
+
+ if ( keyvals != NULL )
+ {
+ valuearray_free( &keyvals );
+ }
+
+ if (vaip == NULL)
+ {
+ return( LDAP_NO_SUCH_ATTRIBUTE );
+ }
+ else
+ {
+ *index= vaip->index;
+ }
+
+ return( LDAP_SUCCESS );
+}
+
+static int
+valuetree_dupvalue_disallow( caddr_t d1, caddr_t d2 )
+{
+ return( 1 );
+}
+
+
+void
+valuetree_free( Avlnode **valuetreep )
+{
+ if ( valuetreep != NULL && *valuetreep != NULL )
+ {
+ avl_free( *valuetreep, valuetree_node_free );
+ *valuetreep = NULL;
+ }
+}
+
+
+static int
+valuetree_node_free( caddr_t data )
+{
+ if ( data!=NULL )
+ {
+ valuetree_node *vaip = (valuetree_node *)data;
+
+ slapi_value_free(&vaip->sval);
+ slapi_ch_free( (void **)&data );
+ }
+ return( 0 );
+}
+
+
+static int
+valuetree_node_cmp( caddr_t d1, caddr_t d2 )
+{
+ const struct berval *bv1, *bv2;
+ int rc;
+
+ bv1 = slapi_value_get_berval(((valuetree_node *)d1)->sval);
+ bv2 = slapi_value_get_berval(((valuetree_node *)d2)->sval);
+
+ if ( bv1->bv_len < bv2->bv_len ) {
+ rc = -1;
+ } else if ( bv1->bv_len > bv2->bv_len ) {
+ rc = 1;
+ } else {
+ rc = memcmp( bv1->bv_val, bv2->bv_val, bv1->bv_len );
+ }
+
+ return( rc );
+}
+
+/* <=========================== Value Set =======================> */
+
+/*
+ * JCM: All of these valueset functions are just forwarded to the
+ * JCM: valuearray functions... waste of time. Inline them!
+ */
+
+Slapi_ValueSet *
+slapi_valueset_new()
+{
+ Slapi_ValueSet *vs = (Slapi_ValueSet *)slapi_ch_calloc(1,sizeof(Slapi_ValueSet));
+
+ if(vs)
+ slapi_valueset_init(vs);
+
+ return vs;
+}
+
+void
+slapi_valueset_init(Slapi_ValueSet *vs)
+{
+ if(vs!=NULL)
+ {
+ vs->va= NULL;
+ }
+}
+
+void
+slapi_valueset_done(Slapi_ValueSet *vs)
+{
+ if(vs!=NULL)
+ {
+ if(vs->va!=NULL)
+ {
+ valuearray_free(&vs->va);
+ vs->va= NULL;
+ }
+ }
+}
+
+void
+slapi_valueset_free(Slapi_ValueSet *vs)
+{
+ if(vs!=NULL)
+ {
+ slapi_valueset_done(vs);
+ slapi_ch_free((void **)&vs);
+ }
+}
+
+void
+slapi_valueset_set_from_smod(Slapi_ValueSet *vs, Slapi_Mod *smod)
+{
+ Slapi_Value **va= NULL;
+ valuearray_init_bervalarray(slapi_mod_get_ldapmod_byref(smod)->mod_bvalues, &va);
+ valueset_set_valuearray_passin(vs, va);
+}
+
+void
+valueset_set_valuearray_byval(Slapi_ValueSet *vs, Slapi_Value **addvals)
+{
+ slapi_valueset_init(vs);
+ valueset_add_valuearray(vs,addvals);
+}
+
+void
+valueset_set_valuearray_passin(Slapi_ValueSet *vs, Slapi_Value **addvals)
+{
+ slapi_valueset_init(vs);
+ vs->va= addvals;
+}
+
+void
+slapi_valueset_set_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2)
+{
+ slapi_valueset_init(vs1);
+ valueset_add_valueset(vs1,vs2);
+}
+
+int
+slapi_valueset_first_value( Slapi_ValueSet *vs, Slapi_Value **v )
+{
+ return valuearray_first_value(vs->va,v);
+}
+
+int
+slapi_valueset_next_value( Slapi_ValueSet *vs, int index, Slapi_Value **v)
+{
+ return valuearray_next_value(vs->va,index,v);
+}
+
+int
+slapi_valueset_count( const Slapi_ValueSet *vs)
+{
+ int r=0;
+ if (NULL != vs)
+ {
+ if(!valuearray_isempty(vs->va))
+ {
+ r= valuearray_count(vs->va);
+ }
+ }
+ return r;
+}
+
+int
+valueset_isempty( const Slapi_ValueSet *vs)
+{
+ return valuearray_isempty(vs->va);
+}
+
+
+Slapi_Value *
+slapi_valueset_find(const Slapi_Attr *a, const Slapi_ValueSet *vs, const Slapi_Value *v)
+{
+ Slapi_Value *r= NULL;
+ if(!valuearray_isempty(vs->va))
+ {
+ int i= valuearray_find(a,vs->va,v);
+ if(i!=-1)
+ {
+ r= vs->va[i];
+ }
+ }
+ return r;
+}
+
+/*
+ * The value is found in the set, removed and returned.
+ * The caller is responsible for freeing the value.
+ */
+Slapi_Value *
+valueset_remove_value(const Slapi_Attr *a, Slapi_ValueSet *vs, const Slapi_Value *v)
+{
+ Slapi_Value *r= NULL;
+ if(!valuearray_isempty(vs->va))
+ {
+ r= valuearray_remove_value(a, vs->va, v);
+ }
+ return r;
+}
+
+/*
+ * Remove any values older than the CSN.
+ */
+int
+valueset_purge(Slapi_ValueSet *vs, const CSN *csn)
+{
+ int r= 0;
+ if(!valuearray_isempty(vs->va))
+ {
+ r= valuearray_purge(&vs->va, csn);
+ }
+ return r;
+}
+
+Slapi_Value **
+valueset_get_valuearray(const Slapi_ValueSet *vs)
+{
+ return (Slapi_Value**)vs->va;
+}
+
+size_t
+valueset_size(const Slapi_ValueSet *vs)
+{
+ size_t s= 0;
+ if(!valuearray_isempty(vs->va))
+ {
+ s= valuearray_size(vs->va);
+ }
+ return s;
+}
+
+/*
+ * The value array is passed in by value.
+ */
+void
+valueset_add_valuearray(Slapi_ValueSet *vs, Slapi_Value **addvals)
+{
+ if(!valuearray_isempty(addvals))
+ {
+ valuearray_add_valuearray(&vs->va, addvals, 0);
+ }
+}
+
+void
+valueset_add_valuearray_ext(Slapi_ValueSet *vs, Slapi_Value **addvals, PRUint32 flags)
+{
+ if(!valuearray_isempty(addvals))
+ {
+ valuearray_add_valuearray(&vs->va, addvals, flags);
+ }
+}
+
+/*
+ * The value is passed in by value.
+ */
+void
+slapi_valueset_add_value(Slapi_ValueSet *vs, const Slapi_Value *addval)
+{
+ valuearray_add_value(&vs->va,addval);
+}
+
+void
+slapi_valueset_add_value_ext(Slapi_ValueSet *vs, Slapi_Value *addval, unsigned long flags)
+{
+ Slapi_Value *oneval[2];
+ oneval[0]= (Slapi_Value*)addval;
+ oneval[1]= NULL;
+ valuearray_add_valuearray(&vs->va, oneval, flags);
+}
+
+/*
+ * The string is passed in by value.
+ */
+void
+valueset_add_string(Slapi_ValueSet *vs, const char *s, CSNType t, const CSN *csn)
+{
+ Slapi_Value v;
+ value_init(&v,NULL,t,csn);
+ slapi_value_set_string(&v,s);
+ valuearray_add_value(&vs->va,&v);
+ value_done(&v);
+}
+
+/*
+ * The value set is passed in by value.
+ */
+void
+valueset_add_valueset(Slapi_ValueSet *vs1, const Slapi_ValueSet *vs2)
+{
+ if (vs1 && vs2)
+ valueset_add_valuearray(vs1, vs2->va);
+}
+
+void
+valueset_remove_string(const Slapi_Attr *a, Slapi_ValueSet *vs, const char *s)
+{
+ Slapi_Value v;
+ value_init(&v,NULL,CSN_TYPE_NONE,NULL);
+ slapi_value_set_string(&v,s);
+ valuearray_remove_value(a,vs->va,&v);
+ value_done(&v);
+}
+
+void
+valueset_update_csn(Slapi_ValueSet *vs, CSNType t, const CSN *csn)
+{
+ if(!valuearray_isempty(vs->va))
+ {
+ valuearray_update_csn(vs->va,t,csn);
+ }
+}
+
+/*
+ * If we are adding or deleting SLAPD_MODUTIL_TREE_THRESHHOLD or more
+ * entries, we use an AVL tree to speed up searching for duplicates or
+ * values we are trying to delete. This threshhold is somewhat arbitrary;
+ * we should really take some measurements to determine an optimal number.
+ */
+#define SLAPD_MODUTIL_TREE_THRESHHOLD 5
+/*
+ * Remove an array of values from a value set.
+ * The removed values are passed back in an array.
+ *
+ * Returns
+ * LDAP_SUCCESS - OK.
+ * LDAP_NO_SUCH_ATTRIBUTE - A value to be deleted was not in the value set.
+ * LDAP_OPERATIONS_ERROR - Something very bad happened.
+ */
+int
+valueset_remove_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestodelete, int flags, Slapi_Value ***va_out)
+{
+ int rc= LDAP_SUCCESS;
+ if(!valuearray_isempty(vs->va))
+ {
+ int numberofvaluestodelete= valuearray_count(valuestodelete);
+ struct valuearrayfast vaf_out;
+ if ( va_out )
+ {
+ valuearrayfast_init(&vaf_out,*va_out);
+ }
+
+ /*
+ * determine whether we should use an AVL tree of values or not
+ */
+ if ( numberofvaluestodelete >= SLAPD_MODUTIL_TREE_THRESHHOLD)
+ {
+ /*
+ * Several values to delete: first build an AVL tree that
+ * holds all of the existing values and use that to find
+ * the values we want to delete.
+ */
+ Avlnode *vtree = NULL;
+ int numberofexistingvalues= slapi_valueset_count(vs);
+ rc= valuetree_add_valuearray( a->a_type, a->a_plugin, vs->va, &vtree, NULL );
+ if ( rc!=LDAP_SUCCESS )
+ {
+ /*
+ * failed while constructing AVL tree of existing
+ * values... something bad happened.
+ */
+ rc= LDAP_OPERATIONS_ERROR;
+ }
+ else
+ {
+ int i;
+ /*
+ * find and mark all the values that are to be deleted
+ */
+ for ( i = 0; rc == LDAP_SUCCESS && valuestodelete[i] != NULL; ++i )
+ {
+ int index= 0;
+ rc = valuetree_find( a, valuestodelete[i], vtree, &index );
+ if(rc==LDAP_SUCCESS)
+ {
+ if(vs->va[index]!=NULL)
+ {
+ /* Move the value to be removed to the out array */
+ if ( va_out )
+ {
+ if (vs->va[index]->v_csnset && (flags & SLAPI_VALUE_FLAG_PRESERVECSNSET))
+ {
+ valuestodelete[i]->v_csnset = csnset_dup (vs->va[index]->v_csnset);
+ }
+ valuearrayfast_add_value_passin(&vaf_out,vs->va[index]);
+ vs->va[index] = NULL;
+ }
+ else
+ {
+ if (flags & SLAPI_VALUE_FLAG_PRESERVECSNSET)
+ {
+ valuestodelete[i]->v_csnset = vs->va[index]->v_csnset;
+ vs->va[index]->v_csnset = NULL;
+ }
+ slapi_value_free ( & vs->va[index] );
+ }
+ }
+ else
+ {
+ /* We already deleted this value... */
+ if((flags & SLAPI_VALUE_FLAG_IGNOREERROR) == 0)
+ {
+ /* ...that's an error. */
+ rc= LDAP_NO_SUCH_ATTRIBUTE;
+ }
+ }
+ }
+ else
+ {
+ /* Couldn't find the value to be deleted */
+ if(rc==LDAP_NO_SUCH_ATTRIBUTE && (flags & SLAPI_VALUE_FLAG_IGNOREERROR ))
+ {
+ rc= LDAP_SUCCESS;
+ }
+ }
+ }
+ valuetree_free( &vtree );
+
+ if ( rc != LDAP_SUCCESS )
+ {
+ LDAPDebug( LDAP_DEBUG_ANY,"could not find value %d for attr %s (%s)\n", i-1, a->a_type, ldap_err2string( rc ));
+ }
+ else
+ {
+ /* Shunt up all the remaining values to cover the deleted ones. */
+ valuearray_compress(vs->va,numberofexistingvalues);
+ }
+ }
+ }
+ else
+ {
+ /* We don't have to delete very many values, so we use brute force. */
+ int i;
+ for ( i = 0; rc==LDAP_SUCCESS && valuestodelete[i] != NULL; ++i )
+ {
+ Slapi_Value *found= valueset_remove_value(a, vs, valuestodelete[i]);
+ if(found!=NULL)
+ {
+ if ( va_out )
+ {
+ if (found->v_csnset && (flags & SLAPI_VALUE_FLAG_PRESERVECSNSET))
+ {
+ valuestodelete[i]->v_csnset = csnset_dup (found->v_csnset);
+ }
+ valuearrayfast_add_value_passin(&vaf_out,found);
+ }
+ else
+ {
+ if (flags & SLAPI_VALUE_FLAG_PRESERVECSNSET)
+ {
+ valuestodelete[i]->v_csnset = found->v_csnset;
+ found->v_csnset = NULL;
+ }
+ slapi_value_free ( & found );
+ }
+ }
+ else
+ {
+ if((flags & SLAPI_VALUE_FLAG_IGNOREERROR) == 0)
+ {
+ LDAPDebug( LDAP_DEBUG_ARGS,"could not find value %d for attr %s\n", i-1, a->a_type, 0 );
+ rc= LDAP_NO_SUCH_ATTRIBUTE;
+ }
+ }
+ }
+ }
+ if ( va_out )
+ {
+ *va_out= vaf_out.va;
+ if(rc!=LDAP_SUCCESS)
+ {
+ valuearray_free(va_out);
+ }
+ }
+ }
+ return rc;
+}
+
+/*
+ * Check if the set of values in the valueset and the valuearray intersect.
+ *
+ * Returns
+ * LDAP_SUCCESS - No intersection.
+ * LDAP_NO_SUCH_ATTRIBUTE - There is an intersection.
+ * LDAP_OPERATIONS_ERROR - There are duplicate values in the value set already.
+ */
+int
+valueset_intersectswith_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **values, int *duplicate_index )
+{
+ int rc= LDAP_SUCCESS;
+
+ if ( duplicate_index ) {
+ *duplicate_index = -1;
+ }
+
+ if(valuearray_isempty(vs->va))
+ {
+ /* No intersection */
+ }
+ else
+ {
+ int numberofvalues= valuearray_count(values);
+ /*
+ * determine whether we should use an AVL tree of values or not
+ */
+ if (numberofvalues==0)
+ {
+ /* No intersection */
+ }
+ else if ( numberofvalues >= SLAPD_MODUTIL_TREE_THRESHHOLD)
+ {
+ /*
+ * Several values to add: use an AVL tree to detect duplicates.
+ */
+ Avlnode *vtree = NULL;
+ rc= valuetree_add_valuearray( a->a_type, a->a_plugin, vs->va, &vtree, duplicate_index );
+ if(rc==LDAP_OPERATIONS_ERROR)
+ {
+ /* There were already duplicate values in the value set */
+ }
+ else
+ {
+ rc= valuetree_add_valuearray( a->a_type, a->a_plugin, values, &vtree, duplicate_index );
+ /*
+ * Returns LDAP_OPERATIONS_ERROR if something very bad happens.
+ * Or LDAP_TYPE_OR_VALUE_EXISTS if a value already exists.
+ */
+ }
+ valuetree_free( &vtree );
+ }
+ else
+ {
+ /*
+ * Small number of values to add: don't bother constructing
+ * an AVL tree, etc. since it probably isn't worth the time.
+ *
+ * JCM - This is actually quite slow because the comparison function is looked up many times.
+ */
+ int i;
+ for ( i = 0; rc == LDAP_SUCCESS && values[i] != NULL; ++i )
+ {
+ if(valuearray_find(a, vs->va, values[i])!=-1)
+ {
+ rc = LDAP_TYPE_OR_VALUE_EXISTS;
+ *duplicate_index = i;
+ break;
+ }
+ }
+ }
+ }
+ return rc;
+}
+
+Slapi_ValueSet *
+valueset_dup(const Slapi_ValueSet *dupee)
+{
+ Slapi_ValueSet *duped= (Slapi_ValueSet *)slapi_ch_calloc(1,sizeof(Slapi_ValueSet));
+ if (NULL!=duped)
+ {
+ valueset_add_valuearray( duped, dupee->va );
+ }
+ return duped;
+}
+
+/* quickly throw away any old contents of this valueset, and stick in the
+ * new ones.
+ */
+void
+valueset_replace(Slapi_ValueSet *vs, Slapi_Value **vals)
+{
+ if(!valuearray_isempty(vs->va))
+ {
+ slapi_valueset_done(vs);
+ }
+ vs->va = vals;
+}
+
+/*
+ * Search the value set for each value to be update,
+ * and update the value with the CSN provided.
+ * Updated values are moved from the valuestoupdate
+ * array to the valueupdated array.
+ */
+void
+valueset_update_csn_for_valuearray(Slapi_ValueSet *vs, const Slapi_Attr *a, Slapi_Value **valuestoupdate, CSNType t, const CSN *csn, Slapi_Value ***valuesupdated)
+{
+ if(!valuearray_isempty(valuestoupdate) &&
+ !valuearray_isempty(vs->va))
+ {
+ /*
+ * determine whether we should use an AVL tree of values or not
+ */
+ struct valuearrayfast vaf_valuesupdated;
+ int numberofvaluestoupdate= valuearray_count(valuestoupdate);
+ valuearrayfast_init(&vaf_valuesupdated,*valuesupdated);
+ if (numberofvaluestoupdate>=SLAPD_MODUTIL_TREE_THRESHHOLD)
+ {
+ int i;
+ Avlnode *vtree = NULL;
+ int rc= valuetree_add_valuearray( a->a_type, a->a_plugin, vs->va, &vtree, NULL );
+ PR_ASSERT(rc==LDAP_SUCCESS);
+ for (i=0;valuestoupdate[i]!=NULL;++i)
+ {
+ int index= 0;
+ rc = valuetree_find( a, valuestoupdate[i], vtree, &index );
+ if(rc==LDAP_SUCCESS)
+ {
+ value_update_csn(vs->va[index],t,csn);
+ valuearrayfast_add_value_passin(&vaf_valuesupdated,valuestoupdate[i]);
+ valuestoupdate[i] = NULL;
+ }
+ }
+ valuetree_free(&vtree);
+ }
+ else
+ {
+ int i;
+ for (i=0;valuestoupdate[i]!=NULL;++i)
+ {
+ int index= valuearray_find(a, vs->va, valuestoupdate[i]);
+ if(index!=-1)
+ {
+ value_update_csn(vs->va[index],t,csn);
+ valuearrayfast_add_value_passin(&vaf_valuesupdated,valuestoupdate[i]);
+ valuestoupdate[i]= NULL;
+ }
+ }
+ }
+ valuearray_compress(valuestoupdate,numberofvaluestoupdate);
+ *valuesupdated= vaf_valuesupdated.va;
+ }
+}
diff --git a/ldap/servers/slapd/vattr.c b/ldap/servers/slapd/vattr.c
new file mode 100644
index 00000000..ca360b08
--- /dev/null
+++ b/ldap/servers/slapd/vattr.c
@@ -0,0 +1,2387 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ Virtual Attributes
+
+ This file implements the "virtual attribute API", which is the interface
+ by which any joe servercode gets the values of attributes associated with an
+ entry which are _not_ stored with the entry. Attributes which _are_ stored
+ with the entry will also be returned by this interface, unless the caller
+ specifies the SLAPI_REALATTRS_ONLY flag. This means that the casual caller
+ looking for attribute values should probably call the virtual attribute interface
+ rather than the regular Slapi_Entry_Attr_Find... and so on calls.
+ This interface is different from that one in that the data returned is
+ a copy, to be freed by the caller. Details on how to free the returned data is
+ given individually for each function.
+
+ The thing is implemented with a service provider model. The code in here
+ does NOT know how to generate computed attr values etc, it just calls the
+ registered providers of such information. It also takes care of any crusty
+ special cases. Everything above the line here is crispy clean.
+
+ Implicit in this interface is the assumption that the value of an attribute
+ can only depend on the entry and some independent stored state. For example,
+ the value can't depend upon who is asking, since we don't pass that information
+ over the interface.
+
+ More design: we'd like to have the regular result returning code in result.c call this
+ interface. However, as it stands, his would incur a malloc, a copy and a free for every
+ value. Too expensive. So, it would be good to modify the interface such that when we
+ retrieve values from inside the entry, we just fetch a pointer like before. When we
+ retrieve values which are generated, we get copies of the data (or can we get pointers
+ there too ?? --- no).
+
+ One way to achieve this: allow the caller to say that they perfer to receive pointers
+ and not copies. They are then informed by the function whether they did receive pointers
+ or copies. They then call the free function only when needed. The implicit lifetime of
+ the returned pointers is the lifetime of the entry object passed into the function.
+ Nasty, but one has to do these things in the name of the god performance.
+
+ DBDB: remember to rename the structures mark complained weren't compliant with the slapi naming scheme.
+
+*/
+
+#include "slap.h"
+
+#include "vattr_spi.h"
+#include "statechange.h"
+
+#ifdef SOURCEFILE
+#undef SOURCEFILE
+#endif
+#define SOURCEFILE "vattr.c"
+static char *sourcefile = SOURCEFILE;
+
+/* Define only for module test code */
+/* #define VATTR_TEST_CODE */
+
+/* Loop context structure */
+struct _vattr_context {
+ Slapi_PBlock *pb;
+ unsigned int vattr_context_loop_count;
+ unsigned int error_displayed;
+};
+#define VATTR_LOOP_COUNT_MAX 50
+
+typedef vattr_sp_handle vattr_sp_handle_list;
+
+/* Local prototypes */
+static int vattr_map_create();
+static void vattr_map_destroy();
+int vattr_map_sp_insert(char *type_to_add, vattr_sp_handle *sp, void *hint);
+vattr_sp_handle_list *vattr_map_sp_getlist(char *type_to_find);
+vattr_sp_handle_list *vattr_map_namespace_sp_getlist(Slapi_DN *dn, const char *type_to_find);
+vattr_sp_handle_list *vattr_map_sp_get_complete_list();
+vattr_sp_handle *vattr_map_sp_first(vattr_sp_handle_list *list,void **hint);
+vattr_sp_handle *vattr_map_sp_next(vattr_sp_handle_list *list,void **hint);
+vattr_sp_handle *vattr_list_sp_first(vattr_sp_handle_list *list);
+vattr_sp_handle *vattr_list_sp_next(vattr_sp_handle_list *list);
+int vattr_call_sp_get_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *buffer_flags, void *hint);
+int vattr_call_sp_get_batch_values(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, char **type, Slapi_ValueSet*** results,int **type_name_disposition, char*** actual_type_name, int flags, int *buffer_flags, void** hint);
+int vattr_call_sp_compare_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, const char *type, Slapi_Value* test_this,int *result, int flags, void* hint);
+int vattr_call_sp_get_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags);
+void schema_changed_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data);
+int slapi_vattrspi_register_internal(vattr_sp_handle **h, vattr_get_fn_type get_fn, vattr_get_ex_fn_type get_ex_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn, void *options);
+
+#ifdef VATTR_TEST_CODE
+int vattr_basic_sp_init();
+#endif
+
+void **statechange_api;
+
+/* Housekeeping Functions, called by server startup/shutdown code */
+
+/* Called on server startup, init all structures etc */
+void vattr_init()
+{
+ statechange_api = 0;
+ vattr_map_create();
+
+#ifdef VATTR_TEST_CODE
+ vattr_basic_sp_init();
+#endif
+}
+
+/* Called on server shutdown, free all structures, inform service providers that we're going down etc */
+void vattr_cleanup()
+{
+ vattr_map_destroy();
+}
+
+/* The public interface functions start here */
+
+/* Function which returns the value(s) of an attribute, given an entry and the attribute type name */
+/* Return 0 if OK, ?? if attr doesn't exist, ?? if some error condition ?? if result doesn't need to be free'ed */
+
+int slapi_vattr_values_get(/* Entry we're interested in */ Slapi_Entry *e, /* attr type name */ char *type, /* pointer to result set */ Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *buffer_flags)
+{
+ vattr_context *c = NULL;
+ return slapi_vattr_values_get_sp(c,e,type,results,type_name_disposition,actual_type_name,flags, buffer_flags);
+}
+
+int slapi_vattr_values_get_ex(/* Entry we're interested in */ Slapi_Entry *e,/* attr type name */ char *type, /* pointer to result set */ Slapi_ValueSet*** results,int **type_name_disposition, char*** actual_type_name, int flags, int *buffer_flags, int *subtype_count)
+{
+ vattr_context *c = NULL;
+ return slapi_vattr_values_get_sp_ex(c,e,type,results,type_name_disposition,actual_type_name,flags, buffer_flags, subtype_count);
+}
+
+int slapi_vattr_namespace_values_get(/* Entry we're interested in */ Slapi_Entry *e, /* backend namespace dn*/ Slapi_DN *namespace_dn, /* attr type name */ char *type, /* pointer to result set */ Slapi_ValueSet*** results,int **type_name_disposition, char*** actual_type_name, int flags, int *buffer_flags, int *subtype_count)
+{
+ vattr_context *c = NULL;
+ return slapi_vattr_namespace_values_get_sp(c,e,namespace_dn,type,results,type_name_disposition,actual_type_name,flags, buffer_flags, subtype_count);
+}
+
+
+/*
+ * If pointers into the entry were requested then we might have
+ * a stashed pointer to the entry values, otherwise will be null.
+ */
+Slapi_ValueSet *vattr_typethang_get_values(vattr_type_thang *t)
+{
+ return t->type_values;
+}
+
+/*
+ * This can be much faster than using slapi_vattr_values_get()
+ * when you have a vattr_type_thang list returned from slapi_vattr_list_types().
+ *
+ * We call the vattr SPs to get values for an attribute type in the list only
+ * if the results field for that attribute type is null.
+ * If the type list comes from slapi_vattr_list_types() then the value is null
+ * only for attributes for which an SP wishes to provide a value, so fo the other
+ * ones don't bother calling the SPs again--just use the real value we picked up
+ * from the entry.
+ *
+ */
+int slapi_vattr_values_type_thang_get(
+ Slapi_Entry *e,
+ vattr_type_thang *type_thang,
+ Slapi_ValueSet **results,
+ int *type_name_disposition,
+ char **actual_type_name,
+ int flags,
+ int *buffer_flags
+)
+{
+ int rc = 0;
+ char *type = NULL;
+
+ type = vattr_typethang_get_name(type_thang);
+ *results = vattr_typethang_get_values(type_thang);
+
+ if (*results != NULL) {
+ /* we already have a pointer directly into the entry */
+ *actual_type_name = type;
+ *type_name_disposition =
+ SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
+ } else {
+ /* fall back to usual implementation */
+ rc = slapi_vattr_values_get(e,type,results,
+ type_name_disposition,
+ actual_type_name,
+ flags,buffer_flags);
+ }
+
+ return rc;
+}
+
+static void vattr_helper_get_entry_conts(Slapi_Entry *e,char *type, vattr_get_thang *my_get)
+{
+ Slapi_Attr *a = NULL;
+ void *dummy = 0;
+
+ a = attrlist_find_ex(e->e_attrs,type,&(my_get->get_name_disposition), &(my_get->get_type_name), &dummy);
+ if (a) {
+ my_get->get_present = 1;
+ my_get->get_present_values = &(a->a_present_values);
+ my_get->get_attr = a;
+ }
+}
+
+static int vattr_helper_get_entry_conts_with_subtypes(Slapi_Entry *e,const char *type, vattr_get_thang **my_get)
+{
+ Slapi_Attr *a = NULL;
+ void *hint = 0;
+ int counter = 0;
+ int attr_count = attrlist_count_subtypes(e->e_attrs,type);
+
+ if(attr_count > 0)
+ {
+ *my_get = (vattr_get_thang *)slapi_ch_calloc(attr_count, sizeof(vattr_get_thang));
+
+ /* pick up attributes with sub-types and slip into the get_thang list */
+ for(counter = 0; counter < attr_count; counter++)
+ {
+ a = attrlist_find_ex(e->e_attrs,type,&((*my_get)[counter].get_name_disposition), &((*my_get)[counter].get_type_name), &hint);
+ if (a) {
+ (*my_get)[counter].get_present = 1;
+ (*my_get)[counter].get_present_values = &(a->a_present_values);
+ (*my_get)[counter].get_attr = a;
+ }
+ }
+ }
+
+ return attr_count;
+}
+
+static int vattr_helper_get_entry_conts_no_subtypes(Slapi_Entry *e,const char *type, vattr_get_thang **my_get)
+{
+ int attr_count = 0;
+ Slapi_Attr *a = attrlist_find(e->e_attrs,type);
+
+ if (a) {
+ attr_count = 1;
+ *my_get = (vattr_get_thang *)slapi_ch_calloc(1, sizeof(vattr_get_thang));
+ (*my_get)[0].get_present = 1;
+ (*my_get)[0].get_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ (*my_get)[0].get_type_name = a->a_type;
+ (*my_get)[0].get_present_values = &(a->a_present_values);
+ (*my_get)[0].get_attr = a;
+ }
+
+ return attr_count;
+}
+
+static int vattr_helper_get_entry_conts_ex(Slapi_Entry *e,const char *type, vattr_get_thang **my_get, int suppress_subtypes)
+{
+ int rc;
+
+ if ( suppress_subtypes ) {
+ rc = vattr_helper_get_entry_conts_no_subtypes(e, type, my_get);
+ } else {
+ rc = vattr_helper_get_entry_conts_with_subtypes(e, type, my_get);
+ }
+
+ return rc;
+}
+
+
+vattr_context *vattr_context_new( Slapi_PBlock *pb )
+{
+ vattr_context *c = (vattr_context *)slapi_ch_calloc(1, sizeof(vattr_context));
+ /* The payload is zero, which is what we want */
+ if ( c ) {
+ c->pb = pb;
+ }
+
+ return c;
+}
+
+static int vattr_context_check(vattr_context *c)
+{
+ /* Observe the loop count and see if it's higher than is allowed */
+ if (c->vattr_context_loop_count > VATTR_LOOP_COUNT_MAX) {
+ return SLAPI_VIRTUALATTRS_LOOP_DETECTED;
+ } else return 0;
+}
+
+static void vattr_context_mark(vattr_context *c)
+{
+ c->vattr_context_loop_count += 1;
+}
+
+static int vattr_context_unmark(vattr_context *c)
+{
+ return (c->vattr_context_loop_count -= 1);
+}
+
+/* modify the context structure on exit from a vattr sp function */
+static void vattr_context_ungrok(vattr_context **c)
+{
+ /* Decrement the loop count */
+ if (0 == vattr_context_unmark(*c)) {
+ /* If necessary, delete the structure */
+ slapi_ch_free((void **)c);
+ }
+}
+
+/* Check and mess with the context structure on entry to a vattr sp function */
+static int vattr_context_grok(vattr_context **c)
+{
+ int rc = 0;
+ /* First check that we've not got into an infinite loop.
+ We do so by means of the vattr_context structure.
+ */
+
+ /* Do we have a context at all ?? */
+ if (NULL == *c) {
+ /* No, so let's make one */
+ *c = vattr_context_new( NULL );
+ if (NULL == *c) {
+ return ENOMEM;
+ }
+ } else {
+ /* Yes, so let's check its contents */
+ rc = vattr_context_check(*c);
+ }
+ /* mark the context as having been used once */
+ vattr_context_mark(*c);
+ return rc;
+}
+
+
+
+/* keep track of error messages so we don't spam the error log */
+static void vattr_context_set_loop_msg_displayed(vattr_context **c)
+{
+ (*c)->error_displayed = 1;
+}
+
+static int vattr_context_is_loop_msg_displayed(vattr_context **c)
+{
+ return (*c)->error_displayed;
+}
+
+/*
+ * vattr_test_filter:
+ *
+ * . tests an ava, presence or substring filter against e.
+ * . group these filter types together to avoid having to duplicate the
+ * . vattr specific code in three seperate routines.
+ * . handles virtual attrs in the filter.
+ * . does update the vattrcache if a call to this calculates vattrs
+ *
+ * returns: 0 filter matched
+ * -1 filter did not match
+ * >0 an ldap error code
+ *
+*/
+int vattr_test_filter( /* Entry we're interested in */ Slapi_Entry *e,
+ Slapi_Filter *f,
+ filter_type_t filter_type,
+ char * type) {
+ int rc = -1;
+ int sp_bit = 0; /* Set if an SP supplied an answer */
+ vattr_sp_handle_list *list = NULL;
+ Slapi_DN *sdn;
+ Slapi_Backend *be;
+ Slapi_DN *namespace_dn;
+
+ /* get the namespace this entry belongs to */
+ sdn = slapi_entry_get_sdn( e );
+ be = slapi_be_select( sdn );
+ namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
+
+ /* Look for attribute in the map */
+
+ if(namespace_dn)
+ {
+ list = vattr_map_namespace_sp_getlist(namespace_dn, type);
+ }
+ else
+ {
+ list = vattr_map_namespace_sp_getlist(NULL, type);
+ }
+
+ if (list) {
+ vattr_sp_handle *current_handle = NULL;
+ Slapi_Attr *cache_attr = NULL;
+ /* first lets consult the cache to save work */
+ int cache_status;
+
+ cache_status = slapi_entry_vattrcache_findAndTest(e, type,
+ f,
+ filter_type,
+ &rc);
+ switch(cache_status)
+ {
+ case SLAPI_ENTRY_VATTR_RESOLVED_EXISTS: /* cached vattr */
+ {
+ sp_bit = 1;
+ break;
+ }
+
+ case SLAPI_ENTRY_VATTR_RESOLVED_ABSENT: /* does not exist */
+ break; /* look in entry */
+
+ case SLAPI_ENTRY_VATTR_NOT_RESOLVED: /* not resolved */
+ default: /* any other result, resolve */
+ {
+ int flags = SLAPI_VIRTUALATTRS_REQUEST_POINTERS;
+ void *hint = NULL;
+ Slapi_ValueSet **results = NULL; /* pointer to result set */
+ int *type_name_disposition;
+ char **actual_type_name;
+ int buffer_flags;
+ vattr_get_thang my_get = {0};
+ vattr_context ctx;
+ /* bit cacky, but need to make a null terminated lists for now
+ * for the (unimplemented and so fake) batch attribute request
+ */
+ char *types[2];
+ void *hint_list[2];
+
+ types[0] = type;
+ types[1] = 0;
+ hint_list[1] = 0;
+
+ /* set up some local context */
+ ctx.vattr_context_loop_count=1;
+ ctx.error_displayed = 0;
+
+ for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint))
+ {
+ hint_list[0] = hint;
+
+ rc = vattr_call_sp_get_batch_values(current_handle,&ctx,e,
+ &my_get,types,&results,&type_name_disposition,
+ &actual_type_name,flags,&buffer_flags, hint_list);
+
+ if (0 == rc)
+ {
+ sp_bit = 1;
+ break;
+ }
+ }
+
+ if(!sp_bit)
+ {
+ /*
+ * No vattr sp supplied an answer so will look in the
+ * entry itself.
+ * but first lets cache the no result
+ */
+ slapi_entry_vattrcache_merge_sv(e, type, NULL );
+
+ }
+ else
+ {
+ /*
+ * A vattr sp supplied an answer.
+ * so turn the value into a Slapi_Attr, pass
+ * to the syntax plugin for comparison.
+ */
+
+ if ( filter_type == FILTER_TYPE_AVA ||
+ filter_type == FILTER_TYPE_SUBSTRING ) {
+ Slapi_Attr *a = NULL;
+ int i=0;
+ /* may need this when we have a passin interface for set_valueset */
+ /*Slapi_ValueSet null_valueset = {0};*/
+
+ rc=-1;
+
+ if(results && actual_type_name && type_name_disposition)
+ {
+ while(results[i] && rc)
+ {
+ a = slapi_attr_new();
+ slapi_attr_init(a, type);
+ /* a now contains a *copy* of results */
+ slapi_attr_set_valueset( a, results[i]);
+
+ if ( filter_type == FILTER_TYPE_AVA ) {
+ rc = plugin_call_syntax_filter_ava( a,
+ f->f_choice, &f->f_ava );
+ } else if ( filter_type == FILTER_TYPE_SUBSTRING) {
+ rc = plugin_call_syntax_filter_sub( a,
+ &f->f_sub);
+ }
+
+ /*
+ * Cache stuff: dups results
+ */
+ slapi_entry_vattrcache_merge_sv(e, actual_type_name[i],
+ results[i] );
+ /*
+ * Free stuff, just in case we did not
+ * get pointers.
+ */
+ slapi_vattr_values_free( &(results[i]),
+ &(actual_type_name[i]),
+ buffer_flags);
+ /* may need this when we support a passin set_valueset */
+ /*slapi_attr_set_valueset( a, &null_valueset);*/
+ /* since a contains a copy of results, we must free it */
+ slapi_attr_free(&a);
+ i++;
+ }
+ }
+
+ slapi_ch_free((void**)&results);
+ slapi_ch_free((void**)&actual_type_name);
+ slapi_ch_free((void**)&type_name_disposition);
+
+ } else if ( filter_type == FILTER_TYPE_PRES ) {
+ /*
+ * Cache stuff: dups results
+ */
+ int i=0;
+
+ while(results[i])
+ {
+ slapi_entry_vattrcache_merge_sv(e, actual_type_name[i],
+ results[i] );
+ /*
+ * Free stuff, just in case we did not
+ * get pointers.
+ */
+ slapi_vattr_values_free( &results[i],
+ &actual_type_name[i],
+ buffer_flags);
+ }
+ slapi_ch_free((void**)&results);
+ slapi_ch_free((void**)&actual_type_name);
+ slapi_ch_free((void**)&type_name_disposition);
+ }
+ }
+
+ break;
+ }
+ }/* switch */
+ }
+ /* If no SP supplied the answer, take it from the entry */
+ if (!sp_bit)
+ {
+ int acl_test_done;
+
+ if ( filter_type == FILTER_TYPE_AVA ) {
+
+ rc = test_ava_filter( NULL /* pb not needed */,
+ e, e->e_attrs, &f->f_ava,
+ f->f_choice,
+ 0 /* no access check */,
+ 0 /* do test filter */,
+ &acl_test_done);
+
+ } else if ( filter_type == FILTER_TYPE_SUBSTRING ) {
+
+ rc = test_substring_filter( NULL, e, f, 0 /* no access check */,
+ 0 /* do test filter */, &acl_test_done);
+
+ } else if ( filter_type == FILTER_TYPE_PRES ) {
+
+ rc = test_presence_filter( NULL, e, f->f_type,
+ 0 /* no access check */,
+ 0 /* do test filter */,
+ &acl_test_done);
+ }
+ }
+ return rc;
+}
+/*
+ * deprecated in favour of slapi_vattr_values_get_sp_ex() which
+ * returns subtypes too.
+*/
+SLAPI_DEPRECATED int
+slapi_vattr_values_get_sp(vattr_context *c,
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* attr type name */ char *type,
+ /* pointer to result set */ Slapi_ValueSet** results,
+ int *type_name_disposition,
+ char** actual_type_name, int flags,
+ int *buffer_flags)
+{
+
+ PRBool use_local_ctx=PR_FALSE;
+ vattr_context ctx;
+ int rc = 0;
+ int sp_bit = 0; /* Set if an SP supplied an answer */
+ vattr_sp_handle_list *list = NULL;
+
+ vattr_get_thang my_get = {0};
+
+ if (c != NULL) {
+ rc = vattr_context_grok(&c);
+ if (0 != rc) {
+ if(!vattr_context_is_loop_msg_displayed(&c))
+ {
+ /* Print a handy error log message */
+ LDAPDebug(LDAP_DEBUG_ANY,"Detected virtual attribute loop in get on entry %s, attribute %s\n", slapi_entry_get_dn_const(e), type, 0);
+ vattr_context_set_loop_msg_displayed(&c);
+ }
+ return rc;
+ }
+ } else {
+ use_local_ctx=PR_TRUE;
+ ctx.vattr_context_loop_count=1;
+ ctx.error_displayed = 0;
+ }
+
+ /* For attributes which are in the entry, we just need to get to the Slapi_Attr structure and yank out the slapi_value_set
+ structure. We either return a pointer directly to it, or we copy it, depending upon whether the caller asked us to try to
+ avoid copying.
+ */
+
+ /* First grok the entry, and remember what we saw. This call does no more than walk down the entry attribute list, do some string compares and copy pointers. */
+ vattr_helper_get_entry_conts(e,type, &my_get);
+ /* Having done that, we now consult the attribute map to find service providers who are interested */
+ /* Look for attribute in the map */
+ if(!(flags & SLAPI_REALATTRS_ONLY))
+ {
+ list = vattr_map_sp_getlist(type);
+ if (list) {
+ vattr_sp_handle *current_handle = NULL;
+ void *hint = NULL;
+ Slapi_Attr* cache_attr = 0;
+ char *vattr_type = NULL;
+ /* first lets consult the cache to save work */
+ int cache_status;
+
+ cache_status =
+ slapi_entry_vattrcache_find_values_and_type(e, type,
+ results,
+ actual_type_name);
+ switch(cache_status)
+ {
+ case SLAPI_ENTRY_VATTR_RESOLVED_EXISTS: /* cached vattr */
+ {
+ sp_bit = 1;
+
+ /* Complete analysis of type matching */
+ if ( 0 == slapi_attr_type_cmp( type , *actual_type_name, SLAPI_TYPE_CMP_EXACT) )
+ {
+ *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ } else {
+ *type_name_disposition = SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE;
+ }
+
+ break;
+ }
+
+ case SLAPI_ENTRY_VATTR_RESOLVED_ABSENT: /* does not exist */
+ break; /* look in entry */
+
+ case SLAPI_ENTRY_VATTR_NOT_RESOLVED: /* not resolved */
+ default: /* any other result, resolve */
+ {
+ for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint))
+ {
+ if (use_local_ctx)
+ {
+ rc = vattr_call_sp_get_value(current_handle,&ctx,e,&my_get,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint);
+ }
+ else
+ {
+ /* call this SP */
+ rc = vattr_call_sp_get_value(current_handle,c,e,&my_get,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint);
+ }
+
+ if (0 == rc)
+ {
+ sp_bit = 1;
+ break;
+ }
+ }
+
+ if(!sp_bit)
+ {
+ /* clean up, we have failed and must now examine the
+ * entry itself
+ * But first lets cache the no result
+ * Creates the type (if necessary).
+ */
+ slapi_entry_vattrcache_merge_sv(e, type, NULL );
+
+ }
+ else
+ {
+ /*
+ * we need to cache the virtual attribute
+ * creates the type (if necessary) and dups
+ * results.
+ */
+ slapi_entry_vattrcache_merge_sv(e, *actual_type_name,
+ *results );
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ /* If no SP supplied the answer, take it from the entry */
+ if (!sp_bit && !(flags & SLAPI_VIRTUALATTRS_ONLY))
+ {
+ rc = 0; /* reset return code (cause an sp must have failed) */
+ *type_name_disposition = my_get.get_name_disposition;
+
+ if (my_get.get_present) {
+ if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
+ *results = my_get.get_present_values;
+ *actual_type_name = my_get.get_type_name;
+ } else {
+ *results = valueset_dup(my_get.get_present_values);
+ if (NULL == *results) {
+ rc = ENOMEM;
+ } else {
+ *actual_type_name = slapi_ch_strdup(my_get.get_type_name);
+ if (NULL == *actual_type_name) {
+ rc = ENOMEM;
+ }
+ }
+ }
+ if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
+ *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
+ } else {
+ *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
+ }
+ } else {
+ rc = SLAPI_VIRTUALATTRS_NOT_FOUND;
+ }
+ }
+ if (!use_local_ctx) {
+ vattr_context_ungrok(&c);
+ }
+ return rc;
+}
+
+/*
+ *
+ * returns 0: (no_error && type found ) in which case:
+ * results: contains the current values for type and
+ * all it's subtypes in e
+ * type_name_disposition: how each type was matched
+ * SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS
+ * SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE
+ * actual_type_name: type name as found
+ * flags: bit mask of options:
+ * SLAPI_REALATTRS_ONLY
+ * SLAPI_VIRTUALATTRS_ONLY
+ * SLAPI_VIRTUALATTRS_REQUEST_POINTERS
+ * SLAPI_VIRTUALATTRS_LIST_OPERATIONAL_ATTRS
+ * buffer_flags: bit mask to be used as input flags for
+ * slapi_values_free()
+ * SLAPI_VIRTUALATTRS_RETURNED_POINTERS
+ * SLAPI_VIRTUALATTRS_RETURNED_COPIES
+ * SLAPI_VIRTUALATTRS_REALATTRS_ONLY
+ * item_count: number of subtypes matched
+ * otherwise:
+ * SLAPI_VIRTUALATTRS_LOOP_DETECTED (failed to eval a vattr)
+ * SLAPI_VIRTUALATTRS_NOT_FOUND (type not recognised by any vattr
+ * sp && not a real attr in entry )
+ * ENOMEM (memory error)
+ *
+ * Note:
+ * . modifes the virtual cache in the entry.
+ * . for cached vattrs you always get a copy, so it will need to be
+ * freed via slapi_values_free().
+ *
+ */
+
+int slapi_vattr_values_get_sp_ex(vattr_context *c,
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* attr type name */ char *type,
+ /* pointer to result set */ Slapi_ValueSet*** results,
+ int **type_name_disposition,
+ char*** actual_type_name, int flags,
+ int *buffer_flags, int *item_count)
+{
+ return slapi_vattr_namespace_values_get_sp(
+ c, e, NULL, type, results, type_name_disposition,
+ actual_type_name, flags, buffer_flags, item_count
+ );
+}
+
+int slapi_vattr_namespace_values_get_sp(vattr_context *c,
+ /* Entry we're interested in */ Slapi_Entry *e,
+ /* DN denoting backend namespace */ Slapi_DN *namespace_dn,
+ /* attr type name */ char *type,
+ /* pointer to result set */ Slapi_ValueSet*** results,
+ int **type_name_disposition,
+ char*** actual_type_name, int flags,
+ int *buffer_flags, int *item_count)
+{
+
+ int rc = 0;
+ int sp_bit = 0; /* Set if an SP supplied an answer */
+ vattr_sp_handle_list *list = NULL;
+ vattr_get_thang *my_get = NULL;
+ int attr_count = 0;
+
+ rc = vattr_context_grok(&c);
+ if (0 != rc) {
+ /* Print a handy error log message */
+ if(!vattr_context_is_loop_msg_displayed(&c))
+ {
+ LDAPDebug(LDAP_DEBUG_ANY,"Detected virtual attribute loop in get on entry %s, attribute %s\n", slapi_entry_get_dn_const(e), type, 0);
+ vattr_context_set_loop_msg_displayed(&c);
+ }
+ return rc;
+ }
+
+ /* Having done that, we now consult the attribute map to find service providers who are interested */
+ /* Look for attribute in the map */
+ if(!(flags & SLAPI_REALATTRS_ONLY))
+ {
+ /* we use the vattr namespace aware version of this */
+ list = vattr_map_namespace_sp_getlist(namespace_dn, type);
+ if (list) {
+ vattr_sp_handle *current_handle = NULL;
+ void *hint = NULL;
+ Slapi_Attr* cache_attr = 0;
+ char *vattr_type=NULL;
+ /* first lets consult the cache to save work */
+ int cache_status;
+
+ cache_status =
+ slapi_entry_vattrcache_find_values_and_type_ex(e, type,
+ results,
+ actual_type_name);
+ switch(cache_status)
+ {
+ case SLAPI_ENTRY_VATTR_RESOLVED_EXISTS: /* cached vattr */
+ {
+ sp_bit = 1;
+
+ /* Complete analysis of type matching */
+ *type_name_disposition =
+ (int *)slapi_ch_malloc(sizeof(*type_name_disposition));
+ if ( 0 == slapi_attr_type_cmp( type , **actual_type_name, SLAPI_TYPE_CMP_EXACT) )
+ {
+ **type_name_disposition =
+ SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_EXACTLY_OR_ALIAS;
+ } else {
+ **type_name_disposition =
+ SLAPI_VIRTUALATTRS_TYPE_NAME_MATCHED_SUBTYPE;
+ }
+
+ *item_count = 1;
+
+ break;
+ }
+
+ case SLAPI_ENTRY_VATTR_RESOLVED_ABSENT: /* does not exist */
+ break; /* look in entry */
+
+ case SLAPI_ENTRY_VATTR_NOT_RESOLVED: /* not resolved */
+ default: /* any other result, resolve */
+ {
+ /* bit cacky, but need to make a null terminated lists for now
+ * for the (unimplemented and so fake) batch attribute request
+ */
+ char **type_list = (char**)slapi_ch_calloc(2,sizeof(char*));
+ void **hint_list = (void**)slapi_ch_calloc(2,sizeof(void*));
+
+ type_list[0] = type;
+
+ for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(current_handle,&hint)) {
+ /* call this SP */
+
+ hint_list[0] = hint;
+
+ rc = vattr_call_sp_get_batch_values(current_handle,c,e,my_get,
+ type_list,results,type_name_disposition,
+ actual_type_name, flags,buffer_flags, hint_list);
+ if (0 == rc) {
+ sp_bit = 1; /* this sp provided an answer, we are done */
+
+ /* count the items in the (null terminated) result list */
+ *item_count = 0;
+
+ while((*results)[*item_count])
+ {
+ (*item_count)++;
+ }
+
+ break;
+ }
+ }
+
+ slapi_ch_free((void**)&type_list);
+ slapi_ch_free((void**)&hint_list);
+
+ if(!sp_bit)
+ {
+ /* we have failed and must now examine the entry itself
+ *
+ * But first lets cache the no result
+ * dups the type (if necessary).
+ */
+ slapi_entry_vattrcache_merge_sv(e, type, NULL );
+
+ }
+ else
+ {
+ /*
+ * we need to cache the virtual attribute
+ * dups the type (if necessary) and results.
+ */
+ /*
+ * this (and above) will of course need to get updated
+ * when we do real batched attributes
+ */
+ slapi_entry_vattrcache_merge_sv(e, **actual_type_name,
+ **results );
+ }
+ }
+ }
+ }
+ }
+
+ /* If no SP supplied the answer, take it from the entry */
+ if (!sp_bit && !(flags & SLAPI_VIRTUALATTRS_ONLY))
+ {
+ int counter;
+
+ /* First grok the entry - allocates memory for list */
+ attr_count = vattr_helper_get_entry_conts_ex(e,type, &my_get,
+ (0 != (flags & SLAPI_VIRTUALATTRS_SUPPRESS_SUBTYPES)));
+ *item_count = attr_count;
+ rc = 0; /* reset return code (cause an sp must have failed) */
+
+ if(attr_count > 0)
+ {
+
+ *results = (Slapi_ValueSet**)slapi_ch_calloc(1, sizeof(*results) * attr_count);
+ *type_name_disposition = (int *)slapi_ch_malloc(sizeof(*type_name_disposition) * attr_count);
+ *actual_type_name = (char**)slapi_ch_malloc(sizeof(*actual_type_name) * attr_count);
+
+ /* For attributes which are in the entry, we just need to get to the Slapi_Attr structure and yank out the slapi_value_set
+ structure. We either return a pointer directly to it, or we copy it, depending upon whether the caller asked us to try to
+ avoid copying.
+ */
+ for(counter = 0; counter < attr_count; counter++)
+ {
+ (*type_name_disposition)[counter] = my_get[counter].get_name_disposition;
+
+ if (my_get[counter].get_present) {
+ if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
+ /* pointers will do, good */
+ (*results)[counter] = my_get[counter].get_present_values;
+ (*actual_type_name)[counter] = my_get[counter].get_type_name;
+ } else {
+ /* need to copy the values */
+ (*results)[counter] = valueset_dup(my_get[counter].get_present_values);
+ if (NULL == (*results)[counter]) {
+ rc = ENOMEM;
+ } else {
+ (*actual_type_name)[counter] = slapi_ch_strdup(my_get[counter].get_type_name);
+ if (NULL == (*actual_type_name)[counter]) {
+ rc = ENOMEM;
+ }
+ }
+ }
+ if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
+ *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
+ } else {
+ *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
+ }
+ } else {
+ rc = SLAPI_VIRTUALATTRS_NOT_FOUND;
+ }
+ }
+
+ slapi_ch_free((void **)&my_get);
+ }
+ }
+ vattr_context_ungrok(&c);
+ return rc;
+}
+
+/* Do we need a call to free the results from the above ? */
+
+void slapi_vattr_values_free(Slapi_ValueSet **value, char** actual_type_name,
+ int flags)
+{
+ /* Check whether we need to free the strings */
+ if (flags & SLAPI_VIRTUALATTRS_RETURNED_POINTERS) {
+ /* We don't need to free the values */
+ } else {
+ /* Free the valueset */
+ if (*value) {
+ slapi_valueset_free(*value);
+ }
+ if (*actual_type_name) {
+ slapi_ch_free((void **)actual_type_name);
+ }
+ }
+ *actual_type_name = NULL;
+ *value = NULL;
+}
+
+/* Function like the one above but doing a compare operation */
+/* Same return codes as above. Compare result value returned in "result": 0 if compare true, 1 if compare false */
+
+int slapi_vattr_value_compare(Slapi_Entry *e, char *type, Slapi_Value *test_this, int *result, int flags)
+{
+ return slapi_vattr_namespace_value_compare_sp(NULL,e,NULL,type,test_this,result,flags);
+}
+
+/* namespace version of above */
+int slapi_vattr_namespace_value_compare(Slapi_Entry *e, Slapi_DN *namespace_dn, const char *type, Slapi_Value *test_this, int *result, int flags)
+{
+ return slapi_vattr_namespace_value_compare_sp(NULL,e,namespace_dn,type,test_this,result,flags);
+}
+
+int slapi_vattr_value_compare_sp(vattr_context *c,/* Entry we're interested in */ Slapi_Entry *e,/* attr type name */ char *type, Slapi_Value *test_this,/* pointer to result */ int *result, int flags)
+{
+ return slapi_vattr_namespace_value_compare_sp(c,e,NULL,type,test_this,result,flags);
+}
+
+int slapi_vattr_namespace_value_compare_sp(vattr_context *c,/* Entry we're interested in */ Slapi_Entry *e, /* backend namespace dn*/Slapi_DN *namespace_dn, /* attr type name */ const char *type, Slapi_Value *test_this,/* pointer to result */ int *result, int flags)
+{
+ int rc = 0;
+
+ int sp_bit = 0; /* Set if an SP supplied an answer */
+ vattr_sp_handle_list *list = NULL;
+
+ vattr_get_thang *my_get = 0;
+
+ *result = 0; /* return "compare false" by default */
+
+ rc = vattr_context_grok(&c);
+ if (0 != rc) {
+ /* Print a handy error log message */
+ LDAPDebug(LDAP_DEBUG_ANY,"Detected virtual attribute loop in compare on entry %s, attribute %s\n", slapi_entry_get_dn_const(e), type, 0);
+ return rc;
+ }
+
+ /* Having done that, we now consult the attribute map to find service providers who are interested */
+ /* Look for attribute in the map */
+ list = vattr_map_namespace_sp_getlist(namespace_dn, type);
+ if (list) {
+ vattr_sp_handle *current_handle = NULL;
+ void *hint = NULL;
+ for (current_handle = vattr_map_sp_first(list,&hint); current_handle; current_handle = vattr_map_sp_next(list,&hint)) {
+ /* call this SP */
+ rc = vattr_call_sp_compare_value(current_handle,c,e,my_get,type,test_this,result,flags, hint);
+ if (0 == rc) {
+ sp_bit = 1;
+ break;
+ }
+ }
+ }
+ /* If no SP supplied the answer, take it from the entry */
+ if (!sp_bit) {
+ /* Grok the entry, and remember what we saw. This call does no more than walk down the entry attribute list, do some string compares and copy pointers. */
+ int attr_count = vattr_helper_get_entry_conts_ex(e,type, &my_get,
+ (0 != (flags & SLAPI_VIRTUALATTRS_SUPPRESS_SUBTYPES)));
+
+ if (my_get && my_get->get_present) {
+ int i;
+ Slapi_Value *Dummy_value = NULL;
+
+ /* Put the required stuff in the fake attr */
+
+ for(i=0;i<attr_count;i++)
+ {
+ Dummy_value = slapi_valueset_find( my_get[i].get_attr, my_get[i].get_present_values, test_this );
+
+ if (Dummy_value) {
+ *result = 1; /* return "compare true" */
+
+ break;
+ }
+ }
+ } else {
+ rc = SLAPI_VIRTUALATTRS_NOT_FOUND;
+ }
+ }
+ vattr_context_ungrok(&c);
+ slapi_ch_free((void **)&my_get);
+ return rc;
+}
+
+/* Function to obtain the list of attribute types which are available on this entry */
+
+/*
+ Need to call service providers here:
+ We know only the entry's DN and so we could restrict our choice of SPs based on that.
+ However, we don't yet implement such fancyness.
+ For now, we just crawl through all the SPs, asking them in turn to contribute.
+ This is pretty inefficient because we will trawl the list for each wildcard attribute type search operation.
+ Service providers should therefore handle the call as fast as they can.
+ */
+
+struct _vattr_type_list_context {
+ unsigned int vattr_context_loop_count;
+ vattr_type_thang *types;
+ int realattrs_only; /* TRUE implies list contains only real attrs */
+ int list_is_copies;
+ int flags;
+ size_t list_length;
+ size_t block_length;
+};
+
+/* Helper function which converts a type list from pointers to copies */
+static int vattr_convert_type_list(vattr_type_list_context *thang)
+{
+ vattr_type_thang *old_list = NULL;
+ vattr_type_thang *new_list = NULL;
+ size_t index = 0;
+
+ old_list = thang->types;
+ /* Make a new list */
+ new_list = (vattr_type_thang*)slapi_ch_calloc(thang->block_length, sizeof(vattr_type_thang));
+ if (NULL == new_list) {
+ return ENOMEM;
+ }
+ /* Walk the list strdup'ing the type name and copying the rest of the structure contents */
+ for (index = 0; index < thang->list_length; index++) {
+ new_list[index].type_flags = old_list[index].type_flags;
+ new_list[index].type_name = slapi_ch_strdup(old_list[index].type_name);
+ /*
+ * list_is_copies does not affect type_values as it
+ * is always a pointer never a copy.
+ */
+ new_list[index].type_values = old_list[index].type_values;
+ }
+ /* Mark it a copy list */
+ thang->list_is_copies = 1;
+ /* Free the original list */
+ slapi_ch_free((void **)&(thang->types));
+ /* swap lists */
+ thang->types = new_list;
+
+ return 0;
+}
+
+/*
+ * Returns all the attribute types from e, both real and virtual.
+ *
+ * Any of the attributes found in the entry to start with, for
+ * whom no vattr SP volunteered, will also have a pointer to the
+ * original valueset in the entry--this fact can be used by
+ * calling slapi_vattr_values_type_thang_get(), which will
+ * take the values present in the vattr_type_thang list
+ * rather than calling slapi_vattr_values_get() to retrieve the value.
+*/
+
+#define TYPE_LIST_EXTRA_SPACE 5 /* Number of extra slots we allow for SP's to insert types */
+
+int slapi_vattr_list_attrs(/* Entry we're interested in */ Slapi_Entry *e,
+ /* pointer to receive the list */ vattr_type_thang **types,
+ int flags, int *buffer_flags)
+{
+ int rc = 0;
+ size_t attr_count = 0;
+ vattr_type_thang *result_array = NULL ;
+ Slapi_Attr *current_attr = NULL;
+ size_t i = 0;
+ int list_is_copies = 0;
+ vattr_sp_handle_list *list = NULL;
+ size_t list_length = 0;
+ size_t block_length = 0;
+ vattr_type_list_context type_context = {0};
+
+ block_length = 1 + TYPE_LIST_EXTRA_SPACE;
+
+ if(!(flags & SLAPI_VIRTUALATTRS_ONLY))
+ {
+ /* First find what's in the entry itself*/
+ /* Count the attributes */
+ for (current_attr = e->e_attrs; current_attr != NULL; current_attr = current_attr->a_next, attr_count++) ;
+ block_length += attr_count;
+ /* Allocate the pointer array */
+ result_array = (vattr_type_thang*)slapi_ch_calloc(block_length,sizeof(vattr_type_thang));
+ if (NULL == result_array) {
+ return ENOMEM;
+ }
+ list_length = attr_count;
+
+ /* Now copy the pointers into the array */
+ i = 0;
+ for (current_attr = e->e_attrs; current_attr != NULL; current_attr = current_attr->a_next) {
+ char *mypointer = NULL;
+ if (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS) {
+ mypointer = current_attr->a_type;
+ result_array[i].type_values = &(current_attr->a_present_values);
+ } else {
+ mypointer = slapi_ch_strdup(current_attr->a_type);
+ list_is_copies = 1;
+ }
+ result_array[i].type_flags = current_attr->a_flags;
+ result_array[i++].type_name = mypointer;
+ }
+ PR_ASSERT(i == attr_count);
+ }
+
+ /* if we didnt send real attrs we need to allocate result array */
+ if(NULL == result_array)
+ {
+ result_array = (vattr_type_thang*)slapi_ch_calloc(block_length,sizeof(vattr_type_thang));
+ if (NULL == result_array) {
+ return ENOMEM;
+ }
+ }
+
+ /* Then ask the service providers for their input */
+ type_context.flags = flags;
+ type_context.realattrs_only = 1; /* until we know otherwise */
+ type_context.list_is_copies = list_is_copies;
+ type_context.types = result_array;
+ type_context.list_length = list_length;
+ type_context.block_length = block_length;
+
+ /*
+ * At this point type_context.types is a list of all
+ * the attributetypes (copies or pointers) and values (copies, if present)
+ * found in the entry.
+ */
+
+ if(!(flags & SLAPI_REALATTRS_ONLY))
+ {
+ list = vattr_map_sp_get_complete_list();
+ if (list) {
+ vattr_sp_handle *current_handle = NULL;
+
+ for (current_handle = vattr_list_sp_first(list); current_handle; current_handle = vattr_list_sp_next((vattr_sp_handle_list *)current_handle)) {
+ /* call this SP */
+ rc = vattr_call_sp_get_types(current_handle,e,&type_context,
+ flags);
+ if (0 != rc) {
+ /* DBDB do what on error condition ? */
+ }
+ }
+ /* assert enough space for the null terminator */
+ PR_ASSERT( type_context.list_length < type_context.block_length);
+ i = type_context.list_length;
+ }
+ }
+
+ /*
+ * Now type_context.types is a list of all the types in this entry--
+ * real and virtual. For real ones, the values field is filled in.
+ * For virtual ones (including virtual ones which will overwrite a real
+ * value) the values field is null--this fact may used
+ * subsequently by callers of slapi_vattr_list_attrs()
+ * by calling slapi_vattr_values_type_thang_get() which
+ * will only calculate the values for attributetypes with
+ * non-null values.
+ */
+
+ flags = type_context.flags;
+ list_is_copies = type_context.list_is_copies;
+ result_array = type_context.types;
+ list_length = type_context.list_length;
+ block_length = type_context.block_length;
+
+ if (list_is_copies) {
+ *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_COPIES;
+ } else {
+ *buffer_flags = SLAPI_VIRTUALATTRS_RETURNED_POINTERS;
+ }
+
+ /* Let the caller know if the list contains only real attrs */
+ if (type_context.realattrs_only) {
+ *buffer_flags |= SLAPI_VIRTUALATTRS_REALATTRS_ONLY;
+ }
+
+ result_array[i].type_name = NULL;
+
+ if (types && list_length) {
+ *types = result_array;
+ }
+ else
+ *types = 0;
+
+ return rc;
+}
+
+static int vattr_add_thang_to_list(vattr_type_list_context *c, vattr_type_thang *thang)
+{
+ vattr_type_thang *new_list = NULL;
+
+ /* Will it fit in the current block ? */
+ if (c->list_length == c->block_length - 1) {
+ c->block_length *= 2;
+
+ new_list = (vattr_type_thang*)slapi_ch_realloc((char *)c->types,
+ c->block_length * (int)sizeof(vattr_type_thang));
+ if (NULL == new_list) {
+ return ENOMEM;
+ }
+
+ c->types = new_list;
+ }
+ /* Add to the end of the list */
+ c->types[c->list_length ] = *thang;
+ c->list_length += 1;
+ return 0;
+}
+
+/* Called by SP's during their get_types call, to have the server add a
+ * type to the type list.
+ *
+ * c: the vattr_type_list_context passed from the original caller of
+ * slapi_vattr_list_attrs()
+ * thang: the new type to be added to the type list.
+ * flags: tells the routine whether to copy the thang or not.
+ * SLAPI_VIRTUALATTRS_REQUEST_POINTERS--no need to copy it.
+ * !(SLAPI_VIRTUALATTRS_REQUEST_POINTERS)--need to copy it.
+ *
+ * Checks to see if the requested type is already in the list,
+ * and if it is, if the value of the attribute is
+ * non-null, it resets the value to null. This means that when used
+ * subsequently, the type list indicates whether, for a given attribute type,
+ * the SP's need to be called to retrieve the value.
+ *
+*/
+int slapi_vattrspi_add_type(vattr_type_list_context *c,
+ vattr_type_thang *thang, int flags)
+{
+ int rc = 0;
+ unsigned int index = 0;
+ vattr_type_thang thang_to_add = {0};
+
+ int found_it = 0;
+
+ PR_ASSERT(c);
+
+ /* We are no longer sure that the list contains only real attrs */
+ c->realattrs_only = 0;
+
+ /* Check to see if the type is in the list already */
+ for (index = 0; index < c->list_length; index++) {
+ if (0 == slapi_UTF8CASECMP(c->types[index].type_name,thang->type_name)) {
+ found_it = 1;
+ break;
+ }
+ }
+ /*
+ * If found and there are values specified in the vattr_type_thang, then
+ * that means it's a real attribute--because SP's do not add values
+ * when called via slapi_vattr_list_attrs()/vattr_call_sp_get_types().
+ * However, an SP is willing to claim responsibility for this attribute
+ * type, so to ensure that that virtual value will get calculated, set the
+ * original real value to NULL here.
+ * The guiding rule here is "if an SP is prepared
+ * to provide a value for an attribute type, then that is the one
+ * that must be returned to the user". Note, this does not prevent
+ * the SP implementing a "merge real with virtual policy", if they
+ * wish.
+ */
+
+ if (found_it) {
+
+ if ( c->types[index].type_values != NULL ) {
+ /*
+ * Any values in this list are always pointers.
+ * See slapi_vattr_list_types() and vattr_convert_type_list()
+ */
+ c->types[index].type_values = NULL;
+ }
+
+ return 0;
+ }
+ /*
+ * If it's not in the list then we need to add it.
+ * If the list is already copies, then we need to make a copy of what the
+ * SP passed us.
+ * If the SP indicated that the type name it passed us is volatile,
+ * !(flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS)
+ * then we need to copy it anyway.
+ */
+
+ /* rbyrneXXX optimisation for COS: if each type_thang could have a
+ * free_flag
+ * then we would not have to convert all the real attrs to copies
+ * just because an SP returned a copy (note: only COS rrequires copies;
+ * roles returns a pointer to a static string "nsRole").
+ */
+ if (!c->list_is_copies &&
+ (0 == (flags & SLAPI_VIRTUALATTRS_REQUEST_POINTERS))) {
+ /* Means we need to turn the existing list into a list of copies */
+ vattr_convert_type_list(c);
+ }
+ if (c->list_is_copies) {
+ thang_to_add.type_flags = thang->type_flags;
+ thang_to_add.type_name = slapi_ch_strdup(thang->type_name);
+ } else {
+ thang_to_add = *thang;
+ }
+ /* Lastly, we add to the list, using a function which hides the complexity of extending the list if it fills up */
+ vattr_add_thang_to_list(c, &thang_to_add);
+
+ return rc;
+}
+
+/* Function to free the list returned in the function above */
+/* Written, reviewed, debug stepped */
+
+void slapi_vattr_attrs_free(vattr_type_thang **types, int flags)
+{
+ if (NULL == *types) {
+ return;
+ }
+ /* Check whether we need to free the strings */
+ if (flags & SLAPI_VIRTUALATTRS_RETURNED_POINTERS) {
+ /* We don't need to free the values */
+ } else {
+ char *attr_name_to_free = NULL;
+ size_t i = 0;
+ /* Walk down the set of values, fr eeing each one in turn */
+ for (; (attr_name_to_free = (*types)[i].type_name) != NULL; i++) {
+ slapi_ch_free((void **)&attr_name_to_free);
+ }
+ }
+ /* We always need to free the pointer block */
+ slapi_ch_free((void **)types);
+}
+
+char *vattr_typethang_get_name(vattr_type_thang *t)
+{
+ return t->type_name;
+}
+
+unsigned long vattr_typethang_get_flags(vattr_type_thang *t)
+{
+ return t->type_flags;
+}
+
+vattr_type_thang *vattr_typethang_next(vattr_type_thang *t)
+{
+ t++;
+ if (t->type_name) {
+ return t;
+ } else {
+ return NULL;
+ }
+}
+
+vattr_type_thang *vattr_typethang_first(vattr_type_thang *t)
+{
+ return t;
+}
+
+vattr_get_thang *slapi_vattr_getthang_first(vattr_get_thang *t)
+{
+ return t;
+}
+
+vattr_get_thang *slapi_vattr_getthang_next(vattr_get_thang *t)
+{
+ t++;
+ if (t->get_present) {
+ return t;
+ } else {
+ return NULL;
+ }
+}
+
+
+
+
+/* End of the public interface functions */
+
+/* Everything below here is the SPI interface, only callable by vattr service providers.
+ Currently this interface is not public. Interface definitions are in vattr_spi.h
+ */
+
+/* Structures used in the SPI interface */
+
+/* Service provider object */
+
+
+struct _vattr_sp {
+ /* vtbl */
+ vattr_get_fn_type sp_get_fn;
+ vattr_get_ex_fn_type sp_get_ex_fn;
+ vattr_compare_fn_type sp_compare_fn;
+ vattr_types_fn_type sp_types_fn;
+ void *sp_data; /* Pointer for use by the Service Provider */
+};
+typedef struct _vattr_sp vattr_sp;
+
+/* Service provider handle */
+struct _vattr_sp_handle {
+ vattr_sp *sp;
+ struct _vattr_sp_handle *next; /* So we can link them together in the map */
+ void *hint; /* Hint to the SP */
+};
+
+/* Calls made by Service Providers */
+/* Call to register as a service provider */
+/* This function needs to do the following:
+ o Let the provider say "hey, I'm here". It should probably get some handle back which it can use in future calls.
+ o Say whether it wants to be called to resolve every single query, or whether it will say in advance what attrs it services.
+ */
+
+static vattr_sp_handle *vattr_sp_list = NULL;
+
+int slapi_vattrspi_register(vattr_sp_handle **h, vattr_get_fn_type get_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn)
+{
+ return slapi_vattrspi_register_internal(h, get_fn, 0, compare_fn, types_fn, 0);
+}
+
+int slapi_vattrspi_register_ex(vattr_sp_handle **h, vattr_get_ex_fn_type get_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn, void *options)
+{
+ return slapi_vattrspi_register_internal(h, 0, get_fn, compare_fn, types_fn, options);
+}
+
+/* options not used yet - for future expansion */
+int slapi_vattrspi_register_internal(vattr_sp_handle **h, vattr_get_fn_type get_fn, vattr_get_ex_fn_type get_ex_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn, void *options)
+{
+ vattr_sp_handle *return_to_caller = NULL;
+ vattr_sp_handle *list_handle = NULL;
+ vattr_sp *new_sp = NULL;
+ /* Make a service provider handle */
+ new_sp = (vattr_sp*)slapi_ch_calloc(1,sizeof(vattr_sp));
+ if (NULL == new_sp) {
+ slapd_nasty(sourcefile,7,0);
+ return ENOMEM;
+ }
+ return_to_caller = (vattr_sp_handle*)slapi_ch_calloc(1,sizeof(vattr_sp_handle));
+ if (NULL == return_to_caller) {
+ slapd_nasty(sourcefile,8,0);
+ return ENOMEM;
+ }
+ new_sp->sp_get_fn = get_fn;
+ new_sp->sp_get_ex_fn = get_ex_fn;
+ new_sp->sp_compare_fn = compare_fn;
+ new_sp->sp_types_fn = types_fn;
+ return_to_caller->sp = new_sp;
+ /* Add to the service provider list */
+ /* Make a handle for the list */
+ list_handle = (vattr_sp_handle*)slapi_ch_calloc(1, sizeof (vattr_sp_handle));
+ if (NULL == list_handle) {
+ return ENOMEM;
+ }
+ *list_handle = *return_to_caller;
+ list_handle->next = vattr_sp_list;
+ vattr_sp_list = list_handle;
+ /* Return the handle to the caller */
+ *h = return_to_caller;
+ return 0;
+}
+
+vattr_sp_handle_list *vattr_map_sp_get_complete_list()
+{
+ return vattr_sp_list;
+}
+
+int slapi_vattrspi_regattr(vattr_sp_handle *h,char *type_name_to_register, char* DN , void *hint)
+{
+ int ret = 0;
+ char *type_to_add;
+ int free_type_to_add = 0;
+
+ /* Supplying a DN means that the plugin requires to be called
+ * only when the considering attributes in relevant entries - almost
+ *
+ * Actually the smallest namespace is the backend.
+ *
+ * atttributes that are tied to backends have the format DN::attr
+ * this essentially makes the attribute have split namespaces
+ * that are treated as separate attributes in the vattr code
+ */
+ if(DN)
+ {
+ /* as a coutesy we accept any old DN and will convert
+ * to a namespace DN, this helps to hide details
+ * (that we might decide to change) anyway
+ */
+ Slapi_DN original_dn;
+ Slapi_Backend *be;
+ Slapi_DN *namespace_dn;
+
+ slapi_sdn_init(&original_dn);
+ slapi_sdn_set_dn_byref(&original_dn,DN);
+ be = slapi_be_select( &original_dn );
+ namespace_dn = (Slapi_DN*)slapi_be_getsuffix(be, 0);
+
+ if(namespace_dn && be != defbackend_get_backend()) /* just in case someone thinks "" is a good namespace */
+ {
+ type_to_add = (char*)PR_smprintf("%s::%s",
+ (char*)slapi_sdn_get_dn(namespace_dn),
+ type_name_to_register);
+
+ if(!type_to_add)
+ {
+ ret = -1;
+ }
+
+ free_type_to_add = 1;
+ }
+ else
+ {
+ type_to_add = type_name_to_register;
+ }
+
+ slapi_sdn_done(&original_dn);
+ }
+ else
+ {
+ type_to_add = type_name_to_register;
+ }
+
+ ret = vattr_map_sp_insert(type_to_add,h,hint);
+
+ if(free_type_to_add)
+ {
+ PR_smprintf_free(type_to_add);
+ }
+
+ return ret;
+}
+
+
+/* Call to advertise or refute that you generate the value for some attribute, and to signal that the definition for this attribute has changed */
+/* This call needs to do the following:
+ o Let the SP say "you know, I will generate the value of attribute "foo", within subtree "bar". (we might ignore the subtree for now to keep things simple
+ o Same as above, but say "you know, I'm not doing that any more". (we'll do that with a addordel flag).
+ o Say, "you know that definition I said I did, well it's changed".
+*/
+
+/* Functions to handle the context stucture */
+
+int slapi_vattr_context_create(vattr_context **c)
+{
+ return 0;
+}
+
+void slapi_vattr_context_destroy(vattr_context *c)
+{
+}
+
+int vattr_call_sp_get_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *buffer_flags, void* hint)
+{
+ int ret = -1;
+
+ if(handle->sp->sp_get_fn)
+ {
+ ret = ((handle->sp->sp_get_fn)(handle,c,e,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint));
+ }
+
+ return ret;
+}
+
+int vattr_call_sp_get_batch_values(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, char **type, Slapi_ValueSet*** results,int **type_name_disposition, char*** actual_type_name, int flags, int *buffer_flags, void** hint)
+{
+ int ret = 0;
+
+ if(handle->sp->sp_get_ex_fn)
+ {
+ ret = ((handle->sp->sp_get_ex_fn)(handle,c,e,type,results,type_name_disposition,actual_type_name,flags,buffer_flags, hint));
+ }
+ else
+ {
+ /* make our args look like the simple non-batched case */
+ *results = (Slapi_ValueSet**)slapi_ch_calloc(2, sizeof(*results)); /* 2 for null terminated list */
+ *type_name_disposition = (int *)slapi_ch_calloc(2, sizeof(*type_name_disposition));
+ *actual_type_name = (char**)slapi_ch_calloc(2, sizeof(*actual_type_name));
+
+ ret =((handle->sp->sp_get_fn)(handle,c,e,*type,*results,*type_name_disposition,*actual_type_name,flags,buffer_flags, hint));
+ if(ret)
+ {
+ slapi_ch_free((void**)results );
+ slapi_ch_free((void**)type_name_disposition );
+ slapi_ch_free((void**)actual_type_name );
+ }
+ }
+
+ return ret;
+}
+
+int vattr_call_sp_compare_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, vattr_get_thang *my_get, const char *type, Slapi_Value* test_this,int *result, int flags, void* hint)
+{
+ return ((handle->sp->sp_compare_fn)(handle,c,e,(char*)type,test_this,result,flags, hint));
+}
+
+int vattr_call_sp_get_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags)
+{
+ return ((handle->sp->sp_types_fn)(handle,e,type_context,flags));
+}
+
+/* Service provider entry point prototypes */
+
+/* Call which allows a SP to say what attributes can be used to define a given attribute, used for loop detection */
+/* Not implementing this yet */
+/* typedef int (*vattrspi_explain_definition) (); */
+
+/* Function called to indicate to the SP that the game is over, we free the handle, not the SP */
+typedef int (*vattrspi_deregister) (vattr_sp_handle *h);
+
+/* End of the SPI functions */
+
+/* Implementation functions only after here */
+
+/* The attribute map */
+
+/* We need a structure which can map attribute type names to SP's which might tell us
+something useful. We need a function which, given an attr type name, can return
+a set of SP's to ask about said attr. SP's which don't tell us which attrs they are
+handling always get asked. The first SP which tells us the answer wins, we don't
+attempt to arbitrate between them. One might imaging doing this stuff in a unified
+way with other stuff pertaining to types (schema, syntax). Someday. For now this
+is a separate thing in the insterests of stability.
+*/
+
+/* Virtual Attribute map implementation */
+
+/* The virtual attribute type map is implemented as a hash table.
+ The single key is the attribute type base name (not an alias)
+ (what about subtypes??). The hash table takes care of translating
+ this key to a list of probable service providers for the type.
+
+ Other than the obvious lookup function, we need functions to
+ allow entries to be added and removed from the map.
+
+ Because the map is likely to be consulted at least once for every search
+ operation performed by the server, it's important that it is free from
+ performance deficiencies such as lock contention (is the NSPR hash table
+ implementation even thread safe ?
+
+ */
+
+#define VARRT_MAP_HASHTABLE_SIZE 10
+
+/* Attribute map oject */
+/* Needs to contain: a linked list of pointers to provider handles handles,
+ The type name,
+ other stuff ?
+
+ Access to the entire map will be controlled via a single RW lock.
+ */
+
+struct _objAttrValue
+{
+ struct _objAttrValue *pNext;
+ Slapi_Value *val;
+};
+typedef struct _objAttrValue objAttrValue;
+
+struct _vattr_map_entry {
+ char * /* currect ? */ type_name;
+ vattr_sp_handle *sp_list;
+ objAttrValue *objectclasses; /* objectclasses for this type to check schema with*/
+};
+typedef struct _vattr_map_entry vattr_map_entry;
+
+
+vattr_map_entry test_entry = {NULL};
+
+struct _vattr_map {
+ PRRWLock *lock;
+ PLHashTable *hashtable; /* Hash table */
+};
+typedef struct _vattr_map vattr_map;
+
+static vattr_map *the_map = NULL;
+
+static PRIntn vattr_hash_compare_keys(const void *v1, const void *v2)
+{
+ /* Should this be subtype aware, etc ? */
+ return ( (0 == strcasecmp(v1,v2)) ? 1 : 0) ;
+}
+
+static PRIntn vattr_hash_compare_values(const void *v1, const void *v2)
+{
+ return( ((char *)v1 == (char *)v2 ) ? 1 : 0);
+}
+
+static PLHashNumber vattr_hash_fn(const void *type_name)
+{
+ /* need a hash function here */
+ /* Sum the bytes for now */
+ PLHashNumber result = 0;
+ char * current_position = NULL;
+ char current_char = 0;
+ for (current_position = (char*) type_name; *current_position; current_position++) {
+ current_char = tolower(*current_position);
+ result += current_char;
+ }
+ return result;
+}
+
+static int vattr_map_create()
+{
+ the_map = (vattr_map*)slapi_ch_calloc(1, sizeof(vattr_map));
+ if (NULL == the_map) {
+ slapd_nasty(sourcefile,1,0);
+ return ENOMEM;
+ }
+
+ the_map->hashtable = PL_NewHashTable(VARRT_MAP_HASHTABLE_SIZE,
+ vattr_hash_fn, vattr_hash_compare_keys,
+ vattr_hash_compare_values, NULL, NULL);
+
+ if (NULL == the_map->hashtable) {
+ slapd_nasty(sourcefile,2,0);
+ return ENOMEM;
+ }
+
+ the_map->lock = PR_NewRWLock(0,SOURCEFILE "1");
+ if (NULL == the_map) {
+ slapd_nasty(sourcefile,3,0);
+ return ENOMEM;
+ }
+ return 0;
+}
+
+static void vattr_map_destroy()
+{
+ if (the_map) {
+ if (the_map->hashtable) {
+ PL_HashTableDestroy(the_map->hashtable);
+ }
+ if (the_map->lock) {
+ PR_DestroyRWLock(the_map->lock);
+ }
+ }
+ slapi_ch_free ((void**)&the_map);
+}
+
+/* Returns 0 if present, entry returned in result. Returns SLAPI_VIRTUALATTRS_NOT_FOUND if not found */
+static int vattr_map_lookup(const char *type_to_find, vattr_map_entry **result)
+{
+ char *basetype = 0;
+ char *tmp = 0;
+ char buf[SLAPD_TYPICAL_ATTRIBUTE_NAME_MAX_LENGTH];
+
+ *result = NULL;
+ PR_ASSERT(the_map);
+
+ /* vattrs need to support subtypes
+ * we insist that one service provider
+ * will support all subtypes for a
+ * given superior, hence we look for
+ * superiors only here
+ */
+
+ tmp = slapi_attr_basetype( type_to_find, buf, sizeof(buf));
+ if(tmp)
+ {
+ basetype = tmp;
+ }
+ else
+ {
+ basetype = buf;
+ }
+
+ /* Get the reader lock */
+ PR_RWLock_Rlock(the_map->lock);
+ *result = (vattr_map_entry*)PL_HashTableLookupConst(the_map->hashtable,
+ (void*)basetype);
+ /* Release ze lock */
+ PR_RWLock_Unlock(the_map->lock);
+
+ if(tmp)
+ {
+ slapi_ch_free_string(&tmp);
+ }
+
+ if (*result) {
+ return 0;
+ } else {
+ return SLAPI_VIRTUALATTRS_NOT_FOUND;
+ }
+}
+
+/* Insert an entry into the attribute map */
+int vattr_map_insert(vattr_map_entry *vae)
+{
+ char *copy_of_type_name = NULL;
+ PR_ASSERT(the_map);
+ copy_of_type_name = slapi_ch_strdup(vae->type_name);
+ if (NULL == copy_of_type_name) {
+ slapd_nasty(sourcefile,6,0);
+ return ENOMEM;
+ }
+ /* Get the writer lock */
+ PR_RWLock_Wlock(the_map->lock);
+ /* Insert the thing */
+ /* It's illegal to call this function if the entry is already there */
+ PR_ASSERT(NULL == PL_HashTableLookupConst(the_map->hashtable,(void*)copy_of_type_name));
+ PL_HashTableAdd(the_map->hashtable,(void*)copy_of_type_name,(void*)vae);
+ /* Unlock and we're done */
+ PR_RWLock_Unlock(the_map->lock);
+ return 0;
+}
+
+/*
+ vattr_delete_attrvals
+ ---------------------
+ deletes a value list
+*/
+void vattr_delete_attrvals(objAttrValue **attrval)
+{
+ objAttrValue *val = *attrval;
+
+ while(val)
+ {
+ objAttrValue *next = val->pNext;
+ slapi_value_free(&val->val);
+ slapi_ch_free((void**)&val);
+ val = next;
+ }
+}
+
+/*
+ vattr_add_attrval
+ -----------------
+ adds a value to an attribute value list
+*/
+int vattr_add_attrval(objAttrValue **attrval, char *val)
+{
+ int ret = 0;
+ objAttrValue *theVal;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> vattr_add_attrval\n",0,0,0);
+
+ /* create the attrvalue */
+ theVal = (objAttrValue*) slapi_ch_malloc(sizeof(objAttrValue));
+ if(theVal)
+ {
+ theVal->val = slapi_value_new_string(val);
+ if(theVal->val)
+ {
+ theVal->pNext = *attrval;
+ *attrval = theVal;
+ }
+ else
+ {
+ slapi_ch_free((void**)&theVal);
+ LDAPDebug( LDAP_DEBUG_ANY, "vattr_add_attrval: failed to allocate memory\n",0,0,0);
+ ret = -1;
+ }
+ }
+ else
+ {
+ LDAPDebug( LDAP_DEBUG_ANY, "vattr_add_attrval: failed to allocate memory\n",0,0,0);
+ ret = -1;
+ }
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- vattr_add_attrval\n",0,0,0);
+ return ret;
+}
+
+
+objAttrValue *vattr_map_entry_build_schema(char *type_name)
+{
+ objAttrValue *ret = 0;
+ struct objclass *oc;
+ int attr_index = 0;
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "--> vattr_map_entry_build_schema\n",0,0,0);
+
+ /* this is the first opportunity to register
+ * with the statechange api, our init function
+ * gets called prior to loading plugins, so it
+ * was not available then
+ */
+ if(!statechange_api)
+ {
+ /* grab statechange api - we never release this */
+ if(!slapi_apib_get_interface(StateChange_v1_0_GUID, &statechange_api))
+ {
+ /* register for schema changes via dn */
+ statechange_register(statechange_api, "vattr", "cn=schema", NULL, NULL, (notify_callback) schema_changed_callback);
+ }
+ }
+
+ if(!config_get_schemacheck())
+ {
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- vattr_map_entry_build_schema - schema off\n",0,0,0);
+ return 0;
+ }
+
+ oc_lock_read();
+ for ( oc = g_get_global_oc_nolock(); oc != NULL; oc = oc->oc_next )
+ {
+ char **pppAttrs[2];
+ int index;
+ int attrType = 0;
+ int oc_added = 0;
+
+ pppAttrs[0] = oc->oc_required;
+ pppAttrs[1] = oc->oc_allowed;
+
+ /* we need to check both required and allowed attributes */
+ while(!oc_added && attrType < 2)
+ {
+ if(pppAttrs[attrType])
+ {
+ index = 0;
+
+ while(pppAttrs[attrType][index])
+ {
+ if(!PL_strcasecmp(pppAttrs[attrType][index], type_name))
+ {
+ vattr_add_attrval(&ret, oc->oc_name);
+ oc_added = 1;
+ break;
+ }
+ index++;
+ }
+ }
+ attrType++;
+ }
+ }
+ oc_unlock();
+
+ LDAPDebug( LDAP_DEBUG_TRACE, "<-- vattr_map_entry_build_schema\n",0,0,0);
+ return ret;
+}
+
+static PRIntn vattr_map_entry_rebuild_schema(PLHashEntry *he, PRIntn i, void *arg)
+{
+ vattr_map_entry *entry = (vattr_map_entry *)(he->value);
+
+ if(entry->objectclasses)
+ vattr_delete_attrvals(&(entry->objectclasses));
+
+ entry->objectclasses = vattr_map_entry_build_schema(entry->type_name);
+
+ return HT_ENUMERATE_NEXT;
+}
+
+void schema_changed_callback(Slapi_Entry *e, char *dn, int modtype, Slapi_PBlock *pb, void *caller_data)
+{
+ /* Get the writer lock */
+ PR_RWLock_Wlock(the_map->lock);
+
+ /* go through the list */
+ PL_HashTableEnumerateEntries(the_map->hashtable, vattr_map_entry_rebuild_schema, 0);
+
+ /* Unlock and we're done */
+ PR_RWLock_Unlock(the_map->lock);
+}
+
+
+int slapi_vattr_schema_check_type(Slapi_Entry *e, char *type)
+{
+ int ret = 0;
+ vattr_map_entry *map_entry;
+
+ if(config_get_schemacheck())
+ {
+ Slapi_Attr *attr;
+
+ if(0 == slapi_entry_attr_find(e, "objectclass", &attr))
+ {
+ Slapi_ValueSet *vs;
+
+ if(0 == slapi_attr_get_valueset(attr, &vs))
+ {
+ objAttrValue *obj;
+
+ if(0 == vattr_map_lookup(type, &map_entry))
+ {
+ PR_RWLock_Rlock(the_map->lock);
+
+ obj = map_entry->objectclasses;
+
+ while(obj)
+ {
+ if(slapi_valueset_find(attr, vs, obj->val))
+ {
+ /* this entry has an objectclass
+ * that allows or requires the
+ * attribute type
+ */
+ ret = -1;
+ break;
+ }
+
+ obj = obj->pNext;
+ }
+
+ PR_RWLock_Unlock(the_map->lock);
+ }
+
+ slapi_valueset_free(vs);
+ }
+ }
+
+ }
+ else
+ ret = -1;
+
+ return ret;
+}
+
+vattr_map_entry *vattr_map_entry_new(char *type_name, vattr_sp_handle *sph, void* hint)
+{
+ vattr_map_entry *result = NULL;
+ vattr_sp_handle *sp_copy = NULL;
+ sp_copy = (vattr_sp_handle*)slapi_ch_calloc(1, sizeof (vattr_sp_handle));
+ if (!sp_copy) {
+ return NULL;
+ }
+ sp_copy->sp = sph->sp;
+ sp_copy->hint = hint;
+ result = (vattr_map_entry*)slapi_ch_calloc(1, sizeof (vattr_map_entry));
+ if (result) {
+ result->type_name = slapi_ch_strdup(type_name);
+ result->sp_list = sp_copy;
+ }
+
+ /* go get schema */
+ result->objectclasses = vattr_map_entry_build_schema(type_name);
+
+ return result;
+}
+
+/* On top of the map, we need functions to manipulate the SP handles from within */
+
+/* Function to get the SP list from the map, given a type name */
+/* The resulting list is in the map, but is safe to read regardless of concurrent updates */
+vattr_sp_handle_list *vattr_map_sp_getlist(char *type_to_find)
+{
+ int ret = 0;
+ vattr_map_entry *result = NULL;
+ ret = vattr_map_lookup(type_to_find,&result);
+ if (0 == ret) {
+ return (vattr_sp_handle_list*) result->sp_list;
+ } else {
+ return NULL;
+ }
+}
+
+/* same as above, but filters the list based on the supplied backend dn
+ * when we stored these dn based attributes, we concatenated them with
+ * the dn like this dn::attribute, so we need to do two checks for the
+ * attribute, one with, and one without the dn
+ */
+vattr_sp_handle_list *vattr_map_namespace_sp_getlist(Slapi_DN *dn, const char *type_to_find)
+{
+ int ret = 0;
+ vattr_map_entry *result = NULL;
+ vattr_sp_handle_list* return_list = 0;
+
+ ret = vattr_map_lookup(type_to_find,&result);
+ if (0 == ret) {
+ return_list = (vattr_sp_handle_list*) result->sp_list;
+ } else {
+ /* we have allowed the global namespace provider a shot
+ * now it is time to query for split namespace providers
+ */
+ if(dn) {
+ char *split_dn = (char*)slapi_sdn_get_dn(dn);
+ char *split_type_to_find =
+ (char*)PR_smprintf("%s::%s",split_dn, type_to_find);
+
+ if(split_type_to_find)
+ {
+ ret = vattr_map_lookup(split_type_to_find,&result);
+ if (0 == ret) {
+ return_list = (vattr_sp_handle_list*) result->sp_list;
+ }
+
+ PR_smprintf_free(split_type_to_find);
+ }
+ }
+ }
+
+ return return_list;
+}
+
+
+/* Iterator function for the list */
+vattr_sp_handle *vattr_map_sp_next(vattr_sp_handle_list *list, void **hint)
+{
+ vattr_sp_handle *result = NULL;
+ vattr_sp_handle *current = (vattr_sp_handle*) list;
+ PR_ASSERT(list);
+ PR_ASSERT(hint);
+ result = current->next;
+ *hint = current->hint;
+ return result;
+}
+
+/* Iterator function for the list */
+vattr_sp_handle *vattr_map_sp_first(vattr_sp_handle_list *list, void **hint)
+{
+ vattr_sp_handle *result = NULL;
+ PR_ASSERT(list);
+ PR_ASSERT(hint);
+ result = (vattr_sp_handle*)list;
+ *hint = result->hint;
+ return result;
+}
+
+/* Iterator function for the list */
+vattr_sp_handle *vattr_list_sp_next(vattr_sp_handle_list *list)
+{
+ vattr_sp_handle *result = NULL;
+ vattr_sp_handle *current = (vattr_sp_handle*) list;
+ PR_ASSERT(list);
+ result = current->next;
+ return result;
+}
+
+/* Iterator function for the list */
+vattr_sp_handle *vattr_list_sp_first(vattr_sp_handle_list *list)
+{
+ vattr_sp_handle *result = NULL;
+ PR_ASSERT(list);
+ result = (vattr_sp_handle*)list;
+ return result;
+}
+
+/* Function to insert an SP into the map entry for a given type name */
+/* Note that SP's can't ever remmove themselves from the map---if they could
+we'd need to hold a lock on the read path, which we don't want to do.
+So any SP which relinquishes its need to handle a type needs to continue
+to handle the calls on it, but return nothing */
+/* DBDB need to sort out memory ownership here, it's not quite right */
+
+int vattr_map_sp_insert(char *type_to_add, vattr_sp_handle *sp, void *hint)
+{
+ int result = 0;
+ vattr_map_entry *map_entry = NULL;
+ /* Is this type already there ? */
+ result = vattr_map_lookup(type_to_add,&map_entry);
+ /* If it is, add this SP to the list, safely even if readers are traversing the list at the same time */
+ if (0 == result) {
+ int found = 0;
+ vattr_sp_handle *list_entry = NULL;
+ /* Walk the list checking that the daft SP isn't already here */
+ for (list_entry = map_entry->sp_list ; list_entry; list_entry = list_entry->next) {
+ if (list_entry == sp) {
+ found = 1;
+ break;
+ }
+ }
+ /* If it is, we do nothing */
+ if(found) {
+ return 0;
+ }
+ /* We insert the SP handle into the linked list at the head */
+ sp->next = map_entry->sp_list;
+ map_entry->sp_list = sp;
+ } else {
+ /* If not, add it */
+ map_entry = vattr_map_entry_new(type_to_add,sp,hint);
+ if (NULL == map_entry) {
+ return ENOMEM;
+ }
+ return vattr_map_insert(map_entry);
+ }
+ return 0;
+}
+
+/*
+ * returns non-zero if type is a cachable virtual attr, zero otherwise.
+ *
+ * Decision point for caching vattrs...to be expanded to be configurable,
+ * allow sp's to have a say etc.
+*/
+
+static int cache_all = 0;
+
+int slapi_vattrcache_iscacheable( const char * type ) {
+
+ int rc = 0;
+
+ if(/*cache_all ||*/ !slapi_UTF8CASECMP((char *)type, "nsrole")) {
+ rc = 1;
+ }
+
+ return(rc);
+}
+
+/*
+ * slapi_vattrcache_cache_all and slapi_vattrcache_cache_none
+ * ----------------------------------------------------------
+ * limited control for deciding whether to
+ * cache anything, in reality controls whether
+ * to cache cos attributes right now
+ */
+void slapi_vattrcache_cache_all()
+{
+ cache_all = -1;
+}
+
+void slapi_vattrcache_cache_none()
+{
+ cache_all = 0;
+}
+
+void vattrcache_entry_READ_LOCK(const Slapi_Entry *e){
+ PR_RWLock_Rlock(e->e_virtual_lock);
+}
+
+void vattrcache_entry_READ_UNLOCK(const Slapi_Entry *e) {
+ PR_RWLock_Unlock(e->e_virtual_lock);
+
+}
+void vattrcache_entry_WRITE_LOCK(const Slapi_Entry *e){
+ PR_RWLock_Wlock(e->e_virtual_lock);
+
+}
+void vattrcache_entry_WRITE_UNLOCK(const Slapi_Entry *e){
+ PR_RWLock_Unlock(e->e_virtual_lock);
+}
+
+#ifdef VATTR_TEST_CODE
+
+/* Prototype SP begins here */
+
+/* Get value function */
+int vattr_basic_sp_get_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *buffer_flags, void *hint)
+{
+ Slapi_Value *value = NULL;
+ *buffer_flags = 0;
+ *actual_type_name = slapi_ch_strdup("dbtestattr");
+ value = slapi_value_new_string("Hello Client");
+ *results = slapi_ch_calloc(1,sizeof(Slapi_ValueSet));
+ slapi_valueset_init(*results);
+ slapi_valueset_add_value_ext(*results,value,SLAPI_VALUE_FLAG_PASSIN);
+ return 0;
+}
+
+/* Compare value function */
+int vattr_basic_sp_compare_value(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result,int flags, void *hint)
+{
+ *result = 0;
+ return 0;
+}
+
+int vattr_basic_sp_list_types(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags)
+{
+ static char* test_type_name = "dbtestattr";
+ vattr_type_thang thang = {0};
+
+ thang.type_name = test_type_name;
+ thang.type_flags = 0;
+
+ slapi_vattrspi_add_type(type_context,&thang,SLAPI_VIRTUALATTRS_REQUEST_POINTERS);
+ return 0;
+}
+
+int vattr_basic_sp_init()
+{
+ int ret = 0;
+ vattr_sp_handle *my_handle = NULL;
+ /* Register SP */
+ ret = slapi_vattrspi_register(&my_handle,vattr_basic_sp_get_value, vattr_basic_sp_compare_value, vattr_basic_sp_list_types);
+ if (ret) {
+ slapd_nasty(sourcefile,4,0);
+ return ret;
+ }
+ /* Register interest in some attribute over the entire tree */
+ ret = slapi_vattrspi_regattr(my_handle,"dbtestattr","", NULL);
+ if (ret) {
+ slapd_nasty(sourcefile,5,0);
+ return ret;
+ }
+ /* Register interest in some attribute over the entire tree */
+ ret = slapi_vattrspi_regattr(my_handle,"dbtestattr1","", NULL);
+ if (ret) {
+ slapd_nasty(sourcefile,5,0);
+ return ret;
+ }
+ /* Register interest in some attribute over the entire tree */
+ ret = slapi_vattrspi_regattr(my_handle,"dbtestattr2","", NULL);
+ if (ret) {
+ slapd_nasty(sourcefile,5,0);
+ return ret;
+ }
+ /* Register interest in some attribute over the entire tree */
+ ret = slapi_vattrspi_regattr(my_handle,"dbtestatt3r","", NULL);
+ if (ret) {
+ slapd_nasty(sourcefile,5,0);
+ return ret;
+ }
+ return ret;
+}
+
+/* What do we do on shutdown ? */
+int vattr_basic_sp_cleanup()
+{
+ return 0;
+}
+
+#endif
+
+
+
+
diff --git a/ldap/servers/slapd/vattr_spi.h b/ldap/servers/slapd/vattr_spi.h
new file mode 100644
index 00000000..c9de3988
--- /dev/null
+++ b/ldap/servers/slapd/vattr_spi.h
@@ -0,0 +1,54 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* Defines the vattr SPI interface, used by COS and Roles at present */
+/* Also needs to be included by any code which participates in the vattr
+ loop detection scheme (e.g. filter test code)
+ */
+
+/* Loop context structure */
+typedef struct _vattr_context vattr_context;
+typedef struct _vattr_sp_handle vattr_sp_handle;
+typedef struct _vattr_type_list_context vattr_type_list_context;
+
+typedef int (*vattr_get_fn_type)(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_ValueSet** results,int *type_name_disposition, char** actual_type_name, int flags, int *free_flags, void *hint);
+typedef int (*vattr_get_ex_fn_type)(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char **type, Slapi_ValueSet*** results,int **type_name_disposition, char*** actual_type_name, int flags, int *free_flags, void **hint);
+typedef int (*vattr_compare_fn_type)(vattr_sp_handle *handle, vattr_context *c, Slapi_Entry *e, char *type, Slapi_Value *test_this, int* result, int flags, void *hint);
+typedef int (*vattr_types_fn_type)(vattr_sp_handle *handle,Slapi_Entry *e,vattr_type_list_context *type_context,int flags);
+
+vattr_context *vattr_context_new( Slapi_PBlock *pb );
+
+int slapi_vattrspi_register(vattr_sp_handle **h, vattr_get_fn_type get_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn);
+
+/* options must be set to null */
+int slapi_vattrspi_register_ex(vattr_sp_handle **h, vattr_get_ex_fn_type get_fn, vattr_compare_fn_type compare_fn, vattr_types_fn_type types_fn, void *options);
+int slapi_vattrspi_regattr(vattr_sp_handle *h,char *type_name_to_register, char* DN /* Is there a DN type ?? */, void *hint);
+
+/* Type thang structure used by slapi_vattrspi_add_type() */
+struct _vattr_type_thang {
+ char *type_name;
+ unsigned long type_flags; /* Same values as Slapi_Attr->a_flags */
+ Slapi_ValueSet *type_values; /* for slapi_vattr_list_attrs() use only */
+};
+
+int slapi_vattrspi_add_type(vattr_type_list_context *c, vattr_type_thang *thang, int flags);
+
+/* get thang structure used by slapi_vattr_values_get_sp() */
+struct _vattr_get_thang {
+ int get_present;
+ char *get_type_name;
+ int get_name_disposition;
+ Slapi_ValueSet *get_present_values;
+ Slapi_Attr *get_attr;
+};
+
+/* Loop-detection-aware versions of the functions, to be called by service providers and their ilk */
+SLAPI_DEPRECATED int slapi_vattr_values_get_sp(vattr_context *c, /* Entry we're interested in */ Slapi_Entry *e, /* attr type name */ char *type, /* pointer to result set */ Slapi_ValueSet** results,int *type_name_disposition, char **actual_type_name, int flags, int *free_flags);
+int slapi_vattr_values_get_sp_ex(vattr_context *c, /* Entry we're interested in */ Slapi_Entry *e, /* attr type name */ char *type, /* pointer to result set */ Slapi_ValueSet*** results,int **type_name_disposition, char ***actual_type_name, int flags, int *free_flags, int *subtype_count);
+int slapi_vattr_namespace_values_get_sp(vattr_context *c, /* Entry we're interested in */ Slapi_Entry *e, /* backend namespace dn */ Slapi_DN *namespace_dn, /* attr type name */ char *type, /* pointer to result set */ Slapi_ValueSet*** results,int **type_name_disposition, char ***actual_type_name, int flags, int *free_flags, int *subtype_count);
+int slapi_vattr_value_compare_sp(vattr_context *c, Slapi_Entry *e,char *type, Slapi_Value *test_this, int *result, int flags);
+int slapi_vattr_namespace_value_compare_sp(vattr_context *c,/* Entry we're interested in */ Slapi_Entry *e, /* backend namespace dn*/Slapi_DN *namespace_dn, /* attr type name */ const char *type, Slapi_Value *test_this,/* pointer to result */ int *result, int flags);
+
diff --git a/ldap/servers/slapd/views.h b/ldap/servers/slapd/views.h
new file mode 100644
index 00000000..10a7b135
--- /dev/null
+++ b/ldap/servers/slapd/views.h
@@ -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 **/
+
+#ifndef _VIEWS_H_
+#define _VIEWS_H_
+
+/* mechanics */
+
+typedef int (*api_views_entry_exists)(char *view_dn, Slapi_Entry *e);
+typedef int (*api_views_entry_dn_exists)(char *view_dn, char *e_dn);
+
+/* API ID for slapi_apib_get_interface */
+
+#define Views_v1_0_GUID "000e5b1e-9958-41da-a573-db8064a3894e"
+
+/* API */
+
+/* the api broker reserves api[0] for its use */
+
+#define views_entry_exists(api, dn, entry) \
+ ((api_views_entry_exists*)(api))[1]( dn, entry )
+
+#define views_entry_dn_exists(api, dn, entry_dn) \
+ ((api_views_entry_dn_exists*)(api))[2]( dn, entry_dn )
+
+#endif /*_VIEWS_H_*/
diff --git a/ldap/servers/snmp/Makefile b/ldap/servers/snmp/Makefile
new file mode 100644
index 00000000..4e40d8c0
--- /dev/null
+++ b/ldap/servers/snmp/Makefile
@@ -0,0 +1,91 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Make file SNMP subagent for Netscape Directory Server
+#
+#
+# Revision History:
+#
+# 07/31/97 Created by stevross
+#
+#
+
+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)
+
+OBJDEST = $(OBJDIR)/ns-ldapagt/obj
+INCLDEST = $(OBJDIR)/ns-ldapagt/include
+BINDIR = $(LDAP_SERVER_RELDIR)
+EXTDEST = $(BINDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+MCC_SERVER=
+
+ARCH := $(shell uname -s)
+ifneq ($(ARCH), WINNT)
+ARCH := $(shell $(MCOM_ROOT)/ldapserver/nsarch)
+endif
+
+
+SNMPMODULE = ns-ldapagt
+
+# the netscape-ldap.mib goes in the plugins/snmp directory, and the other mib like
+# files go in the plugins/snmp/mibs directory
+NSMIB_DEST_DIR = $(RELDIR)/plugins/snmp
+NSMIB_SRC_FILES = netscape-ldap.mib
+MIBS_DEST_DIR = $(NSMIB_DEST_DIR)/mibs
+MIBS_SRC_FILES = NETWORK-SERVICES-MIB.txt \
+ RFC1155-SMI.txt \
+ RFC-1215.txt \
+ SNMPv2-CONF.txt \
+ SNMPv2-SMI.txt \
+ SNMPv2-TC.txt
+MIB_DEST_FILES = $(addprefix $(MIBS_DEST_DIR)/,$(notdir $(MIBS_SRC_FILES))) \
+ $(addprefix $(NSMIB_DEST_DIR)/,$(NSMIB_SRC_FILES))
+
+default: all
+
+ifneq ($(ARCH), WINNT)
+all: $(EXTDEST)/$(SNMPMODULE) $(NSMIB_DEST_DIR)/$(NSMIB_SRC_FILES) $(MIB_DEST_FILES)
+else
+OBJ_SUFFIX=obj
+all: $(MIB_DEST_FILES)
+ cd ntagt; $(MAKE) $(MFLAGS) all
+endif
+
+# Rule to create destination directories
+$(MIBS_DEST_DIR) $(NSMIB_DEST_DIR):
+ $(MKDIR) $@
+
+# Rule to copy subagent binary to release area
+$(EXTDEST)/$(SNMPMODULE): $(EXTDEST)
+ifneq ($(ARCH), WINNT)
+ $(CP) $(NSCP_DISTDIR)/peer/obj/$(SNMPMODULE) $(EXTDEST)/$(SNMPMODULE)
+endif
+
+# this rule is for mib files in the local directory that go in the nsmib directory
+$(NSMIB_DEST_DIR)/$(NSMIB_SRC_FILES): $(NSMIB_DEST_DIR)
+ $(CP) ./$(NSMIB_SRC_FILES) $@
+
+# this rule is for mib files which go in the mibs subdir
+$(MIBS_DEST_DIR)/%: % $(MIBS_DEST_DIR)
+ $(CP) $< $@
+
+clean: localclean
+
+localclean:
+ifneq ($(ARCH), WINNT)
+ $(RM) $(EXTDEST)/$(SNMPMODULE)$(EXE_SUFFIX)
+endif
+
diff --git a/ldap/servers/snmp/NETWORK-SERVICES-MIB.txt b/ldap/servers/snmp/NETWORK-SERVICES-MIB.txt
new file mode 100644
index 00000000..cadc5504
--- /dev/null
+++ b/ldap/servers/snmp/NETWORK-SERVICES-MIB.txt
@@ -0,0 +1,650 @@
+-- extracted from rfc2788.txt
+-- at Fri Mar 24 07:07:18 2000
+
+ NETWORK-SERVICES-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ OBJECT-TYPE, Counter32, Gauge32, MODULE-IDENTITY, mib-2
+ FROM SNMPv2-SMI
+ TimeStamp, TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP
+ FROM SNMPv2-CONF
+ SnmpAdminString
+ FROM SNMP-FRAMEWORK-MIB;
+
+ application MODULE-IDENTITY
+ LAST-UPDATED "200003030000Z"
+ ORGANIZATION "IETF Mail and Directory Management Working Group"
+ CONTACT-INFO
+ " Ned Freed
+
+ Postal: Innosoft International, Inc.
+ 1050 Lakes Drive
+ West Covina, CA 91790
+ US
+
+ Tel: +1 626 919 3600
+ Fax: +1 626 919 3614
+
+ E-Mail: ned.freed@innosoft.com"
+ DESCRIPTION
+ "The MIB module describing network service applications"
+ REVISION "200003030000Z"
+ DESCRIPTION
+ "This revision, published in RFC 2788, changes a number of
+ DisplayStrings to SnmpAdminStrings. Note that this change
+ is not strictly supported by SMIv2. However, the alternative
+ of deprecating the old objects and defining new objects
+ would have a more adverse impact on backward compatibility
+ and interoperability, given the particular semantics of
+ these objects. The defining reference for distinguished
+ names has also been updated from RFC 1779 to RFC 2253."
+ REVISION "199905120000Z"
+ DESCRIPTION
+ "This revision fixes a few small technical problems found
+ in previous versions, mostly in regards to the conformance
+ groups for different versions of this MIB. No changes have
+ been made to the objects this MIB defines since RFC 2248."
+ REVISION "199708170000Z"
+ DESCRIPTION
+ "This revision, published in RFC 2248, adds the
+ applDescription and applURL objects, adds the quiescing
+ state to the applOperStatus object and renames the MIB
+ from the APPLICATION-MIB to the NETWORK-SERVICE-MIB."
+ REVISION "199311280000Z"
+ DESCRIPTION
+ "The original version of this MIB was published in RFC 1565"
+ ::= {mib-2 27}
+
+ -- Textual conventions
+
+ -- DistinguishedName is used to refer to objects in the
+ -- directory.
+
+ DistinguishedName ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION
+ "A Distinguished Name represented in accordance with
+ RFC 2253, presented in the UTF-8 charset defined in
+ RFC 2279."
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+ -- Uniform Resource Locators are stored in URLStrings.
+
+ URLString ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION
+ "A Uniform Resource Locator represented in accordance
+ with RFCs 1738 and 2368, presented in the NVT ASCII
+ charset defined in RFC 854."
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+ -- The basic applTable contains a list of the application
+ -- entities.
+
+ applTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF ApplEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The table holding objects which apply to all different
+ kinds of applications providing network services.
+ Each network service application capable of being
+ monitored should have a single entry in this table."
+ ::= {application 1}
+
+ applEntry OBJECT-TYPE
+ SYNTAX ApplEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry associated with a single network service
+ application."
+ INDEX {applIndex}
+ ::= {applTable 1}
+
+ ApplEntry ::= SEQUENCE {
+ applIndex
+ INTEGER,
+ applName
+ SnmpAdminString,
+ applDirectoryName
+ DistinguishedName,
+ applVersion
+ SnmpAdminString,
+ applUptime
+ TimeStamp,
+ applOperStatus
+ INTEGER,
+ applLastChange
+ TimeStamp,
+ applInboundAssociations
+ Gauge32,
+ applOutboundAssociations
+ Gauge32,
+ applAccumulatedInboundAssociations
+ Counter32,
+ applAccumulatedOutboundAssociations
+ Counter32,
+ applLastInboundActivity
+ TimeStamp,
+ applLastOutboundActivity
+ TimeStamp,
+ applRejectedInboundAssociations
+ Counter32,
+ applFailedOutboundAssociations
+ Counter32,
+ applDescription
+ SnmpAdminString,
+ applURL
+ URLString
+ }
+
+ applIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index to uniquely identify the network service
+ application. This attribute is the index used for
+ lexicographic ordering of the table."
+ ::= {applEntry 1}
+
+ applName OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name the network service application chooses to be
+ known by."
+ ::= {applEntry 2}
+
+ applDirectoryName OBJECT-TYPE
+ SYNTAX DistinguishedName
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The Distinguished Name of the directory entry where
+ static information about this application is stored.
+ An empty string indicates that no information about
+ the application is available in the directory."
+ ::= {applEntry 3}
+
+ applVersion OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The version of network service application software.
+ This field is usually defined by the vendor of the
+ network service application software."
+ ::= {applEntry 4}
+ applUptime OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time the network service
+ application was last initialized. If the application was
+ last initialized prior to the last initialization of the
+ network management subsystem, then this object contains
+ a zero value."
+ ::= {applEntry 5}
+
+ applOperStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1),
+ down(2),
+ halted(3),
+ congested(4),
+ restarting(5),
+ quiescing(6)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates the operational status of the network service
+ application. 'down' indicates that the network service is
+ not available. 'up' indicates that the network service
+ is operational and available. 'halted' indicates that the
+ service is operational but not available. 'congested'
+ indicates that the service is operational but no additional
+ inbound associations can be accommodated. 'restarting'
+ indicates that the service is currently unavailable but is
+ in the process of restarting and will be available soon.
+ 'quiescing' indicates that service is currently operational
+ but is in the process of shutting down. Additional inbound
+ associations may be rejected by applications in the
+ 'quiescing' state."
+ ::= {applEntry 6}
+
+ applLastChange OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time the network service
+ application entered its current operational state. If
+ the current state was entered prior to the last
+ initialization of the local network management subsystem,
+ then this object contains a zero value."
+ ::= {applEntry 7}
+
+ applInboundAssociations OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of current associations to the network service
+ application, where it is the responder. An inbound
+ association occurs when another application successfully
+ connects to this one."
+ ::= {applEntry 8}
+
+ applOutboundAssociations OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of current associations to the network service
+ application, where it is the initiator. An outbound
+ association occurs when this application successfully
+ connects to another one."
+ ::= {applEntry 9}
+
+ applAccumulatedInboundAssociations OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of associations to the application entity
+ since application initialization, where it was the responder."
+ ::= {applEntry 10}
+
+ applAccumulatedOutboundAssociations OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of associations to the application entity
+ since application initialization, where it was the initiator."
+ ::= {applEntry 11}
+
+ applLastInboundActivity OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time this application last
+ had an inbound association. If the last association
+ occurred prior to the last initialization of the network
+ subsystem, then this object contains a zero value."
+ ::= {applEntry 12}
+
+ applLastOutboundActivity OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time this application last
+ had an outbound association. If the last association
+ occurred prior to the last initialization of the network
+ subsystem, then this object contains a zero value."
+ ::= {applEntry 13}
+
+ applRejectedInboundAssociations OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of inbound associations the application
+ entity has rejected, since application initialization.
+ Rejected associations are not counted in the accumulated
+ association totals. Note that this only counts
+ associations the application entity has rejected itself;
+ it does not count rejections that occur at lower layers
+ of the network. Thus, this counter may not reflect the
+ true number of failed inbound associations."
+ ::= {applEntry 14}
+
+ applFailedOutboundAssociations OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number associations where the application entity
+ is initiator and association establishment has failed,
+ since application initialization. Failed associations are
+ not counted in the accumulated association totals."
+ ::= {applEntry 15}
+
+ applDescription OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A text description of the application. This information
+ is intended to identify and briefly describe the
+ application in a status display."
+ ::= {applEntry 16}
+
+ applURL OBJECT-TYPE
+ SYNTAX URLString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A URL pointing to a description of the application.
+ This information is intended to identify and describe
+ the application in a status display."
+ ::= {applEntry 17}
+
+ -- The assocTable augments the information in the applTable
+ -- with information about associations. Note that two levels
+ -- of compliance are specified below, depending on whether
+ -- association monitoring is mandated.
+
+ assocTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AssocEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The table holding a set of all active application
+ associations."
+ ::= {application 2}
+
+ assocEntry OBJECT-TYPE
+ SYNTAX AssocEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry associated with an association for a network
+ service application."
+ INDEX {applIndex, assocIndex}
+ ::= {assocTable 1}
+
+ AssocEntry ::= SEQUENCE {
+ assocIndex
+ INTEGER,
+ assocRemoteApplication
+ SnmpAdminString,
+ assocApplicationProtocol
+ OBJECT IDENTIFIER,
+ assocApplicationType
+ INTEGER,
+ assocDuration
+ TimeStamp
+ }
+
+ assocIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index to uniquely identify each association for a network
+ service application. This attribute is the index that is
+ used for lexicographic ordering of the table. Note that the
+ table is also indexed by the applIndex."
+ ::= {assocEntry 1}
+
+ assocRemoteApplication OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The name of the system running remote network service
+ application. For an IP-based application this should be
+ either a domain name or IP address. For an OSI application
+ it should be the string encoded distinguished name of the
+ managed object. For X.400(1984) MTAs which do not have a
+ Distinguished Name, the RFC 2156 syntax 'mta in
+ globalid' used in X400-Received: fields can be used. Note,
+ however, that not all connections an MTA makes are
+ necessarily to another MTA."
+ ::= {assocEntry 2}
+
+ assocApplicationProtocol OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An identification of the protocol being used for the
+ application. For an OSI Application, this will be the
+ Application Context. For Internet applications, OID
+ values of the form {applTCPProtoID port} or {applUDPProtoID
+ port} are used for TCP-based and UDP-based protocols,
+ respectively. In either case 'port' corresponds to the
+ primary port number being used by the protocol. The
+ usual IANA procedures may be used to register ports for
+ new protocols."
+ ::= {assocEntry 3}
+
+ assocApplicationType OBJECT-TYPE
+ SYNTAX INTEGER {
+ uainitiator(1),
+ uaresponder(2),
+ peerinitiator(3),
+ peerresponder(4)}
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This indicates whether the remote application is some type of
+ client making use of this network service (e.g., a Mail User
+ Agent) or a server acting as a peer. Also indicated is whether
+ the remote end initiated an incoming connection to the network
+ service or responded to an outgoing connection made by the
+ local application. MTAs and messaging gateways are
+ considered to be peers for the purposes of this variable."
+ ::= {assocEntry 4}
+
+ assocDuration OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time this association was
+ started. If this association started prior to the last
+ initialization of the network subsystem, then this
+ object contains a zero value."
+ ::= {assocEntry 5}
+
+
+ -- Conformance information
+
+ applConformance OBJECT IDENTIFIER ::= {application 3}
+
+ applGroups OBJECT IDENTIFIER ::= {applConformance 1}
+ applCompliances OBJECT IDENTIFIER ::= {applConformance 2}
+
+ -- Compliance statements
+
+ applCompliance MODULE-COMPLIANCE
+ STATUS obsolete
+ DESCRIPTION
+ "The compliance statement for RFC 1565 implementations
+ which support the Network Services Monitoring MIB
+ for basic monitoring of network service applications.
+ This is the basic compliance statement for RFC 1565."
+ MODULE
+ MANDATORY-GROUPS {applRFC1565Group}
+ ::= {applCompliances 1}
+
+ assocCompliance MODULE-COMPLIANCE
+ STATUS obsolete
+ DESCRIPTION
+ "The compliance statement for RFC 1565 implementations
+ which support the Network Services Monitoring MIB
+ for basic monitoring of network service applications
+ and their associations."
+ MODULE
+ MANDATORY-GROUPS {applRFC1565Group, assocRFC1565Group}
+ ::= {applCompliances 2}
+
+ applRFC2248Compliance MODULE-COMPLIANCE
+ STATUS deprecated
+ DESCRIPTION
+ "The compliance statement for RFC 2248 implementations
+ which support the Network Services Monitoring MIB
+ for basic monitoring of network service applications."
+ MODULE
+ MANDATORY-GROUPS {applRFC2248Group}
+ ::= {applCompliances 3}
+
+ assocRFC2248Compliance MODULE-COMPLIANCE
+ STATUS deprecated
+ DESCRIPTION
+ "The compliance statement for RFC 2248 implementations
+ which support the Network Services Monitoring MIB for
+ basic monitoring of network service applications and
+ their associations."
+ MODULE
+ MANDATORY-GROUPS {applRFC2248Group, assocRFC2248Group}
+ ::= {applCompliances 4}
+
+ applRFC2788Compliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for RFC 2788 implementations
+ which support the Network Services Monitoring MIB
+ for basic monitoring of network service applications."
+ MODULE
+ MANDATORY-GROUPS {applRFC2788Group}
+ ::= {applCompliances 5}
+
+ assocRFC2788Compliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for RFC 2788 implementations
+ which support the Network Services Monitoring MIB for
+ basic monitoring of network service applications and
+ their associations."
+ MODULE
+ MANDATORY-GROUPS {applRFC2788Group, assocRFC2788Group}
+ ::= {applCompliances 6}
+
+
+ -- Units of conformance
+
+ applRFC1565Group OBJECT-GROUP
+ OBJECTS {
+ applName, applVersion, applUptime, applOperStatus,
+ applLastChange, applInboundAssociations,
+ applOutboundAssociations, applAccumulatedInboundAssociations,
+ applAccumulatedOutboundAssociations, applLastInboundActivity,
+ applLastOutboundActivity, applRejectedInboundAssociations,
+ applFailedOutboundAssociations}
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects providing basic monitoring of
+ network service applications. This is the original set
+ of such objects defined in RFC 1565."
+ ::= {applGroups 7}
+
+ assocRFC1565Group OBJECT-GROUP
+ OBJECTS {
+ assocRemoteApplication, assocApplicationProtocol,
+ assocApplicationType, assocDuration}
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects providing basic monitoring of
+ network service applications' associations. This is the
+ original set of such objects defined in RFC 1565."
+ ::= {applGroups 2}
+
+ applRFC2248Group OBJECT-GROUP
+ OBJECTS {
+ applName, applVersion, applUptime, applOperStatus,
+ applLastChange, applInboundAssociations,
+ applOutboundAssociations, applAccumulatedInboundAssociations,
+ applAccumulatedOutboundAssociations, applLastInboundActivity,
+ applLastOutboundActivity, applRejectedInboundAssociations,
+ applFailedOutboundAssociations, applDescription, applURL}
+ STATUS deprecated
+ DESCRIPTION
+ "A collection of objects providing basic monitoring of
+ network service applications. This group was originally
+ defined in RFC 2248; note that applDirectoryName is
+ missing."
+ ::= {applGroups 3}
+
+ assocRFC2248Group OBJECT-GROUP
+ OBJECTS {
+ assocRemoteApplication, assocApplicationProtocol,
+ assocApplicationType, assocDuration}
+ STATUS deprecated
+ DESCRIPTION
+ "A collection of objects providing basic monitoring of
+ network service applications' associations. This group
+ was originally defined by RFC 2248."
+ ::= {applGroups 4}
+
+ applRFC2788Group OBJECT-GROUP
+ OBJECTS {
+ applName, applDirectoryName, applVersion, applUptime,
+ applOperStatus, applLastChange, applInboundAssociations,
+ applOutboundAssociations, applAccumulatedInboundAssociations,
+ applAccumulatedOutboundAssociations, applLastInboundActivity,
+ applLastOutboundActivity, applRejectedInboundAssociations,
+ applFailedOutboundAssociations, applDescription, applURL}
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic monitoring of
+ network service applications. This is the appropriate
+ group for RFC 2788 -- it adds the applDirectoryName object
+ missing in RFC 2248."
+ ::= {applGroups 5}
+
+ assocRFC2788Group OBJECT-GROUP
+ OBJECTS {
+ assocRemoteApplication, assocApplicationProtocol,
+ assocApplicationType, assocDuration}
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic monitoring of
+ network service applications' associations. This is
+ the appropriate group for RFC 2788."
+ ::= {applGroups 6}
+
+ -- OIDs of the form {applTCPProtoID port} are intended to be used
+ -- for TCP-based protocols that don't have OIDs assigned by other
+ -- means. {applUDPProtoID port} serves the same purpose for
+ -- UDP-based protocols. In either case 'port' corresponds to
+ -- the primary port number being used by the protocol. For example,
+ -- assuming no other OID is assigned for SMTP, an OID of
+ -- {applTCPProtoID 25} could be used, since SMTP is a TCP-based
+ -- protocol that uses port 25 as its primary port.
+
+ applTCPProtoID OBJECT IDENTIFIER ::= {application 4}
+ applUDPProtoID OBJECT IDENTIFIER ::= {application 5}
+
+ END
+
+--
+-- Copyright (C) The Internet Society (2000). All Rights Reserved.
+--
+-- This document and translations of it may be copied and furnished to
+-- others, and derivative works that comment on or otherwise explain it
+-- or assist in its implementation may be prepared, copied, published
+-- and distributed, in whole or in part, without restriction of any
+-- kind, provided that the above copyright notice and this paragraph are
+-- included on all such copies and derivative works. However, this
+-- document itself may not be modified in any way, such as by removing
+-- the copyright notice or references to the Internet Society or other
+-- Internet organizations, except as needed for the purpose of
+-- developing Internet standards in which case the procedures for
+-- copyrights defined in the Internet Standards process must be
+-- followed, or as required to translate it into languages other than
+-- English.
+--
+-- The limited permissions granted above are perpetual and will not be
+-- revoked by the Internet Society or its successors or assigns.
+--
+-- This document and the information contained herein is provided on an
+-- "AS IS" basis and THE INTERNET SOCIETY AND THE INTERNET ENGINEERING
+-- TASK FORCE DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
+-- BUT NOT LIMITED TO ANY WARRANTY THAT THE USE OF THE INFORMATION
+-- HEREIN WILL NOT INFRINGE ANY RIGHTS OR ANY IMPLIED WARRANTIES OF
+-- MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+--
diff --git a/ldap/servers/snmp/RFC-1215.txt b/ldap/servers/snmp/RFC-1215.txt
new file mode 100644
index 00000000..64327233
--- /dev/null
+++ b/ldap/servers/snmp/RFC-1215.txt
@@ -0,0 +1,38 @@
+
+RFC-1215 DEFINITIONS ::= BEGIN
+
+-- This module is a empty module. It has been created solely for the
+-- purpose of allowing other modules to correctly import the TRAP-TYPE
+-- clause from RFC-1215 where it should be imported from. It's a
+-- built in type in the UCD-SNMP code, and in fact RFC-1215 doesn't
+-- actually define a mib at all; it only defines macros. However,
+-- importing the TRAP-TYPE is conventionally done from an import
+-- clause pointing to RFC-1215.
+--
+-- Wes 7/17/98
+
+TRAP-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::= "ENTERPRISE" value
+ (enterprise OBJECT IDENTIFIER)
+ VarPart
+ DescrPart
+ ReferPart
+ VALUE NOTATION ::= value (VALUE INTEGER)
+ VarPart ::=
+ "VARIABLES" "{" VarTypes "}"
+ | empty
+ VarTypes ::=
+ VarType | VarTypes "," VarType
+ VarType ::=
+ value (vartype ObjectName)
+ DescrPart ::=
+ "DESCRIPTION" value (description DisplayString)
+ | empty
+ ReferPart ::=
+ "REFERENCE" value (reference DisplayString)
+ | empty
+END
+
+
+END
diff --git a/ldap/servers/snmp/RFC1155-SMI.txt b/ldap/servers/snmp/RFC1155-SMI.txt
new file mode 100644
index 00000000..3abc7ffb
--- /dev/null
+++ b/ldap/servers/snmp/RFC1155-SMI.txt
@@ -0,0 +1,119 @@
+RFC1155-SMI DEFINITIONS ::= BEGIN
+
+EXPORTS -- EVERYTHING
+ internet, directory, mgmt,
+ experimental, private, enterprises,
+ OBJECT-TYPE, ObjectName, ObjectSyntax, SimpleSyntax,
+ ApplicationSyntax, NetworkAddress, IpAddress,
+ Counter, Gauge, TimeTicks, Opaque;
+
+ -- the path to the root
+
+ internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }
+
+ directory OBJECT IDENTIFIER ::= { internet 1 }
+
+ mgmt OBJECT IDENTIFIER ::= { internet 2 }
+
+ experimental OBJECT IDENTIFIER ::= { internet 3 }
+
+ private OBJECT IDENTIFIER ::= { internet 4 }
+ enterprises OBJECT IDENTIFIER ::= { private 1 }
+
+ -- definition of object types
+
+ OBJECT-TYPE MACRO ::=
+ BEGIN
+ TYPE NOTATION ::= "SYNTAX" type (TYPE ObjectSyntax)
+ "ACCESS" Access
+ "STATUS" Status
+ VALUE NOTATION ::= value (VALUE ObjectName)
+
+ Access ::= "read-only"
+ | "read-write"
+ | "write-only"
+ | "not-accessible"
+ Status ::= "mandatory"
+ | "optional"
+ | "obsolete"
+ END
+
+ -- names of objects in the MIB
+
+ ObjectName ::=
+ OBJECT IDENTIFIER
+
+ -- syntax of objects in the MIB
+
+ ObjectSyntax ::=
+ CHOICE {
+ simple
+ SimpleSyntax,
+ -- note that simple SEQUENCEs are not directly
+ -- mentioned here to keep things simple (i.e.,
+ -- prevent mis-use). However, application-wide
+ -- types which are IMPLICITly encoded simple
+ -- SEQUENCEs may appear in the following CHOICE
+
+ application-wide
+ ApplicationSyntax
+ }
+
+ SimpleSyntax ::=
+ CHOICE {
+ number
+ INTEGER,
+ string
+ OCTET STRING,
+ object
+ OBJECT IDENTIFIER,
+ empty
+ NULL
+ }
+
+ ApplicationSyntax ::=
+ CHOICE {
+ address
+ NetworkAddress,
+ counter
+ Counter,
+ gauge
+ Gauge,
+ ticks
+ TimeTicks,
+ arbitrary
+ Opaque
+
+ -- other application-wide types, as they are
+ -- defined, will be added here
+ }
+
+ -- application-wide types
+
+ NetworkAddress ::=
+ CHOICE {
+ internet
+ IpAddress
+ }
+
+ IpAddress ::=
+ [APPLICATION 0] -- in network-byte order
+ IMPLICIT OCTET STRING (SIZE (4))
+
+ Counter ::=
+ [APPLICATION 1]
+ IMPLICIT INTEGER (0..4294967295)
+
+ Gauge ::=
+ [APPLICATION 2]
+ IMPLICIT INTEGER (0..4294967295)
+
+ TimeTicks ::=
+ [APPLICATION 3]
+ IMPLICIT INTEGER (0..4294967295)
+
+ Opaque ::=
+ [APPLICATION 4] -- arbitrary ASN.1 value,
+ IMPLICIT OCTET STRING -- "double-wrapped"
+
+ END
diff --git a/ldap/servers/snmp/SNMPv2-CONF.txt b/ldap/servers/snmp/SNMPv2-CONF.txt
new file mode 100644
index 00000000..24a1eed9
--- /dev/null
+++ b/ldap/servers/snmp/SNMPv2-CONF.txt
@@ -0,0 +1,322 @@
+SNMPv2-CONF DEFINITIONS ::= BEGIN
+
+IMPORTS ObjectName, NotificationName, ObjectSyntax
+ FROM SNMPv2-SMI;
+
+-- definitions for conformance groups
+
+OBJECT-GROUP MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ ObjectsPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ ObjectsPart ::=
+ "OBJECTS" "{" Objects "}"
+ Objects ::=
+ Object
+ | Objects "," Object
+ Object ::=
+
+ value(ObjectName)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- a character string as defined in [2]
+ Text ::= value(IA5String)
+END
+
+-- more definitions for conformance groups
+
+NOTIFICATION-GROUP MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ NotificationsPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ NotificationsPart ::=
+ "NOTIFICATIONS" "{" Notifications "}"
+ Notifications ::=
+ Notification
+ | Notifications "," Notification
+ Notification ::=
+ value(NotificationName)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- a character string as defined in [2]
+ Text ::= value(IA5String)
+END
+
+-- definitions for compliance statements
+
+MODULE-COMPLIANCE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+ ModulePart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ ModulePart ::=
+ Modules
+ Modules ::=
+ Module
+ | Modules Module
+ Module ::=
+ -- name of module --
+ "MODULE" ModuleName
+ MandatoryPart
+ CompliancePart
+
+ ModuleName ::=
+ -- identifier must start with uppercase letter
+ identifier ModuleIdentifier
+ -- must not be empty unless contained
+ -- in MIB Module
+ | empty
+ ModuleIdentifier ::=
+ value(OBJECT IDENTIFIER)
+ | empty
+
+ MandatoryPart ::=
+ "MANDATORY-GROUPS" "{" Groups "}"
+ | empty
+
+ Groups ::=
+
+ Group
+ | Groups "," Group
+ Group ::=
+ value(OBJECT IDENTIFIER)
+
+ CompliancePart ::=
+ Compliances
+ | empty
+
+ Compliances ::=
+ Compliance
+ | Compliances Compliance
+ Compliance ::=
+ ComplianceGroup
+ | Object
+
+ ComplianceGroup ::=
+ "GROUP" value(OBJECT IDENTIFIER)
+ "DESCRIPTION" Text
+
+ Object ::=
+ "OBJECT" value(ObjectName)
+ SyntaxPart
+ WriteSyntaxPart
+ AccessPart
+ "DESCRIPTION" Text
+
+ -- must be a refinement for object's SYNTAX clause
+ SyntaxPart ::= "SYNTAX" Syntax
+ | empty
+
+ -- must be a refinement for object's SYNTAX clause
+ WriteSyntaxPart ::= "WRITE-SYNTAX" Syntax
+ | empty
+
+ Syntax ::= -- Must be one of the following:
+ -- a base type (or its refinement),
+ -- a textual convention (or its refinement), or
+ -- a BITS pseudo-type
+ type
+ | "BITS" "{" NamedBits "}"
+
+ NamedBits ::= NamedBit
+ | NamedBits "," NamedBit
+
+ NamedBit ::= identifier "(" number ")" -- number is nonnegative
+
+ AccessPart ::=
+ "MIN-ACCESS" Access
+ | empty
+ Access ::=
+ "not-accessible"
+ | "accessible-for-notify"
+ | "read-only"
+ | "read-write"
+ | "read-create"
+
+ -- a character string as defined in [2]
+ Text ::= value(IA5String)
+END
+
+-- definitions for capabilities statements
+
+AGENT-CAPABILITIES MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "PRODUCT-RELEASE" Text
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+ ModulePart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ Status ::=
+ "current"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ ModulePart ::=
+ Modules
+ | empty
+ Modules ::=
+ Module
+ | Modules Module
+ Module ::=
+ -- name of module --
+ "SUPPORTS" ModuleName
+ "INCLUDES" "{" Groups "}"
+ VariationPart
+
+ ModuleName ::=
+
+ -- identifier must start with uppercase letter
+ identifier ModuleIdentifier
+ ModuleIdentifier ::=
+ value(OBJECT IDENTIFIER)
+ | empty
+
+ Groups ::=
+ Group
+ | Groups "," Group
+ Group ::=
+ value(OBJECT IDENTIFIER)
+
+ VariationPart ::=
+ Variations
+ | empty
+ Variations ::=
+ Variation
+ | Variations Variation
+
+ Variation ::=
+ ObjectVariation
+ | NotificationVariation
+
+ NotificationVariation ::=
+ "VARIATION" value(NotificationName)
+ AccessPart
+ "DESCRIPTION" Text
+
+ ObjectVariation ::=
+ "VARIATION" value(ObjectName)
+ SyntaxPart
+ WriteSyntaxPart
+ AccessPart
+ CreationPart
+ DefValPart
+ "DESCRIPTION" Text
+
+ -- must be a refinement for object's SYNTAX clause
+ SyntaxPart ::= "SYNTAX" Syntax
+ | empty
+
+ WriteSyntaxPart ::= "WRITE-SYNTAX" Syntax
+ | empty
+
+ Syntax ::= -- Must be one of the following:
+ -- a base type (or its refinement),
+ -- a textual convention (or its refinement), or
+ -- a BITS pseudo-type
+
+ type
+ | "BITS" "{" NamedBits "}"
+
+ NamedBits ::= NamedBit
+ | NamedBits "," NamedBit
+
+ NamedBit ::= identifier "(" number ")" -- number is nonnegative
+
+ AccessPart ::=
+ "ACCESS" Access
+ | empty
+
+ Access ::=
+ "not-implemented"
+ -- only "not-implemented" for notifications
+ | "accessible-for-notify"
+ | "read-only"
+ | "read-write"
+ | "read-create"
+ -- following is for backward-compatibility only
+ | "write-only"
+
+ CreationPart ::=
+ "CREATION-REQUIRES" "{" Cells "}"
+ | empty
+ Cells ::=
+ Cell
+ | Cells "," Cell
+ Cell ::=
+ value(ObjectName)
+
+ DefValPart ::= "DEFVAL" "{" Defvalue "}"
+ | empty
+
+ Defvalue ::= -- must be valid for the object's syntax
+ -- in this macro's SYNTAX clause, if present,
+ -- or if not, in object's OBJECT-TYPE macro
+ value(ObjectSyntax)
+ | "{" BitsValue "}"
+
+ BitsValue ::= BitNames
+ | empty
+
+ BitNames ::= BitName
+ | BitNames "," BitName
+
+ BitName ::= identifier
+
+ -- a character string as defined in [2]
+ Text ::= value(IA5String)
+END
+
+END
diff --git a/ldap/servers/snmp/SNMPv2-SMI.txt b/ldap/servers/snmp/SNMPv2-SMI.txt
new file mode 100644
index 00000000..1c01e1df
--- /dev/null
+++ b/ldap/servers/snmp/SNMPv2-SMI.txt
@@ -0,0 +1,344 @@
+SNMPv2-SMI DEFINITIONS ::= BEGIN
+
+-- the path to the root
+
+org OBJECT IDENTIFIER ::= { iso 3 } -- "iso" = 1
+dod OBJECT IDENTIFIER ::= { org 6 }
+internet OBJECT IDENTIFIER ::= { dod 1 }
+
+directory OBJECT IDENTIFIER ::= { internet 1 }
+
+mgmt OBJECT IDENTIFIER ::= { internet 2 }
+mib-2 OBJECT IDENTIFIER ::= { mgmt 1 }
+transmission OBJECT IDENTIFIER ::= { mib-2 10 }
+
+experimental OBJECT IDENTIFIER ::= { internet 3 }
+
+private OBJECT IDENTIFIER ::= { internet 4 }
+enterprises OBJECT IDENTIFIER ::= { private 1 }
+
+security OBJECT IDENTIFIER ::= { internet 5 }
+
+snmpV2 OBJECT IDENTIFIER ::= { internet 6 }
+
+-- transport domains
+snmpDomains OBJECT IDENTIFIER ::= { snmpV2 1 }
+
+-- transport proxies
+snmpProxys OBJECT IDENTIFIER ::= { snmpV2 2 }
+
+-- module identities
+snmpModules OBJECT IDENTIFIER ::= { snmpV2 3 }
+
+-- Extended UTCTime, to allow dates with four-digit years
+-- (Note that this definition of ExtUTCTime is not to be IMPORTed
+-- by MIB modules.)
+ExtUTCTime ::= OCTET STRING(SIZE(11 | 13))
+ -- format is YYMMDDHHMMZ or YYYYMMDDHHMMZ
+
+ -- where: YY - last two digits of year (only years
+ -- between 1900-1999)
+ -- YYYY - last four digits of the year (any year)
+ -- MM - month (01 through 12)
+ -- DD - day of month (01 through 31)
+ -- HH - hours (00 through 23)
+ -- MM - minutes (00 through 59)
+ -- Z - denotes GMT (the ASCII character Z)
+ --
+ -- For example, "9502192015Z" and "199502192015Z" represent
+ -- 8:15pm GMT on 19 February 1995. Years after 1999 must use
+ -- the four digit year format. Years 1900-1999 may use the
+ -- two or four digit format.
+
+-- definitions for information modules
+
+MODULE-IDENTITY MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "LAST-UPDATED" value(Update ExtUTCTime)
+ "ORGANIZATION" Text
+ "CONTACT-INFO" Text
+ "DESCRIPTION" Text
+ RevisionPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ RevisionPart ::=
+ Revisions
+ | empty
+ Revisions ::=
+ Revision
+ | Revisions Revision
+ Revision ::=
+ "REVISION" value(Update ExtUTCTime)
+ "DESCRIPTION" Text
+
+ -- a character string as defined in section 3.1.1
+ Text ::= value(IA5String)
+END
+
+OBJECT-IDENTITY MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "STATUS" Status
+ "DESCRIPTION" Text
+
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- a character string as defined in section 3.1.1
+ Text ::= value(IA5String)
+END
+
+-- names of objects
+-- (Note that these definitions of ObjectName and NotificationName
+-- are not to be IMPORTed by MIB modules.)
+
+ObjectName ::=
+ OBJECT IDENTIFIER
+
+NotificationName ::=
+ OBJECT IDENTIFIER
+
+-- syntax of objects
+
+-- the "base types" defined here are:
+-- 3 built-in ASN.1 types: INTEGER, OCTET STRING, OBJECT IDENTIFIER
+-- 8 application-defined types: Integer32, IpAddress, Counter32,
+-- Gauge32, Unsigned32, TimeTicks, Opaque, and Counter64
+
+ObjectSyntax ::=
+ CHOICE {
+ simple
+ SimpleSyntax,
+ -- note that SEQUENCEs for conceptual tables and
+ -- rows are not mentioned here...
+
+ application-wide
+ ApplicationSyntax
+ }
+
+-- built-in ASN.1 types
+
+SimpleSyntax ::=
+ CHOICE {
+ -- INTEGERs with a more restrictive range
+ -- may also be used
+ integer-value -- includes Integer32
+ INTEGER (-2147483648..2147483647),
+ -- OCTET STRINGs with a more restrictive size
+ -- may also be used
+ string-value
+ OCTET STRING (SIZE (0..65535)),
+ objectID-value
+ OBJECT IDENTIFIER
+ }
+
+-- indistinguishable from INTEGER, but never needs more than
+-- 32-bits for a two's complement representation
+Integer32 ::=
+ INTEGER (-2147483648..2147483647)
+
+-- application-wide types
+
+ApplicationSyntax ::=
+ CHOICE {
+ ipAddress-value
+ IpAddress,
+ counter-value
+ Counter32,
+ timeticks-value
+ TimeTicks,
+ arbitrary-value
+ Opaque,
+ big-counter-value
+ Counter64,
+ unsigned-integer-value -- includes Gauge32
+ Unsigned32
+ }
+
+-- in network-byte order
+
+-- (this is a tagged type for historical reasons)
+IpAddress ::=
+ [APPLICATION 0]
+ IMPLICIT OCTET STRING (SIZE (4))
+
+-- this wraps
+Counter32 ::=
+ [APPLICATION 1]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- this doesn't wrap
+Gauge32 ::=
+ [APPLICATION 2]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- an unsigned 32-bit quantity
+-- indistinguishable from Gauge32
+Unsigned32 ::=
+ [APPLICATION 2]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- hundredths of seconds since an epoch
+TimeTicks ::=
+ [APPLICATION 3]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- for backward-compatibility only
+Opaque ::=
+ [APPLICATION 4]
+ IMPLICIT OCTET STRING
+
+-- for counters that wrap in less than one hour with only 32 bits
+Counter64 ::=
+ [APPLICATION 6]
+ IMPLICIT INTEGER (0..18446744073709551615)
+
+-- definition for objects
+
+OBJECT-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "SYNTAX" Syntax
+ UnitsPart
+ "MAX-ACCESS" Access
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+ IndexPart
+ DefValPart
+
+ VALUE NOTATION ::=
+ value(VALUE ObjectName)
+
+ Syntax ::= -- Must be one of the following:
+ -- a base type (or its refinement),
+ -- a textual convention (or its refinement), or
+ -- a BITS pseudo-type
+ type
+ | "BITS" "{" NamedBits "}"
+
+ NamedBits ::= NamedBit
+ | NamedBits "," NamedBit
+
+ NamedBit ::= identifier "(" number ")" -- number is nonnegative
+
+ UnitsPart ::=
+ "UNITS" Text
+ | empty
+
+ Access ::=
+ "not-accessible"
+ | "accessible-for-notify"
+ | "read-only"
+ | "read-write"
+ | "read-create"
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ IndexPart ::=
+ "INDEX" "{" IndexTypes "}"
+ | "AUGMENTS" "{" Entry "}"
+ | empty
+ IndexTypes ::=
+ IndexType
+ | IndexTypes "," IndexType
+ IndexType ::=
+ "IMPLIED" Index
+ | Index
+
+ Index ::=
+ -- use the SYNTAX value of the
+ -- correspondent OBJECT-TYPE invocation
+ value(ObjectName)
+ Entry ::=
+ -- use the INDEX value of the
+ -- correspondent OBJECT-TYPE invocation
+ value(ObjectName)
+
+ DefValPart ::= "DEFVAL" "{" Defvalue "}"
+ | empty
+
+ Defvalue ::= -- must be valid for the type specified in
+ -- SYNTAX clause of same OBJECT-TYPE macro
+ value(ObjectSyntax)
+ | "{" BitsValue "}"
+
+ BitsValue ::= BitNames
+ | empty
+
+ BitNames ::= BitName
+ | BitNames "," BitName
+
+ BitName ::= identifier
+
+ -- a character string as defined in section 3.1.1
+ Text ::= value(IA5String)
+END
+
+-- definitions for notifications
+
+NOTIFICATION-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ ObjectsPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE NotificationName)
+
+ ObjectsPart ::=
+ "OBJECTS" "{" Objects "}"
+ | empty
+ Objects ::=
+ Object
+
+ | Objects "," Object
+ Object ::=
+ value(ObjectName)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- a character string as defined in section 3.1.1
+ Text ::= value(IA5String)
+END
+
+-- definitions of administrative identifiers
+
+zeroDotZero OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "A value used for null identifiers."
+ ::= { 0 0 }
+
+END
diff --git a/ldap/servers/snmp/SNMPv2-TC.txt b/ldap/servers/snmp/SNMPv2-TC.txt
new file mode 100644
index 00000000..860bf71e
--- /dev/null
+++ b/ldap/servers/snmp/SNMPv2-TC.txt
@@ -0,0 +1,772 @@
+SNMPv2-TC DEFINITIONS ::= BEGIN
+
+IMPORTS
+ TimeTicks FROM SNMPv2-SMI;
+
+-- definition of textual conventions
+
+TEXTUAL-CONVENTION MACRO ::=
+
+BEGIN
+ TYPE NOTATION ::=
+ DisplayPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+ "SYNTAX" Syntax
+
+ VALUE NOTATION ::=
+ value(VALUE Syntax) -- adapted ASN.1
+
+ DisplayPart ::=
+ "DISPLAY-HINT" Text
+ | empty
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- a character string as defined in [2]
+ Text ::= value(IA5String)
+
+ Syntax ::= -- Must be one of the following:
+ -- a base type (or its refinement), or
+ -- a BITS pseudo-type
+ type
+ | "BITS" "{" NamedBits "}"
+
+ NamedBits ::= NamedBit
+ | NamedBits "," NamedBit
+
+ NamedBit ::= identifier "(" number ")" -- number is nonnegative
+
+END
+
+DisplayString ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION
+ "Represents textual information taken from the NVT ASCII
+
+ character set, as defined in pages 4, 10-11 of RFC 854.
+
+ To summarize RFC 854, the NVT ASCII repertoire specifies:
+
+ - the use of character codes 0-127 (decimal)
+
+ - the graphics characters (32-126) are interpreted as
+ US ASCII
+
+ - NUL, LF, CR, BEL, BS, HT, VT and FF have the special
+ meanings specified in RFC 854
+
+ - the other 25 codes have no standard interpretation
+
+ - the sequence 'CR LF' means newline
+
+ - the sequence 'CR NUL' means carriage-return
+
+ - an 'LF' not preceded by a 'CR' means moving to the
+ same column on the next line.
+
+ - the sequence 'CR x' for any x other than LF or NUL is
+ illegal. (Note that this also means that a string may
+ end with either 'CR LF' or 'CR NUL', but not with CR.)
+
+ Any object defined using this syntax may not exceed 255
+ characters in length."
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+PhysAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1x:"
+ STATUS current
+ DESCRIPTION
+ "Represents media- or physical-level addresses."
+ SYNTAX OCTET STRING
+
+MacAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1x:"
+ STATUS current
+ DESCRIPTION
+ "Represents an 802 MAC address represented in the
+ `canonical' order defined by IEEE 802.1a, i.e., as if it
+ were transmitted least significant bit first, even though
+ 802.5 (in contrast to other 802.x protocols) requires MAC
+ addresses to be transmitted most significant bit first."
+ SYNTAX OCTET STRING (SIZE (6))
+
+TruthValue ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents a boolean value."
+ SYNTAX INTEGER { true(1), false(2) }
+
+TestAndIncr ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents integer-valued information used for atomic
+ operations. When the management protocol is used to specify
+ that an object instance having this syntax is to be
+ modified, the new value supplied via the management protocol
+ must precisely match the value presently held by the
+ instance. If not, the management protocol set operation
+ fails with an error of `inconsistentValue'. Otherwise, if
+ the current value is the maximum value of 2^31-1 (2147483647
+ decimal), then the value held by the instance is wrapped to
+ zero; otherwise, the value held by the instance is
+ incremented by one. (Note that regardless of whether the
+ management protocol set operation succeeds, the variable-
+ binding in the request and response PDUs are identical.)
+
+ The value of the ACCESS clause for objects having this
+ syntax is either `read-write' or `read-create'. When an
+ instance of a columnar object having this syntax is created,
+ any value may be supplied via the management protocol.
+
+ When the network management portion of the system is re-
+ initialized, the value of every object instance having this
+ syntax must either be incremented from its value prior to
+ the re-initialization, or (if the value prior to the re-
+ initialization is unknown) be set to a pseudo-randomly
+ generated value."
+ SYNTAX INTEGER (0..2147483647)
+
+AutonomousType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents an independently extensible type identification
+ value. It may, for example, indicate a particular sub-tree
+ with further MIB definitions, or define a particular type of
+ protocol or hardware."
+ SYNTAX OBJECT IDENTIFIER
+
+InstancePointer ::= TEXTUAL-CONVENTION
+ STATUS obsolete
+ DESCRIPTION
+ "A pointer to either a specific instance of a MIB object or
+ a conceptual row of a MIB table in the managed device. In
+ the latter case, by convention, it is the name of the
+ particular instance of the first accessible columnar object
+ in the conceptual row.
+
+ The two uses of this textual convention are replaced by
+ VariablePointer and RowPointer, respectively."
+ SYNTAX OBJECT IDENTIFIER
+
+VariablePointer ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A pointer to a specific object instance. For example,
+ sysContact.0 or ifInOctets.3."
+ SYNTAX OBJECT IDENTIFIER
+
+RowPointer ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents a pointer to a conceptual row. The value is the
+ name of the instance of the first accessible columnar object
+ in the conceptual row.
+
+ For example, ifIndex.3 would point to the 3rd row in the
+ ifTable (note that if ifIndex were not-accessible, then
+ ifDescr.3 would be used instead)."
+ SYNTAX OBJECT IDENTIFIER
+
+RowStatus ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "The RowStatus textual convention is used to manage the
+ creation and deletion of conceptual rows, and is used as the
+ value of the SYNTAX clause for the status column of a
+ conceptual row (as described in Section 7.7.1 of [2].)
+
+ The status column has six defined values:
+
+ - `active', which indicates that the conceptual row is
+ available for use by the managed device;
+
+ - `notInService', which indicates that the conceptual
+ row exists in the agent, but is unavailable for use by
+ the managed device (see NOTE below); 'notInService' has
+ no implication regarding the internal consistency of
+ the row, availability of resources, or consistency with
+ the current state of the managed device;
+
+ - `notReady', which indicates that the conceptual row
+ exists in the agent, but is missing information
+ necessary in order to be available for use by the
+ managed device (i.e., one or more required columns in
+ the conceptual row have not been instanciated);
+
+ - `createAndGo', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row and to have its status automatically set
+ to active, making it available for use by the managed
+ device;
+
+ - `createAndWait', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row (but not make it available for use by
+ the managed device); and,
+ - `destroy', which is supplied by a management station
+ wishing to delete all of the instances associated with
+ an existing conceptual row.
+
+ Whereas five of the six values (all except `notReady') may
+ be specified in a management protocol set operation, only
+ three values will be returned in response to a management
+ protocol retrieval operation: `notReady', `notInService' or
+ `active'. That is, when queried, an existing conceptual row
+ has only three states: it is either available for use by
+ the managed device (the status column has value `active');
+ it is not available for use by the managed device, though
+ the agent has sufficient information to attempt to make it
+ so (the status column has value `notInService'); or, it is
+ not available for use by the managed device, and an attempt
+ to make it so would fail because the agent has insufficient
+ information (the state column has value `notReady').
+
+ NOTE WELL
+
+ This textual convention may be used for a MIB table,
+ irrespective of whether the values of that table's
+ conceptual rows are able to be modified while it is
+ active, or whether its conceptual rows must be taken
+ out of service in order to be modified. That is, it is
+ the responsibility of the DESCRIPTION clause of the
+ status column to specify whether the status column must
+ not be `active' in order for the value of some other
+ column of the same conceptual row to be modified. If
+ such a specification is made, affected columns may be
+ changed by an SNMP set PDU if the RowStatus would not
+ be equal to `active' either immediately before or after
+ processing the PDU. In other words, if the PDU also
+ contained a varbind that would change the RowStatus
+ value, the column in question may be changed if the
+ RowStatus was not equal to `active' as the PDU was
+ received, or if the varbind sets the status to a value
+ other than 'active'.
+
+ Also note that whenever any elements of a row exist, the
+ RowStatus column must also exist.
+
+ To summarize the effect of having a conceptual row with a
+ status column having a SYNTAX clause value of RowStatus,
+ consider the following state diagram:
+
+ STATE
+ +--------------+-----------+-------------+-------------
+ | A | B | C | D
+ | |status col.|status column|
+ |status column | is | is |status column
+ ACTION |does not exist| notReady | notInService| is active
+--------------+--------------+-----------+-------------+-------------
+set status |noError ->D|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndGo |inconsistent- | | |
+ | Value| | |
+--------------+--------------+-----------+-------------+-------------
+set status |noError see 1|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndWait |wrongValue | | |
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError
+column to | Value| entValue| |
+active | | | |
+ | | or | |
+ | | | |
+ | |see 2 ->D|see 8 ->D| ->D
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError ->C
+column to | Value| entValue| |
+notInService | | | |
+ | | or | | or
+ | | | |
+ | |see 3 ->C| ->C|see 6
+--------------+--------------+-----------+-------------+-------------
+set status |noError |noError |noError |noError ->A
+column to | | | | or
+destroy | ->A| ->A| ->A|see 7
+--------------+--------------+-----------+-------------+-------------
+set any other |see 4 |noError |noError |see 5
+column to some| | | |
+value | | see 1| ->C| ->D
+--------------+--------------+-----------+-------------+-------------
+
+ (1) goto B or C, depending on information available to the
+ agent.
+
+ (2) if other variable bindings included in the same PDU,
+ provide values for all columns which are missing but
+ required, and all columns have acceptable values, then
+ return noError and goto D.
+
+ (3) if other variable bindings included in the same PDU,
+ provide legal values for all columns which are missing but
+ required, then return noError and goto C.
+
+ (4) at the discretion of the agent, the return value may be
+ either:
+
+ inconsistentName: because the agent does not choose to
+ create such an instance when the corresponding
+ RowStatus instance does not exist, or
+
+ inconsistentValue: if the supplied value is
+ inconsistent with the state of some other MIB object's
+ value, or
+
+ noError: because the agent chooses to create the
+ instance.
+
+ If noError is returned, then the instance of the status
+ column must also be created, and the new state is B or C,
+ depending on the information available to the agent. If
+ inconsistentName or inconsistentValue is returned, the row
+ remains in state A.
+
+ (5) depending on the MIB definition for the column/table,
+ either noError or inconsistentValue may be returned.
+
+ (6) the return value can indicate one of the following
+ errors:
+
+ wrongValue: because the agent does not support
+ notInService (e.g., an agent which does not support
+ createAndWait), or
+
+ inconsistentValue: because the agent is unable to take
+ the row out of service at this time, perhaps because it
+ is in use and cannot be de-activated.
+
+ (7) the return value can indicate the following error:
+
+ inconsistentValue: because the agent is unable to
+ remove the row at this time, perhaps because it is in
+ use and cannot be de-activated.
+
+ (8) the transition to D can fail, e.g., if the values of the
+ conceptual row are inconsistent, then the error code would
+ be inconsistentValue.
+
+ NOTE: Other processing of (this and other varbinds of) the
+ set request may result in a response other than noError
+ being returned, e.g., wrongValue, noCreation, etc.
+
+ Conceptual Row Creation
+
+ There are four potential interactions when creating a
+ conceptual row: selecting an instance-identifier which is
+ not in use; creating the conceptual row; initializing any
+ objects for which the agent does not supply a default; and,
+ making the conceptual row available for use by the managed
+ device.
+
+ Interaction 1: Selecting an Instance-Identifier
+
+ The algorithm used to select an instance-identifier varies
+ for each conceptual row. In some cases, the instance-
+ identifier is semantically significant, e.g., the
+ destination address of a route, and a management station
+ selects the instance-identifier according to the semantics.
+
+ In other cases, the instance-identifier is used solely to
+ distinguish conceptual rows, and a management station
+ without specific knowledge of the conceptual row might
+ examine the instances present in order to determine an
+ unused instance-identifier. (This approach may be used, but
+ it is often highly sub-optimal; however, it is also a
+ questionable practice for a naive management station to
+ attempt conceptual row creation.)
+
+ Alternately, the MIB module which defines the conceptual row
+ might provide one or more objects which provide assistance
+ in determining an unused instance-identifier. For example,
+ if the conceptual row is indexed by an integer-value, then
+ an object having an integer-valued SYNTAX clause might be
+ defined for such a purpose, allowing a management station to
+ issue a management protocol retrieval operation. In order
+ to avoid unnecessary collisions between competing management
+ stations, `adjacent' retrievals of this object should be
+ different.
+
+ Finally, the management station could select a pseudo-random
+ number to use as the index. In the event that this index
+
+ was already in use and an inconsistentValue was returned in
+ response to the management protocol set operation, the
+ management station should simply select a new pseudo-random
+ number and retry the operation.
+
+ A MIB designer should choose between the two latter
+ algorithms based on the size of the table (and therefore the
+ efficiency of each algorithm). For tables in which a large
+ number of entries are expected, it is recommended that a MIB
+ object be defined that returns an acceptable index for
+ creation. For tables with small numbers of entries, it is
+ recommended that the latter pseudo-random index mechanism be
+ used.
+
+ Interaction 2: Creating the Conceptual Row
+
+ Once an unused instance-identifier has been selected, the
+ management station determines if it wishes to create and
+ activate the conceptual row in one transaction or in a
+ negotiated set of interactions.
+
+ Interaction 2a: Creating and Activating the Conceptual Row
+
+ The management station must first determine the column
+ requirements, i.e., it must determine those columns for
+ which it must or must not provide values. Depending on the
+ complexity of the table and the management station's
+ knowledge of the agent's capabilities, this determination
+ can be made locally by the management station. Alternately,
+ the management station issues a management protocol get
+ operation to examine all columns in the conceptual row that
+ it wishes to create. In response, for each column, there
+ are three possible outcomes:
+
+ - a value is returned, indicating that some other
+ management station has already created this conceptual
+ row. We return to interaction 1.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. For those
+ columns to which the agent provides read-create access,
+ the `noSuchInstance' exception tells the management
+ station that it should supply a value for this column
+ when the conceptual row is to be created.
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station can not issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ Once the column requirements have been determined, a
+ management protocol set operation is accordingly issued.
+ This operation also sets the new instance of the status
+ column to `createAndGo'.
+
+ When the agent processes the set operation, it verifies that
+ it has sufficient information to make the conceptual row
+ available for use by the managed device. The information
+ available to the agent is provided by two sources: the
+ management protocol set operation which creates the
+ conceptual row, and, implementation-specific defaults
+ supplied by the agent (note that an agent must provide
+ implementation-specific defaults for at least those objects
+ which it implements as read-only). If there is sufficient
+ information available, then the conceptual row is created, a
+ `noError' response is returned, the status column is set to
+ `active', and no further interactions are necessary (i.e.,
+ interactions 3 and 4 are skipped). If there is insufficient
+ information, then the conceptual row is not created, and the
+ set operation fails with an error of `inconsistentValue'.
+ On this error, the management station can issue a management
+ protocol retrieval operation to determine if this was
+ because it failed to specify a value for a required column,
+ or, because the selected instance of the status column
+ already existed. In the latter case, we return to
+ interaction 1. In the former case, the management station
+ can re-issue the set operation with the additional
+ information, or begin interaction 2 again using
+ `createAndWait' in order to negotiate creation of the
+ conceptual row.
+
+ NOTE WELL
+
+ Regardless of the method used to determine the column
+ requirements, it is possible that the management
+ station might deem a column necessary when, in fact,
+ the agent will not allow that particular columnar
+ instance to be created or written. In this case, the
+ management protocol set operation will fail with an
+ error such as `noCreation' or `notWritable'. In this
+ case, the management station decides whether it needs
+ to be able to set a value for that particular columnar
+ instance. If not, the management station re-issues the
+ management protocol set operation, but without setting
+ a value for that particular columnar instance;
+ otherwise, the management station aborts the row
+ creation algorithm.
+
+ Interaction 2b: Negotiating the Creation of the Conceptual
+ Row
+
+ The management station issues a management protocol set
+ operation which sets the desired instance of the status
+ column to `createAndWait'. If the agent is unwilling to
+ process a request of this sort, the set operation fails with
+ an error of `wrongValue'. (As a consequence, such an agent
+ must be prepared to accept a single management protocol set
+ operation, i.e., interaction 2a above, containing all of the
+ columns indicated by its column requirements.) Otherwise,
+ the conceptual row is created, a `noError' response is
+ returned, and the status column is immediately set to either
+ `notInService' or `notReady', depending on whether it has
+ sufficient information to (attempt to) make the conceptual
+ row available for use by the managed device. If there is
+ sufficient information available, then the status column is
+ set to `notInService'; otherwise, if there is insufficient
+ information, then the status column is set to `notReady'.
+ Regardless, we proceed to interaction 3.
+
+ Interaction 3: Initializing non-defaulted Objects
+
+ The management station must now determine the column
+ requirements. It issues a management protocol get operation
+ to examine all columns in the created conceptual row. In
+ the response, for each column, there are three possible
+ outcomes:
+
+ - a value is returned, indicating that the agent
+ implements the object-type associated with this column
+ and had sufficient information to provide a value. For
+ those columns to which the agent provides read-create
+ access (and for which the agent allows their values to
+ be changed after their creation), a value return tells
+ the management station that it may issue additional
+ management protocol set operations, if it desires, in
+ order to change the value associated with this column.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. However,
+ the agent does not have sufficient information to
+ provide a value, and until a value is provided, the
+ conceptual row may not be made available for use by the
+ managed device. For those columns to which the agent
+ provides read-create access, the `noSuchInstance'
+ exception tells the management station that it must
+ issue additional management protocol set operations, in
+ order to provide a value associated with this column.
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station can not issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ If the value associated with the status column is
+ `notReady', then the management station must first deal with
+ all `noSuchInstance' columns, if any. Having done so, the
+ value of the status column becomes `notInService', and we
+ proceed to interaction 4.
+
+ Interaction 4: Making the Conceptual Row Available
+
+ Once the management station is satisfied with the values
+ associated with the columns of the conceptual row, it issues
+ a management protocol set operation to set the status column
+ to `active'. If the agent has sufficient information to
+ make the conceptual row available for use by the managed
+ device, the management protocol set operation succeeds (a
+ `noError' response is returned). Otherwise, the management
+ protocol set operation fails with an error of
+ `inconsistentValue'.
+
+ NOTE WELL
+
+ A conceptual row having a status column with value
+ `notInService' or `notReady' is unavailable to the
+ managed device. As such, it is possible for the
+ managed device to create its own instances during the
+ time between the management protocol set operation
+ which sets the status column to `createAndWait' and the
+ management protocol set operation which sets the status
+ column to `active'. In this case, when the management
+ protocol set operation is issued to set the status
+ column to `active', the values held in the agent
+ supersede those used by the managed device.
+
+ If the management station is prevented from setting the
+ status column to `active' (e.g., due to management station
+ or network failure) the conceptual row will be left in the
+ `notInService' or `notReady' state, consuming resources
+ indefinitely. The agent must detect conceptual rows that
+ have been in either state for an abnormally long period of
+ time and remove them. It is the responsibility of the
+ DESCRIPTION clause of the status column to indicate what an
+ abnormally long period of time would be. This period of
+ time should be long enough to allow for human response time
+ (including `think time') between the creation of the
+ conceptual row and the setting of the status to `active'.
+ In the absence of such information in the DESCRIPTION
+ clause, it is suggested that this period be approximately 5
+ minutes in length. This removal action applies not only to
+ newly-created rows, but also to previously active rows which
+ are set to, and left in, the notInService state for a
+ prolonged period exceeding that which is considered normal
+ for such a conceptual row.
+
+ Conceptual Row Suspension
+
+ When a conceptual row is `active', the management station
+ may issue a management protocol set operation which sets the
+ instance of the status column to `notInService'. If the
+ agent is unwilling to do so, the set operation fails with an
+ error of `wrongValue' or `inconsistentValue'. Otherwise,
+ the conceptual row is taken out of service, and a `noError'
+ response is returned. It is the responsibility of the
+ DESCRIPTION clause of the status column to indicate under
+ what circumstances the status column should be taken out of
+ service (e.g., in order for the value of some other column
+ of the same conceptual row to be modified).
+
+ Conceptual Row Deletion
+
+ For deletion of conceptual rows, a management protocol set
+ operation is issued which sets the instance of the status
+ column to `destroy'. This request may be made regardless of
+ the current value of the status column (e.g., it is possible
+ to delete conceptual rows which are either `notReady',
+ `notInService' or `active'.) If the operation succeeds,
+ then all instances associated with the conceptual row are
+ immediately removed."
+ SYNTAX INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+TimeStamp ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "The value of the sysUpTime object at which a specific
+ occurrence happened. The specific occurrence must be
+
+ defined in the description of any object defined using this
+ type.
+
+ If sysUpTime is reset to zero as a result of a re-
+ initialization of the network management (sub)system, then
+ the values of all TimeStamp objects are also reset.
+ However, after approximately 497 days without a re-
+ initialization, the sysUpTime object will reach 2^^32-1 and
+ then increment around to zero; in this case, existing values
+ of TimeStamp objects do not change. This can lead to
+ ambiguities in the value of TimeStamp objects."
+ SYNTAX TimeTicks
+
+TimeInterval ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A period of time, measured in units of 0.01 seconds."
+ SYNTAX INTEGER (0..2147483647)
+
+DateAndTime ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
+ STATUS current
+ DESCRIPTION
+ "A date-time specification.
+
+ field octets contents range
+ ----- ------ -------- -----
+ 1 1-2 year* 0..65536
+ 2 3 month 1..12
+ 3 4 day 1..31
+ 4 5 hour 0..23
+ 5 6 minutes 0..59
+ 6 7 seconds 0..60
+ (use 60 for leap-second)
+ 7 8 deci-seconds 0..9
+ 8 9 direction from UTC '+' / '-'
+ 9 10 hours from UTC* 0..13
+ 10 11 minutes from UTC 0..59
+
+ * Notes:
+ - the value of year is in network-byte order
+ - daylight saving time in New Zealand is +13
+
+ For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+ displayed as:
+
+ 1992-5-26,13:30:15.0,-4:0
+
+ Note that if only local time is known, then timezone
+ information (fields 8-10) is not present."
+ SYNTAX OCTET STRING (SIZE (8 | 11))
+
+StorageType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Describes the memory realization of a conceptual row. A
+ row which is volatile(2) is lost upon reboot. A row which
+ is either nonVolatile(3), permanent(4) or readOnly(5), is
+ backed up by stable storage. A row which is permanent(4)
+ can be changed but not deleted. A row which is readOnly(5)
+ cannot be changed nor deleted.
+
+ If the value of an object with this syntax is either
+ permanent(4) or readOnly(5), it cannot be written.
+ Conversely, if the value is either other(1), volatile(2) or
+ nonVolatile(3), it cannot be modified to be permanent(4) or
+ readOnly(5). (All illegal modifications result in a
+ 'wrongValue' error.)
+
+ Every usage of this textual convention is required to
+ specify the columnar objects which a permanent(4) row must
+ at a minimum allow to be writable."
+ SYNTAX INTEGER {
+ other(1), -- eh?
+ volatile(2), -- e.g., in RAM
+ nonVolatile(3), -- e.g., in NVRAM
+ permanent(4), -- e.g., partially in ROM
+ readOnly(5) -- e.g., completely in ROM
+ }
+
+TDomain ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Denotes a kind of transport service.
+
+ Some possible values, such as snmpUDPDomain, are defined in
+ the SNMPv2-TM MIB module. Other possible values are defined
+ in other MIB modules."
+ REFERENCE "The SNMPv2-TM MIB module is defined in RFC 1906."
+ SYNTAX OBJECT IDENTIFIER
+
+TAddress ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Denotes a transport service address.
+
+ A TAddress value is always interpreted within the context of a
+ TDomain value. Thus, each definition of a TDomain value must
+ be accompanied by a definition of a textual convention for use
+ with that TDomain. Some possible textual conventions, such as
+ SnmpUDPAddress for snmpUDPDomain, are defined in the SNMPv2-TM
+ MIB module. Other possible textual conventions are defined in
+ other MIB modules."
+ REFERENCE "The SNMPv2-TM MIB module is defined in RFC 1906."
+ SYNTAX OCTET STRING (SIZE (1..255))
+
+END
diff --git a/ldap/servers/snmp/netscape-ldap.mib b/ldap/servers/snmp/netscape-ldap.mib
new file mode 100644
index 00000000..3e51839a
--- /dev/null
+++ b/ldap/servers/snmp/netscape-ldap.mib
@@ -0,0 +1,727 @@
+-- BEGIN COPYRIGHT BLOCK
+-- Copyright 2001 Sun Microsystems, Inc.
+-- Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+-- All rights reserved.
+-- END COPYRIGHT BLOCK
+--
+--
+-- MIB for Netscape Directory Server 7
+--
+-- This is an implementation of the MADMAN mib for monitoring LDAP/CLDAP and X.500
+-- directories described in RFC 2788 and 2789
+-- with the addition of traps for server up and down events
+
+NSLDAP-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, Counter32, Gauge32, OBJECT-TYPE
+ FROM SNMPv2-SMI
+ DisplayString, TimeStamp, TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP
+ FROM SNMPv2-CONF
+ applIndex, DistinguishedName, URLString
+ FROM NETWORK-SERVICES-MIB
+ enterprises
+ FROM RFC1155-SMI
+ TRAP-TYPE
+ FROM RFC-1215;
+
+ netscape OBJECT IDENTIFIER ::= { enterprises 1450 }
+
+ URLString ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "I couldn't find it but madman said it should be here, guessing DisplayString"
+ SYNTAX DisplayString
+
+ nsldap MODULE-IDENTITY
+ LAST-UPDATED "200207160000Z"
+ ORGANIZATION "Netscape Communications Corp"
+ CONTACT-INFO
+ " AOL Strategic Business Solutions
+ Postal: 22000 AOL Way
+ Dulles, VA 20166
+
+ Website: http://enterprise.netscape.com"
+ DESCRIPTION
+ " An implementation of the MADMAN mib for monitoring LDAP/CLDAP and X.500
+ directories described in RFC 2788 and 2789
+ used for Netscape Directory Server 7"
+ ::= { netscape 7}
+
+ dsOpsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF DsOpsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ " The table holding information related to the
+ DS operations."
+ ::= {nsldap 1}
+
+ dsOpsEntry OBJECT-TYPE
+ SYNTAX DsOpsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ " Entry containing operations related statistics
+ for a DS."
+ INDEX { applIndex}
+ ::= {dsOpsTable 1}
+
+ DsOpsEntry ::= SEQUENCE {
+
+ -- Bindings
+
+ dsAnonymousBinds
+ Counter32,
+ dsUnAuthBinds
+ Counter32,
+ dsSimpleAuthBinds
+ Counter32,
+ dsStrongAuthBinds
+ Counter32,
+ dsBindSecurityErrors
+ Counter32,
+
+ -- In-coming operations
+
+ dsInOps
+ Counter32,
+ dsReadOps
+ Counter32,
+ dsCompareOps
+ Counter32,
+ dsAddEntryOps
+ Counter32,
+ dsRemoveEntryOps
+ Counter32,
+ dsModifyEntryOps
+ Counter32,
+ dsModifyRDNOps
+ Counter32,
+ dsListOps
+ Counter32,
+ dsSearchOps
+ Counter32,
+ dsOneLevelSearchOps
+ Counter32,
+ dsWholeSubtreeSearchOps
+ Counter32,
+
+ -- Out going operations
+
+ dsReferrals
+ Counter32,
+ dsChainings
+ Counter32,
+
+ -- Errors
+
+ dsSecurityErrors
+ Counter32,
+ dsErrors
+ Counter32
+ }
+
+ -- CLDAP does not use binds; for A CLDAP DS the bind
+ -- related counters will be inaccessible.
+ --
+ -- CLDAP and LDAP implement "Read" and "List" operations
+ -- indirectly via the "search" operation; the following
+ -- counters will be inaccessible for CLDAP and LDAP DSs:
+ -- dsReadOps, dsListOps
+ --
+ -- CLDAP does not implement "Compare", "Add", "Remove",
+ -- "Modify", "ModifyRDN"; the following counters will be
+ -- inaccessible for CLDAP DSs:
+ -- dsCompareOps, dsAddEntryOps, dsRemoveEntryOps,
+ -- dsModifyEntryOps, dsModifyRDNOps.
+ --
+ -- CLDAP and LDAP DS's do not return Referrals
+ -- the following fields will remain inaccessible for
+ -- CLDAP and LDAP DSs: dsReferrals.
+
+ dsAnonymousBinds OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of anonymous binds to this DS from UAs
+ since application start."
+ ::= {dsOpsEntry 1}
+
+ dsUnAuthBinds OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of un-authenticated binds to this DS since
+ application start."
+ ::= {dsOpsEntry 2}
+
+ dsSimpleAuthBinds OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of binds to this DS that were authenticated
+ using simple authentication procedures since
+ application start."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 8.1.2.1.1. and, RFC1777 Section 4.1"
+ ::= {dsOpsEntry 3}
+
+ dsStrongAuthBinds OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of binds to this DS that were authenticated
+ using the strong authentication procedures since
+ application start. This includes the binds that were
+ authenticated using external authentication procedures."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Sections 8.1.2.1.2 & 8.1.2.1.3. and, RFC1777 Section 4.1."
+ ::= {dsOpsEntry 4}
+
+ dsBindSecurityErrors OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of bind operations that have been rejected
+ by this DS due to inappropriateAuthentication or
+ invalidCredentials."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 12.7.2 and, RFC1777 Section 4."
+ ::= {dsOpsEntry 5}
+
+ dsInOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of operations forwarded to this DS
+ from UAs or other DSs since application
+ start up."
+ ::= {dsOpsEntry 6}
+
+ dsReadOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of read operations serviced by
+ this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 9.1."
+ ::= {dsOpsEntry 7}
+
+ dsCompareOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of compare operations serviced by
+ this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 9.2. and, RFC1777 section 4.8"
+ ::= {dsOpsEntry 8}
+
+ dsAddEntryOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of addEntry operations serviced by
+ this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 11.1. and, RFC1777 Section 4.5."
+ ::= {dsOpsEntry 9}
+
+ dsRemoveEntryOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of removeEntry operations serviced by
+ this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 11.2. and, RFC1777 Section 4.6."
+ ::= {dsOpsEntry 10}
+
+ dsModifyEntryOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of modifyEntry operations serviced by
+ this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 11.3. and, RFC1777 Section 4.4."
+ ::= {dsOpsEntry 11}
+
+ dsModifyRDNOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of modifyRDN operations serviced by
+ this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 11.4.and, RFC1777 Section 4.7"
+ ::= {dsOpsEntry 12}
+
+ dsListOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of list operations serviced by
+ this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 10.1."
+ ::= {dsOpsEntry 13}
+
+ dsSearchOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of search operations- baseObject searches,
+ oneLevel searches and wholeSubtree searches,
+ serviced by this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 10.2. and, RFC1777 Section 4.3."
+ ::= {dsOpsEntry 14}
+
+ dsOneLevelSearchOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of oneLevel search operations serviced
+ by this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 10.2.2.2. and, RFC1777 Section 4.3."
+ ::= {dsOpsEntry 15}
+
+ dsWholeSubtreeSearchOps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of wholeSubtree search operations serviced
+ by this DS since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 10.2.2.2. and, RFC1777 Section 4.3."
+ ::= {dsOpsEntry 16}
+
+ dsReferrals OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of referrals returned by this DS in response
+ to requests for operations since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 12.6."
+ ::= {dsOpsEntry 17}
+
+ dsChainings OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of operations forwarded by this DS
+ to other DSs since application startup."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.518, 1988:
+ Section 14."
+ ::= {dsOpsEntry 18}
+
+ dsSecurityErrors OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of operations forwarded to this DS
+ which did not meet the security requirements. "
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Section 12.7. and, RFC1777 Section 4."
+ ::= {dsOpsEntry 19}
+
+ dsErrors OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of operations that could not be serviced
+ due to errors other than security errors, and
+ referrals.
+ A partially serviced operation will not be counted
+ as an error.
+ The errors include NameErrors, UpdateErrors, Attribute
+ errors and ServiceErrors."
+ REFERENCE
+ " CCITT Blue Book Fascicle VIII.8 - Rec. X.511, 1988:
+ Sections 12.4, 12.5, 12.8 & 12.9. and, RFC1777 Section 4."
+ ::= {dsOpsEntry 20}
+
+ -- Entry statistics/Cache performance
+ dsEntriesTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF DsEntriesEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ " The table holding information related to the
+ entry statistics and cache performance of the DSs."
+ ::= {nsldap 2}
+
+ dsEntriesEntry OBJECT-TYPE
+ SYNTAX DsEntriesEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ " Entry containing statistics pertaining to entries
+ held by a DS."
+ INDEX { applIndex }
+ ::= {dsEntriesTable 1}
+
+
+ DsEntriesEntry ::= SEQUENCE {
+
+ dsMasterEntries
+ Gauge32,
+ dsCopyEntries
+ Gauge32,
+ dsCacheEntries
+ Gauge32,
+ dsCacheHits
+ Counter32,
+ dsSlaveHits
+ Counter32
+ }
+
+ -- A (C)LDAP frontend to the X.500 Directory will not have
+ -- MasterEntries, CopyEntries; the following counters will
+ -- be inaccessible for LDAP/CLDAP frontends to the X.500
+ -- directory: dsMasterEntries, dsCopyEntries, dsSlaveHits.
+
+ dsMasterEntries OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of entries mastered in the DS."
+ ::= {dsEntriesEntry 1}
+
+ dsCopyEntries OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of entries for which systematic (slave)
+ copies are maintained in the DS."
+ ::= {dsEntriesEntry 2}
+
+ dsCacheEntries OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of entries cached (non-systematic copies) in
+ the DS. This will include the entries that are
+ cached partially. The negative cache is not counted."
+ ::= {dsEntriesEntry 3}
+
+ dsCacheHits OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of operations that were serviced from
+ the locally held cache since application
+ startup."
+ ::= {dsEntriesEntry 4}
+
+ dsSlaveHits OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Number of operations that were serviced from
+ the locally held object replications ( shadow
+ entries) since application startup."
+ ::= {dsEntriesEntry 5}
+
+ -- The dsIntTable contains statistical data on the peer DSs
+ -- with which the monitored DSs (attempt to) interact. This
+ -- table will provide a useful insight into the effect of
+ -- neighbours on the DS performance.
+ -- The table keeps track of the last "N" DSs with which the
+ -- monitored DSs has interacted (attempted to interact),
+ -- where "N" is a locally-defined constant.
+
+ dsIntTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF DsIntEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ " Each row of this table contains some details
+ related to the history of the interaction
+ of the monitored DSs with their respective
+ peer DSs."
+ ::= { nsldap 3 }
+
+ dsIntEntry OBJECT-TYPE
+ SYNTAX DsIntEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ " Entry containing interaction details of a DS
+ with a peer DS."
+ INDEX { applIndex, dsIntIndex }
+ ::= { dsIntTable 1 }
+
+ DsIntEntry ::= SEQUENCE {
+
+ dsIntIndex
+ INTEGER,
+ dsName
+ DistinguishedName,
+ dsTimeOfCreation
+ TimeStamp,
+ dsTimeOfLastAttempt
+ TimeStamp,
+ dsTimeOfLastSuccess
+ TimeStamp,
+ dsFailuresSinceLastSuccess
+ Counter32,
+ dsFailures
+ Counter32,
+ dsSuccesses
+ Counter32,
+ dsURL
+ URLString
+
+ }
+
+ dsIntIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ " Together with applIndex it forms the unique key to
+ identify the conceptual row which contains useful info
+ on the (attempted) interaction between the DS (referred
+ to by applIndex) and a peer DS."
+ ::= {dsIntEntry 1}
+
+ dsName OBJECT-TYPE
+ SYNTAX DistinguishedName
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Distinguished Name of the peer DS to which this
+ entry pertains."
+ ::= {dsIntEntry 2}
+
+ dsTimeOfCreation OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " The value of sysUpTime when this row was created.
+ If the entry was created before the network management
+ subsystem was initialized, this object will contain
+ a value of zero."
+ ::= {dsIntEntry 3}
+
+ dsTimeOfLastAttempt OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " The value of sysUpTime when the last attempt was made
+ to contact this DS. If the last attempt was made before
+ the network management subsystem was initialized, this
+ object will contain a value of zero."
+ ::= {dsIntEntry 4}
+
+ dsTimeOfLastSuccess OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " The value of sysUpTime when the last attempt made to
+ contact this DS was successful. If there have
+ been no successful attempts this entry will have a value
+ of zero. If the last successful attempt was made before
+ the network management subsystem was initialized, this
+ object will contain a value of zero."
+ ::= {dsIntEntry 5}
+
+ dsFailuresSinceLastSuccess OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " The number of failures since the last time an
+ attempt to contact this DS was successful. If
+ there has been no successful attempts, this counter
+ will contain the number of failures since this entry
+ was created."
+ ::= {dsIntEntry 6}
+
+ dsFailures OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Cumulative failures since the creation of
+ this entry."
+ ::= {dsIntEntry 7}
+
+ dsSuccesses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " Cumulative successes since the creation of
+ this entry."
+ ::= {dsIntEntry 8}
+
+ dsURL OBJECT-TYPE
+ SYNTAX URLString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ " URL of the DS application."
+ ::= {dsIntEntry 9}
+
+--
+-- Information about this installation of the directory server
+--
+
+ dsEntityTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF DsEntityEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table holds general information related to an installed
+ instance of a directory server"
+ ::= {nsldap 5}
+
+ dsEntityEntry OBJECT-TYPE
+ SYNTAX DsEntityEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Entry of general information about an installed instance
+ of a directory server"
+ INDEX { applIndex}
+ ::= {dsEntityTable 1}
+
+ DsEntityEntry ::= SEQUENCE {
+ dsEntityDescr
+ DisplayString,
+ dsEntityVers
+ DisplayString,
+ dsEntityOrg
+ DisplayString,
+ dsEntityLocation
+ DisplayString,
+ dsEntityContact
+ DisplayString,
+ dsEntityName
+ DisplayString
+ }
+
+ dsEntityDescr OBJECT-TYPE
+ SYNTAX DisplayString(SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A general textual description of this directory server."
+ ::= {dsEntityEntry 1}
+
+ dsEntityVers OBJECT-TYPE
+ SYNTAX DisplayString(SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The version of this directory server"
+ ::={dsEntityEntry 2}
+
+ dsEntityOrg OBJECT-TYPE
+ SYNTAX DisplayString(SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Organization responsible for directory server at this installation"
+ ::={dsEntityEntry 3}
+
+ dsEntityLocation OBJECT-TYPE
+ SYNTAX DisplayString(SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Physical location of this entity (directory server).
+ For example: hostname, building number, lab number, etc."
+ ::={dsEntityEntry 4}
+
+ dsEntityContact OBJECT-TYPE
+ SYNTAX DisplayString(SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Contact person(s)responsible for the directory server at this
+ installation, together with information on how to conact."
+ ::={dsEntityEntry 5}
+
+ dsEntityName OBJECT-TYPE
+ SYNTAX DisplayString(SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "Name assigned to this entity at the installation site"
+ ::={dsEntityEntry 6}
+
+--
+-- Traps
+--
+--
+ nsDirectoryServerDown TRAP-TYPE
+ ENTERPRISE netscape
+ VARIABLES { dsEntityDescr, dsEntityVers, dsEntityLocation,
+ dsEntityContact }
+ DESCRIPTION "This trap is generated whenever the agent detects the
+ directory server to be (potentially) Down."
+ ::= 7001
+
+ nsDirectoryServerStart TRAP-TYPE
+ ENTERPRISE netscape
+ VARIABLES { dsEntityDescr, dsEntityVers, dsEntityLocation }
+ DESCRIPTION "This trap is generated whenever the agent detects the
+ directory server to have (re)started."
+ ::= 7002
+
+ END
+
diff --git a/ldap/servers/snmp/ntagt/Makefile b/ldap/servers/snmp/ntagt/Makefile
new file mode 100644
index 00000000..22605b2f
--- /dev/null
+++ b/ldap/servers/snmp/ntagt/Makefile
@@ -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
+#
+#############################################################################
+# SNMP NT Subagent Common Rulesets #
+#############################################################################
+
+MCOM_ROOT = ../../../../..
+MSRV_ROOT = ../../..
+SLAPD_ROOT = $(MSRV_ROOT)/servers/slapd
+SNMP_ROOT = $(MSRV_ROOT)/servers/snmp
+LIBDEST = $(OBJDIR)/obj
+BINDIR = $(LDAP_SERVER_RELDIR)
+
+NOSTDCLEAN = true # don't let nsconfig.mk define target clean
+NOSTDSTRIP = true # don't let nsconfig.mk define target strip
+NSPR20 = true
+
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(MSRV_ROOT)/nsldap.mk
+
+OBJ_SUFFIX = obj
+
+INCLUDES += -I../../slapd -I$(MCOM_ROOT)/ldapserver/ldap/include
+
+CCOPTS += $(CFLAGS) $(DLL_CFLAGS) $(MCC_INCLUDE) $(INCLUDES) -I$(SNMP_ROOT)
+CXXOPTS += $(CFLAGS) $(DLL_CXXFLAGS) $(MCC_INCLUDE) $(INCLUDES) -I$(SNMP_ROOT)
+
+EXTRA_LIBS = advapi32.lib user32.lib snmpapi.lib mgmtapi.lib $(LDAP_SDK_LIBLDAP_DLL)
+
+#############################################################################
+# SNMP NT Subagent Core Components #
+#############################################################################
+
+LOCAL_SRCS = agtmmap.c \
+ nsldapagt_nt.c \
+ nsldapmib_nt.c
+
+SNMP_SRCS = $(LOCAL_SRCS)
+
+LOCAL_INCS = agtmmap.h \
+ nsldapagt_nt.h \
+ nsldapmib_nt.h
+
+SNMP_INCS = $(LOCAL_INCS)
+
+SNMP_OBJS = $(addprefix $(LIBDEST)/, \
+ agtmmap.$(OBJ_SUFFIX) \
+ nsldapagt_nt.$(OBJ_SUFFIX) \
+ nsldapmib_nt.$(OBJ_SUFFIX))
+
+
+SNMP_LIB = ns-ldapagt.$(DLL_SUFFIX)
+SNMP_IMPLIB = ns-ldapagt.$(LIB_SUFFIX)
+
+#############################################################################
+# SNMP NT Subagent Build Rules #
+#############################################################################
+
+# Now we get into the actual build rules
+AGTMMAP = agtmmap
+
+all: $(LDAP_SERVER_RELDIR) $(AGTMMAP) $(BINDIR)/$(SNMP_LIB)
+
+over: clean all
+
+$(AGTMMAP): $(SLAPD_ROOT)/$(AGTMMAP).c $(SLAPD_ROOT)/$(AGTMMAP).h
+ $(CP) $(SLAPD_ROOT)/$(AGTMMAP).c .
+ $(CP) $(SLAPD_ROOT)/$(AGTMMAP).h .
+
+$(SNMP_OBJS): $(SNMP_SRCS) $(SNMP_INCS)
+
+$(BINDIR)/$(SNMP_LIB): $(SNMP_OBJS) $(SNMP_RES) Makefile
+ $(LINK_DLL) $(LD_EXTRAS) /DEF:"nsldapagt_nt.def" /VERSION:"7" \
+ $(SNMP_OBJS) $(EXTRA_LIBS)
+
+$(LIBDEST)/%.$(OBJ_SUFFIX): %.cxx
+ $(CCP) -c $(CXXOPTS) $< -Fo$(LIBDEST)/$*.$(OBJ_SUFFIX)
+
+$(LIBDEST)/%.$(OBJ_SUFFIX): %.c
+ $(CC) -c $(CCOPTS) $< -Fo$(LIBDEST)/$*.$(OBJ_SUFFIX)
+
+$(LIBDEST)/%.$(OBJ_SUFFIX): $(SNMP_ROOT)/%.cxx
+ $(CCP) -c $(CXXOPTS) $< -Fo$(LIBDEST)/$*.$(OBJ_SUFFIX)
+
+$(LIBDEST)/%.$(OBJ_SUFFIX): $(SNMP_ROOT)/%.c
+ $(CC) -c $(CCOPTS) $< -Fo$(LIBDEST)/$*.$(OBJ_SUFFIX)
+
+clean: localclean
+
+localclean:
+ $(RM) $(SNMP_OBJS) $(LIBDEST)/$(SNMP_LIB) $(LIBDEST)/$(SNMP_IMPLIB) $(AGTMMAP).c $(AGTMMAP).h
+
+#############################################################################
+# Depend Area #
+#############################################################################
+
+# DO NOT DELETE THIS LINE -- make depend depends on it.
+
diff --git a/ldap/servers/snmp/ntagt/msrvdefs.mak b/ldap/servers/snmp/ntagt/msrvdefs.mak
new file mode 100644
index 00000000..ac877d9c
--- /dev/null
+++ b/ldap/servers/snmp/ntagt/msrvdefs.mak
@@ -0,0 +1,492 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#############################################################################
+# Mail Server Common Rulesets #
+#############################################################################
+
+MSRV_RELEASE = 4.0
+
+ifeq ($(DEBUG), optimize)
+MSRV_DEBUG = no
+else
+MSRV_DEBUG = yes
+endif
+
+ifeq ($(MSRV_DEBUG), yes)
+DEBUG_DEST = DBG-
+else
+DEBUG_DEST =
+endif
+
+# this allows mixing DBG objects with non DBG libs, avoiding
+# a complete autobuild or other linking hacks. Any DBG libs
+# (under mailserv2) will get picked up first, followed by non-DBG
+# libs. In any event, no DBG libs will be linked if MSRV_DEBUG=no.
+NDBGDEST = $(MSRV_ROOT)/built/$(ARCH)
+
+# This is where we are generally supposed to put built stuff
+BLDDEST = $(MSRV_ROOT)/built/$(DEBUG_DEST)$(ARCH)
+
+# module specific locations for build stuff
+LIBDEST = $(BLDDEST)/lib
+NETDEST = $(BLDDEST)/network
+LOCDEST = $(BLDDEST)/local
+EXTDEST = $(BLDDEST)/extras
+BINDEST = $(BLDDEST)/bin
+OBJDEST = $(BLDDEST)/obj
+
+IMPORTS_DIR = $(MSRV_ROOT)/code/import
+
+
+# Extensions for generated files.
+
+SHLIB_SUFFIX = so
+ARCHIVE_SUFFIX = a
+OBJ_SUFFIX = o
+EXE_SUFFIX =
+
+export SHLIB_EXT ARCHIVE_EXT OBJ_EXT EXE_EXT
+
+RM = rm -f
+AR = ar cr
+MD = mkdir -p
+MAKE = gmake
+STRIP = strip
+CP = cp
+ECHO = echo
+
+# For reasons you really don't want to know, we put all the C++ core
+# modules into a static lib on Unix platforms. If the system supports
+# shared libs, we use it only for C-derived object modules.
+
+ifneq ($(ARCH), WINNT)
+STAT_LIB = libNSmObj.$(ARCHIVE_SUFFIX)
+endif
+
+ifeq ($(ARCH), WINNT)
+
+ifeq ($(DEBUG), full)
+ML_DEBUG = /DEBUG
+ifeq ($(NTDEBUGENV),ON)
+MC_DEBUGENV= /D__NTDebugEnv__
+else
+MC_DEBUGENV=
+endif
+ifeq ($(NTDEBUGSLEEP),ON)
+MC_DEBUG=/D__NTDebug__ /D__NTDebugSleep__ $(MC_DEBUGENV)
+else
+MC_DEBUG = /D__NTDebug__ $(MC_DEBUGENV)
+endif
+else
+ML_DEBUG =
+MC_DEBUG =
+endif
+
+endif
+### Solaris #############################################################
+
+ifeq ($(ARCH), SOLARIS)
+ BUILD_SHARED = TRUE
+ BUILDAPI_SHARED = FALSE
+ PLUGIN_SHARED = TRUE
+ CC = gcc
+ CXX = g++
+
+ifeq ($(PURIFY), yes)
+ CC = /stuff/iasrc3/xtern/purify/purify gcc
+ CXX = /stuff/iasrc3/xtern/purify/purify g++
+endif
+
+ifeq ($(QUANTIFY), yes)
+ CC = /stuff/iasrc3/xtern/quantify/quantify gcc
+ CXX = /stuff/iasrc3/xtern/quantify/quantify g++
+endif
+
+ LD = ld
+ DLL_CFLAGS = -fpic
+ DLL_CXXFLAGS = -fpic
+ DLL_LDFLAGS = -G
+ OPTIMIZE_FLAGS = -O2
+ CFLAGS = $(DLL_CFLAGS) -DSVR4 -D__svr4__ -DSOLARIS \
+ -DHAVE_NIS -DHAS_GETSPNAM -DHAS_FGETPWENT \
+ -DXP_UNIX -DSTATOBJS \
+ -DMSRV_RELEASE=\"$(MSRV_RELEASE)\" \
+ -DOSVERSION=$(OSVERSION) -D_REENTRANT
+ LD_EXTRAS = -L/tools/ns/lib -lthread -lsocket -lnsl -lgen -ldl
+ MADM_LDLIBS = -ldl
+endif
+
+### IRIX notes ##########################################################
+## Suppress warnings about statement unreachable (3203) and
+## unused parameters (3262). Increase Olimit
+## Suppress REALLY ANNOYING link warnings unless a debug build
+## 84 is unsed libs. 85 is duplicate symbol preemption.
+## This hides duplicate symbols in the link - so watch it
+##########################################################################
+ifeq ($(ARCH), IRIX)
+ BUILD_SHARED = TRUE
+ BUILDAPI_SHARED = FALSE
+ PLUGIN_SHARED = TRUE
+ CC = cc
+ifneq ($(MSRV_DEBUG),yes)
+ CXX = CC -woff 3203,3262 -Wl,-woff,84 -Wl,-woff,85
+else
+ CXX = CC
+endif
+ LD = CC
+ DLL_CFLAGS =
+ DLL_CXXFLAGS =
+ DLL_LDFLAGS = -shared
+ OPTIMIZE_FLAGS = -O -Olimit 4096
+ CFLAGS = $(DLL_CFLAGS) -DIRIX -DSTATOBJS \
+ -DHAVE_NIS -DHAS_GETSPNAM -DHAS_FGETPWENT \
+ -DXP_UNIX \
+ -DMSRV_RELEASE=\"$(MSRV_RELEASE)\" \
+ -DOSVERSION=$(OSVERSION)
+
+ LD_EXTRAS =
+endif
+
+### HPUX notes ###########################################################
+## g++ does not support pic on a300 architecture
+## -Wl,+b,/usr/lib,+s is needed so that runtime can find shared lib
+## correctly
+## Also, gcc is used to compile and link modules with c-based main
+## to overcome a global constructor problem. Change in
+## admin/src/Makefile and code/network/IMAP4-Server/unix/Makefile
+## and code/tools/Makefile
+#########################################################################
+
+ifeq ($(ARCH), HPUX)
+ SHLIB_SUFFIX = sl
+ BUILD_SHARED = TRUE
+ BUILDAPI_SHARED = FALSE
+ PLUGIN_SHARED = TRUE
+ CC = cc
+ CXX = g++
+ LD = ld
+ NATIVE_CFLAGS = -Aa -D_HPUX_SOURCE
+ DLL_CFLAGS = +z
+ DLL_CXXFLAGS =
+ DLL_LDFLAGS = -b
+ OPTIMIZE_FLAGS = -O
+ CFLAGS = -DHPUX -DSTATOBJS -DHAVE_NIS \
+ -DXP_UNIX -DHAS_FGETPWENT \
+ -DMSRV_RELEASE=\"$(MSRV_RELEASE)\" \
+ -DOSVERSION=$(OSVERSION)
+ LD_EXTRAS = -Wl,+b,/usr/lib,+s \
+ -L/tools/ns/lib -liostream -ldld -lm
+ #-L/tools/ns/lib -liostream -ldld -lm -lpthread
+ MSRV_INCLUDES = -I/tools/ns/lib/g++-include
+endif
+
+
+### OSF1 notes ############################################################
+## -taso options and -DIS_64 are needed to get 32 bit behavior on the alpha
+## ...otherwise libdbm will not work
+###########################################################################
+
+ifeq ($(ARCH), OSF1)
+ BUILD_SHARED = TRUE
+ BUILDAPI_SHARED = FALSE
+ PLUGIN_SHARED = TRUE
+ CC = cc -taso -DIS_64 -Olimit 4000
+ CXX = g++
+ LD = ld
+ DLL_CFLAGS =
+ DLL_CXXFLAGS =
+ DLL_LDFLAGS =
+ OPTIMIZE_FLAGS = -O
+ CFLAGS = -DOSF1 -DSTATOBJS -DHAVE_NIS -DXP_UNIX \
+ -DHAS_FGETPWENT \
+ -DMSRV_RELEASE=\"$(MSRV_RELEASE)\" \
+ -DOSVERSION=$(OSVERSION)
+ LD_EXTRAS = -lc_r -L/tools/ns/lib -liostream -Wl,-taso
+ MSRV_INCLUDES = -I/tools/ns/lib/g++-include
+endif
+
+### AIX notes #############################################################
+## Yah, right. In your dreams...
+## What a horrid c++ platform. We need to supply our own g++ config file
+## because the systems supplied one is broken. Lots of surprises in store.
+## Needs a separate build tree on 3.2.5 because automount is broken.
+## Also, like HP - gcc is used to compile and link modules with c-based main
+## to overcome a global constructor problem. Change in
+## admin/src/Makefile and code/network/IMAP4-Server/unix/Makefile
+## and code/tools/Makefile
+##
+## DLL_CFLAGS type of stuff is set specifically in plugins/Makefile
+## and also local/SMTP-Router/Makefile to use a specific export list
+## (for the NSmatch plugin in this case). Also see further below for the
+## linker override option to use the import list instead of a named lib
+##########################################################################
+
+## AIX 4
+ifeq ($(ARCH), AIX)
+ BUILD_SHARED = FALSE
+ BUILDAPI_SHARED = FALSE
+ PLUGIN_SHARED = TRUE
+ SHLIB_SUFFIX = _shr.a
+ CC = cc
+ CXX = g++
+# CXX = g++ -I$(MSRV_ROOT)/code/include/aix
+ LD = ld
+ DLL_CLAGS =
+ DLL_CXXFLAGS =
+ OPTIMIZE_FLAGS = -O
+ CFLAGS = -DAIX -DAIXV3 -DAIXV4 -DSTATOBJS \
+ -DHAVE_NIS -DXP_UNIX -mcpu=common\
+ -DMSRV_RELEASE=\"$(MSRV_RELEASE)\" \
+ -DOSVERSION=$(OSVERSION)
+ LD_EXTRAS = -L/gnu/install/lib -L/gnu/install/lib/gcc-lib/powerpc-ibm-aix4.1.4.0/2.7.2.1/common -lstdc++ -ls -lsvld -lgcc -lc_r
+# LD_EXTRAS = -L/usr/gnu/lib -liostream -ls -ldl
+ MSRV_INCLUDES = -I/gnu/install/lib/g++-include
+# MSRV_INCLUDES = -I/usr/gnu/lib/g++-include
+endif
+
+## AIX 3
+#ifeq ($(ARCH), AIX)
+# BUILD_SHARED = FALSE
+# BUILDAPI_SHARED = FALSE
+# PLUGIN_SHARED = TRUE
+# CC = svcc
+# CXX = g++ -I$(MSRV_ROOT)/code/include/aix
+# LD = ld
+# DLL_CLAGS =
+# DLL_CXXFLAGS =
+# OPTIMIZE_FLAGS = -O
+# CFLAGS = -DAIX -DAIXV3 -DSTATOBJS \
+# -DHAVE_NIS -DXP_UNIX \
+# -DMSRV_RELEASE=\"$(MSRV_RELEASE)\"
+# LD_EXTRAS = -L/tools/ns/lib -liostream -ls
+# MSRV_INCLUDES = -I/tools/ns/lib/g++-include
+#endif
+
+
+ifeq ($(ARCH), WINNT)
+
+ SHLIB_SUFFIX = dll
+ ARCHIVE_SUFFIX = lib
+ RM = del /q
+ EXE_SUFFIX = .exe
+ OBJ_SUFFIX = obj
+
+ SHARED_LIB = NetscapeMTA30.$(SHLIB_SUFFIX)
+ SHARED_IMPLIB = NetscapeMTA30.$(ARCHIVE_SUFFIX)
+ SHARED_BASE_LIB = NetscapeMTAX30.$(SHLIB_SUFFIX)
+ SHARED_BASE_IMPLIB = NetscapeMTAX30.$(ARCHIVE_SUFFIX)
+ MATCH_LIB = NSMatch30.$(SHLIB_SUFFIX)
+ MATCH_IMPLIB = NSMatch30.$(ARCHIVE_SUFFIX)
+ POSEC_LIB = nsSupport30.$(SHLIB_SUFFIX)
+ POSEC_IMPLIB = nsSupport30.$(ARCHIVE_SUFFIX)
+ MDBAPI_LIB = NetscapeMDB30.$(SHLIB_SUFFIX)
+ MDBAPI_IMPLIB = NetscapeMDB30.$(ARCHIVE_SUFFIX)
+ BUILD_SHARED = TRUE
+ BUILDAPI_SHARED = TRUE
+ PLUGIN_SHARED = TRUE
+ POSEC_SHARED = FALSE
+ CFLAGS = /D__NT__ $(MC_DEBUG) \
+ /DMSRV_RELEASE=\"$(MSRV_RELEASE)\" \
+ /D$(NS_PRODUCT) $(XP_FLAG) \
+ /D__USE_THREAD_HEAPS__ -Gy
+ OPTIMIZE_FLAGS = -Ob1 -O2
+ DLL_CFLAGS = /D__Lib__
+ DLL_CXXFLAGS = /D__Lib__
+ LD_EXTRAS = /INCREMENTAL:NO $(ML_DEBUG)
+ LINK_CONSOLE = link /NOLOGO /SUBSYSTEM:CONSOLE $(ML_DEBUG) \
+ /OUT:$@ /OPT:REF /MAP
+endif
+
+
+.SUFFIXES: .cxx
+
+# In Debug mode, always build archive libraries
+
+ifeq ($(MSRV_DEBUG), yes)
+
+ifneq ($(ARCH), WINNT)
+MSRV_DBG_DEFINES = -g -DMSRV_DEBUG $(DBG_FLAGS)
+BUILD_SHARED = FALSE
+PLUGIN_SHARED = FALSE
+else
+MSRV_DBG_DEFINES = /Od /Zi $(DBG_FLAGS)
+endif
+
+else
+MSRV_DBG_DEFINES = $(OPTIMIZE_FLAGS)
+endif
+
+
+ifneq ($(ARCH), WINNT)
+
+ifeq ($(BUILD_SHARED), TRUE)
+ SHARED_LIB = libNSmail.$(SHLIB_SUFFIX)
+else
+ SHARED_LIB = libNSmail.$(ARCHIVE_SUFFIX)
+endif
+
+ifeq ($(BUILDAPI_SHARED), TRUE)
+ MDBAPI_LIB = libNSmdb.$(SHLIB_SUFFIX)
+else
+ MDBAPI_LIB = libNSmdb.$(ARCHIVE_SUFFIX)
+endif
+
+
+ifeq ($(PLUGIN_SHARED), TRUE)
+ifeq ($(ARCH), AIX)
+ MATCH_LIB = libNSmatch$(SHLIB_SUFFIX)
+ HDR_LIB = libNShdr$(SHLIB_SUFFIX)
+else
+ MATCH_LIB = libNSmatch.$(SHLIB_SUFFIX)
+ HDR_LIB = libNShdr.$(SHLIB_SUFFIX)
+endif
+else
+ MATCH_LIB = libNSmatch.$(ARCHIVE_SUFFIX)
+ HDR_LIB = libNShdr.$(ARCHIVE_SUFFIX)
+endif
+
+
+ifeq ($(ARCH), HPUX)
+ifeq ($(MSRV_HPUX_CURSES_STATIC), TRUE)
+CURSES=/usr/lib/libHcurses.a
+else
+CURSES=/usr/lib/libcurses.sl
+endif
+else
+CURSES=-lcurses -ltermcap
+endif
+
+ifeq ($(ARCH), AIX)
+CURSES=-lcurses
+endif
+
+# Before merge stuff - nirmal 4/24
+#LD_LINKLIB = -L$(LIBDEST) -L/usr/lib -L$(NDBGDEST)/lib \
+# -lNSmdb -lNSmail -lNSmObj \
+# -lNSmail -lNSmdb -L$(NSCP_DISTDIR)/lib \
+# -llcache10 -lldap10 $(CURSES)
+#
+
+ifeq ($(ARCH), HPUX)
+LD_LINKLIB = -L$(LIBDEST) -L/usr/lib -L$(NDBGDEST)/lib \
+ -lNSmdb -lNSmail -lNSmObj -lNSmail -lNSmdb \
+ -L$(NSCP_DISTDIR)/lib -llcache10 \
+ -lldap10 \
+ $(CURSES)
+else
+LD_LINKLIB = -L$(LIBDEST) -L/usr/lib -L$(NDBGDEST)/lib \
+ -lNSmdb -lNSmail -lNSmObj -lNSmail -lNSmdb \
+ $(NSCP_DISTDIR)/lib/liblcache10.$(SHLIB_SUFFIX) \
+ $(NSCP_DISTDIR)/lib/libldap10.$(SHLIB_SUFFIX) \
+ $(CURSES)
+endif
+
+ifeq ($(ARCH), AIX)
+CURSES=-lcurses
+LD_LINKLIB = -L$(LIBDEST) -L/usr/lib -L$(NDBGDEST)/lib \
+ -lNSmdb -lNSmail -lNSmObj \
+ $(NSCP_DISTDIR)/lib/liblcache10$(SHLIB_SUFFIX) \
+ $(NSCP_DISTDIR)/lib/libldap10$(SHLIB_SUFFIX) \
+ $(NSCP_DISTDIR)/lib/libssldap10.a \
+ $(CURSES)
+
+endif
+
+
+LD_MATCHLIB = -lNSmatch
+else # ARCH = WINNT section
+LD_POSECLIB = $(addprefix $(LIBDEST)/, $(POSEC_IMPLIB))
+LD_LINKLIB = $(addprefix $(LIBDEST)/, $(SHARED_IMPLIB))
+LD_MATCHLIB = $(addprefix $(LIBDEST)/, $(MATCH_IMPLIB))
+endif
+
+ifeq ($(ARCH), WINNT)
+LD_LINKLIB += $(NSCP_DISTDIR)/lib/nsldap32v10.lib $(NSCP_DISTDIR)/lib/nslch32v10.lib
+LDX_LINKLIB = $(LD_LINKLIB) $(LIBDEST)/$(SHARED_BASE_IMPLIB)
+
+I18NLIBS=$(addsuffix .$(LIB_SUFFIX),\
+ $(addprefix $(OBJDIR)/lib/lib, \
+ ldapu $(LIBADMIN) $(FRAME) $(CRYPT) $(LIBACCESS))) \
+ $(LIBDBM) $(LIBXP) $(LIBNSPR) $(LIBARES) $(LIBSEC)
+else
+
+# The way I18LIBS was defined in server3_mail_branch, is quite misleading.
+# (see modules.mk for details). After this, LD_LINKLIB gets redefined
+# and that adds unwanted lines to the link of bunch of things. Please
+# add I18LIBS to the individual makefiles, where necessary. See
+# mailserv2/admin/src/Makefile -> DEPLIBS for an example.
+# I am changing this definition for the merge. Retain these changes in
+# future merges. I haved added posix4 to keep what was before merge.
+# - Nirmal 4/24/97.
+#I18NLIBS=$(addsuffix .$(LIB_SUFFIX),\
+# $(addprefix $(OBJDIR)/lib/lib, \
+# ldapu $(LIBADMIN) $(FRAME) $(CRYPT) $(LIBACCESS))) \
+# $(LIBDBM) $(LIBXP) $(LIBNSPR) $(LIBARES) \
+# -L$(MCOM_ROOT)/components/ldapsdk/$(NSOBJDIR_NAME)/lib \
+# -lssldap10 $(LIBSEC)
+I18NLIBS=$(addsuffix .$(LIB_SUFFIX),\
+ $(addprefix $(OBJDIR)/lib/lib, \
+ ldapu $(LIBADMIN) $(FRAME) $(CRYPT) $(LIBACCESS))) \
+ $(LIBDBM) $(LIBXP) $(LIBNSPR) $(LIBARES) \
+ -L$(NSCP_DISTDIR)/lib \
+ -lssldap10 $(LIBSEC)
+
+endif
+
+ifeq ($(ARCH), SOLARIS) # IRIX and HPUX have no posix4 lib
+ I18NLIBS += -lposix4
+endif
+
+LD_LINKLIB += $(I18NLIBS)
+
+ifeq ($(ARCH), IRIX)
+LD_LINKLIB += $(NSCP_DISTDIR)/lib/libldap10.so
+endif
+
+##########################################################################
+## AIX override to make dynamic linking work correctly
+## instead of linking directly with the shared object, we use an
+## import list. Note this syntax only works with g++ or gcc as the compiler
+##########################################################################
+
+ifeq ($(ARCH), AIX)
+LD_MATCHLIB = -Wl,-bI:$(MSRV_ROOT)/code/plugins/NSMatch.exp
+endif
+
+
+
+DB_DEFINES = -DMEMMOVE -D__DBINTERFACE_PRIVATE -DPOSIX_MISTAKE
+
+INCLUDES = -I$(MSRV_ROOT)/code/include \
+ -I$(MCOM_ROOT)/lib/libdbm \
+ -I$(MSRV_ROOT)/contrib/regex \
+ $(MSRV_INCLUDES)
+
+CCOPTS = $(MSRV_DBG_DEFINES) $(CFLAGS) $(INCLUDES) \
+ $(MCC_INCLUDE) $(NSPR_DEFINES)
+CXXOPTS = $(MSRV_DBG_DEFINES) $(CFLAGS) $(INCLUDES) \
+ $(MCC_INCLUDE) $(NSPR_DEFINES)
+
+
+MSRVDESTS = $(BLDDEST) $(LIBDEST) $(NETDEST) $(LOCDEST) $(EXTDEST) \
+ $(BINDEST) $(OBJDEST)
+
+$(MSRVDESTS):
+ $(MD) $@
+
+default: all
+
+all: $(MSRVDESTS)
+
+depend: localdepend
+
+clean: localclean
+
+spotless: clean
+ $(RM) -r $(BLDDEST)
+
diff --git a/ldap/servers/snmp/ntagt/nslagtcom_nt.h b/ldap/servers/snmp/ntagt/nslagtcom_nt.h
new file mode 100644
index 00000000..0a9f7eb5
--- /dev/null
+++ b/ldap/servers/snmp/ntagt/nslagtcom_nt.h
@@ -0,0 +1,32 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*-------------------------------------------------------------------------
+ *
+ * nslagtcom_nt.h - Common definitions for NS Directory Server's SNMP
+ * subagent on NT.
+ * The definitions in here should be kept so that modules
+ * other than the subagent can share this file.
+ *
+ * Revision History:
+ * 07/27/1997 Steve Ross Created
+ *
+ *
+ *
+ *-----------------------------------------------------------------------*/
+
+#ifndef __NSLAGTCOM_NT_H_
+#define __NSLMAGTCOM_NT_H_
+
+/*-------------------------------------------------------------------------
+ *
+ * Defines
+ *
+ *-----------------------------------------------------------------------*/
+
+#define MAGT_NSEV_SNMPTRAP "NSEV_SNMPTRAP_LDAP"
+
+#endif /* __NSLAGTCOM_NT_H_ */
diff --git a/ldap/servers/snmp/ntagt/nsldapagt_nt.c b/ldap/servers/snmp/ntagt/nsldapagt_nt.c
new file mode 100644
index 00000000..268ee27e
--- /dev/null
+++ b/ldap/servers/snmp/ntagt/nsldapagt_nt.c
@@ -0,0 +1,1738 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*-------------------------------------------------------------------------
+ *
+ * nsldapagt_nt.c - SNMP Extension Agent for Directory Server on NT.
+ * Provides SNMP data to NT SNMP Service on behalf of the
+ * Directory Server installed on the current system. SNMP
+ * data is collected from the following sources:
+ * 1. config file (static data)
+ * 2. daemonstats file (dynamic data)
+ *
+ * Revision History:
+ * 07/25/1997 Steve Ross Created
+ *
+ *
+ *-----------------------------------------------------------------------*/
+
+
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <io.h>
+#include <windows.h>
+#include <winsock.h>
+#include <time.h>
+#include <snmp.h>
+#include "nt/regparms.h"
+#include "agtmmap.h"
+#include "nslagtcom_nt.h"
+#include "nsldapmib_nt.h"
+#include "nsldapagt_nt.h"
+#include "ldap.h"
+
+/*-------------------------------------------------------------------------
+ *
+ * Defines
+ *
+ *-----------------------------------------------------------------------*/
+
+#define REPLACE(x, y) do {if ((x)) SNMP_free((x));\
+ (x) = SNMP_malloc(strlen((y)) + 1);\
+ if ((x)) strcpy((x), (y));} while(0)
+
+#define export extern "C"
+
+/*-------------------------------------------------------------------------
+ *
+ * Globals
+ *
+ *-----------------------------------------------------------------------*/
+
+instance_list_t *pInstanceList = NULL;
+
+/*
+ * Extension Agent DLLs need access to elapsed time agent has been active.
+ * This is implemented by initializing the Extension Agent with a time zero
+ * reference, and allowing the agent to compute elapsed time by subtracting
+ * the time zero reference from the current system time. This Extension
+ * Agent implements this reference with dwTimeZero.
+ */
+DWORD dwTimeZero = 0;
+
+/*-------------------------------------------------------------------------
+ *
+ * Externs
+ *
+ *-----------------------------------------------------------------------*/
+
+extern AsnObjectIdentifier MIB_OidPrefix;
+extern UINT MIB_num_vars;
+
+/*------------------------ prototypes -----------------------------------*/
+// char *getRootDirFromConfFile(char *filename, char *szLogPath);
+char *getRootDirFromConfFile(char *filename);
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtInitInstance: initializes entry in instance list
+ *
+ *
+ *
+ *
+ *
+ *-----------------------------------------------------------------------*/
+
+ int MagtInitInstance(instance_list_t *pInstance)
+ {
+
+
+ pInstance->ghTrapEvent = NULL;
+ pInstance->pOpsStatInfo = NULL;
+ pInstance->pEntriesStatInfo = NULL;
+ pInstance->ppIntStatInfo = NULL;
+ pInstance->pMibInfo = NULL;
+ pInstance->oldUpdateTime = 0;
+ pInstance->oldStartTime = 0;
+ pInstance->graceCycles = MAGT_TIME_QUANTUM;
+ pInstance->mmapStale = MAGT_FALSE;
+ pInstance->mmapOk = MAGT_FALSE;
+ pInstance->serverUp = MAGT_FALSE;
+ pInstance->downTrapSent = MAGT_FALSE;
+ pInstance->trapType = MAGT_TRAP_NONE;
+
+ return 0;
+ }
+
+ int MagtInitStats(MagtOpsTblInfo_t *OpsTblInfo,
+ MagtEntriesTblInfo_t *EntriesTblInfo,
+ MagtIntTblInfo_t **IntTblInfo )
+ {
+ int i;
+
+ if (OpsTblInfo != NULL)
+ {
+ OpsTblInfo->AnonymousBinds = 0;
+ OpsTblInfo->UnAuthBinds = 0;
+ OpsTblInfo->SimpleAuthBinds = 0;
+ OpsTblInfo->StrongAuthBinds = 0;
+ OpsTblInfo->BindSecurityErrors = 0;
+ OpsTblInfo->InOps = 0;
+ OpsTblInfo->ReadOps = 0;
+ OpsTblInfo->CompareOps = 0;
+ OpsTblInfo->AddEntryOps = 0;
+ OpsTblInfo->RemoveEntryOps = 0;
+ OpsTblInfo->ModifyEntryOps = 0;
+ OpsTblInfo->ModifyRDNOps = 0;
+ OpsTblInfo->ListOps = 0;
+ OpsTblInfo->SearchOps = 0;
+ OpsTblInfo->OneLevelSearchOps = 0;
+ OpsTblInfo->WholeSubtreeSearchOps = 0;
+ OpsTblInfo->Referrals = 0;
+ OpsTblInfo->Chainings = 0;
+ OpsTblInfo->SecurityErrors = 0;
+ OpsTblInfo->Errors = 0;
+ }
+
+ if(EntriesTblInfo != NULL)
+ {
+ EntriesTblInfo->MasterEntries = 0;
+ EntriesTblInfo->CopyEntries = 0;
+ EntriesTblInfo->CacheEntries = 0;
+ EntriesTblInfo->CacheHits = 0;
+ EntriesTblInfo->SlaveHits = 0;
+ }
+
+ if(IntTblInfo != NULL)
+ {
+ for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++)
+ {
+ strcpy(IntTblInfo[i]->DsName.val, "Not Available");
+ IntTblInfo[i]->DsName.len = strlen("Not Available");
+
+ IntTblInfo[i]->TimeOfCreation = 0;
+ IntTblInfo[i]->TimeOfLastAttempt = 0;
+ IntTblInfo[i]->TimeOfLastSuccess = 0;
+ IntTblInfo[i]->FailuresSinceLastSuccess = 0;
+ IntTblInfo[i]->Failures = 0;
+ IntTblInfo[i]->Successes = 0;
+
+ strcpy(IntTblInfo[i]->URL.val, "Not Available");
+ IntTblInfo[i]->URL.len = strlen("Not Available");
+ }
+ }
+
+ return 0;
+ }
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtCheckServer: Checks the Server's status and indicates
+ * which trap is to be generated if necessary.
+ *
+ * Returns: MAGT_TRAP_NONE - No trap to be generated
+ * Trap # - Id of trap to be generated
+ *
+ *-----------------------------------------------------------------------*/
+
+int MagtCheckServer(instance_list_t *pInstance)
+{
+ int err;
+
+ if (pInstance->mmapStale == MAGT_TRUE)
+ pInstance->mmapOk = MAGT_FALSE; /* Ensure open of mmap */
+
+ err = MagtReadStats(&(pInstance->hdrInfo),
+ NULL,
+ NULL,
+ NULL,
+ pInstance->szStatsPath,
+ pInstance->szLogPath); /* Find times info in hdr */
+
+ if (pInstance->mmapOk == MAGT_FALSE)
+ {
+ if (err != 0) /* Cannot open mmap file */
+ {
+ if ((pInstance->serverUp == MAGT_TRUE) || /* Server status changes */
+ (pInstance->downTrapSent == MAGT_FALSE)) /* Down trap was not sent */
+ {
+ pInstance->serverUp = MAGT_FALSE;
+ pInstance->downTrapSent = MAGT_TRUE;
+ pInstance->trapType = MAGT_TRAP_SERVER_DOWN;
+ }
+ }
+ else
+ {
+ pInstance->mmapOk = MAGT_TRUE;
+
+ /*
+ * Since mmapOk was false, it means the mmap file couldn't be
+ * opened before. Now it is opened ok, so it will be assumed
+ * that the server has gone down and up and a start trap may need
+ * to be sent.
+ */
+ if (pInstance->mmapStale == MAGT_FALSE)
+ pInstance->serverUp = MAGT_FALSE;
+ else
+ pInstance->mmapStale = MAGT_FALSE; /* Not stale anymore */
+ }
+ }
+
+ if (pInstance->trapType == MAGT_TRAP_NONE)
+ {
+ if (err != 0)
+ {
+ pInstance->mmapOk = MAGT_FALSE;
+
+ /*
+ * If the mmap file does not exist, assume server has gone down.
+ */
+ if (err == ENOENT)
+ {
+ if((pInstance->serverUp == MAGT_TRUE) || /* Server status changes */
+ (pInstance->downTrapSent == MAGT_FALSE)) /* Down trap was not sent */
+ {
+ pInstance->serverUp = MAGT_FALSE;
+ pInstance->downTrapSent = MAGT_TRUE;
+ pInstance->trapType = MAGT_TRAP_SERVER_DOWN;
+ }
+ }
+ }
+ else /* Got hdr info ok */
+ {
+
+ /*
+ * The fact that header info can be read will be taken as the
+ * server is up. If it was not up before, a server start trap
+ * will need to be sent.
+ */
+ if (((pInstance->hdrInfo.restarted) || (pInstance->hdrInfo.startTime > pInstance->oldStartTime))
+ && (pInstance->hdrInfo.updateTime > pInstance->oldUpdateTime))
+ {
+ pInstance->oldUpdateTime = pInstance->hdrInfo.updateTime;
+ pInstance->oldStartTime = pInstance->hdrInfo.startTime;
+ pInstance->graceCycles = MAGT_TIME_QUANTUM;
+ pInstance->serverUp = MAGT_TRUE;
+ pInstance->downTrapSent = MAGT_FALSE;
+ pInstance->trapType = MAGT_TRAP_SERVER_START;
+ }
+ else
+ {
+ if (pInstance->hdrInfo.updateTime > pInstance->oldUpdateTime)
+ {
+ pInstance->oldUpdateTime = pInstance->hdrInfo.updateTime;
+ if (pInstance->graceCycles == 0)
+ {
+
+ /*
+ * The server has probably been stuck and has been restarted.
+ */
+ pInstance->serverUp = MAGT_TRUE;
+ pInstance->downTrapSent = MAGT_FALSE;
+ pInstance->trapType = MAGT_TRAP_SERVER_START;
+ }
+
+ /*
+ * Reset grace cycles in either case because server is healthy.
+ */
+ pInstance->graceCycles = MAGT_TIME_QUANTUM;
+ }
+ else /* Mmap file not updated */
+ {
+ pInstance->mmapStale = MAGT_TRUE;
+
+ /*
+ * The server is not responding, send trap if one has not
+ * been sent yet.
+ */
+ if (pInstance->graceCycles > 0)
+ {
+ pInstance->graceCycles--;
+ if (pInstance->graceCycles == 0)
+ {
+ pInstance->trapType = MAGT_TRAP_SERVER_DOWN;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return pInstance->trapType;
+}
+
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtCleanUp: Cleans up any allocated global resources.
+ *
+ * Returns: None
+ *
+ *-----------------------------------------------------------------------*/
+
+void MagtCleanUp()
+{
+ instance_list_t *pInstance;
+
+ for (pInstance = pInstanceList; pInstance; pInstance = pInstance->pNext)
+ {
+ if (pInstance->pCfgInfo != NULL)
+ GlobalFree(pInstance->pCfgInfo);
+
+ if (pInstance->pMibInfo != NULL)
+ GlobalFree(pInstance->pMibInfo);
+
+ if (pInstance->szRootDir != NULL)
+ GlobalFree(pInstance->szRootDir);
+
+ if (pInstance->ghTrapEvent != NULL)
+ CloseHandle(pInstance->ghTrapEvent);
+ }
+
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtConfProcess: Processes a configuration entry and updates the
+ * corresponding static info field.
+ *
+ * Returns: None
+ *
+ *-----------------------------------------------------------------------*/
+
+void MagtConfProcess(char *line, int lineLen,
+ MagtLDAPInfo_t *info)
+
+{
+ char keyWord[MAGT_MAX_LINELEN + 1];
+ char *val, *p;
+
+ if (line == NULL) /* Shouldn't happen */
+ return;
+
+ if ((*line) == '#') /* Comment - Ignore */
+ return;
+
+ keyWord[0] = '\0';
+
+ if (sscanf(line, "%s", keyWord) != 1) /* Partial entry */
+ return;
+
+ val = line;
+
+ /*
+ * Go past any spaces preceding the keyword.
+ */
+ while ((*val) && (isspace(*val)))
+ ++val;
+
+ if (!(*val))
+ return;
+
+ /*
+ * Go past the keyword.
+ */
+ for (; (*val) && !(isspace(*val)); ++val);
+
+ if (!(*val))
+ return;
+
+ /*
+ * Go past the spaces that follow the key word.
+ */
+ while ((*val) && (isspace(*val)))
+ ++val;
+
+ if (!(*val))
+ return;
+
+ /*
+ * Strip CRLF characters.
+ */
+ if ((p = strchr(val, '\r')) != NULL)
+ *p = '\0';
+ if ((p = strchr(val, '\n')) != NULL)
+ *p = '\0';
+
+ /*
+ * Now val points to the value and keyWord points to the key word.
+ */
+
+ if (!stricmp(keyWord, "nsslapd-port:"))
+ {
+ info->port = atoi(val);
+ return;
+ }
+
+ if (!stricmp(keyWord, "nsslapd-localhost:"))
+ {
+ REPLACE(info->host, val);
+ info->host[strlen(info->host)] = '\0';
+ return;
+ }
+
+ if (!stricmp(keyWord, "nsslapd-rootdn:"))
+ {
+ REPLACE(info->rootdn, val);
+ info->rootdn[strlen(info->rootdn)] = '\0';
+ return;
+ }
+
+ if (!stricmp(keyWord, "nsslapd-rootpw:"))
+ {
+ REPLACE(info->rootpw, val);
+ info->rootpw[strlen(info->rootpw)] = '\0';
+ return;
+ }
+
+ /*
+ * None of the above? Invalid keyword. Just return.
+ */
+ return;
+}
+
+
+char *getRootDirFromConfFile(char *confpath)
+{
+ char *rootDir = NULL;
+ const char *config = "\\config\0" ;
+ char instanceDir[MAGT_MAX_LINELEN + 1] = "";
+ size_t len ;
+
+ if (confpath) {
+ len = strlen(confpath) - strlen(config) ;
+ strncpy(instanceDir, confpath, len);
+ rootDir = _strdup(instanceDir) ; // allocate memory for rootDir and set up to value pointed by instanceDir
+ return rootDir ;
+ }
+ else return NULL ;
+}
+
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtInitMibStorage: Initializes the storage pointers of MIB variables.
+ *
+ * Returns: None
+ *
+ *-----------------------------------------------------------------------*/
+
+void MagtInitMibStorage(MagtMibEntry_t * MibInfo,
+ MagtOpsTblInfo_t * pOpsStatInfo,
+ MagtEntriesTblInfo_t * pEntriesStatInfo,
+ MagtIntTblInfo_t ** ppIntStatInfo,
+ MagtStaticInfo_t * pCfgInfo)
+{
+ switch(MibInfo->uId)
+ {
+ case MAGT_ID_DESC:
+ MibInfo->Storage = pCfgInfo->entityDescr.val;
+ break;
+ case MAGT_ID_VERS:
+ MibInfo->Storage = pCfgInfo->entityVers.val;
+ break;
+ case MAGT_ID_ORG:
+ MibInfo->Storage = pCfgInfo->entityOrg.val;
+ break;
+ case MAGT_ID_LOC:
+ MibInfo->Storage = pCfgInfo->entityLocation.val;
+ break;
+ case MAGT_ID_CONTACT:
+ MibInfo->Storage = pCfgInfo->entityContact.val;
+ break;
+ case MAGT_ID_NAME:
+ MibInfo->Storage = pCfgInfo->entityName.val;
+ break;
+ case MAGT_ID_APPLINDEX:
+ MibInfo->Storage = &pCfgInfo->ApplIndex;
+ break;
+
+ /* operations table attrs */
+ case MAGT_ID_ANONYMOUS_BINDS:
+ MibInfo->Storage = &pOpsStatInfo->AnonymousBinds;
+ break;
+ case MAGT_ID_UNAUTH_BINDS:
+ MibInfo->Storage = &pOpsStatInfo->UnAuthBinds;
+ break;
+ case MAGT_ID_SIMPLE_AUTH_BINDS:
+ MibInfo->Storage = &pOpsStatInfo->SimpleAuthBinds;
+ break;
+ case MAGT_ID_STRONG_AUTH_BINDS:
+ MibInfo->Storage = &pOpsStatInfo->StrongAuthBinds;
+ break;
+ case MAGT_ID_BIND_SECURITY_ERRORS:
+ MibInfo->Storage = &pOpsStatInfo->BindSecurityErrors;
+ break;
+ case MAGT_ID_IN_OPS:
+ MibInfo->Storage = &pOpsStatInfo->InOps;
+ break;
+ case MAGT_ID_READ_OPS:
+ MibInfo->Storage = &pOpsStatInfo->ReadOps;
+ break;
+ case MAGT_ID_COMPARE_OPS:
+ MibInfo->Storage = &pOpsStatInfo->CompareOps;
+ break;
+ case MAGT_ID_ADD_ENTRY_OPS:
+ MibInfo->Storage = &pOpsStatInfo->AddEntryOps;
+ break;
+ case MAGT_ID_REMOVE_ENTRY_OPS:
+ MibInfo->Storage = &pOpsStatInfo->RemoveEntryOps;
+ break;
+ case MAGT_ID_MODIFY_ENTRY_OPS:
+ MibInfo->Storage = &pOpsStatInfo->ModifyEntryOps;
+ break;
+ case MAGT_ID_MODIFY_RDN_OPS:
+ MibInfo->Storage = &pOpsStatInfo->ModifyRDNOps;
+ break;
+ case MAGT_ID_LIST_OPS:
+ MibInfo->Storage = &pOpsStatInfo->ListOps;
+ break;
+ case MAGT_ID_SEARCH_OPS:
+ MibInfo->Storage = &pOpsStatInfo->SearchOps;
+ break;
+ case MAGT_ID_ONE_LEVEL_SEARCH_OPS:
+ MibInfo->Storage = &pOpsStatInfo->OneLevelSearchOps;
+ break;
+ case MAGT_ID_WHOLE_SUBTREE_SEARCH_OPS:
+ MibInfo->Storage = &pOpsStatInfo->WholeSubtreeSearchOps;
+ break;
+ case MAGT_ID_REFERRALS:
+ MibInfo->Storage = &pOpsStatInfo->Referrals;
+ break;
+ case MAGT_ID_CHAININGS:
+ MibInfo->Storage = &pOpsStatInfo->Chainings;
+ break;
+ case MAGT_ID_SECURITY_ERRORS:
+ MibInfo->Storage = &pOpsStatInfo->SecurityErrors;
+ break;
+ case MAGT_ID_ERRORS:
+ MibInfo->Storage = &pOpsStatInfo->Errors;
+ break;
+ /* entries table attrs */
+ case MAGT_ID_MASTER_ENTRIES:
+ MibInfo->Storage = &pEntriesStatInfo->MasterEntries;
+ break;
+ case MAGT_ID_COPY_ENTRIES:
+ MibInfo->Storage = &pEntriesStatInfo->CopyEntries;
+ break;
+ case MAGT_ID_CACHE_ENTRIES:
+ MibInfo->Storage = &pEntriesStatInfo->CacheEntries;
+ break;
+ case MAGT_ID_CACHE_HITS:
+ MibInfo->Storage = &pEntriesStatInfo->CacheHits;
+ break;
+ case MAGT_ID_SLAVE_HITS:
+ MibInfo->Storage = &pEntriesStatInfo->SlaveHits;
+ break;
+ /* interaction table entries
+ *---------------------------------
+ * a little different because table of N entries, we can get current value of n
+ * from MibInfo->Oid.ids[MibInfo->Oid.idLength] because dsIntIndex is last,
+ * subtract 1 from it because oids go from 1 to NUM_SNMP_INT_TBL_ROWS array goes
+ * from 0 to NUM_SNMP_INT_TBL_ROWS - 1
+ * if this ever changes this logic will have to change to get it from
+ * appropriate spot
+ */
+ case MAGT_ID_DS_NAME:
+ MibInfo->Storage = ppIntStatInfo[MibInfo->Oid.ids[MibInfo->Oid.idLength - 1] - 1]->DsName.val;
+ break;
+ case MAGT_ID_TIME_OF_CREATION:
+ MibInfo->Storage = &(ppIntStatInfo[MibInfo->Oid.ids[MibInfo->Oid.idLength - 1] - 1]->TimeOfCreation);
+ break;
+ case MAGT_ID_TIME_OF_LAST_ATTEMPT:
+ MibInfo->Storage = &(ppIntStatInfo[MibInfo->Oid.ids[MibInfo->Oid.idLength - 1] - 1]->TimeOfLastAttempt);
+ break;
+ case MAGT_ID_TIME_OF_LAST_SUCCESS:
+ MibInfo->Storage = &(ppIntStatInfo[MibInfo->Oid.ids[MibInfo->Oid.idLength - 1] - 1]->TimeOfLastSuccess);
+ break;
+ case MAGT_ID_FAILURES_SINCE_LAST_SUCCESS:
+ MibInfo->Storage = &(ppIntStatInfo[MibInfo->Oid.ids[MibInfo->Oid.idLength - 1] - 1]->FailuresSinceLastSuccess);
+ break;
+ case MAGT_ID_FAILURES:
+ MibInfo->Storage = &(ppIntStatInfo[MibInfo->Oid.ids[MibInfo->Oid.idLength - 1] - 1]->Failures);
+ break;
+ case MAGT_ID_SUCCESSES:
+ MibInfo->Storage = &(ppIntStatInfo[MibInfo->Oid.ids[MibInfo->Oid.idLength - 1] - 1]->Successes);
+ break;
+ case MAGT_ID_URL:
+ MibInfo->Storage = ppIntStatInfo[MibInfo->Oid.ids[MibInfo->Oid.idLength - 1] - 1]->URL.val;
+ break;
+
+
+ default:
+ break;
+ }
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * ReadStaticSettingsOverLdap: Reads static information from the directory server
+ *
+ *
+ * Returns: 0 - No error
+ * -1 - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+int ReadStaticSettingsOverLdap(MagtLDAPInfo_t ldapInfo, MagtStaticInfo_t *staticInfo, int *SNMPoff)
+{
+ LDAP *ld;
+ LDAPMessage *result, *e;
+ BerElement *ber;
+ char *a;
+ char **vals;
+ char *attrs[]={LDAP_ATTR_SNMP_ENABLED,
+ LDAP_ATTR_SNMP_DESCRIPTION,
+ LDAP_ATTR_SNMP_ORGANIZATION,
+ LDAP_ATTR_SNMP_LOCATION,
+ LDAP_ATTR_SNMP_CONTACT,
+ NULL};
+ /* set the applIndex to the ldap port */
+ staticInfo->ApplIndex = ldapInfo.port;
+
+ /* get rest of static settings from the Directory Server */
+ if ( ( ld = ldap_init( ldapInfo.host, ldapInfo.port ) ) == NULL )
+ {
+ return -1;
+ }
+
+ if ( ldap_simple_bind_s( ld, NULL, NULL) != LDAP_SUCCESS )
+ {
+ return -1;
+ }
+
+
+ if ( ldap_search_s( ld, LDAP_CONFIG_DN, LDAP_SCOPE_BASE, BASE_OBJECTCLASS_SEARCH,
+ attrs, 0, &result ) != LDAP_SUCCESS )
+ {
+ return -1;
+
+ }else{
+
+ e = ldap_first_entry( ld, result );
+
+ if(e != NULL)
+ {
+ for ( a = ldap_first_attribute( ld, e, &ber );
+ a != NULL; a = ldap_next_attribute( ld, e, ber ) )
+ {
+ if ((vals = ldap_get_values( ld, e, a)) != NULL )
+ {
+ MagtDispStr_t *pStaticAttr=NULL;
+ /* we only want the first value, ignore any others */
+ if( 0 == strcmp(LDAP_ATTR_SNMP_ENABLED, a) )
+ {
+ if(0 == stricmp(SNMP_ON, vals[0]) )
+ {
+ *SNMPoff = 0;
+ }else{
+ *SNMPoff = 1;
+ }
+ }else if( 0 == strcmp(LDAP_ATTR_SNMP_DESCRIPTION, a) ){
+ pStaticAttr = &(staticInfo->entityDescr);
+ }else if( 0 == strcmp(LDAP_ATTR_SNMP_ORGANIZATION, a) ){
+ pStaticAttr = &(staticInfo->entityOrg);
+ }else if( 0 == strcmp(LDAP_ATTR_SNMP_LOCATION, a) ){
+ pStaticAttr = &(staticInfo->entityLocation);
+ }else if( 0 == strcmp(LDAP_ATTR_SNMP_CONTACT, a) ){
+ pStaticAttr = &(staticInfo->entityContact);
+ }
+ /* stevross: missing the following for NT
+ version
+ DSName
+ */
+
+ /* for Unix also missing
+ MasterHost, MasterPort
+ */
+ if(pStaticAttr != NULL && vals[0] != NULL)
+ {
+ REPLACE(pStaticAttr->val, vals[0]);
+ pStaticAttr->len = strlen(pStaticAttr->val);
+ }
+
+ ldap_value_free( vals );
+
+ }
+
+ ldap_memfree( a );
+
+ }
+
+ if ( ber != NULL )
+ {
+ ldap_ber_free( ber, 0 );
+ }
+ }
+ }
+
+ ldap_msgfree( result );
+ ldap_unbind( ld );
+
+ return 0;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtLoadStaticInfo: Loads static information from the configuration
+ * file.
+ *
+ * Returns: 0 - No error
+ * -1 - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+int MagtLoadStaticInfo(MagtStaticInfo_t *staticInfo, char *pszRootDir, int *SNMPOff, char *pszLogPath)
+{
+ char confpath[MAX_PATH];
+ FILE *fp;
+ char linebuf[MAGT_MAX_LINELEN + 1];
+ int lineLen;
+ char logMsg[1024];
+ MagtLDAPInfo_t ldapInfo;
+
+ /*
+ * Set-up default values first.
+ */
+
+ staticInfo->entityDescr.val = NULL;
+ staticInfo->entityVers.val = NULL;
+ staticInfo->entityOrg.val = NULL;
+ staticInfo->entityLocation.val = NULL;
+ staticInfo->entityContact.val = NULL;
+ staticInfo->entityName.val = NULL;
+
+ staticInfo->ApplIndex = 0;
+
+ REPLACE(staticInfo->entityDescr.val, "Netscape Directory Server");
+ staticInfo->entityDescr.len = strlen(staticInfo->entityDescr.val);
+
+ REPLACE(staticInfo->entityVers.val, "7");
+ staticInfo->entityVers.len = strlen(staticInfo->entityVers.val);
+
+ REPLACE(staticInfo->entityOrg.val, "Not Available");
+ staticInfo->entityOrg.len = strlen(staticInfo->entityOrg.val);
+
+ REPLACE(staticInfo->entityLocation.val, "Not Available");
+ staticInfo->entityLocation.len = strlen(staticInfo->entityLocation.val);
+
+ REPLACE(staticInfo->entityContact.val, "Not Available");
+ staticInfo->entityContact.len = strlen(staticInfo->entityContact.val);
+
+ REPLACE(staticInfo->entityName.val, "Not Available");
+ staticInfo->entityName.len = strlen(staticInfo->entityName.val);
+
+ /*
+ * Read any config info from dse.ldif (for now its just port used as
+ * applIndex
+ */
+
+ wsprintf(confpath, "%s/%s/%s", pszRootDir, MAGT_CONFDIR, DSE_LDIF);
+
+ if ((fp = fopen(confpath, "r")) == (FILE *) NULL)
+ {
+ wsprintf(logMsg,
+ "Failed to open dse.ldif (error = %d)\n",
+ errno);
+ MagtLog(logMsg, pszLogPath);
+ return (-1);
+ }
+
+
+ while ((lineLen = MagtReadLine(linebuf, MAGT_MAX_LINELEN, fp)) > 0)
+ {
+ /*
+ * Update the configured entries.
+ */
+ MagtConfProcess(linebuf, lineLen, &ldapInfo);
+ }
+ fclose (fp);
+
+ if( 0 != ReadStaticSettingsOverLdap(ldapInfo, staticInfo, SNMPOff) < 0 )
+ {
+ wsprintf(logMsg,
+ "Failed to read SNMP configuration over ldap\n");
+ MagtLog(logMsg, pszLogPath);
+ return (-1);
+ }
+
+ return (0);
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtLog: Logs the specified message into the log file.
+ * Notes: Log file is opened and closed each time.
+ *
+ * Returns: None
+ *
+ *-----------------------------------------------------------------------*/
+
+void MagtLog(char *logMsg, char *pszLogPath)
+{
+ FILE *f;
+ char *szTime;
+
+ f = fopen(pszLogPath, "a");
+ if (!f)
+ return;
+ szTime = MagtLogTime();
+ if (szTime != NULL)
+ {
+ fprintf(f, "%s %s", szTime, logMsg);
+ SNMP_free(szTime);
+ }
+ else /* No time string returned */
+ {
+ fprintf(f, "%s %s", "00000000000000", logMsg);
+ }
+ fclose(f);
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtLogTime: Returns time for logging purpose.
+ *
+ * Returns: Formatted time string - No error
+ * "00000000000000" - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+char *MagtLogTime()
+{
+ time_t timeNow;
+ struct tm tmLocal;
+ char dateBuf[64];
+ char *timeStr = NULL;
+ static timeZoneSet = MAGT_FALSE;
+
+ timeNow = time(0);
+ memcpy(&tmLocal, localtime(&timeNow), sizeof(tmLocal));
+
+ /*
+ * Set up the timezone information.
+ */
+ if (!timeZoneSet)
+ {
+ tzset();
+ timeZoneSet = MAGT_TRUE;
+ }
+
+ /*
+ * Create the date string.
+ */
+ if (!strftime(dateBuf, 64, "%Y%m%d%H%M%S", &tmLocal))
+ {
+ strcpy(dateBuf, "00000000000000");
+ }
+ REPLACE(timeStr, dateBuf);
+
+ return timeStr;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtOpenLog: Creates and opens the log file.
+ * Backs up any old log file.
+ *
+ * Returns: None
+ *
+ *-----------------------------------------------------------------------*/
+
+void MagtOpenLog(char *pszRootDir, char *pszLogPath)
+{
+ char logDir[MAX_PATH];
+ char oldPath[MAX_PATH];
+ int fd;
+
+ wsprintf(logDir, "%s\\%s", pszRootDir, "logs");
+ if (mkdir(logDir) != 0)
+ {
+ if (errno != EEXIST)
+ return;
+ }
+
+ wsprintf(pszLogPath, "%s\\%s", logDir, MAGT_LOGFILE);
+ wsprintf(oldPath, "%s\\%s%s", logDir, MAGT_LOGFILE, ".old");
+
+ /*
+ * Rename old log file to keep a back up.
+ */
+ unlink(oldPath);
+ rename(pszLogPath, oldPath);
+
+ /*
+ * Create and open new log file.
+ */
+ fd = open(pszLogPath,
+ _O_WRONLY | _O_CREAT | _O_TRUNC,
+ _S_IWRITE);
+ if (fd != -1)
+ close(fd);
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtReadLine: Reads one line of text (up to n chars) from specified
+ * file.
+ *
+ * Returns: Len read - No error
+ * -1 - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+int MagtReadLine(char *buf, int n, FILE *fp)
+{
+ if (fgets(buf, n, fp) != NULL)
+ {
+ return(strlen(buf));
+ }
+ else
+ {
+ return(-1);
+ }
+}
+
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtReadStats: Reads statistics from stats file. The hdr and tbl data
+ * buffers will be filled in if they are not NULL.
+ *
+ * Returns: 0 - No errors
+ * errno - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+int MagtReadStats(MagtHdrInfo_t *hdrInfo,
+ MagtOpsTblInfo_t *OpsTblInfo,
+ MagtEntriesTblInfo_t *EntriesTblInfo,
+ MagtIntTblInfo_t **IntTblInfo,
+ char * pszStatsPath,
+ char * pszLogPath)
+{
+ int hdl;
+ int err;
+ int i;
+ struct agt_stats_t *pfile_stats;
+
+ if ((err = agt_mopen_stats(pszStatsPath, O_RDONLY, &hdl)) != 0)
+ {
+
+ /*
+ now with multiple instances this function gets called
+ on every snmprequest. Hence
+ logging here became too expensive, now let caller interpret
+ results and figure out if it should log something or not
+ */
+
+
+ return err;
+ }
+
+
+
+ if ( (hdl > 1) || (hdl < 0) )
+ {
+ return (EINVAL); /* Inavlid handle */
+ }
+
+ if ((mmap_tbl [hdl].maptype != AGT_MAP_READ) && (mmap_tbl [hdl].maptype != AGT_MAP_RDWR))
+ {
+ return (EINVAL); /* Inavlid handle */
+ }
+
+ if (mmap_tbl [hdl].fp <= (caddr_t) 0)
+ {
+ return (EFAULT); /* Something got corrupted */
+ }
+
+#if (0)
+ fprintf (stderr, "%s@%d> fp = %d\n", __FILE__, __LINE__, mmap_tbl [hdl].fp);
+#endif
+
+ pfile_stats = (struct agt_stats_t *) (mmap_tbl [hdl].fp);
+
+ /*
+ * Only fill in buffers if they are not NULL. This way, one can choose
+ * to get only the hdr info or only the tbl info.
+ */
+ if (hdrInfo != NULL)
+ {
+ hdrInfo->versMajor = pfile_stats->hdr_stats.hdrVersionMjr;
+ hdrInfo->versMinor = pfile_stats->hdr_stats.hdrVersionMnr;
+ hdrInfo->restarted = pfile_stats->hdr_stats.restarted;
+ hdrInfo->startTime = pfile_stats->hdr_stats.startTime;
+ hdrInfo->updateTime = pfile_stats->hdr_stats.updateTime;
+ }
+ if (OpsTblInfo != NULL){
+ OpsTblInfo->AnonymousBinds = pfile_stats->ops_stats.dsAnonymousBinds;
+ OpsTblInfo->UnAuthBinds = pfile_stats->ops_stats.dsUnAuthBinds;
+ OpsTblInfo->SimpleAuthBinds = pfile_stats->ops_stats.dsSimpleAuthBinds;
+ OpsTblInfo->StrongAuthBinds = pfile_stats->ops_stats.dsStrongAuthBinds;
+ OpsTblInfo->BindSecurityErrors = pfile_stats->ops_stats.dsBindSecurityErrors;
+ OpsTblInfo->InOps = pfile_stats->ops_stats.dsInOps;
+ OpsTblInfo->ReadOps = pfile_stats->ops_stats.dsReadOps;
+ OpsTblInfo->CompareOps = pfile_stats->ops_stats.dsCompareOps;
+ OpsTblInfo->AddEntryOps = pfile_stats->ops_stats.dsAddEntryOps;
+ OpsTblInfo->RemoveEntryOps = pfile_stats->ops_stats.dsRemoveEntryOps;
+ OpsTblInfo->ModifyEntryOps = pfile_stats->ops_stats.dsModifyEntryOps;
+ OpsTblInfo->ModifyRDNOps = pfile_stats->ops_stats.dsModifyRDNOps;
+ OpsTblInfo->ListOps = pfile_stats->ops_stats.dsListOps;
+ OpsTblInfo->SearchOps = pfile_stats->ops_stats.dsSearchOps;
+ OpsTblInfo->OneLevelSearchOps = pfile_stats->ops_stats.dsOneLevelSearchOps;
+ OpsTblInfo->WholeSubtreeSearchOps = pfile_stats->ops_stats.dsWholeSubtreeSearchOps;
+ OpsTblInfo->Referrals = pfile_stats->ops_stats.dsReferrals;
+ OpsTblInfo->Chainings = pfile_stats->ops_stats.dsChainings;
+ OpsTblInfo->SecurityErrors = pfile_stats->ops_stats.dsSecurityErrors;
+ OpsTblInfo->Errors = pfile_stats->ops_stats.dsErrors;
+ }
+ if(EntriesTblInfo != NULL){
+ EntriesTblInfo->MasterEntries = pfile_stats->entries_stats.dsMasterEntries;
+ EntriesTblInfo->CopyEntries = pfile_stats->entries_stats.dsCopyEntries;
+ EntriesTblInfo->CacheEntries = pfile_stats->entries_stats.dsCacheEntries;
+ EntriesTblInfo->CacheHits = pfile_stats->entries_stats.dsCacheHits;
+ EntriesTblInfo->SlaveHits = pfile_stats->entries_stats.dsSlaveHits;
+ }
+
+ if(IntTblInfo != NULL){
+ for(i=0; i < NUM_SNMP_INT_TBL_ROWS; i++)
+ {
+
+ strcpy(IntTblInfo[i]->DsName.val, pfile_stats->int_stats[i].dsName);
+ IntTblInfo[i]->DsName.len = strlen(pfile_stats->int_stats[i].dsName);
+
+ IntTblInfo[i]->TimeOfCreation = pfile_stats->int_stats[i].dsTimeOfCreation;
+ IntTblInfo[i]->TimeOfLastAttempt = pfile_stats->int_stats[i].dsTimeOfLastAttempt;
+ IntTblInfo[i]->TimeOfLastSuccess = pfile_stats->int_stats[i].dsTimeOfLastSuccess;
+ IntTblInfo[i]->FailuresSinceLastSuccess = pfile_stats->int_stats[i].dsFailuresSinceLastSuccess;
+ IntTblInfo[i]->Failures = pfile_stats->int_stats[i].dsFailures;
+ IntTblInfo[i]->Successes = pfile_stats->int_stats[i].dsSuccesses;
+ strcpy(IntTblInfo[i]->URL.val, pfile_stats->int_stats[i].dsURL);
+ IntTblInfo[i]->URL.len = strlen(pfile_stats->int_stats[i].dsURL);
+
+ }
+ }
+
+ agt_mclose_stats(hdl);
+ return 0;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * DllMain: Standard WIN32 DLL entry point.
+ *
+ * Returns: TRUE
+ *
+ *-----------------------------------------------------------------------*/
+
+BOOL WINAPI DllMain(HANDLE hDll, DWORD dwReason, LPVOID lpReserved)
+{
+
+ switch(dwReason)
+ {
+ case DLL_PROCESS_ATTACH:
+ case DLL_THREAD_ATTACH:
+ case DLL_THREAD_DETACH:
+ break;
+ case DLL_PROCESS_DETACH:
+ MagtCleanUp();
+ break;
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * SnmpExtensionInit: Entry point to coordinate the initializations of the
+ * Extension Agent and the Extendible Agent. The
+ * Extendible Agent provides the Extension Agent with a
+ * time zero reference; and the Extension Agent
+ * provides the Extendible Agent with an Event handle
+ * for communicating occurence of traps, and an object
+ * identifier representing the root of the MIB subtree
+ * that the Extension Agent supports.
+ *
+ * Returns: TRUE - No error
+ * FALSE - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+BOOL WINAPI SnmpExtensionInit(IN DWORD dwTimeZeroReference,
+ OUT HANDLE *hPollForTrapEvent,
+ OUT AsnObjectIdentifier *supportedView)
+{
+ int nMibIndex = 0;
+ SECURITY_ATTRIBUTES sa;
+ PSECURITY_ATTRIBUTES psa = NULL;
+ SECURITY_DESCRIPTOR sd;
+ char logMsg[1024];
+ int i;
+
+ instance_list_t *pInstance;
+
+ /*
+ * Record the time reference provided by the Extendible Agent.
+ */
+
+ dwTimeZero = dwTimeZeroReference;
+
+ /*
+ * Create a security descriptor that gives everyone access to the
+ * trap event. This is so that the SNMP process can set the event
+ * when it detects that the server is up or down. Without this
+ * relaxed ACL, the SNMP process which usually runs as the Netscape
+ * DS user can not set the trap event created by this DLL which is
+ * loaded by the Extendible Agent, which usually runs as LocalSystem.
+ */
+ if (InitializeSecurityDescriptor(&sd,
+ SECURITY_DESCRIPTOR_REVISION) == TRUE)
+ {
+ if (SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE) == TRUE)
+ {
+ sa.nLength = sizeof(SECURITY_ATTRIBUTES);
+ sa.bInheritHandle = TRUE;
+ sa.lpSecurityDescriptor = &sd;
+ psa = &sa;
+ }
+ }
+
+ /*
+ * Create an event that will be used to communicate the occurence of
+ * traps to the Extendible Agent.
+ * The event will have a signaled initial state so that the status of
+ * the server can be checked as soon as the subagent is loaded and
+ * the necessary trap will be generated.
+ */
+ if ((*hPollForTrapEvent = CreateEvent(psa,
+ FALSE,
+ FALSE,
+ MAGT_NSEV_SNMPTRAP)) == NULL)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Indicate the MIB view supported by this Extension Agent, an object
+ * identifier representing the sub root of the MIB that is supported.
+ */
+ *supportedView = MIB_OidPrefix;
+
+
+ /*
+ * Initialize globals.
+ */
+
+ if ( !_FindNetscapeServers() )
+ {
+ return FALSE;
+ }
+
+ for (pInstance = pInstanceList; pInstance; pInstance = pInstance->pNext)
+ {
+ MagtInitInstance(pInstance);
+ }
+
+ for (pInstance = pInstanceList; pInstance; pInstance = pInstance->pNext)
+ {
+ /* build the mib */
+
+ if ((pInstance->pOpsStatInfo = (MagtOpsTblInfo_t *) GlobalAlloc(GPTR,
+ sizeof(MagtOpsTblInfo_t))) == NULL)
+ {
+ wsprintf(logMsg, "Failed to allocate ops stats structure (error = %d)\n",
+ GetLastError());
+ MagtLog(logMsg, pInstance->szLogPath);
+ return FALSE;
+ }
+
+ if ((pInstance->pEntriesStatInfo = (MagtEntriesTblInfo_t *) GlobalAlloc(GPTR,
+ sizeof(MagtEntriesTblInfo_t))) == NULL)
+ {
+ wsprintf(logMsg, "Failed to allocate entries stat structure (error = %d)\n",
+ GetLastError());
+ MagtLog(logMsg, pInstance->szLogPath);
+ return FALSE;
+ }
+
+ if ((pInstance->ppIntStatInfo = (MagtIntTblInfo_t **) GlobalAlloc(GPTR,
+ NUM_SNMP_INT_TBL_ROWS * sizeof(MagtIntTblInfo_t *))) == NULL)
+ {
+ wsprintf(logMsg, "Failed to allocate interaction stat structure (error = %d)\n",
+ GetLastError());
+ MagtLog(logMsg, pInstance->szLogPath);
+ return FALSE;
+ }
+
+ for(i =0; i < NUM_SNMP_INT_TBL_ROWS; i++)
+ {
+ pInstance->ppIntStatInfo[i] = (MagtIntTblInfo_t *) GlobalAlloc(GPTR,
+ sizeof(MagtIntTblInfo_t));
+
+ /* make the static char for name and url so they have one address for later use */
+ pInstance->ppIntStatInfo[i]->DsName.val = (char *) GlobalAlloc(GPTR,
+ 100 * sizeof(char));
+ pInstance->ppIntStatInfo[i]->URL.val = (char *) GlobalAlloc(GPTR,
+ 100 * sizeof(char));
+ }
+
+ /* initialize the stats we just allocated */
+ MagtInitStats(pInstance->pOpsStatInfo,
+ pInstance->pEntriesStatInfo,
+ pInstance->ppIntStatInfo);
+
+
+ if( Mib_init(&(pInstance->pMibInfo), pInstance->pCfgInfo->ApplIndex) == -1)
+ {
+ wsprintf(logMsg, "Failed to create Mib structure (error = %d)\n",
+ GetLastError());
+ MagtLog(logMsg, pInstance->szLogPath);
+ return FALSE;
+ }
+
+ for (nMibIndex = 0; nMibIndex < (int) MIB_num_vars; nMibIndex++)
+ {
+ MagtInitMibStorage(&(pInstance->pMibInfo[nMibIndex]),
+ pInstance->pOpsStatInfo,
+ pInstance->pEntriesStatInfo,
+ pInstance->ppIntStatInfo,
+ pInstance->pCfgInfo);
+ }
+
+
+ /*
+ * Construct the path to stats file.
+ */
+ wsprintfA(pInstance->szStatsPath, "%s/logs/%s", pInstance->szRootDir,
+ AGT_STATS_FILE);
+
+ if (MagtReadStats(NULL, pInstance->pOpsStatInfo,
+ pInstance->pEntriesStatInfo,
+ pInstance->ppIntStatInfo,
+ pInstance->szStatsPath,
+ pInstance->szLogPath) != 0)
+ {
+ wsprintf(logMsg,
+ "Failed to open Memory Mapped Stats File. Make sure ns-slapd is running\n",
+ GetLastError());
+ MagtLog(logMsg, pInstance->szLogPath);
+ }
+
+
+ }
+
+ /* now that all mib's set up set next pointer from last entry to first
+ entry of next instance */
+
+ for (nMibIndex = 0; nMibIndex < (int) MIB_num_vars; nMibIndex++)
+ {
+
+ for (pInstance = pInstanceList; pInstance; pInstance = pInstance->pNext)
+ {
+ if(pInstance->pNext != NULL)
+ {
+ pInstance->pMibInfo[nMibIndex].MibNext = &(pInstance->pNext->pMibInfo[nMibIndex]);
+ }else{
+ if (nMibIndex + 1 != (int) MIB_num_vars)
+ {
+ pInstance->pMibInfo[nMibIndex].MibNext = &(pInstanceList->pMibInfo[nMibIndex + 1]);
+ }
+ }
+ }
+
+
+ }
+
+ /*
+ * Set event to have SnmpExtensionTrap invoked for initial check of
+ * Server status.
+ */
+ if (SetEvent(*hPollForTrapEvent) == FALSE)
+ {
+ /* don't have a specific instance to log it to, find something better to do later */
+ }
+
+ return TRUE;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * SnmpExtensionTrap: Entry point to communicate traps to the Extendible
+ * Agent. The Extendible Agent will query this entry
+ * point when the trap event (supplied at initialization
+ * time) is asserted, which indicates that zero or more
+ * traps may have occured. The Extendible Agent will
+ * repeatedly call this entry point until FALSE is
+ * returned, indicating that all outstanding traps have
+ * been processed.
+ *
+ * Returns: TRUE - Valid trap data
+ * FALSE - No trap data
+ *
+ *-----------------------------------------------------------------------*/
+
+BOOL WINAPI SnmpExtensionTrap(OUT AsnObjectIdentifier *enterprise,
+ OUT AsnInteger *genericTrap,
+ OUT AsnInteger *specificTrap,
+ OUT AsnTimeticks *timeStamp,
+ OUT RFC1157VarBindList *variableBindings)
+{
+ static UINT oidList[] = {1, 3, 6, 1, 4, 1, 1450};
+ static UINT oidListLen = MAGT_OID_SIZEOF(oidList);
+ static RFC1157VarBind *trapVars = NULL;
+ static MagtTrapTask_t trapTask = MAGT_TRAP_GENERATION;
+ int nVarLen;
+ char logMsg[1024];
+ instance_list_t *pInstance;
+
+
+ if (trapTask == MAGT_TRAP_CLEANUP)
+ {
+ if (variableBindings->list != NULL)
+ SNMP_FreeVarBind(variableBindings->list);
+
+ trapTask = MAGT_TRAP_GENERATION;
+ }
+
+
+ if (trapTask == MAGT_TRAP_GENERATION)
+ {
+
+ for (pInstance = pInstanceList; pInstance; pInstance = pInstance->pNext)
+ {
+ MagtCheckServer(pInstance);
+
+ /*
+ * If there is no trap to be generated for this instance keep looking at other
+ * instances.
+ */
+ if (pInstance->trapType == MAGT_TRAP_NONE)
+ {
+ continue;
+ }
+
+ enterprise->ids = (UINT *) SNMP_malloc(sizeof(UINT) * oidListLen);
+ if (enterprise->ids == NULL)
+ {
+ wsprintf(logMsg,
+ "Failed to allocate enterprise id\n");
+ MagtLog(logMsg, pInstance->szLogPath);
+ return FALSE;
+ }
+ enterprise->idLength = oidListLen;
+ memcpy(enterprise->ids, oidList, sizeof(UINT) * oidListLen);
+
+ *genericTrap = SNMP_GENERICTRAP_ENTERSPECIFIC;
+ *specificTrap = pInstance->trapType;
+ *timeStamp = GetCurrentTime() - dwTimeZero;
+
+ /*
+ * Set up the variable binding list with variables specified in the MIB
+ * for each trap.
+ */
+ if ((trapVars = SNMP_malloc(sizeof(RFC1157VarBind) * 4)) == NULL)
+ {
+ wsprintf(logMsg,
+ "Failed to allocate trap variables\n");
+ MagtLog(logMsg, pInstance->szLogPath);
+ SNMP_oidfree(enterprise);
+ return FALSE;
+ }
+
+ if ((nVarLen = MagtFillTrapVars(pInstance->trapType, trapVars, pInstance->pCfgInfo)) == 0)
+ {
+ wsprintf(logMsg,
+ "Failed to fill trap variables\n");
+ MagtLog(logMsg, pInstance->szLogPath);
+ SNMP_free(trapVars);
+ SNMP_oidfree(enterprise);
+ return FALSE;
+ }
+
+ variableBindings->list = trapVars;
+ variableBindings->len = nVarLen;
+
+ trapTask = MAGT_TRAP_CLEANUP;
+
+ wsprintf(logMsg,
+ "Sending trap %d\n",
+ pInstance->trapType);
+ MagtLog(logMsg, pInstance->szLogPath);
+
+ /* reset the trap type for this instance */
+ pInstance->trapType = MAGT_TRAP_NONE;
+
+ /*
+ * Indicate that a trap should be sent and parameters contain valid
+ * data.
+ */
+ return TRUE;
+ }
+
+
+ }
+
+ /*
+ * Indicate that no more traps are available and parameters do not
+ * refer to any valid data.
+ */
+
+ return FALSE;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * SnmpExtensionQuery: Entry point to resolve queries for MIB variables in
+ * their supported MIB view (supplied at
+ * initialization time). The supported requestType is
+ * Get/GetNext.
+ *
+ * Returns: TRUE - No error
+ * FALSE - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+BOOL WINAPI SnmpExtensionQuery(IN BYTE requestType,
+ IN OUT RFC1157VarBindList *variableBindings,
+ OUT AsnInteger *errorStatus,
+ OUT AsnInteger *errorIndex)
+{
+ static time_t lastChkTime = 0;
+ UINT i;
+ HANDLE hTrapEvent;
+ time_t currTime;
+
+ /*
+ * Check for valid input.
+ */
+
+ if (variableBindings == NULL ||
+ errorStatus == NULL ||
+ errorIndex == NULL)
+ {
+ return FALSE;
+ }
+
+ /*
+ * Iterate through the variable bindings list to resolve individual
+ * variable bindings.
+ */
+
+ for (i = 0; i < variableBindings->len; i++)
+ {
+ *errorStatus = MagtResolveVarBind(&variableBindings->list[i],
+ requestType);
+
+ /*
+ * Test and handle case where GetNext past end of MIB view supported by
+ * this Extension Agent occurs. Special processing is required to
+ * communicate this situation to the Extendible Agent so it can take
+ * appropriate action.
+ */
+ if (*errorStatus == SNMP_ERRORSTATUS_NOSUCHNAME &&
+ requestType == MAGT_MIB_ACTION_GETNEXT)
+ {
+ *errorStatus = SNMP_ERRORSTATUS_NOERROR;
+
+ /*
+ * Modify variable binding of such variables so the OID points just
+ * outside the MIB view supported by this Extension Agent. The
+ * Extendible Agent tests for this, and takes appropriate action.
+ */
+ SNMP_oidfree(&variableBindings->list[i].name);
+ SNMP_oidcpy(&variableBindings->list[i].name, &MIB_OidPrefix);
+ variableBindings->list[i].name.ids[MAGT_MIB_PREFIX_LEN - 1]++;
+ }
+
+ /*
+ * If an error was indicated, communicate error status and error index
+ * to the Extendible Agent. The Extendible Agent will ensure that the
+ * original variable bindings are returned in the response packet.
+ */
+ if (*errorStatus != SNMP_ERRORSTATUS_NOERROR)
+ {
+ *errorIndex = i + 1;
+ return FALSE;
+ }
+ }
+
+ /*
+ * Before going back, set the trap event so server status can be checked
+ * to see if a trap needs to be generated. This is to cover the case the
+ * SNMP process is unable to set the trap event because it is stuck.
+ */
+ currTime = time(0);
+
+ /*
+ * If just check status, do not generate event again.
+ */
+ if ((currTime - lastChkTime) >= MAGT_TIME_QUANTUM * 3)
+ {
+ if ((hTrapEvent = OpenEvent(EVENT_MODIFY_STATE, FALSE,
+ (LPCTSTR)MAGT_NSEV_SNMPTRAP)) != NULL)
+ SetEvent(hTrapEvent);
+
+ lastChkTime = currTime;
+ }
+
+ return TRUE;
+}
+
+
+/* --- Open Function --------------------------------------------------------------------- */
+
+
+/* _FindNetscapeServers()
+ * Function to loop through registry looking for netscape servers
+ * Stores them into pInstanceList as it finds them.
+ */
+
+#define MAX_KEY_SIZE 128
+DWORD
+_FindNetscapeServers()
+{
+ LONG regStatus,
+ status;
+ HKEY hKeyNetscape = NULL,
+ hKeyNetscapeConf;
+ DWORD dwKey,
+ type,
+ dwServerKeySize,
+ size,
+ dwServerCount = 0;
+ WCHAR szServerKeyName[MAX_KEY_SIZE],
+ szPath[MAX_KEY_SIZE];
+ FILETIME fileTime;
+ instance_list_t *pNew;
+ instance_list_t *pCurrent;
+ DWORD iUniqueID = 0;
+ char logMsg[1024];
+ regStatus = RegOpenKeyEx(
+ HKEY_LOCAL_MACHINE,
+ TEXT(KEY_SOFTWARE_NETSCAPE) TEXT("\\") TEXT(DS_KEY_ROOT),
+ 0L,
+ KEY_ALL_ACCESS,
+ &hKeyNetscape);
+
+ if (regStatus != ERROR_SUCCESS) {
+ goto ExitPoint;
+ }
+
+ dwKey = 0;
+ do {
+ dwServerKeySize = MAX_KEY_SIZE;
+ regStatus = RegEnumKeyEx(
+ hKeyNetscape,
+ dwKey,
+ (char *) szServerKeyName,
+ &dwServerKeySize,
+ NULL,
+ 0,
+ 0,
+ &fileTime);
+ dwKey++;
+
+ if (regStatus == ERROR_SUCCESS) {
+
+ regStatus = RegOpenKeyEx(
+ hKeyNetscape,
+ (char *) szServerKeyName,
+ 0L,
+ KEY_ALL_ACCESS,
+ &hKeyNetscapeConf);
+
+ if (regStatus != ERROR_SUCCESS) {
+ continue;
+ }
+
+ /* Now look for "ConfigurationPath" to find 3.0 netscape servers */
+ size = MAX_KEY_SIZE;
+ status = RegQueryValueEx(
+ hKeyNetscapeConf,
+ TEXT(VALUE_CONFIG_PATH),
+ 0L,
+ &type,
+ (LPBYTE)szPath,
+ &size);
+ if ( status == ERROR_SUCCESS ) {
+ /* this is a netscape server */
+ if ( (pNew = (instance_list_t *)malloc(sizeof(instance_list_t))) == NULL) {
+ status = (unsigned long)-1;
+ RegCloseKey(hKeyNetscapeConf);
+ goto ExitPoint;
+ }
+ if ( (pNew->pInstanceName = (PWCH)malloc(sizeof(WCHAR) *(dwServerKeySize+1))) == NULL) {
+ status = (unsigned long)-1;
+ RegCloseKey(hKeyNetscapeConf);
+ goto ExitPoint;
+ }
+ if ( (pNew->pConfPath = (PWCH)malloc(sizeof(WCHAR) *(size+1))) == NULL) {
+ status = (unsigned long)-1;
+ RegCloseKey(hKeyNetscapeConf);
+ goto ExitPoint;
+ }
+
+
+ pNew->Handle = 0;
+ pNew->pData = NULL;
+
+ pNew->instance.ParentObjectTitleIndex = 0;
+ pNew->instance.ParentObjectInstance = 0;
+ pNew->instance.UniqueID = -1;
+ pNew->instance.NameOffset = sizeof(PERF_INSTANCE_DEFINITION);
+ lstrcpy((char *) pNew->pInstanceName, (char *) szServerKeyName);
+
+ lstrcpy((char *) pNew->pConfPath, (char *) szPath);
+
+ pNew->instance.NameLength = (dwServerKeySize+1) * sizeof(WCHAR);
+ pNew->instance.ByteLength = sizeof(PERF_INSTANCE_DEFINITION) +
+ (((pNew->instance.NameLength + sizeof(DWORD)-1)/sizeof(DWORD))*sizeof(DWORD));
+ pNew->instance.UniqueID = iUniqueID++;
+
+ wsprintf(pNew->szLogPath, "\\%s", MAGT_LOGFILE);
+ if( ((char *) pNew->szRootDir = getRootDirFromConfFile(pNew->pConfPath) ) != NULL)
+ {
+ /* can only check if getRootDir */
+
+ /* open the log */
+
+ MagtOpenLog(pNew->szRootDir, pNew->szLogPath);
+
+ if ((pNew->pCfgInfo = (MagtStaticInfo_t *) GlobalAlloc(GPTR,
+ sizeof(MagtStaticInfo_t))) == NULL)
+ {
+ /* something fatal happened but try to free this
+ node that won't be used anyway
+ */
+ if(pNew != NULL)
+ {
+ free(pNew);
+ }
+ status = (unsigned long)-1;
+ goto ExitPoint;
+ }
+
+ MagtLoadStaticInfo(pNew->pCfgInfo, pNew->szRootDir, &pNew->SNMPOff, pNew->szLogPath);
+
+
+ if ( pNew->SNMPOff )
+ {
+ wsprintf(logMsg,
+ "SNMP subagent is not configured to be on\n");
+ MagtLog(logMsg, pNew->szLogPath);
+
+ /* since not adding this to list free it */
+ if(pNew != NULL)
+ {
+ free(pNew);
+ }
+ }else{
+ /* new instance that is on to add to list */
+
+ /* if first element null or less than first element add to beginning */
+ if( (pInstanceList == NULL)
+ || (pNew->pCfgInfo->ApplIndex < pInstanceList->pCfgInfo->ApplIndex) )
+ {
+ pNew->pNext = pInstanceList;
+ pInstanceList = pNew;
+ }else{
+ /* must be after first element */
+ for(pCurrent= pInstanceList; pCurrent; pCurrent=pCurrent->pNext)
+ {
+ if(pNew->pCfgInfo->ApplIndex == pCurrent->pCfgInfo->ApplIndex)
+ {
+ /* ApplIndex must be unique, another instance on this host
+ is already configured to be on using this applIndex,
+ so I can't monitor this one. Log the error and
+ don't add this instance to the list */
+
+ wsprintf(logMsg,
+ "Another server instance with this ApplIndex: %d is already being"
+ " monitored. ApplIndex must be unique. Turn off"
+ " SNMP monitoring of the other server instance or change"
+ " the ApplIndex of one of the server instances.\n",
+ pNew->pCfgInfo->ApplIndex);
+ MagtLog(logMsg, pNew->szLogPath);
+
+ /* since not adding this to list free it */
+ if(pNew != NULL)
+ {
+ free(pNew);
+ }
+ }else if( (pCurrent->pNext == NULL)
+ || ( (pNew->pCfgInfo->ApplIndex > pCurrent->pCfgInfo->ApplIndex)
+ && (pNew->pCfgInfo->ApplIndex < pCurrent->pNext->pCfgInfo->ApplIndex)) )
+ {
+ /* if next is null or if greater this element and less then next one
+ add it inbetween */
+ pNew->pNext=pCurrent->pNext;
+ pCurrent->pNext=pNew;
+ break;
+ }
+ }
+ }
+ }
+ }
+ dwServerCount++;
+ }
+
+ RegCloseKey(hKeyNetscapeConf);
+ }
+
+ } while ( regStatus != ERROR_NO_MORE_ITEMS );
+
+ExitPoint:
+ if (hKeyNetscape)
+ RegCloseKey (hKeyNetscape);
+
+ return dwServerCount;
+}
+
diff --git a/ldap/servers/snmp/ntagt/nsldapagt_nt.def b/ldap/servers/snmp/ntagt/nsldapagt_nt.def
new file mode 100644
index 00000000..9968af40
--- /dev/null
+++ b/ldap/servers/snmp/ntagt/nsldapagt_nt.def
@@ -0,0 +1,24 @@
+; BEGIN COPYRIGHT BLOCK
+; Copyright 2001 Sun Microsystems, Inc.
+; Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+; All rights reserved.
+; END COPYRIGHT BLOCK
+;
+LIBRARY ns-ldapagt
+
+DESCRIPTION 'Netscape Directory Server SNMP Agent'
+
+CODE LOADONCALL MOVEABLE DISCARDABLE
+DATA PRELOAD MOVEABLE SINGLE
+
+SEGMENTS
+ _TEXT PRELOAD
+ INIT_TEXT PRELOAD
+
+HEAPSIZE 1024
+
+EXPORTS
+ SnmpExtensionInit
+ SnmpExtensionTrap
+ SnmpExtensionQuery
+
diff --git a/ldap/servers/snmp/ntagt/nsldapagt_nt.h b/ldap/servers/snmp/ntagt/nsldapagt_nt.h
new file mode 100644
index 00000000..16e472db
--- /dev/null
+++ b/ldap/servers/snmp/ntagt/nsldapagt_nt.h
@@ -0,0 +1,228 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*-------------------------------------------------------------------------
+ *
+ * nsldapagt_nt.h - Definitions for NS Directory Server's SNMP subagent on
+ * NT.
+ *
+ * Revision History:
+ * 07/25/1997 Steve Ross Created
+ *
+ *
+ *-----------------------------------------------------------------------*/
+
+#ifndef __NSLDAPAGT_NT_H_
+#define __NSLDAPAGT_NT_H_
+
+/*-------------------------------------------------------------------------
+ *
+ * Defines
+ *
+ *-----------------------------------------------------------------------*/
+
+#define MAGT_MAX_LINELEN 255
+#define MAGT_CONFFILE "snmp.conf"
+#define MAGT_CONFDIR "config"
+#define DSE_LDIF "dse.ldif"
+#define MAGT_LOGFILE "nsldapagt.log"
+#define MAGT_TIME_QUANTUM 10
+
+#define MAGT_TRAP_NONE 0
+#define MAGT_TRAP_SERVER_DOWN 7001
+#define MAGT_TRAP_SERVER_START 7002
+
+#define LDAP_CONFIG_DN "cn=SNMP,cn=config"
+#define BASE_OBJECTCLASS_SEARCH "objectclass=*"
+
+#define LDAP_ATTR_SNMP_ENABLED "nssnmpenabled"
+#define LDAP_ATTR_SNMP_DESCRIPTION "nssnmpdescription"
+#define LDAP_ATTR_SNMP_ORGANIZATION "nssnmporganization"
+#define LDAP_ATTR_SNMP_LOCATION "nssnmplocation"
+#define LDAP_ATTR_SNMP_CONTACT "nssnmpcontact"
+
+#define SNMP_ON "ON"
+
+/*-------------------------------------------------------------------------
+ *
+ * Types
+ *
+ *-----------------------------------------------------------------------*/
+
+typedef enum
+{
+ MAGT_FALSE = 0,
+ MAGT_TRUE
+} MagtBool_t;
+
+typedef enum
+{
+ MAGT_TRAP_GENERATION,
+ MAGT_TRAP_CLEANUP
+} MagtTrapTask_t;
+
+typedef struct MagtDispStr
+{
+ int len;
+ unsigned char *val;
+} MagtDispStr_t;
+
+typedef struct MagtStaticInfo
+{
+ MagtDispStr_t entityDescr;
+ MagtDispStr_t entityVers;
+ MagtDispStr_t entityOrg;
+ MagtDispStr_t entityLocation;
+ MagtDispStr_t entityContact;
+ MagtDispStr_t entityName;
+ int ApplIndex;
+
+} MagtStaticInfo_t;
+
+typedef struct MagtLDAPInfo
+{
+ char *host;
+ int port;
+ char *rootdn;
+ char *rootpw;
+
+
+} MagtLDAPInfo_t;
+
+typedef struct MagtHdrInfo
+{
+ int versMajor;
+ int versMinor;
+ int restarted;
+ time_t startTime;
+ time_t updateTime;
+} MagtHdrInfo_t;
+
+typedef struct MagtOpsTblInfo
+{
+ int AnonymousBinds;
+ int UnAuthBinds;
+ int SimpleAuthBinds;
+ int StrongAuthBinds;
+ int BindSecurityErrors;
+ int InOps;
+ int ReadOps;
+ int CompareOps;
+ int AddEntryOps;
+ int RemoveEntryOps;
+ int ModifyEntryOps;
+ int ModifyRDNOps;
+ int ListOps;
+ int SearchOps;
+ int OneLevelSearchOps;
+ int WholeSubtreeSearchOps;
+ int Referrals;
+ int Chainings;
+ int SecurityErrors;
+ int Errors;
+} MagtOpsTblInfo_t;
+
+typedef struct MagtEntriesTblInfo
+{
+ int MasterEntries;
+ int CopyEntries;
+ int CacheEntries;
+ int CacheHits;
+ int SlaveHits;
+} MagtEntriesTblInfo_t;
+
+typedef struct MagtIntTblInfo
+{
+ MagtDispStr_t DsName;
+ time_t TimeOfCreation;
+ time_t TimeOfLastAttempt;
+ time_t TimeOfLastSuccess;
+ int FailuresSinceLastSuccess;
+ int Failures;
+ int Successes;
+ MagtDispStr_t URL;
+}MagtIntTblInfo_t;
+
+typedef struct instance_list_t {
+ PERF_INSTANCE_DEFINITION instance;
+ PWSTR pInstanceName;
+ PWSTR pConfPath;
+ int Handle;
+ struct agt_stats_t * pData;
+ HANDLE ghTrapEvent;
+ MagtOpsTblInfo_t * pOpsStatInfo;
+ MagtEntriesTblInfo_t * pEntriesStatInfo;
+ MagtIntTblInfo_t ** ppIntStatInfo;
+ MagtStaticInfo_t * pCfgInfo;
+ MagtMibEntry_t * pMibInfo;
+ char * szRootDir;
+ char szLogPath[MAX_PATH];
+ char szStatsPath[MAX_PATH];
+ int SNMPOff;
+
+
+ /* trap stuff */
+ time_t oldUpdateTime;
+ time_t oldStartTime;
+ int graceCycles;
+ MagtBool_t mmapStale;
+ MagtBool_t mmapOk;
+ MagtBool_t serverUp;
+ MagtBool_t downTrapSent;
+ int trapType;
+ MagtHdrInfo_t hdrInfo;
+
+ struct instance_list_t * pNext;
+} instance_list_t;
+
+/*-------------------------------------------------------------------------
+ *
+ * Prototypes
+ *
+ *-----------------------------------------------------------------------*/
+
+int MagtCheckServer(instance_list_t *pInstance);
+
+void MagtCleanUp();
+
+void MagtConfProcess(char *line, int lineLen,
+ MagtLDAPInfo_t *info);
+
+char *MagtGetRootDir(void);
+
+
+void MagtInitMibStorage(MagtMibEntry_t * MibInfo,
+ MagtOpsTblInfo_t * pOpsStatInfo,
+ MagtEntriesTblInfo_t * pEntriesStatInfo,
+ MagtIntTblInfo_t ** ppIntStatInfo,
+ MagtStaticInfo_t * pCfgInfo);
+
+
+int MagtLoadStaticInfo(MagtStaticInfo_t *staticInfo, char *pszRootDir, int *SNMPOff, char *pszLogPath);
+
+void MagtLog(char *logMsg, char *pszLogPath);
+
+char *MagtLogTime();
+
+void MagtOpenLog(char *pszRootDir, char *pszLogPath);
+
+int MagtReadLine(char *buf,
+ int n,
+ FILE *fp);
+
+int MagtReadStats(MagtHdrInfo_t *hdrInfo,
+ MagtOpsTblInfo_t *OpsTblInfo,
+ MagtEntriesTblInfo_t *EntriesTblInfo,
+ MagtIntTblInfo_t **IntTblInfo,
+ char * pszStatsPath,
+ char * pszLogPath);
+
+DWORD _FindNetscapeServers();
+
+extern instance_list_t *pInstanceList;
+
+
+#endif /* __NSLDAPAGT_NT_H_ */
diff --git a/ldap/servers/snmp/ntagt/nsldapmib_nt.c b/ldap/servers/snmp/ntagt/nsldapmib_nt.c
new file mode 100644
index 00000000..af977a23
--- /dev/null
+++ b/ldap/servers/snmp/ntagt/nsldapmib_nt.c
@@ -0,0 +1,1041 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*-------------------------------------------------------------------------
+ *
+ * nsldapmib_nt.c - NS Directory Server's MIB for extended SNMP agent
+ * on NT.
+ *
+ * Revision History:
+ * 07/25/1997 Steve Ross Created
+ *
+ *
+ *-----------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <malloc.h>
+#include <time.h>
+#include <windows.h>
+#include <malloc.h>
+#include <snmp.h>
+#include <mgmtapi.h>
+#include "nsldapmib_nt.h"
+#include "nsldapagt_nt.h"
+#include "agtmmap.h"
+
+/*-------------------------------------------------------------------------
+ *
+ * Globals
+ *
+ *-----------------------------------------------------------------------*/
+
+/*
+ * For ldap, the prefix to all MIB variables is 1.3.6.1.4.1.1450.7
+ */
+UINT OID_Prefix[] = {1, 3, 6, 1, 4, 1, 1450, 7};
+AsnObjectIdentifier MIB_OidPrefix = {MAGT_OID_SIZEOF(OID_Prefix),
+ OID_Prefix};
+
+/*
+ * OID of each MIB variable.
+ * For example, the OID for mtaReceivedMessages is:
+ * 1.3.6.1.4.1.1450.7
+ *
+ * - nsldap = netscape 7
+ * -dsOpsTable = nsldap 1
+ * -dsEntriesTable = nsldap 2
+ * -dsIntTable = nsldap 3
+ * -dsEntityINfo = nsldap 5
+ *
+ */
+
+
+UINT OID_ApplIndex[] = {389};
+/* setup the parts of the OID we know in advance */
+
+/* ops table */
+UINT OID_AnonymousBinds[] = {1, 1, 1};
+UINT OID_UnAuthBinds[] = {1, 1, 2};
+UINT OID_SimpleAuthBinds[] = {1, 1, 3};
+UINT OID_StrongAuthBinds[] = {1, 1, 4};
+UINT OID_BindSecurityErrors[] = {1, 1, 5};
+UINT OID_InOps[] = {1, 1, 6};
+UINT OID_ReadOps[] = {1, 1, 7};
+UINT OID_CompareOps[] = {1, 1, 8};
+UINT OID_AddEntryOps[] = {1, 1, 9};
+UINT OID_RemoveEntryOps[] = {1, 1, 10};
+UINT OID_ModifyEntryOps[] = {1, 1, 11};
+UINT OID_ModifyRDNOps[] = {1, 1, 12};
+UINT OID_ListOps[] = {1, 1, 13};
+UINT OID_SearchOps[] = {1, 1, 14};
+UINT OID_OneLevelSearchOps[] = {1, 1, 15};
+UINT OID_WholeSubtreeSearchOps[] = {1, 1, 16};
+UINT OID_Referrals[] = {1, 1, 17};
+UINT OID_Chainings[] = {1, 1, 18};
+UINT OID_SecurityErrors[] = {1, 1, 19};
+UINT OID_Errors[] = {1, 1, 20};
+
+/* entries table */
+UINT OID_MasterEntries[] = {2, 1, 1};
+UINT OID_CopyEntries[] = {2, 1, 2};
+UINT OID_CacheEntries[] = {2, 1, 3};
+UINT OID_CacheHits[] = {2, 1, 4};
+UINT OID_SlaveHits[] = {2, 1, 5};
+
+/* interaction table */
+UINT OID_DsIntIndex[] = {3, 1, 1};
+UINT OID_DsName[] = {3, 1, 2};
+UINT OID_TimeOfCreation[] = {3, 1, 3};
+UINT OID_TimeOfLastAttempt[] = {3, 1, 4};
+UINT OID_TimeOfLastSuccess[] = {3, 1, 5};
+UINT OID_FailuresSinceLastSuccess[] = {3, 1, 6};
+UINT OID_Failures[] = {3, 1, 7};
+UINT OID_Successes[] = {3, 1, 8};
+UINT OID_URL[] = {3, 1, 9};
+
+/* entity table */
+UINT OID_EntityDescr[] = {5, 1, 1};
+UINT OID_EntityVers[] = {5, 1, 2};
+UINT OID_EntityOrg[] = {5, 1, 3};
+UINT OID_EntityLocation[] = {5, 1, 4};
+UINT OID_EntityContact[] = {5, 1, 5};
+UINT OID_EntityName[] = {5, 1, 6};
+
+
+/* make AsnObjectIdentifiers so can use snmputilOidcpy for each server instance, and append to put on indexes later */
+/* ops table */
+AsnObjectIdentifier ASN_AnonymousBinds = {MAGT_OID_SIZEOF(OID_AnonymousBinds) ,OID_AnonymousBinds};
+AsnObjectIdentifier ASN_UnAuthBinds = {MAGT_OID_SIZEOF(OID_UnAuthBinds) ,OID_UnAuthBinds};
+AsnObjectIdentifier ASN_SimpleAuthBinds = {MAGT_OID_SIZEOF(OID_SimpleAuthBinds) ,OID_SimpleAuthBinds};
+AsnObjectIdentifier ASN_StrongAuthBinds = {MAGT_OID_SIZEOF(OID_StrongAuthBinds) ,OID_StrongAuthBinds};
+AsnObjectIdentifier ASN_BindSecurityErrors = {MAGT_OID_SIZEOF(OID_BindSecurityErrors) ,OID_BindSecurityErrors};
+AsnObjectIdentifier ASN_InOps = {MAGT_OID_SIZEOF(OID_InOps) ,OID_InOps};
+AsnObjectIdentifier ASN_ReadOps = {MAGT_OID_SIZEOF(OID_ReadOps) ,OID_ReadOps};
+AsnObjectIdentifier ASN_CompareOps = {MAGT_OID_SIZEOF(OID_CompareOps) ,OID_CompareOps};
+AsnObjectIdentifier ASN_AddEntryOps = {MAGT_OID_SIZEOF(OID_AddEntryOps) ,OID_AddEntryOps};
+AsnObjectIdentifier ASN_RemoveEntryOps = {MAGT_OID_SIZEOF(OID_RemoveEntryOps) ,OID_RemoveEntryOps};
+AsnObjectIdentifier ASN_ModifyEntryOps = {MAGT_OID_SIZEOF(OID_ModifyEntryOps) ,OID_ModifyEntryOps};
+AsnObjectIdentifier ASN_ModifyRDNOps = {MAGT_OID_SIZEOF(OID_ModifyRDNOps) ,OID_ModifyRDNOps};
+AsnObjectIdentifier ASN_ListOps = {MAGT_OID_SIZEOF(OID_ListOps) ,OID_ListOps};
+AsnObjectIdentifier ASN_SearchOps = {MAGT_OID_SIZEOF(OID_SearchOps) ,OID_SearchOps};
+AsnObjectIdentifier ASN_OneLevelSearchOps = {MAGT_OID_SIZEOF(OID_OneLevelSearchOps) ,OID_OneLevelSearchOps};
+AsnObjectIdentifier ASN_WholeSubtreeSearchOps = {MAGT_OID_SIZEOF(OID_WholeSubtreeSearchOps),OID_WholeSubtreeSearchOps};
+AsnObjectIdentifier ASN_Referrals = {MAGT_OID_SIZEOF(OID_Referrals) ,OID_Referrals};
+AsnObjectIdentifier ASN_Chainings = {MAGT_OID_SIZEOF(OID_Chainings) ,OID_Chainings};
+AsnObjectIdentifier ASN_SecurityErrors = {MAGT_OID_SIZEOF(OID_SecurityErrors) ,OID_SecurityErrors};
+AsnObjectIdentifier ASN_Errors = {MAGT_OID_SIZEOF(OID_Errors) ,OID_Errors};
+
+/* entries table */
+AsnObjectIdentifier ASN_MasterEntries = {MAGT_OID_SIZEOF(OID_MasterEntries) ,OID_MasterEntries};
+AsnObjectIdentifier ASN_CopyEntries = {MAGT_OID_SIZEOF(OID_CopyEntries) ,OID_CopyEntries};
+AsnObjectIdentifier ASN_CacheEntries = {MAGT_OID_SIZEOF(OID_CacheEntries) ,OID_CacheEntries};
+AsnObjectIdentifier ASN_CacheHits = {MAGT_OID_SIZEOF(OID_CacheHits) ,OID_CacheHits};
+AsnObjectIdentifier ASN_SlaveHits = {MAGT_OID_SIZEOF(OID_SlaveHits) ,OID_SlaveHits};
+
+/* interaction table */
+AsnObjectIdentifier ASN_DsName = {MAGT_OID_SIZEOF(OID_DsName) ,OID_DsName};
+AsnObjectIdentifier ASN_TimeOfCreation = {MAGT_OID_SIZEOF(OID_TimeOfCreation) ,OID_TimeOfCreation};
+AsnObjectIdentifier ASN_TimeOfLastAttempt = {MAGT_OID_SIZEOF(OID_TimeOfLastAttempt) ,OID_TimeOfLastAttempt};
+AsnObjectIdentifier ASN_TimeOfLastSuccess = {MAGT_OID_SIZEOF(OID_TimeOfLastSuccess) ,OID_TimeOfLastSuccess};
+AsnObjectIdentifier ASN_FailuresSinceLastSuccess = {MAGT_OID_SIZEOF(OID_FailuresSinceLastSuccess) ,OID_FailuresSinceLastSuccess};
+AsnObjectIdentifier ASN_Failures = {MAGT_OID_SIZEOF(OID_Failures) ,OID_Failures};
+AsnObjectIdentifier ASN_Successes = {MAGT_OID_SIZEOF(OID_Successes) ,OID_Successes};
+AsnObjectIdentifier ASN_URL = {MAGT_OID_SIZEOF(OID_URL) ,OID_URL};
+
+/* entity table */
+AsnObjectIdentifier ASN_EntityDescr = {MAGT_OID_SIZEOF(OID_EntityDescr) ,OID_EntityDescr};
+AsnObjectIdentifier ASN_EntityVers = {MAGT_OID_SIZEOF(OID_EntityVers) ,OID_EntityVers};
+AsnObjectIdentifier ASN_EntityOrg = {MAGT_OID_SIZEOF(OID_EntityOrg) ,OID_EntityOrg};
+AsnObjectIdentifier ASN_EntityLocation = {MAGT_OID_SIZEOF(OID_EntityLocation) ,OID_EntityLocation};
+AsnObjectIdentifier ASN_EntityContact = {MAGT_OID_SIZEOF(OID_EntityContact) ,OID_EntityContact};
+AsnObjectIdentifier ASN_EntityName = {MAGT_OID_SIZEOF(OID_EntityName) ,OID_EntityName};
+
+/*
+ * Storage definitions for MIB.
+ */
+char szPlaceHolder[] = "Not Available";
+int nPlaceHolder = 0;
+
+#define NUM_ENTITY_COLUMNS 6
+#define NUM_OPS_COLUMNS 20
+#define NUM_ENTRIES_COLUMNS 5
+#define NUM_INT_COLUMNS 8
+#define NUM_INT_ROWS 5
+
+
+UINT MIB_num_vars;
+
+void OidAppendIndex(AsnObjectIdentifier *Oid, int Index);
+
+int Mib_init(MagtMibEntry_t **Mib, int ApplIndex)
+{
+ int i;
+ int j;
+
+ MIB_num_vars = (UINT) 71;
+
+ /* allocate the memory for this Mib Instance */
+ if( (*Mib = (MagtMibEntry_t *) GlobalAlloc(GPTR, MIB_num_vars *
+ sizeof(MagtMibEntry_t ) )) == NULL)
+ {
+ return -1;
+ }
+
+ /**************************
+ * Ops Table Stuff
+ * --------------
+ * AnonymousBinds
+ * UnAuthBinds
+ * SimpleAuthBinds
+ * StrongAuthBinds
+ * BindSecurityErrors
+ * InOps
+ * ReadOps
+ * CompareOps
+ * AddEntryOps
+ * RemoveEntryOps
+ * ModifyEntryOps
+ * ModifyRDNOps
+ * ListOps
+ * SearchOps
+ * OneLevelSearchOps
+ * WholeSubtreeSearchOps
+ * Referrals
+ * Chainings
+ * SecurityErrors
+ * Errors
+ **************************/
+
+
+ i=0;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_AnonymousBinds);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_ANONYMOUS_BINDS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_UnAuthBinds);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_UNAUTH_BINDS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_SimpleAuthBinds);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_SIMPLE_AUTH_BINDS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_StrongAuthBinds);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_STRONG_AUTH_BINDS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_BindSecurityErrors);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_BIND_SECURITY_ERRORS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_InOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_IN_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_ReadOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_READ_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_CompareOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_COMPARE_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_AddEntryOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_ADD_ENTRY_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_RemoveEntryOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_REMOVE_ENTRY_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_ModifyEntryOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_MODIFY_ENTRY_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_ModifyRDNOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_MODIFY_RDN_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_ListOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_LIST_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_SearchOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_SEARCH_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_OneLevelSearchOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_ONE_LEVEL_SEARCH_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_WholeSubtreeSearchOps);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_WHOLE_SUBTREE_SEARCH_OPS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_Referrals);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_REFERRALS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_Chainings);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_CHAININGS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_SecurityErrors);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_SECURITY_ERRORS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_Errors);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_ERRORS;
+
+ /**************************
+ * Entries Table Stuff
+ * --------------
+ * MasterEntries
+ * CopyEntries
+ * CacheEntries
+ * CacheHits
+ * SlaveHits
+ **************************/
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_MasterEntries);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_MASTER_ENTRIES;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_CopyEntries);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_COPY_ENTRIES;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_CacheEntries);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_CACHE_ENTRIES;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_CacheHits);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_CACHE_HITS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_SlaveHits);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_SLAVE_HITS;
+
+
+ /**************************
+ * Interaction Table Stuff
+ * --------------
+ * DsName
+ * TimeOfCreation
+ * TimeOfLastAttempt
+ * TimeOfLastSuccess
+ * FailuresSinceLastSuccess
+ * Failures
+ * Successes
+ * URL
+ **************************/
+
+ for(j=1; j <= NUM_SNMP_INT_TBL_ROWS; j++)
+ {
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_DsName);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ OidAppendIndex(&((*Mib)[i].Oid), j);
+ (*Mib)[i].Storage = szPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1213_DISPSTRING;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_DS_NAME;
+
+ }
+
+ for(j=1; j <= NUM_SNMP_INT_TBL_ROWS; j++)
+ {
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_TimeOfCreation);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ OidAppendIndex(&((*Mib)[i].Oid), j);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_TIMETICKS;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_TIME_OF_CREATION;
+ }
+
+ for(j=1; j <= NUM_SNMP_INT_TBL_ROWS; j++)
+ {
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_TimeOfLastAttempt);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ OidAppendIndex(&((*Mib)[i].Oid), j);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_TIMETICKS;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_TIME_OF_LAST_ATTEMPT;
+ }
+
+ for(j=1; j <= NUM_SNMP_INT_TBL_ROWS; j++)
+ {
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_TimeOfLastSuccess);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ OidAppendIndex(&((*Mib)[i].Oid), j);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_TIMETICKS;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_TIME_OF_LAST_SUCCESS;
+ }
+
+ for(j=1; j <= NUM_SNMP_INT_TBL_ROWS; j++)
+ {
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_FailuresSinceLastSuccess);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ OidAppendIndex(&((*Mib)[i].Oid), j);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_FAILURES_SINCE_LAST_SUCCESS;
+ }
+
+ for(j=1; j <= NUM_SNMP_INT_TBL_ROWS; j++)
+ {
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_Failures);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ OidAppendIndex(&((*Mib)[i].Oid), j);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_FAILURES;
+ }
+
+ for(j=1; j <= NUM_SNMP_INT_TBL_ROWS; j++)
+ {
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_Successes);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ OidAppendIndex(&((*Mib)[i].Oid), j);
+ (*Mib)[i].Storage = &nPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1155_COUNTER;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_SUCCESSES;
+ }
+
+ for(j=1; j <= NUM_SNMP_INT_TBL_ROWS; j++)
+ {
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_URL);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ OidAppendIndex(&((*Mib)[i].Oid), j);
+ (*Mib)[i].Storage = szPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1213_DISPSTRING;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_URL;
+ }
+
+ /**************************
+ * Entity Stuff
+ * --------------
+ * EntityDescr
+ * EntityVers
+ * EntityOrg
+ * EntityLocation
+ * EntityContact
+ * EntityName
+ **************************/
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_EntityDescr);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = szPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1213_DISPSTRING;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_DESC;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_EntityVers);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = szPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1213_DISPSTRING;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_VERS;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_EntityOrg);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = szPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1213_DISPSTRING;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_ORG;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_EntityLocation);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = szPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1213_DISPSTRING;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_LOC;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_EntityContact);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = szPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1213_DISPSTRING;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_CONTACT;
+
+ i++;
+ SnmpUtilOidCpy(&((*Mib)[i].Oid), &ASN_EntityName);
+ OidAppendIndex(&((*Mib)[i].Oid), ApplIndex);
+ (*Mib)[i].Storage = szPlaceHolder;
+ (*Mib)[i].Type = ASN_RFC1213_DISPSTRING;
+ (*Mib)[i].Access = MAGT_MIB_ACCESS_READ;
+ (*Mib)[i].MibFunc = MagtMIBLeafFunc;
+ (*Mib)[i].MibNext = NULL;
+ (*Mib)[i].uId = MAGT_ID_NAME;
+
+ return 0;
+}
+
+void OidAppendIndex(AsnObjectIdentifier *Oid, int Index)
+{
+ UINT OID_Index[1];
+ AsnObjectIdentifier ASN_Index;
+
+ OID_Index[0] = Index;
+ ASN_Index.ids = OID_Index;
+ ASN_Index.idLength = 1;
+
+ SnmpUtilOidAppend(Oid, &ASN_Index);
+
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtFillTrapVars: Fills in the variable list for the specified trap.
+ *
+ * Returns: 0 - No variable filled
+ * n - Number of variables filled
+ *
+ *-----------------------------------------------------------------------*/
+
+int MagtFillTrapVars(int trapType, RFC1157VarBind *trapVars, MagtStaticInfo_t *pCfgInfo)
+{
+ MagtDispStr_t varVals[4];
+ int nVarLen = 0;
+ int i, j;
+ static AsnObjectIdentifier varOid[4] = {{MAGT_OID_SIZEOF(OID_EntityDescr),
+ OID_EntityDescr},
+ {MAGT_OID_SIZEOF(OID_EntityVers),
+ OID_EntityVers},
+ {MAGT_OID_SIZEOF(OID_EntityLocation),
+ OID_EntityLocation},
+ {MAGT_OID_SIZEOF(OID_EntityContact),
+ OID_EntityContact}};
+
+ /*
+ * Get the variable values from the static info which has been obtained
+ * from the snmp config file at initialization time.
+ */
+ varVals[0].len = pCfgInfo->entityDescr.len;
+ varVals[0].val = pCfgInfo->entityDescr.val;
+ varVals[1].len = pCfgInfo->entityVers.len;
+ varVals[1].val = pCfgInfo->entityVers.val;
+ varVals[2].len = pCfgInfo->entityLocation.len;
+ varVals[2].val = pCfgInfo->entityLocation.val;
+ varVals[3].len = pCfgInfo->entityContact.len;
+ varVals[3].val = pCfgInfo->entityContact.val;
+
+ for (i = 0; i < 4; i++)
+ {
+ SNMP_oidcpy(&trapVars[i].name, &MIB_OidPrefix);
+ SNMP_oidappend(&trapVars[i].name, &varOid[i]);
+ trapVars[i].value.asnType = ASN_OCTETSTRING;
+ trapVars[i].value.asnValue.string.length = varVals[i].len;
+ trapVars[i].value.asnValue.string.stream =
+ SNMP_malloc((trapVars[i].value.asnValue.string.length) *
+ sizeof(char));
+ if (trapVars[i].value.asnValue.string.stream == NULL)
+ {
+
+ /*
+ * Clean up any allocated variable binding allocated up until now.
+ */
+ for (j = 0; j < i; j++)
+ {
+ SNMP_FreeVarBind(&trapVars[j]);
+ return nVarLen;
+ }
+ }
+ memcpy(trapVars[i].value.asnValue.string.stream, varVals[i].val,
+ trapVars[i].value.asnValue.string.length);
+ trapVars[i].value.asnValue.string.dynamic = TRUE;
+ }
+
+ switch (trapType)
+ {
+ case MAGT_TRAP_SERVER_DOWN:
+ nVarLen = 4;
+ break;
+ case MAGT_TRAP_SERVER_START:
+ nVarLen = 3;
+ break;
+ default:
+ break;
+ }
+
+ return nVarLen;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtMIBLeafFunc: Performs generic actions on leaf variables in the MIB.
+ * Note that SET action is not supported.
+ *
+ * Returns: SNMP_ERRORSTATUS_NOERROR - No error
+ * PDU error codes - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+UINT MagtMIBLeafFunc(IN UINT Action, IN MagtMibEntry_t *mibPtr,
+ IN RFC1157VarBind *VarBind)
+{
+ UINT ErrStat = SNMP_ERRORSTATUS_NOERROR;
+ static AsnObjectIdentifier ApplIndexOid = {MAGT_OID_SIZEOF(OID_ApplIndex),
+ OID_ApplIndex};
+ instance_list_t *pInstance;
+ char logMsg[1024];
+
+ switch(Action)
+ {
+ case MAGT_MIB_ACTION_GETNEXT:
+ /*
+ * If there is no next pointer, this is the end of the MIB tree.
+ */
+ if (mibPtr->MibNext == NULL)
+ {
+ ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
+ return ErrStat;
+ }
+
+ /*
+ * Set up VarBind to contain the OID of the next variable.
+ */
+ SNMP_oidfree(&VarBind->name);
+ SNMP_oidcpy(&VarBind->name, &MIB_OidPrefix);
+ SNMP_oidappend(&VarBind->name, &mibPtr->MibNext->Oid);
+
+ /*
+ * Call function to process the GET request.
+ */
+ ErrStat = (*mibPtr->MibNext->MibFunc)(MAGT_MIB_ACTION_GET, mibPtr->MibNext,
+ VarBind);
+ break;
+ case MAGT_MIB_ACTION_GET:
+
+ /*
+ * Make sure that the variable's access right allows GET.
+ */
+ if (mibPtr->Access != MAGT_MIB_ACCESS_READ &&
+ mibPtr->Access != MAGT_MIB_ACCESS_READWRITE)
+ {
+ ErrStat = SNMP_ERRORSTATUS_NOSUCHNAME;
+ return ErrStat;
+ }
+
+ if (mibPtr->Storage == NULL) /* Counter not supported */
+ {
+ ErrStat = SNMP_ERRORSTATUS_GENERR;
+ return ErrStat;
+ }
+
+ if ((VarBind->name.ids[MAGT_MIB_PREFIX_LEN] > 1) &&
+ (SNMP_oidcmp(&mibPtr->Oid, &ApplIndexOid) != 0))
+ {
+
+ /*
+ * Read stats file to update counter statistics.
+ */
+
+ /* need to update all of them because don't know which instance resulted
+ into call into this function */
+ for (pInstance = pInstanceList; pInstance; pInstance = pInstance->pNext)
+ {
+ if (MagtReadStats(NULL, pInstance->pOpsStatInfo,
+ pInstance->pEntriesStatInfo,
+ pInstance->ppIntStatInfo,
+ pInstance->szStatsPath,
+ pInstance->szLogPath) != 0)
+ {
+
+ /* this server is off/or went down since we
+ started up snmp. The snmp agent will
+ return last values it was set to until
+ server starts back up. If server was not
+ started will return null for strings and
+ 0 for values */
+
+ /* to log for each snmp request is to expensive
+ for now, just silently acknowledge the fact
+ and think about something better for the future
+ */
+
+
+ }
+ }
+ }
+
+ /*
+ * Set up VarBind's return value.
+ */
+ VarBind->value.asnType = mibPtr->Type;
+ switch (VarBind->value.asnType)
+ {
+ case ASN_RFC1155_TIMETICKS:
+ case ASN_RFC1155_COUNTER:
+ case ASN_RFC1155_GAUGE:
+ case ASN_INTEGER:
+ VarBind->value.asnValue.number = *(AsnInteger *)(mibPtr->Storage);
+ break;
+ case ASN_RFC1155_IPADDRESS:
+ case ASN_OCTETSTRING: /* = ASN_RFC1213_DISPSTRING */
+ VarBind->value.asnValue.string.length =
+ strlen((LPSTR)mibPtr->Storage);
+ VarBind->value.asnValue.string.stream =
+ SNMP_malloc((VarBind->value.asnValue.string.length + 2) *
+ sizeof(char));
+ if (VarBind->value.asnValue.string.stream == NULL)
+ {
+ ErrStat = SNMP_ERRORSTATUS_GENERR;
+ return ErrStat;
+ }
+ memcpy(VarBind->value.asnValue.string.stream,
+ (LPSTR)mibPtr->Storage,
+ VarBind->value.asnValue.string.length);
+ VarBind->value.asnValue.string.dynamic = TRUE;
+ break;
+ case ASN_OBJECTIDENTIFIER:
+ VarBind->value.asnValue.object =
+ *(AsnObjectIdentifier *)(mibPtr->Storage);
+ break;
+ default:
+ ErrStat = SNMP_ERRORSTATUS_GENERR;
+ break;
+ } /* Switch */
+
+ break;
+ default:
+ ErrStat = SNMP_ERRORSTATUS_GENERR;
+ break;
+ } /* Switch */
+
+ return ErrStat;
+}
+
+/*-------------------------------------------------------------------------
+ *
+ * MagtResolveVarBind: Resolves a single variable binding. Modifies the
+ * variable on a GET or a GETNEXT.
+ *
+ * Returns: SNMP_ERRORSTATUS_NOERROR - No error
+ * PDU error codes - Errors
+ *
+ *-----------------------------------------------------------------------*/
+
+UINT MagtResolveVarBind(IN OUT RFC1157VarBind *VarBind, IN UINT PduAction)
+{
+ MagtMibEntry_t *mibPtr = NULL;
+ AsnObjectIdentifier TempOid;
+ int CompResult;
+ UINT i = 0;
+ UINT nResult;
+ instance_list_t *pInstance;
+
+ pInstance = pInstanceList;
+
+ while (mibPtr == NULL && pInstance !=NULL)
+ {
+ /*
+ * Construct OID with complete prefix for comparison purpose
+ */
+ SNMP_oidcpy(&TempOid, &MIB_OidPrefix);
+ SNMP_oidappend(&TempOid, &(pInstance->pMibInfo[i].Oid));
+
+ /*
+ * Check for OID in MIB. On a GET-NEXT, the OID does not have to match
+ * exactly a variable in the MIB, it must only fall under the MIB root.
+ */
+ CompResult = SNMP_oidcmp(&VarBind->name, &TempOid);
+
+ if (CompResult < 0) /* Not an exact match */
+ {
+ if (PduAction != MAGT_MIB_ACTION_GETNEXT) /* Only GET-NEXT is valid */
+ {
+
+ pInstance=pInstance->pNext;
+ i=0;
+ if(pInstance == NULL)
+ {
+ nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
+ return nResult;
+ }else{
+ continue;
+ }
+
+ }
+
+ /*
+ * Since the match was not exact, but var bind name is within MIB,
+ * we are at the next MIB variable down from the one specified.
+ */
+ PduAction = MAGT_MIB_ACTION_GET;
+ mibPtr = &(pInstance->pMibInfo[i]);
+
+ /*
+ * Replace var bind name with new name.
+ */
+ SNMP_oidfree(&VarBind->name);
+ SNMP_oidcpy(&VarBind->name, &MIB_OidPrefix);
+ SNMP_oidappend(&VarBind->name, &mibPtr->Oid);
+ }
+ else
+ {
+ if (CompResult == 0) /* Found an exact match */
+ {
+ mibPtr = &(pInstance->pMibInfo[i]);
+ }else{
+ /* see if it is one of the other ApplIndex */
+ instance_list_t *pApplIndex;
+ for(pApplIndex = pInstance; pApplIndex; pApplIndex=pApplIndex->pNext)
+ {
+ SNMP_oidfree(&TempOid);
+
+ SNMP_oidcpy(&TempOid, &MIB_OidPrefix);
+ SNMP_oidappend(&TempOid, &(pApplIndex->pMibInfo[i].Oid));
+
+ CompResult = SNMP_oidcmp(&VarBind->name, &TempOid);
+ if(CompResult == 0)
+ {
+ mibPtr = &(pApplIndex->pMibInfo[i]);
+ }
+ }
+ }
+
+
+ }
+
+ /*
+ * Free OID memory before checking another variable.
+ */
+ SNMP_oidfree(&TempOid);
+ i++;
+
+ if(i == MIB_num_vars)
+ {
+ pInstance=pInstance->pNext;
+ i=0;
+ }
+ } /* While */
+
+ if (mibPtr == NULL) /* OID not within MIB's scope */
+ {
+ nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
+ return nResult;
+ }
+
+ if (*mibPtr->MibFunc == NULL)
+ {
+ nResult = SNMP_ERRORSTATUS_NOSUCHNAME;
+ return nResult;
+ }
+
+ /*
+ * Call function to process request. Each MIB entry has a function pointer
+ * that knows how to process its MIB variable.
+ */
+ nResult = (*mibPtr->MibFunc)(PduAction, mibPtr, VarBind);
+
+ SNMP_oidfree(&TempOid); /* Free temp memory */
+
+ return nResult;
+
+}
diff --git a/ldap/servers/snmp/ntagt/nsldapmib_nt.h b/ldap/servers/snmp/ntagt/nsldapmib_nt.h
new file mode 100644
index 00000000..ac53dad7
--- /dev/null
+++ b/ldap/servers/snmp/ntagt/nsldapmib_nt.h
@@ -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 **/
+
+/*-------------------------------------------------------------------------
+ *
+ * nsldapmib_nt.h - Definitions for NS Directory Server's MIB on NT.
+ *
+ * Revision History:
+ * 07/25/1997 Steve Ross Created
+ *
+ *
+ *
+ *-----------------------------------------------------------------------*/
+
+#ifndef __NSLDAPMIB_NT_H_
+#define __NSLDAPMIB_NT_H_
+
+/*-------------------------------------------------------------------------
+ *
+ * Defines
+ *
+ *-----------------------------------------------------------------------*/
+
+#define MAGT_MIB_PREFIX_LEN MIB_OidPrefix.idLength
+#define MAGT_MAX_STRING_LEN 255
+
+#define MAGT_MIB_ACCESS_READ 0
+#define MAGT_MIB_ACCESS_WRITE 1
+#define MAGT_MIB_ACCESS_READWRITE 2
+
+#define MAGT_MIB_ACTION_GET ASN_RFC1157_GETREQUEST
+#define MAGT_MIB_ACTION_SET ASN_RFC1157_SETREQUEST
+#define MAGT_MIB_ACTION_GETNEXT ASN_RFC1157_GETNEXTREQUEST
+
+/*
+ * Macro to determine number of sub-oids in array.
+ */
+#define MAGT_OID_SIZEOF(Oid) (sizeof Oid / sizeof(UINT))
+
+/*
+ * Unique ID for each entry in the MIB.
+ */
+enum
+{
+ MAGT_ID_DESC = 0,
+ MAGT_ID_VERS,
+ MAGT_ID_ORG,
+ MAGT_ID_LOC,
+ MAGT_ID_CONTACT,
+ MAGT_ID_NAME,
+ /* operations table attrs */
+ MAGT_ID_ANONYMOUS_BINDS,
+ MAGT_ID_UNAUTH_BINDS,
+ MAGT_ID_SIMPLE_AUTH_BINDS,
+ MAGT_ID_STRONG_AUTH_BINDS ,
+ MAGT_ID_BIND_SECURITY_ERRORS,
+ MAGT_ID_IN_OPS,
+ MAGT_ID_READ_OPS,
+ MAGT_ID_COMPARE_OPS,
+ MAGT_ID_ADD_ENTRY_OPS,
+ MAGT_ID_REMOVE_ENTRY_OPS,
+ MAGT_ID_MODIFY_ENTRY_OPS,
+ MAGT_ID_MODIFY_RDN_OPS,
+ MAGT_ID_LIST_OPS,
+ MAGT_ID_SEARCH_OPS,
+ MAGT_ID_ONE_LEVEL_SEARCH_OPS,
+ MAGT_ID_WHOLE_SUBTREE_SEARCH_OPS,
+ MAGT_ID_REFERRALS,
+ MAGT_ID_CHAININGS,
+ MAGT_ID_SECURITY_ERRORS,
+ MAGT_ID_ERRORS,
+ /* entries table attrs */
+ MAGT_ID_MASTER_ENTRIES,
+ MAGT_ID_COPY_ENTRIES,
+ MAGT_ID_CACHE_ENTRIES,
+ MAGT_ID_CACHE_HITS,
+ MAGT_ID_SLAVE_HITS,
+ /* interaction table entries */
+ MAGT_ID_DS_NAME,
+ MAGT_ID_TIME_OF_CREATION,
+ MAGT_ID_TIME_OF_LAST_ATTEMPT,
+ MAGT_ID_TIME_OF_LAST_SUCCESS,
+ MAGT_ID_FAILURES_SINCE_LAST_SUCCESS,
+ MAGT_ID_FAILURES,
+ MAGT_ID_SUCCESSES,
+ MAGT_ID_URL,
+ /* applIndex */
+ MAGT_ID_APPLINDEX
+};
+
+/*-------------------------------------------------------------------------
+ *
+ * Types
+ *
+ *-----------------------------------------------------------------------*/
+
+typedef struct MagtMibEntry
+{
+ AsnObjectIdentifier Oid;
+ void *Storage;
+ BYTE Type;
+ UINT Access;
+ UINT (*MibFunc)(UINT, struct MagtMibEntry *, RFC1157VarBind *);
+ struct MagtMibEntry *MibNext;
+ UINT uId;
+} MagtMibEntry_t;
+
+#include "nsldapagt_nt.h"
+/*-------------------------------------------------------------------------
+ *
+ * Prototypes
+ *
+ *-----------------------------------------------------------------------*/
+
+int MagtFillTrapVars(int trapType,
+ RFC1157VarBind * trapVars,
+ MagtStaticInfo_t * pCfgInfo);
+
+UINT MagtMIBLeafFunc(IN UINT Action,
+ IN MagtMibEntry_t *MibPtr,
+ IN RFC1157VarBind *VarBind);
+
+UINT MagtResolveVarBind(IN OUT RFC1157VarBind *VarBind,
+ IN UINT PduAction);
+
+int Mib_init(MagtMibEntry_t **Mib, int ApplIndex);
+#endif /* __NSLDAPMIB_NT_H_ */
diff --git a/ldap/systools/Makefile b/ldap/systools/Makefile
new file mode 100644
index 00000000..969c3b95
--- /dev/null
+++ b/ldap/systools/Makefile
@@ -0,0 +1,96 @@
+#
+# 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 LDAP Server tools.
+#
+
+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 = $(OBJDIR)/servers/tools/obj
+BINDIR = $(LDAP_SERVER_RELDIR)
+
+SLAPD_OBJDIR = $(LDAP_OBJDIR)
+
+include $(MCOM_ROOT)/ldapserver/nsdefs.mk
+include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+include $(LDAP_SRC)/nsldap.mk
+
+ifeq ($(ARCH), OSF1)
+PLATFORM_SPECIFIC_EXTRA_LIBRARY = -lcxx
+else # OSF1
+# oems might need to edit this for their platform
+PLATFORM_SPECIFIC_EXTRA_LIBRARY =
+endif # OSF1
+
+
+ifeq ($(USE_64), 1)
+ifeq ($(ARCH), HPUX)
+LDFLAGS += +DA2.0W +DS2.0 +Z
+endif
+ifeq ($(ARCH), SOLARIS)
+LDFLAGS += -xarch=v9
+endif
+endif
+
+LDFLAGS += $(EXLDFLAGS)
+
+DEPLIBS=
+
+EXTRA_LIBS_DEP =
+
+EXTRA_LIBS = $(PLATFORM_SPECIFIC_EXTRA_LIBRARY)
+
+ifeq ($(ARCH), Linux)
+EXTRA_LIBS += -lcrypt
+endif
+
+ifeq ($(ARCH), SOLARIS)
+EXTRA_LIBS += -lelf
+endif
+
+ifeq ($(ARCH), AIX)
+EXTRA_LIBS += -lodm
+endif
+
+TOOL_OBJS = idsktune.o pio.o viewcore.o
+ALL_OBJS = $(addprefix $(OBJDEST)/, $(TOOL_OBJS))
+
+DSKTUNE = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, dsktune))
+VIEWCORE = $(addsuffix $(EXE_SUFFIX), \
+ $(addprefix $(BINDIR)/, viewcore))
+
+ifeq ($(ARCH), SOLARIS)
+BINS= $(DSKTUNE) $(VIEWCORE)
+else
+BINS= $(DSKTUNE)
+endif
+
+all: $(OBJDEST) $(BINDIR) $(BINS)
+
+$(DSKTUNE): $(OBJDEST)/idsktune.o $(OBJDEST)/pio.o $(EXTRA_LIBS_DEP)
+ $(LINK_EXE_NOLIBSOBJS) $< $(OBJDEST)/pio.o $(EXTRA_LIBS)
+
+$(VIEWCORE): $(OBJDEST)/viewcore.o $(EXTRA_LIBS_DEP)
+ $(LINK_EXE_NOLIBSOBJS) $< $(EXTRA_LIBS)
+
+$(OBJDEST):
+ $(MKDIR) $(OBJDEST)
+
+$(OBJDEST)/idsktune.o: sol_patches.c hp_patches.c
+
+clean:
+ -$(RM) $(ALL_OBJS)
+ -$(RM) $(BINS)
+
+
diff --git a/ldap/systools/README b/ldap/systools/README
new file mode 100644
index 00000000..2573a5f7
--- /dev/null
+++ b/ldap/systools/README
@@ -0,0 +1,31 @@
+How to get the list of patches:
+
+We used to just kind of guess which patches were needed. Now, we look at the
+patches installed on the system and build our list from that. WARNING - The
+system that you run this on must be a pretty clean system, with no extra
+software or hardware packages (e.g. compilers, software development
+environments, etc.). We don't want to complain to our customers that they
+must install the C compiler! So, I recommend running these scripts on a fresh
+clean QA-type system that has had the latest recommended patches or jumbo
+patch set applied. If for some reason you need to edit the auto generated
+patch files, please put a comment in this file with the date and your ID.
+
+Solaris:
+ You will need one system for each supported OS release. This means, for
+DS 6.2, both a Solaris 8 and a Solaris 9 system. Log into each system as root
+and execute the getSolPatches.pl script. By default it tries to use
+/usr/bin/perl, so if that is not available, any perl version > 5.005_03 can be
+used (older versions might work). Redirect the output to a file
+(e.g. /tmp/patches), then copy that file over solN_patches.c, where N is the
+OS release number (e.g. 8 or 9). Then, merge the files together into one -
+for example, mergeSolPatches.pl sol8_patches.c sol9_patches.c > sol_patches.c.
+Each patch is already tagged with what release version it came from and is applied to.
+
+HP:
+ Log into the reference machine and run getHPPatches.pl > /tmp/patches. You
+may have to be superuser - for some reason, swlist must be run as root on some
+machines but not others. So, if you run it and get strange error messages, try
+it as root. Then, copy /tmp/patches over hp_patches.c. By default, the perl
+script tries to use /tools/ns/bin/perl5.6.1, so if that does not exist, try
+another version of perl. HP ships with a very old version of perl (v4) that
+may or may not work.
diff --git a/ldap/systools/getHPPatches.pl b/ldap/systools/getHPPatches.pl
new file mode 100755
index 00000000..4d1be441
--- /dev/null
+++ b/ldap/systools/getHPPatches.pl
@@ -0,0 +1,83 @@
+#!/tools/ns/bin/perl5.6.1 -w
+
+$patchcmd = "swlist -l bundle";
+# [output sample]
+# Initializing...
+# Contacting target "linux2"...
+#
+# Target: linux2:/
+#
+#
+# B6268AA B.11.00.05 Graphics and Technical Computing Software
+# BUNDLE B.11.00 Patch Bundle
+# HPUXEng64RT B.11.00.01 English HP-UX 64-bit Runtime Environment
+# HWE1100 B.11.00.0206.5 Hardware Enablement Patches for HP-UX 11.00, June 2002
+# OnlineDiag B.11.00.21.10 HPUX 11.0 Support Tools Bundle, Jun 2002
+# QPK1100 B.11.00.64.4 Quality Pack for HP-UX 11.00, March 2004
+# UnlimUserLic B.11.00.02 HP-UX Unlimited-User License
+# XSWGR1100 B.11.00.47.08 General Release Patches, November 1999 (ACE)
+
+%month2digit = (
+ 'January', 1,
+ 'February', 2,
+ 'March', 3,
+ 'April', 4,
+ 'May', 5,
+ 'June', 6,
+ 'July', 7,
+ 'August', 8,
+ 'September', 9,
+ 'October', 10,
+ 'November', 11,
+ 'December', 12,
+);
+
+open PATCHCMD, "$patchcmd|" or die "Error: could not open $patchcmd: $!";
+sleep 1;
+
+$qpk_str = "";
+$month_year = "";
+while (<PATCHCMD>) {
+ chop;
+ if (/^\s+(QPK.*), ([A-Za-z]* [12][0-9]*)/) {
+ $qpk_str = $1;
+ $month_year = $2;
+ }
+}
+close PATCHCMD;
+
+$date = gmtime;
+$host = `hostname`;
+chop $host;
+$dom = `domainname`;
+$un = `uname -a`;
+
+print "/* This list was generated by $0 */\n";
+print "/* on $host.$dom */\n";
+print "/* at $date GMT */\n";
+print "/* Here is the information from uname -a:\n";
+print $un;
+if ( $qpk_str eq "" )
+{
+ print " Quality Pack is not installed on the system. */\n";
+}
+else
+{
+ ($qpkname, $version, $description) = split(/[ ]+/, $qpk_str, 3);
+ print "$qpkname\n";
+ print "$version\n";
+ print "$description\n";
+
+ if ( $month_year eq "" )
+ {
+ print " Quality pack has no date info. */\n";
+ print "$qpk_str <$month_year>\n";
+ }
+ else
+ {
+ ($month, $year) = split(/\s/, $month_year, 2);
+ $mo = $month2digit{$month};
+ print " The following is a Quality Pack installed on the system. */\n";
+ print "{\"$qpkname\", \"$version\", \"$description\", $year, $mo, 0},\n";
+ }
+}
diff --git a/ldap/systools/getSolPatches.pl b/ldap/systools/getSolPatches.pl
new file mode 100755
index 00000000..7b463fef
--- /dev/null
+++ b/ldap/systools/getSolPatches.pl
@@ -0,0 +1,64 @@
+#!/usr/bin/perl -w
+
+$patchdir = "/var/sadm/patch";
+
+# key is the major patch number
+# the value is a hash ref which has two keys 'iminor' and 'val'
+# the value of key 'iminor' is the minor patch number
+# the system keeps track of all revisions (minor number) for each patch (major number)
+# we only want to list the highest revision, since on Solaris higher revisions include
+# and supersede lower revisions
+# the value of key 'val' is the string to print out
+%patches = ();
+
+opendir PATCHDIR, $patchdir or die "Error: could not open $patchdir: $!: you must be superuser to run this script\n";
+while ($dir = readdir PATCHDIR) {
+ if ($dir =~ /(\d+)\-(\d+)/) {
+ $major = $1;
+ $minor = $2;
+ $iminor = int($2);
+ if (! $patches{$major} || ! $patches{$major}->{iminor} || ($patches{$major}->{iminor} < $iminor)) {
+ open IN, "$patchdir/$dir/README.$major\-$minor" or die "Error: could not open $patchdir/$dir/README.$major\-$minor: $! - you must be superuser to run this script\n";
+ while (<IN>) {
+ chop;
+ if (/^Synopsis:\s+/) {
+ $desc = $';
+ }
+ if (/^Date:\s+/) {
+ $date = $';
+ }
+ if (/^SunOS Release:\s+(\d+)\.(\d+)/) {
+ $majrel = $1;
+ $minrel = $2;
+ last;
+ }
+ }
+ $required = 1; # how to tell if patch is not required, only recommended?
+ $patches{$major}->{val} = "{$major,$iminor,$required,2$minrel,0,0,\"$date: $desc\"},\n";
+ close IN;
+ $patches{$major}->{iminor} = $iminor;
+ }
+ }
+}
+closedir PATCHDIR;
+
+$date = gmtime;
+$host = `hostname`;
+$dom = `domainname`;
+$rel = `cat /etc/release`;
+
+chomp $host;
+chomp $dom;
+chomp $date;
+print "/* This list was generated by $0 */\n";
+print "/* on $host.$dom */\n";
+print "/* at $date GMT */\n";
+print "/* Here is the information from /etc/release:\n";
+print $rel;
+print " The following is a list of patches installed on the system */\n";
+print "/* a patch that is commented out is either a duplicate or */\n";
+print "/* a patch that is superseded by another patch */\n";
+
+for $major (sort keys %patches) {
+ print $patches{$major}->{val};
+}
diff --git a/ldap/systools/hp_patches.c b/ldap/systools/hp_patches.c
new file mode 100644
index 00000000..2437675c
--- /dev/null
+++ b/ldap/systools/hp_patches.c
@@ -0,0 +1,5 @@
+{"PHSS_30966","1.0","ld(1) and linker tools cumulative patch",0,0,0},
+{"PHSS_39486","1.0","KRB5-Client Version 1.0 cumulative patch",0,0,0},
+{"PHSS_39487","1.0","GSS-API Version 1.0 Cumulative patch",0,0,0},
+{"GOLDAPPS11i","B.11.11.0406.5","Gold Applications Patches for HP-UX 11i v1",2004,6,0},
+{"GOLDBASE11i","B.11.11.0406.5","Gold Base Patches for HP-UX 11i v1",2004,6,0},
diff --git a/ldap/systools/idsktune.c b/ldap/systools/idsktune.c
new file mode 100644
index 00000000..c6afaa1d
--- /dev/null
+++ b/ldap/systools/idsktune.c
@@ -0,0 +1,3279 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2004 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+ * Don't forget to update build_date when the patch sets are updated.
+ * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! */
+static char *build_date = "19-MARCH-2004";
+
+#if defined(__FreeBSD__) || defined(__bsdi)
+#define IDDS_BSD_INCLUDE 1
+#define IDDS_BSD_SYSCTL 1
+#endif
+
+#if defined(linux) || defined(__linux) || defined(__linux__)
+#define IDDS_LINUX_INCLUDE 1
+#define IDDS_LINUX_SYSCTL 1
+#endif
+
+#if defined(__sun) || defined(__sun__) || defined(_AIX) || defined(__hppa) || defined(_nec_ews_svr4) || defined(__osf__) || defined(__sgi) || defined(sgi)
+#define IDDS_SYSV_INCLUDE 1
+#endif
+
+#include <sys/types.h>
+
+#if defined(IDDS_BSD_INCLUDE)
+#include <sys/time.h>
+#endif
+
+#if !defined(_WIN32) && !defined(__VMS)
+#include <sys/resource.h>
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#if !defined(_WIN32) && !defined(__VMS) && !defined(IDDS_LINUX_INCLUDE) && !defined(IDDS_BSD_INCLUDE)
+#if defined(__hppa) && defined(f_type)
+#undef f_type
+#endif
+#include <sys/statvfs.h>
+#define IDDS_HAVE_STATVFS
+#endif
+
+#if defined(_WIN32)
+#include <windows.h>
+#define MAXPATHLEN 1024
+extern char *optarg;
+#endif
+
+#if defined(IDDS_SYSV_INCLUDE) || defined(IDDS_BSD_INCLUDE)
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <sys/param.h>
+#endif
+
+#if defined(__sun) || defined(__sun__) || defined(__osf__) || defined(_nec_ews_svr4) || defined(__sgi) || defined(sgi)
+/* not available on HP-UX or AIX */
+#include <sys/systeminfo.h>
+#endif
+
+#if defined(__sun)
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/mnttab.h>
+#define IDDS_MNTENT mnttab
+#define IDDS_MNTENT_DIRNAME mnt_mountp
+#define IDDS_MNTENT_OPTIONS mnt_mntopts
+#define IDDS_MNTENT_MNTTAB "/etc/mnttab"
+#endif
+
+#if defined(IDDS_LINUX_INCLUDE)
+#include <sys/vfs.h>
+#include <sys/utsname.h>
+#include <linux/kernel.h>
+#include <linux/sys.h>
+#include <sys/time.h>
+#include <sys/param.h>
+#include <mntent.h>
+
+#define IDDS_MNTENT mntent
+#define IDDS_MNTENT_DIRNAME mnt_dir
+#define IDDS_MNTENT_OPTIONS mnt_opts
+#define IDDS_MNTENT_MNTTAB "/etc/mtab"
+#endif
+
+#if defined(__hppa)
+#include <sys/pstat.h>
+#include <mntent.h>
+
+#define IDDS_MNTENT mntent
+#define IDDS_MNTENT_DIRNAME mnt_dir
+#define IDDS_MNTENT_OPTIONS mnt_opts
+#define IDDS_MNTENT_MNTTAB "/etc/mnttab"
+#endif
+
+#if defined(_AIX)
+#include <pthread.h>
+#include <signal.h>
+#include <sys/inttypes.h>
+#include <odmi.h>
+#include <fstab.h>
+
+struct CuAt {
+ __long32_t _id;
+ __long32_t _reserved;
+ __long32_t _scratch;
+ char name[16];
+ char attribute[16];
+ char value[256];
+ char type[8];
+ char generic[8];
+ char rep[8];
+ short nls_index;
+};
+#define CuAt_Descs 7
+
+struct fix {
+ __long32_t _id;
+ __long32_t _reserved;
+ __long32_t _scratch;
+ char name[16];
+ char abstract[60];
+ char type[2];
+ char *filesets;
+ char *symptom;
+ };
+
+#define fix_Descs 5
+
+struct Class CuAt_CLASS[];
+extern struct Class fix_CLASS[];
+
+static void idds_aix_odm_get_cuat (char *query,char *buf);
+
+#define IDDS_MNTENT fstab
+#define IDDS_MNTENT_DIRNAME fs_file
+/* AIX does not have /etc/mnttab */
+/* #define IDDS_MNTENT_OPTIONS */
+
+#endif
+
+#if defined(__VMS)
+#error "This program is not available for VMS"
+#endif
+
+#if defined(__osf__)
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/swap.h>
+#include <sys/sysinfo.h>
+#include <sys/utsname.h>
+#include <sys/systeminfo.h>
+#include <machine/hal_sysinfo.h>
+#include <machine/cpuconf.h>
+#include <fstab.h>
+
+#define IDDS_MNTENT fstab
+#define IDDS_MNTENT_DIRNAME fs_file
+#define IDDS_MNTENT_OPTIONS fs_mntops
+#endif
+
+
+#include "pio.h"
+
+int flag_html = 0;
+int flag_debug = 0;
+int flag_quick = 0;
+int flag_os_bad = 0;
+int flag_solaris_9 = 0;
+int flag_solaris_8 = 0;
+int flag_solaris_7 = 0;
+int flag_solaris_26 = 0;
+int flag_solaris_251 = 0;
+int flag_tru64_40b = 0;
+int flag_tru64_tuning_needed = 0;
+int solaris_version = 0;
+int flag_intel = 0;
+int flag_arch_bad = 0;
+int phys_mb = 0;
+int swap_mb = 0;
+int flag_mproc = 0;
+int tcp_max_listen = 0;
+int flag_nonroot = 0;
+int flag_carrier = 0;
+
+int conn_thread = 1;
+int maxconn = 0;
+int client = 0;
+
+int mem_min = 256;
+int mem_rec = 1024;
+
+/* Define name variations on different platforms */
+
+#if defined(__sun)
+#define NAME_NDD_CFG_FILE "/etc/init.d/inetinit"
+#define NAME_TCP_TIME_WAIT_INTERVAL "tcp_time_wait_interval"
+#define NAME_TCP_CONN_REQ_MAX_Q "tcp_conn_req_max_q"
+#define NAME_TCP_KEEPALIVE_INTERVAL "tcp_keepalive_interval"
+#define NAME_TCP_SMALLEST_ANON_PORT "tcp_smallest_anon_port"
+#endif
+
+#if defined(__hppa)
+#define NAME_NDD_CFG_FILE "/etc/rc.config.d/nddconf"
+#define NAME_TCP_TIME_WAIT_INTERVAL "tcp_time_wait_interval"
+#define NAME_TCP_CONN_REQ_MAX_Q "tcp_conn_request_max"
+#define NAME_TCP_KEEPALIVE_INTERVAL "tcp_keepalive_interval"
+#define NAME_TCP_SMALLEST_ANON_PORT "tcp_smallest_anon_port"
+#endif
+
+#if defined(IDDS_LINUX_SYSCTL)
+#define NAME_TCP_KEEPALIVE_INTERVAL "net.ipv4.tcp_keepalive_time"
+#endif
+
+#if defined(IDDS_BSD_SYSCTL)
+#define NAME_TCP_SMALLEST_ANON_PORT "net.inet.ip.portrange.hifirst"
+#endif
+
+#if defined(__sun) || defined(__hppa) || defined(IDDS_BSD_SYSCTL) || defined(IDDS_LINUX_SYSCTL)
+
+long ndd_tcp_conn_req_max_q = 0;
+long ndd_tcp_conn_req_max_q0 = 0;
+long ndd_tcp_rexmit_interval_initial = 0;
+long ndd_tcp_slow_start_initial = 0;
+long ndd_tcp_keepalive_interval = 0;
+long ndd_tcp_time_wait_interval = 0;
+long ndd_tcp_smallest_anon_port = 0;
+long ndd_tcp_deferred_ack_interval = 0;
+long ndd_tcp_ip_abort_cinterval = 0;
+long ndd_tcp_ip_abort_interval = 0;
+long ndd_tcp_strong_iss = 0;
+int hpux_ndd_change_needed = 0;
+
+
+#endif
+
+char install_dir[MAXPATHLEN];
+int avail_root = 0;
+int avail_opt = 0;
+int max_core = 0;
+
+#if defined(__sun)
+#define SUN_NETWORK_DEVICE "/dev/hme"
+
+char solaris_release_string[128];
+
+struct iii_pinfo {
+ int pnum;
+ int pver;
+ int preq;
+ int sol;
+ int intel;
+ int seen;
+ char *pdesc;
+} iii_patches[] = {
+
+#include "sol_patches.c"
+/* sol_patches.c is a generated file
+ if you need to include patches not automatically
+ generated, please list them individually here
+*/
+
+ {0,0,0,0,0}
+};
+
+#endif
+
+#if defined(__hppa)
+struct pst_dynamic pst_dyn;
+struct pst_static pst_stt;
+struct pst_vminfo pst_vmm;
+
+struct iii_pinfo_hp {
+ char *qpk_name;
+ char *qpk_version;
+ char *qpk_desc;
+ int qpk_yr;
+ int qpk_mo;
+ int seen;
+} iii_qpk[] = {
+
+#include "hp_patches.c"
+/* hp_patches.c is a generated file
+ if you need to include patches not automatically
+ generated, please list them individually here
+*/
+ {NULL, NULL, NULL, 0, 0, 0}
+};
+
+static void hp_check_qpk(void);
+#endif
+
+#if defined(_AIX)
+
+static struct ClassElem CuAt_ClassElem[] = {
+ { "name",ODM_CHAR, 12,16, NULL,NULL,0,NULL ,-1,0},
+ { "attribute",ODM_CHAR, 28,16, NULL,NULL,0,NULL ,-1,0},
+ { "value",ODM_CHAR, 44,256, NULL,NULL,0,NULL ,-1,0},
+ { "type",ODM_CHAR, 300,8, NULL,NULL,0,NULL ,-1,0},
+ { "generic",ODM_CHAR, 308,8, NULL,NULL,0,NULL ,-1,0},
+ { "rep",ODM_CHAR, 316,8, NULL,NULL,0,NULL ,-1,0},
+ { "nls_index",ODM_SHORT, 324, 2, NULL,NULL,0,NULL ,-1,0},
+};
+
+static struct ClassElem fix_ClassElem[] = {
+ { "name",ODM_CHAR, 12,16, NULL,NULL,0,NULL ,-1,0},
+ { "abstract",ODM_CHAR, 28,60, NULL,NULL,0,NULL ,-1,0},
+ { "type",ODM_CHAR, 88,2, NULL,NULL,0,NULL ,-1,0},
+ { "filesets",ODM_VCHAR, 92,64, NULL,NULL,0,NULL ,-1,0},
+ { "symptom",ODM_VCHAR, 96,64, NULL,NULL,0,NULL ,-1,0},
+ };
+struct StringClxn fix_STRINGS[] = {
+ "fix.vc", 0,NULL,NULL,0,0,0
+ };
+
+#ifdef __64BIT__
+struct Class CuAt_CLASS[] = {
+ ODMI_MAGIC, "CuAt", 328, CuAt_Descs, CuAt_ClassElem, NULL,FALSE,NULL,NULL,0,0,NULL,0,"", 0,-ODMI_MAGIC
+};
+struct Class fix_CLASS[] = {
+ ODMI_MAGIC, "fix", 100, fix_Descs, fix_ClassElem, fix_STRINGS,FALSE,NULL,NULL,0,0,NULL,0,"", 0,-ODMI_MAGIC
+ };
+
+#else
+struct Class CuAt_CLASS[] = {
+ ODMI_MAGIC, "CuAt", sizeof(struct CuAt), CuAt_Descs, CuAt_ClassElem, NULL,FALSE,NULL,NULL,0,0,NULL,0,"", 0,-ODMI_MAGIC
+};
+struct Class fix_CLASS[] = {
+ ODMI_MAGIC, "fix", sizeof(struct fix), fix_Descs, fix_ClassElem, fix_STRINGS,FALSE,NULL,NULL,0,0,NULL,0,"", 0,-ODMI_MAGIC
+ };
+
+#endif
+
+void idds_aix_odm_get_cuat (char *query,char *buf)
+{
+ struct CuAt cuat,*cp;
+
+ cp = odm_get_first(CuAt_CLASS,query,&cuat);
+
+ if (cp == NULL || cp == (struct CuAt *)-1) {
+ if (flag_debug) {
+ printf("DEBUG : query of %s failed, error %d\n",query,odmerrno);
+ }
+ *buf = '\0';
+ return;
+ } else {
+ if (flag_debug) {
+ printf("DEBUG : query of %s resulted in %s\n",query,cuat.value);
+ }
+ }
+ strcpy(buf,cuat.value);
+}
+
+int idds_aix_odm_get_fix (char *query)
+{
+ struct fix fix,*cp;
+
+ cp = odm_get_first(fix_CLASS,query,&fix);
+
+ if (cp == NULL || cp == (struct fix *)-1) {
+ if (flag_debug) {
+ printf("DEBUG : query of %s failed, error %d\n",query,odmerrno);
+ }
+ return 0;
+ } else {
+ if (flag_debug) {
+ printf("DEBUG : query of %s resulted in data\n",query);
+ }
+ }
+ return 1;
+}
+
+#define AIX_CHECK_PATCH_CMD "/usr/bin/lslpp -c -L bos.rte.libpthreads bos.rte.libc"
+
+
+/* called once for each patch
+ * a is always "bos"
+ * b is "bos.rte.libpthreads:4.3.3.25: : :C:F:libpthreads Library"
+ */
+
+/* We assume the patch is in 4.3.3.1 and later. We don't check for AIX 5.0 */
+/* Since the next major release after 4.3.3 is 5.0, we assume there won't be a
+ * 4.10 or a 4.4.10.
+ */
+
+int aix_check_patch_bos(char *a,char *b)
+{
+ char *c;
+ char *d;
+ char *e;
+ int d3;
+ int d4;
+
+ c = strchr(b,':');
+ if (c == NULL) return 0;
+ *c = '\0';
+ c++;
+
+ d = strchr(c,':');
+ if (d != NULL) *d = '\0';
+
+ if (c[0] >= '5') {
+ /* AIX 5.x */
+ if (flag_debug) printf("DEBUG : %s is version 5 or later (%s)\n",
+ b,c);
+ return 0;
+ } else if (c[0] != '4') {
+ /* AIX 3.x or earlier */
+ printf("ERROR : Incorrect version of %s: %s\n\n",
+ b,c);
+ flag_os_bad = 1;
+ return 0;
+ } else if (c[2] >= '4') {
+ /* AIX 4.4 and later */
+ if (flag_debug) printf("DEBUG : %s is version 4.4 or later (%s)\n",
+ b,c);
+ return 0;
+ } else if (c[2] != '3') {
+ /* AIX 4.2 and earlier */
+ printf("ERROR : Incorrect version of %s: %s\n\n",
+ b,c);
+ flag_os_bad = 1;
+ return 0;
+ }
+
+ /* It's 4.3.x.x */
+
+ e = strchr(c+4,'.');
+ if (e != NULL) {
+ *e = '\0';
+ e++;
+ d4 = atoi(e);
+ } else {
+ d4 = 0;
+ }
+
+ d3 = atoi(c+4);
+
+ if (d3 > 4) {
+ if (flag_debug) printf("DEBUG : %s is version 4.3.4 or later (%s)\n",
+ b,c);
+ return 0;
+ } else if (d3 < 3) {
+ printf("ERROR : Incorrect version of %s: %s.%d; must be 4.3.3.1 or later\n\n",
+ b,c,d4);
+ flag_os_bad = 1;
+ return 0;
+ }
+ if (d4 >= 27) {
+ if (flag_debug) printf("DEBUG : %s is version 4.3.3.27 or later (%s.%d)\n",
+ b,c,d4);
+ } else if (d4 > 0) {
+ if (flag_debug) printf("ERROR : Incorrect version of %s: %s.%d; must be 4.3.3.27 or later\n\n",
+ b,c,d4);
+ } else { /* d4 = 0 */
+ printf("ERROR : Incorrect version of %s: %s.%d; must be 4.3.3.1 or later\n\n",
+ b,c,d4);
+ flag_os_bad = 1;
+ }
+
+ return 0;
+}
+
+struct iii_pio_parsetab ptb_aixpatch[] = {
+ {"bos", aix_check_patch_bos}
+};
+
+static void aix_check_patches(void)
+{
+ if (flag_debug) printf("DEBUG : %s\n",AIX_CHECK_PATCH_CMD);
+
+ if (iii_pio_procparse(AIX_CHECK_PATCH_CMD,
+ III_PIO_SZ(ptb_aixpatch),
+ ptb_aixpatch) == -1) {
+ perror(AIX_CHECK_PATCH_CMD);
+ }
+
+ if (flag_os_bad) {
+ printf("NOTICE : AIX APARs and fixes can be obtained from\n"
+ " http://service.software.ibm.com/cgi-bin/support/rs6000.support/downloads or \n");
+ printf(" http://techsupport.services.ibm.com/rs6k/ml.fixes.html\n\n");
+ }
+}
+
+static void idds_aix_pio_get_oslevel(char *osl)
+{
+ FILE *fp;
+ char *rp;
+ char rls[128];
+ int i;
+ int rm = 0;
+
+ osl[0] = '\0';
+
+ fp = popen("/usr/bin/oslevel","r");
+
+ if (fp == NULL) {
+ perror("/usr/bin/oslevel");
+ return;
+ }
+
+ if (fgets(osl,128,fp) == NULL) {
+ pclose(fp);
+ return;
+ }
+ pclose(fp);
+
+ rp = strchr(osl,'\n');
+ if (rp) *rp = '\0';
+
+ i = 0;
+ for (rp = osl;*rp;rp++) {
+ if (*rp != '.') {
+ rls[i] = *rp;
+ i++;
+ }
+ }
+ rls[i] = '\0';
+ /* rls now contains a value such as 4330 */
+
+ for (i = 1;i<99;i++) {
+ char rmtest[128];
+ char ifout[BUFSIZ];
+
+ sprintf(rmtest,"name=%s-%02d_AIX_ML",rls,i);
+
+ if (idds_aix_odm_get_fix(rmtest) == 0) break;
+ rm = i;
+ }
+
+ rp = osl + strlen(osl);
+ sprintf(rp,".%02d",rm);
+
+}
+
+#endif
+
+#if defined(__sun)
+
+static void ids_get_platform_solaris(char *buf)
+{
+ struct utsname u;
+ char sbuf[128];
+ FILE *fp;
+
+#if defined(sparc) || defined(__sparc)
+ int is_u = 0;
+
+ sbuf[0] = '\0';
+ sysinfo(SI_MACHINE,sbuf,128);
+
+ if (strcmp(sbuf,"sun4u") == 0) {
+ is_u = 1;
+ }
+
+ sbuf[0] = '\0';
+ sysinfo(SI_PLATFORM,sbuf,128);
+
+ sprintf(buf,"%ssparc%s-%s-solaris",
+ is_u ? "u" : "",
+ sizeof(long) == 4 ? "" : "v9",
+ sbuf);
+#else
+#if defined(i386) || defined(__i386)
+ sprintf(buf,"i386-unknown-solaris");
+#else
+ sprintf(buf,"unknown-unknown-solaris");
+#endif /* not i386 */
+#endif /* not sparc */
+
+ uname(&u);
+ if (isascii(u.release[0]) && isdigit(u.release[0])) strcat(buf,u.release);
+
+ fp = fopen("/etc/release","r");
+
+ if (fp != NULL) {
+ char *rp;
+
+ sbuf[0] = '\0';
+ fgets(sbuf,128,fp);
+ fclose(fp);
+ rp = strstr(sbuf,"Solaris");
+ if (rp) {
+ rp += 8;
+ while(*rp != 's' && *rp != '\0') rp++;
+ if (*rp == 's') {
+ strcpy(solaris_release_string,rp);
+ rp = strchr(solaris_release_string,' ');
+ if (rp) *rp = '\0';
+ strcat(buf,"_");
+ strcat(buf,solaris_release_string);
+ }
+ }
+ } else {
+ if (flag_debug) printf("DEBUG : No /etc/release file\n");
+ }
+}
+
+int sun_check_kern_arch(char *a,char *b)
+{
+ if (strcmp(b,"i86pc") == 0) {
+ flag_intel = 1;
+ if (flag_debug) printf("DEBUG : Kernel architecture: i86pc\n");
+ } else if (strcmp(b,"sun4u") == 0) {
+ if (flag_debug) printf("DEBUG : Kernel architecture: sun4u\n");
+ } else {
+ if (flag_html) printf("<P>\n");
+ printf("%s: The kernel architecture is %s. Netscape products are optimized\nfor the UltraSPARC architecture and will exhibit poorer performance on earlier\nmachines.\n\n","WARNING",b);
+ if (flag_html) printf("</P>\n");
+ flag_arch_bad = 1;
+ }
+ return 0;
+}
+
+/* This check is now obsolete. See solaris_check_mu() */
+int sun_check_release(char *a,char *b)
+{
+ if (flag_html) printf("<P>\n");
+ if (strcmp(b,"9") == 0 ||
+ strcmp(b,"5.9") == 0) {
+ if (flag_debug) printf("DEBUG : Release 5.9\n");
+ solaris_version = 29;
+ flag_solaris_9 = 1;
+ } else if (strcmp(b,"8") == 0 ||
+ strcmp(b,"5.8") == 0) {
+ if (flag_debug) printf("DEBUG : Release 5.8\n");
+ solaris_version = 28;
+ flag_solaris_8 = 1;
+ } else if (strcmp(b,"7") == 0 ||
+ strcmp(b,"5.7") == 0) {
+ if (flag_debug) printf("DEBUG : Release 5.7\n");
+ solaris_version = 27;
+ flag_solaris_7 = 1;
+ } else if (strcmp(b,"5.6") == 0) {
+ flag_solaris_26 = 1;
+ solaris_version = 26;
+ if (flag_debug) printf("DEBUG : Release 5.6\n");
+ } else if (strcmp(b,"5.5.1") == 0) {
+ if (client == 0) {
+ printf("%s: Solaris versions prior to 2.6 are not suitable for running Internet\nservices; upgrading to 2.6 or later is required.\n\n",
+ "ERROR ");
+ flag_os_bad = 1;
+ }
+ flag_solaris_251 = 1;
+ solaris_version = 251;
+ } else if (strcmp(b,"5.5") == 0) {
+ printf("%s: Solaris versions prior to 2.6 are not suitable for running Internet\nservices; upgrading to 2.6 or later is required.\n\n",
+ "ERROR ");
+ flag_os_bad = 1;
+ solaris_version = 25;
+ } else if (strcmp(b,"5.4") == 0) {
+ printf("%s: Solaris versions prior to 2.6 are not suitable for running Internet\nservices; upgrading to 2.6 is required.\n\n",
+ "ERROR ");
+ flag_os_bad = 1;
+ solaris_version = 24;
+ } else if (strcmp(b,"5.3") == 0) {
+ printf("%s: Solaris 2.3 is not supported.\n\n",
+ "ERROR ");
+ flag_os_bad = 1;
+ } else {
+ printf("%s: Solaris version %s, as reported by showrev -a, is unrecognized.\n\n",
+ "NOTICE ",b);
+ flag_os_bad = 1;
+ }
+ if (flag_html) printf("</P>\n");
+
+ return 0;
+}
+
+/* This check is now obsolete. See solaris_check_mu() instead. */
+int sun_check_kern_ver(char *a,char *b)
+{
+ char *rp,*pp;
+ int pw = 0;
+
+ if (flag_html) printf("<P>\n");
+ rp = strrchr(b,' ');
+ if (rp == NULL || rp == b) {
+ printf("NOTICE : Kernel version: \"%s\" not recognized.\n\n",b);
+ if (flag_html) printf("</P>\n");
+ return 0;
+ }
+ *rp = '\0';
+ rp++;
+ pp = strrchr(b,' ');
+ if (pp == 0) {
+ printf("NOTICE : Kernel version: \"%s\" not recognized.\n\n",b);
+ if (flag_html) printf("</P>\n");
+ return 0;
+ }
+ pp++;
+
+ if (strcmp(rp,"1997") == 0 ||
+ strcmp(rp,"1996") == 0) {
+ printf("%s: This kernel was built in %s %s. Kernel builds prior to\n"
+ "mid-1998 are lacking many tuning fixes, uprading is strongly recommended.\n\n","ERROR ",pp,rp);
+ pw = 1;
+ flag_os_bad = 1;
+ }
+
+ if (flag_solaris_26 && strcmp(rp,"1998") == 0) {
+ if (strncmp(pp,"Jan",3) == 0 ||
+ strncmp(pp,"Feb",3) == 0 ||
+ strncmp(pp,"Mar",3) == 0 ||
+ strncmp(pp,"Apr",3) == 0) {
+ printf("%s: This kernel was built in %s %s. Kernel builds prior to\n"
+ "mid-1998 are lacking many tuning fixes, uprading is strongly recommended.\n\n","WARNING",pp,rp);
+ pw = 1;
+ flag_os_bad = 1;
+ }
+ }
+
+ if (flag_debug && pw == 0) {
+ printf("DEBUG : Kernel build date %s %s\n",pp,rp);
+ }
+ if (flag_html) printf("</P>\n");
+
+ return 0;
+}
+
+int sun_check_patch(char *a,char *b)
+{
+ char *rp;
+ int pid = 0;
+ int pver = 0;
+ int i;
+
+ rp = strchr(b,'O');
+ if (rp == NULL) {
+ printf("%s: Cannot parse patch line %s\n","NOTICE ",b);
+ return 0;
+ }
+ *rp = '\0';
+ rp = strchr(b,'-');
+ if (b == NULL) {
+ printf("%s: Cannot parse patch line %s\n","NOTICE ",b);
+ }
+ *rp = '\0';
+ rp++;
+ pid = atoi(b);
+ pver = atoi(rp);
+
+ for (i = 0; iii_patches[i].pnum != 0; i++) {
+ if (iii_patches[i].pnum == pid) {
+ if (iii_patches[i].seen < pver) {
+ iii_patches[i].seen = pver;
+ }
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+int sun_check_etcsystem(void)
+{
+ FILE *fp;
+ char buf[8192];
+ int pp_set = -1;
+ int tchs = 0;
+
+ fp = fopen("/etc/system","r");
+
+ if (fp == NULL) {
+ perror("/etc/system");
+ return -1;
+ }
+ while(fgets(buf,8192,fp) != NULL) {
+ char *rp;
+ rp = strchr(buf,'\n');
+ if (rp) {
+ *rp = '\0';
+ }
+ if (buf[0] == '*') continue; /* comment */
+ if (strncmp(buf,"set",3) != 0) continue;
+ if (flag_debug) printf("DEBUG : saw %s in /etc/system\n",buf);
+ if (strstr(buf,"priority_paging") != NULL) {
+ rp = strchr(buf,'=');
+ if (rp == NULL) continue;
+ rp++;
+ while(isspace(*rp)) rp++;
+ if (*rp == '1') {
+ pp_set = 1;
+ } else {
+ pp_set = 0;
+ }
+ } else if (strstr(buf,"tcp:tcp_conn_hash_size") != NULL) {
+ rp = strchr(buf,'=');
+ if (rp == NULL) continue;
+ rp++;
+ while(isspace(*rp)) rp++;
+ tchs = atoi(rp);
+ }
+ }
+ fclose(fp);
+
+ /* ias tuning recommends setting tcp_conn_hash_size to 8192 XXX */
+
+ if (pp_set == 1) {
+ if (flag_debug) printf("DEBUG : saw priority_paging=1 in /etc/system\n");
+ } else if (flag_solaris_7) {
+ if (pp_set == 0) {
+ printf("NOTICE : priority_paging is set to 0 in /etc/system.\n\n");
+ } else {
+ printf("WARNING: priority_paging is not set to 1 in /etc/system. See Sun FAQ 2833.\n\n");
+ }
+ }
+
+
+}
+
+void sun_check_mu(void)
+{
+ if (solaris_release_string[0] == '\0') {
+ if (flag_debug) printf("DEBUG : No /etc/release line parsed\n");
+ return;
+ }
+
+ switch(solaris_version) {
+ case 26:
+ if (strcmp(solaris_release_string,"s297s_smccServer_37cshwp") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 2.6 FCS. Solaris 2.6\nMaintenance Update 2 has been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s297s_hw2smccDesktop_09") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 2.6 3/98. Solaris 2.6\nMaintenance Update 2 has been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s297s_hw3smccDesktop_09") == 0) {
+ if (flag_debug) printf("DEBUG : Solaris 2.6 5/98\n");
+ } else if (strcmp(solaris_release_string,"s297s_smccServer_37cshwp") == 0) {
+ if (flag_debug) printf("DEBUG : Solaris 2.6 MU2\n");
+ } else {
+ if (flag_debug) printf("DEBUG : Solaris 2.6 Unrecognized\n");
+ }
+ break;
+ case 27:
+ if (strcmp(solaris_release_string,"s998s_SunServer_21al2b") == 0) {
+ /* FCS */
+ printf("NOTICE : This machine appears to be running Solaris 7 FCS. Solaris 7 11/99\nhas been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s998s_u1SunServer_10") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 7 3/99. Solaris 7 11/99\nhas been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s998s_u2SunServer_09") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 7 5/99. Solaris 7 11/99\nhas been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s998s_u3SunServer_11") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 7 8/99. Solaris 7 11/99\nhas been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s998s_u4SunServer_10") == 0) {
+ if (flag_debug) printf("DEBUG : 11/99\n");
+ } else {
+ if (flag_debug) printf("DEBUG : Solaris 7 Unrecognized\n");
+ }
+ break;
+ case 28:
+ if (strcmp(solaris_release_string,"s28_27b") == 0) {
+ printf("ERROR : This machine appears to be running Solaris 8 Beta.\n\n");
+ } else if (strcmp(solaris_release_string,"s28_32d") == 0) {
+ printf("ERROR : This machine appears to be running Solaris 8 Beta Refresh.\n\n");
+ } else if (strcmp(solaris_release_string,"s28_38shwp2") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 8 FCS. Solaris 8 Update\n4 has been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s28s_u1wos_08") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 8 Update 1. Solaris 8\nUpdate 4 has been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s28_38shwp2") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 8 Maint Update 1.\nSolaris 8 Update 4 has been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s28s_u2wos_11b") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 8 Update 2. Solaris 8\nUpdate 4 has been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s28_38shwp2") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 8 Maint Update 2.\nSolaris 8 Update 4 has been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s28s_u3wos_08") == 0) {
+ printf("NOTICE : This machine appears to be running Solaris 8 Update 3. Solaris 8\nUpdate 4 has been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s28s_u4wos_03") == 0) {
+ printf("ERROR : This machine appears to be running Solaris 8 Update 4 BETA. Solaris 8\nUpdate 4 has been released subsequent to this.\n\n");
+ } else if (strcmp(solaris_release_string,"s28s_u4wos_08") == 0) {
+ if (flag_debug) printf("DEBUG : Solaris 8 Update 4 (4/01)\n\n");
+ } else if (strcmp(solaris_release_string,"s28s_u5wos_08") == 0) {
+ if (flag_debug) printf("DEBUG : Solaris 8 Update 5\n\n");
+ } else {
+ if (flag_debug) printf("DEBUG : Solaris 8 Unrecognized\n");
+ }
+ break;
+ case 29:
+ if (flag_debug) printf("DEBUG : Solaris 9 Unrecognized\n");
+ break;
+ default:
+ if (flag_debug) printf("DEBUG : Solaris Unrecognized\n");
+ /* probably pretty old */
+ break;
+ }
+
+}
+
+#endif
+
+int check_memsize(char *a,char *b)
+{
+ char *rp;
+ int mult = 1;
+
+ rp = strchr(b,' ');
+
+ if (rp == NULL) {
+ printf("%s: Cannot parse Memory size: line %s\n\n","NOTICE ",b);
+ return 0;
+ }
+ if (!isdigit(*b)) {
+ printf("%s: Cannot parse Memory size: line %s\n\n","NOTICE ",b);
+ return 0;
+ }
+
+ *rp = '\0';
+ rp++;
+ if (strcmp(rp,"Megabytes") == 0) {
+ } else if (strcmp(rp,"Gigabytes") == 0) {
+ mult = 1024;
+ } else {
+ printf("%s: Cannot parse Memory size: line %s %s\n\n","NOTICE ",b,rp);
+ return 0;
+ }
+ phys_mb = atoi(b) * mult;
+
+
+ return 0;
+}
+
+int check_swapsize(char *a,char *b)
+{
+ char *rp,*kp;
+ int used, avail;
+
+ rp = strchr(b,'=');
+
+ if (rp == NULL) {
+ printf("NOTICE : Cannot parse swap -s output: %s\n", b);
+ return 0;
+ }
+ rp++;
+ if (isspace(*rp)) rp++;
+ if (!(isdigit(*rp))) {
+ printf("NOTICE : Cannot parse swap -s output: %s\n", b);
+ return 0;
+ }
+ kp = strchr(rp,'k');
+ if (kp == NULL) {
+ printf("NOTICE : Cannot parse swap -s output: %s\n", b);
+ return 0;
+ }
+
+ *kp = '\0';
+ used = atoi(rp);
+ *kp = 'k';
+
+ rp = strchr(b,',');
+
+ if (rp == NULL) {
+ printf("NOTICE : Cannot parse swap -s output: %s\n", b);
+ return 0;
+ }
+ rp++;
+ if (isspace(*rp)) rp++;
+ if (!(isdigit(*rp))) {
+ printf("NOTICE : Cannot parse swap -s output: %s\n", b);
+ return 0;
+ }
+
+ kp = strchr(rp,'k');
+ if (kp == NULL) {
+ printf("NOTICE : Cannot parse swap -s output: %s\n", b);
+ return 0;
+ }
+ *kp = '\0';
+ avail = atoi(rp);
+
+ if (flag_debug) {
+ printf("DEBUG : swap used %dK avail %dK\n", used, avail);
+ }
+
+ swap_mb = (used+avail)/1024-(phys_mb*7/8);
+
+
+ return 0;
+}
+
+#if defined(__sun)
+
+int check_kthread(char *a,char *b)
+{
+ flag_mproc = 1;
+ return 0;
+}
+
+int check_tcpmaxlisten(char *a,char *b)
+{
+ if (flag_os_bad == 1) return 0;
+
+ if (client) return 0;
+
+ if (flag_html) printf("<P>\n");
+
+ if (isdigit(*b)) {
+ tcp_max_listen = atoi(b);
+ if (tcp_max_listen <= 1024) {
+ printf("%s: The kernel has been configured with a maximum of 1024 for the listen\nbacklog queue size. This will prevent it from being raised with ndd.\n","ERROR ");
+
+ if (flag_mproc == 0) {
+ printf("The following line should be added to the file /etc/init.d/inetinit:\n");
+ if (flag_html) printf("</P><PRE>\n");
+ printf("echo \"tcp_param_arr+14/W 0t65536\" | adb -kw /dev/ksyms /dev/mem\n");
+ printf("\n");
+ if (flag_html) printf("</PRE><P>\n");
+ } else {
+ printf("As this is a multiprocessor, contact your Solaris support representative for\ninformation on changing the parameter at tcp_param_arr+14, as documented in\nSun Security Bulletin #00136 section B.1.\n\n");
+ }
+
+ } else if (tcp_max_listen < 65536) {
+
+ printf("%s: The kernel has a configured limit of %d for the maximum listen\nbacklog queue size. Setting a value larger than this with ndd will not have\nan effect.\n","WARNING",tcp_max_listen);
+
+ if (flag_mproc == 0) {
+ printf("The value can be raised by adding the following line to the file\n/etc/init.d/inetinit:\n");
+
+ if (flag_html) printf("</P><PRE>\n");
+ printf("echo \"tcp_param_arr+14/W 0t65536\" | adb -kw /dev/ksyms /dev/mem\n");
+ if (flag_html) printf("</PRE><P>\n");
+ printf("\n\n");
+ }
+
+ } else {
+ if (flag_debug) printf("DEBUG : tcp_param_arr+0x14: %d\n",tcp_max_listen);
+ }
+
+ } else if (strcmp(b,"-1") == 0) {
+ /* OK I guess */
+ tcp_max_listen = 65535;
+
+ } else {
+ printf("NOTICE : tcp_param_arr+0x14: %s cannot be parsed\n\n", b);
+ }
+
+ if (flag_html) printf("</P>\n");
+
+ return 0;
+}
+
+struct iii_pio_parsetab ptb_showrev[] = {
+ {"Release",sun_check_release},
+ {"Kernel architecture",sun_check_kern_arch},
+ {"Kernel version",sun_check_kern_ver},
+ {"Patch",sun_check_patch}
+};
+
+struct iii_pio_parsetab ptb_adb[] = {
+ {" kernel thread at:",check_kthread},
+ {"tcp_param_arr+0x14",check_tcpmaxlisten}
+};
+
+#endif
+
+struct iii_pio_parsetab ptb_prtconf[] = {
+ {"Memory size",check_memsize}
+};
+
+struct iii_pio_parsetab ptb_swap[] = {
+ {"total",check_swapsize}
+};
+
+#if defined(IDDS_LINUX_INCLUDE)
+static void
+linux_check_release(void)
+{
+ FILE *fp;
+ char osl[128];
+ char *cmd = strdup("/bin/uname -r");
+
+ if (flag_html) printf("<P>\n");
+ if (flag_debug) printf("DEBUG : %s\n",cmd);
+ fp = popen(cmd,"r");
+
+ if (fp == NULL) {
+ perror("popen");
+ return;
+ }
+
+ if (fgets(osl,128,fp) == NULL) {
+ printf("WARNING: Cannot determine the kernel number.\n");
+ pclose(fp);
+ return;
+ }
+ pclose(fp);
+
+ if (flag_debug) {
+ printf("DEBUG : %s\n",osl);
+ }
+
+ if (atoi(strtok(osl, ".")) < 2) {
+ printf("ERROR: We support kernel version 2.4.7 and higher.\n\n");
+ flag_os_bad = 1;
+ return;
+ }
+ if (atoi(strtok(NULL, ".")) < 4) {
+ printf("ERROR: We support kernel version 2.4.7 and higher.\n\n");
+ flag_os_bad = 1;
+ return;
+ }
+ if (atoi(strtok(NULL, "-")) < 7) {
+ printf("ERROR: We support kernel version 2.4.7 and higher.\n\n");
+ flag_os_bad = 1;
+ return;
+ }
+}
+#endif /* IDDS_LINUX_INCLUDE */
+
+
+
+#if defined(__osf__)
+
+#ifndef SLS_BUFSIZ
+#define SLS_BUFSIZ 8192
+#endif
+
+static void ids_get_platform_tru64(char *buf)
+{
+ struct utsname u;
+ int r,start = 0;
+ unsigned long pt;
+ struct cpu_info cpu_info;
+ char platname[SLS_BUFSIZ];
+ char *sp;
+
+ r = getsysinfo(GSI_CPU_INFO,(caddr_t)&cpu_info,sizeof(struct cpu_info),&start,NULL);
+
+ start = 0;
+
+ r = getsysinfo(GSI_PLATFORM_NAME,(caddr_t)&platname[0],SLS_BUFSIZ,&start,NULL);
+
+ start = 0;
+
+ r = getsysinfo(GSI_PROC_TYPE,(caddr_t)&pt,sizeof(long),&start,NULL);
+
+ switch(pt & 0xff) {
+ default:
+ sprintf(buf,"alpha-");
+ break;
+ case EV4_CPU:
+ sprintf(buf,"alpha_ev4_21064_%dMhz-",cpu_info.mhz);
+ break;
+ case EV45_CPU:
+ sprintf(buf,"alpha_ev4.5_21064_%dMhz-",cpu_info.mhz);
+ break;
+ case EV5_CPU:
+ sprintf(buf,"alpha_ev5_21164_%dMHz-",cpu_info.mhz);
+ break;
+ case EV56_CPU:
+ sprintf(buf,"alpha_ev5.6_21164A_%dMHz-",cpu_info.mhz);
+ break;
+ case EV6_CPU:
+ sprintf(buf,"alpha_ev6_21264_%dMHz-",cpu_info.mhz);
+ break;
+ }
+
+ sp = buf+strlen(buf);
+
+ for (r = 0; platname[r] != '\0';r++) {
+ if (platname[r] == ' ' || platname[r] == '-') {
+ *sp = '_';
+ sp++;
+ } else {
+ *sp = platname[r];
+ sp++;
+ }
+ }
+
+ sprintf(sp,"-tru64_");
+
+ if (uname(&u) == 0) {
+ strcat(buf,u.release);
+ strcat(buf,"_");
+ strcat(buf,u.version);
+ }
+
+ /* XXX GSI_LMF see sys/lmf.h and sys/lmfklic.h */
+}
+
+/* returns number of k in swap area */
+static int idds_osf_get_swapk (void)
+{
+ int src,i;
+ struct swaptable *swtab;
+ int res = 0;
+
+ src = swapctl(SC_GETNSWP,NULL);
+ if (src < 1) {
+ return 0;
+ }
+
+ swtab = calloc(1,sizeof(int) + ((src+1) * sizeof(struct swapent)));
+ swtab->swt_n = src;
+ for (i = 0; i < src; i++) {
+ swtab->swt_ent[i].ste_path = calloc(1024,sizeof(char));
+ }
+
+ if (swapctl(SC_LIST,swtab) < 0) {
+ res = 0;
+ } else {
+ for (i = 0; i< src; i++) {
+ if (swtab->swt_ent[i].ste_flags & ST_INDEL) continue;
+ res += (swtab->swt_ent[i].ste_length / 2);
+ }
+ }
+
+ for (i = 0; i < src; i++) {
+ free(swtab->swt_ent[i].ste_path);
+ }
+ free(swtab);
+ return res;
+}
+
+
+int idds_osf_get_memk(void)
+{
+ int start = 0, physmem = 0,r;
+ r = getsysinfo(GSI_PHYSMEM,(caddr_t)&physmem,sizeof(physmem),&start,NULL);
+ if (r == -1) {
+ return 0;
+ }
+ return physmem;
+}
+
+#endif
+
+static void gen_tests (void)
+{
+#ifndef _WIN32
+ uid_t uid;
+#endif
+
+
+ if (flag_html) printf("<P>\n");
+
+#if defined(__sun)
+ if (flag_debug) printf("DEBUG : /usr/bin/showrev -a\n");
+
+ if (iii_pio_procparse("/usr/bin/showrev -a",
+ III_PIO_SZ(ptb_showrev),
+ ptb_showrev) == -1) {
+ perror("/usr/bin/showrev -a");
+ } else {
+ int i;
+ int pur = 0;
+
+ for (i = 0; iii_patches[i].pnum != 0; i++) {
+ if (iii_patches[i].sol == solaris_version &&
+ iii_patches[i].intel == flag_intel) {
+
+ if (iii_patches[i].seen >= iii_patches[i].pver) {
+ if (flag_debug) {
+ printf("DEBUG : Patch %d-%02d, %d-%02d required (%s)\n",
+ iii_patches[i].pnum,
+ iii_patches[i].seen,
+ iii_patches[i].pnum,
+ iii_patches[i].pver,
+ iii_patches[i].pdesc);
+ }
+ } else if (iii_patches[i].seen != 0) {
+ if (flag_html) printf("<P>\n");
+ if (iii_patches[i].preq == 1 || flag_quick == 0) {
+ printf("%s: Patch %d-%02d is present, but %d-%02d (%s) is a more recent version.\n\n",
+ iii_patches[i].preq ? "ERROR " : "NOTICE ",
+ iii_patches[i].pnum,
+ iii_patches[i].seen,
+ iii_patches[i].pnum,
+ iii_patches[i].pver,
+ iii_patches[i].pdesc);
+ pur++;
+ if (flag_carrier || iii_patches[i].preq) flag_os_bad = 1;
+ }
+ if (flag_html) printf("</P>\n");
+ } else {
+ if (flag_html) printf("<P>\n");
+ if (iii_patches[i].preq) {
+ printf("%s: Patch %d-%02d (%s) is required but not installed.\n\n",
+ "ERROR ",
+ iii_patches[i].pnum,
+ iii_patches[i].pver,
+ iii_patches[i].pdesc);
+ flag_os_bad = 1;
+ pur++;
+ } else {
+ if (flag_quick == 0) {
+ printf("%s: Patch %d-%02d (%s) is not installed.\n\n",
+ "NOTICE ",
+ iii_patches[i].pnum,
+ iii_patches[i].pver,
+ iii_patches[i].pdesc);
+ pur++;
+ }
+ }
+ if (flag_html) printf("</P>\n");
+ }
+
+ } else if (iii_patches[i].seen) {
+ if (flag_html) printf("<P>\n");
+ printf("%s: Patch %d-%d seen on Solaris %d (%s) but intended for\nSolaris %d %s.\n\n",
+ "WARNING",
+ iii_patches[i].pnum,
+ iii_patches[i].seen,
+ solaris_version,
+ flag_intel ? "(Intel)" : "",
+ iii_patches[i].sol,
+ iii_patches[i].intel ? "(Intel)" : "");
+ if (flag_html) printf("</P>\n");
+ pur++;
+ }
+
+ } /* for */
+
+ if (pur) {
+ printf("NOTICE : Solaris patches can be obtained from http://sunsolve.sun.com or your\nSolaris support representative. Solaris patches listed as required by the\nJRE are located at http://www.sun.com/software/solaris/jre/download.html or\ncan be obtained from your Solaris support representative.\n\n");
+ }
+
+ }
+
+ sun_check_mu();
+#endif
+
+#if defined(IDDS_LINUX_INCLUDE)
+ linux_check_release();
+#endif
+
+#if defined(_AIX)
+ aix_check_patches();
+#endif
+
+#if !defined(_WIN32)
+ if (access("/usr/sbin/prtconf",X_OK) == 0) {
+ if (flag_debug) printf("DEBUG : /usr/sbin/prtconf\n");
+ if (iii_pio_procparse("/usr/sbin/prtconf",
+ III_PIO_SZ(ptb_prtconf),
+ ptb_prtconf) == -1) {
+ perror("/usr/sbin/prtconf");
+ }
+ }
+#endif
+
+#if defined(__osf__)
+ phys_mb = (idds_osf_get_memk())/1024;
+#else
+#if defined(_AIX)
+ if (1) {
+ char buf[BUFSIZ];
+ unsigned long l;
+
+ idds_aix_odm_get_cuat("attribute=realmem",buf);
+
+ if (buf) {
+ phys_mb = atoi(buf);
+ phys_mb = (phys_mb /1024) * (PAGESIZE / 1024);
+ }
+
+ l = psdanger(0);
+ swap_mb = PAGESIZE/1024;
+ swap_mb = swap_mb * (l / 1024);
+ }
+#else
+#if defined(_SC_PHYS_PAGES)
+ if (1) {
+ int pk,l;
+
+ pk = sysconf(_SC_PAGESIZE);
+ pk /= 1024;
+ l = sysconf(_SC_PHYS_PAGES);
+ if (l < 0) l = 0;
+ phys_mb = (l * pk) / 1024;
+ }
+#else
+#if defined(__hppa)
+ hp_check_qpk();
+ if (pstat_getdynamic(&pst_dyn,sizeof(pst_dyn),1,0) == -1 ||
+ pstat_getstatic(&pst_stt,sizeof(pst_stt),1,0) == -1 ||
+ pstat_getvminfo(&pst_vmm,sizeof(pst_vmm),1,0) == -1) {
+ perror("pstat_getdynamic");
+ } else {
+ if (flag_debug) {
+ printf("DEBUG : Static info\n");
+ printf("DEBUG : Physical memory size %d\n",pst_stt.physical_memory);
+ printf("DEBUG : Page size %d\n",pst_stt.page_size);
+ printf("DEBUG : Max nfile %d\n",pst_stt.pst_max_nfile);
+
+ printf("DEBUG : Dynamic info\n");
+ printf("DEBUG : Physical memory size %d\n",pst_dyn.psd_rm);
+ printf("DEBUG : Virtual Memory size %d\n",pst_dyn.psd_vm);
+ printf("DEBUG : Physical memory size %d active\n",pst_dyn.psd_arm);
+ printf("DEBUG : Virtual Memory size %d active\n",pst_dyn.psd_avm);
+ printf("DEBUG : Processors %d\n",pst_dyn.psd_proc_cnt);
+
+ printf("DEBUG : VM Info\n");
+ printf("DEBUG : Pages on disk backing %d\n",pst_vmm.psv_swapspc_cnt);
+ printf("DEBUG : Max pages on disk backing %d\n",pst_vmm.psv_swapspc_max);
+ }
+ phys_mb = pst_stt.page_size / 1024;
+ phys_mb = phys_mb * (pst_stt.physical_memory / 1024);
+ swap_mb = pst_stt.page_size / 1024;
+ swap_mb = swap_mb * (pst_vmm.psv_swapspc_cnt / 1024);
+ }
+#else
+#if defined(IDDS_BSD_SYSCTL)
+ /* phys_mb from hw.physmem / 1048576 */
+ /* swap_mb from vm.stats.vm.v_page_count * v_page_size / 1048576 */
+#endif
+#endif
+#endif
+#endif
+#endif
+
+ if (flag_html) printf("<P>\n");
+
+ if (phys_mb != 0 && phys_mb < mem_min) {
+ printf("%s: Only %dMB of physical memory is available on the system. %dMB is the\nrecommended minimum. %dMB is recommended for best performance on large production system.\n\n","ERROR ",phys_mb,
+ mem_min, mem_rec);
+ flag_arch_bad = 1;
+ } else if (phys_mb != 0 && phys_mb < mem_rec) {
+ printf("%s: %dMB of physical memory is available on the system. %dMB is recommended for best performance on large production system.\n\n",
+ "WARNING",
+ phys_mb,mem_rec);
+ } else if (flag_debug) {
+ printf("DEBUG : Memory size %d\n",phys_mb);
+ }
+
+ if (flag_html) printf("</P>\n");
+
+#if !defined(_WIN32)
+ if (access("/usr/sbin/swap",X_OK) == 0) {
+ if (flag_debug) printf("DEBUG : /usr/sbin/swap -s\n");
+ if (iii_pio_procparse("/usr/sbin/swap -s",
+ III_PIO_SZ(ptb_swap),
+ ptb_swap) == -1) {
+ perror("/usr/sbin/swap -s");
+ }
+ }
+#endif
+
+#if defined(__osf__)
+ swap_mb = (idds_osf_get_swapk()) / 1024;
+#else
+#if defined(IDDS_LINUX_INCLUDE)
+ if (1) {
+ struct sysinfo linux_si;
+
+ if (sysinfo(&linux_si) == 0) {
+ swap_mb = linux_si.totalswap / 1048576;
+ }
+ }
+#endif
+#endif
+
+ if (client == 0 && swap_mb < 0) {
+ if (flag_html) printf("<P>\n");
+ printf("%s: There is less swap space than physical memory.\n\n",
+ "ERROR ");
+ if (flag_html) printf("</P>\n");
+
+ } else if (client == 0 && swap_mb && swap_mb < phys_mb) {
+#if defined(_AIX) || defined(__hppa) || defined(__sun)
+#else
+ if (flag_html) printf("<P>\n");
+ printf("%s: There is %dMB of physical memory but only %dMB of swap space.\n\n",
+ "ERROR ",
+ phys_mb,swap_mb);
+ if (flag_html) printf("</P>\n");
+#endif
+ } else {
+ if (flag_debug) printf("DEBUG : %d MB swap configured\n", swap_mb);
+ }
+
+#ifndef _WIN32
+ uid = getuid();
+ if (uid != 0) {
+ uid = geteuid();
+ }
+#endif
+
+#if defined(__sun)
+ if (uid != 0) {
+ if (flag_html) printf("<P>\n");
+ if (flag_quick == 0) {
+ printf("WARNING: This program should be run by the superuser to collect kernel\ninformation on the overriding maximum backlog queue size and IP tuning.\n\n");
+ }
+ flag_nonroot = 1;
+ if (flag_html) printf("</P>\n");
+ }
+#endif
+
+
+#if defined(__sun)
+ if (flag_quick == 0 && flag_nonroot == 0) {
+ if (flag_debug) printf("DEBUG : adb\n");
+ if (iii_pio_procparse("/usr/bin/echo \"tcp_param_arr+14/D\" | /usr/bin/adb -k /dev/ksyms /dev/mem",
+ III_PIO_SZ(ptb_adb),
+ ptb_adb) == -1) {
+ perror("adb");
+ }
+ }
+
+ sun_check_etcsystem();
+#endif
+
+#ifndef _WIN32
+ if (uid != 0) {
+ printf("\n");
+ }
+#endif
+
+ if (flag_html) printf("</P>\n");
+}
+
+
+
+#if defined(__sun) || defined(__hppa) || defined(IDDS_BSD_SYSCTL) || defined(IDDS_LINUX_SYSCTL)
+
+static int ndd_get_tcp (char *a,long *vPtr)
+{
+ char buf[8192];
+
+#if defined(__sun)
+ sprintf(buf,"/usr/sbin/ndd /dev/tcp %s",a);
+#else
+#if defined(__hppa)
+ sprintf(buf,"/usr/bin/ndd /dev/tcp %s",a);
+#else
+#if defined(IDDS_BSD_SYSCTL) || defined(IDDS_LINUX_SYSCTL)
+ sprintf(buf,"/sbin/sysctl -n %s",a);
+#else
+ sprintf(buf,"ndd /dev/tcp %s",a);
+#endif
+#endif
+#endif
+
+ if (flag_debug) printf("DEBUG : %s\n",buf);
+ if (iii_pio_getnum(buf,vPtr) == -1) {
+ if (flag_solaris_251) {
+ if (strcmp(a,"tcp_conn_req_max_q0") == 0 ||
+ strcmp(a,"tcp_conn_req_max_q") == 0 ||
+ strcmp(a,"tcp_slow_start_initial") == 0) {
+ return -1;
+ }
+ }
+
+ printf("NOTICE : %s failed\n",buf);
+ return -1;
+ }
+
+ return 0;
+}
+
+#endif
+
+#if defined(__sun)
+
+static int patch_get_ver(int n)
+{
+ int i;
+
+ for (i = 0;iii_patches[i].pnum != 0; i++) {
+ if (iii_patches[i].pnum == n) {
+ return iii_patches[i].seen;
+ }
+ }
+
+ return 0;
+}
+#endif
+
+#if defined(__osf__)
+
+int tru64_check_tcbhashsize(char *a,char *b)
+{
+ int i;
+
+ if (strcmp(b,"unknown attribute") == 0) {
+ printf("WARNING: TCP tuning parameters are missing.\n\n");
+ return 0;
+ }
+ i = atoi(b);
+
+ if (i < 32) {
+ printf("WARNING: The inet tuning parameter tcbhashsize is set too low (%d),\nand should be raised to between 512 and 1024.\n\n",i);
+ flag_tru64_tuning_needed = 1;
+ } else if (i < 512) {
+ printf("NOTICE : The inet tuning parameter tcbhashsize is set too low (%d),\nand should be raised to between 512 and 1024.\n\n",i);
+ flag_tru64_tuning_needed = 1;
+ } else {
+ if (flag_debug) printf("DEBUG : tcbhashsize %d\n",i);
+ }
+
+ return 0;
+}
+
+int tru64_check_present_smp(char *a,char *b)
+{
+ if (strcmp(b,"unknown attribute") == 0) {
+ printf("WARNING: If this is a multiprocessor system, additional tuning patches need\nto be installed, as sysconfig -q inet tuning parameter %s is missing.\n",
+ a);
+ printf("NOTICE : If this is a uniprocessor system, the above warning can be ignored.\n\n");
+ } else {
+ if (flag_debug) printf("DEBUG : %s %s\n", a, b);
+ }
+
+ return 0;
+}
+
+int tru64_check_msl(char *a,char *b)
+{
+ int i;
+
+ if (strcmp(b,"unknown attribute") == 0) {
+ printf("WARNING: TCP tuning parameters are missing.\n\n");
+ return 0;
+ }
+ i = atoi(b);
+
+ if (i >= 60) {
+ printf("NOTICE : If running in a LAN or private network, the inet tcp_msl value can be\nreduced from %d (%d seconds) to increase performance.\n\n",
+ i, i/2);
+ flag_tru64_tuning_needed = 1;
+ }
+
+ return 0;
+}
+
+int tru64_check_present_client(char *a,char *b)
+{
+ if (strcmp(b,"unknown attribute") == 0) {
+ printf("ERROR : This system is lacking necessary tuning patches. Upgrade to 4.0E\nor later is required.\n\n");
+ flag_os_bad = 1;
+ } else {
+ if (flag_debug) {
+ printf("DEBUG : %s %s\n",a,b);
+ }
+ }
+
+ return 0;
+}
+
+int tru64_check_conn(char *a,char *b)
+{
+ int i;
+
+ i = atoi(b);
+
+ if (strcmp(a,"somaxconn") == 0 && i && i < 32767) {
+ printf("NOTICE : Increasing the socket tuning parameter somaxconn from %d to 65500\n is recommended.\n\n",i);
+ flag_tru64_tuning_needed = 1;
+ }
+
+ if (flag_debug) printf("DEBUG : %s %s\n",a,b);
+
+ return 0;
+}
+
+int tru64_check_threads(char *a,char *b)
+{
+ int i;
+
+ i = atoi(b);
+
+ if (i < 512) {
+ printf("WARNING: The proc tuning parameter max-threads-per-user should be raised from\n%d to at least 512.\n\n",i);
+ flag_tru64_tuning_needed = 1;
+ } else {
+ if (flag_debug) printf("DEBUG : %s %s\n",a,b);
+ }
+
+ return 0;
+}
+
+struct iii_pio_parsetab ptb_sysconfig_inet[] = {
+ {"tcbhashsize ",tru64_check_tcbhashsize},
+ {"tcbhashnum ",tru64_check_present_smp},
+ {"ipqs ",tru64_check_present_smp},
+ {"tcp_msl ",tru64_check_msl},
+ {"ipport_userreserved_min ",tru64_check_present_client}
+};
+
+struct iii_pio_parsetab ptb_sysconfig_socket[] = {
+ {"sominconn ",tru64_check_conn},
+ {"somaxconn ",tru64_check_conn}
+};
+
+struct iii_pio_parsetab ptb_sysconfig_proc[] = {
+ {"max-threads-per-user ",tru64_check_threads}
+};
+
+static void sysconfig_tests (void)
+{
+ struct utsname u;
+
+ if (uname(&u) == 0) {
+ if ((u.release[0] == 'T' || u.release[0] == 'V') && u.release[1] == '5') {
+ if (flag_debug) printf("DEBUG : Tru64 UNIX %s %s\n",
+ u.release,u.version);
+ } else if (strcmp(u.release,"V4.0") == 0) {
+ int iv;
+
+ /* Digital UNIX 4.x */
+ iv = atoi(u.version);
+
+ if (iv < 564) {
+ printf("ERROR : Digital UNIX versions prior to 4.0D are not supported as they lack\nnecessary kernel tuning parameters. Upgrade to 4.0E or later.\n\n");
+ flag_tru64_40b = 1;
+ flag_os_bad = 1;
+ } else if (iv < 878) {
+ printf("WARNING: Tru64 UNIX versions prior to 4.0D require a patch to provide \noptimal Internet performance.\n\n");
+ flag_tru64_40b = 1;
+ } else {
+ if (flag_debug) printf("DEBUG : Digital UNIX %s %s\n",
+ u.release,u.version);
+ }
+
+ } else if (u.release[0] == 'V' && u.release[1] == '3') {
+ printf("ERROR : Digital UNIX versions prior to 4.0D are not supported as they lack\nnecessary kernel tuning parameters. Upgrade to 4.0E or later.\n\n");
+ flag_os_bad = 1;
+
+ } else {
+ printf("%s: Tru64 UNIX release %s is not recognized.\n",
+ "NOTICE ", u.release);
+ }
+ }
+
+ /* inet subsystem raise tcbhashsize from 32/512 to 1024 */
+ /* inet subsystem raise tcbhashnum to 16 if multiprocessor, also ipqs
+ * not on 4.0D */
+ /* inet subsystem lower tcp_msl from 60 (30 secs) if on LAN */
+ /* client: inet subsystem raise ipport_userreserved_min from 5000 to 65000
+ * requires E or later */
+ if (iii_pio_procparse("/sbin/sysconfig -q inet",
+ III_PIO_SZ(ptb_sysconfig_inet),
+ ptb_sysconfig_inet) == -1) {
+ perror("/sbin/sysconfig");
+ }
+
+ /* socket raise sominconn to 65535 */
+ /* socket subsystem raise somaxconn from 1024 to 32767 */
+ if (iii_pio_procparse("/sbin/sysconfig -q socket",
+ III_PIO_SZ(ptb_sysconfig_socket),
+ ptb_sysconfig_socket) == -1) {
+ perror("/sbin/sysconfig");
+ }
+
+
+ /* proc max-threads-per-user from 256 to 512 or 4096 */
+ if (iii_pio_procparse("/sbin/sysconfig -q proc",
+ III_PIO_SZ(ptb_sysconfig_proc),
+ ptb_sysconfig_proc) == -1) {
+ perror("/sbin/sysconfig");
+ }
+
+ if (1) {
+ printf("NOTICE : More information on tuning is available on the web from Compaq at\nhttp://www.unix.digital.com/internet/tuning.htm\n\n");
+ printf("NOTICE : Additional performance recommendations can be obtained from the\nsys_check kit from Compaq, located at the following web site:\nftp://ftp.digital.com/pub/DEC/IAS/sys_check/sys_check.html\n\n");
+ }
+}
+#endif
+
+#if defined(__hppa)
+
+#include <dirent.h>
+#define HP_PATCH_DIR "/var/adm/sw/products"
+
+char *mo_lookup[] =
+{
+ "January",
+ "February",
+ "March",
+ "April",
+ "May",
+ "June",
+ "July",
+ "August",
+ "September",
+ "October",
+ "November",
+ "December",
+ NULL
+};
+
+static int month_lookup(char *month)
+{
+ int i;
+
+ for (i = 0; mo_lookup[i]; i++)
+ {
+ if (!strcmp(month, mo_lookup[i]))
+ return i+1;
+ }
+}
+
+static void hp_check_index(char *index_path, char *desc, int yr, int mo)
+{
+ FILE *fp = fopen(index_path, "r");
+ char buf[BUFSIZ];
+ if (NULL == fp)
+ {
+ printf("ERROR: Failed to open Patch info file %s\n", index_path);
+ return;
+ }
+ while (fgets(buf, BUFSIZ, fp))
+ {
+ if (!strncmp(buf, "title", 5))
+ {
+ char *p;
+ char *datep = NULL;
+ if (p = strstr(buf, desc))
+ {
+ if (NULL != p)
+ {
+ /* found */
+ datep = strrchr(buf, ',');
+ if (!datep)
+ {
+ /* printf("WARNING: No date found: %s\n", datep);*/
+ continue;
+ }
+ datep++;
+ while (*datep == ' ' || *datep == '\t') datep++;
+ p = strchr(datep, ' ');
+ if (p)
+ {
+ char *q = p + 1;
+ while (*q == ' ' || *q == '\t') q++;
+ if (isdigit(*q))
+ {
+ char *qq;
+ int my_year;
+ for (qq = q; qq && *qq && isdigit(*qq); qq++) ;
+ if (qq && *qq)
+ *qq = '\0';
+ my_year = atoi(q);
+ if (my_year < yr)
+ {
+ printf("ERROR : %s, %s is older than the supported QPK of %s %d\n\n",
+ desc, datep, mo_lookup[mo-1], yr);
+ }
+ else if (my_year == yr)
+ {
+ int my_month;
+ *p = '\0';
+ my_month = month_lookup(datep);
+ *p = ' ';
+ if (my_month < mo)
+ {
+ printf("ERROR : %s, %s is older than the supported QPK of %s %d\n\n",
+ desc, datep, mo_lookup[mo-1], yr);
+ }
+#ifdef QPK_DEBUG
+ else
+ {
+ printf("NOTICE: %s: Date %s is NO older than %d/%d\n",
+ desc, datep, mo, yr);
+ }
+#endif
+ }
+#ifdef QPK_DEBUG
+ else
+ {
+ printf("NOTICE: %s: Date %s is NO older than %d/%d\n",
+ desc, datep, mo, yr);
+ }
+#endif
+ }
+ else
+ {
+ printf("WARNING: Bad formatted date: %s\n", datep);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ fclose(fp);
+}
+
+static void hp_check_qpk()
+{
+ char fbuf[MAXPATHLEN];
+ int i,pm= 0;
+ int not_su = 0;
+ int found = 0;
+
+ DIR *prod_dir = NULL;
+ struct dirent *dp = NULL;
+
+ if (access(HP_PATCH_DIR,X_OK) == -1) {
+ printf("\nWARNING : Only the superuser can check which patches are installed. You must\nrun dsktune as root to ensure the necessary patches are present. If required\npatches are not present, the server may not function correctly.\n\n");
+ not_su = 1;
+ return;
+ }
+
+ for (i = 0; iii_qpk[i].qpk_name; i++)
+ {
+
+ prod_dir = opendir(HP_PATCH_DIR);
+ if (!prod_dir)
+ {
+ printf("ERROR : Patch directory %s has a problem.\n\n", HP_PATCH_DIR);
+ return;
+ }
+ found = 0;
+ while ((dp = readdir(prod_dir)) != NULL)
+ {
+ int len = strlen(iii_qpk[i].qpk_name);
+ if (strncmp(dp->d_name, iii_qpk[i].qpk_name, len) == 0)
+ {
+ /* matched */
+ found=1;
+ sprintf(fbuf, "%s/%s/pfiles/INDEX", HP_PATCH_DIR, dp->d_name);
+ if (access(fbuf, R_OK) == -1)
+ {
+ printf("WARNING : Patch info file %s does not exist or not readable.\n\n", fbuf);
+ }
+ else
+ {
+ hp_check_index(fbuf, iii_qpk[i].qpk_desc, iii_qpk[i].qpk_yr, iii_qpk[i].qpk_mo);
+ }
+ }
+ }
+ if(found==0)
+ {
+ printf("ERROR : Patch %s (%s) was not found.\n\n",iii_qpk[i].qpk_name,iii_qpk[i].qpk_desc);
+ }
+ (void) closedir(prod_dir);
+ }
+}
+
+static void hp_pthreads_tests(void)
+{
+ unsigned long tmax,omax;
+ long cpu64;
+
+ cpu64 = sysconf(_SC_HW_32_64_CAPABLE);
+
+ if (_SYSTEM_SUPPORTS_LP64OS(cpu64) == 0) {
+ printf("WARNING: This system does not support 64 bit operating systems.\n\n");
+ } else {
+ if (flag_debug) printf("DEBUG : _SC_HW_32_64_CAPABLE 0x%x\n",cpu64);
+ }
+
+ tmax = sysconf(_SC_THREAD_THREADS_MAX);
+
+ if (tmax < 128) {
+ printf("WARNING: only %d threads are available in a process.\n", tmax);
+ printf("NOTICE : use sam Kernel Configuration Parameters to change max_thread_proc\n");
+ printf("and nkthreads as needed.\n\n");
+ } else {
+ if (flag_debug) printf("DEBUG : HP-UX max threads %ld\n", tmax);
+ }
+
+ /* XXX set ncallout (max number of pending timeouts ) to 128 + NPROC */
+
+
+ /* set maxfiles to at least 120 */
+ omax = sysconf(_SC_OPEN_MAX);
+
+ if (omax < 120) {
+ printf("WARNING: only %d files can be opened at once in a process.\n",omax);
+ printf("NOTICE : use sam Kernel Configuration Parameters to change maxfiles.\n");
+ } else {
+ if (flag_debug) printf("DEBUG : HP-UX maxfiles %ld\n", omax);
+ }
+
+}
+#endif
+
+#if defined(__sun)
+static void sun_check_network_device(void)
+{
+ int devfd;
+ char buf[8192];
+ long ls;
+
+ if (flag_intel || flag_arch_bad || flag_os_bad) return;
+
+ devfd = open(SUN_NETWORK_DEVICE,O_RDONLY);
+
+ if (devfd == -1) {
+ switch (errno) {
+
+ case EACCES:
+ if (flag_debug) printf("DEBUG : got EACCES opening %s\n",
+ SUN_NETWORK_DEVICE);
+ break;
+ case ENOENT:
+ if (flag_debug) printf("DEBUG : got ENOENT opening %s\n",
+ SUN_NETWORK_DEVICE);
+ break;
+ default:
+ if (flag_debug) printf("DEBUG : got %d opening %s\n",
+ errno,SUN_NETWORK_DEVICE);
+ }
+ return;
+ } else {
+ close(devfd);
+ }
+
+ sprintf(buf,"/usr/sbin/ndd %s link_speed",SUN_NETWORK_DEVICE);
+ if (flag_debug) printf("DEBUG : %s\n",buf);
+ if (iii_pio_getnum(buf,&ls) == -1) {
+ if (flag_debug) printf("DEBUG : %s link_speed variable not available\n",
+ SUN_NETWORK_DEVICE);
+ } else {
+ /* XXX look at link speed */
+ if (flag_debug) printf("DEBUG : %s link_speed is %d\n",
+ SUN_NETWORK_DEVICE,ls);
+ }
+}
+#endif
+
+#if defined(__sun) || defined(__hppa) || defined(IDDS_BSD_SYSCTL) || defined(IDDS_LINUX_SYSCTL)
+
+static void ndd_tests (void)
+{
+ if (flag_html) printf("<P>\n");
+
+#if defined(IDDS_LINUX_SYSCTL)
+ /* following linux sysctls are TBD:
+ net.ipv4.tcp_max_syn_backlog, net.ipv4.tcp_fin_timeout
+ tcp_retries2 and tcp_retries
+ */
+#endif
+
+#if !defined(IDDS_BSD_SYSCTL) && !defined(IDDS_LINUX_SYSCTL)
+ {
+ char *name_tcp_time_wait_interval;
+ if (!flag_solaris_26) {
+ name_tcp_time_wait_interval = NAME_TCP_TIME_WAIT_INTERVAL;
+ } else {
+ name_tcp_time_wait_interval = "tcp_close_wait_interval";
+ }
+
+ if (ndd_get_tcp(name_tcp_time_wait_interval, &ndd_tcp_time_wait_interval) == 0) {
+ if (ndd_tcp_time_wait_interval >= 240000) {
+ if (flag_html) printf("<P>\n");
+ printf("%s: The %s is set to %d milliseconds (%d seconds).\n"
+ "This value should be reduced to allow for more simultaneous connections\n"
+ "to the server.\n",
+ flag_carrier ? "ERROR " : "WARNING",
+ name_tcp_time_wait_interval,
+ ndd_tcp_time_wait_interval,
+ ndd_tcp_time_wait_interval/1000);
+#ifdef NAME_NDD_CFG_FILE
+ printf("A line similar to the following\nshould be added to the %s file:\n", NAME_NDD_CFG_FILE);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp %s %d\n\n", name_tcp_time_wait_interval, 30000);
+ if (flag_html) printf("</PRE><P>\n");
+#endif
+ if (flag_carrier) flag_os_bad = 1;
+ } else if (ndd_tcp_time_wait_interval < 10000) {
+ if (flag_html) printf("<P>\n");
+ printf("WARNING: The %s is set to %d milliseconds. Values below\n30000 may cause problems.\n\n",
+ name_tcp_time_wait_interval, ndd_tcp_time_wait_interval);
+ if (flag_html) printf("</P>\n");
+ } else {
+ if (flag_debug) {
+ printf("DEBUG : %s %d\n", name_tcp_time_wait_interval, ndd_tcp_time_wait_interval);
+ }
+ }
+ }
+ }
+
+#if defined(__sun)
+ if (client == 0) {
+ if (ndd_get_tcp("tcp_conn_req_max_q0",&ndd_tcp_conn_req_max_q0) == 0) {
+
+ if (ndd_tcp_conn_req_max_q0 < 1024) {
+ if (flag_html) printf("<P>\n");
+ printf("ERROR : The tcp_conn_req_max_q0 value is too low, %d.\n\n",
+ ndd_tcp_conn_req_max_q0);
+ if (flag_solaris_251) {
+ printf("ERROR : Patches %s and %s may need to be applied.\n\n",
+ flag_intel ? "103631-10" : "103630-13",
+ flag_intel ? "103581-18" : "103582-18");
+ }
+ if (flag_html) printf("</P>\n");
+ } else if (ndd_tcp_conn_req_max_q0 >= (flag_carrier ? 10240 : 1024)) {
+ if (flag_debug) {
+ printf("DEBUG : tcp_conn_req_max_q0 %d\n",
+ ndd_tcp_conn_req_max_q0);
+ }
+ } else {
+ if (flag_html) printf("<P>\n");
+ printf("WARNING: The tcp_conn_req_max_q0 value is currently %d, which will limit the\nvalue of listen backlog which can be configured. It can be raised by adding\nto /etc/init.d/inetinit, after any adb command, a line similar to:\n",
+ ndd_tcp_conn_req_max_q0);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp tcp_conn_req_max_q0 65536\n");
+ if (flag_html) printf("</PRE><P>\n");
+ if (tcp_max_listen == 1024) {
+ printf("Raising this to a value larger than 1024 may require that adb be used first\nto change the maximum setting.\n");
+ }
+ if (flag_html) printf("</P>\n");
+
+ printf("\n");
+ }
+
+ if (tcp_max_listen && ndd_tcp_conn_req_max_q0 > tcp_max_listen) {
+ if (flag_html) printf("<P>\n");
+ printf("WARNING: tcp_conn_req_max_q0 is larger than the kernel will allow.\n\n");
+ if (flag_html) printf("</P>\n");
+ }
+
+ } else {
+ if (flag_solaris_251) {
+ if (flag_html) printf("<P>\n");
+ printf("ERROR : Solaris tuning parameters were improved in patch %s for\nSolaris 2.5.1 which introduces a fix for the SYN flood attack. Installing\nthis patch is strongly recommended.\n\n",
+ flag_intel ? "103581-18" : "103582-18");
+ if (flag_html) printf("</P>\n");
+
+ }
+ }
+ }
+#endif
+
+ if (client == 0) {
+ int recommended_tcp_conn_req_max = 128;
+
+ if (ndd_get_tcp(NAME_TCP_CONN_REQ_MAX_Q, &ndd_tcp_conn_req_max_q) == 0) {
+ if (flag_html) printf("<P>\n");
+ if (ndd_tcp_conn_req_max_q < recommended_tcp_conn_req_max) {
+ printf("ERROR : The NDD %s value %d is lower than the recommended minimum, %d.\n\n",
+ NAME_TCP_CONN_REQ_MAX_Q, ndd_tcp_conn_req_max_q, recommended_tcp_conn_req_max);
+ if (flag_solaris_251) {
+ printf("ERROR : Patches %s and %s may need to be applied.\n\n",
+ flag_intel ? "103631-10" : "103630-13",
+ flag_intel ? "103581-18" : "103582-18");
+ }
+ } else if (ndd_tcp_conn_req_max_q >= ndd_tcp_conn_req_max_q0) {
+ if (flag_debug) {
+ printf("DEBUG : %s %d\n", NAME_TCP_CONN_REQ_MAX_Q, ndd_tcp_conn_req_max_q);
+ }
+ } else {
+ printf("NOTICE : The %s value is currently %d, which will limit the\nvalue of listen backlog which can be configured. ",
+ NAME_TCP_CONN_REQ_MAX_Q, ndd_tcp_conn_req_max_q);
+#ifdef NAME_NDD_CFG_FILE
+ printf("It can be raised by adding\nto %s, after any adb command, a line similar to:\n", NAME_NDD_CFG_FILE);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp %s %d\n", NAME_TCP_CONN_REQ_MAX_Q, ndd_tcp_conn_req_max_q0);
+ if (flag_html) printf("</PRE><P>\n");
+#endif
+ if (tcp_max_listen == 1024) {
+ printf("Raising this to a value larger than 1024 may require that adb be used first\nto change the maximum setting.\n");
+ }
+ printf("\n");
+ }
+ if (flag_html) printf("</P><P>\n");
+
+ if (tcp_max_listen && ndd_tcp_conn_req_max_q > tcp_max_listen) {
+ printf("WARNING: %s (value %d) is larger than the kernel will allow.\n\n", NAME_TCP_CONN_REQ_MAX_Q, ndd_tcp_conn_req_max_q);
+ }
+
+ if (flag_html) printf("</P><P>\n");
+
+ } else {
+ if (flag_solaris_251) {
+ if (flag_html) printf("</P><P>\n");
+ printf("ERROR : Solaris tuning parameters were improved in patch %s for\nSolaris 2.5.1 which introduces a fix for the SYN flood attack. Installing\nthis patch is strongly recommended.\n\n",
+ flag_intel ? "103581-18" : "103582-18");
+
+ if (flag_html) printf("</P><P>\n");
+ }
+ }
+ }
+#endif
+ /* end of Solaris/HP-only code */
+
+ if (client == 0) {
+ if (ndd_get_tcp(NAME_TCP_KEEPALIVE_INTERVAL, &ndd_tcp_keepalive_interval) == 0) {
+
+#if defined(IDDS_LINUX_SYSCTL)
+ ndd_tcp_keepalive_interval *= 1000; /* seconds to milliseconds */
+#endif
+
+ if (ndd_tcp_keepalive_interval) {
+ if (solaris_version == 25 || solaris_version == 24) {
+ if (flag_html) printf("</P><P>\n");
+ printf("ERROR : The %s should not be set on versions of Solaris\nprior to 2.6 as thery contain a bug that causes infinite transmission.\n\n",NAME_TCP_KEEPALIVE_INTERVAL);
+ if (flag_html) printf("</P><P>\n");
+ } else if (flag_solaris_251) {
+ if (flag_html) printf("</P><P>\n");
+ printf("WARNING: There may be a bug in Solaris 2.5.1 which causes infinite\nretransmission when the %s (%ld s) is set. As there is\nno known fix, upgrading to Solaris 2.6 or later is recommended.\n\n",
+ NAME_TCP_KEEPALIVE_INTERVAL, ndd_tcp_keepalive_interval/1000);
+ if (flag_html) printf("</P><P>\n");
+ } else {
+ if (ndd_tcp_keepalive_interval < 60000) {
+ if (flag_html) printf("</P><P>\n");
+ printf("NOTICE : The %s is set to %ld milliseconds\n(%ld seconds). This may cause excessive retransmissions in WAN\nenvironments.\n\n",
+ NAME_TCP_KEEPALIVE_INTERVAL,
+ ndd_tcp_keepalive_interval,
+ ndd_tcp_keepalive_interval/1000);
+ if (flag_html) printf("</P><P>\n");
+ } else if (ndd_tcp_keepalive_interval > 600000) {
+ if (flag_html) printf("</P><P>\n");
+ printf("NOTICE : The %s is set to %ld milliseconds\n(%ld minutes). This may cause temporary server congestion from lost\nclient connections.\n\n",
+ NAME_TCP_KEEPALIVE_INTERVAL,
+ ndd_tcp_keepalive_interval,
+ ndd_tcp_keepalive_interval / 60000);
+ if (flag_html) printf("</P><P>\n");
+#ifdef NAME_NDD_CFG_FILE
+ printf("A line similar to the following should be added to %s:\n", NAME_NDD_CFG_FILE);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp %s %d\n\n", NAME_TCP_KEEPALIVE_INTERVAL, 600000);
+ if (flag_html) printf("</PRE><P>\n");
+#endif
+ } else if (flag_debug) {
+ printf("DEBUG : %s %ld (%ld seconds)\n",
+ NAME_TCP_KEEPALIVE_INTERVAL,
+ ndd_tcp_keepalive_interval,
+ ndd_tcp_keepalive_interval / 1000);
+ }
+ }
+ } else {
+ if (flag_solaris_251) {
+ if (flag_html) printf("</P><P>\n");
+ printf("NOTICE : The %s is currently not set. Setting this value\nshould only be done on Solaris 2.6 or later, due to a bug in earlier versions\nof Solaris.\n\n",NAME_TCP_KEEPALIVE_INTERVAL);
+ if (flag_html) printf("</P><P>\n");
+ } else {
+ if (flag_html) printf("</P><P>\n");
+#ifdef NAME_NDD_CFG_FILE
+ printf("NOTICE : The %s is currently not set. This could result in\neventual server congestion. The interval can be set by adding the following\ncommand to %s:\n",NAME_TCP_KEEPALIVE_INTERVAL, NAME_NDD_CFG_FILE);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp %s 60000\n",NAME_TCP_KEEPALIVE_INTERVAL);
+ if (flag_html) printf("</PRE><P>\n");
+#endif
+ printf("\n");
+ }
+ }
+ }
+ }
+
+#if !defined(IDDS_LINUX_SYSCTL)
+ if (ndd_get_tcp("tcp_rexmit_interval_initial",
+ &ndd_tcp_rexmit_interval_initial) == 0) {
+ if (ndd_tcp_rexmit_interval_initial > 2000) {
+ if (flag_html) printf("</P><P>\n");
+ printf("NOTICE : The NDD tcp_rexmit_interval_initial is currently set to %ld\nmilliseconds (%ld seconds). This may cause packet loss for clients on\nSolaris 2.5.1 due to a bug in that version of Solaris. If the clients\nare not using Solaris 2.5.1, no problems should occur.\n\n",
+ ndd_tcp_rexmit_interval_initial,
+ ndd_tcp_rexmit_interval_initial/1000);
+ if (flag_html) printf("</P><P>\n");
+#ifdef NAME_NDD_CFG_FILE
+ if (client) {
+ printf("NOTICE : For testing on a LAN or high speed WAN, this interval can be reduced\n"
+ "by adding to %s file:\n", NAME_NDD_CFG_FILE);
+ } else {
+ printf("NOTICE : If the directory service is intended only for LAN or private \n"
+ "high-speed WAN environment, this interval can be reduced by adding to\n"
+ "%s file:\n", NAME_NDD_CFG_FILE);
+ }
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp tcp_rexmit_interval_initial 500\n\n");
+ if (flag_html) printf("</PRE><P>\n");
+#endif
+ } else {
+ if (flag_html) printf("</P><P>\n");
+ printf("NOTICE : The tcp_rexmit_interval_initial is currently set to %ld\n"
+ "milliseconds (%ld seconds). This may cause excessive retransmission on the\n"
+ "Internet.\n\n",
+ ndd_tcp_rexmit_interval_initial,
+ ndd_tcp_rexmit_interval_initial/1000);
+ if (flag_html) printf("</P><P>\n");
+ }
+ }
+#endif
+
+#if !defined(IDDS_LINUX_SYSCTL)
+ if (ndd_get_tcp("tcp_ip_abort_cinterval", &ndd_tcp_ip_abort_cinterval) == 0) {
+ if (ndd_tcp_ip_abort_cinterval > 10000) {
+ if (flag_html) printf("</P><P>\n");
+ printf("NOTICE : The NDD tcp_ip_abort_cinterval is currently set to %ld\n"
+ "milliseconds (%ld seconds). This may cause long delays in establishing\n"
+ "outgoing connections if the destination server is down.\n\n",
+ ndd_tcp_ip_abort_cinterval,
+ ndd_tcp_ip_abort_cinterval/1000);
+ if (flag_html) printf("</P><P>\n");
+#ifdef NAME_NDD_CFG_FILE
+ printf("NOTICE : If the directory service is intended only for LAN or private \n"
+ "high-speed WAN environment, this interval can be reduced by adding to\n"
+ "%s file:\n", NAME_NDD_CFG_FILE);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp tcp_ip_abort_cinterval 10000\n\n");
+ if (flag_html) printf("</PRE><P>\n");
+#endif
+ }
+ }
+ if (ndd_get_tcp("tcp_ip_abort_interval", &ndd_tcp_ip_abort_interval) == 0) {
+ if (ndd_tcp_ip_abort_cinterval > 60000) {
+ if (flag_html) printf("</P><P>\n");
+ printf("NOTICE : The NDD tcp_ip_abort_interval is currently set to %ld\nmilliseconds (%ld seconds). This may cause long delays in detecting\nconnection failure if the destination server is down.\n\n",
+ ndd_tcp_ip_abort_cinterval,
+ ndd_tcp_ip_abort_cinterval/1000);
+ if (flag_html) printf("</P><P>\n");
+#ifdef NAME_NDD_CFG_FILE
+ printf("NOTICE : If the directory service is intended only for LAN or private \nhigh-speed WAN environment, this interval can be reduced by adding to\n%s:\n", NAME_NDD_CFG_FILE);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp tcp_ip_abort_interval 60000\n\n");
+ if (flag_html) printf("</PRE><P>\n");
+#endif
+ }
+ }
+#endif
+
+#if defined(__sun)
+ if (ndd_get_tcp("tcp_strong_iss",
+ &ndd_tcp_strong_iss) == 0) {
+ switch(ndd_tcp_strong_iss) {
+ case 0:
+ if (flag_debug) printf("DEBUG : tcp_strong_iss 0\n");
+ break;
+ case 1:
+ if (flag_debug) printf("DEBUG : tcp_strong_iss 1\n");
+ printf("NOTICE : The TCP initial sequence number generation is not based on RFC 1948.\nIf this directory service is intended for external access, add the following\nto /etc/init.d/inetinit:\n");
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp tcp_strong_iss 2\n\n");
+ if (flag_html) printf("</PRE><P>\n");
+ break;
+ case 2:
+ if (flag_debug) printf("DEBUG : tcp_strong_iss 2\n");
+ break;
+ }
+ } else {
+ if (flag_debug) printf("DEBUG : tcp_strong_iss not found\n");
+ }
+#endif
+
+ /* Linux uses net.ipv4.ip_local_port_range = 1024 4999 */
+#if !defined(IDDS_LINUX_SYSCTL)
+ if (ndd_get_tcp(NAME_TCP_SMALLEST_ANON_PORT,
+ &ndd_tcp_smallest_anon_port) == 0) {
+ if (ndd_tcp_smallest_anon_port >= 32768) {
+ int aport = 65536-ndd_tcp_smallest_anon_port;
+
+ if (flag_html) printf("</P><P>\n");
+ printf("%s: The NDD %s is currently %ld. This allows a\nmaximum of %ld simultaneous connections. ",
+ (flag_carrier || aport <= 16384) ? "ERROR " : "NOTICE ",
+ NAME_TCP_SMALLEST_ANON_PORT,
+ ndd_tcp_smallest_anon_port,
+ 65536 - ndd_tcp_smallest_anon_port);
+ if (flag_carrier) flag_os_bad = 1;
+#ifdef NAME_NDD_CFG_FILE
+ printf("More ports can be made available by\nadding a line to %s:\n", NAME_NDD_CFG_FILE);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp tcp_smallest_anon_port 8192\n");
+ if (flag_html) printf("</PRE><P>\n");
+#endif
+ printf("\n");
+ } else {
+ if (flag_debug) {
+ printf("DEBUG : %s %ld\n", NAME_TCP_SMALLEST_ANON_PORT,
+ ndd_tcp_smallest_anon_port);
+ }
+ }
+ }
+#endif
+
+#if defined(__sun)
+ if (ndd_get_tcp("tcp_slow_start_initial",&ndd_tcp_slow_start_initial) == 0) {
+ if (ndd_tcp_slow_start_initial == 2 || ndd_tcp_slow_start_initial == 4) {
+ if (flag_debug) printf("DEBUG : tcp_slow_start_initial %ld\n",
+ ndd_tcp_slow_start_initial);
+ } else if (ndd_tcp_slow_start_initial == 1) {
+ if (client == 0) {
+ if (flag_html) printf("</P><P>\n");
+ printf("NOTICE : tcp_slow_start_initial is currently 1. If clients are running on\nWindows TCP/IP stack, improved performance may be obtained by changing this\nvalue to 2.");
+
+ printf("This line can be added to the /etc/init.d/inetinit file:\n");
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp tcp_slow_start_initial 2\n");
+ if (flag_html) printf("</PRE><P>\n");
+ printf("\n");
+ }
+ } else {
+ printf("NOTICE : Unrecognized tcp_slow_start_initial value %ld\n\n",
+ ndd_tcp_slow_start_initial);
+ }
+
+
+ } else {
+ if (flag_solaris_251) {
+ int cpv;
+
+ cpv = patch_get_ver(flag_intel ? 103581: 103582);
+
+ if (flag_html) printf("</P><P>\n");
+ printf("ERROR : Solaris tuning parameters were improved in patch %s for\nSolaris 2.5.1 which introduces the tcp_slow_start_initial variable. Installing\n%spatch is strongly recommended.\n\n",
+ flag_intel ? "103581-15" : "103582-15",
+ cpv == 0 ? "this or a later version of this " : "a later version of this ");
+ if (flag_html) printf("</P><P>\n");
+ }
+ }
+#endif
+
+#if defined(IDDS_BSD_SYSCTL)
+ if (1) {
+ if (ndd_get_tcp("net.inet.tcp.delayed_ack",&ndd_tcp_deferred_ack_interval) == 0) {
+ if (ndd_tcp_deferred_ack_interval > 0) {
+ printf("WARNING: net.inet.tcp.delayed_ack is currently set. This will\ncause FreeBSD to insert artificial delays in the LDAP protocol. It should\nbe reduced during load testing.\n");
+ } else {
+ if (flag_debug) printf("DEBUG : ndd /dev/tcp tcp_deferred_ack_interval %ld\n", ndd_tcp_deferred_ack_interval);
+ }
+ }
+ }
+#endif
+
+#if defined(__sun) || defined(__hppa)
+ if (1) {
+ if (ndd_get_tcp("tcp_deferred_ack_interval",&ndd_tcp_deferred_ack_interval) == 0) {
+ if (ndd_tcp_deferred_ack_interval > 5) {
+ printf("%s: tcp_deferred_ack_interval is currently %ld milliseconds. This will\ncause the operating system to insert artificial delays in the LDAP protocol. It should\nbe reduced during load testing.\n",
+ flag_carrier ? "ERROR " : "WARNING",
+ ndd_tcp_deferred_ack_interval);
+ if (flag_carrier) flag_os_bad = 1;
+#ifdef NAME_NDD_CFG_FILE
+ printf("This line can be added to the %s file:\n", NAME_NDD_CFG_FILE);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ndd -set /dev/tcp tcp_deferred_ack_interval 5\n");
+ if (flag_html) printf("</PRE><P>\n");
+#endif
+ printf("\n");
+ } else {
+ if (flag_debug) printf("DEBUG : ndd /dev/tcp tcp_deferred_ack_interval %ld\n", ndd_tcp_deferred_ack_interval);
+ }
+ }
+ }
+#endif
+
+ /* must be root to see
+ * ip_forward_src_routed, ip_forward_directed_broadcasts,
+ * ip_forwarding XXX
+ */
+
+#if defined(__sun)
+ sun_check_network_device();
+#endif
+
+#if !defined(IDDS_LINUX_SYSCTL)
+ if (hpux_ndd_change_needed) {
+ printf("NOTICE : ndd settings can be placed in /etc/rc.config.d/nddconf\n\n");
+ }
+#endif
+
+ if (flag_html) printf("</P>\n");
+
+}
+
+#endif
+
+static int get_disk_avail(char *dir)
+{
+
+#if defined(__sun)
+ char cmd[8192];
+ FILE *fp;
+ char buf[8192];
+
+ if (client) return 0;
+
+ sprintf(cmd,"df -b %s",dir);
+
+ if (flag_debug) printf("DEBUG : %s\n",cmd);
+ fp = popen(cmd,"r");
+
+ if (fp == NULL) {
+ perror("popen");
+ return -1;
+ }
+
+ while (fgets(buf,8192,fp) != NULL) {
+ char *rp;
+ int i;
+
+ rp = strchr(buf,'\n');
+
+ if (rp) {
+ *rp = '\0';
+ }
+
+ if (strncmp(buf,"Filesystem",10) == 0) {
+ continue;
+ }
+ if (strncmp(buf,"df: ",4) == 0) {
+ printf("ERROR : %s\n\n", buf);
+ fclose(fp);
+ return -1;
+ }
+ rp = strchr(buf,':');
+ if (rp) {
+ *rp = '\0';
+ if (flag_html) printf("<P>\n");
+ printf("ERROR : %s partition is on file system mounted from %s, not local.\n\n",dir,buf);
+ if (flag_html) printf("</P>\n");
+ fclose(fp);
+ return -1;
+ }
+
+ rp = strchr(buf,' ');
+ if (rp == NULL) {
+ rp = strchr(buf,'\t');
+ }
+ if (rp == NULL) continue;
+
+ while(isspace(*rp)) rp++;
+
+ if (!isdigit(*rp)) {
+ continue;
+ }
+ i = atoi(rp);
+ fclose(fp);
+ return (i / 1024);
+ }
+ fclose (fp);
+#else
+#if defined(IDDS_HAVE_STATVFS)
+ struct statvfs vfs;
+
+ if (statvfs(dir,&vfs) == 0) {
+ return ((vfs.f_bfree * (vfs.f_bsize / 1024)) / 1024);
+ }
+#else
+#if defined(IDDS_LINUX_INCLUDE)
+ struct statfs sfs;
+
+ if (statfs(dir,&sfs) == 0) {
+ return ((sfs.f_bfree * (sfs.f_bsize / 1024)) / 1024);
+ }
+#else
+#if defined(_WIN32)
+ /* could use GetDiskFreeSpaceEx */
+#endif
+#endif
+#endif
+#endif
+ return -1;
+}
+
+/* return 0 if fsmnt is a longer subset of reqdir than mntbuf */
+static int mntdir_matches(char *reqdir,int reqlen,char *fsmnt,char *mntbuf)
+{
+ int cml;
+ int pml;
+
+ cml = strlen(fsmnt);
+ pml = strlen(mntbuf);
+
+ /* incoming file system is 'below' */
+ if (reqlen < cml) {
+ if (flag_debug) printf("DEBUG : mntdir_matches want %s < input %s\n",
+ reqdir, fsmnt);
+ return -1;
+ }
+
+ if (reqlen == cml && strcmp(reqdir,fsmnt) == 0) {
+ /* exact match */
+ if (flag_debug) printf("DEBUG : reqlen %d == cml %d\n", reqlen, cml);
+ strcpy(mntbuf,fsmnt);
+ return 0;
+ }
+
+ /* assert reqlen >= cml */
+
+ if (strncmp(fsmnt,reqdir,cml) != 0) {
+ if (flag_debug) printf("DEBUG : fsmnt %s != reqdir %s\n", fsmnt, reqdir);
+ return -1;
+ }
+
+ if (reqdir[cml] != '/' && cml > 1) {
+ if (flag_debug) printf("DEBUG : fsmnt %s: reqdir %s is %c not / \n",
+ fsmnt, reqdir, reqdir[cml]);
+ return -1;
+ }
+
+ if (pml > cml) {
+ if (flag_debug) printf("DEBUG : pml %d > cml %d\n", pml, cml);
+ return -1;
+ }
+
+ if (flag_debug) printf("DEBUG : replacing %s with %s\n", mntbuf, fsmnt);
+ strcpy(mntbuf,fsmnt);
+
+ return 0;
+}
+
+/* check that the file system has largefiles on HP */
+
+static int check_fs_options(char *reqdir,char mntbuf[MAXPATHLEN])
+{
+#if defined(IDDS_MNTENT_DIRNAME)
+ FILE *fp = NULL;
+ int found = -1;
+ int any_found = 0;
+ int reqlen = strlen(reqdir);
+ char optbuf[BUFSIZ];
+
+ if (client == 1) return -1;
+
+ mntbuf[0] = '\0';
+ optbuf[0] = '\0';
+
+#if defined(IDDS_MNTENT_MNTTAB)
+ fp = fopen(IDDS_MNTENT_MNTTAB,"r");
+
+ if (fp == NULL) {
+ perror(IDDS_MNTENT_MNTTAB);
+ return -1;
+ }
+#endif
+
+ while(1) {
+ struct IDDS_MNTENT *mep;
+
+#if defined(__sun)
+ struct IDDS_MNTENT m;
+
+ mep = &m;
+ if (getmntent(fp,mep) != 0) break;
+#else
+#if defined(__hppa) || defined(IDDS_LINUX_INCLUDE)
+ mep = getmntent(fp);
+ if (mep == NULL) break;
+#else
+#if !defined(IDDS_MNTENT_MNTTAB)
+ /* not quite the same, but Tru64 and AIX don't have getmntent */
+ mep = getfsent();
+ if (mep == NULL) break;
+#else
+ break;
+#endif
+#endif
+#endif
+
+ if (mntdir_matches(reqdir,reqlen,mep->IDDS_MNTENT_DIRNAME,mntbuf) == 0) {
+ found = 0;
+#if defined(IDDS_MNTENT_OPTIONS)
+ strcpy(optbuf,mep->IDDS_MNTENT_OPTIONS);
+#else
+ strcpy(optbuf,"");
+#endif
+
+ if (flag_debug) printf("DEBUG : file system %s matches %s with options %s\n",
+ mntbuf, reqdir, optbuf);
+ } else {
+#if defined(IDDS_MNTENT_OPTIONS)
+ if (strstr(mep->IDDS_MNTENT_OPTIONS,"nolargefiles") != NULL) {
+
+ } else if (strstr(mep->IDDS_MNTENT_OPTIONS,"largefiles") != NULL) {
+ if (flag_debug) printf("DEBUG : file system %s allows largefiles\n",
+ mep->IDDS_MNTENT_DIRNAME);
+ any_found++;
+ }
+#endif
+ }
+
+ }
+
+ if (fp) fclose (fp);
+
+#if defined(__hppa)
+ if (found == 0) {
+ int largefile_missing = 0;
+
+ if (strstr(optbuf,"nolargefiles") != NULL) {
+ largefile_missing = 1;
+ } else if (strstr(optbuf,"largefiles") == NULL) {
+ largefile_missing = 1;
+ }
+
+ if (largefile_missing) {
+ if (any_found == 0) {
+ printf("WARNING: largefiles option is not present on mount of %s, \nfiles may be limited to 2GB in size.\n\n", mntbuf);
+ } else {
+ printf("WARNING: largefiles option is not present on mount of %s, \nalthough it is present on other file systems. Files on the %s\nfile system will be limited to 2GB in size.\n\n", mntbuf, mntbuf);
+ }
+ }
+ } else {
+ if (any_found == 0) {
+ printf("WARNING: no file system mounted with largefiles option.\n\n");
+ }
+ }
+#endif
+
+
+ return found;
+
+#else
+ return -1;
+#endif
+}
+
+static void check_disk_quota(char mntbuf[MAXPATHLEN])
+{
+#if defined(__sun)
+ char qfname[MAXPATHLEN];
+ struct stat sbuf;
+
+ sprintf(qfname,"%s/quotas",mntbuf);
+ if (stat(qfname,&sbuf) == 0 || errno == EACCES) {
+ printf("NOTICE : quotas are present on file system %s.\n\n",mntbuf);
+ }
+
+#endif
+}
+
+static void disk_tests(void)
+{
+#ifndef _WIN32
+ struct rlimit r;
+#endif
+ char mntbuf[MAXPATHLEN];
+
+ if (client) return;
+
+ avail_root = get_disk_avail("/");
+ if (flag_debug) printf("DEBUG : %dMB available on /\n",avail_root);
+
+ if (flag_html) printf("<P>\n");
+
+ if (avail_root != -1 && avail_root < 2) {
+ if (flag_html) printf("</P><P>\n");
+ printf("ERROR : / partition is full\n");
+ flag_os_bad = 1;
+ if (flag_html) printf("</P><P>\n");
+ }
+
+#if defined(RLIMIT_CORE)
+ getrlimit(RLIMIT_CORE,&r);
+ if (flag_debug) printf("DEBUG : RLIMIT_CORE is %ld, %ld\n", r.rlim_cur, r.rlim_max);
+ if (r.rlim_cur == -1 || r.rlim_cur >= 2147483647) {
+ if (swap_mb <2048) {
+ max_core = swap_mb;
+ } else {
+ max_core = 2048;
+ }
+ } else {
+ max_core = r.rlim_max / (1024*1024);
+ }
+ if (phys_mb) {
+ if (max_core > (phys_mb + swap_mb)) {
+ max_core = phys_mb + swap_mb;
+ }
+ }
+#endif
+
+ if (avail_root != -1 && max_core > avail_root && flag_quick == 0) {
+ if (flag_html) printf("</P><P>\n");
+ printf("NOTICE : / partition has less space available, %dMB, than the largest \nallowable core file size of %dMB. A daemon process which dumps core could\ncause the root partition to be filled.\n\n",
+ avail_root, max_core);
+ if (flag_html) printf("</P><P>\n");
+ }
+
+ if (install_dir[0] == '\0') {
+#if defined(_WIN32)
+ /* TBD */
+#else
+ if (access("/usr/netscape",X_OK) == 0) {
+ sprintf(install_dir,"/usr/netscape");
+ } else {
+ sprintf(install_dir,"/opt");
+ }
+#endif
+ }
+
+ if (check_fs_options(install_dir,mntbuf) == 0) {
+
+ } else {
+ strcpy(mntbuf,install_dir);
+ }
+
+ avail_opt = get_disk_avail(mntbuf);
+ if (flag_debug) printf("DEBUG : %dMB available on %s\n",
+ avail_opt,mntbuf);
+
+ if (avail_opt != -1) {
+ if (flag_html) printf("</P><P>\n");
+ if (avail_opt < 2) {
+ printf("ERROR : %s partition is full.\n",mntbuf);
+ } else if (avail_opt < 100) {
+ printf("NOTICE : %s partition has only %dMB free.\n",mntbuf,avail_opt);
+ }
+ if (flag_html) printf("</P><P>\n");
+ }
+
+
+ check_disk_quota(mntbuf);
+
+ if (flag_html) printf("</P>\n");
+
+}
+
+#if 0
+/* The function hasn't been used. #if 0 to get rid of compiler warning */
+static int get_disk_usage(char *s)
+{
+#ifndef _WIN32
+ char cmd[8192];
+ char buf[8192];
+ FILE *fp;
+ int i;
+
+ sprintf(cmd,"du -s -k %s",s);
+ if (flag_debug) printf("DEBUG : du -s -k %s\n",s);
+ fp = popen(cmd,"r");
+ if (fp == NULL) {
+ perror("du");
+ return 0;
+ }
+ buf[0] = '\0';
+ fgets(buf,8192,fp);
+ fclose (fp);
+ i = atoi(buf);
+ return (i / 1024);
+#else
+ return 0;
+#endif
+}
+#endif
+
+static void check_mem_size(int ro,char *rn)
+{
+#ifndef _WIN32
+ struct rlimit r;
+ int rprev;
+ long m_mb;
+ int m_change_needed = 0;
+
+ getrlimit(ro,&r);
+ rprev = r.rlim_cur;
+ r.rlim_cur = r.rlim_max;
+ setrlimit(ro,&r);
+ getrlimit(ro,&r);
+
+ if (flag_debug) printf("DEBUG : %s (%d) max %d prev %d.\n",
+ rn, ro, (int)r.rlim_cur, rprev);
+
+#if defined(__alpha) || defined(__ALPHA)
+ if (r.rlim_cur <= 0L) return;
+#endif
+ if (r.rlim_cur <= 0) return;
+
+ m_mb = r.rlim_cur / 1048576;
+
+ if (m_mb < mem_min) { /* 64 MB */
+ printf("ERROR : processes are limited by %s to %ld MB in size.\n",
+ rn, m_mb);
+ m_change_needed = 1;
+ flag_os_bad = 1;
+ } else if (m_mb <= mem_rec) {
+ printf("WARNING: processes are limited by %s to %ld MB in size.\n",
+ rn, m_mb);
+ m_change_needed = 1;
+ }
+
+ if (m_change_needed) {
+#if defined(__hppa)
+ printf("NOTICE : use sam Kernel Configuration Parameters to change maxdsiz parameter.\n");
+#endif
+ printf("\n");
+ }
+
+#endif
+}
+
+static void limits_tests(void)
+{
+#ifndef _WIN32
+ struct rlimit r;
+
+#if defined(RLIMIT_NOFILE)
+ getrlimit(RLIMIT_NOFILE,&r);
+
+ if (r.rlim_max <= 1024) {
+ if (flag_html) printf("<P>\n");
+
+ if (flag_carrier) {
+ printf("ERROR : There are only %ld file descriptors (hard limit) available, which\nlimit the number of simultaneous connections. ",r.rlim_max);
+ flag_os_bad = 1;
+ } else {
+ printf("WARNING: There are only %ld file descriptors (hard limit) available, which\nlimit the number of simultaneous connections. ",r.rlim_max);
+ }
+
+#if defined(__sun)
+ printf("Additional file descriptors,\nup to 65536, are available by adding to /etc/system a line like\n");
+ if (flag_html) printf("</P><PRE>\n");
+ printf("set rlim_fd_max=4096\n");
+ if (flag_html) printf("</PRE><P>\n");
+#else
+#if defined(__hppa)
+ printf("Additional file descriptors,\nup to 60000, are available by editing /stand/system and regenerating the kernel.\n");
+ if (flag_html) printf("</P><PRE>\n");
+ printf("maxfiles_lim 4096\n");
+ if (flag_html) printf("</PRE><P>\n");
+#else
+ printf("\n");
+#endif
+#endif
+ printf("\n");
+
+ if (flag_html) printf("</P>\n");
+
+ } else {
+ if (flag_debug) printf("DEBUG : %ld descriptors (hard limit) available.\n",
+ r.rlim_max);
+ }
+
+ if (r.rlim_cur <= 1024) {
+ if (flag_html) printf("<P>\n");
+
+ if (flag_carrier) {
+ printf("ERROR : There are only %ld file descriptors (soft limit) available, which\nlimit the number of simultaneous connections. ",r.rlim_cur);
+ flag_os_bad = 1;
+ } else {
+ printf("WARNING: There are only %ld file descriptors (soft limit) available, which\nlimit the number of simultaneous connections. ",r.rlim_cur);
+ }
+
+#if defined(__sun) || defined(__hppa)
+ printf("Additional file descriptors,\nup to %ld (hard limit), are available by issuing \'ulimit\' (\'limit\' for tcsh)\ncommand with proper arguments.\n", r.rlim_max);
+ if (flag_html) printf("</P><PRE>\n");
+ printf("ulimit -n 4096\n");
+ if (flag_html) printf("</PRE><P>\n");
+#else
+ printf("\n");
+#endif
+ printf("\n");
+
+ if (flag_html) printf("</P>\n");
+
+ } else {
+ if (flag_debug) printf("DEBUG : %ld descriptors (soft limit) available.\n",
+ r.rlim_cur);
+ }
+#endif
+
+#if defined(RLIMIT_DATA)
+ check_mem_size(RLIMIT_DATA,"RLIMIT_DATA");
+#endif
+
+#if defined(RLIMIT_VMEM)
+ check_mem_size(RLIMIT_VMEM,"RLIMIT_VMEM");
+#endif
+
+#if defined(RLIMIT_AS)
+ check_mem_size(RLIMIT_AS,"RLIMIT_AS");
+#endif
+
+#endif
+}
+
+/*
+*** return the type of platform on which the software is running.
+***/
+
+static void ids_get_platform(char *buf)
+{
+#if defined(IDDS_LINUX_INCLUDE) || defined(__osf__) || defined(_AIX) || defined(__hppa) || defined(IDDS_BSD_INCLUDE)
+ struct utsname u;
+#endif
+#if defined(_WIN32)
+ SYSTEM_INFO sysinfo;
+ OSVERSIONINFO osinfo;
+ char osbuf[128];
+
+#endif
+#if defined(__hppa) || defined(_AIX)
+ char model[128];
+ char procstr[128];
+ char oslevel[128];
+#endif
+
+#if defined(__hppa)
+ long cpuvers, cputype;
+#endif
+
+#if defined(_WIN32)
+ osinfo.dwOSVersionInfoSize = sizeof(osinfo);
+ GetSystemInfo(&sysinfo);
+ sprintf(osbuf,"win32");
+ if (GetVersionEx(&osinfo) != 0) {
+ if (osinfo.dwPlatformId == VER_PLATFORM_WIN32_NT) {
+ sprintf(osbuf,"winnt%d.%d.%d",
+ osinfo.dwMajorVersion,
+ osinfo.dwMinorVersion,
+ osinfo.dwBuildNumber);
+ if (osinfo.szCSDVersion[0]) {
+ strcat(osbuf," (");
+ strcat(osbuf,osinfo.szCSDVersion);
+ strcat(osbuf,")");
+ }
+ }
+ }
+
+ switch(sysinfo.wProcessorArchitecture) {
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ sprintf(buf,"i%d86-unknown-%s",sysinfo.wProcessorLevel,osbuf);
+ break;
+ case PROCESSOR_ARCHITECTURE_ALPHA:
+ sprintf(buf,"alpha%d-unknown-%s",
+ sysinfo.wProcessorLevel,osbuf);
+ break;
+ case PROCESSOR_ARCHITECTURE_MIPS:
+ sprintf(buf,"mips-unknown-%s",osbuf);
+ break;
+ case PROCESSOR_ARCHITECTURE_PPC:
+ sprintf(buf,"ppc-unknown-%s",osbuf);
+ break;
+ case PROCESSOR_ARCHITECTURE_UNKNOWN:
+ sprintf(buf,"unknown-unknown-%s",osbuf);
+ break;
+ }
+#else
+#if defined(IDDS_LINUX_INCLUDE)
+ if (uname(&u) == 0) {
+ sprintf(buf,"%s-unknown-linux%s",
+ u.machine,u.release);
+ } else {
+ sprintf(buf,"i386-unknown-linux");
+ }
+
+#else
+#if defined(__sun)
+ ids_get_platform_solaris(buf);
+#else
+#if defined(_AIX)
+
+ if (getenv("ODMPATH") == NULL) {
+ putenv("ODMPATH=/usr/lib/objrepos:/etc/objrepos");
+ }
+
+ /* i386, powerpc, rs6000 */
+ idds_aix_odm_get_cuat("name=proc0",procstr);
+ idds_aix_odm_get_cuat("attribute=modelname",model);
+ oslevel[0] = '\0';
+ idds_aix_pio_get_oslevel(oslevel);
+
+ if (uname(&u) == 0) {
+ if (oslevel[0]) {
+ sprintf(buf,"%s-%s-%s%s",
+ procstr[0] ? procstr : "unknown" ,
+ model[0] ? model : "ibm",
+ u.sysname,oslevel);
+
+ } else {
+ sprintf(buf,"%s-%s-%s%s.%s",
+ procstr[0] ? procstr : "unknown" ,
+ model[0] ? model : "ibm",
+ u.sysname,u.version,u.release);
+ }
+ } else {
+ sprintf(buf,"%s-unknown-aix", procstr[0] ? procstr : "unknown");
+ }
+#else
+#if defined(IDDS_BSD_INCLUDE)
+ uname(&u);
+ sprintf(buf,"%s-unknown-%s%s",
+ u.machine,u.sysname,u.release);
+#else
+#if defined(__hppa)
+ uname(&u);
+ confstr(_CS_MACHINE_MODEL,model,128);
+ cpuvers = sysconf(_SC_CPU_VERSION);
+ cputype = sysconf(_SC_CPU_CHIP_TYPE);
+
+
+ switch(cpuvers) {
+ case CPU_PA_RISC1_0:
+ sprintf(procstr,"hppa1.0/%d",cputype);
+ break;
+ case CPU_PA_RISC1_1:
+ sprintf(procstr,"hppa1.1/%d",cputype);
+ break;
+ case CPU_PA_RISC1_2:
+ sprintf(procstr,"hppa1.2/%d",cputype);
+ break;
+ case CPU_PA_RISC2_0:
+ sprintf(procstr,"hppa2.0/%d",cputype);
+ break;
+ default:
+ sprintf(procstr,"hppa_0x%x/%d",cpuvers,cputype);
+ break;
+ }
+
+ sprintf(buf,"%s-hp%s-hpux_%s",procstr,model,u.release);
+
+
+#else
+#if defined(__VMS)
+#if defined (__ALPHA)
+ sprintf(buf,"alpha-dec-vms");
+#else
+ sprintf(buf,"vax-dec-vms");
+#endif
+
+#else
+#if defined(__osf__)
+#if defined(__alpha) || defined(__ALPHA)
+ ids_get_platform_tru64(buf);
+#else
+ sprintf(buf,"unknown-unknown-osf");
+#endif
+#else
+#if defined(SI_HW_PROVIDER) && defined(SI_MACHINE) && defined(SI_SYSNAME) && defined(SI_RELEASE)
+ if (1) {
+ char *bp;
+
+ sysinfo(SI_MACHINE,buf,64);
+ bp = buf + strlen(buf);
+ *bp = '-';
+ bp++;
+ sysinfo(SI_HW_PROVIDER,bp,64);
+ bp = bp + strlen(bp);
+ *bp = '-';
+ bp++;
+ sysinfo(SI_SYSNAME,bp,64);
+ bp = bp + strlen(bp);
+ sysinfo(SI_RELEASE,bp,64);
+ }
+#else
+#if defined(SI_MACHINE)
+ sysinfo(SI_MACHINE,buf,64);
+ strcat(buf,"-unknown-unknown");
+#else
+ sprintf(buf,"unknown");
+#endif /* has SI_HW_PROVIDER */
+#endif /* has SI_MACHINE */
+#endif /* OSF */
+#endif /* VMS */
+#endif /* HPUX */
+#endif /* FREEBSD */
+#endif /* AIX */
+#endif /* SUN */
+#endif /* LINUX */
+#endif /* WIN32 */
+}
+
+static int count_processors(void)
+{
+ int nproc = 0;
+
+#if defined(_SC_NPROCESSORS_ONLN) && !defined(__osf__)
+ nproc = sysconf(_SC_NPROCESSORS_ONLN);
+#endif
+
+#if defined(_WIN32)
+ SYSTEM_INFO sysinfo;
+
+ GetSystemInfo(&sysinfo);
+ nproc = sysinfo.dwNumberOfProcessors;
+#endif
+
+#if defined(IDDS_BSD_SYSCTL) && defined(__FreeBSD__)
+ int fblen = sizeof(int);
+ int tmp;
+ sysctlbyname("hw.ncpu",&nproc,&fblen,NULL,0);
+#endif
+
+#if defined(__osf__)
+ struct cpu_info cpu_info;
+ int start = 0;
+
+ cpu_info.cpus_in_box = 0;
+ getsysinfo(GSI_CPU_INFO,(caddr_t)&cpu_info,sizeof(struct cpu_info),&start,NULL);
+ nproc = cpu_info.cpus_in_box;
+#endif
+ return nproc;
+}
+
+static void usage(char *av)
+{
+ printf("usage: %s [-q] [-D] [-v] [-c] [-i installdir]\n",av);
+ printf(" -q dsktune only reports essential settings\n");
+ printf(" -c dsktune only reports tuning information for client machines\n");
+ printf(" -D dsktune also reports the commands executed\n");
+ printf(" -v dsktune only reports its release version date\n");
+ printf(" -i specify alternate server installation directory\n");
+ printf("\n");
+ exit(1);
+}
+
+static void print_version(void)
+{
+ printf("%s\n",build_date);
+ exit(1);
+}
+
+int main(int argc,char *argv[])
+{
+ int i;
+
+#ifdef _WIN32
+
+#else
+ while((i = getopt(argc,argv,"DvHqcCi:")) != EOF) {
+ switch(i) {
+ case 'D':
+ flag_debug = 1;
+ break;
+ case 'H':
+ flag_html = 1;
+ break;
+ case 'v':
+ print_version();
+ break;
+ case 'q':
+ flag_quick = 1;
+ break;
+ case 'c':
+ client = 1;
+ break;
+ case 'C':
+ flag_carrier = 1;
+ break;
+ case 'i':
+ strcpy(install_dir,optarg);
+ break;
+ default:
+ usage(argv[0]);
+ break;
+ }
+ }
+#endif
+
+#if defined(_AIX)
+ if (1) {
+ char *s = getenv("ODMPATH");
+ if (s == NULL) {
+ putenv("ODMPATH=/usr/lib/objrepos:/etc/objrepos");
+ }
+ }
+#endif
+
+ if (flag_quick == 0) {
+ char sysbuf[BUFSIZ];
+ int nproc;
+ if (flag_html) printf("<P>\n");
+ printf("Netscape Directory Server system tuning analysis version %s.\n\n", build_date);
+ ids_get_platform(sysbuf);
+ nproc = count_processors();
+ if (nproc == 1) {
+ printf("NOTICE : System is %s (1 processor).\n\n",sysbuf);
+ } else if (nproc > 1) {
+ printf("NOTICE : System is %s (%d processors).\n\n",sysbuf,nproc);
+ } else {
+ printf("NOTICE : System is %s.\n\n",sysbuf);
+ }
+ if (flag_html) printf("</P>\n");
+ }
+
+ gen_tests();
+
+#if defined(__sun) || defined(__hppa) || defined(IDDS_BSD_SYSCTL) || defined(IDDS_LINUX_SYSCTL)
+ ndd_tests();
+#endif
+
+#if defined(__hppa)
+ hp_pthreads_tests();
+#endif
+
+#if defined(__osf__)
+ sysconfig_tests();
+#endif
+
+ limits_tests();
+
+ disk_tests();
+
+ if (flag_os_bad || flag_arch_bad) {
+ if (flag_html) printf("<P>\n");
+ printf("ERROR : The above errors MUST be corrected before proceeding.\n\n");
+ if (flag_html) printf("</P>\n");
+ exit(1);
+ }
+
+ exit(0);
+ return 0;
+}
+
diff --git a/ldap/systools/mergeSolPatches.pl b/ldap/systools/mergeSolPatches.pl
new file mode 100755
index 00000000..4deefad4
--- /dev/null
+++ b/ldap/systools/mergeSolPatches.pl
@@ -0,0 +1,57 @@
+#!/usr/bin/perl -w
+
+# take a solaris8 patch list and a solaris9 patch list and merge them
+# together, removing duplicates
+# we are looking for patches that have the same major revision
+# number and release OS. We only want to keep the one with the highest
+# minor revision number
+
+# key is the major patch number
+# the value is a hash ref which has two keys 'iminor' and 'val'
+# the value of key 'iminor' is the minor patch number
+# the system keeps track of all revisions (minor number) for each patch (major number)
+# we only want to list the highest revision, since on Solaris higher revisions include
+# and supersede lower revisions
+# the value of key 'val' is the string to print out
+%patches = ();
+@lines = ();
+
+for $file (@ARGV) {
+ open IN, $file or die "Error: could not open $file: $!";
+ while (<IN>) {
+ if (/^\s*\{(\d+),(\d+),\d,(\d+),/) {
+ $major = $1;
+ $minor = $2;
+ $rel = $3;
+ my $h = { 'val' => $_ };
+ $patches{$major}{$rel}{$minor} = $h;
+ if (! $patches{$major}{$rel}{highestminor}) {
+ $patches{$major}{$rel}{highestminor} = $minor;
+ } elsif ($patches{$major}{$rel}{highestminor} <= $minor) { # highest minor rev is lt or eq new minor
+ my $oldminor = $patches{$major}{$rel}{highestminor};
+ $patches{$major}{$rel}{$oldminor}->{skip} = 1;
+ $patches{$major}{$rel}{highestminor} = $minor;
+ } elsif ($patches{$major}{$rel}{highestminor} > $minor) {
+ # skip the new one
+ $h->{skip} = 1;
+ }
+ push @lines, $h; # put a hash ref into lines
+ } else {
+ push @lines, $_; # put the scalar value into lines
+ }
+ }
+ close IN;
+}
+
+for (@lines) {
+ if (ref($_)) {
+ if ($_->{skip}) {
+ chomp $_->{val};
+ print "/* duplicate or superseded ", $_->{val}, " */\n";
+ } else {
+ print $_->{val};
+ }
+ } else {
+ print;
+ }
+}
diff --git a/ldap/systools/pio.c b/ldap/systools/pio.c
new file mode 100644
index 00000000..4d6593c0
--- /dev/null
+++ b/ldap/systools/pio.c
@@ -0,0 +1,94 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "pio.h"
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+
+int iii_pio_procparse (
+ const char *cmd,
+ int count,
+ struct iii_pio_parsetab *tb
+)
+{
+ FILE *fp;
+ char buf[8192];
+ int rc = 0;
+
+ fp = popen(cmd,"r");
+
+ if (fp == NULL) {
+ return -1;
+ }
+
+ while (fgets(buf,8192,fp) != NULL && rc >= 0) {
+ char *rp;
+ int i;
+
+ rp = strchr(buf,'\n');
+
+ if (rp) {
+ *rp = '\0';
+ }
+
+ rp = strchr(buf,':');
+
+#if defined(__osf__)
+ if (rp == NULL) {
+ rp = strchr(buf,'=');
+ }
+#endif
+
+ if (rp == NULL) continue;
+
+ *rp = '\0';
+ rp++;
+ while(isspace(*rp)) rp++;
+
+ for (i = 0; i < count; i++) {
+ if (strcmp(tb[i].token,buf) == 0) {
+ rc = (tb[i].fn)(buf,rp);
+ break;
+ }
+ }
+ }
+
+ pclose(fp);
+
+ return rc;
+}
+
+int iii_pio_getnum (
+ const char *cmd,
+ long *valPtr
+)
+{
+ FILE *fp;
+ char buf[8192];
+ int rc = 0;
+
+ fp = popen(cmd,"r");
+
+ if (fp == NULL) {
+ return -1;
+ }
+
+ if (fgets(buf,8192,fp) == NULL) {
+ pclose(fp);
+ return -1;
+ }
+
+ pclose(fp);
+
+ if (!(isdigit(*buf))) {
+ return -1;
+ }
+
+ *valPtr = atol(buf);
+
+ return 0;
+}
diff --git a/ldap/systools/pio.h b/ldap/systools/pio.h
new file mode 100644
index 00000000..6f24bf8e
--- /dev/null
+++ b/ldap/systools/pio.h
@@ -0,0 +1,32 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef _H_III_PIO_H
+#define _H_III_PIO_H
+
+#include <stdio.h>
+
+struct iii_pio_parsetab {
+ char *token;
+ int (*fn)(char *,char *);
+};
+
+#define III_PIO_SZ(x) (sizeof(x)/sizeof(struct iii_pio_parsetab))
+
+extern int iii_pio_procparse (
+ const char *cmd,
+ int count,
+ struct iii_pio_parsetab *
+);
+
+extern int iii_pio_getnum (
+ const char *cmd,
+ long *valPtr
+);
+
+#endif /* _H_III_PIO_H */
+
+
diff --git a/ldap/systools/sol_patches.c b/ldap/systools/sol_patches.c
new file mode 100644
index 00000000..4363087d
--- /dev/null
+++ b/ldap/systools/sol_patches.c
@@ -0,0 +1,271 @@
+/* This list was generated by /u/norikoyasuo/bin/getSolPatches.pl */
+/* on droid.mcom.com */
+/* at Thu Mar 18 18:34:27 2004 GMT */
+/* Here is the information from /etc/release:
+ Solaris 8 s28_38shwp2 SPARC
+ Copyright 2000 Sun Microsystems, Inc. All Rights Reserved.
+ Assembled 21 January 2000
+ The following is a list of patches installed on the system */
+/* a patch that is commented out is either a duplicate or */
+/* a patch that is superseded by another patch */
+{108434,14,1,28,0,0,"Jan/16/2004: SunOS 5.8: 32-Bit Shared library patch for C++"},
+{108435,14,1,28,0,0,"Jan/16/2004: SunOS 5.8: 64-Bit Shared library patch for C++"},
+{108528,27,1,28,0,0,"Nov/25/2003: SunOS 5.8: kernel update patch"},
+{108652,77,1,28,0,0,"Jan/26/2004: X11 6.4.1: Xsun patch"},
+{108725,15,1,28,0,0,"Jan/23/2004: SunOS 5.8: st driver patch"},
+{108727,26,1,28,0,0,"Dec/02/2003: SunOS 5.8: /kernel/fs/nfs and /kernel/fs/sparcv9/nfs patch"},
+{108806,17,1,28,0,0,"Aug/12/2003: SunOS 5.8: Sun Quad FastEthernet qfe driver"},
+{108827,20,1,28,0,0,"Mar/20/2002: SunOS 5.8: /usr/lib/libthread.so.1 patch"},
+{108869,22,1,28,0,0,"Aug/19/2003: SunOS 5.8: snmpdx/mibiisa/libssasnmp/snmplib patch"},
+{108875,12,1,28,0,0,"Apr/10/2002: SunOS 5.8: c2audit patch"},
+{108899,4,1,28,0,0,"Feb/18/2003: SunOS 5.8: /usr/bin/ftp patch"},
+{108901,4,1,28,0,0,"Jul/23/2001: SunOS 5.8: /kernel/sys/rpcmod and /kernel/strmod/rpcmod patch"},
+{108919,20,1,28,0,0,"Sep/22/2003: CDE 1.4: dtlogin patch"},
+{108949,7,1,28,0,0,"Dec/07/2001: CDE 1.4: libDtHelp/libDtSvc patch"},
+{108968,8,1,28,0,0,"Jan/22/2003: SunOS 5.8: vol/vold/rmmount/dev_pcmem.so.1 patch"},
+{108974,37,1,28,0,0,"Jan/07/2004: SunOS 5.8: dada, uata, dad, sd, ssd and scsi drivers patch"},
+{108975,8,1,28,0,0,"Apr/18/2003: SunOS 5.8: /usr/bin/rmformat and /usr/sbin/format patch"},
+{108977,2,1,28,0,0,"Apr/18/2003: SunOS 5.8: libsmedia patch"},
+{108981,13,1,28,0,0,"Nov/25/2003: SunOS 5.8: /kernel/drv/hme and /kernel/drv/sparcv9/hme patch"},
+{108985,3,1,28,0,0,"Jun/25/2001: SunOS 5.8: /usr/sbin/in.rshd patch"},
+{108987,13,1,28,0,0,"Apr/07/2003: SunOS 5.8: Patch for patchadd and patchrm"},
+{108989,2,1,28,0,0,"Jul/18/00: SunOS 5.8: /usr/kernel/sys/acctctl and /usr/kernel/sys/exacctsys patch"},
+{108993,31,1,28,0,0,"Dec/10/2003: SunOS 5.8: LDAP2 client, libc, libthread and libnsl libraries patch"},
+{108997,3,1,28,0,0,"Jul/18/00: SunOS 5.8: libexacct and libproject patch"},
+{109007,15,1,28,0,0,"Jan/27/2004: SunOS 5.8: at/atrm/batch/cron patch"},
+{109091,6,1,28,0,0,"Apr/08/2003: SunOS 5.8: /usr/lib/fs/ufs/ufsrestore patch"},
+/* Web-Based Enterprise Management (WBEM) {109134,28,1,28,0,0,"Jun/10/2003: SunOS 5.8: WBEM patch"}, */
+{109147,27,1,28,0,0,"Nov/26/2003: SunOS 5.8: linker patch"},
+{109149,2,1,28,0,0,"Nov/13/2001: SunOS 5.8:: /usr/sbin/mkdevmaps and /usr/sbin/mkdevalloc patch"},
+{109152,2,1,28,0,0,"Mar/27/2003: SunOS 5.8: /usr/4lib/libc.so.x.9 and libdbm patch"},
+{109202,5,1,28,0,0,"Jun/06/2003: SunOS 5.8: /kernel/misc/gld and /kernel/misc/sparcv9/gld patch"},
+{109223,4,1,28,0,0,"Dec/23/2003: SunOS 5.8: kpasswd, libgss.so.1 and libkadm5clnt.so.1 patch"},
+{109234,9,1,28,0,0,"Aug/07/2002: SunOS 5.8: Apache Security and NCA Patch"},
+{109238,2,1,28,0,0,"Sep/17/2001: SunOS 5.8: /usr/bin/sparcv7/ipcs and /usr/bin/sparcv9/ipcs patch"},
+{109277,3,1,28,0,0,"Oct/25/2002: SunOS 5.8: /usr/bin/iostat patch"},
+{109318,34,1,28,0,0,"Nov/14/2003: SunOS 5.8: suninstall Patch"},
+{109320,8,1,28,0,0,"Nov/26/2003: SunOS 5.8: LP Patch"},
+{109324,5,1,28,0,0,"Dec/05/2002: SunOS 5.8: sh/jsh/rsh/pfsh patch"},
+{109326,13,1,28,0,0,"Jan/29/2004: SunOS 5.8: libresolv.so.2 and in.named patch"},
+{109328,3,1,28,0,0,"Oct/29/2002: SunOS 5.8: ypserv, ypxfr and ypxfrd patch"},
+{109354,19,1,28,0,0,"Apr/15/2003: CDE 1.4: dtsession patch"},
+{109458,3,1,28,0,0,"Jan/07/2003: SunOS 5.8: /kernel/strmod/ldterm patch"},
+{109460,10,1,28,0,0,"Aug/04/2003: SunOS 5.8: socal and sf drivers patch"},
+{109470,2,1,28,0,0,"Aug/29/00: CDE 1.4: Actions Patch"},
+{109657,9,1,28,0,0,"Jan/07/2003: SunOS 5.8: isp driver patch"},
+{109667,5,1,28,0,0,"Jun/16/2003: SunOS 5.8: /usr/lib/inet/xntpd and /usr/sbin/ntpdate patch"},
+{109695,3,1,28,0,0,"Jul/23/2001: SunOS 5.8: /etc/smartcard/opencard.properties patch"},
+{109778,14,1,28,0,0,"Jan/26/2004: SunOS 5.8: Misc loc have errors in CTYPE and lv colln monetary"},
+{109783,2,1,28,0,0,"Oct/02/2002: SunOS 5.8: /usr/lib/nfs/nfsd and /usr/lib/nfs/lockd patch"},
+{109793,23,1,28,0,0,"Oct/13/2003: SunOS 5.8: su driver patch"},
+{109805,17,1,28,0,0,"Sep/29/2003: SunOS 5.8: /usr/lib/security/pam_krb5.so.1 patch"},
+{109815,20,1,28,0,0,"Jan/07/2004: SunOS 5.8: se, acebus, pcf8574, pcf8591 and scsb patch"},
+{109862,3,1,28,0,0,"Dec/18/2002: X11 6.4.1 Font Server patch"},
+{109873,22,1,28,0,0,"Dec/04/2003: SunOS 5.8: prtdiag and platform libprtdiag_psr.so.1 patch"},
+{109882,6,1,28,0,0,"Jun/05/2002: SunOS 5.8: eri header files patch"},
+{109883,2,1,28,0,0,"Dec/20/2000: SunOS 5.8: /usr/include/sys/ecppsys.h patch"},
+{109885,14,1,28,0,0,"Oct/01/2003: SunOS 5.8: glm patch"},
+{109887,18,1,28,0,0,"Nov/17/2003: SunOS 5.8: smartcard and usr/sbin/ocfserv patch"},
+{109888,26,1,28,0,0,"Nov/26/2003: SunOS 5.8: platform drivers patch"},
+{109893,4,1,28,0,0,"Dec/24/2002: SunOS 5.8: stc driver patch"},
+{109894,1,1,28,0,0,"Nov/15/2000: SunOS 5.8: /kernel/drv/sparcv9/bpp driver patch"},
+{109896,24,1,28,0,0,"Feb/02/2004: SunOS 5.8: USB and Audio Framework patch"},
+{109898,5,1,28,0,0,"Oct/22/2001: SunOS 5.8: /kernel/drv/arp patch"},
+{109922,4,1,28,0,0,"Jan/22/2003: SunOS 5.8: pcelx and pcser driver patch"},
+{109928,5,1,28,0,0,"Jun/27/2002: SunOS 5.8: pcmem and pcmcia patch"},
+{110068,4,1,28,0,0,"Nov/05/2003: CDE 1.4: PDASync patch"},
+{110075,1,1,28,0,0,"Mar/13/2001: SunOS 5.8: /kernel/drv/devinfo and /kernel/drv/sparcv9/devinfo patch"},
+{110283,6,1,28,0,0,"Nov/26/2002: SunOS 5.8: mkfs and newfs patch"},
+{110286,11,1,28,0,0,"Sep/24/2003: OpenWindows 3.6.2: Tooltalk patch"},
+{110322,2,1,28,0,0,"Aug/19/2002: SunOS 5.8: /usr/lib/netsvc/yp/ypbind patch"},
+{110335,3,1,28,0,0,"Dec/03/2003: CDE 1.4: dtprintinfo patch"},
+{110380,4,1,28,0,0,"Dec/21/2001: SunOS 5.8: ufssnapshots support, libadm patch"},
+{110386,3,1,28,0,0,"Apr/08/2003: SunOS 5.8: RBAC Feature Patch"},
+{110387,5,1,28,0,0,"Aug/19/2003: SunOS 5.8: ufssnapshots support, ufsdump patch"},
+{110389,5,1,28,0,0,"Jan/22/2003: SunOS 5.8: cvc CPU signature"},
+{110453,4,1,28,0,0,"Feb/21/2003: SunOS 5.8: admintool Patch"},
+{110458,2,1,28,0,0,"May/29/2001: SunOS 5.8: libcurses patch"},
+{110460,32,1,28,0,0,"Nov/17/2003: SunOS 5.8: fruid/PICL plug-ins patch"},
+{110461,3,1,28,0,0,"Feb/27/2003: SunOS 5.8: ttcompat patch"},
+{110609,4,1,28,0,0,"Apr/18/2003: SunOS 5.8: cdio.h and command.h USB header patch"},
+/* {110615,4,1,28,0,0,"Jan/23/2002: SunOS 5.8: sendmail patch"}, */
+{110662,12,1,28,0,0,"Apr/24/2003: SunOS 5.8: ksh patch"},
+{110668,4,1,28,0,0,"Apr/08/2003: SunOS 5.8: /usr/sbin/in.telnetd patch"},
+/* rcp to non-solaris {110670,1,1,28,0,0,"Mar/30/2001: SunOS 5.8: usr/sbin/static/rcp patch"}, */
+{110700,1,1,28,0,0,"Jan/08/2001: SunOS 5.8: automount patch"},
+{110820,10,1,28,0,0,"Dec/19/2002: SunOS 5.8: /platform/SUNW,Sun-Fire-15000/kernel/drv/sparcv9/dman patch"},
+{110838,6,1,28,0,0,"Dec/16/2002: SunOS 5.8: /platform/SUNW,Sun-Fire-15000/kernel/drv/sparcv9/axq patch"},
+{110842,11,1,28,0,0,"May/08/2003: SunOS 5.8: hpc3130 driver patch for SUNW,Sun-Fire-880"},
+{110896,2,1,28,0,0,"Jan/03/2003: SunOS 5.8: cachefs/mount patch"},
+{110898,9,1,28,0,0,"Jan/26/2004: SunOS 5.8: csh/pfcsh patch"},
+{110901,1,1,28,0,0,"Mar/02/2001: SunOS 5.8: /kernel/drv/sgen and /kernel/drv/sparcv9/sgen patch"},
+{110903,7,1,28,0,0,"Nov/25/2003: SunOS 5.8: edit, ex, vedit, vi and view patch"},
+{110916,5,1,28,0,0,"Dec/15/2003: SunOS 5.8: sort patch"},
+{110934,14,1,28,0,0,"Aug/05/2003: SunOS 5.8: pkgtrans, pkgadd, pkgchk, pkgmk and libpkg.a patch"},
+/* wtmp {110939,1,1,28,0,0,"Mar/06/2001: SunOS 5.8: /usr/lib/acct/closewtmp patch"}, */
+{110943,2,1,28,0,0,"Nov/14/2003: SunOS 5.8: /usr/bin/tcsh patch"},
+{110945,8,1,28,0,0,"May/29/2003: SunOS 5.8: /usr/sbin/syslogd patch"},
+{110951,5,1,28,0,0,"Nov/14/2003: SunOS 5.8: /usr/sbin/tar and /usr/sbin/static/tar patch"},
+{110953,6,1,28,0,0,"Dec/09/2003: SunOS 5.8: /usr/kernel/drv/llc2 patch"},
+{110955,4,1,28,0,0,"Dec/24/2002: SunOS 5.8: /kernel/strmod/timod patch"},
+{110957,2,1,28,0,0,"Nov/06/2001: SunOS 5.8: /usr/bin/mailx patch"},
+{111023,3,1,28,0,0,"Dec/09/2003: SunOS 5.8: /kernel/fs/mntfs and /kernel/fs/sparcv9/mntfs patch"},
+{111069,1,1,28,0,0,"Aug/02/2001: SunOS 5.8: bsmunconv overwrites root cron tab if cu created /tmp/root"},
+/* uucp {111071,1,1,28,0,0,"Mar/30/2001: SunOS 5.8: cu patch"}, */
+{111085,2,1,28,0,0,"Dec/13/2001: SunOS 5.8: /usr/bin/login patch"},
+{111098,1,1,28,0,0,"Jul/17/2001: SunOS 5.8: ROC timezone should be avoided for political reasons"},
+{111111,3,1,28,0,0,"Mar/28/2002: SunOS 5.8: /usr/bin/nawk patch"},
+{111232,1,1,28,0,0,"Apr/25/2001: SunOS 5.8: patch in.fingerd"},
+{111234,1,1,28,0,0,"Apr/25/2001: SunOS 5.8: patch finger"},
+{111293,4,1,28,0,0,"Sep/25/2001: SunOS 5.8: /usr/lib/libdevinfo.so.1 patch"},
+{111302,2,1,28,0,0,"Sep/11/2002: SunOS 5.8: EDHCP libraries patch"},
+{111310,1,1,28,0,0,"Aug/21/2001: SunOS 5.8: /usr/lib/libdhcpagent.so.1 patch"},
+{111317,5,1,28,0,0,"Dec/10/2003: SunOS 5.8: /sbin/init and /usr/sbin/init patch"},
+{111321,3,1,28,0,0,"Oct/02/2002: SunOS 5.8: klmmod and klmops patch"},
+{111325,2,1,28,0,0,"Jun/14/2002: SunOS 5.8: /usr/lib/saf/ttymon patch"},
+{111327,5,1,28,0,0,"Dec/04/2001: SunOS 5.8: libsocket patch"},
+{111400,2,1,28,0,0,"Jan/28/2004: SunOS 5.8: KCMS configure tool has a security vulnerability"},
+{111504,1,1,28,0,0,"Jun/15/2001: SunOS 5.8: /usr/bin/tip patch"},
+{111548,1,1,28,0,0,"Jun/15/2001: SunOS 5.8: catman, man, whatis, apropos and makewhatis patch"},
+/* uucp {111570,2,1,28,0,0,"Sep/11/2002: SunOS 5.8: uucp patch"}, */
+{111588,4,1,28,0,0,"Dec/24/2002: SunOS 5.8: /kernel/drv/ws and /kernel/fs/specfs patch"},
+/* {111596,3,1,28,0,0,"Feb/28/2003: SunOS 5.8: /usr/lib/netsvc/yp/rpc.yppasswdd patch"}, */
+{111606,4,1,28,0,0,"Jul/30/2003: SunOS 5.8: /usr/sbin/in.ftpd patch"},
+{111624,4,1,28,0,0,"Oct/02/2002: SunOS 5.8: /usr/sbin/inetd patch"},
+{111626,3,1,28,0,0,"Nov/11/2002: OpenWindows 3.6.2: Xview Patch"},
+{111659,6,1,28,0,0,"Mar/04/2002: SunOS 5.8: passwd and pam_unix.so.1 patch"},
+{111826,1,1,28,0,0,"Aug/15/2001: SunOS 5.8: /usr/sbin/sparcv7/whodo & /usr/sbin/sparcv9/whodo patch"},
+{111874,6,1,28,0,0,"Jan/23/2003: SunOS 5.8: usr/bin/mail patch"},
+/* old progreg and Live Upgrade problem {111879,1,1,28,0,0,"Aug/27/2001: SunOS 5.8: Solaris Product Registry patch SUNWwsr"}, */
+{111881,3,1,28,0,0,"Dec/24/2002: SunOS 5.8: /usr/kernel/strmod/telmod patch"},
+{111958,2,1,28,0,0,"May/13/2002: SunOS 5.8: /usr/lib/nfs/statd patch"},
+{112039,1,1,28,0,0,"Sep/17/2001: SunOS 5.8: usr/bin/ckitem patch"},
+{112138,1,1,28,0,0,"Nov/05/2001: SunOS 5.8:: usr/bin/domainname patch"},
+{112161,3,1,28,0,0,"Dec/04/2003: SunOS 5.8: remove libprtdiag_psr.so.1 of SUNW,Netra-T12 SUNW,Netra-T4"},
+{112218,1,1,28,0,0,"Nov/13/2001: SunOS 5.8:: pam_ldap.so.1 patch"},
+{112237,9,1,28,0,0,"Nov/05/2003: SunOS 5.8: mech_krb5.so.1 patch"},
+{112254,1,1,28,0,0,"Feb/27/2002: SunOS 5.8: /kernel/sched/TS patch"},
+{112325,1,1,28,0,0,"Jan/22/2002: SunOS 5.8: /kernel/fs/udfs and /kernel/fs/sparcv9/udfs patch"},
+{112396,2,1,28,0,0,"Mar/28/2002: SunOS 5.8: /usr/bin/fgrep patch"},
+{112425,1,1,28,0,0,"Feb/19/2002: SunOS 5.8: /usr/lib/fs/ufs/mount and /etc/fs/ufs/mount patch"},
+{112459,1,1,28,0,0,"Mar/07/2002: SunOS 5.8: /usr/lib/pt_chmod patch"},
+{112609,2,1,28,0,0,"May/29/2003: SunOS 5.8: /kernel/drv/le and /kernel/drv/sparcv9/le patch"},
+{112611,2,1,28,0,0,"Oct/21/2003: SunOS 5.8: /usr/lib/libz.so.1 patch"},
+{112668,1,1,28,0,0,"May/14/2002: SunOS 5.8: /usr/bin/gzip patch"},
+/* {112792,1,1,28,0,0,"Jul/09/2002: SunOS 5.8: /usr/lib/pcmciad patch"}, */
+{112796,1,1,28,0,0,"May/27/2002: SunOS 5.8: /usr/sbin/in.talkd patch"},
+{112846,1,1,28,0,0,"Jun/17/2002: SunOS 5.8: /usr/lib/netsvc/rwall/rpc.rwalld patch"},
+{113648,3,1,28,0,0,"Dec/10/2003: SunOS 5.8: /usr/sbin/mount patch"},
+{113650,2,1,28,0,0,"May/28/2003: SunOS 5.8: /usr/lib/utmp_update patch"},
+{113685,5,1,28,0,0,"Oct/06/2003: SunOS 5.8: logindmux/ptsl/ms/bufmod/llc1/kb/zs/zsh/ptem patch"},
+{113687,1,1,28,0,0,"Dec/24/2002: SunOS 5.8: /kernel/misc/kbtrans patch"},
+{113792,1,1,28,0,0,"Nov/25/2002: OpenWindows 3.6.2: mailtool patch"},
+{114162,1,1,28,0,0,"Apr/07/2003: SunOS 5.8: /kernel/drv/lofi drivers and /usr/sbin/lofiadm patch"},
+{114673,1,1,28,0,0,"Apr/16/2003: SunOS 5.8: /usr/sbin/wall patch"},
+{114802,2,1,28,0,0,"Jan/08/2004: SunOS 5.8: Patch for assembler"},
+{114984,1,1,28,0,0,"Apr/29/2003: SunOS 5.8: /usr/kernel/fs/namefs patch"},
+{115576,1,1,28,0,0,"Jul/28/2003: SunOS 5.8: /kernel/exec/elfexec and /kernel/exec/sparcv9/elfexec patch"},
+{115797,1,1,28,0,0,"Aug/15/2003: CDE 1.4: dtspcd Patch"},
+{115827,1,1,28,0,0,"Oct/27/2003: SunOS 5.8: /sbin/sulogin and /sbin/netstrategy patch"},
+{116602,1,1,28,0,0,"Dec/10/2003: SunOS 5.8: /sbin/uadmin and /sbin/hostconfig patch"},
+/* This list was generated by /u/norikoyasuo/bin/getSolPatches.pl */
+/* on tmolus.mcom.com */
+/* at Thu Mar 18 10:34:35 2004 GMT */
+/* Here is the information from /etc/release:
+ Solaris 9 s9_58shwpl3 SPARC
+ Copyright 2002 Sun Microsystems, Inc. All Rights Reserved.
+ Use is subject to license terms.
+ Assembled 15 April 2002
+ The following is a list of patches installed on the system */
+/* a patch that is commented out is either a duplicate or */
+/* a patch that is superseded by another patch */
+{112233,11,1,29,0,0,"Dec/23/2003: SunOS 5.9: Kernel Patch"},
+{112540,18,1,29,0,0,"Sep/02/2003: SunOS 5.9: Expert3D IFB Graphics Patch"},
+{112601,9,1,29,0,0,"Oct/28/2003: SunOS 5.9: PGX32 Graphics"},
+{112617,2,1,29,0,0,"Jan/15/2003: CDE 1.5: rpc.cmsd patch"},
+{112661,6,1,29,0,0,"Oct/03/2003: SunOS 5.9: IIIM and X Input & Output Method patch"},
+{112764,6,1,29,0,0,"Apr/16/2003: SunOS 5.9: Sun Quad FastEthernet qfe driver"},
+{112785,30,1,29,0,0,"Dec/19/2003: X11 6.6.1: Xsun patch"},
+{112807,7,1,29,0,0,"Sep/25/2003: CDE 1.5: dtlogin patch"},
+{112808,6,1,29,0,0,"Dec/01/2003: CDE1.5: Tooltalk patch"},
+{112817,16,1,29,0,0,"Jan/05/2004: SunOS 5.9: Sun GigaSwift Ethernet 1.0 driver patch"},
+{112834,3,1,29,0,0,"Sep/01/2003: SunOS 5.9: patch scsi"},
+{112874,22,1,29,0,0,"Jan/30/2004: SunOS 5.9: lgroup API libc Patch"},
+{112875,1,1,29,0,0,"Jun/21/2002: SunOS 5.9: patch /usr/lib/netsvc/rwall/rpc.rwalld"},
+{112902,8,1,29,0,0,"Dec/06/2002: SunOS 5.9: kernel/drv/ip Patch"},
+{112907,2,1,29,0,0,"Oct/13/2003: SunOS 5.9: libgss Patch"},
+{112908,11,1,29,0,0,"Nov/06/2003: SunOS 5.9: krb5 shared object Patch"},
+{112921,3,1,29,0,0,"Jan/20/2004: SunOS 5.9: libkadm5 Patch"},
+{112922,2,1,29,0,0,"Apr/24/2003: SunOS 5.9: krb5 lib Patch"},
+{112923,3,1,29,0,0,"Nov/06/2003: SunOS 5.9: krb5 usr/lib Patch"},
+{112925,3,1,29,0,0,"Nov/06/2003: SunOS 5.9: ktutil kdb5_util kadmin kadmin.local kadmind Patch"},
+{112926,5,1,29,0,0,"Nov/17/2003: SunOS 5.9: smartcard Patch"},
+{112945,21,1,29,0,0,"Jan/28/2004: SunOS 5.9: wbem Patch"},
+{112951,4,1,29,0,0,"Dec/12/2002: SunOS 5.9: patchadd and patchrm Patch"},
+{112960,10,1,29,0,0,"Dec/23/2003: SunOS 5.9: patch libsldap ldap_cachemgr libldap"},
+{112963,10,1,29,0,0,"Oct/14/2003: SunOS 5.9: linker patch"},
+{112964,4,1,29,0,0,"Apr/23/2003: SunOS 5.9: /usr/bin/ksh Patch"},
+{112965,2,1,29,0,0,"Aug/01/2003: SunOS 5.9: patch /kernel/drv/sparcv9/eri"},
+{112970,6,1,29,0,0,"Jan/13/2004: SunOS 5.9: patch libresolv"},
+{112975,3,1,29,0,0,"Oct/24/2003: SunOS 5.9: patch /kernel/sys/kaio"},
+{112998,3,1,29,0,0,"May/29/2003: SunOS 5.9: patch /usr/sbin/syslogd"},
+{113026,14,1,29,0,0,"Jan/16/2004: SunOS 5.9: /kernel/drv/md Patch"},
+{113030,2,1,29,0,0,"Dec/18/2002: SunOS 5.9: /kernel/sys/doorfs Patch"},
+{113033,3,1,29,0,0,"Dec/24/2002: SunOS 5.9: patch /kernel/drv/isp and /kernel/drv/sparcv9/isp"},
+{113068,4,1,29,0,0,"May/16/2003: SunOS 5.9: hpc3130 patch"},
+{113073,5,1,29,0,0,"Sep/25/2003: SunOS 5.9: ufs_log patch"},
+{113077,9,1,29,0,0,"Sep/24/2003: SunOS 5.9: /platform/sun4u/kernal/drv/su Patch"},
+{113096,3,1,29,0,0,"May/01/2003: X11 6.6.1: OWconfig patch"},
+{113146,2,1,29,0,0,"May/01/2003: SunOS 5.9: Apache Security Patch"},
+{113240,5,1,29,0,0,"Jul/08/2003: CDE 1.5: dtsession patch"},
+{113273,4,1,29,0,0,"Oct/08/2003: SunOS 5.9: /usr/lib/ssh/sshd Patch"},
+{113277,17,1,29,0,0,"Oct/24/2003: SunOS 5.9: sd and ssd Patch"},
+{113278,4,1,29,0,0,"Feb/02/2004: SunOS 5.9: NFS Daemon , rpcmod Patch"},
+{113279,1,1,29,0,0,"Sep/17/2002: SunOS 5.9: klmmod Patch"},
+{113319,17,1,29,0,0,"Dec/15/2003: SunOS 5.9: libnsl nispasswdd patch"},
+{113329,5,1,29,0,0,"Jan/20/2004: SunOS 5.9: lp Patch"},
+{113333,2,1,29,0,0,"Nov/18/2002: SunOS 5.9: libmeta Patch"},
+{113451,6,1,29,0,0,"Jan/22/2004: SunOS 5.9: IKE Patch"},
+{113454,14,1,29,0,0,"Nov/18/2003: SunOS 5.9: ufs Patch"},
+{113464,6,1,29,0,0,"Sep/29/2003: SunOS 5.9: IPMP Headers Patch"},
+{113492,4,1,29,0,0,"Dec/24/2003: SunOS 5.9: fsck Patch"},
+{113573,3,1,29,0,0,"Aug/12/2003: SunOS 5.9: libpsvc Patch"},
+{113574,3,1,29,0,0,"May/23/2003: SunOS 5.9: SUNW,Sun-Fire-880 libpsvc Patch"},
+{113579,1,1,29,0,0,"Nov/08/2002: SunOS 5.9: ypserv/ypxfrd Patch"},
+{113713,11,1,29,0,0,"Nov/04/2003: SunOS 5.9: pkginstall Patch"},
+{113718,2,1,29,0,0,"Jun/04/2003: SunOS 5.9: usr/lib/utmp_update Patch"},
+{113859,3,1,29,0,0,"Dec/24/2003: SunOS 5.9: Sun ONE Directory Server 5.1 patch"},
+{113923,2,1,29,0,0,"Dec/18/2002: X11 6.6.1: security font server patch"},
+{113993,6,1,29,0,0,"Sep/15/2003: SunOS 5.9: mkfs Patch"},
+{114008,1,1,29,0,0,"Mar/19/2003: SunOS 5.9: cachefsd Patch"},
+{114014,3,1,29,0,0,"Apr/01/2003: SunOS 5.9: libxml, libxslt and Freeware man pages Patch"},
+{114016,1,1,29,0,0,"May/01/2003: tomcat security patch"},
+{114125,1,1,29,0,0,"Aug/13/2003: SunOS 5.9: IKE config.sample patch"},
+{114127,2,1,29,0,0,"Dec/24/2003: SunOS 5.9: abi_libefi.so.1 Patch"},
+{114129,1,1,29,0,0,"Mar/31/2003: SunOS 5.9: multi-terabyte disk support -libuuid patch"},
+{114133,1,1,29,0,0,"Feb/03/2003: SunOS 5.9: mail Patch"},
+{114135,1,1,29,0,0,"Jan/22/2003: SunOS 5.9: at utility Patch"},
+{114332,7,1,29,0,0,"Oct/01/2003: SunOS 5.9: c2audit & *libbsm.so.1 Patch"},
+{114359,1,1,29,0,0,"Mar/03/2003: SunOS 5.9: mc-us3 Patch"},
+{114361,1,1,29,0,0,"Apr/30/2003: SunOS 5.9: /kernel/drv/lofi Patch"},
+{114363,2,1,29,0,0,"Jan/27/2004: SunOS 5.9: sort Patch"},
+{114375,6,1,29,0,0,"Jul/25/2003: SunOS 5.9: Enchilada/Stiletto - PICL & FRUID"},
+{114385,3,1,29,0,0,"Aug/04/2003: SunOS 5.9: Enchilada/Stiletto - pmugpio pmubus driver"},
+{114482,4,1,29,0,0,"Sep/02/2003: SunOS 5.9: Product Registry CLI Revision"},
+{114495,1,1,29,0,0,"Dec/03/2003: CDE 1.5: dtprintinfo patch"},
+{114564,3,1,29,0,0,"Nov/14/2003: SunOS 5.9: /usr/sbin/in.ftpd Patch"},
+{114569,2,1,29,0,0,"Apr/24/2003: SunOS 5.9: libdbm.so.1 Patch"},
+{114571,1,1,29,0,0,"Apr/04/2003: SunOS 5.9: libc.so.*.9/bcp Patch"},
+{114636,2,1,29,0,0,"Aug/06/2003: SunOS 5.9: KCMS security fix"},
+{114684,2,1,29,0,0,"May/27/2003: SunOS 5.9: samba Patch"},
+{114713,1,1,29,0,0,"Mar/26/2003: SunOS 5.9: newtask Patch"},
+{114721,4,1,29,0,0,"Sep/15/2003: SunOS 5.9: ufsrestore and ufsdump Patch"},
+{114729,1,1,29,0,0,"May/29/2003: SunOS 5.9: usr/sbin/in.telnetd Patch"},
+{114861,1,1,29,0,0,"Apr/22/2003: SunOS 5.9: /usr/sbin/wall"},
+{114864,2,1,29,0,0,"Jun/13/2003: SunOS 5.9: Sun-Fire-480R libpsvcpolicy_psr.so.1 Patch"},
+{114971,1,1,29,0,0,"Sep/04/2003: SunOS 5.9: usr/kernel/fs/namefs Patch"},
+{115172,1,1,29,0,0,"Sep/15/2003: SunOS 5.9: kernel/drv/le Patch"},
+{115689,1,1,29,0,0,"Jan/27/2004: SunOS 5.9: /usr/lib/patch/patchutil Patch"},
+{115754,2,1,29,0,0,"Oct/21/2003: SunOS 5.9: zlib security Patch"},
+{116237,1,1,29,0,0,"Nov/26/2003: SunOS 5.9: pfexec Patch"},
+{116245,1,1,29,0,0,"Jan/27/2004: SunOS 5.9: uncompress Patch"},
diff --git a/ldap/systools/viewcore.c b/ldap/systools/viewcore.c
new file mode 100644
index 00000000..dce91a37
--- /dev/null
+++ b/ldap/systools/viewcore.c
@@ -0,0 +1,464 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <fcntl.h>
+#include <stdio.h>
+#ifdef linux
+#include <elf.h>
+#include <libelf/libelf.h>
+#else
+#if defined(__osf__)
+#include <elf_abi.h>
+#else
+#ifndef _AIX
+#include <libelf.h>
+#endif
+#endif
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+#if defined(sparc) || defined(__sparc)
+#include <sys/elf_SPARC.h>
+#else
+#if !defined(linux) && !defined(_AIX) && !defined(__osf__)
+#include <sys/elf_386.h>
+#endif
+#endif
+
+
+char *reldate = "23-APR-2002";
+
+char *ofname = NULL;
+FILE *of = NULL;
+
+static void failure(char *s);
+
+struct segment {
+ char *vaddr;
+ int len;
+ char *physaddr;
+};
+
+struct segment segments[65536];
+int segment_max;
+
+char *modes[8] = { "---", "--X", "-W-", "-WX", "R--", "R-X", "RW-", "RWX" };
+
+char *erf;
+char *erf2;
+
+char *find_string(char *addr,int l)
+{
+ int i,off,j;
+ char *np;
+
+ for (i = 0; i < segment_max;i++) {
+ if (addr >= segments[i].vaddr &&
+ addr <= (segments[i].vaddr + segments[i].len)) {
+ off = addr - segments[i].vaddr;
+
+ np = segments[i].physaddr + off;
+
+
+ for (j = 0; j < 256; j++) {
+ if (np[j] == '\0') {
+ return np;
+ }
+ if (!isascii(np[j])) {
+ break;
+ }
+ }
+ if (l) {
+ return("<bad pointer>");
+ }
+ return NULL;
+ }
+ }
+ if (l) {
+ return "<out of segment>";
+ }
+ return NULL;
+}
+
+struct iii_msgarray {
+ unsigned int magic1;
+ unsigned int magic2;
+ unsigned int pos;
+ unsigned int magic4;
+ void *pointers[128][5];
+} iii_msgarray;
+
+
+void view_debug(char *cp)
+{
+ int i;
+ char *s;
+ char *s2;
+ struct iii_msgarray *p = (struct iii_msgarray *)cp;
+
+ for (i = 0; i < 128; i++) {
+ int dl;
+ int j,ap = 1;
+
+ if (p->pointers[i][1] == NULL) continue;
+
+ if (i == p->pos) {
+ fprintf(of,"*");
+ } else {
+ fprintf(of," ");
+ }
+
+ dl = (int)p->pointers[i][0];
+ switch(dl) {
+ case 0:
+ fprintf(of,"E ");
+ break;
+ case 1:
+ fprintf(of," ");
+ break;
+ case 4:
+ fprintf(of,"A ");
+ break;
+ case 8:
+ fprintf(of,"C ");
+ break;
+ case 64:
+ fprintf(of,"G ");
+ break;
+ case 4096:
+ fprintf(of,"R ");
+ break;
+ case 0xffff:
+ fprintf(of,"A ");
+ break;
+ default:
+ fprintf(of," %5d ",p->pointers[i][0]);
+ }
+
+ s = find_string(p->pointers[i][1],1);
+
+ for (j = 0; s[j] != '\0'; j++) {
+ if (s[j] == '\n') break;
+ if (s[j] == '%') {
+ if (s[j+1] == 'l') j++;
+
+ switch(s[j+1]) {
+ case '%':
+ default:
+ fprintf(of,"%c",s[j+1]);
+ break;
+ case 'x':
+ ap++;
+ if (ap >= 5) {
+ fprintf(of,"(? (%%x)");
+ } else {
+ fprintf(of,"%x", p->pointers[i][ap]);
+ }
+ break;
+ case 'd':
+ ap++;
+ if (ap >= 5) {
+ fprintf(of,"(? (%%d)");
+ } else {
+ fprintf(of,"%d", p->pointers[i][ap]);
+ }
+ break;
+ case 's':
+ ap++;
+ if (ap >= 5) {
+ fprintf(of,"(? (%%s)");
+ } else {
+ s2 = find_string(p->pointers[i][ap],0);
+ if (s2) {
+ fprintf(of,"%s", s2);
+ } else {
+ fprintf(of,"(0x%x)", p->pointers[i][ap]);
+ }
+ }
+ break;
+ }
+ j++;
+ } else {
+ fprintf(of,"%c",s[j]);
+ }
+ }
+ fprintf(of,"\n");
+ }
+}
+
+int seek_debug(char *erf,int start, int mx)
+{
+ int i;
+ unsigned int m1 = 0x0abbccdd;
+ unsigned int m2 = 0xdeadbeef;
+
+ for (i=start; i < mx; i+= sizeof(m1)) {
+ if (memcmp(&erf[i],&m1,sizeof(m1)) == 0 &&
+ memcmp(&erf[i+4],&m2,sizeof(m2)) == 0) {
+ view_debug(&erf[i]);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#if !defined(_AIX) && !defined(__osf__)
+void add_segment(Elf32_Phdr *phdr,char *base,int which)
+{
+ int i;
+
+ i = segment_max;
+
+ if (i >= 65536) {
+ fprintf(of,"too many segments\n");
+ exit(1);
+ }
+ i++;
+ segment_max = i;
+
+ segments[i].vaddr = (char *)phdr->p_vaddr;
+ segments[i].len = phdr->p_filesz;
+ segments[i].physaddr = base + phdr->p_offset;
+}
+
+void load_segments(Elf *elf,int phnum,char *base,int flen, int which)
+{
+ Elf32_Phdr *phdr;
+ int i;
+
+
+ phdr = elf32_getphdr(elf);
+
+ if (phdr == NULL) {
+ failure("getphdr");
+ }
+
+ /* printf("headers at %d\n",ehdr->e_phoff); */
+
+ for (i = 0; i < phnum; i++) {
+ if (phdr[i].p_type == PT_NOTE) {
+ if (which) {
+ fprintf(of,"%d: NOTE offset=0x%x filesz=0x%x flags=%d align=%d\n",
+ i, phdr[i].p_offset,
+ phdr[i].p_filesz,
+ phdr[i].p_flags, phdr[i].p_align);
+ }
+
+ } else if (phdr[i].p_type == PT_LOAD) {
+ if (which) {
+ fprintf(of,"%d: LOAD vaddr=0x%x filesz=0x%x memsz=0x%x mode=%s\n",
+ i, phdr[i].p_vaddr,
+ phdr[i].p_filesz, phdr[i].p_memsz,
+ modes[phdr[i].p_flags & 0x7]);
+ }
+
+ if (phdr[i].p_offset && phdr[i].p_filesz) {
+ if (phdr[i].p_offset + phdr[i].p_filesz > flen) {
+ fprintf(of,"%d: segment out of range - core file is incomplete.\n",i);
+ continue;
+ }
+ }
+
+ if ((phdr[i].p_flags == 7 || phdr[i].p_flags == 5) && phdr[i].p_filesz) {
+ add_segment(&phdr[i],base,which);
+ }
+ } else {
+
+ if (which) {
+ fprintf(of,"%d: type=%d offset=0x%x vaddr=0x%x p=0x%x filesz=%d memsz=%d flags=%d align=%d\n",
+ i, phdr[i].p_type,phdr[i].p_offset, phdr[i].p_vaddr,
+ phdr[i].p_paddr, phdr[i].p_filesz, phdr[i].p_memsz,
+ phdr[i].p_flags, phdr[i].p_align);
+ }
+ }
+ }
+}
+
+#endif
+
+void try_adb(char *pf,char *cf)
+{
+ char buf[2048];
+ FILE *p;
+
+ if (ofname != NULL) {
+ sprintf(buf,"/usr/bin/adb %s %s >>%s",pf,cf,ofname);
+ } else {
+ sprintf(buf,"/usr/bin/adb %s %s",pf,cf);
+ }
+
+ p = popen(buf,"w");
+
+ if (p == NULL) {
+ perror(buf);
+ return;
+ }
+
+ fprintf(p,"$L\n");
+ fprintf(p,"$m\n");
+ fprintf(p,"$?\n");
+ fprintf(p,"$C\n");
+#ifdef notanymore
+ fprintf(p,"sls_release_date /S\n");
+ fprintf(p,"lash_release_date /S\n");
+#endif
+
+ fprintf(p,"$q\n");
+ pclose(p);
+}
+
+void
+main(int argc, char ** argv)
+{
+#if !defined(_AIX) && !defined(__osf__)
+ Elf32_Ehdr * ehdr;
+ Elf32_Phdr * phdr;
+ Elf * elf;
+ Elf * elf2;
+ int fd,fd2;
+ int exf = 0;
+ int i;
+ size_t flen = 0;
+ size_t flen2 = 0;
+ time_t t;
+
+ if (of == NULL) {
+ of = stdout;
+ }
+
+ time(&t);
+
+ if (argc != 4) {
+ fprintf(of,"Core analysis %s needs three arguments: executable, core file, dest file\n",
+ reldate);
+ exit(1);
+ }
+
+ ofname = argv[3];
+ of = fopen(ofname,"a");
+
+ fprintf(of,"Core analysis %s. Copyright 2001 Sun Microsystems, Inc.\nPortions copyright 1999, 2001-2003 Netscape Communications Corporation.\nAll rights reserved.\nCurrently %sOpening %s %s\n",reldate,ctime(&t),argv[1],argv[2]);
+
+ if ((fd2 = open(argv[1], O_RDONLY)) == -1) {
+ perror(argv[1]);
+ exit(1);
+ }
+ (void) elf_version(EV_CURRENT);
+ /* Obtain the ELF descriptor */
+ if ((elf2 = elf_begin(fd2, ELF_C_READ, NULL)) == NULL)
+ failure("beginining");
+
+ if ((erf2 = elf_rawfile(elf2,&flen2)) == NULL) {
+ failure("elf_rawfile");
+ }
+
+ /* Obtain the .shstrtab data buffer */
+ if ((ehdr = elf32_getehdr(elf2)) == NULL) {
+ failure("reading header");
+ }
+
+ if (ehdr->e_type == ET_CORE) {
+ fprintf(of,"Executable file should be given as the first argument.\n");
+ exit(1);
+ }
+
+ if (ehdr->e_machine == EM_SPARC ||
+ ehdr->e_machine == EM_SPARC32PLUS ||
+ ehdr->e_machine == EM_SPARCV9) {
+ fprintf(of,"architecture is SPARC\n");
+ exf = EM_SPARC;
+ } else if (ehdr->e_machine == EM_386) {
+ fprintf(of,"architecture is x86\n");
+ exf = ehdr->e_machine;
+ } else {
+ fprintf(of,"unknown architecture %d\n",ehdr->e_machine);
+ exit(1);
+ }
+
+
+ if (ehdr->e_phnum == 0) {
+ fprintf(of,"no program header in program file\n");
+ exit(1);
+ }
+
+ load_segments(elf2,ehdr->e_phnum,erf2,flen2,0);
+
+ /* Open the input file */
+ if ((fd = open(argv[2], O_RDONLY)) == -1) {
+ perror(argv[2]);
+ exit(1);
+ }
+
+ /* Obtain the ELF descriptor */
+ if ((elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
+ failure("beginining");
+
+ if ((erf = elf_rawfile(elf,&flen)) == NULL) {
+ failure("elf_rawfile");
+ }
+
+ /* Obtain the .shstrtab data buffer */
+ if ((ehdr = elf32_getehdr(elf)) == NULL) {
+ failure("reading header");
+ }
+
+ if (ehdr->e_type != ET_CORE) {
+ fprintf(of,"second argument is ELF but not a core file\n");
+ exit(1);
+ }
+
+ if (ehdr->e_machine != exf) {
+ fprintf(of,"Architecture mismatch between executable and core file.\n");
+ exit(1);
+ }
+
+ if (ehdr->e_phnum == 0) {
+ fprintf(of,"no program header in core file\n");
+ exit(1);
+ }
+
+ load_segments(elf,ehdr->e_phnum,erf,flen,1);
+
+
+#ifdef notanymore
+ fprintf(of,"Seeking debug information in core file.\n");
+
+ phdr = elf32_getphdr(elf);
+
+ for (i = 0; i < ehdr->e_phnum; i++) {
+ if (phdr[i].p_type == PT_LOAD) {
+
+ if (phdr[i].p_offset && phdr[i].p_filesz) {
+ if (phdr[i].p_offset + phdr[i].p_filesz > flen) {
+ continue;
+ }
+ if (seek_debug(erf,phdr[i].p_offset,phdr[i].p_filesz)) {
+ break;
+ }
+ }
+
+ }
+ }
+#endif
+
+ if (of != stdout) {
+ fclose(of);
+ }
+
+ try_adb(argv[1],argv[2]);
+
+#endif
+}
+
+static void
+failure(char *msg)
+{
+ fprintf(of, "%s: %s\n", msg, elf_errmsg(elf_errno()));
+ exit(1);
+}
diff --git a/lib/base/Makefile b/lib/base/Makefile
new file mode 100644
index 00000000..f58195d3
--- /dev/null
+++ b/lib/base/Makefile
@@ -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
+#
+# The base library contains the base set of functionality for ldapserver
+# servers. Cross-platform I/O and other generic functions are
+# provided here.
+
+
+MCOM_ROOT=../../..
+MODULE=LibBase
+
+include ../../nsdefs.mk
+
+OBJDEST=$(OBJDIR)/lib/base
+
+ifeq ($(ARCH), WINNT)
+LIBS=$(OBJDIR)/lib/libbase.lib
+ifeq ($(BSCINFO), yes)
+BSCS=$(OBJDIR)/lib/libbase.bsc
+endif
+else
+LIBS=$(OBJDIR)/lib/libbase.a
+endif
+
+include ../../nsconfig.mk
+
+MCC_INCLUDE += $(ADMINUTIL_INCLUDE)
+
+LOCAL_DEPS = $(NSPR_DEP) $(ADMINUTIL_DEP) $(SECURITY_DEP) $(DBM_DEP)
+
+all: $(LOCAL_DEPS) $(OBJDEST) $(LIBS) $(BSCS)
+
+$(OBJDEST):
+ mkdir -p $(OBJDEST)
+
+ifeq ($(ARCH), WINNT)
+OSOBJS = nterrors.o eventlog.o eventhandler.o ntpipe.o pathnames.o
+else
+OSOBJS =
+endif
+
+OBJS = $(addprefix $(OBJDEST)/, \
+ dstats.o \
+ daemon.o \
+ shexp.o \
+ regexp.o \
+ pblock.o \
+ plist.o \
+ buffer.o \
+ netbuf.o \
+ file.o \
+ net.o \
+ session.o \
+ cinfo.o \
+ util.o \
+ ereport.o \
+ sem.o \
+ fsmutex.o \
+ systhr.o \
+ crit.o \
+ rwlock.o \
+ dns.o \
+ dnsdmain.o \
+ shmem.o \
+ dll.o \
+ servssl.o \
+ lexer.o \
+ restart.o \
+ objndx.o \
+ cache.o \
+ pool.o \
+ time_cache.o \
+ dns_cache.o \
+ system.o \
+ xp.o \
+ nscperror.o \
+ language.o \
+ fasttime.o \
+ secpwd.o \
+ $(OSOBJS) \
+ )
+
+MODULE_CFLAGS=-I$(NSROOT)/include/base
+
+ifeq ($(PRODUCT),"Netscape Catalog Server")
+ifeq ($(ARCH), WINNT)
+MCC_INCLUDE := $(subst -I$(MCOM_ROOT)/lib/libnet,,$(MCC_INCLUDE))
+endif
+endif
+
+#$(OBJDEST)/fasttime.o : $(OBJDIR)/fasttime.o
+# cp $< $@
+
+$(LIBS): $(OBJS)
+ rm -f $@
+ $(AR) $(OBJS)
+ $(RANLIB) $@
+
+ifeq ($(ARCH), WINNT)
+ifeq ($(BSCINFO), yes)
+$(BSCS): $(OBJS)
+ $(BSCMAKE) $(OBJDEST)/*.sbr
+endif
+endif
+
+include $(INCLUDE_DEPENDS)
+
diff --git a/lib/base/crit.cpp b/lib/base/crit.cpp
new file mode 100644
index 00000000..06f5fba4
--- /dev/null
+++ b/lib/base/crit.cpp
@@ -0,0 +1,399 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * crit.c: Critical section abstraction. Used in threaded servers to protect
+ * areas where two threads can interfere with each other.
+ *
+ * Condvars are condition variables that are used for thread-thread
+ * synchronization.
+ *
+ * Rob McCool
+ */
+
+#include "systems.h"
+
+#include "netsite.h"
+#include "crit.h"
+#include "pool.h"
+#include "ereport.h"
+
+#include "base/dbtbase.h"
+
+#ifdef USE_NSPR
+/*
+#include "prmon.h"
+#include "private/primpl.h"
+*/
+#include "nspr.h"
+
+/* private/primpl.h is gone fromnspr21 19971028 */
+#if 0
+#ifdef XP_WIN32
+#include "private/primpl.h"
+#endif /* XP_WIN32 */
+#endif
+
+#include "prthread.h"
+#include "prlock.h"
+#include "prcvar.h"
+#include "prinrval.h"
+
+/*
+ * Defined to replace PR_Monitor() with PR_Lock().
+ */
+typedef struct critical {
+ PRLock *lock;
+ PRUint32 count;
+ PRThread *owner;
+} critical_t;
+
+typedef struct condvar {
+ critical_t *lock;
+ PRCondVar *cvar;
+} condvar_t;
+
+#endif
+/* -------------------------- critical sections --------------------------- */
+
+/* Useful for ASSERTs only. Returns non-zero if the current thread is the owner.
+ */
+NSAPI_PUBLIC int crit_owner_is_me(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+
+ return (crit->owner == PR_GetCurrentThread());
+#else
+ return 1;
+#endif
+}
+
+NSAPI_PUBLIC CRITICAL crit_init(void)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)PERM_MALLOC(sizeof(critical_t)) ;
+
+ if (crit) {
+ if (!(crit->lock = PR_NewLock())) {
+ PERM_FREE(crit);
+ return NULL;
+ }
+ crit->count = 0;
+ crit->owner = 0;
+ }
+ return (void *) crit;
+#else
+ return NULL;
+#endif
+}
+
+NSAPI_PUBLIC void crit_enter(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+ PRThread *me = PR_GetCurrentThread();
+
+ if ( crit->owner == me) {
+ NS_ASSERT(crit->count > 0);
+ crit->count++;
+ }
+ else {
+ PR_Lock(crit->lock);
+ NS_ASSERT(crit->count == 0);
+ crit->count = 1;
+ crit->owner = me;
+ }
+#endif
+}
+
+NSAPI_PUBLIC void crit_exit(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+
+ if (crit->owner != PR_GetCurrentThread())
+ return;
+
+ if ( --crit->count == 0) {
+ crit->owner = 0;
+ PR_Unlock(crit->lock);
+ }
+ NS_ASSERT(crit->count >= 0);
+#endif
+}
+
+NSAPI_PUBLIC void crit_terminate(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+
+ PR_DestroyLock((PRLock*)crit->lock);
+ PERM_FREE(crit);
+#endif
+}
+
+
+/* ------------------------- condition variables -------------------------- */
+
+
+NSAPI_PUBLIC CONDVAR condvar_init(CRITICAL id)
+{
+#ifdef USE_NSPR
+ critical_t *crit = (critical_t*)id;
+
+ condvar_t *cvar = (condvar_t*)PERM_MALLOC(sizeof(condvar_t)) ;
+
+ if (crit) {
+ cvar->lock = crit;
+ if ((cvar->cvar = PR_NewCondVar((PRLock *)cvar->lock->lock)) == 0) {
+ PERM_FREE(cvar);
+ return NULL;
+ }
+ }
+ return (void *) cvar;
+#endif
+}
+
+NSAPI_PUBLIC void condvar_wait(CONDVAR _cv)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ /* Save away recursion count so we can restore it after the wait */
+ int saveCount = cv->lock->count;
+ PRThread *saveOwner = cv->lock->owner;
+
+ NS_ASSERT(cv->lock->owner == PR_GetCurrentThread());
+ cv->lock->count = 0;
+ cv->lock->owner = 0;
+
+ PR_WaitCondVar(cv->cvar, PR_INTERVAL_NO_TIMEOUT);
+
+ cv->lock->count = saveCount;
+ cv->lock->owner = saveOwner;
+#endif
+}
+
+
+NSAPI_PUBLIC void condvar_timed_wait(CONDVAR _cv, long secs)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ /* Save away recursion count so we can restore it after the wait */
+ int saveCount = cv->lock->count;
+ PRThread *saveOwner = cv->lock->owner;
+
+ NS_ASSERT(cv->lock->owner == PR_GetCurrentThread());
+ cv->lock->count = 0;
+ cv->lock->owner = 0;
+
+ PRIntervalTime timeout = PR_INTERVAL_NO_TIMEOUT;
+ if (secs > 0)
+ timeout = PR_SecondsToInterval(secs);
+ PR_WaitCondVar(cv->cvar, timeout);
+
+ cv->lock->count = saveCount;
+ cv->lock->owner = saveOwner;
+#endif
+}
+
+
+
+NSAPI_PUBLIC void condvar_notify(CONDVAR _cv)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ NS_ASSERT(cv->lock->owner == PR_GetCurrentThread());
+ PR_NotifyCondVar(cv->cvar);
+#endif
+}
+
+NSAPI_PUBLIC void condvar_notifyAll(CONDVAR _cv)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ NS_ASSERT(cv->lock->owner == PR_GetCurrentThread());
+ PR_NotifyAllCondVar(cv->cvar);
+#endif
+}
+
+NSAPI_PUBLIC void condvar_terminate(CONDVAR _cv)
+{
+#ifdef USE_NSPR
+ condvar_t *cv = (condvar_t *)_cv;
+ PR_DestroyCondVar(cv->cvar);
+ PERM_FREE(cv);
+#endif
+}
+
+/* ----------------------- Counting semaphores ---------------------------- */
+/* These are currently not listed in crit.h because they aren't yet used;
+ * although they do work.
+ */
+
+/*
+ * XXXMB - these should be in NSPR.
+ *
+ */
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+#include <synch.h>
+typedef sema_t counting_sem_t;
+#elif defined(IRIX) && defined(HW_THREADS)
+#include <ulocks.h>
+typedef usema_t *counting_sem_t;
+#else
+typedef struct counting_sem_t {
+ CRITICAL lock;
+ CRITICAL cv_lock;
+ CONDVAR cv;
+ int count;
+ int max;
+} counting_sem_t;
+#endif
+
+NSAPI_PUBLIC COUNTING_SEMAPHORE
+cs_init(int initial_count)
+{
+ counting_sem_t *cs = (counting_sem_t *)PERM_MALLOC(sizeof(counting_sem_t));
+#if defined(SOLARIS) && defined(HW_THREADS)
+ if ( sema_init(cs, initial_count, USYNC_THREAD, NULL) < 0) {
+ ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csInitFailureS_), system_errmsg());
+ PERM_FREE(cs);
+ return NULL;
+ }
+
+ return (COUNTING_SEMAPHORE)cs;
+#elif defined(IRIX) && defined(HW_THREADS)
+ usptr_t *arena;
+
+ usconfig(CONF_INITSIZE, 64*1024);
+ if ( (arena = usinit("/tmp/cs.locks")) == NULL)
+ return NULL;
+
+ if ( (cs = (counting_sem_t *)usnewsema(arena, 0)) == NULL)
+ return NULL;
+
+ return cs;
+
+#else
+
+ cs->count = initial_count;
+ cs->lock = crit_init();
+ cs->cv_lock = crit_init();
+ cs->cv = condvar_init(cs->cv_lock);
+
+ return (COUNTING_SEMAPHORE)cs;
+#endif
+}
+
+NSAPI_PUBLIC void
+cs_terminate(COUNTING_SEMAPHORE csp)
+{
+ counting_sem_t *cs = (counting_sem_t *)csp;
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+ if ( sema_destroy(cs) < 0 ) {
+ ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csTerminateFailureS_), system_errmsg());
+ }
+ PERM_FREE(cs);
+ return;
+#elif defined(IRIX) && defined(HW_THREADS)
+ /* usfreesema() */
+ return;
+#else
+ condvar_terminate(cs->cv);
+ crit_terminate(cs->cv_lock);
+ crit_terminate(cs->lock);
+ PERM_FREE(cs);
+
+ return;
+#endif
+}
+
+NSAPI_PUBLIC int
+cs_wait(COUNTING_SEMAPHORE csp)
+{
+ counting_sem_t *cs = (counting_sem_t *)csp;
+ int ret;
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+ if ( (ret = sema_wait(cs)) < 0 ) {
+ ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csWaitFailureS_), system_errmsg());
+ return -1;
+ }
+ return ret;
+#elif defined(IRIX) && defined(HW_THREADS)
+ uspsema(cs);
+ return 0;
+#else
+ crit_enter(cs->lock);
+ while ( cs->count == 0 ) {
+ crit_enter(cs->cv_lock);
+ crit_exit(cs->lock);
+ condvar_wait(cs->cv);
+ crit_exit(cs->cv_lock);
+ crit_enter(cs->lock);
+ }
+ ret = --(cs->count);
+ crit_exit(cs->lock);
+
+ return 0;
+#endif
+}
+
+NSAPI_PUBLIC int
+cs_trywait(COUNTING_SEMAPHORE csp)
+{
+ counting_sem_t *cs = (counting_sem_t *)csp;
+ int ret;
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+ ret = sema_trywait(cs)?-1:0;
+ return ret;
+#elif defined(IRIX) && defined(HW_THREADS)
+ ret = uscpsema(cs);
+ return (ret == 1)?0:-1;
+#else
+ crit_enter(cs->lock);
+ if (cs->count > 0) {
+ ret = --(cs->count);
+ crit_exit(cs->lock);
+ return 0;
+ }
+ crit_exit(cs->lock);
+ return -1;
+
+#endif
+}
+
+NSAPI_PUBLIC int
+cs_release(COUNTING_SEMAPHORE csp)
+{
+ counting_sem_t *cs = (counting_sem_t *)csp;
+ int ret;
+
+#if defined(SOLARIS) && defined(HW_THREADS)
+ if ( (ret = sema_post(cs)) < 0 ) {
+ ereport(LOG_FAILURE, XP_GetAdminStr(DBT_csPostFailureS_), system_errmsg());
+ return -1;
+ }
+ return ret;
+#elif defined(IRIX) && defined(HW_THREADS)
+ usvsema(cs);
+ return 0;
+#else
+ crit_enter(cs->lock);
+ ret = ++(cs->count);
+ if (cs->count == 1) {
+ crit_enter(cs->cv_lock);
+ condvar_notify(cs->cv);
+ crit_exit(cs->cv_lock);
+ }
+ crit_exit(cs->lock);
+
+ return 0;
+#endif
+}
diff --git a/lib/base/dns.cpp b/lib/base/dns.cpp
new file mode 100644
index 00000000..f9e38886
--- /dev/null
+++ b/lib/base/dns.cpp
@@ -0,0 +1,176 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * dns.c: DNS resolution routines
+ *
+ * Rob McCool
+ */
+#define DNS_GUESSING
+
+#include "netsite.h"
+#ifdef XP_UNIX
+#include "systems.h"
+#else /* XP_WIN32 */
+#include "base/systems.h"
+#endif /* XP_WIN32 */
+
+#include "net.h" /* SYS_NETFD, various headers to do DNS */
+
+/* Under NT, these are taken care of by net.h including winsock.h */
+#ifdef XP_UNIX
+#include <arpa/inet.h> /* inet_ntoa */
+#include <netdb.h> /* struct hostent */
+#ifdef NEED_GHN_PROTO
+extern "C" int gethostname (char *name, size_t namelen);
+#endif
+#endif
+#ifdef DNS_CACHE
+#include "base/dns_cache.h"
+#include "base/ereport.h"
+#endif /* DNS_CACHE */
+#include <stdio.h>
+#include <nspr.h>
+#include "frame/conf.h"
+
+/* ---------------------------- dns_find_fqdn ----------------------------- */
+
+
+/* defined in dnsdmain.c */
+extern "C" NSAPI_PUBLIC char *dns_guess_domain(char * hname);
+
+char *net_find_fqdn(PRHostEnt *p)
+{
+ int x;
+
+ if((!p->h_name) || (!p->h_aliases))
+ return NULL;
+
+ if(!strchr(p->h_name, '.')) {
+ for(x = 0; p->h_aliases[x]; ++x) {
+ if((strchr(p->h_aliases[x], '.')) &&
+ (!strncmp(p->h_aliases[x], p->h_name, strlen(p->h_name))))
+ {
+ return STRDUP(p->h_aliases[x]);
+ }
+ }
+#ifdef DNS_GUESSING
+ return dns_guess_domain(p->h_name);
+#else
+ return NULL;
+#endif /* DNS_GUESSING */
+ }
+ else
+ return STRDUP(p->h_name);
+}
+
+
+/* ----------------------------- dns_ip2host ------------------------------ */
+
+
+char *dns_ip2host(char *ip, int verify)
+{
+ /* struct in_addr iaddr; */
+ PRNetAddr iaddr;
+ char *hn;
+#ifdef DNS_CACHE
+ dns_cache_entry_t *dns_entry;
+#endif
+ static unsigned long laddr = 0;
+ static char myhostname[256];
+ PRHostEnt hent;
+ char buf[PR_NETDB_BUF_SIZE];
+ PRStatus err;
+
+
+ err = PR_InitializeNetAddr(PR_IpAddrNull, 0, &iaddr);
+
+ if((iaddr.inet.ip = inet_addr(ip)) == -1)
+ goto bong;
+
+#ifdef DNS_CACHE
+ if ( (dns_entry = dns_cache_lookup_ip((unsigned int)iaddr.inet.ip)) ) {
+ hn = NULL;
+ if ( dns_entry->host &&
+ /* Only use entry if the cache entry has been verified or if
+ * verify is off...
+ */
+ (dns_entry->verified || !verify) ) {
+ hn = STRDUP( dns_entry->host );
+ (void)dns_cache_use_decrement(dns_entry);
+ return hn;
+ }
+ dns_cache_delete(dns_entry);
+ dns_entry = 0;
+ }
+#endif
+
+ /*
+ * See if it happens to be the localhost IP address, and try
+ * the local host name if so.
+ */
+ if (laddr == 0) {
+ laddr = inet_addr("127.0.0.1");
+ myhostname[0] = 0;
+ PR_GetSystemInfo(PR_SI_HOSTNAME, myhostname, sizeof(myhostname));
+ }
+
+ /* Have to match the localhost IP address and have a hostname */
+ if ((iaddr.inet.ip == laddr) && (myhostname[0] != 0)) {
+ /*
+ * Now try for a fully-qualified domain name, starting with
+ * the local hostname.
+ */
+ err = PR_GetHostByName(myhostname,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+
+ /* Don't verify if we get a fully-qualified name this way */
+ verify = 0;
+ }
+ else {
+ err = PR_GetHostByAddr(&iaddr,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+ }
+
+ if ((err == PR_FAILURE) || !(hn = net_find_fqdn(&hent))) goto bong;
+
+
+ if(verify) {
+ char **haddr = 0;
+ err = PR_GetHostByName(hn,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+
+ if(err == PR_SUCCESS) {
+ for(haddr = hent.h_addr_list; *haddr; haddr++) {
+ if(((struct in_addr *)(*haddr))->s_addr == iaddr.inet.ip)
+ break;
+ }
+ }
+
+ if((err == PR_FAILURE) || (!(*haddr)))
+ goto bong;
+ }
+
+#ifdef DNS_CACHE
+ if ( (dns_entry = dns_cache_insert(hn, (unsigned int)iaddr.inet.ip, verify)) ) {
+ (void) dns_cache_use_decrement(dns_entry);
+ }
+#endif /* DNS_CACHE */
+ return hn;
+ bong:
+#ifdef DNS_CACHE
+ /* Insert the lookup failure */
+ if ( (dns_entry = dns_cache_insert(NULL, (unsigned int)iaddr.inet.ip, verify)) ) {
+ (void) dns_cache_use_decrement(dns_entry);
+ }
+#endif /* DNS_CACHE */
+ return NULL;
+}
diff --git a/lib/base/dnsdmain.cpp b/lib/base/dnsdmain.cpp
new file mode 100644
index 00000000..f37e475c
--- /dev/null
+++ b/lib/base/dnsdmain.cpp
@@ -0,0 +1,159 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * dnsdmain.c: DNS domain guessing stuff moved out of dns.c because of the
+ * string ball problems
+ */
+
+
+#include "netsite.h"
+#include "base/net.h"
+#include <string.h>
+#include <stdio.h>
+#ifdef XP_UNIX
+#include <unistd.h>
+#endif
+#include <ctype.h>
+#include "util.h"
+
+/* Under NT, this is taken care of by net.h including winsock.h */
+#ifdef XP_UNIX
+#include <netdb.h> /* struct hostent */
+#endif
+extern "C" {
+#include <nspr.h>
+}
+#include "frame/conf.h"
+
+
+
+/* This is contained in resolv.h on most systems. */
+#define _PATH_RESCONF "/etc/resolv.conf"
+
+#ifdef XP_UNIX
+NSPR_BEGIN_EXTERN_C
+#ifdef Linux
+extern int getdomainname(char *, size_t);
+#else
+extern int getdomainname(char *, int);
+#endif /* Linux */
+#if defined(HPUX) || defined (UnixWare) || defined(Linux) || defined(IRIX6_5)
+extern int gethostname (char *name, size_t namelen);
+#else
+#ifndef AIX
+extern int gethostname (char *name, int namelen);
+#endif
+#endif
+NSPR_END_EXTERN_C
+#endif
+
+
+/* ---------------------------- dns_guess_domain -------------------------- */
+
+
+extern "C" NSAPI_PUBLIC char *dns_guess_domain(char * hname)
+{
+ FILE *f;
+ char * cp;
+ int hnlen;
+ char line[256];
+ static int dnlen = 0;
+ static char * domain = 0;
+ PRHostEnt hent;
+ char buf[PR_NETDB_BUF_SIZE];
+ PRStatus err;
+
+ /* Sanity check */
+ if (strchr(hname, '.')) {
+ return STRDUP(hname);
+ }
+
+ if (dnlen == 0) {
+
+ /* First try a little trick that seems to often work... */
+
+ /*
+ * Get the local host name, even it doesn't come back
+ * fully qualified.
+ */
+ line[0] = 0;
+ gethostname(line, sizeof(line));
+ if (line[0] != 0) {
+ /* Is it fully qualified? */
+ domain = strchr(line, '.');
+ if (domain == 0) {
+ /* No, try gethostbyname() */
+ err = PR_GetHostByName(line,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+ if (err == PR_SUCCESS) {
+ /* See if h_name is fully-qualified */
+ if (hent.h_name) domain = strchr(hent.h_name, '.');
+
+ /* Otherwise look for a fully qualified alias */
+ if ((domain == 0) &&
+ (hent.h_aliases && hent.h_aliases[0])) {
+ char **p;
+ for (p = hent.h_aliases; *p; ++p) {
+ domain = strchr(*p, '.');
+ if (domain) break;
+ }
+ }
+ }
+ }
+ }
+
+ /* Still no luck? */
+ if (domain == 0) {
+
+ f = fopen(_PATH_RESCONF, "r");
+
+ /* See if there's a domain entry in their resolver configuration */
+ if(f) {
+ while(fgets(line, sizeof(line), f)) {
+ if(!strncasecmp(line, "domain ", 7)) {
+ for (cp = &line[7]; *cp && isspace(*cp); ++cp) ;
+ if (*cp) {
+ domain = cp;
+ for (; *cp && !isspace(*cp); ++cp) ;
+ *cp = 0;
+ }
+ break;
+ }
+ }
+ fclose(f);
+ }
+ }
+
+#ifndef NO_DOMAINNAME
+ if (domain == 0) {
+ /* No domain found. Try getdomainname. */
+ getdomainname(line, sizeof(line));
+ if (line[0] != 0) domain = &line[0];
+ }
+#endif
+
+ if (domain != 0) {
+ if (domain[0] == '.') ++domain;
+ domain = STRDUP(domain);
+ dnlen = strlen(domain);
+ }
+ else dnlen = -1;
+ }
+
+ if (domain != 0) {
+ hnlen = strlen(hname);
+ if ((hnlen + dnlen + 2) <= sizeof(line)) {
+ strcpy(line, hname);
+ line[hnlen] = '.';
+ strcpy(&line[hnlen+1], domain);
+ return STRDUP(line);
+ }
+ }
+
+ return 0;
+}
diff --git a/lib/base/ereport.cpp b/lib/base/ereport.cpp
new file mode 100644
index 00000000..3454d01f
--- /dev/null
+++ b/lib/base/ereport.cpp
@@ -0,0 +1,249 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * ereport.c: Records transactions, reports errors to administrators, etc.
+ *
+ * Rob McCool
+ */
+
+
+#include "private/pprio.h" /* for nspr20 binary release */
+#include "netsite.h"
+#include "file.h" /* system_fopenWA, system_write_atomic */
+#include "pblock.h"
+#include "session.h"
+#include "util.h" /* util_vsprintf */
+#include "ereport.h"
+
+#include "base/dbtbase.h"
+
+#include <stdarg.h>
+#include <stdio.h> /* vsprintf */
+#include <string.h> /* strcpy */
+#include <time.h> /* localtime */
+
+#ifdef XP_UNIX
+#include <syslog.h> /* error logging to syslog */
+
+static SYS_FILE _error_fd;
+#else /* WIN32 */
+#include <nt/regparms.h>
+#include <nt/messages.h>
+#include "eventlog.h"
+
+static SYS_FILE _error_fd;
+#endif /* XP_UNIX */
+
+static PRBool _ereport_initialized = PR_FALSE;
+
+
+NSAPI_PUBLIC SYS_FILE ereport_getfd(void) { return _error_fd; }
+
+
+
+/* ----------------------------- ereport_init ----------------------------- */
+
+
+NSAPI_PUBLIC char *ereport_init(char *err_fn, char *email,
+ PASSWD pwuser, char *version)
+{
+ char err[MAGNUS_ERROR_LEN];
+ SYS_FILE new_fd;
+
+#ifdef XP_UNIX
+ if(!strcmp(err_fn, "SYSLOG")) {
+#ifdef NET_SSL
+ openlog("secure-httpd", LOG_PID, LOG_DAEMON);
+#else
+ openlog("httpd", LOG_PID, LOG_DAEMON);
+#endif
+ _error_fd = PR_ImportFile(ERRORS_TO_SYSLOG);
+
+ _ereport_initialized = PR_TRUE;
+ return NULL;
+ }
+#endif /* XP_UNIX */
+ if( (new_fd = system_fopenWA(err_fn)) == SYS_ERROR_FD) {
+ util_snprintf(err, MAGNUS_ERROR_LEN, "can't open error log %s (%s)", err_fn,
+ system_errmsg());
+#ifdef XP_UNIX
+ _error_fd = PR_ImportFile(STDERR_FILENO);
+#else
+ _error_fd = PR_ImportFile(NULL);
+#endif
+ return STRDUP(err);
+ }
+ _error_fd = new_fd;
+
+#ifdef XP_UNIX
+ if(pwuser)
+ chown(err_fn, pwuser->pw_uid, pwuser->pw_gid);
+#endif /* XP_UNIX */
+
+ _ereport_initialized = PR_TRUE;
+
+ ereport(LOG_INFORM, XP_GetAdminStr(DBT_successfulServerStartup_));
+ ereport(LOG_INFORM, XP_GetAdminStr(DBT_SBS_), MAGNUS_VERSION_STRING, BUILD_NUM);
+ if (strcasecmp(BUILD_NUM, version)) {
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_netscapeExecutableAndSharedLibra_));
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_executableVersionIsS_), version);
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_sharedLibraryVersionIsS_), BUILD_NUM);
+
+ }
+
+ /* Initialize thread-specific error handling */
+ system_errmsg_init();
+
+ return NULL;
+}
+
+
+
+/* -------------------------- ereport_terminate --------------------------- */
+
+
+NSAPI_PUBLIC void ereport_terminate(void)
+{
+ if (!_ereport_initialized)
+ return;
+
+#ifdef XP_UNIX
+ ereport(LOG_INFORM, XP_GetAdminStr(DBT_errorReportingShuttingDown_));
+ if(PR_FileDesc2NativeHandle(_error_fd) != ERRORS_TO_SYSLOG)
+ system_fclose(_error_fd);
+ else
+ closelog();
+#else /* WIN32 */
+ if(PR_FileDesc2NativeHandle(_error_fd) != NULL)
+ system_fclose(_error_fd);
+#endif /* XP_UNIX */
+
+}
+
+
+/* ------------------------------- ereport -------------------------------- */
+
+
+static int degree_msg[] = {
+ DBT_warning_,
+ DBT_config_,
+ DBT_security_,
+ DBT_failure_,
+ DBT_catastrophe_,
+ DBT_info_,
+ DBT_verbose_
+ };
+
+#ifdef XP_UNIX
+static int degree_syslog[] = {
+ LOG_WARNING, LOG_ERR, LOG_NOTICE, LOG_ALERT, LOG_CRIT, LOG_INFO, LOG_INFO
+};
+#endif/* XP_UNIX */
+
+
+NSAPI_PUBLIC int ereport_v(int degree, char *fmt, va_list args)
+{
+ char errstr[MAX_ERROR_LEN];
+ int pos = 0;
+ struct tm *tms, tmss;
+ time_t t;
+#ifdef MCC_PROXY
+ char *p;
+ int i;
+#endif /* MCC_PROXY */
+
+ if (!_ereport_initialized)
+ return IO_OKAY;
+
+#ifdef XP_UNIX
+ if(PR_FileDesc2NativeHandle(_error_fd) != ERRORS_TO_SYSLOG) {
+#endif /* XP_UNIX */
+ t = time(NULL);
+ tms = system_localtime(&t, &tmss);
+ util_strftime(errstr, ERR_TIMEFMT, tms);
+ pos = strlen(errstr);
+
+ pos += util_snprintf(&errstr[pos], MAX_ERROR_LEN - pos, " %s: ",
+ XP_GetAdminStr(degree_msg[degree]));
+#ifdef XP_UNIX
+ }
+#endif /* XP_UNIX */
+
+ pos += util_vsnprintf(&errstr[pos], sizeof(errstr) - pos, fmt, args);
+
+ pos += util_snprintf(&errstr[pos], sizeof(errstr) - pos, ENDLINE);
+
+#ifdef MCC_PROXY
+ /* Thanx to netlib, the proxy sometimes generates multiline err msgs */
+ for(p=errstr, i=pos-1; i>0; i--, p++) {
+ if (*p == '\n' || *p == '\r') *p = ' ';
+ }
+#endif /* MCC_PROXY */
+
+#if defined XP_UNIX
+ if(PR_FileDesc2NativeHandle(_error_fd) != ERRORS_TO_SYSLOG)
+ return system_fwrite_atomic(_error_fd, errstr, pos);
+ syslog(degree_syslog[degree], errstr);
+ return IO_OKAY;
+#elif defined XP_WIN32 /* XP_WIN32 */
+ if(PR_FileDesc2NativeHandle(_error_fd) != NULL)
+ {
+#ifdef MCC_HTTPD
+ /* also write to NT Event Log if error is serious */
+ switch (degree)
+ {
+ case LOG_MISCONFIG:
+ case LOG_SECURITY:
+ case LOG_CATASTROPHE:
+ LogErrorEvent(NULL, EVENTLOG_ERROR_TYPE,
+ 0, MSG_BAD_PARAMETER,
+ errstr, NULL);
+ break;
+ default:
+ break;
+ }
+#endif
+ return system_fwrite_atomic(_error_fd, errstr, pos);
+ }
+ else { /* log to the EventLogger */
+ /* Write to the event logger... */
+ switch (degree) {
+ case LOG_WARN:
+ LogErrorEvent(NULL, EVENTLOG_WARNING_TYPE,
+ 0, MSG_BAD_PARAMETER,
+ errstr, NULL);
+ break;
+ case LOG_MISCONFIG:
+ case LOG_SECURITY:
+ case LOG_FAILURE:
+ case LOG_CATASTROPHE:
+ LogErrorEvent(NULL, EVENTLOG_ERROR_TYPE,
+ 0, MSG_BAD_PARAMETER,
+ errstr, NULL);
+ break;
+
+ case LOG_INFORM:
+ default:
+ LogErrorEvent(NULL, EVENTLOG_INFORMATION_TYPE,
+ 0, MSG_BAD_PARAMETER,
+ errstr, NULL);
+ break;
+ }
+ return (IO_OKAY);
+ }
+#endif /* XP_WIN32 */
+
+}
+
+NSAPI_PUBLIC int ereport(int degree, char *fmt, ...)
+{
+ va_list args;
+ int rv;
+ va_start(args, fmt);
+ rv = ereport_v(degree, fmt, args);
+ va_end(args);
+ return rv;
+}
diff --git a/lib/base/eventlog.cpp b/lib/base/eventlog.cpp
new file mode 100644
index 00000000..b8762842
--- /dev/null
+++ b/lib/base/eventlog.cpp
@@ -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 **/
+// //
+// Name: EVENTLOG //
+// Platforms: WIN32 //
+// ...................................................................... //
+// Revision History: //
+// 01-12-95 Initial Version, Aruna Victor (aruna@netscape.com) //
+// 12-02-96 Code cleanup, Andy Hakim (ahakim@netscape.com) //
+// - consolidated admin and http functions into one //
+// - moved registry modification code to installer //
+// - removed several unecessary functions //
+// - changed function parameters to existing functions //
+// //
+//--------------------------------------------------------------------------//
+
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "netsite.h"
+#include "base/eventlog.h"
+#include "frame/conf.h"
+#include <nt/regparms.h>
+#include <nt/messages.h>
+
+HANDLE ghEventSource;
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC HANDLE InitializeLogging(char *szEventLogName)
+{
+ ghEventSource = RegisterEventSource(NULL, szEventLogName);
+ return ghEventSource;
+}
+
+
+
+NSAPI_PUBLIC BOOL TerminateLogging(HANDLE hEventSource)
+{
+ BOOL bReturn = FALSE;
+ if(hEventSource == NULL)
+ hEventSource = ghEventSource;
+ if(hEventSource)
+ bReturn = DeregisterEventSource(hEventSource);
+ return(bReturn);
+}
+
+
+
+NSAPI_PUBLIC BOOL LogErrorEvent(HANDLE hEventSource, WORD fwEventType, WORD fwCategory, DWORD IDEvent, LPTSTR chMsg, LPTSTR lpszMsg)
+{
+ BOOL bReturn = FALSE;
+ LPTSTR lpszStrings[2];
+
+ lpszStrings[0] = chMsg;
+ lpszStrings[1] = lpszMsg;
+
+ if(hEventSource == NULL)
+ hEventSource = ghEventSource;
+
+ if(hEventSource)
+ bReturn = ReportEvent(hEventSource, fwEventType, fwCategory,
+ IDEvent, NULL, 2, 0, (LPCTSTR *)lpszStrings, NULL);
+ return(bReturn);
+}
+
+NSPR_END_EXTERN_C
diff --git a/lib/base/file.cpp b/lib/base/file.cpp
new file mode 100644
index 00000000..7382be46
--- /dev/null
+++ b/lib/base/file.cpp
@@ -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 **/
+/*
+ * file.c: system specific functions for reading/writing files
+ *
+ * See file.h for formal definitions of what these functions do
+ *
+ * Rob McCool
+ */
+
+
+#include "base/file.h"
+#include "ereport.h"
+#ifdef BSD_RLIMIT
+#include <sys/time.h>
+#include <sys/resource.h>
+#else
+#include <stdlib.h>
+#include <signal.h>
+#endif
+#ifdef XP_WIN32
+#include <time.h> /* time */
+#include <sys/stat.h> /* stat */
+#include <errno.h>
+#include <direct.h>
+#include <base/nterr.h>
+/* Removed for ns security integration
+#include <xp_error.h>
+*/
+#endif
+#include <prerror.h>
+
+#include "private/pprio.h"
+#include "prlock.h"
+
+extern "C" char *nscperror_lookup(int err);
+
+/* --- globals -------------------------------------------------------------*/
+/* PRFileDesc * SYS_ERROR_FD = NULL; */
+
+const int errbuf_size = 256;
+const unsigned int LOCKFILERANGE=0x7FFFFFFF;
+PRLock *_atomic_write_lock = NULL;
+
+/* --------------------------------- stat --------------------------------- */
+
+
+ /* XXXMB - Can't convert to PR_GetFileInfo because we directly exported
+ * the stat interface... Damn.
+ */
+NSAPI_PUBLIC int system_stat(char *path, struct stat *finfo)
+{
+#ifdef XP_WIN32
+
+ int chop, l;
+
+/* The NT stat is very peculiar about directory names. */
+/* XXX aruna - there is a bug here, maybe in the C runtime.
+ * Stating the same path in a separate program succeeds. From
+ * jblack's profiling, this needs to be replaced by the Win32
+ * calls anyway.*/
+
+ l = strlen(path);
+ if((path[l - 1] == '/') &&
+ (!(isalpha(path[0]) && (!strcmp(&path[1], ":/")))))
+ {
+ chop = 1;
+ path[--l] = '\0';
+ }
+ else chop = 0;
+#endif /* XP_WIN32 */
+
+#ifdef XP_UNIX
+ if(stat(path, finfo) == -1)
+ return -1;
+#else /* XP_WIN32 */
+
+ if(_stat(path, (struct _stat *)finfo) == -1) {
+ /* XXXMB - this sucks;
+ * try to convert to an error code we'll expect...
+ */
+ switch(errno) {
+ case ENOENT: PR_SetError(PR_FILE_NOT_FOUND_ERROR, errno); break;
+ default: PR_SetError(PR_UNKNOWN_ERROR, errno); break;
+ }
+ return -1;
+ }
+
+ /* NT sets the time fields to -1 if it thinks that the file
+ * is a device ( like com1.html, lpt1.html etc) In this case
+ * simply set last modified time to the current time....
+ */
+
+ if (finfo->st_mtime == -1) {
+ finfo->st_mtime = time(NULL);
+ }
+ if (finfo->st_atime == -1) {
+ finfo->st_atime = 0;
+ }
+ if (finfo->st_ctime == -1) {
+ finfo->st_ctime = 0;
+ }
+ if(chop)
+ path[l++] = '/';
+
+#endif /* XP_WIN32 */
+
+ if(S_ISREG(finfo->st_mode) && (path[strlen(path) - 1] == '/')) {
+ /* File with trailing slash */
+ errno = ENOENT;
+ return -1;
+ }
+ return 0;
+}
+
+
+NSAPI_PUBLIC int system_fread(SYS_FILE fd, char *buf, int sz)
+{
+ /* XXXMB - this is the *one* function which does return a length
+ * instead of the IO_ERROR/IO_OKAY.
+ */
+ return PR_Read(fd, buf, sz);
+}
+
+NSAPI_PUBLIC int system_fwrite(SYS_FILE fd, char *buf, int sz) {
+ int n,o,w;
+
+ for(n=sz,o=0; n; n-=w,o+=w) {
+ if((w = PR_Write(fd, &buf[o], n)) < 0)
+ return IO_ERROR;
+ }
+ return IO_OKAY;
+}
+
+/* ---------------------------- Standard UNIX ----------------------------- */
+
+#ifdef XP_UNIX
+
+#include <sys/file.h> /* flock */
+
+NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz)
+{
+ int ret;
+#if 0
+ if(flock(fd,LOCK_EX) == -1)
+ return IO_ERROR;
+#endif
+ ret = system_fwrite(fd,buf,sz);
+#if 0
+ if(flock(fd,LOCK_UN) == -1)
+ return IO_ERROR; /* ??? */
+#endif
+ return ret;
+}
+
+/* -------------------------- system_nocoredumps -------------------------- */
+
+
+NSAPI_PUBLIC int system_nocoredumps(void)
+{
+#ifdef BSD_RLIMIT
+ struct rlimit rl;
+
+ rl.rlim_cur = 0;
+ rl.rlim_max = 0;
+ return setrlimit(RLIMIT_CORE, &rl);
+#else
+#if defined(SNI)
+/* C++ compiler seems to find more that one overloaded instance of exit() ?! */
+#define EXITFUNC ::exit
+#else
+#define EXITFUNC exit
+#endif
+ signal(SIGQUIT, EXITFUNC);
+ signal(SIGILL, EXITFUNC);
+ signal(SIGTRAP, EXITFUNC);
+ signal(SIGABRT, EXITFUNC);
+ signal(SIGIOT, EXITFUNC);
+ signal(SIGEMT, EXITFUNC);
+ signal(SIGFPE, EXITFUNC);
+ signal(SIGBUS, EXITFUNC);
+ signal(SIGSEGV, EXITFUNC);
+ signal(SIGSYS, EXITFUNC);
+
+
+ return 0;
+#endif
+}
+#endif /* XP_UNIX */
+
+/* --------------------------- file_setinherit ---------------------------- */
+
+NSAPI_PUBLIC int file_setinherit(SYS_FILE fd, int value)
+{
+#if defined(XP_WIN32)
+ int ret;
+
+// ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), 0, value?HANDLE_FLAG_INHERIT:0);
+ // This function did nothing before since the mask was set to 0.
+ ret = SetHandleInformation((HANDLE)PR_FileDesc2NativeHandle(fd), HANDLE_FLAG_INHERIT, value?HANDLE_FLAG_INHERIT:0);
+ return ret==0?-1:0;
+#elif defined(XP_UNIX)
+ int flags = 0;
+ PRInt32 nativeFD;
+ PRFileDesc *bottom = fd;
+
+ while (bottom->lower != NULL) {
+ bottom = bottom->lower;
+ }
+
+ nativeFD = PR_FileDesc2NativeHandle(bottom);
+#if 0
+fprintf(stderr, "\nInfo(file_setinherit): Native file descriptor is %d\n", nativeFD);
+#endif
+ flags = fcntl(nativeFD, F_GETFD, 0);
+ if(flags == -1)
+ return -1;
+ if(value)
+ flags &= (~FD_CLOEXEC);
+ else
+ flags |= FD_CLOEXEC;
+ fcntl(nativeFD, F_SETFD, flags);
+ return 0;
+
+ /* Comment out for ns security/ nspr integration (HACK for NOW)
+ int flags = fcntl(PR_FileDesc2NativeHandle(fd), F_GETFD, 0);
+ if(flags == -1)
+ return -1;
+ if(value)
+ flags &= (~FD_CLOEXEC);
+ else
+ flags |= FD_CLOEXEC;
+ fcntl(PR_FileDesc2NativeHandle(fd), F_SETFD, flags);
+ return 0;
+ */
+#endif
+}
+
+NSAPI_PUBLIC SYS_FILE system_fopenRO(char *p)
+{
+ SYS_FILE f = PR_Open(p, PR_RDONLY, 0);
+
+ if (!f)
+ return SYS_ERROR_FD;
+ return f;
+}
+
+NSAPI_PUBLIC SYS_FILE system_fopenWA(char *p)
+{
+ SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_APPEND, 0644);
+
+ if (!f)
+ return SYS_ERROR_FD;
+ return f;
+}
+
+NSAPI_PUBLIC SYS_FILE system_fopenRW(char *p)
+{
+ SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE, 0644);
+
+ if (!f)
+ return SYS_ERROR_FD;
+ return f;
+}
+
+NSAPI_PUBLIC SYS_FILE system_fopenWT(char *p)
+{
+ SYS_FILE f = PR_Open(p, PR_RDWR|PR_CREATE_FILE|PR_TRUNCATE, 0644);
+
+ if (!f)
+ return SYS_ERROR_FD;
+ return f;
+}
+
+NSAPI_PUBLIC int system_fclose(SYS_FILE fd)
+{
+ return (PR_Close(fd));
+}
+
+
+#ifdef FILE_WIN32
+
+int CgiBuffering;
+
+NSAPI_PUBLIC SYS_FILE system_fopen(char *path, int access, int flags)
+{
+ char p2[MAX_PATH];
+ SYS_FILE ret;
+ HANDLE fd;
+
+ if (strlen(path) >= MAX_PATH) {
+ return SYS_ERROR_FD;
+ }
+
+ file_unix2local(path, p2);
+
+ fd = CreateFile(p2, access, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, flags, 0, NULL);
+ ret = PR_ImportFile((int32)fd);
+
+ if(ret == INVALID_HANDLE_VALUE)
+ return SYS_ERROR_FD;
+
+ return ret;
+}
+
+
+
+NSAPI_PUBLIC int system_pread(SYS_FILE fd, char *buf, int BytesToRead) {
+ unsigned long BytesRead = 0;
+ int result = 0;
+ BOOLEAN TimeoutSet = FALSE;
+
+ /* XXXMB - nspr20 should be able to do this; but right now it doesn't
+ * return proper error info.
+ * fix it later...
+ */
+ if(ReadFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf, BytesToRead, &BytesRead, NULL) == FALSE) {
+ if (GetLastError() == ERROR_BROKEN_PIPE) {
+ return IO_EOF;
+ } else {
+ return IO_ERROR;
+ }
+ }
+ return (BytesRead ? BytesRead : IO_EOF);
+}
+
+NSAPI_PUBLIC int system_pwrite(SYS_FILE fd, char *buf, int BytesToWrite)
+{
+ unsigned long BytesWritten;
+
+ if (WriteFile((HANDLE)PR_FileDesc2NativeHandle(fd), (LPVOID)buf,
+ BytesToWrite, &BytesWritten, NULL) == FALSE) {
+ return IO_ERROR;
+ }
+ return BytesWritten;
+}
+
+
+NSAPI_PUBLIC int system_fwrite_atomic(SYS_FILE fd, char *buf, int sz)
+{
+ int ret;
+
+#if 0
+ if(system_flock(fd) == IO_ERROR)
+ return IO_ERROR;
+#endif
+ /* XXXMB - this is technically thread unsafe, but it catches any
+ * callers of fwrite_atomic when we're single threaded and just coming
+ * to life.
+ */
+ if (!_atomic_write_lock) {
+ _atomic_write_lock = PR_NewLock();
+ }
+ PR_Lock(_atomic_write_lock);
+ ret = system_fwrite(fd,buf,sz);
+ PR_Unlock(_atomic_write_lock);
+#if 0
+ if(system_ulock(fd) == IO_ERROR)
+ return IO_ERROR;
+#endif
+ return ret;
+}
+
+
+NSAPI_PUBLIC void file_unix2local(char *path, char *p2)
+{
+ /* Try to handle UNIX-style paths */
+ if((!strchr(path, FILE_PATHSEP))) {
+ int x;
+
+ for(x = 0; path[x]; x++)
+ p2[x] = (path[x] == '/' ? '\\' : path[x]);
+ p2[x] = '\0';
+ }
+ else
+ strcpy(p2, path);
+}
+
+
+NSAPI_PUBLIC int system_nocoredumps(void)
+{
+ return 0;
+}
+
+/* --------------------------- system_winerr ------------------------------ */
+
+
+#include <winsock.h>
+#include <errno.h>
+#include "util.h"
+
+NSAPI_PUBLIC char *system_winsockerr(void)
+{
+ int errn = WSAGetLastError();
+
+ return FindError(errn);
+}
+
+NSAPI_PUBLIC char *system_winerr(void)
+{
+ int errn = GetLastError();
+
+ if (errn == 0)
+ errn = WSAGetLastError();
+ return FindError(errn);
+}
+
+/* ------------------------- Dir related stuff ---------------------------- */
+
+
+NSAPI_PUBLIC SYS_DIR dir_open(char *pathp)
+{
+ dir_s *ret = (dir_s *) MALLOC(sizeof(dir_s));
+ char path[MAX_PATH];
+ int l;
+
+ if (strlen(pathp) >= MAX_PATH) {
+ return NULL;
+ }
+
+ l = util_sprintf(path, "%s", pathp) - 1;
+ path[strlen(pathp)] = '\0';
+ if(path[strlen(path) - 1] != FILE_PATHSEP)
+ strcpy (path + strlen(path), "\\*.*");
+ else
+ util_sprintf(path, "%s*.*", path);
+
+ ret->de.d_name = NULL;
+ if( (ret->dp = FindFirstFile(path, &ret->fdata)) != INVALID_HANDLE_VALUE)
+ return ret;
+ FREE(ret);
+ return NULL;
+}
+
+NSAPI_PUBLIC SYS_DIRENT *dir_read(SYS_DIR ds)
+{
+ if(FindNextFile(ds->dp, &ds->fdata) == FALSE)
+ return NULL;
+ if(ds->de.d_name)
+ FREE(ds->de.d_name);
+ ds->de.d_name = STRDUP(ds->fdata.cFileName);
+
+ return &ds->de;
+}
+
+NSAPI_PUBLIC void dir_close(SYS_DIR ds)
+{
+ FindClose(ds->dp);
+ if(ds->de.d_name)
+ FREE(ds->de.d_name);
+ FREE(ds);
+}
+
+#endif /* FILE_WIN32 */
+
+NSAPI_PUBLIC int file_notfound(void)
+{
+#ifdef FILE_WIN32
+ int errn = PR_GetError();
+ return (errn == PR_FILE_NOT_FOUND_ERROR);
+#else
+ return (errno == ENOENT);
+#endif
+}
+
+NSAPI_PUBLIC int dir_create_all(char *dir)
+{
+ struct stat fi;
+ char *t;
+
+#ifdef XP_WIN32
+ t = dir + 3;
+#else /* XP_UNIX */
+ t = dir + 1;
+#endif
+ while(1) {
+ t = strchr(t, FILE_PATHSEP);
+ if(t) *t = '\0';
+ if(stat(dir, &fi) == -1) {
+ if(dir_create(dir) == -1)
+ return -1;
+ }
+ if(t) *t++ = FILE_PATHSEP;
+ else break;
+ }
+ return 0;
+}
+
+
+#ifdef XP_UNIX
+#if !defined(SNI) && !defined(LINUX)
+extern char *sys_errlist[];
+#endif /* SNI */
+#endif
+
+#ifdef NET_SSL
+
+#define ERRMSG_SIZE 35
+#ifdef THREAD_ANY
+static int errmsg_key = -1;
+#include "systhr.h"
+/* Removed for ns security integration
+#include "xp_error.h"
+*/
+#else
+static char errmsg[ERRMSG_SIZE];
+#endif
+
+#include "util.h"
+
+static char *_errmsg_new(int code)
+{
+ char *ret;
+#ifdef THREAD_ANY
+ if(!(ret = (char *) systhread_getdata(errmsg_key))) {
+ ret = (char *) PERM_MALLOC(256);
+ systhread_setdata(errmsg_key, (void *)ret);
+ }
+#else
+ ret = errmsg;
+#endif
+ util_snprintf(ret, ERRMSG_SIZE, "libsec code %d", code);
+#ifndef MCC_BATMAN
+ PR_SetError(0,0);
+#endif
+ return ret;
+}
+#endif
+
+
+void system_errmsg_init(void)
+{
+ if (errmsg_key == -1) {
+#if defined(THREAD_ANY) && defined(NET_SSL)
+ errmsg_key = systhread_newkey();
+#endif
+#ifdef XP_WIN32
+ HashNtErrors();
+#endif
+ if (!_atomic_write_lock)
+ _atomic_write_lock = PR_NewLock();
+ }
+}
+
+NSAPI_PUBLIC int system_errmsg_fn(char **buff, size_t maxlen)
+{
+ char static_error[128];
+ char *lmsg = 0; /* Local message pointer */
+ size_t msglen = 0;
+ int sys_error = 0;
+ PRErrorCode nscp_error;
+#ifdef XP_WIN32
+ LPTSTR sysmsg = 0;
+#endif
+
+
+ /* Grab the OS error message */
+#ifdef XP_WIN32
+ sys_error = GetLastError();
+#else
+ sys_error = errno;
+#endif
+ nscp_error = PR_GetError();
+
+ /* If there is a NSPR error, but it is "unknown", try to get the OSError
+ * and use that instead.
+ */
+ if (nscp_error == PR_UNKNOWN_ERROR)
+ errno = PR_GetOSError();
+
+ if (nscp_error != 0 && nscp_error != PR_UNKNOWN_ERROR){
+ char *nscp_error_msg;
+
+ nscp_error_msg = nscperror_lookup(nscp_error);
+ if(nscp_error_msg){
+ PR_SetError(0, 0);
+ lmsg = nscp_error_msg;
+ } else {
+ util_snprintf(static_error, ERRMSG_SIZE, "unknown error %d", nscp_error);
+ lmsg = static_error;
+ }
+ } else {
+#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;
+ else
+ lmsg = system_winerr();
+ SetLastError(0);
+#else
+/* replaced
+#if defined(SNI) || defined(LINUX)
+ / C++ platform has no definition for sys_errlist /
+ lmsg = strerror(errno);
+#else
+ lmsg = sys_errlist[errno];
+#endif
+with lmsg =strerror(errno);*/
+ lmsg=strerror(errno);
+ errno = 0;
+#endif
+ }
+
+ /* At this point lmsg points to something. */
+ msglen = strlen(lmsg);
+
+ if (*buff == NULL)
+ *buff = STRDUP(lmsg);
+ else if (maxlen > msglen)
+ memcpy(*buff, lmsg, msglen+1);
+ else
+ msglen = 0;
+
+#ifdef XP_WIN32
+ /* NT's FormatMessage() dynamically allocated the msg; free it */
+ if (sysmsg)
+ LocalFree(sysmsg);
+#endif
+
+ return msglen;
+}
+
+NSAPI_PUBLIC char *
+system_errmsg(void)
+{
+ char *buff = 0;
+
+ if (errmsg_key == -1)
+ return "unknown early startup error";
+
+ // rmaxwell - This is extremely lame.
+ // Allocate a buffer in thread local storage to
+ // hold the last error message.
+ // The whole error message facility is broken and should be
+ // updated to get error strings out of the code.
+ if(!(buff = (char *) systhread_getdata(errmsg_key))) {
+ buff = (char *) PERM_MALLOC(errbuf_size);
+ systhread_setdata(errmsg_key, (void *)buff);
+ }
+ system_errmsg_fn(&buff, errbuf_size);
+ if (buff == 0)
+ buff = "Could not retrieve system error message";
+ return buff;
+}
+
+NSAPI_PUBLIC int
+system_rename(char *oldpath, char *newpath)
+{
+ return rename(oldpath, newpath);
+}
+
+NSAPI_PUBLIC int
+system_unlink(char *path)
+{
+ return PR_Delete(path)==PR_FAILURE?-1:0;
+}
+
+NSAPI_PUBLIC int system_lseek(SYS_FILE fd, int off, int wh)
+{
+ switch (wh) {
+ case 0:
+ return PR_Seek(fd, off, PR_SEEK_SET);
+ break;
+ case 1:
+ return PR_Seek(fd, off, PR_SEEK_CUR);
+ break;
+ case 2:
+ return PR_Seek(fd, off, PR_SEEK_END);
+ break;
+ default:
+ return -1;
+ }
+}
+
+NSAPI_PUBLIC int
+system_tlock(SYS_FILE fd)
+{
+ return PR_TLockFile(fd);
+}
+
+NSAPI_PUBLIC int
+system_flock(SYS_FILE fd)
+{
+ return PR_LockFile(fd);
+}
+
+NSAPI_PUBLIC int
+system_ulock(SYS_FILE fd)
+{
+ return PR_UnlockFile(fd);
+}
diff --git a/lib/base/fsmutex.cpp b/lib/base/fsmutex.cpp
new file mode 100644
index 00000000..06fe2403
--- /dev/null
+++ b/lib/base/fsmutex.cpp
@@ -0,0 +1,187 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * fsmutex: Mutexes that are filesystem-based so they're available from more
+ * than one process and address space
+ *
+ * Rob McCool
+ */
+
+#include "base/fsmutex.h"
+#ifdef THREAD_ANY
+#include "base/crit.h"
+#include "base/systhr.h"
+#endif
+
+#include "base/util.h"
+#ifdef XP_WIN32
+typedef HANDLE sys_fsmutex_t;
+#endif
+
+#ifdef XP_UNIX
+#include "base/file.h"
+typedef SYS_FILE sys_fsmutex_t;
+#endif
+
+
+typedef struct {
+ sys_fsmutex_t mutex;
+ char *id;
+#ifdef THREAD_ANY
+ CRITICAL crit;
+#endif
+ int flags;
+} fsmutex_s;
+
+
+
+/* ----------------------------- fsmutex_init ----------------------------- */
+
+
+#ifdef XP_UNIX
+static int
+_fsmutex_create(fsmutex_s *fsm, char *name, int number)
+{
+ char tn[256];
+ SYS_FILE lfd;
+ int visible = (fsm->flags & FSMUTEX_VISIBLE ? 1 : 0);
+
+ util_snprintf(tn, 256, "/tmp/%s.%d", name, number);
+ if(!visible)
+ unlink(tn);
+ if( (lfd = PR_Open(tn, PR_RDWR|PR_CREATE_FILE, 0644)) == NULL)
+ return -1;
+
+ if(!visible)
+ unlink(tn);
+ else
+ fsm->id = PERM_STRDUP(tn);
+ fsm->mutex = lfd;
+ return 0;
+}
+#endif
+
+#ifdef XP_WIN32
+static int
+_fsmutex_create(fsmutex_s *fsm, char *name, int number)
+{
+ char tn[256];
+ util_snprintf(tn, sizeof(tn), "%s.%d", name, number);
+
+ fsm->id = NULL;
+ fsm->mutex = CreateMutex(NULL, FALSE,
+ (fsm->flags & FSMUTEX_VISIBLE ? tn : NULL));
+ return (fsm->mutex ? 0 : -1);
+}
+#endif
+
+NSAPI_PUBLIC FSMUTEX
+fsmutex_init(char *name, int number, int flags)
+{
+ fsmutex_s *ret = (fsmutex_s *) PERM_MALLOC(sizeof(fsmutex_s));
+
+ ret->flags = flags;
+ if(_fsmutex_create(ret, name, number) == -1) {
+ PERM_FREE(ret);
+ return NULL;
+ }
+#ifdef THREAD_ANY
+ if(flags & FSMUTEX_NEEDCRIT)
+ ret->crit = crit_init();
+#endif
+ return (FSMUTEX) ret;
+}
+
+#ifdef XP_UNIX
+NSAPI_PUBLIC void
+fsmutex_setowner(FSMUTEX fsm, uid_t uid, gid_t gid)
+{
+ if(!geteuid())
+ (void) chown( ((fsmutex_s *)fsm)->id, uid, gid);
+}
+#endif
+
+
+/* -------------------------- fsmutex_terminate --------------------------- */
+
+
+#ifdef XP_UNIX
+static void
+_fsmutex_delete(fsmutex_s *fsm)
+{
+ if(fsm->flags & FSMUTEX_VISIBLE)
+ unlink(fsm->id);
+ PERM_FREE(fsm->id);
+ PR_Close(fsm->mutex);
+}
+#endif
+
+#ifdef XP_WIN32
+static void
+_fsmutex_delete(fsmutex_s *fsm)
+{
+ CloseHandle(fsm->mutex);
+}
+#endif
+
+NSAPI_PUBLIC void
+fsmutex_terminate(FSMUTEX id)
+{
+ fsmutex_s *fsm = (fsmutex_s *) id;
+
+ _fsmutex_delete(fsm);
+#ifdef THREAD_ANY
+ if(fsm->flags & FSMUTEX_NEEDCRIT)
+ crit_terminate(fsm->crit);
+#endif
+ PERM_FREE(fsm);
+}
+
+
+/* ----------------------------- fsmutex_lock ----------------------------- */
+
+
+NSAPI_PUBLIC void
+fsmutex_lock(FSMUTEX id)
+{
+ fsmutex_s *fsm = (fsmutex_s *) id;
+#ifdef THREAD_ANY
+ if(fsm->flags & FSMUTEX_NEEDCRIT)
+ crit_enter(fsm->crit);
+#endif
+#ifdef XP_UNIX
+#ifdef THREAD_NSPR_USER
+ /* Poll to avoid blocking. XXXrobm If errno is wrong this may go awry. */
+ while(system_tlock(fsm->mutex) == -1)
+ systhread_sleep(1000);
+#else
+ system_flock(fsm->mutex );
+#endif
+#endif
+#ifdef XP_WIN32
+ WaitForSingleObject(fsm->mutex, INFINITE);
+#endif
+}
+
+
+/* ---------------------------- fsmutex_unlock ---------------------------- */
+
+
+NSAPI_PUBLIC void
+fsmutex_unlock(FSMUTEX id)
+{
+ fsmutex_s *fsm = (fsmutex_s *) id;
+#ifdef XP_UNIX
+ system_ulock(fsm->mutex);
+#endif
+#ifdef XP_WIN32
+ ReleaseMutex(fsm->mutex);
+#endif
+#ifdef THREAD_ANY
+ if(fsm->flags & FSMUTEX_NEEDCRIT)
+ crit_exit(fsm->crit);
+#endif
+}
diff --git a/lib/base/lexer.cpp b/lib/base/lexer.cpp
new file mode 100644
index 00000000..e521c51f
--- /dev/null
+++ b/lib/base/lexer.cpp
@@ -0,0 +1,978 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (lexer.c)
+ *
+ * This module provides functions to assist parsers in lexical
+ * analysis. The idea is to provide a slightly higher-level
+ * interface than that of ctype.h.
+ */
+
+#include "netsite.h"
+#include "base/nsassert.h"
+
+#include "lexer_pvt.h"
+#include "base/lexer.h"
+
+/*
+ * Description (lex_class_check)
+ *
+ * This function checks whether a given character belongs to one or
+ * specified character classes.
+ *
+ * Arguments:
+ *
+ * chtab - character class table pointer
+ * code - character code to be tested
+ * cbits - bit mask of character classes
+ *
+ * Returns:
+ *
+ * The return value is zero if the code is not in any of the character
+ * classes. It is non-zero, if the code is in at least one of the
+ * classes.
+ */
+NSAPI_PUBLIC
+int lex_class_check(void * chtab, char code, unsigned long cbits)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ int rv = 0; /* return value */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ bp = lct->lct_bv + code * lct->lct_bvbytes;
+
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & cbits) {
+ rv = 1;
+ break;
+ }
+ cbits >>= 8;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (lex_class_create)
+ *
+ * This function creates a new character class table. A
+ * character class table is used to map a character code to a
+ * set of character classes. The mapping for a given character
+ * is expressed as a bit vector, where each bit indicates the
+ * membership of that character in one of the character classes.
+ *
+ * Arguments:
+ *
+ * classc - the number of character classes being defined
+ * classv - pointers to null-terminated strings containing
+ * the character codes in each character class
+ * pchtab - indicates where to store a returned handle for
+ * the character class table
+ *
+ * Returns:
+ *
+ * If successful, the return value is the number of character
+ * classes specified (classc), and a handle for the created table
+ * is returned through pchtab.
+ *
+ * Usage Notes:
+ *
+ * Null (\000) can never be in any character classes, since it
+ * marks the end of the classv[] strings.
+ *
+ * classv[] can included NULL pointers, in which case bits will be
+ * allocated for corresponding empty character classes.
+ */
+NSAPI_PUBLIC
+int lex_class_create(int classc, char * classv[], void **pchtab)
+{
+ int ncodes = 128; /* number of character encodings */
+ int bvbytes; /* bytes per bit vector */
+ LEXClassTab_t * ct; /* class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ char * cp; /* class string pointer */
+ int bitmask; /* class bit mask */
+ int bnum; /* byte number in bit vector */
+ int ci; /* character index */
+ int i; /* class index */
+
+ /* Get number of bytes per bit vector */
+ NS_ASSERT(classc > 0);
+ bvbytes = (classc + 7) >> 3;
+
+ /* Allocate the character class table */
+ ct = (LEXClassTab_t *)calloc(1, sizeof(LEXClassTab_t) + ncodes * bvbytes);
+ if (ct == NULL) {
+
+ /* Error - insufficient memory */
+ return LEXERR_MALLOC;
+ }
+
+ /* Initialize the class table */
+ ct->lct_classc = classc;
+ ct->lct_bvbytes = bvbytes;
+ ct->lct_bv = (unsigned char *)(ct + 1);
+
+ /* Initialize the bit vectors */
+ for (i = 0; i < classc; ++i) {
+
+ cp = classv[i];
+ if (cp != NULL) {
+
+ bitmask = 1 << (i & 7);
+ bnum = i >> 7;
+
+ while ((ci = *cp++) != 0) {
+ bp = ct->lct_bv + ci + bnum;
+ *bp |= bitmask;
+ }
+ }
+ }
+
+ /* Return pointer to table */
+ NS_ASSERT(pchtab != NULL);
+ *pchtab = (void *)ct;
+
+ return classc;
+}
+
+NSAPI_PUBLIC
+void lex_class_destroy(void * chtab)
+{
+ FREE((void *)chtab);
+}
+
+NSAPI_PUBLIC
+LEXStream_t * lex_stream_create(LEXStreamGet_t strmget, void * strmid,
+ char * buf, int buflen)
+{
+ LEXStream_t * lst; /* stream structure pointer */
+
+ /* Allocate the stream structure */
+ lst = (LEXStream_t *)MALLOC(sizeof(LEXStream_t));
+ if (lst == NULL) {
+ /* Error - insufficient memory */
+ return 0;
+ }
+
+ lst->lst_strmid = strmid;
+ lst->lst_get = strmget;
+
+ /*
+ * Allocate a buffer for the stream if there's a positive length
+ * but a NULL buffer pointer.
+ */
+ if ((buflen > 0) && (buf == NULL)) {
+
+ buf = (char *)MALLOC(buflen);
+ if (buf == NULL) {
+ FREE((void *)lst);
+ return 0;
+ }
+
+ /* Also initialize the current position and residual length */
+ lst->lst_cp = buf;
+ lst->lst_len = 0;
+ lst->lst_flags = LST_FREEBUF;
+ }
+
+ lst->lst_buf = buf;
+ lst->lst_buflen = buflen;
+
+ return lst;
+}
+
+NSAPI_PUBLIC
+void lex_stream_destroy(LEXStream_t * lst)
+{
+ if ((lst->lst_flags & LST_FREEBUF) && (lst->lst_buf != NULL)) {
+ FREE(lst->lst_buf);
+ }
+ FREE((void *)lst);
+}
+
+/*
+ * Description (lex_token_new)
+ *
+ * This function creates a new token object. A token object is
+ * used to accumulate text in an associated buffer. If the
+ * 'growlen' argument is specified as a value that is greater
+ * than zero, then the token buffer will be reallocated as
+ * necessary to accomodate more text. The initial size of
+ * the token buffer is given by 'initlen', which may be zero,
+ * and should be zero if lex_token_setbuf() is used.
+ *
+ * The token object is allocated from the memory pool given
+ * by the 'pool' argument. The default pool for the current
+ * thread is used if 'pool' is null.
+ *
+ * Arguments:
+ *
+ * pool - handle for memory pool to be used
+ * initlen - initial length of token buffer
+ * growlen - amount to grow a full token buffer
+ * token - pointer to returned token handle
+ *
+ * Returns:
+ *
+ * If successful, the function return value is zero and a handle
+ * for the new token is returned via 'token'. Otherwise a negative
+ * error code is returned.
+ */
+
+NSAPI_PUBLIC
+int lex_token_new(pool_handle_t * pool, int initlen, int growlen, void **token)
+{
+ LEXToken_t * lt; /* new token pointer */
+
+ /* Allocate the token structure */
+ if (pool) {
+ lt = (LEXToken_t *)pool_calloc(pool, 1, sizeof(LEXToken_t));
+ }
+ else {
+ lt = (LEXToken_t *)CALLOC(sizeof(LEXToken_t));
+ }
+ if (lt == NULL) {
+ /* Error - insufficient memory */
+ return LEXERR_MALLOC;
+ }
+
+ /* Save the memory pool handle for future allocations */
+ lt->lt_mempool = pool;
+
+ /* Allocate the initial token buffer if initlen > 0 */
+ if (initlen > 0) {
+ if (pool) {
+ lt->lt_buf = (char *)pool_malloc(pool, initlen);
+ }
+ else {
+ lt->lt_buf = (char *)MALLOC(initlen);
+ }
+ if (lt->lt_buf == NULL) {
+ /* Error - insufficient memory */
+ if (pool) {
+ pool_free(pool, (void *)lt);
+ }
+ else {
+ FREE((void *)lt);
+ }
+ return LEXERR_MALLOC;
+ }
+
+ lt->lt_initlen = initlen;
+ lt->lt_buflen = initlen;
+ lt->lt_buf[0] = 0;
+ }
+
+ if (growlen > 0) lt->lt_inclen = growlen;
+
+ NS_ASSERT(token != NULL);
+ *token = (void *)lt;
+
+ return 0;
+}
+
+/*
+ * Description (lex_token_start)
+ *
+ * This function discards any current contents of the token buffer
+ * associated with a specified token object, so that any new data
+ * appended to the token will start at the beginning of the token
+ * buffer. If there is no token buffer currently associated with
+ * the token, and the 'initlen' value specified to lex_token_new()
+ * was greater than zero, then a new token buffer is allocated.
+ * This function enables a token and optionally its token buffer
+ * to be reused.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ *
+ * Returns:
+ *
+ * If successful, the function return value is zero. Otherwise
+ * a negative error code is returned.
+ */
+
+NSAPI_PUBLIC int
+lex_token_start(void * token)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+
+ /* Do we need to allocate a token buffer? */
+ if ((lt->lt_buf == NULL) && (lt->lt_initlen > 0)) {
+
+ /* Allocate the initial token buffer */
+ if (lt->lt_mempool) {
+ lt->lt_buf = (char *)pool_malloc(lt->lt_mempool, lt->lt_initlen);
+ }
+ else {
+ lt->lt_buf = (char *)MALLOC(lt->lt_initlen);
+ }
+ if (lt->lt_buf == NULL) {
+ /* Error - insufficient memory */
+ return LEXERR_MALLOC;
+ }
+ lt->lt_buflen = lt->lt_initlen;
+ }
+
+ lt->lt_len = 0;
+ lt->lt_buf[0] = 0;
+
+ return 0;
+}
+
+/*
+ * Description (lex_token_info)
+ *
+ * This function returns information about the token buffer currently
+ * associated with a token object. This includes a pointer to the
+ * token data, if any, the current length of the token data, and the
+ * current size of the token buffer.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ * tdatalen - pointer to returned token data length
+ * (may be null)
+ * tbufflen - pointer to returned token buffer length
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The function return value is a pointer to the beginning of the
+ * token data, or null if there is no token buffer associated with
+ * the token. The token data length and token buffer length are
+ * returned via 'tdatalen' and 'tbufflen', respectively.
+ */
+
+NSAPI_PUBLIC
+char * lex_token_info(void * token, int * tdatalen, int * tbufflen)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+
+ if (tdatalen) *tdatalen = lt->lt_len;
+ if (tbufflen) *tbufflen = lt->lt_buflen;
+
+ return lt->lt_buf;
+}
+
+/*
+ * Description (lex_token)
+ *
+ * This function returns a pointer to the current token buffer, if any.
+ * If the length of the token is also needed, use lex_token_info().
+ * This function would normally be used when the token is a
+ * null-terminated string. See also lex_token_take().
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ *
+ * Returns:
+ *
+ * A pointer to the beginning of the current token is returned.
+ * The pointer is null if no token buffer is currently associated
+ * with the token object.
+ */
+
+NSAPI_PUBLIC
+char * lex_token(void * token)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+
+ return lt->lt_buf;
+}
+
+/*
+ * Description (lex_token_destroy)
+ *
+ * This function destroys a specified token object. The memory
+ * associated with the token object and its token buffer, if any,
+ * is freed to whence it came. Note that token objects can be
+ * associated with a memory pool, and destroyed implicitly when
+ * the pool is destroyed via pool_destroy().
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ */
+
+NSAPI_PUBLIC
+void lex_token_destroy(void * token)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+
+ if (lt) {
+ if (lt->lt_mempool) {
+ if (lt->lt_buf) {
+ pool_free(lt->lt_mempool, (void *)(lt->lt_buf));
+ }
+ pool_free(lt->lt_mempool, (void *)lt);
+ }
+ else {
+ if (lt->lt_buf) {
+ FREE(lt->lt_buf);
+ }
+ FREE(lt);
+ }
+ }
+}
+
+/*
+ * Description (lex_token_get)
+ *
+ * This function returns a pointer to the current token buffer,
+ * leaving the token with no associated token buffer. The caller
+ * assumes ownership of the returned token buffer. The length
+ * of the token data and the length of the token buffer are returned
+ * if requested. Note that lex_token_take() performs a similar
+ * operation.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ * tdatalen - pointer to returned token data length
+ * (may be null)
+ * tbufflen - pointer to returned token buffer length
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The function return value is a pointer to the beginning of the
+ * token data, or null if there is no token buffer associated with
+ * the token. The token data length and token buffer length are
+ * returned via 'tdatalen' and 'tbufflen', respectively.
+ */
+
+NSAPI_PUBLIC
+char * lex_token_get(void * token, int * tdatalen, int * tbufflen)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+ char * tokenstr;
+
+ tokenstr = lt->lt_buf;
+ if (tdatalen) *tdatalen = lt->lt_len;
+ if (tbufflen) *tbufflen = lt->lt_buflen;
+
+ lt->lt_buf = NULL;
+ lt->lt_buflen = 0;
+ lt->lt_len = 0;
+
+ return tokenstr;
+}
+
+/*
+ * Description (lex_token_take)
+ *
+ * This function returns a pointer to the current token buffer,
+ * leaving the token with no associated token buffer. The caller
+ * assumes ownership of the returned token buffer. Note that
+ * lex_token_get() performs a similar operation, but returns more
+ * information.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ *
+ * Returns:
+ *
+ * A pointer to the beginning of the current token is returned.
+ * The pointer is null if no token buffer is currently associated
+ * with the token object.
+ */
+
+NSAPI_PUBLIC
+char * lex_token_take(void * token)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+ char * tokenstr;
+
+ tokenstr = lt->lt_buf;
+
+ lt->lt_buf = NULL;
+ lt->lt_buflen = 0;
+ lt->lt_len = 0;
+
+ return tokenstr;
+}
+
+/*
+ * Description (lex_token_append)
+ *
+ * This function appends data to the end of a token. If 'growlen'
+ * was specified as a greater-than-zero value for lex_token_new(),
+ * then the token buffer may be reallocated to accomodate the
+ * new data if necessary. A null byte is maintained in the token
+ * buffer following the token data, but it is not included in the
+ * token data length.
+ *
+ * Arguments:
+ *
+ * token - handle for token object
+ * nbytes - number of bytes of new data
+ * src - pointer to new data
+ *
+ * Returns:
+ *
+ * If successful, the function return value is the new length of
+ * the token data. Otherwise a negative error code is returned.
+ */
+
+NSAPI_PUBLIC
+int lex_token_append(void * token, int nbytes, char * src)
+{
+ LEXToken_t * lt = (LEXToken_t *)token; /* token pointer */
+ int bufsize;
+ int length;
+
+ NS_ASSERT(nbytes >= 0);
+ NS_ASSERT((src != NULL) || (nbytes == 0));
+
+ if (nbytes > 0) {
+
+ bufsize = lt->lt_buflen;
+ length = lt->lt_len + nbytes;
+
+ if (length >= bufsize) {
+
+ while (length >= bufsize) {
+ bufsize += lt->lt_inclen;
+ }
+
+ if (lt->lt_mempool) {
+ if (lt->lt_buf) {
+ lt->lt_buf = (char *)pool_realloc(lt->lt_mempool,
+ lt->lt_buf, bufsize);
+ }
+ else {
+ lt->lt_buf = (char *)pool_malloc(lt->lt_mempool, bufsize);
+ }
+ }
+ else {
+ if (lt->lt_buf) {
+ lt->lt_buf = (char *)REALLOC(lt->lt_buf, bufsize);
+ }
+ else {
+ lt->lt_buf = (char *)MALLOC(bufsize);
+ }
+ }
+ }
+
+ if (lt->lt_buf) {
+
+ memcpy((void *)(lt->lt_buf + lt->lt_len), (void *)src, nbytes);
+ lt->lt_buf[length] = 0;
+ lt->lt_len = length;
+ lt->lt_buflen = bufsize;
+ }
+ else {
+ /* Error - insufficient memory */
+ return LEXERR_MALLOC;
+ }
+ }
+
+ return lt->lt_len;
+}
+
+NSAPI_PUBLIC
+int lex_next_char(LEXStream_t * lst, void * chtab, unsigned long cbits)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int rv; /* return value */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ /* Get the next character from the buffer */
+ rv = *lst->lst_cp;
+
+ bitmask = cbits;
+ bp = lct->lct_bv + rv * lct->lct_bvbytes;
+
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) {
+ /* Update the buffer pointer and length */
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ break;
+ }
+ bitmask >>= 8;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC
+int lex_scan_over(LEXStream_t * lst, void * chtab, unsigned long cbits,
+ void * token)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ char * cp; /* current pointer in stream buffer */
+ unsigned char * bp; /* bit vector pointer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int cv = 0; /* current character value */
+ int rv = 0; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+ cv = *cp;
+ bitmask = cbits;
+ bp = lct->lct_bv + cv * lct->lct_bvbytes;
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) goto more_token;
+ bitmask >>= 8;
+ }
+
+ done = 1;
+ break;
+
+ more_token:
+ slen += 1;
+ cp += 1;
+ }
+
+ /* If the current segment is not empty, append it to the token */
+ if (slen > 0) {
+ rv = lex_token_append(token, slen, lst->lst_cp);
+ if (rv < 0) break;
+
+ /* Update the stream buffer pointer and length */
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return ((rv < 0) ? rv : cv);
+}
+
+/*
+ * Description (lex_scan_string)
+ *
+ * This function parses a quoted string into the specified token.
+ * The current character in the LEX stream is taken to be the
+ * beginning quote character. The quote character may be included
+ * in the string by preceding it with a '\'. Any newline
+ * characters to be included in the string must also be preceded
+ * by '\'. The string is terminated by another occurrence of the
+ * quote character, or an unquoted newline, or EOF.
+ *
+ * Arguments:
+ *
+ * lst - pointer to LEX stream structure
+ * token - handle for token
+ * flags - bit flags (unused - must be zero)
+ *
+ * Returns:
+ *
+ * The terminating character is returned, or zero if EOF. The
+ * string is returned in the token, without the beginning and
+ * ending quote characters. An error is indicated by a negative
+ * return value.
+ */
+
+NSAPI_PUBLIC
+int lex_scan_string(LEXStream_t * lst, void * token, int flags)
+{
+ char * cp; /* current pointer in stream buffer */
+ int cv; /* current character value */
+ int rv; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int cquote = 0; /* character quote indication */
+ int qchar = -1; /* quote character */
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+
+ /* Get the next character */
+ cv = *cp;
+
+ /* Pick up the quote character if we don't have it yet */
+ if (qchar < 0) {
+ qchar = cv;
+
+ /* Don't include it in the string */
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ cp += 1;
+ continue;
+ }
+
+ /* cquote is 1 if the last character was '\' */
+ if (cquote == 0) {
+
+ /* Is this a string terminator? */
+ if ((cv == qchar) || (cv == '\n')) {
+
+ /* Append whatever we have to this point */
+ if (slen > 0) goto append_it;
+
+ /*
+ * If the terminator is the expected quote character,
+ * just skip it. If it's anything else, leave it as
+ * the current character.
+ */
+ if (cv == qchar) {
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ }
+
+ done = 1;
+ goto append_it;
+ }
+
+ /* Got the character quote character? */
+ if (cv == '\\') {
+
+ /* Append anything we have so far first */
+ if (slen > 0) goto append_it;
+
+ /* Then skip the character */
+ cquote = 1;
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ cp += 1;
+ continue;
+ }
+ }
+ else {
+
+ /* Include any character following '\' */
+ cquote = 0;
+ }
+
+ /* Include this character in the string */
+ slen += 1;
+ cp += 1;
+ }
+
+ append_it:
+
+ /* If the current segment is not empty, append it to the token */
+ if (slen > 0) {
+ rv = lex_token_append(token, slen, lst->lst_cp);
+ if (rv < 0) break;
+
+ /* Update the stream buffer pointer and length */
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return ((rv < 0) ? rv : cv);
+}
+
+NSAPI_PUBLIC
+int lex_scan_to(LEXStream_t * lst, void * chtab, unsigned long cbits,
+ void * token)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ char * cp; /* current pointer in stream buffer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int cv = 0; /* current character value */
+ int rv = 0; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+ cv = *cp;
+ bitmask = cbits;
+ bp = lct->lct_bv + cv * lct->lct_bvbytes;
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) {
+ done = 1;
+ goto append_it;
+ }
+ bitmask >>= 8;
+ }
+
+ slen += 1;
+ cp += 1;
+ }
+
+ append_it:
+
+ /* If the current segment is not empty, append it to the token */
+ if (slen > 0) {
+ rv = lex_token_append(token, slen, lst->lst_cp);
+ if (rv < 0) break;
+
+ /* Update the stream buffer pointer and length */
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return ((rv < 0) ? rv : cv);
+}
+
+NSAPI_PUBLIC
+int lex_skip_over(LEXStream_t * lst, void * chtab, unsigned long cbits)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ char * cp; /* current pointer in stream buffer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int rv = 0; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+ rv = *cp;
+ bitmask = cbits;
+ bp = lct->lct_bv + rv * lct->lct_bvbytes;
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) goto next_ch;
+ bitmask >>= 8;
+ }
+
+ done = 1;
+ break;
+
+ next_ch:
+ slen += 1;
+ cp += 1;
+ }
+
+ if (slen > 0) {
+ /* Update the stream buffer pointer and length */
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC
+int lex_skip_to(LEXStream_t * lst, void * chtab, unsigned long cbits)
+{
+ LEXClassTab_t * lct; /* character class table pointer */
+ unsigned char * bp; /* bit vector pointer */
+ char * cp; /* current pointer in stream buffer */
+ unsigned long bitmask; /* class bit mask temporary */
+ int rv; /* return value */
+ int slen; /* token segment length */
+ int done = 0; /* done indication */
+ int i; /* loop index */
+
+ lct = (LEXClassTab_t *)chtab;
+
+ while (!done) {
+
+ /* Go get more stream data if none left in the buffer */
+ if (lst->lst_len <= 0) {
+ rv = (*lst->lst_get)(lst);
+ if (rv <= 0) {
+ return rv;
+ }
+ }
+
+ slen = 0;
+ cp = lst->lst_cp;
+
+ while (slen < lst->lst_len) {
+ rv = *cp;
+ bitmask = cbits;
+ bp = lct->lct_bv + rv * lct->lct_bvbytes;
+ for (i = 0; i < lct->lct_bvbytes; ++i) {
+ if (*bp++ & bitmask) {
+ done = 1;
+ goto update_it;
+ }
+ bitmask >>= 8;
+ }
+ slen += 1;
+ cp += 1;
+ }
+
+ update_it:
+ /* Update the stream buffer pointer and length */
+ if (slen > 0) {
+ lst->lst_cp += slen;
+ lst->lst_len -= slen;
+ }
+ }
+
+ return rv;
+}
diff --git a/lib/base/lexer_pvt.h b/lib/base/lexer_pvt.h
new file mode 100644
index 00000000..d4a43f38
--- /dev/null
+++ b/lib/base/lexer_pvt.h
@@ -0,0 +1,30 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef __LEXER_PVT_H
+#define __LEXER_PVT_H
+
+#ifndef _POOL_H_
+#include "base/pool.h"
+#endif /* _POOL_H_ */
+
+typedef struct LEXClassTab_s LEXClassTab_t;
+struct LEXClassTab_s {
+ int lct_classc; /* number of character classes */
+ int lct_bvbytes; /* number of bytes per bit vector */
+ unsigned char * lct_bv; /* pointer to bit vector area */
+};
+
+typedef struct LEXToken_s LEXToken_t;
+struct LEXToken_s {
+ char * lt_buf; /* token buffer pointer */
+ int lt_len; /* length of token data */
+ int lt_buflen; /* current length of buffer */
+ int lt_inclen; /* buffer length increment */
+ int lt_initlen; /* initial length of token buffer */
+ pool_handle_t * lt_mempool; /* token memory pool */
+};
+
+#endif /* __LEXER_PVT_H */
diff --git a/lib/base/net.cpp b/lib/base/net.cpp
new file mode 100644
index 00000000..0d15b121
--- /dev/null
+++ b/lib/base/net.cpp
@@ -0,0 +1,578 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * net.c: sockets abstraction and DNS related things
+ *
+ * Note: sockets created with net_socket are placed in non-blocking mode,
+ * however this API simulates that the calls are blocking.
+ *
+ * Rob McCool
+ */
+
+
+#include "netsite.h"
+#include "prio.h"
+#include "private/pprio.h"
+#include <nspr.h>
+
+#include <frame/conf.h>
+/* Removed for ns security integration
+#include "sslio/sslio.h"
+*/
+
+#include "net.h"
+#include "util.h"
+#include "daemon.h" /* child_exit */
+#include "ereport.h" /* error reporting */
+#include <string.h>
+#ifdef XP_UNIX
+#include <arpa/inet.h> /* inet_ntoa */
+#include <netdb.h> /* hostent stuff */
+#ifdef NEED_GHN_PROTO
+extern "C" int gethostname (char *name, size_t namelen);
+#endif
+#endif /* XP_UNIX */
+#ifdef LINUX
+#include <sys/ioctl.h> /* ioctl */
+#endif
+
+extern "C" {
+#include "ssl.h"
+}
+
+#if defined(OSF1)
+#include <stropts.h>
+#endif
+#include "base/systems.h"
+#include "base/dbtbase.h"
+
+#if defined(OSF1)
+#include <stropts.h>
+#endif
+
+#ifdef IRIX
+#include <bstring.h> /* fd_zero uses bzero */
+#endif
+#include "netio.h"
+
+net_io_t net_io_functions;
+/* removed for ns security integration
+#include "xp_error.h"
+*/
+
+#include "libadmin/libadmin.h"
+
+int net_enabledns = 1;
+int net_enableAsyncDNS = 0;
+int net_listenqsize = DAEMON_LISTEN_SIZE;
+unsigned int NET_BUFFERSIZE = NET_DEFAULT_BUFFERSIZE;
+unsigned int NET_READ_TIMEOUT = NET_DEFAULT_READ_TIMEOUT;
+unsigned int NET_WRITE_TIMEOUT = NET_DEFAULT_WRITE_TIMEOUT;
+unsigned int SSL_HANDSHAKE_TIMEOUT = SSL_DEFAULT_HANDSHAKE_TIMEOUT;
+
+
+/* ------------------------------ net_init -------------------------------- */
+NSAPI_PUBLIC int net_init(int security_on)
+{
+ return 0;
+}
+
+/* ------------------------------ net_socket ------------------------------ */
+NSAPI_PUBLIC SYS_NETFD net_socket(int domain, int type, int protocol)
+{
+ SYS_NETFD sock;
+ SYS_NETFD prsock;
+
+ if (security_active) {
+ if (protocol == IPPROTO_TCP)
+ prsock = PR_NewTCPSocket();
+ else
+ prsock = PR_NewUDPSocket();
+ if(prsock)
+ sock = SSL_ImportFD(NULL, prsock);
+ else sock = NULL;
+ }
+ else {
+ if (protocol == IPPROTO_TCP) sock = PR_NewTCPSocket();
+ else sock = PR_NewUDPSocket();
+ }
+
+ if (sock == NULL)
+ return (SYS_NETFD)SYS_NET_ERRORFD;
+ return sock;
+}
+
+
+/* ---------------------------- net_getsockopt ---------------------------- */
+NSAPI_PUBLIC int net_getsockopt(SYS_NETFD s, int level, int optname,
+ void *optval, int *optlen)
+{
+ return getsockopt(PR_FileDesc2NativeHandle(s), level, optname,
+ (char *)optval, (TCPLEN_T *)optlen);
+}
+
+
+/* ---------------------------- net_setsockopt ---------------------------- */
+
+
+NSAPI_PUBLIC int net_setsockopt(SYS_NETFD s, int level, int optname,
+ const void *optval, int optlen)
+{
+ return setsockopt(PR_FileDesc2NativeHandle(s), level, optname,
+ (const char *)optval, optlen);
+}
+/* ------------------------------ net_listen ------------------------------ */
+
+
+NSAPI_PUBLIC int net_listen(SYS_NETFD s, int backlog)
+{
+ return PR_Listen(s, backlog)==PR_FAILURE?IO_ERROR:0;
+}
+
+
+/* ------------------------- net_create_listener -------------------------- */
+
+
+NSAPI_PUBLIC SYS_NETFD net_create_listener(char *ipstr, int port)
+{
+ SYS_NETFD sd;
+ /*
+ struct sockaddr_in sa_server;
+ */
+ PRNetAddr sa_server;
+ PRStatus status;
+ PRInt32 flags;
+
+ if ((sd = net_socket(AF_INET,SOCK_STREAM,IPPROTO_TCP)) == SYS_NET_ERRORFD) {
+ return SYS_NET_ERRORFD;
+ }
+
+#ifdef SOLARIS
+ /*
+ * unset NONBLOCK flag;
+ */
+ /* Have no idea why Solaris want to unset NONBLOCK flag when it should
+ be in NON-BLOCK mode, and new NSPR20 does not give file descriptor
+ back, so the code are removed --- yjh
+ flags = fcntl(sd->osfd, F_GETFL, 0);
+ fcntl(sd->osfd, F_SETFL, flags & ~O_NONBLOCK);
+ */
+#endif
+ /* Convert to NSPR21 for ns security integration
+ ZERO((char *) &sa_server, sizeof(sa_server));
+ sa_server.sin_family=AF_INET;
+ sa_server.sin_addr.s_addr = (ipstr ? inet_addr(ipstr) : htonl(INADDR_ANY));
+ sa_server.sin_port=htons(port);
+ if(net_bind(sd, (struct sockaddr *) &sa_server,sizeof(sa_server)) < 0) {
+ return SYS_NET_ERRORFD;
+ }
+ net_listen(sd, net_listenqsize);
+ */
+
+ if (ipstr) {
+ status = PR_InitializeNetAddr(PR_IpAddrNull, port, &sa_server);
+ if (status == PR_SUCCESS) sa_server.inet.ip = inet_addr(ipstr);
+ else return SYS_NET_ERRORFD;
+ }
+ else {
+ status = PR_InitializeNetAddr(PR_IpAddrAny, port, &sa_server);
+ if (status == PR_FAILURE) return SYS_NET_ERRORFD;
+ }
+
+ status = PR_Bind(sd, &sa_server);
+ if (status == PR_FAILURE) return SYS_NET_ERRORFD;
+
+
+ status = PR_Listen(sd, net_listenqsize);
+ if (status == PR_FAILURE) return SYS_NET_ERRORFD;
+
+ return sd;
+}
+/* ------------------------------ net_select ------------------------------ */
+
+/*
+NSAPI_PUBLIC int net_select(int nfds, fd_set *r, fd_set *w, fd_set *e,
+ struct timeval *timeout)
+{
+ PR_fd_set rd, wr, ex;
+ int index;
+ int rv;
+
+ if (nfds > (64*1024))
+ return -1;
+
+ PR_FD_ZERO(&rd);
+ PR_FD_ZERO(&wr);
+ PR_FD_ZERO(&ex);
+
+ for (index=0; index<nfds; index++) {
+ if (FD_ISSET(index, r))
+ PR_FD_NSET(index, &rd);
+ if (FD_ISSET(index, w))
+ PR_FD_NSET(index, &wr);
+ if (FD_ISSET(index, e))
+ PR_FD_NSET(index, &ex);
+ }
+
+ rv = PR_Select(0, &rd, &wr, &ex, PR_SecondsToInterval(timeout->tv_sec));
+ if (rv > 0) {
+ FD_ZERO(r);
+ FD_ZERO(w);
+ FD_ZERO(e);
+ for (index=0; index<nfds; index++) {
+ if (PR_FD_NISSET(index, &rd))
+ FD_SET(index, r);
+ if (PR_FD_NISSET(index, &wr))
+ FD_SET(index, w);
+ if (PR_FD_NISSET(index, &ex))
+ FD_SET(index, e);
+ }
+ }
+
+ return rv;
+}
+*/
+
+NSAPI_PUBLIC int net_select(int nfds, fd_set *r, fd_set *w, fd_set *e,
+ struct timeval *timeout)
+{
+ return 1;
+}
+
+
+/* ----------------------------- net_isalive ------------------------------ */
+
+
+/*
+ * XXXmikep As suggested by shaver@ingenia.com. If everyone was POSIX
+ * compilent, a write() of 0 bytes would work as well
+ */
+NSAPI_PUBLIC int net_isalive(SYS_NETFD sd)
+{
+ char c;
+ if (PR_RecvFrom(sd, &c, 1, MSG_PEEK, NULL, 0) == -1 ) {
+ return 0;
+ }
+ return 1;
+}
+
+
+/* ------------------------------ net_connect ------------------------------ */
+
+NSAPI_PUBLIC int net_connect(SYS_NETFD s, const void *sockaddr, int namelen)
+{
+ int rv;
+
+ child_status(CHILD_WRITING);
+ rv = PR_Connect(s, (PRNetAddr *)sockaddr, PR_INTERVAL_NO_TIMEOUT);
+ child_status(CHILD_PROCESSING);
+
+ return rv==PR_FAILURE?IO_ERROR:0;
+}
+
+
+/* ------------------------------ net_ioctl ------------------------------ */
+
+
+NSAPI_PUBLIC int net_ioctl(SYS_NETFD s, int tag, void *result)
+{
+#if defined(NET_WINSOCK)
+ return ioctlsocket(PR_FileDesc2NativeHandle(s),tag,(unsigned long *)result);
+#elif defined(XP_UNIX)
+ return ioctl(PR_FileDesc2NativeHandle(s), tag, result);
+#else
+ write me;
+#endif
+
+}
+/* --------------------------- net_getpeername ---------------------------- */
+
+
+NSAPI_PUBLIC int net_getpeername(SYS_NETFD s, struct sockaddr *name,
+ int *namelen)
+{
+#if defined (SNI) || defined (UnixWare)
+ return getpeername(PR_FileDesc2NativeHandle(s), name, (size_t *)namelen);
+#else /* defined (SNI) || defined (UnixWare) */
+ return getpeername(PR_FileDesc2NativeHandle(s), name, (TCPLEN_T *)namelen);
+#endif /* defined (SNI) || defined (UnixWare) */
+}
+
+
+/* ------------------------------ net_close ------------------------------- */
+
+
+NSAPI_PUBLIC int net_close(SYS_NETFD s)
+{
+ return PR_Close(s)==PR_FAILURE?IO_ERROR:0;
+}
+
+NSAPI_PUBLIC int net_shutdown(SYS_NETFD s, int how)
+{
+ switch (how) {
+ case 0:
+ return PR_Shutdown(s, PR_SHUTDOWN_RCV);
+ break;
+ case 1:
+ return PR_Shutdown(s, PR_SHUTDOWN_SEND);
+ break;
+ case 2:
+ return PR_Shutdown(s, PR_SHUTDOWN_BOTH);
+ break;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+
+
+/* ------------------------------- net_bind ------------------------------- */
+
+NSAPI_PUBLIC int net_bind(SYS_NETFD s, const struct sockaddr *name,
+ int namelen)
+{
+ return PR_Bind(s, (const PRNetAddr *)name)==PR_FAILURE?IO_ERROR:0;
+}
+
+
+/* ------------------------------ net_accept ------------------------------ */
+
+
+NSAPI_PUBLIC SYS_NETFD net_accept(SYS_NETFD sd, struct sockaddr *addr,
+ int *addrlen)
+{
+ SYS_NETFD sock = PR_Accept(sd, (PRNetAddr *)addr, PR_INTERVAL_NO_TIMEOUT);
+
+ if (sock == NULL)
+ return SYS_NET_ERRORFD;
+ return sock;
+}
+
+/* ------------------------------- net_read ------------------------------- */
+
+NSAPI_PUBLIC int net_read(SYS_NETFD fd, char *buf, int sz, int timeout)
+{
+ int rv;
+
+ if (timeout == NET_ZERO_TIMEOUT)
+ timeout = PR_INTERVAL_NO_WAIT;
+ else if (timeout == NET_INFINITE_TIMEOUT)
+ timeout = PR_INTERVAL_NO_TIMEOUT;
+ else
+ timeout = PR_SecondsToInterval(timeout);
+
+ child_status(CHILD_READING);
+ rv = PR_Recv(fd, buf, sz, 0, timeout);
+
+ child_status(CHILD_PROCESSING);
+ return rv;
+}
+
+
+/* ------------------------------ net_write ------------------------------- */
+
+#ifndef NEEDS_WRITEV
+int net_writev(SYS_NETFD fd, struct iovec *iov, int iov_size)
+{
+ int rv;
+
+ child_status(CHILD_WRITING);
+ rv = PR_Writev(fd, (PRIOVec *)iov, iov_size, PR_INTERVAL_NO_TIMEOUT);
+ child_status(CHILD_PROCESSING);
+ return rv;
+}
+
+#else /* NEEDS_WRITEV */
+
+/* Since SSL and NT do not support writev(), we just emulate it.
+ * This does not lead to the optimal number of packets going out...
+ */
+int net_writev(SYS_NETFD fd, struct iovec *iov, int iov_size)
+{
+ int index;
+
+ child_status(CHILD_WRITING);
+
+ for (index=0; index<iov_size; index++) {
+
+ /* net_write already does the buffer for nonblocked IO */
+ if ( net_write(fd, iov[index].iov_base, iov[index].iov_len) ==IO_ERROR){
+ child_status(CHILD_PROCESSING);
+ return IO_ERROR;
+ }
+ }
+
+ child_status(CHILD_PROCESSING);
+ return IO_OKAY;
+}
+#endif /* NEEDS_WRITEV */
+
+
+NSAPI_PUBLIC int net_write(SYS_NETFD fd, char *buf, int sz)
+{
+ int rv;
+
+ child_status(CHILD_WRITING);
+ rv = PR_Send(fd, buf, sz, 0, PR_INTERVAL_NO_TIMEOUT);
+ child_status(CHILD_PROCESSING);
+ if(rv < 0) {
+ return IO_ERROR;
+ }
+ return rv;
+}
+
+NSAPI_PUBLIC int net_socketpair(SYS_NETFD *pair)
+{
+ return PR_NewTCPSocketPair(pair);
+}
+
+#ifdef XP_UNIX
+NSAPI_PUBLIC SYS_NETFD net_dup2(SYS_NETFD prfd, int osfd)
+{
+ SYS_NETFD newfd = NULL;
+
+ if (prfd && PR_FileDesc2NativeHandle(prfd) != osfd) {
+ if (dup2(PR_FileDesc2NativeHandle(prfd), osfd) != -1) {
+ newfd = PR_ImportFile(osfd);
+ if (!newfd)
+ close(osfd);
+ }
+ }
+
+ return newfd;
+}
+
+NSAPI_PUBLIC int net_is_STDOUT(SYS_NETFD prfd)
+{
+ int fd = PR_FileDesc2NativeHandle(prfd);
+ if (fd == STDOUT_FILENO) return 1;
+ return 0;
+}
+
+NSAPI_PUBLIC int net_is_STDIN(SYS_NETFD prfd)
+{
+ int fd = PR_FileDesc2NativeHandle(prfd);
+ if (fd == STDIN_FILENO) return 1;
+ return 0;
+}
+
+#endif /* XP_UNIX */
+
+/* -------------------------- Accept mutex crap --------------------------- */
+
+
+#ifndef NET_WINSOCK
+
+
+#include "sem.h"
+static SEMAPHORE mob_sem;
+static int have_mob_sem;
+
+
+void net_accept_enter(void)
+{
+ if(sem_grab(mob_sem) == -1)
+ ereport(LOG_CATASTROPHE, "sem_grab failed (%s)", system_errmsg());
+ have_mob_sem = 1;
+}
+
+int net_accept_tenter(void)
+{
+ int ret = sem_tgrab(mob_sem);
+ if(ret != -1)
+ have_mob_sem = 1;
+ return ret;
+}
+
+void net_accept_exit(void)
+{
+ if(sem_release(mob_sem) == -1)
+ ereport(LOG_CATASTROPHE, "sem_release failed (%s)", system_errmsg());
+ have_mob_sem = 0;
+}
+
+#ifdef AIX
+#undef accept
+#define accept naccept
+#endif
+
+void net_accept_texit(void)
+{
+ if(have_mob_sem && (sem_release(mob_sem) == -1))
+ ereport(LOG_CATASTROPHE, "sem_release failed (%s)", system_errmsg());
+ have_mob_sem = 0;
+}
+
+int net_accept_init(int port)
+{
+ /* XXXMB how to translate this to nspr? */
+ /* since SSL_AcceptHook is no longer in ns security (HCL_1_5),
+ so this is gone! (It does exist in HCL_101)
+ SSL_AcceptHook((SSLAcceptFunc)PR_Accept);
+ */
+ have_mob_sem = 0;
+ mob_sem = sem_init("netsite", port);
+ return (mob_sem == SEM_ERROR ? -1 : 0);
+}
+
+void net_accept_terminate(void)
+{
+ sem_terminate(mob_sem);
+}
+
+#endif /* !NET_WINSOCK */
+
+
+/* ----------------------------- net_ip2host ------------------------------ */
+
+
+char *dns_ip2host(char *ip, int verify);
+
+NSAPI_PUBLIC char *net_ip2host(char *ip, int verify)
+{
+ if(!net_enabledns)
+ return NULL;
+
+ return dns_ip2host(ip, verify);
+}
+
+
+
+/* ---------------------------- util_hostname ----------------------------- */
+
+
+
+#ifdef XP_UNIX
+#include <sys/param.h>
+#else /* WIN32 */
+#define MAXHOSTNAMELEN 255
+#endif /* XP_UNIX */
+
+/* Defined in dns.c */
+char *net_find_fqdn(PRHostEnt *p);
+
+NSAPI_PUBLIC char *util_hostname(void)
+{
+ char str[MAXHOSTNAMELEN];
+ PRHostEnt hent;
+ char buf[PR_NETDB_BUF_SIZE];
+ PRStatus err;
+
+ gethostname(str, MAXHOSTNAMELEN);
+ err = PR_GetHostByName(
+ str,
+ buf,
+ PR_NETDB_BUF_SIZE,
+ &hent);
+
+ if (err == PR_FAILURE)
+ return NULL;
+ return net_find_fqdn(&hent);
+}
+
+
diff --git a/lib/base/nscperror.c b/lib/base/nscperror.c
new file mode 100644
index 00000000..9d791f89
--- /dev/null
+++ b/lib/base/nscperror.c
@@ -0,0 +1,162 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* nscperrors.c
+ * Very crude error handling for nspr and libsec.
+ */
+
+#include "netsite.h"
+
+#define NSCP_NSPR_ERROR_BASE (-6000)
+#define NSCP_NSPR_MAX_ERROR (NSCP_NSPR_ERROR_BASE + 29)
+#define NSCP_LIBSEC_ERROR_BASE (-8192)
+#define NSCP_LIBSEC_MAX_ERROR (NSCP_LIBSEC_ERROR_BASE + 63)
+#define NSCP_LIBSSL_ERROR_BASE (-12288)
+#define NSCP_LIBSSL_MAX_ERROR (NSCP_LIBSSL_ERROR_BASE + 19)
+
+typedef struct nscp_error_t {
+ int errorNumber;
+ const char *errorString;
+} nscp_error_t;
+
+nscp_error_t nscp_nspr_errors[] = {
+ { 0, "NSPR error" },
+ { 1, "Out of memory" },
+ { 2, "Bad file descriptor" },
+ { 3, "Data temporarily not available" },
+ { 4, "Access fault" },
+ { 5, "Invalid method" },
+ { 6, "Illegal access" },
+ { 7, "Unknown error" },
+ { 8, "Pending interrupt" },
+ { 9, "Not implemented" },
+ { 10, "IO error" },
+ { 11, "IO timeout error" },
+ { 12, "IO already pending error" },
+ { 13, "Directory open error" },
+ { 14, "Invalid Argument" },
+ { 15, "Address not available" },
+ { 16, "Address not supported" },
+ { 17, "Already connected" },
+ { 18, "Bad address" },
+ { 19, "Address already in use" },
+ { 20, "Connection refused" },
+ { 21, "Network unreachable" },
+ { 22, "Connection timed out" },
+ { 23, "Not connected" },
+ { 24, "Load library error" },
+ { 25, "Unload library error" },
+ { 26, "Find symbol error" },
+ { 27, "Connection reset by peer" },
+ { 28, "Range Error" },
+ { 29, "File Not Found Error" }
+};
+
+nscp_error_t nscp_libsec_errors[] = {
+ { 0, "SEC_ERROR_IO" },
+ { 1, "SEC_ERROR_LIBRARY_FAILURE" },
+ { 2, "SEC_ERROR_BAD_DATA" },
+ { 3, "SEC_ERROR_OUTPUT_LEN" },
+ { 4, "SEC_ERROR_INPUT_LEN" },
+ { 5, "SEC_ERROR_INVALID_ARGS" },
+ { 6, "SEC_ERROR_INVALID_ALGORITHM" },
+ { 7, "SEC_ERROR_INVALID_AVA" },
+ { 8, "SEC_ERROR_INVALID_TIME" },
+ { 9, "SEC_ERROR_BAD_DER" },
+ { 10, "SEC_ERROR_BAD_SIGNATURE" },
+ { 11, "SEC_ERROR_EXPIRED_CERTIFICATE" },
+ { 12, "SEC_ERROR_REVOKED_CERTIFICATE" },
+ { 13, "SEC_ERROR_UNKNOWN_ISSUER" },
+ { 14, "SEC_ERROR_BAD_KEY" },
+ { 15, "SEC_ERROR_BAD_PASSWORD" },
+ { 16, "SEC_ERROR_UNUSED" },
+ { 17, "SEC_ERROR_NO_NODELOCK" },
+ { 18, "SEC_ERROR_BAD_DATABASE" },
+ { 19, "SEC_ERROR_NO_MEMORY" },
+ { 20, "SEC_ERROR_UNTRUSTED_ISSUER" },
+ { 21, "SEC_ERROR_UNTRUSTED_CERT" },
+ { 22, "SEC_ERROR_DUPLICATE_CERT" },
+ { 23, "SEC_ERROR_DUPLICATE_CERT_TIME" },
+ { 24, "SEC_ERROR_ADDING_CERT" },
+ { 25, "SEC_ERROR_FILING_KEY" },
+ { 26, "SEC_ERROR_NO_KEY" },
+ { 27, "SEC_ERROR_CERT_VALID" },
+ { 28, "SEC_ERROR_CERT_NOT_VALID" },
+ { 29, "SEC_ERROR_CERT_NO_RESPONSE" },
+ { 30, "SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE" },
+ { 31, "SEC_ERROR_CRL_EXPIRED" },
+ { 32, "SEC_ERROR_CRL_BAD_SIGNATURE" },
+ { 33, "SEC_ERROR_CRL_INVALID" },
+ { 34, "SEC_ERROR_" },
+ { 35, "SEC_ERROR_" },
+ { 36, "SEC_ERROR_" },
+ { 37, "SEC_ERROR_" },
+ { 38, "SEC_ERROR_" },
+ { 39, "SEC_ERROR_" },
+ { 40, "SEC_ERROR_" },
+ { 41, "SEC_ERROR_" },
+ { 42, "SEC_ERROR_" },
+ { 43, "SEC_ERROR_" },
+ { 44, "SEC_ERROR_" },
+ { 45, "SEC_ERROR_" },
+ { 46, "SEC_ERROR_" },
+ { 47, "SEC_ERROR_" },
+ { 48, "SEC_ERROR_" },
+ { 49, "SEC_ERROR_" },
+ { 50, "SEC_ERROR_" },
+ { 51, "SEC_ERROR_" },
+ { 52, "SEC_ERROR_" },
+ { 53, "SEC_ERROR_" },
+ { 54, "SEC_ERROR_" },
+ { 55, "SEC_ERROR_" },
+ { 56, "SEC_ERROR_" },
+ { 57, "SEC_ERROR_" },
+ { 58, "SEC_ERROR_" },
+ { 59, "SEC_ERROR_" },
+ { 60, "SEC_ERROR_" },
+ { 61, "SEC_ERROR_" },
+ { 62, "SEC_ERROR_" },
+ { 63, "SEC_ERROR_NEED_RANDOM" }
+};
+
+nscp_error_t nscp_libssl_errors[] = {
+ { 0, "SSL_ERROR_EXPORT_ONLY_SERVER" },
+ { 1, "SSL_ERROR_US_ONLY_SERVER" },
+ { 2, "SSL_ERROR_NO_CYPHER_OVERLAP" },
+ { 3, "SSL_ERROR_NO_CERTIFICATE" },
+ { 4, "SSL_ERROR_BAD_CERTIFICATE" },
+ { 5, "unused SSL error #5" },
+ { 6, "SSL_ERROR_BAD_CLIENT - the server has encountered bad data from the client." },
+ { 7, "SSL_ERROR_BAD_SERVER" },
+ { 8, "SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE" },
+ { 9, "SSL_ERROR_UNSUPPORTED_VERSION" },
+ { 10, "unused SSL error #10" },
+ { 11, "SSL_ERROR_WRONG_CERTIFICATE" },
+ { 12, "SSL_ERROR_BAD_CERT_DOMAIN" },
+ { 13, "SSL_ERROR_POST_WARNING" },
+ { 14, "SSL_ERROR_SSL2_DISABLED" },
+ { 15, "SSL_ERROR_BAD_MAC_READ - SSL has received a record with an incorrect Message Authentication Code." },
+ { 16, "SSL_ERROR_BAD_MAC_ALERT - SSL has received an error indicating an incorrect Message Authentication Code." },
+ { 17, "SSL_ERROR_BAD_CERT_ALERT - the server cannot verify your certificate." },
+ { 18, "SSL_ERROR_REVOKED_CERT_ALERT - the server has rejected your certificate as revoked." },
+ { 19, "SSL_ERROR_EXPIRED_CERT_ALERT - the server has rejected your certificate as expired." },
+};
+
+const char *
+nscperror_lookup(int error)
+{
+ if ((error >= NSCP_NSPR_ERROR_BASE) &&
+ (error <= NSCP_NSPR_MAX_ERROR)) {
+ return nscp_nspr_errors[error-NSCP_NSPR_ERROR_BASE].errorString;
+ } else if ((error >= NSCP_LIBSEC_ERROR_BASE) &&
+ (error <= NSCP_LIBSEC_MAX_ERROR)) {
+ return nscp_libsec_errors[error-NSCP_LIBSEC_ERROR_BASE].errorString;
+ } else if ((error >= NSCP_LIBSSL_ERROR_BASE) &&
+ (error <= NSCP_LIBSSL_MAX_ERROR)) {
+ return nscp_libssl_errors[error-NSCP_LIBSSL_ERROR_BASE].errorString;
+ } else {
+ return (const char *)NULL;
+ }
+}
diff --git a/lib/base/nterrors.cpp b/lib/base/nterrors.cpp
new file mode 100644
index 00000000..2eaf29b3
--- /dev/null
+++ b/lib/base/nterrors.cpp
@@ -0,0 +1,83 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * nterrors.c: Conversion of error numbers to explanation strings
+ *
+ * Aruna Victor 12/6/95
+ */
+
+
+#include <windows.h>
+#include <stdio.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <netsite.h>
+#include <base/nterrors.h>
+#include <base/nterr.h>
+
+struct _NtHashedError {
+ int ErrorNumber;
+ char *ErrorString;
+ struct _NtHashedError *next;
+} ;
+
+typedef struct _NtHashedError NtHashedError;
+
+NtHashedError *hashedNtErrors[200];
+
+#define HASH_ERROR_MODULUS 199
+#define DEFAULT_ERROR_STRING "Error Number is unknown"
+
+char *
+FindError(int error)
+{
+ NtHashedError *tmp;
+
+ int hashValue = error % HASH_ERROR_MODULUS;
+ tmp = hashedNtErrors[hashValue];
+
+ while(tmp) {
+ if (tmp->ErrorNumber == error) {
+ return tmp->ErrorString;
+ }
+ tmp = tmp->next;
+ }
+ return(DEFAULT_ERROR_STRING);
+}
+
+void
+EnterError(NtHashedError *error)
+{
+ NtHashedError *tmp;
+ int hashValue;
+ int number = 199;
+
+ hashValue = error->ErrorNumber % HASH_ERROR_MODULUS;
+
+ if(!(tmp = hashedNtErrors[hashValue])){
+ hashedNtErrors[hashValue] = error;
+ } else {
+ while(tmp->next) {
+ tmp = tmp->next;
+ }
+ tmp->next = error;
+ }
+}
+
+void
+HashNtErrors()
+{
+ NtHashedError *error;
+ int i = 0;
+
+ while(NtErrorStrings[i].ErrorString) {
+ error = (NtHashedError *)MALLOC(sizeof(NtHashedError));
+ error->ErrorNumber = NtErrorStrings[i].ErrorNumber;
+ error->ErrorString = NtErrorStrings[i++].ErrorString;
+ error->next = NULL;
+ EnterError(error);
+ }
+} \ No newline at end of file
diff --git a/lib/base/plist.cpp b/lib/base/plist.cpp
new file mode 100644
index 00000000..fe9d909e
--- /dev/null
+++ b/lib/base/plist.cpp
@@ -0,0 +1,1154 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * MODULE: plist.c
+ *
+ * DESCRIPTION:
+ *
+ * This module implements property lists. A property list is an
+ * ordered array of property values. Each property value has an
+ * handle for some data item, and may have a reference to
+ * another property list which describes the type of the data
+ * item. Each property value has a property index which specifies
+ * its position in the property list. A property value may also
+ * have a name. Since the data item associated with a property
+ * value may reference another property list, it is possible to
+ * construct arbitrary linked structures of property lists.
+ *
+ * IMPLEMENTATION NOTES:
+ */
+
+#include "netsite.h"
+#include "base/plist.h"
+#include "plist_pvt.h"
+
+int plistHashSizes[] = PLSTSIZES;
+
+/*
+ * FUNCTION: PListAssignValue
+ *
+ * DESCRIPTION:
+ *
+ * This function sets the value and/or type of a defined property
+ * in given property list. If the property type is specified as
+ * NULL, it is unchanged. However, the property value is always
+ * set to the specified value.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pname - the property name
+ * pvalue - the new property value
+ * ptype - the new property type, or NULL
+ *
+ * RETURNS:
+ *
+ * If successful, the property index of the referenced property is
+ * returned as the function value. Errors are indicated by a
+ * negative return code as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListAssignValue(PList_t plist, const char *pname,
+ const void *pvalue, PList_t ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t *pv;
+ int pindex;
+ int i;
+
+ if (!plist) return ERRPLUNDEF;
+
+ /* Got a symbol table for this property list? */
+ if (pl->pl_symtab) {
+
+ /* Yes, compute hash of specified name */
+ i = PListHashName(pl->pl_symtab, pname);
+
+ /* Search hash collision list for matching name */
+ for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) {
+
+ if (!strcmp(pname, pv->pv_name)) {
+
+ /* Name match, get property index */
+ pindex = pv->pv_pi;
+
+ /* Set the new value */
+ pv->pv_value = (char *)pvalue;
+
+ /* Set type if type is given */
+ if (ptype) pv->pv_type = (PListStruct_t *)ptype;
+
+ /* Return the property index */
+ return pindex;
+ }
+ }
+ }
+
+ /* Error - specified property name is undefined */
+ return ERRPLUNDEF;
+}
+
+/*
+ * FUNCTION: PListCreate
+ *
+ * DESCRIPTION:
+ *
+ * This function creates a new property list and returns a handle for
+ * it. It allows the caller to reserve a specified number of
+ * property indices at the beginning of the list, and also to limit
+ * the total number of property values that may be added to the list.
+ *
+ * ARGUMENTS:
+ *
+ * mempool - handle for a memory pool to be associated
+ * with the new property list
+ * resvprop - number of reserved property indices
+ * maxprop - maximum number of properties in list
+ * (zero or negative imposes no limit)
+ * flags - unused, reserved, must be zero
+ *
+ * RETURNS:
+ *
+ * If successful, the function return value is a handle for the new
+ * property list. Otherwise NULL is returned.
+ */
+
+NSAPI_PUBLIC PList_t
+PListCreate(pool_handle_t *mempool, int resvprop, int maxprop, int flags)
+{
+ PListStruct_t *plist; /* pointer to property list structure */
+ int i;
+
+ plist = (PListStruct_t *)pool_malloc(mempool, sizeof(PListStruct_t));
+ if (plist) {
+
+ /* Negative maxprop is the same as zero, i.e. no limit */
+ if (maxprop < 0) maxprop = 0;
+
+ /* If resvprop and maxprop are both specified, limit resvprop */
+ if (resvprop > 0) {
+ if (maxprop && (resvprop > maxprop)) resvprop = maxprop;
+ }
+ else resvprop = 0;
+
+ /* Initialize property list structure */
+ plist->pl_mempool = mempool;
+ plist->pl_symtab = NULL;
+ plist->pl_maxprop = maxprop;
+ plist->pl_resvpi = resvprop;
+ plist->pl_initpi = resvprop;
+ plist->pl_lastpi = resvprop;
+
+ /* Set initialize size for array of property value pointers */
+ plist->pl_cursize = (resvprop) ? resvprop : PLIST_DEFSIZE;
+
+ /* Allocate the initial array of property value pointers */
+ plist->pl_ppval = (pb_entry **)pool_malloc(mempool,
+ (plist->pl_cursize *
+ sizeof(PLValueStruct_t *)));
+ if (!plist->pl_ppval) {
+
+ /* Failed - insufficient memory */
+ pool_free(mempool, (void *)plist);
+ plist = NULL;
+ }
+ else {
+ /* NULL out pointers in the reserved index range, if any */
+ for (i = 0; i < plist->pl_lastpi; ++i) {
+ plist->pl_ppval[i] = 0;
+ }
+ }
+ }
+
+ return (PList_t)plist;
+}
+
+/*
+ * FUNCTION: PListDefProp
+ *
+ * DESCRIPTION:
+ *
+ * This function creates a new property in a specified property list.
+ * The 'pindex' argument may be used to request a particular property
+ * index for the new property. If 'pindex' is greater than zero,
+ * the specified value is used as the new property's index, provided
+ * there is no property at that index already. If 'pindex' is zero,
+ * then the next available property index is assigned to the new
+ * property. A name may optionally be specified for the new property.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - new property index (or zero)
+ * pname - new property name (or NULL)
+ *
+ * RETURNS:
+ *
+ * If successful, the index of the new property is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListDefProp(PList_t plist, int pindex, const char *pname, const int flags)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+ int cursize;
+ int i;
+ int wrapped;
+
+ if (!plist) return ERRPLUNDEF;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Is pindex specified? */
+ if (pindex > 0) {
+
+ /* Yes, is it in the reserved range? */
+ if (flags != PLFLG_IGN_RES && pindex > pl->pl_resvpi) {
+ /* No, error */
+ return ERRPLINVPI;
+ }
+
+ i = pindex - 1;
+
+ if (ppval[i]) {
+ /* Error - property already exists at specified index */
+ return ERRPLEXIST;
+ }
+ }
+ else {
+
+ /*
+ * Look for a free property index, starting at pl_lastpi + 1.
+ * (Note that i is the property index - 1)
+ */
+ for (wrapped = 0, i = pl->pl_lastpi; ;) {
+
+ /* Are we in an initialized part of the array? */
+ if (i < pl->pl_initpi) {
+
+ /* Yes, use this index if it's free */
+ if (ppval[i] == 0) break;
+
+ /* Otherwise step to the next one */
+ ++i;
+ }
+ else {
+
+ /* Have we reached the end yet? */
+ if (i < pl->pl_cursize) {
+
+ /*
+ * We are above the highest initialized index, but
+ * still within the allocated size. An index in
+ * this range can be used with no further checks.
+ */
+ ppval[i] = 0;
+ }
+ else {
+
+ /*
+ * It's looking like time to grow the array, but
+ * first go back and look for an unused, unreserved
+ * index that might have been freed.
+ */
+ if (!wrapped) {
+
+ i = pl->pl_resvpi;
+ wrapped = 1;
+ continue;
+ }
+
+ /*
+ * Grow the array unless there is a specified maximum
+ * size and we've reached it.
+ */
+ i = pl->pl_cursize;
+ if (pl->pl_maxprop && (i > pl->pl_maxprop)) {
+
+ /* Error - property list is full */
+ return ERRPLFULL;
+ }
+
+ /* Increase planned size of list */
+ cursize = i + PLIST_DEFGROW;
+
+ /* Reallocate the array of property value pointers */
+ ppval = (PLValueStruct_t **)pool_realloc(pl->pl_mempool,
+ (void *)ppval,
+ (cursize * sizeof(PLValueStruct_t *)));
+ if (!ppval) {
+
+ /* Error - insufficient memory */
+ return ERRPLNOMEM;
+ }
+
+ /* Initialize the first new entry and select it */
+ ppval[i] = NULL;
+ pl->pl_ppval = (pb_entry **)ppval;
+ pl->pl_cursize = cursize;
+ }
+
+ /* Update the highest initialized index value */
+ pl->pl_initpi = i + 1;
+ break;
+ }
+ }
+
+ /* Set the starting point for the next allocation */
+ pl->pl_lastpi = i + 1;
+ }
+
+ /* We have a property index (i + 1). Create a new property value */
+ pv = (PLValueStruct_t *)pool_calloc(pl->pl_mempool,
+ 1, sizeof(PLValueStruct_t));
+ if (!pv) {
+
+ /* Error - insufficient memory */
+ return ERRPLNOMEM;
+ }
+
+ pv->pv_pbentry.param = &pv->pv_pbparam;
+ pv->pv_pi = i + 1;
+ ppval[i] = pv;
+
+ /* Name the property if the name was specified */
+ if (pname) {
+
+ /* XXX Maybe should delete property if naming fails */
+ return PListNameProp(plist, i + 1, pname);
+ }
+
+ /* Return the property index of the new property */
+ return i + 1;
+}
+
+/*
+ * FUNCTION: PListDeleteProp
+ *
+ * DESCRIPTION:
+ *
+ * This function deletes a property from a specified property list.
+ * The property can be specified by its property index, using a
+ * pindex value greater than zero, or by its name, by specifying
+ * pindex as zero and pname as the property name. This does not
+ * have any effect on the data referenced by the property value,
+ * if any, nor does it have any effect on the property list that
+ * describes the property value's type, if any.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index, or zero
+ * pname - the property name, or NULL
+ */
+
+NSAPI_PUBLIC const void *
+PListDeleteProp(PList_t plist, int pindex, const char *pname_in)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t **pvp;
+ PLValueStruct_t *pv = NULL;
+ int i;
+ const void *pvalue = NULL;
+ char *pname = (char *)pname_in;
+
+ if (!plist) return NULL;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Get the pointer to the property structure */
+ pv = ppval[pindex - 1];
+ pname = 0;
+ if (pv) {
+ pname = pv->pv_name;
+ }
+ }
+
+ if (pname && pl->pl_symtab) {
+
+ /* Compute hash of specified property name */
+ i = PListHashName(pl->pl_symtab, pname);
+
+ /* Search hash collision list for matching name */
+ for (pvp = &pl->pl_symtab->pt_hash[i]; *pvp; pvp = &(*pvp)->pv_next) {
+
+ pv = *pvp;
+ if (!strcmp(pname, pv->pv_name)) {
+
+ /* Found it. Get its index and remove it. */
+ pindex = pv->pv_pi;
+ *pvp = pv->pv_next;
+ break;
+ }
+ }
+ }
+
+ /* Found the indicated property by index or name? */
+ if (pv) {
+
+ /* Yes, remove it from the property list */
+ ppval[pindex - 1] = NULL;
+
+ /* Free the property name, if any */
+ if (pv->pv_name) {
+ pool_free(pl->pl_mempool, (void *)(pv->pv_name));
+ }
+ pvalue = pv->pv_value;
+
+ /* Free the property */
+ pool_free(pl->pl_mempool, (void *)pv);
+ }
+ return(pvalue);
+}
+
+/*
+ * FUNCTION: PListFindValue
+ *
+ * DESCRIPTION:
+ *
+ * This function retrieves the value and type of a property with a
+ * specified property name. If the pvalue argument is non-NULL,
+ * it specifies a location in which to return the property value.
+ * Similarly, if ptype is non-NULL, it specifies where the property
+ * list describing the property type is to be returned. If a
+ * property has no value, the value returned for pvalue is NULL.
+ * If a property has no type, the value returned for ptype is NULL.
+ * A property can have a value, a type, both, or neither.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pname - pointer to property name string
+ * pvalue - property value return pointer
+ * ptype - property type return pointer
+ *
+ * RETURNS:
+ *
+ * If successful, the index of the referenced property is returned
+ * as the function value. Errors are indicated by a negative
+ * return code as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListFindValue(PList_t plist, const char *pname, void **pvalue, PList_t *ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t *pv;
+ int pindex;
+ int i;
+
+ if (!plist) return ERRPLUNDEF;
+
+ /* Got a symbol table for this property list? */
+ if (pl->pl_symtab) {
+
+ /* Yes, compute hash of specified name */
+ i = PListHashName(pl->pl_symtab, pname);
+
+ /* Search hash collision list for matching name */
+ for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) {
+
+ if (!strcmp(pname, pv->pv_name)) {
+
+ /* Name match, get property index */
+ pindex = pv->pv_pi;
+
+ /* Return the value if requested */
+ if (pvalue) *pvalue = (void *)(pv->pv_value);
+
+ /* Return the type if requested */
+ if (ptype) *ptype = (PList_t)(pv->pv_type);
+
+ /* Return the property index */
+ return pindex;
+ }
+ }
+ }
+
+ /* Error - specified property name is undefined */
+ return ERRPLUNDEF;
+}
+
+/*
+ * FUNCTION: PListInitProp
+ *
+ * DESCRIPTION:
+ *
+ * This function combines the functions of PListDefProp() and
+ * PListSetValue(), defining a new property and assigning it an
+ * initial value and optionally a type and/or a name.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - a reserved property index, or zero
+ * pname - the new property name, or NULL
+ * pvalue - the new property value
+ * ptype - the new property type, or NULL
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListInitProp(PList_t plist, int pindex, const char *pname,
+ const void *pvalue, PList_t ptype)
+{
+ int rv;
+
+ if (!plist) return ERRPLUNDEF;
+
+ /* Create the property */
+ rv = PListDefProp(plist, pindex, pname, PLFLG_USE_RES);
+ if (rv > 0) {
+
+ /* If that worked, set the value and type */
+ rv = PListSetValue(plist, rv, pvalue, ptype);
+ }
+
+ return rv;
+}
+
+/*
+ * FUNCTION: PListNew
+ *
+ * DESCRIPTION:
+ *
+ * This function creates a new property list, using the specified
+ * memory pool for allocating the internal data structures used to
+ * represent it. If the mempool argument is NULL, the default
+ * memory pool is used.
+ *
+ * ARGUMENTS:
+ *
+ * mempool - handle for a memory pool to be associated
+ * with the new property list
+ *
+ * RETURNS:
+ *
+ * If successful, the function return value is a handle for the new
+ * property list. Otherwise NULL is returned.
+ */
+
+NSAPI_PUBLIC PList_t
+PListNew(pool_handle_t *mempool)
+{
+ /* Just call PListCreate with default parameters */
+ return PListCreate(mempool, 0, 0, 0);
+}
+
+/*
+ * FUNCTION: PListDestroy
+ *
+ * DESCRIPTION:
+ *
+ * This function destroys a specified property list. This means
+ * that any dynamic memory which was allocated as a result of calls
+ * to the property list API is freed to the memory pool from which
+ * it was allocated. Property value data is not freed, nor are
+ * any property lists associated with property types.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ */
+
+void
+PListDestroy(PList_t plist)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+ int i;
+
+ if (!plist) return;
+
+ /* Free the property name symbol table if any */
+ if (pl->pl_symtab) {
+ pool_free(pl->pl_mempool, (void *)(pl->pl_symtab));
+ }
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Loop over the initialized property indices */
+ for (i = 0; i < pl->pl_initpi; ++i) {
+
+ /* Got a property here? */
+ pv = ppval[i];
+ if (pv) {
+
+ /* Free the property name string if any */
+ if (pv->pv_name) {
+ pool_free(pl->pl_mempool, (void *)(pv->pv_name));
+ }
+
+ /* Free the property value structure */
+ pool_free(pl->pl_mempool, (void *)pv);
+ }
+ }
+
+ /* Free the array of pointers to property values */
+ pool_free(pl->pl_mempool, (void *)ppval);
+
+ /* Free the property list head */
+ pool_free(pl->pl_mempool, (void *)pl);
+}
+
+/*
+ * FUNCTION: PListGetValue
+ *
+ * DESCRIPTION:
+ *
+ * This function retrieves the value and type of the property with
+ * the property index given by pindex in the specified property
+ * list. The pindex argument must specify the index of a defined
+ * property. If the pvalue argument is non-NULL, it specifies a
+ * location in which to return the property value. Similarly, if
+ * ptype is non-NULL, it specifies where the property list
+ * describing the property type is to be returned. If a property
+ * has no value, the value returned for pvalue is NULL. If a
+ * property has no type, the value returned for ptype is NULL. A
+ * property can have a value, a type, both, or neither.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index
+ * pvalue - property value return pointer
+ * ptype - property type return pointer
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListGetValue(PList_t plist, int pindex, void **pvalue, PList_t *ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+
+ if (!plist) return ERRPLUNDEF;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Does the property exist? */
+ pv = ppval[pindex - 1];
+ if (pv) {
+
+ /* Yes, return the value if requested */
+ if (pvalue) *pvalue = (void *)(pv->pv_value);
+
+ /* Return the type if requested */
+ if (ptype) *ptype = (PList_t)(pv->pv_type);
+
+ /* Successful return */
+ return pindex;
+ }
+ }
+
+ /* Error - invalid property index or non-existent property */
+ return ERRPLINVPI;
+}
+
+/*
+ * FUNCTION: PListHashName
+ *
+ * DESCRIPTION:
+ *
+ * This function hashes a given property name for a specified
+ * symbol table. It produces a value that can be used as an
+ * index in the pt_hash array associated with the symbol table.
+ *
+ * ARGUMENTS:
+ *
+ * symtab - pointer to the symbol table
+ * pname - pointer to the property name string
+ *
+ * RETURNS:
+ *
+ * The hash index is returned as the function value.
+ */
+
+int
+PListHashName(PLSymbolTable_t *symtab, const char *pname)
+{
+ unsigned int hashval = 0; /* hash value */
+
+ while (*pname) {
+ hashval = (hashval<<5) ^ (*pname++ & 0x7f);
+ }
+
+ return hashval % PLSIZENDX(symtab->pt_sizendx);
+}
+
+/*
+ * FUNCTION: PListNameProp
+ *
+ * DESCRIPTION:
+ *
+ * This function assigns a name to a defined property with the
+ * property index, pindex. If the property has an existing name,
+ * it will be replaced with the name specified by pname.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index
+ * pname - the new property name
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListNameProp(PList_t plist, int pindex, const char *pname)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t *pv;
+ PLSymbolTable_t *pt;
+ int i;
+
+ if (!plist) return ERRPLUNDEF;
+
+ pt = pl->pl_symtab;
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Does the property exist? */
+ pv = ((PLValueStruct_t **)(pl->pl_ppval))[pindex - 1];
+ if (pv) {
+
+ /* If it has a name already, unname it */
+ if (pv->pv_name) {
+ PLValueStruct_t **pvp;
+
+ /* Get hash bucket index */
+ i = PListHashName(pt, pv->pv_name);
+
+ /* Seach hash collision list for this property */
+ for (pvp = &pt->pt_hash[i];
+ *pvp; pvp = &(*pvp)->pv_next) {
+
+ if (*pvp == pv) {
+
+ /* Remove it from the list */
+ *pvp = pv->pv_next;
+ break;
+ }
+ }
+
+ /* Free the current name string */
+ pool_free(pl->pl_mempool, (void *)(pv->pv_name));
+ }
+
+ /* Got a new name? */
+ if (pname) {
+
+ /* Yes, is there a hash table? */
+ if (!pt) {
+
+ /* No, create one */
+ pt = (PLSymbolTable_t *)pool_calloc(pl->pl_mempool, 1,
+ PLHASHSIZE(0));
+ if (!pt) {
+ return ERRPLNOMEM;
+ }
+
+ pl->pl_symtab = pt;
+ }
+ else {
+
+ /* Is it time to grow the hash table? */
+ i = PLSIZENDX(pt->pt_sizendx);
+ if ((pt->pt_sizendx < PLMAXSIZENDX) &&
+ pt->pt_nsyms >= (i + i)) {
+
+ PLSymbolTable_t *npt;
+
+ /* Yes, allocate the new table */
+ npt = (PLSymbolTable_t *)pool_calloc(pl->pl_mempool, 1,
+ PLHASHSIZE(pt->pt_sizendx+1));
+ if (npt) {
+ PLValueStruct_t *opv;
+ PLValueStruct_t *npv;
+ int j;
+
+ npt->pt_sizendx = pt->pt_sizendx + 1;
+ npt->pt_nsyms = pt->pt_nsyms;
+
+ /* Rehash all the names into the new table */
+ for (i = 0; i < PLSIZENDX(pt->pt_sizendx); ++i) {
+ for (opv = pt->pt_hash[i]; opv; opv = npv) {
+ npv = opv->pv_next;
+ j = PListHashName(npt, opv->pv_name);
+ opv->pv_next = npt->pt_hash[j];
+ npt->pt_hash[j] = opv;
+ }
+ }
+
+ pl->pl_symtab = npt;
+
+ /* Free the old symbol table */
+ pool_free(pl->pl_mempool, (void *)pt);
+ pt = npt;
+ }
+ }
+ }
+
+ /* Duplicate the name string */
+ pv->pv_name = pool_strdup(pl->pl_mempool, (char *)pname);
+
+ /* Add name to symbol table */
+ i = PListHashName(pt, pname);
+ pv->pv_next = pt->pt_hash[i];
+ pt->pt_hash[i] = pv;
+ }
+
+ /* Successful return */
+ return pindex;
+ }
+ }
+
+ /* Error - invalid property index or non-existent property */
+ return ERRPLINVPI;
+}
+
+/*
+ * FUNCTION: PListSetType
+ *
+ * DESCRIPTION:
+ *
+ * This function sets the property type of the defined property
+ * with the property index, pindex. The property list describing
+ * the property type is specified by ptype. If ptype is NULL,
+ * the property type will be set to be undefined (NULL).
+ *
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index
+ * ptype - the new property type, or NULL
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListSetType(PList_t plist, int pindex, PList_t ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+
+ if (!plist) return ERRPLUNDEF;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Does the property exist? */
+ pv = ppval[pindex - 1];
+ if (pv) {
+
+ /* Yes, set the new type */
+ pv->pv_type = ptype;
+
+ /* Successful return */
+ return pindex;
+ }
+ }
+
+ /* Error - invalid property index or non-existent property */
+ return ERRPLINVPI;
+}
+
+/*
+ * FUNCTION: PListSetValue
+ *
+ * DESCRIPTION:
+ *
+ * This function sets the value and optionally the type of a
+ * defined property in a given property list. The pindex argument
+ * specifies the property index, which must be greater than zero.
+ * The ptype argument specifies a property list that describes the
+ * property type. If ptype is NULL, the property type, if any, is
+ * unchanged by this function. However, the property value is
+ * always set to the value given by pvalue.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * pindex - the property index
+ * pvalue - the new property value
+ * ptype - the new property type, or NULL
+ *
+ * RETURNS:
+ *
+ * If successful, the property index (pindex) is returned as the
+ * function value. Errors are indicated by a negative return code
+ * as defined in plist.h.
+ */
+
+NSAPI_PUBLIC int
+PListSetValue(PList_t plist, int pindex, const void *pvalue, PList_t ptype)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+
+ if (!plist) return ERRPLUNDEF;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Check for valid property index */
+ if ((pindex > 0) && (pindex <= pl->pl_initpi)) {
+
+ /* Does the property exist? */
+ pv = ppval[pindex - 1];
+ if (pv) {
+
+ /* Yes, set the new value */
+ pv->pv_value = (char *)pvalue;
+
+ /* Set type if type is given */
+ if (ptype) pv->pv_type = (PListStruct_t *)ptype;
+
+ /* Successful return */
+ return pindex;
+ }
+ }
+
+ /* Error - invalid property index or non-existent property */
+ return ERRPLINVPI;
+}
+
+/*
+ * FUNCTION: PListEnumerate
+ *
+ * DESCRIPTION:
+ *
+ * This function walks through a specified property list
+ * calling a user supplied function with the property
+ * name and value as parameters.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * user_func - handle for the user function
+ */
+
+NSAPI_PUBLIC void
+PListEnumerate(PList_t plist, PListFunc_t *user_func, void *user_data)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+ int i;
+
+ if (!plist) return;
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Loop over the initialized property indices */
+ for (i = 0; i < pl->pl_initpi; ++i) {
+
+ /* Got a property here? */
+ pv = ppval[i];
+ if (pv) {
+ (*user_func)(pv->pv_name, pv->pv_value, user_data);
+ }
+
+ }
+
+}
+
+/*
+ * FUNCTION: PListCreateDuplicate
+ *
+ * DESCRIPTION:
+ *
+ * This function creates a new property list and returns a handle for
+ * it. The source plist provides the new plists parameters.
+ *
+ * ARGUMENTS:
+ *
+ * src_plist - source plist to duplicate
+ * mempool - handle for a memory pool to be associated
+ * with the new property list, only
+ * used if flags is set to PLFLG_NEW_MPOOL
+ * flags - if PLFLG_NEW_MPOOL uses new_mempool
+ * parameter
+ *
+ * RETURNS:
+ *
+ * If successful, the function return value is a handle for the new
+ * property list. Otherwise NULL is returned.
+ */
+
+static PList_t
+PListCreateDuplicate(PList_t src_plist, pool_handle_t *new_mempool, int flags)
+{
+ PListStruct_t *plist; /* pointer to property list structure */
+ int i;
+ pool_handle_t *mempool;
+
+ mempool = (flags == PLFLG_NEW_MPOOL) ? new_mempool : src_plist->pl_mempool;
+
+ plist = (PListStruct_t *)pool_malloc(mempool, sizeof(PListStruct_t));
+ if (plist) {
+
+ /* Initialize property list structure */
+ plist->pl_mempool = mempool;
+ plist->pl_symtab = NULL;
+ plist->pl_maxprop = src_plist->pl_maxprop;
+ plist->pl_resvpi = src_plist->pl_resvpi;
+ plist->pl_initpi = src_plist->pl_initpi;
+ plist->pl_lastpi = src_plist->pl_lastpi;
+
+ /* Set initialize size for array of property value pointers */
+ plist->pl_cursize = src_plist->pl_cursize;
+
+ /* Allocate the initial array of property value pointers */
+ plist->pl_ppval = (pb_entry **)pool_malloc(mempool,
+ (plist->pl_cursize *
+ sizeof(PLValueStruct_t *)));
+ if (!plist->pl_ppval) {
+
+ /* Failed - insufficient memory */
+ pool_free(mempool, (void *)plist);
+ plist = NULL;
+ }
+ else {
+ /* NULL out pointers in the reserved index range, if any */
+ for (i = 0; i < plist->pl_lastpi; ++i) {
+ plist->pl_ppval[i] = 0;
+ }
+ }
+ }
+
+ return (PList_t)plist;
+}
+
+
+/*
+ * FUNCTION: PListDuplicate
+ *
+ * DESCRIPTION:
+ *
+ * This function duplicates a specified PList_t.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ * mempool - handle for a memory pool to be associated
+ * with the new property list
+ * resvprop - number of reserved property indices
+ * maxprop - maximum number of properties in list
+ * (zero or negative imposes no limit)
+ * flags - unused, reserved, must be zero
+ *
+ * RETURNS:
+ *
+ * If successful, the function return value is a handle for the new
+ * property list. Otherwise NULL is returned.
+ */
+
+NSAPI_PUBLIC PList_t
+PListDuplicate(PList_t plist, pool_handle_t *new_mempool, int flags)
+{
+ PListStruct_t *pl = (PListStruct_t *)plist;
+ PLValueStruct_t **ppval;
+ PLValueStruct_t *pv;
+ int i;
+ int rv = 0;
+ PList_t new_plist;
+
+ if (!plist) return NULL;
+
+ new_plist = PListCreateDuplicate(plist, new_mempool, flags);
+ if (new_plist == NULL) {
+ return(NULL);
+ }
+
+ ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+ /* Loop over the initialized property indices */
+ for (i = 0; i < pl->pl_initpi; ++i) {
+
+ /* Got a property here? */
+ pv = ppval[i];
+ if (pv) {
+ /* Create the property */
+ rv = PListDefProp(new_plist, i + 1, pv->pv_name, PLFLG_IGN_RES);
+ if (rv > 0) {
+
+ /* If that worked, set the value and type */
+ rv = PListSetValue(new_plist, rv, pv->pv_value, pv->pv_type);
+ }
+
+ if ( rv <= 0 ) {
+ PListDestroy(new_plist);
+ return(NULL);
+ }
+ }
+
+ }
+
+ return(new_plist);
+}
+
+/*
+ * FUNCTION: PListGetPool
+ *
+ * DESCRIPTION:
+ *
+ * This function returns the memory pool the PList is allocated from.
+ *
+ * ARGUMENTS:
+ *
+ * plist - handle for the property list
+ *
+ * RETURNS:
+ *
+ * The memory pool address, which can be NULL.
+ */
+
+NSAPI_PUBLIC pool_handle_t *
+PListGetPool(PList_t plist)
+{
+ if (!plist) return NULL;
+
+ return(plist->pl_mempool);
+}
+
diff --git a/lib/base/plist_pvt.h b/lib/base/plist_pvt.h
new file mode 100644
index 00000000..e4b861c5
--- /dev/null
+++ b/lib/base/plist_pvt.h
@@ -0,0 +1,122 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _PLIST_PVT_H
+#define _PLIST_PVT_H
+
+/*
+ * FILE: plist_pvt.h
+ *
+ * DESCRIPTION:
+ *
+ * This file contains private definitions for the property list
+ * utility implementation.
+ */
+
+#include "base/pool.h"
+
+/* Forward declarations */
+typedef struct PLValueStruct_s PLValueStruct_t;
+typedef struct PLSymbol_s PLSymbol_t;
+typedef struct PLSymbolTable_s PLSymbolTable_t;
+typedef struct PListStruct_s PListStruct_t;
+
+/*
+ * TYPE: PLValueStruct_t
+ *
+ * DESCRIPTION:
+ *
+ * This type represents a property value. It is dynamically
+ * allocated when a new property is added to a property list.
+ * It contains a reference to a property list that contains
+ * information about the property value, and a reference to
+ * the property value data.
+ */
+
+#ifndef PBLOCK_H
+#include "base/pblock.h"
+#endif /* PBLOCK_H */
+#include <stddef.h>
+
+struct PLValueStruct_s {
+ pb_entry pv_pbentry; /* used for pblock compatibility */
+ pb_param pv_pbparam; /* property name and value pointers */
+ PLValueStruct_t *pv_next; /* property name hash collision link */
+ PListStruct_t *pv_type; /* property value type reference */
+ int pv_pi; /* property index */
+ int pv_flags; /* bit flags */
+};
+
+#define pv_name pv_pbparam.name
+#define pv_value pv_pbparam.value
+
+/* pv_flags definitions */
+#define PVF_MALLOC 0x1 /* allocated via MALLOC */
+
+/* Offset to pv_pbparam in PLValueStruct_t */
+#define PVPBOFFSET offsetof(struct PLValueStruct_s,pv_pbparam)
+
+/* Convert pb_param pointer to PLValueStruct_t pointer */
+#define PATOPV(p) ((PLValueStruct_t *)((char *)(p) - PVPBOFFSET))
+
+/*
+ * TYPE: PLSymbolTable_t
+ *
+ * DESCRIPTION:
+ *
+ * This type represents a symbol table that maps property names
+ * to properties. It is dynamically allocated the first time a
+ * property is named.
+ */
+
+#define PLSTSIZES {7, 19, 31, 67, 123, 257, 513}
+#define PLMAXSIZENDX (sizeof(plistHashSizes)/sizeof(plistHashSizes[0]))
+
+struct PLSymbolTable_s {
+ int pt_sizendx; /* pt_hash size, as an index in PLSTSIZES */
+ int pt_nsyms; /* number of symbols in table */
+ PLValueStruct_t *pt_hash[1];/* variable-length array */
+};
+
+/*
+ * TYPE: PListStruct_t
+ *
+ * DESCRIPTION:
+ *
+ * This type represents the top-level of a property list structure.
+ * It is dynamically allocated when a property list is created, and
+ * freed when the property list is destroyed. It references a
+ * dynamically allocated array of pointers to property value
+ * structures (PLValueStruct_t).
+ */
+
+#define PLIST_DEFSIZE 8 /* default initial entries in pl_ppval */
+#define PLIST_DEFGROW 16 /* default incremental entries for pl_ppval */
+
+struct PListStruct_s {
+ pblock pl_pb; /* pblock subset of property list head */
+ PLSymbolTable_t *pl_symtab; /* property name to index symbol table */
+ pool_handle_t *pl_mempool; /* associated memory pool handle */
+ int pl_maxprop; /* maximum number of properties */
+ int pl_resvpi; /* number of reserved property indices */
+ int pl_lastpi; /* last allocated property index */
+ int pl_cursize; /* current size of pl_ppval in entries */
+};
+
+#define pl_initpi pl_pb.hsize /* number of pl_ppval entries initialized */
+#define pl_ppval pl_pb.ht /* pointer to array of value pointers */
+
+/* Convert pblock pointer to PListStruct_t pointer */
+#define PBTOPL(p) ((PListStruct_t *)(p))
+
+#define PLSIZENDX(i) (plistHashSizes[i])
+#define PLHASHSIZE(i) (sizeof(PLSymbolTable_t) + \
+ (PLSIZENDX(i) - 1)*sizeof(PLValueStruct_t *))
+
+extern int plistHashSizes[7];
+
+extern int PListHashName(PLSymbolTable_t *symtab, const char *pname);
+
+#endif /* _PLIST_PVT_H */
diff --git a/lib/base/pool.cpp b/lib/base/pool.cpp
new file mode 100644
index 00000000..56232e3f
--- /dev/null
+++ b/lib/base/pool.cpp
@@ -0,0 +1,654 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Generic pool handling routines.
+ *
+ * Hopefully these reduce the number of malloc/free calls.
+ *
+ *
+ * Thread warning:
+ * This implementation is thread safe. However, simultaneous
+ * mallocs/frees to the same "pool" are not safe. If you wish to
+ * use this module across multiple threads, you should define
+ * POOL_LOCKING which will make the malloc pools safe.
+ *
+ * Mike Belshe
+ * 11-20-95
+ *
+ */
+
+#include "netsite.h"
+#include "base/systems.h"
+#include "base/systhr.h"
+
+#ifdef MALLOC_POOLS
+#include "base/pool.h"
+#include "base/ereport.h"
+#include "base/session.h"
+#include "frame/req.h"
+#include "frame/http.h"
+#include "base/util.h"
+#include "base/crit.h"
+
+#include "base/dbtbase.h"
+
+#ifdef DEBUG
+#define POOL_ZERO_DEBUG
+#endif
+#undef POOL_LOCKING
+
+#define BLOCK_SIZE (32 * 1024)
+#define MAX_FREELIST_SIZE (BLOCK_SIZE * 32)
+
+/* WORD SIZE 8 sets us up for 8 byte alignment. */
+#define WORD_SIZE 8
+#undef ALIGN
+#define ALIGN(x) ( (x + WORD_SIZE-1) & (~(WORD_SIZE-1)) )
+
+/* block_t
+ * When the user allocates space, a BLOCK_SIZE (or larger) block is created in
+ * the pool. This block is used until all the space is eaten within it.
+ * When all the space is gone, a new block is created.
+ *
+ */
+typedef struct block_t {
+ char *data; /* the real alloc'd space */
+ char *start; /* first free byte in block */
+ char *end; /* ptr to end of block */
+ struct block_t *next; /* ptr to next block */
+} block_t;
+
+/* pool_t
+ * A pool is a collection of blocks. The blocks consist of multiple
+ * allocations of memory, but a single allocation cannot be freed by
+ * itself. Once the memory is allocated it is allocated until the
+ * entire pool is freed.
+ */
+typedef struct pool_t {
+#ifdef DEBUG_CACHES
+ time_t time_created;
+#endif
+#ifdef POOL_LOCKING
+ CRITICAL lock; /* lock for modifying the pool */
+#endif
+ block_t *curr_block; /* current block being used */
+ block_t *used_blocks; /* blocks that are all used up */
+ long size; /* size of memory in pool */
+ struct pool_t *next; /* known_pools list */
+} pool_t;
+
+/* known_pools
+ * Primarily for debugging, keep a list of all active malloc pools.
+ */
+static pool_t *known_pools = NULL;
+static CRITICAL known_pools_lock = NULL;
+static unsigned long pool_blocks_created = 0;
+static unsigned long pool_blocks_freed = 0;
+
+/* freelist
+ * Internally we maintain a list of free blocks which we try to pull from
+ * whenever possible. This list will never have more than MAX_FREELIST_SIZE
+ * bytes within it.
+ */
+static CRITICAL freelist_lock = NULL;
+static block_t *freelist = NULL;
+static unsigned long freelist_size = 0;
+static unsigned long freelist_max = MAX_FREELIST_SIZE;
+static int pool_disable = 0;
+
+int
+pool_internal_init()
+{
+ if (pool_disable == 0) {
+ if (known_pools_lock == NULL) {
+ known_pools_lock = crit_init();
+ freelist_lock = crit_init();
+ }
+ } else
+ ereport(LOG_INFORM, XP_GetAdminStr(DBT_poolInitMemoryPoolsDisabled_));
+
+ return 0;
+}
+
+NSAPI_PUBLIC int
+pool_init(pblock *pb, Session *sn, Request *rq)
+{
+ char *str_free_size = pblock_findval("free-size", pb);
+ char *str_pool_disable = pblock_findval("disable", pb);
+
+ if (str_free_size != NULL) {
+ if ( (freelist_max = atoi(str_free_size)) <= 0) {
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_poolInitFreeSize0UsingD_),
+ MAX_FREELIST_SIZE);
+ freelist_max = MAX_FREELIST_SIZE;
+ }
+ }
+
+ if (str_pool_disable && strcasecmp(str_pool_disable, "false") )
+ pool_disable = 1;
+ else
+ pool_disable = 0;
+
+ if (known_pools_lock == NULL) {
+ known_pools_lock = crit_init();
+ freelist_lock = crit_init();
+ }
+
+ return REQ_PROCEED;
+}
+
+
+static block_t *
+_create_block(int size)
+{
+ block_t *newblock = NULL;
+ long bytes = ALIGN(size);
+ block_t *free_ptr,
+ *last_free_ptr = NULL;
+
+ /* check freelist for large enough block first */
+
+ crit_enter(freelist_lock);
+ free_ptr = freelist;
+ while(free_ptr && ((free_ptr->end - free_ptr->data) < bytes)) {
+ last_free_ptr = free_ptr;
+ free_ptr = free_ptr->next;
+ }
+
+ if (free_ptr) {
+ newblock = free_ptr;
+ if (last_free_ptr)
+ last_free_ptr->next = free_ptr->next;
+ else
+ freelist = free_ptr->next;
+ freelist_size -= (newblock->end - newblock->data);
+ crit_exit(freelist_lock);
+ bytes = free_ptr->end - free_ptr->data;
+ }
+ else {
+ pool_blocks_created++;
+ crit_exit(freelist_lock);
+ if (((newblock = (block_t *)PERM_MALLOC(sizeof(block_t))) == NULL) ||
+ ((newblock->data = (char *)PERM_MALLOC(bytes)) == NULL)) {
+ ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolCreateBlockOutOfMemory_));
+ if (newblock)
+ PERM_FREE(newblock);
+ return NULL;
+ }
+ }
+ newblock->start = newblock->data;
+ newblock->end = newblock->data + bytes;
+ newblock->next = NULL;
+
+ return newblock;
+}
+
+/* Caller must hold lock for the pool */
+static void
+_free_block(block_t *block)
+{
+
+#ifdef POOL_ZERO_DEBUG
+ memset(block->data, 0xa, block->end-block->data);
+#endif /* POOL_ZERO_DEBUG */
+
+ if ((freelist_size + block->end - block->data) > freelist_max) {
+ /* Just have to delete the whole block! */
+
+ crit_enter(freelist_lock);
+ pool_blocks_freed++;
+ crit_exit(freelist_lock);
+
+ PERM_FREE(block->data);
+#ifdef POOL_ZERO_DEBUG
+ memset(block, 0xa, sizeof(block));
+#endif /* POOL_ZERO_DEBUG */
+
+ PERM_FREE(block);
+ return;
+ }
+ crit_enter(freelist_lock);
+ freelist_size += (block->end - block->data);
+ block->start = block->data;
+
+ block->next = freelist;
+ freelist = block;
+ crit_exit(freelist_lock);
+}
+
+/* ptr_in_pool()
+ * Checks to see if the given pointer is in the given pool.
+ * If true, returns a ptr to the block_t containing the ptr;
+ * otherwise returns NULL
+ */
+block_t *
+_ptr_in_pool(pool_t *pool, void *ptr)
+{
+ block_t *block_ptr = NULL;
+
+ /* try to find a block which contains this ptr */
+
+ if ( ((char *)ptr < (char *)pool->curr_block->end) &&
+ ((char *)ptr >= (char *)pool->curr_block->data) )
+ block_ptr = pool->curr_block;
+ else
+ for( block_ptr = pool->used_blocks;
+ block_ptr &&
+ (((char *)ptr >= (char *)block_ptr->end) &&
+ ((char *)ptr < (char *)block_ptr->data));
+ block_ptr = block_ptr->next);
+
+ return block_ptr;
+}
+
+
+NSAPI_PUBLIC pool_handle_t *
+pool_create()
+{
+ pool_t *newpool;
+
+ if (pool_disable)
+ return NULL;
+
+ newpool = (pool_t *)PERM_MALLOC(sizeof(pool_t));
+
+ if (newpool) {
+ /* Have to initialize now, as pools get created sometimes
+ * before pool_init can be called...
+ */
+ if (known_pools_lock == NULL) {
+ known_pools_lock = crit_init();
+ freelist_lock = crit_init();
+ }
+
+ if ( (newpool->curr_block =_create_block(BLOCK_SIZE)) == NULL) {
+ ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolCreateOutOfMemory_));
+ PERM_FREE(newpool);
+ return NULL;
+ }
+ newpool->used_blocks = NULL;
+ newpool->size = 0;
+ newpool->next = NULL;
+#ifdef POOL_LOCKING
+ newpool->lock = crit_init();
+#endif
+#ifdef DEBUG_CACHES
+ newpool->time_created = time(NULL);
+#endif
+
+ /* Add to known pools list */
+ crit_enter(known_pools_lock);
+ newpool->next = known_pools;
+ known_pools = newpool;
+ crit_exit(known_pools_lock);
+ }
+ else
+ ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolCreateOutOfMemory_1));
+
+ return (pool_handle_t *)newpool;
+}
+
+NSAPI_PUBLIC void
+pool_destroy(pool_handle_t *pool_handle)
+{
+ pool_t *pool = (pool_t *)pool_handle;
+ block_t *tmp_blk;
+ pool_t *last, *search;
+
+ if (pool_disable)
+ return;
+
+ crit_enter(known_pools_lock);
+#ifdef POOL_LOCKING
+ crit_enter(pool->lock);
+#endif
+
+ if (pool->curr_block)
+ _free_block(pool->curr_block);
+
+ while(pool->used_blocks) {
+ tmp_blk = pool->used_blocks;
+ pool->used_blocks = pool->used_blocks->next;
+ _free_block(tmp_blk);
+ }
+
+ /* Remove from the known pools list */
+ for (last = NULL, search = known_pools; search;
+ last = search, search = search->next)
+ if (search == pool)
+ break;
+ if (search) {
+ if(last)
+ last->next = search->next;
+ else
+ known_pools = search->next;
+
+ }
+
+#ifdef POOL_LOCKING
+ crit_exit(pool->lock);
+ crit_terminate(pool->lock);
+#endif
+ crit_exit(known_pools_lock);
+
+#ifdef POOL_ZERO_DEBUG
+ memset(pool, 0xa, sizeof(pool));
+#endif /* POOL_ZERO_DEBUG */
+
+ PERM_FREE(pool);
+
+ return;
+}
+
+
+NSAPI_PUBLIC void *
+pool_malloc(pool_handle_t *pool_handle, size_t size)
+{
+ pool_t *pool = (pool_t *)pool_handle;
+ long reqsize, blocksize;
+ char *ptr;
+
+ if (pool == NULL || pool_disable) {
+ return PERM_MALLOC(size);
+ }
+
+#ifdef DEBUG
+ if (size == 0)
+ return NULL;
+#endif
+
+#ifdef POOL_LOCKING
+ crit_enter(pool->lock);
+#endif
+
+ reqsize = ALIGN(size);
+ ptr = pool->curr_block->start;
+ pool->curr_block->start += reqsize;
+
+ /* does this fit into the last allocated block? */
+ if (pool->curr_block->start > pool->curr_block->end) {
+
+ /* Did not fit; time to allocate a new block */
+
+ pool->curr_block->start -= reqsize; /* keep structs in tact */
+
+ pool->curr_block->next = pool->used_blocks;
+ pool->used_blocks = pool->curr_block;
+
+ /* Allocate a chunk of memory which is a multiple of BLOCK_SIZE
+ * bytes
+ */
+ blocksize = ( (size + BLOCK_SIZE-1) / BLOCK_SIZE ) * BLOCK_SIZE;
+ if ( (pool->curr_block = _create_block(blocksize)) == NULL) {
+ ereport(LOG_CATASTROPHE, XP_GetAdminStr(DBT_poolMallocOutOfMemory_));
+#ifdef POOL_LOCKING
+ crit_exit(pool->lock);
+#endif
+ return NULL;
+ }
+
+ ptr = pool->curr_block->start;
+ reqsize = ALIGN(size);
+ pool->curr_block->start += reqsize;
+ }
+
+ pool->size += reqsize;
+
+#ifdef POOL_LOCKING
+ crit_exit(pool->lock);
+#endif
+ return ptr;
+}
+
+void _pool_free_error()
+{
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_freeUsedWherePermFreeShouldHaveB_));
+
+ return;
+}
+
+NSAPI_PUBLIC void
+pool_free(pool_handle_t *pool_handle, void *ptr)
+{
+ if (pool_handle == NULL || pool_disable) {
+ PERM_FREE(ptr);
+ return;
+ }
+
+#ifdef DEBUG
+ /* Just to be nice, check to see if the ptr was allocated in a pool.
+ * If not, issue a warning and do a REAL free just to make sure that
+ * we don't leak memory.
+ */
+ if ( !_ptr_in_pool((pool_t *)pool_handle, ptr) ) {
+ _pool_free_error();
+
+ PERM_FREE(ptr);
+ }
+#endif
+ return;
+}
+
+NSAPI_PUBLIC void *
+pool_calloc(pool_handle_t *pool_handle, size_t nelem, size_t elsize)
+{
+ void *ptr;
+
+ if (pool_handle == NULL || pool_disable)
+ return PERM_CALLOC(elsize * nelem);
+
+ ptr = pool_malloc(pool_handle, elsize * nelem);
+ if (ptr)
+ memset(ptr, 0, elsize * nelem);
+ return ptr;
+}
+
+NSAPI_PUBLIC void *
+pool_realloc(pool_handle_t *pool_handle, void *ptr, size_t size)
+{
+ pool_t *pool = (pool_t *)pool_handle;
+ void *newptr;
+ block_t *block_ptr;
+ int oldsize;
+
+ if (pool_handle == NULL || pool_disable)
+ return PERM_REALLOC(ptr, size);
+
+ if ( (newptr = pool_malloc(pool_handle, size)) == NULL)
+ return NULL;
+
+ /* With our structure we don't know exactly where the end
+ * of the original block is. But we do know an upper bound
+ * which is a valid ptr. Search the outstanding blocks
+ * for the block which contains this ptr, and copy...
+ */
+#ifdef POOL_LOCKING
+ crit_enter(pool->lock);
+#endif
+
+ if ( !(block_ptr = _ptr_in_pool(pool, ptr)) ) {
+ /* User is trying to realloc nonmalloc'd space! */
+ return newptr;
+ }
+
+ oldsize = block_ptr->end - (char *)ptr ;
+ if (oldsize > size)
+ oldsize = size;
+ memmove((char *)newptr, (char *)ptr, oldsize);
+#ifdef POOL_LOCKING
+ crit_exit(pool->lock);
+#endif
+
+ return newptr;
+}
+
+NSAPI_PUBLIC char *
+pool_strdup(pool_handle_t *pool_handle, const char *orig_str)
+{
+ char *new_str;
+ int len = strlen(orig_str);
+
+ if (pool_handle == NULL || pool_disable)
+ return PERM_STRDUP(orig_str);
+
+ new_str = (char *)pool_malloc(pool_handle, len+1);
+
+ if (new_str)
+ memcpy(new_str, orig_str, len+1);
+
+ return new_str;
+}
+
+NSAPI_PUBLIC long
+pool_space(pool_handle_t *pool_handle)
+{
+ pool_t *pool = (pool_t *)pool_handle;
+
+ return pool->size;
+}
+
+NSAPI_PUBLIC int pool_enabled()
+{
+#ifndef THREAD_ANY
+ /* we don't have USE_NSPR defined so systhread_getdata is undef'ed */
+ return 0;
+#else
+ if (pool_disable || (getThreadMallocKey() == -1) )
+ return 0;
+
+ if (!systhread_getdata(getThreadMallocKey()))
+ return 0;
+
+ return 1;
+#endif
+}
+
+
+/* pool_service_debug()
+ * NSAPI service routine to print state information about the existing
+ * pools. Hopefully useful in debugging.
+ *
+ */
+#define MAX_DEBUG_LINE 1024
+#ifdef DEBUG_CACHES /* XXXrobm causes entanglement in install and admserv cgis */
+NSAPI_PUBLIC int
+pool_service_debug(pblock *pb, Session *sn, Request *rq)
+{
+ char tmp_buf[MAX_DEBUG_LINE];
+ char cbuf[DEF_CTIMEBUF];
+ int len;
+ pool_t *pool_ptr;
+ block_t *block_ptr;
+ int pool_cnt, block_cnt;
+
+ param_free(pblock_remove("content-type", rq->srvhdrs));
+ pblock_nvinsert("content-type", "text/html", rq->srvhdrs);
+
+ protocol_status(sn, rq, PROTOCOL_OK, NULL);
+ protocol_start_response(sn, rq);
+
+ len = util_sprintf(tmp_buf, "<H2>Memory pool status report</H2>\n");
+ net_write(sn->csd, tmp_buf, len);
+
+ len = util_sprintf(tmp_buf, "Note: The 0 block in each pool is \
+the currently used block <P>\n");
+ net_write(sn->csd, tmp_buf, len);
+
+ len = util_sprintf(tmp_buf, "Freelist size: %d/%d<P>", freelist_size,
+ freelist_max);
+ net_write(sn->csd, tmp_buf, len);
+
+ len = util_sprintf(tmp_buf, "Pool disabled: %d<P>", pool_disable);
+ net_write(sn->csd, tmp_buf, len);
+
+ len = util_sprintf(tmp_buf, "Blocks created: %d<P> Blocks freed: %d",
+ pool_blocks_created, pool_blocks_freed);
+ net_write(sn->csd, tmp_buf, len);
+
+ /* Create an HTML table */
+ len = util_sprintf(tmp_buf, "<UL><TABLE BORDER=4>\n");
+ net_write(sn->csd, tmp_buf, len);
+ len = util_sprintf(tmp_buf, "<TH>Pool #</TH>\n");
+ net_write(sn->csd, tmp_buf, len);
+ len = util_sprintf(tmp_buf, "<TH>Pool size #</TH>\n");
+ net_write(sn->csd, tmp_buf, len);
+#ifdef DEBUG_CACHES
+ len = util_sprintf(tmp_buf, "<TH>Time Created</TH>\n");
+ net_write(sn->csd, tmp_buf, len);
+#endif
+ len = util_sprintf(tmp_buf, "<TH>Blocks</TH>\n");
+ net_write(sn->csd, tmp_buf, len);
+
+ crit_enter(known_pools_lock);
+ for (pool_cnt = 0, pool_ptr = known_pools; pool_ptr;
+ pool_ptr = pool_ptr->next, pool_cnt++) {
+
+#ifdef POOL_LOCKING
+ crit_enter(pool_ptr->lock);
+#endif
+ len = util_snprintf(tmp_buf, MAX_DEBUG_LINE,
+#ifndef DEBUG_CACHES
+"<tr align=right> <td>%d</td> <td>%d</td> <td> <TABLE BORDER=2> <TH>Block #</TH><TH>data</TH><TH>curr size</TH> <TH>max size</TH>\n",
+#else
+"<tr align=right> <td>%d</td> <td>%d</td> <td>%s</td> <td> <TABLE BORDER=2> <TH>Block #</TH><TH>data</TH><TH>curr size</TH> <TH>max size</TH>\n",
+#endif
+ pool_cnt, pool_space((pool_handle_t *)pool_ptr)
+#ifdef DEBUG_CACHES
+ , util_ctime(&(pool_ptr->time_created), cbuf, DEF_CTIMEBUF));
+#else
+ );
+#endif
+ net_write(sn->csd, tmp_buf, len);
+
+ /* Print the first block */
+ len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, "\
+<tr align=right> \
+<td>%d</td> \
+<td>%d</td> \
+<td>%d</td> \
+<td>%d</td> \
+</tr>\n",
+ 0, pool_ptr->curr_block->data,
+ pool_ptr->curr_block->start -pool_ptr->curr_block->data,
+ pool_ptr->curr_block->end - pool_ptr->curr_block->data);
+
+ net_write(sn->csd, tmp_buf, len);
+
+ for (block_cnt = 1, block_ptr = pool_ptr->used_blocks; block_ptr;
+ block_ptr = block_ptr->next, block_cnt++) {
+
+ len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, "\
+<tr align=right> \
+<td>%d</td> \
+<td>%d</td> \
+<td>%d</td> \
+<td>%d</td> \
+</tr>\n",
+ block_cnt, block_ptr->data,
+ block_ptr->start - block_ptr->data,
+ block_ptr->end - block_ptr->data);
+
+ net_write(sn->csd, tmp_buf, len);
+ }
+#ifdef POOL_LOCKING
+ crit_exit(pool_ptr->lock);
+#endif
+
+ len = util_snprintf(tmp_buf, MAX_DEBUG_LINE, "</TABLE></TD></TR>");
+
+ net_write(sn->csd, tmp_buf, len);
+ }
+ crit_exit(known_pools_lock);
+
+ len = util_sprintf(tmp_buf, "</TABLE></UL>\n");
+ net_write(sn->csd, tmp_buf, len);
+
+ return REQ_PROCEED;
+
+}
+#endif /* 0 */
+#endif /* MALLOC_POOLS */
+
diff --git a/lib/base/rwlock.cpp b/lib/base/rwlock.cpp
new file mode 100644
index 00000000..1b99e062
--- /dev/null
+++ b/lib/base/rwlock.cpp
@@ -0,0 +1,131 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <stdlib.h>
+#include "crit.h"
+#include "rwlock.h"
+
+/*
+ * rwLock.c
+ * Implements a shared/exclusive lock package atop the
+ * critical section/condition variables. It allows multiple
+ * shared lock holders and only one exclusive lock holder
+ * on a lock variable.
+ *
+ * NOTE : It currently favors writers over readers and writers
+ * may starve readers. It is usually preferable to allow updates
+ * if they are not as frequent. We may have to change this if
+ * the common usage pattern differs from this.
+ */
+
+typedef struct {
+ CRITICAL crit; /* Short term crit to synchronize lock ops */
+ CONDVAR readFree; /* Indicates lock is free for readers */
+ CONDVAR writeFree; /* Indicates lock is free for the writer */
+ int numReaders; /* Number of read locks held */
+ int write; /* Flag to indicate write lock held */
+ int numWriteWaiters;/* Number of threads waiting for write lock */
+} rwLock_t;
+
+/*
+ * rwlock_init()
+ * Allocate and initialize the rwlock structure and return
+ * to the caller.
+ */
+RWLOCK rwlock_Init()
+{
+ rwLock_t *rwLockP;
+
+ rwLockP = (rwLock_t *)PERM_MALLOC(sizeof(rwLock_t));
+ rwLockP->numReaders = 0;
+ rwLockP->write = 0;
+ rwLockP->numWriteWaiters = 0;
+ rwLockP->crit = crit_init();
+ rwLockP->readFree = condvar_init(rwLockP->crit);
+ rwLockP->writeFree = condvar_init(rwLockP->crit);
+ return((RWLOCK)rwLockP);
+}
+
+/*
+ * rwlock_terminate()
+ * Terminate the associated condvars and critical sections
+ */
+void rwlock_Terminate(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_terminate(rwLockP->crit);
+ condvar_terminate(rwLockP->readFree);
+ condvar_terminate(rwLockP->writeFree);
+ PERM_FREE(rwLockP);
+}
+
+/*
+ * rwlock_ReadLock -- Obtain a shared lock. The caller would
+ * block if there are writers or writeWaiters.
+ */
+void rwlock_ReadLock(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_enter(rwLockP->crit);
+ while (rwLockP->write || rwLockP->numWriteWaiters != 0)
+ condvar_wait(rwLockP->readFree);
+ rwLockP->numReaders++;
+ crit_exit(rwLockP->crit);
+}
+
+/*
+ * rwlock_writeLock -- Obtain an exclusive lock. The caller would
+ * block if there are other readers or a writer.
+ */
+void rwlock_WriteLock(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_enter(rwLockP->crit);
+ rwLockP->numWriteWaiters++;
+ while (rwLockP->numReaders != 0 || rwLockP->write)
+ condvar_wait(rwLockP->writeFree);
+ rwLockP->numWriteWaiters--;
+ rwLockP->write = 1;
+ crit_exit(rwLockP->crit);
+}
+
+/*
+ * rw_Unlock -- Releases the lock.
+ */
+void rwlock_Unlock(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_enter(rwLockP->crit);
+ if (rwLockP->write)
+ rwLockP->write = 0;
+ else
+ rwLockP->numReaders--;
+ if (rwLockP->numReaders == 0)
+ if (rwLockP->numWriteWaiters != 0)
+ condvar_notify(rwLockP->writeFree);
+ else
+ condvar_notifyAll(rwLockP->readFree);
+ crit_exit(rwLockP->crit);
+}
+
+/*
+ * rwlock_DemoteLock -- Change an exclusive lock on the given lock
+ * variable into a shared lock.
+ */
+void rwlock_DemoteLock(RWLOCK lockP)
+{
+ rwLock_t *rwLockP = (rwLock_t *)lockP;
+
+ crit_enter(rwLockP->crit);
+ rwLockP->numReaders = 1;
+ rwLockP->write = 0;
+ if (rwLockP->numWriteWaiters == 0)
+ condvar_notifyAll(rwLockP->readFree);
+ crit_exit(rwLockP->crit);
+}
diff --git a/lib/base/shexp.cpp b/lib/base/shexp.cpp
new file mode 100644
index 00000000..8cb2aae4
--- /dev/null
+++ b/lib/base/shexp.cpp
@@ -0,0 +1,290 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * shexp.c: shell-like wildcard match routines
+ *
+ *
+ * See shexp.h for public documentation.
+ *
+ * Rob McCool
+ *
+ */
+
+#include "shexp.h"
+#include <ctype.h> /* isalpha, tolower */
+
+
+/* ----------------------------- shexp_valid ------------------------------ */
+
+
+int valid_subexp(char *exp, char stop)
+{
+ register int x,y,t;
+ int nsc,np,tld;
+
+ x=0;nsc=0;tld=0;
+
+ while(exp[x] && (exp[x] != stop)) {
+ switch(exp[x]) {
+ case '~':
+ if(tld) return INVALID_SXP;
+ else ++tld;
+ case '*':
+ case '?':
+ case '^':
+ case '$':
+ ++nsc;
+ break;
+ case '[':
+ ++nsc;
+ if((!exp[++x]) || (exp[x] == ']'))
+ return INVALID_SXP;
+ for(++x;exp[x] && (exp[x] != ']');++x)
+ if(exp[x] == '\\')
+ if(!exp[++x])
+ return INVALID_SXP;
+ if(!exp[x])
+ return INVALID_SXP;
+ break;
+ case '(':
+ ++nsc;
+ while(1) {
+ if(exp[++x] == ')')
+ return INVALID_SXP;
+ for(y=x;(exp[y]) && (exp[y] != '|') && (exp[y] != ')');++y)
+ if(exp[y] == '\\')
+ if(!exp[++y])
+ return INVALID_SXP;
+ if(!exp[y])
+ return INVALID_SXP;
+ t = valid_subexp(&exp[x],exp[y]);
+ if(t == INVALID_SXP)
+ return INVALID_SXP;
+ x+=t;
+ if(exp[x] == ')') {
+ break;
+ }
+ }
+ break;
+ case ')':
+ case ']':
+ return INVALID_SXP;
+ case '\\':
+ if(!exp[++x])
+ return INVALID_SXP;
+ default:
+ break;
+ }
+ ++x;
+ }
+ if((!stop) && (!nsc))
+ return NON_SXP;
+ return ((exp[x] == stop) ? x : INVALID_SXP);
+}
+
+NSAPI_PUBLIC int shexp_valid(char *exp) {
+ int x;
+
+ x = valid_subexp(exp, '\0');
+ return (x < 0 ? x : VALID_SXP);
+}
+
+
+/* ----------------------------- shexp_match ----------------------------- */
+
+
+#define MATCH 0
+#define NOMATCH 1
+#define ABORTED -1
+
+int _shexp_match(char *str, char *exp);
+
+int handle_union(char *str, char *exp)
+{
+ char *e2 = (char *) MALLOC(sizeof(char)*strlen(exp));
+ register int t,p2,p1 = 1;
+ int cp;
+
+ while(1) {
+ for(cp=1;exp[cp] != ')';cp++)
+ if(exp[cp] == '\\')
+ ++cp;
+ for(p2 = 0;(exp[p1] != '|') && (p1 != cp);p1++,p2++) {
+ if(exp[p1] == '\\')
+ e2[p2++] = exp[p1++];
+ e2[p2] = exp[p1];
+ }
+ for(t=cp+1;(e2[p2] = exp[t]);++t,++p2);
+ if(_shexp_match(str,e2) == MATCH) {
+ FREE(e2);
+ return MATCH;
+ }
+ if(p1 == cp) {
+ FREE(e2);
+ return NOMATCH;
+ }
+ else ++p1;
+ }
+}
+
+
+int _shexp_match(char *str, char *exp)
+{
+ register int x,y;
+ int ret,neg;
+
+ ret = 0;
+ for(x=0,y=0;exp[y];++y,++x) {
+ if((!str[x]) && (exp[y] != '(') && (exp[y] != '$') && (exp[y] != '*'))
+ ret = ABORTED;
+ else {
+ switch(exp[y]) {
+ case '$':
+ if( (str[x]) )
+ ret = NOMATCH;
+ else
+ --x; /* we don't want loop to increment x */
+ break;
+ case '*':
+ while(exp[++y] == '*');
+ if(!exp[y])
+ return MATCH;
+ while(str[x]) {
+ switch(_shexp_match(&str[x++],&exp[y])) {
+ case NOMATCH:
+ continue;
+ case ABORTED:
+ ret = ABORTED;
+ break;
+ default:
+ return MATCH;
+ }
+ break;
+ }
+ if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
+ return MATCH;
+ else
+ ret = ABORTED;
+ break;
+ case '[':
+ if((neg = ((exp[++y] == '^') && (exp[y+1] != ']'))))
+ ++y;
+
+ if((isalnum(exp[y])) && (exp[y+1] == '-') &&
+ (isalnum(exp[y+2])) && (exp[y+3] == ']'))
+ {
+ int start = exp[y], end = exp[y+2];
+
+ /* Droolproofing for pinheads not included */
+ if(neg ^ ((str[x] < start) || (str[x] > end))) {
+ ret = NOMATCH;
+ break;
+ }
+ y+=3;
+ }
+ else {
+ int matched;
+
+ for(matched=0;exp[y] != ']';y++)
+ matched |= (str[x] == exp[y]);
+ if(neg ^ (!matched))
+ ret = NOMATCH;
+ }
+ break;
+ case '(':
+ return handle_union(&str[x],&exp[y]);
+ break;
+ case '?':
+ break;
+ case '\\':
+ ++y;
+ default:
+#ifdef XP_UNIX
+ if(str[x] != exp[y])
+#else /* XP_WIN32 */
+ if(strnicmp(str + x, exp + y, 1))
+#endif /* XP_WIN32 */
+ ret = NOMATCH;
+ break;
+ }
+ }
+ if(ret)
+ break;
+ }
+ return (ret ? ret : (str[x] ? NOMATCH : MATCH));
+}
+
+NSAPI_PUBLIC int shexp_match(char *str, char *xp) {
+ register int x;
+ char *exp = STRDUP(xp);
+
+ for(x=strlen(exp)-1;x;--x) {
+ if((exp[x] == '~') && (exp[x-1] != '\\')) {
+ exp[x] = '\0';
+ if(_shexp_match(str,&exp[++x]) == MATCH)
+ goto punt;
+ break;
+ }
+ }
+ if(_shexp_match(str,exp) == MATCH) {
+ FREE(exp);
+ return 0;
+ }
+
+ punt:
+ FREE(exp);
+ return 1;
+}
+
+
+/* ------------------------------ shexp_cmp ------------------------------- */
+
+
+NSAPI_PUBLIC int shexp_cmp(char *str, char *exp)
+{
+ switch(shexp_valid(exp)) {
+ case INVALID_SXP:
+ return -1;
+ case NON_SXP:
+#ifdef XP_UNIX
+ return (strcmp(exp,str) ? 1 : 0);
+#else /* XP_WIN32 */
+ return (stricmp(exp,str) ? 1 : 0);
+#endif /* XP_WIN32 */
+ default:
+ return shexp_match(str, exp);
+ }
+}
+
+
+/* ---------------------------- shexp_casecmp ----------------------------- */
+
+
+NSAPI_PUBLIC int shexp_casecmp(char *str, char *exp)
+{
+ char *lstr = STRDUP(str), *lexp = STRDUP(exp), *t;
+ int ret;
+
+ for(t = lstr; *t; t++)
+ if(isalpha(*t)) *t = tolower(*t);
+ for(t = lexp; *t; t++)
+ if(isalpha(*t)) *t = tolower(*t);
+
+ switch(shexp_valid(lexp)) {
+ case INVALID_SXP:
+ ret = -1;
+ break;
+ case NON_SXP:
+ ret = (strcmp(lexp, lstr) ? 1 : 0);
+ break;
+ default:
+ ret = shexp_match(lstr, lexp);
+ }
+ FREE(lstr);
+ FREE(lexp);
+ return ret;
+}
+
diff --git a/lib/base/shmem.cpp b/lib/base/shmem.cpp
new file mode 100644
index 00000000..1ddd76d3
--- /dev/null
+++ b/lib/base/shmem.cpp
@@ -0,0 +1,127 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * shmem.h: Portable abstraction for memory shared among a server's workers
+ *
+ * Rob McCool
+ */
+
+
+#include "shmem.h"
+
+#if defined (SHMEM_UNIX_MMAP)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <private/pprio.h> /* for nspr20 binary release */
+
+NSPR_BEGIN_EXTERN_C
+#include <sys/mman.h>
+NSPR_END_EXTERN_C
+
+NSAPI_PUBLIC shmem_s *shmem_alloc(char *name, int size, int expose)
+{
+ shmem_s *ret = (shmem_s *) PERM_MALLOC(sizeof(shmem_s));
+ char *growme;
+
+ if( (ret->fd = PR_Open(name, PR_RDWR | PR_CREATE_FILE | PR_TRUNCATE, 0666)) == NULL) {
+ PERM_FREE(ret);
+ return NULL;
+ }
+ growme = (char *) PERM_MALLOC(size);
+ ZERO(growme, size);
+ if(PR_Write(ret->fd, (char *)growme, size) < 0) {
+ PR_Close(ret->fd);
+ PERM_FREE(growme);
+ PERM_FREE(ret);
+ return NULL;
+ }
+ PERM_FREE(growme);
+ PR_Seek(ret->fd, 0, PR_SEEK_SET);
+ if( (ret->data = (char *)mmap(NULL, size, PROT_READ | PROT_WRITE,
+ SHMEM_MMAP_FLAGS, PR_FileDesc2NativeHandle(ret->fd), 0)) == (caddr_t) -1)
+ {
+ PR_Close(ret->fd);
+ PERM_FREE(ret);
+ return NULL;
+ }
+ if(!expose) {
+ ret->name = NULL;
+ unlink(name);
+ }
+ else
+ ret->name = STRDUP(name);
+ ret->size = size;
+ return ret;
+}
+
+
+NSAPI_PUBLIC void shmem_free(shmem_s *region)
+{
+ if(region->name) {
+ unlink(region->name);
+ PERM_FREE(region->name);
+ }
+ munmap((char *)region->data, region->size); /* CLEARLY, C++ SUCKS */
+ PR_Close(region->fd);
+ PERM_FREE(region);
+}
+
+#elif defined (SHMEM_WIN32_MMAP)
+
+#define PAGE_SIZE (1024*8)
+#define ALIGN(x) ( (x+PAGE_SIZE-1) & (~(PAGE_SIZE-1)) )
+NSAPI_PUBLIC shmem_s *shmem_alloc(char *name, int size, int expose)
+{
+ shmem_s *ret = (shmem_s *) PERM_MALLOC(sizeof(shmem_s));
+ HANDLE fHandle;
+
+ ret->fd = 0; /* not used on NT */
+
+ size = ALIGN(size);
+ if( !(ret->fdmap = CreateFileMapping(
+ (HANDLE)0xffffffff,
+ NULL,
+ PAGE_READWRITE,
+ 0,
+ size,
+ name)) )
+ {
+ int err = GetLastError();
+ PERM_FREE(ret);
+ return NULL;
+ }
+ if( !(ret->data = (char *)MapViewOfFile (
+ ret->fdmap,
+ FILE_MAP_ALL_ACCESS,
+ 0,
+ 0,
+ 0)) )
+ {
+ CloseHandle(ret->fdmap);
+ PERM_FREE(ret);
+ return NULL;
+ }
+ ret->size = size;
+ ret->name = NULL;
+
+ return ret;
+}
+
+
+NSAPI_PUBLIC void shmem_free(shmem_s *region)
+{
+ if(region->name) {
+ DeleteFile(region->name);
+ PERM_FREE(region->name);
+ }
+ UnmapViewOfFile(region->data);
+ CloseHandle(region->fdmap);
+ PERM_FREE(region);
+}
+
+#endif /* SHMEM_WIN32_MMAP */
diff --git a/lib/base/system.cpp b/lib/base/system.cpp
new file mode 100644
index 00000000..e58538b4
--- /dev/null
+++ b/lib/base/system.cpp
@@ -0,0 +1,264 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * system.c: A grab bag of system-level abstractions
+ *
+ * Many authors
+ */
+
+#include "netsite.h"
+#include "base/nsassert.h"
+#include "base/ereport.h"
+
+#ifdef XP_WIN32
+#include <windows.h>
+static char *version = "Netscape Server/2.0";
+#endif
+
+#include "base/systems.h" /* find out if we have malloc pools */
+
+static int thread_malloc_key = -1;
+
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+#include "base/pool.h"
+#include "base/systhr.h"
+
+#define MALLOC_KEY \
+ ((pool_handle_t *)(thread_malloc_key != -1 ? systhread_getdata(thread_malloc_key) : NULL))
+
+#endif
+
+
+#ifdef MCC_DEBUG
+#define DEBUG_MALLOC
+#endif
+
+#ifdef DEBUG_MALLOC
+
+/* The debug malloc routines provide several functions:
+ *
+ * - detect allocated memory overflow/underflow
+ * - detect multiple frees
+ * - intentionally clobbers malloc'd buffers
+ * - intentionally clobbers freed buffers
+ */
+#define DEBUG_MAGIC 0x12345678
+#define DEBUG_MARGIN 32
+#define DEBUG_MARGIN_CHAR '*'
+#define DEBUG_MALLOC_CHAR '.'
+#define DEBUG_FREE_CHAR 'X'
+#endif /* DEBUG_MALLOC */
+
+/* On NT, the server version string is not statically encoded based
+ * upon a product compile define but dynamically set by the server
+ * exe at startup.
+ */
+
+NSAPI_PUBLIC char *system_version()
+{
+#ifdef XP_WIN32
+ return version;
+#else /* XP_UNIX */
+ return MAGNUS_VERSION_STRING;
+#endif /* XP_UNIX */
+}
+
+NSAPI_PUBLIC void system_version_set(char *server_version)
+{
+#ifdef XP_WIN32
+ version = PERM_STRDUP(server_version);
+#endif
+}
+
+
+NSAPI_PUBLIC void *system_malloc(int size)
+{
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ return pool_malloc(MALLOC_KEY, size);
+#else
+ return malloc(size);
+#endif
+}
+
+
+NSAPI_PUBLIC void *system_calloc(int size)
+{
+ void *ret;
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ ret = pool_malloc(MALLOC_KEY, size);
+#else
+ ret = malloc(size);
+#endif
+ if(ret)
+ ZERO(ret, size);
+ return ret;
+}
+
+
+NSAPI_PUBLIC void *system_realloc(void *ptr, int size)
+{
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ return pool_realloc(MALLOC_KEY, ptr, size);
+#else
+ return realloc(ptr, size);
+#endif
+}
+
+
+NSAPI_PUBLIC void system_free(void *ptr)
+{
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ pool_free(MALLOC_KEY, ptr);
+#else
+ NS_ASSERT(ptr);
+ free(ptr);
+#endif
+}
+
+NSAPI_PUBLIC char *system_strdup(const char *ptr)
+{
+ NS_ASSERT(ptr);
+#if defined(MALLOC_POOLS) && defined(MCC_HTTPD) && defined(THREAD_ANY)
+ return pool_strdup(MALLOC_KEY, ptr);
+#else
+ return strdup(ptr);
+#endif
+}
+
+
+NSAPI_PUBLIC void *system_malloc_perm(int size)
+{
+#ifndef DEBUG_MALLOC
+ return malloc(size);
+#else
+ char *ptr = (char *)malloc(size + 2*DEBUG_MARGIN+2*sizeof(int));
+ char *real_ptr;
+ int *magic;
+ int *length;
+
+ magic = (int *)ptr;
+ *magic = DEBUG_MAGIC;
+ ptr += sizeof(int);
+ length = (int *)ptr;
+ *length = size;
+ ptr += sizeof(int);
+ memset(ptr, DEBUG_MARGIN_CHAR, DEBUG_MARGIN);
+ ptr += DEBUG_MARGIN;
+ memset(ptr, DEBUG_MALLOC_CHAR, size);
+ real_ptr = ptr;
+ ptr += size;
+ memset(ptr, DEBUG_MARGIN_CHAR, DEBUG_MARGIN);
+
+ return real_ptr;
+#endif
+}
+
+NSAPI_PUBLIC void *system_calloc_perm(int size)
+{
+ void *ret = system_malloc_perm(size);
+ if(ret)
+ ZERO(ret, size);
+ return ret;
+}
+
+NSAPI_PUBLIC void *system_realloc_perm(void *ptr, int size)
+{
+#ifndef DEBUG_MALLOC
+ return realloc(ptr, size);
+#else
+ int *magic, *length;
+ char *baseptr;
+ char *cptr;
+
+ cptr = (char *)ptr - DEBUG_MARGIN - 2 * sizeof(int);
+ magic = (int *)cptr;
+ if (*magic == DEBUG_MAGIC) {
+ cptr += sizeof(int);
+ length = (int *)cptr;
+ if (*length < size) {
+ char *newptr = (char *)system_malloc_perm(size);
+ memcpy(newptr, ptr, *length);
+ system_free_perm(ptr);
+
+ return newptr;
+ }else {
+ return ptr;
+ }
+ } else {
+ ereport(LOG_WARN, "realloc: attempt to realloc to smaller size");
+ return realloc(ptr, size);
+ }
+
+#endif
+}
+
+NSAPI_PUBLIC void system_free_perm(void *ptr)
+{
+#ifdef DEBUG_MALLOC
+ int *length, *magic;
+ char *baseptr, *cptr;
+ int index;
+
+ NS_ASSERT(ptr);
+
+ cptr = baseptr = ((char *)ptr) - DEBUG_MARGIN - 2*sizeof(int);
+
+ magic = (int *)cptr;
+ if (*magic == DEBUG_MAGIC) {
+ cptr += sizeof(int);
+
+ length = (int *)cptr;
+
+ cptr += sizeof(int);
+ for (index=0; index<DEBUG_MARGIN; index++)
+ if (cptr[index] != DEBUG_MARGIN_CHAR) {
+ ereport(LOG_CATASTROPHE, "free: corrupt memory (prebounds overwrite)");
+ break;
+ }
+
+ cptr += DEBUG_MARGIN + *length;
+ for (index=0; index<DEBUG_MARGIN; index++)
+ if (cptr[index] != DEBUG_MARGIN_CHAR) {
+ ereport(LOG_CATASTROPHE, "free: corrupt memory (prebounds overwrite)");
+ break;
+ }
+
+ memset(baseptr, DEBUG_FREE_CHAR, *length + 2*DEBUG_MARGIN+sizeof(int));
+ } else {
+ ereport(LOG_CATASTROPHE, "free: freeing unallocated memory");
+ }
+ free(baseptr);
+#else
+ free(ptr);
+#endif
+}
+
+NSAPI_PUBLIC char *system_strdup_perm(const char *ptr)
+{
+#ifndef DEBUG_MALLOC
+ NS_ASSERT(ptr);
+ return strdup(ptr);
+#else
+ int len = strlen(ptr);
+ char *nptr = (char *)system_malloc_perm(len+1);
+ memcpy(nptr, ptr, len);
+ nptr[len] = '\0';
+ return nptr;
+#endif
+}
+
+NSAPI_PUBLIC int
+getThreadMallocKey(void)
+{
+ return thread_malloc_key;
+}
+
+void
+setThreadMallocKey(int key)
+{
+ thread_malloc_key = key;
+}
+
diff --git a/lib/base/systhr.cpp b/lib/base/systhr.cpp
new file mode 100644
index 00000000..ac29121a
--- /dev/null
+++ b/lib/base/systhr.cpp
@@ -0,0 +1,256 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * systhr.c: Abstracted threading mechanisms
+ *
+ * Rob McCool
+ */
+
+#include "systhr.h"
+#include "ereport.h"
+
+#define USE_NSPR
+#ifdef USE_NSPR
+#include "nspr.h"
+#include "private/prpriv.h"
+extern "C" {
+int32 PR_GetSysfdTableMax(void);
+int32 PR_SetSysfdTableSize(int table_size);
+}
+#endif
+#include "systems.h"
+
+#ifdef THREAD_WIN32
+#include <process.h>
+
+typedef struct {
+ HANDLE hand;
+ DWORD id;
+} sys_thread_s;
+
+#endif
+
+
+
+#if defined (USE_NSPR)
+
+
+#define DEFAULT_STACKSIZE (64*1024)
+
+static unsigned long _systhr_stacksize = DEFAULT_STACKSIZE;
+
+NSAPI_PUBLIC
+void systhread_set_default_stacksize(unsigned long size)
+{
+ _systhr_stacksize = size;
+}
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC SYS_THREAD
+#ifdef UnixWare /* for ANSI C++ standard, see base/systrh.h */
+systhread_start(int prio, int stksz, ArgFn_systhread_start fn, void *arg)
+#else
+systhread_start(int prio, int stksz, void (*fn)(void *), void *arg)
+#endif
+{
+#if (defined(Linux) || defined(SNI) || defined(UnixWare)) && !defined(USE_PTHREADS)
+ prio /= 8; /* quick and dirty fix for user thread priority scale problem */
+ if (prio > 3) prio = 3;
+#endif
+
+ PRThread *ret = PR_CreateThread(PR_USER_THREAD, (void (*)(void *))fn,
+ (void *)arg, (PRThreadPriority)prio,
+ PR_GLOBAL_THREAD, PR_UNJOINABLE_THREAD,
+ stksz ? stksz : _systhr_stacksize);
+ return (void *) ret;
+}
+
+NSPR_END_EXTERN_C
+
+
+NSAPI_PUBLIC SYS_THREAD systhread_current(void)
+{
+ return PR_GetCurrentThread();
+}
+
+NSAPI_PUBLIC void systhread_yield(void)
+{
+ /* PR_Yield(); */
+ PR_Sleep(PR_INTERVAL_NO_WAIT);
+}
+
+
+NSAPI_PUBLIC void systhread_timerset(int usec)
+{
+ /* This is an interesting problem. If you ever do turn on interrupts
+ * on the server, you're in for lots of fun with NSPR Threads
+ PR_StartEvents(usec); */
+}
+
+
+NSAPI_PUBLIC
+SYS_THREAD systhread_attach(void)
+{
+ PRThread *ret;
+ ret = PR_AttachThread(PR_USER_THREAD, PR_PRIORITY_NORMAL, NULL);
+
+ return (void *) ret;
+}
+
+NSAPI_PUBLIC
+void systhread_detach(SYS_THREAD thr)
+{
+ /* XXXMB - this is not correct! */
+ PR_DetachThread();
+}
+
+NSAPI_PUBLIC void systhread_terminate(SYS_THREAD thr)
+{
+
+ /* Should never be here. PR_DestroyThread is no
+ * longer used. */
+ PR_ASSERT(0);
+
+ /* PR_DestroyThread((PRThread *) thr); */
+}
+
+NSAPI_PUBLIC void systhread_sleep(int milliseconds)
+{
+ PR_Sleep(milliseconds);
+}
+
+NSAPI_PUBLIC void systhread_init(char *name)
+{
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
+#ifdef XP_UNIX
+ /* XXXrobm allocate all the fd's we can... */
+ PR_SetSysfdTableSize(PR_GetSysfdTableMax());
+#endif
+}
+
+
+NSAPI_PUBLIC int systhread_newkey()
+{
+ uintn newkey;
+
+ PR_NewThreadPrivateIndex(&newkey, NULL);
+ return (newkey);
+}
+
+NSAPI_PUBLIC void *systhread_getdata(int key)
+{
+ return PR_GetThreadPrivate(key);
+}
+
+NSAPI_PUBLIC void systhread_setdata(int key, void *data)
+{
+ PR_SetThreadPrivate(key, data);
+}
+
+/*
+ * Drag in the Java code, so our dynamic library full of it works
+ * i.e. force these symbols to load.
+ */
+NSAPI_PUBLIC void systhread_dummy(void)
+{
+
+#ifndef NSPR20
+ /* nspr/gc.c */
+ PR_InitGC(0,0);
+ /* nspr/prsystem.c */
+ PR_GetSystemInfo(PR_SI_SYSNAME, 0, 0);
+ /* nspr/linker.c */
+ PR_GetLibName(0, 0);
+ /* nspr/file.c */
+ PR_Mkdir(0, 0);
+ /* nspr/prnetdb.c */
+ PR_gethostbyname(0, 0, 0, 0, 0);
+ /* nspr/longlong.c */
+ LL_TO_S(LL_ZERO, 0, NULL, 0);
+#endif /* NSPR20 */
+}
+
+#elif defined(THREAD_WIN32)
+
+#include <nspr/prthread.h>
+#define DEFAULT_STACKSIZE 262144
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC
+SYS_THREAD systhread_start(int prio, int stksz, void (*fn)(void *), void *arg)
+{
+ sys_thread_s *ret = (sys_thread_s *) MALLOC(sizeof(sys_thread_s));
+
+ if ((ret->hand = (HANDLE)_beginthreadex(NULL, stksz, (unsigned (__stdcall *)(void *))fn,
+ arg, 0, &ret->id)) == 0) {
+ FREE(ret);
+ return NULL;
+ }
+ return (void *)ret;
+}
+
+NSPR_END_EXTERN_C
+
+NSAPI_PUBLIC SYS_THREAD systhread_current(void)
+{
+ /* XXXrobm this is busted.... */
+ return GetCurrentThread();
+}
+
+NSAPI_PUBLIC void systhread_timerset(int usec)
+{
+}
+
+NSAPI_PUBLIC SYS_THREAD systhread_attach(void)
+{
+ return NULL;
+}
+
+NSAPI_PUBLIC void systhread_yield(void)
+{
+ systhread_sleep(0);
+}
+
+NSAPI_PUBLIC void systhread_terminate(SYS_THREAD thr)
+{
+ TerminateThread(((sys_thread_s *)thr)->hand, 0);
+}
+
+
+NSAPI_PUBLIC void systhread_sleep(int milliseconds)
+{
+ /* XXXrobm there must be a better way to do this */
+ HANDLE sem = CreateSemaphore(NULL, 1, 4, "sleeper");
+ WaitForSingleObject(sem, INFINITE);
+ WaitForSingleObject(sem, milliseconds);
+ CloseHandle(sem);
+}
+
+NSAPI_PUBLIC void systhread_init(char *name)
+{
+ PR_Init(PR_USER_THREAD, 1, 0);
+}
+
+
+NSAPI_PUBLIC int systhread_newkey()
+{
+ return TlsAlloc();
+}
+
+NSAPI_PUBLIC void *systhread_getdata(int key)
+{
+ return (void *)TlsGetValue(key);
+}
+
+NSAPI_PUBLIC void systhread_setdata(int key, void *data)
+{
+ TlsSetValue(key, data);
+}
+
+#endif
+
diff --git a/lib/base/util.cpp b/lib/base/util.cpp
new file mode 100644
index 00000000..55d6ca56
--- /dev/null
+++ b/lib/base/util.cpp
@@ -0,0 +1,1449 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * util.c: A hodge podge of utility functions and standard functions which
+ * are unavailable on certain systems
+ *
+ * Rob McCool
+ */
+
+#ifdef XP_UNIX
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <stdlib.h>
+#include "prthread.h"
+#endif /* XP_UNIX */
+
+#include "base/util.h"
+
+#include "base/dbtbase.h"
+#include "base/ereport.h"
+
+
+#ifdef XP_UNIX
+#include <sys/types.h>
+#endif /* WIN32 */
+
+/* ----------------------------- util_getline ----------------------------- */
+
+#define LF 10
+#define CR 13
+
+NSAPI_PUBLIC int util_getline(filebuf_t *buf, int lineno, int maxlen, char *l) {
+ int i, x;
+
+ x = 0;
+ while(1) {
+ i = filebuf_getc(buf);
+ switch(i) {
+ case IO_EOF:
+ l[x] = '\0';
+ return 1;
+ case LF:
+ if(x && (l[x-1] == '\\')) {
+ --x;
+ continue;
+ }
+ l[x] = '\0';
+ return 0;
+ case IO_ERROR:
+ util_sprintf(l, "I/O error reading file at line %d", lineno);
+ return -1;
+ case CR:
+ continue;
+ default:
+ l[x] = (char) i;
+ if(++x == maxlen) {
+ util_sprintf(l, "line %d is too long", lineno);
+ return -1;
+ }
+ break;
+ }
+ }
+}
+
+
+/* ---------------------------- util_can_exec ----------------------------- */
+
+#ifdef XP_UNIX
+NSAPI_PUBLIC int util_can_exec(struct stat *fi, uid_t uid, gid_t gid)
+{
+ if(!uid)
+ return 1;
+ if((fi->st_mode & S_IXOTH) ||
+ ((gid == fi->st_gid) && (fi->st_mode & S_IXGRP)) ||
+ ((uid == fi->st_uid) && (fi->st_mode & S_IXUSR)))
+ return 1;
+ return 0;
+}
+#endif /* XP_UNIX */
+
+
+/* --------------------------- util_env_create ---------------------------- */
+
+
+NSAPI_PUBLIC char **util_env_create(char **env, int n, int *pos)
+{
+ int x;
+
+ if(!env) {
+ *pos = 0;
+ return (char **) MALLOC((n + 1)*sizeof(char *));
+ }
+ else {
+ for(x = 0; (env[x]); x++);
+ env = (char **) REALLOC(env, (n + x + 1)*(sizeof(char *)));
+ *pos = x;
+ return env;
+ }
+}
+
+
+/* ---------------------------- util_env_free ----------------------------- */
+
+
+NSAPI_PUBLIC void util_env_free(char **env)
+{
+ register char **ep = env;
+
+ for(ep = env; *ep; ep++)
+ FREE(*ep);
+ FREE(env);
+}
+
+/* ----------------------------- util_env_str ----------------------------- */
+
+
+NSAPI_PUBLIC char *util_env_str(char *name, char *value) {
+ char *t,*tp;
+
+ t = (char *) MALLOC(strlen(name)+strlen(value)+2); /* 2: '=' and '\0' */
+
+ for(tp=t; (*tp = *name); tp++,name++);
+ for(*tp++ = '='; (*tp = *value); tp++,value++);
+ return t;
+}
+
+
+/* --------------------------- util_env_replace --------------------------- */
+
+
+NSAPI_PUBLIC void util_env_replace(char **env, char *name, char *value)
+{
+ int x, y, z;
+ char *i;
+
+ for(x = 0; env[x]; x++) {
+ i = strchr(env[x], '=');
+ *i = '\0';
+ if(!strcmp(env[x], name)) {
+ y = strlen(env[x]);
+ z = strlen(value);
+
+ env[x] = (char *) REALLOC(env[x], y + z + 2);
+ util_sprintf(&env[x][y], "=%s", value);
+ return;
+ }
+ *i = '=';
+ }
+}
+
+
+/* ---------------------------- util_env_find ----------------------------- */
+
+
+NSAPI_PUBLIC char *util_env_find(char **env, char *name)
+{
+ char *i;
+ int x, r;
+
+ for(x = 0; env[x]; x++) {
+ i = strchr(env[x], '=');
+ *i = '\0';
+ r = !strcmp(env[x], name);
+ *i = '=';
+ if(r)
+ return i + 1;
+ }
+ return NULL;
+}
+
+
+/* ---------------------------- util_env_copy ----------------------------- */
+
+
+NSAPI_PUBLIC char **util_env_copy(char **src, char **dst)
+{
+ char **src_ptr;
+ int src_cnt;
+ int index;
+
+ if (!src)
+ return NULL;
+
+ for (src_cnt = 0, src_ptr = src; *src_ptr; src_ptr++, src_cnt++);
+
+ if (!src_cnt)
+ return NULL;
+
+ dst = util_env_create(dst, src_cnt, &index);
+
+ for (src_ptr = src, index=0; *src_ptr; index++, src_ptr++)
+ dst[index] = STRDUP(*src_ptr);
+ dst[index] = NULL;
+
+ return dst;
+}
+
+/* ---------------------------- util_hostname ----------------------------- */
+
+
+/*
+ * MOVED TO NET.C TO AVOID INTERDEPENDENCIES
+ */
+
+
+/* --------------------------- util_chdir2path ---------------------------- */
+
+
+NSAPI_PUBLIC int util_chdir2path(char *path)
+{
+ /* use FILE_PATHSEP to accomodate WIN32 */
+ char *t = strrchr(path, FILE_PATHSEP);
+ int ret;
+
+ if(!t)
+ return -1;
+
+ *t = '\0';
+#ifdef XP_UNIX
+ ret = chdir(path);
+#else /* WIN32 */
+ ret = SetCurrentDirectory(path);
+#endif /* XP_UNIX */
+
+ /* use FILE_PATHSEP instead of chdir to accomodate WIN32 */
+ *t = FILE_PATHSEP;
+
+ return ret;
+}
+
+
+/* --------------------------- util_is_mozilla ---------------------------- */
+
+
+NSAPI_PUBLIC int util_is_mozilla(char *ua, char *major, char *minor)
+{
+ if((!ua) || strncasecmp(ua, "Mozilla/", 8))
+ return 0;
+
+ /* Major version. I punted on supporting versions like 10.0 */
+ if(ua[8] > major[0])
+ return 1;
+ else if((ua[8] < major[0]) || (ua[9] != '.'))
+ return 0;
+
+ /* Minor version. Support version numbers like 0.96 */
+ if(ua[10] < minor[0])
+ return 0;
+ else if((ua[10] > minor[0]) || (!minor[1]))
+ return 1;
+
+ if((!isdigit(ua[11])) || (ua[11] < minor[1]))
+ return 0;
+ else
+ return 1;
+}
+
+
+/* ----------------------------- util_is_url ------------------------------ */
+
+
+#include <ctype.h> /* isalpha */
+
+NSAPI_PUBLIC int util_is_url(char *url)
+{
+ char *t = url;
+
+ while(*t) {
+ if(*t == ':')
+ return 1;
+ if(!isalpha(*t))
+ return 0;
+ ++t;
+ }
+ return 0;
+}
+
+
+/* --------------------------- util_later_than ---------------------------- */
+
+
+int _mstr2num(char *str) {
+ if(!strcasecmp(str, "Jan")) return 0;
+ if(!strcasecmp(str, "Feb")) return 1;
+ if(!strcasecmp(str, "Mar")) return 2;
+ if(!strcasecmp(str, "Apr")) return 3;
+ if(!strcasecmp(str, "May")) return 4;
+ if(!strcasecmp(str, "Jun")) return 5;
+ if(!strcasecmp(str, "Jul")) return 6;
+ if(!strcasecmp(str, "Aug")) return 7;
+ if(!strcasecmp(str, "Sep")) return 8;
+ if(!strcasecmp(str, "Oct")) return 9;
+ if(!strcasecmp(str, "Nov")) return 10;
+ if(!strcasecmp(str, "Dec")) return 11;
+ return -1;
+}
+
+int _time_compare(struct tm *lms, char *ims, int later_than_op)
+{
+ int y = 0, mnum = 0, d = 0, h = 0, m = 0, s = 0, x;
+ char t[128];
+
+ /* Supported formats start with weekday (which we don't care about) */
+ /* The sizeof(t) is to avoid buffer overflow with t */
+ if((!(ims = strchr(ims,' '))) || (strlen(ims) > (sizeof(t) - 2)))
+ return 0;
+
+ while(*ims && isspace(*ims)) ++ims;
+ if((!(*ims)) || (strlen(ims) < 2))
+ return 0;
+
+ /* Standard HTTP (RFC 850) starts with dd-mon-yy */
+ if(ims[2] == '-') {
+ sscanf(ims, "%s %d:%d:%d", t, &h, &m, &s);
+ if(strlen(t) < 6)
+ return 0;
+ t[2] = '\0';
+ t[6] = '\0';
+ d = atoi(t);
+ mnum = _mstr2num(&t[3]);
+ x = atoi(&t[7]);
+ /* Postpone wraparound until 2070 */
+ y = x + (x < 70 ? 2000 : 1900);
+ }
+ /* The ctime format starts with a month name */
+ else if(isalpha(*ims)) {
+ sscanf(ims,"%s %d %d:%d:%d %*s %d", t, &d, &h, &m, &s, &y);
+ mnum = _mstr2num(t);
+ }
+ /* RFC 822 */
+ else {
+ sscanf(ims, "%d %s %d %d:%d:%d", &d, t, &y, &h, &m, &s);
+ mnum = _mstr2num(t);
+ }
+
+ if (later_than_op) {
+ if( (x = (1900 + lms->tm_year) - y) )
+ return x < 0;
+
+ if(mnum == -1)
+ return 0;
+
+ /* XXXMB - this will fail if you check if december 31 1996 is later
+ * than january 1 1997
+ */
+ if((x = lms->tm_mon - mnum) || (x = lms->tm_mday - d) ||
+ (x = lms->tm_hour - h) || (x = lms->tm_min - m) ||
+ (x = lms->tm_sec - s))
+ return x < 0;
+
+ return 1;
+ }
+ else {
+ return (mnum != -1 &&
+ 1900 + lms->tm_year == y &&
+ lms->tm_mon == mnum &&
+ lms->tm_mday == d &&
+ lms->tm_hour == h &&
+ lms->tm_min == m &&
+ lms->tm_sec == s);
+ }
+}
+
+
+/* Returns 0 if lms later than ims
+ * Returns 1 if equal
+ * Returns 1 if ims later than lms
+ */
+NSAPI_PUBLIC int util_later_than(struct tm *lms, char *ims)
+{
+ return _time_compare(lms, ims, 1);
+}
+
+
+NSAPI_PUBLIC int util_time_equal(struct tm *lms, char *ims)
+{
+ return _time_compare(lms, ims, 0);
+}
+
+/* util_str_time_equal()
+ *
+ * Function to compare if two time strings are equal
+ *
+ * Acceptible date formats:
+ * Saturday, 17-Feb-96 19:41:34 GMT <RFC850>
+ * Sat, 17 Mar 1996 19:41:34 GMT <RFC1123>
+ *
+ * Argument t1 MUST be RFC1123 format.
+ *
+ * Note- it is not the intention of this routine to *always* match
+ * There are cases where we would return != when the strings might
+ * be equal (especially with case). The converse should not be true.
+ *
+ * Return 0 if equal, -1 if not equal.
+ */
+#define MINIMUM_LENGTH 18
+#define RFC1123_DAY 5
+#define RFC1123_MONTH 8
+#define RFC1123_YEAR 12
+#define RFC1123_HOUR 17
+#define RFC1123_MINUTE 20
+#define RFC1123_SECOND 23
+NSAPI_PUBLIC int util_str_time_equal(char *t1, char *t2)
+{
+ int index;
+
+ /* skip over leading whitespace... */
+ while(*t1 && isspace(*t1)) ++t1;
+ while(*t2 && isspace(*t2)) ++t2;
+
+ /* Check weekday */
+ if ( (t1[0] != t2[0]) || (t1[1] != t2[1]) )
+ return -1;
+
+ /* Skip to date */
+ while(*t2 && !isspace(*t2)) ++t2;
+ t2++;
+
+ /* skip if not strings not long enough */
+ if ( (strlen(t1) < MINIMUM_LENGTH) || (strlen(t2) < MINIMUM_LENGTH) )
+ return -1;
+
+ if ( (t1[RFC1123_DAY] != t2[0]) || (t1[RFC1123_DAY+1] != t2[1]) )
+ return -1;
+
+ /* Skip to the month */
+ t2 += 3;
+
+ if ( (t1[RFC1123_MONTH] != t2[0]) || (t1[RFC1123_MONTH+1] != t2[1]) ||
+ (t1[RFC1123_MONTH+2] != t2[2]) )
+ return -1;
+
+ /* Skip to year */
+ t2 += 4;
+
+ if ( (t1[RFC1123_YEAR] != t2[0]) ) {
+ /* Assume t2 is RFC 850 format */
+ if ( (t1[RFC1123_YEAR+2] != t2[0]) || (t1[RFC1123_YEAR+3] != t2[1]) )
+ return -1;
+
+ /* skip to hour */
+ t2 += 3;
+ } else {
+ /* Assume t2 is RFC 1123 format */
+ if ( (t1[RFC1123_YEAR+1] != t2[1]) || (t1[RFC1123_YEAR+2] != t2[2]) ||
+ (t1[RFC1123_YEAR+3] != t2[3]) )
+ return -1;
+
+ /* skip to hour */
+ t2 += 5;
+ }
+
+ /* check date */
+ for (index=0; index<8; index++) {
+ if ( t1[RFC1123_HOUR+index] != t2[index] )
+ return -1;
+ }
+
+ /* Ignore timezone */
+
+ return 0;
+}
+
+
+/* --------------------------- util_uri_is_evil --------------------------- */
+
+
+NSAPI_PUBLIC int util_uri_is_evil(char *t)
+{
+ register int x;
+
+ for(x = 0; t[x]; ++x) {
+ if(t[x] == '/') {
+ if(t[x+1] == '/')
+ return 1;
+ if(t[x+1] == '.') {
+ switch(t[x+2]) {
+ case '.':
+ if((!t[x+3]) || (t[x+3] == '/'))
+ return 1;
+ case '/':
+ case '\0':
+ return 1;
+ }
+ }
+ }
+#ifdef XP_WIN32
+ /* On NT, the directory "abc...." is the same as "abc"
+ * The only cheap way to catch this globally is to disallow
+ * names with the trailing "."s. Hopefully this is not over
+ * restrictive
+ */
+ if ((t[x] == '.') && ( (t[x+1] == '/') || (t[x+1] == '\0') )) {
+ return 1;
+ }
+#endif
+ }
+ return 0;
+}
+
+/* ---------------------------- util_uri_parse ---------------------------- */
+
+NSAPI_PUBLIC void util_uri_parse(char *uri)
+{
+ int spos = 0, tpos = 0;
+ int l = strlen(uri);
+
+ while(uri[spos]) {
+ if(uri[spos] == '/') {
+ if((spos != l) && (uri[spos+1] == '.')) {
+ if(uri[spos+2] == '/')
+ spos += 2;
+ else
+ if((spos <= (l-3)) &&
+ (uri[spos+2] == '.') && (uri[spos+3] == '/')) {
+ spos += 3;
+ while((tpos > 0) && (uri[--tpos] != '/'))
+ uri[tpos] = '\0';
+ } else
+ uri[tpos++] = uri[spos++];
+ } else {
+ if(uri[spos+1] != '/')
+ uri[tpos++] = uri[spos++];
+ else
+ spos++;
+ }
+ } else
+ uri[tpos++] = uri[spos++];
+ }
+ uri[tpos] = '\0';
+}
+
+
+/* -------------------- util_uri_unescape_and_normalize -------------------- */
+
+#ifdef XP_WIN32
+/* The server calls this function to unescape the URI and also normalize
+ * the uri. Normalizing the uri converts all "\" characters in the URI
+ * and pathinfo portion to "/". Does not touch "\" in query strings.
+ */
+void util_uri_unescape_and_normalize(char *s)
+{
+ char *t, *u;
+
+ for(t = s, u = s; *t; ++t, ++u) {
+ if((*t == '%') && t[1] && t[2]) {
+ *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) +
+ (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0'));
+ t += 2;
+ }
+ else
+ if(u != t)
+ *u = *t;
+ if (*u == '\\') /* normalize */
+ *u = '/';
+ }
+ *u = *t;
+}
+#endif /* XP_WIN32 */
+
+/* -------------------------- util_uri_unescape --------------------------- */
+
+NSAPI_PUBLIC void util_uri_unescape(char *s)
+{
+ char *t, *u;
+
+ for(t = s, u = s; *t; ++t, ++u) {
+ if((*t == '%') && t[1] && t[2]) {
+ *u = ((t[1] >= 'A' ? ((t[1] & 0xdf) - 'A')+10 : (t[1] - '0'))*16) +
+ (t[2] >= 'A' ? ((t[2] & 0xdf) - 'A')+10 : (t[2] - '0'));
+ t += 2;
+ }
+ else
+ if(u != t)
+ *u = *t;
+ }
+ *u = *t;
+}
+
+
+/* --------------------------- util_uri_escape ---------------------------- */
+
+
+NSAPI_PUBLIC char *util_uri_escape(char *od, char *s)
+{
+ char *d;
+
+ if(!od)
+ od = (char *) MALLOC((strlen(s)*3) + 1);
+ d = od;
+
+ while(*s) {
+ if(strchr("% ?#:+&*\"<>\r\n", *s)) {
+ sprintf(d, "%%%2x", *s);
+ ++s; d += 3;
+ }
+ else
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return od;
+}
+
+
+/* --------------------------- util_url_escape ---------------------------- */
+
+
+NSAPI_PUBLIC char *util_url_escape(char *od, char *s)
+{
+ char *d;
+
+ if(!od)
+ od = (char *) MALLOC((strlen(s)*3) + 1);
+ d = od;
+
+ while(*s) {
+ if(strchr("% +*\"<>\r\n", *s)) {
+ sprintf(d, "%%%.2x", *s);
+ ++s; d += 3;
+ }
+ else
+ *d++ = *s++;
+ }
+ *d = '\0';
+ return od;
+}
+
+
+/* ------------------------- util_mime_separator -------------------------- */
+
+
+NSAPI_PUBLIC int util_mime_separator(char *sep)
+{
+ srand(time(NULL));
+ return util_sprintf(sep, "%c%c--%d%d%d", CR, LF, rand(), rand(), rand());
+}
+
+
+/* ------------------------------ util_itoa ------------------------------- */
+
+
+/*
+ * Assumption: Reversing the digits will be faster in the general case
+ * than doing a log10 or some nasty trick to find the # of digits.
+ */
+
+NSAPI_PUBLIC int util_itoa(int i, char *a)
+{
+ register int x, y, p;
+ register char c;
+ int negative;
+
+ negative = 0;
+ if(i < 0) {
+ *a++ = '-';
+ negative = 1;
+ i = -i;
+ }
+ p = 0;
+ while(i > 9) {
+ a[p++] = (i%10) + '0';
+ i /= 10;
+ }
+ a[p++] = i + '0';
+
+ if(p > 1) {
+ for(x = 0, y = p - 1; x < y; ++x, --y) {
+ c = a[x];
+ a[x] = a[y];
+ a[y] = c;
+ }
+ }
+ a[p] = '\0';
+ return p + negative;
+}
+
+
+/* ----------------------------- util_sprintf ----------------------------- */
+
+
+#include "prprf.h"
+
+/*
+ XXXrobm the NSPR interfaces don't allow me to just pass in a buffer
+ without a size
+ */
+#define UTIL_PRF_MAXSIZE 1048576
+
+NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register const char *fmt,
+ va_list args)
+{
+ return PR_vsnprintf(s, n, fmt, args);
+}
+
+NSAPI_PUBLIC int util_snprintf(char *s, int n, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ return PR_vsnprintf(s, n, fmt, args);
+}
+
+NSAPI_PUBLIC int util_vsprintf(char *s, register const char *fmt, va_list args)
+{
+ return PR_vsnprintf(s, UTIL_PRF_MAXSIZE, fmt, args);
+}
+
+NSAPI_PUBLIC int util_sprintf(char *s, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ return PR_vsnprintf(s, UTIL_PRF_MAXSIZE, fmt, args);
+}
+
+/* ---------------------------- util_sh_escape ---------------------------- */
+
+
+NSAPI_PUBLIC char *util_sh_escape(char *s)
+{
+ char *ns = (char *) MALLOC(strlen(s) * 2 + 1); /* worst case */
+ register char *t, *u;
+
+ for(t = s, u = ns; *t; ++t, ++u) {
+ if(strchr("&;`'\"|*?~<>^()[]{}$\\ #!", *t))
+ *u++ = '\\';
+ *u = *t;
+ }
+ *u = '\0';
+ return ns;
+}
+
+/* --------------------------- util_strcasecmp ---------------------------- */
+
+
+#ifdef NEED_STRCASECMP
+/* These are stolen from mcom/lib/xp */
+NSAPI_PUBLIC
+int util_strcasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two)
+{
+ CASECMPARG_T char *pA;
+ CASECMPARG_T char *pB;
+
+ for(pA=one, pB=two; *pA && *pB; pA++, pB++)
+ {
+ int tmp = tolower(*pA) - tolower(*pB);
+ if (tmp)
+ return tmp;
+ }
+ if (*pA)
+ return 1;
+ if (*pB)
+ return -1;
+ return 0;
+}
+#endif /* NEED_STRCASECMP */
+
+#ifdef NEED_STRNCASECMP
+NSAPI_PUBLIC
+int util_strncasecmp(CASECMPARG_T char *one, CASECMPARG_T char *two, int n)
+{
+ CASECMPARG_T char *pA;
+ CASECMPARG_T char *pB;
+
+ for(pA=one, pB=two;; pA++, pB++)
+ {
+ int tmp;
+ if (pA == one+n)
+ return 0;
+ if (!(*pA && *pB))
+ return *pA - *pB;
+ tmp = tolower(*pA) - tolower(*pB);
+ if (tmp)
+ return tmp;
+ }
+}
+#endif /* NEED_STRNCASECMP */
+
+#ifdef XP_WIN32
+
+
+/* util_delete_directory()
+ * This routine deletes all the files in a directory. If delete_directory is
+ * TRUE it will also delete the directory itself.
+ */
+VOID
+util_delete_directory(char *FileName, BOOL delete_directory)
+{
+ HANDLE firstFile;
+ WIN32_FIND_DATA findData;
+ char *TmpFile, *NewFile;
+
+ if (FileName == NULL)
+ return;
+
+ TmpFile = (char *)MALLOC(strlen(FileName) + 5);
+ sprintf(TmpFile, "%s\\*.*", FileName);
+ firstFile = FindFirstFile(TmpFile, &findData);
+ FREE(TmpFile);
+
+ if (firstFile == INVALID_HANDLE_VALUE)
+ return;
+
+ if(strcmp(findData.cFileName, ".") &&
+ strcmp(findData.cFileName, "..")) {
+ NewFile = (char *)MALLOC(strlen(FileName) + 1 +
+ strlen(findData.cFileName) + 1);
+ sprintf(NewFile, "%s\\%s",FileName, findData.cFileName);
+ DeleteFile(NewFile);
+ FREE(NewFile);
+ }
+ while (TRUE) {
+ if(!(FindNextFile(firstFile, &findData))) {
+ if (GetLastError() != ERROR_NO_MORE_FILES) {
+ ereport(LOG_WARN, XP_GetAdminStr(DBT_couldNotRemoveTemporaryDirectory_), FileName, GetLastError());
+ } else {
+ FindClose(firstFile);
+ if (delete_directory)
+ if(!RemoveDirectory(FileName)) {
+ ereport(LOG_WARN,
+ XP_GetAdminStr(DBT_couldNotRemoveTemporaryDirectory_1),
+ FileName, GetLastError());
+ }
+ return;
+ }
+ } else {
+ if(strcmp(findData.cFileName, ".") &&
+ strcmp(findData.cFileName, "..")) {
+ NewFile = (char *)MALLOC(strlen(FileName) + 5 +
+ strlen(findData.cFileName) + 1);
+ sprintf(NewFile,"%s\\%s", FileName, findData.cFileName);
+ DeleteFile(NewFile);
+ FREE(NewFile);
+ }
+ }
+ }
+}
+#endif
+
+/* ------------------------------ util_strftime --------------------------- */
+/*
+ * Copyright (c) 1989 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)strftime.c 5.11 (Berkeley) 2/24/91";
+#endif /* LIBC_SCCS and not lint */
+
+#ifdef XP_UNIX
+#include <sys/types.h>
+#include <sys/time.h>
+#include <string.h>
+#include <stdio.h>
+#endif
+
+static char *afmt[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
+};
+static char *Afmt[] = {
+ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
+ "Saturday",
+};
+
+static char *bfmt[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep",
+ "Oct", "Nov", "Dec",
+};
+static char *Bfmt[] = {
+ "January", "February", "March", "April", "May", "June", "July",
+ "August", "September", "October", "November", "December",
+};
+
+#define TM_YEAR_BASE 1900
+
+static void _util_strftime_conv(char *, int, int, char);
+
+#define _util_strftime_add(str) for (;(*pt = *str++); pt++);
+#define _util_strftime_copy(str, len) memcpy(pt, str, len); pt += len;
+#define _util_strftime_fmt util_strftime
+
+/* util_strftime()
+ * This is an optimized version of strftime for speed. Avoids the thread
+ * unsafeness of BSD strftime calls.
+ */
+int
+util_strftime(char *pt, const char *format, const struct tm *t)
+{
+ char *start = pt;
+ char *scrap;
+
+ for (; *format; ++format) {
+ if (*format == '%')
+ switch(*++format) {
+ case 'a': /* abbreviated weekday name */
+ *pt++ = afmt[t->tm_wday][0];
+ *pt++ = afmt[t->tm_wday][1];
+ *pt++ = afmt[t->tm_wday][2];
+ continue;
+ case 'd': /* day of month */
+ _util_strftime_conv(pt, t->tm_mday, 2, '0');
+ pt += 2;
+ continue;
+ case 'S':
+ _util_strftime_conv(pt, t->tm_sec, 2, '0');
+ pt += 2;
+ continue;
+ case 'M':
+ _util_strftime_conv(pt, t->tm_min, 2, '0');
+ pt += 2;
+ continue;
+ case 'H':
+ _util_strftime_conv(pt, t->tm_hour, 2, '0');
+ pt += 2;
+ continue;
+ case 'Y':
+ if (t->tm_year < 100) {
+ *pt++ = '1';
+ *pt++ = '9';
+ _util_strftime_conv(pt, t->tm_year, 2, '0');
+ } else {
+ /* will fail after 2100; but who cares? */
+ *pt++ = '2';
+ *pt++ = '0';
+ _util_strftime_conv(pt, t->tm_year-100, 2, '0');
+ }
+ pt += 2;
+ continue;
+ case 'b': /* abbreviated month name */
+ case 'h':
+ *pt++ = bfmt[t->tm_mon][0];
+ *pt++ = bfmt[t->tm_mon][1];
+ *pt++ = bfmt[t->tm_mon][2];
+ continue;
+ case 'T':
+ case 'X':
+ pt += _util_strftime_fmt(pt, "%H:%M:%S", t);
+ continue;
+ case '\0':
+ --format;
+ break;
+ case 'A':
+ if (t->tm_wday < 0 || t->tm_wday > 6)
+ return(0);
+ scrap = Afmt[t->tm_wday];
+ _util_strftime_add(scrap);
+ continue;
+ case 'B':
+ if (t->tm_mon < 0 || t->tm_mon > 11)
+ return(0);
+ scrap = Bfmt[t->tm_mon];
+ _util_strftime_add(scrap);
+ continue;
+ case 'C':
+ pt += _util_strftime_fmt(pt, "%a %b %e %H:%M:%S %Y", t);
+ continue;
+ case 'c':
+ pt += _util_strftime_fmt(pt, "%m/%d/%y %H:%M:%S", t);
+ continue;
+ case 'D':
+ pt += _util_strftime_fmt(pt, "%m/%d/%y", t);
+ continue;
+ case 'e':
+ _util_strftime_conv(pt, t->tm_mday, 2, ' ');
+ pt += 2;
+ continue;
+ case 'I':
+ _util_strftime_conv(pt, t->tm_hour % 12 ?
+ t->tm_hour % 12 : 12, 2, '0');
+ pt += 2;
+ continue;
+ case 'j':
+ _util_strftime_conv(pt, t->tm_yday + 1, 3, '0');
+ pt += 3;
+ continue;
+ case 'k':
+ _util_strftime_conv(pt, t->tm_hour, 2, ' ');
+ pt += 2;
+ continue;
+ case 'l':
+ _util_strftime_conv(pt, t->tm_hour % 12 ?
+ t->tm_hour % 12 : 12, 2, ' ');
+ pt += 2;
+ continue;
+ case 'm':
+ _util_strftime_conv(pt, t->tm_mon + 1, 2, '0');
+ pt += 2;
+ continue;
+ case 'n':
+ *pt = '\n';
+ pt++;
+ continue;
+ case 'p':
+ if (t->tm_hour >= 12) {
+ *pt = 'P';
+ pt++;
+ } else {
+ *pt = 'A';
+ pt++;
+ }
+ *pt = 'M';
+ pt++;
+ continue;
+ case 'R':
+ pt += _util_strftime_fmt(pt, "%H:%M", t);
+ continue;
+ case 'r':
+ pt += _util_strftime_fmt(pt, "%I:%M:%S %p", t);
+ continue;
+ case 't':
+ *pt = '\t';
+ pt++;
+ continue;
+ case 'U':
+ _util_strftime_conv(pt, (t->tm_yday + 7 - t->tm_wday) / 7,
+ 2, '0');
+ pt += 2;
+ continue;
+ case 'W':
+ _util_strftime_conv(pt, (t->tm_yday + 7 -
+ (t->tm_wday ? (t->tm_wday - 1) : 6))
+ / 7, 2, '0');
+ pt += 2;
+ continue;
+ case 'w':
+ _util_strftime_conv(pt, t->tm_wday, 1, '0');
+ pt += 1;
+ continue;
+ case 'x':
+ pt += _util_strftime_fmt(pt, "%m/%d/%y", t);
+ continue;
+ case 'y':
+ _util_strftime_conv(pt, (t->tm_year + TM_YEAR_BASE)
+ % 100, 2, '0');
+ pt += 2;
+ continue;
+ case '%':
+ /*
+ * X311J/88-090 (4.12.3.5): if conversion char is
+ * undefined, behavior is undefined. Print out the
+ * character itself as printf(3) does.
+ */
+ default:
+ break;
+ }
+ *pt = *format;
+ pt++;
+ }
+
+ start[pt-start] = '\0';
+
+ return pt - start;
+}
+
+static void
+_util_strftime_conv(char *pt, int n, int digits, char pad)
+{
+ static char buf[10];
+ register char *p;
+
+ if (n >= 100) {
+ p = buf + sizeof(buf)-2;
+ for (; n > 0 && p > buf; n /= 10, --digits)
+ *p-- = n % 10 + '0';
+ while (p > buf && digits-- > 0)
+ *p-- = pad;
+ p++;
+ _util_strftime_add(p);
+ } else {
+ int tens;
+ int ones = n;
+
+ tens = 0;
+ if ( ones >= 10 ) {
+ while ( ones >= 10 ) {
+ tens++;
+ ones = ones - 10;
+ }
+ *pt++ = '0'+tens;
+ digits--;
+ }
+ else
+ *pt++ = '0';
+ *pt++ = '0'+ones;
+ digits--;
+ while(digits--)
+ *pt++ = pad;
+ }
+ return;
+}
+
+
+#ifdef XP_UNIX
+/*
+ * Local Thread Safe version of waitpid. This prevents the process
+ * from blocking in the system call.
+ */
+NSAPI_PUBLIC pid_t
+util_waitpid(pid_t pid, int *statptr, int options)
+{
+ pid_t rv;
+
+ for(rv = 0; !rv; PR_Sleep(500)) {
+ rv = waitpid(pid, statptr, options | WNOHANG);
+ if (rv == -1) {
+ if (errno == EINTR)
+ rv = 0; /* sleep and try again */
+ else
+ ereport(LOG_WARN, "waitpid failed for pid %d:%s", pid, system_errmsg());
+ }
+ }
+ return rv;
+}
+#endif
+
+/*
+ * Various reentrant routines by mikep. See util.h and systems.h
+ */
+
+/*
+ * These are only necessary if we turn on interrupts in NSPR
+ */
+#ifdef NEED_RELOCKS
+#include "crit.h"
+#define RE_LOCK(name) \
+ static CRITICAL name##_crit = 0; \
+ if (name##_crit == 0) name##_crit = crit_init(); \
+ crit_enter(name##_crit)
+
+#define RE_UNLOCK(name) crit_exit(name##_crit)
+
+#else
+#define RE_LOCK(name) /* nada */
+#define RE_UNLOCK(name) /* nil */
+#endif
+
+
+NSAPI_PUBLIC char *
+util_strtok(register char *s,
+ register const char *delim,
+ register char **lasts)
+{
+#ifdef HAVE_STRTOK_R
+ return strtok_r(s, delim, lasts);
+#else
+ /*
+ * THIS IS THE THREAD SAFE VERSION OF strtok captured from
+ * public NetBSD. Note that no locks are needed
+ */
+ register char *spanp;
+ register int c, sc;
+ char *tok;
+
+ if (s == NULL && (s = *lasts) == NULL)
+ return (NULL);
+
+ /*
+ * Skip (span) leading delimiters (s += strspn(s, delim),
+ * sort of).
+ */
+
+cont:
+ c = *s++;
+ for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+ if (c == sc)
+ goto cont;
+ }
+
+ if (c == 0) { /* no non-delimiter characters */
+ *lasts = NULL;
+ return (NULL);
+ }
+ tok = s - 1;
+
+ /*
+ * Scan token (scan for delimiters: s += strcspn(s, delim),
+ * sort of).
+ * Note that delim must have one NUL; we stop if we see that, too.
+ */
+ for (;;) {
+ c = *s++;
+ spanp = (char *)delim;
+ do {
+ if ((sc = *spanp++) == c) {
+ if (c == 0)
+ s = NULL;
+ else
+ s[-1] = 0;
+ *lasts = s;
+ return (tok);
+ }
+ } while (sc != 0);
+ }
+ /* NOTREACHED */
+#endif /* no strtok_r */
+}
+
+#ifndef XP_WIN32
+NSAPI_PUBLIC struct passwd *
+util_getpwnam(const char *name, struct passwd *result, char *buffer,
+ int buflen)
+{
+#ifdef HAVE_PW_R
+
+#ifdef AIX
+#if OSVERSION >= 4320
+ return ((int)getpwnam_r(name, result, buffer, buflen, 0) == 0 ? result : NULL);
+#else
+ return ((int)getpwnam_r(name, result, buffer, buflen) == 0 ? result : NULL);
+#endif
+#else
+ return getpwnam_r(name, result, buffer, buflen);
+#endif /* AIX */
+
+#else
+ char *lastp;
+ struct passwd *r;
+ RE_LOCK(pw);
+ r = getpwnam(name);
+ if (!r)
+ return r;
+
+ result->pw_gid = r->pw_gid;
+ result->pw_uid = r->pw_uid;
+ /* Hope this buffer is long enough */
+ if (buffer)
+ util_snprintf(buffer, buflen, "%s:%s:%d:%d:%s:%s:%s", r->pw_name, r->pw_passwd,
+ r->pw_uid, r->pw_gid, r->pw_gecos, r->pw_dir, r->pw_shell);
+ RE_UNLOCK(pw);
+
+ result->pw_name = util_strtok(buffer, ":", &lastp);
+ result->pw_passwd = util_strtok(NULL, ":", &lastp);
+ (void) util_strtok(NULL, ":", &lastp);
+ (void) util_strtok(NULL, ":", &lastp);
+ result->pw_gecos = util_strtok(NULL, ":", &lastp);
+ result->pw_dir = util_strtok(NULL, ":", &lastp);
+ result->pw_shell = util_strtok(NULL, ":", &lastp);
+ return result;
+#endif
+}
+#endif
+
+NSAPI_PUBLIC struct tm *
+util_localtime(const time_t *clock, struct tm *res)
+{
+#ifdef HAVE_TIME_R
+ return localtime_r(clock, res);
+#else
+ struct tm *rv;
+ time_t zero = 0x7fffffff;
+
+ RE_LOCK(localtime);
+ RE_UNLOCK(localtime);
+ rv = localtime(clock);
+ if (!rv)
+ rv = localtime(&zero);
+ if (rv)
+ *res = *rv;
+ else
+ return NULL;
+ return res;
+#endif
+}
+
+
+NSAPI_PUBLIC char *
+util_ctime(const time_t *clock, char *buf, int buflen)
+{
+/*
+ * From cgi-src/restore.c refering to XP_WIN32:
+ * MLM - gross, but it works, better now FLC
+ */
+#if !defined(HAVE_TIME_R) || defined(XP_WIN32)
+ RE_LOCK(ctime);
+ strncpy(buf, ctime(clock), buflen);
+ buf[buflen - 1] = '\0';
+ RE_UNLOCK(ctime);
+ return buf;
+#elif HAVE_TIME_R == 2
+ return ctime_r(clock, buf);
+#else /* HAVE_TIME_R == 3 */
+ return ctime_r(clock, buf, buflen);
+#endif
+}
+
+NSAPI_PUBLIC struct tm *
+util_gmtime(const time_t *clock, struct tm *res)
+{
+#ifdef HAVE_TIME_R
+ return gmtime_r(clock, res);
+#else
+ struct tm *rv;
+ time_t zero = 0x7fffffff;
+
+ RE_LOCK(gmtime);
+ rv = gmtime(clock);
+ RE_UNLOCK(gmtime);
+ if (!rv)
+ rv = gmtime(&zero);
+ if (rv)
+ *res = *rv;
+ else
+ return NULL;
+
+ return res;
+#endif
+}
+
+NSAPI_PUBLIC char *
+util_asctime(const struct tm *tm, char *buf, int buflen)
+{
+#if HAVE_TIME_R == 2
+ return asctime_r(tm, buf);
+#elif HAVE_TIME_R == 3
+ return asctime_r(tm, buf, buflen);
+#else
+ RE_LOCK(asctime);
+ strncpy(buf, asctime(tm), buflen);
+ buf[buflen - 1] = '\0';
+ RE_UNLOCK(asctime);
+ return buf;
+#endif
+}
+
+NSAPI_PUBLIC char *
+util_strerror(int errnum, char *msg, int buflen)
+{
+#ifdef HAVE_STRERROR_R
+ /* More IBM real-genius */
+ return ((int)strerror_r(errnum, msg, buflen) > 0) ? msg : NULL;
+#else
+ /* RE_LOCK(strerror); I don't think this is worth the trouble */
+ (void)strncpy(msg, strerror(errnum), buflen);
+ msg[buflen - 1] = '\0';
+ return msg;
+ /* RE_UNLOCK(strerror); */
+#endif
+}
+
+
+
+/* ------------------------------- OLD CODE ------------------------------- */
+
+
+#if 0
+
+NSAPI_PUBLIC int util_vsnprintf(char *s, int n, register char *fmt,
+ va_list args)
+{
+ register int pos = 0, max = (n > 2 ? n-2 : -1), boundson;
+ register char c, *t;
+
+ if((max == -1) && (n != -1))
+ goto punt;
+
+ boundson = (n != -1);
+ while(*fmt) {
+ if(boundson && (pos > max))
+ break;
+ c = *fmt++;
+ switch(c) {
+ case '%':
+ switch(*fmt++) {
+ case 'd':
+ if(boundson && ((pos + 10) > max))
+ goto punt;
+ pos += util_itoa(va_arg(args, int), &s[pos]);
+ break;
+ case 's':
+ t = va_arg(args, char *);
+ while(*t) {
+ s[pos++] = *t++;
+ if(boundson && (pos > max))
+ goto punt;
+ }
+ break;
+ case 'c':
+ s[pos++] = (char) va_arg(args, int);
+ break;
+ case '%':
+ s[pos++] = '%';
+ break;
+ }
+ break;
+ case '\\':
+ if( (s[pos++] = *fmt) )
+ ++fmt;
+ break;
+ default:
+ s[pos++] = c;
+ }
+ }
+ punt:
+ s[pos] = '\0';
+
+ va_end(args);
+ return pos;
+}
+
+NSAPI_PUBLIC int util_snprintf(char *s, int n, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ return util_vsnprintf(s, n, fmt, args);
+}
+
+NSAPI_PUBLIC int util_vsprintf(char *s, register char *fmt, va_list args)
+{
+ return util_vsnprintf(s, -1, fmt, args);
+}
+
+NSAPI_PUBLIC int util_sprintf(char *s, char *fmt, ...)
+{
+ va_list args;
+
+ va_start(args, fmt);
+ return util_vsnprintf(s, -1, fmt, args);
+}
+#endif
diff --git a/lib/ldaputil/Makefile b/lib/ldaputil/Makefile
new file mode 100644
index 00000000..c6c95400
--- /dev/null
+++ b/lib/ldaputil/Makefile
@@ -0,0 +1,65 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Makefile for libldapu.a (ldaputil library)
+#
+MCOM_ROOT=../../..
+MODULE=LibLdapUtil
+
+OBJDEST=$(OBJDIR)/lib/ldaputil
+
+include ../../nsconfig.mk
+
+ifeq ($(ARCH), WINNT)
+LIBS=$(OBJDIR)/lib/libldapu.lib
+MODULE_CFLAGS+= -DWINSOCK
+else
+LIBS=$(OBJDIR)/lib/libldapu.a
+endif
+
+LOCAL_DEPS = $(LDAPSDK_DEP)
+
+MCC_INCLUDE=-I$(NSROOT)/include \
+ -I$(MCOM_ROOT)/include \
+ $(DBM_INCLUDE) $(LDAPSDK_INCLUDE) \
+ $(SECURITY_INCLUDE) $(NSPR_INCLUDE)
+
+all: $(OBJDEST) $(LOCAL_DEPS) $(LIBS)
+
+$(OBJDEST):
+ mkdir -p $(OBJDEST)
+
+OSOBJS =
+
+OBJS=$(addprefix $(OBJDEST)/, \
+ ldapauth.o \
+ ldapdb.o \
+ dbconf.o \
+ certmap.o \
+ cert.o \
+ init.o \
+ encode.o \
+ errors.o \
+ vtable.o \
+ )
+
+MODULE_CFLAGS+= $(TESTFLAGS)
+MODULE_CFLAGS+= -DLDAPDB_THREAD_SAFE -I.
+
+ifeq ($(LDAP_NO_LIBLCACHE),1)
+MODULE_CFLAGS+=-DNO_LIBLCACHE
+endif
+
+
+$(LIBS): $(OBJS)
+ rm -f $@
+ $(AR) $(OBJS)
+ $(RANLIB) $@
+
+include $(INCLUDE_DEPENDS)
+
diff --git a/lib/ldaputil/cert.c b/lib/ldaputil/cert.c
new file mode 100644
index 00000000..34c41845
--- /dev/null
+++ b/lib/ldaputil/cert.c
@@ -0,0 +1,452 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <string.h>
+#include <malloc.h>
+
+/* removed for ns security integration
+#include <sec.h>
+*/
+#include "prmem.h"
+#include "key.h"
+#include "cert.h"
+#include <ldaputil/certmap.h>
+#include <ldaputil/errors.h>
+#include <ldaputil/cert.h>
+#include "ldaputili.h"
+
+NSAPI_PUBLIC int ldapu_get_cert (void *SSLendpoint, void **cert)
+{
+ /* TEMPORARY -- not implemented yet*/
+ return LDAPU_FAILED;
+}
+
+
+NSAPI_PUBLIC int ldapu_get_cert_subject_dn (void *cert_in, char **subjectDN)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ char *cert_subject = CERT_NameToAscii(&cert->subject);
+
+ if (cert_subject != NULL)
+ *subjectDN = strdup(cert_subject);
+ else
+ *subjectDN=NULL;
+
+ PR_Free(cert_subject);
+ return *subjectDN ? LDAPU_SUCCESS : LDAPU_ERR_EXTRACT_SUBJECTDN_FAILED;
+}
+
+NSAPI_PUBLIC int ldapu_get_cert_issuer_dn (void *cert_in, char **issuerDN)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ char *cert_issuer = CERT_NameToAscii(&cert->issuer);
+
+ *issuerDN = strdup(cert_issuer);
+ PR_Free(cert_issuer);
+
+ return *issuerDN ? LDAPU_SUCCESS : LDAPU_ERR_EXTRACT_ISSUERDN_FAILED;
+}
+
+NSAPI_PUBLIC int ldapu_get_cert_der (void *cert_in, unsigned char **der,
+ unsigned int *len)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ SECItem derCert = ((CERTCertificate*)cert)->derCert;
+ unsigned char *data = derCert.data;
+
+ *len = derCert.len;
+ *der = (unsigned char *)malloc(*len);
+
+ if (!*der) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ memcpy(*der, data, *len);
+
+ return *len ? LDAPU_SUCCESS : LDAPU_ERR_EXTRACT_DERCERT_FAILED;
+}
+
+static int certmap_name_to_secoid (const char *str)
+{
+ if (!ldapu_strcasecmp(str, "c")) return SEC_OID_AVA_COUNTRY_NAME;
+ if (!ldapu_strcasecmp(str, "o")) return SEC_OID_AVA_ORGANIZATION_NAME;
+ if (!ldapu_strcasecmp(str, "cn")) return SEC_OID_AVA_COMMON_NAME;
+ if (!ldapu_strcasecmp(str, "l")) return SEC_OID_AVA_LOCALITY;
+ if (!ldapu_strcasecmp(str, "st")) return SEC_OID_AVA_STATE_OR_PROVINCE;
+ if (!ldapu_strcasecmp(str, "ou")) return SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME;
+ if (!ldapu_strcasecmp(str, "uid")) return SEC_OID_RFC1274_UID;
+ if (!ldapu_strcasecmp(str, "e")) return SEC_OID_PKCS9_EMAIL_ADDRESS;
+ if (!ldapu_strcasecmp(str, "mail")) return SEC_OID_RFC1274_MAIL;
+ if (!ldapu_strcasecmp(str, "dc")) return SEC_OID_AVA_DC;
+
+ return SEC_OID_AVA_UNKNOWN; /* return invalid OID */
+}
+
+NSAPI_PUBLIC int ldapu_get_cert_ava_val (void *cert_in, int which_dn,
+ const char *attr, char ***val_out)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ CERTName *cert_dn;
+ CERTRDN **rdns;
+ CERTRDN **rdn;
+ CERTAVA **avas;
+ CERTAVA *ava;
+ int attr_tag = certmap_name_to_secoid(attr);
+ char **val;
+ char **ptr;
+ int rv;
+
+ *val_out = 0;
+
+ if (attr_tag == SEC_OID_AVA_UNKNOWN) {
+ return LDAPU_ERR_INVALID_ARGUMENT;
+ }
+
+ if (which_dn == LDAPU_SUBJECT_DN)
+ cert_dn = &cert->subject;
+ else if (which_dn == LDAPU_ISSUER_DN)
+ cert_dn = &cert->issuer;
+ else
+ return LDAPU_ERR_INVALID_ARGUMENT;
+
+ val = (char **)malloc(32*sizeof(char *));
+
+ if (!val) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ ptr = val;
+
+ rdns = cert_dn->rdns;
+
+ if (rdns) {
+ for (rdn = rdns; *rdn; rdn++) {
+ avas = (*rdn)->avas;
+ while ((ava = *avas++) != NULL) {
+ int tag = CERT_GetAVATag(ava);
+
+ if (tag == attr_tag) {
+ char buf[BIG_LINE];
+ int lenLen;
+ int vallen;
+ /* Found it */
+
+ /* Copied from ns/lib/libsec ...
+ * XXX this code is incorrect in general
+ * -- should use a DER template.
+ */
+ lenLen = 2;
+ if (ava->value.len >= 128) lenLen = 3;
+ vallen = ava->value.len - lenLen;
+
+ rv = CERT_RFC1485_EscapeAndQuote(buf,
+ BIG_LINE,
+ (char*) ava->value.data + lenLen,
+ vallen);
+
+ if (rv == SECSuccess) {
+ *ptr++ = strdup(buf);
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ *ptr = 0;
+
+ if (*val) {
+ /* At least one value found */
+ *val_out = val;
+ rv = LDAPU_SUCCESS;
+ }
+ else {
+ free(val);
+ rv = LDAPU_FAILED;
+ }
+
+ return rv;
+}
+
+static void
+_rdns_free (char*** rdns)
+{
+ auto char*** rdn;
+ for (rdn = rdns; *rdn; ++rdn) {
+ ldap_value_free (*rdn);
+ }
+ free (rdns);
+}
+
+static char***
+_explode_dn (const char* dn)
+{
+ auto char*** exp = NULL;
+ if (dn && *dn) {
+ auto char** rdns = ldap_explode_dn (dn, 0);
+ if (rdns) {
+ auto size_t expLen = 0;
+ auto char** rdn;
+ for (rdn = rdns; *rdn; ++rdn) {
+ auto char** avas = ldap_explode_rdn (*rdn, 0);
+ if (avas && *avas) {
+ exp = (char***) ldapu_realloc (exp, sizeof(char**) * (expLen + 2));
+ if (exp) {
+ exp[expLen++] = avas;
+ } else {
+ ldap_value_free (avas);
+ break;
+ }
+ } else { /* parse error */
+ if (avas) {
+ ldap_value_free (avas);
+ }
+ if (exp) {
+ exp[expLen] = NULL;
+ _rdns_free (exp);
+ exp = NULL;
+ }
+ break;
+ }
+ }
+ if (exp) {
+ exp[expLen] = NULL;
+ }
+ ldap_value_free (rdns);
+ }
+ }
+ return exp;
+}
+
+static size_t
+_rdns_count (char*** rdns)
+{
+ auto size_t count = 0;
+ auto char*** rdn;
+ for (rdn = rdns; *rdns; ++rdns) {
+ auto char** ava;
+ for (ava = *rdns; *ava; ++ava) {
+ ++count;
+ }
+ }
+ return count;
+}
+
+static int
+_replaceAVA (char* attr, char** avas)
+{
+ if (attr && avas) {
+ for (; *avas; ++avas) {
+ if (!ldapu_strcasecmp (*avas, attr)) {
+ *avas = attr;
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+struct _attr_getter_pair {
+ char* (*getter) (CERTName* dn);
+ const char* name1;
+ const char* name2;
+} _attr_getter_table[] =
+{
+ {NULL, "OU", "organizationalUnitName"},
+ {CERT_GetOrgName, "O", "organizationName"},
+ {CERT_GetCommonName, "CN", "commonName"},
+ {CERT_GetCertEmailAddress, "E", NULL},
+ {CERT_GetCertEmailAddress, "MAIL", "rfc822mailbox"},
+ {CERT_GetCertUid, "uid", NULL},
+ {CERT_GetCountryName, "C", "country"},
+ {CERT_GetStateName, "ST", "state"},
+ {CERT_GetLocalityName, "L", "localityName"},
+ {CERT_GetDomainComponentName, "DC", "dc"},
+ {NULL, NULL, NULL}
+};
+
+static int
+_is_OU (const char* attr)
+{
+ auto struct _attr_getter_pair* descAttr;
+ for (descAttr = _attr_getter_table; descAttr->name1; ++descAttr) {
+ if (descAttr->getter == NULL) { /* OU attribute */
+ if (!ldapu_strcasecmp (attr, descAttr->name1) || (descAttr->name2 &&
+ !ldapu_strcasecmp (attr, descAttr->name2))) {
+ return 1;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static char**
+_previous_OU (char** ava, char** avas)
+{
+ while (ava != avas) {
+ --ava;
+ if (_is_OU (*ava)) {
+ return ava;
+ }
+ }
+ return NULL;
+}
+
+static char*
+_value_normalize (char* value)
+ /* Remove leading and trailing spaces, and
+ change consecutive spaces to a single space.
+ */
+{
+ auto char* t;
+ auto char* f;
+ t = f = value;
+ while (*f == ' ') ++f; /* ignore leading spaces */
+ for (; *f; ++f) {
+ if (*f != ' ' || t[-1] != ' ') {
+ *t++ = *f; /* no consecutive spaces */
+ }
+ }
+ if (t > value && t[-1] == ' ') {
+ --t; /* ignore trailing space */
+ }
+ *t = '\0';
+ return value;
+}
+
+static int
+_explode_AVA (char* AVA)
+ /* Change an attributeTypeAndValue a la <draft-ietf-asid-ldapv3-dn>,
+ to the type name, followed immediately by the attribute value,
+ both normalized.
+ */
+{
+ auto char* value = strchr (AVA, '=');
+ if (!value) return LDAPU_FAILED;
+ *value++ = '\0';
+ _value_normalize (AVA);
+ _value_normalize (value);
+ {
+ auto char* typeEnd = AVA + strlen (AVA);
+ if ((typeEnd + 1) != value) {
+ memmove (typeEnd+1, value, strlen(value)+1);
+ }
+ }
+ return LDAPU_SUCCESS;
+}
+
+static char*
+_AVA_value (char* AVA)
+{
+ return (AVA + strlen (AVA) + 1);
+}
+
+static int
+_value_match (char* value, char* desc)
+{
+ auto const int result =
+ !ldapu_strcasecmp (_value_normalize(value), desc);
+ return result;
+}
+
+int
+ldapu_member_certificate_match (void* cert, const char* desc)
+/*
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS cert matches desc
+ * LDAPU_FAILED cert doesn't match desc
+ * <rv> Something went wrong.
+ */
+{
+ auto int err = LDAPU_FAILED;
+ auto char*** descRDNs;
+ if (!cert || !desc || desc[0] != '{') return LDAPU_FAILED;
+ if (desc[1] == '\0') return LDAPU_SUCCESS; /* no AVAs */
+ descRDNs = _explode_dn (desc+1);
+ if (descRDNs) {
+ auto char** descAVAs = (char**)ldapu_malloc(sizeof(char*) * (_rdns_count(descRDNs)+1));
+ if (!descAVAs) {
+ err = LDAPU_ERR_OUT_OF_MEMORY;
+ } else {
+ auto CERTName* subject = &(((CERTCertificate*)cert)->subject);
+ auto char** descAVA;
+
+ err = LDAPU_SUCCESS;
+ { /* extract all the AVAs, but not duplicate types, except OU */
+ auto size_t descAVAsLen = 0;
+ auto char*** descRDN;
+ descAVAs[0] = NULL;
+ for (descRDN = descRDNs; err == LDAPU_SUCCESS && *descRDN; ++descRDN) {
+ for (descAVA = *descRDN; err == LDAPU_SUCCESS && *descAVA; ++descAVA) {
+ err = _explode_AVA (*descAVA);
+ if (err == LDAPU_SUCCESS) {
+ if (_is_OU (*descAVA) ||
+ !_replaceAVA (*descAVA, descAVAs)) {
+ descAVAs[descAVAsLen++] = *descAVA;
+ descAVAs[descAVAsLen] = NULL;
+ }
+ }
+ }
+ }
+ }
+
+ /* match all the attributes except OU */
+ for (descAVA = descAVAs; err == LDAPU_SUCCESS && *descAVA; ++descAVA) {
+ auto struct _attr_getter_pair* descAttr;
+ err = LDAPU_FAILED; /* if no match */
+ for (descAttr = _attr_getter_table; descAttr->name1; ++descAttr) {
+ if (!ldapu_strcasecmp (*descAVA, descAttr->name1) || (descAttr->name2 &&
+ !ldapu_strcasecmp (*descAVA, descAttr->name2))) {
+ if (descAttr->getter == NULL) { /* OU attribute */
+ err = LDAPU_SUCCESS; /* for now */
+ } else {
+ auto char* certVal = (*(descAttr->getter))(subject);
+ if (certVal && _value_match (certVal, _AVA_value (*descAVA))) {
+ err = LDAPU_SUCCESS;
+ }
+ PR_Free (certVal);
+ }
+ break;
+ }
+ }
+ }
+
+ /* match the OU attributes */
+ if (err == LDAPU_SUCCESS && descAVA != descAVAs) {
+ /* Iterate over the OUs in the certificate subject */
+ auto CERTRDN** certRDN = subject->rdns;
+ descAVA = _previous_OU (descAVA, descAVAs);
+ for (; descAVA && *certRDN; ++certRDN) {
+ auto CERTAVA** certAVA = (*certRDN)->avas;
+ for (; descAVA && *certAVA; ++certAVA) {
+ auto const int tag = CERT_GetAVATag (*certAVA);
+ if (tag == SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME) {
+ auto const size_t certValLen =(*certAVA)->value.len;
+ auto const size_t lenLen = (certValLen < 128) ? 2 : 3;
+ auto const size_t buflen = certValLen - lenLen;
+ auto char* buf = (char*)ldapu_malloc(buflen+1);
+ if (!buf) {
+ err = LDAPU_ERR_OUT_OF_MEMORY;
+ descAVA = NULL;
+ } else {
+ memcpy (buf, (*certAVA)->value.data+lenLen, buflen);
+ buf[buflen] = 0;
+ if (_value_match (buf, _AVA_value (*descAVA))) {
+ descAVA = _previous_OU (descAVA, descAVAs);
+ }
+ free (buf);
+ }
+ }
+ }
+ }
+ if (descAVA) {
+ err = LDAPU_FAILED; /* no match for descAVA in subject */
+ }
+ }
+ free (descAVAs);
+ }
+ _rdns_free (descRDNs);
+ }
+ return err;
+}
+
diff --git a/lib/ldaputil/certmap.c b/lib/ldaputil/certmap.c
new file mode 100644
index 00000000..c2c718fc
--- /dev/null
+++ b/lib/ldaputil/certmap.c
@@ -0,0 +1,1950 @@
+/** 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 <string.h>
+#include <ctype.h>
+#include <malloc.h>
+
+/* removed for ns security integration
+#include <sec.h>
+*/
+#include <plstr.h>
+#include <prlink.h>
+#include <key.h>
+#include <cert.h>
+#include <ldaputil/certmap.h>
+#include <ldaputil/ldapauth.h>
+#include <ldaputil/errors.h>
+#include <ldaputil/ldaputil.h>
+#include "ldaputili.h"
+
+#ifndef BIG_LINE
+#define BIG_LINE 1024
+#endif
+
+/* This is hack, the function is defined in cert/alg1485.c */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+static char this_dllname[256];
+static const char *LIB_DIRECTIVE = "certmap";
+static const int LIB_DIRECTIVE_LEN = 7; /* strlen("LIB_DIRECTIVE") */
+
+static char *ldapu_dn_normalize( char *dn );
+
+typedef struct {
+ FILE *fp;
+ void *arg;
+} LDAPUPrintInfo_t;
+
+static LDAPUCertMapListInfo_t *certmap_listinfo = 0;
+static LDAPUCertMapInfo_t *default_certmap_info = 0;
+
+static const char *certmap_attrs [] = {
+ 0,
+ 0,
+ 0,
+ 0
+};
+
+const long CERTMAP_BIT_POS_UNKNOWN = 0; /* unknown OID */
+const long CERTMAP_BIT_POS_CN = 1L << 1; /* Common Name */
+const long CERTMAP_BIT_POS_OU = 1L << 2; /* Organization unit */
+const long CERTMAP_BIT_POS_O = 1L << 3; /* Organization */
+const long CERTMAP_BIT_POS_C = 1L << 4; /* Country */
+const long CERTMAP_BIT_POS_L = 1L << 5; /* Locality */
+const long CERTMAP_BIT_POS_ST = 1L << 6; /* State or Province */
+const long CERTMAP_BIT_POS_MAIL = 1L << 7; /* E-mail Address */
+const long CERTMAP_BIT_POS_UID = 1L << 8; /* UID */
+const long CERTMAP_BIT_POS_DC = 1L << 9; /* DC */
+
+const int SEC_OID_AVA_UNKNOWN = 0; /* unknown OID */
+
+static long certmap_secoid_to_bit_pos (int oid)
+{
+ switch(oid) {
+ case SEC_OID_AVA_COUNTRY_NAME: return CERTMAP_BIT_POS_C;
+ case SEC_OID_AVA_ORGANIZATION_NAME: return CERTMAP_BIT_POS_O;
+ case SEC_OID_AVA_COMMON_NAME: return CERTMAP_BIT_POS_CN;
+ case SEC_OID_AVA_LOCALITY: return CERTMAP_BIT_POS_L;
+ case SEC_OID_AVA_STATE_OR_PROVINCE: return CERTMAP_BIT_POS_ST;
+ case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: return CERTMAP_BIT_POS_OU;
+ case SEC_OID_RFC1274_UID: return CERTMAP_BIT_POS_UID;
+ /* Map "E" and "MAIL" to the same bit position */
+ case SEC_OID_PKCS9_EMAIL_ADDRESS: return CERTMAP_BIT_POS_MAIL;
+ case SEC_OID_RFC1274_MAIL: return CERTMAP_BIT_POS_MAIL;
+ case SEC_OID_AVA_DC: return CERTMAP_BIT_POS_DC;
+ default: return CERTMAP_BIT_POS_UNKNOWN;
+ }
+}
+
+static const char *certmap_secoid_to_name (int oid)
+{
+ switch(oid) {
+ case SEC_OID_AVA_COUNTRY_NAME: return "C";
+ case SEC_OID_AVA_ORGANIZATION_NAME: return "O";
+ case SEC_OID_AVA_COMMON_NAME: return "CN";
+ case SEC_OID_AVA_LOCALITY: return "L";
+ case SEC_OID_AVA_STATE_OR_PROVINCE: return "ST";
+ case SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME: return "OU";
+ case SEC_OID_RFC1274_UID: return "UID";
+ /* Map both 'e' and 'mail' to 'mail' in LDAP */
+ case SEC_OID_PKCS9_EMAIL_ADDRESS: return "MAIL";
+ case SEC_OID_RFC1274_MAIL: return "MAIL";
+ case SEC_OID_AVA_DC: return "DC";
+ default: return 0;
+ }
+}
+
+static void tolower_string (char *str)
+{
+ if (str) {
+ while (*str) {
+ *str = tolower(*str);
+ str++;
+ }
+ }
+}
+
+static long certmap_name_to_bit_pos (const char *str)
+{
+ if (!ldapu_strcasecmp(str, "c")) return CERTMAP_BIT_POS_C;
+ if (!ldapu_strcasecmp(str, "o")) return CERTMAP_BIT_POS_O;
+ if (!ldapu_strcasecmp(str, "cn")) return CERTMAP_BIT_POS_CN;
+ if (!ldapu_strcasecmp(str, "l")) return CERTMAP_BIT_POS_L;
+ if (!ldapu_strcasecmp(str, "st")) return CERTMAP_BIT_POS_ST;
+ if (!ldapu_strcasecmp(str, "ou")) return CERTMAP_BIT_POS_OU;
+ if (!ldapu_strcasecmp(str, "uid")) return CERTMAP_BIT_POS_UID;
+ /* Map "E" and "MAIL" to the same bit position */
+ if (!ldapu_strcasecmp(str, "e")) return CERTMAP_BIT_POS_MAIL;
+ if (!ldapu_strcasecmp(str, "mail")) return CERTMAP_BIT_POS_MAIL;
+ if (!ldapu_strcasecmp(str, "dc")) return CERTMAP_BIT_POS_DC;
+
+ return CERTMAP_BIT_POS_UNKNOWN;
+}
+
+static int certmap_name_to_secoid (const char *str)
+{
+ if (!ldapu_strcasecmp(str, "c")) return SEC_OID_AVA_COUNTRY_NAME;
+ if (!ldapu_strcasecmp(str, "o")) return SEC_OID_AVA_ORGANIZATION_NAME;
+ if (!ldapu_strcasecmp(str, "cn")) return SEC_OID_AVA_COMMON_NAME;
+ if (!ldapu_strcasecmp(str, "l")) return SEC_OID_AVA_LOCALITY;
+ if (!ldapu_strcasecmp(str, "st")) return SEC_OID_AVA_STATE_OR_PROVINCE;
+ if (!ldapu_strcasecmp(str, "ou")) return SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME;
+ if (!ldapu_strcasecmp(str, "uid")) return SEC_OID_RFC1274_UID;
+ if (!ldapu_strcasecmp(str, "e")) return SEC_OID_PKCS9_EMAIL_ADDRESS;
+ if (!ldapu_strcasecmp(str, "mail")) return SEC_OID_RFC1274_MAIL;
+ if (!ldapu_strcasecmp(str, "dc")) return SEC_OID_AVA_DC;
+
+ return SEC_OID_AVA_UNKNOWN; /* return invalid OID */
+}
+
+NSAPI_PUBLIC int ldapu_list_alloc (LDAPUList_t **list)
+{
+ *list = (LDAPUList_t *)malloc(sizeof(LDAPUList_t));
+
+ if (!*list) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ memset((void *)*list, 0, sizeof(LDAPUList_t));
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_list_add_node (LDAPUList_t *list, LDAPUListNode_t *node)
+{
+ if (list->head) {
+ node->prev = list->tail;
+ list->tail->next = node;
+ }
+ else {
+ node->prev = 0;
+ list->head = node;
+ }
+
+ node->next = 0;
+ list->tail = node;
+ return LDAPU_SUCCESS;
+}
+
+NSAPI_PUBLIC int ldapu_list_add_info (LDAPUList_t *list, void *info)
+{
+ LDAPUListNode_t *node;
+
+ /* Allocate the list node and set info in the node. */
+ node = (LDAPUListNode_t *)malloc(sizeof(LDAPUListNode_t));
+
+ if (!node) {
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ memset((void *)node, 0, sizeof(LDAPUListNode_t));
+ node->info = info;
+
+ return ldapu_list_add_node(list, node);
+}
+
+static int ldapu_list_remove_node (LDAPUList_t *list, LDAPUListNode_t *node)
+{
+ if (list->head == node) {
+ list->head = node->next;
+ if (list->tail == node) list->tail = 0; /* removed the only node */
+ }
+ else if (list->tail == node) {
+ list->tail = node->prev;
+ }
+ else {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+ }
+
+ node->next = 0;
+ node->prev = 0;
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_list_copy (const LDAPUList_t *from, LDAPUList_t **to,
+ LDAPUListNodeFn_t copy_fn)
+{
+ LDAPUListNode_t *node = from->head;
+ LDAPUListNode_t *newnode;
+ LDAPUList_t *list;
+ int rv;
+
+ *to = 0;
+ rv = ldapu_list_alloc(&list);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ while(node) {
+ newnode = (LDAPUListNode_t *)(*copy_fn)(node->info, 0);
+ if (!newnode) return LDAPU_ERR_OUT_OF_MEMORY;
+ rv = ldapu_list_add_info(list, newnode);
+ if (rv != LDAPU_SUCCESS) return rv;
+ node = node->next;
+ }
+
+ *to = list;
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_list_find_node (const LDAPUList_t *list,
+ LDAPUListNode_t **found,
+ LDAPUListNodeFn_t find_fn,
+ void *find_arg)
+{
+ LDAPUListNode_t *node = list->head;
+
+ while(node) {
+ if ((*find_fn)(node->info, find_arg) == LDAPU_SUCCESS) {
+ *found = node;
+ return LDAPU_SUCCESS;
+ }
+ node = node->next;
+ }
+
+ return LDAPU_ERR_CERTMAP_INFO_MISSING;
+}
+
+static int ldapu_list_print (LDAPUList_t *list, LDAPUListNodeFn_t print_fn,
+ LDAPUPrintInfo_t *pinfo)
+{
+ LDAPUListNode_t *node = list->head;
+ int rv;
+
+ while(node) {
+ rv = (int)(*print_fn)(node->info, pinfo);
+ if (rv != LDAPU_SUCCESS) return rv;
+ node = node->next;
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+
+static void ldapu_list_free (LDAPUList_t *list, LDAPUListNodeFn_t free_fn)
+{
+ if (list) {
+ auto LDAPUListNode_t *node = list->head;
+ while (node) {
+ auto LDAPUListNode_t *next = node->next;
+ if (free_fn) {
+ (*free_fn)(node->info, 0);
+ node->info = 0;
+ }
+ node->info = 0;
+ free(node);
+ node = next;
+ }
+ list->head = 0;
+ list->tail = 0;
+ }
+ return;
+}
+
+NSAPI_PUBLIC int ldapu_propval_alloc (const char *prop, const char *val,
+ LDAPUPropVal_t **propval)
+{
+ *propval = (LDAPUPropVal_t *)malloc(sizeof(LDAPUPropVal_t));
+
+ if (!*propval) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ (*propval)->prop = prop ? strdup(prop) : 0;
+ (*propval)->val = val ? strdup(val) : 0;
+
+ if ((!prop || (*propval)->prop) && (!val || (*propval)->val)) {
+ /* strdup worked */
+ return LDAPU_SUCCESS;
+ }
+ else {
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+}
+
+static void *ldapu_propval_copy (void *info, void *arg)
+{
+ LDAPUPropVal_t *propval = (LDAPUPropVal_t *)info;
+ LDAPUPropVal_t *copy = 0;
+ int rv;
+
+ rv = ldapu_propval_alloc(propval->prop, propval->val, &copy);
+
+ if (rv != LDAPU_SUCCESS) return 0;
+ return copy;
+}
+
+#define PRINT_STR(x) (x ? x : "<NULL>")
+
+static void * ldapu_propval_print (void *info, void *arg)
+{
+ LDAPUPropVal_t *propval = (LDAPUPropVal_t *)info;
+ LDAPUPrintInfo_t *pinfo = (LDAPUPrintInfo_t *)arg;
+
+ if (!pinfo || !pinfo->fp) {
+ fprintf(stderr, "\tprop = \"%s\", \tval = \"%s\"\n",
+ PRINT_STR(propval->prop),
+ PRINT_STR(propval->val));
+ }
+ else {
+ char *issuerName = (char *)pinfo->arg;
+
+ fprintf(pinfo->fp, "%s:%s %s\n", issuerName,
+ propval->prop ? propval->prop : "",
+ propval->val ? propval->val : "");
+ }
+
+ return 0;
+}
+
+static int PresentInComps (long comps_bitmask, int tag)
+{
+ long bit = certmap_secoid_to_bit_pos(tag);
+
+ if (comps_bitmask & bit)
+ return 1;
+ else
+ return 0;
+}
+
+static void print_oid_bitmask (long bitmask)
+{
+ fprintf(stderr, "%x: ", bitmask);
+
+ if (PresentInComps(bitmask, SEC_OID_AVA_COUNTRY_NAME))
+ fprintf(stderr, " C");
+ if (PresentInComps(bitmask, SEC_OID_AVA_ORGANIZATION_NAME))
+ fprintf(stderr, " O");
+ if (PresentInComps(bitmask, SEC_OID_AVA_COMMON_NAME))
+ fprintf(stderr, " CN");
+ if (PresentInComps(bitmask, SEC_OID_AVA_LOCALITY))
+ fprintf(stderr, " L");
+ if (PresentInComps(bitmask, SEC_OID_AVA_STATE_OR_PROVINCE))
+ fprintf(stderr, " ST");
+ if (PresentInComps(bitmask, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME))
+ fprintf(stderr, " OU");
+ if (PresentInComps(bitmask, SEC_OID_PKCS9_EMAIL_ADDRESS))
+ fprintf(stderr, " E");
+ if (PresentInComps(bitmask, SEC_OID_RFC1274_UID))
+ fprintf(stderr, " UID");
+ if (PresentInComps(bitmask, SEC_OID_RFC1274_MAIL))
+ fprintf(stderr, " MAIL");
+ if (PresentInComps(bitmask, SEC_OID_AVA_DC))
+ fprintf(stderr, " DC");
+ /* check for not yet known oid */
+ if (PresentInComps(bitmask, 34325))
+ fprintf(stderr, " UNKNOWN");
+
+ fprintf(stderr, "\n");
+}
+
+static void *ldapu_certinfo_print (void *info, void *arg)
+{
+ LDAPUCertMapInfo_t *certinfo = (LDAPUCertMapInfo_t*)info;
+ LDAPUPrintInfo_t *pinfo = (LDAPUPrintInfo_t *)arg;
+
+ if (!certinfo) return (void *)LDAPU_ERR_WRONG_ARGS;
+
+ if (!pinfo || !pinfo->fp) {
+ fprintf(stderr, "Printing cert mapinfo: \"%s\" ...\n",
+ PRINT_STR(certinfo->issuerName));
+ fprintf(stderr, "\tissuerDN = \"%s\"\n",
+ PRINT_STR(certinfo->issuerDN));
+ fprintf(stderr, "\tParsed dncomps: ");
+ print_oid_bitmask(certinfo->dncomps);
+ fprintf(stderr, "\tParsed filtercomps: ");
+ print_oid_bitmask(certinfo->filtercomps);
+
+ if (certinfo->propval) {
+ fprintf(stderr, "\tPrinting propval pairs: ...\n");
+ if (certinfo->propval)
+ ldapu_list_print(certinfo->propval, ldapu_propval_print, pinfo);
+ }
+ else {
+ fprintf(stderr, "\tNo propval pairs\n");
+ }
+ }
+ else {
+ LDAPUPrintInfo_t pinfo2;
+
+ pinfo2.fp = pinfo->fp;
+ pinfo2.arg = certinfo->issuerName;
+
+ /* Write certinfo to pinfo->fp */
+ fprintf(pinfo->fp, "%s %s %s\n", LIB_DIRECTIVE, certinfo->issuerName,
+ certinfo->issuerDN ? certinfo->issuerDN : "");
+ if (certinfo->propval)
+ ldapu_list_print(certinfo->propval, ldapu_propval_print, &pinfo2);
+ fprintf(pinfo->fp, "\n");
+ }
+
+ return (void *)LDAPU_SUCCESS;
+}
+
+static int dbconf_to_certmap_err (int err)
+{
+ switch(err) {
+ case LDAPU_ERR_DBNAME_IS_MISSING:
+ return LDAPU_ERR_CANAME_IS_MISSING;
+ case LDAPU_ERR_PROP_IS_MISSING:
+ return LDAPU_ERR_CAPROP_IS_MISSING;
+ default:
+ return err;
+ }
+}
+
+/* CAUTION: this function hijacks some substructures from db_info and make
+ * the pointers to it NULL in the db_info. It is safe to deallocate db_info.
+ */
+static int dbinfo_to_certinfo (DBConfDBInfo_t *db_info,
+ LDAPUCertMapInfo_t **certinfo_out)
+{
+ LDAPUCertMapInfo_t *certinfo;
+ int rv;
+
+ *certinfo_out = 0;
+
+ certinfo = (LDAPUCertMapInfo_t *)malloc(sizeof(LDAPUCertMapInfo_t));
+
+ if (!certinfo) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ memset((void *)certinfo, 0, sizeof(LDAPUCertMapInfo_t));
+
+ /* hijack few structures rather then copy. Make the pointers to the
+ structures NULL in the original structure so that they don't freed up
+ when db_info is freed. */
+ certinfo->issuerName = db_info->dbname;
+ db_info->dbname = 0;
+
+ certinfo->issuerDN = ldapu_dn_normalize(db_info->url);
+ db_info->url = 0;
+
+ /* hijack actual prop-vals from dbinfo -- to avoid strdup calls */
+ if (db_info->firstprop) {
+ LDAPUPropValList_t *propval_list;
+ LDAPUPropVal_t *propval;
+ DBPropVal_t *dbpropval;
+
+ dbpropval = db_info->firstprop;
+
+ rv = ldapu_list_alloc(&propval_list);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ while(dbpropval) {
+ propval = (LDAPUPropVal_t *)malloc(sizeof(LDAPUPropVal_t));
+
+ if (!propval) {
+ free(certinfo);
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ propval->prop = dbpropval->prop;
+ dbpropval->prop = 0;
+
+ propval->val = dbpropval->val;
+ dbpropval->val = 0;
+
+ rv = ldapu_list_add_info(propval_list, propval);
+
+ if (rv != LDAPU_SUCCESS) {
+ free(certinfo);
+ return rv;
+ }
+
+ dbpropval = dbpropval->next;
+ }
+
+ certinfo->propval = propval_list;
+ }
+
+ *certinfo_out = certinfo;
+
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_binary_cmp_certs (void *subject_cert,
+ void *entry_cert_binary,
+ unsigned long entry_cert_len)
+{
+ SECItem derCert = ((CERTCertificate*)subject_cert)->derCert;
+ int rv;
+
+ /* binary compare the two certs */
+ if (derCert.len == entry_cert_len &&
+ !memcmp(derCert.data, entry_cert_binary, entry_cert_len))
+ {
+ rv = LDAPU_SUCCESS;
+ }
+ else {
+ rv = LDAPU_ERR_CERT_VERIFY_FAILED;
+ }
+
+ return rv;
+}
+
+
+static int ldapu_cert_verifyfn_default (void *subject_cert, LDAP *ld,
+ void *certmap_info, LDAPMessage *res,
+ LDAPMessage **entry_out)
+{
+ LDAPMessage *entry;
+ struct berval **bvals;
+ int i;
+ int rv = LDAPU_ERR_CERT_VERIFY_FAILED;
+ char *cert_attr = ldapu_strings[LDAPU_STR_ATTR_CERT];
+ char *cert_attr_nosubtype = ldapu_strings[LDAPU_STR_ATTR_CERT_NOSUBTYPE];
+
+ *entry_out = 0;
+
+ for (entry = ldapu_first_entry(ld, res); entry != NULL;
+ entry = ldapu_next_entry(ld, entry))
+ {
+ if (((bvals = ldapu_get_values_len(ld, entry, cert_attr)) == NULL) &&
+ ((bvals = ldapu_get_values_len(ld, entry, cert_attr_nosubtype)) == NULL)) {
+ rv = LDAPU_ERR_CERT_VERIFY_NO_CERTS;
+ continue;
+ }
+
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ rv = ldapu_binary_cmp_certs (subject_cert,
+ bvals[i]->bv_val,
+ bvals[i]->bv_len);
+
+ if (rv == LDAPU_SUCCESS) {
+ break;
+ }
+ }
+
+ ldapu_value_free_len(ld, bvals);
+
+ if (rv == LDAPU_SUCCESS) {
+ *entry_out = entry;
+ break;
+ }
+ }
+
+ return rv;
+}
+
+static int parse_into_bitmask (const char *comps_in, long *bitmask_out,
+ long default_val)
+{
+ long bitmask;
+ char *comps = comps_in ? strdup(comps_in) : 0;
+
+ if (!comps) {
+ /* Not present in the config file */
+ bitmask = default_val;
+ }
+ else if (!*comps) {
+ /* present but empty */
+ bitmask = 0;
+ }
+ else {
+ char *ptr = comps;
+ char *name = comps;
+ long bit;
+ int break_loop = 0;
+
+ bitmask = 0;
+
+ while (*name) {
+ /* advance ptr to delimeter */
+ while(*ptr && !isspace(*ptr) && *ptr != ',') ptr++;
+
+ if (!*ptr)
+ break_loop = 1;
+ else
+ *ptr++ = 0;
+
+ bit = certmap_name_to_bit_pos(name);
+ bitmask |= bit;
+
+ if (break_loop) break;
+ /* skip delimeters */
+ while(*ptr && (isspace(*ptr) || *ptr == ',')) ptr++;
+ name = ptr;
+ }
+ }
+
+ if (comps) free(comps);
+ *bitmask_out = bitmask;
+/* print_oid_bitmask(bitmask); */
+ return LDAPU_SUCCESS;
+}
+
+static int process_certinfo (LDAPUCertMapInfo_t *certinfo)
+{
+ int rv = LDAPU_SUCCESS;
+ char *dncomps = 0;
+ char *filtercomps = 0;
+ char *libname = 0;
+ char *verify = 0;
+ char *fname = 0;
+ char *searchAttr = 0;
+
+ if (!ldapu_strcasecmp(certinfo->issuerName, "default")) {
+ default_certmap_info = certinfo;
+ }
+ else if (!certinfo->issuerDN) {
+ return LDAPU_ERR_NO_ISSUERDN_IN_CONFIG_FILE;
+ }
+ else {
+ rv = ldapu_list_add_info(certmap_listinfo, certinfo);
+ }
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for dncomps property and parse it into the dncomps bitmask */
+ rv = ldapu_certmap_info_attrval (certinfo, LDAPU_ATTR_DNCOMPS, &dncomps);
+
+ if (rv == LDAPU_SUCCESS && dncomps) {
+ certinfo->dncompsState = COMPS_HAS_ATTRS;
+ tolower_string(dncomps);
+ }
+ else if (rv == LDAPU_FAILED) {
+ certinfo->dncompsState = COMPS_COMMENTED_OUT;
+ rv = LDAPU_SUCCESS;
+ }
+ else if (rv == LDAPU_SUCCESS && !dncomps) {
+ certinfo->dncompsState = COMPS_EMPTY;
+ dncomps = ""; /* present but empty */
+ }
+
+ rv = parse_into_bitmask (dncomps, &certinfo->dncomps, -1);
+
+ if (dncomps && *dncomps) free(dncomps);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for filtercomps property and parse it into the filtercomps bitmask */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_FILTERCOMPS,
+ &filtercomps);
+
+ if (rv == LDAPU_SUCCESS && filtercomps) {
+ certinfo->filtercompsState = COMPS_HAS_ATTRS;
+ tolower_string(filtercomps);
+ }
+ else if (rv == LDAPU_FAILED) {
+ certinfo->filtercompsState = COMPS_COMMENTED_OUT;
+ rv = LDAPU_SUCCESS;
+ }
+ else if (rv == LDAPU_SUCCESS && !filtercomps) {
+ certinfo->filtercompsState = COMPS_EMPTY;
+ filtercomps = ""; /* present but empty */
+ }
+
+ rv = parse_into_bitmask (filtercomps, &certinfo->filtercomps, 0);
+
+ if (filtercomps && *filtercomps) free(filtercomps);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for "CmapLdapAttr" property and store it into searchAttr */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_CERTMAP_LDAP_ATTR,
+ &searchAttr);
+
+ if (rv == LDAPU_FAILED || !searchAttr || !*searchAttr)
+ rv = LDAPU_SUCCESS;
+ else {
+ certinfo->searchAttr = searchAttr ? strdup(searchAttr) : 0;
+
+ if (searchAttr && !certinfo->searchAttr)
+ rv = LDAPU_ERR_OUT_OF_MEMORY;
+ else
+ rv = LDAPU_SUCCESS;
+ }
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for verifycert property and set the default verify function */
+ /* The value of the verifycert property is ignored */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_VERIFYCERT, &verify);
+
+ if (rv == LDAPU_SUCCESS) {
+ if (!ldapu_strcasecmp(verify, "on"))
+ certinfo->verifyCert = 1;
+ else if (!ldapu_strcasecmp(verify, "off"))
+ certinfo->verifyCert = 0;
+ else if (!verify || !*verify) /* for mail/news backward compatibilty */
+ certinfo->verifyCert = 1; /* otherwise, this should be an error */
+ else
+ rv = LDAPU_ERR_MISSING_VERIFYCERT_VAL;
+ }
+ else if (rv == LDAPU_FAILED) rv = LDAPU_SUCCESS;
+
+ if (verify && *verify) free(verify);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ {
+ PRLibrary *lib = 0;
+
+ /* look for the library property and load it */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_LIBRARY, &libname);
+
+ if (rv == LDAPU_SUCCESS) {
+ if (libname && *libname) {
+ lib = PR_LoadLibrary(libname);
+ if (!lib) rv = LDAPU_ERR_UNABLE_TO_LOAD_PLUGIN;
+ }
+ else {
+ rv = LDAPU_ERR_MISSING_LIBNAME;
+ }
+ }
+ else if (rv == LDAPU_FAILED) rv = LDAPU_SUCCESS;
+
+ if (libname) free(libname);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* look for the InitFn property, find it in the libray and call it */
+ rv = ldapu_certmap_info_attrval(certinfo, LDAPU_ATTR_INITFN, &fname);
+
+ if (rv == LDAPU_SUCCESS) {
+ if (fname && *fname) {
+ /* If lib is NULL, PR_FindSymbol will search all libs loaded
+ * through PR_LoadLibrary.
+ */
+ CertMapInitFn_t fn = (CertMapInitFn_t)PR_FindSymbol(lib, fname);
+
+ if (!fn) {
+ rv = LDAPU_ERR_MISSING_INIT_FN_IN_LIB;
+ }
+ else {
+ rv = (*fn)(certinfo, certinfo->issuerName,
+ certinfo->issuerDN, this_dllname);
+ }
+ }
+ else {
+ rv = LDAPU_ERR_MISSING_INIT_FN_NAME;
+ }
+ }
+ else if (lib) {
+ /* If library is specified, init function must be specified */
+ /* If init fn is specified, library may not be specified */
+ rv = LDAPU_ERR_MISSING_INIT_FN_IN_CONFIG;
+ }
+ else if (rv == LDAPU_FAILED) rv = LDAPU_SUCCESS;
+
+ if (fname) free(fname);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+ }
+
+ return rv;
+}
+
+/* This function will read multiple certmap directives and set the information
+ * in the global certmap_listinfo structure.
+ */
+int certmap_read_certconfig_file (const char *file)
+{
+ DBConfInfo_t *conf_info = 0;
+ int rv;
+
+ /* Read the config file */
+ rv = dbconf_read_config_file_sub(file, LIB_DIRECTIVE, LIB_DIRECTIVE_LEN,
+ &conf_info);
+
+ /* Convert the conf_info into certmap_listinfo. Some of the
+ * sub-structures are simply hijacked rather than copied since we are
+ * going to (carefully) free the conf_info anyway.
+ */
+
+ if (rv == LDAPU_SUCCESS && conf_info) {
+ DBConfDBInfo_t *nextdb;
+ DBConfDBInfo_t *curdb;
+ LDAPUCertMapInfo_t *certinfo;
+
+ curdb = conf_info->firstdb;
+
+ while (curdb) {
+ nextdb = curdb->next;
+ rv = dbinfo_to_certinfo(curdb, &certinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ dbconf_free_confinfo(conf_info);
+ return rv;
+ }
+
+ rv = process_certinfo(certinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ dbconf_free_confinfo(conf_info);
+ return rv;
+ }
+
+ curdb = nextdb;
+ }
+
+ dbconf_free_confinfo(conf_info);
+ }
+ else {
+ rv = dbconf_to_certmap_err(rv);
+ }
+
+ return rv;
+}
+
+/* This function will read the "certmap default" directive from the config
+ * file and set the information in the global certmap_info.
+ */
+int certmap_read_default_certinfo (const char *file)
+{
+ DBConfDBInfo_t *db_info = 0;
+ int rv;
+
+ rv = dbconf_read_default_dbinfo_sub(file, LIB_DIRECTIVE, LIB_DIRECTIVE_LEN,
+ &db_info);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = dbinfo_to_certinfo(db_info, &default_certmap_info);
+
+ dbconf_free_dbinfo(db_info);
+ return rv;
+}
+
+static int ldapu_cert_searchfn_default (void *cert, LDAP *ld,
+ void *certmap_info_in,
+ const char *basedn, const char *dn,
+ const char *filter,
+ const char **attrs, LDAPMessage ***res)
+{
+ int rv = LDAPU_FAILED;
+ const char *ldapdn;
+ LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)certmap_info_in;
+ LDAPMessage * single_res = NULL;
+ LDAPMessage ** multiple_res = NULL;
+
+
+ if (certmap_info && certmap_info->searchAttr) {
+ char *subjectDN = 0;
+ char *certFilter = 0;
+ int len;
+
+ rv = ldapu_get_cert_subject_dn(cert, &subjectDN);
+
+ if (rv != LDAPU_SUCCESS || !subjectDN || !*subjectDN) return rv;
+ len = strlen(certmap_info->searchAttr) + strlen(subjectDN) +
+ strlen("=") + 1;
+ certFilter = (char *)malloc(len * sizeof(char));
+ if (!certFilter) return LDAPU_ERR_OUT_OF_MEMORY;
+ sprintf(certFilter, "%s=%s", certmap_info->searchAttr, subjectDN);
+ free(subjectDN);
+ if ( ldapu_strcasecmp(basedn, "") ) {
+ rv = ldapu_find(ld, basedn, LDAP_SCOPE_SUBTREE, certFilter, attrs, 0, &single_res);
+ ldapu_free((void *)certFilter);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = (LDAPMessage **) ldapu_malloc(2 * sizeof(LDAPMessage *));
+ (*res)[0] = single_res;
+ (*res)[1] = NULL;
+ return rv;
+ } else if (single_res) {
+ ldapu_msgfree(ld, single_res);
+ single_res = 0;
+ }
+ } else {
+ rv = ldapu_find_entire_tree(ld, LDAP_SCOPE_SUBTREE, certFilter, attrs, 0, &multiple_res);
+ ldapu_free((void *)certFilter);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = multiple_res;
+ return rv;
+ } else if (multiple_res) {
+ int n;
+ for ( n = 0; multiple_res[n] != NULL; n++)
+ ldapu_msgfree(ld, multiple_res[n]);
+ ldapu_memfree(ld, multiple_res);
+ }
+ }
+
+ }
+
+ if (dn && *dn) {
+ /* First do the base level search --- NOT ANY MORE!! */
+ /* We actually do the search on the whole subtree hanging from "ldapdn" since we want to
+ * find all the entries that match the filter.
+ * If we get more than one matching entry in return, it'll be at verify time that we'll
+ * choose the correct one among them all.
+ * However, if certificate verify is not active, certificate mapping will fail and will
+ * consequently display an error message (something done at 'handle_handshake_done' level,
+ * for instance). */
+ ldapdn = dn;
+
+ if ( ldapu_strcasecmp(ldapdn, "") ) {
+ rv = ldapu_find(ld, ldapdn, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &single_res);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = (LDAPMessage **) ldapu_malloc(2 * sizeof(LDAPMessage *));
+ (*res)[0] = single_res;
+ (*res)[1] = NULL;
+ return rv;
+ } else if (single_res) {
+ ldapu_msgfree(ld, single_res);
+ single_res = 0;
+ }
+ } else {
+ rv = ldapu_find_entire_tree(ld, LDAP_SCOPE_SUBTREE, filter, attrs, 0, &multiple_res);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = multiple_res;
+ return rv;
+ } else if (multiple_res) {
+ int n;
+ for ( n = 0; multiple_res[n] != NULL; n++)
+ ldapu_msgfree(ld, multiple_res[n]);
+ ldapu_memfree(ld, multiple_res);
+ }
+ }
+ } else {
+ /* default the dn and filter for subtree search */
+ ldapdn = basedn;
+ if (!filter || !*filter) {
+ if (certmap_info && certmap_info->searchAttr) {
+ /* dn & filter returned by the mapping function are both NULL
+ and 'searchAttr' based search has failed. Don't do brute
+ force search if 'searchAttr' is being used. Otherwise,
+ this search will result in all LDAP entries being
+ returned.
+ */
+ }
+ else {
+ filter = "objectclass=*";
+ }
+ }
+ }
+
+ /* For local LDAP DB, the LDAP_SCOPE_BASE search may fail for dn == basedn
+ * since that object doesn't actually exists.
+ */
+ if ((rv == LDAPU_FAILED || rv == LDAP_NO_SUCH_OBJECT) && filter && (!dn || !*dn)) {
+
+ /* Try the subtree search only if the filter is non-NULL */
+ if ( ldapu_strcasecmp(ldapdn, "") ) {
+ rv = ldapu_find(ld, ldapdn, LDAP_SCOPE_SUBTREE, filter, 0, 0, &single_res);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = (LDAPMessage **) ldapu_malloc(2 * sizeof(LDAPMessage *));
+ (*res)[0] = single_res;
+ (*res)[1] = NULL;
+ return rv;
+ } else if (single_res) {
+ ldapu_msgfree(ld, single_res);
+ single_res = 0;
+ }
+ } else {
+ rv = ldapu_find_entire_tree(ld, LDAP_SCOPE_SUBTREE, filter, 0, 0, &multiple_res);
+ if (rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ *res = multiple_res;
+ return rv;
+ } else if (multiple_res) {
+ int n;
+ for ( n = 0; multiple_res[n] != NULL; n++)
+ ldapu_msgfree(ld, multiple_res[n]);
+ ldapu_memfree(ld, multiple_res);
+ }
+ }
+ }
+
+ if (rv == LDAPU_FAILED) {
+ /* Not an error but couldn't map the cert */
+ rv = LDAPU_ERR_MAPPED_ENTRY_NOT_FOUND;
+ }
+ else if ((!dn || !*dn) && (rv == LDAP_NO_SUCH_OBJECT)) {
+ rv = LDAPU_ERR_INVALID_SUFFIX;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_issuer_certinfo (const char *issuerDN, void **certmap_info)
+{
+ *certmap_info = 0;
+
+ if (!issuerDN || !*issuerDN || !ldapu_strcasecmp(issuerDN, "default")) {
+ *certmap_info = default_certmap_info;
+ }
+ else if (certmap_listinfo) {
+ char *n_issuerDN = ldapu_dn_normalize (ldapu_strdup(issuerDN));
+ LDAPUListNode_t *cur = certmap_listinfo->head;
+ int rv = LDAPU_FAILED;
+ while(cur) {
+ if (!ldapu_strcasecmp(n_issuerDN, ((LDAPUCertMapInfo_t *)cur->info)->issuerDN))
+ {
+ *certmap_info = cur->info;
+ rv = LDAPU_SUCCESS;
+ break;
+ }
+ cur = cur->next;
+ }
+ if (n_issuerDN) ldapu_free (n_issuerDN);
+ }
+ return *certmap_info ? LDAPU_SUCCESS : LDAPU_FAILED;
+}
+
+NSAPI_PUBLIC int ldapu_certmap_info_attrval (void *certmap_info_in,
+ const char *attr, char **val)
+{
+ /* Look for given attr in the certmap_info and return its value */
+ LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)certmap_info_in;
+ LDAPUListNode_t *curprop = certmap_info->propval ? certmap_info->propval->head : 0;
+ LDAPUPropVal_t *propval;
+ int rv = LDAPU_FAILED;
+
+ *val = 0;
+ while(curprop) {
+ propval = (LDAPUPropVal_t *)curprop->info;
+ if (!ldapu_strcasecmp(propval->prop, attr)) {
+ *val = propval->val ? strdup(propval->val) : 0;
+ rv = LDAPU_SUCCESS;
+ break;
+ }
+ curprop = curprop->next;
+ }
+
+ return rv;
+}
+
+static int AddAVAToBuf (char *buf, int size, int *len,
+ const char *tagName, CERTAVA *ava)
+{
+ int lenLen;
+ int taglen;
+ SECStatus rv;
+
+ buf += *len;
+
+ /* Copied from ns/lib/libsec ...
+ * XXX this code is incorrect in general
+ * -- should use a DER template.
+ */
+ lenLen = 2;
+ if (ava->value.len >= 128) lenLen = 3;
+
+ taglen = PL_strlen(tagName);
+ memcpy(buf, tagName, taglen);
+ buf[taglen++] = '=';
+
+ rv = CERT_RFC1485_EscapeAndQuote(buf+taglen,
+ size-taglen,
+ (char*) ava->value.data + lenLen,
+ ava->value.len - lenLen);
+
+ *len += strlen(buf);
+
+ return (rv == SECSuccess ? LDAPU_SUCCESS : LDAPU_FAILED);
+}
+
+static int AddToLdapDN (char *ldapdn, int size, int *dnlen,
+ const char *tagName, CERTAVA *ava)
+{
+ char *dn = ldapdn + *dnlen;
+
+ if (*dnlen) { strcat(dn, ", "); dn += 2; *dnlen += 2; }
+ return AddAVAToBuf(ldapdn, size, dnlen, tagName, ava);
+}
+
+static int AddToFilter (char *filter, int size, int *flen,
+ const char *tagName, CERTAVA *ava)
+{
+ int rv;
+
+ /* Append opening parenthesis */
+ strcat(filter + *flen, " (");
+ *flen += 2;
+ rv = AddAVAToBuf(filter, size, flen, tagName, ava);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* Append closing parenthesis */
+ strcat(filter + *flen, ")");
+ (*flen)++;
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_free_cert_ava_val (char **val)
+{
+ char **ptr = val;
+
+ if (!val) return LDAPU_SUCCESS;
+
+ while(*ptr) free(*ptr++);
+ free(val);
+
+ return LDAPU_SUCCESS;
+}
+
+static int ldapu_cert_mapfn_default (void *cert_in, LDAP *ld,
+ void *certmap_info_in,
+ char **ldapDN_out, char **filter_out)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ LDAPUCertMapInfo_t *certmap_info= (LDAPUCertMapInfo_t *)certmap_info_in;
+ int rv = LDAPU_SUCCESS;
+
+ *ldapDN_out = *filter_out = 0;
+
+ if (!certmap_info) {
+ /* Use subject DN as is -- identity mapping function */
+ rv = ldapu_get_cert_subject_dn(cert, ldapDN_out);
+
+ return rv;
+ }
+ else {
+ /*
+ * Iterate over rdns from the subject and collect AVAs depending on
+ * dnComps and filtercomps to form ldapDN and filter respectively.
+ * certmap_info->dncomps
+ */
+ CERTName *subject = &cert->subject;
+ CERTRDN **rdns = subject->rdns;
+ CERTRDN **lastRdn;
+ CERTRDN **rdn;
+ CERTAVA **avas;
+ CERTAVA *ava;
+ char ldapdn[BIG_LINE];
+ char filter[BIG_LINE];
+ int dnlen = 0; /* ldap DN length */
+ int flen = 0; /* filter length */
+ int numfavas = 0; /* no of avas added to filter */
+
+ if (rdns == NULL) {
+ /* error */
+ }
+
+ /* find last RDN */
+ lastRdn = rdns;
+ while (*lastRdn) lastRdn++;
+ lastRdn--;
+
+ /* Initialize filter to "(&" */
+ strcpy(filter, "(&");
+ flen = 2;
+
+ /*
+ * Loop over subject rdns in the _reverse_ order while forming ldapDN
+ * and filter.
+ */
+ for (rdn = lastRdn; rdn >= rdns; rdn--) {
+ avas = (*rdn)->avas;
+ while ((ava = *avas++) != NULL) {
+ int tag = CERT_GetAVATag(ava);
+ const char *tagName = certmap_secoid_to_name(tag);
+
+ if (PresentInComps(certmap_info->dncomps, tag)) {
+ rv = AddToLdapDN(ldapdn, BIG_LINE, &dnlen, tagName, ava);
+ if (rv != LDAPU_SUCCESS) return rv;
+ }
+
+ if (PresentInComps(certmap_info->filtercomps, tag)) {
+ rv = AddToFilter(filter, BIG_LINE, &flen, tagName, ava);
+ if (rv != LDAPU_SUCCESS) return rv;
+ numfavas++;
+ }
+ }
+ }
+
+ if (numfavas == 0) {
+ /* nothing added to filter */
+ *filter = 0;
+ }
+ else if (numfavas == 1) {
+ /* one ava added to filter -- remove "(& (" from the front and ")"
+ * from the end.
+ */
+ *filter_out = strdup(filter+4);
+ if (!*filter_out) return LDAPU_ERR_OUT_OF_MEMORY;
+ (*filter_out)[strlen(*filter_out)-1] = 0;
+ }
+ else {
+ /* Add the closing parenthesis to filter */
+ strcat(filter+flen, ")");
+ *filter_out = strdup(filter);
+ }
+
+ if (dnlen >= BIG_LINE) return LDAPU_FAILED;
+ ldapdn[dnlen] = 0;
+ *ldapDN_out = *ldapdn ? strdup(ldapdn) : 0;
+
+ if ((numfavas && !*filter_out) || (dnlen && !*ldapDN_out)) {
+ /* strdup failed */
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ if ((certmap_info->dncompsState == COMPS_HAS_ATTRS && dnlen == 0) ||
+ (certmap_info->filtercompsState == COMPS_HAS_ATTRS &&
+ numfavas == 0))
+ {
+ /* At least one attr in DNComps should be present in the cert */
+ /* Same is true for FilterComps */
+ rv = LDAPU_ERR_MAPPED_ENTRY_NOT_FOUND;
+ }
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_set_cert_mapfn (const char *issuerDN,
+ CertMapFn_t mapfn)
+{
+ LDAPUCertMapInfo_t *certmap_info;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+
+ /* Don't set the mapping function if certmap_info doesen't exist */
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ certmap_info->mapfn = mapfn;
+ return LDAPU_SUCCESS;
+}
+
+static CertMapFn_t ldapu_get_cert_mapfn_sub (LDAPUCertMapInfo_t *certmap_info)
+{
+ CertMapFn_t mapfn;
+
+ if (certmap_info && certmap_info->mapfn)
+ mapfn = certmap_info->mapfn;
+ else if (default_certmap_info && default_certmap_info->mapfn)
+ mapfn = default_certmap_info->mapfn;
+ else
+ mapfn = ldapu_cert_mapfn_default;
+
+ return mapfn;
+}
+
+NSAPI_PUBLIC CertMapFn_t ldapu_get_cert_mapfn (const char *issuerDN)
+{
+ LDAPUCertMapInfo_t *certmap_info = 0;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+ /* certmap_info may be NULL -- use the default */
+
+ return ldapu_get_cert_mapfn_sub(certmap_info);
+}
+
+NSAPI_PUBLIC int ldapu_set_cert_searchfn (const char *issuerDN,
+ CertSearchFn_t searchfn)
+{
+ LDAPUCertMapInfo_t *certmap_info;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+
+ /* Don't set the mapping function if certmap_info doesen't exist */
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ certmap_info->searchfn = searchfn;
+ return LDAPU_SUCCESS;
+}
+
+static CertSearchFn_t ldapu_get_cert_searchfn_sub (LDAPUCertMapInfo_t *certmap_info)
+{
+ CertSearchFn_t searchfn;
+
+ if (certmap_info && certmap_info->searchfn)
+ searchfn = certmap_info->searchfn;
+ else if (default_certmap_info && default_certmap_info->searchfn)
+ searchfn = default_certmap_info->searchfn;
+ else
+ searchfn = ldapu_cert_searchfn_default;
+
+ return searchfn;
+}
+
+NSAPI_PUBLIC CertSearchFn_t ldapu_get_cert_searchfn (const char *issuerDN)
+{
+ LDAPUCertMapInfo_t *certmap_info = 0;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+ /* certmap_info may be NULL -- use the default */
+
+ return ldapu_get_cert_searchfn_sub(certmap_info);
+}
+
+NSAPI_PUBLIC int ldapu_set_cert_verifyfn (const char *issuerDN,
+ CertVerifyFn_t verifyfn)
+{
+ LDAPUCertMapInfo_t *certmap_info;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+
+ /* Don't set the verify function if certmap_info doesen't exist */
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ certmap_info->verifyfn = verifyfn;
+ return LDAPU_SUCCESS;
+}
+
+static CertVerifyFn_t ldapu_get_cert_verifyfn_sub (LDAPUCertMapInfo_t *certmap_info)
+{
+ CertVerifyFn_t verifyfn;
+
+ if (certmap_info && certmap_info->verifyfn)
+ verifyfn = certmap_info->verifyfn;
+ else if (default_certmap_info && default_certmap_info->verifyfn)
+ verifyfn = default_certmap_info->verifyfn;
+ else
+ verifyfn = ldapu_cert_verifyfn_default;
+
+ return verifyfn;
+}
+
+NSAPI_PUBLIC CertVerifyFn_t ldapu_get_cert_verifyfn (const char *issuerDN)
+{
+ LDAPUCertMapInfo_t *certmap_info = 0;
+ int rv;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+ /* certmap_info may be NULL -- use the default */
+
+ return ldapu_get_cert_verifyfn_sub(certmap_info);
+}
+
+static int ldapu_certinfo_copy (const LDAPUCertMapInfo_t *from,
+ const char *newIssuerName,
+ const char *newIssuerDN,
+ LDAPUCertMapInfo_t *to)
+{
+ /* This function is not tested and is not used */
+ int rv;
+
+ to->issuerName = newIssuerName ? strdup(newIssuerName) : 0;
+ to->issuerDN = newIssuerDN ? strdup(newIssuerDN) : 0;
+ if (from->propval) {
+ rv = ldapu_list_copy(from->propval, &to->propval, ldapu_propval_copy);
+ if (rv != LDAPU_SUCCESS) return rv;
+ }
+ else {
+ to->propval = 0;
+ }
+
+ return process_certinfo(to);
+}
+
+NSAPI_PUBLIC int ldapu_cert_to_ldap_entry (void *cert, LDAP *ld,
+ const char *basedn,
+ LDAPMessage **res)
+{
+ char *issuerDN = 0;
+ char *ldapDN = 0;
+ char *filter = 0;
+ LDAPUCertMapInfo_t *certmap_info;
+ LDAPMessage **res_array = NULL;
+ CertMapFn_t mapfn;
+ CertVerifyFn_t verifyfn;
+ CertSearchFn_t searchfn;
+ void *entry_cert = 0;
+ int rv,i,j;
+
+ *res = 0;
+
+ if (!certmap_attrs[0]) {
+ /* Initialize certmap_attrs */
+ certmap_attrs[0] = ldapu_strings[LDAPU_STR_ATTR_USER];
+ certmap_attrs[1] = ldapu_strings[LDAPU_STR_ATTR_CERT];
+ certmap_attrs[2] = ldapu_strings[LDAPU_STR_ATTR_CERT_NOSUBTYPE];
+ certmap_attrs[3] = 0;
+ }
+
+ rv = ldapu_get_cert_issuer_dn(cert, &issuerDN);
+
+ if (rv != LDAPU_SUCCESS) return LDAPU_ERR_NO_ISSUERDN_IN_CERT;
+
+ /* don't free the certmap_info -- its a pointer to an internal structure */
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certmap_info);
+ free(issuerDN);
+
+ if (!certmap_info) certmap_info = default_certmap_info;
+
+ /* Get the mapping function from the certmap_info */
+ mapfn = ldapu_get_cert_mapfn_sub(certmap_info);
+
+ rv = (*mapfn)(cert, ld, certmap_info, &ldapDN, &filter);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* Get the search function from the certmap_info - certinfo maybe NULL */
+ searchfn = ldapu_get_cert_searchfn_sub(certmap_info);
+
+ rv = (*searchfn)(cert, ld, certmap_info, basedn, ldapDN, filter,
+ certmap_attrs, &res_array);
+
+ if (ldapDN) free(ldapDN);
+ if (filter) free(filter);
+
+ /*
+ * Get the verify cert function & call it.
+ */
+ j = 0;
+ if ((rv == LDAPU_SUCCESS || rv == LDAPU_ERR_MULTIPLE_MATCHES) &&
+ (certmap_info ? certmap_info->verifyCert : 0))
+ {
+ verifyfn = ldapu_get_cert_verifyfn_sub(certmap_info);
+
+ if (verifyfn) {
+ int verify_rv;
+
+ i = 0;
+ do {
+ LDAPMessage *entry;
+ verify_rv = (*verifyfn)(cert, ld, certmap_info, res_array[i], &entry);
+
+ if (rv == LDAPU_ERR_MULTIPLE_MATCHES) {
+ if (verify_rv == LDAPU_SUCCESS) {
+ /* 'entry' points to the matched entry */
+ /* Get the 'res' which only contains this entry */
+ char *dn = ldapu_get_dn(ld, entry);
+ if (*res) ldapu_msgfree(ld, *res);
+ rv = ldapu_find(ld, dn, LDAP_SCOPE_BASE, 0, certmap_attrs, 0, res);
+ ldapu_memfree(ld, dn);
+ }
+ else {
+ /* Verify failed for multiple matches -- keep rv */
+ /* multiple matches err is probably more interesting to
+ the caller then any other error returned by the verify
+ fn */
+ }
+ }
+ else /* rv == LDAPU_SUCCESS */ {
+ if (verify_rv == LDAPU_SUCCESS) {
+ *res = res_array[0];
+ j = 1;
+ } else {
+ rv = verify_rv;
+ }
+ }
+ } while ( (verify_rv != LDAPU_SUCCESS) && (res_array[++i] != NULL) );
+ }
+ } else {
+ if (rv == LDAPU_SUCCESS) {
+ *res = res_array[0];
+ j = 1;
+ }
+ }
+
+
+
+ if (rv != LDAPU_SUCCESS) {
+ if (*res) { ldapu_msgfree(ld, *res); *res = 0; }
+ }
+
+ i = j; /* ugaston - if the search had been successful, despite verifyCert being "off",
+ * mapping is considered successful, so we keep the first (and only) response message.
+ * If, on the other hand, the search had returned multiple matches, the fact
+ * of having verifyCert "off" automatically turns the mapping faulty, so we
+ * don't need to care about keeping any response at all.
+ */
+
+ if (res_array) {
+ while (res_array[i] != NULL) {
+ ldapu_msgfree(ld, res_array[i]);
+ res_array[i++] = 0;
+ }
+ ldapu_memfree(ld, res_array);
+ }
+ return rv;
+}
+
+/* The caller shouldn't free the entry */
+NSAPI_PUBLIC int ldapu_cert_to_user (void *cert, LDAP *ld, const char *basedn,
+ LDAPMessage **res_out, char **user)
+{
+ int rv;
+ LDAPMessage *res;
+ LDAPMessage *entry;
+ int numEntries;
+ char **attrVals;
+
+ *res_out = 0;
+ *user = 0;
+
+ rv = ldapu_cert_to_ldap_entry(cert, ld, basedn, &res);
+
+ if (rv != LDAPU_SUCCESS) {
+ return rv;
+ }
+
+ if (!res) {
+ return LDAPU_ERR_EMPTY_LDAP_RESULT;
+ }
+
+ /* Extract user login (the 'uid' attr) from 'res' */
+ numEntries = ldapu_count_entries(ld, res);
+
+ if (numEntries != 1) {
+ return LDAPU_ERR_MULTIPLE_MATCHES;
+ }
+
+ entry = ldapu_first_entry(ld, res);
+
+ if (!entry) {
+ return LDAPU_ERR_MISSING_RES_ENTRY;
+ }
+
+ attrVals = ldapu_get_values(ld, entry,
+ ldapu_strings[LDAPU_STR_ATTR_USER]);
+
+ if (!attrVals || !attrVals[0]) {
+ return LDAPU_ERR_MISSING_UID_ATTR;
+ }
+
+ *user = strdup(attrVals[0]);
+ ldapu_value_free(ld, attrVals);
+
+/* ldapu_msgfree(res); */
+
+ if (!*user) {
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ *res_out = res;
+ return LDAPU_SUCCESS;
+}
+
+
+NSAPI_PUBLIC int ldapu_certinfo_modify (const char *issuerName,
+ const char *issuerDN,
+ const LDAPUPropValList_t *propval)
+{
+ LDAPUCertMapInfo_t *certinfo = 0;
+ int rv;
+
+ /* Make sure issuerName & issuerDN are both NULL or are both non-NULL */
+ if (!issuerName || !*issuerName) {
+ /* issuerDN must be NULL */
+ if (issuerDN) return LDAPU_ERR_WRONG_ARGS;
+ }
+ else if (!issuerDN || !*issuerDN) {
+ /* error - issuerName must be NULL but it is not */
+ return LDAPU_ERR_WRONG_ARGS;
+ }
+
+ if (!issuerDN) {
+ /* Modify the default certinfo */
+ certinfo = default_certmap_info;
+ }
+ else {
+ rv = ldapu_issuer_certinfo(issuerDN, (void **)&certinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ /* allocate new certinfo & add to the list */
+ certinfo = (LDAPUCertMapInfo_t *)malloc(sizeof(LDAPUCertMapInfo_t));
+ if (!certinfo) return LDAPU_ERR_OUT_OF_MEMORY;
+ memset((void *)certinfo, 0, sizeof(LDAPUCertMapInfo_t));
+
+ certinfo->issuerName = strdup(issuerName);
+ certinfo->issuerDN = strdup(issuerDN);
+
+ if (!certinfo->issuerName || !certinfo->issuerDN)
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Now modify the certinfo */
+ /* Free the old propval list and add new propval */
+ ldapu_propval_list_free(certinfo->propval);
+
+ if (propval) {
+ rv = ldapu_list_copy (propval, &certinfo->propval, ldapu_propval_copy);
+ if (rv != LDAPU_SUCCESS) return rv;
+ }
+
+ /* process_certinfo processes the info and adds to the certmap_listinfo */
+ process_certinfo(certinfo);
+
+ return LDAPU_SUCCESS;
+}
+
+/* ldapu_propval_same - returns LDAPU_SUCCESS or LDAPU_FAILED */
+static void * ldapu_propval_same (void *info, void *find_arg)
+{
+ /* check if info has find_arg as the issuerDN */
+ const char *issuerDN = (const char *)find_arg;
+ const LDAPUCertMapInfo_t *certinfo = (const LDAPUCertMapInfo_t *) info;
+
+ if (!ldapu_strcasecmp(certinfo->issuerDN, issuerDN))
+ return (void *)LDAPU_SUCCESS;
+ else
+ return (void *)LDAPU_FAILED;
+}
+
+NSAPI_PUBLIC int ldapu_certinfo_delete (const char *issuerDN)
+{
+ int rv;
+ LDAPUListNode_t *node;
+
+ if (!issuerDN || !*issuerDN)
+ return LDAPU_ERR_WRONG_ARGS;
+
+ rv = ldapu_list_find_node (certmap_listinfo, &node, ldapu_propval_same,
+ (void *)issuerDN);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = ldapu_list_remove_node (certmap_listinfo, node);
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_certinfo_save (const char *fname,
+ const char *old_fname,
+ const char *tmp_fname)
+{
+ /* Copy the header from the old_fname into a temporary file
+ * Save the default_certmap_info and certmap_listinfo into the temporary
+ * file. Rename the temporary file to the new file.
+ */
+ FILE *ofp;
+ FILE *tfp;
+ char buf[BIG_LINE];
+ char *ptr;
+ int eof;
+ int rv;
+ LDAPUPrintInfo_t pinfo;
+
+#ifdef XP_WIN32
+ if ((ofp = fopen(old_fname, "rt")) == NULL)
+#else
+ if ((ofp = fopen(old_fname, "r")) == NULL)
+#endif
+ {
+ return LDAPU_ERR_CANNOT_OPEN_FILE;
+ }
+
+ if ((tfp = fopen(tmp_fname, "w")) == NULL)
+ {
+ return LDAPU_ERR_CANNOT_OPEN_FILE;
+ }
+
+ eof = 0;
+ while(!eof) {
+ if (!fgets(buf, BIG_LINE, ofp)) break;
+
+ ptr = buf;
+
+ /* skip leading whitespace */
+ while(*ptr && isspace(*ptr)) ++ptr;
+
+ if (*ptr && *ptr != '#') {
+ /* It's not a comment, we are done */
+ break;
+ }
+
+ fprintf(tfp, "%s", buf);
+ }
+
+ fclose(ofp);
+
+ /* Output the default_certmap_info */
+ pinfo.fp = tfp;
+ pinfo.arg = default_certmap_info->issuerName;
+
+ rv = (int)ldapu_certinfo_print (default_certmap_info, &pinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ fclose(tfp);
+ return rv;
+ }
+
+ if (certmap_listinfo) {
+ rv = ldapu_list_print (certmap_listinfo, ldapu_certinfo_print,
+ &pinfo);
+
+ if (rv != LDAPU_SUCCESS) {
+ fclose(tfp);
+ return rv;
+ }
+ }
+
+ fclose(tfp);
+
+ /* replace old file with the tmp file */
+#ifdef _WIN32
+ if ( !MoveFileEx(tmp_fname, fname, MOVEFILE_REPLACE_EXISTING ))
+#else
+ if ( rename( tmp_fname, fname) != 0 )
+#endif
+ {
+ return LDAPU_ERR_RENAME_FILE_FAILED;
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+static void * ldapu_propval_free (void *propval_in, void *arg)
+{
+ LDAPUPropVal_t *propval = (LDAPUPropVal_t *)propval_in;
+
+ if (propval->prop) free(propval->prop);
+ if (propval->val) free(propval->val);
+ memset((void *)propval, 0, sizeof(LDAPUPropVal_t));
+ free(propval);
+ return 0;
+}
+
+void ldapu_certinfo_free (void *info_in)
+{
+ LDAPUCertMapInfo_t *certmap_info = (LDAPUCertMapInfo_t *)info_in;
+
+ if (certmap_info->issuerName) free(certmap_info->issuerName);
+ if (certmap_info->issuerDN) free(certmap_info->issuerDN);
+ if (certmap_info->propval)
+ ldapu_list_free(certmap_info->propval, ldapu_propval_free);
+ if (certmap_info->searchAttr) free(certmap_info->searchAttr);
+ memset((void *)certmap_info, 0, sizeof(LDAPUCertMapInfo_t));
+ free(certmap_info);
+}
+
+static void * ldapu_certinfo_free_helper (void *info, void *arg)
+{
+ ldapu_certinfo_free(info);
+ return (void *)LDAPU_SUCCESS;
+}
+
+void ldapu_certmap_listinfo_free (void *certmap_listinfo)
+{
+ LDAPUCertMapListInfo_t *list = (LDAPUCertMapListInfo_t *)certmap_listinfo;
+ ldapu_list_free(list, ldapu_certinfo_free_helper);
+}
+
+void ldapu_propval_list_free (void *propval_list)
+{
+ LDAPUPropValList_t *list = (LDAPUPropValList_t *)propval_list;
+ ldapu_list_free(list, ldapu_propval_free);
+}
+
+int ldapu_certmap_init (const char *config_file,
+ const char *dllname,
+ LDAPUCertMapListInfo_t **certmap_list,
+ LDAPUCertMapInfo_t **certmap_default)
+{
+ int rv;
+ certmap_listinfo = (LDAPUCertMapListInfo_t *)malloc(sizeof(LDAPUCertMapListInfo_t));
+
+ *certmap_list = 0;
+ *certmap_default = 0;
+ sprintf(this_dllname, "%s", dllname);
+
+ if (!certmap_listinfo) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ memset((void *)certmap_listinfo, 0, sizeof(LDAPUCertMapListInfo_t));
+
+ rv = certmap_read_certconfig_file(config_file);
+
+ if (rv == LDAPU_SUCCESS) {
+ *certmap_list = certmap_listinfo;
+ *certmap_default = default_certmap_info;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldaputil_exit ()
+{
+ if (default_certmap_info) {
+ ldapu_certinfo_free(default_certmap_info);
+ default_certmap_info = 0;
+ }
+
+ if (certmap_listinfo) {
+ ldapu_certmap_listinfo_free(certmap_listinfo);
+ certmap_listinfo = 0;
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+
+NSAPI_PUBLIC void ldapu_free (void *ptr)
+{
+ if (ptr) free(ptr);
+}
+
+NSAPI_PUBLIC void ldapu_free_old (char *ptr)
+{
+ free((void *)ptr);
+}
+
+NSAPI_PUBLIC void *ldapu_malloc (int size)
+{
+ return malloc(size);
+}
+
+NSAPI_PUBLIC char *ldapu_strdup (const char *ptr)
+{
+ return strdup(ptr);
+}
+
+NSAPI_PUBLIC void *ldapu_realloc (void *ptr, int size)
+{
+ return realloc(ptr, size);
+}
+
+#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
+
+static char *
+ldapu_dn_normalize( char *dn )
+{
+ char *d, *s;
+ int state, gotesc;
+
+ 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';
+
+ /* Trim trailing spaces */
+ d--;
+ while ( d >= dn && *d == ' ' ) {
+ *d-- = '\0';
+ }
+
+ return( dn );
+}
diff --git a/lib/ldaputil/certmap.conf b/lib/ldaputil/certmap.conf
new file mode 100644
index 00000000..35c1e9c8
--- /dev/null
+++ b/lib/ldaputil/certmap.conf
@@ -0,0 +1,48 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# This file configures how a certificate is mapped to an LDAP entry. See the
+# documentation for more information on this file.
+#
+# The format of this file is as follows:
+# certmap <name> <issuerDN>
+# <name>:<prop1> [<val1>]
+# <name>:<prop2> [<val2>]
+#
+# Notes:
+#
+# 1. Mapping can be defined per issuer of a certificate. If mapping doesn't
+# exists for a particular 'issuerDN' then the server uses the default
+# mapping.
+#
+# 2. There must be an entry for <name>=default and issuerDN "default".
+# This mapping is the default mapping.
+#
+# 3. '#' can be used to comment out a line.
+#
+# 4. DNComps & FilterComps are used to form the base DN and filter resp. for
+# performing an LDAP search while mapping the cert to a user entry.
+#
+# 5. DNComps can be one of the following:
+# commented out - take the user's DN from the cert as is
+# empty - search the entire LDAP tree (DN == suffix)
+# attr names - a comma separated list of attributes to form DN
+#
+# 6. FilterComps can be one of the following:
+# commented out - set the filter to "objectclass=*"
+# empty - set the filter to "objectclass=*"
+# attr names - a comma separated list of attributes to form the filter
+#
+
+certmap default default
+#default:DNComps
+#default:FilterComps e, uid
+#default:verifycert on
+#default:CmapLdapAttr certSubjectDN
+#default:library <path_to_shared_lib_or_dll>
+#default:InitFn <Init function's name>
diff --git a/lib/ldaputil/dbconf.c b/lib/ldaputil/dbconf.c
new file mode 100644
index 00000000..684d62df
--- /dev/null
+++ b/lib/ldaputil/dbconf.c
@@ -0,0 +1,704 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <string.h>
+#include <malloc.h>
+#include <ctype.h>
+
+#include <ldaputil/errors.h>
+#include <ldaputil/certmap.h>
+#include <ldaputil/encode.h>
+#include <ldaputil/dbconf.h>
+
+#define BIG_LINE 1024
+
+static const char *DB_DIRECTIVE = "directory";
+static const int DB_DIRECTIVE_LEN = 9; /* strlen("DB_DIRECTIVE") */
+
+static const char *ENCODED = "encoded";
+
+static void insert_dbinfo_propval(DBConfDBInfo_t *db_info,
+ DBPropVal_t *propval)
+{
+ if (db_info->lastprop) {
+ db_info->lastprop->next = propval;
+ }
+ else {
+ db_info->firstprop = propval;
+ }
+
+ db_info->lastprop = propval;
+}
+
+static void insert_dbconf_dbinfo(DBConfInfo_t *conf_info,
+ DBConfDBInfo_t *db_info)
+{
+ if (conf_info->lastdb) {
+ conf_info->lastdb->next = db_info;
+ }
+ else {
+ conf_info->firstdb = db_info;
+ }
+
+ conf_info->lastdb = db_info;
+}
+
+void dbconf_free_propval (DBPropVal_t *propval)
+{
+ if (propval) {
+ if (propval->prop) free(propval->prop);
+ if (propval->val) free(propval->val);
+ memset((void *)propval, 0, sizeof(DBPropVal_t));
+ free(propval);
+ }
+}
+
+NSAPI_PUBLIC void dbconf_free_dbinfo (DBConfDBInfo_t *db_info)
+{
+ if (db_info) {
+ DBPropVal_t *next;
+ DBPropVal_t *cur;
+
+ if (db_info->dbname) free(db_info->dbname);
+ if (db_info->url) free(db_info->url);
+
+ cur = db_info->firstprop;
+
+ while(cur) {
+ next = cur->next;
+ dbconf_free_propval(cur);
+ cur = next;
+ }
+
+ memset((void *)db_info, 0, sizeof(DBConfDBInfo_t));
+ free(db_info);
+ }
+}
+
+NSAPI_PUBLIC void dbconf_free_confinfo (DBConfInfo_t *conf_info)
+{
+ DBConfDBInfo_t *next;
+ DBConfDBInfo_t *cur;
+
+ if (conf_info) {
+ cur = conf_info->firstdb;
+
+ while (cur) {
+ next = cur->next;
+ dbconf_free_dbinfo(cur);
+ cur = next;
+ }
+
+ memset((void *)conf_info, 0, sizeof(DBConfInfo_t));
+ free(conf_info);
+ }
+}
+
+static int skip_blank_lines_and_spaces(FILE *fp, char *buf, char **ptr_out,
+ int *eof)
+{
+ char *ptr = buf;
+ char *end;
+
+ while(buf && (*buf || fgets(buf, BIG_LINE, fp))) {
+ ptr = buf;
+
+ /* skip leading whitespace */
+ while(*ptr && isspace(*ptr)) ++ptr;
+
+ /* skip blank line or comment */
+ if (!*ptr || *ptr == '#') {
+ *buf = 0; /* to force reading of next line */
+ continue;
+ }
+
+ /* Non-blank line found */
+ break;
+ }
+
+ *ptr_out = ptr;
+ if (!*ptr) {
+ *eof = 1;
+ }
+ else {
+ /* skip trailing whitespace */
+ end = ptr + strlen(ptr) - 1;
+ while(isspace(*end)) *end-- = 0;
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+static int dbconf_parse_propval (char *buf, char *ptr,
+ DBConfDBInfo_t *db_info)
+{
+ char *dbname = db_info->dbname;
+ int dbname_len = strlen(dbname);
+ char *prop;
+ char *val;
+ DBPropVal_t *propval;
+ char *delimeter_chars = " \t";
+ char *lastchar;
+ int end_of_prop;
+ char *encval = 0; /* encoded value */
+ char *origprop = 0;
+
+ if ((ptr - buf + dbname_len > BIG_LINE) ||
+ strncmp(ptr, dbname, dbname_len) ||
+ !(ptr[dbname_len] == ':' || isspace(ptr[dbname_len])))
+ {
+ /* Not a prop-val for the current db but not an error */
+ return LDAPU_ERR_NOT_PROPVAL;
+ }
+
+ /* remove the last char if it is newline */
+ lastchar = strrchr(buf, '\n');
+ if (lastchar) *lastchar = '\0';
+
+ prop = ptr + dbname_len + 1;
+
+ while(*prop && (isspace(*prop) || *prop == ':')) ++prop;
+
+ if (!*prop) {
+ return LDAPU_ERR_PROP_IS_MISSING;
+ }
+
+ end_of_prop = strcspn(prop, delimeter_chars);
+
+ if (prop[end_of_prop] != '\0') {
+ /* buf doesn't end here -- val is present */
+ prop[end_of_prop] = '\0';
+ val = &prop[end_of_prop + 1];
+
+ while(*val && isspace(*val)) ++val;
+ if (*val == '\0') val = 0;
+ }
+ else {
+ val = 0;
+ }
+
+ /*
+ * The prop-val line could be one of the following:
+ * "<dbname>:prop val" OR "<dbname>:encoded prop encval"
+ * If (prop == "encoded") then the val has "prop encval".
+ * Get the actual prop from val and get encval (i.e. encoded value)
+ * and decode it. If it is encoded then the val part must be non-NULL.
+ */
+ if (val && *val && !strcmp(prop, ENCODED)) {
+ /* val has the actual prop followed by the encoded value */
+ origprop = prop;
+ prop = val;
+ while(*prop && (isspace(*prop) || *prop == ':')) ++prop;
+
+ if (!*prop) {
+ return LDAPU_ERR_PROP_IS_MISSING;
+ }
+
+ end_of_prop = strcspn(prop, delimeter_chars);
+
+ if (prop[end_of_prop] != '\0') {
+ /* buf doesn't end here -- encval is present */
+ prop[end_of_prop] = '\0';
+ encval = &prop[end_of_prop + 1];
+
+ while(*encval && isspace(*encval)) ++encval;
+ if (*encval == '\0') encval = 0;
+ }
+ else {
+ encval = 0;
+ }
+
+ if (!encval) {
+ /* special case - if encval is null, "encoded" itself is a
+ * property and what we have in prop now is the value. */
+ val = prop;
+ prop = origprop;
+ }
+ else {
+ /* decode the value */
+ val = dbconf_decodeval(encval);
+ }
+ }
+
+ /* Success - we have prop & val */
+ propval = (DBPropVal_t *)malloc(sizeof(DBPropVal_t));
+
+ if (!propval) return LDAPU_ERR_OUT_OF_MEMORY;
+ memset((void *)propval, 0, sizeof(DBPropVal_t));
+ propval->prop = strdup(prop);
+ propval->val = val ? strdup(val) : 0;
+
+ if (!propval->prop || (val && !propval->val)) {
+ dbconf_free_propval(propval);
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ if (encval) free(val); /* val was allocated by dbconf_decodeval */
+
+ insert_dbinfo_propval(db_info, propval);
+ return LDAPU_SUCCESS;
+}
+
+static int dbconf_read_propval (FILE *fp, char *buf, DBConfDBInfo_t *db_info,
+ int *eof)
+{
+ int rv;
+ char *ptr = buf;
+
+ while(buf && (*buf || fgets(buf, BIG_LINE, fp))) {
+ ptr = buf;
+
+ rv = skip_blank_lines_and_spaces(fp, buf, &ptr, eof);
+
+ if (rv != LDAPU_SUCCESS || *eof) return rv;
+
+ /* We have a non-blank line which could be prop-val pair for the
+ * dbname in the db_info. parse the prop-val pair and continue.
+ */
+ rv = dbconf_parse_propval(buf, ptr, db_info);
+
+ if (rv == LDAPU_ERR_NOT_PROPVAL) return LDAPU_SUCCESS;
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ *buf = 0; /* to force reading of next line */
+ }
+
+ if (!*buf) *eof = 1;
+
+ return LDAPU_SUCCESS;
+}
+
+static int parse_directive(char *buf, const char *directive,
+ const int directive_len,
+ DBConfDBInfo_t **db_info_out)
+{
+ DBConfDBInfo_t *db_info;
+ char *dbname;
+ char *url;
+ int end_of_dbname;
+ char *delimeter_chars = " \t";
+ char *lastchar;
+
+ /* remove the last char if it is newline */
+ lastchar = strrchr(buf, '\n');
+ if (lastchar) *lastchar = '\0';
+
+ if (strncmp(buf, directive, directive_len) ||
+ !isspace(buf[directive_len]))
+ {
+ return LDAPU_ERR_DIRECTIVE_IS_MISSING;
+ }
+
+ dbname = buf + directive_len + 1;
+
+ while(*dbname && isspace(*dbname)) ++dbname;
+
+ if (!*dbname) {
+ return LDAPU_ERR_DBNAME_IS_MISSING;
+ }
+
+ end_of_dbname = strcspn(dbname, delimeter_chars);
+
+ if (dbname[end_of_dbname] != '\0') {
+ /* buf doesn't end here -- url is present */
+ dbname[end_of_dbname] = '\0';
+ url = &dbname[end_of_dbname + 1];
+
+ while(*url && isspace(*url)) ++url;
+
+ if (*url == '\0') url = 0;
+ }
+ else {
+ url = 0;
+ }
+
+ /* Success - we have dbname & url */
+ db_info = (DBConfDBInfo_t *)malloc(sizeof(DBConfDBInfo_t));
+
+ if (!db_info) return LDAPU_ERR_OUT_OF_MEMORY;
+ memset((void *)db_info, 0, sizeof(DBConfDBInfo_t));
+ db_info->dbname = strdup(dbname);
+ db_info->url = url ? strdup(url) : 0;
+
+ if (!db_info->dbname || (url && !db_info->url)) {
+ dbconf_free_dbinfo(db_info);
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ *db_info_out = db_info;
+ return LDAPU_SUCCESS;
+}
+
+/* Read the next database info from the file and put it in db_info_out. The
+ * buf may contain first line of the database info. When this function
+ * finishes, the buf may contain unprocessed information (which should be
+ * passed to the next call to read_db_info).
+ */
+static int read_db_info (FILE *fp, char *buf, DBConfDBInfo_t **db_info_out,
+ const char *directive, const int directive_len,
+ int *eof)
+{
+ char *ptr;
+ int found_directive = 0;
+ DBConfDBInfo_t *db_info;
+ int rv;
+
+ *db_info_out = 0;
+
+ rv = skip_blank_lines_and_spaces(fp, buf, &ptr, eof);
+
+ if (rv != LDAPU_SUCCESS || *eof) return rv;
+
+ /* We possibly have a directive of the form "directory <name> <url>" */
+ rv = parse_directive(ptr, directive, directive_len, &db_info);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ /* We have parsed the directive successfully -- lets look for additional
+ * property-value pairs for the database.
+ */
+ if (!fgets(buf, BIG_LINE, fp)) {
+ *eof = 1;
+ rv = LDAPU_SUCCESS;
+ }
+ else {
+ rv = dbconf_read_propval(fp, buf, db_info, eof);
+ }
+
+ if (rv != LDAPU_SUCCESS) {
+ dbconf_free_dbinfo(db_info);
+ *db_info_out = 0;
+ }
+ else {
+ *db_info_out = db_info;
+ }
+
+ return rv;
+}
+
+int dbconf_read_config_file_sub (const char *file,
+ const char *directive,
+ const int directive_len,
+ DBConfInfo_t **conf_info_out)
+{
+ FILE *fp;
+ DBConfInfo_t *conf_info;
+ DBConfDBInfo_t *db_info;
+ char buf[BIG_LINE];
+ int rv;
+ int eof;
+
+ buf[0] = 0;
+
+#ifdef XP_WIN32
+ if ((fp = fopen(file, "rt")) == NULL)
+#else
+ if ((fp = fopen(file, "r")) == NULL)
+#endif
+ {
+ return LDAPU_ERR_CANNOT_OPEN_FILE;
+ }
+
+ /* Allocate DBConfInfo_t */
+ conf_info = (DBConfInfo_t *)malloc(sizeof(DBConfInfo_t));
+
+ if (!conf_info) {
+ fclose(fp);
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ memset((void *)conf_info, 0, sizeof(DBConfInfo_t));
+
+ /* Read each db info */
+ eof = 0;
+ while(!eof &&
+ ((rv = read_db_info(fp, buf, &db_info, directive, directive_len, &eof)) == LDAPU_SUCCESS))
+ {
+ insert_dbconf_dbinfo(conf_info, db_info);
+ }
+
+ if (rv != LDAPU_SUCCESS) {
+ dbconf_free_confinfo(conf_info);
+ *conf_info_out = 0;
+ }
+ else {
+ *conf_info_out = conf_info;
+ }
+
+ fclose(fp);
+ return rv;
+}
+
+NSAPI_PUBLIC int dbconf_read_config_file (const char *file, DBConfInfo_t **conf_info_out)
+{
+ return dbconf_read_config_file_sub(file, DB_DIRECTIVE, DB_DIRECTIVE_LEN,
+ conf_info_out);
+}
+
+int dbconf_read_default_dbinfo_sub (const char *file,
+ const char *directive,
+ const int directive_len,
+ DBConfDBInfo_t **db_info_out)
+{
+ FILE *fp;
+ DBConfDBInfo_t *db_info;
+ char buf[BIG_LINE];
+ int rv;
+ int eof;
+
+ buf[0] = 0;
+
+#ifdef XP_WIN32
+ if ((fp = fopen(file, "rt")) == NULL)
+#else
+ if ((fp = fopen(file, "r")) == NULL)
+#endif
+ {
+ return LDAPU_ERR_CANNOT_OPEN_FILE;
+ }
+
+ /* Read each db info until eof or dbname == default*/
+ eof = 0;
+
+ while(!eof &&
+ ((rv = read_db_info(fp, buf, &db_info, directive, directive_len, &eof)) == LDAPU_SUCCESS))
+ {
+ if (!strcmp(db_info->dbname, DBCONF_DEFAULT_DBNAME)) break;
+ dbconf_free_dbinfo(db_info);
+ }
+
+ if (rv != LDAPU_SUCCESS) {
+ *db_info_out = 0;
+ }
+ else {
+ *db_info_out = db_info;
+ }
+
+ fclose(fp);
+ return rv;
+}
+
+
+NSAPI_PUBLIC int dbconf_read_default_dbinfo (const char *file,
+ DBConfDBInfo_t **db_info_out)
+{
+ return dbconf_read_default_dbinfo_sub(file, DB_DIRECTIVE, DB_DIRECTIVE_LEN,
+ db_info_out);
+}
+
+/*
+ * ldapu_strncasecmp - is like strncasecmp on UNIX but also accepts null strings.
+ */
+/* Not tested */
+static int ldapu_strncasecmp (const char *s1, const char *s2, size_t len)
+{
+ int ls1, ls2; /* tolower values of chars in s1 & s2 resp. */
+
+ if (0 == len) return 0;
+ else if (!s1) return !s2 ? 0 : 0-tolower(*s2);
+ else if (!s2) return tolower(*s1);
+
+#ifdef XP_WIN32
+ while(len > 0 && *s1 && *s2 &&
+ (ls1 = tolower(*s1)) == (ls2 = tolower(*s2)))
+ {
+ s1++; s2++; len--;
+ }
+
+ if (0 == len)
+ return 0;
+ else if (!*s1)
+ return *s2 ? 0-tolower(*s2) : 0;
+ else if (!*s2)
+ return tolower(*s1);
+ else
+ return ls1 - ls2;
+#else
+ return strncasecmp(s1, s2, len);
+#endif
+}
+
+
+/*
+ * ldapu_strcasecmp - is like strcasecmp on UNIX but also accepts null strings.
+ */
+int ldapu_strcasecmp (const char *s1, const char *s2)
+{
+ int ls1, ls2; /* tolower values of chars in s1 & s2 resp. */
+
+ if (!s1) return !s2 ? 0 : 0-tolower(*s2);
+ else if (!s2) return tolower(*s1);
+
+#ifdef XP_WIN32
+ while(*s1 && *s2 && (ls1 = tolower(*s1)) == (ls2 = tolower(*s2))) { s1++; s2++; }
+
+ if (!*s1)
+ return *s2 ? 0-tolower(*s2) : 0;
+ else if (!*s2)
+ return tolower(*s1);
+ else
+ return ls1 - ls2;
+#else
+ return strcasecmp(s1, s2);
+#endif
+}
+
+NSAPI_PUBLIC int ldapu_dbinfo_attrval (DBConfDBInfo_t *db_info,
+ const char *attr, char **val)
+{
+ /* Look for given attr in the db_info and return its value */
+ int rv = LDAPU_ATTR_NOT_FOUND;
+ DBPropVal_t *next;
+
+ *val = 0;
+
+ if (db_info) {
+ next = db_info->firstprop;
+ while (next) {
+ rv = ldapu_strcasecmp(attr, next->prop);
+ if (!rv) {
+ /* Found the property */
+ *val = next->val ? strdup(next->val) : 0;
+
+ if (next->val && !*val) {
+ rv = LDAPU_ERR_OUT_OF_MEMORY;
+ }
+ else {
+ rv = LDAPU_SUCCESS;
+ }
+ break;
+ }
+ next = next->next;
+ }
+ }
+
+ return rv;
+}
+
+void dbconf_print_propval (DBPropVal_t *propval)
+{
+ if (propval) {
+ fprintf(stderr, "\tprop: \"%s\"\tval: \"%s\"\n", propval->prop,
+ propval->val ? propval->val : "");
+ }
+ else {
+ fprintf(stderr, "Null propval\n");
+ }
+}
+
+void dbconf_print_dbinfo (DBConfDBInfo_t *db_info)
+{
+ DBPropVal_t *next;
+
+ if (db_info) {
+ fprintf(stderr, "dbname: \"%s\"\n", db_info->dbname);
+ fprintf(stderr, "url: \t\"%s\"\n", db_info->url ? db_info->url : "");
+ next = db_info->firstprop;
+ while (next) {
+ dbconf_print_propval(next);
+ next = next->next;
+ }
+ }
+ else {
+ fprintf(stderr, "Null db_info\n");
+ }
+}
+
+void dbconf_print_confinfo (DBConfInfo_t *conf_info)
+{
+ DBConfDBInfo_t *next;
+
+ if (conf_info) {
+ next = conf_info->firstdb;
+ while (next) {
+ dbconf_print_dbinfo(next);
+ next = next->next;
+ }
+ }
+ else {
+ fprintf(stderr, "Null conf_info\n");
+ }
+}
+
+
+
+NSAPI_PUBLIC int dbconf_output_db_directive (FILE *fp, const char *dbname,
+ const char *url)
+{
+ fprintf(fp, "%s %s %s\n", DB_DIRECTIVE, dbname, url);
+ return LDAPU_SUCCESS;
+}
+
+NSAPI_PUBLIC int dbconf_output_propval (FILE *fp, const char *dbname,
+ const char *prop, const char *val, const int encoded)
+{
+ if (encoded && val && *val) {
+ char *new_val = dbconf_encodeval(val);
+
+ if (!new_val) return LDAPU_ERR_OUT_OF_MEMORY;
+ fprintf(fp, "%s:%s %s %s\n", dbname, ENCODED,
+ prop, new_val);
+ free(new_val);
+ }
+ else {
+ fprintf(fp, "%s:%s %s\n", dbname, prop, val ? val : "");
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+
+
+NSAPI_PUBLIC int dbconf_get_dbnames (const char *dbmap, char ***dbnames_out, int *cnt_out)
+{
+ DBConfInfo_t *conf_info = 0;
+ DBConfDBInfo_t *db = 0;
+ int cnt = 0;
+ char **dbnames = 0;
+ char *heap = 0;
+ int rv;
+
+ *dbnames_out = 0;
+ *cnt_out = 0;
+
+ rv = dbconf_read_config_file(dbmap, &conf_info);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ db = conf_info->firstdb;
+
+
+ dbnames = (char **)malloc(32*1024);
+ heap = (char *)dbnames + 2*1024;
+
+ if (!dbnames) {
+ dbconf_free_confinfo(conf_info);
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ *dbnames_out = dbnames;
+
+ while(db) {
+ *dbnames++ = heap;
+ strcpy(heap, db->dbname);
+ heap += strlen(db->dbname)+1;
+ db = db->next;
+ cnt++;
+ }
+
+ *dbnames = NULL;
+ *cnt_out = cnt;
+ dbconf_free_confinfo(conf_info);
+
+ return LDAPU_SUCCESS;
+}
+
+NSAPI_PUBLIC int dbconf_free_dbnames (char **dbnames)
+{
+ if (dbnames)
+ free(dbnames);
+
+ return LDAPU_SUCCESS;
+}
diff --git a/lib/ldaputil/encode.c b/lib/ldaputil/encode.c
new file mode 100644
index 00000000..3157418c
--- /dev/null
+++ b/lib/ldaputil/encode.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 **/
+
+#include <malloc.h>
+#include <string.h>
+#include <ldaputil/certmap.h>
+#include <ldaputil/encode.h>
+
+/* The magic set of 64 chars in the uuencoded data */
+static unsigned char uuset[] = {
+'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
+'U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n',
+'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7',
+'8','9','+','/' };
+
+static int do_uuencode(unsigned char *src, unsigned char *dst, int srclen)
+{
+ int i, r;
+ unsigned char *p;
+
+/* To uuencode, we snip 8 bits from 3 bytes and store them as
+6 bits in 4 bytes. 6*4 == 8*3 (get it?) and 6 bits per byte
+yields nice clean bytes
+
+It goes like this:
+ AAAAAAAA BBBBBBBB CCCCCCCC
+turns into the standard set of uuencode ascii chars indexed by numbers:
+ 00AAAAAA 00AABBBB 00BBBBCC 00CCCCCC
+
+Snip-n-shift, snip-n-shift, etc....
+
+*/
+
+ for (p=dst,i=0; i < srclen; i += 3) {
+ /* Do 3 bytes of src */
+ register char b0, b1, b2;
+
+ b0 = src[0];
+ if (i==srclen-1)
+ b1 = b2 = '\0';
+ else if (i==srclen-2) {
+ b1 = src[1];
+ b2 = '\0';
+ }
+ else {
+ b1 = src[1];
+ b2 = src[2];
+ }
+
+ *p++ = uuset[b0>>2];
+ *p++ = uuset[(((b0 & 0x03) << 4) | ((b1 & 0xf0) >> 4))];
+ *p++ = uuset[(((b1 & 0x0f) << 2) | ((b2 & 0xc0) >> 6))];
+ *p++ = uuset[b2 & 0x3f];
+ src += 3;
+ }
+ *p = 0; /* terminate the string */
+ r = (unsigned char *)p - (unsigned char *)dst;/* remember how many we did */
+
+ /* Always do 4-for-3, but if not round threesome, have to go
+ clean up the last extra bytes */
+
+ for( ; i != srclen; i--)
+ *--p = '=';
+
+ return r;
+}
+
+const unsigned char pr2six[256]={
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
+ 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
+ 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
+ 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
+ 64,64,64,64,64,64,64,64,64,64,64,64,64
+};
+
+static char *_uudecode(const char *bufcoded)
+{
+ register const char *bufin = bufcoded;
+ register unsigned char *bufout;
+ register int nprbytes;
+ unsigned char *bufplain;
+ int nbytesdecoded;
+
+ /* Find the length */
+ while(pr2six[(int)*(bufin++)] <= 63);
+ nprbytes = bufin - bufcoded - 1;
+ nbytesdecoded = ((nprbytes+3)/4) * 3;
+
+ bufout = (unsigned char *) malloc(nbytesdecoded + 1);
+ bufplain = bufout;
+
+ bufin = bufcoded;
+
+ while (nprbytes > 0) {
+ *(bufout++) = (unsigned char)
+ (pr2six[(int)(*bufin)] << 2 | pr2six[(int)bufin[1]] >> 4);
+ *(bufout++) = (unsigned char)
+ (pr2six[(int)bufin[1]] << 4 | pr2six[(int)bufin[2]] >> 2);
+ *(bufout++) = (unsigned char)
+ (pr2six[(int)bufin[2]] << 6 | pr2six[(int)bufin[3]]);
+ bufin += 4;
+ nprbytes -= 4;
+ }
+
+ if(nprbytes & 03) {
+ if(pr2six[(int)bufin[-2]] > 63)
+ nbytesdecoded -= 2;
+ else
+ nbytesdecoded -= 1;
+ }
+ bufplain[nbytesdecoded] = '\0';
+
+ return (char *)bufplain;
+}
+
+
+char *dbconf_encodeval (const char *val)
+{
+ int len = strlen(val);
+ char *dst = (char *)malloc(2*len);
+
+ if (dst) {
+ do_uuencode((unsigned char *)val, (unsigned char *)dst, len);
+ }
+
+ return dst;
+}
+
+char *dbconf_decodeval (const char *val)
+{
+ return _uudecode(val);
+}
+
diff --git a/lib/ldaputil/errors.c b/lib/ldaputil/errors.c
new file mode 100644
index 00000000..d2f50843
--- /dev/null
+++ b/lib/ldaputil/errors.c
@@ -0,0 +1,202 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <ldaputil/errors.h>
+#include <ldaputil/certmap.h>
+
+NSAPI_PUBLIC char *ldapu_err2string(int err)
+{
+ char *rv;
+
+ switch(err) {
+
+ /* Error codes defined in certmap.h */
+ case LDAPU_SUCCESS:
+ rv = "success";
+ break;
+ case LDAPU_FAILED:
+ rv = "ldap search didn't find an ldap entry";
+ break;
+ case LDAPU_CERT_MAP_FUNCTION_FAILED:
+ rv = "Cert mapping function failed";
+ break;
+ case LDAPU_CERT_SEARCH_FUNCTION_FAILED:
+ rv = "Cert search function failed";
+ break;
+ case LDAPU_CERT_VERIFY_FUNCTION_FAILED:
+ rv = "Cert verify function failed";
+ break;
+ case LDAPU_CERT_MAP_INITFN_FAILED:
+ rv = "Certmap InitFn function failed";
+ break;
+
+
+ /* Error codes returned by ldapdb.c */
+ case LDAPU_ERR_URL_INVALID_PREFIX:
+ rv = "invalid local ldap database url prefix -- must be ldapdb://";
+ break;
+ case LDAPU_ERR_URL_NO_BASEDN:
+ rv = "base dn is missing in ldapdb url";
+ break;
+ case LDAPU_ERR_OUT_OF_MEMORY:
+ rv = "out of memory";
+ break;
+ case LDAPU_ERR_LDAP_INIT_FAILED:
+ rv = "Couldn't initialize connection to the ldap directory server";
+ break;
+ case LDAPU_ERR_LCACHE_INIT_FAILED:
+ rv = "Couldn't initialize connection to the local ldap directory";
+ break;
+ case LDAPU_ERR_LDAP_SET_OPTION_FAILED:
+ rv = "ldap_set_option failed for local ldap database";
+ break;
+ case LDAPU_ERR_NO_DEFAULT_CERTDB:
+ rv = "default cert database not initialized when using LDAP over SSL";
+ break;
+
+
+ /* Errors returned by ldapauth.c */
+ case LDAPU_ERR_CIRCULAR_GROUPS:
+ rv = "Circular groups were detected during group membership check";
+ break;
+ case LDAPU_ERR_INVALID_STRING:
+ rv = "Invalid string";
+ break;
+ case LDAPU_ERR_INVALID_STRING_INDEX:
+ rv = "Invalid string index";
+ break;
+ case LDAPU_ERR_MISSING_ATTR_VAL:
+ rv = "Missing attribute value from the search result";
+ break;
+
+
+ /* Errors returned by dbconf.c */
+ case LDAPU_ERR_CANNOT_OPEN_FILE:
+ rv = "cannot open the config file";
+ break;
+ case LDAPU_ERR_DBNAME_IS_MISSING:
+ rv = "database name is missing";
+ break;
+ case LDAPU_ERR_PROP_IS_MISSING:
+ rv = "database property is missing";
+ break;
+ case LDAPU_ERR_DIRECTIVE_IS_MISSING:
+ rv = "illegal directive in the config file";
+ break;
+ case LDAPU_ERR_NOT_PROPVAL:
+ rv = "internal error - LDAPU_ERR_NOT_PROPVAL";
+ break;
+
+
+ /* Error codes returned by certmap.c */
+ case LDAPU_ERR_NO_ISSUERDN_IN_CERT:
+ rv = "cannot extract issuer DN from the cert";
+ break;
+ case LDAPU_ERR_NO_ISSUERDN_IN_CONFIG_FILE:
+ rv = "issuer DN missing for non-default certmap";
+ break;
+ case LDAPU_ERR_CERTMAP_INFO_MISSING:
+ rv = "cert to ldap entry mapping information is missing";
+ break;
+ case LDAPU_ERR_MALFORMED_SUBJECT_DN:
+ rv = "Found malformed subject DN in the certificate";
+ break;
+ case LDAPU_ERR_MAPPED_ENTRY_NOT_FOUND:
+ rv = "Certificate couldn't be mapped to an ldap entry";
+ break;
+ case LDAPU_ERR_UNABLE_TO_LOAD_PLUGIN:
+ rv = "Unable to load certmap plugin library";
+ break;
+ case LDAPU_ERR_MISSING_INIT_FN_IN_CONFIG:
+ rv = "InitFn must be provided when using certmap plugin library";
+ break;
+ case LDAPU_ERR_MISSING_INIT_FN_IN_LIB:
+ rv = "Could not find InitFn in the certmap plugin library";
+ break;
+ case LDAPU_ERR_CERT_VERIFY_FAILED:
+ rv = "Could not matching certificate in User's LDAP entry";
+ break;
+ case LDAPU_ERR_CERT_VERIFY_NO_CERTS:
+ rv = "User's LDAP entry doesn't have any certificates to compare";
+ break;
+ case LDAPU_ERR_MISSING_LIBNAME:
+ rv = "Library name is missing in the config file";
+ break;
+ case LDAPU_ERR_MISSING_INIT_FN_NAME:
+ rv = "Init function name is missing in the config file";
+ break;
+ case LDAPU_ERR_WRONG_ARGS:
+ rv = "ldaputil API function called with wrong arguments";
+ break;
+ case LDAPU_ERR_RENAME_FILE_FAILED:
+ rv = "Renaming of file failed";
+ break;
+ case LDAPU_ERR_MISSING_VERIFYCERT_VAL:
+ rv = "VerifyCert property value must be on or off";
+ break;
+ case LDAPU_ERR_CANAME_IS_MISSING:
+ rv = "Cert issuer name is missing";
+ break;
+ case LDAPU_ERR_CAPROP_IS_MISSING:
+ rv = "property name is missing";
+ break;
+ case LDAPU_ERR_UNKNOWN_CERT_ATTR:
+ rv = "unknown cert attribute";
+ break;
+
+
+ case LDAPU_ERR_EMPTY_LDAP_RESULT:
+ rv = "ldap search returned empty result";
+ break;
+ case LDAPU_ERR_MULTIPLE_MATCHES:
+ rv = "ldap search returned multiple matches when one expected";
+ break;
+ case LDAPU_ERR_MISSING_RES_ENTRY:
+ rv = "Could not extract entry from the ldap search result";
+ break;
+ case LDAPU_ERR_MISSING_UID_ATTR:
+ rv = "ldap entry is missing the 'uid' attribute value";
+ break;
+ case LDAPU_ERR_INVALID_ARGUMENT:
+ rv = "invalid argument passed to the certmap API function";
+ break;
+ case LDAPU_ERR_INVALID_SUFFIX:
+ rv = "invalid LDAP directory suffix";
+ break;
+
+
+ /* Error codes returned by cert.c */
+ case LDAPU_ERR_EXTRACT_SUBJECTDN_FAILED:
+ rv = "Couldn't extract the subject DN from the certificate";
+ break;
+ case LDAPU_ERR_EXTRACT_ISSUERDN_FAILED:
+ rv = "Couldn't extract the issuer DN from the certificate";
+ break;
+ case LDAPU_ERR_EXTRACT_DERCERT_FAILED:
+ rv = "Couldn't extract the original DER encoding from the certificate";
+ break;
+
+
+ case LDAPU_ERR_NOT_IMPLEMENTED:
+ rv = "function not implemented yet";
+ break;
+ case LDAPU_ERR_INTERNAL:
+ rv = "ldaputil internal error";
+ break;
+
+ default:
+ if (err > 0) {
+ /* LDAP errors are +ve */
+ rv = ldap_err2string(err);
+ }
+ else {
+ rv = "internal error - unknown error code";
+ }
+ break;
+ }
+
+ return rv;
+}
diff --git a/lib/ldaputil/examples/Certmap.mak b/lib/ldaputil/examples/Certmap.mak
new file mode 100644
index 00000000..618db42b
--- /dev/null
+++ b/lib/ldaputil/examples/Certmap.mak
@@ -0,0 +1,254 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+!IF "$(CFG)" == ""
+CFG=Certmap - Win32 Debug
+!MESSAGE No configuration specified. Defaulting to Certmap - Win32 Debug.
+!ENDIF
+
+!IF "$(CFG)" != "Certmap - Win32 Release" && "$(CFG)" !=\
+ "Certmap - Win32 Debug"
+!MESSAGE Invalid configuration "$(CFG)" specified.
+!MESSAGE You can specify a configuration when running NMAKE on this makefile
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Certmap.mak" CFG="Certmap - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Certmap - Win32 Release" (based on\
+ "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "Certmap - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+!ERROR An invalid configuration is specified.
+!ENDIF
+
+!IF "$(OS)" == "Windows_NT"
+NULL=
+!ELSE
+NULL=nul
+!ENDIF
+################################################################################
+# Begin Project
+# PROP Target_Last_Scanned "Certmap - Win32 Debug"
+CPP=cl.exe
+RSC=rc.exe
+MTL=mktyplib.exe
+
+!IF "$(CFG)" == "Certmap - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+OUTDIR=.\Release
+INTDIR=.\Release
+
+ALL : "$(OUTDIR)\Certmap.dll"
+
+CLEAN :
+ -@erase "$(INTDIR)\init.obj"
+ -@erase "$(INTDIR)\plugin.obj"
+ -@erase "$(OUTDIR)\Certmap.dll"
+ -@erase "$(OUTDIR)\Certmap.exp"
+ -@erase "$(OUTDIR)\Certmap.lib"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MT /W3 /GX /O2 /I "c:\netscape\suitespot\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "c:\netscape\suitespot\include" /D "WIN32"\
+ /D "NDEBUG" /D "_WINDOWS" /Fp"$(INTDIR)/Certmap.pch" /YX /Fo"$(INTDIR)/" /c
+CPP_OBJS=.\Release/
+CPP_SBRS=.\.
+# ADD BASE MTL /nologo /D "NDEBUG" /win32
+# ADD MTL /nologo /D "NDEBUG" /win32
+MTL_PROJ=/nologo /D "NDEBUG" /win32
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/Certmap.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:windows /dll /incremental:no\
+ /pdb:"$(OUTDIR)/Certmap.pdb" /machine:I386 /out:"$(OUTDIR)/Certmap.dll"\
+ /implib:"$(OUTDIR)/Certmap.lib"
+LINK32_OBJS= \
+ "$(INTDIR)\init.obj" \
+ "$(INTDIR)\plugin.obj" \
+ "C:\Netscape\SuiteSpot\lib\nsldap32v10.lib"
+
+"$(OUTDIR)\Certmap.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ELSEIF "$(CFG)" == "Certmap - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Target_Dir ""
+OUTDIR=.\Debug
+INTDIR=.\Debug
+
+ALL : "$(OUTDIR)\Certmap.dll"
+
+CLEAN :
+ -@erase "$(INTDIR)\init.obj"
+ -@erase "$(INTDIR)\plugin.obj"
+ -@erase "$(INTDIR)\vc40.idb"
+ -@erase "$(INTDIR)\vc40.pdb"
+ -@erase "$(OUTDIR)\Certmap.dll"
+ -@erase "$(OUTDIR)\Certmap.exp"
+ -@erase "$(OUTDIR)\Certmap.ilk"
+ -@erase "$(OUTDIR)\Certmap.lib"
+ -@erase "$(OUTDIR)\Certmap.pdb"
+
+"$(OUTDIR)" :
+ if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)"
+
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+# ADD CPP /nologo /MTd /W3 /Gm /GX /Zi /Od /I "c:\netscape\suitespot\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c
+CPP_PROJ=/nologo /MTd /W3 /Gm /GX /Zi /Od /I "c:\netscape\suitespot\include" /D\
+ "WIN32" /D "_DEBUG" /D "_WINDOWS" /Fp"$(INTDIR)/Certmap.pch" /YX\
+ /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c
+CPP_OBJS=.\Debug/
+CPP_SBRS=.\.
+# ADD BASE MTL /nologo /D "_DEBUG" /win32
+# ADD MTL /nologo /D "_DEBUG" /win32
+MTL_PROJ=/nologo /D "_DEBUG" /win32
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+BSC32_FLAGS=/nologo /o"$(OUTDIR)/Certmap.bsc"
+BSC32_SBRS= \
+
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /dll /debug /machine:I386
+LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\
+ advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\
+ odbccp32.lib /nologo /subsystem:windows /dll /incremental:yes\
+ /pdb:"$(OUTDIR)/Certmap.pdb" /debug /machine:I386 /out:"$(OUTDIR)/Certmap.dll"\
+ /implib:"$(OUTDIR)/Certmap.lib"
+LINK32_OBJS= \
+ "$(INTDIR)\init.obj" \
+ "$(INTDIR)\plugin.obj" \
+ "C:\Netscape\SuiteSpot\lib\nsldap32v10.lib"
+
+"$(OUTDIR)\Certmap.dll" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS)
+ $(LINK32) @<<
+ $(LINK32_FLAGS) $(LINK32_OBJS)
+<<
+
+!ENDIF
+
+.c{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_OBJS)}.obj:
+ $(CPP) $(CPP_PROJ) $<
+
+.c{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cpp{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+.cxx{$(CPP_SBRS)}.sbr:
+ $(CPP) $(CPP_PROJ) $<
+
+################################################################################
+# Begin Target
+
+# Name "Certmap - Win32 Release"
+# Name "Certmap - Win32 Debug"
+
+!IF "$(CFG)" == "Certmap - Win32 Release"
+
+!ELSEIF "$(CFG)" == "Certmap - Win32 Debug"
+
+!ENDIF
+
+################################################################################
+# Begin Source File
+
+SOURCE=.\plugin.c
+DEP_CPP_PLUGI=\
+ ".\plugin.h"\
+ "c:\netscape\suitespot\include\certmap.h"\
+ "c:\netscape\suitespot\include\lber.h"\
+ "c:\netscape\suitespot\include\ldap.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+
+"$(INTDIR)\plugin.obj" : $(SOURCE) $(DEP_CPP_PLUGI) "$(INTDIR)"
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=.\init.c
+DEP_CPP_INIT_=\
+ ".\plugin.h"\
+ "c:\netscape\suitespot\include\certmap.h"\
+ "c:\netscape\suitespot\include\lber.h"\
+ "c:\netscape\suitespot\include\ldap.h"\
+ {$(INCLUDE)}"\sys\types.h"\
+
+
+"$(INTDIR)\init.obj" : $(SOURCE) $(DEP_CPP_INIT_) "$(INTDIR)"
+
+
+# End Source File
+################################################################################
+# Begin Source File
+
+SOURCE=C:\Netscape\SuiteSpot\lib\nsldap32v10.lib
+
+!IF "$(CFG)" == "Certmap - Win32 Release"
+
+!ELSEIF "$(CFG)" == "Certmap - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# End Target
+# End Project
+################################################################################
diff --git a/lib/ldaputil/examples/Makefile b/lib/ldaputil/examples/Makefile
new file mode 100644
index 00000000..4e8b1b4e
--- /dev/null
+++ b/lib/ldaputil/examples/Makefile
@@ -0,0 +1,91 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Makefile for certmap example program.
+#
+
+#
+# Please set the ARCH variable to one of the following:
+# SOLARIS, IRIX, HPUX
+#
+ARCH =
+
+
+#
+# Please set the SROOT to be same as your server root
+#
+SROOT =
+
+#
+# Uncomment the following if you need the debug build
+#
+#COMMON_DEFS = -g
+
+ifndef ARCH
+arch:
+ @echo "Please edit the Makefile and set the variable: ARCH"
+ @exit 1
+endif
+
+ifndef SROOT
+sroot:
+ @echo "Please edit the Makefile and set the server root variable: SROOT"
+ @exit 1
+endif
+
+ifeq ($(ARCH), SOLARIS)
+CC_CMD = cc -DSOLARIS -D_REENTRANT
+LD_SHAREDCMD = ld -G
+endif
+
+ifeq ($(ARCH), IRIX)
+CC_CMD = cc
+LD_SHAREDCMD = ld -32 -shared
+endif
+
+ifeq ($(ARCH), HPUX)
+ BIN = certmap.sl
+else
+ BIN = certmap.so
+endif
+
+OBJS = init.o plugin.o
+
+INCLUDE_FLAGS=-I. -I$(SROOT)/include
+
+INC_FILES = \
+ $(SROOT)/include/certmap.h \
+ $(SROOT)/include/ldap.h \
+ $(SROOT)/include/lber.h
+
+all: $(BIN)
+
+$(INC_FILES):
+ @echo
+ @echo "To extend the Certificate to LDAP entry mapping by"
+ @echo "writing your own functions, you need to download the"
+ @echo "Certmap API (version 1.0) and LDAP SDK (version 1.0)."
+ @echo "Please download these from http://???"
+ @echo "Make sure the following files exist:"
+ @echo "\t$(SROOT)/include/certmap.h"
+ @echo "\t$(SROOT)/include/ldap.h"
+ @echo "\t$(SROOT)/include/lber.h"
+ @echo
+ @exit 1
+
+$(BIN): $(INC_FILES) $(OBJS)
+ $(LD_SHAREDCMD) $(OBJS) -o $@ $(EXTRA_LDDEFINES)
+
+certmap.dll: $(OBJS)
+ $(LD_SHAREDCMD) $(OBJS) -o $@ $(EXTRA_LDDEFINES)
+
+.c.o:
+ $(CC_CMD) $(COMMON_DEFS) $(INCLUDE_FLAGS) -c $<
+
+clean:
+ rm -f $(OBJS) certmap.so $(EXTRA_CLEAN)
diff --git a/lib/ldaputil/examples/README b/lib/ldaputil/examples/README
new file mode 100644
index 00000000..626ef2c9
--- /dev/null
+++ b/lib/ldaputil/examples/README
@@ -0,0 +1,97 @@
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+This directory contains an example program to demonstrate
+writing plugins using the "Certificate to LDAP Mapping" API.
+Please read the "Managing Netscape Servers" manual to find out
+about how certificate to ldap mapping can be configured using
+the <ServerRoot>/userdb/certmap.conf file. Also refer to the
+"Certificate to LDAP Mapping API" documentation to find out
+about the various API functions and how you can write your
+plugin.
+
+This example demonstrate use of most of the API functions. It
+defines a mapping function, a search function, and a verify
+function. Read the API doc to learn about these functions.
+The init.c file also contains an init function which sets the
+mapping, search and verify functions.
+
+The Mapping Function
+--------------------
+
+The mapping function extracts the attributes "CN", "E", "O" and
+"C" from the certificate's subject DN using the function
+ldapu_get_cert_ava_val. If the attributes "C" doesn't exists
+then it defaults to "US". It then gets the value of a custom
+certmap.conf property "defaultOU" using the function
+ldapu_certmap_info_attrval. This demonstrates how you can have
+your own custom properties defined in the certmap.conf file.
+The mapping function then returns an ldapdn of the form:
+"cn=<name>, ou=<defaultOU>, o=<o>, c=<c>".
+
+If the "E" attribute has a value, it returns a filter
+"mail=<e>". Finally, the mapping function frees the structures
+returned by some of the API functions it called.
+
+
+The Search Function
+-------------------
+
+The search function calls a dummy function to get the
+certificate's serial number. It then does a subtree search in
+the entire directory for the filter
+"certSerialNumber=<serial No.>". If this fails, it calls the
+default search function. This demonstrates how you can use the
+default functions in your custom functions.
+
+The Verify Function
+-------------------
+
+The verify function returns LDAPU_SUCCESS if only one entry was
+returned by the search function. Otherwise, it returns
+LDAPU_CERT_VERIFY_FUNCTION_FAILED.
+
+
+Error Reporting
+---------------
+
+To report errors/warning, there is a function defined called
+plugin_ereport. This function demonstrates how to get the
+subject DN and the issuer DN from the certificate.
+
+Build Procedure
+---------------
+On UNIX: Edit the Makefile, and set the variables ARCH & SROOT
+according to the comments in the Makefile. Download LDAP SDK
+from the Netscape's DevEdge site and make the ldap include
+files available in <SROOT>/include. Copy the
+../include/certmap.h file to the <SROOT>/include directory.
+Use 'gmake' to build the plugin. A shared library plugin.so
+(plugin.sl on HP) will be created in the current directory.
+
+On NT: Execute the following command:
+NMAKE /f "Certmap.mak" CFG="Certmap - Win32 Debug"
+Certmap.dll will be created in the Debug subdirectory.
+
+Certmap.conf Configuration
+--------------------------
+Save a copy of certmap.conf file.
+Change the certmap.conf file as follows:
+
+certmap default default
+default:defaultOU marketing
+default:library <path to the shared library>
+default:InitFn plugin_init_fn
+
+
+After experimenting with this example, restore the old copy of
+certmap.conf file. Or else, set the certmap.conf file as follows:
+
+certmap default default
+default:DNComps
+default:FilterComps e, mail, uid
+default:VerifyCert on
diff --git a/lib/ldaputil/examples/init.c b/lib/ldaputil/examples/init.c
new file mode 100644
index 00000000..fc606dd9
--- /dev/null
+++ b/lib/ldaputil/examples/init.c
@@ -0,0 +1,40 @@
+/** 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 <string.h>
+#include <ctype.h>
+
+#include "certmap.h" /* Public Certmap API */
+#include "plugin.h" /* must define extern "C" functions */
+
+
+NSAPI_PUBLIC int plugin_init_fn (void *certmap_info, const char *issuerName,
+ const char *issuerDN, const char *libname)
+{
+ static int initialized = 0;
+ int rv;
+
+ /* Make sure CertmapDLLInit is initialized only once */
+ if (!initialized) {
+#ifdef WIN32
+ CertmapDLLInit(rv, libname);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+#endif
+ initialized = 1;
+ }
+
+ fprintf(stderr, "plugin_init_fn called.\n");
+ ldapu_set_cert_mapfn(issuerDN, plugin_mapping_fn);
+ ldapu_set_cert_verifyfn(issuerDN, plugin_verify_fn);
+
+ if (!default_searchfn)
+ default_searchfn = ldapu_get_cert_searchfn(issuerDN);
+
+ ldapu_set_cert_searchfn(issuerDN, plugin_search_fn);
+ return LDAPU_SUCCESS;
+}
diff --git a/lib/ldaputil/examples/plugin.c b/lib/ldaputil/examples/plugin.c
new file mode 100644
index 00000000..4e4adfaf
--- /dev/null
+++ b/lib/ldaputil/examples/plugin.c
@@ -0,0 +1,239 @@
+/** 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 <string.h>
+#include <ctype.h>
+
+#include "certmap.h" /* Public Certmap API */
+#include "plugin.h" /* must define extern "C" functions */
+
+#ifdef WIN32
+CertmapDLLInitFnTbl /* Initialize Certmap Function Table */
+#endif
+
+CertSearchFn_t default_searchfn = 0;
+
+
+/* plugin_ereport -
+ This function prints an error message to stderr. It prints the issuerDN
+ and subjectDN alongwith the given message.
+ */
+static void plugin_ereport (const char *msg, void *cert)
+{
+ int rv;
+ char *subjectDN;
+ char *issuerDN;
+ char *default_subjectDN = "Failed to get the subject DN";
+ char *default_issuerDN = "Failed to get the issuer DN";
+
+ rv = ldapu_get_cert_subject_dn(cert, &subjectDN);
+
+ if (rv != LDAPU_SUCCESS || !subjectDN) {
+ subjectDN = default_subjectDN;
+ }
+
+ rv = ldapu_get_cert_issuer_dn(cert, &issuerDN);
+
+ if (rv != LDAPU_SUCCESS || !issuerDN) {
+ issuerDN = default_issuerDN;
+ }
+
+ fprintf(stderr, "%s. Issuer: %s, Subject: %s\n", msg, issuerDN,
+ subjectDN);
+
+ if (default_subjectDN != subjectDN) ldapu_free(subjectDN);
+ if (default_issuerDN != issuerDN) ldapu_free(issuerDN);
+}
+
+
+/* plugin_mapping_fn -
+ This mapping function extracts "CN", "O" and "C" attributes from the
+ subject DN to form ldapDN. It inserts "ou=<defaultOU>" between the
+ "CN" and the "O" attr-value pair. The <defaultOU> can be configured in
+ the certmap.conf config file.
+ If the "C" attr is absent, it defaults to "US".
+ It extracts the "E" attribute to form the filter.
+ */
+int plugin_mapping_fn (void *cert, LDAP *ld, void *certmap_info,
+ char **ldapDN, char **filter)
+{
+ char **cn_val; /* get this from the cert */
+ char **o_val; /* get this from the cert */
+ char **c_val; /* get this from the cert */
+ char **e_val; /* get this from the cert */
+ char *ou_val; /* get this from the config file */
+ int len;
+ int rv;
+
+ fprintf(stderr, "plugin_mapping_fn called.\n");
+
+ rv = ldapu_get_cert_ava_val(cert, LDAPU_SUBJECT_DN, "CN", &cn_val);
+
+ if (rv != LDAPU_SUCCESS || !cn_val) {
+ plugin_ereport("plugin_mapping_fn: Failed to extract \"CN\" from the cert", cert);
+ return LDAPU_CERT_MAP_FUNCTION_FAILED;
+ }
+
+ rv = ldapu_get_cert_ava_val(cert, LDAPU_SUBJECT_DN, "O", &o_val);
+
+ if (rv != LDAPU_SUCCESS || !o_val) {
+ plugin_ereport("plugin_mapping_fn: Failed to extract \"O\" from the cert", cert);
+ return LDAPU_CERT_MAP_FUNCTION_FAILED;
+ }
+
+ rv = ldapu_get_cert_ava_val(cert, LDAPU_SUBJECT_DN, "C", &c_val);
+
+ if (rv != LDAPU_SUCCESS || !c_val) {
+ plugin_ereport("plugin_mapping_fn: Failed to extract \"C\" from the cert", cert);
+ }
+
+ rv = ldapu_get_cert_ava_val(cert, LDAPU_SUBJECT_DN, "E", &e_val);
+
+ if (rv != LDAPU_SUCCESS || !e_val) {
+ /* Don't return error -- just print the warning */
+ plugin_ereport("plugin_mapping_fn: Failed to extract \"E\" from the cert", cert);
+ }
+
+ /* Get the "OU" from the "defaultOU" property from the config file */
+ rv = ldapu_certmap_info_attrval(certmap_info, "defaultOU", &ou_val);
+
+ if (rv != LDAPU_SUCCESS || !ou_val) {
+ plugin_ereport("plugin_mapping_fn: Failed to get \"defaultOU\" from the configuration", cert);
+ return LDAPU_CERT_MAP_FUNCTION_FAILED;
+ }
+
+ len = strlen("cn=, ou=, o=, c=") + strlen(cn_val[0]) + strlen(ou_val) +
+ strlen(o_val[0]) + (c_val ? strlen(c_val[0]) : strlen("US")) + 1;
+ *ldapDN = (char *)ldapu_malloc(len);
+
+ if (!*ldapDN) {
+ plugin_ereport("plugin_mapping_fn: Ran out of memory", cert);
+ return LDAPU_CERT_MAP_FUNCTION_FAILED;
+ }
+
+ if (e_val) {
+ len = strlen("mail=") + strlen(e_val[0]) + 1;
+ *filter = (char *)ldapu_malloc(len);
+
+ if (!*filter) {
+ free(*ldapDN);
+ plugin_ereport("plugin_mapping_fn: Ran out of memory", cert);
+ return LDAPU_CERT_MAP_FUNCTION_FAILED;
+ }
+ sprintf(*filter, "mail=%s", e_val[0]);
+ }
+ else {
+ *filter = 0;
+ }
+
+ sprintf(*ldapDN, "cn=%s, ou=%s, o=%s, c=%s", cn_val[0], ou_val,
+ o_val[0], c_val ? c_val[0] : "US");
+
+ ldapu_free_cert_ava_val(cn_val);
+ ldapu_free_cert_ava_val(o_val);
+ ldapu_free_cert_ava_val(c_val);
+ ldapu_free_cert_ava_val(e_val);
+ ldapu_free(ou_val);
+
+ fprintf(stderr, "plugin_mapping_fn Returned:\n\tldapDN: \"%s\"\n\tfilter: \"%s\"\n",
+ *ldapDN, *filter ? *filter : "<NULL>");
+
+ return LDAPU_SUCCESS;
+}
+
+
+int plugin_cert_serial_number (void *cert)
+{
+ /* Just a stub function. You can get the DER encoded cert by using the
+ function ldapu_get_cert_der:
+ */
+ unsigned char *derCert;
+ unsigned int len;
+ int rv;
+ int sno;
+
+ rv = ldapu_get_cert_der(cert, &derCert, &len);
+
+ /* extract the serial number from derCert */
+ sno = 43534754; /* a fake value for now */
+
+ ldapu_free((char *)derCert);
+
+ return sno;
+}
+
+/* plugin_search_fn -
+ This function first does a search based on the cert's serial number.
+ If that fails, it calls the default search function.
+ */
+int plugin_search_fn (void *cert, LDAP *ld, void *certmap_info,
+ const char *suffix,
+ const char *ldapdn, const char *filter,
+ const char **attrs, LDAPMessage **res)
+{
+ int rv;
+ char snoFilter[256];
+
+ fprintf(stderr, "plugin_search_fn called.\n");
+ sprintf(snoFilter, "certSerialNumber=%d",
+ plugin_cert_serial_number(cert));
+
+ /* Search the entire LDAP tree for "certSerialNumber=<serial No.>" */
+ rv = ldap_search_s(ld, suffix, LDAP_SCOPE_SUBTREE, snoFilter,
+ (char **)attrs, 0, res);
+
+ /* ldap_search_s returns LDAP_SUCCESS (rather than LDAPU_SUCCESS)
+ if there is no error but there may not be any matching entries.
+ */
+ if (rv == LDAP_SUCCESS) {
+ /* There was no error but check if any entries matched */
+ int numEntries = ldap_count_entries(ld, *res);
+
+ if (numEntries > 0) {
+ /* at least one entry matched */
+ /* change the return value to LDAPU_SUCCESS from LDAP_SUCCESS */
+ rv = LDAPU_SUCCESS;
+ }
+ else {
+ /* Try the default search function */
+ rv = (*default_searchfn)(cert, ld, certmap_info, suffix, ldapdn,
+ filter, attrs, res);
+ }
+ }
+
+ /* It's ok to return the error code from ldap_search_s */
+ return rv;
+}
+
+/*
+ plugin_verify_fn -
+ This function returns success if only one entry exists in 'res'.
+ */
+int plugin_verify_fn (void *cert, LDAP *ld, void *certmap_info,
+ LDAPMessage *res, LDAPMessage **entry)
+{
+ int rv;
+ int numEntries;
+
+ fprintf(stderr, "plugin_verify_fn called.\n");
+ numEntries = ldap_count_entries(ld, res);
+
+ if (numEntries == 1) {
+ *entry = ldap_first_entry(ld, res);
+ rv = LDAPU_SUCCESS;
+ }
+ else {
+ plugin_ereport("plugin_verify_fn: Failing because multiple entries matched.",
+ cert);
+ *entry = 0;
+ rv = LDAPU_CERT_VERIFY_FUNCTION_FAILED;
+ }
+
+ return rv;
+}
+
+
diff --git a/lib/ldaputil/examples/plugin.h b/lib/ldaputil/examples/plugin.h
new file mode 100644
index 00000000..f73ab377
--- /dev/null
+++ b/lib/ldaputil/examples/plugin.h
@@ -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 **/
+#ifndef _CERTMAP_PLUGIN_H
+#define _CERTMAP_PLUGIN_H
+
+extern CertSearchFn_t default_searchfn;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int plugin_mapping_fn (void *cert, LDAP *ld, void *certmap_info,
+ char **ldapDN, char **filter);
+
+extern int plugin_search_fn (void *cert, LDAP *ld, void *certmap_info,
+ const char *basedn,
+ const char *dn, const char *filter,
+ const char **attrs, LDAPMessage **res);
+
+extern int plugin_verify_fn (void *cert, LDAP *ld, void *certmap_info,
+ LDAPMessage *res, LDAPMessage **entry);
+
+NSAPI_PUBLIC int plugin_init_fn (void *certmap_info, const char *issuerName,
+ const char *issuerDN, const char *dllname);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CERTMAP_PLUGIN_H */
diff --git a/lib/ldaputil/init.c b/lib/ldaputil/init.c
new file mode 100644
index 00000000..8c403e77
--- /dev/null
+++ b/lib/ldaputil/init.c
@@ -0,0 +1,185 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <string.h>
+#include <prlink.h>
+#include <prio.h>
+
+/*#include "base/file.h"*/
+#include "ldaputil/certmap.h"
+/*#include "ldaputil/ldapdb.h"*/
+#include "ldaputil/ldaputil.h"
+#include "ldaputil/cert.h"
+#include "ldaputil/errors.h"
+#include "ldaputil/init.h"
+
+#ifdef XP_WIN32
+#define DLL_SUFFIX ".dll"
+#ifndef FILE_PATHSEP
+#define FILE_PATHSEP '\\'
+#endif
+#else
+#ifndef FILE_PATHSEP
+#define FILE_PATHSEP '/'
+#endif
+#ifdef HPUX
+#define DLL_SUFFIX ".sl"
+#else
+#define DLL_SUFFIX ".so"
+#endif
+#endif
+
+static int load_server_libs (const char *dir)
+{
+ int rv = LDAPU_SUCCESS;
+ PRDir* ds;
+ int suffix_len = strlen(DLL_SUFFIX);
+
+ if ((ds = PR_OpenDir(dir)) != NULL) {
+ PRDirEntry *d;
+
+ /* Dir exists */
+ while( (d = PR_ReadDir(ds, PR_SKIP_BOTH)) ) {
+ PRLibrary *lib = 0;
+ char *libname = d->name;
+ int len = strlen(libname);
+ int is_lib;
+
+ is_lib = (len > suffix_len && !strcmp(libname+len-suffix_len,
+ DLL_SUFFIX));
+
+ if(is_lib) {
+ char path[1024];
+
+ sprintf(path, "%s%c%s", dir, FILE_PATHSEP, libname);
+ lib = PR_LoadLibrary(path);
+ if (!lib) rv = LDAPU_ERR_UNABLE_TO_LOAD_PLUGIN;
+ }
+ }
+ }
+ else {
+ /* It's ok if dir doesn't exists */
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldaputil_init (const char *config_file,
+ const char *dllname,
+ const char *serv_root,
+ const char *serv_type,
+ const char *serv_id)
+{
+ int rv = LDAPU_SUCCESS;
+ static int initialized = 0;
+
+ /* If already initialized, cleanup the old structures */
+ if (initialized) ldaputil_exit();
+
+ if (config_file && *config_file) {
+ char dir[1024];
+
+ LDAPUCertMapListInfo_t *certmap_list;
+ LDAPUCertMapInfo_t *certmap_default;
+
+ if (serv_root && *serv_root) {
+ /* Load common libraries */
+ sprintf(dir, "%s%clib%c%s", serv_root, FILE_PATHSEP,
+ FILE_PATHSEP, "common");
+ rv = load_server_libs(dir);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ if (serv_type && *serv_type) {
+ /* Load server type specific libraries */
+ sprintf(dir, "%s%clib%c%s", serv_root, FILE_PATHSEP,
+ FILE_PATHSEP, serv_type);
+ rv = load_server_libs(dir);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ if (serv_id && *serv_id) {
+ /* Load server instance specific libraries */
+ sprintf(dir, "%s%clib%c%s", serv_root, FILE_PATHSEP,
+ FILE_PATHSEP, serv_id);
+ rv = load_server_libs(dir);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+ }
+ }
+ }
+
+ rv = ldapu_certmap_init (config_file, dllname, &certmap_list,
+ &certmap_default);
+ }
+
+ initialized = 1;
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ return rv;
+}
+
+static LDAPUDispatchVector_t __ldapu_vector = {
+ ldapu_cert_to_ldap_entry,
+ ldapu_set_cert_mapfn,
+ ldapu_get_cert_mapfn,
+ ldapu_set_cert_searchfn,
+ ldapu_get_cert_searchfn,
+ ldapu_set_cert_verifyfn,
+ ldapu_get_cert_verifyfn,
+ ldapu_get_cert_subject_dn,
+ ldapu_get_cert_issuer_dn,
+ ldapu_get_cert_ava_val,
+ ldapu_free_cert_ava_val,
+ ldapu_get_cert_der,
+ ldapu_issuer_certinfo,
+ ldapu_certmap_info_attrval,
+ ldapu_err2string,
+ ldapu_free_old,
+ ldapu_malloc,
+ ldapu_strdup,
+ ldapu_free
+};
+
+#ifdef XP_UNIX
+LDAPUDispatchVector_t *__ldapu_table = &__ldapu_vector;
+#endif
+
+#if 0
+NSAPI_PUBLIC int CertMapDLLInitFn(LDAPUDispatchVector_t **table)
+{
+ *table = &__ldapu_vector;
+}
+#endif
+
+NSAPI_PUBLIC int CertMapDLLInitFn(LDAPUDispatchVector_t **table)
+{
+ *table = (LDAPUDispatchVector_t *)malloc(sizeof(LDAPUDispatchVector_t));
+
+ if (!*table) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ (*table)->f_ldapu_cert_to_ldap_entry = ldapu_cert_to_ldap_entry;
+ (*table)->f_ldapu_set_cert_mapfn = ldapu_set_cert_mapfn;
+ (*table)->f_ldapu_get_cert_mapfn = ldapu_get_cert_mapfn;
+ (*table)->f_ldapu_set_cert_searchfn = ldapu_set_cert_searchfn;
+ (*table)->f_ldapu_get_cert_searchfn = ldapu_get_cert_searchfn;
+ (*table)->f_ldapu_set_cert_verifyfn = ldapu_set_cert_verifyfn;
+ (*table)->f_ldapu_get_cert_verifyfn = ldapu_get_cert_verifyfn;
+ (*table)->f_ldapu_get_cert_subject_dn = ldapu_get_cert_subject_dn;
+ (*table)->f_ldapu_get_cert_issuer_dn = ldapu_get_cert_issuer_dn;
+ (*table)->f_ldapu_get_cert_ava_val = ldapu_get_cert_ava_val;
+ (*table)->f_ldapu_free_cert_ava_val = ldapu_free_cert_ava_val;
+ (*table)->f_ldapu_get_cert_der = ldapu_get_cert_der;
+ (*table)->f_ldapu_issuer_certinfo = ldapu_issuer_certinfo;
+ (*table)->f_ldapu_certmap_info_attrval = ldapu_certmap_info_attrval;
+ (*table)->f_ldapu_err2string = ldapu_err2string;
+ (*table)->f_ldapu_free_old = ldapu_free_old;
+ (*table)->f_ldapu_malloc = ldapu_malloc;
+ (*table)->f_ldapu_strdup = ldapu_strdup;
+ (*table)->f_ldapu_free = ldapu_free;
+ return LDAPU_SUCCESS;
+}
diff --git a/lib/ldaputil/ldapauth.c b/lib/ldaputil/ldapauth.c
new file mode 100644
index 00000000..d8088269
--- /dev/null
+++ b/lib/ldaputil/ldapauth.c
@@ -0,0 +1,1099 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * ldapauth.cpp: Implements LDAP integration in the web server.
+ *
+ * Nitin More, John Kristian
+ */
+
+/* #define DBG_PRINT */
+
+#include <stdio.h> /* for BUFSIZ */
+#include <string.h> /* for strncpy, strcat */
+#include <ldap.h>
+
+#include <ldaputil/certmap.h>
+#include <ldaputil/errors.h>
+#include <ldaputil/ldapauth.h>
+
+#include <ldaputili.h>
+
+/* If we are not interested in the returned attributes, just ask for one
+ * attribute in the call to ldap_search. Also don't ask for the attribute
+ * value -- just the attr.
+ */
+static const char *default_search_attrs[] = { "c" , 0 };
+static int default_search_attrsonly = 1;
+
+/*
+ * ldapu_find
+ * Description:
+ * Caller should free res if it is not NULL.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * base basedn (where to start the search)
+ * scope scope for the search. One of
+ * LDAP_SCOPE_SUBTREE, LDAP_SCOPE_ONELEVEL, and
+ * LDAP_SCOPE_BASE
+ * filter LDAP filter
+ * attrs A NULL-terminated array of strings indicating which
+ * attributes to return for each matching entry. Passing
+ * NULL for this parameter causes all available
+ * attributes to be retrieved.
+ * attrsonly A boolean value that should be zero if both attribute
+ * types and values are to be returned, non-zero if only
+ * types are wanted.
+ * res A result parameter which will contain the results of
+ * the search upon completion of the call.
+ * Return Values:
+ * LDAPU_SUCCESS if entry is found
+ * LDAPU_FAILED if entry is not found
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_find (LDAP *ld, const char *base, int scope,
+ const char *filter, const char **attrs,
+ int attrsonly, LDAPMessage **res)
+{
+ int retval;
+#ifdef USE_THIS_CODE /* ASYNCHRONOUS */
+ int msgid;
+#endif
+ int numEntries;
+
+ *res = 0;
+
+ /* If base is NULL set it to null string */
+ if (!base) {
+ DBG_PRINT1("ldapu_find: basedn is missing -- assuming null string\n");
+ base = "";
+ }
+
+ if (!filter || !*filter) {
+ DBG_PRINT1("ldapu_find: filter is missing -- assuming objectclass=*\n");
+ filter = ldapu_strings[LDAPU_STR_FILTER_DEFAULT];
+ }
+
+ DBG_PRINT2("\tbase:\t\"%s\"\n", base);
+ DBG_PRINT2("\tfilter:\t\"%s\"\n", filter ? filter : "<NULL>");
+ DBG_PRINT2("\tscope:\t\"%s\"\n",
+ (scope == LDAP_SCOPE_SUBTREE ? "LDAP_SCOPE_SUBTREE"
+ : (scope == LDAP_SCOPE_ONELEVEL ? "LDAP_SCOPE_ONELEVEL"
+ : "LDAP_SCOPE_BASE")));
+
+ retval = ldapu_search_s(ld, base, scope, filter, (char **)attrs,
+ attrsonly, res);
+
+ if (retval != LDAP_SUCCESS)
+ {
+ /* retval = ldap_result2error(ld, *res, 0); */
+ DBG_PRINT2("ldapu_search_s: %s\n", ldapu_err2string(retval));
+ return(retval);
+ }
+
+ numEntries = ldapu_count_entries(ld, *res);
+
+ if (numEntries == 1) {
+ /* success */
+ return LDAPU_SUCCESS;
+ }
+ else if (numEntries == 0) {
+ /* not found -- but not an error */
+ DBG_PRINT1("ldapu_search_s: Entry not found\n");
+ return LDAPU_FAILED;
+ }
+ else if (numEntries > 0) {
+ /* Found more than one entry! */
+ DBG_PRINT1("ldapu_search_s: Found more than one entry\n");
+ return LDAPU_ERR_MULTIPLE_MATCHES;
+ }
+ else {
+ /* should never get here */
+ DBG_PRINT1("ldapu_search_s: should never reach here\n");
+ ldapu_msgfree(ld, *res);
+ return LDAP_OPERATIONS_ERROR;
+ }
+}
+
+
+/* Search function for the cases where base = "" = NULL suffix, that is, search to
+ * be performed on the entire DIT tree.
+ * We actually do various searches taking a naming context at a time as the base for
+ * the search. */
+
+int ldapu_find_entire_tree (LDAP *ld, int scope,
+ const char *filter, const char **attrs,
+ int attrsonly, LDAPMessage ***res)
+{
+ int retval = LDAPU_FAILED;
+ int rv,i, num_namingcontexts;
+ LDAPMessage *result_entry, *result = NULL;
+ const char *suffix_attr[2] = {"namingcontexts", NULL};
+ /* these are private suffixes that may contain pseudo users
+ e.g. replication manager that may have certs */
+ int num_private_suffix = 1;
+ const char *private_suffix_list[2] = {"cn=config", NULL};
+ char **suffix_list, **suffix = NULL;
+
+ rv = ldapu_find(ld, "",LDAP_SCOPE_BASE, "objectclass=*", suffix_attr, 0, &result);
+ if (rv != LDAP_SUCCESS) {
+ if (result) ldapu_msgfree(ld, result);
+ return rv;
+ }
+
+ result_entry = ldapu_first_entry(ld, result);
+ suffix = ldapu_get_values(ld, result_entry, suffix_attr[0]);
+ suffix_list = suffix;
+ num_namingcontexts = ldap_count_values(suffix);
+ /* add private suffixes to our list of suffixes to search */
+ if (num_private_suffix) {
+ suffix_list = ldapu_realloc(suffix_list,
+ sizeof(char *)*(num_namingcontexts+num_private_suffix+1));
+ if (!suffix_list) {
+ if (result) {
+ ldapu_msgfree(ld, result);
+ }
+ retval = LDAPU_FAILED;
+ return retval;
+ }
+ for (i = num_namingcontexts; i < (num_namingcontexts+num_private_suffix); ++i) {
+ suffix_list[i] = strdup(private_suffix_list[i-num_namingcontexts]);
+ }
+ suffix_list[i] = NULL;
+ num_namingcontexts += num_private_suffix;
+ suffix = suffix_list;
+ }
+ if (result) ldapu_msgfree(ld, result);
+ result = 0;
+ i = 0;
+
+ /* ugaston - the caller function must remember to free the memory allocated here */
+ *res = (LDAPMessage **) ldapu_malloc((num_namingcontexts + 1) * sizeof(LDAPMessage *));
+ while (suffix && *suffix) {
+ rv = ldapu_find(ld, *suffix, scope, filter, attrs, attrsonly, &result);
+ if (scope == LDAP_SCOPE_BASE && rv == LDAP_SUCCESS) {
+ retval = rv;
+ (*res)[i++] = result;
+ break;
+ }
+
+ switch (rv) {
+ case LDAP_SUCCESS:
+ if (retval == LDAP_SUCCESS) {
+ retval = LDAPU_ERR_MULTIPLE_MATCHES;
+ (*res)[i++] = result;
+ break;
+ }
+ case LDAPU_ERR_MULTIPLE_MATCHES:
+ retval = rv;
+ (*res)[i++] = result;
+ break;
+ default:
+ if (retval != LDAP_SUCCESS && retval != LDAPU_ERR_MULTIPLE_MATCHES) {
+ retval = rv;
+ }
+ if (result) ldapu_msgfree(ld, result);
+ result = 0;
+ break;
+ }
+
+ suffix++;
+ }
+
+ (*res)[i] = NULL;
+ ldapu_value_free(ld, suffix_list);
+ return retval;
+}
+
+
+
+/*
+ * ldapu_find_uid_attrs
+ * Description:
+ * Maps the given uid to a user dn. Caller should free res if it is not
+ * NULL. Accepts the attrs & attrsonly args.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * uid User's name
+ * base basedn (where to start the search)
+ * attrs list of attributes to retrieve
+ * attrsonly flag indicating if attr values are to be retrieved
+ * res A result parameter which will contain the results of
+ * the search upon completion of the call.
+ * Return Values:
+ * LDAPU_SUCCESS if entry is found
+ * LDAPU_FAILED if entry is not found
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_find_uid_attrs (LDAP *ld, const char *uid, const char *base,
+ const char **attrs, int attrsonly,
+ LDAPMessage **res)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ char filter[ BUFSIZ ];
+ int retval;
+
+ /* setup filter as (uid=<uid>) */
+ sprintf(filter, ldapu_strings[LDAPU_STR_FILTER_USER], uid);
+
+ retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, res);
+
+ return retval;
+}
+
+/*
+ * ldapu_find_uid
+ * Description:
+ * Maps the given uid to a user dn. Caller should free res if it is not
+ * NULL.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * uid User's name
+ * base basedn (where to start the search)
+ * res A result parameter which will contain the results of
+ * the search upon completion of the call.
+ * Return Values:
+ * LDAPU_SUCCESS if entry is found
+ * LDAPU_FAILED if entry is not found
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_find_uid (LDAP *ld, const char *uid, const char *base,
+ LDAPMessage **res)
+{
+ const char **attrs = 0; /* get all attributes ... */
+ int attrsonly = 0; /* ... and their values */
+ int retval;
+
+ retval = ldapu_find_uid_attrs(ld, uid, base, attrs, attrsonly, res);
+
+ return retval;
+}
+
+/*
+ * ldapu_find_userdn
+ * Description:
+ * Maps the given uid to a user dn. Caller should free dn if it is not
+ * NULL.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * uid User's name
+ * base basedn (where to start the search)
+ * dn user dn
+ * Return Values:
+ * LDAPU_SUCCESS if entry is found
+ * LDAPU_FAILED if entry is not found
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_find_userdn (LDAP *ld, const char *uid, const char *base,
+ char **dn)
+{
+ LDAPMessage *res = 0;
+ int retval;
+
+ retval = ldapu_find_uid_attrs(ld, uid, base, default_search_attrs,
+ default_search_attrsonly, &res);
+
+ if (retval == LDAPU_SUCCESS) {
+ LDAPMessage *entry;
+
+ entry = ldapu_first_entry(ld, res);
+ *dn = ldapu_get_dn(ld, entry);
+ }
+ else {
+ *dn = 0;
+ }
+
+ if (res) ldapu_msgfree(ld, res);
+
+ return retval;
+}
+
+/*
+ * ldapu_find_group_attrs
+ * Description:
+ * Maps the given groupid to a group dn. Caller should free res if it is
+ * not NULL. Accepts the attrs & attrsonly args.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * groupid Groups's name
+ * base basedn (where to start the search)
+ * attrs list of attributes to retrieve
+ * attrsonly flag indicating if attr values are to be retrieved
+ * res A result parameter which will contain the results of
+ * the search upon completion of the call.
+ * Return Values:
+ * LDAPU_SUCCESS if entry is found
+ * LDAPU_FAILED if entry is not found
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_find_group_attrs (LDAP *ld, const char *groupid,
+ const char *base, const char **attrs,
+ int attrsonly, LDAPMessage **res)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ char filter[ BUFSIZ ];
+ int retval;
+
+ /* setup the filter */
+ sprintf(filter,
+ ldapu_strings[LDAPU_STR_FILTER_GROUP],
+ groupid);
+
+ retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, res);
+
+ return retval;
+}
+
+/*
+ * ldapu_find_group
+ * Description:
+ * Maps the given groupid to a group dn. Caller should free res if it is
+ * not NULL.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * groupid Groups's name
+ * base basedn (where to start the search)
+ * res A result parameter which will contain the results of
+ * the search upon completion of the call.
+ * Return Values:
+ * LDAPU_SUCCESS if entry is found
+ * LDAPU_FAILED if entry is not found
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_find_group (LDAP *ld, const char *groupid, const char *base,
+ LDAPMessage **res)
+{
+ const char **attrs = 0; /* get all attributes ... */
+ int attrsonly = 0; /* ... and their values */
+ int retval;
+
+ retval = ldapu_find_group_attrs (ld, groupid, base, attrs, attrsonly, res);
+
+ return retval;
+}
+
+/*
+ * ldapu_find_groupdn
+ * Description:
+ * Maps the given groupid to a group dn. Caller should free dn if it is
+ * not NULL.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * groupid Groups's name
+ * base basedn (where to start the search)
+ * dn group dn
+ * Return Values:
+ * LDAPU_SUCCESS if entry is found
+ * LDAPU_FAILED if entry is not found
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_find_groupdn (LDAP *ld, const char *groupid, const char *base,
+ char **dn)
+{
+ LDAPMessage *res = 0;
+ int retval;
+
+ retval = ldapu_find_group_attrs(ld, groupid, base, default_search_attrs,
+ default_search_attrsonly, &res);
+
+ if (retval == LDAPU_SUCCESS) {
+ LDAPMessage *entry;
+
+ /* get ldap entry */
+ entry = ldapu_first_entry(ld, res);
+ *dn = ldapu_get_dn(ld, entry);
+ }
+ else {
+ *dn = 0;
+ }
+
+ if (res) ldapu_msgfree(ld, res);
+
+ return retval;
+}
+
+
+/*
+ * continuable_err
+ * Description:
+ * Returns true for benign errors (i.e. errors for which recursive
+ * search can continue.
+ * Return Values:
+ * 0 (zero) - if not a benign error
+ * 1 - if a benign error -- search can continue.
+ */
+static int continuable_err (int err)
+{
+ return (err == LDAPU_FAILED);
+}
+
+int ldapu_auth_udn_gdn_recurse (LDAP *ld, const char *userdn,
+ const char *groupdn, const char *base,
+ int recurse_cnt)
+{
+ char filter[ BUFSIZ ];
+ const char **attrs = default_search_attrs;
+ int attrsonly = default_search_attrsonly;
+ LDAPMessage *res = 0;
+ int retval;
+ char member_filter[ BUFSIZ ];
+
+ if (recurse_cnt >= 30)
+ return LDAPU_ERR_CIRCULAR_GROUPS;
+
+ /* setup the filter */
+ sprintf(member_filter, ldapu_strings[LDAPU_STR_FILTER_MEMBER], userdn, userdn);
+
+ retval = ldapu_find(ld, groupdn, LDAP_SCOPE_BASE, member_filter, attrs,
+ attrsonly, &res);
+
+ if (res) ldap_msgfree(res);
+
+ if (retval != LDAPU_SUCCESS && continuable_err(retval)) {
+ LDAPMessage *entry;
+
+ DBG_PRINT2("Find parent groups of \"%s\"\n", userdn);
+
+ /* Modify the filter to include the objectclass check */
+ sprintf(filter, ldapu_strings[LDAPU_STR_FILTER_MEMBER_RECURSE],
+ member_filter);
+ retval = ldapu_find(ld, base, LDAP_SCOPE_SUBTREE, filter,
+ attrs, attrsonly, &res);
+
+ if (retval == LDAPU_SUCCESS || retval == LDAPU_ERR_MULTIPLE_MATCHES) {
+ /* Found at least one group the userdn is member of */
+
+ if (!res) {
+ /* this should never happen */
+ retval = LDAPU_ERR_EMPTY_LDAP_RESULT;
+ }
+ else {
+ retval = LDAPU_ERR_MISSING_RES_ENTRY;
+
+ for (entry = ldap_first_entry(ld, res); entry != NULL;
+ entry = ldap_next_entry(ld, entry))
+ {
+ char *dn = ldap_get_dn(ld, entry);
+
+ retval = ldapu_auth_udn_gdn_recurse(ld, dn, groupdn,
+ base, recurse_cnt+1);
+ ldap_memfree(dn);
+
+ if (retval == LDAPU_SUCCESS || !continuable_err(retval)) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (res) ldap_msgfree(res);
+ }
+
+ return retval;
+}
+
+/*
+ * ldapu_auth_userdn_groupdn:
+ * Description:
+ * Checks if the user (userdn) belongs to the given group (groupdn).
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * userdn User's full DN -- actually it could be a group
+ * dn to check subgroup membership.
+ * groupdn Group's full DN
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user is member of the group
+ * LDAPU_FAILED if user is not a member of the group
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_auth_userdn_groupdn (LDAP *ld, const char *userdn,
+ const char *groupdn, const char *base)
+{
+ return ldapu_auth_udn_gdn_recurse(ld, userdn, groupdn, base, 0);
+}
+
+
+/*
+ * ldapu_auth_uid_groupdn:
+ * Description:
+ * Similar to ldapu_auth_userdn_groupdn but first maps the uid to a
+ * full user DN before calling ldapu_auth_userdn_groupdn.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * uid User's login name
+ * groupdn Group's full DN
+ * base basedn (where to start the search)
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user is member of the group
+ * LDAPU_FAILED if user is not a member of the group
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_auth_uid_groupdn (LDAP *ld, const char *uid, const char *groupdn,
+ const char *base)
+{
+ int retval;
+ char *dn;
+
+ /* First find userdn for the given uid and
+ then call ldapu_auth_userdn_groupdn */
+ retval = ldapu_find_userdn(ld, uid, base, &dn);
+
+ if (retval == LDAPU_SUCCESS) {
+
+ retval = ldapu_auth_userdn_groupdn(ld, dn, groupdn, base);
+ ldap_memfree(dn);
+ }
+
+ return retval;
+}
+
+/*
+ * ldapu_auth_uid_groupid:
+ * Description:
+ * Similar to ldapu_auth_uid_groupdn but first maps the groupid to a
+ * full group DN before calling ldapu_auth_uid_groupdn.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * uid User's login name
+ * groupid Group's name
+ * base basedn (where to start the search)
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user is member of the group
+ * LDAPU_FAILED if user is not a member of the group
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_auth_uid_groupid (LDAP *ld, const char *uid,
+ const char *groupid, const char *base)
+{
+ int retval;
+ char *dn;
+
+ /* First find groupdn for the given groupid and
+ then call ldapu_auth_uid_groupdn */
+ retval = ldapu_find_groupdn(ld, groupid, base, &dn);
+
+ if (retval == LDAPU_SUCCESS) {
+ retval = ldapu_auth_uid_groupdn(ld, uid, dn, base);
+ ldapu_memfree(ld, dn);
+ }
+
+ return retval;
+}
+
+/*
+ * ldapu_auth_userdn_groupid:
+ * Description:
+ * Similar to ldapu_auth_userdn_groupdn but first maps the groupid to a
+ * full group DN before calling ldapu_auth_userdn_groupdn.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * userdn User's full DN
+ * groupid Group's name
+ * base basedn (where to start the search)
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user is member of the group
+ * LDAPU_FAILED if user is not a member of the group
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_auth_userdn_groupid (LDAP *ld, const char *userdn,
+ const char *groupid, const char *base)
+{
+ int retval;
+ char *groupdn;
+
+ /* First find groupdn for the given groupid and
+ then call ldapu_auth_userdn_groupdn */
+ retval = ldapu_find_groupdn(ld, groupid, base, &groupdn);
+
+ if (retval == LDAPU_SUCCESS) {
+ retval = ldapu_auth_userdn_groupdn(ld, userdn, groupdn, base);
+ ldap_memfree(groupdn);
+ }
+
+ return retval;
+}
+
+
+LDAPUStr_t *ldapu_str_alloc (const int size)
+{
+ LDAPUStr_t *lstr = (LDAPUStr_t *)ldapu_malloc(sizeof(LDAPUStr_t));
+
+ if (!lstr) return 0;
+ lstr->size = size < 0 ? 1024 : size;
+ lstr->str = (char *)ldapu_malloc(lstr->size*sizeof(char));
+ lstr->len = 0;
+ lstr->str[lstr->len] = 0;
+
+ return lstr;
+}
+
+
+void ldapu_str_free (LDAPUStr_t *lstr)
+{
+ if (lstr) {
+ if (lstr->str) ldapu_free(lstr->str);
+ ldapu_free((void *)lstr);
+ }
+}
+
+
+int ldapu_str_append(LDAPUStr_t *lstr, const char *arg)
+{
+ int arglen = strlen(arg);
+ int len = lstr->len + arglen;
+
+ if (len >= lstr->size) {
+ /* realloc some more */
+ lstr->size += arglen > 4095 ? arglen+1 : 4096;
+ lstr->str = (char *)ldapu_realloc(lstr->str, lstr->size);
+ if (!lstr->str) return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ memcpy((void *)&(lstr->str[lstr->len]), (void *)arg, arglen);
+ lstr->len += arglen;
+ lstr->str[lstr->len] = 0;
+ return LDAPU_SUCCESS;
+}
+
+
+/*
+ * ldapu_auth_userdn_groupids_recurse:
+ * Description:
+ * Checks if the user is member of the given comma separated list of
+ * group names.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * filter filter to use in the search
+ * groupids some representation of group names. Example,
+ * a comma separated names in a string, hash
+ * table, etc. This function doesn't need to
+ * know the name of the groups. It calls the
+ * following function to check if one of the
+ * groups returned by the search is in the list.
+ * grpcmpfn group name comparison function.
+ * base basedn (where to start the search)
+ * recurse_cnt recursion count to detect circular groups
+ * group_out if successful, pointer to the user's group
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user is member of one of the groups
+ * LDAPU_FAILED if user is not a member of the group
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+static int ldapu_auth_userdn_groupids_recurse (LDAP *ld, const char *filter,
+ void *groupids,
+ LDAPU_GroupCmpFn_t grpcmpfn,
+ const char *base,
+ int recurse_cnt,
+ char **group_out)
+{
+ LDAPMessage *res = 0;
+ const char *attrs[] = { "CN", 0 };
+ int attrsonly = 0;
+ LDAPMessage *entry;
+ int rv;
+ int retval;
+ int i;
+ int done;
+
+ if (recurse_cnt >= 30)
+ return LDAPU_ERR_CIRCULAR_GROUPS;
+
+ /* Perform the ldap lookup */
+ retval = ldapu_find(ld, base, LDAP_SCOPE_SUBTREE, filter, attrs,
+ attrsonly, &res);
+
+ if (retval != LDAPU_SUCCESS && retval != LDAPU_ERR_MULTIPLE_MATCHES ) {
+ /* user is not a member of any group */
+ if (res) ldap_msgfree(res);
+ return retval;
+ }
+
+ retval = LDAPU_FAILED;
+ done = 0;
+
+ /* check if one of the matched groups is one of the given groups */
+ for (entry = ldap_first_entry(ld, res); entry != NULL && !done;
+ entry = ldap_next_entry(ld, entry))
+ {
+ struct berval **bvals;
+
+ if ((bvals = ldap_get_values_len(ld, entry, "CN")) == NULL) {
+ /* This shouldn't happen */
+ retval = LDAPU_ERR_MISSING_ATTR_VAL;
+ continue;
+ }
+
+ /* "CN" may have multiple values */
+ /* Check each value of "CN" against the 'groupids' */
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ rv = (*grpcmpfn)(groupids, bvals[i]->bv_val, bvals[i]->bv_len);
+ if (rv == LDAPU_SUCCESS) {
+ char *group = (char *)ldapu_malloc(bvals[i]->bv_len+1);
+
+ if (!group) {
+ retval = LDAPU_ERR_OUT_OF_MEMORY;
+ }
+ else {
+ strncpy(group, bvals[i]->bv_val, bvals[i]->bv_len);
+ group[bvals[i]->bv_len] = 0;
+ *group_out = group;
+ retval = LDAPU_SUCCESS;
+ }
+ done = 1; /* exit from the outer loop too */
+ break;
+ }
+ }
+
+ ldap_value_free_len(bvals);
+ }
+
+ if (retval == LDAPU_FAILED) {
+ /* None of the matched groups is in 'groupids' */
+ /* Perform the nested group membership check */
+ LDAPUStr_t *filter1;
+ LDAPUStr_t *filter2;
+ char *rfilter = 0;
+ int rlen;
+ /* Finally we need a filter which looks like:
+ (| (& (objectclass=groupofuniquenames)
+ (| (uniquemember=<grp1dn>)(uniquemember=<grp2dn>) ...))
+ (& (objectclass=groupofnames)
+ (| (member=<grp1dn>)(member=<grp2dn>) ...)))
+ Construct 2 sub-filters first as follows:
+ (uniquemember=<grp1dn>)(uniquemember=<grp2dn>)... AND
+ (member=<grp1dn>)(member=<grp2dn>)...
+ Then insert them in the main filter.
+ */
+ filter1 = ldapu_str_alloc(1024);
+ filter2 = ldapu_str_alloc(1024);
+ if (!filter1 || !filter2) return LDAPU_ERR_OUT_OF_MEMORY;
+ rv = LDAPU_SUCCESS;
+
+ for (entry = ldap_first_entry(ld, res); entry != NULL;
+ entry = ldap_next_entry(ld, entry))
+ {
+ char *dn = ldap_get_dn(ld, entry);
+ if (((rv = ldapu_str_append(filter1, "(uniquemember="))
+ != LDAPU_SUCCESS) ||
+ ((rv = ldapu_str_append(filter1, dn)) != LDAPU_SUCCESS) ||
+ ((rv = ldapu_str_append(filter1, ")")) != LDAPU_SUCCESS) ||
+ ((rv = ldapu_str_append(filter2, "(member="))
+ != LDAPU_SUCCESS) ||
+ ((rv = ldapu_str_append(filter2, dn)) != LDAPU_SUCCESS) ||
+ ((rv = ldapu_str_append(filter2, ")")) != LDAPU_SUCCESS))
+ {
+ ldap_memfree(dn);
+ break;
+ }
+ ldap_memfree(dn);
+ }
+
+ if (rv != LDAPU_SUCCESS) {
+ /* something went wrong in appending to filter1 or filter2 */
+ ldapu_str_free(filter1);
+ ldapu_str_free(filter2);
+ retval = rv;
+ }
+ else {
+ /* Insert the 2 filters in the main filter */
+ rlen = filter1->len + filter2->len +
+ strlen("(| (& (objectclass=groupofuniquenames)"
+ "(| ))"
+ "(& (objectclass=groupofnames)"
+ "(| )))") + 1;
+ rfilter = (char *)ldapu_malloc(rlen);
+ if (!rfilter) return LDAPU_ERR_OUT_OF_MEMORY;
+ sprintf(rfilter,
+ "(| (& (objectclass=groupofuniquenames)"
+ "(| %s))"
+ "(& (objectclass=groupofnames)"
+ "(| %s)))",
+ filter1->str, filter2->str);
+ ldapu_str_free(filter1);
+ ldapu_str_free(filter2);
+ retval = ldapu_auth_userdn_groupids_recurse(ld, rfilter, groupids,
+ grpcmpfn, base,
+ ++recurse_cnt,
+ group_out);
+ ldapu_free(rfilter);
+ }
+
+ }
+
+ if (res) ldap_msgfree(res);
+ return retval;
+}
+
+/*
+ * ldapu_auth_userdn_groupids:
+ * Description:
+ * Checks if the user is member of the given comma separated list of
+ * group names.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * userdn User's full DN
+ * groupids some representation of group names. Example,
+ * a comma separated names in a string, hash
+ * table, etc. This function doesn't need to
+ * know the name of the groups. It calls the
+ * following function to check if one of the
+ * groups returned by the search is in the list.
+ * grpcmpfn group name comparison function.
+ * base basedn (where to start the search)
+ * group_out if successful, pointer to the user's group
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user is member of one of the groups
+ * LDAPU_FAILED if user is not a member of the group
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_auth_userdn_groupids (LDAP *ld, const char *userdn,
+ void *groupids,
+ LDAPU_GroupCmpFn_t grpcmpfn,
+ const char *base,
+ char **group_out)
+{
+ char *filter;
+ int len;
+ int rv;
+
+ *group_out = 0;
+ /* allocate a big enough filter */
+ /* The filter looks like:
+ (| (& (objectclass=groupofuniquenames)(uniquemember=<userdn>))
+ (& (objectclass=groupofnames)(member=<userdn>)))
+ */
+
+ len = 2 * strlen(userdn) + 1 +
+ strlen("(| (& (objectclass=groupofuniquenames)(uniquemember=))"
+ "(& (objectclass=groupofnames)(member=)))");
+ filter = (char *)ldapu_malloc(len);
+
+ if (!filter) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ sprintf(filter, "(| (& (objectclass=groupofuniquenames)(uniquemember=%s))"
+ "(& (objectclass=groupofnames)(member=%s)))",
+ userdn, userdn);
+
+ rv = ldapu_auth_userdn_groupids_recurse(ld, filter, groupids,
+ grpcmpfn, base,
+ 0, group_out);
+
+ ldapu_free(filter);
+ return rv;
+}
+
+
+/*
+ * ldapu_auth_userdn_attrfilter:
+ * Description:
+ * Checks if the user's entry has the given attributes
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * userdn User's full DN
+ * attrfilter attribute filter
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user is member of the group
+ * LDAPU_FAILED if user is not a member of the group
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_auth_userdn_attrfilter (LDAP *ld, const char *userdn,
+ const char *attrfilter)
+{
+ const char *base = userdn;
+ int scope = LDAP_SCOPE_BASE;
+ const char *filter = attrfilter;
+ const char **attrs = default_search_attrs;
+ int attrsonly = default_search_attrsonly;
+ LDAPMessage *res = 0;
+ int retval;
+
+ retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, &res);
+
+ if (res) ldapu_msgfree(ld, res);
+
+ return retval;
+}
+
+/*
+ * ldapu_auth_uid_attrfilter:
+ * Description:
+ * Checks if the user's entry has the given attributes. First maps
+ the uid to userdn.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * uid User's name
+ * attrfilter attribute filter
+ * base basedn (where to start the search)
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user is member of the group
+ * LDAPU_FAILED if user is not a member of the group
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_auth_uid_attrfilter (LDAP *ld, const char *uid, const char *attrfilter,
+ const char *base)
+{
+ int scope = LDAP_SCOPE_SUBTREE;
+ char filter[ BUFSIZ ];
+ const char **attrs = default_search_attrs;
+ int attrsonly = default_search_attrsonly;
+ LDAPMessage *res = 0;
+ int retval;
+
+ /* setup filter as (& (uid=<uid>) (attrfilter)) */
+ if (*attrfilter == '(')
+ sprintf(filter, "(& (uid=%s) %s)", uid, attrfilter);
+ else
+ sprintf(filter, "(& (uid=%s) (%s))", uid, attrfilter);
+
+ retval = ldapu_find(ld, base, scope, filter, attrs, attrsonly, &res);
+
+ if (res) ldapu_msgfree(ld, res);
+
+ return retval;
+}
+
+/*
+ * ldapu_auth_userdn_password:
+ * Description:
+ * Checks the user's password against LDAP by binding using the
+ * userdn and the password.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * userdn User's full DN
+ * password User's password (clear text)
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user credentials are valid
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_auth_userdn_password (LDAP *ld, const char *userdn, const char *password)
+{
+ LDAPMessage *res = 0;
+ int retval;
+
+ DBG_PRINT2("\tuserdn:\t\"%s\"\n", userdn);
+ DBG_PRINT2("\tpassword:\t\"%s\"\n", password);
+
+ retval = ldap_simple_bind_s(ld, userdn, password);
+
+ if (retval != LDAP_SUCCESS)
+ {
+ DBG_PRINT2("ldap_simple_bind_s: %s\n", ldap_err2string(retval));
+ return(retval);
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+/*
+ * ldapu_auth_uid_password:
+ * Description:
+ * First converts the uid to userdn and calls
+ * ldapu_auth_userdn_password.
+ * Arguments:
+ * ld Pointer to LDAP (assumes connection has been
+ * established and the client has called the
+ * appropriate bind routine)
+ * uid User's name
+ * password User's password (clear text)
+ * Return Values: (same as ldapu_find)
+ * LDAPU_SUCCESS if user credentials are valid
+ * <rv> if error, where <rv> can be passed to
+ * ldap_err2string to get an error string.
+ */
+int ldapu_auth_uid_password (LDAP *ld, const char *uid,
+ const char *password, const char *base)
+{
+ int retval;
+ char *dn;
+
+ /* First find userdn for the given uid and
+ then call ldapu_auth_userdn_password */
+ retval = ldapu_find_userdn(ld, uid, base, &dn);
+
+ if (retval == LDAPU_SUCCESS) {
+ retval = ldapu_auth_userdn_password(ld, dn, password);
+ ldapu_memfree(ld, dn);
+ }
+
+ return retval;
+}
+
+
+/* ldapu_string_set --
+ * This function is not tested yet for its usefulness. This is to be used to
+ * customize the strings used in the LDAP searches performed through
+ * 'ldaputil'. This could also be extended to setting customized error
+ * messages (and even i18n equivalent of error messages).
+ */
+NSAPI_PUBLIC int ldapu_string_set (const int type, const char *filter)
+{
+ if (!filter || !*filter) return LDAPU_ERR_INVALID_STRING;
+
+ if (type < 0 || type >= LDAPU_STR_MAX_INDEX)
+ return LDAPU_ERR_INVALID_STRING_INDEX;
+
+ ldapu_strings[type] = strdup(filter);
+
+ if (!ldapu_strings[type]) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ return LDAPU_SUCCESS;
+}
+
+
+NSAPI_PUBLIC const char *ldapu_string_get (const int type)
+{
+ if (type < 0 || type >= LDAPU_STR_MAX_INDEX)
+ return 0;
+
+ return ldapu_strings[type];
+}
diff --git a/lib/ldaputil/ldapdb.c b/lib/ldaputil/ldapdb.c
new file mode 100644
index 00000000..2dfc30ca
--- /dev/null
+++ b/lib/ldaputil/ldapdb.c
@@ -0,0 +1,583 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef DONT_USE_LDAP_SSL
+#define USE_LDAP_SSL
+#endif
+
+
+#include <string.h>
+#include <malloc.h>
+
+#ifdef LDAPDB_THREAD_SAFE
+#include <nspr.h>
+#include <prthread.h>
+#include <prmon.h>
+/* removed for new ns security integration
+#include <xp_error.h>
+*/
+#endif /* LDAPDB_THREAD_SAFE */
+
+#include "ldaputil/errors.h"
+#include "ldaputil/certmap.h"
+#include "ldaputil/ldapdb.h"
+
+#ifdef USE_LDAP_SSL
+/* removed for new ns security integration
+#include <sec.h>
+#include <key.h>
+#include "cert.h"
+*/
+#include <ssl.h>
+#include "ldap_ssl.h"
+#endif
+
+#include "ldaputili.h"
+
+#define LDAPDB_PREFIX_WITH_SLASHES "ldapdb://"
+#define LDAPDB_PREFIX_WITH_SLASHES_LEN 9
+
+#ifndef LDAPDB_THREAD_SAFE
+#define ldb_crit_init(x)
+#define ldb_crit_enter(x)
+#define ldb_crit_exit(x)
+#else
+#ifdef NSPR20
+uintn tsdindex;
+#else
+int32 tsdindex;
+#endif
+
+static void ldb_crit_init (LDAPDatabase_t *ldb)
+{
+ ldb->crit = PR_NewMonitor();
+}
+
+static void ldb_crit_enter (LDAPDatabase_t *ldb)
+{
+ PR_EnterMonitor(ldb->crit);
+}
+
+static void ldb_crit_exit (LDAPDatabase_t *ldb)
+{
+ PR_ExitMonitor(ldb->crit);
+}
+
+struct ldap_error {
+ int le_errno;
+ char *le_matched;
+ char *le_errmsg;
+};
+
+
+static void set_ld_error( int err, char *matched, char *errmsg, void *dummy )
+{
+ struct ldap_error *le;
+
+#ifdef NSPR20
+ if (!(le = (struct ldap_error *) PR_GetThreadPrivate(tsdindex))) {
+ le = (struct ldap_error *) malloc(sizeof(struct ldap_error));
+ memset((void *)le, 0, sizeof(struct ldap_error));
+ PR_SetThreadPrivate(tsdindex, (void *)le);
+ }
+#else
+ le = (struct ldap_error *) PR_GetThreadPrivate( PR_CurrentThread(), tsdindex );
+#endif
+ le->le_errno = err;
+ if ( le->le_matched != NULL ) {
+ ldap_memfree( le->le_matched );
+ }
+ le->le_matched = matched;
+ if ( le->le_errmsg != NULL ) {
+ ldap_memfree( le->le_errmsg );
+ }
+ le->le_errmsg = errmsg;
+}
+
+static int get_ld_error( char **matched, char **errmsg, void *dummy )
+{
+ struct ldap_error *le;
+
+#ifdef NSPR20
+ le = (struct ldap_error *) PR_GetThreadPrivate( tsdindex);
+#else
+ le = (struct ldap_error *) PR_GetThreadPrivate( PR_CurrentThread(), tsdindex );
+#endif
+ if ( matched != NULL ) {
+ *matched = le->le_matched;
+ }
+ if ( errmsg != NULL ) {
+ *errmsg = le->le_errmsg;
+ }
+ return( le->le_errno );
+}
+
+static void set_errno( int err )
+{
+ PR_SetError( err, 0);
+}
+
+static int get_errno( void )
+{
+ return( PR_GetError() );
+}
+
+#ifdef LDAP_OPT_DNS_FN_PTRS /* not supported in older LDAP SDKs */
+static LDAPHostEnt *
+ldapu_copyPRHostEnt2LDAPHostEnt( LDAPHostEnt *ldhp, PRHostEnt *prhp )
+{
+ ldhp->ldaphe_name = prhp->h_name;
+ ldhp->ldaphe_aliases = prhp->h_aliases;
+ ldhp->ldaphe_addrtype = prhp->h_addrtype;
+ ldhp->ldaphe_length = prhp->h_length;
+ ldhp->ldaphe_addr_list = prhp->h_addr_list;
+ return( ldhp );
+}
+
+static LDAPHostEnt *
+ldapu_gethostbyname( const char *name, LDAPHostEnt *result,
+ char *buffer, int buflen, int *statusp, void *extradata )
+{
+ PRHostEnt prhent;
+
+ if( !statusp || ( *statusp = (int)PR_GetHostByName( name, buffer,
+ buflen, &prhent )) == PR_FAILURE ) {
+ return( NULL );
+ }
+
+ return( ldapu_copyPRHostEnt2LDAPHostEnt( result, &prhent ));
+}
+
+static LDAPHostEnt *
+ldapu_gethostbyaddr( const char *addr, int length, int type,
+ LDAPHostEnt *result, char *buffer, int buflen, int *statusp,
+ void *extradata )
+{
+ return( (LDAPHostEnt *)PR_GetError() );
+}
+#endif /* LDAP_OPT_DNS_FN_PTRS */
+#endif /* LDAPDB_THREAD_SAFE */
+
+
+static void unescape_ldap_basedn (char *str)
+{
+ if (strchr(str, '%')) {
+ register int x = 0, y = 0;
+ int l = strlen(str);
+ char digit;
+
+ while(x < l) {
+ if((str[x] == '%') && (x < (l - 2))) {
+ ++x;
+ digit = (str[x] >= 'A' ?
+ ((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
+ digit *= 16;
+
+ ++x;
+ digit += (str[x] >= 'A' ?
+ ((str[x] & 0xdf) - 'A')+10 : (str[x] - '0'));
+
+ str[y] = digit;
+ }
+ else {
+ str[y] = str[x];
+ }
+ x++;
+ y++;
+ }
+ str[y] = '\0';
+ }
+}
+
+/*
+ * extract_path_and_basedn:
+ * Description:
+ * Parses the ldapdb url and returns pathname to the lcache.conf file
+ * and basedn. The caller must free the memory allocated for the
+ * returned path and the basedn.
+ * Arguments:
+ * url URL (must begin with ldapdb://)
+ * path Pathname to the lcache.conf file
+ * basedn basedn for the ldapdb.
+ * Return Values: (same as ldap_find)
+ * LDAPU_SUCCESS if the URL is parsed successfully
+ * <rv> if error, one of the LDAPU_ errors.
+ */
+static int extract_path_and_basedn(const char *url_in, char **path_out,
+ char **basedn_out)
+{
+ char *url = strdup(url_in);
+ char *basedn;
+ char *path;
+
+ *path_out = 0;
+ *basedn_out = 0;
+
+ if (!url) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ if (strncmp(url, LDAPDB_URL_PREFIX, LDAPDB_URL_PREFIX_LEN)) {
+ free(url);
+ return LDAPU_ERR_URL_INVALID_PREFIX;
+ }
+
+ path = url + LDAPDB_URL_PREFIX_LEN;
+
+ if (strncmp(path, "//", 2)) {
+ free(url);
+ return LDAPU_ERR_URL_INVALID_PREFIX;
+ }
+
+ path += 2;
+
+ /* Find base DN -- empty string is OK */
+ if ((basedn = strrchr(path, '/')) == NULL) {
+ free(url);
+ return LDAPU_ERR_URL_NO_BASEDN;
+ }
+
+ *basedn++ = '\0'; /* terminate the path */
+ unescape_ldap_basedn(basedn);
+ *basedn_out = strdup(basedn);
+ *path_out = strdup(path);
+ free(url);
+ return (*basedn_out && *path_out) ? LDAPU_SUCCESS : LDAPU_ERR_OUT_OF_MEMORY;
+}
+
+NSAPI_PUBLIC int ldapu_ldapdb_url_parse (const char *url,
+ LDAPDatabase_t **ldb_out)
+{
+ char *path = 0;
+ char *basedn = 0;
+ LDAPDatabase_t *ldb = 0;
+ int rv;
+
+ rv = extract_path_and_basedn(url, &path, &basedn);
+
+ if (rv != LDAPU_SUCCESS) {
+ if (path) free(path);
+ if (basedn) free(basedn);
+ return rv;
+ }
+
+ ldb = (LDAPDatabase_t *)malloc(sizeof(LDAPDatabase_t));
+
+ if (!ldb) {
+ if (path) free(path);
+ if (basedn) free(basedn);
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ memset((void *)ldb, 0, sizeof(LDAPDatabase_t));
+ ldb->basedn = basedn; /* extract_path_and_basedn has allocated */
+ ldb->host = path; /* memory for us -- don't make a copy */
+ ldb_crit_init(ldb);
+ *ldb_out = ldb;
+
+ return LDAPU_SUCCESS;
+}
+
+
+/*
+ * ldapu_url_parse:
+ * Description:
+ * Parses the ldapdb or ldap url and returns a LDAPDatabase_t struct
+ * Arguments:
+ * url URL (must begin with ldapdb://)
+ * binddn DN to use to bind to ldap server.
+ * bindpw Password to use to bind to ldap server.
+ * ldb a LDAPDatabase_t struct filled from parsing
+ * the url.
+ * Return Values: (same as ldap_find)
+ * LDAPU_SUCCESS if the URL is parsed successfully
+ * <rv> if error, one of the LDAPU_ errors.
+ */
+NSAPI_PUBLIC int ldapu_url_parse (const char *url, const char *binddn,
+ const char *bindpw,
+ LDAPDatabase_t **ldb_out)
+{
+ LDAPDatabase_t *ldb;
+ LDAPURLDesc *ludp = 0;
+ int rv;
+
+ *ldb_out = 0;
+
+ if (!strncmp(url, LDAPDB_PREFIX_WITH_SLASHES,
+ LDAPDB_PREFIX_WITH_SLASHES_LEN))
+ {
+ return ldapu_ldapdb_url_parse(url, ldb_out);
+ }
+
+ /* call ldapsdk's parse function */
+ rv = ldap_url_parse((char *)url, &ludp);
+
+ if (rv != LDAP_SUCCESS) {
+ if (ludp) ldap_free_urldesc(ludp);
+ return LDAPU_ERR_URL_PARSE_FAILED;
+ }
+
+ ldb = (LDAPDatabase_t *)malloc(sizeof(LDAPDatabase_t));
+
+ if (!ldb) {
+ ldap_free_urldesc(ludp);
+ return LDAPU_ERR_OUT_OF_MEMORY;
+ }
+
+ memset((void *)ldb, 0, sizeof(LDAPDatabase_t));
+ ldb->host = ludp->lud_host ? strdup(ludp->lud_host) : 0;
+ ldb->use_ssl = ludp->lud_options & LDAP_URL_OPT_SECURE;
+ ldb->port = ludp->lud_port ? ludp->lud_port : ldb->use_ssl ? 636 : 389;
+ ldb->basedn = ludp->lud_dn ? strdup(ludp->lud_dn) : 0;
+ ldb_crit_init(ldb);
+ ldap_free_urldesc(ludp);
+
+ if (binddn) ldb->binddn = strdup(binddn);
+
+ if (bindpw) ldb->bindpw = strdup(bindpw);
+
+ /* success */
+ *ldb_out = ldb;
+
+ return LDAPU_SUCCESS;
+}
+
+NSAPI_PUBLIC void ldapu_free_LDAPDatabase_t (LDAPDatabase_t *ldb)
+{
+ if (ldb->host) free(ldb->host);
+ if (ldb->basedn) free(ldb->basedn);
+ if (ldb->filter) free(ldb->filter);
+ if (ldb->binddn) free(ldb->binddn);
+ if (ldb->bindpw) free(ldb->bindpw);
+ if (ldb->ld) ldapu_unbind(ldb->ld);
+ memset((void *)ldb, 0, sizeof(LDAPDatabase_t));
+ free(ldb);
+}
+
+NSAPI_PUBLIC LDAPDatabase_t *ldapu_copy_LDAPDatabase_t (const LDAPDatabase_t *ldb)
+{
+ LDAPDatabase_t *nldb = (LDAPDatabase_t *)malloc(sizeof(LDAPDatabase_t));
+
+ if (!nldb) return 0;
+
+ memset((void *)nldb, 0, sizeof(LDAPDatabase_t));
+ nldb->use_ssl = ldb->use_ssl;
+ if (ldb->host) nldb->host = strdup(ldb->host);
+ nldb->port = ldb->port;
+ if (ldb->basedn) nldb->basedn = strdup(ldb->basedn);
+ nldb->scope = ldb->scope;
+ if (ldb->filter) nldb->filter = strdup(ldb->filter);
+ nldb->ld = 0;
+ if (ldb->binddn) nldb->binddn = strdup(ldb->binddn);
+ if (ldb->bindpw) nldb->bindpw = strdup(ldb->bindpw);
+ nldb->bound = 0;
+ ldb_crit_init(nldb);
+
+ return nldb;
+}
+
+NSAPI_PUBLIC int ldapu_is_local_db (const LDAPDatabase_t *ldb)
+{
+ return ldb->port ? 0 : 1;
+}
+
+static int LDAP_CALL LDAP_CALLBACK
+ldapu_rebind_proc (LDAP *ld, char **whop, char **passwdp,
+ int *authmethodp, int freeit, void *arg)
+{
+ if (freeit == 0) {
+ LDAPDatabase_t *ldb = (LDAPDatabase_t *)arg;
+ *whop = ldb->binddn;
+ *passwdp = ldb->bindpw;
+ *authmethodp = LDAP_AUTH_SIMPLE;
+ }
+
+ return LDAP_SUCCESS;
+}
+
+NSAPI_PUBLIC int ldapu_ldap_init(LDAPDatabase_t *ldb)
+{
+ LDAP *ld = 0;
+
+ ldb_crit_enter(ldb);
+
+#ifdef USE_LDAP_SSL
+ /* Note. This assume the security related initialization is done */
+ /* The step needed is :
+ PR_Init
+ RNG_SystemInfoForRNG
+ RNG_RNGInit
+ CERT_OpenCertDBFilename
+ CERT_SetDefaultCertDB
+ SECMOD_init
+
+ And because ldapssl_init depends on security initialization, it is
+ no good for non-ssl init
+ */
+ if (ldb->use_ssl)
+ ld = ldapssl_init(ldb->host, ldb->port, ldb->use_ssl);
+ else ldap_init(ldb->host, ldb->port);
+#else
+ ld = ldapu_init(ldb->host, ldb->port);
+#endif
+
+ if (ld == NULL) {
+ DBG_PRINT1("ldapu_ldap_init: Failed to initialize connection");
+ ldb_crit_exit(ldb);
+ return LDAPU_ERR_LDAP_INIT_FAILED;
+ }
+
+#ifdef LDAPDB_THREAD_SAFE
+ {
+ struct ldap_thread_fns tfns;
+
+#ifdef NSPR20
+ PR_NewThreadPrivateIndex(&tsdindex, NULL);
+#else
+ tsdindex = PR_NewThreadPrivateID();
+#endif
+
+ /* set mutex pointers */
+ memset( &tfns, '\0', sizeof(struct ldap_thread_fns) );
+ tfns.ltf_mutex_alloc = (void *(*)(void))PR_NewMonitor;
+ tfns.ltf_mutex_free = (void (*)(void *))PR_DestroyMonitor;
+ tfns.ltf_mutex_lock = (int (*)(void *)) PR_EnterMonitor;
+ tfns.ltf_mutex_unlock = (int (*)(void *)) PR_ExitMonitor;
+ tfns.ltf_get_errno = get_errno;
+ tfns.ltf_set_errno = set_errno;
+ tfns.ltf_get_lderrno = get_ld_error;
+ tfns.ltf_set_lderrno = set_ld_error;
+ /* set ld_errno pointers */
+ if ( ldapu_set_option( ld, LDAP_OPT_THREAD_FN_PTRS, (void *) &tfns )
+ != 0 ) {
+ ldb_crit_exit(ldb);
+ return LDAPU_ERR_LDAP_SET_OPTION_FAILED;
+ }
+ }
+#ifdef LDAP_OPT_DNS_FN_PTRS /* not supported in older LDAP SDKs */
+ {
+ /* install DNS functions */
+ struct ldap_dns_fns dnsfns;
+ memset( &dnsfns, '\0', sizeof(struct ldap_dns_fns) );
+ dnsfns.lddnsfn_bufsize = PR_NETDB_BUF_SIZE;
+ dnsfns.lddnsfn_gethostbyname = ldapu_gethostbyname;
+ dnsfns.lddnsfn_gethostbyaddr = ldapu_gethostbyaddr;
+ if ( ldapu_set_option( ld, LDAP_OPT_DNS_FN_PTRS, (void *)&dnsfns )
+ != 0 ) {
+ ldb_crit_exit(ldb);
+ return LDAPU_ERR_LDAP_SET_OPTION_FAILED;
+ }
+ }
+#endif /* LDAP_OPT_DNS_FN_PTRS */
+#endif /* LDAPDB_THREAD_SAFE */
+
+ if (ldapu_is_local_db(ldb)) {
+ /* No more Local db support, force error! */
+ return LDAPU_ERR_LCACHE_INIT_FAILED;
+#if 0
+ int optval = 1;
+
+ if (lcache_init(ld, ldb->host) != 0) {
+ ldb_crit_exit(ldb);
+ return LDAPU_ERR_LCACHE_INIT_FAILED;
+ }
+
+ if (ldap_set_option(ld, LDAP_OPT_CACHE_ENABLE, &optval) != 0) {
+ ldb_crit_exit(ldb);
+ return LDAPU_ERR_LDAP_SET_OPTION_FAILED;
+ }
+
+ optval = LDAP_CACHE_LOCALDB;
+
+ if (ldap_set_option(ld, LDAP_OPT_CACHE_STRATEGY, &optval) != 0) {
+ ldb_crit_exit(ldb);
+ return LDAPU_ERR_LDAP_SET_OPTION_FAILED;
+ }
+#endif
+ }
+ else if (ldb->binddn && *ldb->binddn) {
+ /* Set the rebind proc */
+ /* Rebind proc is used when chasing a referral */
+ ldap_set_rebind_proc(ld, ldapu_rebind_proc, (void *)ldb);
+ }
+
+ ldb->ld = ld;
+ ldb_crit_exit(ldb);
+
+ return LDAPU_SUCCESS;
+}
+
+NSAPI_PUBLIC int ldapu_ldap_rebind (LDAPDatabase_t *ldb)
+{
+ int retry;
+ int rv = LDAPU_FAILED;
+
+ ldb_crit_enter(ldb);
+
+ if (ldb->ld) {
+ retry = (ldb->bound != -1 ? 1 : 0); /* avoid recursion */
+
+#ifdef USE_LDAP_SSL
+ if (ldb->use_ssl && !CERT_GetDefaultCertDB()) {
+ /* default cert database has not been initialized */
+ rv = LDAPU_ERR_NO_DEFAULT_CERTDB;
+ }
+ else
+#endif
+ {
+ rv = ldap_simple_bind_s(ldb->ld, ldb->binddn, ldb->bindpw);
+ }
+
+ /* retry once if the LDAP server is down */
+ if (rv == LDAP_SERVER_DOWN && retry) {
+ ldb->bound = -1; /* to avoid recursion */
+ rv = ldapu_ldap_reinit_and_rebind(ldb);
+ }
+
+ if (rv == LDAPU_SUCCESS) ldb->bound = 1;
+ }
+
+ ldb_crit_exit(ldb);
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_ldap_init_and_bind (LDAPDatabase_t *ldb)
+{
+ int rv = LDAPU_SUCCESS;
+
+ ldb_crit_enter(ldb);
+
+ if (!ldb->ld) {
+ rv = ldapu_ldap_init(ldb);
+ /* ldb->bound may be set to -1 to avoid recursion */
+ if (ldb->bound == 1) ldb->bound = 0;
+ }
+
+ /* bind as binddn & bindpw if not bound already */
+ if (rv == LDAPU_SUCCESS && ldb->bound != 1) {
+ rv = ldapu_ldap_rebind (ldb);
+ }
+
+ ldb_crit_exit(ldb);
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ldapu_ldap_reinit_and_rebind (LDAPDatabase_t *ldb)
+{
+ int rv;
+
+ ldb_crit_enter(ldb);
+
+ if (ldb->ld) {
+ ldapu_unbind(ldb->ld);
+ ldb->ld = 0;
+ }
+
+ rv = ldapu_ldap_init_and_bind(ldb);
+ ldb_crit_exit(ldb);
+ return rv;
+}
+
diff --git a/lib/ldaputil/ldapu-changes.html b/lib/ldaputil/ldapu-changes.html
new file mode 100644
index 00000000..124181f5
--- /dev/null
+++ b/lib/ldaputil/ldapu-changes.html
@@ -0,0 +1,403 @@
+<!-- BEGIN COPYRIGHT BLOCK
+ Copyright 2001 Sun Microsystems, Inc.
+ Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ All rights reserved.
+ END COPYRIGHT BLOCK -->
+<HTML>
+<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="Author" CONTENT="Nitin More">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.01 [en] (WinNT; U) [Netscape]">
+</HEAD>
+<BODY>
+
+<CENTER>
+<H1>
+Change Log for the ldaputil library</H1></CENTER>
+
+<DT>
+Author: Nitin More</DT>
+
+<DT>
+E-mail:&nbsp; <A HREF="mailto:nitin@netscape.com">nitin@netscape.com</A></DT>
+
+<DT>
+Phone: (415) 937-4240</DT>
+
+<CENTER></CENTER>
+
+<CENTER>
+<HR WIDTH="100%"></CENTER>
+
+<CENTER></CENTER>
+
+<CENTER><B><FONT SIZE=+1>Changes since Apr 17, 1997</FONT></B></CENTER>
+
+
+<P>Last Update: Aug 25, 1997
+
+<P>All the new changes have been checked into the server3_tier_branch.&nbsp;
+The server3_branch is frozen &amp; contains the version of 'ldaputil' for
+the SuiteSpot 3.0 release.
+<H2>
+Changed:</H2>
+Several bug fixes went in since I last modified this file.&nbsp; The important
+ones are:
+<UL>
+<LI>
+<A HREF="http://scopus/bugsplat/show_bug.cgi?id=79373">79373</A>: Attributes
+listed multiple times in certmap.conf were turining that attribute off
+and enabling some other attribute.&nbsp; (For example, if you have "E"
+as well as "MAIL" in FilterComps, they cancelled each other).</LI>
+
+<LI>
+<A HREF="http://scopus/bugsplat/show_bug.cgi?id=58474">58474</A>: If nested
+group checks goes on for 30 recursions, a circular groups error is returned.</LI>
+
+<LI>
+<A HREF="http://scopus/bugsplat/show_bug.cgi?id=80004">80004</A>: after
+thoroughly testing the certmap utility, several (mostly minor) oddities
+were found &amp; fixed.</LI>
+</UL>
+
+<H2>
+Added:</H2>
+
+<UL>
+<LI>
+<A HREF="http://scopus/bugsplat/show_bug.cgi?id=79370">79370</A>: Group
+membership check is optimized now through the new function <B>ldapu_auth_userdn_groupids</B>.&nbsp;
+Use this new function to get the optimization.&nbsp; This function's algorithm
+is as follows:</LI>
+
+<BR>The first search uses the following filter (w/o the group names!):
+<OL><TT>(| (&amp; (objectclass=groupofuniquenames)</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (uniquemember=&lt;userDN>))</TT>
+<BR><TT>&nbsp;&nbsp; (&amp; (objectclass=groupofnames)(member=&lt;userDN>)))</TT>
+<BR>&nbsp;</OL>
+This gives us all the groups the user is member of.&nbsp; We ask for only
+the "CN" attributes of the returned groups.&nbsp; We check if "CN" of any
+of the returned groups is one of the groups we have.&nbsp; If yes, we have
+succeeded.&nbsp; If there are no groups returned then we have failed.&nbsp;
+Otherwise, we continue with the nested group check.&nbsp; To perform that
+check, we need DNs of all the groups the user is member of, which we already
+have from the previous search.&nbsp; Now we repeat the search as follows:
+<OL><TT>(| (&amp; (objectclass=groupofuniquenames)</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (| (uniquemember=&lt;grp1DN>)...
+(uniquemember=&lt;grpNDN>))</TT>
+<BR><TT>&nbsp;&nbsp; (&amp; (objectclass=groupofnames)</TT>
+<BR><TT>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; (| (member=&lt;grp1DN>)... (member=&lt;grpNDN>))</TT></OL>
+We check the list of groups returned by this search with the groups in
+the ACL and recursively continue until we succeed or no more groups are
+returned from the searches.
+
+<P>Advantages of this new function is it checks multiple groups at the
+same time.&nbsp; Previously we were performing 2 ldap lookups per group.&nbsp;
+Now we achieve this in a single ldap lookup!
+
+<P><B><BLINK>Caution</BLINK></B>: this function allows multiple groups
+with the same "CN".
+
+<P>To use this function, you need to provide a list of group names in any
+form (e.g comma separated string, a hash table, array of strings, etc.)
+and a function to compare the name returned by the ldap lookup with your
+group names.</UL>
+
+<CENTER><B><FONT SIZE=+1>Changes since Mar 22, 1997</FONT></B></CENTER>
+
+
+<P>Last Update: Apr 17, 1997
+
+<P>Now that all beta releases are out for servers using this library, I
+could do some incompatible changes to make this library more flexible.
+No more incompatible changes are planned (except for possibly one: see
+http://scopus/bugsplat/show_bug.cgi?id=58482). <B><BLINK>All 3.0 SuiteSpot
+servers supporting client auth need to upgrade to this version.</BLINK></B>
+<H2>
+Changed:</H2>
+
+<UL>
+<LI>
+<B>Exchanged certmap.h &amp; ldaputil.h: </B>ldaputil.h had public API
+but when the file was installed on the server root, it was called certmap.h.
+Since we already had a certmap.h, this was causing lot of confusion. If
+you were including "certmap.h", now include "ldaputil.h" and vice versa.</LI>
+
+<LI>
+<B>Renamed 'SearchComps' to 'FilterComps'</B>: Shouldn't affect your code
+but may affect tests and documentation.</LI>
+
+<LI>
+<B>'VerifyCert' must be either "on" or "off"</B>: VerifyCert didn't have
+a value. Now it must have a value. If it has a value of "on" then the "verification"
+step is on, otherwise it is off.</LI>
+
+<LI>
+<B>Important bug fixes</B>: One bug was causing stack corruption &amp;
+weird unpredictable results. The other important bug was to map 'E' in
+cert to 'MAIL' in LDAP.</LI>
+</UL>
+
+<H2>
+Added:</H2>
+
+<UL>
+<LI>
+<B>Settable 'search function'</B>: User defined search function can be
+set for cert to ldap mapping.</LI>
+
+<LI>
+<B>ldapu_get_cert_ava_val &amp; ldapu_free_cert_ava_val</B>: API functions
+to get &amp; free an attribute's value(s) from either the subject DN or
+the issuer DN from a cert.</LI>
+</UL>
+
+<H2>
+Open Bugs:</H2>
+
+<UL>Following bugs may not get fixed by RTM.</UL>
+
+<UL>
+<LI>
+<A HREF="http://scopus/bugsplat/show_bug.cgi?id=51279">51279</A>: 'uniquemember'
+bug</LI>
+
+<LI>
+<A HREF="http://scopus/bugsplat/show_bug.cgi?id=58474">58474</A>:&nbsp;
+'circular groups' results in infinite loop</LI>
+
+<LI>
+<A HREF="http://scopus/bugsplat/show_bug.cgi?id=58478">58478</A>: Don't
+allow a space as a valid delimeter for DNComps &amp; FilterComps.</LI>
+
+<LI>
+<A HREF="http://scopus/bugsplat/show_bug.cgi?id=58482">58482</A>: Make
+the 'search function' configurable.</LI>
+
+<BR>
+<HR WIDTH="100%"></UL>
+
+<CENTER>
+<H3>
+Changes since Mar 18, 1997</H3></CENTER>
+
+<DT>
+Last Update: Mar 22, 1997</DT>
+
+<DT>
+A query on how to map a verisign certificate prompted these changes.&nbsp;
+I was hoping I don't have to do any major changes when I wrote this document
+on Mar 18. These are incompatible changes -- please review them before
+you upgrade.&nbsp; I have checked in this file in CVS under "ns/netsite/lib/ldaputil/ldapu-changes.html".
+I have added all the "XYZ_branch" and "XYZ_point" tags to this file so
+that you can easily see this file in your tree.&nbsp; When I make significant
+changes to this file/library, I will retag this file for your branch to
+make it same as the server3_branch. [Let me know if I shouldn't do it for
+your branch].</DT>
+
+<H2>
+Changed:</H2>
+
+<UL>
+<LI>
+<B>ldapu_cert_to_ldap_entry</B>: The major change was to allow for the
+mapped DN to be NULL and in that case, start the search from the basedn
+of the LDAP server. This required API change so that the basedn can be
+passed to the ldapu_cert_to_ldap_entry function. This change was required
+for correctly mapping certs from verisign w/o writing plugins. The Verisign
+certs can be mapped correctly using the following setting in the &lt;ServerRoot>/userdb/certmap.conf
+file:</LI>
+
+<UL><TT><FONT SIZE=+1>certmap verisign &lt;verisign's DN></FONT></TT>
+<BR><TT><FONT SIZE=+1>verisign:dncomps</FONT></TT>
+<BR><TT><FONT SIZE=+1>verisign:searchcomps cn, e</FONT></TT></UL>
+The mapped DN will be NULL so basedn will be used.&nbsp; The filter will
+be
+<BR>(&amp; (cn="&lt;user's CN>") (mail="&lt;user's mail>")).&nbsp; The
+new signature of ldapu_cert_to_ldap_entry is as follows:
+<BR>&nbsp;&nbsp;&nbsp; int ldapu_cert_to_ldap_entry(void *cert, LDAP *ld,
+const char *basedn, LDAPMessage **res);
+<LI>
+<B>verify cert functions</B>: A major change in how verify cert functions
+work.&nbsp; This is function is now called even when multiple potential
+matches are found for the cert.&nbsp; The mapping is successful if the
+verify function can reduce the number of matches to exactly one.&nbsp;
+For example, if there are multiple "Joe Smith" entries, at most one of
+those will have the cert in it's "userCertificate" attr.&nbsp; The verify
+function will select that entry.&nbsp; The verify function is called with
+"LDAPMessage *res" containing all the potential matches.&nbsp; It should
+return a pointer to the matched entry in the new "LDAPMessage **entry"
+parameter.&nbsp; The new signature for CertVerifyFn_t is as follows:</LI>
+
+<BR>&nbsp;&nbsp;&nbsp; typedef int (*CertVerifyFn_t)(void *cert, LDAP *ld,
+LDAPMessage *res,
+<BR>&nbsp;
+
+<P>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+LDAPMessage **entry);
+<LI>
+typedef int (*<B>CertMapInitiFn_t)</B>: Renamed from CertmapInitFn_t.&nbsp;
+Now this has two extra parameters to make it easy to use it in a plugin.
+Other API functions require "issuerDN" but this function was called with
+"LDAPUCertMapInfo_t *certinfo".&nbsp; There was no public API function
+to get the issuerDN from "certinfo". The new signature for CertMapInitFn_t
+is as follows:</LI>
+
+<BR>&nbsp;&nbsp;&nbsp; typedef int (*CertMapInitFn_t)(void *certmap_info,
+const char *issuerName,
+<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
+const char *issuerDN);
+<LI>
+(ldapauth.h) <B>ldapu_auth_* functions:</B> For multiple matches, these
+functions now return LDAPU_ERR_MULTIPLE_MATCHES instead of LDAPU_FAILED.
+This change was required to make nested group membership work efficiently
+and enable the new functionality of verify cert function.</LI>
+</UL>
+
+<DT>
+
+<HR WIDTH="100%"></DT>
+
+<CENTER>
+<H3>
+Changes since Feb 1, 1997</H3></CENTER>
+
+<DT>
+Last Update: Mar 18, 1997</DT>
+
+<DT>
+There have been several changes to the netsite/lib/ldaputil recently. If
+you use this library, please start using the latest version of ldaputil
+on the server3_branch so that all the servers go out with the same API
+and behavior. Review the changes before you upgrade. If you don't plan
+to upgrade, please let me know.</DT>
+
+<H2>
+Renamed:</H2>
+Following structures and functions are renamed. But this shouldn't affect
+you unless you have written a certmap plugin.
+<DD>
+<TT><FONT SIZE=+1>struct CertMappingFunction_t ---> CertMapFn_t</FONT></TT></DD>
+
+<DD>
+<TT><FONT SIZE=+1>struct CertVerifyFunction_t ---> CertVerifyFn_t</FONT></TT></DD>
+
+<DD>
+<TT><FONT SIZE=+1>ldapu_set_cert_mapping_function ---> ldapu_set_cert_mapfn</FONT></TT></DD>
+
+<DD>
+<TT><FONT SIZE=+1>ldapu_get_cert_mapping_function ---> ldapu_get_cert_mapfn</FONT></TT></DD>
+
+<DD>
+<TT><FONT SIZE=+1>ldapu_set_cert_verify_function ---> ldapu_set_cert_verifyfn</FONT></TT></DD>
+
+<DD>
+<TT><FONT SIZE=+1>ldapu_get_cert_verify_function ---> ldapu_get_cert_verifyfn</FONT></TT></DD>
+
+<H2>
+Removed: (from .h)</H2>
+Removed the following functions from .h files. They are still in the .c
+file as static functions. I don't think these should be public. If you
+think otherwise, let me know.
+<DD>
+<TT><FONT SIZE=+1>ldapu_cert_mapping_function_default</FONT></TT></DD>
+
+<DD>
+<TT><FONT SIZE=+1>ldapu_cert_verify_function_default</FONT></TT></DD>
+
+<DD>
+<TT><FONT SIZE=+1>ldapu_search_cert_dn</FONT></TT></DD>
+
+<DD>
+<TT><FONT SIZE=+1>ldapu_subject_dn_to_ldap_dn</FONT></TT></DD>
+
+<H2>
+Changed:</H2>
+The following changes may affect you. Please review them carefully before
+you upgrade to the latest version of ldaputil.
+<UL>
+<LI>
+<TT>ldapu_auth_userdn_groupdn</TT> -- added <TT>const char *base</TT> argument
+for group within group membership check</LI>
+
+<LI>
+ldap_init and bind calls using <TT>LDAPDatabase_t *ldb</TT> retry once
+if the LDAP server is/went down.</LI>
+
+<LI>
+<TT>typedef CertVerifyFn_t</TT> has different arguments.</LI>
+
+<LI>
+DNs from cert with escaped/quoted characters are correctly handled now.</LI>
+
+<LI>
+cert to ldap entry mapping is optimized by not using string comparisons
+during thruntime. A bitmask is created when the config file is read, cert
+data is mapped to bits and compared against the bitmask.</LI>
+
+<LI>
+Only the required attrs are retrieved in most <TT>ldap_search_s </TT>calls
+from ldaputil. Some new functions were added to keep older functions the
+same.</LI>
+
+<LI>
+Fixed a core dump in ldapu_free_LDAPDatabase_t when using the local db.</LI>
+
+<LI>
+ldaputil functions for initializing connection to the LDAP server and binding
+to the server are thread-safe now. This requires linking to netsite/lib/base.
+If you don't use libbase, you can turn off the thread-safe code using a
+compile time option.</LI>
+</UL>
+
+<H2>
+Added:</H2>
+
+<UL>
+<LI>
+Documentation to functions in ldaputil.h (customer API) - ldaputil.h is
+the external public API for customers to write there plugins.</LI>
+
+<LI>
+<TT>ldapu_get_cert_der</TT> - returns raw DER encoded cert data</LI>
+
+<LI>
+<TT>ldapu_cert_to_user</TT> - Similar to ldapu_cert_to_ldap_entry but only
+retrieves the 'uid' and 'userCertificate' attributes from LDAP and also
+extracts the user id.</LI>
+
+<LI>
+<TT>ldapu_find_uid_attrs</TT> and <TT>ldapu_find_group_attrs</TT> - Similar
+to ldapu_find_uid and ldapu_find_group resp., but only retrieves the specified
+attributes. Internally used during password verification and group membership
+checks.</LI>
+
+<LI>
+<TT>ldapu_certinfo_delete, ldapu_certinfo_modify and ldapu_certinfo_save</TT>
+- API for the certmap config file GUI tool which is not yet developed.
+Any volunteers?</LI>
+</UL>
+
+<H2>
+<FONT SIZE=+1>TODO/Bugs:</FONT></H2>
+
+<UL>
+<LI>
+uniquemember attribute is not handled correctly in the group membership
+check. If the user's entry has 'x500UniqueIdentifier' attribute populated,
+the group could refer to the user entry by the user's dn followed by '#'
+and an unique identifier. For example, the group entry could have:</LI>
+
+<DD>
+uniquemember: cn=Joe Smith,o=Netscape,c=US#jsmith</DD>
+
+<DT>
+where, 'jsmith' is one of the values of the 'x500UniqueIdentifier' attribute
+for the Joe Smith entry.</DT>
+
+<DT>
+</DT>
+</UL>
+
+</BODY>
+</HTML>
diff --git a/lib/ldaputil/ldaputili.h b/lib/ldaputil/ldaputili.h
new file mode 100644
index 00000000..fe8a65f3
--- /dev/null
+++ b/lib/ldaputil/ldaputili.h
@@ -0,0 +1,62 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _LDAPU_LDAPUTILI_H
+#define _LDAPU_LDAPUTILI_H
+
+#include <ldaputil/ldaputil.h>
+
+#include <ssl.h>
+
+#define BIG_LINE 1024
+
+extern const int SEC_OID_AVA_UNKNOWN; /* unknown OID */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+SECStatus CERT_RFC1485_EscapeAndQuote (char *dst, int dstlen, char *src, int srclen);
+
+extern void* ldapu_list_empty (LDAPUList_t* list, LDAPUListNodeFn_t free_fn, void* arg);
+extern void ldapu_list_move (LDAPUList_t* from, LDAPUList_t* into);
+
+extern int ldapu_get_cert_ava_val (void *cert_in, int which_dn,
+ const char *attr, char ***val_out);
+
+extern int ldapu_member_certificate_match (void* cert, const char* desc);
+
+/* Each of several LDAP API functions has a counterpart here.
+ * They behave the same, but their implementation may be replaced
+ * by calling ldapu_VTable_set(); as Directory Server does.
+ */
+#ifdef USE_LDAP_SSL
+extern LDAP* ldapu_ssl_init( const char *host, int port, int encrypted );
+#else
+extern LDAP* ldapu_init ( const char *host, int port );
+#endif
+extern int ldapu_set_option( LDAP *ld, int opt, void *val );
+extern int ldapu_simple_bind_s( LDAP* ld, const char *username, const char *passwd );
+extern int ldapu_unbind( LDAP *ld );
+extern int ldapu_search_s( LDAP *ld, const char *base, int scope,
+ const char *filter, char **attrs, int attrsonly, LDAPMessage **res );
+extern int ldapu_count_entries( LDAP *ld, LDAPMessage *chain );
+extern LDAPMessage* ldapu_first_entry( LDAP *ld, LDAPMessage *chain );
+extern LDAPMessage* ldapu_next_entry( LDAP *ld, LDAPMessage *entry );
+extern int ldapu_msgfree( LDAP *ld, LDAPMessage *chain );
+extern char* ldapu_get_dn( LDAP *ld, LDAPMessage *entry );
+extern void ldapu_memfree( LDAP *ld, void *dn );
+extern char* ldapu_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **ber );
+extern char* ldapu_next_attribute( LDAP *ld, LDAPMessage *entry, BerElement *ber );
+extern void ldapu_ber_free( LDAP *ld, BerElement *ber, int freebuf );
+extern char** ldapu_get_values( LDAP *ld, LDAPMessage *entry, const char *target );
+extern struct berval** ldapu_get_values_len( LDAP *ld, LDAPMessage *entry, const char *target );
+extern void ldapu_value_free( LDAP *ld, char **vals );
+extern void ldapu_value_free_len( LDAP *ld, struct berval **vals );
+
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/lib/ldaputil/utest/Makefile b/lib/ldaputil/utest/Makefile
new file mode 100644
index 00000000..e6f2e5c6
--- /dev/null
+++ b/lib/ldaputil/utest/Makefile
@@ -0,0 +1,117 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Makefile for ldaputil unit test.
+#
+MCOM_ROOT=../../../..
+MODULE=LibLdapUtil
+
+OBJDEST=.
+UTESTDEST=utest
+
+include ../../../nsconfig.mk
+
+MODULE_CFLAGS=-I$(NSROOT)/include
+
+include $(INCLUDE_DEPENDS)
+
+TESTFLAGS = -DUTEST -DDBG_PRINT -DDONT_USE_LDAP_SSL
+
+CC=CC
+PURIFY=
+
+CSRC = stubs.c
+CPPSRC = auth.cpp
+TSRC = authtest
+SRC = $(CSRC) $(CPPSRC) $(TSRC)
+XSRC = ../ldapauth.c ../ldapdb.c ../errors.c ../dbconf.c ../certmap.c ../ldapauth.c ../init.c ../encode.c
+
+COBJ = $(CPPSRC:%.cpp=%.o) $(CSRC:%.c=%.o)
+XOBJ = $(XSRC:../%.c=../utest/%.o)
+
+ifeq ($(ARCH), WINNT)
+ BINS=./auth.exe
+ LDAP_LIBLINK = $(addprefix $(LDAP_LIBPATH)/, $(addsuffix .lib, $(LDAP_LIBNAMES)))
+ XLIBS = ${LDAP_LIBLINK}
+ LOCAL_LINK_EXE = link -OUT:"$@" /MAP $(ARCH_LINK_DEBUG) $(LCFLAGS) /NOLOGO \
+ /PDB:NONE /INCREMENTAL:NO /SUBSYSTEM:windows $(XLIBS)
+else
+ BINS = auth
+ LDAP_LIBLINK = -L$(LDAP_LIBPATH) $(addprefix -l, ${LDAP_SOLIB_NAMES})
+endif
+
+ifeq ($(ARCH), SOLARIS)
+ XLIBS = -R$(LDAP_LIBPATH) ${LDAP_LIBLINK} $(LIBNSPR) $(LIBSEC) -lthread -lposix4 -lsocket -lnsl -ldl
+else
+ ifeq ($(ARCH), IRIX)
+ XLIBS = ${LDAP_LIBLINK} $(LIBNSPR) $(LIBSEC)
+ else
+ ifeq ($(ARCH), WINNT)
+ echo "XLIBS = ${XLIBS}"
+ else
+ #Other UNIX platforms
+ XLIBS = -R$(LDAP_LIBPATH) ${LDAP_LIBLINK} $(LIBNSPR) $(LIBSEC) -lthread -lposix4 -lsocket -lnsl -ldl
+ endif
+ endif
+endif
+
+PLUGIN = plugin.so
+
+all: $(LIBLDAP) $(COBJ) $(TSRC) ${BINS} $(PLUGIN)
+ ./authtest 2> test.out
+ diff test.out test.ref
+ @echo
+ @echo "The unit test is passed if there is no diff output, and the"
+ @echo "Purify window shows no errors and 0 bytes leaked."
+ @echo
+ @echo "Run - gmake coverage - manually to get code coverage analysis."
+ @echo
+
+auth: $(XOBJ) $(COBJ)
+ $(PURIFY) $(CC) $(XLIBS) $^ -o $@
+
+auth.exe: $(XOBJ) $(COBJ)
+ $(PURIFY) $(LOCAL_LINK_EXE) $(XOBJ) $(COBJ) ${XLIBS}
+
+testcert: testcert.o $(XOBJ) ../utest/cert.o
+ $(PURIFY) $(CC) $(XLIBS) $^ -o $@
+
+%.o:%.c
+ $(PURIFY) $(CC) -c $(CFLAGS) $(TESTFLAGS) $(MCC_INCLUDE) $< -o $@
+
+../utest/%.o:../%.c
+ $(PURIFY) $(CC) -c $(CFLAGS) $(TESTFLAGS) $(MCC_INCLUDE) -I.. $< -o $(OBJDEST)/$*.o
+
+../utest/%.o:../%.cpp
+ $(PURIFY) $(CC) -c $(CFLAGS) $(TESTFLAGS) $(MCC_INCLUDE) -I.. $< -o $(OBJDEST)/$*.o
+
+PLUGIN_INC = ./include
+
+$(PLUGIN_INC):
+ mkdir -p include
+
+certmap.h: ../../../include/ldaputil/extcmap.h
+ \rm -rf $(PLUGIN_INC)/$@
+ cp $^ $(PLUGIN_INC)/$@
+
+ldap.h: $(LDAP_INCLUDE)/ldap.h
+ \rm -rf $(PLUGIN_INC)/$@
+ cp $^ $(PLUGIN_INC)/$@
+
+lber.h: $(LDAP_INCLUDE)/lber.h
+ \rm -rf $(PLUGIN_INC)/$@
+ cp $^ $(PLUGIN_INC)/$@
+
+example.o: example.c $(PLUGIN_INC) certmap.h ldap.h lber.h
+ $(CC) -c -I$(PLUGIN_INC) $*.c -o $(OBJDEST)/$*.o
+
+plugin.o: plugin.c $(PLUGIN_INC) certmap.h ldap.h lber.h
+ $(PURIFY) $(CC) -c -I. -I$(PLUGIN_INC) $*.c -o $(OBJDEST)/$*.o
+
+$(PLUGIN): plugin.o
+ $(LINK_DLL) $^
diff --git a/lib/ldaputil/utest/auth.cpp b/lib/ldaputil/utest/auth.cpp
new file mode 100644
index 00000000..e952f742
--- /dev/null
+++ b/lib/ldaputil/utest/auth.cpp
@@ -0,0 +1,574 @@
+/** 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 <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include <prinit.h> // for PR_Init
+#include <prpriv.h> // for PR_Exit
+#include <ldaputil/certmap.h>
+#include <ldaputil/init.h>
+#include <ldaputil/ldapdb.h>
+#include <ldaputil/ldapauth.h>
+#include <ldaputil/dbconf.h>
+#include <ldaputil/ldaputil.h>
+#include <ldap.h>
+
+static const char* dllname = "plugin.so";
+
+char *global_issuer_dn = "o=Netscape Communications, c=US";
+
+#define NSPR_INIT(Program) (PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 8))
+
+static int ldapu_certinfo_save_test (const char *fname, const char *old_fname)
+{
+ int rv;
+
+ /* Read the original certmap config file first */
+ rv = ldaputil_init(old_fname, dllname, NULL, NULL, NULL);
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "ldapu_certinfo_save_test failed. Reason: %s\n",
+ ldapu_err2string(rv));
+ return rv;
+ }
+
+ rv = ldapu_certinfo_save(fname, old_fname, "certmap.tmp");
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "ldapu_certinfo_save_test failed. Reason: %s\n",
+ ldapu_err2string(rv));
+ }
+
+ return rv;
+}
+
+static int ldapu_certinfo_delete_test (const char *fname, const char *old_fname)
+{
+ int rv;
+
+ /* Read the original certmap config file first */
+ rv = ldaputil_init(old_fname, dllname, NULL, NULL, NULL);
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "ldapu_certinfo_delete_test failed. Reason: %s\n",
+ ldapu_err2string(rv));
+ return rv;
+ }
+
+ /* rv = ldapu_certinfo_delete("o=Ace Industry, c=US"); */
+ rv = ldapu_certinfo_delete("o=Netscape Communications, c=US");
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "ldapu_certinfo_delete failed. Reason: %s\n",
+ ldapu_err2string(rv));
+ return rv;
+ }
+
+ rv = ldapu_certinfo_save(fname, old_fname, "certmap.tmp");
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "ldapu_certinfo_delete_test failed. Reason: %s\n",
+ ldapu_err2string(rv));
+ }
+
+ return rv;
+}
+
+static int ldapu_certinfo_new_test (const char *fname, const char *old_fname)
+{
+ int rv;
+ LDAPUPropValList_t *propval_list;
+ LDAPUPropVal_t *propval;
+
+ /* Read the original certmap config file first */
+ rv = ldaputil_init(old_fname, dllname, NULL, NULL, NULL);
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "ldapu_certinfo_new_test failed. Reason: %s\n",
+ ldapu_err2string(rv));
+ return rv;
+ }
+
+ /* Setup propval_list */
+ rv = ldapu_list_alloc(&propval_list);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = ldapu_propval_alloc("prop1", "val1", &propval);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = ldapu_list_add_info(propval_list, propval);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = ldapu_propval_alloc("prop2", "val2", &propval);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = ldapu_list_add_info(propval_list, propval);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = ldapu_propval_alloc("prop3", 0, &propval);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = ldapu_list_add_info(propval_list, propval);
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ rv = ldapu_certinfo_modify("newmap", "o=Mcom Communications, c=US",
+ propval_list);
+
+ ldapu_propval_list_free(propval_list);
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "ldapu_certinfo_delete failed. Reason: %s\n",
+ ldapu_err2string(rv));
+ return rv;
+ }
+
+ rv = ldapu_certinfo_save(fname, old_fname, "certmap.tmp");
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "ldapu_certinfo_new_test failed. Reason: %s\n",
+ ldapu_err2string(rv));
+ }
+
+ return rv;
+}
+
+static int get_dbnames_test (const char *mapfile)
+{
+ char **names;
+ int cnt;
+ int rv;
+ int i;
+
+ rv = dbconf_get_dbnames(mapfile, &names, &cnt);
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "get_dbnames_test failed. Reason: %s\n",
+ ldapu_err2string(rv));
+ }
+ else {
+ for(i = 0; i < cnt; i++) {
+ fprintf(stderr, "\tdbname[%d] = \"%s\"\n",
+ i, names[i]);
+ }
+ }
+
+ dbconf_free_dbnames(names);
+
+ return rv;
+}
+
+static int case_ignore_strcmp (const char *s1, const char *s2)
+{
+ int ls1, ls2; /* tolower values of chars in s1 & s2 resp. */
+
+ if (!s1) return !s2 ? 0 : 0-tolower(*s2);
+ else if (!s2) return tolower(*s1);
+
+ while(*s1 && *s2 && (ls1 = tolower(*s1)) == (ls2 = tolower(*s2))) { s1++; s2++; }
+
+ if (!*s1)
+ return *s2 ? 0-tolower(*s2) : 0;
+ else if (!*s2)
+ return tolower(*s1);
+ else
+ return ls1 - ls2;
+}
+
+#define STRCASECMP3(s1, s2, rv) \
+{ \
+ int i = case_ignore_strcmp(s1, s2); \
+ fprintf(stderr, "strcasecmp(\"%s\", \"%s\")\t=\t%d\t%s\tExpected: %d\n", \
+ s1 ? s1 : "<NULL>", s2 ? s2 : "<NULL>", \
+ i, i == rv ? "SUCCESS" : "FAILED", rv); \
+}
+
+#ifndef XP_WIN32
+#define STRCASECMP(s1, s2) STRCASECMP3(s1, s2, strcasecmp(s1, s2))
+#else
+#define STRCASECMP(s1, s2) STRCASECMP3(s1, s2, case_ignore_strcmp(s1, s2))
+#endif
+
+static void strcasecmp_test ()
+{
+ STRCASECMP3(0, "aBcD", 0-tolower('a'));
+ STRCASECMP3(0, 0, 0);
+ STRCASECMP3("aBcD", 0, tolower('a'));
+
+ STRCASECMP("AbCd", "aBcD");
+ STRCASECMP("AbCd", "abcd");
+ STRCASECMP("ABCD", "ABCD");
+ STRCASECMP("abcd", "abcd");
+
+ STRCASECMP("AbCd", "aBcD3");
+ STRCASECMP("AbCd", "abcd3");
+ STRCASECMP("ABCD", "ABCD3");
+ STRCASECMP("abcd", "abcd3");
+
+ STRCASECMP("AbCd1", "aBcD");
+ STRCASECMP("AbCd2", "abcd");
+ STRCASECMP("ABCDX", "ABCD");
+ STRCASECMP("abcdY", "abcd");
+
+ STRCASECMP("AbCd5", "aBcD1");
+ STRCASECMP("AbCd5", "abcd1");
+ STRCASECMP("ABCD5", "ABCD1");
+ STRCASECMP("abcd5", "abcd1");
+
+ STRCASECMP("AbCd2", "aBcDp");
+ STRCASECMP("AbCd2", "abcdQ");
+ STRCASECMP("ABCD2", "ABCDr");
+ STRCASECMP("abcd2", "abcdS");
+}
+
+static int certmap_tests (const char *config_file) { return 0; }
+
+static int read_config_test (const char *config_file, const char *dbname,
+ const char *url,
+ const char *binddn, const char *bindpw)
+{
+ int rv;
+ DBConfDBInfo_t *db_info;
+ char *dn;
+ char *pw;
+
+ rv = dbconf_read_default_dbinfo(config_file, &db_info);
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "config_test failed: %s\n",
+ ldapu_err2string(rv));
+ return LDAPU_FAILED;
+ }
+
+ if (strcmp(db_info->dbname, dbname) ||
+ strcmp(db_info->url, url)) {
+ fprintf(stderr, "config_test failed: %s\n",
+ "first line in config file is wrong");
+ return LDAPU_FAILED;
+ }
+
+ if ((ldapu_dbinfo_attrval(db_info, "binddn", &dn) != LDAPU_SUCCESS) ||
+ (ldapu_dbinfo_attrval(db_info, "bindpw", &pw) != LDAPU_SUCCESS))
+ {
+ fprintf(stderr, "config_test failed: %s\n",
+ "properties are missing");
+ return LDAPU_FAILED;
+ }
+
+ if (strcmp(dn, binddn) ||
+ strcmp(pw, bindpw)) {
+ fprintf(stderr, "config_test failed: %s\n",
+ "property values are wrong");
+ return LDAPU_FAILED;
+ }
+
+ fprintf(stderr, "binddn from config file: \"%s\"\n", dn);
+ fprintf(stderr, "bindpw from config file: \"%s\"\n", pw);
+
+ /* cleanup */
+ dbconf_free_dbinfo(db_info);
+ free(dn);
+ free(pw);
+
+ return LDAPU_SUCCESS;
+}
+
+static int config_test (const char *binddn, const char *bindpw)
+{
+ char *config_file = "config_out.conf";
+ FILE *fp = fopen(config_file, "w");
+ const char *dbname = "default";
+ const char *url = "file:/foobar/path";
+ int rv;
+
+ if (!fp) return LDAPU_FAILED;
+
+ dbconf_output_db_directive(fp, dbname, url);
+ dbconf_output_propval(fp, dbname, "binddn", binddn, 0);
+ dbconf_output_propval(fp, dbname, "bindpw", bindpw, 1);
+
+ fclose(fp);
+
+ fprintf(stderr, "Config file written: %s\n", config_file);
+
+ rv = read_config_test(config_file, dbname, url, binddn, bindpw);
+
+ return rv;
+}
+
+static int
+compare_groupid(const void *arg, const char *group, const int len)
+{
+ auto const char* groupid = (const char*)arg;
+ auto int err = LDAPU_FAILED;
+ if (len == strlen (groupid) && !strncasecmp (groupid, group, len)) {
+ err = LDAPU_SUCCESS;
+ }
+ return err;
+}
+
+static int
+compare_group(LDAP* directory, LDAPMessage* entry, void* set)
+{
+ auto int err = LDAPU_FAILED;
+ auto char** vals = ldap_get_values (directory, entry, "CN");
+ if (vals) {
+ auto char** val;
+ for (val = vals; *val; ++val) {
+ if (!strcasecmp (*val, (char*)set)) {
+ err = LDAPU_SUCCESS;
+ break;
+ }
+ }
+ ldap_value_free (vals);
+ }
+ return err;
+}
+
+int perform_test (int argc, char *argv[])
+{
+ int test_type;
+ int retval = LDAPU_SUCCESS;
+ DBConfDBInfo_t *db_info;
+ LDAPDatabase_t *ldb;
+ LDAP *ld;
+ char *dbmap_file = "dblist.conf";
+ char *binddn = 0;
+ char *bindpw = 0;
+ char *basedn;
+ int retry = 1;
+ int rv;
+
+ fprintf(stderr, "\nStart of test: ./auth %s \"%s\" \"%s\"\n",
+ argv[1], argv[2], argv[3]);
+
+ rv = dbconf_read_default_dbinfo(dbmap_file, &db_info);
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "Error reading dbmap file \"%s\". Reason: %s\n",
+ dbmap_file, ldapu_err2string(rv));
+ return rv;
+ }
+
+ ldapu_dbinfo_attrval (db_info, LDAPU_ATTR_BINDDN, &binddn);
+ ldapu_dbinfo_attrval (db_info, LDAPU_ATTR_BINDPW, &bindpw);
+
+ rv = ldapu_url_parse (db_info->url, binddn, bindpw, &ldb);
+ free(binddn);
+ free(bindpw);
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "Error parsing ldap url \"%s\". Reason: %s\n",
+ db_info->url, ldapu_err2string(rv));
+ return rv;
+ }
+
+ basedn = ldb->basedn;
+
+ test_type = atoi(argv[1]);
+
+ retry = 1;
+
+ while(retry) {
+ retry = 0;
+
+ rv = ldapu_ldap_init_and_bind (ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ fprintf(stderr, "Error initializing connection to LDAP. Reason: %s\n",
+ ldapu_err2string(rv));
+ return rv;
+ }
+
+ ld = ldb->ld;
+
+ switch(test_type) {
+ case 1:
+ fprintf(stderr, "\nuserdn:\t\t\"%s\"\ngroupdn:\t\"%s\"\n",
+ argv[2], argv[3]);
+ retval = ldapu_auth_userdn_groupdn(ld, argv[2], argv[3], basedn);
+ break;
+
+ case 2:
+ fprintf(stderr, "\nuid:\t\t\"%s\"\ngroupdn:\t\"%s\"\n", argv[2], argv[3]);
+ retval = ldapu_auth_uid_groupdn(ld, argv[2], argv[3], basedn);
+ break;
+
+ case 3:
+ fprintf(stderr, "\nuid:\t\t\"%s\"\ngroupid:\t\"%s\"\n", argv[2], argv[3]);
+ retval = ldapu_auth_uid_groupid(ld, argv[2], argv[3], basedn);
+ break;
+
+ case 4:
+ fprintf(stderr, "\nuserdn:\t\t\"%s\"\ngroupid:\t\"%s\"\n", argv[2], argv[3]);
+ retval = ldapu_auth_userdn_groupid(ld, argv[2], argv[3], basedn);
+ break;
+
+ case 5:
+ fprintf(stderr, "\nuserdn:\t\t\"%s\"\nattrFilter:\t\"%s\"\n", argv[2], argv[3]);
+ retval = ldapu_auth_userdn_attrfilter(ld, argv[2], argv[3]);
+ break;
+
+ case 6:
+ fprintf(stderr, "\nuid:\t\t\"%s\"\nattrFilter:\t\"%s\"\n", argv[2], argv[3]);
+ retval = ldapu_auth_uid_attrfilter(ld, argv[2], argv[3], basedn);
+ break;
+
+ case 7:
+ fprintf(stderr, "\nuserdn:\t\t\"%s\"\npassword:\t\"%s\"\n", argv[2], argv[3]);
+ retval = ldapu_auth_userdn_password(ld, argv[2], argv[3]);
+ break;
+
+ case 8:
+ fprintf(stderr, "\nuid:\t\t\"%s\"\npassword:\t\"%s\"\n", argv[2], argv[3]);
+ retval = ldapu_auth_uid_password(ld, argv[2], argv[3], basedn);
+ break;
+
+ case 9: {
+ /* plugin test */
+ LDAPMessage *entry = 0;
+ LDAPMessage *res = 0;
+
+ fprintf(stderr, "Cert Map issuer DN: \"%s\"\n", argv[2]);
+ fprintf(stderr, "Cert Map subject DN: \"%s\"\n", argv[3]);
+ retval = ldaputil_init("certmap.conf", dllname, NULL, NULL, NULL);
+
+ if (retval != LDAPU_SUCCESS) {
+ fprintf(stderr, "Cert Map info test failed. Reason: %s\n",
+ ldapu_err2string(retval));
+ break;
+ }
+
+ if (*(argv[2]))
+ global_issuer_dn = argv[2];
+ else
+ global_issuer_dn = 0;
+
+ retval = ldapu_cert_to_ldap_entry(argv[3], ld, ldb->basedn, &res);
+
+ if (retval == LDAPU_SUCCESS) {
+ char *dn;
+
+ entry = ldap_first_entry(ld, res);
+ dn = ldap_get_dn(ld, entry);
+ fprintf(stderr, "Matched entry to cert: \"%s\"\n", dn);
+ ldap_memfree(dn);
+ }
+ else if (retval == LDAPU_FAILED) {
+ /* Not an error but couldn't map the cert */
+ }
+ else {
+ fprintf(stderr, "Cert Map info test failed. Reason: %s\n",
+ ldapu_err2string(retval));
+ break;
+ }
+
+ /* TEMPORARY -- when & how to free the entry */
+ if (res) ldap_msgfree(res);
+
+ break;
+ } /* case 9 */
+
+ case 10:
+ if ((retval = config_test(argv[2], argv[3])) == LDAPU_SUCCESS) {
+ fprintf(stderr, "Config file test succeeded\n");
+ }
+ else {
+ fprintf(stderr, "Config file test failed\n");
+ }
+ break;
+
+ case 11:
+ retval = get_dbnames_test(argv[2]);
+ break;
+
+ case 12:
+ retval = ldapu_certinfo_save_test(argv[2], argv[3]);
+ break;
+
+ case 13:
+ retval = ldapu_certinfo_delete_test(argv[2], argv[3]);
+ break;
+
+ case 14:
+ retval = ldapu_certinfo_new_test(argv[2], argv[3]);
+ break;
+
+ case 15:
+ fprintf(stderr, "\nuserdn:\t\t\"%s\"\ngroupid:\t\"%s\"\n", argv[2], argv[3]);
+ {
+ auto LDAPU_DNList_t* userDNs = ldapu_DNList_alloc();
+ ldapu_DNList_add(userDNs, argv[2]);
+ retval = ldapu_auth_usercert_groups(ld, basedn, userDNs, NULL,
+ argv[3], compare_group, 30, NULL);
+ ldapu_DNList_free(userDNs);
+ }
+ break;
+
+ case 16:
+ fprintf(stderr, "\nuserCert:\t\"%s\"\ngroupid:\t\"%s\"\n", argv[2], argv[3]);
+ retval = ldapu_auth_usercert_groupids(ld, NULL/*userDN*/, argv[2], argv[3],
+ compare_groupid, basedn, NULL/*group_out*/);
+ break;
+
+ } /* switch */
+
+ if (retval == LDAP_SERVER_DOWN) {
+ /* retry */
+ retry = 1;
+ ldb->ld = 0;
+ }
+ else if (retval == LDAPU_SUCCESS) {
+ fprintf(stderr, "Authentication succeeded.\n");
+ }
+ else {
+ fprintf(stderr, "Authentication failed.\n");
+ }
+ }
+
+ /* cleanup */
+// ldapu_free_LDAPDatabase_t(ldb);
+// dbconf_free_dbinfo(db_info);
+// ldaputil_exit();
+ return retval;
+}
+
+int main (int argc, char *argv[])
+{
+ int rv;
+
+ NSPR_INIT("auth");
+
+ if (argc != 4) {
+ fprintf(stderr, "argc = %d\n", argc);
+ fprintf(stderr, "usage: %s test_type user_dn group_dn\n", argv[0]);
+ fprintf(stderr, "\t%s 1 <userdn> <groupdn>\n", argv[0]);
+ fprintf(stderr, "\t%s 2 <uid> <groupdn>\n", argv[0]);
+ fprintf(stderr, "\t%s 3 <uid> <groupid>\n", argv[0]);
+ fprintf(stderr, "\t%s 4 <userdn> <groupid>\n", argv[0]);
+ fprintf(stderr, "\t%s 5 <userdn> <attrFilter>\n", argv[0]);
+ fprintf(stderr, "\t%s 6 <uid> <attrFilter>\n", argv[0]);
+ fprintf(stderr, "\t%s 7 <userdn> <password>\n", argv[0]);
+ fprintf(stderr, "\t%s 8 <uid> <password>\n", argv[0]);
+ fprintf(stderr, "\t%s 9 <certmap.conf> <subjectDN>\n", argv[0]);
+ fprintf(stderr, "\t%s 10 <binddn> <bindpw>\n", argv[0]);
+ fprintf(stderr, "\t%s 11 <dbmap> <ignore>\n", argv[0]);
+ fprintf(stderr, "\t%s 12 <newconfig> <oldconfig> ... to test save\n", argv[0]);
+ fprintf(stderr, "\t%s 13 <newconfig> <oldconfig> ... to test delete\n", argv[0]);
+ fprintf(stderr, "\t%s 14 <newconfig> <oldconfig> ... to test add\n", argv[0]);
+ fprintf(stderr, "\t%s 15 <userdn> <groupid>\n", argv[0]);
+ fprintf(stderr, "\t%s 16 <userCertDescription> <groupid>\n", argv[0]);
+ exit(LDAP_PARAM_ERROR);
+ }
+
+ rv = perform_test(argc, argv);
+ /* PR_Exit(); */
+
+ return rv;
+}
+
diff --git a/lib/ldaputil/utest/authtest b/lib/ldaputil/utest/authtest
new file mode 100755
index 00000000..c713349b
--- /dev/null
+++ b/lib/ldaputil/utest/authtest
@@ -0,0 +1,106 @@
+#!/bin/ksh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# setup for test
+USERDN="cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+USER2DN="cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US"
+
+UID="hmiller"
+U2ID="scarter"
+
+GROUPDN="cn=Directory Administrators, o=Ace Industry, c=US"
+GROUPID="Directory Administrators"
+
+ATTRFILTER="mail=hmiller@aceindustry.com"
+ATTR2FILTER="mail=scarter@aceindustry.com"
+
+function check_result {
+ echo "\nStart of test: $1 $2 \"$3\" \"$4\""
+ if ( `$1 $2 "$3" "$4"` ) then
+ if [ $5 == "fail" ]; then
+ echo "**** Test Failed ****";
+ else
+ echo "Test Succeeded";
+ fi
+ else
+ if [ $5 == "fail" ]; then
+ echo "Test Succeeded";
+ else
+ echo "**** Test Failed ****";
+ fi
+ fi
+}
+
+function must_fail {
+ check_result $1 $2 "$3" "$4" "fail";
+}
+
+function must_succeed {
+ check_result $1 $2 "$3" "$4" "success";
+}
+
+# test for <userdn> <groupdn>
+must_succeed ./auth 1 "${USERDN}" "${GROUPDN}"
+must_fail ./auth 1 "${USER2DN}" "${GROUPDN}"
+
+# test for <uid> <groupdn>
+must_succeed ./auth 2 "${UID}" "${GROUPDN}"
+must_fail ./auth 2 "${U2ID}" "${GROUPDN}"
+
+# test for <uid> <groupid>
+must_succeed ./auth 3 "${UID}" "${GROUPID}"
+must_fail ./auth 3 "${U2ID}" "${GROUPID}"
+
+# test for <userdn> <groupid>
+must_succeed ./auth 4 "${USERDN}" "${GROUPID}"
+must_fail ./auth 4 "${USER2DN}" "${GROUPID}"
+must_succeed ./auth 15 "${USERDN}" "${GROUPID}"
+must_fail ./auth 15 "${USER2DN}" "${GROUPID}"
+must_succeed ./auth 16 "{${USERDN}" "${GROUPID}"
+must_fail ./auth 16 "{${USER2DN}" "${GROUPID}"
+
+# test for <userdn> <attrFilter>
+must_succeed ./auth 5 "${USERDN}" "${ATTRFILTER}"
+must_fail ./auth 5 "${USERDN}" "${ATTR2FILTER}"
+must_fail ./auth 5 "${USER2DN}" "${ATTRFILTER}"
+
+# test for <uid> <attrFilter>
+must_succeed ./auth 6 "${UID}" "${ATTRFILTER}"
+must_fail ./auth 6 "${UID}" "${ATTR2FILTER}"
+must_fail ./auth 6 "${U2ID}" "${ATTRFILTER}"
+
+# test for <userdn> <password>
+must_succeed ./auth 7 "${USERDN}" "hillock"
+must_fail ./auth 7 "${USERDN}" "garbage"
+
+# test for <uid> <password>
+must_succeed ./auth 8 "${UID}" "hillock"
+must_fail ./auth 8 "${UID}" "garbage"
+
+#test for cert to ldap entry mapping
+must_succeed ./auth 9 "o=Ace Industry, c=US" "cn=Kirsten Vaughan, ou=Human Resources, o=Ace Industry, c=US"
+#must_fail ./auth 9 "default" "cn=Kirsten Vaughan, o=Ace Industry, c=US"
+
+# test for encode/decode bindpw
+must_succeed ./auth 10 "cn=Foo Bar, o=Netscape Communication, c=US" "foobar"
+
+# test for reading dbnames from dbswitch.conf file
+must_succeed ./auth 11 dblist.conf ignore
+
+# test for saving certmap info
+must_succeed ./auth 12 certmap.new certmap.conf
+cat certmap.conf certmap.new 1>&2
+
+# test for delete certmap info
+must_succeed ./auth 13 certmap.new certmap.conf
+cat certmap.conf certmap.new 1>&2
+
+# test for add certmap info
+must_succeed ./auth 14 certmap.new certmap.conf
+cat certmap.conf certmap.new 1>&2
+
diff --git a/lib/ldaputil/utest/certmap.conf b/lib/ldaputil/utest/certmap.conf
new file mode 100644
index 00000000..53ab6fca
--- /dev/null
+++ b/lib/ldaputil/utest/certmap.conf
@@ -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
+#
+
+# Comments before any certmap directive - line 1
+# Comments before any certmap directive - line 2
+
+# Comments before any certmap directive - line 3
+# Comments before any certmap directive - line 4
+# Comments before any certmap directive - line 5
+
+
+# Comments before any certmap directive - line 6
+
+certmap default default
+#default:DNComps o, ou ,c
+#default:FilterComps cn
+
+
+certmap default1 o=Netscape Communications, c=US
+default1:library ./plugin.so
+default1:InitFn plugin_init_fn
+default1:DNComps ou o c
+default1:FilterComps l
+#default1:verifycert
+
+# Following line has trailing spaces
+certmap default2 o=Ace Industry, c=US
+default2:InitFn plugin_init_fn
+default2:DNComps cn o ou c
+default2:FilterComps l
+default2:verifycert on
diff --git a/lib/ldaputil/utest/dblist.conf b/lib/ldaputil/utest/dblist.conf
new file mode 100644
index 00000000..c38580ac
--- /dev/null
+++ b/lib/ldaputil/utest/dblist.conf
@@ -0,0 +1,15 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+directory default ldap://:3334/o=Airius.com
+directory default1 ldap:///o=Ace Industry, c=US
+directory default2 ldap:///o=Ace Industry, c=US
+directory default3 ldap:///o=Ace Industry, c=US
+directory default4 ldap:///o=Ace Industry, c=US
+directory default5 ldap:///o=Ace Industry, c=US
+directory default6 ldap:///o=Ace Industry, c=US
diff --git a/lib/ldaputil/utest/example.c b/lib/ldaputil/utest/example.c
new file mode 100644
index 00000000..185fbe51
--- /dev/null
+++ b/lib/ldaputil/utest/example.c
@@ -0,0 +1,116 @@
+/** 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 <certmap.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* The init function must be defined extern "C" if using a C++ compiler */
+int plugin_init_fn (void *certmap_info, const char *issuerName,
+ const char *issuerDN);
+
+#ifdef __cplusplus
+}
+#endif
+
+
+static int extract_ldapdn_and_filter (const char *subjdn, void *certmap_info,
+ char **ldapDN, char **filter)
+{
+ /* extract the ldapDN and filter from subjdn */
+ /* You can also use the ldapu_certmap_info_attrval function to get value
+ of a config file parameter for the certmap_info. */
+ return LDAPU_SUCCESS;
+}
+
+static int plugin_mapping_fn (void *cert, LDAP *ld, void *certmap_info,
+ char **ldapDN, char **filter)
+{
+ char *subjdn;
+ int rv;
+
+ fprintf(stderr, "plugin_mapping_fn called.\n");
+ rv = ldapu_get_cert_subject_dn(cert, &subjdn);
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ *ldapDN = 0;
+ *filter = 0;
+
+ rv = extract_ldapdn_and_filter(subjdn, certmap_info, ldapDN, filter);
+
+ if (rv != LDAPU_SUCCESS) {
+ /* This function must return LDAPU_FAILED or
+ LDAPU_CERT_MAP_FUNCTION_FAILED on error */
+ return LDAPU_CERT_MAP_FUNCTION_FAILED;
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+static int plugin_cmp_certs (void *subject_cert,
+ void *entry_cert_binary,
+ unsigned long entry_cert_len)
+{
+ /* compare the certs */
+ return LDAPU_SUCCESS;
+}
+
+static int plugin_verify_fn (void *cert, LDAP *ld, void *certmap_info,
+ LDAPMessage *res, LDAPMessage **entry_out)
+{
+ LDAPMessage *entry;
+ struct berval **bvals;
+ char *cert_attr = "userCertificate;binary";
+ int i;
+ int rv;
+
+ fprintf(stderr, "plugin_verify_fn called.\n");
+ *entry_out = 0;
+
+ for (entry = ldap_first_entry(ld, res); entry != NULL;
+ entry = ldap_next_entry(ld, entry))
+ {
+ if ((bvals = ldap_get_values_len(ld, entry, cert_attr)) == NULL) {
+ rv = LDAPU_CERT_VERIFY_FUNCTION_FAILED;
+ /* Maybe one of the remaining entries will match */
+ continue;
+ }
+
+ for ( i = 0; bvals[i] != NULL; i++ ) {
+ rv = plugin_cmp_certs (cert,
+ bvals[i]->bv_val,
+ bvals[i]->bv_len);
+
+ if (rv == LDAPU_SUCCESS) {
+ break;
+ }
+ }
+
+ ldap_value_free_len(bvals);
+
+ if (rv == LDAPU_SUCCESS) {
+ *entry_out = entry;
+ break;
+ }
+ }
+
+ return rv;
+}
+
+int plugin_init_fn (void *certmap_info, const char *issuerName,
+ const char *issuerDN)
+{
+ fprintf(stderr, "plugin_init_fn called.\n");
+ ldapu_set_cert_mapfn(issuerDN, plugin_mapping_fn);
+ ldapu_set_cert_verifyfn(issuerDN, plugin_verify_fn);
+ return LDAPU_SUCCESS;
+}
+
diff --git a/lib/ldaputil/utest/plugin.c b/lib/ldaputil/utest/plugin.c
new file mode 100644
index 00000000..29f7765b
--- /dev/null
+++ b/lib/ldaputil/utest/plugin.c
@@ -0,0 +1,115 @@
+/** 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 <string.h>
+#include <ctype.h>
+
+#include <plugin.h> /* must define extern "C" functions */
+#include <certmap.h> /* Public Certmap API */
+
+static CertSearchFn_t default_searchfn = 0;
+
+static int plugin_attr_val (void *cert, int which_dn, const char *attr)
+{
+ char **val;
+ int rv = ldapu_get_cert_ava_val(cert, which_dn, attr, &val);
+ char **attr_val = val; /* preserve the pointer for free */
+
+ if (rv != LDAPU_SUCCESS || !val) {
+ fprintf(stderr, "\t%s: *** Failed ***\n", attr);
+ }
+ else if (!*val) {
+ fprintf(stderr, "\t%s: *** Empty ***\n", attr);
+ }
+ else {
+ fprintf(stderr, "\t%s: \"%s\"", attr, *val++);
+ while(*val) {
+ fprintf(stderr, ", \"%s\"", *val++);
+ }
+ fprintf(stderr, "\n");
+ }
+
+ ldapu_free_cert_ava_val(attr_val);
+
+ return LDAPU_SUCCESS;
+}
+
+static int plugin_mapping_fn (void *cert, LDAP *ld, void *certmap_info,
+ char **ldapDN, char **filter)
+{
+ char *subjdn;
+ char *issuerDN;
+ char *ptr;
+ char *comma;
+
+ fprintf(stderr, "plugin_mapping_fn called.\n");
+ ldapu_get_cert_subject_dn(cert, &subjdn);
+ ldapu_get_cert_issuer_dn(cert, &issuerDN);
+
+ fprintf(stderr, "Value of attrs from subject DN & issuer DN:\n");
+ fprintf(stderr, "\tCert: \"%s\"\n", (char *)cert);
+ fprintf(stderr, "\tsubjdn: \"%s\"\n", subjdn);
+ plugin_attr_val(cert, LDAPU_SUBJECT_DN, "cn");
+ plugin_attr_val(cert, LDAPU_SUBJECT_DN, "ou");
+ plugin_attr_val(cert, LDAPU_SUBJECT_DN, "o");
+ plugin_attr_val(cert, LDAPU_SUBJECT_DN, "c");
+ fprintf(stderr, "\tissuerDN: \"%s\"\n", issuerDN);
+ plugin_attr_val(cert, LDAPU_ISSUER_DN, "cn");
+ plugin_attr_val(cert, LDAPU_ISSUER_DN, "ou");
+ plugin_attr_val(cert, LDAPU_ISSUER_DN, "o");
+ plugin_attr_val(cert, LDAPU_ISSUER_DN, "c");
+
+ if (subjdn && *subjdn) {
+ comma = ptr = strchr(subjdn, ',');
+
+ while(*ptr == ',' || isspace(*ptr)) ptr++;
+ *ldapDN = strdup(ptr);
+
+ /* Set filter to the first AVA in the subjdn */
+ *filter = subjdn;
+ *comma = 0;
+ }
+ else {
+ *ldapDN = 0;
+ *filter = 0;
+ }
+
+ return LDAPU_SUCCESS;
+}
+
+static int plugin_search_fn (void *cert, LDAP *ld, void *certmap_info,
+ const char *basedn,
+ const char *dn, const char *filter,
+ const char **attrs, LDAPMessage **res)
+{
+ fprintf(stderr, "plugin_search_fn called.\n");
+ return (*default_searchfn)(cert, ld, certmap_info, basedn, dn, filter,
+ attrs, res);
+}
+
+static int plugin_verify_fn (void *cert, LDAP *ld, void *certmap_info,
+ LDAPMessage *res, LDAPMessage **entry)
+{
+ fprintf(stderr, "plugin_verify_fn called.\n");
+ *entry = ldap_first_entry(ld, res);
+ return LDAPU_SUCCESS;
+}
+
+int plugin_init_fn (void *certmap_info, const char *issuerName,
+ const char *issuerDN)
+{
+ fprintf(stderr, "plugin_init_fn called.\n");
+ ldapu_set_cert_mapfn(issuerDN, plugin_mapping_fn);
+ ldapu_set_cert_verifyfn(issuerDN, plugin_verify_fn);
+
+ if (!default_searchfn)
+ default_searchfn = ldapu_get_cert_searchfn(issuerDN);
+
+ ldapu_set_cert_searchfn(issuerDN, plugin_search_fn);
+ return LDAPU_SUCCESS;
+}
+
diff --git a/lib/ldaputil/utest/plugin.h b/lib/ldaputil/utest/plugin.h
new file mode 100644
index 00000000..124a121a
--- /dev/null
+++ b/lib/ldaputil/utest/plugin.h
@@ -0,0 +1,20 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _CERTMAP_PLUGIN_H
+#define _CERTMAP_PLUGIN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int plugin_init_fn (void *certmap_info, const char *issuerName,
+ const char *issuerDN);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _CERTMAP_PLUGIN_H */
diff --git a/lib/ldaputil/utest/stubs.c b/lib/ldaputil/utest/stubs.c
new file mode 100644
index 00000000..03717331
--- /dev/null
+++ b/lib/ldaputil/utest/stubs.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 **/
+#include <ctype.h> /* isspace */
+#include <string.h>
+#include <stdio.h> /* sprintf */
+#include <stdlib.h> /* malloc */
+
+#include <ldap.h>
+#include <ldaputil/certmap.h>
+#include <ldaputil/cert.h>
+#include <ldaputil/errors.h>
+
+#define BIG_LINE 1024
+
+NSAPI_PUBLIC int ldapu_get_cert_subject_dn (void *cert_in, char **subjectDN)
+{
+ char *cert = (char *)cert_in;
+
+ *subjectDN = strdup((char *)cert);
+ return *subjectDN ? LDAPU_SUCCESS : LDAPU_FAILED;
+}
+
+NSAPI_PUBLIC int ldapu_get_cert_issuer_dn (void *cert, char **issuerDN)
+{
+ extern char *global_issuer_dn;
+ /* TEMPORARY -- not implemented yet*/
+ *issuerDN = global_issuer_dn ? strdup(global_issuer_dn) : 0;
+ return LDAPU_SUCCESS;
+}
+
+/* A stub to remove link errors -- ignore SSL */
+LDAP *ldapssl_init (const char *host, int port, int secure)
+{
+ LDAP *ld = 0;
+
+ if ((ld = ldap_init(host, port)) == NULL) {
+ fprintf(stderr, "ldap_init: Failed to initialize connection");
+ return(0);
+ }
+
+ return ld;
+}
+
+NSAPI_PUBLIC int ldapu_get_cert_ava_val (void *cert_in, int which_dn,
+ const char *attr, char ***val_out)
+{
+ int rv;
+ char *cert_dn;
+ char **ptr;
+ char **val;
+ char *dnptr;
+ char attr_eq1[BIG_LINE];
+ char attr_eq2[BIG_LINE];
+ char *comma;
+
+ *val_out = 0;
+
+ if (which_dn == LDAPU_SUBJECT_DN)
+ rv = ldapu_get_cert_subject_dn(cert_in, &cert_dn);
+ else if (which_dn == LDAPU_ISSUER_DN)
+ rv = ldapu_get_cert_issuer_dn(cert_in, &cert_dn);
+ else
+ return LDAPU_ERR_INVALID_ARGUMENT;
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ val = (char **)malloc(32*sizeof(char *));
+
+ if (!val) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ ptr = val;
+ sprintf(attr_eq1, "%s =", attr);
+ sprintf(attr_eq2, "%s=", attr);
+
+ while(cert_dn &&
+ ((dnptr = strstr(cert_dn, attr_eq1)) ||
+ (dnptr = strstr(cert_dn, attr_eq2))))
+ {
+ dnptr = strchr(dnptr, '=');
+ dnptr++;
+ while(isspace(*dnptr)) dnptr++;
+ comma = strchr(dnptr, ',');
+
+ if (comma) {
+ *ptr = (char *)malloc((comma-dnptr+1)*sizeof(char));
+ strncpy(*ptr, dnptr, (comma-dnptr));
+ (*ptr++)[comma-dnptr] = 0;
+ }
+ else {
+ *ptr++ = strdup(dnptr);
+ }
+ cert_dn = comma;
+ }
+
+ *ptr = 0;
+ *val_out = val;
+ return LDAPU_SUCCESS;
+}
+
+NSAPI_PUBLIC int ldapu_get_cert_der (void *cert_in, unsigned char **der,
+ unsigned int *len)
+{
+ return LDAPU_FAILED;
+}
diff --git a/lib/ldaputil/utest/stubs.cpp b/lib/ldaputil/utest/stubs.cpp
new file mode 100644
index 00000000..92e6f978
--- /dev/null
+++ b/lib/ldaputil/utest/stubs.cpp
@@ -0,0 +1,102 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <ctype.h> /* isspace */
+#include <string.h>
+#include <stdio.h> /* sprintf */
+#include <stdlib.h> /* malloc */
+
+#include <ldaputil/ldaputil.h>
+#include <ldaputil/cert.h>
+#include <ldaputil/errors.h>
+#include "../ldaputili.h"
+
+#define BIG_LINE 1024
+
+NSAPI_PUBLIC int ldapu_get_cert_subject_dn (void *cert_in, char **subjectDN)
+{
+ char *cert = (char *)cert_in;
+
+ *subjectDN = strdup((char *)cert);
+ return *subjectDN ? LDAPU_SUCCESS : LDAPU_FAILED;
+}
+
+NSAPI_PUBLIC int ldapu_get_cert_issuer_dn (void *cert, char **issuerDN)
+{
+ /* TEMPORARY -- not implemented yet*/
+ *issuerDN = strdup("o=Netscape Communications, c=US");
+ return *issuerDN ? LDAPU_SUCCESS : LDAPU_FAILED;
+}
+
+NSAPI_PUBLIC int ldapu_get_cert_ava_val (void *cert_in, int which_dn,
+ const char *attr, char ***val_out)
+{
+ int rv;
+ char *cert_dn;
+ char **ptr;
+ char **val;
+ char *dnptr;
+ char attr_eq1[BIG_LINE];
+ char attr_eq2[BIG_LINE];
+ char *comma;
+
+ *val_out = 0;
+
+ if (which_dn == LDAPU_SUBJECT_DN)
+ rv = ldapu_get_cert_subject_dn(cert_in, &cert_dn);
+ else if (which_dn == LDAPU_ISSUER_DN)
+ rv = ldapu_get_cert_issuer_dn(cert_in, &cert_dn);
+ else
+ return LDAPU_ERR_INVALID_ARGUMENT;
+
+ if (rv != LDAPU_SUCCESS) return rv;
+
+ val = (char **)malloc(32*sizeof(char *));
+
+ if (!val) return LDAPU_ERR_OUT_OF_MEMORY;
+
+ ptr = val;
+ sprintf(attr_eq1, "%s =", attr);
+ sprintf(attr_eq2, "%s=", attr);
+
+ while(cert_dn &&
+ ((dnptr = strstr(cert_dn, attr_eq1)) ||
+ (dnptr = strstr(cert_dn, attr_eq2))))
+ {
+ dnptr = strchr(dnptr, '=');
+ dnptr++;
+ while(isspace(*dnptr)) dnptr++;
+ comma = strchr(dnptr, ',');
+
+ if (comma) {
+ *ptr = (char *)malloc((comma-dnptr+1)*sizeof(char));
+ strncpy(*ptr, dnptr, (comma-dnptr));
+ (*ptr++)[comma-dnptr] = 0;
+ }
+ else {
+ *ptr++ = strdup(dnptr);
+ }
+ cert_dn = comma;
+ }
+
+ *ptr = 0;
+ *val_out = val;
+ return LDAPU_SUCCESS;
+}
+
+NSAPI_PUBLIC int ldapu_get_cert_der (void *cert_in, unsigned char **der,
+ unsigned int *len)
+{
+ return LDAPU_FAILED;
+}
+
+int
+ldapu_member_certificate_match (void* cert, const char* desc)
+{
+ if (!strcasecmp ((char*)cert, desc)) {
+ return LDAPU_SUCCESS;
+ }
+ return LDAPU_FAILED;
+}
diff --git a/lib/ldaputil/utest/test.ref b/lib/ldaputil/utest/test.ref
new file mode 100644
index 00000000..fae39056
--- /dev/null
+++ b/lib/ldaputil/utest/test.ref
@@ -0,0 +1,448 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+Start of test: ./auth 1 "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US" "cn=Directory Administrators, o=Ace Industry, c=US"
+
+userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+groupdn: "cn=Directory Administrators, o=Ace Industry, c=US"
+ base: "cn=Directory Administrators, o=Ace Industry, c=US"
+ filter: "(| (uniquemember=cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US) (member=cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US))"
+ scope: "LDAP_SCOPE_BASE"
+Authentication succeeded.
+
+Start of test: ./auth 1 "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US" "cn=Directory Administrators, o=Ace Industry, c=US"
+
+userdn: "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US"
+groupdn: "cn=Directory Administrators, o=Ace Industry, c=US"
+ base: "cn=Directory Administrators, o=Ace Industry, c=US"
+ filter: "(| (uniquemember=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US) (member=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US))"
+ scope: "LDAP_SCOPE_BASE"
+ldap_search_s: Entry not found
+Find parent groups of "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (| (uniquemember=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US) (member=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US)) (| (objectclass=groupofuniquenames) (objectclass=groupofnames)))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ldap_search_s: Entry not found
+Authentication failed.
+
+Start of test: ./auth 2 "hmiller" "cn=Directory Administrators, o=Ace Industry, c=US"
+
+uid: "hmiller"
+groupdn: "cn=Directory Administrators, o=Ace Industry, c=US"
+ base: "o=Ace Industry, c=US"
+ filter: "uid=hmiller"
+ scope: "LDAP_SCOPE_SUBTREE"
+ base: "cn=Directory Administrators, o=Ace Industry, c=US"
+ filter: "(| (uniquemember=cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US) (member=cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US))"
+ scope: "LDAP_SCOPE_BASE"
+Authentication succeeded.
+
+Start of test: ./auth 2 "scarter" "cn=Directory Administrators, o=Ace Industry, c=US"
+
+uid: "scarter"
+groupdn: "cn=Directory Administrators, o=Ace Industry, c=US"
+ base: "o=Ace Industry, c=US"
+ filter: "uid=scarter"
+ scope: "LDAP_SCOPE_SUBTREE"
+ base: "cn=Directory Administrators, o=Ace Industry, c=US"
+ filter: "(| (uniquemember=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US) (member=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US))"
+ scope: "LDAP_SCOPE_BASE"
+ldap_search_s: Entry not found
+Find parent groups of "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (| (uniquemember=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US) (member=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US)) (| (objectclass=groupofuniquenames) (objectclass=groupofnames)))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ldap_search_s: Entry not found
+Authentication failed.
+
+Start of test: ./auth 3 "hmiller" "Directory Administrators"
+
+uid: "hmiller"
+groupid: "Directory Administrators"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (cn=Directory Administrators) (| (objectclass=groupofuniquenames) (objectclass=groupofnames)))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ base: "o=Ace Industry, c=US"
+ filter: "uid=hmiller"
+ scope: "LDAP_SCOPE_SUBTREE"
+ base: "cn=Directory Administrators, o=Ace Industry, c=US"
+ filter: "(| (uniquemember=cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US) (member=cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US))"
+ scope: "LDAP_SCOPE_BASE"
+Authentication succeeded.
+
+Start of test: ./auth 3 "scarter" "Directory Administrators"
+
+uid: "scarter"
+groupid: "Directory Administrators"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (cn=Directory Administrators) (| (objectclass=groupofuniquenames) (objectclass=groupofnames)))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ base: "o=Ace Industry, c=US"
+ filter: "uid=scarter"
+ scope: "LDAP_SCOPE_SUBTREE"
+ base: "cn=Directory Administrators, o=Ace Industry, c=US"
+ filter: "(| (uniquemember=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US) (member=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US))"
+ scope: "LDAP_SCOPE_BASE"
+ldap_search_s: Entry not found
+Find parent groups of "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (| (uniquemember=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US) (member=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US)) (| (objectclass=groupofuniquenames) (objectclass=groupofnames)))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ldap_search_s: Entry not found
+Authentication failed.
+
+Start of test: ./auth 4 "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US" "Directory Administrators"
+
+userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+groupid: "Directory Administrators"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (cn=Directory Administrators) (| (objectclass=groupofuniquenames) (objectclass=groupofnames)))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ base: "cn=Directory Administrators, o=Ace Industry, c=US"
+ filter: "(| (uniquemember=cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US) (member=cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US))"
+ scope: "LDAP_SCOPE_BASE"
+Authentication succeeded.
+
+Start of test: ./auth 4 "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US" "Directory Administrators"
+
+userdn: "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US"
+groupid: "Directory Administrators"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (cn=Directory Administrators) (| (objectclass=groupofuniquenames) (objectclass=groupofnames)))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ base: "cn=Directory Administrators, o=Ace Industry, c=US"
+ filter: "(| (uniquemember=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US) (member=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US))"
+ scope: "LDAP_SCOPE_BASE"
+ldap_search_s: Entry not found
+Find parent groups of "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (| (uniquemember=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US) (member=cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US)) (| (objectclass=groupofuniquenames) (objectclass=groupofnames)))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ldap_search_s: Entry not found
+Authentication failed.
+
+Start of test: ./auth 5 "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US" "mail=hmiller@aceindustry.com"
+
+userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+attrFilter: "mail=hmiller@aceindustry.com"
+ base: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+ filter: "mail=hmiller@aceindustry.com"
+ scope: "LDAP_SCOPE_BASE"
+Authentication succeeded.
+
+Start of test: ./auth 5 "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US" "mail=scarter@aceindustry.com"
+
+userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+attrFilter: "mail=scarter@aceindustry.com"
+ base: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+ filter: "mail=scarter@aceindustry.com"
+ scope: "LDAP_SCOPE_BASE"
+ldap_search_s: Entry not found
+Authentication failed.
+
+Start of test: ./auth 5 "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US" "mail=hmiller@aceindustry.com"
+
+userdn: "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US"
+attrFilter: "mail=hmiller@aceindustry.com"
+ base: "cn=Sam Carter, ou=Accounting, o=Ace Industry, c=US"
+ filter: "mail=hmiller@aceindustry.com"
+ scope: "LDAP_SCOPE_BASE"
+ldap_search_s: Entry not found
+Authentication failed.
+
+Start of test: ./auth 6 "hmiller" "mail=hmiller@aceindustry.com"
+
+uid: "hmiller"
+attrFilter: "mail=hmiller@aceindustry.com"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (uid=hmiller) (mail=hmiller@aceindustry.com))"
+ scope: "LDAP_SCOPE_SUBTREE"
+Authentication succeeded.
+
+Start of test: ./auth 6 "hmiller" "mail=scarter@aceindustry.com"
+
+uid: "hmiller"
+attrFilter: "mail=scarter@aceindustry.com"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (uid=hmiller) (mail=scarter@aceindustry.com))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ldap_search_s: Entry not found
+Authentication failed.
+
+Start of test: ./auth 6 "scarter" "mail=hmiller@aceindustry.com"
+
+uid: "scarter"
+attrFilter: "mail=hmiller@aceindustry.com"
+ base: "o=Ace Industry, c=US"
+ filter: "(& (uid=scarter) (mail=hmiller@aceindustry.com))"
+ scope: "LDAP_SCOPE_SUBTREE"
+ldap_search_s: Entry not found
+Authentication failed.
+
+Start of test: ./auth 7 "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US" "hillock"
+
+userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+password: "hillock"
+ userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+ password: "hillock"
+Authentication succeeded.
+
+Start of test: ./auth 7 "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US" "garbage"
+
+userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+password: "garbage"
+ userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+ password: "garbage"
+ldap_simple_bind_s: Invalid credentials
+Authentication failed.
+
+Start of test: ./auth 8 "hmiller" "hillock"
+
+uid: "hmiller"
+password: "hillock"
+ base: "o=Ace Industry, c=US"
+ filter: "uid=hmiller"
+ scope: "LDAP_SCOPE_SUBTREE"
+ userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+ password: "hillock"
+Authentication succeeded.
+
+Start of test: ./auth 8 "hmiller" "garbage"
+
+uid: "hmiller"
+password: "garbage"
+ base: "o=Ace Industry, c=US"
+ filter: "uid=hmiller"
+ scope: "LDAP_SCOPE_SUBTREE"
+ userdn: "cn=Harry Miller, ou=Human Resources, o=Ace Industry, c=US"
+ password: "garbage"
+ldap_simple_bind_s: Invalid credentials
+Authentication failed.
+
+Start of test: ./auth 9 "o=Ace Industry, c=US" "cn=Kirsten Vaughan, ou=Human Resources, o=Ace Industry, c=US"
+Cert Map issuer DN: "o=Ace Industry, c=US"
+Cert Map subject DN: "cn=Kirsten Vaughan, ou=Human Resources, o=Ace Industry, c=US"
+plugin_init_fn called.
+plugin_init_fn called.
+plugin_mapping_fn called.
+Value of attrs from subject DN & issuer DN:
+ Cert: "cn=Kirsten Vaughan, ou=Human Resources, o=Ace Industry, c=US"
+ subjdn: "cn=Kirsten Vaughan, ou=Human Resources, o=Ace Industry, c=US"
+ cn: "Kirsten Vaughan"
+ ou: "Human Resources"
+ o: "Ace Industry"
+ c: "US"
+ issuerDN: "o=Ace Industry, c=US"
+ cn: *** Empty ***
+ ou: *** Empty ***
+ o: "Ace Industry"
+ c: "US"
+plugin_search_fn called.
+ base: "ou=Human Resources, o=Ace Industry, c=US"
+ filter: "cn=Kirsten Vaughan"
+ scope: "LDAP_SCOPE_BASE"
+ldap_search_s: Entry not found
+ base: "ou=Human Resources, o=Ace Industry, c=US"
+ filter: "cn=Kirsten Vaughan"
+ scope: "LDAP_SCOPE_SUBTREE"
+plugin_verify_fn called.
+Matched entry to cert: "cn=Kirsten Vaughan, ou=Human Resources, o=Ace Industry, c=US"
+Authentication succeeded.
+
+Start of test: ./auth 10 "cn=Foo Bar, o=Netscape Communication, c=US" "foobar"
+Config file written: config_out.conf
+binddn from config file: "cn=Foo Bar, o=Netscape Communication, c=US"
+bindpw from config file: "foobar"
+Config file test succeeded
+Authentication succeeded.
+
+Start of test: ./auth 11 "dblist.conf" "ignore"
+ dbname[0] = "default"
+ dbname[1] = "default1"
+ dbname[2] = "default2"
+ dbname[3] = "default3"
+ dbname[4] = "default4"
+ dbname[5] = "default5"
+ dbname[6] = "default6"
+Authentication succeeded.
+
+Start of test: ./auth 12 "certmap.new" "certmap.conf"
+plugin_init_fn called.
+plugin_init_fn called.
+Authentication succeeded.
+
+# Comments before any certmap directive - line 1
+# Comments before any certmap directive - line 2
+
+# Comments before any certmap directive - line 3
+# Comments before any certmap directive - line 4
+# Comments before any certmap directive - line 5
+
+
+# Comments before any certmap directive - line 6
+
+certmap default default
+#default:DNComps o, ou ,c
+#default:FilterComps cn
+
+
+certmap default1 o=Netscape Communications, c=US
+default1:library ./plugin.so
+default1:InitFn plugin_init_fn
+default1:DNComps ou o c
+default1:FilterComps l
+#default1:verifycert
+
+# Following line has trailing spaces
+certmap default2 o=Ace Industry, c=US
+default2:InitFn plugin_init_fn
+default2:DNComps cn o ou c
+default2:FilterComps l
+default2:verifycert on
+
+# Comments before any certmap directive - line 1
+# Comments before any certmap directive - line 2
+
+# Comments before any certmap directive - line 3
+# Comments before any certmap directive - line 4
+# Comments before any certmap directive - line 5
+
+
+# Comments before any certmap directive - line 6
+
+certmap default default
+
+certmap default1 o=Netscape Communications, c=US
+default1:library ./plugin.so
+default1:InitFn plugin_init_fn
+default1:DNComps ou o c
+default1:FilterComps l
+
+certmap default2 o=Ace Industry, c=US
+default2:InitFn plugin_init_fn
+default2:DNComps cn o ou c
+default2:FilterComps l
+default2:verifycert on
+
+
+Start of test: ./auth 13 "certmap.new" "certmap.conf"
+plugin_init_fn called.
+plugin_init_fn called.
+Authentication succeeded.
+
+# Comments before any certmap directive - line 1
+# Comments before any certmap directive - line 2
+
+# Comments before any certmap directive - line 3
+# Comments before any certmap directive - line 4
+# Comments before any certmap directive - line 5
+
+
+# Comments before any certmap directive - line 6
+
+certmap default default
+#default:DNComps o, ou ,c
+#default:FilterComps cn
+
+
+certmap default1 o=Netscape Communications, c=US
+default1:library ./plugin.so
+default1:InitFn plugin_init_fn
+default1:DNComps ou o c
+default1:FilterComps l
+#default1:verifycert
+
+# Following line has trailing spaces
+certmap default2 o=Ace Industry, c=US
+default2:InitFn plugin_init_fn
+default2:DNComps cn o ou c
+default2:FilterComps l
+default2:verifycert on
+
+# Comments before any certmap directive - line 1
+# Comments before any certmap directive - line 2
+
+# Comments before any certmap directive - line 3
+# Comments before any certmap directive - line 4
+# Comments before any certmap directive - line 5
+
+
+# Comments before any certmap directive - line 6
+
+certmap default default
+
+certmap default2 o=Ace Industry, c=US
+default2:InitFn plugin_init_fn
+default2:DNComps cn o ou c
+default2:FilterComps l
+default2:verifycert on
+
+
+Start of test: ./auth 14 "certmap.new" "certmap.conf"
+plugin_init_fn called.
+plugin_init_fn called.
+Authentication succeeded.
+
+# Comments before any certmap directive - line 1
+# Comments before any certmap directive - line 2
+
+# Comments before any certmap directive - line 3
+# Comments before any certmap directive - line 4
+# Comments before any certmap directive - line 5
+
+
+# Comments before any certmap directive - line 6
+
+certmap default default
+#default:DNComps o, ou ,c
+#default:FilterComps cn
+
+
+certmap default1 o=Netscape Communications, c=US
+default1:library ./plugin.so
+default1:InitFn plugin_init_fn
+default1:DNComps ou o c
+default1:FilterComps l
+#default1:verifycert
+
+# Following line has trailing spaces
+certmap default2 o=Ace Industry, c=US
+default2:InitFn plugin_init_fn
+default2:DNComps cn o ou c
+default2:FilterComps l
+default2:verifycert on
+
+# Comments before any certmap directive - line 1
+# Comments before any certmap directive - line 2
+
+# Comments before any certmap directive - line 3
+# Comments before any certmap directive - line 4
+# Comments before any certmap directive - line 5
+
+
+# Comments before any certmap directive - line 6
+
+certmap default default
+
+certmap default1 o=Netscape Communications, c=US
+default1:library ./plugin.so
+default1:InitFn plugin_init_fn
+default1:DNComps ou o c
+default1:FilterComps l
+
+certmap default2 o=Ace Industry, c=US
+default2:InitFn plugin_init_fn
+default2:DNComps cn o ou c
+default2:FilterComps l
+default2:verifycert on
+
+certmap newmap o=Mcom Communications, c=US
+newmap:prop1 val1
+newmap:prop2 val2
+newmap:prop3
+
diff --git a/lib/ldaputil/vtable.c b/lib/ldaputil/vtable.c
new file mode 100644
index 00000000..b50678c4
--- /dev/null
+++ b/lib/ldaputil/vtable.c
@@ -0,0 +1,427 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include "ldaputili.h"
+#include <ldap.h>
+#ifdef USE_LDAP_SSL
+#include <ldap_ssl.h>
+#endif
+
+#if defined( _WINDOWS ) && ! defined( _WIN32 )
+/* On 16-bit WINDOWS platforms, it's erroneous to call LDAP API functions
+ * via a function pointer, since they are not declared LDAP_CALLBACK.
+ * So, we define the following functions, which are LDAP_CALLBACK, and
+ * simply delegate to their counterparts in the LDAP API.
+ */
+
+#ifdef USE_LDAP_SSL
+static LDAP_CALL LDAP_CALLBACK LDAP*
+ldapuVd_ssl_init( const char *host, int port, int encrypted )
+{
+ return ldapssl_init (host, port, encrypted);
+}
+#else
+static LDAP_CALL LDAP_CALLBACK LDAP*
+ldapuVd_init ( const char *host, int port )
+{
+ return ldap_init (host, port);
+}
+#endif
+
+static LDAP_CALL LDAP_CALLBACK int
+ldapuVd_set_option( LDAP *ld, int opt, void *val )
+{
+ return ldap_set_option (ld, opt, val);
+}
+
+static LDAP_CALL LDAP_CALLBACK int
+ldapuVd_simple_bind_s( LDAP* ld, const char *username, const char *passwd )
+{
+ return ldap_simple_bind_s (ld, username, passwd);
+}
+
+static LDAP_CALL LDAP_CALLBACK int
+ldapuVd_unbind( LDAP *ld )
+{
+ return ldap_unbind (ld);
+}
+
+static LDAP_CALL LDAP_CALLBACK int
+ldapuVd_search_s( LDAP* ld, const char* baseDN, int scope, const char* filter,
+ char** attrs, int attrsonly, LDAPMessage** result )
+{
+ return ldap_search_s (ld, baseDN, scope, filter, attrs, attrsonly, result);
+}
+
+static LDAP_CALL LDAP_CALLBACK int
+ldapuVd_count_entries( LDAP* ld, LDAPMessage* msg )
+{
+ return ldap_count_entries (ld, msg);
+}
+
+static LDAP_CALL LDAP_CALLBACK LDAPMessage*
+ldapuVd_first_entry( LDAP* ld, LDAPMessage* msg )
+{
+ return ldap_first_entry (ld, msg);
+}
+
+static LDAP_CALL LDAP_CALLBACK LDAPMessage*
+ldapuVd_next_entry( LDAP* ld, LDAPMessage* entry )
+{
+ return ldap_next_entry(ld, entry);
+}
+
+static LDAP_CALL LDAP_CALLBACK char*
+ldapuVd_get_dn( LDAP* ld, LDAPMessage* entry )
+{
+ return ldap_get_dn (ld, entry);
+}
+
+static LDAP_CALL LDAP_CALLBACK char*
+ldapuVd_first_attribute( LDAP* ld, LDAPMessage* entry, BerElement** iter )
+{
+ return ldap_first_attribute (ld, entry, iter);
+}
+
+static LDAP_CALL LDAP_CALLBACK char*
+ldapuVd_next_attribute( LDAP* ld, LDAPMessage* entry, BerElement* iter)
+{
+ return ldap_next_attribute (ld, entry, iter);
+}
+
+static LDAP_CALL LDAP_CALLBACK char**
+ldapuVd_get_values( LDAP *ld, LDAPMessage *entry, const char *desc )
+{
+ return ldap_get_values (ld, entry, desc);
+}
+
+static LDAP_CALL LDAP_CALLBACK struct berval**
+ldapuVd_get_values_len( LDAP *ld, LDAPMessage *entry, const char *desc )
+{
+ return ldap_get_values_len (ld, entry, desc);
+}
+
+#else
+/* On other platforms, an LDAP API function can be called via a pointer. */
+#ifdef USE_LDAP_SSL
+#define ldapuVd_ssl_init ldapssl_init
+#else
+#define ldapuVd_init ldap_init
+#endif
+#define ldapuVd_set_option ldap_set_option
+#define ldapuVd_simple_bind_s ldap_simple_bind_s
+#define ldapuVd_unbind ldap_unbind
+#define ldapuVd_set_option ldap_set_option
+#define ldapuVd_simple_bind_s ldap_simple_bind_s
+#define ldapuVd_unbind ldap_unbind
+#define ldapuVd_search_s ldap_search_s
+#define ldapuVd_count_entries ldap_count_entries
+#define ldapuVd_first_entry ldap_first_entry
+#define ldapuVd_next_entry ldap_next_entry
+#define ldapuVd_get_dn ldap_get_dn
+#define ldapuVd_first_attribute ldap_first_attribute
+#define ldapuVd_next_attribute ldap_next_attribute
+#define ldapuVd_get_values ldap_get_values
+#define ldapuVd_get_values_len ldap_get_values_len
+
+#endif
+
+/* Several functions in the standard LDAP API have no LDAP* parameter,
+ but all the VTable functions do. Here are some little functions that
+ make up the difference, by ignoring their LDAP* parameter:
+*/
+static int LDAP_CALL LDAP_CALLBACK
+ldapuVd_msgfree( LDAP *ld, LDAPMessage *chain )
+{
+ return ldap_msgfree (chain);
+}
+
+static void LDAP_CALL LDAP_CALLBACK
+ldapuVd_memfree( LDAP *ld, void *dn )
+{
+ ldap_memfree (dn);
+}
+
+static void LDAP_CALL LDAP_CALLBACK
+ldapuVd_ber_free( LDAP *ld, BerElement *ber, int freebuf )
+{
+ ldap_ber_free (ber, freebuf);
+}
+
+static void LDAP_CALL LDAP_CALLBACK
+ldapuVd_value_free( LDAP *ld, char **vals )
+{
+ ldap_value_free (vals);
+}
+
+static void LDAP_CALL LDAP_CALLBACK
+ldapuVd_value_free_len( LDAP *ld, struct berval **vals )
+{
+ ldap_value_free_len (vals);
+}
+
+static LDAPUVTable_t ldapu_VTable = {
+/* By default, the VTable points to the standard LDAP API. */
+#ifdef USE_LDAP_SSL
+ ldapuVd_ssl_init,
+#else
+ ldapuVd_init,
+#endif
+ ldapuVd_set_option,
+ ldapuVd_simple_bind_s,
+ ldapuVd_unbind,
+ ldapuVd_search_s,
+ ldapuVd_count_entries,
+ ldapuVd_first_entry,
+ ldapuVd_next_entry,
+ ldapuVd_msgfree,
+ ldapuVd_get_dn,
+ ldapuVd_memfree,
+ ldapuVd_first_attribute,
+ ldapuVd_next_attribute,
+ ldapuVd_ber_free,
+ ldapuVd_get_values,
+ ldapuVd_value_free,
+ ldapuVd_get_values_len,
+ ldapuVd_value_free_len
+};
+
+/* Replace ldapu_VTable. Subsequently, ldaputil will call the
+ functions in 'from' (not the LDAP API) to access the directory.
+ */
+void
+ldapu_VTable_set (LDAPUVTable_t* from)
+{
+ if (from) {
+ memcpy (&ldapu_VTable, from, sizeof(LDAPUVTable_t));
+ }
+}
+
+#ifdef USE_LDAP_SSL
+LDAP*
+ldapu_ssl_init( const char *defhost, int defport, int defsecure )
+{
+ if (ldapu_VTable.ldapuV_ssl_init) {
+ return ldapu_VTable.ldapuV_ssl_init (defhost, defport, defsecure);
+ }
+ return NULL;
+}
+#else
+LDAP*
+ldapu_init( const char *defhost, int defport )
+{
+ if (ldapu_VTable.ldapuV_init) {
+ return ldapu_VTable.ldapuV_init (defhost, defport);
+ }
+ return NULL;
+}
+#endif
+
+int
+ldapu_set_option( LDAP *ld, int option, void *optdata )
+{
+ if (ldapu_VTable.ldapuV_set_option) {
+ return ldapu_VTable.ldapuV_set_option (ld, option, optdata);
+ }
+ return LDAP_LOCAL_ERROR;
+}
+
+int
+ldapu_simple_bind_s( LDAP *ld, const char *who, const char *passwd )
+{
+ if (ldapu_VTable.ldapuV_simple_bind_s) {
+ return ldapu_VTable.ldapuV_simple_bind_s (ld, who, passwd);
+ }
+ return LDAP_LOCAL_ERROR;
+}
+
+int
+ldapu_unbind( LDAP *ld )
+{
+ if (ldapu_VTable.ldapuV_unbind) {
+ return ldapu_VTable.ldapuV_unbind (ld);
+ }
+ return LDAP_LOCAL_ERROR;
+}
+
+int
+ldapu_search_s( LDAP *ld, const char *base, int scope,
+ const char *filter, char **attrs, int attrsonly, LDAPMessage **res )
+{
+ if (ldapu_VTable.ldapuV_search_s) {
+ return ldapu_VTable.ldapuV_search_s (ld, base, scope, filter, attrs, attrsonly, res);
+ }
+ return LDAP_LOCAL_ERROR;
+}
+
+int
+ldapu_count_entries( LDAP *ld, LDAPMessage *chain )
+{
+ if (ldapu_VTable.ldapuV_count_entries) {
+ return ldapu_VTable.ldapuV_count_entries (ld, chain);
+ }
+ return 0;
+}
+
+LDAPMessage*
+ldapu_first_entry( LDAP *ld, LDAPMessage *chain )
+{
+ if (ldapu_VTable.ldapuV_first_entry) {
+ return ldapu_VTable.ldapuV_first_entry (ld, chain);
+ }
+ return NULL;
+}
+
+LDAPMessage*
+ldapu_next_entry( LDAP *ld, LDAPMessage *entry )
+{
+ if (ldapu_VTable.ldapuV_next_entry) {
+ return ldapu_VTable.ldapuV_next_entry (ld, entry);
+ }
+ return NULL;
+}
+
+int
+ldapu_msgfree( LDAP* ld, LDAPMessage *chain )
+{
+ if (ldapu_VTable.ldapuV_msgfree) {
+ return ldapu_VTable.ldapuV_msgfree (ld, chain);
+ }
+ return LDAP_SUCCESS;
+}
+
+char*
+ldapu_get_dn( LDAP *ld, LDAPMessage *entry )
+{
+ if (ldapu_VTable.ldapuV_get_dn) {
+ return ldapu_VTable.ldapuV_get_dn (ld, entry);
+ }
+ return NULL;
+}
+
+void
+ldapu_memfree( LDAP* ld, void *p )
+{
+ if (ldapu_VTable.ldapuV_memfree) {
+ ldapu_VTable.ldapuV_memfree (ld, p);
+ }
+}
+
+char*
+ldapu_first_attribute( LDAP *ld, LDAPMessage *entry, BerElement **ber )
+{
+ if (ldapu_VTable.ldapuV_first_attribute) {
+ return ldapu_VTable.ldapuV_first_attribute (ld, entry, ber);
+ }
+ return NULL;
+}
+
+char*
+ldapu_next_attribute( LDAP *ld, LDAPMessage *entry, BerElement *ber )
+{
+ if (ldapu_VTable.ldapuV_next_attribute) {
+ return ldapu_VTable.ldapuV_next_attribute (ld, entry, ber);
+ }
+ return NULL;
+}
+
+void
+ldapu_ber_free( LDAP* ld, BerElement *ber, int freebuf )
+{
+ if (ldapu_VTable.ldapuV_ber_free) {
+ ldapu_VTable.ldapuV_ber_free (ld, ber, freebuf);
+ }
+}
+
+char**
+ldapu_get_values( LDAP *ld, LDAPMessage *entry, const char *desc )
+{
+ if (ldapu_VTable.ldapuV_get_values) {
+ return ldapu_VTable.ldapuV_get_values (ld, entry, desc);
+ } else if (!ldapu_VTable.ldapuV_value_free
+ && ldapu_VTable.ldapuV_get_values_len) {
+ auto struct berval** bvals =
+ ldapu_VTable.ldapuV_get_values_len (ld, entry, desc);
+ if (bvals) {
+ auto char** vals = (char**)
+ ldapu_malloc ((ldap_count_values_len (bvals) + 1)
+ * sizeof(char*));
+ if (vals) {
+ auto char** val;
+ auto struct berval** bval;
+ for (val = vals, bval = bvals; *bval; ++val, ++bval) {
+ auto const size_t len = (*bval)->bv_len;
+ *val = (char*) ldapu_malloc (len + 1);
+ memcpy (*val, (*bval)->bv_val, len);
+ (*val)[len] = '\0';
+ }
+ *val = NULL;
+ ldapu_value_free_len(ld, bvals);
+ return vals;
+ }
+ }
+ ldapu_value_free_len(ld, bvals);
+ }
+ return NULL;
+}
+
+void
+ldapu_value_free( LDAP *ld, char **vals )
+{
+ if (ldapu_VTable.ldapuV_value_free) {
+ ldapu_VTable.ldapuV_value_free (ld, vals);
+ } else if (!ldapu_VTable.ldapuV_get_values && vals) {
+ auto char** val;
+ for (val = vals; *val; ++val) {
+ free (*val);
+ }
+ free (vals);
+ }
+}
+
+struct berval**
+ldapu_get_values_len( LDAP *ld, LDAPMessage *entry, const char *desc )
+{
+ if (ldapu_VTable.ldapuV_get_values_len) {
+ return ldapu_VTable.ldapuV_get_values_len (ld, entry, desc);
+ } else if (!ldapu_VTable.ldapuV_value_free_len
+ && ldapu_VTable.ldapuV_get_values) {
+ auto char** vals =
+ ldapu_VTable.ldapuV_get_values (ld, entry, desc);
+ if (vals) {
+ auto struct berval** bvals = (struct berval**)
+ ldapu_malloc ((ldap_count_values (vals) + 1)
+ * sizeof(struct berval*));
+ if (bvals) {
+ auto char** val;
+ auto struct berval** bval;
+ for (val = vals, bval = bvals; *val; ++val, ++bval) {
+ auto const size_t len = strlen(*val);
+ *bval = (struct berval*) ldapu_malloc (sizeof(struct berval) + len);
+ (*bval)->bv_len = len;
+ (*bval)->bv_val = ((char*)(*bval)) + sizeof(struct berval);
+ memcpy ((*bval)->bv_val, *val, len);
+ }
+ *bval = NULL;
+ return bvals;
+ }
+ }
+ }
+ return NULL;
+}
+
+void
+ldapu_value_free_len( LDAP *ld, struct berval **vals )
+{
+ if (ldapu_VTable.ldapuV_value_free_len) {
+ ldapu_VTable.ldapuV_value_free_len (ld, vals);
+ } else if (!ldapu_VTable.ldapuV_get_values_len && vals) {
+ auto struct berval** val;
+ for (val = vals; *val; ++val) {
+ free (*val);
+ }
+ free (vals);
+ }
+}
diff --git a/lib/libaccess/Makefile b/lib/libaccess/Makefile
new file mode 100644
index 00000000..1ed3b58a
--- /dev/null
+++ b/lib/libaccess/Makefile
@@ -0,0 +1,176 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Makefile for libaccess.a
+#
+MCOM_ROOT=../../..
+MODULE=LibAccess
+include ../../nsdefs.mk
+
+OBJDEST=$(OBJDIR)/lib/libaccess
+UTESTDEST=$(OBJDIR)/lib/libaccess/utest
+LEX=flex
+
+include ../../nsconfig.mk
+
+MCC_INCLUDE += $(ADMINUTIL_INCLUDE)
+
+ifeq ($(ARCH), WINNT)
+LIBS=$(OBJDIR)/lib/libaccess.lib
+CC=cl -nologo -MT
+VALUES=$(OBJDEST)/values.h
+else
+VALUES=
+LIBS=$(OBJDIR)/lib/libaccess.a
+endif
+
+all: $(OBJDEST) $(LIBS)
+
+$(OBJDEST):
+ mkdir -p $(OBJDEST)
+
+$(UTESTDEST):
+ mkdir -p $(UTESTDEST)
+
+OSOBJS =
+
+OBJS=$(addprefix $(OBJDEST)/, usi.o \
+ attrec.o \
+ nseframe.o \
+ nsdb.o \
+ nsdbmgmt.o \
+ nsuser.o \
+ nsumgmt.o \
+ nsgroup.o \
+ nsgmgmt.o \
+ nsadb.o \
+ nscert.o \
+ nsamgmt.o \
+ nsautherr.o \
+ symbols.o \
+ acltools.o \
+ aclutil.o \
+ aclcache.o \
+ aclflush.o \
+ authdb.o \
+ method.o \
+ ldapacl.o \
+ register.o \
+ lasdns.o \
+ lasip.o \
+ lastod.o \
+ usrcache.o \
+ lasgroup.o \
+ lasuser.o \
+ lasprogram.o \
+ aclspace.o \
+ acl.tab.o \
+ acl.yy.o \
+ acleval.o \
+ oneeval.o \
+ access_plhash.o \
+ aclparse.o \
+ aclbuild.o \
+ aclerror.o \
+ acladmin.o \
+ aclcgi.o \
+ $(OSOBJS) \
+ )
+
+#
+# AVA Mapping files. Currently not compiled in (FORTEZZA for reference only).
+#
+AVAMAPFILES = lex.yy.o y.tab.o avapfile.o avadb.o
+
+MODULE_CFLAGS=-I$(NSROOT)/include -DACL_LIB_INTERNAL $(TESTFLAGS)
+
+ifeq ($(LDAP_NO_LIBLCACHE),1)
+MODULE_CFLAGS+=-DNO_LIBLCACHE
+endif
+
+LOCAL_DEPS = $(LDAPSDK_DEP)
+
+$(LIBS): $(LOCAL_DEPS) $(OBJS)
+ rm -f $@
+ $(AR) $(OBJS)
+ $(RANLIB) $@
+
+include $(INCLUDE_DEPENDS)
+
+#
+# acl.tab.c acl.tab.h and acl.yy.c should not be generated by the build,
+# they are checked in and should be pulled from the tree by
+# default. The following rules are provided in case the grammar or
+# lexer needs changes.
+#
+
+#
+# Right now it's best to run yacc on a Solaris machine because the
+# /usr/lib/yaccpar makes the NT compiler happier. It should work on
+# other UNIX systems -- but that's what is checked in and tested.
+#
+yacc:
+ $(YACC) -d acltext.y
+ sed -f yy-sed y.tab.h > acl.tab.h
+ sed -f yy-sed y.tab.c > acl.tab.cpp
+ rm y.tab.h y.tab.c
+
+#
+# Flex generates a case insenitive lexer. It also provides mechanisms
+# that allow NSPR to replace it's standard IO routines. The standard UNIX
+# lex wants to use some stupid library! One would think that lex could
+# generate all the code it needs just like FLEX.
+#
+flex:
+ $(LEX) -i aclscan.l
+ sed -f yy-sed lex.yy.c > acl.yy.cpp
+ rm lex.yy.c
+
+#
+# more AVA mapping stuff, needs to be made to work with the other lexx/yacc
+# code added for 3.0
+#
+#ifeq ($(ARCH), WINNT)
+#$(OBJDEST)/y.tab.o: $(OBJDEST)/y.tab.c $(VALUES) $(OBJDEST)/y.tab.h
+# $(CC) -c $(CFLAGS) $(MCC_INCLUDE) -I$(OBJDEST) -I. $< -Fo$*.o
+#else
+#$(OBJDEST)/y.tab.o: $(OBJDEST)/y.tab.c $(OBJDEST)/y.tab.h
+# $(CC) -c $(CFLAGS) $(MCC_INCLUDE) -I. -o $*.o $<
+#endif
+#
+#ifeq ($(ARCH), WINNT)
+#$(OBJDEST)/y.tab.h: wintab.h
+# cp wintab.h $(OBJDEST)/y.tab.h
+#
+#$(OBJDEST)/y.tab.c: winnt.y
+# cp winnt.y $(OBJDEST)/y.tab.c
+#
+#$(OBJDEST)/values.h: winnt.v
+# cp winnt.v $(OBJDEST)/values.h
+#else
+#$(OBJDEST)/y.tab.h $(OBJDEST)/y.tab.c: avaparse.y
+# yacc -d avaparse.y
+# mv y.tab.h $(OBJDEST)/
+# mv y.tab.c $(OBJDEST)/
+#endif
+#
+#$(OBJDEST)/lex.yy.o: $(OBJDEST)/lex.yy.c $(OBJDEST)/y.tab.h
+#ifeq ($(ARCH), WINNT)
+# $(CC) -c $(CFLAGS) $(MCC_INCLUDE) -I$(OBJDEST) -I. $< -Fo$*.o
+#else
+# $(CC) -c $(CFLAGS) $(MCC_INCLUDE) -I. -o $*.o $<
+#endif
+#
+#ifeq ($(ARCH), WINNT)
+#$(OBJDEST)/lex.yy.c: winnt.l
+# cp winnt.l $(OBJDEST)/lex.yy.c
+#else
+#$(OBJDEST)/lex.yy.c: avascan.l
+# lex avascan.l
+# mv lex.yy.c $(OBJDEST)/
+#endif
diff --git a/lib/libaccess/access_plhash.cpp b/lib/libaccess/access_plhash.cpp
new file mode 100644
index 00000000..7666e95e
--- /dev/null
+++ b/lib/libaccess/access_plhash.cpp
@@ -0,0 +1,65 @@
+/** 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 a function which augments the standard nspr PL_HashTable
+ api. The problem is that the hash table lookup function in the standard NSPR
+ actually modifies the hash table being searched, which means that it cannot be
+ used with read locks in a multi threaded environment. This function is a
+ lookup function which is guaranteed not to modify the hash table passed in,
+ so that it can be used with read locks.
+*/
+
+#include "plhash.h"
+
+/* prototypes */
+NSPR_BEGIN_EXTERN_C
+PR_IMPLEMENT(void *)
+ACL_HashTableLookup_const(PLHashTable *ht, const void *key);
+NSPR_END_EXTERN_C
+
+/*
+** Multiplicative hash, from Knuth 6.4.
+*/
+#define GOLDEN_RATIO 0x9E3779B9U
+
+PR_IMPLEMENT(PLHashEntry **)
+ACL_HashTableRawLookup_const(PLHashTable *ht, PLHashNumber keyHash, const void *key)
+{
+ PLHashEntry *he, **hep;
+ PLHashNumber h;
+
+#ifdef HASHMETER
+ ht->nlookups++;
+#endif
+ h = keyHash * GOLDEN_RATIO;
+ h >>= ht->shift;
+ hep = &ht->buckets[h];
+ while ((he = *hep) != 0) {
+ if (he->keyHash == keyHash && (*ht->keyCompare)(key, he->key)) {
+ return hep;
+ }
+ hep = &he->next;
+#ifdef HASHMETER
+ ht->nsteps++;
+#endif
+ }
+ return hep;
+}
+
+PR_IMPLEMENT(void *)
+ACL_HashTableLookup_const(PLHashTable *ht, const void *key)
+{
+ PLHashNumber keyHash;
+ PLHashEntry *he, **hep;
+
+ keyHash = (*ht->keyHash)(key);
+ hep = ACL_HashTableRawLookup_const(ht, keyHash, key);
+ if ((he = *hep) != 0) {
+ return he->value;
+ }
+ return 0;
+}
diff --git a/lib/libaccess/access_plhash.h b/lib/libaccess/access_plhash.h
new file mode 100644
index 00000000..fb1d86a1
--- /dev/null
+++ b/lib/libaccess/access_plhash.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 **/
+
+NSPR_BEGIN_EXTERN_C
+/*
+ * access_plhash.cpp - supplement to NSPR plhash
+ */
+extern void *
+ACL_HashTableLookup_const(
+ void *ht, /* really a PLHashTable */
+ const void *key);
+
+NSPR_END_EXTERN_C
+
diff --git a/lib/libaccess/acl.tab.cpp b/lib/libaccess/acl.tab.cpp
new file mode 100644
index 00000000..bc17be3d
--- /dev/null
+++ b/lib/libaccess/acl.tab.cpp
@@ -0,0 +1,1718 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+# line 8 "acltext.y"
+#include <string.h>
+#include <netsite.h>
+#include <base/util.h>
+#include <base/plist.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/nserror.h>
+#include "parse.h"
+#include "aclscan.h"
+
+#define MAX_LIST_SIZE 255
+static ACLListHandle_t *curr_acl_list; /* current acl list */
+static ACLHandle_t *curr_acl; /* current acl */
+static ACLExprHandle_t *curr_expr; /* current expression */
+static PFlags_t pflags; /* current authorization flags */
+static char *curr_args_list[MAX_LIST_SIZE]; /* current args */
+static char *curr_user_list[MAX_LIST_SIZE]; /* current users v2 */
+static char *curr_ip_dns_list[MAX_LIST_SIZE]; /* current ip/dns v2 */
+static PList_t curr_auth_info; /* current authorization method */
+static int use_generic_rights; /* use generic rights for conversion */
+
+int acl_PushListHandle(ACLListHandle_t *handle)
+{
+ curr_acl_list = handle;
+ return(0);
+}
+
+static void
+acl_string_lower(char *s)
+{
+int ii;
+int len;
+
+ len = strlen(s);
+ for (ii = 0; ii < len; ii++)
+ s[ii] = tolower(s[ii]);
+
+ return;
+}
+
+static void
+acl_clear_args(char **args_list)
+{
+ args_list[0] = NULL;
+}
+
+static void
+acl_add_arg(char **args_list, char *arg)
+{
+ static int args_index;
+
+ if ( args_list[0] == NULL ) {
+ args_index = 0;
+ }
+ args_list[args_index] = arg;
+ args_index++;
+ args_list[args_index] = NULL;
+}
+
+static void
+acl_free_args(char **args_list)
+{
+ int ii;
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( args_list[ii] )
+ PERM_FREE(args_list[ii]);
+ else
+ break;
+ }
+}
+
+static int
+acl_set_args(ACLExprHandle_t *expr, char **args_list)
+{
+ int ii;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( args_list[ii] ) {
+ if ( ACL_ExprAddArg(NULL, expr, args_list[ii]) < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ } else
+ break;
+ }
+ return(0);
+}
+
+static int
+acl_set_users(ACLExprHandle_t *expr, char **user_list)
+{
+ int ii;
+ int jj;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( user_list[ii] ) {
+ if ( ACL_ExprTerm(NULL, expr, "user", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ } else
+ break;
+ }
+
+ acl_free_args(user_list);
+
+ for (jj = 0; jj < ii - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ aclerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+acl_set_users_or_groups(ACLExprHandle_t *expr, char **user_list)
+{
+ int ii;
+ int jj;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( user_list[ii] ) {
+ if ( ACL_ExprTerm(NULL, expr, "user", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ if ( ACL_ExprTerm(NULL, expr, "group", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ } else
+ break;
+ }
+
+ acl_free_args(user_list);
+
+ for (jj = 0; jj < (ii * 2) - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ aclerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+acl_set_ip_dns(ACLExprHandle_t *expr, char **ip_dns)
+{
+ int ii;
+ int jj;
+ int len;
+ char *attr;
+ char *val;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( ip_dns[ii] ) {
+
+ attr = "ip";
+ val = ip_dns[ii];
+ len = strlen(val);
+
+ for (jj = 0; jj < len; jj++) {
+ if ( strchr("0123456789.*", val[jj]) == 0 ) {
+ attr = "dns";
+ break;
+ }
+ }
+
+ if ( ACL_ExprTerm(NULL, expr, attr, CMP_OP_EQ,
+ val) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ acl_free_args(ip_dns);
+ return(-1);
+ }
+
+ } else
+ break;
+ }
+
+ acl_free_args(ip_dns);
+
+ for (jj = 0; jj < ii - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ aclerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+
+ return(0);
+}
+
+
+
+# line 223 "acltext.y"
+typedef union
+#ifdef __cplusplus
+ ACLSTYPE
+#endif
+ {
+ char *string;
+ int ival;
+} ACLSTYPE;
+# define ACL_ABSOLUTE_TOK 257
+# define ACL_ACL_TOK 258
+# define ACL_ALLOW_TOK 259
+# define ACL_ALWAYS_TOK 260
+# define ACL_AND_TOK 261
+# define ACL_AT_TOK 262
+# define ACL_AUTHENTICATE_TOK 263
+# define ACL_CONTENT_TOK 264
+# define ACL_DEFAULT_TOK 265
+# define ACL_DENY_TOK 266
+# define ACL_GROUP_TOK 267
+# define ACL_IN_TOK 268
+# define ACL_INHERIT_TOK 269
+# define ACL_NOT_TOK 270
+# define ACL_NULL_TOK 271
+# define ACL_OR_TOK 272
+# define ACL_QSTRING_TOK 273
+# define ACL_READ_TOK 274
+# define ACL_TERMINAL_TOK 275
+# define ACL_VARIABLE_TOK 276
+# define ACL_VERSION_TOK 277
+# define ACL_WRITE_TOK 278
+# define ACL_WITH_TOK 279
+# define ACL_EQ_TOK 280
+# define ACL_GE_TOK 281
+# define ACL_GT_TOK 282
+# define ACL_LE_TOK 283
+# define ACL_LT_TOK 284
+# define ACL_NE_TOK 285
+
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#else
+#include <netsite.h>
+#include <memory.h>
+#endif
+
+
+#ifdef __cplusplus
+
+#ifndef aclerror
+ void aclerror(const char *);
+#endif
+
+#ifndef acllex
+#ifdef __EXTERN_C__
+ extern "C" { int acllex(void); }
+#else
+ int acllex(void);
+#endif
+#endif
+ int acl_Parse(void);
+
+#endif
+#define aclclearin aclchar = -1
+#define aclerrok aclerrflag = 0
+extern int aclchar;
+extern int aclerrflag;
+ACLSTYPE acllval;
+ACLSTYPE aclval;
+typedef int acltabelem;
+#ifndef ACLMAXDEPTH
+#define ACLMAXDEPTH 150
+#endif
+#if ACLMAXDEPTH > 0
+int acl_acls[ACLMAXDEPTH], *acls = acl_acls;
+ACLSTYPE acl_aclv[ACLMAXDEPTH], *aclv = acl_aclv;
+#else /* user does initial allocation */
+int *acls;
+ACLSTYPE *aclv;
+#endif
+static int aclmaxdepth = ACLMAXDEPTH;
+# define ACLERRCODE 256
+
+# line 952 "acltext.y"
+
+acltabelem aclexca[] ={
+-1, 1,
+ 0, -1,
+ -2, 0,
+ };
+# define ACLNPROD 120
+# define ACLLAST 251
+acltabelem aclact[]={
+
+ 176, 177, 178, 180, 179, 181, 156, 109, 69, 53,
+ 160, 116, 76, 6, 185, 169, 118, 186, 170, 117,
+ 150, 78, 85, 149, 77, 18, 144, 29, 17, 86,
+ 28, 11, 3, 126, 10, 136, 140, 82, 89, 104,
+ 87, 101, 7, 129, 127, 171, 133, 79, 72, 40,
+ 132, 38, 102, 55, 108, 37, 172, 105, 39, 60,
+ 60, 107, 128, 63, 59, 45, 61, 61, 93, 23,
+ 46, 6, 131, 130, 158, 142, 137, 157, 125, 134,
+ 154, 147, 56, 122, 112, 30, 75, 94, 81, 111,
+ 139, 138, 88, 73, 165, 164, 155, 57, 50, 49,
+ 48, 27, 14, 41, 65, 58, 145, 97, 153, 146,
+ 98, 152, 120, 25, 184, 151, 119, 24, 99, 64,
+ 13, 32, 15, 21, 5, 175, 159, 106, 103, 8,
+ 100, 124, 84, 83, 66, 54, 52, 143, 80, 51,
+ 67, 90, 36, 35, 26, 34, 33, 22, 31, 20,
+ 135, 113, 62, 74, 96, 47, 92, 71, 44, 68,
+ 43, 70, 42, 95, 16, 91, 9, 4, 19, 12,
+ 2, 1, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 110, 115, 114, 121, 123, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 95, 141, 0,
+ 0, 0, 0, 0, 0, 148, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 163, 0, 0, 0, 166,
+ 167, 168, 0, 0, 0, 0, 174, 0, 173, 0,
+ 161, 0, 0, 0, 118, 78, 162, 117, 77, 182,
+ 183 };
+acltabelem aclpact[]={
+
+ -245,-10000000,-10000000, -234, -187,-10000000, -242,-10000000,-10000000, 80,
+-10000000,-10000000, 43, -248, -189, 76, 69,-10000000,-10000000,-10000000,
+ -189,-10000000, 42, -246, -38, -248,-10000000, -208,-10000000,-10000000,
+ -195,-10000000,-10000000, -208, 41, 40, 39,-10000000,-10000000, -270,
+ -213, -43, 38,-10000000,-10000000, -199, -200,-10000000,-10000000,-10000000,
+-10000000, 79,-10000000,-10000000,-10000000, -271,-10000000, -195,-10000000, -220,
+-10000000,-10000000, -28, -221, -239,-10000000, -235, -238,-10000000,-10000000,
+-10000000, -28,-10000000,-10000000, -194,-10000000, -252,-10000000,-10000000,-10000000,
+ 66,-10000000,-10000000,-10000000, 78, -223, -218, -203,-10000000, -273,
+ -238,-10000000, -39, -29, 75, 68, -39, -40, -239, -243,
+-10000000, -231, -202,-10000000, -232, -184,-10000000, -185, -214, -227,
+-10000000,-10000000, -241,-10000000,-10000000,-10000000, -257, -240,-10000000,-10000000,
+ -252,-10000000, -250,-10000000, 65,-10000000,-10000000,-10000000,-10000000,-10000000,
+-10000000,-10000000,-10000000,-10000000, -44, -241, -253, 74, 67, 64,
+-10000000,-10000000, -45, 37, -274, -30, -243,-10000000,-10000000, 36,
+ 35,-10000000, -257, -257,-10000000, -250, -258,-10000000, -216,-10000000,
+ -30, -30, -280,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,
+-10000000, -30, -30, 73,-10000000, -259,-10000000,-10000000,-10000000,-10000000,
+-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000 };
+acltabelem aclpgo[]={
+
+ 0, 171, 170, 169, 168, 167, 124, 166, 122, 103,
+ 164, 162, 160, 158, 105, 157, 93, 156, 89, 154,
+ 153, 151, 86, 87, 91, 90, 76, 79, 150, 149,
+ 123, 147, 121, 146, 145, 143, 142, 141, 92, 140,
+ 139, 138, 75, 88, 137, 136, 104, 135, 134, 133,
+ 132, 131, 77, 130, 128, 127, 78, 74, 126, 125 };
+acltabelem aclr1[]={
+
+ 0, 1, 1, 3, 1, 2, 5, 5, 6, 7,
+ 7, 8, 8, 10, 10, 9, 9, 11, 11, 15,
+ 13, 13, 14, 14, 17, 12, 19, 12, 16, 16,
+ 20, 20, 23, 23, 22, 22, 21, 21, 21, 24,
+ 24, 25, 26, 26, 26, 26, 18, 28, 28, 27,
+ 27, 4, 29, 29, 30, 30, 31, 31, 32, 32,
+ 33, 33, 33, 37, 36, 39, 36, 38, 40, 34,
+ 41, 41, 43, 42, 42, 44, 44, 45, 35, 47,
+ 35, 48, 46, 49, 50, 50, 50, 50, 50, 50,
+ 50, 55, 55, 55, 55, 53, 53, 53, 53, 54,
+ 54, 54, 54, 51, 51, 56, 52, 52, 52, 57,
+ 57, 57, 58, 58, 59, 59, 59, 59, 59, 59 };
+acltabelem aclr2[]={
+
+ 0, 0, 2, 1, 10, 2, 2, 4, 17, 3,
+ 3, 2, 6, 3, 3, 4, 6, 2, 2, 1,
+ 8, 6, 3, 3, 1, 10, 1, 10, 7, 3,
+ 2, 6, 2, 6, 3, 3, 2, 2, 6, 3,
+ 3, 5, 2, 2, 6, 6, 7, 7, 7, 2,
+ 4, 2, 2, 4, 6, 4, 5, 5, 2, 4,
+ 4, 4, 4, 1, 10, 1, 8, 7, 1, 17,
+ 2, 6, 3, 4, 6, 7, 7, 1, 6, 1,
+ 6, 1, 5, 10, 0, 3, 5, 3, 5, 3,
+ 5, 3, 3, 5, 5, 3, 3, 5, 5, 3,
+ 3, 5, 5, 2, 6, 3, 2, 7, 7, 2,
+ 6, 5, 7, 7, 2, 2, 2, 2, 2, 2 };
+acltabelem aclchk[]={
+
+-10000000, -1, -2, 277, -5, -6, 258, 276, -6, -7,
+ 276, 273, -3, 40, 59, -8, -10, 276, 273, -4,
+ -29, -30, -31, 258, 41, 44, -30, 59, 276, 273,
+ 123, -8, -32, -33, -34, -35, -36, 263, 259, 266,
+ 257, -9, -11, -12, -13, 260, 265, -32, 59, 59,
+ 59, -40, -45, 279, -47, 266, 125, 59, -14, 263,
+ 259, 266, -14, 263, 40, -46, -48, -39, -46, 279,
+ -9, -15, 268, -16, -20, -22, 40, 276, 273, 268,
+ -41, -43, 276, -49, -50, 257, 264, 275, -38, 276,
+ -37, -16, -17, 262, -23, -22, -19, 41, 44, 40,
+ -53, 264, 275, -54, 257, 275, -55, 264, 257, 280,
+ -38, -18, 123, -21, -24, -25, 40, 276, 273, 41,
+ 44, -18, 123, -43, -51, -56, 276, 275, 264, 275,
+ 257, 257, 264, 273, -27, -28, 276, -26, -24, -25,
+ 276, -23, -42, -44, 276, 41, 44, 125, -27, 276,
+ 273, 41, 44, 44, 125, 59, 280, -52, -57, -58,
+ 40, 270, 276, -56, 59, 59, -26, -26, -42, 273,
+ 276, 261, 272, -52, -57, -59, 280, 281, 282, 284,
+ 283, 285, -52, -52, 41, 273, 276 };
+acltabelem acldef[]={
+
+ 1, -2, 2, 0, 5, 6, 0, 3, 7, 0,
+ 9, 10, 0, 0, 0, 0, 11, 13, 14, 4,
+ 51, 52, 0, 0, 0, 0, 53, 55, 56, 57,
+ 0, 12, 54, 58, 0, 0, 0, 68, 77, 79,
+ 0, 0, 0, 17, 18, 0, 0, 59, 60, 61,
+ 62, 0, 81, 65, 81, 0, 8, 15, 19, 0,
+ 22, 23, 0, 0, 0, 78, 84, 0, 80, 63,
+ 16, 0, 24, 21, 29, 30, 0, 34, 35, 26,
+ 0, 70, 72, 82, 0, 85, 87, 89, 66, 0,
+ 0, 20, 0, 0, 0, 32, 0, 0, 0, 0,
+ 86, 95, 96, 88, 99, 100, 90, 91, 92, 0,
+ 64, 25, 0, 28, 36, 37, 0, 39, 40, 31,
+ 0, 27, 0, 71, 0, 103, 105, 97, 98, 101,
+ 102, 93, 94, 67, 0, 49, 0, 0, 42, 43,
+ 41, 33, 0, 0, 0, 0, 0, 46, 50, 0,
+ 0, 38, 0, 0, 69, 73, 0, 83, 106, 109,
+ 0, 0, 0, 104, 47, 48, 44, 45, 74, 75,
+ 76, 0, 0, 0, 111, 0, 114, 115, 116, 117,
+ 118, 119, 107, 108, 110, 112, 113 };
+typedef struct
+#ifdef __cplusplus
+ acltoktype
+#endif
+{ char *t_name; int t_val; } acltoktype;
+#ifndef ACLDEBUG
+# define ACLDEBUG 0 /* don't allow debugging */
+#endif
+
+#if ACLDEBUG
+
+acltoktype acltoks[] =
+{
+ "ACL_ABSOLUTE_TOK", 257,
+ "ACL_ACL_TOK", 258,
+ "ACL_ALLOW_TOK", 259,
+ "ACL_ALWAYS_TOK", 260,
+ "ACL_AND_TOK", 261,
+ "ACL_AT_TOK", 262,
+ "ACL_AUTHENTICATE_TOK", 263,
+ "ACL_CONTENT_TOK", 264,
+ "ACL_DEFAULT_TOK", 265,
+ "ACL_DENY_TOK", 266,
+ "ACL_GROUP_TOK", 267,
+ "ACL_IN_TOK", 268,
+ "ACL_INHERIT_TOK", 269,
+ "ACL_NOT_TOK", 270,
+ "ACL_NULL_TOK", 271,
+ "ACL_OR_TOK", 272,
+ "ACL_QSTRING_TOK", 273,
+ "ACL_READ_TOK", 274,
+ "ACL_TERMINAL_TOK", 275,
+ "ACL_VARIABLE_TOK", 276,
+ "ACL_VERSION_TOK", 277,
+ "ACL_WRITE_TOK", 278,
+ "ACL_WITH_TOK", 279,
+ "ACL_EQ_TOK", 280,
+ "ACL_GE_TOK", 281,
+ "ACL_GT_TOK", 282,
+ "ACL_LE_TOK", 283,
+ "ACL_LT_TOK", 284,
+ "ACL_NE_TOK", 285,
+ "-unknown-", -1 /* ends search */
+};
+
+char * aclreds[] =
+{
+ "-no such reduction-",
+ "start : /* empty */",
+ "start : start_acl_v2",
+ "start : ACL_VERSION_TOK ACL_VARIABLE_TOK",
+ "start : ACL_VERSION_TOK ACL_VARIABLE_TOK ';' start_acl_v3",
+ "start_acl_v2 : acl_list_v2",
+ "acl_list_v2 : acl_v2",
+ "acl_list_v2 : acl_list_v2 acl_v2",
+ "acl_v2 : ACL_ACL_TOK acl_name_v2 '(' arg_list_v2 ')' '{' directive_list_v2 '}'",
+ "acl_name_v2 : ACL_VARIABLE_TOK",
+ "acl_name_v2 : ACL_QSTRING_TOK",
+ "arg_list_v2 : arg_v2",
+ "arg_list_v2 : arg_v2 ',' arg_list_v2",
+ "arg_v2 : ACL_VARIABLE_TOK",
+ "arg_v2 : ACL_QSTRING_TOK",
+ "directive_list_v2 : directive_v2 ';'",
+ "directive_list_v2 : directive_v2 ';' directive_list_v2",
+ "directive_v2 : auth_method_v2",
+ "directive_v2 : auth_statement_v2",
+ "auth_statement_v2 : ACL_ALWAYS_TOK auth_type_v2",
+ "auth_statement_v2 : ACL_ALWAYS_TOK auth_type_v2 host_spec_list_action_v2",
+ "auth_statement_v2 : ACL_DEFAULT_TOK auth_type_v2 host_spec_list_action_v2",
+ "auth_type_v2 : ACL_ALLOW_TOK",
+ "auth_type_v2 : ACL_DENY_TOK",
+ "auth_method_v2 : ACL_ALWAYS_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK",
+ "auth_method_v2 : ACL_ALWAYS_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK realm_definition_v2",
+ "auth_method_v2 : ACL_DEFAULT_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK",
+ "auth_method_v2 : ACL_DEFAULT_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK realm_definition_v2",
+ "host_spec_list_action_v2 : user_expr_v2 ACL_AT_TOK host_spec_list_v2",
+ "host_spec_list_action_v2 : user_expr_v2",
+ "user_expr_v2 : user_v2",
+ "user_expr_v2 : '(' user_list_v2 ')'",
+ "user_list_v2 : user_v2",
+ "user_list_v2 : user_v2 ',' user_list_v2",
+ "user_v2 : ACL_VARIABLE_TOK",
+ "user_v2 : ACL_QSTRING_TOK",
+ "host_spec_list_v2 : dns_spec_v2",
+ "host_spec_list_v2 : ip_spec_v2",
+ "host_spec_list_v2 : '(' dns_ip_spec_list_v2 ')'",
+ "dns_spec_v2 : ACL_VARIABLE_TOK",
+ "dns_spec_v2 : ACL_QSTRING_TOK",
+ "ip_spec_v2 : ACL_VARIABLE_TOK ACL_VARIABLE_TOK",
+ "dns_ip_spec_list_v2 : dns_spec_v2",
+ "dns_ip_spec_list_v2 : ip_spec_v2",
+ "dns_ip_spec_list_v2 : dns_spec_v2 ',' dns_ip_spec_list_v2",
+ "dns_ip_spec_list_v2 : ip_spec_v2 ',' dns_ip_spec_list_v2",
+ "realm_definition_v2 : '{' methods_list_v2 '}'",
+ "method_v2 : ACL_VARIABLE_TOK ACL_VARIABLE_TOK ';'",
+ "method_v2 : ACL_VARIABLE_TOK ACL_QSTRING_TOK ';'",
+ "methods_list_v2 : method_v2",
+ "methods_list_v2 : method_v2 methods_list_v2",
+ "start_acl_v3 : acl_list",
+ "acl_list : acl",
+ "acl_list : acl_list acl",
+ "acl : named_acl ';' body_list",
+ "acl : named_acl ';'",
+ "named_acl : ACL_ACL_TOK ACL_VARIABLE_TOK",
+ "named_acl : ACL_ACL_TOK ACL_QSTRING_TOK",
+ "body_list : body",
+ "body_list : body body_list",
+ "body : authenticate_statement ';'",
+ "body : authorization_statement ';'",
+ "body : deny_statement ';'",
+ "deny_statement : ACL_ABSOLUTE_TOK ACL_DENY_TOK ACL_WITH_TOK",
+ "deny_statement : ACL_ABSOLUTE_TOK ACL_DENY_TOK ACL_WITH_TOK deny_common",
+ "deny_statement : ACL_DENY_TOK ACL_WITH_TOK",
+ "deny_statement : ACL_DENY_TOK ACL_WITH_TOK deny_common",
+ "deny_common : ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK",
+ "authenticate_statement : ACL_AUTHENTICATE_TOK",
+ "authenticate_statement : ACL_AUTHENTICATE_TOK '(' attribute_list ')' '{' parameter_list '}'",
+ "attribute_list : attribute",
+ "attribute_list : attribute_list ',' attribute",
+ "attribute : ACL_VARIABLE_TOK",
+ "parameter_list : parameter ';'",
+ "parameter_list : parameter ';' parameter_list",
+ "parameter : ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK",
+ "parameter : ACL_VARIABLE_TOK ACL_EQ_TOK ACL_VARIABLE_TOK",
+ "authorization_statement : ACL_ALLOW_TOK",
+ "authorization_statement : ACL_ALLOW_TOK auth_common_action",
+ "authorization_statement : ACL_DENY_TOK",
+ "authorization_statement : ACL_DENY_TOK auth_common_action",
+ "auth_common_action : /* empty */",
+ "auth_common_action : auth_common",
+ "auth_common : flag_list '(' args_list ')' expression",
+ "flag_list : /* empty */",
+ "flag_list : ACL_ABSOLUTE_TOK",
+ "flag_list : ACL_ABSOLUTE_TOK content_static",
+ "flag_list : ACL_CONTENT_TOK",
+ "flag_list : ACL_CONTENT_TOK absolute_static",
+ "flag_list : ACL_TERMINAL_TOK",
+ "flag_list : ACL_TERMINAL_TOK content_absolute",
+ "content_absolute : ACL_CONTENT_TOK",
+ "content_absolute : ACL_ABSOLUTE_TOK",
+ "content_absolute : ACL_CONTENT_TOK ACL_ABSOLUTE_TOK",
+ "content_absolute : ACL_ABSOLUTE_TOK ACL_CONTENT_TOK",
+ "content_static : ACL_CONTENT_TOK",
+ "content_static : ACL_TERMINAL_TOK",
+ "content_static : ACL_CONTENT_TOK ACL_TERMINAL_TOK",
+ "content_static : ACL_TERMINAL_TOK ACL_CONTENT_TOK",
+ "absolute_static : ACL_ABSOLUTE_TOK",
+ "absolute_static : ACL_TERMINAL_TOK",
+ "absolute_static : ACL_ABSOLUTE_TOK ACL_TERMINAL_TOK",
+ "absolute_static : ACL_TERMINAL_TOK ACL_ABSOLUTE_TOK",
+ "args_list : arg",
+ "args_list : args_list ',' arg",
+ "arg : ACL_VARIABLE_TOK",
+ "expression : factor",
+ "expression : factor ACL_AND_TOK expression",
+ "expression : factor ACL_OR_TOK expression",
+ "factor : base_expr",
+ "factor : '(' expression ')'",
+ "factor : ACL_NOT_TOK factor",
+ "base_expr : ACL_VARIABLE_TOK relop ACL_QSTRING_TOK",
+ "base_expr : ACL_VARIABLE_TOK relop ACL_VARIABLE_TOK",
+ "relop : ACL_EQ_TOK",
+ "relop : ACL_GE_TOK",
+ "relop : ACL_GT_TOK",
+ "relop : ACL_LT_TOK",
+ "relop : ACL_LE_TOK",
+ "relop : ACL_NE_TOK",
+};
+#endif /* ACLDEBUG */
+
+
+/*
+** Skeleton parser driver for yacc output
+*/
+
+/*
+** yacc user known macros and defines
+*/
+#define ACLERROR goto aclerrlab
+#define ACLACCEPT return(0)
+#define ACLABORT return(1)
+#define ACLBACKUP( newtoken, newvalue )\
+{\
+ if ( aclchar >= 0 || ( aclr2[ acltmp ] >> 1 ) != 1 )\
+ {\
+ aclerror( "syntax error - cannot backup" );\
+ goto aclerrlab;\
+ }\
+ aclchar = newtoken;\
+ aclstate = *aclps;\
+ acllval = newvalue;\
+ goto aclnewstate;\
+}
+#define ACLRECOVERING() (!!aclerrflag)
+#define ACLNEW(type) PERM_MALLOC(sizeof(type) * aclnewmax)
+#define ACLCOPY(to, from, type) \
+ (type *) memcpy(to, (char *) from, aclnewmax * sizeof(type))
+#define ACLENLARGE( from, type) \
+ (type *) PERM_REALLOC((char *) from, aclnewmax * sizeof(type))
+#ifndef ACLDEBUG
+# define ACLDEBUG 1 /* make debugging available */
+#endif
+
+/*
+** user known globals
+*/
+int acldebug; /* set to 1 to get debugging */
+
+/*
+** driver internal defines
+*/
+#define ACLFLAG (-10000000)
+
+/*
+** global variables used by the parser
+*/
+ACLSTYPE *aclpv; /* top of value stack */
+int *aclps; /* top of state stack */
+
+int aclstate; /* current state */
+int acltmp; /* extra var (lasts between blocks) */
+
+int aclnerrs; /* number of errors */
+int aclerrflag; /* error recovery flag */
+int aclchar; /* current input token number */
+
+
+
+#ifdef ACLNMBCHARS
+#define ACLLEX() aclcvtok(acllex())
+/*
+** aclcvtok - return a token if i is a wchar_t value that exceeds 255.
+** If i<255, i itself is the token. If i>255 but the neither
+** of the 30th or 31st bit is on, i is already a token.
+*/
+#if defined(__STDC__) || defined(__cplusplus)
+int aclcvtok(int i)
+#else
+int aclcvtok(i) int i;
+#endif
+{
+ int first = 0;
+ int last = ACLNMBCHARS - 1;
+ int mid;
+ wchar_t j;
+
+ if(i&0x60000000){/*Must convert to a token. */
+ if( aclmbchars[last].character < i ){
+ return i;/*Giving up*/
+ }
+ while ((last>=first)&&(first>=0)) {/*Binary search loop*/
+ mid = (first+last)/2;
+ j = aclmbchars[mid].character;
+ if( j==i ){/*Found*/
+ return aclmbchars[mid].tvalue;
+ }else if( j<i ){
+ first = mid + 1;
+ }else{
+ last = mid -1;
+ }
+ }
+ /*No entry in the table.*/
+ return i;/* Giving up.*/
+ }else{/* i is already a token. */
+ return i;
+ }
+}
+#else/*!ACLNMBCHARS*/
+#define ACLLEX() acllex()
+#endif/*!ACLNMBCHARS*/
+
+/*
+** acl_Parse - return 0 if worked, 1 if syntax error not recovered from
+*/
+#if defined(__STDC__) || defined(__cplusplus)
+int acl_Parse(void)
+#else
+int acl_Parse()
+#endif
+{
+ register ACLSTYPE *aclpvt; /* top of value stack for $vars */
+
+#if defined(__cplusplus) || defined(lint)
+/*
+ hacks to please C++ and lint - goto's inside switch should never be
+ executed; aclpvt is set to 0 to avoid "used before set" warning.
+*/
+ static int __yaccpar_lint_hack__ = 0;
+ switch (__yaccpar_lint_hack__)
+ {
+ case 1: goto aclerrlab;
+ case 2: goto aclnewstate;
+ }
+ aclpvt = 0;
+#endif
+
+ /*
+ ** Initialize externals - acl_Parse may be called more than once
+ */
+ aclpv = &aclv[-1];
+ aclps = &acls[-1];
+ aclstate = 0;
+ acltmp = 0;
+ aclnerrs = 0;
+ aclerrflag = 0;
+ aclchar = -1;
+
+#if ACLMAXDEPTH <= 0
+ if (aclmaxdepth <= 0)
+ {
+ if ((aclmaxdepth = ACLEXPAND(0)) <= 0)
+ {
+ aclerror("yacc initialization error");
+ ACLABORT;
+ }
+ }
+#endif
+
+ {
+ register ACLSTYPE *acl_pv; /* top of value stack */
+ register int *acl_ps; /* top of state stack */
+ register int acl_state; /* current state */
+ register int acl_n; /* internal state number info */
+ goto aclstack; /* moved from 6 lines above to here to please C++ */
+
+ /*
+ ** get globals into registers.
+ ** branch to here only if ACLBACKUP was called.
+ */
+ aclnewstate:
+ acl_pv = aclpv;
+ acl_ps = aclps;
+ acl_state = aclstate;
+ goto acl_newstate;
+
+ /*
+ ** get globals into registers.
+ ** either we just started, or we just finished a reduction
+ */
+ aclstack:
+ acl_pv = aclpv;
+ acl_ps = aclps;
+ acl_state = aclstate;
+
+ /*
+ ** top of for (;;) loop while no reductions done
+ */
+ acl_stack:
+ /*
+ ** put a state and value onto the stacks
+ */
+#if ACLDEBUG
+ /*
+ ** if debugging, look up token value in list of value vs.
+ ** name pairs. 0 and negative (-1) are special values.
+ ** Note: linear search is used since time is not a real
+ ** consideration while debugging.
+ */
+ if ( acldebug )
+ {
+ register int acl_i;
+
+ printf( "State %d, token ", acl_state );
+ if ( aclchar == 0 )
+ printf( "end-of-file\n" );
+ else if ( aclchar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( acl_i = 0; acltoks[acl_i].t_val >= 0;
+ acl_i++ )
+ {
+ if ( acltoks[acl_i].t_val == aclchar )
+ break;
+ }
+ printf( "%s\n", acltoks[acl_i].t_name );
+ }
+ }
+#endif /* ACLDEBUG */
+ if ( ++acl_ps >= &acls[ aclmaxdepth ] ) /* room on stack? */
+ {
+ /*
+ ** reallocate and recover. Note that pointers
+ ** have to be reset, or bad things will happen
+ */
+ int aclps_index = (acl_ps - acls);
+ int aclpv_index = (acl_pv - aclv);
+ int aclpvt_index = (aclpvt - aclv);
+ int aclnewmax;
+#ifdef ACLEXPAND
+ aclnewmax = ACLEXPAND(aclmaxdepth);
+#else
+ aclnewmax = 2 * aclmaxdepth; /* double table size */
+ if (aclmaxdepth == ACLMAXDEPTH) /* first time growth */
+ {
+ char *newacls = (char *)ACLNEW(int);
+ char *newaclv = (char *)ACLNEW(ACLSTYPE);
+ if (newacls != 0 && newaclv != 0)
+ {
+ acls = ACLCOPY(newacls, acls, int);
+ aclv = ACLCOPY(newaclv, aclv, ACLSTYPE);
+ }
+ else
+ aclnewmax = 0; /* failed */
+ }
+ else /* not first time */
+ {
+ acls = ACLENLARGE(acls, int);
+ aclv = ACLENLARGE(aclv, ACLSTYPE);
+ if (acls == 0 || aclv == 0)
+ aclnewmax = 0; /* failed */
+ }
+#endif
+ if (aclnewmax <= aclmaxdepth) /* tables not expanded */
+ {
+ aclerror( "yacc stack overflow" );
+ ACLABORT;
+ }
+ aclmaxdepth = aclnewmax;
+
+ acl_ps = acls + aclps_index;
+ acl_pv = aclv + aclpv_index;
+ aclpvt = aclv + aclpvt_index;
+ }
+ *acl_ps = acl_state;
+ *++acl_pv = aclval;
+
+ /*
+ ** we have a new state - find out what to do
+ */
+ acl_newstate:
+ if ( ( acl_n = aclpact[ acl_state ] ) <= ACLFLAG )
+ goto acldefault; /* simple state */
+#if ACLDEBUG
+ /*
+ ** if debugging, need to mark whether new token grabbed
+ */
+ acltmp = aclchar < 0;
+#endif
+ if ( ( aclchar < 0 ) && ( ( aclchar = ACLLEX() ) < 0 ) )
+ aclchar = 0; /* reached EOF */
+#if ACLDEBUG
+ if ( acldebug && acltmp )
+ {
+ register int acl_i;
+
+ printf( "Received token " );
+ if ( aclchar == 0 )
+ printf( "end-of-file\n" );
+ else if ( aclchar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( acl_i = 0; acltoks[acl_i].t_val >= 0;
+ acl_i++ )
+ {
+ if ( acltoks[acl_i].t_val == aclchar )
+ break;
+ }
+ printf( "%s\n", acltoks[acl_i].t_name );
+ }
+ }
+#endif /* ACLDEBUG */
+ if ( ( ( acl_n += aclchar ) < 0 ) || ( acl_n >= ACLLAST ) )
+ goto acldefault;
+ if ( aclchk[ acl_n = aclact[ acl_n ] ] == aclchar ) /*valid shift*/
+ {
+ aclchar = -1;
+ aclval = acllval;
+ acl_state = acl_n;
+ if ( aclerrflag > 0 )
+ aclerrflag--;
+ goto acl_stack;
+ }
+
+ acldefault:
+ if ( ( acl_n = acldef[ acl_state ] ) == -2 )
+ {
+#if ACLDEBUG
+ acltmp = aclchar < 0;
+#endif
+ if ( ( aclchar < 0 ) && ( ( aclchar = ACLLEX() ) < 0 ) )
+ aclchar = 0; /* reached EOF */
+#if ACLDEBUG
+ if ( acldebug && acltmp )
+ {
+ register int acl_i;
+
+ printf( "Received token " );
+ if ( aclchar == 0 )
+ printf( "end-of-file\n" );
+ else if ( aclchar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( acl_i = 0;
+ acltoks[acl_i].t_val >= 0;
+ acl_i++ )
+ {
+ if ( acltoks[acl_i].t_val
+ == aclchar )
+ {
+ break;
+ }
+ }
+ printf( "%s\n", acltoks[acl_i].t_name );
+ }
+ }
+#endif /* ACLDEBUG */
+ /*
+ ** look through exception table
+ */
+ {
+ register int *aclxi = aclexca;
+
+ while ( ( *aclxi != -1 ) ||
+ ( aclxi[1] != acl_state ) )
+ {
+ aclxi += 2;
+ }
+ while ( ( *(aclxi += 2) >= 0 ) &&
+ ( *aclxi != aclchar ) )
+ ;
+ if ( ( acl_n = aclxi[1] ) < 0 )
+ ACLACCEPT;
+ }
+ }
+
+ /*
+ ** check for syntax error
+ */
+ if ( acl_n == 0 ) /* have an error */
+ {
+ /* no worry about speed here! */
+ switch ( aclerrflag )
+ {
+ case 0: /* new error */
+ aclerror( "syntax error" );
+ goto skip_init;
+ aclerrlab:
+ /*
+ ** get globals into registers.
+ ** we have a user generated syntax type error
+ */
+ acl_pv = aclpv;
+ acl_ps = aclps;
+ acl_state = aclstate;
+ skip_init:
+ aclnerrs++;
+ /* FALLTHRU */
+ case 1:
+ case 2: /* incompletely recovered error */
+ /* try again... */
+ aclerrflag = 3;
+ /*
+ ** find state where "error" is a legal
+ ** shift action
+ */
+ while ( acl_ps >= acls )
+ {
+ acl_n = aclpact[ *acl_ps ] + ACLERRCODE;
+ if ( acl_n >= 0 && acl_n < ACLLAST &&
+ aclchk[aclact[acl_n]] == ACLERRCODE) {
+ /*
+ ** simulate shift of "error"
+ */
+ acl_state = aclact[ acl_n ];
+ goto acl_stack;
+ }
+ /*
+ ** current state has no shift on
+ ** "error", pop stack
+ */
+#if ACLDEBUG
+# define _POP_ "Error recovery pops state %d, uncovers state %d\n"
+ if ( acldebug )
+ printf( _POP_, *acl_ps,
+ acl_ps[-1] );
+# undef _POP_
+#endif
+ acl_ps--;
+ acl_pv--;
+ }
+ /*
+ ** there is no state on stack with "error" as
+ ** a valid shift. give up.
+ */
+ ACLABORT;
+ case 3: /* no shift yet; eat a token */
+#if ACLDEBUG
+ /*
+ ** if debugging, look up token in list of
+ ** pairs. 0 and negative shouldn't occur,
+ ** but since timing doesn't matter when
+ ** debugging, it doesn't hurt to leave the
+ ** tests here.
+ */
+ if ( acldebug )
+ {
+ register int acl_i;
+
+ printf( "Error recovery discards " );
+ if ( aclchar == 0 )
+ printf( "token end-of-file\n" );
+ else if ( aclchar < 0 )
+ printf( "token -none-\n" );
+ else
+ {
+ for ( acl_i = 0;
+ acltoks[acl_i].t_val >= 0;
+ acl_i++ )
+ {
+ if ( acltoks[acl_i].t_val
+ == aclchar )
+ {
+ break;
+ }
+ }
+ printf( "token %s\n",
+ acltoks[acl_i].t_name );
+ }
+ }
+#endif /* ACLDEBUG */
+ if ( aclchar == 0 ) /* reached EOF. quit */
+ ACLABORT;
+ aclchar = -1;
+ goto acl_newstate;
+ }
+ }/* end if ( acl_n == 0 ) */
+ /*
+ ** reduction by production acl_n
+ ** put stack tops, etc. so things right after switch
+ */
+#if ACLDEBUG
+ /*
+ ** if debugging, print the string that is the user's
+ ** specification of the reduction which is just about
+ ** to be done.
+ */
+ if ( acldebug )
+ printf( "Reduce by (%d) \"%s\"\n",
+ acl_n, aclreds[ acl_n ] );
+#endif
+ acltmp = acl_n; /* value to switch over */
+ aclpvt = acl_pv; /* $vars top of value stack */
+ /*
+ ** Look in goto table for next state
+ ** Sorry about using acl_state here as temporary
+ ** register variable, but why not, if it works...
+ ** If aclr2[ acl_n ] doesn't have the low order bit
+ ** set, then there is no action to be done for
+ ** this reduction. So, no saving & unsaving of
+ ** registers done. The only difference between the
+ ** code just after the if and the body of the if is
+ ** the goto acl_stack in the body. This way the test
+ ** can be made before the choice of what to do is needed.
+ */
+ {
+ /* length of production doubled with extra bit */
+ register int acl_len = aclr2[ acl_n ];
+
+ if ( !( acl_len & 01 ) )
+ {
+ acl_len >>= 1;
+ aclval = ( acl_pv -= acl_len )[1]; /* $$ = $1 */
+ acl_state = aclpgo[ acl_n = aclr1[ acl_n ] ] +
+ *( acl_ps -= acl_len ) + 1;
+ if ( acl_state >= ACLLAST ||
+ aclchk[ acl_state =
+ aclact[ acl_state ] ] != -acl_n )
+ {
+ acl_state = aclact[ aclpgo[ acl_n ] ];
+ }
+ goto acl_stack;
+ }
+ acl_len >>= 1;
+ aclval = ( acl_pv -= acl_len )[1]; /* $$ = $1 */
+ acl_state = aclpgo[ acl_n = aclr1[ acl_n ] ] +
+ *( acl_ps -= acl_len ) + 1;
+ if ( acl_state >= ACLLAST ||
+ aclchk[ acl_state = aclact[ acl_state ] ] != -acl_n )
+ {
+ acl_state = aclact[ aclpgo[ acl_n ] ];
+ }
+ }
+ /* save until reenter driver code */
+ aclstate = acl_state;
+ aclps = acl_ps;
+ aclpv = acl_pv;
+ }
+ /*
+ ** code supplied by user is placed in this switch
+ */
+ switch( acltmp )
+ {
+
+case 3:
+# line 266 "acltext.y"
+{
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+case 8:
+# line 286 "acltext.y"
+{
+ acl_free_args(curr_args_list);
+ } break;
+case 9:
+# line 292 "acltext.y"
+{
+ curr_acl = ACL_AclNew(NULL, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ aclerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ acl_clear_args(curr_args_list);
+ use_generic_rights = 0;
+ if (strstr(curr_acl->tag, "READ")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("read"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("execute"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("list"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("info"));
+ } if (strstr(curr_acl->tag, "WRITE")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("write"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("delete"));
+ }
+ } break;
+case 10:
+# line 314 "acltext.y"
+{
+ curr_acl = ACL_AclNew(NULL, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ aclerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ acl_clear_args(curr_args_list);
+ use_generic_rights = 0;
+ if (strstr(curr_acl->tag, "READ")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("read"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("execute"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("list"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("info"));
+ } if (strstr(curr_acl->tag, "WRITE")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("write"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("delete"));
+ }
+ } break;
+case 13:
+# line 342 "acltext.y"
+{
+ char acl_tmp_arg[255];
+ char *acl_new_arg;
+
+ if (!use_generic_rights) {
+ acl_string_lower(aclpvt[-0].string);
+ strcpy(acl_tmp_arg, "http_");
+ strcat(acl_tmp_arg, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ acl_new_arg = PERM_STRDUP(acl_tmp_arg);
+ acl_add_arg(curr_args_list, acl_new_arg);
+ } else {
+ PERM_FREE(aclpvt[-0].string);
+ }
+ } break;
+case 14:
+# line 358 "acltext.y"
+{
+ if (!use_generic_rights) {
+ acl_add_arg(curr_args_list, aclpvt[-0].string);
+ } else {
+ PERM_FREE(aclpvt[-0].string);
+ }
+ } break;
+case 19:
+# line 376 "acltext.y"
+{
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ aclerror("Could not set authorization processing flags");
+ return(-1);
+ }
+ } break;
+case 22:
+# line 388 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_ALLOW) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ acl_clear_args(curr_user_list);
+ acl_clear_args(curr_ip_dns_list);
+ } break;
+case 23:
+# line 398 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_DENY) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ acl_clear_args(curr_user_list);
+ acl_clear_args(curr_ip_dns_list);
+ } break;
+case 24:
+# line 411 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(auth) failed");
+ return(-1);
+ }
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ aclerror("Could not set authorization processing flags");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ aclerror("Could not set authorization info");
+ return(-1);
+ }
+ } break;
+case 26:
+# line 430 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(auth) failed");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ aclerror("Could not set authorization info");
+ return(-1);
+ }
+ } break;
+case 28:
+# line 446 "acltext.y"
+{
+ if ( acl_set_users_or_groups(curr_expr, curr_user_list) < 0 ) {
+ aclerror("acl_set_users_or_groups() failed");
+ return(-1);
+ }
+
+ if ( acl_set_ip_dns(curr_expr, curr_ip_dns_list) < 0 ) {
+ aclerror("acl_set_ip_dns() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAnd(NULL, curr_expr) < 0 ) {
+ aclerror("ACL_ExprAnd() failed");
+ return(-1);
+ }
+
+ if ( acl_set_args(curr_expr, curr_args_list) < 0 ) {
+ aclerror("acl_set_args() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 29:
+# line 473 "acltext.y"
+{
+ if ( acl_set_users_or_groups(curr_expr, curr_user_list) < 0 ) {
+ aclerror("acl_set_users_or_groups() failed");
+ return(-1);
+ }
+
+ if ( acl_set_args(curr_expr, curr_args_list) < 0 ) {
+ aclerror("acl_set_args() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 34:
+# line 500 "acltext.y"
+{
+ acl_add_arg(curr_user_list, aclpvt[-0].string);
+ } break;
+case 35:
+# line 504 "acltext.y"
+{
+ acl_add_arg(curr_user_list, aclpvt[-0].string);
+ } break;
+case 39:
+# line 516 "acltext.y"
+{
+ acl_add_arg(curr_ip_dns_list, aclpvt[-0].string);
+ } break;
+case 40:
+# line 520 "acltext.y"
+{
+ acl_add_arg(curr_ip_dns_list, aclpvt[-0].string);
+ } break;
+case 41:
+# line 526 "acltext.y"
+{
+ char tmp_str[255];
+
+ util_sprintf(tmp_str, "%s+%s", aclpvt[-1].string, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-1].string);
+ PERM_FREE(aclpvt[-0].string);
+ acl_add_arg(curr_ip_dns_list, PERM_STRDUP(tmp_str));
+ } break;
+case 46:
+# line 543 "acltext.y"
+{
+ if ( ACL_ExprAddArg(NULL, curr_expr, "user") < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAddArg(NULL, curr_expr, "group") < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 47:
+# line 562 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if (strcmp(aclpvt[-2].string, "database") == 0) {
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-1].string);
+ } else {
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index(aclpvt[-2].string), aclpvt[-2].string, aclpvt[-1].string, NULL) < 0 ) {
+ }
+ PERM_FREE(aclpvt[-2].string);
+ }
+ } break;
+case 48:
+# line 575 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if (strcmp(aclpvt[-2].string, "database") == 0) {
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-1].string);
+ } else {
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index(aclpvt[-2].string), aclpvt[-2].string, aclpvt[-1].string, NULL) < 0 ) {
+ }
+ PERM_FREE(aclpvt[-2].string);
+ }
+ } break;
+case 56:
+# line 611 "acltext.y"
+{
+ curr_acl = ACL_AclNew(NULL, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ aclerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ } break;
+case 57:
+# line 620 "acltext.y"
+{
+ curr_acl = ACL_AclNew(NULL, aclpvt[-0].string);
+ PERM_FREE(aclpvt[-0].string);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ aclerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ } break;
+case 63:
+# line 641 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_RESPONSE) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ aclerror("Could not set deny processing flags");
+ return(-1);
+ }
+ } break;
+case 65:
+# line 659 "acltext.y"
+{
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_RESPONSE) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 67:
+# line 674 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( ACL_ExprSetDenyWith(NULL, curr_expr,
+ aclpvt[-2].string, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprSetDenyWith() failed");
+ return(-1);
+ }
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+case 68:
+# line 687 "acltext.y"
+{
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ aclerror("Could not set authorization info");
+ return(-1);
+ }
+ } break;
+case 69:
+# line 701 "acltext.y"
+{
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 72:
+# line 713 "acltext.y"
+{
+ acl_string_lower(aclpvt[-0].string);
+ if ( ACL_ExprAddArg(NULL, curr_expr, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+case 75:
+# line 728 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index(aclpvt[-2].string), aclpvt[-2].string, aclpvt[-0].string, NULL) < 0 ) {
+ }
+ PERM_FREE(aclpvt[-2].string);
+ } break;
+case 76:
+# line 736 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index(aclpvt[-2].string), aclpvt[-2].string, aclpvt[-0].string, NULL) < 0 ) {
+ }
+ PERM_FREE(aclpvt[-2].string);
+ } break;
+case 77:
+# line 746 "acltext.y"
+{
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_ALLOW) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ } break;
+case 79:
+# line 756 "acltext.y"
+{
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_DENY) ;
+ if ( curr_expr == NULL ) {
+ aclerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ } break;
+case 81:
+# line 768 "acltext.y"
+{
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ aclerror("Could not add authorization");
+ return(-1);
+ }
+ } break;
+case 82:
+# line 775 "acltext.y"
+{
+ if ( ACL_ExprSetPFlags (NULL, curr_expr, pflags) < 0 ) {
+ aclerror("Could not set authorization processing flags");
+ return(-1);
+ }
+#ifdef DEBUG
+ if ( ACL_ExprDisplay(curr_expr) < 0 ) {
+ aclerror("ACL_ExprDisplay() failed");
+ return(-1);
+ }
+ printf("Parsed authorization.\n");
+#endif
+ } break;
+case 85:
+# line 795 "acltext.y"
+{
+ pflags = ACL_PFLAG_ABSOLUTE;
+ } break;
+case 86:
+# line 799 "acltext.y"
+{
+ pflags = ACL_PFLAG_ABSOLUTE;
+ } break;
+case 87:
+# line 803 "acltext.y"
+{
+ pflags = ACL_PFLAG_CONTENT;
+ } break;
+case 88:
+# line 807 "acltext.y"
+{
+ pflags = ACL_PFLAG_CONTENT;
+ } break;
+case 89:
+# line 811 "acltext.y"
+{
+ pflags = ACL_PFLAG_TERMINAL;
+ } break;
+case 90:
+# line 815 "acltext.y"
+{
+ pflags = ACL_PFLAG_TERMINAL;
+ } break;
+case 91:
+# line 821 "acltext.y"
+{
+ pflags |= ACL_PFLAG_CONTENT;
+ } break;
+case 92:
+# line 825 "acltext.y"
+{
+ pflags |= ACL_PFLAG_ABSOLUTE;
+ } break;
+case 93:
+# line 829 "acltext.y"
+{
+ pflags |= ACL_PFLAG_ABSOLUTE | ACL_PFLAG_CONTENT;
+ } break;
+case 94:
+# line 833 "acltext.y"
+{
+ pflags |= ACL_PFLAG_ABSOLUTE | ACL_PFLAG_CONTENT;
+ } break;
+case 95:
+# line 839 "acltext.y"
+{
+ pflags |= ACL_PFLAG_CONTENT;
+ } break;
+case 96:
+# line 843 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL;
+ } break;
+case 97:
+# line 847 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_CONTENT;
+ } break;
+case 98:
+# line 851 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_CONTENT;
+ } break;
+case 99:
+# line 857 "acltext.y"
+{
+ pflags |= ACL_PFLAG_ABSOLUTE;
+ } break;
+case 100:
+# line 861 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL;
+ } break;
+case 101:
+# line 865 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_ABSOLUTE;
+ } break;
+case 102:
+# line 869 "acltext.y"
+{
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_ABSOLUTE;
+ } break;
+case 105:
+# line 879 "acltext.y"
+{
+ acl_string_lower(aclpvt[-0].string);
+ if ( ACL_ExprAddArg(NULL, curr_expr, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ PERM_FREE( aclpvt[-0].string );
+ } break;
+case 107:
+# line 891 "acltext.y"
+{
+ if ( ACL_ExprAnd(NULL, curr_expr) < 0 ) {
+ aclerror("ACL_ExprAnd() failed");
+ return(-1);
+ }
+ } break;
+case 108:
+# line 898 "acltext.y"
+{
+ if ( ACL_ExprOr(NULL, curr_expr) < 0 ) {
+ aclerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ } break;
+case 111:
+# line 909 "acltext.y"
+{
+ if ( ACL_ExprNot(NULL, curr_expr) < 0 ) {
+ aclerror("ACL_ExprNot() failed");
+ return(-1);
+ }
+ } break;
+case 112:
+# line 918 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( ACL_ExprTerm(NULL, curr_expr,
+ aclpvt[-2].string, (CmpOp_t) aclpvt[-1].ival, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ return(-1);
+ }
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+case 113:
+# line 931 "acltext.y"
+{
+ acl_string_lower(aclpvt[-2].string);
+ if ( ACL_ExprTerm(NULL, curr_expr,
+ aclpvt[-2].string, (CmpOp_t) aclpvt[-1].ival, aclpvt[-0].string) < 0 ) {
+ aclerror("ACL_ExprTerm() failed");
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ return(-1);
+ }
+ PERM_FREE(aclpvt[-2].string);
+ PERM_FREE(aclpvt[-0].string);
+ } break;
+ }
+ goto aclstack; /* reset registers in driver code */
+}
+
diff --git a/lib/libaccess/acl.tab.h b/lib/libaccess/acl.tab.h
new file mode 100644
index 00000000..359f290a
--- /dev/null
+++ b/lib/libaccess/acl.tab.h
@@ -0,0 +1,44 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+typedef union
+#ifdef __cplusplus
+ ACLSTYPE
+#endif
+ {
+ char *string;
+ int ival;
+} ACLSTYPE;
+extern ACLSTYPE acllval;
+# define ACL_ABSOLUTE_TOK 257
+# define ACL_ACL_TOK 258
+# define ACL_ALLOW_TOK 259
+# define ACL_ALWAYS_TOK 260
+# define ACL_AND_TOK 261
+# define ACL_AT_TOK 262
+# define ACL_AUTHENTICATE_TOK 263
+# define ACL_CONTENT_TOK 264
+# define ACL_DEFAULT_TOK 265
+# define ACL_DENY_TOK 266
+# define ACL_GROUP_TOK 267
+# define ACL_IN_TOK 268
+# define ACL_INHERIT_TOK 269
+# define ACL_NOT_TOK 270
+# define ACL_NULL_TOK 271
+# define ACL_OR_TOK 272
+# define ACL_QSTRING_TOK 273
+# define ACL_READ_TOK 274
+# define ACL_TERMINAL_TOK 275
+# define ACL_VARIABLE_TOK 276
+# define ACL_VERSION_TOK 277
+# define ACL_WRITE_TOK 278
+# define ACL_WITH_TOK 279
+# define ACL_EQ_TOK 280
+# define ACL_GE_TOK 281
+# define ACL_GT_TOK 282
+# define ACL_LE_TOK 283
+# define ACL_LT_TOK 284
+# define ACL_NE_TOK 285
diff --git a/lib/libaccess/acl.yy.cpp b/lib/libaccess/acl.yy.cpp
new file mode 100644
index 00000000..90821330
--- /dev/null
+++ b/lib/libaccess/acl.yy.cpp
@@ -0,0 +1,1995 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define ACL_FLEX_MAJOR_VERSION 2
+#define ACL_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+
+/* Use prototypes in function declarations. */
+#define ACL_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define ACL_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define ACL_USE_PROTOS
+#define ACL_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define ACL_USE_CONST
+#define ACL_USE_PROTOS
+#endif
+
+#ifdef ACL_USE_CONST
+#define aclconst const
+#else
+#define aclconst
+#endif
+
+
+#ifdef ACL_USE_PROTOS
+#define ACL_PROTO(proto) proto
+#else
+#define ACL_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define ACL_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define ACL_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN acl_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The ACLSTATE alias is for lex
+ * compatibility.
+ */
+#define ACL_START ((acl_start - 1) / 2)
+#define ACLSTATE ACL_START
+
+/* Action number for EOF rule of a given start state. */
+#define ACL_STATE_EOF(state) (ACL_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define ACL_NEW_FILE aclrestart( aclin )
+
+#define ACL_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define ACL_BUF_SIZE 16384
+
+typedef struct acl_buffer_state *ACL_BUFFER_STATE;
+
+extern int aclleng;
+extern FILE *aclin, *aclout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * aclless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the aclless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define aclless(n) \
+ do \
+ { \
+ /* Undo effects of setting up acltext. */ \
+ *acl_cp = acl_hold_char; \
+ ACL_RESTORE_ACL_MORE_OFFSET \
+ acl_c_buf_p = acl_cp = acl_bp + n - ACL_MORE_ADJ; \
+ ACL_DO_BEFORE_ACTION; /* set up acltext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) aclunput( c, acltext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int acl_size_t;
+
+
+struct acl_buffer_state
+ {
+ FILE *acl_input_file;
+
+ char *acl_ch_buf; /* input buffer */
+ char *acl_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ acl_size_t acl_buf_size;
+
+ /* Number of characters read into acl_ch_buf, not including EOB
+ * characters.
+ */
+ int acl_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can PERM_REALLOC() it to grow it, and should PERM_FREE() it to
+ * delete it.
+ */
+ int acl_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int acl_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int acl_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int acl_fill_buffer;
+
+ int acl_buffer_status;
+#define ACL_BUFFER_NEW 0
+#define ACL_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as ACL_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via aclrestart()), so that the user can continue scanning by
+ * just pointing aclin at a new input file.
+ */
+#define ACL_BUFFER_EOF_PENDING 2
+ };
+
+static ACL_BUFFER_STATE acl_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define ACL_CURRENT_BUFFER acl_current_buffer
+
+
+/* acl_hold_char holds the character lost when acltext is formed. */
+static char acl_hold_char;
+
+static int acl_n_chars; /* number of characters read into acl_ch_buf */
+
+
+int aclleng;
+
+/* Points to current character in buffer. */
+static char *acl_c_buf_p = (char *) 0;
+static int acl_init = 1; /* whether we need to initialize */
+static int acl_start = 0; /* start state number */
+
+/* Flag which is used to allow aclwrap()'s to do buffer switches
+ * instead of setting up a fresh aclin. A bit of a hack ...
+ */
+static int acl_did_buffer_switch_on_eof;
+
+void aclrestart ACL_PROTO(( FILE *input_file ));
+
+void acl_switch_to_buffer ACL_PROTO(( ACL_BUFFER_STATE new_buffer ));
+void acl_load_buffer_state ACL_PROTO(( void ));
+ACL_BUFFER_STATE acl_create_buffer ACL_PROTO(( FILE *file, int size ));
+void acl_delete_buffer ACL_PROTO(( ACL_BUFFER_STATE b ));
+void acl_init_buffer ACL_PROTO(( ACL_BUFFER_STATE b, FILE *file ));
+void acl_flush_buffer ACL_PROTO(( ACL_BUFFER_STATE b ));
+#define ACL_FLUSH_BUFFER acl_flush_buffer( acl_current_buffer )
+
+ACL_BUFFER_STATE acl_scan_buffer ACL_PROTO(( char *base, acl_size_t size ));
+ACL_BUFFER_STATE acl_scan_string ACL_PROTO(( aclconst char *str ));
+ACL_BUFFER_STATE acl_scan_bytes ACL_PROTO(( aclconst char *bytes, int len ));
+
+static void *ACL_FLEX_ALLOC ACL_PROTO(( acl_size_t ));
+static void *ACL_FLEX_REALLOC ACL_PROTO(( void *, acl_size_t ));
+static void ACL_FLEX_FREE ACL_PROTO(( void * ));
+
+#define acl_new_buffer acl_create_buffer
+
+#define acl_set_interactive(is_interactive) \
+ { \
+ if ( ! acl_current_buffer ) \
+ acl_current_buffer = acl_create_buffer( aclin, ACL_BUF_SIZE ); \
+ acl_current_buffer->acl_is_interactive = is_interactive; \
+ }
+
+#define acl_set_bol(at_bol) \
+ { \
+ if ( ! acl_current_buffer ) \
+ acl_current_buffer = acl_create_buffer( aclin, ACL_BUF_SIZE ); \
+ acl_current_buffer->acl_at_bol = at_bol; \
+ }
+
+#define ACL_AT_BOL() (acl_current_buffer->acl_at_bol)
+
+typedef unsigned char ACL_CHAR;
+FILE *aclin = (FILE *) 0, *aclout = (FILE *) 0;
+typedef int acl_state_type;
+extern char *acltext;
+#define acltext_ptr acltext
+
+static acl_state_type acl_get_previous_state ACL_PROTO(( void ));
+static acl_state_type acl_try_NUL_trans ACL_PROTO(( acl_state_type current_state ));
+static int acl_get_next_buffer ACL_PROTO(( void ));
+static void acl_fatal_error ACL_PROTO(( aclconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up acltext.
+ */
+#define ACL_DO_BEFORE_ACTION \
+ acltext_ptr = acl_bp; \
+ aclleng = (int) (acl_cp - acl_bp); \
+ acl_hold_char = *acl_cp; \
+ *acl_cp = '\0'; \
+ acl_c_buf_p = acl_cp;
+
+#define ACL_NUM_RULES 30
+#define ACL_END_OF_BUFFER 31
+static aclconst short int acl_accept[104] =
+ { 0,
+ 0, 0, 31, 30, 2, 1, 30, 30, 3, 28,
+ 29, 25, 22, 24, 29, 29, 29, 29, 29, 29,
+ 29, 29, 29, 2, 1, 27, 0, 4, 3, 29,
+ 26, 23, 29, 29, 29, 29, 9, 29, 29, 29,
+ 14, 29, 21, 29, 29, 29, 29, 6, 29, 29,
+ 20, 29, 29, 29, 29, 29, 19, 29, 29, 29,
+ 29, 29, 29, 29, 29, 29, 13, 29, 29, 29,
+ 18, 29, 7, 29, 29, 29, 29, 29, 29, 29,
+ 29, 8, 29, 29, 29, 29, 29, 29, 29, 29,
+ 11, 12, 15, 29, 17, 5, 29, 16, 29, 29,
+
+ 29, 10, 0
+ } ;
+
+static aclconst int acl_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 4, 5, 6, 1, 1, 1, 1, 7,
+ 7, 8, 1, 7, 8, 8, 1, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 1, 7, 9,
+ 10, 11, 1, 1, 12, 13, 14, 15, 16, 17,
+ 8, 18, 19, 8, 8, 20, 21, 22, 23, 8,
+ 8, 24, 25, 26, 27, 28, 29, 8, 30, 8,
+ 1, 1, 1, 1, 8, 1, 12, 13, 14, 15,
+
+ 16, 17, 8, 18, 19, 8, 8, 20, 21, 22,
+ 23, 8, 8, 24, 25, 26, 27, 28, 29, 8,
+ 30, 8, 7, 1, 7, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static aclconst int acl_meta[31] =
+ { 0,
+ 1, 1, 2, 1, 1, 1, 1, 3, 1, 1,
+ 1, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3
+ } ;
+
+static aclconst short int acl_base[108] =
+ { 0,
+ 0, 0, 118, 119, 115, 0, 106, 28, 0, 119,
+ 0, 105, 119, 104, 21, 90, 96, 89, 87, 85,
+ 92, 91, 87, 103, 0, 119, 33, 119, 0, 0,
+ 119, 119, 79, 83, 17, 87, 0, 75, 78, 22,
+ 81, 72, 0, 73, 72, 69, 71, 0, 70, 80,
+ 0, 73, 64, 77, 58, 71, 0, 65, 60, 66,
+ 63, 53, 51, 64, 63, 51, 0, 53, 57, 56,
+ 0, 47, 0, 48, 50, 49, 50, 50, 46, 44,
+ 40, 0, 39, 38, 37, 36, 49, 38, 43, 39,
+ 0, 0, 0, 36, 0, 0, 36, 0, 33, 16,
+
+ 24, 0, 119, 48, 51, 54, 29
+ } ;
+
+static aclconst short int acl_def[108] =
+ { 0,
+ 103, 1, 103, 103, 103, 104, 103, 105, 106, 103,
+ 107, 103, 103, 103, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 103, 104, 103, 105, 103, 106, 107,
+ 103, 103, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+
+ 107, 107, 0, 103, 103, 103, 103
+ } ;
+
+static aclconst short int acl_nxt[150] =
+ { 0,
+ 4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
+ 14, 15, 11, 16, 17, 11, 11, 11, 18, 11,
+ 11, 19, 20, 11, 11, 21, 11, 22, 23, 11,
+ 28, 30, 28, 33, 34, 28, 49, 28, 54, 102,
+ 35, 101, 36, 55, 100, 50, 37, 38, 25, 99,
+ 25, 27, 27, 27, 29, 98, 29, 97, 96, 95,
+ 94, 93, 92, 91, 90, 89, 88, 87, 86, 85,
+ 84, 83, 82, 81, 80, 79, 78, 77, 76, 75,
+ 74, 73, 72, 71, 70, 69, 68, 67, 66, 65,
+ 64, 63, 62, 61, 60, 59, 58, 57, 56, 53,
+
+ 52, 51, 48, 47, 24, 46, 45, 44, 43, 42,
+ 41, 40, 39, 32, 31, 26, 24, 103, 3, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103
+ } ;
+
+static aclconst short int acl_chk[150] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 8, 107, 8, 15, 15, 27, 35, 27, 40, 101,
+ 15, 100, 15, 40, 99, 35, 15, 15, 104, 97,
+ 104, 105, 105, 105, 106, 94, 106, 90, 89, 88,
+ 87, 86, 85, 84, 83, 81, 80, 79, 78, 77,
+ 76, 75, 74, 72, 70, 69, 68, 66, 65, 64,
+ 63, 62, 61, 60, 59, 58, 56, 55, 54, 53,
+ 52, 50, 49, 47, 46, 45, 44, 42, 41, 39,
+
+ 38, 36, 34, 33, 24, 23, 22, 21, 20, 19,
+ 18, 17, 16, 14, 12, 7, 5, 3, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103
+ } ;
+
+static acl_state_type acl_last_accepting_state;
+static char *acl_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define aclmore() aclmore_used_but_not_detected
+#define ACL_MORE_ADJ 0
+#define ACL_RESTORE_ACL_MORE_OFFSET
+char *acltext;
+#line 1 "aclscan.l"
+#define INITIAL 0
+/*
+ * Lexical analyzer for ACL
+ */
+#line 6 "aclscan.l"
+#include "acl.tab.h" /* token codes */
+#include <base/file.h>
+#include <libaccess/acl.h>
+#include <libaccess/nserror.h>
+#include "aclpriv.h"
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <libaccess/aclerror.h>
+#ifdef XP_WIN32
+#include <io.h>
+#endif
+
+#include "parse.h"
+#include "aclscan.h"
+
+static int acl_scanner_input(char *buffer, int max_size);
+
+#define ACL_NEVER_INTERACTIVE 1
+#undef ACL_INPUT
+#define ACL_INPUT(buf, result, max) (result = acl_scanner_input(buf, max))
+
+static int acl_lineno;
+static int acl_tokenpos;
+static char acl_filename[500];
+static NSErr_t *acl_errp;
+static int acl_use_buffer;
+static char *acl_buffer;
+static int acl_buffer_length;
+static int acl_buffer_offset;
+static char *last_string;
+static SYS_FILE acl_prfd;
+
+
+#line 466 "acl.yy.cpp"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef ACL_SKIP_ACLWRAP
+#ifdef __cplusplus
+extern "C" int aclwrap ACL_PROTO(( void ));
+#else
+extern int aclwrap ACL_PROTO(( void ));
+#endif
+#endif
+
+#ifndef ACL_NO_UNPUT
+static void aclunput ACL_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef acltext_ptr
+static void acl_flex_strncpy ACL_PROTO(( char *, aclconst char *, int ));
+#endif
+
+#ifdef ACL_NEED_STRLEN
+static int acl_flex_strlen ACL_PROTO(( aclconst char * ));
+#endif
+
+#ifndef ACL_NO_INPUT
+#ifdef __cplusplus
+static int aclinput ACL_PROTO(( void ));
+#else
+static int input ACL_PROTO(( void ));
+#endif
+#endif
+
+#if ACL_STACK_USED
+static int acl_start_stack_ptr = 0;
+static int acl_start_stack_depth = 0;
+static int *acl_start_stack = 0;
+#ifndef ACL_NO_PUSH_STATE
+static void acl_push_state ACL_PROTO(( int new_state ));
+#endif
+#ifndef ACL_NO_POP_STATE
+static void acl_pop_state ACL_PROTO(( void ));
+#endif
+#ifndef ACL_NO_TOP_STATE
+static int acl_top_state ACL_PROTO(( void ));
+#endif
+
+#else
+#define ACL_NO_PUSH_STATE 1
+#define ACL_NO_POP_STATE 1
+#define ACL_NO_TOP_STATE 1
+#endif
+
+#ifdef ACL_MALLOC_DECL
+ACL_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef ACL_READ_BUF_SIZE
+#define ACL_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( acltext, aclleng, 1, aclout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or ACL_NULL,
+ * is returned in "result".
+ */
+#ifndef ACL_INPUT
+#define ACL_INPUT(buf,result,max_size) \
+ if ( acl_current_buffer->acl_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( aclin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( aclin ) ) \
+ ACL_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, aclin )) == 0) \
+ && ferror( aclin ) ) \
+ ACL_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "aclterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef aclterminate
+#define aclterminate() return ACL_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef ACL_START_STACK_INCR
+#define ACL_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef ACL_FATAL_ERROR
+#define ACL_FATAL_ERROR(msg) acl_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef ACL_DECL
+#define ACL_DECL int acllex ACL_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after acltext and aclleng
+ * have been set up.
+ */
+#ifndef ACL_USER_ACTION
+#define ACL_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef ACL_BREAK
+#define ACL_BREAK break;
+#endif
+
+#define ACL_RULE_SETUP \
+ ACL_USER_ACTION
+
+ACL_DECL
+ {
+ register acl_state_type acl_current_state;
+ register char *acl_cp, *acl_bp;
+ register int acl_act;
+
+#line 47 "aclscan.l"
+
+
+#line 620 "acl.yy.cpp"
+
+ if ( acl_init )
+ {
+ acl_init = 0;
+
+#ifdef ACL_USER_INIT
+ ACL_USER_INIT;
+#endif
+
+ if ( ! acl_start )
+ acl_start = 1; /* first start state */
+
+ if ( ! aclin )
+ aclin = stdin;
+
+ if ( ! aclout )
+ aclout = stdout;
+
+ if ( ! acl_current_buffer )
+ acl_current_buffer =
+ acl_create_buffer( aclin, ACL_BUF_SIZE );
+
+ acl_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ acl_cp = acl_c_buf_p;
+
+ /* Support of acltext. */
+ *acl_cp = acl_hold_char;
+
+ /* acl_bp points to the position in acl_ch_buf of the start of
+ * the current run.
+ */
+ acl_bp = acl_cp;
+
+ acl_current_state = acl_start;
+acl_match:
+ do
+ {
+ register ACL_CHAR acl_c = acl_ec[ACL_SC_TO_UI(*acl_cp)];
+ if ( acl_accept[acl_current_state] )
+ {
+ acl_last_accepting_state = acl_current_state;
+ acl_last_accepting_cpos = acl_cp;
+ }
+ while ( acl_chk[acl_base[acl_current_state] + acl_c] != acl_current_state )
+ {
+ acl_current_state = (int) acl_def[acl_current_state];
+ if ( acl_current_state >= 104 )
+ acl_c = acl_meta[(unsigned int) acl_c];
+ }
+ acl_current_state = acl_nxt[acl_base[acl_current_state] + (unsigned int) acl_c];
+ ++acl_cp;
+ }
+ while ( acl_base[acl_current_state] != 119 );
+
+acl_find_action:
+ acl_act = acl_accept[acl_current_state];
+ if ( acl_act == 0 )
+ { /* have to back up */
+ acl_cp = acl_last_accepting_cpos;
+ acl_current_state = acl_last_accepting_state;
+ acl_act = acl_accept[acl_current_state];
+ }
+
+ ACL_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( acl_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of ACL_DO_BEFORE_ACTION */
+ *acl_cp = acl_hold_char;
+ acl_cp = acl_last_accepting_cpos;
+ acl_current_state = acl_last_accepting_state;
+ goto acl_find_action;
+
+case 1:
+ACL_RULE_SETUP
+#line 49 "aclscan.l"
+{
+ acl_lineno++;
+ acl_tokenpos = 0;
+ aclless(1);
+ }
+ ACL_BREAK
+case 2:
+ACL_RULE_SETUP
+#line 55 "aclscan.l"
+;
+ ACL_BREAK
+case 3:
+ACL_RULE_SETUP
+#line 57 "aclscan.l"
+;
+ ACL_BREAK
+case ACL_STATE_EOF(INITIAL):
+#line 59 "aclscan.l"
+{
+ acllval.string = NULL;
+ last_string = acllval.string;
+ return(0);
+ }
+ ACL_BREAK
+case 4:
+ACL_RULE_SETUP
+#line 65 "aclscan.l"
+{
+ acllval.string = PERM_STRDUP( acltext+1 );
+ last_string = acllval.string;
+ if ( acllval.string[aclleng-2] != '"' )
+ fprintf(stderr, "Unterminated string\n") ;
+ else
+ acllval.string[aclleng-2] = '\0';
+ acl_tokenpos += aclleng;
+ return ACL_QSTRING_TOK;
+ }
+ ACL_BREAK
+case 5:
+ACL_RULE_SETUP
+#line 77 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_ABSOLUTE_TOK;
+ }
+ ACL_BREAK
+case 6:
+ACL_RULE_SETUP
+#line 83 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_ACL_TOK;
+ }
+ ACL_BREAK
+case 7:
+ACL_RULE_SETUP
+#line 89 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_ALLOW_TOK;
+ }
+ ACL_BREAK
+case 8:
+ACL_RULE_SETUP
+#line 95 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_ALWAYS_TOK;
+ }
+ ACL_BREAK
+case 9:
+ACL_RULE_SETUP
+#line 101 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_AT_TOK;
+ }
+ ACL_BREAK
+case 10:
+ACL_RULE_SETUP
+#line 107 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_AUTHENTICATE_TOK;
+ }
+ ACL_BREAK
+case 11:
+ACL_RULE_SETUP
+#line 113 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_CONTENT_TOK;
+ }
+ ACL_BREAK
+case 12:
+ACL_RULE_SETUP
+#line 119 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_DEFAULT_TOK;
+ }
+ ACL_BREAK
+case 13:
+ACL_RULE_SETUP
+#line 125 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_DENY_TOK;
+ }
+ ACL_BREAK
+case 14:
+ACL_RULE_SETUP
+#line 131 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_IN_TOK;
+ }
+ ACL_BREAK
+case 15:
+ACL_RULE_SETUP
+#line 137 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_INHERIT_TOK;
+ }
+ ACL_BREAK
+case 16:
+ACL_RULE_SETUP
+#line 143 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_TERMINAL_TOK;
+ }
+ ACL_BREAK
+case 17:
+ACL_RULE_SETUP
+#line 149 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_VERSION_TOK;
+ }
+ ACL_BREAK
+case 18:
+ACL_RULE_SETUP
+#line 155 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_WITH_TOK;
+ }
+ ACL_BREAK
+case 19:
+ACL_RULE_SETUP
+#line 161 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return ACL_NOT_TOK;
+ }
+ ACL_BREAK
+case 20:
+ACL_RULE_SETUP
+#line 167 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = ACL_EXPR_OP_AND;
+ acl_tokenpos += aclleng;
+ return ACL_AND_TOK;
+ }
+ ACL_BREAK
+case 21:
+ACL_RULE_SETUP
+#line 174 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = ACL_EXPR_OP_OR;
+ acl_tokenpos += aclleng;
+ return ACL_OR_TOK;
+ }
+ ACL_BREAK
+case 22:
+ACL_RULE_SETUP
+#line 181 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_EQ;
+ acl_tokenpos += aclleng;
+ return ACL_EQ_TOK;
+ }
+ ACL_BREAK
+case 23:
+ACL_RULE_SETUP
+#line 188 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_GE;
+ acl_tokenpos += aclleng;
+ return ACL_GE_TOK;
+ }
+ ACL_BREAK
+case 24:
+ACL_RULE_SETUP
+#line 195 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_GT;
+ acl_tokenpos += aclleng;
+ return ACL_GT_TOK;
+ }
+ ACL_BREAK
+case 25:
+ACL_RULE_SETUP
+#line 202 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_LT;
+ acl_tokenpos += aclleng;
+ return ACL_LT_TOK;
+ }
+ ACL_BREAK
+case 26:
+ACL_RULE_SETUP
+#line 209 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_LE;
+ acl_tokenpos += aclleng;
+ return ACL_LE_TOK;
+ }
+ ACL_BREAK
+case 27:
+ACL_RULE_SETUP
+#line 216 "aclscan.l"
+{
+ last_string = NULL;
+ acllval.ival = CMP_OP_NE;
+ acl_tokenpos += aclleng;
+ return ACL_NE_TOK;
+ }
+ ACL_BREAK
+case 28:
+ACL_RULE_SETUP
+#line 223 "aclscan.l"
+{
+ last_string = NULL;
+ acl_tokenpos += aclleng;
+ return acltext[0];
+ }
+ ACL_BREAK
+case 29:
+ACL_RULE_SETUP
+#line 229 "aclscan.l"
+{
+ acl_tokenpos += aclleng;
+ acllval.string = PERM_STRDUP( acltext );
+ last_string = acllval.string;
+ return ACL_VARIABLE_TOK;
+ }
+ ACL_BREAK
+case 30:
+ACL_RULE_SETUP
+#line 235 "aclscan.l"
+ECHO;
+ ACL_BREAK
+#line 983 "acl.yy.cpp"
+
+ case ACL_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int acl_amount_of_matched_text = (int) (acl_cp - acltext_ptr) - 1;
+
+ /* Undo the effects of ACL_DO_BEFORE_ACTION. */
+ *acl_cp = acl_hold_char;
+ ACL_RESTORE_ACL_MORE_OFFSET
+
+ if ( acl_current_buffer->acl_buffer_status == ACL_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed aclin at a new source and called
+ * acllex(). If so, then we have to assure
+ * consistency between acl_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ acl_n_chars = acl_current_buffer->acl_n_chars;
+ acl_current_buffer->acl_input_file = aclin;
+ acl_current_buffer->acl_buffer_status = ACL_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for acl_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since acl_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( acl_c_buf_p <= &acl_current_buffer->acl_ch_buf[acl_n_chars] )
+ { /* This was really a NUL. */
+ acl_state_type acl_next_state;
+
+ acl_c_buf_p = acltext_ptr + acl_amount_of_matched_text;
+
+ acl_current_state = acl_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * acl_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ acl_next_state = acl_try_NUL_trans( acl_current_state );
+
+ acl_bp = acltext_ptr + ACL_MORE_ADJ;
+
+ if ( acl_next_state )
+ {
+ /* Consume the NUL. */
+ acl_cp = ++acl_c_buf_p;
+ acl_current_state = acl_next_state;
+ goto acl_match;
+ }
+
+ else
+ {
+ acl_cp = acl_c_buf_p;
+ goto acl_find_action;
+ }
+ }
+
+ else switch ( acl_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ acl_did_buffer_switch_on_eof = 0;
+
+ if ( aclwrap() )
+ {
+ /* Note: because we've taken care in
+ * acl_get_next_buffer() to have set up
+ * acltext, we can now set up
+ * acl_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * ACL_NULL, it'll still work - another
+ * ACL_NULL will get returned.
+ */
+ acl_c_buf_p = acltext_ptr + ACL_MORE_ADJ;
+
+ acl_act = ACL_STATE_EOF(ACL_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! acl_did_buffer_switch_on_eof )
+ ACL_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ acl_c_buf_p =
+ acltext_ptr + acl_amount_of_matched_text;
+
+ acl_current_state = acl_get_previous_state();
+
+ acl_cp = acl_c_buf_p;
+ acl_bp = acltext_ptr + ACL_MORE_ADJ;
+ goto acl_match;
+
+ case EOB_ACT_LAST_MATCH:
+ acl_c_buf_p =
+ &acl_current_buffer->acl_ch_buf[acl_n_chars];
+
+ acl_current_state = acl_get_previous_state();
+
+ acl_cp = acl_c_buf_p;
+ acl_bp = acltext_ptr + ACL_MORE_ADJ;
+ goto acl_find_action;
+ }
+ break;
+ }
+
+ default:
+ ACL_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of acllex */
+
+
+/* acl_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int acl_get_next_buffer()
+ {
+ register char *dest = acl_current_buffer->acl_ch_buf;
+ register char *source = acltext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( acl_c_buf_p > &acl_current_buffer->acl_ch_buf[acl_n_chars + 1] )
+ ACL_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( acl_current_buffer->acl_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( acl_c_buf_p - acltext_ptr - ACL_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (acl_c_buf_p - acltext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( acl_current_buffer->acl_buffer_status == ACL_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ acl_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ acl_current_buffer->acl_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef ACL_USES_REJECT
+ ACL_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ ACL_BUFFER_STATE b = acl_current_buffer;
+
+ int acl_c_buf_p_offset =
+ (int) (acl_c_buf_p - b->acl_ch_buf);
+
+ if ( b->acl_is_our_buffer )
+ {
+ int new_size = b->acl_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->acl_buf_size += b->acl_buf_size / 8;
+ else
+ b->acl_buf_size *= 2;
+
+ b->acl_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ ACL_FLEX_REALLOC( (void *) b->acl_ch_buf,
+ b->acl_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->acl_ch_buf = 0;
+
+ if ( ! b->acl_ch_buf )
+ ACL_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ acl_c_buf_p = &b->acl_ch_buf[acl_c_buf_p_offset];
+
+ num_to_read = acl_current_buffer->acl_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > ACL_READ_BUF_SIZE )
+ num_to_read = ACL_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ ACL_INPUT( (&acl_current_buffer->acl_ch_buf[number_to_move]),
+ acl_n_chars, num_to_read );
+ }
+
+ if ( acl_n_chars == 0 )
+ {
+ if ( number_to_move == ACL_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ aclrestart( aclin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ acl_current_buffer->acl_buffer_status =
+ ACL_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ acl_n_chars += number_to_move;
+ acl_current_buffer->acl_ch_buf[acl_n_chars] = ACL_END_OF_BUFFER_CHAR;
+ acl_current_buffer->acl_ch_buf[acl_n_chars + 1] = ACL_END_OF_BUFFER_CHAR;
+
+ acltext_ptr = &acl_current_buffer->acl_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* acl_get_previous_state - get the state just before the EOB char was reached */
+
+static acl_state_type acl_get_previous_state()
+ {
+ register acl_state_type acl_current_state;
+ register char *acl_cp;
+
+ acl_current_state = acl_start;
+
+ for ( acl_cp = acltext_ptr + ACL_MORE_ADJ; acl_cp < acl_c_buf_p; ++acl_cp )
+ {
+ register ACL_CHAR acl_c = (*acl_cp ? acl_ec[ACL_SC_TO_UI(*acl_cp)] : 1);
+ if ( acl_accept[acl_current_state] )
+ {
+ acl_last_accepting_state = acl_current_state;
+ acl_last_accepting_cpos = acl_cp;
+ }
+ while ( acl_chk[acl_base[acl_current_state] + acl_c] != acl_current_state )
+ {
+ acl_current_state = (int) acl_def[acl_current_state];
+ if ( acl_current_state >= 104 )
+ acl_c = acl_meta[(unsigned int) acl_c];
+ }
+ acl_current_state = acl_nxt[acl_base[acl_current_state] + (unsigned int) acl_c];
+ }
+
+ return acl_current_state;
+ }
+
+
+/* acl_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = acl_try_NUL_trans( current_state );
+ */
+
+#ifdef ACL_USE_PROTOS
+static acl_state_type acl_try_NUL_trans( acl_state_type acl_current_state )
+#else
+static acl_state_type acl_try_NUL_trans( acl_current_state )
+acl_state_type acl_current_state;
+#endif
+ {
+ register int acl_is_jam;
+ register char *acl_cp = acl_c_buf_p;
+
+ register ACL_CHAR acl_c = 1;
+ if ( acl_accept[acl_current_state] )
+ {
+ acl_last_accepting_state = acl_current_state;
+ acl_last_accepting_cpos = acl_cp;
+ }
+ while ( acl_chk[acl_base[acl_current_state] + acl_c] != acl_current_state )
+ {
+ acl_current_state = (int) acl_def[acl_current_state];
+ if ( acl_current_state >= 104 )
+ acl_c = acl_meta[(unsigned int) acl_c];
+ }
+ acl_current_state = acl_nxt[acl_base[acl_current_state] + (unsigned int) acl_c];
+ acl_is_jam = (acl_current_state == 103);
+
+ return acl_is_jam ? 0 : acl_current_state;
+ }
+
+
+#ifndef ACL_NO_UNPUT
+#ifdef ACL_USE_PROTOS
+static void aclunput( int c, register char *acl_bp )
+#else
+static void aclunput( c, acl_bp )
+int c;
+register char *acl_bp;
+#endif
+ {
+ register char *acl_cp = acl_c_buf_p;
+
+ /* undo effects of setting up acltext */
+ *acl_cp = acl_hold_char;
+
+ if ( acl_cp < acl_current_buffer->acl_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = acl_n_chars + 2;
+ register char *dest = &acl_current_buffer->acl_ch_buf[
+ acl_current_buffer->acl_buf_size + 2];
+ register char *source =
+ &acl_current_buffer->acl_ch_buf[number_to_move];
+
+ while ( source > acl_current_buffer->acl_ch_buf )
+ *--dest = *--source;
+
+ acl_cp += (int) (dest - source);
+ acl_bp += (int) (dest - source);
+ acl_n_chars = acl_current_buffer->acl_buf_size;
+
+ if ( acl_cp < acl_current_buffer->acl_ch_buf + 2 )
+ ACL_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--acl_cp = (char) c;
+
+
+ acltext_ptr = acl_bp;
+ acl_hold_char = *acl_cp;
+ acl_c_buf_p = acl_cp;
+ }
+#endif /* ifndef ACL_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int aclinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *acl_c_buf_p = acl_hold_char;
+
+ if ( *acl_c_buf_p == ACL_END_OF_BUFFER_CHAR )
+ {
+ /* acl_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( acl_c_buf_p < &acl_current_buffer->acl_ch_buf[acl_n_chars] )
+ /* This was really a NUL. */
+ *acl_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = acl_c_buf_p - acltext_ptr;
+ ++acl_c_buf_p;
+
+ switch ( acl_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( aclwrap() )
+ {
+ acl_c_buf_p = acltext_ptr + offset;
+ return EOF;
+ }
+
+ if ( ! acl_did_buffer_switch_on_eof )
+ ACL_NEW_FILE;
+#ifdef __cplusplus
+ return aclinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ acl_c_buf_p = acltext_ptr + offset;
+ break;
+
+ case EOB_ACT_LAST_MATCH:
+#ifdef __cplusplus
+ ACL_FATAL_ERROR(
+ "unexpected last match in aclinput()" );
+#else
+ ACL_FATAL_ERROR(
+ "unexpected last match in input()" );
+#endif
+ }
+ }
+ }
+
+ c = *(unsigned char *) acl_c_buf_p; /* cast for 8-bit char's */
+ *acl_c_buf_p = '\0'; /* preserve acltext */
+ acl_hold_char = *++acl_c_buf_p;
+
+
+ return c;
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void aclrestart( FILE *input_file )
+#else
+void aclrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! acl_current_buffer )
+ acl_current_buffer = acl_create_buffer( aclin, ACL_BUF_SIZE );
+
+ acl_init_buffer( acl_current_buffer, input_file );
+ acl_load_buffer_state();
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void acl_switch_to_buffer( ACL_BUFFER_STATE new_buffer )
+#else
+void acl_switch_to_buffer( new_buffer )
+ACL_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( acl_current_buffer == new_buffer )
+ return;
+
+ if ( acl_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *acl_c_buf_p = acl_hold_char;
+ acl_current_buffer->acl_buf_pos = acl_c_buf_p;
+ acl_current_buffer->acl_n_chars = acl_n_chars;
+ }
+
+ acl_current_buffer = new_buffer;
+ acl_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (aclwrap()) processing, but the only time this flag
+ * is looked at is after aclwrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ acl_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void acl_load_buffer_state( void )
+#else
+void acl_load_buffer_state()
+#endif
+ {
+ acl_n_chars = acl_current_buffer->acl_n_chars;
+ acltext_ptr = acl_c_buf_p = acl_current_buffer->acl_buf_pos;
+ aclin = acl_current_buffer->acl_input_file;
+ acl_hold_char = *acl_c_buf_p;
+ }
+
+
+#ifdef ACL_USE_PROTOS
+ACL_BUFFER_STATE acl_create_buffer( FILE *file, int size )
+#else
+ACL_BUFFER_STATE acl_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ ACL_BUFFER_STATE b;
+
+ b = (ACL_BUFFER_STATE) ACL_FLEX_ALLOC( sizeof( struct acl_buffer_state ) );
+ if ( ! b )
+ ACL_FATAL_ERROR( "out of dynamic memory in acl_create_buffer()" );
+
+ b->acl_buf_size = size;
+
+ /* acl_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->acl_ch_buf = (char *) ACL_FLEX_ALLOC( b->acl_buf_size + 2 );
+ if ( ! b->acl_ch_buf )
+ ACL_FATAL_ERROR( "out of dynamic memory in acl_create_buffer()" );
+
+ b->acl_is_our_buffer = 1;
+
+ acl_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void acl_delete_buffer( ACL_BUFFER_STATE b )
+#else
+void acl_delete_buffer( b )
+ACL_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == acl_current_buffer )
+ acl_current_buffer = (ACL_BUFFER_STATE) 0;
+
+ if ( b->acl_is_our_buffer )
+ ACL_FLEX_FREE( (void *) b->acl_ch_buf );
+
+ ACL_FLEX_FREE( (void *) b );
+ }
+
+
+#ifndef ACL_ALWAYS_INTERACTIVE
+#ifndef ACL_NEVER_INTERACTIVE
+extern int isatty ACL_PROTO(( int ));
+#endif
+#endif
+
+#ifdef ACL_USE_PROTOS
+void acl_init_buffer( ACL_BUFFER_STATE b, FILE *file )
+#else
+void acl_init_buffer( b, file )
+ACL_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ acl_flush_buffer( b );
+
+ b->acl_input_file = file;
+ b->acl_fill_buffer = 1;
+
+#if ACL_ALWAYS_INTERACTIVE
+ b->acl_is_interactive = 1;
+#else
+#if ACL_NEVER_INTERACTIVE
+ b->acl_is_interactive = 0;
+#else
+ b->acl_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef ACL_USE_PROTOS
+void acl_flush_buffer( ACL_BUFFER_STATE b )
+#else
+void acl_flush_buffer( b )
+ACL_BUFFER_STATE b;
+#endif
+
+ {
+ b->acl_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->acl_ch_buf[0] = ACL_END_OF_BUFFER_CHAR;
+ b->acl_ch_buf[1] = ACL_END_OF_BUFFER_CHAR;
+
+ b->acl_buf_pos = &b->acl_ch_buf[0];
+
+ b->acl_at_bol = 1;
+ b->acl_buffer_status = ACL_BUFFER_NEW;
+
+ if ( b == acl_current_buffer )
+ acl_load_buffer_state();
+ }
+
+
+#ifndef ACL_NO_SCAN_BUFFER
+#ifdef ACL_USE_PROTOS
+ACL_BUFFER_STATE acl_scan_buffer( char *base, acl_size_t size )
+#else
+ACL_BUFFER_STATE acl_scan_buffer( base, size )
+char *base;
+acl_size_t size;
+#endif
+ {
+ ACL_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != ACL_END_OF_BUFFER_CHAR ||
+ base[size-1] != ACL_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (ACL_BUFFER_STATE) ACL_FLEX_ALLOC( sizeof( struct acl_buffer_state ) );
+ if ( ! b )
+ ACL_FATAL_ERROR( "out of dynamic memory in acl_scan_buffer()" );
+
+ b->acl_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->acl_buf_pos = b->acl_ch_buf = base;
+ b->acl_is_our_buffer = 0;
+ b->acl_input_file = 0;
+ b->acl_n_chars = b->acl_buf_size;
+ b->acl_is_interactive = 0;
+ b->acl_at_bol = 1;
+ b->acl_fill_buffer = 0;
+ b->acl_buffer_status = ACL_BUFFER_NEW;
+
+ acl_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef ACL_NO_SCAN_STRING
+#ifdef ACL_USE_PROTOS
+ACL_BUFFER_STATE acl_scan_string( aclconst char *str )
+#else
+ACL_BUFFER_STATE acl_scan_string( str )
+aclconst char *str;
+#endif
+ {
+ int len;
+ for ( len = 0; str[len]; ++len )
+ ;
+
+ return acl_scan_bytes( str, len );
+ }
+#endif
+
+
+#ifndef ACL_NO_SCAN_BYTES
+#ifdef ACL_USE_PROTOS
+ACL_BUFFER_STATE acl_scan_bytes( aclconst char *bytes, int len )
+#else
+ACL_BUFFER_STATE acl_scan_bytes( bytes, len )
+aclconst char *bytes;
+int len;
+#endif
+ {
+ ACL_BUFFER_STATE b;
+ char *buf;
+ acl_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) ACL_FLEX_ALLOC( n );
+ if ( ! buf )
+ ACL_FATAL_ERROR( "out of dynamic memory in acl_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = ACL_END_OF_BUFFER_CHAR;
+
+ b = acl_scan_buffer( buf, n );
+ if ( ! b )
+ ACL_FATAL_ERROR( "bad buffer in acl_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->acl_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef ACL_NO_PUSH_STATE
+#ifdef ACL_USE_PROTOS
+static void acl_push_state( int new_state )
+#else
+static void acl_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( acl_start_stack_ptr >= acl_start_stack_depth )
+ {
+ acl_size_t new_size;
+
+ acl_start_stack_depth += ACL_START_STACK_INCR;
+ new_size = acl_start_stack_depth * sizeof( int );
+
+ if ( ! acl_start_stack )
+ acl_start_stack = (int *) ACL_FLEX_ALLOC( new_size );
+
+ else
+ acl_start_stack = (int *) ACL_FLEX_REALLOC(
+ (void *) acl_start_stack, new_size );
+
+ if ( ! acl_start_stack )
+ ACL_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ acl_start_stack[acl_start_stack_ptr++] = ACL_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef ACL_NO_POP_STATE
+static void acl_pop_state()
+ {
+ if ( --acl_start_stack_ptr < 0 )
+ ACL_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(acl_start_stack[acl_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef ACL_NO_TOP_STATE
+static int acl_top_state()
+ {
+ return acl_start_stack[acl_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef ACL_EXIT_FAILURE
+#define ACL_EXIT_FAILURE 2
+#endif
+
+#ifdef ACL_USE_PROTOS
+static void acl_fatal_error( aclconst char msg[] )
+#else
+static void acl_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( ACL_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine aclless() so it works in section 3 code. */
+
+#undef aclless
+#define aclless(n) \
+ do \
+ { \
+ /* Undo effects of setting up acltext. */ \
+ acltext[aclleng] = acl_hold_char; \
+ acl_c_buf_p = acltext + n; \
+ acl_hold_char = *acl_c_buf_p; \
+ *acl_c_buf_p = '\0'; \
+ aclleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef acltext_ptr
+#ifdef ACL_USE_PROTOS
+static void acl_flex_strncpy( char *s1, aclconst char *s2, int n )
+#else
+static void acl_flex_strncpy( s1, s2, n )
+char *s1;
+aclconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef ACL_NEED_STRLEN
+#ifdef ACL_USE_PROTOS
+static int acl_flex_strlen( aclconst char *s )
+#else
+static int acl_flex_strlen( s )
+aclconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef ACL_USE_PROTOS
+static void *ACL_FLEX_ALLOC( acl_size_t size )
+#else
+static void *ACL_FLEX_ALLOC( size )
+acl_size_t size;
+#endif
+ {
+ return (void *) PERM_MALLOC( size );
+ }
+
+#ifdef ACL_USE_PROTOS
+static void *ACL_FLEX_REALLOC( void *ptr, acl_size_t size )
+#else
+static void *ACL_FLEX_REALLOC( ptr, size )
+void *ptr;
+acl_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) PERM_REALLOC( (char *) ptr, size );
+ }
+
+#ifdef ACL_USE_PROTOS
+static void ACL_FLEX_FREE( void *ptr )
+#else
+static void ACL_FLEX_FREE( ptr )
+void *ptr;
+#endif
+ {
+ PERM_FREE( ptr );
+ }
+
+#if ACL_MAIN
+int main()
+ {
+ acllex();
+ return 0;
+ }
+#endif
+#line 235 "aclscan.l"
+
+
+void
+acl_detab(char *t, char *s)
+{
+ int ii;
+ int pos;
+ int len;
+
+ if (s == NULL || t == NULL)
+ return;
+
+ len = strlen(s);
+ pos = 0;
+ for (ii = 0; ii < len; ii++) {
+ if (s[ii] == '\t') {
+ t[pos] = ' ';
+ } else {
+ t[pos] = s[ii];
+ }
+ pos++;
+ }
+ t[pos] = '\0';
+ return;
+}
+
+void
+aclerror(const char *s)
+{
+char errorStr[256];
+
+#if defined(UTEST) || defined(ACL_COMPILER)
+ printf("ACL file: %s\n", acl_filename);
+ printf("Syntax error at line: %d, token: %s\n", acl_lineno, acltext);
+ if ( last_string )
+ PERM_FREE(last_string);
+#else
+ sprintf(errorStr, "%d", acl_lineno);
+ if (acltext) {
+ nserrGenerate(acl_errp, ACLERRPARSE, ACLERR1780, ACL_Program,
+ 3, acl_filename, errorStr, acltext);
+ } else {
+ nserrGenerate(acl_errp, ACLERRPARSE, ACLERR1780, ACL_Program,
+ 2, acl_filename, errorStr);
+ }
+ if ( last_string )
+ PERM_FREE(last_string);
+#endif
+
+}
+
+int
+acl_InitScanner(NSErr_t *errp, char *filename, char *buffer)
+{
+ acl_errp = errp;
+ acl_lineno = 1;
+ acl_use_buffer = (filename == NULL) ? 1 : 0 ;
+ if ( filename != NULL ) {
+ strcpy(acl_filename, filename);
+#ifdef UTEST
+ aclin = fopen(filename, "r");
+ if ( aclin == NULL ) {
+ return(-1);
+ }
+#else
+ acl_prfd = system_fopenRO(filename);
+ if ( acl_prfd == NULL ) {
+ return(-1);
+ }
+ aclin = (FILE *) acl_prfd;
+#endif
+ aclrestart(aclin);
+ } else if ( buffer != NULL ) {
+ strcpy(acl_filename, "internal-buffer");
+ acl_buffer_offset = 0;
+ acl_buffer_length = strlen(buffer);
+ acl_buffer = PERM_STRDUP(buffer);
+ if (acl_buffer == NULL)
+ return(-1);
+ aclrestart(NULL);
+ } else {
+ return(-1);
+ }
+ return(0);
+}
+
+int
+acl_EndScanner()
+{
+ acl_lineno = 0;
+ if ( acl_use_buffer) {
+ if ( acl_buffer )
+ PERM_FREE(acl_buffer);
+ } else if ( aclin ) {
+#ifdef UTEST
+ fclose(aclin);
+#else
+ if ( acl_prfd ) {
+ system_fclose(acl_prfd);
+ acl_prfd = NULL;
+ }
+#endif
+ aclin = NULL ;
+ }
+ return(0);
+}
+
+int
+aclwrap()
+{
+ return(1);
+}
+
+static int
+acl_scanner_input(char *buffer, int max_size)
+{
+ int len = 0;
+
+ if ( acl_use_buffer ) {
+ len = (acl_buffer_length > max_size) ? max_size :
+ acl_buffer_length;
+ memcpy(buffer, (const void *) &acl_buffer[acl_buffer_offset],
+ len);
+ acl_buffer_length -= len;
+ acl_buffer_offset += len;
+ }
+#ifdef UTEST
+ else if ( ((len = fread( buffer, 1, max_size, aclin )) == 0)
+ && ferror( aclin ) ) {
+ aclerror( "scanner input failed" );
+ }
+#else
+ else if ( (len = system_fread( acl_prfd, buffer, max_size)) < 0 ) {
+ aclerror( "scanner input failed" );
+ }
+#endif
+
+ return(len);
+}
diff --git a/lib/libaccess/aclbuild.cpp b/lib/libaccess/aclbuild.cpp
new file mode 100644
index 00000000..8c4647dc
--- /dev/null
+++ b/lib/libaccess/aclbuild.cpp
@@ -0,0 +1,1360 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (aclbuild.c)
+ *
+ * This module provides functions for building Access Control List
+ * (ACL) structures in memory.
+ *
+ */
+
+#include <assert.h>
+#include "base/systems.h"
+#include "netsite.h"
+#include "libaccess/nsauth.h"
+#include "libaccess/nsuser.h"
+#include "libaccess/nsgroup.h"
+#include "libaccess/nsadb.h"
+#include "libaccess/aclerror.h"
+#include "libaccess/aclstruct.h"
+#include "libaccess/aclbuild.h"
+#include "libaccess/aclparse.h"
+#include "libaccess/acleval.h"
+#include "libaccess/usi.h"
+
+char * ACL_Program = "NSACL"; /* ACL facility name */
+
+/*
+ * Description (accCreate)
+ *
+ * This function creates a new access control context, which
+ * provides context information for a set of ACL definitions.
+ * The caller also provides a handle for a symbol table to be
+ * used to store definitions of ACL and rights names.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * stp - symbol table handle (may be null)
+ * pacc - pointer to returned context handle
+ *
+ * Returns:
+ *
+ * If the context is created successfully, the return value is zero.
+ * Otherwise it is a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int accCreate(NSErr_t * errp, void * stp, ACContext_t **pacc)
+{
+ ACContext_t * acc; /* pointer to new context */
+ int rv; /* result value */
+ int eid; /* error id */
+
+ *pacc = 0;
+
+ /* Do we need to create a symbol table? */
+ if (stp == 0) {
+
+ /* Yes, create a symbol table for ACL, rights, etc. names */
+ rv = symTableNew(&stp);
+ if (rv < 0) goto err_nomem1;
+ }
+
+ /* Allocate the context structure */
+ acc = (ACContext_t *)MALLOC(sizeof(ACContext_t));
+ if (acc == 0) goto err_nomem2;
+
+ /* Initialize it */
+ acc->acc_stp = stp;
+ acc->acc_acls = 0;
+ acc->acc_rights = 0;
+ acc->acc_refcnt = 0;
+
+ *pacc = acc;
+ return 0;
+
+ err_nomem1:
+ rv = ACLERRNOMEM;
+ eid = ACLERR3000;
+ goto err_ret;
+
+ err_nomem2:
+ rv = ACLERRNOMEM;
+ eid = ACLERR3020;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ return rv;
+}
+
+/*
+ * Description (accDestroy)
+ *
+ * This function destroys a set of ACL data structures referenced
+ * by a specified ACContext_t structure, including the ACContext_t
+ * itself.
+ *
+ * Arguments:
+ *
+ * acc - pointer to ACContext_t structure
+ * flags - bit flags (unused - must be zero)
+ */
+
+void accDestroy(ACContext_t * acc, int flags)
+{
+ ACL_t * acl;
+
+ if (acc != 0) {
+
+ /*
+ * First destroy all ACLs and any unnamed structures they reference.
+ * Note that aclDestroy() modifies the acc_acls list.
+ */
+ while ((acl = acc->acc_acls) != 0) {
+
+ aclDelete(acl);
+ }
+
+ /* If there's a symbol table, destroy everything it references */
+ if (acc->acc_stp != 0) {
+ symTableEnumerate(acc->acc_stp, 0, accDestroySym);
+
+ /* Destroy the symbol table itself */
+ symTableDestroy(acc->acc_stp, 0);
+ }
+
+ /* Free the ACContext_t structure */
+ FREE(acc);
+ }
+}
+
+/*
+ * Description (accDestroySym)
+ *
+ * This function is called to destroy the data structure associated
+ * with a specified Symbol_t symbol table entry. It examines the
+ * type of the symbol and calls the appropriate destructor.
+ *
+ * Arguments:
+ *
+ * sym - pointer to symbol table entry
+ * argp - unused - must be zero
+ *
+ * Returns:
+ *
+ * The return value is SYMENUMREMOVE.
+ */
+
+int accDestroySym(Symbol_t * sym, void * argp)
+{
+ switch (sym->sym_type) {
+ case ACLSYMACL: /* ACL */
+ aclDestroy((ACL_t *)sym);
+ break;
+
+ case ACLSYMRIGHT: /* access right */
+ {
+ RightDef_t * rdp = (RightDef_t *)sym;
+
+ if (rdp->rd_sym.sym_name != 0) {
+ FREE(rdp->rd_sym.sym_name);
+ }
+ FREE(rdp);
+ }
+ break;
+
+ case ACLSYMRDEF: /* access rights list */
+ aclRightSpecDestroy((RightSpec_t *)sym);
+ break;
+
+ case ACLSYMREALM: /* realm name */
+ aclRealmSpecDestroy((RealmSpec_t *)sym);
+ break;
+
+ case ACLSYMHOST: /* host specifications */
+ aclHostSpecDestroy((HostSpec_t *)sym);
+ break;
+
+ case ACLSYMUSER: /* user/group list */
+ aclUserSpecDestroy((UserSpec_t *)sym);
+ break;
+ }
+
+ return SYMENUMREMOVE;
+}
+
+/*
+ * Description (accReadFile)
+ *
+ * This function reads a specfied file containing ACL definitions
+ * and creates data structures in memory to represent the ACLs.
+ * The caller may provide a pointer to an existing ACContext_t
+ * structure which will serve as the root of the ACL structures,
+ * or else a new one will be created.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * aclfile - pointer to the ACL filename string
+ * pacc - value/result ACContext_t
+ *
+ * Returns:
+ *
+ * If the ACL file is read successfully, the return value is zero.
+ * Otherwise it is a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int accReadFile(NSErr_t * errp, char * aclfile, ACContext_t **pacc)
+{
+ ACContext_t * acc = *pacc; /* pointer to ACL root structure */
+ ACLFile_t * acf = 0; /* pointer to ACL file handle */
+ void * stp = 0; /* ACL symbol table handle */
+ int rv; /* result value */
+ int eid; /* error id value */
+
+ /* Initialize the ACL parser */
+ rv = aclParseInit();
+ if (rv < 0) goto err_init;
+
+ /* Do we need to create a new ACContext_t structure? */
+ if (acc == 0) {
+
+ /* Yes, create a symbol table for ACL, rights, etc. names */
+ rv = symTableNew(&stp);
+ if (rv < 0) goto err_crsym;
+
+ /* Create a root structure for the ACLs, including the symbol table */
+ rv = accCreate(errp, stp, &acc);
+ if (rv < 0) goto err_ret2;
+ }
+
+ /* Open the ACL definition file */
+ rv = aclFileOpen(errp, aclfile, 0, &acf);
+ if (rv < 0) goto err_ret3;
+
+ /* Parse the ACL definitions, building ACL structures in memory */
+ rv = aclACLParse(errp, acf, acc, 0);
+ if (rv < 0) goto err_ret4;
+
+ aclFileClose(acf, 0);
+
+ if (pacc) *pacc = acc;
+
+ return rv;
+
+ err_init:
+ eid = ACLERR3100;
+ goto err_ret;
+
+ err_crsym:
+ eid = ACLERR3120;
+ rv = ACLERRNOMEM;
+ goto err_ret;
+
+ err_ret4:
+ aclFileClose(acf, 0);
+ err_ret3:
+ /* Destroy the ACContext_t if we just created it */
+ if (acc != *pacc) {
+ accDestroy(acc, 0);
+ }
+ goto err_ret;
+
+ err_ret2:
+ symTableDestroy(stp, 0);
+
+ err_ret:
+ return rv;
+}
+
+/*
+ * Description (aclAuthDNSAdd)
+ *
+ * This function adds a DNS name specification to the DNS filter
+ * associated with a given host list. The DNS name specification is
+ * either a fully-qualified domain name or a domain name suffix,
+ * indicated by a leading ".", e.g. (".mcom.com"). The name
+ * components included in a suffix must be complete. For example,
+ * ".scape.com" will not match names ending in ".netscape.com".
+ *
+ * Arguments:
+ *
+ * hspp - pointer to host list pointer
+ * dnsspec - DNS name or suffix string pointer
+ * fqdn - non-zero if dnsspec is fully qualified
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero.
+ * An error is indicated by a negative return code (ACLERRxxxx
+ * - see aclerror.h).
+ */
+
+int aclAuthDNSAdd(HostSpec_t **hspp, char * dnsspec, int fqdn)
+{
+ HostSpec_t * hsp; /* host list pointer */
+ void * table; /* access control hash table pointer */
+ Symbol_t * sym; /* hash table entry pointer */
+ int rv; /* result value */
+
+ fqdn = (fqdn) ? 1 : 0;
+
+ /* Create the HostSpec_t if it doesn't exist */
+ hsp = *hspp;
+ if (hsp == 0) {
+
+ hsp = (HostSpec_t *)MALLOC(sizeof(HostSpec_t));
+ if (hsp == 0) goto err_nomem;
+ memset((void *)hsp, 0, sizeof(HostSpec_t));
+ hsp->hs_sym.sym_type = ACLSYMHOST;
+ }
+
+ /* Get pointer to hash table used for DNS filter */
+ table = hsp->hs_host.inh_dnf.dnf_hash;
+ if (table == 0) {
+
+ /* None there yet, so create one */
+ rv = symTableNew(&table);
+ if (rv < 0) goto punt;
+ hsp->hs_host.inh_dnf.dnf_hash = table;
+ }
+
+ /* See if the DNS spec is already in the table */
+ rv = symTableFindSym(table, dnsspec, fqdn, (void **)&sym);
+ if (rv < 0) {
+ if (rv != SYMERRNOSYM) goto punt;
+
+ /* It's not there, so add it */
+ sym = (Symbol_t *)MALLOC(sizeof(Symbol_t));
+ sym->sym_name = STRDUP(dnsspec);
+ sym->sym_type = fqdn;
+
+ rv = symTableAddSym(table, sym, (void *)sym);
+ if (rv < 0) goto err_nomem;
+ }
+
+ *hspp = hsp;
+
+ punt:
+ return rv;
+
+ err_nomem:
+ rv = ACLERRNOMEM;
+ goto punt;
+}
+
+/*
+ * Description (aclAuthIPAdd)
+ *
+ * This function adds an IP address specification to the IP filter
+ * associated with a given host list. The IP address specification
+ * consists of an IP host or network address and an IP netmask.
+ * For host addresses the netmask value is 255.255.255.255.
+ *
+ * Arguments:
+ *
+ * hspp - pointer to host list pointer
+ * ipaddr - IP host or network address
+ * netmask - IP netmask value
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero.
+ * An error is indicated by a negative return code (ACLERRxxxx
+ * - see aclerror.h).
+ */
+
+int aclAuthIPAdd(HostSpec_t **hspp, IPAddr_t ipaddr, IPAddr_t netmask)
+{
+ HostSpec_t * hsp; /* host list pointer */
+ IPFilter_t * ipf; /* IP filter pointer */
+ IPNode_t * ipn; /* current node pointer */
+ IPNode_t * lastipn; /* last (lower) node pointer */
+ IPLeaf_t * leaf; /* leaf node pointer */
+ IPAddr_t bitmask; /* bit mask for current node */
+ int lastbit; /* number of last bit set in netmask */
+ int i; /* loop index */
+
+ /* Create the HostSpec_t if it doesn't exist */
+ hsp = *hspp;
+ if (hsp == 0) {
+
+ hsp = (HostSpec_t *)MALLOC(sizeof(HostSpec_t));
+ if (hsp == 0) goto err_nomem;
+ memset((void *)hsp, 0, sizeof(HostSpec_t));
+ hsp->hs_sym.sym_type = ACLSYMHOST;
+ }
+
+ ipf = &hsp->hs_host.inh_ipf;
+
+ /* If the filter doesn't have a root node yet, create it */
+ if (ipf->ipf_tree == 0) {
+
+ /* Allocate node */
+ ipn = (IPNode_t *)MALLOC(sizeof(IPNode_t));
+ if (ipn == 0) goto err_nomem;
+
+ /* Initialize it to test bit 31, but without any descendants */
+ ipn->ipn_type = IPN_NODE;
+ ipn->ipn_bit = 31;
+ ipn->ipn_parent = NULL;
+ ipn->ipn_clear = NULL;
+ ipn->ipn_set = NULL;
+ ipn->ipn_masked = NULL;
+
+ /* Set it as the root node in the radix tree */
+ ipf->ipf_tree = ipn;
+ }
+
+ /* First we search the tree to see where this IP specification fits */
+
+ lastipn = NULL;
+
+ for (ipn = ipf->ipf_tree; (ipn != NULL) && (ipn->ipn_type == IPN_NODE); ) {
+
+ /* Get a mask for the bit this node tests */
+ bitmask = (IPAddr_t) 1<<ipn->ipn_bit;
+
+ /* Save pointer to last internal node */
+ lastipn = ipn;
+
+ /* Is this a bit we care about? */
+ if (bitmask & netmask) {
+
+ /* Yes, get address of set or clear descendant pointer */
+ ipn = (bitmask & ipaddr) ? ipn->ipn_set : ipn->ipn_clear;
+ }
+ else {
+ /* No, get the address of the masked descendant pointer */
+ ipn = ipn->ipn_masked;
+ }
+ }
+
+ /* Did we end up at a leaf node? */
+ if (ipn == NULL) {
+
+ /*
+ * No, well, we need to find a leaf node if possible. The
+ * reason is that we need an IP address and netmask to compare
+ * to the IP address and netmask we're inserting. We know that
+ * they're the same up to the bit tested by the lastipn node,
+ * but we need to know the *highest* order bit that's different.
+ * Any leaf node below lastipn will do.
+ */
+
+ leaf = NULL;
+ ipn = lastipn;
+
+ while (ipn != NULL) {
+
+ /* Look for any non-null child link of the current node */
+ for (i = 0; i < IPN_NLINKS; ++i) {
+ if (ipn->ipn_links[i]) break;
+ }
+
+ /*
+ * Fail search for leaf if no non-null child link found.
+ * This should only happen on the root node of the tree
+ * when the tree is empty.
+ */
+ if (i >= IPN_NLINKS) {
+ assert(ipn == ipf->ipf_tree);
+ break;
+ }
+
+ /* Step to the child node */
+ ipn = ipn->ipn_links[i];
+
+ /* Is it a leaf? */
+ if (ipn->ipn_type == IPN_LEAF) {
+
+ /* Yes, search is over */
+ leaf = (IPLeaf_t *)ipn;
+ ipn = NULL;
+ break;
+ }
+ }
+ }
+ else {
+
+ /* Yes, loop terminated on a leaf node */
+ assert(ipn->ipn_type == IPN_LEAF);
+ leaf = (IPLeaf_t *)ipn;
+ }
+
+ /* Got a leaf yet? */
+ if (leaf != NULL) {
+
+ /* Combine the IP address and netmask differences */
+ bitmask = (leaf->ipl_ipaddr ^ ipaddr) | (leaf->ipl_netmask ^ netmask);
+
+ /* Are both the IP address and the netmask the same? */
+ if (bitmask == 0) {
+
+ /* Yes, duplicate entry */
+ return 0;
+ }
+
+ /* Find the bit number of the first different bit */
+ for (lastbit = 31;
+ (bitmask & 0x80000000) == 0; --lastbit, bitmask <<= 1) ;
+
+ /* Generate a bit mask with just that bit */
+ bitmask = (IPAddr_t) (1 << lastbit);
+
+ /*
+ * Go up the tree from lastipn, looking for an internal node
+ * that tests lastbit. Stop if we get to a node that tests
+ * a higher bit number first.
+ */
+ for (ipn = lastipn, lastipn = (IPNode_t *)leaf;
+ ipn != NULL; ipn = ipn->ipn_parent) {
+
+ if (ipn->ipn_bit >= lastbit) {
+ if (ipn->ipn_bit == lastbit) {
+ /* Need to add a leaf off ipn node */
+ lastipn = NULL;
+ }
+ break;
+ }
+ lastipn = ipn;
+ }
+
+ assert(ipn != NULL);
+ }
+ else {
+
+ /* Just hang a leaf off the lastipn node if no leaf */
+ ipn = lastipn;
+ lastipn = NULL;
+ lastbit = ipn->ipn_bit;
+ }
+
+ /*
+ * If lastipn is not NULL at this point, the new leaf will hang
+ * off an internal node inserted between the upper node, referenced
+ * by ipn, and the lower node, referenced by lastipn. The lower
+ * node may be an internal node or a leaf.
+ */
+ if (lastipn != NULL) {
+ IPNode_t * parent = ipn; /* parent of the new node */
+
+ assert((lastipn->ipn_type == IPN_LEAF) ||
+ (ipn == lastipn->ipn_parent));
+
+ /* Allocate space for the internal node */
+ ipn = (IPNode_t *)MALLOC(sizeof(IPNode_t));
+ if (ipn == NULL) goto err_nomem;
+
+ ipn->ipn_type = IPN_NODE;
+ ipn->ipn_bit = lastbit;
+ ipn->ipn_parent = parent;
+ ipn->ipn_clear = NULL;
+ ipn->ipn_set = NULL;
+ ipn->ipn_masked = NULL;
+
+ bitmask = (IPAddr_t) (1 << lastbit);
+
+ /*
+ * The values in the leaf we found above determine which
+ * descendant link of the new internal node will reference
+ * the subtree that we just ascended.
+ */
+ if (leaf->ipl_netmask & bitmask) {
+ if (leaf->ipl_ipaddr & bitmask) {
+ ipn->ipn_set = lastipn;
+ }
+ else {
+ ipn->ipn_clear = lastipn;
+ }
+ }
+ else {
+ ipn->ipn_masked = lastipn;
+ }
+
+ /* Allocate space for the new leaf */
+ leaf = (IPLeaf_t *)MALLOC(sizeof(IPLeaf_t));
+ if (leaf == NULL) {
+ FREE((void *)ipn);
+ goto err_nomem;
+ }
+
+ /* Insert internal node in tree */
+
+ /* First the downward link from the parent to the new node */
+ for (i = 0; i < IPN_NLINKS; ++i) {
+ if (parent->ipn_links[i] == lastipn) {
+ parent->ipn_links[i] = ipn;
+ break;
+ }
+ }
+
+ /* Then the upward link from the child (if it's not a leaf) */
+ if (lastipn->ipn_type == IPN_NODE) {
+ lastipn->ipn_parent = ipn;
+ }
+ }
+ else {
+ /* Allocate space for a leaf node only */
+ leaf = (IPLeaf_t *)MALLOC(sizeof(IPLeaf_t));
+ if (leaf == NULL) goto err_nomem;
+ }
+
+ /* Initialize the new leaf */
+ leaf->ipl_type = IPN_LEAF;
+ leaf->ipl_ipaddr = ipaddr;
+ leaf->ipl_netmask = netmask;
+
+ /*
+ * Select the appropriate descendant link of the internal node
+ * and point it at the new leaf.
+ */
+ bitmask = (IPAddr_t) (1 << ipn->ipn_bit);
+ if (bitmask & netmask) {
+ if (bitmask & ipaddr) {
+ assert(ipn->ipn_set == NULL);
+ ipn->ipn_set = (IPNode_t *)leaf;
+ }
+ else {
+ assert(ipn->ipn_clear == NULL);
+ ipn->ipn_clear = (IPNode_t *)leaf;
+ }
+ }
+ else {
+ assert(ipn->ipn_masked == NULL);
+ ipn->ipn_masked = (IPNode_t *)leaf;
+ }
+
+ *hspp = hsp;
+
+ /* Successful completion */
+ return 0;
+
+ err_nomem:
+ return ACLERRNOMEM;
+}
+
+/*
+ * Description (aclAuthNameAdd)
+ *
+ * This function adds a user or group to a given user list,
+ * in the context of a specified ACL that is being created. The
+ * name of the user or group is provided by the caller, and is
+ * looked up in the authentication database associated with the
+ * specified user list. The return value indicates whether the name
+ * matched a user or group name, and whether the corresponding user
+ * or group id was already present in the given user list.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * usp - pointer to user list specification
+ * rlm - pointer to current authentication realm
+ * name - pointer to user or group name string
+ *
+ * Returns:
+ *
+ * The return value is zero if the name is not found in the
+ * authentication database. If the name is found, the return value
+ * is a positive value containing bit flags:
+ *
+ * AIF_GROUP - name matches a group name
+ * AIF_USER - name matches a user name
+ * AIF_DUP - name was already represented in the
+ * specified user list
+ *
+ * An error is indicated by a negative return code (ACLERRxxxx
+ * - see aclerror.h), and an error frame will be generated if
+ * an error list is provided.
+ */
+
+int aclAuthNameAdd(NSErr_t * errp, UserSpec_t * usp,
+ Realm_t * rlm, char * name)
+{
+ void * guoptr; /* group or user object pointer */
+ int irv; /* insert result value */
+ int eid; /* error id */
+ int rv; /* result value */
+
+ /* There must be a realm specified in order to handle users */
+ if (rlm == 0) goto err_norealm;
+
+ /* Open the authentication database if it's not already */
+ if (rlm->rlm_authdb == 0) {
+
+ if (rlm->rlm_aif == 0) {
+ rlm->rlm_aif = &NSADB_AuthIF;
+ }
+
+ rv = (*rlm->rlm_aif->aif_open)(errp,
+ rlm->rlm_dbname, 0, &rlm->rlm_authdb);
+ if (rv < 0) goto err_open;
+ }
+
+ /* Look up the name in the authentication DB */
+ rv = (*rlm->rlm_aif->aif_findname)(errp, rlm->rlm_authdb, name,
+ (AIF_USER|AIF_GROUP), (void **)&guoptr);
+ if (rv <= 0) {
+ if (rv < 0) goto err_adb;
+
+ /* The name was not found in the database */
+ return 0;
+ }
+
+ /* The name was found. Was it a user name? */
+ if (rv == AIF_USER) {
+
+ /* Yes, add the user id to the user list */
+ irv = usiInsert(&usp->us_user.uu_user, ((UserObj_t *)guoptr)->uo_uid);
+ rv = ANA_USER;
+ }
+ else {
+
+ /* No, must be a group name. Add group id to an_groups list. */
+ irv = usiInsert(&usp->us_user.uu_group,
+ ((GroupObj_t *)guoptr)->go_gid);
+ rv = ANA_GROUP;
+ }
+
+ /* Examine the result of the insert operation */
+ if (irv <= 0) {
+ if (irv < 0) goto err_ins;
+
+ /* Id was already in the list */
+ rv |= ANA_DUP;
+ }
+
+ punt:
+ return rv;
+
+ err_norealm:
+ eid = ACLERR3400;
+ rv = ACLERRNORLM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 1, name);
+ goto punt;
+
+ err_open:
+ eid = ACLERR3420;
+ rv = ACLERROPEN;
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 2, rlm->rlm_dbname, system_errmsg());
+ goto punt;
+
+ err_adb:
+ /* Error accessing authentication database. */
+ eid = ACLERR3440;
+ rv = ACLERRADB;
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, rlm->rlm_dbname, name);
+ goto punt;
+
+ err_ins:
+ /* Error on insert operation. Must be lack of memory. */
+ eid = ACLERR3460;
+ rv = ACLERRNOMEM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto punt;
+}
+
+/*
+ * Description (aclClientsDirCreate)
+ *
+ * This function allocates and initializes a new ACClients_t
+ * ACL directive.
+ *
+ * Arguments:
+ *
+ * None.
+ *
+ * Returns:
+ *
+ * If successful, a pointer to the new ACClients_t is returned.
+ * A shortage of dynamic memory is indicated by a null return value.
+ */
+
+ACClients_t * aclClientsDirCreate()
+{
+ ACClients_t * acd; /* pointer to new ACClients_t */
+
+ acd = (ACClients_t *)MALLOC(sizeof(ACClients_t));
+ if (acd != 0) {
+ memset((void *)acd, 0, sizeof(ACClients_t));
+ }
+
+ return acd;
+}
+
+/*
+ * Description (aclCreate)
+ *
+ * This function creates a new ACL root structure. The caller
+ * specifies the name to be associated with the ACL. The ACL handle
+ * returned by this function is passed to other functions in this
+ * module when adding information to the ACL.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acc - pointer to an access control context
+ * aclname - pointer to ACL name string
+ * pacl - pointer to returned ACL handle
+ *
+ * Returns:
+ *
+ * The return value is zero if the ACL is created successfully.
+ * Otherwise it is a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int aclCreate(NSErr_t * errp, ACContext_t * acc, char * aclname, ACL_t **pacl)
+{
+ ACL_t * acl; /* pointer to created ACL */
+ int rv; /* result value */
+ int eid; /* error id */
+
+ *pacl = 0;
+
+ /* Allocate the ACL_t structure */
+ acl = (ACL_t *) MALLOC(sizeof(ACL_t));
+ if (acl == 0) goto err_nomem;
+
+ /* Initialize the structure */
+ memset((void *)acl, 0, sizeof(ACL_t));
+ acl->acl_sym.sym_name = STRDUP(aclname);
+ acl->acl_sym.sym_type = ACLSYMACL;
+ acl->acl_acc = acc;
+ acl->acl_refcnt = 1;
+
+ /* Add it to the symbol table for the specified context */
+ rv = symTableAddSym(acc->acc_stp, &acl->acl_sym, (void *)acl);
+ if (rv < 0) goto err_addsym;
+
+ /* Add it to the list of ACLs for the specified context */
+ acl->acl_next = acc->acc_acls;
+ acc->acc_acls = acl;
+ acc->acc_refcnt += 1;
+
+ *pacl = acl;
+ return 0;
+
+ err_nomem:
+ rv = ACLERRNOMEM;
+ eid = ACLERR3200;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto done;
+
+ err_addsym:
+ FREE(acl);
+ rv = ACLERRDUPSYM;
+ eid = ACLERR3220;
+ nserrGenerate(errp, rv, eid, ACL_Program, 1, aclname);
+
+ done:
+ return rv;
+}
+
+/*
+ * Description (aclDestroy)
+ *
+ * This function destroys an ACL structure and its sub-structures.
+ * It does not free the ACContext_t referenced by the ACL.
+ *
+ * Arguments:
+ *
+ * acl - pointer to ACL_t structure
+ */
+
+void aclDestroy(ACL_t * acl)
+{
+ ACL_t **pacl; /* ACL list link pointer */
+ ACDirective_t * acd; /* ACL directive pointer */
+ ACDirective_t * nacd; /* next ACL directive pointer */
+
+ /* Is there an ACContext_t structure? */
+ if (acl->acl_acc != 0) {
+
+ /* Remove this ACL from the list in the ACContext_t structure */
+ for (pacl = &acl->acl_acc->acc_acls;
+ *pacl != 0; pacl = &(*pacl)->acl_next) {
+
+ if (*pacl == acl) {
+ *pacl = acl->acl_next;
+ acl->acl_acc->acc_refcnt -= 1;
+ break;
+ }
+ }
+ }
+
+ /* Destroy each ACL directive */
+ for (acd = acl->acl_dirf; acd != 0; acd = nacd) {
+ nacd = acd->acd_next;
+ aclDirectiveDestroy(acd);
+ }
+
+ /* Free the ACL rights list if it is unnamed */
+ if ((acl->acl_rights != 0) && (acl->acl_rights->rs_sym.sym_name == 0)) {
+ aclRightSpecDestroy(acl->acl_rights);
+ }
+
+ /* Free the ACL name string, if any */
+ if (acl->acl_sym.sym_name != 0) {
+ FREE(acl->acl_sym.sym_name);
+ }
+
+ /* Free the ACL itself */
+ FREE(acl);
+}
+
+/*
+ * Description (aclDelete)
+ *
+ * This function removes a specified ACL from the symbol table
+ * associated with its ACL context, and then destroys the ACL
+ * structure and any unnamed objects it references (other than
+ * the ACL context).
+ *
+ * Arguments:
+ *
+ * acl - pointer to the ACL
+ */
+
+void aclDelete(ACL_t * acl)
+{
+ ACContext_t * acc = acl->acl_acc;
+
+ if ((acc != 0) && (acl->acl_sym.sym_name != 0)) {
+ symTableRemoveSym(acc->acc_stp, &acl->acl_sym);
+ }
+
+ aclDestroy(acl);
+}
+
+/*
+ * Description (aclDirectiveAdd)
+ *
+ * This function adds a given directive to a specified ACL.
+ *
+ * Arguments:
+ *
+ * acl - pointer to the ACL
+ * acd - pointer to the directive to be added
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. An error is indicated
+ * by a negative return value.
+ */
+
+int aclDirectiveAdd(ACL_t * acl, ACDirective_t * acd)
+{
+ /* Add the directive to the end of the ACL's directive list */
+ acd->acd_next = 0;
+
+ if (acl->acl_dirl == 0) {
+ /* First entry in empty list */
+ acl->acl_dirf = acd;
+ }
+ else {
+ /* Append to end of list */
+ acl->acl_dirl->acd_next = acd;
+ }
+
+ acl->acl_dirl = acd;
+
+ return 0;
+}
+
+/*
+ * Description (aclDirectiveCreate)
+ *
+ * This function allocates and initializes a new ACDirective_t
+ * structure, representing an ACL directive.
+ *
+ * Arguments:
+ *
+ * None.
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a new ACDirective_t.
+ * Otherwise the return value is null.
+ */
+
+ACDirective_t * aclDirectiveCreate()
+{
+ ACDirective_t * acd;
+
+ acd = (ACDirective_t *) MALLOC(sizeof(ACDirective_t));
+ if (acd != 0) {
+ memset((void *)acd, 0, sizeof(ACDirective_t));
+ }
+
+ return acd;
+}
+
+/*
+ * Description (aclDirectiveDestroy)
+ *
+ * This function destroys an ACL directive structure.
+ *
+ * Arguments:
+ *
+ * acd - pointer to ACL directive structure
+ */
+
+void aclDirectiveDestroy(ACDirective_t * acd)
+{
+ switch (acd->acd_action) {
+ case ACD_ALLOW:
+ case ACD_DENY:
+ {
+ ACClients_t * acp;
+ ACClients_t * nacp;
+
+ /* Free a list of ACClients_t structures */
+ for (acp = acd->acd_cl; acp != 0; acp = nacp) {
+ nacp = acp->cl_next;
+
+ /* Free the HostSpec_t if it's there and unnamed */
+ if ((acp->cl_host != 0) &&
+ (acp->cl_host->hs_sym.sym_name == 0)) {
+ aclHostSpecDestroy(acp->cl_host);
+ }
+
+ /* Free the UserSpec_t if it's there and unnamed */
+ if ((acp->cl_user != 0) &&
+ (acp->cl_user->us_sym.sym_name == 0)) {
+ aclUserSpecDestroy(acp->cl_user);
+ }
+ }
+ }
+ break;
+
+ case ACD_AUTH:
+ {
+ RealmSpec_t * rsp = acd->acd_auth.au_realm;
+
+ /* Destroy the RealmSpec_t if it's unnamed */
+ if ((rsp != 0) && (rsp->rs_sym.sym_name == 0)) {
+ aclRealmSpecDestroy(rsp);
+ }
+ }
+ break;
+ }
+
+ FREE(acd);
+}
+
+/*
+ * Description (aclDNSSpecDestroy)
+ *
+ * This function destroys an entry in a DNS filter. It is intended
+ * mainly to be used by aclHostSpecDestroy().
+ *
+ * Arguments:
+ *
+ * sym - pointer to Symbol_t for DNS filter entry
+ * argp - unused (must be zero)
+ *
+ * Returns:
+ *
+ * The return value is SYMENUMREMOVE.
+ */
+
+int aclDNSSpecDestroy(Symbol_t * sym, void * argp)
+{
+ if (sym != 0) {
+
+ /* Free the DNS specification string if any */
+ if (sym->sym_name != 0) {
+ FREE(sym->sym_name);
+ }
+
+ /* Free the Symbol_t structure */
+ FREE(sym);
+ }
+
+ /* Indicate that the symbol table entry should be removed */
+ return SYMENUMREMOVE;
+}
+
+/*
+ * Description (aclHostSpecDestroy)
+ *
+ * This function destroys a HostSpec_t structure and its sub-structures.
+ *
+ * Arguments:
+ *
+ * hsp - pointer to HostSpec_t structure
+ */
+
+void aclHostSpecDestroy(HostSpec_t * hsp)
+{
+ if (hsp == 0) return;
+
+ /* Free the IP filter if any */
+ if (hsp->hs_host.inh_ipf.ipf_tree != 0) {
+ IPNode_t * ipn; /* current node pointer */
+ IPNode_t * parent; /* parent node pointer */
+ int i;
+
+ /* Traverse tree, freeing nodes */
+ for (parent = hsp->hs_host.inh_ipf.ipf_tree; parent != NULL; ) {
+
+ /* Look for a link to a child node */
+ for (i = 0; i < IPN_NLINKS; ++i) {
+ ipn = parent->ipn_links[i];
+ if (ipn != NULL) break;
+ }
+
+ /* Any children for the parent node? */
+ if (ipn == NULL) {
+
+ /* Otherwise back up the tree */
+ ipn = parent;
+ parent = ipn->ipn_parent;
+
+ /* Free the lower node */
+ FREE(ipn);
+ continue;
+ }
+
+ /*
+ * Found a child node for the current parent.
+ * NULL out the downward link and check it out.
+ */
+ parent->ipn_links[i] = NULL;
+
+ /* Is it a leaf? */
+ if (ipn->ipn_type == IPN_LEAF) {
+ /* Yes, free it */
+ FREE(ipn);
+ continue;
+ }
+
+ /* No, step down the tree */
+ parent = ipn;
+ }
+ }
+
+ /* Free the DNS filter if any */
+ if (hsp->hs_host.inh_dnf.dnf_hash != 0) {
+
+ /* Destroy each entry in the symbol table */
+ symTableEnumerate(hsp->hs_host.inh_dnf.dnf_hash, 0,
+ aclDNSSpecDestroy);
+
+ /* Destroy the symbol table itself */
+ symTableDestroy(hsp->hs_host.inh_dnf.dnf_hash, 0);
+ }
+
+ /* Free the symbol name if any */
+ if (hsp->hs_sym.sym_name != 0) {
+ FREE(hsp->hs_sym.sym_name);
+ }
+
+ /* Free the HostSpec_t structure */
+ FREE(hsp);
+}
+
+/*
+ * Description (aclRealmSpecDestroy)
+ *
+ * This function destroys a RealmSpec_t structure.
+ *
+ * Arguments:
+ *
+ * rsp - pointer to RealmSpec_t structure
+ */
+
+void aclRealmSpecDestroy(RealmSpec_t * rsp)
+{
+ /* Close the realm authentication database if it appears open */
+ if ((rsp->rs_realm.rlm_aif != 0) &&
+ (rsp->rs_realm.rlm_authdb != 0)) {
+ (*rsp->rs_realm.rlm_aif->aif_close)(rsp->rs_realm.rlm_authdb, 0);
+ }
+
+ /* Free the prompt string if any */
+ if (rsp->rs_realm.rlm_prompt != 0) {
+ FREE(rsp->rs_realm.rlm_prompt);
+ }
+
+ /* Free the database filename string if any */
+ if (rsp->rs_realm.rlm_dbname != 0) {
+ FREE(rsp->rs_realm.rlm_dbname);
+ }
+
+ /* Free the realm specification name if any */
+ if (rsp->rs_sym.sym_name != 0) {
+ FREE(rsp->rs_sym.sym_name);
+ }
+
+ /* Free the RealmSpec_t structure */
+ FREE(rsp);
+}
+
+/*
+ * Description (aclRightDef)
+ *
+ * This function find or creates an access right with a specified
+ * name in a given ACL context. If a new access right definition
+ * is created, it assigns a unique integer identifier to the the
+ * right, adds it to the ACL context symbol table and to the
+ * list of all access rights for the context. Note that access
+ * right names are case-insensitive.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acc - pointer to an access control context
+ * rname - access right name (e.g. "GET")
+ * prd - pointer to returned RightDef_t pointer
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The return value is zero if the access right definition already
+ * existed or one if it was created successfully. Otherwise it is
+ * a negative error code (ACLERRxxxx - see aclerror.h), and an error
+ * frame will be generated if an error list is provided.
+ */
+
+int aclRightDef(NSErr_t * errp,
+ ACContext_t * acc, char * rname, RightDef_t **prd)
+{
+ RightDef_t * rdp; /* pointer to right definition */
+ int eid; /* error id code */
+ int rv; /* result value */
+ static int last_rid = 0; /* last assigned right id */
+
+ /* See if there's already a symbol table entry for it */
+ rv = symTableFindSym(acc->acc_stp, rname, ACLSYMRIGHT, (void **)&rdp);
+ if (rv) {
+
+ /* No, create an entry */
+
+ /* Allocate a right definition structure and initialize it */
+ rdp = (RightDef_t *)MALLOC(sizeof(RightDef_t));
+ if (rdp == 0) goto err_nomem;
+
+ rdp->rd_sym.sym_name = STRDUP(rname);
+ rdp->rd_sym.sym_type = ACLSYMRIGHT;
+ rdp->rd_next = acc->acc_rights;
+ rdp->rd_id = ++last_rid;
+
+ /* Add the right name to the symbol table for the ACL context */
+ rv = symTableAddSym(acc->acc_stp, &rdp->rd_sym, (void *)rdp);
+ if (rv) goto err_stadd;
+
+ /* Add the right definition to the list for the ACL context */
+ acc->acc_rights = rdp;
+
+ /* Indicate a new right definition was created */
+ rv = 1;
+ }
+
+ /* Return a pointer to the RightDef_t structure if indicated */
+ if (prd != 0) *prd = rdp;
+
+ return rv;
+
+ err_nomem:
+ eid = ACLERR3600;
+ rv = ACLERRNOMEM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto punt;
+
+ err_stadd:
+ FREE(rdp->rd_sym.sym_name);
+ FREE(rdp);
+ eid = ACLERR3620;
+ rv = ACLERRDUPSYM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 1, rname);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (aclRightSpecDestroy)
+ *
+ * This function destroys a RightSpec_t structure.
+ *
+ * Arguments:
+ *
+ * rsp - pointer to RightSpec_t structure
+ */
+
+void aclRightSpecDestroy(RightSpec_t * rsp)
+{
+ if (rsp != 0) {
+
+ UILFREE(&rsp->rs_list);
+
+ if (rsp->rs_sym.sym_name != 0) {
+ FREE(rsp->rs_sym.sym_name);
+ }
+
+ FREE(rsp);
+ }
+}
+
+/*
+ * Description (aclUserSpecCreate)
+ *
+ * This function allocates and initializes a new UserSpec_t
+ * structure, representing a list of users and groups.
+ *
+ * Arguments:
+ *
+ * None.
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a new UserSpec_t.
+ * Otherwise the return value is null.
+ */
+
+UserSpec_t * aclUserSpecCreate()
+{
+ UserSpec_t * usp;
+
+ usp = (UserSpec_t *) MALLOC(sizeof(UserSpec_t));
+ if (usp != 0) {
+ memset((void *)usp, 0, sizeof(UserSpec_t));
+ usp->us_sym.sym_type = ACLSYMUSER;
+ }
+
+ return usp;
+}
+
+/*
+ * Description (aclUserSpecDestroy)
+ *
+ * This function destroys a UserSpec_t structure.
+ *
+ * Arguments:
+ *
+ * usp - pointer to UserSpec_t structure
+ */
+
+void aclUserSpecDestroy(UserSpec_t * usp)
+{
+ if (usp != 0) {
+
+ UILFREE(&usp->us_user.uu_user);
+ UILFREE(&usp->us_user.uu_group);
+
+ if (usp->us_sym.sym_name != 0) {
+ FREE(usp->us_sym.sym_name);
+ }
+
+ FREE(usp);
+ }
+}
diff --git a/lib/libaccess/aclcache.cpp b/lib/libaccess/aclcache.cpp
new file mode 100644
index 00000000..34d2ecfb
--- /dev/null
+++ b/lib/libaccess/aclcache.cpp
@@ -0,0 +1,579 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <base/nsassert.h>
+#include <base/crit.h>
+#include <base/ereport.h>
+#include <plhash.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/usrcache.h>
+#include <libaccess/las.h>
+#include <libaccess/ldapacl.h>
+#include "aclutil.h"
+#include "permhash.h"
+#include "aclcache.h"
+
+
+static CRITICAL acl_hash_crit = NULL; /* Controls Global Hash */
+
+enum {
+ ACL_URI_HASH,
+ ACL_URI_GET_HASH
+};
+
+/* ACL_ListHashKeyHash
+ * Given an ACL List address, computes a randomized hash value of the
+ * ACL structure pointer addresses by simply adding them up. Returns
+ * the resultant hash value.
+ */
+static PLHashNumber
+ACL_ListHashKeyHash(const void *Iacllist)
+{
+ PLHashNumber hash=0;
+ ACLWrapper_t *wrap;
+ ACLListHandle_t *acllist=(ACLListHandle_t *)Iacllist;
+
+ for (wrap=acllist->acl_list_head; wrap; wrap=wrap->wrap_next) {
+ hash += (PLHashNumber)(PRSize)wrap->acl;
+ }
+
+ return (hash);
+}
+
+/* ACL_ListHashKeyCompare
+ * Given two acl lists, compares the addresses of the acl pointers within
+ * them to see if theyre identical. Returns 1 if equal, 0 otherwise.
+ */
+static int
+ACL_ListHashKeyCompare(const void *Iacllist1, const void *Iacllist2)
+{
+ ACLWrapper_t *wrap1, *wrap2;
+ ACLListHandle_t *acllist1=(ACLListHandle_t *)Iacllist1;
+ ACLListHandle_t *acllist2=(ACLListHandle_t *)Iacllist2;
+
+ if (acllist1->acl_count != acllist2->acl_count)
+ return 0;
+
+ wrap1 = acllist1->acl_list_head;
+ wrap2 = acllist2->acl_list_head;
+
+ while ((wrap1 != NULL) && (wrap2 != NULL)) {
+ if (wrap1->acl != wrap2->acl)
+ return 0;
+ wrap1 = wrap1->wrap_next;
+ wrap2 = wrap2->wrap_next;
+ }
+
+ if ((wrap1 != NULL) || (wrap2 != NULL))
+ return 0;
+ else
+ return 1;
+}
+
+/* ACL_ListHashValueCompare
+ * Returns 1 if equal, 0 otherwise
+ */
+static int
+ACL_ListHashValueCompare(const void *acllist1, const void *acllist2)
+{
+
+ return (acllist1 == acllist2);
+}
+
+void
+ACL_ListHashInit()
+{
+ ACLListHash = PR_NewHashTable(200,
+ ACL_ListHashKeyHash,
+ ACL_ListHashKeyCompare,
+ ACL_ListHashValueCompare,
+ &ACLPermAllocOps,
+ NULL);
+ if (ACLListHash == NULL) {
+ ereport(LOG_SECURITY, "Unable to allocate ACL List Hash\n");
+ return;
+ }
+
+ return;
+}
+
+static void
+ACL_ListHashDestroy()
+{
+ if (ACLListHash) {
+ PR_HashTableDestroy(ACLListHash);
+ ACLListHash = NULL;
+ }
+
+ return;
+}
+
+/* ACL_ListHashUpdate
+ * Typically called with the &rq->acllist. Checks if the newly generated
+ * acllist matches one that's already been created. If so, toss the new
+ * list and set the pointer to the old list in its place.
+ */
+void
+ACL_ListHashUpdate(ACLListHandle_t **acllistp)
+{
+ NSErr_t *errp = 0;
+ ACLListHandle_t *tmp_acllist;
+
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+
+ tmp_acllist = (ACLListHandle_t *)PR_HashTableLookup(ACLListHash, *acllistp);
+ if (tmp_acllist && tmp_acllist != *acllistp) {
+ NS_ASSERT(*acllistp && *acllistp != ACL_LIST_NO_ACLS);
+ ACL_ListDestroy(errp, *acllistp);
+ *acllistp = tmp_acllist;
+ NS_ASSERT(ACL_CritHeld());
+ tmp_acllist->ref_count++; /* we're gonna use it */
+ } else { /* Wasn't in the list */
+ PR_HashTableAdd(ACLListHash, *acllistp, *acllistp);
+ }
+
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+}
+
+/* ACL_ListCacheEnter
+ * In some cases, the URI cache is useless. E.g. when virtual servers are used.
+ * When that happens, the List Cache is still useful, because the cached ACL
+ * List has the Eval cache in it, plus any LAS caches.
+ */
+NSAPI_PUBLIC void
+ACL_ListHashEnter(ACLListHandle_t **acllistp)
+{
+ NSErr_t *errp = 0;
+
+ ACL_CritEnter();
+
+ /* Look for a matching ACL List and use it if we find one. */
+ if (*acllistp) {
+ NS_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ ACL_ListHashUpdate(acllistp);
+ } else {
+ *acllistp = ACL_LIST_NO_ACLS;
+ }
+
+ ACL_CritExit();
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+}
+
+/* ACL_ListHashCheck
+ * When Virtual Servers are active, and the ACL URI cache is inactive, someone
+ * with an old ACL List pointer can check to see if it's still valid. This will
+ * also increment the reference count on it.
+ */
+NSAPI_PUBLIC int
+ACL_ListHashCheck(ACLListHandle_t **acllistp)
+{
+ ACLListHandle_t *tmp_acllist;
+
+ if (*acllistp == ACL_LIST_NO_ACLS) return 1;
+
+ ACL_CritEnter();
+
+ tmp_acllist = (ACLListHandle_t *)PR_HashTableLookup(ACLListHash, *acllistp);
+ if (tmp_acllist) {
+ NS_ASSERT(*acllistp && *acllistp != ACL_LIST_NO_ACLS);
+ *acllistp = tmp_acllist;
+ NS_ASSERT(ACL_CritHeld());
+ tmp_acllist->ref_count++; /* we're gonna use it */
+ ACL_CritExit();
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return 1; /* Normal path */
+ } else { /* Wasn't in the list */
+ ACL_CritExit();
+ return 0;
+ }
+
+}
+
+
+void
+ACL_UriHashDestroy(void)
+{
+ if (acl_uri_hash) {
+ PR_HashTableDestroy(acl_uri_hash);
+ acl_uri_hash = NULL;
+ }
+ if (acl_uri_get_hash) {
+ PR_HashTableDestroy(acl_uri_get_hash);
+ acl_uri_get_hash = NULL;
+ }
+ pool_destroy((void **)acl_uri_hash_pool);
+ acl_uri_hash_pool = NULL;
+
+}
+
+void
+ACL_Destroy(void)
+{
+ ACL_ListHashDestroy();
+ ACL_UriHashDestroy();
+ ACL_LasHashDestroy();
+}
+
+/* Only used in ASSERT statements to verify that we have the lock */
+int
+ACL_CritHeld(void)
+{
+ return (crit_owner_is_me(acl_hash_crit));
+}
+
+NSAPI_PUBLIC void
+ACL_CritEnter(void)
+{
+ crit_enter(acl_hash_crit);
+}
+
+NSAPI_PUBLIC void
+ACL_CritExit(void)
+{
+ crit_exit(acl_hash_crit);
+}
+
+void
+ACL_CritInit(void)
+{
+ acl_hash_crit = crit_init();
+}
+
+void
+ACL_UriHashInit(void)
+{
+ acl_uri_hash = PR_NewHashTable(200,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ acl_uri_get_hash = PR_NewHashTable(200,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ acl_uri_hash_pool = pool_create();
+}
+
+/* ACL_CacheCheck
+ * INPUT
+ * uri A URI string pointer
+ * acllistp A pointer to an acllist placeholder. E.g. &rq->acllist
+ * OUTPUT
+ * return 1 if cached. 0 if not. The reference count on the ACL List
+ * is INCREMENTED, and will be decremented when ACL_EvalDestroy or
+ * ACL_ListDecrement is
+ * called.
+ */
+int
+ACL_INTCacheCheck(int which, char *uri, ACLListHandle_t **acllistp)
+{
+ PLHashTable *hash;
+ NS_ASSERT(uri && acl_uri_hash && acl_uri_get_hash);
+
+ /* ACL cache: If the ACL List is already in the cache, there's no need
+ * to go through the pathcheck directives.
+ * NULL means that the URI hasn't been accessed before.
+ * ACL_LIST_NO_ACLS
+ * means that the URI has no ACLs.
+ * Anything else is a pointer to the acllist.
+ */
+ ACL_CritEnter();
+
+ /* Get the pointer to the hash table after acquiring the lock */
+ if (which == ACL_URI_HASH)
+ hash = acl_uri_hash;
+ else
+ hash = acl_uri_get_hash;
+
+ *acllistp = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
+ if (*acllistp != NULL) {
+ if (*acllistp != ACL_LIST_NO_ACLS) {
+ NS_ASSERT((*acllistp)->ref_count >= 0);
+ NS_ASSERT(ACL_CritHeld());
+ (*acllistp)->ref_count++;
+ }
+ ACL_CritExit();
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return 1; /* Normal path */
+ }
+
+ ACL_CritExit();
+ return 0;
+}
+
+int
+ACL_CacheCheckGet(char *uri, ACLListHandle_t **acllistp)
+{
+ return (ACL_INTCacheCheck(ACL_URI_GET_HASH, uri, acllistp));
+}
+
+int
+ACL_CacheCheck(char *uri, ACLListHandle_t **acllistp)
+{
+ return (ACL_INTCacheCheck(ACL_URI_HASH, uri, acllistp));
+}
+
+
+/* ACL_CacheEnter
+ * INPUT
+ * acllist or 0 if there were no ACLs that applied.
+ * OUTPUT
+ * The acllist address may be changed if it matches an existing one.
+ */
+static void
+ACL_INTCacheEnter(int which, char *uri, ACLListHandle_t **acllistp)
+{
+ ACLListHandle_t *tmpacllist;
+ NSErr_t *errp = 0;
+ PLHashTable *hash;
+
+ NS_ASSERT(uri);
+
+ ACL_CritEnter();
+
+ /* Get the pointer to the hash table after acquiring the lock */
+ if (which == ACL_URI_HASH)
+ hash = acl_uri_hash;
+ else
+ hash = acl_uri_get_hash;
+
+ /* Check again (now that we're in the critical section) to see if
+ * someone else created an ACL List for this URI. If so, discard the
+ * list that we made and replace it with the one just found.
+ */
+ tmpacllist = (ACLListHandle_t *)PR_HashTableLookup(hash, uri);
+ if (tmpacllist != NULL) {
+ if (tmpacllist != ACL_LIST_NO_ACLS) {
+ NS_ASSERT(ACL_CritHeld());
+ tmpacllist->ref_count++; /* we're going to use it */
+ }
+ ACL_CritExit();
+ if (*acllistp && *acllistp != ACL_LIST_NO_ACLS) {
+ ACL_ListDestroy(errp, *acllistp);
+ }
+ *acllistp = tmpacllist;
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+ }
+
+ /* Didn't find another list, so put ours in. */
+ /* Look for a matching ACL List and use it if we find one. */
+ if (*acllistp) {
+ NS_ASSERT(*acllistp != ACL_LIST_NO_ACLS);
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ ACL_ListHashUpdate(acllistp);
+ } else {
+ *acllistp = ACL_LIST_NO_ACLS;
+ }
+ PR_HashTableAdd(hash, pool_strdup((void **)acl_uri_hash_pool, uri), (void *)*acllistp);
+
+ ACL_CritExit();
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+}
+
+void
+ACL_CacheEnter(char *uri, ACLListHandle_t **acllistp)
+{
+ ACL_INTCacheEnter(ACL_URI_HASH, uri, acllistp);
+ return;
+}
+
+void
+ACL_CacheEnterGet(char *uri, ACLListHandle_t **acllistp)
+{
+ ACL_INTCacheEnter(ACL_URI_GET_HASH, uri, acllistp);
+ return;
+}
+
+/* ACL_AddAclName
+ * Adds the ACLs for just the terminal object specified in a pathname.
+ * INPUT
+ * path The filesystem pathname of the terminal object.
+ * acllistp The address of the list of ACLs found thus far.
+ * Could be NULL. If so, a new acllist will be allocated (if any
+ * acls are found). Otherwise the existing list will be added to.
+ * masterlist Usually acl_root_30.
+ */
+void
+ACL_AddAclName(char *path, ACLListHandle_t **acllistp, ACLListHandle_t
+*masterlist)
+{
+ ACLHandle_t *acl;
+ NSErr_t *errp = 0;
+
+#ifdef XP_WIN32
+ acl = ACL_ListFind(errp, masterlist, path, ACL_CASE_INSENSITIVE);
+#else
+ acl = ACL_ListFind(errp, masterlist, path, ACL_CASE_SENSITIVE);
+#endif
+ if (!acl)
+ return;
+
+ NS_ASSERT(ACL_AssertAcl(acl));
+
+ if (!*acllistp)
+ *acllistp = ACL_ListNew(errp);
+ ACL_ListAppend(NULL, *acllistp, acl, 0);
+
+ NS_ASSERT(ACL_AssertAcllist(*acllistp));
+ return;
+}
+
+
+/* ACL_GetPathAcls
+ * Adds the ACLs for all directories plus the terminal object along a given
+ * filesystem pathname. For each pathname component, look for the name, the
+ * name + "/", and the name + "/*". The last one is because the resource
+ * picker likes to postpend "/*" for directories.
+ * INPUT
+ * path The filesystem pathname of the terminal object.
+ * acllistp The address of the list of ACLs found thus far.
+ * Could be NULL. If so, a new acllist will be allocated (if any
+ * acls are found). Otherwise the existing list will be added to.
+ * prefix A string to be prepended to the path component when looking
+ * for a matching ACL tag.
+ */
+void
+ACL_GetPathAcls(char *path, ACLListHandle_t **acllistp, char *prefix,
+ACLListHandle_t *masterlist)
+{
+ char *slashp=path;
+ int slashidx;
+ char ppath[ACL_PATH_MAX];
+ int prefixlen;
+ char *dst;
+
+ NS_ASSERT(path);
+ NS_ASSERT(prefix);
+
+ dst = strncpy(ppath, prefix, ACL_PATH_MAX);
+ if (dst >= (ppath+ACL_PATH_MAX-1)) {
+ ereport(LOG_SECURITY, "Abort - the path is too long for ACL_GetPathAcls to handle\n");
+ abort();
+ }
+ prefixlen = strlen(ppath);
+
+ /* Handle the first "/". i.e. the root directory */
+ if (*path == '/') {
+ ppath[prefixlen]='/';
+ ppath[prefixlen+1]='\0';
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ strcat(ppath, "*");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ slashp = path;
+ }
+
+ do {
+ slashp = strchr(++slashp, '/');
+ if (slashp) {
+ slashidx = slashp - path;
+ strncpy(&ppath[prefixlen], path, slashidx);
+ ppath[slashidx+prefixlen] = '\0';
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ /* Must also handle "/a/b/" in addition to "/a/b" */
+ strcat(ppath, "/");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ strcat(ppath, "*");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ continue;
+ }
+ strcpy(&ppath[prefixlen], path);
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ strcat(ppath, "/");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ strcat(ppath, "*");
+ ACL_AddAclName(ppath, acllistp, masterlist);
+ break;
+ } while (slashp);
+
+}
+
+
+static int get_is_owner_default (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ /* Make sure we don't generate error "all getters declined" message from
+ * ACL_GetAttribute.
+ */
+ PListInitProp(subject, ACL_ATTR_IS_OWNER_INDEX, ACL_ATTR_IS_OWNER,
+ "true", 0);
+
+ return LAS_EVAL_TRUE;
+}
+
+
+NSAPI_PUBLIC int
+ACL_Init(void)
+{
+ ACL_InitAttr2Index();
+ ACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
+ oldACLGlobal = (ACLGlobal_p)PERM_CALLOC(sizeof(ACLGlobal_s));
+ NS_ASSERT(ACLGlobal && oldACLGlobal);
+ ACL_DATABASE_POOL = pool_create();
+ ACL_METHOD_POOL = pool_create();
+ ACL_CritInit();
+ ACL_UriHashInit();
+ ACL_ListHashInit();
+ ACL_LasHashInit();
+ ACL_Init2();
+ init_ldb_rwlock();
+ ACL_RegisterInit();
+
+ return 0;
+}
+
+/* This one gets called at startup AND at cache flush time. */
+void
+ACL_Init2(void)
+{
+
+ /* Register the ACL functions */
+ ACL_LasRegister(NULL, "timeofday", LASTimeOfDayEval, LASTimeOfDayFlush);
+ ACL_LasRegister(NULL, "dayofweek", LASDayOfWeekEval, LASDayOfWeekFlush);
+ ACL_LasRegister(NULL, "ip", LASIpEval, LASIpFlush);
+ ACL_LasRegister(NULL, "dns", LASDnsEval, LASDnsFlush);
+ ACL_LasRegister(NULL, "dnsalias", LASDnsEval, LASDnsFlush);
+ ACL_LasRegister(NULL, "group", LASGroupEval, (LASFlushFunc_t)NULL);
+ ACL_LasRegister(NULL, "user", LASUserEval, (LASFlushFunc_t)NULL);
+#ifdef MCC_ADMSERV
+ ACL_LasRegister(NULL, "program", LASProgramEval, (LASFlushFunc_t)NULL);
+#endif
+
+ ACL_AttrGetterRegister(NULL, ACL_ATTR_USERDN,
+ get_userdn_ldap,
+ ACL_METHOD_ANY, ACL_DBTYPE_ANY,
+ ACL_AT_END, NULL);
+ return;
+}
+
+NSAPI_PUBLIC int
+ACL_InitPostMagnus(void)
+{
+ int rv;
+
+ rv = ACL_AttrGetterRegister(NULL, ACL_ATTR_IS_OWNER,
+ get_is_owner_default,
+ ACL_METHOD_ANY, ACL_DBTYPE_ANY,
+ ACL_AT_END, NULL);
+ return rv;
+}
+
+NSAPI_PUBLIC int
+ACL_LateInitPostMagnus(void)
+{
+ return acl_usr_cache_init();
+}
diff --git a/lib/libaccess/aclcache.h b/lib/libaccess/aclcache.h
new file mode 100644
index 00000000..1f375bcf
--- /dev/null
+++ b/lib/libaccess/aclcache.h
@@ -0,0 +1,27 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef CACHE_H
+#define CACHE_H
+
+NSPR_BEGIN_EXTERN_C
+
+extern void ACL_ListHashInit(void);
+extern void ACL_ListHashUpdate(ACLListHandle_t **acllistp);
+extern void ACL_Destroy(void);
+extern int ACL_CritHeld(void);
+extern void ACL_CritInit(void);
+extern void ACL_UriHashInit(void);
+extern void ACL_UriHashDestroy(void);
+extern int ACL_CacheCheck(char *uri, ACLListHandle_t **acllist_p);
+extern void ACL_CacheEnter(char *uri, ACLListHandle_t **acllist_p);
+extern void ACL_CacheAbort(ACLListHandle_t **acllist_p);
+extern void ACL_Init2(void);
+extern int ACL_RegisterInit ();
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/aclerror.cpp b/lib/libaccess/aclerror.cpp
new file mode 100644
index 00000000..2cbf2874
--- /dev/null
+++ b/lib/libaccess/aclerror.cpp
@@ -0,0 +1,246 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (aclerror.c)
+ *
+ * This module provides error-handling facilities for ACL-related
+ * errors.
+ */
+
+#include "base/systems.h"
+#ifdef NSPR20
+#include "prprf.h"
+#else
+#include "nspr/prprf.h"
+#endif
+#include <base/nsassert.h>
+#include "libaccess/nserror.h"
+#include "libaccess/nsautherr.h"
+#include "libaccess/aclerror.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+#define aclerrnomem XP_GetAdminStr(DBT_AclerrfmtAclerrnomem)
+#define aclerropen XP_GetAdminStr(DBT_AclerrfmtAclerropen)
+#define aclerrdupsym1 XP_GetAdminStr(DBT_AclerrfmtAclerrdupsym1)
+#define aclerrdupsym3 XP_GetAdminStr(DBT_AclerrfmtAclerrdupsym3)
+#define aclerrsyntax XP_GetAdminStr(DBT_AclerrfmtAclerrsyntax)
+#define aclerrundef XP_GetAdminStr(DBT_AclerrfmtAclerrundef)
+#define aclaclundef XP_GetAdminStr(DBT_AclerrfmtAclaclundef)
+#define aclerradb XP_GetAdminStr(DBT_AclerrfmtAclerradb)
+#define aclerrparse1 XP_GetAdminStr(DBT_AclerrfmtAclerrparse1)
+#define aclerrparse2 XP_GetAdminStr(DBT_AclerrfmtAclerrparse2)
+#define aclerrparse3 XP_GetAdminStr(DBT_AclerrfmtAclerrparse3)
+#define aclerrnorlm XP_GetAdminStr(DBT_AclerrfmtAclerrnorlm)
+#define unknownerr XP_GetAdminStr(DBT_AclerrfmtUnknownerr)
+#define aclerrinternal XP_GetAdminStr(DBT_AclerrfmtAclerrinternal)
+#define aclerrinval XP_GetAdminStr(DBT_AclerrfmtAclerrinval)
+#define aclerrfail XP_GetAdminStr(DBT_AclerrfmtAclerrfail)
+#define aclerrio XP_GetAdminStr(DBT_AclerrfmtAclerrio)
+
+/*
+ * Description (aclErrorFmt)
+ *
+ * This function formats an ACL error message into a buffer provided
+ * by the caller. The ACL error information is passed in an error
+ * list structure. The caller can indicate how many error frames
+ * should be processed. A newline is inserted between messages for
+ * different error frames. The error frames on the error list are
+ * all freed, regardless of the maximum depth for traceback.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer
+ * msgbuf - pointer to error message buffer
+ * maxlen - maximum length of generated message
+ * maxdepth - maximum depth for traceback
+ */
+
+void aclErrorFmt(NSErr_t * errp, char * msgbuf, int maxlen, int maxdepth)
+{
+ NSEFrame_t * efp; /* error frame pointer */
+ int len; /* length of error message text */
+ int depth = 0; /* current depth */
+
+ msgbuf[0] = 0;
+
+ while ((efp = errp->err_first) != 0) {
+
+ /* Stop if the message buffer is full */
+ if (maxlen <= 0) break;
+
+ if (depth > 0) {
+ /* Put a newline & tab between error frame messages */
+ *msgbuf++ = '\n';
+ if (--maxlen <= 0) break;
+ *msgbuf++ = '\t';
+ if (--maxlen <= 0) break;
+ }
+
+ if (!strcmp(efp->ef_program, ACL_Program)) {
+
+ /* Identify the facility generating the error and the id number */
+ len = PR_snprintf(msgbuf, maxlen,
+ "[%s%d] ", efp->ef_program, efp->ef_errorid);
+ msgbuf += len;
+ maxlen -= len;
+
+ if (maxlen <= 0) break;
+
+ len = 0;
+
+ switch (efp->ef_retcode) {
+
+ case ACLERRFAIL:
+ case ACLERRNOMEM:
+ case ACLERRINTERNAL:
+ case ACLERRINVAL:
+ switch (efp->ef_errc) {
+ case 3:
+ PR_snprintf(msgbuf, maxlen, efp->ef_errv[0], efp->ef_errv[1], efp->ef_errv[2]);
+ break;
+ case 2:
+ PR_snprintf(msgbuf, maxlen, efp->ef_errv[0], efp->ef_errv[1]);
+ break;
+ case 1:
+ strncpy(msgbuf, efp->ef_errv[0], maxlen);
+ break;
+ default:
+ NS_ASSERT(0); /* don't break -- continue into case 0 */
+ case 0:
+ switch (efp->ef_retcode) {
+ case ACLERRFAIL:
+ strncpy(msgbuf, XP_GetAdminStr(DBT_AclerrfmtAclerrfail), maxlen);
+ break;
+ case ACLERRNOMEM:
+ strncpy(msgbuf, aclerrnomem, maxlen);
+ break;
+ case ACLERRINTERNAL:
+ strncpy(msgbuf, aclerrinternal, maxlen);
+ break;
+ case ACLERRINVAL:
+ strncpy(msgbuf, aclerrinval, maxlen);
+ break;
+ }
+ break;
+ }
+ msgbuf[maxlen-1] = '\0';
+ len = strlen(msgbuf);
+ break;
+
+ case ACLERROPEN:
+ /* File open error: filename, system_errmsg */
+ if (efp->ef_errc == 2) {
+ len = PR_snprintf(msgbuf, maxlen, aclerropen,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ case ACLERRDUPSYM:
+ /* Duplicate symbol */
+ if (efp->ef_errc == 1) {
+ /* Duplicate symbol: filename, line#, symbol */
+ len = PR_snprintf(msgbuf, maxlen, aclerrdupsym1,
+ efp->ef_errv[0]);
+ }
+ else if (efp->ef_errc == 3) {
+ /* Duplicate symbol: symbol */
+ len = PR_snprintf(msgbuf, maxlen, aclerrdupsym3,
+ efp->ef_errv[0], efp->ef_errv[1],
+ efp->ef_errv[2]);
+ }
+ break;
+
+ case ACLERRSYNTAX:
+ if (efp->ef_errc == 2) {
+ /* Syntax error: filename, line# */
+ len = PR_snprintf(msgbuf, maxlen, aclerrsyntax,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ case ACLERRUNDEF:
+ if (efp->ef_errorid == ACLERR3800) {
+ /* Undefined symbol: acl, method/database name */
+ len = PR_snprintf(msgbuf, maxlen, aclaclundef,
+ efp->ef_errv[0], efp->ef_errv[1],
+ efp->ef_errv[2]);
+ }
+ else if (efp->ef_errc == 3) {
+ /* Undefined symbol: filename, line#, symbol */
+ len = PR_snprintf(msgbuf, maxlen, aclerrundef,
+ efp->ef_errv[0], efp->ef_errv[1],
+ efp->ef_errv[2]);
+ }
+ break;
+
+ case ACLERRADB:
+ if (efp->ef_errc == 2) {
+ /* Authentication database error: DB name, symbol */
+ len = PR_snprintf(msgbuf, maxlen, aclerradb,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ case ACLERRPARSE:
+ if (efp->ef_errc == 2) {
+ /* Parse error: filename, line# */
+ len = PR_snprintf(msgbuf, maxlen, aclerrparse2,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ else if (efp->ef_errc == 3) {
+ /* Parse error: filename, line#, token */
+ len = PR_snprintf(msgbuf, maxlen, aclerrparse3,
+ efp->ef_errv[0], efp->ef_errv[1],
+ efp->ef_errv[2]);
+ }
+ else if (efp->ef_errc == 1) {
+ /* Parse error: line or pointer */
+ len = PR_snprintf(msgbuf, maxlen, aclerrparse1,
+ efp->ef_errv[0]);
+ }
+ break;
+
+ case ACLERRNORLM:
+ if (efp->ef_errc == 1) {
+ /* No realm: name */
+ len = PR_snprintf(msgbuf, maxlen, aclerrnorlm,
+ efp->ef_errv[0]);
+ }
+ break;
+
+ case ACLERRIO:
+ if (efp->ef_errc == 2) {
+ len = PR_snprintf(msgbuf, maxlen, aclerrio,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ default:
+ len = PR_snprintf(msgbuf, maxlen, unknownerr, efp->ef_retcode);
+ break;
+ }
+ }
+ else if (!strcmp(efp->ef_program, NSAuth_Program)) {
+ nsadbErrorFmt(errp, msgbuf, maxlen, maxdepth - depth);
+ }
+ else {
+ len = PR_snprintf(msgbuf, maxlen, unknownerr, efp->ef_retcode);
+ }
+
+ msgbuf += len;
+ maxlen -= len;
+
+ /* Free this frame */
+ nserrFFree(errp, efp);
+
+ if (++depth >= maxdepth) break;
+ }
+
+ /* Free any remaining error frames */
+ nserrDispose(errp);
+}
diff --git a/lib/libaccess/acleval.cpp b/lib/libaccess/acleval.cpp
new file mode 100644
index 00000000..a2be1f7b
--- /dev/null
+++ b/lib/libaccess/acleval.cpp
@@ -0,0 +1,556 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (acleval.c)
+ *
+ * This module provides functions for evaluating Access Control List
+ * (ACL) structures in memory.
+ *
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "libaccess/symbols.h"
+#include "libaccess/aclerror.h"
+#include "libaccess/acleval.h"
+#include <assert.h>
+
+/*
+ * Description (RLMEQUIV)
+ *
+ * Macro for realm comparison. Both realm pointers must be non-null.
+ * The realms are equivalent if the pointers are equal, or if the
+ * authentication methods and database names are the same. The
+ * prompt string is not considered.
+ */
+#define RLMEQUIV(rlm1, rlm2) (((rlm1) != 0) && ((rlm2) != 0) && \
+ (((rlm1) == (rlm2)) || \
+ (((rlm1)->rlm_ameth == (rlm2)->rlm_ameth) && \
+ ((rlm1)->rlm_dbname != 0) && \
+ ((rlm2)->rlm_dbname != 0) && \
+ !strcmp((rlm1)->rlm_dbname, \
+ (rlm2)->rlm_dbname))))
+
+int aclDNSLookup(DNSFilter_t * dnf, char * dnsspec, int fqdn, char **match)
+{
+ char * subdns; /* suffix of client DNS name */
+ void * table; /* hash table pointer */
+ Symbol_t * sym; /* DNS spec symbol pointer */
+ int rv; /* result value */
+
+ fqdn = (fqdn) ? 1 : 0;
+
+ if (match) *match = 0;
+
+ /* Handle null or empty filter */
+ if ((dnf == 0) || (dnf->dnf_hash == 0)) {
+
+ return ACL_NOMATCH;
+ }
+
+ /* Got the client's DNS name? */
+ if (!dnsspec || !*dnsspec) {
+ /* No, use special one */
+ dnsspec = "unknown";
+ }
+
+ /* Get hash table pointer */
+ table = dnf->dnf_hash;
+
+ /*
+ * Look up each possible suffix for the client domain name,
+ * starting with the entire string, and working toward the
+ * last component.
+ */
+
+ subdns = dnsspec;
+
+ while (subdns != 0) {
+
+ /* Look up the domain name suffix in the hash table */
+ rv = symTableFindSym(table, subdns, fqdn, (void **)&sym);
+ if (rv == 0) break;
+
+ /* Step to the next level */
+ if (subdns[0] == '.') subdns += 1;
+ subdns = strchr(subdns, '.');
+
+ /* If it was fully qualified, now it's not */
+ fqdn = 0;
+ }
+
+ /* One more possibility if nothing found yet... */
+ if (rv) {
+ rv = symTableFindSym(table, "*", 0, (void **)&sym);
+ }
+
+ if (rv == 0) {
+ if (match) *match = sym->sym_name;
+ rv = ACL_DNMATCH;
+ }
+ else rv = ACL_NOMATCH;
+
+ return rv;
+}
+
+int aclIPLookup(IPFilter_t * ipf, IPAddr_t ipaddr, void **match)
+{
+ IPLeaf_t * leaf; /* radix tree leaf pointer */
+ IPAddr_t bitmask; /* bit mask for current node */
+ IPNode_t * ipn; /* current internal node */
+ IPNode_t * lastipn; /* last internal node seen in search */
+ IPNode_t * mipn; /* ipn_masked subtree root pointer */
+
+ if (match) *match = 0;
+
+ /* Handle null or empty IP filter */
+ if ((ipf == 0) || (ipf->ipf_tree == 0)) goto fail;
+
+ lastipn = NULL;
+ ipn = ipf->ipf_tree;
+
+ /*
+ * The tree traversal first works down the tree, under the assumption
+ * that all of the bits in the given IP address may be significant.
+ * The internal nodes of the tree will cause particular bits of the
+ * IP address to be tested, and the ipn_clear or ipn_set link to
+ * a descendant followed accordingly. The internal nodes are arranged
+ * in such a way that high-order bits are tested before low-order bits.
+ * Usually some bits are skipped, as they are not needed to distinguish
+ * the entries in the tree.
+ *
+ * At the bottom of the tree, a leaf node may be found, or the last
+ * descendant link may be NULL. If a leaf node is found, it is
+ * tested for a match against the given IP address. If it doesn't
+ * match, or the link was NULL, backtracking begins, as described
+ * below.
+ *
+ * Backtracking follows the ipn_parent links back up the tree from
+ * the last internal node, looking for internal nodes with ipn_masked
+ * descendants. The subtrees attached to these links are traversed
+ * downward, as before, with the same processing at the bottom as
+ * the first downward traversal. Following the ipn_masked links is
+ * essentially examining the possibility that the IP address bit
+ * associated with the internal node may be masked out by the
+ * ipl_netmask in a leaf at the bottom of such a subtree. Since
+ * the ipn_masked links are examined from the bottom of the tree
+ * to the top, this looks at the low-order bits first.
+ */
+
+ while (ipn != NULL) {
+
+ /*
+ * Work down the tree testing bits in the IP address indicated
+ * by the internal nodes. Exit the loop when there are no more
+ * internal nodes.
+ */
+ while ((ipn != NULL) && (ipn->ipn_type == IPN_NODE)) {
+
+ /* Save pointer to internal node */
+ lastipn = ipn;
+
+ /* Get a mask for the bit this node tests */
+ bitmask = (IPAddr_t) 1<<ipn->ipn_bit;
+
+ /* Select link to follow for this IP address */
+ ipn = (bitmask & ipaddr) ? ipn->ipn_set : ipn->ipn_clear;
+ }
+
+ /* Did we end up with a non-NULL node pointer? */
+ if (ipn != NULL) {
+
+ /* It must be a leaf node */
+ assert(ipn->ipn_type == IPN_LEAF);
+ leaf = (IPLeaf_t *)ipn;
+
+ /* Is it a matching leaf? */
+ if (leaf->ipl_ipaddr == (ipaddr & leaf->ipl_netmask)) goto win;
+ }
+
+ /*
+ * Backtrack, starting at lastipn. Search each subtree
+ * emanating from an ipn_masked link. Step up the tree
+ * until the ipn_masked link of the node referenced by
+ * "ipf->ipf_tree" has been considered.
+ */
+
+ for (ipn = lastipn; ipn != NULL; ipn = ipn->ipn_parent) {
+
+ /*
+ * Look for a node with a non-NULL masked link, but don't
+ * go back to the node we just came from.
+ */
+
+ if ((ipn->ipn_masked != NULL) && (ipn->ipn_masked != lastipn)) {
+
+ /* Get the root of this subtree */
+ mipn = ipn->ipn_masked;
+
+ /* If this is an internal node, start downward traversal */
+ if (mipn->ipn_type == IPN_NODE) {
+ ipn = mipn;
+ break;
+ }
+
+ /* Otherwise it's a leaf */
+ assert(mipn->ipn_type == IPN_LEAF);
+ leaf = (IPLeaf_t *)mipn;
+
+ /* Is it a matching leaf? */
+ if (leaf->ipl_ipaddr == (ipaddr & leaf->ipl_netmask)) goto win;
+ }
+
+ /* Don't consider nodes above the given root */
+ if (ipn == ipf->ipf_tree) goto fail;
+
+ lastipn = ipn;
+ }
+ }
+
+ fail:
+ /* No matching entry found */
+ return ACL_NOMATCH;
+
+ win:
+ /* Found a match in leaf */
+ if (match) *match = (void *)leaf;
+
+ return ACL_IPMATCH;
+}
+
+int aclUserLookup(UidUser_t * uup, UserObj_t * uoptr)
+{
+ int gl1cnt; /* elements left in uup->uu_group list */
+ int gl2cnt; /* elements left in uoptr->uo_groups list */
+ USI_t * gl1ptr; /* pointer to next group in uup->uu_group */
+ USI_t * gl2ptr; /* pointer to next group in uoptr->uo_groups */
+
+ /* Try for a direct match on the user id */
+ if (usiPresent(&uup->uu_user, uoptr->uo_uid)) {
+ return ACL_USMATCH;
+ }
+
+ /*
+ * Now we want to see if there are any matches between the
+ * uup->uu_group group id list and the list of groups in the
+ * user object.
+ */
+
+ gl1cnt = UILCOUNT(&uup->uu_group);
+ gl1ptr = UILLIST(&uup->uu_group);
+ gl2cnt = UILCOUNT(&uoptr->uo_groups);
+ gl2ptr = UILLIST(&uoptr->uo_groups);
+
+ while ((gl1cnt > 0) && (gl2cnt > 0)) {
+
+ if (*gl1ptr == *gl2ptr) {
+ return ACL_GRMATCH;
+ }
+
+ if (*gl1ptr < *gl2ptr) {
+ ++gl1ptr;
+ --gl1cnt;
+ }
+ else {
+ ++gl2ptr;
+ --gl2cnt;
+ }
+ }
+
+ return ACL_NOMATCH;
+}
+
+/*
+ * Description (aclEvaluate)
+ *
+ * This function evaluates a given ACL against specified client
+ * information and a particular access right that is needed to
+ * service the client. It can optionally return the ACL directive
+ * number which allows or denies the client's access.
+ *
+ * Arguments:
+ *
+ * acl - pointer to ACL to evaluate
+ * arid - desired access right id value
+ * clauth - pointer to client authentication information
+ * padn - pointer to returned ACL directive number
+ * (may be null)
+ *
+ * Returns:
+ *
+ * A return value of zero indicates that the given ACL does not
+ * control the desired access right, or contains no directives which
+ * match the specified client. A positive return value contains a
+ * value of ACD_ALLOW, ACD_DENY, or ACD_AUTH, and may also have the
+ * ACD_ALWAYS bit flag set. The value indicates whether the client
+ * should be allowed or denied access, or whether authentication is
+ * needed. The ACD_ALWAYS flag indicates if the action should occur
+ * immediately, terminating any further ACL evaluation. An error
+ * is indicated by a negative error code (ACLERRxxxx - see aclerror.h).
+ */
+
+int aclEvaluate(ACL_t * acl, USI_t arid, ClAuth_t * clauth, int * padn)
+{
+ ACDirective_t * acd; /* current ACL directive pointer */
+ RightSpec_t * rsp; /* pointer to rights controlled by ACL */
+ ACClients_t * csp; /* pointer to clients specification */
+ HostSpec_t * hsp; /* pointer to host specification */
+ UserSpec_t * usp; /* pointer to user specification */
+ Realm_t * rlm = 0; /* current authentication realm pointer */
+ Realm_t * authrlm = 0; /* realm to be used for authentication */
+ int ndir; /* ACL directive number */
+ int rv; /* result value */
+ int decision = 0; /* current access control decision */
+ int result = 0; /* function return value */
+ int mdn = 0; /* matching directive number */
+
+ if (padn) *padn = 0;
+
+ /* Does this ACL control the desired access right? */
+
+ rsp = acl->acl_rights;
+ if ((rsp == 0) || !usiPresent(&rsp->rs_list, arid)) {
+
+ /* No, nothing to do */
+ return 0;
+ }
+
+ ndir = 0;
+
+ /* Loop on each ACL directive */
+ for (acd = acl->acl_dirf; acd != 0; acd = acd->acd_next) {
+
+ /* Bump directive number */
+ ++ndir;
+
+ /* Dispatch on directive action code */
+ switch (acd->acd_action) {
+
+ case ACD_ALLOW:
+ case ACD_DENY:
+
+ /* Loop to process list of client specifications */
+ for (csp = acd->acd_cl; csp != 0; csp = csp->cl_next) {
+
+ /* Is there a host list? */
+ hsp = csp->cl_host;
+ if (hsp != 0) {
+
+ /* An empty host list will not match */
+ rv = 0;
+
+ /* Yes, is there an IP address filter? */
+ if (hsp->hs_host.inh_ipf.ipf_tree != 0) {
+
+ /*
+ * Yes, see if the the client's IP address
+ * matches anything in the IP filter.
+ */
+ rv = aclIPLookup(&hsp->hs_host.inh_ipf,
+ clauth->cla_ipaddr, 0);
+ }
+
+ /* If no IP match, is there a DNS filter? */
+ if (!rv && (hsp->hs_host.inh_dnf.dnf_hash != 0)) {
+
+ /* Yes, try for a DNS match */
+ rv = aclDNSLookup(&hsp->hs_host.inh_dnf,
+ clauth->cla_dns, 1, 0);
+ }
+
+ /*
+ * Does the client match the host list? If not, skip
+ * to the next client specification.
+ */
+ if (!rv) continue;
+ }
+
+ /* Is there a user list? */
+ usp = csp->cl_user;
+ if (usp != 0) {
+
+ /* Yes, has the client user been authenticated yet? */
+ if ((clauth->cla_realm != 0) && (clauth->cla_uoptr != 0)) {
+
+ /*
+ * Yes, has the client user been authenticated in the
+ * realm associated with this user list?
+ */
+ if (RLMEQUIV(rlm, clauth->cla_realm)) {
+
+ /*
+ * Yes, does the user spec allow all
+ * authenticated users?
+ */
+ rv = (usp->us_flags & ACL_USALL) ? ACL_GRMATCH : 0;
+ if (!rv) {
+
+ /*
+ * No, need to check client user against list.
+ */
+ rv = aclUserLookup(&usp->us_user,
+ clauth->cla_uoptr);
+ }
+
+ /* Got a match yet? */
+ if (rv) {
+
+ /*
+ * Yes, update the the access control decision,
+ * clearing any pending authentication request
+ * flag.
+ */
+ authrlm = 0;
+ decision = acd->acd_action;
+
+ /* Copy the "always" flag to the result */
+ result = (acd->acd_flags & ACD_ALWAYS);
+ mdn = ndir;
+ }
+ }
+ else {
+
+ /*
+ * The client has been authenticated already,
+ * but not in the realm used by this directive.
+ * Since directives in a given ACL are not
+ * independent policy statements, it seems that
+ * the proper thing to do here is to reject
+ * this ACL in its entirity. This case is not
+ * an authentication failure per se, but rather
+ * an inability to evaluate this particular
+ * ACL directive which requires authentication.
+ */
+ return 0;
+ }
+ }
+ else {
+
+ /*
+ * The client user has not been authenticated in this
+ * realm yet, but could potentially be one of the
+ * users on this user list. This directive is
+ * therefore "potentially matching". The question
+ * is: would it change the current decision to allow
+ * or deny the client if the client user actually did
+ * match the user list?
+ */
+ if ((authrlm == 0) && (decision != acd->acd_action)) {
+
+ /*
+ * Yes, set the "request authentication" flag,
+ * along with ACD_ALWAYS if it is set in the
+ * directive.
+ */
+ authrlm = rlm;
+ decision = ACD_AUTH;
+ result = (acd->acd_flags & ACD_ALWAYS);
+ mdn = ndir;
+ }
+ }
+ }
+ else {
+
+ /*
+ * There is no user list. Therefore any user,
+ * authenticated or not, is considered a match.
+ * Update the decision, and clear the
+ * "authentication requested" flag.
+ */
+ authrlm = 0;
+ decision = acd->acd_action;
+ result = (acd->acd_flags & ACD_ALWAYS);
+ mdn = ndir;
+ }
+
+ /*
+ * If we hit a client specification that requires
+ * immediate action, exit the loop.
+ */
+ if (result & ACD_ALWAYS) break;
+ }
+ break;
+
+ case ACD_AUTH:
+
+ /* Got a pointer to a realm specification? */
+ if (acd->acd_auth.au_realm != 0) {
+
+ /* Yes, update the current realm pointer */
+ rlm = &acd->acd_auth.au_realm->rs_realm;
+
+ /* Has the client already successfully authenticated? */
+ if ((clauth->cla_realm == 0) || (clauth->cla_uoptr == 0)) {
+
+ /*
+ * No, if this is an "always" directive, override any
+ * previously selected realm and request authentication.
+ */
+ if ((acd->acd_flags & ACD_ALWAYS) != 0) {
+
+ /* Set decision to request authentication */
+ authrlm = rlm;
+ decision = ACD_AUTH;
+ result = ACD_ALWAYS;
+ mdn = ndir;
+ }
+ }
+ }
+ break;
+
+ case ACD_EXEC:
+
+ /* Conditionally terminate ACL evaluation */
+ switch (decision) {
+ case ACD_ALLOW:
+ if (acd->acd_flags & ACD_EXALLOW) {
+ result = (acd->acd_flags & ACD_ALWAYS);
+ goto out;
+ }
+ break;
+ case ACD_DENY:
+ if (acd->acd_flags & ACD_EXDENY) {
+ result = (acd->acd_flags & ACD_ALWAYS);
+ goto out;
+ }
+ break;
+ case ACD_AUTH:
+ if (acd->acd_flags & ACD_EXAUTH) {
+ result = (acd->acd_flags & ACD_ALWAYS);
+ goto out;
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ /*
+ * If we hit a directive that requires immediate action, exit
+ * the loop.
+ */
+ if (result & ACD_ALWAYS) break;
+ }
+
+ out:
+ /* If the decision is to request authentication, set the desired realm */
+ if (decision == ACD_AUTH) {
+ clauth->cla_realm = authrlm;
+ }
+
+ /* Combine decision with flags already in result */
+ result |= decision;
+
+ /* Return matching directive number if desired */
+ if (padn) *padn = mdn;
+
+ return result;
+}
diff --git a/lib/libaccess/aclflush.cpp b/lib/libaccess/aclflush.cpp
new file mode 100644
index 00000000..dfee47d6
--- /dev/null
+++ b/lib/libaccess/aclflush.cpp
@@ -0,0 +1,178 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Source file for the ACL_CacheFlush-related routines.
+ */
+
+#include <base/nsassert.h>
+#include <base/util.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/las.h>
+#include "aclcache.h"
+#include <libaccess/dbtlibaccess.h>
+
+extern void ACL_DatabaseDestroy(void);
+
+PRIntn
+deletelists(PRHashEntry *he, PRIntn i, void *arg)
+{
+ ACLListHandle_t *acllist=(ACLListHandle_t *)he->value;
+ NSErr_t *errp = 0;
+
+ NS_ASSERT(he);
+ NS_ASSERT(he->value);
+
+ if (acllist->ref_count) {
+ // If the list is in use, increment the counter. Then set the
+ // stale flag. The other user can't delete the list since we're
+ // counted as well. Finally, decrement the counter and whoever
+ // sets it to zero will delete the ACL List.
+ NS_ASSERT(ACL_CritHeld());
+ acllist->ref_count++;
+ acllist->flags |= ACL_LIST_STALE;
+ if (--acllist->ref_count == 0)
+ ACL_ListDestroy(errp, acllist);
+ } else {
+ ACL_ListDestroy(errp, acllist);
+ }
+
+ return 0;
+}
+
+PRIntn
+restartdeletelists(PRHashEntry *he, PRIntn i, void *arg)
+{
+ NSErr_t *errp = 0;
+
+ // Cannot be anyone left using the lists, so just free them no matter
+ // what.
+ ACLListHandle_t *acllist=(ACLListHandle_t *)he->value;
+
+ NS_ASSERT(he);
+ NS_ASSERT(he->value);
+
+ ACL_ListDestroy(errp, acllist);
+
+ return 0;
+}
+
+static AclCacheFlushFunc_t AclCacheFlushRoutine = NULL;
+
+NSAPI_PUBLIC int
+ACL_CacheFlushRegister(AclCacheFlushFunc_t flush_func)
+{
+ NS_ASSERT(flush_func);
+ AclCacheFlushRoutine = flush_func;
+
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_CacheFlush(void)
+{
+ ACLGlobal_p newACLGlobal;
+ NSErr_t *errp = 0;
+
+ NS_ASSERT(ACLGlobal);
+ NS_ASSERT(ACLGlobal->masterlist);
+ NS_ASSERT(ACLGlobal->listhash);
+ NS_ASSERT(ACLGlobal->urihash);
+ NS_ASSERT(ACLGlobal->urigethash);
+ NS_ASSERT(ACLGlobal->pool);
+
+ ACL_CritEnter();
+
+ // Swap the pointers. Keep using the current database/method tables
+ // until the new ones are built. This is a kludge. An in-progress
+ // evaluation could conceivably get messed up, but the window seems
+ // small.
+ newACLGlobal = oldACLGlobal;
+
+ oldACLGlobal = ACLGlobal;
+ ACLGlobal = newACLGlobal;
+
+ // Prepare the new ACLGlobal structure
+ ACL_UriHashInit(); /* Also initializes ACLGlobal->pool */
+ ACL_ListHashInit();
+ ACLGlobal->evalhash = oldACLGlobal->evalhash;
+ ACLGlobal->flushhash = oldACLGlobal->flushhash;
+ ACLGlobal->methodhash = oldACLGlobal->methodhash;
+ ACLGlobal->dbtypehash = oldACLGlobal->dbtypehash;
+ ACLGlobal->dbnamehash = oldACLGlobal->dbnamehash;
+ ACLGlobal->attrgetterhash = oldACLGlobal->attrgetterhash;
+ ACLGlobal->databasepool = oldACLGlobal->databasepool;
+ ACLGlobal->methodpool = oldACLGlobal->methodpool;
+
+ // Mark all existing ACL Lists as stale. Delete any unreferenced ones.
+ PR_HashTableEnumerateEntries(oldACLGlobal->listhash, deletelists, NULL);
+
+ // Delete the old master list.
+ ACL_ListDestroy(errp, oldACLGlobal->masterlist);
+ oldACLGlobal->masterlist = NULL;
+ PR_HashTableDestroy(oldACLGlobal->listhash);
+ oldACLGlobal->listhash = NULL;
+ PR_HashTableDestroy(oldACLGlobal->urihash);
+ oldACLGlobal->urihash = NULL;
+ PR_HashTableDestroy(oldACLGlobal->urigethash);
+ oldACLGlobal->urigethash = NULL;
+ pool_destroy(oldACLGlobal->pool);
+ oldACLGlobal->pool = NULL;
+ memset(oldACLGlobal, 0, sizeof(ACLGlobal_s));
+
+
+ // Read in the ACLs again in lib/frame
+ if (AclCacheFlushRoutine) {
+ (*AclCacheFlushRoutine)();
+ }
+
+ ACL_CritExit();
+
+ return 0;
+}
+
+
+NSAPI_PUBLIC void
+ACL_Restart(void *clntData)
+{
+ NSErr_t *errp = 0;
+
+ NS_ASSERT(ACLGlobal);
+ NS_ASSERT(ACLGlobal->masterlist);
+ NS_ASSERT(ACLGlobal->listhash);
+ NS_ASSERT(ACLGlobal->urihash);
+ NS_ASSERT(ACLGlobal->urigethash);
+ NS_ASSERT(ACLGlobal->pool);
+
+ // Unlike ACL_CacheFlush, this routine can be much more cavalier about
+ // freeing up memory, since there's guaranteed to be no users about at
+ // this time.
+
+ ACL_DatabaseDestroy();
+ ACL_MethodSetDefault(errp, ACL_METHOD_INVALID);
+
+ // Mark all existing ACL Lists as stale. Delete any unreferenced ones
+ // (i.e. all of them)
+ PR_HashTableEnumerateEntries(ACLGlobal->listhash, restartdeletelists, NULL);
+
+ // Delete the master list.
+ ACL_ListDestroy(errp, ACLGlobal->masterlist);
+
+ ACL_LasHashDestroy();
+ PR_HashTableDestroy(ACLGlobal->listhash);
+ PR_HashTableDestroy(ACLGlobal->urihash);
+ PR_HashTableDestroy(ACLGlobal->urigethash);
+ pool_destroy(ACLGlobal->pool);
+
+ PERM_FREE(ACLGlobal);
+ ACLGlobal = NULL;
+ PERM_FREE(oldACLGlobal);
+ oldACLGlobal = NULL;
+
+ return;
+}
diff --git a/lib/libaccess/aclparse.cpp b/lib/libaccess/aclparse.cpp
new file mode 100644
index 00000000..d8c429fe
--- /dev/null
+++ b/lib/libaccess/aclparse.cpp
@@ -0,0 +1,2241 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (aclparse.c)
+ *
+ * This module provides functions for parsing a file containing
+ * Access Control List (ACL) definitions. It builds a representation
+ * of the ACLs in memory, using the services of the aclbuild module.
+ */
+
+#include <base/systems.h>
+#include <base/file.h>
+#include <base/util.h>
+#include <netsite.h>
+#include <libaccess/nsadb.h>
+#include <libaccess/aclerror.h>
+#include <libaccess/aclparse.h>
+#include <libaccess/symbols.h>
+
+#ifdef XP_UNIX
+#include <sys/types.h>
+#include <netinet/in.h> /* ntohl */
+#include <arpa/inet.h>
+#endif
+
+void * aclChTab = 0; /* character class table handle */
+
+static char * classv[] = {
+ " \t\r\f\013", /* class 0 - whitespace */
+ "\n", /* class 1 - newline */
+ ",.;@*()+{}\"\'", /* class 2 - special characters */
+ "0123456789", /* class 3 - digits */
+ /* class 4 - letters */
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz",
+ "-", /* class 5 - hyphen */
+ "_", /* class 6 - underscore */
+ "/-_.:" /* class 7 - filename special characters */
+};
+
+static int classc = sizeof(classv)/sizeof(char *);
+
+/*
+ * Description (aclAuthListParse)
+ *
+ * This function parses an auth-list. An auth-list specifies
+ * combinations of user/group names and host addresses/names.
+ * An auth-list entry can identify a collection of users and/or
+ * groups, a collection of hosts by IP addresses or DNS names,
+ * or a combination of the two. Each auth-spec adds another
+ * ACClients_t structure to the specified list.
+ *
+ * The syntax for an auth-list is:
+ *
+ * auth-list ::= auth-spec | auth-list "," auth-spec
+ * auth-spec ::= auth-users [at-token auth-hosts]
+ * auth-users - see aclAuthUsersParse()
+ * auth-hosts - see aclAuthHostsParse()
+ * at-token ::= "at" | "@"
+ *
+ * The caller provides a pointer to a ClientSpec_t structure,
+ * which is built up with new information as auth-specs are parsed.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACL context object
+ * rlm - pointer to authentication realm object
+ * clsp - pointer to returned ACClients_t list head
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the auth-list, i.e. the first token which is not
+ * recognized as the start of an auth-spec. It is the caller's
+ * responsibility to validate this token as a legitimate terminator
+ * of an auth-list. If a parsing error occurs in the middle of
+ * an auth-spec, the return value is ACLERRPARSE, and an error frame
+ * is generated if an error list is provided. For other kinds of
+ * errors a negative error code (from aclerror.h) is returned.
+ */
+
+int aclAuthListParse(NSErr_t * errp, ACLFile_t * acf,
+ ACContext_t * acc, Realm_t * rlm, ACClients_t **clsp)
+{
+ void * token = acf->acf_token; /* token handle */
+ ACClients_t * csp; /* client spec pointer */
+ UserSpec_t * usp; /* user spec pointer */
+ HostSpec_t * hsp; /* host spec pointer */
+ int rv; /* result value */
+ int eid; /* error id */
+
+ /* Loop once for each auth-spec */
+ for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
+
+ usp = 0;
+ hsp = 0;
+
+ /* Parse auth-users into user and group lists in the ACClients_t */
+ rv = aclAuthUsersParse(errp, acf, rlm, &usp, 0);
+ if (rv < 0) break;
+
+ /* Is the at-token there? */
+ if ((rv == TOKEN_AT) || !strcasecmp(lex_token(token), KEYWORD_AT)) {
+
+ /* Step to the next token after the at-token */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /* Parse auth-hosts part, adding information to the HostSpec_t */
+ rv = aclAuthHostsParse(errp, acf, acc, &hsp);
+ if (rv < 0) break;
+ }
+
+ /* Create a new ACClients_t structure for the parsed information */
+ csp = (ACClients_t *)MALLOC(sizeof(ACClients_t));
+ if (csp == 0) goto err_nomem;
+
+ csp->cl_next = 0;
+ csp->cl_user = usp;
+ csp->cl_host = hsp;
+
+ /* Add it to the end of the list referenced by clsp */
+ while (*clsp != 0) clsp = &(*clsp)->cl_next;
+ *clsp = csp;
+
+ /* Need a "," to keep going */
+ if (rv != TOKEN_COMMA) break;
+ }
+
+ return rv;
+
+ err_nomem:
+ eid = ACLERR1000;
+ nserrGenerate(errp, ACLERRNOMEM, eid, ACL_Program, 0);
+ return ACLERRNOMEM;
+}
+
+/*
+ * Description (aclAuthHostsParse)
+ *
+ * This function parses a list of IP address and/or DNS name
+ * specifications, adding information to the IP and DNS filters
+ * associated with a specified HostSpec_t. The syntax of the
+ * auth-hosts construct is:
+ *
+ * auth-hosts ::= auth-host-elem | "(" auth-host-list ")"
+ * | "hosts" host-list-name
+ * auth-host-elem ::= auth-ip-spec | auth-dns-spec
+ * auth-ip-spec ::= ipaddr | ipaddr netmask
+ * auth-dns-spec ::= fqdn | dns-suffix
+ * auth-host-list ::= auth-host-elem | auth-host-list "," auth-host-elem
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACL context object
+ * hspp - pointer to HostSpec_t pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the auth-hosts, i.e. either the first token after a
+ * single auth-host-elem or the first token after the closing ")"
+ * of a list of auth-host-elems. It is the caller's responsibility
+ * to validate this token as a legitimate successor of auth-hosts.
+ * If a parsing error occurs in the middle of auth-hosts, the return
+ * value is ACLERRPARSE, and an error frame is generated if an error
+ * list is provided. For other kinds of errors a negative error
+ * code (from aclerror.h) is returned.
+ */
+
+int aclAuthHostsParse(NSErr_t * errp,
+ ACLFile_t * acf, ACContext_t * acc, HostSpec_t **hspp)
+{
+ void * token = acf->acf_token; /* token handle */
+ char * tokenstr; /* token string pointer */
+ int islist = 0; /* true if auth-host-list */
+ int fqdn; /* fully qualified domain name */
+ IPAddr_t ipaddr; /* IP address value */
+ IPAddr_t netmask; /* IP netmask value */
+ int arv; /* alternate result value */
+ int rv; /* result value */
+ int eid; /* error id */
+ char linestr[16]; /* line number string buffer */
+
+ rv = acf->acf_ttype;
+
+ /* Are we starting an auth-host-list? */
+ if (rv == TOKEN_LPAREN) {
+
+ /* Yes, it appears so */
+ islist = 1;
+
+ /* Step token to first auth-host-elem */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+ }
+ else if (rv == TOKEN_IDENT) {
+
+ /* Could this be "hosts host-list-name"? */
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_HOSTS)) {
+
+ /* We don't support lists of host lists yet */
+ if (*hspp != 0) goto err_unshl;
+
+ /* Get host-list-name */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+
+ if (rv != TOKEN_IDENT) goto err_hlname;
+
+ tokenstr = lex_token(token);
+
+ /* Look up the host-list-name in the ACL symbol table */
+ rv = symTableFindSym(acc->acc_stp,
+ tokenstr, ACLSYMHOST, (void **)hspp);
+ if (rv < 0) goto err_undefhl;
+
+ /* Step to token after the host-list-name */
+ rv = aclGetToken(errp, acf, 0);
+
+ return rv;
+ }
+ }
+
+ /* Loop for each auth-host-elem */
+ for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
+
+ /* Does this look like an auth-ip-spec? */
+ if (rv == TOKEN_NUMBER) {
+
+ /* Yes, go parse it */
+ rv = aclGetIPAddr(errp, acf, &ipaddr, &netmask);
+ if (rv < 0) goto punt;
+
+ arv = aclAuthIPAdd(hspp, ipaddr, netmask);
+ if (arv < 0) goto err_ipadd;
+ }
+ else if ((rv == TOKEN_STAR) || (rv == TOKEN_IDENT)) {
+
+ /* Get fully qualified DNS name indicator value */
+ fqdn = (rv == TOKEN_IDENT) ? 1 : 0;
+
+ /* This looks like the start of an auth-dns-spec */
+ rv = aclGetDNSString(errp, acf);
+ if (rv < 0) goto punt;
+
+ tokenstr = lex_token(token);
+
+ /* If the DNS spec begins with "*.", strip the "*" */
+ if (tokenstr && (tokenstr[0] == '*') && (tokenstr[1] == '.')) {
+ tokenstr += 1;
+ }
+
+ arv = aclAuthDNSAdd(hspp, tokenstr, fqdn);
+ if (arv < 0) goto err_dnsadd;
+
+ /* Pick up the next token */
+ rv = aclGetToken(errp, acf, 0);
+ }
+ else break;
+
+ /* If this is a list, we need a "," to keep going */
+ if (!islist || (rv != TOKEN_COMMA)) break;
+ }
+
+ /* Were we parsing an auth-host-list? */
+ if (islist) {
+
+ /* Yes, check for closing ")" */
+ if (acf->acf_ttype != TOKEN_RPAREN) goto err_norp;
+
+ /* Got it. Step to next token for caller. */
+ rv = aclGetToken(errp, acf, 0);
+ }
+
+ punt:
+ return rv;
+
+ err_unshl:
+ eid = ACLERR1100;
+ goto err_parse;
+
+ err_hlname:
+ eid = ACLERR1120;
+ goto err_parse;
+
+ err_undefhl:
+ eid = ACLERR1140;
+ rv = ACLERRUNDEF;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+ goto punt;
+
+ err_ipadd:
+ eid = ACLERR1180;
+ rv = arv;
+ goto err_ret;
+
+ err_dnsadd:
+ eid = ACLERR1200;
+ rv = arv;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto punt;
+
+ err_norp:
+ eid = ACLERR1220;
+ err_parse:
+ rv = ACLERRPARSE;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclAuthUsersParse)
+ *
+ * This function parses a list of users and groups subject to
+ * authorization, adding the information to a specified UserSpec_t.
+ * The syntax it parses is:
+ *
+ * auth-users ::= auth-user-elem | "(" auth-user-list ")"
+ * auth-user-elem ::= username | groupname
+ * | "all" | "anyone"
+ * auth-user-list ::= auth-user-elem | auth-user-list "," auth-user-elem
+ *
+ * If the 'elist' argument is non-null, an auth-user-list will be
+ * accepted without the enclosing parentheses. Any invalid user
+ * or group names will not cause a fatal error, but will be returned
+ * in an array of strings via 'elist'.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * rlm - pointer to authentication realm object
+ * uspp - pointer to UserSpec_t pointer
+ * elist - pointer to returned pointer to array
+ * of strings containing invalid user or
+ * group names (may be null)
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the auth-users, i.e. either the first token after a
+ * single auth-user-elem or the first token after the closing ")"
+ * of a list of auth-user-elems. It is the caller's responsibility
+ * to validate this token as a legitimate successor of auth-users.
+ * If a parsing error occurs in the middle of auth-users, the return
+ * value is ACLERRPARSE, and an error frame is generated if an error
+ * list is provided. For other kinds of errors a negative error
+ * code (from aclerror.h) is returned.
+ */
+
+int aclAuthUsersParse(NSErr_t * errp, ACLFile_t * acf,
+ Realm_t * rlm, UserSpec_t **uspp, char ***elist)
+{
+ void * token = acf->acf_token; /* token handle */
+ char * tokenstr; /* token string pointer */
+ UserSpec_t * usp; /* user list head structure */
+ int islist = 0; /* true if auth-user-list */
+ int inlist = 0; /* true if UserSpec_t was supplied */
+ int any = 0; /* true if KEYWORD_ANY seen */
+ int all = 0; /* true if KEYWORD_ALL seen */
+ int elemcnt = 0; /* count of auth-user-elem seen */
+ int elen = 0; /* length of evec in (char *) */
+ int ecnt = 0; /* entries used in evec */
+ char **evec = 0; /* list of bad user/group names */
+ int rv; /* result value */
+ int eid; /* error id */
+ char linestr[16]; /* line number string buffer */
+ int errc = 2;
+
+ usp = *uspp;
+ if ((usp != 0) && (usp->us_flags & ACL_USALL)) all = 1;
+
+ if (elist != 0) inlist = 1;
+ else {
+
+ /* Check for opening "(" */
+ if (acf->acf_ttype == TOKEN_LPAREN) {
+
+ /* Looks like an auth-user-list */
+ islist = 1;
+
+ /* Step token to first auth-user-elem */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+ }
+ }
+
+ /* Loop for each auth-user-elem */
+ for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
+
+ /* Looking for a user or group identifier */
+ if ((rv == TOKEN_IDENT) || (rv == TOKEN_STRING)) {
+
+ /*
+ * If KEYWORD_ALL or KEYWORD_ANY has already appeared
+ * in this auth-spec, then return an error.
+ */
+ if (all | any) goto err_allany;
+
+ /* Check for reserved words */
+ tokenstr = lex_token(token);
+
+ /* KEYWORD_AT begins auth-hosts, but is invalid here */
+ if (!strcasecmp(tokenstr, KEYWORD_AT)) break;
+
+ /* Check for special group names */
+ if (!strcasecmp(tokenstr, KEYWORD_ANY)) {
+
+ /*
+ * Any user, with no authentication needed. This can
+ * only appear once in an auth-spec, and cannot be used
+ * in combination with KEYWORD_ALL (or any other user or
+ * group identifiers, but that will get checked before
+ * we return).
+ */
+
+ if ((elemcnt > 0) || (usp != 0)) goto err_any;
+ any = 1;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_ALL)) {
+
+ /*
+ * Any authenticated user. This can only appear once in
+ * an auth-spec, and cannot be used in combination with
+ * KEYWORD_ANY (or any other user or group identifiers,
+ * but that will get checked before we return).
+ */
+
+ if (elemcnt > 0) goto err_all;
+
+ /* Create a UserSpec_t structure if we haven't got one yet */
+ if (usp == 0) {
+ usp = aclUserSpecCreate();
+ if (usp == 0) goto err_nomem1;
+ *uspp = usp;
+ }
+
+ usp->us_flags |= ACL_USALL;
+ all = 1;
+ }
+ else {
+
+ /* Create a UserSpec_t structure if we haven't got one yet */
+ if (usp == 0) {
+ usp = aclUserSpecCreate();
+ if (usp == 0) goto err_nomem2;
+ *uspp = usp;
+ }
+
+ /* This should be a user or group name */
+ rv = aclAuthNameAdd(errp, usp, rlm, tokenstr);
+ if (rv <= 0) {
+
+ /* The name was not found in the authentication DB */
+ if (elist != 0) {
+ if (evec == 0) {
+ evec = (char **)MALLOC(4*sizeof(char *));
+ evec[0] = 0;
+ ecnt = 1;
+ elen = 4;
+ }
+ else if (ecnt >= elen) {
+ elen += 4;
+ evec = (char **)REALLOC(evec, elen*sizeof(char *));
+ }
+ evec[ecnt-1] = STRDUP(tokenstr);
+ evec[ecnt] = 0;
+ ++ecnt;
+
+ }
+ else if (rv < 0) goto err_badgun;
+ }
+
+ /* Don't allow duplicate names */
+ if (rv & ANA_DUP) {
+ if (elist == 0) goto err_dupgun;
+ }
+ }
+
+ /* Count number of auth-user-elems seen */
+ elemcnt += 1;
+
+ /* Get the token after the auth-user-elem */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+ }
+
+ /* If this is a list, we need a "," to keep going */
+ if (!(islist | inlist) || (rv != TOKEN_COMMA)) break;
+ }
+
+ /* Were we parsing an auth-user-list? */
+ if (islist) {
+
+ /* Yes, check for closing ")" */
+ if (acf->acf_ttype != TOKEN_RPAREN) goto err_norp;
+
+ /* Got it. Step to next token for caller. */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+ }
+
+ /*
+ * If we didn't see any auth-user-elems, then the auth-user we were
+ * called to parse is missing. We will forgive and forget if the
+ * current token is a comma, however, so as to allow empty auth-specs.
+ */
+ if ((elemcnt <= 0) && (rv != TOKEN_COMMA)) {
+ goto err_noelem;
+ }
+
+ punt:
+ /* Return list of bad names if indicated */
+ if (elist != 0) *elist = evec;
+
+ return rv;
+
+ err_badgun:
+ /* Encountered an unknown user or group name */
+ eid = ACLERR1360;
+ rv = ACLERRUNDEF;
+ goto err_retgun;
+
+ err_dupgun:
+ /* A user or group name was specified multiple times */
+ eid = ACLERR1380;
+ rv = ACLERRDUPSYM;
+ goto err_retgun;
+
+ err_retgun:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+ goto punt;
+
+ err_norp:
+ /* Missing ")" */
+ eid = ACLERR1400;
+ goto err_parse;
+
+ err_noelem:
+ eid = ACLERR1420;
+ goto err_parse;
+
+ err_all:
+ eid = ACLERR1440;
+ goto err_parse;
+
+ err_any:
+ eid = ACLERR1460;
+ goto err_parse;
+
+ err_allany:
+ eid = ACLERR1480;
+ goto err_parse;
+
+ err_nomem1:
+ eid = ACLERR1500;
+ rv = ACLERRNOMEM;
+ errc = 0;
+ goto err_ret;
+
+ err_nomem2:
+ eid = ACLERR1520;
+ rv = ACLERRNOMEM;
+ errc = 0;
+ goto err_ret;
+
+ err_parse:
+ rv = ACLERRPARSE;
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, errc, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclDirectivesParse)
+ *
+ * This function parses the directives inside an ACL definition.
+ * The syntax for a directive list is:
+ *
+ * dir-list ::= directive | dir-list ";" directive
+ * directive ::= auth-directive | access-directive | exec-directive
+ * auth-directive ::= dir-force "authenticate" ["in" realm-spec]
+ * access-directive ::= dir-force dir-access auth-list
+ * exec-directive ::= dir-force "execute" ["if" exec-optlist]
+ * exec-optlist ::= exec-condition | exec-optlist "," exec-condition
+ * exec-condition ::= dir-access | "authenticate"
+ * dir-force ::= "Always" | "Default"
+ * dir-access ::= "allow" | "deny"
+ *
+ * See aclAuthListParse() for auth-list syntax.
+ * See aclRealmSpecParse() for realm-spec syntax.
+ *
+ * The caller provides a pointer to an ACL structure, which is
+ * built up with new information as directives are parsed.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acl - pointer to ACL structure
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the directive list, i.e. the first token which is not
+ * recognized as the start of a directive. It is the caller's
+ * responsibility to validate this token as a legitimate terminator
+ * of a directive list. If a parsing error occurs in the middle of
+ * a directive, the return value is ACLERRPARSE, and an error frame
+ * is generated if an error list is provided. For other kinds of
+ * errors a negative error code (from aclerror.h) is returned.
+ */
+
+int aclDirectivesParse(NSErr_t * errp, ACLFile_t * acf, ACL_t * acl)
+{
+ void * token = acf->acf_token; /* token handle */
+ char * tokenstr; /* token string */
+ Realm_t * rlm = 0; /* current realm pointer */
+ ACDirective_t * acd; /* directive pointer */
+ int action; /* directive action code */
+ int flags; /* directive action flags */
+ int arv; /* alternate return value */
+ int rv; /* result value */
+ int eid; /* error id */
+ char linestr[16]; /* line number string buffer */
+
+ /* Look for top-level directives */
+ for (rv = acf->acf_ttype; ; rv = aclGetToken(errp, acf, 0)) {
+
+ action = 0;
+ flags = 0;
+
+ /* Check for beginning of directive */
+ if (rv == TOKEN_IDENT) {
+
+ /* Check identifier for directive dir-force keywords */
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_DEFAULT)) {
+ flags = ACD_DEFAULT;
+ }
+ else if (!strcasecmp(tokenstr, "always")) {
+ flags = ACD_ALWAYS;
+ }
+ else break;
+
+ /*
+ * Now we're looking for dir-access, "authenticate",
+ * or "execute".
+ */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* An identifier would be nice ... */
+ if (rv != TOKEN_IDENT) goto err_access;
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_AUTH)) {
+
+ /* process auth-directive */
+ action = ACD_AUTH;
+
+ /* Create a new directive object */
+ acd = aclDirectiveCreate();
+ if (acd == 0) goto err_nomem1;
+
+ /* Get the next token after KEYWORD_AUTH */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /* Could we have "in" realm-spec here? */
+ if (rv == TOKEN_IDENT) {
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_IN)) {
+
+ /* Get the next token after KEYWORD_IN */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /* Parse the realm-spec */
+ rv = aclRealmSpecParse(errp, acf, acl->acl_acc,
+ &acd->acd_auth.au_realm);
+ if (rv < 0) break;
+
+ /* Set current realm */
+ if (acd->acd_auth.au_realm != 0) {
+
+ /* Close database in current realm if any */
+ if (rlm && rlm->rlm_authdb) {
+ (*rlm->rlm_aif->aif_close)(rlm->rlm_authdb, 0);
+ rlm->rlm_authdb = 0;
+ }
+
+ rlm = &acd->acd_auth.au_realm->rs_realm;
+ }
+ }
+ }
+
+ /* Add this directive to the ACL */
+ acd->acd_action = action;
+ acd->acd_flags = flags;
+
+ arv = aclDirectiveAdd(acl, acd);
+ if (arv < 0) goto err_diradd1;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_EXECUTE)) {
+
+ /* process exec-directive */
+ action = ACD_EXEC;
+
+ /* Create a new directive object */
+ acd = aclDirectiveCreate();
+ if (acd == 0) goto err_nomem3;
+
+ /* Get the next token after KEYWORD_EXECUTE */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /* Could we have "if" exec-optlist here? */
+ if (rv == TOKEN_IDENT) {
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_IF)) {
+
+ for (;;) {
+
+ /* Get the next token after KEYWORD_IF or "," */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ /*
+ * Looking for "allow", "deny", or "authenticate"
+ */
+ if (rv == TOKEN_IDENT) {
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_ALLOW)) {
+ flags |= ACD_EXALLOW;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_DENY)) {
+ flags |= ACD_EXDENY;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_AUTH)) {
+ flags |= ACD_EXAUTH;
+ }
+ else goto err_exarg;
+ }
+
+ /* End of directive if no comma */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) break;
+
+ if (rv != TOKEN_COMMA) break;
+ }
+ }
+ }
+ else flags = (ACD_EXALLOW|ACD_EXDENY|ACD_EXAUTH);
+
+ if (rv < 0) break;
+
+ /* Add this directive to the ACL */
+ acd->acd_action = action;
+ acd->acd_flags = flags;
+
+ arv = aclDirectiveAdd(acl, acd);
+ if (arv < 0) goto err_diradd3;
+ }
+ else {
+
+ /* process access-directive */
+
+ if (!strcasecmp(tokenstr, KEYWORD_ALLOW)) {
+ action = ACD_ALLOW;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_DENY)) {
+ action = ACD_DENY;
+ }
+ else goto err_acctype;
+
+ /* Get the next token after dir-access */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* Create a new directive object */
+ acd = aclDirectiveCreate();
+ if (acd == 0) goto err_nomem2;
+
+ /* Parse a list of auth-specs */
+ rv = aclAuthListParse(errp, acf, acl->acl_acc, rlm,
+ &acd->acd_cl);
+ if (rv < 0) break;
+
+ /* Add this directive to the ACL */
+ acd->acd_action = action;
+ acd->acd_flags = flags;
+
+ arv = aclDirectiveAdd(acl, acd);
+ if (arv < 0) goto err_diradd2;
+ }
+ }
+
+ /* Need a ";" to keep going */
+ if (rv != TOKEN_EOS) break;
+ }
+
+ punt:
+ /* Close database in current realm if any */
+ if (rlm && rlm->rlm_authdb) {
+ (*rlm->rlm_aif->aif_close)(rlm->rlm_authdb, 0);
+ rlm->rlm_authdb = 0;
+ }
+
+ return rv;
+
+ err_access:
+ /* dir-access not present */
+ eid = ACLERR1600;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_acctype:
+ /* dir-access identifier is invalid */
+ eid = ACLERR1620;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_diradd1:
+ eid = ACLERR1640;
+ rv = arv;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_diradd2:
+ eid = ACLERR1650;
+ rv = arv;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_nomem1:
+ eid = ACLERR1660;
+ rv = ACLERRNOMEM;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_nomem2:
+ eid = ACLERR1680;
+ rv = ACLERRNOMEM;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_nomem3:
+ eid = ACLERR1685;
+ rv = ACLERRNOMEM;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_diradd3:
+ eid = ACLERR1690;
+ rv = arv;
+ tokenstr = 0;
+ goto err_ret;
+
+ err_exarg:
+ eid = ACLERR1695;
+ rv = ACLERRSYNTAX;
+ goto err_ret;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ if (tokenstr) {
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+ }
+ else {
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 2, acf->acf_filename, linestr);
+ }
+ goto punt;
+}
+
+/*
+ * Description (aclACLParse)
+ *
+ * This function parses a data stream containing ACL definitions,
+ * and builds a representation of the ACLs in memory. Each ACL
+ * has a user-specified name, and a pointer to the ACL structure
+ * is stored under the name in a symbol table provided by the caller.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACContext_t structure
+ * flags - bit flags (unused - must be zero)
+ *
+ * Returns:
+ *
+ * The return value is zero if the stream is parsed successfully.
+ * Otherwise it is a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int aclACLParse(NSErr_t * errp, ACLFile_t * acf, ACContext_t * acc, int flags)
+{
+ void * token = acf->acf_token; /* handle for current token */
+ char * tokenstr; /* current token string */
+ char * aclname; /* ACL name string */
+ ACL_t * aclp; /* pointer to ACL structure */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ /* Look for top-level statements */
+ for (;;) {
+
+ /* Get a token to begin a statement */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* An identifier would be nice ... */
+ if (rv != TOKEN_IDENT) {
+
+ /* Empty statements are ok, if pointless */
+ if (rv == TOKEN_EOS) continue;
+
+ /* EOF is valid here */
+ if (rv == TOKEN_EOF) break;
+
+ /* Anything else is unacceptable */
+ goto err_nostmt;
+ }
+
+ /* Check identifier for statement keywords */
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_ACL)) {
+
+ /* ACL name rights-list { acl-def-list }; */
+
+ /* Get the name of the ACL */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) goto err_aclname;
+ aclname = lex_token(token);
+
+ /* Create the ACL structure */
+ rv = aclCreate(errp, acc, aclname, &aclp);
+ if (rv < 0) goto punt;
+
+ /* Get the next token after the ACL name */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* Parse the rights specification */
+ rv = aclRightsParse(errp, acf, acc, &aclp->acl_rights);
+
+ /* Want a "{" to open the ACL directive list */
+ if (rv != TOKEN_LBRACE) {
+ if (rv < 0) goto punt;
+ goto err_aclopen;
+ }
+
+ /* Get the first token in the ACL directive list */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+
+ /* Parse the ACL directive list */
+ rv = aclDirectivesParse(errp, acf, aclp);
+
+ /* Want a "}" to close the ACL directive list */
+ if (rv != TOKEN_RBRACE) {
+ if (rv < 0) goto punt;
+ goto err_aclclose;
+ }
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_INCLUDE)) {
+ /* Include "filename"; */
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_REALM)) {
+ /* Realm name realm-spec */
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_RIGHTS)) {
+ /* Rights name rights-def; */
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_HOSTS)) {
+ /* Hosts name auth-hosts; */
+ }
+ else goto err_syntax;
+ }
+
+ return 0;
+
+ err_nostmt:
+ eid = ACLERR1700;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_aclname:
+ eid = ACLERR1720;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_aclopen:
+ eid = ACLERR1740;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_aclclose:
+ eid = ACLERR1760;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+
+ err_syntax:
+ eid = ACLERR1780;
+ rv = ACLERRPARSE;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (aclFileClose)
+ *
+ * This function closes an ACL file previously opened by aclFileOpen(),
+ * and frees any associated data structures.
+ *
+ * Arguments:
+ *
+ * acf - pointer to ACL file information
+ * flags - bit flags (unused - must be zero)
+ */
+
+void aclFileClose(ACLFile_t * acf, int flags)
+{
+ if (acf != 0) {
+
+ /* Destroy the associated lexer stream if any */
+ if (acf->acf_lst != 0) {
+ lex_stream_destroy(acf->acf_lst);
+ }
+
+ /* Close the file if it's open */
+ if (acf->acf_fd != SYS_ERROR_FD) {
+ system_fclose(acf->acf_fd);
+ }
+
+ /* Destroy any associated token */
+ if (acf->acf_token != 0) {
+ lex_token_destroy(acf->acf_token);
+ }
+
+ /* Free the filename string if any */
+ if (acf->acf_filename != 0) {
+ FREE(acf->acf_filename);
+ }
+
+ /* Free the ACLFile_t structure */
+ FREE(acf);
+ }
+}
+
+/*
+ * Description (aclFileOpen)
+ *
+ * This function opens a specified filename and creates a structure
+ * to contain information about the file during parsing. This
+ * includes a handle for a LEX data stream for the file.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * filename - name of file to be opened
+ * flags - bit flags (unused - must be zero)
+ * pacf - pointer to returned ACLFile_t pointer
+ *
+ * Returns:
+ *
+ * The return value is zero if the file is opened successfully, and
+ * a pointer to the ACLFile_t is returned in the location specified
+ * by 'pacf'. Otherwise a negative error code (ACLERRxxxx - see
+ * aclerror.h) is returned, and an error frame will be generated if
+ * an error list is provided.
+ */
+
+int aclFileOpen(NSErr_t * errp,
+ char * filename, int flags, ACLFile_t **pacf)
+{
+ ACLFile_t * acf; /* pointer to ACL file structure */
+ int rv; /* return value */
+ int eid; /* error identifier */
+ char * errmsg; /* system error message string */
+
+ *pacf = 0;
+
+ /* Allocate the ACLFile_t structure */
+ acf = (ACLFile_t *)MALLOC(sizeof(ACLFile_t));
+ if (acf == 0) goto err_nomem1;
+
+ memset((void *)acf, 0, sizeof(ACLFile_t));
+ acf->acf_filename = STRDUP(filename);
+ acf->acf_lineno = 1;
+ acf->acf_flags = flags;
+
+ /* Create a LEX token object */
+ rv = lex_token_new((pool_handle_t *)0, 32, 8, &acf->acf_token);
+ if (rv < 0) goto err_nomem2;
+
+ /* Open the file */
+ acf->acf_fd = system_fopenRO(acf->acf_filename);
+ if (acf->acf_fd == SYS_ERROR_FD) goto err_open;
+
+ /* Create a LEX stream for the file */
+ acf->acf_lst = lex_stream_create(aclStreamGet,
+ (void *)acf->acf_fd, 0, 8192);
+ if (acf->acf_lst == 0) goto err_nomem3;
+
+ *pacf = acf;
+ return 0;
+
+ err_open: /* file open error */
+ rv = ACLERROPEN;
+ eid = ACLERR1900;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ goto punt;
+
+ err_nomem1: /* MALLOC of ACLFile_t failed */
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ goto err_mem;
+
+ err_nomem2: /* lex_token_new() failed */
+ rv = ACLERRNOMEM;
+ eid = ACLERR1940;
+ goto err_mem;
+
+ err_nomem3: /* lex_stream_create() failed */
+ system_fclose(acf->acf_fd);
+ rv = ACLERRNOMEM;
+ eid = ACLERR1960;
+
+ err_mem:
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ goto punt;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (aclGetDNSString)
+ *
+ * This function parses a DNS name specification, which consists
+ * of a sequence of DNS name components separated by ".". Each
+ * name component must start with a letter, and contains only
+ * letters, digits, and hyphens. An exception is that the first
+ * component may be the wildcard indicator, "*". This function
+ * assumes that the current token already contains a TOKEN_STAR
+ * or TOKEN_IDENT. The complete DNS name specification is
+ * returned as the current token string.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ *
+ * Returns:
+ *
+ * The character terminating the DNS name specification is returned
+ * as the function value. The current token type is unchanged, but
+ * the string associated with the current token contains the
+ * complete DNS name specification. An error is indicated by a
+ * negative return value, and an error frame is generated if an
+ * error list is provided.
+ */
+
+int aclGetDNSString(NSErr_t * errp, ACLFile_t * acf)
+{
+ LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
+ void * token = acf->acf_token; /* LEX token handle */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ /* The current token should be TOKEN_STAR or TOKEN_IDENT */
+ rv = acf->acf_ttype;
+
+ if ((rv != TOKEN_STAR) && (rv != TOKEN_IDENT)) goto err_dns1;
+
+ /* Loop to parse [ "." dns-component ]+ */
+ for (;;) {
+
+ /* Try to step over a "." */
+ rv = lex_next_char(lst, aclChTab, 0);
+
+ /* End of DNS string if there's not one there */
+ if (rv != '.') break;
+
+ /* Append the "." to the token string */
+ (void)lex_token_append(token, 1, ".");
+
+ /* Advance the input stream past the "." */
+ rv = lex_next_char(lst, aclChTab, CCM_SPECIAL);
+
+ /* Next we want to see a letter */
+ rv = lex_next_char(lst, aclChTab, 0);
+
+ /* Error if it's not there */
+ if (!lex_class_check(aclChTab, rv, CCM_LETTER)) goto err_dns2;
+
+ /* Append a string of letters, digits, hyphens to token */
+ rv = lex_scan_over(lst, aclChTab, (CCM_LETTER|CCM_DIGIT|CCM_HYPHEN),
+ token);
+ if (rv < 0) goto err_dns3;
+ }
+
+ punt:
+ return rv;
+
+ err_dns1:
+ eid = ACLERR2100;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_dns2:
+ eid = ACLERR2120;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_dns3:
+ eid = ACLERR2140;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+int aclGetFileSpec(NSErr_t * errp, ACLFile_t * acf, int flags)
+{
+ LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
+ void * token = acf->acf_token; /* LEX token handle */
+ char * tokenstr; /* token string pointer */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ /* Skip whitespace */
+ rv = lex_skip_over(lst, aclChTab, CCM_WS);
+ if (rv < 0) goto err_lex1;
+
+ /* Begin a new token string */
+ rv = lex_token_start(token);
+
+ rv = lex_scan_over(lst, aclChTab, CCM_FILENAME, token);
+ if (rv < 0) goto err_lex2;
+
+ tokenstr = lex_token(token);
+
+ if (!tokenstr || !*tokenstr) goto err_nofn;
+
+ punt:
+ return rv;
+
+ err_lex1:
+ eid = ACLERR2900;
+ goto err_parse;
+
+ err_lex2:
+ eid = ACLERR2920;
+ goto err_parse;
+
+ err_nofn:
+ eid = ACLERR2940;
+
+ err_parse:
+ rv = ACLERRPARSE;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclGetIPAddr)
+ *
+ * This function retrieves an IP address specification from a given
+ * input stream. The specification consists of an IP address expressed
+ * in the standard "." notation, possibly followed by whitespace and a
+ * netmask, also in "." form. The IP address and netmask values are
+ * returned. If no netmask is specified, a default value of 0xffffffff
+ * is returned.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * pip - pointer to returned IP address value
+ * pmask - pointer to returned IP netmask value
+ *
+ * Returns:
+ *
+ * If successful, the return value identifies the type of the token
+ * following the IP address specification. This token type value is
+ * also returned in acf_ttype. An error is indicated by a negative
+ * error code (ACLERRxxxx - see aclerror.h), and an error frame will
+ * be generated if an error list is provided. The token type code in
+ * acf_ttype is TOKEN_ERROR when an error code is returned.
+ */
+
+int aclGetIPAddr(NSErr_t * errp,
+ ACLFile_t * acf, IPAddr_t * pip, IPAddr_t * pmask)
+{
+ LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
+ void * token = acf->acf_token; /* LEX token handle */
+ char * tokenstr; /* token string pointer */
+ IPAddr_t ipaddr; /* IP address */
+ IPAddr_t netmask; /* IP netmask */
+ int dotcnt; /* count of '.' seen in address */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ /* Set default return values */
+ *pip = 0;
+ *pmask = 0xffffffff;
+
+ rv = acf->acf_ttype;
+
+ /* The current token must be a number */
+ if (rv != TOKEN_NUMBER) {
+
+ /* No IP address present */
+ return rv;
+ }
+
+ /* Assume no netmask */
+ netmask = 0xffffffff;
+
+ for (dotcnt = 0;;) {
+
+ /* Append digits and letters to the current token */
+ rv = lex_scan_over(lst, aclChTab, (CCM_DIGIT|CCM_LETTER), token);
+ if (rv < 0) goto err_lex1;
+
+ /* Stop when no "." follows the digits and letters */
+ if (rv != '.') break;
+
+ /* Stop if we've already seen three "." */
+ if (++dotcnt > 3) break;
+
+ /* Advance past the "." */
+ (void)lex_next_char(lst, aclChTab, CCM_SPECIAL);
+
+ /* Check the next character for a "*" */
+ rv = lex_next_char(lst, aclChTab, 0);
+ if (rv == '*') {
+
+ /* Advance past the "*" */
+ (void)lex_next_char(lst, aclChTab, CCM_SPECIAL);
+
+ netmask <<= ((4-dotcnt)*8);
+ netmask = htonl(netmask);
+
+ while (dotcnt < 4) {
+ (void)lex_token_append(token, 2, ".0");
+ ++dotcnt;
+ }
+ break;
+ }
+ else {
+ /* Append the "." to the token string */
+ (void)lex_token_append(token, 1, ".");
+ }
+ }
+
+ /* Get a pointer to the token string */
+ tokenstr = lex_token(token);
+
+ /* A NULL pointer or an empty string is an error */
+ if (!tokenstr || !*tokenstr) goto err_noip;
+
+ /* Convert IP address to binary */
+ ipaddr = inet_addr(tokenstr);
+ if (ipaddr == (unsigned long)-1) goto err_badip;
+
+ /* Skip whitespace */
+ rv = lex_skip_over(lst, aclChTab, CCM_WS);
+ if (rv < 0) goto err_lex2;
+
+ /* A digit is the start of a netmask */
+ if ((netmask == 0xffffffff) && lex_class_check(aclChTab, rv, CCM_DIGIT)) {
+
+ /* Initialize token for network mask */
+ rv = lex_token_start(token);
+
+ for (dotcnt = 0;;) {
+
+ /* Collect token including digits, letters, and periods */
+ rv = lex_scan_over(lst, aclChTab, (CCM_DIGIT|CCM_LETTER), token);
+ if (rv < 0) goto err_lex3;
+
+ /* Stop when no "." follows the digits and letters */
+ if (rv != '.') break;
+
+ /* Stop if we've already seen three "." */
+ if (++dotcnt > 3) break;
+
+ /* Append the "." to the token string */
+ (void)lex_token_append(token, 1, ".");
+
+ /* Advance past the "." */
+ (void)lex_next_char(lst, aclChTab, CCM_SPECIAL);
+ }
+
+ /* Get a pointer to the token string */
+ tokenstr = lex_token(token);
+
+ /* A NULL pointer or an empty string is an error */
+ if (!tokenstr || !*tokenstr) goto err_nonm;
+
+ /* Convert netmask to binary. */
+ netmask = inet_addr(tokenstr);
+ if (netmask == (unsigned long)-1) {
+
+ /*
+ * Unfortunately inet_addr() doesn't distinguish between an
+ * error and a valid conversion of "255.255.255.255". So
+ * we check for it explicitly. Too bad if "0xff.0xff.0xff.0xff"
+ * is specified. Don't do that!
+ */
+ if (strcmp(tokenstr, "255.255.255.255")) goto err_badnm;
+ }
+ }
+
+ /* Return the IP address and netmask in host byte order */
+ *pip = ntohl(ipaddr);
+ *pmask = ntohl(netmask);
+
+ /* Get the token following the IP address (and netmask) */
+ rv = aclGetToken(errp, acf, 0);
+
+ punt:
+ acf->acf_ttype = (rv < 0) ? TOKEN_ERROR : rv;
+ return rv;
+
+ err_lex1:
+ eid = ACLERR2200;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_lex2:
+ eid = ACLERR2220;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_lex3:
+ eid = ACLERR2240;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_noip:
+ eid = ACLERR2260;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_badip:
+ eid = ACLERR2280;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_nonm:
+ eid = ACLERR2300;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_badnm:
+ eid = ACLERR2320;
+ rv = ACLERRPARSE;
+ goto err_ret;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclGetToken)
+ *
+ * This function retrieves the next token in an ACL definition file.
+ * It skips blank lines, comments, and white space. It updates
+ * the current line number as newlines are encountered.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * flags - bit flags:
+ * AGT_NOSKIP - don't skip leading whitespace
+ * AGT_APPEND - append to token buffer
+ * (else start new token)
+ *
+ * Returns:
+ *
+ * The return value is a code identifying the next token if successful.
+ * This token type value is also returned in acf_ttype. An error
+ * is indicated by a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ * The token type code in acf_ttype is TOKEN_ERROR when an error code
+ * is returned.
+ */
+
+int aclGetToken(NSErr_t * errp, ACLFile_t * acf, int flags)
+{
+ LEXStream_t * lst = acf->acf_lst; /* LEX stream handle */
+ void * token = acf->acf_token; /* LEX token handle */
+ int dospecial = 0; /* handle CCM_SPECIAL character */
+ int tv; /* token value */
+ int rv; /* result value */
+ int eid; /* error id */
+ char spech;
+ char linestr[16]; /* line number string buffer */
+
+ /* Begin a new token, unless AGT_APPEND is set */
+ if (!(flags & AGT_APPEND)) {
+ rv = lex_token_start(token);
+ }
+
+ /* Loop to read file */
+ tv = 0;
+ do {
+
+ /*
+ * If the AGT_NOSKIP flag is not set, skip whitespace (but not
+ * newline). If the flag is set, just get the next character.
+ */
+ rv = lex_skip_over(lst, aclChTab, (flags & AGT_NOSKIP) ? 0 : CCM_WS);
+ if (rv <= 0) {
+ if (rv < 0) goto err_lex1;
+
+ /* Exit loop if EOF */
+ if (rv == 0) {
+ tv = TOKEN_EOF;
+ break;
+ }
+ }
+
+ /* Analyze character after whitespace */
+ switch (rv) {
+
+ case '\n': /* newline */
+
+ /* Keep count of lines as we're skipping whitespace */
+ acf->acf_lineno += 1;
+ (void)lex_next_char(lst, aclChTab, CCM_NL);
+ break;
+
+ case '#': /* Beginning of comment */
+
+ /* Skip to a newline if so */
+ rv = lex_skip_to(lst, aclChTab, CCM_NL);
+ break;
+
+ case ';': /* End of statement */
+ tv = TOKEN_EOS;
+ dospecial = 1;
+ break;
+
+ case '@': /* at sign */
+ tv = TOKEN_AT;
+ dospecial = 1;
+ break;
+
+ case '+': /* plus sign */
+ tv = TOKEN_PLUS;
+ dospecial = 1;
+ break;
+
+ case '*': /* asterisk */
+ tv = TOKEN_STAR;
+ dospecial = 1;
+ break;
+
+ case '.': /* period */
+ tv = TOKEN_PERIOD;
+ dospecial = 1;
+ break;
+
+ case ',': /* comma */
+ tv = TOKEN_COMMA;
+ dospecial = 1;
+ break;
+
+ case '(': /* left parenthesis */
+ tv = TOKEN_LPAREN;
+ dospecial = 1;
+ break;
+
+ case ')': /* right parenthesis */
+ tv = TOKEN_RPAREN;
+ dospecial = 1;
+ break;
+
+ case '{': /* left brace */
+ tv = TOKEN_LBRACE;
+ dospecial = 1;
+ break;
+
+ case '}': /* right brace */
+ tv = TOKEN_RBRACE;
+ dospecial = 1;
+ break;
+
+ case '\"': /* double quote */
+ case '\'': /* single quote */
+
+ /* Append string contents to token buffer */
+ rv = lex_scan_string(lst, token, 0);
+ tv = TOKEN_STRING;
+ break;
+
+ default:
+
+ /* Check for identifier, beginning with a letter */
+ if (lex_class_check(aclChTab, rv, CCM_LETTER)) {
+
+ /* Append valid identifier characters to token buffer */
+ rv = lex_scan_over(lst, aclChTab, CCM_IDENT, token);
+ tv = TOKEN_IDENT;
+ break;
+ }
+
+ /* Check for a number, beginning with a digit */
+ if (lex_class_check(aclChTab, rv, CCM_DIGIT)) {
+ char digit;
+
+ /* Save the first digit */
+ digit = (char)rv;
+
+ /* Append the first digit to the token */
+ rv = lex_token_append(token, 1, &digit);
+
+ /* Skip over the first digit */
+ rv = lex_next_char(lst, aclChTab, CCM_DIGIT);
+
+ /* If it's '0', we might have "0x.." */
+ if (rv == '0') {
+
+ /* Pick up the next character */
+ rv = lex_next_char(lst, aclChTab, 0);
+
+ /* Is it 'x'? */
+ if (rv == 'x') {
+
+ /* Yes, append it to the token */
+ digit = (char)rv;
+ rv = lex_token_append(token, 1, &digit);
+
+ /* Step over it */
+ rv = lex_next_char(lst, aclChTab, CCM_LETTER);
+ }
+ }
+ /* Get more digits, if any */
+ rv = lex_scan_over(lst, aclChTab, CCM_DIGIT, token);
+ tv = TOKEN_NUMBER;
+ break;
+ }
+
+ /* Unrecognized character */
+
+ spech = *lst->lst_cp;
+ lex_token_append(token, 1, &spech);
+ lst->lst_cp += 1;
+ lst->lst_len -= 1;
+ tv = TOKEN_HUH;
+ break;
+ }
+
+ /* Handle CCM_SPECIAL character? */
+ if (dospecial) {
+
+ /* Yes, clear the flag for next time */
+ dospecial = 0;
+
+ /* Get the character and advance past it */
+ rv = lex_next_char(lst, aclChTab, CCM_SPECIAL);
+
+ /* Append the character to the token buffer */
+ spech = (char)rv;
+ (void)lex_token_append(token, 1, &spech);
+ }
+ }
+ while ((tv == 0) && (rv > 0));
+
+ if (rv < 0) {
+ tv = TOKEN_ERROR;
+ }
+ else rv = tv;
+
+ acf->acf_ttype = tv;
+ return rv;
+
+ err_lex1:
+ rv = ACLERRPARSE;
+ eid = ACLERR2400;
+
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+
+ acf->acf_ttype = TOKEN_ERROR;
+ return rv;
+}
+
+/*
+ * Description (aclParseInit)
+ *
+ * This function is called to initialize the ACL parser. It
+ * creates a LEX character class table to assist in parsing.
+ *
+ * Arguments:
+ *
+ * None.
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. An error is indicated
+ * by a negative return value.
+ */
+
+int aclParseInit()
+{
+ int rv; /* result value */
+
+ /* Have we created the character class table yet? */
+ if (aclChTab == 0) {
+
+ /* No, initialize character classes for lexer processing */
+ rv = lex_class_create(classc, classv, &aclChTab);
+ if (rv < 0) goto err_nomem;
+ }
+
+ return 0;
+
+ err_nomem:
+ return ACLERRNOMEM;
+}
+
+/*
+ * Description (aclRealmSpecParse)
+ *
+ * This function parses an authentication realm specification. An
+ * authentication realm includes an authentication database and
+ * an authentication method. The syntax of a realm-spec is:
+ *
+ * realm-spec ::= "{" realm-directive-list "}" | "realm" realm-name
+ * realm-directive-list ::= realm-directive |
+ * realm-directive-list ";" realm-directive
+ * realm-directive ::= realm-db-directive | realm-meth-directive
+ * | realm-prompt-directive
+ * realm-db-directive ::= "database" db-file-path
+ * realm-meth-directive ::= "method" auth-method-name
+ * auth-method-name ::= "basic" | "SSL"
+ * realm-prompt-directive ::= "prompt" quote-char string quote-char
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACContext_t structure
+ * rspp - pointer to RealmSpec_t pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is the token type of the token
+ * following the realm-spec, i.e. either the first token after a
+ * realm-name or the first token after the closing "}". It is the
+ * caller's responsibility to validate this token as a legitimate
+ * successor of a realm-spec. If a parsing error occurs in the
+ * middle of a realm-spec, the return value is ACLERRPARSE, and an
+ * error frame is generated if an error list is provided. For
+ * other kinds of errors a negative error code (from aclerror.h)
+ * is returned.
+ */
+
+int aclRealmSpecParse(NSErr_t * errp,
+ ACLFile_t * acf, ACContext_t * acc, RealmSpec_t **rspp)
+{
+ void * token = acf->acf_token; /* handle for current token */
+ char * tokenstr; /* current token string */
+ RealmSpec_t * rsp; /* realm spec pointer */
+ RealmSpec_t * nrsp; /* named realm spec pointer */
+ int rv; /* result value */
+ int eid; /* error id value */
+ char linestr[16]; /* line number string buffer */
+
+ rv = acf->acf_ttype;
+
+ /* Is the current token a "{" ? */
+ if (rv != TOKEN_LBRACE) {
+
+ /* No, could it be KEYWORD_REALM? */
+ if (rv == TOKEN_IDENT) {
+
+ tokenstr = lex_token(token);
+
+ if (!strcasecmp(tokenstr, KEYWORD_REALM)) {
+
+ /* Yes, step to the realm name */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) {
+ if (rv < 0) goto punt;
+ goto err_rlmname;
+ }
+
+ tokenstr = lex_token(token);
+
+ /* Look up the named realm specification */
+ rv = symTableFindSym(acc->acc_stp, tokenstr, ACLSYMREALM,
+ (void **)&nrsp);
+ if (rv < 0) goto err_undrlm;
+
+ /* Return the named realm specification */
+ *rspp = nrsp;
+
+ /* Step to the token after the realm name */
+ rv = aclGetToken(errp, acf, 0);
+ }
+ }
+
+ return rv;
+ }
+
+ /* Step to the token after the "{" */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv < 0) goto punt;
+
+ rsp = *rspp;
+ if (rsp == 0) {
+ rsp = (RealmSpec_t *)MALLOC(sizeof(RealmSpec_t));
+ if (rsp == 0) goto err_nomem;
+ memset((void *)rsp, 0, sizeof(RealmSpec_t));
+ rsp->rs_sym.sym_type = ACLSYMREALM;
+ *rspp = rsp;
+ }
+
+ /* Loop for each realm-directive */
+ for (;; rv = aclGetToken(errp, acf, 0)) {
+
+ if (rv != TOKEN_IDENT) {
+
+ /* Exit loop on "}" */
+ if (rv == TOKEN_RBRACE) break;
+
+ /* Ignore null directives */
+ if (rv == TOKEN_EOS) continue;
+
+ /* Otherwise need an identifier to start a directive */
+ goto err_nodir;
+ }
+
+ tokenstr = lex_token(token);
+
+ /* Figure out which realm-directive this is */
+ if (!strcasecmp(tokenstr, KEYWORD_DATABASE)) {
+
+ /* Get a file specification for the database */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_STRING) {
+ if (rv < 0) goto punt;
+ goto err_nodb;
+ }
+
+ rsp->rs_realm.rlm_dbname = lex_token_take(token);
+ rsp->rs_realm.rlm_aif = &NSADB_AuthIF;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_METHOD)) {
+
+ /* Step to the method identifier */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) {
+ if (rv < 0) goto punt;
+ goto err_nometh;
+ }
+
+ tokenstr = lex_token(token);
+
+ /* Interpret method name and set method in realm structure */
+ if (!strcasecmp(tokenstr, KEYWORD_BASIC)) {
+ rsp->rs_realm.rlm_ameth = AUTH_METHOD_BASIC;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_SSL) && server_enterprise) {
+ rsp->rs_realm.rlm_ameth = AUTH_METHOD_SSL;
+ }
+ else goto err_badmeth;
+ }
+ else if (!strcasecmp(tokenstr, KEYWORD_PROMPT)) {
+
+ /* Step to the realm prompt string */
+ rv = aclGetToken(errp, acf, 0);
+ if ((rv != TOKEN_STRING) && (rv != TOKEN_IDENT)) {
+ if (rv < 0) goto punt;
+ goto err_noprompt;
+ }
+
+ /* Reference a copy of the prompt string from the realm */
+ rsp->rs_realm.rlm_prompt = lex_token_take(token);
+ }
+ else goto err_baddir;
+
+ /* Get the token after the realm-directive */
+ rv = aclGetToken(errp, acf, 0);
+
+ /* Need a ";" to keep going */
+ if (rv != TOKEN_EOS) break;
+ }
+
+ if (rv != TOKEN_RBRACE) goto err_rbrace;
+
+ /* Get the token after the realm-spec */
+ rv = aclGetToken(errp, acf, 0);
+
+ punt:
+ return rv;
+
+ err_rlmname:
+ eid = ACLERR2500;
+ goto err_parse;
+
+ err_undrlm:
+ eid = ACLERR2520;
+ rv = ACLERRUNDEF;
+ goto err_sym;
+
+ err_nomem:
+ eid = ACLERR2540;
+ rv = ACLERRNOMEM;
+ goto ret_err;
+
+ err_nodir:
+ eid = ACLERR2560;
+ goto err_parse;
+
+ err_nodb:
+ eid = ACLERR2570;
+ goto err_parse;
+
+ err_nometh:
+ eid = ACLERR2580;
+ goto err_parse;
+
+ err_badmeth:
+ eid = ACLERR2600;
+ goto err_sym;
+
+ err_noprompt:
+ eid = ACLERR2605;
+ goto err_parse;
+
+ err_baddir:
+ eid = ACLERR2610;
+ goto err_sym;
+
+ err_rbrace:
+ eid = ACLERR2620;
+ goto err_parse;
+
+ err_sym:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, tokenstr);
+ goto punt;
+
+ err_parse:
+ rv = ACLERRPARSE;
+ ret_err:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+ goto punt;
+}
+
+/*
+ * Description (aclRightsParse)
+ *
+ * This function parse an access rights list. The syntax for an
+ * access rights list is:
+ *
+ * rights-list ::= "(" list-of-rights ")"
+ * list-of-rights ::= rights-elem | list-of-rights "," rights-elem
+ * rights-elem ::= right-name | "+" rights-def-name
+ * right-name ::= identifier
+ * rights-def-name ::= identifier
+ *
+ * An element of a rights list is either the name of a particular
+ * access right (e.g. Read), or the name associated with an
+ * external definition of an access rights list, preceded by "+"
+ * (e.g. +editor-rights). The list is enclosed in parentheses,
+ * and the elements are separated by commas.
+ *
+ * This function adds to a list of rights provided by the caller.
+ * Access rights are internally assigned unique integer identifiers,
+ * and a symbol table is maintained to map an access right name to
+ * its identifier.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * acf - pointer to ACLFile_t for ACL file
+ * acc - pointer to ACContext_t structure
+ * rights - pointer to rights list head
+ *
+ * Returns:
+ *
+ * The return value is a code identifying the next token if successful.
+ * End-of-stream is indicated by a return value of TOKEN_EOF. An error
+ * is indicated by a negative error code (ACLERRxxxx - see aclerror.h),
+ * and an error frame will be generated if an error list is provided.
+ */
+
+int aclRightsParse(NSErr_t * errp, ACLFile_t * acf, ACContext_t * acc,
+ RightSpec_t **rights)
+{
+ void * token = acf->acf_token; /* LEX token handle */
+ char * ename; /* element name string pointer */
+ RightSpec_t * rsp; /* rights specification pointer */
+ RightSpec_t * nrsp; /* named rights spec pointer */
+ RightDef_t * rdp; /* right definition pointer */
+ int rv; /* result value */
+ int eid; /* error id */
+ char linestr[16]; /* line number string buffer */
+
+ /* Look for a left parenthesis */
+ if (acf->acf_ttype != TOKEN_LPAREN) {
+
+ /* No rights list present */
+ return 0;
+ }
+
+ rsp = *rights;
+
+ /* Create a RightSpec_t if we don't have one */
+ if (rsp == 0) {
+ rsp = (RightSpec_t *)MALLOC(sizeof(RightSpec_t));
+ if (rsp == 0) goto err_nomem1;
+ memset((void *)rsp, 0, sizeof(RightSpec_t));
+ rsp->rs_sym.sym_type = ACLSYMRDEF;
+ *rights = rsp;
+ }
+
+ /* Parse list elements */
+ for (;;) {
+
+ /* Look for an identifier */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) {
+
+ /* No, maybe a "+" preceding a rights definition name? */
+ if (rv != TOKEN_PLUS) {
+
+ /* One more chance, we'll allow the closing ")" after "," */
+ if (rv != TOKEN_RPAREN) {
+ /* No, bad news */
+ if (rv < 0) goto punt;
+ goto err_elem;
+ }
+
+ /* Got right paren after comma */
+ break;
+ }
+
+ /* Got a "+", try for the rights definition name */
+ rv = aclGetToken(errp, acf, 0);
+ if (rv != TOKEN_IDENT) {
+ if (rv < 0) goto punt;
+ goto err_rdef;
+ }
+
+ /* Get a pointer to the token string */
+ ename = lex_token(token);
+
+ /* See if it matches a rights definition in the symbol table */
+ rv = symTableFindSym(acc->acc_stp, ename, ACLSYMRDEF,
+ (void **)&nrsp);
+ if (rv) goto err_undef;
+
+ /*
+ * Merge the rights from the named rights list into the
+ * current rights list.
+ */
+ rv = uilMerge(&rsp->rs_list, &nrsp->rs_list);
+ if (rv < 0) goto err_nomem2;
+ }
+ else {
+
+ /* The current token is an access right name */
+
+ /* Get a pointer to the token string */
+ ename = lex_token(token);
+
+
+ /* Find or create an access right definition */
+ rv = aclRightDef(errp, acc, ename, &rdp);
+ if (rv < 0) goto err_radd;
+
+ /* Add the id for this right to the current rights list */
+ rv = usiInsert(&rsp->rs_list, rdp->rd_id);
+ if (rv < 0) goto err_nomem3;
+ }
+
+ rv = aclGetToken(errp, acf, 0);
+
+ /* Want a comma to continue the list */
+ if (rv != TOKEN_COMMA) {
+
+ /* A right parenthesis will end the list nicely */
+ if (rv == TOKEN_RPAREN) {
+
+ /* Get the first token after the rights list */
+ rv = aclGetToken(errp, acf, 0);
+ break;
+ }
+
+ /* Anything else is an error */
+ if (rv < 0) goto punt;
+ goto err_list;
+ }
+ }
+
+ return rv;
+
+ err_elem:
+ eid = ACLERR2700;
+ rv = ACLERRSYNTAX;
+ goto err_ret;
+
+ err_rdef:
+ eid = ACLERR2720;
+ rv = ACLERRSYNTAX;
+ goto err_ret;
+
+ err_undef:
+ eid = ACLERR2740;
+ rv = ACLERRUNDEF;
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program,
+ 3, acf->acf_filename, linestr, ename);
+ return rv;
+
+ err_nomem1:
+ eid = ACLERR2760;
+ goto err_nomem;
+
+ err_nomem2:
+ eid = ACLERR2780;
+ goto err_nomem;
+
+ err_radd:
+ eid = ACLERR2800;
+ goto err_ret;
+
+ err_nomem3:
+ eid = ACLERR2820;
+ goto err_nomem;
+
+ err_nomem:
+ rv = ACLERRNOMEM;
+ goto err_ret;
+
+ err_list:
+
+ eid = ACLERR2840;
+ rv = ACLERRSYNTAX;
+
+ err_ret:
+ sprintf(linestr, "%d", acf->acf_lineno);
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, acf->acf_filename, linestr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (aclStreamGet)
+ *
+ * This function is the stream read function designated by
+ * aclFileOpen() to read the file associated with the LEX stream
+ * it creates. It reads the next chunk of the file into the
+ * stream buffer.
+ *
+ * Arguments:
+ *
+ * lst - pointer to LEX stream structure
+ *
+ * Returns:
+ *
+ * The return value is the number of bytes read if successful.
+ * A return value of zero indicates end-of-file. An error is
+ * indicated by a negative return value.
+ */
+
+int aclStreamGet(LEXStream_t * lst)
+{
+ SYS_FILE fd = (SYS_FILE)(lst->lst_strmid);
+ int len;
+
+ len = system_fread(fd, lst->lst_buf, lst->lst_buflen);
+ if (len >= 0) {
+ lst->lst_len = len;
+ lst->lst_cp = lst->lst_buf;
+ }
+
+ return len;
+}
diff --git a/lib/libaccess/aclpriv.h b/lib/libaccess/aclpriv.h
new file mode 100644
index 00000000..a93cc055
--- /dev/null
+++ b/lib/libaccess/aclpriv.h
@@ -0,0 +1,171 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * ACL private data structure definitions
+ */
+
+#ifndef ACL_PARSER_HEADER
+#define ACL_PARSER_HEADER
+
+#include <netsite.h>
+#include <plhash.h>
+#include <base/pool.h>
+#include <base/plist.h>
+#include <libaccess/las.h>
+
+
+#define ACL_TERM_BSIZE 4
+#define ACL_FALSE_IDX -2
+#define ACL_TRUE_IDX -1
+#define ACL_MIN_IDX 0
+#define ACL_EXPR_STACK 1024
+#define ACL_TABLE_THRESHOLD 10
+
+typedef enum {
+ ACL_EXPR_OP_AND,
+ ACL_EXPR_OP_OR,
+ ACL_EXPR_OP_NOT
+ } ACLExprOp_t;
+
+
+typedef struct ACLExprEntry {
+ char *attr_name; /* LAS name input */
+ CmpOp_t comparator; /* LAS comparator input */
+ char *attr_pattern; /* LAS attribute input */
+ int false_idx; /* index, -1 true, -2 false */
+ int true_idx; /* index, -1 true, -2 false */
+ int start_flag; /* marks start of an expr */
+ void *las_cookie; /* private data store for LAS */
+ LASEvalFunc_t las_eval_func; /* LAS function */
+} ACLExprEntry_t;
+
+typedef struct ACLExprRaw {
+ char *attr_name; /* expr lval */
+ CmpOp_t comparator; /* comparator */
+ char *attr_pattern; /* expr rval */
+ ACLExprOp_t logical; /* logical operator */
+} ACLExprRaw_t;
+
+typedef struct ACLExprStack {
+ char *expr_text[ACL_EXPR_STACK];
+ ACLExprRaw_t *expr[ACL_EXPR_STACK];
+ int stack_index;
+ int found_subexpression;
+ int last_subexpression;
+} ACLExprStack_t;
+
+typedef struct ACLExprHandle {
+ char *expr_tag;
+ char *acl_tag;
+ int expr_number;
+ ACLExprType_t expr_type;
+ int expr_flags;
+ int expr_argc;
+ char **expr_argv;
+ PList_t expr_auth;
+ ACLExprEntry_t *expr_arry;
+ int expr_arry_size;
+ int expr_term_index;
+ ACLExprRaw_t *expr_raw;
+ int expr_raw_index;
+ int expr_raw_size;
+ struct ACLExprHandle *expr_next; /* Null-terminated */
+} ACLExprHandle_t;
+
+typedef struct ACLHandle {
+ int ref_count;
+ char *tag;
+ PFlags_t flags;
+ char *las_name;
+ pblock *pb;
+ char **attr_name;
+ int expr_count;
+ ACLExprHandle_t *expr_list_head; /* Null-terminated */
+ ACLExprHandle_t *expr_list_tail;
+} ACLHandle_t;
+
+
+typedef struct ACLWrapper {
+ ACLHandle_t *acl;
+ struct ACLWrapper *wrap_next;
+} ACLWrapper_t;
+
+#define ACL_LIST_STALE 0x1
+#define ACL_LIST_IS_STALE(x) ((x)->flags & ACL_LIST_STALE)
+
+typedef struct ACLListHandle {
+ ACLWrapper_t *acl_list_head; /* Null-terminated */
+ ACLWrapper_t *acl_list_tail; /* Null-terminated */
+ int acl_count;
+ void *acl_sym_table;
+ void *cache;
+ uint32 flags;
+ int ref_count;
+} ACLListHandle_t;
+
+typedef struct ACLAceNumEntry {
+ int acenum;
+ struct ACLAceNumEntry *next;
+ struct ACLAceNumEntry *chain; /* only used for freeing memory */
+} ACLAceNumEntry_t;
+
+typedef struct ACLAceEntry {
+ ACLExprHandle_t *acep;
+ /* Array of auth block ptrs for all the expr
+ clauses in this ACE */
+ PList_t *autharray;
+ /* PList with auth blocks for ALL attributes */
+ PList_t global_auth;
+ struct ACLAceEntry *next; /* Null-terminated list */
+} ACLAceEntry_t;
+
+typedef struct PropList PropList_t;
+
+typedef struct ACLEvalHandle {
+ pool_handle_t *pool;
+ ACLListHandle_t *acllist;
+ PList_t subject;
+ PList_t resource;
+ int default_result;
+} ACLEvalHandle_t;
+
+
+typedef struct ACLListCache {
+/* Hash table for all access rights used in all acls in this list. Each
+ * hash entry has a list of ACE numbers that relate to this referenced
+ * access right.
+ */
+ PLHashTable *Table;
+ char *deny_response;
+ char *deny_type;
+ ACLAceEntry_t *acelist; /* Evaluation order
+ * list of all ACEs
+ */
+ ACLAceNumEntry_t *chain_head; /* Chain of all Ace num
+ * entries for this
+ * ACL list so we can free them
+ */
+ ACLAceNumEntry_t *chain_tail;
+} ACLListCache_t;
+
+/* this is to speed up acl_to_str_append */
+typedef struct acl_string_s {
+ char * str;
+ long str_size;
+ long str_len;
+} acl_string_t;
+
+
+
+NSPR_BEGIN_EXTERN_C
+extern int ACL_ExprDisplay( ACLExprHandle_t *acl_expr );
+extern int ACL_AssertAcl( ACLHandle_t *acl );
+extern int ACL_EvalDestroyContext ( ACLListCache_t *cache );
+extern time_t *acl_get_req_time(PList_t resource);
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/aclscan.h b/lib/libaccess/aclscan.h
new file mode 100644
index 00000000..df54f374
--- /dev/null
+++ b/lib/libaccess/aclscan.h
@@ -0,0 +1,25 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Internal functions for scanner.
+ */
+
+
+#ifndef ACLSCAN_H
+#define ACLSCAN_H
+
+NSPR_BEGIN_EXTERN_C
+
+extern int acl_InitScanner(NSErr_t *errp, char *filename, char *buffer);
+extern int acl_EndScanner(void);
+extern void aclerror(const char *s);
+extern int acllex(void);
+
+NSPR_END_EXTERN_C
+
+#endif
+
diff --git a/lib/libaccess/aclscan.l b/lib/libaccess/aclscan.l
new file mode 100644
index 00000000..009e02db
--- /dev/null
+++ b/lib/libaccess/aclscan.l
@@ -0,0 +1,379 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Lexical analyzer for ACL
+ */
+
+%{
+#include "acl.tab.h" /* token codes */
+#include <base/file.h>
+#include <libaccess/acl.h>
+#include <libaccess/nserror.h>
+#include "aclpriv.h"
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <libaccess/aclerror.h>
+#ifdef XP_WIN32
+#include <io.h>
+#endif
+
+#include "parse.h"
+#include "aclscan.h"
+
+static int acl_scanner_input(char *buffer, int max_size);
+
+#define YY_NEVER_INTERACTIVE 1
+#undef YY_INPUT
+#define YY_INPUT(buf, result, max) (result = acl_scanner_input(buf, max))
+
+static int acl_lineno;
+static int acl_tokenpos;
+static char acl_filename[500];
+static NSErr_t *acl_errp;
+static int acl_use_buffer;
+static char *acl_buffer;
+static int acl_buffer_length;
+static int acl_buffer_offset;
+static char *last_string;
+static SYS_FILE acl_prfd;
+
+
+%}
+
+ws [ \t]+
+comment #.*
+qstring \"[^\"\n]*[\"\n]
+variable [\*a-zA-Z0-9\.\-\_][\*a-zA-Z0-9\.\-\_]*
+
+%%
+
+\n.* {
+ acl_lineno++;
+ acl_tokenpos = 0;
+ yyless(1);
+ }
+
+{ws} ;
+
+{comment} ;
+
+<<EOF>> {
+ yylval.string = NULL;
+ last_string = yylval.string;
+ return(0);
+ }
+
+{qstring} {
+ yylval.string = PERM_STRDUP( yytext+1 );
+ last_string = yylval.string;
+ if ( yylval.string[yyleng-2] != '"' )
+ fprintf(stderr, "Unterminated string\n") ;
+ else
+ yylval.string[yyleng-2] = '\0';
+ acl_tokenpos += yyleng;
+ return ACL_QSTRING_TOK;
+ }
+
+
+absolute {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_ABSOLUTE_TOK;
+ }
+
+acl {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_ACL_TOK;
+ }
+
+allow {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_ALLOW_TOK;
+ }
+
+always {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_ALWAYS_TOK;
+ }
+
+at {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_AT_TOK;
+ }
+
+authenticate {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_AUTHENTICATE_TOK;
+ }
+
+content {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_CONTENT_TOK;
+ }
+
+default {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_DEFAULT_TOK;
+ }
+
+deny {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_DENY_TOK;
+ }
+
+in {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_IN_TOK;
+ }
+
+inherit {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_INHERIT_TOK;
+ }
+
+terminal {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_TERMINAL_TOK;
+ }
+
+version {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_VERSION_TOK;
+ }
+
+with {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_WITH_TOK;
+ }
+
+not {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return ACL_NOT_TOK;
+ }
+
+and {
+ last_string = NULL;
+ yylval.ival = ACL_EXPR_OP_AND;
+ acl_tokenpos += yyleng;
+ return ACL_AND_TOK;
+ }
+
+or {
+ last_string = NULL;
+ yylval.ival = ACL_EXPR_OP_OR;
+ acl_tokenpos += yyleng;
+ return ACL_OR_TOK;
+ }
+
+"=" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_EQ;
+ acl_tokenpos += yyleng;
+ return ACL_EQ_TOK;
+ }
+
+">=" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_GE;
+ acl_tokenpos += yyleng;
+ return ACL_GE_TOK;
+ }
+
+">" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_GT;
+ acl_tokenpos += yyleng;
+ return ACL_GT_TOK;
+ }
+
+"<" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_LT;
+ acl_tokenpos += yyleng;
+ return ACL_LT_TOK;
+ }
+
+"<=" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_LE;
+ acl_tokenpos += yyleng;
+ return ACL_LE_TOK;
+ }
+
+"!=" {
+ last_string = NULL;
+ yylval.ival = CMP_OP_NE;
+ acl_tokenpos += yyleng;
+ return ACL_NE_TOK;
+ }
+
+[(){},;] {
+ last_string = NULL;
+ acl_tokenpos += yyleng;
+ return yytext[0];
+ }
+
+{variable} {
+ acl_tokenpos += yyleng;
+ yylval.string = PERM_STRDUP( yytext );
+ last_string = yylval.string;
+ return ACL_VARIABLE_TOK;
+ }
+%%
+
+void
+acl_detab(char *t, char *s)
+{
+ int ii;
+ int pos;
+ int len;
+
+ if (s == NULL || t == NULL)
+ return;
+
+ len = strlen(s);
+ pos = 0;
+ for (ii = 0; ii < len; ii++) {
+ if (s[ii] == '\t') {
+ t[pos] = ' ';
+ } else {
+ t[pos] = s[ii];
+ }
+ pos++;
+ }
+ t[pos] = '\0';
+ return;
+}
+
+void
+yyerror(const char *s)
+{
+char errorStr[256];
+
+#if defined(UTEST) || defined(ACL_COMPILER)
+ printf("ACL file: %s\n", acl_filename);
+ printf("Syntax error at line: %d, token: %s\n", acl_lineno, yytext);
+ if ( last_string )
+ free(last_string);
+#else
+ sprintf(errorStr, "%d", acl_lineno);
+ if (yytext) {
+ nserrGenerate(acl_errp, ACLERRPARSE, ACLERR1780, ACL_Program,
+ 3, acl_filename, errorStr, yytext);
+ } else {
+ nserrGenerate(acl_errp, ACLERRPARSE, ACLERR1780, ACL_Program,
+ 2, acl_filename, errorStr);
+ }
+ if ( last_string )
+ free(last_string);
+#endif
+
+}
+
+int
+acl_InitScanner(NSErr_t *errp, char *filename, char *buffer)
+{
+ acl_errp = errp;
+ acl_lineno = 1;
+ acl_use_buffer = (filename == NULL) ? 1 : 0 ;
+ if ( filename != NULL ) {
+ strcpy(acl_filename, filename);
+#ifdef UTEST
+ yyin = fopen(filename, "r");
+ if ( yyin == NULL ) {
+ return(-1);
+ }
+#else
+ acl_prfd = system_fopenRO(filename);
+ if ( acl_prfd == NULL ) {
+ return(-1);
+ }
+ yyin = (FILE *) acl_prfd;
+#endif
+ yyrestart(yyin);
+ } else if ( buffer != NULL ) {
+ strcpy(acl_filename, "internal-buffer");
+ acl_buffer_offset = 0;
+ acl_buffer_length = strlen(buffer);
+ acl_buffer = PERM_STRDUP(buffer);
+ if (acl_buffer == NULL)
+ return(-1);
+ yyrestart(NULL);
+ } else {
+ return(-1);
+ }
+ return(0);
+}
+
+int
+acl_EndScanner()
+{
+ acl_lineno = 0;
+ if ( acl_use_buffer) {
+ if ( acl_buffer )
+ PERM_FREE(acl_buffer);
+ } else if ( yyin ) {
+#ifdef UTEST
+ fclose(yyin);
+#else
+ if ( acl_prfd ) {
+ system_fclose(acl_prfd);
+ acl_prfd = NULL;
+ }
+#endif
+ yyin = NULL ;
+ }
+ return(0);
+}
+
+int
+yywrap()
+{
+ return(1);
+}
+
+static int
+acl_scanner_input(char *buffer, int max_size)
+{
+ int len = 0;
+
+ if ( acl_use_buffer ) {
+ len = (acl_buffer_length > max_size) ? max_size :
+ acl_buffer_length;
+ memcpy(buffer, (const void *) &acl_buffer[acl_buffer_offset],
+ len);
+ acl_buffer_length -= len;
+ acl_buffer_offset += len;
+ }
+#ifdef UTEST
+ else if ( ((len = fread( buffer, 1, max_size, aclin )) == 0)
+ && ferror( aclin ) ) {
+ yyerror( "scanner input failed" );
+ }
+#else
+ else if ( (len = system_fread( acl_prfd, buffer, max_size)) < 0 ) {
+ yyerror( "scanner input failed" );
+ }
+#endif
+
+ return(len);
+}
diff --git a/lib/libaccess/aclspace.cpp b/lib/libaccess/aclspace.cpp
new file mode 100644
index 00000000..fb211075
--- /dev/null
+++ b/lib/libaccess/aclspace.cpp
@@ -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 **/
+
+#include <string.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclglobal.h>
+
+/* Ordered list of generic rights */
+char *generic_rights[7] = {
+ "read",
+ "write",
+ "execute",
+ "delete",
+ "info",
+ "list",
+ NULL
+ } ;
+
+char *http_generic[7] = {
+ "http_get, http_head, http_trace, http_revlog, http_options, http_copy, http_getattribute, http_index, http_getproperties, http_getattributenames ",
+ "http_put, http_mkdir, http_startrev, http_stoprev, http_edit, http_post, http_save, http_setattribute, http_revadd, http_revlabel, http_lock, http_unlock, http_unedit, http_stoprev, http_startrev",
+ "http_post",
+ "http_delete, http_destroy, http_move",
+ "http_head, http_trace, http_options",
+ "http_index",
+ NULL
+ } ;
+
+/* Pointer to all global ACL data. This pointer is moved (atomically)
+ when a cache flush call is made.
+*/
+ACLGlobal_p ACLGlobal;
+ACLGlobal_p oldACLGlobal;
diff --git a/lib/libaccess/acltext.y b/lib/libaccess/acltext.y
new file mode 100644
index 00000000..01d6ae1f
--- /dev/null
+++ b/lib/libaccess/acltext.y
@@ -0,0 +1,957 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * This grammar is intended to parse the version 3.0
+ * and version 2.0 ACL text files and output an ACLListHandle_t
+ * structure.
+ */
+
+%{
+#include <string.h>
+#include <netsite.h>
+#include <base/util.h>
+#include <base/plist.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/nserror.h>
+#include "parse.h"
+#include "aclscan.h"
+
+#define MAX_LIST_SIZE 255
+static ACLListHandle_t *curr_acl_list; /* current acl list */
+static ACLHandle_t *curr_acl; /* current acl */
+static ACLExprHandle_t *curr_expr; /* current expression */
+static PFlags_t pflags; /* current authorization flags */
+static char *curr_args_list[MAX_LIST_SIZE]; /* current args */
+static char *curr_user_list[MAX_LIST_SIZE]; /* current users v2 */
+static char *curr_ip_dns_list[MAX_LIST_SIZE]; /* current ip/dns v2 */
+static PList_t curr_auth_info; /* current authorization method */
+static int use_generic_rights; /* use generic rights for conversion */
+
+int acl_PushListHandle(ACLListHandle_t *handle)
+{
+ curr_acl_list = handle;
+ return(0);
+}
+
+static void
+acl_string_lower(char *s)
+{
+int ii;
+int len;
+
+ len = strlen(s);
+ for (ii = 0; ii < len; ii++)
+ s[ii] = tolower(s[ii]);
+
+ return;
+}
+
+static void
+acl_clear_args(char **args_list)
+{
+ args_list[0] = NULL;
+}
+
+static void
+acl_add_arg(char **args_list, char *arg)
+{
+ static int args_index;
+
+ if ( args_list[0] == NULL ) {
+ args_index = 0;
+ }
+ args_list[args_index] = arg;
+ args_index++;
+ args_list[args_index] = NULL;
+}
+
+static void
+acl_free_args(char **args_list)
+{
+ int ii;
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( args_list[ii] )
+ free(args_list[ii]);
+ else
+ break;
+ }
+}
+
+static int
+acl_set_args(ACLExprHandle_t *expr, char **args_list)
+{
+ int ii;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( args_list[ii] ) {
+ if ( ACL_ExprAddArg(NULL, expr, args_list[ii]) < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ } else
+ break;
+ }
+ return(0);
+}
+
+static int
+acl_set_users(ACLExprHandle_t *expr, char **user_list)
+{
+ int ii;
+ int jj;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( user_list[ii] ) {
+ if ( ACL_ExprTerm(NULL, expr, "user", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ } else
+ break;
+ }
+
+ acl_free_args(user_list);
+
+ for (jj = 0; jj < ii - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ yyerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+acl_set_users_or_groups(ACLExprHandle_t *expr, char **user_list)
+{
+ int ii;
+ int jj;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( user_list[ii] ) {
+ if ( ACL_ExprTerm(NULL, expr, "user", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ if ( ACL_ExprTerm(NULL, expr, "group", CMP_OP_EQ,
+ user_list[ii]) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ acl_free_args(user_list);
+ return(-1);
+ }
+ } else
+ break;
+ }
+
+ acl_free_args(user_list);
+
+ for (jj = 0; jj < (ii * 2) - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ yyerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+static int
+acl_set_ip_dns(ACLExprHandle_t *expr, char **ip_dns)
+{
+ int ii;
+ int jj;
+ int len;
+ char *attr;
+ char *val;
+
+ if (expr == NULL)
+ return(-1);
+
+ for (ii = 0; ii < MAX_LIST_SIZE; ii++) {
+ if ( ip_dns[ii] ) {
+
+ attr = "ip";
+ val = ip_dns[ii];
+ len = strlen(val);
+
+ for (jj = 0; jj < len; jj++) {
+ if ( strchr("0123456789.*", val[jj]) == 0 ) {
+ attr = "dns";
+ break;
+ }
+ }
+
+ if ( ACL_ExprTerm(NULL, expr, attr, CMP_OP_EQ,
+ val) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ acl_free_args(ip_dns);
+ return(-1);
+ }
+
+ } else
+ break;
+ }
+
+ acl_free_args(ip_dns);
+
+ for (jj = 0; jj < ii - 1; jj++) {
+ if ( ACL_ExprOr(NULL, expr) < 0 ) {
+ yyerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+
+ return(0);
+}
+
+
+%}
+
+%union {
+ char *string;
+ int ival;
+}
+
+%token ACL_ABSOLUTE_TOK
+%token ACL_ACL_TOK
+%token ACL_ALLOW_TOK
+%token ACL_ALWAYS_TOK
+%token ACL_AND_TOK
+%token ACL_AT_TOK
+%token ACL_AUTHENTICATE_TOK
+%token ACL_CONTENT_TOK
+%token ACL_DEFAULT_TOK
+%token ACL_DENY_TOK
+%token ACL_GROUP_TOK
+%token ACL_IN_TOK
+%token ACL_INHERIT_TOK
+%token ACL_NOT_TOK
+%token ACL_NULL_TOK
+%token ACL_OR_TOK
+%token <string> ACL_QSTRING_TOK
+%token ACL_READ_TOK
+%token ACL_TERMINAL_TOK
+%token <string> ACL_VARIABLE_TOK
+%token ACL_VERSION_TOK
+%token ACL_WRITE_TOK
+%token ACL_WITH_TOK
+
+%token <ival> ACL_EQ_TOK
+%token <ival> ACL_GE_TOK
+%token <ival> ACL_GT_TOK
+%token <ival> ACL_LE_TOK
+%token <ival> ACL_LT_TOK
+%token <ival> ACL_NE_TOK
+
+%%
+
+/*
+ * If no version is specified then we have a version 2.0 ACL.
+ */
+start: | start_acl_v2
+ | ACL_VERSION_TOK ACL_VARIABLE_TOK
+ {
+ free($<string>2);
+ }
+ ';' start_acl_v3
+ ;
+
+/*
+ ************************************************************
+ * Parse version 2.0 ACL
+ ************************************************************
+ */
+start_acl_v2: acl_list_v2
+ ;
+
+acl_list_v2: acl_v2
+ | acl_list_v2 acl_v2
+ ;
+
+acl_v2: ACL_ACL_TOK acl_name_v2
+ '(' arg_list_v2 ')' '{' directive_list_v2 '}'
+ {
+ acl_free_args(curr_args_list);
+ }
+ ;
+
+acl_name_v2: ACL_VARIABLE_TOK
+ {
+ curr_acl = ACL_AclNew(NULL, $<string>1);
+ free($<string>1);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ yyerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ acl_clear_args(curr_args_list);
+ use_generic_rights = 0;
+ if (strstr(curr_acl->tag, "READ")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("read"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("execute"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("list"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("info"));
+ } if (strstr(curr_acl->tag, "WRITE")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("write"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("delete"));
+ }
+ }
+ | ACL_QSTRING_TOK
+ {
+ curr_acl = ACL_AclNew(NULL, $<string>1);
+ free($<string>1);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ yyerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ acl_clear_args(curr_args_list);
+ use_generic_rights = 0;
+ if (strstr(curr_acl->tag, "READ")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("read"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("execute"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("list"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("info"));
+ } if (strstr(curr_acl->tag, "WRITE")) {
+ use_generic_rights++;
+ acl_add_arg(curr_args_list, PERM_STRDUP("write"));
+ acl_add_arg(curr_args_list, PERM_STRDUP("delete"));
+ }
+ }
+ ;
+
+arg_list_v2: arg_v2
+ | arg_v2 ',' arg_list_v2
+ ;
+
+arg_v2: ACL_VARIABLE_TOK
+ {
+ char acl_tmp_arg[255];
+ char *acl_new_arg;
+
+ if (!use_generic_rights) {
+ acl_string_lower($<string>1);
+ strcpy(acl_tmp_arg, "http_");
+ strcat(acl_tmp_arg, $<string>1);
+ PERM_FREE($<string>1);
+ acl_new_arg = PERM_STRDUP(acl_tmp_arg);
+ acl_add_arg(curr_args_list, acl_new_arg);
+ } else {
+ PERM_FREE($<string>1);
+ }
+ }
+ | ACL_QSTRING_TOK
+ {
+ if (!use_generic_rights) {
+ acl_add_arg(curr_args_list, $<string>1);
+ } else {
+ PERM_FREE($<string>1);
+ }
+ }
+ ;
+
+directive_list_v2: directive_v2 ';'
+ | directive_v2 ';' directive_list_v2
+ ;
+
+directive_v2: auth_method_v2
+ | auth_statement_v2
+ ;
+
+auth_statement_v2: ACL_ALWAYS_TOK auth_type_v2
+ {
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ yyerror("Could not set authorization processing flags");
+ return(-1);
+ }
+ }
+ host_spec_list_action_v2
+ | ACL_DEFAULT_TOK auth_type_v2 host_spec_list_action_v2
+ ;
+
+auth_type_v2: ACL_ALLOW_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_ALLOW) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ acl_clear_args(curr_user_list);
+ acl_clear_args(curr_ip_dns_list);
+ }
+ | ACL_DENY_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_DENY) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ acl_clear_args(curr_user_list);
+ acl_clear_args(curr_ip_dns_list);
+ }
+ ;
+
+auth_method_v2:
+ ACL_ALWAYS_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(auth) failed");
+ return(-1);
+ }
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ yyerror("Could not set authorization processing flags");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ yyerror("Could not set authorization info");
+ return(-1);
+ }
+ }
+ realm_definition_v2
+ | ACL_DEFAULT_TOK ACL_AUTHENTICATE_TOK ACL_IN_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(auth) failed");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ yyerror("Could not set authorization info");
+ return(-1);
+ }
+ }
+ realm_definition_v2
+ ;
+
+host_spec_list_action_v2: user_expr_v2 ACL_AT_TOK host_spec_list_v2
+ {
+ if ( acl_set_users_or_groups(curr_expr, curr_user_list) < 0 ) {
+ yyerror("acl_set_users_or_groups() failed");
+ return(-1);
+ }
+
+ if ( acl_set_ip_dns(curr_expr, curr_ip_dns_list) < 0 ) {
+ yyerror("acl_set_ip_dns() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAnd(NULL, curr_expr) < 0 ) {
+ yyerror("ACL_ExprAnd() failed");
+ return(-1);
+ }
+
+ if ( acl_set_args(curr_expr, curr_args_list) < 0 ) {
+ yyerror("acl_set_args() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ | user_expr_v2
+ {
+ if ( acl_set_users_or_groups(curr_expr, curr_user_list) < 0 ) {
+ yyerror("acl_set_users_or_groups() failed");
+ return(-1);
+ }
+
+ if ( acl_set_args(curr_expr, curr_args_list) < 0 ) {
+ yyerror("acl_set_args() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ ;
+
+user_expr_v2: user_v2
+ | '(' user_list_v2 ')'
+ ;
+
+user_list_v2: user_v2
+ | user_v2 ',' user_list_v2
+ ;
+
+user_v2: ACL_VARIABLE_TOK
+ {
+ acl_add_arg(curr_user_list, $<string>1);
+ }
+ | ACL_QSTRING_TOK
+ {
+ acl_add_arg(curr_user_list, $<string>1);
+ }
+ ;
+
+
+host_spec_list_v2: dns_spec_v2
+ | ip_spec_v2
+ | '(' dns_ip_spec_list_v2 ')'
+ ;
+
+dns_spec_v2: ACL_VARIABLE_TOK
+ {
+ acl_add_arg(curr_ip_dns_list, $<string>1);
+ }
+ | ACL_QSTRING_TOK
+ {
+ acl_add_arg(curr_ip_dns_list, $<string>1);
+ }
+ ;
+
+ip_spec_v2: ACL_VARIABLE_TOK ACL_VARIABLE_TOK
+ {
+ char tmp_str[255];
+
+ util_sprintf(tmp_str, "%s+%s", $<string>1, $<string>2);
+ free($<string>1);
+ free($<string>2);
+ acl_add_arg(curr_ip_dns_list, PERM_STRDUP(tmp_str));
+ }
+ ;
+
+dns_ip_spec_list_v2: dns_spec_v2
+ | ip_spec_v2
+ | dns_spec_v2 ',' dns_ip_spec_list_v2
+ | ip_spec_v2 ',' dns_ip_spec_list_v2
+ ;
+
+realm_definition_v2: '{' methods_list_v2 '}'
+ {
+ if ( ACL_ExprAddArg(NULL, curr_expr, "user") < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAddArg(NULL, curr_expr, "group") < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ ;
+
+method_v2: ACL_VARIABLE_TOK ACL_VARIABLE_TOK ';'
+ {
+ acl_string_lower($<string>1);
+ if (strcmp($<string>1, "database") == 0) {
+ free($<string>1);
+ free($<string>2);
+ } else {
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index($<string>1), $<string>1, $<string>2, NULL) < 0 ) {
+ }
+ free($<string>1);
+ }
+ }
+ | ACL_VARIABLE_TOK ACL_QSTRING_TOK ';'
+ {
+ acl_string_lower($<string>1);
+ if (strcmp($<string>1, "database") == 0) {
+ free($<string>1);
+ free($<string>2);
+ } else {
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index($<string>1), $<string>1, $<string>2, NULL) < 0 ) {
+ }
+ free($<string>1);
+ }
+ }
+ ;
+
+methods_list_v2: method_v2
+ | method_v2 methods_list_v2
+ ;
+
+/*
+ ************************************************************
+ * Parse version 3.0 ACL
+ ************************************************************
+ */
+
+start_acl_v3: acl_list
+ ;
+
+acl_list: acl
+ | acl_list acl
+ ;
+
+acl: named_acl ';' body_list
+ | named_acl ';'
+ ;
+
+named_acl: ACL_ACL_TOK ACL_VARIABLE_TOK
+ {
+ curr_acl = ACL_AclNew(NULL, $<string>2);
+ free($<string>2);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ yyerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ }
+ | ACL_ACL_TOK ACL_QSTRING_TOK
+ {
+ curr_acl = ACL_AclNew(NULL, $<string>2);
+ free($<string>2);
+ if ( ACL_ListAppend(NULL, curr_acl_list, curr_acl, 0) < 0 ) {
+ yyerror("Couldn't add ACL to list.");
+ return(-1);
+ }
+ }
+ ;
+
+body_list: body
+ | body body_list
+ ;
+
+body: authenticate_statement ';'
+ | authorization_statement ';'
+ | deny_statement ';'
+ ;
+
+deny_statement:
+ ACL_ABSOLUTE_TOK ACL_DENY_TOK ACL_WITH_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_RESPONSE) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ if ( ACL_ExprSetPFlags(NULL, curr_expr,
+ ACL_PFLAG_ABSOLUTE) < 0 ) {
+ yyerror("Could not set deny processing flags");
+ return(-1);
+ }
+ }
+ deny_common
+ | ACL_DENY_TOK ACL_WITH_TOK
+ {
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_RESPONSE) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ deny_common
+ ;
+
+deny_common: ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprSetDenyWith(NULL, curr_expr,
+ $<string>1, $<string>3) < 0 ) {
+ yyerror("ACL_ExprSetDenyWith() failed");
+ return(-1);
+ }
+ free($<string>1);
+ free($<string>3);
+ }
+ ;
+
+authenticate_statement: ACL_AUTHENTICATE_TOK
+ {
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_AUTH) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ curr_auth_info = PListCreate(NULL, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ if ( ACL_ExprAddAuthInfo(curr_expr, curr_auth_info) < 0 ) {
+ yyerror("Could not set authorization info");
+ return(-1);
+ }
+ }
+ '(' attribute_list ')' '{' parameter_list '}'
+ {
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ ;
+
+attribute_list: attribute
+ | attribute_list ',' attribute
+
+attribute: ACL_VARIABLE_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprAddArg(NULL, curr_expr, $<string>1) < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ free($<string>1);
+ }
+ ;
+
+parameter_list: parameter ';'
+ | parameter ';' parameter_list
+ ;
+
+parameter: ACL_VARIABLE_TOK ACL_EQ_TOK ACL_QSTRING_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index($<string>1), $<string>1, $<string>3, NULL) < 0 ) {
+ }
+ free($<string>1);
+ }
+ | ACL_VARIABLE_TOK ACL_EQ_TOK ACL_VARIABLE_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( PListInitProp(curr_auth_info,
+ ACL_Attr2Index($<string>1), $<string>1, $<string>3, NULL) < 0 ) {
+ }
+ free($<string>1);
+ }
+ ;
+
+authorization_statement: ACL_ALLOW_TOK
+ {
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_ALLOW) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(allow) failed");
+ return(-1);
+ }
+ }
+ auth_common_action
+ | ACL_DENY_TOK
+ {
+ pflags = 0;
+ curr_expr = ACL_ExprNew(ACL_EXPR_TYPE_DENY) ;
+ if ( curr_expr == NULL ) {
+ yyerror("ACL_ExprNew(deny) failed");
+ return(-1);
+ }
+ }
+ auth_common_action
+ ;
+
+auth_common_action:
+ {
+ if ( ACL_ExprAppend(NULL, curr_acl, curr_expr) < 0 ) {
+ yyerror("Could not add authorization");
+ return(-1);
+ }
+ }
+ auth_common
+ {
+ if ( ACL_ExprSetPFlags (NULL, curr_expr, pflags) < 0 ) {
+ yyerror("Could not set authorization processing flags");
+ return(-1);
+ }
+#ifdef DEBUG
+ if ( ACL_ExprDisplay(curr_expr) < 0 ) {
+ yyerror("ACL_ExprDisplay() failed");
+ return(-1);
+ }
+ printf("Parsed authorization.\n");
+#endif
+ }
+ ;
+
+auth_common: flag_list '(' args_list ')' expression
+ ;
+
+flag_list:
+ | ACL_ABSOLUTE_TOK
+ {
+ pflags = ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_ABSOLUTE_TOK content_static
+ {
+ pflags = ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_CONTENT_TOK
+ {
+ pflags = ACL_PFLAG_CONTENT;
+ }
+ | ACL_CONTENT_TOK absolute_static
+ {
+ pflags = ACL_PFLAG_CONTENT;
+ }
+ | ACL_TERMINAL_TOK
+ {
+ pflags = ACL_PFLAG_TERMINAL;
+ }
+ | ACL_TERMINAL_TOK content_absolute
+ {
+ pflags = ACL_PFLAG_TERMINAL;
+ }
+ ;
+
+content_absolute: ACL_CONTENT_TOK
+ {
+ pflags |= ACL_PFLAG_CONTENT;
+ }
+ | ACL_ABSOLUTE_TOK
+ {
+ pflags |= ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_CONTENT_TOK ACL_ABSOLUTE_TOK
+ {
+ pflags |= ACL_PFLAG_ABSOLUTE | ACL_PFLAG_CONTENT;
+ }
+ | ACL_ABSOLUTE_TOK ACL_CONTENT_TOK
+ {
+ pflags |= ACL_PFLAG_ABSOLUTE | ACL_PFLAG_CONTENT;
+ }
+ ;
+
+content_static: ACL_CONTENT_TOK
+ {
+ pflags |= ACL_PFLAG_CONTENT;
+ }
+ | ACL_TERMINAL_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL;
+ }
+ | ACL_CONTENT_TOK ACL_TERMINAL_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_CONTENT;
+ }
+ | ACL_TERMINAL_TOK ACL_CONTENT_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_CONTENT;
+ }
+ ;
+
+absolute_static: ACL_ABSOLUTE_TOK
+ {
+ pflags |= ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_TERMINAL_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL;
+ }
+ | ACL_ABSOLUTE_TOK ACL_TERMINAL_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_ABSOLUTE;
+ }
+ | ACL_TERMINAL_TOK ACL_ABSOLUTE_TOK
+ {
+ pflags |= ACL_PFLAG_TERMINAL | ACL_PFLAG_ABSOLUTE;
+ }
+ ;
+
+args_list: arg
+ | args_list ',' arg
+ ;
+
+arg: ACL_VARIABLE_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprAddArg(NULL, curr_expr, $<string>1) < 0 ) {
+ yyerror("ACL_ExprAddArg() failed");
+ return(-1);
+ }
+ free( $<string>1 );
+ }
+ ;
+
+expression: factor
+ | factor ACL_AND_TOK expression
+ {
+ if ( ACL_ExprAnd(NULL, curr_expr) < 0 ) {
+ yyerror("ACL_ExprAnd() failed");
+ return(-1);
+ }
+ }
+ | factor ACL_OR_TOK expression
+ {
+ if ( ACL_ExprOr(NULL, curr_expr) < 0 ) {
+ yyerror("ACL_ExprOr() failed");
+ return(-1);
+ }
+ }
+ ;
+
+factor: base_expr
+ | '(' expression ')'
+ | ACL_NOT_TOK factor
+ {
+ if ( ACL_ExprNot(NULL, curr_expr) < 0 ) {
+ yyerror("ACL_ExprNot() failed");
+ return(-1);
+ }
+ }
+ ;
+
+base_expr: ACL_VARIABLE_TOK relop ACL_QSTRING_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprTerm(NULL, curr_expr,
+ $<string>1, (CmpOp_t) $<ival>2, $<string>3) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ free($<string>1);
+ free($<string>3);
+ return(-1);
+ }
+ free($<string>1);
+ free($<string>3);
+ }
+ | ACL_VARIABLE_TOK relop ACL_VARIABLE_TOK
+ {
+ acl_string_lower($<string>1);
+ if ( ACL_ExprTerm(NULL, curr_expr,
+ $<string>1, (CmpOp_t) $<ival>2, $<string>3) < 0 ) {
+ yyerror("ACL_ExprTerm() failed");
+ free($<string>1);
+ free($<string>3);
+ return(-1);
+ }
+ free($<string>1);
+ free($<string>3);
+ }
+ ;
+
+relop: ACL_EQ_TOK
+ | ACL_GE_TOK
+ | ACL_GT_TOK
+ | ACL_LT_TOK
+ | ACL_LE_TOK
+ | ACL_NE_TOK
+ ;
+%%
diff --git a/lib/libaccess/acltools.cpp b/lib/libaccess/acltools.cpp
new file mode 100644
index 00000000..1283147e
--- /dev/null
+++ b/lib/libaccess/acltools.cpp
@@ -0,0 +1,3457 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Tools to build and maintain access control lists.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#define ALLOCATE_ATTR_TABLE 1 /* Include the table of PList names */
+
+#include <netsite.h>
+#include <base/plist.h>
+#include <base/util.h>
+#include <base/crit.h>
+#include <base/file.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/aclerror.h>
+#include <libaccess/symbols.h>
+#include <libaccess/aclstruct.h>
+#include <libaccess/las.h>
+
+#include "aclscan.h"
+#include "parse.h"
+#include "oneeval.h"
+
+#include <libaccess/authdb.h>
+
+static CRITICAL acl_parse_crit = NULL;
+
+/*
+ * Allocate a new ACL handle
+ *
+ * This function creates a new ACL structure that will be used for
+ * access control information.
+ *
+ * Input:
+ * tag Specifies an identifier name for the new ACL, or
+ * it may be NULL when no name is required.
+ * Returns:
+ * A new ACL structure.
+ */
+
+NSAPI_PUBLIC ACLHandle_t *
+ACL_AclNew(NSErr_t *errp, char *tag )
+{
+ACLHandle_t *handle;
+
+ handle = ( ACLHandle_t * ) PERM_CALLOC ( 1 * sizeof (ACLHandle_t) );
+ if ( handle && tag ) {
+ handle->tag = PERM_STRDUP( tag );
+ if ( handle->tag == NULL ) {
+ PERM_FREE(handle);
+ return(NULL);
+ }
+ }
+ return(handle);
+}
+
+/*
+ * Appends to a specified ACL
+ *
+ * This function appends a specified ACL to the end of a given ACL list.
+ *
+ * Input:
+ * errp The error stack
+ * flags should always be zero now
+ * acl_list target ACL list
+ * acl new acl
+ * Returns:
+ * < 0 failure
+ * > 0 The number of acl's in the current list
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprAppend( NSErr_t *errp, ACLHandle_t *acl,
+ ACLExprHandle_t *expr )
+{
+
+ if ( acl == NULL || expr == NULL )
+ return(ACLERRUNDEF);
+
+ expr->acl_tag = acl->tag;
+
+ if ( expr->expr_type == ACL_EXPR_TYPE_AUTH ||
+ expr->expr_type == ACL_EXPR_TYPE_RESPONSE ) {
+ expr->expr_number = -1; // expr number isn't valid
+ } else {
+ acl->expr_count++;
+ expr->expr_number = acl->expr_count;
+ }
+
+ if ( acl->expr_list_head == NULL ) {
+ acl->expr_list_head = expr;
+ acl->expr_list_tail = expr;
+ } else {
+ acl->expr_list_tail->expr_next = expr;
+ acl->expr_list_tail = expr;
+ }
+
+ return(acl->expr_count);
+}
+
+/*
+ * Add authentication information to an ACL
+ *
+ * This function adds authentication data to an expr, based on
+ * the information provided by the parameters.
+ *
+ * Input:
+ * expr an authenticate expression to add database
+ * and method information to. ie, auth_info
+ * auth_info authentication information, eg database,
+ * method, etc.
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprAddAuthInfo( ACLExprHandle_t *expr, PList_t auth_info )
+{
+ if ( expr == NULL || auth_info == NULL )
+ return(ACLERRUNDEF);
+
+ expr->expr_auth = auth_info;
+
+ return(0);
+}
+
+/*
+ * Add authorization information to an ACL
+ *
+ * This function adds an authorization to a given ACL, based on the information
+ * provided by the parameters.
+ *
+ * Input:
+ * errp The error stack
+ * access_rights strings which identify the access rights to be
+ * controlled by the generated expr.
+ * flags processing flags
+ * allow non-zero to allow the indicated rights, or zero to
+ * deny them.
+ * attr_expr handle for an attribute expression, which may be
+ * obtained by calling ACL_ExprNew()
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_AddPermInfo( NSErr_t *errp, ACLHandle_t *acl,
+ char **access_rights,
+ PFlags_t flags,
+ int allow,
+ ACLExprHandle_t *expr,
+ char *tag )
+{
+ if ( acl == NULL || expr == NULL )
+ return(ACLERRUNDEF);
+
+ expr->expr_flags = flags;
+ expr->expr_argv = (char **) access_rights;
+ expr->expr_tag = PERM_STRDUP( tag );
+ if ( expr->expr_tag == NULL )
+ return(ACLERRNOMEM);
+ return(ACL_ExprAppend( errp, acl, expr ));
+}
+
+/*
+ * Add rights information to an expression
+ *
+ * This function adds a right to an authorization, based on the information
+ * provided by the parameters.
+ *
+ * Input:
+ * errp The error stack
+ * access_right strings which identify the access rights to be
+ * controlled by the generated expr.
+ * expr handle for an attribute expression, which may be
+ * obtained by calling ACL_ExprNew()
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprAddArg( NSErr_t *errp,
+ ACLExprHandle_t *expr,
+ char *arg )
+{
+
+ if ( expr == NULL )
+ return(ACLERRUNDEF);
+
+ if (expr->expr_argv == NULL)
+ expr->expr_argv = (char **) PERM_MALLOC( 2 * sizeof(char *) );
+ else
+ expr->expr_argv = (char **) PERM_REALLOC( expr->expr_argv,
+ (expr->expr_argc+2)
+ * sizeof(char *) );
+
+ if (expr->expr_argv == NULL)
+ return(ACLERRNOMEM);
+
+ expr->expr_argv[expr->expr_argc] = PERM_STRDUP( arg );
+ if (expr->expr_argv[expr->expr_argc] == NULL)
+ return(ACLERRNOMEM);
+ expr->expr_argc++;
+ expr->expr_argv[expr->expr_argc] = NULL;
+
+ return(0);
+
+}
+
+
+NSAPI_PUBLIC int
+ACL_ExprSetDenyWith( NSErr_t *errp, ACLExprHandle_t *expr, char *deny_type, char *deny_response)
+{
+int rv;
+
+ if ( expr->expr_argc == 0 ) {
+ if ( (rv = ACL_ExprAddArg(errp, expr, deny_type)) < 0 )
+ return(rv);
+ if ( (rv = ACL_ExprAddArg(errp, expr, deny_response)) < 0 )
+ return(rv);
+ } else if ( expr->expr_argc == 2 ) {
+ if ( deny_type ) {
+ if ( expr->expr_argv[0] )
+ PERM_FREE(expr->expr_argv[0]);
+ expr->expr_argv[0] = PERM_STRDUP(deny_type);
+ if ( expr->expr_argv[0] == NULL )
+ return(ACLERRNOMEM);
+ }
+ if ( deny_response ) {
+ if ( expr->expr_argv[1] )
+ PERM_FREE(expr->expr_argv[1]);
+ expr->expr_argv[1] = PERM_STRDUP(deny_response);
+ if ( expr->expr_argv[0] == NULL )
+ return(ACLERRNOMEM);
+ }
+ } else {
+ return(ACLERRINTERNAL);
+ }
+ return(0);
+}
+
+NSAPI_PUBLIC int
+ACL_ExprGetDenyWith( NSErr_t *errp, ACLExprHandle_t *expr, char **deny_type,
+char **deny_response)
+{
+ if ( expr->expr_argc == 2 ) {
+ *deny_type = expr->expr_argv[0];
+ *deny_response = expr->expr_argv[1];
+ return(0);
+ } else {
+ return(ACLERRUNDEF);
+ }
+}
+
+/*
+ * Function to set the authorization statement processing flags.
+ *
+ * Input:
+ * errp The error reporting stack
+ * expr The authoization statement
+ * flags The flags to set
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprSetPFlags( NSErr_t *errp,
+ ACLExprHandle_t *expr,
+ PFlags_t flags )
+{
+ if ( expr == NULL )
+ return(ACLERRUNDEF);
+
+ expr->expr_flags |= flags;
+ return(0);
+}
+
+/*
+ * Function to clear the authorization statement processing flags.
+ *
+ * Input:
+ * errp The error reporting stack
+ * expr The authoization statement
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprClearPFlags( NSErr_t *errp,
+ ACLExprHandle_t *expr )
+{
+ if ( expr == NULL )
+ return(ACLERRUNDEF);
+
+ expr->expr_flags = 0;
+ return(0);
+}
+
+/*
+ * Allocate a new expression handle.
+ *
+ * Returns:
+ * NULL If handle could not be allocated.
+ * pointer New handle.
+ */
+
+NSAPI_PUBLIC ACLExprHandle_t *
+ACL_ExprNew( const ACLExprType_t expr_type )
+{
+ACLExprHandle_t *expr_handle;
+
+ expr_handle = ( ACLExprHandle_t * ) PERM_CALLOC ( sizeof(ACLExprHandle_t) );
+ if ( expr_handle ) {
+ expr_handle->expr_arry = ( ACLExprEntry_t * )
+ PERM_CALLOC( ACL_TERM_BSIZE * sizeof(ACLExprEntry_t) ) ;
+ expr_handle->expr_arry_size = ACL_TERM_BSIZE;
+ expr_handle->expr_type = expr_type;
+
+ expr_handle->expr_raw = ( ACLExprRaw_t * )
+ PERM_CALLOC( ACL_TERM_BSIZE * sizeof(ACLExprRaw_t) ) ;
+ expr_handle->expr_raw_size = ACL_TERM_BSIZE;
+
+ }
+ return(expr_handle);
+}
+
+
+/*
+ * LOCAL FUNCTION
+ *
+ * displays the ASCII equivalent index value.
+ */
+
+static char *
+acl_index_string ( int value, char *buffer )
+{
+
+ if ( value == ACL_TRUE_IDX ) {
+ strcpy( buffer, "TRUE" );
+ return( buffer );
+ }
+
+ if ( value == ACL_FALSE_IDX ) {
+ strcpy( buffer, "FALSE" );
+ return( buffer );
+ }
+
+ sprintf( buffer, "goto %d", value );
+ return( buffer );
+}
+
+
+/*
+ * LOCAL FUNCTION
+ *
+ * displays ASCII equivalent of CmpOp_t
+ */
+
+static char *
+acl_comp_string( CmpOp_t cmp )
+{
+ switch (cmp) {
+ case CMP_OP_EQ:
+ return("=");
+ case CMP_OP_NE:
+ return("!=");
+ case CMP_OP_GT:
+ return(">");
+ case CMP_OP_LT:
+ return("<");
+ case CMP_OP_GE:
+ return(">=");
+ case CMP_OP_LE:
+ return("<=");
+ default:
+ return("unknown op");
+ }
+}
+
+/*
+ * Add a term to the specified attribute expression.
+ *
+ * Input:
+ * errp Error stack
+ * acl_expr Target expression handle
+ * attr_name Term Attribute name
+ * cmp Comparison operator
+ * attr_pattern Pattern for comparison
+ * Ouput:
+ * acl_expr New term added
+ * Returns:
+ * 0 Success
+ * < 0 Error
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprTerm( NSErr_t *errp, ACLExprHandle_t *acl_expr,
+ char *attr_name,
+ CmpOp_t cmp,
+ char *attr_pattern )
+{
+ACLExprEntry_t *expr;
+ACLExprRaw_t *raw_expr;
+
+ if ( acl_expr == NULL || acl_expr->expr_arry == NULL )
+ return(ACLERRUNDEF);
+
+ if ( acl_expr->expr_term_index >= acl_expr->expr_arry_size ) {
+ acl_expr->expr_arry = ( ACLExprEntry_t *)
+ PERM_REALLOC ( acl_expr->expr_arry,
+ (acl_expr->expr_arry_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprEntry_t));
+ if ( acl_expr->expr_arry == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_arry_size += ACL_TERM_BSIZE;
+ }
+
+ expr = &acl_expr->expr_arry[acl_expr->expr_term_index];
+ acl_expr->expr_term_index++;
+
+ expr->attr_name = PERM_STRDUP(attr_name);
+ if ( expr->attr_name == NULL )
+ return(ACLERRNOMEM);
+ expr->comparator = cmp;
+ expr->attr_pattern = PERM_STRDUP(attr_pattern);
+ if ( expr->attr_pattern == NULL )
+ return(ACLERRNOMEM);
+ expr->true_idx = ACL_TRUE_IDX;
+ expr->false_idx = ACL_FALSE_IDX;
+ expr->start_flag = 1;
+ expr->las_cookie = 0;
+ expr->las_eval_func = 0;
+
+ if ( acl_expr->expr_raw_index >= acl_expr->expr_raw_size ) {
+ acl_expr->expr_raw = ( ACLExprRaw_t *)
+ PERM_REALLOC ( acl_expr->expr_raw,
+ (acl_expr->expr_raw_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprRaw_t));
+ if ( acl_expr->expr_raw == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_raw_size += ACL_TERM_BSIZE;
+ }
+
+ raw_expr = &acl_expr->expr_raw[acl_expr->expr_raw_index];
+ acl_expr->expr_raw_index++;
+
+ raw_expr->attr_name = expr->attr_name;
+ raw_expr->comparator = cmp;
+ raw_expr->attr_pattern = expr->attr_pattern;
+ raw_expr->logical = (ACLExprOp_t)0;
+
+#ifdef DEBUG_LEVEL_2
+ printf ( "%d: %s %s %s, t=%d, f=%d\n",
+ acl_expr->expr_term_index - 1,
+ expr->attr_name,
+ acl_comp_string( expr->comparator ),
+ expr->attr_pattern,
+ expr->true_idx,
+ expr->false_idx );
+#endif
+
+ return(0);
+}
+
+/*
+ * Negate the previous term or subexpression.
+ *
+ * Input:
+ * errp The error stack
+ * acl_expr The expression to negate
+ * Ouput
+ * acl_expr The negated expression
+ * Returns:
+ * 0 Success
+ * < 0 Failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprNot( NSErr_t *errp, ACLExprHandle_t *acl_expr )
+{
+int idx;
+int ii;
+int expr_one = 0;
+ACLExprRaw_t *raw_expr;
+
+ if ( acl_expr == NULL )
+ return(ACLERRUNDEF);
+
+
+ if ( acl_expr->expr_raw_index >= acl_expr->expr_raw_size ) {
+ acl_expr->expr_raw = ( ACLExprRaw_t *)
+ PERM_REALLOC ( acl_expr->expr_raw,
+ (acl_expr->expr_raw_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprRaw_t));
+ if ( acl_expr->expr_raw == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_raw_size += ACL_TERM_BSIZE;
+ }
+
+ raw_expr = &acl_expr->expr_raw[acl_expr->expr_raw_index];
+ acl_expr->expr_raw_index++;
+
+ raw_expr->logical = ACL_EXPR_OP_NOT;
+ raw_expr->attr_name = NULL;
+
+ /* Find the last expression */
+ idx = acl_expr->expr_term_index - 1;
+ for ( ii = idx; ii >= 0; ii-- ) {
+ if ( acl_expr->expr_arry[ii].start_flag ) {
+ expr_one = ii;
+ break;
+ }
+ }
+
+#ifdef DEBUG_LEVEL_2
+ printf("not, start index=%d\n", expr_one);
+#endif
+
+
+ /*
+ * The intent here is negate the last expression by
+ * modifying the true and false links.
+ */
+
+ for ( ii = expr_one; ii < acl_expr->expr_term_index; ii++ ) {
+ if ( acl_expr->expr_arry[ii].true_idx == ACL_TRUE_IDX )
+ acl_expr->expr_arry[ii].true_idx = ACL_FALSE_IDX;
+ else if ( acl_expr->expr_arry[ii].true_idx == ACL_FALSE_IDX )
+ acl_expr->expr_arry[ii].true_idx = ACL_TRUE_IDX;
+
+ if ( acl_expr->expr_arry[ii].false_idx == ACL_TRUE_IDX )
+ acl_expr->expr_arry[ii].false_idx = ACL_FALSE_IDX;
+ else if ( acl_expr->expr_arry[ii].false_idx == ACL_FALSE_IDX )
+ acl_expr->expr_arry[ii].false_idx = ACL_TRUE_IDX;
+
+ }
+
+ return(0) ;
+}
+
+/*
+ * Logical 'and' the previous two terms or subexpressions.
+ *
+ * Input:
+ * errp The error stack
+ * acl_expr The terms or subexpressions
+ * Output:
+ * acl_expr The expression after logical 'and'
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprAnd( NSErr_t *errp, ACLExprHandle_t *acl_expr )
+{
+int idx;
+int ii;
+int expr_one = ACL_FALSE_IDX;
+int expr_two = ACL_FALSE_IDX;
+ACLExprRaw_t *raw_expr;
+
+ if ( acl_expr == NULL )
+ return(ACLERRUNDEF);
+
+ if ( acl_expr->expr_raw_index >= acl_expr->expr_raw_size ) {
+ acl_expr->expr_raw = ( ACLExprRaw_t *)
+ PERM_REALLOC ( acl_expr->expr_raw,
+ (acl_expr->expr_raw_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprRaw_t) );
+ if ( acl_expr->expr_raw == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_raw_size += ACL_TERM_BSIZE;
+ }
+
+ raw_expr = &acl_expr->expr_raw[acl_expr->expr_raw_index];
+ acl_expr->expr_raw_index++;
+
+ raw_expr->logical = ACL_EXPR_OP_AND;
+ raw_expr->attr_name = NULL;
+
+ /* Find the last two expressions */
+ idx = acl_expr->expr_term_index - 1;
+ for ( ii = idx; ii >= 0; ii-- ) {
+ if ( acl_expr->expr_arry[ii].start_flag ) {
+ if ( expr_two == ACL_FALSE_IDX )
+ expr_two = ii;
+ else if ( expr_one == ACL_FALSE_IDX ) {
+ expr_one = ii;
+ break;
+ }
+ }
+ }
+
+#ifdef DEBUG_LEVEL_2
+ printf("and, index=%d, first expr=%d, second expr=%d\n", idx, expr_one, expr_two);
+#endif
+
+ for ( ii = expr_one; ii < expr_two; ii++) {
+ if ( acl_expr->expr_arry[ii].true_idx == ACL_TRUE_IDX )
+ acl_expr->expr_arry[ii].true_idx = expr_two;
+ if ( acl_expr->expr_arry[ii].false_idx == ACL_TRUE_IDX )
+ acl_expr->expr_arry[ii].false_idx = expr_two;
+ }
+
+ acl_expr->expr_arry[expr_two].start_flag = 0;
+ return(0);
+}
+
+/*
+ * Logical 'or' the previous two terms or subexpressions.
+ *
+ * Input:
+ * errp The error stack
+ * acl_expr The terms or subexpressions
+ * Output:
+ * acl_expr The expression after logical 'or'
+ */
+
+NSAPI_PUBLIC int
+ACL_ExprOr( NSErr_t *errp, ACLExprHandle_t *acl_expr )
+{
+int idx;
+int ii;
+int expr_one = ACL_FALSE_IDX;
+int expr_two = ACL_FALSE_IDX;
+ACLExprRaw_t *raw_expr;
+
+ if ( acl_expr == NULL )
+ return(ACLERRUNDEF);
+
+ if ( acl_expr->expr_raw_index >= acl_expr->expr_raw_size ) {
+ acl_expr->expr_raw = ( ACLExprRaw_t *)
+ PERM_REALLOC ( acl_expr->expr_raw,
+ (acl_expr->expr_raw_size + ACL_TERM_BSIZE)
+ * sizeof(ACLExprRaw_t) );
+ if ( acl_expr->expr_raw == NULL )
+ return(ACLERRNOMEM);
+ acl_expr->expr_raw_size += ACL_TERM_BSIZE;
+ }
+
+ raw_expr = &acl_expr->expr_raw[acl_expr->expr_raw_index];
+ acl_expr->expr_raw_index++;
+
+ raw_expr->logical = ACL_EXPR_OP_OR;
+ raw_expr->attr_name = NULL;
+
+ /* Find the last two expressions */
+ idx = acl_expr->expr_term_index - 1;
+ for ( ii = idx; ii >= 0; ii-- ) {
+ if ( acl_expr->expr_arry[ii].start_flag ) {
+ if ( expr_two == ACL_FALSE_IDX )
+ expr_two = ii;
+ else if ( expr_one == ACL_FALSE_IDX ) {
+ expr_one = ii;
+ break;
+ }
+ }
+ }
+
+#ifdef DEBUG_LEVEL_2
+ printf("or, index=%d, first expr=%d, second expr=%d\n", idx, expr_one, expr_two);
+#endif
+
+ for ( ii = expr_one; ii < expr_two; ii++) {
+ if ( acl_expr->expr_arry[ii].true_idx == ACL_FALSE_IDX )
+ acl_expr->expr_arry[ii].true_idx = expr_two;
+ if ( acl_expr->expr_arry[ii].false_idx == ACL_FALSE_IDX )
+ acl_expr->expr_arry[ii].false_idx = expr_two;
+ }
+ acl_expr->expr_arry[expr_two].start_flag = 0;
+
+ return(0);
+}
+
+/*
+ * INTERNAL FUNCTION (GLOBAL)
+ *
+ * Write an expression array to standard output. This
+ * is only useful debugging.
+ */
+
+int
+ACL_ExprDisplay( ACLExprHandle_t *acl_expr )
+{
+int ii;
+char buffer[256];
+
+ if ( acl_expr == NULL )
+ return(0);
+
+ for ( ii = 0; ii < acl_expr->expr_term_index; ii++ ) {
+ printf ("%d: if ( %s %s %s ) ",
+ ii,
+ acl_expr->expr_arry[ii].attr_name,
+ acl_comp_string( acl_expr->expr_arry[ii].comparator ),
+ acl_expr->expr_arry[ii].attr_pattern );
+
+ printf("%s ", acl_index_string(acl_expr->expr_arry[ii].true_idx, buffer));
+ printf("else %s\n",
+ acl_index_string(acl_expr->expr_arry[ii].false_idx, buffer) );
+ }
+
+ return(0);
+}
+
+/*
+ * Creates a handle for a new list of ACLs
+ *
+ * This function creates a new list of ACLs. The list is initially empty
+ * and can be added to by ACL_ListAppend(). A resource manager would use
+ * these functions to build up a list of all the ACLs applicable to a
+ * particular resource access.
+ *
+ * Input:
+ * Returns:
+ * NULL failure, otherwise returns a new
+ * ACLListHandle
+ */
+
+NSAPI_PUBLIC ACLListHandle_t *
+ACL_ListNew(NSErr_t *errp)
+{
+ACLListHandle_t *handle;
+
+ handle = ( ACLListHandle_t * ) PERM_CALLOC ( sizeof(ACLListHandle_t) );
+ handle->ref_count = 1;
+ return(handle);
+}
+
+/*
+ * Allocates a handle for an ACL wrapper
+ *
+ * This wrapper is just used for ACL list creation. It's a way of
+ * linking ACLs into a list. This is an internal function.
+ */
+
+static ACLWrapper_t *
+acl_wrapper_new(void)
+{
+ACLWrapper_t *handle;
+
+ handle = ( ACLWrapper_t * ) PERM_CALLOC ( sizeof(ACLWrapper_t) );
+ return(handle);
+}
+
+/*
+ * Description
+ *
+ * This function destroys an entry a symbol table entry for an
+ * ACL.
+ *
+ * Arguments:
+ *
+ * sym - pointer to Symbol_t for an ACL entry
+ * argp - unused (must be zero)
+ *
+ * Returns:
+ *
+ * The return value is SYMENUMREMOVE.
+ */
+
+static
+int acl_hash_entry_destroy(Symbol_t * sym, void * argp)
+{
+ if (sym != 0) {
+
+ /* Free the acl name string if any */
+ if (sym->sym_name != 0) {
+ PERM_FREE(sym->sym_name);
+ }
+
+ /* Free the Symbol_t structure */
+ PERM_FREE(sym);
+ }
+
+ /* Indicate that the symbol table entry should be removed */
+ return SYMENUMREMOVE;
+}
+
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Create a new symbol with the sym_name equal to the
+ * acl->tag value. Attaches the acl to the sym_data
+ * pointer.
+ */
+
+static Symbol_t *
+acl_sym_new(ACLHandle_t *acl)
+{
+ Symbol_t *sym;
+ /* It's not there, so add it */
+ sym = (Symbol_t *) PERM_MALLOC(sizeof(Symbol_t));
+ if ( sym == NULL )
+ return(NULL);
+
+ sym->sym_name = PERM_STRDUP(acl->tag);
+ if ( sym->sym_name == NULL ) {
+ PERM_FREE(sym);
+ return(NULL);
+ }
+
+ sym->sym_type = ACLSYMACL;
+ sym->sym_data = (void *) acl;
+ return(sym);
+
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Add a acl symbol to an acl_list's symbol table.
+ *
+ * Each acl list has a symbol table. the symbol table
+ * is a quick qay to reference named acl's
+ */
+
+static int
+acl_sym_add(ACLListHandle_t *acl_list, ACLHandle_t *acl)
+{
+Symbol_t *sym;
+int rv;
+
+ if ( acl->tag == NULL )
+ return(ACLERRUNDEF);
+
+ rv = symTableFindSym(acl_list->acl_sym_table,
+ acl->tag,
+ ACLSYMACL,
+ (void **)&sym);
+ if ( rv == SYMERRNOSYM ) {
+ sym = acl_sym_new(acl);
+ if ( sym )
+ rv = symTableAddSym(acl_list->acl_sym_table, sym, (void *)sym);
+ }
+
+ if ( sym == NULL || rv < 0 )
+ return(ACLERRUNDEF);
+
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Destroy an acl_list's symbol table and all memory referenced
+ * by the symbol table. This does not destroy an acl_list.
+ */
+
+static void
+acl_symtab_destroy(ACLListHandle_t *acl_list)
+{
+ /* Destroy each entry in the symbol table */
+ symTableEnumerate(acl_list->acl_sym_table, 0, acl_hash_entry_destroy);
+ /* Destory the hash table itself */
+ symTableDestroy(acl_list->acl_sym_table, 0);
+ acl_list->acl_sym_table = NULL;
+ return;
+}
+
+
+/*
+ * Appends to a specified ACL
+ *
+ * This function appends a specified ACL to the end of a given ACL list.
+ *
+ * Input:
+ * errp The error stack
+ * flags should always be zero now
+ * acl_list target ACL list
+ * acl new acl
+ * Returns:
+ * > 0 The number of acl's in the current list
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ListAppend( NSErr_t *errp, ACLListHandle_t *acl_list, ACLHandle_t *acl,
+ int flags )
+{
+ ACLWrapper_t *wrapper;
+ ACLHandle_t *tmp_acl;
+
+ if ( acl_list == NULL || acl == NULL )
+ return(ACLERRUNDEF);
+
+ if ( acl_list->acl_sym_table == NULL &&
+ acl_list->acl_count == ACL_TABLE_THRESHOLD ) {
+
+ /*
+ * The symbol table isn't really critical so we don't log
+ * an error if its creation fails.
+ */
+
+ symTableNew(&acl_list->acl_sym_table);
+ if ( acl_list->acl_sym_table ) {
+ for (wrapper = acl_list->acl_list_head; wrapper;
+ wrapper = wrapper->wrap_next ) {
+ tmp_acl = wrapper->acl;
+ if ( acl_sym_add(acl_list, tmp_acl) ) {
+ acl_symtab_destroy(acl_list);
+ break;
+ }
+ }
+ }
+ }
+
+ wrapper = acl_wrapper_new();
+ if ( wrapper == NULL )
+ return(ACLERRNOMEM);
+
+ wrapper->acl = acl;
+
+ if ( acl_list->acl_list_head == NULL ) {
+ acl_list->acl_list_head = wrapper;
+ acl_list->acl_list_tail = wrapper;
+ } else {
+ acl_list->acl_list_tail->wrap_next = wrapper;
+ acl_list->acl_list_tail = wrapper;
+ }
+
+ acl->ref_count++;
+
+ acl_list->acl_count++;
+
+
+ if ( acl_list->acl_sym_table ) {
+ /*
+ * If we fail to insert the ACL then we
+ * might as well destroy this hash table since it is
+ * useless.
+ */
+ if ( acl_sym_add(acl_list, acl) ) {
+ acl_symtab_destroy(acl_list);
+ }
+ }
+
+
+ return(acl_list->acl_count);
+}
+
+/*
+ * Concatenates two ACL lists
+ *
+ * Attaches all ACLs in acl_list2 to the end of acl_list1. acl_list2
+ * is left unchanged.
+ *
+ * Input:
+ * errp pointer to the error stack
+ * acl_list1 target ACL list
+ * acl_list2 source ACL list
+ * Output:
+ * acl_list1 list contains the concatenation of acl_list1
+ * and acl_list2.
+ * Returns:
+ * > 0 Number of ACLs in acl_list1 after concat
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ListConcat( NSErr_t *errp, ACLListHandle_t *acl_list1,
+ ACLListHandle_t *acl_list2, int flags )
+{
+ACLWrapper_t *wrapper;
+int rv;
+
+ if ( acl_list1 == NULL || acl_list2 == NULL )
+ return(ACLERRUNDEF);
+
+ for ( wrapper = acl_list2->acl_list_head;
+ wrapper != NULL; wrapper = wrapper->wrap_next )
+ if ( (rv = ACL_ListAppend ( errp, acl_list1, wrapper->acl, 0 )) < 0 )
+ return(rv);
+
+ return(acl_list1->acl_count);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Free up memory associated with and ACLExprEntry. Probably
+ * only useful internally since we aren't exporting
+ * this structure.
+ */
+
+static void
+ACL_ExprEntryDestroy( ACLExprEntry_t *entry )
+{
+ LASFlushFunc_t flushp;
+
+ if ( entry == NULL )
+ return;
+
+ if ( entry->las_cookie )
+/* freeLAS(NULL, entry->attr_name, &entry->las_cookie); */
+ {
+ ACL_LasFindFlush( NULL, entry->attr_name, &flushp );
+ if ( flushp )
+ ( *flushp )( &entry->las_cookie );
+ }
+
+ if ( entry->attr_name )
+ PERM_FREE( entry->attr_name );
+
+ if ( entry->attr_pattern )
+ PERM_FREE( entry->attr_pattern );
+
+ return;
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * This function is used to free all the pvalue memory
+ * in a plist.
+ */
+
+static void
+acl_expr_auth_destroy(char *pname, const void *pvalue, void *user_data)
+{
+ PERM_FREE((char *) pvalue);
+ return;
+}
+
+/*
+ * Free up memory associated with and ACLExprHandle.
+ *
+ * Input:
+ * expr expression handle to free up
+ */
+
+NSAPI_PUBLIC void
+ACL_ExprDestroy( ACLExprHandle_t *expr )
+{
+int ii;
+
+ if ( expr == NULL )
+ return;
+
+ if ( expr->expr_tag )
+ PERM_FREE( expr->expr_tag );
+
+ if ( expr->expr_argv ) {
+ for ( ii = 0; ii < expr->expr_argc; ii++ )
+ if ( expr->expr_argv[ii] )
+ PERM_FREE( expr->expr_argv[ii] );
+ PERM_FREE( expr->expr_argv );
+ }
+
+ for ( ii = 0; ii < expr->expr_term_index; ii++ )
+ ACL_ExprEntryDestroy( &expr->expr_arry[ii] );
+
+ if ( expr->expr_auth ) {
+ PListEnumerate(expr->expr_auth, acl_expr_auth_destroy, NULL);
+ PListDestroy(expr->expr_auth);
+ }
+
+ PERM_FREE( expr->expr_arry );
+ PERM_FREE( expr->expr_raw );
+
+ PERM_FREE( expr );
+
+ return;
+}
+
+/*
+ * Free up memory associated with and ACLHandle.
+ *
+ * Input:
+ * acl target acl
+ */
+
+NSAPI_PUBLIC void
+ACL_AclDestroy(NSErr_t *errp, ACLHandle_t *acl )
+{
+ACLExprHandle_t *handle;
+ACLExprHandle_t *tmp;
+
+ if ( acl == NULL )
+ return;
+
+ acl->ref_count--;
+
+ if ( acl->ref_count )
+ return;
+
+ if ( acl->tag )
+ PERM_FREE( acl->tag );
+
+ if ( acl->las_name )
+ PERM_FREE( acl->las_name );
+
+ if ( acl->attr_name )
+ PERM_FREE( acl->attr_name );
+
+ handle = acl->expr_list_head;
+ while ( handle ) {
+ tmp = handle;
+ handle = handle->expr_next;
+ ACL_ExprDestroy( tmp );
+ }
+
+ PERM_FREE(acl);
+
+ return;
+}
+
+/*
+ * Destorys a input ACL List
+ *
+ * Input:
+ * acl_list target list
+ * Output:
+ * none target list is freed
+ */
+
+NSAPI_PUBLIC void
+ACL_ListDestroy(NSErr_t *errp, ACLListHandle_t *acl_list )
+{
+ ACLWrapper_t *wrapper;
+ ACLWrapper_t *tmp_wrapper;
+ ACLHandle_t *tmp_acl;
+
+
+ if ( acl_list == NULL )
+ return;
+
+ if ( acl_list->acl_sym_table ) {
+ /* Destroy each entry in the symbol table */
+ symTableEnumerate(acl_list->acl_sym_table, 0, acl_hash_entry_destroy);
+ /* Destory the hash table itself */
+ symTableDestroy(acl_list->acl_sym_table, 0);
+ }
+
+ ACL_EvalDestroyContext( (ACLListCache_t *)acl_list->cache );
+
+ wrapper = acl_list->acl_list_head;
+
+ while ( wrapper ) {
+ tmp_acl = wrapper->acl;
+ tmp_wrapper = wrapper;
+ wrapper = wrapper->wrap_next;
+ PERM_FREE( tmp_wrapper );
+ ACL_AclDestroy(errp, tmp_acl );
+ }
+
+ PERM_FREE( acl_list );
+
+ return;
+}
+
+/*
+ * FUNCTION: ACL_ListGetFirst
+ *
+ * DESCRIPTION:
+ *
+ * This function is used to start an enumeration of an
+ * ACLListHandle_t. It returns an ACLHandle_t* for the first
+ * ACL on the list, and initializes a handle supplied by the
+ * caller, which is used to track the current position in the
+ * enumeration. This function is normally used in a loop
+ * such as:
+ *
+ * ACLListHandle_t *acl_list = <some ACL list>;
+ * ACLHandle_t *cur_acl;
+ * ACLListEnum_t acl_enum;
+ *
+ * for (cur_acl = ACL_ListGetFirst(acl_list, &acl_enum);
+ * cur_acl != 0;
+ * cur_acl = ACL_ListGetNext(acl_list, &acl_enum)) {
+ * ...
+ * }
+ *
+ * The caller should guarantee that no ACLs are added or removed
+ * from the ACL list during the enumeration.
+ *
+ * ARGUMENTS:
+ *
+ * acl_list - handle for the ACL list
+ * acl_enum - pointer to uninitialized enumeration handle
+ *
+ * RETURNS:
+ *
+ * As described above. If the acl_list argument is null, or the
+ * referenced ACL list is empty, the return value is null.
+ */
+
+NSAPI_PUBLIC ACLHandle_t *
+ACL_ListGetFirst(ACLListHandle_t *acl_list, ACLListEnum_t *acl_enum)
+{
+ ACLWrapper_t *wrapper;
+ ACLHandle_t *acl = 0;
+
+ *acl_enum = 0;
+
+ if (acl_list) {
+
+ wrapper = acl_list->acl_list_head;
+ *acl_enum = (ACLListEnum_t)wrapper;
+
+ if (wrapper) {
+ acl = wrapper->acl;
+ }
+ }
+
+ return acl;
+}
+
+NSAPI_PUBLIC ACLHandle_t *
+ACL_ListGetNext(ACLListHandle_t *acl_list, ACLListEnum_t *acl_enum)
+{
+ ACLWrapper_t *wrapper = (ACLWrapper_t *)(*acl_enum);
+ ACLHandle_t *acl = 0;
+
+ if (wrapper) {
+
+ wrapper = wrapper->wrap_next;
+ *acl_enum = (ACLListEnum_t)wrapper;
+
+ if (wrapper) acl = wrapper->acl;
+ }
+
+ return acl;
+}
+
+/*
+ * FUNCTION: ACL_AclGetTag
+ *
+ * DESCRIPTION:
+ *
+ * Returns the tag string associated with an ACL.
+ *
+ * ARGUMENTS:
+ *
+ * acl - handle for an ACL
+ *
+ * RETURNS:
+ *
+ * The return value is a pointer to the ACL tag string.
+ */
+
+NSAPI_PUBLIC const char *
+ACL_AclGetTag(ACLHandle_t *acl)
+{
+ return (acl) ? (const char *)(acl->tag) : 0;
+}
+
+/*
+ * Finds a named ACL in an input list.
+ *
+ * Input:
+ * acl_list a list of ACLs to search
+ * acl_name the name of the ACL to find
+ * flags e.g. ACL_CASE_INSENSITIVE
+ * Returns:
+ * NULL No ACL found
+ * acl A pointer to an ACL with named acl_name
+ */
+
+NSAPI_PUBLIC ACLHandle_t *
+ACL_ListFind (NSErr_t *errp, ACLListHandle_t *acl_list, char *acl_name, int flags )
+{
+ACLHandle_t *result = NULL;
+ACLWrapper_t *wrapper;
+Symbol_t *sym;
+
+ if ( acl_list == NULL || acl_name == NULL )
+ return( result );
+
+ /*
+ * right now the symbol table exists if there hasn't been
+ * any collisions based on using case insensitive names.
+ * if there are any collisions then the table will be
+ * deleted and we will look up using list search.
+ *
+ * we should probably create two hash tables, one for case
+ * sensitive lookups and the other for insensitive.
+ */
+ if ( acl_list->acl_sym_table ) {
+ if ( symTableFindSym(acl_list->acl_sym_table,
+ acl_name, ACLSYMACL, (void **) &sym) >= 0 ) {
+ result = (ACLHandle_t *) sym->sym_data;
+ if ( result && (flags & ACL_CASE_SENSITIVE) &&
+ strcmp(result->tag, acl_name) ) {
+ result = NULL; /* case doesn't match */
+ }
+ }
+ return( result );
+ }
+
+ if ( flags & ACL_CASE_INSENSITIVE ) {
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag &&
+ strcasecmp( wrapper->acl->tag, acl_name ) == 0 ) {
+ result = wrapper->acl;
+ break;
+ }
+ }
+ } else {
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag &&
+ strcmp( wrapper->acl->tag, acl_name ) == 0 ) {
+ result = wrapper->acl;
+ break;
+ }
+ }
+ }
+
+ return( result );
+}
+
+/*
+ * Function parses an input ACL file and resturns an
+ * ACLListHandle_t pointer that represents the entire
+ * file without the comments.
+ *
+ * Input:
+ * filename the name of the target ACL text file
+ * errp a pointer to an error stack
+ *
+ * Returns:
+ * NULL parse failed
+ *
+ */
+
+NSAPI_PUBLIC ACLListHandle_t *
+ACL_ParseFile( NSErr_t *errp, char *filename )
+{
+ACLListHandle_t *handle = NULL;
+int eid = 0;
+int rv = 0;
+char *errmsg;
+
+ ACL_InitAttr2Index();
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ if ( acl_InitScanner( errp, filename, NULL ) < 0 ) {
+ rv = ACLERROPEN;
+ eid = ACLERR1900;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ } else {
+
+ handle = ACL_ListNew(errp);
+ if ( handle == NULL ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else if ( acl_PushListHandle( handle ) < 0 ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else if ( acl_Parse() ) {
+ rv = ACLERRPARSE;
+ eid = ACLERR1780;
+ }
+
+ if ( acl_EndScanner() < 0 ) {
+ rv = ACLERROPEN;
+ eid = ACLERR1500;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ }
+
+ }
+
+ if ( rv || eid ) {
+ ACL_ListDestroy(errp, handle);
+ handle = NULL;
+ }
+
+ crit_exit( acl_parse_crit );
+ return(handle);
+
+}
+
+/*
+ * Function parses an input ACL string and returns an
+ * ACLListHandle_t pointer that represents the entire
+ * file without the comments.
+ *
+ * Input:
+ * buffer the target ACL buffer
+ * errp a pointer to an error stack
+ *
+ * Returns:
+ * NULL parse failed
+ *
+ */
+
+NSAPI_PUBLIC ACLListHandle_t *
+ACL_ParseString( NSErr_t *errp, char *buffer )
+{
+ACLListHandle_t *handle = NULL;
+int eid = 0;
+int rv = 0;
+char *errmsg;
+
+ ACL_InitAttr2Index();
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ if ( acl_InitScanner( errp, NULL, buffer ) < 0 ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else {
+
+ handle = ACL_ListNew(errp);
+ if ( handle == NULL ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else if ( acl_PushListHandle( handle ) < 0 ) {
+ rv = ACLERRNOMEM;
+ eid = ACLERR1920;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else if ( acl_Parse() ) {
+ rv = ACLERRPARSE;
+ eid = ACLERR1780;
+ }
+
+ if ( acl_EndScanner() < 0 ) {
+ rv = ACLERROPEN;
+ eid = ACLERR1500;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, "buffer", errmsg);
+ }
+
+ }
+
+ if ( rv || eid ) {
+ ACL_ListDestroy(errp, handle);
+ handle = NULL;
+ }
+
+ crit_exit( acl_parse_crit );
+ return(handle);
+
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Convert sub-expression to string.
+ */
+
+static int
+acl_expr_string( ACLExprOp_t logical, ACLExprStack_t *expr_stack )
+{
+char **expr_text;
+char **prev_expr_text;
+char *tmp;
+
+ switch (logical) {
+ case ACL_EXPR_OP_NOT:
+ if ( expr_stack->stack_index < 1 ) {
+ printf("expression stack underflow.\n");
+ return(ACLERRINTERNAL);
+ }
+
+ expr_text = &expr_stack->expr_text[expr_stack->stack_index - 1];
+ tmp = (char *) PERM_MALLOC(strlen(*expr_text) + 7);
+ if ( tmp == NULL )
+ return(ACLERRNOMEM);
+
+ if ( expr_stack->found_subexpression ) {
+ sprintf(tmp, "not (%s)", *expr_text);
+ expr_stack->found_subexpression = 0;
+ expr_stack->last_subexpression = expr_stack->stack_index - 1;
+ } else {
+ sprintf(tmp, "not %s", *expr_text);
+ }
+
+ PERM_FREE(*expr_text);
+ *expr_text = tmp;
+ return(0);
+
+ case ACL_EXPR_OP_AND:
+ case ACL_EXPR_OP_OR:
+ if ( expr_stack->stack_index < 2 ) {
+ printf("expression stack underflow.\n");
+ return(ACLERRINTERNAL);
+ }
+
+ expr_stack->stack_index--;
+ prev_expr_text = &expr_stack->expr_text[expr_stack->stack_index];
+ expr_stack->stack_index--;
+ expr_text = &expr_stack->expr_text[expr_stack->stack_index];
+
+ tmp = (char *) PERM_MALLOC (strlen(*expr_text)
+ + strlen(*prev_expr_text) + 15);
+ if ( tmp == NULL )
+ return(ACLERRNOMEM);
+
+ if ( expr_stack->found_subexpression &&
+ expr_stack->stack_index == expr_stack->last_subexpression &&
+ logical == ACL_EXPR_OP_AND ) {
+ sprintf(tmp, "%s and\n (%s)", *expr_text, *prev_expr_text);
+ } else if ( expr_stack->found_subexpression &&
+ expr_stack->stack_index == expr_stack->last_subexpression ) {
+ sprintf(tmp, "%s or\n (%s)", *expr_text, *prev_expr_text);
+ } else if ( logical == ACL_EXPR_OP_AND ) {
+ sprintf(tmp, "%s and\n %s", *expr_text, *prev_expr_text);
+ } else {
+ sprintf(tmp, "%s or\n %s", *expr_text, *prev_expr_text);
+ }
+
+ expr_stack->found_subexpression++;
+ expr_stack->stack_index++;
+ PERM_FREE(*expr_text);
+ PERM_FREE(*prev_expr_text);
+ *expr_text = tmp;
+ *prev_expr_text = NULL;
+ return(0);
+
+ default:
+ printf("Bad boolean logic value.\n");
+ return(ACLERRINTERNAL);
+ }
+
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Reduce all sub-expressions to a single string.
+ */
+
+static int
+acl_reduce_expr_logic( ACLExprStack_t *expr_stack, ACLExprRaw_t *expr_raw )
+{
+char **expr_text;
+char **prev_expr_text;
+char *tmp;
+
+ if (expr_raw->attr_name) {
+ if (expr_stack->stack_index >= ACL_EXPR_STACK ) {
+ printf("expression stack overflow.");
+ return(ACLERRINTERNAL);
+ }
+
+ if ( expr_stack->found_subexpression && expr_stack->stack_index > 0 ) {
+ prev_expr_text = &expr_stack->expr_text[expr_stack->stack_index-1];
+ tmp = (char *) PERM_MALLOC(strlen(*prev_expr_text) + 3);
+ sprintf(tmp, "(%s)", *prev_expr_text);
+ PERM_FREE(*prev_expr_text);
+ *prev_expr_text = tmp;
+ expr_stack->found_subexpression = 0;
+ expr_stack->last_subexpression = expr_stack->stack_index - 1;
+ }
+
+ expr_stack->expr[expr_stack->stack_index] = expr_raw;
+ expr_text = &expr_stack->expr_text[expr_stack->stack_index];
+ *expr_text = (char *) PERM_MALLOC(strlen(expr_raw->attr_name)
+ + strlen(expr_raw->attr_pattern)
+ + 7);
+ if ( *expr_text == NULL )
+ return(ACLERRNOMEM);
+
+ sprintf(*expr_text, "%s %s \"%s\"", expr_raw->attr_name,
+ acl_comp_string(expr_raw->comparator),
+ expr_raw->attr_pattern);
+
+ expr_stack->stack_index++;
+ expr_stack->expr_text[expr_stack->stack_index] = NULL;
+ } else {
+ return(acl_expr_string(expr_raw->logical, expr_stack));
+ }
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Appends str2 to str1.
+ *
+ * Input:
+ * str1 an existing dynamically allocated string
+ * str2 a text string
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+static int
+acl_to_str_append(acl_string_t * p_aclstr, const char *str2)
+{
+ int str2len, newlen;
+
+ if (p_aclstr == NULL || str2 == NULL)
+ return (ACLERRINTERNAL);
+ if (p_aclstr->str == NULL) {
+ p_aclstr->str = (char *) PERM_MALLOC(4096);
+ if (p_aclstr->str == NULL)
+ return (ACLERRNOMEM);
+ p_aclstr->str_size = 4096;
+ p_aclstr->str_len = 0;
+ }
+
+ str2len = strlen(str2);
+ newlen = p_aclstr->str_len + str2len;
+ if (newlen >= p_aclstr->str_size) {
+ p_aclstr->str_size = str2len > 4095 ? str2len+p_aclstr->str_size+1 : 4096+p_aclstr->str_size ;
+ p_aclstr->str = (char *) PERM_REALLOC(p_aclstr->str, p_aclstr->str_size);
+ if (p_aclstr->str == NULL)
+ return (ACLERRNOMEM);
+ }
+ memcpy((void *)&(p_aclstr->str[p_aclstr->str_len]), (void *) str2, str2len+1);
+ p_aclstr->str_len += str2len;
+ return 0;
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output Authorization Expression type either "Allow" or "Deny"
+ */
+
+static int
+acl_to_str_expr_type( acl_string_t *str_t, ACLExprHandle_t *expr )
+{
+ switch (expr->expr_type) {
+ case ACL_EXPR_TYPE_ALLOW:
+ acl_to_str_append(str_t, "allow ");
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute ");
+ return(0);
+ case ACL_EXPR_TYPE_DENY:
+ acl_to_str_append(str_t, "deny ");
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute ");
+ return(0);
+ case ACL_EXPR_TYPE_AUTH:
+ acl_to_str_append(str_t, "authenticate ");
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute ");
+ return(0);
+ case ACL_EXPR_TYPE_RESPONSE:
+ acl_to_str_append(str_t, "deny with ");
+ return(0);
+ default:
+ return(ACLERRINTERNAL);
+ }
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output Authorization Expression Rights "(right, right)"
+ */
+
+static int
+acl_to_str_expr_arg( acl_string_t *str_t, ACLExprHandle_t *expr )
+{
+int ii;
+
+ if ( expr->expr_argc <= 0 ) {
+ return(ACLERRINTERNAL);
+ }
+
+ if ( expr->expr_type == ACL_EXPR_TYPE_RESPONSE ) {
+ acl_to_str_append(str_t, expr->expr_argv[0]);
+ acl_to_str_append(str_t, "=\"");
+ acl_to_str_append(str_t, expr->expr_argv[1]);
+ acl_to_str_append(str_t, "\";\n");
+ return(0);
+ }
+
+ acl_to_str_append(str_t, "(");
+ for (ii = 0; ii < expr->expr_argc; ii++) {
+ acl_to_str_append(str_t, expr->expr_argv[ii]);
+ if ( ii < expr->expr_argc - 1 ) {
+ acl_to_str_append(str_t, ",");
+ }
+ }
+ acl_to_str_append(str_t, ") ");
+
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Walks through the authentication statement PList_t and
+ * prints the structure to a string.
+ */
+
+static void
+acl_to_str_auth_expr(char *lval, const void *rval, void *user_data)
+{
+ // ###### char **str = (char **) user_data;
+ acl_string_t * p_aclstr = (acl_string_t *) user_data;
+
+ acl_to_str_append(p_aclstr, "\t");
+ acl_to_str_append(p_aclstr, lval);
+ acl_to_str_append(p_aclstr, " = \"");
+ acl_to_str_append(p_aclstr, (char *) rval);
+ acl_to_str_append(p_aclstr, "\";\n");
+
+ return;
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output the logic part of the authencation statement to a string.
+ */
+
+static int
+acl_to_str_auth_logic( acl_string_t *str_t, ACLExprHandle_t *expr)
+{
+
+ if ( expr->expr_auth == NULL ) {
+ acl_to_str_append(str_t, "{\n");
+ acl_to_str_append(str_t, "# Authenticate statement with no body?\n");
+ acl_to_str_append(str_t, "\tnull=null;\n");
+ acl_to_str_append(str_t, "};\n");
+ return(0);
+ }
+
+ acl_to_str_append(str_t, "{\n");
+ PListEnumerate(expr->expr_auth, acl_to_str_auth_expr, (void *) str_t);
+ acl_to_str_append(str_t, "};\n");
+
+ return(0);
+}
+
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output the logic part of the authorization statement to a string.
+ */
+
+static int
+acl_to_str_expr_logic( acl_string_t *str_t, ACLExprHandle_t *expr, ACLExprStack_t *expr_stack)
+{
+int rv = 0;
+int ii;
+
+ expr_stack->stack_index = 0;
+ expr_stack->found_subexpression = 0;
+ expr_stack->last_subexpression = -1;
+
+ for (ii = 0; ii < expr->expr_raw_index; ii++) {
+ rv = acl_reduce_expr_logic(expr_stack, &expr->expr_raw[ii]);
+ if (rv) break;
+ }
+
+ if (!rv && expr_stack->expr_text[0]) {
+ acl_to_str_append(str_t, "\n ");
+ acl_to_str_append(str_t, expr_stack->expr_text[0]);
+ acl_to_str_append(str_t, ";\n");
+ PERM_FREE(expr_stack->expr_text[0]);
+ }
+
+ return(rv);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output an ACL list to a string.
+ */
+
+static int
+acl_to_str_create( acl_string_t *str_t, ACLListHandle_t *acl_list )
+{
+ACLWrapper_t *wrap;
+ACLHandle_t *acl;
+ACLExprHandle_t *expr;
+int rv = 0;
+ACLExprStack_t *expr_stack;
+
+ expr_stack = (ACLExprStack_t *) PERM_MALLOC(sizeof(ACLExprStack_t));
+ if ( expr_stack == NULL )
+ return(ACLERRNOMEM);
+
+ acl_to_str_append(str_t, "# File automatically written\n");
+ acl_to_str_append(str_t, "#\n");
+ acl_to_str_append(str_t, "# You may edit this file by hand\n");
+ acl_to_str_append(str_t, "#\n\n");
+ if ( acl_list->acl_list_head == NULL ) {
+ PERM_FREE(expr_stack);
+ return(0);
+ }
+
+ acl_to_str_append(str_t, "version 3.0;\n");
+ for (wrap = acl_list->acl_list_head; wrap && !rv;
+ wrap = wrap->wrap_next ) {
+ acl = wrap->acl;
+ if ( acl->tag ) {
+ acl_to_str_append(str_t, "\nacl \"");
+ acl_to_str_append(str_t, acl->tag);
+ acl_to_str_append(str_t, "\";\n");
+ } else {
+ acl_to_str_append(str_t, "\nacl;\n");
+ }
+
+ for (expr = acl->expr_list_head; expr && rv == 0;
+ expr = expr->expr_next ) {
+
+ if ( (rv = acl_to_str_expr_type(str_t, expr)) < 0 )
+ break;
+
+ if ( (rv = acl_to_str_expr_arg(str_t, expr)) < 0)
+ break;
+
+ switch (expr->expr_type) {
+ case ACL_EXPR_TYPE_DENY:
+ case ACL_EXPR_TYPE_ALLOW:
+ rv = acl_to_str_expr_logic(str_t, expr, expr_stack);
+ break;
+ case ACL_EXPR_TYPE_AUTH:
+ rv = acl_to_str_auth_logic(str_t, expr);
+ break;
+ case ACL_EXPR_TYPE_RESPONSE:
+ break;
+ }
+
+ }
+ }
+
+ PERM_FREE(expr_stack);
+ return(rv);
+}
+
+
+/*
+ * Creates an ACL text string from an ACL handle
+ *
+ * Input:
+ * errp error stack
+ * acl target text string pointer
+ * acl_list Source ACL list handle
+ * Ouput:
+ * acl a chunk of dynamic memory pointing to ACL text
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_WriteString(NSErr_t *errp, char **acl, ACLListHandle_t *acl_list)
+{
+ int rv;
+ acl_string_t str_t = {NULL,0,0};
+
+ if ( acl_list == NULL || acl == NULL )
+ return(ACLERRUNDEF);
+
+ rv = acl_to_str_create(&str_t, acl_list);
+ *acl = str_t.str;
+
+ return ( rv );
+}
+
+/*
+ * Write an ACL text file from an input ACL list structure.
+ *
+ * Input:
+ * filename name for the output text file
+ * acl_list a list of ACLs to convert to text
+ * Output:
+ * errp an error stack, set if there are errors
+ * to report
+ * Returns:
+ * 0 success
+ * ACLERROPEN,
+ * ACLERRNOMEM on failure
+ */
+
+NSAPI_PUBLIC int
+ACL_WriteFile( NSErr_t *errp, char *filename, ACLListHandle_t *acl_list )
+{
+int rv;
+int eid;
+char *errmsg;
+#ifdef UTEST
+FILE *ofp;
+#else
+SYS_FILE ofp;
+#endif
+acl_string_t aclstr = {NULL,0,0};
+char *acl_text = NULL;
+
+ if ( filename == NULL || acl_list == NULL ) {
+ rv = ACLERROPEN;
+ eid = ACLERR1900;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ return(ACLERROPEN);
+ }
+
+#ifdef UTEST
+ ofp = fopen(filename, "w");
+ if ( ofp == NULL ) {
+#else
+ ofp = system_fopenWT(filename);
+ if ( ofp == SYS_ERROR_FD ) {
+#endif
+ rv = ACLERROPEN;
+ eid = ACLERR1900;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ return(ACLERROPEN);
+ }
+
+ rv = acl_to_str_create(&aclstr, acl_list);
+ acl_text = aclstr.str;
+
+ if ( rv ) {
+ eid = ACLERR3000;
+ rv = ACLERRNOMEM;
+ nserrGenerate(errp, rv, eid, ACL_Program, 0);
+ } else {
+#ifdef UTEST
+ if (fputs(acl_text, ofp) == 0) {
+#else
+ if (system_fwrite_atomic(ofp, acl_text, strlen(acl_text))==IO_ERROR) {
+#endif
+ eid = ACLERR3200;
+ rv = ACLERRIO;
+ errmsg = system_errmsg();
+ nserrGenerate(errp, rv, eid, ACL_Program, 2, filename, errmsg);
+ }
+ }
+
+ if ( acl_text )
+ PERM_FREE(acl_text);
+
+#ifdef UTEST
+ fclose(ofp);
+#else
+ system_fclose(ofp);
+#endif
+
+ return(rv);
+}
+
+/*
+ * Delete a named ACL from an ACL list
+ *
+ * Input:
+ * acl_list Target ACL list handle
+ * acl_name Name of the target ACL
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ListAclDelete(NSErr_t *errp, ACLListHandle_t *acl_list, char *acl_name, int flags )
+{
+ACLHandle_t *acl = NULL;
+ACLWrapper_t *wrapper;
+ACLWrapper_t *wrapper_prev = NULL;
+Symbol_t *sym;
+
+ if ( acl_list == NULL || acl_name == NULL )
+ return(ACLERRUNDEF);
+
+ if ( flags & ACL_CASE_INSENSITIVE ) {
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag &&
+ strcasecmp( wrapper->acl->tag, acl_name ) == 0 ) {
+ acl = wrapper->acl;
+ break;
+ }
+ wrapper_prev = wrapper;
+ }
+ } else {
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag &&
+ strcmp( wrapper->acl->tag, acl_name ) == 0 ) {
+ acl = wrapper->acl;
+ break;
+ }
+ wrapper_prev = wrapper;
+ }
+ }
+
+ if ( acl ) {
+
+ if ( wrapper_prev ) {
+ wrapper_prev->wrap_next = wrapper->wrap_next;
+ } else {
+ acl_list->acl_list_head = wrapper->wrap_next;
+ }
+
+ if ( acl_list->acl_list_tail == wrapper ) {
+ acl_list->acl_list_tail = wrapper_prev;
+ }
+
+ acl = wrapper->acl;
+ acl_list->acl_count--;
+ PERM_FREE(wrapper);
+
+ if ( acl_list->acl_sym_table ) {
+ if ( symTableFindSym(acl_list->acl_sym_table,
+ acl->tag, ACLSYMACL, (void **) &sym) < 0 ) {
+
+ /* not found, this is an error of some sort */
+
+ } else {
+ symTableRemoveSym(acl_list->acl_sym_table, sym);
+ acl_hash_entry_destroy(sym, 0);
+ }
+ }
+
+ ACL_AclDestroy(errp, acl);
+ return(0);
+ }
+
+ return(ACLERRUNDEF);
+}
+
+/*
+ * local function: translate string to lower case
+ * return <0: fail
+ * 0: succeed
+ */
+int
+open_file_buf(FILE ** file, char * filename, char *mode, char ** buf, long * size)
+{
+ int rv = 0;
+ long cur = 0;
+ long in = 0;
+ struct stat fi;
+
+ if (filename==NULL || mode==NULL) {
+ rv = ACLERROPEN;
+ goto open_cleanup;
+ }
+
+ if ((*file=fopen(filename,mode))==NULL) {
+ rv = ACLERROPEN;
+ goto open_cleanup;
+ }
+
+ if (system_stat(filename, &fi)==-1) {
+ rv = ACLERROPEN;
+ goto open_cleanup;
+ }
+
+ *size = fi.st_size;
+
+ if ((*buf=(char *)PERM_MALLOC(*size+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto open_cleanup;
+ }
+
+
+ rv = 0;
+ while (cur<*size) {
+ in=fread(&(*buf)[cur], 1, *size, *file);
+ cur = cur+in;
+ if (feof(*file)) {
+ break;
+ }
+ if (ferror(*file)) {
+ rv = ACLERRIO;
+ break;
+ }
+ }
+ if (rv==0)
+ (*buf)[cur] = 0;
+
+open_cleanup:
+ if (rv<0) {
+ if (*file)
+ fclose(*file);
+ if (*buf)
+ PERM_FREE(*buf);
+ }
+ return rv;
+}
+
+
+/*
+ * local function: writes buf to disk and close the file
+ */
+void
+close_file_buf(FILE * file, char * filename, char * mode, char * buf)
+{
+ if (file==NULL)
+ return;
+ fclose(file);
+ if (strchr(mode, 'w')!=NULL || strchr(mode, 'a')!=NULL) {
+ file = fopen(filename, "wb");
+ fwrite(buf,1,strlen(buf),file);
+ fclose(file);
+ }
+ PERM_FREE(buf);
+}
+
+
+/*
+ * local function: translate string to lower case
+ */
+char *
+str_tolower(char * string)
+{
+ register char * p = string;
+ for (; *p; p++)
+ *p = tolower(*p);
+ return string;
+}
+
+/*
+ * local function: get the first name appear in block
+ * return: 0 : not found,
+ * 1 : found
+ */
+int
+acl_get_first_name(char * block, char ** name, char ** next)
+{
+ char bounds[] = "\t \"\';";
+ char boundchar;
+ char *p=NULL, *q=NULL, *start=NULL, *end=NULL;
+
+ if (block==NULL)
+ return 0;
+try_next:
+ if ((p=strstr(block, "acl"))!=NULL) {
+
+ // check if this "acl" is the first occurance in this line.
+ for (q=p-1; ((q>=block) && *q!='\n'); q--) {
+ if (strchr(" \t",*q)==NULL) {
+ // if not, try next;
+ block = p+3;
+ goto try_next;
+ }
+ }
+
+ p+=3;
+ while (strchr(bounds,*p)&&(*p!=0))
+ p++;
+ if (*p==0)
+ return 0;
+ boundchar = *(p-1);
+ start = p;
+ while ((boundchar!=*p)&&(*p!=0)&&(*p!=';'))
+ p++;
+ if (*p==0)
+ return 0;
+ end = p;
+ *name = (char *)PERM_MALLOC(end-start+1);
+ strncpy(*name, start, (end-start));
+ (*name)[end-start]=0;
+ *next = end;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * local function: find the pointer to acl string from the given block
+ */
+char *
+acl_strstr(char * block, char * aclname)
+{
+ const char set[] = "\t \"\';";
+ char * name, * rstr = NULL;
+ char * lowerb = block;
+ int found = 0;
+
+ if (block==NULL||aclname==NULL)
+ return NULL;
+
+ while ((name = strstr(block, aclname))!=NULL && !found) {
+ if (name>lowerb) { // This should be true, just in case
+ if ((strchr(set,name[-1])!=0) && (strchr(set,name[strlen(aclname)])!=0)) {
+ // the other 2 sides are in boundary set, that means, this is an exact match.
+ while (&name[-1]>=lowerb) {
+ name --;
+ if (strchr(set, *name)==0)
+ break; // should point to 'l'
+ }
+
+ if (name==lowerb)
+ return NULL;
+
+ if ((name-2)>=lowerb)
+ if ((name[-2]=='a') && (name[-1]=='c') && (*name=='l')) {
+ name -= 2; // name point to 'a'
+ rstr = name;
+ while (TRUE) {
+ if (name==lowerb) {
+ found = 1;
+ break;
+ }
+ else if (name[-1]==' '||name[-1]=='\t')
+ name --;
+ else if (name[-1]=='\n') {
+ found = 1;
+ break;
+ }
+ else
+ break; // acl is not at the head, there are other chars.
+ }
+ }
+ }
+ block = name + strlen(aclname);
+ }
+ }
+ return rstr;
+}
+
+
+
+/*
+ * local function: find the acl string from mapfile and return its acl structure
+ */
+int
+get_acl_from_file(char * filename, char * aclname, ACLListHandle_t ** acllist_pp)
+{
+ int rv = 0;
+ char * pattern=NULL;
+ char header[] = "version 3.0;\n";
+ int headerlen = strlen(header);
+ long filesize;
+ FILE * file;
+ char * mirror=NULL, * text=NULL, *nextname=NULL;
+ char * block=NULL, * aclhead=NULL, * aclend=NULL;
+
+ *acllist_pp = NULL;
+
+ // build the acl name pattern, which should be acl "..."
+ // the ".." is built by acl_to_str_create
+
+ if (aclname==NULL) {
+ rv = ACLERRUNDEF;
+ goto get_cleanup;
+ }
+
+ if ((pattern=(char *)PERM_MALLOC(strlen(aclname) + 1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto get_cleanup;
+ }
+ else {
+ sprintf(pattern,"%s", aclname);
+ str_tolower(pattern);
+ }
+
+ /* get the acl text from the mapfile */
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto get_cleanup;
+
+ if ((mirror = (char *) PERM_MALLOC(filesize+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto get_cleanup;
+ }
+
+ memcpy(mirror, block, filesize);
+ mirror[filesize]=0;
+ str_tolower(mirror);
+
+ if ((aclhead = acl_strstr(mirror, pattern))!=NULL) {
+ // use mirror to search, then transfer to work on block;
+ aclhead = block + (aclhead - mirror);
+ acl_get_first_name(aclhead+3, &nextname, &aclend);
+ aclend = acl_strstr(aclhead+3, nextname);
+ if (aclend == NULL) {
+ // this is the last acl in the file
+ aclend = &aclhead[strlen(aclhead)];
+ }
+
+ int len = aclend - aclhead;
+ text = (char *) PERM_MALLOC(len + headerlen + 1);
+ sprintf(text, "%s", header);
+ memcpy(&text[headerlen], aclhead, len);
+ text[headerlen + len] = 0;
+
+ if ((*acllist_pp=ACL_ParseString(NULL, text))==NULL) {
+ rv = ACLERRPARSE;
+ }
+ }
+
+get_cleanup:
+ if (pattern)
+ PERM_FREE(pattern);
+ if (file)
+ close_file_buf(file, filename, "rb", block);
+ if (mirror)
+ PERM_FREE(mirror);
+ if (text)
+ PERM_FREE(text);
+ if (nextname)
+ PERM_FREE(nextname);
+ return rv;
+}
+
+
+/*
+ * local function: delete the acl string from mapfile
+ */
+int
+delete_acl_from_file(char * filename, char * aclname)
+{
+ char * pattern=NULL;
+ char header[] = "version 3.0;\n";
+ int headerlen = strlen(header);
+ int rv = ACLERRUNDEF;
+ long filesize;
+ FILE * file;
+ char * mirror=NULL, * text=NULL, * nextname=NULL;
+ char * block=NULL, * aclhead=NULL, * aclend=NULL;
+ int remain;
+
+ // build the acl name pattern, which should be acl "..."
+ // the ".." is built by acl_to_str_create
+
+ if (aclname==NULL) {
+ rv = ACLERRUNDEF;
+ goto delete_cleanup;
+ }
+
+ if ((pattern=(char *)PERM_MALLOC(strlen(aclname) + 10))==NULL) {
+ rv = ACLERRNOMEM;
+ goto delete_cleanup;
+ }
+ else {
+ sprintf(pattern,"%s", aclname);
+ str_tolower(pattern);
+ }
+
+ /* file the acl text from the mapfile */
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto delete_cleanup;
+
+ if ((mirror = (char *) PERM_MALLOC(filesize+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto delete_cleanup;
+ }
+
+ memcpy(mirror, block, filesize);
+ mirror[filesize]=0;
+ str_tolower(mirror);
+
+ if ((aclhead = acl_strstr(mirror, pattern))!=NULL) {
+ // use mirror to search, then transfer to work on block;
+ aclhead = block + (aclhead - mirror);
+ acl_get_first_name(aclhead+3, &nextname, &aclend);
+ aclend = acl_strstr(aclhead+3, nextname);
+ if (aclend == NULL) {
+ // this is the last acl in the file
+ aclend = &aclhead[strlen(aclhead)];
+ }
+
+ int len = aclend - aclhead;
+ text = (char *) PERM_MALLOC(len + headerlen + 1);
+ sprintf(text, "%s", header);
+ memcpy(&text[headerlen], aclhead, len);
+ text[headerlen + len] = 0;
+
+ if (ACL_ParseString(NULL, text)==NULL) {
+ rv = ACLERRPARSE;
+ goto delete_cleanup;
+ }
+ }
+
+ if (aclhead!=NULL) { // found the acl in the map file
+
+ // int filesize = mpfile->Size();
+
+ remain = strlen(aclend);
+ if (memcpy(aclhead, aclend, remain)!=NULL)
+ rv = 0;
+ else
+ rv = ACLERRIO;
+
+ aclhead[remain]=0;
+
+ block = (char *) PERM_REALLOC(block, strlen(block)+1);
+ }
+ else
+ rv = ACLERRUNDEF;
+
+delete_cleanup:
+ if (pattern)
+ PERM_FREE(pattern);
+ if (text)
+ PERM_FREE(text);
+ if (mirror)
+ PERM_FREE(mirror);
+ if (nextname)
+ PERM_FREE(nextname);
+ if (file)
+ close_file_buf(file, filename, "wb", block);
+ return rv;
+}
+
+/*
+ * local function: append the acl string to file
+ */
+int
+append_acl_to_file(char * filename, char * aclname, char * acltext)
+{
+ int rv;
+ /* acltext has been parsed to verify syntax up to this point */
+ char * pattern=NULL;
+ char * start=NULL;
+ char * block;
+ long filesize;
+ FILE * file;
+ long len;
+
+ if ((pattern=(char *)PERM_MALLOC(strlen(aclname) + 10))==NULL) {
+ rv = ACLERRNOMEM;
+ goto append_cleanup;
+ }
+ else {
+ sprintf(pattern,"%s", aclname);
+ }
+
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto append_cleanup;
+
+ // find the begining of acl, skip the version part
+
+ len = strlen(block);
+ start = acl_strstr(acltext, pattern);
+ if ((block=(char *)PERM_REALLOC(block, len+strlen(start)+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto append_cleanup;
+ }
+ strcat(block, start);
+
+append_cleanup:
+ if (pattern)
+ PERM_FREE(pattern);
+ if (file)
+ close_file_buf(file, filename, "wb", block);
+
+ return rv;
+}
+
+
+
+/*
+ * local function: rename the acl name in the file
+ */
+int
+rename_acl_in_file(char * filename, char * aclname, char * newname)
+{
+ ACLListHandle_t * racllist=NULL;
+ char * pattern=NULL;
+ char header[] = "version 3.0;\n";
+ int headerlen = strlen(header);
+ int rv = 0;
+ long filesize;
+ FILE * file;
+ int remain;
+ long len;
+ char * text=NULL, * mirror=NULL, * nextname=NULL;
+ char * block=NULL, * aclhead=NULL, * aclend=NULL;
+ char * cut=NULL;
+ acl_string_t str_t = {NULL,0,0};
+
+ // build the acl name pattern, which should be acl "..."
+ // the ".." is built by acl_to_str_create
+
+ if (aclname==NULL || newname==NULL) {
+ rv = ACLERRUNDEF;
+ goto rename_cleanup;
+ }
+
+ if ((pattern=(char *)PERM_MALLOC(strlen(aclname) + 10))==NULL) {
+ rv = ACLERRNOMEM;
+ goto rename_cleanup;
+ }
+ else {
+ sprintf(pattern,"%s", aclname);
+ str_tolower(pattern);
+ }
+
+ // file the acl text from the mapfile
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto rename_cleanup;
+
+ if ((mirror = (char *) PERM_MALLOC(filesize+1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto rename_cleanup;
+ }
+
+ memcpy(mirror, block, filesize);
+ mirror[filesize]=0;
+ str_tolower(mirror);
+
+ if ((aclhead = acl_strstr(mirror, pattern))!=NULL) {
+ // use mirror to search, then transfer to work on block;
+ aclhead = block + (aclhead - mirror);
+ acl_get_first_name(aclhead+3, &nextname, &aclend);
+ aclend = acl_strstr(aclhead+3, nextname);
+ if (aclend == NULL) {
+ // this is the last acl in the file
+ aclend = &aclhead[strlen(aclhead)];
+ }
+
+ len = aclend - aclhead;
+ text = (char *) PERM_MALLOC(len + headerlen + 1);
+ sprintf(text, "%s", header);
+ memcpy(&text[headerlen], aclhead, len);
+ text[headerlen + len] = 0;
+
+ if ((racllist=ACL_ParseString(NULL, text))==NULL) {
+ rv = ACLERRPARSE;
+ goto rename_cleanup;
+ }
+ }
+
+ if (aclhead!=NULL) { // found the acl in the map file
+
+ remain = strlen(aclend);
+ // delete the acltext from where it is
+ if (memcpy(aclhead, aclend, remain)!=NULL)
+ rv = 0;
+ else
+ rv = ACLERRUNDEF;
+
+ aclhead[remain] = 0;
+ len = strlen(block);
+
+ /* establish the renamed the acl */
+ acl_to_str_append(&str_t, "acl \"");
+ acl_to_str_append(&str_t, newname);
+ acl_to_str_append(&str_t, "\";");
+ /* skip acl "..."; the semicollon in the last counts for the +1
+ add the rest acl text to str_t */
+ cut = strchr(text, ';'); // skip version ...;
+ cut = strchr(cut+1, ';') + 1; // skip acl ...;
+ if (cut==NULL) {
+ rv = ACLERRUNDEF;
+ goto rename_cleanup;
+ }
+ acl_to_str_append(&str_t, cut);
+ // acl_to_str_append(&str_t, "\n");
+
+ if ((block=(char *) PERM_REALLOC(block, len + strlen(str_t.str) + 1))==NULL) {
+ rv = ACLERRNOMEM;
+ goto rename_cleanup;
+ }
+ // strcat(block, "\n");
+ strcat(block, str_t.str);
+ }
+ else
+ rv = ACLERRUNDEF;
+
+rename_cleanup:
+ if (pattern)
+ PERM_FREE(pattern);
+ if (text)
+ PERM_FREE(text);
+ if (mirror)
+ PERM_FREE(mirror);
+ if (nextname)
+ PERM_FREE(nextname);
+ if (str_t.str)
+ PERM_FREE(str_t.str);
+ if (file)
+ close_file_buf(file, filename, "wb", block);
+ return rv;
+}
+
+
+/*
+ * Retrieves the definition of a named ACL
+ *
+ * Input:
+ * errp a error stack
+ * filename Target ACL file
+ * acl_name Name of the target ACL
+ * acl_text a dynmaically allocated text (result)
+ * Output:
+ * errp error stack is set on error
+ * Returns:
+ * 0 success
+ * <0 failure
+ */
+NSAPI_PUBLIC int
+ACL_FileGetAcl(NSErr_t *errp,
+ char *filename,
+ char *acl_name,
+ // ACLListHandle_t **acllist_p,
+ char ** acltext,
+ int flags)
+{
+ int rv;
+ ACLListHandle_t * acllist_p;
+
+ if (acl_parse_crit == NULL)
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ rv = get_acl_from_file(filename, acl_name, &acllist_p);
+
+ if (acllist_p == NULL) {
+ *acltext = NULL;
+ goto get_cleanup;
+ }
+
+ /*
+ if ((rv=ACL_Decompose(errp, acltext, acllist_p))<0) {
+ *acltext = NULL;
+ goto get_cleanup;
+ }
+ */
+ if ((rv=ACL_WriteString(errp, acltext, acllist_p))<0) {
+ *acltext = NULL;
+ goto get_cleanup;
+ }
+
+
+get_cleanup:
+
+ crit_exit( acl_parse_crit );
+
+ return rv;
+}
+
+
+
+/*
+ * Delete a named ACL from an ACL file
+ *
+ * Input:
+ * errp a error stack
+ * filename Target ACL file
+ * acl_name Name of the target ACL
+ * Output:
+ * errp error stack is set on error
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_FileDeleteAcl(NSErr_t *errp,
+ char *filename,
+ char *acl_name,
+ int flags)
+{
+ int rv = 0;
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ rv = delete_acl_from_file(filename, acl_name);
+
+ crit_exit( acl_parse_crit );
+ return(rv);
+}
+
+
+/*
+ * Sets the definition of an ACL in an ACL file
+ *
+ * Input:
+ * errp a error stack
+ * filename Target ACL file
+ * acl_name Name of the target ACL
+ * acl_text a string that defines the new ACL
+ * Output:
+ * errp error stack is set on error
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_FileSetAcl(NSErr_t *errp,
+ char *filename,
+ char *acl_text,
+ int flags)
+{
+ int rv = 0;
+ ACLListHandle_t *new_acl_list = NULL;
+ char **acl_name_list = NULL;
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ // get the acl name.
+ new_acl_list = ACL_ParseString(errp, acl_text);
+ if ( new_acl_list == NULL ) {
+ rv = ACLERRPARSE;
+ goto set_cleanup;
+ }
+
+ if ( ACL_ListGetNameList(errp, new_acl_list, &acl_name_list) < 0 ) {
+ rv = ACLERRNOMEM;
+ goto set_cleanup;
+ }
+
+
+ delete_acl_from_file(filename, acl_name_list[0]);
+ rv = append_acl_to_file(filename, acl_name_list[0], acl_text);
+
+set_cleanup:
+
+ crit_exit( acl_parse_crit );
+ if (new_acl_list)
+ ACL_ListDestroy(errp, new_acl_list);
+ if (acl_name_list)
+ free(acl_name_list);
+ return(rv);
+}
+
+
+/*
+ * Rename a named ACL in ACL text file
+ *
+ * Input:
+ * errp a error stack
+ * filename Target ACL file
+ * acl_name Name of the target ACL
+ * new_acl_name New ACL name
+ * Output:
+ * errp error stack is set on error
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_FileRenameAcl(NSErr_t *errp,
+ char *filename,
+ char *aclname,
+ char *newname,
+ int flags)
+{
+ int rv = 0;
+
+ if ( acl_parse_crit == NULL )
+ acl_parse_crit = crit_init();
+
+ crit_enter( acl_parse_crit );
+
+ rv = rename_acl_in_file(filename, aclname, newname);
+
+ crit_exit( acl_parse_crit );
+ return(rv);
+
+}
+
+
+//
+// Merge a list of ACLs into one ACL
+//
+// Input:
+// filename the target acl file
+// acl_list ACLs to merge
+// new_acl_name resultant ACL
+// flags currently ignored
+// Returns:
+// 0 success
+// < 0 failure
+//
+
+NSAPI_PUBLIC int
+ACL_FileMergeAcl(NSErr_t *errp,
+ char *filename,
+ char **acl_name_list,
+ char *new_acl_name,
+ int flags)
+{
+ ACLListHandle_t *new_acl_list = NULL;
+ ACLListHandle_t *tmp_acl_list = NULL;
+ int ii;
+ int rv;
+ ACLHandle_t *tmp_acl;
+ ACLHandle_t *new_acl;
+ ACLExprHandle_t *expr;
+
+
+ tmp_acl_list = ACL_ParseFile(errp, filename);
+ if ( tmp_acl_list == NULL ) {
+ rv = ACLERRPARSE;
+ goto cleanup;
+ }
+
+ new_acl_list = ACL_ParseFile(errp, filename);
+ if ( new_acl_list == NULL ) {
+ rv = ACLERRPARSE;
+ goto cleanup;
+ }
+
+ // first get rid of all the ACLs that will be merged
+
+ for (ii = 0; acl_name_list[ii]; ii++) {
+ rv = ACL_ListAclDelete(errp, new_acl_list, acl_name_list[ii], flags);
+ if ( rv < 0 )
+ goto cleanup;
+ }
+
+ // now create ACL to house the merged result
+ new_acl = ACL_AclNew(errp, new_acl_name);
+ if ( new_acl == NULL ) {
+ rv = ACLERRNOMEM;
+ goto cleanup;
+ }
+
+ rv = ACL_ListAppend(errp, new_acl_list, new_acl, flags);
+ if ( rv < 0 )
+ goto cleanup;
+
+ for (ii = 0; acl_name_list[ii]; ii++) {
+ tmp_acl = ACL_ListFind(errp, tmp_acl_list, acl_name_list[ii], flags);
+ if ( tmp_acl == NULL ) {
+ rv = ACLERRUNDEF;
+ goto cleanup;
+ }
+ for (expr = tmp_acl->expr_list_head; expr; expr = expr->expr_next) {
+ // This call can't really fail unless we pass it a NULL
+ // or some memory is corrupt.
+ rv = ACL_ExprAppend(errp, new_acl, expr);
+ if ( rv < 0 )
+ goto cleanup;
+ tmp_acl->expr_list_head = expr->expr_next;
+ tmp_acl->expr_count--;
+ }
+
+ // Last bit of clean up so the destroy routine isn't confused.
+
+ tmp_acl->expr_list_tail = NULL;
+ tmp_acl->expr_count = 0;
+ }
+
+ rv = ACL_WriteFile(errp, filename, new_acl_list);
+
+cleanup:
+ if ( new_acl_list )
+ ACL_ListDestroy(errp, new_acl_list);
+ if ( tmp_acl_list )
+ ACL_ListDestroy(errp, tmp_acl_list);
+ return(rv);
+}
+
+//
+// Merge a list of ACL files into one ACL file
+//
+// Input:
+// filename the target acl file
+// file_list ACL files to merge
+// flags currently ignored
+// Returns:
+// 0 success
+// < 0 failure
+//
+
+NSAPI_PUBLIC int
+ACL_FileMergeFile(NSErr_t *errp,
+ char *filename,
+ char **file_list,
+ int flags)
+{
+ ACLListHandle_t *new_acl_list = NULL;
+ ACLListHandle_t *tmp_acl_list = NULL;
+ int ii;
+ int rv;
+
+ // we don't care if they have nothing to do
+
+ if ( filename == NULL || file_list == NULL )
+ return(0);
+
+ new_acl_list = ACL_ListNew(errp);
+ if (new_acl_list == NULL)
+ return(ACLERRNOMEM);
+
+ for (ii = 0; file_list[ii]; ii++) {
+ tmp_acl_list = ACL_ParseFile(errp, file_list[ii]);
+ if (tmp_acl_list == NULL) {
+ rv = ACLERRPARSE;
+ goto cleanup;
+ }
+ rv = ACL_ListConcat(errp, new_acl_list, tmp_acl_list, flags);
+ if ( rv < 0 )
+ goto cleanup;
+ ACL_ListDestroy(errp, tmp_acl_list);
+ tmp_acl_list = NULL;
+ }
+
+ rv = ACL_WriteFile(errp, filename, new_acl_list);
+
+cleanup:
+ if ( new_acl_list )
+ ACL_ListDestroy(errp, new_acl_list);
+ if ( tmp_acl_list )
+ ACL_ListDestroy(errp, tmp_acl_list);
+ return(rv);
+}
+
+/*
+ * Destroy a NameList
+ *
+ * Input:
+ * name_list a dynamically allocated array of strings
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_NameListDestroy(NSErr_t *errp, char **name_list)
+{
+ int list_index;
+
+ if ( name_list == NULL )
+ return(ACLERRUNDEF);
+
+ for ( list_index = 0; name_list[list_index]; list_index++ ) {
+ PERM_FREE(name_list[list_index]);
+ }
+ PERM_FREE(name_list);
+ return(0);
+}
+
+
+/*
+ * Gets a name list of consisting of all ACL names for input list.
+ *
+ * Input:
+ * acl_list an ACL List handle
+ * name_list pointer to a list of string pointers
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+NSAPI_PUBLIC int
+ACL_ListGetNameList(NSErr_t *errp, ACLListHandle_t *acl_list, char ***name_list)
+{
+ const int block_size = 50;
+ ACLWrapper_t *wrapper;
+ int list_index;
+ int list_size;
+ char **tmp_list;
+ char **local_list;
+ char *name;
+
+
+ if ( acl_list == NULL )
+ return(ACLERRUNDEF);
+
+ list_size = block_size;
+ local_list = (char **) PERM_MALLOC(sizeof(char *) * list_size);
+ if ( local_list == NULL )
+ return(ACLERRNOMEM);
+ list_index = 0;
+ local_list[list_index] = NULL;
+
+ for ( wrapper = acl_list->acl_list_head; wrapper != NULL;
+ wrapper = wrapper->wrap_next ) {
+ if ( wrapper->acl->tag )
+ name = wrapper->acl->tag;
+ else
+ name = "noname";
+ if ( list_index + 2 > list_size ) {
+ list_size += block_size;
+ tmp_list = (char **) PERM_REALLOC(local_list,
+ sizeof(char *) * list_size);
+ if ( tmp_list == NULL ) {
+ ACL_NameListDestroy(errp, local_list);
+ return(ACLERRNOMEM);
+ }
+ local_list = tmp_list;
+ }
+ local_list[list_index] = PERM_STRDUP(name);
+ if ( local_list[list_index] == NULL ) {
+ ACL_NameListDestroy(errp, local_list);
+ return(ACLERRNOMEM);
+ }
+ list_index++;
+ local_list[list_index] = NULL;
+ }
+ *name_list = local_list;
+ return(0);
+}
+
+/*
+ * Gets a name list of consisting of all ACL names from the input aclfile
+ *
+ * Input:
+ * filename acl file
+ * name_list pointer to a list of string pointers
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_FileGetNameList(NSErr_t *errp, char * filename, char ***name_list)
+{
+
+ const int block_size = 50;
+ int rv, list_size, list_index;
+ char ** local_list;
+ char * block ;
+ char * name;
+ char * next;
+ long filesize;
+ FILE * file;
+ char * head;
+
+ if ((rv=open_file_buf(&file, filename, "rb", &block, &filesize))<0)
+ goto list_cleanup;
+
+ list_size = block_size;
+ local_list = (char **) PERM_MALLOC(sizeof(char *) * list_size);
+ if ( local_list == NULL ) {
+ rv = ACLERRNOMEM;
+ goto list_cleanup;
+ }
+ list_index = 0;
+ local_list[list_index] = NULL;
+
+ head = block;
+ while ((acl_get_first_name(head, &name, &next))) {
+
+ if (list_index+2 > list_size) {
+ list_size += block_size;
+ char ** tmp_list = (char **) PERM_REALLOC(local_list, sizeof(char *) * list_size);
+ if ( tmp_list == NULL ) {
+ rv = ACLERRNOMEM;
+ goto list_cleanup;
+ }
+ local_list = tmp_list;
+ }
+ // local_list[list_index] = PERM_STRDUP(name);
+ local_list[list_index] = name;
+ if ( local_list[list_index] == NULL ) {
+ rv = ACLERRNOMEM;
+ goto list_cleanup;
+ }
+ list_index++;
+ local_list[list_index] = NULL;
+ head = next;
+ }
+
+ rv = 0;
+ *name_list = local_list;
+
+list_cleanup:
+ if (local_list && rv<0)
+ ACL_NameListDestroy(errp, local_list);
+ if (file)
+ close_file_buf(file, filename, "rb", block);
+
+ return rv;
+}
+
+/*
+ * Changes method to method plus DBTYPE, and registers
+ * databases.
+ *
+ * Input:
+ * errp error stack
+ * acl_list Target ACL list handle
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_ListPostParseForAuth(NSErr_t *errp, ACLListHandle_t *acl_list )
+{
+ ACLHandle_t *acl;
+ ACLWrapper_t *wrap;
+ ACLExprHandle_t *expr;
+ char *method;
+ char *database;
+ int rv;
+ ACLDbType_t *dbtype;
+ ACLMethod_t *methodtype;
+
+ if ( acl_list == NULL )
+ return(0);
+
+ for ( wrap = acl_list->acl_list_head; wrap; wrap = wrap->wrap_next ) {
+
+ acl = wrap->acl;
+ if ( acl == NULL )
+ continue;
+
+ for ( expr = acl->expr_list_head; expr; expr = expr->expr_next ) {
+
+ if ( expr->expr_type != ACL_EXPR_TYPE_AUTH ||
+ expr->expr_auth == NULL)
+ continue;
+
+ rv = PListGetValue(expr->expr_auth, ACL_ATTR_METHOD_INDEX,
+ (void **) &method, NULL);
+ if ( rv >= 0 ) {
+ methodtype = (ACLMethod_t *)PERM_MALLOC(sizeof(ACLMethod_t));
+ rv = ACL_MethodFind(errp, method, methodtype);
+ if (rv) {
+ nserrGenerate(errp, ACLERRUNDEF, ACLERR3800, ACL_Program,
+ 3, acl->tag, "method", method);
+ PERM_FREE(methodtype);
+ return(ACLERRUNDEF);
+ }
+
+ rv = PListSetValue(expr->expr_auth, ACL_ATTR_METHOD_INDEX,
+ methodtype, NULL);
+ if ( rv < 0 ) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR3810, ACL_Program,
+ 0);
+ return(ACLERRNOMEM);
+ }
+ PERM_FREE(method);
+ }
+
+ rv = PListGetValue(expr->expr_auth, ACL_ATTR_DATABASE_INDEX,
+ (void **) &database, NULL);
+
+ if (rv < 0) continue;
+
+ /* The following function lets user use databases which are
+ * not registered by their administrators. This also fixes
+ * the backward compatibility.
+ */
+ dbtype = (ACLDbType_t *)PERM_MALLOC(sizeof(ACLDbType_t));
+ rv = ACL_RegisterDbFromACL(errp, (const char *) database,
+ dbtype);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRUNDEF, ACLERR3800, ACL_Program,
+ 3, acl->tag, "database", database);
+ PERM_FREE(dbtype);
+ return(ACLERRUNDEF);
+ }
+
+ rv = PListInitProp(expr->expr_auth, ACL_ATTR_DBTYPE_INDEX, ACL_ATTR_DBTYPE,
+ dbtype, NULL);
+ if ( rv < 0 ) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR3810, ACL_Program,
+ 0);
+ return(ACLERRNOMEM);
+ }
+
+ }
+
+ }
+
+ return(0);
+
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output Authorization Expression Rights "right, right"
+ */
+
+static int
+acl_decompose_expr_arg( acl_string_t *str_t, ACLExprHandle_t *expr )
+{
+int ii;
+
+ if ( expr->expr_argc <= 0 ) {
+ return(ACLERRINTERNAL);
+ }
+
+ if ( expr->expr_type == ACL_EXPR_TYPE_RESPONSE ) {
+ acl_to_str_append(str_t, expr->expr_argv[0]);
+ acl_to_str_append(str_t, " \"");
+ acl_to_str_append(str_t, expr->expr_argv[1]);
+ acl_to_str_append(str_t, "\";\n");
+ return(0);
+ }
+
+ for (ii = 0; ii < expr->expr_argc; ii++) {
+ acl_to_str_append(str_t, expr->expr_argv[ii]);
+ if ( ii < expr->expr_argc - 1 ) {
+ acl_to_str_append(str_t, ",");
+ }
+ }
+ acl_to_str_append(str_t, ";\n");
+
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Walks through the authentication statement PList_t and
+ * prints the structure to a string.
+ */
+
+static void
+acl_decompose_auth_expr(char *lval, const void *rval, void *user_data)
+{
+ acl_string_t * p_aclstr = (acl_string_t *) user_data;
+ // ####
+
+ acl_to_str_append(p_aclstr, " ");
+ acl_to_str_append(p_aclstr, lval);
+ acl_to_str_append(p_aclstr, "=\"");
+ acl_to_str_append(p_aclstr, (char *) rval);
+ acl_to_str_append(p_aclstr, "\"");
+
+ return;
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output the logic part of the authencation statement to a string.
+ */
+
+static int
+acl_decompose_auth_logic( acl_string_t * str_t, ACLExprHandle_t *expr)
+{
+
+ if ( expr->expr_auth == NULL )
+ return(0);
+
+ acl_to_str_append(str_t, "exprs");
+ PListEnumerate(expr->expr_auth, acl_decompose_auth_expr, (void *) str_t);
+ acl_to_str_append(str_t, ";\n");
+
+ return(0);
+}
+
+/*
+ * LOCAL FUNCTION
+ *
+ * Output the logic part of the authorization statement to a string.
+ */
+
+static int
+acl_decompose_expr_logic( acl_string_t *str_t, ACLExprHandle_t *expr, ACLExprStack_t *expr_stack)
+{
+int rv = 0;
+int ii;
+
+ expr_stack->stack_index = 0;
+ expr_stack->found_subexpression = 0;
+ expr_stack->last_subexpression = -1;
+
+ for (ii = 0; ii < expr->expr_raw_index; ii++) {
+ rv = acl_reduce_expr_logic(expr_stack, &expr->expr_raw[ii]);
+ if (rv) break;
+ }
+
+ if (!rv && expr_stack->expr_text[0]) {
+ acl_to_str_append(str_t, "exprs ");
+ acl_to_str_append(str_t, expr_stack->expr_text[0]);
+ acl_to_str_append(str_t, ";\n");
+ PERM_FREE(expr_stack->expr_text[0]);
+ }
+
+ return(rv);
+}
+
+static int
+acl_decompose(acl_string_t *str_t, ACLListHandle_t *acl_list)
+{
+ACLWrapper_t *wrap;
+ACLHandle_t *acl;
+ACLExprHandle_t *expr;
+int rv = 0;
+ACLExprStack_t *expr_stack;
+
+ expr_stack = (ACLExprStack_t *) PERM_MALLOC(sizeof(ACLExprStack_t));
+ if ( expr_stack == NULL )
+ return(ACLERRNOMEM);
+
+ if ( acl_list->acl_list_head == NULL ) {
+ PERM_FREE(expr_stack);
+ return(0);
+ }
+
+ acl_to_str_append(str_t, "version 3.0;");
+ for (wrap = acl_list->acl_list_head; wrap && !rv;
+ wrap = wrap->wrap_next ) {
+ acl = wrap->acl;
+ if ( acl->tag ) {
+ acl_to_str_append(str_t, "\nname \"");
+ acl_to_str_append(str_t, acl->tag);
+ acl_to_str_append(str_t, "\";\n");
+ } else {
+ acl_to_str_append(str_t, "\nname;\n");
+ }
+
+ for (expr = acl->expr_list_head; expr && rv == 0;
+ expr = expr->expr_next ) {
+
+ switch (expr->expr_type) {
+ case ACL_EXPR_TYPE_DENY:
+ acl_to_str_append(str_t, "type deny;\nrights ");
+ if ( (rv = acl_decompose_expr_arg(str_t, expr)) < 0 )
+ break;
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute true;\n");
+ rv = acl_decompose_expr_logic(str_t, expr, expr_stack);
+ break;
+ case ACL_EXPR_TYPE_ALLOW:
+ acl_to_str_append(str_t, "type allow;\nrights ");
+ if ( (rv = acl_decompose_expr_arg(str_t, expr)) < 0 )
+ break;
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute true;\n");
+ rv = acl_decompose_expr_logic(str_t, expr, expr_stack);
+ break;
+ case ACL_EXPR_TYPE_AUTH:
+ acl_to_str_append(str_t, "type authenticate;\nattrs ");
+ if ( (rv = acl_decompose_expr_arg(str_t, expr)) < 0 )
+ break;
+ if ( IS_ABSOLUTE(expr->expr_flags) )
+ acl_to_str_append(str_t, "absolute true;\n");
+ rv = acl_decompose_auth_logic(str_t, expr);
+ break;
+ case ACL_EXPR_TYPE_RESPONSE:
+ acl_to_str_append(str_t, "type response;\nattrs ");
+ rv = acl_decompose_expr_arg(str_t, expr);
+ break;
+ }
+ }
+ }
+
+ PERM_FREE(expr_stack);
+ return(rv);
+}
+
+/*
+ * Converts an ACLListHandle_t to a parameter list suitable for passing
+ * to the ACL UI.
+ *
+ * Input:
+ * errp error stack
+ * acl a pointer to a string, holds the result of the
+ * decomposition.
+ * acl_list Target ACL list handle
+ * Returns:
+ * 0 success
+ * < 0 failure
+ */
+
+NSAPI_PUBLIC int
+ACL_Decompose(NSErr_t *errp, char **acl, ACLListHandle_t *acl_list)
+{
+ int rv ;
+ acl_string_t aclstr={NULL,0,0};
+
+ if ( acl_list == NULL || acl == NULL )
+ return(ACLERRUNDEF);
+
+ rv = acl_decompose(&aclstr, acl_list);
+ *acl = aclstr.str;
+
+ return ( rv );
+}
+
+/*
+ * The following routines are used to validate input parameters. They always
+ * return 1, or cause an NS_ASSERT failure. The proper way to use them is
+ * with an NS_ASSERT in the calling function. E.g.
+ * NS_ASSERT(ACL_AssertAcllist(acllist));
+ */
+
+int
+ACL_AssertAcllist(ACLListHandle_t *acllist)
+{
+ ACLWrapper_t *wrap;
+
+ if (acllist == ACL_LIST_NO_ACLS) return 1;
+ NS_ASSERT(acllist);
+ NS_ASSERT(acllist->acl_list_head);
+ NS_ASSERT(acllist->acl_list_tail);
+ NS_ASSERT(acllist->acl_count);
+ NS_ASSERT(acllist->ref_count > 0);
+
+ for (wrap=acllist->acl_list_head; wrap; wrap=wrap->wrap_next) {
+ NS_ASSERT(ACL_AssertAcl(wrap->acl));
+ }
+
+ /* Artificially limit ACL lists to 10 ACLs for now */
+ NS_ASSERT(acllist->acl_count < 10);
+
+ return 1;
+}
+
+int
+ACL_AssertAcl(ACLHandle_t *acl)
+{
+ NS_ASSERT(acl);
+ NS_ASSERT(acl->ref_count);
+ NS_ASSERT(acl->expr_count);
+ NS_ASSERT(acl->expr_list_head);
+ NS_ASSERT(acl->expr_list_tail);
+
+ return 1;
+}
+
+static PList_t ACLAttr2IndexPList = NULL;
+
+int
+ACL_InitAttr2Index(void)
+{
+ int i;
+
+ if (ACLAttr2IndexPList) return 0;
+
+ ACLAttr2IndexPList = PListNew(NULL);
+ for (i = 1; i < ACL_ATTR_INDEX_MAX; i++) {
+ PListInitProp(ACLAttr2IndexPList, NULL, ACLAttrTable[i], (const void *)i, NULL);
+ }
+
+ return 0;
+}
+
+/*
+ * Attempt to locate the index number for one of the known attribute names
+ * that are stored in plists. If we can't match it, just return 0.
+ */
+int
+ACL_Attr2Index(const char *attrname)
+{
+ int index = 0;
+
+ if ( ACLAttr2IndexPList ) {
+ PListFindValue(ACLAttr2IndexPList, attrname, (void **)&index, NULL);
+ if (index < 0) index = 0;
+ }
+ return index;
+}
diff --git a/lib/libaccess/aclutil.cpp b/lib/libaccess/aclutil.cpp
new file mode 100644
index 00000000..8d30fffb
--- /dev/null
+++ b/lib/libaccess/aclutil.cpp
@@ -0,0 +1,223 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Source file for the TimeOfDay and DayOfWeek LAS drivers
+ */
+
+#include <netsite.h>
+#include <base/crit.h>
+/* #include <plhash.h> */
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/las.h>
+#include <libaccess/nserror.h>
+#include "aclutil.h"
+
+/* Generic evaluator of comparison operators in attribute evaluation
+ * statements.
+ * INPUT
+ * CmpOp_t ACL_TOKEN_EQ, ACL_TOKEN_NE etc.
+ * result 0 if equal, >0 if real > pattern, <0 if
+ * real < pattern.
+ * RETURNS
+ * LAS_EVAL_TRUE or LAS_EVAL_FALSE or LAS_EVAL_INVALID
+ * DEBUG
+ * Can add asserts that the strcmp failure cases are one of the
+ * remaining legal comparators.
+ */
+int
+evalComparator(CmpOp_t ctok, int result)
+{
+ if (result == 0) {
+ switch(ctok) {
+ case CMP_OP_EQ:
+ case CMP_OP_GE:
+ case CMP_OP_LE:
+ return LAS_EVAL_TRUE;
+ case CMP_OP_NE:
+ case CMP_OP_GT:
+ case CMP_OP_LT:
+ return LAS_EVAL_FALSE;
+ default:
+ return LAS_EVAL_INVALID;
+ }
+ } else if (result > 0) {
+ switch(ctok) {
+ case CMP_OP_GT:
+ case CMP_OP_GE:
+ case CMP_OP_NE:
+ return LAS_EVAL_TRUE;
+ case CMP_OP_LT:
+ case CMP_OP_LE:
+ case CMP_OP_EQ:
+ return LAS_EVAL_FALSE;
+ default:
+ return LAS_EVAL_INVALID;
+ }
+ } else { /* real < pattern */
+ switch(ctok) {
+ case CMP_OP_LT:
+ case CMP_OP_LE:
+ case CMP_OP_NE:
+ return LAS_EVAL_TRUE;
+ case CMP_OP_GT:
+ case CMP_OP_GE:
+ case CMP_OP_EQ:
+ return LAS_EVAL_FALSE;
+ default:
+ return LAS_EVAL_INVALID;
+ }
+ }
+}
+
+
+/* Takes a string and returns the same string with all uppercase
+* letters converted to lowercase.
+*/
+void
+makelower(char *string)
+{
+ while (*string) {
+ *string = tolower(*string);
+ string++;
+ }
+}
+
+
+/* Given an LAS_EVAL_* value, translates to ACL_RES_* */
+int
+EvalToRes(int value)
+{
+ switch (value) {
+ case LAS_EVAL_TRUE:
+ return ACL_RES_ALLOW;
+ case LAS_EVAL_FALSE:
+ return ACL_RES_DENY;
+ case LAS_EVAL_DECLINE:
+ return ACL_RES_FAIL;
+ case LAS_EVAL_FAIL:
+ return ACL_RES_FAIL;
+ case LAS_EVAL_INVALID:
+ return ACL_RES_INVALID;
+ case LAS_EVAL_NEED_MORE_INFO:
+ return ACL_RES_DENY;
+ default:
+ NS_ASSERT(1);
+ return ACL_RES_ERROR;
+ }
+}
+
+const char *comparator_string (int comparator)
+{
+ static char invalid_cmp[32];
+
+ switch(comparator) {
+ case CMP_OP_EQ: return "CMP_OP_EQ";
+ case CMP_OP_NE: return "CMP_OP_NE";
+ case CMP_OP_GT: return "CMP_OP_GT";
+ case CMP_OP_LT: return "CMP_OP_LT";
+ case CMP_OP_GE: return "CMP_OP_GE";
+ case CMP_OP_LE: return "CMP_OP_LE";
+ default:
+ sprintf(invalid_cmp, "unknown comparator %d", comparator);
+ return invalid_cmp;
+ }
+}
+
+/* Return the pointer to the next token after replacing the following 'delim'
+ * char with NULL.
+ * WARNING - Modifies the first parameter */
+char *acl_next_token (char **ptr, char delim)
+{
+ char *str = *ptr;
+ char *token = str;
+ char *comma;
+
+ if (!token) { *ptr = 0; return 0; }
+
+ /* ignore leading whitespace */
+ while(*token && isspace(*token)) token++;
+
+ if (!*token) { *ptr = 0; return 0; }
+
+ if ((comma = strchr(token, delim)) != NULL) {
+ *comma++ = 0;
+ }
+
+ {
+ /* ignore trailing whitespace */
+ int len = strlen(token);
+ char *sptr = token+len-1;
+
+ while(*sptr == ' ' || *sptr == '\t') *sptr-- = 0;
+ }
+
+ *ptr = comma;
+ return token;
+}
+
+
+/* Returns a pointer to the next token and it's length */
+/* tokens are separated by 'delim' characters */
+/* ignores whitespace surrounding the tokens */
+const char *acl_next_token_len (const char *ptr, char delim, int *len)
+{
+ const char *str = ptr;
+ const char *token = str;
+ const char *comma;
+
+ *len = 0;
+
+ if (!token) { return 0; }
+
+ /* ignore leading whitespace */
+ while(*token && isspace(*token)) token++;
+
+ if (!*token) { return 0; }
+ if (*token == delim) { return token; } /* str starts with delim! */
+
+ if ((comma = strchr(token, delim)) != NULL) {
+ *len = comma - token;
+ }
+ else {
+ *len = strlen(token);
+ }
+
+ {
+ /* ignore trailing whitespace */
+ const char *sptr = token + *len - 1;
+
+ while(*sptr == ' ' || *sptr == '\t') {
+ sptr--;
+ (*len)--;
+ }
+ }
+
+ return token;
+}
+
+/* acl_get_req_time --
+ * If the REQ_TIME is available on the 'resource' plist, return it.
+ * Otherwise, make a system call to get the time and insert the time on the
+ * 'resource' PList. Allocate the time_t structure using the 'resource'
+ * PList's pool.
+ */
+time_t *acl_get_req_time (PList_t resource)
+{
+ time_t *req_time = 0;
+ int rv = PListGetValue(resource, ACL_ATTR_TIME_INDEX, (void **)&req_time,
+ NULL);
+
+ if (rv < 0) {
+ req_time = (time_t *)pool_malloc(PListGetPool(resource), sizeof(time_t));
+ time(req_time);
+ PListInitProp(resource, ACL_ATTR_TIME_INDEX, ACL_ATTR_TIME,
+ (void *)req_time, NULL);
+ }
+
+ return req_time;
+}
diff --git a/lib/libaccess/aclutil.h b/lib/libaccess/aclutil.h
new file mode 100644
index 00000000..34a1d0a6
--- /dev/null
+++ b/lib/libaccess/aclutil.h
@@ -0,0 +1,25 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef ACLUTIL_H
+#define ACLUTIL_H
+
+NSPR_BEGIN_EXTERN_C
+
+int evalComparator(CmpOp_t ctok, int result);
+void makelower(char *string);
+int EvalToRes(int value);
+const char *comparator_string (int comparator);
+
+/*Warning: acl_next_token modifies 'ptr' */
+char *acl_next_token (char **ptr, char delim);
+
+const char *acl_next_token_len (const char *ptr,
+ char delim, int *len);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/attrec.cpp b/lib/libaccess/attrec.cpp
new file mode 100644
index 00000000..8911e896
--- /dev/null
+++ b/lib/libaccess/attrec.cpp
@@ -0,0 +1,309 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (attrec.c)
+ *
+ * This module contains routines for encoding and decoding
+ * attribute records. See attrec.h for a description of attribute
+ * records.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#define __PRIVATE_ATTREC
+#include "libaccess/attrec.h"
+
+/*
+ * Description (NTS_Length)
+ *
+ * This function returns the length of a null-terminated string.
+ * The length includes the terminating null octet.
+ *
+ * Use of the NTSLENGTH() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * nts - a pointer to the null-terminate string
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The length of the string. If 'nts' is null, the value is one,
+ * since there is always a null octet.
+ */
+
+int NTS_Length(NTS_t nts)
+{
+ return ((nts) ? strlen((const char *)nts) + 1 : 1);
+}
+
+/*
+ * Description (NTS_Decode)
+ *
+ * This function decodes a null-terminated string from a specified
+ * attribute record buffer. It copies the string into a dynamically
+ * allocated buffer, if 'pnts' is not null, and returns a pointer
+ * to it. The return value of the function is a pointer to the
+ * octet following the NTS in the attribute record buffer.
+ *
+ * Use of the NTSDECODE() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * cp - pointer into the attribute record buffer
+ * pnts - pointer to returned reference to decoded
+ * NTS, or null, if the decoded NTS is not
+ * to be copied to a dynamic buffer
+ *
+ * Returns:
+ *
+ * The function return value is a pointer to the octet following
+ * the NTS in the attribute record buffer. A pointer to a
+ * dynamically allocated buffer containing the decoded NTS will
+ * be returned through 'pnts', if it is non-null. This returned
+ * pointer will be null if the NTS contains only a terminating
+ * octet.
+ */
+
+ATR_t NTS_Decode(ATR_t cp, NTS_t * pnts)
+{
+ NTS_t nts = 0;
+ int len = NTSLENGTH(cp); /* length of the string */
+
+ /* Are we going to return a copy of the string? */
+ if (pnts) {
+
+ /* Yes, is it more than just a null octet? */
+ if (len > 1) {
+
+ /* Yes, allocate a buffer and copy the string to it */
+ nts = (NTS_t)MALLOC(len);
+ if (nts) {
+ memcpy((void *)nts, (void *)cp, len);
+ }
+ }
+
+ /* Return a pointer to the copied string, or null */
+ *pnts = nts;
+ }
+
+ /* Return pointer to octet after string */
+ return cp + len;
+}
+
+/*
+ * Description (NTS_Encode)
+ *
+ * This function encodes a null-terminated string into a specified
+ * attribute record buffer. It returns a pointer to the octet
+ * following the encoding.
+ *
+ * Use of the NTSENCODE() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * cp - pointer into the attribute record buffer
+ * nts - pointer to the string to be encoded
+ *
+ * Returns:
+ *
+ * A pointer to the octet following the encoding in the attribute
+ * record buffer is returned.
+ */
+
+ATR_t NTS_Encode(ATR_t cp, NTS_t nts)
+{
+
+ /* Is the string pointer null? */
+ if (nts) {
+ int len = NTSLENGTH(nts);
+
+ /* No, copy the string to the attribute record buffer */
+ memcpy((void *)cp, (void *)nts, len);
+
+ /* Get pointer to octet after it */
+ cp += len;
+ }
+ else {
+
+ /* A null pointer indicates an empty NTS, i.e. just a null octet */
+ *cp++ = 0;
+ }
+
+ /* Return a pointer to the octet after the encoding */
+ return cp;
+}
+
+/*
+ * Description (USI_Decode)
+ *
+ * This function decodes an unsigned integer value from a specified
+ * attribute record buffer.
+ *
+ * Use of the USIDECODE() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * cp - pointer into the attribute record buffer
+ * pval - pointer to returned integer value
+ *
+ * Returns:
+ *
+ * If 'pval' is not null, the decoded integer value is returned
+ * in the referenced location. The function return value is a
+ * pointer to the octet following the USI encoding in the attribute
+ * record buffer.
+ */
+
+ATR_t USI_Decode(ATR_t cp, USI_t * pval)
+{
+ int val;
+
+ /* Is this a length value? */
+ if (*(cp) & 0x80) {
+ int i;
+ int len;
+
+ /* Yes, build the value from the indicated number of octets */
+ len = *cp++ & 0x7;
+ val = 0;
+ for (i = 0; i < len; ++i) {
+ val <<= 8;
+ val |= (cp[i] & 0xff);
+ }
+ cp += len;
+ }
+ else {
+
+ /* This octet is the value */
+ val = *cp++;
+ }
+
+ /* Return the value if there's a place to put it */
+ if (pval) *pval = val;
+
+ /* Return a pointer to the next item in the attribute record */
+ return cp;
+}
+
+/*
+ * Description (USI_Encode)
+ *
+ * This function encodes an unsigned integer value into a specified
+ * attribute record buffer.
+ *
+ * Use of the USIENCODE() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * cp - pointer into the attribute record buffer
+ * val - the value to be encoded
+ *
+ * Returns:
+ *
+ * A pointer to the octet following the generated encoding in the
+ * attribute record buffer is returned.
+ */
+
+ATR_t USI_Encode(ATR_t cp, USI_t val)
+{
+ /* Check size of value to be encoded */
+ if (val <= 0x7f) *cp++ = val;
+ else if (val <= 0xff) {
+ /* Length plus 8-bit value */
+ *cp++ = 0x81;
+ *cp++ = val;
+ }
+ else if (val <= 0xffff) {
+ /* Length plus 16-bit value */
+ *cp++ = 0x82;
+ cp[1] = val & 0xff;
+ val >>= 8;
+ cp[0] = val & 0xff;
+ cp += 2;
+ }
+ else if (val <= 0xffffff) {
+ /* Length plus 24-bit value */
+ *cp++ = 0x83;
+ cp[2] = val & 0xff;
+ val >>= 8;
+ cp[1] = val & 0xff;
+ val >>= 8;
+ cp[0] = val & 0xff;
+ cp += 3;
+ }
+ else {
+ /* Length plus 32-bit value */
+ *cp++ = 0x84;
+ cp[3] = val & 0xff;
+ val >>= 8;
+ cp[2] = val & 0xff;
+ val >>= 8;
+ cp[1] = val & 0xff;
+ val >>= 8;
+ cp[0] = val & 0xff;
+ cp += 4;
+ }
+
+ /* Return a pointer to the next position in the attribute record */
+ return cp;
+}
+
+/*
+ * Description (USI_Insert)
+ *
+ * This function is a variation of USI_Encode() that always generates
+ * the maximum-length encoding for USI value, regardless of the
+ * actual specified value. For arguments, returns, see USI_Encode().
+ *
+ * Use of the USIINSERT() macro is recommended. The USIALLOC() macro
+ * returns the number of octets that USIINSERT() will generate.
+ */
+
+ATR_t USI_Insert(ATR_t cp, USI_t val)
+{
+ int i;
+
+ assert(USIALLOC() == 5);
+
+ *cp++ = 0x84;
+ for (i = 3; i >= 0; --i) {
+ cp[i] = val & 0xff;
+ val >>= 8;
+ }
+
+ return cp + 5;
+}
+
+/*
+ * Description (USI_Length)
+ *
+ * This function returns the number of octets required to encode
+ * an unsigned integer value.
+ *
+ * Use of the USILENGTH() macro is recommended (see attrec.h).
+ *
+ * Arguments:
+ *
+ * val - the unsigned integer value
+ *
+ * Returns:
+ *
+ * The number of octets required to encode the specified value is
+ * returned.
+ */
+
+int USI_Length(USI_t val)
+{
+ return (((USI_t)(val) <= 0x7f) ? 1
+ : (((USI_t)(val) <= 0xff) ? 2
+ : (((USI_t)(val) <= 0xffff) ? 3
+ : (((USI_t)(val) <= 0xffffff) ? 4
+ : 5))));
+}
+
diff --git a/lib/libaccess/authdb.cpp b/lib/libaccess/authdb.cpp
new file mode 100644
index 00000000..0d27635d
--- /dev/null
+++ b/lib/libaccess/authdb.cpp
@@ -0,0 +1,339 @@
+/** 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 <string.h>
+
+#include <plhash.h>
+
+#include <netsite.h>
+#include "permhash.h"
+#include <ldaputil/errors.h>
+#include <ldaputil/certmap.h>
+#include <ldaputil/dbconf.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/authdb.h>
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include <libaccess/acl.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+#define BIG_LINE 1024
+
+char *ACL_default_dbname = 0;
+ACLDbType_t ACL_default_dbtype = ACL_DBTYPE_INVALID;
+ACLMethod_t ACL_default_method = ACL_METHOD_INVALID;
+int acl_registered_dbcnt = 0;
+
+extern int acl_registered_names(PLHashTable *ht, int count, char ***names);
+
+/************************** Database Types *************************/
+
+#define databaseNamesHashTable ACLDbNameHash
+
+int acl_num_databases ()
+{
+ return acl_registered_dbcnt;
+}
+
+static int reg_dbname_internal (NSErr_t *errp, ACLDbType_t dbtype,
+ const char *dbname, const char *url,
+ PList_t plist)
+{
+ DbParseFn_t parseFunc;
+ void *db;
+ int rv;
+ AuthdbInfo_t *authdb_info;
+
+ if (!ACL_DbTypeIsRegistered(errp, dbtype)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4400, ACL_Program, 2, XP_GetAdminStr(DBT_DbtypeNotDefinedYet), dbname);
+ return -1;
+ }
+
+ parseFunc = ACL_DbTypeParseFn(errp, dbtype);
+
+ if (!parseFunc) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4400, ACL_Program, 2, XP_GetAdminStr(DBT_DbtypeNotDefinedYet), dbname);
+ return -1;
+ }
+
+ rv = (*parseFunc)(errp, dbtype, dbname, url, plist, (void **)&db);
+
+ if (rv < 0) {
+ /* plist contains error message/code */
+ return rv;
+ }
+
+ /* Store the db returned by the parse function in the hash table.
+ */
+
+ authdb_info = (AuthdbInfo_t *)pool_malloc(ACL_DATABASE_POOL, sizeof(AuthdbInfo_t));
+
+ if (!authdb_info) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4420, ACL_Program, 0);
+ return -1;
+ }
+
+ authdb_info->dbname = pool_strdup(ACL_DATABASE_POOL, dbname);
+ authdb_info->dbtype = dbtype;
+ authdb_info->dbinfo = db; /* value returned from parseFunc */
+
+ PR_HashTableAdd(ACLDbNameHash, authdb_info->dbname, authdb_info);
+ acl_registered_dbcnt++;
+
+ return 0;
+}
+
+NSAPI_PUBLIC int ACL_DatabaseRegister (NSErr_t *errp, ACLDbType_t dbtype,
+ const char *dbname, const char *url,
+ PList_t plist)
+{
+ if (!dbname || !*dbname) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4500, ACL_Program, 1, XP_GetAdminStr(DBT_DatabaseRegisterDatabaseNameMissing));
+ return -1;
+ }
+
+ return reg_dbname_internal(errp, dbtype, dbname, url, plist);
+}
+
+NSAPI_PUBLIC int
+ACL_DatabaseNamesGet(NSErr_t *errp, char ***names, int *count)
+{
+ *count = acl_registered_dbcnt;
+ return acl_registered_names (ACLDbNameHash, *count, names);
+}
+
+NSAPI_PUBLIC int
+ACL_DatabaseNamesFree(NSErr_t *errp, char **names, int count)
+{
+ int i;
+
+ for (i = count-1; i; i--) FREE(names[i]);
+
+ FREE(names);
+ return 0;
+}
+
+/* try to determine the dbtype from the database url */
+static int acl_url_to_dbtype (const char *url, ACLDbType_t *dbtype_out)
+{
+ ACLDbType_t dbtype;
+ NSErr_t *errp = 0;
+
+ *dbtype_out = dbtype = ACL_DBTYPE_INVALID;
+ if (!url || !*url) return -1;
+
+ // urls with ldap:, ldaps: and ldapdb: are all of type ACL_DBTYPE_LDAP.
+ if (!strncmp(url, URL_PREFIX_LDAP, URL_PREFIX_LDAP_LEN))
+ dbtype = ACL_DbTypeLdap;
+ else {
+ /* treat prefix in the url as dbtype if it has been registered.
+ */
+ int prefix_len = strcspn(url, ":");
+ char dbtypestr[BIG_LINE];
+
+ if (prefix_len) {
+ strncpy(dbtypestr, url, prefix_len);
+ dbtypestr[prefix_len] = 0;
+
+ if (!ACL_DbTypeFind(errp, dbtypestr, &dbtype)) {
+ /* prefix is not a registered dbtype */
+ dbtype = ACL_DBTYPE_INVALID;
+ }
+ }
+ }
+
+ if (ACL_DbTypeIsEqual(errp, dbtype, ACL_DBTYPE_INVALID)) {
+ /* try all the registered parse functions to determine the dbtype */
+ }
+
+ if (ACL_DbTypeIsEqual(errp, dbtype, ACL_DBTYPE_INVALID)) return -1;
+
+ *dbtype_out = dbtype;
+ return 0;
+}
+
+NSAPI_PUBLIC int ACL_RegisterDbFromACL (NSErr_t *errp, const char *url,
+ ACLDbType_t *dbtype)
+{
+ /* If the database by name url is already registered, don't do anything.
+ * If it is not registered, determine the dbtype from the url.
+ * If the dbtype can be determined, register the database with dbname same
+ * as the url. Return the dbtype.
+ */
+ void *db;
+ int rv;
+ PList_t plist;
+
+ if (ACL_DatabaseFind(errp, url, dbtype, &db) == LAS_EVAL_TRUE)
+ return 0;
+
+ /* The database is not registered yet. Parse the url to find out its
+ * type. If parsing fails, return failure.
+ */
+ rv = acl_url_to_dbtype(url, dbtype);
+
+ if (rv < 0) {
+ return rv;
+ }
+
+ plist = PListNew(NULL);
+ rv = ACL_DatabaseRegister(errp, *dbtype, url, url, plist);
+ PListDestroy(plist);
+ return rv;
+}
+
+NSAPI_PUBLIC int ACL_DatabaseFind(NSErr_t *errp, const char *name,
+ ACLDbType_t *dbtype, void **db)
+{
+ AuthdbInfo_t *info;
+
+ *dbtype = ACL_DBTYPE_INVALID;
+ *db = 0;
+
+ if (ACLDbNameHash) {
+ info = (AuthdbInfo_t *)PR_HashTableLookup(ACLDbNameHash,
+#ifdef NSPR20
+ name
+#else
+ (char *)name
+#endif
+ );
+
+ if (info) {
+ *dbtype = info->dbtype;
+ *db = info->dbinfo;
+
+ return LAS_EVAL_TRUE;
+ }
+ }
+
+ return LAS_EVAL_FAIL;
+}
+
+
+NSAPI_PUBLIC int ACL_ReadDbMapFile (NSErr_t *errp, const char *map_file,
+ int default_only)
+{
+ DBConfInfo_t *info;
+ DBConfDBInfo_t *db_info;
+ DBPropVal_t *propval;
+ PList_t plist;
+ int rv;
+ int seen_default = 0;
+
+ if (default_only)
+ rv = dbconf_read_default_dbinfo(map_file, &db_info);
+ else
+ rv = dbconf_read_config_file(map_file, &info);
+
+ if (rv != LDAPU_SUCCESS) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4600, ACL_Program, 3, XP_GetAdminStr(DBT_ReadDbMapFileErrorReadingFile), map_file, ldapu_err2string(rv));
+ return -1;
+ }
+
+ rv = 0;
+
+ if (!default_only)
+ db_info = info->firstdb;
+
+ while(db_info) {
+ char *url = db_info->url;
+ char *dbname = db_info->dbname;
+ ACLDbType_t dbtype;
+
+ /* process db_info */
+ if (url) {
+ rv = acl_url_to_dbtype(url, &dbtype);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4610, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileCouldntDetermineDbtype), url);
+ break;
+ }
+ }
+ else {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4620, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileMissingUrl), dbname);
+ rv = -1;
+ break;
+ }
+
+ /* convert any property-value pairs in db_info into plist */
+ plist = PListNew(NULL);
+ propval = db_info->firstprop;
+
+ while(propval) {
+ if (propval->prop) {
+ PListInitProp(plist, 0, propval->prop, propval->val, 0);
+ }
+ else {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4630, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileInvalidPropertyPair), dbname);
+ rv = -1;
+ break;
+ }
+ propval = propval->next;
+ }
+
+ if (rv < 0) break;
+
+ /* register the database */
+ rv = ACL_DatabaseRegister(errp, dbtype, dbname, url, plist);
+ PListDestroy(plist);
+
+ if (rv < 0) {
+ /* Failed to register database */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4640, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileRegisterDatabaseFailed), dbname);
+ break;
+ }
+
+ /* If the dbname is "default", set the default_dbtype */
+ if (!strcmp(dbname, DBCONF_DEFAULT_DBNAME)) {
+ if (!ACL_DbTypeIsEqual(errp, dbtype, ACL_DbTypeLdap)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4350, ACL_Program, 1,
+ XP_GetAdminStr(DBT_ReadDbMapFileDefaultDatabaseNotLdap));
+ rv = -1;
+ break;
+ }
+ if (seen_default) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4360, ACL_Program, 1, XP_GetAdminStr(DBT_ReadDbMapFileMultipleDefaultDatabases));
+ rv = -1;
+ break;
+ }
+ seen_default = 1;
+ ACL_DatabaseSetDefault(errp, dbname);
+ }
+
+ db_info = db_info->next;
+ }
+
+ if (!seen_default) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4370, ACL_Program, 1, XP_GetAdminStr(DBT_ReadDbMapFileMissingDefaultDatabase));
+ rv = -1;
+ }
+
+ if (default_only)
+ dbconf_free_dbinfo(db_info);
+ else
+ dbconf_free_confinfo(info);
+
+ return rv;
+}
+
+void
+ACL_DatabaseDestroy(void)
+{
+ pool_destroy(ACL_DATABASE_POOL);
+ ACL_DATABASE_POOL = NULL;
+ ACLDbNameHash = NULL;
+ return;
+}
+
diff --git a/lib/libaccess/avadb.c b/lib/libaccess/avadb.c
new file mode 100644
index 00000000..c0d98704
--- /dev/null
+++ b/lib/libaccess/avadb.c
@@ -0,0 +1,300 @@
+/** 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 <stdlib.h>
+#include <string.h>
+
+#include "libaccess/ava.h"
+#include "libaccess/avadb.h"
+#include "base/session.h"
+#include "base/pblock.h"
+#include "frame/req.h"
+#include "frame/log.h"
+
+#include "libadmin/libadmin.h"
+#include "libaccess/avapfile.h"
+
+#define DB_NAME "AvaMap"
+
+enum {AVA_DB_SUCCESS=0,AVA_DB_FAILURE};
+
+#ifdef XP_UNIX
+#include "mcom_ndbm.h"
+
+USE_NSAPI int AddEntry (char *key, char *value) {
+ datum keyd;
+ datum valued;
+ DBM *db = NULL;
+ char dbpath[150];
+
+ sprintf (dbpath, "%s%c%s", get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ db = dbm_open (dbpath, O_RDWR | O_CREAT, 0644);
+
+ if (!db)
+ return AVA_DB_FAILURE;
+
+ keyd.dptr = key;
+ keyd.dsize = strlen (key) + 1;
+
+ valued.dptr = value;
+ valued.dsize = strlen(value) + 1;
+
+ dbm_store (db, keyd, valued, DBM_REPLACE);
+ dbm_close (db);
+
+ return AVA_DB_SUCCESS;
+}
+
+USE_NSAPI int DeleteEntry (char *key) {
+ datum keyd;
+ DBM *db = NULL;
+ char dbpath[150];
+
+ sprintf (dbpath, "%s%c%s", get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ db = dbm_open (dbpath, O_RDWR, 0644);
+
+ if (!db)
+ return AVA_DB_FAILURE;
+
+ keyd.dptr = key;
+ keyd.dsize = strlen (key) + 1;
+
+ dbm_delete (db, keyd);
+
+ dbm_close (db);
+
+ return AVA_DB_SUCCESS;
+}
+
+USE_NSAPI char *GetValue (char *key) {
+ datum keyd;
+ datum valued;
+ DBM *db = NULL;
+ char dbpath[150];
+
+ sprintf (dbpath, "%s%c%s", get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ db = dbm_open (dbpath, O_RDONLY, 0644);
+
+ if (!db)
+ return NULL;
+
+ keyd.dptr = key;
+ keyd.dsize = strlen (key) + 1;
+
+ valued = dbm_fetch (db, keyd);
+
+ dbm_close (db);
+
+ return valued.dptr;
+}
+
+#else
+
+#include <stdio.h>
+
+
+#define lmemcpy memcpy
+#define lmemcmp memcmp
+#define lmemset memset
+
+static int mkhash8(char *x,int len) {
+ unsigned int i,hash = 0;
+ for (i=0; i < len; i++) { hash += x[i]; }
+
+ return (int) (hash & 0xff);
+}
+
+static void mkpath(char *target, char *dir, char sep, char *name) {
+ int len;
+
+ len = strlen(dir);
+ lmemcpy(target,dir,len);
+ target += len;
+
+ *target++ = sep;
+
+ len = strlen(name);
+ lmemcpy(target,name,len);
+ target += len;
+
+ *target = 0;
+}
+
+#define DELETED_LEN 8
+static char DELETED[] = { 0xff, 0x0, 0xff, 0x0, 0xff, 0x0, 0xff , 0x0 };
+
+
+#define RECORD_SIZE 512
+USE_NSAPI int AddEntry (char *key, char *value) {
+ int empty, hash;
+ char dbpath[150];
+ char record[RECORD_SIZE];
+ int key_len, val_len,size;
+ FILE *f;
+
+ mkpath (dbpath, get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ f = fopen(dbpath, "rb+");
+ if (f == NULL) {
+ f = fopen(dbpath,"wb+");
+ }
+
+ if (f == NULL)
+ return AVA_DB_FAILURE;
+
+ key_len = strlen(key)+1;
+ val_len = strlen(value);
+
+ if ((key_len+val_len) > RECORD_SIZE) {
+ fclose(f);
+ return AVA_DB_FAILURE;
+ }
+
+
+ /* now hash the key */
+ hash = mkhash8(key,key_len);
+ empty = -1;
+
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ for (;;) {
+ size= fread(record,1,RECORD_SIZE,f);
+ if (size < RECORD_SIZE) {
+ break;
+ }
+ if (lmemcmp(record,key,key_len) == 0) {
+ break;
+ }
+ if ((empty == -1) && (lmemcmp(record,DELETED,DELETED_LEN) == 0)) {
+ empty = hash;
+ }
+ if (record == 0) {
+ break;
+ }
+ hash++;
+ }
+
+ if (empty != -1) { hash = empty; }
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ /* build the record */
+ lmemset(record,0,RECORD_SIZE);
+
+ lmemcpy(record,key,key_len);
+ lmemcpy(&record[key_len],value,val_len);
+ size= fwrite(record,1,RECORD_SIZE,f);
+ if (size != RECORD_SIZE) {
+ fclose(f);
+ return AVA_DB_FAILURE;
+ }
+ fclose(f);
+
+ return AVA_DB_SUCCESS;
+}
+
+USE_NSAPI int DeleteEntry (char *key) {
+ int found,hash;
+ char dbpath[150];
+ char record[RECORD_SIZE];
+ int key_len,size;
+ FILE *f;
+
+ mkpath (dbpath, get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ f = fopen(dbpath, "rb+");
+
+ if (f == NULL)
+ return AVA_DB_FAILURE;
+
+ key_len = strlen(key)+1;
+
+
+ /* now hash the key */
+ hash = mkhash8(key,key_len);
+ found = 0;
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ for (;;) {
+ size= fread(record,1,RECORD_SIZE,f);
+ if (size < RECORD_SIZE) {
+ break;
+ }
+ if (lmemcmp(record,key,key_len) == 0) {
+ found++;
+ break;
+ }
+ if (record == 0) {
+ break;
+ }
+ hash++;
+ }
+
+ if (!found) {
+ fclose(f);
+ return AVA_DB_SUCCESS;
+ }
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ /* build the record */
+ lmemset(record,0,RECORD_SIZE);
+
+ lmemcpy(record,DELETED,DELETED_LEN);
+ size= fwrite(record,1,RECORD_SIZE,f);
+ if (size != RECORD_SIZE) {
+ fclose(f);
+ return AVA_DB_FAILURE;
+ }
+ fclose(f);
+
+ return AVA_DB_SUCCESS;
+}
+
+USE_NSAPI char *GetValue (char *key) {
+ int hash,size;
+ char dbpath[150];
+ char record[RECORD_SIZE];
+ int key_len,found = 0;
+ FILE *f;
+
+ mkpath (dbpath, get_httpacl_dir(), FILE_PATHSEP, DB_NAME);
+
+ f = fopen(dbpath, "rb");
+
+ if (f == NULL)
+ return NULL;
+
+ key_len = strlen(key)+1;
+
+ /* now hash the key */
+ hash = mkhash8(key,key_len);
+
+ fseek(f,hash*RECORD_SIZE,SEEK_SET);
+
+ for(;;) {
+ size= fread(record,1,RECORD_SIZE,f);
+ if (size < RECORD_SIZE) {
+ break;
+ }
+ if (lmemcmp(record,key,key_len) == 0) {
+ found++;
+ break;
+ }
+ if (record == 0) {
+ break;
+ }
+ hash++;
+ }
+
+ fclose(f);
+ if (!found) return NULL;
+
+ return system_strdup(&record[key_len+1]);
+}
+
+#endif
diff --git a/lib/libaccess/avaparse.y b/lib/libaccess/avaparse.y
new file mode 100644
index 00000000..c28ef165
--- /dev/null
+++ b/lib/libaccess/avaparse.y
@@ -0,0 +1,140 @@
+/** 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 <ctype.h>
+#include <string.h>
+#include "libaccess/ava.h"
+#include "libaccess/avapfile.h"
+#include "netsite.h"
+
+extern int linenum;
+extern char yytext[];
+
+static void AddDefType (int defType, char *defId);
+static void AddAVA (char* userID);
+
+void yyerror(const char* string);
+extern void logerror(const char* string,int num, char *file);
+
+AVAEntry tempEntry;
+AVATable entryTable;
+
+%}
+
+%union {
+ char *string;
+ int num;
+}
+
+%token DEF_C DEF_CO DEF_OU DEF_CN EQ_SIGN DEF_START
+%token DEF_L DEF_E DEF_ST
+%token <string> USER_ID DEF_ID
+
+%type <num> def.type
+
+%start source
+
+%%
+
+source: ava.database
+ |
+ ;
+
+
+ava.database: ava.database ava
+ | ava
+ ;
+
+ava: USER_ID definitions {AddAVA($1);};
+
+definitions: definition.list
+ |
+ ;
+
+definition.list: definition.list definition
+ | definition
+ ;
+
+
+definition: def.type EQ_SIGN DEF_ID {AddDefType($1, $3);};
+
+def.type: DEF_C {$$ = DEF_C; }
+ | DEF_CO {$$ = DEF_CO;}
+ | DEF_OU {$$ = DEF_OU;}
+ | DEF_CN {$$ = DEF_CN;}
+ | DEF_L {$$ = DEF_L; }
+ | DEF_E {$$ = DEF_E; }
+ | DEF_ST {$$ = DEF_ST;}
+ ;
+
+%%
+
+void yyerror(const char* string) {
+ logerror(string,linenum,currFile);
+}
+
+
+void AddDefType (int defType, char *defId) {
+ switch (defType) {
+ case DEF_C:
+ tempEntry.country = defId;
+ break;
+ case DEF_CO:
+ tempEntry.company = defId;
+ break;
+ case DEF_OU:
+ if (tempEntry.numOrgs % ORGS_ALLOCSIZE == 0) {
+ if (tempEntry.numOrgs == 0) {
+ tempEntry.organizations =
+ PERM_MALLOC (sizeof (char*) * ORGS_ALLOCSIZE);
+ } else {
+ char **temp;
+ temp =
+ PERM_MALLOC(sizeof(char*) * (tempEntry.numOrgs + ORGS_ALLOCSIZE));
+ memcpy (temp, tempEntry.organizations,
+ sizeof(char*)*tempEntry.numOrgs);
+ PERM_FREE (tempEntry.organizations);
+ tempEntry.organizations = temp;
+ }
+ }
+ tempEntry.organizations[tempEntry.numOrgs++] = defId;
+ break;
+ case DEF_CN:
+ tempEntry.CNEntry = defId;
+ break;
+ case DEF_E:
+ tempEntry.email = defId;
+ break;
+ case DEF_L:
+ tempEntry.locality = defId;
+ break;
+ case DEF_ST:
+ tempEntry.state = defId;
+ break;
+ default:
+ break;
+ }
+}
+
+void AddAVA (char* userID) {
+ AVAEntry *newAVA;
+
+ newAVA = (AVAEntry*)PERM_MALLOC(sizeof(AVAEntry));
+ if (!newAVA) {
+ yyerror ("Out of Memory in AddAVA");
+ return;
+ }
+ *newAVA = tempEntry;
+ newAVA->userid = userID;
+
+ _addAVAtoTable (newAVA, &entryTable);
+
+ tempEntry.CNEntry = tempEntry.userid = tempEntry.country = tempEntry.company = 0;
+ tempEntry.email = tempEntry.locality = tempEntry.state = NULL;
+ tempEntry.numOrgs = 0;
+}
diff --git a/lib/libaccess/avapfile.c b/lib/libaccess/avapfile.c
new file mode 100644
index 00000000..8c955d9d
--- /dev/null
+++ b/lib/libaccess/avapfile.c
@@ -0,0 +1,428 @@
+/** 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 <stdlib.h>
+#include <string.h>
+
+#include "libaccess/ava.h"
+
+#include "base/session.h"
+#include "base/pblock.h"
+#include "frame/req.h"
+#include "frame/log.h"
+
+#include "libadmin/libadmin.h"
+#include "libaccess/avapfile.h"
+
+#define ALLOC_SIZE 20
+#define SUCCESS 0
+
+struct parsedStruct {
+ char *fileName;
+ AVATable *avaTable;
+};
+
+typedef struct parsedStruct Parsed;
+
+/* globals for yy_error if needed */
+Session *yy_sn = NULL;
+Request *yy_rq = NULL;
+
+/*This will be a dynamic array of parsedStruct*. Re-sizing if necessary.*/
+struct ParsedTable {
+ Parsed **parsedTable;
+ int numEntries;
+};
+
+char *currFile;
+
+static struct ParsedTable parsedFiles = {NULL, 0};
+
+extern AVATable entryTable; /*Table where entries are stored*/
+extern AVAEntry tempEntry; /*Used to restore parser's state*/
+extern linenum;
+
+AVAEntry * AVAEntry_Dup(AVAEntry *entry) {
+ int i;
+ AVAEntry *newAVA = NULL;
+/* copy the AVA entry */
+
+ if (entry) {
+ newAVA = (AVAEntry *) PERM_MALLOC(sizeof(AVAEntry));
+ memset(newAVA,0, sizeof(AVAEntry));
+ newAVA->userid = 0;
+ newAVA->CNEntry = 0;
+ newAVA->email = 0;
+ newAVA->locality = 0;
+ newAVA->state = 0;
+ newAVA->country = 0;
+ newAVA->company = 0;
+ newAVA->organizations = 0;
+ newAVA->numOrgs = 0;
+ if (entry->userid) newAVA->userid = PERM_STRDUP(entry->userid);
+ if (entry->CNEntry) newAVA->CNEntry = PERM_STRDUP(entry->CNEntry);
+ if (entry->email) newAVA->email = PERM_STRDUP(entry->email);
+ if (entry->locality) newAVA->locality = PERM_STRDUP(entry->locality);
+ if (entry->state) newAVA->state = PERM_STRDUP(entry->state);
+ if (entry->country) newAVA->country = PERM_STRDUP(entry->country);
+ if (entry->company) newAVA->company = PERM_STRDUP(entry->company);
+ if (entry->organizations) {
+ newAVA->organizations = PERM_MALLOC(sizeof(char *)*entry->numOrgs);
+ newAVA->numOrgs = entry->numOrgs;
+ for (i=0; i<entry->numOrgs; i++)
+ newAVA->organizations[i] = PERM_STRDUP (entry->organizations[i]);
+ }
+ }
+ return newAVA;
+}
+
+void _addAVAtoTable (AVAEntry *newAVA, AVATable *table) {
+ int i;
+ int insertIndex = -1;
+
+ if (table->numEntries%ENTRIES_ALLOCSIZE == 0) {
+ if (table->numEntries == 0) {
+ table->enteredTable =
+ (AVAEntry**) PERM_MALLOC (sizeof(AVAEntry*) * ENTRIES_ALLOCSIZE);
+ } else {
+ AVAEntry **temp;
+
+ temp =
+ PERM_MALLOC(sizeof(AVAEntry*)*(table->numEntries+ENTRIES_ALLOCSIZE));
+ memmove(temp, table->enteredTable, sizeof(AVAEntry*)*table->numEntries);
+ PERM_FREE(table->enteredTable);
+ table->enteredTable = temp;
+ }
+ }
+
+ for (i=table->numEntries-1; i >= 0; i--) {
+ if (strcmp(newAVA->userid, table->enteredTable[i]->userid) > 0) {
+ insertIndex = i+1;
+ break;
+ } else {
+ table->enteredTable[i+1] = table->enteredTable[i];
+ }
+ }
+
+
+ table->enteredTable[(insertIndex == -1) ? 0 : insertIndex] = newAVA;
+ (table->numEntries)++;
+}
+
+AVATable *AVATableDup(AVATable *table) {
+ AVATable *newTable = (AVATable*)PERM_MALLOC (sizeof(AVATable));
+ /* round the puppy so _addAVAtoTable still works */
+ int size = (table->numEntries + (ENTRIES_ALLOCSIZE-1))/ENTRIES_ALLOCSIZE;
+ int i;
+
+ newTable->enteredTable =
+ (AVAEntry**)PERM_MALLOC(size*ENTRIES_ALLOCSIZE*sizeof(AVAEntry *));
+
+ for (i=0; i < table->numEntries; i++) {
+ newTable->enteredTable[i] = AVAEntry_Dup(table->enteredTable[i]);
+ }
+ newTable->numEntries = table->numEntries;
+ return newTable;
+}
+
+
+
+
+AVAEntry *_getAVAEntry(char *groupName, AVATable *mapTable) {
+ char line[BIG_LINE];
+ int lh, rh, mid, cmp;;
+
+ if (!mapTable) {
+ sprintf (line, "NULL Pointer passed as mapTable when trying to get entry %s", groupName);
+ report_error (SYSTEM_ERROR, "File Not Found", line);
+ }
+
+
+ lh = 0;
+ rh = mapTable->numEntries-1;
+
+ while (lh <= rh) {
+ mid = lh + ((rh-lh)/2);
+ cmp = strcmp(groupName, mapTable->enteredTable[mid]->userid);
+ if (cmp == 0)
+ return mapTable->enteredTable[mid];
+ else if (cmp > 0)
+ lh = mid + 1;
+ else
+ rh = mid - 1;
+ }
+
+ return NULL;
+
+}
+
+AVATable *_getTable (char *fileName) {
+ int lh, rh, mid, cmp;
+ AVATable *table = NULL;
+
+ /*First checks to see if it's already been parsed*/
+
+ lh = 0;
+ rh = parsedFiles.numEntries-1;
+ while (lh <= rh) {
+ mid = lh + ((rh - lh)/2);
+ cmp = strcmp(fileName, parsedFiles.parsedTable[mid]->fileName);
+ if (cmp == SUCCESS) {
+ return parsedFiles.parsedTable[mid]->avaTable;
+ } else if (cmp < SUCCESS) {
+ rh = mid-1;
+ } else {
+ lh = mid+1;
+ }
+ }
+
+ yyin = fopen (fileName, "r");
+
+ if (yyin) {
+ if (!yyparse()) {
+ table = _wasParsed (fileName);
+ table->userdb = NULL;
+ }
+ fclose (yyin);
+ }
+
+ return table;
+}
+
+int _hasBeenParsed (char *aclFileName){
+ return (_getTable(aclFileName) != NULL);
+}
+
+AVATable* _wasParsed (char *inFileName) {
+ Parsed *newEntry;
+ int i;
+
+ if (!inFileName)
+ return NULL;
+
+ newEntry = (Parsed*) PERM_MALLOC (sizeof(Parsed));
+ newEntry->fileName = PERM_STRDUP (inFileName);
+ newEntry->avaTable = AVATableDup(&entryTable);
+
+ if (parsedFiles.numEntries % ALLOC_SIZE == 0) {
+ if (parsedFiles.numEntries) {
+ Parsed **temp;
+
+ temp = PERM_MALLOC (sizeof(Parsed*)*(parsedFiles.numEntries + ALLOC_SIZE));
+ if (!temp)
+ return NULL;
+ memcpy (temp, parsedFiles.parsedTable, sizeof(Parsed*)*parsedFiles.numEntries);
+ PERM_FREE (parsedFiles.parsedTable);
+ parsedFiles.parsedTable = temp;
+ } else {
+ parsedFiles.parsedTable =
+ (Parsed**) PERM_MALLOC (sizeof (Parsed*) * ALLOC_SIZE);
+ if (!parsedFiles.parsedTable)
+ return NULL;
+ }
+ }
+ for (i=parsedFiles.numEntries; i > 0; i--) {
+ if (strcmp(newEntry->fileName,parsedFiles.parsedTable[i-1]->fileName) < 0) {
+ parsedFiles.parsedTable[i] = parsedFiles.parsedTable[i-1];
+ } else {
+ break;
+ }
+ }
+ parsedFiles.parsedTable[i] = newEntry;
+ parsedFiles.numEntries++;
+
+/*Initialize parser structures to resemble that before parse*/
+ entryTable.numEntries = 0;
+ tempEntry.country = tempEntry.company = tempEntry.CNEntry = NULL;
+ tempEntry.email = tempEntry.locality = tempEntry.state = NULL;
+ linenum = 1;
+
+ return newEntry->avaTable;
+}
+
+AVAEntry *_deleteAVAEntry (char *group, AVATable *table) {
+ int removeIndex;
+ int lh, rh, mid, cmp;
+ AVAEntry *entry = NULL;
+
+ if (!group || !table)
+ return NULL;
+
+ lh = 0;
+ rh = table->numEntries - 1;
+
+ while (lh <= rh) {
+ mid = lh + ((rh-lh)/2);
+ cmp = strcmp (group, table->enteredTable[mid]->userid);
+ if (cmp == SUCCESS) {
+ removeIndex = mid;
+ break;
+ } else if (cmp < SUCCESS) {
+ rh = mid-1;
+ } else {
+ lh = mid+1;
+ }
+ }
+
+ if (lh > rh)
+ return NULL;
+
+ entry = table->enteredTable[removeIndex];
+
+ memmove ((char*)(table->enteredTable)+(sizeof(AVAEntry*)*removeIndex),
+ (char*)(table->enteredTable)+(sizeof(AVAEntry*)*(removeIndex+1)),
+ (table->numEntries - removeIndex - 1)*sizeof(AVAEntry*));
+
+ (table->numEntries)--;
+
+ return entry;
+}
+
+void AVAEntry_Free (AVAEntry *entry) {
+ int i;
+
+ if (entry) {
+ if (entry->userid)
+ PERM_FREE (entry->userid);
+ if (entry->CNEntry)
+ PERM_FREE (entry->CNEntry);
+ if (entry->email)
+ PERM_FREE (entry->email);
+ if (entry->locality)
+ PERM_FREE (entry->locality);
+ if (entry->state)
+ PERM_FREE (entry->state);
+ if (entry->country)
+ PERM_FREE (entry->country);
+ if (entry->company)
+ PERM_FREE (entry->company);
+ if (entry->organizations) {
+ for (i=0; i<entry->numOrgs; i++)
+ PERM_FREE (entry->organizations[i]);
+ PERM_FREE(entry->organizations);
+ }
+ }
+}
+
+void PrintHeader(FILE *outfile){
+
+ fprintf (outfile,"/*This file is generated automatically by the admin server\n");
+ fprintf (outfile," *Any changes you make manually may be lost if other\n");
+ fprintf (outfile," *changes are made through the admin server.\n");
+ fprintf (outfile," */\n\n\n");
+
+}
+
+void writeOutEntry (FILE *outfile, AVAEntry *entry) {
+ int i;
+
+ /*What should I do if the group id is not there?*/
+ if (!entry || !(entry->userid))
+ report_error (SYSTEM_ERROR, "AVA-DB Failure",
+ "Bad entry passed to write out function");
+
+ fprintf (outfile,"%s: {\n", entry->userid);
+ if (entry->CNEntry)
+ fprintf (outfile,"\tCN=\"%s\"\n", entry->CNEntry);
+ if (entry->email)
+ fprintf (outfile,"\tE=\"%s\"\n", entry->email);
+ if (entry->company)
+ fprintf (outfile,"\tO=\"%s\"\n", entry->company);
+ if (entry->organizations) {
+ for (i=0; i < entry->numOrgs; i++) {
+ fprintf (outfile, "\tOU=\"%s\"\n", entry->organizations[i]);
+ }
+ }
+ if (entry->locality)
+ fprintf (outfile,"\tL=\"%s\"\n",entry->locality);
+ if (entry->state)
+ fprintf (outfile,"\tST=\"%s\"\n",entry->state);
+ if (entry->country)
+ fprintf (outfile,"\tC=\"%s\"\n", entry->country);
+
+ fprintf (outfile,"}\n\n\n");
+
+}
+
+void writeOutFile (char *authdb, AVATable *table) {
+ char line[BIG_LINE];
+ char mess[200];
+ FILE *newfile;
+ int i;
+
+ sprintf (line, "%s%c%s%c%s.%s", get_authdb_dir(), FILE_PATHSEP, authdb, FILE_PATHSEP,
+ AUTH_DB_FILE, AVADB_TAG);
+
+ if (!table) {
+ sprintf (mess, "The structure for file %s was not loaded before writing out", line);
+ report_error (SYSTEM_ERROR, "Internal Error", mess);
+ }
+
+ newfile = fopen (line, "w");
+
+ if (!newfile) {
+ sprintf (mess, "Could not open file %s for writing.", line);
+ report_error(FILE_ERROR, "No File", mess);
+ }
+
+ PrintHeader (newfile);
+
+ for (i=0;i < table->numEntries; i++) {
+ writeOutEntry (newfile, table->enteredTable[i]);
+ }
+
+ fclose(newfile);
+}
+
+
+void
+logerror(char *error,int line,char *file) {
+ /* paranoia */
+ /*ava-mapping is only functin that initializes yy_sn and yy_rq*/
+ if ((yy_sn != NULL) && (yy_rq != NULL)) {
+ log_error (LOG_FAILURE, "ava-mapping", yy_sn, yy_rq,
+ "Parse error line %d of %s: %s", line, file, error);
+ } else {
+ char errMess[250];
+
+ sprintf (errMess, "Parse error line %d of %s: %s", line, file, error);
+ report_error (SYSTEM_ERROR, "Failure: Loading AVA-DB Table", errMess);
+ }
+}
+
+
+void outputAVAdbs(char *chosen) {
+ char *authdbdir = get_authdb_dir();
+ char **listings;
+ int i;
+ int numListings = 0;
+ int hasOptions = 0;
+
+ listings = list_auth_dbs(authdbdir);
+
+ while (listings[numListings++] != NULL);
+
+ for (i=0; listings[i] != NULL ; i++) {
+ if (!hasOptions) {
+ printf ("<select name=\"%s\"%s onChange=\"form.submit()\">",AVA_DB_SEL,
+ (numListings > SELECT_OVERFLOW)?"size=5":"");
+ hasOptions = 1;
+ }
+
+ printf ("<option value=\"%s\"%s>%s\n",listings[i],
+ (strcmp(chosen, listings[i]) == 0) ? "SELECTED":"",listings[i]);
+ }
+
+ if (hasOptions)
+ printf ("</select>\n");
+ else
+ printf ("<i><b>Insert an AVA-Database entry first</b></i>\n");/*This should never happen,
+ *since I never create an empty
+ *avadb file,
+ *but one never knows
+ */
+
+}
diff --git a/lib/libaccess/avascan.l b/lib/libaccess/avascan.l
new file mode 100644
index 00000000..ceae1426
--- /dev/null
+++ b/lib/libaccess/avascan.l
@@ -0,0 +1,106 @@
+/** 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 <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "y.tab.h"
+#include "libaccess/ava.h"
+#include "netsite.h"
+
+int linenum = 1;
+int first_time = 1;
+int old_state;
+int num_nested_comments = 0;
+
+extern AVAEntry tempEntry;
+extern AVATable entryTable;
+
+void strip_quotes(void);
+
+%}
+
+%s COMMENT NORM DEFINES DEF_TYPE
+
+uc_letter [A-Z]
+lc_letter [a-z]
+digit [0-9]
+under_score _
+
+letter ([A-Z,a-z])
+
+white_space ([ \t]*)
+identifier ([_,A-Z,a-z][_,A-Z,a-z,0-9]*)
+def_identifier (({white_space}{identifier})+)
+text (\"[^\"]*\")
+comments (([^"*/"\n])*)
+
+
+
+%%
+
+%{
+ if (first_time) {
+ BEGIN NORM;
+ first_time = tempEntry.numOrgs = 0;
+ old_state = NORM;
+ tempEntry.userid = 0;
+ tempEntry.country = 0;
+ tempEntry.CNEntry = 0;
+ tempEntry.email = 0;
+ tempEntry.locality = 0;
+ tempEntry.state = 0;
+ entryTable.numEntries = 0;
+ }
+%}
+
+
+"/*" {BEGIN COMMENT; num_nested_comments++;}
+<COMMENT>"*/" {num_nested_comments--;
+ if (!num_nested_comments) BEGIN old_state;}
+<COMMENT>. {;}
+
+<NORM>{identifier} {yylval.string = PERM_STRDUP(yytext);
+ return USER_ID;}
+<NORM>":"{white_space}\{ {BEGIN DEF_TYPE;
+ old_state = DEF_TYPE;}
+
+<DEF_TYPE>"C" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_C; }
+<DEF_TYPE>"O" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_CO;}
+<DEF_TYPE>"OU" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_OU;}
+<DEF_TYPE>"CN" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_CN;}
+<DEF_TYPE>"L" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_L;}
+<DEF_TYPE>"E" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_E;}
+<DEF_TYPE>"ST" {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_ST;}
+<DEF_TYPE>"}" {BEGIN NORM;old_state = NORM;}
+
+<DEFINES>= {return EQ_SIGN;}
+<DEFINES>{text} {BEGIN DEF_TYPE; old_state = DEF_TYPE;
+ strip_quotes();
+ return DEF_ID;}
+
+{white_space} {;}
+\n {linenum++;}
+. {yyerror("Bad input character");}
+%%
+
+int yywrap () {
+ return 1;
+}
+
+void strip_quotes(void) {
+ yytext[strlen(yytext)-1]= '\0';
+ yylval.string = PERM_STRDUP(&yytext[1]);
+}
diff --git a/lib/libaccess/las.h b/lib/libaccess/las.h
new file mode 100644
index 00000000..3dfdf1e9
--- /dev/null
+++ b/lib/libaccess/las.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 **/
+
+#ifndef LAS_H
+#define LAS_H
+
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include <base/plist.h>
+
+NSPR_BEGIN_EXTERN_C
+
+extern int LASTimeOfDayEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASDayOfWeekEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASIpEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASDnsEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASGroupEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+extern int LASUserEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+/* MLM - for admin delegation */
+extern int LASProgramEval(NSErr_t *errp, char *attribute, CmpOp_t comparator,
+ char *pattern, int *cachable, void **las_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth);
+
+extern void LASTimeOfDayFlush(void **cookie);
+extern void LASDayOfWeekFlush(void **cookie);
+extern void LASIpFlush(void **cookie);
+extern void LASDnsFlush(void **cookie);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/lasdns.cpp b/lib/libaccess/lasdns.cpp
new file mode 100644
index 00000000..22a37dac
--- /dev/null
+++ b/lib/libaccess/lasdns.cpp
@@ -0,0 +1,373 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* lasdns.c
+ * This file contains the DNS LAS code.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef XP_WIN32
+/* #include <winsock2.h> */
+#include <winsock.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#endif
+
+#include <netsite.h>
+extern "C" {
+#include <prnetdb.h>
+}
+#include <base/plist.h>
+#include <base/pool.h>
+#include <libaccess/nserror.h>
+#include <libaccess/nsauth.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include "lasdns.h"
+#include "aclutil.h"
+#include "aclcache.h"
+#include "permhash.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+#include "access_plhash.h"
+extern "C" {
+#include <nspr.h>
+}
+
+#ifdef UTEST
+extern int LASDnsGetDns(char **dnsv);
+#endif
+
+/* LASDnsMatch
+ * Given an array of fully-qualified dns names, tries to match them
+ * against a given hash table.
+ * INPUT
+ * dns DNS string
+ * context pointer to an LAS DNS context structure
+ *
+ * In our usage, this context is derived from
+ * an acllist cache, which is a representation of
+ * of some global acis--in other words it's a global thing
+ * shared between threads--hence the use
+ * of the "read-only" hash lookup routines here.
+ */
+int
+LASDnsMatch(char *token, LASDnsContext_t *context)
+{
+
+ /* Test for the unusual case where "*" is allowed */
+ if (ACL_HashTableLookup_const(context->Table, "*"))
+ return LAS_EVAL_TRUE;
+
+ /* Start with the full name. Then strip off each component
+ * leaving the remainder starting with a period. E.g.
+ * splash.mcom.com
+ * .mcom.com
+ * .com
+ * Search the hash table for each remaining portion. Remember that
+ * wildcards were put in with the leading period intact.
+ */
+ do {
+ if (ACL_HashTableLookup_const(context->Table, token))
+ return LAS_EVAL_TRUE;
+
+ token = strchr(&token[1], '.');
+ } while (token != NULL);
+
+ return LAS_EVAL_FALSE;
+
+}
+
+/* LASDNSBuild
+ * Builds a hash table of all the hostnames provided (plus their aliases
+ * if aliasflg is true). Wildcards are only permitted in the leftmost
+ * field. They're represented in the hash table by a leading period.
+ * E.g. ".mcom.com".
+ *
+ * RETURNS Zero on success, else LAS_EVAL_INVALID
+ */
+int
+LASDnsBuild(NSErr_t *errp, char *attr_pattern, LASDnsContext_t *context, int aliasflg)
+{
+ int delimiter; /* length of valid token */
+ char token[256]; /* max length dns name */
+ int i;
+ int ipcnt;
+ char **p;
+ unsigned long *ipaddrs=0;
+ pool_handle_t *pool;
+ PRStatus error=PR_SUCCESS;
+ char buffer[PR_NETDB_BUF_SIZE];
+#ifdef UTEST
+ struct hostent *he, host;
+#else
+ PRHostEnt *he, host;
+#endif
+
+ context->Table = PR_NewHashTable(0,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ pool = pool_create();
+ context->pool = pool;
+ if ((!context->Table) || (!context->pool)) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4700, ACL_Program, 1,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAllocateHashT_));
+ return LAS_EVAL_INVALID;
+ }
+
+ do {
+ /* Get a single hostname from the pattern string */
+ delimiter = strcspn(attr_pattern, ", \t");
+ strncpy(token, attr_pattern, delimiter);
+ token[delimiter] = '\0';
+
+ /* Skip any white space after the token */
+ attr_pattern += delimiter;
+ attr_pattern += strspn(attr_pattern, ", \t");
+
+ /* If there's a wildcard, strip it off but leave the "."
+ * Can't have aliases for a wildcard pattern.
+ * Treat "*" as a special case. If so, go ahead and hash it.
+ */
+ if (token[0] == '*') {
+ if (token[1] != '\0') {
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, &token[1]), (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4710, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token);
+ return LAS_EVAL_INVALID;
+ }
+ } else {
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, token), (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4720, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token);
+ return LAS_EVAL_INVALID;
+ }
+ }
+ } else {
+ /* This is a single hostname add it to the hash table */
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, &token[0]), (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4730, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), token);
+ return LAS_EVAL_INVALID;
+ }
+
+ if (aliasflg) {
+ /* memset(buffer, '\0', PR_NETDB_BUF_SIZE);
+ */
+#ifdef UTEST
+ he = gethostbyname(token);
+#else
+ error = PR_GetHostByName(token,
+ buffer,
+ PR_NETDB_BUF_SIZE,
+ &host);
+ if (error == PR_SUCCESS) he = &host;
+ else he = NULL;
+#endif
+ if (he) {
+ /* Make a copy of the list of IP addresses if any */
+ if (he->h_addr_list && he->h_addr_list[0]) {
+
+ /* Count the IP addresses */
+ for (p = he->h_addr_list, ipcnt = 0; *p; ++p) {
+ ++ipcnt;
+ }
+
+ /* Allocate space */
+ ipaddrs = (unsigned long *)PERM_MALLOC(ipcnt * sizeof(unsigned long));
+
+ /* Copy IP addresses */
+ for (i = 0; i < ipcnt; ++i) {
+ ipaddrs[i] = 0;
+ memcpy((void *)&ipaddrs[i], he->h_addr_list[i], 4);
+ }
+ }
+
+ /* Add each of the aliases to the list */
+ if (he->h_aliases && he->h_aliases[0]) {
+
+ for (p = he->h_aliases; *p; ++p) {
+ /* Add it to the hash table */
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, *p), (void*)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4740, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), *p);
+ PERM_FREE(ipaddrs);
+ return LAS_EVAL_INVALID;
+ }
+ }
+ }
+
+ for (i = 0; i < ipcnt; ++i) {
+
+#ifdef UTEST
+ he = gethostbyaddr((char *)&ipaddrs[i], 4, AF_INET);
+#else
+ error = PR_GetHostByAddr((PRNetAddr *)&ipaddrs[i],
+ buffer,
+ PR_NETDB_BUF_SIZE,
+ &host);
+ if (error == PR_SUCCESS) he = &host;
+ else he = NULL;
+#endif
+ if (he) {
+ if (he->h_name) {
+ /* Add it to the hash table */
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, he->h_name),
+ (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4750, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), he->h_name);
+ PERM_FREE(ipaddrs);
+ return LAS_EVAL_INVALID;
+ }
+ }
+
+ if (he->h_aliases && he->h_aliases[0]) {
+ for (p = he->h_aliases; *p; ++p) {
+ /* Add it to the hash table */
+ if (!PR_HashTableAdd(context->Table, pool_strdup(pool, *p), (void *)-1)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4760, ACL_Program, 2,
+ XP_GetAdminStr(DBT_lasdnsbuildUnableToAddKeySN_), *p);
+ PERM_FREE(ipaddrs);
+ return LAS_EVAL_INVALID;
+ }
+ }
+ }
+ }
+ }
+
+ PERM_FREE(ipaddrs);
+
+ } /* if he */
+
+
+ } /* if aliasflg */
+
+ } /* else - single hostname */
+
+
+ } while ((attr_pattern != NULL) &&
+ (attr_pattern[0] != '\0') &&
+ (delimiter != (int)NULL));
+
+ return 0;
+}
+
+/* LASDnsFlush
+ * Given the address of a las_cookie for a DNS expression entry, frees up
+ * all allocated memory for it. This includes the hash table, plus the
+ * context structure.
+ */
+void
+LASDnsFlush(void **las_cookie)
+{
+ if (*las_cookie == NULL)
+ return;
+
+ pool_destroy(((LASDnsContext_t *)*las_cookie)->pool);
+ PR_HashTableDestroy(((LASDnsContext_t *)*las_cookie)->Table);
+ PERM_FREE(*las_cookie);
+ *las_cookie = NULL;
+ return;
+}
+
+/*
+ * LASDnsEval
+ * INPUT
+ * attr_name The string "dns" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of DNS names
+ * Any segment(s) in a DNS name can be wildcarded using
+ * "*". Note that this is not a true Regular Expression
+ * form.
+ * *cachable Always set to ACL_INDEF_CACHE
+ * subject Subject property list
+ * resource Resource property list
+ * auth_info Authentication info, if any
+ * RETURNS
+ * ret code The usual LAS return codes.
+ */
+int LASDnsEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ int result;
+ int aliasflg;
+ char *my_dns;
+ LASDnsContext_t *context;
+ int rv;
+
+ *cachable = ACL_INDEF_CACHABLE;
+
+ if (strcmp(attr_name, "dns") == 0)
+ aliasflg = 0;
+ else if (strcmp(attr_name, "dnsalias") == 0)
+ aliasflg = 1;
+ else {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4800, ACL_Program, 2, XP_GetAdminStr(DBT_lasDnsBuildReceivedRequestForAtt_), attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4810, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsevalIllegalComparatorDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ /* If this is the first time through, build the pattern tree first. */
+ if (*LAS_cookie == NULL) {
+ ACL_CritEnter();
+ if (*LAS_cookie == NULL) { /* Must check again */
+ *LAS_cookie = context =
+ (LASDnsContext_t *)PERM_MALLOC(sizeof(LASDnsContext_t));
+ if (context == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4820, ACL_Program, 1, XP_GetAdminStr(DBT_lasdnsevalUnableToAllocateContex_));
+ ACL_CritExit();
+ return LAS_EVAL_FAIL;
+ }
+ context->Table = NULL;
+ LASDnsBuild(errp, attr_pattern, context, aliasflg);
+ }
+ ACL_CritExit();
+ } else
+ context = (LASDnsContext *) *LAS_cookie;
+
+ /* Call the DNS attribute getter */
+#ifdef UTEST
+ LASDnsGetDns(&my_dns); /* gets stuffed on return */
+#else
+ rv = ACL_GetAttribute(errp, ACL_ATTR_DNS, (void **)&my_dns,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ if (subject || resource) {
+ char rv_str[16];
+ /* Don't ereport if called from ACL_CachableAclList */
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4830, ACL_Program, 2, XP_GetAdminStr(DBT_lasdnsevalUnableToGetDnsErrorDN_), rv_str);
+ }
+ return LAS_EVAL_FAIL;
+ }
+#endif
+
+ result = LASDnsMatch(my_dns, context);
+
+ if (comparator == CMP_OP_NE) {
+ if (result == LAS_EVAL_FALSE)
+ return LAS_EVAL_TRUE;
+ else if (result == LAS_EVAL_TRUE)
+ return LAS_EVAL_FALSE;
+ }
+ return (result);
+}
diff --git a/lib/libaccess/lasdns.h b/lib/libaccess/lasdns.h
new file mode 100644
index 00000000..3d86dc98
--- /dev/null
+++ b/lib/libaccess/lasdns.h
@@ -0,0 +1,10 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+typedef struct LASDnsContext {
+ PRHashTable *Table;
+ pool_handle_t *pool;
+} LASDnsContext_t;
diff --git a/lib/libaccess/lasgroup.cpp b/lib/libaccess/lasgroup.cpp
new file mode 100644
index 00000000..6ff5d1bb
--- /dev/null
+++ b/lib/libaccess/lasgroup.cpp
@@ -0,0 +1,164 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* #define DBG_PRINT */
+
+/* lasgroup.c
+ * This file contains the Group LAS code.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <netsite.h>
+#include "aclpriv.h"
+#include <libaccess/usrcache.h>
+#include <libaccess/las.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+#include <ldaputil/errors.h> /* for DBG_PRINT */
+#include "aclutil.h"
+
+#ifdef UTEST
+extern char *LASGroupGetUser();
+#endif /* UTEST */
+
+
+/*
+ * LASGroupEval
+ * INPUT
+ * attr_name The string "group" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of groups
+ * *cachable Always set to ACL_NOT_CACHABLE
+ * subject Subjust property list
+ * resource Resource property list
+ * auth_info Authentication info, if any
+ * RETURNS
+ * retcode The usual LAS return codes.
+ */
+int LASGroupEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable,
+ void **LAS_cookie, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ char *groups = attr_pattern;
+ int retcode;
+ char *member_of;
+ char *user;
+ char *dbname;
+ time_t *req_time = 0;
+ const char *group;
+ char delim;
+ int len;
+ int rv;
+
+ *cachable = ACL_NOT_CACHABLE;
+ *LAS_cookie = (void *)0;
+
+ if (strcmp(attr_name, ACL_ATTR_GROUP) != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4900, ACL_Program, 2, XP_GetAdminStr(DBT_lasGroupEvalReceivedRequestForAt_), attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR4910, ACL_Program, 2, XP_GetAdminStr(DBT_lasgroupevalIllegalComparatorDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ if (!strcmp(attr_pattern, "anyone")) {
+ *cachable = ACL_INDEF_CACHABLE;
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ /* Get the authenticated user */
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&user,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4920, ACL_Program, 2, XP_GetAdminStr(DBT_lasGroupEvalUnableToGetDatabaseName), rv_str);
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = LAS_EVAL_FALSE;
+
+ if (acl_usr_cache_enabled()) {
+ /* avoid unnecessary system call to get time if cache is disabled */
+ req_time = acl_get_req_time(resource);
+
+ /* Loop through all the groups and check if any is in the cache */
+ group = groups;
+ delim = ',';
+ while((group = acl_next_token_len(group, delim, &len)) != NULL) {
+ rv = acl_usr_cache_group_len_check(user, dbname, group, len, *req_time);
+ if (rv == LAS_EVAL_TRUE) {
+ /* cached group exists */
+ break;
+ }
+ if (0 != (group = strchr(group+len, delim)))
+ group++;
+ else
+ break;
+ }
+ /* group need not be NULL-terminated */
+ /* If you need to use it, copy it properly */
+ group = 0;
+ }
+
+ if (rv != LAS_EVAL_TRUE) {
+ /* not found in the cache or not one of the groups we want */
+ PListDeleteProp(subject, ACL_ATTR_GROUPS_INDEX, ACL_ATTR_GROUPS);
+ PListInitProp(subject, ACL_ATTR_GROUPS_INDEX, ACL_ATTR_GROUPS, groups, 0);
+ PListDeleteProp(subject, ACL_ATTR_USER_ISMEMBER_INDEX, ACL_ATTR_USER_ISMEMBER);
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER_ISMEMBER, (void **)&member_of,
+ subject, resource, auth_info, global_auth);
+
+ PListDeleteProp(subject, ACL_ATTR_GROUPS_INDEX, ACL_ATTR_GROUPS);
+
+ if (rv != LAS_EVAL_TRUE && rv != LAS_EVAL_FALSE) {
+ return rv;
+ }
+
+ if (rv == LAS_EVAL_TRUE) {
+ /* User is a member of one of the groups */
+ /* update the user's cache */
+ acl_usr_cache_set_group(user, dbname, member_of, *req_time);
+ }
+ }
+
+ if (rv == LAS_EVAL_TRUE) {
+ retcode = (comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ }
+ else {
+ /* User is not a member of any of the groups */
+ retcode = (comparator == CMP_OP_EQ ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+
+ DBG_PRINT4("%s LASGroupEval: uid = \"%s\" groups = \"%s\"\n",
+ (retcode == LAS_EVAL_FALSE) ? "LAS_EVAL_FALSE"
+ : (retcode == LAS_EVAL_TRUE) ? "LAS_EVAL_TRUE"
+ : "Error",
+ user, attr_pattern);
+
+ return retcode;
+}
+
+
+/* LASGroupFlush
+ * Deallocates any memory previously allocated by the LAS
+ */
+void
+LASGroupFlush(void **las_cookie)
+{
+ /* do nothing */
+ return;
+}
diff --git a/lib/libaccess/lasip.cpp b/lib/libaccess/lasip.cpp
new file mode 100644
index 00000000..2c70a22b
--- /dev/null
+++ b/lib/libaccess/lasip.cpp
@@ -0,0 +1,487 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* aclip.c
+ * This file contains the IP LAS code.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <netsite.h>
+#include <base/plist.h>
+#include <libaccess/nserror.h>
+#include <libaccess/nsauth.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include "lasip.h"
+#include "aclutil.h"
+#include "aclcache.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+#define LAS_IP_IS_CONSTANT(x) (((x) == (LASIpTree_t *)LAS_EVAL_TRUE) || ((x) == (LASIpTree_t *)LAS_EVAL_FALSE))
+
+#ifdef UTEST
+extern int LASIpGetIp();
+#endif
+
+static int
+LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop);
+
+/* dotdecimal
+ * Takes netmask and ip strings and returns the numeric values,
+ * accounting for wildards in the ip specification. Wildcards in the
+ * ip override the netmask where they conflict.
+ * INPUT
+ * ipstr e.g. "123.45.67.89"
+ * netmaskstr e.g. "255.255.255.0"
+ * RETURNS
+ * *ip
+ * *netmask e.g. 0xffffff00
+ * result NULL on success or else one of the LAS_EVAL_* codes.
+ */
+int
+dotdecimal(char *ipstr, char *netmaskstr, int *ip, int *netmask)
+{
+ int i;
+ char token[64];
+ char *dotptr; /* location of the "." */
+ int dotidx; /* index of the period char */
+
+ /* Sanity check the patterns */
+
+ /* Netmask can only have digits and periods. */
+ if (strcspn(netmaskstr, "0123456789."))
+ return LAS_EVAL_INVALID;
+
+ /* IP can only have digits, periods and "*" */
+ if (strcspn(ipstr, "0123456789.*"))
+ return LAS_EVAL_INVALID;
+
+ *netmask = *ip = 0; /* Start with "don't care" */
+
+ for (i=0; i<4; i++) {
+ dotptr = strchr(netmaskstr, '.');
+
+ /* copy out the token, then point beyond it */
+ if (dotptr == NULL)
+ strcpy(token, netmaskstr);
+ else {
+ dotidx = dotptr-netmaskstr;
+ strncpy(token, netmaskstr, dotidx);
+ token[dotidx] = '\0';
+ netmaskstr = ++dotptr; /* skip the period */
+ }
+
+ /* Turn into a number and shift left as appropriate */
+ *netmask += (atoi(token))<<(8*(4-i-1));
+
+ if (dotptr == NULL)
+ break;
+ }
+
+ for (i=0; i<4; i++) {
+ dotptr = strchr(ipstr, '.');
+
+ /* copy out the token, then point beyond it */
+ if (dotptr == NULL)
+ strcpy(token, ipstr);
+ else {
+ dotidx = dotptr-ipstr;
+ strncpy(token, ipstr, dotidx);
+ token[dotidx] = '\0';
+ ipstr = ++dotptr;
+ }
+
+ /* check for wildcard */
+ if (strcmp(token, "*") == 0) {
+ switch(i) {
+ case 0:
+ if (dotptr == NULL)
+ *netmask &= 0x00000000;
+ else
+ *netmask &= 0x00ffffff;
+ break;
+ case 1:
+ if (dotptr == NULL)
+ *netmask &= 0xff000000;
+ else
+ *netmask &= 0xff00ffff;
+ break;
+ case 2:
+ if (dotptr == NULL)
+ *netmask &= 0xffff0000;
+ else
+ *netmask &= 0xffff00ff;
+ break;
+ case 3:
+ *netmask &= 0xffffff00;
+ break;
+ }
+ continue;
+ } else {
+ /* Turn into a number and shift left as appropriate */
+ *ip += (atoi(token))<<(8*(4-i-1));
+ }
+
+ /* check for end of string */
+ if (dotptr == NULL) {
+ switch(i) {
+ case 0:
+ *netmask &= 0xff000000;
+ break;
+ case 1:
+ *netmask &= 0xffff0000;
+ break;
+ case 2:
+ *netmask &= 0xffffff00;
+ break;
+ }
+ break;
+ }
+ }
+
+ return (int)NULL;
+}
+
+
+/* LASIpTreeAlloc
+ * Malloc a node and set the actions to LAS_EVAL_FALSE
+ */
+static LASIpTree_t *
+LASIpTreeAllocNode(NSErr_t *errp)
+{
+ LASIpTree_t *newnode;
+
+ newnode = (LASIpTree_t *)PERM_MALLOC(sizeof(LASIpTree_t));
+ if (newnode == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR5000, ACL_Program, 1, XP_GetAdminStr(DBT_lasiptreeallocNoMemoryN_));
+ return NULL;
+ }
+ newnode->action[0] = (LASIpTree_t *)LAS_EVAL_FALSE;
+ newnode->action[1] = (LASIpTree_t *)LAS_EVAL_FALSE;
+ return newnode;
+}
+
+
+/* LASIpTreeDealloc
+ * Deallocates a Tree starting from a given node down.
+ * INPUT
+ * startnode Starting node to remove. Could be a constant in
+ * which case, just return success.
+ * OUTPUT
+ * N/A
+ */
+static void
+LASIpTreeDealloc(LASIpTree_t *startnode)
+{
+ int i;
+
+ if (startnode == NULL)
+ return;
+
+ /* If this is just a constant then we're done */
+ if (LAS_IP_IS_CONSTANT(startnode))
+ return;
+
+ /* Else recursively call ourself for each branch down */
+ for (i=0; i<2; i++) {
+ if (!(LAS_IP_IS_CONSTANT(startnode->action[i])))
+ LASIpTreeDealloc(startnode->action[i]);
+ }
+
+ /* Now deallocate the local node */
+ PERM_FREE(startnode);
+}
+
+/*
+ * LASIpBuild
+ * INPUT
+ * attr_name The string "ip" - in lower case.
+ * comparator CmpOpEQ or CmpOpNE only
+ * attr_pattern A comma-separated list of IP addresses and netmasks
+ * in dotted-decimal form. Netmasks are optionally
+ * prepended to the IP address using a plus sign. E.g.
+ * 255.255.255.0+123.45.67.89. Any byte in the IP address
+ * (but not the netmask) can be wildcarded using "*"
+ * context A pointer to the IP LAS context structure.
+ * RETURNS
+ * ret code The usual LAS return codes.
+ */
+static int
+LASIpBuild(NSErr_t *errp, char *attr_name, CmpOp_t comparator, char *attr_pattern, LASIpTree_t **treetop)
+{
+ unsigned int delimiter; /* length of valid token */
+ char token[64], token2[64]; /* a single ip[+netmask] */
+ char *curptr; /* current place in attr_pattern */
+ int netmask, ip;
+ char *plusptr;
+ int retcode;
+
+ /* ip address can be delimited by space, tab, comma, or carriage return
+ * only.
+ */
+ curptr = attr_pattern;
+ do {
+ delimiter = strcspn(curptr, ", \t");
+ delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
+ strncpy(token, curptr, delimiter);
+ token[delimiter] = '\0';
+ /* skip all the white space after the token */
+ curptr = strpbrk((curptr+delimiter), "1234567890+.*");
+
+ /* Is there a netmask? */
+ plusptr = strchr(token, '+');
+ if (plusptr == NULL) {
+ if (curptr && (*curptr == '+')) {
+ /* There was a space before (and possibly after) the plus sign*/
+ curptr = strpbrk((++curptr), "1234567890.*");
+ delimiter = strcspn(curptr, ", \t");
+ delimiter = (delimiter <= strlen(curptr)) ? delimiter : strlen(curptr);
+ strncpy(token2, curptr, delimiter);
+ token2[delimiter] = '\0';
+ retcode = dotdecimal(token, token2, &ip, &netmask);
+ if (retcode)
+ return (retcode);
+ curptr = strpbrk((++curptr), "1234567890+.*");
+ } else {
+ retcode =dotdecimal(token, "255.255.255.255", &ip, &netmask);
+ if (retcode)
+ return (retcode);
+ }
+ } else {
+ /* token is the IP addr string in both cases */
+ *plusptr ='\0'; /* truncate the string */
+ retcode =dotdecimal(token, ++plusptr, &ip, &netmask);
+ if (retcode)
+ return (retcode);
+ }
+
+ if (LASIpAddPattern(errp, netmask, ip, treetop) != (int)NULL)
+ return LAS_EVAL_INVALID;
+
+ } while ((curptr != NULL) && (delimiter != (int)NULL));
+
+ return (int)NULL;
+}
+
+
+/* LASIpAddPattern
+ * Takes a netmask and IP address and a pointer to an existing IP
+ * tree and adds nodes as appropriate to recognize the new pattern.
+ * INPUT
+ * netmask e.g. 0xffffff00
+ * pattern IP address in 4 bytes
+ * *treetop An existing IP tree or 0 if a new tree
+ * RETURNS
+ * ret code NULL on success, ACL_RES_ERROR on failure
+ * **treetop If this is a new tree, the head of the tree.
+ */
+static int
+LASIpAddPattern(NSErr_t *errp, int netmask, int pattern, LASIpTree_t **treetop)
+{
+ int stopbit; /* Don't care after this point */
+ int curbit; /* current bit we're working on */
+ int curval; /* value of pattern[curbit] */
+ LASIpTree_t *curptr; /* pointer to the current node */
+ LASIpTree_t *newptr;
+
+ /* stop at the first 1 in the netmask from low to high */
+ for (stopbit=0; stopbit<32; stopbit++) {
+ if ((netmask&(1<<stopbit)) != 0)
+ break;
+ }
+
+ /* Special case if there's no tree. Allocate the first node */
+ if (*treetop == (LASIpTree_t *)NULL) { /* No tree at all */
+ curptr = LASIpTreeAllocNode(errp);
+ if (curptr == NULL) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5100, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_));
+ return ACL_RES_ERROR;
+ }
+ *treetop = curptr;
+ }
+
+ /* Special case if the netmask is 0.
+ */
+ if (stopbit > 31) {
+ curptr->action[0] = (LASIpTree_t *)LAS_EVAL_TRUE;
+ curptr->action[1] = (LASIpTree_t *)LAS_EVAL_TRUE;
+ return 0;
+ }
+
+
+ /* follow the tree down the pattern path bit by bit until the
+ * end of the tree is reached (i.e. a constant).
+ */
+ for (curbit=31,curptr=*treetop; curbit >= 0; curbit--) {
+
+ /* Is the current bit ON? If so set curval to 1 else 0 */
+ curval = (pattern & (1<<curbit)) ? 1 : 0;
+
+ /* Are we done, if so remove the rest of the tree */
+ if (curbit == stopbit) {
+ LASIpTreeDealloc(curptr->action[curval]);
+ curptr->action[curval] =
+ (LASIpTree_t *)LAS_EVAL_TRUE;
+
+ /* This is the normal exit point. Most other
+ * exits must be due to errors.
+ */
+ return 0;
+ }
+
+ /* Oops reached the end - must allocate */
+ if (LAS_IP_IS_CONSTANT(curptr->action[curval])) {
+ newptr = LASIpTreeAllocNode(errp);
+ if (newptr == NULL) {
+ LASIpTreeDealloc(*treetop);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5110, ACL_Program, 1, XP_GetAdminStr(DBT_ipLasUnableToAllocateTreeNodeN_1));
+ return ACL_RES_ERROR;
+ }
+ curptr->action[curval] = newptr;
+ }
+
+ /* Keep going down the tree */
+ curptr = curptr->action[curval];
+ }
+
+ return ACL_RES_ERROR;
+}
+
+/* LASIpFlush
+ * Deallocates any memory previously allocated by the LAS
+ */
+void
+LASIpFlush(void **las_cookie)
+{
+ if (*las_cookie == NULL)
+ return;
+
+ LASIpTreeDealloc(((LASIpContext_t *)*las_cookie)->treetop);
+ PERM_FREE(*las_cookie);
+ *las_cookie = NULL;
+ return;
+}
+
+/*
+ * LASIpEval
+ * INPUT
+ * attr_name The string "ip" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of IP addresses and netmasks
+ * in dotted-decimal form. Netmasks are optionally
+ * prepended to the IP address using a plus sign. E.g.
+ * 255.255.255.0+123.45.67.89. Any byte in the IP address
+ * (but not the netmask) can be wildcarded using "*"
+ * *cachable Always set to ACL_INDEF_CACHABLE
+ * subject Subject property list
+ * resource Resource property list
+ * auth_info The authentication info if any
+ * RETURNS
+ * ret code The usual LAS return codes.
+ */
+int LASIpEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie,
+ PList_t subject, PList_t resource, PList_t auth_info,
+ PList_t global_auth)
+{
+ int bit;
+ int value;
+ IPAddr_t ip;
+ int retcode;
+ LASIpTree_t *node;
+ LASIpContext_t *context;
+ int rv;
+ char ip_str[124];
+
+ *cachable = ACL_INDEF_CACHABLE;
+
+ if (strcmp(attr_name, "ip") != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5200, ACL_Program, 2, XP_GetAdminStr(DBT_lasIpBuildReceivedRequestForAttr_), attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5210, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalIllegalComparatorDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ /* GET THE IP ADDR FROM THE SESSION CONTEXT AND STORE IT IN THE
+ * VARIABLE ip.
+ */
+#ifndef UTEST
+ rv = ACL_GetAttribute(errp, ACL_ATTR_IP, (void **)&ip,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ if (subject || resource) {
+ /* Don't ereport if called from ACL_CachableAclList */
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5220, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalUnableToGetSessionAddre_), rv_str);
+ }
+ return LAS_EVAL_FAIL;
+ }
+#else
+ ip = (IPAddr_t)LASIpGetIp();
+#endif
+
+ /* If this is the first time through, build the pattern tree first.
+ */
+ if (*LAS_cookie == NULL) {
+ if (strcspn(attr_pattern, "0123456789.*,+ \t")) {
+ return LAS_EVAL_INVALID;
+ }
+ ACL_CritEnter();
+ if (*LAS_cookie == NULL) { /* must check again */
+ *LAS_cookie = context =
+ (LASIpContext_t *)PERM_MALLOC(sizeof(LASIpContext_t));
+ if (context == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR5230, ACL_Program, 1, XP_GetAdminStr(DBT_lasipevalUnableToAllocateContext_));
+ ACL_CritExit();
+ return LAS_EVAL_FAIL;
+ }
+ context->treetop = NULL;
+ retcode = LASIpBuild(errp, attr_name, comparator, attr_pattern,
+ &context->treetop);
+ if (retcode) {
+ ACL_CritExit();
+ return (retcode);
+ }
+ }
+ ACL_CritExit();
+ } else
+ context = (LASIpContext *) *LAS_cookie;
+
+ node = context->treetop;
+
+ for (bit=31; bit >=0; bit--) {
+ value = (ip & (IPAddr_t) (1<<bit)) ? 1 : 0;
+ if (LAS_IP_IS_CONSTANT(node->action[value]))
+ /* Reached a result, so return it */
+ if (comparator == CMP_OP_EQ)
+ return((int)(PRSize)node->action[value]);
+ else
+ return(((int)(PRSize)node->action[value] ==
+ LAS_EVAL_TRUE) ?
+ LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+
+ else
+ /* Move on to the next bit */
+ node = node->action[value];
+ }
+
+ /* Cannot reach here. Even a 32 bit mismatch has a conclusion in
+ * the pattern tree.
+ */
+ sprintf(ip_str, "%x", ip);
+ nserrGenerate(errp, ACLERRINTERNAL, ACLERR5240, ACL_Program, 2, XP_GetAdminStr(DBT_lasipevalReach32BitsWithoutConcl_), ip_str);
+ return LAS_EVAL_INVALID;
+}
+
diff --git a/lib/libaccess/lasip.h b/lib/libaccess/lasip.h
new file mode 100644
index 00000000..0e162d9b
--- /dev/null
+++ b/lib/libaccess/lasip.h
@@ -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 **/
+
+typedef struct LASIpTree {
+ struct LASIpTree *action[2];
+} LASIpTree_t;
+
+typedef struct LASIpContext {
+ LASIpTree_t *treetop; /* Top of the pattern tree */
+} LASIpContext_t;
diff --git a/lib/libaccess/lastod.cpp b/lib/libaccess/lastod.cpp
new file mode 100644
index 00000000..d304986d
--- /dev/null
+++ b/lib/libaccess/lastod.cpp
@@ -0,0 +1,170 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* Source file for the TimeOfDay and DayOfWeek LAS drivers
+*/
+#include <time.h>
+
+#include <netsite.h>
+#include <base/util.h>
+#include <base/plist.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include "aclutil.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+/* Day of the week LAS driver
+ * Note that everything is case-insensitive.
+ * INPUT
+ * attr must be the string "dayofweek".
+ * comparator can only be "=" or "!=".
+ * pattern any sequence of 3-letter day names. I.e. sun, mon,
+ * tue, wed, thu, fri, sat. Comma delimiters can be used
+ * but are not necessary. E.g. mon,TueweDThuFRISat
+ * OUTPUT
+ * cachable Will be set to ACL_NOT_CACHABLE.
+ * return code set to LAS_EVAL_*
+ */
+int
+LASDayOfWeekEval(NSErr_t *errp, char *attr, CmpOp_t comparator, char *pattern,
+ ACLCachable_t *cachable, void **las_cookie, PList_t subject,
+ PList_t resource, PList_t auth_info, PList_t global_auth)
+{
+#ifndef UTEST
+ struct tm *tm_p, tm;
+#endif
+ time_t t;
+ char daystr[5]; /* Current local day in ddd */
+ char lcl_pattern[512];
+ char *compare;
+
+ /* Sanity checking */
+ if (strcmp(attr, "dayofweek") != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5400, ACL_Program, 2, XP_GetAdminStr(DBT_unexpectedAttributeInDayofweekSN_), attr);
+ return LAS_EVAL_INVALID;
+ }
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5410, ACL_Program, 2, XP_GetAdminStr(DBT_illegalComparatorForDayofweekDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+ *cachable = ACL_NOT_CACHABLE;
+
+ /* Obtain and format the local time */
+#ifndef UTEST
+ t = time(NULL);
+ tm_p = system_localtime(&t, &tm);
+ util_strftime(daystr, "%a", tm_p);
+#else
+ t = (0x1000000); /* Mon 2120 hr */
+ strftime(daystr, 4, "%a", localtime(&t));
+#endif
+ makelower(daystr);
+ strcpy(lcl_pattern, pattern);
+ makelower(lcl_pattern);
+
+ /* Compare the value to the pattern */
+ compare = strstr(lcl_pattern, daystr);
+
+ if ((compare != NULL) && (comparator == CMP_OP_EQ))
+ return LAS_EVAL_TRUE;
+ if ((compare == NULL) && (comparator == CMP_OP_NE))
+ return LAS_EVAL_TRUE;
+ return LAS_EVAL_FALSE;
+}
+
+
+/* Time of day LAS
+ * INPUT
+ * attr must be "timeofday".
+ * comparator one of =, !=, >, <, >=, <=
+ * pattern HHMM military 24-hour clock. E.g. 0700, 2315.
+ * OUTPUT
+ * cachable will be set to ACL_NOT_CACHABLE.
+ * return code set to LAS_EVAL_*
+ */
+int
+LASTimeOfDayEval(NSErr_t *errp, char *attr, CmpOp_t comparator, char *pattern,
+ ACLCachable_t *cachable, void **LAS_cookie, PList_t subject,
+ PList_t resource, PList_t auth_info, PList_t global_auth)
+{
+#ifndef UTEST
+ struct tm *tm_p, tm;
+#endif
+ time_t t;
+ char timestr[6]; /* Current local time in HHMM */
+ char start[6], end[6];
+ int compare; /* >0, 0, <0 means that current time is greater, equal to, or less than the pattern */
+ char *dash;
+ int intpattern, inttime, intstart, intend;
+
+ if (strcmp(attr, "timeofday") != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5600, ACL_Program, 2, XP_GetAdminStr(DBT_unexpectedAttributeInTimeofdaySN_), attr);
+ return LAS_EVAL_INVALID;
+ }
+ *cachable = ACL_NOT_CACHABLE;
+
+ /* Obtain and format the local time */
+#ifndef UTEST
+ t = time(NULL);
+ tm_p = system_localtime(&t, &tm);
+ util_strftime(timestr, "%H%M", tm_p);
+#else
+ t = (0x1000000); /* Mon 2120 hr */
+ strftime(timestr, 5, "%H%M", localtime(&t));
+#endif
+#ifdef DEBUG
+ printf ("timestr = %s\n", timestr);
+#endif
+ inttime = atoi(timestr);
+
+
+ dash = strchr(pattern, '-');
+ if (dash) {
+ if (comparator != CMP_OP_EQ && comparator != CMP_OP_NE) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5610, ACL_Program, 2, XP_GetAdminStr(DBT_illegalComparatorForTimeOfDayDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ strncpy(start, pattern, dash-pattern);
+ start[dash-pattern]='\0';
+ intstart = atoi(start);
+
+ strcpy(end, dash+1);
+ intend = atoi(end);
+
+ if (intend >= intstart) {
+ return(evalComparator(comparator, !(inttime >= intstart && inttime <= intend)));
+ } else { /* range wraps around midnight */
+ return(evalComparator(comparator, !(inttime >= intstart || inttime <= intend)));
+ }
+ }
+
+
+ /* ELSE - Just a single time value given. */
+
+ /* Compare the value to the pattern */
+ intpattern = atoi(pattern);
+ compare = inttime - intpattern;
+
+ /* Test against what the user wanted done */
+ return(evalComparator(comparator, compare));
+}
+
+void
+LASDayOfWeekFlush(void **cookie)
+{
+ return;
+}
+
+void
+LASTimeOfDayFlush(void **cookie)
+{
+ return;
+}
+
diff --git a/lib/libaccess/lasuser.cpp b/lib/libaccess/lasuser.cpp
new file mode 100644
index 00000000..d58f9a3f
--- /dev/null
+++ b/lib/libaccess/lasuser.cpp
@@ -0,0 +1,154 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* lasuser.c
+ * This file contains the User LAS code.
+ */
+
+#include <netsite.h>
+#include <base/shexp.h>
+#include <base/util.h>
+#include <libaccess/las.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+#include "aclutil.h"
+
+#ifdef UTEST
+extern char * LASUserGetUser();
+#endif
+
+
+/*
+ * LASUserEval
+ * INPUT
+ * attr_name The string "user" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of users
+ * *cachable Always set to ACL_NOT_CACHABLE.
+ * subject Subject property list
+ * resource Resource property list
+ * auth_info Authentication info, if any
+ * RETURNS
+ * retcode The usual LAS return codes.
+ */
+int LASUserEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable,
+ void **LAS_cookie, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ char *uid;
+ char *users;
+ char *user;
+ char *comma;
+ int retcode;
+ int matched;
+ int is_owner;
+ int rv;
+
+ *cachable = ACL_NOT_CACHABLE;
+ *LAS_cookie = (void *)0;
+
+ if (strcmp(attr_name, ACL_ATTR_USER) != 0) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5700, ACL_Program, 2, XP_GetAdminStr(DBT_lasUserEvalReceivedRequestForAtt_), attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5710, ACL_Program, 2, XP_GetAdminStr(DBT_lasuserevalIllegalComparatorDN_), comparator_string(comparator));
+ return LAS_EVAL_INVALID;
+ }
+
+ if (!strcmp(attr_pattern, "anyone")) {
+ *cachable = ACL_INDEF_CACHABLE;
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ /* get the authenticated user name */
+#ifndef UTEST
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&uid,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+#else
+ uid = (char *)LASUserGetUser();
+#endif
+
+ /* We have an authenticated user */
+ if (!strcmp(attr_pattern, "all")) {
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ users = STRDUP(attr_pattern);
+
+ if (!users) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR5720, ACL_Program, 1,
+ XP_GetAdminStr(DBT_lasuserevalRanOutOfMemoryN_));
+ return LAS_EVAL_FAIL;
+ }
+
+ user = users;
+ matched = 0;
+
+ /* check if the uid is one of the users */
+ while(user != 0 && *user != 0 && !matched) {
+ if ((comma = strchr(user, ',')) != NULL) {
+ *comma++ = 0;
+ }
+
+ /* ignore leading whitespace */
+ while(*user == ' ' || *user == '\t') user++;
+
+ if (*user) {
+ /* ignore trailing whitespace */
+ int len = strlen(user);
+ char *ptr = user+len-1;
+
+ while(*ptr == ' ' || *ptr == '\t') *ptr-- = 0;
+ }
+
+ if (!strcasecmp(user, ACL_ATTR_OWNER)) {
+ rv = ACL_GetAttribute(errp, ACL_ATTR_IS_OWNER, (void **)&is_owner,
+ subject, resource, auth_info, global_auth);
+ if (rv == LAS_EVAL_TRUE)
+ matched = 1;
+ else
+ /* continue checking for next user */
+ user = comma;
+ }
+ else if (!WILDPAT_CASECMP(uid, user)) {
+ /* uid is one of the users */
+ matched = 1;
+ }
+ else {
+ /* continue checking for next user */
+ user = comma;
+ }
+ }
+
+ if (comparator == CMP_OP_EQ) {
+ retcode = (matched ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ }
+ else {
+ retcode = (matched ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+
+ FREE(users);
+ return retcode;
+}
+
+
+/* LASUserFlush
+ * Deallocates any memory previously allocated by the LAS
+ */
+void
+LASUserFlush(void **las_cookie)
+{
+ /* do nothing */
+ return;
+}
diff --git a/lib/libaccess/lcache.h b/lib/libaccess/lcache.h
new file mode 100644
index 00000000..0e39a3a6
--- /dev/null
+++ b/lib/libaccess/lcache.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 **/
+
+#ifndef CACHE_H
+#define CACHE_H
+
+NSPR_BEGIN_EXTERN_C
+
+extern void ACL_ListHashUpdate(ACLListHandle_t **acllistp);
+extern void ACL_Init(void);
+extern void ACL_CritEnter(void);
+extern void ACL_CritExit(void);
+extern ENTRY *ACL_GetUriHash(ENTRY item, ACTION action);
+extern int ACL_CacheCheck(char *uri, ACLListHandle_t **acllist_p);
+extern void ACL_CacheEnter(char *uri, ACLListHandle_t **acllist_p);
+extern void ACL_CacheAbort(ACLListHandle_t **acllist_p);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/ldapacl.cpp b/lib/libaccess/ldapacl.cpp
new file mode 100644
index 00000000..ad9d7f7f
--- /dev/null
+++ b/lib/libaccess/ldapacl.cpp
@@ -0,0 +1,822 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* #define DBG_PRINT */
+
+#include <netsite.h>
+#include <base/rwlock.h>
+#include <base/ereport.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include "aclutil.h"
+#include <ldaputil/errors.h>
+#include <ldaputil/certmap.h>
+#include <ldaputil/ldaputil.h>
+#include <ldaputil/dbconf.h>
+#include <ldaputil/ldapauth.h>
+#include <libaccess/authdb.h>
+#include <libaccess/ldapacl.h>
+#include <libaccess/usrcache.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/aclerror.h>
+
+#define BIG_LINE 1024
+
+static int need_ldap_over_ssl = 0;
+static RWLOCK ldb_rwlock = (RWLOCK)0;
+
+void init_ldb_rwlock ()
+{
+ ldb_rwlock = rwlock_Init();
+}
+
+void ldb_write_rwlock (LDAPDatabase_t *ldb, RWLOCK lock)
+{
+ DBG_PRINT1("ldb_write_rwlock\n");
+ /* Don't lock for local database -- let ldapsdk handle thread safety*/
+ if (!ldapu_is_local_db(ldb))
+ rwlock_WriteLock(lock);
+}
+
+void ldb_read_rwlock (LDAPDatabase_t *ldb, RWLOCK lock)
+{
+ DBG_PRINT1("ldb_read_rwlock\n");
+ /* Don't lock for local database -- let ldapsdk handle thread safety*/
+ if (!ldapu_is_local_db(ldb))
+ rwlock_ReadLock(lock);
+}
+
+void ldb_unlock_rwlock (LDAPDatabase_t *ldb, RWLOCK lock)
+{
+ DBG_PRINT1("ldb_unlock_rwlock\n");
+ /* we don't lock for local database */
+ if (!ldapu_is_local_db(ldb))
+ rwlock_Unlock(lock);
+}
+
+int ACL_NeedLDAPOverSSL ()
+{
+ return need_ldap_over_ssl;
+}
+
+NSAPI_PUBLIC int parse_ldap_url (NSErr_t *errp, ACLDbType_t dbtype,
+ const char *dbname, const char *url,
+ PList_t plist, void **db)
+{
+ LDAPDatabase_t *ldb;
+ char *binddn = 0;
+ char *bindpw = 0;
+ int rv;
+
+ *db = 0;
+
+ if (!url || !*url) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5800, ACL_Program, 1, XP_GetAdminStr(DBT_ldapaclDatabaseUrlIsMissing));
+ return -1;
+ }
+
+ if (!dbname || !*dbname) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5810, ACL_Program, 1, XP_GetAdminStr(DBT_ldapaclDatabaseNameIsMissing));
+ return -1;
+ }
+
+ /* look for binddn and bindpw in the plist */
+ if (plist) {
+ PListFindValue(plist, LDAPU_ATTR_BINDDN, (void **)&binddn, NULL);
+ PListFindValue(plist, LDAPU_ATTR_BINDPW, (void **)&bindpw, NULL);
+ }
+
+ rv = ldapu_url_parse(url, binddn, bindpw, &ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5820, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclErrorParsingLdapUrl), ldapu_err2string(rv));
+ return -1;
+ }
+
+ /* success */
+ *db = ldb;
+
+ /* Check if we need to do LDAP over SSL */
+ if (!need_ldap_over_ssl) {
+ need_ldap_over_ssl = ldb->use_ssl;
+ }
+
+ return 0;
+}
+
+int get_is_valid_password_basic_ldap (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ /* If the raw-user-name and raw-user-password attributes are present then
+ * verify the password against the LDAP database.
+ * Otherwise call AttrGetter for raw-user-name.
+ */
+ char *raw_user;
+ char *raw_pw;
+ char *userdn = 0;
+ int rv;
+ char *dbname;
+ ACLDbType_t dbtype;
+ LDAPDatabase_t *ldb;
+ time_t *req_time = 0;
+ pool_handle_t *subj_pool = PListGetPool(subject)
+
+ DBG_PRINT1("get_is_valid_password_basic_ldap\n");
+ rv = ACL_GetAttribute(errp, ACL_ATTR_RAW_USER, (void **)&raw_user,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_RAW_PASSWORD, (void **)&raw_pw,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ if (!raw_pw || !*raw_pw) {
+ /* Null password is not allowed in LDAP since most LDAP servers let
+ * the bind call succeed as anonymous login (with limited privileges).
+ */
+ return LAS_EVAL_FALSE;
+ }
+
+ /* Authenticate the raw_user and raw_pw against LDAP database. */
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5830, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetDatabaseName), rv_str);
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, (void **)&ldb);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5840, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetParsedDatabaseName), dbname);
+ return rv;
+ }
+
+ if (acl_usr_cache_enabled()) {
+ /* avoid unnecessary system call to get time if cache is disabled */
+ req_time = acl_get_req_time(resource);
+
+ /* We have user name and password. */
+ /* Check the cache to see if the password is valid */
+ rv = acl_usr_cache_passwd_check(raw_user, dbname, raw_pw, *req_time,
+ &userdn, subj_pool);
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ }
+
+ if (rv != LAS_EVAL_TRUE) {
+ LDAPMessage *res = 0;
+ const char *some_attrs[] = { "C", 0 };
+ LDAP *ld;
+ char *udn;
+ /* Not found in the cache */
+
+ /* Since we will bind with the user/password and other code relying on
+ * ldb being bound as ldb->binddn and ldb->bindpw may fail. So block
+ * them until we are done.
+ */
+ ldb_write_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5850, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclCoudlntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ /* LDAPU_REQ will reconnect & retry once if LDAP server went down */
+ ld = ldb->ld;
+ LDAPU_REQ(rv, ldb, ldapu_find_uid_attrs(ld, raw_user,
+ ldb->basedn, some_attrs,
+ 1, &res));
+
+ if (rv == LDAPU_SUCCESS) {
+ LDAPMessage *entry = ldap_first_entry(ld, res);
+
+ userdn = ldap_get_dn(ld, entry);
+
+ /* LDAPU_REQ will reconnect & retry once if LDAP server went down */
+ LDAPU_REQ(rv, ldb, ldapu_auth_userdn_password(ld, userdn, raw_pw));
+
+ /* Make sure we rebind with the server's DN
+ * ignore errors from ldapu_ldap_rebind -- we will get the same
+ * errors in subsequent calls to LDAP. Return status from the
+ * above call is our only interest now.
+ */
+ ldapu_ldap_rebind(ldb);
+ }
+
+ if (res) ldap_msgfree(res);
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+
+ if (rv == LDAPU_FAILED || rv == LDAP_INVALID_CREDENTIALS) {
+ /* user entry not found or incorrect password */
+ if (userdn) ldap_memfree(userdn);
+ return LAS_EVAL_FALSE;
+ }
+ else if (rv != LDAPU_SUCCESS) {
+ /* some unexpected LDAP error */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5860, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclPassworkCheckLdapError), ldapu_err2string(rv));
+ if (userdn) ldap_memfree(userdn);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Make an entry in the cache */
+ if (acl_usr_cache_enabled()) {
+ acl_usr_cache_insert(raw_user, dbname, userdn, raw_pw, 0, 0,
+ *req_time);
+ }
+ udn = pool_strdup(subj_pool, userdn);
+ ldap_memfree(userdn);
+ userdn = udn;
+ }
+
+ PListInitProp(subject, ACL_ATTR_IS_VALID_PASSWORD_INDEX, ACL_ATTR_IS_VALID_PASSWORD, raw_user, 0);
+ PListInitProp(subject, ACL_ATTR_USERDN_INDEX, ACL_ATTR_USERDN, userdn, 0);
+ return LAS_EVAL_TRUE;
+}
+
+static int acl_grpcmpfn (const void *groupids, const char *group,
+ const int len)
+{
+ const char *token = (const char *)groupids;
+ int tlen;
+ char delim = ',';
+
+ while((token = acl_next_token_len(token, delim, &tlen)) != NULL) {
+ if (tlen > 0 && tlen == len && !strncmp(token, group, len))
+ return LDAPU_SUCCESS;
+ else if (tlen == 0 || 0 != (token = strchr(token+tlen, delim)))
+ token++;
+ else
+ break;
+ }
+
+ return LDAPU_FAILED;
+}
+
+int get_user_ismember_ldap (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ int retval;
+ int rv;
+ char *userdn;
+ char *groups;
+ char *member_of = 0;
+ LDAPDatabase_t *ldb;
+ char *dbname;
+ ACLDbType_t dbtype;
+
+ DBG_PRINT1("get_user_ismember_ldap\n");
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USERDN, (void **)&userdn, subject,
+ resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_GROUPS, (void **)&groups, subject,
+ resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5900, ACL_Program, 2, XP_GetAdminStr(DBT_GetUserIsMemberLdapUnabelToGetDatabaseName), rv_str);
+ return rv;
+ }
+
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, (void **)&ldb);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR5910, ACL_Program, 2, XP_GetAdminStr(DBT_GetUserIsMemberLdapUnableToGetParsedDatabaseName), dbname);
+ return rv;
+ }
+
+ ldb_read_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5930, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetUserIsMemberLdapCouldntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ /* check if the user is member of any of the groups */
+ /* LDAPU_REQ will reconnect & retry once if LDAP server went down */
+ LDAPU_REQ(rv, ldb, ldapu_auth_userdn_groupids(ldb->ld,
+ userdn,
+ groups,
+ acl_grpcmpfn,
+ ldb->basedn,
+ &member_of));
+
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+
+ if (rv == LDAPU_SUCCESS) {
+ /* User is a member of one of the groups */
+ if (member_of) {
+ PListInitProp(subject, ACL_ATTR_USER_ISMEMBER_INDEX,
+ ACL_ATTR_USER_ISMEMBER,
+ pool_strdup(PListGetPool(subject), member_of), 0);
+ retval = LAS_EVAL_TRUE;
+ }
+ else {
+ /* This shouldn't happen */
+ retval = LAS_EVAL_FALSE;
+ }
+ }
+ else if (rv == LDAPU_FAILED) {
+ /* User is not a member of any of the groups */
+ retval = LAS_EVAL_FALSE;
+ }
+ else {
+ /* unexpected LDAP error */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5950, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetUserIsMemberLdapError),
+ ldapu_err2string(rv));
+ retval = LAS_EVAL_FAIL;
+ }
+
+ return retval;
+}
+
+
+/* This function returns LDAPU error codes so that the caller can call
+ * ldapu_err2string to get the error string.
+ */
+int acl_map_cert_to_user (NSErr_t *errp, const char *dbname,
+ LDAPDatabase_t *ldb, void *cert,
+ PList_t resource, pool_handle_t *pool,
+ char **user, char **userdn)
+{
+ int rv;
+ LDAPMessage *res;
+ LDAPMessage *entry;
+ char *uid;
+ time_t *req_time = 0;
+
+ if (acl_usr_cache_enabled()) {
+ req_time = acl_get_req_time(resource);
+
+ rv = acl_cert_cache_get_uid (cert, dbname, *req_time, user, userdn,
+ pool);
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ }
+
+ if (rv != LAS_EVAL_TRUE) {
+ /* Not found in the cache */
+
+ ldb_read_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ /* LDAPU_REQ will reconnect & retry once if LDAP server went down */
+ /* it sets the variable rv */
+ if (rv == LDAPU_SUCCESS) {
+ char *dn = 0;
+
+ LDAPU_REQ(rv, ldb, ldapu_cert_to_user(cert, ldb->ld, ldb->basedn,
+ &res, &uid));
+
+ if (rv == LDAPU_SUCCESS) {
+ char *dn;
+
+ *user = pool_strdup(pool, uid);
+ if (!*user) rv = LDAPU_ERR_OUT_OF_MEMORY;
+ free(uid);
+
+ entry = ldap_first_entry(ldb->ld, res);
+ dn = ldap_get_dn(ldb->ld, entry);
+ if (acl_usr_cache_enabled()) {
+ acl_cert_cache_insert (cert, dbname, *user, dn, *req_time);
+ }
+ *userdn = dn ? pool_strdup(pool, dn) : 0;
+ if (!*userdn) rv = LDAPU_ERR_OUT_OF_MEMORY;
+ ldap_memfree(dn);
+ }
+ if (res) ldap_msgfree(res);
+ }
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ }
+ else {
+ rv = LDAPU_SUCCESS;
+ }
+
+ return rv;
+}
+
+
+/*
+ * ACL_LDAPDatabaseHandle -
+ * Finds the internal structure representing the 'dbname'. If it is an LDAP
+ * database, returns the 'LDAP *ld' pointer. Also, binds to the LDAP server.
+ * The LDAP *ld handle can be used in calls to LDAP API.
+ * Returns LAS_EVAL_TRUE if successful, otherwise logs an error in
+ * LOG_SECURITY and returns LAS_EVAL_FAIL.
+ */
+int ACL_LDAPDatabaseHandle (NSErr_t *errp, const char *dbname, LDAP **ld,
+ char **basedn)
+{
+ int rv;
+ ACLDbType_t dbtype;
+ void *db;
+ LDAPDatabase_t *ldb;
+
+ *ld = 0;
+ if (!dbname || !*dbname) dbname = DBCONF_DEFAULT_DBNAME;
+
+ /* Check if the ldb is already in the ACLUserLdbHash */
+ ldb = (LDAPDatabase_t *)PR_HashTableLookup(ACLUserLdbHash, dbname);
+
+ if (!ldb) {
+
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, &db);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRINVAL, ACLERR6000, ACL_Program, 2, XP_GetAdminStr(DBT_LdapDatabaseHandleNotARegisteredDatabase), dbname);
+ return LAS_EVAL_FAIL;
+ }
+
+ if (!ACL_DbTypeIsEqual(errp, dbtype, ACL_DbTypeLdap)) {
+ /* Not an LDAP database -- error */
+ nserrGenerate(errp, ACLERRINVAL, ACLERR6010, ACL_Program, 2, XP_GetAdminStr(DBT_LdapDatabaseHandleNotAnLdapDatabase), dbname);
+ return LAS_EVAL_FAIL;
+ }
+
+ ldb = ldapu_copy_LDAPDatabase_t((LDAPDatabase_t *)db);
+
+ if (!ldb) {
+ /* Not an LDAP database -- error */
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR6020, ACL_Program, 1, XP_GetAdminStr(DBT_LdapDatabaseHandleOutOfMemory));
+ return LAS_EVAL_FAIL;
+ }
+
+ PR_HashTableAdd(ACLUserLdbHash, PERM_STRDUP(dbname), ldb);
+ }
+
+ if (!ldb->ld) {
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR6030, ACL_Program, 2, XP_GetAdminStr(DBT_LdapDatabaseHandleCouldntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+ }
+
+ /*
+ * Force the rebind -- we don't know whether the customer has used this ld
+ * to bind as somebody else. It will also check if the LDAP server is up
+ * and running, reestablish the connection if the LDAP server has rebooted
+ * since it was last used.
+ */
+ rv = ldapu_ldap_rebind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR6040, ACL_Program, 2, XP_GetAdminStr(DBT_LdapDatabaseHandleCouldntBindToLdapServer), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ *ld = ldb->ld;
+
+ if (basedn) {
+ /* They asked for the basedn too */
+ *basedn = PERM_STRDUP(ldb->basedn);
+ }
+
+ return LAS_EVAL_TRUE;
+}
+
+int get_userdn_ldap (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ char *uid;
+ char *dbname;
+ char *userdn;
+ time_t *req_time = 0;
+ pool_handle_t *subj_pool = PListGetPool(subject);
+ int rv;
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&uid, subject,
+ resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return LAS_EVAL_FAIL;
+ }
+
+ /* The getter for ACL_ATTR_USER may have put the USERDN on the PList */
+ rv = PListGetValue(subject, ACL_ATTR_USERDN_INDEX, (void **)&userdn, NULL);
+
+ if (rv >= 0) {
+ /* Nothing to do */
+ return LAS_EVAL_TRUE;
+ }
+
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5830, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetDatabaseName), rv_str);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Check if the userdn is available in the usr_cache */
+ if (acl_usr_cache_enabled()) {
+ /* avoid unnecessary system call to get time if cache is disabled */
+ req_time = acl_get_req_time(resource);
+
+ rv = acl_usr_cache_get_userdn(uid, dbname, *req_time, &userdn,
+ subj_pool);
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ }
+
+ if (rv == LAS_EVAL_TRUE) {
+ /* Found in the cache */
+ PListInitProp(subject, ACL_ATTR_USERDN_INDEX, ACL_ATTR_USERDN,
+ userdn, 0);
+ }
+ else {
+ ACLDbType_t dbtype;
+ LDAPDatabase_t *ldb = 0;
+
+ /* Perform LDAP lookup */
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, (void **)&ldb);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5840, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetParsedDatabaseName), dbname);
+ return rv;
+ }
+
+ ldb_read_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5850, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclCoudlntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ LDAPU_REQ(rv, ldb, ldapu_find_userdn(ldb->ld, uid, ldb->basedn,
+ &userdn));
+
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+
+ if (rv == LDAPU_SUCCESS) {
+ /* Found it. Store it in the cache also. */
+ PListInitProp(subject, ACL_ATTR_USERDN_INDEX, ACL_ATTR_USERDN,
+ pool_strdup(subj_pool, userdn), 0);
+ if (acl_usr_cache_enabled()) {
+ acl_usr_cache_set_userdn(uid, dbname, userdn, *req_time);
+ }
+ ldapu_free(userdn);
+ rv = LAS_EVAL_TRUE;
+ }
+ else if (rv == LDAPU_FAILED) {
+ /* Not found but not an error */
+ rv = LAS_EVAL_FALSE;
+ }
+ else {
+ /* some unexpected LDAP error */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5860, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclPassworkCheckLdapError), ldapu_err2string(rv));
+ rv = LAS_EVAL_FAIL;
+ }
+ }
+
+ return rv;
+}
+
+/* Attr getter for LDAP database to check if the user exists */
+int get_user_exists_ldap (NSErr_t *errp, PList_t subject,
+ PList_t resource, PList_t auth_info,
+ PList_t global_auth, void *unused)
+{
+ int rv;
+ char *user;
+ char *userdn;
+
+ /* See if the userdn is already available */
+ rv = PListGetValue(subject, ACL_ATTR_USERDN_INDEX, (void **)&userdn, NULL);
+
+ if (rv >= 0) {
+ /* Check if the DN is still valid against the database */
+ /* Get the database name */
+ char *dbname;
+ ACLDbType_t dbtype;
+ LDAPDatabase_t *ldb = 0;
+ LDAPMessage *res;
+ const char *some_attrs[] = { "c", 0 };
+
+ rv = ACL_AuthInfoGetDbname(auth_info, &dbname);
+
+ if (rv < 0) {
+ char rv_str[16];
+ sprintf(rv_str, "%d", rv);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5830, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetDatabaseName), rv_str);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Perform LDAP lookup */
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, (void **)&ldb);
+
+ if (rv != LAS_EVAL_TRUE) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5840, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ldapaclUnableToGetParsedDatabaseName), dbname);
+ return rv;
+ }
+
+ ldb_read_rwlock(ldb, ldb_rwlock);
+ rv = ldapu_ldap_init_and_bind(ldb);
+
+ if (rv != LDAPU_SUCCESS) {
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5850, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclCoudlntInitializeConnectionToLdap), ldapu_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ LDAPU_REQ(rv, ldb, ldapu_find (ldb->ld, ldb->basedn, LDAP_SCOPE_BASE,
+ NULL, some_attrs, 1, &res));
+
+ ldb_unlock_rwlock(ldb, ldb_rwlock);
+
+ if (rv == LDAPU_SUCCESS) {
+ /* Found it. */
+ rv = LAS_EVAL_TRUE;
+ }
+ else if (rv == LDAPU_FAILED) {
+ /* Not found but not an error */
+ rv = LAS_EVAL_FALSE;
+ }
+ else {
+ /* some unexpected LDAP error */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR5860, ACL_Program, 2, XP_GetAdminStr(DBT_ldapaclPassworkCheckLdapError), ldapu_err2string(rv));
+ rv = LAS_EVAL_FAIL;
+ }
+ }
+ else {
+ /* If the DN doesn't exist, should we just return an error ? */
+ /* If yes, we don't need rest of the code */
+
+ /* If we don't have a DN, we must have a user at least */
+ rv = PListGetValue(subject, ACL_ATTR_USER_INDEX, (void **)&user, NULL);
+
+ if (rv < 0) {
+ /* We don't even have a user name */
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USERDN, (void **)&userdn, subject,
+ resource, auth_info, global_auth);
+ }
+
+ /* If we can get the userdn then the user exists */
+ if (rv == LAS_EVAL_TRUE) {
+ PListInitProp(subject, ACL_ATTR_USER_EXISTS_INDEX,
+ ACL_ATTR_USER_EXISTS, userdn, 0);
+ }
+
+ return rv;
+}
+
+/* acl_user_exists - */
+/* Function to check if the user still exists */
+/* This function works for all kinds of databases */
+/* Returns 0 on success and -ve value on failure */
+NSAPI_PUBLIC int acl_user_exists (const char *user, const char *userdn,
+ const char *dbname, const int logerr)
+{
+ NSErr_t err = NSERRINIT;
+ NSErr_t *errp = &err;
+ pool_handle_t *pool = 0;
+ time_t *req_time = 0;
+ PList_t subject = 0;
+ PList_t resource = 0;
+ PList_t auth_info = 0;
+ PList_t global_auth = NULL;
+ char *olddn = 0;
+ int rv;
+
+ /* Check if the userdn is available in the usr_cache */
+ if (acl_usr_cache_enabled() && userdn) {
+ /* avoid unnecessary system call to get time if cache is disabled */
+ req_time = (time_t *)MALLOC(sizeof(time_t));
+
+ if (req_time) {
+ time(req_time);
+ rv = acl_usr_cache_userdn_check(user, dbname, userdn, *req_time);
+ FREE((void *)req_time);
+ }
+
+ if (rv == LAS_EVAL_TRUE)
+ {
+ /* Found in the cache with the same DN */
+ return 0;
+ }
+ }
+
+ pool = pool_create();
+ subject = PListCreate(pool, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ resource = PListCreate(pool, ACL_ATTR_INDEX_MAX, NULL, NULL);
+ auth_info = PListCreate(pool, ACL_ATTR_INDEX_MAX, NULL, NULL);
+
+ if (!pool || !subject || !resource || !auth_info) {
+ /* ran out of memory */
+ goto no_mem;
+ }
+
+ /* store a pointer to the user rather than a copy */
+ rv = PListInitProp(subject, ACL_ATTR_USER_INDEX, ACL_ATTR_USER,
+ user, 0);
+ if (rv < 0) { /* Plist error */ goto plist_err; }
+
+ if (userdn && *userdn) {
+ /* store a pointer to the userdn rather than a copy */
+ rv = PListInitProp(subject, ACL_ATTR_USERDN_INDEX, ACL_ATTR_USERDN,
+ userdn, 0);
+ if (rv < 0) { /* Plist error */ goto plist_err; }
+ }
+
+ /* store the cached dbname on auth_info */
+ rv = ACL_AuthInfoSetDbname(errp, auth_info, dbname);
+ if (rv < 0) { /* auth_info error */ goto err; }
+
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER_EXISTS, (void **)&user,
+ subject, resource, auth_info, global_auth);
+
+ if (rv == LAS_EVAL_TRUE) {
+ /* User still exists */
+ rv = 0;
+ }
+ else if (rv == LAS_EVAL_FALSE) {
+ /* User doesn't exist anymore */
+ nserrGenerate(errp, ACLERRFAIL, 5880, ACL_Program, 2, XP_GetAdminStr(DBT_AclUserExistsNot), user);
+ goto err;
+ }
+ else {
+ /* Unexpected error while checking the existence of the user */
+ goto err;
+ }
+
+ goto done;
+
+plist_err:
+ nserrGenerate(errp, ACLERRFAIL, 5890, ACL_Program, 1, XP_GetAdminStr(DBT_AclUserPlistError));
+ goto err;
+
+no_mem:
+ nserrGenerate(errp, ACLERRNOMEM, 5870, ACL_Program, 1, XP_GetAdminStr(DBT_AclUserExistsOutOfMemory));
+ goto err;
+
+err:
+ if (logerr) {
+ /* Unexpected error while checking the existence of the user */
+ char buf[BIG_LINE];
+ /* generate error message (upto depth 6) into buf */
+ aclErrorFmt(errp, buf, BIG_LINE, 6);
+ ereport(LOG_SECURITY, "Error while checking the existence of user: %s", buf);
+ }
+
+ nserrDispose(errp);
+ rv = -1;
+
+done:
+ /* Destroy the PLists & the pool */
+ if (subject) PListDestroy(subject);
+ if (resource) PListDestroy(resource);
+ if (auth_info) PListDestroy(auth_info);
+ if (pool) pool_destroy(pool);
+ return rv;
+}
diff --git a/lib/libaccess/ldapauth.h b/lib/libaccess/ldapauth.h
new file mode 100644
index 00000000..409aa6e9
--- /dev/null
+++ b/lib/libaccess/ldapauth.h
@@ -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 **/
+
+#ifndef LDAP_AUTH_H
+#define LDAP_AUTH_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "ldap/ldap.h"
+
+const int LDAP_ACL_SUCCESS = 0;
+const int LDAP_ACL_FAILED = -1;
+
+extern int ldap_auth_userdn_groupdn (LDAP *ld, char *userdn,
+ char *groupdn);
+extern int ldap_auth_uid_groupdn (LDAP *ld, char *uid,
+ char *groupdn);
+extern int ldap_auth_uid_groupid (LDAP *ld, char *uid,
+ char *groupid);
+extern int ldap_auth_userdn_groupid (LDAP *ld, char *userdn,
+ char *groupid);
+extern int ldap_auth_userdn_attrfilter (LDAP *ld, char *userdn,
+ char *attrfilter);
+extern int ldap_auth_uid_attrfilter (LDAP *ld, char *uid,
+ char *attrfilter);
+extern int ldap_auth_userdn_password (LDAP *ld, char *userdn,
+ char *password);
+extern int ldap_find_uid (LDAP *ld, char *uid, LDAPMessage **res);
+extern int ldap_auth_uid_password (LDAP *ld, char *uid,
+ char *password);
+extern LDAP *init_ldap();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LDAP_AUTH_H */
diff --git a/lib/libaccess/leval.h b/lib/libaccess/leval.h
new file mode 100644
index 00000000..22d3ee8a
--- /dev/null
+++ b/lib/libaccess/leval.h
@@ -0,0 +1,18 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef LEVAL_H
+#define LEVAL_H
+
+NSPR_BEGIN_EXTERN_C
+
+int
+freeLAS(NSErr_t *errp, char *attribute, void **las_cookie);
+
+NSPR_END_EXTERN_C
+
+#endif
+
diff --git a/lib/libaccess/lparse.h b/lib/libaccess/lparse.h
new file mode 100644
index 00000000..6386d56e
--- /dev/null
+++ b/lib/libaccess/lparse.h
@@ -0,0 +1,27 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * This grammar is intended to parse the version 3.0 ACL
+ * and output an ACLParseACE_t structure.
+ */
+
+#ifndef LPARSE_H
+#define LPARSE_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int aclPushListHandle(ACLListHandle_t *handle);
+extern int aclparse(void);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/lib/libaccess/method.cpp b/lib/libaccess/method.cpp
new file mode 100644
index 00000000..1425ad55
--- /dev/null
+++ b/lib/libaccess/method.cpp
@@ -0,0 +1,163 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <netsite.h>
+#include <libaccess/las.h>
+#include <libaccess/acl.h>
+#include <libaccess/aclerror.h>
+#include <libaccess/dbtlibaccess.h>
+#include "aclpriv.h"
+
+NSAPI_PUBLIC int ACL_ModuleRegister (NSErr_t *errp, const char *module_name,
+ AclModuleInitFunc func)
+{
+ int rv;
+
+ if (!module_name || !*module_name) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4200, ACL_Program, 1,
+ XP_GetAdminStr(DBT_ModuleRegisterModuleNameMissing));
+ return -1;
+ }
+
+ rv = (*func)(errp);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4210, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ModuleRegisterFailed), module_name);
+ return rv;
+ }
+
+ return 0;
+}
+
+
+static int attr_getter_is_matching(NSErr_t *errp, ACLAttrGetter_t *getter,
+ ACLMethod_t method, ACLDbType_t dbtype)
+{
+ if ((ACL_MethodIsEqual(errp, getter->method, method) ||
+ ACL_MethodIsEqual(errp, getter->method, ACL_METHOD_ANY)) &&
+ (ACL_DbTypeIsEqual(errp, getter->dbtype, dbtype) ||
+ ACL_DbTypeIsEqual(errp, getter->dbtype, ACL_DBTYPE_ANY)))
+ {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+
+NSAPI_PUBLIC int ACL_GetAttribute(NSErr_t *errp, const char *attr, void **val,
+ PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ int rv;
+ void *attrval;
+ ACLAttrGetterFn_t func;
+ ACLAttrGetterList_t getters;
+ ACLAttrGetter_t *getter;
+ ACLMethod_t method;
+ ACLDbType_t dbtype;
+
+ /* If subject PList is NULL, we will fail anyway */
+ if (!subject) return LAS_EVAL_FAIL;
+
+ /* Is the attribute already present in the subject property list? */
+
+ rv = PListFindValue(subject, attr, &attrval, NULL);
+ if (rv >= 0) {
+
+ /* Yes, take it from there */
+ *val = attrval;
+ return LAS_EVAL_TRUE;
+ }
+
+ /* Get the authentication method and database type */
+
+ rv = ACL_AuthInfoGetMethod(errp, auth_info, &method);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4300, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeCouldntDetermineMethod), attr);
+ return LAS_EVAL_FAIL;
+ }
+
+ rv = ACL_AuthInfoGetDbType (errp, auth_info, &dbtype);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4380, ACL_Program, 2,
+ XP_GetAdminStr(DBT_ReadDbMapFileCouldntDetermineDbtype), attr);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Get the list of attribute getters */
+
+ rv = ACL_AttrGetterFind(errp, attr, &getters);
+
+ if ((rv < 0) || (getters == 0)) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4310, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeCouldntLocateGetter), attr);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Iterate over each getter and see if it should be called
+ * Call each matching getter until a getter which doesn't decline is
+ * found.
+ */
+
+ for (getter = ACL_AttrGetterFirst(&getters);
+ getter != 0;
+ getter = ACL_AttrGetterNext(&getters, getter)) {
+
+ /* Require matching method and database type */
+
+ if (attr_getter_is_matching(errp, getter, method, dbtype)) {
+
+ /* Call the getter function */
+ func = getter->fn;
+ rv = (*func)(errp, subject, resource, auth_info, global_auth,
+ getter->arg);
+
+ /* Did the getter succeed? */
+ if (rv == LAS_EVAL_TRUE) {
+
+ /*
+ * Yes, it should leave the attribute on the subject
+ * property list.
+ */
+ rv = PListFindValue(subject, attr, (void **)&attrval, NULL);
+
+ if (rv < 0) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4320, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeDidntSetAttr), attr);
+ return LAS_EVAL_FAIL;
+ }
+
+ /* Got it */
+ *val = attrval;
+ return LAS_EVAL_TRUE;
+ }
+
+ /* Did the getter decline? */
+ if (rv != LAS_EVAL_DECLINE) {
+
+ /* No, did it fail to get the attribute */
+ if (rv == LAS_EVAL_FAIL || rv == LAS_EVAL_INVALID) {
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4330, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeDidntGetAttr), attr);
+ }
+
+ return rv;
+ }
+ }
+ }
+
+ /* If we fall out of the loop, all the getters declined */
+ nserrGenerate(errp, ACLERRFAIL, ACLERR4340, ACL_Program, 2,
+ XP_GetAdminStr(DBT_GetAttributeAllGettersDeclined), attr);
+ return LAS_EVAL_FAIL;
+}
+
diff --git a/lib/libaccess/nsadb.cpp b/lib/libaccess/nsadb.cpp
new file mode 100644
index 00000000..a87951b8
--- /dev/null
+++ b/lib/libaccess/nsadb.cpp
@@ -0,0 +1,582 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsadb.c)
+ *
+ * This module contains routines for retrieving information from
+ * a Netscape authentication database. An authentication database
+ * consists of a user database and a group database. This module
+ * implements an authentication database based on Netscape user and
+ * group databases defined in nsuser.h and nsgroup.h, which in turn
+ * are based on the Netscape (server) database implementation
+ * defined in nsdb.h. The interface for managing information in
+ * an authentication database is described separately in nsamgmt.h.
+ */
+
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#include <base/fsmutex.h>
+#include <libaccess/nsdbmgmt.h>
+#define __PRIVATE_NSADB
+#include <libaccess/nsadb.h>
+#include <libaccess/nsuser.h>
+#include <libaccess/nsgroup.h>
+
+/*
+ * Description (NSADB_AuthIF)
+ *
+ * This structure defines a generic authentication database
+ * interface for this module. It does not currently support
+ * user/group id lookup.
+ */
+AuthIF_t NSADB_AuthIF = {
+ 0, /* find user/group by id */
+ nsadbFindByName, /* find user/group by name */
+ nsadbIdToName, /* lookup name for user/group id */
+ nsadbOpen, /* open a named database */
+ nsadbClose, /* close a database */
+};
+
+/*
+ * Description (nsadbClose)
+ *
+ * This function closes an authentication database previously opened
+ * via nsadbOpen().
+ *
+ * Arguments:
+ *
+ * authdb - handle returned by nsadbOpen()
+ * flags - unused (must be zero)
+ */
+
+NSAPI_PUBLIC void nsadbClose(void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+
+ if (adb->adb_userdb != 0) {
+ ndbClose(adb->adb_userdb, 0);
+ }
+
+ if (adb->adb_groupdb != 0) {
+ ndbClose(adb->adb_groupdb, 0);
+ }
+
+#if defined(CLIENT_AUTH)
+ nsadbCloseCerts(authdb, flags);
+#endif
+
+ if (adb->adb_dbname) {
+ FREE(adb->adb_dbname);
+ }
+
+ FREE(adb);
+}
+
+/*
+ * Description (nsadbOpen)
+ *
+ * This function is used to open an authentication database.
+ * The caller specifies a name for the database, which is actually
+ * the name of a directory containing the files which comprise the
+ * database. The caller also indicates whether this is a new
+ * database, in which case it is created.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * adbname - name of this database (directory)
+ * flags - open flags:
+ * AIF_CREATE - new database (create)
+ * rptr - pointer to returned handle
+ *
+ * Returns:
+ *
+ * A handle for accessing the database is always returned via 'rptr'
+ * unless there was a shortage of dynamic memory, in which case a
+ * null handle is returned. The return value of the function is
+ * 0 if it completes successfully. An error is indicated by a
+ * negative return value (see nsautherr.h).
+ */
+
+NSAPI_PUBLIC int nsadbOpen(NSErr_t * errp,
+ char * adbname, int flags, void **rptr)
+{
+ AuthDB_t * authdb = 0; /* pointer to database descriptor */
+ SYS_DIR dbdir; /* database directory handle */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Make sure we have a place to return the database handle */
+ if (rptr == 0) goto err_inval;
+
+ /* Allocate the database descriptor */
+ authdb = (AuthDB_t *)MALLOC(sizeof(AuthDB_t));
+ if (authdb == 0) goto err_nomem;
+
+ /* Return the descriptor pointer as the database handle */
+ *rptr = (void *)authdb;
+
+ authdb->adb_dbname = STRDUP(adbname);
+ authdb->adb_userdb = 0;
+ authdb->adb_groupdb = 0;
+#if defined(CLIENT_AUTH)
+ authdb->adb_certdb = 0;
+ authdb->adb_certlock = 0;
+ authdb->adb_certnm = 0;
+#endif
+ authdb->adb_flags = 0;
+
+ /* See if the database directory exists */
+ dbdir = dir_open(adbname);
+ if (dbdir == 0) {
+ /* No, create it if this is a new database, else error */
+ if (flags & AIF_CREATE) {
+ rv = dir_create(adbname);
+ if (rv < 0) goto err_mkdir;
+ authdb->adb_flags |= ADBF_NEW;
+ }
+ else goto err_dopen;
+ }
+ else {
+ /* Ok, it's there */
+ dir_close(dbdir);
+ }
+
+ return 0;
+
+ err_inval:
+ eid = NSAUERR3000;
+ rv = NSAERRINVAL;
+ goto err_ret;
+
+ err_nomem:
+ /* Error - insufficient dynamic memory */
+ eid = NSAUERR3020;
+ rv = NSAERRNOMEM;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+
+ err_mkdir:
+ eid = NSAUERR3040;
+ rv = NSAERRMKDIR;
+ goto err_dir;
+
+ err_dopen:
+ eid = NSAUERR3060;
+ rv = NSAERROPEN;
+ goto err_dir;
+
+ err_dir:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, adbname);
+ goto punt;
+
+ punt:
+ /* Fatal error - free database descriptor and return null handle */
+ if (authdb) {
+ if (authdb->adb_dbname) {
+ FREE(authdb->adb_dbname);
+ }
+ FREE(authdb);
+ }
+
+ if (rptr) *rptr = 0;
+
+ return rv;
+}
+
+/*
+ * Description (nsadbOpenUsers)
+ *
+ * This function is called to open the users subdatabase of an
+ * open authentication database. The caller specifies flags to
+ * indicate whether read or write access is required. This
+ * function is normally called only by routines below the
+ * nsadbOpen() API, in response to perform particular operations
+ * on user or group objects. If the open is successful, the
+ * resulting handle is stored in the AuthDB_t structure.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * flags - open flags:
+ * ADBF_UREAD - open for read
+ * ADBF_UWRITE - open for read/write
+ * Returns:
+ *
+ * The return value is zero if the operation is successfully
+ * completed. An error is indicated by a negative return value
+ * (see nsautherr.h), and an error frame is generated if an error
+ * frame list was provided.
+ */
+
+NSAPI_PUBLIC int nsadbOpenUsers(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * userfn = 0; /* user database name */
+ int dblen; /* strlen(adb_dbname) */
+ int uversion; /* user database version number */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ if (adb == 0) goto err_inval;
+
+ /* Is the user database already open? */
+ if (adb->adb_userdb != 0) {
+
+ /* Yes, is it open for the desired access? */
+ if (adb->adb_flags & flags) {
+
+ /* Yes, that was easy */
+ return 0;
+ }
+ }
+ else {
+
+ /* We need to open the database */
+
+ /* Allocate space for the user database filename */
+ dblen = strlen(adb->adb_dbname);
+
+ userfn = (char *)MALLOC(dblen + strlen(ADBUSERDBNAME) + 2);
+ if (userfn == 0) goto err_nomem;
+
+ /* Construct user database name */
+ strcpy(userfn, adb->adb_dbname);
+
+ /* Put in a '/' (or '\') if it's not there */
+ if (userfn[dblen-1] != FILE_PATHSEP) {
+ userfn[dblen] = FILE_PATHSEP;
+ userfn[dblen+1] = 0;
+ ++dblen;
+ }
+
+ strcpy(&userfn[dblen], ADBUSERDBNAME);
+
+ adb->adb_userdb = ndbOpen(errp,
+ userfn, 0, NDB_TYPE_USERDB, &uversion);
+ if (adb->adb_userdb == 0) goto err_uopen;
+
+ FREE(userfn);
+ }
+
+ /*
+ * We don't really reopen the database to get the desired
+ * access mode, since that is handled at the nsdb level.
+ * But we do update the flags, just for the record.
+ */
+ adb->adb_flags &= ~(ADBF_UREAD|ADBF_UWRITE);
+ if (flags & ADBF_UWRITE) adb->adb_flags |= ADBF_UWRITE;
+ else adb->adb_flags |= ADBF_UREAD;
+
+ return 0;
+
+ err_inval:
+ eid = NSAUERR3200;
+ rv = NSAERRINVAL;
+ goto err_ret;
+
+ err_nomem:
+ eid = NSAUERR3220;
+ rv = NSAERRNOMEM;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+
+ err_uopen:
+ eid = NSAUERR3240;
+ rv = NSAERROPEN;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, userfn);
+ goto punt;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbOpenGroups)
+ *
+ * This function is called to open the groups subdatabase of an
+ * open authentication database. The caller specifies flags to
+ * indicate whether read or write access is required. This
+ * function is normally called only by routines below the
+ * nsadbOpen() API, in response to perform particular operations
+ * on user or group objects. If the open is successful, the
+ * resulting handle is stored in the AuthDB_t structure.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * flags - open flags:
+ * ADBF_GREAD - open for read
+ * ADBF_GWRITE - open for read/write
+ * Returns:
+ *
+ * The return value is zero if the operation is successfully
+ * completed. An error is indicated by a negative return value
+ * (see nsautherr.h), and an error frame is generated if an error
+ * frame list was provided.
+ */
+
+NSAPI_PUBLIC int nsadbOpenGroups(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * groupfn = 0; /* group database name */
+ int dblen; /* strlen(adb_dbname) */
+ int gversion; /* group database version number */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ if (adb == 0) goto err_inval;
+
+ /* Is the group database already open? */
+ if (adb->adb_groupdb != 0) {
+
+ /* Yes, is it open for the desired access? */
+ if (adb->adb_flags & flags) {
+
+ /* Yes, that was easy */
+ return 0;
+ }
+ }
+ else {
+
+ /* We need to open the database */
+
+ /* Allocate space for the group database filename */
+ dblen = strlen(adb->adb_dbname);
+
+ groupfn = (char *)MALLOC(dblen + strlen(ADBGROUPDBNAME) + 2);
+ if (groupfn == 0) goto err_nomem;
+
+ /* Construct group database name */
+ strcpy(groupfn, adb->adb_dbname);
+
+ /* Put in a '/' (or '\') if it's not there */
+ if (groupfn[dblen-1] != FILE_PATHSEP) {
+ groupfn[dblen] = FILE_PATHSEP;
+ groupfn[dblen+1] = 0;
+ ++dblen;
+ }
+
+ strcpy(&groupfn[dblen], ADBGROUPDBNAME);
+
+ adb->adb_groupdb = ndbOpen(errp,
+ groupfn, 0, NDB_TYPE_GROUPDB, &gversion);
+ if (adb->adb_groupdb == 0) goto err_gopen;
+
+ FREE(groupfn);
+ }
+
+ /*
+ * We don't really reopen the database to get the desired
+ * access mode, since that is handled at the nsdb level.
+ * But we do update the flags, just for the record.
+ */
+ adb->adb_flags &= ~(ADBF_GREAD|ADBF_GWRITE);
+ if (flags & ADBF_GWRITE) adb->adb_flags |= ADBF_GWRITE;
+ else adb->adb_flags |= ADBF_GREAD;
+
+ return 0;
+
+ err_inval:
+ eid = NSAUERR3300;
+ rv = NSAERRINVAL;
+ goto err_ret;
+
+ err_nomem:
+ eid = NSAUERR3320;
+ rv = NSAERRNOMEM;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+
+ err_gopen:
+ eid = NSAUERR3340;
+ rv = NSAERROPEN;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, groupfn);
+ goto punt;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbIdToName)
+ *
+ * This function looks up a specified user or group id in the
+ * authentication database. The name associated with the specified
+ * id is returned.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * id - user or group id
+ * flags - AIF_USER or AIF_GROUP (defined in nsauth.h)
+ * rptr - pointer to returned group or user name
+ *
+ * Returns:
+ *
+ * The return value is zero if no error occurs,
+ * A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbIdToName(NSErr_t * errp,
+ void * authdb, USI_t id, int flags, char **rptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ void * whichdb = 0;
+ char * name;
+ int rv;
+
+ if (rptr != 0) *rptr = 0;
+
+ /* Decide whether to use user or group database */
+ if (flags & AIF_USER) {
+
+ whichdb = adb->adb_userdb;
+ if (whichdb == 0) {
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UREAD);
+ if (rv < 0) goto punt;
+ whichdb = adb->adb_userdb;
+ }
+ }
+ else if (flags & AIF_GROUP) {
+
+ whichdb = adb->adb_groupdb;
+ if (whichdb == 0) {
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+ whichdb = adb->adb_groupdb;
+ }
+ }
+
+ if (whichdb != 0) {
+
+ /* Get the name corresponding to the id */
+ rv = ndbIdToName(errp, whichdb, id, 0, &name);
+ if (rv < 0) goto punt;
+
+ if ((rptr != 0)) *rptr = name;
+ rv = 0;
+ }
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbFindByName)
+ *
+ * This function looks up a specified name in the authentication
+ * database. Flags specified by the caller indicate whether a
+ * group name, user name, or either should be found. The caller
+ * may optionally provide for the return of a user or group object
+ * pointer, in which case the information associated with a
+ * matching group or user is used to create a group or user object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * name - name of group or user
+ * flags - search flags (defined in nsauth.h)
+ * rptr - pointer to returned group or user
+ * object pointer (may be null)
+ *
+ * Returns:
+ *
+ * The return value is a non-negative value if no error occurs,
+ * and the value indicates whether the name matched a group or
+ * user:
+ *
+ * AIF_NONE - name did not match a group or user name
+ * AIF_GROUP - name matched a group name
+ * AIF_USER - name matched a user name
+ *
+ * If the value is AIF_GROUP or AIF_USER, and rptr is non-null,
+ * then a group or user object is created, and a pointer to it is
+ * returned in the location indicated by rptr.
+ *
+ * A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbFindByName(NSErr_t * errp, void * authdb,
+ char * name, int flags, void **rptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ ATR_t recptr;
+ int reclen;
+ int rv;
+
+ if (rptr != 0) *rptr = 0;
+
+ /* Search for group name? */
+ if (flags & AIF_GROUP) {
+
+ if (adb->adb_groupdb == 0) {
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+ }
+
+ /* Look up the name in the group database */
+ rv = ndbFindName(errp, adb->adb_groupdb, 0, (char *)name,
+ &reclen, (char **)&recptr);
+ if (rv == 0) {
+
+ /* Found it. Make a group object if requested. */
+ if (rptr != 0) {
+
+ /* Got the group record. Decode into a group object. */
+ *rptr = (void *)groupDecode((NTS_t)name, reclen, recptr);
+ }
+
+ return AIF_GROUP;
+ }
+ }
+
+ /* Search for user name? */
+ if (flags & AIF_USER) {
+
+ if (adb->adb_userdb == 0) {
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UREAD);
+ if (rv < 0) goto punt;
+ }
+
+ /* Look up the name in the user database */
+ rv = ndbFindName(errp, adb->adb_userdb, 0, (char *)name,
+ &reclen, (char **)&recptr);
+ if (rv == 0) {
+
+ /* Found it. Make a user object if requested. */
+ if (rptr != 0) {
+
+ /* Got the user record. Decode into a user object. */
+ *rptr = (void *)userDecode((NTS_t)name, reclen, recptr);
+ }
+
+ return AIF_USER;
+ }
+ }
+
+ /* Nothing found */
+ nserrDispose(errp);
+ return AIF_NONE;
+
+ punt:
+ return rv;
+}
diff --git a/lib/libaccess/nsamgmt.cpp b/lib/libaccess/nsamgmt.cpp
new file mode 100644
index 00000000..544d3617
--- /dev/null
+++ b/lib/libaccess/nsamgmt.cpp
@@ -0,0 +1,1567 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsamgmt.c)
+ *
+ * This module contains routines for managing information in a
+ * Netscape authentication database. An authentication database
+ * consists of a user database and a group database. This module
+ * implements an authentication database based on Netscape user and
+ * group databases defined in nsuser.h and nsgroup.h, which in turn
+ * are based on the Netscape (server) database implementation
+ * defined in nsdb.h. The interface for retrieving information
+ * from an authentication database is described separately in
+ * nsadb.h.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "base/file.h"
+#define __PRIVATE_NSADB
+#include "libaccess/nsamgmt.h"
+#include "libaccess/nsumgmt.h"
+#include "libaccess/nsgmgmt.h"
+
+/*
+ * Description (nsadbEnumUsersHelp)
+ *
+ * This is a local function that is called by NSDB during user
+ * database enumeration. It decodes user records into user
+ * objects, and presents them to the caller of nsadbEnumerateUsers(),
+ * via the specified call-back function. The call-back function
+ * return value may be a negative error code, which will cause
+ * enumeration to stop, and the error code will be returned from
+ * nsadbEnumerateUsers(). If the return value of the call-back
+ * function is not negative, it can contain one or more of the
+ * following flags:
+ *
+ * ADBF_KEEPOBJ - do not free the UserObj_t structure
+ * that was passed to the call-back function
+ * ADBF_STOPENUM - stop the enumeration without an error
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to UserEnumArgs_t structure
+ * namelen - user record key length including null
+ * terminator
+ * name - user record key (user account name)
+ * reclen - length of user record
+ * recptr - pointer to user record contents
+ *
+ * Returns:
+ *
+ * If the call-back returns a negative result, that value is
+ * returned. If the call-back returns ADBF_STOPENUM, then
+ * -1 is returned, causing the enumeration to stop. Otherwise
+ * the return value is zero.
+ */
+
+typedef struct EnumUserArgs_s EnumUserArgs_t;
+struct EnumUserArgs_s {
+ void * authdb;
+ int (*func)(NSErr_t * ferrp,
+ void * authdb, void * argp, UserObj_t * uoptr);
+ void * user;
+ int rv;
+};
+
+static int nsadbEnumUsersHelp(NSErr_t * errp, void * parg,
+ int namelen, char * name,
+ int reclen, char * recptr)
+{
+ EnumUserArgs_t * ue = (EnumUserArgs_t *)parg;
+ UserObj_t * uoptr; /* user object pointer */
+ int rv;
+
+ uoptr = userDecode((NTS_t)name, reclen, (ATR_t)recptr);
+ if (uoptr != 0) {
+ rv = (*ue->func)(errp, ue->authdb, ue->user, uoptr);
+ if (rv >= 0) {
+
+ /* Count the number of users seen */
+ ue->rv += 1;
+
+ /* Free the user object unless the call-back says not to */
+ if (!(rv & ADBF_KEEPOBJ)) {
+ userFree(uoptr);
+ }
+ /* Return either 0 or -1, depending on ADBF_STOPENUM */
+ rv = (rv & ADBF_STOPENUM) ? -1 : 0;
+ }
+ else {
+ /* Free the user object in the event of an error */
+ userFree(uoptr);
+
+ /* Also return the error code */
+ ue->rv = rv;
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumGroupsHelp)
+ *
+ * This is a local function that is called by NSDB during group
+ * database enumeration. It decodes group records into group
+ * objects, and presents them to the caller of nsadbEnumerateGroups(),
+ * via the specified call-back function. The call-back function
+ * return value may be a negative error code, which will cause
+ * enumeration to stop, and the error code will be returned from
+ * nsadbEnumerateGroups(). If the return value of the call-back
+ * function is not negative, it can contain one or more of the
+ * following flags:
+ *
+ * ADBF_KEEPOBJ - do not free the GroupObj_t structure
+ * that was passed to the call-back function
+ * ADBF_STOPENUM - stop the enumeration without an error
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to GroupEnumArgs_t structure
+ * namelen - group record key length including null
+ * terminator
+ * name - group record key (group name)
+ * reclen - length of group record
+ * recptr - pointer to group record contents
+ *
+ * Returns:
+ *
+ * If the call-back returns a negative result, that value is
+ * returned. If the call-back returns ADBF_STOPENUM, then
+ * -1 is returned, causing the enumeration to stop. Otherwise
+ * the return value is zero.
+ */
+
+typedef struct EnumGroupArgs_s EnumGroupArgs_t;
+struct EnumGroupArgs_s {
+ void * authdb;
+ int (*func)(NSErr_t * ferrp,
+ void * authdb, void * argp, GroupObj_t * goptr);
+ void * user;
+ int rv;
+};
+
+static int nsadbEnumGroupsHelp(NSErr_t * errp, void * parg,
+ int namelen, char * name,
+ int reclen, char * recptr)
+{
+ EnumGroupArgs_t * eg = (EnumGroupArgs_t *)parg;
+ GroupObj_t * goptr; /* group object pointer */
+ int rv;
+
+ goptr = groupDecode((NTS_t)name, reclen, (ATR_t)recptr);
+ if (goptr != 0) {
+ rv = (*eg->func)(errp, eg->authdb, eg->user, goptr);
+ if (rv >= 0) {
+
+ /* Count the number of groups seen */
+ eg->rv += 1;
+
+ /* Free the group object unless the call-back says not to */
+ if (!(rv & ADBF_KEEPOBJ)) {
+ groupFree(goptr);
+ }
+ /* Return either 0 or -1, depending on ADBF_STOPENUM */
+ rv = (rv & ADBF_STOPENUM) ? -1 : 0;
+ }
+ else {
+ /* Free the group object in the event of an error */
+ groupFree(goptr);
+
+ /* Also return the error code */
+ eg->rv = rv;
+ }
+ }
+
+ return rv;
+}
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * Description (nsadbAddGroupToGroup)
+ *
+ * This function adds a child group, C, to the definition of a
+ * parent group P. This involves updating the group entries of
+ * C and P in the group database. It also involves updating
+ * the group lists of any user descendants of C, to reflect the
+ * fact that these users are now members of P and P's ancestors.
+ * A check is made for an attempt to create a cycle in the group
+ * hierarchy, and this is rejected as an error.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * pgoptr - pointer to parent group object
+ * cgoptr - pointer to child group object
+ *
+ * Returns:
+ *
+ * The return value is zero if group C was not already a direct
+ * member of group P, and was added successfully. A return value
+ * of +1 indicates that group C was already a direct member of
+ * group P. A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbAddGroupToGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * pgoptr, GroupObj_t * cgoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t gsuper; /* list of ancestors of group P */
+ USIList_t dglist; /* descendant groups of C */
+ GroupObj_t * dgoptr; /* descendant group object pointer */
+ UserObj_t * uoptr; /* user object pointer */
+ USI_t id; /* current descendant group id */
+ int usercount; /* count of users for descendant */
+ USI_t * userlist; /* pointer to array of descendant user ids */
+ USI_t * idlist; /* pointer to array of descendant group ids */
+ int pass; /* loop pass number */
+ int i; /* loop index */
+ int rv; /* result value */
+
+ /* Is C a direct member of P already? */
+ if (usiPresent(&pgoptr->go_groups, cgoptr->go_gid)) {
+ /* Yes, indicate that */
+ return 0;
+ }
+
+ dgoptr = 0;
+ uoptr = 0;
+
+ /* Initialize a list of the group descendants of group C */
+ UILINIT(&dglist);
+
+ /* Initialize a list of P and its ancestors */
+ UILINIT(&gsuper);
+
+ /* Add P to the ancestor list */
+ rv = usiInsert(&gsuper, pgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Open user database since the group lists of users may be modified */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Open group database since group entries will be modified */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* Merge all the ancestors of group P into the list */
+ rv = nsadbSuperGroups(errp, authdb, pgoptr, &gsuper);
+ if (rv < 0) goto punt;
+
+ /*
+ * Each pass through the following loop visits C and all of C's
+ * descendant groups.
+ *
+ * The first pass checks to see if making group C a member of
+ * group P would create a cycle in the group structure. It does
+ * this by examining C and all of its dependents to see if any
+ * appear in the list containing P and P's ancestors.
+ *
+ * The second pass updates the group lists of all users contained
+ * in group C to include P and P's ancestors.
+ */
+
+ for (pass = 1; pass < 3; ++pass) {
+
+ /* Use the group C as the first descendant */
+ id = cgoptr->go_gid;
+ dgoptr = cgoptr;
+
+ for (;;) {
+
+ if (pass == 1) {
+ /*
+ * Check for attempt to create a cycle in the group
+ * hierarchy. See if this descendant is a member of
+ * the list of P and P's ancestors (gsuper).
+ */
+ if (usiPresent(&gsuper, id)) {
+ /*
+ * Error - operation would create a cycle
+ * in the group structure.
+ */
+ return -1;
+ }
+ }
+ else {
+
+ /*
+ * Merge the list of ancestors of P (gsuper) with the
+ * group lists of any direct user members of the current
+ * descendant group, referenced by dgoptr.
+ */
+
+ /* Get direct user member list size and pointer */
+ usercount = UILCOUNT(&dgoptr->go_users);
+ userlist = UILLIST(&dgoptr->go_users);
+
+ /* For each direct user member of this descendant ... */
+ for (i = 0; i < usercount; ++i) {
+
+ /* Get a user object for the user */
+ uoptr = userFindByUid(errp,
+ adb->adb_userdb, userlist[i]);
+ if (uoptr == 0) {
+ /*
+ * Error - user not found,
+ * databases are inconsistent.
+ */
+ rv = -1;
+ goto punt;
+ }
+
+ /* Merge gsuper into the user's group list */
+ rv = uilMerge(&uoptr->uo_groups, &gsuper);
+ if (rv < 0) goto punt;
+
+ /* Write out the user object */
+ uoptr->uo_flags |= UOF_MODIFIED;
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+ if (rv) goto punt;
+
+ /* Free the user object */
+ userFree(uoptr);
+ uoptr = 0;
+ }
+ }
+
+ /*
+ * Merge the direct member groups of the current descendant
+ * group into the list of descendants to be processed.
+ */
+ rv = uilMerge(&dglist, &dgoptr->go_groups);
+ if (rv < 0) goto punt;
+
+ /* Free the group object for the current descendant */
+ if (dgoptr != cgoptr) {
+ groupFree(dgoptr);
+ dgoptr = 0;
+ }
+
+ /* Exit the loop if the descendant list is empty */
+ if (UILCOUNT(&dglist) <= 0) break;
+
+ /* Otherwise remove the next descendant from the list */
+ idlist = UILLIST(&dglist);
+ id = idlist[0];
+ rv = usiRemove(&dglist, id);
+ if (rv < 0) goto punt;
+
+ /* Now get a group object for this descendant group */
+ dgoptr = groupFindByGid(errp, adb->adb_groupdb, id);
+ if (dgoptr == 0) {
+ /* Error - group not found, databases are inconsistent */
+ rv = -1;
+ goto punt;
+ }
+ }
+ }
+
+ /* Now add C to P's list of member groups */
+ rv = usiInsert(&pgoptr->go_groups, cgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Add P to C's list of parent groups */
+ rv = usiInsert(&cgoptr->go_pgroups, pgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Update the database entry for group C */
+ cgoptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, cgoptr);
+ if (rv) goto punt;
+
+ /* Update the database entry for group P */
+ pgoptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, pgoptr);
+
+ return rv;
+
+ punt:
+ /* Handle errors */
+ UILFREE(&gsuper);
+ UILFREE(&dglist);
+ if (dgoptr) {
+ groupFree(dgoptr);
+ }
+ if (uoptr) {
+ userFree(uoptr);
+ }
+ return rv;
+}
+
+/*
+ * Description (nsadbAddUserToGroup)
+ *
+ * This function adds a user to a group definition. This involves
+ * updating the group entry in the group database, and the user
+ * entry in the user database. The caller provides a pointer to
+ * a user object for the user to be added, a pointer to a group
+ * object for the group being modified, and a handle for the
+ * authentication databases (from nsadbOpen()).
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to group object
+ * uoptr - pointer to user object
+ *
+ * Returns:
+ *
+ * The return value is zero if the user was not already a direct
+ * member of the group, and was added successfully. A return value
+ * of +1 indicates that the user was already a direct member of the
+ * group. A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbAddUserToGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * goptr, UserObj_t * uoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t nglist; /* new group list for specified user */
+ USIList_t gsuper; /* groups containing+ the specified group */
+ GroupObj_t * aoptr; /* group object for 'id' group */
+ USI_t * idlist; /* pointer to gsuper gid array */
+ USI_t id; /* current gid from gsuper */
+ int rv; /* result value */
+
+ /* Is the user already a direct member of the group? */
+ if (usiPresent(&goptr->go_users, uoptr->uo_uid)) {
+
+ /* Yes, nothing to do */
+ return 1;
+ }
+
+ /*
+ * The user object contains a list of all of the groups that contain
+ * the user, either directly or indirectly. We need to add the
+ * specified group and its ancestors to this list. Each group contains
+ * a list of the group's parents, which is used to locate all of the
+ * group's ancestors. As an optimization, we need not consider any
+ * ancestors which are already on the user's current group list.
+ */
+
+ /*
+ * The following loop will deal with two lists of group ids. One
+ * is the list that will become the new group list for the user,
+ * which is initialized to the user's current group list. The other
+ * is a list of ancestors of the group to be considered for addition
+ * to the user's group list. This list is initialized to the specified
+ * group.
+ */
+
+ /* Initialize both lists to be empty */
+ UILINIT(&nglist);
+ UILINIT(&gsuper);
+
+ /* Make a copy of the user's current group list */
+ rv = uilDuplicate(&nglist, &uoptr->uo_groups);
+ if (rv < 0) goto punt;
+
+ /* Start the other list with the specified group */
+ rv = usiInsert(&gsuper, goptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Open user database since the group lists of users may be modified */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Open group database since group entries will be modified */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* While entries remain on the ancestor list */
+ while (UILCOUNT(&gsuper) > 0) {
+
+ /* Get pointer to array of ancestor group ids */
+ idlist = UILLIST(&gsuper);
+
+ /* Remove the first ancestor */
+ id = idlist[0];
+ usiRemove(&gsuper, id);
+
+ /* Is the ancestor on the user's current group list? */
+ if (!usiPresent(&uoptr->uo_groups, id)) {
+
+ /* No, add its parents to the ancestor list */
+
+ /* Look up the ancestor group (get a group object for it) */
+ aoptr = groupFindByGid(errp, adb->adb_groupdb, id);
+ if (aoptr == 0) {
+ /* Error - group not found, database inconsistent */
+ rv = -1;
+ goto punt;
+ }
+
+ /* Merge the ancestors parents into the ancestor list */
+ rv = uilMerge(&gsuper, &aoptr->go_pgroups);
+
+ /* Lose the ancestor group object */
+ groupFree(aoptr);
+
+ /* See if the merge worked */
+ if (rv < 0) goto punt;
+ }
+
+ /* Add the ancestor to the new group list for the user */
+ rv = usiInsert(&nglist, id);
+ if (rv < 0) goto punt;
+ }
+
+ /* Add the user to the group's user member list */
+ rv = usiInsert(&goptr->go_users, uoptr->uo_uid);
+ if (rv < 0) goto punt;
+
+ /* Replace the user's group list with the new one */
+ UILREPLACE(&uoptr->uo_groups, &nglist);
+
+ /* Write out the updated user object */
+ uoptr->uo_flags |= UOF_MODIFIED;
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+ if (rv < 0) goto punt;
+
+ /* Write out the updated group object */
+ goptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, goptr);
+
+ return rv;
+
+ punt:
+ /* Handle error */
+
+ /* Free ancestor and new group lists */
+ UILFREE(&nglist);
+ UILFREE(&gsuper);
+
+ return rv;
+}
+
+/*
+ * Description (nsadbCreateGroup)
+ *
+ * This function creates a new group in a specified authentication
+ * database. The group is described by a group object. A group
+ * object can be created by calling nsadbGroupNew().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to group object
+ *
+ * Returns:
+ */
+
+NSAPI_PUBLIC int nsadbCreateGroup(NSErr_t * errp, void * authdb, GroupObj_t * goptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ int rv;
+
+ /* Open the group database for write access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* Add this group to the database */
+ rv = groupStore(errp, adb->adb_groupdb, 0, goptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbCreateUser)
+ *
+ * This function creates a new user in a specified authentication
+ * database. The user is described by a user object. A user
+ * object can be created by calling nsadbUserNew().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * uoptr - pointer to user object
+ *
+ * Returns:
+ */
+
+NSAPI_PUBLIC int nsadbCreateUser(NSErr_t * errp, void * authdb, UserObj_t * uoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ int rv;
+
+ /* Open the user database for write access */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Add this user to the database */
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumerateUsers)
+ *
+ * This function is called to enumerate all of the users in a
+ * given authentication database to a call-back function specified
+ * by the caller. The call-back function is provided with a
+ * handle for the authentication database, an opaque value provided
+ * by the caller, and a pointer to a user object. See the
+ * description of nsadbEnumUsersHelp above for the interpretation
+ * of the call-back function's return value.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * argp - opaque value for call-back function
+ * func - pointer to call-back function
+ *
+ * Returns:
+ *
+ * If the call-back function returns a negative error code, this
+ * value is returned. A negative value may also be returned if
+ * nsadb encounters an error. Otherwise the result is the number
+ * of users enumerated.
+ */
+
+NSAPI_PUBLIC int nsadbEnumerateUsers(NSErr_t * errp, void * authdb, void * argp,
+#ifdef UnixWare
+ ArgFn_EnumUsers func) /* for ANSI C++ standard, see nsamgmt.h */
+#else
+ int (*func)(NSErr_t * ferrp, void * authdb, void * parg, UserObj_t * uoptr))
+#endif
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ EnumUserArgs_t args; /* arguments for enumeration helper */
+ int rv; /* result value */
+
+ /* Open the users subdatabase for read access */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UREAD);
+ if (rv < 0) goto punt;
+
+ args.authdb = authdb;
+ args.func = func;
+ args.user = argp;
+ args.rv = 0;
+
+ rv = ndbEnumerate(errp, adb->adb_userdb,
+ NDBF_ENUMNORM, (void *)&args, nsadbEnumUsersHelp);
+ if (rv < 0) goto punt;
+
+ rv = args.rv;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumerateGroups)
+ *
+ * This function is called to enumerate all of the groups in a
+ * given authentication database to a call-back function specified
+ * by the caller. The call-back function is provided with a
+ * handle for the authentication database, an opaque value provided
+ * by the caller, and a pointer to a group object. See the
+ * description of nsadbEnumGroupsHelp above for the interpretation
+ * of the call-back function's return value.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * argp - opaque value for call-back function
+ * func - pointer to call-back function
+ *
+ * Returns:
+ *
+ * If the call-back function returns a negative error code, this
+ * value is returned. A negative value may also be returned if
+ * nsadb encounters an error. Otherwise the result is the number
+ * of groups enumerated.
+ */
+
+NSAPI_PUBLIC int nsadbEnumerateGroups(NSErr_t * errp, void * authdb, void * argp,
+#ifdef UnixWare
+ ArgFn_EnumGroups func) /* for ANSI C++ standard, see nsamgmt.h */
+#else
+ int (*func)(NSErr_t * ferrp, void * authdb, void * parg, GroupObj_t * goptr))
+#endif
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ EnumGroupArgs_t args;
+ int rv; /* result value */
+
+ /* Open group database for read access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+
+ args.authdb = authdb;
+ args.func = func;
+ args.user = argp;
+ args.rv = 0;
+
+ rv = ndbEnumerate(errp, adb->adb_groupdb,
+ NDBF_ENUMNORM, (void *)&args, nsadbEnumGroupsHelp);
+ if (rv < 0) goto punt;
+
+ rv = args.rv;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbIsUserInGroup)
+ *
+ * This function tests whether a given user id is a member of the
+ * group associated with a specified group id. The caller may
+ * provide a list of group ids for groups to which the user is
+ * already known to belong, and this may speed up the check.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * uid - user id
+ * gid - group id
+ * ngroups - number of group ids in grplist
+ * grplist - groups the user is known to belong to
+ *
+ * Returns:
+ *
+ * The return value is +1 if the user is found to belong to the
+ * indicated group, or 0 if the user does not belong to the group.
+ * An error is indicated by a negative return value.
+ */
+
+NSAPI_PUBLIC int nsadbIsUserInGroup(NSErr_t * errp, void * authdb,
+ USI_t uid, USI_t gid, int ngroups, USI_t * grplist)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t dglist; /* descendant group list */
+ GroupObj_t * goptr = 0; /* group object pointer */
+ USI_t * idlist; /* pointer to array of group ids */
+ USI_t tgid; /* test group id */
+ int i; /* loop index */
+ int rv; /* result value */
+
+ UILINIT(&dglist);
+
+ /* Open group database for read access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+
+ for (tgid = gid;;) {
+
+ /* Get a group object for this group id */
+ goptr = groupFindByGid(errp, adb->adb_groupdb, tgid);
+ if (goptr == 0) {
+ /* Error - group id not found, databases are inconsistent */
+ rv = -1;
+ goto punt;
+ }
+
+ /* Is the user a direct member of this group? */
+ if (usiPresent(&goptr->go_users, uid)) goto is_member;
+
+ /*
+ * Is there any group to which the user is already known to
+ * belong that is a direct group member of this group? If so,
+ * the user is also a member of this group.
+ */
+
+ /* Scan list of groups to which the user is known to belong */
+ for (i = 0; i < ngroups; ++i) {
+
+ if (usiPresent(&goptr->go_groups, grplist[i])) goto is_member;
+ }
+
+ /* Merge group member list of this group with descendants list */
+ rv = uilMerge(&dglist, &goptr->go_groups);
+ if (rv < 0) goto punt;
+
+ /*
+ * If descendants list is empty, the user is not contained in
+ * the specified group.
+ */
+ if (UILCOUNT(&dglist) <= 0) {
+ rv = 0;
+ goto punt;
+ }
+
+ /* Remove the next id from the descendants list */
+ idlist = UILLIST(&dglist);
+ tgid = idlist[0];
+
+ rv = usiRemove(&dglist, tgid);
+ if (rv < 0) goto punt;
+
+ groupFree(goptr);
+ goptr = 0;
+ }
+
+ is_member:
+ rv = 1;
+
+ punt:
+ if (goptr) {
+ groupFree(goptr);
+ }
+ UILFREE(&dglist);
+ return rv;
+}
+
+/*
+ * Description (nsadbModifyGroup)
+ *
+ * This function is called to write modifications to a group to
+ * a specified authentication database. The group is assumed to
+ * already exist in the database. Information about the group
+ * is passed in a group object. This function should not be used
+ * to alter the lists of group members or parents.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to modified group object
+ *
+ * Returns:
+ *
+ * The return value is zero if the group information is successfully
+ * updated. An error is indicated by a negative return value, and
+ * an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbModifyGroup(NSErr_t * errp, void * authdb, GroupObj_t * goptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ int rv;
+
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ rv = groupStore(errp, adb->adb_groupdb, 0, goptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbModifyUser)
+ *
+ * This function is called to write modifications to a user to
+ * a specified authentication database. The user is assumed to
+ * already exist in the database. Information about the user
+ * is passed in a user object. This function should not be used
+ * to modify the list of groups which contain the user.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * uoptr - pointer to modified user object
+ *
+ * Returns:
+ *
+ * The return value is zero if the user information is successfully
+ * updated. An error is indicated by a negative return value, and
+ * an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbModifyUser(NSErr_t * errp, void * authdb, UserObj_t * uoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ int rv;
+
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbRemoveGroup)
+ *
+ * This function is called to remove a given group name from
+ * a specified authentication database. This can cause updates
+ * to both the user and group subdatabases.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * name - pointer to name of group to remove
+ *
+ * Returns:
+ *
+ * The return value is zero if the group information is successfully
+ * removed. An error is indicated by a negative return value, and
+ * an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbRemoveGroup(NSErr_t * errp, void * authdb, char * name)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ UserObj_t * uoptr = 0; /* user object pointer */
+ GroupObj_t * goptr = 0; /* group object pointer */
+ GroupObj_t * ogoptr = 0; /* other group object pointer */
+ char * ugname; /* user or group name */
+ USI_t * list; /* pointer into user/group id list */
+ int cnt; /* count of user or group ids */
+ int i; /* loop index */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Open the groups subdatabase for write access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* Look up the group to be removed, and get a group object */
+ rv = nsadbFindByName(errp, authdb, name, AIF_GROUP, (void **)&goptr);
+ if (rv != AIF_GROUP) {
+ if (rv < 0) goto punt;
+ goto err_nogroup;
+ }
+
+ /* Mark the group for delete */
+ goptr->go_flags |= GOF_DELPEND;
+
+ /* Does the specified group belong to any groups? */
+ cnt = UILCOUNT(&goptr->go_pgroups);
+ if (cnt > 0) {
+
+ /* Yes, for each parent group ... */
+ for (i = 0; i < cnt; ++i) {
+
+ /* Note that nsadbRemGroupFromGroup() will shrink this list */
+ list = UILLIST(&goptr->go_pgroups);
+
+ /* Get group name associated with the group id */
+ rv = nsadbIdToName(errp, authdb, *list, AIF_GROUP, &ugname);
+ if (rv < 0) goto punt;
+
+ /* Look up the group by name and get a group object for it */
+ rv = nsadbFindByName(errp,
+ authdb, ugname, AIF_GROUP, (void **)&ogoptr);
+ if (rv < 0) goto punt;
+
+ /* Remove the specified group from the parent group */
+ rv = nsadbRemGroupFromGroup(errp, authdb, ogoptr, goptr);
+ if (rv < 0) goto punt;
+
+ /* Free the parent group object */
+ groupFree(ogoptr);
+ ogoptr = 0;
+ }
+ }
+
+ /* Are there any group members of this group? */
+ cnt = UILCOUNT(&goptr->go_groups);
+ if (cnt > 0) {
+
+ /* For each group member of the group ... */
+
+ for (i = 0; i < cnt; ++i) {
+
+ /* Note that nsadbRemGroupFromGroup() will shrink this list */
+ list = UILLIST(&goptr->go_groups);
+
+ /* Get group name associated with the group id */
+ rv = nsadbIdToName(errp, authdb, *list, AIF_GROUP, &ugname);
+ if (rv < 0) goto punt;
+
+ /* Look up the group by name and get a group object for it */
+ rv = nsadbFindByName(errp,
+ authdb, ugname, AIF_GROUP, (void **)&ogoptr);
+ if (rv < 0) goto punt;
+
+ /* Remove member group from the specified group */
+ rv = nsadbRemGroupFromGroup(errp, authdb, goptr, ogoptr);
+ if (rv < 0) goto punt;
+
+ /* Free the member group object */
+ groupFree(ogoptr);
+ ogoptr = 0;
+ }
+ }
+
+ /* Are there any direct user members of this group? */
+ cnt = UILCOUNT(&goptr->go_users);
+ if (cnt > 0) {
+
+ /* Yes, open users subdatabase for write access */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* For each user member of the group ... */
+ for (i = 0; i < cnt; ++i) {
+
+ /* Note that nsadbRemUserFromGroup() will shrink this list */
+ list = UILLIST(&goptr->go_users);
+
+ /* Get user name associated with the user id */
+ rv = nsadbIdToName(errp, authdb, *list, AIF_USER, &ugname);
+ if (rv < 0) goto punt;
+
+ /* Look up the user by name and get a user object for it */
+ rv = nsadbFindByName(errp,
+ authdb, ugname, AIF_USER, (void **)&uoptr);
+ if (rv < 0) goto punt;
+
+ /* Remove user from the group */
+ rv = nsadbRemUserFromGroup(errp, authdb, goptr, uoptr);
+ if (rv < 0) goto punt;
+
+ /* Free the member user object */
+ userFree(uoptr);
+ uoptr = 0;
+ }
+ }
+
+ /* Free the group object for the specified group */
+ groupFree(goptr);
+ goptr = 0;
+
+ /* Now we can remove the group entry */
+ rv = groupRemove(errp, adb->adb_groupdb, 0, (NTS_t)name);
+
+ return rv;
+
+ err_nogroup:
+ eid = NSAUERR4100;
+ rv = NSAERRNAME;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 2, adb->adb_dbname, name);
+ goto punt;
+
+ punt:
+ /* Free any user or group objects that we created */
+ if (ogoptr != 0) {
+ groupFree(ogoptr);
+ }
+ if (uoptr != 0) {
+ userFree(uoptr);
+ }
+ if (goptr != 0) {
+ groupFree(goptr);
+ }
+ return rv;
+}
+
+/*
+ * Description (nsadbRemoveUser)
+ *
+ * This function is called to remove a given user name from
+ * a specified authentication database. This can cause updates
+ * to both the user and user subdatabases.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * name - pointer to name of user to remove
+ *
+ * Returns:
+ *
+ * The return value is zero if the user information is successfully
+ * removed. An error is indicated by a negative return value, and
+ * an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbRemoveUser(NSErr_t * errp, void * authdb, char * name)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ UserObj_t * uoptr = 0; /* user object pointer */
+ GroupObj_t * goptr = 0; /* group object pointer */
+ char * gname; /* group name */
+ USI_t * list; /* pointer into group id list */
+ int gcnt; /* number of groups containing user */
+ int i; /* loop index */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Open the users subdatabase for write access */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Look up the user to be removed, and get a user object */
+ rv = nsadbFindByName(errp, authdb, name, AIF_USER, (void **)&uoptr);
+ if (rv != AIF_USER) {
+ if (rv < 0) goto punt;
+ goto err_nouser;
+ }
+
+ /* Mark the user for delete */
+ uoptr->uo_flags |= UOF_DELPEND;
+
+ /* Does this user belong to any groups? */
+ gcnt = UILCOUNT(&uoptr->uo_groups);
+ if (gcnt > 0) {
+
+ /* Yes, get pointer to list of group ids */
+ list = UILLIST(&uoptr->uo_groups);
+
+ /* Open groups subdatabase for write access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* For each group that the user belongs to ... */
+ for (i = 0; i < gcnt; ++i) {
+
+ /* Get group name associated with the group id */
+ rv = nsadbIdToName(errp, authdb, *list, AIF_GROUP, &gname);
+ if (rv < 0) goto punt;
+
+ /* Look up the group by name and get a group object for it */
+ rv = nsadbFindByName(errp,
+ authdb, gname, AIF_GROUP, (void **)&goptr);
+ if (rv < 0) goto punt;
+
+ /* Remove user from group if it's a direct member */
+ rv = nsadbRemUserFromGroup(errp, authdb, goptr, uoptr);
+ if (rv < 0) goto punt;
+
+ /* Free the group object */
+ groupFree(goptr);
+ goptr = 0;
+
+ ++list;
+ }
+ }
+
+#ifdef CLIENT_AUTH
+ /* Remove certificate mapping for user, if any */
+ rv = nsadbRemoveUserCert(errp, authdb, name);
+#endif
+
+ /* Free the user object */
+ userFree(uoptr);
+
+ /* Now we can remove the user entry */
+ rv = userRemove(errp, adb->adb_userdb, 0, (NTS_t)name);
+
+ return rv;
+
+ err_nouser:
+ eid = NSAUERR4000;
+ rv = NSAERRNAME;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 2, adb->adb_dbname, name);
+ goto punt;
+
+ punt:
+ if (goptr != 0) {
+ groupFree(goptr);
+ }
+ if (uoptr != 0) {
+ userFree(uoptr);
+ }
+ return rv;
+}
+
+/*
+ * Description (nsadbRemGroupFromGroup)
+ *
+ * This function removes a given group C from a parent group P.
+ * The group C must be a direct member of the group P. However,
+ * group C may also be a member of one or more of P's ancestor or
+ * descendant groups, and this function deals with that. The
+ * group entries for C and P are updated in the group database.
+ * But the real work is updating the groups lists of all of the
+ * users contained in C.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * pgoptr - pointer to parent group object
+ * cgoptr - pointer to child group object
+ *
+ * Returns:
+ *
+ * The return value is zero if group C was a direct member of
+ * group P, and was removed successfully. A return value of +1
+ * indicates that group C was not a direct member of the group P.
+ * A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbRemGroupFromGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * pgoptr, GroupObj_t * cgoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t dglist; /* list of descendant groups of C */
+ GroupObj_t * dgoptr; /* descendant group object pointer */
+ UserObj_t * uoptr; /* user object pointer */
+ USI_t * gidlist; /* pointer to group id array */
+ USI_t * userlist; /* pointer to array of descendant user ids */
+ USI_t dgid; /* descendant group id */
+ int iusr; /* index on descendant user list */
+ int usercnt; /* count of descendant users */
+ int igrp; /* index of group in user group id list */
+ int rv; /* result value */
+
+ dgoptr = 0;
+ uoptr = 0;
+
+ /* Initialize a list of descendant groups of C */
+ UILINIT(&dglist);
+
+ /* Is group C a direct member of group P? */
+ if (!usiPresent(&pgoptr->go_groups, cgoptr->go_gid)) {
+
+ /* No, nothing to do */
+ return 1;
+ }
+
+ /* Remove group C from group P's group member list */
+ rv = usiRemove(&pgoptr->go_groups, cgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Remove group P from group C's parent group list */
+ rv = usiRemove(&cgoptr->go_pgroups, pgoptr->go_gid);
+ if (rv < 0) goto punt;
+
+ /* Open user database since the group lists of users may be modified */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Open group database since group entries will be modified */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+
+ /* Write out the updated group C object */
+ cgoptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, cgoptr);
+ if (rv) goto punt;
+
+ /* Write out the updated group P object */
+ pgoptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, pgoptr);
+ if (rv) goto punt;
+
+ /* Now check the group lists of all users contained in group C */
+ dgoptr = cgoptr;
+ dgid = cgoptr->go_gid;
+
+ for (;;) {
+
+ /* Scan the direct user members of this descendant group */
+ usercnt = UILCOUNT(&dgoptr->go_users);
+ userlist = UILLIST(&dgoptr->go_users);
+
+ for (iusr = 0; iusr < usercnt; ++iusr) {
+
+ /* Get a user object for this user member */
+ uoptr = userFindByUid(errp, adb->adb_userdb, userlist[iusr]);
+ if (uoptr == 0) {
+ /* Error - user id not found, databases are inconsistent */
+ rv = -1;
+ goto punt;
+ }
+
+ /* Scan the group list for this user */
+ for (igrp = 0; igrp < UILCOUNT(&uoptr->uo_groups); ) {
+
+ gidlist = UILLIST(&uoptr->uo_groups);
+
+ /* Is the user a member of this group? */
+ if (nsadbIsUserInGroup(errp, authdb,
+ uoptr->uo_uid, gidlist[igrp],
+ igrp, gidlist)) {
+
+ /* Yes, step to next group id */
+ ++igrp;
+ }
+ else {
+ /*
+ * No, remove it from the user's list of groups. The
+ * next group id to consider will be shifted into the
+ * igrp position when the current id is removed.
+ */
+ rv = usiRemove(&uoptr->uo_groups, gidlist[igrp]);
+ if (rv < 0) goto punt;
+ uoptr->uo_flags |= UOF_MODIFIED;
+ }
+ }
+
+ /* Write out the user object if it was changed */
+ if (uoptr->uo_flags & UOF_MODIFIED) {
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+ if (rv < 0) goto punt;
+ }
+
+ /* Free the user object */
+ userFree(uoptr);
+ uoptr = 0;
+ }
+
+ /*
+ * Merge the direct member groups of this group into the
+ * descendants list.
+ */
+ rv = uilMerge(&dglist, &dgoptr->go_groups);
+ if (rv < 0) goto punt;
+
+ /* Free this descendant group object */
+ if (dgoptr != cgoptr) {
+ groupFree(dgoptr);
+ dgoptr = 0;
+ }
+
+ /* If the descendants list is empty, we're done */
+ if (UILCOUNT(&dglist) <= 0) break;
+
+ /* Remove the next group id from the descendants list */
+ gidlist = UILLIST(&dglist);
+ dgid = gidlist[0];
+ rv = usiRemove(&dglist, dgid);
+ if (rv < 0) goto punt;
+
+ /* Get a group object for this descendant group */
+ dgoptr = groupFindByGid(errp, adb->adb_groupdb, dgid);
+ if (dgoptr == 0) {
+ /* Error - group id not found, databases are inconsistent */
+ rv = -1;
+ goto punt;
+ }
+ }
+
+ UILFREE(&dglist);
+ return 0;
+
+ punt:
+ if (dgoptr) {
+ groupFree(dgoptr);
+ }
+ if (uoptr) {
+ userFree(uoptr);
+ }
+ UILFREE(&dglist);
+ return rv;
+}
+
+/*
+ * Description (nsadbRemUserFromGroup)
+ *
+ * This function removes a given user from a specified group G.
+ * The user must be a direct member of the group. However, the
+ * user may also be a member of one or more of G's descendant
+ * groups, and this function deals with that. The group entry
+ * for G is updated in the group database, with the user removed
+ * from its user member list. The user entry is updated in the
+ * user database, with an updated list of all groups which now
+ * contain the user.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to group object
+ * uoptr - pointer to user object
+ *
+ * Returns:
+ *
+ * The return value is zero if the user was a direct member of the
+ * group, and was removed successfully. A return value of +1
+ * indicates that the user was not a direct member of the
+ * group. A negative return value indicates an error.
+ */
+
+NSAPI_PUBLIC int nsadbRemUserFromGroup(NSErr_t * errp, void * authdb,
+ GroupObj_t * goptr, UserObj_t * uoptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USI_t * idlist; /* pointer to user group id array */
+ USI_t tgid; /* test group id */
+ int igrp; /* position in user group list */
+ int rv; /* result value */
+
+ /* Is the user a direct member of the group? */
+ if (!usiPresent(&goptr->go_users, uoptr->uo_uid)) {
+
+ /* No, nothing to do */
+ return 1;
+ }
+
+ /* Remove the user from the group's user member list */
+ rv = usiRemove(&goptr->go_users, uoptr->uo_uid);
+ if (rv < 0) goto punt;
+
+ /* If the user object is pending deletion, no need to open databases */
+ if (!(uoptr->uo_flags & UOF_DELPEND)) {
+
+ /*
+ * Open user database since the group list of the user
+ * will be modified.
+ */
+ rv = nsadbOpenUsers(errp, authdb, ADBF_UWRITE);
+ if (rv < 0) goto punt;
+
+ /* Open group database since group entries will be modified */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GWRITE);
+ if (rv < 0) goto punt;
+ }
+
+ /*
+ * Write out the updated group object. This must be done here
+ * because nsadbIsUserInGroup() in the loop below will read the
+ * entry for this group, and it needs to reflect the user's
+ * removal from being a direct member of the group. This does
+ * not preclude the possibility that the user will still be an
+ * indirect member of this group.
+ */
+ goptr->go_flags |= GOF_MODIFIED;
+ rv = groupStore(errp, adb->adb_groupdb, 0, goptr);
+ if (rv) goto punt;
+
+ /* If a delete is pending on the user, we're done */
+ if (uoptr->uo_flags & UOF_DELPEND) goto punt;
+
+ /*
+ * Begin loop to check whether user is still a member of each
+ * of the groups in its group list. Note that the group list
+ * may shrink during an iteration of the loop.
+ */
+
+ for (igrp = 0; igrp < UILCOUNT(&uoptr->uo_groups); ) {
+
+ /* Get pointer to the user's array of group ids */
+ idlist = UILLIST(&uoptr->uo_groups);
+
+ /* Get the group id of the next group to consider */
+ tgid = idlist[igrp];
+
+ /* Is the user a member of this group? */
+ if (nsadbIsUserInGroup(errp, authdb,
+ uoptr->uo_uid, tgid, igrp, idlist)) {
+
+ /* Yes, step to next group id */
+ ++igrp;
+ }
+ else {
+
+ /*
+ * No, remove it from the user's list of groups. The
+ * next group id to consider will be shifted into the
+ * igrp position when the current id is removed.
+ */
+ rv = usiRemove(&uoptr->uo_groups, tgid);
+ if (rv < 0) goto punt;
+ }
+ }
+
+ /* Write out the updated user object */
+ uoptr->uo_flags |= UOF_MODIFIED;
+ rv = userStore(errp, adb->adb_userdb, 0, uoptr);
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (nsadbSuperGroups)
+ *
+ * This function builds a list of the group ids for all groups
+ * which contain, directly or indirectly, a specified group as
+ * a subgroup. We call these the supergroups of the specified
+ * group.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle for authentication databases
+ * goptr - pointer to group object
+ * gsuper - pointer to list to contain supergroups
+ * (caller must initialize)
+ *
+ * Returns:
+ *
+ * Returns the number of elements in gsuper if successful. An
+ * error is indicated by a negative return value.
+ */
+
+NSAPI_PUBLIC int nsadbSuperGroups(NSErr_t * errp, void * authdb,
+ GroupObj_t * goptr, USIList_t * gsuper)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ USIList_t aglist; /* ancestor group id list */
+ GroupObj_t * aoptr; /* ancestor group object pointer */
+ USI_t * idlist; /* pointer to array of group ids */
+ USI_t id; /* current group id */
+ int rv; /* result value */
+
+ /* Initialize an empty ancestor group list */
+ UILINIT(&aglist);
+
+ /* Enter loop with specified group as first ancestor */
+ id = goptr->go_gid;
+ aoptr = goptr;
+
+ /* Open group database for read access */
+ rv = nsadbOpenGroups(errp, authdb, ADBF_GREAD);
+ if (rv < 0) goto punt;
+
+ /* Loop until the ancestor list is empty */
+ for (;;) {
+
+ /* Merge parent groups of current ancestor into ancestor list */
+ rv = uilMerge(&aglist, &aoptr->go_pgroups);
+ if (rv < 0) goto punt;
+
+ /* Also merge parent groups into the result list */
+ rv = uilMerge(gsuper, &aoptr->go_pgroups);
+ if (rv < 0) goto punt;
+
+ /* Free the ancestor group object (but not the original) */
+ if (aoptr != goptr) {
+ groupFree(aoptr);
+ aoptr = 0;
+ }
+
+ /* Exit the loop if the ancestor list is empty */
+ if (UILCOUNT(&aglist) <= 0) break;
+
+ /* Get pointer to array of ancestor group ids */
+ idlist = UILLIST(&aglist);
+
+ /* Remove the first ancestor */
+ id = idlist[0];
+ rv = usiRemove(&aglist, id);
+
+ /* Get a group object for the ancestor */
+ aoptr = groupFindByGid(errp, adb->adb_groupdb, id);
+ if (aoptr == 0) {
+ /* Error - group not found, database inconsistent */
+ rv = -1;
+ goto punt;
+ }
+ }
+
+ return UILCOUNT(gsuper);
+
+ punt:
+ /* Handle error */
+
+ /* Free ancestor list */
+ UILFREE(&aglist);
+
+ return rv;
+}
+
+NSPR_END_EXTERN_C
+
diff --git a/lib/libaccess/nsautherr.cpp b/lib/libaccess/nsautherr.cpp
new file mode 100644
index 00000000..308c0698
--- /dev/null
+++ b/lib/libaccess/nsautherr.cpp
@@ -0,0 +1,126 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsautherr.c)
+ *
+ * This module provides facilities for handling authentication
+ * errors.
+ */
+
+#include <string.h>
+#include "base/systems.h"
+#include "prprf.h"
+#include "libaccess/nserror.h"
+#include "libaccess/nsautherr.h"
+
+/* Error message formats XXX internationalize XXX */
+static char * nsaerrnomem = "insufficient dynamic memory";
+static char * nsaerrinval = "invalid argument";
+static char * nsaerropen = "error opening %s";
+static char * nsaerrmkdir = "error creating %s";
+static char * nsaerrname = "%s not found in database %s";
+static char * unknownerr = "error code %d";
+
+/*
+ * Description (nsadbErrorFmt)
+ *
+ * This function formats an authentication error message into a
+ * buffer provided by the caller. The authentication error
+ * information is passed in an error list structure. The caller
+ * can indicate how many error frames should be processed. A
+ * newline is inserted between messages for different error frames.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer
+ * msgbuf - pointer to error message buffer
+ * maxlen - maximum length of generated message
+ * maxdepth - maximum depth for traceback
+ */
+
+NSAPI_PUBLIC void nsadbErrorFmt(NSErr_t * errp, char * msgbuf, int maxlen, int maxdepth)
+{
+ NSEFrame_t * efp; /* error frame pointer */
+ int len; /* length of error message text */
+ int depth = 0; /* current depth */
+
+ msgbuf[0] = 0;
+
+ for (efp = errp->err_first; efp != 0; efp = efp->ef_next) {
+
+ /* Stop if the message buffer is full */
+ if (maxlen <= 0) break;
+
+ if (depth > 0) {
+ /* Put a newline between error frame messages */
+ *msgbuf++ = '\n';
+ if (--maxlen <= 0) break;
+ }
+
+ /* Identify the facility generating the error and the id number */
+ len = PR_snprintf(msgbuf, maxlen,
+ "[%s%d] ", efp->ef_program, efp->ef_errorid);
+ msgbuf += len;
+ maxlen -= len;
+
+ if (maxlen <= 0) break;
+
+ len = 0;
+
+ if (!strcmp(efp->ef_program, NSAuth_Program)) {
+
+ switch (efp->ef_retcode) {
+ case NSAERRNOMEM:
+ strncpy(msgbuf, nsaerrnomem, maxlen);
+ len = strlen(nsaerrnomem);
+ break;
+
+ case NSAERRINVAL:
+ /* Invalid function argument error: */
+ strncpy(msgbuf, nsaerrinval, maxlen);
+ len = strlen(nsaerrinval);
+ break;
+
+ case NSAERROPEN:
+ /* File open error: filename */
+ if (efp->ef_errc == 1) {
+ len = PR_snprintf(msgbuf, maxlen, nsaerropen,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ case NSAERRMKDIR:
+ /* error creating database directory: database name */
+ if (efp->ef_errc == 1) {
+ len = PR_snprintf(msgbuf, maxlen, nsaerrmkdir,
+ efp->ef_errv[0]);
+ }
+ break;
+
+ case NSAERRNAME:
+ /* user or group name not found: database, name */
+ if (efp->ef_errc == 2) {
+ len = PR_snprintf(msgbuf, maxlen, nsaerrname,
+ efp->ef_errv[0], efp->ef_errv[1]);
+ }
+ break;
+
+ default:
+ len = PR_snprintf(msgbuf, maxlen, unknownerr, efp->ef_retcode);
+ break;
+ }
+ }
+ else {
+ len = PR_snprintf(msgbuf, maxlen, unknownerr, efp->ef_retcode);
+ }
+
+ msgbuf += len;
+ maxlen -= len;
+
+ if (++depth >= maxdepth) break;
+ }
+}
diff --git a/lib/libaccess/nscert.cpp b/lib/libaccess/nscert.cpp
new file mode 100644
index 00000000..97939b24
--- /dev/null
+++ b/lib/libaccess/nscert.cpp
@@ -0,0 +1,963 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * Description (nsadb.c)
+ *
+ * This module contains routines for accessing and storing information
+ * in a Netscape client certificate to username database. This
+ * database is used to associate a username with a client certificate
+ * that is presented to a server.
+ */
+
+#if defined(CLIENT_AUTH)
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#include <base/fsmutex.h>
+#include <libaccess/nsdbmgmt.h>
+#define __PRIVATE_NSADB
+#include <libaccess/nsadb.h>
+#include <libaccess/nsamgmt.h>
+
+static FSMUTEX nscert_lock = 0;
+
+NSAPI_PUBLIC int nsadbCertInitialize(void)
+{
+#ifdef XP_UNIX
+ nscert_lock = fsmutex_init("NSCERTMAP", geteuid(),
+ FSMUTEX_VISIBLE|FSMUTEX_NEEDCRIT);
+#else /* XP_WIN32 */
+ char winuser[128];
+ DWORD wulength;
+ strcpy(winuser, "NSCERTMAP_");
+ wulength = 128 - 11;
+ GetUserName(winuser+10, &wulength);
+ nscert_lock = fsmutex_init(winuser, 0,
+ FSMUTEX_VISIBLE|FSMUTEX_NEEDCRIT);
+#endif
+ return (nscert_lock == 0) ? -1 : 0;
+}
+
+NSAPI_PUBLIC int nsadbDecodeCertRec(int reclen, char * recptr,
+ CertObj_t * coptr)
+{
+ ATR_t cp = (ATR_t)recptr; /* current pointer into record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+
+ /* Parse user DB record */
+ while ((cp - (ATR_t)recptr) < reclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case CAT_USERNAME: /* username associated with cert */
+ cp = NTSDECODE(cp, (NTS_t *)&coptr->co_username);
+ break;
+
+ case CAT_CERTID: /* certificate-to-user map id */
+ cp = USIDECODE(cp, &coptr->co_certid);
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Description (nsadbDecodeCertKey)
+ *
+ * This function decodes information from a certificate key.
+ * Currently a certificate key includes the DER encoding of the
+ * issuer and subject distinguished names. This is used to
+ * uniquely identify client certificates, even across certificate
+ * renewals. SECItems for the issuer and subject are provided
+ * by the caller. These are updated with the pointers and lengths
+ * of DER encodings, which can be decoded using nsadbDecodeCertName()
+ * into SECName structures. The returned SECItems refer to data
+ * in the provided key buffer.
+ *
+ * Arguments:
+ *
+ * keylen - length of the certificate key encoding
+ * keyptr - buffer containing certificate key encoding
+ * issuer - pointer to SECItem for returning issuer
+ * subject - pointer to SECItem for returning subject
+ *
+ * Returns:
+ *
+ * Zero is returned if no errors are encountered. Otherwise -1.
+ */
+
+NSAPI_PUBLIC int nsadbDecodeCertKey(int keylen, char * keyptr,
+ SECItem * issuer, SECItem * subject)
+{
+ ATR_t cp = (ATR_t)keyptr; /* current pointer into DB record */
+ USI_t len; /* attribute value encoding length */
+ USI_t tag; /* attribute tag */
+
+ /* Parse user DB record */
+ while ((cp - (ATR_t)keyptr) < keylen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case KAT_ISSUER: /* issuer DER encoding */
+ issuer->len = len;
+ issuer->data = cp;
+ cp += len;
+ break;
+
+ case KAT_SUBJECT: /* subject name DER encoding */
+ subject->len = len;
+ subject->data = cp;
+ cp += len;
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Description (nsadbEncodeCertKey)
+ *
+ * This function encodes information provided by the caller into
+ * a certificate key. The certificate key is returned in a
+ * buffer obtained from MALLOC().
+ *
+ * Arguments:
+ *
+ * issuer - pointer to SECItem for issuer DER
+ * subject - pointer to SECItem for subject DER
+ * keylen - returned length of certificate key
+ * keyptr - returned pointer to buffer containing
+ * certificate key encoding
+ *
+ * Returns:
+ *
+ * Zero is returned if no errors are encountered. Otherwise -1.
+ */
+
+NSAPI_PUBLIC int nsadbEncodeCertKey(SECItem * issuer, SECItem * subject,
+ int * keylen, char **keyptr)
+{
+ ATR_t cp; /* pointer into key buffer */
+ ATR_t kptr; /* pointer to key buffer */
+ int klen; /* length of key */
+ int rv = -1;
+
+ /* Compute length of key encoding */
+ klen = 1 + USILENGTH(issuer->len) + issuer->len +
+ 1 + USILENGTH(subject->len) + subject->len;
+
+ /* Allocate buffer to contain the key */
+ kptr = (ATR_t)MALLOC(klen);
+ if (kptr) {
+ /* Encode issuer and subject as attributes */
+ cp = kptr;
+ *cp++ = KAT_ISSUER;
+ cp = USIENCODE(cp, issuer->len);
+ memcpy(cp, issuer->data, issuer->len);
+ cp += issuer->len;
+ *cp++ = KAT_SUBJECT;
+ cp = USIENCODE(cp, subject->len);
+ memcpy(cp, subject->data, subject->len);
+ rv = 0;
+ }
+
+ /* Return length and buffer pointer */
+ if (keylen) *keylen = klen;
+ *keyptr = (char *)kptr;
+
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumCertsHelp)
+ *
+ * This is a local function that is called by NSDB during certificate
+ * to user database enumeration. It decodes certificate records into
+ * CertObj_t structures, and presents them to the caller of
+ * nsadbEnumerateCerts(), via the specified call-back function.
+ * The call-back function return value may be a negative error code,
+ * which will cause enumeration to stop, and the error code will be
+ * returned from nsadbEnumerateCerts(). If the return value of the
+ * call-back function is not negative, it can contain one or more of
+ * the following flags:
+ *
+ * ADBF_KEEPOBJ - do not free the CertObj_t structure
+ * that was passed to the call-back function
+ * ADBF_STOPENUM - stop the enumeration without an error
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to CertEnumArgs_t structure
+ * keylen - certificate record key length
+ * keyptr - certificate record key
+ * reclen - length of certificate record
+ * recptr - pointer to certificate record contents
+ *
+ * Returns:
+ *
+ * If the call-back returns a negative result, that value is
+ * returned. If the call-back returns ADBF_STOPENUM, then
+ * -1 is returned, causing the enumeration to stop. Otherwise
+ * the return value is zero.
+ */
+
+typedef struct CertEnumArgs_s CertEnumArgs_t;
+struct CertEnumArgs_s {
+ int rv; /* just a return value */
+ void * client; /* the current key for lookup */
+ void * authdb; /* the authentication data base */
+ CertEnumCallback func; /* client's callback function */
+};
+
+static int nsadbEnumCertsHelp(NSErr_t * errp, void * parg,
+ int keylen, char * keyptr,
+ int reclen, char * recptr)
+{
+ CertEnumArgs_t * ce = (CertEnumArgs_t *)parg;
+ CertObj_t * coptr;
+ int rv = NSAERRNOMEM;
+
+ /* Allocate a CertObj_t structure and initialize it */
+ coptr = (CertObj_t *)MALLOC(sizeof(CertObj_t));
+ if (coptr) {
+
+ coptr->co_issuer.data = 0;
+ coptr->co_subject.data = 0;
+ coptr->co_username = 0;
+ coptr->co_certid = 0;
+
+ /* Decode the certificate key */
+ rv = nsadbDecodeCertKey(keylen, keyptr,
+ &coptr->co_issuer, &coptr->co_subject);
+
+ /* Decode the certificate record */
+ rv = nsadbDecodeCertRec(reclen, recptr, coptr);
+
+ /* Pass the CertObj_t to the callback function */
+ rv = (*ce->func)(errp, ce->authdb, ce->client, coptr);
+ if (rv >= 0) {
+
+ /* Count the number of records seen */
+ ce->rv += 1;
+
+ /* Free the user object unless the call-back says not to */
+ if (!(rv & ADBF_KEEPOBJ)) {
+ nsadbFreeCertObj(coptr);
+ }
+ /* Return either 0 or -1, depending on ADBF_STOPENUM */
+ rv = (rv & ADBF_STOPENUM) ? -1 : 0;
+ }
+ else {
+ /* return the error code */
+ ce->rv = rv;
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * Description (nsadbEnumerateClients)
+ *
+ * (See description for nsadbEnumerateUsers)
+ */
+
+NSAPI_PUBLIC int nsadbEnumerateCerts(NSErr_t * errp, void * authdb,
+ void * argp, CertEnumCallback func)
+{
+ AuthDB_t * adb = (AuthDB_t*)authdb;
+ CertEnumArgs_t helper_data;
+ int rv;
+
+ /* Open the certificate subdatabase for read access */
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CREAD);
+ if (rv >= 0) {
+ helper_data.authdb = authdb;
+ helper_data.func = func;
+ helper_data.client = argp;
+ helper_data.rv = 0;
+
+ rv = ndbEnumerate(errp, adb->adb_certdb, NDBF_ENUMNORM,
+ (void*)&helper_data, nsadbEnumCertsHelp);
+ }
+
+ return (rv < 0) ? rv: helper_data.rv;
+}
+
+NSAPI_PUBLIC void nsadbFreeCertObj(CertObj_t * coptr)
+{
+ if (coptr) {
+ FREE(coptr->co_username);
+ FREE(coptr);
+ }
+}
+
+NSAPI_PUBLIC int nsadbGetCertById(NSErr_t * errp, void * authdb,
+ USI_t certid, CertObj_t **coptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ CertObj_t * cop = 0;
+ char * keyptr;
+ char * recptr;
+ int keylen;
+ int reclen;
+ int rv;
+
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CREAD);
+ if (rv < 0) goto punt;
+
+ /* Get the name corresponding to the id */
+ rv = ndbIdToName(errp, adb->adb_certdb, certid, &keylen, &keyptr);
+ if (rv < 0) goto punt;
+
+ rv = ndbFindName(errp, adb->adb_certdb,
+ keylen, keyptr, &reclen, &recptr);
+ if (rv < 0) goto punt;
+
+ /* Allocate a CertObj_t structure and initialize it */
+ cop = (CertObj_t *)MALLOC(sizeof(CertObj_t));
+ if (cop) {
+
+ cop->co_issuer.data = 0;
+ cop->co_subject.data = 0;
+ cop->co_username = 0;
+ cop->co_certid = 0;
+
+ /* Decode the certificate key */
+ rv = nsadbDecodeCertKey(keylen, keyptr,
+ &cop->co_issuer, &cop->co_subject);
+
+ /* Decode the certificate record */
+ rv = nsadbDecodeCertRec(reclen, recptr, cop);
+
+ }
+
+ punt:
+ if (coptr) *coptr = cop;
+ return rv;
+}
+
+/*
+ * Description (nsadbGetUserByCert)
+ *
+ * This function looks up a specified client certificate in the
+ * authentication database. It returns a pointer to the username
+ * associated with the client certificate, if any. The username
+ * buffer remains valid until the authentication database is
+ * closed.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * cert - pointer to client certificate
+ * username - pointer to returned user name (or null)
+ *
+ * Returns:
+ *
+ * The return value will be zero if the certificate is found. Also,
+ * *username will be set to the string value of the associated username
+ * iff username is not null.
+ */
+
+NSAPI_PUBLIC int nsadbGetUserByCert(NSErr_t * errp, void * authdb,
+ CERTCertificate * cert, char **username)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ ATR_t cp; /* current pointer into DB record */
+ char * user = 0; /* pointer to username */
+ char * keyptr = 0; /* pointer to cert key */
+ char * recptr; /* pointer to cert db record */
+ int keylen; /* length of cert key */
+ int reclen; /* length of cert db record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+ int rv;
+
+ /* Construct the record key from the certificate */
+ rv = nsadbEncodeCertKey(&cert->derIssuer, &cert->derSubject,
+ &keylen, &keyptr);
+
+ if (adb->adb_certdb == NULL) {
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CREAD);
+ if (rv < 0) goto punt;
+ }
+
+ rv = ndbFindName(errp, adb->adb_certdb,
+ keylen, keyptr, &reclen, &recptr);
+ if (rv < 0) goto punt;
+
+ /* Parse cert DB record */
+ cp = (ATR_t)recptr;
+
+ while ((cp - (ATR_t)recptr) < reclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* We want the CAT_USERNAME attribute */
+ if (tag == CAT_USERNAME) {
+
+ /* Get the username associated with the cert */
+ user = (char *)cp;
+ break;
+ }
+
+ /* Just skip other attributes */
+ cp += len;
+ }
+
+ punt:
+ if (keyptr) {
+ FREE(keyptr);
+ }
+ if (username) *username = user;
+ return rv;
+}
+
+/*
+ * Description (see description for nsadbOpenUsers)
+ */
+
+int nsadbOpenCerts(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t *adb = (AuthDB_t*)authdb;
+ char *dbname = NULL; /* user database name */
+ int dblen; /* strlen(adb_dbname) */
+ int version; /* database version */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ if (adb == NULL) goto err_inval;
+
+ /* Is the user database already open? */
+ if (adb->adb_certdb != 0) {
+
+ /* Yes, is it open for the desired access? */
+ if (adb->adb_flags & flags) {
+
+ /* Yes, that was easy */
+ return 0;
+ }
+ }
+ else {
+ /* Allocate space for the user database filename */
+ dblen = strlen(adb->adb_dbname);
+
+ dbname = (char *)MALLOC(dblen + strlen(ADBCERTDBNAME) + 2);
+ if (dbname == 0) goto err_nomem;
+
+ /* Construct user database name */
+ strcpy(dbname, adb->adb_dbname);
+
+ /* Put in a '/' (or '\') if it's not there */
+ if (dbname[dblen-1] != FILE_PATHSEP) {
+ dbname[dblen] = FILE_PATHSEP;
+ dbname[dblen+1] = 0;
+ ++dblen;
+ }
+
+ strcpy(&dbname[dblen], ADBCERTDBNAME);
+
+ if (nscert_lock == 0) {
+ rv = nsadbCertInitialize();
+ if (rv < 0) goto err_lock;
+ }
+ adb->adb_certlock = nscert_lock;
+ if (adb->adb_certlock == 0) goto punt;
+
+ fsmutex_lock((FSMUTEX)(adb->adb_certlock));
+
+ adb->adb_certdb = ndbOpen(errp,
+ dbname, 0, NDB_TYPE_CLIENTDB, &version);
+ if (adb->adb_certdb == 0) {
+ fsmutex_unlock((FSMUTEX)(adb->adb_certlock));
+ goto err_open;
+ }
+ }
+
+ /*
+ * We don't really reopen the database to get the desired
+ * access mode, since that is handled at the nsdb level.
+ * But we do update the flags, just for the record.
+ */
+ adb->adb_flags &= ~(ADBF_CREAD|ADBF_CWRITE);
+ if (flags & ADBF_CWRITE) adb->adb_flags |= ADBF_CWRITE;
+ else adb->adb_flags |= ADBF_CREAD;
+ rv = 0;
+
+ punt:
+ if (dbname != NULL) FREE(dbname);
+ return rv;
+
+ err_inval:
+ eid = NSAUERR3400;
+ rv = NSAERRINVAL;
+ goto err_ret;
+
+ err_nomem:
+ eid = NSAUERR3420;
+ rv = NSAERRNOMEM;
+ goto err_ret;
+
+ err_lock:
+ eid = NSAUERR3430;
+ rv = NSAERRLOCK;
+ goto err_ret;
+
+ err_open:
+ eid = NSAUERR3440;
+ rv = NSAERROPEN;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, dbname);
+ goto punt;
+
+}
+
+NSAPI_PUBLIC void nsadbCloseCerts(void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+
+ if (adb->adb_certnm != 0) {
+ /* Close the username-to-certid database */
+ nsadbCloseCertUsers(authdb, flags);
+ }
+
+ if (adb->adb_certdb != 0) {
+
+ ndbClose(adb->adb_certdb, 0);
+ adb->adb_certdb = 0;
+
+ /*
+ * A lock is held for the certificate map DB as long as it is
+ * open, so release the lock now.
+ */
+ fsmutex_unlock((FSMUTEX)(adb->adb_certlock));
+ }
+}
+
+/*
+ * Description (nsadbOpenCertUsers)
+ *
+ * This function opens a database that maps user names to client
+ * certificates. The database appears as "Certs.nm" in the
+ * authentication database directory. This function requires
+ * that the primary certificate database be opened (Certs.db)
+ * first, and will open it if necessary, acquiring a global
+ * lock in the process. The lock will not be released until
+ * nsadbCloseCerts() or nsadbClose() is called.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * flags - same as nsadbOpenCerts()
+ *
+ * Returns:
+ *
+ * The return value is zero if the operation is successful.
+ * Otherwise a negative error code is returned.
+ */
+
+NSAPI_PUBLIC int nsadbOpenCertUsers(NSErr_t * errp, void * authdb, int flags)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * dbname = 0;
+ int dblen;
+ int oflags = O_RDONLY; /* assume read-only access */
+ int eid;
+ int rv;
+
+ /* The primary certificate mapping database must be open first */
+ if (adb->adb_certdb != 0) {
+
+ /* It's open, but is it read-only when we need write? */
+ if (((flags & adb->adb_flags) == 0) && (flags & ADBF_CWRITE)) {
+
+ /* Yes, close it */
+ nsadbCloseCerts(authdb, 0);
+ }
+ }
+
+ /* Open it for the desired access if necessary */
+ if (adb->adb_certdb == 0) {
+ /*
+ * Open it for the desired access. Note that this acquires
+ * a global lock which is not released until nsadbClose() is
+ * called for the entire authentication database.
+ */
+ rv = nsadbOpenCerts(errp, authdb, flags);
+ if (rv < 0) {
+ /* Go no further if that failed */
+ return rv;
+ }
+ }
+
+ /* Now look at the username-to-certid database in particular */
+ if (adb->adb_certnm && (adb->adb_flags & flags)) {
+
+ /* The database is already open for the desired access */
+ return 0;
+ }
+
+ dblen = strlen(adb->adb_dbname);
+ dbname = (char *)MALLOC(dblen + strlen(ADBUMAPDBNAME) + 2);
+ strcpy(dbname, adb->adb_dbname);
+ if (dbname[dblen-1] != FILE_PATHSEP) {
+ dbname[dblen] = FILE_PATHSEP;
+ dbname[++dblen] = 0;
+ }
+ strcpy(&dbname[dblen], ADBUMAPDBNAME);
+
+ /* Check for write access and set open flags appropriately if so */
+ if (flags & ADBF_CWRITE) {
+ oflags = O_CREAT|O_RDWR;
+ }
+
+ /* Open the username-to-certid database */
+// adb->adb_certnm = dbopen(dbname, oflags, 0644, DB_HASH, 0);
+ adb->adb_certnm = 0;
+ if (adb->adb_certnm == 0) goto err_open;
+
+ punt:
+ FREE(dbname);
+
+ return rv;
+
+ err_open:
+ eid = NSAUERR3600;
+ rv = NSAERROPEN;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, dbname);
+ goto punt;
+}
+
+/*
+ * Description (nsadbFindCertUser)
+ *
+ * This function checks to see whether a client certificate is
+ * registered for a specified user name. If so, it returns the
+ * certificate mapping id (for use with nsadbGetCertById()).
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * username - pointer to user name string
+ * id - pointer to returned certificate mapping id
+ *
+ * Returns:
+ *
+ * If a certificate is registered for the specified user, the return
+ * value is zero and the certificate mapping id is returned via 'id'.
+ * Otherwise the return value is a negative error code (nsautherr.h)
+ * and an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbFindCertUser(NSErr_t * errp, void * authdb,
+ const char * username, USI_t * id)
+{
+ int eid;
+ int rv;
+ eid = NSAUERR3700;
+ rv = NSAERRNAME;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ return rv;
+}
+
+/*
+ * Description (nsadbAddCertUser)
+ *
+ * This function adds an entry to the username-to-cert id database,
+ * with a given username and certificate mapping id.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * username - pointer to user name string
+ * id - certificate mapping id
+ *
+ * Returns:
+ *
+ * If the entry is added successfully, the return value is zero.
+ * Otherwise the return value is a negative error code (nsautherr.h)
+ * and an error frame is generated if an error frame list is provided.
+ */
+
+NSAPI_PUBLIC int nsadbAddCertUser(NSErr_t * errp, void * authdb,
+ const char * username, USI_t id)
+{
+ /* Need to be ported on NSS 3.2 */
+ int eid;
+ int rv;
+
+ eid = NSAUERR3800;
+ rv = NSAERRPUT;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ return rv;
+}
+
+NSAPI_PUBLIC int nsadbRemoveCertUser(NSErr_t * errp, void * authdb,
+ char * username)
+{
+ /* Need to be ported on NSS 3.2 */
+ int eid;
+ int rv;
+
+ eid = NSAUERR3800;
+ rv = NSAERRPUT;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ return rv;
+}
+
+NSAPI_PUBLIC void nsadbCloseCertUsers(void * authdb, int flags)
+{
+ /* Need to be ported on NSS 3.2 */
+}
+
+/*
+ * Description (nsadbPutUserByCert)
+ *
+ * This function looks up a stores a client certificate mapping
+ * in the authentication database along with the associated username.
+ * It assumes that a record with the specified certificate key does
+ * not already exist, and will replace it if it does.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * authdb - handle returned by nsadbOpen()
+ * certLen - length of the certificate key
+ * cert - certificate key pointer
+ * user - username to be associated with the
+ * certificate
+ *
+ * Returns:
+ *
+ */
+
+NSAPI_PUBLIC int nsadbPutUserByCert(NSErr_t * errp, void * authdb,
+ CERTCertificate * cert,
+ const char * username)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ ATR_t cp; /* pointer into cert record contents */
+ char * keyptr = 0; /* pointer to cert record key */
+ char * recptr = 0; /* pointer to cert record contents */
+ int keylen; /* length of cert record key */
+ int reclen; /* length of cert record contents */
+ USI_t certid;
+ int usrlen;
+ int certidlen;
+ int eid;
+ int rv;
+
+ /* Construct the record key from the certificate */
+ rv = nsadbEncodeCertKey(&cert->derIssuer, &cert->derSubject,
+ &keylen, &keyptr);
+
+ /* Open the username-to-cert id database for write */
+ rv = nsadbOpenCertUsers(errp, authdb, ADBF_CWRITE);
+ if (rv) goto punt;
+
+ /* If the username is already mapped to a cert, it's an error */
+ certid = 0;
+ rv = nsadbFindCertUser(errp, authdb, username, &certid);
+ if (rv == 0) goto err_map;
+
+ /*
+ * Allocate a certificate id and write a record mapping this id
+ * to the specified certificate key.
+ */
+ certid = 0;
+ rv = ndbAllocId(errp, adb->adb_certdb, keylen, keyptr, &certid);
+ if (rv) goto punt;
+
+ /* Record the username as being mapped to the allocated cert id */
+ rv = nsadbAddCertUser(errp, authdb, username, certid);
+ if (rv < 0) goto punt;
+
+ nsadbCloseCertUsers(authdb, 0);
+
+ /*
+ * First we need to figure out how long the generated record will be.
+ * This doesn't have to be exact, but it must not be smaller than the
+ * actual record size.
+ */
+
+ /* CAT_USERNAME attribute: tag, length, NTS */
+ usrlen = NTSLENGTH(username);
+ if (usrlen > 127) goto err_user;
+ reclen = 2 + usrlen;
+
+ /* CAT_CERTID attribute: tag, length, USI */
+ certidlen = USILENGTH(certid);
+ reclen += 2 + certidlen;
+
+ /* Allocate the attribute record buffer */
+ recptr = (char *)MALLOC(reclen);
+ if (recptr) {
+
+ cp = (ATR_t)recptr;
+
+ /* Encode CAT_USERNAME attribute */
+ *cp++ = CAT_USERNAME;
+ *cp++ = usrlen;
+ cp = NTSENCODE(cp, (NTS_t)username);
+
+ /* Encode CAT_CERTID attribute */
+ *cp++ = CAT_CERTID;
+ *cp++ = certidlen;
+ cp = USIENCODE(cp, certid);
+ }
+
+ /* Store the record in the database under the certificate key */
+ rv = ndbStoreName(errp, adb->adb_certdb,
+ 0, keylen, keyptr, reclen, recptr);
+
+ punt:
+ if (keyptr) {
+ FREE(keyptr);
+ }
+ if (recptr) {
+ FREE(recptr);
+ }
+
+ return rv;
+
+ err_user:
+ eid = NSAUERR3500;
+ rv = NSAERRINVAL;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, adb->adb_dbname);
+ goto punt;
+
+ err_map:
+ eid = NSAUERR3520;
+ rv = NSAERRCMAP;
+ nsadbCloseCertUsers(authdb, 0);
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 1, adb->adb_dbname);
+ goto punt;
+}
+
+NSAPI_PUBLIC int nsadbRemoveCert(NSErr_t * errp, void * authdb,
+ void * username, CertObj_t * coptr)
+{
+ AuthDB_t * adb = (AuthDB_t *)authdb;
+ char * keyptr = 0; /* pointer to cert record key */
+ int keylen; /* length of cert record key */
+ int rv;
+ int rv2;
+
+ /* If a username is specified, require it to match */
+ if (username && strcmp((char *)username, coptr->co_username)) {
+ return 0;
+ }
+
+ /* Construct the record key from the certificate */
+ rv = nsadbEncodeCertKey(&coptr->co_issuer, &coptr->co_subject,
+ &keylen, &keyptr);
+
+ if (adb->adb_certdb == NULL) {
+ rv = nsadbOpenCerts(errp, authdb, ADBF_CWRITE);
+ if (rv < 0) goto punt;
+ }
+
+ /* Remove the username-to-cert id entry from Certs.nm */
+ rv = nsadbOpenCertUsers(errp, authdb, ADBF_CWRITE);
+ if (rv < 0) goto punt;
+ rv = nsadbRemoveCertUser(errp, authdb, coptr->co_username);
+ nsadbCloseCertUsers(authdb, 0);
+
+ /* Free the cert id value, if any */
+ rv = 0;
+ if (coptr->co_certid != 0) {
+ rv = ndbFreeId(errp, adb->adb_certdb,
+ keylen, keyptr, coptr->co_certid);
+ }
+
+ /* Delete the cert record */
+ rv2 = ndbDeleteName(errp, adb->adb_certdb, 0, keylen, keyptr);
+
+ punt:
+ if (keyptr) {
+ FREE(keyptr);
+ }
+ return (rv) ? rv : rv2;
+}
+
+NSAPI_PUBLIC int nsadbRemoveUserCert(NSErr_t * errp,
+ void * authdb, char * username)
+{
+ CertObj_t * coptr = 0;
+ USI_t certid = 0;
+ int rv;
+
+ /*
+ * Open for read access at first. We don't want to create the
+ * database if it's not already there. This will do nothing
+ * if the database is already open for write, since that implies
+ * read access as well.
+ */
+ rv = nsadbOpenCertUsers(errp, authdb, ADBF_CREAD);
+ if (rv < 0) goto punt;
+
+ /* Find a certificate mapping id for the given username */
+ rv = nsadbFindCertUser(errp, authdb, username, &certid);
+ if (rv < 0) goto punt;
+
+ /* Look up the mapping from the mapping id */
+ rv = nsadbGetCertById(errp, authdb, certid, &coptr);
+ if (rv < 0) goto punt;
+
+ /* It's there, so remove it. This will re-open for write if needed. */
+ rv = nsadbRemoveCert(errp, authdb, (void *)username, coptr);
+
+ punt:
+
+ if (coptr != 0) {
+ nsadbFreeCertObj(coptr);
+ }
+
+ return rv;
+}
+
+#endif /* defined(CLIENT_AUTH) */
diff --git a/lib/libaccess/nsdb.cpp b/lib/libaccess/nsdb.cpp
new file mode 100644
index 00000000..0479b8f3
--- /dev/null
+++ b/lib/libaccess/nsdb.cpp
@@ -0,0 +1,836 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsdb.c)
+ *
+ * This provides access to a Netscape server database.
+ * A server database is composed of two (libdbm) DB files. One
+ * of these (<dbname>.db) contains records indexed by a string
+ * key. These records contain the primary information in the
+ * database. A second DB file (<dbname>.id) is used to map an
+ * integer id value to a string key, which can then be used to
+ * locate a record in the first file.
+ *
+ * Normally the records in the primary DB file will contain the
+ * id values which are used to key the id-to-name DB. When this
+ * is the case, it is possible to construct the id-to-name DB from
+ * the primary DB file, and an interface is provided to facilitate
+ * this.
+ */
+
+#include <stdio.h>
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#define __PRIVATE_NSDB
+#include <libaccess/nsdb.h>
+
+#include <errno.h>
+
+#define NDBMODE 0644 /* mode for creating files */
+
+char * NSDB_Program = "NSDB"; /* NSDB facility name */
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * Description (ndbClose)
+ *
+ * This function closes the specified database. This involves
+ * closing the primary and id-to-name DB files, and freeing the
+ * NSDB_t object.
+ *
+ * Arguments:
+ *
+ * ndb - database handle from ndbOpen()
+ * flags - (currently unused - should be zero)
+ *
+ */
+
+void ndbClose(void * ndb, int flags)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+
+ if (ndbp->ndb_flags & (NDBF_WRNAME|NDBF_RDNAME)) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ }
+
+ if (ndbp->ndb_flags & (NDBF_WRID|NDBF_RDID)) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ }
+
+ if (ndbp->ndb_pname) {
+ FREE(ndbp->ndb_pname);
+ }
+
+ if (ndbp->ndb_iname) {
+ FREE(ndbp->ndb_iname);
+ }
+
+ FREE(ndbp);
+}
+
+/*
+ * Description (ndbEnumerate)
+ *
+ * This function is called to enumerate the records of the primary
+ * DB file to a caller-specified function. The function specified
+ * by the caller is called with the name (key), length and address
+ * of each record in the primary DB file. The 'flags' argument can
+ * be used to select normal data records, metadata records, or both.
+ * If the 'flags' value is zero, only normal data records are
+ * enumerated. The function specified by the caller returns -1 to
+ * terminate the enumeration, 0 to continue it, or +1 to restart
+ * the enumeration from the beginning.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - bit flags:
+ * NDBF_ENUMNORM - normal data records
+ * NDBF_ENUMMETA - metadata records
+ * func - pointer to caller's enumeration function
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if an
+ * error frame list was provided by the caller.
+ */
+
+int ndbEnumerate(NSErr_t * errp, void * ndb, int flags, void * argp,
+#ifdef UnixWare
+ ArgFn_ndbEnum func) /* for ANSI C++ standard, see nsdb.h */
+#else
+ int (*func)(NSErr_t * ferrp, void * parg,
+ int namelen, char * name,
+ int reclen, char * recptr))
+#endif
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ int rv;
+ int dbflag;
+
+ /* Is the user DB open for reading names? */
+ if (!(ndbp->ndb_flags & NDBF_RDNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_RDNAME);
+ if (rv) goto punt;
+ }
+
+ if (flags == 0) flags = NDBF_ENUMNORM;
+
+ for (dbflag = R_FIRST; ; dbflag = (rv > 0) ? R_FIRST : R_NEXT) {
+
+ /* Retrieve the next (first) record from the primary DB */
+ rv = (*ndbp->ndb_pdb->seq)(ndbp->ndb_pdb, &key, &rec, dbflag);
+ if (rv) break;
+
+ /* Is this a metadata record? */
+ if (*(char *)key.data == NDB_MDPREFIX) {
+
+ /* Yes, skip it if metadata was not requested */
+ if (!(flags & NDBF_ENUMMETA)) continue;
+ }
+ else {
+ /* Skip normal data if not requested */
+ if (!(flags & NDBF_ENUMNORM)) continue;
+ }
+
+ /* Pass this record to the caller's function */
+ rv = (*func)(errp, argp,
+ key.size, (char *)key.data, rec.size, (char *)rec.data);
+ if (rv < 0) break;
+ }
+
+ /* Indicate success */
+ rv = 0;
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (ndbFindName)
+ *
+ * This function retrieves from the database a record with the
+ * specified key.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * namelen - length of the key, including null
+ * terminator if any
+ * name - pointer to the key of the desired record
+ * reclen - pointer to returned record length
+ * recptr - pointer to returned record pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero, and the length and
+ * address of the returned record are returned through reclen and
+ * recptr. Otherwise the return value is non-zero, and an error
+ * frame is generated if an error frame list was provided by the
+ * caller.
+ *
+ * Notes:
+ *
+ * The record buffer is dynamically allocated and is freed
+ * automatically when the database is closed.
+ */
+
+int ndbFindName(NSErr_t * errp, void * ndb, int namelen, char * name,
+ int * reclen, char **recptr)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Is the user DB open for reading names? */
+ if (!(ndbp->ndb_flags & NDBF_RDNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_RDNAME);
+ if (rv) goto punt;
+ }
+
+ /* Set up record key. Include the terminating null byte. */
+ key.data = (void *)name;
+ key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
+
+ /* Initialize record buffer descriptor */
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_pget;
+
+ /* Return record length and address */
+ if (reclen) *reclen = rec.size;
+ if (recptr) *recptr = (char *)rec.data;
+
+ /* Indicate success */
+ rv = 0;
+
+ punt:
+ return rv;
+
+ err_pget:
+ eid = NSDBERR1000;
+ rv = NDBERRGET;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, name);
+ goto punt;
+}
+
+/*
+ * Description (ndbIdToName)
+ *
+ * This function looks up a specified id in the id-to-name DB
+ * file, and returns the associated name string. This name
+ * can be used to retrieve a record using ndbFindName().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * id - id to look up
+ * plen - pointer to returned length of name
+ * (may be null, length includes null terminator
+ * in a string)
+ * pname - pointer to returned name string pointer
+ *
+ * Returns:
+ *
+ * The return value is zero if the operation is successful. An
+ * error is indicated by a negative return value (see nsdberr.h),
+ * and an error frame is generated if an error frame list was
+ * provided by the caller.
+ */
+
+int ndbIdToName(NSErr_t * errp,
+ void * ndb, unsigned int id, int * plen, char **pname)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ char * name = 0;
+ int namelen = 0;
+ uint32 myid = id - 1;
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Is the id-to-name DB open for reading ids? */
+ if (!(ndbp->ndb_flags & NDBF_RDID)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_RDID);
+ if (rv) goto punt;
+ }
+
+ /* Set up record key */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(myid);
+#endif
+ key.data = (void *)&myid;
+ key.size = sizeof(myid);
+
+ /* Initialize record buffer descriptor */
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_idb->get)(ndbp->ndb_idb, &key, &rec, 0);
+ if (rv) goto err_iget;
+
+ /* Get the name pointer (terminating null is part of the name) */
+ namelen = rec.size;
+ name = (char *) rec.data;
+
+ punt:
+ /* Return name length and size if requested */
+ if (plen) *plen = namelen;
+ if (pname) *pname = name;
+
+ return rv;
+
+ err_iget:
+ eid = NSDBERR1100;
+ rv = NDBERRGET;
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_iname, system_errmsg());
+ goto punt;
+}
+
+/*
+ * Description (ndbInitPrimary)
+ *
+ * This function creates and initializes the primary DB file.
+ * Initialization involves writing any required metadata records.
+ * Currently there is a ?dbtype record, which specifies the nsdb
+ * version number, and a database type and version number that
+ * were passed as arguments to ndbOpen(). There is also a
+ * ?idmap record, which contains an allocation bitmap for id values
+ * used as keys in the associated id-to-name DB file.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if an
+ * error frame list was provided by the caller.
+ */
+
+int ndbInitPrimary(NSErr_t * errp, void * ndb)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ uint32 m;
+ int i;
+#endif
+ int eid; /* error id code */
+ int rv; /* result value */
+ uint32 dbtype[4];
+
+ /* Error if the primary DB is marked as existing already */
+ if (!(ndbp->ndb_flags & NDBF_NONAME)) goto err_exists;
+
+ /* First create the primary DB file */
+ ndbp->ndb_pdb = dbopen(ndbp->ndb_pname, O_RDWR | O_CREAT | O_TRUNC,
+ NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_pdb) goto err_open;
+
+ /* Generate data for the ?dbtype record */
+ dbtype[0] = NDB_VERSION;
+ dbtype[1] = ndbp->ndb_dbtype;
+ dbtype[2] = ndbp->ndb_version;
+ dbtype[3] = 0;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ for (i = 0; i < 4; ++i) {
+ m = dbtype[i];
+ M_32_SWAP(m);
+ dbtype[i] = m;
+ }
+#endif
+
+ /* Set up descriptors for the ?dbtype record key and data */
+ key.data = (void *)NDB_DBTYPE;
+ key.size = strlen(NDB_DBTYPE) + 1;
+
+ rec.data = (void *)dbtype;
+ rec.size = sizeof(dbtype);
+
+ /* Write the ?dbtype record out */
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mput1;
+
+ /* Write out an empty ?idmap record */
+ key.data = (void *)NDB_IDMAP;
+ key.size = strlen(NDB_IDMAP) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Write the ?idmap record */
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mput2;
+
+ /* Close the DB file */
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+
+ /* Clear the flag that says the primary DB file does not exist */
+ ndbp->ndb_flags &= ~(NDBF_NONAME|NDBF_RDNAME|NDBF_WRNAME);
+
+ /* Indicate success */
+ return 0;
+
+ err_exists:
+ /* Primary database already exists */
+ eid = NSDBERR1200;
+ rv = NDBERREXIST;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 1, ndbp->ndb_pname);
+ return rv;
+
+ err_open:
+ /* Error opening primary database for write */
+ eid = NSDBERR1220;
+ rv = NDBERROPEN;
+ goto err_dbio;
+
+ err_mput1:
+ /* Error writing "?dbtype" record */
+ eid = NSDBERR1240;
+ rv = NDBERRMDPUT;
+ goto err_dbio;
+
+ err_mput2:
+ /* Error writing "?idmap" record */
+ eid = NSDBERR1260;
+ rv = NDBERRMDPUT;
+ goto err_dbio;
+
+ err_dbio:
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_pname, system_errmsg());
+
+ /* Close the primary DB file if it exists */
+ if (ndbp->ndb_pdb) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ ndbp->ndb_flags &= ~(NDBF_RDNAME|NDBF_WRNAME);
+ }
+
+ /* Delete the file */
+ system_unlink(ndbp->ndb_pname);
+ return rv;
+}
+
+/*
+ * Description (ndbOpen)
+ *
+ * This function opens a server database by name. The specified
+ * name may be the name of the primary DB file, or the name
+ * without the ".db" suffix. This function will attempt to open
+ * both the primary and the id-to-name DB files for read access.
+ * If either of the DB files do not exist, they are not created
+ * here, but a handle for the database will still be returned.
+ * The DB files will be created when a subsequent access writes
+ * to the database. The caller also specifies an application
+ * database type, which is checked against a value stored in
+ * in the database metadata, if the primary DB file exists, or
+ * which is stored in the file metadata when the file is created.
+ * A type-specific version number is passed and returned. The
+ * value passed will be stored in the file metadata if it is
+ * subsequently created. If the file exists, the value in the
+ * file metadata is returned, and it is the caller's responsibility
+ * to interpret it.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * dbname - primary DB filename
+ * flags - (currently unused - should be zero)
+ * dbtype - application DB type (NDB_TYPE_xxxxx)
+ * version - (in/out) type-specific version number
+ *
+ * Returns:
+ *
+ * A handle that can be used for subsequent accesses to the database
+ * is returned, or 0, if an error occurs, and an error frame is
+ * generated if an error frame list was provided by the caller.
+ */
+
+void * ndbOpen(NSErr_t * errp,
+ char * dbname, int flags, int dbtype, int * version)
+{
+ NSDB_t * ndbp = 0; /* database object pointer */
+ char * pname = 0; /* primary DB file name */
+ char * iname = 0; /* id-to-name DB file name */
+ int namelen;
+ uint32 dbtrec[4];
+ uint32 m;
+ DBT key;
+ DBT rec;
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Get the database name */
+ namelen = strlen(dbname);
+ if (!strcmp(&dbname[namelen-3], ".db")) {
+ namelen -= 3;
+ }
+
+ /* Get the primary DB file name */
+ pname = (char *)MALLOC(namelen + 4);
+ if (pname == 0) goto err_nomem1;
+ strncpy(pname, dbname, namelen);
+ strcpy(&pname[namelen], ".db");
+
+ /* Get the id-to-name DB file name */
+ iname = (char *)MALLOC(namelen + 4);
+ if (iname == 0) goto err_nomem2;
+ strncpy(iname, dbname, namelen);
+ strcpy(&iname[namelen], ".id");
+
+ /* Allocate the database object */
+ ndbp = (NSDB_t *)MALLOC(sizeof(NSDB_t));
+ if (ndbp == 0) goto err_nomem3;
+
+ /* Initialize the database object */
+ ndbp->ndb_pname = pname;
+ ndbp->ndb_pdb = 0;
+ ndbp->ndb_iname = iname;
+ ndbp->ndb_idb = 0;
+ ndbp->ndb_flags = 0;
+ ndbp->ndb_dbtype = dbtype;
+ ndbp->ndb_version = (version) ? *version : 0;
+
+ /* Open the primary DB file */
+ ndbp->ndb_pdb = dbopen(pname, O_RDONLY, NDBMODE, DB_HASH, 0);
+
+ /* Was it there? */
+ if (ndbp->ndb_pdb) {
+
+ /* Retrieve the ?dbtype record */
+ key.data = (void *)NDB_DBTYPE;
+ key.size = strlen(NDB_DBTYPE) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Read the ?dbtype record */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mdget;
+
+ /* Check it out */
+ if (rec.size < 16) goto err_fmt;
+
+ /* Copy data to an aligned area */
+ memcpy((void *)dbtrec, rec.data, sizeof(dbtrec));
+
+ /* Get the NSDB version number */
+ m = dbtrec[0];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(m);
+#endif
+ /* Assume forward compatibility with versions up to current + 0.5 */
+ if (m > (NDB_VERSION + 5)) goto err_vers;
+
+ /* XXX Assume infinite backward compatibility */
+
+ /* Get the application database type */
+ m = dbtrec[1];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(m);
+#endif
+ /* It's got to match */
+ if (m != dbtype) goto err_type;
+
+ /* Get the type-specific version number */
+ m = dbtrec[3];
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(m);
+#endif
+ /* Don't check it. Just return it. */
+ if (version) *version = m;
+
+ /* The value in dbtrec[3] is currently ignored */
+
+ /* Mark the primary DB file open for read access */
+ ndbp->ndb_flags |= NDBF_RDNAME;
+ }
+ else {
+ /* Indicate that the primary DB file does not exist */
+ ndbp->ndb_flags |= NDBF_NONAME;
+ }
+
+ return (void *)ndbp;
+
+ err_nomem1:
+ eid = NSDBERR1400;
+ rv = NDBERRNOMEM;
+ goto err_nomem;
+
+ err_nomem2:
+ eid = NSDBERR1420;
+ rv = NDBERRNOMEM;
+ goto err_nomem;
+
+ err_nomem3:
+ eid = NSDBERR1440;
+ rv = NDBERRNOMEM;
+ err_nomem:
+ nserrGenerate(errp, rv, eid, NSDB_Program, 0);
+ goto punt;
+
+ err_mdget:
+ eid = NSDBERR1460;
+ rv = NDBERRMDGET;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname,
+ system_errmsg());
+ goto err_ret;
+
+ err_fmt:
+ eid = NSDBERR1480;
+ rv = NDBERRMDFMT;
+ goto err_ret;
+
+ err_vers:
+ {
+ char vnbuf[16];
+
+ eid = NSDBERR1500;
+ rv = NDBERRVERS;
+ sprintf(vnbuf, "%d", (int)m);
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, vnbuf);
+ }
+ goto punt;
+
+ err_type:
+ eid = NSDBERR1520;
+ rv = NDBERRDBTYPE;
+ goto err_ret;
+
+ err_ret:
+ nserrGenerate(errp, rv, eid, NSDB_Program, 1, ndbp->ndb_pname);
+ goto punt;
+
+ punt:
+ /* Error clean-up */
+ if (pname) FREE(pname);
+ if (iname) FREE(iname);
+ if (ndbp) {
+ /* Close the DB files if we got as far as opening them */
+ if (ndbp->ndb_pdb) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ }
+ if (ndbp->ndb_idb) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ }
+ FREE(ndbp);
+ }
+ return 0;
+}
+
+/*
+ * Description (ndbReOpen)
+ *
+ * This function is called to ensure that the primary DB file
+ * and/or the id-to-name DB file are open with specified access
+ * rights. For example, a file may be open for read, and it needs
+ * to be open for write. Both the primary and id-to-name DB files
+ * can be manipulated with a single call.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - (currently unused - should be zero)
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned (NDBERRxxxx - see nsdb.h). If an error
+ * list is provided, an error frame will be generated when the
+ * return value is non-zero.
+ */
+
+int ndbReOpen(NSErr_t * errp, void * ndb, int flags)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ char * dbname; /* database name pointer */
+ int eid;
+ int rv;
+
+ /* Want to read or write the primary DB file? */
+ if (flags & (NDBF_RDNAME|NDBF_WRNAME)) {
+
+ /* Need to open for write? */
+ if ((flags & NDBF_WRNAME) && !(ndbp->ndb_flags & NDBF_WRNAME)) {
+
+ /* If it's already open for read, close it first */
+ if (ndbp->ndb_flags & NDBF_RDNAME) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ ndbp->ndb_flags &= ~NDBF_RDNAME;
+ }
+
+ /* Create it if it doesn't exist */
+ if (ndbp->ndb_flags & NDBF_NONAME) {
+ rv = ndbInitPrimary(errp, ndb);
+ if (rv) goto err_init;
+ }
+
+ /* Open primary DB file for write access */
+ dbname = ndbp->ndb_pname;
+ ndbp->ndb_pdb = dbopen(dbname, O_RDWR, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_pdb) goto err_open1;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= (NDBF_RDNAME|NDBF_WRNAME);
+ }
+
+ /* Need to open for read? */
+ if ((flags & NDBF_RDNAME) && !(ndbp->ndb_flags & NDBF_RDNAME)) {
+
+ /* If it's already open for write, close it first */
+ if (ndbp->ndb_flags & NDBF_WRNAME) {
+ (*ndbp->ndb_pdb->close)(ndbp->ndb_pdb);
+ ndbp->ndb_flags &= ~(NDBF_RDNAME|NDBF_WRNAME);
+ }
+
+ /* Open primary DB file for read access */
+ dbname = ndbp->ndb_pname;
+ ndbp->ndb_pdb = dbopen(dbname, O_RDONLY, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_pdb) goto err_open2;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= NDBF_RDNAME;
+ }
+ }
+
+ /* Want to read or write the id-to-name DB file? */
+ if (flags & (NDBF_RDID|NDBF_WRID)) {
+
+ /* Need to open for write? */
+ if ((flags & NDBF_WRID) && !(ndbp->ndb_flags & NDBF_WRID)) {
+
+ /*
+ * If it's not open for read yet, try to open it for read
+ * in order to find out if it exists.
+ */
+ if (!(ndbp->ndb_flags & NDBF_RDID)) {
+
+ /* Open id-to-name DB file for read access */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname, O_RDONLY, NDBMODE, DB_HASH,0);
+
+ /* Does it exist? */
+ if (ndbp->ndb_idb == 0) {
+
+ /* No, create it */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname,O_RDWR | O_CREAT | O_TRUNC,
+ NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_idb) goto err_open3;
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ }
+ else {
+ /* Mark it open for read */
+ ndbp->ndb_flags |= NDBF_RDID;
+ }
+ }
+
+ /* If it's already open for read, close it first */
+ if (ndbp->ndb_flags & NDBF_RDID) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ ndbp->ndb_flags &= ~NDBF_RDID;
+ }
+
+ /* Open id-to-name DB file for write access */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname, O_RDWR, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_idb) goto err_open4;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= (NDBF_RDID|NDBF_WRID);
+ }
+
+ /* Need to open for read? */
+ if ((flags & NDBF_RDID) && !(ndbp->ndb_flags & NDBF_RDID)) {
+
+ /* If it's already open for write, close it first */
+ if (ndbp->ndb_flags & NDBF_WRID) {
+ (*ndbp->ndb_idb->close)(ndbp->ndb_idb);
+ ndbp->ndb_flags &= ~(NDBF_RDID|NDBF_WRID);
+ }
+
+ /* Open id-to-name DB file for read access */
+ dbname = ndbp->ndb_iname;
+ ndbp->ndb_idb = dbopen(dbname, O_RDONLY, NDBMODE, DB_HASH, 0);
+ if (!ndbp->ndb_idb) goto err_open5;
+
+ /* Update flags to indicate successful open */
+ ndbp->ndb_flags |= NDBF_RDID;
+ }
+ }
+
+ /* Successful completion */
+ return 0;
+
+ /* Begin error handlers */
+
+ err_init: /* failed to create primary DB file */
+ (void)nserrGenerate(errp, NDBERRPINIT, NSDBERR1600, NSDB_Program,
+ 1,
+ ndbp->ndb_pname /* primary DB filename */
+ );
+ rv = NDBERRPINIT;
+ goto punt;
+
+ err_open1:
+ eid = NSDBERR1620;
+ goto err_open;
+
+ err_open2:
+ eid = NSDBERR1640;
+ goto err_open;
+
+ err_open3:
+ eid = NSDBERR1660;
+ goto err_open;
+
+ err_open4:
+ eid = NSDBERR1680;
+ goto err_open;
+
+ err_open5:
+ eid = NSDBERR1700;
+ goto err_open;
+
+ err_open: /* database open error */
+ rv = NDBERROPEN;
+ (void)nserrGenerate(errp, NDBERROPEN, eid, NSDB_Program,
+ 2, dbname, system_errmsg());
+
+ punt:
+ return rv;
+}
+
+NSPR_END_EXTERN_C
+
diff --git a/lib/libaccess/nsdbmgmt.cpp b/lib/libaccess/nsdbmgmt.cpp
new file mode 100644
index 00000000..c1151e08
--- /dev/null
+++ b/lib/libaccess/nsdbmgmt.cpp
@@ -0,0 +1,685 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsdbmgmt.h)
+ *
+ * The file describes the interface for managing information in
+ * a Netscape (server) database. A database is composed of
+ * two (libdbm) DB files. One of these (<dbname>.db) contains
+ * records indexed by a string key. These records contain the
+ * primary information in the database. A second DB file
+ * (<dbname>.id) is used to map an integer id value to a string
+ * key, which can then be used to locate a record in the first file.
+ * The interface for retrieving information from a database is
+ * described in nsdb.h.
+ */
+
+#include <base/systems.h>
+#include <netsite.h>
+#include <base/file.h>
+#define __PRIVATE_NSDB
+#include <libaccess/nsdbmgmt.h>
+#include <base/util.h>
+
+/*
+ * Description (ndbAllocId)
+ *
+ * This function allocates a unique id to be associated with a
+ * name in the primary DB file. An id bitmap is maintained in
+ * the primary DB file as a metadata record, and an entry is
+ * created in the id-to-name DB for the assigned id and the
+ * specified name. An allocated id value is always non-zero.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * namelen - length of key of the desired record,
+ * including null terminator if any
+ * name - pointer to the key of the desired record
+ * id - pointer to returned id value
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero, and the allocated id
+ * is returned through 'id'. Otherwise a non-zero error code is
+ * returned (NDBERRxxxx - see nsdb.h). If an error list is
+ * provided, an error frame will be generated when the return
+ * value is non-zero.
+ */
+
+int ndbAllocId(NSErr_t * errp,
+ void * ndb, int namelen, char * name, unsigned int * id)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ unsigned char * idmap;
+ unsigned char * newmap = 0;
+ int m;
+ int mmsk;
+ uint32 idval;
+ int myid;
+ int i, n;
+ int rv;
+ long eid;
+
+ /*
+ * Ensure that the name does not start with the metadata
+ * prefix character.
+ */
+ if (!name || (name[0] == NDB_MDPREFIX)) goto err_name;
+
+ /*
+ * Read the primary DB file metadata record containing the id
+ * allocation bitmap.
+ */
+
+ /*
+ * We need the primary and the id-to-name DB files open for write
+ * (and implicitly read) access.
+ */
+ if ((ndbp->ndb_flags & (NDBF_WRNAME|NDBF_WRID))
+ != (NDBF_WRNAME|NDBF_WRID)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, (NDBF_WRNAME|NDBF_WRID));
+ if (rv < 0) goto punt;
+ }
+
+ /* Set the key to the id allocation bitmap record name */
+ key.data = (void *)NDB_IDMAP;
+ key.size = strlen(NDB_IDMAP) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mdget;
+
+ /* Search for an available id in the bitmap */
+ n = rec.size;
+ idmap = (unsigned char *)rec.data;
+
+ for (i = 0, m = 0; i < n; ++i) {
+
+ m = idmap[i];
+ if (m != 0) break;
+ }
+
+ /* Did we find a byte with an available bit? */
+ if (m == 0) {
+
+ /* No, need to grow the bitmap */
+ newmap = (unsigned char *)MALLOC(rec.size + 32);
+ if (newmap == 0) goto err_nomem1;
+
+ /* Initialize free space at the beginning of the new map */
+ for (i = 0; i < 32; ++i) {
+ newmap[i] = 0xff;
+ }
+
+ /* Copy the old map after it */
+ n += 32;
+ for ( ; i < n; ++i) {
+ newmap[i] = idmap[i-32];
+ }
+
+ /* Set i and m to allocate the new highest id value */
+ i = 0;
+ m = 0xff;
+ }
+ else {
+
+ /*
+ * It's unfortunate, but it appears to be necessary to copy the
+ * the ?idmap record into a new buffer before updating it, rather
+ * than simply updating it in place. The problem is that the
+ * libdbm put routine deletes the old record and then re-inserts
+ * it. But once it has deleted the old record, it may take the
+ * opportunity to move another record into the space that the
+ * old record occupied, which is the same space that the new
+ * record occupies. So the new record data is overwritten before
+ * new record is inserted. :-(
+ */
+
+ newmap = (unsigned char *)MALLOC(rec.size);
+ if (newmap == 0) goto err_nomem2;
+
+ memcpy((void *)newmap, (void *)idmap, rec.size);
+ }
+
+ /* Calculate the id associated with the low-order bit of byte i */
+ myid = (n - i - 1) << 3;
+
+ /* Find the first free (set) bit in that word */
+ for (mmsk = 1; !(m & mmsk); mmsk <<= 1, myid += 1) ;
+
+ /* Clear the bit */
+ m &= ~mmsk;
+ newmap[i] = m;
+
+ /* Write the bitmap back out */
+
+ rec.data = (void *)newmap;
+ rec.size = n;
+
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+
+ /* Check for error on preceding put operation */
+ if (rv) goto err_putpdb;
+
+ /* Create the key for the id-to-name record */
+ idval = myid;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(idval);
+#endif
+
+ key.data = (void *)&idval;
+ key.size = sizeof(uint32);
+
+ rec.data = (void *)name;
+ rec.size = (namelen > 0) ? namelen : (strlen(name) + 1);
+
+ /* Write the id-to-name record */
+ rv = (*ndbp->ndb_idb->put)(ndbp->ndb_idb, &key, &rec, 0);
+ if (rv) goto err_putidb;
+
+ /* Return the id value + 1, to avoid returning a zero id */
+ if (id) *id = myid + 1;
+
+ punt:
+
+ /* Free the new map space if any */
+ if (newmap) {
+ FREE(newmap);
+ }
+
+ return rv;
+
+ err_name: /* invalid name parameter */
+ eid = NSDBERR2000;
+ rv = NDBERRNAME;
+ if (name == 0) {
+ name = "(null)";
+ }
+ else if ((namelen > 0) && (namelen != strlen(name) + 1)) {
+ name = "(unprintable)";
+ }
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB filename */
+ name /* name string */
+ );
+ goto punt;
+
+ err_mdget: /* error on get from primary DB file */
+ eid = NSDBERR2020;
+ rv = NDBERRMDGET;
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB filename */
+ (char *)key.data /* key name string */
+ );
+ goto punt;
+
+ err_nomem1:
+ eid = NSDBERR2040;
+ goto err_nomem;
+
+ err_nomem2:
+ eid = NSDBERR2060;
+ err_nomem: /* insufficient memory */
+ rv = NDBERRNOMEM;
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program, 0);
+ goto punt;
+
+ err_putpdb: /* error on put to primary DB file */
+ eid = NSDBERR2080;
+ rv = NDBERRMDPUT;
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB filename */
+ (char *)key.data /* key name string */
+ );
+ goto punt;
+
+ err_putidb: /* error on put to id-to-name DB */
+ {
+ char idstring[16];
+
+ eid = NSDBERR2100;
+ rv = NDBERRIDPUT;
+
+ util_sprintf(idstring, "%d", myid);
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_iname, /* id-to-name DB file */
+ idstring /* id value for key */
+ );
+ }
+ goto punt;
+}
+
+/*
+ * Description (ndbDeleteName)
+ *
+ * This function deletes a named record from the primary DB file.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - (currently unused - should be zero)
+ * namelen - length of name key, including null
+ * terminator if any
+ * name - pointer to name key
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned (NDBERRxxxx - see nsdberr.h). If an error
+ * list is provided, an error frame will be generated when the
+ * return value is non-zero.
+ */
+
+int ndbDeleteName(NSErr_t * errp,
+ void * ndb, int flags, int namelen, char * name)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ int eid;
+ int rv;
+
+ /* Is the primary DB open for write access? */
+ if (!(ndbp->ndb_flags & NDBF_WRNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_WRNAME);
+ if (rv) goto punt;
+ }
+
+ /* Set up the key descriptor */
+ key.data = (void *)name;
+ key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
+
+ /* Delete the record from the primary DB file */
+ rv = (*ndbp->ndb_pdb->del)(ndbp->ndb_pdb, &key, 0);
+ if (rv) goto err_delpdb;
+
+ /* Successful completion */
+ return 0;
+
+ /* Begin error handlers */
+
+ err_delpdb: /* error deleting record from primary DB */
+ eid = NSDBERR2200;
+ rv = NDBERRNMDEL;
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB name */
+ (char *)key.data /* primary key */
+ );
+ punt:
+ return rv;
+}
+
+/*
+ * Description (ndbFreeId)
+ *
+ * This function frees an id value associated with a name in the
+ * primary DB file. It is normally called when the named record
+ * is being deleted from the primary DB file. It deletes the
+ * record in the id-to-name DB file that is keyed by the id value,
+ * and updates the id allocation bitmap in the primary DB file.
+ * The caller may specify the name that is associated with the id
+ * value, in which case the id-to-name record will be fetched,
+ * and the name matched, before the record is deleted. Alternatively
+ * the name parameter can be specified as zero, and id-to-name
+ * record will be deleted without a check.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * namelen - length of name (including null terminator)
+ * name - name associated with the id value (optional)
+ * id - id value to be freed
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if the
+ * caller provided an error frame list.
+ */
+
+int ndbFreeId(NSErr_t * errp,
+ void * ndb, int namelen, char * name, unsigned int id)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ char * recname;
+ DBT key;
+ DBT rec;
+ uint32 idval;
+ int reclen;
+ int mmsk;
+ unsigned char * idmap = 0;
+ int i;
+ int eid;
+ int rv;
+
+ /*
+ * We need the primary and the id-to-name DB files open for write
+ * (and implicitly read) access.
+ */
+ if ((ndbp->ndb_flags & (NDBF_WRNAME|NDBF_WRID))
+ != (NDBF_WRNAME|NDBF_WRID)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, (NDBF_WRNAME|NDBF_WRID));
+ if (rv) goto punt;
+ }
+
+ /* Was the name for this id value provided by the caller? */
+ if (name) {
+
+ /* Get length of name if not provided */
+ if (namelen <= 0) namelen = strlen(name) + 1;
+
+ /* Yes, look up the id and check for a match */
+ rv = ndbIdToName(errp, ndb, id, &reclen, &recname);
+ if (rv < 0) goto punt;
+
+ /* Fail if the supplied name doesn't match */
+ if ((namelen != reclen) ||
+ strncmp(recname, name, reclen)) goto err_badid1;
+ }
+
+ /* Caller views the id space as starting at 1, but we start at 0 */
+ id -= 1;
+
+ /* Create the key for the id-to-name record */
+ idval = id;
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(idval);
+#endif
+
+ key.data = (void *)&idval;
+ key.size = sizeof(uint32);
+
+ /* Delete the id-to-name record */
+ rv = (*ndbp->ndb_idb->del)(ndbp->ndb_idb, &key, 0);
+ if (rv) goto err_del;
+
+ /* Set the key to the id allocation bitmap record name */
+ key.data = (void *)NDB_IDMAP;
+ key.size = strlen(NDB_IDMAP) + 1;
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_pdb->get)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mdget;
+
+ /* Make sure the id is in the range of the bitmap */
+ i = (rec.size << 3) - id - 1;
+ if (i < 0) goto err_badid2;
+
+ /*
+ * See comment in ndbAllocId() about updating ?idmap. Bottom line
+ * is: we have to copy the record before updating it.
+ */
+
+ idmap = (unsigned char *)MALLOC(rec.size);
+ if (idmap == 0) goto err_nomem;
+
+ memcpy((void *)idmap, rec.data, rec.size);
+
+ /* Calculate the index of the byte with this id's bit */
+ i >>= 3;
+
+ /* Calculate the bitmask for the bitmap byte */
+ mmsk = 1 << (id & 7);
+
+ /* Set the bit in the bitmap */
+ idmap[i] |= mmsk;
+
+ /* Write the bitmap back out */
+
+ rec.data = (void *)idmap;
+
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec, 0);
+ if (rv) goto err_mdput;
+
+ punt:
+
+ if (idmap) {
+ FREE(idmap);
+ }
+
+ return rv;
+
+ err_badid1:
+ /* Name associated with id doesn't match supplied name */
+ eid = NSDBERR2300;
+ rv = NDBERRBADID;
+ goto err_id;
+
+ err_del:
+ /* Error deleting id-to-name record */
+ eid = NSDBERR2320;
+ rv = NDBERRIDDEL;
+ goto err_dbio;
+
+ err_mdget:
+ /* Error reading id bitmap from primary DB file */
+ eid = NSDBERR2340;
+ rv = NDBERRMDGET;
+ goto err_dbio;
+
+ err_badid2:
+ eid = NSDBERR2360;
+ rv = NDBERRBADID;
+ err_id:
+ {
+ char idbuf[16];
+
+ util_sprintf(idbuf, "%d", id);
+ nserrGenerate(errp, rv, eid, NSDB_Program, 2, ndbp->ndb_pname, idbuf);
+ }
+ goto punt;
+
+ err_nomem:
+ eid = NSDBERR2380;
+ rv = NDBERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSDB_Program, 0);
+ goto punt;
+
+ err_mdput:
+ eid = NSDBERR2400;
+ rv = NDBERRMDPUT;
+ goto err_dbio;
+
+ err_dbio:
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_pname, system_errmsg());
+ goto punt;
+}
+
+/*
+ * Description (ndbRenameId)
+ *
+ * This function changes the name associated with a specified id
+ * int the id-to-name DB file.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * namelen - length of new name string, including
+ * null terminator if any
+ * newname - pointer to the new name string
+ * id - id value to be renamed
+ *
+ * Returns:
+ *
+ * The return value is zero if the operation is successful. An
+ * error is indicated by a non-zero return value, and an error
+ * frame is generated if the caller provided an error frame list.
+ */
+
+int ndbRenameId(NSErr_t * errp,
+ void * ndb, int namelen, char * newname, unsigned int id)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ uint32 idval = id - 1;
+ int eid;
+ int rv;
+
+ /*
+ * Ensure that the name does not start with the metadata
+ * prefix character.
+ */
+ if (!newname || (newname[0] == NDB_MDPREFIX)) goto err_name;
+
+ /*
+ * We need the id-to-name DB file open for write
+ * (and implicitly read) access.
+ */
+ if (!(ndbp->ndb_flags & NDBF_WRID)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_WRID);
+ if (rv) goto punt;
+ }
+
+ /* Set up record key */
+#if BYTE_ORDER == LITTLE_ENDIAN
+ M_32_SWAP(idval);
+#endif
+ key.data = (void *)&idval;
+ key.size = sizeof(uint32);
+
+ rec.data = 0;
+ rec.size = 0;
+
+ /* Retrieve the record by its key */
+ rv = (*ndbp->ndb_idb->get)(ndbp->ndb_idb, &key, &rec, 0);
+ if (rv) goto err_idget;
+
+ /* Set up to write the new name */
+ rec.data = (void *)newname;
+ rec.size = (namelen > 0) ? namelen : (strlen(newname) + 1);
+
+ /* Write the id-to-name record */
+ rv = (*ndbp->ndb_idb->put)(ndbp->ndb_idb, &key, &rec, 0);
+ if (rv) goto err_idput;
+
+ punt:
+ return rv;
+
+ err_name:
+ eid = NSDBERR2500;
+ rv = NDBERRNAME;
+ if (newname == 0) newname = "(null)";
+ else if ((namelen > 0) && (namelen != (strlen(newname) + 1))) {
+ newname = "(unprintable)";
+ }
+ (void)nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2,
+ ndbp->ndb_pname, /* primary DB filename */
+ newname /* name string */
+ );
+ goto punt;
+
+ err_idget:
+ /* Error getting id record from id-to-name database */
+ eid = NSDBERR2520;
+ rv = NDBERRGET;
+ goto err_dbio;
+
+ err_idput:
+ /* Error putting id record back to id-to-name database */
+ eid = NSDBERR2540;
+ rv = NDBERRIDPUT;
+ err_dbio:
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_pname, system_errmsg());
+ goto punt;
+}
+
+/*
+ * Description (ndbStoreName)
+ *
+ * This function stores a record, keyed by a specified name, in the
+ * primary DB file. The record will overwrite any existing record
+ * with the same key, unless NDBF_NEWNAME, is included in the 'flags'
+ * argument. If NDBF_NEWNAME is set, and the record already exists,
+ * it is not overwritten, and an error is returned.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * ndb - database handle from ndbOpen()
+ * flags - bit flags:
+ * NDBF_NEWNAME - name is new
+ * namelen - length of name key, including null
+ * terminator if any
+ * name - pointer to name key
+ * reclen - length of the record data
+ * recptr - pointer to the record data
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise a non-zero
+ * error code is returned, and an error frame is generated if the
+ * caller provided an error frame list.
+ */
+
+int ndbStoreName(NSErr_t * errp, void * ndb, int flags,
+ int namelen, char * name, int reclen, char * recptr)
+{
+ NSDB_t * ndbp = (NSDB_t *)ndb; /* database object pointer */
+ DBT key;
+ DBT rec;
+ int eid;
+ int rv;
+
+ /* Is the primary DB open for write access? */
+ if (!(ndbp->ndb_flags & NDBF_WRNAME)) {
+
+ /* No, (re)open it */
+ rv = ndbReOpen(errp, ndb, NDBF_WRNAME);
+ if (rv) goto punt;
+ }
+
+ /* Set up the key and record descriptors */
+ key.data = (void *)name;
+ key.size = (namelen > 0) ? namelen : (strlen(name) + 1);
+
+ rec.data = (void *)recptr;
+ rec.size = reclen;
+
+ /* Write the record to the primary DB file */
+ rv = (*ndbp->ndb_pdb->put)(ndbp->ndb_pdb, &key, &rec,
+ (flags & NDBF_NEWNAME) ? R_NOOVERWRITE : 0);
+ if (rv) goto err_put;
+
+ punt:
+ return rv;
+
+ err_put:
+ eid = NSDBERR2700;
+ rv = NDBERRPUT;
+ nserrGenerate(errp, rv, eid, NSDB_Program,
+ 2, ndbp->ndb_pname, system_errmsg());
+ goto punt;
+}
diff --git a/lib/libaccess/nseframe.cpp b/lib/libaccess/nseframe.cpp
new file mode 100644
index 00000000..c878940b
--- /dev/null
+++ b/lib/libaccess/nseframe.cpp
@@ -0,0 +1,207 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nseframe.c)
+ *
+ * This module is part of the NSACL_RES_ERROR facility. It contains functions
+ * for allocating, freeing, and managing error frame structures. It
+ * does not contain routines for generating error messages through
+ * the use of a message file.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "libaccess/nserror.h"
+
+/*
+ * Description (nserrDispose)
+ *
+ * This function is used to dispose of an entire list of error
+ * frames when the error information is no longer needed. It
+ * does not free the list head, since it is usually not dynamically
+ * allocated.
+ *
+ * Arguments:
+ *
+ * errp - error frame list head pointer
+ */
+
+void nserrDispose(NSErr_t * errp)
+{
+ /* Ignore null list head */
+ if (errp == 0) return;
+
+ while (errp->err_first) {
+
+ nserrFFree(errp, errp->err_first);
+ }
+}
+
+/*
+ * Description (nserrFAlloc)
+ *
+ * This is the default allocator for error frame structures. It
+ * calls an allocator function indicated by err_falloc, if any,
+ * or else uses MALLOC().
+ *
+ * Arguments:
+ *
+ * errp - error frame list head pointer
+ * (may be null)
+ *
+ * Returns:
+ *
+ * The return value is a pointer to a cleared error frame. The
+ * frame will not have been added to the list referenced by errp.
+ * An allocation error is indicated by a null return value.
+ */
+
+NSEFrame_t * nserrFAlloc(NSErr_t * errp)
+{
+ NSEFrame_t * efp; /* return error frame pointer */
+
+ /* Allocate the error frame */
+ efp = (errp && errp->err_falloc)
+ ? (*errp->err_falloc)(errp)
+ : (NSEFrame_t *)MALLOC(sizeof(NSEFrame_t));
+
+ if (efp) {
+ /* Clear the error frame */
+ memset((void *)efp, 0, sizeof(NSEFrame_t));
+ }
+
+ return efp;
+}
+
+/*
+ * Description (nserrFFree)
+ *
+ * This function frees an error frame structure. If an error list
+ * head is specified, it first checks whether the indicated error
+ * frame is on the list, and removes it if so. If the ef_dispose
+ * field is non-null, the indicated function is called. The error
+ * frame is deallocated using either a function indicated by
+ * err_free in the list head, or FREE() otherwise.
+ *
+ * Arguments:
+ *
+ * errp - error frame list head pointer
+ * (may be null)
+ * efp - error frame pointer
+ */
+
+void nserrFFree(NSErr_t * errp, NSEFrame_t * efp)
+{
+ NSEFrame_t **lefp; /* pointer to error frame pointer */
+ NSEFrame_t * pefp; /* previous error frame on list */
+ int i;
+
+ /* Ignore null error frame pointer */
+ if (efp == 0) return;
+
+ /* Got a list head? */
+ if (errp) {
+
+ /* Yes, see if this frame is on the list */
+ pefp = 0;
+ for (lefp = &errp->err_first; *lefp != 0; lefp = &pefp->ef_next) {
+ if (*lefp == efp) {
+
+ /* Yes, remove it */
+ *lefp = efp->ef_next;
+ if (errp->err_last == efp) errp->err_last = pefp;
+ break;
+ }
+ pefp = *lefp;
+ }
+ }
+
+ /* Free strings referenced by the frame */
+ for (i = 0; i < efp->ef_errc; ++i) {
+ if (efp->ef_errv[i]) {
+ FREE(efp->ef_errv[i]);
+ }
+ }
+
+ /* Free the frame */
+ if (errp && errp->err_ffree) {
+ (*errp->err_ffree)(errp, efp);
+ }
+ else {
+ FREE(efp);
+ }
+}
+
+/*
+ * Description (nserrGenerate)
+ *
+ * This function is called to generate an error frame and add it
+ * to a specified error list.
+ *
+ * Arguments:
+ *
+ * errp - error frame list head pointer
+ * (may be null)
+ * retcode - return code (ef_retcode)
+ * errorid - error id (ef_errorid)
+ * program - program string pointer (ef_program)
+ * errc - count of error arguments (ef_errc)
+ * ... - values for ef_errv[]
+ *
+ * Returns:
+ *
+ * The return value is a pointer to the generated error frame, filled
+ * in with the provided information. An allocation error is indicated
+ * by a null return value.
+ */
+
+NSEFrame_t * nserrGenerate(NSErr_t * errp, long retcode, long errorid,
+ char * program, int errc, ...)
+{
+ NSEFrame_t * efp; /* error frame pointer */
+ char * esp; /* error string pointer */
+ int i;
+ va_list ap;
+
+ /* Null frame list head pointer means do nothing */
+ if (errp == 0) {
+ return 0;
+ }
+
+ /* Limit the number of values in ef_errv[] */
+ if (errc > NSERRMAXARG) errc = NSERRMAXARG;
+
+ /* Allocate the error frame */
+ efp = nserrFAlloc(errp);
+
+ /* Did we get it? */
+ if (efp) {
+
+ /* Yes, copy information into it */
+ efp->ef_retcode = retcode;
+ efp->ef_errorid = errorid;
+ efp->ef_program = program;
+ efp->ef_errc = errc;
+
+ /* Get the string arguments and copy them */
+ va_start(ap, errc);
+ for (i = 0; i < errc; ++i) {
+ esp = va_arg(ap, char *);
+ efp->ef_errv[i] = STRDUP(esp);
+ }
+
+ /* Add the frame to the list (if any) */
+ if (errp) {
+ efp->ef_next = errp->err_first;
+ errp->err_first = efp;
+ if (efp->ef_next == 0) errp->err_last = efp;
+ }
+ }
+
+ /* Return the error frame pointer */
+ return efp;
+}
diff --git a/lib/libaccess/nsgmgmt.cpp b/lib/libaccess/nsgmgmt.cpp
new file mode 100644
index 00000000..922b21bc
--- /dev/null
+++ b/lib/libaccess/nsgmgmt.cpp
@@ -0,0 +1,434 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsgmgmt.c)
+ *
+ * This module contains routines for managing information in a
+ * Netscape group database. Information for a particular group
+ * is modified by retrieving the current information in the form
+ * of a group object (GroupObj_t), calling functions in this module,
+ * to modify the group object, and then calling groupStore() to
+ * write the information in the group object back to the database.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#include "libaccess/nsdbmgmt.h"
+#define __PRIVATE_NSGROUP
+#include "libaccess/nsgmgmt.h"
+
+/*
+ * Description (groupAddMember)
+ *
+ * This function adds a member to a group object. The member may
+ * be another group or a user, expressed as a group id or user id,
+ * respectively. The 'isgid' argument is non-zero if the new
+ * member is a group, or zero if it is a user.
+ *
+ * Arguments:
+ *
+ * goptr - group object pointer
+ * isgid - non-zero if 'id' is a group id
+ * zero if 'id' is a user id
+ * id - group or user id to be added
+ *
+ * Returns:
+ *
+ * Returns zero if the specified member is already a direct member
+ * of the group. Returns one if the member was added successfully.
+ */
+
+NSAPI_PUBLIC int groupAddMember(GroupObj_t * goptr, int isgid, USI_t id)
+{
+ USIList_t * uilptr;
+ int rv = 0;
+
+ /* Point to the relevant uid or gid list */
+ uilptr = (isgid) ? &goptr->go_groups : &goptr->go_users;
+
+ /* Add the id to the selected list */
+ rv = usiInsert(uilptr, id);
+ if (rv > 0) {
+ goptr->go_flags |= GOF_MODIFIED;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (groupCreate)
+ *
+ * This function creates a group object, using information about
+ * the group provided by the caller. The strings passed for the
+ * group name and description may be on the stack. The group id
+ * is set to zero, but the group object is marked as being new.
+ * A group id will be assigned when groupStore() is called to add
+ * the group to a group database.
+ *
+ * Arguments:
+ *
+ * name - pointer to group name string
+ * desc - pointer to group description string
+ *
+ * Returns:
+ *
+ * A pointer to a dynamically allocated GroupObj_t structure is
+ * returned.
+ */
+
+NSAPI_PUBLIC GroupObj_t * groupCreate(NTS_t name, NTS_t desc)
+{
+ GroupObj_t * goptr; /* group object pointer */
+
+ goptr = (GroupObj_t *)MALLOC(sizeof(GroupObj_t));
+ if (goptr) {
+ goptr->go_name = (NTS_t)STRDUP((char *)name);
+ goptr->go_gid = 0;
+ goptr->go_flags = (GOF_MODIFIED | GOF_NEW);
+ if (desc) {
+ goptr->go_desc = (desc) ? (NTS_t)STRDUP((char *)desc) : 0;
+ }
+ UILINIT(&goptr->go_users);
+ UILINIT(&goptr->go_groups);
+ UILINIT(&goptr->go_pgroups);
+ }
+
+ return goptr;
+}
+
+/*
+ * Description (groupDeleteMember)
+ *
+ * This function removes a specified member from a group object's
+ * list of members. The member to be remove may be a group or a
+ * user, expressed as a group id or user id, respectively. The
+ * 'isgid' argument is non-zero if the member being removed is a
+ * group, or zero if it is a user.
+ *
+ * Arguments:
+ *
+ * goptr - pointer to group object
+ * isgid - non-zero if 'id' is a group id
+ * zero if 'id' is a user id
+ * id - group or user id to be removed
+ *
+ * Returns:
+ *
+ * The return value is zero if the specified member was not present
+ * in the group object, or one if the member was successfully removed.
+ */
+
+NSAPI_PUBLIC int groupDeleteMember(GroupObj_t * goptr, int isgid, USI_t id)
+{
+ USIList_t * uilptr; /* pointer to list of member users or groups */
+ int rv; /* return value */
+
+ /* Get pointer to appropriate list of ids */
+ uilptr = (isgid) ? &goptr->go_groups : &goptr->go_users;
+
+ /* Remove the specified id */
+ rv = usiRemove(uilptr, id);
+ if (rv > 0) {
+ goptr->go_flags |= GOF_MODIFIED;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (groupEncode)
+ *
+ * This function encodes a group object into a group DB record.
+ *
+ * Arguments:
+ *
+ * goptr - pointer to group object
+ * greclen - pointer to returned record length
+ * grecptr - pointer to returned record pointer
+ *
+ * Returns:
+ *
+ * The function return value is zero if successful. The length
+ * and location of the created attribute record are returned
+ * through 'greclen' and 'grecptr'. A non-zero function value
+ * is returned if there's an error.
+ */
+
+NSAPI_PUBLIC int groupEncode(GroupObj_t * goptr, int * greclen, ATR_t * grecptr)
+{
+ int reclen; /* length of DB record */
+ ATR_t rptr; /* DB record pointer */
+ ATR_t rstart = 0; /* pointer to beginning of DB record */
+ ATR_t glptr; /* saved pointer to UAT_GROUPS length */
+ ATR_t gptr; /* saved pointer to after length at glptr */
+ int gidlen; /* gid encoding length */
+ int fllen; /* flags encoding length */
+ USI_t dsclen; /* group description encoding length */
+ USI_t nulen; /* member user count encoding length */
+ USI_t nglen; /* member group count encoding length */
+ int idcnt; /* count of user or group ids */
+ USI_t * ids; /* pointer to array of user or group ids */
+ int i; /* id index */
+ int rv = -1;
+
+ /*
+ * First we need to figure out how long the generated record will be.
+ * This doesn't have to be exact, but it must not be smaller than the
+ * actual record size.
+ */
+
+ /* GAT_GID attribute: tag, length, USI */
+ gidlen = USILENGTH(goptr->go_gid);
+ reclen = (1 + 1 + gidlen);
+
+ /* GAT_FLAGS attribute: tag, length, USI */
+ fllen = USILENGTH(goptr->go_flags & GOF_DBFLAGS);
+ reclen += (1 + 1 + fllen);
+
+ /* GAT_DESCRIPT attribute: tag, length, NTS */
+ dsclen = NTSLENGTH(goptr->go_desc);
+ reclen += (1 + USILENGTH(dsclen) + dsclen);
+
+ /* GAT_USERS attribute: tag, length, USI(count), USI(uid)... */
+ idcnt = UILCOUNT(&goptr->go_users);
+ nulen = USILENGTH(idcnt);
+ reclen += (1 + USIALLOC() + nulen + (5 * idcnt));
+
+ /* GAT_GROUPS attribute: tag, length, USI(count), USI(gid)... */
+ idcnt = UILCOUNT(&goptr->go_groups);
+ nglen = USILENGTH(idcnt);
+ reclen += (1 + USIALLOC() + nglen + (5 * idcnt));
+
+ /* GAT_PGROUPS attribute: tag, length, USI(count), USI(gid)... */
+ idcnt = UILCOUNT(&goptr->go_pgroups);
+ nglen = USILENGTH(idcnt);
+ reclen += (1 + USIALLOC() + nglen + (5 * idcnt));
+
+ /* Allocate the attribute record buffer */
+ rptr = (ATR_t)MALLOC(reclen);
+ if (rptr) {
+
+ /* Save pointer to start of record */
+ rstart = rptr;
+
+ /* Encode GAT_GID attribute */
+ *rptr++ = GAT_GID;
+ *rptr++ = gidlen;
+ rptr = USIENCODE(rptr, goptr->go_gid);
+
+ /* Encode GAT_FLAGS attribute */
+ *rptr++ = GAT_FLAGS;
+ *rptr++ = fllen;
+ rptr = USIENCODE(rptr, (goptr->go_flags & GOF_DBFLAGS));
+
+ /* Encode GAT_DESCRIPT attribute */
+ *rptr++ = GAT_DESCRIPT;
+ rptr = USIENCODE(rptr, dsclen);
+ rptr = NTSENCODE(rptr, goptr->go_desc);
+
+ /* Encode GAT_USERS attribute */
+ *rptr++ = GAT_USERS;
+
+ /*
+ * Save a pointer to the attribute encoding length, and reserve
+ * space for the maximum encoding size of a USI_t value.
+ */
+ glptr = rptr;
+ rptr += USIALLOC();
+ gptr = rptr;
+
+ /* Encode number of user members */
+ idcnt = UILCOUNT(&goptr->go_users);
+ rptr = USIENCODE(rptr, idcnt);
+
+ /* Generate user ids encodings */
+ ids = UILLIST(&goptr->go_users);
+ for (i = 0; i < idcnt; ++i) {
+ rptr = USIENCODE(rptr, ids[i]);
+ }
+
+ /* Now fix up the GAT_USERS attribute encoding length */
+ glptr = USIINSERT(glptr, (USI_t)(rptr - gptr));
+
+ /* Encode GAT_GROUPS attribute */
+ *rptr++ = GAT_GROUPS;
+
+ /*
+ * Save a pointer to the attribute encoding length, and reserve
+ * space for the maximum encoding size of a USI_t value.
+ */
+ glptr = rptr;
+ rptr += USIALLOC();
+ gptr = rptr;
+
+ /* Encode number of groups */
+ idcnt = UILCOUNT(&goptr->go_groups);
+ rptr = USIENCODE(rptr, idcnt);
+
+ /* Generate group ids encodings */
+ ids = UILLIST(&goptr->go_groups);
+ for (i = 0; i < idcnt; ++i) {
+ rptr = USIENCODE(rptr, ids[i]);
+ }
+
+ /* Now fix up the GAT_GROUPS attribute encoding length */
+ glptr = USIINSERT(glptr, (USI_t)(rptr - gptr));
+
+ /* Encode GAT_PGROUPS attribute */
+ *rptr++ = GAT_PGROUPS;
+
+ /*
+ * Save a pointer to the attribute encoding length, and reserve
+ * space for the maximum encoding size of a USI_t value.
+ */
+ glptr = rptr;
+ rptr += USIALLOC();
+ gptr = rptr;
+
+ /* Encode number of groups */
+ idcnt = UILCOUNT(&goptr->go_pgroups);
+ rptr = USIENCODE(rptr, idcnt);
+
+ /* Generate group ids encodings */
+ ids = UILLIST(&goptr->go_pgroups);
+ for (i = 0; i < idcnt; ++i) {
+ rptr = USIENCODE(rptr, ids[i]);
+ }
+
+ /* Now fix up the GAT_PGROUPS attribute encoding length */
+ glptr = USIINSERT(glptr, (USI_t)(rptr - gptr));
+
+ /* Return record length and location if requested */
+ if (greclen) *greclen = rptr - rstart;
+ if (grecptr) *grecptr = rstart;
+
+ /* Indicate success */
+ rv = 0;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (groupRemove)
+ *
+ * This function is called to remove a group from a specified group
+ * database. Both the primary DB file and the id-to-name DB file
+ * are updated.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * flags - (unused - must be zero)
+ * name - pointer to group name
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code.
+ */
+
+NSAPI_PUBLIC int groupRemove(NSErr_t * errp, void * groupdb, int flags, NTS_t name)
+{
+ GroupObj_t * goptr; /* group object pointer */
+ int rv;
+ int rv2;
+
+ /* First retrieve the group record */
+ goptr = groupFindByName(errp, groupdb, name);
+ if (!goptr) {
+ /* Error - specified group not found */
+ return NSAERRNAME;
+ }
+
+ /* Free the group id value, if any */
+ rv = 0;
+ if (goptr->go_gid != 0) {
+ rv = ndbFreeId(errp, groupdb, 0, (char *)name, goptr->go_gid);
+ }
+
+ rv2 = ndbDeleteName(errp, groupdb, 0, 0, (char *)name);
+
+ return (rv) ? rv : rv2;
+}
+
+/*
+ * Description (groupStore)
+ *
+ * This function is called to store a group object in the database.
+ * If the object was created by groupCreate(), it is assumed to be
+ * a new group, the group account name must not match any existing
+ * group account names in the database, and a gid is assigned before
+ * adding the group to the database. If the object was created by
+ * groupFindByName(), the information in the group object will
+ * replace the existing database entry for the indicated group
+ * name.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * flags - (unused - must be zero)
+ * goptr - group object pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code. The group object remains intact in either
+ * case.
+ */
+
+NSAPI_PUBLIC int groupStore(NSErr_t * errp, void * groupdb, int flags, GroupObj_t * goptr)
+{
+ ATR_t recptr = 0;
+ USI_t gid;
+ int reclen = 0;
+ int stflags = 0;
+ int eid;
+ int rv;
+
+ /* If this is a new group, allocate a uid value */
+ if (goptr->go_flags & GOF_NEW) {
+
+ rv = ndbAllocId(errp, groupdb, 0, (char *)goptr->go_name, &gid);
+ if (rv) goto punt;
+
+ goptr->go_gid = gid;
+
+ /* Let the database manager know that this is a new entry */
+ stflags = NDBF_NEWNAME;
+ }
+
+ /* Convert the information in the group object to a DB record */
+ rv = groupEncode(goptr, &reclen, &recptr);
+ if (rv) goto err_nomem;
+
+ /*
+ * Store the record in the database under the group name.
+ * If this is a new entry, a group id to group name mapping
+ * also will be added to the id-to-name DB file.
+ */
+ rv = ndbStoreName(errp, groupdb, stflags,
+ 0, (char *)goptr->go_name, reclen, (char *)recptr);
+
+ FREE(recptr);
+
+ if (rv == 0) {
+ goptr->go_flags &= ~(GOF_NEW | GOF_MODIFIED);
+ }
+
+ punt:
+ return rv;
+
+ err_nomem:
+ eid = NSAUERR2000;
+ rv = NSAERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+}
diff --git a/lib/libaccess/nsgroup.cpp b/lib/libaccess/nsgroup.cpp
new file mode 100644
index 00000000..c67c85ba
--- /dev/null
+++ b/lib/libaccess/nsgroup.cpp
@@ -0,0 +1,336 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsgroup.c)
+ *
+ * This module contains routines for accessing information in a
+ * Netscape group database. Group information is returned in the
+ * form of a group object (GroupObj_t), defined in nsauth.h.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#define __PRIVATE_NSGROUP
+#include "libaccess/nsgroup.h"
+
+/*
+ * Description (groupDecode)
+ *
+ * This function decodes an external group DB record into a
+ * dynamically allocated GroupObj_t structure. The DB record is
+ * encoded as an attribute record as defined in attrec.h.
+ *
+ * Arguments:
+ *
+ * name - pointer to group name string
+ * greclen - length of the group DB record, in octets
+ * grecptr - pointer to group DB record
+ *
+ * Returns:
+ *
+ * A pointer to the allocated GroupObj_t structure is returned.
+ */
+
+NSAPI_PUBLIC GroupObj_t * groupDecode(NTS_t name, int greclen, ATR_t grecptr)
+{
+ ATR_t cp = grecptr; /* current pointer into DB record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+ int i; /* group id index */
+ int idcnt; /* count of user or group ids */
+ USI_t * ids; /* pointer to array of ids */
+ GroupObj_t * goptr; /* group object pointer */
+
+ /* Allocate a group object structure */
+ goptr = (GroupObj_t *)MALLOC(sizeof(GroupObj_t));
+ if (goptr) {
+
+ goptr->go_name = (unsigned char *) STRDUP((char *)name);
+ goptr->go_gid = 0;
+ goptr->go_flags = GOF_MODIFIED;
+ goptr->go_desc = 0;
+ UILINIT(&goptr->go_users);
+ UILINIT(&goptr->go_groups);
+ UILINIT(&goptr->go_pgroups);
+
+ /* Parse group DB record */
+ while ((cp - grecptr) < greclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case GAT_GID: /* group id */
+ cp = USIDECODE(cp, &goptr->go_gid);
+ break;
+
+ case GAT_FLAGS: /* flags */
+ cp = USIDECODE(cp, &goptr->go_flags);
+ break;
+
+ case GAT_DESCRIPT: /* group description */
+ cp = NTSDECODE(cp, &goptr->go_desc);
+ break;
+
+ case GAT_USERS: /* member users of this group */
+
+ /* First get the number of user ids following */
+ cp = USIDECODE(cp, (unsigned *)&idcnt);
+
+ if (idcnt > 0) {
+
+ /* Allocate space for user ids */
+ ids = usiAlloc(&goptr->go_users, idcnt);
+ if (ids) {
+ for (i = 0; i < idcnt; ++i) {
+ cp = USIDECODE(cp, ids + i);
+ }
+ }
+ }
+ break;
+
+ case GAT_GROUPS: /* member groups of this group */
+
+ /* First get the number of group ids following */
+ cp = USIDECODE(cp, (unsigned *)&idcnt);
+
+ if (idcnt > 0) {
+
+ /* Allocate space for group ids */
+ ids = usiAlloc(&goptr->go_groups, idcnt);
+ if (ids) {
+ for (i = 0; i < idcnt; ++i) {
+ cp = USIDECODE(cp, ids + i);
+ }
+ }
+ }
+ break;
+
+ case GAT_PGROUPS: /* parent groups of this group */
+
+ /* First get the number of group ids following */
+ cp = USIDECODE(cp, (USI_t *)&idcnt);
+
+ if (idcnt > 0) {
+
+ /* Allocate space for group ids */
+ ids = usiAlloc(&goptr->go_pgroups, idcnt);
+ if (ids) {
+ for (i = 0; i < idcnt; ++i) {
+ cp = USIDECODE(cp, ids + i);
+ }
+ }
+ }
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+ }
+
+ return goptr;
+}
+
+/*
+ * Description (groupEnumHelp)
+ *
+ * This is a local function that is called by NSDB during group
+ * database enumeration. It decodes group records into group
+ * objects, and presents them to the caller of groupEnumerate().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to GroupEnumArgs_t structure
+ * namelen - length of group record key, including null
+ * terminator
+ * name - group record key (group account name)
+ * reclen - length of group record
+ * recptr - pointer to group record contents
+ *
+ * Returns:
+ *
+ * Returns whatever value is returned from the upcall to the caller
+ * of groupEnumerate().
+ */
+
+static int groupEnumHelp(NSErr_t * errp, void * parg,
+ int namelen, char * name, int reclen, char * recptr)
+{
+ GroupEnumArgs_t * ge = (GroupEnumArgs_t *)parg;
+ GroupObj_t * goptr; /* group object pointer */
+ int rv;
+
+ goptr = groupDecode((NTS_t)name, reclen, (ATR_t)recptr);
+
+ rv = (*ge->func)(errp, ge->user, goptr);
+
+ if (!(ge->flags & GOF_ENUMKEEP)) {
+ FREE(goptr);
+ }
+
+ return rv;
+}
+
+/*
+ * Description (groupEnumerate)
+ *
+ * This function enumerates all of the groups in a specified group
+ * database, calling a caller-specified function with a group object
+ * for each group in the database. A 'flags' value of GOF_ENUMKEEP
+ * can be specified to keep the group objects around (not free them)
+ * after the caller's function returns. Otherwise, each group
+ * object is freed after being presented to the caller's function.
+ * The 'argp' argument is an opaque pointer, which is passed to
+ * the caller's function as 'parg' on each call, along with a
+ * group object pointer.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * flags - bit flags:
+ * GOF_ENUMKEEP - keep group objects
+ * argp - passed to 'func' as 'parg'
+ * func - pointer to caller's enumeration function
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code.
+ */
+
+NSAPI_PUBLIC int groupEnumerate(NSErr_t * errp, void * groupdb, int flags, void * argp,
+ int (*func)(NSErr_t * ferrp,
+ void * parg, GroupObj_t * goptr))
+{
+ int rv;
+ GroupEnumArgs_t args;
+
+ args.groupdb = groupdb;
+ args.flags = flags;
+ args.func = func;
+ args.user = argp;
+
+ rv = ndbEnumerate(errp,
+ groupdb, NDBF_ENUMNORM, (void *)&args, groupEnumHelp);
+
+ return rv;
+}
+
+/*
+ * Description (groupFindByName)
+ *
+ * This function looks up a group record for a specified group name,
+ * converts the group record to the internal group object form, and
+ * returns a pointer to the group object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * name - group name to find
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a group object
+ * for the specified group. Otherwise it is 0.
+ */
+
+NSAPI_PUBLIC GroupObj_t * groupFindByName(NSErr_t * errp, void * groupdb, NTS_t name)
+{
+ GroupObj_t * goptr = 0;
+ ATR_t grecptr;
+ int greclen;
+ int rv;
+
+ /* Look up the group name in the database */
+ rv = ndbFindName(errp, groupdb, 0, (char *)name, &greclen, (char **)&grecptr);
+ if (rv == 0) {
+
+ /* Got the group record. Decode into a group object. */
+ goptr = groupDecode(name, greclen, grecptr);
+ }
+
+ return goptr;
+}
+
+/*
+ * Description (groupFindByGid)
+ *
+ * This function looks up a group record for a specified group id,
+ * converts the group record to the internal group object form, and
+ * returns a pointer to the group object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * groupdb - handle for group DB access
+ * gid - group id to find
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a group object
+ * for the specified group. Otherwise it is 0.
+ */
+
+NSAPI_PUBLIC GroupObj_t * groupFindByGid(NSErr_t * errp, void * groupdb, USI_t gid)
+{
+ GroupObj_t * goptr = 0;
+ NTS_t name;
+ ATR_t grecptr;
+ int greclen;
+ int rv;
+
+ /* Get the group account name corresponding to the gid */
+ rv = ndbIdToName(errp, groupdb, gid, 0, (char **)&name);
+ if (rv == 0) {
+
+ rv = ndbFindName(errp, groupdb, 0, (char *)name, &greclen, (char **)&grecptr);
+ if (rv == 0) {
+
+ /* Got the group record. Decode into a group object. */
+ goptr = groupDecode(name, greclen, grecptr);
+ }
+ }
+
+ return goptr;
+}
+
+/*
+ * Description (groupFree)
+ *
+ * This function is called to free a group object. Group objects
+ * are not automatically freed when a group database is closed.
+ *
+ * Arguments:
+ *
+ * goptr - group object pointer
+ *
+ */
+
+NSAPI_PUBLIC void groupFree(GroupObj_t * goptr)
+{
+ if (goptr) {
+
+ if (goptr->go_name) FREE(goptr->go_name);
+ if (goptr->go_desc) FREE(goptr->go_desc);
+ UILFREE(&goptr->go_users);
+ UILFREE(&goptr->go_groups);
+ UILFREE(&goptr->go_pgroups);
+ FREE(goptr);
+ }
+}
diff --git a/lib/libaccess/nslock.cpp b/lib/libaccess/nslock.cpp
new file mode 100644
index 00000000..2cf0b00b
--- /dev/null
+++ b/lib/libaccess/nslock.cpp
@@ -0,0 +1,268 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nslock.c)
+ *
+ * This modules provides an interprocess locking mechanism, based
+ * on a named lock.
+ */
+
+#include "netsite.h"
+#include "base/file.h"
+#define __PRIVATE_NSLOCK
+#include "nslock.h"
+#include <assert.h>
+
+char * NSLock_Program = "NSLOCK";
+
+#ifdef FILE_UNIX
+/*
+ * The process-wide list of locks, NSLock_List, is protected by the
+ * critical section, NSLock_Crit.
+ */
+CRITICAL NSLock_Crit = 0;
+NSLock_t * NSLock_List = 0;
+#endif /* FILE_UNIX */
+
+/*
+ * Description (nsLockOpen)
+ *
+ * This function is used to initialize a handle for a lock. The
+ * caller specifies a unique name for the lock, and a handle is
+ * returned. The returned handle should be used by only one
+ * thread at a time, i.e. if multiple threads in a process are
+ * using the same lock, they should either have their own handles
+ * or protect a single handle with a critical section.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * lockname - pointer to name of lock
+ * plock - pointer to returned handle for lock
+ *
+ * Returns:
+ *
+ * If successful, a handle for the specified lock is returned via
+ * 'plock', and the return value is zero. Otherwise the return
+ * value is a negative error code (see nslock.h), and an error
+ * frame is generated if an error frame list was provided.
+ */
+
+NSAPI_PUBLIC int nsLockOpen(NSErr_t * errp, char * lockname, void **plock)
+{
+ NSLock_t * nl = 0; /* pointer to lock structure */
+ int len; /* length of lockname */
+ int eid;
+ int rv;
+
+#ifdef FILE_UNIX
+ /* Have we created the critical section for NSLock_List yet? */
+ if (NSLock_Crit == 0) {
+
+ /* Narrow the window for simultaneous initialization */
+ NSLock_Crit = (CRITICAL)(-1);
+
+ /* Create it */
+ NSLock_Crit = crit_init();
+ }
+
+ /* Lock the list of locks */
+ crit_enter(NSLock_Crit);
+
+ /* See if a lock with the specified name exists already */
+ for (nl = NSLock_List; nl != 0; nl = nl->nl_next) {
+ if (!strcmp(nl->nl_name, lockname)) break;
+ }
+
+ /* Create a new lock if we didn't find it */
+ if (nl == 0) {
+
+ len = strlen(lockname);
+
+ nl = (NSLock_t *)PERM_MALLOC(sizeof(NSLock_t) + len + 5);
+ if (nl == 0) goto err_nomem;
+
+ nl->nl_name = (char *)(nl + 1);
+ strcpy(nl->nl_name, lockname);
+ strcpy(&nl->nl_name[len], ".lck");
+ nl->nl_cnt = 0;
+
+ nl->nl_fd = open(nl->nl_name, O_RDWR|O_CREAT|O_EXCL, 0644);
+ if (nl->nl_fd < 0) {
+
+ if (errno != EEXIST) {
+ crit_exit(NSLock_Crit);
+ goto err_create;
+ }
+
+ /* O_RDWR or O_WRONLY is required to use lockf on Solaris */
+ nl->nl_fd = open(nl->nl_name, O_RDWR, 0);
+ if (nl->nl_fd < 0) {
+ crit_exit(NSLock_Crit);
+ goto err_open;
+ }
+ }
+
+ /* Remove ".lck" from the lock name */
+ nl->nl_name[len] = 0;
+
+ /* Create a critical section for this lock (gag!) */
+ nl->nl_crit = crit_init();
+
+ /* Add this lock to NSLock_List */
+ nl->nl_next = NSLock_List;
+ NSLock_List = nl;
+ }
+
+ crit_exit(NSLock_Crit);
+
+#else
+/* write me */
+ nl = (void *)4;
+#endif /* FILE_UNIX */
+
+ *plock = (void *)nl;
+ return 0;
+
+ err_nomem:
+ eid = NSLERR1000;
+ rv = NSLERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSLock_Program, 0);
+ goto punt;
+
+ err_create:
+ eid = NSLERR1020;
+ rv = NSLERRCREATE;
+ goto err_file;
+
+ err_open:
+ eid = NSLERR1040;
+ rv = NSLERROPEN;
+ err_file:
+ nserrGenerate(errp, rv, eid, NSLock_Program, 1, nl->nl_name);
+ punt:
+ if (nl) {
+ FREE(nl);
+ }
+ *plock = 0;
+ return rv;
+}
+
+/*
+ * Description (nsLockAcquire)
+ *
+ * This function is used to acquire exclusive ownership of a lock
+ * previously accessed via nsLockOpen(). The calling thread will
+ * be blocked until the lock is acquired. Other threads in the
+ * process should not be blocked.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * lock - handle for lock from nsLockOpen()
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise the return
+ * value is a negative error code (see nslock.h), and an error
+ * frame is generated if an error frame list was provided.
+ */
+
+NSAPI_PUBLIC int nsLockAcquire(NSErr_t * errp, void * lock)
+{
+ NSLock_t * nl = (NSLock_t *)lock;
+ int eid;
+ int rv;
+
+#ifdef FILE_UNIX
+ /* Enter the critical section for the lock */
+ crit_enter(nl->nl_crit);
+
+ /* Acquire the file lock if we haven't already */
+ if (nl->nl_cnt == 0) {
+ rv = system_flock(nl->nl_fd);
+ if (rv) {
+ crit_exit(nl->nl_crit);
+ goto err_lock;
+ }
+ }
+
+ /* Bump the lock count */
+ nl->nl_cnt++;
+
+ crit_exit(nl->nl_crit);
+#else
+ /* write me */
+#endif /* FILE_UNIX */
+
+ /* Indicate success */
+ return 0;
+
+ err_lock:
+ eid = NSLERR1100;
+ rv = NSLERRLOCK;
+ nserrGenerate(errp, rv, eid, NSLock_Program, 1, nl->nl_name);
+
+ return rv;
+}
+
+/*
+ * Description (nsLockRelease)
+ *
+ * This function is used to release exclusive ownership to a lock
+ * that was previously obtained via nsLockAcquire().
+ *
+ * Arguments:
+ *
+ * lock - handle for lock from nsLockOpen()
+ */
+
+NSAPI_PUBLIC void nsLockRelease(void * lock)
+{
+ NSLock_t * nl = (NSLock_t *)lock;
+
+#ifdef FILE_UNIX
+ assert(nl->nl_cnt > 0);
+
+ crit_enter(nl->nl_crit);
+
+ if (--nl->nl_cnt <= 0) {
+ system_ulock(nl->nl_fd);
+ nl->nl_cnt = 0;
+ }
+
+ crit_exit(nl->nl_crit);
+#endif /* FILE_UNIX */
+}
+
+/*
+ * Description (nsLockClose)
+ *
+ * This function is used to close a lock handle that was previously
+ * acquired via nsLockOpen(). The lock should not be owned.
+ *
+ * Arguments:
+ *
+ * lock - handle for lock from nsLockOpen()
+ */
+
+NSAPI_PUBLIC void nsLockClose(void * lock)
+{
+ NSLock_t * nl = (NSLock_t *)lock;
+
+#ifdef FILE_UNIX
+ /* Don't do anything with the lock, since it will get used again */
+#if 0
+ crit_enter(nl->nl_crit);
+ close(nl->nl_fd);
+ crit_exit(nl->nl_crit);
+ FREE(nl);
+#endif
+#else
+ /* write me */
+#endif FILE_UNIX
+}
diff --git a/lib/libaccess/nsumgmt.cpp b/lib/libaccess/nsumgmt.cpp
new file mode 100644
index 00000000..3db677f0
--- /dev/null
+++ b/lib/libaccess/nsumgmt.cpp
@@ -0,0 +1,456 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsumgmt.c)
+ *
+ * This module contains routines for managing information in a
+ * Netscape user database. Information for a particular user
+ * is modified by retrieving the current information in the form
+ * of a user object (UserObj_t), calling functions in this module,
+ * to modify the user object, and then calling userStore() to
+ * write the information in the user object back to the database.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#include "libaccess/nsdbmgmt.h"
+#define __PRIVATE_NSUSER
+#include "libaccess/nsumgmt.h"
+
+/*
+ * Description (userAddGroup)
+ *
+ * This function adds a group id to the list of group ids associated
+ * with a user object.
+ *
+ * Arguments:
+ *
+ * uoptr - user object pointer
+ * gid - group id to be added
+ *
+ * Returns:
+ *
+ * Returns zero if the group id is already present in the group id list.
+ * Returns one if the group id was added successfully.
+ * Returns a negative value if an error occurs.
+ */
+
+int userAddGroup(UserObj_t * uoptr, USI_t gid)
+{
+ int rv;
+
+ rv = usiInsert(&uoptr->uo_groups, gid);
+
+ if (rv > 0) {
+
+ uoptr->uo_flags |= UOF_MODIFIED;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (userCreate)
+ *
+ * This function creates a user object, using information about
+ * the user provided by the caller. The strings passed for the
+ * user account name, password, and real user name may be on the
+ * stack. The user id is set to zero, but the user object is
+ * marked as being new. A user id will be assigned when
+ * userStore() is called to add the user to a user database.
+ *
+ * Arguments:
+ *
+ * name - pointer to user account name string
+ * pwd - pointer to (encrypted) password string
+ * rname - real user name (gecos string)
+ *
+ * Returns:
+ *
+ * A pointer to a dynamically allocated UserObj_t structure is
+ * returned.
+ */
+
+NSAPI_PUBLIC UserObj_t * userCreate(NTS_t name, NTS_t pwd, NTS_t rname)
+{
+ UserObj_t * uoptr; /* user object pointer */
+
+ uoptr = (UserObj_t *)MALLOC(sizeof(UserObj_t));
+ if (uoptr) {
+ uoptr->uo_name = (NTS_t)STRDUP((char *)name);
+ uoptr->uo_pwd = (pwd) ? (NTS_t)STRDUP((char *)pwd) : 0;
+ uoptr->uo_uid = 0;
+ uoptr->uo_flags = (UOF_MODIFIED | UOF_NEW);
+ uoptr->uo_rname = (rname) ? (NTS_t)STRDUP((char *)rname) : 0;
+ UILINIT(&uoptr->uo_groups);
+ }
+
+ return uoptr;
+}
+
+/*
+ * Description (userDeleteGroup)
+ *
+ * This function removes a specified group id from a user object's
+ * list of groups.
+ *
+ * Arguments:
+ *
+ * uoptr - pointer to user object
+ * gid - group id to remove
+ *
+ * Returns:
+ *
+ * The return value is zero if the specified group id was not present
+ * in the user object, or one if the group was successfully removed.
+ */
+
+int userDeleteGroup(UserObj_t * uoptr, USI_t gid)
+{
+ int rv; /* return value */
+
+ rv = usiRemove(&uoptr->uo_groups, gid);
+ if (rv > 0) {
+ uoptr->uo_flags |= UOF_MODIFIED;
+ }
+
+ return rv;
+}
+
+/*
+ * Description (userEncode)
+ *
+ * This function encodes a user object into a user DB record.
+ *
+ * Arguments:
+ *
+ * uoptr - pointer to user object
+ * ureclen - pointer to returned record length
+ * urecptr - pointer to returned record pointer
+ *
+ * Returns:
+ *
+ * The function return value is zero if successful. The length
+ * and location of the created attribute record are returned
+ * through 'ureclen' and 'urecptr'. A non-zero function value
+ * is returned if there's an error.
+ */
+
+int userEncode(UserObj_t * uoptr, int * ureclen, ATR_t * urecptr)
+{
+ int reclen; /* length of DB record */
+ ATR_t rptr; /* DB record pointer */
+ ATR_t rstart = 0; /* pointer to beginning of DB record */
+ ATR_t glptr; /* saved pointer to UAT_GROUPS length */
+ ATR_t gptr; /* saved pointer to after length at glptr */
+ int pwdlen; /* password encoding length */
+ int uidlen; /* uid encoding length */
+ int fllen; /* account flags encoding length */
+ USI_t rnlen; /* real name encoding length */
+ USI_t nglen; /* group count encoding length */
+ USI_t gcnt; /* number of group ids */
+ USI_t * gids; /* pointer to array of group ids */
+ int i; /* group id index */
+ int rv = -1;
+
+ /*
+ * First we need to figure out how long the generated record will be.
+ * This doesn't have to be exact, but it must not be smaller than the
+ * actual record size.
+ */
+
+ /* UAT_PASSWORD attribute: tag, length, NTS */
+ pwdlen = NTSLENGTH(uoptr->uo_pwd);
+ reclen = 1 + 1 + pwdlen;
+ if (pwdlen > 127) goto punt;
+
+ /* UAT_UID attribute: tag, length, USI */
+ uidlen = USILENGTH(uoptr->uo_uid);
+ reclen += (1 + 1 + uidlen);
+
+ /* UAT_ACCFLAGS attribute: tag, length, USI */
+ fllen = USILENGTH(uoptr->uo_flags & UOF_DBFLAGS);
+ reclen += (1 + 1 + fllen);
+
+ /* UAT_REALNAME attribute: tag, length, NTS */
+ rnlen = NTSLENGTH(uoptr->uo_rname);
+ reclen += (1 + USILENGTH(rnlen) + rnlen);
+
+ /* UAT_GROUPS attribute: tag, length, USI(count), USI(gid)... */
+ gcnt = UILCOUNT(&uoptr->uo_groups);
+ nglen = USILENGTH(gcnt);
+ reclen += (1 + USIALLOC() + nglen + (5 * gcnt));
+
+ /* Allocate the attribute record buffer */
+ rptr = (ATR_t)MALLOC(reclen);
+ if (rptr) {
+
+ /* Save pointer to start of record */
+ rstart = rptr;
+
+ /* Encode UAT_PASSWORD attribute */
+ *rptr++ = UAT_PASSWORD;
+ *rptr++ = pwdlen;
+ rptr = NTSENCODE(rptr, uoptr->uo_pwd);
+
+ /* Encode UAT_UID attribute */
+ *rptr++ = UAT_UID;
+ *rptr++ = uidlen;
+ rptr = USIENCODE(rptr, uoptr->uo_uid);
+
+ /* Encode UAT_ACCFLAGS attribute */
+ *rptr++ = UAT_ACCFLAGS;
+ *rptr++ = fllen;
+ rptr = USIENCODE(rptr, (uoptr->uo_flags & UOF_DBFLAGS));
+
+ /* Encode UAT_REALNAME attribute */
+ *rptr++ = UAT_REALNAME;
+ rptr = USIENCODE(rptr, rnlen);
+ rptr = NTSENCODE(rptr, uoptr->uo_rname);
+
+ /* Encode UAT_GROUPS attribute */
+ *rptr++ = UAT_GROUPS;
+
+ /*
+ * Save a pointer to the attribute encoding length, and reserve
+ * space for the maximum encoding size of a USI_t value.
+ */
+ glptr = rptr;
+ rptr += USIALLOC();
+ gptr = rptr;
+
+ /* Encode number of groups */
+ rptr = USIENCODE(rptr, gcnt);
+
+ /* Generate group ids encodings */
+ gids = UILLIST(&uoptr->uo_groups);
+ for (i = 0; i < gcnt; ++i) {
+ rptr = USIENCODE(rptr, gids[i]);
+ }
+
+ /* Now fix up the UAT_GROUPS attribute encoding length */
+ glptr = USIINSERT(glptr, (USI_t)(rptr - gptr));
+
+ /* Return record length and location if requested */
+ if (ureclen) *ureclen = rptr - rstart;
+ if (urecptr) *urecptr = rstart;
+
+ /* Indicate success */
+ rv = 0;
+ }
+
+ punt:
+ return rv;
+}
+
+/*
+ * Description (userRemove)
+ *
+ * This function is called to remove a user from a specified user
+ * database. Both the primary DB file and the id-to-name DB file
+ * are updated.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * flags - (unused - must be zero)
+ * name - pointer to user account name
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code.
+ */
+
+NSAPI_PUBLIC int userRemove(NSErr_t * errp, void * userdb, int flags, NTS_t name)
+{
+ UserObj_t * uoptr; /* user object pointer */
+ int rv;
+ int rv2;
+
+ /* First retrieve the user record */
+ uoptr = userFindByName(errp, userdb, name);
+ if (!uoptr) {
+ /* Error - specified user not found */
+ return NSAERRNAME;
+ }
+
+ /* Free the user id value, if any */
+ rv = 0;
+ if (uoptr->uo_uid != 0) {
+ rv = ndbFreeId(errp, userdb, 0, (char *)name, uoptr->uo_uid);
+ }
+
+ rv2 = ndbDeleteName(errp, userdb, 0, 0, (char *)name);
+
+ return (rv) ? rv : rv2;
+}
+
+/*
+ * Description (userRename)
+ *
+ * This function is called to change the account name associated
+ * with an existing user. The caller provides a pointer to a
+ * user object for the existing user (with the current user account
+ * name referenced by uo_name), and the new account name for this
+ * user. A check is made to ensure the uniqueness of the new name
+ * in the specified user database. The account name in the user
+ * object is modified. The user database is not modified until
+ * userStore() is called.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * uoptr - user object pointer
+ * newname - pointer to new account name string
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code. The user object remains intact in either
+ * case.
+ */
+
+NSAPI_PUBLIC int userRename(NSErr_t * errp, void * userdb, UserObj_t * uoptr, NTS_t newname)
+{
+ int reclen; /* user record length */
+ ATR_t recptr = 0; /* user record pointer */
+ char * oldname; /* old user account name */
+ int eid; /* error id code */
+ int rv; /* result value */
+
+ /* Save the current account name and replace it with the new one */
+ oldname = (char *)uoptr->uo_name;
+ uoptr->uo_name = (unsigned char *) STRDUP((char *)newname);
+
+ if ((oldname != 0) && !(uoptr->uo_flags & UOF_NEW)) {
+
+ /* Convert the information in the user object to a DB record */
+ rv = userEncode(uoptr, &reclen, &recptr);
+ if (rv) goto err_nomem;
+
+ /*
+ * Store the record in the database
+ * under the new user account name.
+ */
+ rv = ndbStoreName(errp, userdb, NDBF_NEWNAME,
+ 0, (char *)uoptr->uo_name, reclen, (char *)recptr);
+ if (rv) goto punt;
+
+ /* Change the mapping of the user id to the new name */
+ rv = ndbRenameId(errp, userdb, 0, (char *)uoptr->uo_name, uoptr->uo_uid);
+ if (rv) goto punt;
+
+ /* Delete the user record with the old account name */
+ rv = ndbDeleteName(errp, userdb, 0, 0, oldname);
+ if (rv) goto punt;
+ }
+ else {
+ /* Set flags in user object for userStore() */
+ uoptr->uo_flags |= UOF_MODIFIED;
+ }
+
+ punt:
+ if (recptr) {
+ FREE(recptr);
+ }
+ if (oldname) {
+ FREE(oldname);
+ }
+ return rv;
+
+ err_nomem:
+ eid = NSAUERR1000;
+ rv = NSAERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+ goto punt;
+}
+
+/*
+ * Description (userStore)
+ *
+ * This function is called to store a user object in the database.
+ * If the object was created by userCreate(), it is assumed to be
+ * a new user account, the user account name must not match any
+ * existing user account names in the database, and a uid is
+ * assigned before adding the user to the database. If the object
+ * was created by userFindByName(), the information in the user
+ * object will replace the existing database entry for the
+ * indicated user account name.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * flags - (unused - must be zero)
+ * uoptr - user object pointer
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code. The user object remains intact in either
+ * case.
+ */
+
+NSAPI_PUBLIC int userStore(NSErr_t * errp, void * userdb, int flags, UserObj_t * uoptr)
+{
+ ATR_t recptr = 0;
+ USI_t uid;
+ int reclen = 0;
+ int stflags = 0;
+ int eid;
+ int rv;
+
+ /* If this is a new user, allocate a uid value */
+ if (uoptr->uo_flags & UOF_NEW) {
+ /*
+ * Yes, allocate a user id and add a user id to user
+ * account name mapping to the id-to-name DB file.
+ */
+ uid = 0;
+ rv = ndbAllocId(errp, userdb, 0, (char *)uoptr->uo_name, &uid);
+ if (rv) goto punt;
+
+ uoptr->uo_uid = uid;
+
+ /* Let the database manager know that this is a new entry */
+ stflags = NDBF_NEWNAME;
+ }
+
+ /* Convert the information in the user object to a DB record */
+ rv = userEncode(uoptr, &reclen, &recptr);
+ if (rv) goto err_nomem;
+
+ /* Store the record in the database under the user account name. */
+ rv = ndbStoreName(errp, userdb, stflags,
+ 0, (char *)uoptr->uo_name, reclen, (char *)recptr);
+ if (rv) goto punt;
+
+ FREE(recptr);
+ recptr = 0;
+
+ uoptr->uo_flags &= ~(UOF_NEW | UOF_MODIFIED);
+ return 0;
+
+ err_nomem:
+ eid = NSAUERR1100;
+ rv = NSAERRNOMEM;
+ nserrGenerate(errp, rv, eid, NSAuth_Program, 0);
+
+ punt:
+ if (recptr) {
+ FREE(recptr);
+ }
+ if ((uoptr->uo_flags & UOF_NEW) && (uid != 0)) {
+ /* Free the user id value if we failed after allocating it */
+ ndbFreeId(errp, userdb, 0, (char *)uoptr->uo_name, uid);
+ }
+ return rv;
+}
diff --git a/lib/libaccess/nsuser.cpp b/lib/libaccess/nsuser.cpp
new file mode 100644
index 00000000..158235a5
--- /dev/null
+++ b/lib/libaccess/nsuser.cpp
@@ -0,0 +1,309 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (nsuser.c)
+ *
+ * This module contains routines for accessing information in a
+ * Netscape user database. User information is returned in the
+ * form of a user object (UserObj_t), defined in nsauth.h.
+ */
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#define __PRIVATE_NSUSER
+#include "libaccess/nsuser.h"
+
+/* Authentication facility name for error frame generation */
+char * NSAuth_Program = "NSAUTH";
+
+/*
+ * Description (userDecode)
+ *
+ * This function decodes an external user DB record into a dynamically
+ * allocated UserObj_t structure. The DB record is encoded as an
+ * attribute record as defined in attrec.h.
+ *
+ * Arguments:
+ *
+ * name - pointer to user account name string
+ * ureclen - length of the user DB record, in octets
+ * urecptr - pointer to user DB record
+ *
+ * Returns:
+ *
+ * A pointer to the allocated UserObj_t structure is returned.
+ */
+
+UserObj_t * userDecode(NTS_t name, int ureclen, ATR_t urecptr)
+{
+ ATR_t cp = urecptr; /* current pointer into DB record */
+ USI_t tag; /* attribute tag */
+ USI_t len; /* attribute value encoding length */
+ USI_t gcnt; /* number of group ids */
+ USI_t * gids; /* pointer to array of group ids */
+ int i; /* group id index */
+ UserObj_t * uoptr; /* user object pointer */
+
+ /* Allocate a user object structure */
+ uoptr = (UserObj_t *)MALLOC(sizeof(UserObj_t));
+ if (uoptr) {
+
+ uoptr->uo_name = (unsigned char *) STRDUP((char *)name);
+ uoptr->uo_pwd = 0;
+ uoptr->uo_uid = 0;
+ uoptr->uo_flags = 0;
+ uoptr->uo_rname = 0;
+ UILINIT(&uoptr->uo_groups);
+
+ /* Parse user DB record */
+ while ((cp - urecptr) < ureclen) {
+
+ /* Get the attribute tag */
+ cp = USIDECODE(cp, &tag);
+
+ /* Get the length of the encoding of the attribute value */
+ cp = USIDECODE(cp, &len);
+
+ /* Process this attribute */
+ switch (tag) {
+
+ case UAT_PASSWORD: /* encrypted password */
+ cp = NTSDECODE(cp, &uoptr->uo_pwd);
+ break;
+
+ case UAT_UID: /* user id */
+ cp = USIDECODE(cp, &uoptr->uo_uid);
+ break;
+
+ case UAT_ACCFLAGS: /* account flags */
+ cp = USIDECODE(cp, &uoptr->uo_flags);
+ break;
+
+ case UAT_REALNAME: /* real name of user */
+ cp = NTSDECODE(cp, &uoptr->uo_rname);
+ break;
+
+ case UAT_GROUPS: /* groups which include user */
+
+ /* First get the number of group ids following */
+ cp = USIDECODE(cp, &gcnt);
+
+ if (gcnt > 0) {
+
+ /* Allocate space for group ids */
+ gids = usiAlloc(&uoptr->uo_groups, gcnt);
+ if (gids) {
+ for (i = 0; i < gcnt; ++i) {
+ cp = USIDECODE(cp, gids + i);
+ }
+ }
+ }
+ break;
+
+ default: /* unrecognized attribute */
+ /* Just skip it */
+ cp += len;
+ break;
+ }
+ }
+ }
+
+ return uoptr;
+}
+
+/*
+ * Description (userEnumHelp)
+ *
+ * This is a local function that is called by NSDB during user
+ * database enumeration. It decodes user records into user
+ * objects, and presents them to the caller of userEnumerate().
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * parg - pointer to UserEnumArgs_t structure
+ * namelen - user record key length including null
+ * terminator
+ * name - user record key (user account name)
+ * reclen - length of user record
+ * recptr - pointer to user record contents
+ *
+ * Returns:
+ *
+ * Returns whatever value is returned from the upcall to the caller
+ * of userEnumerate().
+ */
+
+static int userEnumHelp(NSErr_t * errp, void * parg,
+ int namelen, char * name, int reclen, char * recptr)
+{
+ UserEnumArgs_t * ue = (UserEnumArgs_t *)parg;
+ UserObj_t * uoptr; /* user object pointer */
+ int rv;
+
+ uoptr = userDecode((NTS_t)name, reclen, (ATR_t)recptr);
+
+ rv = (*ue->func)(errp, ue->user, uoptr);
+
+ if (!(ue->flags & UOF_ENUMKEEP)) {
+ userFree(uoptr);
+ }
+
+ return rv;
+}
+
+/*
+ * Description (userEnumerate)
+ *
+ * This function enumerates all of the users in a specified user
+ * database, calling a caller-specified function with a user object
+ * for each user in the database. A 'flags' value of UOF_ENUMKEEP
+ * can be specified to keep the user objects around (not free them)
+ * after the caller's function returns. Otherwise, each user
+ * object is freed after being presented to the caller's function.
+ * The 'argp' argument is an opaque pointer, which is passed to
+ * the caller's function as 'parg' on each call, along with a
+ * user object pointer.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * flags - bit flags:
+ * UOF_ENUMKEEP - keep user objects
+ * argp - passed to 'func' as 'parg'
+ * func - pointer to caller's enumeration function
+ *
+ * Returns:
+ *
+ * If successful, the return value is zero. Otherwise it is a
+ * non-zero error code, and an error frame is generated if an error
+ * frame list was provided by the caller.
+ */
+
+int userEnumerate(NSErr_t * errp, void * userdb, int flags, void * argp,
+ int (*func)(NSErr_t * ferrp, void * parg, UserObj_t * uoptr))
+{
+ int rv;
+ UserEnumArgs_t args;
+
+ args.userdb = userdb;
+ args.flags = flags;
+ args.func = func;
+ args.user = argp;
+
+ rv = ndbEnumerate(errp,
+ userdb, NDBF_ENUMNORM, (void *)&args, userEnumHelp);
+
+ return rv;
+}
+
+/*
+ * Description (userFindByName)
+ *
+ * This function looks up a user record for a specified user account
+ * name, converts the user record to the internal user object form,
+ * and returns a pointer to the user object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * name - user account name to find
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a user object
+ * for the specified user. Otherwise it is 0, and an error frame
+ * is generated if an error frame list was provided by the caller.
+ */
+
+UserObj_t * userFindByName(NSErr_t * errp, void * userdb, NTS_t name)
+{
+ UserObj_t * uoptr = 0;
+ ATR_t urecptr;
+ int ureclen;
+ int rv;
+
+ /* Look up the user name in the database */
+ rv = ndbFindName(errp, userdb, 0, (char *) name, &ureclen, (char **)&urecptr);
+ if (rv == 0) {
+
+ /* Got the user record. Decode into a user object. */
+ uoptr = userDecode(name, ureclen, urecptr);
+ }
+
+ return uoptr;
+}
+
+/*
+ * Description (userFindByUid)
+ *
+ * This function looks up a user record for a specified user id,
+ * converts the user record to the internal user object form, and
+ * returns a pointer to the user object.
+ *
+ * Arguments:
+ *
+ * errp - error frame list pointer (may be null)
+ * userdb - handle for user DB access
+ * uid - user id to find
+ *
+ * Returns:
+ *
+ * If successful, the return value is a pointer to a user object
+ * for the specified user. Otherwise it is 0, and an error frame
+ * is generated if an error frame list was provided by the caller.
+ */
+
+UserObj_t * userFindByUid(NSErr_t * errp, void * userdb, USI_t uid)
+{
+ UserObj_t * uoptr = 0;
+ NTS_t name;
+ ATR_t urecptr;
+ int ureclen;
+ int rv;
+
+ /* Get the user account name corresponding to the uid */
+ rv = ndbIdToName(errp, userdb, uid, 0, (char **)&name);
+ if (rv == 0) {
+
+ rv = ndbFindName(errp, userdb, 0, (char *)name, &ureclen, (char **)&urecptr);
+ if (rv == 0) {
+
+ /* Got the user record. Decode into a user object. */
+ uoptr = userDecode(name, ureclen, urecptr);
+ }
+ }
+
+ return uoptr;
+}
+
+/*
+ * Description (userFree)
+ *
+ * This function is called to free a user object. User objects
+ * are not automatically freed when a user database is closed.
+ *
+ * Arguments:
+ *
+ * uoptr - user object pointer
+ *
+ */
+
+NSAPI_PUBLIC void userFree(UserObj_t * uoptr)
+{
+ if (uoptr) {
+
+ if (uoptr->uo_name) FREE(uoptr->uo_name);
+ if (uoptr->uo_pwd) FREE(uoptr->uo_pwd);
+ if (uoptr->uo_rname) FREE(uoptr->uo_rname);
+ UILFREE(&uoptr->uo_groups);
+ FREE(uoptr);
+ }
+}
diff --git a/lib/libaccess/oneeval.cpp b/lib/libaccess/oneeval.cpp
new file mode 100644
index 00000000..be837599
--- /dev/null
+++ b/lib/libaccess/oneeval.cpp
@@ -0,0 +1,1054 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (acleval.c)
+ *
+ * This module provides functions for evaluating Access Control List
+ * (ACL) structures in memory.
+ *
+ */
+
+#include <string.h>
+#include <sys/types.h>
+#include <assert.h>
+
+#include <netsite.h>
+#include <base/systems.h>
+#include <base/crit.h>
+#include <base/session.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include <libaccess/symbols.h>
+#include <libaccess/aclerror.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+#include "access_plhash.h"
+#include "aclutil.h"
+#include "aclcache.h"
+#include "oneeval.h"
+#include "permhash.h"
+
+static int acl_default_result = ACL_RES_DENY;
+
+static ACLDispatchVector_t __nsacl_vector = {
+
+ /* Error frame stack support */
+
+ nserrDispose,
+ nserrFAlloc,
+ nserrFFree,
+ nserrGenerate,
+
+ /* Property list support */
+
+ PListAssignValue,
+ PListCreate,
+ PListDefProp,
+ PListDeleteProp,
+ PListFindValue,
+ PListInitProp,
+ PListNew,
+ PListDestroy,
+ PListGetValue,
+ PListNameProp,
+ PListSetType,
+ PListSetValue,
+ PListEnumerate,
+ PListDuplicate,
+ PListGetPool,
+
+ /* ACL attribute handling */
+
+ ACL_LasRegister,
+
+ /* method/dbtype registration routines */
+
+ ACL_MethodRegister,
+ ACL_MethodIsEqual,
+ ACL_MethodNameIsEqual,
+ ACL_MethodFind,
+ ACL_MethodGetDefault,
+ ACL_MethodSetDefault,
+ ACL_AuthInfoGetMethod,
+
+ ACL_DbTypeRegister,
+ ACL_DbTypeIsEqual,
+ ACL_DbTypeNameIsEqual,
+ ACL_DbTypeFind,
+ ACL_DbTypeGetDefault,
+ ACL_AuthInfoGetDbType,
+ ACL_DbTypeIsRegistered,
+ ACL_DbTypeParseFn,
+
+ ACL_AttrGetterRegister,
+
+ ACL_ModuleRegister,
+ ACL_GetAttribute,
+ ACL_DatabaseRegister,
+ ACL_DatabaseFind,
+ ACL_DatabaseSetDefault,
+ ACL_LDAPDatabaseHandle,
+ ACL_AuthInfoGetDbname,
+ ACL_CacheFlushRegister,
+ ACL_CacheFlush,
+
+ /* ACL language and file interfaces */
+
+ ACL_ParseFile,
+ ACL_ParseString,
+ ACL_WriteString,
+ ACL_WriteFile,
+ ACL_FileRenameAcl,
+ ACL_FileDeleteAcl,
+ ACL_FileGetAcl,
+ ACL_FileSetAcl,
+
+ /* ACL Expression construction interfaces */
+
+ ACL_ExprNew,
+ ACL_ExprDestroy,
+ ACL_ExprSetPFlags,
+ ACL_ExprClearPFlags,
+ ACL_ExprTerm,
+ ACL_ExprNot,
+ ACL_ExprAnd,
+ ACL_ExprOr,
+ ACL_ExprAddAuthInfo,
+ ACL_ExprAddArg,
+ ACL_ExprSetDenyWith,
+ ACL_ExprGetDenyWith,
+ ACL_ExprAppend,
+
+ /* ACL manipulation */
+
+ ACL_AclNew,
+ ACL_AclDestroy,
+
+ /* ACL list manipulation */
+
+ ACL_ListNew,
+ ACL_ListConcat,
+ ACL_ListAppend,
+ ACL_ListDestroy,
+ ACL_ListFind,
+ ACL_ListAclDelete,
+ ACL_ListGetNameList,
+ ACL_NameListDestroy,
+
+ /* ACL evaluation */
+
+ ACL_EvalTestRights,
+ ACL_EvalNew,
+ ACL_EvalDestroy,
+ ACL_EvalSetACL,
+ ACL_EvalGetSubject,
+ ACL_EvalSetSubject,
+ ACL_EvalGetResource,
+ ACL_EvalSetResource,
+
+ /* Access to critical section for ACL cache */
+
+ ACL_CritEnter,
+ ACL_CritExit,
+
+ /* Miscellaneous functions */
+
+ ACL_AclGetTag,
+ ACL_ListGetFirst,
+ ACL_ListGetNext,
+
+ /* Functions added after ES 3.0 release */
+ ACL_DatabaseGetDefault,
+ ACL_SetDefaultResult,
+ ACL_GetDefaultResult
+};
+
+NSAPI_PUBLIC ACLDispatchVector_t *__nsacl_table = &__nsacl_vector;
+
+int ACLEvalAce(
+ NSErr_t *errp,
+ ACLEvalHandle_t *acleval,
+ ACLExprHandle_t *ace,
+ ACLCachable_t *cachable,
+ PList_t autharray[],
+ PList_t global_auth
+ )
+{
+ ACLCachable_t local_cachable;
+ int result;
+ ACLExprEntry_t *expr;
+ int expr_index = 0;
+
+ expr = &ace->expr_arry[0];
+ *cachable = ACL_INDEF_CACHABLE;
+
+ while (TRUE)
+ {
+ local_cachable = ACL_NOT_CACHABLE;
+
+ /* Call the LAS driver */
+ if (!expr->las_eval_func) {
+ ACL_CritEnter();
+ if (!expr->las_eval_func) { /* Must check again after locking */
+ ACL_LasFindEval(errp, expr->attr_name, &expr->las_eval_func);
+ if (!expr->las_eval_func) { /* Couldn't find it */
+ ACL_CritExit();
+ return LAS_EVAL_INVALID;
+ }
+ }
+ ACL_CritExit();
+ }
+ result = (*expr->las_eval_func)(
+ errp,
+ expr->attr_name,
+ expr->comparator,
+ expr->attr_pattern,
+ &local_cachable,
+ &expr->las_cookie,
+ acleval->subject,
+ acleval->resource,
+ autharray ? autharray[expr_index] : NULL,
+ global_auth);
+
+ /* Evaluate the cachable value */
+ if (local_cachable < *cachable) {
+
+ /* Take the minimum value */
+ *cachable = local_cachable;
+ }
+
+ /* Evaluate the return code */
+ switch (result) {
+ case LAS_EVAL_TRUE:
+ if (expr->true_idx < 0)
+ return (expr->true_idx);
+ else {
+ expr_index = expr->true_idx;
+ expr = &ace->expr_arry[expr->true_idx];
+ }
+ break;
+
+ case LAS_EVAL_FALSE:
+ if (expr->false_idx < 0)
+ return (expr->false_idx);
+ else {
+ expr_index = expr->false_idx;
+ expr = &ace->expr_arry[expr->false_idx];
+ }
+ break;
+
+ default:
+ return (result);
+ }
+
+ }
+}
+
+
+int
+ACL_EvalDestroyContext(ACLListCache_t *cache)
+{
+ ACLAceEntry_t *cur_ace, *next_ace;
+ ACLAceNumEntry_t *cur_num_p, *next_num_p;
+ ACLExprHandle_t *acep;
+
+ if (!cache)
+ return 0;
+
+ PR_HashTableDestroy(cache->Table);
+ cache->Table = NULL;
+
+ cur_ace = cache->acelist;
+ cache->acelist = NULL;
+ while (cur_ace) {
+ if (cur_ace->autharray)
+ PERM_FREE(cur_ace->autharray);
+ if ((cur_ace->global_auth) &&
+ (cur_ace->acep->expr_type == ACL_EXPR_TYPE_AUTH))
+ PListDestroy(cur_ace->global_auth);
+ next_ace = cur_ace->next;
+ acep = cur_ace->acep; /* The ACE structure itself */
+ PERM_FREE(cur_ace);
+ cur_ace = next_ace;
+ }
+
+ cur_num_p = cache->chain_head;
+ cache->chain_head = NULL;
+ while (cur_num_p) {
+ next_num_p = cur_num_p->chain;
+ PERM_FREE(cur_num_p);
+ cur_num_p = next_num_p;
+ }
+
+ PERM_FREE(cache);
+
+ return 0;
+}
+
+
+/* ACLEvalBuildContext
+ * Builds three structures:
+ * Table - A hash table of all access rights referenced by any ACE in any
+ * of the ACLs in this list. Each hash entry then has a list of
+ * the relevant ACEs, in the form of indexes to the ACE linked
+ * list.
+ * ACE List - A linked list of all the ACEs in the proper evaluation order.
+ *
+ * For concurrency control, the caller must call ACL_CritEnter()
+ */
+int
+ACLEvalBuildContext(
+ NSErr_t *errp,
+ ACLEvalHandle_t *acleval)
+{
+ ACLHandle_t *acl;
+ ACLExprHandle_t *ace;
+ int ace_cnt = -1;
+ ACLAceEntry_t *acelast, *new_ace;
+ ACLAceNumEntry_t *entry, *temp_entry;
+ char **argp;
+ ACLListCache_t *cache;
+ ACLWrapper_t *wrapper;
+ PList_t curauthplist=NULL, absauthplist=NULL;
+ int i, rv;
+ ACLExprEntry_t *expr;
+ PList_t authplist;
+
+ /* Allocate the cache context and link it into the ACLListHandle */
+ cache = (ACLListCache_t *)PERM_CALLOC(sizeof(ACLListCache_t));
+ if (cache == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4010, ACL_Program, 0);
+ goto error;
+ }
+
+ /* Allocate the access rights hash table */
+ cache->Table = PR_NewHashTable(0,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+
+ if (cache->Table == NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4000, ACL_Program, 1,
+ XP_GetAdminStr(DBT_EvalBuildContextUnableToCreateHash));
+ goto error;
+ }
+
+ wrapper = acleval->acllist->acl_list_head;
+
+ /* Loop through all the ACLs in the list */
+ while (wrapper)
+ {
+ acl = wrapper->acl;
+ ace = acl->expr_list_head;
+
+ while (ace) /* Loop through all the ACEs in this ACL */
+ {
+
+ /* allocate a new ace list entry and link it in to the ordered
+ * list.
+ */
+ new_ace = (ACLAceEntry_t *)PERM_CALLOC(sizeof(ACLAceEntry_t));
+ if (new_ace == (ACLAceEntry_t *)NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4020, ACL_Program, 1,
+ XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAceEntry));
+ goto error;
+ }
+ new_ace->acep = ace;
+ ace_cnt++;
+
+ if (cache->acelist == NULL)
+ cache->acelist = acelast = new_ace;
+ else {
+ acelast->next = new_ace;
+ acelast = new_ace;
+ new_ace->acep = ace;
+ }
+ new_ace->next = NULL;
+
+ argp = ace->expr_argv;
+
+ switch (ace->expr_type)
+ {
+ case ACL_EXPR_TYPE_ALLOW:
+ case ACL_EXPR_TYPE_DENY:
+
+ /* Add this ACE to the appropriate entries in the access rights
+ * hash table
+ */
+ while (*argp)
+ {
+ entry =
+ (ACLAceNumEntry_t *)PERM_CALLOC(sizeof(ACLAceNumEntry_t));
+ if (entry == (ACLAceNumEntry_t *)NULL) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4030, ACL_Program, 1,
+ XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAceEntry));
+ goto error;
+ }
+ if (cache->chain_head == NULL)
+ cache->chain_head = cache->chain_tail = entry;
+ else {
+ cache->chain_tail->chain = entry;
+ cache->chain_tail = entry;
+ }
+ entry->acenum = ace_cnt;
+
+ /*
+ * OK to call PL_HasTableLookup() even though it mods
+ * the Table as this routine is called in critical section.
+ */
+ temp_entry = (ACLAceNumEntry_t *)PL_HashTableLookup(cache->Table, *argp);
+ /* the first ACE for this right? */
+ if (temp_entry) {
+ /* Link it in at the end */
+ while (temp_entry->next) {
+ temp_entry = temp_entry->next;
+ }
+ temp_entry->next = entry;
+ } else /* just link it in */
+ PR_HashTableAdd(cache->Table, *argp, entry);
+
+ argp++;
+
+ }
+
+ /* See if any of the clauses require authentication. */
+ if (curauthplist) {
+ for (i = 0; i < ace->expr_term_index; i++) {
+ expr = &ace->expr_arry[i];
+ rv = PListFindValue(curauthplist, expr->attr_name,
+ NULL, &authplist);
+ if (rv > 0) {
+ /* First one for this ACE? */
+ if (!new_ace->autharray) {
+ new_ace->autharray = (PList_t *)PERM_CALLOC(sizeof(PList_t *) * ace->expr_term_index);
+ if (!new_ace->autharray) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4040, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPointerArray));
+ goto error;
+ }
+ }
+ new_ace->autharray[i] = authplist;
+ }
+ }
+ }
+ break;
+
+ case ACL_EXPR_TYPE_AUTH:
+
+ /* Allocate the running auth tables if none yet */
+ if (!curauthplist) {
+ curauthplist = PListNew(NULL);
+ if (!curauthplist) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
+ goto error;
+ }
+ absauthplist = PListNew(NULL);
+ if (!absauthplist) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
+ goto error;
+ }
+ } else { /* duplicate the existing auth table */
+ curauthplist = PListDuplicate(curauthplist, NULL, 0);
+ if (!curauthplist) {
+ nserrGenerate(errp, ACLERRNOMEM, ACLERR4050, ACL_Program, 1, XP_GetAdminStr(DBT_EvalBuildContextUnableToAllocAuthPlist));
+ goto error;
+ }
+ }
+
+ /* For each listed attribute */
+ while (*argp)
+ {
+ /* skip any attributes that were absoluted */
+ if (PListFindValue(absauthplist, *argp, NULL, NULL) < 0)
+ {
+ /* Save pointer to the property list */
+ PListInitProp(curauthplist, NULL, *argp, ace->expr_auth,
+ ace->expr_auth);
+ if (IS_ABSOLUTE(ace->expr_flags))
+ PListInitProp(absauthplist, NULL, *argp, NULL,
+ NULL);
+ }
+
+ argp++;
+ }
+
+ break;
+
+ case ACL_EXPR_TYPE_RESPONSE:
+ (void) ACL_ExprGetDenyWith(NULL, ace, &cache->deny_type,
+ &cache->deny_response);
+ break;
+
+ default:
+ NS_ASSERT(0);
+
+ } /* switch expr_type */
+
+ new_ace->global_auth = curauthplist;
+ ace = ace->expr_next;
+ }
+
+ /* Next ACL please */
+ wrapper = wrapper->wrap_next;
+ }
+
+ if (absauthplist)
+ PListDestroy(absauthplist);
+
+ /* This must be done last to avoid a race in initialization */
+ acleval->acllist->cache = (void *)cache;
+
+ return 0;
+
+error:
+ if (absauthplist)
+ PListDestroy(absauthplist);
+ if (cache) {
+ ACL_EvalDestroyContext(cache);
+ }
+ acleval->acllist->cache = NULL;
+ return ACL_RES_ERROR;
+}
+
+/* ACL_InvalidateSubjectPList
+ * Given a new authentication plist, enumerate the plist and for each
+ * key in the plist, search for the matching key in the subject plist
+ * and delete any matches. E.g. "user", "group".
+ */
+void
+ACL_InvalidateSubjectPList(char *attr, const void *value, void *user_data)
+{
+ PList_t subject = (PList_t)user_data;
+
+ PListDeleteProp(subject, 0, attr);
+ return;
+}
+
+NSAPI_PUBLIC int ACL_SetDefaultResult (NSErr_t *errp,
+ ACLEvalHandle_t *acleval,
+ int result)
+{
+ int rv;
+
+ switch(result) {
+ case ACL_RES_ALLOW:
+ case ACL_RES_DENY:
+ case ACL_RES_FAIL:
+ case ACL_RES_INVALID:
+ acleval->default_result = result;
+ rv = 0;
+ break;
+ default:
+ rv = -1;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int ACL_GetDefaultResult (ACLEvalHandle_t *acleval)
+{
+ return acleval->default_result;
+}
+
+/* ACL_INTEvalTestRights
+ * INPUT
+ * *errp The usual error context stack
+ * *acleval A list of ACLs
+ * **rights An array of strings listing the requested rights
+ * **map_generic An array of strings listing the specific rights
+ * that map from the generic rights.
+ * OUTPUT
+ * **deny_type bong file type passed on the way back out
+ * **deny_response bong file pathname passed on the way back out
+ * **acl_tag Name of the ACL that denies access
+ * *expr_num ACE number within the denying ACL
+ * *cachable Is the result cachable?
+ */
+static int
+ACL_INTEvalTestRights(
+ NSErr_t *errp,
+ ACLEvalHandle_t *acleval,
+ char **rights,
+ char **map_generic,
+ char **deny_type,
+ char **deny_response,
+ char **acl_tag,
+ int *expr_num,
+ ACLCachable_t *cachable)
+{
+ struct rights_ent {
+ char right[64]; /* lowercase-ed rights string */
+ int result; /* Interim result value */
+ int absolute; /* ACE with absolute keyword */
+ int count; /* # specific + generic rights */
+ ACLAceNumEntry_t *acelist[ACL_MAX_GENERIC+1];
+ /* List of relevant ACEs */
+ };
+ struct rights_ent *rarray_p;
+ struct rights_ent rights_arry[ACL_MAX_TEST_RIGHTS];
+ ACLAceNumEntry_t *alllist; /* List of ACEs for "all" rights */
+ ACLAceEntry_t *cur_ace;
+ ACLListCache_t *cache;
+ int rights_cnt = 0;
+ int prev_acenum, cur_acenum;
+ int i, j, right_num, delta;
+ ACLCachable_t ace_cachable;
+ int result;
+ int absolute;
+ int skipflag;
+ int g_num; /* index into the generic rights array. */
+ char **g_rights;
+ PList_t global_auth=NULL;
+ int allow_error = 0;
+ int allow_absolute = 0;
+ char *allow_tag = NULL;
+ int allow_num = 0;
+ int default_result = ACL_GetDefaultResult(acleval);
+
+ *acl_tag = NULL;
+ *expr_num = 0;
+ *cachable = ACL_INDEF_CACHABLE;
+
+ /*
+ * The acleval contains the list of acis we are asking about.
+ * In our case it's always of length 1.
+ * The acleval is a per aclpb structure but
+ * the acllist is a global structure derived from the global
+ * aci cache--so access to acllist is multi-threaded.
+ * Hence, for example the use of the "read-only" hash
+ * lookup routines in this function--ACL_EvalTestRights()
+ * is called in a "reader only context" so this code is therefore
+ * thread-safe.
+ */
+
+ if (acleval->acllist == ACL_LIST_NO_ACLS) return ACL_RES_ALLOW;
+
+ /* Build up the access right - indexed structures */
+ if (acleval->acllist->cache == NULL) {
+ ACL_CritEnter();
+ if (acleval->acllist->cache == NULL) { /* Check again */
+ if (ACLEvalBuildContext(errp, acleval) == ACL_RES_ERROR) {
+ nserrGenerate(errp, ACLERRINTERNAL, ACLERR4110, ACL_Program,
+ 1, XP_GetAdminStr(DBT_EvalTestRightsEvalBuildContextFailed));
+ ACL_CritExit();
+ return ACL_RES_ERROR;
+ }
+ }
+ ACL_CritExit();
+ }
+ cache = (ACLListCache_t *)acleval->acllist->cache;
+ *deny_response = cache->deny_response;
+ *deny_type = cache->deny_type;
+
+ /* For the list of rights requested, get back the list of relevant
+ * ACEs. If we want
+ * to alter the precedence of allow/deny, this would be a good
+ * place to do it.
+ */
+
+ while (*rights)
+ {
+ rarray_p = &rights_arry[rights_cnt];
+
+ /* Initialize the rights array entry */
+ strcpy(&rarray_p->right[0], *rights);
+ makelower(&rarray_p->right[0]);
+ rarray_p->result = default_result;
+ rarray_p->absolute = 0;
+ rarray_p->count = 1; // There's always the specific right
+
+ /* Locate the list of ACEs that apply to the right */
+ rarray_p->acelist[0] =
+ (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table, rarray_p->right);
+
+ /* See if the requested right also maps back to a generic right and
+ * if so, locate the acelist for it as well.
+ */
+ if (map_generic)
+ {
+ for (g_rights=map_generic, g_num=0; *g_rights; g_rights++, g_num++)
+ {
+ if (strstr(*g_rights, rarray_p->right)) {
+ // Add it to our acelist, but skip 0 'cause that's the
+ // specific right.
+ rarray_p->acelist[rarray_p->count++] =
+ (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table,
+ (char *)generic_rights[g_num]);
+ NS_ASSERT (rarray_p->count < ACL_MAX_GENERIC);
+ }
+ }
+ }
+
+ rights_cnt++;
+ rights++;
+ NS_ASSERT (rights_cnt < ACL_MAX_TEST_RIGHTS);
+ }
+
+ /* Special case - look for an entry that applies to "all" rights */
+ alllist = (ACLAceNumEntry_t *)ACL_HashTableLookup_const(cache->Table, "all");
+
+ /* Ok, we've now got a list of relevant ACEs. Now evaluate things. */
+ prev_acenum = -1;
+ cur_ace = cache->acelist;
+
+ /* Loop through the relevant ACEs for the requested rights */
+ while (TRUE)
+ {
+ cur_acenum = 10000; /* Pick a really high num so we lose */
+ /* Find the lowest ACE among the rights lists */
+ for (i=0; i<rights_cnt; i++) {
+ rarray_p = &rights_arry[i];
+ if (rarray_p->absolute) continue; // This right doesn't matter
+ for (j=0; j<rarray_p->count; j++) {
+ if ((rarray_p->acelist[j] != NULL) &&
+ (rarray_p->acelist[j]->acenum < cur_acenum)) {
+ cur_acenum = rarray_p->acelist[j]->acenum;
+ }
+ }
+ }
+
+ /* Special case - look for the "all" rights ace list and see if its
+ * the lowest of all.
+ */
+ if (alllist && (alllist->acenum < cur_acenum))
+ cur_acenum = alllist->acenum;
+
+ /* If no new ACEs then we're done - evaluate the rights list */
+ if (cur_acenum == 10000)
+ break;
+
+ /* Locate that ACE and evaluate it. We have to step through the
+ * linked list of ACEs to find it.
+ */
+ if (prev_acenum == -1)
+ delta = cur_acenum;
+ else
+ delta = cur_acenum - prev_acenum;
+
+ for (i=0; i<delta; i++)
+ cur_ace = cur_ace->next;
+
+ if (global_auth && global_auth != cur_ace->global_auth) {
+ /* We must enumerate the auth_info plist and remove entries for
+ * each attribute from the subject property list.
+ */
+ PListEnumerate(cur_ace->global_auth, ACL_InvalidateSubjectPList,
+ acleval->subject);
+ }
+ global_auth = cur_ace->global_auth;
+
+ result = ACLEvalAce(errp, acleval, cur_ace->acep, &ace_cachable,
+ cur_ace->autharray, cur_ace->global_auth);
+
+ /* Evaluate the cachable value */
+ if (ace_cachable < *cachable) {
+ /* Take the minimum value */
+ *cachable = ace_cachable;
+ }
+
+ /* Under certain circumstances, no matter what happens later,
+ * the current result is not gonna change.
+ */
+ if ((result != LAS_EVAL_TRUE) && (result != LAS_EVAL_FALSE)) {
+ if (cur_ace->acep->expr_type != ACL_EXPR_TYPE_ALLOW) {
+ if (allow_error) {
+ *acl_tag = allow_tag;
+ *expr_num = allow_num;
+ return (allow_error);
+ } else {
+ *acl_tag = cur_ace->acep->acl_tag;
+ *expr_num = cur_ace->acep->expr_number;
+ return (EvalToRes(result));
+ }
+ } else {
+ /* If the error is on an allow statement, continue processing
+ * and see if a subsequent allow works. If not, remember the
+ * error and return it.
+ */
+ if (!allow_error) {
+ allow_error = EvalToRes(result);
+ allow_tag = cur_ace->acep->acl_tag;
+ allow_num = cur_ace->acep->expr_number;
+ }
+ if (IS_ABSOLUTE(cur_ace->acep->expr_flags)) {
+ allow_absolute = 1;
+ }
+ }
+ }
+
+ /* Now apply the result to the rights array. Look to see which rights'
+ * acelist include the current one, or if the current one is on the
+ * "all" rights ace list.
+ */
+ for (right_num=0; right_num<rights_cnt; right_num++)
+ {
+ rarray_p = &rights_arry[right_num];
+
+ /* Have we fixated on a prior result? */
+ if (rarray_p->absolute)
+ continue;
+
+ skipflag = 1;
+
+ // Did this ace apply to this right?
+ for (i=0; i<rarray_p->count; i++) {
+ if ((rarray_p->acelist[i]) &&
+ (rarray_p->acelist[i]->acenum == cur_acenum)) {
+ rarray_p->acelist[i] = rarray_p->acelist[i]->next;
+ skipflag = 0;
+ }
+ }
+
+ /* This ace was on the "all" rights queue */
+ if ((alllist) && (alllist->acenum == cur_acenum)) {
+ skipflag = 0;
+ }
+
+ if (skipflag)
+ continue; /* doesn't apply to this right */
+
+ if (IS_ABSOLUTE(cur_ace->acep->expr_flags) && (result ==
+ LAS_EVAL_TRUE)) {
+ rarray_p->absolute = 1;
+ absolute = 1;
+ } else
+ absolute = 0;
+
+ switch (cur_ace->acep->expr_type) {
+ case ACL_EXPR_TYPE_ALLOW:
+ if (result == LAS_EVAL_TRUE) {
+ rarray_p->result = ACL_RES_ALLOW;
+ if (!allow_absolute) {
+ /* A previous ALLOW error was superceded */
+ allow_error = 0;
+ }
+ }
+ else if (!*acl_tag) {
+ *acl_tag = cur_ace->acep->acl_tag;
+ *expr_num = cur_ace->acep->expr_number;
+ }
+ break;
+ case ACL_EXPR_TYPE_DENY:
+ if (result == LAS_EVAL_TRUE) {
+ *acl_tag = cur_ace->acep->acl_tag;
+ *expr_num = cur_ace->acep->expr_number;
+ if (absolute) {
+ if (allow_error) {
+ *acl_tag = allow_tag;
+ *expr_num = allow_num;
+ return (allow_error);
+ }
+ return (ACL_RES_DENY);
+ }
+ rarray_p->result = ACL_RES_DENY;
+ }
+ break;
+ default:
+ /* a non-authorization ACE, just ignore */
+ break;
+ }
+
+ }
+
+ /* This ace was on the "all" rights queue */
+ if ((alllist) && (alllist->acenum == cur_acenum)) {
+ alllist = alllist->next;
+ }
+
+ /* If this is an absolute, check to see if all the rights
+ * have already been fixed by this or previous absolute
+ * statements. If so, we can compute the response without
+ * evaluating any more of the ACL list.
+ */
+ if (absolute) {
+ for (i=0; i<rights_cnt; i++) {
+ /* Non absolute right, so skip this section */
+ if (rights_arry[i].absolute == 0)
+ break;
+ /* This shouldn't be possible, but check anyway.
+ * Any absolute non-allow result should already
+ * have been returned earlier.
+ */
+ if (rights_arry[i].result != ACL_RES_ALLOW) {
+ char result_str[16];
+ sprintf(result_str, "%d", rights_arry[i].result);
+ nserrGenerate(errp, ACLERRINTERNAL, ACLERR4100, ACL_Program, 3, XP_GetAdminStr(DBT_EvalTestRightsInterimAbsoluteNonAllowValue), rights[i], result_str);
+ break;
+ }
+ if (i == (rights_cnt - 1))
+ return ACL_RES_ALLOW;
+ }
+ }
+
+ prev_acenum = cur_acenum;
+
+ } /* Next ACE */
+
+ /* Do an AND on the results for the individual rights */
+ for (right_num=0; right_num<rights_cnt; right_num++)
+ if (rights_arry[right_num].result != ACL_RES_ALLOW) {
+ if (allow_error) {
+ *acl_tag = allow_tag;
+ *expr_num = allow_num;
+ return (allow_error);
+ }
+ return (rights_arry[right_num].result);
+ }
+
+ return (ACL_RES_ALLOW);
+
+}
+
+
+/* ACL_CachableAclList
+ * Returns 1 if the ACL list will always evaluate to ALLOW for http_get.
+ */
+NSAPI_PUBLIC int
+ACL_CachableAclList(ACLListHandle_t *acllist)
+{
+ ACLEvalHandle_t *acleval;
+ char *bong;
+ char *bong_type;
+ char *acl_tag;
+ int expr_num;
+ int rv;
+ static char *rights[] = { "http_get", NULL };
+ ACLCachable_t cachable=ACL_INDEF_CACHABLE;
+
+ if (!acllist || acllist == ACL_LIST_NO_ACLS) {
+ return 1;
+ }
+ acleval = ACL_EvalNew(NULL, NULL);
+ ACL_EvalSetACL(NULL, acleval, acllist);
+ rv = ACL_INTEvalTestRights(NULL, acleval, rights, http_generic,
+ &bong_type, &bong, &acl_tag, &expr_num,
+ &cachable);
+
+ ACL_EvalDestroyNoDecrement(NULL, NULL, acleval);
+ if (rv == ACL_RES_ALLOW && cachable == ACL_INDEF_CACHABLE) {
+ return 1;
+ }
+
+ return 0;
+}
+
+
+NSAPI_PUBLIC int
+ACL_EvalTestRights(
+ NSErr_t *errp,
+ ACLEvalHandle_t *acleval,
+ char **rights,
+ char **map_generic,
+ char **deny_type,
+ char **deny_response,
+ char **acl_tag,
+ int *expr_num)
+{
+ ACLCachable_t cachable;
+
+ return (ACL_INTEvalTestRights(errp, acleval, rights, map_generic,
+ deny_type, deny_response,
+ acl_tag, expr_num, &cachable));
+}
+
+
+NSAPI_PUBLIC ACLEvalHandle_t *
+ACL_EvalNew(NSErr_t *errp, pool_handle_t *pool)
+{
+ ACLEvalHandle_t *rv = ((ACLEvalHandle_t *)pool_calloc(pool, sizeof(ACLEvalHandle_t), 1));
+ rv->default_result = ACL_RES_DENY;
+ return rv;
+}
+
+NSAPI_PUBLIC void
+ACL_EvalDestroy(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval)
+{
+ if (!acleval->acllist || acleval->acllist == ACL_LIST_NO_ACLS)
+ return;
+ NS_ASSERT(acleval->acllist->ref_count > 0);
+
+ ACL_CritEnter();
+ NS_ASSERT(ACL_CritHeld());
+ if (--acleval->acllist->ref_count == 0) {
+ if (ACL_LIST_IS_STALE(acleval->acllist)) {
+ ACL_ListDestroy(errp, acleval->acllist);
+ }
+ }
+ ACL_CritExit();
+ pool_free(pool, acleval);
+}
+
+NSAPI_PUBLIC void
+ACL_EvalDestroyNoDecrement(NSErr_t *errp, pool_handle_t *pool, ACLEvalHandle_t *acleval)
+{
+ /*if (!acleval->acllist || acleval->acllist == ACL_LIST_NO_ACLS)
+ return; */
+
+ /* olga: we need to free acleval unconditionally to avoid memory leaks */
+ if (acleval)
+ pool_free(pool, acleval);
+}
+
+NSAPI_PUBLIC int
+ACL_ListDecrement(NSErr_t *errp, ACLListHandle_t *acllist)
+{
+ if (!acllist || acllist == ACL_LIST_NO_ACLS)
+ return 0;
+
+ NS_ASSERT(ACL_AssertAcllist(acllist));
+
+ ACL_CritEnter();
+ NS_ASSERT(ACL_CritHeld());
+ if (--acllist->ref_count == 0) {
+ if (ACL_LIST_IS_STALE(acllist)) {
+ ACL_ListDestroy(errp, acllist);
+ }
+ }
+ ACL_CritExit();
+
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_EvalSetACL(NSErr_t *errp, ACLEvalHandle_t *acleval, ACLListHandle_t *acllist)
+{
+ NS_ASSERT(ACL_AssertAcllist(acllist));
+
+ acleval->acllist = acllist;
+ return(0);
+}
+
+NSAPI_PUBLIC int
+ACL_EvalSetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t subject)
+{
+ acleval->subject = subject;
+ return 0;
+}
+
+NSAPI_PUBLIC PList_t
+ACL_EvalGetSubject(NSErr_t *errp, ACLEvalHandle_t *acleval)
+{
+ return (acleval->subject);
+}
+
+NSAPI_PUBLIC int
+ACL_EvalSetResource(NSErr_t *errp, ACLEvalHandle_t *acleval, PList_t resource)
+{
+ acleval->resource = resource;
+ return 0;
+}
+
+NSAPI_PUBLIC PList_t
+ACL_EvalGetResource(NSErr_t *errp, ACLEvalHandle_t *acleval)
+{
+ return (acleval->resource);
+}
diff --git a/lib/libaccess/oneeval.h b/lib/libaccess/oneeval.h
new file mode 100644
index 00000000..022570dd
--- /dev/null
+++ b/lib/libaccess/oneeval.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 LEVAL_H
+#define LEVAL_H
+
+NSPR_BEGIN_EXTERN_C
+
+int
+freeLAS(NSErr_t *errp, char *attribute, void **las_cookie);
+
+NSPR_END_EXTERN_C
+
+#endif
+
diff --git a/lib/libaccess/parse.h b/lib/libaccess/parse.h
new file mode 100644
index 00000000..420bd913
--- /dev/null
+++ b/lib/libaccess/parse.h
@@ -0,0 +1,21 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * module private routines for handling the yacc based
+ * ACL Parser.
+ */
+
+#ifndef PARSE_H
+#define PARSE_H
+
+NSPR_BEGIN_EXTERN_C
+
+extern int acl_PushListHandle(ACLListHandle_t *handle);
+extern int acl_Parse(void);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/permhash.h b/lib/libaccess/permhash.h
new file mode 100644
index 00000000..f072be2b
--- /dev/null
+++ b/lib/libaccess/permhash.h
@@ -0,0 +1,79 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef _PERMHASH_H_
+#define _PERMHASH_H_
+
+#include <string.h>
+#include <plhash.h>
+#include <base/pool.h>
+#include <base/util.h>
+
+static void *
+ACL_PermAllocTable(void *pool, PRSize size)
+{
+ return pool_malloc((pool_handle_t *)pool, size);
+}
+
+static void
+ACL_PermFreeTable(void *pool, void *item)
+{
+ pool_free((pool_handle_t *)pool, item);
+}
+
+static PLHashEntry *
+ACL_PermAllocEntry(void *pool, const void *unused)
+{
+ return ((PLHashEntry *)pool_malloc((pool_handle_t *)pool, sizeof(PLHashEntry)));
+}
+
+static void
+ACL_PermFreeEntry(void *pool, PLHashEntry *he, PRUintn flag)
+{
+ if (flag == HT_FREE_ENTRY)
+ pool_free((pool_handle_t *)pool, he);
+}
+
+static PLHashAllocOps ACLPermAllocOps = {
+ ACL_PermAllocTable,
+ ACL_PermFreeTable,
+ ACL_PermAllocEntry,
+ ACL_PermFreeEntry
+};
+
+static int
+PR_StringFree(PLHashEntry *he, int i, void *arg)
+{
+ PERM_FREE(he->key);
+ return 0;
+}
+
+static PLHashNumber
+PR_HashCaseString(const void *key)
+{
+ PLHashNumber h;
+ const unsigned char *s;
+
+ h = 0;
+ for (s = (const unsigned char *)key; *s; s++)
+ h = (h >> 28) ^ (h << 4) ^ tolower(*s);
+ return h;
+}
+
+static int
+PR_CompareCaseStrings(const void *v1, const void *v2)
+{
+ const char *s1 = (const char *)v1;
+ const char *s2 = (const char *)v2;
+
+#ifdef XP_WIN32
+ return (util_strcasecmp(s1, s2) == 0);
+#else
+ return (strcasecmp(s1, s2) == 0);
+#endif
+}
+
+
+#endif /* _PERMHASH_H */
diff --git a/lib/libaccess/register.cpp b/lib/libaccess/register.cpp
new file mode 100644
index 00000000..2973e1d5
--- /dev/null
+++ b/lib/libaccess/register.cpp
@@ -0,0 +1,821 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * LAS registration interface
+ */
+
+#include <netsite.h>
+#include <plhash.h>
+#include <base/systems.h>
+#include <base/util.h>
+#include <base/nsassert.h>
+#include "permhash.h"
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/aclglobal.h>
+#include <libaccess/ldapacl.h>
+#include "aclcache.h"
+#include <libaccess/dbtlibaccess.h>
+#include <libaccess/aclerror.h>
+
+/* This is to force aclspace.o into ns-httpd30.dll */
+static ACLGlobal_p *link_ACLGlobal = &ACLGlobal;
+
+/* This forces oneeval.o into ns-httpd30.dll */
+static ACLDispatchVector_t **link_nsacl_table = &__nsacl_table;
+
+ACLMethod_t ACLMethodDefault = ACL_METHOD_INVALID;
+ACLDbType_t ACLDbTypeDefault = ACL_DBTYPE_INVALID;
+static char *ACLDatabaseDefault = 0;
+
+ACLDbType_t ACL_DbTypeLdap = ACL_DBTYPE_INVALID;
+
+DbParseFn_t ACLDbParseFnTable[ACL_MAX_DBTYPE];
+
+void
+ACL_LasHashInit()
+{
+ int i;
+
+ ACLLasEvalHash = PR_NewHashTable(0,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLLasEvalHash);
+
+ ACLLasFlushHash = PR_NewHashTable(0,
+ PR_HashString,
+ PR_CompareStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLLasFlushHash);
+
+ ACLMethodHash = PR_NewHashTable(ACL_MAX_METHOD,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLMethodHash);
+
+ ACLDbTypeHash = PR_NewHashTable(ACL_MAX_DBTYPE,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLDbTypeHash);
+
+ for (i = 0; i < ACL_MAX_DBTYPE; i++)
+ ACLDbParseFnTable[i] = 0;
+
+ ACLAttrGetterHash = PR_NewHashTable(256,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLDbTypeHash);
+
+ ACLDbNameHash = PR_NewHashTable(0,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ ACL_DATABASE_POOL);
+ NS_ASSERT(ACLDbNameHash);
+
+ ACLUserLdbHash = PR_NewHashTable(0,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ NULL);
+ NS_ASSERT(ACLUserLdbHash);
+
+ return;
+}
+
+void
+ACL_LasHashDestroy()
+{
+ if (ACLLasEvalHash) {
+ PR_HashTableDestroy(ACLLasEvalHash);
+ ACLLasEvalHash=NULL;
+ }
+ if (ACLLasFlushHash) {
+ PR_HashTableDestroy(ACLLasFlushHash);
+ ACLLasFlushHash=NULL;
+ }
+}
+
+/* ACL_LasRegister
+ * INPUT
+ * errp NSError structure
+ * attr_name E.g. "ip" or "dns" etc.
+ * eval_func E.g. LASIpEval
+ * flush_func Optional - E.g. LASIpFlush or NULL
+ * OUTPUT
+ * 0 on success, non-zero on failure
+ */
+NSAPI_PUBLIC int
+ACL_LasRegister(NSErr_t *errp, char *attr_name, LASEvalFunc_t eval_func,
+LASFlushFunc_t flush_func)
+{
+
+ if ((!attr_name) || (!eval_func)) return -1;
+
+ ACL_CritEnter();
+
+ /* See if the function is already registered. If so, report and
+ * error, but go ahead and replace it.
+ */
+ if (PR_HashTableLookup(ACLLasEvalHash, attr_name) != NULL) {
+ nserrGenerate(errp, ACLERRDUPSYM, ACLERR3900, ACL_Program, 1,
+ attr_name);
+ }
+
+ /* Put it in the hash tables */
+ PR_HashTableAdd(ACLLasEvalHash, attr_name, (void *)eval_func);
+ PR_HashTableAdd(ACLLasFlushHash, attr_name, (void *)flush_func);
+
+ ACL_CritExit();
+ return 0;
+}
+
+/* ACL_LasFindEval
+ * INPUT
+ * errp NSError pointer
+ * attr_name E.g. "ip" or "user" etc.
+ * eval_funcp Where the function pointer is returned. NULL if the
+ * function isn't registered.
+ * Must be called in a critical section as ACLEvalHash is a global
+ * variable.
+ * OUTPUT
+ * 0 on success, non-zero on failure
+ */
+NSAPI_PUBLIC int
+ACL_LasFindEval(NSErr_t *errp, char *attr_name, LASEvalFunc_t *eval_funcp)
+{
+
+ NS_ASSERT(attr_name);
+ if (!attr_name) return -1;
+
+ *eval_funcp = (LASEvalFunc_t)PR_HashTableLookup(ACLLasEvalHash, attr_name);
+ return 0;
+}
+
+
+/* ACL_LasFindFlush
+ * INPUT
+ * errp NSError pointer
+ * attr_name E.g. "ip" or "user" etc.
+ * eval_funcp Where the function pointer is returned. NULL if the
+ * function isn't registered.
+ * OUTPUT
+ * 0 on success, non-zero on failure
+ */
+NSAPI_PUBLIC int
+ACL_LasFindFlush(NSErr_t *errp, char *attr_name, LASFlushFunc_t *flush_funcp)
+{
+
+ NS_ASSERT(attr_name);
+ if (!attr_name) return -1;
+
+ *flush_funcp = (LASFlushFunc_t)PR_HashTableLookup(ACLLasFlushHash, attr_name);
+ return 0;
+}
+
+
+/* ACL_MethodRegister
+ * INPUT
+ * name Method name string. Can be freed after return.
+ * OUTPUT
+ * &t Place to return the Method_t (>0)
+ * retcode 0 on success, non-zero otherwise
+ */
+
+int cur_method = 0; /* Use a static counter to generate the numbers */
+
+NSAPI_PUBLIC int
+ACL_MethodRegister(NSErr_t *errp, const char *name, ACLMethod_t *t)
+{
+ ACLMethod_t rv;
+
+ ACL_CritEnter();
+
+ /* See if this is already registered */
+ rv = (ACLMethod_t) PR_HashTableLookup(ACLMethodHash, name);
+ if (rv != NULL) {
+ *t = rv;
+ ACL_CritExit();
+ return 0;
+ }
+
+ /* To prevent the hash table from resizing, don't get to 32 entries */
+ if (cur_method >= (ACL_MAX_METHOD-1)) {
+ ACL_CritExit();
+ return -1;
+ }
+
+ /* Put it in the hash table */
+ rv = PR_HashTableAdd(ACLMethodHash, name, (void *)++cur_method);
+ *t = (ACLMethod_t) cur_method;
+
+ ACL_CritExit();
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_MethodFind(NSErr_t *errp, const char *name, ACLMethod_t *t)
+{
+ ACLMethod_t rv;
+
+ /* Don't have to get the Critical Section lock 'cause the only danger
+ * would be if the hash table had to be resized. We created it with
+ * room for 32 entries before that happens.
+ */
+ rv = (ACLMethod_t) PR_HashTableLookup(ACLMethodHash, name);
+ if (rv != NULL) {
+ *t = rv;
+ return 0;
+ }
+
+ return -1;
+}
+
+typedef struct HashEnumArg_s {
+ char **names;
+ int count;
+} HashEnumArg_t;
+
+typedef HashEnumArg_t *HashEnumArg_p;
+
+static int acl_hash_enumerator (PLHashEntry *he, PRIntn i, void *arg)
+{
+ HashEnumArg_t *info = (HashEnumArg_t *)arg;
+ char **names = info->names;
+
+ names[info->count++] = STRDUP((const char *)he->key);
+
+ return names[info->count-1] ? 0 : -1;
+}
+
+int acl_registered_names(PLHashTable *ht, int count, char ***names)
+{
+ HashEnumArg_t arg;
+ int rv;
+
+ if (count == 0) {
+ *names = 0;
+ return 0;
+ }
+
+ arg.names = (char **)MALLOC(count * sizeof(char *));
+ arg.count = 0;
+
+ if (!arg.names) return -1;
+
+ rv = PR_HashTableEnumerateEntries(ht, acl_hash_enumerator, &arg);
+
+ if (rv >= 0) {
+ /* success */
+ *names = arg.names;
+ }
+ else {
+ *names = 0;
+ }
+
+ return rv;
+}
+
+NSAPI_PUBLIC int
+ACL_MethodNamesGet(NSErr_t *errp, char ***names, int *count)
+{
+ *count = cur_method;
+ return acl_registered_names (ACLMethodHash, *count, names);
+}
+
+NSAPI_PUBLIC int
+ACL_MethodNamesFree(NSErr_t *errp, char **names, int count)
+{
+ int i;
+
+ if (!names) return 0;
+
+ for (i = count-1; i; i--) FREE(names[i]);
+
+ FREE(names);
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_DbTypeFind(NSErr_t *errp, const char *name, ACLDbType_t *t)
+{
+ ACLDbType_t rv;
+
+ /* Don't have to get the Critical Section lock 'cause the only danger
+ * would be if the hash table had to be resized. We created it with
+ * room for 32 entries before that happens.
+ */
+ rv = (ACLDbType_t) PR_HashTableLookup(ACLDbTypeHash, name);
+ if (rv != NULL) {
+ *t = rv;
+ return 0;
+ }
+
+ return -1;
+}
+
+/* ACL_DbTypeRegister
+ * INPUT
+ * name DbType name string. Can be freed after return.
+ * OUTPUT
+ * &t Place to return the DbType (>0)
+ * retcode 0 on success, non-zero otherwise
+ */
+
+int cur_dbtype = 0; /* Use a static counter to generate the numbers */
+
+NSAPI_PUBLIC int
+ACL_DbTypeRegister(NSErr_t *errp, const char *name, DbParseFn_t func, ACLDbType_t *t)
+{
+ ACLDbType_t rv;
+
+ ACL_CritEnter();
+
+ /* See if this is already registered */
+ rv = (ACLDbType_t) PR_HashTableLookup(ACLDbTypeHash, name);
+ if (rv != NULL) {
+ *t = rv;
+ ACLDbParseFnTable[(int)(PRSize)rv] = func;
+ ACL_CritExit();
+ return 0;
+ }
+
+ /* To prevent the hash table from resizing, don't get to 32 entries */
+ if (cur_dbtype >= (ACL_MAX_DBTYPE-1)) {
+ ACL_CritExit();
+ return -1;
+ }
+
+ /* Put it in the hash table */
+ rv = PR_HashTableAdd(ACLDbTypeHash, name, (void *)++cur_dbtype);
+ *t = (ACLDbType_t) cur_dbtype;
+ ACLDbParseFnTable[cur_dbtype] = func;
+
+ ACL_CritExit();
+ return 0;
+}
+
+
+NSAPI_PUBLIC int
+ACL_DbTypeIsRegistered (NSErr_t *errp, const ACLDbType_t t)
+{
+ return (0 < ((int)(PRSize)t) && ((int)(PRSize)t) <= cur_dbtype);
+}
+
+
+/* ACL_MethodIsEqual
+ * RETURNS non-zero if equal.
+ */
+NSAPI_PUBLIC int
+ACL_MethodIsEqual(NSErr_t *errp, const ACLMethod_t t1, const ACLMethod_t t2)
+{
+ return (t1 == t2);
+}
+
+
+/* ACL_DbTypeIsEqual
+ * RETURNS non-zero if equal.
+ */
+NSAPI_PUBLIC int
+ACL_DbTypeIsEqual(NSErr_t *errp, const ACLDbType_t t1, const ACLDbType_t t2)
+{
+ return (t1 == t2);
+}
+
+
+/* ACL_MethodNameIsEqual
+ * Takes a method type and a method name and sees if they match.
+ * Returns non-zero on match.
+ */
+NSAPI_PUBLIC int
+ACL_MethodNameIsEqual(NSErr_t *errp, const ACLMethod_t t1, const char *name)
+{
+ int rv;
+ ACLMethod_t t2;
+
+ rv = ACL_MethodFind(errp, name, &t2);
+ if (rv)
+ return (rv);
+ else
+ return (t1 == t2);
+}
+
+/* ACL_DbTypeNameIsEqual
+ * Takes a dbtype type and a dbtype name and sees if they match.
+ * Returns non-zero on match.
+ */
+NSAPI_PUBLIC int
+ACL_DbTypeNameIsEqual(NSErr_t *errp, const ACLDbType_t t1, const char *name)
+{
+ int rv;
+ ACLDbType_t t2;
+
+ rv = ACL_DbTypeFind(errp, name, &t2);
+ if (rv)
+ return (rv);
+ else
+ return (t1 == t2);
+}
+
+/* ACL_MethodGetDefault
+ */
+NSAPI_PUBLIC ACLMethod_t
+ACL_MethodGetDefault(NSErr_t *errp)
+{
+ return (ACLMethodDefault);
+}
+
+/* ACL_MethodSetDefault
+ */
+NSAPI_PUBLIC int
+ACL_MethodSetDefault(NSErr_t *errp, const ACLMethod_t t)
+{
+ ACLMethodDefault = t;
+ return 0;
+}
+
+
+/* ACL_DbTypeGetDefault
+ */
+NSAPI_PUBLIC ACLDbType_t
+ACL_DbTypeGetDefault(NSErr_t *errp)
+{
+ return (ACLDbTypeDefault);
+}
+
+/* ACL_DbTypeSetDefault
+ */
+NSAPI_PUBLIC int
+ACL_DbTypeSetDefault(NSErr_t *errp, ACLDbType_t t)
+{
+ ACLDbTypeDefault = t;
+ return 0;
+}
+
+
+/* ACL_DatabaseGetDefault
+ */
+NSAPI_PUBLIC const char *
+ACL_DatabaseGetDefault(NSErr_t *errp)
+{
+ return (ACLDatabaseDefault);
+}
+
+/* ACL_DatabaseSetDefault
+ */
+NSAPI_PUBLIC int
+ACL_DatabaseSetDefault(NSErr_t *errp, const char *dbname)
+{
+ ACLDbType_t dbtype;
+ int rv;
+ void *db;
+
+ if (!dbname || !*dbname) return LAS_EVAL_FAIL;
+
+ rv = ACL_DatabaseFind(errp, dbname, &dbtype, &db);
+
+ if (rv != LAS_EVAL_TRUE) return -1;
+
+ if (ACLDatabaseDefault) pool_free(ACL_DATABASE_POOL, ACLDatabaseDefault);
+
+ ACL_DbTypeSetDefault(errp, dbtype);
+ ACLDatabaseDefault = pool_strdup(ACL_DATABASE_POOL, dbname);
+
+ return ACLDatabaseDefault ? 0 : -1;
+}
+
+
+/* ACL_AuthInfoGetMethod
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * OUTPUT
+ * *t The Method number. This can be the default method
+ number if the auth_info PList doesn't explicitly have a Method entry.
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoGetMethod(NSErr_t *errp, PList_t auth_info, ACLMethod_t *t)
+{
+ ACLMethod_t *methodp;
+
+ if (!auth_info ||
+ PListGetValue(auth_info, ACL_ATTR_METHOD_INDEX, (void **)&methodp, NULL) < 0)
+ {
+ /* No entry for "method" */
+ *t = ACLMethodDefault;
+ } else {
+ *t = *methodp;
+ }
+
+ return 0;
+}
+
+
+/* ACL_AuthInfoSetMethod
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * t The Method number.
+ * OUTPUT
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoSetMethod(NSErr_t *errp, PList_t auth_info, ACLMethod_t t)
+{
+ ACLMethod_t *methodp;
+ int rv;
+
+ if (auth_info) {
+ rv = PListGetValue(auth_info, ACL_ATTR_METHOD_INDEX, (void **)&methodp,
+ NULL);
+
+ if (rv < 0) {
+ /* No entry for "method" */
+ methodp = (ACLMethod_t *)PERM_MALLOC(sizeof(ACLMethod_t));
+ if (!methodp) return -1;
+ *methodp = t;
+ PListInitProp(auth_info, ACL_ATTR_METHOD_INDEX, ACL_ATTR_METHOD, methodp, 0);
+ }
+ else {
+ /* replace the old entry */
+ if (!methodp) return -1;
+ *methodp = t;
+ }
+ }
+ else {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* ACL_AuthInfoSetDbname
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * dbname Name of the new auth_info database.
+ * OUTPUT
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoSetDbname(NSErr_t *errp, PList_t auth_info, const char *dbname)
+{
+ ACLDbType_t *dbtype = (ACLDbType_t *)PERM_MALLOC(sizeof(ACLDbType_t));
+ ACLDbType_t *t2;
+ char *copy;
+ char *n2;
+ void *db;
+ int old1;
+ int old2;
+ int rv;
+
+ if (!dbtype) {
+ /* out of memory */
+ return -1;
+ }
+
+ if (auth_info) {
+ rv = ACL_DatabaseFind(errp, dbname, dbtype, (void **)&db);
+
+ if (rv != LAS_EVAL_TRUE) {
+ PERM_FREE(dbtype);
+ return -1;
+ }
+
+ /* Check the existing entry */
+ old1 = PListGetValue(auth_info, ACL_ATTR_DBTYPE_INDEX, (void **)&t2,
+ NULL);
+ old2 = PListGetValue(auth_info, ACL_ATTR_DATABASE_INDEX, (void **)&n2,
+ NULL);
+
+ if (old1 >= 0 && old2 >= 0) {
+ /* check if the old entry is same */
+ if (ACL_DbTypeIsEqual(errp, *dbtype, *t2)) {
+ /* Nothing to do */
+ PERM_FREE(dbtype);
+ return 0;
+ }
+ }
+ /* free the old entries */
+ if (old1 >= 0) {
+ PListDeleteProp(auth_info, ACL_ATTR_DBTYPE_INDEX, ACL_ATTR_DBTYPE);
+ PERM_FREE(t2);
+ }
+ if (old2 >= 0) {
+ PListDeleteProp(auth_info, ACL_ATTR_DATABASE_INDEX, ACL_ATTR_DATABASE);
+ PERM_FREE(n2);
+ }
+
+ /* Create new entries for "dbtype" & "dbname" */
+ copy = (char *)PERM_STRDUP(dbname);
+ if (!copy) return -1;
+ PListInitProp(auth_info, ACL_ATTR_DATABASE_INDEX,
+ ACL_ATTR_DATABASE, copy, 0);
+ PListInitProp(auth_info, ACL_ATTR_DBTYPE_INDEX, ACL_ATTR_DBTYPE,
+ dbtype, 0);
+ }
+ else {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/* ACL_AuthInfoGetDbType
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * OUTPUT
+ * *t The DbType number. This can be the default dbtype
+ * number if the auth_info PList doesn't explicitly
+ * have a DbType entry.
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoGetDbType(NSErr_t *errp, PList_t auth_info, ACLDbType_t *t)
+{
+ ACLDbType_t *dbtypep;
+
+ if (!auth_info ||
+ PListGetValue(auth_info, ACL_ATTR_DBTYPE_INDEX, (void **)&dbtypep, NULL) < 0)
+ {
+ /* No entry for "dbtype" */
+ *t = ACLDbTypeDefault;
+ } else {
+ *t = *dbtypep;
+ }
+
+ return 0;
+}
+
+/* ACL_AuthInfoGetDbname
+ * INPUT
+ * auth_info A PList of the authentication name/value pairs as
+ * provided by EvalTestRights to the LAS.
+ * OUTPUT
+ * dbname The database name. This can be the default database
+ * name if the auth_info PList doesn't explicitly
+ * have a database entry.
+ * retcode 0 on success.
+ */
+NSAPI_PUBLIC int
+ACL_AuthInfoGetDbname(PList_t auth_info, char **dbname)
+{
+ char *dbstr;
+
+ if (!auth_info ||
+ PListGetValue(auth_info, ACL_ATTR_DATABASE_INDEX, (void **)&dbstr, NULL) < 0)
+ {
+ /* No entry for "database" */
+ dbstr = ACLDatabaseDefault;
+ }
+
+ /* else the value was already set by the PListGetValue call */
+ *dbname = dbstr;
+ return 0;
+}
+
+NSAPI_PUBLIC DbParseFn_t
+ACL_DbTypeParseFn(NSErr_t *errp, const ACLDbType_t dbtype)
+{
+ if (ACL_DbTypeIsRegistered(errp, dbtype))
+ return ACLDbParseFnTable[(int)(PRSize)dbtype];
+ else
+ return 0;
+}
+
+/* The hash table is keyed by attribute name, and contains pointers to the
+ * PRCList headers. These in turn, circularly link a set of AttrGetter_s
+ * structures.
+ */
+NSAPI_PUBLIC int
+ACL_AttrGetterRegister(NSErr_t *errp, const char *attr, ACLAttrGetterFn_t fn,
+ ACLMethod_t m, ACLDbType_t d, int position, void *arg)
+{
+ ACLAttrGetter_t *getter;
+ PLHashEntry **hep;
+
+ if (position != ACL_AT_FRONT && position != ACL_AT_END) {
+ return -1;
+ }
+
+ ACL_CritEnter();
+
+ hep = PR_HashTableRawLookup(ACLAttrGetterHash, PR_HashCaseString(attr), attr);
+
+ /* Now, allocate the current entry */
+ getter = (ACLAttrGetter_t *)CALLOC(sizeof(ACLAttrGetter_t));
+ if (getter == NULL) {
+ ACL_CritExit();
+ return -1;
+ }
+ getter->method = m;
+ getter->dbtype = d;
+ getter->fn = fn;
+ getter->arg = arg;
+
+ if (*hep == 0) { /* New entry */
+
+ PR_INIT_CLIST(&getter->list);
+ PR_HashTableAdd(ACLAttrGetterHash, attr, (void *)getter);
+ }
+ else {
+
+ ACLAttrGetter_t *head = (ACLAttrGetter_t *)((*hep)->value);
+
+ PR_INSERT_BEFORE(&getter->list, &head->list);
+
+ if (position == ACL_AT_FRONT) {
+
+ /* Set new head of list */
+ (*hep)->value = (void *)getter;
+ }
+ }
+
+ ACL_CritExit();
+ return 0;
+}
+
+NSAPI_PUBLIC int
+ACL_AttrGetterFind(NSErr_t *errp, const char *attr,
+ ACLAttrGetterList_t *getters)
+{
+ *getters = PR_HashTableLookup(ACLAttrGetterHash, attr);
+ if (*getters)
+ return 0;
+ else
+ return -1;
+}
+
+NSAPI_PUBLIC
+ACLAttrGetter_t * ACL_AttrGetterFirst(ACLAttrGetterList_t *getters)
+{
+ ACLAttrGetter_t * first = 0;
+
+ if (getters && *getters) {
+
+ first = (ACLAttrGetter_t *)(*getters);
+ }
+
+ return first;
+}
+
+NSAPI_PUBLIC ACLAttrGetter_t *
+ACL_AttrGetterNext(ACLAttrGetterList_t *getters, ACLAttrGetter_t *last)
+{
+ ACLAttrGetter_t *head;
+ ACLAttrGetter_t *next = 0;
+
+ if (getters && *getters && last) {
+
+ head = (ACLAttrGetter_t *)(*getters);
+ if (head) {
+
+ /* End of list? */
+ if (last != (ACLAttrGetter_t *)PR_LIST_TAIL(&head->list)) {
+
+ /* No, get next entry */
+ next = (ACLAttrGetter_t *)PR_NEXT_LINK(&last->list);
+ }
+ }
+ }
+
+ return next;
+}
+
+int
+ACL_RegisterInit ()
+{
+ NSErr_t *errp = 0;
+ int rv;
+
+ /* Register the ldap database */
+ rv = ACL_DbTypeRegister(errp, ACL_DBTYPE_LDAP, parse_ldap_url, &ACL_DbTypeLdap);
+
+ return rv;
+}
+
diff --git a/lib/libaccess/register.h b/lib/libaccess/register.h
new file mode 100644
index 00000000..981e2cb8
--- /dev/null
+++ b/lib/libaccess/register.h
@@ -0,0 +1,98 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#ifndef ACL_REGISTER_HEADER
+#define ACL_REGISTER_HEADER
+
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include <libaccess/las.h>
+
+typedef void * ACLMethod_t;
+#define ACL_METHOD_ANY (ACLMethod_t)-1
+#define ACL_METHOD_INVALID (ACLMethod_t)-2
+typedef void * ACLDbType_t;
+#define ACL_DBTYPE_ANY (ACLDbType_t)-1
+#define ACL_DBTYPE_INVALID (ACLDbType_t)-2
+
+typedef struct ACLGetter_s {
+ ACLMethod_t method;
+ ACLDbType_t db;
+ AttrGetterFn fn;
+} ACLGetter_t;
+typedef ACLGetter_s * ACLGetter_p;
+
+/*
+ * Command values for the "position" argument to ACL_RegisterGetter
+ * Any positive >0 value is the specific position in the list to insert
+ * the new function.
+ */
+#define ACL_AT_FRONT 0
+#define ACL_AT_END -1
+#define ACL_REPLACE_ALL -2
+#define ACL_REPLACE_MATCHING -3
+
+#ifdef ACL_LIB_INTERNAL
+#define ACL_MAX_METHOD 32
+#define ACL_MAX_DBTYPE 32
+#endif
+
+NSPR_BEGIN_EXTERN_C
+
+NSAPI_PUBLIC extern int
+ ACL_LasRegister( NSErr_t *errp, char *attr_name, LASEvalFunc_t
+ eval_func, LASFlushFunc_t flush_func );
+NSAPI_PUBLIC extern int
+ ACL_LasFindEval( NSErr_t *errp, char *attr_name, LASEvalFunc_t
+ *eval_funcp );
+NSAPI_PUBLIC extern int
+ ACL_LasFindFlush( NSErr_t *errp, char *attr_name, LASFlushFunc_t
+ *flush_funcp );
+extern void
+ ACL_LasHashInit( void );
+extern void
+ ACL_LasHashDestroy( void );
+
+/*
+ * Revised, normalized method/dbtype registration routines
+ */
+NSAPI_PUBLIC extern int
+ ACL_MethodRegister(const char *name, ACLMethod_t *t);
+NSAPI_PUBLIC extern int
+ ACL_MethodIsEqual(ACLMethod_t t1, ACLMethod_t t2);
+NSAPI_PUBLIC extern int
+ ACL_MethodNameIsEqual(ACLMethod_t t, const char *name);
+NSAPI_PUBLIC extern int
+ ACL_MethodFind(const char *name, ACLMethod_t *t);
+NSAPI_PUBLIC extern ACLMethod_t
+ ACL_MethodGetDefault();
+NSAPI_PUBLIC extern void
+ ACL_MethodSetDefault();
+NSAPI_PUBLIC extern int
+ ACL_AuthInfoGetMethod(PList_t auth_info, ACLMethod_t *t);
+
+NSAPI_PUBLIC extern int
+ ACL_DbTypeRegister(const char *name, DbParseFn_t func, ACLDbType_t *t);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeIsEqual(ACLDbType_t t1, ACLDbType_t t2);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeNameIsEqual(ACLDbType_t t, const char *name);
+NSAPI_PUBLIC extern int
+ ACL_DbTypeFind(const char *name, ACLDbType_t *t);
+NSAPI_PUBLIC extern ACLDbType_t
+ ACL_DbTypeGetDefault();
+NSAPI_PUBLIC extern void
+ ACL_DbTypeSetDefault();
+NSAPI_PUBLIC extern int
+ ACL_AuthInfoGetDbType(PList_t auth_info, ACLDbType_t *t);
+
+NSAPI_PUBLIC extern int
+ ACL_RegisterGetter(AttrGetterFn fn, ACLMethod_t m, ACLDbType_t d, int
+ position, void *arg);
+
+NSPR_END_EXTERN_C
+
+#endif
diff --git a/lib/libaccess/symbols.cpp b/lib/libaccess/symbols.cpp
new file mode 100644
index 00000000..ca1e18b1
--- /dev/null
+++ b/lib/libaccess/symbols.cpp
@@ -0,0 +1,350 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/*
+ * Description (symbols.c)
+ *
+ * This module implements a symbol table for ACL-related structures.
+ * The symbol table associates string names and types with pointers
+ * to various kinds of structures.
+ */
+/*
+#include <base/systems.h>
+*/
+#include <plhash.h>
+#include <base/util.h>
+#include <netsite.h>
+#define __PRIVATE_SYMBOLS
+#include "libaccess/symbols.h"
+#include <ctype.h>
+
+static PLHashEntry * symAllocEntry(void * pool, const void *unused);
+static void * symAllocTable(void * pool, PRSize size);
+static int symCmpName(const void * name1, const void * name2);
+static int symCmpValue(const void * value1, const void * value2);
+static PLHashNumber symHash(const void * symkey);
+static void symFreeEntry(void * pool, PLHashEntry * he, PRUintn flag);
+static void symFreeTable(void * pool, void * item);
+
+/* Table of pointers to functions associated with the hash table */
+static PLHashAllocOps SymAllocOps = {
+ symAllocTable, /* allocate the hash table */
+ symFreeTable, /* free the hash table */
+ symAllocEntry, /* allocate a table entry */
+ symFreeEntry, /* free a table entry */
+};
+
+static void * symAllocTable(void * pool, PRSize size)
+{
+ return (void *)PERM_MALLOC(size);
+}
+
+static void symFreeTable(void * pool, void * item)
+{
+ PERM_FREE(item);
+}
+
+
+
+static PLHashEntry * symAllocEntry(void * pool, const void *ignored)
+{
+ PLHashEntry * he;
+
+ he = (PLHashEntry *) PERM_MALLOC(sizeof(PLHashEntry));
+
+ return he;
+}
+
+static void symFreeEntry(void * pool, PLHashEntry * he, PRUintn flag)
+{
+ if (flag == HT_FREE_ENTRY) {
+ /* Just free the hash entry, not anything it references */
+ PERM_FREE(he);
+ }
+}
+
+
+static int symCmpName(const void * name1, const void * name2)
+{
+ Symbol_t * sym1 = (Symbol_t *)name1;
+ Symbol_t * sym2 = (Symbol_t *)name2;
+
+ return ((sym1->sym_type == sym2->sym_type) &&
+ !strcasecmp(sym1->sym_name, sym2->sym_name));
+}
+
+static int symCmpValue(const void * value1, const void * value2)
+{
+ return (value1 == value2);
+}
+
+static PLHashNumber symHash(const void * symkey)
+{
+ Symbol_t * sym = (Symbol_t *)symkey;
+ char * cp;
+ PLHashNumber h;
+
+ h = sym->sym_type;
+ cp = sym->sym_name;
+ if (cp) {
+ while (*cp) {
+ h = (h << 3) ^ tolower(*cp);
+ ++cp;
+ }
+ }
+
+ return h;
+}
+
+/* Helper function for symTableEnumerate() */
+typedef struct {
+ int (*func)(Symbol_t * sym, void * parg);
+ void * argp;
+} SymTableEnum_t;
+
+static int symTableEnumHelp(PLHashEntry * he, int n, void * step)
+{
+ SymTableEnum_t * ste = (SymTableEnum_t *)step;
+ int ret = 0;
+ int rv;
+
+ rv = (*ste->func)((Symbol_t *)(he->key), ste->argp);
+ if (rv != 0) {
+ if (rv & SYMENUMREMOVE) ret = HT_ENUMERATE_REMOVE;
+ if (rv & SYMENUMSTOP) ret |= HT_ENUMERATE_STOP;
+ }
+
+ return ret;
+}
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * Description (symTableAddSym)
+ *
+ * This function adds a symbol definition to the symbol table.
+ * The symbol definition includes a name string, a type, and a
+ * reference to a structure.
+ *
+ * Arguments:
+ *
+ * table - handle for symbol table
+ * newsym - pointer to new symbol name and type
+ * symref - pointer to structure named by symbol
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero. An error is indicated
+ * by a negative return code (SYMERRxxxx - see symbols.h).
+ */
+
+int symTableAddSym(void * table, Symbol_t * newsym, void * symref)
+{
+ SymTable_t * st = (SymTable_t *)table;
+ PLHashEntry * he;
+ PLHashEntry **hep;
+ PLHashNumber keyhash;
+ int rv = 0;
+
+ /* Compute the hash value for this symbol */
+ keyhash = symHash((const void *)newsym);
+
+ crit_enter(st->stb_crit);
+
+ /* See if another symbol already has the same name and type */
+ hep = PL_HashTableRawLookup(st->stb_ht, keyhash, (void *)newsym);
+ if (*hep == 0) {
+
+ /* Expand the hash table if necessary and allocate an entry */
+ he = PL_HashTableRawAdd(st->stb_ht,
+ hep, keyhash, (void *)newsym, symref);
+ }
+ else {
+ /* The symbol is already there. It's an error */
+ rv = SYMERRDUPSYM;
+ }
+
+ crit_exit(st->stb_crit);
+ return rv;
+}
+
+/*
+ * Description (symTableRemoveSym)
+ *
+ * This function removes an entry from a symbol table. It does
+ * not free the entry itself, just the hash entry that references
+ * it.
+ *
+ * Arguments:
+ *
+ * table - symbol table handle
+ * sym - pointer to symbol structure
+ */
+
+void symTableRemoveSym(void * table, Symbol_t * sym)
+{
+ SymTable_t * st = (SymTable_t *)table;
+
+ if (sym->sym_name != 0) {
+ crit_enter(st->stb_crit);
+ PL_HashTableRemove(st->stb_ht, (void *)sym);
+ crit_exit(st->stb_crit);
+ }
+}
+
+/*
+ * Description (symTableEnumerate)
+ *
+ * This function enumerates all of the entries in a symbol table,
+ * calling a specified function for each entry. The function
+ * specified by the caller may return flags indicating actions
+ * to be taken for each entry or whether to terminate the
+ * enumeration. These flags are defined in symbols.h as
+ * SYMENUMxxxx.
+ *
+ * Arguments:
+ *
+ * table - symbol table handle
+ * argp - argument for caller function
+ * func - function to be called for each entry
+ */
+
+void symTableEnumerate(void * table, void * argp,
+#ifdef UnixWare /* Fix bug in UnixWare compiler for name mangeling - nedh@sco.com */
+ ArgFn_symTableEnum func)
+#else
+ int (*func)(Symbol_t * sym, void * parg))
+#endif
+{
+ SymTable_t * st = (SymTable_t *)table;
+ SymTableEnum_t ste; /* enumeration arguments */
+
+ ste.func = func;
+ ste.argp = argp;
+
+ crit_enter(st->stb_crit);
+ (void)PL_HashTableEnumerateEntries(st->stb_ht,
+ symTableEnumHelp, (void *)&ste);
+ crit_exit(st->stb_crit);
+}
+
+/*
+ * Description (symTableFindSym)
+ *
+ * This function locates a symbol with a specified name and type
+ * in a given symbol table. It returns a pointer to the structure
+ * named by the symbol.
+ *
+ * Arguments:
+ *
+ * table - symbol table handle
+ * symname - symbol name string pointer
+ * symtype - symbol type code
+ * psymref - pointer to returned structure pointer
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero and the structure pointer
+ * associated with the symbol name and type is returned in the
+ * location specified by 'psymref'. An error is indicated by a
+ * negative return code (SYMERRxxxx - see symbols.h).
+ */
+
+int symTableFindSym(void * table, char * symname,
+ int symtype, void **psymref)
+{
+ SymTable_t * st = (SymTable_t *)table;
+ Symbol_t sym;
+ void * symref;
+
+ /* Create temporary entry with fields needed by symHash() */
+ sym.sym_name = symname;
+ sym.sym_type = symtype;
+
+ crit_enter(st->stb_crit);
+
+ symref = PL_HashTableLookup(st->stb_ht, (void *)&sym);
+
+ crit_exit(st->stb_crit);
+
+ *psymref = symref;
+
+ return (symref) ? 0 : SYMERRNOSYM;
+}
+
+/*
+ * Description (symTableDestroy)
+ *
+ * This function destroys a symbol table created by symTableNew().
+ *
+ * Arguments:
+ *
+ * table - symbol table handle from symTableNew()
+ * flags - bit flags (unused - must be zero)
+ */
+
+void symTableDestroy(void * table, int flags)
+{
+ SymTable_t * st = (SymTable_t *)table;
+
+ if (st) {
+ if (st->stb_crit) {
+ crit_terminate(st->stb_crit);
+ }
+
+ if (st->stb_ht) {
+ PL_HashTableDestroy(st->stb_ht);
+ }
+
+ PERM_FREE(st);
+ }
+}
+
+/*
+ * Description (symTableNew)
+ *
+ * This function creates a new symbol table, and returns a handle
+ * for it.
+ *
+ * Arguments:
+ *
+ * ptable - pointer to returned symbol table handle
+ *
+ * Returns:
+ *
+ * If successful, the return code is zero and a handle for the new
+ * symbol table is returned in the location specified by 'ptable'.
+ * An error is indicated by a negative return code (SYMERRxxxx
+ * - see symbols.h).
+ */
+
+int symTableNew(void **ptable)
+{
+ SymTable_t * st;
+
+ /* Allocate the symbol table object */
+ st = (SymTable_t *)PERM_MALLOC(sizeof(SymTable_t));
+ if (st == 0) goto err_nomem;
+
+ /* Get a monitor for it */
+ st->stb_crit = crit_init();
+
+ st->stb_ht = PL_NewHashTable(0, symHash, symCmpName, symCmpValue,
+ &SymAllocOps, 0);
+ if (st->stb_ht == 0) goto err_nomem;
+
+ *ptable = st;
+ return 0;
+
+ err_nomem:
+ if (st) {
+ symTableDestroy(st, 0);
+ }
+ return SYMERRNOMEM;
+}
+
+NSPR_END_EXTERN_C
+
diff --git a/lib/libaccess/userauth.cpp b/lib/libaccess/userauth.cpp
new file mode 100644
index 00000000..3413fbd0
--- /dev/null
+++ b/lib/libaccess/userauth.cpp
@@ -0,0 +1,12 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* userauth.c
+ * This file contain code to authenticate user.
+ */
+
+
+
diff --git a/lib/libaccess/usi.cpp b/lib/libaccess/usi.cpp
new file mode 100644
index 00000000..677f3bd7
--- /dev/null
+++ b/lib/libaccess/usi.cpp
@@ -0,0 +1,371 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "base/systems.h"
+#include "netsite.h"
+#include "assert.h"
+#include "libaccess/usi.h"
+
+/*
+ * Description (usiAlloc)
+ *
+ * This function is used to initialize a USIList_t structure to
+ * reference an array of unsigned integers, where the size of the
+ * array is specified. The caller is responsible for initializing
+ * the specified number of values in the array.
+ *
+ * Arguments:
+ *
+ * uilptr - pointer to list head
+ * count - number of entries to allocate
+ *
+ * Returns:
+ *
+ * If successful, a pointer to the USI_t array now referenced by the
+ * list head (uilptr) is returned. An error is indicated by a null
+ * return value.
+ */
+
+USI_t * usiAlloc(USIList_t * uilptr, int count)
+{
+ /* Is there space already allocated for this list? */
+ if (uilptr->uil_size > 0) {
+
+ /* If it's not big enough to hold the desired size, free it */
+ if (count > uilptr->uil_size) {
+ FREE(uilptr->uil_list);
+ UILINIT(uilptr);
+ }
+ }
+
+ /* Do we need space? */
+ if (uilptr->uil_size < count) {
+
+ /* Yes, allocate space for the specified number of values */
+ uilptr->uil_list = (USI_t *)MALLOC(sizeof(USI_t) * count);
+ if (uilptr->uil_list == 0) {
+
+ /* Error - no memory available */
+ uilptr->uil_count = 0;
+ return 0;
+ }
+
+ uilptr->uil_size = count;
+ }
+
+ uilptr->uil_count = count;
+
+ return uilptr->uil_list;
+}
+
+/*
+ * Description (usiInsert)
+ *
+ * This function is called to insert a specified USI_t value into
+ * a given list of USI_t values. The values are maintained in an
+ * array, where they are kept in ascending order. Duplicate values
+ * are rejected.
+ *
+ * Arguments:
+ *
+ * uilptr - pointer to list head
+ * usi - value to be inserted
+ *
+ * Returns:
+ *
+ * If the specified value is already in the list, zero is returned.
+ * If the value is successfully inserted into the list, +1 is
+ * returned. An error is indicated by a negative return value.
+ */
+
+int usiInsert(USIList_t * uilptr, USI_t usi)
+{
+ int ilow, ihigh, i;
+ USI_t * ids;
+
+ ids = uilptr->uil_list;
+
+ /* Binary search for specified group id */
+ i = 0;
+ for (ilow = 0, ihigh = uilptr->uil_count; ilow != ihigh; ) {
+
+ i = (ilow + ihigh) >> 1;
+ if (usi == ids[i]) {
+ /* The value is already in the list */
+ return 0;
+ }
+
+ if (usi > ids[i]) {
+ ilow = i + 1;
+ }
+ else {
+ ihigh = i;
+ }
+ }
+
+ /* Check for empty list */
+ if (uilptr->uil_count <= 0) {
+
+ /* Any space allocated for the list yet? */
+ if (uilptr->uil_size <= 0) {
+
+ /* No, allocate some initial space */
+ ids = (USI_t *) MALLOC(sizeof(USI_t) * 4);
+ if (ids == 0) {
+ /* Error - no memory available */
+ return -1;
+ }
+
+ uilptr->uil_size = 4;
+ uilptr->uil_list = ids;
+ }
+
+ /* Value will be inserted at ilow, which is zero */
+ }
+ else {
+
+ /*
+ * Set ilow to the index at which the specified value
+ * should be inserted.
+ */
+ if (usi > ids[i]) ++i;
+ ilow = i;
+
+ /* Is there space for another value? */
+ if (uilptr->uil_count >= uilptr->uil_size) {
+
+ /* No, expand the array to hold more values */
+ ids = (USI_t *)REALLOC(ids,
+ (uilptr->uil_size + 4) * sizeof(USI_t));
+ if (ids == 0) {
+ /* Error - no memory available */
+ return -1;
+ }
+
+ uilptr->uil_size += 4;
+ uilptr->uil_list = ids;
+ }
+
+ /* Copy higher values up */
+ for (i = uilptr->uil_count; i > ilow; --i) {
+ ids[i] = ids[i-1];
+ }
+ }
+
+ /* Add the new value */
+ ids[ilow] = usi;
+ uilptr->uil_count += 1;
+
+ return 1;
+}
+
+/*
+ * Description (usiPresent)
+ *
+ * This function is called to check whether a specified USI_t value
+ * is present in a given list.
+ *
+ * Arguments:
+ *
+ * uilptr - pointer to list head
+ * usi - value to check for
+ *
+ * Returns:
+ *
+ * The return value is the index of the value in the list, plus one,
+ * if the value is present in the list, 0 if it is not.
+ */
+
+int usiPresent(USIList_t * uilptr, USI_t usi)
+{
+ int ilow, ihigh, i;
+ USI_t * ids;
+
+ ids = uilptr->uil_list;
+
+ /* Binary search for specified group id */
+ i = 0;
+ for (ilow = 0, ihigh = uilptr->uil_count; ilow != ihigh; ) {
+
+ i = (ilow + ihigh) >> 1;
+ if (usi == ids[i]) {
+ /* The value is in the list */
+ return i + 1;
+ }
+
+ if (usi > ids[i]) {
+ ilow = i + 1;
+ }
+ else {
+ ihigh = i;
+ }
+ }
+
+ /* The value was not found */
+ return 0;
+}
+
+/*
+ * Description (usiRemove)
+ *
+ * This function is called to remove a specified USI_t value from
+ * a given list. The list is compressed when the value is removed.
+ *
+ * Arguments:
+ *
+ * uilptr - pointer to list head
+ * usi - value to be removed
+ *
+ * Returns:
+ *
+ * Returns the value returned by usiPresent(uilptr, usi).
+ */
+
+int usiRemove(USIList_t * uilptr, USI_t usi)
+{
+ USI_t * ids;
+ int i, j;
+
+ i = usiPresent(uilptr, usi);
+ if (i > 0) {
+
+ /* Compress the remaining values */
+ ids = uilptr->uil_list;
+ for (j = i ; j < uilptr->uil_count; ++j) {
+ ids[j-1] = ids[j];
+ }
+
+ /* Decrement the number of values and free space if none left */
+ if (--uilptr->uil_count <= 0) {
+ FREE(uilptr->uil_list);
+ UILINIT(uilptr);
+ }
+ }
+
+ return i;
+}
+
+/*
+ * Description (uilDuplicate)
+ *
+ * This function is called to make a duplicate of a specified
+ * source list, in a given destination list. Any existing list
+ * referenced by the destination list head is either overwritten
+ * or replaced with a newly allocated list. The values in the
+ * source list are copied to the destination. Note that the
+ * destination list area may be larger than the source list area
+ * on return, i.e. their uil_size values may differ.
+ *
+ * Arguments:
+ *
+ * dstptr - pointer to destination list head
+ * srcptr - pointer to source list head
+ *
+ * Returns:
+ *
+ * The number of elements in the source and destination lists is
+ * returned if successful. An error is indicated by a negative
+ * return value.
+ */
+
+int uilDuplicate(USIList_t * dstptr, USIList_t * srcptr)
+{
+ USI_t * idlist;
+ USI_t * srclist;
+ int count;
+ int i;
+
+ count = srcptr->uil_count;
+ srclist = srcptr->uil_list;
+
+ /* Allocate enough space in the destination list */
+ idlist = usiAlloc(dstptr, count);
+ if ((idlist == 0) && (count > 0)) {
+ /* Error - insufficient memory */
+ return -1;
+ }
+
+ /* Copy source values to destination */
+ for (i = 0; i < count; ++i) {
+ idlist[i] = srclist[i];
+ }
+
+ /* Return number of entries in destination list */
+ return count;
+}
+
+/*
+ * Description (uilMerge)
+ *
+ * This function is called to merge the values in a source list
+ * into a destination list. That is, any values in the source
+ * list which are not in the destination list will be inserted
+ * in it.
+ *
+ * Arguments:
+ *
+ * dstptr - pointer to destination list head
+ * srcptr - pointer to source list head
+ *
+ * Returns:
+ *
+ * The resulting number of elements in the destination list is
+ * returned if successful. An error is indicated by a negative
+ * return value.
+ */
+
+int uilMerge(USIList_t * dstptr, USIList_t * srcptr)
+{
+ USIList_t mglist; /* list head for merged list */
+ USI_t * srclist = srcptr->uil_list;
+ USI_t * dstlist = dstptr->uil_list;
+ int isrc, idst;
+ int scnt, dcnt;
+ int rv;
+
+ UILINIT(&mglist);
+
+ scnt = srcptr->uil_count;
+ dcnt = dstptr->uil_count;
+ isrc = 0;
+ idst = 0;
+
+ while ((isrc < scnt) && (idst < dcnt)) {
+
+ if (srclist[isrc] >= dstlist[idst]) {
+ rv = usiInsert(&mglist, dstlist[idst]);
+ if (rv < 0) goto punt;
+ if (srclist[isrc] == dstlist[idst]) ++isrc;
+ ++idst;
+ }
+ else if (srclist[isrc] < dstlist[idst]) {
+ rv = usiInsert(&mglist, srclist[isrc]);
+ if (rv < 0) goto punt;
+ ++isrc;
+ }
+ }
+
+ while (isrc < scnt) {
+ rv = usiInsert(&mglist, srclist[isrc]);
+ if (rv < 0) goto punt;
+ ++isrc;
+ }
+
+ while (idst < dcnt) {
+ rv = usiInsert(&mglist, dstlist[idst]);
+ if (rv < 0) goto punt;
+ ++idst;
+ }
+
+ UILREPLACE(dstptr, &mglist);
+
+ return dstptr->uil_count;
+
+ punt:
+ UILFREE(&mglist);
+ return rv;
+}
+
diff --git a/lib/libaccess/usrcache.cpp b/lib/libaccess/usrcache.cpp
new file mode 100644
index 00000000..2f79d2cc
--- /dev/null
+++ b/lib/libaccess/usrcache.cpp
@@ -0,0 +1,657 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/* #define DBG_PRINT */
+
+
+#include <netsite.h>
+extern "C" {
+#include <secitem.h>
+}
+#include <base/crit.h>
+#include <ldaputil/errors.h>
+#include <libaccess/usrcache.h>
+#include <libaccess/las.h>
+#include <libaccess/authdb.h>
+#include "permhash.h"
+
+/* uid is unique within a database. The user cache tables are stored per
+ * database. The following table maps a database name to the corresponding
+ * user cache table. The user cache table is another hash table which stores
+ * the UserCacheObj instances.
+ */
+static PRHashTable *databaseUserCacheTable = 0;
+static time_t acl_usr_cache_lifetime = (time_t)120;
+static PRCList *usrobj_list = 0;
+static const int num_usrobj = 200;
+static CRITICAL usr_hash_crit = NULL; /* Controls user cache hash tables & */
+ /* usrobj link list */
+static pool_handle_t *usrcache_pool = NULL;
+static PRHashTable *singleDbTable = 0;
+
+#define USEROBJ_PTR(l) \
+ ((UserCacheObj*) ((char*) (l) - offsetof(UserCacheObj, list)))
+
+static void user_hash_crit_enter (void)
+{
+ /* Caching may be disabled (usr_hash_crit will be NULL) */
+ if (usr_hash_crit) crit_enter(usr_hash_crit);
+}
+
+static void user_hash_crit_exit (void)
+{
+ /* Caching may be disabled (usr_hash_crit will be NULL) */
+ if (usr_hash_crit) crit_exit(usr_hash_crit);
+}
+
+static void user_hash_crit_init (void)
+{
+ usr_hash_crit = crit_init();
+}
+
+static PRHashNumber
+usr_cache_hash_cert(const void *key)
+{
+ PRHashNumber h;
+ const unsigned char *s;
+ unsigned int i = 0;
+ SECItem *derCert = (SECItem *)key;
+ unsigned int len = derCert->len;
+
+ h = 0;
+ for (s = (const unsigned char *)derCert->data; i < len; s++, i++)
+ h = (h >> 28) ^ (h << 4) ^ *s;
+ return h;
+}
+
+static PRHashNumber
+usr_cache_hash_fn (const void *key)
+{
+ UserCacheObj *usrObj = (UserCacheObj *)key;
+
+ if (usrObj->derCert)
+ return usr_cache_hash_cert(usrObj->derCert);
+ else
+ return PR_HashCaseString(usrObj->uid);
+}
+
+static int
+usr_cache_compare_certs(const void *v1, const void *v2)
+{
+ const SECItem *c1 = (const SECItem *)v1;
+ const SECItem *c2 = (const SECItem *)v2;
+
+ return (c1->len == c2 ->len && !memcmp(c1->data, c2->data, c1->len));
+}
+
+static int
+usr_cache_compare_fn(const void *v1, const void *v2)
+{
+ UserCacheObj *usrObj1 = (UserCacheObj *)v1;
+ UserCacheObj *usrObj2 = (UserCacheObj *)v2;
+
+ if (usrObj1->derCert && usrObj2->derCert)
+ return usr_cache_compare_certs(usrObj1->derCert, usrObj2->derCert);
+ else if (!usrObj1->derCert && !usrObj2->derCert)
+ return PR_CompareCaseStrings(usrObj1->uid, usrObj1->uid);
+ else
+ return 0;
+}
+
+static PRHashTable *alloc_db2uid_table ()
+{
+ return PR_NewHashTable(0,
+ usr_cache_hash_fn,
+ usr_cache_compare_fn,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ usrcache_pool);
+}
+
+
+int acl_usr_cache_set_timeout (const int nsec)
+{
+ acl_usr_cache_lifetime = (time_t)nsec;
+ return 0;
+}
+
+
+int acl_usr_cache_enabled ()
+{
+ return (acl_usr_cache_lifetime > 0);
+}
+
+
+int acl_usr_cache_init ()
+{
+ UserCacheObj *usrobj;
+ int i;
+
+ if (acl_usr_cache_lifetime <= 0) {
+ /* Caching is disabled */
+ DBG_PRINT1("usrcache is disabled");
+ return 0;
+ }
+
+ usrcache_pool = pool_create();
+ user_hash_crit_init();
+
+ if (acl_num_databases() == 0) {
+ /* Something wrong -- No databases registered yet! */
+ return -1;
+ }
+ else if (acl_num_databases() == 1) {
+ /* Optimize for single database */
+ DBG_PRINT1("Optimizing usrcache for single db");
+ singleDbTable = alloc_db2uid_table();
+ }
+ else {
+ singleDbTable = 0;
+ databaseUserCacheTable = PR_NewHashTable(0,
+ PR_HashCaseString,
+ PR_CompareCaseStrings,
+ PR_CompareValues,
+ &ACLPermAllocOps,
+ usrcache_pool);
+ }
+
+ /* Allocate first UserCacheObj and initialize the circular link list */
+ usrobj = (UserCacheObj *)pool_malloc(usrcache_pool, sizeof(UserCacheObj));
+ if (!usrobj) return -1;
+ memset((void *)usrobj, 0, sizeof(UserCacheObj));
+ usrobj_list = &usrobj->list;
+ PR_INIT_CLIST(usrobj_list);
+
+ /* Allocate rest of the UserCacheObj and put them in the link list */
+ for(i = 0; i < num_usrobj; i++){
+ usrobj = (UserCacheObj *)pool_malloc(usrcache_pool,
+ sizeof(UserCacheObj));
+
+ if (!usrobj) return -1;
+ memset((void *)usrobj, 0, sizeof(UserCacheObj));
+ PR_INSERT_AFTER(&usrobj->list, usrobj_list);
+ }
+
+ return (singleDbTable || databaseUserCacheTable) ? 0 : -1;
+}
+
+/* If the user hash table exists in the databaseUserCacheTable then return it.
+ * Otherwise, create a new hash table, insert it in the databaseUserCacheTable
+ * and then return it.
+ */
+static int usr_cache_table_get (const char *dbname, PRHashTable **usrTable)
+{
+ PRHashTable *table;
+
+ if (singleDbTable) {
+ *usrTable = singleDbTable;
+ return LAS_EVAL_TRUE;
+ }
+
+ user_hash_crit_enter();
+
+ table = (PRHashTable *)PR_HashTableLookup(databaseUserCacheTable,
+ dbname);
+
+ if (!table) {
+ /* create a new table and insert it in the databaseUserCacheTable */
+ table = alloc_db2uid_table();
+
+ if (table) {
+ PR_HashTableAdd(databaseUserCacheTable,
+ pool_strdup(usrcache_pool, dbname),
+ table);
+ }
+ }
+
+ *usrTable = table;
+
+ user_hash_crit_exit();
+
+ return table ? LAS_EVAL_TRUE : LAS_EVAL_FAIL;
+}
+
+int acl_usr_cache_insert (const char *uid, const char *dbname,
+ const char *userdn, const char *passwd,
+ const char *group,
+ const SECItem *derCert, const time_t time)
+{
+ PRHashTable *usrTable;
+ UserCacheObj *usrobj;
+ UserCacheObj key;
+ int rv;
+
+ if (acl_usr_cache_lifetime <= 0) {
+ /* Caching is disabled */
+ return LAS_EVAL_TRUE;
+ }
+
+ rv = usr_cache_table_get (dbname, &usrTable);
+
+ if (rv != LAS_EVAL_TRUE) return rv;
+
+ user_hash_crit_enter();
+
+ key.uid = (char *)uid;
+ key.derCert = (SECItem *)derCert;
+
+ usrobj = (UserCacheObj *)PR_HashTableLookup(usrTable, &key);
+
+ if (usrobj) {
+ time_t elapsed = time - usrobj->time;
+ int expired = (elapsed >= acl_usr_cache_lifetime);
+
+ /* Free & reset the old values in usrobj if -- there is an old value
+ * and if the new value is given then it is different or the usrobj
+ * has expired */
+ /* Set the field if the new value is given and the field is not set */
+ /* If the usrobj has not expired then we only want to update the field
+ * whose new value is non-NULL and different */
+
+ /* Work on the 'uid' field */
+ if (usrobj->uid &&
+ (uid ? strcmp(usrobj->uid, uid) : expired))
+ {
+ pool_free(usrcache_pool, usrobj->uid);
+ usrobj->uid = 0;
+ }
+ if (uid && !usrobj->uid) {
+ usrobj->uid = pool_strdup(usrcache_pool, uid);
+ }
+
+ /* Work on the 'userdn' field */
+ if (usrobj->userdn &&
+ (userdn ? strcmp(usrobj->userdn, userdn) : expired))
+ {
+ pool_free(usrcache_pool, usrobj->userdn);
+ usrobj->userdn = 0;
+ }
+ if (userdn && !usrobj->userdn) {
+ usrobj->userdn = pool_strdup(usrcache_pool, userdn);
+ }
+
+ /* Work on the 'passwd' field */
+ if (usrobj->passwd &&
+ (passwd ? strcmp(usrobj->passwd, passwd) : expired))
+ {
+ pool_free(usrcache_pool, usrobj->passwd);
+ usrobj->passwd = 0;
+ }
+ if (passwd && !usrobj->passwd) {
+ usrobj->passwd = pool_strdup(usrcache_pool, passwd);
+ }
+
+ /* Work on the 'group' field -- not replace a valid group */
+ if (!expired && usrobj->group &&
+ (group ? strcmp(usrobj->group, group) : expired))
+ {
+ pool_free(usrcache_pool, usrobj->group);
+ usrobj->group = 0;
+ }
+ if (group && !usrobj->group) {
+ usrobj->group = pool_strdup(usrcache_pool, group);
+ }
+
+ /* Work on the 'derCert' field */
+ if (usrobj->derCert &&
+ (derCert ? (derCert->len != usrobj->derCert->len ||
+ memcmp(usrobj->derCert->data, derCert->data,
+ derCert->len))
+ : expired))
+ {
+ SECITEM_FreeItem(usrobj->derCert, PR_TRUE);
+ usrobj->derCert = 0;
+ }
+ if (derCert && !usrobj->derCert) {
+ usrobj->derCert = SECITEM_DupItem((SECItem *)derCert);
+ }
+
+ /* Reset the time only if the usrobj has expired */
+ if (expired) {
+ DBG_PRINT1("Replace ");
+ usrobj->time = time;
+ }
+ else {
+ DBG_PRINT1("Update ");
+ }
+ }
+ else {
+ /* Get the last usrobj from the link list, erase it and use it */
+ /* Maybe the last usrobj is not invalid yet but we don't want to grow
+ * the list of usrobjs. The last obj is the best candidate for being
+ * not valid. We don't want to compare the time -- just use it.
+ */
+ PRCList *tail = PR_LIST_TAIL(usrobj_list);
+ usrobj = USEROBJ_PTR(tail);
+
+ /* If the removed usrobj is in the hashtable, remove it from there */
+ if (usrobj->hashtable) {
+ PR_HashTableRemove(usrobj->hashtable, usrobj);
+ }
+
+ /* Free the memory associated with the usrobj */
+ if (usrobj->userdn) pool_free(usrcache_pool, usrobj->userdn);
+ if (usrobj->passwd) pool_free(usrcache_pool, usrobj->passwd);
+ if (usrobj->group) pool_free(usrcache_pool, usrobj->group);
+ if (usrobj->derCert) SECITEM_FreeItem(usrobj->derCert, PR_TRUE);
+ if (usrobj->uid) pool_free(usrcache_pool, usrobj->uid);
+
+ /* Fill in the usrobj with the current data */
+ usrobj->uid = pool_strdup(usrcache_pool, uid);
+ usrobj->userdn = userdn ? pool_strdup(usrcache_pool, userdn) : 0;
+ usrobj->passwd = passwd ? pool_strdup(usrcache_pool, passwd) : 0;
+ usrobj->derCert = derCert ? SECITEM_DupItem((SECItem *)derCert) : 0;
+ usrobj->group = group ? pool_strdup(usrcache_pool, group) : 0;
+ usrobj->time = time;
+
+ /* Add the usrobj to the user hash table */
+ PR_HashTableAdd(usrTable, usrobj, usrobj);
+ usrobj->hashtable = usrTable;
+ DBG_PRINT1("Insert ");
+ }
+
+ /* Move the usrobj to the head of the list */
+ PR_REMOVE_LINK(&usrobj->list);
+ PR_INSERT_AFTER(&usrobj->list, usrobj_list);
+
+ /* Set the time in the UserCacheObj */
+ if (usrobj) {
+ rv = LAS_EVAL_TRUE;
+ }
+ else {
+ rv = LAS_EVAL_FAIL;
+ }
+
+ DBG_PRINT4("acl_usr_cache_insert: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
+ usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
+ uid, time);
+
+ user_hash_crit_exit();
+ return rv;
+}
+
+static int acl_usr_cache_get_usrobj (const char *uid, const SECItem *derCert,
+ const char *dbname, const time_t time,
+ UserCacheObj **usrobj_out)
+{
+ PRHashTable *usrtable;
+ UserCacheObj *usrobj;
+ UserCacheObj key;
+ time_t elapsed;
+ int rv;
+
+ *usrobj_out = 0;
+
+ if (acl_usr_cache_lifetime <= 0) {
+ /* Caching is disabled */
+ return LAS_EVAL_FALSE;
+ }
+
+ rv = usr_cache_table_get(dbname, &usrtable);
+ if (!usrtable) return LAS_EVAL_FALSE;
+
+ key.uid = (char *)uid;
+ key.derCert = (SECItem *)derCert;
+
+ usrobj = (UserCacheObj *)PR_HashTableLookup(usrtable, &key);
+
+ if (!usrobj) return LAS_EVAL_FALSE;
+
+ rv = LAS_EVAL_FALSE;
+
+ elapsed = time - usrobj->time;
+
+ /* If the cache is valid, return the usrobj */
+ if (elapsed < acl_usr_cache_lifetime) {
+ rv = LAS_EVAL_TRUE;
+ *usrobj_out = usrobj;
+ DBG_PRINT4("usr_cache found: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
+ usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
+ usrobj->uid, time);
+ }
+ else {
+ DBG_PRINT4("usr_cache expired: derCert = \"%s\" uid = \"%s\" at time = %ld\n",
+ usrobj->derCert ? (char *)usrobj->derCert->data : "<NONE>",
+ usrobj->uid, time);
+ }
+
+ return rv;
+}
+
+int acl_usr_cache_passwd_check (const char *uid, const char *dbname,
+ const char *passwd,
+ const time_t time, char **dn,
+ pool_handle_t *pool)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj->passwd && passwd &&
+ !strcmp(usrobj->passwd, passwd))
+ {
+ /* extract dn from the usrobj */
+ *dn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
+ rv = LAS_EVAL_TRUE;
+ DBG_PRINT1("Success ");
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_passwd_check: uid = \"%s\" at time = %ld\n",
+ uid, time);
+ user_hash_crit_exit();
+
+ return rv;
+}
+
+
+static int group_check_helper (UserCacheObj *usrobj, void *val)
+{
+ if (usrobj->group && !strcmp(usrobj->group, (char *)val))
+ return LAS_EVAL_TRUE;
+ else
+ return LAS_EVAL_FALSE;
+}
+
+int acl_usr_cache_group_check (const char *uid, const char *dbname,
+ const char *group, const time_t time)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj->group && group &&
+ !strcmp(usrobj->group, group))
+ {
+ DBG_PRINT1("Success ");
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_group_check: uid = \"%s\" group = \"%s\"\n",
+ uid, group ? group : "<NONE>");
+ user_hash_crit_exit();
+
+ return rv;
+}
+
+int acl_usr_cache_group_len_check (const char *uid, const char *dbname,
+ const char *group, const int len,
+ const time_t time)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj->group && group &&
+ !strncmp(usrobj->group, group, len))
+ {
+ rv = LAS_EVAL_TRUE;
+ DBG_PRINT1("Success ");
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_group_check: uid = \"%s\" group = \"%s\"\n",
+ uid, group);
+ user_hash_crit_exit();
+
+ return rv;
+}
+
+
+int acl_usr_cache_get_userdn (const char *uid, const char *dbname,
+ const time_t time, char **userdn,
+ pool_handle_t *pool)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ *userdn = 0;
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE) {
+ *userdn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
+ DBG_PRINT1("Success ");
+ }
+ else {
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_get_userdn: uid = \"%s\" userdn = \"%s\"\n",
+ uid, *userdn ? *userdn : "<NONE>");
+ user_hash_crit_exit();
+
+ return *userdn ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+}
+
+int acl_usr_cache_userdn_check (const char *uid, const char *dbname,
+ const char *userdn, const time_t time)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj->userdn && userdn &&
+ !strcmp(usrobj->userdn, userdn))
+ {
+ DBG_PRINT1("Success ");
+ }
+ else {
+ rv = LAS_EVAL_FALSE;
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_userdn_check: uid = \"%s\" userdn = \"%s\"\n",
+ uid, userdn ? userdn : "<NONE>");
+ user_hash_crit_exit();
+
+ return rv;
+}
+
+int acl_usr_cache_set_userdn (const char *uid, const char *dbname,
+ const char *userdn, const time_t time)
+{
+ int rv;
+
+ /* acl_usr_cache_insert updates the existing un-expired entry or creates a
+ * new one */
+ rv = acl_usr_cache_insert(uid, dbname, userdn, 0, 0, 0, time);
+
+ return rv;
+}
+
+int acl_usr_cache_get_group (const char *uid, const char *dbname,
+ const time_t time, char **group,
+ pool_handle_t *pool)
+{
+ UserCacheObj *usrobj;
+ int rv;
+
+ *group = 0;
+ user_hash_crit_enter();
+ rv = acl_usr_cache_get_usrobj(uid, 0, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE) {
+ *group = usrobj->group ? pool_strdup(pool, usrobj->group) : 0;
+ DBG_PRINT1("Success ");
+ }
+ else {
+ DBG_PRINT1("Failed ");
+ }
+
+ DBG_PRINT3("acl_usr_cache_get_group: uid = \"%s\" group = \"%s\"\n",
+ uid, *group ? *group : "<NONE>");
+ user_hash_crit_exit();
+
+ return *group ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+}
+
+int acl_usr_cache_set_group (const char *uid, const char *dbname,
+ const char *group, const time_t time)
+{
+ int rv;
+
+ /* acl_usr_cache_insert updates the existing un-expired entry or creates a
+ * new one */
+ rv = acl_usr_cache_insert(uid, dbname, 0, 0, group, 0, time);
+
+ return rv;
+}
+
+int acl_cert_cache_insert (void *cert_in, const char *dbname,
+ const char *uid, const char *dn,
+ const time_t time)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ SECItem derCert = cert->derCert;
+ int rv;
+
+ rv = acl_usr_cache_insert(uid, dbname, dn, 0, 0, &derCert, time);
+
+ return rv;
+}
+
+/* Returns LAS_EVAL_TRUE if the user's cache is valid and returns uid */
+int acl_cert_cache_get_uid (void *cert_in, const char *dbname,
+ const time_t time, char **uid, char **dn,
+ pool_handle_t *pool)
+{
+ CERTCertificate *cert = (CERTCertificate *)cert_in;
+ SECItem derCert = cert->derCert;
+ UserCacheObj *usrobj = 0;
+ int rv;
+
+ rv = acl_usr_cache_get_usrobj(0, &derCert, dbname, time, &usrobj);
+
+ if (rv == LAS_EVAL_TRUE && usrobj && usrobj->uid) {
+ *uid = pool_strdup(pool, usrobj->uid);
+ *dn = usrobj->userdn ? pool_strdup(pool, usrobj->userdn) : 0;
+ }
+ else {
+ *uid = 0;
+ *dn = 0;
+ rv = LAS_EVAL_FALSE;
+ }
+
+ return rv;
+}
+
diff --git a/lib/libaccess/utest.mk b/lib/libaccess/utest.mk
new file mode 100644
index 00000000..f33e6e6d
--- /dev/null
+++ b/lib/libaccess/utest.mk
@@ -0,0 +1,61 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+#CFLAGS = -g -DDEBUG -I.
+CFLAGS = -g -I. -I../../../include $(TESTFLAGS)
+#LEX = flex
+CC=gcc
+
+HEAD = aclparse.h acltools.h lparse.h acl.h acleval.h lasdns.h lasip.h mthash.h stubs.h aclscan.h acl.tab.h
+XSRC = aclparse.y aclscan.l
+CSRC = acleval.c aclutil.c lasdns.c lasip.c lastod.c mthash.c testmain.c acltools.c space.c acl.tab.c acl.yy.c
+SRC = $(HEAD) $(XSRC) $(CSRC)
+
+XOBJ = acl.tab.o acl.yy.o testmain.o acltools.o
+COBJ = $(CSRC:%.c=%.o)
+OBJ = $(XOBJ) $(COBJ)
+
+always: $(OBJ)
+
+acleval.o: stubs.h aclparse.h acl.h acleval.h mthash.h
+
+aclutil.o: acl.h aclparse.h
+
+lasdns.o: acl.h aclparse.h lasdns.h mthash.h
+
+lasip.o: acl.h aclparse.h lasip.h
+
+lastod.o: acl.h aclparse.h
+
+acltools.o: aclparse.h aclscan.h lparse.h aclparse.y
+
+testmain.o: aclparse.h acltools.h
+
+acl.yy.o: acl.yy.c acl.tab.h
+
+acl.yy.o acl.tab.o acltools.o: aclparse.h acltools.h lparse.h
+
+yacc: aclparse.y
+ $(YACC) -dv aclparse.y
+ mv y.tab.h acl.tab.h
+ mv y.tab.c acl.tab.c
+#sed -f yy-sed y.tab.h > acl.tab.h
+#sed -f yy-sed y.tab.c > acl.tab.c
+
+# Should only run this on an SGI, where flex() is present
+flex: aclscan.l
+ $(LEX) aclscan.l
+ mv lex.yy.c acl.yy.c
+#sed -f yy-sed lex.yy.c > acl.yy.c
+
+clean:
+ rm -f aclparse aclparse.pure y.output acl.tab.c acl.tab.h acl.yy.c lex.yy.c y.tab.c y.tab.h aclparse.c $(OBJ)
+
+# Check it out from the RCS directory
+$(SRC): RCS/$$@,v
+ co $@
diff --git a/lib/libaccess/utest/.purify b/lib/libaccess/utest/.purify
new file mode 100644
index 00000000..56b9983e
--- /dev/null
+++ b/lib/libaccess/utest/.purify
@@ -0,0 +1,19 @@
+suppress umr process_gethost
+suppress umr _door_gethostbyname_r
+suppress umr _get_hostserv_inetnetdir_byname
+suppress umr _get_hostserv_inetnetdir_byaddr
+suppress umr gethostbyname_r
+suppress umr _nsc_trydoorcall
+suppress umr LASDnsBuild
+suppress umr PR_HashString
+suppress umr mthsearch
+suppress umr Hash
+suppress umr strcmp
+suppress umr mthsearch
+suppress umr strlen
+suppress umr strdup
+suppress umr strcpy
+suppress umr PListFindValue
+suppress umr LASIpEval
+suppress umr LASDnsEval
+suppress mlk system_strdup_perm
diff --git a/lib/libaccess/utest/Makefile b/lib/libaccess/utest/Makefile
new file mode 100644
index 00000000..2acedff0
--- /dev/null
+++ b/lib/libaccess/utest/Makefile
@@ -0,0 +1,119 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+#
+MCOM_ROOT=../../../..
+MODULE=LibAcl
+include ../../../nsdefs.mk
+
+OBJDEST=.
+UTESTDEST=utest
+
+include ../../../nsconfig.mk
+
+MODULE_CFLAGS=-I$(NSROOT)/include/libaccess -I$(NSROOT)/include -I$(NSROOT)/include/public -I. -DACL_LIB_INTERNAL
+
+include $(INCLUDE_DEPENDS)
+
+#TESTFLAGS = -DUTEST -DDEBUG_LEVEL_2
+TESTFLAGS = -DUTEST
+CC = $(CCC)
+
+CSRC = acltest.cpp onetest.cpp ustubs.cpp twotest.cpp
+TSRC = aclfile0 aclfile1 aclfile2 aclfile3 aclfile4 aclfile5 aclfile6 aclfile7 aclfile8 aclfile9 aclfile10 aclfile11 aclfile12 aclfile13 aclfile14 aclfile15 aclfile16 aclfile17 aclfile18 aclfile19 test.ref
+SRC = $(CSRC) $(TSRC)
+XSRC = \
+ ../oneeval.cpp \
+ ../lastod.cpp \
+ ../lasip.cpp \
+ ../aclutil.cpp \
+ ../lasdns.cpp \
+ ../acl.tab.cpp \
+ ../acl.yy.cpp \
+ ../acltools.cpp \
+ ../aclspace.cpp \
+ ../lasgroup.cpp \
+ ../lasuser.cpp \
+ ../lasprogram.cpp \
+ ../nseframe.cpp \
+ ../aclcache.cpp \
+ ../register.cpp \
+ ../symbols.cpp \
+ ../method.cpp \
+ ../authdb.cpp
+
+COBJ = $(CSRC:%.cpp=%.o)
+XOBJ = $(XSRC:../%.cpp=%.o)
+
+# This may be needed for other platforms too
+ifeq ($(ARCH), IRIX)
+XLIBS = -rpath $(LDAP_LIBPATH)
+endif
+
+ifeq ($(ARCH), HPUX)
+XLIBS = -lpthread
+endif
+ifeq ($(ARCH), SOLARIS)
+XLIBS = -lsocket -lnsl -ldl -lposix4
+endif
+
+XLIBS+= $(OBJDIR)/lib/base/plist.o \
+ $(OBJDIR)/lib/base/pool.o \
+ $(OBJDIR)/lib/base/util.o \
+ $(OBJDIR)/lib/base/ereport.o \
+ $(OBJDIR)/lib/base/system.o \
+ $(OBJDIR)/lib/base/shexp.o \
+ $(OBJDIR)/lib/base/pblock.o \
+ $(OBJDIR)/lib/base/file.o \
+ $(OBJDIR)/lib/base/systhr.o \
+ $(OBJDIR)/lib/base/nscperror.o \
+ $(OBJDIR)/lib/libldapu.a \
+ $(LIBNSPR)
+
+all: $(COBJ) $(TSRC) acltest
+ ./acltest > test.out
+ diff test.ref test.out
+ @echo
+ @echo "The unit test is passed if there is no diff output, and the"
+ @echo "Purify window shows no errors and 0 bytes leaked."
+ @echo
+ @echo "Run - gmake coverage - manually to get code coverage analysis."
+ @echo
+
+aclparse: ustubs.o testmain.o $(XOBJ)
+ purify $(CC) -o aclparse testmain.o $(XOBJ) ustubs.o $(XLIBS)
+
+aclparse.pure: acl.tab.o acl.yy.o testmain.o acltools.o ustubs.o
+ purify -user-path=.. $(CC) -o aclparse.pure $(XOBJ) ustubs.o $(XLIBS)
+
+onetest: onetest.o ustubs.o $(XOBJ)
+ $(CC) -o onetest onetest.o $(XOBJ) ustubs.o $(XLIBS)
+
+twotest: twotest.o ustubs.o $(XOBJ)
+ $(CC) -o twotest twotest.o $(XOBJ) ustubs.o $(XLIBS)
+
+acltest: acltest.o ustubs.o $(XOBJ)
+# purify $(CC) -o acltest acltest.o $(XOBJ) ustubs.o $(XLIBS)
+ $(CC) -o acltest acltest.o $(XOBJ) ustubs.o $(XLIBS)
+
+coverage: acltest.o ustubs.o $(XOBJ)
+ purecov $(CC) -o acltestcov acltest.o $(XOBJ) ustubs.o $(XLIBS)
+ rm -f *.pcv
+ acltestcov
+
+lasemail: lasemail.o
+ $(LD) -G -h lasemail.so -o lasemail.so lasemail.o
+
+#$(XOBJ): $(XSRC)
+# cd ..; gmake OBJDEST=$(UTESTDEST) CC=$(OCC) TESTFLAGS=$(TESTFLAGS)
+
+%.o:../%.c
+ $(CC) -c $(CFLAGS) $(TESTFLAGS) $(MCC_INCLUDE) -I.. $< -o $(OBJDEST)/$*.o
+
+%.o:../%.cpp
+ $(CC) -c $(CFLAGS) $(TESTFLAGS) $(MCC_INCLUDE) -I.. $< -o $(OBJDEST)/$*.o
diff --git a/lib/libaccess/utest/acl.dat b/lib/libaccess/utest/acl.dat
new file mode 100644
index 00000000..d640adca
--- /dev/null
+++ b/lib/libaccess/utest/acl.dat
@@ -0,0 +1,12 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+
+acl davids;
+
+deny (all) dns=aruba.mcom.com;
diff --git a/lib/libaccess/utest/aclfile0 b/lib/libaccess/utest/aclfile0
new file mode 100644
index 00000000..8bb2a428
--- /dev/null
+++ b/lib/libaccess/utest/aclfile0
@@ -0,0 +1,55 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile0;
+deny with uri="test";
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+
+acl aclfile0.0;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.1;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.2;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.3;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.4;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.5;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.6;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.7;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.8;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.9;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.10;
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
+acl aclfile0.11;
+allow (read, write, execute) (timeofday<2100);
+acl aclfile0.12;
+authenticate (user, group) {
+ database=franco;
+ method=basic;
+};
+allow (read, write, execute) (timeofday<2100);
+allow (read, write, execute) (dayofweek!=sun or ip="255.255.255.255+*.*.*.*, 255.255.0.0+190.198.162.1");
diff --git a/lib/libaccess/utest/aclfile1 b/lib/libaccess/utest/aclfile1
new file mode 100644
index 00000000..e148f1a1
--- /dev/null
+++ b/lib/libaccess/utest/aclfile1
@@ -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
+#
+version 3.0;
+acl aclfile1;
+deny (read, write, execute) (timeofday<2100);
+deny (read, write, execute) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile10 b/lib/libaccess/utest/aclfile10
new file mode 100644
index 00000000..f0f5a223
--- /dev/null
+++ b/lib/libaccess/utest/aclfile10
@@ -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
+#
+version 3.0;
+acl aclfile10;
+deny absolute (read) ip="17.34.*";
+allow (read,write) timeofday>1700;
+deny (read) dns="*.mcom.com";
+allow (read,write) dayofweek=mon;
diff --git a/lib/libaccess/utest/aclfile11 b/lib/libaccess/utest/aclfile11
new file mode 100644
index 00000000..9fe73cb2
--- /dev/null
+++ b/lib/libaccess/utest/aclfile11
@@ -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
+#
+version 3.0;
+acl aclfile11;
+allow (read) (timeofday<2100);
+allow (html_write, execute) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile12 b/lib/libaccess/utest/aclfile12
new file mode 100644
index 00000000..ac154d7a
--- /dev/null
+++ b/lib/libaccess/utest/aclfile12
@@ -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
+#
+version 3.0;
+acl aclfile12;
+allow (read) (timeofday<2100);
+allow (read, html_write, execute) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile13 b/lib/libaccess/utest/aclfile13
new file mode 100644
index 00000000..7334d03d
--- /dev/null
+++ b/lib/libaccess/utest/aclfile13
@@ -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
+#
+version 3.0;
+acl aclfile13;
+allow (read) (ip="17.34.1.1+255.255.0.0");
+allow (html_write) (dns!="*.microsoft.com");
diff --git a/lib/libaccess/utest/aclfile14 b/lib/libaccess/utest/aclfile14
new file mode 100644
index 00000000..5fc5c706
--- /dev/null
+++ b/lib/libaccess/utest/aclfile14
@@ -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
+#
+version 3.0;
+acl aclfile14;
+allow (read, write) (ip="17.34.*");
+deny (write) (dns!="*.mcom.com");
diff --git a/lib/libaccess/utest/aclfile15 b/lib/libaccess/utest/aclfile15
new file mode 100644
index 00000000..2d8701ec
--- /dev/null
+++ b/lib/libaccess/utest/aclfile15
@@ -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
+#
+version 3.0;
+acl aclfile15;
+allow (html_read, write) (dns="*.mcom.com");
+deny (read) (ip="17.34.*");
diff --git a/lib/libaccess/utest/aclfile16 b/lib/libaccess/utest/aclfile16
new file mode 100644
index 00000000..54ce99f8
--- /dev/null
+++ b/lib/libaccess/utest/aclfile16
@@ -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
+#
+version 3.0;
+acl aclfile16;
+allow (html_read, write) (dns="*.mcom.com");
+deny (read) (ip="17.34.1.1 + 255.255.0.0");
diff --git a/lib/libaccess/utest/aclfile17 b/lib/libaccess/utest/aclfile17
new file mode 100644
index 00000000..128076f3
--- /dev/null
+++ b/lib/libaccess/utest/aclfile17
@@ -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
+#
+version 3.0;
+acl aclfile17;
+allow absolute (all) (dns="*.mcom.com");
+deny (read) (ip="17.34.1.1+255.255.0.0");
diff --git a/lib/libaccess/utest/aclfile18 b/lib/libaccess/utest/aclfile18
new file mode 100644
index 00000000..4a80bc27
--- /dev/null
+++ b/lib/libaccess/utest/aclfile18
@@ -0,0 +1,19 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile18;
+authenticate (user) {
+ method=SSL;
+ database=LDAP;
+};
+allow (read, write, execute, create) dns="*.mcom.com";
+authenticate (user) {
+ method=basic;
+ database=20;
+};
+allow (read, write, execute, create) (timeofday>1700 or timeofday<0800);
diff --git a/lib/libaccess/utest/aclfile19 b/lib/libaccess/utest/aclfile19
new file mode 100644
index 00000000..4433f4c7
--- /dev/null
+++ b/lib/libaccess/utest/aclfile19
@@ -0,0 +1,14 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclfile19A;
+deny (read, write, execute, create) dns!="*.mcom.com";
+allow absolute (read) ((timeofday>1700 or timeofday<0800) or dayofweek=satsunmon);
+
+acl aclfile19B;
+deny (write) dns="*.mcom.com";
diff --git a/lib/libaccess/utest/aclfile2 b/lib/libaccess/utest/aclfile2
new file mode 100644
index 00000000..eee5c30c
--- /dev/null
+++ b/lib/libaccess/utest/aclfile2
@@ -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
+#
+version 3.0;
+acl aclfile2;
+deny (read) (timeofday<2100);
+deny (read) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile3 b/lib/libaccess/utest/aclfile3
new file mode 100644
index 00000000..094c1abe
--- /dev/null
+++ b/lib/libaccess/utest/aclfile3
@@ -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
+#
+version 3.0;
+acl aclfile3;
+allow (read) (timeofday<2100);
+allow (read) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile4 b/lib/libaccess/utest/aclfile4
new file mode 100644
index 00000000..befc7b4b
--- /dev/null
+++ b/lib/libaccess/utest/aclfile4
@@ -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
+#
+version 3.0;
+acl aclfile4;
+allow (read) (timeofday>0700);
+allow (write) (dayofweek!=sun);
diff --git a/lib/libaccess/utest/aclfile5 b/lib/libaccess/utest/aclfile5
new file mode 100644
index 00000000..8b0e1e8d
--- /dev/null
+++ b/lib/libaccess/utest/aclfile5
@@ -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
+#
+version 3.0;
+acl aclfile5;
+allow (read) (ip="17.34.*");
+allow (write) (dns!="*.microsoft.com");
diff --git a/lib/libaccess/utest/aclfile6 b/lib/libaccess/utest/aclfile6
new file mode 100644
index 00000000..9646b548
--- /dev/null
+++ b/lib/libaccess/utest/aclfile6
@@ -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
+#
+version 3.0;
+acl aclfile6;
+allow (read,
+write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+allow (read, write) (ip="17.34.*");
+deny (write)
+(dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
+deny (write) (dns!="*.mcom.com");
diff --git a/lib/libaccess/utest/aclfile7 b/lib/libaccess/utest/aclfile7
new file mode 100644
index 00000000..d8f9aa13
--- /dev/null
+++ b/lib/libaccess/utest/aclfile7
@@ -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
+#
+version 3.0;
+acl aclfile7;
+allow (read,write) (dns="*.mcom.com");
+deny (read) (ip="17.34.*");
diff --git a/lib/libaccess/utest/aclfile8 b/lib/libaccess/utest/aclfile8
new file mode 100644
index 00000000..b11cfe7e
--- /dev/null
+++ b/lib/libaccess/utest/aclfile8
@@ -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
+#
+version 3.0;
+acl aclfile8;
+allow (read, write, execute, create) dns="*.mcom.com";
+allow (read, write, execute, create) (timeofday>1700 or timeofday<0800);
diff --git a/lib/libaccess/utest/aclfile9 b/lib/libaccess/utest/aclfile9
new file mode 100644
index 00000000..2a0ab35e
--- /dev/null
+++ b/lib/libaccess/utest/aclfile9
@@ -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
+#
+version 3.0;
+acl aclfile9;
+deny (read) ip="*.34.*+*.128.*.0";
+allow (read, write, execute, create) ((timeofday>1700 or timeofday<0800) or dayofweek=satsunmon);
diff --git a/lib/libaccess/utest/aclgrp0 b/lib/libaccess/utest/aclgrp0
new file mode 100644
index 00000000..ba08fbf1
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp0
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp0;
+allow (read, write, execute) (group = marketing or group!="Directory Administrators");
diff --git a/lib/libaccess/utest/aclgrp1 b/lib/libaccess/utest/aclgrp1
new file mode 100644
index 00000000..7a804404
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp1
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp1;
+allow (read, write, execute) (group!="Directory Administrators");
diff --git a/lib/libaccess/utest/aclgrp2 b/lib/libaccess/utest/aclgrp2
new file mode 100644
index 00000000..13938c19
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp2
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp2;
+allow (read, write, execute) (group=marketing);
diff --git a/lib/libaccess/utest/aclgrp3 b/lib/libaccess/utest/aclgrp3
new file mode 100644
index 00000000..30b44d5c
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp3
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp3;
+allow (read, write, execute) (group>"Directory Admin,marketing");
diff --git a/lib/libaccess/utest/aclgrp4 b/lib/libaccess/utest/aclgrp4
new file mode 100644
index 00000000..5b07d6c2
--- /dev/null
+++ b/lib/libaccess/utest/aclgrp4
@@ -0,0 +1,10 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+version 3.0;
+acl aclgrp4;
+allow (read, write, execute) (group = " marketing ,, Directory Administrators ,, ");
diff --git a/lib/libaccess/utest/acltest.cpp b/lib/libaccess/utest/acltest.cpp
new file mode 100644
index 00000000..c643f873
--- /dev/null
+++ b/lib/libaccess/utest/acltest.cpp
@@ -0,0 +1,796 @@
+/** 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 <netsite.h>
+#include <base/session.h>
+#include <base/daemon.h>
+#include <base/systhr.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+#include "../aclcache.h"
+#include <libaccess/las.h>
+
+
+extern ACLListHandle_t *ACL_ParseFile(NSErr_t *errp, char *filename);
+
+int
+TestEvalFunc(NSErr_t *errp, char *attr, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable,
+ void **las_cookie, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ return 0;
+}
+
+void
+TestFlushFunc(void **cookie)
+{
+ return;
+}
+
+static int parse_dburl (NSErr_t *errp, ACLDbType_t dbtype,
+ const char *dbname, const char *url,
+ PList_t plist, void **db)
+{
+ *db = strdup(url);
+ return 0;
+}
+
+
+main()
+{
+ ACLListHandle_t *acl_list;
+ int result;
+ ACLCachable_t cachable = 0;
+ void *las_cookie=NULL;
+ ACLEvalHandle_t eval;
+ char *rights[3];
+ char filename[20];
+ char newfilename[25];
+ int i;
+ char *map_generic[7];
+ LASEvalFunc_t Eval_funcp;
+ LASFlushFunc_t Flush_funcp;
+ char *bong;
+ char *bong_type;
+ char *acl_tag;
+ int expr_num;
+ int ii;
+ char **name_list;
+ ACLMethod_t method=NULL;
+ ACLDbType_t dbtype=NULL;
+ int rv;
+ ACLAttrGetterList_t aglist;
+ ACLAttrGetter_t *agptr;
+ char **names;
+ int cnt;
+
+ systhread_init("acl_utest");
+
+ char *acl_file_list[3] = {"aclfile6", "aclfile7", NULL};
+ char *new_filename = "merge6_7";
+ char *acl_name_list[3] = {"aclfile6", "aclfile7", NULL};
+ char *new_aclname = "merge6_7";
+ char *bad_acl_file_list[3] = {"bad_aclfile6", "bad_aclfile7", NULL};
+
+ if ( ACL_FileMergeFile(NULL, new_filename, bad_acl_file_list, 0) < 0 ) {
+ printf("Failed ACL_FileMergeFile() test.\n");
+ }
+
+ if ( ACL_FileMergeFile(NULL, new_filename, acl_file_list, 0) < 0 ) {
+ printf("Failed ACL_FileMergeFile() test.\n");
+ }
+
+ if ( ACL_FileMergeAcl(NULL, new_filename, acl_name_list, new_aclname, 0) < 0 ) {
+ printf("Failed ACL_FileMergeAcl() test.\n");
+ }
+
+ /* LAS Registration Unit Tests */
+
+ ACL_Init();
+
+ rv = ACL_MethodRegister(NULL, "one", &method);
+ printf("Method one is #%d, rv=%d\n", (int)method, rv);
+
+ rv = ACL_MethodRegister(NULL, "two", &method);
+ printf("Method two is #%d, rv=%d\n", (int)method, rv);
+
+ rv = ACL_MethodRegister(NULL, "one", &method);
+ printf("Method one repeated is #%d, rv=%d\n", (int)method, rv);
+
+ rv = ACL_MethodRegister(NULL, "three", &method);
+ printf("Method three is #%d, rv=%d\n", (int)method, rv);
+
+ rv = ACL_MethodNamesGet(NULL, &names, &cnt);
+
+ for(i = 0; i < cnt; i++) {
+ printf("\tMethod[%d] = \"%s\"\n", i, names[i]);
+ }
+
+ ACL_MethodNamesFree(NULL, names, cnt);
+
+ if (!ACL_MethodIsEqual(NULL, method, method)) {
+ printf("Error comparing methods");
+ }
+
+ if (!ACL_MethodNameIsEqual(NULL, method, "three")) {
+ printf("Error comparing method by name");
+ }
+
+ /* Since LDAP is already registered by ACL_Init, the first number
+ * we'll get is actually 2.
+ */
+ rv = ACL_DbTypeRegister(NULL, "two", parse_dburl, &dbtype);
+ printf("DbType two is #%d, rv=%d\n", (int)dbtype, rv);
+
+ rv = ACL_DbTypeRegister(NULL, "three", parse_dburl, &dbtype);
+ printf("DbType three is #%d, rv=%d\n", (int)dbtype, rv);
+
+ rv = ACL_DbTypeRegister(NULL, "two", parse_dburl, &dbtype);
+ printf("DbType two repeated is #%d, rv=%d\n", (int)dbtype, rv);
+
+ rv = ACL_DbTypeRegister(NULL, "four", parse_dburl, &dbtype);
+ printf("DbType four is #%d, rv=%d\n", (int)dbtype, rv);
+
+ if (!ACL_DbTypeIsEqual(NULL, dbtype, dbtype)) {
+ printf("Error comparing dbtypes\n");
+ }
+
+ if (!ACL_DbTypeNameIsEqual(NULL, dbtype, "four")) {
+ printf("Error comparing dbtype by name\n");
+ }
+
+ rv = ACL_DatabaseRegister(NULL, dbtype, "db1", "url for db1", NULL);
+ if (rv < 0) {
+ printf("ACL_DatabaseRegister failed for db1\n");
+ }
+
+ rv = ACL_DatabaseRegister(NULL, dbtype, "db2", "url for db2", NULL);
+ if (rv < 0) {
+ printf("ACL_DatabaseRegister failed for db2\n");
+ }
+
+ rv = ACL_DatabaseRegister(NULL, dbtype, "db3", "url for db3", NULL);
+ if (rv < 0) {
+ printf("ACL_DatabaseRegister failed for db3\n");
+ }
+
+ rv = ACL_DatabaseNamesGet(NULL, &names, &cnt);
+
+ for(i = 0; i < cnt; i++) {
+ printf("\tDatabase[%d] = \"%s\"\n", i, names[i]);
+ }
+
+ if (ACL_AttrGetterRegister(NULL, "attr", (ACLAttrGetterFn_t)2, (ACLMethod_t)10, (ACLDbType_t)20, ACL_AT_FRONT, NULL)) {
+ printf("Error registering attr getter\n");
+ }
+
+ if (ACL_AttrGetterRegister(NULL, "attr", (ACLAttrGetterFn_t)3, (ACLMethod_t)10, (ACLDbType_t)20, ACL_AT_END, NULL)) {
+ printf("Error registering attr getter\n");
+ }
+
+ if (ACL_AttrGetterRegister(NULL, "attr", (ACLAttrGetterFn_t)1, (ACLMethod_t)10, (ACLDbType_t)20, ACL_AT_FRONT, NULL)) {
+ printf("Error registering attr getter\n");
+ }
+
+ if (ACL_AttrGetterRegister(NULL, "attr", (ACLAttrGetterFn_t)4, (ACLMethod_t)10, (ACLDbType_t)20, ACL_AT_END, NULL)) {
+ printf("Error registering attr getter\n");
+ }
+
+ if (ACL_AttrGetterFind(NULL, "attr", &aglist)) {
+ printf("Error finding attr getter\n");
+ }
+
+ for (i = 0, agptr = ACL_AttrGetterFirst(&aglist);
+ i < 4;
+ i++, agptr = ACL_AttrGetterNext(&aglist, agptr)) {
+
+ if (agptr) {
+ printf("position %d\n", (int)(agptr->fn));
+ }
+ else {
+ printf("***Error: missing getter ***\n");
+ }
+ }
+
+#ifndef XP_WIN32
+ if (ACL_LasRegister(NULL, "test_attr", TestEvalFunc, TestFlushFunc)) {
+ printf("Error registering Test LAS functions\n");
+ }
+ ACL_LasFindEval(NULL, "test_attr", &Eval_funcp);
+ if (Eval_funcp != TestEvalFunc) {
+ printf("Error finding Eval function - expecting %x, got %x\n",
+ TestEvalFunc, Eval_funcp);
+ }
+ ACL_LasFindFlush(NULL, "test_attr", &Flush_funcp);
+ if (Flush_funcp != TestFlushFunc) {
+ printf("Error finding Flush function - expecting %x, got %x\n",
+ TestFlushFunc, Flush_funcp);
+ }
+ ACL_LasFindEval(NULL, "wrong_attr", &Eval_funcp);
+ if (Eval_funcp != NULL) {
+ printf("Error finding Eval function - expecting NULL, got %x\n",
+ Eval_funcp);
+ }
+ ACL_LasFindFlush(NULL, "wrong_attr", &Flush_funcp);
+ if (Flush_funcp != NULL) {
+ printf("Error finding Flush function - expecting NULL, got %x\n",
+ Flush_funcp);
+ }
+#endif /* !XP_WIN32 */
+
+ /* ACL Eval Unit Tests
+ */
+ rights[0] = "http_get";
+ rights[1] = "http_post";
+ rights[2] = NULL;
+
+ eval.subject = NULL;
+ eval.resource = NULL;
+
+ for (i=0; i<10; i++) {
+ sprintf(filename, "aclfile%d", i);
+ eval.acllist = ACL_ParseFile((NSErr_t *)NULL, filename);
+ if ( eval.acllist == NULL ) {
+ printf("Couldn't parse.\n");
+ continue;
+ }
+
+ sprintf(newfilename, "%s.v30", filename);
+ if ( ACL_WriteFile(NULL, newfilename, eval.acllist) < 0) {
+ printf("Couldn't write %s.\n", newfilename);
+ }
+ result = ACL_EvalTestRights(NULL, &eval, &rights[0],
+ http_generic, &bong, &bong_type, &acl_tag, &expr_num);
+ ACL_ListDestroy(NULL, eval.acllist);
+ printf("%s = %d\n\n", filename, result);
+ }
+
+/********************************************************************
+
+ TEST #1
+
+ TEST ACL_ParseString()
+ TEST ACL_WriteFile()
+ TEST ACL_ParseFile()
+ TEST ACL_ListFind()
+
+*********************************************************************/
+ acl_list = ACL_ParseString((NSErr_t *)NULL,
+ "version 3.0; acl > franco;");
+ if ( acl_list != NULL ) {
+ ACL_ListDestroy(NULL, acl_list);
+ printf("Test #1a fails parsed invalid ACL\n");
+ goto skip_test;
+ }
+
+ acl_list = ACL_ParseString((NSErr_t *)NULL,
+ "version 3.0; acl franco; \nallow (read) user=franco;");
+ if ( acl_list == NULL ) {
+ printf("Test #1b fails couldn't parse valid ACL\n");
+ goto skip_test;
+ } else {
+ if ( ACL_WriteFile(NULL, "buffer", acl_list) < 0) {
+ printf("Test #1b, couldn't write %s.\n", "buffer");
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+ acl_list = ACL_ParseString((NSErr_t *)NULL,
+ "version 3.0; acl franco; \njunk (read) user=franco;");
+
+ if ( acl_list != NULL ) {
+ printf("Test #1c failed missed syntax error\n");
+ ACL_ListDestroy(NULL, acl_list);
+ goto skip_test;
+ }
+
+ acl_list = ACL_ParseString((NSErr_t *)NULL,
+ "version 3.0; acl franco; \nallow (read) user=franco;");
+
+ if ( acl_list == NULL ) {
+ printf("Test #1d couldn't parse valid ACL\n");
+ } else {
+ ACL_ListDestroy(NULL, acl_list);
+ goto skip_test;
+ }
+
+ acl_list= ACL_ParseFile((NSErr_t *)NULL, "buffer");
+ if ( acl_list == NULL ) {
+ printf("Test #1e, couldn't perform ACL_ParseFile(buffer)\n");
+ goto skip_test;
+ } else {
+ if ( ACL_ListFind(NULL, acl_list, "franco", ACL_CASE_INSENSITIVE) == NULL ) {
+ printf("Test #1e, couldn't find %s in %s.\n", "franco", "buffer");
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+/********************************************************************
+
+ TEST #2
+
+ TEST ACL_FileDeleteAcl()
+ TEST ACL_ParseFile()
+ TEST ACL_ListFind()
+
+*********************************************************************/
+ if ( ACL_FileDeleteAcl(NULL, "buffer", "franco", ACL_CASE_INSENSITIVE) < 0) {
+ printf("Test #2, couldn't write %s.\n", "buffer");
+ }
+ acl_list= ACL_ParseFile((NSErr_t *)NULL, "buffer");
+ if ( acl_list == NULL ) {
+ printf("Test #2, couldn't perform ACL_ParseFile(buffer)\n");
+ goto skip_test;
+ } else {
+ if ( ACL_ListFind(NULL, acl_list, "franco", ACL_CASE_INSENSITIVE) ) {
+ printf("Couldn't delete %s from %s.\n", "franco", "buffer");
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+/********************************************************************
+
+ TEST #3
+
+ TEST ACL_FileSetAcl()
+ TEST ACL_ParseFile()
+ TEST ACL_ListFind()
+
+*********************************************************************/
+ if ( ACL_FileSetAcl(NULL, "buffer",
+ "version 3.0; acl FileSetAcl; \nallow (read) user=franco;",
+ ACL_CASE_INSENSITIVE)< 0) {
+ printf("Test #3, couldn't ACL_FileSetACL(%s).\n", "FileSetAcl");
+ }
+ if ( ACL_FileSetAcl(NULL, "buffer",
+ "version 3.0; acl franco; \nallow (read) user=franco;",
+ ACL_CASE_INSENSITIVE)< 0) {
+ printf("Test #3, couldn't ACL_FileSetACL(%s).\n", "franco");
+ }
+ acl_list= ACL_ParseFile((NSErr_t *)NULL, "buffer");
+ if ( acl_list == NULL ) {
+ printf("Test #3, couldn't perform ACL_ParseFile(buffer)\n");
+ goto skip_test;
+ } else {
+ if ( ACL_ListFind(NULL, acl_list, "franco", ACL_CASE_INSENSITIVE) == NULL) {
+ printf("Test #3, couldn't set %s in %s.\n", "franco", "buffer");
+ }
+ if ( ACL_ListFind(NULL, acl_list, "filesetacl", ACL_CASE_INSENSITIVE) == NULL) {
+ printf("Test #3, couldn't set %s in %s.\n", "filesetacl", "buffer");
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+/********************************************************************
+
+ TEST #4
+
+ TEST ACL_FileRenameAcl()
+ TEST ACL_ParseFile()
+ TEST ACL_ListFind()
+
+*********************************************************************/
+ if ( ACL_FileRenameAcl(NULL, "buffer", "FileSetAcl", "loser", ACL_CASE_INSENSITIVE)< 0) {
+ printf("Test #4, fail ACL_FileRenameACL(filesetacl, loser).\n");
+ }
+ if ( ACL_FileRenameAcl(NULL, "buffer", "franco", "bigdogs",
+ ACL_CASE_INSENSITIVE)< 0) {
+ printf("Test #4, fail ACL_FileRenameACL(franco, bigdogs).\n");
+ }
+ acl_list= ACL_ParseFile((NSErr_t *)NULL, "buffer");
+ if ( acl_list == NULL ) {
+ printf("Test #3, couldn't perform ACL_ParseFile(buffer)\n");
+ goto skip_test;
+ } else {
+ if ( ACL_ListFind(NULL, acl_list, "loser", ACL_CASE_INSENSITIVE) == NULL) {
+ printf("Test #4, fail rename %s in %s.\n", "loser", "buffer");
+ }
+ if ( ACL_ListFind(NULL, acl_list, "bigdogs", ACL_CASE_INSENSITIVE) == NULL) {
+ printf("Test #4, fail rename %s in %s.\n", "bigdogs", "buffer");
+ }
+ if ( ACL_ListGetNameList(NULL, acl_list, &name_list) < 0 ) {
+ printf("Test #4, yikes, the GetNameList failed.\n");
+ } else {
+ for (ii = 0; name_list[ii]; ii++)
+ printf("ACL %s\n", name_list[ii]);
+ ACL_NameListDestroy(NULL, name_list);
+ }
+ ACL_ListDestroy(NULL, acl_list);
+ }
+
+
+
+
+skip_test:
+/********************************************************************
+
+ END
+
+*********************************************************************/
+
+ rights[0] = "html_read";
+ rights[1] = "html_write";
+
+ map_generic[0] = "html_read";
+ map_generic[1] = "html_write";
+ map_generic[2] = "N/A";
+ map_generic[3] = "html_create";
+ map_generic[4] = "html_delete";
+ map_generic[5] = "N/A";
+ map_generic[6] = NULL;
+
+ for (i=10; i<20; i++) {
+ sprintf(filename, "aclfile%d", i);
+ eval.acllist = ACL_ParseFile((NSErr_t *)NULL, filename);
+ if ( eval.acllist == NULL ) {
+ printf("Parse failed.\n");
+ continue;
+ }
+ result = ACL_EvalTestRights(NULL, &eval, &rights[0], map_generic, &bong, &bong_type, &acl_tag, &expr_num);
+ ACL_ListDestroy(NULL, eval.acllist);
+ printf("%s = %d\n\n", filename, result);
+ }
+
+ /*
+ * Program LAS Unit Tests
+ */
+ char *groups[32] = {
+ "http-foo",
+ "http-bar",
+ "http-grog",
+ NULL
+ };
+ char *programs[32] = {
+ "foo, fubar, frobozz",
+ "bar, shoo, fly",
+ "grog, beer",
+ NULL
+ };
+ struct program_groups program_groups;
+ program_groups.groups = groups;
+ program_groups.programs = programs;
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo, http-bar,http-grog", &cachable, &las_cookie, (PList_t)"foo", (PList_t)&program_groups, NULL, NULL);
+ printf("program = foo %d\n\n", result);
+
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo, http-bar,http-grog", &cachable, &las_cookie, (PList_t)"nomatch", (PList_t)&program_groups, NULL, NULL);
+ printf("program = nomatch %d\n\n", result);
+
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo, http-bar,http-grog", &cachable, &las_cookie, (PList_t)"beer", (PList_t)&program_groups, NULL, NULL);
+ printf("program = beer %d\n\n", result);
+
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo, http-bar, http-grog", &cachable, &las_cookie, (PList_t)"http-grog", (PList_t)&program_groups, NULL, NULL);
+ printf("program = http-grog %d\n\n", result);
+
+ result = LASProgramEval(NULL, "program", CMP_OP_EQ, "http-foo", &cachable, &las_cookie, (PList_t)"ubar", (PList_t)&program_groups, NULL, NULL);
+ printf("program = ubar %d\n\n", result);
+
+
+ /*
+ * DNS LAS Unit Tests
+ */
+
+ result = LASDnsEval(NULL, "dnsalias", CMP_OP_EQ, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dnsalias = *? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dnsalias", CMP_OP_EQ, "aruba.mcom.com brain251.mcom.com", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dnsalias = aruba.mcom.com brain251.mcom.com? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = *? %d\n\n", result);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_NE, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns != *? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "aruba.mcom.com", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = aruba.mcom.com? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "ai.mit.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = ai.mit.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "*.ai.mit.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = *.ai.mit.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "*.mit.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = *.mit.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_EQ, "*.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns = *.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_NE, "*.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns != *.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "mistake", CMP_OP_NE, "*.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("mistake != *.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+ result = LASDnsEval(NULL, "dns", CMP_OP_GT, "*.edu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("dns > *.edu? %d\n\n", result);
+
+ LASDnsFlush(&las_cookie);
+
+
+ /*
+ * IP LAS Unit Tests
+ */
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = *? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_NE, "*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip != *? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "*.*.*.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = *.*.*.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.*.*.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.*.*.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.*.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.*.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.*", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.*? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.*+255.255.255.255", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.*+255.255.255.255? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.69+255.255.255.254, 123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.69+255.255.255.254, 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_NE, "17.34.51.69+255.255.255.254, 123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip != 17.34.51.69+255.255.255.254, 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.68, 17.34.51.69", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.68, 17.34.51.69? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.68, 17.34.51.69, 123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.68, 17.34.51.69, 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_NE, "17.34.51.68, 17.34.51.69, 123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip != 17.34.51.68, 17.34.51.69, 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.68", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.68? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.69", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.69? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.51.69+255.255.255.254", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.51.69+255.255.255.254? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.34.50.69+255.255.254.0", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.34.50.69+255.255.254.0? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "17.35.50.69+255.254.0.0", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 17.35.50.69+255.254.0.0? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "16.35.50.69+254.0.0.0", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 16.35.50.69+254.0.0.0? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_EQ, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip = 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_NE, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip != 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_GT, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip > 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_LT, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip < 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_GE, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip >= 123.45.67.89? %d\n\n", result);
+
+ result = LASIpEval(NULL, "ip", CMP_OP_LE, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("ip <= 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+ result = LASIpEval(NULL, "mistake", CMP_OP_LE, "123.45.67.89", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf ("mistake <= 123.45.67.89? %d\n\n", result);
+
+ LASIpFlush(&las_cookie);
+
+
+ /*
+ * Time of Day unit tests.
+ */
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GT, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time > 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LT, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time < 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GT, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time > 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LT, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time < 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GT, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time > 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LT, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time < 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GE, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time >= 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LE, "2120", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time <= 2120? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GE, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time >= 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LE, "0700", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time <= 0700? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_GE, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time >= 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LE, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time <= 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "mistake", CMP_OP_LE, "2400", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("mistake <= 2400? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "0800-2200", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 0800-2200? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "0800-2200", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 0800-2200? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_EQ, "2200-0800", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time = 2200-0800? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_NE, "2200-0800", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time != 2200-0800? %d\n\n", result);
+
+ result = LASTimeOfDayEval(NULL, "timeofday", CMP_OP_LE, "2200-0800", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("time <= 2200-0800? %d\n\n", result);
+
+
+ /*
+ * Day Of Week Unit Tests
+ */
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "Mon", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= mon? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "tUe", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= tUe? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "weD", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= weD? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "THu", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= THu? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "FrI", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= FrI? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "sAT", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= tUe? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_EQ, "mon,tuewed,thu,frisatsun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("= mon,tuewed,thu,frisatsun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_NE, "mon,tuewed,thu,frisatsun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("!= mon,tuewed,thu,frisatsun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_GT, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("> Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_LT, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("< Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_GE, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf(">= Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "dayofweek", CMP_OP_LE, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("<= Sun? %d\n\n", result);
+
+ result = LASDayOfWeekEval(NULL, "mistake", CMP_OP_LE, "Sun", &cachable, &las_cookie, NULL, NULL, NULL, NULL);
+ printf("mistake <= Sun? %d\n\n", result);
+
+
+ ACL_Destroy();
+
+ exit(0);
+
+}
diff --git a/lib/libaccess/utest/lasemail.cpp b/lib/libaccess/utest/lasemail.cpp
new file mode 100644
index 00000000..469a315f
--- /dev/null
+++ b/lib/libaccess/utest/lasemail.cpp
@@ -0,0 +1,180 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/* lasemail.cpp
+ * This file contains the Email LAS code.
+ */
+
+#include <ldap.h>
+#include <nsacl/aclapi.h>
+
+#define ACL_ATTR_EMAIL "email"
+
+extern "C" {
+extern int LASEmailEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator, char *attr_pattern, ACLCachable_t *cachable, void **LAS_cookie, PList_t subject, PList_t resource, PList_t auth_info, PList_t global_auth);
+extern void LASEmailFlush(void **las_cookie);
+extern int LASEmailModuleInit();
+}
+
+
+/*
+ * LASEmailEval
+ * INPUT
+ * attr_name The string "email" - in lower case.
+ * comparator CMP_OP_EQ or CMP_OP_NE only
+ * attr_pattern A comma-separated list of emails
+ * (we currently support only one e-mail addr)
+ * *cachable Always set to ACL_NOT_CACHABLE.
+ * subject Subject property list
+ * resource Resource property list
+ * auth_info Authentication info, if any
+ * RETURNS
+ * retcode The usual LAS return codes.
+ */
+int LASEmailEval(NSErr_t *errp, char *attr_name, CmpOp_t comparator,
+ char *attr_pattern, ACLCachable_t *cachable,
+ void **LAS_cookie, PList_t subject, PList_t resource,
+ PList_t auth_info, PList_t global_auth)
+{
+ char *uid;
+ char *email;
+ int rv;
+ LDAP *ld;
+ char *basedn;
+ LDAPMessage *res;
+ int numEntries;
+ char filter[1024];
+ int matched;
+
+ *cachable = ACL_NOT_CACHABLE;
+ *LAS_cookie = (void *)0;
+
+ if (strcmp(attr_name, ACL_ATTR_EMAIL) != 0) {
+ fprintf(stderr, "LASEmailEval called for incorrect attr \"%s\"\n",
+ attr_name);
+ return LAS_EVAL_INVALID;
+ }
+
+ if ((comparator != CMP_OP_EQ) && (comparator != CMP_OP_NE)) {
+ fprintf(stderr, "LASEmailEval called with incorrect comparator %d\n",
+ comparator);
+ return LAS_EVAL_INVALID;
+ }
+
+ if (!strcmp(attr_pattern, "anyone")) {
+ *cachable = ACL_INDEF_CACHABLE;
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ /* get the authenticated user name */
+ rv = ACL_GetAttribute(errp, ACL_ATTR_USER, (void **)&uid,
+ subject, resource, auth_info, global_auth);
+
+ if (rv != LAS_EVAL_TRUE) {
+ return rv;
+ }
+
+ /* We have an authenticated user */
+ if (!strcmp(attr_pattern, "all")) {
+ return comparator == CMP_OP_EQ ? LAS_EVAL_TRUE : LAS_EVAL_FALSE;
+ }
+
+ /* do an ldap lookup for: (& (uid=<user>) (mail=<email>)) */
+ rv = ACL_LDAPDatabaseHandle(errp, NULL, &ld, &basedn);
+
+ if (rv != LAS_EVAL_TRUE) {
+ fprintf(stderr, "unable to get LDAP handle\n");
+ return rv;
+ }
+
+ /* Formulate the filter -- assume single e-mail in attr_pattern */
+ /* If we support multiple comma separated e-mail addresses in the
+ * attr_pattern then the filter will look like:
+ * (& (uid=<user>) (| (mail=<email1>) (mail=<email2>)))
+ */
+ sprintf(filter, "(& (uid=%s) (mail=%s))", uid, attr_pattern);
+
+ rv = ldap_search_s(ld, basedn, LDAP_SCOPE_SUBTREE, filter,
+ 0, 0, &res);
+
+ if (rv != LDAP_SUCCESS)
+ {
+ fprintf(stderr, "ldap_search_s: %s\n", ldap_err2string(rv));
+ return LAS_EVAL_FAIL;
+ }
+
+ numEntries = ldap_count_entries(ld, res);
+
+ if (numEntries == 1) {
+ /* success */
+ LDAPMessage *entry = ldap_first_entry(ld, res);
+ char *dn = ldap_get_dn(ld, entry);
+
+ fprintf(stderr, "ldap_search_s: Entry found. DN: \"%s\"\n", dn);
+ ldap_memfree(dn);
+ matched = 1;
+ }
+ else if (numEntries == 0) {
+ /* not found -- but not an error */
+ fprintf(stderr, "ldap_search_s: Entry not found. Filter: \"%s\"\n",
+ filter);
+ matched = 0;
+ }
+ else if (numEntries > 0) {
+ /* Found more than one entry! */
+ fprintf(stderr, "ldap_search_s: Found more than one entry. Filter: \"%s\"\n",
+ filter);
+ return LAS_EVAL_FAIL;
+ }
+
+ if (comparator == CMP_OP_EQ) {
+ rv = (matched ? LAS_EVAL_TRUE : LAS_EVAL_FALSE);
+ }
+ else {
+ rv = (matched ? LAS_EVAL_FALSE : LAS_EVAL_TRUE);
+ }
+
+ return rv;
+}
+
+
+/* LASEmailFlush
+ * Deallocates any memory previously allocated by the LAS
+ */
+void
+LASEmailFlush(void **las_cookie)
+{
+ /* do nothing */
+ return;
+}
+
+/* LASEmailModuleInit --
+ * Register the e-mail LAS.
+ *
+ * To load this functions in the web server, compile the file in
+ * "lasemail.so" and add the following lines to the
+ * <ServerRoot>/https-<name>/config/obj.conf file. Be sure to change the
+ * "lasemail.so" portion to the full pathname. E.g. /nshome/lib/lasemail.so.
+ *
+ * Init fn="load-modules" funcs="LASEmailModuleInit" shlib="lasemail.so"
+ * Init fn="acl-register-module" module="lasemail" func="LASEmailModuleInit"
+ */
+int LASEmailModuleInit ()
+{
+ NSErr_t err = NSERRINIT;
+ NSErr_t *errp = &err;
+ int rv;
+
+ rv = ACL_LasRegister(errp, ACL_ATTR_EMAIL, LASEmailEval, LASEmailFlush);
+
+ if (rv < 0) {
+ fprintf(stderr, "ACL_LasRegister failed. Error: %d\n", rv);
+ return rv;
+ }
+
+ return rv;
+}
+
diff --git a/lib/libaccess/utest/onetest.cpp b/lib/libaccess/utest/onetest.cpp
new file mode 100644
index 00000000..3bcccbb1
--- /dev/null
+++ b/lib/libaccess/utest/onetest.cpp
@@ -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 **/
+#include <stdio.h>
+#include <netsite.h>
+#include <libaccess/nserror.h>
+#include <base/session.h>
+#include <libaccess/acl.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+#include <base/plist.h>
+#include <base/ereport.h>
+
+extern ACLListHandle_t *ACL_ParseFile(NSErr_t *errp, char *filename);
+extern ACLEvalDestroyContext(NSErr_t *errp, ACLEvalHandle_t *acleval);
+
+
+main(int arc, char **argv)
+{
+ int result;
+ int cachable;
+ void *las_cookie=NULL;
+ ACLEvalHandle_t eval;
+ char *rights[2];
+ char filename[20];
+ int i;
+ char *bong;
+ char *bong_type;
+ char *acl_tag;
+ int expr_num;
+
+ /* ACL Eval Unit Tests
+ */
+ rights[0] = "read";
+ rights[1] = "write";
+ rights[2] = NULL;
+
+ eval.acllist = ACL_ParseFile((NSErr_t *)NULL, argv[1]);
+ result = ACL_EvalTestRights(NULL, &eval, &rights[0], NULL, &bong, &bong_type, &acl_tag, &expr_num);
+ ACLEvalDestroyContext(NULL, &eval);
+ ACL_ListDestroy(NULL, eval.acllist);
+ printf("%s = %d\n\n", argv[1], result);
+
+}
diff --git a/lib/libaccess/utest/shexp.cpp b/lib/libaccess/utest/shexp.cpp
new file mode 100644
index 00000000..23e9e909
--- /dev/null
+++ b/lib/libaccess/utest/shexp.cpp
@@ -0,0 +1,294 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * shexp.c: shell-like wildcard match routines
+ *
+ *
+ * See shexp.h for public documentation.
+ *
+ * Rob McCool
+ *
+ */
+
+#include "shexp.h"
+#include <ctype.h> /* isalpha, tolower */
+
+
+/* ----------------------------- shexp_valid ------------------------------ */
+
+
+int valid_subexp(char *exp, char stop)
+{
+ register int x,y,t;
+ int nsc,np,tld;
+
+ x=0;nsc=0;tld=0;
+
+ while(exp[x] && (exp[x] != stop)) {
+ switch(exp[x]) {
+ case '~':
+ if(tld) return INVALID_SXP;
+ else ++tld;
+ case '*':
+ case '?':
+ case '^':
+ case '$':
+ ++nsc;
+ break;
+ case '[':
+ ++nsc;
+ if((!exp[++x]) || (exp[x] == ']'))
+ return INVALID_SXP;
+ for(++x;exp[x] && (exp[x] != ']');++x)
+ if(exp[x] == '\\')
+ if(!exp[++x])
+ return INVALID_SXP;
+ if(!exp[x])
+ return INVALID_SXP;
+ break;
+ case '(':
+ ++nsc;np = 0;
+ while(1) {
+ if(exp[++x] == ')')
+ return INVALID_SXP;
+ for(y=x;(exp[y]) && (exp[y] != '|') && (exp[y] != ')');++y)
+ if(exp[y] == '\\')
+ if(!exp[++y])
+ return INVALID_SXP;
+ if(!exp[y])
+ return INVALID_SXP;
+ if(exp[y] == '|')
+ ++np;
+ t = valid_subexp(&exp[x],exp[y]);
+ if(t == INVALID_SXP)
+ return INVALID_SXP;
+ x+=t;
+ if(exp[x] == ')') {
+ if(!np)
+ return INVALID_SXP;
+ break;
+ }
+ }
+ break;
+ case ')':
+ case ']':
+ return INVALID_SXP;
+ case '\\':
+ if(!exp[++x])
+ return INVALID_SXP;
+ default:
+ break;
+ }
+ ++x;
+ }
+ if((!stop) && (!nsc))
+ return NON_SXP;
+ return ((exp[x] == stop) ? x : INVALID_SXP);
+}
+
+NSAPI_PUBLIC int shexp_valid(char *exp) {
+ int x;
+
+ x = valid_subexp(exp, '\0');
+ return (x < 0 ? x : VALID_SXP);
+}
+
+
+/* ----------------------------- shexp_match ----------------------------- */
+
+
+#define MATCH 0
+#define NOMATCH 1
+#define ABORTED -1
+
+int _shexp_match(char *str, char *exp);
+
+int handle_union(char *str, char *exp)
+{
+ char *e2 = (char *) MALLOC(sizeof(char)*strlen(exp));
+ register int t,p2,p1 = 1;
+ int cp;
+
+ while(1) {
+ for(cp=1;exp[cp] != ')';cp++)
+ if(exp[cp] == '\\')
+ ++cp;
+ for(p2 = 0;(exp[p1] != '|') && (p1 != cp);p1++,p2++) {
+ if(exp[p1] == '\\')
+ e2[p2++] = exp[p1++];
+ e2[p2] = exp[p1];
+ }
+ for(t=cp+1;(e2[p2] = exp[t]);++t,++p2);
+ if(_shexp_match(str,e2) == MATCH) {
+ FREE(e2);
+ return MATCH;
+ }
+ if(p1 == cp) {
+ FREE(e2);
+ return NOMATCH;
+ }
+ else ++p1;
+ }
+}
+
+
+int _shexp_match(char *str, char *exp)
+{
+ register int x,y;
+ int ret,neg;
+
+ ret = 0;
+ for(x=0,y=0;exp[y];++y,++x) {
+ if((!str[x]) && (exp[y] != '(') && (exp[y] != '$') && (exp[y] != '*'))
+ ret = ABORTED;
+ else {
+ switch(exp[y]) {
+ case '$':
+ if( (str[x]) )
+ ret = NOMATCH;
+ else
+ --x; /* we don't want loop to increment x */
+ break;
+ case '*':
+ while(exp[++y] == '*');
+ if(!exp[y])
+ return MATCH;
+ while(str[x]) {
+ switch(_shexp_match(&str[x++],&exp[y])) {
+ case NOMATCH:
+ continue;
+ case ABORTED:
+ ret = ABORTED;
+ break;
+ default:
+ return MATCH;
+ }
+ break;
+ }
+ if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
+ return MATCH;
+ else
+ ret = ABORTED;
+ break;
+ case '[':
+ if((neg = ((exp[++y] == '^') && (exp[y+1] != ']'))))
+ ++y;
+
+ if((isalnum(exp[y])) && (exp[y+1] == '-') &&
+ (isalnum(exp[y+2])) && (exp[y+3] == ']'))
+ {
+ int start = exp[y], end = exp[y+2];
+
+ /* Droolproofing for pinheads not included */
+ if(neg ^ ((str[x] < start) || (str[x] > end))) {
+ ret = NOMATCH;
+ break;
+ }
+ y+=3;
+ }
+ else {
+ int matched;
+
+ for(matched=0;exp[y] != ']';y++)
+ matched |= (str[x] == exp[y]);
+ if(neg ^ (!matched))
+ ret = NOMATCH;
+ }
+ break;
+ case '(':
+ return handle_union(&str[x],&exp[y]);
+ break;
+ case '?':
+ break;
+ case '\\':
+ ++y;
+ default:
+#ifdef XP_UNIX
+ if(str[x] != exp[y])
+#else /* XP_WIN32 */
+ if(strnicmp(str + x, exp + y, 1))
+#endif /* XP_WIN32 */
+ ret = NOMATCH;
+ break;
+ }
+ }
+ if(ret)
+ break;
+ }
+ return (ret ? ret : (str[x] ? NOMATCH : MATCH));
+}
+
+NSAPI_PUBLIC int shexp_match(char *str, char *xp) {
+ register int x;
+ char *exp = STRDUP(xp);
+
+ for(x=strlen(exp)-1;x;--x) {
+ if((exp[x] == '~') && (exp[x-1] != '\\')) {
+ exp[x] = '\0';
+ if(_shexp_match(str,&exp[++x]) == MATCH)
+ goto punt;
+ break;
+ }
+ }
+ if(_shexp_match(str,exp) == MATCH) {
+ FREE(exp);
+ return 0;
+ }
+
+ punt:
+ FREE(exp);
+ return 1;
+}
+
+
+/* ------------------------------ shexp_cmp ------------------------------- */
+
+
+NSAPI_PUBLIC int shexp_cmp(char *str, char *exp)
+{
+ switch(shexp_valid(exp)) {
+ case INVALID_SXP:
+ return -1;
+ case NON_SXP:
+#ifdef XP_UNIX
+ return (strcmp(exp,str) ? 1 : 0);
+#else /* XP_WIN32 */
+ return (stricmp(exp,str) ? 1 : 0);
+#endif /* XP_WIN32 */
+ default:
+ return shexp_match(str, exp);
+ }
+}
+
+
+/* ---------------------------- shexp_casecmp ----------------------------- */
+
+
+NSAPI_PUBLIC int shexp_casecmp(char *str, char *exp)
+{
+ char *lstr = STRDUP(str), *lexp = STRDUP(exp), *t;
+ int ret;
+
+ for(t = lstr; *t; t++)
+ if(isalpha(*t)) *t = tolower(*t);
+ for(t = lexp; *t; t++)
+ if(isalpha(*t)) *t = tolower(*t);
+
+ switch(shexp_valid(lexp)) {
+ case INVALID_SXP:
+ ret = -1;
+ break;
+ case NON_SXP:
+ ret = (strcmp(lexp, lstr) ? 1 : 0);
+ break;
+ default:
+ ret = shexp_match(lstr, lexp);
+ }
+ FREE(lstr);
+ FREE(lexp);
+ return ret;
+}
+
diff --git a/lib/libaccess/utest/shexp.h b/lib/libaccess/utest/shexp.h
new file mode 100644
index 00000000..edc91842
--- /dev/null
+++ b/lib/libaccess/utest/shexp.h
@@ -0,0 +1,131 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * shexp.h: Defines and prototypes for shell exp. match routines
+ *
+ *
+ * This routine will match a string with a shell expression. The expressions
+ * accepted are based loosely on the expressions accepted by zsh.
+ *
+ * o * matches anything
+ * o ? matches one character
+ * o \ will escape a special character
+ * o $ matches the end of the string
+ * o [abc] matches one occurence of a, b, or c. The only character that needs
+ * to be escaped in this is ], all others are not special.
+ * o [a-z] matches any character between a and z
+ * o [^az] matches any character except a or z
+ * o ~ followed by another shell expression will remove any pattern
+ * matching the shell expression from the match list
+ * o (foo|bar) will match either the substring foo, or the substring bar.
+ * These can be shell expressions as well.
+ *
+ * The public interface to these routines is documented below.
+ *
+ * Rob McCool
+ *
+ */
+
+#ifndef SHEXP_H
+#define SHEXP_H
+
+/*
+ * Requires that the macro MALLOC be set to a "safe" malloc that will
+ * exit if no memory is available. If not under MCC httpd, define MALLOC
+ * to be the real malloc and play with fire, or make your own function.
+ */
+
+#include "../netsite.h"
+
+#include <ctype.h> /* isalnum */
+#include <string.h> /* strlen */
+
+
+/*
+ * Wrappers for shexp/regexp
+ *
+ * Portions of code that explicitly want to have either shexp's
+ * or regexp's should call those functions directly.
+ *
+ * Common code bases for multiple products should use the following
+ * macros instead to use either shell or regular expressions,
+ * depending on the flavor chosen for a given server.
+ *
+ */
+#if defined(MCC_PROXY) && defined(USE_REGEX)
+
+#include "base/regexp.h"
+
+#define WILDPAT_VALID(exp) regexp_valid(exp)
+#define WILDPAT_MATCH(str, exp) regexp_match(str, exp)
+#define WILDPAT_CMP(str, exp) regexp_cmp(str, exp)
+#define WILDPAT_CASECMP(str, exp) regexp_casecmp(str, exp)
+
+#else /* HTTP servers */
+
+#define WILDPAT_VALID(exp) shexp_valid(exp)
+#define WILDPAT_MATCH(str, exp) shexp_match(str, exp)
+#define WILDPAT_CMP(str, exp) shexp_cmp(str, exp)
+#define WILDPAT_CASECMP(str, exp) shexp_casecmp(str, exp)
+
+#endif
+
+
+/* --------------------------- Public routines ---------------------------- */
+
+NSPR_BEGIN_EXTERN_C
+
+/*
+ * shexp_valid takes a shell expression exp as input. It returns:
+ *
+ * NON_SXP if exp is a standard string
+ * INVALID_SXP if exp is a shell expression, but invalid
+ * VALID_SXP if exp is a valid shell expression
+ */
+
+#define NON_SXP -1
+#define INVALID_SXP -2
+#define VALID_SXP 1
+
+/* and generic shexp/regexp versions */
+#define NON_WILDPAT NON_SXP
+#define INVALID_WILDPAT INVALID_SXP
+#define VALID_WILDPAT VALID_SXP
+
+/* and regexp versions */
+#define NON_REGEXP NON_SXP
+#define INVALID_REGEXP INVALID_SXP
+#define VALID_REGEXP VALID_SXP
+
+
+NSAPI_PUBLIC int shexp_valid(char *exp);
+
+/*
+ * shexp_match
+ *
+ * Takes a prevalidated shell expression exp, and a string str.
+ *
+ * Returns 0 on match and 1 on non-match.
+ */
+
+NSAPI_PUBLIC int shexp_match(char *str, char *exp);
+
+
+/*
+ * shexp_cmp
+ *
+ * Same as above, but validates the exp first. 0 on match, 1 on non-match,
+ * -1 on invalid exp. shexp_casecmp does the same thing but is case
+ * insensitive.
+ */
+
+NSAPI_PUBLIC int shexp_cmp(char *str, char *exp);
+NSAPI_PUBLIC int shexp_casecmp(char *str, char *exp);
+
+NSPR_END_EXTERN_C
+
+#endif
+
diff --git a/lib/libaccess/utest/test.ref b/lib/libaccess/utest/test.ref
new file mode 100644
index 00000000..d5207382
--- /dev/null
+++ b/lib/libaccess/utest/test.ref
@@ -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
+#
+Failed ACL_FileMergeFile() test.
+Method one is #1, rv=0
+Method two is #2, rv=0
+Method one repeated is #1, rv=0
+Method three is #3, rv=0
+ Method[0] = "two"
+ Method[1] = "three"
+ Method[2] = "one"
+DbType two is #2, rv=0
+DbType three is #3, rv=0
+DbType two repeated is #2, rv=0
+DbType four is #4, rv=0
+ Database[0] = "db2"
+ Database[1] = "db1"
+ Database[2] = "db3"
+position 1
+position 2
+position 3
+position 4
+aclfile0 = 0
+
+aclfile1 = 1
+
+aclfile2 = 1
+
+aclfile3 = 1
+
+aclfile4 = 0
+
+aclfile5 = 0
+
+aclfile6 = 0
+
+aclfile7 = 1
+
+aclfile8 = 0
+
+aclfile9 = 3
+
+ACL file: internal-buffer
+Syntax error at line: 1, token: >
+ACL file: internal-buffer
+Syntax error at line: 2, token: junk
+aclfile10 = 1
+
+aclfile11 = 1
+
+aclfile12 = 0
+
+aclfile13 = 0
+
+aclfile14 = 0
+
+aclfile15 = 1
+
+aclfile16 = 1
+
+aclfile17 = 0
+
+aclfile18 = 0
+
+aclfile19 = 1
+
+program = foo -1
+
+program = nomatch -2
+
+program = beer -1
+
+program = http-grog -2
+
+program = ubar -2
+
+dnsalias = *? -1
+
+dnsalias = aruba.mcom.com brain251.mcom.com? -1
+
+dns = *? -1
+
+dns != *? -2
+
+dns = aruba.mcom.com? -1
+
+dns = ai.mit.edu? -2
+
+dns = *.ai.mit.edu? -2
+
+dns = *.mit.edu? -2
+
+dns = *.edu? -2
+
+dns != *.edu? -1
+
+mistake != *.edu? -5
+
+dns > *.edu? -5
+
+ip = *? -1
+
+ip != *? -2
+
+ip = *.*.*.*? -1
+
+ip = 17.*? -1
+
+ip = 17.*.*.*? -1
+
+ip = 17.34.*? -1
+
+ip = 17.34.*.*? -1
+
+ip = 17.34.51.*? -1
+
+ip = 17.34.51.*+255.255.255.255? -1
+
+ip = 17.34.51.69+255.255.255.254, 123.45.67.89? -1
+
+ip != 17.34.51.69+255.255.255.254, 123.45.67.89? -2
+
+ip = 17.34.51.68, 17.34.51.69? -1
+
+ip = 17.34.51.68, 17.34.51.69, 123.45.67.89? -1
+
+ip != 17.34.51.68, 17.34.51.69, 123.45.67.89? -2
+
+ip = 17.34.51.68? -1
+
+ip = 17.34.51.69? -2
+
+ip = 17.34.51.69+255.255.255.254? -1
+
+ip = 17.34.50.69+255.255.254.0? -1
+
+ip = 17.35.50.69+255.254.0.0? -1
+
+ip = 16.35.50.69+254.0.0.0? -1
+
+ip = 123.45.67.89? -2
+
+ip != 123.45.67.89? -1
+
+ip > 123.45.67.89? -5
+
+ip < 123.45.67.89? -5
+
+ip >= 123.45.67.89? -5
+
+ip <= 123.45.67.89? -5
+
+mistake <= 123.45.67.89? -5
+
+time = 2120? -1
+
+time != 2120? -2
+
+time = 0700? -2
+
+time != 0700? -1
+
+time = 2400? -2
+
+time != 2400? -1
+
+time > 2120? -2
+
+time < 2120? -2
+
+time > 0700? -1
+
+time < 0700? -2
+
+time > 2400? -2
+
+time < 2400? -1
+
+time >= 2120? -1
+
+time <= 2120? -1
+
+time >= 0700? -1
+
+time <= 0700? -2
+
+time >= 2400? -2
+
+time <= 2400? -1
+
+mistake <= 2400? -5
+
+time = 0800-2200? -1
+
+time != 0800-2200? -2
+
+time = 2200-0800? -2
+
+time != 2200-0800? -1
+
+time <= 2200-0800? -5
+
+= mon? -1
+
+= tUe? -2
+
+= weD? -2
+
+= THu? -2
+
+= FrI? -2
+
+= tUe? -2
+
+= Sun? -2
+
+= mon,tuewed,thu,frisatsun? -1
+
+!= mon,tuewed,thu,frisatsun? -2
+
+> Sun? -5
+
+< Sun? -5
+
+>= Sun? -5
+
+<= Sun? -5
+
+mistake <= Sun? -5
+
diff --git a/lib/libaccess/utest/testmain.cpp b/lib/libaccess/utest/testmain.cpp
new file mode 100644
index 00000000..4da14cee
--- /dev/null
+++ b/lib/libaccess/utest/testmain.cpp
@@ -0,0 +1,52 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * ACL parser unit test program
+ */
+
+#include <stdio.h>
+#include <netsite.h>
+#include <libaccess/acl.h>
+#include <libaccess/nserror.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+
+main(int argc, char **argv)
+{
+
+ACLListHandle_t *acllist;
+int ii;
+char filename[255];
+ACLWrapper_t *wrap;
+ACLExprHandle_t *expr;
+
+ if ( argc < 2 ) {
+ fprintf(stderr, "usage: aclparse <filenames>\n");
+ exit(1);
+ }
+ for (ii = 1; ii < argc; ii++ ) {
+ acllist = ACL_ParseFile(NULL, argv[ii]);
+ if ( acllist == NULL ) {
+ printf("Failed to parse ACL.\n");
+
+ } else {
+ for (wrap = acllist->acl_list_head; wrap;
+ wrap = wrap->wrap_next) {
+ for (expr=wrap->acl->expr_list_head;
+ expr;
+ expr = expr->expr_next ) {
+ ACL_ExprDisplay(expr);
+ }
+ }
+ }
+
+
+ sprintf(filename, "%s.v30", argv[ii]);
+ ACL_WriteFile(NULL, filename, acllist);
+ ACL_ListDestroy( acllist );
+ }
+
+}
diff --git a/lib/libaccess/utest/twotest.cpp b/lib/libaccess/utest/twotest.cpp
new file mode 100644
index 00000000..2d4fb503
--- /dev/null
+++ b/lib/libaccess/utest/twotest.cpp
@@ -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 **/
+#include <stdio.h>
+#include <netsite.h>
+#include <base/session.h>
+#include <base/plist.h>
+#include <base/ereport.h>
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/las.h>
+
+
+extern ACLListHandle_t *ACL_ParseFile(NSErr_t *errp, char *filename);
+extern ACLEvalDestroyContext(NSErr_t *errp, ACLEvalHandle_t *acleval);
+
+main(int arc, char **argv)
+{
+ int result;
+ int cachable;
+ void *las_cookie=NULL;
+ ACLEvalHandle_t eval;
+ char *rights[2];
+ char *map_generic[7];
+ char filename[20];
+ int i;
+ char *bong;
+ char *bong_type;
+ char *acl_tag;
+ int expr_num;
+
+ /* ACL Eval Unit Tests
+ */
+
+ rights[0] = "html_read";
+ rights[1] = "html_write";
+ rights[2] = NULL;
+
+ map_generic[0] = "html_read";
+ map_generic[1] = "html_write";
+ map_generic[2] = "N/A";
+ map_generic[3] = "html_create";
+ map_generic[4] = "html_delete";
+ map_generic[5] = "N/A";
+ map_generic[6] = NULL;
+
+ eval.acllist = ACL_ParseFile((NSErr_t *)NULL, argv[1]);
+ result = ACL_EvalTestRights(NULL, &eval, &rights[0], map_generic, &bong, &bong_type, &acl_tag, &expr_num);
+ ACLEvalDestroyContext(NULL, &eval);
+ ACL_ListDestroy(NULL, eval.acllist);
+ printf("%s = %d\n\n", argv[1], result);
+
+}
diff --git a/lib/libaccess/utest/ustubs.cpp b/lib/libaccess/utest/ustubs.cpp
new file mode 100644
index 00000000..ccfa3108
--- /dev/null
+++ b/lib/libaccess/utest/ustubs.cpp
@@ -0,0 +1,283 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <sys/types.h>
+#include <malloc.h>
+#include <string.h>
+#include <base/crit.h>
+#include <base/plist.h>
+
+#include <libaccess/nserror.h>
+#include <libaccess/acl.h>
+#include "../aclpriv.h"
+#include <libaccess/aclproto.h>
+#include <libaccess/ldapacl.h>
+#include <ldaputil/dbconf.h>
+#ifdef NSPR20
+#include <prprf.h>
+#else
+#include <nspr/prprf.h>
+#endif
+
+NSPR_BEGIN_EXTERN_C
+extern char * ACL_Program;
+extern int conf_getglobals();
+extern int SPconf_getglobals();
+extern int ereport(int, char*, ...);
+extern int SPereport(int, char*, ...);
+extern char * GetAdminLanguage(void);
+extern char * XP_GetStringFromDatabase(char *strLibraryName, char *strLanguage, int iToken);
+extern void ACL_Restart(void *cntlData);
+extern int XP_SetError();
+extern int XP_GetError();
+extern int acl_usr_cache_init();
+extern int acl_usr_cache_set_group();
+extern int acl_usr_cache_group_check();
+extern int sema_destroy();
+extern char *ldapu_err2string(int err);
+extern int ACL_CacheFlush(void);
+NSPR_END_EXTERN_C
+
+static char errbuf[10];
+
+char *
+ldapu_err2string(int err)
+{
+ sprintf(errbuf, "%d", err);
+ return errbuf;
+}
+
+
+void init_ldb_rwlock ()
+{
+}
+
+sema_destroy()
+{
+ return 0;
+}
+
+#ifdef notdef
+char *system_errmsg()
+{
+ static char errmsg[1024];
+
+ sprintf(errmsg, "Stubbed system_errmsg");
+ return errmsg;
+}
+#endif
+
+int
+ACL_CacheFlushRegister(AclCacheFlushFunc_t flush_func)
+{
+ return 0;
+}
+
+acl_usr_cache_init()
+{
+ return 0;
+}
+
+acl_usr_cache_group_check()
+{
+ return 0;
+}
+
+acl_usr_cache_set_group()
+{
+ return 0;
+}
+
+XP_SetError()
+{
+ return 0;
+}
+
+XP_GetError()
+{
+ return 0;
+}
+
+CRITICAL
+crit_init()
+{
+ return (CRITICAL)1;
+}
+
+void
+crit_enter(CRITICAL c)
+{
+ return;
+}
+
+void
+crit_exit(CRITICAL c)
+{
+ return;
+}
+
+void
+crit_terminate(CRITICAL c)
+{
+ return;
+}
+
+int crit_owner_is_me(CRITICAL id)
+{
+ return 1;
+}
+
+symTableFindSym()
+{
+ return 0;
+}
+
+int
+ldap_auth_uid_groupid(LDAP *ld, char *uid, char *groupid,
+ char *base)
+{
+ return 0;
+}
+
+LDAP *
+init_ldap (char *host, int port, int use_ssl)
+{
+ return (LDAP *)"init_ldap_stub";
+}
+
+int ACL_LDAPDatabaseHandle (NSErr_t *errp, const char *dbname, LDAP **ld,
+ char **basedn)
+{
+ *ld = (LDAP *)"ACL_LDAPDatabaseHandle_stub";
+ if (basedn) *basedn = strdup("unknown basedn");
+ return LAS_EVAL_TRUE;
+}
+
+#ifdef notdef
+NSEFrame_t * nserrGenerate(NSErr_t * errp, long retcode, long errorid,
+ char * program, int errc, ...)
+{
+ return 0;
+}
+#endif
+
+char * ACL_Program;
+
+char *
+LASUserGetUser()
+{
+ return "hmiller";
+}
+
+LASIpGetIp()
+{
+ return(0x11223344);
+}
+
+LASDnsGetDns(char **dnsv)
+{
+ *dnsv = "aruba.mcom.com";
+ return 0;
+}
+
+int
+ACL_DestroyList()
+{
+return(0);
+}
+
+aclCheckHosts()
+{
+return(0);
+}
+
+aclCheckUsers()
+{
+return(0);
+}
+
+char *LASGroupGetUser()
+{
+ return("hmiller");
+}
+
+int
+SPconf_getglobals()
+{
+ return 0;
+}
+
+int
+conf_getglobals()
+{
+ return 0;
+}
+
+int
+SPereport(int degree, char *fmt, ...)
+{
+ va_list args;
+ char errstr[1024];
+
+ va_start(args, fmt);
+ PR_vsnprintf(&errstr[0], sizeof(errstr), fmt, args);
+ printf("%s", errstr);
+ va_end(args);
+ return 0;
+}
+
+int
+ereport(int degree, char *fmt, ...)
+{
+ va_list args;
+ char errstr[1024];
+
+ va_start(args, fmt);
+ PR_vsnprintf(&errstr[0], sizeof(errstr), fmt, args);
+ printf("%s", errstr);
+ va_end(args);
+ return 0;
+}
+
+#ifdef notdef
+int dbconf_read_config_file (const char *file, DBConfInfo_t **conf_info_out)
+{
+ return 0;
+}
+#endif
+
+char *
+GetAdminLanguage(void)
+{
+ return "";
+}
+
+static char errstr[1024];
+
+char *
+XP_GetStringFromDatabase(char *strLibraryName, char *strLanguage, int iToken)
+{
+ sprintf(errstr, "XP_GetAdminStr called for error %d\n", iToken);
+ return errstr;
+}
+
+void
+ACL_Restart(void * cntlData)
+{
+ return;
+}
+
+NSAPI_PUBLIC int
+parse_ldap_url(NSErr_t *errp, ACLDbType_t dbtype, const char *name, const char
+*url, PList_t plist, void **db)
+{
+ return 0;
+}
+
+int
+ACL_CacheFlush(void)
+{
+ return 0;
+}
diff --git a/lib/libaccess/winnt.l b/lib/libaccess/winnt.l
new file mode 100644
index 00000000..ce72b535
--- /dev/null
+++ b/lib/libaccess/winnt.l
@@ -0,0 +1,762 @@
+/** 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>
+# define U(x) x
+# define NLSTATE yyprevious=YYNEWLINE
+# define BEGIN yybgin = yysvec + 1 +
+# define INITIAL 0
+# define YYLERR yysvec
+# define YYSTATE (yyestate-yysvec-1)
+# define YYOPTIM 1
+# define YYLMAX BUFSIZ
+#ifndef __cplusplus
+# define output(c) (void)putc(c,yyout)
+#else
+# define lex_output(c) (void)putc(c,yyout)
+#endif
+
+#if defined(__cplusplus) || defined(__STDC__)
+
+#if defined(__cplusplus) && defined(__EXTERN_C__)
+extern "C" {
+#endif
+ int yyback(int *, int);
+ int yyinput(void);
+ int yylook(void);
+ void yyoutput(int);
+ int yyracc(int);
+ int yyreject(void);
+ void yyunput(int);
+ int yylex(void);
+#ifdef YYLEX_E
+ void yywoutput(wchar_t);
+ wchar_t yywinput(void);
+#endif
+#ifndef yyless
+ void yyless(int);
+#endif
+#ifndef yywrap
+ int yywrap(void);
+#endif
+#ifdef LEXDEBUG
+ void allprint(char);
+ void sprint(char *);
+#endif
+#if defined(__cplusplus) && defined(__EXTERN_C__)
+}
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+ void exit(int);
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+# define unput(c) {yytchar= (c);if(yytchar=='\n')yylineno--;*yysptr++=yytchar;}
+# define yymore() (yymorfg=1)
+#ifndef __cplusplus
+# define input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
+#else
+# define lex_input() (((yytchar=yysptr>yysbuf?U(*--yysptr):getc(yyin))==10?(yylineno++,yytchar):yytchar)==EOF?0:yytchar)
+#endif
+#define ECHO fprintf(yyout, "%s",yytext)
+# define REJECT { nstr = yyreject(); goto yyfussy;}
+int yyleng; extern char yytext[];
+int yymorfg;
+extern char *yysptr, yysbuf[];
+int yytchar;
+FILE *yyin = NULL, *yyout = NULL;
+extern int yylineno;
+struct yysvf {
+ struct yywork *yystoff;
+ struct yysvf *yyother;
+ int *yystops;};
+struct yysvf *yyestate;
+extern struct yysvf yysvec[], *yybgin;
+
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include "y.tab.h"
+#include "libaccess/ava.h"
+/*#include "netsite.h" */
+
+int linenum = 1;
+int first_time = 1;
+int old_state;
+int num_nested_comments = 0;
+
+extern AVAEntry tempEntry;
+extern AVATable entryTable;
+
+void strip_quotes(void);
+
+# define COMMENT 2
+# define NORM 4
+# define DEFINES 6
+# define DEF_TYPE 8
+# define YYNEWLINE 10
+yylex(){
+int nstr; extern int yyprevious;
+
+ if (yyin == NULL) yyin = stdin;
+ if (yyout == NULL) yyout = stdout;
+ if (first_time) {
+ BEGIN NORM;
+ first_time = tempEntry.numOrgs = 0;
+ old_state = NORM;
+ tempEntry.userid = 0;
+ tempEntry.country = 0;
+ tempEntry.CNEntry = 0;
+ tempEntry.email = 0;
+ tempEntry.locality = 0;
+ tempEntry.state = 0;
+ entryTable.numEntries = 0;
+ }
+#ifdef __cplusplus
+/* to avoid CC and lint complaining yyfussy not being used ...*/
+static int __lex_hack = 0;
+if (__lex_hack) goto yyfussy;
+#endif
+while((nstr = yylook()) >= 0)
+yyfussy: switch(nstr){
+case 0:
+if(yywrap()) return(0); break;
+case 1:
+
+# line 58 "avascan.l"
+ {BEGIN COMMENT; num_nested_comments++;}
+break;
+case 2:
+
+# line 59 "avascan.l"
+ {num_nested_comments--;
+ if (!num_nested_comments) BEGIN old_state;}
+break;
+case 3:
+
+# line 61 "avascan.l"
+ {;}
+break;
+case 4:
+
+# line 63 "avascan.l"
+ {yylval.string = system_strdup(yytext);
+ return USER_ID;}
+break;
+case 5:
+
+# line 65 "avascan.l"
+{BEGIN DEF_TYPE;
+ old_state = DEF_TYPE;}
+break;
+case 6:
+
+# line 68 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_C; }
+break;
+case 7:
+
+# line 70 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_CO;}
+break;
+case 8:
+
+# line 72 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_OU;}
+break;
+case 9:
+
+# line 74 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_CN;}
+break;
+case 10:
+
+# line 76 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_L;}
+break;
+case 11:
+
+# line 78 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_E;}
+break;
+case 12:
+
+# line 80 "avascan.l"
+ {BEGIN DEFINES; old_state = DEFINES;
+ return DEF_ST;}
+break;
+case 13:
+
+# line 82 "avascan.l"
+ {BEGIN NORM;old_state = NORM;}
+break;
+case 14:
+
+# line 84 "avascan.l"
+ {return EQ_SIGN;}
+break;
+case 15:
+
+# line 85 "avascan.l"
+ {BEGIN DEF_TYPE; old_state = DEF_TYPE;
+ strip_quotes();
+ return DEF_ID;}
+break;
+case 16:
+
+# line 89 "avascan.l"
+ {;}
+break;
+case 17:
+
+# line 90 "avascan.l"
+ {linenum++;}
+break;
+case 18:
+
+# line 91 "avascan.l"
+ {yyerror("Bad input character");}
+break;
+case -1:
+break;
+default:
+(void)fprintf(yyout,"bad switch yylook %d",nstr);
+} return(0); }
+/* end of yylex */
+
+int yywrap () {
+ return 1;
+}
+
+void strip_quotes(void) {
+ yytext[strlen(yytext)-1]= '\0';
+ yylval.string = system_strdup(&yytext[1]);
+}
+int yyvstop[] = {
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+16,
+0,
+
+18,
+0,
+
+16,
+18,
+0,
+
+17,
+0,
+
+18,
+0,
+
+3,
+18,
+0,
+
+3,
+16,
+18,
+0,
+
+3,
+18,
+0,
+
+3,
+18,
+0,
+
+4,
+18,
+0,
+
+18,
+0,
+
+18,
+0,
+
+14,
+18,
+0,
+
+6,
+18,
+0,
+
+11,
+18,
+0,
+
+10,
+18,
+0,
+
+7,
+18,
+0,
+
+18,
+0,
+
+13,
+18,
+0,
+
+16,
+0,
+
+1,
+0,
+
+2,
+0,
+
+4,
+0,
+
+5,
+0,
+
+15,
+0,
+
+9,
+0,
+
+8,
+0,
+
+12,
+0,
+0};
+# define YYTYPE unsigned char
+struct yywork { YYTYPE verify, advance; } yycrank[] = {
+0,0, 0,0, 1,11, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 1,12, 1,13,
+0,0, 3,15, 12,29, 0,0,
+20,33, 0,0, 0,0, 0,0,
+0,0, 3,16, 3,13, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 9,11, 0,0, 1,11,
+0,0, 12,29, 7,21, 20,33,
+8,21, 9,12, 9,13, 14,30,
+0,0, 1,11, 3,15, 4,17,
+1,14, 1,11, 2,14, 7,14,
+4,18, 8,14, 3,17, 5,19,
+3,15, 17,31, 5,14, 3,18,
+3,15, 6,19, 10,14, 21,35,
+6,14, 7,22, 9,11, 8,22,
+0,0, 5,20, 0,0, 21,35,
+21,35, 0,0, 0,0, 6,20,
+9,11, 0,0, 0,0, 9,14,
+9,11, 23,37, 10,23, 0,0,
+10,24, 27,39, 26,38, 0,0,
+0,0, 0,0, 0,0, 10,25,
+0,0, 0,0, 10,26, 0,0,
+21,36, 0,0, 10,27, 9,23,
+0,0, 9,24, 0,0, 0,0,
+0,0, 0,0, 21,35, 0,0,
+9,25, 0,0, 21,35, 9,26,
+0,0, 0,0, 0,0, 9,27,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 0,0, 20,34, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 19,32, 0,0, 0,0,
+10,28, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 0,0,
+0,0, 0,0, 0,0, 0,0,
+0,0, 9,28, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+0,0, 0,0, 0,0, 0,0,
+19,32, 0,0, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+19,32, 19,32, 19,32, 19,32,
+0,0};
+struct yysvf yysvec[] = {
+0, 0, 0,
+yycrank+-1, 0, yyvstop+1,
+yycrank+-3, yysvec+1, yyvstop+3,
+yycrank+-12, 0, yyvstop+5,
+yycrank+-5, yysvec+3, yyvstop+7,
+yycrank+-11, yysvec+1, yyvstop+9,
+yycrank+-17, yysvec+1, yyvstop+11,
+yycrank+-4, yysvec+1, yyvstop+13,
+yycrank+-6, yysvec+1, yyvstop+15,
+yycrank+-32, 0, yyvstop+17,
+yycrank+-15, yysvec+9, yyvstop+19,
+yycrank+0, 0, yyvstop+21,
+yycrank+5, 0, yyvstop+23,
+yycrank+0, 0, yyvstop+26,
+yycrank+1, 0, yyvstop+28,
+yycrank+0, 0, yyvstop+30,
+yycrank+0, yysvec+12, yyvstop+33,
+yycrank+10, 0, yyvstop+37,
+yycrank+0, yysvec+14, yyvstop+40,
+yycrank+93, 0, yyvstop+43,
+yycrank+7, 0, yyvstop+46,
+yycrank+-62, 0, yyvstop+48,
+yycrank+0, 0, yyvstop+50,
+yycrank+3, 0, yyvstop+53,
+yycrank+0, 0, yyvstop+56,
+yycrank+0, 0, yyvstop+59,
+yycrank+1, 0, yyvstop+62,
+yycrank+1, 0, yyvstop+65,
+yycrank+0, 0, yyvstop+67,
+yycrank+0, yysvec+12, yyvstop+70,
+yycrank+0, 0, yyvstop+72,
+yycrank+0, 0, yyvstop+74,
+yycrank+0, yysvec+19, yyvstop+76,
+yycrank+0, yysvec+20, 0,
+yycrank+0, 0, yyvstop+78,
+yycrank+0, yysvec+21, 0,
+yycrank+0, 0, yyvstop+80,
+yycrank+0, 0, yyvstop+82,
+yycrank+0, 0, yyvstop+84,
+yycrank+0, 0, yyvstop+86,
+0, 0, 0};
+struct yywork *yytop = yycrank+215;
+struct yysvf *yybgin = yysvec+1;
+char yymatch[] = {
+ 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 9, 10, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 9, 1, 34, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 44, 1, 1, 1,
+ 48, 48, 48, 48, 48, 48, 48, 48,
+ 48, 48, 1, 1, 1, 1, 1, 1,
+ 1, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 1, 1, 1, 1, 44,
+ 1, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1,
+0};
+char yyextra[] = {
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,
+0};
+/* Copyright (c) 1989 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#pragma ident "@(#)ncform 6.7 93/06/07 SMI"
+
+int yylineno =1;
+# define YYU(x) x
+# define NLSTATE yyprevious=YYNEWLINE
+char yytext[YYLMAX];
+struct yysvf *yylstate [YYLMAX], **yylsp, **yyolsp;
+char yysbuf[YYLMAX];
+char *yysptr = yysbuf;
+int *yyfnd;
+extern struct yysvf *yyestate;
+int yyprevious = YYNEWLINE;
+#if defined(__cplusplus) || defined(__STDC__)
+int yylook(void)
+#else
+yylook()
+#endif
+{
+ register struct yysvf *yystate, **lsp;
+ register struct yywork *yyt;
+ struct yysvf *yyz;
+ int yych, yyfirst;
+ struct yywork *yyr;
+# ifdef LEXDEBUG
+ int debug;
+# endif
+ char *yylastch;
+ /* start off machines */
+# ifdef LEXDEBUG
+ debug = 0;
+# endif
+ yyfirst=1;
+ if (!yymorfg)
+ yylastch = yytext;
+ else {
+ yymorfg=0;
+ yylastch = yytext+yyleng;
+ }
+ for(;;){
+ lsp = yylstate;
+ yyestate = yystate = yybgin;
+ if (yyprevious==YYNEWLINE) yystate++;
+ for (;;){
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"state %d\n",yystate-yysvec-1);
+# endif
+ yyt = yystate->yystoff;
+ if(yyt == yycrank && !yyfirst){ /* may not be any transitions */
+ yyz = yystate->yyother;
+ if(yyz == 0)break;
+ if(yyz->yystoff == yycrank)break;
+ }
+#ifndef __cplusplus
+ *yylastch++ = yych = input();
+#else
+ *yylastch++ = yych = lex_input();
+#endif
+ if(yylastch > &yytext[YYLMAX]) {
+ fprintf(yyout,"Input string too long, limit %d\n",YYLMAX);
+ exit(1);
+ }
+ yyfirst=0;
+ tryagain:
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"char ");
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ yyr = yyt;
+ if ( (int)yyt > (int)yycrank){
+ yyt = yyr + yych;
+ if (yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transitions */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ if(lsp > &yylstate[YYLMAX]) {
+ fprintf(yyout,"Input string too long, limit %d\n",YYLMAX);
+ exit(1);
+ }
+ goto contin;
+ }
+ }
+# ifdef YYOPTIM
+ else if((int)yyt < (int)yycrank) { /* r < yycrank */
+ yyt = yyr = yycrank+(yycrank-yyt);
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"compressed state\n");
+# endif
+ yyt = yyt + yych;
+ if(yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transitions */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ if(lsp > &yylstate[YYLMAX]) {
+ fprintf(yyout,"Input string too long, limit %d\n",YYLMAX);
+ exit(1);
+ }
+ goto contin;
+ }
+ yyt = yyr + YYU(yymatch[yych]);
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"try fall back character ");
+ allprint(YYU(yymatch[yych]));
+ putchar('\n');
+ }
+# endif
+ if(yyt <= yytop && yyt->verify+yysvec == yystate){
+ if(yyt->advance+yysvec == YYLERR) /* error transition */
+ {unput(*--yylastch);break;}
+ *lsp++ = yystate = yyt->advance+yysvec;
+ if(lsp > &yylstate[YYLMAX]) {
+ fprintf(yyout,"Input string too long, limit %d\n",YYLMAX);
+ exit(1);
+ }
+ goto contin;
+ }
+ }
+ if ((yystate = yystate->yyother) && (yyt= yystate->yystoff) != yycrank){
+# ifdef LEXDEBUG
+ if(debug)fprintf(yyout,"fall back to state %d\n",yystate-yysvec-1);
+# endif
+ goto tryagain;
+ }
+# endif
+ else
+ {unput(*--yylastch);break;}
+ contin:
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"state %d char ",yystate-yysvec-1);
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ ;
+ }
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"stopped at %d with ",*(lsp-1)-yysvec-1);
+ allprint(yych);
+ putchar('\n');
+ }
+# endif
+ while (lsp-- > yylstate){
+ *yylastch-- = 0;
+ if (*lsp != 0 && (yyfnd= (*lsp)->yystops) && *yyfnd > 0){
+ yyolsp = lsp;
+ if(yyextra[*yyfnd]){ /* must backup */
+ while(yyback((*lsp)->yystops,-*yyfnd) != 1 && lsp > yylstate){
+ lsp--;
+ unput(*yylastch--);
+ }
+ }
+ yyprevious = YYU(*yylastch);
+ yylsp = lsp;
+ yyleng = yylastch-yytext+1;
+ yytext[yyleng] = 0;
+# ifdef LEXDEBUG
+ if(debug){
+ fprintf(yyout,"\nmatch ");
+ sprint(yytext);
+ fprintf(yyout," action %d\n",*yyfnd);
+ }
+# endif
+ return(*yyfnd++);
+ }
+ unput(*yylastch);
+ }
+ if (yytext[0] == 0 /* && feof(yyin) */)
+ {
+ yysptr=yysbuf;
+ return(0);
+ }
+#ifndef __cplusplus
+ yyprevious = yytext[0] = input();
+ if (yyprevious>0)
+ output(yyprevious);
+#else
+ yyprevious = yytext[0] = lex_input();
+ if (yyprevious>0)
+ lex_output(yyprevious);
+#endif
+ yylastch=yytext;
+# ifdef LEXDEBUG
+ if(debug)putchar('\n');
+# endif
+ }
+ }
+#if defined(__cplusplus) || defined(__STDC__)
+int yyback(int *p, int m)
+#else
+yyback(p, m)
+ int *p;
+#endif
+{
+ if (p==0) return(0);
+ while (*p) {
+ if (*p++ == m)
+ return(1);
+ }
+ return(0);
+}
+ /* the following are only used in the lex library */
+#if defined(__cplusplus) || defined(__STDC__)
+int yyinput(void)
+#else
+yyinput()
+#endif
+{
+#ifndef __cplusplus
+ return(input());
+#else
+ return(lex_input());
+#endif
+ }
+#if defined(__cplusplus) || defined(__STDC__)
+void yyoutput(int c)
+#else
+yyoutput(c)
+ int c;
+#endif
+{
+#ifndef __cplusplus
+ output(c);
+#else
+ lex_output(c);
+#endif
+ }
+#if defined(__cplusplus) || defined(__STDC__)
+void yyunput(int c)
+#else
+yyunput(c)
+ int c;
+#endif
+{
+ unput(c);
+ }
diff --git a/lib/libaccess/winnt.v b/lib/libaccess/winnt.v
new file mode 100644
index 00000000..9fea3453
--- /dev/null
+++ b/lib/libaccess/winnt.v
@@ -0,0 +1,156 @@
+/* Copyright (c) 1988 AT&T */
+/* All Rights Reserved */
+
+/* THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF AT&T */
+/* The copyright notice above does not evidence any */
+/* actual or intended publication of such source code. */
+
+#ifndef _VALUES_H
+#define _VALUES_H
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * These values work with any binary representation of integers
+ * where the high-order bit contains the sign.
+ */
+
+/* a number used normally for size of a shift */
+#define BITSPERBYTE 8
+
+#define BITS(type) (BITSPERBYTE * (int)sizeof (type))
+
+/* short, regular and long ints with only the high-order bit turned on */
+#define HIBITS ((short)(1 << BITS(short) - 1))
+
+#if defined(__STDC__)
+
+#define HIBITI (1U << BITS(int) - 1)
+#define HIBITL (1UL << BITS(long) - 1)
+
+#else
+
+#define HIBITI ((unsigned)1 << BITS(int) - 1)
+#define HIBITL (1L << BITS(long) - 1)
+
+#endif
+
+/* largest short, regular and long int */
+#define MAXSHORT ((short)~HIBITS)
+#define MAXINT ((int)(~HIBITI))
+#define MAXLONG ((long)(~HIBITL))
+
+/*
+ * various values that describe the binary floating-point representation
+ * _EXPBASE - the exponent base
+ * DMAXEXP - the maximum exponent of a double (as returned by frexp())
+ * FMAXEXP - the maximum exponent of a float (as returned by frexp())
+ * DMINEXP - the minimum exponent of a double (as returned by frexp())
+ * FMINEXP - the minimum exponent of a float (as returned by frexp())
+ * MAXDOUBLE - the largest double
+ * ((_EXPBASE ** DMAXEXP) * (1 - (_EXPBASE ** -DSIGNIF)))
+ * MAXFLOAT - the largest float
+ * ((_EXPBASE ** FMAXEXP) * (1 - (_EXPBASE ** -FSIGNIF)))
+ * MINDOUBLE - the smallest double (_EXPBASE ** (DMINEXP - 1))
+ * MINFLOAT - the smallest float (_EXPBASE ** (FMINEXP - 1))
+ * DSIGNIF - the number of significant bits in a double
+ * FSIGNIF - the number of significant bits in a float
+ * DMAXPOWTWO - the largest power of two exactly representable as a double
+ * FMAXPOWTWO - the largest power of two exactly representable as a float
+ * _IEEE - 1 if IEEE standard representation is used
+ * _DEXPLEN - the number of bits for the exponent of a double
+ * _FEXPLEN - the number of bits for the exponent of a float
+ * _HIDDENBIT - 1 if high-significance bit of mantissa is implicit
+ * LN_MAXDOUBLE - the natural log of the largest double -- log(MAXDOUBLE)
+ * LN_MINDOUBLE - the natural log of the smallest double -- log(MINDOUBLE)
+ * LN_MAXFLOAT - the natural log of the largest float -- log(MAXFLOAT)
+ * LN_MINFLOAT - the natural log of the smallest float -- log(MINFLOAT)
+ */
+
+#if defined(__STDC__)
+
+/*
+ * Note that the following construct, "!#machine(name)", is a non-standard
+ * extension to ANSI-C. It is maintained here to provide compatibility
+ * for existing compilations systems, but should be viewed as transitional
+ * and may be removed in a future release. If it is required that this
+ * file not contain this extension, edit this file to remove the offending
+ * condition.
+ *
+ * These machines are all IEEE-754:
+ */
+#if #machine(i386) || defined(__i386) || #machine(sparc) || defined(__sparc)
+#define MAXDOUBLE 1.79769313486231570e+308
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+#define MINDOUBLE 4.94065645841246544e-324
+#define MINFLOAT ((float)1.40129846432481707e-45)
+#define _IEEE 1
+#define _DEXPLEN 11
+#define _HIDDENBIT 1
+#define _LENBASE 1
+#define DMINEXP (-(DMAXEXP + DSIGNIF - _HIDDENBIT - 3))
+#define FMINEXP (-(FMAXEXP + FSIGNIF - _HIDDENBIT - 3))
+#else
+#error ISA not supported
+#endif
+
+#else
+
+/*
+ * These machines are all IEEE-754:
+ */
+#if defined(i386) || defined(__i386) || defined(sparc) || defined(__sparc)
+#define MAXDOUBLE 1.79769313486231570e+308
+#define MAXFLOAT ((float)3.40282346638528860e+38)
+#define MINDOUBLE 4.94065645841246544e-324
+#define MINFLOAT ((float)1.40129846432481707e-45)
+#define _IEEE 1
+#define _DEXPLEN 11
+#define _HIDDENBIT 1
+#define _LENBASE 1
+#define DMINEXP (-(DMAXEXP + DSIGNIF - _HIDDENBIT - 3))
+#define FMINEXP (-(FMAXEXP + FSIGNIF - _HIDDENBIT - 3))
+#else
+/* #error is strictly ansi-C, but works as well as anything for K&R systems. */
+/*#error ISA not supported */
+#endif
+
+#endif /* __STDC__ */
+
+#define _EXPBASE (1 << _LENBASE)
+#define _FEXPLEN 8
+#define DSIGNIF (BITS(double) - _DEXPLEN + _HIDDENBIT - 1)
+#define FSIGNIF (BITS(float) - _FEXPLEN + _HIDDENBIT - 1)
+#define DMAXPOWTWO ((double)(1L << BITS(long) - 2) * \
+ (1L << DSIGNIF - BITS(long) + 1))
+#define FMAXPOWTWO ((float)(1L << FSIGNIF - 1))
+#define DMAXEXP ((1 << _DEXPLEN - 1) - 1 + _IEEE)
+#define FMAXEXP ((1 << _FEXPLEN - 1) - 1 + _IEEE)
+#define LN_MAXDOUBLE (M_LN2 * DMAXEXP)
+#define LN_MAXFLOAT (float)(M_LN2 * FMAXEXP)
+#define LN_MINDOUBLE (M_LN2 * (DMINEXP - 1))
+#define LN_MINFLOAT (float)(M_LN2 * (FMINEXP - 1))
+#define H_PREC (DSIGNIF % 2 ? (1L << DSIGNIF/2) * M_SQRT2 : 1L << DSIGNIF/2)
+#define FH_PREC \
+ (float)(FSIGNIF % 2 ? (1L << FSIGNIF/2) * M_SQRT2 : 1L << FSIGNIF/2)
+#define X_EPS (1.0/H_PREC)
+#define FX_EPS (float)((float)1.0/FH_PREC)
+#define X_PLOSS ((double)(long)(M_PI * H_PREC))
+#define FX_PLOSS ((float)(long)(M_PI * FH_PREC))
+#define X_TLOSS (M_PI * DMAXPOWTWO)
+#define FX_TLOSS (float)(M_PI * FMAXPOWTWO)
+#define M_LN2 0.69314718055994530942
+#define M_PI 3.14159265358979323846
+#define M_SQRT2 1.41421356237309504880
+#define MAXBEXP DMAXEXP /* for backward compatibility */
+#define MINBEXP DMINEXP /* for backward compatibility */
+#define MAXPOWTWO DMAXPOWTWO /* for backward compatibility */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _VALUES_H */
diff --git a/lib/libaccess/winnt.y b/lib/libaccess/winnt.y
new file mode 100644
index 00000000..0ac06dfd
--- /dev/null
+++ b/lib/libaccess/winnt.y
@@ -0,0 +1,793 @@
+/** 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 <ctype.h>
+#include <string.h>
+#include "libaccess/ava.h"
+/*#include "libaccess/avapfile.h" */
+/* #include "netsite.h" */
+
+extern char *currFile;
+
+extern int linenum;
+extern char yytext[];
+
+static void AddDefType (int defType, char *defId);
+static void AddAVA (char* userID);
+
+void yyerror(const char* string);
+extern void logerror(const char* string,int num, char *file);
+
+AVAEntry tempEntry;
+AVATable entryTable;
+
+
+typedef union
+#ifdef __cplusplus
+ YYSTYPE
+#endif
+ {
+ char *string;
+ int num;
+} YYSTYPE;
+# define DEF_C 257
+# define DEF_CO 258
+# define DEF_OU 259
+# define DEF_CN 260
+# define EQ_SIGN 261
+# define DEF_START 262
+# define DEF_L 263
+# define DEF_E 264
+# define DEF_ST 265
+# define USER_ID 266
+# define DEF_ID 267
+
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#else
+#include <malloc.h>
+#include <memory.h>
+#endif
+
+#include <values.h>
+
+#ifdef __cplusplus
+
+#ifndef yyerror
+ void yyerror(const char *);
+#endif
+
+#ifndef yylex
+#ifdef __EXTERN_C__
+ extern "C" { int yylex(void); }
+#else
+ int yylex(void);
+#endif
+#endif
+ int yyparse(void);
+
+#endif
+#define yyclearin yychar = -1
+#define yyerrok yyerrflag = 0
+extern int yychar;
+extern int yyerrflag;
+YYSTYPE yylval;
+YYSTYPE yyval;
+typedef int yytabelem;
+#ifndef YYMAXDEPTH
+#define YYMAXDEPTH 150
+#endif
+#if YYMAXDEPTH > 0
+int yy_yys[YYMAXDEPTH], *yys = yy_yys;
+YYSTYPE yy_yyv[YYMAXDEPTH], *yyv = yy_yyv;
+#else /* user does initial allocation */
+int *yys;
+YYSTYPE *yyv;
+#endif
+static int yymaxdepth = YYMAXDEPTH;
+# define YYERRCODE 256
+
+
+
+void yyerror(const char* string) {
+ logerror(string,linenum,currFile);
+}
+
+
+void AddDefType (int defType, char *defId) {
+ switch (defType) {
+ case DEF_C:
+ tempEntry.country = defId;
+ break;
+ case DEF_CO:
+ tempEntry.company = defId;
+ break;
+ case DEF_OU:
+ if (tempEntry.numOrgs % ORGS_ALLOCSIZE == 0) {
+ if (tempEntry.numOrgs == 0) {
+ tempEntry.organizations =
+ system_malloc_perm (sizeof (char*) * ORGS_ALLOCSIZE);
+ } else {
+ char **temp;
+ temp =
+ system_malloc_perm(sizeof(char*) * (tempEntry.numOrgs + ORGS_ALLOCSIZE));
+ memcpy (temp, tempEntry.organizations,
+ sizeof(char*)*tempEntry.numOrgs);
+ system_free_perm(tempEntry.organizations);
+ tempEntry.organizations = temp;
+ }
+ }
+ tempEntry.organizations[tempEntry.numOrgs++] = defId;
+ break;
+ case DEF_CN:
+ tempEntry.CNEntry = defId;
+ break;
+ case DEF_E:
+ tempEntry.email = defId;
+ break;
+ case DEF_L:
+ tempEntry.locality = defId;
+ break;
+ case DEF_ST:
+ tempEntry.state = defId;
+ break;
+ default:
+ break;
+ }
+}
+
+void AddAVA (char* userID) {
+ AVAEntry *newAVA;
+
+ newAVA = (AVAEntry*)system_malloc_perm(sizeof(AVAEntry));
+ if (!newAVA) {
+ yyerror ("Out of Memory in AddAVA");
+ return;
+ }
+ *newAVA = tempEntry;
+ newAVA->userid = userID;
+
+ _addAVAtoTable (newAVA, &entryTable);
+
+ tempEntry.CNEntry = tempEntry.userid = tempEntry.country = tempEntry.company = 0;
+ tempEntry.email = tempEntry.locality = tempEntry.state = NULL;
+ tempEntry.numOrgs = 0;
+}
+yytabelem yyexca[] ={
+-1, 1,
+ 0, -1,
+ -2, 0,
+ };
+# define YYNPROD 18
+# define YYLAST 19
+yytabelem yyact[]={
+
+ 10, 11, 12, 13, 19, 4, 14, 15, 16, 18,
+ 8, 3, 7, 6, 5, 2, 1, 9, 17 };
+yytabelem yypact[]={
+
+ -261,-10000000, -261,-10000000, -257,-10000000,-10000000, -257,-10000000, -252,
+-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000,-10000000, -263,-10000000 };
+yytabelem yypgo[]={
+
+ 0, 17, 16, 15, 11, 13, 12, 10 };
+yytabelem yyr1[]={
+
+ 0, 2, 2, 3, 3, 4, 5, 5, 6, 6,
+ 7, 1, 1, 1, 1, 1, 1, 1 };
+yytabelem yyr2[]={
+
+ 0, 2, 0, 4, 2, 5, 2, 0, 4, 2,
+ 7, 3, 3, 3, 3, 3, 3, 3 };
+yytabelem yychk[]={
+
+-10000000, -2, -3, -4, 266, -4, -5, -6, -7, -1,
+ 257, 258, 259, 260, 263, 264, 265, -7, 261, 267 };
+yytabelem yydef[]={
+
+ 2, -2, 1, 4, 7, 3, 5, 6, 9, 0,
+ 11, 12, 13, 14, 15, 16, 17, 8, 0, 10 };
+typedef struct
+#ifdef __cplusplus
+ yytoktype
+#endif
+{ char *t_name; int t_val; } yytoktype;
+#ifndef YYDEBUG
+# define YYDEBUG 0 /* don't allow debugging */
+#endif
+
+#if YYDEBUG
+
+yytoktype yytoks[] =
+{
+ "DEF_C", 257,
+ "DEF_CO", 258,
+ "DEF_OU", 259,
+ "DEF_CN", 260,
+ "EQ_SIGN", 261,
+ "DEF_START", 262,
+ "DEF_L", 263,
+ "DEF_E", 264,
+ "DEF_ST", 265,
+ "USER_ID", 266,
+ "DEF_ID", 267,
+ "-unknown-", -1 /* ends search */
+};
+
+char * yyreds[] =
+{
+ "-no such reduction-",
+ "source : ava.database",
+ "source : /* empty */",
+ "ava.database : ava.database ava",
+ "ava.database : ava",
+ "ava : USER_ID definitions",
+ "definitions : definition.list",
+ "definitions : /* empty */",
+ "definition.list : definition.list definition",
+ "definition.list : definition",
+ "definition : def.type EQ_SIGN DEF_ID",
+ "def.type : DEF_C",
+ "def.type : DEF_CO",
+ "def.type : DEF_OU",
+ "def.type : DEF_CN",
+ "def.type : DEF_L",
+ "def.type : DEF_E",
+ "def.type : DEF_ST",
+};
+#endif /* YYDEBUG */
+
+
+/*
+** Skeleton parser driver for yacc output
+*/
+
+/*
+** yacc user known macros and defines
+*/
+#define YYERROR goto yyerrlab
+#define YYACCEPT return(0)
+#define YYABORT return(1)
+#define YYBACKUP( newtoken, newvalue )\
+{\
+ if ( yychar >= 0 || ( yyr2[ yytmp ] >> 1 ) != 1 )\
+ {\
+ yyerror( "syntax error - cannot backup" );\
+ goto yyerrlab;\
+ }\
+ yychar = newtoken;\
+ yystate = *yyps;\
+ yylval = newvalue;\
+ goto yynewstate;\
+}
+#define YYRECOVERING() (!!yyerrflag)
+#define YYNEW(type) system_malloc(sizeof(type) * yynewmax)
+#define YYCOPY(to, from, type) \
+ (type *) memcpy(to, (char *) from, yynewmax * sizeof(type))
+#define YYENLARGE( from, type) \
+ (type *) system_realloc((char *) from, yynewmax * sizeof(type))
+#ifndef YYDEBUG
+# define YYDEBUG 1 /* make debugging available */
+#endif
+
+/*
+** user known globals
+*/
+int yydebug; /* set to 1 to get debugging */
+
+/*
+** driver internal defines
+*/
+#define YYFLAG (-10000000)
+
+/*
+** global variables used by the parser
+*/
+YYSTYPE *yypv; /* top of value stack */
+int *yyps; /* top of state stack */
+
+int yystate; /* current state */
+int yytmp; /* extra var (lasts between blocks) */
+
+int yynerrs; /* number of errors */
+int yyerrflag; /* error recovery flag */
+int yychar; /* current input token number */
+
+
+
+#ifdef YYNMBCHARS
+#define YYLEX() yycvtok(yylex())
+/*
+** yycvtok - return a token if i is a wchar_t value that exceeds 255.
+** If i<255, i itself is the token. If i>255 but the neither
+** of the 30th or 31st bit is on, i is already a token.
+*/
+#if defined(__STDC__) || defined(__cplusplus)
+int yycvtok(int i)
+#else
+int yycvtok(i) int i;
+#endif
+{
+ int first = 0;
+ int last = YYNMBCHARS - 1;
+ int mid;
+ wchar_t j;
+
+ if(i&0x60000000){/*Must convert to a token. */
+ if( yymbchars[last].character < i ){
+ return i;/*Giving up*/
+ }
+ while ((last>=first)&&(first>=0)) {/*Binary search loop*/
+ mid = (first+last)/2;
+ j = yymbchars[mid].character;
+ if( j==i ){/*Found*/
+ return yymbchars[mid].tvalue;
+ }else if( j<i ){
+ first = mid + 1;
+ }else{
+ last = mid -1;
+ }
+ }
+ /*No entry in the table.*/
+ return i;/* Giving up.*/
+ }else{/* i is already a token. */
+ return i;
+ }
+}
+#else/*!YYNMBCHARS*/
+#define YYLEX() yylex()
+#endif/*!YYNMBCHARS*/
+
+/*
+** yyparse - return 0 if worked, 1 if syntax error not recovered from
+*/
+#if defined(__STDC__) || defined(__cplusplus)
+int yyparse(void)
+#else
+int yyparse()
+#endif
+{
+ register YYSTYPE *yypvt; /* top of value stack for $vars */
+
+#if defined(__cplusplus) || defined(lint)
+/*
+ hacks to please C++ and lint - goto's inside switch should never be
+ executed; yypvt is set to 0 to avoid "used before set" warning.
+*/
+ static int __yaccpar_lint_hack__ = 0;
+ switch (__yaccpar_lint_hack__)
+ {
+ case 1: goto yyerrlab;
+ case 2: goto yynewstate;
+ }
+ yypvt = 0;
+#endif
+
+ /*
+ ** Initialize externals - yyparse may be called more than once
+ */
+ yypv = &yyv[-1];
+ yyps = &yys[-1];
+ yystate = 0;
+ yytmp = 0;
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = -1;
+
+#if YYMAXDEPTH <= 0
+ if (yymaxdepth <= 0)
+ {
+ if ((yymaxdepth = YYEXPAND(0)) <= 0)
+ {
+ yyerror("yacc initialization error");
+ YYABORT;
+ }
+ }
+#endif
+
+ {
+ register YYSTYPE *yy_pv; /* top of value stack */
+ register int *yy_ps; /* top of state stack */
+ register int yy_state; /* current state */
+ register int yy_n; /* internal state number info */
+ goto yystack; /* moved from 6 lines above to here to please C++ */
+
+ /*
+ ** get globals into registers.
+ ** branch to here only if YYBACKUP was called.
+ */
+ yynewstate:
+ yy_pv = yypv;
+ yy_ps = yyps;
+ yy_state = yystate;
+ goto yy_newstate;
+
+ /*
+ ** get globals into registers.
+ ** either we just started, or we just finished a reduction
+ */
+ yystack:
+ yy_pv = yypv;
+ yy_ps = yyps;
+ yy_state = yystate;
+
+ /*
+ ** top of for (;;) loop while no reductions done
+ */
+ yy_stack:
+ /*
+ ** put a state and value onto the stacks
+ */
+#if YYDEBUG
+ /*
+ ** if debugging, look up token value in list of value vs.
+ ** name pairs. 0 and negative (-1) are special values.
+ ** Note: linear search is used since time is not a real
+ ** consideration while debugging.
+ */
+ if ( yydebug )
+ {
+ register int yy_i;
+
+ printf( "State %d, token ", yy_state );
+ if ( yychar == 0 )
+ printf( "end-of-file\n" );
+ else if ( yychar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val == yychar )
+ break;
+ }
+ printf( "%s\n", yytoks[yy_i].t_name );
+ }
+ }
+#endif /* YYDEBUG */
+ if ( ++yy_ps >= &yys[ yymaxdepth ] ) /* room on stack? */
+ {
+ /*
+ ** reallocate and recover. Note that pointers
+ ** have to be reset, or bad things will happen
+ */
+ int yyps_index = (yy_ps - yys);
+ int yypv_index = (yy_pv - yyv);
+ int yypvt_index = (yypvt - yyv);
+ int yynewmax;
+#ifdef YYEXPAND
+ yynewmax = YYEXPAND(yymaxdepth);
+#else
+ yynewmax = 2 * yymaxdepth; /* double table size */
+ if (yymaxdepth == YYMAXDEPTH) /* first time growth */
+ {
+ char *newyys = (char *)YYNEW(int);
+ char *newyyv = (char *)YYNEW(YYSTYPE);
+ if (newyys != 0 && newyyv != 0)
+ {
+ yys = YYCOPY(newyys, yys, int);
+ yyv = YYCOPY(newyyv, yyv, YYSTYPE);
+ }
+ else
+ yynewmax = 0; /* failed */
+ }
+ else /* not first time */
+ {
+ yys = YYENLARGE(yys, int);
+ yyv = YYENLARGE(yyv, YYSTYPE);
+ if (yys == 0 || yyv == 0)
+ yynewmax = 0; /* failed */
+ }
+#endif
+ if (yynewmax <= yymaxdepth) /* tables not expanded */
+ {
+ yyerror( "yacc stack overflow" );
+ YYABORT;
+ }
+ yymaxdepth = yynewmax;
+
+ yy_ps = yys + yyps_index;
+ yy_pv = yyv + yypv_index;
+ yypvt = yyv + yypvt_index;
+ }
+ *yy_ps = yy_state;
+ *++yy_pv = yyval;
+
+ /*
+ ** we have a new state - find out what to do
+ */
+ yy_newstate:
+ if ( ( yy_n = yypact[ yy_state ] ) <= YYFLAG )
+ goto yydefault; /* simple state */
+#if YYDEBUG
+ /*
+ ** if debugging, need to mark whether new token grabbed
+ */
+ yytmp = yychar < 0;
+#endif
+ if ( ( yychar < 0 ) && ( ( yychar = YYLEX() ) < 0 ) )
+ yychar = 0; /* reached EOF */
+#if YYDEBUG
+ if ( yydebug && yytmp )
+ {
+ register int yy_i;
+
+ printf( "Received token " );
+ if ( yychar == 0 )
+ printf( "end-of-file\n" );
+ else if ( yychar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( yy_i = 0; yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val == yychar )
+ break;
+ }
+ printf( "%s\n", yytoks[yy_i].t_name );
+ }
+ }
+#endif /* YYDEBUG */
+ if ( ( ( yy_n += yychar ) < 0 ) || ( yy_n >= YYLAST ) )
+ goto yydefault;
+ if ( yychk[ yy_n = yyact[ yy_n ] ] == yychar ) /*valid shift*/
+ {
+ yychar = -1;
+ yyval = yylval;
+ yy_state = yy_n;
+ if ( yyerrflag > 0 )
+ yyerrflag--;
+ goto yy_stack;
+ }
+
+ yydefault:
+ if ( ( yy_n = yydef[ yy_state ] ) == -2 )
+ {
+#if YYDEBUG
+ yytmp = yychar < 0;
+#endif
+ if ( ( yychar < 0 ) && ( ( yychar = YYLEX() ) < 0 ) )
+ yychar = 0; /* reached EOF */
+#if YYDEBUG
+ if ( yydebug && yytmp )
+ {
+ register int yy_i;
+
+ printf( "Received token " );
+ if ( yychar == 0 )
+ printf( "end-of-file\n" );
+ else if ( yychar < 0 )
+ printf( "-none-\n" );
+ else
+ {
+ for ( yy_i = 0;
+ yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val
+ == yychar )
+ {
+ break;
+ }
+ }
+ printf( "%s\n", yytoks[yy_i].t_name );
+ }
+ }
+#endif /* YYDEBUG */
+ /*
+ ** look through exception table
+ */
+ {
+ register int *yyxi = yyexca;
+
+ while ( ( *yyxi != -1 ) ||
+ ( yyxi[1] != yy_state ) )
+ {
+ yyxi += 2;
+ }
+ while ( ( *(yyxi += 2) >= 0 ) &&
+ ( *yyxi != yychar ) )
+ ;
+ if ( ( yy_n = yyxi[1] ) < 0 )
+ YYACCEPT;
+ }
+ }
+
+ /*
+ ** check for syntax error
+ */
+ if ( yy_n == 0 ) /* have an error */
+ {
+ /* no worry about speed here! */
+ switch ( yyerrflag )
+ {
+ case 0: /* new error */
+ yyerror( "syntax error" );
+ goto skip_init;
+ yyerrlab:
+ /*
+ ** get globals into registers.
+ ** we have a user generated syntax type error
+ */
+ yy_pv = yypv;
+ yy_ps = yyps;
+ yy_state = yystate;
+ skip_init:
+ yynerrs++;
+ /* FALLTHRU */
+ case 1:
+ case 2: /* incompletely recovered error */
+ /* try again... */
+ yyerrflag = 3;
+ /*
+ ** find state where "error" is a legal
+ ** shift action
+ */
+ while ( yy_ps >= yys )
+ {
+ yy_n = yypact[ *yy_ps ] + YYERRCODE;
+ if ( yy_n >= 0 && yy_n < YYLAST &&
+ yychk[yyact[yy_n]] == YYERRCODE) {
+ /*
+ ** simulate shift of "error"
+ */
+ yy_state = yyact[ yy_n ];
+ goto yy_stack;
+ }
+ /*
+ ** current state has no shift on
+ ** "error", pop stack
+ */
+#if YYDEBUG
+# define _POP_ "Error recovery pops state %d, uncovers state %d\n"
+ if ( yydebug )
+ printf( _POP_, *yy_ps,
+ yy_ps[-1] );
+# undef _POP_
+#endif
+ yy_ps--;
+ yy_pv--;
+ }
+ /*
+ ** there is no state on stack with "error" as
+ ** a valid shift. give up.
+ */
+ YYABORT;
+ case 3: /* no shift yet; eat a token */
+#if YYDEBUG
+ /*
+ ** if debugging, look up token in list of
+ ** pairs. 0 and negative shouldn't occur,
+ ** but since timing doesn't matter when
+ ** debugging, it doesn't hurt to leave the
+ ** tests here.
+ */
+ if ( yydebug )
+ {
+ register int yy_i;
+
+ printf( "Error recovery discards " );
+ if ( yychar == 0 )
+ printf( "token end-of-file\n" );
+ else if ( yychar < 0 )
+ printf( "token -none-\n" );
+ else
+ {
+ for ( yy_i = 0;
+ yytoks[yy_i].t_val >= 0;
+ yy_i++ )
+ {
+ if ( yytoks[yy_i].t_val
+ == yychar )
+ {
+ break;
+ }
+ }
+ printf( "token %s\n",
+ yytoks[yy_i].t_name );
+ }
+ }
+#endif /* YYDEBUG */
+ if ( yychar == 0 ) /* reached EOF. quit */
+ YYABORT;
+ yychar = -1;
+ goto yy_newstate;
+ }
+ }/* end if ( yy_n == 0 ) */
+ /*
+ ** reduction by production yy_n
+ ** put stack tops, etc. so things right after switch
+ */
+#if YYDEBUG
+ /*
+ ** if debugging, print the string that is the user's
+ ** specification of the reduction which is just about
+ ** to be done.
+ */
+ if ( yydebug )
+ printf( "Reduce by (%d) \"%s\"\n",
+ yy_n, yyreds[ yy_n ] );
+#endif
+ yytmp = yy_n; /* value to switch over */
+ yypvt = yy_pv; /* $vars top of value stack */
+ /*
+ ** Look in goto table for next state
+ ** Sorry about using yy_state here as temporary
+ ** register variable, but why not, if it works...
+ ** If yyr2[ yy_n ] doesn't have the low order bit
+ ** set, then there is no action to be done for
+ ** this reduction. So, no saving & unsaving of
+ ** registers done. The only difference between the
+ ** code just after the if and the body of the if is
+ ** the goto yy_stack in the body. This way the test
+ ** can be made before the choice of what to do is needed.
+ */
+ {
+ /* length of production doubled with extra bit */
+ register int yy_len = yyr2[ yy_n ];
+
+ if ( !( yy_len & 01 ) )
+ {
+ yy_len >>= 1;
+ yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
+ yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
+ *( yy_ps -= yy_len ) + 1;
+ if ( yy_state >= YYLAST ||
+ yychk[ yy_state =
+ yyact[ yy_state ] ] != -yy_n )
+ {
+ yy_state = yyact[ yypgo[ yy_n ] ];
+ }
+ goto yy_stack;
+ }
+ yy_len >>= 1;
+ yyval = ( yy_pv -= yy_len )[1]; /* $$ = $1 */
+ yy_state = yypgo[ yy_n = yyr1[ yy_n ] ] +
+ *( yy_ps -= yy_len ) + 1;
+ if ( yy_state >= YYLAST ||
+ yychk[ yy_state = yyact[ yy_state ] ] != -yy_n )
+ {
+ yy_state = yyact[ yypgo[ yy_n ] ];
+ }
+ }
+ /* save until reenter driver code */
+ yystate = yy_state;
+ yyps = yy_ps;
+ yypv = yy_pv;
+ }
+ /*
+ ** code supplied by user is placed in this switch
+ */
+ switch( yytmp )
+ {
+
+case 5:
+{AddAVA(yypvt[-1].string);} break;
+case 10:
+{AddDefType(yypvt[-2].num, yypvt[-0].string);} break;
+case 11:
+{yyval.num = DEF_C; } break;
+case 12:
+{yyval.num = DEF_CO;} break;
+case 13:
+{yyval.num = DEF_OU;} break;
+case 14:
+{yyval.num = DEF_CN;} break;
+case 15:
+{yyval.num = DEF_L; } break;
+case 16:
+{yyval.num = DEF_E; } break;
+case 17:
+{yyval.num = DEF_ST;} break;
+ }
+ goto yystack; /* reset registers in driver code */
+}
+
diff --git a/lib/libaccess/wintab.h b/lib/libaccess/wintab.h
new file mode 100644
index 00000000..b764cf78
--- /dev/null
+++ b/lib/libaccess/wintab.h
@@ -0,0 +1,26 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+typedef union
+#ifdef __cplusplus
+ YYSTYPE
+#endif
+ {
+ char *string;
+ int num;
+} YYSTYPE;
+extern YYSTYPE yylval;
+# define DEF_C 257
+# define DEF_CO 258
+# define DEF_OU 259
+# define DEF_CN 260
+# define EQ_SIGN 261
+# define DEF_START 262
+# define DEF_L 263
+# define DEF_E 264
+# define DEF_ST 265
+# define USER_ID 266
+# define DEF_ID 267
diff --git a/lib/libaccess/yy-sed b/lib/libaccess/yy-sed
new file mode 100644
index 00000000..24c4eaac
--- /dev/null
+++ b/lib/libaccess/yy-sed
@@ -0,0 +1,21 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+/#include <unistd.h>/d
+/#include <values.h>/d
+/#pragma ident/d
+s/malloc.h/netsite.h/g
+s/yyparse/acl_Parse/g
+s/yy_flex_alloc/ACL_FLEX_ALLOC/g
+s/yy_flex_realloc/ACL_FLEX_REALLOC/g
+s/yy_flex_free/ACL_FLEX_FREE/g
+s/malloc(/PERM_MALLOC(/g
+s/free(/PERM_FREE(/g
+s/realloc(/PERM_REALLOC(/g
+s/yy/acl/g
+s/YY/ACL/g
+s/lex.acl.c/acl.yy.cpp/g
diff --git a/lib/libadmin/Makefile b/lib/libadmin/Makefile
new file mode 100644
index 00000000..68029ce2
--- /dev/null
+++ b/lib/libadmin/Makefile
@@ -0,0 +1,61 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# The admin libraries
+
+MCOM_ROOT=../../..
+
+MODULE=LibAdmin
+MODULE_CFLAGS=-DENCRYPT_PASSWORDS -DUSE_ADMSERV
+
+include ../../nsdefs.mk
+
+OBJDEST=$(OBJDIR)/lib/libadmin
+
+ifeq ($(ARCH), WINNT)
+LIBS=$(OBJDIR)/lib/libadmin.lib
+else
+LIBS=$(OBJDIR)/lib/libadmin.a
+endif
+
+OBJS=$(addprefix $(OBJDEST)/, admconf.o form_get.o error.o admlog.o \
+ magconf.o ns-util.o objconf.o password.o \
+ referer.o template.o util.o \
+ hinstall.o admserv.o install.o nsnews.o \
+ commit.o pcontrol.o get_msg.o \
+ multconf.o httpcon.o authdb.o usrlists.o \
+ dstats.o backup.o cluster.o \
+ keyconf.o strlist.o $(OSOBJS))
+
+# moved files [to libadminutil] : form_post.o strlist.o distadm.o cron_conf.o
+# candidate for moing: admlog.o error.o admserv.o
+# replaced files: error.o [by libadminutil/errRpt.c]
+# removed for lack of ndbm support from binary release of libdbm.... userdb.o
+#!! nsnews.o does not work anymore.
+
+all: $(OBJDEST) $(LIBS)
+
+$(LIBS): $(addprefix $(MCOM_ROOT)/ldapserver/include/libadmin/, \
+ hadm_msgs.i la_msgs.i)
+
+include ../../nsconfig.mk
+
+MCC_INCLUDE += $(ADMINUTIL_INCLUDE)
+
+ifeq ($(ARCH), HPUX)
+CC=$(CCC)
+endif
+
+$(OBJDEST):
+ mkdir -p $(OBJDEST)
+
+$(LIBS): $(OBJS)
+ rm -f $@
+ $(AR) $(OBJS)
+ $(RANLIB) $@
+
+include $(INCLUDE_DEPENDS)
diff --git a/lib/libadmin/authdb.c b/lib/libadmin/authdb.c
new file mode 100644
index 00000000..8aff4ca8
--- /dev/null
+++ b/lib/libadmin/authdb.c
@@ -0,0 +1,2467 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * authdb.c: Functions to aid in user/group database admin
+ *
+ * These things leak memory like a sieve.
+ *
+ * Ben Polk
+ * (blame Mike McCool for functions with an MLM)
+ */
+
+#ifdef XP_UNIX
+#include <dirent.h>
+#endif /* WIN32? */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <stdio.h>
+#include "base/shexp.h"
+#include "base/util.h"
+#include "libadminutil/admutil.h"
+#include "libadmin/libadmin.h"
+
+#include "libaccess/nsgmgmt.h"
+#include "libaccess/nsumgmt.h"
+/* XXX MLM - This shouldn't have to define itself as private. */
+#define __PRIVATE_NSADB
+#include "libaccess/nsadb.h"
+#include "libaccess/nsamgmt.h"
+#include "libaccess/aclerror.h"
+#include "libaccess/aclbuild.h"
+#include "libaccess/acladmin.h"
+#include "usrlists.h"
+
+#define BUF_SIZE 10
+
+void list_authdbs(char *fullpath, char *partialpath);
+
+static char **list;
+static int listsize;
+static int curentry;
+
+/*
+ * Rights we know about. This should be moved out to some
+ * external location. Perhaps obj.conf?
+ */
+NSAPI_PUBLIC char *acl_read_rights[] =
+{
+ "GET",
+ "HEAD",
+ "POST",
+ "INDEX",
+#ifdef MCC_PROXY
+ "CONNECT",
+#endif
+ NULL
+};
+
+NSAPI_PUBLIC char *acl_write_rights[] =
+{
+ "PUT",
+ "DELETE",
+ "MKDIR",
+ "RMDIR",
+ "MOVE",
+ NULL
+};
+
+
+/*
+ * passfilter - function returns non-zero if the regular expression
+ * passed in matches the string passed in.
+ */
+static int passfilter(char *str, char *regexp)
+{
+ if (!str)
+ return 0; /* NULL string never matches */
+ else if (!regexp)
+ return 1; /* NULL regexp matches everything */
+ else
+ return(!shexp_casecmp(str, regexp));
+}
+
+NSAPI_PUBLIC char **list_auth_dbs(char *fullpath)
+{
+ list = new_strlist(BUF_SIZE);
+ listsize = BUF_SIZE;
+ curentry = 0;
+ list_authdbs(fullpath, "");
+
+ return(list);
+}
+
+NSAPI_PUBLIC void output_authdb_selector(char *path, char *element, char *current) {
+ char **pathlist = list_auth_dbs(path);
+ int currentnum = -1;
+ int plen = path ? strlen(path) : 0;
+ register int x;
+
+ /*
+ * If the 'current' string begins with the 'path' string, remove the
+ * 'path' prefix.
+ */
+ if (!strncmp(current, path, plen)) {
+ current += plen;
+ if (*current == FILE_PATHSEP) ++current;
+ }
+
+ if (pathlist[0]) /* Is there at least one database? */
+ {
+ /* Find current selection in list of databases. */
+ for(x=0; pathlist[x]; x++) {
+ if(!strcmp(current, pathlist[x])) {
+ currentnum = x;
+ continue;
+ }
+ }
+
+/* BONEHEAD */
+ fprintf(stdout, "<SELECT name=\"%s\" %s>",
+ element, (x>SELECT_OVERFLOW) ? "size=5" : "");
+
+ /* If the current selection is in there, put it first. */
+ if(currentnum != -1) {
+ fprintf(stdout, "<OPTION value=\"%s\" SELECTED>%s\n",
+ pathlist[currentnum], pathlist[currentnum]);
+
+ }
+ for(x=0; pathlist[x]; x++) {
+ if (x == currentnum)
+ continue;
+
+ fprintf(stdout, "<OPTION value=\"%s\">%s\n",
+ pathlist[x], pathlist[x]);
+ }
+ fprintf(stdout, "</SELECT>");
+ } else {
+ fprintf(stdout, "<b>No databases found.</b>");
+ }
+}
+
+NSAPI_PUBLIC char *get_current_authdb()
+{
+ char **config = get_adm_config();
+ return(STRDUP(config[3]));
+}
+
+NSAPI_PUBLIC void set_current_authdb(char *current)
+{
+ char **config = get_adm_config();
+ config[3] = STRDUP(current);
+ write_adm_config(config);
+}
+
+void list_authdbs(char *fullpath, char *partialpath)
+{
+ int stat_good;
+ struct stat finfo;
+ char **dirlisting;
+ char *path = (char *)MALLOC(strlen(fullpath)+strlen(partialpath)+2);
+
+ sprintf(path, "%s%c%s", fullpath, FILE_PATHSEP, partialpath);
+ if( !(dirlisting = list_directory(path,0)))
+ return;
+ else {
+ register int x;
+ char *entry, *newppath;
+
+ for(x=0; dirlisting[x]; x++) {
+ entry = (char *)MALLOC(strlen(path)+strlen(dirlisting[x])+2);
+ sprintf(entry, "%s%s", path, dirlisting[x]);
+
+#ifdef XP_UNIX
+ stat_good = (lstat(entry, &finfo) == -1 ? 0 : 1);
+#else /* WIN32 */
+ stat_good = (stat(entry, &finfo) == -1 ? 0 : 1);
+#endif /* XP_UNIX */
+
+ if(!stat_good)
+ continue;
+ newppath = (char *)MALLOC(strlen(partialpath)+strlen(dirlisting[x])+3);
+
+ if(S_ISDIR(finfo.st_mode)) {
+ sprintf(newppath, "%s%s", partialpath, dirlisting[x]);
+ curentry++;
+
+ if(!(curentry < listsize)) {
+ listsize += BUF_SIZE;
+ list = grow_strlist(list, listsize);
+ }
+ list[curentry-1] = STRDUP(newppath);
+ list[curentry] = NULL;
+ }
+
+ FREE(entry);
+ FREE(newppath);
+ }
+ }
+}
+
+/* Get the userdb directory. (V1.x) */
+NSAPI_PUBLIC char *get_userdb_dir(void)
+{
+ char *userdb;
+ char line[BIG_LINE];
+
+#ifdef USE_ADMSERV
+ char *tmp = getenv("NETSITE_ROOT");
+
+ sprintf(line, "%s%cuserdb", tmp, FILE_PATHSEP);
+#else
+ char *tmp = get_mag_var("#ServerRoot");
+
+ sprintf(line, "%s%cadmin%cuserdb", tmp, FILE_PATHSEP, FILE_PATHSEP);
+#endif
+ userdb = STRDUP(line);
+ return userdb;
+}
+
+/* Get the httpacl directory. (V2.x) */
+NSAPI_PUBLIC char *get_httpacl_dir(void)
+{
+ char *httpacl;
+ char line[BIG_LINE];
+
+#ifdef USE_ADMSERV
+ char *tmp = getenv("NETSITE_ROOT");
+
+ sprintf(line, "%s%chttpacl", tmp, FILE_PATHSEP);
+#else
+ char *tmp = get_mag_var("#ServerRoot");
+
+ sprintf(line, "%s%cadmin%chttpacl", tmp, FILE_PATHSEP, FILE_PATHSEP);
+#endif
+ httpacl = STRDUP(line);
+ return httpacl;
+}
+
+/* Get the authdb directory. (V2.x) */
+NSAPI_PUBLIC char *get_authdb_dir(void)
+{
+ char *authdb;
+ char line[BIG_LINE];
+
+#ifdef USE_ADMSERV
+ char *tmp = getenv("NETSITE_ROOT");
+
+ sprintf(line, "%s%cauthdb", tmp, FILE_PATHSEP);
+#else
+ char *tmp = get_mag_var("#ServerRoot");
+
+ sprintf(line, "%s%cadmin%cauthdb", tmp, FILE_PATHSEP, FILE_PATHSEP);
+#endif
+ authdb = STRDUP(line);
+ return authdb;
+}
+/*
+ * groupOrUser - function sets its return variable flags
+ * based on whether the name passed in is
+ * a user or a group in the specified database.
+ * It could be both, although the entry form
+ * are intended to prohibit this.
+ * Returns: 0 if no error occurs, something else otherwise.
+ */
+NSAPI_PUBLIC int groupOrUser(char *db_path, char *name, int *is_user, int *is_group)
+{
+ int rv = 1;
+ UserObj_t *uoptr;
+ GroupObj_t *goptr;
+ void *padb;
+
+ if (name && is_user && is_group) {
+ *is_user = 0;
+ *is_group = 0;
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (!rv) {
+
+ rv = nsadbFindByName(NULL, padb, name, AIF_USER, (void **)&uoptr);
+ if (rv == AIF_USER) {
+ *is_user = 1;
+ }
+
+ rv = nsadbFindByName(NULL, padb, name, AIF_GROUP, (void **)&goptr);
+ if (rv == AIF_GROUP) {
+ *is_group = 1;
+ }
+
+ nsadbClose(padb, 0);
+ }
+ }
+
+ return rv;
+}
+
+/*
+ * getfullname - function to get the fullname of a user.
+ * Return: Returns 0 if it works, something else if it fails.
+ */
+NSAPI_PUBLIC int getfullname(char *db_path, char *user, char **fullname) {
+ int rv;
+ UserObj_t *uoptr;
+ void *padb;
+
+ if (db_path && user)
+ {
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv == 0) {
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ if (rv == AIF_USER) {
+ *fullname = (uoptr->uo_rname != 0) ? STRDUP((char *)uoptr->uo_rname)
+ : STRDUP("");
+ }
+ else
+ rv = 1;
+ nsadbClose(padb, 0);
+ }
+ }
+ else
+ rv = 1;
+
+ return rv;
+}
+
+/*
+ * setfullname - function to set the fullname for the specified user.
+ * Return: Returns 0 if it works, something else if it fails.
+ */
+NSAPI_PUBLIC int setfullname(char *db_path, char *user, char *fullname) {
+ int rv;
+ UserObj_t *uoptr;
+ void *padb;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, "Failed To Open Database",
+ "An error occurred while trying to update "
+ "the user's fullname in the database.");
+ } else {
+ /* See if the user already exists, if so, update it. */
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ if (rv == AIF_USER) {
+ uoptr->uo_rname = (NTS_t)fullname;
+ } else {
+ /* User doesn't exist, so we've failed. */
+ report_error(SYSTEM_ERROR, user,
+ "Unable to change this user's fullname, "
+ "user was not found in the database.");
+ rv = 1;
+ }
+
+ if (uoptr) {
+ rv = nsadbModifyUser(NULL, padb, uoptr);
+ if (rv < 0)
+ report_error(SYSTEM_ERROR, user,
+ "A database error occurred while "
+ "trying to change the user fullname.");
+ }
+ nsadbClose(padb, 0);
+ }
+ return rv;
+}
+
+/* Set a user's login name MLM*/
+NSAPI_PUBLIC int setusername(char *db_path, char *user, char *newname) {
+ int rv;
+ UserObj_t *uoptr;
+ void *padb;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, "Failed To Open Database",
+ "An error occurred while trying to update "
+ "the user's fullname in the database.");
+ } else {
+ /* See if the user already exists, if so, update it. */
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ if (rv != AIF_USER) {
+ /* User doesn't exist, so we've failed. */
+ report_error(SYSTEM_ERROR, user,
+ "Unable to change this user's fullname, "
+ "user was not found in the database.");
+ rv = 1;
+ }
+ if (uoptr) {
+ rv = userRename(NULL, ((AuthDB_t *)padb)->adb_userdb,
+ uoptr, (NTS_t)newname);
+
+ if (rv < 0)
+ report_error(SYSTEM_ERROR, user,
+ "A database error occurred while "
+ "trying to change the login name.");
+ }
+ nsadbClose(padb, 0);
+ }
+ return rv;
+}
+
+/*
+ * addusertogroup - function to add a user to a group
+ * Return: Returns 0 if it works, something else if it fails.
+ */
+NSAPI_PUBLIC int addusertogroup(char *db_path, char *user, char *group) {
+ int rv;
+ UserObj_t *uoptr;
+ GroupObj_t *goptr;
+ void *padb;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, "Failed To Open Database",
+ "An error occurred while trying to add "
+ "user to a group.");
+ } else {
+ /* See if the user and group exist. */
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ if (goptr == 0) {
+ report_error(INCORRECT_USAGE, group,
+ "The group was not found.");
+ }
+ else if (uoptr == 0) {
+ report_error(INCORRECT_USAGE, user,
+ "The user was not found.");
+ }
+ else {
+ rv = nsadbAddUserToGroup(NULL, padb, goptr, uoptr);
+ }
+
+ nsadbClose(padb, 0);
+ }
+ return rv;
+}
+
+/*
+ * addgrouptogroup - function to add a group to a group
+ * Return: Returns 0 if it works, something else if it fails.
+ */
+NSAPI_PUBLIC int addgrouptogroup(char *db_path, char *memgroup, char *group) {
+ int rv;
+ GroupObj_t *goptr;
+ GroupObj_t *mem_goptr;
+ void *padb;
+
+ if (!strcmp(memgroup, group)) {
+ report_error(INCORRECT_USAGE, group,
+ "You can't add a group to itself.");
+ }
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, "Failed To Open Database",
+ "An error occurred while trying to add "
+ "group to a group.");
+ } else {
+ /* See if the groups exist. */
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ rv = nsadbFindByName(NULL,
+ padb, memgroup, AIF_GROUP, (void **)&mem_goptr);
+ if (goptr == 0) {
+ report_error(INCORRECT_USAGE, group,
+ "The target group was not found.");
+ }
+ else if (mem_goptr == 0) {
+ report_error(INCORRECT_USAGE, memgroup,
+ "The group to add was not found.");
+ }
+ else {
+ rv = nsadbAddGroupToGroup(NULL, padb, goptr, mem_goptr);
+ }
+
+ nsadbClose(padb, 0);
+ }
+ return rv;
+}
+
+/*
+ * remuserfromgroup - function to remove a user from a group
+ * Return: Returns 0 if it works, something else if it fails.
+ */
+NSAPI_PUBLIC int remuserfromgroup(char *db_path, char *user, char *group) {
+ int rv;
+ UserObj_t *uoptr;
+ GroupObj_t *goptr;
+ void *padb;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, "Failed To Open Database",
+ "An error occurred while trying to add "
+ "user to a group.");
+ } else {
+ /* See if the user and group exist. */
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ if (goptr == 0) {
+ report_error(SYSTEM_ERROR, group,
+ "The group was not found.");
+ }
+ else if (uoptr == 0) {
+ report_error(SYSTEM_ERROR, user,
+ "The user was not found.");
+ }
+ else {
+ rv = nsadbRemUserFromGroup(NULL, padb, goptr, uoptr);
+ if (rv)
+ report_error(SYSTEM_ERROR, "Error taking out user",
+ "An error occured trying to take "
+ "the user out of the group.");
+ }
+
+ nsadbClose(padb, 0);
+ }
+ return rv;
+}
+
+/*
+ * remgroupfromgroup - function to remove a group to a group
+ * Return: Returns 0 if it works, something else if it fails.
+ */
+NSAPI_PUBLIC int remgroupfromgroup(char *db_path, char *memgroup, char *group) {
+ int rv;
+ GroupObj_t *goptr;
+ GroupObj_t *mem_goptr;
+ void *padb;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, "Failed To Open Database",
+ "An error occurred while trying to remove "
+ "a group from a group.");
+ } else {
+ /* See if the groups exist. */
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ rv = nsadbFindByName(NULL,
+ padb, memgroup, AIF_GROUP, (void **)&mem_goptr);
+ if (goptr == 0) {
+ report_error(SYSTEM_ERROR, group,
+ "The target group was not found.");
+ }
+ else if (mem_goptr == 0) {
+ report_error(SYSTEM_ERROR, memgroup,
+ "The group to remove was not found.");
+ }
+ else {
+ rv = nsadbRemGroupFromGroup(NULL, padb, goptr, mem_goptr);
+ }
+
+ nsadbClose(padb, 0);
+ }
+ return rv;
+}
+
+/*
+ * setpw - function to set the password for the specified user.
+ * Return: Returns 0 if it works, something else if it fails.
+ */
+NSAPI_PUBLIC int setpw(char *db_path, char *user, char *pwd) {
+ int rv;
+ UserObj_t *uoptr = 0;
+ void *padb;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, "Failed To Open Database",
+ "An error occurred while trying to add "
+ "the password to the database.");
+ } else {
+ /* See if the user already exists, if so, update it. */
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ if (uoptr != 0) {
+ uoptr->uo_pwd = (NTS_t)STRDUP(pw_enc(pwd));
+ } else {
+ /* User doesn't exist, so we've failed. */
+ report_error(SYSTEM_ERROR, user,
+ "Unable to change this user's password, "
+ "user was not found in the database.");
+ rv = 1;
+ }
+
+ if (uoptr) {
+ rv = nsadbModifyUser(NULL, padb, uoptr);
+ if (rv < 0)
+ report_error(SYSTEM_ERROR, user,
+ "A database error occurred while "
+ "trying to change the user password.");
+ }
+ nsadbClose(padb, 0);
+ }
+ return rv;
+}
+
+/*
+ * setdbpw - function to set the password on the special user
+ * who's password is used as the database password.
+ * If the password passed in is NULL, the user is
+ * removed or not created.
+ * If the password is not NULL, then the user will
+ * be created if needed, and it's password set to
+ * the one passed in.
+ *
+ * Return: Returns 0 if it works, something else if it fails.
+ */
+NSAPI_PUBLIC int setdbpw(char *db_path, char *pwd)
+{
+ int rv;
+ UserObj_t *uoptr = 0;
+ void *padb;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, "Failed To Open Database",
+ "An error occurred while trying to add "
+ "the password to the database.");
+ }
+ /*
+ * If NULL pwd, remove the user if it exists.
+ */
+ else if (pwd == NULL) {
+ rv = nsadbRemoveUser(NULL, padb, DBPW_USER);
+ nsadbClose(padb, 0);
+
+ /*
+ * If we get success(0) or a no such user error(NSAERRNAME)
+ * we're happy.
+ */
+ if (rv != 0 && rv != NSAERRNAME) {
+ report_error(SYSTEM_ERROR, "Remove Password Failed",
+ "An error occurred while trying to remove "
+ "the password for the database.");
+ }
+ } else {
+ /* See if the user already exists, if so, just update it. */
+ rv = nsadbFindByName(NULL, padb, DBPW_USER, AIF_USER, (void **)&uoptr);
+ if (uoptr == 0) {
+ /* User doesn't exist, so add it. */
+ uoptr = userCreate((NTS_t)DBPW_USER, (NTS_t)pw_enc(pwd), (NTS_t)DBPW_USER);
+ if (uoptr == 0) {
+ report_error(SYSTEM_ERROR, "Failed To Update Database",
+ "An error occurred while trying to add "
+ "the password to the database.");
+ rv = 1;
+ }
+ else {
+ rv = nsadbCreateUser(NULL, padb, uoptr);
+ }
+ } else {
+ uoptr->uo_pwd = (NTS_t)STRDUP(pw_enc(pwd));
+ rv = nsadbModifyUser(NULL, padb, uoptr);
+ }
+
+ nsadbClose(padb, 0);
+
+ if (uoptr) {
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, "Failed To Set Database Password",
+ "An error occurred while trying to save "
+ "the password in the database.");
+ rv = 1;
+ }
+ userFree(uoptr);
+ }
+ }
+ return rv;
+}
+
+/*
+ * checkdbpw - Return TRUE if the password is correct, or database
+ * doesn't have one, because the password user isn't there.
+ * Return FALSE if required password is not correct.
+ */
+NSAPI_PUBLIC int checkdbpw(char *db_path, char *pwd)
+{
+ int rv;
+ UserObj_t *uoptr = 0;
+ void *padb;
+ int fpwOK = 0;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv == 0) {
+ rv = nsadbFindByName(NULL, padb, DBPW_USER, AIF_USER, (void **)&uoptr);
+ if (uoptr == 0) {
+ fpwOK = 1; /* Password userid isn't there, so none required. */
+ } else {
+ if (pwd == NULL)
+ fpwOK = 0; /* PW user exists, no pw passed in, return false. */
+ else {
+ if (pw_cmp(pwd, (char *)uoptr->uo_pwd))
+ fpwOK = 0; /* passwords are different, so return false. */
+ else
+ fpwOK = 1; /* passwords are the same, so return true. */
+ }
+ userFree(uoptr);
+ }
+ nsadbClose(padb, 0);
+ }
+ return fpwOK;
+}
+
+/*
+ * Create a link to another CGI:
+ * val - value text on the link
+ * targ - name of the CGI to start
+ * arg - argument to pass to the CGI
+ */
+void output_cgi_link(char *val, char *trg, char *arg)
+{
+ char line[BIG_LINE];
+ sprintf(line, "%s?%s", trg, arg);
+ printf("<a href=index?options+acss+%s target='options'>%s</a>",
+ util_uri_escape(NULL, line), val);
+}
+
+/*
+ * groupEnumCB - callback function from libaccess group enumerator
+ */
+static int groupEnumCB (NSErr_t * errp,
+ void * padb, void *parg, GroupObj_t *goptr)
+{
+ if (goptr && goptr->go_name && strlen((char *)goptr->go_name))
+ ulsAddToList(parg, goptr->go_gid, (char *)goptr->go_name);
+
+ return 0; /* 0: continue enumeration */
+}
+
+/*
+ * userEnumCB - callback function from libaccess group enumerator
+ */
+static int userEnumCB (NSErr_t * errp,
+ void * padb, void *parg, UserObj_t *uoptr)
+{
+ if (uoptr && uoptr->uo_name && strlen((char *)uoptr->uo_name))
+ ulsAddToList(parg, uoptr->uo_uid, (char *)uoptr->uo_name);
+
+ return 0; /* 0: continue enumeration */
+}
+
+/*
+ * idfound - horribly inefficient scan through the idlist table
+ * returning true if the specified id is found, false
+ * otherwise.
+ */
+int idfound(int id, int *idlist, int count)
+{
+ int i;
+ for (i = 0; i < count; ++i) {
+ if (id == idlist[i])
+ return 1;
+ }
+ return 0;
+}
+
+void output_groups_user_is_in(char *db_path, char *user)
+{
+ int rv;
+ UserObj_t *uoptr = 0;
+ GroupObj_t *goptr = 0;
+ void *padb;
+ USI_t *gidlist;
+ int i;
+ int id;
+ char *group;
+ char *gname;
+ int groupCount;
+ char line[BIG_LINE];
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list group membership.");
+ } else {
+ /* See if the user exists. */
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ if (uoptr == 0) {
+ /* User doesn't exist, so we've failed. */
+ report_error(SYSTEM_ERROR, user,
+ "Unable to find user when trying to "
+ "list group membership.");
+ rv = 1;
+ } else {
+ groupCount = UILCOUNT(&uoptr->uo_groups);
+ if (groupCount > 0) {
+ void *DirectlyInList;
+ void *IndirectlyInList;
+ ulsAlloc(&DirectlyInList);
+ ulsAlloc(&IndirectlyInList);
+
+ gidlist = UILLIST(&uoptr->uo_groups);
+ for (i = 0; i < groupCount; ++i) {
+ rv = nsadbIdToName(NULL,
+ padb, gidlist[i], AIF_GROUP, &gname);
+ if (rv >= 0) {
+ rv = nsadbFindByName(NULL, padb, gname, AIF_GROUP,
+ (void **)&goptr);
+ }
+ if (goptr != 0) {
+ if (goptr->go_name && strlen((char *)goptr->go_name)) {
+ if (idfound(uoptr->uo_uid,
+ (int*)UILLIST(&goptr->go_users),
+ UILCOUNT(&goptr->go_users))) {
+ ulsAddToList(DirectlyInList, goptr->go_gid,
+ (char *)goptr->go_name);
+ }
+ else {
+ ulsAddToList(IndirectlyInList, goptr->go_gid,
+ (char *)goptr->go_name);
+ }
+ }
+ groupFree(goptr);
+ goptr = 0;
+ }
+ }
+ ulsSortName(DirectlyInList);
+ ulsGetCount(DirectlyInList, &groupCount);
+ for (i=0; i<groupCount; ++i) {
+ group = NULL;
+ ulsGetEntry(DirectlyInList, i, &id, &group);
+ if (group) {
+ printf("<tr><td>");
+ printf("Member of <b>%s</b></td><td>", group);
+ sprintf(line, "group=%s", group);
+ output_cgi_link("Edit Group", "grped", line);
+ printf("</td><td>");
+ sprintf(line, "remfromgrp_but=1&memuser=%s&group=%s",
+ user, group);
+ output_cgi_link("Remove from Group", "grped", line);
+ printf("</td>\n");
+ }
+ }
+ ulsSortName(IndirectlyInList);
+ ulsGetCount(IndirectlyInList, &groupCount);
+ for (i=0; i<groupCount; ++i) {
+ group = NULL;
+ ulsGetEntry(IndirectlyInList, i, &id, &group);
+ if (group) {
+ printf("<tr><td>");
+ printf("Indirect member of <b>%s</b></td><td>", group);
+ sprintf(line, "group=%s", group);
+ output_cgi_link("Edit Group", "grped", group);
+ printf("</td><td>");
+ sprintf(line, "addtogrp_but=1&memuser=%s&group=%s",
+ user, group);
+ output_cgi_link("Add to Group", "grped", line);
+ printf("</td>\n");
+ }
+ }
+ ulsFree(&DirectlyInList);
+ ulsFree(&IndirectlyInList);
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * output a table with the groups the user isn't a member of
+ */
+void output_nonmembership(char *db_path, char *user)
+{
+ int rv;
+ UserObj_t *uoptr = 0;
+ void *padb;
+ USI_t *gidlist;
+ int i;
+ int id;
+ char *group;
+ int groupCount;
+ char line[BIG_LINE];
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list group membership.");
+ } else {
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ if (uoptr == 0) {
+ report_error(SYSTEM_ERROR, user,
+ "Unable to find user when trying to "
+ "list group membership.");
+ rv = 1;
+ } else {
+ void *sortList;
+
+ ulsAlloc(&sortList);
+ rv = nsadbEnumerateGroups(NULL, padb,
+ (void *)sortList, groupEnumCB);
+
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &groupCount);
+
+ if (groupCount > 0) {
+ gidlist = UILLIST(&uoptr->uo_groups);
+ for (i=0; i<groupCount; ++i) {
+ group = NULL;
+ ulsGetEntry(sortList, i, &id, &group);
+ if (group && !idfound(id, (int*)gidlist, UILCOUNT(&uoptr->uo_groups))){
+ printf("<tr><td>");
+ printf("Not a member of <b>%s</b></td><td>", group);
+ sprintf(line, "group=%s", group);
+ output_cgi_link("Edit Group", "grped", line);
+ printf("</td><td>");
+ sprintf(line, "addtogrp_but=1&memuser=%s&group=%s",
+ user, group);
+ output_cgi_link("Add to Group", "grped", line);
+ printf("</td>\n");
+ }
+ }
+ }
+ ulsFree(&sortList);
+ userFree(uoptr);
+ }
+ }
+ return;
+}
+
+/*
+ * output_group_membership - output a table showing which
+ * groups a user is in.
+ */
+void output_group_membership(char *db_path, char *user)
+{
+ printf("<table border=1><caption align=left>\n");
+ printf("<b>%s group membership:</b>", user);
+ printf("</caption>\n");
+ output_groups_user_is_in(db_path, user);
+ output_nonmembership(db_path, user);
+ printf("</table>\n");
+}
+
+void output_grpgroup_membership(char *db_path, char *group, char *filter)
+{
+ int rv;
+ GroupObj_t *goptr = 0;
+ void *padb;
+ USI_t *gidlist;
+ int i;
+ int id;
+ char *gname;
+ char *memgroup;
+ int groupCount;
+ char line[BIG_LINE];
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list group membership.");
+ } else {
+ /* See if the group exists. */
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ if (goptr == 0) {
+ /* Group doesn't exist, so we've failed. */
+ report_error(SYSTEM_ERROR, group,
+ "Unable to find group when trying to "
+ "list group membership.");
+ rv = 1;
+ } else {
+ groupCount = UILCOUNT(&goptr->go_groups);
+ if (groupCount > 0) {
+ void *sortList;
+ ulsAlloc(&sortList);
+
+ printf("<table border=1><caption align=left>\n");
+ printf("<b>%s has these group members:</b>", group);
+ printf("</caption>\n");
+ gidlist = UILLIST(&goptr->go_groups);
+ for (i = 0; i < groupCount; ++i) {
+ rv = nsadbIdToName(NULL,
+ padb, gidlist[i], AIF_GROUP, &gname);
+ if ((rv >= 0) && (gname != 0) && (strlen(gname) != 0)) {
+ ulsAddToList(sortList, gidlist[i], gname);
+ }
+ }
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &groupCount);
+ for (i=0; i<groupCount; ++i) {
+ memgroup = NULL;
+ ulsGetEntry(sortList, i, &id, &memgroup);
+ if (memgroup && passfilter(memgroup, filter)) {
+ printf("<tr><td>");
+ printf("<b>%s</b></td><td>", memgroup);
+ sprintf(line, "group=%s", memgroup);
+ output_cgi_link("Edit Group", "grped", line);
+ printf("</td><td>");
+ sprintf(line, "remfromgrp_but=1&memgroup=%s&group=%s",
+ memgroup, group);
+ output_cgi_link("Remove from Group", "grped", line);
+ printf("</td>\n");
+ }
+ }
+ printf("</table>\n");
+ ulsFree(&sortList);
+ } else {
+ printf("<b>This group has no group members.</b>");
+ }
+ groupFree(goptr);
+ }
+ nsadbClose(padb, 0);
+ }
+ return;
+}
+
+/*
+ * Output a table showing the user members of a group.
+ */
+NSAPI_PUBLIC void output_user_membership(char *db_path, char *group, char *filter)
+{
+ int rv;
+ GroupObj_t *goptr = 0;
+ void *padb;
+ USI_t *uidlist;
+ char *user;
+ int i;
+ int id;
+ char *memuser;
+ int userCount;
+ char line[BIG_LINE];
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list user membership.");
+ } else {
+ /* See if the group exists. */
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ if (goptr == 0) {
+ /* Group doesn't exist, so we've failed. */
+ nsadbClose(padb, 0);
+ report_error(SYSTEM_ERROR, group,
+ "Unable to find group when trying to "
+ "list user membership.");
+ rv = 1;
+ } else {
+ userCount = UILCOUNT(&goptr->go_users);
+ if (userCount > 0) {
+ void *sortList;
+ ulsAlloc(&sortList);
+
+ printf("<table border=1><caption align=left>\n");
+ printf("<b>%s has these user members:</b>", group);
+ printf("</caption>\n");
+ uidlist = UILLIST(&goptr->go_users);
+ for (i = 0; i < userCount; ++i) {
+ rv = nsadbIdToName(NULL,
+ padb, uidlist[i], AIF_USER, &user);
+ if ((rv >= 0) && (user != 0) && (strlen(user) != 0)) {
+ ulsAddToList(sortList, uidlist[i], user);
+ }
+ }
+ nsadbClose(padb, 0);
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &userCount);
+ for (i=0; i<userCount; ++i) {
+ memuser = NULL;
+ ulsGetEntry(sortList, i, &id, &memuser);
+ if (memuser && passfilter(memuser, filter)) {
+ printf("<tr><td>");
+ printf("<b>%s</b></td><td>", memuser);
+ sprintf(line, "user=%s", memuser);
+ output_cgi_link("Edit User", "usred", line);
+ printf("</td><td>");
+ sprintf(line, "remfromgrp_but=1&memuser=%s&group=%s",
+ memuser, group);
+ output_cgi_link("Remove from Group", "grped", line);
+ printf("</td>\n");
+ }
+ }
+ printf("</table>\n");
+ ulsFree(&sortList);
+ } else {
+ nsadbClose(padb, 0);
+ printf("<b>This group has no user members.</b>");
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * Output a group showing all users.
+ */
+NSAPI_PUBLIC int output_users_list(char *db_path, char *filter)
+{
+ int rv;
+ void *padb;
+ int i;
+ int id;
+ char *user;
+ int userCount;
+ char line[BIG_LINE];
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0)
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list users.");
+ else {
+ void *sortList;
+
+ ulsAlloc(&sortList);
+ rv = nsadbEnumerateUsers(NULL, padb, (void *)sortList, userEnumCB);
+ nsadbClose(padb, 0);
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &userCount);
+
+ if (userCount > 0) {
+
+ printf("<table border=1><caption align=left>\n");
+ printf("<b>User List:</b>");
+ printf("</caption>\n");
+
+ for (i=0; i<userCount; ++i) {
+ user = NULL;
+ ulsGetEntry(sortList, i, &id, &user);
+ if (user && passfilter(user, filter)) {
+ printf("<tr><td>");
+ printf("<b>%s</b></td><td>", user);
+ sprintf(line, "user=%s", user);
+ output_cgi_link("Edit User", "usred", line);
+ printf("</td><td>\n");
+ output_cgi_link("Remove User", "usrrem", line);
+ printf("</td>\n");
+ }
+ }
+ printf("</table>\n");
+ } else {
+ printf("<b>There are no users in the database.</b>");
+ }
+ ulsFree(&sortList);
+ }
+ return rv;
+}
+
+/*
+ * Output a table showing all groups.
+ */
+NSAPI_PUBLIC int output_groups_list(char *db_path, char *filter)
+{
+ int rv;
+ void *padb;
+ int i;
+ int id;
+ char *group;
+ int groupCount;
+ char line[BIG_LINE];
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0)
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list groups.");
+ else {
+ void *sortList;
+
+ ulsAlloc(&sortList);
+ rv = nsadbEnumerateGroups(NULL, padb, (void *)sortList, groupEnumCB);
+ nsadbClose(padb, 0);
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &groupCount);
+
+ if (groupCount > 0) {
+
+ printf("<table border=1><caption align=left>\n");
+ printf("<b>Group List:</b>");
+ printf("</caption>\n");
+
+ for (i=0; i<groupCount; ++i) {
+ group = NULL;
+ ulsGetEntry(sortList, i, &id, &group);
+ if ((group) && (passfilter(group, filter))) {
+ printf("<tr><td>");
+ printf("<b>%s</b></td><td>", group);
+ sprintf(line, "group=%s", group);
+ output_cgi_link("Edit Group", "grped", line);
+ printf("</td><td>");
+ output_cgi_link("Remove Group", "grprem", line);
+ printf("</td>\n");
+ }
+ }
+ printf("</table>\n");
+ } else {
+ printf("<b>There are no groups in the database.</b>");
+ }
+ ulsFree(&sortList);
+ }
+ return rv;
+}
+
+/* Helper function: Return a uls list of all the groups a user is in. MLM */
+void *_list_user_groups(void *padb, char *user, int group_users)
+{
+ int rv;
+ register int i;
+ UserObj_t *uoptr = 0;
+ GroupObj_t *ugoptr = 0;
+ GroupObj_t *goptr = 0;
+ void *userGroupList = NULL;
+ int userGroupCount= 0;
+ USI_t *gidlist;
+ char *ugname = NULL;
+
+ if(!group_users) {
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ } else {
+ rv = nsadbFindByName(NULL, padb, user, AIF_GROUP, (void **)&ugoptr);
+ }
+ if ((uoptr == 0) && (ugoptr == 0)) {
+ /* User doesn't exist, so we've failed. */
+ return NULL;
+ } else {
+ if(uoptr) {
+ userGroupCount = UILCOUNT(&uoptr->uo_groups);
+ } else {
+ userGroupCount = UILCOUNT(&ugoptr->go_groups);
+ }
+ if (userGroupCount > 0) {
+ ulsAlloc(&userGroupList);
+ if(uoptr) {
+ gidlist = UILLIST(&uoptr->uo_groups);
+ } else {
+ gidlist = UILLIST(&ugoptr->go_groups);
+ }
+
+ for (i = 0; i < userGroupCount; ++i) {
+ rv = nsadbIdToName(NULL, padb,
+ gidlist[i], AIF_GROUP, &ugname);
+
+ if (rv >= 0) {
+ rv = nsadbFindByName(NULL, padb, ugname, AIF_GROUP,
+ (void **)&goptr);
+ }
+ if (goptr != 0) {
+ if (goptr->go_name && strlen((char *)goptr->go_name)) {
+ if(uoptr) {
+ if (idfound(uoptr->uo_uid,
+ (int*)UILLIST(&goptr->go_users),
+ UILCOUNT(&goptr->go_users))) {
+ ulsAddToList(userGroupList, goptr->go_gid,
+ (char *)goptr->go_name);
+ }
+ } else {
+ ulsAddToList(userGroupList, goptr->go_gid,
+ (char *)goptr->go_name);
+ }
+ }
+ groupFree(goptr);
+ goptr = 0;
+ }
+ }
+ }
+ }
+ return userGroupList;
+}
+
+/* Output a selector box, with name "name", and make it a multiple
+ * selector box if multiple=1. */
+/* If user is non-null, then if it's a multiple selector, correctly highlight
+ * the groups the user is in.
+ * If group_user is 1, then the variable "user" refers to a *group* as
+ * a member, rather than a user.
+ * Highlight the item "highlight" regardless of membership (as long as
+ * it's non-NULL.) MLM */
+NSAPI_PUBLIC void output_group_selector(char *db_path, int group_user,
+ char *user,
+ char *highlight, char *except,
+ char *name, int none, int multiple)
+{
+ int rv;
+ void *padb;
+ int i, j, isselected;
+ int id;
+ char *group;
+ int groupCount;
+ void *userGroupList = NULL;
+ int userGroupCount= 0;
+ char *ugname = NULL;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0)
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list groups.");
+ else {
+ void *sortList;
+
+ ulsAlloc(&sortList);
+ rv = nsadbEnumerateGroups(NULL, padb, (void *)sortList, groupEnumCB);
+
+ if((multiple) && (user)) {
+ userGroupList=_list_user_groups(padb, user, group_user);
+ if(userGroupList) {
+ ulsSortName(userGroupList);
+ ulsGetCount(userGroupList, &userGroupCount);
+ }
+ }
+ nsadbClose(padb, 0);
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &groupCount);
+
+ if (groupCount > 0) {
+ /* Make a pulldown if we can. If the size is bigger than the
+ * overflow value, make it a box to hack around the fact that
+ * the X Navigator can't scroll pulldown lists. */
+ if((multiple) || (groupCount > SELECT_OVERFLOW)) {
+ printf("<SELECT size=5 name=%s %s>",
+ name, multiple? "MULTIPLE" : "");
+ } else {
+ printf("<SELECT name=%s>", name);
+ }
+ if((!multiple) && (none)) {
+ printf("<OPTION value=NONE>NONE\n");
+ }
+
+ for (i=0; i<groupCount; ++i) {
+ group = NULL;
+ ugname = NULL;
+ isselected=0;
+ ulsGetEntry(sortList, i, &id, &group);
+ if (group) {
+ if((except) && (!strcmp(group, except)))
+ continue;
+ if((highlight) && (!strcmp(group, highlight)))
+ isselected=1;
+ if(userGroupList && !isselected) {
+ for(j=0; j < userGroupCount; j++) {
+ ulsGetEntry(userGroupList, j, &id, &ugname);
+#if 0
+ if(ugname[0] > group[0]) {
+ /* Both lists are sorted, therefore, if we've
+ * hit a letter that's after the group letter,
+ * it must not be here. */
+ /* What can I say, it's a pathetic attempt
+ * on my part to mask the fact that I know
+ * this is inefficient. */
+ break;
+ }
+#endif
+ if(!strcmp(ugname, group)) {
+ isselected=1;
+ break;
+ }
+ }
+ }
+ printf("<OPTION %s>%s\n",
+ isselected? "SELECTED" : "", group);
+ }
+ }
+ printf("</SELECT>");
+ } else {
+ printf("<b>(No groups have been created.)</b>");
+ }
+ ulsFree(&sortList);
+ if(userGroupList)
+ ulsFree(&userGroupList);
+ }
+}
+
+void *_list_group_users(void *padb, char *group, int group_users)
+{
+ int rv;
+ GroupObj_t *goptr = 0;
+ USI_t *uidlist;
+ char *user;
+ int i;
+ int userCount;
+ void *sortList=NULL;
+
+ /* See if the group exists. */
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ if (goptr == 0) {
+ /* Group doesn't exist, so we've failed. */
+ return NULL;
+ } else {
+ if(group_users)
+ userCount = UILCOUNT(&goptr->go_groups);
+ else
+ userCount = UILCOUNT(&goptr->go_users);
+
+ if (userCount > 0) {
+ ulsAlloc(&sortList);
+
+ if(group_users)
+ uidlist = UILLIST(&goptr->go_groups);
+ else
+ uidlist = UILLIST(&goptr->go_users);
+
+ for (i = 0; i < userCount; ++i) {
+ if(group_users)
+ rv = nsadbIdToName(NULL,padb, uidlist[i], AIF_GROUP, &user);
+ else
+ rv = nsadbIdToName(NULL, padb, uidlist[i], AIF_USER, &user);
+ if ((rv >= 0) && (user != 0) && (strlen(user) != 0)) {
+ ulsAddToList(sortList, uidlist[i], user);
+ }
+ }
+ }
+ }
+ return sortList;
+}
+
+/*
+ * Output a selector box of users. If group is non-null, highlight the
+ * users in that group. MLM
+ */
+NSAPI_PUBLIC void output_user_selector(char *db_path, char *group,
+ char *highlight, char *except,
+ char *name, int none, int multiple)
+{
+ int rv;
+ void *padb;
+ int i, j, isselected;
+ int id;
+ char *user;
+ int userCount;
+ void *groupUserList = NULL;
+ int groupUserCount= 0;
+ char *guname = NULL;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0)
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list groups.");
+ else {
+ void *sortList;
+
+ ulsAlloc(&sortList);
+ rv = nsadbEnumerateUsers(NULL, padb, (void *)sortList, userEnumCB);
+
+ if((multiple) && (group)) {
+ groupUserList=_list_group_users(padb, group, 0);
+ if(groupUserList) {
+ ulsSortName(groupUserList);
+ ulsGetCount(groupUserList, &groupUserCount);
+ }
+ }
+ nsadbClose(padb, 0);
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &userCount);
+
+ if (userCount > 0) {
+ /* Make a pulldown if we can. If the size is bigger than the
+ * overflow value, make it a box to hack around the fact that
+ * the X Navigator can't scroll pulldown lists. */
+ if((multiple) || (userCount > SELECT_OVERFLOW)) {
+ printf("<SELECT size=5 name=%s %s>",
+ name, multiple? "MULTIPLE" : "");
+ } else {
+ printf("<SELECT name=%s>", name);
+ }
+ if((!multiple) && (none)) {
+ printf("<OPTION value=NONE>NONE\n");
+ }
+
+ for (i=0; i<userCount; ++i) {
+ user = NULL;
+ guname = NULL;
+ isselected=0;
+ ulsGetEntry(sortList, i, &id, &user);
+ if (user) {
+ if((except) && (!strcmp(user, except)))
+ continue;
+ if((highlight) && (!strcmp(user, highlight)))
+ isselected=1;
+ if(groupUserList && !isselected) {
+ for(j=0; j < groupUserCount; j++) {
+ ulsGetEntry(groupUserList, j, &id, &guname);
+#if 0
+ if(guname[0] > user[0]) {
+ /* Both lists are sorted, therefore, if we've
+ * hit a letter that's after the group letter,
+ * it must not be here. */
+ /* What can I say, it's a pathetic attempt
+ * on my part to mask the fact that I know
+ * this is inefficient. */
+ break;
+ }
+#endif
+ if(!strcmp(guname, user)) {
+ isselected=1;
+ break;
+ }
+ }
+ }
+ printf("<OPTION %s>%s\n",
+ isselected? "SELECTED" : "", user);
+ }
+ }
+ printf("</SELECT>");
+ } else {
+ printf("<b>(No users have been created.)</b>");
+ }
+ ulsFree(&sortList);
+ if(groupUserList)
+ ulsFree(&groupUserList);
+ }
+}
+
+
+int _item_in_list(char *item, char **list)
+{
+ register int i;
+ if(!list) return -1;
+ for(i=0; list[i]; i++) {
+ if(!strcmp(list[i], item))
+ return i;
+ }
+ return -1;
+}
+
+/* Take a char ** null terminated list of group names, and change a user's
+ * memberships so those are the only groups he's in. MLM */
+NSAPI_PUBLIC void change_user_membership(char *db_path, char *user,
+ char **new_groups)
+{
+ void *sortList;
+ int rv;
+ void *padb;
+ UserObj_t *uoptr = NULL;
+ GroupObj_t *goptr = NULL;
+ int groupCount=0;
+ register int i;
+ int index;
+ int id;
+ char *group;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0)
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list groups.");
+
+ sortList=_list_user_groups(padb, user, 0);
+ if(sortList) {
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &groupCount);
+ }
+
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER, (void **)&uoptr);
+ if (uoptr == 0) {
+ report_error(INCORRECT_USAGE, user, "The user was not found.");
+ }
+
+ /* First check the groups he's already in. Remove any that no longer
+ * appear in the list. */
+ for(i=0; i<groupCount; ++i) {
+ ulsGetEntry(sortList, i, &id, &group);
+
+ if( (index=_item_in_list(group, new_groups)) == -1) {
+ goptr=0;
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ if (goptr == 0) {
+ report_error(INCORRECT_USAGE, group,
+ "The group was not found.");
+ }
+ rv = nsadbRemUserFromGroup(NULL, padb, goptr, uoptr);
+ } else {
+ /* This group is in the list, so mark it as taken care of. */
+ if(new_groups)
+ new_groups[index][0]='\0';
+ }
+ }
+ /* Add the user to any remaining groups. */
+ if(new_groups) {
+ for(i=0; new_groups[i]; i++) {
+ if(new_groups[i][0] == '\0')
+ continue;
+ goptr=0;
+ rv = nsadbFindByName(NULL, padb, new_groups[i],
+ AIF_GROUP, (void **)&goptr);
+ if (goptr == 0) {
+ report_error(INCORRECT_USAGE, group,"The group was not found.");
+ }
+ rv = nsadbAddUserToGroup(NULL, padb, goptr, uoptr);
+ }
+ }
+
+ nsadbClose(padb, 0);
+}
+
+/* Take a char ** null terminated list of user names, and change a group's
+ * memberships so those are the only users it has. MLM */
+/* Again, if group_users is 1, then the new_users are assumed to be groups. */
+NSAPI_PUBLIC void change_group_membership(char *db_path, char *group,
+ int group_users, char **new_users)
+{
+ void *sortList;
+ int rv;
+ void *padb;
+ UserObj_t *uoptr = NULL;
+ GroupObj_t *goptr = NULL;
+ GroupObj_t *ugoptr = NULL;
+ int userCount=0;
+ register int i;
+ int index;
+ int id;
+ char *user;
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0)
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list groups.");
+
+ sortList=_list_group_users(padb, group, group_users);
+ if(sortList) {
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &userCount);
+ }
+
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ if (goptr == 0) {
+ report_error(INCORRECT_USAGE, group, "The group was not found.");
+ }
+
+ /* First check the users already there. Remove any that no longer
+ * appear in the list. */
+ for(i=0; i<userCount; ++i) {
+ ulsGetEntry(sortList, i, &id, &user);
+ if( (index=_item_in_list(user, new_users)) == -1) {
+ if(group_users) {
+ ugoptr=0;
+ rv = nsadbFindByName(NULL, padb, user, AIF_GROUP,
+ (void **)&ugoptr);
+ if (ugoptr == 0) {
+ report_error(INCORRECT_USAGE, user,
+ "The group was not found.");
+ }
+ rv = nsadbRemGroupFromGroup(NULL, padb, goptr, ugoptr);
+ } else {
+ uoptr=0;
+ rv = nsadbFindByName(NULL, padb, user, AIF_USER,
+ (void **)&uoptr);
+ if (uoptr == 0) {
+ report_error(INCORRECT_USAGE, user,
+ "The user was not found.");
+ }
+ rv = nsadbRemUserFromGroup(NULL, padb, goptr, uoptr);
+ }
+ } else {
+ /* This user is in the list, so mark it as taken care of. */
+ if(new_users)
+ new_users[index][0]='\0';
+ }
+ }
+ /* Add any remaining users. */
+ if(new_users) {
+ for(i=0; new_users[i]; i++) {
+ if(new_users[i][0] == '\0')
+ continue;
+ if(group_users) {
+ ugoptr=0;
+ rv = nsadbFindByName(NULL, padb, new_users[i],
+ AIF_GROUP, (void **)&ugoptr);
+ if (ugoptr == 0) {
+ report_error(INCORRECT_USAGE, new_users[i],
+ "The group was not found.");
+ }
+ rv = nsadbAddGroupToGroup(NULL, padb, goptr, ugoptr);
+ if(rv) report_error(SYSTEM_ERROR, new_users[i],
+ "Unable to add group to group");
+ } else {
+ uoptr=0;
+ rv = nsadbFindByName(NULL, padb, new_users[i],
+ AIF_USER, (void **)&uoptr);
+ if (uoptr == 0) {
+ report_error(INCORRECT_USAGE, new_users[i],
+ "The user was not found.");
+ }
+ rv = nsadbAddUserToGroup(NULL, padb, goptr, uoptr);
+ if(rv) report_error(SYSTEM_ERROR, new_users[i],
+ "Unable to add user to group");
+ }
+ }
+ }
+
+ nsadbClose(padb, 0);
+}
+
+/*
+ * output a table with the groups that aren't members of the group
+ */
+NSAPI_PUBLIC void output_nongrpgroup_membership(char *db_path, char *group, char *filter)
+{
+ int rv;
+ GroupObj_t *goptr = 0;
+ void *padb;
+ USI_t *gidlist;
+ int i;
+ int id;
+ char *memgroup;
+ int groupCount;
+ char line[BIG_LINE];
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list group membership.");
+ } else {
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ if (goptr == 0) {
+ report_error(SYSTEM_ERROR, group,
+ "Unable to find group when trying to "
+ "list group membership.");
+ rv = 1;
+ nsadbClose(padb, 0);
+ } else {
+ void *sortList;
+
+ printf("<table border=1><caption align=left>\n");
+ printf("<b>These groups are not members of %s:</b>", group);
+ printf("</caption>\n");
+
+ ulsAlloc(&sortList);
+ rv = nsadbEnumerateGroups(NULL,
+ padb, (void *)sortList, groupEnumCB);
+ nsadbClose(padb, 0);
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &groupCount);
+
+ if (groupCount > 0) {
+ gidlist = UILLIST(&goptr->go_groups);
+ for (i=0; i<groupCount; ++i) {
+ memgroup = NULL;
+ ulsGetEntry(sortList, i, &id, &memgroup);
+ if ( memgroup &&
+ strcmp(memgroup, group) &&
+ !idfound(id, (int*)gidlist, UILCOUNT(&goptr->go_groups)) &&
+ passfilter(memgroup, filter)) {
+ printf("<tr>");
+ printf("<td><b>%s</b></td><td>", memgroup);
+ sprintf(line, "group=%s", memgroup);
+ output_cgi_link("Edit Group", "grped", line);
+ printf("</td><td>");
+ sprintf(line, "addtogrp_but=1&memgroup=%s&group=%s",
+ memgroup, group);
+ output_cgi_link("Add to Group", "grped", line);
+ printf("</td>\n");
+ }
+ }
+ printf("</table>\n");
+ }
+ ulsFree(&sortList);
+ groupFree(goptr);
+ }
+ }
+ return;
+}
+
+/*
+ * output a table with the users that aren't members of the group
+ */
+NSAPI_PUBLIC void output_nonuser_membership(char *db_path, char *group, char *filter)
+{
+ int rv;
+ GroupObj_t *goptr = 0;
+ void *padb;
+ USI_t *gidlist;
+ int i;
+ int id;
+ char *memuser;
+ int userCount;
+ char line[BIG_LINE];
+
+ rv = nsadbOpen(NULL, db_path, 0, &padb);
+ if (rv < 0) {
+ report_error(SYSTEM_ERROR, db_path,
+ "Failed to open database while trying "
+ "to list group membership.");
+ } else {
+ rv = nsadbFindByName(NULL, padb, group, AIF_GROUP, (void **)&goptr);
+ if (goptr == 0) {
+ nsadbClose(padb, 0);
+ report_error(SYSTEM_ERROR, group,
+ "Unable to find group when trying to "
+ "list user membership.");
+ rv = 1;
+ } else {
+ void *sortList;
+
+ printf("<table border=1><caption align=left>\n");
+ printf("<b>These users are not members of %s:</b>", group);
+ printf("</caption>\n");
+
+ ulsAlloc(&sortList);
+ rv = nsadbEnumerateUsers(NULL, padb, (void *)sortList, userEnumCB);
+ nsadbClose(padb, 0);
+
+ ulsSortName(sortList);
+ ulsGetCount(sortList, &userCount);
+
+ if (userCount > 0) {
+ gidlist = UILLIST(&goptr->go_users);
+ for (i=0; i<userCount; ++i) {
+ memuser = NULL;
+ ulsGetEntry(sortList, i, &id, &memuser);
+ if ( memuser &&
+ !idfound(id, (int*)gidlist, UILCOUNT(&goptr->go_users)) &&
+ passfilter(memuser, filter)) {
+ printf("<tr>");
+ printf("<td><b>%s</b></td><td>", memuser);
+ sprintf(line, "memuser=%s", memuser);
+ output_cgi_link("Edit User", "usred", line);
+ printf("</td><td>");
+ sprintf(line, "addtogrp_but=1&memuser=%s&group=%s",
+ memuser, group);
+ output_cgi_link("Add to Group", "grped", line);
+ printf("</td>\n");
+ }
+ }
+ printf("</table>\n");
+ }
+ ulsFree(&sortList);
+ groupFree(goptr);
+ }
+ }
+ return;
+}
+
+NSAPI_PUBLIC char *get_acl_file()
+{
+ char line[BIG_LINE];
+ char *acl_file = get_mag_var("ACLFile");
+ if (!acl_file) {
+ sprintf(line, "%s%cgenerated.%s.acl",
+ get_httpacl_dir(), FILE_PATHSEP, get_srvname(0));
+ set_mag_var("ACLFile", line);
+ acl_file = STRDUP(line);
+ }
+ if(!file_exists(acl_file)) {
+ FILE *f;
+ if(! (f=fopen(acl_file, "w")) )
+ report_error(FILE_ERROR, acl_file, "Could not open file.");
+ fclose(f);
+ }
+ return acl_file;
+}
+
+NSAPI_PUBLIC char *get_workacl_file()
+{
+ char line[BIG_LINE];
+ char *workacl_file;
+ sprintf(line, "%s%cgenwork.%s.acl",
+ get_httpacl_dir(), FILE_PATHSEP, get_srvname(0));
+ workacl_file = STRDUP(line);
+
+ if(!file_exists(workacl_file)) {
+ FILE *f;
+ char *current=get_acl_file();
+ if(file_exists(current)) {
+ cp_file(current, workacl_file, 0644);
+ } else {
+ if(! (f=fopen(workacl_file, "w")) )
+ report_error(FILE_ERROR, workacl_file, "Could not open file.");
+ fclose(f);
+ }
+ }
+ return workacl_file;
+}
+
+/*
+ * get_acl_info - Open the specified ACL file. Return a context
+ * handle into it, the data it contains, and whether this is
+ * a default allow or default deny resource.
+ *
+ * Returns: 0 if it works
+ * AUTHDB_ACL_FAIL (-1) if it fails
+ * AUTHDB_ACL_ODD_ACL (-2) if the ACL doesn't appear to be one
+ * generated by the CGI.
+ */
+NSAPI_PUBLIC int get_acl_info(char *acl_file, char *acl_name, void **pacl,
+ char ***hosts, authInfo_t **authinfo,
+ char ***users, char ***userhosts,
+ int *fdefaultallow)
+{
+ int rv = 0;
+ char *acl_sig = NULL;
+ ACContext_t *acl_con = NULL;
+ ACL_t *acl;
+
+ if (hosts)
+ *hosts = NULL;
+ if (authinfo)
+ *authinfo = NULL;
+ if (users)
+ *users = NULL;
+ if (userhosts)
+ *userhosts = NULL;
+ if (fdefaultallow)
+ *fdefaultallow = 0;
+
+ if ((rv = accReadFile(NULL, acl_file, &acl_con)))
+ rv = AUTHDB_ACL_FAIL;
+ else if (!(rv = aclFindByName(acl_con, acl_name, NULL, 0, &acl)))
+ rv = AUTHDB_ACL_NOT_FOUND;
+ else {
+ /*
+ * If we get the ACL open, get it's signiture to see if
+ * it looks like one of ours. Each directive is identified
+ * by a single character in the signiture string. The ones
+ * we care about are:
+ * 'a' - default allow
+ * 'd' - default deny
+ * 'r' - default authenticate
+ *
+ * The ACL used for default allow access has these directives:
+ * default allow anyone at *; (required, shows up as an 'a')
+ * default deny anyone at (hosts); (optional, shows up as a 'd')
+ *
+ * The ACL used for default deny access has these directives:
+ * default deny anyone at *; (required, shows up as an 'd')
+ * default allow anyone at (hosts); (optional, shows up as a 'a')
+ * default authenticate... (optional, shows up as an 'r')
+ * default allow (users) at (hosts); (optional, shows up as a 'a')
+ *
+ * Valid signitures are:
+ * "a"
+ * "ad"
+ * "d"
+ * "da"
+ * "dra"
+ * "dara"
+ */
+
+ if (acl)
+ acl_sig = aclGetSignature(acl);
+
+ if (acl_sig) {
+ if (!strcmp(acl_sig, "a")) {
+ if (fdefaultallow)
+ *fdefaultallow = 1;
+ rv = 0;
+ }
+ else if (!strcmp(acl_sig, "ad")) {
+ if (fdefaultallow)
+ *fdefaultallow = 1;
+ if (hosts)
+ *hosts = aclGetHosts(acl, 2, 1);
+ rv = 0;
+ }
+ else if (!strcmp(acl_sig, "d")) {
+ if (fdefaultallow)
+ *fdefaultallow = 0;
+ rv = 0;
+ }
+ else if (!strcmp(acl_sig, "da")) {
+ if (fdefaultallow)
+ *fdefaultallow = 0;
+ if (hosts)
+ *hosts = aclGetHosts(acl, 2, 1);
+ rv = 0;
+ }
+ else if (!strcmp(acl_sig, "dra")) {
+ if (fdefaultallow)
+ *fdefaultallow = 0;
+ if (authinfo) {
+ char *p;
+ *authinfo = (authInfo_t *)MALLOC(sizeof(authInfo_t));
+ memset(*authinfo, 0, (sizeof(authInfo_t)));
+ if ((p = aclGetAuthMethod(acl, 2)))
+ (*authinfo)->type = strdup(p);
+ if ((p = aclGetDatabase(acl, 2)))
+ (*authinfo)->db_path = strdup(p);
+ if ((p = aclGetPrompt(acl, 2)))
+ (*authinfo)->prompt = strdup(p);
+ }
+ if (users)
+ *users = aclGetUsers(acl, 3, 1);
+ if (userhosts)
+ *userhosts = aclGetHosts(acl, 3, 1);
+ rv = 0;
+ }
+ else if (!strcmp(acl_sig, "dara")) {
+ if (fdefaultallow)
+ *fdefaultallow = 0;
+ if (hosts)
+ *hosts = aclGetHosts(acl, 2, 1);
+ if (authinfo) {
+ char *p;
+ *authinfo = (authInfo_t *)MALLOC(sizeof(authInfo_t));
+ memset(*authinfo, 0, (sizeof(authInfo_t)));
+ if ((p = aclGetAuthMethod(acl, 3)))
+ (*authinfo)->type = strdup(p);
+ if ((p = aclGetDatabase(acl, 3)))
+ (*authinfo)->db_path = strdup(p);
+ if ((p = aclGetPrompt(acl, 3)))
+ (*authinfo)->prompt = strdup(p);
+ }
+ if (users)
+ *users = aclGetUsers(acl, 4, 1);
+ if (userhosts)
+ *userhosts = aclGetHosts(acl, 4, 1);
+ rv = 0;
+ }
+ else
+ rv = AUTHDB_ACL_ODD_ACL;
+ }
+ if (pacl)
+ *pacl = (void *)acl_con;
+ }
+ return rv;
+}
+
+
+static void add_acl_rights(ACContext_t *acc)
+{
+ int rv;
+ char **p;
+ for (p = acl_read_rights; *p; ++p) {
+ rv = aclRightDef(NULL, acc, *p, NULL);
+ }
+ for (p = acl_write_rights; *p; ++p) {
+ rv = aclRightDef(NULL, acc, *p, NULL);
+ }
+}
+
+/*
+ * delete_acl_by_name - remove a specified acl.
+ *
+ * Return: 0 if it deletes an ACL. Otherwise something else.
+ *
+ */
+NSAPI_PUBLIC int delete_acl_by_name(char *acl_file, char *acl_name)
+{
+ int rv = 1;
+ ACContext_t *acl_con = NULL;
+ ACL_t *acl = NULL;
+
+ if (acl_file && acl_name)
+ {
+ rv = accReadFile(NULL, acl_file, &acl_con);
+
+ if (!rv) {
+ rv = aclFindByName(acl_con, acl_name, NULL, 0, &acl);
+ if (rv == 1 && acl) {
+ aclDelete(acl);
+ rv = accWriteFile(acl_con, acl_file, 0);
+ set_commit(0, 1);
+ }
+ }
+ }
+ return rv;
+}
+
+/*
+ * set_acl_info - Replaces the specified ACL with the information
+ * provided. The fdefaultallow is tells us whether
+ * to generate a default allow everyone type ACL, or
+ * a default deny everyone type ACL.
+ *
+ * If opening the ACL file fails with a file open
+ * type error, it is assumed to not exist, and a
+ * new one is created.
+ *
+ * Returns: 0 if it works
+ * AUTHDB_ACL_FAIL if it fails
+ */
+NSAPI_PUBLIC int set_acl_info(char *acl_file, char *acl_name, int prefix,
+ void **pacl, char **rights,
+ char **hosts, authInfo_t *authinfo,
+ char **users, char **userhosts,
+ int fdefaultallow)
+{
+ int rv = AUTHDB_ACL_FAIL;
+ ACContext_t *acl_con = NULL;
+ ACL_t *acl = NULL;
+ int amethod = AUTH_METHOD_BASIC;
+ char *db_path = NULL;
+ char *prompt = NULL;
+
+ /*
+ * Digest parms
+ */
+ if (authinfo) {
+ if (!strcmp(authinfo->type, "SSL"))
+ amethod = AUTH_METHOD_SSL;
+ else
+ amethod = AUTH_METHOD_BASIC;
+ db_path = authinfo->db_path;
+ prompt = authinfo->prompt;
+ }
+
+ if (prefix)
+ prefix = ACLF_NPREFIX;
+ else
+ prefix = 0;
+
+ /*
+ * Open the specified ACL file, destroy the existing ACL with
+ * the specified name if it exists, and then write the new
+ * stuff back out.
+ */
+ if (acl_file && acl_name)
+ {
+ (void)delete_acl_by_name(acl_file, acl_name);
+ rv = accReadFile(NULL, acl_file, &acl_con);
+
+ /*
+ * If the file isn't there, create an empty context.
+ */
+ if (rv == ACLERROPEN)
+ rv = accCreate(0, 0, &acl_con);
+
+ if (rv)
+ rv = AUTHDB_ACL_FAIL;
+ else {
+ (void)add_acl_rights(acl_con);
+
+ if (aclMakeNew(acl_con, "", acl_name,
+ rights, prefix, &acl)) {
+ rv = AUTHDB_ACL_FAIL;
+ }
+ else if (aclPutAllowDeny(
+ NULL, acl, 0, fdefaultallow, NULL, NULL)) {
+ rv = AUTHDB_ACL_FAIL;
+ }
+ else if (hosts &&
+ (rv = aclPutAllowDeny(
+ NULL, acl, 0, !fdefaultallow, NULL, hosts))) {
+
+ rv = AUTHDB_ACL_FAIL;
+ }
+ else if (users && authinfo &&
+ ((rv = aclPutAuth(NULL, acl, 0, amethod, db_path, prompt))||
+ (rv = aclPutAllowDeny(NULL, acl, 0, !fdefaultallow,
+ users, userhosts)))) {
+
+ rv = AUTHDB_ACL_FAIL;
+ }
+ else {
+ if (accWriteFile(acl_con, acl_file, 0)) {
+ rv = AUTHDB_ACL_FAIL;
+ }
+ else {
+ set_commit(0, 1);
+ rv = 0;
+ if (pacl)
+ *pacl = (void *)acl;
+ }
+ }
+ }
+ }
+ return rv;
+}
+
+/*
+ * get_acl_names - Passes back the names of the read and write
+ * ACLs for the current resource.
+ * The directive parm is usually "acl", but is
+ * also used to find stashed items under names
+ * like "acl-disabled".
+ * Returns 0 if no other ACLs are found, 1 if an ACL that
+ * doesn't match the type of name we generate.
+ */
+NSAPI_PUBLIC int get_acl_names(char **readaclname, char **writeaclname, char *directive)
+{
+ pblock **pbs;
+ char *aclname;
+ int fother_acls = 0;
+ char **config = get_adm_config();
+ char *curres = get_current_resource(config);
+ int rtype = get_current_restype(config);
+ int i;
+
+ *readaclname = NULL;
+ *writeaclname = NULL;
+
+ pbs = list_pblocks(rtype, curres, "PathCheck", CHECK_ACL_FN);
+
+ if (pbs) {
+ for (i=0; pbs[i]; ++i) {
+ aclname = pblock_findval(directive, pbs[i]);
+ if (is_readacl(aclname))
+ *readaclname = strdup(aclname);
+ else if (is_writeacl(aclname))
+ *writeaclname = strdup(aclname);
+ else
+ fother_acls = 1;
+ }
+ }
+ return fother_acls;
+}
+
+NSAPI_PUBLIC int is_readacl(char *name) {
+ if (name)
+ return strstr(name, ACLNAME_READ_COOKIE)?1:0;
+ else
+ return 0;
+}
+
+NSAPI_PUBLIC int is_writeacl(char *name) {
+ if (name)
+ return strstr(name, ACLNAME_WRITE_COOKIE)?1:0;
+ else
+ return 0;
+}
+
+NSAPI_PUBLIC int admin_is_ipaddr(char *p)
+{
+ int i;
+ int num_found = 0;
+
+ if (!p || !p[0])
+ return 0; /* NULL isn't an IP Address */
+ else {
+ for (i=0; p[i]; ++i) {
+ if (isalpha(p[i]))
+ return 0; /* If it has an alpha character, it's not IP addr */
+ else if (isdigit(p[i])) {
+ num_found = 1;
+ }
+ }
+ }
+ /*
+ * Well, hard to say what it is, but if there's at least a number
+ * in it, and the ip number checker can parse it, we'll call it
+ * an IP address;
+ */
+ if (num_found && get_ip_and_mask(p))
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * Get the hostnames and ipaddrs strings from the single hosts array
+ * of string pointers.
+ */
+NSAPI_PUBLIC void get_hostnames_and_ipaddrs(char **hosts, char **hostnames, char **ipaddrs)
+{
+ char *p;
+ int nbipaddrs = 0;
+ int nbhostnames = 0;
+ int i;
+ if (hosts && hostnames && ipaddrs) {
+ *hostnames = NULL;
+ *ipaddrs = NULL;
+ /*
+ * Make two passes, once to total the size needed for
+ * the hosts and ipaddrs string, then alloc them and
+ * strcat the strings in.
+ */
+ for(i=0, p=hosts[i]; p; p=hosts[++i]) {
+ if (admin_is_ipaddr(p))
+ nbipaddrs += strlen(p) + 2; /* Teminator and "," */
+ else
+ nbhostnames += strlen(p) + 2;
+ }
+
+ if (nbhostnames) {
+ *hostnames = (char *)MALLOC(nbhostnames + 1);
+ memset(*hostnames, 0, nbhostnames);
+ }
+ if (nbipaddrs) {
+ *ipaddrs = (char *)MALLOC(nbipaddrs + 1);
+ memset(*ipaddrs, 0, nbipaddrs);
+ }
+
+ /*
+ * We've got the space, now go look at each, strcat it
+ * into the correct string, prefixed with a "," for all
+ * but the first.
+ */
+ for(i=0, p=hosts[i]; p; p=hosts[++i]) {
+ if (admin_is_ipaddr(p)) {
+ if (strlen(*ipaddrs))
+ strcat(*ipaddrs, ",");
+ strcat(*ipaddrs, p);
+ }
+ else {
+ if (strlen(*hostnames))
+ strcat(*hostnames, ",");
+ strcat(*hostnames, p);
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * Get the usernames and groups strings from the single users array
+ * of string pointers.
+ */
+NSAPI_PUBLIC void get_users_and_groups(char **users, char **usernames, char **groups,
+ char *db_path)
+{
+ char *p;
+ int nbusernames = 0;
+ int nbgroups = 0;
+ int i;
+ int is_user = 0;
+ int is_group = 0;
+
+ if (users && usernames && groups) {
+ *usernames = NULL;
+ *groups = NULL;
+ /*
+ * Make two passes, once to total the size needed for
+ * the strings, then alloc them and strcat the strings in.
+ */
+ for(i=0, p=users[i]; p; p=users[++i]) {
+ is_user = 0;
+ is_group = 0;
+ groupOrUser(db_path, p, &is_user, &is_group);
+
+ /* Enclose user/group name in quotes if necessary */
+ p = aclSafeIdent(p);
+
+ if (is_user)
+ nbusernames += strlen(p) + 2; /* Teminator and "," */
+ else if (is_group)
+ nbgroups += strlen(p) + 2;
+ }
+
+ if (nbusernames) {
+ *usernames = (char *)MALLOC(nbusernames + 1);
+ memset(*usernames, 0, nbusernames);
+ }
+ if (nbgroups) {
+ *groups = (char *)MALLOC(nbgroups + 1);
+ memset(*groups, 0, nbgroups);
+ }
+
+ /*
+ * We've got the space, now go look at each, strcat it
+ * into the correct string, prefixed with a "," for all
+ * but the first.
+ */
+ for(i=0, p=users[i]; p; p=users[++i]) {
+ is_user = 0;
+ is_group = 0;
+ groupOrUser(db_path, p, &is_user, &is_group);
+
+ /* Enclose user/group name in quotes if necessary */
+ p = aclSafeIdent(p);
+
+ if (is_user) {
+ if (strlen(*usernames))
+ strcat(*usernames, ",");
+ strcat(*usernames, p);
+ }
+ else if (is_group) {
+ if (strlen(*groups))
+ strcat(*groups, ",");
+ strcat(*groups, p);
+ }
+ }
+ }
+ return;
+}
+
+/*
+ * Load from host and IP Addr strings into the array of
+ * pointers to strings.
+ */
+NSAPI_PUBLIC void load_host_array(char ***hosts, char *hostnames, char *ipaddrs)
+{
+ char *tok;
+ int nMax = 20;
+ int nCur = 0;
+ char **hostarr;
+ char *valid_ip;
+
+ if (hosts) {
+ hostarr = new_strlist(nMax);
+ hostarr[0] = NULL;
+ if (hostnames) {
+ for (tok = strtok(hostnames, ",");
+ tok;
+ tok = strtok(NULL, ","))
+ {
+ if (!(nCur < nMax)) {
+ nMax += 20;
+ hostarr = grow_strlist(hostarr, nMax);
+ }
+ hostarr[nCur] = strdup(tok);
+ hostarr[++nCur] = NULL;
+ }
+ }
+ if (ipaddrs) {
+ for (tok = strtok(ipaddrs, ",");
+ tok;
+ tok = strtok(NULL, ","))
+ {
+ if (!(nCur < nMax)) {
+ nMax += 20;
+ hostarr = grow_strlist(hostarr, nMax);
+ }
+ valid_ip = get_ip_and_mask(tok);
+ if (valid_ip) {
+ hostarr[nCur] = strdup(valid_ip);
+ hostarr[++nCur] = NULL;
+ }
+ }
+ }
+ *hosts = hostarr;
+ }
+
+ return;
+}
+
+void load_users_array(char ***users, char *usernames, char *groups)
+{
+ char *tok;
+ int nMax = 20;
+ int nCur = 0;
+ char **userarr;
+
+ if (users) {
+ userarr = new_strlist(nMax);
+ userarr[0] = NULL;
+ if (usernames) {
+ for (tok = strtok(usernames, ",");
+ tok;
+ tok = strtok(NULL, ","))
+ {
+ if (!(nCur < nMax)) {
+ nMax += 20;
+ userarr = grow_strlist(userarr, nMax);
+ }
+ userarr[nCur] = strdup(tok);
+ userarr[++nCur] = NULL;
+ }
+ }
+ if (groups) {
+ for (tok = strtok(groups, ",");
+ tok;
+ tok = strtok(NULL, ","))
+ {
+ if (!(nCur < nMax)) {
+ nMax += 20;
+ userarr = grow_strlist(userarr, nMax);
+ }
+ userarr[nCur] = strdup(tok);
+ userarr[++nCur] = NULL;
+ }
+ }
+ *users = userarr;
+ }
+
+ return;
+}
+
+/* Removes enclosing double quotes from a string (in place) */
+NSAPI_PUBLIC char * str_unquote(char * str)
+{
+ if (str) {
+ if (str[0] == '"') {
+ int len = strlen(str);
+
+ if (str[len-1] == '"') {
+ str[len-1] = 0;
+ ++str;
+ }
+ }
+ }
+
+ return str;
+}
diff --git a/lib/libadmin/error.c b/lib/libadmin/error.c
new file mode 100644
index 00000000..a4f87842
--- /dev/null
+++ b/lib/libadmin/error.c
@@ -0,0 +1,109 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * error.c - Handle error recovery
+ *
+ * All blame to Mike McCool
+ */
+
+#include "libadmin/libadmin.h"
+#if 0
+#include "cgiutils/cgi-util.h"
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef XP_WIN32
+#include <windows.h>
+#include "base/nterr.h"
+#endif
+
+#define ERROR_HTML "error.html"
+
+/* Be sure to edit libadmin.h and add new #define types for these headers. */
+char *error_headers[MAX_ERROR] =
+ {"File System Error",
+ "Memory Error",
+ "System Error",
+ "Incorrect Usage",
+ "Form Element Missing",
+ "Registry Database Error",
+ "Network Error",
+ "Unexpected Failure",
+ "Warning"};
+
+#ifdef XP_UNIX
+#define get_error() errno
+#define verbose_error() system_errmsg()
+#else /* XP_WIN32 */
+int get_error()
+{
+ int error = GetLastError();
+ return(error ? error: WSAGetLastError());
+}
+char *verbose_error()
+{
+ /* Initialize error hash tables */
+ HashNtErrors();
+ return alert_word_wrap(system_errmsg(), WORD_WRAP_WIDTH, "\\n");
+}
+#endif /* XP_WIN32 */
+
+void _report_error(int type, char *info, char *details, int shouldexit)
+{
+ /* Be sure headers are terminated. */
+ fputs("\n", stdout);
+
+ fprintf(stdout, "<SCRIPT LANGUAGE=\"%s\">", MOCHA_NAME);
+ output_alert(type, info, details, 0);
+ if(shouldexit) {
+ fprintf(stdout, "if(history.length>1) history.back();");
+ }
+ fprintf(stdout, "</SCRIPT>\n");
+
+ if(shouldexit) {
+ WSACleanup();
+ exit(0);
+ }
+}
+
+/*
+ * Format and output a call to the JavaScript alert() function.
+ * The caller must ensure a JavaScript context.
+ */
+NSAPI_PUBLIC void output_alert(int type, char *info, char *details, int wait)
+{
+ char *wrapped=NULL;
+ int err;
+
+ if(type >= MAX_ERROR)
+ type=DEFAULT_ERROR;
+
+ wrapped=alert_word_wrap(details, WORD_WRAP_WIDTH, "\\n");
+
+ if(!info) info="";
+ fprintf(stdout, (wait) ? "confirm(\"" : "alert(\"");
+ fprintf(stdout, "%s:%s\\n%s", error_headers[type], info, wrapped);
+ if(type==FILE_ERROR || type==SYSTEM_ERROR) {
+ err = get_error();
+ if(err != 0)
+ fprintf(stdout,
+ "\\n\\nThe system returned error number %d, "
+ "which is %s.", err, verbose_error());
+ }
+ fprintf(stdout, "\");");
+}
+
+NSAPI_PUBLIC void report_error(int type, char *info, char *details)
+{
+ _report_error(type, info, details, 1);
+}
+
+NSAPI_PUBLIC void report_warning(int type, char *info, char *details)
+{
+ _report_error(type, info, details, 0);
+}
+
diff --git a/lib/libadmin/strlist.c b/lib/libadmin/strlist.c
new file mode 100644
index 00000000..46a0c600
--- /dev/null
+++ b/lib/libadmin/strlist.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 **/
+/*
+ * strlist.c: Managing a handle to a list of strings
+ *
+ * All blame to Mike McCool
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "netsite.h"
+#include <libadmin/libadmin.h>
+
+NSAPI_PUBLIC char **new_strlist(int size)
+{
+ char **new_list;
+ register int x;
+
+ new_list = (char **) MALLOC((size+1)*(sizeof(char *)));
+/* <= so we get the one right after the given size as well */
+ for(x=0; x<= size; x++)
+ new_list[x] = NULL;
+
+ return new_list;
+}
+
+NSAPI_PUBLIC char **grow_strlist(char **strlist, int newsize)
+{
+ char **ans;
+
+ ans = (char **) REALLOC(strlist, (newsize+1)*sizeof(char *));
+
+ return ans;
+}
+
+NSAPI_PUBLIC void free_strlist(char **strlist)
+{
+ int x;
+
+ for(x=0; (strlist[x]); x++) free(strlist[x]);
+ free(strlist);
+}
diff --git a/lib/libadmin/template.c b/lib/libadmin/template.c
new file mode 100644
index 00000000..a689d3b5
--- /dev/null
+++ b/lib/libadmin/template.c
@@ -0,0 +1,820 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * template.c: The actual HTML templates in a static variable
+ *
+ * All blame to Mike McCool
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "template.h"
+#include "libadmin/libadmin.h"
+#include "libadmin/dbtlibadmin.h"
+#include "base/util.h"
+
+/* If you add something to this structure, don't forget to document it
+ * in templates.h, and increase MAXTEMPLATE!
+ *
+ * Also, save yourself a lot of grief and put a space after the name.
+ */
+
+static struct template_s templates[MAXTEMPLATE] = {
+ {"IF ", "FUNC conditional"},
+ {"ELSE ", "FUNC conditional"},
+ {"ENDIF ", "FUNC conditional"},
+ {"TITLE ", "<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n"
+ "<BODY bgcolor=\"#C0C0C0\" link=\"#0000EE\" "
+ "vlink=\"#551A8B\" alink=\"#FF0000\" %s>\n"},
+ {"PAGEHEADER ", "FUNC pageheader"},
+ {"DOCSWITCHER ", ""},
+ {"COPYRIGHT ", ""},
+ {"RESOURCEPICKER ", "FUNC respicker"},
+ {"BOOKTRACK ", "FUNC booktrack"},
+ {"BEGININFO ", "<table border=2 width=100%% cellpadding=2>\n"
+ "<tr><td align=center colspan=2>"
+ "<b><FONT size=+1>%s</FONT></b></td></tr>"
+#if 0
+ "<tr><td>"
+ "<IMG src=\"../icons/b-open.gif\" hspace=8 alt=\"*\""
+ "height=26 width=55></td>"
+ "<td>\n"},
+#endif
+ "<td colspan=2>\n"},
+ {"ADDINFO ", "</td></tr><tr><td colspan=2>"},
+ {"ENDINFO ", "</td></tr></table>\n<hr width=10%%>\n"},
+ {"SUBMIT ", "FUNC submit\n"},
+ {"DOCUMENTROOT ", "FUNC docroot"},
+ {"BEGINELEM ", "<pre>"},
+/* {"ELEM ", "<hr width=100%%><b>%s</b>"}, */
+ {"ELEM ", "\n<b>%s</b>"},
+/* {"ENDELEM ", "<hr width=100%%></pre>\n"}, */
+ {"ENDELEM ", "</pre>\n"},
+ {"ELEMADD ", "<b>%s</b>"},
+/* {"ELEMDIV ", "<hr width=100%%>"}, */
+ {"ELEMDIV ", "\n"},
+ {"REFERER ", "FUNC link_referer"},
+ {"INDEX ", "<a href=\"index\">%s</a>\n"},
+ {"SERVERROOT ", "FUNC serverroot"},
+ {"RESTART ", "<a href=\"pcontrol\">%s</a>\n"},
+ {"ACCESS ", "FUNC makeurl"},
+ {"COMMIT ", "<a href=\"commit?commit\">%s</a>\n"},
+ {"BACKOUT ", "<center>If you don't want to %s, you can <a href=index>"
+ "return to the server manager.</a></center>\n"},
+ {"CURSERVNAME", "FUNC curservname"},
+ {"VERIFY ", "FUNC verify"},
+ {"HELPBUTTON", "FUNC helpbutton"},
+ {"DIALOGSUBMIT", "FUNC dialogsubmit"},
+ {"HELPJSFN", "FUNC helpjsfn"}
+};
+
+int get_directive(char *string);
+void conditional(char *input, char **vars, int index);
+void respicker(char **config);
+void currentres(char **config);
+void prevres(char **config);
+void booktrack(char *input, char **vars);
+void docswitcher(char *input);
+void docroot(char **vars);
+void link_referer(char **input, char **vars);
+void serverroot(char **vars);
+char **get_vars(char *string);
+static void output(char *string);
+void makeurl(char **vars);
+void curservname(void);
+void pageheader(char **vars, char **config);
+void submit(int verify, char **vars);
+void helpbutton(char *topic);
+void dialogsubmit(char *topic);
+
+static int status = -1;
+
+/* Filter a page. Takes the page to filter as an argument. Uses above
+ * filters to process.
+ */
+NSAPI_PUBLIC int parse_line(char *line_input, char **input)
+{
+ register int index;
+ char *position;
+ int dirlen = strlen(DIRECTIVE_START);
+ char **vars;
+
+
+ if(!strncmp(line_input, DIRECTIVE_START, dirlen)) {
+ position = (char *) (line_input + dirlen);
+ index = get_directive(position);
+
+ /* did we get one? */
+ if(index != -1) {
+ /* if so, get the vars. */
+ position += strlen(templates[index].name);
+ vars = get_vars(position);
+ /* Dispatch the correct function (done for readability,
+ * although I'm starting to wonder if I should bother)
+ */
+ if(!strncmp(templates[index].format, "FUNC ", 5)) {
+
+ if(!strncmp(templates[index].format+5, "conditional", 11))
+ conditional(input[0], vars, index);
+ else if(!strncmp(templates[index].format+5, "respicker", 9))
+ respicker(input);
+ else if(!strncmp(templates[index].format+5, "booktrack", 9))
+ booktrack(input[0], vars);
+ else if(!strncmp(templates[index].format+5, "docswitcher", 11))
+ docswitcher(input[0]);
+ else if(!strncmp(templates[index].format+5, "docroot", 7))
+ docroot(vars);
+ else if(!strncmp(templates[index].format+5, "link_referer",12))
+ link_referer(input, vars);
+ else if(!strncmp(templates[index].format+5, "serverroot",10))
+ serverroot(vars);
+ else if(!strncmp(templates[index].format+5, "makeurl",7))
+ makeurl(vars);
+ else if(!strncmp(templates[index].format+5, "curservname",11))
+ curservname();
+ else if(!strncmp(templates[index].format+5, "pageheader",10))
+ pageheader(vars, input);
+ else if(!strncmp(templates[index].format+5, "submit",6))
+ submit(0, vars);
+ else if(!strncmp(templates[index].format+5, "verify",6))
+ submit(1, vars);
+ else if(!strncmp(templates[index].format+5, "helpbutton",10))
+ helpbutton(vars[0]);
+ else if(!strncmp(templates[index].format+5, "dialogsubmit",12))
+ dialogsubmit(vars[0]);
+ /* We don't know what this template is. Send it back. */
+ else return -1;
+ } else {
+ /* I just can't believe there's no easy way to create
+ * a va_list. */
+ char line[BIG_LINE];
+ sprintf(line, templates[index].format,
+ (vars[0] != NULL) ? vars[0]: "",
+ (vars[1] != NULL) ? vars[1]: "",
+ (vars[2] != NULL) ? vars[2]: "",
+ (vars[3] != NULL) ? vars[3]: "");
+ output(line);
+ }
+ } else {
+ /* We found a directive, but we can't identify it. Send it back.*/
+ /* Check status first; if we're not supposed to be outputing */
+ /* because of an "IF" block, don't tell the program to */
+ /* try and cope with it. */
+ if(status)
+ return -1;
+ else
+ return 0;
+ }
+ } else
+ /* We found no directive. The line is normal. */
+ output(line_input);
+
+ /* If we're here, we either handled it correctly or the line was benign.*/
+ return 0;
+}
+
+void conditional(char *input, char **vars, int index)
+{
+ if((!strncmp(templates[index].name, "IF", 2)) &&
+ (vars[0] != NULL)) {
+ status = input[atoi(vars[0])] - '0';
+ } else
+ if((!strncmp(templates[index].name, "ELSE", 4)) &&
+ (status != -1)) {
+ status ^= 1;
+ } else
+ if(!strncmp(templates[index].name, "ENDIF", 5))
+ status = -1;
+}
+
+void respicker(char **config)
+{
+ output("<FORM action=rsrcpckr method=GET>\n");
+ output("<hr size=4><center>\n");
+ prevres(config);
+ output("</center><hr size=4>\n");
+ output("</FORM>\n");
+}
+
+void currentres(char **config)
+{
+ int l;
+ char line[BIG_LINE];
+ char *resname, *restype;
+
+ resname = get_current_resource(config);
+ restype = get_current_typestr(config);
+ if(!strcmp(restype, NAME)) {
+ if(!strcmp(resname, "default"))
+ sprintf(line, "<font size=+1>Modifying: "
+ "<b>the entire server</b>.</font>");
+ else
+ sprintf(line, "<font size=+1>Modifying: "
+ "<b>the object named %s</b>.</font>", resname);
+ }
+ else if(!strcmp(restype, FILE_OR_DIR)) {
+ l = strlen(resname) - 1;
+ if(resname[l] == '*') {
+ sprintf(line, "<font size=+1>Modifying: <b>the directory "
+ "%s</b></font>",
+ resname);
+ } else {
+ sprintf(line, "<font size=+1>Modifying: <b>%s %s</b></font>",
+ (strchr(resname, '*')) ? "files matching" : "the file",
+ resname);
+ }
+ }
+ else if(!strcmp(restype, TEMPLATE)) {
+ sprintf(line, "<font size=+1>Modifying: <b>the template %s</b></font>",
+ resname);
+ }
+ else if(!strcmp(restype, WILDCARD)) {
+#ifdef MCC_PROXY
+ sprintf(line, "<font size=+1>Modifying: <b>URLs matching RE %s"
+#else
+ sprintf(line, "<font size=+1>Modifying: <b>files matching %s"
+#endif
+ "</b></font>",
+ resname);
+ }
+ output(line);
+}
+
+void prevres(char **config)
+{
+#ifndef MCC_NEWS
+ char *res = get_current_resource(config);
+ int rtype = get_current_restype(config);
+
+ if(status) {
+ char **options = NULL;
+ register int x=0;
+ int found=0;
+ int option_cnt = total_object_count();
+
+ fprintf(stdout, "<SCRIPT language=JavaScript>\n");
+ fprintf(stdout, "function checkForClick() {\n");
+ fprintf(stdout, " document.forms[0].resource.blur();\n");
+ fprintf(stdout, " var idx=document.forms[0]."
+ "resource.options.selectedIndex;\n");
+ fprintf(stdout, " if(document.forms[0].resource."
+ "options[idx].defaultSelected == 0) {\n");
+ fprintf(stdout, " document.forms[0].submit();\n");
+ fprintf(stdout, " return 1;\n");
+ fprintf(stdout, " } else return 0;\n");
+ fprintf(stdout, "}\n");
+ fprintf(stdout, "</SCRIPT>\n");
+
+#ifdef MCC_PROXY
+ fprintf(stdout, "<TABLE BORDER=0>\n");
+ fprintf(stdout, "<TR><TD><font size=+1>Editing:</font></TD>\n");
+ fprintf(stdout,
+ "<TD><SELECT name=\"resource\" onChange=\"checkForClick()\" SIZE=\"%d\">\n",
+ option_cnt <= 20 ? 1 : 5);
+#else
+ output("<nobr>");
+ fputs("<font size=+1>Editing:</font>\n", stdout);
+ fprintf(stdout, "<SELECT name=\"resource\" "
+ "onChange=\"checkForClick()\" %s>\n",
+ option_cnt <=20 ? "" : "size=5");
+#endif
+
+#ifdef MCC_HTTPD /* template->styles nightmare */
+ if((rtype==PB_NAME) && (strcmp(res, "default"))) {
+ /* enter: STYLES MODE */
+ fprintf(stdout, "<OPTION value=ndefault>Exit styles mode\n");
+ } else {
+ fprintf(stdout, "<OPTION value=ndefault %s>The entire server\n",
+ (!strcmp(res, "default")) ? "SELECTED" : "");
+ }
+#else
+ fprintf(stdout, "<OPTION value=ndefault %s>The entire server\n",
+ (!strcmp(res, "default")) ? "SELECTED" : "");
+#endif
+ if(!strcmp(res, "default")) found=1;
+ options = list_objects(PB_PATH);
+#ifdef MCC_HTTPD /* template->styles nightmare */
+ if((options) && !((rtype==PB_NAME) && (strcmp(res, "default"))) ) {
+#else
+ if(options) {
+#endif
+ for(x=0; options[x]; x++) {
+ fprintf(stdout, "<OPTION value=f%s %s>%s\n",
+ options[x],
+ (!strcmp(options[x], res)) ? "SELECTED" : "",
+ options[x]);
+ if(!strcmp(options[x], res)) found=1;
+ }
+ }
+ options=list_objects(PB_NAME);
+#ifdef MCC_HTTPD /* template->styles nightmare */
+ if((options) && ((rtype==PB_NAME) && (strcmp(res, "default"))) ) {
+#else
+ if(options) {
+#endif
+ for(x=0; options[x]; x++) {
+ if(!strcmp(options[x], "default") ||
+ !strcmp(options[x], "cgi"))
+ continue;
+#ifdef MCC_HTTPD /* template->style usability */
+ fprintf(stdout, "<OPTION value=n%s %s>The style '%s'\n",
+ options[x],
+ (!strcmp(options[x], res)) ? "SELECTED":"",
+ options[x]);
+#else
+ fprintf(stdout, "<OPTION value=n%s %s>The template '%s'\n",
+ options[x],
+ (!strcmp(options[x], res)) ? "SELECTED":"",
+ options[x]);
+#endif
+ if(!strcmp(options[x], res)) found=1;
+ }
+ }
+ if(!found) {
+ if(rtype==PB_NAME) {
+ fprintf(stdout, "<OPTION value=n%s SELECTED>The template %s\n",
+ res, res);
+ } else {
+ fprintf(stdout, "<OPTION value=f%s SELECTED>%s\n",
+ res, res);
+ }
+ }
+ fputs("</SELECT></nobr>\n", stdout);
+ fputs("<nobr>", stdout);
+#ifndef MCC_PROXY
+ fprintf(stdout, "<INPUT type=button value=\"Browse...\" "
+ "onClick=\"window.location='rsrcpckr?b'\"> ");
+#endif
+#ifdef MCC_PROXY
+ fprintf(stdout, "</TD>\n<TD>");
+ fprintf(stdout, "<INPUT type=button value=\"Regular Expression...\" "
+ "onClick=\"var pat="
+ "prompt('Enter the regular expression to edit:', ''); "
+#else
+ fprintf(stdout, "<INPUT type=button value=\"Wildcard...\" "
+ "onClick=\"var pat="
+ "prompt('Enter the wildcard pattern to edit:', ''); "
+#endif
+ "if(pat!=null) window.location='rsrcpckr?"
+ "type="WILDCARD"&resource='+escape(pat);\">");
+#ifdef MCC_PROXY
+ fprintf(stdout, "</TD>\n</TR>\n</TABLE>\n");
+#endif
+ fputs("</nobr>", stdout);
+ /* output("</td></tr>\n"); */
+ }
+#endif
+}
+
+void booktrack(char *input, char **vars)
+{
+ char line[BIG_LINE];
+
+ if((vars[0] != NULL) && (vars[1] != NULL)) {
+ sprintf(line, "<a href=index?0>"
+ "<img src=\"%s\" hspace=8 align=%s alt=\"\"></a>",
+ (input[0] - '0') ? vars[0] : vars[1],
+ (vars[2] != NULL) ? vars[2] : "none");
+ output(line);
+ }
+}
+
+void docswitcher(char *input)
+{
+ char line[BIG_LINE];
+ char *whichimg, *whatmode;
+#ifdef USE_ADMSERV
+ char *qs = getenv("QUERY_STRING");
+ char *sname = getenv("SCRIPT_NAME");
+ char *mtmp;
+
+ char *tmp = getenv("SERVER_NAMES");
+ char *servers = NULL;
+ if(tmp) servers = STRDUP(tmp);
+#endif
+
+ if(!(input[0] - '0')) {
+ whichimg = "b-clsd.gif";
+ whatmode = "Express mode";
+ } else {
+ whichimg = "b-open.gif";
+ whatmode = "Full docs";
+ }
+
+ mtmp = (char *) MALLOC( (sname? strlen(sname) : 0) +
+ (qs? strlen(qs) : 0) +
+ (strlen(whichimg) + strlen(whatmode)) +
+ 1024);
+ sprintf(mtmp, "<center><table border=2 width=95%%>\n"
+ "<tr><td rowspan=2><a href=index%s>"
+ "<img src=\"../icons/%s\" "
+ "alt=\"[%s] \" border=2>"
+ "</td>\n",
+ (qs ? "?0" : sname),
+ whichimg, whatmode);
+ output(mtmp);
+
+#ifdef USE_ADMSERV
+ if(!servers) {
+ sprintf(line, "<td width=100%% align=center rowspan=2><b>%s</b></td>\n",
+ whatmode);
+ output(line);
+ } else
+ if(servers[0] == '(') {
+
+ sprintf(line, "<td width=100%% align=center>Current servers:<br>\n");
+ output(line);
+ output("<b>");
+
+ tmp=strtok(++servers, "|)");
+ while(tmp) {
+ char *tmp2;
+ output("<nobr>");
+ tmp2=strchr(tmp, '-');
+ tmp2++;
+ output(tmp2);
+ tmp=strtok(NULL, "|)");
+ if(tmp)
+ output(",");
+ output("</nobr>\n");
+ }
+ output("</b></td>\n");
+ } else {
+
+ sprintf(line, "<td width=100%% align=center>Current server: ");
+ output(line);
+ output("<b>");
+ tmp = strchr(servers, '-');
+ *tmp++ = '\0';
+ output(tmp);
+ output("</b>");
+ output("</td>\n");
+ }
+#endif
+ sprintf(mtmp, "<td rowspan=2><a href=index%s>"
+ "<img src=\"../icons/%s\" "
+ "alt=\"\" border=2></a></td></tr>\n",
+ (qs? "?0" : sname),
+ whichimg);
+ output(mtmp);
+#ifdef USE_ADMSERV
+ if(servers) {
+ sprintf(line, "<tr><td align=center>"
+ "<a href=\"/admin-serv/bin/chooser\">"
+ "Choose</a> a new server or set of servers</a></td>\n");
+ output(line);
+ }
+#endif
+ sprintf(line, "</tr></table></center>\n");
+ output(line);
+ output("<hr width=10%%>\n");
+}
+
+void docroot(char **vars)
+{
+#ifndef MCC_NEWS
+ char line[BIG_LINE];
+ pblock *pb = grab_pblock(PB_NAME, "default", "NameTrans", "document-root",
+ NULL, NULL);
+ char *docroot = "";
+ if(pb)
+ docroot = pblock_findval("root", pb);
+ sprintf(line, "<b>%s%s</b>\n", docroot, (vars[0] != NULL) ? vars[0] : "");
+ output(line);
+#endif
+}
+
+void serverroot(char **vars)
+{
+ char line[BIG_LINE];
+#ifdef USE_ADMSERV
+ char *sroot = getenv("NETSITE_ROOT");
+#else
+ char *sroot = get_mag_var("#ServerRoot");
+#endif
+ sprintf(line, "%s%s", (sroot) ? sroot : "", (vars[0]) ? vars[0] : "");
+ output(line);
+}
+
+void makeurl(char **vars)
+{
+ char line[BIG_LINE];
+
+ sprintf(line,"<a href=%s target=_blank>%s</a>\n",
+ get_serv_url(), vars[0] ? vars[0] : "");
+ output(line);
+}
+
+void curservname(void)
+{
+ output(get_srvname(0));
+}
+
+NSAPI_PUBLIC
+void pageheader(char **vars, char **config)
+{
+ char line[BIG_LINE];
+#if 0 /* MLM - put in to have non-working Back button */
+ char *ref=get_referer(config);
+ char *t;
+#endif
+
+ output("<center><table border=2 width=100%%>\n");
+
+ util_snprintf(line, BIG_LINE, "<tr>");
+ output(line);
+
+ util_snprintf(line, BIG_LINE, "<td align=center width=100%%>");
+ output(line);
+ util_snprintf(line, BIG_LINE, "<hr size=0 width=0>");
+ output(line);
+#if 0 /* MLM - put in to have non-working Back button */
+ t=strrchr(ref, '/');
+ *t++='\0';
+ util_snprintf(line, BIG_LINE, "<a href=\"%s/index/%s\">", ref, t);
+ output(line);
+ util_snprintf(line, BIG_LINE, "<img align=right src=../icons/back.gif "
+ "width=41 height=26 border=0></a>\n");
+ output(line);
+#endif
+ util_snprintf(line, BIG_LINE, "<FONT size=+2><b>%s</b></FONT>"
+ "<hr size=0 width=0>"
+ "</td>", vars[2]);
+ output(line);
+
+ output("</tr></table></center>\n");
+}
+
+char *_get_help_button(char *topic)
+{
+ char line[BIG_LINE];
+
+ util_snprintf( line, BIG_LINE,
+ "<input type=button value=\"%s\" "
+ "onClick=\"%s\">", XP_GetAdminStr(DBT_help_),
+ topic ? helpJavaScriptForTopic( topic ) : helpJavaScript() );
+
+ return(STRDUP(line));
+}
+
+NSAPI_PUBLIC char *helpJavaScriptForTopic( char *topic )
+{
+ char *tmp;
+ char line[BIG_LINE];
+ char *server=get_srvname(0);
+ char *type;
+ int typeLen;
+
+ /* Get the server type, without the instance name into type */
+ tmp = strchr( server, '-' );
+ typeLen = tmp - server;
+
+ type = (char *)MALLOC( typeLen + 1 );
+ type[typeLen] = '\0';
+ while ( typeLen-- ) {
+ type[typeLen] = server[typeLen];
+ }
+ util_snprintf( line, BIG_LINE,
+ "if ( top.helpwin ) {"
+ " top.helpwin.focus();"
+ " top.helpwin.infotopic.location='%s/%s/admin/tutor?!%s';"
+ "} else {"
+ " window.open('%s/%s/admin/tutor?%s', '"
+ INFO_IDX_NAME"_%s', "
+ HELP_WIN_OPTIONS");}",
+ getenv("SERVER_URL"), server, topic,
+ getenv("SERVER_URL"), server, topic,
+ type );
+
+ return(STRDUP(line));
+}
+
+NSAPI_PUBLIC char *helpJavaScript()
+{
+ char *tmp, *sn;
+
+ tmp=STRDUP(getenv("SCRIPT_NAME"));
+ if(strlen(tmp) > (unsigned)BIG_LINE)
+ tmp[BIG_LINE-2]='\0';
+ sn=strrchr(tmp, '/');
+ if( sn )
+ *sn++='\0';
+ return helpJavaScriptForTopic( sn );
+}
+
+void submit(int verify, char **vars)
+{
+ char line[BIG_LINE];
+ char outline[BIG_LINE];
+
+ if(verify) {
+ util_snprintf(line, BIG_LINE, "<SCRIPT language="MOCHA_NAME">\n"
+ "function verify(form) {\n"
+ " if(confirm('Do you really want to %s?'))\n"
+ " form.submit();\n"
+ "}\n"
+ "</SCRIPT>\n", vars[0]);
+ output(line);
+ }
+
+ output("<center><table border=2 width=100%%><tr>");
+
+ if(!verify) {
+ util_snprintf(outline, BIG_LINE, "%s%s%s%s%s",
+ "<td width=33%% align=center>",
+ "<input type=submit value=\"",
+ XP_GetAdminStr(DBT_ok_),
+ "\">",
+ "</td>\n");
+ } else {
+ util_snprintf(outline, BIG_LINE, "%s%s%s%s%s%s",
+ "<td width=33%% align=center>",
+ "<input type=button value=\"",
+ XP_GetAdminStr(DBT_ok_),
+ "\" ",
+ "onclick=\"verify(this.form)\">",
+ "</td>\n");
+ }
+ output(outline);
+ util_snprintf(outline, BIG_LINE, "%s%s%s%s",
+ "<td width=34%% align=center>",
+ "<input type=reset value=\"",
+ XP_GetAdminStr(DBT_reset_),
+ "\"></td>\n");
+ output(outline);
+
+ util_snprintf(line, BIG_LINE, "<td width=33%% align=center>%s</td>\n",
+ _get_help_button( vars[0] ));
+ output(line);
+
+ output("</tr></table></center>\n");
+
+ output("</form>\n");
+
+ output("<SCRIPT language="MOCHA_NAME">\n");
+ output("</SCRIPT>\n");
+}
+
+void helpbutton(char *topic)
+{
+ output("<form><p><div align=right><table width=33%% border=2>"
+ "<tr><td align=center>");
+ output(_get_help_button(topic));
+ output("</td></tr></table></div></form>\n");
+ output("<SCRIPT language="MOCHA_NAME">\n");
+ output("</SCRIPT>\n");
+}
+
+void dialogsubmit(char *topic)
+{
+ char line[BIG_LINE];
+ char outline[BIG_LINE];
+
+ output("<center><table border=2 width=100%%><tr>");
+
+ util_snprintf(outline, BIG_LINE, "%s%s%s%s%s",
+ "<td width=33%% align=center>",
+ "<input type=submit value=\"",
+ XP_GetAdminStr(DBT_done_),
+ "\">",
+ "</td>\n");
+ output(outline);
+ util_snprintf(outline, BIG_LINE, "%s%s%s%s%s",
+ "<td width=34%% align=center>",
+ "<input type=button value=\"",
+ XP_GetAdminStr(DBT_cancel_),
+ "\" "
+ "onClick=\"top.close()\"></td>\n");
+ output(outline);
+
+ util_snprintf(line, BIG_LINE, "<td width=33%% align=center>%s</td>\n",
+ _get_help_button(topic));
+ output(line);
+
+ output("</tr></table></center>\n");
+
+ output("</form>\n");
+
+ output("<SCRIPT language="MOCHA_NAME">\n");
+ output("</SCRIPT>\n");
+}
+
+void helpjsfn(void)
+{
+ char *tmp;
+ char line[BIG_LINE];
+ char *server=get_srvname(0);
+ char *type;
+ int typeLen;
+
+ /* Get the server type, without the instance name into type */
+ tmp = strchr( server, '-' );
+ typeLen = tmp - server;
+
+ type = (char *)MALLOC( typeLen + 1 );
+ type[typeLen] = '\0';
+ while ( typeLen-- ) {
+ type[typeLen] = server[typeLen];
+ }
+
+ output("function displayHelpTopic(topic)\n");
+ output("{\n");
+ util_snprintf(line, BIG_LINE,
+ " if (top.helpwin) {\n"
+ " top.helpwin.focus();\n"
+ " top.helpwin.infotopic.location='%s/%s/admin/tutor?!' + topic;\n"
+ " } else {\n"
+ " window.open('%s/%s/admin/tutor?' + topic, '"
+ INFO_IDX_NAME"_%s', "
+ HELP_WIN_OPTIONS");\n"
+ " }\n"
+ "}\n",
+ getenv("SERVER_URL"), server,
+ getenv("SERVER_URL"), server,
+ type );
+ output(line);
+}
+
+void link_referer(char **input, char **vars)
+{
+ char line[BIG_LINE];
+
+ sprintf( line, "<SCRIPT language="MOCHA_NAME">\n"
+ "document.writeln( '%s'.link( '%s' ) );\n"
+ "</SCRIPT>\n", ( vars[0] ? vars[0] : getenv( "SCRIPT_NAME" ) ),
+ cookieValue( "adminReferer", NULL ) );
+ output( line );
+}
+
+int get_directive(char *string)
+{
+ int index = -1;
+ register int x;
+
+ for(x=0; x < MAXTEMPLATE; x++) {
+ if(!strncmp(string, templates[x].name,
+ strlen(templates[x].name))) {
+ index = x;
+ break;
+ }
+ }
+ return index;
+}
+
+NSAPI_PUBLIC int directive_is(char *target, char *directive)
+{
+ char *position = (target + strlen(DIRECTIVE_START));
+ return(!(strncmp(directive, position, strlen(directive))));
+}
+
+char **get_vars(char *string)
+{
+ char **vars;
+ register int x;
+ int isvar;
+ char scratch[BIG_LINE];
+ char lastchar;
+
+/* Initialize the vars array.
+ */
+ vars = (char **) MALLOC((MAXVARS)*(sizeof(char *)));
+ for(x=0; x< MAXVARS; x++)
+ vars[x] = NULL;
+
+ isvar = -1;
+ x = 0;
+ scratch[0] = '\0';
+ lastchar = ' ';
+
+ while(*string != '\0') {
+ if((*string == '\"') && (lastchar != '\\'))
+ if(isvar != -1) {
+ vars[x++] = (char *)STRDUP(scratch);
+ isvar = -1;
+ if(x == MAXVARS)
+ break;
+ } else
+ isvar = 0;
+ else
+ if(isvar != -1) {
+ scratch[isvar++] = *string;
+ scratch[isvar] = '\0';
+ }
+ else
+ if(*string == DIRECTIVE_END)
+ break;
+ lastchar = *string;
+ string++;
+ }
+ return vars;
+}
+
+static void output(char *line)
+{
+ if(status)
+ fputs(line, stdout);
+}
diff --git a/lib/libadmin/util.c b/lib/libadmin/util.c
new file mode 100644
index 00000000..b560055d
--- /dev/null
+++ b/lib/libadmin/util.c
@@ -0,0 +1,1340 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/*
+ * util.c: Miscellaneous stuffs
+ *
+ * All blame to Mike McCool
+ */
+
+#include "libadmin/libadmin.h"
+#include "base/util.h"
+#include "private/pprio.h"
+
+#ifdef XP_UNIX
+#include <dirent.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#else
+#include <base/file.h>
+#include <sys/stat.h>
+#endif /* WIN32? */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <ctype.h> /* isdigit */
+
+#define NUM_ENTRIES 64
+
+#ifdef MCC_PROXY
+char *
+XP_GetString()
+{
+ return "ZAP";
+}
+#endif
+
+#ifdef XP_WIN32
+char *GetQueryNT(void)
+{
+ char *qs = getenv("QUERY_STRING");
+ if(qs && (*qs == '\0'))
+ qs = NULL;
+ return qs;
+}
+#endif /* XP_WIN32 */
+
+void escape_for_shell(char *cmd) {
+ register int x,y,l;
+
+ l=strlen(cmd);
+ for(x=0;cmd[x];x++) {
+ if(strchr(" &;`'\"|*!?~<>^()[]{}$\\\x0A",cmd[x])){
+ for(y=l+1;y>x;y--)
+ cmd[y] = cmd[y-1];
+ l++; /* length has been increased */
+ cmd[x] = '\\';
+ x++; /* skip the character */
+ }
+ }
+}
+
+int _admin_dumbsort(const void *s1, const void *s2)
+{
+ return strcmp(*((char **)s1), *((char **)s2));
+}
+
+#ifdef XP_UNIX /* WIN32 change */
+/* Lists all files in a directory. */
+char **list_directory(char *path, int dashA)
+{
+ char **ar;
+ DIR *ds;
+ struct dirent *d;
+ int n, p;
+
+ n = NUM_ENTRIES;
+ p = 0;
+
+ ar = (char **) MALLOC(n * sizeof(char *));
+
+ if(!(ds = opendir(path))) {
+ return NULL;
+ }
+
+ while( (d = readdir(ds)) ) {
+ if ( ( d->d_name[0] != '.' ) ||
+ ( dashA && d->d_name[1] &&
+ ( d->d_name[1] != '.' || d->d_name[2] ) ) ) {
+ if(p == (n-1)) {
+ n += NUM_ENTRIES;
+ ar = (char **) REALLOC(ar, n*sizeof(char *));
+ }
+ /* 2: Leave space to add a trailing slash later */
+ ar[p] = (char *) MALLOC(strlen(d->d_name) + 2);
+ strcpy(ar[p++], d->d_name);
+ }
+ }
+ closedir(ds);
+
+ qsort((void *)ar, p, sizeof(char *), _admin_dumbsort);
+ ar[p] = NULL;
+
+ return ar;
+}
+
+#else /* WIN32 change */
+/* Lists all files in a directory. */
+char **list_directory(char *path, int dashA)
+{
+ char **ar;
+ SYS_DIR ds;
+ SYS_DIRENT *d;
+ int n, p;
+
+ n = NUM_ENTRIES;
+ p = 0;
+
+ ar = (char **) MALLOC(n * sizeof(char *));
+
+ if(!(ds = dir_open(path))) {
+ return NULL;
+ }
+
+ while( (d = dir_read(ds)) ) {
+ if ( ( d->d_name[0] != '.' ) ||
+ ( dashA && d->d_name[1] &&
+ ( d->d_name[1] != '.' || d->d_name[2] ) ) ) {
+ if(p == (n-1)) {
+ n += NUM_ENTRIES;
+ ar = (char **) REALLOC(ar, n*sizeof(char *));
+ }
+ /* 2: Leave space to add a trailing slash later */
+ ar[p] = (char *) MALLOC(strlen(d->d_name) + 2);
+ strcpy(ar[p++], d->d_name);
+ }
+ }
+ dir_close(ds);
+
+ qsort((void *)ar, p, sizeof(char *), _admin_dumbsort);
+ ar[p] = NULL;
+
+ return ar;
+}
+#endif /* WIN32 */
+
+int file_exists(char *fn)
+{
+ struct stat finfo;
+
+ if(!stat(fn, &finfo))
+ return 1;
+ else
+ return 0;
+}
+
+int get_file_size(char *fn)
+{
+ struct stat finfo;
+ int ans = -1;
+
+ if(!stat(fn, &finfo)) {
+ ans = finfo.st_size;
+ } else {
+ report_error(FILE_ERROR, fn, "Could not get size of file.");
+ }
+ return ans;
+}
+
+int ADM_mkdir_p(char *dir, int mode)
+{
+ char path[PATH_MAX];
+ struct stat fi;
+ char *slash = NULL;
+
+ if (dir)
+ strcpy (path, dir);
+ else
+ return 0;
+
+ if (slash = strchr(path, FILE_PATHSEP))
+ slash++; /* go past root */
+ else
+ return 0;
+
+ while (slash && *slash) {
+ slash = strchr(slash, FILE_PATHSEP);
+ if (slash) *slash = '\0'; /* check path till here */
+
+ if (stat(path, &fi) == -1) {
+#ifdef XP_UNIX
+ if (mkdir(path, mode) == -1)
+#else /* XP_WIN32 */
+ if (!CreateDirectory(path, NULL))
+#endif
+ return 0;
+ }
+
+ if (slash) {
+ *slash = FILE_PATHSEP; /* restore path */
+ slash++; /* check remaining path */
+ }
+ }
+ return 1;
+}
+
+int ADM_copy_directory(char *src_dir, char *dest_dir)
+{
+ SYS_DIR ds;
+ SYS_DIRENT *d;
+ struct stat fi;
+ char src_file[PATH_MAX], dest_file[PATH_MAX], fullname[PATH_MAX];
+
+ if (!(ds = dir_open(src_dir)))
+ report_error(FILE_ERROR, "Can't read directory", src_dir);
+
+ while (d = dir_read(ds)) {
+ if (d->d_name[0] != '.') {
+ sprintf(fullname, "%s/%s", src_dir, d->d_name);
+ if (system_stat(fullname, &fi) == -1)
+ continue;
+
+ sprintf(src_file, "%s%c%s", src_dir, FILE_PATHSEP, d->d_name);
+ sprintf(dest_file, "%s%c%s", dest_dir, FILE_PATHSEP, d->d_name);
+ if (S_ISDIR(fi.st_mode)) {
+ char *sub_src_dir = STRDUP(src_file);
+ char *sub_dest_dir = STRDUP(dest_file);
+ if (!ADM_mkdir_p(sub_dest_dir, 0755)) {
+ report_error(FILE_ERROR, "Cannot create directory",
+ sub_dest_dir);
+ return 0;
+ }
+ if (!ADM_copy_directory(sub_src_dir, sub_dest_dir))
+ return 0;
+ FREE(sub_src_dir);
+ FREE(sub_dest_dir);
+ }
+ else
+ cp_file(src_file, dest_file, 0644);
+ }
+ }
+ dir_close(ds);
+ return(1);
+}
+
+void ADM_remove_directory(char *path)
+{
+ struct stat finfo;
+ char **dirlisting;
+ register int x=0;
+ int stat_good = 0;
+ char *fullpath = NULL;
+
+#ifdef XP_UNIX
+ stat_good = (lstat(path, &finfo) == -1 ? 0 : 1);
+#else /* XP_WIN32 */
+ stat_good = (stat(path, &finfo) == -1 ? 0 : 1);
+#endif
+
+ if(!stat_good) return;
+
+ if(S_ISDIR(finfo.st_mode)) {
+ dirlisting = list_directory(path,1);
+ if(!dirlisting) return;
+
+ for(x=0; dirlisting[x]; x++) {
+ fullpath = (char *) MALLOC(strlen(path) +
+ strlen(dirlisting[x]) + 4);
+ sprintf(fullpath, "%s%c%s", path, FILE_PATHSEP, dirlisting[x]);
+#ifdef XP_UNIX
+ stat_good = (lstat(fullpath, &finfo) == -1 ? 0 : 1);
+#else /* XP_WIN32 */
+ stat_good = (stat(fullpath, &finfo) == -1 ? 0 : 1);
+#endif
+ if(!stat_good) continue;
+ if(S_ISDIR(finfo.st_mode)) {
+ ADM_remove_directory(fullpath);
+ } else {
+ unlink(fullpath);
+ }
+ FREE(fullpath);
+ }
+#ifdef XP_UNIX
+ rmdir(path);
+#else /* XP_WIN32 */
+ RemoveDirectory(path);
+#endif
+ } else {
+ delete_file(path);
+ }
+ return;
+}
+
+/* return: mtime(f1) < mtime(f2) ? */
+int mtime_is_earlier(char *file1, char *file2)
+{
+ struct stat fi1, fi2;
+
+ if(stat(file1, &fi1)) {
+ return -1;
+ }
+ if(stat(file2, &fi2)) {
+ return -1;
+ }
+ return( (fi1.st_mtime < fi2.st_mtime) ? 1 : 0);
+}
+
+time_t get_mtime(char *fn)
+{
+ struct stat fi;
+
+ if(stat(fn, &fi))
+ return 0;
+ return fi.st_mtime;
+}
+
+int all_numbers(char *target)
+{
+ register int x=0;
+
+ while(target[x])
+ if(!isdigit(target[x++]))
+ return 0;
+ return 1;
+}
+
+
+int all_numbers_float(char *target)
+{
+ register int x;
+ int seenpt;
+
+ for(x = 0, seenpt = 0; target[x]; ++x) {
+ if((target[x] == '.') && (!seenpt))
+ seenpt = 1;
+ else if((!isdigit(target[x])) && seenpt)
+ return 0;
+ }
+ return 1;
+}
+
+/* Get the admin/config directory. */
+char *get_admcf_dir(int whichone)
+{
+#ifdef USE_ADMSERV
+ char *confdir = NULL;
+
+ char *tmp = get_num_mag_var(whichone, "#ServerRoot");
+ if(!tmp) {
+ /* sigh */
+ report_error(INCORRECT_USAGE, "No server root variable",
+ "The magnus.conf variable #ServerRoot was "
+ "not set. Please set the value of your server "
+ "root through the administrative forms.");
+ }
+ confdir = (char *) MALLOC(strlen(tmp) + strlen("config") + 4);
+ sprintf(confdir, "%s%cconfig%c", tmp, FILE_PATHSEP, FILE_PATHSEP);
+
+ return confdir;
+#else
+ char *confdir;
+ char line[BIG_LINE];
+ sprintf(line, "%s%cadmin%cconfig%c", get_mag_var("#ServerRoot"),
+ FILE_PATHSEP, FILE_PATHSEP, FILE_PATHSEP);
+ confdir = STRDUP(line);
+#endif
+ return STRDUP(confdir);
+}
+
+/* Get the current HTTP server URL. */
+char *get_serv_url(void)
+{
+#ifdef USE_ADMSERV
+ char *name = get_mag_var("ServerName");
+ char *port = get_mag_var("Port");
+ char *protocol = NULL;
+ char line[BIG_LINE];
+
+#ifndef NS_UNSECURE
+ char *security = get_mag_var("Security");
+
+ if(!security || strcasecmp(security, "on")) {
+ protocol = STRDUP("http");
+ if(!strcmp(port, "80"))
+ port = STRDUP("");
+ else {
+ sprintf(line, ":%s", port);
+ port = STRDUP(line);
+ }
+ } else {
+ protocol = STRDUP("https");
+ if(!strcmp(port, "443"))
+ port = STRDUP("");
+ else {
+ sprintf(line, ":%s", port);
+ port = STRDUP(line);
+ }
+ }
+#else
+ protocol = STRDUP("http");
+ if(!strcmp(port, "80"))
+ port = STRDUP("");
+ else {
+ sprintf(line, ":%s", port);
+ port = STRDUP(line);
+ }
+#endif
+
+ sprintf(line, "%s://%s%s", protocol, name, port);
+ return(STRDUP(line));
+#else
+ return(getenv("SERVER_URL"));
+#endif
+}
+
+/* ------------------------------- run_cmd -------------------------------- */
+
+
+/* Previously in install. This is also pretty UNIX-ish. */
+
+/* Nirmal: Added code for Win32 implementation of this function. */
+
+#include <signal.h>
+#ifdef XP_UNIX
+#include <sys/wait.h>
+#endif /* XP_UNIX */
+
+
+int run_cmd(char *cmd, FILE *closeme, struct runcmd_s *rm)
+{
+#ifdef WIN32
+ HANDLE hproc;
+ PROCESS_INFORMATION child;
+ STARTUPINFO siStartInfo ;
+#else
+ struct stat fi;
+ int exstat;
+ char *errmsg, tfn[128];
+ FILE *f;
+ int fd;
+ pid_t pid;
+#endif
+
+
+#ifdef WIN32
+ /* Nirmal:
+ For now, i will just spawn
+ a child in WINNT to execute the command. Communication to
+ the parent is done through stdout pipe, that was setup by
+ the parent.
+
+ */
+ hproc = OpenProcess(STANDARD_RIGHTS_REQUIRED, FALSE, GetCurrentProcessId());
+ if (hproc == NULL) {
+ fprintf(stdout, "Content-type: text/html\n\n");
+ fflush(stdout);
+ report_error(SYSTEM_ERROR, NULL, "Could not open handle to myself");
+ return -1; // stmt. not reached.
+ }
+
+ ZeroMemory(&child, sizeof(PROCESS_INFORMATION));
+ ZeroMemory(&siStartInfo, sizeof(STARTUPINFO));
+ siStartInfo.cb = sizeof(STARTUPINFO);
+ siStartInfo.lpReserved = siStartInfo.lpReserved2 = NULL;
+ siStartInfo.cbReserved2 = 0;
+ siStartInfo.lpDesktop = NULL;
+ siStartInfo.dwFlags = STARTF_USESHOWWINDOW;
+// Several fields arent used when dwFlags is not set.
+// siStartInfo.hStdInput = hChildStdinRd;
+// siStartInfo.hStdOutput = siStartInfo.hStdError = hChildStdoutWr;
+ siStartInfo.wShowWindow = SW_HIDE;
+
+ if ( ! CreateProcess(
+ NULL, // pointer to name of executable module
+ cmd, // pointer to command line string
+ NULL, // pointer to process security attribute
+ NULL, // pointer to thread security attributes
+ TRUE, // handle inheritance flag
+ 0, // creation flags
+ NULL, // pointer to new environment block
+ NULL, // pointer to current directory name
+ &siStartInfo, // pointer to STARTUPINFO
+ &child // pointer to PROCESS_INFORMATION
+ ))
+ {
+ rm->title = "CreateProcess failed";
+ rm->msg = "run_cmd: Can't create new process. ";
+ rm->arg = "";
+ rm->sysmsg = 1;
+ return -1;
+ }
+ else
+ return 0;
+#else
+ sprintf(cmd, "%s > /tmp/startmsg.%d 2>&1 < /dev/null", cmd, getpid()); /* */
+ /* FUCK UNIX SIGNALS. */
+ signal(SIGCHLD, SIG_DFL);
+ switch( (pid = fork()) ) {
+ case 0:
+ /* Hmm. Work around an apparent bug in stdio. */
+ if(closeme)
+ close(fileno(closeme));
+ execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
+ /* DOH! */
+ sprintf(tfn, "/tmp/startmsg.%d", getpid());
+ if(!(f = fopen(tfn, "w")))
+ exit(1);
+ fprintf(f, "Exec of %s failed. The error was %s.\n", cmd,
+ system_errmsg());
+ fclose(f);
+ exit(1);
+ case -1:
+ rm->title = "Fork failed";
+ rm->msg = "Can't create new process. %s";
+ rm->arg = "";
+ rm->sysmsg = 1;
+ return -1;
+ default:
+ sprintf(tfn, "/tmp/startmsg.%d", getpid());
+
+ if(waitpid(pid, &exstat, 0) == -1) {
+ rm->title = "Can't wait for child";
+ rm->msg = "Can't wait for process. %s";
+ rm->arg = "";
+ rm->sysmsg = 1;
+ return -1;
+ }
+ if(exstat) {
+ if(!(fd = open(tfn, O_RDONLY))) {
+ rm->title = "Can't open error file";
+ rm->msg = "Can't find error file %s.";
+ rm->arg = cmd;
+ rm->sysmsg = 1;
+ return -1;
+ }
+ fstat(fd, &fi);
+ if((fi.st_size > 0) && (fi.st_size < 8192)) {
+ errmsg = (char *) MALLOC(fi.st_size + 1);
+ read(fd, errmsg, fi.st_size);
+ errmsg[fi.st_size] = '\0';
+ close(fd);
+ unlink(tfn);
+ rm->title = "Command execution failed";
+ rm->msg = "The command did not execute. "
+ "Here is the output:<p>\n<pre>\n%s\n</pre>\n";
+ rm->arg = errmsg;
+ rm->sysmsg = 0;
+ return -1;
+ }
+ else {
+ close(fd);
+ unlink(tfn);
+
+ rm->title = "Command execution failed";
+ rm->msg = "The command didn't execute, and it did not produce "
+ "any output. Run <code>%s</code> from the command "
+ "line and examine the output.\n";
+ rm->arg = cmd;
+ rm->sysmsg = 0;
+ return -1;
+ }
+ }
+ unlink(tfn);
+ return 0;
+ }
+#endif /* WIN32 */
+
+}
+
+
+
+/* This is basically copy_file from the install section, with the error
+ * reporting changed to match the admin stuff. Since some stuff depends
+ * on copy_file being the install version, I'll cheat and call this one
+ * cp_file. */
+#ifdef XP_UNIX
+
+#define COPY_BUFFER_SIZE 4096
+
+void cp_file(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)
+ report_error(FILE_ERROR, sfile, "Can't open file for reading.");
+
+ fstat(sfd, &fi);
+ if(!(S_ISREG(fi.st_mode))) {
+ close(sfd);
+ return;
+ }
+ len = fi.st_size;
+
+ if( (dfd = open(dfile, O_RDWR | O_CREAT | O_TRUNC, mode)) == -1)
+ report_error(FILE_ERROR, dfile, "Can't write to file.");
+
+ while(len) {
+ read_len = len>COPY_BUFFER_SIZE?COPY_BUFFER_SIZE:len;
+
+ if ( (read_len = read(sfd, copy_buffer, read_len)) == -1) {
+ report_error(FILE_ERROR, sfile, "Error reading file for copy.");
+ }
+
+ if ( write(dfd, copy_buffer, read_len) != read_len) {
+ report_error(FILE_ERROR, dfile, "Error writing file for copy.");
+ }
+
+ len -= read_len;
+ }
+ close(sfd);
+ close(dfd);
+}
+
+#else /* XP_WIN32 */
+void cp_file(char *sfile, char *dfile, int mode)
+{
+ HANDLE sfd, dfd, MapHandle;
+ PCHAR fp;
+ 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) {
+ report_error(FILE_ERROR, "Cannot open file for reading", sfile);
+ }
+ len = GetFileSize(sfd, NULL);
+ if( (dfd = CreateFile(dfile, GENERIC_READ | GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) {
+ report_error(FILE_ERROR, "Cannot open destination file for writing",
+ dfile);
+ }
+ if (len == 0)
+ return;
+ if( (MapHandle = CreateFileMapping(sfd, NULL, PAGE_READONLY,
+ 0, 0, NULL)) == NULL) {
+ report_error(FILE_ERROR, "Cannot create file mapping", sfile);
+ }
+ if (!(fp = MapViewOfFile(MapHandle, FILE_MAP_READ, 0, 0, 0))) {
+ report_error(FILE_ERROR, "Cannot map file %s", sfile);
+ }
+ while ( len) {
+ if(!WriteFile(dfd, fp, len, &BytesWritten, NULL)) {
+ report_error(FILE_ERROR, "Cannot write new file", dfile);
+ }
+ len -= BytesWritten;
+ fp += BytesWritten;
+ }
+
+ CloseHandle(sfd);
+ UnmapViewOfFile(fp);
+ CloseHandle(MapHandle);
+ FlushFileBuffers(dfd);
+ CloseHandle(dfd);
+}
+#endif
+
+int delete_file(char *path)
+{
+#ifdef XP_UNIX
+ return unlink(path);
+#else
+ return !(DeleteFile(path));
+#endif
+}
+
+void create_dir(char *dir, int mode)
+{
+ if ((dir == (char *) NULL) || (strlen(dir) == 0)) {
+ report_error(FILE_ERROR, "No directory is specified",
+ "Could not create a necessary directory.");
+ }
+
+ if(!file_exists(dir)) {
+#ifdef XP_UNIX
+ if(mkdir(dir, mode) == -1) {
+#else /* XP_WIN32 */
+ if(!CreateDirectory(dir, NULL)) {
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+#endif /* XP_WIN32 */
+ report_error(FILE_ERROR, dir,
+ "Could not create a necessary directory.");
+ }
+ }
+}
+
+#ifdef XP_UNIX
+SYS_FILE lf;
+#elif defined(XP_WIN32)
+HANDLE lf;
+#endif
+
+char *get_flock_path(void)
+{
+ char *result="";
+ char *port=getenv("SERVER_PORT");
+#ifdef XP_UNIX
+ result=(char *) MALLOC(strlen("/tmp/lock.%%s.")+strlen(port)+4);
+ sprintf(result, "/tmp/lock.%%s.%s", port);
+#endif
+ return result;
+}
+
+/* Open a file with locking, close a file with unlocking. */
+FILE *fopen_l(char *path, char *mode)
+{
+ FILE *f = fopen(path, mode);
+ char *lockpath;
+ char *sn=get_srvname(0);
+ char *flp=FILE_LOCK_PATH;
+
+ if(f == NULL) return NULL;
+ lockpath=(char *) MALLOC(strlen(sn)+strlen(flp)+16);
+ sprintf(lockpath, flp, sn);
+#ifdef XP_UNIX
+ if( (lf=system_fopenRW(lockpath)) == SYS_ERROR_FD)
+ report_error(FILE_ERROR, lockpath, "Could not open file.");
+ if(system_flock(lf)==IO_ERROR)
+ report_error(FILE_ERROR, lockpath, "Could not lock file.");
+#elif defined(XP_WIN32)
+ /* Using mutexes because if the CGI program dies, the mutex will be
+ * automatically released by the OS for another process to grab.
+ * Semaphores do not have this property; and if the CGI program crashes,
+ * the admin server would be effectively crippled.
+ */
+ if ( (lf = CreateMutex(NULL, 0, lockpath)) == NULL) {
+ report_error(FILE_ERROR, lockpath, "Could not create admin mutex.");
+ } else {
+ if ( WaitForSingleObject(lf, 60*1000) == WAIT_FAILED) {
+ report_error(FILE_ERROR, lockpath, "Unable to obtain mutex after 60 seconds.");
+ }
+ }
+#endif /* XP_UNIX */
+ return f;
+}
+
+void fclose_l(FILE *f)
+{
+ fclose(f);
+#ifdef XP_UNIX
+ if(system_ulock(lf)==IO_ERROR)
+ report_error(FILE_ERROR, NULL, "Could not unlock lock file.");
+ system_fclose(lf);
+#elif defined(XP_WIN32)
+ if (lf) {
+ ReleaseMutex(lf);
+ CloseHandle(lf);
+ }
+#endif /* XP_UNIX */
+}
+
+/* Ripped off from the client. (Sorry, Lou.) */
+/* */
+/* The magic set of 64 chars in the uuencoded data */
+unsigned char uuset[] = {
+'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T',
+'U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n',
+'o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7',
+'8','9','+','/' };
+
+int do_uuencode(unsigned char *src, unsigned char *dst, int srclen)
+{
+ int i, r;
+ unsigned char *p;
+
+/* To uuencode, we snip 8 bits from 3 bytes and store them as
+6 bits in 4 bytes. 6*4 == 8*3 (get it?) and 6 bits per byte
+yields nice clean bytes
+
+It goes like this:
+ AAAAAAAA BBBBBBBB CCCCCCCC
+turns into the standard set of uuencode ascii chars indexed by numbers:
+ 00AAAAAA 00AABBBB 00BBBBCC 00CCCCCC
+
+Snip-n-shift, snip-n-shift, etc....
+
+*/
+
+ for (p=dst,i=0; i < srclen; i += 3) {
+ /* Do 3 bytes of src */
+ register char b0, b1, b2;
+
+ b0 = src[0];
+ if (i==srclen-1)
+ b1 = b2 = '\0';
+ else if (i==srclen-2) {
+ b1 = src[1];
+ b2 = '\0';
+ }
+ else {
+ b1 = src[1];
+ b2 = src[2];
+ }
+
+ *p++ = uuset[b0>>2];
+ *p++ = uuset[(((b0 & 0x03) << 4) | ((b1 & 0xf0) >> 4))];
+ *p++ = uuset[(((b1 & 0x0f) << 2) | ((b2 & 0xc0) >> 6))];
+ *p++ = uuset[b2 & 0x3f];
+ src += 3;
+ }
+ *p = 0; /* terminate the string */
+ r = (unsigned char *)p - (unsigned char *)dst;/* remember how many we did */
+
+ /* Always do 4-for-3, but if not round threesome, have to go
+ clean up the last extra bytes */
+
+ for( ; i != srclen; i--)
+ *--p = '=';
+
+ return r;
+}
+
+char *alert_word_wrap(char *str, int width, char *linefeed)
+{
+ char *ans = NULL;
+ int counter=0;
+ int lsc=0, lsa=0;
+ register int strc=0, ansc=0;
+ register int x=0;
+
+ /* assume worst case */
+ ans = (char *) MALLOC((strlen(str)*strlen(linefeed))+32);
+
+ for(strc=0, ansc=0; str[strc]; /*none*/) {
+ if(str[strc]=='\n') {
+ counter=0;
+ lsc=0, lsa=0;
+ for(x=0; linefeed[x]; x++) {
+ ans[ansc++]=linefeed[x];
+ }
+ strc++;
+ } else if(str[strc]=='\r') {
+ strc++;
+ } else if(str[strc]=='\\') {
+ ans[ansc++]='\\';
+ ans[ansc++]=strc++;
+ } else {
+ if(counter==width) {
+ if(lsc && lsa) {
+ strc=lsc;
+ ansc=lsa;
+
+ counter=0;
+ lsc=0, lsa=0;
+ for(x=0; linefeed[x]; x++) {
+ ans[ansc++]=linefeed[x];
+ }
+ strc++;
+ } else {
+ /* else, you're a loser, I'm breaking your big word anyway */
+ counter=0;
+ lsc=0, lsa=0;
+ for(x=0; linefeed[x]; x++) {
+ ans[ansc++]=linefeed[x];
+ }
+ strc++;
+ }
+ } else {
+ if(str[strc] == ' ') {
+ lsc=strc;
+ lsa=ansc;
+ }
+ ans[ansc++]=str[strc++];
+ counter++;
+ }
+ }
+ }
+ ans[ansc]='\0';
+ return ans;
+}
+
+void remove_directory(char *path)
+{
+ struct stat finfo;
+ char **dirlisting;
+ register int x=0;
+ int stat_good = 0;
+ char *fullpath = NULL;
+
+#ifdef XP_UNIX
+ stat_good = (lstat(path, &finfo) == -1 ? 0 : 1);
+#else /* WIN32 */
+ stat_good = (stat(path, &finfo) == -1 ? 0 : 1);
+#endif /* XP_UNIX */
+
+ if(!stat_good) return;
+
+ if(S_ISDIR(finfo.st_mode)) {
+ dirlisting = list_directory(path,1);
+ if(!dirlisting) return;
+
+ for(x=0; dirlisting[x]; x++) {
+ fullpath = (char *) MALLOC(strlen(path) +
+ strlen(dirlisting[x]) + 4);
+ sprintf(fullpath, "%s%c%s", path, FILE_PATHSEP, dirlisting[x]);
+#ifdef XP_UNIX
+ stat_good = (lstat(fullpath, &finfo) == -1 ? 0 : 1);
+#else /* WIN32 */
+ stat_good = (stat(fullpath, &finfo) == -1 ? 0 : 1);
+#endif /* XP_UNIX */
+ if(!stat_good) continue;
+ if(S_ISDIR(finfo.st_mode)) {
+ remove_directory(fullpath);
+ } else {
+ fprintf(stdout, "<i>Removing file</i> "
+ "<code>%s</code><br>\n", fullpath);
+ unlink(fullpath);
+ }
+ FREE(fullpath);
+ }
+ fprintf(stdout, "<i>Removing directory</i> "
+ "<code>%s</code><br>\n", path);
+#ifdef XP_UNIX
+ rmdir(path);
+#else /* XP_WIN32 */
+ RemoveDirectory(path);
+#endif /* XP_WIN32 */
+ } else {
+ fprintf(stdout, "<i>Removing file</i> <code>%s</code><br>\n", path);
+ unlink(path);
+ }
+ return;
+}
+
+int str_flag_to_int(char *str_flag)
+{
+ if (!str_flag)
+ return -1;
+ if (!strcmp(str_flag, "1"))
+ return 1;
+ return 0;
+}
+
+/*
+ * get_ip_and_mask - function to take something that may be an IP Address
+ * and netmaks, and validate it. It takes two possible
+ *
+ * Parmaters: char *candidate
+ *
+ * Returns NULL if it isn't a valid IP address and mask. It returns
+ * the IP address and mask in the form "iii.iii.iii.iii mmm.mmm.mmm.mmm"
+ * if it is valid. This is in a string dynamicly allocated in this
+ * function.
+ *
+ * Processing: the candidate is assumed to be in one of
+ * these two formats:
+ *
+ * 1. "iii.iii.iii.iii" (returns: "iii.iii.iii.iii 255.255.255.255")
+ * 2. "iii.iii.iii.iii mmm.mmm.mmm.mmm"
+ * 3. "iii.*", "iii.iii.*", or "iii.iii.iii.*"
+ *
+ * The rules are:
+ * I. If it has a space in it, it is assumed to be the delimiter in
+ * format 2.
+ * II. If it has a "*" in it, it's assumed to be format 3.
+ * III. If it's in format 3, the net mask returned is:
+ * 255.0.0.0, 255.255.0.0, or 255.255.255.0 respectivly,
+ * and parts of the address right of the * is replaced with 0s.
+ * IV. We use inet_addr on the pieces to validate them.
+ *
+ *
+ */
+
+char *get_ip_and_mask(char *candidate)
+{
+ char work[BIG_LINE];
+
+ char *p;
+ char *result = NULL;
+ int len;
+ int dots = 0;
+ int i;
+
+ if (candidate && strlen(candidate) < (unsigned) BIG_LINE) {
+
+ if ((p = strchr(candidate, ' '))) {
+ len = p-candidate+1;
+ memcpy(work, candidate, len);
+ work[len] = '\0';
+ if (inet_addr(work) != -1) {
+ len = strlen(candidate)-strlen(p)-1;
+ if (len > 0) {
+ memcpy(work, p+1, len);
+ work[len] = '\0';
+ if (inet_addr(work) != -1) {
+ result = strdup(candidate);
+ }
+ }
+ }
+ }
+ else if ((p = strchr(candidate, '*')) &&
+ (p-candidate > 1 ) &&
+ (*(p-1) == '.') ) {
+ memset(work, 0, BIG_LINE);
+ for (i=0; candidate[i]!='*'; ++i) {
+ if (candidate[i+1] != '*')
+ work[i] = candidate[i];
+ if (candidate[i] == '.')
+ ++dots;
+ }
+ if (dots == 1 || dots == 2 || dots == 3) {
+ for (i=0; i<4-dots; ++i) {
+ strcat(work, ".0");
+ }
+ if (inet_addr(work) != -1) {
+ strcat(work, " ");
+ p = &work[strlen(work)];
+ for (i=0; i<dots; ++i) {
+ if (i==0)
+ strcat(work, "255");
+ else
+ strcat(work, ".255");
+ }
+ for (i=0; i<4-dots; ++i) {
+ strcat(work, ".0");
+ }
+ if (inet_addr(p) != -1) {
+ result = strdup(work);
+ }
+ }
+ }
+ }
+ else {
+ if (inet_addr(candidate) != -1) {
+ strcpy(work, candidate);
+ strcat(work, " 255.255.255.255");
+ result = strdup(work);
+ }
+ }
+ }
+ else
+ result = NULL;
+
+ return result;
+}
+
+/* do fgets with a filebuffer *, instead of a File *. Can't use util_getline
+ because it complains if the line is too long.
+ It does throw away <CR>s, though.
+ */
+NSAPI_PUBLIC char *system_gets( char *line, int size, filebuffer *fb )
+{
+ int c;
+ int i = 0;
+
+ while ( --size ) {
+ switch ( c = filebuf_getc( fb ) ) {
+ case IO_EOF:
+ line[i] = '\0';
+ return i ? line : NULL;
+ case LF:
+ line[i] = c;
+ line[i+1] = '\0';
+ return line; /* got a line, and it fit! */
+ case IO_ERROR:
+ return NULL;
+ case CR:
+ ++size;
+ break;
+ default:
+ line[i++] = c;
+ break;
+ }
+ }
+ /* if we got here, then we overran the buffer size */
+ line[i] = '\0';
+ return line;
+}
+
+#ifndef WIN32
+
+/* make a zero length file, no matter how long it was before */
+NSAPI_PUBLIC int
+system_zero( SYS_FILE f )
+{
+ ftruncate( PR_FileDesc2NativeHandle( f ), 0 );
+ return 0;
+}
+
+#endif
+
+/***********************************************************************
+** FUNCTION: cookieValue
+** DESCRIPTION:
+** Get the current value of the cookie variable
+** INPUTS: var - the name of the cookie variable
+** val - if non-NULL, set the in-memory copy of the var
+** OUTPUTS: None
+** RETURN: NULL if the var doesn't exist, else the value
+** SIDE EFFECTS:
+** Eats memory
+** RESTRICTIONS:
+** Don't screw around with the returned string, if anything else wants
+** to use it.
+** MEMORY: This is a memory leak, so only use it in CGIs
+** ALGORITHM:
+** If it's never been called, build a memory structure of the
+** cookie variables.
+** Look for the passed variable, and return its value, or NULL
+***********************************************************************/
+
+NSAPI_PUBLIC char *
+cookieValue( char *var, char *val )
+{
+ static char **vars = NULL;
+ static char **vals = NULL;
+ static int numVars = -1;
+ int i;
+
+ if ( numVars == -1 ) { /* first time, init the structure */
+ char *cookie = getenv( "HTTP_COOKIE" );
+
+ if ( cookie && *cookie ) {
+ int len = strlen( cookie );
+ int foundVal = 0;
+
+ cookie = STRDUP( cookie );
+ numVars = 0;
+ vars = (char **)MALLOC( sizeof( char * ) );
+ vals = (char **)MALLOC( sizeof( char * ) );
+ vars[0] = cookie;
+ for ( i = 0 ; i < len ; ++i ) {
+ if ( ( ! foundVal ) && ( cookie[i] == '=' ) ) {
+ vals[numVars++] = cookie + i + 1;
+ cookie[i] = '\0';
+ foundVal = 1;
+ } else if ( ( cookie[i] == ';' ) && ( cookie[i+1] == ' ' ) ) {
+ cookie[i] = '\0';
+ vals = (char **) REALLOC( vals,
+ sizeof( char * ) * ( numVars + 1 ) );
+ vars = (char **) REALLOC( vars,
+ sizeof( char * ) * ( numVars + 1 ) );
+ vars[numVars] = cookie + i + 2;
+ i += 2;
+ foundVal = 0;
+ }
+ }
+ } else { /* no cookie, no vars */
+ numVars = 0;
+ }
+ }
+ for ( i = 0 ; i < numVars ; ++i ) {
+ if ( strcmp( vars[i], var ) == 0 ) {
+ if ( val ) {
+ vals[i] = STRDUP( val );
+ } else {
+ return vals[i];
+ }
+ }
+ }
+ return NULL;
+}
+
+/***********************************************************************
+** FUNCTION: jsEscape
+** DESCRIPTION:
+** Escape the usual suspects, so the parser javascript parser won't eat them
+** INPUTS: src - the string
+** OUTPUTS: NONE
+** RETURN: A malloced string, containing the escaped src
+** SIDE EFFECTS:
+** None, except for more memory being eaten
+** RESTRICTIONS:
+** None
+** MEMORY: One Malloc, you should free this if you care
+***********************************************************************/
+
+NSAPI_PUBLIC char *
+jsEscape( char *src )
+{
+ int needsEscaping = 0;
+ int i;
+ char *dest;
+
+ for ( i = 0 ; src[i] ; ++i ) {
+ if ( src[i] == '\\' || src[i] == '\'' || src[i] == '"' ) {
+ ++needsEscaping;
+ }
+ }
+ dest = (char *)MALLOC( i + needsEscaping + 1 );
+ for ( i = 0 ; *src ; ++src ) {
+ if ( ( *src == '\\' ) || ( *src == '\'' ) || ( *src == '"' ) ) {
+ dest[i++] = '\\'; /* escape */
+ }
+ dest[i++] = *src;
+ }
+ dest[i] = '\0';
+ return dest;
+}
+
+/***********************************************************************
+** FUNCTION: jsPWDialogSrc
+** DESCRIPTION:
+** Put the source to the passwordDialog JavaScript function out.
+** INPUTS: inScript - if true, don't put <SCRIPT> stuff out
+** otherJS - if nonNULL, other javascript to execute
+** OUTPUTS: None
+** RETURN: None
+** SIDE EFFECTS:
+** clogs up stdout
+** RESTRICTIONS:
+** Don't use this outside of a CGI, or before the Content-type:
+** MEMORY: No memory change
+** ALGORITHM:
+** @+@What's really going on?
+***********************************************************************/
+
+NSAPI_PUBLIC void
+jsPWDialogSrc( int inScript, char *otherJS )
+{
+ static int srcSpewed = 0;
+
+ otherJS = otherJS ? otherJS : "";
+
+ if ( ! inScript ) {
+ fprintf( stdout, "<SCRIPT LANGUAGE=\""MOCHA_NAME"\">\n" );
+ }
+ if ( ! srcSpewed ) {
+ srcSpewed = 1;
+ fprintf( stdout, "function passwordDialog( prompt, element ) {\n"
+ " var dlg = window.open( '', 'dialog', 'height=60,width=500' );\n"
+ " dlg.document.write(\n"
+ " '<form name=f1 onSubmit=\"opener.document.'\n"
+ " + element + '.value = goo.value; window.close(); "
+ "%s; return false;\">',\n"
+ " prompt, '<input type=password name=goo></form>' );\n"
+ " dlg.document.f1.goo.focus();\n"
+ " dlg.document.close();\n"
+ "}\n", otherJS );
+ }
+ if ( ! inScript ) {
+ fprintf( stdout, "</SCRIPT>\n" );
+ }
+}
+
+static int adm_initialized=0;
+
+/* Initialize NSPR for all the base functions we use */
+NSAPI_PUBLIC int ADM_Init(void)
+{
+ if(!adm_initialized) {
+ NSPR_INIT("AdminPrograms");
+ adm_initialized=1;
+ }
+ return 0;
+}
+
+
+#ifdef XP_UNIX
+/*
+ * This function will return the SuiteSpot user id and group id used to
+ * recommend that Netscape Servers to run as. Any line starts with '#'
+ * is treated as comment. It looks for SuiteSpotUser/SuiteSpotGroup
+ * name/value pair.
+ *
+ * It returns 0 when success and allocate storage for user and group.
+ * returns -1 when only SuiteSpot user id is found.
+ * returns -2 when only SuiteSpot group id is found.
+ * returns -3 when NO SuiteSpot user and group is found.
+ * returns -4 when fails to open <server_root>/install/ssusers.conf
+ */
+NSAPI_PUBLIC int ADM_GetUXSSid(char *sroot, char **user, char **group)
+{
+ int foundUser, foundGroup;
+ char fn[BIG_LINE];
+ char line[BIG_LINE];
+ FILE *f;
+
+ foundUser = 0;
+ foundGroup = 0;
+ *user = (char *) NULL;
+ *group = (char *) NULL;
+
+ sprintf(fn, "%s/install/ssusers.conf", sroot);
+ if (f = fopen(fn, "r")) {
+ while (fgets(line, sizeof(line), f)) {
+ if (line[0] == '#') {
+ continue;
+ }
+ if (!strncmp(line, "SuiteSpotUser", strlen("SuiteSpotUser"))) {
+ char *ptr1;
+ ptr1 = line + strlen("SuiteSpotUser");
+ while ((*ptr1 == '\t') || (*ptr1 == ' ')) {
+ ptr1++;
+ }
+ if ((strlen(ptr1) > 0) && (*user == (char *) NULL)) {
+ *user = (char *) MALLOC(strlen(ptr1)+1);
+ if (ptr1[strlen(ptr1)-1] == '\n') {
+ ptr1[strlen(ptr1)-1] = '\0';
+ }
+ strcpy(*user, ptr1);
+ }
+ foundUser = 1;
+ continue;
+ }
+ if (!strncmp(line, "SuiteSpotGroup", strlen("SuiteSpotGroup"))) {
+ char *ptr1;
+ ptr1 = line + strlen("SuiteSpotGroup");
+ while ((*ptr1 == '\t') || (*ptr1 == ' ')) {
+ ptr1++;
+ }
+ if ((strlen(ptr1) > 0) && (*group == (char *) NULL)) {
+ *group = (char *) MALLOC(strlen(ptr1)+1);
+ if (ptr1[strlen(ptr1)-1] == '\n') {
+ ptr1[strlen(ptr1)-1] = '\0';
+ }
+ strcpy(*group, ptr1);
+ }
+ foundGroup = 1;
+ continue;
+ }
+ }
+ fclose(f);
+ } else {
+ return(-4);
+ }
+
+ if (foundUser && foundGroup) {
+ return(0);
+ } else if (foundUser) {
+ return(-1);
+ } else if (foundGroup) {
+ return(-2);
+ } else {
+ return(-3);
+ }
+}
+#endif /* XP_UNIX */
diff --git a/lib/libnt/Makefile b/lib/libnt/Makefile
new file mode 100644
index 00000000..2f12fe5b
--- /dev/null
+++ b/lib/libnt/Makefile
@@ -0,0 +1,27 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#! gmake
+
+DEPTH = ../..
+
+CSRCS = info.c \
+ path.c \
+ pmddeml.c \
+ registry.c \
+ service.c \
+ tcpip.c \
+ $(NULL)
+
+OBJS = $(CSRCS:.c=.o)
+
+LIBRARY = libnt.$(LIB_SUFFIX)
+
+include $(DEPTH)/config/rules.mk
+
+export:: $(TARGETS)
+ $(INSTALL) -m 444 $(LIBRARY) $(DIST)/lib
diff --git a/lib/libnt/info.c b/lib/libnt/info.c
new file mode 100644
index 00000000..618b95c7
--- /dev/null
+++ b/lib/libnt/info.c
@@ -0,0 +1,81 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <windows.h>
+#include "nt/ntos.h"
+
+OS_TYPE NS_WINAPI INFO_GetOperatingSystem ()
+{
+ OSVERSIONINFO versionInfo;
+ versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx( &versionInfo );
+
+ switch ( versionInfo.dwPlatformId ) {
+ case VER_PLATFORM_WIN32s:
+ return OS_WIN32S;
+ case VER_PLATFORM_WIN32_WINDOWS:
+ return OS_WIN95;
+ case VER_PLATFORM_WIN32_NT:
+ return OS_WINNT;
+ default:
+ break;
+ }
+ return OS_UNKNOWN;
+}
+DWORD NS_WINAPI INFO_GetOSMajorVersion ()
+{
+ OSVERSIONINFO versionInfo;
+ versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx( &versionInfo );
+
+ return versionInfo.dwMajorVersion;
+}
+DWORD NS_WINAPI INFO_GetOSMinorVersion ()
+{
+ OSVERSIONINFO versionInfo;
+ versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx( &versionInfo );
+
+ return versionInfo.dwMinorVersion;
+}
+DWORD NS_WINAPI INFO_GetOSServicePack ()
+{
+ OSVERSIONINFO versionInfo;
+ char * servicePackString = "Service Pack ";
+ int servicePackStringLng = strlen(servicePackString);
+ int servicePackNumber = 0;
+
+ versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx( &versionInfo );
+ if ( strncmp ( versionInfo.szCSDVersion, servicePackString, servicePackStringLng ) == 0 )
+ servicePackNumber = atoi ( &versionInfo.szCSDVersion[servicePackStringLng] );
+
+ return servicePackNumber;
+}
+void NS_WINAPI OS_GetComputerName (LPTSTR computerName, int nComputerNameLength )
+{
+ DWORD computerNameLength = nComputerNameLength;
+ GetComputerName( computerName, &computerNameLength );
+}
+
+PROCESSOR_TYPE NS_WINAPI OS_GetProcessor ()
+{
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo( &systemInfo);
+
+ switch ( systemInfo.wProcessorArchitecture ) {
+ case PROCESSOR_ARCHITECTURE_INTEL:
+ return PROCESSOR_I386;
+ case PROCESSOR_ARCHITECTURE_MIPS:
+ return PROCESSOR_MIPS;
+ case PROCESSOR_ARCHITECTURE_ALPHA:
+ return PROCESSOR_ALPHA;
+ case PROCESSOR_ARCHITECTURE_PPC:
+ return PROCESSOR_PPC;
+ default:
+ break;
+ }
+ return PROCESSOR_UNKNOWN;
+}
diff --git a/lib/libnt/path.c b/lib/libnt/path.c
new file mode 100644
index 00000000..6691bc98
--- /dev/null
+++ b/lib/libnt/path.c
@@ -0,0 +1,266 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/***********************************************************
+ * Path functions - removing ../ from path
+ **********************************************************/
+#include <windows.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <io.h> /* For _findfirst */
+#include <direct.h> /* For _rmdir */
+#include <errno.h>
+#include "nt/ntos.h"
+
+DWORD NS_WINAPI
+PATH_RemoveRelative ( char * path )
+{
+ char * src;
+ char * dst;
+
+ src = path;
+ dst = path;
+ while ( *src ) {
+ if ( *src == '.' ) {
+ if ( *(src+1) == '.' ) {
+ /* strip off the "../" */
+ src += 2;
+
+ /* back off least significant directory */
+ dst--;
+ if ( ( *dst == '\\' ) || ( *dst == '/' ) )
+ *dst--;
+ while ( dst > path ) {
+ if ( ( *dst == '\\' ) || ( *dst == '/' ) )
+ break;
+ dst--;
+ }
+ } else {
+ // remove single "."
+ }
+
+ } else
+ *dst++ = *src++;
+ }
+ *dst = '\0';
+
+ return TRUE;
+}
+DWORD NS_WINAPI
+PATH_ConvertNtSlashesToUnix( LPCTSTR lpszNtPath, LPSTR lpszUnixPath )
+{
+ if ( lpszNtPath == NULL )
+ return 0;
+
+ /* create reverse slashes and escape them */
+ while ( *lpszNtPath ) {
+ if ( *lpszNtPath == '\\' )
+ *lpszUnixPath = '/';
+ else
+ *lpszUnixPath = *lpszNtPath;
+ lpszNtPath++;
+ lpszUnixPath++;
+ }
+ *lpszUnixPath = '\0';
+ return 0;
+}
+
+static DWORD
+PATH_DeleteRecursivelyFoundFile ( char * fullFileName, char * path, char * fileName )
+{
+ if ( strcmp ( fileName, "." ) == 0)
+ return TRUE;
+
+ if ( strcmp ( fileName, ".." ) == 0)
+ return TRUE;
+
+ strcpy ( fullFileName, path );
+ strcat ( fullFileName, "\\" );
+ strcat ( fullFileName, fileName );
+ return PATH_DeleteRecursively ( fullFileName );
+}
+
+/* if the path specified is a file name, the file is deleted
+ * If the path specifies a directory, the directory is deleted
+ */
+DWORD NS_WINAPI
+PATH_DeleteRecursively ( char * path )
+{
+ int result;
+ unsigned short fileStatus;
+ struct _stat buf;
+ struct _finddata_t fileFound;
+ long hFile;
+ DWORD retStatus = TRUE;
+ char fullFileName[_MAX_PATH];
+ int error;
+
+ /* Check if statistics are valid: */
+ result = _stat( path, &buf );
+ if( result != 0 )
+ return TRUE; // file or directory does not exist
+
+ fileStatus = buf.st_mode & _S_IFMT;
+
+ /* check if regular file */
+ if ( fileStatus & _S_IFREG ) {
+ if ( remove ( path ) == -1 ) {
+ error = errno;
+ switch ( error ) {
+ case ENOENT:
+ break;
+
+ case EACCES:
+ break;
+
+ default:
+ break;
+ }
+
+ return FALSE;
+ }
+ return TRUE;
+ }
+ if ( (fileStatus & _S_IFDIR) == 0 )
+ return FALSE;
+
+
+ /* path contains a directory, delete all files recursively */
+ /* Find first .c file in current directory */
+ strcpy ( fullFileName, path );
+ strcat ( fullFileName, "\\*.*");
+ if( (hFile = _findfirst( fullFileName, &fileFound )) != -1L ) { /* directory contain files? */
+ if ( !PATH_DeleteRecursivelyFoundFile ( fullFileName, path, fileFound.name ) )
+ retStatus = FALSE;
+
+ /* Find the rest of the .c files */
+ while( _findnext( hFile, &fileFound ) == 0 ) {
+ if ( !PATH_DeleteRecursivelyFoundFile ( fullFileName, path, fileFound.name ) )
+ retStatus = FALSE;
+ }
+ _findclose( hFile );
+ }
+
+ /* remove the directory, now that it is empty */
+ if ( _rmdir( path ) == -1 )
+ retStatus = FALSE;
+ return retStatus;
+}
+/* GetNextFileInDirectory - gets next file in the directory
+ * Set hFile to zero, when you call it. The routine returns the
+ * next value for hFile. When the routine returns NULL, there is
+ * no more files
+ *
+ */
+DWORD NS_WINAPI
+PATH_GetNextFileInDirectory ( long hFile, char * path, char * lpFileName )
+{
+ int result;
+ unsigned short fileStatus;
+ struct _stat buf;
+ struct _finddata_t fileFound;
+ DWORD retStatus = TRUE;
+ char fullFileName[_MAX_PATH];
+
+ if ( hFile == 0 ) {
+ /* Check if statistics are valid: */
+ result = _stat( path, &buf );
+ if( result != 0 )
+ return 0; // file or directory does not exist
+
+ fileStatus = buf.st_mode & _S_IFMT;
+ if ( (fileStatus & _S_IFDIR) == 0 )
+ return 0;
+
+
+ /* path contains a directory, delete all files recursively */
+ /* Find first .c file in current directory */
+ strcpy ( fullFileName, path );
+ strcat ( fullFileName, "\\*.*");
+ if( (hFile = _findfirst( fullFileName, &fileFound )) == -1L )
+ return 0;
+ if ( ( strcmp ( fileFound.name , "." ) != 0)
+ && ( strcmp ( fileFound.name , ".." ) != 0) ) {
+ strcpy ( lpFileName, fileFound.name );
+ return hFile;
+ }
+ }
+
+ /* Find the rest of the .c files */
+ while( _findnext( hFile, &fileFound ) == 0 ) {
+ if ( ( strcmp ( fileFound.name , "." ) != 0)
+ && ( strcmp ( fileFound.name , ".." ) != 0) ) {
+ strcpy ( lpFileName, fileFound.name );
+ return hFile;
+ }
+ }
+
+ _findclose( hFile );
+ return 0;
+}
+/*---------------------------------------------------------------------------*\
+ *
+ * Function: PATH_GetNextSubDirectory
+ *
+ * Purpose: Gets next sub directory in the path
+ *
+ * Input:
+ * hFile: set to zero first time called; use return value for subsequent calls
+ * path: directory containing sub directories
+ * lpSubDirectoryName: buffer to store sub directorie name
+ * lpSubDirectoryPrefix: chars to exactly match begining of directory name
+ *
+ * Returns:
+ * hFile to be used on subsequent call (0, if no more directories)
+ *
+ * Comments:
+\*---------------------------------------------------------------------------*/
+DWORD NS_WINAPI
+PATH_GetNextSubDirectory( long hFile, char * path, char * lpSubDirectoryName, char * lpSubDirectoryPrefix )
+{
+ int result;
+ unsigned short fileStatus;
+ struct _stat buf;
+ char * subDirectoryPrefix;
+ char * p;
+ char fullFileName[_MAX_PATH];
+ BOOL bSubDirectoryFound;
+
+ do {
+ hFile = PATH_GetNextFileInDirectory ( hFile, path, lpSubDirectoryName );
+ if ( hFile == 0 )
+ return 0;
+
+ /* Check if file is a directory */
+ strcpy ( fullFileName, path );
+ strcat ( fullFileName, "\\" );
+ strcat ( fullFileName, lpSubDirectoryName );
+ result = _stat( fullFileName, &buf );
+ if( result == 0 ) {
+ fileStatus = buf.st_mode & _S_IFMT;
+ if ( (fileStatus & _S_IFDIR) == _S_IFDIR ) {
+
+ /* check if sub directory matches prefix */
+ bSubDirectoryFound = TRUE;
+ if ( lpSubDirectoryPrefix ) {
+ p = lpSubDirectoryName;
+ subDirectoryPrefix = lpSubDirectoryPrefix;
+ while ( *subDirectoryPrefix ) {
+ if ( *subDirectoryPrefix++ != *p++ ) {
+ bSubDirectoryFound = FALSE;
+ break;
+ }
+ }
+ }
+ if ( bSubDirectoryFound )
+ return hFile;
+ }
+ }
+ } while ( hFile );
+
+ return 0; // no more sub directories
+}
+
diff --git a/lib/libnt/pmddeml.c b/lib/libnt/pmddeml.c
new file mode 100644
index 00000000..cee541a1
--- /dev/null
+++ b/lib/libnt/pmddeml.c
@@ -0,0 +1,375 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+/****************************************************************************
+ PROGRAM: pmddeml.c
+
+ PURPOSE: DDEML interface with ProgMan
+
+****************************************************************************/
+
+#include <windows.h> // required for all Windows applications
+#include <ddeml.h> // required for DDEML
+#include <stdio.h> // required for strcpy and strlen
+#include "nt/ntos.h" // specific to this program
+
+BOOL PMDDEML_SendShellCommand (DWORD idInst, LPSTR lpCommand);
+
+HDDEDATA CALLBACK PMDDEML_DdeCallback( UINT uType, // transaction type
+ UINT uFmt, // clipboard data format
+ HCONV hconv, // handle of the conversation
+ HSZ hsz1, // handle of a string
+ HSZ hsz2, // handle of a string
+ HDDEDATA hdata,// handle of a global memory object
+ DWORD dwData1, // transaction-specific data
+ DWORD dwData2 // transaction-specific data
+ );
+/****************************************************************************
+ FUNCTION: PMDDEML_Open()
+
+ PURPOSE: Open PMDDEML interface
+
+ PARAMETERS:
+
+ RETURNS:
+ DWORD handle used in subsequent calls
+****************************************************************************/
+
+DWORD PMDDEML_Open ( void )
+{
+ DWORD idInst = 0L; // instance identifier
+
+ // register this app with the DDEML
+ if (DdeInitialize(&idInst, // receives instance ID
+ (PFNCALLBACK)PMDDEML_DdeCallback, // address of callback function
+ APPCMD_CLIENTONLY, // this is a client app
+ 0L)) // reserved
+ return 0;
+ return idInst;
+}
+/****************************************************************************
+ FUNCTION: PMDDEML_Close()
+
+ PURPOSE: Closes PMDDEML interface
+
+ PARAMETERS:
+ DWORD idInst handle returned by PMDDEML_Open
+
+ RETURNS:
+ TRUE, if successful
+****************************************************************************/
+
+BOOL PMDDEML_Close ( DWORD idInst )
+{
+ // free all DDEML resources associated with this app
+ return DdeUninitialize ( idInst );
+}
+/****************************************************************************
+ FUNCTION: PMDDEML_CreateProgramManagerGroup()
+
+ PURPOSE: Creates a program group
+
+ PARAMETERS:
+ DWORD idInst handle returned by PMDDEML_Open
+ LPCTSTR lpszGroupNamee name of group
+
+ RETURNS:
+ TRUE, if successful
+****************************************************************************/
+
+BOOL PMDDEML_CreateProgramManagerGroup ( DWORD idInst, LPCTSTR lpszGroupName )
+{
+ char szDDEMsg[256]; // instance identifier
+
+ if ( lpszGroupName == NULL )
+ return FALSE;
+
+ sprintf ( szDDEMsg, "[CreateGroup(%s)]", lpszGroupName );
+
+ if ( !PMDDEML_SendShellCommand(idInst, (LPSTR)szDDEMsg ) )
+ return FALSE;
+ return TRUE;
+}
+/****************************************************************************
+ FUNCTION: PMDDEML_DeleteProgramManagerGroup()
+
+ PURPOSE: Deletes a program group
+
+ PARAMETERS:
+ DWORD idInst handle returned by PMDDEML_Open
+ LPCTSTR lpszGroupNamee name of group
+
+ RETURNS:
+ TRUE, if successful
+****************************************************************************/
+
+BOOL PMDDEML_DeleteProgramManagerGroup ( DWORD idInst, LPCTSTR lpszGroupName )
+{
+ char szDDEMsg[256]; // instance identifier
+
+ if ( lpszGroupName == NULL )
+ return FALSE;
+
+ sprintf ( szDDEMsg, "[DeleteGroup(%s)]", lpszGroupName );
+
+ if ( !PMDDEML_SendShellCommand(idInst, (LPSTR)szDDEMsg ) )
+ return FALSE;
+ return TRUE;
+}
+
+BOOL PMDDEML_DeleteProgramCommonManagerGroup ( DWORD idInst,
+ LPCTSTR lpszGroupName )
+{
+ char szDDEMsg[256]; // instance identifier
+
+ if ( lpszGroupName == NULL )
+ return FALSE;
+
+ sprintf ( szDDEMsg, "[DeleteGroup(%s,1)]", lpszGroupName );
+
+ if ( !PMDDEML_SendShellCommand(idInst, (LPSTR)szDDEMsg ) )
+ return FALSE;
+ return TRUE;
+}
+
+/****************************************************************************
+ FUNCTION: PMDDEML_ShowProgramManagerGroup()
+
+ PURPOSE: Deletes a program group
+
+ PARAMETERS:
+ DWORD idInst handle returned by PMDDEML_Open
+ LPCTSTR lpszGroupNamee name of group
+
+ RETURNS:
+ TRUE, if successful
+****************************************************************************/
+
+BOOL PMDDEML_ShowProgramManagerGroup ( DWORD idInst, LPCTSTR lpszGroupName )
+{
+ char szDDEMsg[256]; // instance identifier
+
+ if ( lpszGroupName == NULL )
+ return FALSE;
+
+ sprintf ( szDDEMsg, "[ShowGroup(%s,1)]", lpszGroupName );
+
+ if ( !PMDDEML_SendShellCommand(idInst, (LPSTR)szDDEMsg ) )
+ return FALSE;
+ return TRUE;
+}
+
+BOOL PMDDEML_ShowProgramManagerCommonGroup ( DWORD idInst,
+ LPCTSTR lpszGroupName )
+{
+ char szDDEMsg[256]; // instance identifier
+
+ if ( lpszGroupName == NULL )
+ return FALSE;
+
+ sprintf ( szDDEMsg, "[ShowGroup(%s,1,1)]", lpszGroupName );
+
+ if ( !PMDDEML_SendShellCommand(idInst, (LPSTR)szDDEMsg ) )
+ return FALSE;
+ return TRUE;
+}
+
+/****************************************************************************
+ FUNCTION: PMDDEML_AddIconToProgramManagerGroup()
+
+ PURPOSE: Deletes icon a program group
+
+ PARAMETERS:
+ DWORD idInst handle returned by PMDDEML_Open
+ LPCTSTR lpszCmdLine title of icon in group
+ LPCTSTR lpszTitle title of icon in group
+ LPCTSTR lpszWorkingDir title of icon in group
+ BOOL bReplace True, if icon should be replaced
+
+ RETURNS:
+ TRUE, if successful
+****************************************************************************/
+
+BOOL PMDDEML_AddIconToProgramManagerGroup ( DWORD idInst, LPCTSTR lpszCmdLine,
+ LPCTSTR lpszTitle, LPCTSTR lpszIconPath, LPCTSTR lpszWorkingDir, BOOL bReplace )
+{
+ char szDDEMsg[256]; // instance identifier
+
+ if ( ( lpszCmdLine == NULL ) || ( lpszTitle == NULL ) || ( lpszWorkingDir == NULL ) )
+ return FALSE;
+
+ if ( bReplace ) {
+ sprintf ( szDDEMsg, "[ReplaceItem(%s)]", lpszTitle );
+ PMDDEML_SendShellCommand(idInst, (LPSTR)szDDEMsg );
+ }
+
+ sprintf ( szDDEMsg, "[AddItem(%s,%s,%s,,,,%s)]", lpszCmdLine, lpszTitle,
+ lpszIconPath, lpszWorkingDir );
+
+ if ( !PMDDEML_SendShellCommand(idInst, (LPSTR)szDDEMsg ) )
+ return FALSE;
+ return TRUE;
+}
+
+/****************************************************************************
+ FUNCTION: PMDDEML_DeleteIconInProgramManagerGroup()
+
+ PURPOSE: Deletes icon a program group
+
+ PARAMETERS:
+ DWORD idInst handle returned by PMDDEML_Open
+ LPCTSTR lpszTitle title of icon in group
+
+ RETURNS:
+ TRUE, if successful
+****************************************************************************/
+
+BOOL PMDDEML_DeleteIconInProgramManagerGroup ( DWORD idInst, LPCTSTR lpszTitle )
+{
+ char szDDEMsg[256]; // instance identifier
+
+ if ( lpszTitle == NULL )
+ return FALSE;
+
+ sprintf ( szDDEMsg, "[DeleteItem(%s)]", lpszTitle );
+
+ if ( !PMDDEML_SendShellCommand(idInst, (LPSTR)szDDEMsg ) )
+ return FALSE;
+ return TRUE;
+}
+
+/****************************************************************************
+ FUNCTION: PMDDEML_DdeCallback()
+
+ PURPOSE: Processes messages for DDEML conversation
+
+ PARAMETERS:
+ UINT uType, // transaction type
+ UINT uFmt, // clipboard data format
+ HCONV hconv, // handle of the conversation
+ HSZ hsz1, // handle of a string
+ HSZ hsz2, // handle of a string
+ HDDEDATA hdata,// handle of a global memory object
+ DWORD dwData1, // transaction-specific data
+ DWORD dwData2 // transaction-specific data
+
+ RETURNS:
+ HDDEDATA
+****************************************************************************/
+
+HDDEDATA CALLBACK PMDDEML_DdeCallback( UINT uType, // transaction type
+ UINT uFmt, // clipboard data format
+ HCONV hconv, // handle of the conversation
+ HSZ hsz1, // handle of a string
+ HSZ hsz2, // handle of a string
+ HDDEDATA hdata,// handle of a global memory object
+ DWORD dwData1, // transaction-specific data
+ DWORD dwData2 // transaction-specific data
+ )
+{
+ // Nothing need be done here...
+ return (HDDEDATA)NULL;
+}
+
+
+/****************************************************************************
+ FUNCTION: PMDDEML_SendShellCommand()
+
+ PURPOSE: Sends the given command string to Program Manager
+
+ PARAMETERS:
+ LPSTR - pointer to command string
+
+ RETURNS:
+ BOOL - TRUE if this function succeeds, FALSE otherwise
+****************************************************************************/
+
+BOOL PMDDEML_SendShellCommand (DWORD idInst, // instance identifier
+ LPSTR lpCommand) // command string to execute
+{
+ HSZ hszServTop; // Service and Topic name are "PROGMAN"
+ HCONV hconv; // handle of conversation
+ int nLen; // length of command string
+ HDDEDATA hData; // return value of DdeClientTransaction
+ DWORD dwResult; // result of transaction
+ BOOL bResult=FALSE; // TRUE if this function is successful
+
+ // create string handle to service/topic
+ hszServTop = DdeCreateStringHandle(idInst, "PROGMAN", CP_WINANSI);
+
+ // attempt to start conversation with server app
+ if ((hconv = DdeConnect(idInst, hszServTop, hszServTop, NULL))!= NULL)
+ {
+ // get length of the command string
+ nLen = lstrlen((LPSTR)lpCommand);
+
+ // send command to server app
+ hData = DdeClientTransaction((LPBYTE)lpCommand, // data to pass
+ nLen + 1, // length of data
+ hconv, // handle of conversation
+ NULL, // handle of name-string
+ CF_TEXT, // clipboard format
+ XTYP_EXECUTE, // transaction type
+ 1000, // timeout duration
+ &dwResult); // points to transaction result
+
+ if (hData)
+ bResult = TRUE;
+
+ // end conversation
+ DdeDisconnect(hconv);
+ }
+
+ // free service/topic string handle
+ DdeFreeStringHandle(idInst, hszServTop);
+
+ return bResult;
+}
+
+
+/****************************************************************************
+ FUNCTION: PMDDEML_GetProgramGroupInfo()
+
+ PURPOSE: Gets group info from progman
+
+ PARAMETERS:
+ LPSTR - pointer to command string
+
+ RETURNS:
+ BOOL - TRUE if this function succeeds, FALSE otherwise
+****************************************************************************/
+BOOL PMDDEML_GetProgramGroupInfo(DWORD idInst, LPSTR lpProgramGroup, char *szBuffer, DWORD cbBuffer)
+{
+ HSZ hszServTop; // Service and Topic name are "PROGMAN"
+ HSZ hszTopic; // Topic name is the lpRequest
+ HCONV hconv; // handle of conversation
+ HDDEDATA hData = 0; // return value of DdeClientTransaction
+ DWORD dwResult; // result of transaction
+ BOOL bResult=FALSE; // TRUE if this function is successful
+
+ hszServTop = DdeCreateStringHandle(idInst, "PROGMAN", CP_WINANSI);
+ hszTopic = DdeCreateStringHandle(idInst, lpProgramGroup, CP_WINANSI);
+
+ if((hconv = DdeConnect(idInst, hszServTop, hszServTop, NULL)) != NULL)
+ {
+ hData = DdeClientTransaction((LPBYTE)NULL, // data to pass
+ 0L, // length of data
+ hconv, // handle of conversation
+ hszTopic, // handle of name-string
+ CF_TEXT, // clipboard format
+ XTYP_REQUEST, // transaction type
+ 5000, // timeout duration
+ &dwResult); // points to transaction result
+
+ bResult = (BOOL)DdeGetData(hData, (void FAR*)szBuffer, cbBuffer, 0);
+ DdeDisconnect(hconv);
+ }
+
+ // free service/topic string handle
+ DdeFreeStringHandle(idInst, hszServTop);
+ DdeFreeStringHandle(idInst, hszTopic);
+
+ return bResult;
+}
diff --git a/lib/libnt/registry.c b/lib/libnt/registry.c
new file mode 100644
index 00000000..2e6ec639
--- /dev/null
+++ b/lib/libnt/registry.c
@@ -0,0 +1,242 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+// ERROR.C
+//
+// This file contains the functions needed to install the httpd server.
+// They are as follows.
+//
+// getreg.c
+//
+// This file has the function needed to get a particular value of a key from the registry...
+// 1/16/95 aruna
+//
+
+#include <windows.h>
+#include "nt/ntos.h"
+
+BOOL NS_WINAPI
+REG_CheckIfKeyExists( HKEY hKey, LPCTSTR key )
+{
+ HKEY hQueryKey;
+
+ if (RegOpenKeyEx(hKey, key, 0, KEY_ALL_ACCESS,
+ &hQueryKey) != ERROR_SUCCESS) {
+ return FALSE;
+ }
+
+ RegCloseKey(hQueryKey);
+ return TRUE;
+}
+
+BOOL NS_WINAPI
+REG_GetRegistryParameter(
+ HKEY hKey,
+ LPCTSTR registryKey,
+ LPTSTR QueryValueName,
+ LPDWORD ValueType,
+ LPBYTE ValueBuffer,
+ LPDWORD ValueBufferSize
+ )
+{
+ HKEY hQueryKey;
+
+ if (RegOpenKeyEx(hKey, registryKey, 0, KEY_ALL_ACCESS,
+ &hQueryKey) != ERROR_SUCCESS) {
+
+ return FALSE;
+ }
+
+ if (RegQueryValueEx(hQueryKey, QueryValueName, 0,
+ ValueType, ValueBuffer, ValueBufferSize) != ERROR_SUCCESS) {
+ RegCloseKey(hQueryKey);
+ return FALSE;
+ }
+
+ RegCloseKey(hQueryKey);
+ return TRUE;
+}
+
+BOOL NS_WINAPI
+REG_CreateKey( HKEY hKey, LPCTSTR registryKey )
+{
+ HKEY hNewKey;
+
+ if ( RegCreateKey (hKey, registryKey, &hNewKey) != ERROR_SUCCESS) {
+ return FALSE;
+ }
+
+ RegCloseKey(hNewKey);
+ return TRUE;
+}
+
+BOOL NS_WINAPI
+REG_DeleteKey( HKEY hKey, LPCTSTR registryKey )
+{
+ HKEY hQueryKey;
+ DWORD dwNumberOfSubKeys;
+ char registrySubKey[256];
+ DWORD i;
+
+ /* if key does not exist, then consider it deleted */
+ if ( !REG_CheckIfKeyExists( hKey, registryKey ) )
+ return TRUE;
+
+ if ( !REG_GetSubKeysInfo( hKey, registryKey, &dwNumberOfSubKeys, NULL ) )
+ return FALSE;
+
+ if ( dwNumberOfSubKeys ) {
+ if (RegOpenKeyEx(hKey, registryKey, 0, KEY_ALL_ACCESS,
+ &hQueryKey) != ERROR_SUCCESS) {
+ return FALSE;
+ }
+
+ // loop through all sub keys and delete the subkeys (recursion)
+ for ( i=0; i<dwNumberOfSubKeys; i++ ) {
+ if ( RegEnumKey( hQueryKey, 0, registrySubKey, sizeof(registrySubKey) ) != ERROR_SUCCESS) {
+ RegCloseKey(hQueryKey);
+ return FALSE;
+ }
+ if ( !REG_DeleteKey( hQueryKey, registrySubKey ) ) {
+ RegCloseKey(hQueryKey);
+ return FALSE;
+ }
+ }
+ RegCloseKey(hQueryKey);
+ }
+
+ if ( RegDeleteKey (hKey, registryKey) != ERROR_SUCCESS) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+BOOL NS_WINAPI
+REG_GetSubKey( HKEY hKey, LPCTSTR registryKey, DWORD nSubKeyIndex, LPTSTR registrySubKeyBuffer, DWORD subKeyBufferSize )
+{
+ HKEY hQueryKey;
+
+ if (RegOpenKeyEx(hKey, registryKey, 0, KEY_ALL_ACCESS,
+ &hQueryKey) != ERROR_SUCCESS) {
+ return FALSE;
+ }
+
+ if ( RegEnumKey( hQueryKey, nSubKeyIndex, registrySubKeyBuffer, subKeyBufferSize ) != ERROR_SUCCESS) {
+ RegCloseKey(hQueryKey);
+ return FALSE;
+ }
+
+ RegCloseKey(hQueryKey);
+ return TRUE;
+}
+
+BOOL NS_WINAPI
+REG_GetSubKeysInfo( HKEY hKey, LPCTSTR registryKey, LPDWORD lpdwNumberOfSubKeys, LPDWORD lpdwMaxSubKeyLength )
+{
+ HKEY hQueryKey;
+ char szClass[256]; // address of buffer for class string
+ DWORD cchClass; // address of size of class string buffer
+ DWORD cSubKeys; // address of buffer for number of subkeys
+ DWORD cchMaxSubkey; // address of buffer for longest subkey name length
+ DWORD cchMaxClass; // address of buffer for longest class string length
+ DWORD cValues; // address of buffer for number of value entries
+ DWORD cchMaxValueName; // address of buffer for longest value name length
+ DWORD cbMaxValueData; // address of buffer for longest value data length
+ DWORD cbSecurityDescriptor; // address of buffer for security descriptor length
+ FILETIME ftLastWriteTime; // address of buffer for last write time
+
+
+ if (RegOpenKeyEx(hKey, registryKey, 0, KEY_ALL_ACCESS,
+ &hQueryKey) != ERROR_SUCCESS) {
+ return FALSE;
+ }
+
+ if ( RegQueryInfoKey( hQueryKey, // handle of key to query
+ (char*)&szClass, // address of buffer for class string
+ &cchClass, // address of size of class string buffer
+ NULL, // reserved
+ &cSubKeys, // address of buffer for number of subkeys
+ &cchMaxSubkey, // address of buffer for longest subkey name length
+ &cchMaxClass, // address of buffer for longest class string length
+ &cValues, // address of buffer for number of value entries
+ &cchMaxValueName, // address of buffer for longest value name length
+ &cbMaxValueData, // address of buffer for longest value data length
+ &cbSecurityDescriptor, // address of buffer for security descriptor length
+ &ftLastWriteTime // address of buffer for last write time
+ ) != ERROR_SUCCESS) {
+ RegCloseKey(hQueryKey);
+ return FALSE;
+ }
+
+ // return desired information
+ if ( lpdwNumberOfSubKeys )
+ *lpdwNumberOfSubKeys = cSubKeys;
+ if ( lpdwMaxSubKeyLength )
+ *lpdwMaxSubKeyLength = cchMaxSubkey;
+
+ RegCloseKey(hQueryKey);
+ return TRUE;
+}
+
+BOOL NS_WINAPI
+REG_SetRegistryParameter(
+ HKEY hKey,
+ LPCTSTR registryKey,
+ LPTSTR valueName,
+ DWORD valueType,
+ LPCTSTR ValueString,
+ DWORD valueStringLength
+ )
+{
+ HKEY hQueryKey;
+
+ if (RegOpenKeyEx(hKey, registryKey, 0, KEY_ALL_ACCESS,
+ &hQueryKey) != ERROR_SUCCESS) {
+ return FALSE;
+ }
+
+ if ( RegSetValueEx( hQueryKey, valueName, 0, valueType, (CONST BYTE *)ValueString,
+ valueStringLength ) != ERROR_SUCCESS) {
+ RegCloseKey(hQueryKey);
+ return FALSE;
+ }
+
+ RegCloseKey(hQueryKey);
+ return TRUE;
+}
+
+
+
+
+BOOL NS_WINAPI
+REG_DeleteValue( HKEY hKey, LPCTSTR registryKey, LPCSTR valueName )
+{
+ HKEY hQueryKey;
+ DWORD ValueBufferSize = 256;
+ char ValueBuffer[256];
+ DWORD i, ValueType;
+
+ /* if key does not exist, then consider it deleted */
+ if (RegOpenKeyEx(hKey, registryKey, 0, KEY_ALL_ACCESS,
+ &hQueryKey) != ERROR_SUCCESS) {
+ return FALSE;
+ }
+
+ /* if valuename does not exist, then consider it deleted */
+ if (RegQueryValueEx(hQueryKey, valueName, 0,
+ &ValueType, ValueBuffer, &ValueBufferSize) != ERROR_SUCCESS) {
+ RegCloseKey(hQueryKey);
+ return TRUE;
+ }
+
+ if (RegDeleteValue(hQueryKey, valueName) != ERROR_SUCCESS) {
+ RegCloseKey(hQueryKey);
+ return FALSE;
+ }
+
+ RegCloseKey(hQueryKey);
+ return TRUE;
+}
diff --git a/lib/libnt/service.c b/lib/libnt/service.c
new file mode 100644
index 00000000..1bfc5a5e
--- /dev/null
+++ b/lib/libnt/service.c
@@ -0,0 +1,375 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <windows.h>
+#include "nt/ntos.h"
+
+#define SERVRET_ERROR 0
+#define SERVRET_INSTALLED 1
+#define SERVRET_STARTING 2
+#define SERVRET_STARTED 3
+#define SERVRET_STOPPING 4
+#define SERVRET_REMOVED 5
+
+
+DWORD NS_WINAPI
+SERVICE_GetNTServiceStatus(LPCTSTR szServiceName, LPDWORD lpLastError )
+{
+ SERVICE_STATUS ServiceStatus;
+ SC_HANDLE schService = NULL;
+ SC_HANDLE schSCManager = NULL;
+ DWORD lastError = 0;
+ int ret = 0;
+
+ //ereport(LOG_INFORM, "open SC Manager");
+ if ((schSCManager = OpenSCManager(
+ NULL, // machine (NULL == local)
+ NULL, // database (NULL == default)
+ SC_MANAGER_ALL_ACCESS // access required
+ )) == NULL ) {
+ lastError = GetLastError();
+ ret = SERVRET_ERROR;
+ goto finish;
+ }
+
+ schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
+
+ if (schService == NULL ) {
+ lastError = GetLastError();
+ if (lastError == ERROR_SERVICE_DOES_NOT_EXIST) {
+ lastError = 0;
+ ret = SERVRET_REMOVED;
+ } else
+ ret = SERVRET_ERROR;
+ goto finish;
+ }
+
+ ret = ControlService(schService, SERVICE_CONTROL_INTERROGATE, &ServiceStatus);
+
+ if ( !ret ) {
+ lastError = GetLastError();
+ if ( lastError == ERROR_SERVICE_NOT_ACTIVE ) {
+ lastError = 0;
+ ret = SERVRET_INSTALLED;
+ } else
+ ret = SERVRET_ERROR;
+ goto finish;
+ }
+
+ switch ( ServiceStatus.dwCurrentState ) {
+ case SERVICE_STOPPED: ret = SERVRET_INSTALLED; break;
+ case SERVICE_START_PENDING: ret = SERVRET_STARTING; break;
+ case SERVICE_STOP_PENDING: ret = SERVRET_STOPPING; break;
+ case SERVICE_RUNNING: ret = SERVRET_STARTED; break;
+ case SERVICE_CONTINUE_PENDING: ret = SERVRET_STARTED; break;
+ case SERVICE_PAUSE_PENDING: ret = SERVRET_STARTED; break;
+ case SERVICE_PAUSED: ret = SERVRET_STARTED; break;
+ default: ret = SERVRET_ERROR; break;
+ }
+
+finish:
+ if ( schService)
+ CloseServiceHandle(schService);
+ if ( schSCManager)
+ CloseServiceHandle(schSCManager);
+ if ( lpLastError )
+ *lpLastError = lastError;
+ return ret;
+}
+
+DWORD NS_WINAPI
+SERVICE_InstallNTService(LPCTSTR szServiceName, LPCTSTR szServiceDisplayName, LPCTSTR szServiceExe )
+{
+ LPCTSTR lpszBinaryPathName = szServiceExe;
+ SC_HANDLE schService = NULL;
+ SC_HANDLE schSCManager = NULL;
+ int lastError = 0;
+ int ret = 0;
+
+
+ //ereport(LOG_INFORM, "open SC Manager");
+ if ((schSCManager = OpenSCManager(
+ NULL, // machine (NULL == local)
+ NULL, // database (NULL == default)
+ SC_MANAGER_ALL_ACCESS // access required
+ )) == NULL ) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ /* check if service already exists */
+ schService = OpenService( schSCManager,
+ szServiceName,
+ SERVICE_ALL_ACCESS
+ );
+ if (schService) {
+ lastError = ERROR_SERVICE_EXISTS;
+ goto finish;
+ }
+
+ schService = CreateService(
+ schSCManager, // SCManager database
+ szServiceName, // name of service
+ szServiceDisplayName, // name to display
+ SERVICE_ALL_ACCESS, // desired access
+ SERVICE_WIN32_OWN_PROCESS |
+ SERVICE_INTERACTIVE_PROCESS, // service type
+ SERVICE_AUTO_START, //SERVICE_DEMAND_START, // start type
+ SERVICE_ERROR_NORMAL, // error control type
+ lpszBinaryPathName, // service's binary
+ NULL, // no load ordering group
+ NULL, // no tag identifier
+ NULL, // no dependencies
+ NULL, // LocalSystem account
+ NULL); // no password
+
+ if (schService == NULL) {
+ lastError = GetLastError();
+ }
+
+ // successfully installed service
+
+finish:
+ if ( schService)
+ CloseServiceHandle(schService);
+ if ( schSCManager)
+ CloseServiceHandle(schSCManager);
+ return lastError;
+}
+
+
+DWORD NS_WINAPI
+SERVICE_RemoveNTService(LPCTSTR szServiceName)
+{
+ SC_HANDLE schService = NULL;
+ SC_HANDLE schSCManager = NULL;
+ int lastError = 0;
+ int ret = 0;
+
+ //ereport(LOG_INFORM, "open SC Manager");
+ if ((schSCManager = OpenSCManager(
+ NULL, // machine (NULL == local)
+ NULL, // database (NULL == default)
+ SC_MANAGER_ALL_ACCESS // access required
+ )) == NULL ) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
+
+ if (schService == NULL ) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ ret = DeleteService(schService);
+
+ if ( !ret) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ // successfully removed service
+
+finish:
+ if ( schService)
+ CloseServiceHandle(schService);
+ if ( schSCManager)
+ CloseServiceHandle(schSCManager);
+ return lastError;
+}
+
+DWORD NS_WINAPI
+SERVICE_StartNTService(LPCTSTR szServiceName)
+{
+ SC_HANDLE schService = NULL;
+ SC_HANDLE schSCManager = NULL;
+ int lastError = 0;
+ int ret = 0;
+
+ //ereport(LOG_INFORM, "open SC Manager");
+ if ((schSCManager = OpenSCManager(
+ NULL, // machine (NULL == local)
+ NULL, // database (NULL == default)
+ SC_MANAGER_ALL_ACCESS // access required
+ )) == NULL ) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
+
+ if (schService == NULL ) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ ret = StartService(schService, 0, NULL);
+
+ if ( !ret ) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ // successfully started service
+
+
+finish:
+ if ( schService)
+ CloseServiceHandle(schService);
+ if ( schSCManager)
+ CloseServiceHandle(schSCManager);
+ return lastError;
+}
+
+DWORD NS_WINAPI
+SERVICE_StartNTServiceAndWait(LPCTSTR szServiceName, LPDWORD lpdwLastError)
+{
+ DWORD dwLastError;
+ DWORD dwStatus;
+ int i;
+
+ /* check if service is running */
+ dwStatus = SERVICE_GetNTServiceStatus( szServiceName, &dwLastError );
+ if ( dwStatus == SERVRET_STARTED )
+ return TRUE;
+
+ dwLastError = SERVICE_StartNTService( szServiceName );
+ if ( dwLastError != 0 ) {
+ goto errorExit;
+ }
+
+ for ( i=0; i<5; i++ ) {
+ // make sure the service got installed
+ dwStatus = SERVICE_GetNTServiceStatus( szServiceName, &dwLastError );
+ if ( dwStatus == SERVRET_ERROR) {
+ if ( dwLastError != ERROR_SERVICE_CANNOT_ACCEPT_CTRL )
+ goto errorExit;
+ } else if ( dwStatus == SERVRET_STARTED )
+ return TRUE;
+
+ Sleep ( 1000 );
+ }
+
+ dwLastError = 0;
+
+errorExit:
+ if ( lpdwLastError )
+ *lpdwLastError = dwLastError;
+ return FALSE;
+}
+
+DWORD NS_WINAPI
+SERVICE_StopNTService(LPCTSTR szServiceName)
+{
+ SC_HANDLE schService = NULL;
+ SC_HANDLE schSCManager = NULL;
+ int lastError = 0;
+ int ret = 0;
+ SERVICE_STATUS ServiceStatus;
+
+ //ereport(LOG_INFORM, "open SC Manager");
+ if ((schSCManager = OpenSCManager(
+ NULL, // machine (NULL == local)
+ NULL, // database (NULL == default)
+ SC_MANAGER_ALL_ACCESS // access required
+ )) == NULL ) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ schService = OpenService(schSCManager, szServiceName, SERVICE_ALL_ACCESS);
+
+ if (schService == NULL ) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ ret = ControlService(schService, SERVICE_CONTROL_STOP, &ServiceStatus);
+
+ if ( !ret ) {
+ lastError = GetLastError();
+ goto finish;
+ }
+
+ // server is stopping
+
+finish:
+ if ( schService)
+ CloseServiceHandle(schService);
+ if ( schSCManager)
+ CloseServiceHandle(schSCManager);
+ return lastError;
+}
+
+DWORD NS_WINAPI
+SERVICE_StopNTServiceAndWait(LPCTSTR szServiceName, LPDWORD lpdwLastError)
+{
+ DWORD dwLastError;
+ DWORD dwStatus;
+ int i;
+
+ /* check if service is running */
+ dwStatus = SERVICE_GetNTServiceStatus( szServiceName, &dwLastError );
+ if ( dwStatus != SERVRET_STARTED )
+ return TRUE;
+
+ for ( i=0; i<30; i++ ) {
+ dwLastError = SERVICE_StopNTService( szServiceName );
+ Sleep ( 1000 );
+
+ // make sure the service is stoppped and just installed
+ dwStatus = SERVICE_GetNTServiceStatus( szServiceName, &dwLastError );
+ Sleep ( 1000 );
+ if ( dwStatus == SERVRET_INSTALLED ) {
+ Sleep ( 1000 );
+ return TRUE;
+ }
+ }
+
+ if ( lpdwLastError )
+ *lpdwLastError = dwLastError;
+ return FALSE;
+}
+
+DWORD NS_WINAPI
+SERVICE_ReinstallNTService(LPCTSTR szServiceName, LPCTSTR szServiceDisplayName, LPCTSTR szServiceExe )
+{
+ DWORD dwLastError;
+ DWORD dwStatus;
+ int i;
+
+ for ( i=0; i< 5; i++ ) {
+
+ /* if service is running, stop it */
+ dwStatus = SERVICE_GetNTServiceStatus( szServiceName, &dwLastError );
+ if ( dwStatus == SERVRET_STARTED )
+ SERVICE_StopNTServiceAndWait( szServiceName, &dwLastError );
+
+ /* if service is installed, remove it */
+ dwStatus = SERVICE_GetNTServiceStatus( szServiceName, &dwLastError );
+ if ( dwStatus == SERVRET_INSTALLED )
+ SERVICE_RemoveNTService( szServiceName );
+
+ /* try and install the service again */
+ dwStatus = SERVICE_GetNTServiceStatus( szServiceName, &dwLastError );
+ if ( dwStatus == SERVRET_REMOVED )
+ SERVICE_InstallNTService( szServiceName, szServiceDisplayName, szServiceExe );
+
+ /* try and start the service again */
+ dwStatus = SERVICE_GetNTServiceStatus( szServiceName, &dwLastError );
+ if ( dwStatus == SERVRET_INSTALLED ) {
+ return NO_ERROR;
+ }
+ }
+
+ /* if no error reported, force an error */
+ if ( dwLastError == NO_ERROR )
+ dwLastError = (DWORD)-1;
+
+ return dwLastError;
+}
+
diff --git a/lib/libnt/tcpip.c b/lib/libnt/tcpip.c
new file mode 100644
index 00000000..e15ccdba
--- /dev/null
+++ b/lib/libnt/tcpip.c
@@ -0,0 +1,145 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#include <windows.h>
+#include "nt/ntos.h"
+
+/*---------------------------------------------------------------------------*\
+ *
+ * Function: GetServerDefaultHostName
+ *
+ * Purpose: This function gets the default host name
+ *
+ * Input:
+ *
+ * Returns:
+ *
+ * Comments:
+\*---------------------------------------------------------------------------*/
+DWORD NS_WINAPI
+TCPIP_GetDefaultHostName( LPTSTR lpszFullHostName, LPTSTR lpszHostName, LPTSTR lpszDomainName )
+{
+ char * szKey;
+ char * szName;
+ DWORD dwValueType;
+ DWORD dwIpHostSize = 256;
+ char szIpHost[256];
+ DWORD dwIpDomainSize = 256;
+ char szIpDomain[256];
+ BOOL bWinNT;
+
+ /* get operating system */
+ switch ( INFO_GetOperatingSystem() ) {
+ case OS_WIN95: bWinNT = FALSE; break;
+ case OS_WINNT: bWinNT = TRUE; break;
+ default: return TCPIP_UNSUPPORTED_OS;
+ }
+
+
+#if 0
+ int lastError;
+ WSADATA WSAData;
+ if ( WSAStartup( 0x0101, &WSAData ) != 0 ) {
+ lastError = WSAGetLastError();
+ m_pMainWnd->MessageBox ( "TCP/IP must be installed.\nUse the Network Icon in Control Panel" );
+ return FALSE;
+ }
+ lastError = gethostname ( szIpHost, sizeof(szIpHost) );
+#endif
+
+ /* get list of all keys under Netscape */
+ if ( bWinNT )
+ szKey = "SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters";
+ else
+ szKey = "SYSTEM\\CurrentControlSet\\Services\\Vxd\\MSTCP";
+
+ if( !REG_CheckIfKeyExists( HKEY_LOCAL_MACHINE, szKey ) ) {
+ return TCPIP_NO_TCPIP;
+ }
+
+ /* get host name for computer. May have to get DHCP host name if empty */
+ szName = "Hostname";
+ if( !REG_GetRegistryParameter( HKEY_LOCAL_MACHINE, szKey, szName, &dwValueType, (LPBYTE)szIpHost, &dwIpHostSize ) ) {
+ szIpHost[0] = '\0';
+ }
+
+ /* get domain name for computer. May have to get DHCP host name if empty */
+ szName = "Domain";
+ if( !REG_GetRegistryParameter( HKEY_LOCAL_MACHINE, szKey, szName, &dwValueType, (LPBYTE)szIpDomain, &dwIpDomainSize ) ) {
+ dwIpDomainSize = 0;
+ }
+ if ( dwIpDomainSize == 0 ) {
+ szName = "DhcpDomain";
+ if( !REG_GetRegistryParameter( HKEY_LOCAL_MACHINE, szKey, szName, &dwValueType, (LPBYTE)szIpDomain, &dwIpDomainSize ) ) {
+ dwIpDomainSize = 0;
+ }
+ }
+
+ if ( lpszHostName )
+ strcpy ( lpszHostName, szIpHost );
+
+ strcpy ( lpszFullHostName, szIpHost );
+ if ( lpszDomainName ) {
+ if ( dwIpDomainSize == 0 )
+ *lpszDomainName = '\0';
+ else {
+ strcpy ( lpszDomainName, szIpDomain );
+ strcat ( lpszFullHostName, "." );
+ strcat ( lpszFullHostName, lpszDomainName );
+ }
+ }
+
+ return TCPIP_NO_ERROR;
+}
+/*---------------------------------------------------------------------------*\
+ *
+ * Function: TCPIP_VerifyHostName
+ *
+ * Purpose: This function validates the host name
+ *
+ * Input:
+ *
+ * Returns:
+ *
+ * Comments:
+\*---------------------------------------------------------------------------*/
+DWORD NS_WINAPI
+TCPIP_VerifyHostName( LPCTSTR lpszHostName )
+{
+ struct hostent *ent;
+ WSADATA wsd;
+ int lastError;
+
+ if(WSAStartup(MAKEWORD(1, 1), &wsd) != 0)
+ return TCPIP_NO_WINSOCK_DLL;
+
+ ent = gethostbyname ( lpszHostName );
+ lastError = WSAGetLastError();
+ WSACleanup();
+
+ if ( ent == NULL ) {
+ switch ( lastError ) {
+ case WSANOTINITIALISED: // A successful WSAStartup must occur before using this function.
+ break;
+ case WSAENETDOWN: // The Windows Sockets implementation has detected that the network subsystem has failed.
+ return TCPIP_NETWORK_DOWN;
+ case WSAHOST_NOT_FOUND: // Authoritative Answer Host not found.
+ return TCPIP_HOST_NOT_FOUND;
+ case WSATRY_AGAIN: // Non-Authoritative Host not found, or SERVERFAIL.
+ return TCPIP_HOST_SERVER_DOWN;
+ case WSANO_RECOVERY: // Nonrecoverable errors: FORMERR, REFUSED, NOTIMP.
+ return TCPIP_NETWORK_ERROR;
+ case WSANO_DATA: // Valid name, no data record of requested type.
+ return TCPIP_HOST_VALID_NAME;
+ case WSAEINPROGRESS: // A blocking Windows Sockets operation is in progress.
+ return TCPIP_NETWORK_ERROR;
+ case WSAEINTR: // The (blocking) call was canceled using
+ return TCPIP_NETWORK_ERROR;
+ default:
+ return TCPIP_NETWORK_ERROR;
+ }
+ }
+ return TCPIP_NO_ERROR;
+}
diff --git a/lib/libsi18n/Makefile b/lib/libsi18n/Makefile
new file mode 100644
index 00000000..9b1c9c2e
--- /dev/null
+++ b/lib/libsi18n/Makefile
@@ -0,0 +1,155 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# The libsi18n library support for getting strings from the
+# string database.
+
+MCOM_ROOT=../../..
+MODULE=LibsI18N
+include ../../nsdefs.mk
+
+NSDEFS_PRODUCT = $(NS_PRODUCT)
+
+OBJDEST=$(OBJDIR)/lib/libsi18n
+
+L10NDIR = $(MCOM_ROOT)/ldapserver/l10n
+
+ifeq ($(ARCH), WINNT)
+CCOUT0= /Fo
+CCOUT1= /Fe
+LIBS=$(OBJDIR)/lib/libsi18n.lib
+ifeq ($(BSCINFO), yes)
+BSCS=$(OBJDIR)/lib/libsi18n.bsc
+endif
+else
+LIBS=$(OBJDIR)/lib/libsi18n.a
+CCOUT0= -o
+CCOUT1= -o
+endif
+
+ifeq ($(ARCH), IRIX)
+ ifeq ($(USE_N32), 1)
+ MYLDFLAG = -n32
+ else
+ MYLDFLAG =
+ endif
+else
+ MYLDFLAG =
+endif
+
+ifeq ($(USE_64), 1)
+ifeq ($(ARCH), HPUX)
+ MYLDFLAG = +DA2.0W
+endif
+ifeq ($(ARCH), SOLARIS)
+ MYLDFLAG = -xarch=v9
+endif
+endif
+ifeq ($(BUILD_MODULE), HTTP_ENTERPRISE)
+StringDatabase = ns-httpd.db
+L10N_SERVER = httpd
+DBTheaders = \
+ ../../httpd/src/dbthttpd.h \
+ ../../include/base/dbtbase.h \
+ ../../include/frame/dbtframe.h \
+ ../../include/httpdaemon/dbthttpdaemon.h \
+ ../../include/libaccess/dbtlibaccess.h \
+ ../../include/libadmin/dbtlibadmin.h \
+ ../../include/libir/dbtlibir.h \
+ gshttpd.h
+endif
+
+ifeq ($(BUILD_MODULE), DIRECTORY)
+ StringDatabase = ns-slapd.properties
+ DBTheaders = \
+ ../../httpd/src/dbthttpd.h \
+ ../../include/base/dbtbase.h \
+ ../../include/frame/dbtframe.h \
+ ../../include/httpdaemon/dbthttpdaemon.h \
+ ../../include/libaccess/dbtlibaccess.h \
+ ../../include/libadmin/dbtlibadmin.h \
+ ../../include/libir/dbtlibir.h \
+ ../../ldap/clients/dsgw/dbtdsgw.h \
+ gsslapd.h
+ endif
+
+
+ifeq ($(BUILD_MODULE), HTTP_PERSONAL)
+StringDatabase = ns-httpd.db
+L10N_SERVER = httpd
+DBTheaders = \
+ ../../httpd/src/dbthttpd.h \
+ ../../include/base/dbtbase.h \
+ ../../include/frame/dbtframe.h \
+ ../../include/httpdaemon/dbthttpdaemon.h \
+ ../../include/libaccess/dbtlibaccess.h \
+ ../../include/libadmin/dbtlibadmin.h \
+ gshttpd.h
+endif
+
+ifeq ($(BUILD_MODULE), HTTP_PROXY)
+StringDatabase = ns-proxy.db
+DBTheaders = \
+ ../../httpd/src/dbthttpd.h \
+ ../../include/base/dbtbase.h \
+ ../../include/frame/dbtframe.h \
+ ../../include/httpdaemon/dbthttpdaemon.h \
+ ../../include/libaccess/dbtlibaccess.h \
+ ../../include/libadmin/dbtlibadmin.h \
+ gsproxy.h
+endif
+
+ifeq ($(BUILD_MODULE), HTTP_ADMIN)
+StringDatabase = ns-admin.db
+L10N_SERVER = admserv
+DBTheaders = \
+ ../../admserv/src/dbtadmserv.h \
+ ../../admserv/cgi-src/dbtcgiadmin.h \
+ ../../admserv/user-forms/src/dbtuserforms.h \
+ ../../include/base/dbtbase.h \
+ ../../include/frame/dbtframe.h \
+ ../../include/httpdaemon/dbthttpdaemon.h \
+ ../../include/libaccess/dbtlibaccess.h \
+ ../../include/libadmin/dbtlibadmin.h \
+ ../../include/libir/dbtlibir.h \
+ gsadmserv.h
+endif
+
+include ../../nsconfig.mk
+
+MCC_INCLUDE += $(ADMINUTIL_INCLUDE)
+
+all: $(OBJDEST) $(LIBS) $(BSCS) $(OBJDEST)/$(StringDatabase)
+
+$(OBJDEST)/$(StringDatabase): makstrdb.c ../../include/i18n.h $(DBTheaders)
+ @echo "Building String Database for $(BUILD_MODULE) in"
+ @echo "$(OBJDEST)/$(StringDatabase)"
+ $(CC) -g $(CFLAGS) $(MCC_INCLUDE) -c makstrdb.c \
+ $(CCOUT0)$(OBJDEST)/makstrdb.o
+ $(CC) $(MYLDFLAG) -g $(OBJDEST)/makstrdb.o \
+ $(CCOUT1)$(OBJDEST)/makstrdb.exe
+ cd $(OBJDEST); ./makstrdb.exe
+ rm $(OBJDEST)/makstrdb.exe
+
+$(OBJDEST):
+ mkdir -p $(OBJDEST)
+
+OBJS = \
+ $(OBJDEST)/acclanglist.o \
+ $(OBJDEST)/getstrprop.o \
+ $(OBJDEST)/getlang.o \
+ $(OBJDEST)/coreres.o \
+ $(OBJDEST)/txtfile.o \
+ $(OBJDEST)/propset.o \
+ $(OBJDEST)/reshash.o
+
+
+
+$(LIBS): $(OBJS)
+ rm -f $@
+ $(AR) $(OBJS)
+ $(RANLIB) $@
diff --git a/lib/libsi18n/acclanglist.c b/lib/libsi18n/acclanglist.c
new file mode 100644
index 00000000..cc985cde
--- /dev/null
+++ b/lib/libsi18n/acclanglist.c
@@ -0,0 +1,187 @@
+/** 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 <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+#include "i18n.h"
+
+
+/*
+ * Accept-Language = "Accept-Language" ":"
+ * 1#( language-range [ ";" "q" "=" qvalue ] )
+ * language-range = ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" )
+ *
+ * NLS_AccLangList() assumes that "Accept-Language:" has already
+ * been stripped off. It takes as input
+ *
+ * 1#( ( ( 1*8ALPHA *( "-" 1*8ALPHA ) ) | "*" ) [ ";" "q" "=" qvalue ] )
+ *
+ * and returns a list of languages, ordered by qvalues, in
+ * the array NLS_ACCEPT_LANGUAGE_LIST.
+ *
+ * If there are to many languages (>NLS_MAX_ACCEPT_LANGUAGE) the excess
+ * is ignored. If the language-range is too long (>NLS_MAX_ACCEPT_LENGTH),
+ * the language-range is ignored. In these cases, NLS_AccLangList()
+ * will quietly return, perhaps with numLang = 0. numLang is
+ * returned by the function.
+ */
+
+
+static size_t
+AcceptLangList(const char* AcceptLanguage,
+ ACCEPT_LANGUAGE_LIST AcceptLanguageList)
+{
+ char* input;
+ char* cPtr;
+ char* cPtr1;
+ char* cPtr2;
+ int i;
+ int j;
+ int countLang = 0;
+
+ input = strdup(AcceptLanguage);
+ if (input == (char*)NULL){
+ return 0;
+ }
+
+ cPtr1 = input-1;
+ cPtr2 = input;
+
+ /* put in standard form */
+ while (*(++cPtr1)) {
+ if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
+ else if (isspace(*cPtr1)); /* ignore any space */
+ else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
+ else if (*cPtr1=='*'); /* ignore "*" */
+ else *cPtr2++ = *cPtr1; /* else unchanged */
+ }
+ *cPtr2 = '\0';
+
+ countLang = 0;
+
+ if (strchr(input,';')) {
+ /* deal with the quality values */
+
+ float qvalue[MAX_ACCEPT_LANGUAGE];
+ float qSwap;
+ float bias = 0.0f;
+ char* ptrLanguage[MAX_ACCEPT_LANGUAGE];
+ char* ptrSwap;
+
+ cPtr = strtok(input,",");
+ while (cPtr) {
+ qvalue[countLang] = 1.0f;
+ if (cPtr1 = strchr(cPtr,';')) {
+ sscanf(cPtr1,";q=%f",&qvalue[countLang]);
+ *cPtr1 = '\0';
+ }
+ if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
+ qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
+ ptrLanguage[countLang++] = cPtr;
+ if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
+ }
+ cPtr = strtok(NULL,",");
+ }
+
+ /* sort according to decending qvalue */
+ /* not a very good algorithm, but count is not likely large */
+ for ( i=0 ; i<countLang-1 ; i++ ) {
+ for ( j=i+1 ; j<countLang ; j++ ) {
+ if (qvalue[i]<qvalue[j]) {
+ qSwap = qvalue[i];
+ qvalue[i] = qvalue[j];
+ qvalue[j] = qSwap;
+ ptrSwap = ptrLanguage[i];
+ ptrLanguage[i] = ptrLanguage[j];
+ ptrLanguage[j] = ptrSwap;
+ }
+ }
+ }
+ for ( i=0 ; i<countLang ; i++ ) {
+ strcpy(AcceptLanguageList[i],ptrLanguage[i]);
+ }
+
+ } else {
+ /* simple case: no quality values */
+
+ cPtr = strtok(input,",");
+ while (cPtr) {
+ if (strlen(cPtr)<MAX_ACCEPT_LENGTH) { /* ignore if too long */
+ strcpy(AcceptLanguageList[countLang++],cPtr);
+ if (countLang>=MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
+ }
+ cPtr = strtok(NULL,",");
+ }
+ }
+
+ free(input);
+
+ return countLang;
+}
+
+/*
+ * Get prioritized locale list from NLS_AcceptLangList
+ *
+ * Add additonal language to the list for fallback if locale
+ * name is language_region
+ *
+ */
+
+
+int
+XP_AccLangList(char* AcceptLanguage,
+ ACCEPT_LANGUAGE_LIST AcceptLanguageList)
+{
+ int i;
+ int n;
+ char *defaultLanguage = "en";
+ ACCEPT_LANGUAGE_LIST curLanguageList;
+ int index = 0;
+ char lang[3];
+ int k;
+
+ n = AcceptLangList(AcceptLanguage, curLanguageList);
+
+ if (n == 0)
+ return 0;
+
+ memset(lang, 0, 3);
+ for (i = 0; i < n; i++) {
+ if (*lang && (strncmp(lang, curLanguageList[i], 2) != 0)) {
+ /* add lang if current language is the last occurence in the list */
+ for (k = i+1; (k < n) && strncmp(curLanguageList[k],lang,2); k++);
+
+ if (k == n) {
+ strcpy(AcceptLanguageList[index++], lang);
+ *lang = '\0';
+ }
+ }
+
+ strcpy(AcceptLanguageList[index++], curLanguageList[i]);
+
+ /* Add current language for future appending.,make sure it's not on list */
+ if ((strlen(curLanguageList[i]) > 2) && (curLanguageList[i][2] == '_')) {
+ strncpy(lang, curLanguageList[i], 2);
+ for (k = 0; (k < index) && strcmp(AcceptLanguageList[k], lang); k++);
+
+ if (k != index) lang[0] = '\0';
+ }
+ }
+
+ if (lang[0] != '\0')
+ strcpy(AcceptLanguageList[index++], lang); /* add new lang */
+
+ /* Append defaultLanguage if it's not in the list */
+ for (i = 0; (i < index) && strcmp(AcceptLanguageList[i], defaultLanguage); i++);
+
+ if (i == index)
+ strcpy(AcceptLanguageList[index++], defaultLanguage);
+
+ return index;
+}
diff --git a/lib/libsi18n/coreres.c b/lib/libsi18n/coreres.c
new file mode 100644
index 00000000..5e438069
--- /dev/null
+++ b/lib/libsi18n/coreres.c
@@ -0,0 +1,113 @@
+/** 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 <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "i18n.h"
+
+#include "libadminutil/resource.h"
+#include "propset.h"
+
+#include "coreres.h"
+#if 0
+typedef struct ResourceS
+{
+ char *path;
+ char *package;
+ PropertiesSet *propset;
+} Resource;
+#endif
+
+Resource* core_res_init_resource(const char* path, const char* package)
+{
+ PropertiesSet *propset;
+ char *directory;
+ char *filename;
+ char *file_path;
+ char *p, *q;
+ char *filep;
+ Resource *hres;
+
+ /*********************
+ Create full path information
+ eg. ./es40/admin and cgi.bin.start ==>
+ ./es40/admin/cgi/bin/start.properties
+ **********************/
+ file_path = (char *) malloc (strlen(path) + strlen(package) + 20);
+
+
+ strcpy(file_path, path);
+ if (path[strlen(path)-1] != '/')
+ strcat(file_path, "/");
+
+ p = file_path + strlen(file_path);
+ q = (char *) package;
+
+ filep = p - 1;
+
+ /* Append package to file_path
+ p: end positon of path + 1
+ q: start position of package
+ */
+ while (q && *q) {
+ if (*q == '.') {
+ filep = q;
+ *p ++ = '/';
+ }
+ else
+ *p ++ = *q ++;
+
+ }
+ *p = '\0';
+
+ *filep = '\0';
+ filename = filep + 1;
+ directory = file_path;
+
+ propset = PropertiesInit (directory, filename);
+
+ if (propset == NULL)
+ return NULL;
+
+ hres = (Resource *) malloc(sizeof(Resource));
+ memset(hres, 0, sizeof(Resource));
+
+ hres->path = strdup(file_path);
+ hres->propset = propset;
+
+ if (file_path)
+ free (file_path);
+
+ return hres;
+}
+
+const char *core_res_getstring(Resource *hres, char *key, ACCEPT_LANGUAGE_LIST lang)
+{
+
+ if (key == NULL)
+ return NULL;
+
+ if (hres) {
+ return PropertiesGetString(hres->propset, key, lang);
+ }
+
+ return NULL;
+}
+
+void core_res_destroy_resource(Resource *hres)
+{
+ if (hres) {
+ if (hres->path)
+ free(hres->path);
+ if (hres->package)
+ free(hres->package);
+ PropertiesDestroy(hres->propset);
+
+ free(hres);
+ }
+}
+
diff --git a/lib/libsi18n/coreres.h b/lib/libsi18n/coreres.h
new file mode 100644
index 00000000..9d27060a
--- /dev/null
+++ b/lib/libsi18n/coreres.h
@@ -0,0 +1,15 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef CORERES_H
+#define CORERES_H
+
+#include "libadminutil/resource.h"
+
+Resource* core_res_init_resource(const char* path, const char* package);
+const char *core_res_getstring(Resource *hres, char *key, ACCEPT_LANGUAGE_LIST lang);
+void core_res_destroy_resource(Resource *hres);
+
+#endif
diff --git a/lib/libsi18n/getlang.c b/lib/libsi18n/getlang.c
new file mode 100644
index 00000000..5aa24d04
--- /dev/null
+++ b/lib/libsi18n/getlang.c
@@ -0,0 +1,294 @@
+/** 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 <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "libadmin/libadmin.h"
+#include "frame/conf.h" /* get access on global language setting */
+
+
+#include "i18n.h"
+
+/*********************************************************************
+ strReplace replaces the first instance of from in target with to.
+ from can be "": to is inserted at start of target.
+ to can be "": from is removed from target.
+ if from is not found, 0 is returned; else 1 is returned.
+ *********************************************************************/
+
+static int
+strReplace(char* target,char* from,char* to)
+{
+ /* replace /from/to/ in target */
+
+ char* pFrom;
+ char* pOldTail;
+ int lenTo;
+
+ pFrom = strstr(target,from);
+ if (pFrom) {
+ pOldTail = pFrom+strlen(from);
+ lenTo = strlen(to);
+ memmove(pFrom+lenTo,pOldTail,strlen(pOldTail)+1);
+ memcpy(pFrom,to,lenTo);
+ return 1;
+ }
+
+ return 0;
+}
+
+/*********************************************************************
+ statFileDir is a wrapper to stat() that strips trailing slashes
+ because stat() on Windows seems to return -1 otherwise.
+*********************************************************************/
+
+int
+statFileDir(const char *path, struct stat *info) {
+ int ret, pathlen;
+ char *newpath = strdup(path);
+
+ if(newpath == NULL)
+ return -1;
+
+ for (pathlen = (strlen(newpath) - 1); pathlen >= 0; pathlen--) {
+ if (newpath[pathlen] == '/' || newpath[pathlen] == '\\') {
+ newpath[pathlen] = '\0';
+ } else {
+ break;
+ }
+ }
+
+ ret = stat(newpath, info);
+
+ if (newpath)
+ free(newpath);
+
+ return ret;
+}
+
+/*********************************************************************
+ GetLanguage is reserved for future use. These APIs are not belong
+ to this file. It needs to be moved to somewhere which knows what's
+ the current language setting.
+ *********************************************************************/
+
+static char emptyString[] = "";
+
+static char client_language[128] = "en";
+static char admin_language[128] = "en";
+static char default_language[128] = "en";
+
+void
+SetLanguage(int type, char *language)
+{
+ switch(type) {
+ case CLIENT_LANGUAGE:
+ if (language)
+ strcpy(client_language, language);
+ break;
+ case ADMIN_LANGUAGE:
+ if (language)
+ strcpy(admin_language, language);
+ break;
+ case DEFAULT_LANGUAGE:
+ if (language)
+ strcpy(default_language, language);
+ break;
+ }
+ return ;
+}
+
+
+
+char*
+GetClientLanguage(void)
+{
+ if (client_language)
+ return client_language;
+ else
+ return emptyString;
+}
+
+char*
+GetAdminLanguage(void)
+{
+ if (admin_language)
+ return admin_language;
+ else
+ return emptyString;
+}
+
+char*
+GetDefaultLanguage(void)
+{
+ if (default_language)
+ return default_language;
+ else
+ return "en";
+}
+
+/*********************************************************************
+ GetFileForLanguage looks for a file in the appropriate language.
+ *********************************************************************/
+
+NSAPI_PUBLIC
+int
+GetFileForLanguage(char* filePath,char* language,char* existingFilePath)
+{
+ /* Input: filePath,language
+ * filePath is of the form "/xxx/xxx/$$LANGDIR/xxx/xxx/filename"
+ * or of the form "/xxx/xxx/xxx/xxx/filename".
+ * filename may or may not have an extension.
+ * language is an Accept-Language list; each language-range will be
+ * tried as a subdirectory name and possibly as a filename modifier.
+ * "*" is ignored - default always provided if needed.
+ * "-" is replaced by "_".
+ * $$LANGDIR is a special string replaced by language. It is optional.
+ * For the default case, $$LANGDIR/ is replaced by nothing
+ * (so // is not created).
+ *
+ * Returned: existingPath
+ * existingFilePath is the path of a satisfactory, existing file.
+ * if no file is found, an empty string "" is returned.
+ *
+ * int returned: -1 if no file found (existingFilePath = "")
+ * 0 if default file is returned
+ * 1 if language file is returned (any in list)
+ *
+ * Example:
+ * filePath = "/path/$$LANGDIR/filename.ext"
+ * language = "language"
+ * GetDefaultLanguage() --> "default"
+ * LANG_DELIMIT = "_"
+ *
+ * 1. Try: "/path/language/filename.ext"
+ * 2. Try: "/path/filename_language.ext"
+ * 3. Try: "/path/default/filename.ext"
+ * 4. Try: "/path/filename_default.ext"
+ * 5. Try: "/path/filename.ext"
+ * else: ""
+ *
+ * Example:
+ * language = "en-us;q=0.6,ja;q=0.8,en-ca"
+ *
+ * 1. Try: "/path/en-ca/filename.ext"
+ * 2. Try: "/path/filename_en_ca.ext"
+ * 3. Try: "/path/ja/filename.ext"
+ * 4. Try: "/path/filename_ja.ext"
+ * 5. Try: "/path/en_us/filename.ext"
+ * 6. Try: "/path/filename_en_us.ext"
+ * 7. Try: "/path/default/filename.ext"
+ * 8. Try: "/path/filename_default.ext"
+ * 9. Try: "/path/filename.ext"
+ * else: ""
+ *
+ */
+
+#define LANG_DELIMIT '_'
+
+ int pattern;
+ char* pDot;
+ char* pSlash;
+
+ /* PRFileInfo info; */
+ struct stat info;
+
+ char lang_modifier[MAX_ACCEPT_LENGTH+1];
+
+ ACCEPT_LANGUAGE_LIST acceptLanguageList;
+ int numLang;
+ int iLang;
+ int iCase;
+
+
+ /* escape in case XP_InitStringDatabase has not been called */
+ if (filePath==NULL) {
+ *existingFilePath = '\0';
+ return -1;
+ }
+
+ pattern = (strstr(filePath,"$$LANGDIR/")!=NULL);
+
+ for ( iCase=1 ; iCase>=0 ; iCase-- ) {
+ if (iCase==1) { /* iCase=1 tries requested language */
+ numLang = XP_AccLangList(language,acceptLanguageList);
+ } else { /* iCase=0 tries default language */
+ numLang = XP_AccLangList(GetDefaultLanguage(),acceptLanguageList);
+ }
+
+ for ( iLang=0 ; iLang<numLang ; iLang++ ) {
+
+ /* Try: /path/language/filename.ext */
+ if (pattern) {
+ strcpy(existingFilePath,filePath);
+ strReplace(existingFilePath,"$$LANGDIR",acceptLanguageList[iLang]);
+
+ if (statFileDir(existingFilePath,&info)==0) {
+ return iCase;
+ }
+
+ /*
+ if (PR_GetFileInfo(existingFilePath,&info)==PR_SUCCESS) {
+ return iCase;
+ }
+ */
+ }
+
+ /* Try: /path/filename_language.ext */
+ {
+ strcpy(existingFilePath,filePath);
+ strReplace(existingFilePath,"$$LANGDIR/",emptyString);
+ pDot = strrchr(existingFilePath,'.');
+ pSlash = strrchr(existingFilePath,'/');
+ if (pSlash>=pDot) {
+ pDot = strchr(existingFilePath,'\0');
+ }
+ sprintf(lang_modifier,"%c%s",LANG_DELIMIT,acceptLanguageList[iLang]);
+ strReplace(pDot,emptyString,lang_modifier);
+
+ if (statFileDir(existingFilePath,&info)==0) {
+ return iCase;
+ }
+
+ /*
+ if (PR_GetFileInfo(existingFilePath,&info)==PR_SUCCESS) {
+ return iCase;
+ }
+ */
+ }
+ }
+ }
+
+ /* Try: /path/filename.ext */
+ {
+ strcpy(existingFilePath,filePath);
+ strReplace(existingFilePath,"$$LANGDIR/",emptyString);
+
+ if (statFileDir(existingFilePath,&info)==0) {
+ return 0;
+ }
+
+ /*
+ if (PR_GetFileInfo(existingFilePath,&info)==PR_SUCCESS) {
+ return 0;
+ }
+ */
+ }
+
+ /* Else: */
+ *existingFilePath = '\0';
+ return -1;
+}
+
+
+
+
+
+
diff --git a/lib/libsi18n/getstrmem.c b/lib/libsi18n/getstrmem.c
new file mode 100644
index 00000000..b49b4cc6
--- /dev/null
+++ b/lib/libsi18n/getstrmem.c
@@ -0,0 +1,123 @@
+/** 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 <string.h>
+
+#define COMPILE_STRINGS_IN_MEMORY
+
+static char emptyString[] = "";
+
+#ifdef COMPILE_STRINGS_IN_MEMORY
+
+typedef struct DATABIN {
+ char* pLibraryName;
+ char** pArrayOfLibraryStrings;
+ unsigned numberOfStringsInLibrary;
+ } DATABIN;
+
+#include "getstrmem.h"
+
+#endif
+
+#if 0 /* Example of getstrmem.h */
+ /* It is intended that this header file be generated by program dblink */
+
+ #define NUM_BUCKETS 2 /* must be power of 2 */
+
+ /* strings in library libalpha */
+ static char* libalpha[] = {
+ "",
+ "libalpha string 1",
+ "libalpha string 2",
+ "libalpha string 3",
+ "libalpha string 4",
+ emptyString };
+
+ /* strings in library libbeta */
+ static char* libbeta[] = {
+ "",
+ "libbeta string 1",
+ "libbeta string 2",
+ emptyString };
+
+ /* libraries in bucket for hashKey==0 */
+ static struct DATABIN bucket0[] = {
+ {emptyString, NULL, 0}};
+
+ /* libraries in bucket for hashKey==1 */
+ static struct DATABIN bucket1[] = {
+ {"libalpha", libalpha, 5},
+ {"libbeta", libbeta, 3},
+ {emptyString, NULL, 0}};
+
+ /* array of buckets */
+ static struct DATABIN* buckets[NUM_BUCKETS] = {
+ bucket0,
+ bucket1 };
+
+#endif /* end of example getstrmem.h */
+
+#define BUCKET_MASK NUM_BUCKETS-1
+
+char*
+XP_GetStringFromMemory(char* strLibraryName,int iToken)
+{
+ /*
+ * In memory model called by XP_GetStringFromDatabase
+ * does not use database (nsres, et al.).
+ *
+ * This function uses hash table for library lookup
+ * and direct lookup for string.
+ *
+ * This function is thread safe.
+ */
+
+#ifdef COMPILE_STRINGS_IN_MEMORY
+
+ unsigned hashKey;
+ int found = 0;
+ unsigned uToken = iToken;
+ char* cPtr;
+ DATABIN* pBucket;
+
+ /* calculate hash key */
+ hashKey = 0;
+ cPtr = strLibraryName;
+ while (*cPtr) {
+ hashKey += *(cPtr++);
+ }
+ hashKey &= BUCKET_MASK;
+
+ /* get bucket for this hash key */
+ pBucket = buckets[hashKey];
+
+ /* search overflow buckets */
+ while (*(pBucket->pLibraryName)!='\0') {
+ if (strcmp(pBucket->pLibraryName,strLibraryName)==0) {
+ found = 1;
+ break;
+ }
+ pBucket++;
+ }
+
+ if (!found) {
+ return emptyString;
+ }
+
+ if (uToken<=pBucket->numberOfStringsInLibrary) {
+ return pBucket->pArrayOfLibraryStrings[uToken];
+ } else {
+ /* string token out of range */
+ return emptyString;
+ }
+
+#else
+
+ return emptyString;
+
+#endif
+}
diff --git a/lib/libsi18n/getstrmem.h b/lib/libsi18n/getstrmem.h
new file mode 100644
index 00000000..edb6d754
--- /dev/null
+++ b/lib/libsi18n/getstrmem.h
@@ -0,0 +1,1156 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#define BUCKET_MASK NUM_BUCKETS-1
+typedef struct DATABIN {
+ char* pLibraryName;
+ char** pArrayOfLibraryStrings;
+ unsigned numberOfStringsInLibrary;
+ } DATABIN;
+
+/* It is intended that this header file be generated by program dblink */
+static char emptyString[] = "";
+
+#define NUM_BUCKETS 32 /* must be a power of 2 */
+
+/* strings in library libadmin */
+static char* libadminid[] = {"$DBT: libadmin in memory v1 $"};
+static char* libadmin[] = {
+ "",
+ " Help ",
+ " OK ",
+ " Reset ",
+ " Done ",
+ " Cancel ",
+ emptyString };
+
+/* libraries in bucket for hashKey==0 */
+static struct DATABIN bucket0[] = {
+ {"libadmin",libadmin,5},
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==1 */
+static struct DATABIN bucket1[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==2 */
+static struct DATABIN bucket2[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==3 */
+static struct DATABIN bucket3[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==4 */
+static struct DATABIN bucket4[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==5 */
+static struct DATABIN bucket5[] = {
+ {emptyString,NULL,0} };
+
+/* strings in library userforms */
+static char* userformsid[] = {"$DBT: userforms in memory v1 $"};
+static char* userforms[] = {
+ "",
+ "Error: could not open servers list file.<p>\n",
+ "Error: could not open %s server list file.<p>\n",
+ "Netscape Server Account",
+ "Server Account Management for %s",
+ "Server Account Management",
+ emptyString };
+
+/* libraries in bucket for hashKey==6 */
+static struct DATABIN bucket6[] = {
+ {"userforms",userforms,5},
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==7 */
+static struct DATABIN bucket7[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==8 */
+static struct DATABIN bucket8[] = {
+ {emptyString,NULL,0} };
+
+/* strings in library libaccess */
+static char* libaccessid[] = {"$DBT: libaccess in memory v1 $"};
+static char* libaccess[] = {
+ "",
+ "basic-ncsa",
+ "cannot open database %s",
+ "basic-ncsa",
+ "user %s password did not match database %s",
+ "basic-ncsa",
+ "cannot open connection to LDAP server on %s:%d",
+ "basic-ncsa",
+ "user %s password did not match LDAP on %s:%d",
+ "acl-state",
+ "missing realm",
+ "Unable to allocate ACL List Hash\n",
+ "ACLEvalBuildContext unable to PERM_MALLOC cache structure\n",
+ "ACLEvalBuildContext unable to create hash table\n",
+ "ACLEvalBuildContext unable to allocate ACE Entry\n",
+ "ACLEvalBuildContext unable to allocate ACE entry\n",
+ "ACLEvalBuildContext unable to allocate Boundary Entry\n",
+ "ACLEvalBuildContext failed.\n",
+ "ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%d\n",
+ "LASDnsBuild unable to allocate hash table header\n",
+ "LASDnsBuild unable to add key %s\n",
+ "LASDnsBuild unable to add key %s\n",
+ "LASDnsBuild unable to add key %s\n",
+ "LASDnsBuild unable to add key %s\n",
+ "LASDnsBuild unable to add key %s\n",
+ "LAS DNS build received request for attribute %s\n",
+ "LASDnsEval - illegal comparator %s\n",
+ "LASDnsEval unable to allocate Context struct\n\n",
+ "LASDnsEval unable to get session address %d\n",
+ "LASDnsEval unable to get DNS - error=%s\n",
+ "LAS Group Eval received request for attribute %s\n",
+ "LASGroupEval - illegal comparator %s\n",
+ "LASGroupEval - ran out of memory\n",
+ "LASGroupEval unable to get session address %d\n",
+ "LASGroupEval unable to get session address %d\n",
+ "LASGroupEval - couldn't locate getter for auth-user\n",
+ "LASGroupEval - Attribute getter for auth-user failed\n",
+ "LASGroupEval - Attribute getter didn't set auth-user\n",
+ "Check group membership of user \"%s\" for group \"%s\"\n",
+ "LDAPU_SUCCESS for group \"%s\"\n",
+ "LDAPU_FAILED for group \"%s\"\n",
+ "LAS_EVAL_FALSE\n",
+ "LAS_EVAL_TRUE\n",
+ "LASIpTreeAlloc - no memory\n",
+ "IP LAS unable to allocate tree node\n",
+ "IP LAS unable to allocate tree node\n",
+ "LAS IP build received request for attribute %s\n",
+ "LASIpEval - illegal comparator %s\n",
+ "LASIpEval unable to get session address - error=%s\n",
+ "LASIpEval unable to allocate Context struct\n\n",
+ "LASIpEval - reach 32 bits without conclusion value=%s",
+ "LAS Program Eval received request for attribute %s\n",
+ "LASProgramEval - illegal comparator %s\n",
+ "LASProgram unable to get session address %d\n",
+ "bin",
+ "LASProgramEval: request not of type admin or bin, passing.\n",
+ "LASProgramEval: check if program %s matches pattern %s.\n",
+ "LASProgramEval: Invalid wildcard expression %s.\n",
+ "LAS_EVAL_FALSE\n",
+ "LAS_EVAL_TRUE\n",
+ "Unexpected attribute in dayOfWeek - %s\n",
+ "Illegal comparator for dayOfWeek - %s\n",
+ "Unexpected attribute in timeOfDay - %s\n",
+ "LAS User Eval received request for attribute %s\n",
+ "LASUserEval - illegal comparator %s\n",
+ "LASUserEval - ran out of memory\n",
+ "LASUserEval unable to get session address %d\n",
+ "LASUserEval unable to get session address %d\n",
+ "LASGroupEval - couldn't locate getter for auth-user\n",
+ "LASGroupEval - Attribute getter for auth-user failed\n",
+ "LASGroupEval - Attribute getter didn't set auth-user\n",
+ "Check if uid == user (i.e. check \"%s\" == \"%s)\"\n",
+ "SUCCESS for user \"%s\"\n",
+ "FAILED for user \"%s\"\n",
+ "LAS_EVAL_FALSE\n",
+ "LAS_EVAL_TRUE\n",
+ "",
+ "LASProgram unable to get request address - error=%s",
+ "LASProgram rejecting request for program %s from pattern %s",
+ "ACL_CacheFlush: unable to parse file \"%s\"\n",
+ "ACL_CacheFlush: unable to concatenate ACL list \"%s\"\n",
+ "ACL_CacheFlush: unable to open and process the magnus file \"%s\"\n",
+ "Illegal comparator for timeOfDay - %s\n",
+ "ACL_EvalBuildContext unable to create hash table\n",
+ "ACL_EvalBuildContext unable to PERM_CALLOC cache structure\n",
+ "ACL_EvalBuildContext unable to allocate ACE entry\n",
+ "ACL_EvalBuildContext unable to allocate auth pointer array\n",
+ "ACL_EvalBuildContext unable to allocate auth plist\n",
+ "ACL_EvalTestRights: an interim, absolute non-allow value was encountered. right=%s, value=%s\n",
+ "ACL_INTEvalTestRights: call to ACL_EvalBuildContext returned failure status\n",
+ "ACL_ModuleRegister: module name is missing\n",
+ "ACL_ModuleRegister: call to module init function returned a failed status\n",
+ "ACL_GetAttribute: couldn't determine method for %s\n",
+ "ACL_GetAttribute: couldn't locate getter for %s",
+ "ACL_GetAttribute: attr getter failed to get %s",
+ "ACL_GetAttribute: attr getter failed to get %s",
+ "ACL_GetAttribute: All attribute getters declined for attr %s",
+ "ACL_DatabaseRegister: dbtype for database \"%s\" is not defined yet!",
+ "ACL_DatabaseRegister: database name is missing",
+ "Error reading the DB Map File: %s. Reason: %s",
+ "URL is missing for database %s",
+ "Invalid property value pair for database %s",
+ "\"default\" database must be an LDAP database",
+ "Multiple \"default\" databases are being registered",
+ "\"default\" LDAP database must be registered",
+ "LASGroupEval unable to get database name - error= %s",
+ "received invalid program expression %s",
+ "parse_ldap_url: database url is missing",
+ "parse_ldap_url: database name is missing",
+ "parse_ldap_url: error in parsing ldap url. Reason: %s",
+ "ldap password check: unable to get database name - error=%s",
+ "ldap password check: unable to get parsed database %s",
+ "ldap password check: couldn't initialize connection to LDAP. Reason: %s",
+ "ldap password check: LDAP error: \"%s\"",
+ "get_user_ismember_ldap unable to get database name - error=%s",
+ "get_user_ismember_ldap unable to get parsed database %s",
+ "ldap password check: couldn't initialize connection to LDAP. Reason: %s",
+ "get_user_ismember_ldap: group %s does not exist",
+ "get_user_ismember_ldap: LDAP error: \"%s\"",
+ "ACL_LDAPDatabaseHandle: %s is not a registered database",
+ "ACL_LDAPDatabaseHandle: %s is not an LDAP database",
+ "ACL_LDAPDatabaseHandle: out of memory",
+ "ACL_LDAPDatabaseHandle: couldn't initialize connection to LDAP. Reason: %s",
+ "ACL_LDAPDatabaseHandle: couldn't bind to LDAP server. Reason: %s",
+ "insufficient dynamic memory",
+ "error opening file, %s: %s",
+ "duplicate definition of %s",
+ "file %s, line %s: duplicate definition of %s",
+ "file %s, line %s: syntax error",
+ "file %s, line %s: %s is undefined",
+ "in acl %s, %s %s is undefined",
+ "database %s: error accessing %s",
+ "%s",
+ "file %s, line %s: invalid syntax",
+ "file %s, line %s: syntax error at \"%s\"",
+ "realm %s is not defined",
+ "error code = %d",
+ "internal ACL error",
+ "invalid argument",
+ "ACL_DatabaseRegister: dbtype for database \"%s\" is not defined yet!",
+ "couldn't determine dbtype from: %s",
+ "Failed to register database %s",
+ "ACL call returned failed status",
+ "file %s: ACL IO error - %s",
+ "acl_user_exists: out of memory",
+ "acl_user_exists: user doesn't exist anymore",
+ "acl_user_exists: plist error",
+ emptyString };
+
+/* libraries in bucket for hashKey==9 */
+static struct DATABIN bucket9[] = {
+ {"libaccess",libaccess,146},
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==10 */
+static struct DATABIN bucket10[] = {
+ {emptyString,NULL,0} };
+
+/* strings in library frame */
+static char* frameid[] = {"$DBT: frame in memory v1 $"};
+static char* frame[] = {
+ "",
+ "<TITLE>Not Found</TITLE><H1>Not Found</H1> The requested object does not exist on this server. The link you followed is either outdated, inaccurate, or the server has been instructed not to let you have it. ",
+ "Please inform the site administrator of the <A HREF=\"%s\">referring page</A>.",
+ "Your browser sent a request that this proxy could not understand.",
+ "Proper authorization is required for the administration of this proxy.\nEither your browser does not perform authorization, or your authorization\nhas failed.",
+ "Username authentication is required for using this proxy.\nEither your browser does not perform proxy authorization, or your\nauthorization has failed.",
+ "The proxy's access control configuration denies access to\nthe requested object through this proxy.",
+ "The proxy has encountered an internal error which prevents it from\nfulfilling your request. The most likely cause is a misconfiguration.\nPlease ask the administrator to look for messages in the proxy's error log.",
+ "This proxy server does not implement the requested method.",
+ "An error has occurred on the proxy server.",
+ "Your browser sent a query this server could not understand.",
+ "Proper authorization is required for this area. Either your browser does not perform authorization, or your authorization has failed.",
+ "Your client is not allowed to access the requested object.",
+ "This server has encountered an internal error which prevents it from fulfilling your request. The most likely cause is a misconfiguration. Please ask the administrator to look for messages in the server's error log.",
+ "This server does not implement the requested method.",
+ "An error has occurred.",
+ "Your browser sent a message this server could not understand.",
+ "<HTML><HEAD><TITLE>%s</TITLE></HEAD><BODY><H1>%s</H1>\nThis document has moved to a new <a href=\"%s\">location</a>. Please update your documents and hotlists accordingly.</BODY></HTML>",
+ "<HTML><HEAD><TITLE>%s</TITLE></HEAD>\n<BODY><H1>%s</H1>\n%s\n</BODY></HTML>",
+ "process-uri-objects",
+ "cannot find template %s",
+ "process-uri-objects",
+ "no partial path after object processing",
+ "find-service",
+ "invalid shexp %s",
+ "find-service",
+ "invalid shexp %s",
+ "handle-processed",
+ "no way to service request for %s",
+ "finish-socks-request",
+ "close failed (%s), csd=%d",
+ "This beta software has expired.\n",
+ "mr_accept(%d)",
+ "Error issuing read on accept socket",
+ "acb_accept_connection(%d)",
+ "Error getting accept socket (%d)",
+ "Error in accept! (%d, %s)",
+ "Error creating new accept request",
+ "accepted connection: %d (NSPR %d)",
+ "Error creating new session structure",
+ "accel_read_request()",
+ "Error allocating request read buffer",
+ "Error issuing async read request",
+ "acb_read_request(%d, bytes %d)",
+ "acb_read_req(1 session = %d)",
+ "Error reading request (%d, %s)",
+ "Client aborted connection",
+ "Error reading request",
+ "Error creating new request",
+ "error occurred, closing %d, io was for %d",
+ "accel_async_scan_headers()",
+ "out of memory: accel_async_scan_headers",
+ "out of memory: accel_async_scan_headers",
+ "Error during async read (%d, %s)",
+ "scan-headers reports: line too long",
+ "scan-headers reports: too many headers",
+ "Error reading headers",
+ "scan-headers reports: header missing terminator (an empty line)",
+ "scan-headers reports: header was empty",
+ "name without value: got line \"%s\"",
+ "accel_send_plain_file()",
+ "accel_send_plain_file() - found request %d",
+ "Parse headers lost the URI!",
+ "accel_send_plain_file() - found uri %s",
+ "accel_send_plain_file() - found in cache?",
+ "malloc died!",
+ "Error writing back file\n",
+ "acb_send_plain_file(%d)",
+ "Error writing in acb_send_plain_file (%d, %s)",
+ "acb_close_connection(%d)",
+ "Errored IO in acb_close_connection (%d, %s)",
+ "Unable to close socket %d",
+ "accel-cache-insert: Error allocating entry",
+ "cache-init: server cache disabled",
+ "accel_file_cache: Error initializing file cache",
+ "accel_file_cache: Error creating cache",
+ "accel_file_cache_init: CacheHashSize < %d, using %d",
+ "accel_file_cache_init: CacheHashSize > %d, using %d",
+ "accel_file_cache_init: MaxNumberOfCachedFiles < %d, using %d",
+ "accel_file_cache_init: MaxNumberOfCachedFiles > %d, using %d",
+ "accel_file_cache_init: MaxNumberOfOpenCachedFiles < %d, using %d",
+ "accel_file_cache_init: MaxNumberOfOpenCachedFiles > %d, using %d",
+ "accel_file_cache: Error initializing file cache",
+ "file-cache: enabled = %s ",
+ "on",
+ "off",
+ "file-cache: MaxNumberOfCachedFiles %d (0x%x)",
+ "file-cache: CacheHashSize %d (0x%x)",
+ "file-cache: MaxNumberOfOpenCachedFiles %d (0x%x)",
+ "accel-cache-insert: Error allocating entry",
+ "file-cache-cleanup: munmap failed (%s)",
+ "file-cache-cleanup: found mmapped file \non system without mmap",
+ "file_cache_init: MaxTotalCachedFileSize < %d, using %d",
+ "file_cache_init: MaxTotalCachedFileSize > %d, using %d",
+ "file cache using mmap flags 0x%x",
+ "file cache using mmap prots 0x%x",
+ "file-cache-init: could not create lock",
+ "file-cache: unable to create temporary directory %s.\n",
+ "file-cache: unable to create temporary directory %s.\n",
+ "file-cache: GetTempPath() Cannot find temp directory to store file!",
+ "file-cache-init: set max cached file size to %d",
+ "file-cache-init: could not create lock",
+ "file_cache_destroy()",
+ "file-cache: Unable to get temp file name. Error %s",
+ "file-cache: Unable to get temp file name. Error %s",
+ "file-cache-insert: Error allocating entry",
+ "file-cache-create: Error opening file %s (%s)",
+ "file-cache-create: Error stat()ing file %s (%s)",
+ "file-cache-create: Error mmap()ing file %s (%s)",
+ "file-cache-create: malloc failure",
+ "file-cache-create: error case failed to munmap(%d, %d) (%s)",
+ "file-cache-valid: cannot stat %s",
+ "dir change: invalidating %s (%d)",
+ "file-cache: asynchronous file change notification failed.",
+ "dir change: offset %d, action %d, len %d, name %s",
+ "unable to check async file status",
+ "ReadDirectoryChangesW failure- unable to continue watching %s. Error is %s",
+ "file-cache-add-watch failure- unable to open directory %s. Error %s",
+ "ReadDirectoryChangesW failure- unable to start watching %s. Error %s",
+ "func_exec",
+ "no handler function given for directive",
+ "func_exec",
+ "cannot find function named %s",
+ "handle-request",
+ "method without URI",
+ "http-parse-request",
+ "while scanning HTTP headers, %s",
+ "handle-request",
+ "read from %s failed, error is %s",
+ "handle-request",
+ "request too long",
+ "start-http-response",
+ "write failed (%s)",
+ "start-http-response",
+ "write failed (%s)",
+ "http-status",
+ "%d is not a valid HTTP status code",
+ "finish-request",
+ "close failed (%s)",
+ "Unable to close socket for writing",
+ "os has %d objects",
+ "obj %d has no hash table at %d",
+ "obj %d has no param",
+ "obj %d name %s value %s",
+ ".....directives %d.......",
+ ".....directive %d",
+ ".......instance %d",
+ "...........param name %s value %s",
+ "ClearConfigurationParameters:RegCreateKey %s",
+ "ClearConfigurationParameters:RegEnumKey %s failed",
+ "obj.conf line %d: error in filter file \"%s\" at line %d: %s",
+ "obj.conf line %d: error in filter file \"%s\" at line %d: %s",
+ "Unable to allocate Subject property list.\n",
+ "Unable to set session ptr in Subject property list - error=%d\n",
+ "Unable to set request ptr in Subject property list - error=%d\n",
+ "file-cache-valid: cannot stat %s",
+ "file-cache-create: Error stat()ing file %s (%s)",
+ emptyString };
+
+/* libraries in bucket for hashKey==11 */
+static struct DATABIN bucket11[] = {
+ {"frame",frame,156},
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==12 */
+static struct DATABIN bucket12[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==13 */
+static struct DATABIN bucket13[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==14 */
+static struct DATABIN bucket14[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==15 */
+static struct DATABIN bucket15[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==16 */
+static struct DATABIN bucket16[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==17 */
+static struct DATABIN bucket17[] = {
+ {emptyString,NULL,0} };
+
+/* strings in library admserv */
+static char* admservid[] = {"$DBT: admserv in memory v1 $"};
+static char* admserv[] = {
+ "",
+ "Unauthorized host",
+ "Invalid URL",
+ "no filename extension",
+ "unrecognized type",
+ "<title>Internal Error</title>\n<h1>Internal Error</h1>\nThe administration server was unable to fulfill your request.<p>\n",
+ "Reason:",
+ emptyString };
+
+/* strings in library libir */
+static char* libirid[] = {"$DBT: libadmin in memory v1 $"};
+static char* libir[] = {
+ "",
+ "An I/O error occurred before all form data could be read.",
+ emptyString };
+
+/* libraries in bucket for hashKey==18 */
+static struct DATABIN bucket18[] = {
+ {"admserv",admserv,6},
+ {"libir",libir,1},
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==19 */
+static struct DATABIN bucket19[] = {
+ {emptyString,NULL,0} };
+
+/* strings in library httpdaemon */
+static char* httpdaemonid[] = {"$DBT: httpdaemon in memory v1 $"};
+static char* httpdaemon[] = {
+ "",
+ "Error in ConvertThreadToFiber",
+ "Error in ConvertThreadToFiber",
+ "Error in md_start_system",
+ "Error in CreateFiber - idlefiber",
+ "Error in GetQueuedCompletionStatus",
+ "Error creating completion port",
+ "Could not SetHandleNonInheritable (%s)",
+ "Error accept/read new conn",
+ "Error in Respond()",
+ "Error in RespondCompleted()",
+ "daemon: unable to fork new process (%s)\n",
+ "daemon: setsid failed (%s)\n",
+ "daemon: can't log pid to %s (%s)\n",
+ "warning: could not set group id to %d (%s)\n",
+ "warning: could not set user id to %d (%s)\n",
+ "warning: daemon is running as super-user\n",
+ "could not determine current user name\n",
+ "error: chroot to %s failed (%s)\n",
+ "WARNING! Netscape executable and library have different versions.\n",
+ "startup: listening to %s://%s, port %d as %s\n",
+ "startup: listening to %s://%s, port %d as %s\n",
+ "seminit failed (%s)\n",
+ "Using single threaded accepts.",
+ "Using multi threaded accepts.",
+ "Using partial single threaded accepts.",
+ "This machine has %d processors.",
+ "Error calling thr_seconcurrency(%d)- (%s)",
+ "Set conncurrency to %d.",
+ "can't fork new process (%s)",
+ "This beta software has expired.\n",
+ "can't create IPC pipe (%s)",
+ "write to wakeup pipe failed (%s)",
+ "select thread miss",
+ "startup failure: could not bind to port %d (%s)\n",
+ "startup failure: could not bind to port %d, IP address %s (%s)\n",
+ emptyString };
+
+/* libraries in bucket for hashKey==20 */
+static struct DATABIN bucket20[] = {
+ {"httpdaemon",httpdaemon,35},
+ {emptyString,NULL,0} };
+
+/* strings in library dsgw */
+static char* dsgwid[] = {"$DBT: dsgw in memory v1 $"};
+static char* dsgw[] = {
+ "",
+ "Unknown HTTP request method",
+ "Invalid or incomplete HTML form data",
+ "Out of memory",
+ "Required query/form input is missing",
+ "Illegal character in file path",
+ "Bad or missing configuration file",
+ "Unable to initialize LDAP",
+ "An error occurred while contacting the LDAP server",
+ "Unknown search object type",
+ "Unknown attribute label",
+ "Unknown match prompt",
+ "No search filters for object type",
+ "Unable to open HTML template file",
+ "Unknown search mode - use \"smart\", \"complex\", \"pattern\", or \"auth\"",
+ "Distinguished Name missing in URL",
+ "Unknown scope in URL (should be base, sub, or one)",
+ "Unrecognized URL or unknown error",
+ "Bad URL format",
+ "Internal error",
+ "Unable to write template index file",
+ "Unable to open template index file",
+ "Unable to read directory",
+ "LDAP SSL initialization failed (check the security path)",
+ "For the Users and Groups forms to work over SSL with the Administration Server, you must at least temporarily activate SSL through the <B>Admin Preferences|Encryption On/Off</B> form",
+ "Authentication credentials not found in authentication database",
+ "Error retrieving data from the authentication database",
+ "Your authentication credentials have expired",
+ "Unable to create authentication credentials",
+ "No distinguished name was provided when retrieving credentials",
+ "Cannot open authentication database",
+ "Could not append data to the authentication database",
+ "No Directory Manager is defined",
+ "No search string was provided. Please try again",
+ "Too many arguments on one line in the config. file",
+ "Failed to initialize Windows Sockets",
+ "Authentication credentials could not be obtained from the Administration Server",
+ "Distinguished Name missing in ldapdb:// URL",
+ "Unrecognized URL or unknown error",
+ "Bad URL format",
+ "An error occurred while initializing the local LDAP database",
+ "Unknown directory service type - use \"local\" or \"remote\"",
+ "An error occurred while reading the db configuration file",
+ "NSHOME/userdb path was NULL",
+ "The directory service configuration could not be updated.",
+ "The entry could not be read from the directory.",
+ "The LDAP database could not be erased.",
+ "You may not change entries besides your own.",
+ "Problem",
+ "Authentication Problem",
+ ".\n<P>You must re-authenticate before continuing.\n",
+ ".\n<P>You must re-authenticate before continuing.\n",
+ "unknown error",
+ "The operation was successful.",
+ "An internal error occurred in the server. This usually\nindicates a serious malfunction in the server and should be\nbrought to the attention of your server administrator.",
+ "The server could not understand the request which was sent to\nit by the gateway.",
+ "A time limit was exceeded in responding to your request. If\nyou are searching for entries, you may achieve better results\nif you are more specific in your search.",
+ "A size limit was exceeded in responding to your request. If\nyou are searching for entries, you may achieve better results\nif you are more specific in your search, because too many entries\nmatched your search criteria.",
+ "The gateway attempted to authenticate to the server using\na method the server does not understand.",
+ "The gateway attempted to authenticate to the server using an\nauthentication method which the server does not support. ",
+ "Your request could not be fulfilled, probably because the server\nthat was contacted does not contain the data you are looking\nfor. It is possible that a referral to another server was\nreturned but could not be followed. If you were trying to make\nchanges to the directory, it may be that the server that holds\nthe master copy of the data is not available.",
+ "Your request exceeded an administrative limit in the server.",
+ "A critical extension that the gateway requested is not available in this server.",
+ "The server was unable to process the request, because the\nrequest referred to an attribute which does not exist in the\nentry.",
+ "The server was unable to fulfill your request, because the\nrequest violates a database constraint.",
+ "The server could not add a value to the entry, because that\nvalue is already contained in the entry.",
+ "The server could not locate the entry. If adding a new entry,\nbe sure that the parent of the entry you are trying to add exists.\nIf you received this error while searching or viewing an entry, it indicates that the\nentry which was being searched for does not exist.",
+ "A distinguished name was not in the proper format. ",
+ "The entry you attempted to authenticate as does not have a\npassword set, or is missing other required authentication\ncredentials. You cannot authenticate as that entry until the\nappropriate attributes have been added by the directory manager. ",
+ "The password (or other authentication credentials) you supplied\nis incorrect. If you just changed your password, you might try exiting your browser and connecting again.",
+ "You do not have sufficient privileges to perform the operation. ",
+ "The server is too busy to service your request. Try again\nin a few minutes.",
+ "The LDAP server could not be contacted.",
+ "The server was unwilliing to process your request. Usually,\nthis indicates that serving your request would put a heavy load\non the server. It may also indicate that the server is not\nconfigured to process your request. If searching, you may wish\nto limit the scope of your search.",
+ "The directory server could not honor your request because it\nviolates the schema requirements. Typically, this means that you\nhave not provided a value for a required field. It could also mean\nthat the schema in the directory server needs to be updated.",
+ "The directory server will not allow you to delete or rename\nan entry if that entry has children. If you wish to do this, you\nmust first delete all the child entries.",
+ "The server was unable to add a new entry, or rename an existing\nentry, because an entry by that name already exists.",
+ "Your request would affect several directory servers.",
+ "The directory server could not be contacted. Contact your\ndirectory server administrator for assistance.",
+ "An error occured while sending data to the server.",
+ "An error occured while reading data from the server.",
+ "The server did not respond to the request. \nThe request timed out.",
+ "The server does not support the authentication method used\nby the gateway.",
+ "The search filter constructed by the gateway was in error.",
+ "The operation was cancelled at your request.",
+ "An internal error occurred in the library - a parameter was\nincorrect.",
+ "A connection to the directory server could not be opened. Contact your\ndirectory server administrator for assistance.",
+ "An unknown error was encountered.",
+ "Entry Already Exists",
+ "An entry named ",
+ "onMouseOver=\"window.status='Click here to view this entry'; return true\"",
+ " already exists.<P>Please choose another name and/or location.\n<P>\n",
+ "Parent entry does not exist",
+ "You cannot add an entry by the name:<P><B>%s</B>,<P>\nbecause the parent of that entry does not exist.<P>\nBefore you can add this entry, you must first add\n",
+ "its parent.\n",
+ "an entry named:<P><B>%s</B>.\n",
+ "Warning: no authentication (continuing)...\n",
+ "%s Directory Entry",
+ "<PRE>Entry DN: %s</PRE><P>\n",
+ "Changes to <B>%s</B> have been saved.",
+ "<B>%s</B> has been added.",
+ "<B>%s</B> has been deleted.",
+ "Renamed <B>%s</B> to <B>%s</B>.",
+ "<P><B>Note:</B> because you %s the entry you were \nauthenticated as, it was necessary to discard your \nauthentication credentials. You will need to authenticate \nagain to make additional changes.\n",
+ "deleted",
+ "renamed",
+ "changed the password of",
+ "Attribute %s was changed<BR>\n",
+ " NOT ASCII (%ld bytes)\n",
+ "No values were entered. Please try again.\n",
+ "No changes were made.\n",
+ "<P>Sending %s to the directory server...\n",
+ "information",
+ "changes",
+ "<P>Successfully added entry.\n",
+ "<P>Successfully edited entry. Your changes have been saved.\n",
+ "<P>Successfully deleted entry.\n",
+ "<PRE>The new name for the entry is: %s\n</PRE><HR>\n",
+ "<P>Successfully renamed entry.\n",
+ "You must provide the old password.",
+ "You must provide a new password. Please try again",
+ "The new and confirming passwords do not match. Please try again",
+ "<BR>The %s <B>%s</B> is already in use. Please choose a different one.<BR>\n",
+ "missing form data element \"%.100s\"",
+ "Initializing config info",
+ "Cannot open file.",
+ "Malformed dbconf file.",
+ "Missing property name in dbconf file.",
+ "Out of memory.",
+ "Missing directive in dbconf file.",
+ "Cannot open config file \"%s\"",
+ "Missing argument for \"authlifetime\" directive\n",
+ "Missing argument for \"dirmgr\" directive\n",
+ "Missing argument for \"baseurl\" directive\n",
+ "Bad URL provided for \"baseurl\" directive - the base DN is missing\n",
+ "parsing baseurl directive",
+ "Bad URL provided for \"baseurl\" directive - not an \"ldap://\" URL\n",
+ "\"ldaps://\" URLs are not yet supported\n",
+ "Missing arguments for \"template\" directive\n",
+ "Missing argument for \"sslrequired\" directive\n",
+ "Unknown argument to \"sslrequired\" directive (should be \"never\", \"whenauthenticated\", \"always\")\n",
+ "Missing argument for \"securitypath\" directive\n",
+ "Missing argument for \"location-suffix\" directive\n",
+ "Three arguments are required for the \"location\" directive\n",
+ "At least two arguments are required for the \"newtype\" directive\n",
+ "Unknown location in \"newtype\" directive\n",
+ "Three or four arguments are required for the \"tmplset\" directive\n",
+ "Four arguments are required for the \"attrvset\" directive\n",
+ "Missing argument for \"charset\" directive\n",
+ "Missing argument for \"ClientLanguage\" directive\n",
+ "Missing argument for \"AdminLanguage\" directive\n",
+ "Missing argument for \"DefaultLanguage\" directive\n",
+ "Missing filename for \"include\" directive\n",
+ "Unknown directive in config file\n",
+ "<= erase_db could not open lcache.conf file \"%s\"\n",
+ "<FONT SIZE=\"+1\">\n<P>The database has been deleted. Creating new database... \n</FONT>\n ",
+ "<FONT SIZE=\"+1\">\n<P>The database could not be deleted \n</FONT>\n ",
+ "<= app_suffix could not open ldif file \"%s\"\n",
+ "<= app_suffix could not open tmp file \"%s\"\n",
+ "Unable to rename %s to %s",
+ "null pointer returned by dbconf_read_default_dbinfo().",
+ "Bad \"ldapdb\" URL - the base DN is missing\n",
+ "Bad \"ldapdb\" URL\n",
+ "Bad URL provided for \"baseurl\" directive - the base DN is missing\n",
+ "parsing baseurl directive",
+ "Bad URL provided for \"baseurl\" directive - not an \"ldap:// or ldapdb://\" URL\n",
+ "\"ldaps://\" URLs are not yet supported\n",
+ "No value given for binddn",
+ "No value given for bindpw",
+ "There is no default directory service defined in the dbswitch.conf file",
+ "Cannot open config file \"%s\" for writing",
+ "Unable to rename %s to %s",
+ "config file %s: ",
+ "config file %s: line %d: ",
+ "max %d",
+ " OK ",
+ "Close Window",
+ "Go Back",
+ "{crypt}LOCKED [%s GMT]",
+ "Return to Main",
+ "Return to Main",
+ " Help ",
+ "Help",
+ " Help ",
+ "Help is not yet available.",
+ "Help",
+ "Close Window",
+ "Close Window",
+ "missing ?template",
+ "Authenticate...",
+ "Discard authentication credentials (log out)?",
+ "You did not supply a search string",
+ "The first step in authenticating to the directory is identifying\nyourself.<br>Please type your name:",
+ "Continue",
+ "Continue",
+ "Cancel",
+ "Authenticate as directory manager\"> &nbsp(only available to Directory Administrators)\n",
+ "Authenticate...",
+ "Discard authentication credentials?",
+ "Password for <b>%s</b>: ",
+ "Continue",
+ "Continue",
+ "Cancel",
+ "Authenticate (log in) to the directory",
+ "You are about to authenticate to the directory as \n",
+ "To complete the authentication process, you should\ntype your password.\n",
+ "Before you can edit or add entries, you must authenticate\n(log in) to the directory. This window will guide\nyou through the steps of the authentication\nprocess.\n",
+ "From this screen you may authenticate, or log in, \nto the directory. You will need to authenticate\nbefore you can modify directory entries. If you\nattempt to modify an entry without authenticating,\nyou will be asked to log in.\n",
+ "Authentication Status",
+ "<form>\nYou are currently authenticated to the directory as ",
+ ".\nIf you wish to discard your authentication credentials and log out of the directory, click on the button below.",
+ "Discard Authentication Credentials (log out)",
+ "Your authentication credentials for ",
+ "have expired.\n<HR>\n",
+ "Currently, you are not authenticated to the directory.<HR>\n",
+ "missing \"%s=\"",
+ "unknown \"%s=%s\"",
+ "unknown option %s",
+ "unknown syntax=%s\n",
+ "** HTML type \"%s\" not supported **<BR>\n",
+ "no entries",
+ "1 entry",
+ "%d entries",
+ "where the ",
+ "Edit",
+ "Save Changes",
+ "modify",
+ "add",
+ "Delete",
+ "Delete this entry?",
+ "Rename",
+ "Enter a new name for this entry:",
+ "Edit As",
+ "missing %s=",
+ "Close Window",
+ "Edit...",
+ "missing \"%s=\"\n",
+ "unknown set \"%s\"\n",
+ "unknown syntax \"%s\"\n",
+ "Re-Authenticate",
+ "Close Window",
+ "Do you really want to ",
+ "?",
+ " OK ",
+ " OK ",
+ " Reset ",
+ " Done ",
+ " Cancel ",
+ "found another IF (nested IFs are not supported)",
+ "found ELSE but didn't see an IF",
+ "found ELSE after ELSE (expecting ENDIF)",
+ "found ELIF but didn't see an IF",
+ "found ELIF after ELSE (expecting ENDIF)",
+ "found ENDIF but didn't see an IF",
+ "<BR><B>template error:</B> %s<BR>\n",
+ "ldap_init/lcache_init attempted before config file read",
+ "not running under the administration server",
+ "Could not initialize permissions",
+ "Could not map username to a DN (error from admin server)",
+ "Could not get current username",
+ "Could not get current user password",
+ "Error: %s",
+ "Note: there is no display template for this type of entry available, so it is\ndisplayed below using a default method.",
+ "Invalid user id or NULL LDAP handle",
+ "no match for user id",
+ "more than one match for user id",
+ "the entire directory",
+ "Two arguments are required for the \"includeset\" directive\n",
+ "An error occurred while trying to access the database",
+ "All references to entry could not be changed",
+ "<P>Successfully removed all references to deleted entry.",
+ "<P>Successfully updated all references to renamed entry.",
+ "<P>Removing references to <B>%s</B>...",
+ "<P>Updating references to <B>%s</B>...",
+ "<P>removing %s from %s \n",
+ "The directory server could not be contacted. One common configuration error when using LDAP over SSL is that the certificate used by the directory server must be marked as trusted. Contact your directory server administrator for further assistance.",
+ "A connection to the directory server could not be opened. One common configuration error when using LDAP over SSL is that the certificate used by the directory server must be marked as trusted. Contact your directory server administrator for further assistance.",
+ "Editing",
+ "Adding",
+ "Deleting",
+ "Renaming",
+ "Servers are not configured for CAL",
+ "Cannot update config file \"%s\"\n",
+ "Missing argument for \"locationurl\" directive\n",
+ "Invalid location url\n",
+ "<= app_suffix could not parse LDIF \"%s\"\n",
+ emptyString };
+
+/* libraries in bucket for hashKey==21 */
+static struct DATABIN bucket21[] = {
+ {"dsgw",dsgw,285},
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==22 */
+static struct DATABIN bucket22[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==23 */
+static struct DATABIN bucket23[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==24 */
+static struct DATABIN bucket24[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==25 */
+static struct DATABIN bucket25[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==26 */
+static struct DATABIN bucket26[] = {
+ {emptyString,NULL,0} };
+
+/* strings in library base */
+static char* baseid[] = {"$DBT: base in memory v1 $"};
+static char* base[] = {
+ "",
+ "insufficient memory to create hash table",
+ "insufficient memory to create hash table",
+ "cache_destroy: cache tables appear corrupt.",
+ "unable to allocate hash entry",
+ "cache_insert: unable to create cache entry",
+ "HTTP/1.0 200 OK\nContent-type: text/html\n\n",
+ "<H2>Netscape cache status report</H2>\n",
+ "No caches on system<P>",
+ "<H2>%s cache</H2>\n",
+ "Cache hit ratio: %d/%d (%f)</P>\n</P>\n",
+ "Cache size: %d/%d</P>\n</P>\n",
+ "Hash table size: %d</P>\n</P>\n",
+ "mru : %d</P>\nlru : %d</P>\n",
+ "<UL><TABLE BORDER=4> <TH>Bucket</TH> <TH>Address</TH> <TH>Key</TH> <TH>Access Count</TH> <TH>Delete</TH> <TH>Next</TH> <TH>LRU</TH> <TH>MRU</TH> <TH>Data</TH>\n",
+ "munmap failed (%s)",
+ "munmap failed (%s)",
+ "close failed (%s)",
+ "daemon: unable to fork new process (%s)\n",
+ "daemon: setsid failed (%s)\n",
+ "daemon: can't log pid to %s (%s)\n",
+ "warning: could not set group id to %d (%s)\n",
+ "warning: could not set user id to %d (%s)\n",
+ "warning: daemon is running as super-user\n",
+ "could not determine current user name\n",
+ "error: chroot to %s failed (%s)\n",
+ "",
+ ", address %s",
+ "warning: statistics disabled (%s)\n",
+ "security handshake timed out for pid %d",
+ "warning: statistics disabled (%s)\n",
+ "secure handshake failed (code %d)\n",
+ "accept failed (%s)",
+ "warning: statistics disabled (%s)\n",
+ "select thread miss",
+ "keepalive worker awoken with no work to do",
+ "could not create new thread: %d (%s)",
+ "wait for sema succeeded, but nothing to dequeue",
+ "queue-sema creation failure",
+ "error getting processor info for processor %d",
+ "Error binding to processor %d",
+ "bound process %d to processor %d",
+ "Netscape server is not explicitly binding to any processors.",
+ "cache monitor exited",
+ "cache batch update daemon exited",
+ "Using single threaded accepts.",
+ "Using multi threaded accepts.",
+ "Using partial single threaded accepts.",
+ "This machine has %d processors.",
+ "Error calling thr_seconcurrency(%d)- (%s)",
+ "Set conncurrency to %d.",
+ "WARNING! Netscape executable and library have different versions.\n",
+ "",
+ "",
+ "seminit failed (%s)\n",
+ "This beta software has expired.\n",
+ "Cache monitor respawned",
+ "Cache batch update daemon respawned",
+ "can't find empty statistics slot",
+ "can't fork new process (%s)",
+ "assert failed! %s\n",
+ "mr_table_init()",
+ "malloc failed",
+ "malloc failed!",
+ "mr_add_io(%d, type %d, file %d)",
+ "mr_add_io - stage 1",
+ "mr_add_io - stage 2",
+ "mr_add_io found invalid IO type %d",
+ "mr_add_io - adding timeout",
+ "Out of memory!\n",
+ "done with mr_add_io",
+ "mr_del_io(%d, type %d, file %d)",
+ "mr_del_io found invalid IO type %d",
+ "mr_lookup_io(%d)",
+ "mr_async_io(%d, %d bytes, file %d)",
+ "malloc failure adding async IO",
+ "Error adding async io!",
+ "Cannot seek for read!",
+ "read failure! (%d, %s)",
+ "do_read read %d bytes for file %d",
+ "Cannot seek for write!",
+ "writev failure! (%d, %s)",
+ "write failure! (%d, %s)",
+ "do_write wrote %d bytes for file %d",
+ "do_timeout(mrp %d)",
+ "do_timeout: found IO (timer=%d, time=%d)",
+ "error deleting io",
+ "timeout callback failure for %d\n",
+ "mr_get_event(%d) - outstanding io %d",
+ "mr_get_event: Waiting for reads on FD:",
+ "mr_get_event: Waiting for writes on FD:",
+ " %d",
+ " %d",
+ "mr_get_event set no timeout",
+ "mr_get_event set timeout to: %d.%d sec",
+ "error in select (%d, %s)",
+ "mr_get_event() - select found %d",
+ "error looking up IO fd %d",
+ "read failed for fd %d",
+ "error deleting io",
+ "callback failure for %d\n",
+ "error looking up IO fd %d",
+ "writing: header len %d, writelen %d, total %d",
+ "write failed for fd %d",
+ "error deleting io",
+ "callback failure for %d\n",
+ "Error creating dns cache",
+ "dns_cache_init: hash_size <= 0, using %d",
+ "dns_cache_init: cache-size <= %d, using %d",
+ "dns_cache_init: cache-size is %d is too large, using %d.",
+ "dns_cache_init: expire_time <= 0, using %d",
+ "dns_cache_init: expire is %d is too large, using %d seconds.",
+ "Error creating dns cache",
+ "dns-cache-insert: Error allocating entry",
+ "dns-cache-insert: malloc failure",
+ "successful server startup",
+ "%s B%s",
+ "Netscape executable and shared library have different versions",
+ " executable version is %s",
+ " shared library version is %s",
+ "error reporting shutting down",
+ "warning",
+ "config",
+ "security",
+ "failure",
+ "catastrophe",
+ "info",
+ "verbose",
+ "event_handler:Failed to wait on events %s",
+ "could not wait on resume event event (%s)",
+ "dlopen of %s failed (%s)",
+ "dlopen of %s failed (%s)",
+ "The server is terminating due to an error. Check the event viewer for the error message. SERVER EXITING!",
+ "Terminating the server %s",
+ "kill_server:cannot open server event %s",
+ "kill_server:cannot set server event %s",
+ "error: could not get socket (%s)\n",
+ "error: could not set socket option (%s)\n",
+ "Terminating Service:error: could not bind to address %s port %d (%s)\n",
+ "Terminating Service:error: could not bind to port %d (%s)\n",
+ "SetHandleNonInheritable: could not duplicate socket (%s)",
+ "SetHandleNonInheritable: closing the original socket failed (%s)",
+ "Could not SetHandleInformation (%s)",
+ "Terminating Service:Failure: Could not open statistics file (%s)\n",
+ "Could not set Thread Local Storage Value for thread at slot %d",
+ "secure handshake failed (code %d)\n",
+ "accept failed %d (%s)",
+ "Failed to pulse Event %d %s",
+ "Failed to send MobGrowth Event to parent %s",
+ "Pulsing MobRespawn Event %d",
+ "respawn thread pool to %d (%d)",
+ "Could not open event to signal rotate application. Could not create the MoveLog event:%s",
+ "Failed to send MoveLog Event to rotate app %s",
+ "growing thread pool from %d to %d",
+ "Could not open the ServiceControlManager, Error %d",
+ "StartNetsiteService:Could not open the service %s: Error %d",
+ "StartNetsiteService:Could not start the service %s",
+ "Service Startup: Could not allocate security descriptor",
+ "Service Startup: Could not init security descriptor",
+ "Service Startup: Could not set the security Dacl",
+ "Terminating Service:WinSock init failed: %s",
+ "Httpd Server Startup failed: %s",
+ "can't find empty statistics slot",
+ "NT daemon: could not create new thread %d",
+ "Service Startup Failure. Terminating Service:Could not create event %d:%s",
+ "Service Startup Error. Could not create the MoveLog event:%s",
+ "Failed to wait on Event objects %s",
+ "Failed to wait on Event objects %s",
+ "pipebuf_buf2sd: pipebuf_grab IO_ERROR %d",
+ "pool-init: memory pools disabled",
+ "pool-init: free_size <= 0, using %d",
+ "pool-create-block: out of memory",
+ "pool-create: out of memory",
+ "pool-create: out of memory",
+ "pool-malloc: out of memory",
+ "FREE() used where PERM_FREE() should have been used- problem corrected and supressing further warnings.",
+ "regex error: %s (regex: '%s')",
+ "can't create IPC pipe (%s)",
+ "write to wakeup pipe failed (%s)",
+ "flushing %d connections; current %d; tot %d",
+ "accept failed (%s)",
+ "Error creating time cache",
+ "time-cache: cache disabled",
+ "time_cache_init: hash_size < %d, using default, %d",
+ "time_cache_init: hash_size > %d, using default, %d",
+ "time_cache_init: cache_size < %d, using default, %d",
+ "time_cache_init: cache_size > %d, using default, %d",
+ "Error allocating memory for time_cache",
+ "Error allocating memory for time_cache entry",
+ "Error allocating memory for time_cache entry",
+ "Error inserting new time_cache entry",
+ "Error allocating memory for time_cache",
+ "cs-terminate failure (%s)",
+ "cs-init failure (%s)",
+ "cs-wait failure (%s)",
+ "cs-post failure (%s)",
+ "Unable to create nonblocking socket (%s)",
+ "error: could not set keepalive (%s)\n",
+ "error: could not set recv timeout (%s)\n",
+ "error: could not set send timeout (%s)\n",
+ "Unable to create nonblocking socket (%s)",
+ "sem_grab failed (%s)",
+ "sem_release failed (%s)",
+ "sem_release failed (%s)",
+ "Could not remove temporary directory %s, Error %d",
+ "Could not remove temporary directory %s, Error %d",
+ emptyString };
+
+/* libraries in bucket for hashKey==27 */
+static struct DATABIN bucket27[] = {
+ {"base",base,205},
+ {emptyString,NULL,0} };
+
+/* strings in library cgiadmin */
+static char* cgiadminid[] = {"$DBT: cgiadmin in memory v1 $"};
+static char* cgiadmin[] = {
+ "",
+ "Missing REQUEST_METHOD",
+ "This should only be invoked as CGI program",
+ "Missing ADMSERV_ROOT",
+ "This should only be invoked as CGI program",
+ "Unrecognized request type.",
+ "Startup",
+ "Failed to initialize WinSock",
+ "Bad file",
+ "Expected servers.lst",
+ "Cluster: merge product.lst from %s",
+ "<i>Obtaining product information from %s://%s:%d</i><br>\n",
+ "Updated %s<BR>\n",
+ "Bad file",
+ "Expected servers-instance.lst",
+ "Warning: %s already exists, information not added<BR>\n",
+ "Error: failed to create file %s<BR>\n",
+ "Warning: directory %s will be removed because of above error<BR>\n",
+ "",
+ "Error: %s %s (errno = %d)<BR>\n",
+ "Error: %s %s, %s<BR>\n",
+ "ALLOW ALL OPERATIONS",
+ "ALLOW GET OPERATIONS",
+ "ALLOW SET OPERATIONS",
+ "You accessed this form with an invalid query string.",
+ "community has been removed.",
+ "Community Strings",
+ "Edit a Community",
+ "Add Another Community",
+ "",
+ "Edit",
+ "Remove",
+ "Do you really want to remove this entry?",
+ "<b>Community:</b> %s\n",
+ "<br><b>Operation:</b> %s\n",
+ "No communities exist.",
+ "You should enter a community string.",
+ "You should enter operation you want for this community.",
+ "the community entry has been changed",
+ "%s has been added",
+ "fails to start up master agent",
+ "Please refer to documents to start it",
+ "master agent start up",
+ "can't open config file",
+ "open temp file fails",
+ "open CONFIG fails",
+ "open CONFIG fails",
+ "No permission to start master agent",
+ "You must be running as super user. Please refer to documents",
+ "can't get tcp protocol entry\n",
+ "can't create a sockect",
+ "Please refer to documents for its configuration",
+ "a smux master agent is running or the smux port is not free yet",
+ "Please refer to documents for its configuration",
+ "can't get udp protocol entry\n",
+ "can't create a socket",
+ "Please refer to documents for its configuration",
+ "a snmpd is running or snmp port is not free yet",
+ "Please refer to documents for its configuration",
+ "can't get udp protocol entry\n",
+ "can't create a socket",
+ "Please refer to documents for its configuration",
+ "Fail to start",
+ "Please refer to documents for its configuration",
+ emptyString };
+
+/* libraries in bucket for hashKey==28 */
+static struct DATABIN bucket28[] = {
+ {"cgiadmin",cgiadmin,63},
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==29 */
+static struct DATABIN bucket29[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==30 */
+static struct DATABIN bucket30[] = {
+ {emptyString,NULL,0} };
+
+/* libraries in bucket for hashKey==31 */
+static struct DATABIN bucket31[] = {
+ {emptyString,NULL,0} };
+
+/* array of bucket pointers */
+static struct DATABIN* buckets[32] = {
+ bucket0,
+ bucket1,
+ bucket2,
+ bucket3,
+ bucket4,
+ bucket5,
+ bucket6,
+ bucket7,
+ bucket8,
+ bucket9,
+ bucket10,
+ bucket11,
+ bucket12,
+ bucket13,
+ bucket14,
+ bucket15,
+ bucket16,
+ bucket17,
+ bucket18,
+ bucket19,
+ bucket20,
+ bucket21,
+ bucket22,
+ bucket23,
+ bucket24,
+ bucket25,
+ bucket26,
+ bucket27,
+ bucket28,
+ bucket29,
+ bucket30,
+ bucket31 };
diff --git a/lib/libsi18n/getstrprop.c b/lib/libsi18n/getstrprop.c
new file mode 100644
index 00000000..6b21fdd5
--- /dev/null
+++ b/lib/libsi18n/getstrprop.c
@@ -0,0 +1,137 @@
+/** 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 <string.h>
+#include <stdlib.h>
+
+#include "i18n.h"
+
+#include "getstrmem.h"
+
+#include "libadminutil/resource.h"
+#include "coreres.h"
+
+Resource *hResource = NULL;
+char empty_string[] = "";
+
+char*
+XP_GetStringFromMemory(char* strLibraryName,int iToken);
+
+
+
+void
+XP_InitStringDatabase(char* pathCWD, char* databaseName)
+{
+ hResource = core_res_init_resource (pathCWD, databaseName);
+}
+
+char *XP_GetPropertyString(char* strLibraryName,int iToken, ACCEPT_LANGUAGE_LIST lang)
+{
+ char *key_name;
+ char *result = NULL;
+
+ if (hResource == NULL)
+ return NULL;
+
+ /*creating the key*/
+ key_name=(char*)malloc(strlen(strLibraryName) + 10);
+ sprintf(key_name, "%s-%d", strLibraryName, iToken);
+ if(key_name == NULL)
+ return NULL;
+
+ result = (char *) core_res_getstring(hResource, key_name, lang) ;
+
+ if (key_name)
+ free (key_name);
+
+ if (result == NULL)
+ return empty_string;
+ else
+ return result ;
+}
+
+char*
+XP_GetStringFromDatabase(char* strLibraryName,
+ char* strLanguage,
+ int key)
+{
+ char *result = NULL;
+ ACCEPT_LANGUAGE_LIST alanglist;
+ int n;
+
+ /*
+ * display first choice language if available, otherwise
+ * use default which is english in most case
+ */
+ if (hResource) {
+ n = XP_AccLangList (strLanguage, alanglist);
+ if (n >= MAX_ACCEPT_LANGUAGE)
+ alanglist[MAX_ACCEPT_LANGUAGE-1][0] = '\0';
+ else
+ alanglist[n][0] = '\0';
+ result = XP_GetPropertyString(strLibraryName, key, alanglist);
+ }
+
+ /* we should never come here. */
+ if (result == NULL)
+ result = XP_GetStringFromMemory(strLibraryName,key);
+ return result;
+}
+
+
+char*
+XP_GetStringFromMemory(char* strLibraryName,int iToken)
+{
+ /*
+ * In memory model called by XP_GetStringFromDatabase
+ * does not use database (nsres, et al.).
+ *
+ * This function uses hash table for library lookup
+ * and direct lookup for string.
+ *
+ * This function is thread safe.
+ */
+
+
+ unsigned hashKey;
+ int found = 0;
+ unsigned uToken = iToken;
+ char* cPtr;
+ DATABIN* pBucket;
+
+ /* calculate hash key */
+ hashKey = 0;
+ cPtr = strLibraryName;
+ while (*cPtr) {
+ hashKey += *(cPtr++);
+ }
+ hashKey &= BUCKET_MASK;
+
+ /* get bucket for this hash key */
+ pBucket = buckets[hashKey];
+
+ /* search overflow buckets */
+ while (*(pBucket->pLibraryName)!='\0') {
+ if (strcmp(pBucket->pLibraryName,strLibraryName)==0) {
+ found = 1;
+ break;
+ }
+ pBucket++;
+ }
+
+ if (!found) {
+ return emptyString;
+ }
+
+ if (uToken<=pBucket->numberOfStringsInLibrary) {
+ return pBucket->pArrayOfLibraryStrings[uToken];
+ } else {
+ /* string token out of range */
+ return emptyString;
+ }
+
+}
diff --git a/lib/libsi18n/gsslapd.h b/lib/libsi18n/gsslapd.h
new file mode 100644
index 00000000..bbb44454
--- /dev/null
+++ b/lib/libsi18n/gsslapd.h
@@ -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 **/
+
+#define DATABASE_NAME "ns-slapd"
+
+#ifdef RESOURCE_STR
+
+#undef LIBRARY_NAME
+#include "base/dbtbase.h"
+#undef LIBRARY_NAME
+#include "frame/dbtframe.h"
+#undef LIBRARY_NAME
+#include "httpdaemon/dbthttpdaemon.h"
+#undef LIBRARY_NAME
+#include "libaccess/dbtlibaccess.h"
+#undef LIBRARY_NAME
+#include "libadmin/dbtlibadmin.h"
+#undef LIBRARY_NAME
+#include "libir/dbtlibir.h"
+#undef LIBRARY_NAME
+#include "../ldap/clients/dsgw/dbtdsgw.h"
+
+static RESOURCE_GLOBAL allxpstr[] = {
+ base,
+ frame,
+ httpdaemon,
+ libaccess,
+ libadmin,
+ libir,
+ dsgw,
+ 0
+};
+
+#endif /* ifdef RESOURCE_STR */
diff --git a/lib/libsi18n/makstrdb.c b/lib/libsi18n/makstrdb.c
new file mode 100644
index 00000000..6f8b78dd
--- /dev/null
+++ b/lib/libsi18n/makstrdb.c
@@ -0,0 +1,221 @@
+/** 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 <string.h>
+#include <stdlib.h>
+
+#include "netsite.h"
+#ifdef BERKELEY_DB_RESOURCE
+#include "mcom_db.h"
+#include "nsres.h"
+#endif
+
+#define RESOURCE_STR
+
+/********************************************/
+/* Begin: Application dependent information */
+/********************************************/
+
+#ifdef MCC_ADMSERV
+#include "gsadmserv.h"
+#define GSXXX_H_INCLUDED
+#endif
+
+#ifdef NS_ENTERPRISE
+#include "gshttpd.h"
+#define GSXXX_H_INCLUDED
+#endif
+
+#ifdef NS_DS
+#include "gsslapd.h"
+#define GSXXX_H_INCLUDED
+#endif
+
+#ifdef NS_PERSONAL
+#include "gshttpd.h"
+#define GSXXX_H_INCLUDED
+#endif
+
+#ifdef MCC_PROXY
+#include "gsproxy.h"
+#define GSXXX_H_INCLUDED
+#endif
+
+#ifdef buildAnotherServer
+#include "gsanother.h"
+#define GSXXX_H_INCLUDED
+#endif
+
+/********************************************/
+/* End: Application dependent information */
+/********************************************/
+
+/**********************************************/
+/* Begin: Check that BUILD_MODULE is handled */
+/* and a gs*.h file has been included */
+/**********************************************/
+
+#ifndef GSXXX_H_INCLUDED
+#error Error in makstrdb.c: BUILD_MODULE not handled; gs*.h not included.
+#endif
+
+/********************************************/
+/* End: Check that BUILD_MODULE is handled */
+/* and a gs*.h file has been included */
+/********************************************/
+
+/*******************************************************************************/
+
+#ifdef XP_DEBUG
+
+void
+XP_PrintStringDatabase(void) /* debug routine */
+{
+ int i;
+ int j;
+ char* LibraryName;
+ RESOURCE_TABLE* table;
+
+ j = 0;
+ while (table=allxpstr[j++].restable) {
+ LibraryName = table->str;
+ printf("Library %d: %s\n",j,LibraryName);
+ i = 1;
+ table++;
+ while (table->str) {
+ printf("%d: %s %d \"%s\"\n",i,LibraryName,table->id,table->str);
+ i++;
+ table++;
+ }
+ }
+}
+
+#endif /* XP_DEBUG */
+
+#ifdef BERKELEY_DB_RESOURCE
+/*******************************************************************************/
+
+int
+XP_MakeStringDatabase(void)
+{
+ int j;
+ char* LibraryName;
+ char* cptr;
+ RESOURCE_TABLE* table;
+ NSRESHANDLE hresdb;
+ char DBTlibraryName[128];
+
+ /* Creating database */
+ hresdb = NSResCreateTable(DATABASE_NAME, NULL);
+ if (hresdb==0) {
+ printf("Error creating database %s\n",DATABASE_NAME);
+ return 1;
+ }
+
+ j = 0;
+ while (table=allxpstr[j++].restable) {
+ LibraryName = table->str;
+ printf("Add Library %d: %s\n",j,LibraryName);
+ table++;
+ while (table->str) {
+ if (table->id==-1 && strstr(table->str,"$DBT: ")) {
+ cptr = strstr(table->str,"referenced");
+ if (cptr) {
+ strncpy(cptr,"in DB file",10);
+ }
+ }
+ NSResAddString(hresdb,LibraryName,table->id,table->str,0);
+ table++;
+ }
+ }
+
+ NSResCloseTable(hresdb);
+ return 0;
+}
+#endif
+
+/*******************************************************************************/
+
+int
+XP_MakeStringProperties(void)
+{
+ int j;
+ char* LibraryName;
+ char* cptr;
+ RESOURCE_TABLE* table;
+ FILE *hresfile;
+ char buffer[2000];
+ char *src, *dest;
+ char *dbfile;
+
+ /* Creating database */
+ dbfile = (char *) malloc (strlen(DATABASE_NAME) + 20);
+ strcpy(dbfile, DATABASE_NAME);
+ strcat(dbfile, ".properties");
+
+ hresfile = fopen(dbfile, "w");
+
+ if (hresfile==NULL) {
+ printf("Error creating properties file %s\n",DATABASE_NAME);
+ return 1;
+ }
+
+ j = 0;
+ while (table=allxpstr[j++].restable) {
+ LibraryName = table->str;
+ fprintf(hresfile, "\n");
+ fprintf(hresfile, "#######################################\n");
+ fprintf(hresfile, "############### %s ###############\n", LibraryName);
+ printf("Add Library %d: %s\n",j,LibraryName);
+ table++;
+ while (table->str) {
+ /*
+ Change special char to \uXXXX
+ */
+ src = table->str;
+ dest = buffer;
+ while (*src) {
+ if (*src < 0x20) {
+ strcpy(dest,"\\u00");
+ dest += 4;
+ sprintf(dest, "%02x", *src);
+ dest += 1;
+ }
+ else {
+ *dest = *src;
+ }
+ src ++;
+ dest ++;
+ }
+ *dest = '\0';
+
+ if (table->id > 0) {
+ fprintf(hresfile, "%s-%d =%s\n", LibraryName, table->id, buffer);
+ }
+ table++;
+ }
+ }
+
+ fclose(hresfile);
+ return 0;
+}
+
+
+
+
+/*******************************************************************************/
+
+int main()
+{
+#if 0
+ return XP_MakeStringDatabase();
+#else
+ return XP_MakeStringProperties();
+#endif
+}
+
+/*******************************************************************************/
diff --git a/lib/libsi18n/propset.c b/lib/libsi18n/propset.c
new file mode 100644
index 00000000..350bbe67
--- /dev/null
+++ b/lib/libsi18n/propset.c
@@ -0,0 +1,404 @@
+/** 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 <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include "i18n.h"
+
+#include "txtfile.h"
+#include "reshash.h"
+#include "propset.h"
+
+int PropertiesLoadFileToHash(PropertiesSet *propset, char *language);
+char *GetProertiesFilename(char *directory, char *file, char *language);
+int PropertiesLanguageStatus(PropertiesSet *propset, char *language);
+int PropertiesSetLangStatus(LanguageStatus *langstatus, char *language, int status);
+int unicode_to_UTF8(unsigned int wch, char *utf8);
+char *decode_ascii(char *src);
+
+
+PropertiesSet * PropertiesInit(char *directory, char *file)
+{
+ struct stat buf;
+ char * file_path;
+ PropertiesSet *propset = NULL;
+ PropertiesSet *result = NULL;
+ ResHash *reshash;
+
+ file_path = (char *) malloc (strlen(directory) + strlen(file) + 20);
+
+ strcpy(file_path, directory);
+ strcat(file_path, "/");
+ strcat(file_path, file);
+ strcat(file_path, ".properties");
+
+ if (stat(file_path, &buf) == 0) {
+ propset = (PropertiesSet *) malloc(sizeof(PropertiesSet));
+ memset(propset, 0, sizeof(PropertiesSet));
+ reshash = (ResHash *) ResHashCreate(file);
+
+ if (reshash) {
+ propset->langlist = (LanguageStatus *) malloc(sizeof(LanguageStatus));
+ memset(propset->langlist, 0, sizeof(LanguageStatus));
+
+ propset->res = reshash;
+ propset->directory = strdup(directory);
+ propset->filename = strdup(file);
+ PropertiesLoadFileToHash(propset, NULL);
+ result = propset;
+ }
+ }
+
+ if (file_path)
+ free (file_path);
+
+ return result;
+}
+
+
+char *GetProertiesFilename(char *directory, char *file, char *language)
+{
+ char *filepath;
+
+ if (language && *language == '\0')
+ filepath = (char *) malloc(strlen(directory) + strlen(file) + strlen(language) + 20);
+ else
+ filepath = (char *) malloc(strlen(directory) + strlen(file) + 20);
+
+ strcpy(filepath, directory);
+ if (filepath[strlen(filepath) - 1] != '/')
+ strcat(filepath, "/");
+ strcat(filepath, file);
+ if (language && *language != '\0') {
+ strcat(filepath, "_");
+ strcat(filepath, language);
+ }
+ strcat(filepath, ".properties");
+
+ return filepath;
+}
+
+/*
+ PropertiesLoadToHash
+
+ Opens property file and save data to hash table
+
+ Input
+ propfile: handle
+ file: full path with file extension
+
+ return:
+ 0: SUCCESS
+ 1: FAIL
+*/
+
+int PropertiesLoadFileToHash(PropertiesSet *propset, char *language)
+{
+ TEXTFILE *hfile;
+ char *filepath;
+ char *p, *q;
+ int n;
+ char linebuf[1000];
+ int st;
+
+ st = PropertiesLanguageStatus(propset, language);
+ if (st == LANGUAGE_INVALID)
+ return 1;
+ else if (st == LANGUAGE_LOAD)
+ return 0;
+
+ filepath = GetProertiesFilename(propset->directory, propset->filename, language);
+
+ if ((hfile = OpenTextFile (filepath, TEXT_OPEN_FOR_READ)) == NULL) {
+ PropertiesSetLangStatus(propset->langlist, language, LANGUAGE_INVALID);
+ return 1;
+ }
+
+ while ((n = ReadTextLine(hfile, linebuf)) >= 0) {
+ if (n == 0)
+ continue;
+
+ p = linebuf;
+ /* strip leading spaces */
+ while (*p == ' ' || *p == '\t')
+ p ++;
+ /* skip comment line */
+ if (*p == '\0' || *p == '#' || *p == '=')
+ continue;
+
+ q = strchr (linebuf, '=');
+ if (q) {
+ char *key, *value, *newvalue;
+
+ *q = '\0';
+ key = p;
+ value = q + 1;
+ /* strip trailing space for key */
+ p = key + strlen(key) - 1;
+ while (*p == ' ' || *p == '\t') {
+ *p = '\0';
+ p --;
+ }
+
+ /* decode Unicode escape value */
+ newvalue = decode_ascii(value);
+
+ if (newvalue) {
+ ResHashAdd(propset->res, key, newvalue, language);
+ free(newvalue);
+ }
+ else
+ ResHashAdd(propset->res, key, value, language);
+ }
+ }
+ PropertiesSetLangStatus(propset->langlist, language, LANGUAGE_LOAD);
+ return 0;
+}
+
+/*
+ PropertiesIsLoaded
+
+ Test if current properties associated with language
+ is loaded or not.
+
+ return:
+ 1: SUCCESS
+ 0: FAIL
+ */
+
+int PropertiesLanguageStatus(PropertiesSet *propset, char *language)
+{
+ LanguageStatus *plang;
+
+ plang = propset->langlist;
+ if (language == NULL || *language == '\0') {
+ return plang->status;
+ }
+
+ plang = plang->next;
+
+ while (plang) {
+ if (strcmp(plang->language, language) == 0) {
+ return plang->status;
+ }
+ plang = plang->next;
+ }
+ return LANGUAGE_NONE;
+}
+
+int PropertiesSetLangStatus(LanguageStatus *langlist, char *language, int status)
+{
+ LanguageStatus *plang, *prev;
+ LanguageStatus *langstatus;
+
+ if (language == NULL || *language == '\0') {
+ langlist->status = status;
+ return 0;
+ }
+
+ prev = plang = langlist;
+ plang = plang->next;
+
+ while (plang) {
+ if (strcmp(plang->language, language) == 0) {
+ plang->status = status;
+ return 0;
+ }
+ prev = plang;
+ plang = plang->next;
+ }
+
+ langstatus = (LanguageStatus *) malloc(sizeof(LanguageStatus));
+ memset (langstatus, 0, sizeof(LanguageStatus));
+ langstatus->language = strdup(language);
+ langstatus->status = status;
+ prev->next = langstatus;
+
+ return 0;
+}
+
+
+/***
+ PropertiesOpenFile
+
+ return 0: loaded
+ 1: fail to load file associated with the language
+
+
+ */
+int PropertiesOpenFile(PropertiesSet *propset, char *language)
+{
+ int status;
+ status = PropertiesLanguageStatus(propset, language);
+
+ if (status == LANGUAGE_NONE)
+ return PropertiesLoadFileToHash (propset, language);
+ else if (status == LANGUAGE_INVALID)
+ return 1;
+ else
+ return 0;
+}
+
+const char *PropertiesGetString(PropertiesSet *propset, char *key, ACCEPT_LANGUAGE_LIST acceptlangauge)
+{
+ int i;
+ char *language = NULL;
+
+ i = 0;
+ while (acceptlangauge[i][0]) {
+ if (PropertiesOpenFile(propset, acceptlangauge[i]) == 0) {
+ language = acceptlangauge[i];
+ break;
+ }
+ i ++;
+ }
+
+ return ResHashSearch(propset->res, key, language);
+}
+void PropertiesDestroy(PropertiesSet *propset)
+{
+ LanguageStatus *langattrib, *next;
+
+ if (propset) {
+ if (propset->path)
+ free(propset->path);
+ if (propset->directory)
+ free(propset->directory);
+ if (propset->filename)
+ free(propset->filename);
+
+ ResHashDestroy(propset->res);
+
+ langattrib = propset->langlist;
+ while (langattrib) {
+ next = langattrib->next;
+ if (langattrib->language)
+ free(langattrib->language);
+ free(langattrib);
+ langattrib = next;
+ }
+ }
+}
+
+
+char *decode_ascii(char *src)
+{
+ int i;
+ char utf8[10];
+ int state = 0;
+ int digit = 0;
+ int digit_count = 0;
+ char *result, *p, *q;
+
+ if (src == NULL || *src == '\0')
+ return NULL;
+
+ if (strchr(src, '\\') == NULL)
+ return NULL;
+
+ result = (char *) malloc(strlen(src) + 1);
+
+ p = src;
+ q = result;
+
+ for (;*p; p++) {
+ char ch;
+ int n;
+ if (state == BACKSLASH_U) {
+ ch = toupper(*p);
+ if (ch >= '0' && ch <= '9') {
+ digit = digit * 16 + (ch - '0');
+ digit_count ++;
+ }
+ else if (ch >= 'A' && ch <= 'F') {
+ digit = digit * 16 + (ch - 'A' + 10);
+ digit_count ++;
+ }
+ else {
+ n = unicode_to_UTF8(digit, utf8);
+ for (i = 0; i < n; i++)
+ *q ++ = utf8[i];
+ *q ++ = *p;
+ state = 0;
+ digit_count = 0;
+ }
+
+ if (digit_count == 4) {
+ n = unicode_to_UTF8(digit, utf8);
+ for (i = 0; i < n; i++)
+ *q ++ = utf8[i];
+ state = 0;
+ }
+ }
+ else if (state == BACKSLASH) {
+ if (*p == 'u') {
+ state = BACKSLASH_U;
+ digit = 0;
+ digit_count = 0;
+ continue;
+ }
+ else if (*p == 'n') {
+ *q++ = '\n';
+ state = 0;
+ }
+ else if (*p == 'r') {
+ *q++ = '\r';
+ state = 0;
+ }
+ else {
+ *q++ = '\\';
+ *q++ = *p;
+ state = 0;
+ }
+ }
+ else if (*p == '\\') {
+ state = BACKSLASH;
+ continue;
+ }
+ else {
+ *q++ = *p;
+ state = 0;
+ }
+ }
+ *q = '\0';
+ return result;
+}
+
+
+int unicode_to_UTF8(unsigned int wch, char *utf8)
+{
+ unsigned char hibyte, lobyte, mibyte;
+
+ if (wch <= 0x7F) {
+ /* 0000 007F ==> 0xxxxxxx */
+ utf8[0] = (unsigned char) wch ;
+ utf8[1] = '\0';
+ return 1;
+ }
+ else if (wch <= 0x7FF) {
+ /* 0000 07FF ==> 110xxxxx 10xxxxxx */
+ lobyte = wch & 0x3F;
+ hibyte = (wch >> 6) & 0x1F;
+
+ utf8[0] = 0xC0 | hibyte;
+ utf8[1] = 0x80 | lobyte;
+ utf8[2] = '\0';
+ return 2;
+ }
+ else {
+ /* FFFF ==> 1110xxxx 10xxxxxx 10xxxxxx */
+ lobyte = wch & 0x3F;
+ mibyte = (wch >> 6) & 0x3F;
+ hibyte = (wch >> 12) & 0xF;
+
+ utf8[0] = 0xE0 | hibyte;
+ utf8[1] = 0x80 | mibyte;
+ utf8[2] = 0x80 | lobyte;
+ utf8[3] = '\0';
+ return 3;
+ }
+}
diff --git a/lib/libsi18n/propset.h b/lib/libsi18n/propset.h
new file mode 100644
index 00000000..f7322669
--- /dev/null
+++ b/lib/libsi18n/propset.h
@@ -0,0 +1,43 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef PROPSET_H
+#define PROPSET_H
+
+#include "reshash.h"
+
+
+enum {
+ LANGUAGE_NONE = 0,
+ LANGUAGE_LOAD,
+ LANGUAGE_INVALID
+} ;
+
+enum {
+ BACKSLASH = 1,
+ BACKSLASH_U
+};
+
+
+typedef struct LanguageStatusS {
+ char *language;
+ int status;
+ struct LanguageStatusS *next;
+} LanguageStatus;
+
+typedef struct PropertiesSet {
+ char *path;
+ char *directory;
+ char *filename;
+ LanguageStatus *langlist;
+ ResHash *res;
+} PropertiesSet;
+
+
+PropertiesSet * PropertiesInit(char *directory, char *file);
+const char *PropertiesGetString(PropertiesSet *propset, char *key, ACCEPT_LANGUAGE_LIST acceptlangauge);
+void PropertiesDestroy(PropertiesSet *propfile);
+
+#endif
diff --git a/lib/libsi18n/reshash.c b/lib/libsi18n/reshash.c
new file mode 100644
index 00000000..55740e19
--- /dev/null
+++ b/lib/libsi18n/reshash.c
@@ -0,0 +1,264 @@
+/** 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 <stdlib.h>
+#include <string.h>
+
+#include "reshash.h"
+
+/* ======================== Value with Language list ==================== */
+int ValueAddLanguageItem(ValueNode *node, char *value, char *language)
+{
+ ValueNode *prev, *pvalue;
+
+ if (node == NULL)
+ return 0;
+ if (language == NULL || *language == '\0') {
+ /* should be added to default value */
+ return 0;
+ }
+
+ prev = pvalue = node;
+ while (pvalue != NULL) {
+ if ((pvalue->language == NULL) ||
+ (strcmp(pvalue->language,language) == 0)) {
+ /* if value for the language is already there
+ replace it with latest one.
+ */
+ if (pvalue->language == NULL)
+ pvalue->language = strdup(language);
+ if (pvalue->value)
+ free(pvalue->value);
+ pvalue->value = strdup(value);
+ return 0;
+ }
+ prev = pvalue;
+ pvalue = pvalue->next;
+ }
+ pvalue = (ValueNode *) malloc(sizeof(ValueNode));
+ memset(pvalue, 0, sizeof(ValueNode));
+
+ prev->next = pvalue;
+
+ pvalue->language = strdup(language);
+ pvalue->value = strdup(value);
+ return 0;
+}
+
+const char *ValueSearchItem(ValueNode *node, char *language)
+{
+ ValueNode *pvalue;
+
+ if (node == NULL)
+ return NULL;
+
+ pvalue = node;
+ while (pvalue && pvalue->language) {
+ if (strcmp(pvalue->language,language) == 0) {
+ return pvalue->value;
+ }
+ pvalue = pvalue->next;
+ }
+ return NULL;
+}
+
+void ValueDestroy(ValueNode *node)
+{
+ ValueNode *p, *current;
+ p = node;
+ /* free itself and go next */
+ while (p) {
+ current = p;
+ p = p->next;
+ if (current->language)
+ free (current->language);
+ if (current->value)
+ free (current->value);
+ }
+}
+
+/* ======================== End of Value with Language list ==================== */
+
+
+
+/* ======================== Tree List Implementation============================ */
+
+const char * TreeSearchItem(TreeNode *res, char *key, char *language)
+{
+ int k;
+ const char *result;
+
+ if (res == NULL || res->key == NULL)
+ return NULL;
+
+ k = strcmp(key, res->key);
+
+ if (k > 0) {
+ return TreeSearchItem(res->right, key, language);
+ }
+ else if (k < 0) {
+ return TreeSearchItem(res->left, key, language);
+ }
+ else {
+ /* Add to the current node; */
+ if (language == NULL || *language == '\0')
+ return res->value;
+
+ result = ValueSearchItem(res->vlist, language);
+ if (result)
+ return result;
+ else /* fallback to default value if there is any */
+ return res->value;
+ }
+}
+
+/*
+ TreeAddItem
+ Add value for specific language to the resource tree
+
+ Using binary tree now --> Balanced tree later
+ */
+int TreeAddItem(TreeNode *res, char *key, char *value, char *language)
+{
+ TreeNode *node;
+ ValueNode *vnode;
+ int k;
+
+ if (res->key == NULL) {
+ res->key = strdup(key);
+ k = 0;
+ }
+ else {
+ k = strcmp(key, res->key);
+ }
+
+ if (k > 0) {
+ if (res->right == NULL) {
+ /* Create node and it's value sub list
+ */
+ node = (TreeNode *) malloc (sizeof(TreeNode));
+ memset(node, 0, sizeof(TreeNode));
+ vnode = (ValueNode *) malloc(sizeof(ValueNode));
+ memset(vnode, 0, sizeof(ValueNode));
+ node->vlist = vnode;
+
+ res->right = node;
+
+ /* assign value to node */
+ node->key = strdup(key);
+ if (language == NULL)
+ node->value = strdup(value);
+ else
+ ValueAddLanguageItem(node->vlist, value, language);
+ }
+ else {
+ return TreeAddItem(res->right, key, value, language);
+ }
+ }
+ else if (k < 0) {
+ if (res->left == NULL) {
+ node = (TreeNode *) malloc (sizeof(TreeNode));
+ memset(node, 0, sizeof(TreeNode));
+ vnode = (ValueNode *) malloc(sizeof(ValueNode));
+ memset(vnode, 0, sizeof(ValueNode));
+ node->vlist = vnode;
+
+ res->left = node;
+
+ /* assign value to node */
+ node->key = strdup(key);
+ if (language == NULL)
+ node->value = strdup(value);
+ else
+ return ValueAddLanguageItem(node->vlist, value, language);
+ }
+ else {
+ return TreeAddItem(res->left, key, value, language);
+ }
+ }
+ else {
+ /* Add to the current node; */
+ if (language == NULL)
+ res->value = strdup(value);
+ else
+ return ValueAddLanguageItem(res->vlist, value, language);
+ }
+ return 0;
+}
+
+void TreeDestroy(TreeNode *tree)
+{
+ if (tree == NULL)
+ return;
+ if (tree->vlist)
+ ValueDestroy(tree->vlist);
+ if (tree->key)
+ free(tree->key);
+ if (tree->value)
+ free(tree->value);
+ if (tree->left)
+ TreeDestroy(tree->left);
+ if (tree->right)
+ TreeDestroy(tree->right);
+}
+
+/* ====================== End of Tree implementation ================= */
+
+
+/* ====================== Tree controller (hash ?) ================ */
+ResHash * ResHashCreate(char * name)
+{
+ ResHash *pResHash;
+
+ /* Create hash table */
+ pResHash = (ResHash *) malloc (sizeof(ResHash));
+ if (pResHash == NULL)
+ return NULL;
+
+ memset(pResHash, 0, sizeof(ResHash));
+
+ if (name)
+ pResHash->name = strdup(name);
+
+ /* Create initial tree item and it's valuelist to hash table */
+ pResHash->treelist = (TreeNode *) malloc(sizeof(TreeNode));
+ if (pResHash->treelist)
+ memset(pResHash->treelist, 0, sizeof(TreeNode));
+ pResHash->treelist->vlist = (ValueNode *) malloc(sizeof(ValueNode));
+ memset(pResHash->treelist->vlist, 0, sizeof(ValueNode));
+
+ return pResHash;
+}
+
+int ResHashAdd(ResHash *res, char *key, char *value, char *language)
+{
+#if 0
+ hash = get hash value from key
+ tree = find the tree associated with hash value
+#endif
+ return TreeAddItem(res->treelist, key, value, language);
+}
+
+const char *ResHashSearch(ResHash *res, char *key, char *language)
+{
+#if 0
+ hash = get hash value from key
+ tree = find the tree associated with hash value
+#endif
+ return TreeSearchItem(res->treelist, key, language);
+}
+
+void ResHashDestroy(ResHash *res)
+{
+ if (res == NULL)
+ return;
+ if (res->name)
+ free(res->name);
+ if (res->treelist)
+ TreeDestroy(res->treelist);
+}
+
+/* ========================= End of Tree controller ====================== */
diff --git a/lib/libsi18n/reshash.h b/lib/libsi18n/reshash.h
new file mode 100644
index 00000000..b2b7d797
--- /dev/null
+++ b/lib/libsi18n/reshash.h
@@ -0,0 +1,54 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef RESHASH_H
+#define RESHASH_H
+/**********************************************************************
+ Hash --> Tree --> ValueList
+
+ ValueList: language per item, each list associated with one key
+ Tree: contains multiple keys
+ Hash: Based on hash to decide withc tree to use for lookup
+
+***********************************************************************/
+
+/*
+ Valuelist, each item contains
+ language: ISO two or four letters
+ value: UTF-8 encoding strings
+ */
+typedef struct ValueNode {
+ char *language;
+ char *value;
+ struct ValueNode *next;
+} ValueNode;
+
+
+/*
+ Current: BINARY TREE
+ Future: balanced tree for high search performance
+ */
+typedef struct TreeNodeStruct {
+ ValueNode *vlist;
+ char *key;
+ char *value;
+ struct TreeNodeStruct *left;
+ struct TreeNodeStruct *right;
+} TreeNode;
+
+
+typedef struct ResHash {
+ char *name; /* name of hash table */
+ TreeNode *treelist;
+} ResHash;
+
+
+ResHash * ResHashCreate(char * name);
+int ResHashAdd(ResHash *res, char *key, char *value, char *language);
+const char *ResHashSearch(ResHash *res, char *key, char *language);
+void ResHashDestroy(ResHash *res);
+
+#endif
+
diff --git a/lib/libsi18n/txtfile.c b/lib/libsi18n/txtfile.c
new file mode 100644
index 00000000..a88d1672
--- /dev/null
+++ b/lib/libsi18n/txtfile.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 **/
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+
+#include "txtfile.h"
+
+
+
+#if 0
+char fileBuffer[FILE_BUFFER_SIZE + 1];
+char *fbCurrent;
+int fbSize;
+int fbStatus;
+#endif
+
+
+TEXTFILE * OpenTextFile(char *filename, int access)
+{
+ TEXTFILE *txtfile;
+ FILE *file;
+ int status;
+
+ if (access == TEXT_OPEN_FOR_WRITE) {
+ status = TEXT_FILE_WRITING;
+ file = fopen(filename, "w+");
+ }
+ else {
+ status = TEXT_FILE_READING;
+ file = fopen(filename, "r");
+ }
+
+ if (file == NULL)
+ return NULL;
+
+ txtfile = (TEXTFILE *) malloc (sizeof(TEXTFILE));
+ memset(txtfile, 0, sizeof(TEXTFILE));
+
+ txtfile->file = file;
+ txtfile->fbStatus = status;
+
+ txtfile->fbCurrent = txtfile->fileBuffer;
+ *txtfile->fbCurrent = '\0';
+ txtfile->fbSize = 0;
+ return txtfile;
+}
+
+
+void CloseTextFile(TEXTFILE *txtfile)
+{
+ if (txtfile) {
+ fclose(txtfile->file);
+ free(txtfile);
+ }
+
+}
+
+int FillTextBuffer(TEXTFILE *txtfile)
+{
+ int nLeft, size;
+ nLeft = strlen(txtfile->fbCurrent);
+ memcpy(txtfile->fileBuffer, txtfile->fbCurrent, nLeft+1);
+
+ size = fread(txtfile->fileBuffer + nLeft, 1, FILE_BUFFER_SIZE - nLeft, txtfile->file);
+ if (size == 0)
+ return 0;
+
+ txtfile->fbCurrent = txtfile->fileBuffer;
+ *(txtfile->fbCurrent + size + nLeft) = '\0';
+ txtfile->fbSize = size + nLeft;
+
+ return size;
+}
+
+int ReadTextLine(TEXTFILE *txtfile, char *linebuf)
+{
+ char *p, *q;
+
+ if (txtfile->fbStatus == TEXT_FILE_DONE)
+ return -1;
+
+ p = txtfile->fbCurrent;
+ q = strchr(p, '\n');
+ if (q)
+ {
+ *q = '\0';
+ strcpy(linebuf, p);
+ txtfile->fbCurrent = q + 1;
+ return strlen(linebuf);
+ }
+ else
+ {
+ if (FillTextBuffer(txtfile) == 0)
+ { /* Done with file reading,
+ return last line
+ */
+ txtfile->fbStatus = TEXT_FILE_DONE;
+ if (*txtfile->fbCurrent) {
+ strcpy(linebuf, txtfile->fbCurrent);
+ CloseTextFile(txtfile);
+ return strlen(linebuf);
+ }
+ else {
+ CloseTextFile(txtfile);
+ return -1;
+ }
+ }
+ else {
+ p = txtfile->fbCurrent;
+ q = strchr(p, '\n');
+ if (q)
+ {
+ *q = '\0';
+ strcpy(linebuf, p);
+ txtfile->fbCurrent = q + 1;
+ }
+ else
+ {
+ strcpy(linebuf, txtfile->fbCurrent);
+ txtfile->fbCurrent = txtfile->fbCurrent + strlen(linebuf);
+ }
+ }
+ return strlen(linebuf);
+ }
+}
diff --git a/lib/libsi18n/txtfile.h b/lib/libsi18n/txtfile.h
new file mode 100644
index 00000000..d3f30755
--- /dev/null
+++ b/lib/libsi18n/txtfile.h
@@ -0,0 +1,45 @@
+/** BEGIN COPYRIGHT BLOCK
+ * Copyright 2001 Sun Microsystems, Inc.
+ * Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+#ifndef TXTFILE_H
+#define TXTFILE_H
+
+#define FILE_BUFFER_SIZE 2024
+
+/* file status */
+enum {
+ TEXT_FILE_NONE,
+ TEXT_FILE_READING,
+ TEXT_FILE_WRITING,
+ TEXT_FILE_DONE
+};
+
+typedef struct TEXTFILE {
+ FILE *file;
+ char *fbCurrent;
+ int fbSize;
+ int fbStatus;
+ char fileBuffer[FILE_BUFFER_SIZE + 1];
+} TEXTFILE;
+
+enum {
+ TEXT_OPEN_FOR_READ,
+ TEXT_OPEN_FOR_WRITE
+};
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+TEXTFILE * OpenTextFile(char *filename, int access);
+void CloseTextFile(TEXTFILE *txtfile);
+int ReadTextLine(TEXTFILE *txtfile, char *linebuf);
+
+#ifdef CPLUSPLUS
+};
+#endif
+
+#endif
diff --git a/modules.awk b/modules.awk
new file mode 100644
index 00000000..7f26819f
--- /dev/null
+++ b/modules.awk
@@ -0,0 +1,451 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+# modules.mk: defines rules for each module that any part of the systems
+# will require in dependency lists.
+#
+# The current module will not be defined, you must have set the variable
+# MODULE before this file is included.
+
+
+NS_LIBDIR=$(NSROOT)/lib
+MCOM_LIBDIR=$(MCOM_ROOT)/lib
+HTTPD=$(NSROOT)/httpd
+PROXY=$(NSROOT)/proxy
+BATMAN=$(NSROOT)/batman
+MAIL=$(NSROOT)/mailserv2
+NEWS=$(NSROOT)/news
+CMS=$(NSROOT)/species
+ROGUE=$(MCOM_ROOT)/lw/rogue
+
+# Ari's definitions for MCOM libraries, these should have if statements
+# around them to make sure they only apply to the proxy
+ifeq ($(PRODUCT), "Netscape Proxy Server")
+ifeq ($(ARCH), HPUX)
+MCL_CFLAGS="-DMCC_PROXY -I../ldapserver/include -D_HPUX_SOURCE -Aa +DA1.0 +z"
+else
+MCL_CFLAGS="-DMCC_PROXY -I../ldapserver/include"
+endif
+endif
+
+# We need to customize how libnet works for the Catalog Server...
+ifeq ($(PRODUCT), "Netscape Catalog Server")
+MCL_CFLAGS="-DSEND_FROM_FEILD"
+endif
+
+# ------------------------------- Modules --------------------------------
+
+
+ifneq ($(MODULE), LibRegex)
+LIBREGEX=regex
+LIBRARY regex $(NS_LIBDIR)/libregex
+endif
+
+ifeq ($(PRODUCT), "Netscape Proxy Server")
+ifneq ($(MODULE), LibBase)
+BASE=base $(LIBREGEX) $(LIBSI18N)
+BASE_SSL=base-ssl $(LIBREGEX)
+LIBRARY base $(NS_LIBDIR)/base regex
+endif
+else
+ifneq ($(MODULE), LibBase)
+BASE=base $(LIBSI18N)
+BASE_SSL=base-ssl
+LIBRARY base $(NS_LIBDIR)/base
+endif
+endif
+
+ifneq ($(MODULE), LibAccess)
+LIBACCESS=access $(BASE) $(LIBSI18N)
+LIBRARY libaccess $(NS_LIBDIR)/libaccess
+endif
+
+ifneq ($(MODULE), LibLdapUtil)
+LIBLDAPU=ldapu $(BASE)
+LIBRARY libldapu $(NS_LIBDIR)/ldaputil
+endif
+
+ifneq ($(MODULE), LibHttpDaemon)
+HTTPDAEMON=httpdaemon
+HTTPDAEMON_SSL=httpdaemon-ssl
+LIBRARY libhttpdaemon $(NS_LIBDIR)/httpdaemon
+endif
+
+ifneq ($(MODULE), LibFrame)
+FRAME=frame $(BASE)
+FRAME_SSL=frame-ssl $(BASE_SSL)
+LIBRARY frame $(NS_LIBDIR)/frame
+endif
+
+ifneq ($(MODULE), LibProxy)
+LIBPROXY=libproxy
+LIBPROXY_SSL=libproxy-ssl
+LIBRARY libproxy $(NS_LIBDIR)/libproxy
+endif
+
+ifneq ($(MODULE), LibSNMP)
+LIBSNMP=libsnmp
+LIBSNMP_SSL=libsnmp-ssl
+LIBRARY libsnmp $(NS_LIBDIR)/libsnmp
+endif
+
+ifneq ($(MODULE), LibSAFs)
+SAFS=safs
+SAFS_SSL=safs-ssl
+LIBRARY safs $(NS_LIBDIR)/safs
+endif
+
+ifneq ($(MODULE), LibAR)
+LIBARES=ares
+LIBRARY libares
+endif
+
+ifneq ($(MODULE), CGIUtils)
+CGIUTILS=cgiutils
+LIBRARY cgiutils $(NS_LIBDIR)/cgiutils
+endif
+
+ifneq ($(MODULE), LibAdmin)
+LIBADMIN=admin
+LIBRARY admin $(NS_LIBDIR)/libadmin
+endif
+
+ifneq ($(MODULE), LibAdminUtil)
+#LIBADMINUTIL=adminutil
+LIBRARY adminutil $(NS_LIBDIR)/libadminutil
+endif
+
+ifneq ($(MODULE), LibCrypt)
+LIBCRYPT=crypt
+LIBRARY crypt $(NS_LIBDIR)/libcrypt
+endif
+
+ifneq ($(MODULE), LibMessages)
+LIBMESSAGES=messages
+LIBRARY messages $(NS_LIBDIR)/libmessages
+endif
+
+ifneq ($(MODULE), LibNSCore)
+LIBNSCORE=nscore
+LIBRARY nscore $(NS_LIBDIR)/libnscore
+endif
+
+ifneq ($(MODULE), LibMsgDisp)
+LIBNSCORE=msgdisp
+LIBRARY msgdisp $(NS_LIBDIR)/libmsgdisp
+endif
+
+ifneq ($(MODULE), LibMetaData)
+LIBNSCORE=metadata
+LIBRARY metadata $(NS_LIBDIR)/libmetadata
+endif
+
+ifneq ($(MODULE), LibIr)
+LIBNSCORE=ir
+LIBRARY ir $(NS_LIBDIR)/libir
+endif
+
+ifneq ($(MODULE), LibDocLdr)
+LIBNSCORE=docldr
+LIBRARY docldr $(NS_LIBDIR)/libdocldr
+endif
+
+ifneq ($(MODULE), LibVLdr)
+LIBNSCORE=vldr
+LIBRARY vldr $(NS_LIBDIR)/libvldr
+endif
+
+ifneq ($(MODULE), LibsI18N)
+LIBSI18N=si18n
+LIBRARY si18n $(NS_LIBDIR)/libsi18n
+endif
+
+ifneq ($(MODULE), LibINN)
+LIBINN=inn
+LIBRARY inn $(NS_LIBDIR)/libinn
+endif
+
+
+#ifeq ($(ARCH), WINNT)
+#ifneq ($(MODULE), LibNSPR)
+#ifeq ($(DEBUG), purify)
+#LIBNSPR=$(NSCP_DISTDIR)/lib/$(NSPR_BASENAME).$(LIB_SUFFIX)
+#else
+#LIBNSPR=$(NSCP_DISTDIR)/lib/$(NSPR_BASENAME).$(LIB_SUFFIX)
+#endif
+#NSPRDIR=nspr20
+#DISTLIB libnspr $(MCOM_ROOT)/$(NSPRDIR)
+#endif
+#else
+#ifneq ($(MODULE), LibNSPR)
+#ifeq ($(DEBUG), purify)
+#LIBNSPR=$(NSCP_DISTDIR)/lib/purelibnspr.$(LIB_SUFFIX)
+#SHLIBNSPR=$(NSCP_DISTDIR)/lib/purelibnspr$(DLL_PRESUF).$(DLL_SUFFIX)
+#else
+#LIBNSPR=$(NSCP_DISTDIR)/lib/$(NSPR_BASENAME).$(LIB_SUFFIX)
+#SHLIBNSPR=$(NSCP_DISTDIR)/lib/$(NSPR_BASENAME)$(DLL_PRESUF).$(DLL_SUFFIX)
+#endif
+#NSPRDIR=nspr20
+#DISTLIB libnspr $(MCOM_ROOT)/$(NSPRDIR)
+#endif
+#endif
+#
+#ifneq ($(MODULE), LibSSLio)
+#LIBSSLIO=$(NSCP_DISTDIR)/lib/libsslio.$(LIB_SUFFIX)
+#DISTLIB libsslio $(MCOM_ROOT)/$(NSPRDIR)/lib/sslio libsslio
+#endif
+
+ifneq ($(MODULE), LibDirMon)
+LIBDIRMON=$(NSCP_DISTDIR)/lib/libdirmon.$(LIB_SUFFIX)
+#DISTLIB libdirmon $(MCOM_ROOT)/$(NSPRDIR)/lib/dirmon libdirmon
+DISTLIB libdirmon $(MCOM_ROOT)/nspr20/lib/dirmon libdirmon
+endif
+
+
+#LibAres and LibPRstrm are from NSPR20 BIN release
+#ifneq ($(MODULE), LibAres)
+#LIBARES=$(NSCP_DISTDIR)/lib/libares.$(LIB_SUFFIX)
+#DISTLIB libares $(MCOM_ROOT)/$(NSPRDIR)/lib/arlib libares
+#endif
+
+#ifneq ($(MODULE), LibPRstrm)
+#LIBPRSTRMS=$(NSCP_DISTDIR)/lib/libprstrms.$(LIB_SUFFIX)
+#DISTLIB libprstrms $(MCOM_ROOT)/$(NSPRDIR)/lib/prstreams libprstrms
+#endif
+
+#ifneq ($(MODULE), LibXP)
+#LIBXP=$(MCOM_LIBDIR)/xp/$(NSOBJDIR_NAME)/libxp.$(LIB_SUFFIX)
+#DISTLIB libxp $(MCOM_LIBDIR)/xp libnspr
+#DISTLIB libxp $(MCOM_LIBDIR)/xp
+#endif
+
+#ifneq ($(MODULE), LibDBM)
+#LIBDBM=$(MCOM_LIBDIR)/libdbm/$(NSOBJDIR_NAME)/libdbm.$(LIB_SUFFIX)
+#DISTLIB libdbm $(MCOM_LIBDIR)/libdbm libnspr
+#endif
+
+ifneq ($(MODULE), LibNT)
+LIBNT=$(MCOM_LIBDIR)/libnt/$(NSOBJDIR_NAME)/libnt.$(LIB_SUFFIX)
+DISTLIB libnt $(MCOM_LIBDIR)/libnt
+endif
+
+#ifneq ($(MODULE), LibSecurity)
+#ifeq ($(SECURITY), domestic)
+#WHICHA=us
+#else
+#WHICHA=export
+#endif
+#LIBSEC=$(MCOM_LIBDIR)/libsec/$(NSOBJDIR_NAME)/libsec-$(WHICHA).$(LIB_SUFFIX) $(LIBDBM) $(LIBXP)
+#LIBSECNAME=libsec-$(WHICHA)
+#libsec: $(LIBSECNAME)
+#DISTLIB libsec-$(WHICHA) $(MCOM_LIBDIR)/libsec libnspr libdbm libxp
+#endif
+
+ifdef FORTEZZA
+ifeq ($(ARCH), WINNT)
+LIBSEC += $(MCOM_LIBDIR)/../dist/$(NSOBJDIR_NAME)/lib/tssp32.lib
+else
+FORTEZZA_DRIVER = $(MCOM_LIBDIR)/../dist/$(NSOBJDIR_NAME)/lib/libci.a
+endif
+LIBSEC += $(FORTEZZA_DRIVER)
+endif
+
+ifneq ($(MODULE), LibNet)
+LIBNET=$(MCOM_LIBDIR)/libnet/$(NSOBJDIR_NAME)/libnet.$(LIB_SUFFIX)
+DISTLIB libnet.$(LIB_SUFFIX) $(MCOM_LIBDIR)/libnet
+endif
+
+ifneq ($(MODULE), LibCS)
+LIBCS=libcs
+LIBRARY libcs $(NS_LIBDIR)/libcs
+endif
+
+ifneq ($(MODULE), LibRobotAPI)
+LIBROBOTAPI=librobotapi
+LIBRARY librobotapi $(BATMAN)/rds/api
+endif
+
+ifneq ($(MODULE), httpdAdminHTML)
+MODULE httpd-adm-html $(HTTPD)/newadmin/html
+endif
+
+ifneq ($(MODULE), httpdAdminIcons)
+MODULE httpd-adm-icons $(HTTPD)/newadmin/icons
+endif
+
+ifeq ($(ARCH), WINNT)
+ifneq ($(MODULE), httpdAdminBin)
+# the admin binaries link with the Server DLL
+MODULE httpd-adm-bin $(HTTPD)/newadmin/src
+endif
+endif
+ifneq ($(MODULE), httpdAdminBin)
+ifneq ($(ARCH), WINNT)
+MODULE httpd-adm-bin $(HTTPD)/newadmin/src
+endif
+endif
+
+ifneq ($(MODULE), httpdInstall)
+MODULE httpd-inst $(HTTPD)/newinst
+endif
+
+ifneq ($(MODULE), httpdBinary)
+MODULE httpd-bin $(HTTPD)/src
+endif
+
+ifneq ($(MODULE), httpdExtrasDatabase)
+MODULE httpd-extra-db libxp
+endif
+
+
+ifneq ($(MODULE), httpSubagtBinary)
+MODULE http-subagt-bin $(HTTPD)/plugins/snmp
+endif
+
+
+ifneq ($(MODULE), proxyExtras)
+MODULE proxy-extra libxp
+endif
+
+ifneq ($(MODULE), proxyAdminHTML)
+MODULE proxy-adm-html $(PROXY)/newadmin/html
+endif
+
+ifneq ($(MODULE), proxyAdminIcons)
+MODULE proxy-adm-icons $(PROXY)/newadmin/icons
+endif
+
+ifneq ($(MODULE), proxyAdminBin)
+MODULE proxy-adm-bin $(PROXY)/newadmin/src
+endif
+
+ifneq ($(MODULE), proxyInstallHTML)
+MODULE proxy-inst-html $(PROXY)/newinst/html
+endif
+
+ifneq ($(MODULE), proxyInstallBin)
+MODULE proxy-inst-bin $(PROXY)/newinst/src
+endif
+
+ifneq ($(MODULE), proxyBinary)
+MODULE proxy-bin $(PROXY)/src
+endif
+
+ifneq ($(MODULE), admservBinary)
+MODULE admin-server $(NSROOT)/admserv libnspr frame safs libsnmp libadmin libadminutil libsec-$(WHICHA)
+endif
+
+ifneq ($(MODULE), mailServer)
+MODULE mail-server $(NSROOT)/mailserv2/code libnspr
+endif
+
+ifneq ($(MODULE), mailAdmin)
+MODULE mail-admin $(NSROOT)/mailserv2/admin libnspr frame libsec-$(WHICHA) admin
+endif
+
+ifneq ($(MODULE), mailInstall)
+MODULE mail-inst $(NSROOT)/mailserv2/install libnspr cgiutils regex frame
+endif
+
+ifneq ($(MODULE), nnrpdBinary)
+MODULE news-nnrpd $(NSROOT)/news/nnrpd libnspr inn base libsec-$(WHICHA)
+endif
+
+ifneq ($(MODULE), inndBinary)
+MODULE news-innd $(NSROOT)/news/innd libnspr inn base libsec-$(WHICHA)
+endif
+
+ifneq ($(MODULE), innBackEnds)
+MODULE news-backends $(NSROOT)/news/backends libnspr inn base libsec-$(WHICHA)
+endif
+
+ifneq ($(MODULE), innExpire)
+MODULE news-expire $(NSROOT)/news/expire libnspr inn
+endif
+
+ifneq ($(MODULE), innFrontEnds)
+MODULE news-frontends $(NSROOT)/news/frontends libnspr inn
+endif
+
+ifneq ($(MODULE), innInstall)
+MODULE news-install $(NSROOT)/news/newinst libnspr inn admin base
+endif
+
+ifneq ($(MODULE), innAdmin)
+MODULE news-admin $(NSROOT)/news/admin libnspr inn admin base
+endif
+
+ifneq ($(MODULE), innSiteFiles)
+MODULE news-site $(NSROOT)/news/site libnspr inn
+endif
+
+
+ifneq ($(MODULE), batmanDS)
+MODULE batman-ds $(BATMAN)/ds libcs
+endif
+
+ifneq ($(MODULE), batmanClient)
+MODULE batman-client $(BATMAN)/client libcs
+endif
+
+ifneq ($(MODULE), batmanRDS)
+MODULE batman-rds $(BATMAN)/rds libnspr libcs regex libxp libdbm libnet.$(LIB_SUFFIX) libsec-$(WHICHA) base frame
+endif
+
+ifneq ($(MODULE), batmanMiniRDS)
+MODULE batman-minirds $(BATMAN)/minirds
+endif
+
+ifneq ($(MODULE), batmanDBA)
+MODULE batman-dba $(BATMAN)/dba libcs libdbm
+endif
+
+ifneq ($(MODULE), batmanTaxonomy)
+MODULE batman-taxonomy $(BATMAN)/tax libcs
+endif
+
+ifneq ($(MODULE), httpd-extras)
+MODULE httpd-extras $(HTTPD)/extras
+endif
+
+ifneq ($(MODULE), httpd-mc-icons)
+MODULE httpd-mc-icons $(NSROOT)/mc-icons
+endif
+
+ifneq ($(MODULE), cms-rogue)
+MODULE cms-rogue $(ROGUE)
+endif
+
+ifneq ($(MODULE), cms-cert)
+MODULE cms-cert $(MCOM_ROOT)/certsvc
+endif
+
+ifneq ($(MODULE), ns-config)
+MODULE ns-config $(MCOM_ROOT)/config
+endif
+
+# httpd-bin first so the dll gets built
+ifeq ($(ARCH), WINNT)
+PACKAGE httpd httpd-adm-bin httpd-adm-html httpd-adm-icons httpd-inst
+else
+PACKAGE httpd httpd-bin
+endif
+
+PACKAGE proxy proxy-bin proxy-adm-html proxy-adm-bin proxy-adm-icons proxy-inst-html proxy-inst-bin
+
+PACKAGE mail mail-server mail-admin mail-inst
+
+PACKAGE news news-backends news-expire news-frontends news-innd news-install news-admin news-nnrpd news-site
+
+PACKAGE admserv admin-server
+
+PACKAGE batman batman-rds batman-minirds batman-ds batman-client batman-taxonomy
+
+
+PACKAGE cms-httpd httpd-adm-bin httpd-adm-html httpd-adm-icons httpd-mc-icons httpd-extras httpd-inst
+# base frame admin libaccess cgiutils
+PACKAGE cms-server ns-config libnspr libdbm libsec-$(WHICHA) libxp cms-rogue cms-cert
diff --git a/modules.sh b/modules.sh
new file mode 100644
index 00000000..672ea971
--- /dev/null
+++ b/modules.sh
@@ -0,0 +1,79 @@
+#!/bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# This is extracted from the 2.0 config shell script to decouple the module
+# extraction functionality.
+#
+# Input: modules.awk
+# Output: modules.mk (this will be included in nsconfig.mk)
+#
+
+awk '
+/^LIBRARY.*/ {
+ printf "%s:", $2
+ for (i = 4; i <= NF; i++) printf " %s", $i
+ printf "\n\tcd %s; $(MAKE) $(MFLAGS)\n", $3
+ printf "clean_%s:", $2
+ for (i = 4; i <= NF; i++) printf " clean_%s", $i
+ printf "\n\tcd %s; $(MAKE) clean\n\n", $3
+ printf "depend_%s:", $2
+ for (i = 4; i <= NF; i++) printf " depend_%s", $i
+ printf "\n\tcd %s; $(MAKE) depend\n\n", $3
+ printf("else\nclean:");
+ for (i = 4; i <= NF; i++) printf " clean_%s", $i
+ printf("\ndepend:");
+ for (i = 4; i <= NF; i++) printf " depend_%s", $i
+ printf("\n");
+ next
+}
+/^DISTLIB.*/ {
+ printf "%s:", $2
+ for (i = 4; i <= NF; i++) printf " %s", $i
+ printf "\n\tcd %s; $(MAKE) export $(NSDEFS)\n", $3
+ printf "clean_%s:", $2
+ for (i = 4; i <= NF; i++) printf " clean_%s", $i
+ printf "\n\tcd %s; $(MAKE) clean\n\n", $3
+ printf "depend_%s:", $2
+ for (i = 4; i <= NF; i++) printf " depend_%s", $i
+ printf "\n\tcd %s; $(MAKE) depend\n\n", $3
+ printf("else\nclean:");
+ for (i = 4; i <= NF; i++) printf " clean_%s", $i
+ printf("\ndepend:");
+ for (i = 4; i <= NF; i++) printf " depend_%s", $i
+ printf("\n");
+ next
+}
+/^MODULE.*/ {
+ printf "%s:", $2
+ for (i = 4; i <= NF; i++) printf " %s", $i
+ printf "\n\tcd %s; $(MAKE) $(MFLAGS)\n\n", $3
+ printf "clean_%s:", $2
+ for (i = 4; i <= NF; i++) printf " clean_%s", $i
+ printf "\n\tcd %s; $(MAKE) clean\n\n", $3
+ printf "depend_%s:", $2
+ for (i = 4; i <= NF; i++) printf " depend_%s", $i
+ printf "\n\tcd %s; $(MAKE) depend\n\n", $3
+ printf("else\nclean:");
+ for (i = 4; i <= NF; i++) printf " clean_%s", $i
+ printf("\ndepend:");
+ for (i = 4; i <= NF; i++) printf " depend_%s", $i
+ printf("\n");
+ next
+}
+/^PACKAGE.*/ {
+ printf "%s:", $2
+ for (i = 3; i <= NF; i++) printf " %s", $i
+ printf "\nclean_%s:", $2
+ for (i = 3; i <= NF; i++) printf " clean_%s", $i
+ printf "\ndepend_%s:", $2
+ for (i = 3; i <= NF; i++) printf " depend_%s", $i
+ printf("\n");
+ next
+}
+{print} ' modules.awk > modules.mk
diff --git a/ns_usedb.mk b/ns_usedb.mk
new file mode 100644
index 00000000..0980468e
--- /dev/null
+++ b/ns_usedb.mk
@@ -0,0 +1,153 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# this is ns_usedb.mk
+# a make include file intended to make the use of berkeley db
+# within builds easier.
+# winges to: dboreham
+ifdef bogus_variable_to_skip_comments
+# to use this:
+# include nsconfig.mk because this file uses stuff defined in there
+# in your makefile, define DB_VERSION if you need to
+# (defaults to the latest version otherwise)
+# include this file.
+# you can now use the following variables in your
+# makefile:
+# DB_LIB_DEP Declare a dependency on this if you want to rebuild when the DB lib changes
+# DB_INCLUDE The pathname to the DB include directory use -I$(DB_INCLUDE) in CFLAGS to pickup the db header
+# DB_LIBPATH The pathname to the DB libraries. Use this to find the .so or .dll file
+# DB_LIB The pathname to the DB library file---put this on your linker command line to pickup the library
+# DB_STATIC_LIB The pathname to a static link version of DB.
+#
+# Here is a sample:
+#
+#MCOM_ROOT=../..
+#
+#include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+#include $(MCOM_ROOT)/ldapserver/ns_usedb.mk
+#
+#
+#ifeq ($(ARCH), WINNT)
+#EXE_SUFFIX=.exe
+#OBJ_SUFFIX=obj
+#%.exe: %.$(OBJ_SUFFIX)
+# $(CC) $(LDFLAGS) $< -o $@
+#%.$(OBJ_SUFFIX): %.c
+# $(CC) $(CFLAGS) -c $< -o $@
+#else
+## currently assume that if not NT then UNIX
+#EXE_SUFFIX=
+#OBJ_SUFFIX=o
+#endif
+#
+#LINK_EXE = $(CC) $(LDFLAGS) -o $@ $(OBJS) $< $(EXTRA_LIBS)
+#
+#
+## these modules use DB, so we add to CFLAGS to ensure the headers get found
+#CFLAGS += -I$(DB_INCLUDE)
+## and, again because they us DB, we add the db library to the link flags
+#EXTRA_LIBS += $(DB_LIB)
+#
+#target=prog
+#
+#target_bin=prog$(EXE_SUFFIX)
+#
+#print:
+# @echo =========== Building with the follow DB Variables ============
+# @echo DB_LIB_DEP=$(DB_LIB_DEP)
+# @echo DB_INCLUDE=$(DB_INCLUDE)
+# @echo DB_LIBPATH=$(DB_LIBPATH)
+# @echo DB_LIB=$(DB_LIB)
+# @echo DB_STATIC_LIB=$(DB_STATIC_LIB)
+# @echo DB_VERSION=$(DB_VERSION)
+# @echo =========== ===================================== ============
+#
+#all: print $(DB_LIB_DEP) $(target_bin)
+#
+#$(target_bin): $(target).$(OBJ_SUFFIX)
+# $(LINK_EXE)
+#
+endif
+
+#if no version specified, we'll use the latest one
+ifndef DB_VERSION
+DB_VERSION=20040130
+endif
+
+# Sleepycat version #major#minor
+ifndef DB_MAJOR_MINOR
+DB_MAJOR_MINOR:=db42
+endif
+
+DB_LIBNAME=lib$(DB_MAJOR_MINOR)
+
+# this is the _only_ place the component name gets defined
+# if you're the next person adding a component to the build
+# process, you need only edit this line, and change the
+# external variable names---go home early today !
+# if we wanted to get really smart ass, we could use computed
+# variable names. Hmm...
+component_name:=$(DB_MAJOR_MINOR)
+
+# define the paths to the component parts
+db_components_share=$(COMPONENTS_DIR)/$(component_name)
+MY_NSOBJDIR_TAG=$(NSOBJDIR_TAG).OBJ
+
+db_path_config:=$(NSCP_DISTDIR)/$(component_name)
+ifeq ($(ARCH), IRIX)
+db_release_config:=$(db_components_share)/$(DB_VERSION)/$(NSCONFIG)$(NSOBJDIR_TAG)
+else
+ifeq ($(ARCH), OSF1)
+db_release_config:=$(db_components_share)/$(DB_VERSION)/$(NSCONFIG)$(MY_NSOBJDIR_TAG)
+else
+db_release_config:=$(db_components_share)/$(DB_VERSION)/$(NSCONFIG_NOTAG)$(NS64TAG)$(MY_NSOBJDIR_TAG)
+endif # OSF1
+endif # IRIX
+
+ifeq ($(ARCH), AIX)
+ifeq ($(AIXOS), 4.3)
+CFLAGS += -D__BIT_TYPES_DEFINED__
+endif
+endif # AIX
+
+DB_INCLUDE:=$(db_path_config)/include
+DB_LIBPATH:=$(db_path_config)/lib
+DB_BINPATH:=$(db_path_config)/bin
+# hack below because I couldn't find this defined anywhere in the nsxxx.mk headers
+ifeq ($(ARCH), WINNT)
+db_import_lib_suffix:=$(LIB_SUFFIX)
+DB_LIB:=$(DB_LIBPATH)/$(DB_LIBNAME).$(db_import_lib_suffix)
+DB_STATIC_LIB:=$(DB_LIBPATH)/$(DB_LIBNAME).$(LIB_SUFFIX)
+DB_LIB_DEP:=$(DB_STATIC_LIB)
+else # not WINNT
+db_import_lib_suffix:=$(DLL_SUFFIX)
+DB_LIB:=-L$(DB_LIBPATH) -l$(DB_MAJOR_MINOR)
+# XXXsspitzer: we need the spinlock symbols staticly linked in to libdb
+DB_STATIC_LIB:=-L$(DB_LIBPATH) -ldbs
+DB_LIB_DEP:=$(DB_LIBPATH)/$(DB_LIBNAME).$(DLL_SUFFIX)
+endif # not WINNT
+
+# libdb only needs to be in the server directory since only the server uses it
+PACKAGE_SRC_DEST += $(wildcard $(DB_LIBPATH)/*.$(DLL_SUFFIX)) bin/slapd/server
+
+# add ",bin" to DB_FILES if you want the programs
+DB_FILES=include,lib,bin
+
+ifndef DB_PULL_METHOD
+DB_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(DB_LIB_DEP): $(NSCP_DISTDIR)
+ifdef COMPONENT_DEPS
+ $(FTP_PULL) -method $(DB_PULL_METHOD) \
+ -objdir $(db_path_config) -componentdir $(db_release_config) \
+ -files $(DB_FILES)
+endif
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component $(component_name) file $@" ; \
+ fi
diff --git a/ns_usepurify.mk b/ns_usepurify.mk
new file mode 100644
index 00000000..d06004e2
--- /dev/null
+++ b/ns_usepurify.mk
@@ -0,0 +1,20 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# included Makefile to make building with Purify easier
+#
+
+ifneq ($(ARCH), SOLARIS)
+USE_PURIFY=
+endif
+
+ifdef USE_PURIFY
+PURIFY=purify
+PUREOPTS=-best-effort -always-use-cache-dir=yes -cache-dir=/export/share/pub/richm/purify -follow-child-processes=yes -max-threads=256 -check-debug-timestamps=no
+#PUREOPTS=-follow-child-processes=yes -max-threads=256 -check-debug-timestamps=no
+endif # USE_PURIFY
diff --git a/ns_usequantify.mk b/ns_usequantify.mk
new file mode 100644
index 00000000..69573539
--- /dev/null
+++ b/ns_usequantify.mk
@@ -0,0 +1,18 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2002 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# included Makefile to make building with Quantify easier
+#
+
+ifneq ($(ARCH), SOLARIS)
+USE_QUANTIFY=
+endif
+
+ifdef USE_QUANTIFY
+QUANOPTS=-best-effort -always-use-cache-dir=yes -follow-child-processes=yes -max-threads=256 -check-debug-timestamps=no
+QUANTIFY=quantify $(QUANOPTS)
+endif # USE_QUANTIFY
diff --git a/ns_usesh.mk b/ns_usesh.mk
new file mode 100644
index 00000000..82cd1ac0
--- /dev/null
+++ b/ns_usesh.mk
@@ -0,0 +1,138 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# this is ns_usesh.mk
+# a make include file intended to make the use of SmartHeap
+# within builds easier.
+# winges to: dboreham
+ifdef bogus_variable_to_skip_comments
+# to use this:
+# include nsconfig.mk because this file uses stuff defined in there
+# in your makefile, define SH_VERSION if you need to
+# (defaults to the latest version otherwise)
+# include this file.
+# you can now use the following variables in your
+# makefile:
+# SH_LIB_DEP Declare a dependency on this if you want to rebuild when the DB lib changes
+# SH_INCLUDE The pathname to the DB include directory use -I$(SH_INCLUDE) in CFLAGS to pickup the db header
+# SH_LIBPATH The pathname to the DB libraries. Use this to find the .so or .dll file
+# SH_LIB The pathname to the DB library file---put this on your linker command line to pickup the library
+# SH_STATIC_LIB The pathname to a static link version of DB.
+#
+# Here is a sample:
+#
+#MCOM_ROOT=../..
+#
+#include $(MCOM_ROOT)/ldapserver/nsconfig.mk
+#include $(MCOM_ROOT)/ldapserver/ns_usesh.mk
+#
+#
+#ifeq ($(ARCH), WINNT)
+#EXE_SUFFIX=.exe
+#OBJ_SUFFIX=obj
+#%.exe: %.$(OBJ_SUFFIX)
+# $(CC) $(LDFLAGS) $< -o $@
+#%.$(OBJ_SUFFIX): %.c
+# $(CC) $(CFLAGS) -c $< -o $@
+#else
+## currently assume that if not NT then UNIX
+#EXE_SUFFIX=
+#OBJ_SUFFIX=o
+#endif
+#
+#LINK_EXE = $(CC) $(LDFLAGS) -o $@ $(OBJS) $< $(EXTRA_LIBS)
+#
+#
+## these modules use SH, so we add to CFLAGS to ensure the headers get found
+#CFLAGS += -I$(SH_INCLUDE)
+## and, again because they us DB, we add the db library to the link flags
+#EXTRA_LIBS += $(SH_LIB)
+#
+#target=prog
+#
+#target_bin=prog$(EXE_SUFFIX)
+#
+#print:
+# @echo =========== Building with the follow SH Variables ============
+# @echo SH_LIB_DEP=$(SH_LIB_DEP)
+# @echo SH_INCLUDE=$(SH_INCLUDE)
+# @echo SH_LIBPATH=$(SH_LIBPATH)
+# @echo SH_LIB=$(SH_LIB)
+# @echo SH_STATIC_LIB=$(SH_STATIC_LIB)
+# @echo SH_VERSION=$(SH_VERSION)
+# @echo =========== ===================================== ============
+#
+#all: print $(SH_LIB_DEP) $(target_bin)
+#
+#$(target_bin): $(target).$(OBJ_SUFFIX)
+# $(LINK_EXE)
+#
+endif
+
+#if no version specified, we'll use the latest one
+ifndef SH_VERSION
+SH_VERSION=latest
+endif
+
+# this is the _only_ place the component name gets defined
+# if you're the next person adding a component to the build
+# process, you need only edit this line, and change the
+# external variable names---go home early today !
+# if we wanted to get really smart ass, we could use computed
+# variable names. Hmm...
+component_name:=smartheap6
+# define the paths to the component parts
+sh_path_root:=$(NSCP_DISTDIR)/$(component_name)
+sh_components_share=/share/builds/components/$(component_name)
+sh_release_config:=$(sh_components_share)/$(SH_VERSION)/$(NSCONFIG)$(NS64TAG)$(NSOBJDIR_TAG)
+SH_INCLUDE:=$(sh_path_root)/include
+SH_LIBPATH:=$(sh_path_root)/lib
+# hack below because I couldn't find this defined anywhere in the nsxxx.mk headers
+ifeq ($(ARCH), WINNT)
+sh_import_lib_suffix:=$(LIB_SUFFIX)
+SH_LIB:=$(SH_LIBPATH)/shdsmpmt.$(sh_import_lib_suffix)
+SH_STATIC_LIB:=$(SH_LIBPATH)/shlsmpmt.$(LIB_SUFFIX)
+SH_LIB_DEP:=$(SH_STATIC_LIB)
+else
+sh_import_lib_suffix:=$(DLL_SUFFIX)
+#This needed to get the libraries initialized in the correct order for Solaris C++ code
+ifeq ($(ARCH), SOLARIS)
+SH_LIB:=-L$(SH_LIBPATH) -lsh -lc
+else
+#LA 05/16/01: add C++ smartheap library/test for HPUX
+ ifeq ($(ARCH), HPUX)
+ SH_LIB:=-L$(SH_LIBPATH) -lsh -lsmartheapC_smp
+ else
+ SH_LIB:=-L$(SH_LIBPATH) -lsh
+ endif
+endif
+SH_STATIC_LIB:=-L$(SH_LIBPATH) -lshs
+SH_LIB_DEP:=$(SH_LIBPATH)/libshs.a
+endif
+
+ifeq ($(ARCH), WINNT)
+#Install smartheap dll in the server binary directory
+ifeq ($(DEBUG), optimize)
+PACKAGE_SRC_DEST += $(SH_LIBPATH)/libsh.$(DLL_SUFFIX) bin/slapd/server
+endif
+endif
+
+# add ",bin" to DB_FILES if you want the programs
+SH_FILES=include,lib
+
+ifndef SH_PULL_METHOD
+SH_PULL_METHOD = $(COMPONENT_PULL_METHOD)
+endif
+
+$(SH_LIB_DEP): $(NSCP_DISTDIR)
+ $(FTP_PULL) -method $(SH_PULL_METHOD) \
+ -objdir $(sh_path_root) -componentdir $(sh_release_config) \
+ -files $(SH_FILES)
+ -@if [ ! -f $@ ] ; \
+ then echo "Error: could not get component $(component_name) file $@" ; \
+ fi
diff --git a/nsarch b/nsarch
new file mode 100755
index 00000000..61a6a64a
--- /dev/null
+++ b/nsarch
@@ -0,0 +1,812 @@
+#! /bin/sh
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# Name: nsarch
+#
+# Description: this file determines the system name and outputs the
+# platform information in a format used by Netscape build
+# scripts and utilities; this file is based on the GNU
+# "config.guess" utility; the GNU copyleft is provided
+# somewhere below...
+#
+# For each platform supported by Netscape, we need to provide the
+# following definitions:
+#
+# Variable Description
+# -------- -----------
+# NS_NAME: one word, all upper case system name usually from uname -s that
+# can be used for Makefiles and #defines
+#
+# NS_RELEASE: release number of the OS; if there's a trademark name (like UnixWare),
+# then this is typically the release number of the marketing name
+# (like UnixWare 2.1) rather than the version of generic Unix it is
+# based on (like System V r4.2)
+# this number comes generally from uname -r, but on some systems
+# we need to use uname -v
+#
+# NS_PRETTY_NAME: one word, mixed case system name similar to NS_NAME, but useful
+# for scripts that output something for users to see
+#--------------------------------------------------------------------------
+# GNU's copyleft for "configure.guess"
+#
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 93, 94, 95, 1996 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+#--------------------------------------------------------------------------
+# shell functions
+output_format='standard'
+divider=''
+pretty=0
+
+usage(){
+ echo "Usage: $0 [ [-full {-under | -dash | -none} {-pretty} ] | -gnu ]"
+ echo
+ echo " <no args> Default to output OS name only; suitable for use"
+ echo " in Netscape's makefiles and compiler defines"
+ echo " -f, -full, --full) Full output includes OS name and release number"
+ echo " -d, -dash, --dash) use with -f to specify a dash separator"
+ echo " -u, -under, --under) use with -f to specify a underscore separator"
+ echo " -n, -none, --none) use with -f to specify no separator"
+ echo " -p, -pretty, --pretty) Print prettier mixed case version of OS name"
+ echo " -g, -gnu, --gnu) GNU-style: <chip_arch>-<vendor>-<os_release>"
+ echo " -h, -help, --help) Print this usage message"
+ echo; echo
+}
+
+get_opt(){
+ ARGS=$*
+ cntr=0
+ while [ $cntr -lt $# ]
+ do
+ case $1 in
+ -h|-help|--help) usage
+ exit 0;;
+ -f|-full|--full) output_format="full";;
+ -d|-dash|--dash) divider="dash";;
+ -u|-under|--under) divider="underscore";;
+ -n|-none|--none) divider="none";;
+ -p|-pretty|--pretty) pretty=1;;
+ -g|-gnu|--gnu) output_format="gnu";;
+ *) echo "Error: unknown argument: $1"; echo
+ usage
+ exit 1;;
+ esac
+ shift
+ done
+}
+
+ns_printf(){
+ # handle the case where we didn't set NS_NAME
+ if [ -z "${NS_NAME}" ]; then
+ NS_NAME="${UNAME_SYSTEM}"
+ fi
+
+ # handle the case where we don't have a pretty name
+ if [ -z "${NS_PRETTY_NAME}" ]; then
+ NS_PRETTY_NAME="${NS_NAME}"
+ fi
+
+ # determine which output format to use
+ case ${output_format} in
+ 'standard')
+ if [ $pretty -eq 1 ]; then
+ echo ${NS_PRETTY_NAME}
+ else
+ echo ${NS_NAME}
+ fi;;
+ 'full')
+ if [ $pretty -eq 1 ]; then
+ case "$divider" in
+ 'dash') echo ${NS_PRETTY_NAME} ${NS_RELEASE} | sed -e 's/ /-/';;
+ 'underscore') echo ${NS_PRETTY_NAME} ${NS_RELEASE} | sed -e 's/ /_/';;
+ 'none') echo ${NS_PRETTY_NAME} ${NS_RELEASE} | sed -e 's/ //';;
+ *) echo ${NS_PRETTY_NAME} ${NS_RELEASE};;
+ esac
+ else
+ # since we're outputing full, we don't need the redundant "4"
+ # in the ${NS_NAME}
+ if [ ${NS_NAME} = "SUNOS4" ]; then
+ NS_NAME="SUNOS"
+ fi
+ case "$divider" in
+ 'dash') echo ${NS_NAME} ${NS_RELEASE} | sed -e 's/ /-/';;
+ 'underscore') echo ${NS_NAME} ${NS_RELEASE} | sed -e 's/ /_/';;
+ 'none') echo ${NS_NAME} ${NS_RELEASE} | sed -e 's/ //';;
+ *) echo ${NS_NAME} ${NS_RELEASE};;
+ esac
+ fi;;
+ 'gnu') echo ${GNU_NAME};;
+ esac
+}
+
+
+#--------------------------------------------------------------------------
+# main - get the arguments and start running
+get_opt $*
+
+#--------------------------------------------------------------------------
+# everything that follows is GNU's config.guess slightly modified
+# for Netscape's use
+
+# NT doesn't have /dev/null
+#UNAME_MACHINE=`(uname -m) 2> /dev/null` || UNAME_MACHINE=unknown
+#UNAME_RELEASE=`(uname -r) 2> /dev/null` || UNAME_RELEASE=unknown
+#UNAME_SYSTEM=`(uname -s) 2> /dev/null` || UNAME_SYSTEM=unknown
+#UNAME_VERSION=`(uname -v) 2> /dev/null` || UNAME_VERSION=unknown
+
+UNAME_MACHINE=`(uname -m)` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r)` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s)` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v)` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ alpha:OSF1:*:*)
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ #echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//'`
+ GNU_NAME="alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//'`"
+ NS_NAME="${UNAME_SYSTEM}"
+ NS_RELEASE="`echo ${UNAME_RELEASE} | sed -e 's/^[VTX]//'`"
+ ns_printf
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ #echo alpha-dec-winnt3.5
+ GNU_NAME="alpha-dec-winnt3.5"
+ NS_NAME="WINNT"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-cbm-sysv4
+ exit 0;;
+ amiga:NetBSD:*:*)
+ echo m68k-cbm-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ amiga:OpenBSD:*:*)
+ echo m68k-cbm-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ Pyramid*:OSx*:*:*)
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ #echo pyramid-pyramid-sysv3
+ GNU_NAME="pyramid-pyramid-sysv3"
+ else
+ #echo pyramid-pyramid-bsd
+ GNU_NAME="pyramid-pyramid-bsd"
+ fi
+ ns_printf
+ exit 0 ;;
+ sun4*:SunOS:5.*:*)
+ #echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ GNU_NAME="sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`"
+ NS_NAME="SOLARIS"
+ NS_PRETTY_NAME="Solaris"
+ NS_RELEASE="`echo ${UNAME_RELEASE}|sed -e 's/[^.]*/2/'`"
+ ns_printf
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ #echo i386-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ GNU_NAME="i386-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`"
+ NS_NAME="SOLARISx86"
+ NS_PRETTY_NAME="Solaris-x86"
+ NS_RELEASE="`echo ${UNAME_RELEASE}|sed -e 's/[^.]*/2/'`"
+ ns_printf
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ #echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ GNU_NAME="sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`"
+ ns_printf
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ #echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ GNU_NAME="sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`"
+ NS_NAME="SUNOS4"
+ NS_PRETTY_NAME="SunOS"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:NetBSD:*:*)
+ echo m68k-atari-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:OpenBSD:*:*)
+ echo m68k-atari-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:NetBSD:*:*)
+ echo m68k-sun-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:OpenBSD:*:*)
+ echo m68k-sun-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:NetBSD:*:*)
+ echo m68k-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:OpenBSD:*:*)
+ echo m68k-apple-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ #echo mips-dec-ultrix${UNAME_RELEASE}
+ GNU_NAME="mips-dec-ultrix${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ #echo vax-dec-ultrix${UNAME_RELEASE}
+ GNU_NAME="vax-dec-ultrix${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+ mips:*:4*:UMIPS)
+ echo mips-mips-riscos4sysv
+ exit 0 ;;
+ mips:*:5*:RISCos)
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 -o $UNAME_PROCESSOR = mc88100 ] ; then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+ -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+ #echo m88k-dg-dgux${UNAME_RELEASE}
+ GNU_NAME="m88k-dg-dgux${UNAME_RELEASE}"
+ else
+ #echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ GNU_NAME="m88k-dg-dguxbcs${UNAME_RELEASE}"
+ fi
+ else
+ #echo i586-dg-dgux${UNAME_RELEASE}
+ GNU_NAME="i586-dg-dgux${UNAME_RELEASE}"
+ fi
+ ns_printf
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ #echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ GNU_NAME="mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`"
+ NS_NAME="IRIX"
+ NS_RELEASE="`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`"
+ ns_printf
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i[34]86:AIX:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ # commenting out this test program - unable to execute
+ # cc on some machines...
+ #sed 's/^ //' << EOF >dummy.c
+ ##include <sys/systemcfg.h>
+ #
+ #main()
+ # {
+ # if (!__power_pc())
+ # exit(1);
+ # puts("powerpc-ibm-aix3.2.5");
+ # exit(0);
+ # }
+#EOF
+ #${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ #rm -f dummy.c dummy
+ #echo rs6000-ibm-aix3.2.5
+ GNU_NAME="rs6000-ibm-aix3.2.5"
+ NS_RELEASE="3.2.5"
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ #echo rs6000-ibm-aix3.2.4
+ GNU_NAME="rs6000-ibm-aix3.2.4"
+ NS_RELEASE="3.2.4"
+ else
+ #echo rs6000-ibm-aix3.2
+ GNU_NAME="rs6000-ibm-aix3.2"
+ NS_RELEASE="3.2"
+ fi
+ ns_printf
+ exit 0 ;;
+ *:AIX:*:4)
+ if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=4.${UNAME_RELEASE}
+ fi
+ #echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ GNU_NAME="${IBM_ARCH}-ibm-aix${IBM_REV}"
+ NS_RELEASE="${IBM_REV}"
+ ns_printf
+ exit 0 ;;
+ *:AIX:*:*)
+ #echo rs6000-ibm-aix
+ GNU_NAME="rs6000-ibm-aix"
+ ns_printf
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[3478]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/7?? | 9000/8?[679] ) HP_ARCH=hppa1.1 ;;
+ 9000/8?? ) HP_ARCH=hppa1.0 ;;
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ #echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ GNU_NAME="${HP_ARCH}-hp-hpux${HPUX_REV}"
+ NS_NAME="HPUX"
+ NS_PRETTY_NAME="HP-UX"
+ NS_RELEASE="${HPUX_REV}"
+ ns_printf
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*C90:*:*:*)
+ echo c90-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ hp3[0-9][05]:OpenBSD:*:*)
+ echo m68k-hp-openbsd${UNAME_RELEASE}
+ exit 0 ;;
+ i[34]86:BSD/386:*:* | *:BSD/OS:*:*)
+ #echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ GNU_NAME="${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}"
+ NS_NAME="BSDI"
+ NS_PRETTY_NAME="BSDI"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ *:OpenBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-openbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ i*:CYGWIN*:*)
+ #echo i386-unknown-cygwin32
+ GNU_NAME="i386-unknown-cygwin32"
+ NS_NAME="WINNT"
+ NS_PRETTY_NAME="WinNT"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin32
+ exit 0 ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ *:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us.
+ ld_help_string=`ld --help 2>&1`
+ if echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: elf_i[345]86"; then
+ #echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
+ GNU_NAME="${UNAME_MACHINE}-unknown-linux"
+ NS_NAME="${UNAME_SYSTEM}"
+ NS_RELEASE="${UNAME_RELEASE}"
+ if echo "$NS_RELEASE" | grep >/dev/null 2>&1 "2.0."; then
+ NS_RELEASE="2.0"
+ fi
+ ns_printf
+ exit 0
+ elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86linux"; then
+ #echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
+ GNU_NAME="${UNAME_MACHINE}-unknown-linuxaout"
+ NS_NAME="${UNAME_SYSTEM}"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0
+ elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: i[345]86coff"; then
+ #echo "${UNAME_MACHINE}-unknown-linuxcoff" ; exit 0
+ GNU_NAME="${UNAME_MACHINE}-unknown-linuxcoff"
+ NS_NAME="${UNAME_SYSTEM}"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0
+ elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68kelf"; then
+ #echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
+ GNU_NAME="${UNAME_MACHINE}-unknown-linux"
+ NS_NAME="${UNAME_SYSTEM}"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0
+ elif echo "$ld_help_string" | grep >/dev/null 2>&1 "supported emulations: m68klinux"; then
+ #echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
+ GNU_NAME="${UNAME_MACHINE}-unknown-linuxaout"
+ NS_NAME="${UNAME_SYSTEM}"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0
+ elif test "${UNAME_MACHINE}" = "alpha" ; then
+ #echo alpha-unknown-linux ; exit 0
+ GNU_NAME="alpha-unknown-linux"
+ NS_NAME="${UNAME_SYSTEM}"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0
+ else
+ # Either a pre-BFD a.out linker (linuxoldld) or one that does not give us
+ # useful --help. Gcc wants to distinguish between linuxoldld and linuxaout.
+ test ! -d /usr/lib/ldscripts/. \
+ && echo "${UNAME_MACHINE}-unknown-linuxoldld" && exit 0
+ # Determine whether the default compiler is a.out or elf
+ cat >dummy.c <<EOF
+main(argc, argv)
+int argc;
+char *argv[];
+{
+#ifdef __ELF__
+ printf ("%s-unknown-linux\n", argv[1]);
+#else
+ printf ("%s-unknown-linuxaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+ i[34]86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
+ #if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ #echo ${UNAME_MACHINE}-unixware-sysv${UNAME_RELEASE}
+ if grep SCO /usr/include/sco_values.h >/dev/null 2>/dev/null; then
+ #echo ${UNAME_MACHINE}-unknown-unixware${UNAME_VERSION}
+ # check for UDK, which is like building on Gemini
+ # assumes correct "cc" is first in PATH
+ if cc -V 2>&1 | grep "CCS. 3.2" >/dev/null 2>/dev/null; then
+ NS_NAME="UnixWare"
+ NS_RELEASE="5"
+ else
+ NS_NAME="UNIXWARE"
+ NS_RELEASE="${UNAME_VERSION}"
+ fi
+ GNU_NAME="${UNAME_MACHINE}-unknown-unixware${UNAME_VERSION}"
+ NS_PRETTY_NAME="UnixWare"
+ ns_printf
+ else
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i[34]86:UnixWare:5*:*)
+ GNU_NAME="${UNAME_MACHINE}-unknown-unixware${UNAME_VERSION}"
+ NS_NAME="UnixWare"
+ NS_PRETTY_NAME="UnixWare"
+ NS_RELEASE="${UNAME_VERSION}"
+ ns_printf
+ exit 0 ;;
+ i[34]86:SCO_SV:3.2:*)
+ if /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ GNU_NAME="${UNAME_MACHINE}-unknown-sco`echo $UNAME_REL|sed -e 's/.*v//`"
+ NS_NAME="SCO"
+ NS_PRETTY_NAME="SCO"
+ NS_RELEASE="`echo $UNAME_REL|sed -e 's/.*v//`"
+ ns_printf
+ fi
+ exit 0 ;;
+ i[34]86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|egrep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ #echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
+ GNU_NAME="${UNAME_MACHINE}-unknown-sco${UNAME_REL}"
+ NS_NAME="SCO"
+ NS_PRETTY_NAME="SCO"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ else
+ echo ${UNAME_MACHINE}-unknown-sysv32
+ fi
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-unknown-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M680[234]0:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
+ uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3 && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ 3[34]??/3[34]??:*:4.0:* | 3[34]??/3[34]??,*:*:4.0:*)
+ #uname -p 2>/dev/null | grep Pentium >/dev/null \
+ # && echo i586-ncr-sysv4 && exit 0 ;;
+ uname -p 2>/dev/null | grep Pentium >/dev/null
+ if [ "$?" -eq 0 ]; then
+ GNU_NAME="i586-ncr-sysv${UNAME_RELEASE}"
+ NS_NAME="NCR"
+ NS_RELEASE="${UNAME_VERSION}"
+ ns_printf
+ else
+ GNU_NAME="unknown-ncr-sysv${UNAME_RELEASE}"
+ NS_NAME="NCR"
+ NS_RELEASE="${UNAME_VERSION}"
+ ns_printf
+ fi
+ exit 0 ;;
+ m680[234]0:LynxOS:2.[23]*:*)
+ echo m68k-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i[34]86:LynxOS:2.[23]*:*)
+ echo i386-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.[23]*:*)
+ echo sparc-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.[23]*:*)
+ echo rs6000-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ #echo mips-sni-sysv4
+ GNU_NAME="mips-sni-sysv4"
+ NS_NAME="ReliantUNIX"
+ NS_PRETTY_NAME="Sinix"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ #echo ${UNAME_MACHINE}-sni-sysv4
+ GNU_NAME="${UNAME_MACHINE}-sni-sysv4"
+ else
+ #echo ns32k-sni-sysv
+ GNU_NAME="ns32k-sni-sysv"
+ fi
+ ns_printf
+ exit 0 ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit 0 ;;
+ R?000:*System_V*:*:*)
+ if [ -d /usr/nec ]; then
+ #echo mips-nec-sysv${UNAME_RELEASE}
+ GNU_NAME="mips-nec-sysv${UNAME_RELEASE}"
+ NS_NAME="NEC"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ *:NEWS-OS:*:*)
+ GNU_NAME="mips-sony-newsos"
+ NS_NAME="SONY"
+ NS_RELEASE="${UNAME_RELEASE}"
+ exit 0 ;;
+ *86:Windows_NT:4*:*)
+ GNU_NAME="x86-unknown-winnt4"
+ NS_NAME="WINNT"
+ NS_PRETTY_NAME="WinNT"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+ *:WINNT:4*:*)
+ GNU_NAME="x86-unknown-winnt4"
+ NS_NAME="WINNT"
+ NS_PRETTY_NAME="WinNT"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+ *:WINNT:*:*)
+ GNU_NAME="x86-unknown-winnt"
+ NS_NAME="WINNT"
+ NS_PRETTY_NAME="WinNT"
+ NS_RELEASE="${UNAME_RELEASE}"
+ ns_printf
+ exit 0 ;;
+esac
+
+echo '(Unable to guess system type)' 1>&2
+
+exit 1
diff --git a/nsarch.bat b/nsarch.bat
new file mode 100644
index 00000000..c61c4acc
--- /dev/null
+++ b/nsarch.bat
@@ -0,0 +1,8 @@
+@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 //
+sh nsarch
diff --git a/nsconfig.mk b/nsconfig.mk
new file mode 100644
index 00000000..c4ab985d
--- /dev/null
+++ b/nsconfig.mk
@@ -0,0 +1,1448 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# nsconfig.h: determines which product is being built, how, and for what
+# arch
+#
+# Rob McCool
+
+# This is the default target for all Makefiles which include this file.
+# Those Makefiles should define this target with the appropriate dependencies
+# and build rules.
+#
+# More comment
+all:
+
+
+
+ABS_ROOT := $(shell cd $(MCOM_ROOT); pwd)
+NSROOT=$(MCOM_ROOT)/ldapserver
+MAKE=gmake $(BUILDOPT) NO_MOCHA=1
+
+# 7/12/96 Adrian - allow MAKEFLAGS to propagate
+# override MAKEFLAGS :=
+
+include $(NSROOT)/nsdefs.mk
+include $(NSROOT)/component_versions.mk
+
+# SEC_SUFFIX is the suffix to be applied to the reldate macro which specifies
+# the security of the specified release, either E for export, D for domestic,
+# or F for Fortezza
+ifdef FORTEZZA
+ SEC_SUFFIX = F
+else
+ ifeq ($(SECURITY), domestic)
+ SEC_SUFFIX = D
+ else
+ SEC_SUFFIX = E
+ endif
+endif
+
+PRETTY_ARCH := $(shell uname -s)
+
+NSOS_ARCH := $(subst /,_,$(shell uname -s))
+
+ifneq ($(NO_BUILD_NUM), true)
+ GET_BUILD_NUM := $(shell cat $(NSROOT)/$(BUILD_ARCH)/buildnum.dat)
+endif
+
+ifeq ($(NSOS_ARCH), IRIX64)
+ NSOS_ARCH := IRIX
+endif
+
+# Default
+NSOS_RELEASE := $(shell uname -r)
+NSOS_RELEASE_NOTAG = $(NSOS_RELEASE)
+
+ifeq ($(NSOS_ARCH), AIX)
+ NSOS_TEST := $(shell uname -v)
+ ifeq ($(NSOS_TEST),3)
+ NSOS_RELEASE := $(shell uname -r)
+ else
+ NSOS_RELEASE := $(shell uname -v).$(shell uname -r)
+ endif
+endif
+
+# Get OSF's OS revision number to figure out the OS release
+ifeq ($(NSOS_ARCH),OSF1)
+ NSOS_OSF1REV := $(shell uname -v)
+ ifeq ($(NSOS_OSF1REV),878)
+ NSOS_TAG := D
+ else
+ ifeq ($(NSOS_OSF1REV),564)
+ NSOS_TAG := B
+ else
+ ifeq ($(NSOS_OSF1REV),464)
+ NSOS_TAG := A
+ else
+# Grenoble: Defaulting to release D since these are the only version of components we have so far.
+ NSOS_TAG := D
+ endif
+ endif
+ endif
+ NSOS_RELEASE_NOTAG := $(NSOS_RELEASE)
+ NSOS_RELEASE := $(NSOS_RELEASE_NOTAG)$(NSOS_TAG)
+else
+ NSOS_RELEASE_NOTAG := $(NSOS_RELEASE)
+endif
+
+# IRIX: Recommond: USE_PTHREADS=1 and USE_N32=1
+ifeq ($(NSOS_ARCH), IRIX)
+ ifeq ($(USE_PTHREADS), 1)
+ ifeq ($(USE_N32), 1)
+ NSOS_RELEASE := $(shell uname -r)_n32_PTH
+ else
+ NSOS_RELEASE := $(shell uname -r)_PTH
+ endif
+ endif
+ NSOS_RELEASE_NOTAG := $(shell uname -r)
+endif
+
+# SVR5 (UnixWare7)
+ifeq ($(NSOS_ARCH),UnixWare)
+# For now get the OS release for backward compatibility (UnixWare5)
+NSOS_RELEASE := $(shell uname -r)
+endif
+
+# Catch NCR butchering of SVR4
+ifeq ($(NSOS_ARCH),UNIX_SV)
+ifneq ($(findstring NCR, $(shell grep NCR /etc/bcheckrc | head -1 )),)
+NSOS_ARCH := NCR
+PRETTY_ARCH := NCR
+else # !NCR
+# Make UnixWare something human readable
+NSOS_ARCH := UNIXWARE
+PRETTY_ARCH := UNIXWARE
+endif # !NCR
+# Check for UW2 using UDK, which looks like a Gemini (UnixWare7) build
+NSOS_RELEASE := $(shell $(MCOM_ROOT)/ldapserver/nsarch -f | sed 's/UnixWare //')
+ifeq ($(NSOS_RELEASE),5)
+NSOS_ARCH := UnixWare
+else # NSOS_RELEASE = 5
+# Get the OS release number, not 4.2
+NSOS_RELEASE := $(shell uname -v)
+ifeq ($(NSOS_RELEASE),2.1.2)
+# so we don't need yet another set of duplicate UNIXWARE$VER.mk gmake files
+NSOS_RELEASE := 2.1
+endif # NSOS_RELEASE = 2.1.2
+endif # NSOS_RELEASE = 5
+endif # UNIX_SV
+
+# Clean up SCO
+ifeq ($(NSOS_ARCH),SCO_SV)
+NSOS_ARCH := SCOOS
+ifeq (5.0,$(findstring 5.0,$(shell ls /var/opt/K/SCO/Unix)))
+NSOS_RELEASE := 5.0
+else
+NSOS_RELEASE := UNKNOWN
+endif
+endif
+
+# both values (SINIX-N and ReliantUNIX-N) are possible
+ifeq ($(NSOS_ARCH), SINIX-N)
+NSOS_ARCH := ReliantUNIX
+PRETTY_ARCH := ReliantUNIX
+NSOS_RELEASE := 5.4
+endif
+ifeq ($(NSOS_ARCH), ReliantUNIX-N)
+NSOS_ARCH := ReliantUNIX
+PRETTY_ARCH := ReliantUNIX
+NSOS_RELEASE := 5.4
+endif
+
+# Make NT versions 5.1 and 5.2 look like 5.0 for build purposes
+ifndef NSOS_RELEASE_OVERRIDE
+ifeq ($(NSOS_ARCH),WINNT)
+ifeq ($(NSOS_RELEASE),5.1)
+NSOS_RELEASE_OVERRIDE=5.0
+endif
+ifeq ($(NSOS_RELEASE),5.2)
+NSOS_RELEASE_OVERRIDE=5.0
+endif
+endif
+endif
+
+ifdef NSOS_RELEASE_OVERRIDE
+NSOS_RELEASE_NOTAG := $(NSOS_RELEASE_OVERRIDE)
+NSOS_RELEASE := $(NSOS_RELEASE_NOTAG)$(NSOS_TAG)
+endif
+
+ifeq ($(NSOS_ARCH),Linux)
+#
+# Handle FreeBSD 2.2-STABLE and Linux 2.0.30-osfmach3 and 2.2.14-5.0smp
+#
+ifeq (,$(filter-out Linux FreeBSD,$(NSOS_ARCH)))
+ NSOS_RELEASE := $(shell echo $(NSOS_RELEASE) | sed 's/-.*//')
+endif
+NSOS_RELEASE := $(basename $(NSOS_RELEASE))
+NSOS_ARCH := Linux
+PRETTY_ARCH := Linux
+endif
+
+NSOS_TEST1 := $(shell uname -m)
+ifeq ($(NSOS_ARCH),Linux)
+ ifeq (86,$(findstring 86,$(NSOS_TEST1)))
+ NSOS_TEST1 = x86
+ endif
+
+ ifeq ($(USE_LIBC),1)
+ LIBC_VERSION = _libc
+ else
+ LIBC_VERSION = _glibc
+ endif
+ USE_PTHREADS = 1
+ ifeq ($(USE_PTHREADS),1)
+ PTHREAD_TAG = _PTH
+ endif
+ NSCONFIG = $(NSOS_ARCH)$(NSOS_RELEASE)_$(NSOS_TEST1)$(LIBC_VERSION)$(PTHREAD_TAG)
+ NSCONFIG_NOTAG = $(NSCONFIG)
+else
+ ifeq ($(NSOS_TEST1),i86pc)
+ NSCONFIG = $(NSOS_ARCH)$(NSOS_RELEASE)_$(NSOS_TEST1)
+ NSCONFIG_NOTAG = $(NSOS_ARCH)$(NSOS_RELEASE_NOTAG)_$(NSOS_TEST1)
+ else
+ NSCONFIG = $(NSOS_ARCH)$(NSOS_RELEASE)
+ NSCONFIG_NOTAG = $(NSOS_ARCH)$(NSOS_RELEASE_NOTAG)
+ endif
+endif
+
+ifeq ($(DEBUG), full)
+ MCC_DEBUG=-DMCC_DEBUG $(ARCH_DEBUG)
+ NSOBJDIR_TAG=_DBG
+ ML_DEBUG=$(ARCH_LINK_DEBUG)
+else
+ifeq ($(DEBUG), purify)
+ MCC_DEBUG=$(ARCH_DEBUG)
+ NSOBJDIR_TAG=_DBG
+ ML_DEBUG=$(ARCH_LINK_DEBUG)
+ PUREOPTS=-follow-child-processes=true -check-debug-timestamps=no -best-effort
+ PURIFY=purify $(PUREOPTS)
+else
+ifeq ($(DEBUG), quantify)
+ MCC_DEBUG=$(ARCH_DEBUG)
+ NSOBJDIR_TAG=_DBG
+ ML_DEBUG=$(ARCH_LINK_DEBUG)
+ QUANOPTS=-follow-child-processes=true -check-debug-timestamps=no -best-effort
+ QUANTIFY=quantify $(QUANOPTS)
+ USE_QUANTIFY=1
+else
+ MCC_DEBUG=$(ARCH_OPT)
+ NSOBJDIR_TAG=_OPT
+ ML_DEBUG=$(ARCH_LINK_OPT)
+ BUILDOPT = BUILD_OPT=1
+endif
+endif
+endif
+
+ifeq ($(NSOS_ARCH),WINNT)
+ ifneq ($(PROCESSOR_ARCHITECTURE),x86)
+ NSOBJDIR_NAME = $(NSCONFIG)$(PROCESSOR_ARCHITECTURE)$(NSOBJDIR_TAG).OBJ
+ NSOBJDIR_NAME_32 = $(NSCONFIG)$(PROCESSOR_ARCHITECTURE)$(NSOBJDIR_TAG).OBJ
+ else
+ NSOBJDIR_NAME = $(NSCONFIG)$(NSOBJDIR_TAG).OBJ
+ NSOBJDIR_NAME_32 = $(NSCONFIG)$(NSOBJDIR_TAG).OBJ
+ endif
+else
+ NSOBJDIR_NAME = $(NSCONFIG)$(NS64TAG)$(NSOBJDIR_TAG).OBJ
+ NSOBJDIR_NAME_32 = $(NSCONFIG)$(NSOBJDIR_TAG).OBJ
+ NSOBJDIR_NAME1 = $(NSCONFIG)$(NS64TAG)$(NSOBJDIR_TAG).OBJ
+ NSOBJDIR_NAMEeh = $(NSCONFIG)_eh$(NS64TAG)$(NSOBJDIR_TAG).OBJ
+ NSOBJDIR_NAMEaCC = $(NSCONFIG)$(NS64TAG)$(NSOBJDIR_TAG).OBJ
+ NSOBJDIR_NAME_NOTAG = $(NSCONFIG_NOTAG)$(NS64TAG)$(NSOBJDIR_TAG).OBJ
+ NSOBJDIR_NAME1_NOTAG = $(NSCONFIG_NOTAG)$(NS64TAG)$(NSOBJDIR_TAG).OBJ
+endif
+
+
+# NSPR build stuff
+NSCP_DIST = $(MCOM_ROOT)/dist
+NSCP_DISTDIR = $(MCOM_ROOT)/dist/$(NSOBJDIR_NAME)
+
+MAKE=gmake $(BUILDOPT) NO_MOCHA=1 NO_JAVA=1
+
+export NSPR20=1
+
+LWDEFS = LIVEWIRE=1
+JSDEFS = JSFILE=1 JS_THREADSAFE=1
+
+-include ../lw/config/netsite-config.mk
+
+NSDEFS=SERVER_BUILD=1 XCFLAGS=$(MCL_CFLAGS) USE_PTHREADS=$(USE_PTHREADS) \
+ NS_PRODUCT=$(NS_PRODUCT) VERSION=$(SERVER_VERSION) \
+ NS_USE_NATIVE=$(NS_USE_NATIVE) NSPR_BASENAME=$(NSPR_BASENAME)
+
+NSPR_DEFINES = -DSERVER_BUILD
+
+
+# Destination for class files and packages
+CLASS_DEST = $(MCOM_ROOT)/dist/classes
+
+# ----------- Where to get shared components --------------------
+# COMPONENTS_DIR_DEV can be used to pull stuff from the integration area
+# at rtm time we switch it over to use the official components
+
+ifndef COMPONENTS_DIR_DEV
+COMPONENTS_DIR_DEV = /share/builds/sbsintegration
+endif
+
+ifndef COMPONENTS_DIR
+COMPONENTS_DIR = /share/builds/components
+endif
+
+# For now, we need to pick up a private build of the LDAP SDK
+#ifndef LDAP_SBC
+#LDAP_SBC = /share/builds/sbsintegration/ds/ds70-bozeman
+#endif
+
+###########################################################
+
+
+# ------------------------ Product-specific flags ------------------------
+
+
+ifdef PRODUCT_IS_DIRECTORY_SERVER
+ ifeq ($(SECURITY), export)
+ MCC_SERVER=-DMCC_HTTPD -DNS_EXPORT -DNET_SSL -DCLIENT_AUTH $(NSPR_DEFINES)
+ endif
+ ifeq ($(SECURITY), domestic)
+ MCC_SERVER=-DMCC_HTTPD -DNS_DOMESTIC -DNET_SSL -DCLIENT_AUTH $(NSPR_DEFINES)
+ endif
+ ifeq ($(SECURITY), none)
+ MCC_SERVER=-DMCC_HTTPD -DNS_UNSECURE $(NSPR_DEFINES)
+ endif
+ DS_SERVER_DEFS = -DNS_DS
+ ifeq ($(BUILD_DEBUG),full)
+ MODULE_CFLAGS += -DDEBUG
+ endif
+ MCC_SERVER += $(DS_SERVER_DEFS)
+ NS_PRODUCT = DIRECTORY_SERVER
+ ifeq ($(LDAP_NO_LIBLCACHE),1)
+ MODULE_CFLAGS+=-DNO_LIBLCACHE
+ endif
+endif
+
+ifdef FORTEZZA
+ MCC_SERVER += -DFORTEZZA -DCLIENT_AUTH
+endif
+
+MCC_SERVER += -DSPAPI20 -DBUILD_NUM=$(GET_BUILD_NUM)
+
+# ----------- Default Flags, may be overridden below ------------
+
+PEER_DATE=19980121
+CPPCMD=$(CC) -E
+HTTPDSO_NAME=$(BUILD_HTTPDLL_NAME)
+MATHLIB=-lm
+LIB_SUFFIX=a
+AR=ar rcv $@
+DLL_PRESUF=
+DLL_SUFFIX=so
+LDAP_DLL_PRESUF=
+LDAP_DLL_SUFFIX=$(DLL_SUFFIX)
+LINK_DLL=ld $(DLL_LDFLAGS) -o $@
+LINK_PLUGIN=$(LINK_DLL)
+
+# ---------------------- OS-specific compile flags -----------------------
+
+
+# Used by peer snmp defines below
+DEVROOT = $(MCOM_ROOT)/../peer
+
+ifeq ($(ARCH), AIX)
+# convert the output of oslevel to a 4 digit number
+# e.g. 4.2.0.0 -> 4200 4.2.1.0 -> 4210
+OSVERSION := $(shell oslevel | sed "s/[.]//g")
+OSMAJORVERSION := $(shell oslevel | cut -f1 -d.)
+OSMINORVERSION := $(shell oslevel | cut -f2 -d.)
+# we had to do a lot of special stuff to make shared libraries work
+ifeq ("yes", $(shell /bin/sh -c "[ $(OSVERSION) -lt 4200 ] && echo yes" ) )
+ OLD_AIX_LINKING=1
+endif
+
+ifdef OLD_AIX_LINKING
+ DLL_PRESUF=_shr
+ DLL_SUFFIX=a
+else
+# there is apparently a lot of stuff to do before we can use .so as the
+# shared library suffix, so leave it for now . . .
+ DLL_PRESUF=
+ DLL_SUFFIX=so
+ LD=xlC_r
+endif
+
+#CC=xlC_r -qinfo -qarch=com -qgenpcomp=$(OBJDIR)/.pcomp -qusepcomp -DAIX -DAIXV3 -DAIXV4 -DSYSV -DOSVERSION=$(OSVERSION)
+CC=xlC_r -qinfo -qarch=com -DAIX -DAIXV3 -DAIXV4 -DSYSV -DOSVERSION=$(OSVERSION) -DAIX$(OSMAJORVERSION)_$(OSMINORVERSION)
+CCC=$(CC)
+CXX=$(CC)
+CPPCMD=/usr/ccs/lib/cpp -P
+ARCH_DEBUG=-g -qfullpath
+ARCH_OPT=-O
+RANLIB=ranlib
+SHARED_FLAG=-brtl
+NONSHARED_FLAG=-bnso -bI:/lib/syscalls.exp
+EXPORT_FILE=$*.exp
+DEF_LIBPATH=/usr/lib/threads:/usr/lpp/xlC/lib:/usr/lib:/lib
+# JCM - LINK_PLUGIN+=-berok
+ifdef OLD_AIX_LINKING
+ MKSHLIB_FLAGS=-p 0 -blibpath:$(DEF_LIBPATH)
+ DLL_LDFLAGS=-bM:SRE -bnoentry -blibpath:$(DEF_LIBPATH)
+ LINK_DLL=$(ABS_ROOT)/build/aixmkshlib -o $@ $(MKSHLIB_FLAGS)
+ MKSHLIB=$(LINK_DLL)
+ EXTRA_LIBS=-lsvld
+else
+ MKSHLIB_FLAGS=-brtl -p 0 -blibpath:$(DEF_LIBPATH)
+ DLL_LDFLAGS=-bM:SRE -bnoentry -blibpath:$(DEF_LIBPATH)
+ LINK_DLL=/usr/lpp/xlC/bin/makeC++SharedLib_r -o $@ $(MKSHLIB_FLAGS)
+ ifeq ($(OSMAJORVERSION), 4)
+ ifeq ($(OSMINORVERSION), 3)
+ LINK_DLL=/usr/ibmcxx/bin/makeC++SharedLib_r -o $@ $(MKSHLIB_FLAGS)
+ endif
+ endif
+ MKSHLIB=$(LINK_DLL)
+ EXTRA_LIBS=-ldl
+endif
+#LINK_DLL=$(LD) $(DLL_LDFLAGS) -o $@
+# AIX plugins can have unresolved references
+ifdef PRODUCT_IS_DIRECTORY_SERVER
+EXTRA_LIBS += -lpthreads -lc_r -lm
+endif
+
+VERITY_ARCH=_rs6k41
+NSAPI_CAPABLE=true
+USE_PTHREADS=1
+ifdef OLD_AIX_LINKING
+ DL_LIB =-lsvld
+else
+ DL_LIB =-ldl
+endif
+NSPR_DEFINES += -DNSPR20
+RWTOOLS_VERSION = latest
+#HTTPDSO_NAME=libdsnshttpd
+PEER_ARCH=aix
+
+else
+ifeq ($(ARCH), BSDI)
+
+CC=cc
+ARCH_DEBUG=-g
+ARCH_OPT=-O2
+ARCH_CFLAGS=-Wall -DNO_GETDOMAINNAME
+RANLIB=ranlib
+NONSHARED_FLAG=-static
+PEER_ARCH=bsdi
+
+else
+ifeq ($(ARCH), HPUX)
+DLL_SUFFIX=sl
+#-D_POSIX_C_SOURCE=199506L turns kernel threads on for HPUX11
+CC=cc -Ae -D_POSIX_C_SOURCE=199506L
+ifeq ($(BUILD_MODULE), HTTP_ADMIN)
+CXX=aCC -DHPUX_ACC -D__STDC_EXT__ -D_POSIX_C_SOURCE=199506L -ext
+else
+CXX=aCC -DHPUX_ACC -D__STDC_EXT__ -D_POSIX_C_SOURCE=199506L -ext
+endif
+CCC=$(CXX)
+ARCH_DEBUG=-g
+ARCH_OPT=-O
+# Compile everything pos-independent in case we need to put it in shared lib
+ifdef USE_64
+ ARCH_CFLAGS=-D_HPUX_SOURCE +DA2.0W +DS2.0 +Z
+else
+ ARCH_CFLAGS=-D_HPUX_SOURCE +DAportable +DS1.1 +Z
+endif
+# NSPR uses fpsetmask which I'm told is in the math lib
+EXTRA_LIBS= -ldld -lm
+ifeq ($(NSOS_RELEASE), B.10.10)
+ARCH_CFLAGS+=-DHPUX10 -DHPUX10_10
+# Debug with HPUX "dde" - makes the server single process - avoids fork()ing.
+# Can also be used for non HPUX if desired.
+#ARCH_CFLAGS+=-DUSE_DDE_DEBUG
+EXTRA_LIBS += -ldce
+else
+
+ifeq ($(NSOS_RELEASE), B.11.00)
+ MODERNHP=1
+endif
+
+ifeq ($(NSOS_RELEASE), B.11.11)
+ MODERNHP=1
+endif
+
+ifeq ($(MODERNHP), 1)
+ifeq ($(NSOS_RELEASE), B.11.00)
+ ARCH_CFLAGS+=-DHPUX11 -DHPUX11_00
+endif
+ifeq ($(NSOS_RELEASE), B.11.11)
+ ARCH_CFLAGS+=-DHPUX11 -DHPUX11_11
+endif
+# Debug with HPUX "dde" - makes the server single process - avoids fork()ing.
+# Can also be used for non HPUX if desired.
+#ARCH_CFLAGS+=-DUSE_DDE_DEBUG
+EXTRA_LIBS+= -lpthread
+endif
+endif
+RANLIB=true
+NONSHARED_FLAG=-Wl,-a,archive
+
+# Flags passed to CC to pass onto the linker; separate it from EXTRA_LIBS
+ifeq ($(USE_64),1)
+LD_CFLAGS=-W1,-E
+else
+LD_CFLAGS=-Wl,-E,-N
+endif
+DLL_CFLAGS=+Z
+DLL_LDFLAGS=-b
+NSAPI_CAPABLE=true
+VERITY_ARCH=_hp800
+USE_PTHREADS=1
+NSPR_DEFINES += -DNSPR20 -D_PR_NTHREAD -D_PR_USECPU -D_REENTRANT
+LINK_DLL=$(CCC) $(DLL_LDFLAGS) $(ARCH_CFLAGS) -o $@
+PEER_ARCH=hp
+RWTOOLS_VERSION = latest
+
+else
+ifeq ($(ARCH), IRIX)
+OSVERSION := $(shell uname -r)
+# the ns/ side of the fence assumes SVR4 is defined. --Rob
+CC=cc -DSVR4
+ifndef PRODUCT_IS_DIRECTORY_SERVER
+CXX=CC -DSVR4 -exceptions
+else
+# XXXmcs: 17-Sep-1997 - the -exceptions flag causes the IRIX CC compiler
+# to dump core when compiling ldapserver/lib/safs/aclsafs.c
+# We don't seem to need this for Directory Server....
+CXX=CC -DSVR4
+endif
+CCC=$(CXX)
+ARCH_DEBUG=-g
+ARCH_OPT=-O
+ifeq ($(USE_N32), 1)
+ ARCH_CFLAGS=-fullwarn -use_readonly_const -MDupdate .depends -n32
+else
+ ARCH_CFLAGS=-fullwarn -use_readonly_const -MDupdate .depends -o32
+endif
+RANLIB=true
+DLL_LDFLAGS=-shared
+NONSHARED_FLAG=-non_shared
+NLIST=-lmld
+NSAPI_CAPABLE=true
+# Use -DIRIX6_2 for 6.x
+ifeq (6.,$(findstring 6.,$(OSVERSION)))
+ARCH_CFLAGS+=-DIRIX6_2
+endif
+ifeq (6.5,$(OSVERSION))
+ARCH_CFLAGS+=-DIRIX6_5 -mips3
+endif
+NSPR_DEFINES += -DNSPR20 -D_PR_NTHREAD -D_SGI_MP_SOURCE
+
+LINK_DLL=$(CCC) $(DLL_LDFLAGS) -o $@
+PEER_ARCH=irix
+
+export NO_DB2=1
+else
+ifeq ($(ARCH), Linux)
+OSVERSION := $(basename $(shell uname -r))
+CC=/usr/bin/gcc -fwritable-strings
+CXX=/usr/bin/g++ -fwritable-strings
+CCC=$(CXX)
+LD=$(CXX)
+ARCH_DEBUG=-g
+ARCH_OPT=-O2
+ARCH_CFLAGS=-Wall -DNO_DBM -DLINUX -DLINUX2_2 -DLINUX2_4 -fPIC -D_REENTRANT
+RANLIB=ranlib
+DLL_LDFLAGS=-shared
+LINK_DLL=$(CC) $(DLL_LDFLAGS) -o $@
+NSPR_DEFINES += -DNSPR20
+NLIST=-lelf
+NSAPI_CAPABLE=true
+EXTRA_LIBS=-ldl -lcrypt -lpthread
+BUILD_IIOPLIB=no
+ifeq (2.4,$(OSVERSION))
+PEER_ARCH=linux2.4
+else
+PEER_ARCH=linux
+endif
+# linux always uses pthreads
+USE_PTHREADS = 1
+# remove this line when smartheap is built for linux
+LDAP_DONT_USE_SMARTHEAP = 1
+
+else
+ifeq ($(ARCH), UNIXWARE)
+
+CC=$(ABS_ROOT)/build/hcc
+CXX=$(ABS_ROOT)/build/hcpp
+CCC=$(CXX)
+CPPCMD=/lib/cpp -P
+ARCH_DEBUG=-g
+ARCH_OPT=
+ARCH_CFLAGS=
+RANLIB=true
+NLIST=-lelf
+NSAPI_CAPABLE=true
+
+# to use native threads - uncomment this
+# export USE_SVR4_THREADS=1
+
+# The -lgen is for syslog.
+
+ifdef USE_SVR4_THREADS
+OS_THREADLIB = -lthread
+endif
+
+EXTRA_LIBS=-lsocket -lnsl -lresolv -ldl -lgen -lC -lc /usr/ucblib/libucb.a $(OS_THREADLIB)
+# extra libs because svr4 doesn't support sockets the way we want...?
+DLL_LDFLAGS=-d y -G
+USE_LD_RUN_PATH=true
+LDAP_VERSION = oem
+RWTOOLS_VERSION = latest
+ADM_RELDATE = oem
+ADM_VERSDIR = admserv35
+AUTOCATALOG_VERSION = oem
+NEED_VTASKSTUB = 1
+NO_MSOFT_OBJ=1
+BUILD_WEBPUB=no
+BUILD_IIOPLIB=no
+NSPR_DEFINES += -DNSPR20
+PEER_ARCH=unixware
+
+export NO_INFORMIX=1
+export NO_ORACLE=1
+export NO_SYBASE=1
+export NO_ODBC=1
+export NO_DB2=1
+
+else
+ifeq ($(ARCH), UnixWare)
+# We don't want to use absolute paths here, because we might want to pickup
+# UDK tools from /udk/usr/ccs, so we depend on the PATH being correctly set
+CC=cc
+CCC=CC
+CXX=$(CCC)
+CPPCMD=/lib/cpp -P
+ARCH_DEBUG=-g
+ARCH_OPT=-O
+SV_REL := $(shell uname -r)
+# SVR5 if Gemini UnixWare
+# SVR4 if UnixWare 2.1.x with the UDK tools
+ifeq ($(SV_REL),5)
+ ARCH_CFLAGS=-DSVR5 -D_SIMPLE_R
+else
+ ARCH_CFLAGS=-DSVR4 -D_SIMPLE_R
+endif
+RANLIB=true
+NLIST=-lelf
+NSAPI_CAPABLE=true
+
+# to use native threads - uncomment this
+# export USE_SVR4_THREADS=1
+
+ifdef USE_SVR4_THREADS
+OS_THREADLIB = -lthread
+endif
+
+# extra libs because svr4 doesn't support sockets the way we want...?
+EXTRA_LIBS=-lsocket -lnsl -lresolv -ldl -lgen -lC -lc /usr/ucblib/libucb.a
+$(OS_THREADLIB)
+LICENSE_LIBS=
+#LICENSE_LIBS=-lscolicense -lannot -li4clnt -li4shl -li4nsi -li4rpci\
+# -lnck_task -lcps -lsocket /usr/ccs/lib/libC.a
+# extra libs because svr4 doesn't support sockets the way we want...?
+VERITY_LIB=_386svr4
+
+#If you comment the line below, you will turn off the SCO licensing.
+#This will allow you to use the server internally for test purposes.
+#MCC_SERVER += -DSCO_PM
+DLL_LDFLAGS=-d y -G
+#DLL_CFLAGS=-KPIC
+USE_LD_RUN_PATH=true
+LDAP10_VERSION = oem
+RWTOOLS_VERSION = latest
+ADM_RELDATE = oem
+ADM_VERSDIR = admserv35
+AUTOCATALOG_VERSION = oem
+NEED_VTASKSTUB = 1
+NO_MSOFT_OBJ=1
+BUILD_WEBPUB=no
+BUILD_IIOPLIB=no
+NSPR_DEFINES += -DNSPR20
+PEER_ARCH=unixware5
+DB_VERSION=oem
+
+export NO_INFORMIX=1
+export NO_ORACLE=1
+export NO_SYBASE=1
+export NO_ODBC=1
+export NO_DB2=1
+
+else
+ifeq ($(ARCH), SCOOS)
+CC=cc -b elf -KPIC -DSCOOS
+CXX=g++ -b elf -DPRFSTREAMS_BROKEN -I/usr/local/lib/g++-include
+CCC=$(CXX)
+CPPCMD=/lib/cpp
+ARCH_DEBUG=-g
+ARCH_OPT=
+ARCH_CFLAGS=
+RANLIB=true
+NLIST=-lelf
+NSAPI_CAPABLE=true
+EXTRA_LIBS=-lsocket -lnsl -ldl -lpmapi -lc -lPW
+DLL_LDFLAGS=-d y -G
+
+VERITY_ARCH = _scoodt
+MCC_SERVER += -DSCO_PM
+DLL_LDFLAGS=-d y -G
+USE_LD_RUN_PATH=true
+LDAP_VERSION = oem
+RWTOOLS_VERSION = latest
+ADM_RELDATE = oem
+ADM_VERSDIR = admserv35
+AUTOCATALOG_VERSION = oem
+BUILD_WEBPUB = no
+NO_MSOFT_OBJ = 1
+NSPR_DEFINES += -DNSPR20
+PEER_ARCH=sco
+
+else
+ifeq ($(ARCH), NCR)
+
+ABS_ROOT := $(shell cd $(MCOM_ROOT); pwd)
+
+NS_USE_GCC = 1
+
+CPPCMD = /lib/cpp
+ARCH_DEBUG = -g
+ARCH_OPT =
+ARCH_CFLAGS =
+RANLIB = true
+NLIST = -lelf
+NSAPI_CAPABLE = true
+
+ifdef NS_USE_GCC
+# if gcc-settings are redefined already - don't touch it
+#
+ifeq (,$(findstring gcc, $(CC)))
+CC = gcc
+CCC = g++
+CXX = g++
+# always use -fpic - some makefiles are still broken and don't distinguish
+# situation when they build shared and static libraries
+ARCH_CFLAGS += -fpic -Wall -DPRFSTREAMS_BROKEN -DNS_USE_GCC $(GCC_FLAGS_EXTRA)
+CCC_EXTRA_LIBS = -L/usr/local/lib -lstdc++ -lg++ -lgcc
+endif
+endif
+
+ifdef NS_USE_NATIVE
+CC = cc
+CCC = ncc
+CXX = ncc
+ARCH_CFLAGS += -DNS_USE_NATIVE
+CCC_EXTRA_LIBS = -L/opt/ncc/lib
+endif
+
+###
+
+# order is important
+EXTRA_LIBS = -lsocket -lnsl -lresolv -lgen -ldl $(CCC_EXTRA_LIBS) -lc /usr/ucblib/libucb.a
+GCC_FLAGS_EXTRA = -pipe
+
+DLL_LDFLAGS = -d y -G
+VERITY_ARCH = _isvr4
+USE_LD_RUN_PATH = true
+LDAP_VERSION = oem
+RWTOOLS_VERSION = latest
+ADM_RELDATE = oem
+ADM_VERSDIR = admserv35
+NEED_VTASKSTUB = 1
+NO_MSOFT_OBJ = 1
+AUTOCATALOG_VERSION = oem
+BUILD_WEBPUB = no
+BUILD_IIOPLIB = no
+DL_LIB =-ldl
+NSPR_DEFINES += -DNSPR20
+# svr4-x86 compatible
+PEER_ARCH=unixware
+
+export NO_ODBC=1
+export NO_DB2=1
+
+else
+ifeq ($(ARCH), SONY)
+
+CC=cc
+ARCH_DEBUG=-g
+ARCH_OPT=
+ARCH_CFLAGS=
+RANLIB=true
+NLIST=-lelf
+NSAPI_CAPABLE=true
+EXTRA_LIBS=-lgen -lsocket -lnsl -ldl
+DLL_LDFLAGS=-G
+# extra libs because svr4 doesn't support sockets the way we want...
+
+LDAP_VERSION = oem
+RWTOOLS_VERSION = latest
+ADM_RELDATE = oem
+ADM_VERSDIR = admserv35
+AUTOCATALOG_VERSION = oem
+
+else
+ifeq ($(ARCH), NEC)
+
+CC=$(MCOM_ROOT)/build/hcc
+ARCH_DEBUG=-g
+ARCH_OPT=-KOlimit=4000
+ARCH_CFLAGS=-Xa
+RANLIB=true
+NLIST=
+NSAPI_CAPABLE=true
+EXTRA_LIBS=-lsocket -lnsl -ldl -lsdbm
+DLL_LDFLAGS=-G
+PEER_ARCH=nec
+LDAP_VERSION = oem
+RWTOOLS_VERSION = latest
+ADM_RELDATE = oem
+ADM_VERSDIR = admserv35
+AUTOCATALOG_VERSION = oem
+
+else
+ifeq ($(ARCH), ReliantUNIX)
+
+# do not use DCE PTHREADS now
+# USE_PTHREADS = 1
+# do not use gcc anymore
+# NS_USE_GCC = 1
+
+DLL_LDFLAGS = -G
+
+ifdef NS_USE_GCC
+
+# gcc section
+CC=gcc
+CXX=gcc
+CCC=gcc
+LD=gld
+ARCH_DEBUG=-gdwarf
+ARCH_OPT=-O2
+ARCH_LDFLAGS=-Xlinker -Blargedynsym
+ARCH_CFLAGS=-pipe -DSVR4 -DSNI
+LINK_DLL=gld $(DLL_LDFLAGS) -o $@
+
+else
+
+# CDS++ section
+CC=cc
+CXX=CC -K old_for_init
+CCC=CC -K old_for_init
+CPPCMD=/usr/ccs/lib/cpp -P
+ARCH_DEBUG=-g
+ARCH_OPT=-O2
+ARCH_LDFLAGS=-Wl,-Blargedynsym
+ARCH_CFLAGS=-DSVR4 -DSNI
+# we need to use $(CCC) if the .so contains C++ code
+# so in Makefiles where we want the .so to be linked with CC
+# we add a DLL_CC = $(CCC)
+LINK_DLL=$(DLL_CC) $(DLL_LDFLAGS) -o $@
+# otherwise, we just use $(CC)
+DLL_CC=$(CC)
+# There is another quirk: You cannot load .so's containing C++
+# code in an executable linked with $(CC)
+
+ifeq ($(USE_PTHREADS), 1)
+ARCH_CFLAGS += -K thread -DUSE_PTHREADS
+ARCH_LDFLAGS += -K thread
+DLL_LDFLAGS += -K thread
+endif
+
+endif
+
+RANLIB=true
+DLL_LDFLAGS=-G
+NONSHARED_FLAG=
+NLIST=-lelf
+NSAPI_CAPABLE=true
+VERITY_ARCH=_mipsabi
+NONSHARED_FLAG=
+EXTRA_LIBS=-lsocket -lnsl -lresolv -ldl -lgen -L/usr/local/lib -lsni
+USE_LD_RUN_PATH=true
+
+#LDAP_VERSION = latest
+#LDAP_RELDATE = latest
+LDAP_RELDATE = 20001119
+RWTOOLS_VERSION = latest
+# NEED_VTASKSTUB = 1
+
+#NO_MSOFT_OBJ=1
+BUILD_WEBPUB=yes
+BUILD_IIOPLIB=yes
+DO_AUTOCATALOG=yes
+DO_PKGAUTOCATALOG=yes
+
+#this is no longer needed
+#NEED_NSPR_MALLOC=yes
+NSPR_DEFINES += -DNSPR20
+
+PEER_ARCH=reliantunix
+RWTOOLS_VERSION = latest
+ADM_RELDATE = oem
+ADM_VERSDIR = admserv35
+AUTOCATALOG_VERSION = oem
+DB_VERSION=oem
+
+#export NO_INFORMIX=1
+#export NO_ORACLE=1
+export NO_SYBASE=1
+export NO_ODBC=1
+export NO_DB2=1
+
+else
+ifeq ($(ARCH), OSF1)
+
+CC=cc
+CCC=cxx
+CXX=cxx
+ARCH_DEBUG=-g
+ARCH_OPT=-O2
+ARCH_CFLAGS=-DIS_64 -DOSF1V4 -DOSF1V4$(NSOS_TAG) -ieee_with_inexact -pthread -std1
+# ranlib no longer needed on OSF1 V4.0
+RANLIB=true
+DLL_LDFLAGS=-shared -all -expect_unresolved "*"
+NONSHARED_FLAG=-non_shared
+NSAPI_CAPABLE=true
+VERITY_ARCH=_aosf40
+ifdef PRODUCT_IS_DIRECTORY_SERVER
+#EXTRA_LIBS+=-lcxxstd -lcxx
+else
+#EXTRA_LIBS=-lcxxstd -lcxx
+endif
+USE_PTHREADS=1
+NSPR_DEFINES += -DNSPR20
+RWTOOLS_VERSION = latest
+PEER_ARCH=osf
+PEERDIR=$(DEVROOT)/osf/dev
+
+export NO_DB2=1
+export NO_ODBC=1
+
+else
+ifeq ($(ARCH), SUNOS4)
+
+# Compile everything position-independent so we can put it into shared lib
+CC=gcc -fPIC
+ARCH_DEBUG=-g
+ARCH_OPT=-O2
+ARCH_CFLAGS=-Wall -pipe
+RANLIB=ranlib
+DLL_CFLAGS=-fPIC
+DLL_LDFLAGS=-assert pure-text
+NONSHARED_FLAG=-static
+NSAPI_CAPABLE=true
+RESOLV_LINK=/usr/local/lib/libresolvPIC.a
+PEER_ARCH=sunos
+
+ifeq ($(RESOLV_FLAG), noresolv)
+EXTRA_LIBS=-ldl
+DNS_STUB_C=dns-stub.c
+DNS_STUB_O=dns-stub.o
+
+else
+EXTRA_LIBS=$(RESOLV_LINK) -ldl
+DNS_STUB_C=nis-stub.c
+DNS_STUB_O=nis-stub.o
+endif
+
+else
+ifeq ($(ARCH), SOLARIS)
+
+#
+# 7/12/96 Adrian - Switch to use SparcWorks for 3.0 Development
+# Therefore no need to separate from catalog server
+#
+OSVERSION := $(shell uname -r | sed "y/./0/")
+NS_USE_NATIVE=1
+CC=cc -v
+CXX=CC +w
+CCC=$(CXX)
+LD=$(CC)
+ARCH_OPT=-xO2
+ARCH_CFLAGS=-DSVR4 -D__svr4 -D__svr4__ -D_SVID_GETTOD -DOSVERSION=$(OSVERSION)
+ifdef USE_64
+ ARCH_CFLAGS += -xarch=v9
+endif
+ARCH_DEBUG=-g
+RANLIB=true
+
+EXTRA_LIBS = -lthread -lposix4 -lsocket -lnsl -ldl -lresolv -lw
+ifdef PRODUCT_IS_DIRECTORY_SERVER
+EXTRA_LIBS += -lgen
+endif
+
+DLL_LDFLAGS=-G
+NONSHARED_FLAG=-static
+NSAPI_CAPABLE=true
+NLIST=-lelf
+VERITY_ARCH=_solaris
+NSPR_DEFINES += -DNSPR20 -D_PR_NTHREAD -D_REENTRANT
+PEER_ARCH=solaris
+
+# XXXrobm BARF
+# ifeq ($(NSOS_RELEASE), 5.3)
+# GCCLIB=/usr/local/lib/gcc-lib/sparc-sun-solaris2.3/2.6.3/libgcc.a
+GCCLIB=
+# We are using a CC compiler but we were linking to libgcc.a - should use sparcworks libC
+#GCCLIB=/tools/ns-arch/sparc_sun_solaris2.5/soft/sparcworks-3.0.1/run/default/share/lib/sparcworks/SUNWspro/SC3.0.1/lib/libC.a
+# else
+# GCCLIB=/usr/local/lib/gcc-lib/sparc-sun-solaris2.4/2.6.3/libgcc.a
+# endif
+
+else
+ifeq ($(ARCH), SOLARISx86)
+OSVERSION := $(shell uname -r | sed "y/./0/")
+NS_USE_NATIVE=1
+# Add SOLARIS define as well as SOLARISx86 which happens automagically
+CC=cc -DSOLARIS
+CXX=CC -DSOLARIS
+CCC=$(CXX)
+ARCH_OPT=-xO2
+ARCH_CFLAGS=-DSVR4 -D__svr4 -D__svr4__ -D_SVID_GETTOD -DOSVERSION=$(OSVERSION)
+ARCH_DEBUG=-g
+RANLIB=true
+
+EXTRA_LIBS = -lsocket -lthread -lposix4 -lnsl -ldl -lresolv -lm -lw
+
+DLL_LDFLAGS=-G
+#LDAP_VERSION = oem
+RWTOOLS_VERSION = latest
+#ADM_RELDATE = oem
+#ADM_VERSDIR = admserv30
+AUTOCATALOG_VERSION = oem
+#DB_VERSION=oem
+NONSHARED_FLAG=-static
+NSAPI_CAPABLE=true
+NLIST=-lelf
+NO_MSOFT_OBJ=1
+BUILD_WEBPUB=no
+BUILD_IIOPLIB=no
+NSPR_DEFINES += -DNSPR20 -D_PR_NTHREAD -D_REENTRANT
+export NO_INFORMIX=1
+export NO_ORACLE=1
+export NO_SYBASE=1
+export NO_ODBC=1
+export NO_DB2=1
+PEER_ARCH=solarisx86
+
+else
+ifeq ($(ARCH), WINNT)
+ifdef DEBUG_RUNTIME
+RTFLAG=-MDd
+else
+RTFLAG=-MD
+endif
+LIB_SUFFIX=lib
+DLL_SUFFIX=dll
+PROCESSOR := $(shell uname -p)
+PEER_ARCH=nti31
+ifeq ($(PROCESSOR), I386)
+CPU_ARCH = x386
+VERITY_ARCH=_nti31
+ARCH_OPT=-DNDEBUG -O2
+CC=cl -nologo $(RTFLAG) -W3 -GT -GX -D_X86_ -Dx386 -DWIN32 -D_WINDOWS -D_RWTOOLSDLL
+CCP=cl -nologo $(RTFLAG) -W3 -GT -GX -D_X86_ -Dx386 -DWIN32 -D_WINDOWS -D_MBCS -D_AFXDLL -D_RWTOOLSDLL
+else
+ifeq ($(PROCESSOR), MIPS)
+CPU_ARCH = MIPS
+VERITY_ARCH=verity_is_undefined
+ARCH_OPT=-DNDEBUG -O2
+CC=cl -nologo $(RTFLAG) -W3 -GT -GX -D_MIPS_ -DWIN32 -D_WINDOWS -D_RWTOOLSDLL
+CCP=cl -nologo $(RTFLAG) -W3 -GT -GX -D_X86_ -Dx386 -DWIN32 -D_WINDOWS -D_MBCS -D_AFXDLL -D_RWTOOLSDLL
+else
+ifeq ($(PROCESSOR), ALPHA)
+CPU_ARCH = ALPHA
+VERITY_ARCH=_ant35
+ARCH_OPT=-DNDEBUG -Od
+CC=cl -nologo $(RTFLAG) -W3 -GT -GX -D_ALPHA=1 -DWIN32 -D_WINDOWS -D_RWTOOLSDLL
+CCP=cl -nologo $(RTFLAG) -W3 -GT -GX -D_ALPHA_ -DWIN32 -D_WINDOWS -D_MBCS -D_AFXDLL -D_RWTOOLSDLL
+BUILD_IIOPLIB=no
+export NO_SYBASE=1
+export NO_ODBC=1
+export NO_DB2=1
+else
+CPU_ARCH = processor_is_undefined
+endif
+endif
+endif
+RC=rc $(MCC_SERVER)
+MC=mc
+ifdef HEAPAGENT
+OBJSWITCH=-Zi
+else
+OBJSWITCH=-Z7
+endif
+ARCH_DEBUG=-D_DEBUG -Od $(OBJSWITCH)
+ARCH_CFLAGS=
+ARCH_LINK_DEBUG=-DEBUG
+ARCH_LINK_OPT=
+RANLIB=echo
+
+EXTRA_LIBS=wsock32.lib kernel32.lib user32.lib gdi32.lib winspool.lib \
+ comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib \
+ rpcrt4.lib uuid.lib odbc32.lib odbccp32.lib winmm.lib
+
+DLL_LDFLAGS=
+NONSHARED_FLAG=
+NSAPI_CAPABLE=true
+NO_MSOFT_OBJ=1
+NSPR_DEFINES += -DNSPR20 -D_PR_NTHREAD -D_PR_USECPU
+
+else
+
+CC=UNKNOWN_SYSTEM_TYPE
+
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+
+# Peer SNMP defines
+ifeq ($(BUILD_SNMP), yes)
+MCC_SERVER += -DPEER_SNMP
+SNMP=libsnmp
+SNMP_INCLUDE=$(DEVROOT)/include
+PEERLIB=$(DEVROOT)/$(PEER_ARCH)/dev
+SNMPNOLIB=snmp
+ifeq ($(ARCH), WINNT)
+PEERLIBOBJ=$(PEERLIB)/mgmt.lib
+else
+PEERLIBOBJ=$(PEERLIB)/mgmt.o
+endif
+else
+SNMP=
+SNMP_INCLUDE=.
+PEERLIB=
+PEERLIBOBJ=
+SNMPNOLIB=
+endif
+
+# ------------------------ The actual build rules ------------------------
+include $(MCOM_ROOT)/ldapserver/nsperl.mk
+
+RELTOOLSPATH = $(ABS_ROOT)/reltools
+FTP_PULL = $(PERL) $(RELTOOLSPATH)/ftp_puller_new.pl -logdir $(ABS_ROOT) -trimlog
+
+# make sure ftp puller exists
+$(RELTOOLSPATH)/ftp_puller_new.pl:
+ cd $(ABS_ROOT) ; cvs co RelToolsLite
+
+# Define preferred pull method for the platform.
+# Can be overridden for the entire build, and also for each component
+# each component has an XXX_PULL_METHOD macro that defaults to the pull
+# method listed below; see components.mk
+ifndef COMPONENT_PULL_METHOD
+ifeq ($(ARCH), WINNT)
+COMPONENT_PULL_METHOD = FTP
+else
+COMPONENT_PULL_METHOD = SYMLINK
+endif
+endif
+
+# platforms without full rtl debugging versions of libraries i.e. not NT
+FULL_RTL_OBJDIR = $(NSOBJDIR_NAME)
+NSCP_DISTDIR_FULL_RTL = $(NSCP_DISTDIR)
+NSCP_ABS_DISTDIR_FULL_RTL = $(ABS_ROOT)/dist/$(FULL_RTL_OBJDIR)
+
+# these components may have additional RTL debugging support built in on NT
+# adminsdk (adminutil), dbm, ldapsdk, NLS, NSPR, NSS (security)
+# we cannot simply redefine NSOBJDIR_NAME and NSCP_DISTDIR because other
+# components do not have this RTL support stuff and the .OBJD directory
+# does not exist
+ifeq ($(ARCH), WINNT)
+ ifeq ($(DEBUG), fulld)
+ FULL_RTL_OBJDIR=$(NSOBJDIR_NAME)D
+ NSCP_DISTDIR_FULL_RTL = $(MCOM_ROOT)/dist/$(FULL_RTL_OBJDIR)
+ NSCP_ABS_DISTDIR_FULL_RTL = $(MCOM_ROOT)/dist/$(FULL_RTL_OBJDIR)
+ endif
+endif
+
+$(NSCP_DISTDIR_FULL_RTL) $(CLASS_DEST): $(RELTOOLSPATH)/ftp_puller_new.pl
+ mkdir -p $@
+
+include $(NSROOT)/components.mk
+
+# these two macros are to fool the crazy NSPR nsinstall and fasttime
+# stuff into putting the objects and binaries in this location
+ABS_OBJDIR=$(ABS_ROOT)/ldapserver/built/$(NS_BUILD_FLAVOR)
+NSDEFS += DIST=$(NSPR_ABS_BUILD_DIR) OBJDIR=$(ABS_OBJDIR) \
+ FASTTIME_HEADER_DEST=$(ABS_OBJDIR)/include \
+ FASTTIME_TARGET_DEST=$(ABS_OBJDIR)
+# NT uses nsinstall.exe from the path
+ifneq ($(ARCH), WINNT)
+ NSDEFS += NSINSTALL=$(ABS_OBJDIR)/nsinstall
+endif
+
+##### FTP over AIX and HPUX since they are flakey over NFS ######
+#################################################################
+ifeq ($(ARCH), AIX)
+ FTP_UNIX=YES
+endif
+ifeq ($(ARCH), HPUX)
+ FTP_UNIX=YES
+endif
+################################################################
+
+#############################################################################
+# Pull the DS4.1 MCC package to get nsslapd.dll/.lib/.so for the DS ResKit
+# ONLY. Do not USE these macros for anything else
+#############################################################################
+MCCBINARYDATE=19990621$(SEC_SUFFIX)
+FULLDSBINARY=$(COMPONENTS_DIR)/mcc41/$(MCCBINARYDATE)/$(NSOBJDIR_NAME)
+
+RM=rm
+DEPEND=makedepend
+
+ifeq ($(ARCH), IRIX)
+STRIP=strip -x
+else
+STRIP=strip
+endif # IRIX
+
+# XXXrobm The Sun MD stuff #includes stuff in the nspr dir without a prefix
+# Otherwise the second NSCP_DISTDIR/include/nspr would not be necessary
+ifdef NSPR20
+MCC_INCLUDE=-I$(NSROOT)/include \
+ -I$(MCOM_ROOT)/include \
+ $(NSPR_INCLUDE) $(DBM_INCLUDE) $(SECURITY_INCLUDE) \
+ $(SVRCORE_INCLUDE) \
+ -I$(MCOM_ROOT)/nspr20/lib
+
+# $(SVRCORE_INCLUDE) $(NLS_INCLUDE) \
+
+else
+MCC_INCLUDE=-I$(NSROOT)/include -I$(MCOM_ROOT)/include \
+ -I$(NSCP_DISTDIR)/include -I$(NSCP_DISTDIR)/include/nspr
+endif
+
+MCC_INCLUDE += -I$(LDAP_INCLUDE)
+MCC_INCLUDE += -I$(SASL_INCLUDE)
+
+ifeq ($(ARCH), WINNT)
+XP_FLAG=-DXP_WIN32 -DXP_WIN -D_WINDOWS -DXP_PC -DXP_WINNT
+else
+XP_FLAG=-DXP_UNIX
+endif
+# CFLAGS_NO_ARCH is needed temporarily by NS_MAIL
+CFLAGS_NO_ARCH=$(NODE_FLAG) $(BOMB) $(MODULE_CFLAGS) $(XP_FLAG) \
+ -D$(ARCH) $(MCC_DEBUG) $(MCC_SERVER)
+CFLAGS=$(ARCH_CFLAGS) $(CFLAGS_NO_ARCH)
+ifeq ($(BUILD_DLL), yes)
+CFLAGS += -DBUILD_DLL
+endif
+LFLAGS=$(ML_DEBUG)
+
+ifeq ($(BSCINFO), yes)
+CBSCFLAGS=-FR$(OBJDEST)/$*.sbr
+endif
+
+include $(NSROOT)/nscore.mk
+
+# These are the defaults, individual Makefiles can override them as necessary
+FVERSION=$(MAJOR_VERSION).$(MINOR_VERSION)
+FVERSION_FLAGS=-v$(FVERSION)
+
+$(NSROOT)/fversion.exe: $(NSROOT)/dategen/fversion.c
+ cl $< user32.lib -link -out:$@
+
+ifeq ($(ARCH), WINNT)
+$(OBJDEST)/%.res: %.rc $(NSROOT)/fversion.exe
+ $(RC) $(shell $(NSROOT)/fversion.exe $(FVERSION_FLAGS)) -Fo$@ $*.rc
+endif
+
+ifdef USE_LINT
+LINT = lint
+LINTCFLAGS = -errchk=%all -u -F -errtags -errhdr -errfmt=simple -Nlevel=4 -Xarch=v9 -erroff=E_ASGN_NEVER_USED
+#no lint for c++ code on Solaris
+#LINTCCFLAGS = $(LINTCFLAGS)
+endif
+
+#ifndef NOSTDCOMPILE
+$(OBJDEST)/%.o: %.cc
+ifeq ($(ARCH), WINNT)
+ $(CCP) -c $(CCFLAGS) $(CFLAGS) $(MCC_INCLUDE) $< -Fo$(OBJDEST)/$*.o
+else
+ $(CCC) -c $(CCFLAGS) $(CFLAGS) $(MCC_INCLUDE) $< -o $(OBJDEST)/$*.o
+endif
+#endif
+
+ifndef NOSTDCOMPILE
+$(OBJDEST)/%.o: %.cpp
+ifeq ($(ARCH), WINNT)
+ $(CCP) -c $(CCFLAGS) $(CFLAGS) $(MCC_INCLUDE) $< -Fo$(OBJDEST)/$*.o
+else
+ $(CCC) -c $(CCFLAGS) $(CFLAGS) $(MCC_INCLUDE) $< -o $(OBJDEST)/$*.o
+endif
+endif
+
+ifndef NOSTDCOMPILE
+$(OBJDEST)/%.o: %.c
+ifeq ($(ARCH), WINNT)
+ifeq ($(BOUNDS_CHECKER), yes)
+ bcompile -c -Zop $(NSROOT)/bchecker.ini -nologo $(RTFLAG) -W3 -GT -GX -DWIN32 \
+ -D_WINDOWS $(CFLAGS) $(MCC_INCLUDE) $< -Fo$(OBJDEST)/$*.o
+else
+ $(CC) -c $(CFLAGS) $(MCC_INCLUDE) $< -Fo$(OBJDEST)/$*.o $(CBSCFLAGS)
+endif
+else
+ $(CC) -c $(CFLAGS) $(MCC_INCLUDE) $< -o $(OBJDEST)/$*.o
+endif
+ifdef USE_LINT
+ $(LINT) $(LINTCFLAGS) $(subst -KPIC,,$(CFLAGS)) $(MCC_INCLUDE) $< > $(OBJDEST)/$*.ln 2>&1
+# $(LINT) $(LINTCFLAGS) $(MODULE_CFLAGS) $(DEFS) $(MCC_SERVER) $(INCLUDES) $(MCC_INCLUDE) $< > $(OBJDEST)/$*.ln 2>&1
+endif
+endif
+
+ifeq ($(ARCH), WINNT)
+AR=lib /nologo /out:"$@"
+ifdef HEAPAGENT
+LDAP_DONT_USE_SMARTHEAP=true
+else
+PDBSWITCH=/PDB:NONE
+endif
+LINK_DLL = link /nologo $(USE_MAP) /DLL $(PDBSWITCH) $(ML_DEBUG) /SUBSYSTEM:WINDOWS $(LLFLAGS) $(DLL_LDFLAGS) /out:"$@"
+LINK_EXE = link -OUT:"$@" $(USE_MAP) $(ARCH_LINK_DEBUG) $(LCFLAGS) /NOLOGO $(PDBSWITCH) /INCREMENTAL:NO \
+ /SUBSYSTEM:windows $(OBJS) $(DEPLIBS) $(EXTRA_LIBS)
+BSCMAKE = bscmake.exe /nologo /o $@
+endif # WINNT
+
+ifndef NOSTDCLEAN
+clean:
+ $(RM) -f .depends $(LIBS) $(OBJDEST)/*.o *_pure_* $(BINS) $(PUREFILES)
+endif
+
+ifndef NOSTDDEPEND
+ifeq ($(ARCH), WINNT)
+INCLUDE_DEPENDS = $(NULL)
+depend:
+ echo making depends
+else
+INCLUDE_DEPENDS = .depends
+.depends:
+ touch .depends
+
+depend:
+ $(DEPEND) -f .depends -- $(MCC_INCLUDE) $(CFLAGS) *.c *.cpp
+endif
+endif
+
+ifndef NOSTDSTRIP
+strip:
+ $(STRIP) $(BINS)
+endif
+
+
+# Whoa. Hack around the fact that we're using CPP for something it
+# wasn't designed to do.
+#
+# Note: I copied and pasted the HTML def to the section below. Please
+# make changes in BOTH places. MLM
+
+ifeq ($(ARCH), WINNT)
+WIN_HTMLDEFS= /D "XP_WIN32" /D"WIN32" $(MCC_SERVER)
+
+$(HTMLDEST)/%.html: %.h
+ cl /nologo /P /EP -I. $(WIN_HTMLDEFS) -Fo$@ $*.h
+ cp $*.i $@
+ rm $*.i
+else
+$(HTMLDEST)/%.html: %.h
+ @echo "$< -> $(HTMLDEST)/$*.html..."
+ @sed -e s/\'/::NETSCAPE_QUOTE_CHAR::/g \
+ -e s/\"/::NETSCAPE_DBL_QUOTE::/g \
+ -e 's^/\*^::NETSCAPE_SLASHSTAR::^g' \
+ -e 's^\*/^::NETSCAPE_STARSLASH::^g' \
+ -e 's^//^::NETSCAPE_DBLSLASH::^g' \
+ -e 's^\.^::NETSCAPE_PERIOD::^g' \
+ -e 's/^# /::NETSCAPE_HASH_BEGIN::/g' $< > /tmp/$*.HTEMP.c
+ @$(CPPCMD) -I. $(MCC_SERVER) -DXP_UNIX $(HTMLDEFS) /tmp/$*.HTEMP.c | \
+ sed -e s/::NETSCAPE_QUOTE_CHAR::/\'/g \
+ -e s/::NETSCAPE_DBL_QUOTE::/\"/g \
+ -e 's^::NETSCAPE_SLASHSTAR::^/\*^g' \
+ -e 's^::NETSCAPE_DBLSLASH::^//^g' \
+ -e 's^::NETSCAPE_PERIOD::^.^g' \
+ -e 's^::NETSCAPE_STARSLASH::^\*/^g' | \
+ egrep -v '^# .*' | grep -v '#ident ' | \
+ sed -e 's/::NETSCAPE_HASH_BEGIN::/# /g' > $(HTMLDEST)/$*.html
+ @rm /tmp/$*.HTEMP.c
+endif
+
+#
+# Compile in TNF_PROBE_*_DEBUG() macros by doing eg: gmake BUILD_DEBUG=optimize TNF_DEBUG=1
+# See aclplugin for TNF_PROBE_0_DEBUG() egs.
+# After do:
+# prex ns-slapd -z -D <instance-dir>
+# enable $all
+# trace $all
+# continue
+# <ctrl-c>
+#
+# and do a tnfdump /tmp/trace-<ns-slapd-PID> to see tnf logs.
+#
+
+ifeq ($(ARCH), SOLARIS)
+ifeq ($(USE_64), 1)
+LDAP_DONT_USE_SMARTHEAP=1
+endif
+ifdef TNF_DEBUG
+CFLAGS += -DTNF_DEBUG
+endif
+endif
+
+# Do the same for index.lst...
+ifeq ($(ARCH), WINNT)
+L_WIN_HTMLDEFS= /D "XP_WIN32" /D"WIN32" $(MCC_SERVER)
+
+$(HTMLDEST)/%.lst: %.lst
+ cl /nologo /P /EP $(L_WIN_HTMLDEFS) -Fo$@ $*.lst
+ cp $*.i $@
+ rm $*.i
+else
+$(HTMLDEST)/%.lst: %.lst
+ @echo "$< -> $(HTMLDEST)/$*.lst..."
+ @sed -e s/\'/::NETSCAPE_QUOTE_CHAR::/g \
+ -e s/\"/::NETSCAPE_DBL_QUOTE::/g \
+ -e 's^/\*^::NETSCAPE_SLASHSTAR::^g' \
+ -e 's^\*/^::NETSCAPE_STARSLASH::^g' \
+ -e 's^//^::NETSCAPE_DBLSLASH::^g' \
+ -e 's/^# /::NETSCAPE_HASH_BEGIN::/g' $< > /tmp/$*.HTEMP.c
+ @$(CPPCMD) -I. $(MCC_SERVER) -DXP_UNIX $(HTMLDEFS) /tmp/$*.HTEMP.c | \
+ sed -e s/::NETSCAPE_QUOTE_CHAR::/\'/g \
+ -e s/::NETSCAPE_DBL_QUOTE::/\"/g \
+ -e 's^::NETSCAPE_SLASHSTAR::^/\*^g' \
+ -e 's^::NETSCAPE_DBLSLASH::^//^g' \
+ -e 's^::NETSCAPE_STARSLASH::^\*/^g' | egrep -v '^# .*' | \
+ sed -e 's/::NETSCAPE_HASH_BEGIN::/# /g' > $(HTMLDEST)/$*.lst
+ @rm /tmp/$*.HTEMP.c
+endif
+
+# ------------------------- Finally, the modules -------------------------
+$(NSROOT)/modules.mk: $(NSROOT)/modules.awk
+ @echo re-making $(NSROOT)/modules.mk ...
+ @cd $(NSROOT); sh modules.sh
+
+include $(NSROOT)/modules.mk
diff --git a/nscore.mk b/nscore.mk
new file mode 100644
index 00000000..5ced7164
--- /dev/null
+++ b/nscore.mk
@@ -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
+#
+# Shared rules for modules depending on nscore
+
+# AIX uname
+AIXOS_VERSION := $(shell uname -v)
+AIXOS_RELEASE := $(shell uname -r)
+AIXOS = $(AIXOS_VERSION).$(AIXOS_RELEASE)
+
+#
+# Compiler
+#
+# Windows NT
+ifeq ($(ARCH), WINNT)
+ CFLAGS += -DOS_windows -DNT
+ PROCESSOR := $(shell uname -p)
+ ifeq ($(PROCESSOR), I386)
+ CFLAGS += -DCPU_x86
+ else
+ ifeq ($(PROCESSOR), ALPHA)
+ CFLAGS += -DCPU_alpha
+ else
+ ifeq ($(PROCESSOR), MIPS)
+ CFLAGS += -DCPU_mips
+ endif
+ endif
+ endif
+endif
+# Solaris
+ifeq ($(ARCH), SOLARIS)
+ CFLAGS += -DCPU_sparc -DOS_solaris
+endif
+#Solarisx86
+ifeq ($(ARCH), SOLARISx86)
+ CFLAGS += -DOS_solaris
+endif
+
+# HP-UX
+ifeq ($(ARCH), HPUX)
+ CFLAGS += -DCPU_hppa -DOS_hpux
+ CFLAGS += -D_NO_THREADS_
+endif
+# AIX
+ifeq ($(ARCH), AIX)
+ CFLAGS += -DCPU_powerpc -DOS_aix
+endif
+# IRIX
+ifeq ($(ARCH), IRIX)
+ CFLAGS += -DCPU_mips -DOS_irix
+ CFLAGS += -D_NO_THREADS_
+endif
+# OSF1
+ifeq ($(ARCH), OSF1)
+ CFLAGS += -DCPU_alpha -DOS_osf1
+endif
+ifeq ($(ARCH), UNIXWARE)
+ CFLAGS += -DSYSV -DSVR4 -DCPU_i486 -DOS_unixware
+endif
+ifeq ($(ARCH), UnixWare)
+ CFLAGS += -DSYSV -DCPU_i486 -DOS_unixware
+ SYSV_REL := $(shell uname -r)
+ifeq ($(SYSV_REL), 5)
+ CFLAGS += -DSVR5
+else
+ CFLAGS += -DSVR4
+endif
+endif
+ifeq ($(ARCH), SCO)
+ CFLAGS += -DSYSV -DCPU_i486 -DOS_sco
+endif
+ifeq ($(ARCH), NCR)
+ CFLAGS += -DSYSV -DSVR4 -DCPU_i486 -DOS_ncr
+endif
diff --git a/nsdefs.mk b/nsdefs.mk
new file mode 100644
index 00000000..6b107def
--- /dev/null
+++ b/nsdefs.mk
@@ -0,0 +1,245 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+#
+# These are the default values
+#
+# Individual modules may override them
+#
+# BUILD_BOMB=[-DPUMPKIN_HOUR=xxxxxxx or just leave it empty]
+# BUILD_DEBUG=[full, optimize, purify, quantify]
+# BUILD_MODULE=[HTTP_ADMIN, HTTP_PERSONAL, HTTP_ENTERPRISE, ...]
+# BUILD_SECURITY=[none, export, domestic]
+
+TMP_ARCH := $(shell uname -s)
+RELEASE := $(shell uname -r)
+ifeq ($(TMP_ARCH), WINNT)
+BUILD_ARCH := $(shell uname -s)
+else
+BUILD_ARCH := $(shell $(MCOM_ROOT)/ldapserver/nsarch)
+endif
+
+USE_HCL=1
+
+PUMPKIN_AGE := 120
+#BUILD_BOMB=
+BUILD_BOMB=-DPUMPKIN_HOUR=$(shell cat $(MCOM_ROOT)/ldapserver/pumpkin.dat)
+BUILD_CHECKER=no
+ifndef BUILD_DEBUG
+BUILD_DEBUG=full
+endif
+BUILD_MODULE=DIRECTORY
+BUILD_NSPR_THREADS=yes
+ifndef BUILD_SECURITY
+BUILD_SECURITY=domestic
+endif
+ifeq ($(USE_PTHREADS), 1)
+ ifeq ($(USE_N32), 1)
+ BUILD_PTHREADS=-n32-pth
+ else
+ BUILD_PTHREADS=-pth
+ endif
+else
+ BUILD_PTHREADS=
+endif
+
+ifdef USE_64
+ NS64TAG=_64
+endif
+
+# Should we build Java code on this platform?
+ifndef BUILD_JAVA_CODE
+ifeq ($(BUILD_ARCH),SOLARIS)
+BUILD_JAVA_CODE=1
+else
+ifeq ($(BUILD_ARCH),WINNT)
+BUILD_JAVA_CODE=1
+else
+BUILD_JAVA_CODE=0
+endif # WINNT
+endif # SOLARIS
+endif # !BUILD_JAVA_CODE
+
+NSPR_SUF=20
+LDAP_SUF=50
+
+# We can't have lite fortezza ( I don't think it makes sense ).
+ifdef FORTEZZA
+BUILD_FORTEZZA=fortezza
+else
+ifdef LITE
+BUILD_FORTEZZA=lite
+else
+BUILD_FORTEZZA=normal
+endif
+endif
+
+ifdef LITE
+IS_DIR_LITE=true
+else
+IS_DIR_LITE=false
+endif
+
+# Foreign language support
+WEBSERVER_LANGS = ja fr de
+
+# default path where to look for shared libraries at runtime
+ifeq ($(BUILD_ARCH), WINNT)
+RPATHFLAG=..\bin\slapd\lib:..\lib:..\..\lib:..\..\..\lib:..\..\..\..\lib
+else
+ifeq ($(BUILD_ARCH), SOLARIS)
+RPATHFLAG=\$$ORIGIN/../bin/slapd/lib:\$$ORIGIN:\$$ORIGIN/../lib:\$$ORIGIN/../../lib:\$$ORIGIN/../../../lib:\$$ORIGIN/../../../../lib
+else
+RPATHFLAG=../bin/slapd/lib:.:../lib:../../lib:../../../lib:../../../../lib
+endif
+endif
+
+MAJOR_VERSION:="7"
+MINOR_VERSION:="0"
+MAJOR_VERSION_NOQUOTES:=7
+MINOR_VERSION_NOQUOTES:=0
+
+# the LINK version is the one used for -l linking e.g. -l$(LINK_HTTPDLL_NAME)
+ifeq ($(BUILD_ARCH), WINNT)
+LINK_HTTPDLL_NAME=ns-dshttpd$(MAJOR_VERSION_NOQUOTES)$(MINOR_VERSION_NOQUOTES)
+BUILD_HTTPDLL_NAME=$(LINK_HTTPDLL_NAME)
+else
+LINK_HTTPDLL_NAME=ns-dshttpd$(MAJOR_VERSION)$(MINOR_VERSION)
+BUILD_HTTPDLL_NAME=lib$(LINK_HTTPDLL_NAME)
+endif # WINNT
+
+ifeq ($(BUILD_ARCH), WINNT)
+GUNZIP=gzip -d
+BUILD_DLL_VERSION=yes
+BUILD_ADMIN_NAME=ns-admin30
+BUILD_IIOPLIB=yes
+else
+GUNZIP=gunzip -d
+endif
+
+define echo_build_parms
+echo ==== Building with the following parameters ====
+echo BUILD_ARCH=$(BUILD_ARCH)
+echo BUILD_MODULE=$(BUILD_MODULE)
+echo BUILD_SECURITY=$(BUILD_SECURITY)
+echo BUILD_DEBUG=$(BUILD_DEBUG)
+echo BUILD_FORTEZZA=$(BUILD_FORTEZZA)
+echo BUILD_NSPR_THREADS=$(BUILD_NSPR_THREADS)
+echo BUILD_BOMB=$(BUILD_BOMB)
+echo BUILD_DLL_VERSION=$(BUILD_DLL_VERSION)
+echo BUILD_HTTPDLL_NAME=$(BUILD_HTTPDLL_NAME)
+echo BUILD_ADMIN_NAME=$(BUILD_ADMIN_NAME)
+echo BUILD_CHECKER=$(BUILD_CHECKER)
+echo BUILD_IIOPLIB=$(BUILD_IIOPLIB)
+endef
+
+#
+# Set up these names because most of the makefiles use them now.
+#
+ARCH=$(BUILD_ARCH)
+SECURITY=$(BUILD_SECURITY)
+DEBUG=$(BUILD_DEBUG)
+B_FORTEZZA=$(BUILD_FORTEZZA)
+BOMB=$(BUILD_BOMB)
+NSPR_THREADS=$(BUILD_NSPR_THREADS)
+BUILD_DLL=$(BUILD_DLL_VERSION)
+ADMINDLL_NAME=$(BUILD_ADMIN_NAME)
+HTTPDLL_NAME=$(BUILD_HTTPDLL_NAME)
+BOUNDS_CHECKER=$(BUILD_CHECKER)
+RESOLV_FLAG=
+DO_SEARCH=
+NODE_FLAG=-DNO_NODELOCK
+
+# It would be best if all output dir definitions below used this, rather than
+# repeating it
+ifeq ($(ARCH), WINNT)
+ifdef DEBUG_RUNTIME
+ifeq ($(DEBUG), full)
+RTSUFFIX=-d
+endif
+endif
+endif
+BASIC_OBJDIR=$(MCOM_ROOT)/ldapserver/built/$(ARCH)$(NS64TAG)-$(SECURITY)-$(DEBUG)$(RTSUFFIX)-$(B_FORTEZZA)
+
+#
+# -- Directory Server Section -----------------------------------------------
+#
+
+ifeq ($(BUILD_MODULE), DIRECTORY)
+ifdef NSPR20
+ NSPR_DIR=nspr20
+else
+ NSPR_DIR=nspr
+endif
+NSPR_BASENAME=libnspr21
+PRODUCT="Netscape Directory Server"
+PRODUCT_IS_DIRECTORY_SERVER=1
+INSTANCE_NAME_PREFIX="Directory Server"
+DIR=slapd
+NS_PRODUCT=DIRECTORY_SERVER
+ARCHPROCESSOR=$(ARCH)
+ifdef INCLUDE_SSL
+SSL_PREFIX=-ssl
+endif
+NS_BUILD_FLAVOR = $(ARCH)$(NS64TAG)-$(SECURITY)$(SSL_PREFIX)-$(DEBUG)$(RTSUFFIX)-$(BUILD_FORTEZZA)$(BUILD_PTHREADS)-$(DIR)
+NC_BUILD_FLAVOR = $(NSCONFIG)$(NSOBJDIR_TAG).OBJ
+ifeq ($(ARCH), WINNT)
+ifeq ($(PROCESSOR), ALPHA)
+ARCHPROCESSOR=$(ARCH)$(PROCESSOR)
+endif
+endif
+COMMON_OBJDIR=$(MCOM_ROOT)/ldapserver/built/$(ARCHPROCESSOR)$(NS64TAG)-$(SECURITY)$(SSL_PREFIX)-$(DEBUG)$(RTSUFFIX)-$(BUILD_FORTEZZA)$(BUILD_PTHREADS)-$(DIR)
+COMMON_OBJDIR_32=$(MCOM_ROOT)/ldapserver/built/$(ARCHPROCESSOR)-$(SECURITY)$(SSL_PREFIX)-$(DEBUG)$(RTSUFFIX)-$(BUILD_FORTEZZA)$(BUILD_PTHREADS)-$(DIR)
+OBJDIR=$(COMMON_OBJDIR)
+OBJDIR_32=$(COMMON_OBJDIR_32)
+DO_SEARCH=no
+DIR_VERSION:=7.0
+DIR_NORM_VERSION:=7.0
+# When you change DIRSDK_VERSION or DIRSDK_VERSION_DLL_SUFFIX, you must
+# update all of the .exp and .def files by executing the following command:
+# cd ldap/libraries; gmake exportfiles
+# Don't forget to commit the new files. Eventually this step will be
+# integrated into the build process. -- Mark Smith <mcs@netscape.com>
+DIRSDK_VERSION:=3.1
+DIRSDK_VERSION_DLL_SUFFIX:=$(LDAP_SUF)
+LDAP_NO_LIBLCACHE:=1
+
+DIRVERDIR=$(COMMON_OBJDIR)/include
+DIRVER_H=$(DIRVERDIR)/dirver.h
+SDKVER_H=$(DIRVERDIR)/sdkver.h
+endif
+
+#
+# -- Default Section --------------------------------------------------------
+#
+# Some of the _OBJDIR is maintained for backward compatibility until they
+# are all cleaned up. Most of them heavily dependent on value of $(DIR)
+#
+
+ifndef AMDSERV_OBJDIR
+ADMSERV_OBJDIR=$(BASIC_OBJDIR)-admin
+endif
+
+ifndef COMMON_OBJDIR
+COMMON_OBJDIR=$(BASIC_OBJDIR)-$(DIR)
+endif
+
+ifndef HTTPD_OBJDIR
+HTTPD_OBJDIR=$(BASIC_OBJDIR)-$(DIR)
+endif
+
+ifndef MC_ICONS_OBJDIR
+MC_ICONS_OBJDIR=$(BASIC_OBJDIR)-$(DIR)
+endif
+
+ifndef OBJDIR
+OBJDIR=$(BASIC_OBJDIR)-$(DIR)
+endif
+
+ifndef PLUGINS_OBJDIR
+PLUGINS_OBJDIR=$(BASIC_OBJDIR)-$(DIR)/plugins
+endif
diff --git a/nsperl.mk b/nsperl.mk
new file mode 100755
index 00000000..86d87dfb
--- /dev/null
+++ b/nsperl.mk
@@ -0,0 +1,88 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+NSPERL_RELDATE := 20020626
+NSPERL_VERSION := nsPerl5.6.1
+NSPERL_COMPONENT_DIR = $(COMPONENTS_DIR)/nsPerl/$(NSPERL_RELDATE)/$(NSOBJDIR_NAME_32)
+# default; will be redefined below for specific platform
+#PERL=$(NSPERL_COMPONENT_DIR)/lib/$(NSPERL_VERSION)/nsperl
+PERL=/share/builds/sbstools/nsPerl/$(NSPERL_RELDATE)/$(NSOBJDIR_NAME_32)/nsperl
+ifeq ($(BUILD_ARCH), WINNT)
+PERL=nsperl
+endif
+
+ifdef USE_OLD_NTPERL
+PERL=perl
+endif
+
+ifdef USE_PERL_FROM_PATH
+PERL = $(shell perl -e 'print "$$\n"')
+endif
+
+NSPERL_ZIP_FILE = nsperl561.zip
+
+# This makefile sets up the environment so that we can build and link
+# perl xsubs. It assumes that you have a perl base directory that has
+# a bin and lib subdir and that which perl yields base dir/bin/perl[.exe]
+# also, this is only really necessary for NT, since this usually just
+# works in the NFS world of unix
+# for unix, we derive the paths from the Config information
+ifdef USE_OLD_NTPERL
+PERL_EXE = $(shell $(PERL) -e '($$foo = $$) =~ s@\\@/@g ; print "$$foo\n"')
+PERL_EXENT = $(subst \,/,$(PERL_EXE))
+PERL_BASEDIR = $(dir $(PERL_EXENT))
+PERL_ROOT = $(subst /bin/,,$(PERL_BASEDIR))
+IS_ACTIVESTATE = $(shell $(PERL) -v | grep -i activestate)
+else
+PERL_CONFIG = $(shell $(PERL) -e 'use Config; foreach $$item (qw(installprivlib installarchlib installsitelib installsitearch prefixexp)) { ($$foo = $$Config{$$item}) =~ s@\\@/@g ; print "$$foo "; } print "\\\n"')
+PERL_LIB = $(word 1, $(PERL_CONFIG))
+PERL_ARCHLIB = $(word 2, $(PERL_CONFIG))
+SITELIB = $(word 3, $(PERL_CONFIG))
+SITEARCH = $(word 4, $(PERL_CONFIG))
+PERL_ROOT = $(word 5, $(PERL_CONFIG))
+endif
+
+ifdef USE_OLD_NTPERL
+PERL_LIB = $(PERL_ROOT)/lib
+PERL_ARCHLIB = $(PERL_LIB)
+PERL_SITE = site
+SITELIB = $(PERL_ROOT)/$(PERL_SITE)/lib
+SITEARCH = $(SITELIB)
+endif
+
+INSTALLSITEARCH = $(SITEARCH)
+INSTALLSITELIB = $(SITELIB)
+SITEARCHEXP = $(SITEARCH)
+SITELIBEXP = $(SITELIB)
+XSUBPPDIR = $(PERL_LIB)/ExtUtils
+XSUBPP = $(XSUBPPDIR)/xsubpp
+XSPROTOARG =
+XSUBPPDEPS = $(XSUBPPDIR)/typemap
+XSUBPPARGS = -typemap $(XSUBPPDIR)/typemap
+PERL_INC = -I$(PERL_ARCHLIB)/CORE
+
+SITEHACK = $(subst $(PERL_ROOT)/,,$(SITELIB))
+ARCHHACK = $(subst $(PERL_ROOT)/,,$(PERL_ARCHLIB))
+
+ifeq ($(ARCH), WINNT)
+ifdef IS_ACTIVESTATE
+# C compilation/linking does not work for activestate; force C++
+PERL_CFLAGS = -TP -D_CONSOLE -DNO_STRICT -DPERL_OBJECT
+ifeq ($(DEBUG), full)
+PERL_CFLAGS += -DNDEBUG
+endif
+LIBPERL_A = /LIBPATH:$(PERL_ARCHLIB)/CORE perlCAPI.lib perlcore.lib PerlCRT.lib
+else
+LIBPERL_A = /LIBPATH:$(PERL_ARCHLIB)/CORE perl56.lib
+endif
+else
+ifeq ($(DEBUG), full)
+PERL_CFLAGS = -UDEBUG
+endif
+LIBPERL_A = -L$(PERL_ARCHLIB)/CORE -lperl
+endif
diff --git a/ntversion.pl b/ntversion.pl
new file mode 100644
index 00000000..ced691e2
--- /dev/null
+++ b/ntversion.pl
@@ -0,0 +1,34 @@
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+@date = localtime();
+$FILEVERSION = &doubleDigit( $date[5] ) . ',' . # year
+ &doubleDigit( $date[4] + 1 ) . ',' . # month
+ &doubleDigit( $date[3] ) . ',' . # date
+ &doubleDigit( $date[2] );
+$FILEVERSIONTEXT = '"' . &doubleDigit( $date[4] ) . '/' . # month
+ &doubleDigit( $date[3] ) . '/' . # date
+ &doubleDigit( $date[5] ) . ' ' . # year
+ &doubleDigit( $date[2] ) . ':' . # hour
+ &doubleDigit( $date[1] ) . '"'; # minute
+$MAJORVERSION=$ARGV[1];
+$MINORVERSION=$ARGV[2];
+
+open(VERSIONFILE, ">$ARGV[0]/ldapserver/include/nt/ntversion.h");
+print VERSIONFILE "// This file is automatically generated.\r\n";
+print VERSIONFILE "// Please do not edit this file manually.\r\n";
+print VERSIONFILE "// It contains the version number of this build.\r\n";
+print VERSIONFILE "\r\n";
+print VERSIONFILE "#define VERSION $FILEVERSION\r\n";
+print VERSIONFILE "#define PRODUCT $MAJORVERSION,0,0,$MINORVERSION\r\n";
+print VERSIONFILE "#define VERSIONTEXT $FILEVERSIONTEXT\r\n";
+print VERSIONFILE "#define PRODUCTTEXT \"$MAJORVERSION.$MINORVERSION\"\r\n";
+close( VERSIONFILE );
+
+sub doubleDigit {
+ $_[0] > 9 ? $_[0] : '0' . $_[0];
+}
diff --git a/pumpkin.pl b/pumpkin.pl
new file mode 100644
index 00000000..8d4c7dc9
--- /dev/null
+++ b/pumpkin.pl
@@ -0,0 +1,15 @@
+#!/usr/local/bin/perl
+#
+# BEGIN COPYRIGHT BLOCK
+# Copyright 2001 Sun Microsystems, Inc.
+# Portions copyright 1999, 2001-2003 Netscape Communications Corporation.
+# All rights reserved.
+# END COPYRIGHT BLOCK
+#
+
+# NT doesn't reliably do perl -e, so we have to do this.
+die "Usage: $0 <days> <file>\n" unless $#ARGV == 1;
+
+open( PUMPKIN, ">$ARGV[1]" ) || die "Can't create $ARGV[1]: $!\n";
+print PUMPKIN time + $ARGV[0] * 24 * 60 * 60;
+close( PUMPKIN );